xref: /onnv-gate/usr/src/cmd/luxadm/qlgcupdate.c (revision 8538:e650bb47662e)
17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM  * CDDL HEADER START
37836SJohn.Forte@Sun.COM  *
47836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM  *
87836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM  * and limitations under the License.
127836SJohn.Forte@Sun.COM  *
137836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM  *
197836SJohn.Forte@Sun.COM  * CDDL HEADER END
207836SJohn.Forte@Sun.COM  */
217836SJohn.Forte@Sun.COM /*
22*8538SReed.Liu@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237836SJohn.Forte@Sun.COM  * Use is subject to license terms.
247836SJohn.Forte@Sun.COM  */
257836SJohn.Forte@Sun.COM 
267836SJohn.Forte@Sun.COM /*
277836SJohn.Forte@Sun.COM  * I18N message number ranges
287836SJohn.Forte@Sun.COM  *  This file: 21000 - 21499
297836SJohn.Forte@Sun.COM  *  Shared common messages: 1 - 1999
307836SJohn.Forte@Sun.COM  */
317836SJohn.Forte@Sun.COM 
327836SJohn.Forte@Sun.COM /*
337836SJohn.Forte@Sun.COM  * Functions to support the download of FCode to PCI HBAs
347836SJohn.Forte@Sun.COM  * Qlogic ISP21XX/22XX boards: FC100/P single port, ISP2200 dual port
357836SJohn.Forte@Sun.COM  * and Emulex cards
367836SJohn.Forte@Sun.COM  */
377836SJohn.Forte@Sun.COM #include <errno.h>
387836SJohn.Forte@Sun.COM #include <ctype.h>
397836SJohn.Forte@Sun.COM #include <fcntl.h>
407836SJohn.Forte@Sun.COM #include <stdio.h>
417836SJohn.Forte@Sun.COM #include <string.h>
427836SJohn.Forte@Sun.COM #include <strings.h>
437836SJohn.Forte@Sun.COM #include <unistd.h>
447836SJohn.Forte@Sun.COM #include <stdlib.h>
457836SJohn.Forte@Sun.COM #include <sys/stat.h>
467836SJohn.Forte@Sun.COM #include <limits.h>
477836SJohn.Forte@Sun.COM #include <signal.h>
487836SJohn.Forte@Sun.COM #include <dirent.h>
497836SJohn.Forte@Sun.COM #include <nl_types.h>
507836SJohn.Forte@Sun.COM #include <utmpx.h>
517836SJohn.Forte@Sun.COM #include <sys/mnttab.h>
527836SJohn.Forte@Sun.COM #include <sys/file.h>
537836SJohn.Forte@Sun.COM #include <sys/mtio.h>
547836SJohn.Forte@Sun.COM #include <sys/scsi/impl/uscsi.h>
557836SJohn.Forte@Sun.COM #include <sys/fibre-channel/fcio.h>
567836SJohn.Forte@Sun.COM #include <stgcom.h>
577836SJohn.Forte@Sun.COM #include <sys/scsi/adapters/ifpio.h>
587836SJohn.Forte@Sun.COM #include <libdevinfo.h>
597836SJohn.Forte@Sun.COM #include "luxadm.h"
607836SJohn.Forte@Sun.COM 
617836SJohn.Forte@Sun.COM /* Error codes - used by the fcode_load_file routine */
627836SJohn.Forte@Sun.COM #define	FCODE_SUCCESS	    0	/* successful completion */
637836SJohn.Forte@Sun.COM #define	FCODE_LOAD_FAILURE  1	/* general failure */
647836SJohn.Forte@Sun.COM #define	FCODE_IOCTL_FAILURE 2	/* FCODE ioctl download failure */
657836SJohn.Forte@Sun.COM 
667836SJohn.Forte@Sun.COM #define	HBA_MAX	128
677836SJohn.Forte@Sun.COM #define	FCODE_HDR 200
687836SJohn.Forte@Sun.COM #define	MAX_RETRIES	3
697836SJohn.Forte@Sun.COM #define	MAX_WAIT_TIME	30
707836SJohn.Forte@Sun.COM 
717836SJohn.Forte@Sun.COM /*
727836SJohn.Forte@Sun.COM  * EMULEX Fcode attributes
737836SJohn.Forte@Sun.COM  */
747836SJohn.Forte@Sun.COM #define	EMULEX_FCODE_VERSION_LENGTH	16
757836SJohn.Forte@Sun.COM #define	EMULEX_READ_BUFFER_SIZE		128
767836SJohn.Forte@Sun.COM 
777836SJohn.Forte@Sun.COM /* Emulex specific error codes */
787836SJohn.Forte@Sun.COM #define	EMLX_ERRNO_START	0x100
797836SJohn.Forte@Sun.COM 
807836SJohn.Forte@Sun.COM /* Diagnostic error codes */
817836SJohn.Forte@Sun.COM #define	EMLX_TEST_FAILED	(EMLX_ERRNO_START + 0)
827836SJohn.Forte@Sun.COM 
837836SJohn.Forte@Sun.COM /* Download image contains bad data */
847836SJohn.Forte@Sun.COM #define	EMLX_IMAGE_BAD		(EMLX_ERRNO_START + 1)
857836SJohn.Forte@Sun.COM /* Download image not compatible with current hardware */
867836SJohn.Forte@Sun.COM #define	EMLX_IMAGE_INCOMPATIBLE	(EMLX_ERRNO_START + 2)
877836SJohn.Forte@Sun.COM /* Unable to take adapter offline */
887836SJohn.Forte@Sun.COM #define	EMLX_IMAGE_FAILED	(EMLX_ERRNO_START + 3)
897836SJohn.Forte@Sun.COM /* Image download failed */
907836SJohn.Forte@Sun.COM #define	EMLX_OFFLINE_FAILED	(EMLX_ERRNO_START + 4)
917836SJohn.Forte@Sun.COM 
927836SJohn.Forte@Sun.COM 
937836SJohn.Forte@Sun.COM 
947836SJohn.Forte@Sun.COM 
957836SJohn.Forte@Sun.COM /*
967836SJohn.Forte@Sun.COM  * This is just a random value chosen to identify Sbus Fcodes. Sbus FCode
977836SJohn.Forte@Sun.COM  * for Ivory is based on a 2200 chip but this value does not reflect that.
987836SJohn.Forte@Sun.COM  */
997836SJohn.Forte@Sun.COM #define	SBUS_CHIP_ID	0x1969
1007836SJohn.Forte@Sun.COM #define	IVORY_BUS	"/sbus@"
1017836SJohn.Forte@Sun.COM #define	IVORY_DRVR	"/SUNW,qlc@"
1027836SJohn.Forte@Sun.COM 
1037836SJohn.Forte@Sun.COM /*	Global variables	*/
1047836SJohn.Forte@Sun.COM static char	fc_trans[] = "SUNW,ifp";	/* fibre channel transport */
1057836SJohn.Forte@Sun.COM static char	fp_trans[] = "SUNW,qlc";	/* fca layer driver	   */
1067836SJohn.Forte@Sun.COM static char	fp_trans_id[] = "fp@";		/* transport layer id	   */
1077836SJohn.Forte@Sun.COM static char	qlgc2100[] = "FC100/P";		/* product name for 2100   */
1087836SJohn.Forte@Sun.COM static char	qlgc2200[] = "ISP2200";		/* product name for 2200   */
1097836SJohn.Forte@Sun.COM static char	qlgc2300[] = "ISP2300";		/* product name for 2300   */
1107836SJohn.Forte@Sun.COM static char	qlgc2312[] = "ISP2312";		/* product name for 2312   */
1117836SJohn.Forte@Sun.COM /*
1127836SJohn.Forte@Sun.COM  * The variable qlgc2200Sbus represents the string which is always the
1137836SJohn.Forte@Sun.COM  * starting string of the version information in an ISP2200 Sbus Fcode.
1147836SJohn.Forte@Sun.COM  */
1157836SJohn.Forte@Sun.COM static char	qlgc2200Sbus[] = "ISP2200 Sbus FC-AL Host Adapter Driver";
1167836SJohn.Forte@Sun.COM static char	pcibus_list[HBA_MAX][PATH_MAX];
1177836SJohn.Forte@Sun.COM /*	Internal functions	*/
1187836SJohn.Forte@Sun.COM static int	q_load_file(int, char *);
1197836SJohn.Forte@Sun.COM static int	q_getbootdev(uchar_t *);
1207836SJohn.Forte@Sun.COM static int	q_getdevctlpath(char *, int *);
1217836SJohn.Forte@Sun.COM static int	q_warn(int);
1227836SJohn.Forte@Sun.COM static int	q_findversion(int, int, uchar_t *, uint16_t *);
123*8538SReed.Liu@Sun.COM static int	q_findfileversion(char *, uchar_t *, uint16_t *, int, int *);
124*8538SReed.Liu@Sun.COM static int	q_findSbusfile(int, int *);
1257836SJohn.Forte@Sun.COM static int	memstrstr(char *, char *, int, int);
1267836SJohn.Forte@Sun.COM static int	fcode_load_file(int, char *, int *);
1277836SJohn.Forte@Sun.COM 
1287836SJohn.Forte@Sun.COM /*
1297836SJohn.Forte@Sun.COM  * Functions to support Fcode download for Emulex HBAs
1307836SJohn.Forte@Sun.COM  */
1317836SJohn.Forte@Sun.COM static int	emulex_fcodeversion(di_node_t, uchar_t *);
1327836SJohn.Forte@Sun.COM static void	handle_emulex_error(int, char *);
1337836SJohn.Forte@Sun.COM 
1347836SJohn.Forte@Sun.COM /*
135*8538SReed.Liu@Sun.COM  * Searches for and updates the cards.	This is the "main" function
1367836SJohn.Forte@Sun.COM  * and will give the output to the user by calling the subfunctions.
1377836SJohn.Forte@Sun.COM  * args: FCode file; if NULL only the current FCode version is printed
1387836SJohn.Forte@Sun.COM  */
1397836SJohn.Forte@Sun.COM int
q_qlgc_update(unsigned int verbose,char * file)1407836SJohn.Forte@Sun.COM q_qlgc_update(unsigned int verbose, char *file)
1417836SJohn.Forte@Sun.COM /*ARGSUSED*/
1427836SJohn.Forte@Sun.COM {
1437836SJohn.Forte@Sun.COM 	int fd, fcode_fd = -1, errnum = 0, devcnt = 0, retval = 0, isSbus = 0;
1447836SJohn.Forte@Sun.COM 	int sbus_off;
1457836SJohn.Forte@Sun.COM 	uint_t i, fflag = 0;
1467836SJohn.Forte@Sun.COM 	uint16_t chip_id = 0, file_id = 0;
1477836SJohn.Forte@Sun.COM 	uchar_t fcode_buf[FCODE_HDR];
1487836SJohn.Forte@Sun.COM 	static uchar_t	bootpath[PATH_MAX];
1497836SJohn.Forte@Sun.COM 	static uchar_t	version[MAXNAMELEN], version_file[MAXNAMELEN];
1507836SJohn.Forte@Sun.COM 	char devpath[PATH_MAX], tmppath[PATH_MAX];
1517836SJohn.Forte@Sun.COM 	void	(*sigint)(); /* to store default SIGTERM setting */
1527836SJohn.Forte@Sun.COM 	static struct	utmpx *utmpp = NULL; /* pointer for getutxent() */
1537836SJohn.Forte@Sun.COM 	char *ptr1, *ptr2;
1547836SJohn.Forte@Sun.COM 	char phys_path[PATH_MAX];
1557836SJohn.Forte@Sun.COM 	/*
1567836SJohn.Forte@Sun.COM 	 * The variables port1 and port2 are used to store the bus id
1577836SJohn.Forte@Sun.COM 	 * e.g. the bus id for this path:
1587836SJohn.Forte@Sun.COM 	 * /devices/sbus@12,0/SUNW,qlc@2,30000/fp@0,0:devctl
1597836SJohn.Forte@Sun.COM 	 * is "sbus@12". They are initialized to a random value and are
1607836SJohn.Forte@Sun.COM 	 * set such that they are not equal initially.
1617836SJohn.Forte@Sun.COM 	 */
1627836SJohn.Forte@Sun.COM 	static char port1[MAXNAMELEN] = {NULL};
1637836SJohn.Forte@Sun.COM 	static char port2[MAXNAMELEN] = {NULL};
1647836SJohn.Forte@Sun.COM 
1657836SJohn.Forte@Sun.COM 	if (file) {
1667836SJohn.Forte@Sun.COM 		fflag++;
1677836SJohn.Forte@Sun.COM 
1687836SJohn.Forte@Sun.COM 		/* check for a valid file */
1697836SJohn.Forte@Sun.COM 		if ((fcode_fd = open(file, O_RDONLY)) < 0) {
1707836SJohn.Forte@Sun.COM 			(void) fprintf(stderr,
1717836SJohn.Forte@Sun.COM 			    MSGSTR(21000, "Error: Could not open %s\n"), file);
1727836SJohn.Forte@Sun.COM 			return (1);
1737836SJohn.Forte@Sun.COM 		}
1747836SJohn.Forte@Sun.COM 		if (read(fcode_fd, fcode_buf, FCODE_HDR) != FCODE_HDR) {
1757836SJohn.Forte@Sun.COM 			perror(MSGSTR(21001, "read"));
1767836SJohn.Forte@Sun.COM 			(void) close(fcode_fd);
1777836SJohn.Forte@Sun.COM 			return (1);
1787836SJohn.Forte@Sun.COM 		}
1797836SJohn.Forte@Sun.COM 
1807836SJohn.Forte@Sun.COM 		/*
1817836SJohn.Forte@Sun.COM 		 * Check if it's SBUS FCode by calling q_findSbusfile
1827836SJohn.Forte@Sun.COM 		 * if it is then isSbus will be 1, if not it will be 0
1837836SJohn.Forte@Sun.COM 		 * in case of an error, it will be -1
1847836SJohn.Forte@Sun.COM 		 */
1857836SJohn.Forte@Sun.COM 		isSbus = q_findSbusfile(fcode_fd, &sbus_off);
1867836SJohn.Forte@Sun.COM 		if (isSbus == -1) {
1877836SJohn.Forte@Sun.COM 			(void) close(fcode_fd);
1887836SJohn.Forte@Sun.COM 			return (1);
1897836SJohn.Forte@Sun.COM 		}
1907836SJohn.Forte@Sun.COM 
1917836SJohn.Forte@Sun.COM 		/*
1927836SJohn.Forte@Sun.COM 		 * FCode header check - make sure it's PCI FCode
1937836SJohn.Forte@Sun.COM 		 * Structure of FCode header (byte# refers to byte numbering
1947836SJohn.Forte@Sun.COM 		 * in FCode spec, not the byte# of our fcode_buf buffer):
195*8538SReed.Liu@Sun.COM 		 * header	byte 00	   0x55	 prom signature byte one
196*8538SReed.Liu@Sun.COM 		 *		byte 01	   0xaa	 prom signature byte two
1977836SJohn.Forte@Sun.COM 		 * data		byte 00-03 P C I R
1987836SJohn.Forte@Sun.COM 		 * OR
199*8538SReed.Liu@Sun.COM 		 * header	byte 32	   0x55
200*8538SReed.Liu@Sun.COM 		 *		byte 33	   0xaa
2017836SJohn.Forte@Sun.COM 		 * data		byte 60-63 P C I R
2027836SJohn.Forte@Sun.COM 		 * The second format with an offset of 32 is used for ifp prom
2037836SJohn.Forte@Sun.COM 		 */
2047836SJohn.Forte@Sun.COM 		if (!(((fcode_buf[0x00] == 0x55) &&
2057836SJohn.Forte@Sun.COM 		    (fcode_buf[0x01] == 0xaa) &&
2067836SJohn.Forte@Sun.COM 		    (fcode_buf[0x1c] == 'P') &&
2077836SJohn.Forte@Sun.COM 		    (fcode_buf[0x1d] == 'C') &&
2087836SJohn.Forte@Sun.COM 		    (fcode_buf[0x1e] == 'I') &&
2097836SJohn.Forte@Sun.COM 		    (fcode_buf[0x1f] == 'R')) ||
2107836SJohn.Forte@Sun.COM 
2117836SJohn.Forte@Sun.COM 		    ((fcode_buf[0x20] == 0x55) &&
2127836SJohn.Forte@Sun.COM 		    (fcode_buf[0x21] == 0xaa) &&
2137836SJohn.Forte@Sun.COM 		    (fcode_buf[0x3c] == 'P') &&
2147836SJohn.Forte@Sun.COM 		    (fcode_buf[0x3d] == 'C') &&
2157836SJohn.Forte@Sun.COM 		    (fcode_buf[0x3e] == 'I') &&
2167836SJohn.Forte@Sun.COM 		    (fcode_buf[0x3f] == 'R')) ||
2177836SJohn.Forte@Sun.COM 
2187836SJohn.Forte@Sun.COM 		    (isSbus))) {
2197836SJohn.Forte@Sun.COM 			(void) fprintf(stderr, MSGSTR(21002,
2207836SJohn.Forte@Sun.COM 			    "Error: %s is not a valid FC100/P, "
2217836SJohn.Forte@Sun.COM 			    "ISP2200, ISP23xx FCode file.\n"),
2227836SJohn.Forte@Sun.COM 			    file);
2237836SJohn.Forte@Sun.COM 			(void) close(fcode_fd);
2247836SJohn.Forte@Sun.COM 			return (1);
2257836SJohn.Forte@Sun.COM 		}
2267836SJohn.Forte@Sun.COM 
2277836SJohn.Forte@Sun.COM 		/* check for single user mode */
2287836SJohn.Forte@Sun.COM 		while ((utmpp = getutxent()) != NULL) {
2297836SJohn.Forte@Sun.COM 			if (strstr(utmpp->ut_line, "run-level") &&
2307836SJohn.Forte@Sun.COM 			    (strcmp(utmpp->ut_line, "run-level S") &&
2317836SJohn.Forte@Sun.COM 				strcmp(utmpp->ut_line, "run-level 1"))) {
2327836SJohn.Forte@Sun.COM 				if (q_warn(1)) {
2337836SJohn.Forte@Sun.COM 					(void) endutxent();
2347836SJohn.Forte@Sun.COM 					(void) close(fcode_fd);
2357836SJohn.Forte@Sun.COM 					return (1);
2367836SJohn.Forte@Sun.COM 				}
2377836SJohn.Forte@Sun.COM 				break;
2387836SJohn.Forte@Sun.COM 			}
2397836SJohn.Forte@Sun.COM 		}
2407836SJohn.Forte@Sun.COM 		(void) endutxent();
2417836SJohn.Forte@Sun.COM 
2427836SJohn.Forte@Sun.COM 		/* get bootpath */
2437836SJohn.Forte@Sun.COM 		if (!q_getbootdev((uchar_t *)&bootpath[0]) &&
2447836SJohn.Forte@Sun.COM 		    getenv("_LUX_D_DEBUG") != NULL) {
2457836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "  Bootpath: %s\n", bootpath);
2467836SJohn.Forte@Sun.COM 		}
2477836SJohn.Forte@Sun.COM 	}
2487836SJohn.Forte@Sun.COM 	/*
2497836SJohn.Forte@Sun.COM 	 * Get count of, and names of PCI slots with ifp device control
2507836SJohn.Forte@Sun.COM 	 * (devctl) nodes.  Search /devices.
2517836SJohn.Forte@Sun.COM 	 */
2527836SJohn.Forte@Sun.COM 	(void) strcpy(devpath, "/devices");
2537836SJohn.Forte@Sun.COM 	if (q_getdevctlpath(devpath, (int *)&devcnt) == 0) {
2547836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, MSGSTR(21003,
2557836SJohn.Forte@Sun.COM 		"\n  Found Path to %d FC100/P, ISP2200, ISP23xx Devices\n"),
2567836SJohn.Forte@Sun.COM 			devcnt);
2577836SJohn.Forte@Sun.COM 	} else {
2587836SJohn.Forte@Sun.COM 		(void) fprintf(stderr, MSGSTR(21004,
2597836SJohn.Forte@Sun.COM 		"Error: Could not get /devices path to FC100/P,"
2607836SJohn.Forte@Sun.COM 		"ISP2200, ISP23xx Cards.\n"));
2617836SJohn.Forte@Sun.COM 		retval++;
2627836SJohn.Forte@Sun.COM 	}
2637836SJohn.Forte@Sun.COM 
2647836SJohn.Forte@Sun.COM 	for (i = 0; i < devcnt; i++) {
2657836SJohn.Forte@Sun.COM 
2667836SJohn.Forte@Sun.COM 		(void) strncpy((char *)phys_path, &pcibus_list[i][0],
2677836SJohn.Forte@Sun.COM 				strlen(&pcibus_list[i][0]));
2687836SJohn.Forte@Sun.COM 		if (fflag && (strstr((char *)bootpath,
2697836SJohn.Forte@Sun.COM 		    strtok((char *)phys_path, ":")) != NULL)) {
2707836SJohn.Forte@Sun.COM 			(void) fprintf(stderr,
2717836SJohn.Forte@Sun.COM 			    MSGSTR(21005, "Ignoring %s (bootpath)\n"),
2727836SJohn.Forte@Sun.COM 			    &pcibus_list[i][0]);
2737836SJohn.Forte@Sun.COM 			continue;
2747836SJohn.Forte@Sun.COM 		}
2757836SJohn.Forte@Sun.COM 
2767836SJohn.Forte@Sun.COM 		(void) fprintf(stdout,
2777836SJohn.Forte@Sun.COM 		MSGSTR(21006, "\n  Opening Device: %s\n"), &pcibus_list[i][0]);
2787836SJohn.Forte@Sun.COM 		/* Check if the device is valid */
2797836SJohn.Forte@Sun.COM 		if ((fd = open(&pcibus_list[i][0], O_RDWR)) < 0) {
2807836SJohn.Forte@Sun.COM 			(void) fprintf(stderr,
2817836SJohn.Forte@Sun.COM 			    MSGSTR(21000, "Error: Could not open %s\n"),
2827836SJohn.Forte@Sun.COM 			    &pcibus_list[i][0]);
2837836SJohn.Forte@Sun.COM 			retval++;
2847836SJohn.Forte@Sun.COM 			continue;
2857836SJohn.Forte@Sun.COM 		}
2867836SJohn.Forte@Sun.COM 		(void) close(fd);
2877836SJohn.Forte@Sun.COM 		/*
2887836SJohn.Forte@Sun.COM 		 * Check FCode version present on the adapter (at last boot)
2897836SJohn.Forte@Sun.COM 		 */
2907836SJohn.Forte@Sun.COM 		if (q_findversion(verbose, i, (uchar_t *)&version[0],
2917836SJohn.Forte@Sun.COM 		    &chip_id) == 0) {
2927836SJohn.Forte@Sun.COM 			if (strlen((char *)version) == 0) {
2937836SJohn.Forte@Sun.COM 				(void) fprintf(stdout, MSGSTR(21007,
2947836SJohn.Forte@Sun.COM 	"  Detected FCode Version:\tNo version available for this FCode\n"));
2957836SJohn.Forte@Sun.COM 			} else {
2967836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, MSGSTR(21008,
2977836SJohn.Forte@Sun.COM 			    "  Detected FCode Version:\t%s\n"), version);
2987836SJohn.Forte@Sun.COM 			}
2997836SJohn.Forte@Sun.COM 		} else {
3007836SJohn.Forte@Sun.COM 			chip_id = 0x0;
3017836SJohn.Forte@Sun.COM 		}
3027836SJohn.Forte@Sun.COM 
3037836SJohn.Forte@Sun.COM 		if (fflag) {
3047836SJohn.Forte@Sun.COM 			/*
3057836SJohn.Forte@Sun.COM 			 * For ISP2200, Sbus HBA, do just 1 download
3067836SJohn.Forte@Sun.COM 			 * for both the ports (dual port HBA)
3077836SJohn.Forte@Sun.COM 			 * Here it is assumed that readdir() always
3087836SJohn.Forte@Sun.COM 			 * returns the paths in pcibus_list[] in the
3097836SJohn.Forte@Sun.COM 			 * sorted order.
3107836SJohn.Forte@Sun.COM 			 */
3117836SJohn.Forte@Sun.COM 			(void) strcpy(tmppath, pcibus_list[i]);
3127836SJohn.Forte@Sun.COM 			if (ptr1 = strstr(tmppath, IVORY_BUS)) {
3137836SJohn.Forte@Sun.COM 				if (ptr2 = strstr(ptr1, IVORY_DRVR)) {
3147836SJohn.Forte@Sun.COM 					ptr2 = strchr(ptr2, ',');
3157836SJohn.Forte@Sun.COM 					if (ptr2 = strchr(++ptr2, ',')) {
3167836SJohn.Forte@Sun.COM 						*ptr2 = '\0';
3177836SJohn.Forte@Sun.COM 					}
3187836SJohn.Forte@Sun.COM 				}
3197836SJohn.Forte@Sun.COM 				(void) strcpy(port2, ptr1);
3207836SJohn.Forte@Sun.COM 				if (strcmp(port1, port2) == 0) {
3217836SJohn.Forte@Sun.COM 				    (void) fprintf(stdout, MSGSTR(21037,
3227836SJohn.Forte@Sun.COM 				    "/n New FCode has already been downloaded "
3237836SJohn.Forte@Sun.COM 				    "to this ISP2200 SBus HBA Card.\n"
3247836SJohn.Forte@Sun.COM 				    "It is sufficient to download to one "
3257836SJohn.Forte@Sun.COM 				    "port of the ISP2200 SBus HBA Card. "
3267836SJohn.Forte@Sun.COM 				    "Moving on...\n"));
3277836SJohn.Forte@Sun.COM 					continue;
3287836SJohn.Forte@Sun.COM 				}
3297836SJohn.Forte@Sun.COM 			}
3307836SJohn.Forte@Sun.COM 			/*
3317836SJohn.Forte@Sun.COM 			 * Check version of the supplied FCode file (once)
3327836SJohn.Forte@Sun.COM 			 */
3337836SJohn.Forte@Sun.COM 			if ((file_id != 0 && version_file != NULL) ||
3347836SJohn.Forte@Sun.COM 			    (q_findfileversion((char *)
3357836SJohn.Forte@Sun.COM 			    &fcode_buf[0], (uchar_t *)&version_file[0],
3367836SJohn.Forte@Sun.COM 			    &file_id, isSbus, &sbus_off) == 0)) {
3377836SJohn.Forte@Sun.COM 				(void) fprintf(stdout, MSGSTR(21009,
3387836SJohn.Forte@Sun.COM 				    "  New FCode Version:\t\t%s\n"),
3397836SJohn.Forte@Sun.COM 				    version_file);
3407836SJohn.Forte@Sun.COM 			} else {
3417836SJohn.Forte@Sun.COM 				(void) close(fcode_fd);
3427836SJohn.Forte@Sun.COM 				return (1);
3437836SJohn.Forte@Sun.COM 			}
3447836SJohn.Forte@Sun.COM 
3457836SJohn.Forte@Sun.COM 			/*
3467836SJohn.Forte@Sun.COM 			 * Load the New FCode
3477836SJohn.Forte@Sun.COM 			 * Give warning if file doesn't appear to be correct
3487836SJohn.Forte@Sun.COM 			 *
3497836SJohn.Forte@Sun.COM 			 */
3507836SJohn.Forte@Sun.COM 			if (chip_id == 0) {
3517836SJohn.Forte@Sun.COM 				errnum = 2; /* can't get chip_id */
3527836SJohn.Forte@Sun.COM 				retval++;
3537836SJohn.Forte@Sun.COM 			} else if (chip_id - file_id != 0) {
3547836SJohn.Forte@Sun.COM 				errnum = 3; /* file/card mismatch */
3557836SJohn.Forte@Sun.COM 				retval++;
3567836SJohn.Forte@Sun.COM 			} else {
3577836SJohn.Forte@Sun.COM 				errnum = 0; /* everything is ok */
3587836SJohn.Forte@Sun.COM 			}
3597836SJohn.Forte@Sun.COM 
3607836SJohn.Forte@Sun.COM 			if (!q_warn(errnum)) {
3617836SJohn.Forte@Sun.COM 				/* Disable user-interrupt Control-C */
3627836SJohn.Forte@Sun.COM 				sigint =
3637836SJohn.Forte@Sun.COM 				    (void (*)(int)) signal(SIGINT, SIG_IGN);
3647836SJohn.Forte@Sun.COM 
3657836SJohn.Forte@Sun.COM 				/* Load FCode */
3667836SJohn.Forte@Sun.COM 				(void) fprintf(stdout, MSGSTR(21010,
3677836SJohn.Forte@Sun.COM 				    "  Loading FCode: %s\n"), file);
3687836SJohn.Forte@Sun.COM 
3697836SJohn.Forte@Sun.COM 				if (q_load_file(fcode_fd,
3707836SJohn.Forte@Sun.COM 				    &pcibus_list[i][0]) == 0) {
3717836SJohn.Forte@Sun.COM 					(void) fprintf(stdout, MSGSTR(21011,
3727836SJohn.Forte@Sun.COM 					"  Successful FCode download: %s\n"),
3737836SJohn.Forte@Sun.COM 					    &pcibus_list[i][0]);
3747836SJohn.Forte@Sun.COM 					(void) strcpy(port1, port2);
3757836SJohn.Forte@Sun.COM 				} else {
3767836SJohn.Forte@Sun.COM 					(void) fprintf(stderr, MSGSTR(21012,
3777836SJohn.Forte@Sun.COM 					"Error: FCode download failed: %s\n"),
3787836SJohn.Forte@Sun.COM 							&pcibus_list[i][0]);
3797836SJohn.Forte@Sun.COM 					retval++;
3807836SJohn.Forte@Sun.COM 				}
3817836SJohn.Forte@Sun.COM 				/* Restore SIGINT (user interrupt) setting */
3827836SJohn.Forte@Sun.COM 				(void) signal(SIGINT, sigint);
3837836SJohn.Forte@Sun.COM 			}
3847836SJohn.Forte@Sun.COM 		}
3857836SJohn.Forte@Sun.COM 	}
3867836SJohn.Forte@Sun.COM 	(void) fprintf(stdout, "  ");
3877836SJohn.Forte@Sun.COM 	(void) fprintf(stdout, MSGSTR(125, "Complete\n"));
3887836SJohn.Forte@Sun.COM 	if (fcode_fd != -1)
3897836SJohn.Forte@Sun.COM 		(void) close(fcode_fd);
3907836SJohn.Forte@Sun.COM 	return (retval);
3917836SJohn.Forte@Sun.COM }
3927836SJohn.Forte@Sun.COM 
3937836SJohn.Forte@Sun.COM 
3947836SJohn.Forte@Sun.COM /*
3957836SJohn.Forte@Sun.COM  * Retrieve the version banner from the card
396*8538SReed.Liu@Sun.COM  *    uses ioctl: FCIO_FCODE_MCODE_VERSION	FCode revision
3977836SJohn.Forte@Sun.COM  */
3987836SJohn.Forte@Sun.COM static int
q_findversion(int verbose,int index,uchar_t * version,uint16_t * chip_id)3997836SJohn.Forte@Sun.COM q_findversion(int verbose, int index, uchar_t *version, uint16_t *chip_id)
4007836SJohn.Forte@Sun.COM /*ARGSUSED*/
4017836SJohn.Forte@Sun.COM {
4027836SJohn.Forte@Sun.COM 	int fd, ntries;
403*8538SReed.Liu@Sun.COM 	struct	ifp_fm_version *version_buffer = NULL;
4047836SJohn.Forte@Sun.COM 	char	prom_ver[100] = {NULL};
4057836SJohn.Forte@Sun.COM 	char	mcode_ver[100] = {NULL};
4067836SJohn.Forte@Sun.COM 	fcio_t	fcio;
4077836SJohn.Forte@Sun.COM 
4087836SJohn.Forte@Sun.COM 	if (strstr(&pcibus_list[index][0], fc_trans)) {
4097836SJohn.Forte@Sun.COM 
4107836SJohn.Forte@Sun.COM 	if ((fd = open(&pcibus_list[index][0], O_RDWR)) < 0) {
4117836SJohn.Forte@Sun.COM 		(void) fprintf(stderr,
4127836SJohn.Forte@Sun.COM 		    MSGSTR(21000, "Error: Could not open %s\n"),
4137836SJohn.Forte@Sun.COM 		    &pcibus_list[index][0]);
4147836SJohn.Forte@Sun.COM 		return (1);
4157836SJohn.Forte@Sun.COM 	}
4167836SJohn.Forte@Sun.COM 
4177836SJohn.Forte@Sun.COM 	if ((version_buffer = (struct ifp_fm_version *)malloc(
4187836SJohn.Forte@Sun.COM 		sizeof (struct ifp_fm_version))) == NULL) {
4197836SJohn.Forte@Sun.COM 		(void) fprintf(stderr,
4207836SJohn.Forte@Sun.COM 		    MSGSTR(21013, "Error: Memory allocation failed\n"));
4217836SJohn.Forte@Sun.COM 		(void) close(fd);
4227836SJohn.Forte@Sun.COM 		return (1);
4237836SJohn.Forte@Sun.COM 	}
4247836SJohn.Forte@Sun.COM 
4257836SJohn.Forte@Sun.COM 	version_buffer->fcode_ver = (char *)version;
4267836SJohn.Forte@Sun.COM 	version_buffer->mcode_ver = mcode_ver;
4277836SJohn.Forte@Sun.COM 	version_buffer->prom_ver = prom_ver;
4287836SJohn.Forte@Sun.COM 	version_buffer->fcode_ver_len = MAXNAMELEN - 1;
4297836SJohn.Forte@Sun.COM 	version_buffer->mcode_ver_len = 100;
4307836SJohn.Forte@Sun.COM 	version_buffer->prom_ver_len = 100;
4317836SJohn.Forte@Sun.COM 
4327836SJohn.Forte@Sun.COM 	if (ioctl(fd, FCIO_FCODE_MCODE_VERSION, version_buffer) < 0) {
4337836SJohn.Forte@Sun.COM 		(void) fprintf(stderr, MSGSTR(21014,
4347836SJohn.Forte@Sun.COM 		"Error: Driver interface FCIO_FCODE_MCODE_VERSION failed\n"));
4357836SJohn.Forte@Sun.COM 		free(version_buffer);
4367836SJohn.Forte@Sun.COM 		(void) close(fd);
4377836SJohn.Forte@Sun.COM 		return (1);
4387836SJohn.Forte@Sun.COM 	}
4397836SJohn.Forte@Sun.COM 	version[version_buffer->fcode_ver_len] = '\0';
4407836SJohn.Forte@Sun.COM 
4417836SJohn.Forte@Sun.COM 	/* Need a way to get card MCODE (firmware) to track certain HW bugs */
4427836SJohn.Forte@Sun.COM 	if (getenv("_LUX_D_DEBUG") != NULL) {
4437836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "  Device %i: QLGC chip_id %x\n",
4447836SJohn.Forte@Sun.COM 		    index+1, *chip_id);
4457836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "  FCode:%s\n  MCODE:%s\n  PROM:%s\n",
4467836SJohn.Forte@Sun.COM 		    (char *)version, mcode_ver, prom_ver);
4477836SJohn.Forte@Sun.COM 	}
4487836SJohn.Forte@Sun.COM 	free(version_buffer);
4497836SJohn.Forte@Sun.COM 
4507836SJohn.Forte@Sun.COM 	} else if (strstr(&pcibus_list[index][0], fp_trans)) {
4517836SJohn.Forte@Sun.COM 		/*
4527836SJohn.Forte@Sun.COM 		 * Get the fcode and prom's fw version
4537836SJohn.Forte@Sun.COM 		 * using the fp ioctls. Currently, we pass
4547836SJohn.Forte@Sun.COM 		 * only the fcode version to the calling function
4557836SJohn.Forte@Sun.COM 		 * and ignore the FW version (using the existing
4567836SJohn.Forte@Sun.COM 		 * implementation).
4577836SJohn.Forte@Sun.COM 		 */
4587836SJohn.Forte@Sun.COM 
4597836SJohn.Forte@Sun.COM 		if ((fd = open(&pcibus_list[index][0], O_RDWR)) < 0) {
4607836SJohn.Forte@Sun.COM 			(void) fprintf(stderr,
4617836SJohn.Forte@Sun.COM 			    MSGSTR(4511, "Could not open %s\n"),
4627836SJohn.Forte@Sun.COM 			    &pcibus_list[index][0]);
4637836SJohn.Forte@Sun.COM 			(void) close(fd);
4647836SJohn.Forte@Sun.COM 			return (1);
4657836SJohn.Forte@Sun.COM 		}
4667836SJohn.Forte@Sun.COM 		/* Get the fcode version */
4677836SJohn.Forte@Sun.COM 		bzero(version, sizeof (version));
4687836SJohn.Forte@Sun.COM 		fcio.fcio_cmd = FCIO_GET_FCODE_REV;
4697836SJohn.Forte@Sun.COM 		/* Information read operation */
4707836SJohn.Forte@Sun.COM 		fcio.fcio_xfer = FCIO_XFER_READ;
4717836SJohn.Forte@Sun.COM 		fcio.fcio_obuf = (caddr_t)version;
4727836SJohn.Forte@Sun.COM 		fcio.fcio_olen = MAXNAMELEN;
4737836SJohn.Forte@Sun.COM 
4747836SJohn.Forte@Sun.COM 		for (ntries = 0; ntries < MAX_RETRIES; ntries++) {
4757836SJohn.Forte@Sun.COM 			if (ioctl(fd, FCIO_CMD, &fcio) != 0) {
4767836SJohn.Forte@Sun.COM 				if ((errno == EAGAIN) &&
4777836SJohn.Forte@Sun.COM 				    (ntries+1 < MAX_RETRIES)) {
4787836SJohn.Forte@Sun.COM 					/* wait 30 secs */
4797836SJohn.Forte@Sun.COM 					(void) sleep(MAX_WAIT_TIME);
4807836SJohn.Forte@Sun.COM 					continue;
4817836SJohn.Forte@Sun.COM 				}
4827836SJohn.Forte@Sun.COM 				(void) close(fd);
4837836SJohn.Forte@Sun.COM 				return (L_FCIO_GET_FCODE_REV_FAIL);
4847836SJohn.Forte@Sun.COM 			}
4857836SJohn.Forte@Sun.COM 			break;
4867836SJohn.Forte@Sun.COM 		}
4877836SJohn.Forte@Sun.COM 		version[MAXNAMELEN-1] = '\0';
4887836SJohn.Forte@Sun.COM 	}
4897836SJohn.Forte@Sun.COM 
4907836SJohn.Forte@Sun.COM 	/* Get type of card from product name in FCode version banner */
4917836SJohn.Forte@Sun.COM 	if (strstr((char *)version, qlgc2100)) {
4927836SJohn.Forte@Sun.COM 		*chip_id = 0x2100;
4937836SJohn.Forte@Sun.COM 	} else if (strstr((char *)version, qlgc2200)) {
4947836SJohn.Forte@Sun.COM 		*chip_id = 0x2200;
4957836SJohn.Forte@Sun.COM 		if (strstr((char *)version, "Sbus")) {
4967836SJohn.Forte@Sun.COM 			*chip_id = SBUS_CHIP_ID;
4977836SJohn.Forte@Sun.COM 		}
4987836SJohn.Forte@Sun.COM 	} else if (strstr((char *)version, qlgc2300)) {
4997836SJohn.Forte@Sun.COM 		*chip_id = 0x2300;
5007836SJohn.Forte@Sun.COM 	} else if (strstr((char *)version, qlgc2312)) {
5017836SJohn.Forte@Sun.COM 		*chip_id = 0x2312;
5027836SJohn.Forte@Sun.COM 	} else {
5037836SJohn.Forte@Sun.COM 		*chip_id = 0x0;
5047836SJohn.Forte@Sun.COM 	}
5057836SJohn.Forte@Sun.COM 
5067836SJohn.Forte@Sun.COM 	(void) close(fd);
5077836SJohn.Forte@Sun.COM 	return (0);
5087836SJohn.Forte@Sun.COM }
5097836SJohn.Forte@Sun.COM 
5107836SJohn.Forte@Sun.COM /*
5117836SJohn.Forte@Sun.COM  * Retrieve the version banner and file type (2100 or 2200) from the file
5127836SJohn.Forte@Sun.COM  */
5137836SJohn.Forte@Sun.COM static int
q_findfileversion(char * dl_fcode,uchar_t * version_file,uint16_t * file_id,int isSbus,int * sbus_offset)5147836SJohn.Forte@Sun.COM q_findfileversion(char *dl_fcode, uchar_t *version_file, uint16_t *file_id,
5157836SJohn.Forte@Sun.COM 		    int isSbus, int *sbus_offset)
5167836SJohn.Forte@Sun.COM {
5177836SJohn.Forte@Sun.COM 	int mark;
5187836SJohn.Forte@Sun.COM 	int qlc_offset = 0;
5197836SJohn.Forte@Sun.COM 	char temp[4] = {NULL};
5207836SJohn.Forte@Sun.COM 
5217836SJohn.Forte@Sun.COM 
5227836SJohn.Forte@Sun.COM 	/*
5237836SJohn.Forte@Sun.COM 	 * Get file version from FCode for 2100 or 2202
5247836SJohn.Forte@Sun.COM 	 */
5257836SJohn.Forte@Sun.COM 	if (isSbus) {
5267836SJohn.Forte@Sun.COM 		*file_id = SBUS_CHIP_ID;
5277836SJohn.Forte@Sun.COM 	} else {
5287836SJohn.Forte@Sun.COM 		if ((dl_fcode[0x23] == 0x22) ||
5297836SJohn.Forte@Sun.COM 		    (dl_fcode[0x23] == 0x23)) {
5307836SJohn.Forte@Sun.COM 			*file_id = dl_fcode[0x22] & 0xff;
5317836SJohn.Forte@Sun.COM 			*file_id |= (dl_fcode[0x23] << 8) & 0xff00;
5327836SJohn.Forte@Sun.COM 		} else {
5337836SJohn.Forte@Sun.COM 			*file_id = dl_fcode[0x42] & 0xff;
5347836SJohn.Forte@Sun.COM 			*file_id |= (dl_fcode[0x43] << 8) & 0xff00;
5357836SJohn.Forte@Sun.COM 		}
5367836SJohn.Forte@Sun.COM 	}
5377836SJohn.Forte@Sun.COM 
5387836SJohn.Forte@Sun.COM 	/*
5397836SJohn.Forte@Sun.COM 	 * Ok, we're just checking for 2200 here. If it is we need
5407836SJohn.Forte@Sun.COM 	 * to offset to find the banner.
5417836SJohn.Forte@Sun.COM 	 */
5427836SJohn.Forte@Sun.COM 	if ((*file_id == 0x2200) ||
5437836SJohn.Forte@Sun.COM 	    (*file_id == 0x2300) ||
5447836SJohn.Forte@Sun.COM 	    (*file_id == 0x2312)) {
5457836SJohn.Forte@Sun.COM 		qlc_offset = -32;
5467836SJohn.Forte@Sun.COM 	}
5477836SJohn.Forte@Sun.COM 
5487836SJohn.Forte@Sun.COM 	/*
5497836SJohn.Forte@Sun.COM 	 * If this is an ISP2200 Sbus Fcode file, then search for the string
5507836SJohn.Forte@Sun.COM 	 * "ISP2200 FC-AL Host Adapter Driver" in the whole fcode file
5517836SJohn.Forte@Sun.COM 	 */
5527836SJohn.Forte@Sun.COM 	if (isSbus) {
5537836SJohn.Forte@Sun.COM 		*file_id = SBUS_CHIP_ID;
5547836SJohn.Forte@Sun.COM 		qlc_offset = *sbus_offset;
5557836SJohn.Forte@Sun.COM 		/* Subtract 111 from the offset we add below for PCI Fcodes */
5567836SJohn.Forte@Sun.COM 		qlc_offset -= 111;
5577836SJohn.Forte@Sun.COM 	}
5587836SJohn.Forte@Sun.COM 
5597836SJohn.Forte@Sun.COM 	/* Banner length varies; grab banner to end of date marker yr/mo/da */
5607836SJohn.Forte@Sun.COM 	version_file[0] = '\0';
5617836SJohn.Forte@Sun.COM 	for (mark = (111 + qlc_offset); mark < (191 + qlc_offset); mark++) {
5627836SJohn.Forte@Sun.COM 		(void) strncpy(temp, (char *)&dl_fcode[mark], 4);
5637836SJohn.Forte@Sun.COM 		if ((strncmp(&temp[0], "/", 1) == 0) &&
5647836SJohn.Forte@Sun.COM 		    (strncmp(&temp[3], "/", 1) == 0)) {
5657836SJohn.Forte@Sun.COM 			(void) strncat((char *)version_file,
5667836SJohn.Forte@Sun.COM 			    (char *)&dl_fcode[mark], 6);
5677836SJohn.Forte@Sun.COM 			break;
5687836SJohn.Forte@Sun.COM 		}
5697836SJohn.Forte@Sun.COM 		(void) strncat((char *)version_file, temp, 1);
5707836SJohn.Forte@Sun.COM 	}
5717836SJohn.Forte@Sun.COM 	return (0);
5727836SJohn.Forte@Sun.COM }
5737836SJohn.Forte@Sun.COM 
5747836SJohn.Forte@Sun.COM /*
5757836SJohn.Forte@Sun.COM  * Find if the FCode file is a ISP2200 SBUS Fcode file
5767836SJohn.Forte@Sun.COM  */
5777836SJohn.Forte@Sun.COM static int
q_findSbusfile(int fd,int * sbus_offset)5787836SJohn.Forte@Sun.COM q_findSbusfile(int fd, int *sbus_offset)
5797836SJohn.Forte@Sun.COM {
5807836SJohn.Forte@Sun.COM 	static int file_size;
5817836SJohn.Forte@Sun.COM 	char *sbus_info;
5827836SJohn.Forte@Sun.COM 	struct stat statinfo;
5837836SJohn.Forte@Sun.COM 
5847836SJohn.Forte@Sun.COM 	if (lseek(fd, 0, SEEK_SET) == -1) {
5857836SJohn.Forte@Sun.COM 		perror(MSGSTR(21022, "seek"));
5867836SJohn.Forte@Sun.COM 		return (-1);
5877836SJohn.Forte@Sun.COM 	}
5887836SJohn.Forte@Sun.COM 	if (fstat(fd, &statinfo)) {
5897836SJohn.Forte@Sun.COM 		perror(MSGSTR(21023, "fstat"));
5907836SJohn.Forte@Sun.COM 		return (-1);
5917836SJohn.Forte@Sun.COM 	}
5927836SJohn.Forte@Sun.COM 	file_size = statinfo.st_size;
5937836SJohn.Forte@Sun.COM 
5947836SJohn.Forte@Sun.COM 	if ((sbus_info = (char *)malloc(file_size)) == NULL) {
5957836SJohn.Forte@Sun.COM 		(void) fprintf(stderr,
5967836SJohn.Forte@Sun.COM 		    MSGSTR(21013, "Error: Memory allocation failed\n"));
5977836SJohn.Forte@Sun.COM 		return (-1);
5987836SJohn.Forte@Sun.COM 	}
5997836SJohn.Forte@Sun.COM 
6007836SJohn.Forte@Sun.COM 	if (read(fd, sbus_info, file_size) < 0) {
6017836SJohn.Forte@Sun.COM 		perror(MSGSTR(21001, "read"));
6027836SJohn.Forte@Sun.COM 		free(sbus_info);
6037836SJohn.Forte@Sun.COM 		return (-1);
6047836SJohn.Forte@Sun.COM 	}
6057836SJohn.Forte@Sun.COM 
6067836SJohn.Forte@Sun.COM 	/*
6077836SJohn.Forte@Sun.COM 	 * Search for the version string in the whole file
6087836SJohn.Forte@Sun.COM 	 */
6097836SJohn.Forte@Sun.COM 	if ((*sbus_offset = memstrstr((char *)sbus_info, qlgc2200Sbus,
6107836SJohn.Forte@Sun.COM 			    file_size, strlen(qlgc2200Sbus))) != -1) {
6117836SJohn.Forte@Sun.COM 		free(sbus_info);
6127836SJohn.Forte@Sun.COM 		return (1);
6137836SJohn.Forte@Sun.COM 	} else {
6147836SJohn.Forte@Sun.COM 		free(sbus_info);
6157836SJohn.Forte@Sun.COM 		return (0);
6167836SJohn.Forte@Sun.COM 	}
6177836SJohn.Forte@Sun.COM }
6187836SJohn.Forte@Sun.COM 
6197836SJohn.Forte@Sun.COM 
6207836SJohn.Forte@Sun.COM /*
6217836SJohn.Forte@Sun.COM  * Build a list of all the devctl entries for all the 2100/2200 based adapters
6227836SJohn.Forte@Sun.COM  */
6237836SJohn.Forte@Sun.COM static int
q_getdevctlpath(char * devpath,int * devcnt)6247836SJohn.Forte@Sun.COM q_getdevctlpath(char *devpath, int *devcnt)
6257836SJohn.Forte@Sun.COM {
6267836SJohn.Forte@Sun.COM 	struct stat	statbuf;
6277836SJohn.Forte@Sun.COM 	struct dirent	*dirp = NULL;
6287836SJohn.Forte@Sun.COM 	DIR		*dp = NULL;
6297836SJohn.Forte@Sun.COM 	char		*ptr = NULL;
6308288SBing.Hu@Sun.COM 	int		err = 0;
6317836SJohn.Forte@Sun.COM 	int		testopen;
6327836SJohn.Forte@Sun.COM 
6337836SJohn.Forte@Sun.COM 	if (lstat(devpath, &statbuf) < 0) {
6347836SJohn.Forte@Sun.COM 		(void) fprintf(stderr,
6357836SJohn.Forte@Sun.COM 		    MSGSTR(21016, "Error: %s lstat() error\n"), devpath);
6367836SJohn.Forte@Sun.COM 		return (1);
6377836SJohn.Forte@Sun.COM 	}
6387836SJohn.Forte@Sun.COM 
6397836SJohn.Forte@Sun.COM 	if ((strstr(devpath, fc_trans) ||
6407836SJohn.Forte@Sun.COM 	    (strstr(devpath, fp_trans_id) && strstr(devpath, fp_trans))) &&
6417836SJohn.Forte@Sun.COM 	    strstr(devpath, "devctl")) {
6427836SJohn.Forte@Sun.COM 		/* Verify the path is valid */
6437836SJohn.Forte@Sun.COM 		if ((testopen = open(devpath, O_RDONLY)) >= 0) {
6447836SJohn.Forte@Sun.COM 			(void) close(testopen);
6457836SJohn.Forte@Sun.COM 			(void) strcpy(pcibus_list[*devcnt], devpath);
6467836SJohn.Forte@Sun.COM 			*devcnt += 1;
6477836SJohn.Forte@Sun.COM 			return (0);
6487836SJohn.Forte@Sun.COM 		}
6497836SJohn.Forte@Sun.COM 	}
6507836SJohn.Forte@Sun.COM 
6517836SJohn.Forte@Sun.COM 	if (S_ISDIR(statbuf.st_mode) == 0) {
6527836SJohn.Forte@Sun.COM 		/*
6537836SJohn.Forte@Sun.COM 		 * not a directory so
6547836SJohn.Forte@Sun.COM 		 * we don't care about it - return
6557836SJohn.Forte@Sun.COM 		 */
6567836SJohn.Forte@Sun.COM 		return (0);
6577836SJohn.Forte@Sun.COM 	}
6587836SJohn.Forte@Sun.COM 
6597836SJohn.Forte@Sun.COM 	/*
6607836SJohn.Forte@Sun.COM 	 * It's a directory. Call ourself to
6617836SJohn.Forte@Sun.COM 	 * traverse the path(s)
6627836SJohn.Forte@Sun.COM 	 */
6637836SJohn.Forte@Sun.COM 	ptr = devpath + strlen(devpath);
6647836SJohn.Forte@Sun.COM 	*ptr++ = '/';
6657836SJohn.Forte@Sun.COM 	*ptr = 0;
6667836SJohn.Forte@Sun.COM 
6677836SJohn.Forte@Sun.COM 	/* Forget the /devices/pseudo/ directory */
6687836SJohn.Forte@Sun.COM 	if (strcmp(devpath, "/devices/pseudo/") == 0) {
6697836SJohn.Forte@Sun.COM 		return (0);
6707836SJohn.Forte@Sun.COM 	}
6717836SJohn.Forte@Sun.COM 
6727836SJohn.Forte@Sun.COM 	if ((dp = opendir(devpath)) == NULL) {
6737836SJohn.Forte@Sun.COM 		(void) fprintf(stderr,
6747836SJohn.Forte@Sun.COM 		    MSGSTR(21017, "Error: %s Can't read directory\n"), devpath);
6757836SJohn.Forte@Sun.COM 		return (1);
6767836SJohn.Forte@Sun.COM 	}
6777836SJohn.Forte@Sun.COM 
6787836SJohn.Forte@Sun.COM 	while ((dirp = readdir(dp)) != NULL) {
6797836SJohn.Forte@Sun.COM 
6807836SJohn.Forte@Sun.COM 		if (strcmp(dirp->d_name, ".") == 0 ||
6817836SJohn.Forte@Sun.COM 		    strcmp(dirp->d_name, "..") == 0) {
6827836SJohn.Forte@Sun.COM 			continue;
6837836SJohn.Forte@Sun.COM 		}
6847836SJohn.Forte@Sun.COM 		(void) strcpy(ptr, dirp->d_name); /* append name */
6857836SJohn.Forte@Sun.COM 		err = q_getdevctlpath(devpath, devcnt);
6867836SJohn.Forte@Sun.COM 	}
6877836SJohn.Forte@Sun.COM 
6887836SJohn.Forte@Sun.COM 	if (closedir(dp) < 0) {
6897836SJohn.Forte@Sun.COM 		(void) fprintf(stderr,
6907836SJohn.Forte@Sun.COM 		MSGSTR(21018, "Error: Can't close directory %s\n"), devpath);
6917836SJohn.Forte@Sun.COM 		return (1);
6927836SJohn.Forte@Sun.COM 	}
6937836SJohn.Forte@Sun.COM 	return (err);
6947836SJohn.Forte@Sun.COM }
6957836SJohn.Forte@Sun.COM 
6967836SJohn.Forte@Sun.COM /*
697*8538SReed.Liu@Sun.COM  * Get the boot device.	 Cannot load FCode to current boot device.
6987836SJohn.Forte@Sun.COM  * Boot devices under volume management will prompt a warning.
6997836SJohn.Forte@Sun.COM  */
7007836SJohn.Forte@Sun.COM static int
q_getbootdev(uchar_t * bootpath)7017836SJohn.Forte@Sun.COM q_getbootdev(uchar_t *bootpath)
7027836SJohn.Forte@Sun.COM {
7037836SJohn.Forte@Sun.COM 	struct mnttab mp;
7047836SJohn.Forte@Sun.COM 	struct mnttab mpref;
7057836SJohn.Forte@Sun.COM 	FILE *fp = NULL;
7067836SJohn.Forte@Sun.COM 	static char buf[BUFSIZ];
7077836SJohn.Forte@Sun.COM 	char *p = NULL, *p1 = NULL;  /* p = full device, p1 = chunk to rm */
7087836SJohn.Forte@Sun.COM 	char *slot = ":devctl";
7097836SJohn.Forte@Sun.COM 	char *root = "/";
7107836SJohn.Forte@Sun.COM 
7117836SJohn.Forte@Sun.COM 	if ((fp = fopen(MNTTAB, "r")) == NULL) {
7127836SJohn.Forte@Sun.COM 		(void) fprintf(stderr,
7137836SJohn.Forte@Sun.COM 		    MSGSTR(21000, "Error: Could not open %s\n"), MNTTAB);
7147836SJohn.Forte@Sun.COM 		return (1);
7157836SJohn.Forte@Sun.COM 	}
7167836SJohn.Forte@Sun.COM 
7177836SJohn.Forte@Sun.COM 	mntnull(&mpref);
7187836SJohn.Forte@Sun.COM 	mpref.mnt_mountp = (char *)root;
7197836SJohn.Forte@Sun.COM 
7207836SJohn.Forte@Sun.COM 	if (getmntany(fp, &mp, &mpref) != 0 ||
7217836SJohn.Forte@Sun.COM 	    mpref.mnt_mountp == NULL) {
7227836SJohn.Forte@Sun.COM 		(void) fprintf(stderr, MSGSTR(21019,
7237836SJohn.Forte@Sun.COM 		    "Error: Cannot get boot device, check %s.\n"), MNTTAB);
7247836SJohn.Forte@Sun.COM 		(void) fclose(fp);
7257836SJohn.Forte@Sun.COM 		return (1);
7267836SJohn.Forte@Sun.COM 	}
7277836SJohn.Forte@Sun.COM 	(void) fclose(fp);
7287836SJohn.Forte@Sun.COM 
7297836SJohn.Forte@Sun.COM 	/*
7307836SJohn.Forte@Sun.COM 	 * If we can't get a link, we may be dealing with a volume mgr
7317836SJohn.Forte@Sun.COM 	 * so give a warning.  If a colon is present, we likely have a
7327836SJohn.Forte@Sun.COM 	 * non-local disk or cd-rom, so no warning is necessary.
7337836SJohn.Forte@Sun.COM 	 * e.g. /devices/pci@1f,4000/scsi@3/sd@6,0:b (cdrom, no link) or
734*8538SReed.Liu@Sun.COM 	 *	storage-e4:/blah/blah remote boot server
7357836SJohn.Forte@Sun.COM 	 */
7367836SJohn.Forte@Sun.COM 	if (readlink(mp.mnt_special, buf, BUFSIZ) < 0) {
7377836SJohn.Forte@Sun.COM 		if (strstr(mp.mnt_special, ":") == NULL) {
7387836SJohn.Forte@Sun.COM 			(void) fprintf(stderr, MSGSTR(21020,
7397836SJohn.Forte@Sun.COM 	"\nWarning: Cannot read boot device link, check %s.\n"), MNTTAB);
7407836SJohn.Forte@Sun.COM 			(void) fprintf(stderr, MSGSTR(21021,
7417836SJohn.Forte@Sun.COM 	"Do not upgrade FCode on adapters controlling the boot device.\n"));
7427836SJohn.Forte@Sun.COM 		}
7437836SJohn.Forte@Sun.COM 		return (1);
7447836SJohn.Forte@Sun.COM 	}
7457836SJohn.Forte@Sun.COM 	/*
7467836SJohn.Forte@Sun.COM 	 * Copy boot device path to bootpath.  First remove leading
7477836SJohn.Forte@Sun.COM 	 * path junk (../../..) then if it's an ifp device, chop off
7487836SJohn.Forte@Sun.COM 	 * the disk and add the devctl to the end of the path.
7497836SJohn.Forte@Sun.COM 	 */
7507836SJohn.Forte@Sun.COM 	if (p = strstr(buf, "/devices")) {
7517836SJohn.Forte@Sun.COM 		if (strstr(buf, fc_trans) != NULL) {
7527836SJohn.Forte@Sun.COM 			p1 = strrchr(p, '/');
7537836SJohn.Forte@Sun.COM 			*p1 = '\0';
7547836SJohn.Forte@Sun.COM 		}
7557836SJohn.Forte@Sun.COM 	}
7567836SJohn.Forte@Sun.COM 	(void) strcpy((char *)bootpath, (char *)p);
7577836SJohn.Forte@Sun.COM 	if (p1) {
7587836SJohn.Forte@Sun.COM 		(void) strcat((char *)bootpath, slot);
7597836SJohn.Forte@Sun.COM 	}
7607836SJohn.Forte@Sun.COM 	return (0);
7617836SJohn.Forte@Sun.COM }
7627836SJohn.Forte@Sun.COM 
7637836SJohn.Forte@Sun.COM /*
7647836SJohn.Forte@Sun.COM  * Load FCode to card.
7657836SJohn.Forte@Sun.COM  *    uses ioctl: IFPIO_FCODE_DOWNLOAD
7667836SJohn.Forte@Sun.COM  */
7677836SJohn.Forte@Sun.COM static int
q_load_file(int fcode_fd,char * device)7687836SJohn.Forte@Sun.COM q_load_file(int fcode_fd, char *device)
7697836SJohn.Forte@Sun.COM {
7707836SJohn.Forte@Sun.COM 	static int	dev_fd, fcode_size;
7717836SJohn.Forte@Sun.COM 	struct stat	stat;
7727836SJohn.Forte@Sun.COM 	ifp_download_t	*download_p = NULL;
7737836SJohn.Forte@Sun.COM 	fcio_t		fcio;
7747836SJohn.Forte@Sun.COM 	uint16_t	file_id = 0;
7757836SJohn.Forte@Sun.COM 	uchar_t		*bin;
7767836SJohn.Forte@Sun.COM 
7777836SJohn.Forte@Sun.COM 	if (lseek(fcode_fd, 0, SEEK_SET) == -1) {
7787836SJohn.Forte@Sun.COM 		perror(MSGSTR(21022, "seek"));
7797836SJohn.Forte@Sun.COM 		(void) close(fcode_fd);
7807836SJohn.Forte@Sun.COM 		return (1);
7817836SJohn.Forte@Sun.COM 	}
7827836SJohn.Forte@Sun.COM 	if (fstat(fcode_fd, &stat) == -1) {
7837836SJohn.Forte@Sun.COM 		perror(MSGSTR(21023, "fstat"));
7847836SJohn.Forte@Sun.COM 		(void) close(fcode_fd);
7857836SJohn.Forte@Sun.COM 		return (1);
7867836SJohn.Forte@Sun.COM 	}
7877836SJohn.Forte@Sun.COM 
7887836SJohn.Forte@Sun.COM 	fcode_size = stat.st_size;
7897836SJohn.Forte@Sun.COM 
7907836SJohn.Forte@Sun.COM 	if (strstr(device, fc_trans)) {
7917836SJohn.Forte@Sun.COM 		if ((download_p = (ifp_download_t *)malloc(
7927836SJohn.Forte@Sun.COM 			sizeof (ifp_download_t) + fcode_size)) == NULL) {
7937836SJohn.Forte@Sun.COM 			(void) fprintf(stderr,
7947836SJohn.Forte@Sun.COM 			    MSGSTR(21013, "Error: Memory allocation failed\n"));
7957836SJohn.Forte@Sun.COM 			(void) close(fcode_fd);
7967836SJohn.Forte@Sun.COM 			return (1);
7977836SJohn.Forte@Sun.COM 		}
7987836SJohn.Forte@Sun.COM 	} else {
7997836SJohn.Forte@Sun.COM 		if ((bin = (uchar_t *)malloc(fcode_size)) == NULL) {
8007836SJohn.Forte@Sun.COM 			(void) fprintf(stderr,
8017836SJohn.Forte@Sun.COM 			    MSGSTR(21013, "Error: Memory allocation failed\n"));
8027836SJohn.Forte@Sun.COM 			(void) close(fcode_fd);
8037836SJohn.Forte@Sun.COM 			return (1);
8047836SJohn.Forte@Sun.COM 		}
8057836SJohn.Forte@Sun.COM 	}
8067836SJohn.Forte@Sun.COM 
8077836SJohn.Forte@Sun.COM 	if (strstr(device, fc_trans)) {
8087836SJohn.Forte@Sun.COM 		if (read(fcode_fd, download_p->dl_fcode, fcode_size)
8097836SJohn.Forte@Sun.COM 		    != fcode_size) {
8107836SJohn.Forte@Sun.COM 			perror(MSGSTR(21001, "read"));
8117836SJohn.Forte@Sun.COM 			free(download_p);
8127836SJohn.Forte@Sun.COM 			(void) close(fcode_fd);
8137836SJohn.Forte@Sun.COM 			return (1);
8147836SJohn.Forte@Sun.COM 		}
8157836SJohn.Forte@Sun.COM 	} else {
8167836SJohn.Forte@Sun.COM 		if (read(fcode_fd, bin, fcode_size)
8177836SJohn.Forte@Sun.COM 		    != fcode_size) {
8187836SJohn.Forte@Sun.COM 			perror(MSGSTR(21001, "read"));
8197836SJohn.Forte@Sun.COM 			free(bin);
8207836SJohn.Forte@Sun.COM 			(void) close(fcode_fd);
8217836SJohn.Forte@Sun.COM 			return (1);
8227836SJohn.Forte@Sun.COM 		}
8237836SJohn.Forte@Sun.COM 	}
8247836SJohn.Forte@Sun.COM 
8257836SJohn.Forte@Sun.COM 
8267836SJohn.Forte@Sun.COM 	if ((dev_fd = open(device, O_RDWR|O_EXCL)) < 0) {
8277836SJohn.Forte@Sun.COM 		(void) fprintf(stderr,
8287836SJohn.Forte@Sun.COM 		    MSGSTR(21000, "Error: Could not open %s\n"), device);
8297836SJohn.Forte@Sun.COM 		free(download_p);
8307836SJohn.Forte@Sun.COM 		return (1);
8317836SJohn.Forte@Sun.COM 	}
8327836SJohn.Forte@Sun.COM 	if (strstr(device, fc_trans)) {
8337836SJohn.Forte@Sun.COM 		download_p->dl_fcode_len = fcode_size;
8347836SJohn.Forte@Sun.COM 		file_id = download_p->dl_fcode[0x42] & 0xff;
8357836SJohn.Forte@Sun.COM 		file_id |= (download_p->dl_fcode[0x43] << 8) & 0xff00;
8367836SJohn.Forte@Sun.COM 		download_p->dl_chip_id = file_id;
8377836SJohn.Forte@Sun.COM 		if (ioctl(dev_fd, IFPIO_FCODE_DOWNLOAD, download_p) < 0) {
8387836SJohn.Forte@Sun.COM 			(void) fprintf(stderr, MSGSTR(21024,
8397836SJohn.Forte@Sun.COM 		    "Error: Driver interface IFPIO_FCODE_DOWNLOAD failed\n"));
8407836SJohn.Forte@Sun.COM 			free(download_p);
8417836SJohn.Forte@Sun.COM 			(void) close(dev_fd);
8427836SJohn.Forte@Sun.COM 			return (1);
8437836SJohn.Forte@Sun.COM 		}
8447836SJohn.Forte@Sun.COM 		free(download_p);
8457836SJohn.Forte@Sun.COM 	} else if (strstr(device, fp_trans)) {
8467836SJohn.Forte@Sun.COM 		fcio.fcio_cmd = FCIO_DOWNLOAD_FCODE;
8477836SJohn.Forte@Sun.COM 		/* Information read operation */
8487836SJohn.Forte@Sun.COM 		fcio.fcio_xfer = FCIO_XFER_WRITE;
8497836SJohn.Forte@Sun.COM 		fcio.fcio_ibuf = (caddr_t)bin;
8507836SJohn.Forte@Sun.COM 		fcio.fcio_ilen = fcode_size;
8517836SJohn.Forte@Sun.COM 
8527836SJohn.Forte@Sun.COM 		if (ioctl(dev_fd, FCIO_CMD, &fcio) != 0) {
8537836SJohn.Forte@Sun.COM 			(void) fprintf(stderr, MSGSTR(21036,
8547836SJohn.Forte@Sun.COM 		    "Error: Driver interface FCIO_DOWNLOAD_FCODE failed\n"));
8557836SJohn.Forte@Sun.COM 			free(download_p);
8567836SJohn.Forte@Sun.COM 			(void) close(dev_fd);
8577836SJohn.Forte@Sun.COM 			return (1);
8587836SJohn.Forte@Sun.COM 		}
8597836SJohn.Forte@Sun.COM 		free(bin);
8607836SJohn.Forte@Sun.COM 	}
8617836SJohn.Forte@Sun.COM 	(void) close(dev_fd);
8627836SJohn.Forte@Sun.COM 	return (0);
8637836SJohn.Forte@Sun.COM }
8647836SJohn.Forte@Sun.COM 
8657836SJohn.Forte@Sun.COM /*
8667836SJohn.Forte@Sun.COM  * Issue warning strings and loop for Yes/No user interaction
8677836SJohn.Forte@Sun.COM  *    err# 0 -- we're ok, warn for pending FCode load
868*8538SReed.Liu@Sun.COM  *	   1 -- not in single user mode
869*8538SReed.Liu@Sun.COM  *	   2 -- can't get chip_id
870*8538SReed.Liu@Sun.COM  *	   3 -- card and file do not have same type (2100/2200)
8717836SJohn.Forte@Sun.COM  */
8727836SJohn.Forte@Sun.COM static int
q_warn(int errnum)8737836SJohn.Forte@Sun.COM q_warn(int errnum)
8747836SJohn.Forte@Sun.COM {
8757836SJohn.Forte@Sun.COM 	char input[1024];
8767836SJohn.Forte@Sun.COM 	input[0] = '\0';
8777836SJohn.Forte@Sun.COM 
8787836SJohn.Forte@Sun.COM 	if (errnum == 1) {
8797836SJohn.Forte@Sun.COM 		(void) fprintf(stderr, MSGSTR(21025,
8807836SJohn.Forte@Sun.COM 		    "\nWarning: System is not in single-user mode.\n"));
8817836SJohn.Forte@Sun.COM 		(void) fprintf(stderr, MSGSTR(21026,
8827836SJohn.Forte@Sun.COM 	"Loading FCode will reset the adapter and terminate I/O activity\n"));
8837836SJohn.Forte@Sun.COM 	} else {
8847836SJohn.Forte@Sun.COM 		if (errnum == 2) {
8857836SJohn.Forte@Sun.COM 			(void) fprintf(stderr, MSGSTR(21027,
8867836SJohn.Forte@Sun.COM 			"  Warning: FCode is missing or existing FCode has"
8877836SJohn.Forte@Sun.COM 			" unrecognized version.\n"));
8887836SJohn.Forte@Sun.COM 			return (1);
8897836SJohn.Forte@Sun.COM 		} else if (errnum == 3) {
8907836SJohn.Forte@Sun.COM 			(void) fprintf(stderr, MSGSTR(21028,
8917836SJohn.Forte@Sun.COM 			"  Warning: New FCode file version does not match this"
8927836SJohn.Forte@Sun.COM 			" board type. Skipping...\n"));
8937836SJohn.Forte@Sun.COM 			return (1);
8947836SJohn.Forte@Sun.COM 		}
8957836SJohn.Forte@Sun.COM 		(void) fprintf(stderr, MSGSTR(21029,
8967836SJohn.Forte@Sun.COM 		"\nWARNING!! This program will update the FCode in this"
8977836SJohn.Forte@Sun.COM 		" FC100/PCI, ISP2200/PCI, ISP23xx/PCI "
8987836SJohn.Forte@Sun.COM 		" and Emulex devices.\n"));
8997836SJohn.Forte@Sun.COM 		(void) fprintf(stderr, MSGSTR(21030,
9007836SJohn.Forte@Sun.COM 		"This may take a few (5) minutes. Please be patient.\n"));
9017836SJohn.Forte@Sun.COM 	}
9027836SJohn.Forte@Sun.COM 
9037836SJohn.Forte@Sun.COM loop1:
9047836SJohn.Forte@Sun.COM 	(void) fprintf(stderr, MSGSTR(21031,
9057836SJohn.Forte@Sun.COM 		"Do you wish to continue ? (y/n) "));
9067836SJohn.Forte@Sun.COM 
9077836SJohn.Forte@Sun.COM 	(void) gets(input);
9087836SJohn.Forte@Sun.COM 
9097836SJohn.Forte@Sun.COM 	if ((strcmp(input, MSGSTR(21032, "y")) == 0) ||
9107836SJohn.Forte@Sun.COM 			(strcmp(input, MSGSTR(40, "yes")) == 0)) {
9117836SJohn.Forte@Sun.COM 		return (0);
9127836SJohn.Forte@Sun.COM 	} else if ((strcmp(input, MSGSTR(21033, "n")) == 0) ||
9137836SJohn.Forte@Sun.COM 			(strcmp(input, MSGSTR(45, "no")) == 0)) {
9147836SJohn.Forte@Sun.COM 		(void) fprintf(stderr,
9157836SJohn.Forte@Sun.COM 		    MSGSTR(21034, "Not Downloading FCode\n"));
9167836SJohn.Forte@Sun.COM 		return (1);
9177836SJohn.Forte@Sun.COM 	} else {
9187836SJohn.Forte@Sun.COM 		(void) fprintf(stderr, MSGSTR(21035, "Invalid input\n"));
9197836SJohn.Forte@Sun.COM 		goto loop1;
9207836SJohn.Forte@Sun.COM 	}
9217836SJohn.Forte@Sun.COM }
9227836SJohn.Forte@Sun.COM 
9237836SJohn.Forte@Sun.COM /*
924*8538SReed.Liu@Sun.COM  * Name	   : memstrstr
9257836SJohn.Forte@Sun.COM  * Input   : pointer to buf1, pointer to buf2, size of buf1, size of buf2
9267836SJohn.Forte@Sun.COM  * Returns :
927*8538SReed.Liu@Sun.COM  *	Offset of the start of contents-of-buf2 in buf1 if it is found
928*8538SReed.Liu@Sun.COM  *	-1 if buf1 does not contain contents of buf2
9297836SJohn.Forte@Sun.COM  * Synopsis:
9307836SJohn.Forte@Sun.COM  * This function works similar to strstr(). The difference is that null
9317836SJohn.Forte@Sun.COM  * characters in the buffer are treated like any other character. So, buf1
9327836SJohn.Forte@Sun.COM  * and buf2 can have embedded null characters in them.
9337836SJohn.Forte@Sun.COM  */
9347836SJohn.Forte@Sun.COM static int
memstrstr(char * s1,char * s2,int size1,int size2)9357836SJohn.Forte@Sun.COM memstrstr(char *s1, char *s2, int size1, int size2)
9367836SJohn.Forte@Sun.COM {
9377836SJohn.Forte@Sun.COM 	int count1, count2;
9387836SJohn.Forte@Sun.COM 	char *s1_ptr, *s2_ptr;
9397836SJohn.Forte@Sun.COM 
9407836SJohn.Forte@Sun.COM 	count1 = size1; count2 = size2;
9417836SJohn.Forte@Sun.COM 	s1_ptr = s1; s2_ptr = s2;
9427836SJohn.Forte@Sun.COM 
9437836SJohn.Forte@Sun.COM 	if ((size2 == 0)||(size1 == 0))
9447836SJohn.Forte@Sun.COM 		return (-1);
9457836SJohn.Forte@Sun.COM 
9467836SJohn.Forte@Sun.COM 	for (count1 = 0; count1 < (size1 - size2 + 1); count1++) {
9477836SJohn.Forte@Sun.COM 		if (*s1_ptr++ == *s2_ptr++) {
9487836SJohn.Forte@Sun.COM 			if (--count2 == 0) {
9497836SJohn.Forte@Sun.COM 				return (count1 - size2 + 1);
9507836SJohn.Forte@Sun.COM 			}
9517836SJohn.Forte@Sun.COM 			continue;
9527836SJohn.Forte@Sun.COM 		}
9537836SJohn.Forte@Sun.COM 		count2 = size2;
9547836SJohn.Forte@Sun.COM 		s2_ptr = s2;
9557836SJohn.Forte@Sun.COM 	}
9567836SJohn.Forte@Sun.COM 
9577836SJohn.Forte@Sun.COM 	return (-1);
9587836SJohn.Forte@Sun.COM }
9597836SJohn.Forte@Sun.COM 
9607836SJohn.Forte@Sun.COM /*
9617836SJohn.Forte@Sun.COM  * generic fcode load file routine.  given a file descriptor to a fcode file
9627836SJohn.Forte@Sun.COM  * this routine will issue the FCIO_DOWNLOAD_FCODE ioctl to the given
9637836SJohn.Forte@Sun.COM  * device.  Any ioctl errors will be returned in fcio_errno
9647836SJohn.Forte@Sun.COM  *
9657836SJohn.Forte@Sun.COM  * Arguments:
9667836SJohn.Forte@Sun.COM  *	fcode_fd    file descriptor to a fcode file
9677836SJohn.Forte@Sun.COM  *	device	    path to the device we will be downloading the fcode onto
9687836SJohn.Forte@Sun.COM  *	fcio_errno  pointer to an int that will be used to return any errors
9697836SJohn.Forte@Sun.COM  *			back to the caller
9707836SJohn.Forte@Sun.COM  * Retrurn Values:
9717836SJohn.Forte@Sun.COM  *	0	    successful download
9727836SJohn.Forte@Sun.COM  *	>0	    otherwise
9737836SJohn.Forte@Sun.COM  */
9747836SJohn.Forte@Sun.COM static int
fcode_load_file(int fcode_fd,char * device,int * fcio_errno)9757836SJohn.Forte@Sun.COM fcode_load_file(int fcode_fd, char *device, int *fcio_errno)
9767836SJohn.Forte@Sun.COM {
9777836SJohn.Forte@Sun.COM 
9787836SJohn.Forte@Sun.COM 	fcio_t		fcio;
9797836SJohn.Forte@Sun.COM 	static int	dev_fd, fcode_size;
9807836SJohn.Forte@Sun.COM 	uchar_t		*bin;
9817836SJohn.Forte@Sun.COM 	struct stat	stat;
9827836SJohn.Forte@Sun.COM 
9837836SJohn.Forte@Sun.COM 	if (device == NULL || fcio_errno == NULL) {
9847836SJohn.Forte@Sun.COM 		return (FCODE_LOAD_FAILURE);
9857836SJohn.Forte@Sun.COM 	}
9867836SJohn.Forte@Sun.COM 
9877836SJohn.Forte@Sun.COM 	*fcio_errno = 0;
9887836SJohn.Forte@Sun.COM 	if (lseek(fcode_fd, 0, SEEK_SET) == -1) {
9897836SJohn.Forte@Sun.COM 		perror(MSGSTR(21022, "seek"));
9907836SJohn.Forte@Sun.COM 		return (FCODE_LOAD_FAILURE);
9917836SJohn.Forte@Sun.COM 	}
9927836SJohn.Forte@Sun.COM 
9937836SJohn.Forte@Sun.COM 	if (fstat(fcode_fd, &stat) == -1) {
9947836SJohn.Forte@Sun.COM 		perror(MSGSTR(21023, "fstat"));
9957836SJohn.Forte@Sun.COM 		return (FCODE_LOAD_FAILURE);
9967836SJohn.Forte@Sun.COM 	}
9977836SJohn.Forte@Sun.COM 
9987836SJohn.Forte@Sun.COM 	fcode_size = stat.st_size;
9997836SJohn.Forte@Sun.COM 
10007836SJohn.Forte@Sun.COM 	if ((bin = (uchar_t *)malloc(fcode_size)) == NULL) {
10017836SJohn.Forte@Sun.COM 		(void) fprintf(stderr,
10027836SJohn.Forte@Sun.COM 		    MSGSTR(21013, "Error: Memory allocation failed\n"));
10037836SJohn.Forte@Sun.COM 		return (FCODE_LOAD_FAILURE);
10047836SJohn.Forte@Sun.COM 	}
10057836SJohn.Forte@Sun.COM 
10067836SJohn.Forte@Sun.COM 	if (read(fcode_fd, bin, fcode_size)
10077836SJohn.Forte@Sun.COM 	    != fcode_size) {
10087836SJohn.Forte@Sun.COM 		perror(MSGSTR(21001, "read"));
10097836SJohn.Forte@Sun.COM 		free(bin);
10107836SJohn.Forte@Sun.COM 		return (FCODE_LOAD_FAILURE);
10117836SJohn.Forte@Sun.COM 	}
10127836SJohn.Forte@Sun.COM 
10137836SJohn.Forte@Sun.COM 	if ((dev_fd = open(device, O_RDWR|O_EXCL)) < 0) {
10147836SJohn.Forte@Sun.COM 		(void) fprintf(stderr,
10157836SJohn.Forte@Sun.COM 		    MSGSTR(21122, "Error: Could not open %s, failed "
10167836SJohn.Forte@Sun.COM 			    "with errno %d\n"), device, errno);
10177836SJohn.Forte@Sun.COM 		free(bin);
10187836SJohn.Forte@Sun.COM 		return (FCODE_LOAD_FAILURE);
10197836SJohn.Forte@Sun.COM 	}
10207836SJohn.Forte@Sun.COM 
10217836SJohn.Forte@Sun.COM 	fcio.fcio_cmd = FCIO_DOWNLOAD_FCODE;
10227836SJohn.Forte@Sun.COM 	fcio.fcio_xfer = FCIO_XFER_WRITE;
10237836SJohn.Forte@Sun.COM 	fcio.fcio_ibuf = (caddr_t)bin;
10247836SJohn.Forte@Sun.COM 	fcio.fcio_ilen = fcode_size;
10257836SJohn.Forte@Sun.COM 
10267836SJohn.Forte@Sun.COM 	if (ioctl(dev_fd, FCIO_CMD, &fcio) != 0) {
10277836SJohn.Forte@Sun.COM 		(void) close(dev_fd);
10287836SJohn.Forte@Sun.COM 		*fcio_errno = fcio.fcio_errno;
10297836SJohn.Forte@Sun.COM 		free(bin);
10307836SJohn.Forte@Sun.COM 		return (FCODE_IOCTL_FAILURE);
10317836SJohn.Forte@Sun.COM 	}
10327836SJohn.Forte@Sun.COM 
10337836SJohn.Forte@Sun.COM 	free(bin);
10347836SJohn.Forte@Sun.COM 	(void) close(dev_fd);
10357836SJohn.Forte@Sun.COM 	return (FCODE_SUCCESS);
10367836SJohn.Forte@Sun.COM }
10377836SJohn.Forte@Sun.COM 
10387836SJohn.Forte@Sun.COM /*
10397836SJohn.Forte@Sun.COM  * Searches for and updates the fcode for Emulex HBA cards
10407836SJohn.Forte@Sun.COM  * args: FCode file; if NULL only the current FCode
10417836SJohn.Forte@Sun.COM  * version is printed
10427836SJohn.Forte@Sun.COM  */
10437836SJohn.Forte@Sun.COM 
10447836SJohn.Forte@Sun.COM int
emulex_update(char * file)10457836SJohn.Forte@Sun.COM emulex_update(char *file)
10467836SJohn.Forte@Sun.COM {
10477836SJohn.Forte@Sun.COM 
1048*8538SReed.Liu@Sun.COM 	int		fd, retval = 0;
1049*8538SReed.Liu@Sun.COM 	int		devcnt = 0;
1050*8538SReed.Liu@Sun.COM 	uint_t		state = 0, fflag = 0;
1051*8538SReed.Liu@Sun.COM 	static uchar_t	bootpath[PATH_MAX];
1052*8538SReed.Liu@Sun.COM 	int		fcode_fd = -1;
10537836SJohn.Forte@Sun.COM 	static struct	utmpx *utmpp = NULL;
1054*8538SReed.Liu@Sun.COM 	di_node_t	root;
1055*8538SReed.Liu@Sun.COM 	di_node_t	node, sib_node, count_node;
1056*8538SReed.Liu@Sun.COM 	di_minor_t	minor_node;
1057*8538SReed.Liu@Sun.COM 	char		phys_path[PATH_MAX], *path;
1058*8538SReed.Liu@Sun.COM 	int		errnum = 0, fcio_errno = 0;
10597836SJohn.Forte@Sun.COM 	static uchar_t	prom_ver_data[MAXNAMELEN];
10607836SJohn.Forte@Sun.COM 	static char	ver_file[EMULEX_FCODE_VERSION_LENGTH];
10617836SJohn.Forte@Sun.COM 	void		(*sigint)();
10627836SJohn.Forte@Sun.COM 	int		prop_entries = -1;
1063*8538SReed.Liu@Sun.COM 	int		*port_data = NULL;
10647836SJohn.Forte@Sun.COM 
10657836SJohn.Forte@Sun.COM 	if (file) {
10667836SJohn.Forte@Sun.COM 		/* set the fcode download flag */
10677836SJohn.Forte@Sun.COM 		fflag++;
10687836SJohn.Forte@Sun.COM 
10697836SJohn.Forte@Sun.COM 		/* check for a valid file */
10707836SJohn.Forte@Sun.COM 		if ((fcode_fd = open(file, O_RDONLY)) < 0) {
10717836SJohn.Forte@Sun.COM 			(void) fprintf(stderr,
10727836SJohn.Forte@Sun.COM 			    MSGSTR(21118, "Error: Could not open %s, failed "
10737836SJohn.Forte@Sun.COM 				    "with errno %d\n"), file, errno);
10747836SJohn.Forte@Sun.COM 			return (1);
10757836SJohn.Forte@Sun.COM 		}
10767836SJohn.Forte@Sun.COM 
10777836SJohn.Forte@Sun.COM 		/* check for single user mode */
10787836SJohn.Forte@Sun.COM 		while ((utmpp = getutxent()) != NULL) {
10797836SJohn.Forte@Sun.COM 			if (strstr(utmpp->ut_line, "run-level") &&
10807836SJohn.Forte@Sun.COM 				(strcmp(utmpp->ut_line, "run-level S") &&
10817836SJohn.Forte@Sun.COM 				strcmp(utmpp->ut_line, "run-level 1"))) {
10827836SJohn.Forte@Sun.COM 				if (q_warn(1)) {
10837836SJohn.Forte@Sun.COM 					(void) endutxent();
10847836SJohn.Forte@Sun.COM 					(void) close(fcode_fd);
10857836SJohn.Forte@Sun.COM 					return (1);
10867836SJohn.Forte@Sun.COM 				}
10877836SJohn.Forte@Sun.COM 				break;
10887836SJohn.Forte@Sun.COM 			}
10897836SJohn.Forte@Sun.COM 		}
10907836SJohn.Forte@Sun.COM 		(void) endutxent();
10917836SJohn.Forte@Sun.COM 
10927836SJohn.Forte@Sun.COM 		/* get bootpath */
10937836SJohn.Forte@Sun.COM 		if (!q_getbootdev((uchar_t *)&bootpath[0]) &&
10947836SJohn.Forte@Sun.COM 		    getenv("_LUX_D_DEBUG") != NULL) {
10957836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "  Bootpath: %s\n", bootpath);
10967836SJohn.Forte@Sun.COM 		}
10977836SJohn.Forte@Sun.COM 	}
10987836SJohn.Forte@Sun.COM 
10997836SJohn.Forte@Sun.COM 	/*
11007836SJohn.Forte@Sun.COM 	 * Download the Fcode to all the emulex cards found
11017836SJohn.Forte@Sun.COM 	 */
11027836SJohn.Forte@Sun.COM 
11037836SJohn.Forte@Sun.COM 	/* Create a snapshot of the kernel device tree */
11047836SJohn.Forte@Sun.COM 	if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
11057836SJohn.Forte@Sun.COM 		(void) fprintf(stderr, MSGSTR(21114,
11067836SJohn.Forte@Sun.COM 		"Error: Could not get /devices path to "
11077836SJohn.Forte@Sun.COM 		"Emulex Devices.\n"));
11087836SJohn.Forte@Sun.COM 		retval++;
11097836SJohn.Forte@Sun.COM 	}
11107836SJohn.Forte@Sun.COM 
11117836SJohn.Forte@Sun.COM 	/* point to first node which matches emulex driver */
11127836SJohn.Forte@Sun.COM 	node = di_drv_first_node("emlxs", root);
11137836SJohn.Forte@Sun.COM 
11147836SJohn.Forte@Sun.COM 	if (node == DI_NODE_NIL) {
11157836SJohn.Forte@Sun.COM 		/*
11167836SJohn.Forte@Sun.COM 		 * Could not find any emulex cards
11177836SJohn.Forte@Sun.COM 		 */
11187836SJohn.Forte@Sun.COM 		(void) di_fini(root);
11197836SJohn.Forte@Sun.COM 		(void) fprintf(stderr, MSGSTR(21115,
11207836SJohn.Forte@Sun.COM 		"\n  Found Path to %d Emulex Devices.\n"), devcnt);
11217836SJohn.Forte@Sun.COM 		retval++;
11227836SJohn.Forte@Sun.COM 	} else {
11237836SJohn.Forte@Sun.COM 		count_node = node;
11247836SJohn.Forte@Sun.COM 		while (count_node != DI_NODE_NIL) {
11257836SJohn.Forte@Sun.COM 			state = di_state(count_node);
11267836SJohn.Forte@Sun.COM 			if ((state & DI_DRIVER_DETACHED)
11277836SJohn.Forte@Sun.COM 			    != DI_DRIVER_DETACHED) {
1128*8538SReed.Liu@Sun.COM 				sib_node = di_child_node(count_node);
1129*8538SReed.Liu@Sun.COM 				while (sib_node != DI_NODE_NIL) {
1130*8538SReed.Liu@Sun.COM 					state = di_state(sib_node);
1131*8538SReed.Liu@Sun.COM 					if ((state & DI_DRIVER_DETACHED) !=
1132*8538SReed.Liu@Sun.COM 					    DI_DRIVER_DETACHED) {
1133*8538SReed.Liu@Sun.COM 						/* Found an attached node */
1134*8538SReed.Liu@Sun.COM 						prop_entries =
1135*8538SReed.Liu@Sun.COM 						    di_prop_lookup_ints(
1136*8538SReed.Liu@Sun.COM 						    DDI_DEV_T_ANY, sib_node,
1137*8538SReed.Liu@Sun.COM 						    "port", &port_data);
1138*8538SReed.Liu@Sun.COM 						if (prop_entries != -1) {
1139*8538SReed.Liu@Sun.COM 							devcnt++;
1140*8538SReed.Liu@Sun.COM 							break;
1141*8538SReed.Liu@Sun.COM 						}
1142*8538SReed.Liu@Sun.COM 					}
1143*8538SReed.Liu@Sun.COM 
1144*8538SReed.Liu@Sun.COM 					sib_node = di_sibling_node(sib_node);
1145*8538SReed.Liu@Sun.COM 				}
11467836SJohn.Forte@Sun.COM 			}
11477836SJohn.Forte@Sun.COM 			count_node = di_drv_next_node(count_node);
11487836SJohn.Forte@Sun.COM 		}
11497836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, MSGSTR(21116,
11507836SJohn.Forte@Sun.COM 		"\n  Found Path to %d Emulex Devices.\n"), devcnt);
11517836SJohn.Forte@Sun.COM 	}
11527836SJohn.Forte@Sun.COM 
11537836SJohn.Forte@Sun.COM 
11547836SJohn.Forte@Sun.COM 	/*
11557836SJohn.Forte@Sun.COM 	 * Traverse device tree to find all emulex cards
11567836SJohn.Forte@Sun.COM 	 */
11577836SJohn.Forte@Sun.COM 	while (node != DI_NODE_NIL) {
11587836SJohn.Forte@Sun.COM 
11597836SJohn.Forte@Sun.COM 		state = di_state(node);
11607836SJohn.Forte@Sun.COM 		if ((state & DI_DRIVER_DETACHED) == DI_DRIVER_DETACHED) {
11617836SJohn.Forte@Sun.COM 			node = di_drv_next_node(node);
11627836SJohn.Forte@Sun.COM 			continue;
11637836SJohn.Forte@Sun.COM 		}
11647836SJohn.Forte@Sun.COM 
11657836SJohn.Forte@Sun.COM 		sib_node = di_child_node(node);
11667836SJohn.Forte@Sun.COM 		while (sib_node != DI_NODE_NIL) {
11677836SJohn.Forte@Sun.COM 			state = di_state(sib_node);
11687836SJohn.Forte@Sun.COM 			if ((state & DI_DRIVER_DETACHED) !=
11697836SJohn.Forte@Sun.COM 			    DI_DRIVER_DETACHED) {
11707836SJohn.Forte@Sun.COM 
11717836SJohn.Forte@Sun.COM 				/* Found an attached node */
11727836SJohn.Forte@Sun.COM 				prop_entries = di_prop_lookup_ints(
11737836SJohn.Forte@Sun.COM 				    DDI_DEV_T_ANY, sib_node,
11747836SJohn.Forte@Sun.COM 				    "port", &port_data);
11757836SJohn.Forte@Sun.COM 				if (prop_entries != -1) {
11767836SJohn.Forte@Sun.COM 
11777836SJohn.Forte@Sun.COM 					/* Found a node with "port" property */
11787836SJohn.Forte@Sun.COM 					minor_node = di_minor_next(sib_node,
11797836SJohn.Forte@Sun.COM 					    DI_MINOR_NIL);
11807836SJohn.Forte@Sun.COM 					break;
11817836SJohn.Forte@Sun.COM 				}
11827836SJohn.Forte@Sun.COM 			}
11837836SJohn.Forte@Sun.COM 			sib_node = di_sibling_node(sib_node);
11847836SJohn.Forte@Sun.COM 		}
11857836SJohn.Forte@Sun.COM 
11867836SJohn.Forte@Sun.COM 		if (sib_node == DI_NODE_NIL) {
1187*8538SReed.Liu@Sun.COM 			goto try_next;
11887836SJohn.Forte@Sun.COM 		}
1189*8538SReed.Liu@Sun.COM 
11907836SJohn.Forte@Sun.COM 		path = di_devfs_path(sib_node);
11917836SJohn.Forte@Sun.COM 		(void) strcpy(phys_path, "/devices");
11927836SJohn.Forte@Sun.COM 		(void) strncat(phys_path, path, strlen(path));
11937836SJohn.Forte@Sun.COM 		di_devfs_path_free(path);
11947836SJohn.Forte@Sun.COM 
11957836SJohn.Forte@Sun.COM 		if (fflag && (strstr((char *)bootpath,
11967836SJohn.Forte@Sun.COM 		    (char *)phys_path) != NULL)) {
11977836SJohn.Forte@Sun.COM 			(void) fprintf(stderr,
11987836SJohn.Forte@Sun.COM 			    MSGSTR(21117, "Ignoring %s (bootpath)\n"),
11997836SJohn.Forte@Sun.COM 			    phys_path);
12007836SJohn.Forte@Sun.COM 			node = di_drv_next_node(node);
12017836SJohn.Forte@Sun.COM 			continue;
12027836SJohn.Forte@Sun.COM 		}
12037836SJohn.Forte@Sun.COM 
12047836SJohn.Forte@Sun.COM 		if (minor_node) {
12057836SJohn.Forte@Sun.COM 			(void) strncat(phys_path, ":", 1);
12067836SJohn.Forte@Sun.COM 			(void) strncat(phys_path,
12077836SJohn.Forte@Sun.COM 				di_minor_name(minor_node),
12087836SJohn.Forte@Sun.COM 				strlen(di_minor_name(minor_node)));
12097836SJohn.Forte@Sun.COM 		}
12107836SJohn.Forte@Sun.COM 
12117836SJohn.Forte@Sun.COM 		(void) fprintf(stdout,
12127836SJohn.Forte@Sun.COM 				MSGSTR(21107, "\n  Opening Device: %s\n"),
12137836SJohn.Forte@Sun.COM 				phys_path);
12147836SJohn.Forte@Sun.COM 
12157836SJohn.Forte@Sun.COM 		/* Check if the device is valid */
12167836SJohn.Forte@Sun.COM 		if ((fd = open(phys_path, O_RDWR)) < 0) {
12177836SJohn.Forte@Sun.COM 			(void) fprintf(stderr,
12187836SJohn.Forte@Sun.COM 			    MSGSTR(21121, "Error: Could not open %s, failed "
12197836SJohn.Forte@Sun.COM 				    "with errno %d\n"), phys_path, errno);
12207836SJohn.Forte@Sun.COM 			retval++;
12217836SJohn.Forte@Sun.COM 			node = di_drv_next_node(node);
12227836SJohn.Forte@Sun.COM 			continue;
12237836SJohn.Forte@Sun.COM 		}
12247836SJohn.Forte@Sun.COM 
12257836SJohn.Forte@Sun.COM 		(void) close(fd);
12267836SJohn.Forte@Sun.COM 
12277836SJohn.Forte@Sun.COM 		/*
12287836SJohn.Forte@Sun.COM 		 * Check FCode version present on the adapter
12297836SJohn.Forte@Sun.COM 		 * (at last boot)
12307836SJohn.Forte@Sun.COM 		 */
12317836SJohn.Forte@Sun.COM 		memset(prom_ver_data, 0, sizeof (prom_ver_data));
12327836SJohn.Forte@Sun.COM 		if (emulex_fcodeversion(node, (uchar_t *)&prom_ver_data[0])
12337836SJohn.Forte@Sun.COM 		    == 0) {
12347836SJohn.Forte@Sun.COM 			errnum = 0;
12357836SJohn.Forte@Sun.COM 			if (strlen((char *)prom_ver_data) == 0) {
12367836SJohn.Forte@Sun.COM 				(void) fprintf(stdout, MSGSTR(21108,
12377836SJohn.Forte@Sun.COM 	"  Detected FCode Version:\tNo version available for this FCode\n"));
12387836SJohn.Forte@Sun.COM 			} else {
12397836SJohn.Forte@Sun.COM 				(void) fprintf(stdout, MSGSTR(21109,
12407836SJohn.Forte@Sun.COM 				    "  Detected FCode Version:\t%s\n"),
12417836SJohn.Forte@Sun.COM 				    prom_ver_data);
12427836SJohn.Forte@Sun.COM 			}
12437836SJohn.Forte@Sun.COM 		} else {
12447836SJohn.Forte@Sun.COM 			errnum = 2; /* can't get prom properties */
12457836SJohn.Forte@Sun.COM 			retval++;
12467836SJohn.Forte@Sun.COM 		}
12477836SJohn.Forte@Sun.COM 
12487836SJohn.Forte@Sun.COM 		if (fflag) {
12497836SJohn.Forte@Sun.COM 
12507836SJohn.Forte@Sun.COM 			memset(ver_file, 0, sizeof (ver_file));
12517836SJohn.Forte@Sun.COM 			if (emulex_fcode_reader(fcode_fd, "fcode-version",
12527836SJohn.Forte@Sun.COM 				    ver_file, sizeof (ver_file)) == 0) {
12537836SJohn.Forte@Sun.COM 				(void) fprintf(stdout, MSGSTR(21110,
12547836SJohn.Forte@Sun.COM 					    "  New FCode Version:\t\t%s\n"),
12557836SJohn.Forte@Sun.COM 					    ver_file);
12567836SJohn.Forte@Sun.COM 			} else {
12577836SJohn.Forte@Sun.COM 				di_fini(root);
12587836SJohn.Forte@Sun.COM 				(void) close(fcode_fd);
12597836SJohn.Forte@Sun.COM 				return (1);
12607836SJohn.Forte@Sun.COM 			}
12617836SJohn.Forte@Sun.COM 
12627836SJohn.Forte@Sun.COM 			/*
12637836SJohn.Forte@Sun.COM 			 * Load the New FCode
12647836SJohn.Forte@Sun.COM 			 * Give warning if file doesn't appear to be correct
12657836SJohn.Forte@Sun.COM 			 */
12667836SJohn.Forte@Sun.COM 			if (!q_warn(errnum)) {
12677836SJohn.Forte@Sun.COM 				/* Disable user-interrupt Control-C */
12687836SJohn.Forte@Sun.COM 				sigint =
12697836SJohn.Forte@Sun.COM 				    (void (*)(int)) signal(SIGINT, SIG_IGN);
12707836SJohn.Forte@Sun.COM 				/* Load FCode */
12717836SJohn.Forte@Sun.COM 				(void) fprintf(stdout, MSGSTR(21111,
12727836SJohn.Forte@Sun.COM 					"  Loading FCode: %s\n"), file);
12737836SJohn.Forte@Sun.COM 				if (fcode_load_file(fcode_fd, phys_path,
12747836SJohn.Forte@Sun.COM 					    &fcio_errno) == FCODE_SUCCESS) {
12757836SJohn.Forte@Sun.COM 					(void) fprintf(stdout, MSGSTR(21112,
12767836SJohn.Forte@Sun.COM 					"  Successful FCode download: %s\n"),
12777836SJohn.Forte@Sun.COM 					phys_path);
12787836SJohn.Forte@Sun.COM 				} else {
12797836SJohn.Forte@Sun.COM 					handle_emulex_error(fcio_errno,
12807836SJohn.Forte@Sun.COM 					    phys_path);
12817836SJohn.Forte@Sun.COM 					retval++;
12827836SJohn.Forte@Sun.COM 				}
12837836SJohn.Forte@Sun.COM 
12847836SJohn.Forte@Sun.COM 				/* Restore SIGINT (user interrupt) setting */
12857836SJohn.Forte@Sun.COM 				(void) signal(SIGINT, sigint);
12867836SJohn.Forte@Sun.COM 			}
12877836SJohn.Forte@Sun.COM 		}
12887836SJohn.Forte@Sun.COM 
1289*8538SReed.Liu@Sun.COM 	try_next:
12907836SJohn.Forte@Sun.COM 		node = di_drv_next_node(node);
12917836SJohn.Forte@Sun.COM 	}
12927836SJohn.Forte@Sun.COM 
12937836SJohn.Forte@Sun.COM 	di_fini(root);
12947836SJohn.Forte@Sun.COM 	(void) fprintf(stdout, "  ");
12957836SJohn.Forte@Sun.COM 	(void) fprintf(stdout, MSGSTR(125, "Complete\n"));
12967836SJohn.Forte@Sun.COM 	if (fcode_fd != -1)
12977836SJohn.Forte@Sun.COM 		(void) close(fcode_fd);
12987836SJohn.Forte@Sun.COM 	return (retval);
12997836SJohn.Forte@Sun.COM 
13007836SJohn.Forte@Sun.COM }
13017836SJohn.Forte@Sun.COM 
13027836SJohn.Forte@Sun.COM /*
13037836SJohn.Forte@Sun.COM  * Retrieve the version from the card.
13047836SJohn.Forte@Sun.COM  *    uses PROM properties
13057836SJohn.Forte@Sun.COM  */
13067836SJohn.Forte@Sun.COM static int
emulex_fcodeversion(di_node_t node,uchar_t * ver)13077836SJohn.Forte@Sun.COM emulex_fcodeversion(di_node_t node, uchar_t *ver) {
13087836SJohn.Forte@Sun.COM 	di_prom_prop_t	    promprop;
13097836SJohn.Forte@Sun.COM 	di_prom_handle_t    ph;
13107836SJohn.Forte@Sun.COM 	char		    *promname;
13117836SJohn.Forte@Sun.COM 	uchar_t		    *ver_data = NULL;
13127836SJohn.Forte@Sun.COM 	int		    size, found = 0;
13137836SJohn.Forte@Sun.COM 
13147836SJohn.Forte@Sun.COM 	/* check to make sure ver is not NULL */
13157836SJohn.Forte@Sun.COM 	if (ver == NULL) {
13167836SJohn.Forte@Sun.COM 		return (1);
13177836SJohn.Forte@Sun.COM 	}
13187836SJohn.Forte@Sun.COM 
13197836SJohn.Forte@Sun.COM 	if ((ph = di_prom_init()) == DI_PROM_HANDLE_NIL) {
13207836SJohn.Forte@Sun.COM 		return (1);
13217836SJohn.Forte@Sun.COM 	}
13227836SJohn.Forte@Sun.COM 
13237836SJohn.Forte@Sun.COM 	for (promprop = di_prom_prop_next(ph, node,
13247836SJohn.Forte@Sun.COM 		DI_PROM_PROP_NIL);
13257836SJohn.Forte@Sun.COM 		promprop != DI_PROM_PROP_NIL;
13267836SJohn.Forte@Sun.COM 		promprop = di_prom_prop_next(ph, node, promprop)) {
13277836SJohn.Forte@Sun.COM 		if (((promname = di_prom_prop_name(
13287836SJohn.Forte@Sun.COM 			promprop)) != NULL) &&
13297836SJohn.Forte@Sun.COM 			(strcmp(promname, "fcode-version") == 0)) {
13307836SJohn.Forte@Sun.COM 			size = di_prom_prop_data(promprop, &ver_data);
13317836SJohn.Forte@Sun.COM 			(void) memset(ver, NULL, size);
13327836SJohn.Forte@Sun.COM 			(void) memcpy(ver, ver_data, size);
13337836SJohn.Forte@Sun.COM 			found = 1;
13347836SJohn.Forte@Sun.COM 		}
13357836SJohn.Forte@Sun.COM 	}
13367836SJohn.Forte@Sun.COM 
13377836SJohn.Forte@Sun.COM 	if (found) {
13387836SJohn.Forte@Sun.COM 		return (0);
13397836SJohn.Forte@Sun.COM 	} else {
13407836SJohn.Forte@Sun.COM 		return (1);
13417836SJohn.Forte@Sun.COM 	}
13427836SJohn.Forte@Sun.COM }
13437836SJohn.Forte@Sun.COM 
13447836SJohn.Forte@Sun.COM /*
13457836SJohn.Forte@Sun.COM  * Retrieves information from the Emulex fcode
13467836SJohn.Forte@Sun.COM  *
13477836SJohn.Forte@Sun.COM  * Given a pattern, this routine will look for this pattern in the fcode
13487836SJohn.Forte@Sun.COM  * file and if found will return the pattern value
13497836SJohn.Forte@Sun.COM  *
13507836SJohn.Forte@Sun.COM  * possible patterns are manufacturer and fcode-version
13517836SJohn.Forte@Sun.COM  */
13527836SJohn.Forte@Sun.COM int
emulex_fcode_reader(int fcode_fd,char * pattern,char * pattern_value,uint32_t pattern_value_size)13537836SJohn.Forte@Sun.COM emulex_fcode_reader(int fcode_fd, char *pattern, char *pattern_value,
13547836SJohn.Forte@Sun.COM     uint32_t pattern_value_size) {
13557836SJohn.Forte@Sun.COM 	int32_t i = 0;
13567836SJohn.Forte@Sun.COM 	uint32_t n = 0;
13577836SJohn.Forte@Sun.COM 	uint32_t b = 0;
13587836SJohn.Forte@Sun.COM 	char byte1;
13597836SJohn.Forte@Sun.COM 	char byte2;
13607836SJohn.Forte@Sun.COM 	char byte3;
13617836SJohn.Forte@Sun.COM 	char byte4;
13627836SJohn.Forte@Sun.COM 	char buffer1[EMULEX_READ_BUFFER_SIZE];
13637836SJohn.Forte@Sun.COM 	char buffer2[EMULEX_READ_BUFFER_SIZE];
13647836SJohn.Forte@Sun.COM 	uint32_t plen, image_size;
13657836SJohn.Forte@Sun.COM 	struct stat	stat;
13667836SJohn.Forte@Sun.COM 	uchar_t		*image;
13677836SJohn.Forte@Sun.COM 
13687836SJohn.Forte@Sun.COM 	/* Check the arguments */
13697836SJohn.Forte@Sun.COM 	if (!fcode_fd || !pattern_value || pattern_value_size < 8) {
13707836SJohn.Forte@Sun.COM 		return (1);
13717836SJohn.Forte@Sun.COM 	}
13727836SJohn.Forte@Sun.COM 
13737836SJohn.Forte@Sun.COM 	if (fstat(fcode_fd, &stat) == -1) {
13747836SJohn.Forte@Sun.COM 		perror(MSGSTR(21023, "fstat"));
13757836SJohn.Forte@Sun.COM 		return (1);
13767836SJohn.Forte@Sun.COM 	}
13777836SJohn.Forte@Sun.COM 	image_size = stat.st_size;
13787836SJohn.Forte@Sun.COM 	if (image_size < 2) {
13797836SJohn.Forte@Sun.COM 		return (1);
13807836SJohn.Forte@Sun.COM 	}
13817836SJohn.Forte@Sun.COM 	if ((image = (uchar_t *)calloc(image_size, 1)) == NULL) {
13827836SJohn.Forte@Sun.COM 		(void) fprintf(stderr,
13837836SJohn.Forte@Sun.COM 		    MSGSTR(21013, "Error: Memory allocation failed\n"));
13847836SJohn.Forte@Sun.COM 		return (1);
13857836SJohn.Forte@Sun.COM 	}
13867836SJohn.Forte@Sun.COM 
13877836SJohn.Forte@Sun.COM 	/* Read the fcode image file */
13887836SJohn.Forte@Sun.COM 	lseek(fcode_fd, 0, SEEK_SET);
13897836SJohn.Forte@Sun.COM 	read(fcode_fd, image, image_size);
13907836SJohn.Forte@Sun.COM 
13917836SJohn.Forte@Sun.COM 	/* Initialize */
13927836SJohn.Forte@Sun.COM 	bzero(buffer1, sizeof (buffer1));
13937836SJohn.Forte@Sun.COM 	bzero(buffer2, sizeof (buffer2));
13947836SJohn.Forte@Sun.COM 	/* Default pattern_value string */
13957836SJohn.Forte@Sun.COM 	strcpy((char *)pattern_value, "<unknown>");
13967836SJohn.Forte@Sun.COM 	plen = strlen(pattern);
13977836SJohn.Forte@Sun.COM 	n = 0;
13987836SJohn.Forte@Sun.COM 	b = 0;
13997836SJohn.Forte@Sun.COM 	i = 0;
14007836SJohn.Forte@Sun.COM 
14017836SJohn.Forte@Sun.COM 	/* Search entire image for pattern string */
14027836SJohn.Forte@Sun.COM 	while (i <= (image_size - 2)) {
14037836SJohn.Forte@Sun.COM 		/* Read next two bytes */
14047836SJohn.Forte@Sun.COM 		byte1 = image[i++];
14057836SJohn.Forte@Sun.COM 		byte2 = image[i++];
14067836SJohn.Forte@Sun.COM 
14077836SJohn.Forte@Sun.COM 		/* Check second byte first due to endianness */
14087836SJohn.Forte@Sun.COM 
14097836SJohn.Forte@Sun.COM 		/* Save byte in circular buffer */
14107836SJohn.Forte@Sun.COM 		buffer1[b++] = byte2;
14117836SJohn.Forte@Sun.COM 		if (b == sizeof (buffer1)) {
14127836SJohn.Forte@Sun.COM 			b = 0;
14137836SJohn.Forte@Sun.COM 		}
14147836SJohn.Forte@Sun.COM 
14157836SJohn.Forte@Sun.COM 		/* Check byte for pattern match */
14167836SJohn.Forte@Sun.COM 		if (pattern[n++] != byte2) {
14177836SJohn.Forte@Sun.COM 			/* If no match, then reset pattern */
14187836SJohn.Forte@Sun.COM 			n = 0;
14197836SJohn.Forte@Sun.COM 		} else {
14207836SJohn.Forte@Sun.COM 			/*
14217836SJohn.Forte@Sun.COM 			 * If complete pattern has been matched then
14227836SJohn.Forte@Sun.COM 			 * exit loop
14237836SJohn.Forte@Sun.COM 			 */
14247836SJohn.Forte@Sun.COM 			if (n == plen) {
14257836SJohn.Forte@Sun.COM 				goto found;
14267836SJohn.Forte@Sun.COM 			}
14277836SJohn.Forte@Sun.COM 		}
14287836SJohn.Forte@Sun.COM 
14297836SJohn.Forte@Sun.COM 
14307836SJohn.Forte@Sun.COM 		/* Check first byte second due to endianness */
14317836SJohn.Forte@Sun.COM 		/* Save byte in circular buffer */
14327836SJohn.Forte@Sun.COM 		buffer1[b++] = byte1;
14337836SJohn.Forte@Sun.COM 		if (b == sizeof (buffer1)) {
14347836SJohn.Forte@Sun.COM 			b = 0;
14357836SJohn.Forte@Sun.COM 		}
14367836SJohn.Forte@Sun.COM 		/* Check byte for pattern match */
14377836SJohn.Forte@Sun.COM 		if (pattern[n++] != byte1) {
14387836SJohn.Forte@Sun.COM 			/* If no match, then reset pattern */
14397836SJohn.Forte@Sun.COM 			n = 0;
14407836SJohn.Forte@Sun.COM 		} else {
14417836SJohn.Forte@Sun.COM 			/*
14427836SJohn.Forte@Sun.COM 			 * If complete pattern has been matched
14437836SJohn.Forte@Sun.COM 			 * then exit loop
14447836SJohn.Forte@Sun.COM 			 */
14457836SJohn.Forte@Sun.COM 			if (n == plen) {
14467836SJohn.Forte@Sun.COM 				goto found;
14477836SJohn.Forte@Sun.COM 			}
14487836SJohn.Forte@Sun.COM 		}
14497836SJohn.Forte@Sun.COM 	}
14507836SJohn.Forte@Sun.COM 
14517836SJohn.Forte@Sun.COM 	/* Not found.  Try again with different endianess */
14527836SJohn.Forte@Sun.COM 
14537836SJohn.Forte@Sun.COM 	/* Initialize */
14547836SJohn.Forte@Sun.COM 	bzero(buffer1, sizeof (buffer1));
14557836SJohn.Forte@Sun.COM 	bzero(buffer2, sizeof (buffer2));
14567836SJohn.Forte@Sun.COM 	n = 0;
14577836SJohn.Forte@Sun.COM 	b = 0;
14587836SJohn.Forte@Sun.COM 	i = 0;
14597836SJohn.Forte@Sun.COM 
14607836SJohn.Forte@Sun.COM 	/* Search entire 32bit endian image for pattern string */
14617836SJohn.Forte@Sun.COM 	while (i <= (image_size - 4)) {
14627836SJohn.Forte@Sun.COM 		/* Read next four bytes */
14637836SJohn.Forte@Sun.COM 		byte1 = image[i++];
14647836SJohn.Forte@Sun.COM 		byte2 = image[i++];
14657836SJohn.Forte@Sun.COM 		byte3 = image[i++];
14667836SJohn.Forte@Sun.COM 		byte4 = image[i++];
14677836SJohn.Forte@Sun.COM 
14687836SJohn.Forte@Sun.COM 		/* Save byte in circular buffer */
14697836SJohn.Forte@Sun.COM 		buffer1[b++] = byte4;
14707836SJohn.Forte@Sun.COM 		if (b == sizeof (buffer1)) {
14717836SJohn.Forte@Sun.COM 			b = 0;
14727836SJohn.Forte@Sun.COM 		}
14737836SJohn.Forte@Sun.COM 
14747836SJohn.Forte@Sun.COM 		/* Check byte for pattern match */
14757836SJohn.Forte@Sun.COM 		if (pattern[n++] != byte4) {
14767836SJohn.Forte@Sun.COM 			/* If no match, then reset pattern */
14777836SJohn.Forte@Sun.COM 			n = 0;
14787836SJohn.Forte@Sun.COM 		} else {
14797836SJohn.Forte@Sun.COM 			/*
14807836SJohn.Forte@Sun.COM 			 * If complete pattern has been matched then exit loop
14817836SJohn.Forte@Sun.COM 			 */
14827836SJohn.Forte@Sun.COM 			if (n == plen) {
14837836SJohn.Forte@Sun.COM 				goto found;
14847836SJohn.Forte@Sun.COM 			}
14857836SJohn.Forte@Sun.COM 		}
14867836SJohn.Forte@Sun.COM 
14877836SJohn.Forte@Sun.COM 		/* Save byte in circular buffer */
14887836SJohn.Forte@Sun.COM 		buffer1[b++] = byte3;
14897836SJohn.Forte@Sun.COM 		if (b == sizeof (buffer1)) {
14907836SJohn.Forte@Sun.COM 			b = 0;
14917836SJohn.Forte@Sun.COM 		}
14927836SJohn.Forte@Sun.COM 
14937836SJohn.Forte@Sun.COM 		/* Check byte for pattern match */
14947836SJohn.Forte@Sun.COM 		if (pattern[n++] != byte3) {
14957836SJohn.Forte@Sun.COM 			/* If no match, then reset pattern */
14967836SJohn.Forte@Sun.COM 			n = 0;
14977836SJohn.Forte@Sun.COM 		} else {
14987836SJohn.Forte@Sun.COM 			/*
14997836SJohn.Forte@Sun.COM 			 * If complete pattern has been matched then exit loop
15007836SJohn.Forte@Sun.COM 			 */
15017836SJohn.Forte@Sun.COM 			if (n == plen) {
15027836SJohn.Forte@Sun.COM 				goto found;
15037836SJohn.Forte@Sun.COM 			}
15047836SJohn.Forte@Sun.COM 		}
15057836SJohn.Forte@Sun.COM 
15067836SJohn.Forte@Sun.COM 		/* Save byte in circular buffer */
15077836SJohn.Forte@Sun.COM 		buffer1[b++] = byte2;
15087836SJohn.Forte@Sun.COM 		if (b == sizeof (buffer1)) {
15097836SJohn.Forte@Sun.COM 			b = 0;
15107836SJohn.Forte@Sun.COM 		}
15117836SJohn.Forte@Sun.COM 
15127836SJohn.Forte@Sun.COM 		/* Check byte for pattern match */
15137836SJohn.Forte@Sun.COM 		if (pattern[n++] != byte2) {
15147836SJohn.Forte@Sun.COM 			/* If no match, then reset pattern */
15157836SJohn.Forte@Sun.COM 			n = 0;
15167836SJohn.Forte@Sun.COM 		} else {
15177836SJohn.Forte@Sun.COM 			/*
15187836SJohn.Forte@Sun.COM 			 * If complete pattern has been matched then exit loop
15197836SJohn.Forte@Sun.COM 			 */
15207836SJohn.Forte@Sun.COM 			if (n == plen) {
15217836SJohn.Forte@Sun.COM 				goto found;
15227836SJohn.Forte@Sun.COM 			}
15237836SJohn.Forte@Sun.COM 		}
15247836SJohn.Forte@Sun.COM 
15257836SJohn.Forte@Sun.COM 		/* Save byte in circular buffer */
15267836SJohn.Forte@Sun.COM 		buffer1[b++] = byte1;
15277836SJohn.Forte@Sun.COM 		if (b == sizeof (buffer1)) {
15287836SJohn.Forte@Sun.COM 			b = 0;
15297836SJohn.Forte@Sun.COM 		}
15307836SJohn.Forte@Sun.COM 
15317836SJohn.Forte@Sun.COM 		/* Check byte for pattern match */
15327836SJohn.Forte@Sun.COM 		if (pattern[n++] != byte1) {
15337836SJohn.Forte@Sun.COM 			/* If no match, then reset pattern */
15347836SJohn.Forte@Sun.COM 			n = 0;
15357836SJohn.Forte@Sun.COM 		} else {
15367836SJohn.Forte@Sun.COM 			/*
15377836SJohn.Forte@Sun.COM 			 * If complete pattern has been matched then exit loop
15387836SJohn.Forte@Sun.COM 			 */
15397836SJohn.Forte@Sun.COM 			if (n == plen) {
15407836SJohn.Forte@Sun.COM 				goto found;
15417836SJohn.Forte@Sun.COM 			}
15427836SJohn.Forte@Sun.COM 		}
15437836SJohn.Forte@Sun.COM 	}
15447836SJohn.Forte@Sun.COM 
15457836SJohn.Forte@Sun.COM 	free(image);
15467836SJohn.Forte@Sun.COM 	return (1);
15477836SJohn.Forte@Sun.COM 
15487836SJohn.Forte@Sun.COM found:
15497836SJohn.Forte@Sun.COM 	free(image);
15507836SJohn.Forte@Sun.COM 
15517836SJohn.Forte@Sun.COM 	/* Align buffer and eliminate non-printable characters */
15527836SJohn.Forte@Sun.COM 	for (i = 0; i < (sizeof (buffer1)-plen); i++) {
15537836SJohn.Forte@Sun.COM 		byte1 = buffer1[b++];
15547836SJohn.Forte@Sun.COM 		if (b == sizeof (buffer1)) {
15557836SJohn.Forte@Sun.COM 			b = 0;
15567836SJohn.Forte@Sun.COM 		}
15577836SJohn.Forte@Sun.COM 		/* Zero any non-printable characters */
15587836SJohn.Forte@Sun.COM 		if (byte1 >= 33 && byte1 <= 126) {
15597836SJohn.Forte@Sun.COM 			buffer2[i] = byte1;
15607836SJohn.Forte@Sun.COM 		} else {
15617836SJohn.Forte@Sun.COM 			buffer2[i] = 0;
15627836SJohn.Forte@Sun.COM 		}
15637836SJohn.Forte@Sun.COM 	}
15647836SJohn.Forte@Sun.COM 
15657836SJohn.Forte@Sun.COM 	/*
15667836SJohn.Forte@Sun.COM 	 *  Scan backwards for first non-zero string. This will be the
15677836SJohn.Forte@Sun.COM 	 *  version string
15687836SJohn.Forte@Sun.COM 	 */
15697836SJohn.Forte@Sun.COM 	for (i = sizeof (buffer1)-plen-1; i >= 0; i--) {
15707836SJohn.Forte@Sun.COM 		if (buffer2[i] != 0) {
15717836SJohn.Forte@Sun.COM 			for (; i >= 0; i--) {
15727836SJohn.Forte@Sun.COM 				if (buffer2[i] == 0) {
15737836SJohn.Forte@Sun.COM 					i++;
15747836SJohn.Forte@Sun.COM 					strncpy((char *)pattern_value,
15757836SJohn.Forte@Sun.COM 					    &buffer2[i], pattern_value_size);
15767836SJohn.Forte@Sun.COM 					break;
15777836SJohn.Forte@Sun.COM 				}
15787836SJohn.Forte@Sun.COM 			}
15797836SJohn.Forte@Sun.COM 			break;
15807836SJohn.Forte@Sun.COM 		}
15817836SJohn.Forte@Sun.COM 	}
15827836SJohn.Forte@Sun.COM 	return (0);
15837836SJohn.Forte@Sun.COM }
15847836SJohn.Forte@Sun.COM 
15857836SJohn.Forte@Sun.COM /*
15867836SJohn.Forte@Sun.COM  * error handling routine to handle emulex error conditions
15877836SJohn.Forte@Sun.COM  */
15887836SJohn.Forte@Sun.COM static void
handle_emulex_error(int fcio_errno,char * phys_path)15897836SJohn.Forte@Sun.COM handle_emulex_error(int fcio_errno, char *phys_path) {
15907836SJohn.Forte@Sun.COM 	if (fcio_errno == EMLX_IMAGE_BAD) {
15917836SJohn.Forte@Sun.COM 		fprintf(stderr, MSGSTR(21119,
15927836SJohn.Forte@Sun.COM 			    "Error: Fcode download failed.  "
15937836SJohn.Forte@Sun.COM 			    "Bad fcode image.\n"));
15947836SJohn.Forte@Sun.COM 	} else if (fcio_errno == EMLX_IMAGE_INCOMPATIBLE) {
15957836SJohn.Forte@Sun.COM 		fprintf(stderr, MSGSTR(21120,
15967836SJohn.Forte@Sun.COM 			    "Error: Fcode download failed.  Fcode is not "
15977836SJohn.Forte@Sun.COM 			    "compatible with card.\n"));
15987836SJohn.Forte@Sun.COM 	} else {
15997836SJohn.Forte@Sun.COM 		(void) fprintf(stderr, MSGSTR(21036,
16007836SJohn.Forte@Sun.COM 		    "Error: Driver interface FCIO_DOWNLOAD_FCODE failed\n"));
16017836SJohn.Forte@Sun.COM 		(void) fprintf(stderr,
16027836SJohn.Forte@Sun.COM 			MSGSTR(21113,
16037836SJohn.Forte@Sun.COM 				"Error: FCode download failed: %s\n"),
16047836SJohn.Forte@Sun.COM 				phys_path);
16057836SJohn.Forte@Sun.COM 	}
16067836SJohn.Forte@Sun.COM }
1607