xref: /titanic_52/usr/src/cmd/raidctl/raidctl.c (revision bd0f52d78d701efcad2c460df61b45677d041c35)
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\tCapacity\t"
2005 	    "Status\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 capacity[16];
2188 	char hsp[16];
2189 
2190 	raid_obj_handle_t hsp_handle;
2191 	raidcfg_hsp_t hsp_attr;
2192 	raidcfg_controller_t ctl_attr;
2193 	int ret;
2194 	char is_indent;
2195 
2196 	if (attrp == NULL) {
2197 		return (FAILURE);
2198 	}
2199 
2200 	(void) snprintf(vendor, sizeof (vendor), "%s", attrp->vendorid);
2201 	(void) printf("%s\t", vendor);
2202 
2203 	(void) snprintf(product, sizeof (product), "%s", attrp->productid);
2204 	(void) printf("%s\t", product);
2205 
2206 	if (attrp->capacity != MAX64BIT) {
2207 		if (size_to_string(attrp->capacity, capacity, 16) != SUCCESS) {
2208 			return (FAILURE);
2209 		}
2210 		(void) printf("%s\t\t", capacity);
2211 	} else {
2212 		(void) printf(gettext("N/A"));
2213 	}
2214 
2215 	if (attrp->state == DISK_STATE_GOOD) {
2216 		(void) printf(gettext("GOOD"));
2217 	} else if (attrp->state == DISK_STATE_FAILED) {
2218 		(void) printf(gettext("FAILED"));
2219 	} else {
2220 		(void) printf(gettext("N/A"));
2221 	}
2222 	(void) printf("\t");
2223 
2224 	/* Controller attribute */
2225 	if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) {
2226 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
2227 		return (FAILURE);
2228 	}
2229 
2230 	hsp_handle = raidcfg_list_head(disk_handle, OBJ_TYPE_HSP);
2231 	if (hsp_handle == 0) {
2232 		(void) printf(gettext("N/A\n"));
2233 	} else {
2234 		is_indent = FALSE;
2235 		while (hsp_handle > 0) {
2236 			if ((ret = raidcfg_get_attr(hsp_handle,
2237 			    &hsp_attr)) < 0) {
2238 				(void) fprintf(stderr, "%s\n",
2239 				    raidcfg_errstr(ret));
2240 				return (FAILURE);
2241 			}
2242 
2243 			if (is_indent == TRUE) {
2244 				(void) printf("\t\t\t\t\t\t\t");
2245 			} else {
2246 				is_indent = TRUE;
2247 			}
2248 
2249 			if (hsp_attr.type == HSP_TYPE_LOCAL) {
2250 				(void) snprintf(hsp, sizeof (hsp),
2251 				    "c%ut%llud%llu",
2252 				    ctl_attr.controller_id,
2253 				    hsp_attr.tag.idl.target_id,
2254 				    hsp_attr.tag.idl.lun);
2255 				(void) printf("%s\n", hsp);
2256 			} else if (hsp_attr.type == HSP_TYPE_GLOBAL) {
2257 				(void) printf(gettext("Global\n"));
2258 			} else {
2259 				return (FAILURE);
2260 			}
2261 
2262 			hsp_handle = raidcfg_list_next(hsp_handle);
2263 		}
2264 	}
2265 	return (SUCCESS);
2266 }
2267 
2268 
2269 /*
2270  * print_indent(indent)
2271  * This function prints specified number of tab characters. It's used to
2272  * format layout.
2273  */
2274 static void
2275 print_indent(uint8_t indent)
2276 {
2277 	uint32_t i;
2278 	for (i = 0; i < indent; i++) {
2279 		(void) fprintf(stdout, "\t");
2280 	}
2281 }
2282 
2283 /*
2284  * get_disk_handle_cidl(ctl_tag, disks_argp, comps_num, handlespp)
2285  * This function parses the string of disk argument, and gets the disks tag
2286  * and separators from the string. Then it translates the tag to handle, and
2287  * stores handles and separators to new buffer pointed by parameter handlespp.
2288  * The format of disk_arg must be C:ID:L, for example, it is 0.1.0. The first
2289  * "0" is channel number, and the second "1" is target number, and the third
2290  * "0" is LUN number. The disk tags are separated by comma and parenthesis.
2291  * Function returns SUCCESS or FAILURE.
2292  */
2293 static int
2294 get_disk_handle_cidl(uint32_t ctl_tag, char *disks_argp, int *comps_nump,
2295 	raid_obj_handle_t **handlespp)
2296 {
2297 	int len = 0;
2298 	int i = 0, j = 0;
2299 	char *p, *t;
2300 	char *delimit = " ";
2301 	char *disks_str;
2302 	disk_tag_t disk_tag;
2303 
2304 	if (disks_argp == NULL || comps_nump == NULL) {
2305 		return (FAILURE);
2306 	}
2307 
2308 	p = disks_argp;
2309 	len = strlen(disks_argp);
2310 
2311 	if ((disks_str = (char *)malloc(3 * len + 4)) == NULL) {
2312 		return (FAILURE);
2313 	}
2314 
2315 	/* Insert whitespace between disk tags, '(' , and ')' */
2316 	disks_str[j ++] = '(';
2317 	disks_str[j ++] = ' ';
2318 
2319 	while (p[i] != '\0') {
2320 		if (p[i] == ')' || p[i] == '(') {
2321 			disks_str[j ++] = ' ';
2322 			disks_str[j ++] = p[i];
2323 			disks_str[j ++] = ' ';
2324 		} else
2325 			disks_str[j ++] = p[i];
2326 		i ++;
2327 	}
2328 	disks_str[j ++] = ' ';
2329 	disks_str[j ++] = ')';
2330 	disks_str[j] = '\0';
2331 
2332 	len = strlen(disks_str) + 1;
2333 
2334 	if ((t = (char *)malloc(len)) == NULL) {
2335 		return (FAILURE);
2336 	}
2337 	(void) memcpy(t, disks_str, len);
2338 	p = strtok(t, delimit);
2339 	while (p != NULL) {
2340 		(*comps_nump)++;
2341 		p = strtok(NULL, delimit);
2342 	}
2343 	free(t);
2344 
2345 	*handlespp = calloc(*comps_nump, sizeof (raid_obj_handle_t));
2346 	if (*handlespp == NULL) {
2347 		return (FAILURE);
2348 	}
2349 
2350 	for (i = 0; i < *comps_nump; i++)
2351 		(*handlespp)[i] = INIT_HANDLE_VALUE;
2352 
2353 	i = 0;
2354 	p = strtok(disks_str, delimit);
2355 	while (p != NULL) {
2356 		if (*p == '(') {
2357 			(*handlespp)[i] = OBJ_SEPARATOR_BEGIN;
2358 		} else if (*p == ')') {
2359 			(*handlespp)[i] = OBJ_SEPARATOR_END;
2360 		} else {
2361 			if (get_disk_tag_cidl(p, &disk_tag) != SUCCESS) {
2362 				free(*handlespp);
2363 				free(disks_str);
2364 				return (INVALID_ARG);
2365 			}
2366 			(*handlespp)[i] =
2367 			    raidcfg_get_disk(raidcfg_get_controller(ctl_tag),
2368 			    disk_tag);
2369 			if ((*handlespp)[i] <= 0) {
2370 				(void) fprintf(stderr, "%s\n",
2371 				    raidcfg_errstr((*handlespp)[i]));
2372 				free(*handlespp);
2373 				free(disks_str);
2374 				return (FAILURE);
2375 			}
2376 		}
2377 		p = strtok(NULL, delimit);
2378 		i++;
2379 	}
2380 
2381 	free(disks_str);
2382 	return (SUCCESS);
2383 }
2384 
2385 /*
2386  * get_disk_handle_ctd(disks_num, disks_argpp, ctl_tagp, disks_handlep)
2387  * This function parses string of single disk with "ctd" format, for example,
2388  * c0t0d0, and translates it to controller tag and disk tag.
2389  * Then it calls lib api and get disk handle. The controller tag and disk
2390  * handle are both returned by out parameters.
2391  * The return value is SUCCESS or FAILURE.
2392  */
2393 static int
2394 get_disk_handle_ctd(int disks_num, char **disks_argpp, uint32_t *ctl_tagp,
2395 	raid_obj_handle_t *disks_handlep)
2396 {
2397 	raid_obj_handle_t ctl_handle;
2398 	disk_tag_t disk_tag;
2399 	uint32_t ctl_id;
2400 	int i;
2401 	int ret;
2402 
2403 	if (disks_handlep == NULL) {
2404 		return (FAILURE);
2405 	}
2406 
2407 	for (i = 0; i < disks_num; i++) {
2408 		if (get_disk_tag_ctd(disks_argpp[i], &disk_tag, &ctl_id) !=
2409 		    SUCCESS) {
2410 			return (INVALID_ARG);
2411 		}
2412 
2413 		*ctl_tagp = ctl_id;
2414 
2415 		if (i == 0) {
2416 			ctl_handle = raidcfg_get_controller(*ctl_tagp);
2417 			if (ctl_handle <= 0) {
2418 				(void) fprintf(stderr, "%s\n",
2419 				    raidcfg_errstr(ctl_handle));
2420 				return (FAILURE);
2421 			}
2422 			ret = raidcfg_open_controller(ctl_handle, NULL);
2423 			if (ret < 0) {
2424 				(void) fprintf(stderr, "%s\n",
2425 				    raidcfg_errstr(ret));
2426 				return (FAILURE);
2427 			}
2428 		}
2429 
2430 		if ((disks_handlep[i] =
2431 		    raidcfg_get_disk(ctl_handle, disk_tag)) < 0) {
2432 			(void) fprintf(stderr, "%s\n",
2433 			    raidcfg_errstr(disks_handlep[i]));
2434 			(void) raidcfg_close_controller(ctl_handle, NULL);
2435 			return (FAILURE);
2436 		}
2437 	}
2438 
2439 	return (SUCCESS);
2440 }
2441 
2442 /*
2443  * get_ctl_tag(argp)
2444  * This function translates controller string to tag. The return value is
2445  * SUCCESS if the string has legal format and is parsed successfully,
2446  * or FAILURE if it fails.
2447  */
2448 static int
2449 get_ctl_tag(char *argp, uint32_t *ctl_tagp)
2450 {
2451 	if (argp == NULL || is_fully_numeric(argp) == FALSE ||
2452 	    ctl_tagp == NULL) {
2453 		return (FAILURE);
2454 	}
2455 	*ctl_tagp = (atoi(argp));
2456 	return (SUCCESS);
2457 }
2458 
2459 /*
2460  * get_array_tag(argp, ctl_tagp, array_tagp)
2461  * This function parses array string to get array tag and controller tag.
2462  * The return value is SUCCESS if the string has legal format, or
2463  * FAILURE if it fails.
2464  */
2465 static int
2466 get_array_tag(char *argp, uint32_t *ctl_tagp, array_tag_t *array_tagp)
2467 {
2468 	char *t = NULL;
2469 	char *cp = NULL;
2470 	char *tp = NULL;
2471 	char *dp = NULL;
2472 
2473 	uint32_t value_c = MAX32BIT;
2474 	uint32_t value_t = MAX32BIT;
2475 	uint32_t value_d = MAX32BIT;
2476 
2477 	int len = 0;
2478 
2479 	if (argp == NULL || (len = strlen(argp)) == 0 ||
2480 	    array_tagp == NULL) {
2481 		return (FAILURE);
2482 	}
2483 
2484 	t = (char *)malloc(len + 1);
2485 	if (t == NULL) {
2486 		return (FAILURE);
2487 	}
2488 
2489 	(void) memcpy(t, argp, len + 1);
2490 
2491 	/* Now remmber to release t memory if exception occurs */
2492 	if (((dp = strchr(t, 'd')) == NULL) ||
2493 	    ((tp = strchr(t, 't')) == NULL) ||
2494 	    ((cp = strchr(t, 'c')) == NULL)) {
2495 		free(t);
2496 		return (FAILURE);
2497 	}
2498 	cp = t;
2499 
2500 	*dp = '\0';
2501 	dp++;
2502 	*tp = '\0';
2503 	tp++;
2504 	cp++;
2505 
2506 	if (is_fully_numeric(dp) == FALSE ||
2507 	    is_fully_numeric(tp) == FALSE ||
2508 	    is_fully_numeric(cp) == FALSE) {
2509 		free(t);
2510 		return (FAILURE);
2511 	}
2512 
2513 	value_c = atoi(cp);
2514 	value_t = atoi(tp);
2515 	value_d = atoi(dp);
2516 
2517 	array_tagp->idl.target_id = value_t;
2518 	array_tagp->idl.lun = value_d;
2519 
2520 	if (ctl_tagp != NULL) {
2521 		*ctl_tagp = value_c;
2522 	}
2523 
2524 	free(t);
2525 	return (SUCCESS);
2526 }
2527 
2528 /*
2529  * get_disk_tag_ctd(argp, disk_tagp)
2530  * This function parses disk string of ctd format, and translates it to
2531  * disk tag and controller tag. The tags is returned by out parameters.
2532  * The return value is SUCCESS if the string has legal format, or FAILURE
2533  * if it fails.
2534  */
2535 static int
2536 get_disk_tag_ctd(char *argp, disk_tag_t *disk_tagp, uint32_t *ctl_tag)
2537 {
2538 	char *t = NULL;
2539 	char *cp = NULL;
2540 	char *tp = NULL;
2541 	char *dp = NULL;
2542 
2543 	uint32_t value_c = MAX32BIT;
2544 	uint32_t value_t = MAX32BIT;
2545 	uint32_t value_d = MAX32BIT;
2546 
2547 	int len = 0;
2548 
2549 	if (argp == NULL || (len = strlen(argp)) == 0 ||
2550 	    disk_tagp == NULL) {
2551 		return (FAILURE);
2552 	}
2553 
2554 	t = (char *)malloc(len + 1);
2555 	if (t == NULL) {
2556 		return (FAILURE);
2557 	}
2558 
2559 	(void) memcpy(t, argp, len + 1);
2560 
2561 	/* Now remmber to release t memory if exception occurs */
2562 	if (((dp = strchr(t, 'd')) == NULL) ||
2563 	    ((tp = strchr(t, 't')) == NULL) ||
2564 	    ((cp = strchr(t, 'c')) == NULL)) {
2565 		free(t);
2566 		return (FAILURE);
2567 	}
2568 	cp = t;
2569 
2570 	*dp = '\0';
2571 	dp++;
2572 	*tp = '\0';
2573 	tp++;
2574 	cp++;
2575 
2576 	if (is_fully_numeric(dp) == FALSE ||
2577 	    is_fully_numeric(tp) == FALSE ||
2578 	    is_fully_numeric(cp) == FALSE) {
2579 		free(t);
2580 		return (FAILURE);
2581 	}
2582 
2583 	value_c = atoi(cp);
2584 	value_t = atoi(tp);
2585 	value_d = atoi(dp);
2586 
2587 	disk_tagp->cidl.bus = 0;
2588 	disk_tagp->cidl.target_id = value_t;
2589 	disk_tagp->cidl.lun = value_d;
2590 	*ctl_tag = value_c;
2591 
2592 	free(t);
2593 	return (SUCCESS);
2594 }
2595 
2596 /*
2597  * get_disk_tag_cidl(argp, disk_tagp)
2598  * This function parses disk string of cidl format and translates it to tag.
2599  * The return value is disk tag if the string has legal format, or FAILURE
2600  * if it fails.
2601  */
2602 static int
2603 get_disk_tag_cidl(char *argp, disk_tag_t *disk_tagp)
2604 {
2605 	int len = 0;
2606 	char *p = NULL;
2607 	char *t = NULL;
2608 	char *dot1p = NULL;
2609 	char *dot2p = NULL;
2610 
2611 	if (argp == NULL || (len = strlen(argp)) == 0) {
2612 		return (FAILURE);
2613 	}
2614 
2615 	if (disk_tagp == NULL) {
2616 		return (FAILURE);
2617 	}
2618 
2619 	t = (char *)malloc(len + 1);
2620 	if (t == NULL) {
2621 		return (FAILURE);
2622 	}
2623 
2624 	(void) memcpy(t, argp, len + 1);
2625 	p = t;
2626 
2627 	dot2p = strrchr(p, '.');
2628 	if (dot2p == NULL) {
2629 		free(t);
2630 		return (FAILURE);
2631 	}
2632 	*dot2p = '\0';
2633 	dot2p++;
2634 
2635 	dot1p = strrchr(p, '.');
2636 	if (dot1p == NULL) {
2637 		free(t);
2638 		return (FAILURE);
2639 	}
2640 	*dot1p = '\0';
2641 	dot1p++;
2642 
2643 	/* Assert only 2 dots in this string */
2644 	if (strrchr(p, '.') != NULL) {
2645 		free(t);
2646 		return (FAILURE);
2647 	}
2648 
2649 	while (*p == ' ')
2650 		p++;
2651 
2652 	if (is_fully_numeric(p) == FALSE ||
2653 	    is_fully_numeric(dot1p) == FALSE ||
2654 	    is_fully_numeric(dot2p) == FALSE) {
2655 		free(t);
2656 		return (FAILURE);
2657 	}
2658 
2659 	disk_tagp->cidl.bus = atoi(p);
2660 	disk_tagp->cidl.target_id = atoi(dot1p);
2661 	disk_tagp->cidl.lun = atoi(dot2p);
2662 
2663 	free(t);
2664 	return (SUCCESS);
2665 }
2666 
2667 /*
2668  * calc_size(sizep, valp)
2669  * This function calculates the value represented by string sizep.
2670  * The string sizep can be decomposed into three parts: an initial,
2671  * possibly empty, sequence of white-space characters; a subject digital
2672  * sequence interpreted as an integer with unit k/K/m/M/g/G/t/T; and a
2673  * final string of one or more unrecognized characters or white-sapce
2674  * characters, including the terminating null. If unrecognized character
2675  * exists or overflow happens, the conversion must fail and return
2676  * INVALID_ARG. If the conversion is performed successfully, result will
2677  * be saved into valp and function returns SUCCESS. It returns FAILURE
2678  * when memory allocation fails.
2679  */
2680 static int
2681 calc_size(char *sizep, uint64_t *valp)
2682 {
2683 	int len;
2684 	uint64_t size;
2685 	uint64_t unit;
2686 	char *t = NULL;
2687 	char *tailp = NULL;
2688 
2689 	if (sizep == NULL || valp == NULL) {
2690 		return (INVALID_ARG);
2691 	}
2692 
2693 	if (is_fully_numeric(sizep) == TRUE) {
2694 		*valp = atoi(sizep);
2695 		return (SUCCESS);
2696 	}
2697 
2698 	len = strlen(sizep);
2699 	if (len == 0) {
2700 		return (INVALID_ARG);
2701 	}
2702 
2703 	t = (char *)malloc(len + 1);
2704 	if (t == NULL) {
2705 		return (FAILURE);
2706 	}
2707 
2708 	(void) memcpy(t, sizep, len + 1);
2709 
2710 	switch (*(t + len - 1)) {
2711 	case 'k':
2712 	case 'K':
2713 		unit = 1024ull;
2714 		errno = 0;
2715 		size = strtoll(t, &tailp, 0);
2716 		break;
2717 	case 'm':
2718 	case 'M':
2719 		unit = 1024ull * 1024ull;
2720 		errno = 0;
2721 		size = strtoll(t, &tailp, 0);
2722 		break;
2723 	case 'g':
2724 	case 'G':
2725 		unit = 1024ull * 1024ull * 1024ull;
2726 		errno = 0;
2727 		size = strtoll(t, &tailp, 0);
2728 		break;
2729 	case 't':
2730 	case 'T':
2731 		unit = 1024ull * 1024ull * 1024ull * 1024ull;
2732 		errno = 0;
2733 		size = strtoll(t, &tailp, 0);
2734 		break;
2735 	default:
2736 		/* The unit must be kilobyte at least. */
2737 		free(t);
2738 		return (INVALID_ARG);
2739 	}
2740 
2741 	*(t + len - 1) = '\0';
2742 	if (is_fully_numeric(t) != TRUE) {
2743 		free(t);
2744 		return (INVALID_ARG);
2745 	}
2746 
2747 	errno = 0;
2748 	size = strtoll(t, &tailp, 0);
2749 
2750 	/* Check overflow condition */
2751 	if (errno == ERANGE || (size > (MAX64BIT / unit))) {
2752 		free(t);
2753 		return (INVALID_ARG);
2754 	}
2755 
2756 	*valp = size * unit;
2757 	free(t);
2758 	return (SUCCESS);
2759 }
2760 
2761 /*
2762  * is_fully_numeric(str)
2763  * This function checks if the string are legal numeric string. The beginning
2764  * or ending characters can be white spaces.
2765  * Return value is TRUE if the string are legal numeric string, or FALSE
2766  * otherwise.
2767  */
2768 static int
2769 is_fully_numeric(char *strp)
2770 {
2771 	uint32_t len;
2772 	uint32_t i;
2773 
2774 	if (strp == NULL) {
2775 		return (FALSE);
2776 	}
2777 
2778 	len = strlen(strp);
2779 	if (len == 0) {
2780 		return (FALSE);
2781 	}
2782 
2783 	/* Skip whitespace characters */
2784 	for (i = 0; i < len; i++) {
2785 		if (strp[i] != ' ') {
2786 			break;
2787 		}
2788 	}
2789 
2790 	/* if strp points all space characters */
2791 	if (i == len) {
2792 		return (FALSE);
2793 	}
2794 
2795 	/* Check the digitals in string */
2796 	for (; i < len; i++) {
2797 		if (!isdigit(strp[i])) {
2798 			break;
2799 		}
2800 	}
2801 
2802 	/* Check the ending string */
2803 	for (; i < len; i++) {
2804 		if (strp[i] != ' ') {
2805 			return (FALSE);
2806 		}
2807 	}
2808 
2809 	return (TRUE);
2810 }
2811 
2812 static int
2813 yes(void)
2814 {
2815 	int	i, b;
2816 	char    ans[SCHAR_MAX + 1];
2817 
2818 	for (i = 0; ; i++) {
2819 		b = getchar();
2820 		if (b == '\n' || b == '\0' || b == EOF) {
2821 			ans[i] = 0;
2822 			break;
2823 		}
2824 		if (i < SCHAR_MAX) {
2825 			ans[i] = b;
2826 		}
2827 	}
2828 	if (i >= SCHAR_MAX) {
2829 		i = SCHAR_MAX;
2830 		ans[SCHAR_MAX] = 0;
2831 	}
2832 
2833 	return (rpmatch(ans));
2834 }
2835 
2836 /*
2837  * Function: int rpmatch(char *)
2838  *
2839  * Description:
2840  *
2841  *	Internationalized get yes / no answer.
2842  *
2843  * Inputs:
2844  *	s	-> Pointer to answer to compare against.
2845  *
2846  * Returns:
2847  *	TRUE	-> Answer was affirmative
2848  *	FALSE	-> Answer was negative
2849  */
2850 
2851 static int
2852 rpmatch(char *s)
2853 {
2854 	int	status;
2855 
2856 	/* match yesexpr */
2857 	status = regexec(&re, s, (size_t)0, NULL, 0);
2858 	if (status != 0) {
2859 		return (FALSE);
2860 	}
2861 	return (TRUE);
2862 }
2863 
2864 static int
2865 size_to_string(uint64_t size, char *string, int len)
2866 {
2867 	int i = 0;
2868 	uint32_t remainder;
2869 	char unit[][2] = {" ", "K", "M", "G", "T"};
2870 
2871 	if (string == NULL) {
2872 		return (FAILURE);
2873 	}
2874 	while (size > 1023) {
2875 		remainder = size % 1024;
2876 		size /= 1024;
2877 		i++;
2878 	}
2879 
2880 	if (i > 4) {
2881 		return (FAILURE);
2882 	}
2883 
2884 	remainder /= 103;
2885 	if (remainder == 0) {
2886 		(void) snprintf(string, len, "%llu", size);
2887 	} else {
2888 		(void) snprintf(string, len, "%llu.%1u", size,
2889 		    remainder);
2890 	}
2891 
2892 	/* make sure there is one byte for unit */
2893 	if ((strlen(string) + 1) >=  len) {
2894 		return (FAILURE);
2895 	}
2896 	(void) strcat(string, unit[i]);
2897 
2898 	return (SUCCESS);
2899 }
2900 
2901 /*
2902  * Only one raidctl is running at one time.
2903  */
2904 static int
2905 enter_raidctl_lock(int *fd)
2906 {
2907 	int fd0 = -1;
2908 	struct flock lock;
2909 
2910 	fd0 = open(RAIDCTL_LOCKF, O_CREAT|O_WRONLY, 0600);
2911 	if (fd0 < 0) {
2912 		if (errno == EACCES) {
2913 			(void) fprintf(stderr,
2914 			    gettext("raidctl:must be root to run raidctl"
2915 			    ": %s\n"), strerror(errno));
2916 		} else {
2917 			(void) fprintf(stderr,
2918 			    gettext("raidctl:failed to open lockfile"
2919 			    " '"RAIDCTL_LOCKF"': %s\n"), strerror(errno));
2920 		}
2921 		return (FAILURE);
2922 	}
2923 
2924 	*fd = fd0;
2925 	lock.l_type = F_WRLCK;
2926 	lock.l_whence = SEEK_SET;
2927 	lock.l_start = 0;
2928 	lock.l_len = 0;
2929 
2930 	if ((fcntl(fd0, F_SETLK, &lock) == -1) &&
2931 	    (errno == EAGAIN || errno == EDEADLK)) {
2932 		if (fcntl(fd0, F_GETLK, &lock) == -1) {
2933 			(void) fprintf(stderr,
2934 			    gettext("raidctl:enter_filelock error\n"));
2935 			return (FAILURE);
2936 		}
2937 		(void) fprintf(stderr, gettext("raidctl:"
2938 		    "enter_filelock:filelock is owned "
2939 		    "by 'process %d'\n"), lock.l_pid);
2940 		return (FAILURE);
2941 	}
2942 
2943 	return (SUCCESS);
2944 }
2945 
2946 static void
2947 exit_raidctl_lock(int fd)
2948 {
2949 	struct flock lock;
2950 
2951 	lock.l_type = F_UNLCK;
2952 	lock.l_whence = SEEK_SET;
2953 	lock.l_start = 0;
2954 	lock.l_len = 0;
2955 	if (fcntl(fd, F_SETLK, &lock) == -1) {
2956 		(void) fprintf(stderr, gettext("raidctl: failed to"
2957 		    " exit_filelock: %s\n"),
2958 		    strerror(errno));
2959 	}
2960 	(void) close(fd);
2961 }
2962