xref: /titanic_52/usr/src/cmd/luxadm/fcalupdate.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 /*
28*fcf3ce44SJohn Forte  * I18N message number ranges
29*fcf3ce44SJohn Forte  *  This file: 4500 - 4999
30*fcf3ce44SJohn Forte  *  Shared common messages: 1 - 1999
31*fcf3ce44SJohn Forte  */
32*fcf3ce44SJohn Forte 
33*fcf3ce44SJohn Forte #include	<fcntl.h>
34*fcf3ce44SJohn Forte #include	<limits.h>
35*fcf3ce44SJohn Forte #include	<setjmp.h>
36*fcf3ce44SJohn Forte #include	<signal.h>
37*fcf3ce44SJohn Forte #include	<siginfo.h>
38*fcf3ce44SJohn Forte #include	<stdio.h>
39*fcf3ce44SJohn Forte #include	<stdlib.h>
40*fcf3ce44SJohn Forte #include	<string.h>
41*fcf3ce44SJohn Forte #include	<strings.h>
42*fcf3ce44SJohn Forte #include	<unistd.h>
43*fcf3ce44SJohn Forte #include	<ctype.h>
44*fcf3ce44SJohn Forte #include	<dirent.h>
45*fcf3ce44SJohn Forte #include	<sys/exec.h>
46*fcf3ce44SJohn Forte #include	<sys/exechdr.h>
47*fcf3ce44SJohn Forte #include	<sys/mman.h>
48*fcf3ce44SJohn Forte #include	<sys/stat.h>
49*fcf3ce44SJohn Forte #include	<sys/types.h>
50*fcf3ce44SJohn Forte #include	<sys/fibre-channel/fcio.h>
51*fcf3ce44SJohn Forte #include	<sys/socalreg.h>
52*fcf3ce44SJohn Forte /*
53*fcf3ce44SJohn Forte  * The following define is not to
54*fcf3ce44SJohn Forte  * include sys/fc4/fcal_linkapp.h
55*fcf3ce44SJohn Forte  * file from sys/socalio.h, since it
56*fcf3ce44SJohn Forte  * has same structure defines as in
57*fcf3ce44SJohn Forte  * sys/fibre-channel/fcio.h.
58*fcf3ce44SJohn Forte  */
59*fcf3ce44SJohn Forte #define	_SYS_FC4_FCAL_LINKAPP_H
60*fcf3ce44SJohn Forte #include	<sys/socalio.h>
61*fcf3ce44SJohn Forte #include	<sys/time.h>
62*fcf3ce44SJohn Forte #include	<nl_types.h>
63*fcf3ce44SJohn Forte #include	<errno.h>
64*fcf3ce44SJohn Forte #include	<stgcom.h>
65*fcf3ce44SJohn Forte #include	<gfc.h>
66*fcf3ce44SJohn Forte #include	<l_common.h>
67*fcf3ce44SJohn Forte #include	"luxadm.h"
68*fcf3ce44SJohn Forte 
69*fcf3ce44SJohn Forte /*	Defines 	*/
70*fcf3ce44SJohn Forte #define	FEPROM_SIZE		256*1024
71*fcf3ce44SJohn Forte #define	FEPROM_MAX_PROGRAM	25
72*fcf3ce44SJohn Forte #define	FEPROM_MAX_ERASE	1000
73*fcf3ce44SJohn Forte #define	FEPROM_READ_MEMORY	0x00
74*fcf3ce44SJohn Forte #define	FEPROM_ERASE		0x20
75*fcf3ce44SJohn Forte #define	FEPROM_ERASE_VERIFY	0xa0
76*fcf3ce44SJohn Forte #define	FEPROM_PROGRAM		0x40
77*fcf3ce44SJohn Forte #define	FEPROM_PROGRAM_VERIFY	0xc0
78*fcf3ce44SJohn Forte #define	FEPROM_RESET		0xff
79*fcf3ce44SJohn Forte #define	HBA_MAX			128
80*fcf3ce44SJohn Forte 
81*fcf3ce44SJohn Forte #define	FOUND			0
82*fcf3ce44SJohn Forte #define	NOT_FOUND		1
83*fcf3ce44SJohn Forte #define	PROM_SIZ		0x20010
84*fcf3ce44SJohn Forte 
85*fcf3ce44SJohn Forte #define	MAX_RETRIES		3
86*fcf3ce44SJohn Forte #define	MAX_WAIT_TIME		30
87*fcf3ce44SJohn Forte 
88*fcf3ce44SJohn Forte /*
89*fcf3ce44SJohn Forte  * The next define is to work around a problem with sbusmem driver not
90*fcf3ce44SJohn Forte  * able to round up mmap() requests that are not around page boundaries.
91*fcf3ce44SJohn Forte  */
92*fcf3ce44SJohn Forte #define	PROM_SIZ_ROUNDED	0x22000
93*fcf3ce44SJohn Forte #define	SAMPLE_SIZ		0x100
94*fcf3ce44SJohn Forte 
95*fcf3ce44SJohn Forte #define	REG_OFFSET		0x20000
96*fcf3ce44SJohn Forte 
97*fcf3ce44SJohn Forte #define	FEPROM_WWN_OFFSET	0x3fe00
98*fcf3ce44SJohn Forte 
99*fcf3ce44SJohn Forte #define	FEPROM_SUN_WWN		0x50200200
100*fcf3ce44SJohn Forte 
101*fcf3ce44SJohn Forte /*
102*fcf3ce44SJohn Forte  * We'll leave this on leadville, as the onboard
103*fcf3ce44SJohn Forte  * isn't allowed to be zapped by luxadm
104*fcf3ce44SJohn Forte  */
105*fcf3ce44SJohn Forte 
106*fcf3ce44SJohn Forte #define	ONBOARD_SOCAL		"SUNW,socal@d"
107*fcf3ce44SJohn Forte 
108*fcf3ce44SJohn Forte #define	SOCAL_STR	"SUNW,socal"
109*fcf3ce44SJohn Forte #define	SOCAL_STR_LEN	10
110*fcf3ce44SJohn Forte 
111*fcf3ce44SJohn Forte 
112*fcf3ce44SJohn Forte static uchar_t	buffer[FEPROM_SIZE];
113*fcf3ce44SJohn Forte 
114*fcf3ce44SJohn Forte static char	sbus_list[HBA_MAX][PATH_MAX];
115*fcf3ce44SJohn Forte static char	sbussoc_list[HBA_MAX][PATH_MAX];
116*fcf3ce44SJohn Forte static char	bootpath[PATH_MAX];
117*fcf3ce44SJohn Forte static char	version[MAXNAMELEN];
118*fcf3ce44SJohn Forte 
119*fcf3ce44SJohn Forte static uint_t	getsbuslist(void);
120*fcf3ce44SJohn Forte static int	load_file(char *, caddr_t, volatile socal_reg_t *);
121*fcf3ce44SJohn Forte static void	usec_delay(int);
122*fcf3ce44SJohn Forte static void	getbootdev(unsigned int);
123*fcf3ce44SJohn Forte static void	getsocpath(char *, int *);
124*fcf3ce44SJohn Forte static int	loadsocpath(const char *, int *);
125*fcf3ce44SJohn Forte static int	warn(void);
126*fcf3ce44SJohn Forte static int	findversion(int, uchar_t *);
127*fcf3ce44SJohn Forte static int	write_feprom(uchar_t *, uchar_t *, volatile socal_reg_t *);
128*fcf3ce44SJohn Forte static int	feprom_erase(volatile uchar_t *, volatile socal_reg_t *);
129*fcf3ce44SJohn Forte 
130*fcf3ce44SJohn Forte static struct exec exec;
131*fcf3ce44SJohn Forte 
132*fcf3ce44SJohn Forte int
133*fcf3ce44SJohn Forte fcal_update(unsigned int verbose, char *file)
134*fcf3ce44SJohn Forte /*ARGSUSED*/
135*fcf3ce44SJohn Forte {
136*fcf3ce44SJohn Forte int		fd, strfound = 0, retval = 0;
137*fcf3ce44SJohn Forte int		fbuf_idx, fd1, bytes_read;
138*fcf3ce44SJohn Forte caddr_t		addr;
139*fcf3ce44SJohn Forte uint_t		i;
140*fcf3ce44SJohn Forte uint_t		fflag = 0;
141*fcf3ce44SJohn Forte uint_t		vflag = 0;
142*fcf3ce44SJohn Forte uint_t		numslots;
143*fcf3ce44SJohn Forte volatile	socal_reg_t *regs;
144*fcf3ce44SJohn Forte char		*slotname, socal[MAXNAMELEN];
145*fcf3ce44SJohn Forte char		fbuf[BUFSIZ];
146*fcf3ce44SJohn Forte 
147*fcf3ce44SJohn Forte 	if (!file)
148*fcf3ce44SJohn Forte 		vflag++;
149*fcf3ce44SJohn Forte 	else {
150*fcf3ce44SJohn Forte 		fflag++;
151*fcf3ce44SJohn Forte 		if ((fd1 = open(file, O_RDONLY)) == -1) {
152*fcf3ce44SJohn Forte 			(void) fprintf(stderr,
153*fcf3ce44SJohn Forte 				MSGSTR(4500,
154*fcf3ce44SJohn Forte 				"Error: open() failed on file "
155*fcf3ce44SJohn Forte 				"%s\n"), file);
156*fcf3ce44SJohn Forte 			return (1);
157*fcf3ce44SJohn Forte 		}
158*fcf3ce44SJohn Forte 	/*
159*fcf3ce44SJohn Forte 	 * We will just make a check to see if it the file
160*fcf3ce44SJohn Forte 	 * has the "SUNW,socal" strings in it
161*fcf3ce44SJohn Forte 	 * We cannot use strstr() here because we are operating on
162*fcf3ce44SJohn Forte 	 * binary data and so is very likely to have embedded NULLs
163*fcf3ce44SJohn Forte 	 */
164*fcf3ce44SJohn Forte 		while (!strfound && ((bytes_read = read(fd1,
165*fcf3ce44SJohn Forte 						fbuf, BUFSIZ)) > 0)) {
166*fcf3ce44SJohn Forte 			for (fbuf_idx = 0; fbuf_idx < bytes_read;
167*fcf3ce44SJohn Forte 							fbuf_idx++) {
168*fcf3ce44SJohn Forte 				/* First check for the SUNW,socal string */
169*fcf3ce44SJohn Forte 				if (strncmp((fbuf + fbuf_idx), SOCAL_STR,
170*fcf3ce44SJohn Forte 						SOCAL_STR_LEN) == 0) {
171*fcf3ce44SJohn Forte 					strfound = 1;
172*fcf3ce44SJohn Forte 					break;
173*fcf3ce44SJohn Forte 				}
174*fcf3ce44SJohn Forte 
175*fcf3ce44SJohn Forte 			}
176*fcf3ce44SJohn Forte 		}
177*fcf3ce44SJohn Forte 		(void) close(fd1);
178*fcf3ce44SJohn Forte 
179*fcf3ce44SJohn Forte 		if (!strfound) {
180*fcf3ce44SJohn Forte 			(void) fprintf(stderr,
181*fcf3ce44SJohn Forte 				MSGSTR(4501,
182*fcf3ce44SJohn Forte 					"Error: %s is not a "
183*fcf3ce44SJohn Forte 					"FC100/S Fcode file\n"), file);
184*fcf3ce44SJohn Forte 			return (1);
185*fcf3ce44SJohn Forte 		}
186*fcf3ce44SJohn Forte 	}
187*fcf3ce44SJohn Forte 
188*fcf3ce44SJohn Forte 	/*
189*fcf3ce44SJohn Forte 	 * Get count of, and names of SBus slots using the SBus memory
190*fcf3ce44SJohn Forte 	 * interface.
191*fcf3ce44SJohn Forte 	 */
192*fcf3ce44SJohn Forte 	(void) getbootdev(verbose);
193*fcf3ce44SJohn Forte 	if (getenv("_LUX_D_DEBUG") != NULL) {
194*fcf3ce44SJohn Forte 		(void) fprintf(stdout, "  Bootpath: %s\n", bootpath);
195*fcf3ce44SJohn Forte 	}
196*fcf3ce44SJohn Forte 
197*fcf3ce44SJohn Forte 	numslots = getsbuslist();
198*fcf3ce44SJohn Forte 	(void) fprintf(stdout,
199*fcf3ce44SJohn Forte 	MSGSTR(4503, "\n  Found Path to %d FC100/S Cards\n"), numslots);
200*fcf3ce44SJohn Forte 
201*fcf3ce44SJohn Forte 	for (i = 0; i < numslots; i++) {
202*fcf3ce44SJohn Forte 
203*fcf3ce44SJohn Forte 		/*
204*fcf3ce44SJohn Forte 		 * Open SBus memory for this slot.
205*fcf3ce44SJohn Forte 		 */
206*fcf3ce44SJohn Forte 		slotname = &sbus_list[i][0];
207*fcf3ce44SJohn Forte 		if (fflag && (strcmp(slotname, bootpath) == 0)) {
208*fcf3ce44SJohn Forte 			(void) fprintf(stderr,
209*fcf3ce44SJohn Forte 			MSGSTR(4504, " Ignoring %s (bootpath)\n"), slotname);
210*fcf3ce44SJohn Forte 			continue;
211*fcf3ce44SJohn Forte 		}
212*fcf3ce44SJohn Forte 
213*fcf3ce44SJohn Forte 		(void) sprintf(socal, "%s:0", &sbussoc_list[i][0]);
214*fcf3ce44SJohn Forte 
215*fcf3ce44SJohn Forte 		if ((fd = open(socal, O_RDWR)) < 0) {
216*fcf3ce44SJohn Forte 			(void) sprintf(socal, "%s:1", &sbussoc_list[i][0]);
217*fcf3ce44SJohn Forte 			if ((fd = open(socal, O_RDWR)) < 0) {
218*fcf3ce44SJohn Forte 				(void) fprintf(stderr,
219*fcf3ce44SJohn Forte 					MSGSTR(4505, "Could not open %s\n"),
220*fcf3ce44SJohn Forte 					&sbussoc_list[i][0]);
221*fcf3ce44SJohn Forte 				(void) fprintf(stderr,
222*fcf3ce44SJohn Forte 					MSGSTR(4506, "Ignoring %s\n"),
223*fcf3ce44SJohn Forte 					&sbussoc_list[i][0]);
224*fcf3ce44SJohn Forte 				retval++;
225*fcf3ce44SJohn Forte 				continue;
226*fcf3ce44SJohn Forte 			}
227*fcf3ce44SJohn Forte 		}
228*fcf3ce44SJohn Forte 
229*fcf3ce44SJohn Forte 		(void) close(fd);
230*fcf3ce44SJohn Forte 
231*fcf3ce44SJohn Forte 		if (verbose) {
232*fcf3ce44SJohn Forte 			(void) fprintf(stdout, "\n  ");
233*fcf3ce44SJohn Forte 			(void) fprintf(stdout,
234*fcf3ce44SJohn Forte 			MSGSTR(85, "Opening %s\n"), slotname);
235*fcf3ce44SJohn Forte 		}
236*fcf3ce44SJohn Forte 
237*fcf3ce44SJohn Forte 		fd = open(slotname, O_RDWR);
238*fcf3ce44SJohn Forte 
239*fcf3ce44SJohn Forte 		if (fd < 0) {
240*fcf3ce44SJohn Forte 			perror(MSGSTR(4507, "open of slotname"));
241*fcf3ce44SJohn Forte 			retval++;
242*fcf3ce44SJohn Forte 			continue;
243*fcf3ce44SJohn Forte 		}
244*fcf3ce44SJohn Forte 
245*fcf3ce44SJohn Forte 		/*
246*fcf3ce44SJohn Forte 		 * Mmap that SBus memory into my memory space.
247*fcf3ce44SJohn Forte 		 */
248*fcf3ce44SJohn Forte 		addr = mmap((caddr_t)0, PROM_SIZ_ROUNDED, PROT_READ|PROT_WRITE,
249*fcf3ce44SJohn Forte 			MAP_SHARED, fd, 0);
250*fcf3ce44SJohn Forte 
251*fcf3ce44SJohn Forte 		if (addr == MAP_FAILED) {
252*fcf3ce44SJohn Forte 			perror(MSGSTR(46, "mmap"));
253*fcf3ce44SJohn Forte 			(void) close(fd);
254*fcf3ce44SJohn Forte 			retval++;
255*fcf3ce44SJohn Forte 			continue;
256*fcf3ce44SJohn Forte 		}
257*fcf3ce44SJohn Forte 
258*fcf3ce44SJohn Forte 		if ((int)addr == -1) {
259*fcf3ce44SJohn Forte 			perror(MSGSTR(46, "mmap"));
260*fcf3ce44SJohn Forte 			(void) close(fd);
261*fcf3ce44SJohn Forte 			retval++;
262*fcf3ce44SJohn Forte 			continue;
263*fcf3ce44SJohn Forte 		}
264*fcf3ce44SJohn Forte 
265*fcf3ce44SJohn Forte 		regs = (socal_reg_t *)((int)addr + REG_OFFSET);
266*fcf3ce44SJohn Forte 
267*fcf3ce44SJohn Forte 		(void) fprintf(stdout,
268*fcf3ce44SJohn Forte 			MSGSTR(4508, "\n  Device: %s\n"),
269*fcf3ce44SJohn Forte 			&sbussoc_list[i][0]);
270*fcf3ce44SJohn Forte 		/*
271*fcf3ce44SJohn Forte 		 * Load the New FCode
272*fcf3ce44SJohn Forte 		 */
273*fcf3ce44SJohn Forte 		if (fflag) {
274*fcf3ce44SJohn Forte 			if (!warn())
275*fcf3ce44SJohn Forte 				retval += load_file(file, addr, regs);
276*fcf3ce44SJohn Forte 		} else if (vflag) {
277*fcf3ce44SJohn Forte 			if (findversion(i, (uchar_t *)&version[0]) == FOUND) {
278*fcf3ce44SJohn Forte 				(void) fprintf(stdout,
279*fcf3ce44SJohn Forte 				MSGSTR(4509,
280*fcf3ce44SJohn Forte 				"  Detected FC100/S Version: %s\n"), version);
281*fcf3ce44SJohn Forte 			}
282*fcf3ce44SJohn Forte 		}
283*fcf3ce44SJohn Forte 
284*fcf3ce44SJohn Forte 		if (munmap(addr, PROM_SIZ) == -1) {
285*fcf3ce44SJohn Forte 			perror(MSGSTR(4510, "munmap"));
286*fcf3ce44SJohn Forte 			retval++;
287*fcf3ce44SJohn Forte 		}
288*fcf3ce44SJohn Forte 
289*fcf3ce44SJohn Forte 		(void) close(fd);
290*fcf3ce44SJohn Forte 
291*fcf3ce44SJohn Forte 	}
292*fcf3ce44SJohn Forte 	(void) fprintf(stdout, "  ");
293*fcf3ce44SJohn Forte 	(void) fprintf(stdout, MSGSTR(125, "Complete\n"));
294*fcf3ce44SJohn Forte 	return (retval);
295*fcf3ce44SJohn Forte }
296*fcf3ce44SJohn Forte 
297*fcf3ce44SJohn Forte static int
298*fcf3ce44SJohn Forte findversion(int index, uchar_t *version)
299*fcf3ce44SJohn Forte /*ARGSUSED*/
300*fcf3ce44SJohn Forte {
301*fcf3ce44SJohn Forte int fd, ntries;
302*fcf3ce44SJohn Forte struct socal_fm_version	*buffer;
303*fcf3ce44SJohn Forte char	socal[MAXNAMELEN];
304*fcf3ce44SJohn Forte char	fp[MAXNAMELEN];
305*fcf3ce44SJohn Forte char	prom_ver[100];
306*fcf3ce44SJohn Forte char	mcode_ver[100];
307*fcf3ce44SJohn Forte uint_t	dev_type;
308*fcf3ce44SJohn Forte fcio_t	fcio;
309*fcf3ce44SJohn Forte char	fw_rev[FC_FW_REV_SIZE + 1];
310*fcf3ce44SJohn Forte 
311*fcf3ce44SJohn Forte 
312*fcf3ce44SJohn Forte 	if ((dev_type = g_get_path_type(&sbussoc_list[index][0])) == 0) {
313*fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
314*fcf3ce44SJohn Forte 	}
315*fcf3ce44SJohn Forte 
316*fcf3ce44SJohn Forte 
317*fcf3ce44SJohn Forte 	if (dev_type &  FC4_FCA_MASK) {
318*fcf3ce44SJohn Forte 		P_DPRINTF("findversion: found an FC4 path\n");
319*fcf3ce44SJohn Forte 		(void) sprintf(socal, "%s:0", &sbussoc_list[index][0]);
320*fcf3ce44SJohn Forte 		if ((fd = open(socal, O_RDWR)) < 0) {
321*fcf3ce44SJohn Forte 			(void) sprintf(socal, "%s:1", &sbussoc_list[index][0]);
322*fcf3ce44SJohn Forte 			if ((fd = open(socal, O_RDWR)) < 0) {
323*fcf3ce44SJohn Forte 				(void) fprintf(stderr,
324*fcf3ce44SJohn Forte 					MSGSTR(4511, "Could not open %s\n"),
325*fcf3ce44SJohn Forte 					&sbussoc_list[index][0]);
326*fcf3ce44SJohn Forte 				(void) close(fd);
327*fcf3ce44SJohn Forte 				return (NOT_FOUND);
328*fcf3ce44SJohn Forte 			}
329*fcf3ce44SJohn Forte 		}
330*fcf3ce44SJohn Forte 		if ((buffer = (struct socal_fm_version *)malloc(
331*fcf3ce44SJohn Forte 				sizeof (struct socal_fm_version))) == NULL) {
332*fcf3ce44SJohn Forte 			(void) fprintf(stderr, MSGSTR(10,
333*fcf3ce44SJohn Forte 				" Error: Unable to allocate memory."));
334*fcf3ce44SJohn Forte 			(void) fprintf(stderr, "\n");
335*fcf3ce44SJohn Forte 			(void) close(fd);
336*fcf3ce44SJohn Forte 			return (NOT_FOUND);
337*fcf3ce44SJohn Forte 		}
338*fcf3ce44SJohn Forte 
339*fcf3ce44SJohn Forte 		buffer->fcode_ver = (char *)version;
340*fcf3ce44SJohn Forte 		buffer->mcode_ver = mcode_ver;
341*fcf3ce44SJohn Forte 		buffer->prom_ver = prom_ver;
342*fcf3ce44SJohn Forte 		buffer->fcode_ver_len = MAXNAMELEN - 1;
343*fcf3ce44SJohn Forte 		buffer->mcode_ver_len = 100;
344*fcf3ce44SJohn Forte 		buffer->prom_ver_len = 100;
345*fcf3ce44SJohn Forte 
346*fcf3ce44SJohn Forte 		if (ioctl(fd, FCIO_FCODE_MCODE_VERSION, buffer) < 0) {
347*fcf3ce44SJohn Forte 			(void) fprintf(stderr, MSGSTR(4512,
348*fcf3ce44SJohn Forte 				"fcal_s_download: could not get"
349*fcf3ce44SJohn Forte 				" fcode version.\n"));
350*fcf3ce44SJohn Forte 			(void) close(fd);
351*fcf3ce44SJohn Forte 			(void) free(buffer);
352*fcf3ce44SJohn Forte 			return (NOT_FOUND);
353*fcf3ce44SJohn Forte 		}
354*fcf3ce44SJohn Forte 		version[buffer->fcode_ver_len] = '\0';
355*fcf3ce44SJohn Forte 		free(buffer);
356*fcf3ce44SJohn Forte 
357*fcf3ce44SJohn Forte 	} else if (dev_type & FC_FCA_MASK) {
358*fcf3ce44SJohn Forte 		/*
359*fcf3ce44SJohn Forte 		 * Get the fcode and prom's fw version
360*fcf3ce44SJohn Forte 		 * using new ioctls. Currently, we pass
361*fcf3ce44SJohn Forte 		 * only the fcode version to the calling function
362*fcf3ce44SJohn Forte 		 * and ignore the FW version (using the existing
363*fcf3ce44SJohn Forte 		 * implementation). The function definition
364*fcf3ce44SJohn Forte 		 * might be changed in future to pass both the
365*fcf3ce44SJohn Forte 		 * fcode and FW revisions to the calling function, if
366*fcf3ce44SJohn Forte 		 * needed by the calling function.
367*fcf3ce44SJohn Forte 		 */
368*fcf3ce44SJohn Forte 		P_DPRINTF("findversion: found an FC path\n");
369*fcf3ce44SJohn Forte 		(void) sprintf(fp, "%s/fp@0,0:devctl",
370*fcf3ce44SJohn Forte 			&sbussoc_list[index][0]);
371*fcf3ce44SJohn Forte 		if ((fd = open(fp, O_RDWR)) < 0) {
372*fcf3ce44SJohn Forte 			(void) sprintf(fp, "%s/fp@1,0:devctl",
373*fcf3ce44SJohn Forte 				&sbussoc_list[index][0]);
374*fcf3ce44SJohn Forte 			if ((fd = open(fp, O_RDWR)) < 0) {
375*fcf3ce44SJohn Forte 				(void) fprintf(stderr,
376*fcf3ce44SJohn Forte 					MSGSTR(4511, "Could not open %s\n"),
377*fcf3ce44SJohn Forte 					&sbussoc_list[index][0]);
378*fcf3ce44SJohn Forte 				(void) close(fd);
379*fcf3ce44SJohn Forte 				return (NOT_FOUND);
380*fcf3ce44SJohn Forte 			}
381*fcf3ce44SJohn Forte 		}
382*fcf3ce44SJohn Forte 		/* Get the fcode version */
383*fcf3ce44SJohn Forte 		bzero(version, sizeof (version));
384*fcf3ce44SJohn Forte 		fcio.fcio_cmd = FCIO_GET_FCODE_REV;
385*fcf3ce44SJohn Forte 		/* Information read operation */
386*fcf3ce44SJohn Forte 		fcio.fcio_xfer = FCIO_XFER_READ;
387*fcf3ce44SJohn Forte 		fcio.fcio_obuf = (caddr_t)version;
388*fcf3ce44SJohn Forte 		fcio.fcio_olen = MAXNAMELEN;
389*fcf3ce44SJohn Forte 
390*fcf3ce44SJohn Forte 		for (ntries = 0; ntries < MAX_RETRIES; ntries++) {
391*fcf3ce44SJohn Forte 			if (ioctl(fd, FCIO_CMD, &fcio) != 0) {
392*fcf3ce44SJohn Forte 				if ((errno == EAGAIN) &&
393*fcf3ce44SJohn Forte 					(ntries+1 < MAX_RETRIES)) {
394*fcf3ce44SJohn Forte 					/* wait 30 secs */
395*fcf3ce44SJohn Forte 					(void) sleep(MAX_WAIT_TIME);
396*fcf3ce44SJohn Forte 					continue;
397*fcf3ce44SJohn Forte 				}
398*fcf3ce44SJohn Forte 				I_DPRINTF("ioctl FCIO_GET_FCODE_REV failed.\n"
399*fcf3ce44SJohn Forte 					"Error: %s\n", strerror(errno));
400*fcf3ce44SJohn Forte 				(void) close(fd);
401*fcf3ce44SJohn Forte 				return (L_FCIO_GET_FCODE_REV_FAIL);
402*fcf3ce44SJohn Forte 			}
403*fcf3ce44SJohn Forte 			break;
404*fcf3ce44SJohn Forte 		}
405*fcf3ce44SJohn Forte 		version[MAXNAMELEN-1] = '\0';
406*fcf3ce44SJohn Forte 
407*fcf3ce44SJohn Forte 		/* Get the FW revision */
408*fcf3ce44SJohn Forte 		bzero(fw_rev, sizeof (fw_rev));
409*fcf3ce44SJohn Forte 		fcio.fcio_cmd = FCIO_GET_FW_REV;
410*fcf3ce44SJohn Forte 		/* Information read operation */
411*fcf3ce44SJohn Forte 		fcio.fcio_xfer = FCIO_XFER_READ;
412*fcf3ce44SJohn Forte 		fcio.fcio_obuf = (caddr_t)fw_rev;
413*fcf3ce44SJohn Forte 		fcio.fcio_olen = FC_FW_REV_SIZE;
414*fcf3ce44SJohn Forte 		for (ntries = 0; ntries < MAX_RETRIES; ntries++) {
415*fcf3ce44SJohn Forte 			if (ioctl(fd, FCIO_CMD, &fcio) != 0) {
416*fcf3ce44SJohn Forte 				if ((errno == EAGAIN) &&
417*fcf3ce44SJohn Forte 					(ntries+1 < MAX_RETRIES)) {
418*fcf3ce44SJohn Forte 					/* wait 30 secs */
419*fcf3ce44SJohn Forte 					(void) sleep(MAX_WAIT_TIME);
420*fcf3ce44SJohn Forte 					continue;
421*fcf3ce44SJohn Forte 				}
422*fcf3ce44SJohn Forte 				I_DPRINTF(" FCIO_GET_FW_REV ioctl failed.\n"
423*fcf3ce44SJohn Forte 					" Error: %s\n", strerror(errno));
424*fcf3ce44SJohn Forte 				(void) close(fd);
425*fcf3ce44SJohn Forte 				return (L_FCIO_GET_FW_REV_FAIL);
426*fcf3ce44SJohn Forte 			}
427*fcf3ce44SJohn Forte 			break;
428*fcf3ce44SJohn Forte 		}
429*fcf3ce44SJohn Forte 	}
430*fcf3ce44SJohn Forte 
431*fcf3ce44SJohn Forte 	(void) close(fd);
432*fcf3ce44SJohn Forte 	return (FOUND);
433*fcf3ce44SJohn Forte }
434*fcf3ce44SJohn Forte /*
435*fcf3ce44SJohn Forte  * program an FEprom with data from 'source_address'.
436*fcf3ce44SJohn Forte  *	program the FEprom with zeroes,
437*fcf3ce44SJohn Forte  *	erase it,
438*fcf3ce44SJohn Forte  *	program it with the real data.
439*fcf3ce44SJohn Forte  */
440*fcf3ce44SJohn Forte static int
441*fcf3ce44SJohn Forte feprom_program(uchar_t *source_address, uchar_t *dest_address,
442*fcf3ce44SJohn Forte 	volatile socal_reg_t *regs)
443*fcf3ce44SJohn Forte {
444*fcf3ce44SJohn Forte 	int i;
445*fcf3ce44SJohn Forte 
446*fcf3ce44SJohn Forte 	(void) fprintf(stdout, MSGSTR(4513, "Filling with zeroes...\n"));
447*fcf3ce44SJohn Forte 	if (!write_feprom((uchar_t *)0, dest_address, regs)) {
448*fcf3ce44SJohn Forte 		(void) fprintf(stderr,
449*fcf3ce44SJohn Forte 			MSGSTR(4514, "FEprom at 0x%x: zero fill failed\n"),
450*fcf3ce44SJohn Forte 			(int)dest_address);
451*fcf3ce44SJohn Forte 		return (0);
452*fcf3ce44SJohn Forte 	}
453*fcf3ce44SJohn Forte 
454*fcf3ce44SJohn Forte 	(void) fprintf(stdout, MSGSTR(4515, "Erasing...\n"));
455*fcf3ce44SJohn Forte 	for (i = 0; i < FEPROM_MAX_ERASE; i++) {
456*fcf3ce44SJohn Forte 		if (feprom_erase(dest_address, regs))
457*fcf3ce44SJohn Forte 			break;
458*fcf3ce44SJohn Forte 	}
459*fcf3ce44SJohn Forte 
460*fcf3ce44SJohn Forte 	if (i >= FEPROM_MAX_ERASE) {
461*fcf3ce44SJohn Forte 		(void) fprintf(stderr,
462*fcf3ce44SJohn Forte 			MSGSTR(4516, "FEprom at 0x%x: failed to erase\n"),
463*fcf3ce44SJohn Forte 			(int)dest_address);
464*fcf3ce44SJohn Forte 		return (0);
465*fcf3ce44SJohn Forte 	} else if (i > 0) {
466*fcf3ce44SJohn Forte 		if (i == 1) {
467*fcf3ce44SJohn Forte 			(void) fprintf(stderr, MSGSTR(4517,
468*fcf3ce44SJohn Forte 				"FEprom erased after %d attempt\n"), i);
469*fcf3ce44SJohn Forte 		} else {
470*fcf3ce44SJohn Forte 			(void) fprintf(stderr, MSGSTR(4518,
471*fcf3ce44SJohn Forte 				"FEprom erased after %d attempts\n"), i);
472*fcf3ce44SJohn Forte 		}
473*fcf3ce44SJohn Forte 	}
474*fcf3ce44SJohn Forte 
475*fcf3ce44SJohn Forte 	(void) fprintf(stdout, MSGSTR(4519, "Programming...\n"));
476*fcf3ce44SJohn Forte 	if (!(write_feprom(source_address, dest_address, regs))) {
477*fcf3ce44SJohn Forte 		(void) fprintf(stderr,
478*fcf3ce44SJohn Forte 			MSGSTR(4520, "FEprom at 0x%x: write failed\n"),
479*fcf3ce44SJohn Forte 			(int)dest_address);
480*fcf3ce44SJohn Forte 		return (0);
481*fcf3ce44SJohn Forte 	}
482*fcf3ce44SJohn Forte 
483*fcf3ce44SJohn Forte 	/* select the zeroth bank at end so we can read it */
484*fcf3ce44SJohn Forte 	regs->socal_cr.w &= ~(0x30000);
485*fcf3ce44SJohn Forte 	(void) fprintf(stdout, MSGSTR(4521, "Programming done\n"));
486*fcf3ce44SJohn Forte 	return (1);
487*fcf3ce44SJohn Forte }
488*fcf3ce44SJohn Forte 
489*fcf3ce44SJohn Forte /*
490*fcf3ce44SJohn Forte  * program an FEprom one byte at a time using hot electron injection.
491*fcf3ce44SJohn Forte  */
492*fcf3ce44SJohn Forte static int
493*fcf3ce44SJohn Forte write_feprom(uchar_t *source_address, uchar_t *dest_address,
494*fcf3ce44SJohn Forte 	volatile socal_reg_t *regs)
495*fcf3ce44SJohn Forte {
496*fcf3ce44SJohn Forte 	int pulse, i;
497*fcf3ce44SJohn Forte 	uchar_t *s = source_address;
498*fcf3ce44SJohn Forte 	volatile uchar_t *d;
499*fcf3ce44SJohn Forte 
500*fcf3ce44SJohn Forte 	for (i = 0; i < FEPROM_SIZE; i++, s++) {
501*fcf3ce44SJohn Forte 
502*fcf3ce44SJohn Forte 		if ((i & 0xffff) == 0) {
503*fcf3ce44SJohn Forte 			(void) fprintf(stdout,
504*fcf3ce44SJohn Forte 			MSGSTR(4522, "selecting bank %d\n"), i>>16);
505*fcf3ce44SJohn Forte 			regs->socal_cr.w &= ~(0x30000);
506*fcf3ce44SJohn Forte 			regs->socal_cr.w |= i & 0x30000;
507*fcf3ce44SJohn Forte 		}
508*fcf3ce44SJohn Forte 
509*fcf3ce44SJohn Forte 		d = dest_address + (i & 0xffff);
510*fcf3ce44SJohn Forte 
511*fcf3ce44SJohn Forte 		for (pulse = 0; pulse < FEPROM_MAX_PROGRAM; pulse++) {
512*fcf3ce44SJohn Forte 			*d = FEPROM_PROGRAM;
513*fcf3ce44SJohn Forte 			*d = source_address ? *s : 0;
514*fcf3ce44SJohn Forte 			usec_delay(50);
515*fcf3ce44SJohn Forte 			*d = FEPROM_PROGRAM_VERIFY;
516*fcf3ce44SJohn Forte 			usec_delay(30);
517*fcf3ce44SJohn Forte 			if (*d == (source_address ? *s : 0))
518*fcf3ce44SJohn Forte 					break;
519*fcf3ce44SJohn Forte 		}
520*fcf3ce44SJohn Forte 
521*fcf3ce44SJohn Forte 		if (pulse >= FEPROM_MAX_PROGRAM) {
522*fcf3ce44SJohn Forte 			*dest_address = FEPROM_RESET;
523*fcf3ce44SJohn Forte 			return (0);
524*fcf3ce44SJohn Forte 		}
525*fcf3ce44SJohn Forte 	}
526*fcf3ce44SJohn Forte 
527*fcf3ce44SJohn Forte 	*dest_address = FEPROM_RESET;
528*fcf3ce44SJohn Forte 	return (1);
529*fcf3ce44SJohn Forte }
530*fcf3ce44SJohn Forte 
531*fcf3ce44SJohn Forte /*
532*fcf3ce44SJohn Forte  * erase an FEprom using Fowler-Nordheim tunneling.
533*fcf3ce44SJohn Forte  */
534*fcf3ce44SJohn Forte static int
535*fcf3ce44SJohn Forte feprom_erase(volatile uchar_t *dest_address, volatile socal_reg_t *regs)
536*fcf3ce44SJohn Forte {
537*fcf3ce44SJohn Forte 	int i;
538*fcf3ce44SJohn Forte 	volatile uchar_t *d = dest_address;
539*fcf3ce44SJohn Forte 
540*fcf3ce44SJohn Forte 	*d = FEPROM_ERASE;
541*fcf3ce44SJohn Forte 	usec_delay(50);
542*fcf3ce44SJohn Forte 	*d = FEPROM_ERASE;
543*fcf3ce44SJohn Forte 
544*fcf3ce44SJohn Forte 	usec_delay(10000); /* wait 10ms while FEprom erases */
545*fcf3ce44SJohn Forte 
546*fcf3ce44SJohn Forte 	for (i = 0; i < FEPROM_SIZE; i++) {
547*fcf3ce44SJohn Forte 
548*fcf3ce44SJohn Forte 		if ((i & 0xffff) == 0) {
549*fcf3ce44SJohn Forte 			regs->socal_cr.w &= ~(0x30000);
550*fcf3ce44SJohn Forte 			regs->socal_cr.w |= i & 0x30000;
551*fcf3ce44SJohn Forte 		}
552*fcf3ce44SJohn Forte 
553*fcf3ce44SJohn Forte 		d = dest_address + (i & 0xffff);
554*fcf3ce44SJohn Forte 
555*fcf3ce44SJohn Forte 		*d = FEPROM_ERASE_VERIFY;
556*fcf3ce44SJohn Forte 		usec_delay(50);
557*fcf3ce44SJohn Forte 		if (*d != 0xff) {
558*fcf3ce44SJohn Forte 			*dest_address = FEPROM_RESET;
559*fcf3ce44SJohn Forte 			return (0);
560*fcf3ce44SJohn Forte 		}
561*fcf3ce44SJohn Forte 	}
562*fcf3ce44SJohn Forte 	*dest_address = FEPROM_RESET;
563*fcf3ce44SJohn Forte 	return (1);
564*fcf3ce44SJohn Forte }
565*fcf3ce44SJohn Forte 
566*fcf3ce44SJohn Forte static void
567*fcf3ce44SJohn Forte usec_delay(int s)
568*fcf3ce44SJohn Forte {
569*fcf3ce44SJohn Forte 	hrtime_t now, then;
570*fcf3ce44SJohn Forte 
571*fcf3ce44SJohn Forte 	now = gethrtime();
572*fcf3ce44SJohn Forte 	then = now + s*1000;
573*fcf3ce44SJohn Forte 	do {
574*fcf3ce44SJohn Forte 		now = gethrtime();
575*fcf3ce44SJohn Forte 	} while (now < then);
576*fcf3ce44SJohn Forte }
577*fcf3ce44SJohn Forte 
578*fcf3ce44SJohn Forte static uint_t
579*fcf3ce44SJohn Forte getsbuslist(void)
580*fcf3ce44SJohn Forte {
581*fcf3ce44SJohn Forte 	int devcnt = 0;
582*fcf3ce44SJohn Forte 	char devpath[PATH_MAX];
583*fcf3ce44SJohn Forte 
584*fcf3ce44SJohn Forte 	/* We're searching the /devices directory, so... */
585*fcf3ce44SJohn Forte 	(void) strcpy(devpath, "/devices");
586*fcf3ce44SJohn Forte 
587*fcf3ce44SJohn Forte 	/* get the directory entries under /devices for socal sbusmem */
588*fcf3ce44SJohn Forte 	(void) getsocpath(devpath, (int *)&devcnt);
589*fcf3ce44SJohn Forte 
590*fcf3ce44SJohn Forte 	return (devcnt);
591*fcf3ce44SJohn Forte }
592*fcf3ce44SJohn Forte 
593*fcf3ce44SJohn Forte static void
594*fcf3ce44SJohn Forte getbootdev(unsigned int verbose)
595*fcf3ce44SJohn Forte {
596*fcf3ce44SJohn Forte 	char *df = "df /";
597*fcf3ce44SJohn Forte 	FILE *ptr;
598*fcf3ce44SJohn Forte 	char *p, *p1;
599*fcf3ce44SJohn Forte 	char bootdev[PATH_MAX];
600*fcf3ce44SJohn Forte 	char buf[BUFSIZ];
601*fcf3ce44SJohn Forte 	int foundroot = 0;
602*fcf3ce44SJohn Forte 
603*fcf3ce44SJohn Forte 
604*fcf3ce44SJohn Forte 	if ((ptr = popen(df, "r")) != NULL) {
605*fcf3ce44SJohn Forte 		while (fgets(buf, BUFSIZ, ptr) != NULL) {
606*fcf3ce44SJohn Forte 			if (p = strstr(buf, "/dev/dsk/")) {
607*fcf3ce44SJohn Forte 				(void) memset((char *)&bootdev[0], 0,
608*fcf3ce44SJohn Forte 					PATH_MAX);
609*fcf3ce44SJohn Forte 				p1 = p;
610*fcf3ce44SJohn Forte 				while (*p1 != '\0') {
611*fcf3ce44SJohn Forte 					if (!isalnum(*p1) && (*p1 != '/'))
612*fcf3ce44SJohn Forte 						*p1 = ' ';
613*fcf3ce44SJohn Forte 					p1++;
614*fcf3ce44SJohn Forte 				}
615*fcf3ce44SJohn Forte 				(void) sscanf(p, "%s", bootdev);
616*fcf3ce44SJohn Forte 				foundroot = 1;
617*fcf3ce44SJohn Forte 			}
618*fcf3ce44SJohn Forte 		}
619*fcf3ce44SJohn Forte 		if (!foundroot) {
620*fcf3ce44SJohn Forte 			if (verbose)
621*fcf3ce44SJohn Forte 				(void) fprintf(stderr, MSGSTR(44,
622*fcf3ce44SJohn Forte 					"root is not on a local disk!\n"));
623*fcf3ce44SJohn Forte 			(void) memset((char *)&bootpath[0], 0, PATH_MAX);
624*fcf3ce44SJohn Forte 			return;
625*fcf3ce44SJohn Forte 		}
626*fcf3ce44SJohn Forte 		(void) pclose(ptr);
627*fcf3ce44SJohn Forte 		if (bootdev[0]) {
628*fcf3ce44SJohn Forte 			char *ls;
629*fcf3ce44SJohn Forte 			char *p1;
630*fcf3ce44SJohn Forte 			char *p2 = NULL;
631*fcf3ce44SJohn Forte 			char *sbusmem = "/sbusmem@";
632*fcf3ce44SJohn Forte 			char *slot = ",0:slot";
633*fcf3ce44SJohn Forte 
634*fcf3ce44SJohn Forte 			ls = (char *)malloc(PATH_MAX);
635*fcf3ce44SJohn Forte 			(void) memset((char *)ls, NULL, PATH_MAX);
636*fcf3ce44SJohn Forte 			(void) strcpy(ls, "ls -l ");
637*fcf3ce44SJohn Forte 			(void) strcat(ls, bootdev);
638*fcf3ce44SJohn Forte 			if ((ptr = popen(ls, "r")) != NULL) {
639*fcf3ce44SJohn Forte 				while (fgets(buf, BUFSIZ, ptr) != NULL) {
640*fcf3ce44SJohn Forte 					if (p = strstr(buf, "/devices")) {
641*fcf3ce44SJohn Forte 					    if (p1 = strstr(buf, "sbus")) {
642*fcf3ce44SJohn Forte 						while (*p1 != '/')
643*fcf3ce44SJohn Forte 							p1++;
644*fcf3ce44SJohn Forte 						p2 = strstr(p1, "@");
645*fcf3ce44SJohn Forte 						++p2;
646*fcf3ce44SJohn Forte 						*p1 = '\0';
647*fcf3ce44SJohn Forte 					    } else {
648*fcf3ce44SJohn Forte 						if (p1 = strstr(buf,
649*fcf3ce44SJohn Forte 								SOCAL_STR)) {
650*fcf3ce44SJohn Forte 							p2 = strstr(p1, "@");
651*fcf3ce44SJohn Forte 							++p2;
652*fcf3ce44SJohn Forte 							--p1;
653*fcf3ce44SJohn Forte 							*p1 = '\0';
654*fcf3ce44SJohn Forte 						}
655*fcf3ce44SJohn Forte 					    }
656*fcf3ce44SJohn Forte 					}
657*fcf3ce44SJohn Forte 				}
658*fcf3ce44SJohn Forte 				(void) pclose(ptr);
659*fcf3ce44SJohn Forte 			}
660*fcf3ce44SJohn Forte 			(void) memset((char *)&bootdev[0], 0, PATH_MAX);
661*fcf3ce44SJohn Forte 			(void) sscanf(p, "%s", bootdev);
662*fcf3ce44SJohn Forte 			(void) memset((char *)&bootpath[0], 0, PATH_MAX);
663*fcf3ce44SJohn Forte 			(void) strcat(bootpath, bootdev);
664*fcf3ce44SJohn Forte 			(void) strcat(bootpath, sbusmem);
665*fcf3ce44SJohn Forte 			if (p2) {
666*fcf3ce44SJohn Forte 				(void) strncat(bootpath, p2, 1);
667*fcf3ce44SJohn Forte 				(void) strcat(bootpath, slot);
668*fcf3ce44SJohn Forte 				(void) strncat(bootpath, p2, 1);
669*fcf3ce44SJohn Forte 			}
670*fcf3ce44SJohn Forte 		}
671*fcf3ce44SJohn Forte 	}
672*fcf3ce44SJohn Forte }
673*fcf3ce44SJohn Forte 
674*fcf3ce44SJohn Forte /*
675*fcf3ce44SJohn Forte  * This function reads "size" bytes from the FC100/S PROM.
676*fcf3ce44SJohn Forte  * source_address: PROM address
677*fcf3ce44SJohn Forte  * dest_address:   local memeory
678*fcf3ce44SJohn Forte  * offset:         Location in PROM to start reading from.
679*fcf3ce44SJohn Forte  */
680*fcf3ce44SJohn Forte static void
681*fcf3ce44SJohn Forte feprom_read(uchar_t *source_address, uchar_t *dest_address,
682*fcf3ce44SJohn Forte 		int offset, int size, volatile socal_reg_t *regs)
683*fcf3ce44SJohn Forte {
684*fcf3ce44SJohn Forte uchar_t  *s = source_address;
685*fcf3ce44SJohn Forte uchar_t  *d = dest_address;
686*fcf3ce44SJohn Forte int	i = offset;
687*fcf3ce44SJohn Forte 
688*fcf3ce44SJohn Forte 	if (getenv("_LUX_D_DEBUG") != NULL) {
689*fcf3ce44SJohn Forte 		(void) fprintf(stdout,
690*fcf3ce44SJohn Forte 			"  feprom_read: selecting bank %d\n",
691*fcf3ce44SJohn Forte 			(i&0xf0000)>>16);
692*fcf3ce44SJohn Forte 		if (size <= 8) {
693*fcf3ce44SJohn Forte 			(void) fprintf(stdout, "  Data read: ");
694*fcf3ce44SJohn Forte 		}
695*fcf3ce44SJohn Forte 	}
696*fcf3ce44SJohn Forte 	regs->socal_cr.w = i & 0xf0000;
697*fcf3ce44SJohn Forte 	s = source_address + (i & 0xffff);
698*fcf3ce44SJohn Forte 	*s = FEPROM_READ_MEMORY;
699*fcf3ce44SJohn Forte 	usec_delay(6);
700*fcf3ce44SJohn Forte 	for (; s < source_address + (i & 0xffff) + size; d++, s++) {
701*fcf3ce44SJohn Forte 		*d = *s;
702*fcf3ce44SJohn Forte 		if ((getenv("_LUX_D_DEBUG") != NULL) &&
703*fcf3ce44SJohn Forte 			(size <= 8)) {
704*fcf3ce44SJohn Forte 			(void) fprintf(stdout, "0x%x ", *d);
705*fcf3ce44SJohn Forte 		}
706*fcf3ce44SJohn Forte 	}
707*fcf3ce44SJohn Forte 	if ((getenv("_LUX_D_DEBUG") != NULL) &&
708*fcf3ce44SJohn Forte 		(size <= 8)) {
709*fcf3ce44SJohn Forte 		(void) fprintf(stdout, "\n  From offset: 0x%x\n",
710*fcf3ce44SJohn Forte 			offset);
711*fcf3ce44SJohn Forte 	}
712*fcf3ce44SJohn Forte }
713*fcf3ce44SJohn Forte 
714*fcf3ce44SJohn Forte 
715*fcf3ce44SJohn Forte static int
716*fcf3ce44SJohn Forte load_file(char *file, caddr_t prom, volatile socal_reg_t *regs)
717*fcf3ce44SJohn Forte {
718*fcf3ce44SJohn Forte uint_t	wwn_d8, wwn_lo;
719*fcf3ce44SJohn Forte uint_t	wwn_hi;
720*fcf3ce44SJohn Forte int ffd = open(file, 0);
721*fcf3ce44SJohn Forte 
722*fcf3ce44SJohn Forte 	wwn_hi = FEPROM_SUN_WWN;
723*fcf3ce44SJohn Forte 
724*fcf3ce44SJohn Forte 	if (ffd < 0) {
725*fcf3ce44SJohn Forte 		perror(MSGSTR(4524, "open of file"));
726*fcf3ce44SJohn Forte 		exit(1);
727*fcf3ce44SJohn Forte 	}
728*fcf3ce44SJohn Forte 	(void) fprintf(stdout, MSGSTR(4525, "Loading FCode: %s\n"), file);
729*fcf3ce44SJohn Forte 
730*fcf3ce44SJohn Forte 	if (read(ffd, &exec, sizeof (exec)) != sizeof (exec)) {
731*fcf3ce44SJohn Forte 		perror(MSGSTR(4526, "read exec"));
732*fcf3ce44SJohn Forte 		exit(1);
733*fcf3ce44SJohn Forte 	}
734*fcf3ce44SJohn Forte 
735*fcf3ce44SJohn Forte 	if (exec.a_trsize || exec.a_drsize) {
736*fcf3ce44SJohn Forte 		(void) fprintf(stderr,
737*fcf3ce44SJohn Forte 			MSGSTR(4527, "%s: is relocatable\n"), file);
738*fcf3ce44SJohn Forte 		exit(1);
739*fcf3ce44SJohn Forte 	}
740*fcf3ce44SJohn Forte 
741*fcf3ce44SJohn Forte 	if (exec.a_data || exec.a_bss) {
742*fcf3ce44SJohn Forte 		(void) fprintf(stderr,
743*fcf3ce44SJohn Forte 			MSGSTR(4528, "%s: has data or bss\n"), file);
744*fcf3ce44SJohn Forte 		exit(1);
745*fcf3ce44SJohn Forte 	}
746*fcf3ce44SJohn Forte 
747*fcf3ce44SJohn Forte 	if (exec.a_machtype != M_SPARC) {
748*fcf3ce44SJohn Forte 		(void) fprintf(stderr,
749*fcf3ce44SJohn Forte 			MSGSTR(4529, "%s: not for SPARC\n"), file);
750*fcf3ce44SJohn Forte 		exit(1);
751*fcf3ce44SJohn Forte 	}
752*fcf3ce44SJohn Forte 
753*fcf3ce44SJohn Forte 	(void) fprintf(stdout, MSGSTR(4530,
754*fcf3ce44SJohn Forte 		"Loading 0x%x bytes from %s at offset 0x%x\n"),
755*fcf3ce44SJohn Forte 		(int)exec.a_text, file, 0);
756*fcf3ce44SJohn Forte 
757*fcf3ce44SJohn Forte 	if (read(ffd, &buffer, exec.a_text) != exec.a_text) {
758*fcf3ce44SJohn Forte 		perror(MSGSTR(4531, "read"));
759*fcf3ce44SJohn Forte 		exit(1);
760*fcf3ce44SJohn Forte 	}
761*fcf3ce44SJohn Forte 
762*fcf3ce44SJohn Forte 	(void) close(ffd);
763*fcf3ce44SJohn Forte 
764*fcf3ce44SJohn Forte 	feprom_read((uchar_t *)prom, (uchar_t *)&wwn_d8,
765*fcf3ce44SJohn Forte 		FEPROM_WWN_OFFSET, 4, regs);
766*fcf3ce44SJohn Forte 	feprom_read((uchar_t *)prom, (uchar_t *)&wwn_lo,
767*fcf3ce44SJohn Forte 		FEPROM_WWN_OFFSET + 4, 4, regs);
768*fcf3ce44SJohn Forte 	wwn_hi |= wwn_d8 & 0x0f; /* only last digit is interesting */
769*fcf3ce44SJohn Forte 	if (getenv("_LUX_D_DEBUG") != NULL) {
770*fcf3ce44SJohn Forte 		(void) fprintf(stdout,
771*fcf3ce44SJohn Forte 			"  load_file: Writing WWN hi:0x%x lo:0x%x "
772*fcf3ce44SJohn Forte 			"to the FC100/S PROM\n", wwn_hi, wwn_lo);
773*fcf3ce44SJohn Forte 	}
774*fcf3ce44SJohn Forte 	/* put wwn into buffer location */
775*fcf3ce44SJohn Forte 	bcopy((const void *)&wwn_hi,
776*fcf3ce44SJohn Forte 		(void *)&buffer[FEPROM_WWN_OFFSET],
777*fcf3ce44SJohn Forte 		sizeof (wwn_hi));
778*fcf3ce44SJohn Forte 	bcopy((const void *)&wwn_lo,
779*fcf3ce44SJohn Forte 		(void *)&buffer[FEPROM_WWN_OFFSET + 4],
780*fcf3ce44SJohn Forte 		sizeof (wwn_lo));
781*fcf3ce44SJohn Forte 	bcopy((const void *)&wwn_hi,
782*fcf3ce44SJohn Forte 		(void *)&buffer[FEPROM_WWN_OFFSET + 8],
783*fcf3ce44SJohn Forte 		sizeof (wwn_hi));
784*fcf3ce44SJohn Forte 	bcopy((const void *)&wwn_lo,
785*fcf3ce44SJohn Forte 		(void *)&buffer[FEPROM_WWN_OFFSET + 0xc],
786*fcf3ce44SJohn Forte 		sizeof (wwn_lo));
787*fcf3ce44SJohn Forte 
788*fcf3ce44SJohn Forte 	if (feprom_program((uchar_t *)buffer, (uchar_t *)prom, regs) == 0) {
789*fcf3ce44SJohn Forte 		/* here 0 means failure */
790*fcf3ce44SJohn Forte 		return (1);
791*fcf3ce44SJohn Forte 	}
792*fcf3ce44SJohn Forte 
793*fcf3ce44SJohn Forte 	return (0);
794*fcf3ce44SJohn Forte }
795*fcf3ce44SJohn Forte 
796*fcf3ce44SJohn Forte static int
797*fcf3ce44SJohn Forte warn(void)
798*fcf3ce44SJohn Forte {
799*fcf3ce44SJohn Forte 	char input[1024];
800*fcf3ce44SJohn Forte 
801*fcf3ce44SJohn Forte 	input[0] = '\0';
802*fcf3ce44SJohn Forte 
803*fcf3ce44SJohn Forte 	(void) fprintf(stderr, MSGSTR(4532,
804*fcf3ce44SJohn Forte "\nWARNING!! This program will update the FCode in this FC100/S Sbus Card.\n"));
805*fcf3ce44SJohn Forte 	(void) fprintf(stderr,  MSGSTR(4533,
806*fcf3ce44SJohn Forte "This may take a few (5) minutes. Please be patient.\n"));
807*fcf3ce44SJohn Forte 
808*fcf3ce44SJohn Forte loop1:
809*fcf3ce44SJohn Forte 	(void) fprintf(stderr, MSGSTR(4534,
810*fcf3ce44SJohn Forte 		"Do you wish to continue ? (y/n) "));
811*fcf3ce44SJohn Forte 
812*fcf3ce44SJohn Forte 	(void) gets(input);
813*fcf3ce44SJohn Forte 
814*fcf3ce44SJohn Forte 	if ((strcmp(input, MSGSTR(4535, "y")) == 0) ||
815*fcf3ce44SJohn Forte 			(strcmp(input, MSGSTR(40, "yes")) == 0)) {
816*fcf3ce44SJohn Forte 		return (FOUND);
817*fcf3ce44SJohn Forte 	} else if ((strcmp(input, MSGSTR(4536, "n")) == 0) ||
818*fcf3ce44SJohn Forte 			(strcmp(input, MSGSTR(45, "no")) == 0)) {
819*fcf3ce44SJohn Forte 		(void) fprintf(stderr, MSGSTR(4537, "Not Downloading FCode\n"));
820*fcf3ce44SJohn Forte 		return (NOT_FOUND);
821*fcf3ce44SJohn Forte 	} else {
822*fcf3ce44SJohn Forte 		(void) fprintf(stderr, MSGSTR(4538, "Invalid input\n"));
823*fcf3ce44SJohn Forte 		goto loop1;
824*fcf3ce44SJohn Forte 	}
825*fcf3ce44SJohn Forte }
826*fcf3ce44SJohn Forte 
827*fcf3ce44SJohn Forte 
828*fcf3ce44SJohn Forte /*
829*fcf3ce44SJohn Forte  * getsocpath():
830*fcf3ce44SJohn Forte  * 	Searches the /devices directory recursively returning all soc_name
831*fcf3ce44SJohn Forte  *	entries in sbussoc_list (global). This excludes port entries and
832*fcf3ce44SJohn Forte  * 	onboard socal (which leaves only directory entries with
833*fcf3ce44SJohn Forte  *	soc_name included). devcnt is updated to reflect number of soc_name
834*fcf3ce44SJohn Forte  *	devices found.
835*fcf3ce44SJohn Forte  */
836*fcf3ce44SJohn Forte 
837*fcf3ce44SJohn Forte static void
838*fcf3ce44SJohn Forte getsocpath(char *devpath, int *devcnt)
839*fcf3ce44SJohn Forte {
840*fcf3ce44SJohn Forte 	struct stat	statbuf;
841*fcf3ce44SJohn Forte 	struct dirent	*dirp;
842*fcf3ce44SJohn Forte 	DIR		*dp;
843*fcf3ce44SJohn Forte 	char		*ptr;
844*fcf3ce44SJohn Forte 
845*fcf3ce44SJohn Forte 	if (lstat(devpath, &statbuf) < 0) {
846*fcf3ce44SJohn Forte 		(void) fprintf(stderr,
847*fcf3ce44SJohn Forte 		MSGSTR(4539, "Error: %s lstat() error\n"), devpath);
848*fcf3ce44SJohn Forte 		exit(1);
849*fcf3ce44SJohn Forte 	}
850*fcf3ce44SJohn Forte 
851*fcf3ce44SJohn Forte 	if (S_ISDIR(statbuf.st_mode) == 0)
852*fcf3ce44SJohn Forte 		/*
853*fcf3ce44SJohn Forte 		 * not a directory so
854*fcf3ce44SJohn Forte 		 * we don't care about it - return
855*fcf3ce44SJohn Forte 		 */
856*fcf3ce44SJohn Forte 		return;
857*fcf3ce44SJohn Forte 
858*fcf3ce44SJohn Forte 	else {
859*fcf3ce44SJohn Forte 		if (strstr(devpath, ONBOARD_SOCAL))
860*fcf3ce44SJohn Forte 			return;
861*fcf3ce44SJohn Forte 
862*fcf3ce44SJohn Forte 		if (strstr(devpath, SOCAL_STR)) {
863*fcf3ce44SJohn Forte 			/* It's a keeper - call the load function */
864*fcf3ce44SJohn Forte 			if ((loadsocpath(devpath, devcnt)) < 0) {
865*fcf3ce44SJohn Forte 				(void) fprintf(stderr,
866*fcf3ce44SJohn Forte 				MSGSTR(4540, "Error: Cannot set device list\n"),
867*fcf3ce44SJohn Forte 					devpath);
868*fcf3ce44SJohn Forte 				exit(1);
869*fcf3ce44SJohn Forte 			}
870*fcf3ce44SJohn Forte 			/*
871*fcf3ce44SJohn Forte 			 * if socal directory - return,
872*fcf3ce44SJohn Forte 			 * nothing else to see here
873*fcf3ce44SJohn Forte 			 */
874*fcf3ce44SJohn Forte 			return;
875*fcf3ce44SJohn Forte 		}
876*fcf3ce44SJohn Forte 	}
877*fcf3ce44SJohn Forte 
878*fcf3ce44SJohn Forte 	/*
879*fcf3ce44SJohn Forte 	 * It's a directory. Call ourself to
880*fcf3ce44SJohn Forte 	 * traverse the path(s)
881*fcf3ce44SJohn Forte 	 */
882*fcf3ce44SJohn Forte 
883*fcf3ce44SJohn Forte 	ptr = devpath + strlen(devpath);
884*fcf3ce44SJohn Forte 	*ptr++ = '/';
885*fcf3ce44SJohn Forte 	*ptr = 0;
886*fcf3ce44SJohn Forte 
887*fcf3ce44SJohn Forte 	/* Forget the /devices/pseudo/ directory */
888*fcf3ce44SJohn Forte 	if (strcmp(devpath, "/devices/pseudo/") == 0)
889*fcf3ce44SJohn Forte 		return;
890*fcf3ce44SJohn Forte 
891*fcf3ce44SJohn Forte 	if ((dp = opendir(devpath)) == NULL) {
892*fcf3ce44SJohn Forte 		(void) fprintf(stderr,
893*fcf3ce44SJohn Forte 		MSGSTR(4541, "Error: %s Can't read directory\n"), devpath);
894*fcf3ce44SJohn Forte 		exit(1);
895*fcf3ce44SJohn Forte 	}
896*fcf3ce44SJohn Forte 
897*fcf3ce44SJohn Forte 	while ((dirp = readdir(dp)) != NULL) {
898*fcf3ce44SJohn Forte 
899*fcf3ce44SJohn Forte 		if (strcmp(dirp->d_name, ".") == 0 ||
900*fcf3ce44SJohn Forte 			strcmp(dirp->d_name, "..") == 0)
901*fcf3ce44SJohn Forte 			continue;
902*fcf3ce44SJohn Forte 
903*fcf3ce44SJohn Forte 		(void) strcpy(ptr, dirp->d_name); /* append name */
904*fcf3ce44SJohn Forte 		getsocpath(devpath, devcnt);
905*fcf3ce44SJohn Forte 	}
906*fcf3ce44SJohn Forte 
907*fcf3ce44SJohn Forte 	if (closedir(dp) < 0) {
908*fcf3ce44SJohn Forte 		(void) fprintf(stderr,
909*fcf3ce44SJohn Forte 		MSGSTR(4542, "Error: %s Can't close directory\n"), devpath);
910*fcf3ce44SJohn Forte 		exit(1);
911*fcf3ce44SJohn Forte 	}
912*fcf3ce44SJohn Forte }
913*fcf3ce44SJohn Forte 
914*fcf3ce44SJohn Forte static int
915*fcf3ce44SJohn Forte loadsocpath(const char *pathname, int *devcnt)
916*fcf3ce44SJohn Forte {
917*fcf3ce44SJohn Forte 	int ret = 0;
918*fcf3ce44SJohn Forte 	int len;
919*fcf3ce44SJohn Forte 	int len_tmp;
920*fcf3ce44SJohn Forte 	char *sp;
921*fcf3ce44SJohn Forte 	char *sp_tmp;
922*fcf3ce44SJohn Forte 	char buffer[PATH_MAX];
923*fcf3ce44SJohn Forte 
924*fcf3ce44SJohn Forte 
925*fcf3ce44SJohn Forte 	/*
926*fcf3ce44SJohn Forte 	 * Okay we found a device, now let's load it in to sbussoc_list
927*fcf3ce44SJohn Forte 	 * and load the sbusmem file into sbus_list
928*fcf3ce44SJohn Forte 	 */
929*fcf3ce44SJohn Forte 
930*fcf3ce44SJohn Forte 	if (pathname != NULL && *devcnt < HBA_MAX) {
931*fcf3ce44SJohn Forte 		(void) strcpy(sbussoc_list[*devcnt], pathname);
932*fcf3ce44SJohn Forte 		if (sp_tmp = strstr(sbussoc_list[*devcnt], SOCAL_STR)) {
933*fcf3ce44SJohn Forte 			sp = sp_tmp;
934*fcf3ce44SJohn Forte 			/* len_tmp will be len of "SUNW,socal@" */
935*fcf3ce44SJohn Forte 			len_tmp = SOCAL_STR_LEN + 1;
936*fcf3ce44SJohn Forte 		}
937*fcf3ce44SJohn Forte 		len = strlen(sbussoc_list[*devcnt]) - strlen(sp);
938*fcf3ce44SJohn Forte 		(void) strncpy(buffer, sbussoc_list[*devcnt], len);
939*fcf3ce44SJohn Forte 		buffer[len] = '\0';
940*fcf3ce44SJohn Forte 		sp += len_tmp;
941*fcf3ce44SJohn Forte 		(void) sprintf(sbus_list[*devcnt], "%ssbusmem@%c,0:slot%c",
942*fcf3ce44SJohn Forte 			buffer, sp[0], sp[0]);
943*fcf3ce44SJohn Forte 		*devcnt += 1;
944*fcf3ce44SJohn Forte 	}
945*fcf3ce44SJohn Forte 	else
946*fcf3ce44SJohn Forte 		ret = -1;
947*fcf3ce44SJohn Forte 	return (ret);
948*fcf3ce44SJohn Forte }
949