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