xref: /titanic_53/usr/src/cmd/raidctl/raidctl.c (revision 6fec3791b5a9a5621db93bfef3a6514bc0511b5d)
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
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
233a4e43d3Ssafa  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <ctype.h>
307c478bd9Sstevel@tonic-gate #include <dirent.h>
317c478bd9Sstevel@tonic-gate #include <errno.h>
327c478bd9Sstevel@tonic-gate #include <fcntl.h>
337c478bd9Sstevel@tonic-gate #include <langinfo.h>
347c478bd9Sstevel@tonic-gate #include <libintl.h>
357c478bd9Sstevel@tonic-gate #include <limits.h>
367c478bd9Sstevel@tonic-gate #include <locale.h>
377c478bd9Sstevel@tonic-gate #include <stdarg.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 <sys/ddi.h>
437c478bd9Sstevel@tonic-gate #include <sys/mpt/mpi.h>
447c478bd9Sstevel@tonic-gate #include <sys/mpt/mpi_ioc.h>
457c478bd9Sstevel@tonic-gate #include <sys/stat.h>
467c478bd9Sstevel@tonic-gate #include <sys/types.h>
477c478bd9Sstevel@tonic-gate #include <sys/pci.h>
487c478bd9Sstevel@tonic-gate #include <unistd.h>
497c478bd9Sstevel@tonic-gate #include <sys/mnttab.h>
507c478bd9Sstevel@tonic-gate #include <sys/dkio.h>
517c478bd9Sstevel@tonic-gate #include <config_admin.h>
527c478bd9Sstevel@tonic-gate #include <sys/param.h>
537c478bd9Sstevel@tonic-gate #include <sys/raidioctl.h>
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate /*
567c478bd9Sstevel@tonic-gate  * list of controllers to list
577c478bd9Sstevel@tonic-gate  * setup like this:
587c478bd9Sstevel@tonic-gate  * [ctrl_num]	[status]
597c478bd9Sstevel@tonic-gate  *
607c478bd9Sstevel@tonic-gate  * where status is:
617c478bd9Sstevel@tonic-gate  * RAID Found,
627c478bd9Sstevel@tonic-gate  * No RAID Found
637c478bd9Sstevel@tonic-gate  * RAID not supported on this controller
647c478bd9Sstevel@tonic-gate  * Invalid Controller
657c478bd9Sstevel@tonic-gate  */
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate typedef enum {
687c478bd9Sstevel@tonic-gate 	RAID_FOUND = 0x0,
697c478bd9Sstevel@tonic-gate 	RAID_NOT_FOUND,
707c478bd9Sstevel@tonic-gate 	RAID_NOT_SUPPORTED,
717c478bd9Sstevel@tonic-gate 	RAID_INVALID_CTRL,
727c478bd9Sstevel@tonic-gate 	RAID_DONT_USE
737c478bd9Sstevel@tonic-gate } raidctl_errno_t;
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate /* For no-mixup indexing of info_ctrl */
767c478bd9Sstevel@tonic-gate #define	INFO_CTRL	0
777c478bd9Sstevel@tonic-gate #define	INFO_STATUS	1
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate static int **info_ctrl = NULL;
807c478bd9Sstevel@tonic-gate /* Length of conrollers list */
817c478bd9Sstevel@tonic-gate static int ctrl_nums = 0;
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate #define	DEVDIR			"/dev/rdsk"
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_NOP		-1
877c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_INFO		0
887c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_CREATE	1
897c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_DELETE	2
907c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_FLASH	3
917c478bd9Sstevel@tonic-gate 
92*6fec3791Sjesseb /* values to use for raid level in raidctl */
93*6fec3791Sjesseb #define	RAID_STRIPE		0
94*6fec3791Sjesseb #define	RAID_MIRROR		1
95*6fec3791Sjesseb 
967c478bd9Sstevel@tonic-gate /*
977c478bd9Sstevel@tonic-gate  * Error return codes
987c478bd9Sstevel@tonic-gate  */
997c478bd9Sstevel@tonic-gate #define	SUCCESS			0
1007c478bd9Sstevel@tonic-gate #define	INVALID_ARG		1
1017c478bd9Sstevel@tonic-gate #define	FAILURE			2
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate /*
1047c478bd9Sstevel@tonic-gate  * FW Update Stuff
1057c478bd9Sstevel@tonic-gate  */
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate /* signature and initial offset for PCI expansion rom images */
1087c478bd9Sstevel@tonic-gate #define	PCIROM_SIG	0xaa55	/* offset 0h, length 2 bytes */
1097c478bd9Sstevel@tonic-gate #define	PCIR_OFF	0x18	/* Pointer to PCI Data Structure */
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate /* offsets in PCI data structure header */
1127c478bd9Sstevel@tonic-gate #define	PCIR_DEVID	0x6	/* PCI device id */
1137c478bd9Sstevel@tonic-gate #define	PCIR_CODETYPE   0x14	/* type of code (intel/fcode) */
1147c478bd9Sstevel@tonic-gate #define	PCIR_INDICATOR  0x15	/* "last image" indicator */
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate /* flags for image types */
1177c478bd9Sstevel@tonic-gate #define	BIOS_IMAGE	0x1
1187c478bd9Sstevel@tonic-gate #define	FCODE_IMAGE	0x2
1197c478bd9Sstevel@tonic-gate #define	UNKNOWN_IMAGE	0x3
1207c478bd9Sstevel@tonic-gate #define	LAST_IMAGE	0x80
1217c478bd9Sstevel@tonic-gate #define	NOT_LAST_IMAGE	0
1227c478bd9Sstevel@tonic-gate #define	PCI_IMAGE_UNIT_SIZE	512
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate /* ID's and offsets for MPT Firmware images */
1257c478bd9Sstevel@tonic-gate #define	FW_ROM_ID			0x5aea	/* bytes 4 & 5 of file */
1267c478bd9Sstevel@tonic-gate #define	FW_ROM_OFFSET_CHIP_TYPE		0x22	/* (U16) */
1277c478bd9Sstevel@tonic-gate #define	FW_ROM_OFFSET_VERSION		0x24	/* (U16) */
1287c478bd9Sstevel@tonic-gate #define	FW_ROM_OFFSET_VERSION_NAME	0x44	/* (32 U8) */
1297c478bd9Sstevel@tonic-gate 
130*6fec3791Sjesseb /* ID's for supported chips */
131*6fec3791Sjesseb #define	LSI_1030	0x30
132*6fec3791Sjesseb #define	LSI_1064	0x50
133*6fec3791Sjesseb #define	LSI_1064E	0x56
134*6fec3791Sjesseb #define	LSI_1068E	0x58
135*6fec3791Sjesseb 
1367c478bd9Sstevel@tonic-gate /* Key to search for when looking for fcode version */
1377c478bd9Sstevel@tonic-gate #define	FCODE_VERS_KEY1		0x12
1387c478bd9Sstevel@tonic-gate #define	FCODE_VERS_KEY2		0x7
1397c478bd9Sstevel@tonic-gate #define	BIOS_STR		"LSI1030 SCSI Host Adapter BIOS  Driver: "
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate /* get a word from a buffer (works with non-word aligned offsets) */
1427c478bd9Sstevel@tonic-gate #define	gw(x) (((x)[0]) + (((x)[1]) << 8))
1437c478bd9Sstevel@tonic-gate 
144*6fec3791Sjesseb /* Number of disks currently supported, per RAID volume */
145*6fec3791Sjesseb #define	N_DISKS		8
146*6fec3791Sjesseb 
147*6fec3791Sjesseb /* Maximum number of RAID volumes currently supported per HBA */
148*6fec3791Sjesseb #define	N_RAIDVOLS	2
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate /*
1517c478bd9Sstevel@tonic-gate  * Function and strings to properly localize our prompt.
1527c478bd9Sstevel@tonic-gate  * So for example in german it would ask (ja/nein) or (yes/no) in
1537c478bd9Sstevel@tonic-gate  * english.
1547c478bd9Sstevel@tonic-gate  */
155*6fec3791Sjesseb static int	yes(void);
1567c478bd9Sstevel@tonic-gate static char	yeschr[SCHAR_MAX + 2];
1577c478bd9Sstevel@tonic-gate static char	nochr[SCHAR_MAX +2];
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate typedef struct raidlist {
160*6fec3791Sjesseb 	raid_config_t	raid_config[N_RAIDVOLS];
1617c478bd9Sstevel@tonic-gate 	int	controller;
1627c478bd9Sstevel@tonic-gate 	char	devctl[MAXPATHLEN];
1637c478bd9Sstevel@tonic-gate 	struct raidlist *next;
1647c478bd9Sstevel@tonic-gate } raidlist_t;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate static raidlist_t	*raids;
1677c478bd9Sstevel@tonic-gate 
168*6fec3791Sjesseb /*
169*6fec3791Sjesseb  * usage: raidctl
170*6fec3791Sjesseb  * usage: raidctl [-f] -c primary secondary
171*6fec3791Sjesseb  * usage: raidctl [-f] -c -r 1 primary secondary
172*6fec3791Sjesseb  * usage: raidctl [-f] -c -r 0 disk1 disk2 [disk3] ...
173*6fec3791Sjesseb  * usage: raidctl [-f] -d volume
174*6fec3791Sjesseb  * usage: raidctl [-f] -F image_file controller
175*6fec3791Sjesseb  * usage: raidctl -l [controller...]
176*6fec3791Sjesseb  *   example:
177*6fec3791Sjesseb  *   raidctl -c c1t1d0 c1t2d0
178*6fec3791Sjesseb  *   raidctl -c -r 0 c1t1d0 c1t2d0 c1t3d0 c1t4d0
179*6fec3791Sjesseb  *   raidctl -d c1t1d0
180*6fec3791Sjesseb  *   raidctl -F image 1
181*6fec3791Sjesseb  */
1827c478bd9Sstevel@tonic-gate static void
1837c478bd9Sstevel@tonic-gate usage(char *prog_name)
1847c478bd9Sstevel@tonic-gate {
1857c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("usage: %s\n"), prog_name);
1867c478bd9Sstevel@tonic-gate 
187*6fec3791Sjesseb 	(void) fprintf(stderr, gettext("usage: %s [-f] -c primary secondary\n"),
1887c478bd9Sstevel@tonic-gate 		prog_name);
189*6fec3791Sjesseb 
190*6fec3791Sjesseb 	(void) fprintf(stderr, gettext("usage: %s [-f] -c -r 1 primary "
191*6fec3791Sjesseb 		"secondary\n"), prog_name);
192*6fec3791Sjesseb 
193*6fec3791Sjesseb 	(void) fprintf(stderr, gettext("usage: %s [-f] -c -r 0 disk1 disk2 "
194*6fec3791Sjesseb 		"[disk3] ...\n"), prog_name);
195*6fec3791Sjesseb 
196*6fec3791Sjesseb 	(void) fprintf(stderr, gettext("usage: %s [-f] -d volume\n"),
197*6fec3791Sjesseb 		prog_name);
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
2007c478bd9Sstevel@tonic-gate 		gettext("usage: %s [-f] -F image_file controller \n"),
2017c478bd9Sstevel@tonic-gate 		prog_name);
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("usage: %s -l [controller...]\n"),
2047c478bd9Sstevel@tonic-gate 		prog_name);
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("example:\n"));
2077c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s -c c1t1d0 c1t2d0\n", prog_name);
208*6fec3791Sjesseb 	(void) fprintf(stderr, "%s -c -r 0 c1t1d0 c1t2d0 "
209*6fec3791Sjesseb 		"c1t3d0 c1t4d0\n", prog_name);
2107c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s -d c1t1d0\n", prog_name);
2117c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s -F image 1\n", prog_name);
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	exit(1);
2147c478bd9Sstevel@tonic-gate }
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate /* Make errno message more "user friendly" */
2177c478bd9Sstevel@tonic-gate static void
2187c478bd9Sstevel@tonic-gate raidctl_error(char *str)
2197c478bd9Sstevel@tonic-gate {
2207c478bd9Sstevel@tonic-gate 	switch (errno) {
2213a4e43d3Ssafa 	case EINVAL:
2223a4e43d3Ssafa 		(void) fprintf(stderr, gettext("Error: "
2233a4e43d3Ssafa 			"invalid argument would be returned\n"));
2243a4e43d3Ssafa 		break;
2257c478bd9Sstevel@tonic-gate 	case EIO:
2267c478bd9Sstevel@tonic-gate 	case EFAULT:
2277c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
2287c478bd9Sstevel@tonic-gate 			gettext("Error: Device inaccessible.\n"));
2297c478bd9Sstevel@tonic-gate 		break;
2307c478bd9Sstevel@tonic-gate 	case ENOTTY:
2317c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Error: "
2327c478bd9Sstevel@tonic-gate 			"Device does not support requested action.\n"));
2337c478bd9Sstevel@tonic-gate 		break;
2347c478bd9Sstevel@tonic-gate 	default:
2357c478bd9Sstevel@tonic-gate 		perror(str);
2367c478bd9Sstevel@tonic-gate 	}
2377c478bd9Sstevel@tonic-gate }
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate static int
2407c478bd9Sstevel@tonic-gate get_link_path(const char *thing, char *buf)
2417c478bd9Sstevel@tonic-gate {
2427c478bd9Sstevel@tonic-gate 	if (readlink(thing, buf, MAXPATHLEN) < 0)
2437c478bd9Sstevel@tonic-gate 		return (1);
2447c478bd9Sstevel@tonic-gate 	return (0);
2457c478bd9Sstevel@tonic-gate }
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate static int
2487c478bd9Sstevel@tonic-gate get_ctrl_devctl(char *ctrl, char *b)
2497c478bd9Sstevel@tonic-gate {
2507c478bd9Sstevel@tonic-gate 	char	devctl_buf[MAXPATHLEN];
2517c478bd9Sstevel@tonic-gate 	char	*colon;
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	(void) strlcpy(devctl_buf, ctrl, MAXPATHLEN);
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	colon = strrchr(devctl_buf, ':');
2567c478bd9Sstevel@tonic-gate 	if (colon == NULL)
2577c478bd9Sstevel@tonic-gate 		return (1);
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 	*colon = 0;
2607c478bd9Sstevel@tonic-gate 	(void) snprintf(devctl_buf, MAXPATHLEN, "%s:devctl", devctl_buf);
2617c478bd9Sstevel@tonic-gate 	(void) strlcpy(b, devctl_buf, MAXPATHLEN);
2627c478bd9Sstevel@tonic-gate 	return (0);
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate static int
2667c478bd9Sstevel@tonic-gate get_devctl(char *disk, char *b)
2677c478bd9Sstevel@tonic-gate {
2687c478bd9Sstevel@tonic-gate 	char	buf1[MAXPATHLEN] = {0};
2697c478bd9Sstevel@tonic-gate 	char	devctl_buf[MAXPATHLEN];
2707c478bd9Sstevel@tonic-gate 	char	*slash;
2717c478bd9Sstevel@tonic-gate 	char	devname[32];
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 	if (get_link_path(disk, buf1))
2747c478bd9Sstevel@tonic-gate 		return (1);
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	(void) strlcpy(devctl_buf, buf1, MAXPATHLEN);
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	slash = strrchr(devctl_buf, '/');
2797c478bd9Sstevel@tonic-gate 	if (slash == NULL)
2807c478bd9Sstevel@tonic-gate 		return (1);
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	*slash = 0;
2837c478bd9Sstevel@tonic-gate 	slash = strrchr(devctl_buf, '/');
2847c478bd9Sstevel@tonic-gate 	(void) strlcpy(devname, slash, 32);
2857c478bd9Sstevel@tonic-gate 	*slash = 0;
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	(void) snprintf(devctl_buf, MAXPATHLEN, "%s%s:devctl",
2887c478bd9Sstevel@tonic-gate 		devctl_buf, devname);
289*6fec3791Sjesseb 
2907c478bd9Sstevel@tonic-gate 	(void) strlcpy(b, devctl_buf, MAXPATHLEN);
291*6fec3791Sjesseb 
2927c478bd9Sstevel@tonic-gate 	return (0);
2937c478bd9Sstevel@tonic-gate }
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate static int
2967c478bd9Sstevel@tonic-gate already_there(int controller)
2977c478bd9Sstevel@tonic-gate {
2987c478bd9Sstevel@tonic-gate 	raidlist_t	*curr = raids;
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
3017c478bd9Sstevel@tonic-gate 		if (curr->controller == controller)
3027c478bd9Sstevel@tonic-gate 			return (1);
303*6fec3791Sjesseb 
3047c478bd9Sstevel@tonic-gate 		curr = curr->next;
3057c478bd9Sstevel@tonic-gate 	}
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	return (0);
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate /*
3117c478bd9Sstevel@tonic-gate  * Display those controllers where RAID volumes were not found
3127c478bd9Sstevel@tonic-gate  */
3137c478bd9Sstevel@tonic-gate static void
3147c478bd9Sstevel@tonic-gate print_no_raids()
3157c478bd9Sstevel@tonic-gate {
3167c478bd9Sstevel@tonic-gate 	int i, space = 0;
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	if (info_ctrl == NULL)
3197c478bd9Sstevel@tonic-gate 		return;
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	for (i = 0; i < ctrl_nums; i++) {
3227c478bd9Sstevel@tonic-gate 		/* Status of '0' means RAID exists at that controller */
3237c478bd9Sstevel@tonic-gate 		if (info_ctrl[i][INFO_STATUS] == RAID_FOUND ||
3247c478bd9Sstevel@tonic-gate 		    info_ctrl[i][INFO_STATUS] == RAID_DONT_USE)
3257c478bd9Sstevel@tonic-gate 			continue;
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 		if (!space && raids != NULL) {
3287c478bd9Sstevel@tonic-gate 			(void) printf("\n");
3297c478bd9Sstevel@tonic-gate 			space = 1;
3307c478bd9Sstevel@tonic-gate 		}
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 		/* switch statement used to enable gettext()'ing of text */
3337c478bd9Sstevel@tonic-gate 		switch (info_ctrl[i][INFO_STATUS]) {
3347c478bd9Sstevel@tonic-gate 		case RAID_INVALID_CTRL:
3357c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Invalid controller '%d'\n"),
3367c478bd9Sstevel@tonic-gate 				info_ctrl[i][INFO_CTRL]);
3377c478bd9Sstevel@tonic-gate 			break;
3387c478bd9Sstevel@tonic-gate 		case RAID_NOT_SUPPORTED:
3397c478bd9Sstevel@tonic-gate 			(void) printf(gettext("No RAID supported "
3407c478bd9Sstevel@tonic-gate 				"on controller '%d'\n"),
3417c478bd9Sstevel@tonic-gate 					info_ctrl[i][INFO_CTRL]);
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 			break;
3447c478bd9Sstevel@tonic-gate 		default:
3457c478bd9Sstevel@tonic-gate 			(void) printf(gettext("No RAID volumes found on "
3467c478bd9Sstevel@tonic-gate 				"controller '%d'\n"), info_ctrl[i][INFO_CTRL]);
3477c478bd9Sstevel@tonic-gate 		}
3487c478bd9Sstevel@tonic-gate 	}
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate static void
3527c478bd9Sstevel@tonic-gate add_raid_to_raidlist(char *ctrl_name, int controller)
3537c478bd9Sstevel@tonic-gate {
3547c478bd9Sstevel@tonic-gate 	raidlist_t		*curr;
3557c478bd9Sstevel@tonic-gate 	char			buf[MAXPATHLEN] = {0};
3567c478bd9Sstevel@tonic-gate 	char			buf1[MAXPATHLEN] = {0};
357*6fec3791Sjesseb 	int			nvols;
3588ba1bcfcSdduvall 	int			fd;
3598ba1bcfcSdduvall 	int			i;
360*6fec3791Sjesseb 	int			n;
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	if (readlink(ctrl_name, buf, sizeof (buf)) < 0)
3637c478bd9Sstevel@tonic-gate 		return;
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	if (get_ctrl_devctl(buf, buf1))
3667c478bd9Sstevel@tonic-gate 		return;
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	/*
3697c478bd9Sstevel@tonic-gate 	 * If "-l" was specified, then only look at those controllers
3707c478bd9Sstevel@tonic-gate 	 * listed as part of the command line input.
3717c478bd9Sstevel@tonic-gate 	 */
3727c478bd9Sstevel@tonic-gate 	if (info_ctrl != NULL) {
3737c478bd9Sstevel@tonic-gate 		for (i = 0; i < ctrl_nums; i++) {
3747c478bd9Sstevel@tonic-gate 			if (info_ctrl[i][INFO_STATUS] == RAID_DONT_USE)
3757c478bd9Sstevel@tonic-gate 				continue;
376*6fec3791Sjesseb 			if (controller == info_ctrl[i][INFO_CTRL])
3777c478bd9Sstevel@tonic-gate 				break;
3787c478bd9Sstevel@tonic-gate 		}
379*6fec3791Sjesseb 		/* return if we didn't find a controller */
380*6fec3791Sjesseb 		if (i == ctrl_nums)
3817c478bd9Sstevel@tonic-gate 			return;
3827c478bd9Sstevel@tonic-gate 	}
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	fd = open(buf1, O_RDONLY);
3857c478bd9Sstevel@tonic-gate 	if (fd == -1) {
3867c478bd9Sstevel@tonic-gate 		if (info_ctrl != NULL)
3877c478bd9Sstevel@tonic-gate 			info_ctrl[i][INFO_STATUS] = RAID_INVALID_CTRL;
3887c478bd9Sstevel@tonic-gate 		return;
3897c478bd9Sstevel@tonic-gate 	}
3907c478bd9Sstevel@tonic-gate 
391*6fec3791Sjesseb 	/*
392*6fec3791Sjesseb 	 * query the HBA driver for volume capacity
393*6fec3791Sjesseb 	 */
394*6fec3791Sjesseb 	if (ioctl(fd, RAID_NUMVOLUMES, &nvols) < 0) {
395*6fec3791Sjesseb 		if (info_ctrl != NULL)
396*6fec3791Sjesseb 			info_ctrl[i][INFO_STATUS] = RAID_NOT_SUPPORTED;
397*6fec3791Sjesseb 		(void) close(fd);
398*6fec3791Sjesseb 		return;
399*6fec3791Sjesseb 	}
400*6fec3791Sjesseb 
401*6fec3791Sjesseb 	/*
402*6fec3791Sjesseb 	 * now iterate through nvols configurations
403*6fec3791Sjesseb 	 */
404*6fec3791Sjesseb 	for (n = 0; n < nvols; n++) {
405*6fec3791Sjesseb 		raid_config_t		config;
406*6fec3791Sjesseb 
407*6fec3791Sjesseb 		/* use unitid to retrieve this volume */
408*6fec3791Sjesseb 		config.unitid = n;
4097c478bd9Sstevel@tonic-gate 		if (ioctl(fd, RAID_GETCONFIG, &config) < 0) {
4107c478bd9Sstevel@tonic-gate 			if (info_ctrl != NULL)
4117c478bd9Sstevel@tonic-gate 				info_ctrl[i][INFO_STATUS] = RAID_NOT_SUPPORTED;
4127c478bd9Sstevel@tonic-gate 			(void) close(fd);
4137c478bd9Sstevel@tonic-gate 			return;
4147c478bd9Sstevel@tonic-gate 		}
4157c478bd9Sstevel@tonic-gate 
416*6fec3791Sjesseb 		/* if ndisks is 0, this volume is not configured */
417*6fec3791Sjesseb 		if (config.ndisks == 0)
418*6fec3791Sjesseb 			continue;
419*6fec3791Sjesseb 
420*6fec3791Sjesseb 		/* otherwise, we have a raid volume */
4217c478bd9Sstevel@tonic-gate 		if (info_ctrl != NULL)
4227c478bd9Sstevel@tonic-gate 			info_ctrl[i][INFO_STATUS] = RAID_FOUND;
4237c478bd9Sstevel@tonic-gate 
424*6fec3791Sjesseb 		/*
425*6fec3791Sjesseb 		 * if raids has not been initialized, do it.
426*6fec3791Sjesseb 		 * otherwise, see if this controller is in
427*6fec3791Sjesseb 		 * raids.
428*6fec3791Sjesseb 		 */
4297c478bd9Sstevel@tonic-gate 		if (raids == NULL) {
4307c478bd9Sstevel@tonic-gate 			raids = (raidlist_t *)malloc(sizeof (raidlist_t));
4317c478bd9Sstevel@tonic-gate 			curr = raids;
4327c478bd9Sstevel@tonic-gate 		} else {
4337c478bd9Sstevel@tonic-gate 			curr = raids;
434*6fec3791Sjesseb 			if (already_there(controller))
435*6fec3791Sjesseb 				goto already_there;
436*6fec3791Sjesseb 
437*6fec3791Sjesseb 			/* add this controller to raids */
4387c478bd9Sstevel@tonic-gate 			while (curr->next != NULL)
4397c478bd9Sstevel@tonic-gate 				curr = curr->next;
4407c478bd9Sstevel@tonic-gate 			curr->next = (raidlist_t *)malloc(sizeof (raidlist_t));
4417c478bd9Sstevel@tonic-gate 			curr = curr->next;
4427c478bd9Sstevel@tonic-gate 		}
443*6fec3791Sjesseb 
444*6fec3791Sjesseb already_there:
4457c478bd9Sstevel@tonic-gate 		curr->next = NULL;
4467c478bd9Sstevel@tonic-gate 		curr->controller = controller;
4477c478bd9Sstevel@tonic-gate 		(void) strlcpy(curr->devctl, buf1, sizeof (curr->devctl));
4487c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
449*6fec3791Sjesseb 		(void) memcpy(&curr->raid_config[n], &config,
450*6fec3791Sjesseb 				(sizeof (raid_config_t)));
451*6fec3791Sjesseb 	}
452*6fec3791Sjesseb 
453*6fec3791Sjesseb 	if (info_ctrl != NULL && info_ctrl[i][INFO_STATUS] != RAID_FOUND)
454*6fec3791Sjesseb 		info_ctrl[i][INFO_STATUS] = RAID_NOT_FOUND;
4557c478bd9Sstevel@tonic-gate }
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate static void
4587c478bd9Sstevel@tonic-gate print_header()
4597c478bd9Sstevel@tonic-gate {
460*6fec3791Sjesseb 	(void) printf(gettext("RAID\tVolume\tRAID\t\tRAID\t\tDisk"));
4617c478bd9Sstevel@tonic-gate 	(void) printf("\n");
462*6fec3791Sjesseb 	(void) printf(gettext("Volume\tType\tStatus\t\tDisk\t\tStatus"));
4637c478bd9Sstevel@tonic-gate 	(void) printf("\n");
4647c478bd9Sstevel@tonic-gate 	(void) printf("------------------------------------------------------");
4657c478bd9Sstevel@tonic-gate 	(void) printf("\n");
4667c478bd9Sstevel@tonic-gate }
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate static void
4697c478bd9Sstevel@tonic-gate print_raidconfig(int c, raid_config_t config)
4707c478bd9Sstevel@tonic-gate {
4717c478bd9Sstevel@tonic-gate 	int	i;
472*6fec3791Sjesseb 	char	voltype[8];
4737c478bd9Sstevel@tonic-gate 
474*6fec3791Sjesseb 	/* print RAID volume target ID and volume type */
475*6fec3791Sjesseb 	if (config.raid_level == RAID_STRIPE) {
476*6fec3791Sjesseb 		(void) snprintf(voltype, sizeof (voltype), "IS");
477*6fec3791Sjesseb 	} else if (config.raid_level == RAID_MIRROR) {
478*6fec3791Sjesseb 		(void) snprintf(voltype, sizeof (voltype), "IM");
479*6fec3791Sjesseb 	}
480*6fec3791Sjesseb 
481*6fec3791Sjesseb 	(void) printf("c%dt%dd0\t%s\t", c, config.targetid, voltype);
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	/* Get RAID Info */
4847c478bd9Sstevel@tonic-gate 	if (config.flags & RAID_FLAG_RESYNCING &&
4857c478bd9Sstevel@tonic-gate 	    config.state == RAID_STATE_DEGRADED) {
4867c478bd9Sstevel@tonic-gate 		(void) printf(gettext("RESYNCING\t"));
4877c478bd9Sstevel@tonic-gate 	} else if (config.state == RAID_STATE_DEGRADED) {
4887c478bd9Sstevel@tonic-gate 		(void) printf(gettext("DEGRADED\t"));
4897c478bd9Sstevel@tonic-gate 	} else if (config.state == RAID_STATE_OPTIMAL) {
4907c478bd9Sstevel@tonic-gate 		(void) printf(gettext("OK\t\t"));
4917c478bd9Sstevel@tonic-gate 	} else if (config.state == RAID_STATE_FAILED) {
4927c478bd9Sstevel@tonic-gate 		(void) printf(gettext("FAILED\t\t"));
4937c478bd9Sstevel@tonic-gate 	} else {
4947c478bd9Sstevel@tonic-gate 		(void) printf(gettext("ERROR\t\t"));
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	/* Get RAID Disks */
4987c478bd9Sstevel@tonic-gate 	(void) printf("c%dt%dd0\t\t", c, config.disk[0]);
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	/* Get RAID Disk's Status */
5017c478bd9Sstevel@tonic-gate 	if (config.diskstatus[0] & RAID_DISKSTATUS_FAILED) {
5027c478bd9Sstevel@tonic-gate 		(void) printf(gettext("FAILED\n"));
5037c478bd9Sstevel@tonic-gate 	} else if (config.diskstatus[0] & RAID_DISKSTATUS_MISSING) {
5047c478bd9Sstevel@tonic-gate 		(void) printf(gettext("MISSING\n"));
5057c478bd9Sstevel@tonic-gate 	} else {
5067c478bd9Sstevel@tonic-gate 		(void) printf(gettext("OK\n"));
5077c478bd9Sstevel@tonic-gate 	}
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	for (i = 1; i < config.ndisks; i++) {
5107c478bd9Sstevel@tonic-gate 		(void) printf("\t\t\t\tc%dt%dd0\t\t", c, config.disk[i]);
5117c478bd9Sstevel@tonic-gate 		if (config.diskstatus[i] & RAID_DISKSTATUS_FAILED) {
5127c478bd9Sstevel@tonic-gate 			(void) printf(gettext("FAILED\n"));
5137c478bd9Sstevel@tonic-gate 		} else if (config.diskstatus[i] & RAID_DISKSTATUS_MISSING) {
5147c478bd9Sstevel@tonic-gate 			(void) printf(gettext("MISSING\n"));
5157c478bd9Sstevel@tonic-gate 		} else {
5167c478bd9Sstevel@tonic-gate 			(void) printf(gettext("OK\n"));
5177c478bd9Sstevel@tonic-gate 		}
5187c478bd9Sstevel@tonic-gate 	}
5197c478bd9Sstevel@tonic-gate }
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate static void
5227c478bd9Sstevel@tonic-gate print_disklist()
5237c478bd9Sstevel@tonic-gate {
5247c478bd9Sstevel@tonic-gate 	raidlist_t	*curr = raids;
525*6fec3791Sjesseb 	int i;
526*6fec3791Sjesseb 
5277c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
528*6fec3791Sjesseb 		for (i = 0; i < N_RAIDVOLS; i++) {
529*6fec3791Sjesseb 			if (curr->raid_config[i].ndisks != 0) {
530*6fec3791Sjesseb 				print_raidconfig(curr->controller,
531*6fec3791Sjesseb 						curr->raid_config[i]);
532*6fec3791Sjesseb 			}
533*6fec3791Sjesseb 		}
5347c478bd9Sstevel@tonic-gate 		curr = curr->next;
5357c478bd9Sstevel@tonic-gate 	}
5367c478bd9Sstevel@tonic-gate }
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate static void
5397c478bd9Sstevel@tonic-gate free_disklist()
5407c478bd9Sstevel@tonic-gate {
5417c478bd9Sstevel@tonic-gate 	raidlist_t	*curr = raids;
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
5447c478bd9Sstevel@tonic-gate 		raidlist_t	*temp;
5457c478bd9Sstevel@tonic-gate 		temp = curr;
5467c478bd9Sstevel@tonic-gate 		curr = curr->next;
5477c478bd9Sstevel@tonic-gate 		free(temp);
5487c478bd9Sstevel@tonic-gate 	}
5497c478bd9Sstevel@tonic-gate }
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate static void
5527c478bd9Sstevel@tonic-gate do_search()
5537c478bd9Sstevel@tonic-gate {
5547c478bd9Sstevel@tonic-gate 	DIR		*dir;
5557c478bd9Sstevel@tonic-gate 	struct dirent	*dp;
5567c478bd9Sstevel@tonic-gate 	char		buf[MAXPATHLEN];
5577c478bd9Sstevel@tonic-gate 	int		c;
5587c478bd9Sstevel@tonic-gate 	int		i, j;
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 	/*
5617c478bd9Sstevel@tonic-gate 	 * In case repeated numbers were found, assign the repititions as
5627c478bd9Sstevel@tonic-gate 	 * RAID_DONT_USE
5637c478bd9Sstevel@tonic-gate 	 */
5647c478bd9Sstevel@tonic-gate 	for (i = 0; i < ctrl_nums; i++) {
5657c478bd9Sstevel@tonic-gate 		int first_one = 1;
5667c478bd9Sstevel@tonic-gate 		for (j = 0; j < ctrl_nums; j++) {
5677c478bd9Sstevel@tonic-gate 			if (info_ctrl[i][INFO_CTRL] ==
5687c478bd9Sstevel@tonic-gate 				info_ctrl[j][INFO_CTRL]) {
5697c478bd9Sstevel@tonic-gate 				if (info_ctrl[j][INFO_STATUS] == RAID_DONT_USE)
5707c478bd9Sstevel@tonic-gate 					continue;
5717c478bd9Sstevel@tonic-gate 				if (first_one) {
5727c478bd9Sstevel@tonic-gate 					first_one = 0;
5737c478bd9Sstevel@tonic-gate 				} else {
5747c478bd9Sstevel@tonic-gate 					info_ctrl[j][INFO_STATUS] =
5757c478bd9Sstevel@tonic-gate 						RAID_DONT_USE;
5767c478bd9Sstevel@tonic-gate 				}
5777c478bd9Sstevel@tonic-gate 			}
5787c478bd9Sstevel@tonic-gate 		}
5797c478bd9Sstevel@tonic-gate 	}
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	if ((dir = opendir("/dev/cfg")) == NULL) {
5827c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
5837c478bd9Sstevel@tonic-gate 			gettext("Cannot open /dev/cfg: %s\n"), strerror(errno));
5847c478bd9Sstevel@tonic-gate 		return;
5857c478bd9Sstevel@tonic-gate 	}
5867c478bd9Sstevel@tonic-gate 	while ((dp = readdir(dir)) != NULL) {
5877c478bd9Sstevel@tonic-gate 		if (strcmp(dp->d_name, ".") == 0 ||
5887c478bd9Sstevel@tonic-gate 		    strcmp(dp->d_name, "..") == 0)
5897c478bd9Sstevel@tonic-gate 			continue;
5907c478bd9Sstevel@tonic-gate 		if (sscanf(dp->d_name, "c%d", &c) != 1)
5917c478bd9Sstevel@tonic-gate 			continue;
5927c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), "/dev/cfg/%s", dp->d_name);
5937c478bd9Sstevel@tonic-gate 		add_raid_to_raidlist(buf, c);
5947c478bd9Sstevel@tonic-gate 	}
5957c478bd9Sstevel@tonic-gate 	(void) closedir(dir);
5967c478bd9Sstevel@tonic-gate }
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate /*
5997c478bd9Sstevel@tonic-gate  * do_info() will do the following:
6007c478bd9Sstevel@tonic-gate  * - create a list of disks' devctls
6017c478bd9Sstevel@tonic-gate  * - try to talk to each of the devctls found
6027c478bd9Sstevel@tonic-gate  * - if raid configuration is found, display it.
6037c478bd9Sstevel@tonic-gate  */
6047c478bd9Sstevel@tonic-gate static void
6057c478bd9Sstevel@tonic-gate do_info()
6067c478bd9Sstevel@tonic-gate {
6077c478bd9Sstevel@tonic-gate 	int i;
6087c478bd9Sstevel@tonic-gate 	(void) chdir(DEVDIR);
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	do_search();
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	if (raids == NULL) {
6137c478bd9Sstevel@tonic-gate 		if (info_ctrl != NULL) {
6147c478bd9Sstevel@tonic-gate 			print_no_raids();
6157c478bd9Sstevel@tonic-gate 			for (i = 0; i < ctrl_nums; i++)
6167c478bd9Sstevel@tonic-gate 				free(info_ctrl[i]);
6177c478bd9Sstevel@tonic-gate 			free(info_ctrl);
6187c478bd9Sstevel@tonic-gate 		} else {
6197c478bd9Sstevel@tonic-gate 			(void) printf(gettext("No RAID volumes found\n"));
6207c478bd9Sstevel@tonic-gate 		}
6217c478bd9Sstevel@tonic-gate 		return;
6227c478bd9Sstevel@tonic-gate 	}
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	print_header();
6257c478bd9Sstevel@tonic-gate 	print_disklist();
6267c478bd9Sstevel@tonic-gate 	print_no_raids();
6277c478bd9Sstevel@tonic-gate 	free_disklist();
6287c478bd9Sstevel@tonic-gate 	if (info_ctrl) {
6297c478bd9Sstevel@tonic-gate 		for (i = 0; i < ctrl_nums; i++)
6307c478bd9Sstevel@tonic-gate 			free(info_ctrl[i]);
6317c478bd9Sstevel@tonic-gate 		free(info_ctrl);
6327c478bd9Sstevel@tonic-gate 	}
6337c478bd9Sstevel@tonic-gate }
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate static int
636*6fec3791Sjesseb disk_in_raid(int c, int t)
637*6fec3791Sjesseb {
638*6fec3791Sjesseb 	raidlist_t	*curr;
639*6fec3791Sjesseb 	raid_config_t	raid;
640*6fec3791Sjesseb 	int i, j, n;
641*6fec3791Sjesseb 
642*6fec3791Sjesseb 	do_search();
643*6fec3791Sjesseb 	curr = raids;
644*6fec3791Sjesseb 
645*6fec3791Sjesseb 	while (curr != NULL) {
646*6fec3791Sjesseb 		if (curr->controller == c) {
647*6fec3791Sjesseb 			for (i = 0; i < N_RAIDVOLS; i++) {
648*6fec3791Sjesseb 				raid = curr->raid_config[i];
649*6fec3791Sjesseb 				if ((n = raid.ndisks) != 0) {
650*6fec3791Sjesseb 					for (j = 0; j < n; j++) {
651*6fec3791Sjesseb 						if (raid.disk[j] == t) {
652*6fec3791Sjesseb 							return (1);
653*6fec3791Sjesseb 						}
654*6fec3791Sjesseb 					}
655*6fec3791Sjesseb 				}
656*6fec3791Sjesseb 			}
657*6fec3791Sjesseb 		}
658*6fec3791Sjesseb 		curr = curr->next;
659*6fec3791Sjesseb 	}
660*6fec3791Sjesseb 	return (0);
661*6fec3791Sjesseb }
662*6fec3791Sjesseb 
663*6fec3791Sjesseb static int
6647c478bd9Sstevel@tonic-gate disk_there(int c, int t)
6657c478bd9Sstevel@tonic-gate {
6667c478bd9Sstevel@tonic-gate 	char	disk[100];
6677c478bd9Sstevel@tonic-gate 	int	fd;
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 	(void) snprintf(disk, sizeof (disk), "c%dt%dd0s2", c, t);
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	fd = open(disk, O_RDWR | O_NDELAY);
6727c478bd9Sstevel@tonic-gate 	if (fd == -1) {
6737c478bd9Sstevel@tonic-gate 		return (-1);
6747c478bd9Sstevel@tonic-gate 	}
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	(void) close(fd);
6777c478bd9Sstevel@tonic-gate 	return (0);
6787c478bd9Sstevel@tonic-gate }
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate static int
6817c478bd9Sstevel@tonic-gate get_controller(char *dev)
6827c478bd9Sstevel@tonic-gate {
6837c478bd9Sstevel@tonic-gate 	raidlist_t	*curr;
6847c478bd9Sstevel@tonic-gate 	int		c;
6857c478bd9Sstevel@tonic-gate 	do_search();
6867c478bd9Sstevel@tonic-gate 	curr = raids;
6877c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
6887c478bd9Sstevel@tonic-gate 		if (strcmp(curr->devctl, dev) == 0) {
6897c478bd9Sstevel@tonic-gate 			c = curr->controller;
6907c478bd9Sstevel@tonic-gate 			break;
6917c478bd9Sstevel@tonic-gate 		}
6927c478bd9Sstevel@tonic-gate 		curr = curr->next;
6937c478bd9Sstevel@tonic-gate 	}
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	free_disklist();
6967c478bd9Sstevel@tonic-gate 	return (c);
6977c478bd9Sstevel@tonic-gate }
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate static int
7007c478bd9Sstevel@tonic-gate disk_mounted(char *d)
7017c478bd9Sstevel@tonic-gate {
7027c478bd9Sstevel@tonic-gate 	struct mnttab	mt;
7037c478bd9Sstevel@tonic-gate 	FILE		*f = fopen("/etc/mnttab", "r");
7047c478bd9Sstevel@tonic-gate 
7058ba1bcfcSdduvall 	while (getmntent(f, &mt) != EOF)
7067c478bd9Sstevel@tonic-gate 		if (strstr(mt.mnt_special, d) != NULL)
7077c478bd9Sstevel@tonic-gate 			return (1);
708*6fec3791Sjesseb 
7097c478bd9Sstevel@tonic-gate 	return (0);
7107c478bd9Sstevel@tonic-gate }
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate static int
7137c478bd9Sstevel@tonic-gate disk_big_enough(char **d, diskaddr_t *cap, int *errcond)
7147c478bd9Sstevel@tonic-gate {
7157c478bd9Sstevel@tonic-gate 	struct dk_minfo minfo;
7167c478bd9Sstevel@tonic-gate 	char		disk[N_DISKS][MAXPATHLEN];
717*6fec3791Sjesseb 	uint_t		disk_lbsize[N_DISKS];
7187c478bd9Sstevel@tonic-gate 	diskaddr_t	disk_capacity[N_DISKS];
7197c478bd9Sstevel@tonic-gate 	int		i, fd;
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 	for (i = 0; i < N_DISKS; i++) {
722*6fec3791Sjesseb 		if (d[i] == NULL)
723*6fec3791Sjesseb 			break;
724*6fec3791Sjesseb 
7257c478bd9Sstevel@tonic-gate 		(void) snprintf(disk[i], sizeof (disk[i]), DEVDIR"/%ss2", d[i]);
7267c478bd9Sstevel@tonic-gate 		fd = open(disk[i], O_RDWR | O_NDELAY);
727*6fec3791Sjesseb 		if (fd == -1)
7287c478bd9Sstevel@tonic-gate 			return (FAILURE);
7297c478bd9Sstevel@tonic-gate 		if (ioctl(fd, DKIOCGMEDIAINFO, &minfo) == -1) {
7307c478bd9Sstevel@tonic-gate 			(void) close(fd);
7317c478bd9Sstevel@tonic-gate 			return (FAILURE);
7327c478bd9Sstevel@tonic-gate 		}
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 		disk_lbsize[i] = minfo.dki_lbsize;
7357c478bd9Sstevel@tonic-gate 		disk_capacity[i] = minfo.dki_capacity;
7367c478bd9Sstevel@tonic-gate 
737*6fec3791Sjesseb 		/* lbsize must be the same on all disks */
738*6fec3791Sjesseb 		if (disk_lbsize[0] != disk_lbsize[i]) {
7397c478bd9Sstevel@tonic-gate 			*errcond = 2;
7407c478bd9Sstevel@tonic-gate 			return (INVALID_ARG);
7417c478bd9Sstevel@tonic-gate 		}
7427c478bd9Sstevel@tonic-gate 
743*6fec3791Sjesseb 		/* ensure drive capacity is greater than or equal to first */
744*6fec3791Sjesseb 		if (disk_capacity[0] > disk_capacity[i]) {
7457c478bd9Sstevel@tonic-gate 			*errcond = 1;
7467c478bd9Sstevel@tonic-gate 			return (INVALID_ARG);
7477c478bd9Sstevel@tonic-gate 		}
748*6fec3791Sjesseb 		(void) close(fd);
749*6fec3791Sjesseb 	}
7507c478bd9Sstevel@tonic-gate 
751*6fec3791Sjesseb 	/*
752*6fec3791Sjesseb 	 * setting capacity as the dk_minfo.dki_capacity of d[0]
753*6fec3791Sjesseb 	 *   this is the number of dki_lbsize blocks on disk
754*6fec3791Sjesseb 	 */
7557c478bd9Sstevel@tonic-gate 	*cap = disk_capacity[0];
7567c478bd9Sstevel@tonic-gate 	return (SUCCESS);
7577c478bd9Sstevel@tonic-gate }
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate static int
7607c478bd9Sstevel@tonic-gate do_config_change_state(cfga_cmd_t cmd, int d, int c)
7617c478bd9Sstevel@tonic-gate {
7627c478bd9Sstevel@tonic-gate 	cfga_err_t	cfga_err;
7637c478bd9Sstevel@tonic-gate 	char		*ap_id;
7647c478bd9Sstevel@tonic-gate 	int		rv = SUCCESS;
7657c478bd9Sstevel@tonic-gate 	int		count = 0;
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 	ap_id = (char *)malloc(100);
7687c478bd9Sstevel@tonic-gate 	if (ap_id == NULL)
7697c478bd9Sstevel@tonic-gate 		return (FAILURE);
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	(void) snprintf(ap_id, 100, "c%d::dsk/c%dt%dd0", c, c, d);
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 	/*
7747c478bd9Sstevel@tonic-gate 	 * If the config_change_state() funcation fails, we want to
7757c478bd9Sstevel@tonic-gate 	 * retry.  If the retry fails, then we return failure to fail.
7767c478bd9Sstevel@tonic-gate 	 *
7777c478bd9Sstevel@tonic-gate 	 * If we fail:
7787c478bd9Sstevel@tonic-gate 	 *
7797c478bd9Sstevel@tonic-gate 	 *	If we were called from create, then we fail the raid
7807c478bd9Sstevel@tonic-gate 	 *	creation.
7817c478bd9Sstevel@tonic-gate 	 *
7827c478bd9Sstevel@tonic-gate 	 *	If we were called from delete, then the disk will not
7837c478bd9Sstevel@tonic-gate 	 *	be re-configured by raidctl.
7847c478bd9Sstevel@tonic-gate 	 */
7857c478bd9Sstevel@tonic-gate 	do {
7867c478bd9Sstevel@tonic-gate 		cfga_err = config_change_state(cmd, 1, &ap_id, NULL,
7877c478bd9Sstevel@tonic-gate 			NULL, NULL, NULL, 0);
7887c478bd9Sstevel@tonic-gate 		count++;
7897c478bd9Sstevel@tonic-gate 	} while (cfga_err != CFGA_OK && count < 2);
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 	if (cfga_err != CFGA_OK)
7927c478bd9Sstevel@tonic-gate 		rv = FAILURE;
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	free(ap_id);
7957c478bd9Sstevel@tonic-gate 	return (rv);
7967c478bd9Sstevel@tonic-gate }
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate static int
799*6fec3791Sjesseb do_create(char **d, int rlevel, int force)
8007c478bd9Sstevel@tonic-gate {
8018ba1bcfcSdduvall 	raid_config_t	config;
802*6fec3791Sjesseb 	raid_config_t	newvol;
8037c478bd9Sstevel@tonic-gate 	char		disk[N_DISKS][MAXPATHLEN] = {0};
804*6fec3791Sjesseb 	int		map[N_DISKS];
8057c478bd9Sstevel@tonic-gate 	char		channel1[MAXPATHLEN];
8067c478bd9Sstevel@tonic-gate 	char		channel2[MAXPATHLEN];
8077c478bd9Sstevel@tonic-gate 	diskaddr_t	capacity;
808*6fec3791Sjesseb 	int		fd, fd2, size, errcond;
8097c478bd9Sstevel@tonic-gate 	int		c[N_DISKS];
8107c478bd9Sstevel@tonic-gate 	int		t[N_DISKS];
8117c478bd9Sstevel@tonic-gate 	char		*tmp;
812*6fec3791Sjesseb 	int		loc, i, devid, n, ndisks = 0;
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 	(void) chdir(DEVDIR);
8157c478bd9Sstevel@tonic-gate 
816*6fec3791Sjesseb 	/* initialize target map */
817*6fec3791Sjesseb 	for (i = 0; i < N_DISKS; i++)
818*6fec3791Sjesseb 		map[i] = -1;
819*6fec3791Sjesseb 
8207c478bd9Sstevel@tonic-gate 	for (i = 0; i < N_DISKS; i++) {
821*6fec3791Sjesseb 		if (d[i] == NULL)
822*6fec3791Sjesseb 			break;
823*6fec3791Sjesseb 
8247c478bd9Sstevel@tonic-gate 		if ((sscanf(d[i], "c%dt%dd0", &c[i], &t[i])) != 2 ||
8257c478bd9Sstevel@tonic-gate 		    t[i] < 0) {
8267c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
8277c478bd9Sstevel@tonic-gate 				gettext("Invalid disk format.\n"));
8287c478bd9Sstevel@tonic-gate 			return (INVALID_ARG);
8297c478bd9Sstevel@tonic-gate 		}
8307c478bd9Sstevel@tonic-gate 
831*6fec3791Sjesseb 		/* ensure that all disks are on the same controller, */
832*6fec3791Sjesseb 		if (c[i] != c[0]) {
833*6fec3791Sjesseb 			(void) fprintf(stderr, gettext("Disks must be "
834*6fec3791Sjesseb 					"on the same controller.\n"));
8357c478bd9Sstevel@tonic-gate 			return (INVALID_ARG);
8367c478bd9Sstevel@tonic-gate 		}
8377c478bd9Sstevel@tonic-gate 
838*6fec3791Sjesseb 		/* that all disks are online, */
839*6fec3791Sjesseb 		if (disk_there(c[0], t[i])) {
840*6fec3791Sjesseb 			(void) printf(gettext("Disk 'c%dt%dd0' is not "
841*6fec3791Sjesseb 				"present.\n"), c[0], t[i]);
8427c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Cannot create RAID volume.\n"));
8437c478bd9Sstevel@tonic-gate 			return (INVALID_ARG);
8447c478bd9Sstevel@tonic-gate 		}
8457c478bd9Sstevel@tonic-gate 
846*6fec3791Sjesseb 		/* that there are no duplicate disks, */
847*6fec3791Sjesseb 		loc = t[i];
848*6fec3791Sjesseb 		if (map[loc] == -1) {
849*6fec3791Sjesseb 			map[loc] = t[i];
850*6fec3791Sjesseb 		} else {
851*6fec3791Sjesseb 			(void) fprintf(stderr,
852*6fec3791Sjesseb 				gettext("Disks must be different.\n"));
853*6fec3791Sjesseb 			return (INVALID_ARG);
854*6fec3791Sjesseb 		}
855*6fec3791Sjesseb 
856*6fec3791Sjesseb 		/* that no disk is already in use by another volume, */
857*6fec3791Sjesseb 		if (disk_in_raid(c[0], t[i])) {
858*6fec3791Sjesseb 			(void) fprintf(stderr, gettext("Disk %s is already in "
859*6fec3791Sjesseb 				"a RAID volume.\n"), d[i]);
860*6fec3791Sjesseb 			return (INVALID_ARG);
861*6fec3791Sjesseb 		}
862*6fec3791Sjesseb 
863*6fec3791Sjesseb 		/* that no target's id is lower than the raidtarg, */
864*6fec3791Sjesseb 		if (t[0] > t[i]) {
865*6fec3791Sjesseb 			(void) fprintf(stderr, gettext("First target ID must "
866*6fec3791Sjesseb 				"be less than other member target IDs.\n"));
867*6fec3791Sjesseb 			return (INVALID_ARG);
868*6fec3791Sjesseb 		}
869*6fec3791Sjesseb 
870*6fec3791Sjesseb 		(void) snprintf(disk[i], sizeof (disk[i]), DEVDIR"/%ss2", d[i]);
871*6fec3791Sjesseb 		ndisks++;
872*6fec3791Sjesseb 	}
873*6fec3791Sjesseb 
874*6fec3791Sjesseb 	/* confirm minimum number of disks */
875*6fec3791Sjesseb 	if (ndisks < 2) {
876*6fec3791Sjesseb 		(void) fprintf(stderr, gettext("At least two disks are required"
877*6fec3791Sjesseb 			" for RAID creation.\n"));
878*6fec3791Sjesseb 		return (INVALID_ARG);
879*6fec3791Sjesseb 	}
880*6fec3791Sjesseb 
881*6fec3791Sjesseb 	/* validate the drive capacities */
8827c478bd9Sstevel@tonic-gate 	switch (disk_big_enough(d, &capacity, &errcond)) {
8837c478bd9Sstevel@tonic-gate 	case FAILURE:
8847c478bd9Sstevel@tonic-gate 		return (FAILURE);
8857c478bd9Sstevel@tonic-gate 	case INVALID_ARG:
8867c478bd9Sstevel@tonic-gate 		switch (errcond) {
8877c478bd9Sstevel@tonic-gate 		case 1:
8887c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Cannot create RAID volume when "
8897c478bd9Sstevel@tonic-gate 			"primary disk is larger than secondary disk.\n"));
8907c478bd9Sstevel@tonic-gate 		break;
8917c478bd9Sstevel@tonic-gate 		case 2:
8927c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Cannot create RAID volume when "
8937c478bd9Sstevel@tonic-gate 			"disk block sizes differ.\n"));
8947c478bd9Sstevel@tonic-gate 		}
8957c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
8967c478bd9Sstevel@tonic-gate 	}
8977c478bd9Sstevel@tonic-gate 
898*6fec3791Sjesseb 	/*
899*6fec3791Sjesseb 	 * capacity is now set to the number of blocks on a disk, which is
900*6fec3791Sjesseb 	 * the total capacity of a mirror.  the capacity of a stripe is the
901*6fec3791Sjesseb 	 * cumulative amount of blocks on all disks
902*6fec3791Sjesseb 	 */
903*6fec3791Sjesseb 	if (rlevel == RAID_STRIPE)
904*6fec3791Sjesseb 		capacity *= ndisks;
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 	if (get_devctl(disk[0], channel1))
9077c478bd9Sstevel@tonic-gate 		return (FAILURE);
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 	fd = open(channel1, O_RDONLY);
9107c478bd9Sstevel@tonic-gate 	if (fd == -1) {
9117c478bd9Sstevel@tonic-gate 		perror(channel1);
9127c478bd9Sstevel@tonic-gate 		return (FAILURE);
9137c478bd9Sstevel@tonic-gate 	}
9147c478bd9Sstevel@tonic-gate 
915*6fec3791Sjesseb 	/*
916*6fec3791Sjesseb 	 * query the HBA driver for volume capacity
917*6fec3791Sjesseb 	 */
918*6fec3791Sjesseb 	if (ioctl(fd, RAID_NUMVOLUMES, &n) < 0) {
919*6fec3791Sjesseb 		raidctl_error("RAID_NUMVOLUMES");
920*6fec3791Sjesseb 		goto fail;
921*6fec3791Sjesseb 	}
922*6fec3791Sjesseb 
923*6fec3791Sjesseb 	/*
924*6fec3791Sjesseb 	 * current support for both LSI1030 and LSI1064/1068 HBAs
925*6fec3791Sjesseb 	 */
926*6fec3791Sjesseb 	if (ioctl(fd, RAID_GETDEVID, &devid) < 0) {
927*6fec3791Sjesseb 		raidctl_error("RAID_GETDEVID");
928*6fec3791Sjesseb 		goto fail;
929*6fec3791Sjesseb 	}
930*6fec3791Sjesseb 
931*6fec3791Sjesseb 	if ((devid == LSI_1064) || (devid == LSI_1064E) || (devid ==
932*6fec3791Sjesseb 	    LSI_1068E)) {
933*6fec3791Sjesseb 		/*
934*6fec3791Sjesseb 		 * no secondary channel, just check to make
935*6fec3791Sjesseb 		 * sure we can fit a new volume
936*6fec3791Sjesseb 		 */
937*6fec3791Sjesseb 		for (i = 0; i < n; i++) {
938*6fec3791Sjesseb 			config.unitid = i;
9397c478bd9Sstevel@tonic-gate 			if (ioctl(fd, RAID_GETCONFIG, &config) < 0) {
9407c478bd9Sstevel@tonic-gate 				raidctl_error("RAID_GETCONFIG");
941*6fec3791Sjesseb 				goto fail;
942*6fec3791Sjesseb 			}
943*6fec3791Sjesseb 
944*6fec3791Sjesseb 			if (config.ndisks == 0)
945*6fec3791Sjesseb 				break;
946*6fec3791Sjesseb 		}
947*6fec3791Sjesseb 
948*6fec3791Sjesseb 		if (i == n) {
949*6fec3791Sjesseb 			(void) printf(gettext("HBA supports a maximum of %d "
950*6fec3791Sjesseb 				"RAID Volumes, HBA is full\n"), n);
951*6fec3791Sjesseb 			goto fail;
952*6fec3791Sjesseb 		}
953*6fec3791Sjesseb 
954*6fec3791Sjesseb 		/*
955*6fec3791Sjesseb 		 * we have the capacity to add a volume, now confirm the
956*6fec3791Sjesseb 		 * creation. the 1064 uses a much larger metadata region
957*6fec3791Sjesseb 		 * than the 1030 (64MB, as opposed to 16KB).  this larger
958*6fec3791Sjesseb 		 * reservation is enough to alter the disk label. therefore,
959*6fec3791Sjesseb 		 * once the volume is created, it must be relabeled.
960*6fec3791Sjesseb 		 * first, confirm that no file systems are mounted, as
961*6fec3791Sjesseb 		 * we will be pulling the disk out from under them
962*6fec3791Sjesseb 		 */
963*6fec3791Sjesseb 		for (i = 0; i < ndisks; i++) {
964*6fec3791Sjesseb 			if (disk_mounted(d[i])) {
965*6fec3791Sjesseb 				(void) fprintf(stderr, gettext("Cannot create "
966*6fec3791Sjesseb 					"RAID volume, disk \"%s\" is mounted "
967*6fec3791Sjesseb 					".\n"), d[i]);
968*6fec3791Sjesseb 				return (INVALID_ARG);
969*6fec3791Sjesseb 			}
970*6fec3791Sjesseb 		}
971*6fec3791Sjesseb 
972*6fec3791Sjesseb 		/*
973*6fec3791Sjesseb 		 * will not support data migration or disk relabeling with
974*6fec3791Sjesseb 		 * this utility, and so next we must confirm the creation as
975*6fec3791Sjesseb 		 * all data on member disks will be lost.
976*6fec3791Sjesseb 		 */
977*6fec3791Sjesseb 		if (!force) {
978*6fec3791Sjesseb 			(void) fprintf(stderr, gettext("Creating RAID volume "
979*6fec3791Sjesseb 			    "c%dt%dd0 will destroy all data on member disks, "
980*6fec3791Sjesseb 			    "proceed (%s/%s)? "), c[0], t[0], yeschr, nochr);
981*6fec3791Sjesseb 			if (!yes()) {
982*6fec3791Sjesseb 				(void) fprintf(stderr, gettext("RAID volume "
983*6fec3791Sjesseb 				    "c%dt%dd0 not created.\n\n"), c[0], t[0]);
984*6fec3791Sjesseb 				(void) close(fd);
985*6fec3791Sjesseb 				return (SUCCESS);
986*6fec3791Sjesseb 			}
987*6fec3791Sjesseb 		}
988*6fec3791Sjesseb 
989*6fec3791Sjesseb 		/*
990*6fec3791Sjesseb 		 * we are ready to move onto the creation
991*6fec3791Sjesseb 		 */
992*6fec3791Sjesseb 		goto no_secondary_channel;
993*6fec3791Sjesseb 	}
994*6fec3791Sjesseb 
995*6fec3791Sjesseb 	/*
996*6fec3791Sjesseb 	 * LSI1030, support for single IM volume
997*6fec3791Sjesseb 	 */
998*6fec3791Sjesseb 	if (rlevel != RAID_MIRROR) {
999*6fec3791Sjesseb 		(void) printf(gettext("HBA only supports RAID "
1000*6fec3791Sjesseb 			"level 1 (mirrored) volumes\n"));
1001*6fec3791Sjesseb 		goto fail;
1002*6fec3791Sjesseb 	}
1003*6fec3791Sjesseb 	/*
1004*6fec3791Sjesseb 	 * look up the volume configuration
1005*6fec3791Sjesseb 	 */
1006*6fec3791Sjesseb 	config.unitid = n;
1007*6fec3791Sjesseb 	if (ioctl(fd, RAID_GETCONFIG, &config) < 0) {
1008*6fec3791Sjesseb 		raidctl_error("RAID_GETCONFIG");
1009*6fec3791Sjesseb 		goto fail;
10107c478bd9Sstevel@tonic-gate 	}
10117c478bd9Sstevel@tonic-gate 
10128ba1bcfcSdduvall 	if (config.ndisks != 0) {
1013*6fec3791Sjesseb 		(void) printf(gettext("RAID Volume already exists "
1014*6fec3791Sjesseb 			"on this controller 'c%dt%dd0'\n"),
1015*6fec3791Sjesseb 			c[0], config.targetid);
1016*6fec3791Sjesseb 		goto fail;
101705411564Sjesseb 	}
101805411564Sjesseb 
101905411564Sjesseb 	/*
10207c478bd9Sstevel@tonic-gate 	 * Make sure there isn't a raid created on this controller's
1021*6fec3791Sjesseb 	 * other channel, if it has multiple channels
10227c478bd9Sstevel@tonic-gate 	 */
10237c478bd9Sstevel@tonic-gate 	(void) strlcpy(channel2, channel1, sizeof (channel2));
10247c478bd9Sstevel@tonic-gate 	tmp = strrchr(channel2, ':');
10257c478bd9Sstevel@tonic-gate 	tmp[0] = 0;
10267c478bd9Sstevel@tonic-gate 	size = strlen(channel2);
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate 	/*
1029*6fec3791Sjesseb 	 * Make sure that the secondary disk is not mounted
1030*6fec3791Sjesseb 	 */
1031*6fec3791Sjesseb 	if (disk_mounted(disk[1])) {
1032*6fec3791Sjesseb 		(void) fprintf(stderr, gettext("Cannot create RAID volume when "
1033*6fec3791Sjesseb 			"secondary disk \"%s\" is mounted.\n"), disk[1]);
1034*6fec3791Sjesseb 		return (INVALID_ARG);
1035*6fec3791Sjesseb 	}
1036*6fec3791Sjesseb 
1037*6fec3791Sjesseb 	/*
10387c478bd9Sstevel@tonic-gate 	 * Format the channel string for the other channel so we can
1039*6fec3791Sjesseb 	 * see if a raid exists on it.  In this case if we are being
1040*6fec3791Sjesseb 	 * asked to create a raid on channel 2 (indicated by the 1,1
1041*6fec3791Sjesseb 	 * at the end of the string) we want to check channel 1),
1042*6fec3791Sjesseb 	 * otherwise we will check channel 2.
10437c478bd9Sstevel@tonic-gate 	 */
10447c478bd9Sstevel@tonic-gate 	if (channel2[size - 2] == ',') {
10457c478bd9Sstevel@tonic-gate 		channel2[size - 1] = 0;
10467c478bd9Sstevel@tonic-gate 		channel2[size - 2] = 0;
1047*6fec3791Sjesseb 		(void) snprintf(channel2, sizeof (channel2),
1048*6fec3791Sjesseb 				"%s:devctl", channel2);
10497c478bd9Sstevel@tonic-gate 	} else {
1050*6fec3791Sjesseb 		(void) snprintf(channel2, sizeof (channel2),
1051*6fec3791Sjesseb 				"%s,1:devctl", channel2);
10527c478bd9Sstevel@tonic-gate 	}
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 	fd2 = open(channel2, O_RDONLY);
10557c478bd9Sstevel@tonic-gate 	if (fd2 == -1) {
10567c478bd9Sstevel@tonic-gate 		if (errno == ENOENT)
10577c478bd9Sstevel@tonic-gate 			goto no_secondary_channel;
10587c478bd9Sstevel@tonic-gate 		perror(channel2);
1059*6fec3791Sjesseb 		goto fail;
10607c478bd9Sstevel@tonic-gate 	}
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	if (ioctl(fd2, RAID_GETCONFIG, &config) < 0) {
1063*6fec3791Sjesseb 		goto fail;
10647c478bd9Sstevel@tonic-gate 	}
10657c478bd9Sstevel@tonic-gate 
10668ba1bcfcSdduvall 	if (config.ndisks != 0) {
10677c478bd9Sstevel@tonic-gate 		int	cx;
10687c478bd9Sstevel@tonic-gate 		cx = get_controller(channel2);
1069*6fec3791Sjesseb 		(void) printf(gettext("RAID Volume already exists "
1070*6fec3791Sjesseb 			"on this controller 'c%dt%dd0'\n"), cx,
1071*6fec3791Sjesseb 			config.targetid);
1072*6fec3791Sjesseb 		goto fail;
10737c478bd9Sstevel@tonic-gate 	}
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate no_secondary_channel:
10767c478bd9Sstevel@tonic-gate 
1077*6fec3791Sjesseb 	/* all checks complete, fill in the config */
1078*6fec3791Sjesseb 	newvol.targetid = t[0];
1079*6fec3791Sjesseb 	newvol.disk[0] = t[0];
1080*6fec3791Sjesseb 	newvol.raid_level = rlevel;
1081*6fec3791Sjesseb 	newvol.ndisks = ndisks;
1082*6fec3791Sjesseb 	newvol.raid_capacity = capacity;
10837c478bd9Sstevel@tonic-gate 
1084*6fec3791Sjesseb 	/* populate config.disk, and unconfigure all disks, except targetid */
1085*6fec3791Sjesseb 	for (i = 1; i < ndisks; i++) {
10867c478bd9Sstevel@tonic-gate 		if (do_config_change_state(CFGA_CMD_UNCONFIGURE,
1087*6fec3791Sjesseb 		    t[i], c[0])) {
10887c478bd9Sstevel@tonic-gate 			perror("config_change_state");
1089*6fec3791Sjesseb 			goto fail;
1090*6fec3791Sjesseb 		}
1091*6fec3791Sjesseb 		newvol.disk[i] = t[i];
10927c478bd9Sstevel@tonic-gate 	}
10937c478bd9Sstevel@tonic-gate 
1094*6fec3791Sjesseb 	if (ioctl(fd, RAID_CREATE, &newvol)) {
1095*6fec3791Sjesseb 		/* reconfigure all disks, except targetid */
1096*6fec3791Sjesseb 		for (i = 1; i < ndisks; i++) {
10977c478bd9Sstevel@tonic-gate 			(void) do_config_change_state(CFGA_CMD_CONFIGURE,
1098*6fec3791Sjesseb 				newvol.disk[i], c[0]);
1099*6fec3791Sjesseb 		}
11007c478bd9Sstevel@tonic-gate 		raidctl_error("RAID_CREATE");
1101*6fec3791Sjesseb 		goto fail;
11027c478bd9Sstevel@tonic-gate 	}
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 	(void) printf(gettext("Volume 'c%dt%dd0' created\n"), c[0], t[0]);
11057c478bd9Sstevel@tonic-gate 	(void) close(fd);
11067c478bd9Sstevel@tonic-gate 	(void) close(fd2);
11077c478bd9Sstevel@tonic-gate 	return (SUCCESS);
11087c478bd9Sstevel@tonic-gate 
1109*6fec3791Sjesseb fail:
11108ba1bcfcSdduvall 	(void) close(fd);
1111*6fec3791Sjesseb 	(void) close(fd2);
11127c478bd9Sstevel@tonic-gate 	return (FAILURE);
11137c478bd9Sstevel@tonic-gate }
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate static int
1116*6fec3791Sjesseb do_delete(char *d, int force)
11177c478bd9Sstevel@tonic-gate {
11188ba1bcfcSdduvall 	raid_config_t	config;
11197c478bd9Sstevel@tonic-gate 	char		disk1[MAXPATHLEN];
11207c478bd9Sstevel@tonic-gate 	char		buf[MAXPATHLEN];
11217c478bd9Sstevel@tonic-gate 	int		fd;
11227c478bd9Sstevel@tonic-gate 	int		target;
11237c478bd9Sstevel@tonic-gate 	int		ctrl;
1124*6fec3791Sjesseb 	int		i, j;
1125*6fec3791Sjesseb 	int		wrong_targ = 0;
1126*6fec3791Sjesseb 	int		nvols;
11277c478bd9Sstevel@tonic-gate 	uint8_t		t;
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	(void) chdir(DEVDIR);
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate 	if ((sscanf(d, "c%dt%dd0", &ctrl, &target)) != 2) {
11327c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Invalid disk format.\n"));
11337c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
11347c478bd9Sstevel@tonic-gate 	}
11357c478bd9Sstevel@tonic-gate 	t = (uint8_t)target;
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate 	(void) snprintf(disk1, sizeof (disk1), DEVDIR"/%ss2", d);
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 	if (get_devctl(disk1, buf) != 0) {
1140*6fec3791Sjesseb 		(void) fprintf(stderr, gettext("Not a volume '%s'\n"), d);
11417c478bd9Sstevel@tonic-gate 		return (FAILURE);
11427c478bd9Sstevel@tonic-gate 	}
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 	fd = open(buf, O_RDONLY);
11457c478bd9Sstevel@tonic-gate 	if (fd == -1) {
11467c478bd9Sstevel@tonic-gate 		perror(buf);
11477c478bd9Sstevel@tonic-gate 		return (FAILURE);
11487c478bd9Sstevel@tonic-gate 	}
11497c478bd9Sstevel@tonic-gate 
1150*6fec3791Sjesseb 	if (ioctl(fd, RAID_NUMVOLUMES, &nvols)) {
1151*6fec3791Sjesseb 		raidctl_error("RAID_NUMVOLUMES");
1152*6fec3791Sjesseb 		goto fail;
1153*6fec3791Sjesseb 	}
1154*6fec3791Sjesseb 
1155*6fec3791Sjesseb 	for (i = 0; i < nvols; i++) {
1156*6fec3791Sjesseb 		config.unitid = i;
11577c478bd9Sstevel@tonic-gate 		if (ioctl(fd, RAID_GETCONFIG, &config)) {
11587c478bd9Sstevel@tonic-gate 			raidctl_error("RAID_GETCONFIG");
11597c478bd9Sstevel@tonic-gate 			goto fail;
11607c478bd9Sstevel@tonic-gate 		}
1161*6fec3791Sjesseb 		if (config.ndisks != 0) {
1162*6fec3791Sjesseb 			/* there is a RAID volume in this slot */
1163*6fec3791Sjesseb 			if (config.targetid != t) {
1164*6fec3791Sjesseb 				wrong_targ++;
1165*6fec3791Sjesseb 				continue;
1166*6fec3791Sjesseb 			}
1167*6fec3791Sjesseb 			/* and it's our target */
1168*6fec3791Sjesseb 			break;
1169*6fec3791Sjesseb 		}
1170*6fec3791Sjesseb 	}
11717c478bd9Sstevel@tonic-gate 
1172*6fec3791Sjesseb 	if (i == nvols) {
1173*6fec3791Sjesseb 		/* we found no RAID volumes */
1174*6fec3791Sjesseb 		(void) fprintf(stderr, gettext("No RAID volumes exist on "
11757c478bd9Sstevel@tonic-gate 			"controller '%d'\n"), ctrl);
11767c478bd9Sstevel@tonic-gate 		goto fail;
11777c478bd9Sstevel@tonic-gate 	}
11787c478bd9Sstevel@tonic-gate 
1179*6fec3791Sjesseb 	if (wrong_targ == nvols) {
1180*6fec3791Sjesseb 		/* we found RAID volumes, but none matched */
11817c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
11827c478bd9Sstevel@tonic-gate 			gettext("RAID volume 'c%dt%dd0' does not exist\n"),
11837c478bd9Sstevel@tonic-gate 			ctrl, t);
11847c478bd9Sstevel@tonic-gate 		goto fail;
11857c478bd9Sstevel@tonic-gate 	}
11867c478bd9Sstevel@tonic-gate 
1187*6fec3791Sjesseb 	/* if this volume is a stripe, all data will be lost */
1188*6fec3791Sjesseb 	if (config.raid_level == RAID_STRIPE) {
1189*6fec3791Sjesseb 		if (disk_mounted(d)) {
1190*6fec3791Sjesseb 			(void) fprintf(stderr, gettext("Cannot delete "
1191*6fec3791Sjesseb 				"RAID0 volume, \"%s\" is mounted.\n"), d);
1192*6fec3791Sjesseb 			return (INVALID_ARG);
1193*6fec3791Sjesseb 		}
1194*6fec3791Sjesseb 
1195*6fec3791Sjesseb 		if (!force) {
1196*6fec3791Sjesseb 			(void) fprintf(stderr, gettext("Deleting volume "
1197*6fec3791Sjesseb 				"c%dt%dd0 will destroy all data it contains, "
1198*6fec3791Sjesseb 				"proceed (%s/%s)? "), ctrl, t, yeschr, nochr);
1199*6fec3791Sjesseb 			if (!yes()) {
1200*6fec3791Sjesseb 				(void) fprintf(stderr, gettext("RAID volume "
1201*6fec3791Sjesseb 					"c%dt%dd0 not deleted.\n\n"), ctrl, t);
1202*6fec3791Sjesseb 				(void) close(fd);
1203*6fec3791Sjesseb 				return (SUCCESS);
1204*6fec3791Sjesseb 			}
1205*6fec3791Sjesseb 		}
1206*6fec3791Sjesseb 	}
1207*6fec3791Sjesseb 
12087c478bd9Sstevel@tonic-gate 	if (ioctl(fd, RAID_DELETE, &t)) {
12097c478bd9Sstevel@tonic-gate 		perror("RAID_DELETE");
12107c478bd9Sstevel@tonic-gate 		goto fail;
12117c478bd9Sstevel@tonic-gate 	}
12127c478bd9Sstevel@tonic-gate 
1213*6fec3791Sjesseb 	/* reconfigure all disks, except targetid */
1214*6fec3791Sjesseb 	for (j = 1; j < config.ndisks; j++) {
1215*6fec3791Sjesseb 		(void) do_config_change_state(CFGA_CMD_CONFIGURE,
1216*6fec3791Sjesseb 			config.disk[j], ctrl);
1217*6fec3791Sjesseb 	}
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("Volume 'c%dt%dd0' deleted.\n"),
12207c478bd9Sstevel@tonic-gate 		ctrl, target);
12217c478bd9Sstevel@tonic-gate 	(void) close(fd);
12227c478bd9Sstevel@tonic-gate 	return (SUCCESS);
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate fail:
12257c478bd9Sstevel@tonic-gate 	(void) close(fd);
12267c478bd9Sstevel@tonic-gate 	return (FAILURE);
12277c478bd9Sstevel@tonic-gate }
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate static int
12307c478bd9Sstevel@tonic-gate getfcodever(uint8_t *rombuf, uint32_t nbytes, char **fcodeversion)
12317c478bd9Sstevel@tonic-gate {
12327c478bd9Sstevel@tonic-gate 	int x, y, size;
12337c478bd9Sstevel@tonic-gate 	int found_1 = 0, found_2 = 0;
12347c478bd9Sstevel@tonic-gate 	int image_length = 0;
12357c478bd9Sstevel@tonic-gate 	int no_of_images = 0;
12367c478bd9Sstevel@tonic-gate 	uint8_t *rombuf_1 = NULL;
12377c478bd9Sstevel@tonic-gate 	uint16_t image_units = 0;
12387c478bd9Sstevel@tonic-gate 
12397c478bd9Sstevel@tonic-gate 	/*
12407c478bd9Sstevel@tonic-gate 	 * Single Image - Open firmware image
12417c478bd9Sstevel@tonic-gate 	 */
12427c478bd9Sstevel@tonic-gate 	if (rombuf[gw(&rombuf[PCIR_OFF]) + PCIR_CODETYPE] == 1) {
12437c478bd9Sstevel@tonic-gate 		rombuf_1 = rombuf + gw(rombuf + PCIR_OFF) + PCI_PDS_INDICATOR;
12447c478bd9Sstevel@tonic-gate 		no_of_images = 1;
12457c478bd9Sstevel@tonic-gate 		goto process_image;
12467c478bd9Sstevel@tonic-gate 	}
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate 	/*
12497c478bd9Sstevel@tonic-gate 	 * Combined Image - First Image - x86/PC-AT Bios image
12507c478bd9Sstevel@tonic-gate 	 */
12517c478bd9Sstevel@tonic-gate 	if (rombuf[gw(&rombuf[PCIR_OFF]) + PCIR_CODETYPE] != 0) {
12527c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("This is neither open image"
12537c478bd9Sstevel@tonic-gate 			    " nor Bios/Fcode combined image\n"));
12547c478bd9Sstevel@tonic-gate 		return (1);
12557c478bd9Sstevel@tonic-gate 	}
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate 	/*
12587c478bd9Sstevel@tonic-gate 	 * Seek to 2nd Image
12597c478bd9Sstevel@tonic-gate 	 */
12607c478bd9Sstevel@tonic-gate 	rombuf_1 = rombuf + gw(rombuf + PCI_ROM_PCI_DATA_STRUCT_PTR);
12617c478bd9Sstevel@tonic-gate 	image_units = gw(rombuf_1 + PCI_PDS_IMAGE_LENGTH);
12627c478bd9Sstevel@tonic-gate 	image_length = image_units * PCI_IMAGE_UNIT_SIZE;
12637c478bd9Sstevel@tonic-gate 	rombuf_1 += image_length;
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate 	/*
12667c478bd9Sstevel@tonic-gate 	 * Combined Image - Second Image - Open Firmware image
12677c478bd9Sstevel@tonic-gate 	 */
12687c478bd9Sstevel@tonic-gate 	if (rombuf_1[PCI_PDS_CODE_TYPE] != 1) {
12697c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("This is neither open image"
12707c478bd9Sstevel@tonic-gate 			    " nor Bios/Fcode combined image\n"));
12717c478bd9Sstevel@tonic-gate 		return (1);
12727c478bd9Sstevel@tonic-gate 	}
12737c478bd9Sstevel@tonic-gate 	rombuf_1 += PCI_PDS_INDICATOR;
12747c478bd9Sstevel@tonic-gate 	no_of_images = 2;
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate process_image:
12777c478bd9Sstevel@tonic-gate 	/*
12787c478bd9Sstevel@tonic-gate 	 * This should be the last image
12797c478bd9Sstevel@tonic-gate 	 */
12807c478bd9Sstevel@tonic-gate 	if (*rombuf_1 != LAST_IMAGE) {
12817c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("This is not a valid "
12827c478bd9Sstevel@tonic-gate 		    "Bios/Fcode image file\n"));
12837c478bd9Sstevel@tonic-gate 		return (1);
12847c478bd9Sstevel@tonic-gate 	}
12857c478bd9Sstevel@tonic-gate 
12867c478bd9Sstevel@tonic-gate 	/*
12877c478bd9Sstevel@tonic-gate 	 * Scan through the bois/fcode file to get the fcode version
12887c478bd9Sstevel@tonic-gate 	 * 0x12 and 0x7 indicate the start of the fcode version string
12897c478bd9Sstevel@tonic-gate 	 */
12907c478bd9Sstevel@tonic-gate 	for (x = 0; x < (nbytes - 8); x++) {
12917c478bd9Sstevel@tonic-gate 		if ((rombuf[x] == FCODE_VERS_KEY1) &&
12927c478bd9Sstevel@tonic-gate 		    (rombuf[x+1] == FCODE_VERS_KEY2) &&
12937c478bd9Sstevel@tonic-gate 		    (rombuf[x+2] == 'v') && (rombuf[x+3] == 'e') &&
12947c478bd9Sstevel@tonic-gate 		    (rombuf[x+4] == 'r') && (rombuf[x+5] == 's') &&
12957c478bd9Sstevel@tonic-gate 		    (rombuf[x+6] == 'i') && (rombuf[x+7] == 'o') &&
12967c478bd9Sstevel@tonic-gate 		    (rombuf[x+8] == 'n')) {
12977c478bd9Sstevel@tonic-gate 			found_1 = 1;
12987c478bd9Sstevel@tonic-gate 			break;
12997c478bd9Sstevel@tonic-gate 		}
13007c478bd9Sstevel@tonic-gate 	}
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate 	/*
13037c478bd9Sstevel@tonic-gate 	 * Store the version string if we have found the beginning of it
13047c478bd9Sstevel@tonic-gate 	 */
13057c478bd9Sstevel@tonic-gate 	if (found_1) {
13067c478bd9Sstevel@tonic-gate 		while (x > 0) {
13077c478bd9Sstevel@tonic-gate 			if (rombuf[--x] == FCODE_VERS_KEY1) {
13087c478bd9Sstevel@tonic-gate 				if (rombuf[x-1] != FCODE_VERS_KEY1) {
13097c478bd9Sstevel@tonic-gate 					x++;
13107c478bd9Sstevel@tonic-gate 				}
13117c478bd9Sstevel@tonic-gate 				break;
13127c478bd9Sstevel@tonic-gate 			}
13137c478bd9Sstevel@tonic-gate 		}
13147c478bd9Sstevel@tonic-gate 		if (x > 0) {
13157c478bd9Sstevel@tonic-gate 			*fcodeversion = (char *)malloc(rombuf[x] + 1);
13167c478bd9Sstevel@tonic-gate 			for (y = 0; y < rombuf[x]; y++) {
13177c478bd9Sstevel@tonic-gate 				(*fcodeversion)[y] = rombuf[x+y+1];
13187c478bd9Sstevel@tonic-gate 			}
13197c478bd9Sstevel@tonic-gate 			(*fcodeversion)[y] = '\0';
13207c478bd9Sstevel@tonic-gate 		} else {
13217c478bd9Sstevel@tonic-gate 			found_1 = 0;
13227c478bd9Sstevel@tonic-gate 		}
13237c478bd9Sstevel@tonic-gate 	}
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate 	/*
13267c478bd9Sstevel@tonic-gate 	 * Scan through the bois/fcode file to get the Bios version
13277c478bd9Sstevel@tonic-gate 	 * "@(#)" string indicates the start of the Bios version string
13287c478bd9Sstevel@tonic-gate 	 * Append this version string, after already existing fcode version.
13297c478bd9Sstevel@tonic-gate 	 */
13307c478bd9Sstevel@tonic-gate 	if (no_of_images == 2) {
13317c478bd9Sstevel@tonic-gate 		for (x = 0; x < (nbytes - 4); x++) {
13327c478bd9Sstevel@tonic-gate 			if ((rombuf[x] == '@') && (rombuf[x+1] == '(') &&
13337c478bd9Sstevel@tonic-gate 			    (rombuf[x+2] == '#') && (rombuf[x+3] == ')')) {
13347c478bd9Sstevel@tonic-gate 				found_2 = 1;
13357c478bd9Sstevel@tonic-gate 				break;
13367c478bd9Sstevel@tonic-gate 			}
13377c478bd9Sstevel@tonic-gate 		}
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate 		if (found_2) {
13407c478bd9Sstevel@tonic-gate 			x += 4;
13417c478bd9Sstevel@tonic-gate 			(*fcodeversion)[y] = '\n';
13427c478bd9Sstevel@tonic-gate 			size = y + strlen((char *)(rombuf + x)) +
13437c478bd9Sstevel@tonic-gate 			    strlen(BIOS_STR) + 2;
13447c478bd9Sstevel@tonic-gate 			*fcodeversion = (char *)realloc((*fcodeversion), size);
13457c478bd9Sstevel@tonic-gate 			y++;
13467c478bd9Sstevel@tonic-gate 			(*fcodeversion)[y] = '\0';
13477c478bd9Sstevel@tonic-gate 			(void) strlcat(*fcodeversion, BIOS_STR, size);
13487c478bd9Sstevel@tonic-gate 			(void) strlcat(*fcodeversion, (char *)(rombuf + x),
13497c478bd9Sstevel@tonic-gate 			    size);
13507c478bd9Sstevel@tonic-gate 		}
13517c478bd9Sstevel@tonic-gate 	}
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 	return ((found_1 || found_2) ? 0 : 1);
13547c478bd9Sstevel@tonic-gate }
13557c478bd9Sstevel@tonic-gate 
13567c478bd9Sstevel@tonic-gate static void
13577c478bd9Sstevel@tonic-gate getfwver(uint8_t *rombuf, char *fwversion)
13587c478bd9Sstevel@tonic-gate {
13597c478bd9Sstevel@tonic-gate 	(void) snprintf(fwversion, 8, "%d.%.2d.%.2d.%.2d",
13607c478bd9Sstevel@tonic-gate 		rombuf[FW_ROM_OFFSET_VERSION + 3],
13617c478bd9Sstevel@tonic-gate 		rombuf[FW_ROM_OFFSET_VERSION + 2],
13627c478bd9Sstevel@tonic-gate 		rombuf[FW_ROM_OFFSET_VERSION + 1],
13637c478bd9Sstevel@tonic-gate 		rombuf[FW_ROM_OFFSET_VERSION + 0]);
13647c478bd9Sstevel@tonic-gate }
13657c478bd9Sstevel@tonic-gate 
13667c478bd9Sstevel@tonic-gate static int
13677c478bd9Sstevel@tonic-gate checkfile(uint8_t *rombuf, uint32_t nbytes, uint32_t chksum, int *imagetype)
13687c478bd9Sstevel@tonic-gate {
13697c478bd9Sstevel@tonic-gate 	char *imageversion = NULL;
13707c478bd9Sstevel@tonic-gate 	char *fwversion;
13717c478bd9Sstevel@tonic-gate 
13727c478bd9Sstevel@tonic-gate 	fwversion = (char *)malloc(8);
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate 	if (gw(&rombuf[0]) == PCIROM_SIG) {
13757c478bd9Sstevel@tonic-gate 		/* imageversion is malloc(2)'ed in getfcodever() */
13767c478bd9Sstevel@tonic-gate 		if (getfcodever(rombuf, nbytes, &imageversion) == 0) {
13777c478bd9Sstevel@tonic-gate 			*imagetype = FCODE_IMAGE;
13787c478bd9Sstevel@tonic-gate 		} else {
13797c478bd9Sstevel@tonic-gate 			*imagetype = UNKNOWN_IMAGE;
13807c478bd9Sstevel@tonic-gate 		}
13817c478bd9Sstevel@tonic-gate 		if (*imagetype != UNKNOWN_IMAGE) {
13827c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Image file contains:\n%s\n"),
13837c478bd9Sstevel@tonic-gate 			    imageversion);
13847c478bd9Sstevel@tonic-gate 			free(imageversion);
13857c478bd9Sstevel@tonic-gate 		} else {
13867c478bd9Sstevel@tonic-gate 			if (imageversion != NULL) {
13877c478bd9Sstevel@tonic-gate 				free(imageversion);
13887c478bd9Sstevel@tonic-gate 			}
13897c478bd9Sstevel@tonic-gate 			return (-1);
13907c478bd9Sstevel@tonic-gate 		}
13917c478bd9Sstevel@tonic-gate 	} else if (gw(&rombuf[3]) == FW_ROM_ID) {
13927c478bd9Sstevel@tonic-gate 			if (chksum != 0) {
13937c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
13947c478bd9Sstevel@tonic-gate 					gettext("The ROM checksum appears bad "
13957c478bd9Sstevel@tonic-gate 					"(%d)\n"), chksum);
13967c478bd9Sstevel@tonic-gate 				return (-1);
13977c478bd9Sstevel@tonic-gate 			}
13987c478bd9Sstevel@tonic-gate 			getfwver(rombuf, fwversion);
13997c478bd9Sstevel@tonic-gate 
14007c478bd9Sstevel@tonic-gate 			if ((gw(&rombuf[FW_ROM_OFFSET_CHIP_TYPE]) &
14017c478bd9Sstevel@tonic-gate 				MPI_FW_HEADER_PID_PROD_MASK) ==
14027c478bd9Sstevel@tonic-gate 				MPI_FW_HEADER_PID_PROD_IM_SCSI) {
14037c478bd9Sstevel@tonic-gate 				(void) printf(gettext("ROM image contains "
14047c478bd9Sstevel@tonic-gate 					"MPT firmware version %s "
14057c478bd9Sstevel@tonic-gate 					"(w/Integrated Mirroring)\n"),
14067c478bd9Sstevel@tonic-gate 						fwversion);
14077c478bd9Sstevel@tonic-gate 			} else {
14087c478bd9Sstevel@tonic-gate 				(void) printf(gettext("ROM image contains "
14097c478bd9Sstevel@tonic-gate 					"MPT firmware ""version %s\n"),
14107c478bd9Sstevel@tonic-gate 						fwversion);
14117c478bd9Sstevel@tonic-gate 			}
14127c478bd9Sstevel@tonic-gate 			free(fwversion);
14137c478bd9Sstevel@tonic-gate 	} else {
14147c478bd9Sstevel@tonic-gate 
14157c478bd9Sstevel@tonic-gate #ifdef	DEBUG
14167c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "Not valid FCODE image %x\n", gw(&rombuf[0]));
14177c478bd9Sstevel@tonic-gate #else
14187c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("Not valid FCODE image\n"));
14197c478bd9Sstevel@tonic-gate #endif
14207c478bd9Sstevel@tonic-gate 		return (-1);
14217c478bd9Sstevel@tonic-gate 	}
14227c478bd9Sstevel@tonic-gate 	return (0);
14237c478bd9Sstevel@tonic-gate }
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate static int
14267c478bd9Sstevel@tonic-gate updateflash(uint8_t *rombuf, uint32_t nbytes, char *devctl)
14277c478bd9Sstevel@tonic-gate {
14287c478bd9Sstevel@tonic-gate 	int fd = 0;
14297c478bd9Sstevel@tonic-gate 	update_flash_t flashdata;
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 	fd = open(devctl, O_RDONLY);
14327c478bd9Sstevel@tonic-gate 	if (fd == -1) {
14337c478bd9Sstevel@tonic-gate 		perror(devctl);
14347c478bd9Sstevel@tonic-gate 		return (-1);
14357c478bd9Sstevel@tonic-gate 	}
14367c478bd9Sstevel@tonic-gate 	(void) memset(&flashdata, 0, sizeof (flashdata));
14377c478bd9Sstevel@tonic-gate 	flashdata.ptrbuffer = (caddr_t)rombuf;
14387c478bd9Sstevel@tonic-gate 	flashdata.size = nbytes;
14397c478bd9Sstevel@tonic-gate 	if ((rombuf[0] == 0x55) && (rombuf[1] == 0xaa)) {
14407c478bd9Sstevel@tonic-gate 		flashdata.type = FW_TYPE_FCODE;
14417c478bd9Sstevel@tonic-gate 	} else {
14427c478bd9Sstevel@tonic-gate 		flashdata.type = FW_TYPE_UCODE;
14437c478bd9Sstevel@tonic-gate 	}
14447c478bd9Sstevel@tonic-gate 
14457c478bd9Sstevel@tonic-gate 	if (ioctl(fd, RAID_UPDATEFW, &flashdata)) {
14467c478bd9Sstevel@tonic-gate 		raidctl_error("RAID_UPDATEFW");
14477c478bd9Sstevel@tonic-gate 		(void) close(fd);
14487c478bd9Sstevel@tonic-gate 		return (-1);
14497c478bd9Sstevel@tonic-gate 	}
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 	(void) close(fd);
14527c478bd9Sstevel@tonic-gate 	return (0);
14537c478bd9Sstevel@tonic-gate }
14547c478bd9Sstevel@tonic-gate 
14557c478bd9Sstevel@tonic-gate static int
14567c478bd9Sstevel@tonic-gate readfile(char *filespec, uint8_t **rombuf, uint32_t *nbytes, uint32_t *chksum)
14577c478bd9Sstevel@tonic-gate {
14587c478bd9Sstevel@tonic-gate 	struct stat	statbuf;
14597c478bd9Sstevel@tonic-gate 	uint32_t	count;
14607c478bd9Sstevel@tonic-gate 	uint32_t	checksum = 0;
14617c478bd9Sstevel@tonic-gate 	int		fd, i;
14627c478bd9Sstevel@tonic-gate 	uint8_t		*filebuf;
14637c478bd9Sstevel@tonic-gate 
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate 	if ((fd = open((const char *)filespec, O_RDONLY | O_NDELAY)) == -1) {
14667c478bd9Sstevel@tonic-gate 		perror(filespec);
14677c478bd9Sstevel@tonic-gate 		return (-1);
14687c478bd9Sstevel@tonic-gate 	}
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate 	if (fstat(fd, &statbuf) != 0) {
14717c478bd9Sstevel@tonic-gate 		perror("fstat");
14727c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
14737c478bd9Sstevel@tonic-gate 			gettext("Error getting stats on file\n"));
14747c478bd9Sstevel@tonic-gate 		(void) close(fd);
14757c478bd9Sstevel@tonic-gate 		return (-1);
14767c478bd9Sstevel@tonic-gate 	}
14777c478bd9Sstevel@tonic-gate 
14787c478bd9Sstevel@tonic-gate #ifdef	DEBUG
14797c478bd9Sstevel@tonic-gate 	(void) printf("Filesize = %ld\n", statbuf.st_size);
14807c478bd9Sstevel@tonic-gate #endif
14817c478bd9Sstevel@tonic-gate 
14827c478bd9Sstevel@tonic-gate 	filebuf = (uint8_t *)realloc(*rombuf, statbuf.st_size + *nbytes);
14837c478bd9Sstevel@tonic-gate 
14847c478bd9Sstevel@tonic-gate 	count = read(fd, filebuf + *nbytes, statbuf.st_size);
14857c478bd9Sstevel@tonic-gate 	(void) close(fd);
14867c478bd9Sstevel@tonic-gate 	if (count != statbuf.st_size) {
14877c478bd9Sstevel@tonic-gate 		perror("size check");
14887c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("File is corrupt\n"));
14897c478bd9Sstevel@tonic-gate 		return (-1);
14907c478bd9Sstevel@tonic-gate 	}
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate 	for (i = 0; i < *nbytes; i++)
14937c478bd9Sstevel@tonic-gate 		checksum += filebuf[i] << (8 * (i & 3));
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate 	*rombuf = filebuf;
14967c478bd9Sstevel@tonic-gate 	*nbytes = *nbytes + count;
14977c478bd9Sstevel@tonic-gate 	*chksum = checksum;
14987c478bd9Sstevel@tonic-gate 
14997c478bd9Sstevel@tonic-gate 	return (0);
15007c478bd9Sstevel@tonic-gate }
15017c478bd9Sstevel@tonic-gate 
15027c478bd9Sstevel@tonic-gate static int
1503*6fec3791Sjesseb yes(void)
15047c478bd9Sstevel@tonic-gate {
15057c478bd9Sstevel@tonic-gate 	int	i, b;
15067c478bd9Sstevel@tonic-gate 	char    ans[SCHAR_MAX + 1];
15077c478bd9Sstevel@tonic-gate 
15087c478bd9Sstevel@tonic-gate 	for (i = 0; ; i++) {
15097c478bd9Sstevel@tonic-gate 		b = getchar();
15107c478bd9Sstevel@tonic-gate 		if (b == '\n' || b == '\0' || b == EOF) {
15117c478bd9Sstevel@tonic-gate 			ans[i] = 0;
15127c478bd9Sstevel@tonic-gate 			break;
15137c478bd9Sstevel@tonic-gate 		}
15147c478bd9Sstevel@tonic-gate 		if (i < SCHAR_MAX)
15157c478bd9Sstevel@tonic-gate 			ans[i] = b;
15167c478bd9Sstevel@tonic-gate 	}
15177c478bd9Sstevel@tonic-gate 	if (i >= SCHAR_MAX) {
15187c478bd9Sstevel@tonic-gate 		i = SCHAR_MAX;
15197c478bd9Sstevel@tonic-gate 		ans[SCHAR_MAX] = 0;
15207c478bd9Sstevel@tonic-gate 	}
1521*6fec3791Sjesseb 	if ((i != 0) && ((strncmp(yeschr, ans, i)) == 0))
15227c478bd9Sstevel@tonic-gate 		return (1);
1523*6fec3791Sjesseb 
15247c478bd9Sstevel@tonic-gate 	return (0);
15257c478bd9Sstevel@tonic-gate }
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate static int
15287c478bd9Sstevel@tonic-gate do_flash(int c, char *fpath, int force)
15297c478bd9Sstevel@tonic-gate {
15307c478bd9Sstevel@tonic-gate 	char		devctl[MAXPATHLEN] = {0};
15317c478bd9Sstevel@tonic-gate 	char		buf[MAXPATHLEN] = {0};
15327c478bd9Sstevel@tonic-gate 	int		rv = 0;
15337c478bd9Sstevel@tonic-gate 	int		imagetype;
15347c478bd9Sstevel@tonic-gate 	uint32_t	nbytes = 0;
15357c478bd9Sstevel@tonic-gate 	uint32_t	chksum;
15367c478bd9Sstevel@tonic-gate 	uint8_t		*rombuf = NULL;
15377c478bd9Sstevel@tonic-gate 	char		cwd[MAXPATHLEN];
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate 	/*
15407c478bd9Sstevel@tonic-gate 	 * Read fw file
15417c478bd9Sstevel@tonic-gate 	 */
15427c478bd9Sstevel@tonic-gate 	rv = readfile(fpath, &rombuf, &nbytes, &chksum);
15437c478bd9Sstevel@tonic-gate 	if (rv != 0) {
15447c478bd9Sstevel@tonic-gate 		return (FAILURE);
15457c478bd9Sstevel@tonic-gate 	}
15467c478bd9Sstevel@tonic-gate 
15477c478bd9Sstevel@tonic-gate 	(void) getcwd(cwd, sizeof (cwd));
15487c478bd9Sstevel@tonic-gate 
15497c478bd9Sstevel@tonic-gate 	(void) chdir(DEVDIR);
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate 	/* Get link from "/dev/cfg" */
15527c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "/dev/cfg/c%d", c);
15537c478bd9Sstevel@tonic-gate 	if (get_link_path(buf, devctl) != 0) {
15547c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
15557c478bd9Sstevel@tonic-gate 			gettext("Invalid controller '%d'\n"), c);
15567c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
15577c478bd9Sstevel@tonic-gate 	}
15587c478bd9Sstevel@tonic-gate 
15597c478bd9Sstevel@tonic-gate 	/* Check File */
15607c478bd9Sstevel@tonic-gate 	rv = checkfile(rombuf, nbytes, chksum, &imagetype);
15617c478bd9Sstevel@tonic-gate 	if (rv != 0) {
15627c478bd9Sstevel@tonic-gate 		return (FAILURE);
15637c478bd9Sstevel@tonic-gate 	}
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate 	/* Confirm */
15667c478bd9Sstevel@tonic-gate 	if (!force) {
15677c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Update flash image on "
15687c478bd9Sstevel@tonic-gate 			"controller %d (%s/%s)? "), c, yeschr, nochr);
1569*6fec3791Sjesseb 		if (!yes()) {
1570*6fec3791Sjesseb 			(void) fprintf(stderr, gettext("Controller %d not "
1571*6fec3791Sjesseb 			    "flashed.\n\n"), c);
15727c478bd9Sstevel@tonic-gate 			return (SUCCESS);
15737c478bd9Sstevel@tonic-gate 		}
15747c478bd9Sstevel@tonic-gate 	}
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate 	/* Do Flash */
15777c478bd9Sstevel@tonic-gate 	if (updateflash(rombuf, nbytes, devctl)) {
15787c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Flash not updated on "
15797c478bd9Sstevel@tonic-gate 		    "Controller %d.\n\n"), c);
15807c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
15817c478bd9Sstevel@tonic-gate 	}
15827c478bd9Sstevel@tonic-gate 	(void) printf(gettext("Flash updated successfully.\n\n"));
15837c478bd9Sstevel@tonic-gate 	return (SUCCESS);
15847c478bd9Sstevel@tonic-gate }
15857c478bd9Sstevel@tonic-gate 
15867c478bd9Sstevel@tonic-gate static int
15877c478bd9Sstevel@tonic-gate fully_numeric(char *str)
15887c478bd9Sstevel@tonic-gate {
15897c478bd9Sstevel@tonic-gate 	int	size = strlen(str);
15907c478bd9Sstevel@tonic-gate 	int	i;
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate 	for (i = 0; i < size; i++) {
15937c478bd9Sstevel@tonic-gate 		if (i == 0 && str[i] == '-' && size != 1)
15947c478bd9Sstevel@tonic-gate 			continue;
15957c478bd9Sstevel@tonic-gate 		if (!isdigit(str[i]))
15967c478bd9Sstevel@tonic-gate 			return (0);
15977c478bd9Sstevel@tonic-gate 	}
15987c478bd9Sstevel@tonic-gate 	return (1);
15997c478bd9Sstevel@tonic-gate }
16007c478bd9Sstevel@tonic-gate 
16017c478bd9Sstevel@tonic-gate /*
16027c478bd9Sstevel@tonic-gate  * Useful parsing macros
16037c478bd9Sstevel@tonic-gate  */
16047c478bd9Sstevel@tonic-gate #define	must_be(s, c)		if (*s++ != c) return (0)
16057c478bd9Sstevel@tonic-gate #define	skip_digits(s)		while (isdigit(*s)) s++
16067c478bd9Sstevel@tonic-gate 
16077c478bd9Sstevel@tonic-gate /*
16087c478bd9Sstevel@tonic-gate  * Return true if a name is in the internal canonical form
16097c478bd9Sstevel@tonic-gate  */
16107c478bd9Sstevel@tonic-gate static int
16117c478bd9Sstevel@tonic-gate canonical_name(char *name)
16127c478bd9Sstevel@tonic-gate {
16137c478bd9Sstevel@tonic-gate 	must_be(name, 'c');
16147c478bd9Sstevel@tonic-gate 	skip_digits(name);
16157c478bd9Sstevel@tonic-gate 	if (*name == 't') {
16167c478bd9Sstevel@tonic-gate 		name++;
16177c478bd9Sstevel@tonic-gate 		skip_digits(name);
16187c478bd9Sstevel@tonic-gate 	}
16197c478bd9Sstevel@tonic-gate 	must_be(name, 'd');
16207c478bd9Sstevel@tonic-gate 	skip_digits(name);
16217c478bd9Sstevel@tonic-gate 	return (*name == 0);
16227c478bd9Sstevel@tonic-gate }
16237c478bd9Sstevel@tonic-gate 
16247c478bd9Sstevel@tonic-gate int
16257c478bd9Sstevel@tonic-gate main(int argc, char **argv)
16267c478bd9Sstevel@tonic-gate {
16277c478bd9Sstevel@tonic-gate 	int	rv = SUCCESS;
16287c478bd9Sstevel@tonic-gate 	int	i, c;
16297c478bd9Sstevel@tonic-gate 	int	findex = DO_HW_RAID_INFO;
16307c478bd9Sstevel@tonic-gate 	int	controller;
1631*6fec3791Sjesseb 	char	*disks[N_DISKS] = {0};
16327c478bd9Sstevel@tonic-gate 	char	*darg;
16337c478bd9Sstevel@tonic-gate 	char	*farg;
1634*6fec3791Sjesseb 	char	*rarg;
16357c478bd9Sstevel@tonic-gate 	char	*progname;
16367c478bd9Sstevel@tonic-gate 
16377c478bd9Sstevel@tonic-gate 	int	l_flag = 0;
16387c478bd9Sstevel@tonic-gate 	int	c_flag = 0;
16397c478bd9Sstevel@tonic-gate 	int	d_flag = 0;
16407c478bd9Sstevel@tonic-gate 	int	f_flag = 0;
16417c478bd9Sstevel@tonic-gate 	int	F_flag = 0;
1642*6fec3791Sjesseb 	int	r_flag = 0;
16437c478bd9Sstevel@tonic-gate 	int	no_flags = 1;
1644*6fec3791Sjesseb 	int	r = RAID_MIRROR;  /* default raid level is 1 */
16457c478bd9Sstevel@tonic-gate 	char	*current_dir;
16467c478bd9Sstevel@tonic-gate 
16477c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
16487c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
16497c478bd9Sstevel@tonic-gate 
16507c478bd9Sstevel@tonic-gate 	if (geteuid() != 0) {
16517c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Must be root.\n"));
16527c478bd9Sstevel@tonic-gate 		exit(1);
16537c478bd9Sstevel@tonic-gate 	}
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 	if ((progname = strrchr(argv[0], '/')) == NULL)
16567c478bd9Sstevel@tonic-gate 		progname = argv[0];
16577c478bd9Sstevel@tonic-gate 	else
16587c478bd9Sstevel@tonic-gate 		progname++;
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate 	raids = NULL;
16617c478bd9Sstevel@tonic-gate 
16627c478bd9Sstevel@tonic-gate 	(void) strncpy(yeschr, nl_langinfo(YESSTR), SCHAR_MAX + 1);
16637c478bd9Sstevel@tonic-gate 	(void) strncpy(nochr, nl_langinfo(NOSTR), SCHAR_MAX + 1);
16647c478bd9Sstevel@tonic-gate 
1665*6fec3791Sjesseb 	while ((c = getopt(argc, argv, "cr:lfd:F:")) != EOF) {
16667c478bd9Sstevel@tonic-gate 		switch (c) {
16677c478bd9Sstevel@tonic-gate 		case 'c':
1668*6fec3791Sjesseb 			if (argc < 4)
16697c478bd9Sstevel@tonic-gate 				usage(progname);
16707c478bd9Sstevel@tonic-gate 			findex = DO_HW_RAID_CREATE;
16717c478bd9Sstevel@tonic-gate 			c_flag = 1;
16727c478bd9Sstevel@tonic-gate 			no_flags = 0;
16737c478bd9Sstevel@tonic-gate 			break;
1674*6fec3791Sjesseb 		case 'r':
1675*6fec3791Sjesseb 			rarg = optarg;
1676*6fec3791Sjesseb 			r = atoi(rarg);
1677*6fec3791Sjesseb 			if ((r != RAID_STRIPE) && (r != RAID_MIRROR))
1678*6fec3791Sjesseb 				usage(progname);
1679*6fec3791Sjesseb 			r_flag = 1;
1680*6fec3791Sjesseb 			break;
16817c478bd9Sstevel@tonic-gate 		case 'd':
16827c478bd9Sstevel@tonic-gate 			darg = optarg;
16837c478bd9Sstevel@tonic-gate 			d_flag = 1;
16847c478bd9Sstevel@tonic-gate 			findex = DO_HW_RAID_DELETE;
16857c478bd9Sstevel@tonic-gate 			no_flags = 0;
16867c478bd9Sstevel@tonic-gate 			break;
16877c478bd9Sstevel@tonic-gate 		case 'l':
16887c478bd9Sstevel@tonic-gate 			findex = DO_HW_RAID_INFO;
16897c478bd9Sstevel@tonic-gate 			l_flag = 1;
16907c478bd9Sstevel@tonic-gate 			no_flags = 0;
16917c478bd9Sstevel@tonic-gate 			break;
16927c478bd9Sstevel@tonic-gate 		case 'F':
16937c478bd9Sstevel@tonic-gate 			findex = DO_HW_RAID_FLASH;
16947c478bd9Sstevel@tonic-gate 			farg = optarg;
16957c478bd9Sstevel@tonic-gate 			F_flag = 1;
16967c478bd9Sstevel@tonic-gate 			no_flags = 0;
16977c478bd9Sstevel@tonic-gate 			break;
16987c478bd9Sstevel@tonic-gate 		case 'f':
16997c478bd9Sstevel@tonic-gate 			f_flag = 1;
17007c478bd9Sstevel@tonic-gate 			no_flags = 0;
17017c478bd9Sstevel@tonic-gate 			break;
1702*6fec3791Sjesseb 		case '?':
1703*6fec3791Sjesseb 		default:
17047c478bd9Sstevel@tonic-gate 			usage(progname);
17057c478bd9Sstevel@tonic-gate 		}
17067c478bd9Sstevel@tonic-gate 	}
17077c478bd9Sstevel@tonic-gate 
17087c478bd9Sstevel@tonic-gate 	if (no_flags && argc > 1)
17097c478bd9Sstevel@tonic-gate 		usage(progname);
17107c478bd9Sstevel@tonic-gate 
17117c478bd9Sstevel@tonic-gate 	/* compatibility rules */
17127c478bd9Sstevel@tonic-gate 	if (c_flag && d_flag)
17137c478bd9Sstevel@tonic-gate 		usage(progname);
1714*6fec3791Sjesseb 	if (l_flag && (d_flag || c_flag || f_flag || F_flag || r_flag))
17157c478bd9Sstevel@tonic-gate 		usage(progname);
1716*6fec3791Sjesseb 	if (F_flag && (d_flag || c_flag || l_flag || r_flag))
17177c478bd9Sstevel@tonic-gate 		usage(progname);
17187c478bd9Sstevel@tonic-gate 
17197c478bd9Sstevel@tonic-gate 	switch (findex) {
17207c478bd9Sstevel@tonic-gate 	case DO_HW_RAID_INFO:
17217c478bd9Sstevel@tonic-gate 		if (l_flag) {
17227c478bd9Sstevel@tonic-gate 			/*
17237c478bd9Sstevel@tonic-gate 			 * "raidctl"	makes argc == 1
17247c478bd9Sstevel@tonic-gate 			 * "-l"		makes argc == 2
17257c478bd9Sstevel@tonic-gate 			 */
17267c478bd9Sstevel@tonic-gate 			ctrl_nums = argc - 2;
17277c478bd9Sstevel@tonic-gate 			if (ctrl_nums != 0) {
17287c478bd9Sstevel@tonic-gate 				info_ctrl = (int **)
17297c478bd9Sstevel@tonic-gate 					malloc(ctrl_nums * sizeof (int));
17307c478bd9Sstevel@tonic-gate 				if (info_ctrl == NULL)
17317c478bd9Sstevel@tonic-gate 					return (FAILURE);
17327c478bd9Sstevel@tonic-gate 			}
17337c478bd9Sstevel@tonic-gate 			for (i = 0; i < ctrl_nums; i++) {
17347c478bd9Sstevel@tonic-gate 				char *tmp = argv[i + 2];
17357c478bd9Sstevel@tonic-gate 
17367c478bd9Sstevel@tonic-gate 				info_ctrl[i] = (int *)malloc(2 * sizeof (int));
17377c478bd9Sstevel@tonic-gate 				if (info_ctrl[i] == NULL) {
17387c478bd9Sstevel@tonic-gate 					free(info_ctrl);
17397c478bd9Sstevel@tonic-gate 					return (FAILURE);
17407c478bd9Sstevel@tonic-gate 				}
17417c478bd9Sstevel@tonic-gate 				if (fully_numeric(tmp)) {
17427c478bd9Sstevel@tonic-gate 					(void) sscanf(tmp, "%d",
17437c478bd9Sstevel@tonic-gate 						&info_ctrl[i][INFO_CTRL]);
17447c478bd9Sstevel@tonic-gate 					info_ctrl[i][INFO_STATUS] =
17457c478bd9Sstevel@tonic-gate 						RAID_INVALID_CTRL;
17467c478bd9Sstevel@tonic-gate 				} else {
17477c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
17487c478bd9Sstevel@tonic-gate 					gettext("Invalid controller '%s'\n"),
17497c478bd9Sstevel@tonic-gate 					tmp);
17507c478bd9Sstevel@tonic-gate 					info_ctrl[i][INFO_STATUS] =
17517c478bd9Sstevel@tonic-gate 						RAID_DONT_USE;
17527c478bd9Sstevel@tonic-gate 				}
17537c478bd9Sstevel@tonic-gate 			}
17547c478bd9Sstevel@tonic-gate 		} else if (argc > 1) {
17557c478bd9Sstevel@tonic-gate 			usage(progname);
17567c478bd9Sstevel@tonic-gate 		}
17577c478bd9Sstevel@tonic-gate 
17587c478bd9Sstevel@tonic-gate 		do_info();
17597c478bd9Sstevel@tonic-gate 		break;
17607c478bd9Sstevel@tonic-gate 	case DO_HW_RAID_CREATE:
17617c478bd9Sstevel@tonic-gate 		for (i = 0; i < N_DISKS; i++) {
1762*6fec3791Sjesseb 			int p = 2 + (r_flag * 2) + f_flag + i;
1763*6fec3791Sjesseb 
1764*6fec3791Sjesseb 			if (p == argc)
1765*6fec3791Sjesseb 				break;
1766*6fec3791Sjesseb 
1767*6fec3791Sjesseb 			disks[i] = argv[p];
1768*6fec3791Sjesseb 
17697c478bd9Sstevel@tonic-gate 			if (!canonical_name(disks[i]))
17707c478bd9Sstevel@tonic-gate 				usage(progname);
1771*6fec3791Sjesseb 
1772*6fec3791Sjesseb 			/* no more than 2 disks for raid level 1 */
1773*6fec3791Sjesseb 			if ((r == RAID_MIRROR) && (i > 1))
1774*6fec3791Sjesseb 				usage(progname);
17757c478bd9Sstevel@tonic-gate 		}
1776*6fec3791Sjesseb 
1777*6fec3791Sjesseb 		rv = do_create(disks, r, f_flag);
17787c478bd9Sstevel@tonic-gate 		break;
17797c478bd9Sstevel@tonic-gate 	case DO_HW_RAID_DELETE:
17807c478bd9Sstevel@tonic-gate 		if (!canonical_name(darg))
17817c478bd9Sstevel@tonic-gate 			usage(progname);
17827c478bd9Sstevel@tonic-gate 
1783*6fec3791Sjesseb 		rv = do_delete(darg, f_flag);
17847c478bd9Sstevel@tonic-gate 		break;
17857c478bd9Sstevel@tonic-gate 	case DO_HW_RAID_FLASH:
17867c478bd9Sstevel@tonic-gate 		ctrl_nums = argc - f_flag - 3;
17877c478bd9Sstevel@tonic-gate 		if (ctrl_nums == 0)
17887c478bd9Sstevel@tonic-gate 			usage(progname);
17897c478bd9Sstevel@tonic-gate 
17907c478bd9Sstevel@tonic-gate 		current_dir = getcwd(NULL, MAXPATHLEN);
17917c478bd9Sstevel@tonic-gate 
17927c478bd9Sstevel@tonic-gate 		for (i = 0; i < ctrl_nums; i++) {
17937c478bd9Sstevel@tonic-gate 			char *tmp = argv[i + 3 + f_flag];
17947c478bd9Sstevel@tonic-gate 			(void) chdir(current_dir);
17957c478bd9Sstevel@tonic-gate 			if (fully_numeric(tmp)) {
17967c478bd9Sstevel@tonic-gate 				(void) sscanf(tmp, "%d", &controller);
17977c478bd9Sstevel@tonic-gate 				rv = do_flash(controller, farg, f_flag);
17987c478bd9Sstevel@tonic-gate 				if (rv == FAILURE)
17997c478bd9Sstevel@tonic-gate 					break;
18007c478bd9Sstevel@tonic-gate 			} else {
18017c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
18027c478bd9Sstevel@tonic-gate 					gettext("Invalid controller '%s'\n"),
18037c478bd9Sstevel@tonic-gate 					tmp);
18047c478bd9Sstevel@tonic-gate 			}
18057c478bd9Sstevel@tonic-gate 		}
18067c478bd9Sstevel@tonic-gate 		free(current_dir);
18077c478bd9Sstevel@tonic-gate 		break;
18087c478bd9Sstevel@tonic-gate 	default:
18097c478bd9Sstevel@tonic-gate 		usage(progname);
18107c478bd9Sstevel@tonic-gate 	}
18117c478bd9Sstevel@tonic-gate 	return (rv);
18127c478bd9Sstevel@tonic-gate }
1813