xref: /titanic_41/usr/src/cmd/raidctl/raidctl.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate #include <ctype.h>
31*7c478bd9Sstevel@tonic-gate #include <dirent.h>
32*7c478bd9Sstevel@tonic-gate #include <errno.h>
33*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
34*7c478bd9Sstevel@tonic-gate #include <langinfo.h>
35*7c478bd9Sstevel@tonic-gate #include <libintl.h>
36*7c478bd9Sstevel@tonic-gate #include <limits.h>
37*7c478bd9Sstevel@tonic-gate #include <locale.h>
38*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
39*7c478bd9Sstevel@tonic-gate #include <stdio.h>
40*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
41*7c478bd9Sstevel@tonic-gate #include <string.h>
42*7c478bd9Sstevel@tonic-gate #include <strings.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/mpt/mpi.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/mpt/mpi_ioc.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/pci.h>
49*7c478bd9Sstevel@tonic-gate #include <unistd.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/mnttab.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/dkio.h>
52*7c478bd9Sstevel@tonic-gate #include <config_admin.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/raidioctl.h>
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate /*
57*7c478bd9Sstevel@tonic-gate  * list of controllers to list
58*7c478bd9Sstevel@tonic-gate  * setup like this:
59*7c478bd9Sstevel@tonic-gate  * [ctrl_num]	[status]
60*7c478bd9Sstevel@tonic-gate  *
61*7c478bd9Sstevel@tonic-gate  * where status is:
62*7c478bd9Sstevel@tonic-gate  * RAID Found,
63*7c478bd9Sstevel@tonic-gate  * No RAID Found
64*7c478bd9Sstevel@tonic-gate  * RAID not supported on this controller
65*7c478bd9Sstevel@tonic-gate  * Invalid Controller
66*7c478bd9Sstevel@tonic-gate  */
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate typedef enum {
69*7c478bd9Sstevel@tonic-gate 	RAID_FOUND = 0x0,
70*7c478bd9Sstevel@tonic-gate 	RAID_NOT_FOUND,
71*7c478bd9Sstevel@tonic-gate 	RAID_NOT_SUPPORTED,
72*7c478bd9Sstevel@tonic-gate 	RAID_INVALID_CTRL,
73*7c478bd9Sstevel@tonic-gate 	RAID_DONT_USE
74*7c478bd9Sstevel@tonic-gate } raidctl_errno_t;
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate /* For no-mixup indexing of info_ctrl */
77*7c478bd9Sstevel@tonic-gate #define	INFO_CTRL	0
78*7c478bd9Sstevel@tonic-gate #define	INFO_STATUS	1
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate static int **info_ctrl = NULL;
81*7c478bd9Sstevel@tonic-gate /* Length of conrollers list */
82*7c478bd9Sstevel@tonic-gate static int ctrl_nums = 0;
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate #define	DEVDIR			"/dev/rdsk"
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_NOP		-1
88*7c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_INFO		0
89*7c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_CREATE	1
90*7c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_DELETE	2
91*7c478bd9Sstevel@tonic-gate #define	DO_HW_RAID_FLASH	3
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate /*
94*7c478bd9Sstevel@tonic-gate  * Error return codes
95*7c478bd9Sstevel@tonic-gate  */
96*7c478bd9Sstevel@tonic-gate #define	SUCCESS			0
97*7c478bd9Sstevel@tonic-gate #define	INVALID_ARG		1
98*7c478bd9Sstevel@tonic-gate #define	FAILURE			2
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate /*
101*7c478bd9Sstevel@tonic-gate  * FW Update Stuff
102*7c478bd9Sstevel@tonic-gate  */
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate /* signature and initial offset for PCI expansion rom images */
105*7c478bd9Sstevel@tonic-gate #define	PCIROM_SIG	0xaa55	/* offset 0h, length 2 bytes */
106*7c478bd9Sstevel@tonic-gate #define	PCIR_OFF	0x18	/* Pointer to PCI Data Structure */
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate /* offsets in PCI data structure header */
109*7c478bd9Sstevel@tonic-gate #define	PCIR_DEVID	0x6	/* PCI device id */
110*7c478bd9Sstevel@tonic-gate #define	PCIR_CODETYPE   0x14	/* type of code (intel/fcode) */
111*7c478bd9Sstevel@tonic-gate #define	PCIR_INDICATOR  0x15	/* "last image" indicator */
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate /* flags for image types */
114*7c478bd9Sstevel@tonic-gate #define	BIOS_IMAGE	0x1
115*7c478bd9Sstevel@tonic-gate #define	FCODE_IMAGE	0x2
116*7c478bd9Sstevel@tonic-gate #define	UNKNOWN_IMAGE	0x3
117*7c478bd9Sstevel@tonic-gate #define	LAST_IMAGE	0x80
118*7c478bd9Sstevel@tonic-gate #define	NOT_LAST_IMAGE	0
119*7c478bd9Sstevel@tonic-gate #define	PCI_IMAGE_UNIT_SIZE	512
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate /* ID's and offsets for MPT Firmware images */
122*7c478bd9Sstevel@tonic-gate #define	FW_ROM_ID			0x5aea	/* bytes 4 & 5 of file */
123*7c478bd9Sstevel@tonic-gate #define	FW_ROM_OFFSET_CHIP_TYPE		0x22	/* (U16) */
124*7c478bd9Sstevel@tonic-gate #define	FW_ROM_OFFSET_VERSION		0x24	/* (U16) */
125*7c478bd9Sstevel@tonic-gate #define	FW_ROM_OFFSET_VERSION_NAME	0x44	/* (32 U8) */
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate /* Key to search for when looking for fcode version */
128*7c478bd9Sstevel@tonic-gate #define	FCODE_VERS_KEY1		0x12
129*7c478bd9Sstevel@tonic-gate #define	FCODE_VERS_KEY2		0x7
130*7c478bd9Sstevel@tonic-gate #define	BIOS_STR		"LSI1030 SCSI Host Adapter BIOS  Driver: "
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate /* get a word from a buffer (works with non-word aligned offsets) */
133*7c478bd9Sstevel@tonic-gate #define	gw(x) (((x)[0]) + (((x)[1]) << 8))
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate /* Number of disks currently supported */
136*7c478bd9Sstevel@tonic-gate #define	N_DISKS		2
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate /*
139*7c478bd9Sstevel@tonic-gate  * Function and strings to properly localize our prompt.
140*7c478bd9Sstevel@tonic-gate  * So for example in german it would ask (ja/nein) or (yes/no) in
141*7c478bd9Sstevel@tonic-gate  * english.
142*7c478bd9Sstevel@tonic-gate  */
143*7c478bd9Sstevel@tonic-gate static int	yes(int c);
144*7c478bd9Sstevel@tonic-gate static char	yeschr[SCHAR_MAX + 2];
145*7c478bd9Sstevel@tonic-gate static char	nochr[SCHAR_MAX +2];
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate typedef struct raidlist {
148*7c478bd9Sstevel@tonic-gate 	raid_config_t	raid_config;
149*7c478bd9Sstevel@tonic-gate 	int	controller;
150*7c478bd9Sstevel@tonic-gate 	char	devctl[MAXPATHLEN];
151*7c478bd9Sstevel@tonic-gate 	struct raidlist *next;
152*7c478bd9Sstevel@tonic-gate } raidlist_t;
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate static raidlist_t	*raids;
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate static void
157*7c478bd9Sstevel@tonic-gate usage(char *prog_name)
158*7c478bd9Sstevel@tonic-gate {
159*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("usage: %s\n"), prog_name);
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("usage: %s -c disk1 disk2\n"),
162*7c478bd9Sstevel@tonic-gate 		prog_name);
163*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("usage: %s -d disk1\n"), prog_name);
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
166*7c478bd9Sstevel@tonic-gate 		gettext("usage: %s [-f] -F image_file controller \n"),
167*7c478bd9Sstevel@tonic-gate 		prog_name);
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("usage: %s -l [controller...]\n"),
170*7c478bd9Sstevel@tonic-gate 		prog_name);
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("example:\n"));
173*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s -c c1t1d0 c1t2d0\n", prog_name);
174*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s -d c1t1d0\n", prog_name);
175*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s -F image 1\n", prog_name);
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 	exit(1);
178*7c478bd9Sstevel@tonic-gate }
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate /* Make errno message more "user friendly" */
181*7c478bd9Sstevel@tonic-gate static void
182*7c478bd9Sstevel@tonic-gate raidctl_error(char *str)
183*7c478bd9Sstevel@tonic-gate {
184*7c478bd9Sstevel@tonic-gate 	switch (errno) {
185*7c478bd9Sstevel@tonic-gate 	case EIO:
186*7c478bd9Sstevel@tonic-gate 	case EFAULT:
187*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
188*7c478bd9Sstevel@tonic-gate 			gettext("Error: Device inaccessible.\n"));
189*7c478bd9Sstevel@tonic-gate 		break;
190*7c478bd9Sstevel@tonic-gate 	case ENOTTY:
191*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Error: "
192*7c478bd9Sstevel@tonic-gate 			"Device does not support requested action.\n"));
193*7c478bd9Sstevel@tonic-gate 		break;
194*7c478bd9Sstevel@tonic-gate 	default:
195*7c478bd9Sstevel@tonic-gate 		perror(str);
196*7c478bd9Sstevel@tonic-gate 	}
197*7c478bd9Sstevel@tonic-gate }
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate static int
200*7c478bd9Sstevel@tonic-gate get_link_path(const char *thing, char *buf)
201*7c478bd9Sstevel@tonic-gate {
202*7c478bd9Sstevel@tonic-gate 	if (readlink(thing, buf, MAXPATHLEN) < 0)
203*7c478bd9Sstevel@tonic-gate 		return (1);
204*7c478bd9Sstevel@tonic-gate 	return (0);
205*7c478bd9Sstevel@tonic-gate }
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate static int
208*7c478bd9Sstevel@tonic-gate get_ctrl_devctl(char *ctrl, char *b)
209*7c478bd9Sstevel@tonic-gate {
210*7c478bd9Sstevel@tonic-gate 	char	devctl_buf[MAXPATHLEN];
211*7c478bd9Sstevel@tonic-gate 	char	*colon;
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(devctl_buf, ctrl, MAXPATHLEN);
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 	colon = strrchr(devctl_buf, ':');
216*7c478bd9Sstevel@tonic-gate 	if (colon == NULL)
217*7c478bd9Sstevel@tonic-gate 		return (1);
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate 	*colon = 0;
220*7c478bd9Sstevel@tonic-gate 	(void) snprintf(devctl_buf, MAXPATHLEN, "%s:devctl", devctl_buf);
221*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(b, devctl_buf, MAXPATHLEN);
222*7c478bd9Sstevel@tonic-gate 	return (0);
223*7c478bd9Sstevel@tonic-gate }
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate static int
226*7c478bd9Sstevel@tonic-gate get_devctl(char *disk, char *b)
227*7c478bd9Sstevel@tonic-gate {
228*7c478bd9Sstevel@tonic-gate 	char	buf1[MAXPATHLEN] = {0};
229*7c478bd9Sstevel@tonic-gate 	char	devctl_buf[MAXPATHLEN];
230*7c478bd9Sstevel@tonic-gate 	char	*slash;
231*7c478bd9Sstevel@tonic-gate 	char	devname[32];
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate 	if (get_link_path(disk, buf1))
234*7c478bd9Sstevel@tonic-gate 		return (1);
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(devctl_buf, buf1, MAXPATHLEN);
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 	slash = strrchr(devctl_buf, '/');
239*7c478bd9Sstevel@tonic-gate 	if (slash == NULL)
240*7c478bd9Sstevel@tonic-gate 		return (1);
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 	*slash = 0;
243*7c478bd9Sstevel@tonic-gate 	slash = strrchr(devctl_buf, '/');
244*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(devname, slash, 32);
245*7c478bd9Sstevel@tonic-gate 	*slash = 0;
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 	(void) snprintf(devctl_buf, MAXPATHLEN, "%s%s:devctl",
248*7c478bd9Sstevel@tonic-gate 		devctl_buf, devname);
249*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(b, devctl_buf, MAXPATHLEN);
250*7c478bd9Sstevel@tonic-gate 	return (0);
251*7c478bd9Sstevel@tonic-gate }
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate static int
254*7c478bd9Sstevel@tonic-gate already_there(int controller)
255*7c478bd9Sstevel@tonic-gate {
256*7c478bd9Sstevel@tonic-gate 	raidlist_t	*curr = raids;
257*7c478bd9Sstevel@tonic-gate 
258*7c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
259*7c478bd9Sstevel@tonic-gate 		if (curr->controller == controller)
260*7c478bd9Sstevel@tonic-gate 			return (1);
261*7c478bd9Sstevel@tonic-gate 		curr = curr->next;
262*7c478bd9Sstevel@tonic-gate 	}
263*7c478bd9Sstevel@tonic-gate 
264*7c478bd9Sstevel@tonic-gate 	return (0);
265*7c478bd9Sstevel@tonic-gate }
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate /*
268*7c478bd9Sstevel@tonic-gate  * Display those controllers where RAID volumes were not found
269*7c478bd9Sstevel@tonic-gate  */
270*7c478bd9Sstevel@tonic-gate static void
271*7c478bd9Sstevel@tonic-gate print_no_raids()
272*7c478bd9Sstevel@tonic-gate {
273*7c478bd9Sstevel@tonic-gate 	int i, space = 0;
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 	if (info_ctrl == NULL)
276*7c478bd9Sstevel@tonic-gate 		return;
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ctrl_nums; i++) {
279*7c478bd9Sstevel@tonic-gate 		/* Status of '0' means RAID exists at that controller */
280*7c478bd9Sstevel@tonic-gate 		if (info_ctrl[i][INFO_STATUS] == RAID_FOUND ||
281*7c478bd9Sstevel@tonic-gate 		    info_ctrl[i][INFO_STATUS] == RAID_DONT_USE)
282*7c478bd9Sstevel@tonic-gate 			continue;
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 		if (!space && raids != NULL) {
285*7c478bd9Sstevel@tonic-gate 			(void) printf("\n");
286*7c478bd9Sstevel@tonic-gate 			space = 1;
287*7c478bd9Sstevel@tonic-gate 		}
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate 		/* switch statement used to enable gettext()'ing of text */
290*7c478bd9Sstevel@tonic-gate 		switch (info_ctrl[i][INFO_STATUS]) {
291*7c478bd9Sstevel@tonic-gate 		case RAID_INVALID_CTRL:
292*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Invalid controller '%d'\n"),
293*7c478bd9Sstevel@tonic-gate 				info_ctrl[i][INFO_CTRL]);
294*7c478bd9Sstevel@tonic-gate 			break;
295*7c478bd9Sstevel@tonic-gate 		case RAID_NOT_SUPPORTED:
296*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("No RAID supported "
297*7c478bd9Sstevel@tonic-gate 				"on controller '%d'\n"),
298*7c478bd9Sstevel@tonic-gate 					info_ctrl[i][INFO_CTRL]);
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate 			break;
301*7c478bd9Sstevel@tonic-gate 		default:
302*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("No RAID volumes found on "
303*7c478bd9Sstevel@tonic-gate 				"controller '%d'\n"), info_ctrl[i][INFO_CTRL]);
304*7c478bd9Sstevel@tonic-gate 		}
305*7c478bd9Sstevel@tonic-gate 	}
306*7c478bd9Sstevel@tonic-gate }
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate static void
309*7c478bd9Sstevel@tonic-gate add_raid_to_raidlist(char *ctrl_name, int controller)
310*7c478bd9Sstevel@tonic-gate {
311*7c478bd9Sstevel@tonic-gate 	raid_config_t	config;
312*7c478bd9Sstevel@tonic-gate 	raidlist_t		*curr;
313*7c478bd9Sstevel@tonic-gate 	char			buf[MAXPATHLEN] = {0};
314*7c478bd9Sstevel@tonic-gate 	char			buf1[MAXPATHLEN] = {0};
315*7c478bd9Sstevel@tonic-gate 	int			fd;
316*7c478bd9Sstevel@tonic-gate 	int			i;
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 	if (readlink(ctrl_name, buf, sizeof (buf)) < 0)
319*7c478bd9Sstevel@tonic-gate 		return;
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 	if (get_ctrl_devctl(buf, buf1))
322*7c478bd9Sstevel@tonic-gate 		return;
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate 	/*
325*7c478bd9Sstevel@tonic-gate 	 * If "-l" was specified, then only look at those controllers
326*7c478bd9Sstevel@tonic-gate 	 * listed as part of the command line input.
327*7c478bd9Sstevel@tonic-gate 	 */
328*7c478bd9Sstevel@tonic-gate 	if (info_ctrl != NULL) {
329*7c478bd9Sstevel@tonic-gate 		int found = 0;
330*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < ctrl_nums; i++) {
331*7c478bd9Sstevel@tonic-gate 			if (info_ctrl[i][INFO_STATUS] == RAID_DONT_USE)
332*7c478bd9Sstevel@tonic-gate 				continue;
333*7c478bd9Sstevel@tonic-gate 			if (controller == info_ctrl[i][INFO_CTRL]) {
334*7c478bd9Sstevel@tonic-gate 				found = 1;
335*7c478bd9Sstevel@tonic-gate 				break;
336*7c478bd9Sstevel@tonic-gate 			}
337*7c478bd9Sstevel@tonic-gate 		}
338*7c478bd9Sstevel@tonic-gate 		if (!found)
339*7c478bd9Sstevel@tonic-gate 			return;
340*7c478bd9Sstevel@tonic-gate 	}
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 	fd = open(buf1, O_RDONLY);
343*7c478bd9Sstevel@tonic-gate 	if (fd == -1) {
344*7c478bd9Sstevel@tonic-gate 		if (info_ctrl != NULL)
345*7c478bd9Sstevel@tonic-gate 			info_ctrl[i][INFO_STATUS] = RAID_INVALID_CTRL;
346*7c478bd9Sstevel@tonic-gate 		return;
347*7c478bd9Sstevel@tonic-gate 	}
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, RAID_GETCONFIG, &config) < 0) {
350*7c478bd9Sstevel@tonic-gate 		if (info_ctrl != NULL)
351*7c478bd9Sstevel@tonic-gate 			info_ctrl[i][INFO_STATUS] = RAID_NOT_SUPPORTED;
352*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
353*7c478bd9Sstevel@tonic-gate 		/* Fail silently */
354*7c478bd9Sstevel@tonic-gate 		return;
355*7c478bd9Sstevel@tonic-gate 	}
356*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 	if (config.ndisks == 0) {
359*7c478bd9Sstevel@tonic-gate 		if (info_ctrl != NULL)
360*7c478bd9Sstevel@tonic-gate 			info_ctrl[i][INFO_STATUS] = RAID_NOT_FOUND;
361*7c478bd9Sstevel@tonic-gate 		return;
362*7c478bd9Sstevel@tonic-gate 	}
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate 	if (info_ctrl != NULL)
365*7c478bd9Sstevel@tonic-gate 		info_ctrl[i][INFO_STATUS] = RAID_FOUND;
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate 	if (raids == NULL) {
368*7c478bd9Sstevel@tonic-gate 		raids = (raidlist_t *)malloc(sizeof (raidlist_t));
369*7c478bd9Sstevel@tonic-gate 		curr = raids;
370*7c478bd9Sstevel@tonic-gate 	} else {
371*7c478bd9Sstevel@tonic-gate 		if (already_there(controller)) {
372*7c478bd9Sstevel@tonic-gate 			return;
373*7c478bd9Sstevel@tonic-gate 		}
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate 		curr = raids;
376*7c478bd9Sstevel@tonic-gate 		/* Seek to the end */
377*7c478bd9Sstevel@tonic-gate 		while (curr->next != NULL)
378*7c478bd9Sstevel@tonic-gate 			curr = curr->next;
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 		curr->next = (raidlist_t *)malloc(sizeof (raidlist_t));
381*7c478bd9Sstevel@tonic-gate 		curr = curr->next;
382*7c478bd9Sstevel@tonic-gate 	}
383*7c478bd9Sstevel@tonic-gate 	curr->next = NULL;
384*7c478bd9Sstevel@tonic-gate 	curr->controller = controller;
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(curr->devctl, buf1, sizeof (curr->devctl));
387*7c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
388*7c478bd9Sstevel@tonic-gate 	(void) memcpy(&curr->raid_config, &config, sizeof (raid_config_t));
389*7c478bd9Sstevel@tonic-gate }
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate static void
392*7c478bd9Sstevel@tonic-gate print_header()
393*7c478bd9Sstevel@tonic-gate {
394*7c478bd9Sstevel@tonic-gate 	(void) printf(gettext("RAID\t\tRAID\t\tRAID\t\tDisk"));
395*7c478bd9Sstevel@tonic-gate 	(void) printf("\n");
396*7c478bd9Sstevel@tonic-gate 	(void) printf(gettext("Volume\t\tStatus\t\tDisk\t\tStatus"));
397*7c478bd9Sstevel@tonic-gate 	(void) printf("\n");
398*7c478bd9Sstevel@tonic-gate 	(void) printf("------------------------------------------------------");
399*7c478bd9Sstevel@tonic-gate 	(void) printf("\n");
400*7c478bd9Sstevel@tonic-gate }
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate static void
403*7c478bd9Sstevel@tonic-gate print_raidconfig(int c, raid_config_t config)
404*7c478bd9Sstevel@tonic-gate {
405*7c478bd9Sstevel@tonic-gate 	int	i;
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate 	/* Get RAID Volume */
408*7c478bd9Sstevel@tonic-gate 	(void) printf("c%dt%dd0\t\t", c, config.targetid);
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate 	/* Get RAID Info */
411*7c478bd9Sstevel@tonic-gate 	if (config.flags & RAID_FLAG_RESYNCING &&
412*7c478bd9Sstevel@tonic-gate 	    config.state == RAID_STATE_DEGRADED) {
413*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("RESYNCING\t"));
414*7c478bd9Sstevel@tonic-gate 	} else if (config.state == RAID_STATE_DEGRADED) {
415*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("DEGRADED\t"));
416*7c478bd9Sstevel@tonic-gate 	} else if (config.state == RAID_STATE_OPTIMAL) {
417*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("OK\t\t"));
418*7c478bd9Sstevel@tonic-gate 	} else if (config.state == RAID_STATE_FAILED) {
419*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("FAILED\t\t"));
420*7c478bd9Sstevel@tonic-gate 	} else {
421*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("ERROR\t\t"));
422*7c478bd9Sstevel@tonic-gate 	}
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate 	/* Get RAID Disks */
425*7c478bd9Sstevel@tonic-gate 	(void) printf("c%dt%dd0\t\t", c, config.disk[0]);
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate 	/* Get RAID Disk's Status */
428*7c478bd9Sstevel@tonic-gate 	if (config.diskstatus[0] & RAID_DISKSTATUS_FAILED) {
429*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("FAILED\n"));
430*7c478bd9Sstevel@tonic-gate 	} else if (config.diskstatus[0] & RAID_DISKSTATUS_MISSING) {
431*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("MISSING\n"));
432*7c478bd9Sstevel@tonic-gate 	} else {
433*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("OK\n"));
434*7c478bd9Sstevel@tonic-gate 	}
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate 	for (i = 1; i < config.ndisks; i++) {
437*7c478bd9Sstevel@tonic-gate 		(void) printf("\t\t\t\tc%dt%dd0\t\t", c, config.disk[i]);
438*7c478bd9Sstevel@tonic-gate 		if (config.diskstatus[i] & RAID_DISKSTATUS_FAILED) {
439*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("FAILED\n"));
440*7c478bd9Sstevel@tonic-gate 		} else if (config.diskstatus[i] & RAID_DISKSTATUS_MISSING) {
441*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("MISSING\n"));
442*7c478bd9Sstevel@tonic-gate 		} else {
443*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("OK\n"));
444*7c478bd9Sstevel@tonic-gate 		}
445*7c478bd9Sstevel@tonic-gate 	}
446*7c478bd9Sstevel@tonic-gate }
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate static void
449*7c478bd9Sstevel@tonic-gate print_disklist()
450*7c478bd9Sstevel@tonic-gate {
451*7c478bd9Sstevel@tonic-gate 	raidlist_t	*curr = raids;
452*7c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
453*7c478bd9Sstevel@tonic-gate 		print_raidconfig(curr->controller, curr->raid_config);
454*7c478bd9Sstevel@tonic-gate 		curr = curr->next;
455*7c478bd9Sstevel@tonic-gate 	}
456*7c478bd9Sstevel@tonic-gate }
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate static void
459*7c478bd9Sstevel@tonic-gate free_disklist()
460*7c478bd9Sstevel@tonic-gate {
461*7c478bd9Sstevel@tonic-gate 	raidlist_t	*curr = raids;
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
464*7c478bd9Sstevel@tonic-gate 		raidlist_t	*temp;
465*7c478bd9Sstevel@tonic-gate 		temp = curr;
466*7c478bd9Sstevel@tonic-gate 		curr = curr->next;
467*7c478bd9Sstevel@tonic-gate 		free(temp);
468*7c478bd9Sstevel@tonic-gate 	}
469*7c478bd9Sstevel@tonic-gate }
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate static void
472*7c478bd9Sstevel@tonic-gate do_search()
473*7c478bd9Sstevel@tonic-gate {
474*7c478bd9Sstevel@tonic-gate 	DIR		*dir;
475*7c478bd9Sstevel@tonic-gate 	struct dirent	*dp;
476*7c478bd9Sstevel@tonic-gate 	char		buf[MAXPATHLEN];
477*7c478bd9Sstevel@tonic-gate 	int		c;
478*7c478bd9Sstevel@tonic-gate 	int		i, j;
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 	/*
481*7c478bd9Sstevel@tonic-gate 	 * In case repeated numbers were found, assign the repititions as
482*7c478bd9Sstevel@tonic-gate 	 * RAID_DONT_USE
483*7c478bd9Sstevel@tonic-gate 	 */
484*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ctrl_nums; i++) {
485*7c478bd9Sstevel@tonic-gate 		int first_one = 1;
486*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < ctrl_nums; j++) {
487*7c478bd9Sstevel@tonic-gate 			if (info_ctrl[i][INFO_CTRL] ==
488*7c478bd9Sstevel@tonic-gate 				info_ctrl[j][INFO_CTRL]) {
489*7c478bd9Sstevel@tonic-gate 				if (info_ctrl[j][INFO_STATUS] == RAID_DONT_USE)
490*7c478bd9Sstevel@tonic-gate 					continue;
491*7c478bd9Sstevel@tonic-gate 				if (first_one) {
492*7c478bd9Sstevel@tonic-gate 					first_one = 0;
493*7c478bd9Sstevel@tonic-gate 				} else {
494*7c478bd9Sstevel@tonic-gate 					info_ctrl[j][INFO_STATUS] =
495*7c478bd9Sstevel@tonic-gate 						RAID_DONT_USE;
496*7c478bd9Sstevel@tonic-gate 				}
497*7c478bd9Sstevel@tonic-gate 			}
498*7c478bd9Sstevel@tonic-gate 		}
499*7c478bd9Sstevel@tonic-gate 	}
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate 	if ((dir = opendir("/dev/cfg")) == NULL) {
502*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
503*7c478bd9Sstevel@tonic-gate 			gettext("Cannot open /dev/cfg: %s\n"), strerror(errno));
504*7c478bd9Sstevel@tonic-gate 		return;
505*7c478bd9Sstevel@tonic-gate 	}
506*7c478bd9Sstevel@tonic-gate 	while ((dp = readdir(dir)) != NULL) {
507*7c478bd9Sstevel@tonic-gate 		if (strcmp(dp->d_name, ".") == 0 ||
508*7c478bd9Sstevel@tonic-gate 		    strcmp(dp->d_name, "..") == 0)
509*7c478bd9Sstevel@tonic-gate 			continue;
510*7c478bd9Sstevel@tonic-gate 		if (sscanf(dp->d_name, "c%d", &c) != 1)
511*7c478bd9Sstevel@tonic-gate 			continue;
512*7c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), "/dev/cfg/%s", dp->d_name);
513*7c478bd9Sstevel@tonic-gate 		add_raid_to_raidlist(buf, c);
514*7c478bd9Sstevel@tonic-gate 	}
515*7c478bd9Sstevel@tonic-gate 	(void) closedir(dir);
516*7c478bd9Sstevel@tonic-gate }
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate /*
519*7c478bd9Sstevel@tonic-gate  * do_info() will do the following:
520*7c478bd9Sstevel@tonic-gate  * - create a list of disks' devctls
521*7c478bd9Sstevel@tonic-gate  * - try to talk to each of the devctls found
522*7c478bd9Sstevel@tonic-gate  * - if raid configuration is found, display it.
523*7c478bd9Sstevel@tonic-gate  */
524*7c478bd9Sstevel@tonic-gate static void
525*7c478bd9Sstevel@tonic-gate do_info()
526*7c478bd9Sstevel@tonic-gate {
527*7c478bd9Sstevel@tonic-gate 	int i;
528*7c478bd9Sstevel@tonic-gate 	(void) chdir(DEVDIR);
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate 	do_search();
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate 	if (raids == NULL) {
533*7c478bd9Sstevel@tonic-gate 		if (info_ctrl != NULL) {
534*7c478bd9Sstevel@tonic-gate 			print_no_raids();
535*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < ctrl_nums; i++)
536*7c478bd9Sstevel@tonic-gate 				free(info_ctrl[i]);
537*7c478bd9Sstevel@tonic-gate 			free(info_ctrl);
538*7c478bd9Sstevel@tonic-gate 		} else {
539*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("No RAID volumes found\n"));
540*7c478bd9Sstevel@tonic-gate 		}
541*7c478bd9Sstevel@tonic-gate 		return;
542*7c478bd9Sstevel@tonic-gate 	}
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate 	print_header();
545*7c478bd9Sstevel@tonic-gate 	print_disklist();
546*7c478bd9Sstevel@tonic-gate 	print_no_raids();
547*7c478bd9Sstevel@tonic-gate 	free_disklist();
548*7c478bd9Sstevel@tonic-gate 	if (info_ctrl) {
549*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < ctrl_nums; i++)
550*7c478bd9Sstevel@tonic-gate 			free(info_ctrl[i]);
551*7c478bd9Sstevel@tonic-gate 		free(info_ctrl);
552*7c478bd9Sstevel@tonic-gate 	}
553*7c478bd9Sstevel@tonic-gate }
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate static int
556*7c478bd9Sstevel@tonic-gate disk_there(int c, int t)
557*7c478bd9Sstevel@tonic-gate {
558*7c478bd9Sstevel@tonic-gate 	char	disk[100];
559*7c478bd9Sstevel@tonic-gate 	int	fd;
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate 	(void) snprintf(disk, sizeof (disk), "c%dt%dd0s2", c, t);
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate 	fd = open(disk, O_RDWR | O_NDELAY);
564*7c478bd9Sstevel@tonic-gate 	if (fd == -1) {
565*7c478bd9Sstevel@tonic-gate 		return (-1);
566*7c478bd9Sstevel@tonic-gate 	}
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
569*7c478bd9Sstevel@tonic-gate 	return (0);
570*7c478bd9Sstevel@tonic-gate }
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate static int
573*7c478bd9Sstevel@tonic-gate get_controller(char *dev)
574*7c478bd9Sstevel@tonic-gate {
575*7c478bd9Sstevel@tonic-gate 	raidlist_t	*curr;
576*7c478bd9Sstevel@tonic-gate 	int		c;
577*7c478bd9Sstevel@tonic-gate 	do_search();
578*7c478bd9Sstevel@tonic-gate 	curr = raids;
579*7c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
580*7c478bd9Sstevel@tonic-gate 		if (strcmp(curr->devctl, dev) == 0) {
581*7c478bd9Sstevel@tonic-gate 			c = curr->controller;
582*7c478bd9Sstevel@tonic-gate 			break;
583*7c478bd9Sstevel@tonic-gate 		}
584*7c478bd9Sstevel@tonic-gate 		curr = curr->next;
585*7c478bd9Sstevel@tonic-gate 	}
586*7c478bd9Sstevel@tonic-gate 
587*7c478bd9Sstevel@tonic-gate 	free_disklist();
588*7c478bd9Sstevel@tonic-gate 	return (c);
589*7c478bd9Sstevel@tonic-gate }
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate static int
592*7c478bd9Sstevel@tonic-gate disk_mounted(char *d)
593*7c478bd9Sstevel@tonic-gate {
594*7c478bd9Sstevel@tonic-gate 	struct mnttab	mt;
595*7c478bd9Sstevel@tonic-gate 	FILE		*f = fopen("/etc/mnttab", "r");
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate 	while (getmntent(f, &mt) != EOF)
598*7c478bd9Sstevel@tonic-gate 		if (strstr(mt.mnt_special, d) != NULL)
599*7c478bd9Sstevel@tonic-gate 			return (1);
600*7c478bd9Sstevel@tonic-gate 	return (0);
601*7c478bd9Sstevel@tonic-gate }
602*7c478bd9Sstevel@tonic-gate 
603*7c478bd9Sstevel@tonic-gate static int
604*7c478bd9Sstevel@tonic-gate disk_big_enough(char **d, diskaddr_t *cap, int *errcond)
605*7c478bd9Sstevel@tonic-gate {
606*7c478bd9Sstevel@tonic-gate 	struct dk_minfo minfo;
607*7c478bd9Sstevel@tonic-gate 	char		disk[N_DISKS][MAXPATHLEN];
608*7c478bd9Sstevel@tonic-gate 	diskaddr_t	disk_lbsize[N_DISKS];
609*7c478bd9Sstevel@tonic-gate 	diskaddr_t	disk_capacity[N_DISKS];
610*7c478bd9Sstevel@tonic-gate 	int		i, fd;
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < N_DISKS; i++) {
613*7c478bd9Sstevel@tonic-gate 		(void) snprintf(disk[i], sizeof (disk[i]), DEVDIR"/%ss2", d[i]);
614*7c478bd9Sstevel@tonic-gate 		fd = open(disk[i],  O_RDWR | O_NDELAY);
615*7c478bd9Sstevel@tonic-gate 		if (fd == -1) {
616*7c478bd9Sstevel@tonic-gate 			return (FAILURE);
617*7c478bd9Sstevel@tonic-gate 		}
618*7c478bd9Sstevel@tonic-gate 
619*7c478bd9Sstevel@tonic-gate 		if (ioctl(fd, DKIOCGMEDIAINFO, &minfo) == -1) {
620*7c478bd9Sstevel@tonic-gate 			(void) close(fd);
621*7c478bd9Sstevel@tonic-gate 			return (FAILURE);
622*7c478bd9Sstevel@tonic-gate 		}
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 		disk_lbsize[i] = minfo.dki_lbsize;
625*7c478bd9Sstevel@tonic-gate 		disk_capacity[i] = minfo.dki_capacity;
626*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
627*7c478bd9Sstevel@tonic-gate 	}
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate 	/* lbsize must be the same on both disks */
630*7c478bd9Sstevel@tonic-gate 	if (disk_lbsize[0] != disk_lbsize[1]) {
631*7c478bd9Sstevel@tonic-gate 		*errcond = 2;
632*7c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
633*7c478bd9Sstevel@tonic-gate 	}
634*7c478bd9Sstevel@tonic-gate 
635*7c478bd9Sstevel@tonic-gate 	/* secondary size is not greater than or equal to primary size */
636*7c478bd9Sstevel@tonic-gate 	if (disk_capacity[0] > disk_capacity[1]) {
637*7c478bd9Sstevel@tonic-gate 		*errcond = 1;
638*7c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
639*7c478bd9Sstevel@tonic-gate 	}
640*7c478bd9Sstevel@tonic-gate 
641*7c478bd9Sstevel@tonic-gate 	/* Secondary disk is big enough */
642*7c478bd9Sstevel@tonic-gate 	*cap = disk_capacity[0];
643*7c478bd9Sstevel@tonic-gate 	return (SUCCESS);
644*7c478bd9Sstevel@tonic-gate }
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate static int
647*7c478bd9Sstevel@tonic-gate do_config_change_state(cfga_cmd_t cmd, int d, int c)
648*7c478bd9Sstevel@tonic-gate {
649*7c478bd9Sstevel@tonic-gate 	cfga_err_t	cfga_err;
650*7c478bd9Sstevel@tonic-gate 	char		*ap_id;
651*7c478bd9Sstevel@tonic-gate 	int		rv = SUCCESS;
652*7c478bd9Sstevel@tonic-gate 	int		count = 0;
653*7c478bd9Sstevel@tonic-gate 
654*7c478bd9Sstevel@tonic-gate 	ap_id = (char *)malloc(100);
655*7c478bd9Sstevel@tonic-gate 	if (ap_id == NULL)
656*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
657*7c478bd9Sstevel@tonic-gate 
658*7c478bd9Sstevel@tonic-gate 	(void) snprintf(ap_id, 100, "c%d::dsk/c%dt%dd0", c, c, d);
659*7c478bd9Sstevel@tonic-gate 
660*7c478bd9Sstevel@tonic-gate 	/*
661*7c478bd9Sstevel@tonic-gate 	 * If the config_change_state() funcation fails, we want to
662*7c478bd9Sstevel@tonic-gate 	 * retry.  If the retry fails, then we return failure to fail.
663*7c478bd9Sstevel@tonic-gate 	 *
664*7c478bd9Sstevel@tonic-gate 	 * If we fail:
665*7c478bd9Sstevel@tonic-gate 	 *
666*7c478bd9Sstevel@tonic-gate 	 *	If we were called from create, then we fail the raid
667*7c478bd9Sstevel@tonic-gate 	 *	creation.
668*7c478bd9Sstevel@tonic-gate 	 *
669*7c478bd9Sstevel@tonic-gate 	 *	If we were called from delete, then the disk will not
670*7c478bd9Sstevel@tonic-gate 	 *	be re-configured by raidctl.
671*7c478bd9Sstevel@tonic-gate 	 */
672*7c478bd9Sstevel@tonic-gate 	do {
673*7c478bd9Sstevel@tonic-gate 		cfga_err = config_change_state(cmd, 1, &ap_id, NULL,
674*7c478bd9Sstevel@tonic-gate 			NULL, NULL, NULL, 0);
675*7c478bd9Sstevel@tonic-gate 		count++;
676*7c478bd9Sstevel@tonic-gate 	} while (cfga_err != CFGA_OK && count < 2);
677*7c478bd9Sstevel@tonic-gate 
678*7c478bd9Sstevel@tonic-gate 	if (cfga_err != CFGA_OK)
679*7c478bd9Sstevel@tonic-gate 		rv = FAILURE;
680*7c478bd9Sstevel@tonic-gate 
681*7c478bd9Sstevel@tonic-gate 	free(ap_id);
682*7c478bd9Sstevel@tonic-gate 	return (rv);
683*7c478bd9Sstevel@tonic-gate }
684*7c478bd9Sstevel@tonic-gate 
685*7c478bd9Sstevel@tonic-gate static int
686*7c478bd9Sstevel@tonic-gate do_create(char **d)
687*7c478bd9Sstevel@tonic-gate {
688*7c478bd9Sstevel@tonic-gate 	raid_config_t	config;
689*7c478bd9Sstevel@tonic-gate 	char		disk[N_DISKS][MAXPATHLEN] = {0};
690*7c478bd9Sstevel@tonic-gate 	char		channel1[MAXPATHLEN];
691*7c478bd9Sstevel@tonic-gate 	char		channel2[MAXPATHLEN];
692*7c478bd9Sstevel@tonic-gate 	diskaddr_t	capacity;
693*7c478bd9Sstevel@tonic-gate 	int		fd, fd2, size, errcond, disk_here = 1;
694*7c478bd9Sstevel@tonic-gate 	int		c[N_DISKS];
695*7c478bd9Sstevel@tonic-gate 	int		t[N_DISKS];
696*7c478bd9Sstevel@tonic-gate 	char		*tmp;
697*7c478bd9Sstevel@tonic-gate 	int		i;
698*7c478bd9Sstevel@tonic-gate 
699*7c478bd9Sstevel@tonic-gate 	(void) chdir(DEVDIR);
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < N_DISKS; i++) {
702*7c478bd9Sstevel@tonic-gate 		if ((sscanf(d[i], "c%dt%dd0", &c[i], &t[i])) != 2 ||
703*7c478bd9Sstevel@tonic-gate 		    t[i] < 0) {
704*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
705*7c478bd9Sstevel@tonic-gate 				gettext("Invalid disk format.\n"));
706*7c478bd9Sstevel@tonic-gate 			return (INVALID_ARG);
707*7c478bd9Sstevel@tonic-gate 		}
708*7c478bd9Sstevel@tonic-gate 		(void) snprintf(disk[i], sizeof (disk[i]), DEVDIR"/%ss2", d[i]);
709*7c478bd9Sstevel@tonic-gate 	}
710*7c478bd9Sstevel@tonic-gate 
711*7c478bd9Sstevel@tonic-gate 	/* Must be on same controller */
712*7c478bd9Sstevel@tonic-gate 	if (c[0] != c[1]) {
713*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
714*7c478bd9Sstevel@tonic-gate 			gettext("Disks must be on the same controller.\n"));
715*7c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
716*7c478bd9Sstevel@tonic-gate 	}
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate 	/* primary disk target must be lower than secondary disk target */
719*7c478bd9Sstevel@tonic-gate 	if (t[0] > t[1]) {
720*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Primary target ID "
721*7c478bd9Sstevel@tonic-gate 				"must be less than secondary target ID.\n"));
722*7c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
723*7c478bd9Sstevel@tonic-gate 	}
724*7c478bd9Sstevel@tonic-gate 
725*7c478bd9Sstevel@tonic-gate 	/* disks must not be the same */
726*7c478bd9Sstevel@tonic-gate 	if (t[0] == t[1]) {
727*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Disks must be different.\n"));
728*7c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
729*7c478bd9Sstevel@tonic-gate 	}
730*7c478bd9Sstevel@tonic-gate 
731*7c478bd9Sstevel@tonic-gate 	/* disks must be present */
732*7c478bd9Sstevel@tonic-gate 	if (disk_there(c[0], t[0])) {
733*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Disk 'c%dt%dd0' is not present.\n"),
734*7c478bd9Sstevel@tonic-gate 			c[0], t[0]);
735*7c478bd9Sstevel@tonic-gate 		disk_here = 0;
736*7c478bd9Sstevel@tonic-gate 	}
737*7c478bd9Sstevel@tonic-gate 	if (disk_there(c[1], t[1])) {
738*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Disk 'c%dt%dd0' is not present.\n"),
739*7c478bd9Sstevel@tonic-gate 			c[0], t[1]);
740*7c478bd9Sstevel@tonic-gate 		disk_here = 0;
741*7c478bd9Sstevel@tonic-gate 	}
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate 	if (!disk_here) {
744*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Cannot create RAID volume.\n"));
745*7c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
746*7c478bd9Sstevel@tonic-gate 	}
747*7c478bd9Sstevel@tonic-gate 
748*7c478bd9Sstevel@tonic-gate 	/* secondary disk's size must be greater or equal to primary disk's */
749*7c478bd9Sstevel@tonic-gate 	switch (disk_big_enough(d, &capacity, &errcond)) {
750*7c478bd9Sstevel@tonic-gate 	case FAILURE:
751*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
752*7c478bd9Sstevel@tonic-gate 	case INVALID_ARG:
753*7c478bd9Sstevel@tonic-gate 		switch (errcond) {
754*7c478bd9Sstevel@tonic-gate 		case 1:
755*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Cannot create RAID volume when "
756*7c478bd9Sstevel@tonic-gate 			"primary disk is larger than secondary disk.\n"));
757*7c478bd9Sstevel@tonic-gate 		break;
758*7c478bd9Sstevel@tonic-gate 		case 2:
759*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Cannot create RAID volume when "
760*7c478bd9Sstevel@tonic-gate 			"disk block sizes differ.\n"));
761*7c478bd9Sstevel@tonic-gate 		}
762*7c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
763*7c478bd9Sstevel@tonic-gate 	}
764*7c478bd9Sstevel@tonic-gate 
765*7c478bd9Sstevel@tonic-gate 	/* secondary disk must not be mounted */
766*7c478bd9Sstevel@tonic-gate 	if (disk_mounted(d[1])) {
767*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Cannot create RAID volume when "
768*7c478bd9Sstevel@tonic-gate 				"secondary disk \"%s\" is mounted.\n"), d[1]);
769*7c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
770*7c478bd9Sstevel@tonic-gate 	}
771*7c478bd9Sstevel@tonic-gate 
772*7c478bd9Sstevel@tonic-gate 	/* Only one RAID can exist per controller */
773*7c478bd9Sstevel@tonic-gate 	if (get_devctl(disk[0], channel1))
774*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate 	fd = open(channel1, O_RDONLY);
777*7c478bd9Sstevel@tonic-gate 	if (fd == -1) {
778*7c478bd9Sstevel@tonic-gate 		perror(channel1);
779*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
780*7c478bd9Sstevel@tonic-gate 	}
781*7c478bd9Sstevel@tonic-gate 
782*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, RAID_GETCONFIG, &config) < 0) {
783*7c478bd9Sstevel@tonic-gate 		raidctl_error("RAID_GETCONFIG");
784*7c478bd9Sstevel@tonic-gate 		goto fail1;
785*7c478bd9Sstevel@tonic-gate 	}
786*7c478bd9Sstevel@tonic-gate 
787*7c478bd9Sstevel@tonic-gate 	if (config.ndisks != 0) {
788*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("RAID Volume already exists on this "
789*7c478bd9Sstevel@tonic-gate 			"controller 'c%dt%dd0'\n"), c[0], config.targetid);
790*7c478bd9Sstevel@tonic-gate 		goto fail1;
791*7c478bd9Sstevel@tonic-gate 	}
792*7c478bd9Sstevel@tonic-gate 
793*7c478bd9Sstevel@tonic-gate 	/*
794*7c478bd9Sstevel@tonic-gate 	 * Make sure there isn't a raid created on this controller's
795*7c478bd9Sstevel@tonic-gate 	 * other channel
796*7c478bd9Sstevel@tonic-gate 	 */
797*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(channel2, channel1, sizeof (channel2));
798*7c478bd9Sstevel@tonic-gate 	tmp = strrchr(channel2, ':');
799*7c478bd9Sstevel@tonic-gate 	tmp[0] = 0;
800*7c478bd9Sstevel@tonic-gate 	size = strlen(channel2);
801*7c478bd9Sstevel@tonic-gate 
802*7c478bd9Sstevel@tonic-gate 	/*
803*7c478bd9Sstevel@tonic-gate 	 * Format the channel string for the other channel so we can
804*7c478bd9Sstevel@tonic-gate 	 * see if a raid exists on it.  In this case if we are being asked
805*7c478bd9Sstevel@tonic-gate 	 * to create a raid on channel 2 (indicated by the 1,1 at the end
806*7c478bd9Sstevel@tonic-gate 	 * of the string) we want to check channel 1) otherwise we will
807*7c478bd9Sstevel@tonic-gate 	 * check channel 2.
808*7c478bd9Sstevel@tonic-gate 	 */
809*7c478bd9Sstevel@tonic-gate 	if (channel2[size - 2] == ',') {
810*7c478bd9Sstevel@tonic-gate 		channel2[size - 1] = 0;
811*7c478bd9Sstevel@tonic-gate 		channel2[size - 2] = 0;
812*7c478bd9Sstevel@tonic-gate 		(void) snprintf(channel2, sizeof (channel2), "%s:devctl",
813*7c478bd9Sstevel@tonic-gate 			channel2);
814*7c478bd9Sstevel@tonic-gate 	} else {
815*7c478bd9Sstevel@tonic-gate 		(void) snprintf(channel2, sizeof (channel2), "%s,1:devctl",
816*7c478bd9Sstevel@tonic-gate 			channel2);
817*7c478bd9Sstevel@tonic-gate 	}
818*7c478bd9Sstevel@tonic-gate 
819*7c478bd9Sstevel@tonic-gate 	fd2 = open(channel2, O_RDONLY);
820*7c478bd9Sstevel@tonic-gate 	if (fd2 == -1) {
821*7c478bd9Sstevel@tonic-gate 		if (errno == ENOENT)
822*7c478bd9Sstevel@tonic-gate 			goto no_secondary_channel;
823*7c478bd9Sstevel@tonic-gate 		perror(channel2);
824*7c478bd9Sstevel@tonic-gate 		goto fail1;
825*7c478bd9Sstevel@tonic-gate 	}
826*7c478bd9Sstevel@tonic-gate 
827*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd2, RAID_GETCONFIG, &config) < 0) {
828*7c478bd9Sstevel@tonic-gate 		goto fail2;
829*7c478bd9Sstevel@tonic-gate 	}
830*7c478bd9Sstevel@tonic-gate 
831*7c478bd9Sstevel@tonic-gate 	if (config.ndisks != 0) {
832*7c478bd9Sstevel@tonic-gate 		int	cx;
833*7c478bd9Sstevel@tonic-gate 		cx = get_controller(channel2);
834*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("RAID Volume already exists on this "
835*7c478bd9Sstevel@tonic-gate 			"controller 'c%dt%dd0'\n"), cx, config.targetid);
836*7c478bd9Sstevel@tonic-gate 		goto fail2;
837*7c478bd9Sstevel@tonic-gate 	}
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate no_secondary_channel:
840*7c478bd9Sstevel@tonic-gate 
841*7c478bd9Sstevel@tonic-gate 	/* No other RAID volumes exist, so we may continue */
842*7c478bd9Sstevel@tonic-gate 	config.raid_capacity = capacity;
843*7c478bd9Sstevel@tonic-gate 	config.raid_level = 1;	/* RAID 1: Mirror */
844*7c478bd9Sstevel@tonic-gate 	config.targetid = t[0];	/* Assume identity of first disk */
845*7c478bd9Sstevel@tonic-gate 	config.disk[0] = t[0];	/* Primary Disk */
846*7c478bd9Sstevel@tonic-gate 	config.disk[1] = t[1];	/* Secondary Disk */
847*7c478bd9Sstevel@tonic-gate 
848*7c478bd9Sstevel@tonic-gate 	/* Make secondary disk inaccessible to the system */
849*7c478bd9Sstevel@tonic-gate 	if (do_config_change_state(CFGA_CMD_UNCONFIGURE,
850*7c478bd9Sstevel@tonic-gate 		config.disk[1], c[0])) {
851*7c478bd9Sstevel@tonic-gate 		perror("config_change_state");
852*7c478bd9Sstevel@tonic-gate 		goto fail2;
853*7c478bd9Sstevel@tonic-gate 	}
854*7c478bd9Sstevel@tonic-gate 
855*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, RAID_CREATE, &config)) {
856*7c478bd9Sstevel@tonic-gate 		(void) do_config_change_state(CFGA_CMD_CONFIGURE,
857*7c478bd9Sstevel@tonic-gate 			config.disk[1], c[0]);
858*7c478bd9Sstevel@tonic-gate 		raidctl_error("RAID_CREATE");
859*7c478bd9Sstevel@tonic-gate 		goto fail2;
860*7c478bd9Sstevel@tonic-gate 	}
861*7c478bd9Sstevel@tonic-gate 
862*7c478bd9Sstevel@tonic-gate 	(void) printf(gettext("Volume 'c%dt%dd0' created\n"), c[0], t[0]);
863*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
864*7c478bd9Sstevel@tonic-gate 	(void) close(fd2);
865*7c478bd9Sstevel@tonic-gate 	return (SUCCESS);
866*7c478bd9Sstevel@tonic-gate 
867*7c478bd9Sstevel@tonic-gate fail2:
868*7c478bd9Sstevel@tonic-gate 	(void) close(fd2);
869*7c478bd9Sstevel@tonic-gate fail1:
870*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
871*7c478bd9Sstevel@tonic-gate 	return (FAILURE);
872*7c478bd9Sstevel@tonic-gate }
873*7c478bd9Sstevel@tonic-gate 
874*7c478bd9Sstevel@tonic-gate static int
875*7c478bd9Sstevel@tonic-gate do_delete(char *d)
876*7c478bd9Sstevel@tonic-gate {
877*7c478bd9Sstevel@tonic-gate 	raid_config_t	config;
878*7c478bd9Sstevel@tonic-gate 	char		disk1[MAXPATHLEN];
879*7c478bd9Sstevel@tonic-gate 	char		buf[MAXPATHLEN];
880*7c478bd9Sstevel@tonic-gate 	int		fd;
881*7c478bd9Sstevel@tonic-gate 	int		target;
882*7c478bd9Sstevel@tonic-gate 	int		ctrl;
883*7c478bd9Sstevel@tonic-gate 	uint8_t		t;
884*7c478bd9Sstevel@tonic-gate 
885*7c478bd9Sstevel@tonic-gate 	(void) chdir(DEVDIR);
886*7c478bd9Sstevel@tonic-gate 
887*7c478bd9Sstevel@tonic-gate 	if ((sscanf(d, "c%dt%dd0", &ctrl, &target)) != 2) {
888*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Invalid disk format.\n"));
889*7c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
890*7c478bd9Sstevel@tonic-gate 	}
891*7c478bd9Sstevel@tonic-gate 	t = (uint8_t)target;
892*7c478bd9Sstevel@tonic-gate 
893*7c478bd9Sstevel@tonic-gate 	(void) snprintf(disk1, sizeof (disk1), DEVDIR"/%ss2", d);
894*7c478bd9Sstevel@tonic-gate 
895*7c478bd9Sstevel@tonic-gate 	if (get_devctl(disk1, buf) != 0) {
896*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
897*7c478bd9Sstevel@tonic-gate 	}
898*7c478bd9Sstevel@tonic-gate 
899*7c478bd9Sstevel@tonic-gate 	fd = open(buf, O_RDONLY);
900*7c478bd9Sstevel@tonic-gate 	if (fd == -1) {
901*7c478bd9Sstevel@tonic-gate 		perror(buf);
902*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
903*7c478bd9Sstevel@tonic-gate 	}
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, RAID_GETCONFIG, &config)) {
906*7c478bd9Sstevel@tonic-gate 		raidctl_error("RAID_GETCONFIG");
907*7c478bd9Sstevel@tonic-gate 		goto fail;
908*7c478bd9Sstevel@tonic-gate 	}
909*7c478bd9Sstevel@tonic-gate 
910*7c478bd9Sstevel@tonic-gate 	if (config.ndisks == 0) {
911*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("No RAID Volume exists on "
912*7c478bd9Sstevel@tonic-gate 			"controller '%d'\n"), ctrl);
913*7c478bd9Sstevel@tonic-gate 		goto fail;
914*7c478bd9Sstevel@tonic-gate 	}
915*7c478bd9Sstevel@tonic-gate 
916*7c478bd9Sstevel@tonic-gate 	if (config.targetid != t) {
917*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
918*7c478bd9Sstevel@tonic-gate 			gettext("RAID volume 'c%dt%dd0' does not exist\n"),
919*7c478bd9Sstevel@tonic-gate 			ctrl, t);
920*7c478bd9Sstevel@tonic-gate 		goto fail;
921*7c478bd9Sstevel@tonic-gate 	}
922*7c478bd9Sstevel@tonic-gate 
923*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, RAID_DELETE, &t)) {
924*7c478bd9Sstevel@tonic-gate 		perror("RAID_DELETE");
925*7c478bd9Sstevel@tonic-gate 		goto fail;
926*7c478bd9Sstevel@tonic-gate 	}
927*7c478bd9Sstevel@tonic-gate 
928*7c478bd9Sstevel@tonic-gate 	/*
929*7c478bd9Sstevel@tonic-gate 	 * Make secondary disk accessible to the system.
930*7c478bd9Sstevel@tonic-gate 	 * Ignore return value from do_config_change_state.
931*7c478bd9Sstevel@tonic-gate 	 */
932*7c478bd9Sstevel@tonic-gate 	(void) do_config_change_state(CFGA_CMD_CONFIGURE, config.disk[1], ctrl);
933*7c478bd9Sstevel@tonic-gate 
934*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("Volume 'c%dt%dd0' deleted.\n"),
935*7c478bd9Sstevel@tonic-gate 		ctrl, target);
936*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
937*7c478bd9Sstevel@tonic-gate 	return (SUCCESS);
938*7c478bd9Sstevel@tonic-gate 
939*7c478bd9Sstevel@tonic-gate fail:
940*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
941*7c478bd9Sstevel@tonic-gate 	return (FAILURE);
942*7c478bd9Sstevel@tonic-gate }
943*7c478bd9Sstevel@tonic-gate 
944*7c478bd9Sstevel@tonic-gate static int
945*7c478bd9Sstevel@tonic-gate getfcodever(uint8_t *rombuf, uint32_t nbytes, char **fcodeversion)
946*7c478bd9Sstevel@tonic-gate {
947*7c478bd9Sstevel@tonic-gate 	int x, y, size;
948*7c478bd9Sstevel@tonic-gate 	int found_1 = 0, found_2 = 0;
949*7c478bd9Sstevel@tonic-gate 	int image_length = 0;
950*7c478bd9Sstevel@tonic-gate 	int no_of_images = 0;
951*7c478bd9Sstevel@tonic-gate 	uint8_t *rombuf_1 = NULL;
952*7c478bd9Sstevel@tonic-gate 	uint16_t image_units = 0;
953*7c478bd9Sstevel@tonic-gate 
954*7c478bd9Sstevel@tonic-gate 	/*
955*7c478bd9Sstevel@tonic-gate 	 * Single Image - Open firmware image
956*7c478bd9Sstevel@tonic-gate 	 */
957*7c478bd9Sstevel@tonic-gate 	if (rombuf[gw(&rombuf[PCIR_OFF]) + PCIR_CODETYPE] == 1) {
958*7c478bd9Sstevel@tonic-gate 		rombuf_1 = rombuf + gw(rombuf + PCIR_OFF) + PCI_PDS_INDICATOR;
959*7c478bd9Sstevel@tonic-gate 		no_of_images = 1;
960*7c478bd9Sstevel@tonic-gate 		goto process_image;
961*7c478bd9Sstevel@tonic-gate 	}
962*7c478bd9Sstevel@tonic-gate 
963*7c478bd9Sstevel@tonic-gate 	/*
964*7c478bd9Sstevel@tonic-gate 	 * Combined Image - First Image - x86/PC-AT Bios image
965*7c478bd9Sstevel@tonic-gate 	 */
966*7c478bd9Sstevel@tonic-gate 	if (rombuf[gw(&rombuf[PCIR_OFF]) + PCIR_CODETYPE] != 0) {
967*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("This is neither open image"
968*7c478bd9Sstevel@tonic-gate 			    " nor Bios/Fcode combined image\n"));
969*7c478bd9Sstevel@tonic-gate 		return (1);
970*7c478bd9Sstevel@tonic-gate 	}
971*7c478bd9Sstevel@tonic-gate 
972*7c478bd9Sstevel@tonic-gate 	/*
973*7c478bd9Sstevel@tonic-gate 	 * Seek to 2nd Image
974*7c478bd9Sstevel@tonic-gate 	 */
975*7c478bd9Sstevel@tonic-gate 	rombuf_1 = rombuf + gw(rombuf + PCI_ROM_PCI_DATA_STRUCT_PTR);
976*7c478bd9Sstevel@tonic-gate 	image_units = gw(rombuf_1 + PCI_PDS_IMAGE_LENGTH);
977*7c478bd9Sstevel@tonic-gate 	image_length = image_units * PCI_IMAGE_UNIT_SIZE;
978*7c478bd9Sstevel@tonic-gate 	rombuf_1 += image_length;
979*7c478bd9Sstevel@tonic-gate 
980*7c478bd9Sstevel@tonic-gate 	/*
981*7c478bd9Sstevel@tonic-gate 	 * Combined Image - Second Image - Open Firmware image
982*7c478bd9Sstevel@tonic-gate 	 */
983*7c478bd9Sstevel@tonic-gate 	if (rombuf_1[PCI_PDS_CODE_TYPE] != 1) {
984*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("This is neither open image"
985*7c478bd9Sstevel@tonic-gate 			    " nor Bios/Fcode combined image\n"));
986*7c478bd9Sstevel@tonic-gate 		return (1);
987*7c478bd9Sstevel@tonic-gate 	}
988*7c478bd9Sstevel@tonic-gate 	rombuf_1 += PCI_PDS_INDICATOR;
989*7c478bd9Sstevel@tonic-gate 	no_of_images = 2;
990*7c478bd9Sstevel@tonic-gate 
991*7c478bd9Sstevel@tonic-gate process_image:
992*7c478bd9Sstevel@tonic-gate 	/*
993*7c478bd9Sstevel@tonic-gate 	 * This should be the last image
994*7c478bd9Sstevel@tonic-gate 	 */
995*7c478bd9Sstevel@tonic-gate 	if (*rombuf_1 != LAST_IMAGE) {
996*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("This is not a valid "
997*7c478bd9Sstevel@tonic-gate 		    "Bios/Fcode image file\n"));
998*7c478bd9Sstevel@tonic-gate 		return (1);
999*7c478bd9Sstevel@tonic-gate 	}
1000*7c478bd9Sstevel@tonic-gate 
1001*7c478bd9Sstevel@tonic-gate 	/*
1002*7c478bd9Sstevel@tonic-gate 	 * Scan through the bois/fcode file to get the fcode version
1003*7c478bd9Sstevel@tonic-gate 	 * 0x12 and 0x7 indicate the start of the fcode version string
1004*7c478bd9Sstevel@tonic-gate 	 */
1005*7c478bd9Sstevel@tonic-gate 	for (x = 0; x < (nbytes - 8); x++) {
1006*7c478bd9Sstevel@tonic-gate 		if ((rombuf[x] == FCODE_VERS_KEY1) &&
1007*7c478bd9Sstevel@tonic-gate 		    (rombuf[x+1] == FCODE_VERS_KEY2) &&
1008*7c478bd9Sstevel@tonic-gate 		    (rombuf[x+2] == 'v') && (rombuf[x+3] == 'e') &&
1009*7c478bd9Sstevel@tonic-gate 		    (rombuf[x+4] == 'r') && (rombuf[x+5] == 's') &&
1010*7c478bd9Sstevel@tonic-gate 		    (rombuf[x+6] == 'i') && (rombuf[x+7] == 'o') &&
1011*7c478bd9Sstevel@tonic-gate 		    (rombuf[x+8] == 'n')) {
1012*7c478bd9Sstevel@tonic-gate 			found_1 = 1;
1013*7c478bd9Sstevel@tonic-gate 			break;
1014*7c478bd9Sstevel@tonic-gate 		}
1015*7c478bd9Sstevel@tonic-gate 	}
1016*7c478bd9Sstevel@tonic-gate 
1017*7c478bd9Sstevel@tonic-gate 	/*
1018*7c478bd9Sstevel@tonic-gate 	 * Store the version string if we have found the beginning of it
1019*7c478bd9Sstevel@tonic-gate 	 */
1020*7c478bd9Sstevel@tonic-gate 	if (found_1) {
1021*7c478bd9Sstevel@tonic-gate 		while (x > 0) {
1022*7c478bd9Sstevel@tonic-gate 			if (rombuf[--x] == FCODE_VERS_KEY1) {
1023*7c478bd9Sstevel@tonic-gate 				if (rombuf[x-1] != FCODE_VERS_KEY1) {
1024*7c478bd9Sstevel@tonic-gate 					x++;
1025*7c478bd9Sstevel@tonic-gate 				}
1026*7c478bd9Sstevel@tonic-gate 				break;
1027*7c478bd9Sstevel@tonic-gate 			}
1028*7c478bd9Sstevel@tonic-gate 		}
1029*7c478bd9Sstevel@tonic-gate 		if (x > 0) {
1030*7c478bd9Sstevel@tonic-gate 			*fcodeversion = (char *)malloc(rombuf[x] + 1);
1031*7c478bd9Sstevel@tonic-gate 			for (y = 0; y < rombuf[x]; y++) {
1032*7c478bd9Sstevel@tonic-gate 				(*fcodeversion)[y] = rombuf[x+y+1];
1033*7c478bd9Sstevel@tonic-gate 			}
1034*7c478bd9Sstevel@tonic-gate 			(*fcodeversion)[y] = '\0';
1035*7c478bd9Sstevel@tonic-gate 		} else {
1036*7c478bd9Sstevel@tonic-gate 			found_1 = 0;
1037*7c478bd9Sstevel@tonic-gate 		}
1038*7c478bd9Sstevel@tonic-gate 	}
1039*7c478bd9Sstevel@tonic-gate 
1040*7c478bd9Sstevel@tonic-gate 	/*
1041*7c478bd9Sstevel@tonic-gate 	 * Scan through the bois/fcode file to get the Bios version
1042*7c478bd9Sstevel@tonic-gate 	 * "@(#)" string indicates the start of the Bios version string
1043*7c478bd9Sstevel@tonic-gate 	 * Append this version string, after already existing fcode version.
1044*7c478bd9Sstevel@tonic-gate 	 */
1045*7c478bd9Sstevel@tonic-gate 	if (no_of_images == 2) {
1046*7c478bd9Sstevel@tonic-gate 		for (x = 0; x < (nbytes - 4); x++) {
1047*7c478bd9Sstevel@tonic-gate 			if ((rombuf[x] == '@') && (rombuf[x+1] == '(') &&
1048*7c478bd9Sstevel@tonic-gate 			    (rombuf[x+2] == '#') && (rombuf[x+3] == ')')) {
1049*7c478bd9Sstevel@tonic-gate 				found_2 = 1;
1050*7c478bd9Sstevel@tonic-gate 				break;
1051*7c478bd9Sstevel@tonic-gate 			}
1052*7c478bd9Sstevel@tonic-gate 		}
1053*7c478bd9Sstevel@tonic-gate 
1054*7c478bd9Sstevel@tonic-gate 		if (found_2) {
1055*7c478bd9Sstevel@tonic-gate 			x += 4;
1056*7c478bd9Sstevel@tonic-gate 			(*fcodeversion)[y] = '\n';
1057*7c478bd9Sstevel@tonic-gate 			size = y + strlen((char *)(rombuf + x)) +
1058*7c478bd9Sstevel@tonic-gate 			    strlen(BIOS_STR) + 2;
1059*7c478bd9Sstevel@tonic-gate 			*fcodeversion = (char *)realloc((*fcodeversion), size);
1060*7c478bd9Sstevel@tonic-gate 			y++;
1061*7c478bd9Sstevel@tonic-gate 			(*fcodeversion)[y] = '\0';
1062*7c478bd9Sstevel@tonic-gate 			(void) strlcat(*fcodeversion, BIOS_STR, size);
1063*7c478bd9Sstevel@tonic-gate 			(void) strlcat(*fcodeversion, (char *)(rombuf + x),
1064*7c478bd9Sstevel@tonic-gate 			    size);
1065*7c478bd9Sstevel@tonic-gate 		}
1066*7c478bd9Sstevel@tonic-gate 	}
1067*7c478bd9Sstevel@tonic-gate 
1068*7c478bd9Sstevel@tonic-gate 	return ((found_1 || found_2) ? 0 : 1);
1069*7c478bd9Sstevel@tonic-gate }
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate static void
1072*7c478bd9Sstevel@tonic-gate getfwver(uint8_t *rombuf, char *fwversion)
1073*7c478bd9Sstevel@tonic-gate {
1074*7c478bd9Sstevel@tonic-gate 	(void) snprintf(fwversion, 8, "%d.%.2d.%.2d.%.2d",
1075*7c478bd9Sstevel@tonic-gate 		rombuf[FW_ROM_OFFSET_VERSION + 3],
1076*7c478bd9Sstevel@tonic-gate 		rombuf[FW_ROM_OFFSET_VERSION + 2],
1077*7c478bd9Sstevel@tonic-gate 		rombuf[FW_ROM_OFFSET_VERSION + 1],
1078*7c478bd9Sstevel@tonic-gate 		rombuf[FW_ROM_OFFSET_VERSION + 0]);
1079*7c478bd9Sstevel@tonic-gate }
1080*7c478bd9Sstevel@tonic-gate 
1081*7c478bd9Sstevel@tonic-gate static int
1082*7c478bd9Sstevel@tonic-gate checkfile(uint8_t *rombuf, uint32_t nbytes, uint32_t chksum, int *imagetype)
1083*7c478bd9Sstevel@tonic-gate {
1084*7c478bd9Sstevel@tonic-gate 	char *imageversion = NULL;
1085*7c478bd9Sstevel@tonic-gate 	char *fwversion;
1086*7c478bd9Sstevel@tonic-gate 
1087*7c478bd9Sstevel@tonic-gate 	fwversion = (char *)malloc(8);
1088*7c478bd9Sstevel@tonic-gate 
1089*7c478bd9Sstevel@tonic-gate 	if (gw(&rombuf[0]) == PCIROM_SIG) {
1090*7c478bd9Sstevel@tonic-gate 		/* imageversion is malloc(2)'ed in getfcodever() */
1091*7c478bd9Sstevel@tonic-gate 		if (getfcodever(rombuf, nbytes, &imageversion) == 0) {
1092*7c478bd9Sstevel@tonic-gate 			*imagetype = FCODE_IMAGE;
1093*7c478bd9Sstevel@tonic-gate 		} else {
1094*7c478bd9Sstevel@tonic-gate 			*imagetype = UNKNOWN_IMAGE;
1095*7c478bd9Sstevel@tonic-gate 		}
1096*7c478bd9Sstevel@tonic-gate 		if (*imagetype != UNKNOWN_IMAGE) {
1097*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Image file contains:\n%s\n"),
1098*7c478bd9Sstevel@tonic-gate 			    imageversion);
1099*7c478bd9Sstevel@tonic-gate 			free(imageversion);
1100*7c478bd9Sstevel@tonic-gate 		} else {
1101*7c478bd9Sstevel@tonic-gate 			if (imageversion != NULL) {
1102*7c478bd9Sstevel@tonic-gate 				free(imageversion);
1103*7c478bd9Sstevel@tonic-gate 			}
1104*7c478bd9Sstevel@tonic-gate 			return (-1);
1105*7c478bd9Sstevel@tonic-gate 		}
1106*7c478bd9Sstevel@tonic-gate 	} else if (gw(&rombuf[3]) == FW_ROM_ID) {
1107*7c478bd9Sstevel@tonic-gate 			if (chksum != 0) {
1108*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
1109*7c478bd9Sstevel@tonic-gate 					gettext("The ROM checksum appears bad "
1110*7c478bd9Sstevel@tonic-gate 					"(%d)\n"), chksum);
1111*7c478bd9Sstevel@tonic-gate 				return (-1);
1112*7c478bd9Sstevel@tonic-gate 			}
1113*7c478bd9Sstevel@tonic-gate 			getfwver(rombuf, fwversion);
1114*7c478bd9Sstevel@tonic-gate 
1115*7c478bd9Sstevel@tonic-gate 			if ((gw(&rombuf[FW_ROM_OFFSET_CHIP_TYPE]) &
1116*7c478bd9Sstevel@tonic-gate 				MPI_FW_HEADER_PID_PROD_MASK) ==
1117*7c478bd9Sstevel@tonic-gate 				MPI_FW_HEADER_PID_PROD_IM_SCSI) {
1118*7c478bd9Sstevel@tonic-gate 				(void) printf(gettext("ROM image contains "
1119*7c478bd9Sstevel@tonic-gate 					"MPT firmware version %s "
1120*7c478bd9Sstevel@tonic-gate 					"(w/Integrated Mirroring)\n"),
1121*7c478bd9Sstevel@tonic-gate 						fwversion);
1122*7c478bd9Sstevel@tonic-gate 			} else {
1123*7c478bd9Sstevel@tonic-gate 				(void) printf(gettext("ROM image contains "
1124*7c478bd9Sstevel@tonic-gate 					"MPT firmware ""version %s\n"),
1125*7c478bd9Sstevel@tonic-gate 						fwversion);
1126*7c478bd9Sstevel@tonic-gate 			}
1127*7c478bd9Sstevel@tonic-gate 			free(fwversion);
1128*7c478bd9Sstevel@tonic-gate 	} else {
1129*7c478bd9Sstevel@tonic-gate 
1130*7c478bd9Sstevel@tonic-gate #ifdef	DEBUG
1131*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "Not valid FCODE image %x\n", gw(&rombuf[0]));
1132*7c478bd9Sstevel@tonic-gate #else
1133*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("Not valid FCODE image\n"));
1134*7c478bd9Sstevel@tonic-gate #endif
1135*7c478bd9Sstevel@tonic-gate 		return (-1);
1136*7c478bd9Sstevel@tonic-gate 	}
1137*7c478bd9Sstevel@tonic-gate 	return (0);
1138*7c478bd9Sstevel@tonic-gate }
1139*7c478bd9Sstevel@tonic-gate 
1140*7c478bd9Sstevel@tonic-gate static int
1141*7c478bd9Sstevel@tonic-gate updateflash(uint8_t *rombuf, uint32_t nbytes, char *devctl)
1142*7c478bd9Sstevel@tonic-gate {
1143*7c478bd9Sstevel@tonic-gate 	int fd = 0;
1144*7c478bd9Sstevel@tonic-gate 	update_flash_t flashdata;
1145*7c478bd9Sstevel@tonic-gate 
1146*7c478bd9Sstevel@tonic-gate 	fd = open(devctl, O_RDONLY);
1147*7c478bd9Sstevel@tonic-gate 	if (fd == -1) {
1148*7c478bd9Sstevel@tonic-gate 		perror(devctl);
1149*7c478bd9Sstevel@tonic-gate 		return (-1);
1150*7c478bd9Sstevel@tonic-gate 	}
1151*7c478bd9Sstevel@tonic-gate 	(void) memset(&flashdata, 0, sizeof (flashdata));
1152*7c478bd9Sstevel@tonic-gate 	flashdata.ptrbuffer = (caddr_t)rombuf;
1153*7c478bd9Sstevel@tonic-gate 	flashdata.size = nbytes;
1154*7c478bd9Sstevel@tonic-gate 	if ((rombuf[0] == 0x55) && (rombuf[1] == 0xaa)) {
1155*7c478bd9Sstevel@tonic-gate 		flashdata.type = FW_TYPE_FCODE;
1156*7c478bd9Sstevel@tonic-gate 	} else {
1157*7c478bd9Sstevel@tonic-gate 		flashdata.type = FW_TYPE_UCODE;
1158*7c478bd9Sstevel@tonic-gate 	}
1159*7c478bd9Sstevel@tonic-gate 
1160*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, RAID_UPDATEFW, &flashdata)) {
1161*7c478bd9Sstevel@tonic-gate 		raidctl_error("RAID_UPDATEFW");
1162*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
1163*7c478bd9Sstevel@tonic-gate 		return (-1);
1164*7c478bd9Sstevel@tonic-gate 	}
1165*7c478bd9Sstevel@tonic-gate 
1166*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
1167*7c478bd9Sstevel@tonic-gate 	return (0);
1168*7c478bd9Sstevel@tonic-gate }
1169*7c478bd9Sstevel@tonic-gate 
1170*7c478bd9Sstevel@tonic-gate static int
1171*7c478bd9Sstevel@tonic-gate readfile(char *filespec, uint8_t **rombuf, uint32_t *nbytes, uint32_t *chksum)
1172*7c478bd9Sstevel@tonic-gate {
1173*7c478bd9Sstevel@tonic-gate 	struct stat	statbuf;
1174*7c478bd9Sstevel@tonic-gate 	uint32_t	count;
1175*7c478bd9Sstevel@tonic-gate 	uint32_t	checksum = 0;
1176*7c478bd9Sstevel@tonic-gate 	int		fd, i;
1177*7c478bd9Sstevel@tonic-gate 	uint8_t		*filebuf;
1178*7c478bd9Sstevel@tonic-gate 
1179*7c478bd9Sstevel@tonic-gate 
1180*7c478bd9Sstevel@tonic-gate 	if ((fd = open((const char *)filespec, O_RDONLY | O_NDELAY)) == -1) {
1181*7c478bd9Sstevel@tonic-gate 		perror(filespec);
1182*7c478bd9Sstevel@tonic-gate 		return (-1);
1183*7c478bd9Sstevel@tonic-gate 	}
1184*7c478bd9Sstevel@tonic-gate 
1185*7c478bd9Sstevel@tonic-gate 	if (fstat(fd, &statbuf) != 0) {
1186*7c478bd9Sstevel@tonic-gate 		perror("fstat");
1187*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1188*7c478bd9Sstevel@tonic-gate 			gettext("Error getting stats on file\n"));
1189*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
1190*7c478bd9Sstevel@tonic-gate 		return (-1);
1191*7c478bd9Sstevel@tonic-gate 	}
1192*7c478bd9Sstevel@tonic-gate 
1193*7c478bd9Sstevel@tonic-gate #ifdef	DEBUG
1194*7c478bd9Sstevel@tonic-gate 	(void) printf("Filesize = %ld\n", statbuf.st_size);
1195*7c478bd9Sstevel@tonic-gate #endif
1196*7c478bd9Sstevel@tonic-gate 
1197*7c478bd9Sstevel@tonic-gate 	filebuf = (uint8_t *)realloc(*rombuf, statbuf.st_size + *nbytes);
1198*7c478bd9Sstevel@tonic-gate 
1199*7c478bd9Sstevel@tonic-gate 	count = read(fd, filebuf + *nbytes, statbuf.st_size);
1200*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
1201*7c478bd9Sstevel@tonic-gate 	if (count != statbuf.st_size) {
1202*7c478bd9Sstevel@tonic-gate 		perror("size check");
1203*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("File is corrupt\n"));
1204*7c478bd9Sstevel@tonic-gate 		return (-1);
1205*7c478bd9Sstevel@tonic-gate 	}
1206*7c478bd9Sstevel@tonic-gate 
1207*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < *nbytes; i++)
1208*7c478bd9Sstevel@tonic-gate 		checksum += filebuf[i] << (8 * (i & 3));
1209*7c478bd9Sstevel@tonic-gate 
1210*7c478bd9Sstevel@tonic-gate 	*rombuf = filebuf;
1211*7c478bd9Sstevel@tonic-gate 	*nbytes = *nbytes + count;
1212*7c478bd9Sstevel@tonic-gate 	*chksum = checksum;
1213*7c478bd9Sstevel@tonic-gate 
1214*7c478bd9Sstevel@tonic-gate 	return (0);
1215*7c478bd9Sstevel@tonic-gate }
1216*7c478bd9Sstevel@tonic-gate 
1217*7c478bd9Sstevel@tonic-gate static int
1218*7c478bd9Sstevel@tonic-gate yes(int c)
1219*7c478bd9Sstevel@tonic-gate {
1220*7c478bd9Sstevel@tonic-gate 	int	i, b;
1221*7c478bd9Sstevel@tonic-gate 	char    ans[SCHAR_MAX + 1];
1222*7c478bd9Sstevel@tonic-gate 
1223*7c478bd9Sstevel@tonic-gate 	for (i = 0; ; i++) {
1224*7c478bd9Sstevel@tonic-gate 		b = getchar();
1225*7c478bd9Sstevel@tonic-gate 		if (b == '\n' || b == '\0' || b == EOF) {
1226*7c478bd9Sstevel@tonic-gate 			ans[i] = 0;
1227*7c478bd9Sstevel@tonic-gate 			break;
1228*7c478bd9Sstevel@tonic-gate 		}
1229*7c478bd9Sstevel@tonic-gate 		if (i < SCHAR_MAX)
1230*7c478bd9Sstevel@tonic-gate 			ans[i] = b;
1231*7c478bd9Sstevel@tonic-gate 	}
1232*7c478bd9Sstevel@tonic-gate 	if (i >= SCHAR_MAX) {
1233*7c478bd9Sstevel@tonic-gate 		i = SCHAR_MAX;
1234*7c478bd9Sstevel@tonic-gate 		ans[SCHAR_MAX] = 0;
1235*7c478bd9Sstevel@tonic-gate 	}
1236*7c478bd9Sstevel@tonic-gate 	if ((i != 0) && ((strncmp(yeschr, ans, i)) == 0)) {
1237*7c478bd9Sstevel@tonic-gate 		return (1);
1238*7c478bd9Sstevel@tonic-gate 	} else {
1239*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("User response is \"%s\", "
1240*7c478bd9Sstevel@tonic-gate 		    "Controller %d not flashed.\n\n"), ans, c);
1241*7c478bd9Sstevel@tonic-gate 		return (0);
1242*7c478bd9Sstevel@tonic-gate 	}
1243*7c478bd9Sstevel@tonic-gate }
1244*7c478bd9Sstevel@tonic-gate 
1245*7c478bd9Sstevel@tonic-gate static int
1246*7c478bd9Sstevel@tonic-gate do_flash(int c, char *fpath, int force)
1247*7c478bd9Sstevel@tonic-gate {
1248*7c478bd9Sstevel@tonic-gate 	char		devctl[MAXPATHLEN] = {0};
1249*7c478bd9Sstevel@tonic-gate 	char		buf[MAXPATHLEN] = {0};
1250*7c478bd9Sstevel@tonic-gate 	int		rv = 0;
1251*7c478bd9Sstevel@tonic-gate 	int		imagetype;
1252*7c478bd9Sstevel@tonic-gate 	uint32_t	nbytes = 0;
1253*7c478bd9Sstevel@tonic-gate 	uint32_t	chksum;
1254*7c478bd9Sstevel@tonic-gate 	uint8_t		*rombuf = NULL;
1255*7c478bd9Sstevel@tonic-gate 	char		cwd[MAXPATHLEN];
1256*7c478bd9Sstevel@tonic-gate 
1257*7c478bd9Sstevel@tonic-gate 	/*
1258*7c478bd9Sstevel@tonic-gate 	 * Read fw file
1259*7c478bd9Sstevel@tonic-gate 	 */
1260*7c478bd9Sstevel@tonic-gate 	rv = readfile(fpath, &rombuf, &nbytes, &chksum);
1261*7c478bd9Sstevel@tonic-gate 	if (rv != 0) {
1262*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
1263*7c478bd9Sstevel@tonic-gate 	}
1264*7c478bd9Sstevel@tonic-gate 
1265*7c478bd9Sstevel@tonic-gate 	(void) getcwd(cwd, sizeof (cwd));
1266*7c478bd9Sstevel@tonic-gate 
1267*7c478bd9Sstevel@tonic-gate 	(void) chdir(DEVDIR);
1268*7c478bd9Sstevel@tonic-gate 
1269*7c478bd9Sstevel@tonic-gate 	/* Get link from "/dev/cfg" */
1270*7c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "/dev/cfg/c%d", c);
1271*7c478bd9Sstevel@tonic-gate 	if (get_link_path(buf, devctl) != 0) {
1272*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1273*7c478bd9Sstevel@tonic-gate 			gettext("Invalid controller '%d'\n"), c);
1274*7c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
1275*7c478bd9Sstevel@tonic-gate 	}
1276*7c478bd9Sstevel@tonic-gate 
1277*7c478bd9Sstevel@tonic-gate 	/* Check File */
1278*7c478bd9Sstevel@tonic-gate 	rv = checkfile(rombuf, nbytes, chksum, &imagetype);
1279*7c478bd9Sstevel@tonic-gate 	if (rv != 0) {
1280*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
1281*7c478bd9Sstevel@tonic-gate 	}
1282*7c478bd9Sstevel@tonic-gate 
1283*7c478bd9Sstevel@tonic-gate 	/* Confirm */
1284*7c478bd9Sstevel@tonic-gate 	if (!force) {
1285*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Update flash image on "
1286*7c478bd9Sstevel@tonic-gate 			"controller %d (%s/%s)? "), c, yeschr, nochr);
1287*7c478bd9Sstevel@tonic-gate 		if (!yes(c)) {
1288*7c478bd9Sstevel@tonic-gate 			return (SUCCESS);
1289*7c478bd9Sstevel@tonic-gate 		}
1290*7c478bd9Sstevel@tonic-gate 	}
1291*7c478bd9Sstevel@tonic-gate 
1292*7c478bd9Sstevel@tonic-gate 	/* Do Flash */
1293*7c478bd9Sstevel@tonic-gate 	if (updateflash(rombuf, nbytes, devctl)) {
1294*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Flash not updated on "
1295*7c478bd9Sstevel@tonic-gate 		    "Controller %d.\n\n"), c);
1296*7c478bd9Sstevel@tonic-gate 		return (INVALID_ARG);
1297*7c478bd9Sstevel@tonic-gate 	}
1298*7c478bd9Sstevel@tonic-gate 	(void) printf(gettext("Flash updated successfully.\n\n"));
1299*7c478bd9Sstevel@tonic-gate 	return (SUCCESS);
1300*7c478bd9Sstevel@tonic-gate }
1301*7c478bd9Sstevel@tonic-gate 
1302*7c478bd9Sstevel@tonic-gate static int
1303*7c478bd9Sstevel@tonic-gate fully_numeric(char *str)
1304*7c478bd9Sstevel@tonic-gate {
1305*7c478bd9Sstevel@tonic-gate 	int	size = strlen(str);
1306*7c478bd9Sstevel@tonic-gate 	int	i;
1307*7c478bd9Sstevel@tonic-gate 
1308*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < size; i++) {
1309*7c478bd9Sstevel@tonic-gate 		if (i == 0 && str[i] == '-' && size != 1)
1310*7c478bd9Sstevel@tonic-gate 			continue;
1311*7c478bd9Sstevel@tonic-gate 		if (!isdigit(str[i]))
1312*7c478bd9Sstevel@tonic-gate 			return (0);
1313*7c478bd9Sstevel@tonic-gate 	}
1314*7c478bd9Sstevel@tonic-gate 	return (1);
1315*7c478bd9Sstevel@tonic-gate }
1316*7c478bd9Sstevel@tonic-gate 
1317*7c478bd9Sstevel@tonic-gate /*
1318*7c478bd9Sstevel@tonic-gate  * Useful parsing macros
1319*7c478bd9Sstevel@tonic-gate  */
1320*7c478bd9Sstevel@tonic-gate #define	must_be(s, c)		if (*s++ != c) return (0)
1321*7c478bd9Sstevel@tonic-gate #define	skip_digits(s)		while (isdigit(*s)) s++
1322*7c478bd9Sstevel@tonic-gate 
1323*7c478bd9Sstevel@tonic-gate /*
1324*7c478bd9Sstevel@tonic-gate  * Return true if a name is in the internal canonical form
1325*7c478bd9Sstevel@tonic-gate  */
1326*7c478bd9Sstevel@tonic-gate static int
1327*7c478bd9Sstevel@tonic-gate canonical_name(char *name)
1328*7c478bd9Sstevel@tonic-gate {
1329*7c478bd9Sstevel@tonic-gate 	must_be(name, 'c');
1330*7c478bd9Sstevel@tonic-gate 	skip_digits(name);
1331*7c478bd9Sstevel@tonic-gate 	if (*name == 't') {
1332*7c478bd9Sstevel@tonic-gate 		name++;
1333*7c478bd9Sstevel@tonic-gate 		skip_digits(name);
1334*7c478bd9Sstevel@tonic-gate 	}
1335*7c478bd9Sstevel@tonic-gate 	must_be(name, 'd');
1336*7c478bd9Sstevel@tonic-gate 	skip_digits(name);
1337*7c478bd9Sstevel@tonic-gate 	return (*name == 0);
1338*7c478bd9Sstevel@tonic-gate }
1339*7c478bd9Sstevel@tonic-gate 
1340*7c478bd9Sstevel@tonic-gate int
1341*7c478bd9Sstevel@tonic-gate main(int argc, char **argv)
1342*7c478bd9Sstevel@tonic-gate {
1343*7c478bd9Sstevel@tonic-gate 	int	rv = SUCCESS;
1344*7c478bd9Sstevel@tonic-gate 	int	i, c;
1345*7c478bd9Sstevel@tonic-gate 	int	findex = DO_HW_RAID_INFO;
1346*7c478bd9Sstevel@tonic-gate 	int	controller;
1347*7c478bd9Sstevel@tonic-gate 	char	*disks[N_DISKS];
1348*7c478bd9Sstevel@tonic-gate 	char	*darg;
1349*7c478bd9Sstevel@tonic-gate 	char	*farg;
1350*7c478bd9Sstevel@tonic-gate 	char	*progname;
1351*7c478bd9Sstevel@tonic-gate 
1352*7c478bd9Sstevel@tonic-gate 	int	l_flag = 0;
1353*7c478bd9Sstevel@tonic-gate 	int	c_flag = 0;
1354*7c478bd9Sstevel@tonic-gate 	int	d_flag = 0;
1355*7c478bd9Sstevel@tonic-gate 	int	f_flag = 0;
1356*7c478bd9Sstevel@tonic-gate 	int	F_flag = 0;
1357*7c478bd9Sstevel@tonic-gate 	int	no_flags = 1;
1358*7c478bd9Sstevel@tonic-gate 	char	*current_dir;
1359*7c478bd9Sstevel@tonic-gate 
1360*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
1361*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
1362*7c478bd9Sstevel@tonic-gate 
1363*7c478bd9Sstevel@tonic-gate 	if (geteuid() != 0) {
1364*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Must be root.\n"));
1365*7c478bd9Sstevel@tonic-gate 		exit(1);
1366*7c478bd9Sstevel@tonic-gate 	}
1367*7c478bd9Sstevel@tonic-gate 
1368*7c478bd9Sstevel@tonic-gate 	if ((progname = strrchr(argv[0], '/')) == NULL)
1369*7c478bd9Sstevel@tonic-gate 		progname = argv[0];
1370*7c478bd9Sstevel@tonic-gate 	else
1371*7c478bd9Sstevel@tonic-gate 		progname++;
1372*7c478bd9Sstevel@tonic-gate 
1373*7c478bd9Sstevel@tonic-gate 	raids = NULL;
1374*7c478bd9Sstevel@tonic-gate 
1375*7c478bd9Sstevel@tonic-gate 	(void) strncpy(yeschr, nl_langinfo(YESSTR), SCHAR_MAX + 1);
1376*7c478bd9Sstevel@tonic-gate 	(void) strncpy(nochr, nl_langinfo(NOSTR), SCHAR_MAX + 1);
1377*7c478bd9Sstevel@tonic-gate 
1378*7c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "clfd:F:")) != EOF) {
1379*7c478bd9Sstevel@tonic-gate 		switch (c) {
1380*7c478bd9Sstevel@tonic-gate 		case 'c':
1381*7c478bd9Sstevel@tonic-gate 			if (f_flag || argc != 4) {
1382*7c478bd9Sstevel@tonic-gate 				usage(progname);
1383*7c478bd9Sstevel@tonic-gate 			}
1384*7c478bd9Sstevel@tonic-gate 
1385*7c478bd9Sstevel@tonic-gate 			findex = DO_HW_RAID_CREATE;
1386*7c478bd9Sstevel@tonic-gate 			c_flag = 1;
1387*7c478bd9Sstevel@tonic-gate 			no_flags = 0;
1388*7c478bd9Sstevel@tonic-gate 			break;
1389*7c478bd9Sstevel@tonic-gate 		case 'd':
1390*7c478bd9Sstevel@tonic-gate 			darg = optarg;
1391*7c478bd9Sstevel@tonic-gate 			d_flag = 1;
1392*7c478bd9Sstevel@tonic-gate 			findex = DO_HW_RAID_DELETE;
1393*7c478bd9Sstevel@tonic-gate 			no_flags = 0;
1394*7c478bd9Sstevel@tonic-gate 			break;
1395*7c478bd9Sstevel@tonic-gate 		case 'l':
1396*7c478bd9Sstevel@tonic-gate 			findex = DO_HW_RAID_INFO;
1397*7c478bd9Sstevel@tonic-gate 			l_flag = 1;
1398*7c478bd9Sstevel@tonic-gate 			no_flags = 0;
1399*7c478bd9Sstevel@tonic-gate 			break;
1400*7c478bd9Sstevel@tonic-gate 		case 'F':
1401*7c478bd9Sstevel@tonic-gate 			findex = DO_HW_RAID_FLASH;
1402*7c478bd9Sstevel@tonic-gate 			farg = optarg;
1403*7c478bd9Sstevel@tonic-gate 			F_flag = 1;
1404*7c478bd9Sstevel@tonic-gate 			no_flags = 0;
1405*7c478bd9Sstevel@tonic-gate 			break;
1406*7c478bd9Sstevel@tonic-gate 		case 'f':
1407*7c478bd9Sstevel@tonic-gate 			f_flag = 1;
1408*7c478bd9Sstevel@tonic-gate 			no_flags = 0;
1409*7c478bd9Sstevel@tonic-gate 			break;
1410*7c478bd9Sstevel@tonic-gate 		case '?': default:
1411*7c478bd9Sstevel@tonic-gate 			usage(progname);
1412*7c478bd9Sstevel@tonic-gate 		}
1413*7c478bd9Sstevel@tonic-gate 	}
1414*7c478bd9Sstevel@tonic-gate 
1415*7c478bd9Sstevel@tonic-gate 	if (no_flags && argc > 1)
1416*7c478bd9Sstevel@tonic-gate 		usage(progname);
1417*7c478bd9Sstevel@tonic-gate 
1418*7c478bd9Sstevel@tonic-gate 	/* compatibility rules */
1419*7c478bd9Sstevel@tonic-gate 	if (c_flag && d_flag)
1420*7c478bd9Sstevel@tonic-gate 		usage(progname);
1421*7c478bd9Sstevel@tonic-gate 	if (l_flag && (d_flag || c_flag || f_flag || F_flag))
1422*7c478bd9Sstevel@tonic-gate 		usage(progname);
1423*7c478bd9Sstevel@tonic-gate 	if (F_flag && (d_flag || c_flag || l_flag))
1424*7c478bd9Sstevel@tonic-gate 		usage(progname);
1425*7c478bd9Sstevel@tonic-gate 
1426*7c478bd9Sstevel@tonic-gate 	switch (findex) {
1427*7c478bd9Sstevel@tonic-gate 	case DO_HW_RAID_INFO:
1428*7c478bd9Sstevel@tonic-gate 		if (l_flag) {
1429*7c478bd9Sstevel@tonic-gate 			/*
1430*7c478bd9Sstevel@tonic-gate 			 * "raidctl"	makes argc == 1
1431*7c478bd9Sstevel@tonic-gate 			 * "-l"		makes argc == 2
1432*7c478bd9Sstevel@tonic-gate 			 */
1433*7c478bd9Sstevel@tonic-gate 			ctrl_nums = argc - 2;
1434*7c478bd9Sstevel@tonic-gate 			if (ctrl_nums != 0) {
1435*7c478bd9Sstevel@tonic-gate 				info_ctrl = (int **)
1436*7c478bd9Sstevel@tonic-gate 					malloc(ctrl_nums * sizeof (int));
1437*7c478bd9Sstevel@tonic-gate 				if (info_ctrl == NULL)
1438*7c478bd9Sstevel@tonic-gate 					return (FAILURE);
1439*7c478bd9Sstevel@tonic-gate 			}
1440*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < ctrl_nums; i++) {
1441*7c478bd9Sstevel@tonic-gate 				char *tmp = argv[i + 2];
1442*7c478bd9Sstevel@tonic-gate 
1443*7c478bd9Sstevel@tonic-gate 				info_ctrl[i] = (int *)malloc(2 * sizeof (int));
1444*7c478bd9Sstevel@tonic-gate 				if (info_ctrl[i] == NULL) {
1445*7c478bd9Sstevel@tonic-gate 					free(info_ctrl);
1446*7c478bd9Sstevel@tonic-gate 					return (FAILURE);
1447*7c478bd9Sstevel@tonic-gate 				}
1448*7c478bd9Sstevel@tonic-gate 				if (fully_numeric(tmp)) {
1449*7c478bd9Sstevel@tonic-gate 					(void) sscanf(tmp, "%d",
1450*7c478bd9Sstevel@tonic-gate 						&info_ctrl[i][INFO_CTRL]);
1451*7c478bd9Sstevel@tonic-gate 					info_ctrl[i][INFO_STATUS] =
1452*7c478bd9Sstevel@tonic-gate 						RAID_INVALID_CTRL;
1453*7c478bd9Sstevel@tonic-gate 				} else {
1454*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
1455*7c478bd9Sstevel@tonic-gate 					gettext("Invalid controller '%s'\n"),
1456*7c478bd9Sstevel@tonic-gate 					tmp);
1457*7c478bd9Sstevel@tonic-gate 					info_ctrl[i][INFO_STATUS] =
1458*7c478bd9Sstevel@tonic-gate 						RAID_DONT_USE;
1459*7c478bd9Sstevel@tonic-gate 				}
1460*7c478bd9Sstevel@tonic-gate 			}
1461*7c478bd9Sstevel@tonic-gate 		} else if (argc > 1) {
1462*7c478bd9Sstevel@tonic-gate 			usage(progname);
1463*7c478bd9Sstevel@tonic-gate 		}
1464*7c478bd9Sstevel@tonic-gate 
1465*7c478bd9Sstevel@tonic-gate 		do_info();
1466*7c478bd9Sstevel@tonic-gate 		break;
1467*7c478bd9Sstevel@tonic-gate 	case DO_HW_RAID_CREATE:
1468*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < N_DISKS; i++) {
1469*7c478bd9Sstevel@tonic-gate 			disks[i] = argv[argc - 2 + i];
1470*7c478bd9Sstevel@tonic-gate 			if (!canonical_name(disks[i]))
1471*7c478bd9Sstevel@tonic-gate 				usage(progname);
1472*7c478bd9Sstevel@tonic-gate 		}
1473*7c478bd9Sstevel@tonic-gate 		rv = do_create(disks);
1474*7c478bd9Sstevel@tonic-gate 		break;
1475*7c478bd9Sstevel@tonic-gate 	case DO_HW_RAID_DELETE:
1476*7c478bd9Sstevel@tonic-gate 		if (!canonical_name(darg))
1477*7c478bd9Sstevel@tonic-gate 			usage(progname);
1478*7c478bd9Sstevel@tonic-gate 
1479*7c478bd9Sstevel@tonic-gate 		rv = do_delete(darg);
1480*7c478bd9Sstevel@tonic-gate 		break;
1481*7c478bd9Sstevel@tonic-gate 	case DO_HW_RAID_FLASH:
1482*7c478bd9Sstevel@tonic-gate 		/*
1483*7c478bd9Sstevel@tonic-gate 		 * "raidctl"	makes argc == 1
1484*7c478bd9Sstevel@tonic-gate 		 * "-F"		makes argc == 2
1485*7c478bd9Sstevel@tonic-gate 		 * "filename"	makes argc == 3
1486*7c478bd9Sstevel@tonic-gate 		 * "-f"		makes argc == 4 if added.
1487*7c478bd9Sstevel@tonic-gate 		 */
1488*7c478bd9Sstevel@tonic-gate 		ctrl_nums = argc - f_flag - 3;
1489*7c478bd9Sstevel@tonic-gate 		if (ctrl_nums == 0)
1490*7c478bd9Sstevel@tonic-gate 			usage(progname);
1491*7c478bd9Sstevel@tonic-gate 
1492*7c478bd9Sstevel@tonic-gate 		current_dir = getcwd(NULL, MAXPATHLEN);
1493*7c478bd9Sstevel@tonic-gate 
1494*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < ctrl_nums; i++) {
1495*7c478bd9Sstevel@tonic-gate 			char *tmp = argv[i + 3 + f_flag];
1496*7c478bd9Sstevel@tonic-gate 			(void) chdir(current_dir);
1497*7c478bd9Sstevel@tonic-gate 			if (fully_numeric(tmp)) {
1498*7c478bd9Sstevel@tonic-gate 				(void) sscanf(tmp, "%d", &controller);
1499*7c478bd9Sstevel@tonic-gate 				rv = do_flash(controller, farg, f_flag);
1500*7c478bd9Sstevel@tonic-gate 				if (rv == FAILURE)
1501*7c478bd9Sstevel@tonic-gate 					break;
1502*7c478bd9Sstevel@tonic-gate 			} else {
1503*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
1504*7c478bd9Sstevel@tonic-gate 					gettext("Invalid controller '%s'\n"),
1505*7c478bd9Sstevel@tonic-gate 					tmp);
1506*7c478bd9Sstevel@tonic-gate 			}
1507*7c478bd9Sstevel@tonic-gate 		}
1508*7c478bd9Sstevel@tonic-gate 		free(current_dir);
1509*7c478bd9Sstevel@tonic-gate 		break;
1510*7c478bd9Sstevel@tonic-gate 	default:
1511*7c478bd9Sstevel@tonic-gate 		usage(progname);
1512*7c478bd9Sstevel@tonic-gate 	}
1513*7c478bd9Sstevel@tonic-gate 	return (rv);
1514*7c478bd9Sstevel@tonic-gate }
1515