xref: /titanic_53/usr/src/cmd/raidctl/raidctl.c (revision b449fa8aa1f53939091aeb3a5af8a8f3ba9d33dc)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57f000930Syw161884  * Common Development and Distribution License (the "License").
67f000930Syw161884  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
20711890bcSjc156560  *
21711890bcSjc156560  *
22a6e966d7Szk194757  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24711890bcSjc156560  *
25711890bcSjc156560  * raidctl.c is the entry file of RAID configuration utility.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <ctype.h>
31711890bcSjc156560 #include <sys/types.h>
32711890bcSjc156560 #include <sys/stat.h>
337c478bd9Sstevel@tonic-gate #include <fcntl.h>
347c478bd9Sstevel@tonic-gate #include <langinfo.h>
35711890bcSjc156560 #include <regex.h>
367c478bd9Sstevel@tonic-gate #include <locale.h>
37711890bcSjc156560 #include <libintl.h>
387c478bd9Sstevel@tonic-gate #include <stdio.h>
397c478bd9Sstevel@tonic-gate #include <stdlib.h>
407c478bd9Sstevel@tonic-gate #include <string.h>
417c478bd9Sstevel@tonic-gate #include <strings.h>
427c478bd9Sstevel@tonic-gate #include <unistd.h>
43711890bcSjc156560 #include <errno.h>
44711890bcSjc156560 #include <libgen.h>
45711890bcSjc156560 #include <raidcfg.h>
46711890bcSjc156560 
47711890bcSjc156560 
48711890bcSjc156560 #define	TRUE		1
49711890bcSjc156560 #define	FALSE		0
50711890bcSjc156560 
51711890bcSjc156560 #ifndef TEXT_DOMAIN
52711890bcSjc156560 #define	TEXT_DOMAIN "SYS_TEST"
53711890bcSjc156560 #endif
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate /*
56711890bcSjc156560  * Return value of command
577c478bd9Sstevel@tonic-gate  */
587c478bd9Sstevel@tonic-gate #define	SUCCESS		0
597c478bd9Sstevel@tonic-gate #define	INVALID_ARG	1
607c478bd9Sstevel@tonic-gate #define	FAILURE		2
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate /*
63711890bcSjc156560  * Initial value of variables
647c478bd9Sstevel@tonic-gate  */
65711890bcSjc156560 #define	INIT_HANDLE_VALUE	-3
66711890bcSjc156560 #define	MAX64BIT		0xffffffffffffffffull
67711890bcSjc156560 #define	MAX32BIT		0xfffffffful
687c478bd9Sstevel@tonic-gate 
69711890bcSjc156560 /*
70711890bcSjc156560  * Flag of set or unset HSP
71711890bcSjc156560  */
72711890bcSjc156560 #define	HSP_SET		1
73711890bcSjc156560 #define	HSP_UNSET	0
747c478bd9Sstevel@tonic-gate 
75711890bcSjc156560 /*
76711890bcSjc156560  * Operate codes of command
77711890bcSjc156560  */
78711890bcSjc156560 #define	DO_HW_RAID_NOP		-1
79711890bcSjc156560 #define	DO_HW_RAID_HELP		0
80711890bcSjc156560 #define	DO_HW_RAID_CREATEO	1
81711890bcSjc156560 #define	DO_HW_RAID_CREATEN	2
82711890bcSjc156560 #define	DO_HW_RAID_DELETE	3
83711890bcSjc156560 #define	DO_HW_RAID_LIST		4
84711890bcSjc156560 #define	DO_HW_RAID_FLASH	5
85711890bcSjc156560 #define	DO_HW_RAID_HSP		6
86711890bcSjc156560 #define	DO_HW_RAID_SET_ATTR	7
87711890bcSjc156560 #define	DO_HW_RAID_SNAPSHOT	8
887c478bd9Sstevel@tonic-gate 
89711890bcSjc156560 #define	LOWER_H	(1 << 0)
90711890bcSjc156560 #define	LOWER_C	(1 << 1)
91711890bcSjc156560 #define	LOWER_D	(1 << 2)
92711890bcSjc156560 #define	LOWER_L	(1 << 3)
93711890bcSjc156560 #define	LOWER_R	(1 << 4)
94711890bcSjc156560 #define	LOWER_Z	(1 << 5)
95711890bcSjc156560 #define	LOWER_G	(1 << 6)
96711890bcSjc156560 #define	LOWER_A	(1 << 7)
97711890bcSjc156560 #define	LOWER_S	(1 << 8)
98711890bcSjc156560 #define	LOWER_P	(1 << 9)
99711890bcSjc156560 #define	LOWER_F	(1 << 10)
100711890bcSjc156560 #define	UPPER_S	(1 << 11)
101711890bcSjc156560 #define	UPPER_C	(1 << 12)
102711890bcSjc156560 #define	UPPER_F	(1 << 13)
1037c478bd9Sstevel@tonic-gate 
104711890bcSjc156560 /* Add a ARRAY state (temporary) */
105711890bcSjc156560 #define	ARRAY_STATE_SYNC	100
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate /*
1087c478bd9Sstevel@tonic-gate  * Function and strings to properly localize our prompt.
109711890bcSjc156560  * So for example in German it would ask (ja/nein) or (yes/no) in
1107c478bd9Sstevel@tonic-gate  * english.
1117c478bd9Sstevel@tonic-gate  */
112711890bcSjc156560 #ifndef SCHAR_MAX
113711890bcSjc156560 #define	SCHAR_MAX	10
114711890bcSjc156560 #endif
115711890bcSjc156560 
116711890bcSjc156560 #define	RAIDCTL_LOCKF "/var/run/lockf_raidctl"
117711890bcSjc156560 
118711890bcSjc156560 /* Locale setting */
1196fec3791Sjesseb static int	yes(void);
120711890bcSjc156560 static int	rpmatch(char *s);
121711890bcSjc156560 static char	*yesstr = NULL;
122711890bcSjc156560 static char	*nostr = NULL;
123711890bcSjc156560 static char	*yesexpr = NULL;
1247c478bd9Sstevel@tonic-gate 
125711890bcSjc156560 static char	*default_yesexpr = "^[yY]";
126711890bcSjc156560 static char	*default_yesstr = "yes";
127711890bcSjc156560 static char	*default_nostr = "no";
1287c478bd9Sstevel@tonic-gate 
129711890bcSjc156560 static regex_t	re;
130711890bcSjc156560 
131711890bcSjc156560 #define	SET_DEFAULT_STRS \
132711890bcSjc156560 	regfree(&re); \
133711890bcSjc156560 	free(yesexpr); \
134711890bcSjc156560 	free(yesstr); \
135711890bcSjc156560 	free(nostr); \
136711890bcSjc156560 	yesexpr = default_yesexpr; \
137711890bcSjc156560 	yesstr = default_yesstr; \
138711890bcSjc156560 	nostr = default_nostr;
139711890bcSjc156560 
140711890bcSjc156560 #define	FREE_STRS \
141711890bcSjc156560 	if (yesexpr != default_yesexpr) \
142711890bcSjc156560 		free(yesexpr); \
143711890bcSjc156560 	if (yesstr != default_yesstr) \
144711890bcSjc156560 		free(yesstr); \
145711890bcSjc156560 	if (nostr != default_nostr) \
146711890bcSjc156560 		free(nostr);
147711890bcSjc156560 
148711890bcSjc156560 /* program name */
149711890bcSjc156560 static char	*prog_namep;
150711890bcSjc156560 
1517c478bd9Sstevel@tonic-gate 
1526fec3791Sjesseb /*
153711890bcSjc156560  * Functions declaration
1546fec3791Sjesseb  */
155711890bcSjc156560 static void helpinfo(char *prog_namep);
156711890bcSjc156560 static int do_create_cidl(char *raid_levelp, char *capacityp, char *disk_argp,
157711890bcSjc156560     char *stripe_sizep, uint32_t f_flag, char **argv, uint32_t optind);
158711890bcSjc156560 static int do_create_ctd(char *raid_levelp, char **disks_argpp,
159711890bcSjc156560     uint32_t disks_num, uint32_t argindex, uint32_t f_flag);
160711890bcSjc156560 static int do_list(char *disk_argp, char **argv, uint32_t optind,
161711890bcSjc156560     uint8_t is_snapshot);
162711890bcSjc156560 static int do_delete(uint32_t f_flag, char **argv, uint32_t optind);
163711890bcSjc156560 static int do_flash(uint8_t f_flag, char *filep, char **ctls_argpp,
164711890bcSjc156560     uint32_t index, uint32_t ctl_num);
165711890bcSjc156560 static int do_set_hsp(char *a_argp, char *disk_argp, char **argv,
166711890bcSjc156560     uint32_t optind);
167711890bcSjc156560 static int do_set_array_attr(uint32_t f_flag, char *p_argp, char **argv,
168711890bcSjc156560     uint32_t optind);
169711890bcSjc156560 static int snapshot_raidsystem(uint8_t recursive, uint8_t indent,
170711890bcSjc156560     uint8_t is_snapshot);
171711890bcSjc156560 static int snapshot_ctl(raid_obj_handle_t ctl_handle, uint8_t recursive,
172711890bcSjc156560     uint8_t indent, uint8_t is_snapshot);
173711890bcSjc156560 static int snapshot_array(raid_obj_handle_t array_handle,
174711890bcSjc156560     uint8_t indent, uint8_t is_sub, uint8_t is_snapshot);
175711890bcSjc156560 static int snapshot_disk(uint32_t ctl_tag, raid_obj_handle_t disk_handle,
176711890bcSjc156560     uint8_t indent, uint8_t is_snapshot);
177711890bcSjc156560 static int print_ctl_table(raid_obj_handle_t ctl_handle);
178711890bcSjc156560 static int print_array_table(raid_obj_handle_t ctl_handle,
179711890bcSjc156560     raid_obj_handle_t array_handle);
180711890bcSjc156560 static int print_disk_table(raid_obj_handle_t ctl_handle,
181711890bcSjc156560     raid_obj_handle_t disk_handle);
182711890bcSjc156560 static int print_ctl_attr(raidcfg_controller_t *attrp);
183711890bcSjc156560 static int print_array_attr(raidcfg_array_t *attrp);
184711890bcSjc156560 static int print_arraypart_attr(raidcfg_arraypart_t *attrp);
185711890bcSjc156560 static int print_disk_attr(raid_obj_handle_t ctl_handle,
186711890bcSjc156560     raid_obj_handle_t disk_handle, raidcfg_disk_t *attrp);
187711890bcSjc156560 static void print_indent(uint8_t indent);
188711890bcSjc156560 static int get_disk_handle_cidl(uint32_t ctl_tag, char *disks_argp,
189711890bcSjc156560     int *comps_nump, raid_obj_handle_t **handlespp);
190711890bcSjc156560 static int get_disk_handle_ctd(int disks_num, char **disks_argpp,
191711890bcSjc156560     uint32_t *ctl_tagp, raid_obj_handle_t *disks_handlep);
192711890bcSjc156560 static int get_ctl_tag(char *argp, uint32_t *ctl_tagp);
193711890bcSjc156560 static int get_array_tag(char *argp, uint32_t *ctl_tagp,
194711890bcSjc156560     array_tag_t *array_tagp);
195711890bcSjc156560 static int get_disk_tag_ctd(char *argp, disk_tag_t *disk_tagp,
196711890bcSjc156560     uint32_t *controller_id);
197711890bcSjc156560 static int get_disk_tag_cidl(char *argp, disk_tag_t *disk_tagp);
198711890bcSjc156560 static int calc_size(char *sizep, uint64_t *valp);
199711890bcSjc156560 static int is_fully_numeric(char *strp);
200711890bcSjc156560 static int size_to_string(uint64_t size, char *string, int len);
201711890bcSjc156560 static int enter_raidctl_lock(int *fd);
202711890bcSjc156560 static void exit_raidctl_lock(int fd);
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate /*
205711890bcSjc156560  * Entry function of raidctl command
2067c478bd9Sstevel@tonic-gate  */
207711890bcSjc156560 int
208711890bcSjc156560 main(int argc, char **argv)
2097c478bd9Sstevel@tonic-gate {
210711890bcSjc156560 	/* operation index */
211711890bcSjc156560 	int8_t findex = DO_HW_RAID_NOP;
2127c478bd9Sstevel@tonic-gate 
213711890bcSjc156560 	/* argument pointers */
214711890bcSjc156560 	char *r_argp = NULL;
215711890bcSjc156560 	char *z_argp = NULL;
216711890bcSjc156560 	char *g_argp = NULL;
217711890bcSjc156560 	char *a_argp = NULL;
218711890bcSjc156560 	char *s_argp = NULL;
219711890bcSjc156560 	char *p_argp = NULL;
220711890bcSjc156560 	char *F_argp = NULL;
221711890bcSjc156560 	char *C_argp = NULL;
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	/*
224711890bcSjc156560 	 * operation flags.
2257c478bd9Sstevel@tonic-gate 	 */
226711890bcSjc156560 	uint8_t r_flag = FALSE;
227711890bcSjc156560 	uint8_t f_flag = FALSE;
228711890bcSjc156560 	uint8_t action = FALSE;
229711890bcSjc156560 	uint64_t options = 0;
2307c478bd9Sstevel@tonic-gate 
231711890bcSjc156560 	/* index and temporary variables */
232711890bcSjc156560 	int ret;
233711890bcSjc156560 	int status;
234711890bcSjc156560 	char c = '\0';
2357c478bd9Sstevel@tonic-gate 
236711890bcSjc156560 	/* fd for the filelock */
2377c478bd9Sstevel@tonic-gate 	int fd;
2387c478bd9Sstevel@tonic-gate 
239711890bcSjc156560 	if (enter_raidctl_lock(&fd) != SUCCESS) {
2407c478bd9Sstevel@tonic-gate 		return (FAILURE);
2417c478bd9Sstevel@tonic-gate 	}
2427c478bd9Sstevel@tonic-gate 
243711890bcSjc156560 	(void) setlocale(LC_ALL, "");
244711890bcSjc156560 	(void) textdomain(TEXT_DOMAIN);
2457c478bd9Sstevel@tonic-gate 
246711890bcSjc156560 	/* parse command line, and get program name */
247711890bcSjc156560 	if ((prog_namep = strrchr(argv[0], '/')) == NULL) {
248711890bcSjc156560 		prog_namep = argv[0];
2496fec3791Sjesseb 	} else {
250711890bcSjc156560 		prog_namep++;
2516fec3791Sjesseb 	}
2526fec3791Sjesseb 
253711890bcSjc156560 	/* close error option messages from getopt */
254711890bcSjc156560 	opterr = 0;
2556fec3791Sjesseb 
256711890bcSjc156560 	/* get yes expression according to current locale */
257711890bcSjc156560 	yesexpr = strdup(nl_langinfo(YESEXPR));
258711890bcSjc156560 	yesstr = strdup(nl_langinfo(YESSTR));
259711890bcSjc156560 	nostr = strdup(nl_langinfo(NOSTR));
260711890bcSjc156560 	if (yesexpr == NULL || yesstr == NULL || nostr == NULL) {
2617c478bd9Sstevel@tonic-gate 		return (FAILURE);
262711890bcSjc156560 	}
263711890bcSjc156560 
264711890bcSjc156560 	/*
265711890bcSjc156560 	 * If the was no expression or if there is a compile error
266711890bcSjc156560 	 * use default yes expression.
267711890bcSjc156560 	 */
268711890bcSjc156560 	status = regcomp(&re, yesexpr, REG_EXTENDED | REG_NOSUB);
269711890bcSjc156560 	if ((*yesexpr == (char)NULL) ||
270711890bcSjc156560 	    (*yesstr == (char)NULL) ||
271711890bcSjc156560 	    (*nostr == (char)NULL) ||
272711890bcSjc156560 	    (status != 0)) {
273711890bcSjc156560 		SET_DEFAULT_STRS;
274711890bcSjc156560 		if (regcomp(&re, default_yesexpr,
275711890bcSjc156560 		    REG_EXTENDED | REG_NOSUB) != 0) {
276711890bcSjc156560 			return (FALSE);
277711890bcSjc156560 		}
278711890bcSjc156560 	}
279711890bcSjc156560 
280711890bcSjc156560 	while ((c = getopt(argc, argv,
281711890bcSjc156560 	    "?hC:cdlF:r:z:g:a:s:p:fS")) != EOF) {
282711890bcSjc156560 		switch (c) {
283711890bcSjc156560 		case 'h':
284711890bcSjc156560 		case '?':
285711890bcSjc156560 			if (action == FALSE) {
286711890bcSjc156560 				findex = DO_HW_RAID_HELP;
287711890bcSjc156560 				action = TRUE;
288711890bcSjc156560 				options |= LOWER_H;
289711890bcSjc156560 			} else {
290711890bcSjc156560 				findex = DO_HW_RAID_NOP;
291711890bcSjc156560 			}
292711890bcSjc156560 			break;
293711890bcSjc156560 		case 'C':
294711890bcSjc156560 			if (action == FALSE) {
295711890bcSjc156560 				findex = DO_HW_RAID_CREATEN;
296711890bcSjc156560 				C_argp = optarg;
297711890bcSjc156560 				action = TRUE;
298711890bcSjc156560 				options |= UPPER_C;
299711890bcSjc156560 			} else {
300711890bcSjc156560 				findex = DO_HW_RAID_NOP;
301711890bcSjc156560 			}
302711890bcSjc156560 			break;
303711890bcSjc156560 		case 'c':
304711890bcSjc156560 			if (action == FALSE) {
305711890bcSjc156560 				findex = DO_HW_RAID_CREATEO;
306711890bcSjc156560 				action = TRUE;
307711890bcSjc156560 				options |= LOWER_C;
308711890bcSjc156560 			} else {
309711890bcSjc156560 				findex = DO_HW_RAID_NOP;
310711890bcSjc156560 			}
311711890bcSjc156560 			break;
312711890bcSjc156560 		case 'd':
313711890bcSjc156560 			if (action == FALSE) {
314711890bcSjc156560 				findex = DO_HW_RAID_DELETE;
315711890bcSjc156560 				action = TRUE;
316711890bcSjc156560 				options |= LOWER_D;
317711890bcSjc156560 			} else {
318711890bcSjc156560 				findex = DO_HW_RAID_NOP;
319711890bcSjc156560 			}
320711890bcSjc156560 			break;
321711890bcSjc156560 		case 'l':
322711890bcSjc156560 			if (action == FALSE) {
323711890bcSjc156560 				findex = DO_HW_RAID_LIST;
324711890bcSjc156560 				action = TRUE;
325711890bcSjc156560 				options |= LOWER_L;
326711890bcSjc156560 			} else {
327711890bcSjc156560 				findex = DO_HW_RAID_NOP;
328711890bcSjc156560 			}
329711890bcSjc156560 			break;
330711890bcSjc156560 		case 'F':
331711890bcSjc156560 			if (action == FALSE) {
332711890bcSjc156560 				findex = DO_HW_RAID_FLASH;
333711890bcSjc156560 				F_argp = optarg;
334711890bcSjc156560 				action = TRUE;
335711890bcSjc156560 				options |= UPPER_F;
336711890bcSjc156560 			} else {
337711890bcSjc156560 				findex = DO_HW_RAID_NOP;
338711890bcSjc156560 			}
339711890bcSjc156560 			break;
340711890bcSjc156560 		case 'a':
341711890bcSjc156560 			if (action == FALSE) {
342711890bcSjc156560 				findex = DO_HW_RAID_HSP;
343711890bcSjc156560 				a_argp = optarg;
344711890bcSjc156560 				action = TRUE;
345711890bcSjc156560 				options |= LOWER_A;
346711890bcSjc156560 			} else {
347711890bcSjc156560 				findex = DO_HW_RAID_NOP;
348711890bcSjc156560 			}
349711890bcSjc156560 			break;
350711890bcSjc156560 		case 'p':
351711890bcSjc156560 			if (action == FALSE) {
352711890bcSjc156560 				findex = DO_HW_RAID_SET_ATTR;
353711890bcSjc156560 				p_argp = optarg;
354711890bcSjc156560 				action = TRUE;
355711890bcSjc156560 				options |= LOWER_P;
356711890bcSjc156560 			} else {
357711890bcSjc156560 				findex = DO_HW_RAID_NOP;
358711890bcSjc156560 			}
359711890bcSjc156560 			break;
360711890bcSjc156560 		case 'r':
361711890bcSjc156560 			r_argp = optarg;
362711890bcSjc156560 			r_flag = TRUE;
363711890bcSjc156560 			options |= LOWER_R;
364711890bcSjc156560 			break;
365711890bcSjc156560 		case 'z':
366711890bcSjc156560 			z_argp = optarg;
367711890bcSjc156560 			options |= LOWER_Z;
368711890bcSjc156560 			break;
369711890bcSjc156560 		case 'g':
370711890bcSjc156560 			g_argp = optarg;
371711890bcSjc156560 			options |= LOWER_G;
372711890bcSjc156560 			break;
373711890bcSjc156560 		case 's':
374711890bcSjc156560 			s_argp = optarg;
375711890bcSjc156560 			options |= LOWER_S;
376711890bcSjc156560 			break;
377711890bcSjc156560 		case 'f':
378711890bcSjc156560 			f_flag = TRUE;
379711890bcSjc156560 			options |= LOWER_F;
380711890bcSjc156560 			break;
381711890bcSjc156560 		case 'S':
382711890bcSjc156560 			if (action == FALSE) {
383711890bcSjc156560 				findex = DO_HW_RAID_SNAPSHOT;
384711890bcSjc156560 				action = TRUE;
385711890bcSjc156560 				options |= UPPER_S;
386711890bcSjc156560 			} else {
387711890bcSjc156560 				findex = DO_HW_RAID_NOP;
388711890bcSjc156560 			}
389711890bcSjc156560 			break;
390711890bcSjc156560 		default:
391711890bcSjc156560 			(void) fprintf(stderr,
392711890bcSjc156560 			    gettext("Invalid argument(s).\n"));
393711890bcSjc156560 			exit_raidctl_lock(fd);
394711890bcSjc156560 			FREE_STRS;
395711890bcSjc156560 			regfree(&re);
396711890bcSjc156560 			return (INVALID_ARG);
397711890bcSjc156560 		}
398711890bcSjc156560 	}
399711890bcSjc156560 
400711890bcSjc156560 	/* parse options */
401711890bcSjc156560 	switch (findex) {
402711890bcSjc156560 	case DO_HW_RAID_HELP:
403711890bcSjc156560 		if ((options & ~(LOWER_H)) != 0) {
404711890bcSjc156560 			ret = INVALID_ARG;
405711890bcSjc156560 		} else {
406711890bcSjc156560 			helpinfo(prog_namep);
407711890bcSjc156560 			ret = SUCCESS;
408711890bcSjc156560 		}
409711890bcSjc156560 		break;
410711890bcSjc156560 	case DO_HW_RAID_CREATEO:
411711890bcSjc156560 		if ((options & ~(LOWER_F | LOWER_C | LOWER_R)) != 0) {
412711890bcSjc156560 			ret = INVALID_ARG;
413711890bcSjc156560 		} else {
414711890bcSjc156560 			if (r_flag != FALSE && f_flag == FALSE) {
415711890bcSjc156560 				ret = do_create_ctd(r_argp, argv, argc - 4,
416711890bcSjc156560 				    optind, f_flag);
417711890bcSjc156560 			} else if (r_flag == FALSE && f_flag == FALSE) {
418711890bcSjc156560 				ret = do_create_ctd(NULL, argv, argc - 2,
419711890bcSjc156560 				    optind, f_flag);
420711890bcSjc156560 			} else if (r_flag != FALSE && f_flag != FALSE) {
421711890bcSjc156560 				ret = do_create_ctd(r_argp, argv, argc - 5,
422711890bcSjc156560 				    optind, f_flag);
423711890bcSjc156560 			} else {
424711890bcSjc156560 				ret = do_create_ctd(NULL, argv, argc - 3,
425711890bcSjc156560 				    optind, f_flag);
426711890bcSjc156560 			}
427711890bcSjc156560 		}
428711890bcSjc156560 		break;
429711890bcSjc156560 	case DO_HW_RAID_CREATEN:
430711890bcSjc156560 		if ((options & ~(LOWER_F | UPPER_C | LOWER_R | LOWER_Z |
431711890bcSjc156560 		    LOWER_S)) != 0) {
432711890bcSjc156560 			ret = INVALID_ARG;
433711890bcSjc156560 		} else {
434711890bcSjc156560 			ret = do_create_cidl(r_argp, z_argp, C_argp, s_argp,
435711890bcSjc156560 			    f_flag, argv, optind);
436711890bcSjc156560 		}
437711890bcSjc156560 		break;
438711890bcSjc156560 	case DO_HW_RAID_DELETE:
439711890bcSjc156560 		if ((options & ~(LOWER_F | LOWER_D)) != 0) {
440711890bcSjc156560 			ret = INVALID_ARG;
441711890bcSjc156560 		} else {
442711890bcSjc156560 			ret = do_delete(f_flag, argv, optind);
443711890bcSjc156560 		}
444711890bcSjc156560 		break;
445711890bcSjc156560 	case DO_HW_RAID_LIST:
446711890bcSjc156560 		if ((options & ~(LOWER_L | LOWER_G)) != 0) {
447711890bcSjc156560 			ret = INVALID_ARG;
448711890bcSjc156560 		} else {
449711890bcSjc156560 			ret = do_list(g_argp, argv, optind, FALSE);
450711890bcSjc156560 		}
451711890bcSjc156560 		break;
452711890bcSjc156560 	case DO_HW_RAID_SNAPSHOT:
453711890bcSjc156560 		if ((options & ~(UPPER_S | LOWER_G)) != 0) {
454711890bcSjc156560 			ret = INVALID_ARG;
455711890bcSjc156560 		} else {
456711890bcSjc156560 			ret = do_list(g_argp, argv, optind, TRUE);
457711890bcSjc156560 		}
458711890bcSjc156560 		break;
459711890bcSjc156560 	case DO_HW_RAID_FLASH:
460711890bcSjc156560 		if ((options & ~(LOWER_F | UPPER_F)) != 0) {
461711890bcSjc156560 			ret = INVALID_ARG;
462711890bcSjc156560 		} else {
463711890bcSjc156560 			if (f_flag == FALSE) {
464711890bcSjc156560 				ret = do_flash(f_flag, F_argp, argv, optind,
465711890bcSjc156560 				    argc - 3);
466711890bcSjc156560 			} else {
467711890bcSjc156560 				ret = do_flash(f_flag, F_argp, argv, optind,
468711890bcSjc156560 				    argc - 4);
469711890bcSjc156560 			}
470711890bcSjc156560 		}
471711890bcSjc156560 		break;
472711890bcSjc156560 	case DO_HW_RAID_HSP:
473711890bcSjc156560 		if ((options & ~(LOWER_A | LOWER_G)) != 0) {
474711890bcSjc156560 			ret = INVALID_ARG;
475711890bcSjc156560 		} else {
476711890bcSjc156560 			ret = do_set_hsp(a_argp, g_argp, argv, optind);
477711890bcSjc156560 		}
478711890bcSjc156560 		break;
479711890bcSjc156560 	case DO_HW_RAID_SET_ATTR:
480711890bcSjc156560 		if ((options & ~(LOWER_F | LOWER_P)) != 0) {
481711890bcSjc156560 			ret = INVALID_ARG;
482711890bcSjc156560 		} else {
483711890bcSjc156560 			ret = do_set_array_attr(f_flag, p_argp, argv, optind);
484711890bcSjc156560 		}
485711890bcSjc156560 		break;
486711890bcSjc156560 	case DO_HW_RAID_NOP:
487711890bcSjc156560 		if (argc == 1) {
488711890bcSjc156560 			ret = do_list(g_argp, argv, optind, FALSE);
489711890bcSjc156560 		} else {
490711890bcSjc156560 			ret = INVALID_ARG;
491711890bcSjc156560 		}
492711890bcSjc156560 		break;
493711890bcSjc156560 	default:
494711890bcSjc156560 		ret = INVALID_ARG;
495711890bcSjc156560 		break;
496711890bcSjc156560 	}
497711890bcSjc156560 
498711890bcSjc156560 	if (ret == INVALID_ARG) {
499711890bcSjc156560 		(void) fprintf(stderr,
500711890bcSjc156560 		    gettext("Invalid argument(s).\n"));
501711890bcSjc156560 	}
502711890bcSjc156560 	exit_raidctl_lock(fd);
503711890bcSjc156560 
504711890bcSjc156560 	FREE_STRS;
505711890bcSjc156560 	regfree(&re);
506711890bcSjc156560 	return (ret);
507711890bcSjc156560 }
508711890bcSjc156560 
509711890bcSjc156560 /*
510711890bcSjc156560  * helpinfo(prog_namep)
511711890bcSjc156560  * This function prints help informations for usrs.
512711890bcSjc156560  */
513711890bcSjc156560 static void
514711890bcSjc156560 helpinfo(char *prog_namep)
515711890bcSjc156560 {
516711890bcSjc156560 	char quote = '"';
517711890bcSjc156560 
518711890bcSjc156560 	(void) printf(gettext("%s [-f] -C %c<disks>%c [-r <raid_level>] "
519711890bcSjc156560 	    "[-z <capacity>] [-s <stripe_size>] <controller>\n"), prog_namep,
520711890bcSjc156560 	    quote, quote);
521711890bcSjc156560 
522711890bcSjc156560 	(void) printf(gettext("%s [-f] -d <volume>\n"), prog_namep);
523711890bcSjc156560 
524711890bcSjc156560 	(void) printf(gettext("%s [-f] -F <filename> <controller1> "
525711890bcSjc156560 	    "[<controller2> ...]\n"), prog_namep);
526711890bcSjc156560 
527711890bcSjc156560 	(void) printf(gettext("%s [-f] -p %c<param>=<value>%c <volume>\n"),
528711890bcSjc156560 	    prog_namep, quote, quote);
529711890bcSjc156560 
530711890bcSjc156560 	(void) printf(gettext("%s [-f] -c [-r <raid_level>] <disk1> <disk2> "
531711890bcSjc156560 	    "[<disk3> ...]\n"), prog_namep);
532711890bcSjc156560 
533711890bcSjc156560 	(void) printf(gettext("%s [-l]\n"), prog_namep);
534711890bcSjc156560 
535711890bcSjc156560 	(void) printf(gettext("%s -l -g <disk> <controller>\n"), prog_namep);
536711890bcSjc156560 
537711890bcSjc156560 	(void) printf(gettext("%s -l <volume>\n"), prog_namep);
538711890bcSjc156560 
539711890bcSjc156560 	(void) printf(gettext("%s -l <controller1> [<controller2> ...]\n"),
540711890bcSjc156560 	    prog_namep);
541711890bcSjc156560 
542711890bcSjc156560 	(void) printf(gettext("%s -a {set | unset} -g <disk> "
543711890bcSjc156560 	    "{<volume> | <controller>}\n"), prog_namep);
544711890bcSjc156560 
545711890bcSjc156560 	(void) printf(gettext("%s -S [<volume> | <controller>]\n"), prog_namep);
546711890bcSjc156560 
547711890bcSjc156560 	(void) printf(gettext("%s -S -g <disk> <controller>\n"), prog_namep);
548711890bcSjc156560 
549711890bcSjc156560 	(void) printf(gettext("%s -h\n"), prog_namep);
550711890bcSjc156560 }
551711890bcSjc156560 
552711890bcSjc156560 /*
553711890bcSjc156560  * do_create_cidl(raid_levelp, capacityp, disks_argp, stripe_sizep,
554711890bcSjc156560  * f_flag, argv, optind)
555711890bcSjc156560  * This function creates a new RAID volume with specified arguments,
556711890bcSjc156560  * and returns result as SUCCESS, INVALID_ARG or FAILURE.
557711890bcSjc156560  * The "c.id.l" is used to express single physical disk. 'c' expresses
558711890bcSjc156560  * bus number, 'id' expresses target number, and 'l' expresses lun.
559711890bcSjc156560  * The physical disks represented by c.id.l may be invisible to OS, which
560711890bcSjc156560  * means physical disks attached to controllers are not accessible by
561711890bcSjc156560  * OS directly. The disks should be organized as a logical volume, and
562711890bcSjc156560  * the logical volume is exported to OS as a single unit. Some hardware
563711890bcSjc156560  * RAID controllers also support physical disks accessed by OS directly,
564711890bcSjc156560  * for example LSI1068. In this case, it's both OK to express physical
565711890bcSjc156560  * disk by c.id.l format or canonical ctd format.
566711890bcSjc156560  */
567711890bcSjc156560 static int
568711890bcSjc156560 do_create_cidl(char *raid_levelp, char *capacityp, char *disks_argp,
569711890bcSjc156560 	char *stripe_sizep, uint32_t f_flag, char **argv, uint32_t optind)
570711890bcSjc156560 {
571711890bcSjc156560 	uint32_t ctl_tag = MAX32BIT;
572711890bcSjc156560 	raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE;
573711890bcSjc156560 	uint32_t raid_level = RAID_LEVEL_1;
574711890bcSjc156560 	uint64_t capacity = 0;
575711890bcSjc156560 	uint64_t stripe_size = (uint64_t)OBJ_ATTR_NONE;
576711890bcSjc156560 	raid_obj_handle_t *disk_handlesp = NULL;
577711890bcSjc156560 	raid_obj_handle_t array_handle = INIT_HANDLE_VALUE;
578711890bcSjc156560 	raidcfg_controller_t ctl_attr;
579711890bcSjc156560 	int comps_num = 0;
580711890bcSjc156560 	int ret = 0;
581711890bcSjc156560 
582711890bcSjc156560 	raidcfg_array_t array_attr;
583711890bcSjc156560 
584711890bcSjc156560 	if (argv[optind] == NULL || argv[optind + 1] != NULL) {
585711890bcSjc156560 		return (INVALID_ARG);
586711890bcSjc156560 	}
587711890bcSjc156560 
588711890bcSjc156560 	if (disks_argp == NULL) {
589711890bcSjc156560 		return (INVALID_ARG);
590711890bcSjc156560 	}
591711890bcSjc156560 
592711890bcSjc156560 	/* Check controller tag */
593711890bcSjc156560 	if (get_ctl_tag(argv[optind], &ctl_tag) != SUCCESS) {
594711890bcSjc156560 		return (INVALID_ARG);
595711890bcSjc156560 	}
596711890bcSjc156560 
597711890bcSjc156560 	ctl_handle = raidcfg_get_controller(ctl_tag);
598711890bcSjc156560 	if (ctl_handle <= 0) {
599711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ctl_handle));
600711890bcSjc156560 		return (FAILURE);
601711890bcSjc156560 	}
602711890bcSjc156560 
603711890bcSjc156560 	if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) {
604711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
605711890bcSjc156560 		return (FAILURE);
606711890bcSjc156560 	}
607711890bcSjc156560 
608711890bcSjc156560 	/* Get raid level */
609711890bcSjc156560 	if (raid_levelp != NULL) {
610711890bcSjc156560 		if (*raid_levelp == '1' &&
611711890bcSjc156560 		    (*(raid_levelp + 1) == 'E' || *(raid_levelp + 1) == 'e')) {
612711890bcSjc156560 			raid_level = RAID_LEVEL_1E;
613711890bcSjc156560 		} else {
614711890bcSjc156560 			if (is_fully_numeric(raid_levelp) == FALSE) {
615711890bcSjc156560 				return (INVALID_ARG);
616711890bcSjc156560 			}
617711890bcSjc156560 
618711890bcSjc156560 			switch (atoi(raid_levelp)) {
619711890bcSjc156560 			case 0:
620711890bcSjc156560 				raid_level = RAID_LEVEL_0;
621711890bcSjc156560 				break;
6227c478bd9Sstevel@tonic-gate 			case 1:
623711890bcSjc156560 				raid_level = RAID_LEVEL_1;
6247c478bd9Sstevel@tonic-gate 				break;
625711890bcSjc156560 			case 5:
626711890bcSjc156560 				raid_level = RAID_LEVEL_5;
627711890bcSjc156560 				break;
628711890bcSjc156560 			case 10:
629711890bcSjc156560 				raid_level = RAID_LEVEL_10;
630711890bcSjc156560 				break;
631711890bcSjc156560 			case 50:
632711890bcSjc156560 				raid_level = RAID_LEVEL_50;
633711890bcSjc156560 				break;
634711890bcSjc156560 			default:
6357c478bd9Sstevel@tonic-gate 				return (INVALID_ARG);
6367c478bd9Sstevel@tonic-gate 			}
637711890bcSjc156560 		}
6387c478bd9Sstevel@tonic-gate 	}
6397c478bd9Sstevel@tonic-gate 
6406fec3791Sjesseb 	/*
641711890bcSjc156560 	 * The rang check of capacity and stripe size is performed in library,
642711890bcSjc156560 	 * and it relates to hardware feature.
6436fec3791Sjesseb 	 */
6446fec3791Sjesseb 
645711890bcSjc156560 	/* Capacity in bytes. Capacity 0 means max available space. */
646711890bcSjc156560 	if (capacityp != NULL) {
647711890bcSjc156560 		if (*capacityp == '-' ||
648711890bcSjc156560 		    calc_size(capacityp, &capacity) != SUCCESS) {
6496fec3791Sjesseb 			return (INVALID_ARG);
6506fec3791Sjesseb 		}
6516fec3791Sjesseb 	}
6526fec3791Sjesseb 
653711890bcSjc156560 	/* Stripe size in bytes */
654711890bcSjc156560 	if (stripe_sizep != NULL) {
655711890bcSjc156560 		if (calc_size(stripe_sizep, &stripe_size) != SUCCESS ||
656711890bcSjc156560 		    *stripe_sizep == '-') {
657711890bcSjc156560 			return (INVALID_ARG);
658711890bcSjc156560 		}
659711890bcSjc156560 	}
660711890bcSjc156560 
661711890bcSjc156560 	/* Open controller before accessing its object */
662711890bcSjc156560 	if ((ret = raidcfg_open_controller(ctl_handle, NULL)) < 0) {
663711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
664711890bcSjc156560 		return (FAILURE);
665711890bcSjc156560 	}
666711890bcSjc156560 
667711890bcSjc156560 	/* Get disks' handles */
668711890bcSjc156560 	if ((ret = get_disk_handle_cidl(ctl_tag, disks_argp, &comps_num,
669711890bcSjc156560 	    &disk_handlesp)) != SUCCESS) {
670711890bcSjc156560 		(void) raidcfg_close_controller(ctl_handle, NULL);
671711890bcSjc156560 		return (ret);
672711890bcSjc156560 	}
673711890bcSjc156560 
674711890bcSjc156560 	if (f_flag == FALSE) {
675711890bcSjc156560 		(void) fprintf(stdout, gettext("Creating RAID volume "
676711890bcSjc156560 		    "will destroy all data on spare space of member disks, "
677711890bcSjc156560 		    "proceed (%s/%s)? "), yesstr, nostr);
6786fec3791Sjesseb 		if (!yes()) {
679711890bcSjc156560 			(void) fprintf(stdout, gettext("RAID volume "
680711890bcSjc156560 			    "not created.\n\n"));
681711890bcSjc156560 			(void) raidcfg_close_controller(ctl_handle, NULL);
682711890bcSjc156560 			free(disk_handlesp);
6836fec3791Sjesseb 			return (SUCCESS);
6846fec3791Sjesseb 		}
6856fec3791Sjesseb 	}
6866fec3791Sjesseb 
687711890bcSjc156560 	/* Create array */
688711890bcSjc156560 	array_handle = raidcfg_create_array(comps_num,
689711890bcSjc156560 	    disk_handlesp, raid_level, capacity, stripe_size, NULL);
6906fec3791Sjesseb 
691711890bcSjc156560 	if (array_handle <= 0) {
692711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(array_handle));
693711890bcSjc156560 		free(disk_handlesp);
694711890bcSjc156560 		(void) raidcfg_close_controller(ctl_handle, NULL);
6957c478bd9Sstevel@tonic-gate 		return (FAILURE);
6967c478bd9Sstevel@tonic-gate 	}
6977c478bd9Sstevel@tonic-gate 
698711890bcSjc156560 	/* Get attribute of the new created array */
699711890bcSjc156560 	if ((ret = raidcfg_get_attr(array_handle, &array_attr)) < 0) {
700711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
701711890bcSjc156560 		free(disk_handlesp);
702711890bcSjc156560 		(void) raidcfg_close_controller(ctl_handle, NULL);
703711890bcSjc156560 		return (FAILURE);
704711890bcSjc156560 	}
705711890bcSjc156560 
706711890bcSjc156560 	(void) fprintf(stdout, gettext("Volume c%ut%llud%llu is created "
707711890bcSjc156560 	    "successfully!\n"), ctl_tag, array_attr.tag.idl.target_id,
708711890bcSjc156560 	    array_attr.tag.idl.lun);
709711890bcSjc156560 
710711890bcSjc156560 	/* Print attribute of array */
711711890bcSjc156560 	(void) print_array_table(ctl_handle, array_handle);
712711890bcSjc156560 
713711890bcSjc156560 	/* Close controller */
714711890bcSjc156560 	(void) raidcfg_close_controller(ctl_handle, NULL);
715711890bcSjc156560 
716711890bcSjc156560 	free(disk_handlesp);
717711890bcSjc156560 	return (SUCCESS);
718711890bcSjc156560 }
719711890bcSjc156560 
720711890bcSjc156560 /*
721711890bcSjc156560  * do_create_ctd(raid_levelp, disks_argpp, disks_num, argindex, f_flag)
722711890bcSjc156560  * This function creates array with specified arguments, and return result
723711890bcSjc156560  * as SUCCESS, FAILURE, or INVALID_ARG. It only supports LSI MPT controller
724711890bcSjc156560  * to be compatible with old raidctl. The capacity and stripe size can't
725711890bcSjc156560  * be specified for LSI MPT controller, and they use zero and default value.
726711890bcSjc156560  * The "ctd" is the canonical expression of physical disks which are
727711890bcSjc156560  * accessible by OS.
728711890bcSjc156560  */
7297c478bd9Sstevel@tonic-gate static int
730711890bcSjc156560 do_create_ctd(char *raid_levelp, char **disks_argpp, uint32_t disks_num,
731711890bcSjc156560 	uint32_t argindex, uint32_t f_flag)
7327c478bd9Sstevel@tonic-gate {
733711890bcSjc156560 	uint32_t ctl_tag = MAX32BIT;
734711890bcSjc156560 	raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE;
735711890bcSjc156560 	uint32_t raid_level = RAID_LEVEL_1;
736711890bcSjc156560 	uint64_t capacity = 0;
737711890bcSjc156560 	uint32_t stripe_size = (uint32_t)OBJ_ATTR_NONE;
738711890bcSjc156560 	raid_obj_handle_t *disk_handlesp = NULL;
739711890bcSjc156560 	raid_obj_handle_t array_handle = INIT_HANDLE_VALUE;
740711890bcSjc156560 	raidcfg_controller_t ctl_attr;
741711890bcSjc156560 	int ret;
742711890bcSjc156560 
743711890bcSjc156560 	raidcfg_array_t array_attr;
7446fec3791Sjesseb 	int i, j;
7457c478bd9Sstevel@tonic-gate 
746711890bcSjc156560 	/* Check disks parameter */
747711890bcSjc156560 	if (disks_argpp == NULL || disks_num < 2) {
7487c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
7497c478bd9Sstevel@tonic-gate 	}
7507c478bd9Sstevel@tonic-gate 
751711890bcSjc156560 	for (i = 0, j = argindex; i < disks_num; i++, j++) {
752711890bcSjc156560 		if (disks_argpp[j] == NULL) {
753711890bcSjc156560 			return (INVALID_ARG);
754711890bcSjc156560 		}
755711890bcSjc156560 	}
7567c478bd9Sstevel@tonic-gate 
757711890bcSjc156560 	/*
758711890bcSjc156560 	 * We need check if the raid_level string is fully numeric. If user
759711890bcSjc156560 	 * input string with unsupported letters, such as "s10", atoi() will
760711890bcSjc156560 	 * return zero because it is an illegal string, but it doesn't mean
761711890bcSjc156560 	 * RAID_LEVEL_0.
762711890bcSjc156560 	 */
763711890bcSjc156560 	if (raid_levelp != NULL) {
764711890bcSjc156560 		if (*raid_levelp == '1' &&
765711890bcSjc156560 		    (*(raid_levelp + 1) == 'E' || *(raid_levelp + 1) == 'e')) {
766711890bcSjc156560 			raid_level = RAID_LEVEL_1E;
767711890bcSjc156560 		} else {
768711890bcSjc156560 			if (is_fully_numeric(raid_levelp) == FALSE) {
769711890bcSjc156560 				return (INVALID_ARG);
770711890bcSjc156560 			}
771711890bcSjc156560 
772711890bcSjc156560 			switch (atoi(raid_levelp)) {
773711890bcSjc156560 			case 0:
774711890bcSjc156560 				raid_level = RAID_LEVEL_0;
775711890bcSjc156560 				break;
776711890bcSjc156560 			case 1:
777711890bcSjc156560 				raid_level = RAID_LEVEL_1;
778711890bcSjc156560 				break;
779711890bcSjc156560 			case 5:
780711890bcSjc156560 				raid_level = RAID_LEVEL_5;
781711890bcSjc156560 				break;
782711890bcSjc156560 			default:
783711890bcSjc156560 				return (INVALID_ARG);
784711890bcSjc156560 			}
785711890bcSjc156560 		}
786711890bcSjc156560 	}
787711890bcSjc156560 
788711890bcSjc156560 	/* Get disks tag and controller tag */
789711890bcSjc156560 	disk_handlesp = (raid_obj_handle_t *)calloc(disks_num + 2,
790711890bcSjc156560 	    sizeof (raid_obj_handle_t));
791711890bcSjc156560 	if (disk_handlesp == NULL) {
7927c478bd9Sstevel@tonic-gate 		return (FAILURE);
7937c478bd9Sstevel@tonic-gate 	}
7947c478bd9Sstevel@tonic-gate 
795711890bcSjc156560 	disk_handlesp[0] = OBJ_SEPARATOR_BEGIN;
796711890bcSjc156560 	disk_handlesp[disks_num + 1] = OBJ_SEPARATOR_END;
797711890bcSjc156560 
798711890bcSjc156560 	if ((ret = get_disk_handle_ctd(disks_num, &disks_argpp[argindex],
799711890bcSjc156560 	    &ctl_tag, &disk_handlesp[1])) != SUCCESS) {
800711890bcSjc156560 		free(disk_handlesp);
801711890bcSjc156560 		return (ret);
802711890bcSjc156560 	}
803711890bcSjc156560 
804711890bcSjc156560 	/* LIB API should check whether all disks here belong to one ctl. */
805711890bcSjc156560 	/* get_disk_handle_ctd has opened controller. */
806711890bcSjc156560 	ctl_handle = raidcfg_get_controller(ctl_tag);
807711890bcSjc156560 
808711890bcSjc156560 	if (ctl_handle <= 0) {
809711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ctl_handle));
810711890bcSjc156560 		(void) raidcfg_close_controller(ctl_handle, NULL);
811711890bcSjc156560 		free(disk_handlesp);
8127c478bd9Sstevel@tonic-gate 		return (FAILURE);
8137c478bd9Sstevel@tonic-gate 	}
8147c478bd9Sstevel@tonic-gate 
815711890bcSjc156560 	/* Check if the controller is host raid type */
816711890bcSjc156560 	if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) {
817711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
818711890bcSjc156560 		(void) raidcfg_close_controller(ctl_handle, NULL);
819711890bcSjc156560 		free(disk_handlesp);
820711890bcSjc156560 		return (FAILURE);
8216fec3791Sjesseb 	}
8226fec3791Sjesseb 
823711890bcSjc156560 	if ((ctl_attr.capability & RAID_CAP_DISK_TRANS) == 0) {
824711890bcSjc156560 		/* -c only support host raid controller, return failure here */
825711890bcSjc156560 		(void) fprintf(stderr,
826711890bcSjc156560 		    gettext("Option -c only supports host raid controller.\n"));
827711890bcSjc156560 		(void) raidcfg_close_controller(ctl_handle, NULL);
828711890bcSjc156560 		free(disk_handlesp);
829711890bcSjc156560 		return (FAILURE);
8307c478bd9Sstevel@tonic-gate 	}
831711890bcSjc156560 
832711890bcSjc156560 	if (f_flag == FALSE) {
833711890bcSjc156560 		(void) fprintf(stdout, gettext("Creating RAID volume "
834711890bcSjc156560 		    "will destroy all data on spare space of member disks, "
835711890bcSjc156560 		    "proceed (%s/%s)? "), yesstr, nostr);
836711890bcSjc156560 		if (!yes()) {
837711890bcSjc156560 			(void) fprintf(stdout, gettext("RAID volume "
838711890bcSjc156560 			    "not created.\n\n"));
839711890bcSjc156560 			free(disk_handlesp);
840711890bcSjc156560 			(void) raidcfg_close_controller(ctl_handle, NULL);
841711890bcSjc156560 			return (SUCCESS);
842711890bcSjc156560 		}
843711890bcSjc156560 	}
844711890bcSjc156560 
845711890bcSjc156560 	/*
846711890bcSjc156560 	 * For old raidctl, capacity is 0, which means to creates
847711890bcSjc156560 	 * max possible capacity of array.
848711890bcSjc156560 	 */
849711890bcSjc156560 
850711890bcSjc156560 	array_handle = raidcfg_create_array(disks_num + 2,
851711890bcSjc156560 	    disk_handlesp, raid_level, capacity, stripe_size, NULL);
852711890bcSjc156560 
853711890bcSjc156560 	if (array_handle <= 0) {
854711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(array_handle));
855711890bcSjc156560 		free(disk_handlesp);
856711890bcSjc156560 		(void) raidcfg_close_controller(ctl_handle, NULL);
857711890bcSjc156560 		return (FAILURE);
858711890bcSjc156560 	}
859711890bcSjc156560 
860711890bcSjc156560 	/* Get attribute of array */
861711890bcSjc156560 	if ((ret = raidcfg_get_attr(array_handle, &array_attr)) < 0) {
862711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
863711890bcSjc156560 		free(disk_handlesp);
864711890bcSjc156560 		(void) raidcfg_close_controller(ctl_handle, NULL);
865711890bcSjc156560 		return (FAILURE);
866711890bcSjc156560 	}
867711890bcSjc156560 
868711890bcSjc156560 	/* Close controller */
869711890bcSjc156560 	(void) raidcfg_close_controller(ctl_handle, NULL);
870711890bcSjc156560 
871711890bcSjc156560 	/* Print feedback for user */
872711890bcSjc156560 	(void) fprintf(stdout,
873711890bcSjc156560 	    gettext("Volume c%ut%llud%llu is created successfully!\n"),
874711890bcSjc156560 	    ctl_tag, array_attr.tag.idl.target_id,
875711890bcSjc156560 	    array_attr.tag.idl.lun);
876711890bcSjc156560 	free(disk_handlesp);
877711890bcSjc156560 	return (SUCCESS);
878711890bcSjc156560 }
879711890bcSjc156560 
880711890bcSjc156560 /*
881711890bcSjc156560  * do_list(disk_arg, argv, optind, is_snapshot)
882711890bcSjc156560  * This function lists RAID's system configuration. It supports various RAID
883711890bcSjc156560  * controller. The return value can be SUCCESS, FAILURE, or INVALID_ARG.
884711890bcSjc156560  */
885711890bcSjc156560 static int
886711890bcSjc156560 do_list(char *disk_argp, char **argv, uint32_t optind, uint8_t is_snapshot)
887711890bcSjc156560 {
888711890bcSjc156560 	uint32_t ctl_tag = MAX32BIT;
889711890bcSjc156560 	raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE;
890711890bcSjc156560 	raid_obj_handle_t disk_handle = INIT_HANDLE_VALUE;
891711890bcSjc156560 	raid_obj_handle_t array_handle = INIT_HANDLE_VALUE;
892711890bcSjc156560 	disk_tag_t disk_tag;
893711890bcSjc156560 	array_tag_t array_tag;
894711890bcSjc156560 
895711890bcSjc156560 	int ret;
896711890bcSjc156560 
897711890bcSjc156560 	/* print RAID system */
898711890bcSjc156560 	if (disk_argp == NULL) {
899711890bcSjc156560 		if (argv[optind] == NULL) {
900711890bcSjc156560 			ret = snapshot_raidsystem(TRUE, 0, is_snapshot);
901711890bcSjc156560 			return (ret);
902711890bcSjc156560 		} else {
903711890bcSjc156560 			if (is_fully_numeric(argv[optind]) == TRUE) {
904711890bcSjc156560 				while (argv[optind] != NULL) {
905711890bcSjc156560 					if (get_ctl_tag(argv[optind], &ctl_tag)
906711890bcSjc156560 					    != SUCCESS) {
907711890bcSjc156560 						ret = INVALID_ARG;
908711890bcSjc156560 						optind++;
9096fec3791Sjesseb 						continue;
9106fec3791Sjesseb 					}
911711890bcSjc156560 					ctl_handle =
912711890bcSjc156560 					    raidcfg_get_controller(ctl_tag);
913711890bcSjc156560 					if (ctl_handle <= 0) {
914711890bcSjc156560 						(void) fprintf(stderr, "%s\n",
915711890bcSjc156560 						    raidcfg_errstr(ctl_handle));
916711890bcSjc156560 						ret = FAILURE;
917711890bcSjc156560 						optind++;
918711890bcSjc156560 						continue;
9196fec3791Sjesseb 					}
920711890bcSjc156560 					ret =
921711890bcSjc156560 					    raidcfg_open_controller(ctl_handle,
922711890bcSjc156560 					    NULL);
923711890bcSjc156560 					if (ret < 0) {
924711890bcSjc156560 						(void) fprintf(stderr, "%s\n",
925711890bcSjc156560 						    raidcfg_errstr(ret));
926711890bcSjc156560 						ret = FAILURE;
927711890bcSjc156560 						optind++;
928711890bcSjc156560 						continue;
9296fec3791Sjesseb 					}
930711890bcSjc156560 					if (is_snapshot == FALSE) {
931711890bcSjc156560 						ret =
932711890bcSjc156560 						    print_ctl_table(ctl_handle);
933711890bcSjc156560 					} else {
934711890bcSjc156560 						ret =
935711890bcSjc156560 						    snapshot_ctl(ctl_handle,
936711890bcSjc156560 						    FALSE, 0, is_snapshot);
9377c478bd9Sstevel@tonic-gate 					}
938711890bcSjc156560 					(void) raidcfg_close_controller(
939711890bcSjc156560 					    ctl_handle, NULL);
940711890bcSjc156560 					optind++;
9417c478bd9Sstevel@tonic-gate 				}
942711890bcSjc156560 			} else {
943711890bcSjc156560 				if (get_array_tag(argv[optind],
944711890bcSjc156560 				    &ctl_tag, &array_tag) != SUCCESS) {
9456fec3791Sjesseb 					return (INVALID_ARG);
9466fec3791Sjesseb 				}
947711890bcSjc156560 				ctl_handle = raidcfg_get_controller(ctl_tag);
948711890bcSjc156560 				if (ctl_handle <= 0) {
949711890bcSjc156560 					(void) fprintf(stderr, "%s\n",
950711890bcSjc156560 					    raidcfg_errstr(ctl_handle));
9517c478bd9Sstevel@tonic-gate 					return (FAILURE);
9527c478bd9Sstevel@tonic-gate 				}
9537c478bd9Sstevel@tonic-gate 
954711890bcSjc156560 				ret = raidcfg_open_controller(ctl_handle, NULL);
955711890bcSjc156560 				if (ret < 0) {
956711890bcSjc156560 					(void) fprintf(stderr, "%s\n",
957711890bcSjc156560 					    raidcfg_errstr(ret));
958711890bcSjc156560 					return (FAILURE);
959711890bcSjc156560 				}
960711890bcSjc156560 
961711890bcSjc156560 				array_handle = raidcfg_get_array(ctl_handle,
962711890bcSjc156560 				    array_tag.idl.target_id, array_tag.idl.lun);
963711890bcSjc156560 				if (array_handle <= 0) {
964711890bcSjc156560 					(void) fprintf(stderr, "%s\n",
965711890bcSjc156560 					    raidcfg_errstr(array_handle));
966711890bcSjc156560 					(void) raidcfg_close_controller(
967711890bcSjc156560 					    ctl_handle, NULL);
968711890bcSjc156560 					return (FAILURE);
969711890bcSjc156560 				}
970711890bcSjc156560 				if (is_snapshot == FALSE) {
971711890bcSjc156560 					ret = print_array_table(ctl_handle,
972711890bcSjc156560 					    array_handle);
973711890bcSjc156560 				} else {
974711890bcSjc156560 					ret = snapshot_array(array_handle, 0,
975711890bcSjc156560 					    FALSE, is_snapshot);
976711890bcSjc156560 				}
977711890bcSjc156560 				(void) raidcfg_close_controller(
978711890bcSjc156560 				    ctl_handle, NULL);
979711890bcSjc156560 			}
980711890bcSjc156560 		}
981711890bcSjc156560 	} else {
982711890bcSjc156560 		if (argv[optind + 1] != NULL) {
983711890bcSjc156560 			return (INVALID_ARG);
984711890bcSjc156560 		}
985711890bcSjc156560 
986711890bcSjc156560 		if (get_ctl_tag(argv[optind], &ctl_tag) != SUCCESS) {
987711890bcSjc156560 			return (INVALID_ARG);
988711890bcSjc156560 		}
989711890bcSjc156560 
990711890bcSjc156560 		ctl_handle = raidcfg_get_controller(ctl_tag);
991711890bcSjc156560 		if (ctl_handle <= 0) {
992711890bcSjc156560 			(void) fprintf(stderr, "%s\n",
993711890bcSjc156560 			    raidcfg_errstr(ctl_handle));
994711890bcSjc156560 			return (FAILURE);
995711890bcSjc156560 		}
996711890bcSjc156560 
997711890bcSjc156560 		if (get_disk_tag_cidl(disk_argp, &disk_tag) != SUCCESS) {
998711890bcSjc156560 			return (INVALID_ARG);
999711890bcSjc156560 		}
1000711890bcSjc156560 
1001711890bcSjc156560 		ret = raidcfg_open_controller(ctl_handle, NULL);
1002711890bcSjc156560 		if (ret < 0) {
1003711890bcSjc156560 			(void) fprintf(stderr, "%s\n",
1004711890bcSjc156560 			    raidcfg_errstr(ret));
1005711890bcSjc156560 			return (FAILURE);
1006711890bcSjc156560 		}
1007711890bcSjc156560 
1008711890bcSjc156560 		disk_handle = raidcfg_get_disk(ctl_handle, disk_tag);
1009711890bcSjc156560 		if (disk_handle <= 0) {
1010711890bcSjc156560 			(void) fprintf(stderr, "%s\n",
1011711890bcSjc156560 			    raidcfg_errstr(disk_handle));
1012711890bcSjc156560 			(void) raidcfg_close_controller(ctl_handle, NULL);
1013711890bcSjc156560 			return (FAILURE);
1014711890bcSjc156560 		}
1015711890bcSjc156560 
1016711890bcSjc156560 		if (is_snapshot == FALSE) {
1017711890bcSjc156560 			ret = print_disk_table(ctl_handle, disk_handle);
1018711890bcSjc156560 		} else {
1019711890bcSjc156560 			ret = snapshot_disk(ctl_tag, disk_handle, 0,
1020711890bcSjc156560 			    is_snapshot);
1021711890bcSjc156560 		}
1022711890bcSjc156560 		(void) raidcfg_close_controller(ctl_handle, NULL);
1023711890bcSjc156560 	}
1024711890bcSjc156560 	return (ret);
1025711890bcSjc156560 }
1026711890bcSjc156560 
1027711890bcSjc156560 /*
1028711890bcSjc156560  * do_delete(f_flag, argv, optind)
1029711890bcSjc156560  * This function deletes a specified array, and return result as SUCCESS,
1030711890bcSjc156560  * FAILURE or INVALID_ARG.
1031711890bcSjc156560  */
1032711890bcSjc156560 static int
1033711890bcSjc156560 do_delete(uint32_t f_flag, char **argv, uint32_t optind)
1034711890bcSjc156560 {
1035711890bcSjc156560 	uint32_t ctl_tag;
1036711890bcSjc156560 	char *array_argp;
1037711890bcSjc156560 	array_tag_t array_tag;
1038711890bcSjc156560 	raid_obj_handle_t ctl_handle;
1039711890bcSjc156560 	raid_obj_handle_t array_handle;
1040711890bcSjc156560 	int ret;
1041711890bcSjc156560 
1042711890bcSjc156560 	array_argp = argv[optind];
1043711890bcSjc156560 	if (array_argp == NULL || argv[optind + 1] != NULL) {
1044711890bcSjc156560 		return (INVALID_ARG);
1045711890bcSjc156560 	}
1046711890bcSjc156560 
1047711890bcSjc156560 	if (get_array_tag(array_argp, &ctl_tag, &array_tag) != SUCCESS) {
1048711890bcSjc156560 		return (INVALID_ARG);
1049711890bcSjc156560 	}
1050711890bcSjc156560 
1051711890bcSjc156560 	ctl_handle = raidcfg_get_controller(ctl_tag);
1052711890bcSjc156560 	if (ctl_handle <= 0) {
1053711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ctl_handle));
1054711890bcSjc156560 		return (INVALID_ARG);
1055711890bcSjc156560 	}
1056711890bcSjc156560 
1057711890bcSjc156560 	ret = raidcfg_open_controller(ctl_handle, NULL);
1058711890bcSjc156560 	if (ret < 0) {
1059711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1060711890bcSjc156560 		return (FAILURE);
1061711890bcSjc156560 	}
1062711890bcSjc156560 
1063711890bcSjc156560 	array_handle = raidcfg_get_array(ctl_handle, array_tag.idl.target_id,
1064711890bcSjc156560 	    array_tag.idl.lun);
1065711890bcSjc156560 	if (array_handle <= 0) {
1066711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(array_handle));
1067711890bcSjc156560 		(void) raidcfg_close_controller(ctl_handle, NULL);
1068711890bcSjc156560 		return (FAILURE);
1069711890bcSjc156560 	}
1070711890bcSjc156560 
1071711890bcSjc156560 	if (f_flag == FALSE) {
1072711890bcSjc156560 		(void) fprintf(stdout, gettext("Deleting RAID volume "
1073711890bcSjc156560 		    "%s will destroy all data it contains, "
1074711890bcSjc156560 		    "proceed (%s/%s)? "), array_argp, yesstr, nostr);
1075711890bcSjc156560 		if (!yes()) {
1076711890bcSjc156560 			(void) fprintf(stdout, gettext("RAID Volume "
1077711890bcSjc156560 			    "%s not deleted.\n\n"), array_argp);
1078711890bcSjc156560 			(void) raidcfg_close_controller(ctl_handle, NULL);
1079711890bcSjc156560 			return (SUCCESS);
1080711890bcSjc156560 		}
1081711890bcSjc156560 	}
1082711890bcSjc156560 
1083711890bcSjc156560 
1084711890bcSjc156560 	if ((ret = raidcfg_delete_array(array_handle, NULL)) < 0) {
1085711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1086711890bcSjc156560 		(void) raidcfg_close_controller(ctl_handle, NULL);
1087711890bcSjc156560 		return (FAILURE);
1088711890bcSjc156560 	}
1089711890bcSjc156560 
1090711890bcSjc156560 	(void) fprintf(stdout, gettext("Volume %s is deleted successfully!\n"),
1091711890bcSjc156560 	    array_argp);
1092711890bcSjc156560 	(void) raidcfg_close_controller(ctl_handle, NULL);
1093711890bcSjc156560 
1094711890bcSjc156560 	return (SUCCESS);
1095711890bcSjc156560 }
1096711890bcSjc156560 
1097711890bcSjc156560 /*
1098711890bcSjc156560  * do_flash(f_flag, filep, ctls_argpp, index, ctl_num)
1099711890bcSjc156560  * This function downloads and updates firmware for specified controller, and
1100711890bcSjc156560  * return result as SUCCESS, FAILURE or INVALID_ARG.
1101711890bcSjc156560  */
1102711890bcSjc156560 static int
1103711890bcSjc156560 do_flash(uint8_t f_flag, char *filep, char **ctls_argpp,
1104711890bcSjc156560 	uint32_t index, uint32_t ctl_num)
1105711890bcSjc156560 {
1106711890bcSjc156560 	uint32_t ctl_tag = MAX32BIT;
1107711890bcSjc156560 	char *ctl_argp = NULL;
1108711890bcSjc156560 	raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE;
1109711890bcSjc156560 	int ret;
1110711890bcSjc156560 	int i, j;
1111711890bcSjc156560 
1112711890bcSjc156560 	if (ctl_num == 0)
1113711890bcSjc156560 		return (INVALID_ARG);
1114711890bcSjc156560 
1115711890bcSjc156560 	for (i = 0, j = index; i < ctl_num; i++, j++) {
1116711890bcSjc156560 		ctl_argp = ctls_argpp[j];
1117711890bcSjc156560 		if (get_ctl_tag(ctl_argp, &ctl_tag) != SUCCESS) {
1118711890bcSjc156560 			return (INVALID_ARG);
1119711890bcSjc156560 		}
1120711890bcSjc156560 
1121711890bcSjc156560 		/* Ask user to confirm operation. */
1122711890bcSjc156560 		if (f_flag == FALSE) {
1123711890bcSjc156560 			(void) fprintf(stdout, gettext("Update flash image on "
1124711890bcSjc156560 			    "controller %d (%s/%s)? "), ctl_tag, yesstr, nostr);
1125711890bcSjc156560 			if (!yes()) {
1126711890bcSjc156560 				(void) fprintf(stdout,
1127711890bcSjc156560 				    gettext("Controller %d not "
1128711890bcSjc156560 				    "flashed.\n\n"), ctl_tag);
1129711890bcSjc156560 				return (SUCCESS);
1130711890bcSjc156560 			}
1131711890bcSjc156560 		}
1132711890bcSjc156560 
1133711890bcSjc156560 		if ((ctl_handle = raidcfg_get_controller(ctl_tag)) < 0) {
1134711890bcSjc156560 			(void) fprintf(stderr, "%s\n",
1135711890bcSjc156560 			    raidcfg_errstr(ctl_handle));
1136711890bcSjc156560 			return (FAILURE);
1137711890bcSjc156560 		}
1138711890bcSjc156560 
1139711890bcSjc156560 		ret = raidcfg_open_controller(ctl_handle, NULL);
1140711890bcSjc156560 		if (ret < 0) {
1141711890bcSjc156560 			(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1142711890bcSjc156560 			return (FAILURE);
1143711890bcSjc156560 		}
1144711890bcSjc156560 
1145711890bcSjc156560 		(void) fprintf(stdout, gettext("Start updating controller "
1146711890bcSjc156560 		    "c%u firmware....\n"), ctl_tag);
1147711890bcSjc156560 
1148711890bcSjc156560 		if ((ret = raidcfg_update_fw(ctl_handle, filep, NULL)) < 0) {
1149711890bcSjc156560 			(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1150711890bcSjc156560 			(void) raidcfg_close_controller(ctl_handle, NULL);
1151711890bcSjc156560 			return (FAILURE);
1152711890bcSjc156560 		}
1153711890bcSjc156560 
1154711890bcSjc156560 		(void) fprintf(stdout, gettext("Update controller "
1155711890bcSjc156560 		    "c%u firmware successfully.\n"), ctl_tag);
1156711890bcSjc156560 
1157711890bcSjc156560 		(void) raidcfg_close_controller(ctl_handle, NULL);
1158711890bcSjc156560 	}
1159711890bcSjc156560 
1160711890bcSjc156560 	return (SUCCESS);
1161711890bcSjc156560 }
1162711890bcSjc156560 
1163711890bcSjc156560 /*
1164711890bcSjc156560  * do_set_hsp(a_argp, disk_argp, argv, optind)
1165711890bcSjc156560  * This function set or unset HSP relationship between disk and controller/
1166711890bcSjc156560  * array, and return result as SUCCESS, FAILURE or INVALID_ARG.
1167711890bcSjc156560  */
1168711890bcSjc156560 static int
1169711890bcSjc156560 do_set_hsp(char *a_argp, char *disk_argp, char **argv, uint32_t optind)
1170711890bcSjc156560 {
1171711890bcSjc156560 	uint32_t flag = MAX32BIT;
1172711890bcSjc156560 	uint32_t ctl_tag = MAX32BIT;
1173711890bcSjc156560 	array_tag_t array_tag;
1174711890bcSjc156560 	raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE;
1175711890bcSjc156560 	raid_obj_handle_t disk_handle = INIT_HANDLE_VALUE;
1176711890bcSjc156560 	raid_obj_handle_t array_handle = INIT_HANDLE_VALUE;
1177711890bcSjc156560 	raidcfg_controller_t ctl_attr;
1178711890bcSjc156560 	disk_tag_t disk_tag;
1179711890bcSjc156560 
1180711890bcSjc156560 	int ret;
1181711890bcSjc156560 	int hsp_type;
1182711890bcSjc156560 	raidcfg_hsp_relation_t hsp_relation;
1183711890bcSjc156560 
1184711890bcSjc156560 	(void) memset(&hsp_relation, 0, sizeof (raidcfg_hsp_relation_t));
1185711890bcSjc156560 
1186711890bcSjc156560 	if (a_argp == NULL) {
1187711890bcSjc156560 		return (INVALID_ARG);
1188711890bcSjc156560 	}
1189711890bcSjc156560 
1190711890bcSjc156560 	if (strcmp(a_argp, "set") == 0) {
1191711890bcSjc156560 		flag = HSP_SET;
1192711890bcSjc156560 	} else if (strcmp(a_argp, "unset") == 0) {
1193711890bcSjc156560 		flag = HSP_UNSET;
1194711890bcSjc156560 	} else {
1195711890bcSjc156560 		return (INVALID_ARG);
1196711890bcSjc156560 	}
1197711890bcSjc156560 
1198711890bcSjc156560 	if (disk_argp == NULL) {
1199711890bcSjc156560 		return (INVALID_ARG);
1200711890bcSjc156560 	}
1201711890bcSjc156560 
1202711890bcSjc156560 	if (argv[optind] == NULL || argv[optind + 1] != NULL) {
1203711890bcSjc156560 		return (INVALID_ARG);
1204711890bcSjc156560 	} else if (is_fully_numeric(argv[optind]) == TRUE) {
1205711890bcSjc156560 		/* Global HSP */
1206711890bcSjc156560 		hsp_type = 0;
1207711890bcSjc156560 		if (get_disk_tag_cidl(disk_argp, &disk_tag) != SUCCESS) {
1208711890bcSjc156560 			return (INVALID_ARG);
1209711890bcSjc156560 		}
1210711890bcSjc156560 
1211711890bcSjc156560 		if (get_ctl_tag(argv[optind], &ctl_tag) != SUCCESS) {
1212711890bcSjc156560 			return (INVALID_ARG);
1213711890bcSjc156560 		}
1214711890bcSjc156560 
1215711890bcSjc156560 		ctl_handle = raidcfg_get_controller(ctl_tag);
1216711890bcSjc156560 		if (ctl_handle <= 0) {
1217711890bcSjc156560 			(void) fprintf(stderr, "%s\n",
1218711890bcSjc156560 			    raidcfg_errstr(ctl_handle));
1219711890bcSjc156560 			return (FAILURE);
1220711890bcSjc156560 		}
1221711890bcSjc156560 
1222711890bcSjc156560 		ret = raidcfg_open_controller(ctl_handle, NULL);
1223711890bcSjc156560 		if (ret < 0) {
1224711890bcSjc156560 			(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1225711890bcSjc156560 			return (FAILURE);
1226711890bcSjc156560 		}
1227711890bcSjc156560 
1228711890bcSjc156560 		disk_handle = raidcfg_get_disk(ctl_handle, disk_tag);
1229711890bcSjc156560 		if (disk_handle <= 0) {
1230711890bcSjc156560 			(void) fprintf(stderr, "%s\n",
1231711890bcSjc156560 			    raidcfg_errstr(disk_handle));
1232711890bcSjc156560 			(void) raidcfg_close_controller(ctl_handle, NULL);
1233711890bcSjc156560 			return (FAILURE);
1234711890bcSjc156560 		}
1235711890bcSjc156560 	} else {
1236711890bcSjc156560 		/* Local HSP */
1237711890bcSjc156560 		hsp_type = 1;
1238711890bcSjc156560 		if (get_array_tag(argv[optind], &ctl_tag, &array_tag) !=
1239711890bcSjc156560 		    SUCCESS) {
1240711890bcSjc156560 			return (INVALID_ARG);
1241711890bcSjc156560 		}
1242711890bcSjc156560 
1243711890bcSjc156560 		/* Open controller */
1244711890bcSjc156560 		ctl_handle = raidcfg_get_controller(ctl_tag);
1245711890bcSjc156560 		if (ctl_handle <= 0) {
1246711890bcSjc156560 			(void) fprintf(stderr, "%s\n",
1247711890bcSjc156560 			    raidcfg_errstr(ctl_handle));
1248711890bcSjc156560 			return (FAILURE);
1249711890bcSjc156560 		}
1250711890bcSjc156560 
1251711890bcSjc156560 		ret = raidcfg_open_controller(ctl_handle, NULL);
1252711890bcSjc156560 		if (ret < 0) {
1253711890bcSjc156560 			(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1254711890bcSjc156560 			return (FAILURE);
1255711890bcSjc156560 		}
1256711890bcSjc156560 
1257711890bcSjc156560 		/* Get controller's attribute */
1258711890bcSjc156560 		if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) {
1259711890bcSjc156560 			(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1260711890bcSjc156560 			(void) raidcfg_close_controller(ctl_handle, NULL);
1261711890bcSjc156560 			return (FAILURE);
1262711890bcSjc156560 		}
1263711890bcSjc156560 
1264711890bcSjc156560 		if (get_disk_tag_cidl(disk_argp, &disk_tag) != SUCCESS) {
1265711890bcSjc156560 			(void) raidcfg_close_controller(ctl_handle, NULL);
1266711890bcSjc156560 			return (INVALID_ARG);
1267711890bcSjc156560 		}
1268711890bcSjc156560 
1269711890bcSjc156560 		/* Get disk handle */
1270711890bcSjc156560 		disk_handle = raidcfg_get_disk(ctl_handle, disk_tag);
1271711890bcSjc156560 		if (disk_handle <= 0) {
1272711890bcSjc156560 			(void) fprintf(stderr, "%s\n",
1273711890bcSjc156560 			    raidcfg_errstr(disk_handle));
1274711890bcSjc156560 			(void) raidcfg_close_controller(ctl_handle, NULL);
1275711890bcSjc156560 			return (FAILURE);
1276711890bcSjc156560 		}
1277711890bcSjc156560 
1278711890bcSjc156560 		/* Get array handle */
1279711890bcSjc156560 		array_handle = raidcfg_get_array(ctl_handle,
1280711890bcSjc156560 		    array_tag.idl.target_id, array_tag.idl.lun);
1281711890bcSjc156560 		if (array_handle <= 0) {
1282711890bcSjc156560 			(void) fprintf(stderr, "%s\n",
1283711890bcSjc156560 			    raidcfg_errstr(array_handle));
1284711890bcSjc156560 			(void) raidcfg_close_controller(ctl_handle, NULL);
1285711890bcSjc156560 			return (FAILURE);
1286711890bcSjc156560 		}
1287711890bcSjc156560 	}
1288711890bcSjc156560 
1289711890bcSjc156560 	hsp_relation.disk_handle = disk_handle;
1290711890bcSjc156560 	if (hsp_type) {
1291711890bcSjc156560 		/* Set or unset local HSP */
1292711890bcSjc156560 		hsp_relation.array_handle = array_handle;
1293711890bcSjc156560 	} else {
1294711890bcSjc156560 		/* Set or unset global HSP */
1295711890bcSjc156560 		hsp_relation.array_handle = OBJ_ATTR_NONE;
1296711890bcSjc156560 	}
1297711890bcSjc156560 
1298711890bcSjc156560 	/* Perform operation of set or unset */
1299711890bcSjc156560 	if (flag == HSP_SET) {
1300711890bcSjc156560 		if ((ret = raidcfg_set_hsp(1, &hsp_relation, NULL)) < 0) {
1301711890bcSjc156560 			(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1302711890bcSjc156560 			(void) raidcfg_close_controller(ctl_handle, NULL);
1303711890bcSjc156560 			return (FAILURE);
1304711890bcSjc156560 		}
1305711890bcSjc156560 
1306711890bcSjc156560 		if (hsp_type) {
1307711890bcSjc156560 			(void) printf(gettext("Set local HSP between disk %s "
1308711890bcSjc156560 			    "and RAID volume %s successfully.\n"),
1309711890bcSjc156560 			    disk_argp, argv[optind]);
1310711890bcSjc156560 		} else {
1311711890bcSjc156560 			(void) printf(gettext("Set global HSP between disk %s "
1312711890bcSjc156560 			    "and controller %s successfully.\n"),
1313711890bcSjc156560 			    disk_argp, argv[optind]);
1314711890bcSjc156560 		}
1315711890bcSjc156560 	} else {
1316711890bcSjc156560 		if ((ret = raidcfg_unset_hsp(1, &hsp_relation, NULL)) < 0) {
1317711890bcSjc156560 			(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1318711890bcSjc156560 			(void) raidcfg_close_controller(ctl_handle, NULL);
1319711890bcSjc156560 			return (FAILURE);
1320711890bcSjc156560 		}
1321711890bcSjc156560 
1322711890bcSjc156560 		if (hsp_type) {
1323711890bcSjc156560 			(void) printf(gettext("Unset local HSP between "
1324711890bcSjc156560 			    "disk %s and RAID volume %s successfully.\n"),
1325711890bcSjc156560 			    disk_argp, argv[optind]);
1326711890bcSjc156560 		} else {
1327711890bcSjc156560 			(void) printf(gettext("Unset global HSP between "
1328711890bcSjc156560 			    "disk %s and controller %s successfully.\n"),
1329711890bcSjc156560 			    disk_argp, argv[optind]);
1330711890bcSjc156560 		}
1331711890bcSjc156560 	}
1332711890bcSjc156560 	(void) raidcfg_close_controller(ctl_handle, NULL);
1333711890bcSjc156560 	return (SUCCESS);
1334711890bcSjc156560 }
1335711890bcSjc156560 
1336711890bcSjc156560 /*
1337711890bcSjc156560  * do_set_array_attr(f_flag, p_argp, argv, optind)
1338711890bcSjc156560  * This function changes array's attribute when array is running.
1339711890bcSjc156560  * The changeable attribute is up to controller's feature.
1340711890bcSjc156560  * The return value can be SUCCESS, FAILURE or INVALID_ARG.
1341711890bcSjc156560  */
1342711890bcSjc156560 static int
1343711890bcSjc156560 do_set_array_attr(uint32_t f_flag, char *p_argp, char **argv, uint32_t optind)
1344711890bcSjc156560 {
1345711890bcSjc156560 	uint32_t ctl_tag = MAX32BIT;
1346711890bcSjc156560 	array_tag_t array_tag;
1347711890bcSjc156560 	uint32_t type = MAX32BIT;
1348711890bcSjc156560 	uint32_t value = MAX32BIT;
1349711890bcSjc156560 	raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE;
1350711890bcSjc156560 	raid_obj_handle_t array_handle = INIT_HANDLE_VALUE;
1351711890bcSjc156560 
1352711890bcSjc156560 	char *param, *op = "=";
1353711890bcSjc156560 
1354711890bcSjc156560 	int ret;
1355711890bcSjc156560 
1356711890bcSjc156560 	if (argv[optind] == NULL || argv[optind + 1] != NULL) {
1357711890bcSjc156560 		return (INVALID_ARG);
1358711890bcSjc156560 	}
1359711890bcSjc156560 
1360711890bcSjc156560 	if (p_argp != NULL) {
1361711890bcSjc156560 		param = strtok(p_argp, op);
1362711890bcSjc156560 		if (strcmp(param, "wp") == 0) {
1363711890bcSjc156560 			type = SET_CACHE_WR_PLY;
1364711890bcSjc156560 			param = strtok(NULL, op);
1365711890bcSjc156560 			if (strcmp(param, "on") == 0) {
1366711890bcSjc156560 				value = CACHE_WR_ON;
1367711890bcSjc156560 			} else if (strcmp(param, "off") == 0) {
1368711890bcSjc156560 				value = CACHE_WR_OFF;
1369711890bcSjc156560 			} else {
1370711890bcSjc156560 				return (INVALID_ARG);
1371711890bcSjc156560 			}
1372*b449fa8aSyw161884 		} else if (strcmp(param, "state") == 0) {
1373*b449fa8aSyw161884 			type = SET_ACTIVATION_PLY;
1374*b449fa8aSyw161884 			param = strtok(NULL, op);
1375*b449fa8aSyw161884 			if (strcmp(param, "activate") == 0) {
1376*b449fa8aSyw161884 				value = ARRAY_ACT_ACTIVATE;
1377*b449fa8aSyw161884 			} else {
1378*b449fa8aSyw161884 				return (INVALID_ARG);
1379*b449fa8aSyw161884 			}
1380*b449fa8aSyw161884 		} else {
1381*b449fa8aSyw161884 			return (INVALID_ARG);
1382*b449fa8aSyw161884 		}
1383711890bcSjc156560 	} else {
1384711890bcSjc156560 		return (INVALID_ARG);
1385711890bcSjc156560 	}
1386711890bcSjc156560 
1387711890bcSjc156560 	if (get_array_tag(argv[optind], &ctl_tag, &array_tag) != SUCCESS) {
1388711890bcSjc156560 		return (INVALID_ARG);
1389711890bcSjc156560 	}
1390711890bcSjc156560 
1391711890bcSjc156560 	ctl_handle = raidcfg_get_controller(ctl_tag);
1392711890bcSjc156560 	if (ctl_handle <= 0) {
1393711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ctl_handle));
1394711890bcSjc156560 		return (FAILURE);
1395711890bcSjc156560 	}
1396711890bcSjc156560 
1397711890bcSjc156560 	ret = raidcfg_open_controller(ctl_handle, NULL);
1398711890bcSjc156560 	if (ret < 0) {
1399711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1400711890bcSjc156560 		return (FAILURE);
1401711890bcSjc156560 	}
1402711890bcSjc156560 
1403711890bcSjc156560 	array_handle = raidcfg_get_array(ctl_handle, array_tag.idl.target_id,
1404711890bcSjc156560 	    array_tag.idl.lun);
1405711890bcSjc156560 	if (array_handle <= 0) {
1406711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(array_handle));
1407711890bcSjc156560 		return (FAILURE);
1408711890bcSjc156560 	}
1409711890bcSjc156560 
1410711890bcSjc156560 	/* Ask user to confirm operation. */
1411711890bcSjc156560 	if (f_flag == FALSE) {
1412711890bcSjc156560 		(void) fprintf(stdout, gettext("Update attribute of "
1413711890bcSjc156560 		    "array %s (%s/%s)? "), argv[optind], yesstr, nostr);
1414711890bcSjc156560 		if (!yes()) {
1415711890bcSjc156560 			(void) fprintf(stdout,
1416711890bcSjc156560 			    gettext("Array %s not "
1417711890bcSjc156560 			    "changed.\n\n"), argv[optind]);
1418711890bcSjc156560 			(void) raidcfg_close_controller(ctl_handle, NULL);
1419711890bcSjc156560 			return (SUCCESS);
1420711890bcSjc156560 		}
1421711890bcSjc156560 	}
1422711890bcSjc156560 
1423711890bcSjc156560 	if ((ret = raidcfg_set_attr(array_handle, type, &value, NULL)) < 0) {
1424711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1425711890bcSjc156560 		(void) raidcfg_close_controller(ctl_handle, NULL);
1426711890bcSjc156560 		return (FAILURE);
1427711890bcSjc156560 	}
1428711890bcSjc156560 
1429711890bcSjc156560 	(void) printf(gettext("Set attribute of RAID volume %s "
1430711890bcSjc156560 	    "successfully.\n"), argv[optind]);
1431711890bcSjc156560 	(void) raidcfg_close_controller(ctl_handle, NULL);
1432711890bcSjc156560 
1433711890bcSjc156560 	return (SUCCESS);
1434711890bcSjc156560 }
1435711890bcSjc156560 
1436711890bcSjc156560 /*
1437711890bcSjc156560  * snapshot_raidsystem(recursive, indent, is_snapshot)
1438711890bcSjc156560  * This function prints the snapshot of whole RAID's system configuration,
1439711890bcSjc156560  * and return result as SUCCESS or FAILURE.
1440711890bcSjc156560  */
1441711890bcSjc156560 static int
1442711890bcSjc156560 snapshot_raidsystem(uint8_t recursive, uint8_t indent, uint8_t is_snapshot)
1443711890bcSjc156560 {
1444711890bcSjc156560 	raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE;
1445711890bcSjc156560 	int ret;
1446711890bcSjc156560 
1447711890bcSjc156560 	ctl_handle = raidcfg_list_head(OBJ_SYSTEM, OBJ_TYPE_CONTROLLER);
1448711890bcSjc156560 	while (ctl_handle > 0) {
1449711890bcSjc156560 		ret = raidcfg_open_controller(ctl_handle, NULL);
1450711890bcSjc156560 		if (ret == 0) {
1451711890bcSjc156560 			if (snapshot_ctl(ctl_handle, recursive, indent,
1452711890bcSjc156560 			    is_snapshot) == FAILURE) {
1453711890bcSjc156560 				(void) raidcfg_close_controller(ctl_handle,
1454711890bcSjc156560 				    NULL);
1455711890bcSjc156560 			}
1456711890bcSjc156560 		}
1457711890bcSjc156560 		ctl_handle = raidcfg_list_next(ctl_handle);
1458711890bcSjc156560 	}
1459711890bcSjc156560 	return (SUCCESS);
1460711890bcSjc156560 }
1461711890bcSjc156560 
1462711890bcSjc156560 /*
1463711890bcSjc156560  * snapshot_ctl(ctl_handle, recursive, indent, is_snapshot)
1464711890bcSjc156560  * This function prints snapshot of specified controller's configuration,
1465711890bcSjc156560  * and return result as SUCCESS or FAILURE.
1466711890bcSjc156560  */
1467711890bcSjc156560 static int
1468711890bcSjc156560 snapshot_ctl(raid_obj_handle_t ctl_handle, uint8_t recursive, uint8_t indent,
1469711890bcSjc156560     uint8_t is_snapshot)
1470711890bcSjc156560 {
1471711890bcSjc156560 	raid_obj_handle_t array_handle = INIT_HANDLE_VALUE;
1472711890bcSjc156560 	raid_obj_handle_t disk_handle = INIT_HANDLE_VALUE;
1473711890bcSjc156560 	raidcfg_controller_t ctl_attr;
1474711890bcSjc156560 	uint32_t ctl_tag;
1475711890bcSjc156560 	char ctlbuf[256];
1476711890bcSjc156560 	int ret;
1477711890bcSjc156560 
1478711890bcSjc156560 	if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) {
1479711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1480711890bcSjc156560 		return (FAILURE);
1481711890bcSjc156560 	}
1482711890bcSjc156560 
1483711890bcSjc156560 	ctl_tag = ctl_attr.controller_id;
1484711890bcSjc156560 	if (is_snapshot == FALSE) {
1485711890bcSjc156560 		print_indent(indent);
1486711890bcSjc156560 		(void) fprintf(stdout, gettext("Controller: %u\n"), ctl_tag);
1487711890bcSjc156560 	} else {
1488711890bcSjc156560 		(void) snprintf(ctlbuf, sizeof (ctlbuf), "%u \"%s\"",
1489711890bcSjc156560 		    ctl_tag, ctl_attr.controller_type);
1490711890bcSjc156560 		(void) fprintf(stdout, "%s", ctlbuf);
1491711890bcSjc156560 
1492711890bcSjc156560 		(void) fprintf(stdout, "\n");
1493711890bcSjc156560 	}
1494711890bcSjc156560 
1495711890bcSjc156560 	if (recursive == TRUE) {
1496711890bcSjc156560 		array_handle = raidcfg_list_head(ctl_handle, OBJ_TYPE_ARRAY);
1497711890bcSjc156560 		while (array_handle > 0) {
1498711890bcSjc156560 			if (snapshot_array(array_handle,
1499711890bcSjc156560 			    indent + 1, FALSE, is_snapshot) == FAILURE) {
1500711890bcSjc156560 				return (FAILURE);
1501711890bcSjc156560 			}
1502711890bcSjc156560 
1503711890bcSjc156560 			array_handle = raidcfg_list_next(array_handle);
1504711890bcSjc156560 		}
1505711890bcSjc156560 
1506711890bcSjc156560 		disk_handle = raidcfg_list_head(ctl_handle, OBJ_TYPE_DISK);
1507711890bcSjc156560 		while (disk_handle > 0) {
1508711890bcSjc156560 			if (snapshot_disk(ctl_tag, disk_handle,
1509711890bcSjc156560 			    indent + 1, is_snapshot) == FAILURE) {
1510711890bcSjc156560 				return (FAILURE);
1511711890bcSjc156560 			}
1512711890bcSjc156560 
1513711890bcSjc156560 			disk_handle = raidcfg_list_next(disk_handle);
1514711890bcSjc156560 		}
1515711890bcSjc156560 	}
1516711890bcSjc156560 	return (SUCCESS);
1517711890bcSjc156560 }
1518711890bcSjc156560 
1519711890bcSjc156560 
1520711890bcSjc156560 /*
1521711890bcSjc156560  * snapshot_array(array_handle, indent, is_sub, is_snapshot)
1522711890bcSjc156560  * This function prints snapshot of specified array's configuration,
1523711890bcSjc156560  * and return result as SUCCESS or FAILURE.
1524711890bcSjc156560  */
1525711890bcSjc156560 static int
1526711890bcSjc156560 snapshot_array(raid_obj_handle_t array_handle, uint8_t indent, uint8_t is_sub,
1527711890bcSjc156560     uint8_t is_snapshot)
1528711890bcSjc156560 {
1529711890bcSjc156560 	raid_obj_handle_t ctl_handle;
1530711890bcSjc156560 	raid_obj_handle_t subarray_handle;
1531711890bcSjc156560 	raid_obj_handle_t arraypart_handle;
1532711890bcSjc156560 	raid_obj_handle_t task_handle;
1533711890bcSjc156560 
1534711890bcSjc156560 	raidcfg_controller_t ctl_attr;
1535711890bcSjc156560 	raidcfg_array_t array_attr;
1536711890bcSjc156560 	raidcfg_arraypart_t arraypart_attr;
1537711890bcSjc156560 	raidcfg_task_t task_attr;
1538711890bcSjc156560 
1539711890bcSjc156560 	char arraybuf[256] = "\0";
1540711890bcSjc156560 	char diskbuf[256] = "\0";
1541711890bcSjc156560 	char tempbuf[256] = "\0";
1542711890bcSjc156560 	int disknum = 0;
1543711890bcSjc156560 
1544711890bcSjc156560 	uint32_t ctl_tag;
1545711890bcSjc156560 	int ret;
1546711890bcSjc156560 
1547711890bcSjc156560 	ctl_handle = raidcfg_get_container(array_handle);
1548711890bcSjc156560 	ret = raidcfg_get_attr(ctl_handle, &ctl_attr);
1549711890bcSjc156560 	if (ret < 0) {
1550711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1551711890bcSjc156560 		return (FAILURE);
1552711890bcSjc156560 	}
1553711890bcSjc156560 	ctl_tag = ctl_attr.controller_id;
1554711890bcSjc156560 
1555711890bcSjc156560 	/* Print array attribute */
1556711890bcSjc156560 	if ((ret = raidcfg_get_attr(array_handle, &array_attr)) < 0) {
1557711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1558711890bcSjc156560 		return (FAILURE);
1559711890bcSjc156560 	}
1560711890bcSjc156560 
1561711890bcSjc156560 	if (is_snapshot == FALSE) {
1562711890bcSjc156560 		print_indent(indent);
1563711890bcSjc156560 		if (is_sub == FALSE) {
1564711890bcSjc156560 			(void) fprintf(stdout, gettext("Volume:"
1565711890bcSjc156560 			    "c%ut%llud%llu\n"),
1566711890bcSjc156560 			    ctl_tag, array_attr.tag.idl.target_id,
1567711890bcSjc156560 			    array_attr.tag.idl.lun);
1568711890bcSjc156560 		} else {
1569711890bcSjc156560 			(void) fprintf(stdout, gettext("Sub-Volume\n"));
1570711890bcSjc156560 		}
1571711890bcSjc156560 	} else {
1572711890bcSjc156560 		(void) snprintf(arraybuf, sizeof (arraybuf), "c%ut%llud%llu ",
1573711890bcSjc156560 		    ctl_tag, array_attr.tag.idl.target_id,
1574711890bcSjc156560 		    array_attr.tag.idl.lun);
1575711890bcSjc156560 
1576711890bcSjc156560 		/* Check if array is in sync state */
1577711890bcSjc156560 		task_handle = raidcfg_list_head(array_handle, OBJ_TYPE_TASK);
1578711890bcSjc156560 		if (task_handle > 0) {
1579711890bcSjc156560 			(void) raidcfg_get_attr(task_handle, &task_attr);
1580711890bcSjc156560 			if (task_attr.task_func == TASK_FUNC_BUILD) {
1581711890bcSjc156560 				array_attr.state = ARRAY_STATE_SYNC;
1582711890bcSjc156560 			}
1583711890bcSjc156560 		} else {
1584711890bcSjc156560 			subarray_handle = raidcfg_list_head(array_handle,
1585711890bcSjc156560 			    OBJ_TYPE_ARRAY);
1586711890bcSjc156560 			while (subarray_handle > 0) {
1587711890bcSjc156560 				task_handle = raidcfg_list_head(subarray_handle,
1588711890bcSjc156560 				    OBJ_TYPE_TASK);
1589711890bcSjc156560 				if (task_handle > 0) {
1590711890bcSjc156560 					(void) raidcfg_get_attr(task_handle,
1591711890bcSjc156560 					    &task_attr);
1592711890bcSjc156560 					if (task_attr.task_func ==
1593711890bcSjc156560 					    TASK_FUNC_BUILD) {
1594711890bcSjc156560 						array_attr.state =
1595711890bcSjc156560 						    ARRAY_STATE_SYNC;
1596711890bcSjc156560 					}
1597711890bcSjc156560 					break;
1598711890bcSjc156560 				}
1599711890bcSjc156560 				subarray_handle =
1600711890bcSjc156560 				    raidcfg_list_next(subarray_handle);
1601711890bcSjc156560 			}
1602711890bcSjc156560 		}
1603711890bcSjc156560 
1604711890bcSjc156560 		/* Print sub array */
1605711890bcSjc156560 		subarray_handle = raidcfg_list_head(array_handle,
1606711890bcSjc156560 		    OBJ_TYPE_ARRAY);
1607711890bcSjc156560 		while (subarray_handle > 0) {
1608711890bcSjc156560 			/* print subarraypart */
1609711890bcSjc156560 			arraypart_handle = raidcfg_list_head(subarray_handle,
1610711890bcSjc156560 			    OBJ_TYPE_ARRAY_PART);
1611711890bcSjc156560 			while (arraypart_handle > 0) {
1612711890bcSjc156560 				if ((ret = raidcfg_get_attr(arraypart_handle,
1613711890bcSjc156560 				    &arraypart_attr)) < 0) {
1614711890bcSjc156560 					(void) fprintf(stderr, "%s\n",
1615711890bcSjc156560 					    raidcfg_errstr(ret));
1616711890bcSjc156560 					return (FAILURE);
1617711890bcSjc156560 				}
1618711890bcSjc156560 
1619711890bcSjc156560 				if (arraypart_attr.tag.cidl.bus == MAX64BIT) {
1620711890bcSjc156560 					(void) snprintf(tempbuf,
1621711890bcSjc156560 					    sizeof (tempbuf),
1622711890bcSjc156560 					    gettext("N/A"));
1623711890bcSjc156560 				} else {
1624711890bcSjc156560 					(void) snprintf(tempbuf,
1625711890bcSjc156560 					    sizeof (tempbuf),
1626711890bcSjc156560 					    "%llu.%llu.%llu",
1627711890bcSjc156560 					    arraypart_attr.tag.cidl.bus,
1628711890bcSjc156560 					    arraypart_attr.tag.cidl.target_id,
1629711890bcSjc156560 					    arraypart_attr.tag.cidl.lun);
1630711890bcSjc156560 				}
1631711890bcSjc156560 				(void) strcat(diskbuf, tempbuf);
1632711890bcSjc156560 				(void) strcat(diskbuf, " ");
1633711890bcSjc156560 				disknum++;
1634711890bcSjc156560 				arraypart_handle =
1635711890bcSjc156560 				    raidcfg_list_next(arraypart_handle);
1636711890bcSjc156560 			}
1637711890bcSjc156560 			subarray_handle = raidcfg_list_next(subarray_handle);
1638711890bcSjc156560 		}
1639711890bcSjc156560 
1640711890bcSjc156560 		/* Print arraypart */
1641711890bcSjc156560 		arraypart_handle = raidcfg_list_head(array_handle,
1642711890bcSjc156560 		    OBJ_TYPE_ARRAY_PART);
1643711890bcSjc156560 		while (arraypart_handle > 0) {
1644711890bcSjc156560 			if ((ret = raidcfg_get_attr(arraypart_handle,
1645711890bcSjc156560 			    &arraypart_attr)) < 0) {
1646711890bcSjc156560 				(void) fprintf(stderr, "%s\n",
1647711890bcSjc156560 				    raidcfg_errstr(ret));
1648711890bcSjc156560 				return (FAILURE);
1649711890bcSjc156560 			}
1650711890bcSjc156560 
1651711890bcSjc156560 			if (arraypart_attr.tag.cidl.bus == MAX64BIT) {
1652711890bcSjc156560 				(void) snprintf(tempbuf, sizeof (tempbuf),
1653711890bcSjc156560 				    gettext("N/A"));
1654711890bcSjc156560 			} else {
1655711890bcSjc156560 				(void) snprintf(tempbuf, sizeof (tempbuf),
1656711890bcSjc156560 				    "%llu.%llu.%llu",
1657711890bcSjc156560 				    arraypart_attr.tag.cidl.bus,
1658711890bcSjc156560 				    arraypart_attr.tag.cidl.target_id,
1659711890bcSjc156560 				    arraypart_attr.tag.cidl.lun);
1660711890bcSjc156560 			}
1661711890bcSjc156560 			(void) strcat(diskbuf, tempbuf);
1662711890bcSjc156560 			(void) strcat(diskbuf, " ");
1663711890bcSjc156560 			disknum++;
1664711890bcSjc156560 			arraypart_handle = raidcfg_list_next(arraypart_handle);
1665711890bcSjc156560 		}
1666711890bcSjc156560 		(void) snprintf(tempbuf, sizeof (tempbuf), "%u ", disknum);
1667711890bcSjc156560 		(void) strcat(arraybuf, tempbuf);
1668711890bcSjc156560 		(void) strcat(arraybuf, diskbuf);
1669711890bcSjc156560 
1670711890bcSjc156560 		switch (array_attr.raid_level) {
1671711890bcSjc156560 		case RAID_LEVEL_0:
1672711890bcSjc156560 			(void) sprintf(tempbuf, "0");
1673711890bcSjc156560 			break;
1674711890bcSjc156560 		case RAID_LEVEL_1:
1675711890bcSjc156560 			(void) sprintf(tempbuf, "1");
1676711890bcSjc156560 			break;
1677711890bcSjc156560 		case RAID_LEVEL_1E:
1678711890bcSjc156560 			(void) sprintf(tempbuf, "1E");
1679711890bcSjc156560 			break;
1680711890bcSjc156560 		case RAID_LEVEL_5:
1681711890bcSjc156560 			(void) sprintf(tempbuf, "5");
1682711890bcSjc156560 			break;
1683711890bcSjc156560 		case RAID_LEVEL_10:
1684711890bcSjc156560 			(void) sprintf(tempbuf, "10");
1685711890bcSjc156560 			break;
1686711890bcSjc156560 		case RAID_LEVEL_50:
1687711890bcSjc156560 			(void) sprintf(tempbuf, "50");
1688711890bcSjc156560 			break;
1689711890bcSjc156560 		default:
1690711890bcSjc156560 			(void) snprintf(tempbuf, sizeof (tempbuf),
1691711890bcSjc156560 			    gettext("N/A"));
1692711890bcSjc156560 			break;
1693711890bcSjc156560 		}
1694711890bcSjc156560 		(void) strcat(arraybuf, tempbuf);
1695711890bcSjc156560 		(void) fprintf(stdout, "%s ", arraybuf);
1696711890bcSjc156560 
1697711890bcSjc156560 		switch (array_attr.state) {
1698711890bcSjc156560 		case ARRAY_STATE_OPTIMAL:
1699711890bcSjc156560 			(void) fprintf(stdout, gettext("OPTIMAL"));
1700711890bcSjc156560 			break;
1701711890bcSjc156560 		case ARRAY_STATE_DEGRADED:
1702711890bcSjc156560 			(void) fprintf(stdout, gettext("DEGRADED"));
1703711890bcSjc156560 			break;
1704711890bcSjc156560 		case ARRAY_STATE_FAILED:
1705711890bcSjc156560 			(void) fprintf(stdout, gettext("FAILED"));
1706711890bcSjc156560 			break;
1707711890bcSjc156560 		case ARRAY_STATE_SYNC:
1708711890bcSjc156560 			(void) fprintf(stdout, gettext("SYNC"));
1709711890bcSjc156560 			break;
1710a6e966d7Szk194757 		case ARRAY_STATE_MISSING:
1711a6e966d7Szk194757 			(void) fprintf(stdout, gettext("MISSING"));
1712a6e966d7Szk194757 			break;
1713711890bcSjc156560 		default:
1714711890bcSjc156560 			(void) fprintf(stdout, gettext("N/A"));
1715711890bcSjc156560 			break;
1716711890bcSjc156560 		}
1717711890bcSjc156560 		(void) fprintf(stdout, "\n");
1718711890bcSjc156560 	}
1719711890bcSjc156560 
1720711890bcSjc156560 	return (SUCCESS);
1721711890bcSjc156560 }
1722711890bcSjc156560 
1723711890bcSjc156560 /*
1724711890bcSjc156560  * snapshot_disk(ctl_tag, disk_handle, indent, is_snapshot)
1725711890bcSjc156560  * This function prints snapshot of specified disk's configuration, and return
1726711890bcSjc156560  * result as SUCCESS or FAILURE.
1727711890bcSjc156560  */
1728711890bcSjc156560 static int
1729711890bcSjc156560 snapshot_disk(uint32_t ctl_tag, raid_obj_handle_t disk_handle, uint8_t indent,
1730711890bcSjc156560     uint8_t is_snapshot)
1731711890bcSjc156560 {
1732711890bcSjc156560 	raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE;
1733711890bcSjc156560 	raid_obj_handle_t hsp_handle;
1734711890bcSjc156560 
1735711890bcSjc156560 	raidcfg_controller_t ctl_attr;
1736711890bcSjc156560 	raidcfg_disk_t disk_attr;
1737711890bcSjc156560 	char diskbuf[256] = "";
1738711890bcSjc156560 	char tempbuf[256] = "";
1739711890bcSjc156560 
1740711890bcSjc156560 	int ret;
1741711890bcSjc156560 
1742711890bcSjc156560 	ctl_handle = raidcfg_get_controller(ctl_tag);
1743711890bcSjc156560 	ret = raidcfg_get_attr(ctl_handle, &ctl_attr);
1744711890bcSjc156560 	if (ret < 0) {
1745711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1746711890bcSjc156560 		return (FAILURE);
1747711890bcSjc156560 	}
1748711890bcSjc156560 
1749711890bcSjc156560 	/* Print attribute of disk */
1750711890bcSjc156560 	if ((ret = raidcfg_get_attr(disk_handle, &disk_attr)) < 0) {
1751711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1752711890bcSjc156560 		return (FAILURE);
1753711890bcSjc156560 	}
1754711890bcSjc156560 
1755711890bcSjc156560 	if (is_snapshot == FALSE) {
1756711890bcSjc156560 		print_indent(indent);
1757711890bcSjc156560 
1758711890bcSjc156560 		hsp_handle = raidcfg_list_head(disk_handle, OBJ_TYPE_HSP);
1759711890bcSjc156560 
1760711890bcSjc156560 		if (disk_attr.tag.cidl.bus == MAX64BIT) {
1761711890bcSjc156560 			(void) fprintf(stdout, gettext("Disk: N/A"));
1762711890bcSjc156560 		} else {
1763711890bcSjc156560 			(void) fprintf(stdout, gettext("Disk: %llu.%llu.%llu"),
1764711890bcSjc156560 			    disk_attr.tag.cidl.bus,
1765711890bcSjc156560 			    disk_attr.tag.cidl.target_id,
1766711890bcSjc156560 			    disk_attr.tag.cidl.lun);
1767711890bcSjc156560 		}
1768711890bcSjc156560 		if (hsp_handle > 0) {
1769711890bcSjc156560 			(void) fprintf(stdout, "(HSP)");
1770711890bcSjc156560 		}
1771711890bcSjc156560 		(void) fprintf(stdout, "\n");
1772711890bcSjc156560 	} else {
1773711890bcSjc156560 		if (disk_attr.tag.cidl.bus == MAX64BIT) {
1774711890bcSjc156560 			(void) fprintf(stdout, gettext("N/A"));
1775711890bcSjc156560 		} else {
1776711890bcSjc156560 			(void) snprintf(diskbuf, sizeof (diskbuf),
1777711890bcSjc156560 			    "%llu.%llu.%llu ",
1778711890bcSjc156560 			    disk_attr.tag.cidl.bus,
1779711890bcSjc156560 			    disk_attr.tag.cidl.target_id,
1780711890bcSjc156560 			    disk_attr.tag.cidl.lun);
1781711890bcSjc156560 		}
1782711890bcSjc156560 		hsp_handle = raidcfg_list_head(disk_handle, OBJ_TYPE_HSP);
1783711890bcSjc156560 		if (hsp_handle > 0) {
1784711890bcSjc156560 			(void) snprintf(tempbuf, sizeof (tempbuf),
1785711890bcSjc156560 			    gettext("HSP"));
1786711890bcSjc156560 		} else if (disk_attr.state == DISK_STATE_GOOD) {
1787711890bcSjc156560 			(void) snprintf(tempbuf, sizeof (tempbuf),
1788711890bcSjc156560 			    gettext("GOOD"));
1789711890bcSjc156560 		} else if (disk_attr.state == DISK_STATE_FAILED) {
1790711890bcSjc156560 			(void) snprintf(tempbuf, sizeof (tempbuf),
1791711890bcSjc156560 			    gettext("FAILED"));
1792711890bcSjc156560 		} else {
1793711890bcSjc156560 			(void) snprintf(tempbuf, sizeof (tempbuf),
1794711890bcSjc156560 			    gettext("N/A"));
1795711890bcSjc156560 		}
1796711890bcSjc156560 
1797711890bcSjc156560 		(void) strcat(diskbuf, tempbuf);
1798711890bcSjc156560 		(void) fprintf(stdout, "%s\n", diskbuf);
1799711890bcSjc156560 	}
1800711890bcSjc156560 
1801711890bcSjc156560 	return (SUCCESS);
1802711890bcSjc156560 }
1803711890bcSjc156560 
1804711890bcSjc156560 static int
1805711890bcSjc156560 print_ctl_table(raid_obj_handle_t ctl_handle)
1806711890bcSjc156560 {
1807711890bcSjc156560 	raidcfg_controller_t ctl_attr;
1808711890bcSjc156560 	char controller[8];
1809711890bcSjc156560 	int ret;
1810711890bcSjc156560 
1811711890bcSjc156560 	if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) {
1812711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1813711890bcSjc156560 		return (FAILURE);
1814711890bcSjc156560 	}
1815711890bcSjc156560 
1816711890bcSjc156560 	(void) fprintf(stdout, gettext("Controller\tType\t\tVersion"));
1817711890bcSjc156560 	(void) fprintf(stdout, "\n");
1818711890bcSjc156560 	(void) fprintf(stdout, "--------------------------------");
1819711890bcSjc156560 	(void) fprintf(stdout, "--------------------------------");
1820711890bcSjc156560 	(void) fprintf(stdout, "\n");
1821711890bcSjc156560 
1822711890bcSjc156560 	(void) snprintf(controller, sizeof (controller), "%u",
1823711890bcSjc156560 	    ctl_attr.controller_id);
1824711890bcSjc156560 	(void) printf("c%s\t\t", controller);
1825711890bcSjc156560 
1826711890bcSjc156560 	(void) print_ctl_attr(&ctl_attr);
1827711890bcSjc156560 	(void) fprintf(stdout, "\n");
1828711890bcSjc156560 
1829711890bcSjc156560 	return (SUCCESS);
1830711890bcSjc156560 }
1831711890bcSjc156560 
1832711890bcSjc156560 static int
1833711890bcSjc156560 print_array_table(raid_obj_handle_t ctl_handle, raid_obj_handle_t array_handle)
1834711890bcSjc156560 {
1835711890bcSjc156560 	raidcfg_controller_t ctl_attr;
1836711890bcSjc156560 	raidcfg_array_t array_attr;
1837711890bcSjc156560 	raidcfg_array_t subarray_attr;
1838711890bcSjc156560 	raidcfg_arraypart_t arraypart_attr;
1839711890bcSjc156560 	raidcfg_task_t task_attr;
1840711890bcSjc156560 
1841711890bcSjc156560 	raid_obj_handle_t subarray_handle;
1842711890bcSjc156560 	raid_obj_handle_t arraypart_handle;
1843711890bcSjc156560 	raid_obj_handle_t task_handle;
1844711890bcSjc156560 
1845*b449fa8aSyw161884 	char array[16];
1846711890bcSjc156560 	char arraypart[8];
1847711890bcSjc156560 	int ret;
1848711890bcSjc156560 	int i;
1849711890bcSjc156560 
1850711890bcSjc156560 	/* Controller attribute */
1851711890bcSjc156560 	if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) {
1852711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1853711890bcSjc156560 		return (FAILURE);
1854711890bcSjc156560 	}
1855711890bcSjc156560 
1856711890bcSjc156560 	/* Array attribute */
1857711890bcSjc156560 	if ((ret = raidcfg_get_attr(array_handle, &array_attr)) < 0) {
1858711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1859711890bcSjc156560 		return (FAILURE);
1860711890bcSjc156560 	}
1861711890bcSjc156560 
1862711890bcSjc156560 	/* print header */
1863711890bcSjc156560 	(void) fprintf(stdout, gettext("Volume\t\t\tSize\tStripe\tStatus\t"
1864711890bcSjc156560 	    " Cache\tRAID"));
1865711890bcSjc156560 	(void) fprintf(stdout, "\n");
1866711890bcSjc156560 	(void) fprintf(stdout, gettext("\tSub\t\t\tSize\t\t\tLevel"));
1867711890bcSjc156560 	(void) fprintf(stdout, "\n");
1868711890bcSjc156560 	(void) fprintf(stdout, gettext("\t\tDisk\t\t\t\t\t"));
1869711890bcSjc156560 	(void) fprintf(stdout, "\n");
1870711890bcSjc156560 	(void) fprintf(stdout, "--------------------------------");
1871711890bcSjc156560 	(void) fprintf(stdout, "--------------------------------");
1872711890bcSjc156560 	(void) fprintf(stdout, "\n");
1873711890bcSjc156560 
1874711890bcSjc156560 	/* print array */
1875711890bcSjc156560 	(void) snprintf(array, sizeof (array), "c%ut%llud%llu",
1876711890bcSjc156560 	    ctl_attr.controller_id, array_attr.tag.idl.target_id,
1877711890bcSjc156560 	    array_attr.tag.idl.lun);
1878*b449fa8aSyw161884 	(void) fprintf(stdout, "%s\t\t", array);
1879*b449fa8aSyw161884 	if (strlen(array) < 8)
1880*b449fa8aSyw161884 		(void) fprintf(stdout, "\t");
1881*b449fa8aSyw161884 
1882711890bcSjc156560 
1883711890bcSjc156560 	/* check if array is in sync state */
1884711890bcSjc156560 	task_handle = raidcfg_list_head(array_handle, OBJ_TYPE_TASK);
1885711890bcSjc156560 	if (task_handle > 0) {
1886711890bcSjc156560 		(void) raidcfg_get_attr(task_handle, &task_attr);
1887711890bcSjc156560 		if (task_attr.task_func == TASK_FUNC_BUILD) {
1888711890bcSjc156560 			array_attr.state = ARRAY_STATE_SYNC;
1889711890bcSjc156560 		}
1890711890bcSjc156560 	} else {
1891711890bcSjc156560 		subarray_handle = raidcfg_list_head(array_handle,
1892711890bcSjc156560 		    OBJ_TYPE_ARRAY);
1893711890bcSjc156560 		while (subarray_handle > 0) {
1894711890bcSjc156560 			task_handle = raidcfg_list_head(subarray_handle,
1895711890bcSjc156560 			    OBJ_TYPE_TASK);
1896711890bcSjc156560 			if (task_handle > 0) {
1897711890bcSjc156560 				(void) raidcfg_get_attr(task_handle,
1898711890bcSjc156560 				    &task_attr);
1899711890bcSjc156560 				if (task_attr.task_func == TASK_FUNC_BUILD) {
1900711890bcSjc156560 					array_attr.state = ARRAY_STATE_SYNC;
1901711890bcSjc156560 				}
1902711890bcSjc156560 				break;
1903711890bcSjc156560 			}
1904711890bcSjc156560 			subarray_handle = raidcfg_list_next(subarray_handle);
1905711890bcSjc156560 		}
1906711890bcSjc156560 	}
1907711890bcSjc156560 
1908711890bcSjc156560 	(void) print_array_attr(&array_attr);
1909711890bcSjc156560 	(void) fprintf(stdout, "\n");
1910711890bcSjc156560 
1911711890bcSjc156560 	/* Print sub array */
1912711890bcSjc156560 	i = 0;			/* Count sub array number */
1913711890bcSjc156560 	subarray_handle = raidcfg_list_head(array_handle, OBJ_TYPE_ARRAY);
1914711890bcSjc156560 	while (subarray_handle > 0) {
1915711890bcSjc156560 		if ((ret = raidcfg_get_attr(subarray_handle,
1916711890bcSjc156560 		    &subarray_attr)) < 0) {
1917711890bcSjc156560 			(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1918711890bcSjc156560 			return (FAILURE);
1919711890bcSjc156560 		}
1920711890bcSjc156560 
1921711890bcSjc156560 		/* Use sub0/sub1 here, not cxtxd0 for subarray */
1922711890bcSjc156560 		(void) snprintf(array, sizeof (array), "sub%u", i++);
1923711890bcSjc156560 		(void) fprintf(stdout, "\t%s\t\t", array);
1924711890bcSjc156560 
1925711890bcSjc156560 		/* Check if array is in sync */
1926711890bcSjc156560 		task_handle = raidcfg_list_head(subarray_handle, OBJ_TYPE_TASK);
1927711890bcSjc156560 		if (task_handle > 0) {
1928711890bcSjc156560 			(void) raidcfg_get_attr(task_handle, &task_attr);
1929711890bcSjc156560 			if (task_attr.task_func == TASK_FUNC_BUILD) {
1930711890bcSjc156560 				subarray_attr.state = ARRAY_STATE_SYNC;
1931711890bcSjc156560 			}
1932711890bcSjc156560 		}
1933711890bcSjc156560 
1934711890bcSjc156560 		(void) print_array_attr(&subarray_attr);
1935711890bcSjc156560 		(void) fprintf(stdout, "\n");
1936711890bcSjc156560 
1937711890bcSjc156560 		/* Print subarraypart */
1938711890bcSjc156560 		arraypart_handle = raidcfg_list_head(subarray_handle,
1939711890bcSjc156560 		    OBJ_TYPE_ARRAY_PART);
1940711890bcSjc156560 		while (arraypart_handle > 0) {
1941711890bcSjc156560 			if ((ret = raidcfg_get_attr(arraypart_handle,
1942711890bcSjc156560 			    &arraypart_attr)) < 0) {
1943711890bcSjc156560 				(void) fprintf(stderr, "%s\n",
1944711890bcSjc156560 				    raidcfg_errstr(ret));
1945711890bcSjc156560 				return (FAILURE);
1946711890bcSjc156560 			}
1947711890bcSjc156560 
1948711890bcSjc156560 			if (arraypart_attr.tag.cidl.bus == MAX64BIT) {
1949711890bcSjc156560 				(void) snprintf(arraypart, sizeof (arraypart),
1950711890bcSjc156560 				    gettext("N/A"));
1951711890bcSjc156560 			} else {
1952711890bcSjc156560 				(void) snprintf(arraypart, sizeof (arraypart),
1953711890bcSjc156560 				    "%llu.%llu.%llu",
1954711890bcSjc156560 				    arraypart_attr.tag.cidl.bus,
1955711890bcSjc156560 				    arraypart_attr.tag.cidl.target_id,
1956711890bcSjc156560 				    arraypart_attr.tag.cidl.lun);
1957711890bcSjc156560 			}
1958711890bcSjc156560 
1959711890bcSjc156560 			(void) fprintf(stdout, "\t\t%s\t", arraypart);
1960711890bcSjc156560 			(void) print_arraypart_attr(&arraypart_attr);
1961711890bcSjc156560 			(void) fprintf(stdout, "\n");
1962711890bcSjc156560 			arraypart_handle = raidcfg_list_next(arraypart_handle);
1963711890bcSjc156560 		}
1964711890bcSjc156560 		subarray_handle = raidcfg_list_next(subarray_handle);
1965711890bcSjc156560 	}
1966711890bcSjc156560 
1967711890bcSjc156560 	/* Print arraypart */
1968711890bcSjc156560 	arraypart_handle = raidcfg_list_head(array_handle,
1969711890bcSjc156560 	    OBJ_TYPE_ARRAY_PART);
1970711890bcSjc156560 	while (arraypart_handle > 0) {
1971711890bcSjc156560 		if ((ret = raidcfg_get_attr(arraypart_handle,
1972711890bcSjc156560 		    &arraypart_attr)) < 0) {
1973711890bcSjc156560 			(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
1974711890bcSjc156560 			return (FAILURE);
1975711890bcSjc156560 		}
1976711890bcSjc156560 
1977711890bcSjc156560 		if (arraypart_attr.tag.cidl.bus == MAX64BIT) {
1978711890bcSjc156560 			(void) snprintf(arraypart, sizeof (arraypart),
1979711890bcSjc156560 			    gettext("N/A"));
1980711890bcSjc156560 		} else {
1981711890bcSjc156560 			(void) snprintf(arraypart, sizeof (arraypart),
1982711890bcSjc156560 			    "%llu.%llu.%llu",
1983711890bcSjc156560 			    arraypart_attr.tag.cidl.bus,
1984711890bcSjc156560 			    arraypart_attr.tag.cidl.target_id,
1985711890bcSjc156560 			    arraypart_attr.tag.cidl.lun);
1986711890bcSjc156560 		}
1987711890bcSjc156560 
1988711890bcSjc156560 		(void) fprintf(stdout, "\t\t%s\t", arraypart);
1989711890bcSjc156560 		(void) print_arraypart_attr(&arraypart_attr);
1990711890bcSjc156560 		(void) fprintf(stdout, "\n");
1991711890bcSjc156560 		arraypart_handle = raidcfg_list_next(arraypart_handle);
1992711890bcSjc156560 	}
1993711890bcSjc156560 
1994711890bcSjc156560 	return (SUCCESS);
1995711890bcSjc156560 }
1996711890bcSjc156560 
1997711890bcSjc156560 static int
1998711890bcSjc156560 print_disk_table(raid_obj_handle_t ctl_handle, raid_obj_handle_t disk_handle)
1999711890bcSjc156560 {
2000711890bcSjc156560 	raidcfg_controller_t ctl_attr;
2001711890bcSjc156560 	raidcfg_disk_t disk_attr;
2002*b449fa8aSyw161884 	raidcfg_prop_t *prop_attr, *prop_attr2;
2003*b449fa8aSyw161884 	raid_obj_handle_t prop_handle;
2004711890bcSjc156560 	char disk[8];
2005711890bcSjc156560 	int ret;
2006711890bcSjc156560 
2007711890bcSjc156560 	if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) {
2008711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
2009711890bcSjc156560 		return (FAILURE);
2010711890bcSjc156560 	}
2011711890bcSjc156560 
2012711890bcSjc156560 	if ((ret = raidcfg_get_attr(disk_handle, &disk_attr)) < 0) {
2013711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
2014711890bcSjc156560 		return (FAILURE);
2015711890bcSjc156560 	}
2016711890bcSjc156560 
2017711890bcSjc156560 	/* Print header */
20189415b234Szk194757 	(void) fprintf(stdout, gettext("Disk\tVendor\tProduct\t\tFirmware\t"
20199415b234Szk194757 	    "Capacity\tStatus\tHSP"));
2020711890bcSjc156560 	(void) fprintf(stdout, "\n");
20219415b234Szk194757 	(void) fprintf(stdout, "--------------------------------------");
20229415b234Szk194757 	(void) fprintf(stdout, "--------------------------------------");
2023711890bcSjc156560 	(void) fprintf(stdout, "\n");
2024711890bcSjc156560 
2025711890bcSjc156560 
2026711890bcSjc156560 	(void) snprintf(disk, sizeof (disk), "%llu.%llu.%llu",
2027711890bcSjc156560 	    disk_attr.tag.cidl.bus,
2028711890bcSjc156560 	    disk_attr.tag.cidl.target_id,
2029711890bcSjc156560 	    disk_attr.tag.cidl.lun);
2030711890bcSjc156560 
2031711890bcSjc156560 	(void) fprintf(stdout, "%s\t", disk);
2032711890bcSjc156560 
2033711890bcSjc156560 	(void) print_disk_attr(ctl_handle, disk_handle, &disk_attr);
2034711890bcSjc156560 
2035*b449fa8aSyw161884 	prop_attr = calloc(1, sizeof (raidcfg_prop_t));
2036*b449fa8aSyw161884 	if (prop_attr == NULL) {
2037*b449fa8aSyw161884 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ERR_NOMEM));
2038*b449fa8aSyw161884 		return (FAILURE);
2039*b449fa8aSyw161884 	}
2040*b449fa8aSyw161884 
2041*b449fa8aSyw161884 	prop_handle = raidcfg_list_head(disk_handle, OBJ_TYPE_PROP);
2042*b449fa8aSyw161884 	if (prop_handle == 0) {
2043*b449fa8aSyw161884 		free(prop_attr);
2044*b449fa8aSyw161884 		return (SUCCESS);
2045*b449fa8aSyw161884 	}
2046*b449fa8aSyw161884 
2047*b449fa8aSyw161884 	do {
2048*b449fa8aSyw161884 		prop_attr->prop_size = 0;
2049*b449fa8aSyw161884 		if ((ret = raidcfg_get_attr(prop_handle, prop_attr)) < 0) {
2050*b449fa8aSyw161884 			free(prop_attr);
2051*b449fa8aSyw161884 			(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
2052*b449fa8aSyw161884 			return (FAILURE);
2053*b449fa8aSyw161884 		}
2054*b449fa8aSyw161884 		if (prop_attr->prop_type == PROP_GUID)
2055*b449fa8aSyw161884 			break;
2056*b449fa8aSyw161884 	} while (prop_handle != 0);
2057*b449fa8aSyw161884 
2058*b449fa8aSyw161884 	prop_attr2 = realloc(prop_attr,
2059*b449fa8aSyw161884 	    sizeof (raidcfg_prop_t) + prop_attr->prop_size);
2060*b449fa8aSyw161884 	free(prop_attr);
2061*b449fa8aSyw161884 	if (prop_attr2 == NULL) {
2062*b449fa8aSyw161884 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ERR_NOMEM));
2063*b449fa8aSyw161884 		return (FAILURE);
2064*b449fa8aSyw161884 	}
2065*b449fa8aSyw161884 
2066*b449fa8aSyw161884 	if ((ret = raidcfg_get_attr(prop_handle, prop_attr2)) < 0) {
2067*b449fa8aSyw161884 		free(prop_attr2);
2068*b449fa8aSyw161884 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
2069*b449fa8aSyw161884 		return (FAILURE);
2070*b449fa8aSyw161884 	}
2071*b449fa8aSyw161884 
2072*b449fa8aSyw161884 	(void) fprintf(stdout, "GUID:%s\n", prop_attr2->prop);
2073*b449fa8aSyw161884 
2074*b449fa8aSyw161884 	free(prop_attr2);
2075711890bcSjc156560 	return (SUCCESS);
2076711890bcSjc156560 }
2077711890bcSjc156560 
2078711890bcSjc156560 /*
2079711890bcSjc156560  * print_ctl_attr(attrp)
2080711890bcSjc156560  * This function prints attribute of specified controller, and return
2081711890bcSjc156560  * result as SUCCESS or FAILURE.
2082711890bcSjc156560  */
2083711890bcSjc156560 static int
2084711890bcSjc156560 print_ctl_attr(raidcfg_controller_t *attrp)
2085711890bcSjc156560 {
2086711890bcSjc156560 	char type[CONTROLLER_TYPE_LEN];
2087711890bcSjc156560 	char version[CONTROLLER_FW_LEN];
2088711890bcSjc156560 
2089711890bcSjc156560 	if (attrp == NULL) {
2090711890bcSjc156560 		return (FAILURE);
2091711890bcSjc156560 	}
2092711890bcSjc156560 
2093711890bcSjc156560 	(void) snprintf(type, sizeof (type), "%s", attrp->controller_type);
2094711890bcSjc156560 	(void) fprintf(stdout, "%-16s", type);
2095711890bcSjc156560 
2096711890bcSjc156560 	(void) snprintf(version, sizeof (version), "%s", attrp->fw_version);
2097711890bcSjc156560 	(void) fprintf(stdout, "%s", version);
2098711890bcSjc156560 
2099711890bcSjc156560 	return (SUCCESS);
2100711890bcSjc156560 }
2101711890bcSjc156560 
2102711890bcSjc156560 /*
2103711890bcSjc156560  * print_array_attr(attrp)
2104711890bcSjc156560  * This function prints attribute of specified array, and return
2105711890bcSjc156560  * result as SUCCESS or FAILURE.
2106711890bcSjc156560  */
2107711890bcSjc156560 static int
2108711890bcSjc156560 print_array_attr(raidcfg_array_t *attrp)
2109711890bcSjc156560 {
2110711890bcSjc156560 	char capacity[8];
2111711890bcSjc156560 	char stripe_size[8];
2112711890bcSjc156560 	char raid_level[8];
2113711890bcSjc156560 
2114711890bcSjc156560 	if (attrp == NULL) {
2115711890bcSjc156560 		return (FAILURE);
2116711890bcSjc156560 	}
2117711890bcSjc156560 
2118711890bcSjc156560 	if (attrp->capacity != MAX64BIT) {
2119711890bcSjc156560 		if (size_to_string(attrp->capacity, capacity, 8) != SUCCESS) {
2120711890bcSjc156560 			return (FAILURE);
2121711890bcSjc156560 		}
2122711890bcSjc156560 		(void) printf("%s\t", capacity);
2123711890bcSjc156560 	} else {
2124711890bcSjc156560 		(void) printf(gettext("N/A\t"));
2125711890bcSjc156560 	}
2126711890bcSjc156560 
2127711890bcSjc156560 	if (attrp->stripe_size != MAX32BIT) {
2128711890bcSjc156560 		(void) snprintf(stripe_size, sizeof (stripe_size), "%uK",
2129711890bcSjc156560 		    attrp->stripe_size / 1024);
2130711890bcSjc156560 		(void) printf("%s\t", stripe_size);
2131711890bcSjc156560 	} else {
2132711890bcSjc156560 		(void) printf(gettext("N/A\t"));
2133711890bcSjc156560 	}
2134711890bcSjc156560 
2135*b449fa8aSyw161884 	if (attrp->state & ARRAY_STATE_INACTIVATE)
2136*b449fa8aSyw161884 		(void) printf("%-8s", gettext("INACTIVE"));
2137*b449fa8aSyw161884 	else {
2138711890bcSjc156560 		switch (attrp->state) {
2139711890bcSjc156560 		case ARRAY_STATE_OPTIMAL:
2140711890bcSjc156560 			(void) printf("%-8s", gettext("OPTIMAL"));
2141711890bcSjc156560 			break;
2142711890bcSjc156560 		case ARRAY_STATE_DEGRADED:
2143711890bcSjc156560 			(void) printf("%-8s", gettext("DEGRADED"));
2144711890bcSjc156560 			break;
2145711890bcSjc156560 		case ARRAY_STATE_FAILED:
2146711890bcSjc156560 			(void) printf("%-8s", gettext("FAILED"));
2147711890bcSjc156560 			break;
2148711890bcSjc156560 		case ARRAY_STATE_SYNC:
2149711890bcSjc156560 			(void) printf("%-8s", gettext("SYNC"));
2150711890bcSjc156560 			break;
2151a6e966d7Szk194757 		case ARRAY_STATE_MISSING:
2152a6e966d7Szk194757 			(void) printf("%-8s", gettext("MISSING"));
2153a6e966d7Szk194757 			break;
2154711890bcSjc156560 		default:
2155711890bcSjc156560 			(void) printf("%-8s", gettext("N/A"));
2156711890bcSjc156560 			break;
2157711890bcSjc156560 		}
2158*b449fa8aSyw161884 	}
2159711890bcSjc156560 	(void) printf(" ");
2160711890bcSjc156560 
2161711890bcSjc156560 	if (attrp->write_policy == CACHE_WR_OFF) {
2162711890bcSjc156560 		(void) printf(gettext("OFF"));
2163711890bcSjc156560 	} else if (attrp->write_policy == CACHE_WR_ON) {
2164711890bcSjc156560 		(void) printf(gettext("ON"));
2165711890bcSjc156560 	} else {
2166711890bcSjc156560 		(void) printf(gettext("N/A"));
2167711890bcSjc156560 	}
2168711890bcSjc156560 	(void) printf("\t");
2169711890bcSjc156560 
2170711890bcSjc156560 	switch (attrp->raid_level) {
2171711890bcSjc156560 	case RAID_LEVEL_0:
2172711890bcSjc156560 		(void) sprintf(raid_level, "RAID0");
2173711890bcSjc156560 		break;
2174711890bcSjc156560 	case RAID_LEVEL_1:
2175711890bcSjc156560 		(void) sprintf(raid_level, "RAID1");
2176711890bcSjc156560 		break;
2177711890bcSjc156560 	case RAID_LEVEL_1E:
2178711890bcSjc156560 		(void) sprintf(raid_level, "RAID1E");
2179711890bcSjc156560 		break;
2180711890bcSjc156560 	case RAID_LEVEL_5:
2181711890bcSjc156560 		(void) sprintf(raid_level, "RAID5");
2182711890bcSjc156560 		break;
2183711890bcSjc156560 	case RAID_LEVEL_10:
2184711890bcSjc156560 		(void) sprintf(raid_level, "RAID10");
2185711890bcSjc156560 		break;
2186711890bcSjc156560 	case RAID_LEVEL_50:
2187711890bcSjc156560 		(void) sprintf(raid_level, "RAID50");
2188711890bcSjc156560 		break;
2189711890bcSjc156560 	default:
2190711890bcSjc156560 		(void) snprintf(raid_level, sizeof (raid_level),
2191711890bcSjc156560 		    gettext("N/A"));
2192711890bcSjc156560 		break;
2193711890bcSjc156560 	}
2194711890bcSjc156560 	(void) printf("%s", raid_level);
2195711890bcSjc156560 
2196711890bcSjc156560 	return (SUCCESS);
2197711890bcSjc156560 }
2198711890bcSjc156560 
2199711890bcSjc156560 /*
2200711890bcSjc156560  * print_arraypart_attr(attrp)
2201711890bcSjc156560  * This function print attribute of specified arraypart, and return
2202711890bcSjc156560  * result as SUCCESS or FAILURE.
2203711890bcSjc156560  */
2204711890bcSjc156560 static int
2205711890bcSjc156560 print_arraypart_attr(raidcfg_arraypart_t *attrp)
2206711890bcSjc156560 {
2207711890bcSjc156560 	char size[8];
2208711890bcSjc156560 
2209711890bcSjc156560 	if (attrp == NULL) {
2210711890bcSjc156560 		return (FAILURE);
2211711890bcSjc156560 	}
2212711890bcSjc156560 
2213711890bcSjc156560 	if (attrp->size != MAX64BIT) {
2214711890bcSjc156560 		if (size_to_string(attrp->size, size, 8) != SUCCESS) {
2215711890bcSjc156560 			return (FAILURE);
2216711890bcSjc156560 		}
2217711890bcSjc156560 		(void) printf("%s\t", size);
2218711890bcSjc156560 	} else {
2219711890bcSjc156560 		(void) printf(gettext("N/A\t"));
2220711890bcSjc156560 	}
2221711890bcSjc156560 
2222711890bcSjc156560 	(void) printf("\t");
2223711890bcSjc156560 
2224711890bcSjc156560 	if (attrp->state == DISK_STATE_GOOD) {
2225711890bcSjc156560 		(void) printf(gettext("GOOD"));
2226711890bcSjc156560 	} else if (attrp->state == DISK_STATE_FAILED) {
2227711890bcSjc156560 		(void) printf(gettext("FAILED"));
2228711890bcSjc156560 	} else {
2229711890bcSjc156560 		(void) printf(gettext("N/A"));
2230711890bcSjc156560 	}
2231711890bcSjc156560 	(void) printf("\t");
2232711890bcSjc156560 
2233711890bcSjc156560 	return (SUCCESS);
2234711890bcSjc156560 }
2235711890bcSjc156560 
2236711890bcSjc156560 /*
2237711890bcSjc156560  * print_disk_attr(ctl_handle, disk_handle, attrp)
2238711890bcSjc156560  * This function prints attribute of specified disk, and return
2239711890bcSjc156560  * result as SUCCESS or FAILURE.
2240711890bcSjc156560  */
2241711890bcSjc156560 static int
2242711890bcSjc156560 print_disk_attr(raid_obj_handle_t ctl_handle, raid_obj_handle_t disk_handle,
2243711890bcSjc156560 	raidcfg_disk_t *attrp)
2244711890bcSjc156560 {
2245711890bcSjc156560 	char vendor[DISK_VENDER_LEN];
2246711890bcSjc156560 	char product[DISK_PRODUCT_LEN];
22479415b234Szk194757 	char revision[DISK_REV_LEN + 1];
2248711890bcSjc156560 	char capacity[16];
2249711890bcSjc156560 	char hsp[16];
2250711890bcSjc156560 
2251711890bcSjc156560 	raid_obj_handle_t hsp_handle;
2252711890bcSjc156560 	raidcfg_hsp_t hsp_attr;
2253711890bcSjc156560 	raidcfg_controller_t ctl_attr;
2254711890bcSjc156560 	int ret;
2255711890bcSjc156560 	char is_indent;
2256711890bcSjc156560 
2257711890bcSjc156560 	if (attrp == NULL) {
2258711890bcSjc156560 		return (FAILURE);
2259711890bcSjc156560 	}
2260711890bcSjc156560 
2261711890bcSjc156560 	(void) snprintf(vendor, sizeof (vendor), "%s", attrp->vendorid);
2262711890bcSjc156560 	(void) printf("%s\t", vendor);
2263711890bcSjc156560 
2264711890bcSjc156560 	(void) snprintf(product, sizeof (product), "%s", attrp->productid);
2265711890bcSjc156560 	(void) printf("%s\t", product);
2266711890bcSjc156560 
22679415b234Szk194757 	(void) snprintf(revision, sizeof (revision), "%s", attrp->revision);
22689415b234Szk194757 	(void) printf("%s\t\t", revision);
22699415b234Szk194757 
2270711890bcSjc156560 	if (attrp->capacity != MAX64BIT) {
2271711890bcSjc156560 		if (size_to_string(attrp->capacity, capacity, 16) != SUCCESS) {
2272711890bcSjc156560 			return (FAILURE);
2273711890bcSjc156560 		}
2274711890bcSjc156560 		(void) printf("%s\t\t", capacity);
2275711890bcSjc156560 	} else {
2276711890bcSjc156560 		(void) printf(gettext("N/A"));
2277711890bcSjc156560 	}
2278711890bcSjc156560 
2279711890bcSjc156560 	if (attrp->state == DISK_STATE_GOOD) {
2280711890bcSjc156560 		(void) printf(gettext("GOOD"));
2281711890bcSjc156560 	} else if (attrp->state == DISK_STATE_FAILED) {
2282711890bcSjc156560 		(void) printf(gettext("FAILED"));
2283711890bcSjc156560 	} else {
2284711890bcSjc156560 		(void) printf(gettext("N/A"));
2285711890bcSjc156560 	}
2286711890bcSjc156560 	(void) printf("\t");
2287711890bcSjc156560 
2288711890bcSjc156560 	/* Controller attribute */
2289711890bcSjc156560 	if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) {
2290711890bcSjc156560 		(void) fprintf(stderr, "%s\n", raidcfg_errstr(ret));
2291711890bcSjc156560 		return (FAILURE);
2292711890bcSjc156560 	}
2293711890bcSjc156560 
2294711890bcSjc156560 	hsp_handle = raidcfg_list_head(disk_handle, OBJ_TYPE_HSP);
2295711890bcSjc156560 	if (hsp_handle == 0) {
2296711890bcSjc156560 		(void) printf(gettext("N/A\n"));
2297711890bcSjc156560 	} else {
2298711890bcSjc156560 		is_indent = FALSE;
2299711890bcSjc156560 		while (hsp_handle > 0) {
2300711890bcSjc156560 			if ((ret = raidcfg_get_attr(hsp_handle,
2301711890bcSjc156560 			    &hsp_attr)) < 0) {
2302711890bcSjc156560 				(void) fprintf(stderr, "%s\n",
2303711890bcSjc156560 				    raidcfg_errstr(ret));
2304711890bcSjc156560 				return (FAILURE);
2305711890bcSjc156560 			}
2306711890bcSjc156560 
2307711890bcSjc156560 			if (is_indent == TRUE) {
2308711890bcSjc156560 				(void) printf("\t\t\t\t\t\t\t");
2309711890bcSjc156560 			} else {
2310711890bcSjc156560 				is_indent = TRUE;
2311711890bcSjc156560 			}
2312711890bcSjc156560 
2313711890bcSjc156560 			if (hsp_attr.type == HSP_TYPE_LOCAL) {
2314711890bcSjc156560 				(void) snprintf(hsp, sizeof (hsp),
2315711890bcSjc156560 				    "c%ut%llud%llu",
2316711890bcSjc156560 				    ctl_attr.controller_id,
2317711890bcSjc156560 				    hsp_attr.tag.idl.target_id,
2318711890bcSjc156560 				    hsp_attr.tag.idl.lun);
2319711890bcSjc156560 				(void) printf("%s\n", hsp);
2320711890bcSjc156560 			} else if (hsp_attr.type == HSP_TYPE_GLOBAL) {
2321711890bcSjc156560 				(void) printf(gettext("Global\n"));
2322711890bcSjc156560 			} else {
2323711890bcSjc156560 				return (FAILURE);
2324711890bcSjc156560 			}
2325711890bcSjc156560 
2326711890bcSjc156560 			hsp_handle = raidcfg_list_next(hsp_handle);
2327711890bcSjc156560 		}
2328711890bcSjc156560 	}
2329711890bcSjc156560 	return (SUCCESS);
2330711890bcSjc156560 }
2331711890bcSjc156560 
2332711890bcSjc156560 
2333711890bcSjc156560 /*
2334711890bcSjc156560  * print_indent(indent)
2335711890bcSjc156560  * This function prints specified number of tab characters. It's used to
2336711890bcSjc156560  * format layout.
2337711890bcSjc156560  */
23387f000930Syw161884 static void
2339711890bcSjc156560 print_indent(uint8_t indent)
23407f000930Syw161884 {
2341711890bcSjc156560 	uint32_t i;
2342711890bcSjc156560 	for (i = 0; i < indent; i++) {
2343711890bcSjc156560 		(void) fprintf(stdout, "\t");
23447f000930Syw161884 	}
23457f000930Syw161884 }
23467f000930Syw161884 
2347711890bcSjc156560 /*
2348711890bcSjc156560  * get_disk_handle_cidl(ctl_tag, disks_argp, comps_num, handlespp)
2349711890bcSjc156560  * This function parses the string of disk argument, and gets the disks tag
2350711890bcSjc156560  * and separators from the string. Then it translates the tag to handle, and
2351711890bcSjc156560  * stores handles and separators to new buffer pointed by parameter handlespp.
2352711890bcSjc156560  * The format of disk_arg must be C:ID:L, for example, it is 0.1.0. The first
2353711890bcSjc156560  * "0" is channel number, and the second "1" is target number, and the third
2354711890bcSjc156560  * "0" is LUN number. The disk tags are separated by comma and parenthesis.
2355711890bcSjc156560  * Function returns SUCCESS or FAILURE.
2356711890bcSjc156560  */
23577c478bd9Sstevel@tonic-gate static int
2358711890bcSjc156560 get_disk_handle_cidl(uint32_t ctl_tag, char *disks_argp, int *comps_nump,
2359711890bcSjc156560 	raid_obj_handle_t **handlespp)
23607c478bd9Sstevel@tonic-gate {
2361711890bcSjc156560 	int len = 0;
2362711890bcSjc156560 	int i = 0, j = 0;
2363711890bcSjc156560 	char *p, *t;
2364711890bcSjc156560 	char *delimit = " ";
2365711890bcSjc156560 	char *disks_str;
2366711890bcSjc156560 	disk_tag_t disk_tag;
23677c478bd9Sstevel@tonic-gate 
2368711890bcSjc156560 	if (disks_argp == NULL || comps_nump == NULL) {
2369711890bcSjc156560 		return (FAILURE);
2370711890bcSjc156560 	}
2371711890bcSjc156560 
2372711890bcSjc156560 	p = disks_argp;
2373711890bcSjc156560 	len = strlen(disks_argp);
2374711890bcSjc156560 
2375711890bcSjc156560 	if ((disks_str = (char *)malloc(3 * len + 4)) == NULL) {
2376711890bcSjc156560 		return (FAILURE);
2377711890bcSjc156560 	}
2378711890bcSjc156560 
2379711890bcSjc156560 	/* Insert whitespace between disk tags, '(' , and ')' */
2380711890bcSjc156560 	disks_str[j ++] = '(';
2381711890bcSjc156560 	disks_str[j ++] = ' ';
2382711890bcSjc156560 
2383711890bcSjc156560 	while (p[i] != '\0') {
2384711890bcSjc156560 		if (p[i] == ')' || p[i] == '(') {
2385711890bcSjc156560 			disks_str[j ++] = ' ';
2386711890bcSjc156560 			disks_str[j ++] = p[i];
2387711890bcSjc156560 			disks_str[j ++] = ' ';
2388711890bcSjc156560 		} else
2389711890bcSjc156560 			disks_str[j ++] = p[i];
2390711890bcSjc156560 		i ++;
2391711890bcSjc156560 	}
2392711890bcSjc156560 	disks_str[j ++] = ' ';
2393711890bcSjc156560 	disks_str[j ++] = ')';
2394711890bcSjc156560 	disks_str[j] = '\0';
2395711890bcSjc156560 
2396711890bcSjc156560 	len = strlen(disks_str) + 1;
2397711890bcSjc156560 
2398711890bcSjc156560 	if ((t = (char *)malloc(len)) == NULL) {
2399711890bcSjc156560 		return (FAILURE);
2400711890bcSjc156560 	}
2401711890bcSjc156560 	(void) memcpy(t, disks_str, len);
2402711890bcSjc156560 	p = strtok(t, delimit);
2403711890bcSjc156560 	while (p != NULL) {
2404711890bcSjc156560 		(*comps_nump)++;
2405711890bcSjc156560 		p = strtok(NULL, delimit);
2406711890bcSjc156560 	}
2407711890bcSjc156560 	free(t);
2408711890bcSjc156560 
2409711890bcSjc156560 	*handlespp = calloc(*comps_nump, sizeof (raid_obj_handle_t));
2410711890bcSjc156560 	if (*handlespp == NULL) {
2411711890bcSjc156560 		return (FAILURE);
2412711890bcSjc156560 	}
2413711890bcSjc156560 
2414711890bcSjc156560 	for (i = 0; i < *comps_nump; i++)
2415711890bcSjc156560 		(*handlespp)[i] = INIT_HANDLE_VALUE;
2416711890bcSjc156560 
2417711890bcSjc156560 	i = 0;
2418711890bcSjc156560 	p = strtok(disks_str, delimit);
2419711890bcSjc156560 	while (p != NULL) {
2420711890bcSjc156560 		if (*p == '(') {
2421711890bcSjc156560 			(*handlespp)[i] = OBJ_SEPARATOR_BEGIN;
2422711890bcSjc156560 		} else if (*p == ')') {
2423711890bcSjc156560 			(*handlespp)[i] = OBJ_SEPARATOR_END;
2424711890bcSjc156560 		} else {
2425711890bcSjc156560 			if (get_disk_tag_cidl(p, &disk_tag) != SUCCESS) {
2426711890bcSjc156560 				free(*handlespp);
2427711890bcSjc156560 				free(disks_str);
2428711890bcSjc156560 				return (INVALID_ARG);
2429711890bcSjc156560 			}
2430711890bcSjc156560 			(*handlespp)[i] =
2431711890bcSjc156560 			    raidcfg_get_disk(raidcfg_get_controller(ctl_tag),
2432711890bcSjc156560 			    disk_tag);
2433711890bcSjc156560 			if ((*handlespp)[i] <= 0) {
2434711890bcSjc156560 				(void) fprintf(stderr, "%s\n",
2435711890bcSjc156560 				    raidcfg_errstr((*handlespp)[i]));
2436711890bcSjc156560 				free(*handlespp);
2437711890bcSjc156560 				free(disks_str);
2438711890bcSjc156560 				return (FAILURE);
2439711890bcSjc156560 			}
2440711890bcSjc156560 		}
2441711890bcSjc156560 		p = strtok(NULL, delimit);
2442711890bcSjc156560 		i++;
2443711890bcSjc156560 	}
2444711890bcSjc156560 
2445711890bcSjc156560 	free(disks_str);
2446711890bcSjc156560 	return (SUCCESS);
24477c478bd9Sstevel@tonic-gate }
24487c478bd9Sstevel@tonic-gate 
24497c478bd9Sstevel@tonic-gate /*
2450711890bcSjc156560  * get_disk_handle_ctd(disks_num, disks_argpp, ctl_tagp, disks_handlep)
2451711890bcSjc156560  * This function parses string of single disk with "ctd" format, for example,
2452711890bcSjc156560  * c0t0d0, and translates it to controller tag and disk tag.
2453711890bcSjc156560  * Then it calls lib api and get disk handle. The controller tag and disk
2454711890bcSjc156560  * handle are both returned by out parameters.
2455711890bcSjc156560  * The return value is SUCCESS or FAILURE.
24567c478bd9Sstevel@tonic-gate  */
2457711890bcSjc156560 static int
2458711890bcSjc156560 get_disk_handle_ctd(int disks_num, char **disks_argpp, uint32_t *ctl_tagp,
2459711890bcSjc156560 	raid_obj_handle_t *disks_handlep)
2460711890bcSjc156560 {
2461711890bcSjc156560 	raid_obj_handle_t ctl_handle;
2462711890bcSjc156560 	disk_tag_t disk_tag;
2463711890bcSjc156560 	uint32_t ctl_id;
2464711890bcSjc156560 	int i;
2465711890bcSjc156560 	int ret;
2466711890bcSjc156560 
2467711890bcSjc156560 	if (disks_handlep == NULL) {
2468711890bcSjc156560 		return (FAILURE);
2469711890bcSjc156560 	}
2470711890bcSjc156560 
2471711890bcSjc156560 	for (i = 0; i < disks_num; i++) {
2472711890bcSjc156560 		if (get_disk_tag_ctd(disks_argpp[i], &disk_tag, &ctl_id) !=
2473711890bcSjc156560 		    SUCCESS) {
2474711890bcSjc156560 			return (INVALID_ARG);
2475711890bcSjc156560 		}
2476711890bcSjc156560 
2477711890bcSjc156560 		*ctl_tagp = ctl_id;
2478711890bcSjc156560 
2479711890bcSjc156560 		if (i == 0) {
2480711890bcSjc156560 			ctl_handle = raidcfg_get_controller(*ctl_tagp);
2481711890bcSjc156560 			if (ctl_handle <= 0) {
2482711890bcSjc156560 				(void) fprintf(stderr, "%s\n",
2483711890bcSjc156560 				    raidcfg_errstr(ctl_handle));
2484711890bcSjc156560 				return (FAILURE);
2485711890bcSjc156560 			}
2486711890bcSjc156560 			ret = raidcfg_open_controller(ctl_handle, NULL);
2487711890bcSjc156560 			if (ret < 0) {
2488711890bcSjc156560 				(void) fprintf(stderr, "%s\n",
2489711890bcSjc156560 				    raidcfg_errstr(ret));
2490711890bcSjc156560 				return (FAILURE);
2491711890bcSjc156560 			}
2492711890bcSjc156560 		}
2493711890bcSjc156560 
2494711890bcSjc156560 		if ((disks_handlep[i] =
2495711890bcSjc156560 		    raidcfg_get_disk(ctl_handle, disk_tag)) < 0) {
2496711890bcSjc156560 			(void) fprintf(stderr, "%s\n",
2497711890bcSjc156560 			    raidcfg_errstr(disks_handlep[i]));
2498711890bcSjc156560 			(void) raidcfg_close_controller(ctl_handle, NULL);
2499711890bcSjc156560 			return (FAILURE);
2500711890bcSjc156560 		}
2501711890bcSjc156560 	}
2502711890bcSjc156560 
2503711890bcSjc156560 	return (SUCCESS);
25047c478bd9Sstevel@tonic-gate }
25057c478bd9Sstevel@tonic-gate 
25067c478bd9Sstevel@tonic-gate /*
2507711890bcSjc156560  * get_ctl_tag(argp)
2508711890bcSjc156560  * This function translates controller string to tag. The return value is
2509711890bcSjc156560  * SUCCESS if the string has legal format and is parsed successfully,
2510711890bcSjc156560  * or FAILURE if it fails.
25117c478bd9Sstevel@tonic-gate  */
2512711890bcSjc156560 static int
2513711890bcSjc156560 get_ctl_tag(char *argp, uint32_t *ctl_tagp)
2514711890bcSjc156560 {
2515711890bcSjc156560 	if (argp == NULL || is_fully_numeric(argp) == FALSE ||
2516711890bcSjc156560 	    ctl_tagp == NULL) {
2517711890bcSjc156560 		return (FAILURE);
25187c478bd9Sstevel@tonic-gate 	}
2519711890bcSjc156560 	*ctl_tagp = (atoi(argp));
2520711890bcSjc156560 	return (SUCCESS);
25217c478bd9Sstevel@tonic-gate }
25227c478bd9Sstevel@tonic-gate 
25237c478bd9Sstevel@tonic-gate /*
2524711890bcSjc156560  * get_array_tag(argp, ctl_tagp, array_tagp)
2525711890bcSjc156560  * This function parses array string to get array tag and controller tag.
2526711890bcSjc156560  * The return value is SUCCESS if the string has legal format, or
2527711890bcSjc156560  * FAILURE if it fails.
25287c478bd9Sstevel@tonic-gate  */
2529711890bcSjc156560 static int
2530711890bcSjc156560 get_array_tag(char *argp, uint32_t *ctl_tagp, array_tag_t *array_tagp)
2531711890bcSjc156560 {
2532711890bcSjc156560 	char *t = NULL;
2533711890bcSjc156560 	char *cp = NULL;
2534711890bcSjc156560 	char *tp = NULL;
2535711890bcSjc156560 	char *dp = NULL;
2536711890bcSjc156560 
2537711890bcSjc156560 	uint32_t value_c = MAX32BIT;
2538711890bcSjc156560 	uint32_t value_t = MAX32BIT;
2539711890bcSjc156560 	uint32_t value_d = MAX32BIT;
2540711890bcSjc156560 
2541711890bcSjc156560 	int len = 0;
2542711890bcSjc156560 
2543711890bcSjc156560 	if (argp == NULL || (len = strlen(argp)) == 0 ||
2544711890bcSjc156560 	    array_tagp == NULL) {
2545711890bcSjc156560 		return (FAILURE);
2546711890bcSjc156560 	}
2547711890bcSjc156560 
2548711890bcSjc156560 	t = (char *)malloc(len + 1);
2549711890bcSjc156560 	if (t == NULL) {
2550711890bcSjc156560 		return (FAILURE);
2551711890bcSjc156560 	}
2552711890bcSjc156560 
2553711890bcSjc156560 	(void) memcpy(t, argp, len + 1);
2554711890bcSjc156560 
2555711890bcSjc156560 	/* Now remmber to release t memory if exception occurs */
2556711890bcSjc156560 	if (((dp = strchr(t, 'd')) == NULL) ||
2557711890bcSjc156560 	    ((tp = strchr(t, 't')) == NULL) ||
2558711890bcSjc156560 	    ((cp = strchr(t, 'c')) == NULL)) {
2559711890bcSjc156560 		free(t);
2560711890bcSjc156560 		return (FAILURE);
2561711890bcSjc156560 	}
2562711890bcSjc156560 	cp = t;
2563711890bcSjc156560 
2564711890bcSjc156560 	*dp = '\0';
2565711890bcSjc156560 	dp++;
2566711890bcSjc156560 	*tp = '\0';
2567711890bcSjc156560 	tp++;
2568711890bcSjc156560 	cp++;
2569711890bcSjc156560 
2570711890bcSjc156560 	if (is_fully_numeric(dp) == FALSE ||
2571711890bcSjc156560 	    is_fully_numeric(tp) == FALSE ||
2572711890bcSjc156560 	    is_fully_numeric(cp) == FALSE) {
2573711890bcSjc156560 		free(t);
2574711890bcSjc156560 		return (FAILURE);
2575711890bcSjc156560 	}
2576711890bcSjc156560 
2577711890bcSjc156560 	value_c = atoi(cp);
2578711890bcSjc156560 	value_t = atoi(tp);
2579711890bcSjc156560 	value_d = atoi(dp);
2580711890bcSjc156560 
2581711890bcSjc156560 	array_tagp->idl.target_id = value_t;
2582711890bcSjc156560 	array_tagp->idl.lun = value_d;
2583711890bcSjc156560 
2584711890bcSjc156560 	if (ctl_tagp != NULL) {
2585711890bcSjc156560 		*ctl_tagp = value_c;
2586711890bcSjc156560 	}
2587711890bcSjc156560 
2588711890bcSjc156560 	free(t);
2589711890bcSjc156560 	return (SUCCESS);
2590711890bcSjc156560 }
2591711890bcSjc156560 
2592711890bcSjc156560 /*
2593711890bcSjc156560  * get_disk_tag_ctd(argp, disk_tagp)
2594711890bcSjc156560  * This function parses disk string of ctd format, and translates it to
2595711890bcSjc156560  * disk tag and controller tag. The tags is returned by out parameters.
2596711890bcSjc156560  * The return value is SUCCESS if the string has legal format, or FAILURE
2597711890bcSjc156560  * if it fails.
2598711890bcSjc156560  */
2599711890bcSjc156560 static int
2600711890bcSjc156560 get_disk_tag_ctd(char *argp, disk_tag_t *disk_tagp, uint32_t *ctl_tag)
2601711890bcSjc156560 {
2602711890bcSjc156560 	char *t = NULL;
2603711890bcSjc156560 	char *cp = NULL;
2604711890bcSjc156560 	char *tp = NULL;
2605711890bcSjc156560 	char *dp = NULL;
2606711890bcSjc156560 
2607711890bcSjc156560 	uint32_t value_c = MAX32BIT;
2608711890bcSjc156560 	uint32_t value_t = MAX32BIT;
2609711890bcSjc156560 	uint32_t value_d = MAX32BIT;
2610711890bcSjc156560 
2611711890bcSjc156560 	int len = 0;
2612711890bcSjc156560 
2613711890bcSjc156560 	if (argp == NULL || (len = strlen(argp)) == 0 ||
2614711890bcSjc156560 	    disk_tagp == NULL) {
2615711890bcSjc156560 		return (FAILURE);
2616711890bcSjc156560 	}
2617711890bcSjc156560 
2618711890bcSjc156560 	t = (char *)malloc(len + 1);
2619711890bcSjc156560 	if (t == NULL) {
2620711890bcSjc156560 		return (FAILURE);
2621711890bcSjc156560 	}
2622711890bcSjc156560 
2623711890bcSjc156560 	(void) memcpy(t, argp, len + 1);
2624711890bcSjc156560 
2625711890bcSjc156560 	/* Now remmber to release t memory if exception occurs */
2626711890bcSjc156560 	if (((dp = strchr(t, 'd')) == NULL) ||
2627711890bcSjc156560 	    ((tp = strchr(t, 't')) == NULL) ||
2628711890bcSjc156560 	    ((cp = strchr(t, 'c')) == NULL)) {
2629711890bcSjc156560 		free(t);
2630711890bcSjc156560 		return (FAILURE);
2631711890bcSjc156560 	}
2632711890bcSjc156560 	cp = t;
2633711890bcSjc156560 
2634711890bcSjc156560 	*dp = '\0';
2635711890bcSjc156560 	dp++;
2636711890bcSjc156560 	*tp = '\0';
2637711890bcSjc156560 	tp++;
2638711890bcSjc156560 	cp++;
2639711890bcSjc156560 
2640711890bcSjc156560 	if (is_fully_numeric(dp) == FALSE ||
2641711890bcSjc156560 	    is_fully_numeric(tp) == FALSE ||
2642711890bcSjc156560 	    is_fully_numeric(cp) == FALSE) {
2643711890bcSjc156560 		free(t);
2644711890bcSjc156560 		return (FAILURE);
2645711890bcSjc156560 	}
2646711890bcSjc156560 
2647711890bcSjc156560 	value_c = atoi(cp);
2648711890bcSjc156560 	value_t = atoi(tp);
2649711890bcSjc156560 	value_d = atoi(dp);
2650711890bcSjc156560 
2651711890bcSjc156560 	disk_tagp->cidl.bus = 0;
2652711890bcSjc156560 	disk_tagp->cidl.target_id = value_t;
2653711890bcSjc156560 	disk_tagp->cidl.lun = value_d;
2654711890bcSjc156560 	*ctl_tag = value_c;
2655711890bcSjc156560 
2656711890bcSjc156560 	free(t);
2657711890bcSjc156560 	return (SUCCESS);
2658711890bcSjc156560 }
2659711890bcSjc156560 
2660711890bcSjc156560 /*
2661711890bcSjc156560  * get_disk_tag_cidl(argp, disk_tagp)
2662711890bcSjc156560  * This function parses disk string of cidl format and translates it to tag.
2663711890bcSjc156560  * The return value is disk tag if the string has legal format, or FAILURE
2664711890bcSjc156560  * if it fails.
2665711890bcSjc156560  */
2666711890bcSjc156560 static int
2667711890bcSjc156560 get_disk_tag_cidl(char *argp, disk_tag_t *disk_tagp)
2668711890bcSjc156560 {
2669711890bcSjc156560 	int len = 0;
2670711890bcSjc156560 	char *p = NULL;
2671711890bcSjc156560 	char *t = NULL;
2672711890bcSjc156560 	char *dot1p = NULL;
2673711890bcSjc156560 	char *dot2p = NULL;
2674711890bcSjc156560 
2675711890bcSjc156560 	if (argp == NULL || (len = strlen(argp)) == 0) {
2676711890bcSjc156560 		return (FAILURE);
2677711890bcSjc156560 	}
2678711890bcSjc156560 
2679711890bcSjc156560 	if (disk_tagp == NULL) {
2680711890bcSjc156560 		return (FAILURE);
2681711890bcSjc156560 	}
2682711890bcSjc156560 
2683711890bcSjc156560 	t = (char *)malloc(len + 1);
2684711890bcSjc156560 	if (t == NULL) {
2685711890bcSjc156560 		return (FAILURE);
2686711890bcSjc156560 	}
2687711890bcSjc156560 
2688711890bcSjc156560 	(void) memcpy(t, argp, len + 1);
2689711890bcSjc156560 	p = t;
2690711890bcSjc156560 
2691711890bcSjc156560 	dot2p = strrchr(p, '.');
2692711890bcSjc156560 	if (dot2p == NULL) {
2693711890bcSjc156560 		free(t);
2694711890bcSjc156560 		return (FAILURE);
2695711890bcSjc156560 	}
2696711890bcSjc156560 	*dot2p = '\0';
2697711890bcSjc156560 	dot2p++;
2698711890bcSjc156560 
2699711890bcSjc156560 	dot1p = strrchr(p, '.');
2700711890bcSjc156560 	if (dot1p == NULL) {
2701711890bcSjc156560 		free(t);
2702711890bcSjc156560 		return (FAILURE);
2703711890bcSjc156560 	}
2704711890bcSjc156560 	*dot1p = '\0';
2705711890bcSjc156560 	dot1p++;
2706711890bcSjc156560 
2707711890bcSjc156560 	/* Assert only 2 dots in this string */
2708711890bcSjc156560 	if (strrchr(p, '.') != NULL) {
2709711890bcSjc156560 		free(t);
2710711890bcSjc156560 		return (FAILURE);
2711711890bcSjc156560 	}
2712711890bcSjc156560 
2713711890bcSjc156560 	while (*p == ' ')
2714711890bcSjc156560 		p++;
2715711890bcSjc156560 
2716711890bcSjc156560 	if (is_fully_numeric(p) == FALSE ||
2717711890bcSjc156560 	    is_fully_numeric(dot1p) == FALSE ||
2718711890bcSjc156560 	    is_fully_numeric(dot2p) == FALSE) {
2719711890bcSjc156560 		free(t);
2720711890bcSjc156560 		return (FAILURE);
2721711890bcSjc156560 	}
2722711890bcSjc156560 
2723711890bcSjc156560 	disk_tagp->cidl.bus = atoi(p);
2724711890bcSjc156560 	disk_tagp->cidl.target_id = atoi(dot1p);
2725711890bcSjc156560 	disk_tagp->cidl.lun = atoi(dot2p);
2726711890bcSjc156560 
2727711890bcSjc156560 	free(t);
2728711890bcSjc156560 	return (SUCCESS);
2729711890bcSjc156560 }
2730711890bcSjc156560 
2731711890bcSjc156560 /*
2732711890bcSjc156560  * calc_size(sizep, valp)
2733711890bcSjc156560  * This function calculates the value represented by string sizep.
2734711890bcSjc156560  * The string sizep can be decomposed into three parts: an initial,
2735711890bcSjc156560  * possibly empty, sequence of white-space characters; a subject digital
2736711890bcSjc156560  * sequence interpreted as an integer with unit k/K/m/M/g/G/t/T; and a
2737711890bcSjc156560  * final string of one or more unrecognized characters or white-sapce
2738711890bcSjc156560  * characters, including the terminating null. If unrecognized character
2739711890bcSjc156560  * exists or overflow happens, the conversion must fail and return
2740711890bcSjc156560  * INVALID_ARG. If the conversion is performed successfully, result will
2741711890bcSjc156560  * be saved into valp and function returns SUCCESS. It returns FAILURE
2742711890bcSjc156560  * when memory allocation fails.
2743711890bcSjc156560  */
2744711890bcSjc156560 static int
2745711890bcSjc156560 calc_size(char *sizep, uint64_t *valp)
2746711890bcSjc156560 {
2747711890bcSjc156560 	int len;
2748711890bcSjc156560 	uint64_t size;
2749711890bcSjc156560 	uint64_t unit;
2750711890bcSjc156560 	char *t = NULL;
2751711890bcSjc156560 	char *tailp = NULL;
2752711890bcSjc156560 
2753711890bcSjc156560 	if (sizep == NULL || valp == NULL) {
2754711890bcSjc156560 		return (INVALID_ARG);
2755700682b8Syw161884 	}
2756700682b8Syw161884 
2757700682b8Syw161884 	if (is_fully_numeric(sizep) == TRUE) {
2758700682b8Syw161884 		*valp = atoi(sizep);
2759700682b8Syw161884 		return (SUCCESS);
2760711890bcSjc156560 	}
2761711890bcSjc156560 
2762711890bcSjc156560 	len = strlen(sizep);
2763711890bcSjc156560 	if (len == 0) {
2764711890bcSjc156560 		return (INVALID_ARG);
2765711890bcSjc156560 	}
2766711890bcSjc156560 
2767711890bcSjc156560 	t = (char *)malloc(len + 1);
2768711890bcSjc156560 	if (t == NULL) {
2769711890bcSjc156560 		return (FAILURE);
2770711890bcSjc156560 	}
2771711890bcSjc156560 
2772711890bcSjc156560 	(void) memcpy(t, sizep, len + 1);
2773711890bcSjc156560 
2774711890bcSjc156560 	switch (*(t + len - 1)) {
2775711890bcSjc156560 	case 'k':
2776711890bcSjc156560 	case 'K':
2777711890bcSjc156560 		unit = 1024ull;
2778711890bcSjc156560 		errno = 0;
2779711890bcSjc156560 		size = strtoll(t, &tailp, 0);
2780711890bcSjc156560 		break;
2781711890bcSjc156560 	case 'm':
2782711890bcSjc156560 	case 'M':
2783711890bcSjc156560 		unit = 1024ull * 1024ull;
2784711890bcSjc156560 		errno = 0;
2785711890bcSjc156560 		size = strtoll(t, &tailp, 0);
2786711890bcSjc156560 		break;
2787711890bcSjc156560 	case 'g':
2788711890bcSjc156560 	case 'G':
2789711890bcSjc156560 		unit = 1024ull * 1024ull * 1024ull;
2790711890bcSjc156560 		errno = 0;
2791711890bcSjc156560 		size = strtoll(t, &tailp, 0);
2792711890bcSjc156560 		break;
2793711890bcSjc156560 	case 't':
2794711890bcSjc156560 	case 'T':
2795711890bcSjc156560 		unit = 1024ull * 1024ull * 1024ull * 1024ull;
2796711890bcSjc156560 		errno = 0;
2797711890bcSjc156560 		size = strtoll(t, &tailp, 0);
2798711890bcSjc156560 		break;
2799711890bcSjc156560 	default:
2800711890bcSjc156560 		/* The unit must be kilobyte at least. */
2801711890bcSjc156560 		free(t);
2802711890bcSjc156560 		return (INVALID_ARG);
2803711890bcSjc156560 	}
2804711890bcSjc156560 
2805711890bcSjc156560 	*(t + len - 1) = '\0';
2806711890bcSjc156560 	if (is_fully_numeric(t) != TRUE) {
2807711890bcSjc156560 		free(t);
2808711890bcSjc156560 		return (INVALID_ARG);
2809711890bcSjc156560 	}
2810711890bcSjc156560 
2811711890bcSjc156560 	errno = 0;
2812711890bcSjc156560 	size = strtoll(t, &tailp, 0);
2813711890bcSjc156560 
2814711890bcSjc156560 	/* Check overflow condition */
2815711890bcSjc156560 	if (errno == ERANGE || (size > (MAX64BIT / unit))) {
2816711890bcSjc156560 		free(t);
2817711890bcSjc156560 		return (INVALID_ARG);
2818711890bcSjc156560 	}
2819711890bcSjc156560 
2820711890bcSjc156560 	*valp = size * unit;
2821711890bcSjc156560 	free(t);
2822711890bcSjc156560 	return (SUCCESS);
2823711890bcSjc156560 }
2824711890bcSjc156560 
2825711890bcSjc156560 /*
2826711890bcSjc156560  * is_fully_numeric(str)
2827711890bcSjc156560  * This function checks if the string are legal numeric string. The beginning
2828711890bcSjc156560  * or ending characters can be white spaces.
2829711890bcSjc156560  * Return value is TRUE if the string are legal numeric string, or FALSE
2830711890bcSjc156560  * otherwise.
2831711890bcSjc156560  */
2832711890bcSjc156560 static int
2833711890bcSjc156560 is_fully_numeric(char *strp)
2834711890bcSjc156560 {
2835711890bcSjc156560 	uint32_t len;
2836711890bcSjc156560 	uint32_t i;
2837711890bcSjc156560 
2838711890bcSjc156560 	if (strp == NULL) {
2839711890bcSjc156560 		return (FALSE);
2840711890bcSjc156560 	}
2841711890bcSjc156560 
2842711890bcSjc156560 	len = strlen(strp);
2843711890bcSjc156560 	if (len == 0) {
2844711890bcSjc156560 		return (FALSE);
2845711890bcSjc156560 	}
2846711890bcSjc156560 
2847711890bcSjc156560 	/* Skip whitespace characters */
2848711890bcSjc156560 	for (i = 0; i < len; i++) {
2849711890bcSjc156560 		if (strp[i] != ' ') {
28507c478bd9Sstevel@tonic-gate 			break;
28517c478bd9Sstevel@tonic-gate 		}
28527c478bd9Sstevel@tonic-gate 	}
28537c478bd9Sstevel@tonic-gate 
2854711890bcSjc156560 	/* if strp points all space characters */
2855711890bcSjc156560 	if (i == len) {
2856711890bcSjc156560 		return (FALSE);
28577c478bd9Sstevel@tonic-gate 	}
28587c478bd9Sstevel@tonic-gate 
2859711890bcSjc156560 	/* Check the digitals in string */
2860711890bcSjc156560 	for (; i < len; i++) {
2861711890bcSjc156560 		if (!isdigit(strp[i])) {
28627c478bd9Sstevel@tonic-gate 			break;
28637c478bd9Sstevel@tonic-gate 		}
28647c478bd9Sstevel@tonic-gate 	}
28657c478bd9Sstevel@tonic-gate 
2866711890bcSjc156560 	/* Check the ending string */
2867711890bcSjc156560 	for (; i < len; i++) {
2868711890bcSjc156560 		if (strp[i] != ' ') {
2869711890bcSjc156560 			return (FALSE);
28707c478bd9Sstevel@tonic-gate 		}
28717c478bd9Sstevel@tonic-gate 	}
28727c478bd9Sstevel@tonic-gate 
2873711890bcSjc156560 	return (TRUE);
28747c478bd9Sstevel@tonic-gate }
28757c478bd9Sstevel@tonic-gate 
28767c478bd9Sstevel@tonic-gate static int
28776fec3791Sjesseb yes(void)
28787c478bd9Sstevel@tonic-gate {
28797c478bd9Sstevel@tonic-gate 	int	i, b;
28807c478bd9Sstevel@tonic-gate 	char    ans[SCHAR_MAX + 1];
28817c478bd9Sstevel@tonic-gate 
28827c478bd9Sstevel@tonic-gate 	for (i = 0; ; i++) {
28837c478bd9Sstevel@tonic-gate 		b = getchar();
28847c478bd9Sstevel@tonic-gate 		if (b == '\n' || b == '\0' || b == EOF) {
28857c478bd9Sstevel@tonic-gate 			ans[i] = 0;
28867c478bd9Sstevel@tonic-gate 			break;
28877c478bd9Sstevel@tonic-gate 		}
2888711890bcSjc156560 		if (i < SCHAR_MAX) {
28897c478bd9Sstevel@tonic-gate 			ans[i] = b;
28907c478bd9Sstevel@tonic-gate 		}
2891711890bcSjc156560 	}
28927c478bd9Sstevel@tonic-gate 	if (i >= SCHAR_MAX) {
28937c478bd9Sstevel@tonic-gate 		i = SCHAR_MAX;
28947c478bd9Sstevel@tonic-gate 		ans[SCHAR_MAX] = 0;
28957c478bd9Sstevel@tonic-gate 	}
28966fec3791Sjesseb 
2897711890bcSjc156560 	return (rpmatch(ans));
2898711890bcSjc156560 }
2899711890bcSjc156560 
2900711890bcSjc156560 /*
2901711890bcSjc156560  * Function: int rpmatch(char *)
2902711890bcSjc156560  *
2903711890bcSjc156560  * Description:
2904711890bcSjc156560  *
2905711890bcSjc156560  *	Internationalized get yes / no answer.
2906711890bcSjc156560  *
2907711890bcSjc156560  * Inputs:
2908711890bcSjc156560  *	s	-> Pointer to answer to compare against.
2909711890bcSjc156560  *
2910711890bcSjc156560  * Returns:
2911711890bcSjc156560  *	TRUE	-> Answer was affirmative
2912711890bcSjc156560  *	FALSE	-> Answer was negative
2913711890bcSjc156560  */
2914711890bcSjc156560 
2915711890bcSjc156560 static int
2916711890bcSjc156560 rpmatch(char *s)
2917711890bcSjc156560 {
2918711890bcSjc156560 	int	status;
2919711890bcSjc156560 
2920711890bcSjc156560 	/* match yesexpr */
2921711890bcSjc156560 	status = regexec(&re, s, (size_t)0, NULL, 0);
2922711890bcSjc156560 	if (status != 0) {
2923711890bcSjc156560 		return (FALSE);
2924711890bcSjc156560 	}
2925711890bcSjc156560 	return (TRUE);
29267c478bd9Sstevel@tonic-gate }
29277c478bd9Sstevel@tonic-gate 
29287c478bd9Sstevel@tonic-gate static int
2929711890bcSjc156560 size_to_string(uint64_t size, char *string, int len)
29307c478bd9Sstevel@tonic-gate {
2931711890bcSjc156560 	int i = 0;
2932711890bcSjc156560 	uint32_t remainder;
2933711890bcSjc156560 	char unit[][2] = {" ", "K", "M", "G", "T"};
29347c478bd9Sstevel@tonic-gate 
2935711890bcSjc156560 	if (string == NULL) {
2936711890bcSjc156560 		return (FAILURE);
2937711890bcSjc156560 	}
2938711890bcSjc156560 	while (size > 1023) {
2939711890bcSjc156560 		remainder = size % 1024;
2940711890bcSjc156560 		size /= 1024;
2941711890bcSjc156560 		i++;
2942711890bcSjc156560 	}
2943711890bcSjc156560 
2944711890bcSjc156560 	if (i > 4) {
29457c478bd9Sstevel@tonic-gate 		return (FAILURE);
29467c478bd9Sstevel@tonic-gate 	}
29477c478bd9Sstevel@tonic-gate 
2948711890bcSjc156560 	remainder /= 103;
2949711890bcSjc156560 	if (remainder == 0) {
2950711890bcSjc156560 		(void) snprintf(string, len, "%llu", size);
2951711890bcSjc156560 	} else {
2952711890bcSjc156560 		(void) snprintf(string, len, "%llu.%1u", size,
2953711890bcSjc156560 		    remainder);
29547c478bd9Sstevel@tonic-gate 	}
29557c478bd9Sstevel@tonic-gate 
2956711890bcSjc156560 	/* make sure there is one byte for unit */
2957711890bcSjc156560 	if ((strlen(string) + 1) >=  len) {
29587c478bd9Sstevel@tonic-gate 		return (FAILURE);
29597c478bd9Sstevel@tonic-gate 	}
2960711890bcSjc156560 	(void) strcat(string, unit[i]);
29617c478bd9Sstevel@tonic-gate 
29627c478bd9Sstevel@tonic-gate 	return (SUCCESS);
29637c478bd9Sstevel@tonic-gate }
29647c478bd9Sstevel@tonic-gate 
29657c478bd9Sstevel@tonic-gate /*
2966711890bcSjc156560  * Only one raidctl is running at one time.
29677c478bd9Sstevel@tonic-gate  */
29687c478bd9Sstevel@tonic-gate static int
2969711890bcSjc156560 enter_raidctl_lock(int *fd)
29707c478bd9Sstevel@tonic-gate {
2971711890bcSjc156560 	int fd0 = -1;
2972711890bcSjc156560 	struct flock lock;
29737c478bd9Sstevel@tonic-gate 
2974711890bcSjc156560 	fd0 = open(RAIDCTL_LOCKF, O_CREAT|O_WRONLY, 0600);
2975711890bcSjc156560 	if (fd0 < 0) {
29767978b887Sanbui 		if (errno == EACCES) {
29777978b887Sanbui 			(void) fprintf(stderr,
29787978b887Sanbui 			    gettext("raidctl:must be root to run raidctl"
29797978b887Sanbui 			    ": %s\n"), strerror(errno));
29807978b887Sanbui 		} else {
29817978b887Sanbui 			(void) fprintf(stderr,
29827978b887Sanbui 			    gettext("raidctl:failed to open lockfile"
2983711890bcSjc156560 			    " '"RAIDCTL_LOCKF"': %s\n"), strerror(errno));
29847978b887Sanbui 		}
29857c478bd9Sstevel@tonic-gate 		return (FAILURE);
29867c478bd9Sstevel@tonic-gate 	}
29877c478bd9Sstevel@tonic-gate 
2988711890bcSjc156560 	*fd = fd0;
2989711890bcSjc156560 	lock.l_type = F_WRLCK;
2990711890bcSjc156560 	lock.l_whence = SEEK_SET;
2991711890bcSjc156560 	lock.l_start = 0;
2992711890bcSjc156560 	lock.l_len = 0;
2993711890bcSjc156560 
2994711890bcSjc156560 	if ((fcntl(fd0, F_SETLK, &lock) == -1) &&
2995711890bcSjc156560 	    (errno == EAGAIN || errno == EDEADLK)) {
2996711890bcSjc156560 		if (fcntl(fd0, F_GETLK, &lock) == -1) {
2997711890bcSjc156560 			(void) fprintf(stderr,
2998711890bcSjc156560 			    gettext("raidctl:enter_filelock error\n"));
29997c478bd9Sstevel@tonic-gate 			return (FAILURE);
30007c478bd9Sstevel@tonic-gate 		}
3001711890bcSjc156560 		(void) fprintf(stderr, gettext("raidctl:"
3002711890bcSjc156560 		    "enter_filelock:filelock is owned "
3003711890bcSjc156560 		    "by 'process %d'\n"), lock.l_pid);
3004711890bcSjc156560 		return (FAILURE);
30057c478bd9Sstevel@tonic-gate 	}
30067c478bd9Sstevel@tonic-gate 
3007711890bcSjc156560 	return (SUCCESS);
30087c478bd9Sstevel@tonic-gate }
30096fec3791Sjesseb 
3010711890bcSjc156560 static void
3011711890bcSjc156560 exit_raidctl_lock(int fd)
3012711890bcSjc156560 {
3013711890bcSjc156560 	struct flock lock;
30147c478bd9Sstevel@tonic-gate 
3015711890bcSjc156560 	lock.l_type = F_UNLCK;
3016711890bcSjc156560 	lock.l_whence = SEEK_SET;
3017711890bcSjc156560 	lock.l_start = 0;
3018711890bcSjc156560 	lock.l_len = 0;
3019711890bcSjc156560 	if (fcntl(fd, F_SETLK, &lock) == -1) {
3020711890bcSjc156560 		(void) fprintf(stderr, gettext("raidctl: failed to"
3021711890bcSjc156560 		    " exit_filelock: %s\n"),
3022711890bcSjc156560 		    strerror(errno));
30237c478bd9Sstevel@tonic-gate 	}
3024711890bcSjc156560 	(void) close(fd);
30257c478bd9Sstevel@tonic-gate }
3026