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