xref: /titanic_53/usr/src/cmd/luxadm/qlgcupdate.c (revision fcf3ce441efd61da9bb2884968af01cb7c1452cc)
1*fcf3ce44SJohn Forte /*
2*fcf3ce44SJohn Forte  * CDDL HEADER START
3*fcf3ce44SJohn Forte  *
4*fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5*fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6*fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7*fcf3ce44SJohn Forte  *
8*fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10*fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11*fcf3ce44SJohn Forte  * and limitations under the License.
12*fcf3ce44SJohn Forte  *
13*fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14*fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16*fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17*fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18*fcf3ce44SJohn Forte  *
19*fcf3ce44SJohn Forte  * CDDL HEADER END
20*fcf3ce44SJohn Forte  */
21*fcf3ce44SJohn Forte /*
22*fcf3ce44SJohn Forte  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*fcf3ce44SJohn Forte  * Use is subject to license terms.
24*fcf3ce44SJohn Forte  */
25*fcf3ce44SJohn Forte 
26*fcf3ce44SJohn Forte /*
27*fcf3ce44SJohn Forte  * I18N message number ranges
28*fcf3ce44SJohn Forte  *  This file: 21000 - 21499
29*fcf3ce44SJohn Forte  *  Shared common messages: 1 - 1999
30*fcf3ce44SJohn Forte  */
31*fcf3ce44SJohn Forte 
32*fcf3ce44SJohn Forte 
33*fcf3ce44SJohn Forte 
34*fcf3ce44SJohn Forte /*
35*fcf3ce44SJohn Forte  * Functions to support the download of FCode to PCI HBAs
36*fcf3ce44SJohn Forte  * Qlogic ISP21XX/22XX boards: FC100/P single port, ISP2200 dual port
37*fcf3ce44SJohn Forte  * and Emulex cards
38*fcf3ce44SJohn Forte  */
39*fcf3ce44SJohn Forte #include <errno.h>
40*fcf3ce44SJohn Forte #include <ctype.h>
41*fcf3ce44SJohn Forte #include <fcntl.h>
42*fcf3ce44SJohn Forte #include <stdio.h>
43*fcf3ce44SJohn Forte #include <string.h>
44*fcf3ce44SJohn Forte #include <strings.h>
45*fcf3ce44SJohn Forte #include <unistd.h>
46*fcf3ce44SJohn Forte #include <stdlib.h>
47*fcf3ce44SJohn Forte #include <sys/stat.h>
48*fcf3ce44SJohn Forte #include <limits.h>
49*fcf3ce44SJohn Forte #include <signal.h>
50*fcf3ce44SJohn Forte #include <dirent.h>
51*fcf3ce44SJohn Forte #include <nl_types.h>
52*fcf3ce44SJohn Forte #include <utmpx.h>
53*fcf3ce44SJohn Forte #include <sys/mnttab.h>
54*fcf3ce44SJohn Forte #include <sys/file.h>
55*fcf3ce44SJohn Forte #include <sys/mtio.h>
56*fcf3ce44SJohn Forte #include <sys/scsi/impl/uscsi.h>
57*fcf3ce44SJohn Forte #include <sys/fibre-channel/fcio.h>
58*fcf3ce44SJohn Forte #include <stgcom.h>
59*fcf3ce44SJohn Forte #include <sys/scsi/adapters/ifpio.h>
60*fcf3ce44SJohn Forte #include <libdevinfo.h>
61*fcf3ce44SJohn Forte #include "luxadm.h"
62*fcf3ce44SJohn Forte 
63*fcf3ce44SJohn Forte /* Error codes - used by the fcode_load_file routine */
64*fcf3ce44SJohn Forte #define	FCODE_SUCCESS	    0	/* successful completion */
65*fcf3ce44SJohn Forte #define	FCODE_LOAD_FAILURE  1	/* general failure */
66*fcf3ce44SJohn Forte #define	FCODE_IOCTL_FAILURE 2	/* FCODE ioctl download failure */
67*fcf3ce44SJohn Forte 
68*fcf3ce44SJohn Forte #define	HBA_MAX	128
69*fcf3ce44SJohn Forte #define	FCODE_HDR 200
70*fcf3ce44SJohn Forte #define	MAX_RETRIES	3
71*fcf3ce44SJohn Forte #define	MAX_WAIT_TIME	30
72*fcf3ce44SJohn Forte 
73*fcf3ce44SJohn Forte /*
74*fcf3ce44SJohn Forte  * EMULEX Fcode attributes
75*fcf3ce44SJohn Forte  */
76*fcf3ce44SJohn Forte #define	EMULEX_FCODE_VERSION_LENGTH	16
77*fcf3ce44SJohn Forte #define	EMULEX_READ_BUFFER_SIZE		128
78*fcf3ce44SJohn Forte 
79*fcf3ce44SJohn Forte /* Emulex specific error codes */
80*fcf3ce44SJohn Forte #define	EMLX_ERRNO_START	0x100
81*fcf3ce44SJohn Forte 
82*fcf3ce44SJohn Forte /* Diagnostic error codes */
83*fcf3ce44SJohn Forte #define	EMLX_TEST_FAILED	(EMLX_ERRNO_START + 0)
84*fcf3ce44SJohn Forte 
85*fcf3ce44SJohn Forte /* Download image contains bad data */
86*fcf3ce44SJohn Forte #define	EMLX_IMAGE_BAD		(EMLX_ERRNO_START + 1)
87*fcf3ce44SJohn Forte /* Download image not compatible with current hardware */
88*fcf3ce44SJohn Forte #define	EMLX_IMAGE_INCOMPATIBLE	(EMLX_ERRNO_START + 2)
89*fcf3ce44SJohn Forte /* Unable to take adapter offline */
90*fcf3ce44SJohn Forte #define	EMLX_IMAGE_FAILED	(EMLX_ERRNO_START + 3)
91*fcf3ce44SJohn Forte /* Image download failed */
92*fcf3ce44SJohn Forte #define	EMLX_OFFLINE_FAILED	(EMLX_ERRNO_START + 4)
93*fcf3ce44SJohn Forte 
94*fcf3ce44SJohn Forte 
95*fcf3ce44SJohn Forte 
96*fcf3ce44SJohn Forte 
97*fcf3ce44SJohn Forte /*
98*fcf3ce44SJohn Forte  * This is just a random value chosen to identify Sbus Fcodes. Sbus FCode
99*fcf3ce44SJohn Forte  * for Ivory is based on a 2200 chip but this value does not reflect that.
100*fcf3ce44SJohn Forte  */
101*fcf3ce44SJohn Forte #define	SBUS_CHIP_ID	0x1969
102*fcf3ce44SJohn Forte #define	IVORY_BUS	"/sbus@"
103*fcf3ce44SJohn Forte #define	IVORY_DRVR	"/SUNW,qlc@"
104*fcf3ce44SJohn Forte 
105*fcf3ce44SJohn Forte /*	Global variables	*/
106*fcf3ce44SJohn Forte static char	fc_trans[] = "SUNW,ifp";	/* fibre channel transport */
107*fcf3ce44SJohn Forte static char	fp_trans[] = "SUNW,qlc";	/* fca layer driver	   */
108*fcf3ce44SJohn Forte static char	fp_trans_id[] = "fp@";		/* transport layer id	   */
109*fcf3ce44SJohn Forte static char	qlgc2100[] = "FC100/P";		/* product name for 2100   */
110*fcf3ce44SJohn Forte static char	qlgc2200[] = "ISP2200";		/* product name for 2200   */
111*fcf3ce44SJohn Forte static char	qlgc2300[] = "ISP2300";		/* product name for 2300   */
112*fcf3ce44SJohn Forte static char	qlgc2312[] = "ISP2312";		/* product name for 2312   */
113*fcf3ce44SJohn Forte /*
114*fcf3ce44SJohn Forte  * The variable qlgc2200Sbus represents the string which is always the
115*fcf3ce44SJohn Forte  * starting string of the version information in an ISP2200 Sbus Fcode.
116*fcf3ce44SJohn Forte  */
117*fcf3ce44SJohn Forte static char	qlgc2200Sbus[] = "ISP2200 Sbus FC-AL Host Adapter Driver";
118*fcf3ce44SJohn Forte static char	pcibus_list[HBA_MAX][PATH_MAX];
119*fcf3ce44SJohn Forte /*	Internal functions	*/
120*fcf3ce44SJohn Forte static int	q_load_file(int, char *);
121*fcf3ce44SJohn Forte static int	q_getbootdev(uchar_t *);
122*fcf3ce44SJohn Forte static int	q_getdevctlpath(char *, int *);
123*fcf3ce44SJohn Forte static int	q_warn(int);
124*fcf3ce44SJohn Forte static int	q_findversion(int, int, uchar_t *, uint16_t *);
125*fcf3ce44SJohn Forte static int 	q_findfileversion(char *, uchar_t *, uint16_t *, int, int *);
126*fcf3ce44SJohn Forte static int 	q_findSbusfile(int, int *);
127*fcf3ce44SJohn Forte static int	memstrstr(char *, char *, int, int);
128*fcf3ce44SJohn Forte static int	fcode_load_file(int, char *, int *);
129*fcf3ce44SJohn Forte 
130*fcf3ce44SJohn Forte /*
131*fcf3ce44SJohn Forte  * Functions to support Fcode download for Emulex HBAs
132*fcf3ce44SJohn Forte  */
133*fcf3ce44SJohn Forte static int	emulex_fcodeversion(di_node_t, uchar_t *);
134*fcf3ce44SJohn Forte static void	handle_emulex_error(int, char *);
135*fcf3ce44SJohn Forte 
136*fcf3ce44SJohn Forte /*
137*fcf3ce44SJohn Forte  * Searches for and updates the cards.  This is the "main" function
138*fcf3ce44SJohn Forte  * and will give the output to the user by calling the subfunctions.
139*fcf3ce44SJohn Forte  * args: FCode file; if NULL only the current FCode version is printed
140*fcf3ce44SJohn Forte  */
141*fcf3ce44SJohn Forte int
142*fcf3ce44SJohn Forte q_qlgc_update(unsigned int verbose, char *file)
143*fcf3ce44SJohn Forte /*ARGSUSED*/
144*fcf3ce44SJohn Forte {
145*fcf3ce44SJohn Forte 	int fd, fcode_fd = -1, errnum = 0, devcnt = 0, retval = 0, isSbus = 0;
146*fcf3ce44SJohn Forte 	int sbus_off;
147*fcf3ce44SJohn Forte 	uint_t i, fflag = 0;
148*fcf3ce44SJohn Forte 	uint16_t chip_id = 0, file_id = 0;
149*fcf3ce44SJohn Forte 	uchar_t fcode_buf[FCODE_HDR];
150*fcf3ce44SJohn Forte 	static uchar_t	bootpath[PATH_MAX];
151*fcf3ce44SJohn Forte 	static uchar_t	version[MAXNAMELEN], version_file[MAXNAMELEN];
152*fcf3ce44SJohn Forte 	char devpath[PATH_MAX], tmppath[PATH_MAX];
153*fcf3ce44SJohn Forte 	void	(*sigint)(); /* to store default SIGTERM setting */
154*fcf3ce44SJohn Forte 	static struct	utmpx *utmpp = NULL; /* pointer for getutxent() */
155*fcf3ce44SJohn Forte 	char *ptr1, *ptr2;
156*fcf3ce44SJohn Forte 	char phys_path[PATH_MAX];
157*fcf3ce44SJohn Forte 	/*
158*fcf3ce44SJohn Forte 	 * The variables port1 and port2 are used to store the bus id
159*fcf3ce44SJohn Forte 	 * e.g. the bus id for this path:
160*fcf3ce44SJohn Forte 	 * /devices/sbus@12,0/SUNW,qlc@2,30000/fp@0,0:devctl
161*fcf3ce44SJohn Forte 	 * is "sbus@12". They are initialized to a random value and are
162*fcf3ce44SJohn Forte 	 * set such that they are not equal initially.
163*fcf3ce44SJohn Forte 	 */
164*fcf3ce44SJohn Forte 	static char port1[MAXNAMELEN] = {NULL};
165*fcf3ce44SJohn Forte 	static char port2[MAXNAMELEN] = {NULL};
166*fcf3ce44SJohn Forte 
167*fcf3ce44SJohn Forte 	if (file) {
168*fcf3ce44SJohn Forte 		fflag++;
169*fcf3ce44SJohn Forte 
170*fcf3ce44SJohn Forte 		/* check for a valid file */
171*fcf3ce44SJohn Forte 		if ((fcode_fd = open(file, O_RDONLY)) < 0) {
172*fcf3ce44SJohn Forte 			(void) fprintf(stderr,
173*fcf3ce44SJohn Forte 			    MSGSTR(21000, "Error: Could not open %s\n"), file);
174*fcf3ce44SJohn Forte 			return (1);
175*fcf3ce44SJohn Forte 		}
176*fcf3ce44SJohn Forte 		if (read(fcode_fd, fcode_buf, FCODE_HDR) != FCODE_HDR) {
177*fcf3ce44SJohn Forte 			perror(MSGSTR(21001, "read"));
178*fcf3ce44SJohn Forte 			(void) close(fcode_fd);
179*fcf3ce44SJohn Forte 			return (1);
180*fcf3ce44SJohn Forte 		}
181*fcf3ce44SJohn Forte 
182*fcf3ce44SJohn Forte 		/*
183*fcf3ce44SJohn Forte 		 * Check if it's SBUS FCode by calling q_findSbusfile
184*fcf3ce44SJohn Forte 		 * if it is then isSbus will be 1, if not it will be 0
185*fcf3ce44SJohn Forte 		 * in case of an error, it will be -1
186*fcf3ce44SJohn Forte 		 */
187*fcf3ce44SJohn Forte 		isSbus = q_findSbusfile(fcode_fd, &sbus_off);
188*fcf3ce44SJohn Forte 		if (isSbus == -1) {
189*fcf3ce44SJohn Forte 			(void) close(fcode_fd);
190*fcf3ce44SJohn Forte 			return (1);
191*fcf3ce44SJohn Forte 		}
192*fcf3ce44SJohn Forte 
193*fcf3ce44SJohn Forte 		/*
194*fcf3ce44SJohn Forte 		 * FCode header check - make sure it's PCI FCode
195*fcf3ce44SJohn Forte 		 * Structure of FCode header (byte# refers to byte numbering
196*fcf3ce44SJohn Forte 		 * in FCode spec, not the byte# of our fcode_buf buffer):
197*fcf3ce44SJohn Forte 		 * header	byte 00    0x55  prom signature byte one
198*fcf3ce44SJohn Forte 		 *		byte 01    0xaa  prom signature byte two
199*fcf3ce44SJohn Forte 		 * data		byte 00-03 P C I R
200*fcf3ce44SJohn Forte 		 * OR
201*fcf3ce44SJohn Forte 		 * header	byte 32    0x55
202*fcf3ce44SJohn Forte 		 *		byte 33    0xaa
203*fcf3ce44SJohn Forte 		 * data		byte 60-63 P C I R
204*fcf3ce44SJohn Forte 		 * The second format with an offset of 32 is used for ifp prom
205*fcf3ce44SJohn Forte 		 */
206*fcf3ce44SJohn Forte 		if (!(((fcode_buf[0x00] == 0x55) &&
207*fcf3ce44SJohn Forte 		    (fcode_buf[0x01] == 0xaa) &&
208*fcf3ce44SJohn Forte 		    (fcode_buf[0x1c] == 'P') &&
209*fcf3ce44SJohn Forte 		    (fcode_buf[0x1d] == 'C') &&
210*fcf3ce44SJohn Forte 		    (fcode_buf[0x1e] == 'I') &&
211*fcf3ce44SJohn Forte 		    (fcode_buf[0x1f] == 'R')) ||
212*fcf3ce44SJohn Forte 
213*fcf3ce44SJohn Forte 		    ((fcode_buf[0x20] == 0x55) &&
214*fcf3ce44SJohn Forte 		    (fcode_buf[0x21] == 0xaa) &&
215*fcf3ce44SJohn Forte 		    (fcode_buf[0x3c] == 'P') &&
216*fcf3ce44SJohn Forte 		    (fcode_buf[0x3d] == 'C') &&
217*fcf3ce44SJohn Forte 		    (fcode_buf[0x3e] == 'I') &&
218*fcf3ce44SJohn Forte 		    (fcode_buf[0x3f] == 'R')) ||
219*fcf3ce44SJohn Forte 
220*fcf3ce44SJohn Forte 		    (isSbus))) {
221*fcf3ce44SJohn Forte 			(void) fprintf(stderr, MSGSTR(21002,
222*fcf3ce44SJohn Forte 			    "Error: %s is not a valid FC100/P, "
223*fcf3ce44SJohn Forte 			    "ISP2200, ISP23xx FCode file.\n"),
224*fcf3ce44SJohn Forte 			    file);
225*fcf3ce44SJohn Forte 			(void) close(fcode_fd);
226*fcf3ce44SJohn Forte 			return (1);
227*fcf3ce44SJohn Forte 		}
228*fcf3ce44SJohn Forte 
229*fcf3ce44SJohn Forte 		/* check for single user mode */
230*fcf3ce44SJohn Forte 		while ((utmpp = getutxent()) != NULL) {
231*fcf3ce44SJohn Forte 			if (strstr(utmpp->ut_line, "run-level") &&
232*fcf3ce44SJohn Forte 			    (strcmp(utmpp->ut_line, "run-level S") &&
233*fcf3ce44SJohn Forte 				strcmp(utmpp->ut_line, "run-level 1"))) {
234*fcf3ce44SJohn Forte 				if (q_warn(1)) {
235*fcf3ce44SJohn Forte 					(void) endutxent();
236*fcf3ce44SJohn Forte 					(void) close(fcode_fd);
237*fcf3ce44SJohn Forte 					return (1);
238*fcf3ce44SJohn Forte 				}
239*fcf3ce44SJohn Forte 				break;
240*fcf3ce44SJohn Forte 			}
241*fcf3ce44SJohn Forte 		}
242*fcf3ce44SJohn Forte 		(void) endutxent();
243*fcf3ce44SJohn Forte 
244*fcf3ce44SJohn Forte 		/* get bootpath */
245*fcf3ce44SJohn Forte 		if (!q_getbootdev((uchar_t *)&bootpath[0]) &&
246*fcf3ce44SJohn Forte 		    getenv("_LUX_D_DEBUG") != NULL) {
247*fcf3ce44SJohn Forte 			(void) fprintf(stdout, "  Bootpath: %s\n", bootpath);
248*fcf3ce44SJohn Forte 		}
249*fcf3ce44SJohn Forte 	}
250*fcf3ce44SJohn Forte 	/*
251*fcf3ce44SJohn Forte 	 * Get count of, and names of PCI slots with ifp device control
252*fcf3ce44SJohn Forte 	 * (devctl) nodes.  Search /devices.
253*fcf3ce44SJohn Forte 	 */
254*fcf3ce44SJohn Forte 	(void) strcpy(devpath, "/devices");
255*fcf3ce44SJohn Forte 	if (q_getdevctlpath(devpath, (int *)&devcnt) == 0) {
256*fcf3ce44SJohn Forte 		(void) fprintf(stdout, MSGSTR(21003,
257*fcf3ce44SJohn Forte 		"\n  Found Path to %d FC100/P, ISP2200, ISP23xx Devices\n"),
258*fcf3ce44SJohn Forte 			devcnt);
259*fcf3ce44SJohn Forte 	} else {
260*fcf3ce44SJohn Forte 		(void) fprintf(stderr, MSGSTR(21004,
261*fcf3ce44SJohn Forte 		"Error: Could not get /devices path to FC100/P,"
262*fcf3ce44SJohn Forte 		"ISP2200, ISP23xx Cards.\n"));
263*fcf3ce44SJohn Forte 		retval++;
264*fcf3ce44SJohn Forte 	}
265*fcf3ce44SJohn Forte 
266*fcf3ce44SJohn Forte 	for (i = 0; i < devcnt; i++) {
267*fcf3ce44SJohn Forte 
268*fcf3ce44SJohn Forte 		(void) strncpy((char *)phys_path, &pcibus_list[i][0],
269*fcf3ce44SJohn Forte 				strlen(&pcibus_list[i][0]));
270*fcf3ce44SJohn Forte 		if (fflag && (strstr((char *)bootpath,
271*fcf3ce44SJohn Forte 		    strtok((char *)phys_path, ":")) != NULL)) {
272*fcf3ce44SJohn Forte 			(void) fprintf(stderr,
273*fcf3ce44SJohn Forte 			    MSGSTR(21005, "Ignoring %s (bootpath)\n"),
274*fcf3ce44SJohn Forte 			    &pcibus_list[i][0]);
275*fcf3ce44SJohn Forte 			continue;
276*fcf3ce44SJohn Forte 		}
277*fcf3ce44SJohn Forte 
278*fcf3ce44SJohn Forte 		(void) fprintf(stdout,
279*fcf3ce44SJohn Forte 		MSGSTR(21006, "\n  Opening Device: %s\n"), &pcibus_list[i][0]);
280*fcf3ce44SJohn Forte 		/* Check if the device is valid */
281*fcf3ce44SJohn Forte 		if ((fd = open(&pcibus_list[i][0], O_RDWR)) < 0) {
282*fcf3ce44SJohn Forte 			(void) fprintf(stderr,
283*fcf3ce44SJohn Forte 			    MSGSTR(21000, "Error: Could not open %s\n"),
284*fcf3ce44SJohn Forte 			    &pcibus_list[i][0]);
285*fcf3ce44SJohn Forte 			retval++;
286*fcf3ce44SJohn Forte 			continue;
287*fcf3ce44SJohn Forte 		}
288*fcf3ce44SJohn Forte 		(void) close(fd);
289*fcf3ce44SJohn Forte 		/*
290*fcf3ce44SJohn Forte 		 * Check FCode version present on the adapter (at last boot)
291*fcf3ce44SJohn Forte 		 */
292*fcf3ce44SJohn Forte 		if (q_findversion(verbose, i, (uchar_t *)&version[0],
293*fcf3ce44SJohn Forte 		    &chip_id) == 0) {
294*fcf3ce44SJohn Forte 			if (strlen((char *)version) == 0) {
295*fcf3ce44SJohn Forte 				(void) fprintf(stdout, MSGSTR(21007,
296*fcf3ce44SJohn Forte 	"  Detected FCode Version:\tNo version available for this FCode\n"));
297*fcf3ce44SJohn Forte 			} else {
298*fcf3ce44SJohn Forte 			(void) fprintf(stdout, MSGSTR(21008,
299*fcf3ce44SJohn Forte 			    "  Detected FCode Version:\t%s\n"), version);
300*fcf3ce44SJohn Forte 			}
301*fcf3ce44SJohn Forte 		} else {
302*fcf3ce44SJohn Forte 			chip_id = 0x0;
303*fcf3ce44SJohn Forte 		}
304*fcf3ce44SJohn Forte 
305*fcf3ce44SJohn Forte 		if (fflag) {
306*fcf3ce44SJohn Forte 			/*
307*fcf3ce44SJohn Forte 			 * For ISP2200, Sbus HBA, do just 1 download
308*fcf3ce44SJohn Forte 			 * for both the ports (dual port HBA)
309*fcf3ce44SJohn Forte 			 * Here it is assumed that readdir() always
310*fcf3ce44SJohn Forte 			 * returns the paths in pcibus_list[] in the
311*fcf3ce44SJohn Forte 			 * sorted order.
312*fcf3ce44SJohn Forte 			 */
313*fcf3ce44SJohn Forte 			(void) strcpy(tmppath, pcibus_list[i]);
314*fcf3ce44SJohn Forte 			if (ptr1 = strstr(tmppath, IVORY_BUS)) {
315*fcf3ce44SJohn Forte 				if (ptr2 = strstr(ptr1, IVORY_DRVR)) {
316*fcf3ce44SJohn Forte 					ptr2 = strchr(ptr2, ',');
317*fcf3ce44SJohn Forte 					if (ptr2 = strchr(++ptr2, ',')) {
318*fcf3ce44SJohn Forte 						*ptr2 = '\0';
319*fcf3ce44SJohn Forte 					}
320*fcf3ce44SJohn Forte 				}
321*fcf3ce44SJohn Forte 				(void) strcpy(port2, ptr1);
322*fcf3ce44SJohn Forte 				if (strcmp(port1, port2) == 0) {
323*fcf3ce44SJohn Forte 				    (void) fprintf(stdout, MSGSTR(21037,
324*fcf3ce44SJohn Forte 				    "/n New FCode has already been downloaded "
325*fcf3ce44SJohn Forte 				    "to this ISP2200 SBus HBA Card.\n"
326*fcf3ce44SJohn Forte 				    "It is sufficient to download to one "
327*fcf3ce44SJohn Forte 				    "port of the ISP2200 SBus HBA Card. "
328*fcf3ce44SJohn Forte 				    "Moving on...\n"));
329*fcf3ce44SJohn Forte 					continue;
330*fcf3ce44SJohn Forte 				}
331*fcf3ce44SJohn Forte 			}
332*fcf3ce44SJohn Forte 			/*
333*fcf3ce44SJohn Forte 			 * Check version of the supplied FCode file (once)
334*fcf3ce44SJohn Forte 			 */
335*fcf3ce44SJohn Forte 			if ((file_id != 0 && version_file != NULL) ||
336*fcf3ce44SJohn Forte 			    (q_findfileversion((char *)
337*fcf3ce44SJohn Forte 			    &fcode_buf[0], (uchar_t *)&version_file[0],
338*fcf3ce44SJohn Forte 			    &file_id, isSbus, &sbus_off) == 0)) {
339*fcf3ce44SJohn Forte 				(void) fprintf(stdout, MSGSTR(21009,
340*fcf3ce44SJohn Forte 				    "  New FCode Version:\t\t%s\n"),
341*fcf3ce44SJohn Forte 				    version_file);
342*fcf3ce44SJohn Forte 			} else {
343*fcf3ce44SJohn Forte 				(void) close(fcode_fd);
344*fcf3ce44SJohn Forte 				return (1);
345*fcf3ce44SJohn Forte 			}
346*fcf3ce44SJohn Forte 
347*fcf3ce44SJohn Forte 			/*
348*fcf3ce44SJohn Forte 			 * Load the New FCode
349*fcf3ce44SJohn Forte 			 * Give warning if file doesn't appear to be correct
350*fcf3ce44SJohn Forte 			 *
351*fcf3ce44SJohn Forte 			 */
352*fcf3ce44SJohn Forte 			if (chip_id == 0) {
353*fcf3ce44SJohn Forte 				errnum = 2; /* can't get chip_id */
354*fcf3ce44SJohn Forte 				retval++;
355*fcf3ce44SJohn Forte 			} else if (chip_id - file_id != 0) {
356*fcf3ce44SJohn Forte 				errnum = 3; /* file/card mismatch */
357*fcf3ce44SJohn Forte 				retval++;
358*fcf3ce44SJohn Forte 			} else {
359*fcf3ce44SJohn Forte 				errnum = 0; /* everything is ok */
360*fcf3ce44SJohn Forte 			}
361*fcf3ce44SJohn Forte 
362*fcf3ce44SJohn Forte 			if (!q_warn(errnum)) {
363*fcf3ce44SJohn Forte 				/* Disable user-interrupt Control-C */
364*fcf3ce44SJohn Forte 				sigint =
365*fcf3ce44SJohn Forte 				    (void (*)(int)) signal(SIGINT, SIG_IGN);
366*fcf3ce44SJohn Forte 
367*fcf3ce44SJohn Forte 				/* Load FCode */
368*fcf3ce44SJohn Forte 				(void) fprintf(stdout, MSGSTR(21010,
369*fcf3ce44SJohn Forte 				    "  Loading FCode: %s\n"), file);
370*fcf3ce44SJohn Forte 
371*fcf3ce44SJohn Forte 				if (q_load_file(fcode_fd,
372*fcf3ce44SJohn Forte 				    &pcibus_list[i][0]) == 0) {
373*fcf3ce44SJohn Forte 					(void) fprintf(stdout, MSGSTR(21011,
374*fcf3ce44SJohn Forte 					"  Successful FCode download: %s\n"),
375*fcf3ce44SJohn Forte 					    &pcibus_list[i][0]);
376*fcf3ce44SJohn Forte 					(void) strcpy(port1, port2);
377*fcf3ce44SJohn Forte 				} else {
378*fcf3ce44SJohn Forte 					(void) fprintf(stderr, MSGSTR(21012,
379*fcf3ce44SJohn Forte 					"Error: FCode download failed: %s\n"),
380*fcf3ce44SJohn Forte 							&pcibus_list[i][0]);
381*fcf3ce44SJohn Forte 					retval++;
382*fcf3ce44SJohn Forte 				}
383*fcf3ce44SJohn Forte 				/* Restore SIGINT (user interrupt) setting */
384*fcf3ce44SJohn Forte 				(void) signal(SIGINT, sigint);
385*fcf3ce44SJohn Forte 			}
386*fcf3ce44SJohn Forte 		}
387*fcf3ce44SJohn Forte 	}
388*fcf3ce44SJohn Forte 	(void) fprintf(stdout, "  ");
389*fcf3ce44SJohn Forte 	(void) fprintf(stdout, MSGSTR(125, "Complete\n"));
390*fcf3ce44SJohn Forte 	if (fcode_fd != -1)
391*fcf3ce44SJohn Forte 		(void) close(fcode_fd);
392*fcf3ce44SJohn Forte 	return (retval);
393*fcf3ce44SJohn Forte }
394*fcf3ce44SJohn Forte 
395*fcf3ce44SJohn Forte 
396*fcf3ce44SJohn Forte /*
397*fcf3ce44SJohn Forte  * Retrieve the version banner from the card
398*fcf3ce44SJohn Forte  *    uses ioctl: FCIO_FCODE_MCODE_VERSION  	FCode revision
399*fcf3ce44SJohn Forte  */
400*fcf3ce44SJohn Forte static int
401*fcf3ce44SJohn Forte q_findversion(int verbose, int index, uchar_t *version, uint16_t *chip_id)
402*fcf3ce44SJohn Forte /*ARGSUSED*/
403*fcf3ce44SJohn Forte {
404*fcf3ce44SJohn Forte 	int fd, ntries;
405*fcf3ce44SJohn Forte 	struct 	ifp_fm_version *version_buffer = NULL;
406*fcf3ce44SJohn Forte 	char	prom_ver[100] = {NULL};
407*fcf3ce44SJohn Forte 	char	mcode_ver[100] = {NULL};
408*fcf3ce44SJohn Forte 	fcio_t	fcio;
409*fcf3ce44SJohn Forte 
410*fcf3ce44SJohn Forte 	if (strstr(&pcibus_list[index][0], fc_trans)) {
411*fcf3ce44SJohn Forte 
412*fcf3ce44SJohn Forte 	if ((fd = open(&pcibus_list[index][0], O_RDWR)) < 0) {
413*fcf3ce44SJohn Forte 		(void) fprintf(stderr,
414*fcf3ce44SJohn Forte 		    MSGSTR(21000, "Error: Could not open %s\n"),
415*fcf3ce44SJohn Forte 		    &pcibus_list[index][0]);
416*fcf3ce44SJohn Forte 		return (1);
417*fcf3ce44SJohn Forte 	}
418*fcf3ce44SJohn Forte 
419*fcf3ce44SJohn Forte 	if ((version_buffer = (struct ifp_fm_version *)malloc(
420*fcf3ce44SJohn Forte 		sizeof (struct ifp_fm_version))) == NULL) {
421*fcf3ce44SJohn Forte 		(void) fprintf(stderr,
422*fcf3ce44SJohn Forte 		    MSGSTR(21013, "Error: Memory allocation failed\n"));
423*fcf3ce44SJohn Forte 		(void) close(fd);
424*fcf3ce44SJohn Forte 		return (1);
425*fcf3ce44SJohn Forte 	}
426*fcf3ce44SJohn Forte 
427*fcf3ce44SJohn Forte 	version_buffer->fcode_ver = (char *)version;
428*fcf3ce44SJohn Forte 	version_buffer->mcode_ver = mcode_ver;
429*fcf3ce44SJohn Forte 	version_buffer->prom_ver = prom_ver;
430*fcf3ce44SJohn Forte 	version_buffer->fcode_ver_len = MAXNAMELEN - 1;
431*fcf3ce44SJohn Forte 	version_buffer->mcode_ver_len = 100;
432*fcf3ce44SJohn Forte 	version_buffer->prom_ver_len = 100;
433*fcf3ce44SJohn Forte 
434*fcf3ce44SJohn Forte 	if (ioctl(fd, FCIO_FCODE_MCODE_VERSION, version_buffer) < 0) {
435*fcf3ce44SJohn Forte 		(void) fprintf(stderr, MSGSTR(21014,
436*fcf3ce44SJohn Forte 		"Error: Driver interface FCIO_FCODE_MCODE_VERSION failed\n"));
437*fcf3ce44SJohn Forte 		free(version_buffer);
438*fcf3ce44SJohn Forte 		(void) close(fd);
439*fcf3ce44SJohn Forte 		return (1);
440*fcf3ce44SJohn Forte 	}
441*fcf3ce44SJohn Forte 	version[version_buffer->fcode_ver_len] = '\0';
442*fcf3ce44SJohn Forte 
443*fcf3ce44SJohn Forte 	/* Need a way to get card MCODE (firmware) to track certain HW bugs */
444*fcf3ce44SJohn Forte 	if (getenv("_LUX_D_DEBUG") != NULL) {
445*fcf3ce44SJohn Forte 		(void) fprintf(stdout, "  Device %i: QLGC chip_id %x\n",
446*fcf3ce44SJohn Forte 		    index+1, *chip_id);
447*fcf3ce44SJohn Forte 		(void) fprintf(stdout, "  FCode:%s\n  MCODE:%s\n  PROM:%s\n",
448*fcf3ce44SJohn Forte 		    (char *)version, mcode_ver, prom_ver);
449*fcf3ce44SJohn Forte 	}
450*fcf3ce44SJohn Forte 	free(version_buffer);
451*fcf3ce44SJohn Forte 
452*fcf3ce44SJohn Forte 	} else if (strstr(&pcibus_list[index][0], fp_trans)) {
453*fcf3ce44SJohn Forte 		/*
454*fcf3ce44SJohn Forte 		 * Get the fcode and prom's fw version
455*fcf3ce44SJohn Forte 		 * using the fp ioctls. Currently, we pass
456*fcf3ce44SJohn Forte 		 * only the fcode version to the calling function
457*fcf3ce44SJohn Forte 		 * and ignore the FW version (using the existing
458*fcf3ce44SJohn Forte 		 * implementation).
459*fcf3ce44SJohn Forte 		 */
460*fcf3ce44SJohn Forte 
461*fcf3ce44SJohn Forte 		if ((fd = open(&pcibus_list[index][0], O_RDWR)) < 0) {
462*fcf3ce44SJohn Forte 			(void) fprintf(stderr,
463*fcf3ce44SJohn Forte 			    MSGSTR(4511, "Could not open %s\n"),
464*fcf3ce44SJohn Forte 			    &pcibus_list[index][0]);
465*fcf3ce44SJohn Forte 			(void) close(fd);
466*fcf3ce44SJohn Forte 			return (1);
467*fcf3ce44SJohn Forte 		}
468*fcf3ce44SJohn Forte 		/* Get the fcode version */
469*fcf3ce44SJohn Forte 		bzero(version, sizeof (version));
470*fcf3ce44SJohn Forte 		fcio.fcio_cmd = FCIO_GET_FCODE_REV;
471*fcf3ce44SJohn Forte 		/* Information read operation */
472*fcf3ce44SJohn Forte 		fcio.fcio_xfer = FCIO_XFER_READ;
473*fcf3ce44SJohn Forte 		fcio.fcio_obuf = (caddr_t)version;
474*fcf3ce44SJohn Forte 		fcio.fcio_olen = MAXNAMELEN;
475*fcf3ce44SJohn Forte 
476*fcf3ce44SJohn Forte 		for (ntries = 0; ntries < MAX_RETRIES; ntries++) {
477*fcf3ce44SJohn Forte 			if (ioctl(fd, FCIO_CMD, &fcio) != 0) {
478*fcf3ce44SJohn Forte 				if ((errno == EAGAIN) &&
479*fcf3ce44SJohn Forte 				    (ntries+1 < MAX_RETRIES)) {
480*fcf3ce44SJohn Forte 					/* wait 30 secs */
481*fcf3ce44SJohn Forte 					(void) sleep(MAX_WAIT_TIME);
482*fcf3ce44SJohn Forte 					continue;
483*fcf3ce44SJohn Forte 				}
484*fcf3ce44SJohn Forte 				(void) close(fd);
485*fcf3ce44SJohn Forte 				return (L_FCIO_GET_FCODE_REV_FAIL);
486*fcf3ce44SJohn Forte 			}
487*fcf3ce44SJohn Forte 			break;
488*fcf3ce44SJohn Forte 		}
489*fcf3ce44SJohn Forte 		version[MAXNAMELEN-1] = '\0';
490*fcf3ce44SJohn Forte 	}
491*fcf3ce44SJohn Forte 
492*fcf3ce44SJohn Forte 	/* Get type of card from product name in FCode version banner */
493*fcf3ce44SJohn Forte 	if (strstr((char *)version, qlgc2100)) {
494*fcf3ce44SJohn Forte 		*chip_id = 0x2100;
495*fcf3ce44SJohn Forte 	} else if (strstr((char *)version, qlgc2200)) {
496*fcf3ce44SJohn Forte 		*chip_id = 0x2200;
497*fcf3ce44SJohn Forte 		if (strstr((char *)version, "Sbus")) {
498*fcf3ce44SJohn Forte 			*chip_id = SBUS_CHIP_ID;
499*fcf3ce44SJohn Forte 		}
500*fcf3ce44SJohn Forte 	} else if (strstr((char *)version, qlgc2300)) {
501*fcf3ce44SJohn Forte 		*chip_id = 0x2300;
502*fcf3ce44SJohn Forte 	} else if (strstr((char *)version, qlgc2312)) {
503*fcf3ce44SJohn Forte 		*chip_id = 0x2312;
504*fcf3ce44SJohn Forte 	} else {
505*fcf3ce44SJohn Forte 		*chip_id = 0x0;
506*fcf3ce44SJohn Forte 	}
507*fcf3ce44SJohn Forte 
508*fcf3ce44SJohn Forte 	(void) close(fd);
509*fcf3ce44SJohn Forte 	return (0);
510*fcf3ce44SJohn Forte }
511*fcf3ce44SJohn Forte 
512*fcf3ce44SJohn Forte /*
513*fcf3ce44SJohn Forte  * Retrieve the version banner and file type (2100 or 2200) from the file
514*fcf3ce44SJohn Forte  */
515*fcf3ce44SJohn Forte static int
516*fcf3ce44SJohn Forte q_findfileversion(char *dl_fcode, uchar_t *version_file, uint16_t *file_id,
517*fcf3ce44SJohn Forte 		    int isSbus, int *sbus_offset)
518*fcf3ce44SJohn Forte {
519*fcf3ce44SJohn Forte 	int mark;
520*fcf3ce44SJohn Forte 	int qlc_offset = 0;
521*fcf3ce44SJohn Forte 	char temp[4] = {NULL};
522*fcf3ce44SJohn Forte 
523*fcf3ce44SJohn Forte 
524*fcf3ce44SJohn Forte 	/*
525*fcf3ce44SJohn Forte 	 * Get file version from FCode for 2100 or 2202
526*fcf3ce44SJohn Forte 	 */
527*fcf3ce44SJohn Forte 	if (isSbus) {
528*fcf3ce44SJohn Forte 		*file_id = SBUS_CHIP_ID;
529*fcf3ce44SJohn Forte 	} else {
530*fcf3ce44SJohn Forte 		if ((dl_fcode[0x23] == 0x22) ||
531*fcf3ce44SJohn Forte 		    (dl_fcode[0x23] == 0x23)) {
532*fcf3ce44SJohn Forte 			*file_id = dl_fcode[0x22] & 0xff;
533*fcf3ce44SJohn Forte 			*file_id |= (dl_fcode[0x23] << 8) & 0xff00;
534*fcf3ce44SJohn Forte 		} else {
535*fcf3ce44SJohn Forte 			*file_id = dl_fcode[0x42] & 0xff;
536*fcf3ce44SJohn Forte 			*file_id |= (dl_fcode[0x43] << 8) & 0xff00;
537*fcf3ce44SJohn Forte 		}
538*fcf3ce44SJohn Forte 	}
539*fcf3ce44SJohn Forte 
540*fcf3ce44SJohn Forte 	/*
541*fcf3ce44SJohn Forte 	 * Ok, we're just checking for 2200 here. If it is we need
542*fcf3ce44SJohn Forte 	 * to offset to find the banner.
543*fcf3ce44SJohn Forte 	 */
544*fcf3ce44SJohn Forte 	if ((*file_id == 0x2200) ||
545*fcf3ce44SJohn Forte 	    (*file_id == 0x2300) ||
546*fcf3ce44SJohn Forte 	    (*file_id == 0x2312)) {
547*fcf3ce44SJohn Forte 		qlc_offset = -32;
548*fcf3ce44SJohn Forte 	}
549*fcf3ce44SJohn Forte 
550*fcf3ce44SJohn Forte 	/*
551*fcf3ce44SJohn Forte 	 * If this is an ISP2200 Sbus Fcode file, then search for the string
552*fcf3ce44SJohn Forte 	 * "ISP2200 FC-AL Host Adapter Driver" in the whole fcode file
553*fcf3ce44SJohn Forte 	 */
554*fcf3ce44SJohn Forte 	if (isSbus) {
555*fcf3ce44SJohn Forte 		*file_id = SBUS_CHIP_ID;
556*fcf3ce44SJohn Forte 		qlc_offset = *sbus_offset;
557*fcf3ce44SJohn Forte 		/* Subtract 111 from the offset we add below for PCI Fcodes */
558*fcf3ce44SJohn Forte 		qlc_offset -= 111;
559*fcf3ce44SJohn Forte 	}
560*fcf3ce44SJohn Forte 
561*fcf3ce44SJohn Forte 	/* Banner length varies; grab banner to end of date marker yr/mo/da */
562*fcf3ce44SJohn Forte 	version_file[0] = '\0';
563*fcf3ce44SJohn Forte 	for (mark = (111 + qlc_offset); mark < (191 + qlc_offset); mark++) {
564*fcf3ce44SJohn Forte 		(void) strncpy(temp, (char *)&dl_fcode[mark], 4);
565*fcf3ce44SJohn Forte 		if ((strncmp(&temp[0], "/", 1) == 0) &&
566*fcf3ce44SJohn Forte 		    (strncmp(&temp[3], "/", 1) == 0)) {
567*fcf3ce44SJohn Forte 			(void) strncat((char *)version_file,
568*fcf3ce44SJohn Forte 			    (char *)&dl_fcode[mark], 6);
569*fcf3ce44SJohn Forte 			break;
570*fcf3ce44SJohn Forte 		}
571*fcf3ce44SJohn Forte 		(void) strncat((char *)version_file, temp, 1);
572*fcf3ce44SJohn Forte 	}
573*fcf3ce44SJohn Forte 	return (0);
574*fcf3ce44SJohn Forte }
575*fcf3ce44SJohn Forte 
576*fcf3ce44SJohn Forte /*
577*fcf3ce44SJohn Forte  * Find if the FCode file is a ISP2200 SBUS Fcode file
578*fcf3ce44SJohn Forte  */
579*fcf3ce44SJohn Forte static int
580*fcf3ce44SJohn Forte q_findSbusfile(int fd, int *sbus_offset)
581*fcf3ce44SJohn Forte {
582*fcf3ce44SJohn Forte 	static int file_size;
583*fcf3ce44SJohn Forte 	char *sbus_info;
584*fcf3ce44SJohn Forte 	struct stat statinfo;
585*fcf3ce44SJohn Forte 
586*fcf3ce44SJohn Forte 	if (lseek(fd, 0, SEEK_SET) == -1) {
587*fcf3ce44SJohn Forte 		perror(MSGSTR(21022, "seek"));
588*fcf3ce44SJohn Forte 		return (-1);
589*fcf3ce44SJohn Forte 	}
590*fcf3ce44SJohn Forte 	if (fstat(fd, &statinfo)) {
591*fcf3ce44SJohn Forte 		perror(MSGSTR(21023, "fstat"));
592*fcf3ce44SJohn Forte 		return (-1);
593*fcf3ce44SJohn Forte 	}
594*fcf3ce44SJohn Forte 	file_size = statinfo.st_size;
595*fcf3ce44SJohn Forte 
596*fcf3ce44SJohn Forte 	if ((sbus_info = (char *)malloc(file_size)) == NULL) {
597*fcf3ce44SJohn Forte 		(void) fprintf(stderr,
598*fcf3ce44SJohn Forte 		    MSGSTR(21013, "Error: Memory allocation failed\n"));
599*fcf3ce44SJohn Forte 		return (-1);
600*fcf3ce44SJohn Forte 	}
601*fcf3ce44SJohn Forte 
602*fcf3ce44SJohn Forte 	if (read(fd, sbus_info, file_size) < 0) {
603*fcf3ce44SJohn Forte 		perror(MSGSTR(21001, "read"));
604*fcf3ce44SJohn Forte 		free(sbus_info);
605*fcf3ce44SJohn Forte 		return (-1);
606*fcf3ce44SJohn Forte 	}
607*fcf3ce44SJohn Forte 
608*fcf3ce44SJohn Forte 	/*
609*fcf3ce44SJohn Forte 	 * Search for the version string in the whole file
610*fcf3ce44SJohn Forte 	 */
611*fcf3ce44SJohn Forte 	if ((*sbus_offset = memstrstr((char *)sbus_info, qlgc2200Sbus,
612*fcf3ce44SJohn Forte 			    file_size, strlen(qlgc2200Sbus))) != -1) {
613*fcf3ce44SJohn Forte 		free(sbus_info);
614*fcf3ce44SJohn Forte 		return (1);
615*fcf3ce44SJohn Forte 	} else {
616*fcf3ce44SJohn Forte 		free(sbus_info);
617*fcf3ce44SJohn Forte 		return (0);
618*fcf3ce44SJohn Forte 	}
619*fcf3ce44SJohn Forte }
620*fcf3ce44SJohn Forte 
621*fcf3ce44SJohn Forte 
622*fcf3ce44SJohn Forte /*
623*fcf3ce44SJohn Forte  * Build a list of all the devctl entries for all the 2100/2200 based adapters
624*fcf3ce44SJohn Forte  */
625*fcf3ce44SJohn Forte static int
626*fcf3ce44SJohn Forte q_getdevctlpath(char *devpath, int *devcnt)
627*fcf3ce44SJohn Forte {
628*fcf3ce44SJohn Forte 	struct stat	statbuf;
629*fcf3ce44SJohn Forte 	struct dirent	*dirp = NULL;
630*fcf3ce44SJohn Forte 	DIR		*dp = NULL;
631*fcf3ce44SJohn Forte 	char		*ptr = NULL;
632*fcf3ce44SJohn Forte 	int		err;
633*fcf3ce44SJohn Forte 	int		testopen;
634*fcf3ce44SJohn Forte 
635*fcf3ce44SJohn Forte 	if (lstat(devpath, &statbuf) < 0) {
636*fcf3ce44SJohn Forte 		(void) fprintf(stderr,
637*fcf3ce44SJohn Forte 		    MSGSTR(21016, "Error: %s lstat() error\n"), devpath);
638*fcf3ce44SJohn Forte 		return (1);
639*fcf3ce44SJohn Forte 	}
640*fcf3ce44SJohn Forte 
641*fcf3ce44SJohn Forte 	if ((strstr(devpath, fc_trans) ||
642*fcf3ce44SJohn Forte 	    (strstr(devpath, fp_trans_id) && strstr(devpath, fp_trans))) &&
643*fcf3ce44SJohn Forte 	    strstr(devpath, "devctl")) {
644*fcf3ce44SJohn Forte 		/* Verify the path is valid */
645*fcf3ce44SJohn Forte 		if ((testopen = open(devpath, O_RDONLY)) >= 0) {
646*fcf3ce44SJohn Forte 			(void) close(testopen);
647*fcf3ce44SJohn Forte 			(void) strcpy(pcibus_list[*devcnt], devpath);
648*fcf3ce44SJohn Forte 			*devcnt += 1;
649*fcf3ce44SJohn Forte 			return (0);
650*fcf3ce44SJohn Forte 		}
651*fcf3ce44SJohn Forte 	}
652*fcf3ce44SJohn Forte 
653*fcf3ce44SJohn Forte 	if (S_ISDIR(statbuf.st_mode) == 0) {
654*fcf3ce44SJohn Forte 		/*
655*fcf3ce44SJohn Forte 		 * not a directory so
656*fcf3ce44SJohn Forte 		 * we don't care about it - return
657*fcf3ce44SJohn Forte 		 */
658*fcf3ce44SJohn Forte 		return (0);
659*fcf3ce44SJohn Forte 	}
660*fcf3ce44SJohn Forte 
661*fcf3ce44SJohn Forte 	/*
662*fcf3ce44SJohn Forte 	 * It's a directory. Call ourself to
663*fcf3ce44SJohn Forte 	 * traverse the path(s)
664*fcf3ce44SJohn Forte 	 */
665*fcf3ce44SJohn Forte 	ptr = devpath + strlen(devpath);
666*fcf3ce44SJohn Forte 	*ptr++ = '/';
667*fcf3ce44SJohn Forte 	*ptr = 0;
668*fcf3ce44SJohn Forte 
669*fcf3ce44SJohn Forte 	/* Forget the /devices/pseudo/ directory */
670*fcf3ce44SJohn Forte 	if (strcmp(devpath, "/devices/pseudo/") == 0) {
671*fcf3ce44SJohn Forte 		return (0);
672*fcf3ce44SJohn Forte 	}
673*fcf3ce44SJohn Forte 
674*fcf3ce44SJohn Forte 	if ((dp = opendir(devpath)) == NULL) {
675*fcf3ce44SJohn Forte 		(void) fprintf(stderr,
676*fcf3ce44SJohn Forte 		    MSGSTR(21017, "Error: %s Can't read directory\n"), devpath);
677*fcf3ce44SJohn Forte 		return (1);
678*fcf3ce44SJohn Forte 	}
679*fcf3ce44SJohn Forte 
680*fcf3ce44SJohn Forte 	while ((dirp = readdir(dp)) != NULL) {
681*fcf3ce44SJohn Forte 
682*fcf3ce44SJohn Forte 		if (strcmp(dirp->d_name, ".") == 0 ||
683*fcf3ce44SJohn Forte 		    strcmp(dirp->d_name, "..") == 0) {
684*fcf3ce44SJohn Forte 			continue;
685*fcf3ce44SJohn Forte 		}
686*fcf3ce44SJohn Forte 		(void) strcpy(ptr, dirp->d_name); /* append name */
687*fcf3ce44SJohn Forte 		err = q_getdevctlpath(devpath, devcnt);
688*fcf3ce44SJohn Forte 	}
689*fcf3ce44SJohn Forte 
690*fcf3ce44SJohn Forte 	if (closedir(dp) < 0) {
691*fcf3ce44SJohn Forte 		(void) fprintf(stderr,
692*fcf3ce44SJohn Forte 		MSGSTR(21018, "Error: Can't close directory %s\n"), devpath);
693*fcf3ce44SJohn Forte 		return (1);
694*fcf3ce44SJohn Forte 	}
695*fcf3ce44SJohn Forte 	return (err);
696*fcf3ce44SJohn Forte }
697*fcf3ce44SJohn Forte 
698*fcf3ce44SJohn Forte /*
699*fcf3ce44SJohn Forte  * Get the boot device.  Cannot load FCode to current boot device.
700*fcf3ce44SJohn Forte  * Boot devices under volume management will prompt a warning.
701*fcf3ce44SJohn Forte  */
702*fcf3ce44SJohn Forte static int
703*fcf3ce44SJohn Forte q_getbootdev(uchar_t *bootpath)
704*fcf3ce44SJohn Forte {
705*fcf3ce44SJohn Forte 	struct mnttab mp;
706*fcf3ce44SJohn Forte 	struct mnttab mpref;
707*fcf3ce44SJohn Forte 	FILE *fp = NULL;
708*fcf3ce44SJohn Forte 	static char buf[BUFSIZ];
709*fcf3ce44SJohn Forte 	char *p = NULL, *p1 = NULL;  /* p = full device, p1 = chunk to rm */
710*fcf3ce44SJohn Forte 	char *slot = ":devctl";
711*fcf3ce44SJohn Forte 	char *root = "/";
712*fcf3ce44SJohn Forte 
713*fcf3ce44SJohn Forte 	if ((fp = fopen(MNTTAB, "r")) == NULL) {
714*fcf3ce44SJohn Forte 		(void) fprintf(stderr,
715*fcf3ce44SJohn Forte 		    MSGSTR(21000, "Error: Could not open %s\n"), MNTTAB);
716*fcf3ce44SJohn Forte 		return (1);
717*fcf3ce44SJohn Forte 	}
718*fcf3ce44SJohn Forte 
719*fcf3ce44SJohn Forte 	mntnull(&mpref);
720*fcf3ce44SJohn Forte 	mpref.mnt_mountp = (char *)root;
721*fcf3ce44SJohn Forte 
722*fcf3ce44SJohn Forte 	if (getmntany(fp, &mp, &mpref) != 0 ||
723*fcf3ce44SJohn Forte 	    mpref.mnt_mountp == NULL) {
724*fcf3ce44SJohn Forte 		(void) fprintf(stderr, MSGSTR(21019,
725*fcf3ce44SJohn Forte 		    "Error: Cannot get boot device, check %s.\n"), MNTTAB);
726*fcf3ce44SJohn Forte 		(void) fclose(fp);
727*fcf3ce44SJohn Forte 		return (1);
728*fcf3ce44SJohn Forte 	}
729*fcf3ce44SJohn Forte 	(void) fclose(fp);
730*fcf3ce44SJohn Forte 
731*fcf3ce44SJohn Forte 	/*
732*fcf3ce44SJohn Forte 	 * If we can't get a link, we may be dealing with a volume mgr
733*fcf3ce44SJohn Forte 	 * so give a warning.  If a colon is present, we likely have a
734*fcf3ce44SJohn Forte 	 * non-local disk or cd-rom, so no warning is necessary.
735*fcf3ce44SJohn Forte 	 * e.g. /devices/pci@1f,4000/scsi@3/sd@6,0:b (cdrom, no link) or
736*fcf3ce44SJohn Forte 	 * 	storage-e4:/blah/blah remote boot server
737*fcf3ce44SJohn Forte 	 */
738*fcf3ce44SJohn Forte 	if (readlink(mp.mnt_special, buf, BUFSIZ) < 0) {
739*fcf3ce44SJohn Forte 		if (strstr(mp.mnt_special, ":") == NULL) {
740*fcf3ce44SJohn Forte 			(void) fprintf(stderr, MSGSTR(21020,
741*fcf3ce44SJohn Forte 	"\nWarning: Cannot read boot device link, check %s.\n"), MNTTAB);
742*fcf3ce44SJohn Forte 			(void) fprintf(stderr, MSGSTR(21021,
743*fcf3ce44SJohn Forte 	"Do not upgrade FCode on adapters controlling the boot device.\n"));
744*fcf3ce44SJohn Forte 		}
745*fcf3ce44SJohn Forte 		return (1);
746*fcf3ce44SJohn Forte 	}
747*fcf3ce44SJohn Forte 	/*
748*fcf3ce44SJohn Forte 	 * Copy boot device path to bootpath.  First remove leading
749*fcf3ce44SJohn Forte 	 * path junk (../../..) then if it's an ifp device, chop off
750*fcf3ce44SJohn Forte 	 * the disk and add the devctl to the end of the path.
751*fcf3ce44SJohn Forte 	 */
752*fcf3ce44SJohn Forte 	if (p = strstr(buf, "/devices")) {
753*fcf3ce44SJohn Forte 		if (strstr(buf, fc_trans) != NULL) {
754*fcf3ce44SJohn Forte 			p1 = strrchr(p, '/');
755*fcf3ce44SJohn Forte 			*p1 = '\0';
756*fcf3ce44SJohn Forte 		}
757*fcf3ce44SJohn Forte 	}
758*fcf3ce44SJohn Forte 	(void) strcpy((char *)bootpath, (char *)p);
759*fcf3ce44SJohn Forte 	if (p1) {
760*fcf3ce44SJohn Forte 		(void) strcat((char *)bootpath, slot);
761*fcf3ce44SJohn Forte 	}
762*fcf3ce44SJohn Forte 	return (0);
763*fcf3ce44SJohn Forte }
764*fcf3ce44SJohn Forte 
765*fcf3ce44SJohn Forte /*
766*fcf3ce44SJohn Forte  * Load FCode to card.
767*fcf3ce44SJohn Forte  *    uses ioctl: IFPIO_FCODE_DOWNLOAD
768*fcf3ce44SJohn Forte  */
769*fcf3ce44SJohn Forte static int
770*fcf3ce44SJohn Forte q_load_file(int fcode_fd, char *device)
771*fcf3ce44SJohn Forte {
772*fcf3ce44SJohn Forte 	static int	dev_fd, fcode_size;
773*fcf3ce44SJohn Forte 	struct stat	stat;
774*fcf3ce44SJohn Forte 	ifp_download_t	*download_p = NULL;
775*fcf3ce44SJohn Forte 	fcio_t		fcio;
776*fcf3ce44SJohn Forte 	uint16_t	file_id = 0;
777*fcf3ce44SJohn Forte 	uchar_t		*bin;
778*fcf3ce44SJohn Forte 
779*fcf3ce44SJohn Forte 	if (lseek(fcode_fd, 0, SEEK_SET) == -1) {
780*fcf3ce44SJohn Forte 		perror(MSGSTR(21022, "seek"));
781*fcf3ce44SJohn Forte 		(void) close(fcode_fd);
782*fcf3ce44SJohn Forte 		return (1);
783*fcf3ce44SJohn Forte 	}
784*fcf3ce44SJohn Forte 	if (fstat(fcode_fd, &stat) == -1) {
785*fcf3ce44SJohn Forte 		perror(MSGSTR(21023, "fstat"));
786*fcf3ce44SJohn Forte 		(void) close(fcode_fd);
787*fcf3ce44SJohn Forte 		return (1);
788*fcf3ce44SJohn Forte 	}
789*fcf3ce44SJohn Forte 
790*fcf3ce44SJohn Forte 	fcode_size = stat.st_size;
791*fcf3ce44SJohn Forte 
792*fcf3ce44SJohn Forte 	if (strstr(device, fc_trans)) {
793*fcf3ce44SJohn Forte 		if ((download_p = (ifp_download_t *)malloc(
794*fcf3ce44SJohn Forte 			sizeof (ifp_download_t) + fcode_size)) == NULL) {
795*fcf3ce44SJohn Forte 			(void) fprintf(stderr,
796*fcf3ce44SJohn Forte 			    MSGSTR(21013, "Error: Memory allocation failed\n"));
797*fcf3ce44SJohn Forte 			(void) close(fcode_fd);
798*fcf3ce44SJohn Forte 			return (1);
799*fcf3ce44SJohn Forte 		}
800*fcf3ce44SJohn Forte 	} else {
801*fcf3ce44SJohn Forte 		if ((bin = (uchar_t *)malloc(fcode_size)) == NULL) {
802*fcf3ce44SJohn Forte 			(void) fprintf(stderr,
803*fcf3ce44SJohn Forte 			    MSGSTR(21013, "Error: Memory allocation failed\n"));
804*fcf3ce44SJohn Forte 			(void) close(fcode_fd);
805*fcf3ce44SJohn Forte 			return (1);
806*fcf3ce44SJohn Forte 		}
807*fcf3ce44SJohn Forte 	}
808*fcf3ce44SJohn Forte 
809*fcf3ce44SJohn Forte 	if (strstr(device, fc_trans)) {
810*fcf3ce44SJohn Forte 		if (read(fcode_fd, download_p->dl_fcode, fcode_size)
811*fcf3ce44SJohn Forte 		    != fcode_size) {
812*fcf3ce44SJohn Forte 			perror(MSGSTR(21001, "read"));
813*fcf3ce44SJohn Forte 			free(download_p);
814*fcf3ce44SJohn Forte 			(void) close(fcode_fd);
815*fcf3ce44SJohn Forte 			return (1);
816*fcf3ce44SJohn Forte 		}
817*fcf3ce44SJohn Forte 	} else {
818*fcf3ce44SJohn Forte 		if (read(fcode_fd, bin, fcode_size)
819*fcf3ce44SJohn Forte 		    != fcode_size) {
820*fcf3ce44SJohn Forte 			perror(MSGSTR(21001, "read"));
821*fcf3ce44SJohn Forte 			free(bin);
822*fcf3ce44SJohn Forte 			(void) close(fcode_fd);
823*fcf3ce44SJohn Forte 			return (1);
824*fcf3ce44SJohn Forte 		}
825*fcf3ce44SJohn Forte 	}
826*fcf3ce44SJohn Forte 
827*fcf3ce44SJohn Forte 
828*fcf3ce44SJohn Forte 	if ((dev_fd = open(device, O_RDWR|O_EXCL)) < 0) {
829*fcf3ce44SJohn Forte 		(void) fprintf(stderr,
830*fcf3ce44SJohn Forte 		    MSGSTR(21000, "Error: Could not open %s\n"), device);
831*fcf3ce44SJohn Forte 		free(download_p);
832*fcf3ce44SJohn Forte 		return (1);
833*fcf3ce44SJohn Forte 	}
834*fcf3ce44SJohn Forte 	if (strstr(device, fc_trans)) {
835*fcf3ce44SJohn Forte 		download_p->dl_fcode_len = fcode_size;
836*fcf3ce44SJohn Forte 		file_id = download_p->dl_fcode[0x42] & 0xff;
837*fcf3ce44SJohn Forte 		file_id |= (download_p->dl_fcode[0x43] << 8) & 0xff00;
838*fcf3ce44SJohn Forte 		download_p->dl_chip_id = file_id;
839*fcf3ce44SJohn Forte 		if (ioctl(dev_fd, IFPIO_FCODE_DOWNLOAD, download_p) < 0) {
840*fcf3ce44SJohn Forte 			(void) fprintf(stderr, MSGSTR(21024,
841*fcf3ce44SJohn Forte 		    "Error: Driver interface IFPIO_FCODE_DOWNLOAD failed\n"));
842*fcf3ce44SJohn Forte 			free(download_p);
843*fcf3ce44SJohn Forte 			(void) close(dev_fd);
844*fcf3ce44SJohn Forte 			return (1);
845*fcf3ce44SJohn Forte 		}
846*fcf3ce44SJohn Forte 		free(download_p);
847*fcf3ce44SJohn Forte 	} else if (strstr(device, fp_trans)) {
848*fcf3ce44SJohn Forte 		fcio.fcio_cmd = FCIO_DOWNLOAD_FCODE;
849*fcf3ce44SJohn Forte 		/* Information read operation */
850*fcf3ce44SJohn Forte 		fcio.fcio_xfer = FCIO_XFER_WRITE;
851*fcf3ce44SJohn Forte 		fcio.fcio_ibuf = (caddr_t)bin;
852*fcf3ce44SJohn Forte 		fcio.fcio_ilen = fcode_size;
853*fcf3ce44SJohn Forte 
854*fcf3ce44SJohn Forte 		if (ioctl(dev_fd, FCIO_CMD, &fcio) != 0) {
855*fcf3ce44SJohn Forte 			(void) fprintf(stderr, MSGSTR(21036,
856*fcf3ce44SJohn Forte 		    "Error: Driver interface FCIO_DOWNLOAD_FCODE failed\n"));
857*fcf3ce44SJohn Forte 			free(download_p);
858*fcf3ce44SJohn Forte 			(void) close(dev_fd);
859*fcf3ce44SJohn Forte 			return (1);
860*fcf3ce44SJohn Forte 		}
861*fcf3ce44SJohn Forte 		free(bin);
862*fcf3ce44SJohn Forte 	}
863*fcf3ce44SJohn Forte 	(void) close(dev_fd);
864*fcf3ce44SJohn Forte 	return (0);
865*fcf3ce44SJohn Forte }
866*fcf3ce44SJohn Forte 
867*fcf3ce44SJohn Forte /*
868*fcf3ce44SJohn Forte  * Issue warning strings and loop for Yes/No user interaction
869*fcf3ce44SJohn Forte  *    err# 0 -- we're ok, warn for pending FCode load
870*fcf3ce44SJohn Forte  *         1 -- not in single user mode
871*fcf3ce44SJohn Forte  *         2 -- can't get chip_id
872*fcf3ce44SJohn Forte  *         3 -- card and file do not have same type (2100/2200)
873*fcf3ce44SJohn Forte  */
874*fcf3ce44SJohn Forte static int
875*fcf3ce44SJohn Forte q_warn(int errnum)
876*fcf3ce44SJohn Forte {
877*fcf3ce44SJohn Forte 	char input[1024];
878*fcf3ce44SJohn Forte 	input[0] = '\0';
879*fcf3ce44SJohn Forte 
880*fcf3ce44SJohn Forte 	if (errnum == 1) {
881*fcf3ce44SJohn Forte 		(void) fprintf(stderr, MSGSTR(21025,
882*fcf3ce44SJohn Forte 		    "\nWarning: System is not in single-user mode.\n"));
883*fcf3ce44SJohn Forte 		(void) fprintf(stderr, MSGSTR(21026,
884*fcf3ce44SJohn Forte 	"Loading FCode will reset the adapter and terminate I/O activity\n"));
885*fcf3ce44SJohn Forte 	} else {
886*fcf3ce44SJohn Forte 		if (errnum == 2) {
887*fcf3ce44SJohn Forte 			(void) fprintf(stderr, MSGSTR(21027,
888*fcf3ce44SJohn Forte 			"  Warning: FCode is missing or existing FCode has"
889*fcf3ce44SJohn Forte 			" unrecognized version.\n"));
890*fcf3ce44SJohn Forte 			return (1);
891*fcf3ce44SJohn Forte 		} else if (errnum == 3) {
892*fcf3ce44SJohn Forte 			(void) fprintf(stderr, MSGSTR(21028,
893*fcf3ce44SJohn Forte 			"  Warning: New FCode file version does not match this"
894*fcf3ce44SJohn Forte 			" board type. Skipping...\n"));
895*fcf3ce44SJohn Forte 			return (1);
896*fcf3ce44SJohn Forte 		}
897*fcf3ce44SJohn Forte 		(void) fprintf(stderr, MSGSTR(21029,
898*fcf3ce44SJohn Forte 		"\nWARNING!! This program will update the FCode in this"
899*fcf3ce44SJohn Forte 		" FC100/PCI, ISP2200/PCI, ISP23xx/PCI "
900*fcf3ce44SJohn Forte 		" and Emulex devices.\n"));
901*fcf3ce44SJohn Forte 		(void) fprintf(stderr, MSGSTR(21030,
902*fcf3ce44SJohn Forte 		"This may take a few (5) minutes. Please be patient.\n"));
903*fcf3ce44SJohn Forte 	}
904*fcf3ce44SJohn Forte 
905*fcf3ce44SJohn Forte loop1:
906*fcf3ce44SJohn Forte 	(void) fprintf(stderr, MSGSTR(21031,
907*fcf3ce44SJohn Forte 		"Do you wish to continue ? (y/n) "));
908*fcf3ce44SJohn Forte 
909*fcf3ce44SJohn Forte 	(void) gets(input);
910*fcf3ce44SJohn Forte 
911*fcf3ce44SJohn Forte 	if ((strcmp(input, MSGSTR(21032, "y")) == 0) ||
912*fcf3ce44SJohn Forte 			(strcmp(input, MSGSTR(40, "yes")) == 0)) {
913*fcf3ce44SJohn Forte 		return (0);
914*fcf3ce44SJohn Forte 	} else if ((strcmp(input, MSGSTR(21033, "n")) == 0) ||
915*fcf3ce44SJohn Forte 			(strcmp(input, MSGSTR(45, "no")) == 0)) {
916*fcf3ce44SJohn Forte 		(void) fprintf(stderr,
917*fcf3ce44SJohn Forte 		    MSGSTR(21034, "Not Downloading FCode\n"));
918*fcf3ce44SJohn Forte 		return (1);
919*fcf3ce44SJohn Forte 	} else {
920*fcf3ce44SJohn Forte 		(void) fprintf(stderr, MSGSTR(21035, "Invalid input\n"));
921*fcf3ce44SJohn Forte 		goto loop1;
922*fcf3ce44SJohn Forte 	}
923*fcf3ce44SJohn Forte }
924*fcf3ce44SJohn Forte 
925*fcf3ce44SJohn Forte /*
926*fcf3ce44SJohn Forte  * Name    : memstrstr
927*fcf3ce44SJohn Forte  * Input   : pointer to buf1, pointer to buf2, size of buf1, size of buf2
928*fcf3ce44SJohn Forte  * Returns :
929*fcf3ce44SJohn Forte  *      Offset of the start of contents-of-buf2 in buf1 if it is found
930*fcf3ce44SJohn Forte  *      -1 if buf1 does not contain contents of buf2
931*fcf3ce44SJohn Forte  * Synopsis:
932*fcf3ce44SJohn Forte  * This function works similar to strstr(). The difference is that null
933*fcf3ce44SJohn Forte  * characters in the buffer are treated like any other character. So, buf1
934*fcf3ce44SJohn Forte  * and buf2 can have embedded null characters in them.
935*fcf3ce44SJohn Forte  */
936*fcf3ce44SJohn Forte static int
937*fcf3ce44SJohn Forte memstrstr(char *s1, char *s2, int size1, int size2)
938*fcf3ce44SJohn Forte {
939*fcf3ce44SJohn Forte 	int count1, count2;
940*fcf3ce44SJohn Forte 	char *s1_ptr, *s2_ptr;
941*fcf3ce44SJohn Forte 
942*fcf3ce44SJohn Forte 	count1 = size1; count2 = size2;
943*fcf3ce44SJohn Forte 	s1_ptr = s1; s2_ptr = s2;
944*fcf3ce44SJohn Forte 
945*fcf3ce44SJohn Forte 	if ((size2 == 0)||(size1 == 0))
946*fcf3ce44SJohn Forte 		return (-1);
947*fcf3ce44SJohn Forte 
948*fcf3ce44SJohn Forte 	for (count1 = 0; count1 < (size1 - size2 + 1); count1++) {
949*fcf3ce44SJohn Forte 		if (*s1_ptr++ == *s2_ptr++) {
950*fcf3ce44SJohn Forte 			if (--count2 == 0) {
951*fcf3ce44SJohn Forte 				return (count1 - size2 + 1);
952*fcf3ce44SJohn Forte 			}
953*fcf3ce44SJohn Forte 			continue;
954*fcf3ce44SJohn Forte 		}
955*fcf3ce44SJohn Forte 		count2 = size2;
956*fcf3ce44SJohn Forte 		s2_ptr = s2;
957*fcf3ce44SJohn Forte 	}
958*fcf3ce44SJohn Forte 
959*fcf3ce44SJohn Forte 	return (-1);
960*fcf3ce44SJohn Forte }
961*fcf3ce44SJohn Forte 
962*fcf3ce44SJohn Forte /*
963*fcf3ce44SJohn Forte  * generic fcode load file routine.  given a file descriptor to a fcode file
964*fcf3ce44SJohn Forte  * this routine will issue the FCIO_DOWNLOAD_FCODE ioctl to the given
965*fcf3ce44SJohn Forte  * device.  Any ioctl errors will be returned in fcio_errno
966*fcf3ce44SJohn Forte  *
967*fcf3ce44SJohn Forte  * Arguments:
968*fcf3ce44SJohn Forte  *	fcode_fd    file descriptor to a fcode file
969*fcf3ce44SJohn Forte  *	device	    path to the device we will be downloading the fcode onto
970*fcf3ce44SJohn Forte  *	fcio_errno  pointer to an int that will be used to return any errors
971*fcf3ce44SJohn Forte  *			back to the caller
972*fcf3ce44SJohn Forte  * Retrurn Values:
973*fcf3ce44SJohn Forte  *	0	    successful download
974*fcf3ce44SJohn Forte  *	>0	    otherwise
975*fcf3ce44SJohn Forte  */
976*fcf3ce44SJohn Forte static int
977*fcf3ce44SJohn Forte fcode_load_file(int fcode_fd, char *device, int *fcio_errno)
978*fcf3ce44SJohn Forte {
979*fcf3ce44SJohn Forte 
980*fcf3ce44SJohn Forte 	fcio_t		fcio;
981*fcf3ce44SJohn Forte 	static int	dev_fd, fcode_size;
982*fcf3ce44SJohn Forte 	uchar_t		*bin;
983*fcf3ce44SJohn Forte 	struct stat	stat;
984*fcf3ce44SJohn Forte 
985*fcf3ce44SJohn Forte 	if (device == NULL || fcio_errno == NULL) {
986*fcf3ce44SJohn Forte 		return (FCODE_LOAD_FAILURE);
987*fcf3ce44SJohn Forte 	}
988*fcf3ce44SJohn Forte 
989*fcf3ce44SJohn Forte 	*fcio_errno = 0;
990*fcf3ce44SJohn Forte 	if (lseek(fcode_fd, 0, SEEK_SET) == -1) {
991*fcf3ce44SJohn Forte 		perror(MSGSTR(21022, "seek"));
992*fcf3ce44SJohn Forte 		return (FCODE_LOAD_FAILURE);
993*fcf3ce44SJohn Forte 	}
994*fcf3ce44SJohn Forte 
995*fcf3ce44SJohn Forte 	if (fstat(fcode_fd, &stat) == -1) {
996*fcf3ce44SJohn Forte 		perror(MSGSTR(21023, "fstat"));
997*fcf3ce44SJohn Forte 		return (FCODE_LOAD_FAILURE);
998*fcf3ce44SJohn Forte 	}
999*fcf3ce44SJohn Forte 
1000*fcf3ce44SJohn Forte 	fcode_size = stat.st_size;
1001*fcf3ce44SJohn Forte 
1002*fcf3ce44SJohn Forte 	if ((bin = (uchar_t *)malloc(fcode_size)) == NULL) {
1003*fcf3ce44SJohn Forte 		(void) fprintf(stderr,
1004*fcf3ce44SJohn Forte 		    MSGSTR(21013, "Error: Memory allocation failed\n"));
1005*fcf3ce44SJohn Forte 		return (FCODE_LOAD_FAILURE);
1006*fcf3ce44SJohn Forte 	}
1007*fcf3ce44SJohn Forte 
1008*fcf3ce44SJohn Forte 	if (read(fcode_fd, bin, fcode_size)
1009*fcf3ce44SJohn Forte 	    != fcode_size) {
1010*fcf3ce44SJohn Forte 		perror(MSGSTR(21001, "read"));
1011*fcf3ce44SJohn Forte 		free(bin);
1012*fcf3ce44SJohn Forte 		return (FCODE_LOAD_FAILURE);
1013*fcf3ce44SJohn Forte 	}
1014*fcf3ce44SJohn Forte 
1015*fcf3ce44SJohn Forte 	if ((dev_fd = open(device, O_RDWR|O_EXCL)) < 0) {
1016*fcf3ce44SJohn Forte 		(void) fprintf(stderr,
1017*fcf3ce44SJohn Forte 		    MSGSTR(21122, "Error: Could not open %s, failed "
1018*fcf3ce44SJohn Forte 			    "with errno %d\n"), device, errno);
1019*fcf3ce44SJohn Forte 		free(bin);
1020*fcf3ce44SJohn Forte 		return (FCODE_LOAD_FAILURE);
1021*fcf3ce44SJohn Forte 	}
1022*fcf3ce44SJohn Forte 
1023*fcf3ce44SJohn Forte 	fcio.fcio_cmd = FCIO_DOWNLOAD_FCODE;
1024*fcf3ce44SJohn Forte 	fcio.fcio_xfer = FCIO_XFER_WRITE;
1025*fcf3ce44SJohn Forte 	fcio.fcio_ibuf = (caddr_t)bin;
1026*fcf3ce44SJohn Forte 	fcio.fcio_ilen = fcode_size;
1027*fcf3ce44SJohn Forte 
1028*fcf3ce44SJohn Forte 	if (ioctl(dev_fd, FCIO_CMD, &fcio) != 0) {
1029*fcf3ce44SJohn Forte 		(void) close(dev_fd);
1030*fcf3ce44SJohn Forte 		*fcio_errno = fcio.fcio_errno;
1031*fcf3ce44SJohn Forte 		free(bin);
1032*fcf3ce44SJohn Forte 		return (FCODE_IOCTL_FAILURE);
1033*fcf3ce44SJohn Forte 	}
1034*fcf3ce44SJohn Forte 
1035*fcf3ce44SJohn Forte 	free(bin);
1036*fcf3ce44SJohn Forte 	(void) close(dev_fd);
1037*fcf3ce44SJohn Forte 	return (FCODE_SUCCESS);
1038*fcf3ce44SJohn Forte }
1039*fcf3ce44SJohn Forte 
1040*fcf3ce44SJohn Forte /*
1041*fcf3ce44SJohn Forte  * Searches for and updates the fcode for Emulex HBA cards
1042*fcf3ce44SJohn Forte  * args: FCode file; if NULL only the current FCode
1043*fcf3ce44SJohn Forte  * version is printed
1044*fcf3ce44SJohn Forte  */
1045*fcf3ce44SJohn Forte 
1046*fcf3ce44SJohn Forte int
1047*fcf3ce44SJohn Forte emulex_update(char *file)
1048*fcf3ce44SJohn Forte {
1049*fcf3ce44SJohn Forte 
1050*fcf3ce44SJohn Forte 	int 		fd, retval = 0;
1051*fcf3ce44SJohn Forte 	int 		devcnt = 0;
1052*fcf3ce44SJohn Forte 	uint_t 		state = 0, fflag = 0;
1053*fcf3ce44SJohn Forte 	static uchar_t  bootpath[PATH_MAX];
1054*fcf3ce44SJohn Forte 	int 		fcode_fd = -1;
1055*fcf3ce44SJohn Forte 	static struct	utmpx *utmpp = NULL;
1056*fcf3ce44SJohn Forte 	di_node_t 	root;
1057*fcf3ce44SJohn Forte 	di_node_t 	node, sib_node, count_node;
1058*fcf3ce44SJohn Forte 	di_minor_t 	minor_node;
1059*fcf3ce44SJohn Forte 	char 		phys_path[PATH_MAX], *path;
1060*fcf3ce44SJohn Forte 	int 		errnum = 0, fcio_errno = 0;
1061*fcf3ce44SJohn Forte 	static uchar_t	prom_ver_data[MAXNAMELEN];
1062*fcf3ce44SJohn Forte 	static char	ver_file[EMULEX_FCODE_VERSION_LENGTH];
1063*fcf3ce44SJohn Forte 	void		(*sigint)();
1064*fcf3ce44SJohn Forte 	int		prop_entries = -1;
1065*fcf3ce44SJohn Forte 	int 		*port_data = NULL;
1066*fcf3ce44SJohn Forte 
1067*fcf3ce44SJohn Forte 	if (file) {
1068*fcf3ce44SJohn Forte 		/* set the fcode download flag */
1069*fcf3ce44SJohn Forte 		fflag++;
1070*fcf3ce44SJohn Forte 
1071*fcf3ce44SJohn Forte 		/* check for a valid file */
1072*fcf3ce44SJohn Forte 		if ((fcode_fd = open(file, O_RDONLY)) < 0) {
1073*fcf3ce44SJohn Forte 			(void) fprintf(stderr,
1074*fcf3ce44SJohn Forte 			    MSGSTR(21118, "Error: Could not open %s, failed "
1075*fcf3ce44SJohn Forte 				    "with errno %d\n"), file, errno);
1076*fcf3ce44SJohn Forte 			return (1);
1077*fcf3ce44SJohn Forte 		}
1078*fcf3ce44SJohn Forte 
1079*fcf3ce44SJohn Forte 		/* check for single user mode */
1080*fcf3ce44SJohn Forte 		while ((utmpp = getutxent()) != NULL) {
1081*fcf3ce44SJohn Forte 			if (strstr(utmpp->ut_line, "run-level") &&
1082*fcf3ce44SJohn Forte 				(strcmp(utmpp->ut_line, "run-level S") &&
1083*fcf3ce44SJohn Forte 				strcmp(utmpp->ut_line, "run-level 1"))) {
1084*fcf3ce44SJohn Forte 				if (q_warn(1)) {
1085*fcf3ce44SJohn Forte 					(void) endutxent();
1086*fcf3ce44SJohn Forte 					(void) close(fcode_fd);
1087*fcf3ce44SJohn Forte 					return (1);
1088*fcf3ce44SJohn Forte 				}
1089*fcf3ce44SJohn Forte 				break;
1090*fcf3ce44SJohn Forte 			}
1091*fcf3ce44SJohn Forte 		}
1092*fcf3ce44SJohn Forte 		(void) endutxent();
1093*fcf3ce44SJohn Forte 
1094*fcf3ce44SJohn Forte 		/* get bootpath */
1095*fcf3ce44SJohn Forte 		if (!q_getbootdev((uchar_t *)&bootpath[0]) &&
1096*fcf3ce44SJohn Forte 		    getenv("_LUX_D_DEBUG") != NULL) {
1097*fcf3ce44SJohn Forte 			(void) fprintf(stdout, "  Bootpath: %s\n", bootpath);
1098*fcf3ce44SJohn Forte 		}
1099*fcf3ce44SJohn Forte 	}
1100*fcf3ce44SJohn Forte 
1101*fcf3ce44SJohn Forte 	/*
1102*fcf3ce44SJohn Forte 	 * Download the Fcode to all the emulex cards found
1103*fcf3ce44SJohn Forte 	 */
1104*fcf3ce44SJohn Forte 
1105*fcf3ce44SJohn Forte 	/* Create a snapshot of the kernel device tree */
1106*fcf3ce44SJohn Forte 	if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
1107*fcf3ce44SJohn Forte 		(void) fprintf(stderr, MSGSTR(21114,
1108*fcf3ce44SJohn Forte 		"Error: Could not get /devices path to "
1109*fcf3ce44SJohn Forte 		"Emulex Devices.\n"));
1110*fcf3ce44SJohn Forte 		retval++;
1111*fcf3ce44SJohn Forte 	}
1112*fcf3ce44SJohn Forte 
1113*fcf3ce44SJohn Forte 	/* point to first node which matches emulex driver */
1114*fcf3ce44SJohn Forte 	node = di_drv_first_node("emlxs", root);
1115*fcf3ce44SJohn Forte 
1116*fcf3ce44SJohn Forte 	if (node == DI_NODE_NIL) {
1117*fcf3ce44SJohn Forte 		/*
1118*fcf3ce44SJohn Forte 		 * Could not find any emulex cards
1119*fcf3ce44SJohn Forte 		 */
1120*fcf3ce44SJohn Forte 		(void) di_fini(root);
1121*fcf3ce44SJohn Forte 		(void) fprintf(stderr, MSGSTR(21115,
1122*fcf3ce44SJohn Forte 		"\n  Found Path to %d Emulex Devices.\n"), devcnt);
1123*fcf3ce44SJohn Forte 		retval++;
1124*fcf3ce44SJohn Forte 	} else {
1125*fcf3ce44SJohn Forte 
1126*fcf3ce44SJohn Forte 		count_node = node;
1127*fcf3ce44SJohn Forte 		while (count_node != DI_NODE_NIL) {
1128*fcf3ce44SJohn Forte 			state = di_state(count_node);
1129*fcf3ce44SJohn Forte 			if ((state & DI_DRIVER_DETACHED)
1130*fcf3ce44SJohn Forte 			    != DI_DRIVER_DETACHED) {
1131*fcf3ce44SJohn Forte 				devcnt++;
1132*fcf3ce44SJohn Forte 			}
1133*fcf3ce44SJohn Forte 			count_node = di_drv_next_node(count_node);
1134*fcf3ce44SJohn Forte 		}
1135*fcf3ce44SJohn Forte 		(void) fprintf(stdout, MSGSTR(21116,
1136*fcf3ce44SJohn Forte 		"\n  Found Path to %d Emulex Devices.\n"), devcnt);
1137*fcf3ce44SJohn Forte 	}
1138*fcf3ce44SJohn Forte 
1139*fcf3ce44SJohn Forte 
1140*fcf3ce44SJohn Forte 	/*
1141*fcf3ce44SJohn Forte 	 * Traverse device tree to find all emulex cards
1142*fcf3ce44SJohn Forte 	 */
1143*fcf3ce44SJohn Forte 	while (node != DI_NODE_NIL) {
1144*fcf3ce44SJohn Forte 
1145*fcf3ce44SJohn Forte 		state = di_state(node);
1146*fcf3ce44SJohn Forte 		if ((state & DI_DRIVER_DETACHED) == DI_DRIVER_DETACHED) {
1147*fcf3ce44SJohn Forte 			node = di_drv_next_node(node);
1148*fcf3ce44SJohn Forte 			continue;
1149*fcf3ce44SJohn Forte 		}
1150*fcf3ce44SJohn Forte 
1151*fcf3ce44SJohn Forte 		sib_node = di_child_node(node);
1152*fcf3ce44SJohn Forte 		while (sib_node != DI_NODE_NIL) {
1153*fcf3ce44SJohn Forte 
1154*fcf3ce44SJohn Forte 			state = di_state(sib_node);
1155*fcf3ce44SJohn Forte 			if ((state & DI_DRIVER_DETACHED) !=
1156*fcf3ce44SJohn Forte 			    DI_DRIVER_DETACHED) {
1157*fcf3ce44SJohn Forte 
1158*fcf3ce44SJohn Forte 				/* Found an attached node */
1159*fcf3ce44SJohn Forte 				prop_entries = di_prop_lookup_ints(
1160*fcf3ce44SJohn Forte 				    DDI_DEV_T_ANY, sib_node,
1161*fcf3ce44SJohn Forte 				    "port", &port_data);
1162*fcf3ce44SJohn Forte 				if (prop_entries != -1) {
1163*fcf3ce44SJohn Forte 
1164*fcf3ce44SJohn Forte 					/* Found a node with "port" property */
1165*fcf3ce44SJohn Forte 					minor_node = di_minor_next(sib_node,
1166*fcf3ce44SJohn Forte 					    DI_MINOR_NIL);
1167*fcf3ce44SJohn Forte 					break;
1168*fcf3ce44SJohn Forte 				}
1169*fcf3ce44SJohn Forte 			}
1170*fcf3ce44SJohn Forte 			sib_node = di_sibling_node(sib_node);
1171*fcf3ce44SJohn Forte 		}
1172*fcf3ce44SJohn Forte 
1173*fcf3ce44SJohn Forte 		if (sib_node == DI_NODE_NIL) {
1174*fcf3ce44SJohn Forte 			return (1);
1175*fcf3ce44SJohn Forte 		}
1176*fcf3ce44SJohn Forte 		path = di_devfs_path(sib_node);
1177*fcf3ce44SJohn Forte 		(void) strcpy(phys_path, "/devices");
1178*fcf3ce44SJohn Forte 		(void) strncat(phys_path, path, strlen(path));
1179*fcf3ce44SJohn Forte 		di_devfs_path_free(path);
1180*fcf3ce44SJohn Forte 
1181*fcf3ce44SJohn Forte 		if (fflag && (strstr((char *)bootpath,
1182*fcf3ce44SJohn Forte 		    (char *)phys_path) != NULL)) {
1183*fcf3ce44SJohn Forte 			(void) fprintf(stderr,
1184*fcf3ce44SJohn Forte 			    MSGSTR(21117, "Ignoring %s (bootpath)\n"),
1185*fcf3ce44SJohn Forte 			    phys_path);
1186*fcf3ce44SJohn Forte 			node = di_drv_next_node(node);
1187*fcf3ce44SJohn Forte 			continue;
1188*fcf3ce44SJohn Forte 		}
1189*fcf3ce44SJohn Forte 
1190*fcf3ce44SJohn Forte 		if (minor_node) {
1191*fcf3ce44SJohn Forte 			(void) strncat(phys_path, ":", 1);
1192*fcf3ce44SJohn Forte 			(void) strncat(phys_path,
1193*fcf3ce44SJohn Forte 				di_minor_name(minor_node),
1194*fcf3ce44SJohn Forte 				strlen(di_minor_name(minor_node)));
1195*fcf3ce44SJohn Forte 		}
1196*fcf3ce44SJohn Forte 
1197*fcf3ce44SJohn Forte 		(void) fprintf(stdout,
1198*fcf3ce44SJohn Forte 				MSGSTR(21107, "\n  Opening Device: %s\n"),
1199*fcf3ce44SJohn Forte 				phys_path);
1200*fcf3ce44SJohn Forte 
1201*fcf3ce44SJohn Forte 		/* Check if the device is valid */
1202*fcf3ce44SJohn Forte 		if ((fd = open(phys_path, O_RDWR)) < 0) {
1203*fcf3ce44SJohn Forte 			(void) fprintf(stderr,
1204*fcf3ce44SJohn Forte 			    MSGSTR(21121, "Error: Could not open %s, failed "
1205*fcf3ce44SJohn Forte 				    "with errno %d\n"), phys_path, errno);
1206*fcf3ce44SJohn Forte 			retval++;
1207*fcf3ce44SJohn Forte 			node = di_drv_next_node(node);
1208*fcf3ce44SJohn Forte 			continue;
1209*fcf3ce44SJohn Forte 		}
1210*fcf3ce44SJohn Forte 
1211*fcf3ce44SJohn Forte 		(void) close(fd);
1212*fcf3ce44SJohn Forte 
1213*fcf3ce44SJohn Forte 		/*
1214*fcf3ce44SJohn Forte 		 * Check FCode version present on the adapter
1215*fcf3ce44SJohn Forte 		 * (at last boot)
1216*fcf3ce44SJohn Forte 		 */
1217*fcf3ce44SJohn Forte 		memset(prom_ver_data, 0, sizeof (prom_ver_data));
1218*fcf3ce44SJohn Forte 		if (emulex_fcodeversion(node, (uchar_t *)&prom_ver_data[0])
1219*fcf3ce44SJohn Forte 		    == 0) {
1220*fcf3ce44SJohn Forte 			errnum = 0;
1221*fcf3ce44SJohn Forte 			if (strlen((char *)prom_ver_data) == 0) {
1222*fcf3ce44SJohn Forte 				(void) fprintf(stdout, MSGSTR(21108,
1223*fcf3ce44SJohn Forte 	"  Detected FCode Version:\tNo version available for this FCode\n"));
1224*fcf3ce44SJohn Forte 			} else {
1225*fcf3ce44SJohn Forte 				(void) fprintf(stdout, MSGSTR(21109,
1226*fcf3ce44SJohn Forte 				    "  Detected FCode Version:\t%s\n"),
1227*fcf3ce44SJohn Forte 				    prom_ver_data);
1228*fcf3ce44SJohn Forte 			}
1229*fcf3ce44SJohn Forte 		} else {
1230*fcf3ce44SJohn Forte 			errnum = 2; /* can't get prom properties */
1231*fcf3ce44SJohn Forte 			retval++;
1232*fcf3ce44SJohn Forte 		}
1233*fcf3ce44SJohn Forte 
1234*fcf3ce44SJohn Forte 		if (fflag) {
1235*fcf3ce44SJohn Forte 
1236*fcf3ce44SJohn Forte 			memset(ver_file, 0, sizeof (ver_file));
1237*fcf3ce44SJohn Forte 			if (emulex_fcode_reader(fcode_fd, "fcode-version",
1238*fcf3ce44SJohn Forte 				    ver_file, sizeof (ver_file)) == 0) {
1239*fcf3ce44SJohn Forte 				(void) fprintf(stdout, MSGSTR(21110,
1240*fcf3ce44SJohn Forte 					    "  New FCode Version:\t\t%s\n"),
1241*fcf3ce44SJohn Forte 					    ver_file);
1242*fcf3ce44SJohn Forte 			} else {
1243*fcf3ce44SJohn Forte 				di_fini(root);
1244*fcf3ce44SJohn Forte 				(void) close(fcode_fd);
1245*fcf3ce44SJohn Forte 				return (1);
1246*fcf3ce44SJohn Forte 			}
1247*fcf3ce44SJohn Forte 
1248*fcf3ce44SJohn Forte 			/*
1249*fcf3ce44SJohn Forte 			 * Load the New FCode
1250*fcf3ce44SJohn Forte 			 * Give warning if file doesn't appear to be correct
1251*fcf3ce44SJohn Forte 			 */
1252*fcf3ce44SJohn Forte 			if (!q_warn(errnum)) {
1253*fcf3ce44SJohn Forte 				/* Disable user-interrupt Control-C */
1254*fcf3ce44SJohn Forte 				sigint =
1255*fcf3ce44SJohn Forte 				    (void (*)(int)) signal(SIGINT, SIG_IGN);
1256*fcf3ce44SJohn Forte 				/* Load FCode */
1257*fcf3ce44SJohn Forte 				(void) fprintf(stdout, MSGSTR(21111,
1258*fcf3ce44SJohn Forte 					"  Loading FCode: %s\n"), file);
1259*fcf3ce44SJohn Forte 				if (fcode_load_file(fcode_fd, phys_path,
1260*fcf3ce44SJohn Forte 					    &fcio_errno) == FCODE_SUCCESS) {
1261*fcf3ce44SJohn Forte 					(void) fprintf(stdout, MSGSTR(21112,
1262*fcf3ce44SJohn Forte 					"  Successful FCode download: %s\n"),
1263*fcf3ce44SJohn Forte 					phys_path);
1264*fcf3ce44SJohn Forte 				} else {
1265*fcf3ce44SJohn Forte 					handle_emulex_error(fcio_errno,
1266*fcf3ce44SJohn Forte 					    phys_path);
1267*fcf3ce44SJohn Forte 					retval++;
1268*fcf3ce44SJohn Forte 				}
1269*fcf3ce44SJohn Forte 
1270*fcf3ce44SJohn Forte 				/* Restore SIGINT (user interrupt) setting */
1271*fcf3ce44SJohn Forte 				(void) signal(SIGINT, sigint);
1272*fcf3ce44SJohn Forte 			}
1273*fcf3ce44SJohn Forte 		}
1274*fcf3ce44SJohn Forte 
1275*fcf3ce44SJohn Forte 		node = di_drv_next_node(node);
1276*fcf3ce44SJohn Forte 	}
1277*fcf3ce44SJohn Forte 
1278*fcf3ce44SJohn Forte 	di_fini(root);
1279*fcf3ce44SJohn Forte 	(void) fprintf(stdout, "  ");
1280*fcf3ce44SJohn Forte 	(void) fprintf(stdout, MSGSTR(125, "Complete\n"));
1281*fcf3ce44SJohn Forte 	if (fcode_fd != -1)
1282*fcf3ce44SJohn Forte 		(void) close(fcode_fd);
1283*fcf3ce44SJohn Forte 	return (retval);
1284*fcf3ce44SJohn Forte 
1285*fcf3ce44SJohn Forte }
1286*fcf3ce44SJohn Forte 
1287*fcf3ce44SJohn Forte /*
1288*fcf3ce44SJohn Forte  * Retrieve the version from the card.
1289*fcf3ce44SJohn Forte  *    uses PROM properties
1290*fcf3ce44SJohn Forte  */
1291*fcf3ce44SJohn Forte static int
1292*fcf3ce44SJohn Forte emulex_fcodeversion(di_node_t node, uchar_t *ver) {
1293*fcf3ce44SJohn Forte 	di_prom_prop_t	    promprop;
1294*fcf3ce44SJohn Forte 	di_prom_handle_t    ph;
1295*fcf3ce44SJohn Forte 	char		    *promname;
1296*fcf3ce44SJohn Forte 	uchar_t		    *ver_data = NULL;
1297*fcf3ce44SJohn Forte 	int		    size, found = 0;
1298*fcf3ce44SJohn Forte 
1299*fcf3ce44SJohn Forte 	/* check to make sure ver is not NULL */
1300*fcf3ce44SJohn Forte 	if (ver == NULL) {
1301*fcf3ce44SJohn Forte 		return (1);
1302*fcf3ce44SJohn Forte 	}
1303*fcf3ce44SJohn Forte 
1304*fcf3ce44SJohn Forte 	if ((ph = di_prom_init()) == DI_PROM_HANDLE_NIL) {
1305*fcf3ce44SJohn Forte 		return (1);
1306*fcf3ce44SJohn Forte 	}
1307*fcf3ce44SJohn Forte 
1308*fcf3ce44SJohn Forte 	for (promprop = di_prom_prop_next(ph, node,
1309*fcf3ce44SJohn Forte 		DI_PROM_PROP_NIL);
1310*fcf3ce44SJohn Forte 		promprop != DI_PROM_PROP_NIL;
1311*fcf3ce44SJohn Forte 		promprop = di_prom_prop_next(ph, node, promprop)) {
1312*fcf3ce44SJohn Forte 		if (((promname = di_prom_prop_name(
1313*fcf3ce44SJohn Forte 			promprop)) != NULL) &&
1314*fcf3ce44SJohn Forte 			(strcmp(promname, "fcode-version") == 0)) {
1315*fcf3ce44SJohn Forte 			size = di_prom_prop_data(promprop, &ver_data);
1316*fcf3ce44SJohn Forte 			(void) memset(ver, NULL, size);
1317*fcf3ce44SJohn Forte 			(void) memcpy(ver, ver_data, size);
1318*fcf3ce44SJohn Forte 			found = 1;
1319*fcf3ce44SJohn Forte 		}
1320*fcf3ce44SJohn Forte 	}
1321*fcf3ce44SJohn Forte 
1322*fcf3ce44SJohn Forte 	if (found) {
1323*fcf3ce44SJohn Forte 		return (0);
1324*fcf3ce44SJohn Forte 	} else {
1325*fcf3ce44SJohn Forte 		return (1);
1326*fcf3ce44SJohn Forte 	}
1327*fcf3ce44SJohn Forte }
1328*fcf3ce44SJohn Forte 
1329*fcf3ce44SJohn Forte /*
1330*fcf3ce44SJohn Forte  * Retrieves information from the Emulex fcode
1331*fcf3ce44SJohn Forte  *
1332*fcf3ce44SJohn Forte  * Given a pattern, this routine will look for this pattern in the fcode
1333*fcf3ce44SJohn Forte  * file and if found will return the pattern value
1334*fcf3ce44SJohn Forte  *
1335*fcf3ce44SJohn Forte  * possible patterns are manufacturer and fcode-version
1336*fcf3ce44SJohn Forte  */
1337*fcf3ce44SJohn Forte int
1338*fcf3ce44SJohn Forte emulex_fcode_reader(int fcode_fd, char *pattern, char *pattern_value,
1339*fcf3ce44SJohn Forte     uint32_t pattern_value_size) {
1340*fcf3ce44SJohn Forte 	int32_t i = 0;
1341*fcf3ce44SJohn Forte 	uint32_t n = 0;
1342*fcf3ce44SJohn Forte 	uint32_t b = 0;
1343*fcf3ce44SJohn Forte 	char byte1;
1344*fcf3ce44SJohn Forte 	char byte2;
1345*fcf3ce44SJohn Forte 	char byte3;
1346*fcf3ce44SJohn Forte 	char byte4;
1347*fcf3ce44SJohn Forte 	char buffer1[EMULEX_READ_BUFFER_SIZE];
1348*fcf3ce44SJohn Forte 	char buffer2[EMULEX_READ_BUFFER_SIZE];
1349*fcf3ce44SJohn Forte 	uint32_t plen, image_size;
1350*fcf3ce44SJohn Forte 	struct stat	stat;
1351*fcf3ce44SJohn Forte 	uchar_t		*image;
1352*fcf3ce44SJohn Forte 
1353*fcf3ce44SJohn Forte 	/* Check the arguments */
1354*fcf3ce44SJohn Forte 	if (!fcode_fd || !pattern_value || pattern_value_size < 8) {
1355*fcf3ce44SJohn Forte 		return (1);
1356*fcf3ce44SJohn Forte 	}
1357*fcf3ce44SJohn Forte 
1358*fcf3ce44SJohn Forte 	if (fstat(fcode_fd, &stat) == -1) {
1359*fcf3ce44SJohn Forte 		perror(MSGSTR(21023, "fstat"));
1360*fcf3ce44SJohn Forte 		return (1);
1361*fcf3ce44SJohn Forte 	}
1362*fcf3ce44SJohn Forte 	image_size = stat.st_size;
1363*fcf3ce44SJohn Forte 	if (image_size < 2) {
1364*fcf3ce44SJohn Forte 		return (1);
1365*fcf3ce44SJohn Forte 	}
1366*fcf3ce44SJohn Forte 	if ((image = (uchar_t *)calloc(image_size, 1)) == NULL) {
1367*fcf3ce44SJohn Forte 		(void) fprintf(stderr,
1368*fcf3ce44SJohn Forte 		    MSGSTR(21013, "Error: Memory allocation failed\n"));
1369*fcf3ce44SJohn Forte 		return (1);
1370*fcf3ce44SJohn Forte 	}
1371*fcf3ce44SJohn Forte 
1372*fcf3ce44SJohn Forte 	/* Read the fcode image file */
1373*fcf3ce44SJohn Forte 	lseek(fcode_fd, 0, SEEK_SET);
1374*fcf3ce44SJohn Forte 	read(fcode_fd, image, image_size);
1375*fcf3ce44SJohn Forte 
1376*fcf3ce44SJohn Forte 	/* Initialize */
1377*fcf3ce44SJohn Forte 	bzero(buffer1, sizeof (buffer1));
1378*fcf3ce44SJohn Forte 	bzero(buffer2, sizeof (buffer2));
1379*fcf3ce44SJohn Forte 	/* Default pattern_value string */
1380*fcf3ce44SJohn Forte 	strcpy((char *)pattern_value, "<unknown>");
1381*fcf3ce44SJohn Forte 	plen = strlen(pattern);
1382*fcf3ce44SJohn Forte 	n = 0;
1383*fcf3ce44SJohn Forte 	b = 0;
1384*fcf3ce44SJohn Forte 	i = 0;
1385*fcf3ce44SJohn Forte 
1386*fcf3ce44SJohn Forte 	/* Search entire image for pattern string */
1387*fcf3ce44SJohn Forte 	while (i <= (image_size - 2)) {
1388*fcf3ce44SJohn Forte 		/* Read next two bytes */
1389*fcf3ce44SJohn Forte 		byte1 = image[i++];
1390*fcf3ce44SJohn Forte 		byte2 = image[i++];
1391*fcf3ce44SJohn Forte 
1392*fcf3ce44SJohn Forte 		/* Check second byte first due to endianness */
1393*fcf3ce44SJohn Forte 
1394*fcf3ce44SJohn Forte 		/* Save byte in circular buffer */
1395*fcf3ce44SJohn Forte 		buffer1[b++] = byte2;
1396*fcf3ce44SJohn Forte 		if (b == sizeof (buffer1)) {
1397*fcf3ce44SJohn Forte 			b = 0;
1398*fcf3ce44SJohn Forte 		}
1399*fcf3ce44SJohn Forte 
1400*fcf3ce44SJohn Forte 		/* Check byte for pattern match */
1401*fcf3ce44SJohn Forte 		if (pattern[n++] != byte2) {
1402*fcf3ce44SJohn Forte 			/* If no match, then reset pattern */
1403*fcf3ce44SJohn Forte 			n = 0;
1404*fcf3ce44SJohn Forte 		} else {
1405*fcf3ce44SJohn Forte 			/*
1406*fcf3ce44SJohn Forte 			 * If complete pattern has been matched then
1407*fcf3ce44SJohn Forte 			 * exit loop
1408*fcf3ce44SJohn Forte 			 */
1409*fcf3ce44SJohn Forte 			if (n == plen) {
1410*fcf3ce44SJohn Forte 				goto found;
1411*fcf3ce44SJohn Forte 			}
1412*fcf3ce44SJohn Forte 		}
1413*fcf3ce44SJohn Forte 
1414*fcf3ce44SJohn Forte 
1415*fcf3ce44SJohn Forte 		/* Check first byte second due to endianness */
1416*fcf3ce44SJohn Forte 		/* Save byte in circular buffer */
1417*fcf3ce44SJohn Forte 		buffer1[b++] = byte1;
1418*fcf3ce44SJohn Forte 		if (b == sizeof (buffer1)) {
1419*fcf3ce44SJohn Forte 			b = 0;
1420*fcf3ce44SJohn Forte 		}
1421*fcf3ce44SJohn Forte 		/* Check byte for pattern match */
1422*fcf3ce44SJohn Forte 		if (pattern[n++] != byte1) {
1423*fcf3ce44SJohn Forte 			/* If no match, then reset pattern */
1424*fcf3ce44SJohn Forte 			n = 0;
1425*fcf3ce44SJohn Forte 		} else {
1426*fcf3ce44SJohn Forte 			/*
1427*fcf3ce44SJohn Forte 			 * If complete pattern has been matched
1428*fcf3ce44SJohn Forte 			 * then exit loop
1429*fcf3ce44SJohn Forte 			 */
1430*fcf3ce44SJohn Forte 			if (n == plen) {
1431*fcf3ce44SJohn Forte 				goto found;
1432*fcf3ce44SJohn Forte 			}
1433*fcf3ce44SJohn Forte 		}
1434*fcf3ce44SJohn Forte 	}
1435*fcf3ce44SJohn Forte 
1436*fcf3ce44SJohn Forte 	/* Not found.  Try again with different endianess */
1437*fcf3ce44SJohn Forte 
1438*fcf3ce44SJohn Forte 	/* Initialize */
1439*fcf3ce44SJohn Forte 	bzero(buffer1, sizeof (buffer1));
1440*fcf3ce44SJohn Forte 	bzero(buffer2, sizeof (buffer2));
1441*fcf3ce44SJohn Forte 	n = 0;
1442*fcf3ce44SJohn Forte 	b = 0;
1443*fcf3ce44SJohn Forte 	i = 0;
1444*fcf3ce44SJohn Forte 
1445*fcf3ce44SJohn Forte 	/* Search entire 32bit endian image for pattern string */
1446*fcf3ce44SJohn Forte 	while (i <= (image_size - 4)) {
1447*fcf3ce44SJohn Forte 		/* Read next four bytes */
1448*fcf3ce44SJohn Forte 		byte1 = image[i++];
1449*fcf3ce44SJohn Forte 		byte2 = image[i++];
1450*fcf3ce44SJohn Forte 		byte3 = image[i++];
1451*fcf3ce44SJohn Forte 		byte4 = image[i++];
1452*fcf3ce44SJohn Forte 
1453*fcf3ce44SJohn Forte 		/* Save byte in circular buffer */
1454*fcf3ce44SJohn Forte 		buffer1[b++] = byte4;
1455*fcf3ce44SJohn Forte 		if (b == sizeof (buffer1)) {
1456*fcf3ce44SJohn Forte 			b = 0;
1457*fcf3ce44SJohn Forte 		}
1458*fcf3ce44SJohn Forte 
1459*fcf3ce44SJohn Forte 		/* Check byte for pattern match */
1460*fcf3ce44SJohn Forte 		if (pattern[n++] != byte4) {
1461*fcf3ce44SJohn Forte 			/* If no match, then reset pattern */
1462*fcf3ce44SJohn Forte 			n = 0;
1463*fcf3ce44SJohn Forte 		} else {
1464*fcf3ce44SJohn Forte 			/*
1465*fcf3ce44SJohn Forte 			 * If complete pattern has been matched then exit loop
1466*fcf3ce44SJohn Forte 			 */
1467*fcf3ce44SJohn Forte 			if (n == plen) {
1468*fcf3ce44SJohn Forte 				goto found;
1469*fcf3ce44SJohn Forte 			}
1470*fcf3ce44SJohn Forte 		}
1471*fcf3ce44SJohn Forte 
1472*fcf3ce44SJohn Forte 		/* Save byte in circular buffer */
1473*fcf3ce44SJohn Forte 		buffer1[b++] = byte3;
1474*fcf3ce44SJohn Forte 		if (b == sizeof (buffer1)) {
1475*fcf3ce44SJohn Forte 			b = 0;
1476*fcf3ce44SJohn Forte 		}
1477*fcf3ce44SJohn Forte 
1478*fcf3ce44SJohn Forte 		/* Check byte for pattern match */
1479*fcf3ce44SJohn Forte 		if (pattern[n++] != byte3) {
1480*fcf3ce44SJohn Forte 			/* If no match, then reset pattern */
1481*fcf3ce44SJohn Forte 			n = 0;
1482*fcf3ce44SJohn Forte 		} else {
1483*fcf3ce44SJohn Forte 			/*
1484*fcf3ce44SJohn Forte 			 * If complete pattern has been matched then exit loop
1485*fcf3ce44SJohn Forte 			 */
1486*fcf3ce44SJohn Forte 			if (n == plen) {
1487*fcf3ce44SJohn Forte 				goto found;
1488*fcf3ce44SJohn Forte 			}
1489*fcf3ce44SJohn Forte 		}
1490*fcf3ce44SJohn Forte 
1491*fcf3ce44SJohn Forte 		/* Save byte in circular buffer */
1492*fcf3ce44SJohn Forte 		buffer1[b++] = byte2;
1493*fcf3ce44SJohn Forte 		if (b == sizeof (buffer1)) {
1494*fcf3ce44SJohn Forte 			b = 0;
1495*fcf3ce44SJohn Forte 		}
1496*fcf3ce44SJohn Forte 
1497*fcf3ce44SJohn Forte 		/* Check byte for pattern match */
1498*fcf3ce44SJohn Forte 		if (pattern[n++] != byte2) {
1499*fcf3ce44SJohn Forte 			/* If no match, then reset pattern */
1500*fcf3ce44SJohn Forte 			n = 0;
1501*fcf3ce44SJohn Forte 		} else {
1502*fcf3ce44SJohn Forte 			/*
1503*fcf3ce44SJohn Forte 			 * If complete pattern has been matched then exit loop
1504*fcf3ce44SJohn Forte 			 */
1505*fcf3ce44SJohn Forte 			if (n == plen) {
1506*fcf3ce44SJohn Forte 				goto found;
1507*fcf3ce44SJohn Forte 			}
1508*fcf3ce44SJohn Forte 		}
1509*fcf3ce44SJohn Forte 
1510*fcf3ce44SJohn Forte 		/* Save byte in circular buffer */
1511*fcf3ce44SJohn Forte 		buffer1[b++] = byte1;
1512*fcf3ce44SJohn Forte 		if (b == sizeof (buffer1)) {
1513*fcf3ce44SJohn Forte 			b = 0;
1514*fcf3ce44SJohn Forte 		}
1515*fcf3ce44SJohn Forte 
1516*fcf3ce44SJohn Forte 		/* Check byte for pattern match */
1517*fcf3ce44SJohn Forte 		if (pattern[n++] != byte1) {
1518*fcf3ce44SJohn Forte 			/* If no match, then reset pattern */
1519*fcf3ce44SJohn Forte 			n = 0;
1520*fcf3ce44SJohn Forte 		} else {
1521*fcf3ce44SJohn Forte 			/*
1522*fcf3ce44SJohn Forte 			 * If complete pattern has been matched then exit loop
1523*fcf3ce44SJohn Forte 			 */
1524*fcf3ce44SJohn Forte 			if (n == plen) {
1525*fcf3ce44SJohn Forte 				goto found;
1526*fcf3ce44SJohn Forte 			}
1527*fcf3ce44SJohn Forte 		}
1528*fcf3ce44SJohn Forte 	}
1529*fcf3ce44SJohn Forte 
1530*fcf3ce44SJohn Forte 	free(image);
1531*fcf3ce44SJohn Forte 	return (1);
1532*fcf3ce44SJohn Forte 
1533*fcf3ce44SJohn Forte found:
1534*fcf3ce44SJohn Forte 	free(image);
1535*fcf3ce44SJohn Forte 
1536*fcf3ce44SJohn Forte 	/* Align buffer and eliminate non-printable characters */
1537*fcf3ce44SJohn Forte 	for (i = 0; i < (sizeof (buffer1)-plen); i++) {
1538*fcf3ce44SJohn Forte 		byte1 = buffer1[b++];
1539*fcf3ce44SJohn Forte 		if (b == sizeof (buffer1)) {
1540*fcf3ce44SJohn Forte 			b = 0;
1541*fcf3ce44SJohn Forte 		}
1542*fcf3ce44SJohn Forte 		/* Zero any non-printable characters */
1543*fcf3ce44SJohn Forte 		if (byte1 >= 33 && byte1 <= 126) {
1544*fcf3ce44SJohn Forte 			buffer2[i] = byte1;
1545*fcf3ce44SJohn Forte 		} else {
1546*fcf3ce44SJohn Forte 			buffer2[i] = 0;
1547*fcf3ce44SJohn Forte 		}
1548*fcf3ce44SJohn Forte 	}
1549*fcf3ce44SJohn Forte 
1550*fcf3ce44SJohn Forte 	/*
1551*fcf3ce44SJohn Forte 	 *  Scan backwards for first non-zero string. This will be the
1552*fcf3ce44SJohn Forte 	 *  version string
1553*fcf3ce44SJohn Forte 	 */
1554*fcf3ce44SJohn Forte 	for (i = sizeof (buffer1)-plen-1; i >= 0; i--) {
1555*fcf3ce44SJohn Forte 		if (buffer2[i] != 0) {
1556*fcf3ce44SJohn Forte 			for (; i >= 0; i--) {
1557*fcf3ce44SJohn Forte 				if (buffer2[i] == 0) {
1558*fcf3ce44SJohn Forte 					i++;
1559*fcf3ce44SJohn Forte 					strncpy((char *)pattern_value,
1560*fcf3ce44SJohn Forte 					    &buffer2[i], pattern_value_size);
1561*fcf3ce44SJohn Forte 					break;
1562*fcf3ce44SJohn Forte 				}
1563*fcf3ce44SJohn Forte 			}
1564*fcf3ce44SJohn Forte 			break;
1565*fcf3ce44SJohn Forte 		}
1566*fcf3ce44SJohn Forte 	}
1567*fcf3ce44SJohn Forte 	return (0);
1568*fcf3ce44SJohn Forte }
1569*fcf3ce44SJohn Forte 
1570*fcf3ce44SJohn Forte /*
1571*fcf3ce44SJohn Forte  * error handling routine to handle emulex error conditions
1572*fcf3ce44SJohn Forte  */
1573*fcf3ce44SJohn Forte static void
1574*fcf3ce44SJohn Forte handle_emulex_error(int fcio_errno, char *phys_path) {
1575*fcf3ce44SJohn Forte 	if (fcio_errno == EMLX_IMAGE_BAD) {
1576*fcf3ce44SJohn Forte 		fprintf(stderr, MSGSTR(21119,
1577*fcf3ce44SJohn Forte 			    "Error: Fcode download failed.  "
1578*fcf3ce44SJohn Forte 			    "Bad fcode image.\n"));
1579*fcf3ce44SJohn Forte 	} else if (fcio_errno == EMLX_IMAGE_INCOMPATIBLE) {
1580*fcf3ce44SJohn Forte 		fprintf(stderr, MSGSTR(21120,
1581*fcf3ce44SJohn Forte 			    "Error: Fcode download failed.  Fcode is not "
1582*fcf3ce44SJohn Forte 			    "compatible with card.\n"));
1583*fcf3ce44SJohn Forte 	} else {
1584*fcf3ce44SJohn Forte 		(void) fprintf(stderr, MSGSTR(21036,
1585*fcf3ce44SJohn Forte 		    "Error: Driver interface FCIO_DOWNLOAD_FCODE failed\n"));
1586*fcf3ce44SJohn Forte 		(void) fprintf(stderr,
1587*fcf3ce44SJohn Forte 			MSGSTR(21113,
1588*fcf3ce44SJohn Forte 				"Error: FCode download failed: %s\n"),
1589*fcf3ce44SJohn Forte 				phys_path);
1590*fcf3ce44SJohn Forte 	}
1591*fcf3ce44SJohn Forte }
1592