xref: /titanic_53/usr/src/cmd/raidctl/raidctl.c (revision 0541156464ba74bca005fda4b225d3bbe53f7a0c)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
233a4e43d3Ssafa  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <ctype.h>
307c478bd9Sstevel@tonic-gate #include <dirent.h>
317c478bd9Sstevel@tonic-gate #include <errno.h>
327c478bd9Sstevel@tonic-gate #include <fcntl.h>
337c478bd9Sstevel@tonic-gate #include <langinfo.h>
347c478bd9Sstevel@tonic-gate #include <libintl.h>
357c478bd9Sstevel@tonic-gate #include <limits.h>
367c478bd9Sstevel@tonic-gate #include <locale.h>
377c478bd9Sstevel@tonic-gate #include <stdarg.h>
387c478bd9Sstevel@tonic-gate #include <stdio.h>
397c478bd9Sstevel@tonic-gate #include <stdlib.h>
407c478bd9Sstevel@tonic-gate #include <string.h>
417c478bd9Sstevel@tonic-gate #include <strings.h>
427c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
437c478bd9Sstevel@tonic-gate #include <sys/mpt/mpi.h>
447c478bd9Sstevel@tonic-gate #include <sys/mpt/mpi_ioc.h>
457c478bd9Sstevel@tonic-gate #include <sys/stat.h>
467c478bd9Sstevel@tonic-gate #include <sys/types.h>
477c478bd9Sstevel@tonic-gate #include <sys/pci.h>
487c478bd9Sstevel@tonic-gate #include <unistd.h>
497c478bd9Sstevel@tonic-gate #include <sys/mnttab.h>
507c478bd9Sstevel@tonic-gate #include <sys/dkio.h>
517c478bd9Sstevel@tonic-gate #include <config_admin.h>
527c478bd9Sstevel@tonic-gate #include <sys/param.h>
537c478bd9Sstevel@tonic-gate #include <sys/raidioctl.h>
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate /*
567c478bd9Sstevel@tonic-gate  * list of controllers to list
577c478bd9Sstevel@tonic-gate  * setup like this:
587c478bd9Sstevel@tonic-gate  * [ctrl_num]	[status]
597c478bd9Sstevel@tonic-gate  *
607c478bd9Sstevel@tonic-gate  * where status is:
617c478bd9Sstevel@tonic-gate  * RAID Found,
627c478bd9Sstevel@tonic-gate  * No RAID Found
637c478bd9Sstevel@tonic-gate  * RAID not supported on this controller
647c478bd9Sstevel@tonic-gate  * Invalid Controller
657c478bd9Sstevel@tonic-gate  */
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate typedef enum {
687c478bd9Sstevel@tonic-gate 	RAID_FOUND = 0x0,
697c478bd9Sstevel@tonic-gate 	RAID_NOT_FOUND,
707c478bd9Sstevel@tonic-gate 	RAID_NOT_SUPPORTED,
717c478bd9Sstevel@tonic-gate 	RAID_INVALID_CTRL,
727c478bd9Sstevel@tonic-gate 	RAID_DONT_USE
737c478bd9Sstevel@tonic-gate } raidctl_errno_t;
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate /* For no-mixup indexing of info_ctrl */
767c478bd9Sstevel@tonic-gate #define	INFO_CTRL	0
777c478bd9Sstevel@tonic-gate #define	INFO_STATUS	1
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate static int **info_ctrl = NULL;
807c478bd9Sstevel@tonic-gate /* Length of conrollers list */
817c478bd9Sstevel@tonic-gate static int ctrl_nums = 0;
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate #define	DEVDIR			"/dev/rdsk"
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_NOP		-1
877c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_INFO		0
887c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_CREATE	1
897c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_DELETE	2
907c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_FLASH	3
917c478bd9Sstevel@tonic-gate 
92*05411564Sjesseb /* values to use for raid level in raidctl */
93*05411564Sjesseb #define	RAID_STRIPE		0
94*05411564Sjesseb #define	RAID_MIRROR		1
95*05411564Sjesseb 
967c478bd9Sstevel@tonic-gate /*
977c478bd9Sstevel@tonic-gate  * Error return codes
987c478bd9Sstevel@tonic-gate  */
997c478bd9Sstevel@tonic-gate #define	SUCCESS			0
1007c478bd9Sstevel@tonic-gate #define	INVALID_ARG		1
1017c478bd9Sstevel@tonic-gate #define	FAILURE			2
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate /*
1047c478bd9Sstevel@tonic-gate  * FW Update Stuff
1057c478bd9Sstevel@tonic-gate  */
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate /* signature and initial offset for PCI expansion rom images */
1087c478bd9Sstevel@tonic-gate #define	PCIROM_SIG	0xaa55	/* offset 0h, length 2 bytes */
1097c478bd9Sstevel@tonic-gate #define	PCIR_OFF	0x18	/* Pointer to PCI Data Structure */
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate /* offsets in PCI data structure header */
1127c478bd9Sstevel@tonic-gate #define	PCIR_DEVID	0x6	/* PCI device id */
1137c478bd9Sstevel@tonic-gate #define	PCIR_CODETYPE   0x14	/* type of code (intel/fcode) */
1147c478bd9Sstevel@tonic-gate #define	PCIR_INDICATOR  0x15	/* "last image" indicator */
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate /* flags for image types */
1177c478bd9Sstevel@tonic-gate #define	BIOS_IMAGE	0x1
1187c478bd9Sstevel@tonic-gate #define	FCODE_IMAGE	0x2
1197c478bd9Sstevel@tonic-gate #define	UNKNOWN_IMAGE	0x3
1207c478bd9Sstevel@tonic-gate #define	LAST_IMAGE	0x80
1217c478bd9Sstevel@tonic-gate #define	NOT_LAST_IMAGE	0
1227c478bd9Sstevel@tonic-gate #define	PCI_IMAGE_UNIT_SIZE	512
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate /* ID's and offsets for MPT Firmware images */
1257c478bd9Sstevel@tonic-gate #define	FW_ROM_ID			0x5aea	/* bytes 4 & 5 of file */
1267c478bd9Sstevel@tonic-gate #define	FW_ROM_OFFSET_CHIP_TYPE		0x22	/* (U16) */
1277c478bd9Sstevel@tonic-gate #define	FW_ROM_OFFSET_VERSION		0x24	/* (U16) */
1287c478bd9Sstevel@tonic-gate #define	FW_ROM_OFFSET_VERSION_NAME	0x44	/* (32 U8) */
1297c478bd9Sstevel@tonic-gate 
130*05411564Sjesseb /* ID's for supported chips */
131*05411564Sjesseb #define	LSI_1030	0x30
132*05411564Sjesseb #define	LSI_1064	0x50
133*05411564Sjesseb #define	LSI_1064E	0x56
134*05411564Sjesseb 
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
1387c478bd9Sstevel@tonic-gate #define	BIOS_STR		"LSI1030 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 
143*05411564Sjesseb /* Number of disks currently supported, per RAID volume */
144*05411564Sjesseb #define	N_DISKS		8
145*05411564Sjesseb 
146*05411564Sjesseb /* Number of RAID volumes currently supported, per HBA */
147*05411564Sjesseb #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  */
1547c478bd9Sstevel@tonic-gate static int	yes(int c);
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 {
159*05411564Sjesseb 	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 
167*05411564Sjesseb /*
168*05411564Sjesseb  * usage: raidctl
169*05411564Sjesseb  * usage: raidctl -c primary secondary
170*05411564Sjesseb  * usage: raidctl -c -r 1 primary secondary
171*05411564Sjesseb  * usage: raidctl -c -r 0 disk1 disk2 [disk3] ...
172*05411564Sjesseb  * usage: raidctl -d volume
173*05411564Sjesseb  * usage: raidctl [-f] -F image_file controller
174*05411564Sjesseb  * usage: raidctl -l [controller...]
175*05411564Sjesseb  *   example:
176*05411564Sjesseb  *   raidctl -c c1t1d0 c1t2d0
177*05411564Sjesseb  *   raidctl -c -r 0 c1t1d0 c1t2d0 c1t3d0 c1t4d0
178*05411564Sjesseb  *   raidctl -d c1t1d0
179*05411564Sjesseb  *   raidctl -F image 1
180*05411564Sjesseb  */
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 
186*05411564Sjesseb 	(void) fprintf(stderr, gettext("usage: %s -c primary secondary\n"),
1877c478bd9Sstevel@tonic-gate 			prog_name);
188*05411564Sjesseb 
189*05411564Sjesseb 	(void) fprintf(stderr, gettext("usage: %s -c -r 1 primary secondary\n"),
190*05411564Sjesseb 			prog_name);
191*05411564Sjesseb 
192*05411564Sjesseb 	(void) fprintf(stderr, gettext("usage: %s -c -r 0 disk1 disk2 "
193*05411564Sjesseb 		"[disk3] ...\n"), prog_name);
194*05411564Sjesseb 
195*05411564Sjesseb 	(void) fprintf(stderr, gettext("usage: %s -d volume\n"), prog_name);
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
1987c478bd9Sstevel@tonic-gate 		gettext("usage: %s [-f] -F image_file controller \n"),
1997c478bd9Sstevel@tonic-gate 		prog_name);
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("usage: %s -l [controller...]\n"),
2027c478bd9Sstevel@tonic-gate 		prog_name);
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("example:\n"));
2057c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s -c c1t1d0 c1t2d0\n", prog_name);
206*05411564Sjesseb 	(void) fprintf(stderr, "%s -c -r 0 c1t1d0 c1t2d0 "
207*05411564Sjesseb 		"c1t3d0 c1t4d0\n", prog_name);
2087c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s -d c1t1d0\n", prog_name);
2097c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s -F image 1\n", prog_name);
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	exit(1);
2127c478bd9Sstevel@tonic-gate }
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate /* Make errno message more "user friendly" */
2157c478bd9Sstevel@tonic-gate static void
2167c478bd9Sstevel@tonic-gate raidctl_error(char *str)
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate 	switch (errno) {
2193a4e43d3Ssafa 	case EINVAL:
2203a4e43d3Ssafa 		(void) fprintf(stderr, gettext("Error: "
2213a4e43d3Ssafa 			"invalid argument would be returned\n"));
2223a4e43d3Ssafa 		break;
2237c478bd9Sstevel@tonic-gate 	case EIO:
2247c478bd9Sstevel@tonic-gate 	case EFAULT:
2257c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
2267c478bd9Sstevel@tonic-gate 			gettext("Error: Device inaccessible.\n"));
2277c478bd9Sstevel@tonic-gate 		break;
2287c478bd9Sstevel@tonic-gate 	case ENOTTY:
2297c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Error: "
2307c478bd9Sstevel@tonic-gate 			"Device does not support requested action.\n"));
2317c478bd9Sstevel@tonic-gate 		break;
2327c478bd9Sstevel@tonic-gate 	default:
2337c478bd9Sstevel@tonic-gate 		perror(str);
2347c478bd9Sstevel@tonic-gate 	}
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate static int
2387c478bd9Sstevel@tonic-gate get_link_path(const char *thing, char *buf)
2397c478bd9Sstevel@tonic-gate {
2407c478bd9Sstevel@tonic-gate 	if (readlink(thing, buf, MAXPATHLEN) < 0)
2417c478bd9Sstevel@tonic-gate 		return (1);
2427c478bd9Sstevel@tonic-gate 	return (0);
2437c478bd9Sstevel@tonic-gate }
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate static int
2467c478bd9Sstevel@tonic-gate get_ctrl_devctl(char *ctrl, char *b)
2477c478bd9Sstevel@tonic-gate {
2487c478bd9Sstevel@tonic-gate 	char	devctl_buf[MAXPATHLEN];
2497c478bd9Sstevel@tonic-gate 	char	*colon;
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	(void) strlcpy(devctl_buf, ctrl, MAXPATHLEN);
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	colon = strrchr(devctl_buf, ':');
2547c478bd9Sstevel@tonic-gate 	if (colon == NULL)
2557c478bd9Sstevel@tonic-gate 		return (1);
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	*colon = 0;
2587c478bd9Sstevel@tonic-gate 	(void) snprintf(devctl_buf, MAXPATHLEN, "%s:devctl", devctl_buf);
2597c478bd9Sstevel@tonic-gate 	(void) strlcpy(b, devctl_buf, MAXPATHLEN);
2607c478bd9Sstevel@tonic-gate 	return (0);
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate static int
2647c478bd9Sstevel@tonic-gate get_devctl(char *disk, char *b)
2657c478bd9Sstevel@tonic-gate {
2667c478bd9Sstevel@tonic-gate 	char	buf1[MAXPATHLEN] = {0};
2677c478bd9Sstevel@tonic-gate 	char	devctl_buf[MAXPATHLEN];
2687c478bd9Sstevel@tonic-gate 	char	*slash;
2697c478bd9Sstevel@tonic-gate 	char	devname[32];
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	if (get_link_path(disk, buf1))
2727c478bd9Sstevel@tonic-gate 		return (1);
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	(void) strlcpy(devctl_buf, buf1, MAXPATHLEN);
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	slash = strrchr(devctl_buf, '/');
2777c478bd9Sstevel@tonic-gate 	if (slash == NULL)
2787c478bd9Sstevel@tonic-gate 		return (1);
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	*slash = 0;
2817c478bd9Sstevel@tonic-gate 	slash = strrchr(devctl_buf, '/');
2827c478bd9Sstevel@tonic-gate 	(void) strlcpy(devname, slash, 32);
2837c478bd9Sstevel@tonic-gate 	*slash = 0;
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	(void) snprintf(devctl_buf, MAXPATHLEN, "%s%s:devctl",
2867c478bd9Sstevel@tonic-gate 		devctl_buf, devname);
287*05411564Sjesseb 
2887c478bd9Sstevel@tonic-gate 	(void) strlcpy(b, devctl_buf, MAXPATHLEN);
289*05411564Sjesseb 
2907c478bd9Sstevel@tonic-gate 	return (0);
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate static int
2947c478bd9Sstevel@tonic-gate already_there(int controller)
2957c478bd9Sstevel@tonic-gate {
2967c478bd9Sstevel@tonic-gate 	raidlist_t	*curr = raids;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
2997c478bd9Sstevel@tonic-gate 		if (curr->controller == controller)
3007c478bd9Sstevel@tonic-gate 			return (1);
3017c478bd9Sstevel@tonic-gate 		curr = curr->next;
3027c478bd9Sstevel@tonic-gate 	}
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	return (0);
3057c478bd9Sstevel@tonic-gate }
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate /*
3087c478bd9Sstevel@tonic-gate  * Display those controllers where RAID volumes were not found
3097c478bd9Sstevel@tonic-gate  */
3107c478bd9Sstevel@tonic-gate static void
3117c478bd9Sstevel@tonic-gate print_no_raids()
3127c478bd9Sstevel@tonic-gate {
3137c478bd9Sstevel@tonic-gate 	int i, space = 0;
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	if (info_ctrl == NULL)
3167c478bd9Sstevel@tonic-gate 		return;
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	for (i = 0; i < ctrl_nums; i++) {
3197c478bd9Sstevel@tonic-gate 		/* Status of '0' means RAID exists at that controller */
3207c478bd9Sstevel@tonic-gate 		if (info_ctrl[i][INFO_STATUS] == RAID_FOUND ||
3217c478bd9Sstevel@tonic-gate 		    info_ctrl[i][INFO_STATUS] == RAID_DONT_USE)
3227c478bd9Sstevel@tonic-gate 			continue;
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 		if (!space && raids != NULL) {
3257c478bd9Sstevel@tonic-gate 			(void) printf("\n");
3267c478bd9Sstevel@tonic-gate 			space = 1;
3277c478bd9Sstevel@tonic-gate 		}
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 		/* switch statement used to enable gettext()'ing of text */
3307c478bd9Sstevel@tonic-gate 		switch (info_ctrl[i][INFO_STATUS]) {
3317c478bd9Sstevel@tonic-gate 		case RAID_INVALID_CTRL:
3327c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Invalid controller '%d'\n"),
3337c478bd9Sstevel@tonic-gate 				info_ctrl[i][INFO_CTRL]);
3347c478bd9Sstevel@tonic-gate 			break;
3357c478bd9Sstevel@tonic-gate 		case RAID_NOT_SUPPORTED:
3367c478bd9Sstevel@tonic-gate 			(void) printf(gettext("No RAID supported "
3377c478bd9Sstevel@tonic-gate 				"on controller '%d'\n"),
3387c478bd9Sstevel@tonic-gate 					info_ctrl[i][INFO_CTRL]);
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 			break;
3417c478bd9Sstevel@tonic-gate 		default:
3427c478bd9Sstevel@tonic-gate 			(void) printf(gettext("No RAID volumes found on "
3437c478bd9Sstevel@tonic-gate 				"controller '%d'\n"), info_ctrl[i][INFO_CTRL]);
3447c478bd9Sstevel@tonic-gate 		}
3457c478bd9Sstevel@tonic-gate 	}
3467c478bd9Sstevel@tonic-gate }
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate static void
3497c478bd9Sstevel@tonic-gate add_raid_to_raidlist(char *ctrl_name, int controller)
3507c478bd9Sstevel@tonic-gate {
351*05411564Sjesseb 	raid_config_t		config[N_RAIDVOLS];
3527c478bd9Sstevel@tonic-gate 	raidlist_t		*curr;
3537c478bd9Sstevel@tonic-gate 	char			buf[MAXPATHLEN] = {0};
3547c478bd9Sstevel@tonic-gate 	char			buf1[MAXPATHLEN] = {0};
355*05411564Sjesseb 	int			fd, i, n;
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	if (readlink(ctrl_name, buf, sizeof (buf)) < 0)
3587c478bd9Sstevel@tonic-gate 		return;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	if (get_ctrl_devctl(buf, buf1))
3617c478bd9Sstevel@tonic-gate 		return;
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	/*
3647c478bd9Sstevel@tonic-gate 	 * If "-l" was specified, then only look at those controllers
3657c478bd9Sstevel@tonic-gate 	 * listed as part of the command line input.
3667c478bd9Sstevel@tonic-gate 	 */
3677c478bd9Sstevel@tonic-gate 	if (info_ctrl != NULL) {
3687c478bd9Sstevel@tonic-gate 		for (i = 0; i < ctrl_nums; i++) {
3697c478bd9Sstevel@tonic-gate 			if (info_ctrl[i][INFO_STATUS] == RAID_DONT_USE)
3707c478bd9Sstevel@tonic-gate 				continue;
371*05411564Sjesseb 			if (controller == info_ctrl[i][INFO_CTRL])
3727c478bd9Sstevel@tonic-gate 				break;
3737c478bd9Sstevel@tonic-gate 		}
374*05411564Sjesseb 		/* return if we didn't find a controller */
375*05411564Sjesseb 		if (i == ctrl_nums)
3767c478bd9Sstevel@tonic-gate 			return;
3777c478bd9Sstevel@tonic-gate 	}
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	fd = open(buf1, O_RDONLY);
3807c478bd9Sstevel@tonic-gate 	if (fd == -1) {
3817c478bd9Sstevel@tonic-gate 		if (info_ctrl != NULL)
3827c478bd9Sstevel@tonic-gate 			info_ctrl[i][INFO_STATUS] = RAID_INVALID_CTRL;
3837c478bd9Sstevel@tonic-gate 		return;
3847c478bd9Sstevel@tonic-gate 	}
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	if (ioctl(fd, RAID_GETCONFIG, &config) < 0) {
3877c478bd9Sstevel@tonic-gate 		if (info_ctrl != NULL)
3887c478bd9Sstevel@tonic-gate 			info_ctrl[i][INFO_STATUS] = RAID_NOT_SUPPORTED;
3897c478bd9Sstevel@tonic-gate 		(void) close(fd);
3907c478bd9Sstevel@tonic-gate 		/* Fail silently */
3917c478bd9Sstevel@tonic-gate 		return;
3927c478bd9Sstevel@tonic-gate 	}
393*05411564Sjesseb 
3947c478bd9Sstevel@tonic-gate 	(void) close(fd);
3957c478bd9Sstevel@tonic-gate 
396*05411564Sjesseb 	/* check if there are any raid volumes on this hba */
397*05411564Sjesseb 	for (n = 0; n < N_RAIDVOLS; n++) {
398*05411564Sjesseb 		if (config[n].ndisks != 0)
399*05411564Sjesseb 			break;
400*05411564Sjesseb 	}
401*05411564Sjesseb 
402*05411564Sjesseb 	if (n == N_RAIDVOLS) {
403*05411564Sjesseb 		/* no raid volumes were found */
4047c478bd9Sstevel@tonic-gate 		if (info_ctrl != NULL)
4057c478bd9Sstevel@tonic-gate 			info_ctrl[i][INFO_STATUS] = RAID_NOT_FOUND;
4067c478bd9Sstevel@tonic-gate 		return;
4077c478bd9Sstevel@tonic-gate 	}
4087c478bd9Sstevel@tonic-gate 
409*05411564Sjesseb 	/* we've at least one raid volume on this hba */
4107c478bd9Sstevel@tonic-gate 	if (info_ctrl != NULL)
4117c478bd9Sstevel@tonic-gate 		info_ctrl[i][INFO_STATUS] = RAID_FOUND;
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	if (raids == NULL) {
4147c478bd9Sstevel@tonic-gate 		raids = (raidlist_t *)malloc(sizeof (raidlist_t));
4157c478bd9Sstevel@tonic-gate 		curr = raids;
4167c478bd9Sstevel@tonic-gate 	} else {
4177c478bd9Sstevel@tonic-gate 		if (already_there(controller)) {
4187c478bd9Sstevel@tonic-gate 			return;
4197c478bd9Sstevel@tonic-gate 		}
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 		curr = raids;
4227c478bd9Sstevel@tonic-gate 		/* Seek to the end */
4237c478bd9Sstevel@tonic-gate 		while (curr->next != NULL)
4247c478bd9Sstevel@tonic-gate 			curr = curr->next;
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 		curr->next = (raidlist_t *)malloc(sizeof (raidlist_t));
4277c478bd9Sstevel@tonic-gate 		curr = curr->next;
4287c478bd9Sstevel@tonic-gate 	}
4297c478bd9Sstevel@tonic-gate 	curr->next = NULL;
4307c478bd9Sstevel@tonic-gate 	curr->controller = controller;
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	(void) strlcpy(curr->devctl, buf1, sizeof (curr->devctl));
4337c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
434*05411564Sjesseb 
435*05411564Sjesseb 	(void) memcpy(&curr->raid_config, &config,
436*05411564Sjesseb 		(sizeof (raid_config_t) * N_RAIDVOLS));
4377c478bd9Sstevel@tonic-gate }
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate static void
4407c478bd9Sstevel@tonic-gate print_header()
4417c478bd9Sstevel@tonic-gate {
442*05411564Sjesseb 	(void) printf(gettext("RAID\tVolume\tRAID\t\tRAID\t\tDisk"));
4437c478bd9Sstevel@tonic-gate 	(void) printf("\n");
444*05411564Sjesseb 	(void) printf(gettext("Volume\tType\tStatus\t\tDisk\t\tStatus"));
4457c478bd9Sstevel@tonic-gate 	(void) printf("\n");
4467c478bd9Sstevel@tonic-gate 	(void) printf("------------------------------------------------------");
4477c478bd9Sstevel@tonic-gate 	(void) printf("\n");
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate static void
4517c478bd9Sstevel@tonic-gate print_raidconfig(int c, raid_config_t config)
4527c478bd9Sstevel@tonic-gate {
4537c478bd9Sstevel@tonic-gate 	int	i;
454*05411564Sjesseb 	char	voltype[8];
4557c478bd9Sstevel@tonic-gate 
456*05411564Sjesseb 	/* print RAID volume target ID and volume type */
457*05411564Sjesseb 	if (config.raid_level == RAID_STRIPE) {
458*05411564Sjesseb 		(void) snprintf(voltype, sizeof (voltype), "IS");
459*05411564Sjesseb 	} else if (config.raid_level == RAID_MIRROR) {
460*05411564Sjesseb 		(void) snprintf(voltype, sizeof (voltype), "IM");
461*05411564Sjesseb 	}
462*05411564Sjesseb 
463*05411564Sjesseb 	(void) printf("c%dt%dd0\t%s\t", c, config.targetid, voltype);
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	/* Get RAID Info */
4667c478bd9Sstevel@tonic-gate 	if (config.flags & RAID_FLAG_RESYNCING &&
4677c478bd9Sstevel@tonic-gate 	    config.state == RAID_STATE_DEGRADED) {
4687c478bd9Sstevel@tonic-gate 		(void) printf(gettext("RESYNCING\t"));
4697c478bd9Sstevel@tonic-gate 	} else if (config.state == RAID_STATE_DEGRADED) {
4707c478bd9Sstevel@tonic-gate 		(void) printf(gettext("DEGRADED\t"));
4717c478bd9Sstevel@tonic-gate 	} else if (config.state == RAID_STATE_OPTIMAL) {
4727c478bd9Sstevel@tonic-gate 		(void) printf(gettext("OK\t\t"));
4737c478bd9Sstevel@tonic-gate 	} else if (config.state == RAID_STATE_FAILED) {
4747c478bd9Sstevel@tonic-gate 		(void) printf(gettext("FAILED\t\t"));
4757c478bd9Sstevel@tonic-gate 	} else {
4767c478bd9Sstevel@tonic-gate 		(void) printf(gettext("ERROR\t\t"));
4777c478bd9Sstevel@tonic-gate 	}
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	/* Get RAID Disks */
4807c478bd9Sstevel@tonic-gate 	(void) printf("c%dt%dd0\t\t", c, config.disk[0]);
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	/* Get RAID Disk's Status */
4837c478bd9Sstevel@tonic-gate 	if (config.diskstatus[0] & RAID_DISKSTATUS_FAILED) {
4847c478bd9Sstevel@tonic-gate 		(void) printf(gettext("FAILED\n"));
4857c478bd9Sstevel@tonic-gate 	} else if (config.diskstatus[0] & RAID_DISKSTATUS_MISSING) {
4867c478bd9Sstevel@tonic-gate 		(void) printf(gettext("MISSING\n"));
4877c478bd9Sstevel@tonic-gate 	} else {
4887c478bd9Sstevel@tonic-gate 		(void) printf(gettext("OK\n"));
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	for (i = 1; i < config.ndisks; i++) {
4927c478bd9Sstevel@tonic-gate 		(void) printf("\t\t\t\tc%dt%dd0\t\t", c, config.disk[i]);
4937c478bd9Sstevel@tonic-gate 		if (config.diskstatus[i] & RAID_DISKSTATUS_FAILED) {
4947c478bd9Sstevel@tonic-gate 			(void) printf(gettext("FAILED\n"));
4957c478bd9Sstevel@tonic-gate 		} else if (config.diskstatus[i] & RAID_DISKSTATUS_MISSING) {
4967c478bd9Sstevel@tonic-gate 			(void) printf(gettext("MISSING\n"));
4977c478bd9Sstevel@tonic-gate 		} else {
4987c478bd9Sstevel@tonic-gate 			(void) printf(gettext("OK\n"));
4997c478bd9Sstevel@tonic-gate 		}
5007c478bd9Sstevel@tonic-gate 	}
5017c478bd9Sstevel@tonic-gate }
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate static void
5047c478bd9Sstevel@tonic-gate print_disklist()
5057c478bd9Sstevel@tonic-gate {
5067c478bd9Sstevel@tonic-gate 	raidlist_t	*curr = raids;
507*05411564Sjesseb 	int i;
508*05411564Sjesseb 
5097c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
510*05411564Sjesseb 		for (i = 0; i < N_RAIDVOLS; i++) {
511*05411564Sjesseb 			if (curr->raid_config[i].ndisks != 0) {
512*05411564Sjesseb 				print_raidconfig(curr->controller,
513*05411564Sjesseb 						curr->raid_config[i]);
514*05411564Sjesseb 			}
515*05411564Sjesseb 		}
5167c478bd9Sstevel@tonic-gate 		curr = curr->next;
5177c478bd9Sstevel@tonic-gate 	}
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate static void
5217c478bd9Sstevel@tonic-gate free_disklist()
5227c478bd9Sstevel@tonic-gate {
5237c478bd9Sstevel@tonic-gate 	raidlist_t	*curr = raids;
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
5267c478bd9Sstevel@tonic-gate 		raidlist_t	*temp;
5277c478bd9Sstevel@tonic-gate 		temp = curr;
5287c478bd9Sstevel@tonic-gate 		curr = curr->next;
5297c478bd9Sstevel@tonic-gate 		free(temp);
5307c478bd9Sstevel@tonic-gate 	}
5317c478bd9Sstevel@tonic-gate }
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate static void
5347c478bd9Sstevel@tonic-gate do_search()
5357c478bd9Sstevel@tonic-gate {
5367c478bd9Sstevel@tonic-gate 	DIR		*dir;
5377c478bd9Sstevel@tonic-gate 	struct dirent	*dp;
5387c478bd9Sstevel@tonic-gate 	char		buf[MAXPATHLEN];
5397c478bd9Sstevel@tonic-gate 	int		c;
5407c478bd9Sstevel@tonic-gate 	int		i, j;
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	/*
5437c478bd9Sstevel@tonic-gate 	 * In case repeated numbers were found, assign the repititions as
5447c478bd9Sstevel@tonic-gate 	 * RAID_DONT_USE
5457c478bd9Sstevel@tonic-gate 	 */
5467c478bd9Sstevel@tonic-gate 	for (i = 0; i < ctrl_nums; i++) {
5477c478bd9Sstevel@tonic-gate 		int first_one = 1;
5487c478bd9Sstevel@tonic-gate 		for (j = 0; j < ctrl_nums; j++) {
5497c478bd9Sstevel@tonic-gate 			if (info_ctrl[i][INFO_CTRL] ==
5507c478bd9Sstevel@tonic-gate 				info_ctrl[j][INFO_CTRL]) {
5517c478bd9Sstevel@tonic-gate 				if (info_ctrl[j][INFO_STATUS] == RAID_DONT_USE)
5527c478bd9Sstevel@tonic-gate 					continue;
5537c478bd9Sstevel@tonic-gate 				if (first_one) {
5547c478bd9Sstevel@tonic-gate 					first_one = 0;
5557c478bd9Sstevel@tonic-gate 				} else {
5567c478bd9Sstevel@tonic-gate 					info_ctrl[j][INFO_STATUS] =
5577c478bd9Sstevel@tonic-gate 						RAID_DONT_USE;
5587c478bd9Sstevel@tonic-gate 				}
5597c478bd9Sstevel@tonic-gate 			}
5607c478bd9Sstevel@tonic-gate 		}
5617c478bd9Sstevel@tonic-gate 	}
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	if ((dir = opendir("/dev/cfg")) == NULL) {
5647c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
5657c478bd9Sstevel@tonic-gate 			gettext("Cannot open /dev/cfg: %s\n"), strerror(errno));
5667c478bd9Sstevel@tonic-gate 		return;
5677c478bd9Sstevel@tonic-gate 	}
5687c478bd9Sstevel@tonic-gate 	while ((dp = readdir(dir)) != NULL) {
5697c478bd9Sstevel@tonic-gate 		if (strcmp(dp->d_name, ".") == 0 ||
5707c478bd9Sstevel@tonic-gate 		    strcmp(dp->d_name, "..") == 0)
5717c478bd9Sstevel@tonic-gate 			continue;
5727c478bd9Sstevel@tonic-gate 		if (sscanf(dp->d_name, "c%d", &c) != 1)
5737c478bd9Sstevel@tonic-gate 			continue;
5747c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), "/dev/cfg/%s", dp->d_name);
5757c478bd9Sstevel@tonic-gate 		add_raid_to_raidlist(buf, c);
5767c478bd9Sstevel@tonic-gate 	}
5777c478bd9Sstevel@tonic-gate 	(void) closedir(dir);
5787c478bd9Sstevel@tonic-gate }
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate /*
5817c478bd9Sstevel@tonic-gate  * do_info() will do the following:
5827c478bd9Sstevel@tonic-gate  * - create a list of disks' devctls
5837c478bd9Sstevel@tonic-gate  * - try to talk to each of the devctls found
5847c478bd9Sstevel@tonic-gate  * - if raid configuration is found, display it.
5857c478bd9Sstevel@tonic-gate  */
5867c478bd9Sstevel@tonic-gate static void
5877c478bd9Sstevel@tonic-gate do_info()
5887c478bd9Sstevel@tonic-gate {
5897c478bd9Sstevel@tonic-gate 	int i;
5907c478bd9Sstevel@tonic-gate 	(void) chdir(DEVDIR);
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	do_search();
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	if (raids == NULL) {
5957c478bd9Sstevel@tonic-gate 		if (info_ctrl != NULL) {
5967c478bd9Sstevel@tonic-gate 			print_no_raids();
5977c478bd9Sstevel@tonic-gate 			for (i = 0; i < ctrl_nums; i++)
5987c478bd9Sstevel@tonic-gate 				free(info_ctrl[i]);
5997c478bd9Sstevel@tonic-gate 			free(info_ctrl);
6007c478bd9Sstevel@tonic-gate 		} else {
6017c478bd9Sstevel@tonic-gate 			(void) printf(gettext("No RAID volumes found\n"));
6027c478bd9Sstevel@tonic-gate 		}
6037c478bd9Sstevel@tonic-gate 		return;
6047c478bd9Sstevel@tonic-gate 	}
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	print_header();
6077c478bd9Sstevel@tonic-gate 	print_disklist();
6087c478bd9Sstevel@tonic-gate 	print_no_raids();
6097c478bd9Sstevel@tonic-gate 	free_disklist();
6107c478bd9Sstevel@tonic-gate 	if (info_ctrl) {
6117c478bd9Sstevel@tonic-gate 		for (i = 0; i < ctrl_nums; i++)
6127c478bd9Sstevel@tonic-gate 			free(info_ctrl[i]);
6137c478bd9Sstevel@tonic-gate 		free(info_ctrl);
6147c478bd9Sstevel@tonic-gate 	}
6157c478bd9Sstevel@tonic-gate }
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate static int
618*05411564Sjesseb disk_in_raid(int c, int t)
619*05411564Sjesseb {
620*05411564Sjesseb 	raidlist_t	*curr;
621*05411564Sjesseb 	raid_config_t	raid;
622*05411564Sjesseb 	int i, j, n;
623*05411564Sjesseb 
624*05411564Sjesseb 	do_search();
625*05411564Sjesseb 	curr = raids;
626*05411564Sjesseb 
627*05411564Sjesseb 	while (curr != NULL) {
628*05411564Sjesseb 		if (curr->controller == c) {
629*05411564Sjesseb 			for (i = 0; i < N_RAIDVOLS; i++) {
630*05411564Sjesseb 				raid = curr->raid_config[i];
631*05411564Sjesseb 				if ((n = raid.ndisks) != 0) {
632*05411564Sjesseb 					for (j = 0; j < n; j++) {
633*05411564Sjesseb 						if (raid.disk[j] == t) {
634*05411564Sjesseb 							return (1);
635*05411564Sjesseb 						}
636*05411564Sjesseb 					}
637*05411564Sjesseb 				}
638*05411564Sjesseb 			}
639*05411564Sjesseb 		}
640*05411564Sjesseb 		curr = curr->next;
641*05411564Sjesseb 	}
642*05411564Sjesseb 	return (0);
643*05411564Sjesseb }
644*05411564Sjesseb 
645*05411564Sjesseb static int
6467c478bd9Sstevel@tonic-gate disk_there(int c, int t)
6477c478bd9Sstevel@tonic-gate {
6487c478bd9Sstevel@tonic-gate 	char	disk[100];
6497c478bd9Sstevel@tonic-gate 	int	fd;
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	(void) snprintf(disk, sizeof (disk), "c%dt%dd0s2", c, t);
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	fd = open(disk, O_RDWR | O_NDELAY);
6547c478bd9Sstevel@tonic-gate 	if (fd == -1) {
6557c478bd9Sstevel@tonic-gate 		return (-1);
6567c478bd9Sstevel@tonic-gate 	}
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	(void) close(fd);
6597c478bd9Sstevel@tonic-gate 	return (0);
6607c478bd9Sstevel@tonic-gate }
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate static int
6637c478bd9Sstevel@tonic-gate get_controller(char *dev)
6647c478bd9Sstevel@tonic-gate {
6657c478bd9Sstevel@tonic-gate 	raidlist_t	*curr;
6667c478bd9Sstevel@tonic-gate 	int		c;
6677c478bd9Sstevel@tonic-gate 	do_search();
6687c478bd9Sstevel@tonic-gate 	curr = raids;
6697c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
6707c478bd9Sstevel@tonic-gate 		if (strcmp(curr->devctl, dev) == 0) {
6717c478bd9Sstevel@tonic-gate 			c = curr->controller;
6727c478bd9Sstevel@tonic-gate 			break;
6737c478bd9Sstevel@tonic-gate 		}
6747c478bd9Sstevel@tonic-gate 		curr = curr->next;
6757c478bd9Sstevel@tonic-gate 	}
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate 	free_disklist();
6787c478bd9Sstevel@tonic-gate 	return (c);
6797c478bd9Sstevel@tonic-gate }
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate static int
6827c478bd9Sstevel@tonic-gate disk_mounted(char *d)
6837c478bd9Sstevel@tonic-gate {
6847c478bd9Sstevel@tonic-gate 	struct mnttab	mt;
6857c478bd9Sstevel@tonic-gate 	FILE		*f = fopen("/etc/mnttab", "r");
6867c478bd9Sstevel@tonic-gate 
687*05411564Sjesseb 	while (getmntent(f, &mt) != EOF) {
6887c478bd9Sstevel@tonic-gate 		if (strstr(mt.mnt_special, d) != NULL)
6897c478bd9Sstevel@tonic-gate 			return (1);
690*05411564Sjesseb 	}
6917c478bd9Sstevel@tonic-gate 	return (0);
6927c478bd9Sstevel@tonic-gate }
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate static int
6957c478bd9Sstevel@tonic-gate disk_big_enough(char **d, diskaddr_t *cap, int *errcond)
6967c478bd9Sstevel@tonic-gate {
6977c478bd9Sstevel@tonic-gate 	struct dk_minfo minfo;
6987c478bd9Sstevel@tonic-gate 	char		disk[N_DISKS][MAXPATHLEN];
699*05411564Sjesseb 	uint_t		disk_lbsize[N_DISKS];
7007c478bd9Sstevel@tonic-gate 	diskaddr_t	disk_capacity[N_DISKS];
7017c478bd9Sstevel@tonic-gate 	int		i, fd;
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	for (i = 0; i < N_DISKS; i++) {
704*05411564Sjesseb 		if (d[i] == NULL)
705*05411564Sjesseb 			break;
706*05411564Sjesseb 
7077c478bd9Sstevel@tonic-gate 		(void) snprintf(disk[i], sizeof (disk[i]), DEVDIR"/%ss2", d[i]);
7087c478bd9Sstevel@tonic-gate 		fd = open(disk[i], O_RDWR | O_NDELAY);
709*05411564Sjesseb 		if (fd == -1)
7107c478bd9Sstevel@tonic-gate 			return (FAILURE);
7117c478bd9Sstevel@tonic-gate 		if (ioctl(fd, DKIOCGMEDIAINFO, &minfo) == -1) {
7127c478bd9Sstevel@tonic-gate 			(void) close(fd);
7137c478bd9Sstevel@tonic-gate 			return (FAILURE);
7147c478bd9Sstevel@tonic-gate 		}
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 		disk_lbsize[i] = minfo.dki_lbsize;
7177c478bd9Sstevel@tonic-gate 		disk_capacity[i] = minfo.dki_capacity;
7187c478bd9Sstevel@tonic-gate 
719*05411564Sjesseb 		/* lbsize must be the same on all disks */
720*05411564Sjesseb 		if (disk_lbsize[0] != disk_lbsize[i]) {
7217c478bd9Sstevel@tonic-gate 			*errcond = 2;
7227c478bd9Sstevel@tonic-gate 			return (INVALID_ARG);
7237c478bd9Sstevel@tonic-gate 		}
7247c478bd9Sstevel@tonic-gate 
725*05411564Sjesseb 		/* ensure drive capacity is greater than or equal to first */
726*05411564Sjesseb 		if (disk_capacity[0] > disk_capacity[i]) {
7277c478bd9Sstevel@tonic-gate 			*errcond = 1;
7287c478bd9Sstevel@tonic-gate 			return (INVALID_ARG);
7297c478bd9Sstevel@tonic-gate 		}
730*05411564Sjesseb 		(void) close(fd);
731*05411564Sjesseb 	}
7327c478bd9Sstevel@tonic-gate 
733*05411564Sjesseb 	/*
734*05411564Sjesseb 	 * setting capacity as the dk_minfo.dki_capacity of d[0]
735*05411564Sjesseb 	 *   this is the number of dki_lbsize blocks on disk
736*05411564Sjesseb 	 */
7377c478bd9Sstevel@tonic-gate 	*cap = disk_capacity[0];
7387c478bd9Sstevel@tonic-gate 	return (SUCCESS);
7397c478bd9Sstevel@tonic-gate }
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate static int
7427c478bd9Sstevel@tonic-gate do_config_change_state(cfga_cmd_t cmd, int d, int c)
7437c478bd9Sstevel@tonic-gate {
7447c478bd9Sstevel@tonic-gate 	cfga_err_t	cfga_err;
7457c478bd9Sstevel@tonic-gate 	char		*ap_id;
7467c478bd9Sstevel@tonic-gate 	int		rv = SUCCESS;
7477c478bd9Sstevel@tonic-gate 	int		count = 0;
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	ap_id = (char *)malloc(100);
7507c478bd9Sstevel@tonic-gate 	if (ap_id == NULL)
7517c478bd9Sstevel@tonic-gate 		return (FAILURE);
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 	(void) snprintf(ap_id, 100, "c%d::dsk/c%dt%dd0", c, c, d);
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	/*
7567c478bd9Sstevel@tonic-gate 	 * If the config_change_state() funcation fails, we want to
7577c478bd9Sstevel@tonic-gate 	 * retry.  If the retry fails, then we return failure to fail.
7587c478bd9Sstevel@tonic-gate 	 *
7597c478bd9Sstevel@tonic-gate 	 * If we fail:
7607c478bd9Sstevel@tonic-gate 	 *
7617c478bd9Sstevel@tonic-gate 	 *	If we were called from create, then we fail the raid
7627c478bd9Sstevel@tonic-gate 	 *	creation.
7637c478bd9Sstevel@tonic-gate 	 *
7647c478bd9Sstevel@tonic-gate 	 *	If we were called from delete, then the disk will not
7657c478bd9Sstevel@tonic-gate 	 *	be re-configured by raidctl.
7667c478bd9Sstevel@tonic-gate 	 */
7677c478bd9Sstevel@tonic-gate 	do {
7687c478bd9Sstevel@tonic-gate 		cfga_err = config_change_state(cmd, 1, &ap_id, NULL,
7697c478bd9Sstevel@tonic-gate 			NULL, NULL, NULL, 0);
7707c478bd9Sstevel@tonic-gate 		count++;
7717c478bd9Sstevel@tonic-gate 	} while (cfga_err != CFGA_OK && count < 2);
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 	if (cfga_err != CFGA_OK)
7747c478bd9Sstevel@tonic-gate 		rv = FAILURE;
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 	free(ap_id);
7777c478bd9Sstevel@tonic-gate 	return (rv);
7787c478bd9Sstevel@tonic-gate }
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate static int
781*05411564Sjesseb do_create(char **d, int rlevel)
7827c478bd9Sstevel@tonic-gate {
783*05411564Sjesseb 	raid_config_t	config[N_RAIDVOLS];
784*05411564Sjesseb 	raid_config_t	newvol;
7857c478bd9Sstevel@tonic-gate 	char		disk[N_DISKS][MAXPATHLEN] = {0};
786*05411564Sjesseb 	int		map[N_DISKS];
7877c478bd9Sstevel@tonic-gate 	char		channel1[MAXPATHLEN];
7887c478bd9Sstevel@tonic-gate 	char		channel2[MAXPATHLEN];
7897c478bd9Sstevel@tonic-gate 	diskaddr_t	capacity;
790*05411564Sjesseb 	int		fd, fd2, size, errcond;
7917c478bd9Sstevel@tonic-gate 	int		c[N_DISKS];
7927c478bd9Sstevel@tonic-gate 	int		t[N_DISKS];
7937c478bd9Sstevel@tonic-gate 	char		*tmp;
794*05411564Sjesseb 	int		loc, i;
795*05411564Sjesseb 	int		ndisks = 0;
796*05411564Sjesseb 	ushort_t	devid;
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	(void) chdir(DEVDIR);
7997c478bd9Sstevel@tonic-gate 
800*05411564Sjesseb 	/* initialize target map */
801*05411564Sjesseb 	for (i = 0; i < N_DISKS; i++)
802*05411564Sjesseb 		map[i] = -1;
803*05411564Sjesseb 
8047c478bd9Sstevel@tonic-gate 	for (i = 0; i < N_DISKS; i++) {
805*05411564Sjesseb 		if (d[i] == NULL)
806*05411564Sjesseb 			break;
807*05411564Sjesseb 
8087c478bd9Sstevel@tonic-gate 		if ((sscanf(d[i], "c%dt%dd0", &c[i], &t[i])) != 2 ||
8097c478bd9Sstevel@tonic-gate 		    t[i] < 0) {
8107c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
8117c478bd9Sstevel@tonic-gate 				gettext("Invalid disk format.\n"));
8127c478bd9Sstevel@tonic-gate 			return (INVALID_ARG);
8137c478bd9Sstevel@tonic-gate 		}
8147c478bd9Sstevel@tonic-gate 
815*05411564Sjesseb 		/* ensure that all disks are on the same controller, */
816*05411564Sjesseb 		if (c[i] != c[0]) {
817*05411564Sjesseb 			(void) fprintf(stderr, gettext("Disks must be "
818*05411564Sjesseb 					"on the same controller.\n"));
8197c478bd9Sstevel@tonic-gate 			return (INVALID_ARG);
8207c478bd9Sstevel@tonic-gate 		}
8217c478bd9Sstevel@tonic-gate 
822*05411564Sjesseb 		/* that all disks are online, */
823*05411564Sjesseb 		if (disk_there(c[0], t[i])) {
824*05411564Sjesseb 			(void) printf(gettext("Disk 'c%dt%dd0' is not "
825*05411564Sjesseb 				"present.\n"), c[0], t[i]);
8267c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Cannot create RAID volume.\n"));
8277c478bd9Sstevel@tonic-gate 			return (INVALID_ARG);
8287c478bd9Sstevel@tonic-gate 		}
8297c478bd9Sstevel@tonic-gate 
830*05411564Sjesseb 		/* that there are no duplicate disks, */
831*05411564Sjesseb 		loc = t[i];
832*05411564Sjesseb 		if (map[loc] == -1) {
833*05411564Sjesseb 			map[loc] = t[i];
834*05411564Sjesseb 		} else {
835*05411564Sjesseb 			(void) fprintf(stderr,
836*05411564Sjesseb 				gettext("Disks must be different.\n"));
837*05411564Sjesseb 			return (INVALID_ARG);
838*05411564Sjesseb 		}
839*05411564Sjesseb 
840*05411564Sjesseb 		/* that no disk is already in use by another volume, */
841*05411564Sjesseb 		if (disk_in_raid(c[0], t[i])) {
842*05411564Sjesseb 			(void) fprintf(stderr, gettext("Disk %s is already in "
843*05411564Sjesseb 				"a RAID volume.\n"), d[i]);
844*05411564Sjesseb 			return (INVALID_ARG);
845*05411564Sjesseb 		}
846*05411564Sjesseb 
847*05411564Sjesseb 		/* that no target's id is lower than the raidtarg, */
848*05411564Sjesseb 		if (t[0] > t[i]) {
849*05411564Sjesseb 			(void) fprintf(stderr, gettext("First target ID must "
850*05411564Sjesseb 				"be less than other member target IDs.\n"));
851*05411564Sjesseb 			return (INVALID_ARG);
852*05411564Sjesseb 		}
853*05411564Sjesseb 
854*05411564Sjesseb 		/* and that no disk other than a mirror primary is mounted */
855*05411564Sjesseb 		if (disk_mounted(d[i])) {
856*05411564Sjesseb 			/* data on all stripe disks will be destroyed */
857*05411564Sjesseb 			if ((rlevel == RAID_STRIPE) && (i != 0)) {
858*05411564Sjesseb 				(void) fprintf(stderr, gettext("Cannot "
859*05411564Sjesseb 					"create RAID0 volume, secondary disk "
860*05411564Sjesseb 					"\"%s\" is mounted.\n"), d[i]);
861*05411564Sjesseb 				return (INVALID_ARG);
862*05411564Sjesseb 			}
863*05411564Sjesseb 			/* data on mirror's secondary will be destroyed */
864*05411564Sjesseb 			if (i != 0) {
865*05411564Sjesseb 				(void) fprintf(stderr, gettext("Cannot "
866*05411564Sjesseb 					"create RAID mirror, secondary "
867*05411564Sjesseb 					"disk \"%s\" is mounted.\n"), d[i]);
868*05411564Sjesseb 				return (INVALID_ARG);
869*05411564Sjesseb 			}
870*05411564Sjesseb 		}
871*05411564Sjesseb 
872*05411564Sjesseb 		(void) snprintf(disk[i], sizeof (disk[i]), DEVDIR"/%ss2", d[i]);
873*05411564Sjesseb 		ndisks++;
874*05411564Sjesseb 	}
875*05411564Sjesseb 
876*05411564Sjesseb 	/* validate the drive capacities */
8777c478bd9Sstevel@tonic-gate 	switch (disk_big_enough(d, &capacity, &errcond)) {
8787c478bd9Sstevel@tonic-gate 	case FAILURE:
8797c478bd9Sstevel@tonic-gate 		return (FAILURE);
8807c478bd9Sstevel@tonic-gate 	case INVALID_ARG:
8817c478bd9Sstevel@tonic-gate 		switch (errcond) {
8827c478bd9Sstevel@tonic-gate 		case 1:
8837c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Cannot create RAID volume when "
8847c478bd9Sstevel@tonic-gate 			"primary disk is larger than secondary disk.\n"));
8857c478bd9Sstevel@tonic-gate 		break;
8867c478bd9Sstevel@tonic-gate 		case 2:
8877c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Cannot create RAID volume when "
8887c478bd9Sstevel@tonic-gate 			"disk block sizes differ.\n"));
8897c478bd9Sstevel@tonic-gate 		}
8907c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
8917c478bd9Sstevel@tonic-gate 	}
8927c478bd9Sstevel@tonic-gate 
893*05411564Sjesseb 	/*
894*05411564Sjesseb 	 * capacity is now set to the number of blocks on a disk, which is
895*05411564Sjesseb 	 * the total capacity of a mirror.  the capacity of a stripe is the
896*05411564Sjesseb 	 * cumulative amount of blocks on all disks
897*05411564Sjesseb 	 */
898*05411564Sjesseb 	if (rlevel == RAID_STRIPE)
899*05411564Sjesseb 		capacity *= ndisks;
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 	if (get_devctl(disk[0], channel1))
9027c478bd9Sstevel@tonic-gate 		return (FAILURE);
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 	fd = open(channel1, O_RDONLY);
9057c478bd9Sstevel@tonic-gate 	if (fd == -1) {
9067c478bd9Sstevel@tonic-gate 		perror(channel1);
9077c478bd9Sstevel@tonic-gate 		return (FAILURE);
9087c478bd9Sstevel@tonic-gate 	}
9097c478bd9Sstevel@tonic-gate 
910*05411564Sjesseb 	/* get the current configuration */
9117c478bd9Sstevel@tonic-gate 	if (ioctl(fd, RAID_GETCONFIG, &config) < 0) {
9127c478bd9Sstevel@tonic-gate 		raidctl_error("RAID_GETCONFIG");
913*05411564Sjesseb 		goto fail;
9147c478bd9Sstevel@tonic-gate 	}
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 	/*
917*05411564Sjesseb 	 * current support for both LSI1030 and LSI1064 HBAs
918*05411564Sjesseb 	 * get the devid of the HBA so we can determine capabilities
919*05411564Sjesseb 	 */
920*05411564Sjesseb 	if (ioctl(fd, RAID_GETDEVID, &devid) < 0) {
921*05411564Sjesseb 		raidctl_error("RAID_GETDEVID");
922*05411564Sjesseb 		goto fail;
923*05411564Sjesseb 	}
924*05411564Sjesseb 
925*05411564Sjesseb 	if ((devid == LSI_1064) || (devid == LSI_1064E)) {
926*05411564Sjesseb 		/*
927*05411564Sjesseb 		 * 2 raid volumes supported, single channel
928*05411564Sjesseb 		 */
929*05411564Sjesseb 		for (i = 0; i < N_RAIDVOLS; i++) {
930*05411564Sjesseb 			if (config[i].ndisks == 0)
931*05411564Sjesseb 				goto no_secondary_channel;
932*05411564Sjesseb 		}
933*05411564Sjesseb 
934*05411564Sjesseb 		(void) printf(gettext("HBA supports a maximum of 2 "
935*05411564Sjesseb 			"RAID Volumes, HBA is full\n"));
936*05411564Sjesseb 		goto fail;
937*05411564Sjesseb 	}
938*05411564Sjesseb 
939*05411564Sjesseb 	/*
940*05411564Sjesseb 	 * LSI1030, support for single IM volume
941*05411564Sjesseb 	 */
942*05411564Sjesseb 	if (rlevel != RAID_MIRROR) {
943*05411564Sjesseb 		(void) printf(gettext("HBA only supports RAID "
944*05411564Sjesseb 			"level 1 (mirrored) volumes\n"));
945*05411564Sjesseb 		goto fail;
946*05411564Sjesseb 	}
947*05411564Sjesseb 
948*05411564Sjesseb 	if (config[0].ndisks != 0) {
949*05411564Sjesseb 		(void) printf(gettext("RAID Volume already exists "
950*05411564Sjesseb 			"on this controller 'c%dt%dd0'\n"),
951*05411564Sjesseb 			c[0], config[0].targetid);
952*05411564Sjesseb 		goto fail;
953*05411564Sjesseb 	}
954*05411564Sjesseb 	/*
9557c478bd9Sstevel@tonic-gate 	 * Make sure there isn't a raid created on this controller's
956*05411564Sjesseb 	 * other channel, if it has multiple channels
9577c478bd9Sstevel@tonic-gate 	 */
9587c478bd9Sstevel@tonic-gate 	(void) strlcpy(channel2, channel1, sizeof (channel2));
9597c478bd9Sstevel@tonic-gate 	tmp = strrchr(channel2, ':');
9607c478bd9Sstevel@tonic-gate 	tmp[0] = 0;
9617c478bd9Sstevel@tonic-gate 	size = strlen(channel2);
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 	/*
9647c478bd9Sstevel@tonic-gate 	 * Format the channel string for the other channel so we can
965*05411564Sjesseb 	 * see if a raid exists on it.  In this case if we are being
966*05411564Sjesseb 	 * asked to create a raid on channel 2 (indicated by the 1,1
967*05411564Sjesseb 	 * at the end of the string) we want to check channel 1),
968*05411564Sjesseb 	 * otherwise we will check channel 2.
9697c478bd9Sstevel@tonic-gate 	 */
9707c478bd9Sstevel@tonic-gate 	if (channel2[size - 2] == ',') {
9717c478bd9Sstevel@tonic-gate 		channel2[size - 1] = 0;
9727c478bd9Sstevel@tonic-gate 		channel2[size - 2] = 0;
973*05411564Sjesseb 		(void) snprintf(channel2, sizeof (channel2),
974*05411564Sjesseb 				"%s:devctl", channel2);
9757c478bd9Sstevel@tonic-gate 	} else {
976*05411564Sjesseb 		(void) snprintf(channel2, sizeof (channel2),
977*05411564Sjesseb 				"%s,1:devctl", channel2);
9787c478bd9Sstevel@tonic-gate 	}
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 	fd2 = open(channel2, O_RDONLY);
9817c478bd9Sstevel@tonic-gate 	if (fd2 == -1) {
9827c478bd9Sstevel@tonic-gate 		if (errno == ENOENT)
9837c478bd9Sstevel@tonic-gate 			goto no_secondary_channel;
9847c478bd9Sstevel@tonic-gate 		perror(channel2);
985*05411564Sjesseb 		goto fail;
9867c478bd9Sstevel@tonic-gate 	}
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 	if (ioctl(fd2, RAID_GETCONFIG, &config) < 0) {
989*05411564Sjesseb 		goto fail;
9907c478bd9Sstevel@tonic-gate 	}
9917c478bd9Sstevel@tonic-gate 
992*05411564Sjesseb 	if (config[0].ndisks != 0) {
9937c478bd9Sstevel@tonic-gate 		int	cx;
9947c478bd9Sstevel@tonic-gate 		cx = get_controller(channel2);
995*05411564Sjesseb 		(void) printf(gettext("RAID Volume already exists "
996*05411564Sjesseb 			"on this controller 'c%dt%dd0'\n"), cx,
997*05411564Sjesseb 			config[0].targetid);
998*05411564Sjesseb 		goto fail;
9997c478bd9Sstevel@tonic-gate 	}
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate no_secondary_channel:
10027c478bd9Sstevel@tonic-gate 
1003*05411564Sjesseb 	/* all checks complete, fill in the config */
1004*05411564Sjesseb 	newvol.targetid = t[0];
1005*05411564Sjesseb 	newvol.disk[0] = t[0];
1006*05411564Sjesseb 	newvol.raid_level = rlevel;
1007*05411564Sjesseb 	newvol.ndisks = ndisks;
1008*05411564Sjesseb 	newvol.raid_capacity = capacity;
10097c478bd9Sstevel@tonic-gate 
1010*05411564Sjesseb 	/* populate config.disk, and unconfigure all disks, except targetid */
1011*05411564Sjesseb 	for (i = 1; i < ndisks; i++) {
10127c478bd9Sstevel@tonic-gate 		if (do_config_change_state(CFGA_CMD_UNCONFIGURE,
1013*05411564Sjesseb 		    t[i], c[0])) {
10147c478bd9Sstevel@tonic-gate 			perror("config_change_state");
1015*05411564Sjesseb 			goto fail;
1016*05411564Sjesseb 		}
1017*05411564Sjesseb 		newvol.disk[i] = t[i];
10187c478bd9Sstevel@tonic-gate 	}
10197c478bd9Sstevel@tonic-gate 
1020*05411564Sjesseb 	if (ioctl(fd, RAID_CREATE, &newvol)) {
1021*05411564Sjesseb 		/* reconfigure all disks, except targetid */
1022*05411564Sjesseb 		for (i = 1; i < ndisks; i++) {
10237c478bd9Sstevel@tonic-gate 			(void) do_config_change_state(CFGA_CMD_CONFIGURE,
1024*05411564Sjesseb 				newvol.disk[i], c[0]);
1025*05411564Sjesseb 		}
10267c478bd9Sstevel@tonic-gate 		raidctl_error("RAID_CREATE");
1027*05411564Sjesseb 		goto fail;
10287c478bd9Sstevel@tonic-gate 	}
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 	(void) printf(gettext("Volume 'c%dt%dd0' created\n"), c[0], t[0]);
10317c478bd9Sstevel@tonic-gate 	(void) close(fd);
10327c478bd9Sstevel@tonic-gate 	(void) close(fd2);
10337c478bd9Sstevel@tonic-gate 	return (SUCCESS);
10347c478bd9Sstevel@tonic-gate 
1035*05411564Sjesseb fail:
10367c478bd9Sstevel@tonic-gate 	(void) close(fd);
1037*05411564Sjesseb 	(void) close(fd2);
10387c478bd9Sstevel@tonic-gate 	return (FAILURE);
10397c478bd9Sstevel@tonic-gate }
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate static int
10427c478bd9Sstevel@tonic-gate do_delete(char *d)
10437c478bd9Sstevel@tonic-gate {
1044*05411564Sjesseb 	raid_config_t	config[N_RAIDVOLS];
10457c478bd9Sstevel@tonic-gate 	char		disk1[MAXPATHLEN];
10467c478bd9Sstevel@tonic-gate 	char		buf[MAXPATHLEN];
10477c478bd9Sstevel@tonic-gate 	int		fd;
10487c478bd9Sstevel@tonic-gate 	int		target;
10497c478bd9Sstevel@tonic-gate 	int		ctrl;
1050*05411564Sjesseb 	int		i, j;
1051*05411564Sjesseb 	int		wrong_targ = 0;
10527c478bd9Sstevel@tonic-gate 	uint8_t		t;
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 	(void) chdir(DEVDIR);
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 	if ((sscanf(d, "c%dt%dd0", &ctrl, &target)) != 2) {
10577c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Invalid disk format.\n"));
10587c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
10597c478bd9Sstevel@tonic-gate 	}
10607c478bd9Sstevel@tonic-gate 	t = (uint8_t)target;
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	(void) snprintf(disk1, sizeof (disk1), DEVDIR"/%ss2", d);
10637c478bd9Sstevel@tonic-gate 
10647c478bd9Sstevel@tonic-gate 	if (get_devctl(disk1, buf) != 0) {
1065*05411564Sjesseb 		(void) fprintf(stderr, gettext("Not a volume '%s'\n"), d);
10667c478bd9Sstevel@tonic-gate 		return (FAILURE);
10677c478bd9Sstevel@tonic-gate 	}
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 	fd = open(buf, O_RDONLY);
10707c478bd9Sstevel@tonic-gate 	if (fd == -1) {
10717c478bd9Sstevel@tonic-gate 		perror(buf);
10727c478bd9Sstevel@tonic-gate 		return (FAILURE);
10737c478bd9Sstevel@tonic-gate 	}
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	if (ioctl(fd, RAID_GETCONFIG, &config)) {
10767c478bd9Sstevel@tonic-gate 		raidctl_error("RAID_GETCONFIG");
10777c478bd9Sstevel@tonic-gate 		goto fail;
10787c478bd9Sstevel@tonic-gate 	}
10797c478bd9Sstevel@tonic-gate 
1080*05411564Sjesseb 	for (i = 0; i < N_RAIDVOLS; i++) {
1081*05411564Sjesseb 		if (config[i].ndisks != 0) {
1082*05411564Sjesseb 			/* there is a RAID volume in this slot */
1083*05411564Sjesseb 			if (config[i].targetid != t) {
1084*05411564Sjesseb 				wrong_targ++;
1085*05411564Sjesseb 				continue;
1086*05411564Sjesseb 			}
1087*05411564Sjesseb 			/* and it's our target */
1088*05411564Sjesseb 			break;
1089*05411564Sjesseb 		}
1090*05411564Sjesseb 	}
1091*05411564Sjesseb 
1092*05411564Sjesseb 	if (i == N_RAIDVOLS) {
1093*05411564Sjesseb 		/* we found no RAID volumes */
1094*05411564Sjesseb 		(void) fprintf(stderr, gettext("No RAID volumes exist on "
10957c478bd9Sstevel@tonic-gate 			"controller '%d'\n"), ctrl);
10967c478bd9Sstevel@tonic-gate 		goto fail;
10977c478bd9Sstevel@tonic-gate 	}
10987c478bd9Sstevel@tonic-gate 
1099*05411564Sjesseb 	if (wrong_targ == N_RAIDVOLS) {
1100*05411564Sjesseb 		/* we found RAID volumes, but none matched */
11017c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
11027c478bd9Sstevel@tonic-gate 			gettext("RAID volume 'c%dt%dd0' does not exist\n"),
11037c478bd9Sstevel@tonic-gate 			ctrl, t);
11047c478bd9Sstevel@tonic-gate 		goto fail;
11057c478bd9Sstevel@tonic-gate 	}
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 	if (ioctl(fd, RAID_DELETE, &t)) {
11087c478bd9Sstevel@tonic-gate 		perror("RAID_DELETE");
11097c478bd9Sstevel@tonic-gate 		goto fail;
11107c478bd9Sstevel@tonic-gate 	}
11117c478bd9Sstevel@tonic-gate 
1112*05411564Sjesseb 	/* reconfigure all disks, except targetid */
1113*05411564Sjesseb 	for (j = 1; j < config[i].ndisks; j++) {
1114*05411564Sjesseb 		(void) do_config_change_state(CFGA_CMD_CONFIGURE,
1115*05411564Sjesseb 			config[i].disk[j], ctrl);
1116*05411564Sjesseb 	}
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("Volume 'c%dt%dd0' deleted.\n"),
11197c478bd9Sstevel@tonic-gate 		ctrl, target);
11207c478bd9Sstevel@tonic-gate 	(void) close(fd);
11217c478bd9Sstevel@tonic-gate 	return (SUCCESS);
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate fail:
11247c478bd9Sstevel@tonic-gate 	(void) close(fd);
11257c478bd9Sstevel@tonic-gate 	return (FAILURE);
11267c478bd9Sstevel@tonic-gate }
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate static int
11297c478bd9Sstevel@tonic-gate getfcodever(uint8_t *rombuf, uint32_t nbytes, char **fcodeversion)
11307c478bd9Sstevel@tonic-gate {
11317c478bd9Sstevel@tonic-gate 	int x, y, size;
11327c478bd9Sstevel@tonic-gate 	int found_1 = 0, found_2 = 0;
11337c478bd9Sstevel@tonic-gate 	int image_length = 0;
11347c478bd9Sstevel@tonic-gate 	int no_of_images = 0;
11357c478bd9Sstevel@tonic-gate 	uint8_t *rombuf_1 = NULL;
11367c478bd9Sstevel@tonic-gate 	uint16_t image_units = 0;
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate 	/*
11397c478bd9Sstevel@tonic-gate 	 * Single Image - Open firmware image
11407c478bd9Sstevel@tonic-gate 	 */
11417c478bd9Sstevel@tonic-gate 	if (rombuf[gw(&rombuf[PCIR_OFF]) + PCIR_CODETYPE] == 1) {
11427c478bd9Sstevel@tonic-gate 		rombuf_1 = rombuf + gw(rombuf + PCIR_OFF) + PCI_PDS_INDICATOR;
11437c478bd9Sstevel@tonic-gate 		no_of_images = 1;
11447c478bd9Sstevel@tonic-gate 		goto process_image;
11457c478bd9Sstevel@tonic-gate 	}
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate 	/*
11487c478bd9Sstevel@tonic-gate 	 * Combined Image - First Image - x86/PC-AT Bios image
11497c478bd9Sstevel@tonic-gate 	 */
11507c478bd9Sstevel@tonic-gate 	if (rombuf[gw(&rombuf[PCIR_OFF]) + PCIR_CODETYPE] != 0) {
11517c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("This is neither open image"
11527c478bd9Sstevel@tonic-gate 			    " nor Bios/Fcode combined image\n"));
11537c478bd9Sstevel@tonic-gate 		return (1);
11547c478bd9Sstevel@tonic-gate 	}
11557c478bd9Sstevel@tonic-gate 
11567c478bd9Sstevel@tonic-gate 	/*
11577c478bd9Sstevel@tonic-gate 	 * Seek to 2nd Image
11587c478bd9Sstevel@tonic-gate 	 */
11597c478bd9Sstevel@tonic-gate 	rombuf_1 = rombuf + gw(rombuf + PCI_ROM_PCI_DATA_STRUCT_PTR);
11607c478bd9Sstevel@tonic-gate 	image_units = gw(rombuf_1 + PCI_PDS_IMAGE_LENGTH);
11617c478bd9Sstevel@tonic-gate 	image_length = image_units * PCI_IMAGE_UNIT_SIZE;
11627c478bd9Sstevel@tonic-gate 	rombuf_1 += image_length;
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 	/*
11657c478bd9Sstevel@tonic-gate 	 * Combined Image - Second Image - Open Firmware image
11667c478bd9Sstevel@tonic-gate 	 */
11677c478bd9Sstevel@tonic-gate 	if (rombuf_1[PCI_PDS_CODE_TYPE] != 1) {
11687c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("This is neither open image"
11697c478bd9Sstevel@tonic-gate 			    " nor Bios/Fcode combined image\n"));
11707c478bd9Sstevel@tonic-gate 		return (1);
11717c478bd9Sstevel@tonic-gate 	}
11727c478bd9Sstevel@tonic-gate 	rombuf_1 += PCI_PDS_INDICATOR;
11737c478bd9Sstevel@tonic-gate 	no_of_images = 2;
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate process_image:
11767c478bd9Sstevel@tonic-gate 	/*
11777c478bd9Sstevel@tonic-gate 	 * This should be the last image
11787c478bd9Sstevel@tonic-gate 	 */
11797c478bd9Sstevel@tonic-gate 	if (*rombuf_1 != LAST_IMAGE) {
11807c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("This is not a valid "
11817c478bd9Sstevel@tonic-gate 		    "Bios/Fcode image file\n"));
11827c478bd9Sstevel@tonic-gate 		return (1);
11837c478bd9Sstevel@tonic-gate 	}
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 	/*
11867c478bd9Sstevel@tonic-gate 	 * Scan through the bois/fcode file to get the fcode version
11877c478bd9Sstevel@tonic-gate 	 * 0x12 and 0x7 indicate the start of the fcode version string
11887c478bd9Sstevel@tonic-gate 	 */
11897c478bd9Sstevel@tonic-gate 	for (x = 0; x < (nbytes - 8); x++) {
11907c478bd9Sstevel@tonic-gate 		if ((rombuf[x] == FCODE_VERS_KEY1) &&
11917c478bd9Sstevel@tonic-gate 		    (rombuf[x+1] == FCODE_VERS_KEY2) &&
11927c478bd9Sstevel@tonic-gate 		    (rombuf[x+2] == 'v') && (rombuf[x+3] == 'e') &&
11937c478bd9Sstevel@tonic-gate 		    (rombuf[x+4] == 'r') && (rombuf[x+5] == 's') &&
11947c478bd9Sstevel@tonic-gate 		    (rombuf[x+6] == 'i') && (rombuf[x+7] == 'o') &&
11957c478bd9Sstevel@tonic-gate 		    (rombuf[x+8] == 'n')) {
11967c478bd9Sstevel@tonic-gate 			found_1 = 1;
11977c478bd9Sstevel@tonic-gate 			break;
11987c478bd9Sstevel@tonic-gate 		}
11997c478bd9Sstevel@tonic-gate 	}
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 	/*
12027c478bd9Sstevel@tonic-gate 	 * Store the version string if we have found the beginning of it
12037c478bd9Sstevel@tonic-gate 	 */
12047c478bd9Sstevel@tonic-gate 	if (found_1) {
12057c478bd9Sstevel@tonic-gate 		while (x > 0) {
12067c478bd9Sstevel@tonic-gate 			if (rombuf[--x] == FCODE_VERS_KEY1) {
12077c478bd9Sstevel@tonic-gate 				if (rombuf[x-1] != FCODE_VERS_KEY1) {
12087c478bd9Sstevel@tonic-gate 					x++;
12097c478bd9Sstevel@tonic-gate 				}
12107c478bd9Sstevel@tonic-gate 				break;
12117c478bd9Sstevel@tonic-gate 			}
12127c478bd9Sstevel@tonic-gate 		}
12137c478bd9Sstevel@tonic-gate 		if (x > 0) {
12147c478bd9Sstevel@tonic-gate 			*fcodeversion = (char *)malloc(rombuf[x] + 1);
12157c478bd9Sstevel@tonic-gate 			for (y = 0; y < rombuf[x]; y++) {
12167c478bd9Sstevel@tonic-gate 				(*fcodeversion)[y] = rombuf[x+y+1];
12177c478bd9Sstevel@tonic-gate 			}
12187c478bd9Sstevel@tonic-gate 			(*fcodeversion)[y] = '\0';
12197c478bd9Sstevel@tonic-gate 		} else {
12207c478bd9Sstevel@tonic-gate 			found_1 = 0;
12217c478bd9Sstevel@tonic-gate 		}
12227c478bd9Sstevel@tonic-gate 	}
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate 	/*
12257c478bd9Sstevel@tonic-gate 	 * Scan through the bois/fcode file to get the Bios version
12267c478bd9Sstevel@tonic-gate 	 * "@(#)" string indicates the start of the Bios version string
12277c478bd9Sstevel@tonic-gate 	 * Append this version string, after already existing fcode version.
12287c478bd9Sstevel@tonic-gate 	 */
12297c478bd9Sstevel@tonic-gate 	if (no_of_images == 2) {
12307c478bd9Sstevel@tonic-gate 		for (x = 0; x < (nbytes - 4); x++) {
12317c478bd9Sstevel@tonic-gate 			if ((rombuf[x] == '@') && (rombuf[x+1] == '(') &&
12327c478bd9Sstevel@tonic-gate 			    (rombuf[x+2] == '#') && (rombuf[x+3] == ')')) {
12337c478bd9Sstevel@tonic-gate 				found_2 = 1;
12347c478bd9Sstevel@tonic-gate 				break;
12357c478bd9Sstevel@tonic-gate 			}
12367c478bd9Sstevel@tonic-gate 		}
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 		if (found_2) {
12397c478bd9Sstevel@tonic-gate 			x += 4;
12407c478bd9Sstevel@tonic-gate 			(*fcodeversion)[y] = '\n';
12417c478bd9Sstevel@tonic-gate 			size = y + strlen((char *)(rombuf + x)) +
12427c478bd9Sstevel@tonic-gate 			    strlen(BIOS_STR) + 2;
12437c478bd9Sstevel@tonic-gate 			*fcodeversion = (char *)realloc((*fcodeversion), size);
12447c478bd9Sstevel@tonic-gate 			y++;
12457c478bd9Sstevel@tonic-gate 			(*fcodeversion)[y] = '\0';
12467c478bd9Sstevel@tonic-gate 			(void) strlcat(*fcodeversion, BIOS_STR, size);
12477c478bd9Sstevel@tonic-gate 			(void) strlcat(*fcodeversion, (char *)(rombuf + x),
12487c478bd9Sstevel@tonic-gate 			    size);
12497c478bd9Sstevel@tonic-gate 		}
12507c478bd9Sstevel@tonic-gate 	}
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 	return ((found_1 || found_2) ? 0 : 1);
12537c478bd9Sstevel@tonic-gate }
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate static void
12567c478bd9Sstevel@tonic-gate getfwver(uint8_t *rombuf, char *fwversion)
12577c478bd9Sstevel@tonic-gate {
12587c478bd9Sstevel@tonic-gate 	(void) snprintf(fwversion, 8, "%d.%.2d.%.2d.%.2d",
12597c478bd9Sstevel@tonic-gate 		rombuf[FW_ROM_OFFSET_VERSION + 3],
12607c478bd9Sstevel@tonic-gate 		rombuf[FW_ROM_OFFSET_VERSION + 2],
12617c478bd9Sstevel@tonic-gate 		rombuf[FW_ROM_OFFSET_VERSION + 1],
12627c478bd9Sstevel@tonic-gate 		rombuf[FW_ROM_OFFSET_VERSION + 0]);
12637c478bd9Sstevel@tonic-gate }
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate static int
12667c478bd9Sstevel@tonic-gate checkfile(uint8_t *rombuf, uint32_t nbytes, uint32_t chksum, int *imagetype)
12677c478bd9Sstevel@tonic-gate {
12687c478bd9Sstevel@tonic-gate 	char *imageversion = NULL;
12697c478bd9Sstevel@tonic-gate 	char *fwversion;
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate 	fwversion = (char *)malloc(8);
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 	if (gw(&rombuf[0]) == PCIROM_SIG) {
12747c478bd9Sstevel@tonic-gate 		/* imageversion is malloc(2)'ed in getfcodever() */
12757c478bd9Sstevel@tonic-gate 		if (getfcodever(rombuf, nbytes, &imageversion) == 0) {
12767c478bd9Sstevel@tonic-gate 			*imagetype = FCODE_IMAGE;
12777c478bd9Sstevel@tonic-gate 		} else {
12787c478bd9Sstevel@tonic-gate 			*imagetype = UNKNOWN_IMAGE;
12797c478bd9Sstevel@tonic-gate 		}
12807c478bd9Sstevel@tonic-gate 		if (*imagetype != UNKNOWN_IMAGE) {
12817c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Image file contains:\n%s\n"),
12827c478bd9Sstevel@tonic-gate 			    imageversion);
12837c478bd9Sstevel@tonic-gate 			free(imageversion);
12847c478bd9Sstevel@tonic-gate 		} else {
12857c478bd9Sstevel@tonic-gate 			if (imageversion != NULL) {
12867c478bd9Sstevel@tonic-gate 				free(imageversion);
12877c478bd9Sstevel@tonic-gate 			}
12887c478bd9Sstevel@tonic-gate 			return (-1);
12897c478bd9Sstevel@tonic-gate 		}
12907c478bd9Sstevel@tonic-gate 	} else if (gw(&rombuf[3]) == FW_ROM_ID) {
12917c478bd9Sstevel@tonic-gate 			if (chksum != 0) {
12927c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
12937c478bd9Sstevel@tonic-gate 					gettext("The ROM checksum appears bad "
12947c478bd9Sstevel@tonic-gate 					"(%d)\n"), chksum);
12957c478bd9Sstevel@tonic-gate 				return (-1);
12967c478bd9Sstevel@tonic-gate 			}
12977c478bd9Sstevel@tonic-gate 			getfwver(rombuf, fwversion);
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate 			if ((gw(&rombuf[FW_ROM_OFFSET_CHIP_TYPE]) &
13007c478bd9Sstevel@tonic-gate 				MPI_FW_HEADER_PID_PROD_MASK) ==
13017c478bd9Sstevel@tonic-gate 				MPI_FW_HEADER_PID_PROD_IM_SCSI) {
13027c478bd9Sstevel@tonic-gate 				(void) printf(gettext("ROM image contains "
13037c478bd9Sstevel@tonic-gate 					"MPT firmware version %s "
13047c478bd9Sstevel@tonic-gate 					"(w/Integrated Mirroring)\n"),
13057c478bd9Sstevel@tonic-gate 						fwversion);
13067c478bd9Sstevel@tonic-gate 			} else {
13077c478bd9Sstevel@tonic-gate 				(void) printf(gettext("ROM image contains "
13087c478bd9Sstevel@tonic-gate 					"MPT firmware ""version %s\n"),
13097c478bd9Sstevel@tonic-gate 						fwversion);
13107c478bd9Sstevel@tonic-gate 			}
13117c478bd9Sstevel@tonic-gate 			free(fwversion);
13127c478bd9Sstevel@tonic-gate 	} else {
13137c478bd9Sstevel@tonic-gate 
13147c478bd9Sstevel@tonic-gate #ifdef	DEBUG
13157c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "Not valid FCODE image %x\n", gw(&rombuf[0]));
13167c478bd9Sstevel@tonic-gate #else
13177c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("Not valid FCODE image\n"));
13187c478bd9Sstevel@tonic-gate #endif
13197c478bd9Sstevel@tonic-gate 		return (-1);
13207c478bd9Sstevel@tonic-gate 	}
13217c478bd9Sstevel@tonic-gate 	return (0);
13227c478bd9Sstevel@tonic-gate }
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate static int
13257c478bd9Sstevel@tonic-gate updateflash(uint8_t *rombuf, uint32_t nbytes, char *devctl)
13267c478bd9Sstevel@tonic-gate {
13277c478bd9Sstevel@tonic-gate 	int fd = 0;
13287c478bd9Sstevel@tonic-gate 	update_flash_t flashdata;
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate 	fd = open(devctl, O_RDONLY);
13317c478bd9Sstevel@tonic-gate 	if (fd == -1) {
13327c478bd9Sstevel@tonic-gate 		perror(devctl);
13337c478bd9Sstevel@tonic-gate 		return (-1);
13347c478bd9Sstevel@tonic-gate 	}
13357c478bd9Sstevel@tonic-gate 	(void) memset(&flashdata, 0, sizeof (flashdata));
13367c478bd9Sstevel@tonic-gate 	flashdata.ptrbuffer = (caddr_t)rombuf;
13377c478bd9Sstevel@tonic-gate 	flashdata.size = nbytes;
13387c478bd9Sstevel@tonic-gate 	if ((rombuf[0] == 0x55) && (rombuf[1] == 0xaa)) {
13397c478bd9Sstevel@tonic-gate 		flashdata.type = FW_TYPE_FCODE;
13407c478bd9Sstevel@tonic-gate 	} else {
13417c478bd9Sstevel@tonic-gate 		flashdata.type = FW_TYPE_UCODE;
13427c478bd9Sstevel@tonic-gate 	}
13437c478bd9Sstevel@tonic-gate 
13447c478bd9Sstevel@tonic-gate 	if (ioctl(fd, RAID_UPDATEFW, &flashdata)) {
13457c478bd9Sstevel@tonic-gate 		raidctl_error("RAID_UPDATEFW");
13467c478bd9Sstevel@tonic-gate 		(void) close(fd);
13477c478bd9Sstevel@tonic-gate 		return (-1);
13487c478bd9Sstevel@tonic-gate 	}
13497c478bd9Sstevel@tonic-gate 
13507c478bd9Sstevel@tonic-gate 	(void) close(fd);
13517c478bd9Sstevel@tonic-gate 	return (0);
13527c478bd9Sstevel@tonic-gate }
13537c478bd9Sstevel@tonic-gate 
13547c478bd9Sstevel@tonic-gate static int
13557c478bd9Sstevel@tonic-gate readfile(char *filespec, uint8_t **rombuf, uint32_t *nbytes, uint32_t *chksum)
13567c478bd9Sstevel@tonic-gate {
13577c478bd9Sstevel@tonic-gate 	struct stat	statbuf;
13587c478bd9Sstevel@tonic-gate 	uint32_t	count;
13597c478bd9Sstevel@tonic-gate 	uint32_t	checksum = 0;
13607c478bd9Sstevel@tonic-gate 	int		fd, i;
13617c478bd9Sstevel@tonic-gate 	uint8_t		*filebuf;
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate 
13647c478bd9Sstevel@tonic-gate 	if ((fd = open((const char *)filespec, O_RDONLY | O_NDELAY)) == -1) {
13657c478bd9Sstevel@tonic-gate 		perror(filespec);
13667c478bd9Sstevel@tonic-gate 		return (-1);
13677c478bd9Sstevel@tonic-gate 	}
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate 	if (fstat(fd, &statbuf) != 0) {
13707c478bd9Sstevel@tonic-gate 		perror("fstat");
13717c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
13727c478bd9Sstevel@tonic-gate 			gettext("Error getting stats on file\n"));
13737c478bd9Sstevel@tonic-gate 		(void) close(fd);
13747c478bd9Sstevel@tonic-gate 		return (-1);
13757c478bd9Sstevel@tonic-gate 	}
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate #ifdef	DEBUG
13787c478bd9Sstevel@tonic-gate 	(void) printf("Filesize = %ld\n", statbuf.st_size);
13797c478bd9Sstevel@tonic-gate #endif
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate 	filebuf = (uint8_t *)realloc(*rombuf, statbuf.st_size + *nbytes);
13827c478bd9Sstevel@tonic-gate 
13837c478bd9Sstevel@tonic-gate 	count = read(fd, filebuf + *nbytes, statbuf.st_size);
13847c478bd9Sstevel@tonic-gate 	(void) close(fd);
13857c478bd9Sstevel@tonic-gate 	if (count != statbuf.st_size) {
13867c478bd9Sstevel@tonic-gate 		perror("size check");
13877c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("File is corrupt\n"));
13887c478bd9Sstevel@tonic-gate 		return (-1);
13897c478bd9Sstevel@tonic-gate 	}
13907c478bd9Sstevel@tonic-gate 
13917c478bd9Sstevel@tonic-gate 	for (i = 0; i < *nbytes; i++)
13927c478bd9Sstevel@tonic-gate 		checksum += filebuf[i] << (8 * (i & 3));
13937c478bd9Sstevel@tonic-gate 
13947c478bd9Sstevel@tonic-gate 	*rombuf = filebuf;
13957c478bd9Sstevel@tonic-gate 	*nbytes = *nbytes + count;
13967c478bd9Sstevel@tonic-gate 	*chksum = checksum;
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate 	return (0);
13997c478bd9Sstevel@tonic-gate }
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate static int
14027c478bd9Sstevel@tonic-gate yes(int c)
14037c478bd9Sstevel@tonic-gate {
14047c478bd9Sstevel@tonic-gate 	int	i, b;
14057c478bd9Sstevel@tonic-gate 	char    ans[SCHAR_MAX + 1];
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate 	for (i = 0; ; i++) {
14087c478bd9Sstevel@tonic-gate 		b = getchar();
14097c478bd9Sstevel@tonic-gate 		if (b == '\n' || b == '\0' || b == EOF) {
14107c478bd9Sstevel@tonic-gate 			ans[i] = 0;
14117c478bd9Sstevel@tonic-gate 			break;
14127c478bd9Sstevel@tonic-gate 		}
14137c478bd9Sstevel@tonic-gate 		if (i < SCHAR_MAX)
14147c478bd9Sstevel@tonic-gate 			ans[i] = b;
14157c478bd9Sstevel@tonic-gate 	}
14167c478bd9Sstevel@tonic-gate 	if (i >= SCHAR_MAX) {
14177c478bd9Sstevel@tonic-gate 		i = SCHAR_MAX;
14187c478bd9Sstevel@tonic-gate 		ans[SCHAR_MAX] = 0;
14197c478bd9Sstevel@tonic-gate 	}
14207c478bd9Sstevel@tonic-gate 	if ((i != 0) && ((strncmp(yeschr, ans, i)) == 0)) {
14217c478bd9Sstevel@tonic-gate 		return (1);
14227c478bd9Sstevel@tonic-gate 	} else {
14237c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("User response is \"%s\", "
14247c478bd9Sstevel@tonic-gate 		    "Controller %d not flashed.\n\n"), ans, c);
14257c478bd9Sstevel@tonic-gate 		return (0);
14267c478bd9Sstevel@tonic-gate 	}
14277c478bd9Sstevel@tonic-gate }
14287c478bd9Sstevel@tonic-gate 
14297c478bd9Sstevel@tonic-gate static int
14307c478bd9Sstevel@tonic-gate do_flash(int c, char *fpath, int force)
14317c478bd9Sstevel@tonic-gate {
14327c478bd9Sstevel@tonic-gate 	char		devctl[MAXPATHLEN] = {0};
14337c478bd9Sstevel@tonic-gate 	char		buf[MAXPATHLEN] = {0};
14347c478bd9Sstevel@tonic-gate 	int		rv = 0;
14357c478bd9Sstevel@tonic-gate 	int		imagetype;
14367c478bd9Sstevel@tonic-gate 	uint32_t	nbytes = 0;
14377c478bd9Sstevel@tonic-gate 	uint32_t	chksum;
14387c478bd9Sstevel@tonic-gate 	uint8_t		*rombuf = NULL;
14397c478bd9Sstevel@tonic-gate 	char		cwd[MAXPATHLEN];
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 	/*
14427c478bd9Sstevel@tonic-gate 	 * Read fw file
14437c478bd9Sstevel@tonic-gate 	 */
14447c478bd9Sstevel@tonic-gate 	rv = readfile(fpath, &rombuf, &nbytes, &chksum);
14457c478bd9Sstevel@tonic-gate 	if (rv != 0) {
14467c478bd9Sstevel@tonic-gate 		return (FAILURE);
14477c478bd9Sstevel@tonic-gate 	}
14487c478bd9Sstevel@tonic-gate 
14497c478bd9Sstevel@tonic-gate 	(void) getcwd(cwd, sizeof (cwd));
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 	(void) chdir(DEVDIR);
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate 	/* Get link from "/dev/cfg" */
14547c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "/dev/cfg/c%d", c);
14557c478bd9Sstevel@tonic-gate 	if (get_link_path(buf, devctl) != 0) {
14567c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
14577c478bd9Sstevel@tonic-gate 			gettext("Invalid controller '%d'\n"), c);
14587c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
14597c478bd9Sstevel@tonic-gate 	}
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate 	/* Check File */
14627c478bd9Sstevel@tonic-gate 	rv = checkfile(rombuf, nbytes, chksum, &imagetype);
14637c478bd9Sstevel@tonic-gate 	if (rv != 0) {
14647c478bd9Sstevel@tonic-gate 		return (FAILURE);
14657c478bd9Sstevel@tonic-gate 	}
14667c478bd9Sstevel@tonic-gate 
14677c478bd9Sstevel@tonic-gate 	/* Confirm */
14687c478bd9Sstevel@tonic-gate 	if (!force) {
14697c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Update flash image on "
14707c478bd9Sstevel@tonic-gate 			"controller %d (%s/%s)? "), c, yeschr, nochr);
14717c478bd9Sstevel@tonic-gate 		if (!yes(c)) {
14727c478bd9Sstevel@tonic-gate 			return (SUCCESS);
14737c478bd9Sstevel@tonic-gate 		}
14747c478bd9Sstevel@tonic-gate 	}
14757c478bd9Sstevel@tonic-gate 
14767c478bd9Sstevel@tonic-gate 	/* Do Flash */
14777c478bd9Sstevel@tonic-gate 	if (updateflash(rombuf, nbytes, devctl)) {
14787c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Flash not updated on "
14797c478bd9Sstevel@tonic-gate 		    "Controller %d.\n\n"), c);
14807c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
14817c478bd9Sstevel@tonic-gate 	}
14827c478bd9Sstevel@tonic-gate 	(void) printf(gettext("Flash updated successfully.\n\n"));
14837c478bd9Sstevel@tonic-gate 	return (SUCCESS);
14847c478bd9Sstevel@tonic-gate }
14857c478bd9Sstevel@tonic-gate 
14867c478bd9Sstevel@tonic-gate static int
14877c478bd9Sstevel@tonic-gate fully_numeric(char *str)
14887c478bd9Sstevel@tonic-gate {
14897c478bd9Sstevel@tonic-gate 	int	size = strlen(str);
14907c478bd9Sstevel@tonic-gate 	int	i;
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate 	for (i = 0; i < size; i++) {
14937c478bd9Sstevel@tonic-gate 		if (i == 0 && str[i] == '-' && size != 1)
14947c478bd9Sstevel@tonic-gate 			continue;
14957c478bd9Sstevel@tonic-gate 		if (!isdigit(str[i]))
14967c478bd9Sstevel@tonic-gate 			return (0);
14977c478bd9Sstevel@tonic-gate 	}
14987c478bd9Sstevel@tonic-gate 	return (1);
14997c478bd9Sstevel@tonic-gate }
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate /*
15027c478bd9Sstevel@tonic-gate  * Useful parsing macros
15037c478bd9Sstevel@tonic-gate  */
15047c478bd9Sstevel@tonic-gate #define	must_be(s, c)		if (*s++ != c) return (0)
15057c478bd9Sstevel@tonic-gate #define	skip_digits(s)		while (isdigit(*s)) s++
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate /*
15087c478bd9Sstevel@tonic-gate  * Return true if a name is in the internal canonical form
15097c478bd9Sstevel@tonic-gate  */
15107c478bd9Sstevel@tonic-gate static int
15117c478bd9Sstevel@tonic-gate canonical_name(char *name)
15127c478bd9Sstevel@tonic-gate {
15137c478bd9Sstevel@tonic-gate 	must_be(name, 'c');
15147c478bd9Sstevel@tonic-gate 	skip_digits(name);
15157c478bd9Sstevel@tonic-gate 	if (*name == 't') {
15167c478bd9Sstevel@tonic-gate 		name++;
15177c478bd9Sstevel@tonic-gate 		skip_digits(name);
15187c478bd9Sstevel@tonic-gate 	}
15197c478bd9Sstevel@tonic-gate 	must_be(name, 'd');
15207c478bd9Sstevel@tonic-gate 	skip_digits(name);
15217c478bd9Sstevel@tonic-gate 	return (*name == 0);
15227c478bd9Sstevel@tonic-gate }
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate int
15257c478bd9Sstevel@tonic-gate main(int argc, char **argv)
15267c478bd9Sstevel@tonic-gate {
15277c478bd9Sstevel@tonic-gate 	int	rv = SUCCESS;
15287c478bd9Sstevel@tonic-gate 	int	i, c;
15297c478bd9Sstevel@tonic-gate 	int	findex = DO_HW_RAID_INFO;
15307c478bd9Sstevel@tonic-gate 	int	controller;
1531*05411564Sjesseb 	char	*disks[N_DISKS] = {0};
15327c478bd9Sstevel@tonic-gate 	char	*darg;
15337c478bd9Sstevel@tonic-gate 	char	*farg;
1534*05411564Sjesseb 	char	*rarg;
15357c478bd9Sstevel@tonic-gate 	char	*progname;
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate 	int	l_flag = 0;
15387c478bd9Sstevel@tonic-gate 	int	c_flag = 0;
15397c478bd9Sstevel@tonic-gate 	int	d_flag = 0;
15407c478bd9Sstevel@tonic-gate 	int	f_flag = 0;
15417c478bd9Sstevel@tonic-gate 	int	F_flag = 0;
1542*05411564Sjesseb 	int	r_flag = 0;
15437c478bd9Sstevel@tonic-gate 	int	no_flags = 1;
1544*05411564Sjesseb 	int	r = RAID_MIRROR;  /* default raid level is 1 */
15457c478bd9Sstevel@tonic-gate 	char	*current_dir;
15467c478bd9Sstevel@tonic-gate 
15477c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
15487c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate 	if (geteuid() != 0) {
15517c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Must be root.\n"));
15527c478bd9Sstevel@tonic-gate 		exit(1);
15537c478bd9Sstevel@tonic-gate 	}
15547c478bd9Sstevel@tonic-gate 
15557c478bd9Sstevel@tonic-gate 	if ((progname = strrchr(argv[0], '/')) == NULL)
15567c478bd9Sstevel@tonic-gate 		progname = argv[0];
15577c478bd9Sstevel@tonic-gate 	else
15587c478bd9Sstevel@tonic-gate 		progname++;
15597c478bd9Sstevel@tonic-gate 
15607c478bd9Sstevel@tonic-gate 	raids = NULL;
15617c478bd9Sstevel@tonic-gate 
15627c478bd9Sstevel@tonic-gate 	(void) strncpy(yeschr, nl_langinfo(YESSTR), SCHAR_MAX + 1);
15637c478bd9Sstevel@tonic-gate 	(void) strncpy(nochr, nl_langinfo(NOSTR), SCHAR_MAX + 1);
15647c478bd9Sstevel@tonic-gate 
1565*05411564Sjesseb 	while ((c = getopt(argc, argv, "cr:lfd:F:")) != EOF) {
15667c478bd9Sstevel@tonic-gate 		switch (c) {
15677c478bd9Sstevel@tonic-gate 		case 'c':
1568*05411564Sjesseb 			if (f_flag || argc < 4)
15697c478bd9Sstevel@tonic-gate 				usage(progname);
15707c478bd9Sstevel@tonic-gate 			findex = DO_HW_RAID_CREATE;
15717c478bd9Sstevel@tonic-gate 			c_flag = 1;
15727c478bd9Sstevel@tonic-gate 			no_flags = 0;
15737c478bd9Sstevel@tonic-gate 			break;
1574*05411564Sjesseb 		case 'r':
1575*05411564Sjesseb 			rarg = optarg;
1576*05411564Sjesseb 			r = atoi(rarg);
1577*05411564Sjesseb 			if ((r != RAID_STRIPE) && (r != RAID_MIRROR))
1578*05411564Sjesseb 				usage(progname);
1579*05411564Sjesseb 			r_flag = 1;
1580*05411564Sjesseb 			break;
15817c478bd9Sstevel@tonic-gate 		case 'd':
15827c478bd9Sstevel@tonic-gate 			darg = optarg;
15837c478bd9Sstevel@tonic-gate 			d_flag = 1;
15847c478bd9Sstevel@tonic-gate 			findex = DO_HW_RAID_DELETE;
15857c478bd9Sstevel@tonic-gate 			no_flags = 0;
15867c478bd9Sstevel@tonic-gate 			break;
15877c478bd9Sstevel@tonic-gate 		case 'l':
15887c478bd9Sstevel@tonic-gate 			findex = DO_HW_RAID_INFO;
15897c478bd9Sstevel@tonic-gate 			l_flag = 1;
15907c478bd9Sstevel@tonic-gate 			no_flags = 0;
15917c478bd9Sstevel@tonic-gate 			break;
15927c478bd9Sstevel@tonic-gate 		case 'F':
15937c478bd9Sstevel@tonic-gate 			findex = DO_HW_RAID_FLASH;
15947c478bd9Sstevel@tonic-gate 			farg = optarg;
15957c478bd9Sstevel@tonic-gate 			F_flag = 1;
15967c478bd9Sstevel@tonic-gate 			no_flags = 0;
15977c478bd9Sstevel@tonic-gate 			break;
15987c478bd9Sstevel@tonic-gate 		case 'f':
15997c478bd9Sstevel@tonic-gate 			f_flag = 1;
16007c478bd9Sstevel@tonic-gate 			no_flags = 0;
16017c478bd9Sstevel@tonic-gate 			break;
1602*05411564Sjesseb 		case '?':
1603*05411564Sjesseb 		default:
16047c478bd9Sstevel@tonic-gate 			usage(progname);
16057c478bd9Sstevel@tonic-gate 		}
16067c478bd9Sstevel@tonic-gate 	}
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate 	if (no_flags && argc > 1)
16097c478bd9Sstevel@tonic-gate 		usage(progname);
16107c478bd9Sstevel@tonic-gate 
16117c478bd9Sstevel@tonic-gate 	/* compatibility rules */
16127c478bd9Sstevel@tonic-gate 	if (c_flag && d_flag)
16137c478bd9Sstevel@tonic-gate 		usage(progname);
1614*05411564Sjesseb 	if (r_flag && !(c_flag))
16157c478bd9Sstevel@tonic-gate 		usage(progname);
1616*05411564Sjesseb 	if (l_flag && (d_flag || c_flag || f_flag || F_flag || r_flag))
1617*05411564Sjesseb 		usage(progname);
1618*05411564Sjesseb 	if (F_flag && (d_flag || c_flag || l_flag || r_flag))
16197c478bd9Sstevel@tonic-gate 		usage(progname);
16207c478bd9Sstevel@tonic-gate 
16217c478bd9Sstevel@tonic-gate 	switch (findex) {
16227c478bd9Sstevel@tonic-gate 	case DO_HW_RAID_INFO:
16237c478bd9Sstevel@tonic-gate 		if (l_flag) {
16247c478bd9Sstevel@tonic-gate 			/*
16257c478bd9Sstevel@tonic-gate 			 * "raidctl"	makes argc == 1
16267c478bd9Sstevel@tonic-gate 			 * "-l"		makes argc == 2
16277c478bd9Sstevel@tonic-gate 			 */
16287c478bd9Sstevel@tonic-gate 			ctrl_nums = argc - 2;
16297c478bd9Sstevel@tonic-gate 			if (ctrl_nums != 0) {
16307c478bd9Sstevel@tonic-gate 				info_ctrl = (int **)
16317c478bd9Sstevel@tonic-gate 					malloc(ctrl_nums * sizeof (int));
16327c478bd9Sstevel@tonic-gate 				if (info_ctrl == NULL)
16337c478bd9Sstevel@tonic-gate 					return (FAILURE);
16347c478bd9Sstevel@tonic-gate 			}
16357c478bd9Sstevel@tonic-gate 			for (i = 0; i < ctrl_nums; i++) {
16367c478bd9Sstevel@tonic-gate 				char *tmp = argv[i + 2];
16377c478bd9Sstevel@tonic-gate 
16387c478bd9Sstevel@tonic-gate 				info_ctrl[i] = (int *)malloc(2 * sizeof (int));
16397c478bd9Sstevel@tonic-gate 				if (info_ctrl[i] == NULL) {
16407c478bd9Sstevel@tonic-gate 					free(info_ctrl);
16417c478bd9Sstevel@tonic-gate 					return (FAILURE);
16427c478bd9Sstevel@tonic-gate 				}
16437c478bd9Sstevel@tonic-gate 				if (fully_numeric(tmp)) {
16447c478bd9Sstevel@tonic-gate 					(void) sscanf(tmp, "%d",
16457c478bd9Sstevel@tonic-gate 						&info_ctrl[i][INFO_CTRL]);
16467c478bd9Sstevel@tonic-gate 					info_ctrl[i][INFO_STATUS] =
16477c478bd9Sstevel@tonic-gate 						RAID_INVALID_CTRL;
16487c478bd9Sstevel@tonic-gate 				} else {
16497c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
16507c478bd9Sstevel@tonic-gate 					gettext("Invalid controller '%s'\n"),
16517c478bd9Sstevel@tonic-gate 					tmp);
16527c478bd9Sstevel@tonic-gate 					info_ctrl[i][INFO_STATUS] =
16537c478bd9Sstevel@tonic-gate 						RAID_DONT_USE;
16547c478bd9Sstevel@tonic-gate 				}
16557c478bd9Sstevel@tonic-gate 			}
16567c478bd9Sstevel@tonic-gate 		} else if (argc > 1) {
16577c478bd9Sstevel@tonic-gate 			usage(progname);
16587c478bd9Sstevel@tonic-gate 		}
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate 		do_info();
16617c478bd9Sstevel@tonic-gate 		break;
16627c478bd9Sstevel@tonic-gate 	case DO_HW_RAID_CREATE:
16637c478bd9Sstevel@tonic-gate 		for (i = 0; i < N_DISKS; i++) {
1664*05411564Sjesseb 			int p = 2 + (r_flag * 2) + i;
1665*05411564Sjesseb 
1666*05411564Sjesseb 			if (p == argc)
1667*05411564Sjesseb 				break;
1668*05411564Sjesseb 
1669*05411564Sjesseb 			disks[i] = argv[p];
1670*05411564Sjesseb 
16717c478bd9Sstevel@tonic-gate 			if (!canonical_name(disks[i]))
16727c478bd9Sstevel@tonic-gate 				usage(progname);
1673*05411564Sjesseb 
1674*05411564Sjesseb 			/* no more than 2 disks for raid level 1 */
1675*05411564Sjesseb 			if ((r == RAID_MIRROR) && (i > 1))
1676*05411564Sjesseb 				usage(progname);
16777c478bd9Sstevel@tonic-gate 		}
1678*05411564Sjesseb 
1679*05411564Sjesseb 		rv = do_create(disks, r);
16807c478bd9Sstevel@tonic-gate 		break;
16817c478bd9Sstevel@tonic-gate 	case DO_HW_RAID_DELETE:
16827c478bd9Sstevel@tonic-gate 		if (!canonical_name(darg))
16837c478bd9Sstevel@tonic-gate 			usage(progname);
16847c478bd9Sstevel@tonic-gate 
16857c478bd9Sstevel@tonic-gate 		rv = do_delete(darg);
16867c478bd9Sstevel@tonic-gate 		break;
16877c478bd9Sstevel@tonic-gate 	case DO_HW_RAID_FLASH:
16887c478bd9Sstevel@tonic-gate 		ctrl_nums = argc - f_flag - 3;
16897c478bd9Sstevel@tonic-gate 		if (ctrl_nums == 0)
16907c478bd9Sstevel@tonic-gate 			usage(progname);
16917c478bd9Sstevel@tonic-gate 
16927c478bd9Sstevel@tonic-gate 		current_dir = getcwd(NULL, MAXPATHLEN);
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 		for (i = 0; i < ctrl_nums; i++) {
16957c478bd9Sstevel@tonic-gate 			char *tmp = argv[i + 3 + f_flag];
16967c478bd9Sstevel@tonic-gate 			(void) chdir(current_dir);
16977c478bd9Sstevel@tonic-gate 			if (fully_numeric(tmp)) {
16987c478bd9Sstevel@tonic-gate 				(void) sscanf(tmp, "%d", &controller);
16997c478bd9Sstevel@tonic-gate 				rv = do_flash(controller, farg, f_flag);
17007c478bd9Sstevel@tonic-gate 				if (rv == FAILURE)
17017c478bd9Sstevel@tonic-gate 					break;
17027c478bd9Sstevel@tonic-gate 			} else {
17037c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
17047c478bd9Sstevel@tonic-gate 					gettext("Invalid controller '%s'\n"),
17057c478bd9Sstevel@tonic-gate 					tmp);
17067c478bd9Sstevel@tonic-gate 			}
17077c478bd9Sstevel@tonic-gate 		}
17087c478bd9Sstevel@tonic-gate 		free(current_dir);
17097c478bd9Sstevel@tonic-gate 		break;
17107c478bd9Sstevel@tonic-gate 	default:
17117c478bd9Sstevel@tonic-gate 		usage(progname);
17127c478bd9Sstevel@tonic-gate 	}
17137c478bd9Sstevel@tonic-gate 	return (rv);
17147c478bd9Sstevel@tonic-gate }
1715