xref: /titanic_53/usr/src/cmd/raidctl/raidctl.c (revision 8ba1bcfcc383cbdad998864b5dff1133decd99a6)
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 
29*8ba1bcfcSdduvall 
307c478bd9Sstevel@tonic-gate #include <ctype.h>
317c478bd9Sstevel@tonic-gate #include <dirent.h>
327c478bd9Sstevel@tonic-gate #include <errno.h>
337c478bd9Sstevel@tonic-gate #include <fcntl.h>
347c478bd9Sstevel@tonic-gate #include <langinfo.h>
357c478bd9Sstevel@tonic-gate #include <libintl.h>
367c478bd9Sstevel@tonic-gate #include <limits.h>
377c478bd9Sstevel@tonic-gate #include <locale.h>
387c478bd9Sstevel@tonic-gate #include <stdarg.h>
397c478bd9Sstevel@tonic-gate #include <stdio.h>
407c478bd9Sstevel@tonic-gate #include <stdlib.h>
417c478bd9Sstevel@tonic-gate #include <string.h>
427c478bd9Sstevel@tonic-gate #include <strings.h>
437c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
447c478bd9Sstevel@tonic-gate #include <sys/mpt/mpi.h>
457c478bd9Sstevel@tonic-gate #include <sys/mpt/mpi_ioc.h>
467c478bd9Sstevel@tonic-gate #include <sys/stat.h>
477c478bd9Sstevel@tonic-gate #include <sys/types.h>
487c478bd9Sstevel@tonic-gate #include <sys/pci.h>
497c478bd9Sstevel@tonic-gate #include <unistd.h>
507c478bd9Sstevel@tonic-gate #include <sys/mnttab.h>
517c478bd9Sstevel@tonic-gate #include <sys/dkio.h>
527c478bd9Sstevel@tonic-gate #include <config_admin.h>
537c478bd9Sstevel@tonic-gate #include <sys/param.h>
547c478bd9Sstevel@tonic-gate #include <sys/raidioctl.h>
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate /*
577c478bd9Sstevel@tonic-gate  * list of controllers to list
587c478bd9Sstevel@tonic-gate  * setup like this:
597c478bd9Sstevel@tonic-gate  * [ctrl_num]	[status]
607c478bd9Sstevel@tonic-gate  *
617c478bd9Sstevel@tonic-gate  * where status is:
627c478bd9Sstevel@tonic-gate  * RAID Found,
637c478bd9Sstevel@tonic-gate  * No RAID Found
647c478bd9Sstevel@tonic-gate  * RAID not supported on this controller
657c478bd9Sstevel@tonic-gate  * Invalid Controller
667c478bd9Sstevel@tonic-gate  */
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate typedef enum {
697c478bd9Sstevel@tonic-gate 	RAID_FOUND = 0x0,
707c478bd9Sstevel@tonic-gate 	RAID_NOT_FOUND,
717c478bd9Sstevel@tonic-gate 	RAID_NOT_SUPPORTED,
727c478bd9Sstevel@tonic-gate 	RAID_INVALID_CTRL,
737c478bd9Sstevel@tonic-gate 	RAID_DONT_USE
747c478bd9Sstevel@tonic-gate } raidctl_errno_t;
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate /* For no-mixup indexing of info_ctrl */
777c478bd9Sstevel@tonic-gate #define	INFO_CTRL	0
787c478bd9Sstevel@tonic-gate #define	INFO_STATUS	1
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate static int **info_ctrl = NULL;
817c478bd9Sstevel@tonic-gate /* Length of conrollers list */
827c478bd9Sstevel@tonic-gate static int ctrl_nums = 0;
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate #define	DEVDIR			"/dev/rdsk"
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_NOP		-1
887c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_INFO		0
897c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_CREATE	1
907c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_DELETE	2
917c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_FLASH	3
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate /*
947c478bd9Sstevel@tonic-gate  * Error return codes
957c478bd9Sstevel@tonic-gate  */
967c478bd9Sstevel@tonic-gate #define	SUCCESS			0
977c478bd9Sstevel@tonic-gate #define	INVALID_ARG		1
987c478bd9Sstevel@tonic-gate #define	FAILURE			2
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate /*
1017c478bd9Sstevel@tonic-gate  * FW Update Stuff
1027c478bd9Sstevel@tonic-gate  */
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate /* signature and initial offset for PCI expansion rom images */
1057c478bd9Sstevel@tonic-gate #define	PCIROM_SIG	0xaa55	/* offset 0h, length 2 bytes */
1067c478bd9Sstevel@tonic-gate #define	PCIR_OFF	0x18	/* Pointer to PCI Data Structure */
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate /* offsets in PCI data structure header */
1097c478bd9Sstevel@tonic-gate #define	PCIR_DEVID	0x6	/* PCI device id */
1107c478bd9Sstevel@tonic-gate #define	PCIR_CODETYPE   0x14	/* type of code (intel/fcode) */
1117c478bd9Sstevel@tonic-gate #define	PCIR_INDICATOR  0x15	/* "last image" indicator */
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate /* flags for image types */
1147c478bd9Sstevel@tonic-gate #define	BIOS_IMAGE	0x1
1157c478bd9Sstevel@tonic-gate #define	FCODE_IMAGE	0x2
1167c478bd9Sstevel@tonic-gate #define	UNKNOWN_IMAGE	0x3
1177c478bd9Sstevel@tonic-gate #define	LAST_IMAGE	0x80
1187c478bd9Sstevel@tonic-gate #define	NOT_LAST_IMAGE	0
1197c478bd9Sstevel@tonic-gate #define	PCI_IMAGE_UNIT_SIZE	512
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate /* ID's and offsets for MPT Firmware images */
1227c478bd9Sstevel@tonic-gate #define	FW_ROM_ID			0x5aea	/* bytes 4 & 5 of file */
1237c478bd9Sstevel@tonic-gate #define	FW_ROM_OFFSET_CHIP_TYPE		0x22	/* (U16) */
1247c478bd9Sstevel@tonic-gate #define	FW_ROM_OFFSET_VERSION		0x24	/* (U16) */
1257c478bd9Sstevel@tonic-gate #define	FW_ROM_OFFSET_VERSION_NAME	0x44	/* (32 U8) */
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate /* Key to search for when looking for fcode version */
1287c478bd9Sstevel@tonic-gate #define	FCODE_VERS_KEY1		0x12
1297c478bd9Sstevel@tonic-gate #define	FCODE_VERS_KEY2		0x7
1307c478bd9Sstevel@tonic-gate #define	BIOS_STR		"LSI1030 SCSI Host Adapter BIOS  Driver: "
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate /* get a word from a buffer (works with non-word aligned offsets) */
1337c478bd9Sstevel@tonic-gate #define	gw(x) (((x)[0]) + (((x)[1]) << 8))
1347c478bd9Sstevel@tonic-gate 
135*8ba1bcfcSdduvall /* Number of disks currently supported */
136*8ba1bcfcSdduvall #define	N_DISKS		2
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate /*
1397c478bd9Sstevel@tonic-gate  * Function and strings to properly localize our prompt.
1407c478bd9Sstevel@tonic-gate  * So for example in german it would ask (ja/nein) or (yes/no) in
1417c478bd9Sstevel@tonic-gate  * english.
1427c478bd9Sstevel@tonic-gate  */
1437c478bd9Sstevel@tonic-gate static int	yes(int c);
1447c478bd9Sstevel@tonic-gate static char	yeschr[SCHAR_MAX + 2];
1457c478bd9Sstevel@tonic-gate static char	nochr[SCHAR_MAX +2];
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate typedef struct raidlist {
148*8ba1bcfcSdduvall 	raid_config_t	raid_config;
1497c478bd9Sstevel@tonic-gate 	int	controller;
1507c478bd9Sstevel@tonic-gate 	char	devctl[MAXPATHLEN];
1517c478bd9Sstevel@tonic-gate 	struct raidlist *next;
1527c478bd9Sstevel@tonic-gate } raidlist_t;
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate static raidlist_t	*raids;
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate static void
1577c478bd9Sstevel@tonic-gate usage(char *prog_name)
1587c478bd9Sstevel@tonic-gate {
1597c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("usage: %s\n"), prog_name);
1607c478bd9Sstevel@tonic-gate 
161*8ba1bcfcSdduvall 	(void) fprintf(stderr, gettext("usage: %s -c disk1 disk2\n"),
1627c478bd9Sstevel@tonic-gate 		prog_name);
163*8ba1bcfcSdduvall 	(void) fprintf(stderr, gettext("usage: %s -d disk1\n"), prog_name);
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
1667c478bd9Sstevel@tonic-gate 		gettext("usage: %s [-f] -F image_file controller \n"),
1677c478bd9Sstevel@tonic-gate 		prog_name);
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("usage: %s -l [controller...]\n"),
1707c478bd9Sstevel@tonic-gate 		prog_name);
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("example:\n"));
1737c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s -c c1t1d0 c1t2d0\n", prog_name);
1747c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s -d c1t1d0\n", prog_name);
1757c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s -F image 1\n", prog_name);
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	exit(1);
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate /* Make errno message more "user friendly" */
1817c478bd9Sstevel@tonic-gate static void
1827c478bd9Sstevel@tonic-gate raidctl_error(char *str)
1837c478bd9Sstevel@tonic-gate {
1847c478bd9Sstevel@tonic-gate 	switch (errno) {
1853a4e43d3Ssafa 	case EINVAL:
1863a4e43d3Ssafa 		(void) fprintf(stderr, gettext("Error: "
1873a4e43d3Ssafa 			"invalid argument would be returned\n"));
1883a4e43d3Ssafa 		break;
1897c478bd9Sstevel@tonic-gate 	case EIO:
1907c478bd9Sstevel@tonic-gate 	case EFAULT:
1917c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1927c478bd9Sstevel@tonic-gate 			gettext("Error: Device inaccessible.\n"));
1937c478bd9Sstevel@tonic-gate 		break;
1947c478bd9Sstevel@tonic-gate 	case ENOTTY:
1957c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Error: "
1967c478bd9Sstevel@tonic-gate 			"Device does not support requested action.\n"));
1977c478bd9Sstevel@tonic-gate 		break;
1987c478bd9Sstevel@tonic-gate 	default:
1997c478bd9Sstevel@tonic-gate 		perror(str);
2007c478bd9Sstevel@tonic-gate 	}
2017c478bd9Sstevel@tonic-gate }
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate static int
2047c478bd9Sstevel@tonic-gate get_link_path(const char *thing, char *buf)
2057c478bd9Sstevel@tonic-gate {
2067c478bd9Sstevel@tonic-gate 	if (readlink(thing, buf, MAXPATHLEN) < 0)
2077c478bd9Sstevel@tonic-gate 		return (1);
2087c478bd9Sstevel@tonic-gate 	return (0);
2097c478bd9Sstevel@tonic-gate }
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate static int
2127c478bd9Sstevel@tonic-gate get_ctrl_devctl(char *ctrl, char *b)
2137c478bd9Sstevel@tonic-gate {
2147c478bd9Sstevel@tonic-gate 	char	devctl_buf[MAXPATHLEN];
2157c478bd9Sstevel@tonic-gate 	char	*colon;
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	(void) strlcpy(devctl_buf, ctrl, MAXPATHLEN);
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	colon = strrchr(devctl_buf, ':');
2207c478bd9Sstevel@tonic-gate 	if (colon == NULL)
2217c478bd9Sstevel@tonic-gate 		return (1);
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	*colon = 0;
2247c478bd9Sstevel@tonic-gate 	(void) snprintf(devctl_buf, MAXPATHLEN, "%s:devctl", devctl_buf);
2257c478bd9Sstevel@tonic-gate 	(void) strlcpy(b, devctl_buf, MAXPATHLEN);
2267c478bd9Sstevel@tonic-gate 	return (0);
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate static int
2307c478bd9Sstevel@tonic-gate get_devctl(char *disk, char *b)
2317c478bd9Sstevel@tonic-gate {
2327c478bd9Sstevel@tonic-gate 	char	buf1[MAXPATHLEN] = {0};
2337c478bd9Sstevel@tonic-gate 	char	devctl_buf[MAXPATHLEN];
2347c478bd9Sstevel@tonic-gate 	char	*slash;
2357c478bd9Sstevel@tonic-gate 	char	devname[32];
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	if (get_link_path(disk, buf1))
2387c478bd9Sstevel@tonic-gate 		return (1);
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	(void) strlcpy(devctl_buf, buf1, MAXPATHLEN);
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	slash = strrchr(devctl_buf, '/');
2437c478bd9Sstevel@tonic-gate 	if (slash == NULL)
2447c478bd9Sstevel@tonic-gate 		return (1);
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	*slash = 0;
2477c478bd9Sstevel@tonic-gate 	slash = strrchr(devctl_buf, '/');
2487c478bd9Sstevel@tonic-gate 	(void) strlcpy(devname, slash, 32);
2497c478bd9Sstevel@tonic-gate 	*slash = 0;
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	(void) snprintf(devctl_buf, MAXPATHLEN, "%s%s:devctl",
2527c478bd9Sstevel@tonic-gate 		devctl_buf, devname);
2537c478bd9Sstevel@tonic-gate 	(void) strlcpy(b, devctl_buf, MAXPATHLEN);
2547c478bd9Sstevel@tonic-gate 	return (0);
2557c478bd9Sstevel@tonic-gate }
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate static int
2587c478bd9Sstevel@tonic-gate already_there(int controller)
2597c478bd9Sstevel@tonic-gate {
2607c478bd9Sstevel@tonic-gate 	raidlist_t	*curr = raids;
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
2637c478bd9Sstevel@tonic-gate 		if (curr->controller == controller)
2647c478bd9Sstevel@tonic-gate 			return (1);
2657c478bd9Sstevel@tonic-gate 		curr = curr->next;
2667c478bd9Sstevel@tonic-gate 	}
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	return (0);
2697c478bd9Sstevel@tonic-gate }
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate /*
2727c478bd9Sstevel@tonic-gate  * Display those controllers where RAID volumes were not found
2737c478bd9Sstevel@tonic-gate  */
2747c478bd9Sstevel@tonic-gate static void
2757c478bd9Sstevel@tonic-gate print_no_raids()
2767c478bd9Sstevel@tonic-gate {
2777c478bd9Sstevel@tonic-gate 	int i, space = 0;
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	if (info_ctrl == NULL)
2807c478bd9Sstevel@tonic-gate 		return;
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	for (i = 0; i < ctrl_nums; i++) {
2837c478bd9Sstevel@tonic-gate 		/* Status of '0' means RAID exists at that controller */
2847c478bd9Sstevel@tonic-gate 		if (info_ctrl[i][INFO_STATUS] == RAID_FOUND ||
2857c478bd9Sstevel@tonic-gate 		    info_ctrl[i][INFO_STATUS] == RAID_DONT_USE)
2867c478bd9Sstevel@tonic-gate 			continue;
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 		if (!space && raids != NULL) {
2897c478bd9Sstevel@tonic-gate 			(void) printf("\n");
2907c478bd9Sstevel@tonic-gate 			space = 1;
2917c478bd9Sstevel@tonic-gate 		}
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 		/* switch statement used to enable gettext()'ing of text */
2947c478bd9Sstevel@tonic-gate 		switch (info_ctrl[i][INFO_STATUS]) {
2957c478bd9Sstevel@tonic-gate 		case RAID_INVALID_CTRL:
2967c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Invalid controller '%d'\n"),
2977c478bd9Sstevel@tonic-gate 				info_ctrl[i][INFO_CTRL]);
2987c478bd9Sstevel@tonic-gate 			break;
2997c478bd9Sstevel@tonic-gate 		case RAID_NOT_SUPPORTED:
3007c478bd9Sstevel@tonic-gate 			(void) printf(gettext("No RAID supported "
3017c478bd9Sstevel@tonic-gate 				"on controller '%d'\n"),
3027c478bd9Sstevel@tonic-gate 					info_ctrl[i][INFO_CTRL]);
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 			break;
3057c478bd9Sstevel@tonic-gate 		default:
3067c478bd9Sstevel@tonic-gate 			(void) printf(gettext("No RAID volumes found on "
3077c478bd9Sstevel@tonic-gate 				"controller '%d'\n"), info_ctrl[i][INFO_CTRL]);
3087c478bd9Sstevel@tonic-gate 		}
3097c478bd9Sstevel@tonic-gate 	}
3107c478bd9Sstevel@tonic-gate }
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate static void
3137c478bd9Sstevel@tonic-gate add_raid_to_raidlist(char *ctrl_name, int controller)
3147c478bd9Sstevel@tonic-gate {
315*8ba1bcfcSdduvall 	raid_config_t	config;
3167c478bd9Sstevel@tonic-gate 	raidlist_t		*curr;
3177c478bd9Sstevel@tonic-gate 	char			buf[MAXPATHLEN] = {0};
3187c478bd9Sstevel@tonic-gate 	char			buf1[MAXPATHLEN] = {0};
319*8ba1bcfcSdduvall 	int			fd;
320*8ba1bcfcSdduvall 	int			i;
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	if (readlink(ctrl_name, buf, sizeof (buf)) < 0)
3237c478bd9Sstevel@tonic-gate 		return;
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	if (get_ctrl_devctl(buf, buf1))
3267c478bd9Sstevel@tonic-gate 		return;
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	/*
3297c478bd9Sstevel@tonic-gate 	 * If "-l" was specified, then only look at those controllers
3307c478bd9Sstevel@tonic-gate 	 * listed as part of the command line input.
3317c478bd9Sstevel@tonic-gate 	 */
3327c478bd9Sstevel@tonic-gate 	if (info_ctrl != NULL) {
333*8ba1bcfcSdduvall 		int found = 0;
3347c478bd9Sstevel@tonic-gate 		for (i = 0; i < ctrl_nums; i++) {
3357c478bd9Sstevel@tonic-gate 			if (info_ctrl[i][INFO_STATUS] == RAID_DONT_USE)
3367c478bd9Sstevel@tonic-gate 				continue;
337*8ba1bcfcSdduvall 			if (controller == info_ctrl[i][INFO_CTRL]) {
338*8ba1bcfcSdduvall 				found = 1;
3397c478bd9Sstevel@tonic-gate 				break;
3407c478bd9Sstevel@tonic-gate 			}
341*8ba1bcfcSdduvall 		}
342*8ba1bcfcSdduvall 		if (!found)
3437c478bd9Sstevel@tonic-gate 			return;
3447c478bd9Sstevel@tonic-gate 	}
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	fd = open(buf1, O_RDONLY);
3477c478bd9Sstevel@tonic-gate 	if (fd == -1) {
3487c478bd9Sstevel@tonic-gate 		if (info_ctrl != NULL)
3497c478bd9Sstevel@tonic-gate 			info_ctrl[i][INFO_STATUS] = RAID_INVALID_CTRL;
3507c478bd9Sstevel@tonic-gate 		return;
3517c478bd9Sstevel@tonic-gate 	}
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	if (ioctl(fd, RAID_GETCONFIG, &config) < 0) {
3547c478bd9Sstevel@tonic-gate 		if (info_ctrl != NULL)
3557c478bd9Sstevel@tonic-gate 			info_ctrl[i][INFO_STATUS] = RAID_NOT_SUPPORTED;
3567c478bd9Sstevel@tonic-gate 		(void) close(fd);
3577c478bd9Sstevel@tonic-gate 		/* Fail silently */
3587c478bd9Sstevel@tonic-gate 		return;
3597c478bd9Sstevel@tonic-gate 	}
3607c478bd9Sstevel@tonic-gate 	(void) close(fd);
3617c478bd9Sstevel@tonic-gate 
362*8ba1bcfcSdduvall 	if (config.ndisks == 0) {
3637c478bd9Sstevel@tonic-gate 		if (info_ctrl != NULL)
3647c478bd9Sstevel@tonic-gate 			info_ctrl[i][INFO_STATUS] = RAID_NOT_FOUND;
3657c478bd9Sstevel@tonic-gate 		return;
3667c478bd9Sstevel@tonic-gate 	}
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	if (info_ctrl != NULL)
3697c478bd9Sstevel@tonic-gate 		info_ctrl[i][INFO_STATUS] = RAID_FOUND;
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	if (raids == NULL) {
3727c478bd9Sstevel@tonic-gate 		raids = (raidlist_t *)malloc(sizeof (raidlist_t));
3737c478bd9Sstevel@tonic-gate 		curr = raids;
3747c478bd9Sstevel@tonic-gate 	} else {
3757c478bd9Sstevel@tonic-gate 		if (already_there(controller)) {
3767c478bd9Sstevel@tonic-gate 			return;
3777c478bd9Sstevel@tonic-gate 		}
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 		curr = raids;
3807c478bd9Sstevel@tonic-gate 		/* Seek to the end */
3817c478bd9Sstevel@tonic-gate 		while (curr->next != NULL)
3827c478bd9Sstevel@tonic-gate 			curr = curr->next;
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 		curr->next = (raidlist_t *)malloc(sizeof (raidlist_t));
3857c478bd9Sstevel@tonic-gate 		curr = curr->next;
3867c478bd9Sstevel@tonic-gate 	}
3877c478bd9Sstevel@tonic-gate 	curr->next = NULL;
3887c478bd9Sstevel@tonic-gate 	curr->controller = controller;
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	(void) strlcpy(curr->devctl, buf1, sizeof (curr->devctl));
3917c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
392*8ba1bcfcSdduvall 	(void) memcpy(&curr->raid_config, &config, sizeof (raid_config_t));
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate static void
3967c478bd9Sstevel@tonic-gate print_header()
3977c478bd9Sstevel@tonic-gate {
398*8ba1bcfcSdduvall 	(void) printf(gettext("RAID\t\tRAID\t\tRAID\t\tDisk"));
3997c478bd9Sstevel@tonic-gate 	(void) printf("\n");
400*8ba1bcfcSdduvall 	(void) printf(gettext("Volume\t\tStatus\t\tDisk\t\tStatus"));
4017c478bd9Sstevel@tonic-gate 	(void) printf("\n");
4027c478bd9Sstevel@tonic-gate 	(void) printf("------------------------------------------------------");
4037c478bd9Sstevel@tonic-gate 	(void) printf("\n");
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate static void
4077c478bd9Sstevel@tonic-gate print_raidconfig(int c, raid_config_t config)
4087c478bd9Sstevel@tonic-gate {
4097c478bd9Sstevel@tonic-gate 	int	i;
4107c478bd9Sstevel@tonic-gate 
411*8ba1bcfcSdduvall 	/* Get RAID Volume */
412*8ba1bcfcSdduvall 	(void) printf("c%dt%dd0\t\t", c, config.targetid);
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	/* Get RAID Info */
4157c478bd9Sstevel@tonic-gate 	if (config.flags & RAID_FLAG_RESYNCING &&
4167c478bd9Sstevel@tonic-gate 	    config.state == RAID_STATE_DEGRADED) {
4177c478bd9Sstevel@tonic-gate 		(void) printf(gettext("RESYNCING\t"));
4187c478bd9Sstevel@tonic-gate 	} else if (config.state == RAID_STATE_DEGRADED) {
4197c478bd9Sstevel@tonic-gate 		(void) printf(gettext("DEGRADED\t"));
4207c478bd9Sstevel@tonic-gate 	} else if (config.state == RAID_STATE_OPTIMAL) {
4217c478bd9Sstevel@tonic-gate 		(void) printf(gettext("OK\t\t"));
4227c478bd9Sstevel@tonic-gate 	} else if (config.state == RAID_STATE_FAILED) {
4237c478bd9Sstevel@tonic-gate 		(void) printf(gettext("FAILED\t\t"));
4247c478bd9Sstevel@tonic-gate 	} else {
4257c478bd9Sstevel@tonic-gate 		(void) printf(gettext("ERROR\t\t"));
4267c478bd9Sstevel@tonic-gate 	}
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	/* Get RAID Disks */
4297c478bd9Sstevel@tonic-gate 	(void) printf("c%dt%dd0\t\t", c, config.disk[0]);
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	/* Get RAID Disk's Status */
4327c478bd9Sstevel@tonic-gate 	if (config.diskstatus[0] & RAID_DISKSTATUS_FAILED) {
4337c478bd9Sstevel@tonic-gate 		(void) printf(gettext("FAILED\n"));
4347c478bd9Sstevel@tonic-gate 	} else if (config.diskstatus[0] & RAID_DISKSTATUS_MISSING) {
4357c478bd9Sstevel@tonic-gate 		(void) printf(gettext("MISSING\n"));
4367c478bd9Sstevel@tonic-gate 	} else {
4377c478bd9Sstevel@tonic-gate 		(void) printf(gettext("OK\n"));
4387c478bd9Sstevel@tonic-gate 	}
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	for (i = 1; i < config.ndisks; i++) {
4417c478bd9Sstevel@tonic-gate 		(void) printf("\t\t\t\tc%dt%dd0\t\t", c, config.disk[i]);
4427c478bd9Sstevel@tonic-gate 		if (config.diskstatus[i] & RAID_DISKSTATUS_FAILED) {
4437c478bd9Sstevel@tonic-gate 			(void) printf(gettext("FAILED\n"));
4447c478bd9Sstevel@tonic-gate 		} else if (config.diskstatus[i] & RAID_DISKSTATUS_MISSING) {
4457c478bd9Sstevel@tonic-gate 			(void) printf(gettext("MISSING\n"));
4467c478bd9Sstevel@tonic-gate 		} else {
4477c478bd9Sstevel@tonic-gate 			(void) printf(gettext("OK\n"));
4487c478bd9Sstevel@tonic-gate 		}
4497c478bd9Sstevel@tonic-gate 	}
4507c478bd9Sstevel@tonic-gate }
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate static void
4537c478bd9Sstevel@tonic-gate print_disklist()
4547c478bd9Sstevel@tonic-gate {
4557c478bd9Sstevel@tonic-gate 	raidlist_t	*curr = raids;
4567c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
457*8ba1bcfcSdduvall 		print_raidconfig(curr->controller, curr->raid_config);
4587c478bd9Sstevel@tonic-gate 		curr = curr->next;
4597c478bd9Sstevel@tonic-gate 	}
4607c478bd9Sstevel@tonic-gate }
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate static void
4637c478bd9Sstevel@tonic-gate free_disklist()
4647c478bd9Sstevel@tonic-gate {
4657c478bd9Sstevel@tonic-gate 	raidlist_t	*curr = raids;
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
4687c478bd9Sstevel@tonic-gate 		raidlist_t	*temp;
4697c478bd9Sstevel@tonic-gate 		temp = curr;
4707c478bd9Sstevel@tonic-gate 		curr = curr->next;
4717c478bd9Sstevel@tonic-gate 		free(temp);
4727c478bd9Sstevel@tonic-gate 	}
4737c478bd9Sstevel@tonic-gate }
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate static void
4767c478bd9Sstevel@tonic-gate do_search()
4777c478bd9Sstevel@tonic-gate {
4787c478bd9Sstevel@tonic-gate 	DIR		*dir;
4797c478bd9Sstevel@tonic-gate 	struct dirent	*dp;
4807c478bd9Sstevel@tonic-gate 	char		buf[MAXPATHLEN];
4817c478bd9Sstevel@tonic-gate 	int		c;
4827c478bd9Sstevel@tonic-gate 	int		i, j;
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	/*
4857c478bd9Sstevel@tonic-gate 	 * In case repeated numbers were found, assign the repititions as
4867c478bd9Sstevel@tonic-gate 	 * RAID_DONT_USE
4877c478bd9Sstevel@tonic-gate 	 */
4887c478bd9Sstevel@tonic-gate 	for (i = 0; i < ctrl_nums; i++) {
4897c478bd9Sstevel@tonic-gate 		int first_one = 1;
4907c478bd9Sstevel@tonic-gate 		for (j = 0; j < ctrl_nums; j++) {
4917c478bd9Sstevel@tonic-gate 			if (info_ctrl[i][INFO_CTRL] ==
4927c478bd9Sstevel@tonic-gate 				info_ctrl[j][INFO_CTRL]) {
4937c478bd9Sstevel@tonic-gate 				if (info_ctrl[j][INFO_STATUS] == RAID_DONT_USE)
4947c478bd9Sstevel@tonic-gate 					continue;
4957c478bd9Sstevel@tonic-gate 				if (first_one) {
4967c478bd9Sstevel@tonic-gate 					first_one = 0;
4977c478bd9Sstevel@tonic-gate 				} else {
4987c478bd9Sstevel@tonic-gate 					info_ctrl[j][INFO_STATUS] =
4997c478bd9Sstevel@tonic-gate 						RAID_DONT_USE;
5007c478bd9Sstevel@tonic-gate 				}
5017c478bd9Sstevel@tonic-gate 			}
5027c478bd9Sstevel@tonic-gate 		}
5037c478bd9Sstevel@tonic-gate 	}
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	if ((dir = opendir("/dev/cfg")) == NULL) {
5067c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
5077c478bd9Sstevel@tonic-gate 			gettext("Cannot open /dev/cfg: %s\n"), strerror(errno));
5087c478bd9Sstevel@tonic-gate 		return;
5097c478bd9Sstevel@tonic-gate 	}
5107c478bd9Sstevel@tonic-gate 	while ((dp = readdir(dir)) != NULL) {
5117c478bd9Sstevel@tonic-gate 		if (strcmp(dp->d_name, ".") == 0 ||
5127c478bd9Sstevel@tonic-gate 		    strcmp(dp->d_name, "..") == 0)
5137c478bd9Sstevel@tonic-gate 			continue;
5147c478bd9Sstevel@tonic-gate 		if (sscanf(dp->d_name, "c%d", &c) != 1)
5157c478bd9Sstevel@tonic-gate 			continue;
5167c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), "/dev/cfg/%s", dp->d_name);
5177c478bd9Sstevel@tonic-gate 		add_raid_to_raidlist(buf, c);
5187c478bd9Sstevel@tonic-gate 	}
5197c478bd9Sstevel@tonic-gate 	(void) closedir(dir);
5207c478bd9Sstevel@tonic-gate }
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate /*
5237c478bd9Sstevel@tonic-gate  * do_info() will do the following:
5247c478bd9Sstevel@tonic-gate  * - create a list of disks' devctls
5257c478bd9Sstevel@tonic-gate  * - try to talk to each of the devctls found
5267c478bd9Sstevel@tonic-gate  * - if raid configuration is found, display it.
5277c478bd9Sstevel@tonic-gate  */
5287c478bd9Sstevel@tonic-gate static void
5297c478bd9Sstevel@tonic-gate do_info()
5307c478bd9Sstevel@tonic-gate {
5317c478bd9Sstevel@tonic-gate 	int i;
5327c478bd9Sstevel@tonic-gate 	(void) chdir(DEVDIR);
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	do_search();
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	if (raids == NULL) {
5377c478bd9Sstevel@tonic-gate 		if (info_ctrl != NULL) {
5387c478bd9Sstevel@tonic-gate 			print_no_raids();
5397c478bd9Sstevel@tonic-gate 			for (i = 0; i < ctrl_nums; i++)
5407c478bd9Sstevel@tonic-gate 				free(info_ctrl[i]);
5417c478bd9Sstevel@tonic-gate 			free(info_ctrl);
5427c478bd9Sstevel@tonic-gate 		} else {
5437c478bd9Sstevel@tonic-gate 			(void) printf(gettext("No RAID volumes found\n"));
5447c478bd9Sstevel@tonic-gate 		}
5457c478bd9Sstevel@tonic-gate 		return;
5467c478bd9Sstevel@tonic-gate 	}
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	print_header();
5497c478bd9Sstevel@tonic-gate 	print_disklist();
5507c478bd9Sstevel@tonic-gate 	print_no_raids();
5517c478bd9Sstevel@tonic-gate 	free_disklist();
5527c478bd9Sstevel@tonic-gate 	if (info_ctrl) {
5537c478bd9Sstevel@tonic-gate 		for (i = 0; i < ctrl_nums; i++)
5547c478bd9Sstevel@tonic-gate 			free(info_ctrl[i]);
5557c478bd9Sstevel@tonic-gate 		free(info_ctrl);
5567c478bd9Sstevel@tonic-gate 	}
5577c478bd9Sstevel@tonic-gate }
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate static int
5607c478bd9Sstevel@tonic-gate disk_there(int c, int t)
5617c478bd9Sstevel@tonic-gate {
5627c478bd9Sstevel@tonic-gate 	char	disk[100];
5637c478bd9Sstevel@tonic-gate 	int	fd;
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	(void) snprintf(disk, sizeof (disk), "c%dt%dd0s2", c, t);
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	fd = open(disk, O_RDWR | O_NDELAY);
5687c478bd9Sstevel@tonic-gate 	if (fd == -1) {
5697c478bd9Sstevel@tonic-gate 		return (-1);
5707c478bd9Sstevel@tonic-gate 	}
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 	(void) close(fd);
5737c478bd9Sstevel@tonic-gate 	return (0);
5747c478bd9Sstevel@tonic-gate }
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate static int
5777c478bd9Sstevel@tonic-gate get_controller(char *dev)
5787c478bd9Sstevel@tonic-gate {
5797c478bd9Sstevel@tonic-gate 	raidlist_t	*curr;
5807c478bd9Sstevel@tonic-gate 	int		c;
5817c478bd9Sstevel@tonic-gate 	do_search();
5827c478bd9Sstevel@tonic-gate 	curr = raids;
5837c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
5847c478bd9Sstevel@tonic-gate 		if (strcmp(curr->devctl, dev) == 0) {
5857c478bd9Sstevel@tonic-gate 			c = curr->controller;
5867c478bd9Sstevel@tonic-gate 			break;
5877c478bd9Sstevel@tonic-gate 		}
5887c478bd9Sstevel@tonic-gate 		curr = curr->next;
5897c478bd9Sstevel@tonic-gate 	}
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	free_disklist();
5927c478bd9Sstevel@tonic-gate 	return (c);
5937c478bd9Sstevel@tonic-gate }
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate static int
5967c478bd9Sstevel@tonic-gate disk_mounted(char *d)
5977c478bd9Sstevel@tonic-gate {
5987c478bd9Sstevel@tonic-gate 	struct mnttab	mt;
5997c478bd9Sstevel@tonic-gate 	FILE		*f = fopen("/etc/mnttab", "r");
6007c478bd9Sstevel@tonic-gate 
601*8ba1bcfcSdduvall 	while (getmntent(f, &mt) != EOF)
6027c478bd9Sstevel@tonic-gate 		if (strstr(mt.mnt_special, d) != NULL)
6037c478bd9Sstevel@tonic-gate 			return (1);
6047c478bd9Sstevel@tonic-gate 	return (0);
6057c478bd9Sstevel@tonic-gate }
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate static int
6087c478bd9Sstevel@tonic-gate disk_big_enough(char **d, diskaddr_t *cap, int *errcond)
6097c478bd9Sstevel@tonic-gate {
6107c478bd9Sstevel@tonic-gate 	struct dk_minfo minfo;
6117c478bd9Sstevel@tonic-gate 	char		disk[N_DISKS][MAXPATHLEN];
612*8ba1bcfcSdduvall 	diskaddr_t	disk_lbsize[N_DISKS];
6137c478bd9Sstevel@tonic-gate 	diskaddr_t	disk_capacity[N_DISKS];
6147c478bd9Sstevel@tonic-gate 	int		i, fd;
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	for (i = 0; i < N_DISKS; i++) {
6177c478bd9Sstevel@tonic-gate 		(void) snprintf(disk[i], sizeof (disk[i]), DEVDIR"/%ss2", d[i]);
6187c478bd9Sstevel@tonic-gate 		fd = open(disk[i],  O_RDWR | O_NDELAY);
619*8ba1bcfcSdduvall 		if (fd == -1) {
6207c478bd9Sstevel@tonic-gate 			return (FAILURE);
621*8ba1bcfcSdduvall 		}
622*8ba1bcfcSdduvall 
6237c478bd9Sstevel@tonic-gate 		if (ioctl(fd, DKIOCGMEDIAINFO, &minfo) == -1) {
6247c478bd9Sstevel@tonic-gate 			(void) close(fd);
6257c478bd9Sstevel@tonic-gate 			return (FAILURE);
6267c478bd9Sstevel@tonic-gate 		}
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 		disk_lbsize[i] = minfo.dki_lbsize;
6297c478bd9Sstevel@tonic-gate 		disk_capacity[i] = minfo.dki_capacity;
630*8ba1bcfcSdduvall 		(void) close(fd);
631*8ba1bcfcSdduvall 	}
6327c478bd9Sstevel@tonic-gate 
633*8ba1bcfcSdduvall 	/* lbsize must be the same on both disks */
634*8ba1bcfcSdduvall 	if (disk_lbsize[0] != disk_lbsize[1]) {
6357c478bd9Sstevel@tonic-gate 		*errcond = 2;
6367c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
6377c478bd9Sstevel@tonic-gate 	}
6387c478bd9Sstevel@tonic-gate 
639*8ba1bcfcSdduvall 	/* secondary size is not greater than or equal to primary size */
640*8ba1bcfcSdduvall 	if (disk_capacity[0] > disk_capacity[1]) {
6417c478bd9Sstevel@tonic-gate 		*errcond = 1;
6427c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
6437c478bd9Sstevel@tonic-gate 	}
6447c478bd9Sstevel@tonic-gate 
645*8ba1bcfcSdduvall 	/* Secondary disk is big enough */
6467c478bd9Sstevel@tonic-gate 	*cap = disk_capacity[0];
6477c478bd9Sstevel@tonic-gate 	return (SUCCESS);
6487c478bd9Sstevel@tonic-gate }
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate static int
6517c478bd9Sstevel@tonic-gate do_config_change_state(cfga_cmd_t cmd, int d, int c)
6527c478bd9Sstevel@tonic-gate {
6537c478bd9Sstevel@tonic-gate 	cfga_err_t	cfga_err;
6547c478bd9Sstevel@tonic-gate 	char		*ap_id;
6557c478bd9Sstevel@tonic-gate 	int		rv = SUCCESS;
6567c478bd9Sstevel@tonic-gate 	int		count = 0;
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	ap_id = (char *)malloc(100);
6597c478bd9Sstevel@tonic-gate 	if (ap_id == NULL)
6607c478bd9Sstevel@tonic-gate 		return (FAILURE);
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	(void) snprintf(ap_id, 100, "c%d::dsk/c%dt%dd0", c, c, d);
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 	/*
6657c478bd9Sstevel@tonic-gate 	 * If the config_change_state() funcation fails, we want to
6667c478bd9Sstevel@tonic-gate 	 * retry.  If the retry fails, then we return failure to fail.
6677c478bd9Sstevel@tonic-gate 	 *
6687c478bd9Sstevel@tonic-gate 	 * If we fail:
6697c478bd9Sstevel@tonic-gate 	 *
6707c478bd9Sstevel@tonic-gate 	 *	If we were called from create, then we fail the raid
6717c478bd9Sstevel@tonic-gate 	 *	creation.
6727c478bd9Sstevel@tonic-gate 	 *
6737c478bd9Sstevel@tonic-gate 	 *	If we were called from delete, then the disk will not
6747c478bd9Sstevel@tonic-gate 	 *	be re-configured by raidctl.
6757c478bd9Sstevel@tonic-gate 	 */
6767c478bd9Sstevel@tonic-gate 	do {
6777c478bd9Sstevel@tonic-gate 		cfga_err = config_change_state(cmd, 1, &ap_id, NULL,
6787c478bd9Sstevel@tonic-gate 			NULL, NULL, NULL, 0);
6797c478bd9Sstevel@tonic-gate 		count++;
6807c478bd9Sstevel@tonic-gate 	} while (cfga_err != CFGA_OK && count < 2);
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	if (cfga_err != CFGA_OK)
6837c478bd9Sstevel@tonic-gate 		rv = FAILURE;
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	free(ap_id);
6867c478bd9Sstevel@tonic-gate 	return (rv);
6877c478bd9Sstevel@tonic-gate }
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate static int
690*8ba1bcfcSdduvall do_create(char **d)
6917c478bd9Sstevel@tonic-gate {
692*8ba1bcfcSdduvall 	raid_config_t	config;
6937c478bd9Sstevel@tonic-gate 	char		disk[N_DISKS][MAXPATHLEN] = {0};
6947c478bd9Sstevel@tonic-gate 	char		channel1[MAXPATHLEN];
6957c478bd9Sstevel@tonic-gate 	char		channel2[MAXPATHLEN];
6967c478bd9Sstevel@tonic-gate 	diskaddr_t	capacity;
697*8ba1bcfcSdduvall 	int		fd, fd2, size, errcond, disk_here = 1;
6987c478bd9Sstevel@tonic-gate 	int		c[N_DISKS];
6997c478bd9Sstevel@tonic-gate 	int		t[N_DISKS];
7007c478bd9Sstevel@tonic-gate 	char		*tmp;
701*8ba1bcfcSdduvall 	int		i;
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	(void) chdir(DEVDIR);
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	for (i = 0; i < N_DISKS; i++) {
7067c478bd9Sstevel@tonic-gate 		if ((sscanf(d[i], "c%dt%dd0", &c[i], &t[i])) != 2 ||
7077c478bd9Sstevel@tonic-gate 		    t[i] < 0) {
7087c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
7097c478bd9Sstevel@tonic-gate 				gettext("Invalid disk format.\n"));
7107c478bd9Sstevel@tonic-gate 			return (INVALID_ARG);
7117c478bd9Sstevel@tonic-gate 		}
712*8ba1bcfcSdduvall 		(void) snprintf(disk[i], sizeof (disk[i]), DEVDIR"/%ss2", d[i]);
713*8ba1bcfcSdduvall 	}
7147c478bd9Sstevel@tonic-gate 
715*8ba1bcfcSdduvall 	/* Must be on same controller */
716*8ba1bcfcSdduvall 	if (c[0] != c[1]) {
717*8ba1bcfcSdduvall 		(void) fprintf(stderr,
718*8ba1bcfcSdduvall 			gettext("Disks must be on the same controller.\n"));
7197c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
7207c478bd9Sstevel@tonic-gate 	}
7217c478bd9Sstevel@tonic-gate 
722*8ba1bcfcSdduvall 	/* primary disk target must be lower than secondary disk target */
723*8ba1bcfcSdduvall 	if (t[0] > t[1]) {
724*8ba1bcfcSdduvall 		(void) fprintf(stderr, gettext("Primary target ID "
725*8ba1bcfcSdduvall 				"must be less than secondary target ID.\n"));
726*8ba1bcfcSdduvall 		return (INVALID_ARG);
727*8ba1bcfcSdduvall 	}
728*8ba1bcfcSdduvall 
729*8ba1bcfcSdduvall 	/* disks must not be the same */
730*8ba1bcfcSdduvall 	if (t[0] == t[1]) {
731*8ba1bcfcSdduvall 		(void) fprintf(stderr, gettext("Disks must be different.\n"));
732*8ba1bcfcSdduvall 		return (INVALID_ARG);
733*8ba1bcfcSdduvall 	}
734*8ba1bcfcSdduvall 
735*8ba1bcfcSdduvall 	/* disks must be present */
736*8ba1bcfcSdduvall 	if (disk_there(c[0], t[0])) {
737*8ba1bcfcSdduvall 		(void) printf(gettext("Disk 'c%dt%dd0' is not present.\n"),
738*8ba1bcfcSdduvall 			c[0], t[0]);
739*8ba1bcfcSdduvall 		disk_here = 0;
740*8ba1bcfcSdduvall 	}
741*8ba1bcfcSdduvall 	if (disk_there(c[1], t[1])) {
742*8ba1bcfcSdduvall 		(void) printf(gettext("Disk 'c%dt%dd0' is not present.\n"),
743*8ba1bcfcSdduvall 			c[0], t[1]);
744*8ba1bcfcSdduvall 		disk_here = 0;
745*8ba1bcfcSdduvall 	}
746*8ba1bcfcSdduvall 
747*8ba1bcfcSdduvall 	if (!disk_here) {
7487c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Cannot create RAID volume.\n"));
7497c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
7507c478bd9Sstevel@tonic-gate 	}
7517c478bd9Sstevel@tonic-gate 
752*8ba1bcfcSdduvall 	/* secondary disk's size must be greater or equal to primary disk's */
7537c478bd9Sstevel@tonic-gate 	switch (disk_big_enough(d, &capacity, &errcond)) {
7547c478bd9Sstevel@tonic-gate 	case FAILURE:
7557c478bd9Sstevel@tonic-gate 		return (FAILURE);
7567c478bd9Sstevel@tonic-gate 	case INVALID_ARG:
7577c478bd9Sstevel@tonic-gate 		switch (errcond) {
7587c478bd9Sstevel@tonic-gate 		case 1:
7597c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Cannot create RAID volume when "
7607c478bd9Sstevel@tonic-gate 			"primary disk is larger than secondary disk.\n"));
7617c478bd9Sstevel@tonic-gate 		break;
7627c478bd9Sstevel@tonic-gate 		case 2:
7637c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Cannot create RAID volume when "
7647c478bd9Sstevel@tonic-gate 			"disk block sizes differ.\n"));
7657c478bd9Sstevel@tonic-gate 		}
7667c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
7677c478bd9Sstevel@tonic-gate 	}
7687c478bd9Sstevel@tonic-gate 
769*8ba1bcfcSdduvall 	/* secondary disk must not be mounted */
770*8ba1bcfcSdduvall 	if (disk_mounted(d[1])) {
771*8ba1bcfcSdduvall 		(void) fprintf(stderr, gettext("Cannot create RAID volume when "
772*8ba1bcfcSdduvall 				"secondary disk \"%s\" is mounted.\n"), d[1]);
773*8ba1bcfcSdduvall 		return (INVALID_ARG);
774*8ba1bcfcSdduvall 	}
7757c478bd9Sstevel@tonic-gate 
776*8ba1bcfcSdduvall 	/* Only one RAID can exist per controller */
7777c478bd9Sstevel@tonic-gate 	if (get_devctl(disk[0], channel1))
7787c478bd9Sstevel@tonic-gate 		return (FAILURE);
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 	fd = open(channel1, O_RDONLY);
7817c478bd9Sstevel@tonic-gate 	if (fd == -1) {
7827c478bd9Sstevel@tonic-gate 		perror(channel1);
7837c478bd9Sstevel@tonic-gate 		return (FAILURE);
7847c478bd9Sstevel@tonic-gate 	}
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	if (ioctl(fd, RAID_GETCONFIG, &config) < 0) {
7877c478bd9Sstevel@tonic-gate 		raidctl_error("RAID_GETCONFIG");
788*8ba1bcfcSdduvall 		goto fail1;
7897c478bd9Sstevel@tonic-gate 	}
7907c478bd9Sstevel@tonic-gate 
791*8ba1bcfcSdduvall 	if (config.ndisks != 0) {
792*8ba1bcfcSdduvall 		(void) printf(gettext("RAID Volume already exists on this "
793*8ba1bcfcSdduvall 			"controller 'c%dt%dd0'\n"), c[0], config.targetid);
794*8ba1bcfcSdduvall 		goto fail1;
79505411564Sjesseb 	}
79605411564Sjesseb 
79705411564Sjesseb 	/*
7987c478bd9Sstevel@tonic-gate 	 * Make sure there isn't a raid created on this controller's
799*8ba1bcfcSdduvall 	 * other channel
8007c478bd9Sstevel@tonic-gate 	 */
8017c478bd9Sstevel@tonic-gate 	(void) strlcpy(channel2, channel1, sizeof (channel2));
8027c478bd9Sstevel@tonic-gate 	tmp = strrchr(channel2, ':');
8037c478bd9Sstevel@tonic-gate 	tmp[0] = 0;
8047c478bd9Sstevel@tonic-gate 	size = strlen(channel2);
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	/*
8077c478bd9Sstevel@tonic-gate 	 * Format the channel string for the other channel so we can
808*8ba1bcfcSdduvall 	 * see if a raid exists on it.  In this case if we are being asked
809*8ba1bcfcSdduvall 	 * to create a raid on channel 2 (indicated by the 1,1 at the end
810*8ba1bcfcSdduvall 	 * of the string) we want to check channel 1) otherwise we will
811*8ba1bcfcSdduvall 	 * check channel 2.
8127c478bd9Sstevel@tonic-gate 	 */
8137c478bd9Sstevel@tonic-gate 	if (channel2[size - 2] == ',') {
8147c478bd9Sstevel@tonic-gate 		channel2[size - 1] = 0;
8157c478bd9Sstevel@tonic-gate 		channel2[size - 2] = 0;
816*8ba1bcfcSdduvall 		(void) snprintf(channel2, sizeof (channel2), "%s:devctl",
817*8ba1bcfcSdduvall 			channel2);
8187c478bd9Sstevel@tonic-gate 	} else {
819*8ba1bcfcSdduvall 		(void) snprintf(channel2, sizeof (channel2), "%s,1:devctl",
820*8ba1bcfcSdduvall 			channel2);
8217c478bd9Sstevel@tonic-gate 	}
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 	fd2 = open(channel2, O_RDONLY);
8247c478bd9Sstevel@tonic-gate 	if (fd2 == -1) {
8257c478bd9Sstevel@tonic-gate 		if (errno == ENOENT)
8267c478bd9Sstevel@tonic-gate 			goto no_secondary_channel;
8277c478bd9Sstevel@tonic-gate 		perror(channel2);
828*8ba1bcfcSdduvall 		goto fail1;
8297c478bd9Sstevel@tonic-gate 	}
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	if (ioctl(fd2, RAID_GETCONFIG, &config) < 0) {
832*8ba1bcfcSdduvall 		goto fail2;
8337c478bd9Sstevel@tonic-gate 	}
8347c478bd9Sstevel@tonic-gate 
835*8ba1bcfcSdduvall 	if (config.ndisks != 0) {
8367c478bd9Sstevel@tonic-gate 		int	cx;
8377c478bd9Sstevel@tonic-gate 		cx = get_controller(channel2);
838*8ba1bcfcSdduvall 		(void) printf(gettext("RAID Volume already exists on this "
839*8ba1bcfcSdduvall 			"controller 'c%dt%dd0'\n"), cx, config.targetid);
840*8ba1bcfcSdduvall 		goto fail2;
8417c478bd9Sstevel@tonic-gate 	}
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate no_secondary_channel:
8447c478bd9Sstevel@tonic-gate 
845*8ba1bcfcSdduvall 	/* No other RAID volumes exist, so we may continue */
846*8ba1bcfcSdduvall 	config.raid_capacity = capacity;
847*8ba1bcfcSdduvall 	config.raid_level = 1;	/* RAID 1: Mirror */
848*8ba1bcfcSdduvall 	config.targetid = t[0];	/* Assume identity of first disk */
849*8ba1bcfcSdduvall 	config.disk[0] = t[0];	/* Primary Disk */
850*8ba1bcfcSdduvall 	config.disk[1] = t[1];	/* Secondary Disk */
8517c478bd9Sstevel@tonic-gate 
852*8ba1bcfcSdduvall 	/* Make secondary disk inaccessible to the system */
8537c478bd9Sstevel@tonic-gate 	if (do_config_change_state(CFGA_CMD_UNCONFIGURE,
854*8ba1bcfcSdduvall 		config.disk[1], c[0])) {
8557c478bd9Sstevel@tonic-gate 		perror("config_change_state");
856*8ba1bcfcSdduvall 		goto fail2;
8577c478bd9Sstevel@tonic-gate 	}
8587c478bd9Sstevel@tonic-gate 
859*8ba1bcfcSdduvall 	if (ioctl(fd, RAID_CREATE, &config)) {
8607c478bd9Sstevel@tonic-gate 		(void) do_config_change_state(CFGA_CMD_CONFIGURE,
861*8ba1bcfcSdduvall 			config.disk[1], c[0]);
8627c478bd9Sstevel@tonic-gate 		raidctl_error("RAID_CREATE");
863*8ba1bcfcSdduvall 		goto fail2;
8647c478bd9Sstevel@tonic-gate 	}
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 	(void) printf(gettext("Volume 'c%dt%dd0' created\n"), c[0], t[0]);
8677c478bd9Sstevel@tonic-gate 	(void) close(fd);
8687c478bd9Sstevel@tonic-gate 	(void) close(fd2);
8697c478bd9Sstevel@tonic-gate 	return (SUCCESS);
8707c478bd9Sstevel@tonic-gate 
871*8ba1bcfcSdduvall fail2:
87205411564Sjesseb 	(void) close(fd2);
873*8ba1bcfcSdduvall fail1:
874*8ba1bcfcSdduvall 	(void) close(fd);
8757c478bd9Sstevel@tonic-gate 	return (FAILURE);
8767c478bd9Sstevel@tonic-gate }
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate static int
8797c478bd9Sstevel@tonic-gate do_delete(char *d)
8807c478bd9Sstevel@tonic-gate {
881*8ba1bcfcSdduvall 	raid_config_t	config;
8827c478bd9Sstevel@tonic-gate 	char		disk1[MAXPATHLEN];
8837c478bd9Sstevel@tonic-gate 	char		buf[MAXPATHLEN];
8847c478bd9Sstevel@tonic-gate 	int		fd;
8857c478bd9Sstevel@tonic-gate 	int		target;
8867c478bd9Sstevel@tonic-gate 	int		ctrl;
8877c478bd9Sstevel@tonic-gate 	uint8_t		t;
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 	(void) chdir(DEVDIR);
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 	if ((sscanf(d, "c%dt%dd0", &ctrl, &target)) != 2) {
8927c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Invalid disk format.\n"));
8937c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
8947c478bd9Sstevel@tonic-gate 	}
8957c478bd9Sstevel@tonic-gate 	t = (uint8_t)target;
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 	(void) snprintf(disk1, sizeof (disk1), DEVDIR"/%ss2", d);
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	if (get_devctl(disk1, buf) != 0) {
9007c478bd9Sstevel@tonic-gate 		return (FAILURE);
9017c478bd9Sstevel@tonic-gate 	}
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	fd = open(buf, O_RDONLY);
9047c478bd9Sstevel@tonic-gate 	if (fd == -1) {
9057c478bd9Sstevel@tonic-gate 		perror(buf);
9067c478bd9Sstevel@tonic-gate 		return (FAILURE);
9077c478bd9Sstevel@tonic-gate 	}
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 	if (ioctl(fd, RAID_GETCONFIG, &config)) {
9107c478bd9Sstevel@tonic-gate 		raidctl_error("RAID_GETCONFIG");
9117c478bd9Sstevel@tonic-gate 		goto fail;
9127c478bd9Sstevel@tonic-gate 	}
9137c478bd9Sstevel@tonic-gate 
914*8ba1bcfcSdduvall 	if (config.ndisks == 0) {
915*8ba1bcfcSdduvall 		(void) fprintf(stderr, gettext("No RAID Volume exists on "
9167c478bd9Sstevel@tonic-gate 			"controller '%d'\n"), ctrl);
9177c478bd9Sstevel@tonic-gate 		goto fail;
9187c478bd9Sstevel@tonic-gate 	}
9197c478bd9Sstevel@tonic-gate 
920*8ba1bcfcSdduvall 	if (config.targetid != t) {
9217c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
9227c478bd9Sstevel@tonic-gate 			gettext("RAID volume 'c%dt%dd0' does not exist\n"),
9237c478bd9Sstevel@tonic-gate 			ctrl, t);
9247c478bd9Sstevel@tonic-gate 		goto fail;
9257c478bd9Sstevel@tonic-gate 	}
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	if (ioctl(fd, RAID_DELETE, &t)) {
9287c478bd9Sstevel@tonic-gate 		perror("RAID_DELETE");
9297c478bd9Sstevel@tonic-gate 		goto fail;
9307c478bd9Sstevel@tonic-gate 	}
9317c478bd9Sstevel@tonic-gate 
932*8ba1bcfcSdduvall 	/*
933*8ba1bcfcSdduvall 	 * Make secondary disk accessible to the system.
934*8ba1bcfcSdduvall 	 * Ignore return value from do_config_change_state.
935*8ba1bcfcSdduvall 	 */
936*8ba1bcfcSdduvall 	(void) do_config_change_state(CFGA_CMD_CONFIGURE, config.disk[1], ctrl);
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("Volume 'c%dt%dd0' deleted.\n"),
9397c478bd9Sstevel@tonic-gate 		ctrl, target);
9407c478bd9Sstevel@tonic-gate 	(void) close(fd);
9417c478bd9Sstevel@tonic-gate 	return (SUCCESS);
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate fail:
9447c478bd9Sstevel@tonic-gate 	(void) close(fd);
9457c478bd9Sstevel@tonic-gate 	return (FAILURE);
9467c478bd9Sstevel@tonic-gate }
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate static int
9497c478bd9Sstevel@tonic-gate getfcodever(uint8_t *rombuf, uint32_t nbytes, char **fcodeversion)
9507c478bd9Sstevel@tonic-gate {
9517c478bd9Sstevel@tonic-gate 	int x, y, size;
9527c478bd9Sstevel@tonic-gate 	int found_1 = 0, found_2 = 0;
9537c478bd9Sstevel@tonic-gate 	int image_length = 0;
9547c478bd9Sstevel@tonic-gate 	int no_of_images = 0;
9557c478bd9Sstevel@tonic-gate 	uint8_t *rombuf_1 = NULL;
9567c478bd9Sstevel@tonic-gate 	uint16_t image_units = 0;
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 	/*
9597c478bd9Sstevel@tonic-gate 	 * Single Image - Open firmware image
9607c478bd9Sstevel@tonic-gate 	 */
9617c478bd9Sstevel@tonic-gate 	if (rombuf[gw(&rombuf[PCIR_OFF]) + PCIR_CODETYPE] == 1) {
9627c478bd9Sstevel@tonic-gate 		rombuf_1 = rombuf + gw(rombuf + PCIR_OFF) + PCI_PDS_INDICATOR;
9637c478bd9Sstevel@tonic-gate 		no_of_images = 1;
9647c478bd9Sstevel@tonic-gate 		goto process_image;
9657c478bd9Sstevel@tonic-gate 	}
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate 	/*
9687c478bd9Sstevel@tonic-gate 	 * Combined Image - First Image - x86/PC-AT Bios image
9697c478bd9Sstevel@tonic-gate 	 */
9707c478bd9Sstevel@tonic-gate 	if (rombuf[gw(&rombuf[PCIR_OFF]) + PCIR_CODETYPE] != 0) {
9717c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("This is neither open image"
9727c478bd9Sstevel@tonic-gate 			    " nor Bios/Fcode combined image\n"));
9737c478bd9Sstevel@tonic-gate 		return (1);
9747c478bd9Sstevel@tonic-gate 	}
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 	/*
9777c478bd9Sstevel@tonic-gate 	 * Seek to 2nd Image
9787c478bd9Sstevel@tonic-gate 	 */
9797c478bd9Sstevel@tonic-gate 	rombuf_1 = rombuf + gw(rombuf + PCI_ROM_PCI_DATA_STRUCT_PTR);
9807c478bd9Sstevel@tonic-gate 	image_units = gw(rombuf_1 + PCI_PDS_IMAGE_LENGTH);
9817c478bd9Sstevel@tonic-gate 	image_length = image_units * PCI_IMAGE_UNIT_SIZE;
9827c478bd9Sstevel@tonic-gate 	rombuf_1 += image_length;
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	/*
9857c478bd9Sstevel@tonic-gate 	 * Combined Image - Second Image - Open Firmware image
9867c478bd9Sstevel@tonic-gate 	 */
9877c478bd9Sstevel@tonic-gate 	if (rombuf_1[PCI_PDS_CODE_TYPE] != 1) {
9887c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("This is neither open image"
9897c478bd9Sstevel@tonic-gate 			    " nor Bios/Fcode combined image\n"));
9907c478bd9Sstevel@tonic-gate 		return (1);
9917c478bd9Sstevel@tonic-gate 	}
9927c478bd9Sstevel@tonic-gate 	rombuf_1 += PCI_PDS_INDICATOR;
9937c478bd9Sstevel@tonic-gate 	no_of_images = 2;
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate process_image:
9967c478bd9Sstevel@tonic-gate 	/*
9977c478bd9Sstevel@tonic-gate 	 * This should be the last image
9987c478bd9Sstevel@tonic-gate 	 */
9997c478bd9Sstevel@tonic-gate 	if (*rombuf_1 != LAST_IMAGE) {
10007c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("This is not a valid "
10017c478bd9Sstevel@tonic-gate 		    "Bios/Fcode image file\n"));
10027c478bd9Sstevel@tonic-gate 		return (1);
10037c478bd9Sstevel@tonic-gate 	}
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate 	/*
10067c478bd9Sstevel@tonic-gate 	 * Scan through the bois/fcode file to get the fcode version
10077c478bd9Sstevel@tonic-gate 	 * 0x12 and 0x7 indicate the start of the fcode version string
10087c478bd9Sstevel@tonic-gate 	 */
10097c478bd9Sstevel@tonic-gate 	for (x = 0; x < (nbytes - 8); x++) {
10107c478bd9Sstevel@tonic-gate 		if ((rombuf[x] == FCODE_VERS_KEY1) &&
10117c478bd9Sstevel@tonic-gate 		    (rombuf[x+1] == FCODE_VERS_KEY2) &&
10127c478bd9Sstevel@tonic-gate 		    (rombuf[x+2] == 'v') && (rombuf[x+3] == 'e') &&
10137c478bd9Sstevel@tonic-gate 		    (rombuf[x+4] == 'r') && (rombuf[x+5] == 's') &&
10147c478bd9Sstevel@tonic-gate 		    (rombuf[x+6] == 'i') && (rombuf[x+7] == 'o') &&
10157c478bd9Sstevel@tonic-gate 		    (rombuf[x+8] == 'n')) {
10167c478bd9Sstevel@tonic-gate 			found_1 = 1;
10177c478bd9Sstevel@tonic-gate 			break;
10187c478bd9Sstevel@tonic-gate 		}
10197c478bd9Sstevel@tonic-gate 	}
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 	/*
10227c478bd9Sstevel@tonic-gate 	 * Store the version string if we have found the beginning of it
10237c478bd9Sstevel@tonic-gate 	 */
10247c478bd9Sstevel@tonic-gate 	if (found_1) {
10257c478bd9Sstevel@tonic-gate 		while (x > 0) {
10267c478bd9Sstevel@tonic-gate 			if (rombuf[--x] == FCODE_VERS_KEY1) {
10277c478bd9Sstevel@tonic-gate 				if (rombuf[x-1] != FCODE_VERS_KEY1) {
10287c478bd9Sstevel@tonic-gate 					x++;
10297c478bd9Sstevel@tonic-gate 				}
10307c478bd9Sstevel@tonic-gate 				break;
10317c478bd9Sstevel@tonic-gate 			}
10327c478bd9Sstevel@tonic-gate 		}
10337c478bd9Sstevel@tonic-gate 		if (x > 0) {
10347c478bd9Sstevel@tonic-gate 			*fcodeversion = (char *)malloc(rombuf[x] + 1);
10357c478bd9Sstevel@tonic-gate 			for (y = 0; y < rombuf[x]; y++) {
10367c478bd9Sstevel@tonic-gate 				(*fcodeversion)[y] = rombuf[x+y+1];
10377c478bd9Sstevel@tonic-gate 			}
10387c478bd9Sstevel@tonic-gate 			(*fcodeversion)[y] = '\0';
10397c478bd9Sstevel@tonic-gate 		} else {
10407c478bd9Sstevel@tonic-gate 			found_1 = 0;
10417c478bd9Sstevel@tonic-gate 		}
10427c478bd9Sstevel@tonic-gate 	}
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate 	/*
10457c478bd9Sstevel@tonic-gate 	 * Scan through the bois/fcode file to get the Bios version
10467c478bd9Sstevel@tonic-gate 	 * "@(#)" string indicates the start of the Bios version string
10477c478bd9Sstevel@tonic-gate 	 * Append this version string, after already existing fcode version.
10487c478bd9Sstevel@tonic-gate 	 */
10497c478bd9Sstevel@tonic-gate 	if (no_of_images == 2) {
10507c478bd9Sstevel@tonic-gate 		for (x = 0; x < (nbytes - 4); x++) {
10517c478bd9Sstevel@tonic-gate 			if ((rombuf[x] == '@') && (rombuf[x+1] == '(') &&
10527c478bd9Sstevel@tonic-gate 			    (rombuf[x+2] == '#') && (rombuf[x+3] == ')')) {
10537c478bd9Sstevel@tonic-gate 				found_2 = 1;
10547c478bd9Sstevel@tonic-gate 				break;
10557c478bd9Sstevel@tonic-gate 			}
10567c478bd9Sstevel@tonic-gate 		}
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate 		if (found_2) {
10597c478bd9Sstevel@tonic-gate 			x += 4;
10607c478bd9Sstevel@tonic-gate 			(*fcodeversion)[y] = '\n';
10617c478bd9Sstevel@tonic-gate 			size = y + strlen((char *)(rombuf + x)) +
10627c478bd9Sstevel@tonic-gate 			    strlen(BIOS_STR) + 2;
10637c478bd9Sstevel@tonic-gate 			*fcodeversion = (char *)realloc((*fcodeversion), size);
10647c478bd9Sstevel@tonic-gate 			y++;
10657c478bd9Sstevel@tonic-gate 			(*fcodeversion)[y] = '\0';
10667c478bd9Sstevel@tonic-gate 			(void) strlcat(*fcodeversion, BIOS_STR, size);
10677c478bd9Sstevel@tonic-gate 			(void) strlcat(*fcodeversion, (char *)(rombuf + x),
10687c478bd9Sstevel@tonic-gate 			    size);
10697c478bd9Sstevel@tonic-gate 		}
10707c478bd9Sstevel@tonic-gate 	}
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 	return ((found_1 || found_2) ? 0 : 1);
10737c478bd9Sstevel@tonic-gate }
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate static void
10767c478bd9Sstevel@tonic-gate getfwver(uint8_t *rombuf, char *fwversion)
10777c478bd9Sstevel@tonic-gate {
10787c478bd9Sstevel@tonic-gate 	(void) snprintf(fwversion, 8, "%d.%.2d.%.2d.%.2d",
10797c478bd9Sstevel@tonic-gate 		rombuf[FW_ROM_OFFSET_VERSION + 3],
10807c478bd9Sstevel@tonic-gate 		rombuf[FW_ROM_OFFSET_VERSION + 2],
10817c478bd9Sstevel@tonic-gate 		rombuf[FW_ROM_OFFSET_VERSION + 1],
10827c478bd9Sstevel@tonic-gate 		rombuf[FW_ROM_OFFSET_VERSION + 0]);
10837c478bd9Sstevel@tonic-gate }
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate static int
10867c478bd9Sstevel@tonic-gate checkfile(uint8_t *rombuf, uint32_t nbytes, uint32_t chksum, int *imagetype)
10877c478bd9Sstevel@tonic-gate {
10887c478bd9Sstevel@tonic-gate 	char *imageversion = NULL;
10897c478bd9Sstevel@tonic-gate 	char *fwversion;
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 	fwversion = (char *)malloc(8);
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate 	if (gw(&rombuf[0]) == PCIROM_SIG) {
10947c478bd9Sstevel@tonic-gate 		/* imageversion is malloc(2)'ed in getfcodever() */
10957c478bd9Sstevel@tonic-gate 		if (getfcodever(rombuf, nbytes, &imageversion) == 0) {
10967c478bd9Sstevel@tonic-gate 			*imagetype = FCODE_IMAGE;
10977c478bd9Sstevel@tonic-gate 		} else {
10987c478bd9Sstevel@tonic-gate 			*imagetype = UNKNOWN_IMAGE;
10997c478bd9Sstevel@tonic-gate 		}
11007c478bd9Sstevel@tonic-gate 		if (*imagetype != UNKNOWN_IMAGE) {
11017c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Image file contains:\n%s\n"),
11027c478bd9Sstevel@tonic-gate 			    imageversion);
11037c478bd9Sstevel@tonic-gate 			free(imageversion);
11047c478bd9Sstevel@tonic-gate 		} else {
11057c478bd9Sstevel@tonic-gate 			if (imageversion != NULL) {
11067c478bd9Sstevel@tonic-gate 				free(imageversion);
11077c478bd9Sstevel@tonic-gate 			}
11087c478bd9Sstevel@tonic-gate 			return (-1);
11097c478bd9Sstevel@tonic-gate 		}
11107c478bd9Sstevel@tonic-gate 	} else if (gw(&rombuf[3]) == FW_ROM_ID) {
11117c478bd9Sstevel@tonic-gate 			if (chksum != 0) {
11127c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
11137c478bd9Sstevel@tonic-gate 					gettext("The ROM checksum appears bad "
11147c478bd9Sstevel@tonic-gate 					"(%d)\n"), chksum);
11157c478bd9Sstevel@tonic-gate 				return (-1);
11167c478bd9Sstevel@tonic-gate 			}
11177c478bd9Sstevel@tonic-gate 			getfwver(rombuf, fwversion);
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 			if ((gw(&rombuf[FW_ROM_OFFSET_CHIP_TYPE]) &
11207c478bd9Sstevel@tonic-gate 				MPI_FW_HEADER_PID_PROD_MASK) ==
11217c478bd9Sstevel@tonic-gate 				MPI_FW_HEADER_PID_PROD_IM_SCSI) {
11227c478bd9Sstevel@tonic-gate 				(void) printf(gettext("ROM image contains "
11237c478bd9Sstevel@tonic-gate 					"MPT firmware version %s "
11247c478bd9Sstevel@tonic-gate 					"(w/Integrated Mirroring)\n"),
11257c478bd9Sstevel@tonic-gate 						fwversion);
11267c478bd9Sstevel@tonic-gate 			} else {
11277c478bd9Sstevel@tonic-gate 				(void) printf(gettext("ROM image contains "
11287c478bd9Sstevel@tonic-gate 					"MPT firmware ""version %s\n"),
11297c478bd9Sstevel@tonic-gate 						fwversion);
11307c478bd9Sstevel@tonic-gate 			}
11317c478bd9Sstevel@tonic-gate 			free(fwversion);
11327c478bd9Sstevel@tonic-gate 	} else {
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate #ifdef	DEBUG
11357c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "Not valid FCODE image %x\n", gw(&rombuf[0]));
11367c478bd9Sstevel@tonic-gate #else
11377c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("Not valid FCODE image\n"));
11387c478bd9Sstevel@tonic-gate #endif
11397c478bd9Sstevel@tonic-gate 		return (-1);
11407c478bd9Sstevel@tonic-gate 	}
11417c478bd9Sstevel@tonic-gate 	return (0);
11427c478bd9Sstevel@tonic-gate }
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate static int
11457c478bd9Sstevel@tonic-gate updateflash(uint8_t *rombuf, uint32_t nbytes, char *devctl)
11467c478bd9Sstevel@tonic-gate {
11477c478bd9Sstevel@tonic-gate 	int fd = 0;
11487c478bd9Sstevel@tonic-gate 	update_flash_t flashdata;
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 	fd = open(devctl, O_RDONLY);
11517c478bd9Sstevel@tonic-gate 	if (fd == -1) {
11527c478bd9Sstevel@tonic-gate 		perror(devctl);
11537c478bd9Sstevel@tonic-gate 		return (-1);
11547c478bd9Sstevel@tonic-gate 	}
11557c478bd9Sstevel@tonic-gate 	(void) memset(&flashdata, 0, sizeof (flashdata));
11567c478bd9Sstevel@tonic-gate 	flashdata.ptrbuffer = (caddr_t)rombuf;
11577c478bd9Sstevel@tonic-gate 	flashdata.size = nbytes;
11587c478bd9Sstevel@tonic-gate 	if ((rombuf[0] == 0x55) && (rombuf[1] == 0xaa)) {
11597c478bd9Sstevel@tonic-gate 		flashdata.type = FW_TYPE_FCODE;
11607c478bd9Sstevel@tonic-gate 	} else {
11617c478bd9Sstevel@tonic-gate 		flashdata.type = FW_TYPE_UCODE;
11627c478bd9Sstevel@tonic-gate 	}
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 	if (ioctl(fd, RAID_UPDATEFW, &flashdata)) {
11657c478bd9Sstevel@tonic-gate 		raidctl_error("RAID_UPDATEFW");
11667c478bd9Sstevel@tonic-gate 		(void) close(fd);
11677c478bd9Sstevel@tonic-gate 		return (-1);
11687c478bd9Sstevel@tonic-gate 	}
11697c478bd9Sstevel@tonic-gate 
11707c478bd9Sstevel@tonic-gate 	(void) close(fd);
11717c478bd9Sstevel@tonic-gate 	return (0);
11727c478bd9Sstevel@tonic-gate }
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate static int
11757c478bd9Sstevel@tonic-gate readfile(char *filespec, uint8_t **rombuf, uint32_t *nbytes, uint32_t *chksum)
11767c478bd9Sstevel@tonic-gate {
11777c478bd9Sstevel@tonic-gate 	struct stat	statbuf;
11787c478bd9Sstevel@tonic-gate 	uint32_t	count;
11797c478bd9Sstevel@tonic-gate 	uint32_t	checksum = 0;
11807c478bd9Sstevel@tonic-gate 	int		fd, i;
11817c478bd9Sstevel@tonic-gate 	uint8_t		*filebuf;
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 	if ((fd = open((const char *)filespec, O_RDONLY | O_NDELAY)) == -1) {
11857c478bd9Sstevel@tonic-gate 		perror(filespec);
11867c478bd9Sstevel@tonic-gate 		return (-1);
11877c478bd9Sstevel@tonic-gate 	}
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 	if (fstat(fd, &statbuf) != 0) {
11907c478bd9Sstevel@tonic-gate 		perror("fstat");
11917c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
11927c478bd9Sstevel@tonic-gate 			gettext("Error getting stats on file\n"));
11937c478bd9Sstevel@tonic-gate 		(void) close(fd);
11947c478bd9Sstevel@tonic-gate 		return (-1);
11957c478bd9Sstevel@tonic-gate 	}
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate #ifdef	DEBUG
11987c478bd9Sstevel@tonic-gate 	(void) printf("Filesize = %ld\n", statbuf.st_size);
11997c478bd9Sstevel@tonic-gate #endif
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 	filebuf = (uint8_t *)realloc(*rombuf, statbuf.st_size + *nbytes);
12027c478bd9Sstevel@tonic-gate 
12037c478bd9Sstevel@tonic-gate 	count = read(fd, filebuf + *nbytes, statbuf.st_size);
12047c478bd9Sstevel@tonic-gate 	(void) close(fd);
12057c478bd9Sstevel@tonic-gate 	if (count != statbuf.st_size) {
12067c478bd9Sstevel@tonic-gate 		perror("size check");
12077c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("File is corrupt\n"));
12087c478bd9Sstevel@tonic-gate 		return (-1);
12097c478bd9Sstevel@tonic-gate 	}
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate 	for (i = 0; i < *nbytes; i++)
12127c478bd9Sstevel@tonic-gate 		checksum += filebuf[i] << (8 * (i & 3));
12137c478bd9Sstevel@tonic-gate 
12147c478bd9Sstevel@tonic-gate 	*rombuf = filebuf;
12157c478bd9Sstevel@tonic-gate 	*nbytes = *nbytes + count;
12167c478bd9Sstevel@tonic-gate 	*chksum = checksum;
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 	return (0);
12197c478bd9Sstevel@tonic-gate }
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate static int
12227c478bd9Sstevel@tonic-gate yes(int c)
12237c478bd9Sstevel@tonic-gate {
12247c478bd9Sstevel@tonic-gate 	int	i, b;
12257c478bd9Sstevel@tonic-gate 	char    ans[SCHAR_MAX + 1];
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	for (i = 0; ; i++) {
12287c478bd9Sstevel@tonic-gate 		b = getchar();
12297c478bd9Sstevel@tonic-gate 		if (b == '\n' || b == '\0' || b == EOF) {
12307c478bd9Sstevel@tonic-gate 			ans[i] = 0;
12317c478bd9Sstevel@tonic-gate 			break;
12327c478bd9Sstevel@tonic-gate 		}
12337c478bd9Sstevel@tonic-gate 		if (i < SCHAR_MAX)
12347c478bd9Sstevel@tonic-gate 			ans[i] = b;
12357c478bd9Sstevel@tonic-gate 	}
12367c478bd9Sstevel@tonic-gate 	if (i >= SCHAR_MAX) {
12377c478bd9Sstevel@tonic-gate 		i = SCHAR_MAX;
12387c478bd9Sstevel@tonic-gate 		ans[SCHAR_MAX] = 0;
12397c478bd9Sstevel@tonic-gate 	}
12407c478bd9Sstevel@tonic-gate 	if ((i != 0) && ((strncmp(yeschr, ans, i)) == 0)) {
12417c478bd9Sstevel@tonic-gate 		return (1);
12427c478bd9Sstevel@tonic-gate 	} else {
12437c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("User response is \"%s\", "
12447c478bd9Sstevel@tonic-gate 		    "Controller %d not flashed.\n\n"), ans, c);
12457c478bd9Sstevel@tonic-gate 		return (0);
12467c478bd9Sstevel@tonic-gate 	}
12477c478bd9Sstevel@tonic-gate }
12487c478bd9Sstevel@tonic-gate 
12497c478bd9Sstevel@tonic-gate static int
12507c478bd9Sstevel@tonic-gate do_flash(int c, char *fpath, int force)
12517c478bd9Sstevel@tonic-gate {
12527c478bd9Sstevel@tonic-gate 	char		devctl[MAXPATHLEN] = {0};
12537c478bd9Sstevel@tonic-gate 	char		buf[MAXPATHLEN] = {0};
12547c478bd9Sstevel@tonic-gate 	int		rv = 0;
12557c478bd9Sstevel@tonic-gate 	int		imagetype;
12567c478bd9Sstevel@tonic-gate 	uint32_t	nbytes = 0;
12577c478bd9Sstevel@tonic-gate 	uint32_t	chksum;
12587c478bd9Sstevel@tonic-gate 	uint8_t		*rombuf = NULL;
12597c478bd9Sstevel@tonic-gate 	char		cwd[MAXPATHLEN];
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate 	/*
12627c478bd9Sstevel@tonic-gate 	 * Read fw file
12637c478bd9Sstevel@tonic-gate 	 */
12647c478bd9Sstevel@tonic-gate 	rv = readfile(fpath, &rombuf, &nbytes, &chksum);
12657c478bd9Sstevel@tonic-gate 	if (rv != 0) {
12667c478bd9Sstevel@tonic-gate 		return (FAILURE);
12677c478bd9Sstevel@tonic-gate 	}
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate 	(void) getcwd(cwd, sizeof (cwd));
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate 	(void) chdir(DEVDIR);
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 	/* Get link from "/dev/cfg" */
12747c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "/dev/cfg/c%d", c);
12757c478bd9Sstevel@tonic-gate 	if (get_link_path(buf, devctl) != 0) {
12767c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
12777c478bd9Sstevel@tonic-gate 			gettext("Invalid controller '%d'\n"), c);
12787c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
12797c478bd9Sstevel@tonic-gate 	}
12807c478bd9Sstevel@tonic-gate 
12817c478bd9Sstevel@tonic-gate 	/* Check File */
12827c478bd9Sstevel@tonic-gate 	rv = checkfile(rombuf, nbytes, chksum, &imagetype);
12837c478bd9Sstevel@tonic-gate 	if (rv != 0) {
12847c478bd9Sstevel@tonic-gate 		return (FAILURE);
12857c478bd9Sstevel@tonic-gate 	}
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 	/* Confirm */
12887c478bd9Sstevel@tonic-gate 	if (!force) {
12897c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Update flash image on "
12907c478bd9Sstevel@tonic-gate 			"controller %d (%s/%s)? "), c, yeschr, nochr);
12917c478bd9Sstevel@tonic-gate 		if (!yes(c)) {
12927c478bd9Sstevel@tonic-gate 			return (SUCCESS);
12937c478bd9Sstevel@tonic-gate 		}
12947c478bd9Sstevel@tonic-gate 	}
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate 	/* Do Flash */
12977c478bd9Sstevel@tonic-gate 	if (updateflash(rombuf, nbytes, devctl)) {
12987c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Flash not updated on "
12997c478bd9Sstevel@tonic-gate 		    "Controller %d.\n\n"), c);
13007c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
13017c478bd9Sstevel@tonic-gate 	}
13027c478bd9Sstevel@tonic-gate 	(void) printf(gettext("Flash updated successfully.\n\n"));
13037c478bd9Sstevel@tonic-gate 	return (SUCCESS);
13047c478bd9Sstevel@tonic-gate }
13057c478bd9Sstevel@tonic-gate 
13067c478bd9Sstevel@tonic-gate static int
13077c478bd9Sstevel@tonic-gate fully_numeric(char *str)
13087c478bd9Sstevel@tonic-gate {
13097c478bd9Sstevel@tonic-gate 	int	size = strlen(str);
13107c478bd9Sstevel@tonic-gate 	int	i;
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate 	for (i = 0; i < size; i++) {
13137c478bd9Sstevel@tonic-gate 		if (i == 0 && str[i] == '-' && size != 1)
13147c478bd9Sstevel@tonic-gate 			continue;
13157c478bd9Sstevel@tonic-gate 		if (!isdigit(str[i]))
13167c478bd9Sstevel@tonic-gate 			return (0);
13177c478bd9Sstevel@tonic-gate 	}
13187c478bd9Sstevel@tonic-gate 	return (1);
13197c478bd9Sstevel@tonic-gate }
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate /*
13227c478bd9Sstevel@tonic-gate  * Useful parsing macros
13237c478bd9Sstevel@tonic-gate  */
13247c478bd9Sstevel@tonic-gate #define	must_be(s, c)		if (*s++ != c) return (0)
13257c478bd9Sstevel@tonic-gate #define	skip_digits(s)		while (isdigit(*s)) s++
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate /*
13287c478bd9Sstevel@tonic-gate  * Return true if a name is in the internal canonical form
13297c478bd9Sstevel@tonic-gate  */
13307c478bd9Sstevel@tonic-gate static int
13317c478bd9Sstevel@tonic-gate canonical_name(char *name)
13327c478bd9Sstevel@tonic-gate {
13337c478bd9Sstevel@tonic-gate 	must_be(name, 'c');
13347c478bd9Sstevel@tonic-gate 	skip_digits(name);
13357c478bd9Sstevel@tonic-gate 	if (*name == 't') {
13367c478bd9Sstevel@tonic-gate 		name++;
13377c478bd9Sstevel@tonic-gate 		skip_digits(name);
13387c478bd9Sstevel@tonic-gate 	}
13397c478bd9Sstevel@tonic-gate 	must_be(name, 'd');
13407c478bd9Sstevel@tonic-gate 	skip_digits(name);
13417c478bd9Sstevel@tonic-gate 	return (*name == 0);
13427c478bd9Sstevel@tonic-gate }
13437c478bd9Sstevel@tonic-gate 
13447c478bd9Sstevel@tonic-gate int
13457c478bd9Sstevel@tonic-gate main(int argc, char **argv)
13467c478bd9Sstevel@tonic-gate {
13477c478bd9Sstevel@tonic-gate 	int	rv = SUCCESS;
13487c478bd9Sstevel@tonic-gate 	int	i, c;
13497c478bd9Sstevel@tonic-gate 	int	findex = DO_HW_RAID_INFO;
13507c478bd9Sstevel@tonic-gate 	int	controller;
1351*8ba1bcfcSdduvall 	char	*disks[N_DISKS];
13527c478bd9Sstevel@tonic-gate 	char	*darg;
13537c478bd9Sstevel@tonic-gate 	char	*farg;
13547c478bd9Sstevel@tonic-gate 	char	*progname;
13557c478bd9Sstevel@tonic-gate 
13567c478bd9Sstevel@tonic-gate 	int	l_flag = 0;
13577c478bd9Sstevel@tonic-gate 	int	c_flag = 0;
13587c478bd9Sstevel@tonic-gate 	int	d_flag = 0;
13597c478bd9Sstevel@tonic-gate 	int	f_flag = 0;
13607c478bd9Sstevel@tonic-gate 	int	F_flag = 0;
13617c478bd9Sstevel@tonic-gate 	int	no_flags = 1;
13627c478bd9Sstevel@tonic-gate 	char	*current_dir;
13637c478bd9Sstevel@tonic-gate 
13647c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
13657c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
13667c478bd9Sstevel@tonic-gate 
13677c478bd9Sstevel@tonic-gate 	if (geteuid() != 0) {
13687c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Must be root.\n"));
13697c478bd9Sstevel@tonic-gate 		exit(1);
13707c478bd9Sstevel@tonic-gate 	}
13717c478bd9Sstevel@tonic-gate 
13727c478bd9Sstevel@tonic-gate 	if ((progname = strrchr(argv[0], '/')) == NULL)
13737c478bd9Sstevel@tonic-gate 		progname = argv[0];
13747c478bd9Sstevel@tonic-gate 	else
13757c478bd9Sstevel@tonic-gate 		progname++;
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate 	raids = NULL;
13787c478bd9Sstevel@tonic-gate 
13797c478bd9Sstevel@tonic-gate 	(void) strncpy(yeschr, nl_langinfo(YESSTR), SCHAR_MAX + 1);
13807c478bd9Sstevel@tonic-gate 	(void) strncpy(nochr, nl_langinfo(NOSTR), SCHAR_MAX + 1);
13817c478bd9Sstevel@tonic-gate 
1382*8ba1bcfcSdduvall 	while ((c = getopt(argc, argv, "clfd:F:")) != EOF) {
13837c478bd9Sstevel@tonic-gate 		switch (c) {
13847c478bd9Sstevel@tonic-gate 		case 'c':
1385*8ba1bcfcSdduvall 			if (f_flag || argc != 4) {
13867c478bd9Sstevel@tonic-gate 				usage(progname);
1387*8ba1bcfcSdduvall 			}
1388*8ba1bcfcSdduvall 
13897c478bd9Sstevel@tonic-gate 			findex = DO_HW_RAID_CREATE;
13907c478bd9Sstevel@tonic-gate 			c_flag = 1;
13917c478bd9Sstevel@tonic-gate 			no_flags = 0;
13927c478bd9Sstevel@tonic-gate 			break;
13937c478bd9Sstevel@tonic-gate 		case 'd':
13947c478bd9Sstevel@tonic-gate 			darg = optarg;
13957c478bd9Sstevel@tonic-gate 			d_flag = 1;
13967c478bd9Sstevel@tonic-gate 			findex = DO_HW_RAID_DELETE;
13977c478bd9Sstevel@tonic-gate 			no_flags = 0;
13987c478bd9Sstevel@tonic-gate 			break;
13997c478bd9Sstevel@tonic-gate 		case 'l':
14007c478bd9Sstevel@tonic-gate 			findex = DO_HW_RAID_INFO;
14017c478bd9Sstevel@tonic-gate 			l_flag = 1;
14027c478bd9Sstevel@tonic-gate 			no_flags = 0;
14037c478bd9Sstevel@tonic-gate 			break;
14047c478bd9Sstevel@tonic-gate 		case 'F':
14057c478bd9Sstevel@tonic-gate 			findex = DO_HW_RAID_FLASH;
14067c478bd9Sstevel@tonic-gate 			farg = optarg;
14077c478bd9Sstevel@tonic-gate 			F_flag = 1;
14087c478bd9Sstevel@tonic-gate 			no_flags = 0;
14097c478bd9Sstevel@tonic-gate 			break;
14107c478bd9Sstevel@tonic-gate 		case 'f':
14117c478bd9Sstevel@tonic-gate 			f_flag = 1;
14127c478bd9Sstevel@tonic-gate 			no_flags = 0;
14137c478bd9Sstevel@tonic-gate 			break;
1414*8ba1bcfcSdduvall 		case '?': default:
14157c478bd9Sstevel@tonic-gate 			usage(progname);
14167c478bd9Sstevel@tonic-gate 		}
14177c478bd9Sstevel@tonic-gate 	}
14187c478bd9Sstevel@tonic-gate 
14197c478bd9Sstevel@tonic-gate 	if (no_flags && argc > 1)
14207c478bd9Sstevel@tonic-gate 		usage(progname);
14217c478bd9Sstevel@tonic-gate 
14227c478bd9Sstevel@tonic-gate 	/* compatibility rules */
14237c478bd9Sstevel@tonic-gate 	if (c_flag && d_flag)
14247c478bd9Sstevel@tonic-gate 		usage(progname);
1425*8ba1bcfcSdduvall 	if (l_flag && (d_flag || c_flag || f_flag || F_flag))
14267c478bd9Sstevel@tonic-gate 		usage(progname);
1427*8ba1bcfcSdduvall 	if (F_flag && (d_flag || c_flag || l_flag))
14287c478bd9Sstevel@tonic-gate 		usage(progname);
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate 	switch (findex) {
14317c478bd9Sstevel@tonic-gate 	case DO_HW_RAID_INFO:
14327c478bd9Sstevel@tonic-gate 		if (l_flag) {
14337c478bd9Sstevel@tonic-gate 			/*
14347c478bd9Sstevel@tonic-gate 			 * "raidctl"	makes argc == 1
14357c478bd9Sstevel@tonic-gate 			 * "-l"		makes argc == 2
14367c478bd9Sstevel@tonic-gate 			 */
14377c478bd9Sstevel@tonic-gate 			ctrl_nums = argc - 2;
14387c478bd9Sstevel@tonic-gate 			if (ctrl_nums != 0) {
14397c478bd9Sstevel@tonic-gate 				info_ctrl = (int **)
14407c478bd9Sstevel@tonic-gate 					malloc(ctrl_nums * sizeof (int));
14417c478bd9Sstevel@tonic-gate 				if (info_ctrl == NULL)
14427c478bd9Sstevel@tonic-gate 					return (FAILURE);
14437c478bd9Sstevel@tonic-gate 			}
14447c478bd9Sstevel@tonic-gate 			for (i = 0; i < ctrl_nums; i++) {
14457c478bd9Sstevel@tonic-gate 				char *tmp = argv[i + 2];
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 				info_ctrl[i] = (int *)malloc(2 * sizeof (int));
14487c478bd9Sstevel@tonic-gate 				if (info_ctrl[i] == NULL) {
14497c478bd9Sstevel@tonic-gate 					free(info_ctrl);
14507c478bd9Sstevel@tonic-gate 					return (FAILURE);
14517c478bd9Sstevel@tonic-gate 				}
14527c478bd9Sstevel@tonic-gate 				if (fully_numeric(tmp)) {
14537c478bd9Sstevel@tonic-gate 					(void) sscanf(tmp, "%d",
14547c478bd9Sstevel@tonic-gate 						&info_ctrl[i][INFO_CTRL]);
14557c478bd9Sstevel@tonic-gate 					info_ctrl[i][INFO_STATUS] =
14567c478bd9Sstevel@tonic-gate 						RAID_INVALID_CTRL;
14577c478bd9Sstevel@tonic-gate 				} else {
14587c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
14597c478bd9Sstevel@tonic-gate 					gettext("Invalid controller '%s'\n"),
14607c478bd9Sstevel@tonic-gate 					tmp);
14617c478bd9Sstevel@tonic-gate 					info_ctrl[i][INFO_STATUS] =
14627c478bd9Sstevel@tonic-gate 						RAID_DONT_USE;
14637c478bd9Sstevel@tonic-gate 				}
14647c478bd9Sstevel@tonic-gate 			}
14657c478bd9Sstevel@tonic-gate 		} else if (argc > 1) {
14667c478bd9Sstevel@tonic-gate 			usage(progname);
14677c478bd9Sstevel@tonic-gate 		}
14687c478bd9Sstevel@tonic-gate 
14697c478bd9Sstevel@tonic-gate 		do_info();
14707c478bd9Sstevel@tonic-gate 		break;
14717c478bd9Sstevel@tonic-gate 	case DO_HW_RAID_CREATE:
14727c478bd9Sstevel@tonic-gate 		for (i = 0; i < N_DISKS; i++) {
1473*8ba1bcfcSdduvall 			disks[i] = argv[argc - 2 + i];
14747c478bd9Sstevel@tonic-gate 			if (!canonical_name(disks[i]))
14757c478bd9Sstevel@tonic-gate 				usage(progname);
14767c478bd9Sstevel@tonic-gate 		}
1477*8ba1bcfcSdduvall 		rv = do_create(disks);
14787c478bd9Sstevel@tonic-gate 		break;
14797c478bd9Sstevel@tonic-gate 	case DO_HW_RAID_DELETE:
14807c478bd9Sstevel@tonic-gate 		if (!canonical_name(darg))
14817c478bd9Sstevel@tonic-gate 			usage(progname);
14827c478bd9Sstevel@tonic-gate 
14837c478bd9Sstevel@tonic-gate 		rv = do_delete(darg);
14847c478bd9Sstevel@tonic-gate 		break;
14857c478bd9Sstevel@tonic-gate 	case DO_HW_RAID_FLASH:
1486*8ba1bcfcSdduvall 		/*
1487*8ba1bcfcSdduvall 		 * "raidctl"	makes argc == 1
1488*8ba1bcfcSdduvall 		 * "-F"		makes argc == 2
1489*8ba1bcfcSdduvall 		 * "filename"	makes argc == 3
1490*8ba1bcfcSdduvall 		 * "-f"		makes argc == 4 if added.
1491*8ba1bcfcSdduvall 		 */
14927c478bd9Sstevel@tonic-gate 		ctrl_nums = argc - f_flag - 3;
14937c478bd9Sstevel@tonic-gate 		if (ctrl_nums == 0)
14947c478bd9Sstevel@tonic-gate 			usage(progname);
14957c478bd9Sstevel@tonic-gate 
14967c478bd9Sstevel@tonic-gate 		current_dir = getcwd(NULL, MAXPATHLEN);
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 		for (i = 0; i < ctrl_nums; i++) {
14997c478bd9Sstevel@tonic-gate 			char *tmp = argv[i + 3 + f_flag];
15007c478bd9Sstevel@tonic-gate 			(void) chdir(current_dir);
15017c478bd9Sstevel@tonic-gate 			if (fully_numeric(tmp)) {
15027c478bd9Sstevel@tonic-gate 				(void) sscanf(tmp, "%d", &controller);
15037c478bd9Sstevel@tonic-gate 				rv = do_flash(controller, farg, f_flag);
15047c478bd9Sstevel@tonic-gate 				if (rv == FAILURE)
15057c478bd9Sstevel@tonic-gate 					break;
15067c478bd9Sstevel@tonic-gate 			} else {
15077c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
15087c478bd9Sstevel@tonic-gate 					gettext("Invalid controller '%s'\n"),
15097c478bd9Sstevel@tonic-gate 					tmp);
15107c478bd9Sstevel@tonic-gate 			}
15117c478bd9Sstevel@tonic-gate 		}
15127c478bd9Sstevel@tonic-gate 		free(current_dir);
15137c478bd9Sstevel@tonic-gate 		break;
15147c478bd9Sstevel@tonic-gate 	default:
15157c478bd9Sstevel@tonic-gate 		usage(progname);
15167c478bd9Sstevel@tonic-gate 	}
15177c478bd9Sstevel@tonic-gate 	return (rv);
15187c478bd9Sstevel@tonic-gate }
1519