xref: /titanic_51/usr/src/cmd/raidctl/raidctl.c (revision ff17c8bf86c3e567734be83f90267edee20f580f)
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 		} else {
1365 			return (INVALID_ARG);
1366 		}
1367 
1368 		param = strtok(NULL, op);
1369 		if (strcmp(param, "on") == 0) {
1370 			value = CACHE_WR_ON;
1371 		} else if (strcmp(param, "off") == 0) {
1372 			value = CACHE_WR_OFF;
1373 		} else {
1374 			return (INVALID_ARG);
1375 		}
1376 
1377 	} else {
1378 		return (INVALID_ARG);
1379 	}
1380 
1381 	if (get_array_tag(argv[optind], &ctl_tag, &array_tag) != SUCCESS) {
1382 		return (INVALID_ARG);
1383 	}
1384 
1385 	ctl_handle = raidcfg_get_controller(ctl_tag);
1386 	if (ctl_handle <= 0) {
1387 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ctl_handle));
1388 		return (FAILURE);
1389 	}
1390 
1391 	ret = raidcfg_open_controller(ctl_handle, NULL);
1392 	if (ret < 0) {
1393 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1394 		return (FAILURE);
1395 	}
1396 
1397 	array_handle = raidcfg_get_array(ctl_handle, array_tag.idl.target_id,
1398 	    array_tag.idl.lun);
1399 	if (array_handle <= 0) {
1400 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(array_handle));
1401 		return (FAILURE);
1402 	}
1403 
1404 	/* Ask user to confirm operation. */
1405 	if (f_flag == FALSE) {
1406 		(void) fprintf(stdout, gettext("Update attribute of "
1407 		    "array %s (%s/%s)? "), argv[optind], yesstr, nostr);
1408 		if (!yes()) {
1409 			(void) fprintf(stdout,
1410 			    gettext("Array %s not "
1411 			    "changed.\n\n"), argv[optind]);
1412 			(void) raidcfg_close_controller(ctl_handle, NULL);
1413 			return (SUCCESS);
1414 		}
1415 	}
1416 
1417 	if ((ret = raidcfg_set_attr(array_handle, type, &value, NULL)) < 0) {
1418 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1419 		(void) raidcfg_close_controller(ctl_handle, NULL);
1420 		return (FAILURE);
1421 	}
1422 
1423 	(void) printf(gettext("Set attribute of RAID volume %s "
1424 	    "successfully.\n"), argv[optind]);
1425 	(void) raidcfg_close_controller(ctl_handle, NULL);
1426 
1427 	return (SUCCESS);
1428 }
1429 
1430 /*
1431  * snapshot_raidsystem(recursive, indent, is_snapshot)
1432  * This function prints the snapshot of whole RAID's system configuration,
1433  * and return result as SUCCESS or FAILURE.
1434  */
1435 static int
1436 snapshot_raidsystem(uint8_t recursive, uint8_t indent, uint8_t is_snapshot)
1437 {
1438 	raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE;
1439 	int ret;
1440 
1441 	ctl_handle = raidcfg_list_head(OBJ_SYSTEM, OBJ_TYPE_CONTROLLER);
1442 	while (ctl_handle > 0) {
1443 		ret = raidcfg_open_controller(ctl_handle, NULL);
1444 		if (ret == 0) {
1445 			if (snapshot_ctl(ctl_handle, recursive, indent,
1446 			    is_snapshot) == FAILURE) {
1447 				(void) raidcfg_close_controller(ctl_handle,
1448 				    NULL);
1449 			}
1450 		}
1451 		ctl_handle = raidcfg_list_next(ctl_handle);
1452 	}
1453 	return (SUCCESS);
1454 }
1455 
1456 /*
1457  * snapshot_ctl(ctl_handle, recursive, indent, is_snapshot)
1458  * This function prints snapshot of specified controller's configuration,
1459  * and return result as SUCCESS or FAILURE.
1460  */
1461 static int
1462 snapshot_ctl(raid_obj_handle_t ctl_handle, uint8_t recursive, uint8_t indent,
1463     uint8_t is_snapshot)
1464 {
1465 	raid_obj_handle_t array_handle = INIT_HANDLE_VALUE;
1466 	raid_obj_handle_t disk_handle = INIT_HANDLE_VALUE;
1467 	raidcfg_controller_t ctl_attr;
1468 	uint32_t ctl_tag;
1469 	char ctlbuf[256];
1470 	int ret;
1471 
1472 	if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) {
1473 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1474 		return (FAILURE);
1475 	}
1476 
1477 	ctl_tag = ctl_attr.controller_id;
1478 	if (is_snapshot == FALSE) {
1479 		print_indent(indent);
1480 		(void) fprintf(stdout, gettext("Controller: %u\n"), ctl_tag);
1481 	} else {
1482 		(void) snprintf(ctlbuf, sizeof (ctlbuf), "%u \"%s\"",
1483 		    ctl_tag, ctl_attr.controller_type);
1484 		(void) fprintf(stdout, "%s", ctlbuf);
1485 
1486 		(void) fprintf(stdout, "\n");
1487 	}
1488 
1489 	if (recursive == TRUE) {
1490 		array_handle = raidcfg_list_head(ctl_handle, OBJ_TYPE_ARRAY);
1491 		while (array_handle > 0) {
1492 			if (snapshot_array(array_handle,
1493 			    indent + 1, FALSE, is_snapshot) == FAILURE) {
1494 				return (FAILURE);
1495 			}
1496 
1497 			array_handle = raidcfg_list_next(array_handle);
1498 		}
1499 
1500 		disk_handle = raidcfg_list_head(ctl_handle, OBJ_TYPE_DISK);
1501 		while (disk_handle > 0) {
1502 			if (snapshot_disk(ctl_tag, disk_handle,
1503 			    indent + 1, is_snapshot) == FAILURE) {
1504 				return (FAILURE);
1505 			}
1506 
1507 			disk_handle = raidcfg_list_next(disk_handle);
1508 		}
1509 	}
1510 	return (SUCCESS);
1511 }
1512 
1513 
1514 /*
1515  * snapshot_array(array_handle, indent, is_sub, is_snapshot)
1516  * This function prints snapshot of specified array's configuration,
1517  * and return result as SUCCESS or FAILURE.
1518  */
1519 static int
1520 snapshot_array(raid_obj_handle_t array_handle, uint8_t indent, uint8_t is_sub,
1521     uint8_t is_snapshot)
1522 {
1523 	raid_obj_handle_t ctl_handle;
1524 	raid_obj_handle_t subarray_handle;
1525 	raid_obj_handle_t arraypart_handle;
1526 	raid_obj_handle_t task_handle;
1527 
1528 	raidcfg_controller_t ctl_attr;
1529 	raidcfg_array_t array_attr;
1530 	raidcfg_arraypart_t arraypart_attr;
1531 	raidcfg_task_t task_attr;
1532 
1533 	char arraybuf[256] = "\0";
1534 	char diskbuf[256] = "\0";
1535 	char tempbuf[256] = "\0";
1536 	int disknum = 0;
1537 
1538 	uint32_t ctl_tag;
1539 	int ret;
1540 
1541 	ctl_handle = raidcfg_get_container(array_handle);
1542 	ret = raidcfg_get_attr(ctl_handle, &ctl_attr);
1543 	if (ret < 0) {
1544 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1545 		return (FAILURE);
1546 	}
1547 	ctl_tag = ctl_attr.controller_id;
1548 
1549 	/* Print array attribute */
1550 	if ((ret = raidcfg_get_attr(array_handle, &array_attr)) < 0) {
1551 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1552 		return (FAILURE);
1553 	}
1554 
1555 	if (is_snapshot == FALSE) {
1556 		print_indent(indent);
1557 		if (is_sub == FALSE) {
1558 			(void) fprintf(stdout, gettext("Volume:"
1559 			    "c%ut%llud%llu\n"),
1560 			    ctl_tag, array_attr.tag.idl.target_id,
1561 			    array_attr.tag.idl.lun);
1562 		} else {
1563 			(void) fprintf(stdout, gettext("Sub-Volume\n"));
1564 		}
1565 	} else {
1566 		(void) snprintf(arraybuf, sizeof (arraybuf), "c%ut%llud%llu ",
1567 		    ctl_tag, array_attr.tag.idl.target_id,
1568 		    array_attr.tag.idl.lun);
1569 
1570 		/* Check if array is in sync state */
1571 		task_handle = raidcfg_list_head(array_handle, OBJ_TYPE_TASK);
1572 		if (task_handle > 0) {
1573 			(void) raidcfg_get_attr(task_handle, &task_attr);
1574 			if (task_attr.task_func == TASK_FUNC_BUILD) {
1575 				array_attr.state = ARRAY_STATE_SYNC;
1576 			}
1577 		} else {
1578 			subarray_handle = raidcfg_list_head(array_handle,
1579 			    OBJ_TYPE_ARRAY);
1580 			while (subarray_handle > 0) {
1581 				task_handle = raidcfg_list_head(subarray_handle,
1582 				    OBJ_TYPE_TASK);
1583 				if (task_handle > 0) {
1584 					(void) raidcfg_get_attr(task_handle,
1585 					    &task_attr);
1586 					if (task_attr.task_func ==
1587 					    TASK_FUNC_BUILD) {
1588 						array_attr.state =
1589 						    ARRAY_STATE_SYNC;
1590 					}
1591 					break;
1592 				}
1593 				subarray_handle =
1594 				    raidcfg_list_next(subarray_handle);
1595 			}
1596 		}
1597 
1598 		/* Print sub array */
1599 		subarray_handle = raidcfg_list_head(array_handle,
1600 		    OBJ_TYPE_ARRAY);
1601 		while (subarray_handle > 0) {
1602 			/* print subarraypart */
1603 			arraypart_handle = raidcfg_list_head(subarray_handle,
1604 			    OBJ_TYPE_ARRAY_PART);
1605 			while (arraypart_handle > 0) {
1606 				if ((ret = raidcfg_get_attr(arraypart_handle,
1607 				    &arraypart_attr)) < 0) {
1608 					(void) fprintf(stderr, "%s\n",
1609 					    raidcfg_errstr(ret));
1610 					return (FAILURE);
1611 				}
1612 
1613 				if (arraypart_attr.tag.cidl.bus == MAX64BIT) {
1614 					(void) snprintf(tempbuf,
1615 					    sizeof (tempbuf),
1616 					    gettext("N/A"));
1617 				} else {
1618 					(void) snprintf(tempbuf,
1619 					    sizeof (tempbuf),
1620 					    "%llu.%llu.%llu",
1621 					    arraypart_attr.tag.cidl.bus,
1622 					    arraypart_attr.tag.cidl.target_id,
1623 					    arraypart_attr.tag.cidl.lun);
1624 				}
1625 				(void) strcat(diskbuf, tempbuf);
1626 				(void) strcat(diskbuf, " ");
1627 				disknum++;
1628 				arraypart_handle =
1629 				    raidcfg_list_next(arraypart_handle);
1630 			}
1631 			subarray_handle = raidcfg_list_next(subarray_handle);
1632 		}
1633 
1634 		/* Print arraypart */
1635 		arraypart_handle = raidcfg_list_head(array_handle,
1636 		    OBJ_TYPE_ARRAY_PART);
1637 		while (arraypart_handle > 0) {
1638 			if ((ret = raidcfg_get_attr(arraypart_handle,
1639 			    &arraypart_attr)) < 0) {
1640 				(void) fprintf(stderr, "%s\n",
1641 				    raidcfg_errstr(ret));
1642 				return (FAILURE);
1643 			}
1644 
1645 			if (arraypart_attr.tag.cidl.bus == MAX64BIT) {
1646 				(void) snprintf(tempbuf, sizeof (tempbuf),
1647 				    gettext("N/A"));
1648 			} else {
1649 				(void) snprintf(tempbuf, sizeof (tempbuf),
1650 				    "%llu.%llu.%llu",
1651 				    arraypart_attr.tag.cidl.bus,
1652 				    arraypart_attr.tag.cidl.target_id,
1653 				    arraypart_attr.tag.cidl.lun);
1654 			}
1655 			(void) strcat(diskbuf, tempbuf);
1656 			(void) strcat(diskbuf, " ");
1657 			disknum++;
1658 			arraypart_handle = raidcfg_list_next(arraypart_handle);
1659 		}
1660 		(void) snprintf(tempbuf, sizeof (tempbuf), "%u ", disknum);
1661 		(void) strcat(arraybuf, tempbuf);
1662 		(void) strcat(arraybuf, diskbuf);
1663 
1664 		switch (array_attr.raid_level) {
1665 		case RAID_LEVEL_0:
1666 			(void) sprintf(tempbuf, "0");
1667 			break;
1668 		case RAID_LEVEL_1:
1669 			(void) sprintf(tempbuf, "1");
1670 			break;
1671 		case RAID_LEVEL_1E:
1672 			(void) sprintf(tempbuf, "1E");
1673 			break;
1674 		case RAID_LEVEL_5:
1675 			(void) sprintf(tempbuf, "5");
1676 			break;
1677 		case RAID_LEVEL_10:
1678 			(void) sprintf(tempbuf, "10");
1679 			break;
1680 		case RAID_LEVEL_50:
1681 			(void) sprintf(tempbuf, "50");
1682 			break;
1683 		default:
1684 			(void) snprintf(tempbuf, sizeof (tempbuf),
1685 			    gettext("N/A"));
1686 			break;
1687 		}
1688 		(void) strcat(arraybuf, tempbuf);
1689 		(void) fprintf(stdout, "%s ", arraybuf);
1690 
1691 		switch (array_attr.state) {
1692 		case ARRAY_STATE_OPTIMAL:
1693 			(void) fprintf(stdout, gettext("OPTIMAL"));
1694 			break;
1695 		case ARRAY_STATE_DEGRADED:
1696 			(void) fprintf(stdout, gettext("DEGRADED"));
1697 			break;
1698 		case ARRAY_STATE_FAILED:
1699 			(void) fprintf(stdout, gettext("FAILED"));
1700 			break;
1701 		case ARRAY_STATE_SYNC:
1702 			(void) fprintf(stdout, gettext("SYNC"));
1703 			break;
1704 		case ARRAY_STATE_MISSING:
1705 			(void) fprintf(stdout, gettext("MISSING"));
1706 			break;
1707 		default:
1708 			(void) fprintf(stdout, gettext("N/A"));
1709 			break;
1710 		}
1711 		(void) fprintf(stdout, "\n");
1712 	}
1713 
1714 	return (SUCCESS);
1715 }
1716 
1717 /*
1718  * snapshot_disk(ctl_tag, disk_handle, indent, is_snapshot)
1719  * This function prints snapshot of specified disk's configuration, and return
1720  * result as SUCCESS or FAILURE.
1721  */
1722 static int
1723 snapshot_disk(uint32_t ctl_tag, raid_obj_handle_t disk_handle, uint8_t indent,
1724     uint8_t is_snapshot)
1725 {
1726 	raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE;
1727 	raid_obj_handle_t hsp_handle;
1728 
1729 	raidcfg_controller_t ctl_attr;
1730 	raidcfg_disk_t disk_attr;
1731 	char diskbuf[256] = "";
1732 	char tempbuf[256] = "";
1733 
1734 	int ret;
1735 
1736 	ctl_handle = raidcfg_get_controller(ctl_tag);
1737 	ret = raidcfg_get_attr(ctl_handle, &ctl_attr);
1738 	if (ret < 0) {
1739 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1740 		return (FAILURE);
1741 	}
1742 
1743 	/* Print attribute of disk */
1744 	if ((ret = raidcfg_get_attr(disk_handle, &disk_attr)) < 0) {
1745 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1746 		return (FAILURE);
1747 	}
1748 
1749 	if (is_snapshot == FALSE) {
1750 		print_indent(indent);
1751 
1752 		hsp_handle = raidcfg_list_head(disk_handle, OBJ_TYPE_HSP);
1753 
1754 		if (disk_attr.tag.cidl.bus == MAX64BIT) {
1755 			(void) fprintf(stdout, gettext("Disk: N/A"));
1756 		} else {
1757 			(void) fprintf(stdout, gettext("Disk: %llu.%llu.%llu"),
1758 			    disk_attr.tag.cidl.bus,
1759 			    disk_attr.tag.cidl.target_id,
1760 			    disk_attr.tag.cidl.lun);
1761 		}
1762 		if (hsp_handle > 0) {
1763 			(void) fprintf(stdout, "(HSP)");
1764 		}
1765 		(void) fprintf(stdout, "\n");
1766 	} else {
1767 		if (disk_attr.tag.cidl.bus == MAX64BIT) {
1768 			(void) fprintf(stdout, gettext("N/A"));
1769 		} else {
1770 			(void) snprintf(diskbuf, sizeof (diskbuf),
1771 			    "%llu.%llu.%llu ",
1772 			    disk_attr.tag.cidl.bus,
1773 			    disk_attr.tag.cidl.target_id,
1774 			    disk_attr.tag.cidl.lun);
1775 		}
1776 		hsp_handle = raidcfg_list_head(disk_handle, OBJ_TYPE_HSP);
1777 		if (hsp_handle > 0) {
1778 			(void) snprintf(tempbuf, sizeof (tempbuf),
1779 			    gettext("HSP"));
1780 		} else if (disk_attr.state == DISK_STATE_GOOD) {
1781 			(void) snprintf(tempbuf, sizeof (tempbuf),
1782 			    gettext("GOOD"));
1783 		} else if (disk_attr.state == DISK_STATE_FAILED) {
1784 			(void) snprintf(tempbuf, sizeof (tempbuf),
1785 			    gettext("FAILED"));
1786 		} else {
1787 			(void) snprintf(tempbuf, sizeof (tempbuf),
1788 			    gettext("N/A"));
1789 		}
1790 
1791 		(void) strcat(diskbuf, tempbuf);
1792 		(void) fprintf(stdout, "%s\n", diskbuf);
1793 	}
1794 
1795 	return (SUCCESS);
1796 }
1797 
1798 static int
1799 print_ctl_table(raid_obj_handle_t ctl_handle)
1800 {
1801 	raidcfg_controller_t ctl_attr;
1802 	char controller[8];
1803 	int ret;
1804 
1805 	if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) {
1806 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1807 		return (FAILURE);
1808 	}
1809 
1810 	(void) fprintf(stdout, gettext("Controller\tType\t\tVersion"));
1811 	(void) fprintf(stdout, "\n");
1812 	(void) fprintf(stdout, "--------------------------------");
1813 	(void) fprintf(stdout, "--------------------------------");
1814 	(void) fprintf(stdout, "\n");
1815 
1816 	(void) snprintf(controller, sizeof (controller), "%u",
1817 	    ctl_attr.controller_id);
1818 	(void) printf("c%s\t\t", controller);
1819 
1820 	(void) print_ctl_attr(&ctl_attr);
1821 	(void) fprintf(stdout, "\n");
1822 
1823 	return (SUCCESS);
1824 }
1825 
1826 static int
1827 print_array_table(raid_obj_handle_t ctl_handle, raid_obj_handle_t array_handle)
1828 {
1829 	raidcfg_controller_t ctl_attr;
1830 	raidcfg_array_t array_attr;
1831 	raidcfg_array_t subarray_attr;
1832 	raidcfg_arraypart_t arraypart_attr;
1833 	raidcfg_task_t task_attr;
1834 
1835 	raid_obj_handle_t subarray_handle;
1836 	raid_obj_handle_t arraypart_handle;
1837 	raid_obj_handle_t task_handle;
1838 
1839 	char array[8];
1840 	char arraypart[8];
1841 	int ret;
1842 	int i;
1843 
1844 	/* Controller attribute */
1845 	if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) {
1846 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1847 		return (FAILURE);
1848 	}
1849 
1850 	/* Array attribute */
1851 	if ((ret = raidcfg_get_attr(array_handle, &array_attr)) < 0) {
1852 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1853 		return (FAILURE);
1854 	}
1855 
1856 	/* print header */
1857 	(void) fprintf(stdout, gettext("Volume\t\t\tSize\tStripe\tStatus\t"
1858 	    " Cache\tRAID"));
1859 	(void) fprintf(stdout, "\n");
1860 	(void) fprintf(stdout, gettext("\tSub\t\t\tSize\t\t\tLevel"));
1861 	(void) fprintf(stdout, "\n");
1862 	(void) fprintf(stdout, gettext("\t\tDisk\t\t\t\t\t"));
1863 	(void) fprintf(stdout, "\n");
1864 	(void) fprintf(stdout, "--------------------------------");
1865 	(void) fprintf(stdout, "--------------------------------");
1866 	(void) fprintf(stdout, "\n");
1867 
1868 	/* print array */
1869 	(void) snprintf(array, sizeof (array), "c%ut%llud%llu",
1870 	    ctl_attr.controller_id, array_attr.tag.idl.target_id,
1871 	    array_attr.tag.idl.lun);
1872 	(void) fprintf(stdout, "%s\t\t\t", array);
1873 
1874 	/* check if array is in sync state */
1875 	task_handle = raidcfg_list_head(array_handle, OBJ_TYPE_TASK);
1876 	if (task_handle > 0) {
1877 		(void) raidcfg_get_attr(task_handle, &task_attr);
1878 		if (task_attr.task_func == TASK_FUNC_BUILD) {
1879 			array_attr.state = ARRAY_STATE_SYNC;
1880 		}
1881 	} else {
1882 		subarray_handle = raidcfg_list_head(array_handle,
1883 		    OBJ_TYPE_ARRAY);
1884 		while (subarray_handle > 0) {
1885 			task_handle = raidcfg_list_head(subarray_handle,
1886 			    OBJ_TYPE_TASK);
1887 			if (task_handle > 0) {
1888 				(void) raidcfg_get_attr(task_handle,
1889 				    &task_attr);
1890 				if (task_attr.task_func == TASK_FUNC_BUILD) {
1891 					array_attr.state = ARRAY_STATE_SYNC;
1892 				}
1893 				break;
1894 			}
1895 			subarray_handle = raidcfg_list_next(subarray_handle);
1896 		}
1897 	}
1898 
1899 	(void) print_array_attr(&array_attr);
1900 	(void) fprintf(stdout, "\n");
1901 
1902 	/* Print sub array */
1903 	i = 0;			/* Count sub array number */
1904 	subarray_handle = raidcfg_list_head(array_handle, OBJ_TYPE_ARRAY);
1905 	while (subarray_handle > 0) {
1906 		if ((ret = raidcfg_get_attr(subarray_handle,
1907 		    &subarray_attr)) < 0) {
1908 			(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1909 			return (FAILURE);
1910 		}
1911 
1912 		/* Use sub0/sub1 here, not cxtxd0 for subarray */
1913 		(void) snprintf(array, sizeof (array), "sub%u", i++);
1914 		(void) fprintf(stdout, "\t%s\t\t", array);
1915 
1916 		/* Check if array is in sync */
1917 		task_handle = raidcfg_list_head(subarray_handle, OBJ_TYPE_TASK);
1918 		if (task_handle > 0) {
1919 			(void) raidcfg_get_attr(task_handle, &task_attr);
1920 			if (task_attr.task_func == TASK_FUNC_BUILD) {
1921 				subarray_attr.state = ARRAY_STATE_SYNC;
1922 			}
1923 		}
1924 
1925 		(void) print_array_attr(&subarray_attr);
1926 		(void) fprintf(stdout, "\n");
1927 
1928 		/* Print subarraypart */
1929 		arraypart_handle = raidcfg_list_head(subarray_handle,
1930 		    OBJ_TYPE_ARRAY_PART);
1931 		while (arraypart_handle > 0) {
1932 			if ((ret = raidcfg_get_attr(arraypart_handle,
1933 			    &arraypart_attr)) < 0) {
1934 				(void) fprintf(stderr, "%s\n",
1935 				    raidcfg_errstr(ret));
1936 				return (FAILURE);
1937 			}
1938 
1939 			if (arraypart_attr.tag.cidl.bus == MAX64BIT) {
1940 				(void) snprintf(arraypart, sizeof (arraypart),
1941 				    gettext("N/A"));
1942 			} else {
1943 				(void) snprintf(arraypart, sizeof (arraypart),
1944 				    "%llu.%llu.%llu",
1945 				    arraypart_attr.tag.cidl.bus,
1946 				    arraypart_attr.tag.cidl.target_id,
1947 				    arraypart_attr.tag.cidl.lun);
1948 			}
1949 
1950 			(void) fprintf(stdout, "\t\t%s\t", arraypart);
1951 			(void) print_arraypart_attr(&arraypart_attr);
1952 			(void) fprintf(stdout, "\n");
1953 			arraypart_handle = raidcfg_list_next(arraypart_handle);
1954 		}
1955 		subarray_handle = raidcfg_list_next(subarray_handle);
1956 	}
1957 
1958 	/* Print arraypart */
1959 	arraypart_handle = raidcfg_list_head(array_handle,
1960 	    OBJ_TYPE_ARRAY_PART);
1961 	while (arraypart_handle > 0) {
1962 		if ((ret = raidcfg_get_attr(arraypart_handle,
1963 		    &arraypart_attr)) < 0) {
1964 			(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1965 			return (FAILURE);
1966 		}
1967 
1968 		if (arraypart_attr.tag.cidl.bus == MAX64BIT) {
1969 			(void) snprintf(arraypart, sizeof (arraypart),
1970 			    gettext("N/A"));
1971 		} else {
1972 			(void) snprintf(arraypart, sizeof (arraypart),
1973 			    "%llu.%llu.%llu",
1974 			    arraypart_attr.tag.cidl.bus,
1975 			    arraypart_attr.tag.cidl.target_id,
1976 			    arraypart_attr.tag.cidl.lun);
1977 		}
1978 
1979 		(void) fprintf(stdout, "\t\t%s\t", arraypart);
1980 		(void) print_arraypart_attr(&arraypart_attr);
1981 		(void) fprintf(stdout, "\n");
1982 		arraypart_handle = raidcfg_list_next(arraypart_handle);
1983 	}
1984 
1985 	return (SUCCESS);
1986 }
1987 
1988 static int
1989 print_disk_table(raid_obj_handle_t ctl_handle, raid_obj_handle_t disk_handle)
1990 {
1991 	raidcfg_controller_t ctl_attr;
1992 	raidcfg_disk_t disk_attr;
1993 	char disk[8];
1994 	int ret;
1995 
1996 	if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) {
1997 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1998 		return (FAILURE);
1999 	}
2000 
2001 	if ((ret = raidcfg_get_attr(disk_handle, &disk_attr)) < 0) {
2002 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
2003 		return (FAILURE);
2004 	}
2005 
2006 	/* Print header */
2007 	(void) fprintf(stdout, gettext("Disk\tVendor\tProduct\t\tFirmware\t"
2008 	    "Capacity\tStatus\tHSP"));
2009 	(void) fprintf(stdout, "\n");
2010 	(void) fprintf(stdout, "--------------------------------------");
2011 	(void) fprintf(stdout, "--------------------------------------");
2012 	(void) fprintf(stdout, "\n");
2013 
2014 
2015 	(void) snprintf(disk, sizeof (disk), "%llu.%llu.%llu",
2016 	    disk_attr.tag.cidl.bus,
2017 	    disk_attr.tag.cidl.target_id,
2018 	    disk_attr.tag.cidl.lun);
2019 
2020 	(void) fprintf(stdout, "%s\t", disk);
2021 
2022 	(void) print_disk_attr(ctl_handle, disk_handle, &disk_attr);
2023 	(void) fprintf(stdout, "\n");
2024 
2025 	return (SUCCESS);
2026 }
2027 
2028 /*
2029  * print_ctl_attr(attrp)
2030  * This function prints attribute of specified controller, and return
2031  * result as SUCCESS or FAILURE.
2032  */
2033 static int
2034 print_ctl_attr(raidcfg_controller_t *attrp)
2035 {
2036 	char type[CONTROLLER_TYPE_LEN];
2037 	char version[CONTROLLER_FW_LEN];
2038 
2039 	if (attrp == NULL) {
2040 		return (FAILURE);
2041 	}
2042 
2043 	(void) snprintf(type, sizeof (type), "%s", attrp->controller_type);
2044 	(void) fprintf(stdout, "%-16s", type);
2045 
2046 	(void) snprintf(version, sizeof (version), "%s", attrp->fw_version);
2047 	(void) fprintf(stdout, "%s", version);
2048 
2049 	return (SUCCESS);
2050 }
2051 
2052 /*
2053  * print_array_attr(attrp)
2054  * This function prints attribute of specified array, and return
2055  * result as SUCCESS or FAILURE.
2056  */
2057 static int
2058 print_array_attr(raidcfg_array_t *attrp)
2059 {
2060 	char capacity[8];
2061 	char stripe_size[8];
2062 	char raid_level[8];
2063 
2064 	if (attrp == NULL) {
2065 		return (FAILURE);
2066 	}
2067 
2068 	if (attrp->capacity != MAX64BIT) {
2069 		if (size_to_string(attrp->capacity, capacity, 8) != SUCCESS) {
2070 			return (FAILURE);
2071 		}
2072 		(void) printf("%s\t", capacity);
2073 	} else {
2074 		(void) printf(gettext("N/A\t"));
2075 	}
2076 
2077 	if (attrp->stripe_size != MAX32BIT) {
2078 		(void) snprintf(stripe_size, sizeof (stripe_size), "%uK",
2079 		    attrp->stripe_size / 1024);
2080 		(void) printf("%s\t", stripe_size);
2081 	} else {
2082 		(void) printf(gettext("N/A\t"));
2083 	}
2084 
2085 	switch (attrp->state) {
2086 	case ARRAY_STATE_OPTIMAL:
2087 		(void) printf("%-8s", gettext("OPTIMAL"));
2088 		break;
2089 	case ARRAY_STATE_DEGRADED:
2090 		(void) printf("%-8s", gettext("DEGRADED"));
2091 		break;
2092 	case ARRAY_STATE_FAILED:
2093 		(void) printf("%-8s", gettext("FAILED"));
2094 		break;
2095 	case ARRAY_STATE_SYNC:
2096 		(void) printf("%-8s", gettext("SYNC"));
2097 		break;
2098 	case ARRAY_STATE_MISSING:
2099 		(void) printf("%-8s", gettext("MISSING"));
2100 		break;
2101 	default:
2102 		(void) printf("%-8s", gettext("N/A"));
2103 		break;
2104 	}
2105 	(void) printf(" ");
2106 
2107 	if (attrp->write_policy == CACHE_WR_OFF) {
2108 		(void) printf(gettext("OFF"));
2109 	} else if (attrp->write_policy == CACHE_WR_ON) {
2110 		(void) printf(gettext("ON"));
2111 	} else {
2112 		(void) printf(gettext("N/A"));
2113 	}
2114 	(void) printf("\t");
2115 
2116 	switch (attrp->raid_level) {
2117 	case RAID_LEVEL_0:
2118 		(void) sprintf(raid_level, "RAID0");
2119 		break;
2120 	case RAID_LEVEL_1:
2121 		(void) sprintf(raid_level, "RAID1");
2122 		break;
2123 	case RAID_LEVEL_1E:
2124 		(void) sprintf(raid_level, "RAID1E");
2125 		break;
2126 	case RAID_LEVEL_5:
2127 		(void) sprintf(raid_level, "RAID5");
2128 		break;
2129 	case RAID_LEVEL_10:
2130 		(void) sprintf(raid_level, "RAID10");
2131 		break;
2132 	case RAID_LEVEL_50:
2133 		(void) sprintf(raid_level, "RAID50");
2134 		break;
2135 	default:
2136 		(void) snprintf(raid_level, sizeof (raid_level),
2137 		    gettext("N/A"));
2138 		break;
2139 	}
2140 	(void) printf("%s", raid_level);
2141 
2142 	return (SUCCESS);
2143 }
2144 
2145 /*
2146  * print_arraypart_attr(attrp)
2147  * This function print attribute of specified arraypart, and return
2148  * result as SUCCESS or FAILURE.
2149  */
2150 static int
2151 print_arraypart_attr(raidcfg_arraypart_t *attrp)
2152 {
2153 	char size[8];
2154 
2155 	if (attrp == NULL) {
2156 		return (FAILURE);
2157 	}
2158 
2159 	if (attrp->size != MAX64BIT) {
2160 		if (size_to_string(attrp->size, size, 8) != SUCCESS) {
2161 			return (FAILURE);
2162 		}
2163 		(void) printf("%s\t", size);
2164 	} else {
2165 		(void) printf(gettext("N/A\t"));
2166 	}
2167 
2168 	(void) printf("\t");
2169 
2170 	if (attrp->state == DISK_STATE_GOOD) {
2171 		(void) printf(gettext("GOOD"));
2172 	} else if (attrp->state == DISK_STATE_FAILED) {
2173 		(void) printf(gettext("FAILED"));
2174 	} else {
2175 		(void) printf(gettext("N/A"));
2176 	}
2177 	(void) printf("\t");
2178 
2179 	return (SUCCESS);
2180 }
2181 
2182 /*
2183  * print_disk_attr(ctl_handle, disk_handle, attrp)
2184  * This function prints attribute of specified disk, and return
2185  * result as SUCCESS or FAILURE.
2186  */
2187 static int
2188 print_disk_attr(raid_obj_handle_t ctl_handle, raid_obj_handle_t disk_handle,
2189 	raidcfg_disk_t *attrp)
2190 {
2191 	char vendor[DISK_VENDER_LEN];
2192 	char product[DISK_PRODUCT_LEN];
2193 	char revision[DISK_REV_LEN + 1];
2194 	char capacity[16];
2195 	char hsp[16];
2196 
2197 	raid_obj_handle_t hsp_handle;
2198 	raidcfg_hsp_t hsp_attr;
2199 	raidcfg_controller_t ctl_attr;
2200 	int ret;
2201 	char is_indent;
2202 
2203 	if (attrp == NULL) {
2204 		return (FAILURE);
2205 	}
2206 
2207 	(void) snprintf(vendor, sizeof (vendor), "%s", attrp->vendorid);
2208 	(void) printf("%s\t", vendor);
2209 
2210 	(void) snprintf(product, sizeof (product), "%s", attrp->productid);
2211 	(void) printf("%s\t", product);
2212 
2213 	(void) snprintf(revision, sizeof (revision), "%s", attrp->revision);
2214 	(void) printf("%s\t\t", revision);
2215 
2216 	if (attrp->capacity != MAX64BIT) {
2217 		if (size_to_string(attrp->capacity, capacity, 16) != SUCCESS) {
2218 			return (FAILURE);
2219 		}
2220 		(void) printf("%s\t\t", capacity);
2221 	} else {
2222 		(void) printf(gettext("N/A"));
2223 	}
2224 
2225 	if (attrp->state == DISK_STATE_GOOD) {
2226 		(void) printf(gettext("GOOD"));
2227 	} else if (attrp->state == DISK_STATE_FAILED) {
2228 		(void) printf(gettext("FAILED"));
2229 	} else {
2230 		(void) printf(gettext("N/A"));
2231 	}
2232 	(void) printf("\t");
2233 
2234 	/* Controller attribute */
2235 	if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) {
2236 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
2237 		return (FAILURE);
2238 	}
2239 
2240 	hsp_handle = raidcfg_list_head(disk_handle, OBJ_TYPE_HSP);
2241 	if (hsp_handle == 0) {
2242 		(void) printf(gettext("N/A\n"));
2243 	} else {
2244 		is_indent = FALSE;
2245 		while (hsp_handle > 0) {
2246 			if ((ret = raidcfg_get_attr(hsp_handle,
2247 			    &hsp_attr)) < 0) {
2248 				(void) fprintf(stderr, "%s\n",
2249 				    raidcfg_errstr(ret));
2250 				return (FAILURE);
2251 			}
2252 
2253 			if (is_indent == TRUE) {
2254 				(void) printf("\t\t\t\t\t\t\t");
2255 			} else {
2256 				is_indent = TRUE;
2257 			}
2258 
2259 			if (hsp_attr.type == HSP_TYPE_LOCAL) {
2260 				(void) snprintf(hsp, sizeof (hsp),
2261 				    "c%ut%llud%llu",
2262 				    ctl_attr.controller_id,
2263 				    hsp_attr.tag.idl.target_id,
2264 				    hsp_attr.tag.idl.lun);
2265 				(void) printf("%s\n", hsp);
2266 			} else if (hsp_attr.type == HSP_TYPE_GLOBAL) {
2267 				(void) printf(gettext("Global\n"));
2268 			} else {
2269 				return (FAILURE);
2270 			}
2271 
2272 			hsp_handle = raidcfg_list_next(hsp_handle);
2273 		}
2274 	}
2275 	return (SUCCESS);
2276 }
2277 
2278 
2279 /*
2280  * print_indent(indent)
2281  * This function prints specified number of tab characters. It's used to
2282  * format layout.
2283  */
2284 static void
2285 print_indent(uint8_t indent)
2286 {
2287 	uint32_t i;
2288 	for (i = 0; i < indent; i++) {
2289 		(void) fprintf(stdout, "\t");
2290 	}
2291 }
2292 
2293 /*
2294  * get_disk_handle_cidl(ctl_tag, disks_argp, comps_num, handlespp)
2295  * This function parses the string of disk argument, and gets the disks tag
2296  * and separators from the string. Then it translates the tag to handle, and
2297  * stores handles and separators to new buffer pointed by parameter handlespp.
2298  * The format of disk_arg must be C:ID:L, for example, it is 0.1.0. The first
2299  * "0" is channel number, and the second "1" is target number, and the third
2300  * "0" is LUN number. The disk tags are separated by comma and parenthesis.
2301  * Function returns SUCCESS or FAILURE.
2302  */
2303 static int
2304 get_disk_handle_cidl(uint32_t ctl_tag, char *disks_argp, int *comps_nump,
2305 	raid_obj_handle_t **handlespp)
2306 {
2307 	int len = 0;
2308 	int i = 0, j = 0;
2309 	char *p, *t;
2310 	char *delimit = " ";
2311 	char *disks_str;
2312 	disk_tag_t disk_tag;
2313 
2314 	if (disks_argp == NULL || comps_nump == NULL) {
2315 		return (FAILURE);
2316 	}
2317 
2318 	p = disks_argp;
2319 	len = strlen(disks_argp);
2320 
2321 	if ((disks_str = (char *)malloc(3 * len + 4)) == NULL) {
2322 		return (FAILURE);
2323 	}
2324 
2325 	/* Insert whitespace between disk tags, '(' , and ')' */
2326 	disks_str[j ++] = '(';
2327 	disks_str[j ++] = ' ';
2328 
2329 	while (p[i] != '\0') {
2330 		if (p[i] == ')' || p[i] == '(') {
2331 			disks_str[j ++] = ' ';
2332 			disks_str[j ++] = p[i];
2333 			disks_str[j ++] = ' ';
2334 		} else
2335 			disks_str[j ++] = p[i];
2336 		i ++;
2337 	}
2338 	disks_str[j ++] = ' ';
2339 	disks_str[j ++] = ')';
2340 	disks_str[j] = '\0';
2341 
2342 	len = strlen(disks_str) + 1;
2343 
2344 	if ((t = (char *)malloc(len)) == NULL) {
2345 		return (FAILURE);
2346 	}
2347 	(void) memcpy(t, disks_str, len);
2348 	p = strtok(t, delimit);
2349 	while (p != NULL) {
2350 		(*comps_nump)++;
2351 		p = strtok(NULL, delimit);
2352 	}
2353 	free(t);
2354 
2355 	*handlespp = calloc(*comps_nump, sizeof (raid_obj_handle_t));
2356 	if (*handlespp == NULL) {
2357 		return (FAILURE);
2358 	}
2359 
2360 	for (i = 0; i < *comps_nump; i++)
2361 		(*handlespp)[i] = INIT_HANDLE_VALUE;
2362 
2363 	i = 0;
2364 	p = strtok(disks_str, delimit);
2365 	while (p != NULL) {
2366 		if (*p == '(') {
2367 			(*handlespp)[i] = OBJ_SEPARATOR_BEGIN;
2368 		} else if (*p == ')') {
2369 			(*handlespp)[i] = OBJ_SEPARATOR_END;
2370 		} else {
2371 			if (get_disk_tag_cidl(p, &disk_tag) != SUCCESS) {
2372 				free(*handlespp);
2373 				free(disks_str);
2374 				return (INVALID_ARG);
2375 			}
2376 			(*handlespp)[i] =
2377 			    raidcfg_get_disk(raidcfg_get_controller(ctl_tag),
2378 			    disk_tag);
2379 			if ((*handlespp)[i] <= 0) {
2380 				(void) fprintf(stderr, "%s\n",
2381 				    raidcfg_errstr((*handlespp)[i]));
2382 				free(*handlespp);
2383 				free(disks_str);
2384 				return (FAILURE);
2385 			}
2386 		}
2387 		p = strtok(NULL, delimit);
2388 		i++;
2389 	}
2390 
2391 	free(disks_str);
2392 	return (SUCCESS);
2393 }
2394 
2395 /*
2396  * get_disk_handle_ctd(disks_num, disks_argpp, ctl_tagp, disks_handlep)
2397  * This function parses string of single disk with "ctd" format, for example,
2398  * c0t0d0, and translates it to controller tag and disk tag.
2399  * Then it calls lib api and get disk handle. The controller tag and disk
2400  * handle are both returned by out parameters.
2401  * The return value is SUCCESS or FAILURE.
2402  */
2403 static int
2404 get_disk_handle_ctd(int disks_num, char **disks_argpp, uint32_t *ctl_tagp,
2405 	raid_obj_handle_t *disks_handlep)
2406 {
2407 	raid_obj_handle_t ctl_handle;
2408 	disk_tag_t disk_tag;
2409 	uint32_t ctl_id;
2410 	int i;
2411 	int ret;
2412 
2413 	if (disks_handlep == NULL) {
2414 		return (FAILURE);
2415 	}
2416 
2417 	for (i = 0; i < disks_num; i++) {
2418 		if (get_disk_tag_ctd(disks_argpp[i], &disk_tag, &ctl_id) !=
2419 		    SUCCESS) {
2420 			return (INVALID_ARG);
2421 		}
2422 
2423 		*ctl_tagp = ctl_id;
2424 
2425 		if (i == 0) {
2426 			ctl_handle = raidcfg_get_controller(*ctl_tagp);
2427 			if (ctl_handle <= 0) {
2428 				(void) fprintf(stderr, "%s\n",
2429 				    raidcfg_errstr(ctl_handle));
2430 				return (FAILURE);
2431 			}
2432 			ret = raidcfg_open_controller(ctl_handle, NULL);
2433 			if (ret < 0) {
2434 				(void) fprintf(stderr, "%s\n",
2435 				    raidcfg_errstr(ret));
2436 				return (FAILURE);
2437 			}
2438 		}
2439 
2440 		if ((disks_handlep[i] =
2441 		    raidcfg_get_disk(ctl_handle, disk_tag)) < 0) {
2442 			(void) fprintf(stderr, "%s\n",
2443 			    raidcfg_errstr(disks_handlep[i]));
2444 			(void) raidcfg_close_controller(ctl_handle, NULL);
2445 			return (FAILURE);
2446 		}
2447 	}
2448 
2449 	return (SUCCESS);
2450 }
2451 
2452 /*
2453  * get_ctl_tag(argp)
2454  * This function translates controller string to tag. The return value is
2455  * SUCCESS if the string has legal format and is parsed successfully,
2456  * or FAILURE if it fails.
2457  */
2458 static int
2459 get_ctl_tag(char *argp, uint32_t *ctl_tagp)
2460 {
2461 	if (argp == NULL || is_fully_numeric(argp) == FALSE ||
2462 	    ctl_tagp == NULL) {
2463 		return (FAILURE);
2464 	}
2465 	*ctl_tagp = (atoi(argp));
2466 	return (SUCCESS);
2467 }
2468 
2469 /*
2470  * get_array_tag(argp, ctl_tagp, array_tagp)
2471  * This function parses array string to get array tag and controller tag.
2472  * The return value is SUCCESS if the string has legal format, or
2473  * FAILURE if it fails.
2474  */
2475 static int
2476 get_array_tag(char *argp, uint32_t *ctl_tagp, array_tag_t *array_tagp)
2477 {
2478 	char *t = NULL;
2479 	char *cp = NULL;
2480 	char *tp = NULL;
2481 	char *dp = NULL;
2482 
2483 	uint32_t value_c = MAX32BIT;
2484 	uint32_t value_t = MAX32BIT;
2485 	uint32_t value_d = MAX32BIT;
2486 
2487 	int len = 0;
2488 
2489 	if (argp == NULL || (len = strlen(argp)) == 0 ||
2490 	    array_tagp == NULL) {
2491 		return (FAILURE);
2492 	}
2493 
2494 	t = (char *)malloc(len + 1);
2495 	if (t == NULL) {
2496 		return (FAILURE);
2497 	}
2498 
2499 	(void) memcpy(t, argp, len + 1);
2500 
2501 	/* Now remmber to release t memory if exception occurs */
2502 	if (((dp = strchr(t, 'd')) == NULL) ||
2503 	    ((tp = strchr(t, 't')) == NULL) ||
2504 	    ((cp = strchr(t, 'c')) == NULL)) {
2505 		free(t);
2506 		return (FAILURE);
2507 	}
2508 	cp = t;
2509 
2510 	*dp = '\0';
2511 	dp++;
2512 	*tp = '\0';
2513 	tp++;
2514 	cp++;
2515 
2516 	if (is_fully_numeric(dp) == FALSE ||
2517 	    is_fully_numeric(tp) == FALSE ||
2518 	    is_fully_numeric(cp) == FALSE) {
2519 		free(t);
2520 		return (FAILURE);
2521 	}
2522 
2523 	value_c = atoi(cp);
2524 	value_t = atoi(tp);
2525 	value_d = atoi(dp);
2526 
2527 	array_tagp->idl.target_id = value_t;
2528 	array_tagp->idl.lun = value_d;
2529 
2530 	if (ctl_tagp != NULL) {
2531 		*ctl_tagp = value_c;
2532 	}
2533 
2534 	free(t);
2535 	return (SUCCESS);
2536 }
2537 
2538 /*
2539  * get_disk_tag_ctd(argp, disk_tagp)
2540  * This function parses disk string of ctd format, and translates it to
2541  * disk tag and controller tag. The tags is returned by out parameters.
2542  * The return value is SUCCESS if the string has legal format, or FAILURE
2543  * if it fails.
2544  */
2545 static int
2546 get_disk_tag_ctd(char *argp, disk_tag_t *disk_tagp, uint32_t *ctl_tag)
2547 {
2548 	char *t = NULL;
2549 	char *cp = NULL;
2550 	char *tp = NULL;
2551 	char *dp = NULL;
2552 
2553 	uint32_t value_c = MAX32BIT;
2554 	uint32_t value_t = MAX32BIT;
2555 	uint32_t value_d = MAX32BIT;
2556 
2557 	int len = 0;
2558 
2559 	if (argp == NULL || (len = strlen(argp)) == 0 ||
2560 	    disk_tagp == NULL) {
2561 		return (FAILURE);
2562 	}
2563 
2564 	t = (char *)malloc(len + 1);
2565 	if (t == NULL) {
2566 		return (FAILURE);
2567 	}
2568 
2569 	(void) memcpy(t, argp, len + 1);
2570 
2571 	/* Now remmber to release t memory if exception occurs */
2572 	if (((dp = strchr(t, 'd')) == NULL) ||
2573 	    ((tp = strchr(t, 't')) == NULL) ||
2574 	    ((cp = strchr(t, 'c')) == NULL)) {
2575 		free(t);
2576 		return (FAILURE);
2577 	}
2578 	cp = t;
2579 
2580 	*dp = '\0';
2581 	dp++;
2582 	*tp = '\0';
2583 	tp++;
2584 	cp++;
2585 
2586 	if (is_fully_numeric(dp) == FALSE ||
2587 	    is_fully_numeric(tp) == FALSE ||
2588 	    is_fully_numeric(cp) == FALSE) {
2589 		free(t);
2590 		return (FAILURE);
2591 	}
2592 
2593 	value_c = atoi(cp);
2594 	value_t = atoi(tp);
2595 	value_d = atoi(dp);
2596 
2597 	disk_tagp->cidl.bus = 0;
2598 	disk_tagp->cidl.target_id = value_t;
2599 	disk_tagp->cidl.lun = value_d;
2600 	*ctl_tag = value_c;
2601 
2602 	free(t);
2603 	return (SUCCESS);
2604 }
2605 
2606 /*
2607  * get_disk_tag_cidl(argp, disk_tagp)
2608  * This function parses disk string of cidl format and translates it to tag.
2609  * The return value is disk tag if the string has legal format, or FAILURE
2610  * if it fails.
2611  */
2612 static int
2613 get_disk_tag_cidl(char *argp, disk_tag_t *disk_tagp)
2614 {
2615 	int len = 0;
2616 	char *p = NULL;
2617 	char *t = NULL;
2618 	char *dot1p = NULL;
2619 	char *dot2p = NULL;
2620 
2621 	if (argp == NULL || (len = strlen(argp)) == 0) {
2622 		return (FAILURE);
2623 	}
2624 
2625 	if (disk_tagp == NULL) {
2626 		return (FAILURE);
2627 	}
2628 
2629 	t = (char *)malloc(len + 1);
2630 	if (t == NULL) {
2631 		return (FAILURE);
2632 	}
2633 
2634 	(void) memcpy(t, argp, len + 1);
2635 	p = t;
2636 
2637 	dot2p = strrchr(p, '.');
2638 	if (dot2p == NULL) {
2639 		free(t);
2640 		return (FAILURE);
2641 	}
2642 	*dot2p = '\0';
2643 	dot2p++;
2644 
2645 	dot1p = strrchr(p, '.');
2646 	if (dot1p == NULL) {
2647 		free(t);
2648 		return (FAILURE);
2649 	}
2650 	*dot1p = '\0';
2651 	dot1p++;
2652 
2653 	/* Assert only 2 dots in this string */
2654 	if (strrchr(p, '.') != NULL) {
2655 		free(t);
2656 		return (FAILURE);
2657 	}
2658 
2659 	while (*p == ' ')
2660 		p++;
2661 
2662 	if (is_fully_numeric(p) == FALSE ||
2663 	    is_fully_numeric(dot1p) == FALSE ||
2664 	    is_fully_numeric(dot2p) == FALSE) {
2665 		free(t);
2666 		return (FAILURE);
2667 	}
2668 
2669 	disk_tagp->cidl.bus = atoi(p);
2670 	disk_tagp->cidl.target_id = atoi(dot1p);
2671 	disk_tagp->cidl.lun = atoi(dot2p);
2672 
2673 	free(t);
2674 	return (SUCCESS);
2675 }
2676 
2677 /*
2678  * calc_size(sizep, valp)
2679  * This function calculates the value represented by string sizep.
2680  * The string sizep can be decomposed into three parts: an initial,
2681  * possibly empty, sequence of white-space characters; a subject digital
2682  * sequence interpreted as an integer with unit k/K/m/M/g/G/t/T; and a
2683  * final string of one or more unrecognized characters or white-sapce
2684  * characters, including the terminating null. If unrecognized character
2685  * exists or overflow happens, the conversion must fail and return
2686  * INVALID_ARG. If the conversion is performed successfully, result will
2687  * be saved into valp and function returns SUCCESS. It returns FAILURE
2688  * when memory allocation fails.
2689  */
2690 static int
2691 calc_size(char *sizep, uint64_t *valp)
2692 {
2693 	int len;
2694 	uint64_t size;
2695 	uint64_t unit;
2696 	char *t = NULL;
2697 	char *tailp = NULL;
2698 
2699 	if (sizep == NULL || valp == NULL) {
2700 		return (INVALID_ARG);
2701 	}
2702 
2703 	if (is_fully_numeric(sizep) == TRUE) {
2704 		*valp = atoi(sizep);
2705 		return (SUCCESS);
2706 	}
2707 
2708 	len = strlen(sizep);
2709 	if (len == 0) {
2710 		return (INVALID_ARG);
2711 	}
2712 
2713 	t = (char *)malloc(len + 1);
2714 	if (t == NULL) {
2715 		return (FAILURE);
2716 	}
2717 
2718 	(void) memcpy(t, sizep, len + 1);
2719 
2720 	switch (*(t + len - 1)) {
2721 	case 'k':
2722 	case 'K':
2723 		unit = 1024ull;
2724 		errno = 0;
2725 		size = strtoll(t, &tailp, 0);
2726 		break;
2727 	case 'm':
2728 	case 'M':
2729 		unit = 1024ull * 1024ull;
2730 		errno = 0;
2731 		size = strtoll(t, &tailp, 0);
2732 		break;
2733 	case 'g':
2734 	case 'G':
2735 		unit = 1024ull * 1024ull * 1024ull;
2736 		errno = 0;
2737 		size = strtoll(t, &tailp, 0);
2738 		break;
2739 	case 't':
2740 	case 'T':
2741 		unit = 1024ull * 1024ull * 1024ull * 1024ull;
2742 		errno = 0;
2743 		size = strtoll(t, &tailp, 0);
2744 		break;
2745 	default:
2746 		/* The unit must be kilobyte at least. */
2747 		free(t);
2748 		return (INVALID_ARG);
2749 	}
2750 
2751 	*(t + len - 1) = '\0';
2752 	if (is_fully_numeric(t) != TRUE) {
2753 		free(t);
2754 		return (INVALID_ARG);
2755 	}
2756 
2757 	errno = 0;
2758 	size = strtoll(t, &tailp, 0);
2759 
2760 	/* Check overflow condition */
2761 	if (errno == ERANGE || (size > (MAX64BIT / unit))) {
2762 		free(t);
2763 		return (INVALID_ARG);
2764 	}
2765 
2766 	*valp = size * unit;
2767 	free(t);
2768 	return (SUCCESS);
2769 }
2770 
2771 /*
2772  * is_fully_numeric(str)
2773  * This function checks if the string are legal numeric string. The beginning
2774  * or ending characters can be white spaces.
2775  * Return value is TRUE if the string are legal numeric string, or FALSE
2776  * otherwise.
2777  */
2778 static int
2779 is_fully_numeric(char *strp)
2780 {
2781 	uint32_t len;
2782 	uint32_t i;
2783 
2784 	if (strp == NULL) {
2785 		return (FALSE);
2786 	}
2787 
2788 	len = strlen(strp);
2789 	if (len == 0) {
2790 		return (FALSE);
2791 	}
2792 
2793 	/* Skip whitespace characters */
2794 	for (i = 0; i < len; i++) {
2795 		if (strp[i] != ' ') {
2796 			break;
2797 		}
2798 	}
2799 
2800 	/* if strp points all space characters */
2801 	if (i == len) {
2802 		return (FALSE);
2803 	}
2804 
2805 	/* Check the digitals in string */
2806 	for (; i < len; i++) {
2807 		if (!isdigit(strp[i])) {
2808 			break;
2809 		}
2810 	}
2811 
2812 	/* Check the ending string */
2813 	for (; i < len; i++) {
2814 		if (strp[i] != ' ') {
2815 			return (FALSE);
2816 		}
2817 	}
2818 
2819 	return (TRUE);
2820 }
2821 
2822 static int
2823 yes(void)
2824 {
2825 	int	i, b;
2826 	char    ans[SCHAR_MAX + 1];
2827 
2828 	for (i = 0; ; i++) {
2829 		b = getchar();
2830 		if (b == '\n' || b == '\0' || b == EOF) {
2831 			ans[i] = 0;
2832 			break;
2833 		}
2834 		if (i < SCHAR_MAX) {
2835 			ans[i] = b;
2836 		}
2837 	}
2838 	if (i >= SCHAR_MAX) {
2839 		i = SCHAR_MAX;
2840 		ans[SCHAR_MAX] = 0;
2841 	}
2842 
2843 	return (rpmatch(ans));
2844 }
2845 
2846 /*
2847  * Function: int rpmatch(char *)
2848  *
2849  * Description:
2850  *
2851  *	Internationalized get yes / no answer.
2852  *
2853  * Inputs:
2854  *	s	-> Pointer to answer to compare against.
2855  *
2856  * Returns:
2857  *	TRUE	-> Answer was affirmative
2858  *	FALSE	-> Answer was negative
2859  */
2860 
2861 static int
2862 rpmatch(char *s)
2863 {
2864 	int	status;
2865 
2866 	/* match yesexpr */
2867 	status = regexec(&re, s, (size_t)0, NULL, 0);
2868 	if (status != 0) {
2869 		return (FALSE);
2870 	}
2871 	return (TRUE);
2872 }
2873 
2874 static int
2875 size_to_string(uint64_t size, char *string, int len)
2876 {
2877 	int i = 0;
2878 	uint32_t remainder;
2879 	char unit[][2] = {" ", "K", "M", "G", "T"};
2880 
2881 	if (string == NULL) {
2882 		return (FAILURE);
2883 	}
2884 	while (size > 1023) {
2885 		remainder = size % 1024;
2886 		size /= 1024;
2887 		i++;
2888 	}
2889 
2890 	if (i > 4) {
2891 		return (FAILURE);
2892 	}
2893 
2894 	remainder /= 103;
2895 	if (remainder == 0) {
2896 		(void) snprintf(string, len, "%llu", size);
2897 	} else {
2898 		(void) snprintf(string, len, "%llu.%1u", size,
2899 		    remainder);
2900 	}
2901 
2902 	/* make sure there is one byte for unit */
2903 	if ((strlen(string) + 1) >=  len) {
2904 		return (FAILURE);
2905 	}
2906 	(void) strcat(string, unit[i]);
2907 
2908 	return (SUCCESS);
2909 }
2910 
2911 /*
2912  * Only one raidctl is running at one time.
2913  */
2914 static int
2915 enter_raidctl_lock(int *fd)
2916 {
2917 	int fd0 = -1;
2918 	struct flock lock;
2919 
2920 	fd0 = open(RAIDCTL_LOCKF, O_CREAT|O_WRONLY, 0600);
2921 	if (fd0 < 0) {
2922 		if (errno == EACCES) {
2923 			(void) fprintf(stderr,
2924 			    gettext("raidctl:must be root to run raidctl"
2925 			    ": %s\n"), strerror(errno));
2926 		} else {
2927 			(void) fprintf(stderr,
2928 			    gettext("raidctl:failed to open lockfile"
2929 			    " '"RAIDCTL_LOCKF"': %s\n"), strerror(errno));
2930 		}
2931 		return (FAILURE);
2932 	}
2933 
2934 	*fd = fd0;
2935 	lock.l_type = F_WRLCK;
2936 	lock.l_whence = SEEK_SET;
2937 	lock.l_start = 0;
2938 	lock.l_len = 0;
2939 
2940 	if ((fcntl(fd0, F_SETLK, &lock) == -1) &&
2941 	    (errno == EAGAIN || errno == EDEADLK)) {
2942 		if (fcntl(fd0, F_GETLK, &lock) == -1) {
2943 			(void) fprintf(stderr,
2944 			    gettext("raidctl:enter_filelock error\n"));
2945 			return (FAILURE);
2946 		}
2947 		(void) fprintf(stderr, gettext("raidctl:"
2948 		    "enter_filelock:filelock is owned "
2949 		    "by 'process %d'\n"), lock.l_pid);
2950 		return (FAILURE);
2951 	}
2952 
2953 	return (SUCCESS);
2954 }
2955 
2956 static void
2957 exit_raidctl_lock(int fd)
2958 {
2959 	struct flock lock;
2960 
2961 	lock.l_type = F_UNLCK;
2962 	lock.l_whence = SEEK_SET;
2963 	lock.l_start = 0;
2964 	lock.l_len = 0;
2965 	if (fcntl(fd, F_SETLK, &lock) == -1) {
2966 		(void) fprintf(stderr, gettext("raidctl: failed to"
2967 		    " exit_filelock: %s\n"),
2968 		    strerror(errno));
2969 	}
2970 	(void) close(fd);
2971 }
2972