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