xref: /titanic_52/usr/src/cmd/raidctl/raidctl.c (revision 7f0009305822c9b9969a6e87e2c5c63d0615c7ee)
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
5*7f000930Syw161884  * Common Development and Distribution License (the "License").
6*7f000930Syw161884  * 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
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
223a4e43d3Ssafa  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <ctype.h>
297c478bd9Sstevel@tonic-gate #include <dirent.h>
307c478bd9Sstevel@tonic-gate #include <errno.h>
317c478bd9Sstevel@tonic-gate #include <fcntl.h>
327c478bd9Sstevel@tonic-gate #include <langinfo.h>
337c478bd9Sstevel@tonic-gate #include <libintl.h>
347c478bd9Sstevel@tonic-gate #include <limits.h>
357c478bd9Sstevel@tonic-gate #include <locale.h>
367c478bd9Sstevel@tonic-gate #include <stdarg.h>
377c478bd9Sstevel@tonic-gate #include <stdio.h>
387c478bd9Sstevel@tonic-gate #include <stdlib.h>
397c478bd9Sstevel@tonic-gate #include <string.h>
407c478bd9Sstevel@tonic-gate #include <strings.h>
417c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
427c478bd9Sstevel@tonic-gate #include <sys/mpt/mpi.h>
437c478bd9Sstevel@tonic-gate #include <sys/mpt/mpi_ioc.h>
447c478bd9Sstevel@tonic-gate #include <sys/stat.h>
457c478bd9Sstevel@tonic-gate #include <sys/types.h>
467c478bd9Sstevel@tonic-gate #include <sys/pci.h>
477c478bd9Sstevel@tonic-gate #include <unistd.h>
487c478bd9Sstevel@tonic-gate #include <sys/mnttab.h>
497c478bd9Sstevel@tonic-gate #include <sys/dkio.h>
507c478bd9Sstevel@tonic-gate #include <config_admin.h>
517c478bd9Sstevel@tonic-gate #include <sys/param.h>
527c478bd9Sstevel@tonic-gate #include <sys/raidioctl.h>
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate /*
557c478bd9Sstevel@tonic-gate  * list of controllers to list
567c478bd9Sstevel@tonic-gate  * setup like this:
577c478bd9Sstevel@tonic-gate  * [ctrl_num]	[status]
587c478bd9Sstevel@tonic-gate  *
597c478bd9Sstevel@tonic-gate  * where status is:
607c478bd9Sstevel@tonic-gate  * RAID Found,
617c478bd9Sstevel@tonic-gate  * No RAID Found
627c478bd9Sstevel@tonic-gate  * RAID not supported on this controller
637c478bd9Sstevel@tonic-gate  * Invalid Controller
647c478bd9Sstevel@tonic-gate  */
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate typedef enum {
677c478bd9Sstevel@tonic-gate 	RAID_FOUND = 0x0,
687c478bd9Sstevel@tonic-gate 	RAID_NOT_FOUND,
697c478bd9Sstevel@tonic-gate 	RAID_NOT_SUPPORTED,
707c478bd9Sstevel@tonic-gate 	RAID_INVALID_CTRL,
717c478bd9Sstevel@tonic-gate 	RAID_DONT_USE
727c478bd9Sstevel@tonic-gate } raidctl_errno_t;
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate /* For no-mixup indexing of info_ctrl */
757c478bd9Sstevel@tonic-gate #define	INFO_CTRL	0
767c478bd9Sstevel@tonic-gate #define	INFO_STATUS	1
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate static int **info_ctrl = NULL;
797c478bd9Sstevel@tonic-gate /* Length of conrollers list */
807c478bd9Sstevel@tonic-gate static int ctrl_nums = 0;
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate #define	DEVDIR			"/dev/rdsk"
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_NOP		-1
867c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_INFO		0
877c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_CREATE	1
887c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_DELETE	2
897c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_FLASH	3
907c478bd9Sstevel@tonic-gate 
916fec3791Sjesseb /* values to use for raid level in raidctl */
926fec3791Sjesseb #define	RAID_STRIPE		0
936fec3791Sjesseb #define	RAID_MIRROR		1
946fec3791Sjesseb 
957c478bd9Sstevel@tonic-gate /*
967c478bd9Sstevel@tonic-gate  * Error return codes
977c478bd9Sstevel@tonic-gate  */
987c478bd9Sstevel@tonic-gate #define	SUCCESS			0
997c478bd9Sstevel@tonic-gate #define	INVALID_ARG		1
1007c478bd9Sstevel@tonic-gate #define	FAILURE			2
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate /*
1037c478bd9Sstevel@tonic-gate  * FW Update Stuff
1047c478bd9Sstevel@tonic-gate  */
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate /* signature and initial offset for PCI expansion rom images */
1077c478bd9Sstevel@tonic-gate #define	PCIROM_SIG	0xaa55	/* offset 0h, length 2 bytes */
1087c478bd9Sstevel@tonic-gate #define	PCIR_OFF	0x18	/* Pointer to PCI Data Structure */
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate /* offsets in PCI data structure header */
1117c478bd9Sstevel@tonic-gate #define	PCIR_DEVID	0x6	/* PCI device id */
1127c478bd9Sstevel@tonic-gate #define	PCIR_CODETYPE   0x14	/* type of code (intel/fcode) */
1137c478bd9Sstevel@tonic-gate #define	PCIR_INDICATOR  0x15	/* "last image" indicator */
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate /* flags for image types */
1167c478bd9Sstevel@tonic-gate #define	BIOS_IMAGE	0x1
1177c478bd9Sstevel@tonic-gate #define	FCODE_IMAGE	0x2
1187c478bd9Sstevel@tonic-gate #define	UNKNOWN_IMAGE	0x3
1197c478bd9Sstevel@tonic-gate #define	LAST_IMAGE	0x80
1207c478bd9Sstevel@tonic-gate #define	NOT_LAST_IMAGE	0
1217c478bd9Sstevel@tonic-gate #define	PCI_IMAGE_UNIT_SIZE	512
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate /* ID's and offsets for MPT Firmware images */
1247c478bd9Sstevel@tonic-gate #define	FW_ROM_ID			0x5aea	/* bytes 4 & 5 of file */
1257c478bd9Sstevel@tonic-gate #define	FW_ROM_OFFSET_CHIP_TYPE		0x22	/* (U16) */
1267c478bd9Sstevel@tonic-gate #define	FW_ROM_OFFSET_VERSION		0x24	/* (U16) */
1277c478bd9Sstevel@tonic-gate #define	FW_ROM_OFFSET_VERSION_NAME	0x44	/* (32 U8) */
1287c478bd9Sstevel@tonic-gate 
1296fec3791Sjesseb /* ID's for supported chips */
1306fec3791Sjesseb #define	LSI_1030	0x30
1316fec3791Sjesseb #define	LSI_1064	0x50
1326fec3791Sjesseb #define	LSI_1064E	0x56
1336fec3791Sjesseb #define	LSI_1068E	0x58
1346fec3791Sjesseb 
1357c478bd9Sstevel@tonic-gate /* Key to search for when looking for fcode version */
1367c478bd9Sstevel@tonic-gate #define	FCODE_VERS_KEY1		0x12
1377c478bd9Sstevel@tonic-gate #define	FCODE_VERS_KEY2		0x7
138*7f000930Syw161884 #define	BIOS_STR		"LSI SCSI Host Adapter BIOS Driver: "
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate /* get a word from a buffer (works with non-word aligned offsets) */
1417c478bd9Sstevel@tonic-gate #define	gw(x) (((x)[0]) + (((x)[1]) << 8))
1427c478bd9Sstevel@tonic-gate 
1436fec3791Sjesseb /* Number of disks currently supported, per RAID volume */
1446fec3791Sjesseb #define	N_DISKS		8
1456fec3791Sjesseb 
1466fec3791Sjesseb /* Maximum number of RAID volumes currently supported per HBA */
1476fec3791Sjesseb #define	N_RAIDVOLS	2
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate /*
1507c478bd9Sstevel@tonic-gate  * Function and strings to properly localize our prompt.
1517c478bd9Sstevel@tonic-gate  * So for example in german it would ask (ja/nein) or (yes/no) in
1527c478bd9Sstevel@tonic-gate  * english.
1537c478bd9Sstevel@tonic-gate  */
1546fec3791Sjesseb static int	yes(void);
1557c478bd9Sstevel@tonic-gate static char	yeschr[SCHAR_MAX + 2];
1567c478bd9Sstevel@tonic-gate static char	nochr[SCHAR_MAX +2];
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate typedef struct raidlist {
1596fec3791Sjesseb 	raid_config_t	raid_config[N_RAIDVOLS];
1607c478bd9Sstevel@tonic-gate 	int	controller;
1617c478bd9Sstevel@tonic-gate 	char	devctl[MAXPATHLEN];
1627c478bd9Sstevel@tonic-gate 	struct raidlist *next;
1637c478bd9Sstevel@tonic-gate } raidlist_t;
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate static raidlist_t	*raids;
1667c478bd9Sstevel@tonic-gate 
1676fec3791Sjesseb /*
1686fec3791Sjesseb  * usage: raidctl
1696fec3791Sjesseb  * usage: raidctl [-f] -c primary secondary
1706fec3791Sjesseb  * usage: raidctl [-f] -c -r 1 primary secondary
1716fec3791Sjesseb  * usage: raidctl [-f] -c -r 0 disk1 disk2 [disk3] ...
1726fec3791Sjesseb  * usage: raidctl [-f] -d volume
1736fec3791Sjesseb  * usage: raidctl [-f] -F image_file controller
1746fec3791Sjesseb  * usage: raidctl -l [controller...]
1756fec3791Sjesseb  *   example:
1766fec3791Sjesseb  *   raidctl -c c1t1d0 c1t2d0
1776fec3791Sjesseb  *   raidctl -c -r 0 c1t1d0 c1t2d0 c1t3d0 c1t4d0
1786fec3791Sjesseb  *   raidctl -d c1t1d0
1796fec3791Sjesseb  *   raidctl -F image 1
1806fec3791Sjesseb  */
1817c478bd9Sstevel@tonic-gate static void
1827c478bd9Sstevel@tonic-gate usage(char *prog_name)
1837c478bd9Sstevel@tonic-gate {
1847c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("usage: %s\n"), prog_name);
1857c478bd9Sstevel@tonic-gate 
1866fec3791Sjesseb 	(void) fprintf(stderr, gettext("usage: %s [-f] -c primary secondary\n"),
1877c478bd9Sstevel@tonic-gate 		prog_name);
1886fec3791Sjesseb 
1896fec3791Sjesseb 	(void) fprintf(stderr, gettext("usage: %s [-f] -c -r 1 primary "
1906fec3791Sjesseb 		"secondary\n"), prog_name);
1916fec3791Sjesseb 
1926fec3791Sjesseb 	(void) fprintf(stderr, gettext("usage: %s [-f] -c -r 0 disk1 disk2 "
1936fec3791Sjesseb 		"[disk3] ...\n"), prog_name);
1946fec3791Sjesseb 
1956fec3791Sjesseb 	(void) fprintf(stderr, gettext("usage: %s [-f] -d volume\n"),
1966fec3791Sjesseb 		prog_name);
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
1997c478bd9Sstevel@tonic-gate 		gettext("usage: %s [-f] -F image_file controller \n"),
2007c478bd9Sstevel@tonic-gate 		prog_name);
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("usage: %s -l [controller...]\n"),
2037c478bd9Sstevel@tonic-gate 		prog_name);
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("example:\n"));
2067c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s -c c1t1d0 c1t2d0\n", prog_name);
2076fec3791Sjesseb 	(void) fprintf(stderr, "%s -c -r 0 c1t1d0 c1t2d0 "
2086fec3791Sjesseb 		"c1t3d0 c1t4d0\n", prog_name);
2097c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s -d c1t1d0\n", prog_name);
2107c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s -F image 1\n", prog_name);
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	exit(1);
2137c478bd9Sstevel@tonic-gate }
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate /* Make errno message more "user friendly" */
2167c478bd9Sstevel@tonic-gate static void
2177c478bd9Sstevel@tonic-gate raidctl_error(char *str)
2187c478bd9Sstevel@tonic-gate {
2197c478bd9Sstevel@tonic-gate 	switch (errno) {
2203a4e43d3Ssafa 	case EINVAL:
2213a4e43d3Ssafa 		(void) fprintf(stderr, gettext("Error: "
2223a4e43d3Ssafa 			"invalid argument would be returned\n"));
2233a4e43d3Ssafa 		break;
2247c478bd9Sstevel@tonic-gate 	case EIO:
2257c478bd9Sstevel@tonic-gate 	case EFAULT:
2267c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
2277c478bd9Sstevel@tonic-gate 			gettext("Error: Device inaccessible.\n"));
2287c478bd9Sstevel@tonic-gate 		break;
2297c478bd9Sstevel@tonic-gate 	case ENOTTY:
2307c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Error: "
2317c478bd9Sstevel@tonic-gate 			"Device does not support requested action.\n"));
2327c478bd9Sstevel@tonic-gate 		break;
2337c478bd9Sstevel@tonic-gate 	default:
2347c478bd9Sstevel@tonic-gate 		perror(str);
2357c478bd9Sstevel@tonic-gate 	}
2367c478bd9Sstevel@tonic-gate }
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate static int
2397c478bd9Sstevel@tonic-gate get_link_path(const char *thing, char *buf)
2407c478bd9Sstevel@tonic-gate {
2417c478bd9Sstevel@tonic-gate 	if (readlink(thing, buf, MAXPATHLEN) < 0)
2427c478bd9Sstevel@tonic-gate 		return (1);
2437c478bd9Sstevel@tonic-gate 	return (0);
2447c478bd9Sstevel@tonic-gate }
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate static int
2477c478bd9Sstevel@tonic-gate get_ctrl_devctl(char *ctrl, char *b)
2487c478bd9Sstevel@tonic-gate {
2497c478bd9Sstevel@tonic-gate 	char	devctl_buf[MAXPATHLEN];
2507c478bd9Sstevel@tonic-gate 	char	*colon;
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	(void) strlcpy(devctl_buf, ctrl, MAXPATHLEN);
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	colon = strrchr(devctl_buf, ':');
2557c478bd9Sstevel@tonic-gate 	if (colon == NULL)
2567c478bd9Sstevel@tonic-gate 		return (1);
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	*colon = 0;
2597c478bd9Sstevel@tonic-gate 	(void) snprintf(devctl_buf, MAXPATHLEN, "%s:devctl", devctl_buf);
2607c478bd9Sstevel@tonic-gate 	(void) strlcpy(b, devctl_buf, MAXPATHLEN);
2617c478bd9Sstevel@tonic-gate 	return (0);
2627c478bd9Sstevel@tonic-gate }
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate static int
2657c478bd9Sstevel@tonic-gate get_devctl(char *disk, char *b)
2667c478bd9Sstevel@tonic-gate {
2677c478bd9Sstevel@tonic-gate 	char	buf1[MAXPATHLEN] = {0};
2687c478bd9Sstevel@tonic-gate 	char	devctl_buf[MAXPATHLEN];
2697c478bd9Sstevel@tonic-gate 	char	*slash;
2707c478bd9Sstevel@tonic-gate 	char	devname[32];
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	if (get_link_path(disk, buf1))
2737c478bd9Sstevel@tonic-gate 		return (1);
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	(void) strlcpy(devctl_buf, buf1, MAXPATHLEN);
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	slash = strrchr(devctl_buf, '/');
2787c478bd9Sstevel@tonic-gate 	if (slash == NULL)
2797c478bd9Sstevel@tonic-gate 		return (1);
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	*slash = 0;
2827c478bd9Sstevel@tonic-gate 	slash = strrchr(devctl_buf, '/');
2837c478bd9Sstevel@tonic-gate 	(void) strlcpy(devname, slash, 32);
2847c478bd9Sstevel@tonic-gate 	*slash = 0;
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	(void) snprintf(devctl_buf, MAXPATHLEN, "%s%s:devctl",
2877c478bd9Sstevel@tonic-gate 		devctl_buf, devname);
2886fec3791Sjesseb 
2897c478bd9Sstevel@tonic-gate 	(void) strlcpy(b, devctl_buf, MAXPATHLEN);
2906fec3791Sjesseb 
2917c478bd9Sstevel@tonic-gate 	return (0);
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate static int
2957c478bd9Sstevel@tonic-gate already_there(int controller)
2967c478bd9Sstevel@tonic-gate {
2977c478bd9Sstevel@tonic-gate 	raidlist_t	*curr = raids;
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
3007c478bd9Sstevel@tonic-gate 		if (curr->controller == controller)
3017c478bd9Sstevel@tonic-gate 			return (1);
3026fec3791Sjesseb 
3037c478bd9Sstevel@tonic-gate 		curr = curr->next;
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	return (0);
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate /*
3107c478bd9Sstevel@tonic-gate  * Display those controllers where RAID volumes were not found
3117c478bd9Sstevel@tonic-gate  */
3127c478bd9Sstevel@tonic-gate static void
3137c478bd9Sstevel@tonic-gate print_no_raids()
3147c478bd9Sstevel@tonic-gate {
3157c478bd9Sstevel@tonic-gate 	int i, space = 0;
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	if (info_ctrl == NULL)
3187c478bd9Sstevel@tonic-gate 		return;
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	for (i = 0; i < ctrl_nums; i++) {
3217c478bd9Sstevel@tonic-gate 		/* Status of '0' means RAID exists at that controller */
3227c478bd9Sstevel@tonic-gate 		if (info_ctrl[i][INFO_STATUS] == RAID_FOUND ||
3237c478bd9Sstevel@tonic-gate 		    info_ctrl[i][INFO_STATUS] == RAID_DONT_USE)
3247c478bd9Sstevel@tonic-gate 			continue;
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 		if (!space && raids != NULL) {
3277c478bd9Sstevel@tonic-gate 			(void) printf("\n");
3287c478bd9Sstevel@tonic-gate 			space = 1;
3297c478bd9Sstevel@tonic-gate 		}
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 		/* switch statement used to enable gettext()'ing of text */
3327c478bd9Sstevel@tonic-gate 		switch (info_ctrl[i][INFO_STATUS]) {
3337c478bd9Sstevel@tonic-gate 		case RAID_INVALID_CTRL:
3347c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Invalid controller '%d'\n"),
3357c478bd9Sstevel@tonic-gate 				info_ctrl[i][INFO_CTRL]);
3367c478bd9Sstevel@tonic-gate 			break;
3377c478bd9Sstevel@tonic-gate 		case RAID_NOT_SUPPORTED:
3387c478bd9Sstevel@tonic-gate 			(void) printf(gettext("No RAID supported "
3397c478bd9Sstevel@tonic-gate 				"on controller '%d'\n"),
3407c478bd9Sstevel@tonic-gate 					info_ctrl[i][INFO_CTRL]);
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 			break;
3437c478bd9Sstevel@tonic-gate 		default:
3447c478bd9Sstevel@tonic-gate 			(void) printf(gettext("No RAID volumes found on "
3457c478bd9Sstevel@tonic-gate 				"controller '%d'\n"), info_ctrl[i][INFO_CTRL]);
3467c478bd9Sstevel@tonic-gate 		}
3477c478bd9Sstevel@tonic-gate 	}
3487c478bd9Sstevel@tonic-gate }
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate static void
3517c478bd9Sstevel@tonic-gate add_raid_to_raidlist(char *ctrl_name, int controller)
3527c478bd9Sstevel@tonic-gate {
3537c478bd9Sstevel@tonic-gate 	raidlist_t		*curr;
3547c478bd9Sstevel@tonic-gate 	char			buf[MAXPATHLEN] = {0};
3557c478bd9Sstevel@tonic-gate 	char			buf1[MAXPATHLEN] = {0};
3566fec3791Sjesseb 	int			nvols;
3578ba1bcfcSdduvall 	int			fd;
3588ba1bcfcSdduvall 	int			i;
3596fec3791Sjesseb 	int			n;
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	if (readlink(ctrl_name, buf, sizeof (buf)) < 0)
3627c478bd9Sstevel@tonic-gate 		return;
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	if (get_ctrl_devctl(buf, buf1))
3657c478bd9Sstevel@tonic-gate 		return;
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 	/*
3687c478bd9Sstevel@tonic-gate 	 * If "-l" was specified, then only look at those controllers
3697c478bd9Sstevel@tonic-gate 	 * listed as part of the command line input.
3707c478bd9Sstevel@tonic-gate 	 */
3717c478bd9Sstevel@tonic-gate 	if (info_ctrl != NULL) {
3727c478bd9Sstevel@tonic-gate 		for (i = 0; i < ctrl_nums; i++) {
3737c478bd9Sstevel@tonic-gate 			if (info_ctrl[i][INFO_STATUS] == RAID_DONT_USE)
3747c478bd9Sstevel@tonic-gate 				continue;
3756fec3791Sjesseb 			if (controller == info_ctrl[i][INFO_CTRL])
3767c478bd9Sstevel@tonic-gate 				break;
3777c478bd9Sstevel@tonic-gate 		}
3786fec3791Sjesseb 		/* return if we didn't find a controller */
3796fec3791Sjesseb 		if (i == ctrl_nums)
3807c478bd9Sstevel@tonic-gate 			return;
3817c478bd9Sstevel@tonic-gate 	}
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	fd = open(buf1, O_RDONLY);
3847c478bd9Sstevel@tonic-gate 	if (fd == -1) {
3857c478bd9Sstevel@tonic-gate 		if (info_ctrl != NULL)
3867c478bd9Sstevel@tonic-gate 			info_ctrl[i][INFO_STATUS] = RAID_INVALID_CTRL;
3877c478bd9Sstevel@tonic-gate 		return;
3887c478bd9Sstevel@tonic-gate 	}
3897c478bd9Sstevel@tonic-gate 
3906fec3791Sjesseb 	/*
3916fec3791Sjesseb 	 * query the HBA driver for volume capacity
3926fec3791Sjesseb 	 */
3936fec3791Sjesseb 	if (ioctl(fd, RAID_NUMVOLUMES, &nvols) < 0) {
3946fec3791Sjesseb 		if (info_ctrl != NULL)
3956fec3791Sjesseb 			info_ctrl[i][INFO_STATUS] = RAID_NOT_SUPPORTED;
3966fec3791Sjesseb 		(void) close(fd);
3976fec3791Sjesseb 		return;
3986fec3791Sjesseb 	}
3996fec3791Sjesseb 
4006fec3791Sjesseb 	/*
4016fec3791Sjesseb 	 * now iterate through nvols configurations
4026fec3791Sjesseb 	 */
4036fec3791Sjesseb 	for (n = 0; n < nvols; n++) {
4046fec3791Sjesseb 		raid_config_t		config;
4056fec3791Sjesseb 
4066fec3791Sjesseb 		/* use unitid to retrieve this volume */
4076fec3791Sjesseb 		config.unitid = n;
4087c478bd9Sstevel@tonic-gate 		if (ioctl(fd, RAID_GETCONFIG, &config) < 0) {
4097c478bd9Sstevel@tonic-gate 			if (info_ctrl != NULL)
4107c478bd9Sstevel@tonic-gate 				info_ctrl[i][INFO_STATUS] = RAID_NOT_SUPPORTED;
4117c478bd9Sstevel@tonic-gate 			(void) close(fd);
4127c478bd9Sstevel@tonic-gate 			return;
4137c478bd9Sstevel@tonic-gate 		}
4147c478bd9Sstevel@tonic-gate 
4156fec3791Sjesseb 		/* if ndisks is 0, this volume is not configured */
4166fec3791Sjesseb 		if (config.ndisks == 0)
4176fec3791Sjesseb 			continue;
4186fec3791Sjesseb 
4196fec3791Sjesseb 		/* otherwise, we have a raid volume */
4207c478bd9Sstevel@tonic-gate 		if (info_ctrl != NULL)
4217c478bd9Sstevel@tonic-gate 			info_ctrl[i][INFO_STATUS] = RAID_FOUND;
4227c478bd9Sstevel@tonic-gate 
4236fec3791Sjesseb 		/*
4246fec3791Sjesseb 		 * if raids has not been initialized, do it.
4256fec3791Sjesseb 		 * otherwise, see if this controller is in
4266fec3791Sjesseb 		 * raids.
4276fec3791Sjesseb 		 */
4287c478bd9Sstevel@tonic-gate 		if (raids == NULL) {
4297c478bd9Sstevel@tonic-gate 			raids = (raidlist_t *)malloc(sizeof (raidlist_t));
4307c478bd9Sstevel@tonic-gate 			curr = raids;
4317c478bd9Sstevel@tonic-gate 		} else {
4327c478bd9Sstevel@tonic-gate 			curr = raids;
4336fec3791Sjesseb 			if (already_there(controller))
4346fec3791Sjesseb 				goto already_there;
4356fec3791Sjesseb 
4366fec3791Sjesseb 			/* add this controller to raids */
4377c478bd9Sstevel@tonic-gate 			while (curr->next != NULL)
4387c478bd9Sstevel@tonic-gate 				curr = curr->next;
4397c478bd9Sstevel@tonic-gate 			curr->next = (raidlist_t *)malloc(sizeof (raidlist_t));
4407c478bd9Sstevel@tonic-gate 			curr = curr->next;
4417c478bd9Sstevel@tonic-gate 		}
4426fec3791Sjesseb 
4436fec3791Sjesseb already_there:
4447c478bd9Sstevel@tonic-gate 		curr->next = NULL;
4457c478bd9Sstevel@tonic-gate 		curr->controller = controller;
4467c478bd9Sstevel@tonic-gate 		(void) strlcpy(curr->devctl, buf1, sizeof (curr->devctl));
4477c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
4486fec3791Sjesseb 		(void) memcpy(&curr->raid_config[n], &config,
4496fec3791Sjesseb 				(sizeof (raid_config_t)));
4506fec3791Sjesseb 	}
4516fec3791Sjesseb 
4526fec3791Sjesseb 	if (info_ctrl != NULL && info_ctrl[i][INFO_STATUS] != RAID_FOUND)
4536fec3791Sjesseb 		info_ctrl[i][INFO_STATUS] = RAID_NOT_FOUND;
4547c478bd9Sstevel@tonic-gate }
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate static void
4577c478bd9Sstevel@tonic-gate print_header()
4587c478bd9Sstevel@tonic-gate {
4596fec3791Sjesseb 	(void) printf(gettext("RAID\tVolume\tRAID\t\tRAID\t\tDisk"));
4607c478bd9Sstevel@tonic-gate 	(void) printf("\n");
4616fec3791Sjesseb 	(void) printf(gettext("Volume\tType\tStatus\t\tDisk\t\tStatus"));
4627c478bd9Sstevel@tonic-gate 	(void) printf("\n");
4637c478bd9Sstevel@tonic-gate 	(void) printf("------------------------------------------------------");
4647c478bd9Sstevel@tonic-gate 	(void) printf("\n");
4657c478bd9Sstevel@tonic-gate }
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate static void
4687c478bd9Sstevel@tonic-gate print_raidconfig(int c, raid_config_t config)
4697c478bd9Sstevel@tonic-gate {
4707c478bd9Sstevel@tonic-gate 	int	i;
4716fec3791Sjesseb 	char	voltype[8];
4727c478bd9Sstevel@tonic-gate 
4736fec3791Sjesseb 	/* print RAID volume target ID and volume type */
4746fec3791Sjesseb 	if (config.raid_level == RAID_STRIPE) {
4756fec3791Sjesseb 		(void) snprintf(voltype, sizeof (voltype), "IS");
4766fec3791Sjesseb 	} else if (config.raid_level == RAID_MIRROR) {
4776fec3791Sjesseb 		(void) snprintf(voltype, sizeof (voltype), "IM");
4786fec3791Sjesseb 	}
4796fec3791Sjesseb 
4806fec3791Sjesseb 	(void) printf("c%dt%dd0\t%s\t", c, config.targetid, voltype);
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	/* Get RAID Info */
4837c478bd9Sstevel@tonic-gate 	if (config.flags & RAID_FLAG_RESYNCING &&
4847c478bd9Sstevel@tonic-gate 	    config.state == RAID_STATE_DEGRADED) {
4857c478bd9Sstevel@tonic-gate 		(void) printf(gettext("RESYNCING\t"));
4867c478bd9Sstevel@tonic-gate 	} else if (config.state == RAID_STATE_DEGRADED) {
4877c478bd9Sstevel@tonic-gate 		(void) printf(gettext("DEGRADED\t"));
4887c478bd9Sstevel@tonic-gate 	} else if (config.state == RAID_STATE_OPTIMAL) {
4897c478bd9Sstevel@tonic-gate 		(void) printf(gettext("OK\t\t"));
4907c478bd9Sstevel@tonic-gate 	} else if (config.state == RAID_STATE_FAILED) {
4917c478bd9Sstevel@tonic-gate 		(void) printf(gettext("FAILED\t\t"));
4927c478bd9Sstevel@tonic-gate 	} else {
4937c478bd9Sstevel@tonic-gate 		(void) printf(gettext("ERROR\t\t"));
4947c478bd9Sstevel@tonic-gate 	}
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	/* Get RAID Disks */
4977c478bd9Sstevel@tonic-gate 	(void) printf("c%dt%dd0\t\t", c, config.disk[0]);
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 	/* Get RAID Disk's Status */
5007c478bd9Sstevel@tonic-gate 	if (config.diskstatus[0] & RAID_DISKSTATUS_FAILED) {
5017c478bd9Sstevel@tonic-gate 		(void) printf(gettext("FAILED\n"));
5027c478bd9Sstevel@tonic-gate 	} else if (config.diskstatus[0] & RAID_DISKSTATUS_MISSING) {
5037c478bd9Sstevel@tonic-gate 		(void) printf(gettext("MISSING\n"));
5047c478bd9Sstevel@tonic-gate 	} else {
5057c478bd9Sstevel@tonic-gate 		(void) printf(gettext("OK\n"));
5067c478bd9Sstevel@tonic-gate 	}
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 	for (i = 1; i < config.ndisks; i++) {
5097c478bd9Sstevel@tonic-gate 		(void) printf("\t\t\t\tc%dt%dd0\t\t", c, config.disk[i]);
5107c478bd9Sstevel@tonic-gate 		if (config.diskstatus[i] & RAID_DISKSTATUS_FAILED) {
5117c478bd9Sstevel@tonic-gate 			(void) printf(gettext("FAILED\n"));
5127c478bd9Sstevel@tonic-gate 		} else if (config.diskstatus[i] & RAID_DISKSTATUS_MISSING) {
5137c478bd9Sstevel@tonic-gate 			(void) printf(gettext("MISSING\n"));
5147c478bd9Sstevel@tonic-gate 		} else {
5157c478bd9Sstevel@tonic-gate 			(void) printf(gettext("OK\n"));
5167c478bd9Sstevel@tonic-gate 		}
5177c478bd9Sstevel@tonic-gate 	}
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate static void
5217c478bd9Sstevel@tonic-gate print_disklist()
5227c478bd9Sstevel@tonic-gate {
5237c478bd9Sstevel@tonic-gate 	raidlist_t	*curr = raids;
5246fec3791Sjesseb 	int i;
5256fec3791Sjesseb 
5267c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
5276fec3791Sjesseb 		for (i = 0; i < N_RAIDVOLS; i++) {
5286fec3791Sjesseb 			if (curr->raid_config[i].ndisks != 0) {
5296fec3791Sjesseb 				print_raidconfig(curr->controller,
5306fec3791Sjesseb 						curr->raid_config[i]);
5316fec3791Sjesseb 			}
5326fec3791Sjesseb 		}
5337c478bd9Sstevel@tonic-gate 		curr = curr->next;
5347c478bd9Sstevel@tonic-gate 	}
5357c478bd9Sstevel@tonic-gate }
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate static void
5387c478bd9Sstevel@tonic-gate free_disklist()
5397c478bd9Sstevel@tonic-gate {
5407c478bd9Sstevel@tonic-gate 	raidlist_t	*curr = raids;
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
5437c478bd9Sstevel@tonic-gate 		raidlist_t	*temp;
5447c478bd9Sstevel@tonic-gate 		temp = curr;
5457c478bd9Sstevel@tonic-gate 		curr = curr->next;
5467c478bd9Sstevel@tonic-gate 		free(temp);
5477c478bd9Sstevel@tonic-gate 	}
5487c478bd9Sstevel@tonic-gate }
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate static void
5517c478bd9Sstevel@tonic-gate do_search()
5527c478bd9Sstevel@tonic-gate {
5537c478bd9Sstevel@tonic-gate 	DIR		*dir;
5547c478bd9Sstevel@tonic-gate 	struct dirent	*dp;
5557c478bd9Sstevel@tonic-gate 	char		buf[MAXPATHLEN];
5567c478bd9Sstevel@tonic-gate 	int		c;
5577c478bd9Sstevel@tonic-gate 	int		i, j;
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	/*
5607c478bd9Sstevel@tonic-gate 	 * In case repeated numbers were found, assign the repititions as
5617c478bd9Sstevel@tonic-gate 	 * RAID_DONT_USE
5627c478bd9Sstevel@tonic-gate 	 */
5637c478bd9Sstevel@tonic-gate 	for (i = 0; i < ctrl_nums; i++) {
5647c478bd9Sstevel@tonic-gate 		int first_one = 1;
5657c478bd9Sstevel@tonic-gate 		for (j = 0; j < ctrl_nums; j++) {
5667c478bd9Sstevel@tonic-gate 			if (info_ctrl[i][INFO_CTRL] ==
5677c478bd9Sstevel@tonic-gate 				info_ctrl[j][INFO_CTRL]) {
5687c478bd9Sstevel@tonic-gate 				if (info_ctrl[j][INFO_STATUS] == RAID_DONT_USE)
5697c478bd9Sstevel@tonic-gate 					continue;
5707c478bd9Sstevel@tonic-gate 				if (first_one) {
5717c478bd9Sstevel@tonic-gate 					first_one = 0;
5727c478bd9Sstevel@tonic-gate 				} else {
5737c478bd9Sstevel@tonic-gate 					info_ctrl[j][INFO_STATUS] =
5747c478bd9Sstevel@tonic-gate 						RAID_DONT_USE;
5757c478bd9Sstevel@tonic-gate 				}
5767c478bd9Sstevel@tonic-gate 			}
5777c478bd9Sstevel@tonic-gate 		}
5787c478bd9Sstevel@tonic-gate 	}
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 	if ((dir = opendir("/dev/cfg")) == NULL) {
5817c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
5827c478bd9Sstevel@tonic-gate 			gettext("Cannot open /dev/cfg: %s\n"), strerror(errno));
5837c478bd9Sstevel@tonic-gate 		return;
5847c478bd9Sstevel@tonic-gate 	}
5857c478bd9Sstevel@tonic-gate 	while ((dp = readdir(dir)) != NULL) {
5867c478bd9Sstevel@tonic-gate 		if (strcmp(dp->d_name, ".") == 0 ||
5877c478bd9Sstevel@tonic-gate 		    strcmp(dp->d_name, "..") == 0)
5887c478bd9Sstevel@tonic-gate 			continue;
5897c478bd9Sstevel@tonic-gate 		if (sscanf(dp->d_name, "c%d", &c) != 1)
5907c478bd9Sstevel@tonic-gate 			continue;
5917c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), "/dev/cfg/%s", dp->d_name);
5927c478bd9Sstevel@tonic-gate 		add_raid_to_raidlist(buf, c);
5937c478bd9Sstevel@tonic-gate 	}
5947c478bd9Sstevel@tonic-gate 	(void) closedir(dir);
5957c478bd9Sstevel@tonic-gate }
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate /*
5987c478bd9Sstevel@tonic-gate  * do_info() will do the following:
5997c478bd9Sstevel@tonic-gate  * - create a list of disks' devctls
6007c478bd9Sstevel@tonic-gate  * - try to talk to each of the devctls found
6017c478bd9Sstevel@tonic-gate  * - if raid configuration is found, display it.
6027c478bd9Sstevel@tonic-gate  */
6037c478bd9Sstevel@tonic-gate static void
6047c478bd9Sstevel@tonic-gate do_info()
6057c478bd9Sstevel@tonic-gate {
6067c478bd9Sstevel@tonic-gate 	int i;
6077c478bd9Sstevel@tonic-gate 	(void) chdir(DEVDIR);
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	do_search();
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	if (raids == NULL) {
6127c478bd9Sstevel@tonic-gate 		if (info_ctrl != NULL) {
6137c478bd9Sstevel@tonic-gate 			print_no_raids();
6147c478bd9Sstevel@tonic-gate 			for (i = 0; i < ctrl_nums; i++)
6157c478bd9Sstevel@tonic-gate 				free(info_ctrl[i]);
6167c478bd9Sstevel@tonic-gate 			free(info_ctrl);
6177c478bd9Sstevel@tonic-gate 		} else {
6187c478bd9Sstevel@tonic-gate 			(void) printf(gettext("No RAID volumes found\n"));
6197c478bd9Sstevel@tonic-gate 		}
6207c478bd9Sstevel@tonic-gate 		return;
6217c478bd9Sstevel@tonic-gate 	}
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	print_header();
6247c478bd9Sstevel@tonic-gate 	print_disklist();
6257c478bd9Sstevel@tonic-gate 	print_no_raids();
6267c478bd9Sstevel@tonic-gate 	free_disklist();
6277c478bd9Sstevel@tonic-gate 	if (info_ctrl) {
6287c478bd9Sstevel@tonic-gate 		for (i = 0; i < ctrl_nums; i++)
6297c478bd9Sstevel@tonic-gate 			free(info_ctrl[i]);
6307c478bd9Sstevel@tonic-gate 		free(info_ctrl);
6317c478bd9Sstevel@tonic-gate 	}
6327c478bd9Sstevel@tonic-gate }
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate static int
6356fec3791Sjesseb disk_in_raid(int c, int t)
6366fec3791Sjesseb {
6376fec3791Sjesseb 	raidlist_t	*curr;
6386fec3791Sjesseb 	raid_config_t	raid;
6396fec3791Sjesseb 	int i, j, n;
6406fec3791Sjesseb 
6416fec3791Sjesseb 	do_search();
6426fec3791Sjesseb 	curr = raids;
6436fec3791Sjesseb 
6446fec3791Sjesseb 	while (curr != NULL) {
6456fec3791Sjesseb 		if (curr->controller == c) {
6466fec3791Sjesseb 			for (i = 0; i < N_RAIDVOLS; i++) {
6476fec3791Sjesseb 				raid = curr->raid_config[i];
6486fec3791Sjesseb 				if ((n = raid.ndisks) != 0) {
6496fec3791Sjesseb 					for (j = 0; j < n; j++) {
6506fec3791Sjesseb 						if (raid.disk[j] == t) {
6516fec3791Sjesseb 							return (1);
6526fec3791Sjesseb 						}
6536fec3791Sjesseb 					}
6546fec3791Sjesseb 				}
6556fec3791Sjesseb 			}
6566fec3791Sjesseb 		}
6576fec3791Sjesseb 		curr = curr->next;
6586fec3791Sjesseb 	}
6596fec3791Sjesseb 	return (0);
6606fec3791Sjesseb }
6616fec3791Sjesseb 
6626fec3791Sjesseb static int
6637c478bd9Sstevel@tonic-gate disk_there(int c, int t)
6647c478bd9Sstevel@tonic-gate {
6657c478bd9Sstevel@tonic-gate 	char	disk[100];
6667c478bd9Sstevel@tonic-gate 	int	fd;
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	(void) snprintf(disk, sizeof (disk), "c%dt%dd0s2", c, t);
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	fd = open(disk, O_RDWR | O_NDELAY);
6717c478bd9Sstevel@tonic-gate 	if (fd == -1) {
6727c478bd9Sstevel@tonic-gate 		return (-1);
6737c478bd9Sstevel@tonic-gate 	}
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	(void) close(fd);
6767c478bd9Sstevel@tonic-gate 	return (0);
6777c478bd9Sstevel@tonic-gate }
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate static int
6807c478bd9Sstevel@tonic-gate get_controller(char *dev)
6817c478bd9Sstevel@tonic-gate {
6827c478bd9Sstevel@tonic-gate 	raidlist_t	*curr;
6837c478bd9Sstevel@tonic-gate 	int		c;
6847c478bd9Sstevel@tonic-gate 	do_search();
6857c478bd9Sstevel@tonic-gate 	curr = raids;
6867c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
6877c478bd9Sstevel@tonic-gate 		if (strcmp(curr->devctl, dev) == 0) {
6887c478bd9Sstevel@tonic-gate 			c = curr->controller;
6897c478bd9Sstevel@tonic-gate 			break;
6907c478bd9Sstevel@tonic-gate 		}
6917c478bd9Sstevel@tonic-gate 		curr = curr->next;
6927c478bd9Sstevel@tonic-gate 	}
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 	free_disklist();
6957c478bd9Sstevel@tonic-gate 	return (c);
6967c478bd9Sstevel@tonic-gate }
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate static int
6997c478bd9Sstevel@tonic-gate disk_mounted(char *d)
7007c478bd9Sstevel@tonic-gate {
7017c478bd9Sstevel@tonic-gate 	struct mnttab	mt;
7027c478bd9Sstevel@tonic-gate 	FILE		*f = fopen("/etc/mnttab", "r");
7037c478bd9Sstevel@tonic-gate 
7048ba1bcfcSdduvall 	while (getmntent(f, &mt) != EOF)
7057c478bd9Sstevel@tonic-gate 		if (strstr(mt.mnt_special, d) != NULL)
7067c478bd9Sstevel@tonic-gate 			return (1);
7076fec3791Sjesseb 
7087c478bd9Sstevel@tonic-gate 	return (0);
7097c478bd9Sstevel@tonic-gate }
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate static int
7127c478bd9Sstevel@tonic-gate disk_big_enough(char **d, diskaddr_t *cap, int *errcond)
7137c478bd9Sstevel@tonic-gate {
7147c478bd9Sstevel@tonic-gate 	struct dk_minfo minfo;
7157c478bd9Sstevel@tonic-gate 	char		disk[N_DISKS][MAXPATHLEN];
7166fec3791Sjesseb 	uint_t		disk_lbsize[N_DISKS];
7177c478bd9Sstevel@tonic-gate 	diskaddr_t	disk_capacity[N_DISKS];
7187c478bd9Sstevel@tonic-gate 	int		i, fd;
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	for (i = 0; i < N_DISKS; i++) {
7216fec3791Sjesseb 		if (d[i] == NULL)
7226fec3791Sjesseb 			break;
7236fec3791Sjesseb 
7247c478bd9Sstevel@tonic-gate 		(void) snprintf(disk[i], sizeof (disk[i]), DEVDIR"/%ss2", d[i]);
7257c478bd9Sstevel@tonic-gate 		fd = open(disk[i], O_RDWR | O_NDELAY);
7266fec3791Sjesseb 		if (fd == -1)
7277c478bd9Sstevel@tonic-gate 			return (FAILURE);
7287c478bd9Sstevel@tonic-gate 		if (ioctl(fd, DKIOCGMEDIAINFO, &minfo) == -1) {
7297c478bd9Sstevel@tonic-gate 			(void) close(fd);
7307c478bd9Sstevel@tonic-gate 			return (FAILURE);
7317c478bd9Sstevel@tonic-gate 		}
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 		disk_lbsize[i] = minfo.dki_lbsize;
7347c478bd9Sstevel@tonic-gate 		disk_capacity[i] = minfo.dki_capacity;
7357c478bd9Sstevel@tonic-gate 
7366fec3791Sjesseb 		/* lbsize must be the same on all disks */
7376fec3791Sjesseb 		if (disk_lbsize[0] != disk_lbsize[i]) {
7387c478bd9Sstevel@tonic-gate 			*errcond = 2;
7397c478bd9Sstevel@tonic-gate 			return (INVALID_ARG);
7407c478bd9Sstevel@tonic-gate 		}
7417c478bd9Sstevel@tonic-gate 
7426fec3791Sjesseb 		/* ensure drive capacity is greater than or equal to first */
7436fec3791Sjesseb 		if (disk_capacity[0] > disk_capacity[i]) {
7447c478bd9Sstevel@tonic-gate 			*errcond = 1;
7457c478bd9Sstevel@tonic-gate 			return (INVALID_ARG);
7467c478bd9Sstevel@tonic-gate 		}
7476fec3791Sjesseb 		(void) close(fd);
7486fec3791Sjesseb 	}
7497c478bd9Sstevel@tonic-gate 
7506fec3791Sjesseb 	/*
7516fec3791Sjesseb 	 * setting capacity as the dk_minfo.dki_capacity of d[0]
7526fec3791Sjesseb 	 *   this is the number of dki_lbsize blocks on disk
7536fec3791Sjesseb 	 */
7547c478bd9Sstevel@tonic-gate 	*cap = disk_capacity[0];
7557c478bd9Sstevel@tonic-gate 	return (SUCCESS);
7567c478bd9Sstevel@tonic-gate }
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate static int
7597c478bd9Sstevel@tonic-gate do_config_change_state(cfga_cmd_t cmd, int d, int c)
7607c478bd9Sstevel@tonic-gate {
7617c478bd9Sstevel@tonic-gate 	cfga_err_t	cfga_err;
7627c478bd9Sstevel@tonic-gate 	char		*ap_id;
7637c478bd9Sstevel@tonic-gate 	int		rv = SUCCESS;
7647c478bd9Sstevel@tonic-gate 	int		count = 0;
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	ap_id = (char *)malloc(100);
7677c478bd9Sstevel@tonic-gate 	if (ap_id == NULL)
7687c478bd9Sstevel@tonic-gate 		return (FAILURE);
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	(void) snprintf(ap_id, 100, "c%d::dsk/c%dt%dd0", c, c, d);
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 	/*
7737c478bd9Sstevel@tonic-gate 	 * If the config_change_state() funcation fails, we want to
7747c478bd9Sstevel@tonic-gate 	 * retry.  If the retry fails, then we return failure to fail.
7757c478bd9Sstevel@tonic-gate 	 *
7767c478bd9Sstevel@tonic-gate 	 * If we fail:
7777c478bd9Sstevel@tonic-gate 	 *
7787c478bd9Sstevel@tonic-gate 	 *	If we were called from create, then we fail the raid
7797c478bd9Sstevel@tonic-gate 	 *	creation.
7807c478bd9Sstevel@tonic-gate 	 *
7817c478bd9Sstevel@tonic-gate 	 *	If we were called from delete, then the disk will not
7827c478bd9Sstevel@tonic-gate 	 *	be re-configured by raidctl.
7837c478bd9Sstevel@tonic-gate 	 */
7847c478bd9Sstevel@tonic-gate 	do {
7857c478bd9Sstevel@tonic-gate 		cfga_err = config_change_state(cmd, 1, &ap_id, NULL,
7867c478bd9Sstevel@tonic-gate 			NULL, NULL, NULL, 0);
7877c478bd9Sstevel@tonic-gate 		count++;
7887c478bd9Sstevel@tonic-gate 	} while (cfga_err != CFGA_OK && count < 2);
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 	if (cfga_err != CFGA_OK)
7917c478bd9Sstevel@tonic-gate 		rv = FAILURE;
7927c478bd9Sstevel@tonic-gate 
7937c478bd9Sstevel@tonic-gate 	free(ap_id);
7947c478bd9Sstevel@tonic-gate 	return (rv);
7957c478bd9Sstevel@tonic-gate }
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate static int
7986fec3791Sjesseb do_create(char **d, int rlevel, int force)
7997c478bd9Sstevel@tonic-gate {
8008ba1bcfcSdduvall 	raid_config_t	config;
8016fec3791Sjesseb 	raid_config_t	newvol;
8027c478bd9Sstevel@tonic-gate 	char		disk[N_DISKS][MAXPATHLEN] = {0};
8036fec3791Sjesseb 	int		map[N_DISKS];
8047c478bd9Sstevel@tonic-gate 	char		channel1[MAXPATHLEN];
8057c478bd9Sstevel@tonic-gate 	char		channel2[MAXPATHLEN];
8067c478bd9Sstevel@tonic-gate 	diskaddr_t	capacity;
8076fec3791Sjesseb 	int		fd, fd2, size, errcond;
8087c478bd9Sstevel@tonic-gate 	int		c[N_DISKS];
8097c478bd9Sstevel@tonic-gate 	int		t[N_DISKS];
8107c478bd9Sstevel@tonic-gate 	char		*tmp;
8116fec3791Sjesseb 	int		loc, i, devid, n, ndisks = 0;
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	(void) chdir(DEVDIR);
8147c478bd9Sstevel@tonic-gate 
8156fec3791Sjesseb 	/* initialize target map */
8166fec3791Sjesseb 	for (i = 0; i < N_DISKS; i++)
8176fec3791Sjesseb 		map[i] = -1;
8186fec3791Sjesseb 
8197c478bd9Sstevel@tonic-gate 	for (i = 0; i < N_DISKS; i++) {
8206fec3791Sjesseb 		if (d[i] == NULL)
8216fec3791Sjesseb 			break;
8226fec3791Sjesseb 
8237c478bd9Sstevel@tonic-gate 		if ((sscanf(d[i], "c%dt%dd0", &c[i], &t[i])) != 2 ||
8247c478bd9Sstevel@tonic-gate 		    t[i] < 0) {
8257c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
8267c478bd9Sstevel@tonic-gate 				gettext("Invalid disk format.\n"));
8277c478bd9Sstevel@tonic-gate 			return (INVALID_ARG);
8287c478bd9Sstevel@tonic-gate 		}
8297c478bd9Sstevel@tonic-gate 
8306fec3791Sjesseb 		/* ensure that all disks are on the same controller, */
8316fec3791Sjesseb 		if (c[i] != c[0]) {
8326fec3791Sjesseb 			(void) fprintf(stderr, gettext("Disks must be "
8336fec3791Sjesseb 					"on the same controller.\n"));
8347c478bd9Sstevel@tonic-gate 			return (INVALID_ARG);
8357c478bd9Sstevel@tonic-gate 		}
8367c478bd9Sstevel@tonic-gate 
8376fec3791Sjesseb 		/* that all disks are online, */
8386fec3791Sjesseb 		if (disk_there(c[0], t[i])) {
8396fec3791Sjesseb 			(void) printf(gettext("Disk 'c%dt%dd0' is not "
8406fec3791Sjesseb 				"present.\n"), c[0], t[i]);
8417c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Cannot create RAID volume.\n"));
8427c478bd9Sstevel@tonic-gate 			return (INVALID_ARG);
8437c478bd9Sstevel@tonic-gate 		}
8447c478bd9Sstevel@tonic-gate 
8456fec3791Sjesseb 		/* that there are no duplicate disks, */
8466fec3791Sjesseb 		loc = t[i];
8476fec3791Sjesseb 		if (map[loc] == -1) {
8486fec3791Sjesseb 			map[loc] = t[i];
8496fec3791Sjesseb 		} else {
8506fec3791Sjesseb 			(void) fprintf(stderr,
8516fec3791Sjesseb 				gettext("Disks must be different.\n"));
8526fec3791Sjesseb 			return (INVALID_ARG);
8536fec3791Sjesseb 		}
8546fec3791Sjesseb 
8556fec3791Sjesseb 		/* that no disk is already in use by another volume, */
8566fec3791Sjesseb 		if (disk_in_raid(c[0], t[i])) {
8576fec3791Sjesseb 			(void) fprintf(stderr, gettext("Disk %s is already in "
8586fec3791Sjesseb 				"a RAID volume.\n"), d[i]);
8596fec3791Sjesseb 			return (INVALID_ARG);
8606fec3791Sjesseb 		}
8616fec3791Sjesseb 
8626fec3791Sjesseb 		/* that no target's id is lower than the raidtarg, */
8636fec3791Sjesseb 		if (t[0] > t[i]) {
8646fec3791Sjesseb 			(void) fprintf(stderr, gettext("First target ID must "
8656fec3791Sjesseb 				"be less than other member target IDs.\n"));
8666fec3791Sjesseb 			return (INVALID_ARG);
8676fec3791Sjesseb 		}
8686fec3791Sjesseb 
8696fec3791Sjesseb 		(void) snprintf(disk[i], sizeof (disk[i]), DEVDIR"/%ss2", d[i]);
8706fec3791Sjesseb 		ndisks++;
8716fec3791Sjesseb 	}
8726fec3791Sjesseb 
8736fec3791Sjesseb 	/* confirm minimum number of disks */
8746fec3791Sjesseb 	if (ndisks < 2) {
8756fec3791Sjesseb 		(void) fprintf(stderr, gettext("At least two disks are required"
8766fec3791Sjesseb 			" for RAID creation.\n"));
8776fec3791Sjesseb 		return (INVALID_ARG);
8786fec3791Sjesseb 	}
8796fec3791Sjesseb 
8806fec3791Sjesseb 	/* validate the drive capacities */
8817c478bd9Sstevel@tonic-gate 	switch (disk_big_enough(d, &capacity, &errcond)) {
8827c478bd9Sstevel@tonic-gate 	case FAILURE:
8837c478bd9Sstevel@tonic-gate 		return (FAILURE);
8847c478bd9Sstevel@tonic-gate 	case INVALID_ARG:
8857c478bd9Sstevel@tonic-gate 		switch (errcond) {
8867c478bd9Sstevel@tonic-gate 		case 1:
8877c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Cannot create RAID volume when "
8887c478bd9Sstevel@tonic-gate 			"primary disk is larger than secondary disk.\n"));
8897c478bd9Sstevel@tonic-gate 		break;
8907c478bd9Sstevel@tonic-gate 		case 2:
8917c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Cannot create RAID volume when "
8927c478bd9Sstevel@tonic-gate 			"disk block sizes differ.\n"));
8937c478bd9Sstevel@tonic-gate 		}
8947c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
8957c478bd9Sstevel@tonic-gate 	}
8967c478bd9Sstevel@tonic-gate 
8976fec3791Sjesseb 	/*
8986fec3791Sjesseb 	 * capacity is now set to the number of blocks on a disk, which is
8996fec3791Sjesseb 	 * the total capacity of a mirror.  the capacity of a stripe is the
9006fec3791Sjesseb 	 * cumulative amount of blocks on all disks
9016fec3791Sjesseb 	 */
9026fec3791Sjesseb 	if (rlevel == RAID_STRIPE)
9036fec3791Sjesseb 		capacity *= ndisks;
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 	if (get_devctl(disk[0], channel1))
9067c478bd9Sstevel@tonic-gate 		return (FAILURE);
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 	fd = open(channel1, O_RDONLY);
9097c478bd9Sstevel@tonic-gate 	if (fd == -1) {
9107c478bd9Sstevel@tonic-gate 		perror(channel1);
9117c478bd9Sstevel@tonic-gate 		return (FAILURE);
9127c478bd9Sstevel@tonic-gate 	}
9137c478bd9Sstevel@tonic-gate 
9146fec3791Sjesseb 	/*
9156fec3791Sjesseb 	 * query the HBA driver for volume capacity
9166fec3791Sjesseb 	 */
9176fec3791Sjesseb 	if (ioctl(fd, RAID_NUMVOLUMES, &n) < 0) {
9186fec3791Sjesseb 		raidctl_error("RAID_NUMVOLUMES");
9196fec3791Sjesseb 		goto fail;
9206fec3791Sjesseb 	}
9216fec3791Sjesseb 
9226fec3791Sjesseb 	/*
9236fec3791Sjesseb 	 * current support for both LSI1030 and LSI1064/1068 HBAs
9246fec3791Sjesseb 	 */
9256fec3791Sjesseb 	if (ioctl(fd, RAID_GETDEVID, &devid) < 0) {
9266fec3791Sjesseb 		raidctl_error("RAID_GETDEVID");
9276fec3791Sjesseb 		goto fail;
9286fec3791Sjesseb 	}
9296fec3791Sjesseb 
9306fec3791Sjesseb 	if ((devid == LSI_1064) || (devid == LSI_1064E) || (devid ==
9316fec3791Sjesseb 	    LSI_1068E)) {
9326fec3791Sjesseb 		/*
9336fec3791Sjesseb 		 * no secondary channel, just check to make
9346fec3791Sjesseb 		 * sure we can fit a new volume
9356fec3791Sjesseb 		 */
9366fec3791Sjesseb 		for (i = 0; i < n; i++) {
9376fec3791Sjesseb 			config.unitid = i;
9387c478bd9Sstevel@tonic-gate 			if (ioctl(fd, RAID_GETCONFIG, &config) < 0) {
9397c478bd9Sstevel@tonic-gate 				raidctl_error("RAID_GETCONFIG");
9406fec3791Sjesseb 				goto fail;
9416fec3791Sjesseb 			}
9426fec3791Sjesseb 
9436fec3791Sjesseb 			if (config.ndisks == 0)
9446fec3791Sjesseb 				break;
9456fec3791Sjesseb 		}
9466fec3791Sjesseb 
9476fec3791Sjesseb 		if (i == n) {
9486fec3791Sjesseb 			(void) printf(gettext("HBA supports a maximum of %d "
9496fec3791Sjesseb 				"RAID Volumes, HBA is full\n"), n);
9506fec3791Sjesseb 			goto fail;
9516fec3791Sjesseb 		}
9526fec3791Sjesseb 
9536fec3791Sjesseb 		/*
9546fec3791Sjesseb 		 * we have the capacity to add a volume, now confirm the
9556fec3791Sjesseb 		 * creation. the 1064 uses a much larger metadata region
9566fec3791Sjesseb 		 * than the 1030 (64MB, as opposed to 16KB).  this larger
9576fec3791Sjesseb 		 * reservation is enough to alter the disk label. therefore,
9586fec3791Sjesseb 		 * once the volume is created, it must be relabeled.
9596fec3791Sjesseb 		 * first, confirm that no file systems are mounted, as
9606fec3791Sjesseb 		 * we will be pulling the disk out from under them
9616fec3791Sjesseb 		 */
9626fec3791Sjesseb 		for (i = 0; i < ndisks; i++) {
9636fec3791Sjesseb 			if (disk_mounted(d[i])) {
9646fec3791Sjesseb 				(void) fprintf(stderr, gettext("Cannot create "
9656fec3791Sjesseb 					"RAID volume, disk \"%s\" is mounted "
9666fec3791Sjesseb 					".\n"), d[i]);
9676fec3791Sjesseb 				return (INVALID_ARG);
9686fec3791Sjesseb 			}
9696fec3791Sjesseb 		}
9706fec3791Sjesseb 
9716fec3791Sjesseb 		/*
9726fec3791Sjesseb 		 * will not support data migration or disk relabeling with
9736fec3791Sjesseb 		 * this utility, and so next we must confirm the creation as
9746fec3791Sjesseb 		 * all data on member disks will be lost.
9756fec3791Sjesseb 		 */
9766fec3791Sjesseb 		if (!force) {
9776fec3791Sjesseb 			(void) fprintf(stderr, gettext("Creating RAID volume "
9786fec3791Sjesseb 			    "c%dt%dd0 will destroy all data on member disks, "
9796fec3791Sjesseb 			    "proceed (%s/%s)? "), c[0], t[0], yeschr, nochr);
9806fec3791Sjesseb 			if (!yes()) {
9816fec3791Sjesseb 				(void) fprintf(stderr, gettext("RAID volume "
9826fec3791Sjesseb 				    "c%dt%dd0 not created.\n\n"), c[0], t[0]);
9836fec3791Sjesseb 				(void) close(fd);
9846fec3791Sjesseb 				return (SUCCESS);
9856fec3791Sjesseb 			}
9866fec3791Sjesseb 		}
9876fec3791Sjesseb 
9886fec3791Sjesseb 		/*
9896fec3791Sjesseb 		 * we are ready to move onto the creation
9906fec3791Sjesseb 		 */
9916fec3791Sjesseb 		goto no_secondary_channel;
9926fec3791Sjesseb 	}
9936fec3791Sjesseb 
9946fec3791Sjesseb 	/*
9956fec3791Sjesseb 	 * LSI1030, support for single IM volume
9966fec3791Sjesseb 	 */
9976fec3791Sjesseb 	if (rlevel != RAID_MIRROR) {
9986fec3791Sjesseb 		(void) printf(gettext("HBA only supports RAID "
9996fec3791Sjesseb 			"level 1 (mirrored) volumes\n"));
10006fec3791Sjesseb 		goto fail;
10016fec3791Sjesseb 	}
10026fec3791Sjesseb 	/*
10036fec3791Sjesseb 	 * look up the volume configuration
10046fec3791Sjesseb 	 */
10056fec3791Sjesseb 	config.unitid = n;
10066fec3791Sjesseb 	if (ioctl(fd, RAID_GETCONFIG, &config) < 0) {
10076fec3791Sjesseb 		raidctl_error("RAID_GETCONFIG");
10086fec3791Sjesseb 		goto fail;
10097c478bd9Sstevel@tonic-gate 	}
10107c478bd9Sstevel@tonic-gate 
10118ba1bcfcSdduvall 	if (config.ndisks != 0) {
10126fec3791Sjesseb 		(void) printf(gettext("RAID Volume already exists "
10136fec3791Sjesseb 			"on this controller 'c%dt%dd0'\n"),
10146fec3791Sjesseb 			c[0], config.targetid);
10156fec3791Sjesseb 		goto fail;
101605411564Sjesseb 	}
101705411564Sjesseb 
101805411564Sjesseb 	/*
10197c478bd9Sstevel@tonic-gate 	 * Make sure there isn't a raid created on this controller's
10206fec3791Sjesseb 	 * other channel, if it has multiple channels
10217c478bd9Sstevel@tonic-gate 	 */
10227c478bd9Sstevel@tonic-gate 	(void) strlcpy(channel2, channel1, sizeof (channel2));
10237c478bd9Sstevel@tonic-gate 	tmp = strrchr(channel2, ':');
10247c478bd9Sstevel@tonic-gate 	tmp[0] = 0;
10257c478bd9Sstevel@tonic-gate 	size = strlen(channel2);
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	/*
10286fec3791Sjesseb 	 * Make sure that the secondary disk is not mounted
10296fec3791Sjesseb 	 */
10306fec3791Sjesseb 	if (disk_mounted(disk[1])) {
10316fec3791Sjesseb 		(void) fprintf(stderr, gettext("Cannot create RAID volume when "
10326fec3791Sjesseb 			"secondary disk \"%s\" is mounted.\n"), disk[1]);
10336fec3791Sjesseb 		return (INVALID_ARG);
10346fec3791Sjesseb 	}
10356fec3791Sjesseb 
10366fec3791Sjesseb 	/*
10377c478bd9Sstevel@tonic-gate 	 * Format the channel string for the other channel so we can
10386fec3791Sjesseb 	 * see if a raid exists on it.  In this case if we are being
10396fec3791Sjesseb 	 * asked to create a raid on channel 2 (indicated by the 1,1
10406fec3791Sjesseb 	 * at the end of the string) we want to check channel 1),
10416fec3791Sjesseb 	 * otherwise we will check channel 2.
10427c478bd9Sstevel@tonic-gate 	 */
10437c478bd9Sstevel@tonic-gate 	if (channel2[size - 2] == ',') {
10447c478bd9Sstevel@tonic-gate 		channel2[size - 1] = 0;
10457c478bd9Sstevel@tonic-gate 		channel2[size - 2] = 0;
10466fec3791Sjesseb 		(void) snprintf(channel2, sizeof (channel2),
10476fec3791Sjesseb 				"%s:devctl", channel2);
10487c478bd9Sstevel@tonic-gate 	} else {
10496fec3791Sjesseb 		(void) snprintf(channel2, sizeof (channel2),
10506fec3791Sjesseb 				"%s,1:devctl", channel2);
10517c478bd9Sstevel@tonic-gate 	}
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate 	fd2 = open(channel2, O_RDONLY);
10547c478bd9Sstevel@tonic-gate 	if (fd2 == -1) {
10557c478bd9Sstevel@tonic-gate 		if (errno == ENOENT)
10567c478bd9Sstevel@tonic-gate 			goto no_secondary_channel;
10577c478bd9Sstevel@tonic-gate 		perror(channel2);
10586fec3791Sjesseb 		goto fail;
10597c478bd9Sstevel@tonic-gate 	}
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate 	if (ioctl(fd2, RAID_GETCONFIG, &config) < 0) {
10626fec3791Sjesseb 		goto fail;
10637c478bd9Sstevel@tonic-gate 	}
10647c478bd9Sstevel@tonic-gate 
10658ba1bcfcSdduvall 	if (config.ndisks != 0) {
10667c478bd9Sstevel@tonic-gate 		int	cx;
10677c478bd9Sstevel@tonic-gate 		cx = get_controller(channel2);
10686fec3791Sjesseb 		(void) printf(gettext("RAID Volume already exists "
10696fec3791Sjesseb 			"on this controller 'c%dt%dd0'\n"), cx,
10706fec3791Sjesseb 			config.targetid);
10716fec3791Sjesseb 		goto fail;
10727c478bd9Sstevel@tonic-gate 	}
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate no_secondary_channel:
10757c478bd9Sstevel@tonic-gate 
10766fec3791Sjesseb 	/* all checks complete, fill in the config */
10776fec3791Sjesseb 	newvol.targetid = t[0];
10786fec3791Sjesseb 	newvol.disk[0] = t[0];
10796fec3791Sjesseb 	newvol.raid_level = rlevel;
10806fec3791Sjesseb 	newvol.ndisks = ndisks;
10816fec3791Sjesseb 	newvol.raid_capacity = capacity;
10827c478bd9Sstevel@tonic-gate 
10836fec3791Sjesseb 	/* populate config.disk, and unconfigure all disks, except targetid */
10846fec3791Sjesseb 	for (i = 1; i < ndisks; i++) {
10857c478bd9Sstevel@tonic-gate 		if (do_config_change_state(CFGA_CMD_UNCONFIGURE,
10866fec3791Sjesseb 		    t[i], c[0])) {
10877c478bd9Sstevel@tonic-gate 			perror("config_change_state");
10886fec3791Sjesseb 			goto fail;
10896fec3791Sjesseb 		}
10906fec3791Sjesseb 		newvol.disk[i] = t[i];
10917c478bd9Sstevel@tonic-gate 	}
10927c478bd9Sstevel@tonic-gate 
10936fec3791Sjesseb 	if (ioctl(fd, RAID_CREATE, &newvol)) {
10946fec3791Sjesseb 		/* reconfigure all disks, except targetid */
10956fec3791Sjesseb 		for (i = 1; i < ndisks; i++) {
10967c478bd9Sstevel@tonic-gate 			(void) do_config_change_state(CFGA_CMD_CONFIGURE,
10976fec3791Sjesseb 				newvol.disk[i], c[0]);
10986fec3791Sjesseb 		}
10997c478bd9Sstevel@tonic-gate 		raidctl_error("RAID_CREATE");
11006fec3791Sjesseb 		goto fail;
11017c478bd9Sstevel@tonic-gate 	}
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate 	(void) printf(gettext("Volume 'c%dt%dd0' created\n"), c[0], t[0]);
11047c478bd9Sstevel@tonic-gate 	(void) close(fd);
11057c478bd9Sstevel@tonic-gate 	(void) close(fd2);
11067c478bd9Sstevel@tonic-gate 	return (SUCCESS);
11077c478bd9Sstevel@tonic-gate 
11086fec3791Sjesseb fail:
11098ba1bcfcSdduvall 	(void) close(fd);
11106fec3791Sjesseb 	(void) close(fd2);
11117c478bd9Sstevel@tonic-gate 	return (FAILURE);
11127c478bd9Sstevel@tonic-gate }
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate static int
11156fec3791Sjesseb do_delete(char *d, int force)
11167c478bd9Sstevel@tonic-gate {
11178ba1bcfcSdduvall 	raid_config_t	config;
11187c478bd9Sstevel@tonic-gate 	char		disk1[MAXPATHLEN];
11197c478bd9Sstevel@tonic-gate 	char		buf[MAXPATHLEN];
11207c478bd9Sstevel@tonic-gate 	int		fd;
11217c478bd9Sstevel@tonic-gate 	int		target;
11227c478bd9Sstevel@tonic-gate 	int		ctrl;
11236fec3791Sjesseb 	int		i, j;
11246fec3791Sjesseb 	int		wrong_targ = 0;
11256fec3791Sjesseb 	int		nvols;
11267c478bd9Sstevel@tonic-gate 	uint8_t		t;
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 	(void) chdir(DEVDIR);
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 	if ((sscanf(d, "c%dt%dd0", &ctrl, &target)) != 2) {
11317c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Invalid disk format.\n"));
11327c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
11337c478bd9Sstevel@tonic-gate 	}
11347c478bd9Sstevel@tonic-gate 	t = (uint8_t)target;
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 	(void) snprintf(disk1, sizeof (disk1), DEVDIR"/%ss2", d);
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate 	if (get_devctl(disk1, buf) != 0) {
11396fec3791Sjesseb 		(void) fprintf(stderr, gettext("Not a volume '%s'\n"), d);
11407c478bd9Sstevel@tonic-gate 		return (FAILURE);
11417c478bd9Sstevel@tonic-gate 	}
11427c478bd9Sstevel@tonic-gate 
11437c478bd9Sstevel@tonic-gate 	fd = open(buf, O_RDONLY);
11447c478bd9Sstevel@tonic-gate 	if (fd == -1) {
11457c478bd9Sstevel@tonic-gate 		perror(buf);
11467c478bd9Sstevel@tonic-gate 		return (FAILURE);
11477c478bd9Sstevel@tonic-gate 	}
11487c478bd9Sstevel@tonic-gate 
11496fec3791Sjesseb 	if (ioctl(fd, RAID_NUMVOLUMES, &nvols)) {
11506fec3791Sjesseb 		raidctl_error("RAID_NUMVOLUMES");
11516fec3791Sjesseb 		goto fail;
11526fec3791Sjesseb 	}
11536fec3791Sjesseb 
11546fec3791Sjesseb 	for (i = 0; i < nvols; i++) {
11556fec3791Sjesseb 		config.unitid = i;
11567c478bd9Sstevel@tonic-gate 		if (ioctl(fd, RAID_GETCONFIG, &config)) {
11577c478bd9Sstevel@tonic-gate 			raidctl_error("RAID_GETCONFIG");
11587c478bd9Sstevel@tonic-gate 			goto fail;
11597c478bd9Sstevel@tonic-gate 		}
11606fec3791Sjesseb 		if (config.ndisks != 0) {
11616fec3791Sjesseb 			/* there is a RAID volume in this slot */
11626fec3791Sjesseb 			if (config.targetid != t) {
11636fec3791Sjesseb 				wrong_targ++;
11646fec3791Sjesseb 				continue;
11656fec3791Sjesseb 			}
11666fec3791Sjesseb 			/* and it's our target */
11676fec3791Sjesseb 			break;
11686fec3791Sjesseb 		}
11696fec3791Sjesseb 	}
11707c478bd9Sstevel@tonic-gate 
11716fec3791Sjesseb 	if (i == nvols) {
11726fec3791Sjesseb 		/* we found no RAID volumes */
11736fec3791Sjesseb 		(void) fprintf(stderr, gettext("No RAID volumes exist on "
11747c478bd9Sstevel@tonic-gate 			"controller '%d'\n"), ctrl);
11757c478bd9Sstevel@tonic-gate 		goto fail;
11767c478bd9Sstevel@tonic-gate 	}
11777c478bd9Sstevel@tonic-gate 
11786fec3791Sjesseb 	if (wrong_targ == nvols) {
11796fec3791Sjesseb 		/* we found RAID volumes, but none matched */
11807c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
11817c478bd9Sstevel@tonic-gate 			gettext("RAID volume 'c%dt%dd0' does not exist\n"),
11827c478bd9Sstevel@tonic-gate 			ctrl, t);
11837c478bd9Sstevel@tonic-gate 		goto fail;
11847c478bd9Sstevel@tonic-gate 	}
11857c478bd9Sstevel@tonic-gate 
11866fec3791Sjesseb 	/* if this volume is a stripe, all data will be lost */
11876fec3791Sjesseb 	if (config.raid_level == RAID_STRIPE) {
11886fec3791Sjesseb 		if (disk_mounted(d)) {
11896fec3791Sjesseb 			(void) fprintf(stderr, gettext("Cannot delete "
11906fec3791Sjesseb 				"RAID0 volume, \"%s\" is mounted.\n"), d);
11916fec3791Sjesseb 			return (INVALID_ARG);
11926fec3791Sjesseb 		}
11936fec3791Sjesseb 
11946fec3791Sjesseb 		if (!force) {
11956fec3791Sjesseb 			(void) fprintf(stderr, gettext("Deleting volume "
11966fec3791Sjesseb 				"c%dt%dd0 will destroy all data it contains, "
11976fec3791Sjesseb 				"proceed (%s/%s)? "), ctrl, t, yeschr, nochr);
11986fec3791Sjesseb 			if (!yes()) {
11996fec3791Sjesseb 				(void) fprintf(stderr, gettext("RAID volume "
12006fec3791Sjesseb 					"c%dt%dd0 not deleted.\n\n"), ctrl, t);
12016fec3791Sjesseb 				(void) close(fd);
12026fec3791Sjesseb 				return (SUCCESS);
12036fec3791Sjesseb 			}
12046fec3791Sjesseb 		}
12056fec3791Sjesseb 	}
12066fec3791Sjesseb 
12077c478bd9Sstevel@tonic-gate 	if (ioctl(fd, RAID_DELETE, &t)) {
12087c478bd9Sstevel@tonic-gate 		perror("RAID_DELETE");
12097c478bd9Sstevel@tonic-gate 		goto fail;
12107c478bd9Sstevel@tonic-gate 	}
12117c478bd9Sstevel@tonic-gate 
12126fec3791Sjesseb 	/* reconfigure all disks, except targetid */
12136fec3791Sjesseb 	for (j = 1; j < config.ndisks; j++) {
12146fec3791Sjesseb 		(void) do_config_change_state(CFGA_CMD_CONFIGURE,
12156fec3791Sjesseb 			config.disk[j], ctrl);
12166fec3791Sjesseb 	}
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("Volume 'c%dt%dd0' deleted.\n"),
12197c478bd9Sstevel@tonic-gate 		ctrl, target);
12207c478bd9Sstevel@tonic-gate 	(void) close(fd);
12217c478bd9Sstevel@tonic-gate 	return (SUCCESS);
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate fail:
12247c478bd9Sstevel@tonic-gate 	(void) close(fd);
12257c478bd9Sstevel@tonic-gate 	return (FAILURE);
12267c478bd9Sstevel@tonic-gate }
12277c478bd9Sstevel@tonic-gate 
1228*7f000930Syw161884 static void
1229*7f000930Syw161884 getimagetype(uint8_t *rombuf, int *imagetype)
1230*7f000930Syw161884 {
1231*7f000930Syw161884 	uint8_t type = rombuf[gw(&rombuf[PCIR_OFF]) + PCIR_CODETYPE];
1232*7f000930Syw161884 	if (type == 0) {
1233*7f000930Syw161884 		*imagetype = BIOS_IMAGE;
1234*7f000930Syw161884 		return;
1235*7f000930Syw161884 	}
1236*7f000930Syw161884 	if (type == 1) {
1237*7f000930Syw161884 		*imagetype = FCODE_IMAGE;
1238*7f000930Syw161884 		return;
1239*7f000930Syw161884 	}
1240*7f000930Syw161884 }
1241*7f000930Syw161884 
12427c478bd9Sstevel@tonic-gate static int
12437c478bd9Sstevel@tonic-gate getfcodever(uint8_t *rombuf, uint32_t nbytes, char **fcodeversion)
12447c478bd9Sstevel@tonic-gate {
12457c478bd9Sstevel@tonic-gate 	int x, y, size;
12467c478bd9Sstevel@tonic-gate 	int found_1 = 0, found_2 = 0;
12477c478bd9Sstevel@tonic-gate 	int image_length = 0;
12487c478bd9Sstevel@tonic-gate 	int no_of_images = 0;
12497c478bd9Sstevel@tonic-gate 	uint8_t *rombuf_1 = NULL;
12507c478bd9Sstevel@tonic-gate 	uint16_t image_units = 0;
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 	/*
12537c478bd9Sstevel@tonic-gate 	 * Single Image - Open firmware image
12547c478bd9Sstevel@tonic-gate 	 */
12557c478bd9Sstevel@tonic-gate 	if (rombuf[gw(&rombuf[PCIR_OFF]) + PCIR_CODETYPE] == 1) {
12567c478bd9Sstevel@tonic-gate 		rombuf_1 = rombuf + gw(rombuf + PCIR_OFF) + PCI_PDS_INDICATOR;
12577c478bd9Sstevel@tonic-gate 		no_of_images = 1;
12587c478bd9Sstevel@tonic-gate 		goto process_image;
12597c478bd9Sstevel@tonic-gate 	}
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate 	/*
12627c478bd9Sstevel@tonic-gate 	 * Combined Image - First Image - x86/PC-AT Bios image
12637c478bd9Sstevel@tonic-gate 	 */
12647c478bd9Sstevel@tonic-gate 	if (rombuf[gw(&rombuf[PCIR_OFF]) + PCIR_CODETYPE] != 0) {
12657c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("This is neither open image"
12667c478bd9Sstevel@tonic-gate 			    " nor Bios/Fcode combined image\n"));
12677c478bd9Sstevel@tonic-gate 		return (1);
12687c478bd9Sstevel@tonic-gate 	}
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 	/*
12717c478bd9Sstevel@tonic-gate 	 * Seek to 2nd Image
12727c478bd9Sstevel@tonic-gate 	 */
12737c478bd9Sstevel@tonic-gate 	rombuf_1 = rombuf + gw(rombuf + PCI_ROM_PCI_DATA_STRUCT_PTR);
12747c478bd9Sstevel@tonic-gate 	image_units = gw(rombuf_1 + PCI_PDS_IMAGE_LENGTH);
12757c478bd9Sstevel@tonic-gate 	image_length = image_units * PCI_IMAGE_UNIT_SIZE;
12767c478bd9Sstevel@tonic-gate 	rombuf_1 += image_length;
12777c478bd9Sstevel@tonic-gate 
12787c478bd9Sstevel@tonic-gate 	/*
12797c478bd9Sstevel@tonic-gate 	 * Combined Image - Second Image - Open Firmware image
12807c478bd9Sstevel@tonic-gate 	 */
12817c478bd9Sstevel@tonic-gate 	if (rombuf_1[PCI_PDS_CODE_TYPE] != 1) {
12827c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("This is neither open image"
12837c478bd9Sstevel@tonic-gate 			    " nor Bios/Fcode combined image\n"));
12847c478bd9Sstevel@tonic-gate 		return (1);
12857c478bd9Sstevel@tonic-gate 	}
12867c478bd9Sstevel@tonic-gate 	rombuf_1 += PCI_PDS_INDICATOR;
12877c478bd9Sstevel@tonic-gate 	no_of_images = 2;
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate process_image:
12907c478bd9Sstevel@tonic-gate 	/*
12917c478bd9Sstevel@tonic-gate 	 * This should be the last image
12927c478bd9Sstevel@tonic-gate 	 */
12937c478bd9Sstevel@tonic-gate 	if (*rombuf_1 != LAST_IMAGE) {
12947c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("This is not a valid "
12957c478bd9Sstevel@tonic-gate 		    "Bios/Fcode image file\n"));
12967c478bd9Sstevel@tonic-gate 		return (1);
12977c478bd9Sstevel@tonic-gate 	}
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate 	/*
1300*7f000930Syw161884 	 * Scan through the bios/fcode file to get the fcode version
13017c478bd9Sstevel@tonic-gate 	 * 0x12 and 0x7 indicate the start of the fcode version string
13027c478bd9Sstevel@tonic-gate 	 */
13037c478bd9Sstevel@tonic-gate 	for (x = 0; x < (nbytes - 8); x++) {
13047c478bd9Sstevel@tonic-gate 		if ((rombuf[x] == FCODE_VERS_KEY1) &&
13057c478bd9Sstevel@tonic-gate 		    (rombuf[x+1] == FCODE_VERS_KEY2) &&
13067c478bd9Sstevel@tonic-gate 		    (rombuf[x+2] == 'v') && (rombuf[x+3] == 'e') &&
13077c478bd9Sstevel@tonic-gate 		    (rombuf[x+4] == 'r') && (rombuf[x+5] == 's') &&
13087c478bd9Sstevel@tonic-gate 		    (rombuf[x+6] == 'i') && (rombuf[x+7] == 'o') &&
13097c478bd9Sstevel@tonic-gate 		    (rombuf[x+8] == 'n')) {
13107c478bd9Sstevel@tonic-gate 			found_1 = 1;
13117c478bd9Sstevel@tonic-gate 			break;
13127c478bd9Sstevel@tonic-gate 		}
13137c478bd9Sstevel@tonic-gate 	}
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate 	/*
13167c478bd9Sstevel@tonic-gate 	 * Store the version string if we have found the beginning of it
13177c478bd9Sstevel@tonic-gate 	 */
13187c478bd9Sstevel@tonic-gate 	if (found_1) {
13197c478bd9Sstevel@tonic-gate 		while (x > 0) {
13207c478bd9Sstevel@tonic-gate 			if (rombuf[--x] == FCODE_VERS_KEY1) {
13217c478bd9Sstevel@tonic-gate 				if (rombuf[x-1] != FCODE_VERS_KEY1) {
13227c478bd9Sstevel@tonic-gate 					x++;
13237c478bd9Sstevel@tonic-gate 				}
13247c478bd9Sstevel@tonic-gate 				break;
13257c478bd9Sstevel@tonic-gate 			}
13267c478bd9Sstevel@tonic-gate 		}
13277c478bd9Sstevel@tonic-gate 		if (x > 0) {
13287c478bd9Sstevel@tonic-gate 			*fcodeversion = (char *)malloc(rombuf[x] + 1);
13297c478bd9Sstevel@tonic-gate 			for (y = 0; y < rombuf[x]; y++) {
13307c478bd9Sstevel@tonic-gate 				(*fcodeversion)[y] = rombuf[x+y+1];
13317c478bd9Sstevel@tonic-gate 			}
13327c478bd9Sstevel@tonic-gate 			(*fcodeversion)[y] = '\0';
13337c478bd9Sstevel@tonic-gate 		} else {
13347c478bd9Sstevel@tonic-gate 			found_1 = 0;
13357c478bd9Sstevel@tonic-gate 		}
13367c478bd9Sstevel@tonic-gate 	}
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate 	/*
1339*7f000930Syw161884 	 * Scan through the bios/fcode file to get the Bios version
13407c478bd9Sstevel@tonic-gate 	 * "@(#)" string indicates the start of the Bios version string
13417c478bd9Sstevel@tonic-gate 	 * Append this version string, after already existing fcode version.
13427c478bd9Sstevel@tonic-gate 	 */
13437c478bd9Sstevel@tonic-gate 	if (no_of_images == 2) {
13447c478bd9Sstevel@tonic-gate 		for (x = 0; x < (nbytes - 4); x++) {
13457c478bd9Sstevel@tonic-gate 			if ((rombuf[x] == '@') && (rombuf[x+1] == '(') &&
13467c478bd9Sstevel@tonic-gate 			    (rombuf[x+2] == '#') && (rombuf[x+3] == ')')) {
13477c478bd9Sstevel@tonic-gate 				found_2 = 1;
13487c478bd9Sstevel@tonic-gate 				break;
13497c478bd9Sstevel@tonic-gate 			}
13507c478bd9Sstevel@tonic-gate 		}
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate 		if (found_2) {
13537c478bd9Sstevel@tonic-gate 			x += 4;
13547c478bd9Sstevel@tonic-gate 			(*fcodeversion)[y] = '\n';
13557c478bd9Sstevel@tonic-gate 			size = y + strlen((char *)(rombuf + x)) +
13567c478bd9Sstevel@tonic-gate 			    strlen(BIOS_STR) + 2;
13577c478bd9Sstevel@tonic-gate 			*fcodeversion = (char *)realloc((*fcodeversion), size);
13587c478bd9Sstevel@tonic-gate 			y++;
13597c478bd9Sstevel@tonic-gate 			(*fcodeversion)[y] = '\0';
13607c478bd9Sstevel@tonic-gate 			(void) strlcat(*fcodeversion, BIOS_STR, size);
13617c478bd9Sstevel@tonic-gate 			(void) strlcat(*fcodeversion, (char *)(rombuf + x),
13627c478bd9Sstevel@tonic-gate 			    size);
13637c478bd9Sstevel@tonic-gate 		}
13647c478bd9Sstevel@tonic-gate 	}
13657c478bd9Sstevel@tonic-gate 
13667c478bd9Sstevel@tonic-gate 	return ((found_1 || found_2) ? 0 : 1);
13677c478bd9Sstevel@tonic-gate }
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate static void
13707c478bd9Sstevel@tonic-gate getfwver(uint8_t *rombuf, char *fwversion)
13717c478bd9Sstevel@tonic-gate {
13727c478bd9Sstevel@tonic-gate 	(void) snprintf(fwversion, 8, "%d.%.2d.%.2d.%.2d",
13737c478bd9Sstevel@tonic-gate 		rombuf[FW_ROM_OFFSET_VERSION + 3],
13747c478bd9Sstevel@tonic-gate 		rombuf[FW_ROM_OFFSET_VERSION + 2],
13757c478bd9Sstevel@tonic-gate 		rombuf[FW_ROM_OFFSET_VERSION + 1],
13767c478bd9Sstevel@tonic-gate 		rombuf[FW_ROM_OFFSET_VERSION + 0]);
13777c478bd9Sstevel@tonic-gate }
13787c478bd9Sstevel@tonic-gate 
13797c478bd9Sstevel@tonic-gate static int
1380*7f000930Syw161884 getbioscodever(uint8_t *rombuf, uint32_t nbytes, char **biosversion)
1381*7f000930Syw161884 {
1382*7f000930Syw161884 	int x, size;
1383*7f000930Syw161884 	int found = 0;
1384*7f000930Syw161884 
1385*7f000930Syw161884 	for (x = 0; x < (nbytes - 4); x++) {
1386*7f000930Syw161884 		if ((rombuf[x] == '@') && (rombuf[x+1] == '(') &&
1387*7f000930Syw161884 		    (rombuf[x+2] == '#') && (rombuf[x+3] == ')')) {
1388*7f000930Syw161884 			found = 1;
1389*7f000930Syw161884 			break;
1390*7f000930Syw161884 		}
1391*7f000930Syw161884 	}
1392*7f000930Syw161884 
1393*7f000930Syw161884 	if (found) {
1394*7f000930Syw161884 		x += 4;
1395*7f000930Syw161884 		size = strlen((char *)(rombuf + x)) + strlen(BIOS_STR) + 1;
1396*7f000930Syw161884 		*biosversion = (char *)realloc((*biosversion), size);
1397*7f000930Syw161884 		bcopy((char *)(rombuf + x), *biosversion, size - 1);
1398*7f000930Syw161884 		(*biosversion)[size - 1] = '\0';
1399*7f000930Syw161884 	}
1400*7f000930Syw161884 
1401*7f000930Syw161884 	return (found);
1402*7f000930Syw161884 
1403*7f000930Syw161884 }
1404*7f000930Syw161884 
1405*7f000930Syw161884 static int
14067c478bd9Sstevel@tonic-gate checkfile(uint8_t *rombuf, uint32_t nbytes, uint32_t chksum, int *imagetype)
14077c478bd9Sstevel@tonic-gate {
14087c478bd9Sstevel@tonic-gate 	char *imageversion = NULL;
1409*7f000930Syw161884 	char *biosversion = NULL;
14107c478bd9Sstevel@tonic-gate 	char *fwversion;
14117c478bd9Sstevel@tonic-gate 
14127c478bd9Sstevel@tonic-gate 	fwversion = (char *)malloc(8);
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 	if (gw(&rombuf[0]) == PCIROM_SIG) {
1415*7f000930Syw161884 
14167c478bd9Sstevel@tonic-gate 		*imagetype = UNKNOWN_IMAGE;
1417*7f000930Syw161884 		getimagetype(rombuf, imagetype);
1418*7f000930Syw161884 
1419*7f000930Syw161884 		if (*imagetype == FCODE_IMAGE) {
1420*7f000930Syw161884 			if (getfcodever(rombuf, nbytes, &imageversion) == 0 &&
1421*7f000930Syw161884 			    imageversion != NULL) {
1422*7f000930Syw161884 				(void) printf(gettext("Image file contains "
1423*7f000930Syw161884 				    "fcode version \t%s\n"), imageversion);
14247c478bd9Sstevel@tonic-gate 				free(imageversion);
1425*7f000930Syw161884 			}
1426*7f000930Syw161884 		} else if (*imagetype == BIOS_IMAGE) {
1427*7f000930Syw161884 			if (getbioscodever(rombuf, nbytes, &biosversion) == 1 &&
1428*7f000930Syw161884 			    biosversion != NULL) {
1429*7f000930Syw161884 				(void) printf(gettext("Image file contains "
1430*7f000930Syw161884 				    "BIOS version \t%s\n"), biosversion);
1431*7f000930Syw161884 				free(biosversion);
1432*7f000930Syw161884 			}
14337c478bd9Sstevel@tonic-gate 		} else {
1434*7f000930Syw161884 			/* When imagetype equals to UNKNOWN_IMAGE */
14357c478bd9Sstevel@tonic-gate 			return (-1);
14367c478bd9Sstevel@tonic-gate 		}
1437*7f000930Syw161884 
14387c478bd9Sstevel@tonic-gate 	} else if (gw(&rombuf[3]) == FW_ROM_ID) {
14397c478bd9Sstevel@tonic-gate 			if (chksum != 0) {
14407c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
14417c478bd9Sstevel@tonic-gate 					gettext("The ROM checksum appears bad "
14427c478bd9Sstevel@tonic-gate 					"(%d)\n"), chksum);
14437c478bd9Sstevel@tonic-gate 				return (-1);
14447c478bd9Sstevel@tonic-gate 			}
14457c478bd9Sstevel@tonic-gate 			getfwver(rombuf, fwversion);
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 			if ((gw(&rombuf[FW_ROM_OFFSET_CHIP_TYPE]) &
14487c478bd9Sstevel@tonic-gate 				MPI_FW_HEADER_PID_PROD_MASK) ==
14497c478bd9Sstevel@tonic-gate 				MPI_FW_HEADER_PID_PROD_IM_SCSI) {
14507c478bd9Sstevel@tonic-gate 				(void) printf(gettext("ROM image contains "
14517c478bd9Sstevel@tonic-gate 					"MPT firmware version %s "
14527c478bd9Sstevel@tonic-gate 					"(w/Integrated Mirroring)\n"),
14537c478bd9Sstevel@tonic-gate 						fwversion);
14547c478bd9Sstevel@tonic-gate 			} else {
14557c478bd9Sstevel@tonic-gate 				(void) printf(gettext("ROM image contains "
14567c478bd9Sstevel@tonic-gate 					"MPT firmware ""version %s\n"),
14577c478bd9Sstevel@tonic-gate 						fwversion);
14587c478bd9Sstevel@tonic-gate 			}
14597c478bd9Sstevel@tonic-gate 			free(fwversion);
14607c478bd9Sstevel@tonic-gate 	} else {
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate #ifdef	DEBUG
14637c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "Not valid FCODE image %x\n", gw(&rombuf[0]));
14647c478bd9Sstevel@tonic-gate #else
14657c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("Not valid FCODE image\n"));
14667c478bd9Sstevel@tonic-gate #endif
14677c478bd9Sstevel@tonic-gate 		return (-1);
14687c478bd9Sstevel@tonic-gate 	}
14697c478bd9Sstevel@tonic-gate 	return (0);
14707c478bd9Sstevel@tonic-gate }
14717c478bd9Sstevel@tonic-gate 
14727c478bd9Sstevel@tonic-gate static int
14737c478bd9Sstevel@tonic-gate updateflash(uint8_t *rombuf, uint32_t nbytes, char *devctl)
14747c478bd9Sstevel@tonic-gate {
14757c478bd9Sstevel@tonic-gate 	int fd = 0;
14767c478bd9Sstevel@tonic-gate 	update_flash_t flashdata;
14777c478bd9Sstevel@tonic-gate 
14787c478bd9Sstevel@tonic-gate 	fd = open(devctl, O_RDONLY);
14797c478bd9Sstevel@tonic-gate 	if (fd == -1) {
14807c478bd9Sstevel@tonic-gate 		perror(devctl);
14817c478bd9Sstevel@tonic-gate 		return (-1);
14827c478bd9Sstevel@tonic-gate 	}
14837c478bd9Sstevel@tonic-gate 	(void) memset(&flashdata, 0, sizeof (flashdata));
14847c478bd9Sstevel@tonic-gate 	flashdata.ptrbuffer = (caddr_t)rombuf;
14857c478bd9Sstevel@tonic-gate 	flashdata.size = nbytes;
14867c478bd9Sstevel@tonic-gate 	if ((rombuf[0] == 0x55) && (rombuf[1] == 0xaa)) {
14877c478bd9Sstevel@tonic-gate 		flashdata.type = FW_TYPE_FCODE;
14887c478bd9Sstevel@tonic-gate 	} else {
14897c478bd9Sstevel@tonic-gate 		flashdata.type = FW_TYPE_UCODE;
14907c478bd9Sstevel@tonic-gate 	}
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate 	if (ioctl(fd, RAID_UPDATEFW, &flashdata)) {
14937c478bd9Sstevel@tonic-gate 		raidctl_error("RAID_UPDATEFW");
14947c478bd9Sstevel@tonic-gate 		(void) close(fd);
14957c478bd9Sstevel@tonic-gate 		return (-1);
14967c478bd9Sstevel@tonic-gate 	}
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 	(void) close(fd);
14997c478bd9Sstevel@tonic-gate 	return (0);
15007c478bd9Sstevel@tonic-gate }
15017c478bd9Sstevel@tonic-gate 
15027c478bd9Sstevel@tonic-gate static int
15037c478bd9Sstevel@tonic-gate readfile(char *filespec, uint8_t **rombuf, uint32_t *nbytes, uint32_t *chksum)
15047c478bd9Sstevel@tonic-gate {
15057c478bd9Sstevel@tonic-gate 	struct stat	statbuf;
15067c478bd9Sstevel@tonic-gate 	uint32_t	count;
15077c478bd9Sstevel@tonic-gate 	uint32_t	checksum = 0;
15087c478bd9Sstevel@tonic-gate 	int		fd, i;
15097c478bd9Sstevel@tonic-gate 	uint8_t		*filebuf;
15107c478bd9Sstevel@tonic-gate 
15117c478bd9Sstevel@tonic-gate 
15127c478bd9Sstevel@tonic-gate 	if ((fd = open((const char *)filespec, O_RDONLY | O_NDELAY)) == -1) {
15137c478bd9Sstevel@tonic-gate 		perror(filespec);
15147c478bd9Sstevel@tonic-gate 		return (-1);
15157c478bd9Sstevel@tonic-gate 	}
15167c478bd9Sstevel@tonic-gate 
15177c478bd9Sstevel@tonic-gate 	if (fstat(fd, &statbuf) != 0) {
15187c478bd9Sstevel@tonic-gate 		perror("fstat");
15197c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
15207c478bd9Sstevel@tonic-gate 			gettext("Error getting stats on file\n"));
15217c478bd9Sstevel@tonic-gate 		(void) close(fd);
15227c478bd9Sstevel@tonic-gate 		return (-1);
15237c478bd9Sstevel@tonic-gate 	}
15247c478bd9Sstevel@tonic-gate 
15257c478bd9Sstevel@tonic-gate #ifdef	DEBUG
15267c478bd9Sstevel@tonic-gate 	(void) printf("Filesize = %ld\n", statbuf.st_size);
15277c478bd9Sstevel@tonic-gate #endif
15287c478bd9Sstevel@tonic-gate 
15297c478bd9Sstevel@tonic-gate 	filebuf = (uint8_t *)realloc(*rombuf, statbuf.st_size + *nbytes);
15307c478bd9Sstevel@tonic-gate 
15317c478bd9Sstevel@tonic-gate 	count = read(fd, filebuf + *nbytes, statbuf.st_size);
15327c478bd9Sstevel@tonic-gate 	(void) close(fd);
15337c478bd9Sstevel@tonic-gate 	if (count != statbuf.st_size) {
15347c478bd9Sstevel@tonic-gate 		perror("size check");
15357c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("File is corrupt\n"));
15367c478bd9Sstevel@tonic-gate 		return (-1);
15377c478bd9Sstevel@tonic-gate 	}
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate 	for (i = 0; i < *nbytes; i++)
15407c478bd9Sstevel@tonic-gate 		checksum += filebuf[i] << (8 * (i & 3));
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate 	*rombuf = filebuf;
15437c478bd9Sstevel@tonic-gate 	*nbytes = *nbytes + count;
15447c478bd9Sstevel@tonic-gate 	*chksum = checksum;
15457c478bd9Sstevel@tonic-gate 
15467c478bd9Sstevel@tonic-gate 	return (0);
15477c478bd9Sstevel@tonic-gate }
15487c478bd9Sstevel@tonic-gate 
15497c478bd9Sstevel@tonic-gate static int
15506fec3791Sjesseb yes(void)
15517c478bd9Sstevel@tonic-gate {
15527c478bd9Sstevel@tonic-gate 	int	i, b;
15537c478bd9Sstevel@tonic-gate 	char    ans[SCHAR_MAX + 1];
15547c478bd9Sstevel@tonic-gate 
15557c478bd9Sstevel@tonic-gate 	for (i = 0; ; i++) {
15567c478bd9Sstevel@tonic-gate 		b = getchar();
15577c478bd9Sstevel@tonic-gate 		if (b == '\n' || b == '\0' || b == EOF) {
15587c478bd9Sstevel@tonic-gate 			ans[i] = 0;
15597c478bd9Sstevel@tonic-gate 			break;
15607c478bd9Sstevel@tonic-gate 		}
15617c478bd9Sstevel@tonic-gate 		if (i < SCHAR_MAX)
15627c478bd9Sstevel@tonic-gate 			ans[i] = b;
15637c478bd9Sstevel@tonic-gate 	}
15647c478bd9Sstevel@tonic-gate 	if (i >= SCHAR_MAX) {
15657c478bd9Sstevel@tonic-gate 		i = SCHAR_MAX;
15667c478bd9Sstevel@tonic-gate 		ans[SCHAR_MAX] = 0;
15677c478bd9Sstevel@tonic-gate 	}
15686fec3791Sjesseb 	if ((i != 0) && ((strncmp(yeschr, ans, i)) == 0))
15697c478bd9Sstevel@tonic-gate 		return (1);
15706fec3791Sjesseb 
15717c478bd9Sstevel@tonic-gate 	return (0);
15727c478bd9Sstevel@tonic-gate }
15737c478bd9Sstevel@tonic-gate 
15747c478bd9Sstevel@tonic-gate static int
15757c478bd9Sstevel@tonic-gate do_flash(int c, char *fpath, int force)
15767c478bd9Sstevel@tonic-gate {
15777c478bd9Sstevel@tonic-gate 	char		devctl[MAXPATHLEN] = {0};
15787c478bd9Sstevel@tonic-gate 	char		buf[MAXPATHLEN] = {0};
15797c478bd9Sstevel@tonic-gate 	int		rv = 0;
15807c478bd9Sstevel@tonic-gate 	int		imagetype;
15817c478bd9Sstevel@tonic-gate 	uint32_t	nbytes = 0;
15827c478bd9Sstevel@tonic-gate 	uint32_t	chksum;
15837c478bd9Sstevel@tonic-gate 	uint8_t		*rombuf = NULL;
15847c478bd9Sstevel@tonic-gate 	char		cwd[MAXPATHLEN];
15857c478bd9Sstevel@tonic-gate 
15867c478bd9Sstevel@tonic-gate 	/*
15877c478bd9Sstevel@tonic-gate 	 * Read fw file
15887c478bd9Sstevel@tonic-gate 	 */
15897c478bd9Sstevel@tonic-gate 	rv = readfile(fpath, &rombuf, &nbytes, &chksum);
15907c478bd9Sstevel@tonic-gate 	if (rv != 0) {
15917c478bd9Sstevel@tonic-gate 		return (FAILURE);
15927c478bd9Sstevel@tonic-gate 	}
15937c478bd9Sstevel@tonic-gate 
15947c478bd9Sstevel@tonic-gate 	(void) getcwd(cwd, sizeof (cwd));
15957c478bd9Sstevel@tonic-gate 
15967c478bd9Sstevel@tonic-gate 	(void) chdir(DEVDIR);
15977c478bd9Sstevel@tonic-gate 
15987c478bd9Sstevel@tonic-gate 	/* Get link from "/dev/cfg" */
15997c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "/dev/cfg/c%d", c);
16007c478bd9Sstevel@tonic-gate 	if (get_link_path(buf, devctl) != 0) {
16017c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
16027c478bd9Sstevel@tonic-gate 			gettext("Invalid controller '%d'\n"), c);
16037c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
16047c478bd9Sstevel@tonic-gate 	}
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate 	/* Check File */
16077c478bd9Sstevel@tonic-gate 	rv = checkfile(rombuf, nbytes, chksum, &imagetype);
16087c478bd9Sstevel@tonic-gate 	if (rv != 0) {
16097c478bd9Sstevel@tonic-gate 		return (FAILURE);
16107c478bd9Sstevel@tonic-gate 	}
16117c478bd9Sstevel@tonic-gate 
16127c478bd9Sstevel@tonic-gate 	/* Confirm */
16137c478bd9Sstevel@tonic-gate 	if (!force) {
16147c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Update flash image on "
16157c478bd9Sstevel@tonic-gate 			"controller %d (%s/%s)? "), c, yeschr, nochr);
16166fec3791Sjesseb 		if (!yes()) {
16176fec3791Sjesseb 			(void) fprintf(stderr, gettext("Controller %d not "
16186fec3791Sjesseb 			    "flashed.\n\n"), c);
16197c478bd9Sstevel@tonic-gate 			return (SUCCESS);
16207c478bd9Sstevel@tonic-gate 		}
16217c478bd9Sstevel@tonic-gate 	}
16227c478bd9Sstevel@tonic-gate 
16237c478bd9Sstevel@tonic-gate 	/* Do Flash */
16247c478bd9Sstevel@tonic-gate 	if (updateflash(rombuf, nbytes, devctl)) {
16257c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Flash not updated on "
16267c478bd9Sstevel@tonic-gate 		    "Controller %d.\n\n"), c);
16277c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
16287c478bd9Sstevel@tonic-gate 	}
16297c478bd9Sstevel@tonic-gate 	(void) printf(gettext("Flash updated successfully.\n\n"));
16307c478bd9Sstevel@tonic-gate 	return (SUCCESS);
16317c478bd9Sstevel@tonic-gate }
16327c478bd9Sstevel@tonic-gate 
16337c478bd9Sstevel@tonic-gate static int
16347c478bd9Sstevel@tonic-gate fully_numeric(char *str)
16357c478bd9Sstevel@tonic-gate {
16367c478bd9Sstevel@tonic-gate 	int	size = strlen(str);
16377c478bd9Sstevel@tonic-gate 	int	i;
16387c478bd9Sstevel@tonic-gate 
16397c478bd9Sstevel@tonic-gate 	for (i = 0; i < size; i++) {
16407c478bd9Sstevel@tonic-gate 		if (i == 0 && str[i] == '-' && size != 1)
16417c478bd9Sstevel@tonic-gate 			continue;
16427c478bd9Sstevel@tonic-gate 		if (!isdigit(str[i]))
16437c478bd9Sstevel@tonic-gate 			return (0);
16447c478bd9Sstevel@tonic-gate 	}
16457c478bd9Sstevel@tonic-gate 	return (1);
16467c478bd9Sstevel@tonic-gate }
16477c478bd9Sstevel@tonic-gate 
16487c478bd9Sstevel@tonic-gate /*
16497c478bd9Sstevel@tonic-gate  * Useful parsing macros
16507c478bd9Sstevel@tonic-gate  */
16517c478bd9Sstevel@tonic-gate #define	must_be(s, c)		if (*s++ != c) return (0)
16527c478bd9Sstevel@tonic-gate #define	skip_digits(s)		while (isdigit(*s)) s++
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate /*
16557c478bd9Sstevel@tonic-gate  * Return true if a name is in the internal canonical form
16567c478bd9Sstevel@tonic-gate  */
16577c478bd9Sstevel@tonic-gate static int
16587c478bd9Sstevel@tonic-gate canonical_name(char *name)
16597c478bd9Sstevel@tonic-gate {
16607c478bd9Sstevel@tonic-gate 	must_be(name, 'c');
16617c478bd9Sstevel@tonic-gate 	skip_digits(name);
16627c478bd9Sstevel@tonic-gate 	if (*name == 't') {
16637c478bd9Sstevel@tonic-gate 		name++;
16647c478bd9Sstevel@tonic-gate 		skip_digits(name);
16657c478bd9Sstevel@tonic-gate 	}
16667c478bd9Sstevel@tonic-gate 	must_be(name, 'd');
16677c478bd9Sstevel@tonic-gate 	skip_digits(name);
16687c478bd9Sstevel@tonic-gate 	return (*name == 0);
16697c478bd9Sstevel@tonic-gate }
16707c478bd9Sstevel@tonic-gate 
16717c478bd9Sstevel@tonic-gate int
16727c478bd9Sstevel@tonic-gate main(int argc, char **argv)
16737c478bd9Sstevel@tonic-gate {
16747c478bd9Sstevel@tonic-gate 	int	rv = SUCCESS;
16757c478bd9Sstevel@tonic-gate 	int	i, c;
16767c478bd9Sstevel@tonic-gate 	int	findex = DO_HW_RAID_INFO;
16777c478bd9Sstevel@tonic-gate 	int	controller;
16786fec3791Sjesseb 	char	*disks[N_DISKS] = {0};
16797c478bd9Sstevel@tonic-gate 	char	*darg;
16807c478bd9Sstevel@tonic-gate 	char	*farg;
16816fec3791Sjesseb 	char	*rarg;
16827c478bd9Sstevel@tonic-gate 	char	*progname;
16837c478bd9Sstevel@tonic-gate 
16847c478bd9Sstevel@tonic-gate 	int	l_flag = 0;
16857c478bd9Sstevel@tonic-gate 	int	c_flag = 0;
16867c478bd9Sstevel@tonic-gate 	int	d_flag = 0;
16877c478bd9Sstevel@tonic-gate 	int	f_flag = 0;
16887c478bd9Sstevel@tonic-gate 	int	F_flag = 0;
16896fec3791Sjesseb 	int	r_flag = 0;
16907c478bd9Sstevel@tonic-gate 	int	no_flags = 1;
16916fec3791Sjesseb 	int	r = RAID_MIRROR;  /* default raid level is 1 */
16927c478bd9Sstevel@tonic-gate 	char	*current_dir;
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
16957c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
16967c478bd9Sstevel@tonic-gate 
16977c478bd9Sstevel@tonic-gate 	if (geteuid() != 0) {
16987c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Must be root.\n"));
16997c478bd9Sstevel@tonic-gate 		exit(1);
17007c478bd9Sstevel@tonic-gate 	}
17017c478bd9Sstevel@tonic-gate 
17027c478bd9Sstevel@tonic-gate 	if ((progname = strrchr(argv[0], '/')) == NULL)
17037c478bd9Sstevel@tonic-gate 		progname = argv[0];
17047c478bd9Sstevel@tonic-gate 	else
17057c478bd9Sstevel@tonic-gate 		progname++;
17067c478bd9Sstevel@tonic-gate 
17077c478bd9Sstevel@tonic-gate 	raids = NULL;
17087c478bd9Sstevel@tonic-gate 
17097c478bd9Sstevel@tonic-gate 	(void) strncpy(yeschr, nl_langinfo(YESSTR), SCHAR_MAX + 1);
17107c478bd9Sstevel@tonic-gate 	(void) strncpy(nochr, nl_langinfo(NOSTR), SCHAR_MAX + 1);
17117c478bd9Sstevel@tonic-gate 
17126fec3791Sjesseb 	while ((c = getopt(argc, argv, "cr:lfd:F:")) != EOF) {
17137c478bd9Sstevel@tonic-gate 		switch (c) {
17147c478bd9Sstevel@tonic-gate 		case 'c':
17156fec3791Sjesseb 			if (argc < 4)
17167c478bd9Sstevel@tonic-gate 				usage(progname);
17177c478bd9Sstevel@tonic-gate 			findex = DO_HW_RAID_CREATE;
17187c478bd9Sstevel@tonic-gate 			c_flag = 1;
17197c478bd9Sstevel@tonic-gate 			no_flags = 0;
17207c478bd9Sstevel@tonic-gate 			break;
17216fec3791Sjesseb 		case 'r':
17226fec3791Sjesseb 			rarg = optarg;
17236fec3791Sjesseb 			r = atoi(rarg);
17246fec3791Sjesseb 			if ((r != RAID_STRIPE) && (r != RAID_MIRROR))
17256fec3791Sjesseb 				usage(progname);
17266fec3791Sjesseb 			r_flag = 1;
17276fec3791Sjesseb 			break;
17287c478bd9Sstevel@tonic-gate 		case 'd':
17297c478bd9Sstevel@tonic-gate 			darg = optarg;
17307c478bd9Sstevel@tonic-gate 			d_flag = 1;
17317c478bd9Sstevel@tonic-gate 			findex = DO_HW_RAID_DELETE;
17327c478bd9Sstevel@tonic-gate 			no_flags = 0;
17337c478bd9Sstevel@tonic-gate 			break;
17347c478bd9Sstevel@tonic-gate 		case 'l':
17357c478bd9Sstevel@tonic-gate 			findex = DO_HW_RAID_INFO;
17367c478bd9Sstevel@tonic-gate 			l_flag = 1;
17377c478bd9Sstevel@tonic-gate 			no_flags = 0;
17387c478bd9Sstevel@tonic-gate 			break;
17397c478bd9Sstevel@tonic-gate 		case 'F':
17407c478bd9Sstevel@tonic-gate 			findex = DO_HW_RAID_FLASH;
17417c478bd9Sstevel@tonic-gate 			farg = optarg;
17427c478bd9Sstevel@tonic-gate 			F_flag = 1;
17437c478bd9Sstevel@tonic-gate 			no_flags = 0;
17447c478bd9Sstevel@tonic-gate 			break;
17457c478bd9Sstevel@tonic-gate 		case 'f':
17467c478bd9Sstevel@tonic-gate 			f_flag = 1;
17477c478bd9Sstevel@tonic-gate 			no_flags = 0;
17487c478bd9Sstevel@tonic-gate 			break;
17496fec3791Sjesseb 		case '?':
17506fec3791Sjesseb 		default:
17517c478bd9Sstevel@tonic-gate 			usage(progname);
17527c478bd9Sstevel@tonic-gate 		}
17537c478bd9Sstevel@tonic-gate 	}
17547c478bd9Sstevel@tonic-gate 
17557c478bd9Sstevel@tonic-gate 	if (no_flags && argc > 1)
17567c478bd9Sstevel@tonic-gate 		usage(progname);
17577c478bd9Sstevel@tonic-gate 
17587c478bd9Sstevel@tonic-gate 	/* compatibility rules */
17597c478bd9Sstevel@tonic-gate 	if (c_flag && d_flag)
17607c478bd9Sstevel@tonic-gate 		usage(progname);
17616fec3791Sjesseb 	if (l_flag && (d_flag || c_flag || f_flag || F_flag || r_flag))
17627c478bd9Sstevel@tonic-gate 		usage(progname);
17636fec3791Sjesseb 	if (F_flag && (d_flag || c_flag || l_flag || r_flag))
17647c478bd9Sstevel@tonic-gate 		usage(progname);
17657c478bd9Sstevel@tonic-gate 
17667c478bd9Sstevel@tonic-gate 	switch (findex) {
17677c478bd9Sstevel@tonic-gate 	case DO_HW_RAID_INFO:
17687c478bd9Sstevel@tonic-gate 		if (l_flag) {
17697c478bd9Sstevel@tonic-gate 			/*
17707c478bd9Sstevel@tonic-gate 			 * "raidctl"	makes argc == 1
17717c478bd9Sstevel@tonic-gate 			 * "-l"		makes argc == 2
17727c478bd9Sstevel@tonic-gate 			 */
17737c478bd9Sstevel@tonic-gate 			ctrl_nums = argc - 2;
17747c478bd9Sstevel@tonic-gate 			if (ctrl_nums != 0) {
17757c478bd9Sstevel@tonic-gate 				info_ctrl = (int **)
17767c478bd9Sstevel@tonic-gate 					malloc(ctrl_nums * sizeof (int));
17777c478bd9Sstevel@tonic-gate 				if (info_ctrl == NULL)
17787c478bd9Sstevel@tonic-gate 					return (FAILURE);
17797c478bd9Sstevel@tonic-gate 			}
17807c478bd9Sstevel@tonic-gate 			for (i = 0; i < ctrl_nums; i++) {
17817c478bd9Sstevel@tonic-gate 				char *tmp = argv[i + 2];
17827c478bd9Sstevel@tonic-gate 
17837c478bd9Sstevel@tonic-gate 				info_ctrl[i] = (int *)malloc(2 * sizeof (int));
17847c478bd9Sstevel@tonic-gate 				if (info_ctrl[i] == NULL) {
17857c478bd9Sstevel@tonic-gate 					free(info_ctrl);
17867c478bd9Sstevel@tonic-gate 					return (FAILURE);
17877c478bd9Sstevel@tonic-gate 				}
17887c478bd9Sstevel@tonic-gate 				if (fully_numeric(tmp)) {
17897c478bd9Sstevel@tonic-gate 					(void) sscanf(tmp, "%d",
17907c478bd9Sstevel@tonic-gate 						&info_ctrl[i][INFO_CTRL]);
17917c478bd9Sstevel@tonic-gate 					info_ctrl[i][INFO_STATUS] =
17927c478bd9Sstevel@tonic-gate 						RAID_INVALID_CTRL;
17937c478bd9Sstevel@tonic-gate 				} else {
17947c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
17957c478bd9Sstevel@tonic-gate 					gettext("Invalid controller '%s'\n"),
17967c478bd9Sstevel@tonic-gate 					tmp);
17977c478bd9Sstevel@tonic-gate 					info_ctrl[i][INFO_STATUS] =
17987c478bd9Sstevel@tonic-gate 						RAID_DONT_USE;
17997c478bd9Sstevel@tonic-gate 				}
18007c478bd9Sstevel@tonic-gate 			}
18017c478bd9Sstevel@tonic-gate 		} else if (argc > 1) {
18027c478bd9Sstevel@tonic-gate 			usage(progname);
18037c478bd9Sstevel@tonic-gate 		}
18047c478bd9Sstevel@tonic-gate 
18057c478bd9Sstevel@tonic-gate 		do_info();
18067c478bd9Sstevel@tonic-gate 		break;
18077c478bd9Sstevel@tonic-gate 	case DO_HW_RAID_CREATE:
18087c478bd9Sstevel@tonic-gate 		for (i = 0; i < N_DISKS; i++) {
18096fec3791Sjesseb 			int p = 2 + (r_flag * 2) + f_flag + i;
18106fec3791Sjesseb 
18116fec3791Sjesseb 			if (p == argc)
18126fec3791Sjesseb 				break;
18136fec3791Sjesseb 
18146fec3791Sjesseb 			disks[i] = argv[p];
18156fec3791Sjesseb 
18167c478bd9Sstevel@tonic-gate 			if (!canonical_name(disks[i]))
18177c478bd9Sstevel@tonic-gate 				usage(progname);
18186fec3791Sjesseb 
18196fec3791Sjesseb 			/* no more than 2 disks for raid level 1 */
18206fec3791Sjesseb 			if ((r == RAID_MIRROR) && (i > 1))
18216fec3791Sjesseb 				usage(progname);
18227c478bd9Sstevel@tonic-gate 		}
18236fec3791Sjesseb 
18246fec3791Sjesseb 		rv = do_create(disks, r, f_flag);
18257c478bd9Sstevel@tonic-gate 		break;
18267c478bd9Sstevel@tonic-gate 	case DO_HW_RAID_DELETE:
18277c478bd9Sstevel@tonic-gate 		if (!canonical_name(darg))
18287c478bd9Sstevel@tonic-gate 			usage(progname);
18297c478bd9Sstevel@tonic-gate 
18306fec3791Sjesseb 		rv = do_delete(darg, f_flag);
18317c478bd9Sstevel@tonic-gate 		break;
18327c478bd9Sstevel@tonic-gate 	case DO_HW_RAID_FLASH:
18337c478bd9Sstevel@tonic-gate 		ctrl_nums = argc - f_flag - 3;
18347c478bd9Sstevel@tonic-gate 		if (ctrl_nums == 0)
18357c478bd9Sstevel@tonic-gate 			usage(progname);
18367c478bd9Sstevel@tonic-gate 
18377c478bd9Sstevel@tonic-gate 		current_dir = getcwd(NULL, MAXPATHLEN);
18387c478bd9Sstevel@tonic-gate 
18397c478bd9Sstevel@tonic-gate 		for (i = 0; i < ctrl_nums; i++) {
18407c478bd9Sstevel@tonic-gate 			char *tmp = argv[i + 3 + f_flag];
18417c478bd9Sstevel@tonic-gate 			(void) chdir(current_dir);
18427c478bd9Sstevel@tonic-gate 			if (fully_numeric(tmp)) {
18437c478bd9Sstevel@tonic-gate 				(void) sscanf(tmp, "%d", &controller);
18447c478bd9Sstevel@tonic-gate 				rv = do_flash(controller, farg, f_flag);
18457c478bd9Sstevel@tonic-gate 				if (rv == FAILURE)
18467c478bd9Sstevel@tonic-gate 					break;
18477c478bd9Sstevel@tonic-gate 			} else {
18487c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
18497c478bd9Sstevel@tonic-gate 					gettext("Invalid controller '%s'\n"),
18507c478bd9Sstevel@tonic-gate 					tmp);
18517c478bd9Sstevel@tonic-gate 			}
18527c478bd9Sstevel@tonic-gate 		}
18537c478bd9Sstevel@tonic-gate 		free(current_dir);
18547c478bd9Sstevel@tonic-gate 		break;
18557c478bd9Sstevel@tonic-gate 	default:
18567c478bd9Sstevel@tonic-gate 		usage(progname);
18577c478bd9Sstevel@tonic-gate 	}
18587c478bd9Sstevel@tonic-gate 	return (rv);
18597c478bd9Sstevel@tonic-gate }
1860