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