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