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