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