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