1/*
2 * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
3 * of PCI-SCSI IO processors.
4 *
5 * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
6 *
7 * This driver is derived from the Linux sym53c8xx driver.
8 * Copyright (C) 1998-2000  Gerard Roudier
9 *
10 * The sym53c8xx driver is derived from the ncr53c8xx driver that had been
11 * a port of the FreeBSD ncr driver to Linux-1.2.13.
12 *
13 * The original ncr driver has been written for 386bsd and FreeBSD by
14 *         Wolfgang Stanglmeier        <wolf@cologne.de>
15 *         Stefan Esser                <se@mi.Uni-Koeln.de>
16 * Copyright (C) 1994  Wolfgang Stanglmeier
17 *
18 * Other major contributions:
19 *
20 * NVRAM detection and reading.
21 * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
22 *
23 *-----------------------------------------------------------------------------
24 *
25 * This program is free software; you can redistribute it and/or modify
26 * it under the terms of the GNU General Public License as published by
27 * the Free Software Foundation; either version 2 of the License, or
28 * (at your option) any later version.
29 *
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
33 * GNU General Public License for more details.
34 *
35 * You should have received a copy of the GNU General Public License
36 * along with this program; if not, write to the Free Software
37 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
38 */
39
40#include "sym_glue.h"
41#include "sym_nvram.h"
42
43#ifdef	SYM_CONF_DEBUG_NVRAM
44static u_char Tekram_boot_delay[7] = {3, 5, 10, 20, 30, 60, 120};
45#endif
46
47/*
48 *  Get host setup from NVRAM.
49 */
50void sym_nvram_setup_host(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram)
51{
52	/*
53	 *  Get parity checking, host ID, verbose mode
54	 *  and miscellaneous host flags from NVRAM.
55	 */
56	switch (nvram->type) {
57	case SYM_SYMBIOS_NVRAM:
58		if (!(nvram->data.Symbios.flags & SYMBIOS_PARITY_ENABLE))
59			np->rv_scntl0  &= ~0x0a;
60		np->myaddr = nvram->data.Symbios.host_id & 0x0f;
61		if (nvram->data.Symbios.flags & SYMBIOS_VERBOSE_MSGS)
62			np->verbose += 1;
63		if (nvram->data.Symbios.flags1 & SYMBIOS_SCAN_HI_LO)
64			shost->reverse_ordering = 1;
65		if (nvram->data.Symbios.flags2 & SYMBIOS_AVOID_BUS_RESET)
66			np->usrflags |= SYM_AVOID_BUS_RESET;
67		break;
68	case SYM_TEKRAM_NVRAM:
69		np->myaddr = nvram->data.Tekram.host_id & 0x0f;
70		break;
71#ifdef CONFIG_PARISC
72	case SYM_PARISC_PDC:
73		if (nvram->data.parisc.host_id != -1)
74			np->myaddr = nvram->data.parisc.host_id;
75		if (nvram->data.parisc.factor != -1)
76			np->minsync = nvram->data.parisc.factor;
77		if (nvram->data.parisc.width != -1)
78			np->maxwide = nvram->data.parisc.width;
79		switch (nvram->data.parisc.mode) {
80			case 0: np->scsi_mode = SMODE_SE; break;
81			case 1: np->scsi_mode = SMODE_HVD; break;
82			case 2: np->scsi_mode = SMODE_LVD; break;
83			default: break;
84		}
85#endif
86	default:
87		break;
88	}
89}
90
91/*
92 *  Get target set-up from Symbios format NVRAM.
93 */
94static void
95sym_Symbios_setup_target(struct sym_tcb *tp, int target, Symbios_nvram *nvram)
96{
97	Symbios_target *tn = &nvram->target[target];
98
99	if (!(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED))
100		tp->usrtags = 0;
101	if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE))
102		tp->usrflags &= ~SYM_DISC_ENABLED;
103	if (!(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME))
104		tp->usrflags |= SYM_SCAN_BOOT_DISABLED;
105	if (!(tn->flags & SYMBIOS_SCAN_LUNS))
106		tp->usrflags |= SYM_SCAN_LUNS_DISABLED;
107	tp->usr_period = (tn->sync_period + 3) / 4;
108	tp->usr_width = (tn->bus_width == 0x8) ? 0 : 1;
109}
110
111static const unsigned char Tekram_sync[16] = {
112	25, 31, 37, 43, 50, 62, 75, 125, 12, 15, 18, 21, 6, 7, 9, 10
113};
114
115/*
116 *  Get target set-up from Tekram format NVRAM.
117 */
118static void
119sym_Tekram_setup_target(struct sym_tcb *tp, int target, Tekram_nvram *nvram)
120{
121	struct Tekram_target *tn = &nvram->target[target];
122
123	if (tn->flags & TEKRAM_TAGGED_COMMANDS) {
124		tp->usrtags = 2 << nvram->max_tags_index;
125	}
126
127	if (tn->flags & TEKRAM_DISCONNECT_ENABLE)
128		tp->usrflags |= SYM_DISC_ENABLED;
129
130	if (tn->flags & TEKRAM_SYNC_NEGO)
131		tp->usr_period = Tekram_sync[tn->sync_index & 0xf];
132	tp->usr_width = (tn->flags & TEKRAM_WIDE_NEGO) ? 1 : 0;
133}
134
135/*
136 *  Get target setup from NVRAM.
137 */
138void sym_nvram_setup_target(struct sym_tcb *tp, int target, struct sym_nvram *nvp)
139{
140	switch (nvp->type) {
141	case SYM_SYMBIOS_NVRAM:
142		sym_Symbios_setup_target(tp, target, &nvp->data.Symbios);
143		break;
144	case SYM_TEKRAM_NVRAM:
145		sym_Tekram_setup_target(tp, target, &nvp->data.Tekram);
146		break;
147	default:
148		break;
149	}
150}
151
152#ifdef	SYM_CONF_DEBUG_NVRAM
153/*
154 *  Dump Symbios format NVRAM for debugging purpose.
155 */
156static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram)
157{
158	int i;
159
160	/* display Symbios nvram host data */
161	printf("%s: HOST ID=%d%s%s%s%s%s%s\n",
162		sym_name(np), nvram->host_id & 0x0f,
163		(nvram->flags  & SYMBIOS_SCAM_ENABLE)	? " SCAM"	:"",
164		(nvram->flags  & SYMBIOS_PARITY_ENABLE)	? " PARITY"	:"",
165		(nvram->flags  & SYMBIOS_VERBOSE_MSGS)	? " VERBOSE"	:"",
166		(nvram->flags  & SYMBIOS_CHS_MAPPING)	? " CHS_ALT"	:"",
167		(nvram->flags2 & SYMBIOS_AVOID_BUS_RESET)?" NO_RESET"	:"",
168		(nvram->flags1 & SYMBIOS_SCAN_HI_LO)	? " HI_LO"	:"");
169
170	/* display Symbios nvram drive data */
171	for (i = 0 ; i < 15 ; i++) {
172		struct Symbios_target *tn = &nvram->target[i];
173		printf("%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n",
174		sym_name(np), i,
175		(tn->flags & SYMBIOS_DISCONNECT_ENABLE)	? " DISC"	: "",
176		(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME)	? " SCAN_BOOT"	: "",
177		(tn->flags & SYMBIOS_SCAN_LUNS)		? " SCAN_LUNS"	: "",
178		(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ"	: "",
179		tn->bus_width,
180		tn->sync_period / 4,
181		tn->timeout);
182	}
183}
184
185/*
186 *  Dump TEKRAM format NVRAM for debugging purpose.
187 */
188static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram)
189{
190	int i, tags, boot_delay;
191	char *rem;
192
193	/* display Tekram nvram host data */
194	tags = 2 << nvram->max_tags_index;
195	boot_delay = 0;
196	if (nvram->boot_delay_index < 6)
197		boot_delay = Tekram_boot_delay[nvram->boot_delay_index];
198	switch ((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6) {
199	default:
200	case 0:	rem = "";			break;
201	case 1: rem = " REMOVABLE=boot device";	break;
202	case 2: rem = " REMOVABLE=all";		break;
203	}
204
205	printf("%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n",
206		sym_name(np), nvram->host_id & 0x0f,
207		(nvram->flags1 & SYMBIOS_SCAM_ENABLE)	? " SCAM"	:"",
208		(nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES":"",
209		(nvram->flags & TEKRAM_DRIVES_SUP_1GB)	? " >1GB"	:"",
210		(nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET"	:"",
211		(nvram->flags & TEKRAM_ACTIVE_NEGATION)	? " ACT_NEG"	:"",
212		(nvram->flags & TEKRAM_IMMEDIATE_SEEK)	? " IMM_SEEK"	:"",
213		(nvram->flags & TEKRAM_SCAN_LUNS)	? " SCAN_LUNS"	:"",
214		(nvram->flags1 & TEKRAM_F2_F6_ENABLED)	? " F2_F6"	:"",
215		rem, boot_delay, tags);
216
217	/* display Tekram nvram drive data */
218	for (i = 0; i <= 15; i++) {
219		int sync, j;
220		struct Tekram_target *tn = &nvram->target[i];
221		j = tn->sync_index & 0xf;
222		sync = Tekram_sync[j];
223		printf("%s-%d:%s%s%s%s%s%s PERIOD=%d\n",
224		sym_name(np), i,
225		(tn->flags & TEKRAM_PARITY_CHECK)	? " PARITY"	: "",
226		(tn->flags & TEKRAM_SYNC_NEGO)		? " SYNC"	: "",
227		(tn->flags & TEKRAM_DISCONNECT_ENABLE)	? " DISC"	: "",
228		(tn->flags & TEKRAM_START_CMD)		? " START"	: "",
229		(tn->flags & TEKRAM_TAGGED_COMMANDS)	? " TCQ"	: "",
230		(tn->flags & TEKRAM_WIDE_NEGO)		? " WIDE"	: "",
231		sync);
232	}
233}
234#else
235static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) { (void)np; (void)nvram; }
236static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram) { (void)np; (void)nvram; }
237#endif	/* SYM_CONF_DEBUG_NVRAM */
238
239
240/*
241 *  24C16 EEPROM reading.
242 *
243 *  GPOI0 - data in/data out
244 *  GPIO1 - clock
245 *  Symbios NVRAM wiring now also used by Tekram.
246 */
247
248#define SET_BIT 0
249#define CLR_BIT 1
250#define SET_CLK 2
251#define CLR_CLK 3
252
253/*
254 *  Set/clear data/clock bit in GPIO0
255 */
256static void S24C16_set_bit(struct sym_device *np, u_char write_bit, u_char *gpreg,
257			  int bit_mode)
258{
259	udelay(5);
260	switch (bit_mode) {
261	case SET_BIT:
262		*gpreg |= write_bit;
263		break;
264	case CLR_BIT:
265		*gpreg &= 0xfe;
266		break;
267	case SET_CLK:
268		*gpreg |= 0x02;
269		break;
270	case CLR_CLK:
271		*gpreg &= 0xfd;
272		break;
273
274	}
275	OUTB(np, nc_gpreg, *gpreg);
276	INB(np, nc_mbox1);
277	udelay(5);
278}
279
280/*
281 *  Send START condition to NVRAM to wake it up.
282 */
283static void S24C16_start(struct sym_device *np, u_char *gpreg)
284{
285	S24C16_set_bit(np, 1, gpreg, SET_BIT);
286	S24C16_set_bit(np, 0, gpreg, SET_CLK);
287	S24C16_set_bit(np, 0, gpreg, CLR_BIT);
288	S24C16_set_bit(np, 0, gpreg, CLR_CLK);
289}
290
291/*
292 *  Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!!
293 */
294static void S24C16_stop(struct sym_device *np, u_char *gpreg)
295{
296	S24C16_set_bit(np, 0, gpreg, SET_CLK);
297	S24C16_set_bit(np, 1, gpreg, SET_BIT);
298}
299
300/*
301 *  Read or write a bit to the NVRAM,
302 *  read if GPIO0 input else write if GPIO0 output
303 */
304static void S24C16_do_bit(struct sym_device *np, u_char *read_bit, u_char write_bit,
305			 u_char *gpreg)
306{
307	S24C16_set_bit(np, write_bit, gpreg, SET_BIT);
308	S24C16_set_bit(np, 0, gpreg, SET_CLK);
309	if (read_bit)
310		*read_bit = INB(np, nc_gpreg);
311	S24C16_set_bit(np, 0, gpreg, CLR_CLK);
312	S24C16_set_bit(np, 0, gpreg, CLR_BIT);
313}
314
315/*
316 *  Output an ACK to the NVRAM after reading,
317 *  change GPIO0 to output and when done back to an input
318 */
319static void S24C16_write_ack(struct sym_device *np, u_char write_bit, u_char *gpreg,
320			    u_char *gpcntl)
321{
322	OUTB(np, nc_gpcntl, *gpcntl & 0xfe);
323	S24C16_do_bit(np, NULL, write_bit, gpreg);
324	OUTB(np, nc_gpcntl, *gpcntl);
325}
326
327/*
328 *  Input an ACK from NVRAM after writing,
329 *  change GPIO0 to input and when done back to an output
330 */
331static void S24C16_read_ack(struct sym_device *np, u_char *read_bit, u_char *gpreg,
332			   u_char *gpcntl)
333{
334	OUTB(np, nc_gpcntl, *gpcntl | 0x01);
335	S24C16_do_bit(np, read_bit, 1, gpreg);
336	OUTB(np, nc_gpcntl, *gpcntl);
337}
338
339/*
340 *  WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK,
341 *  GPIO0 must already be set as an output
342 */
343static void S24C16_write_byte(struct sym_device *np, u_char *ack_data, u_char write_data,
344			     u_char *gpreg, u_char *gpcntl)
345{
346	int x;
347
348	for (x = 0; x < 8; x++)
349		S24C16_do_bit(np, NULL, (write_data >> (7 - x)) & 0x01, gpreg);
350
351	S24C16_read_ack(np, ack_data, gpreg, gpcntl);
352}
353
354/*
355 *  READ a byte from the NVRAM and then send an ACK to say we have got it,
356 *  GPIO0 must already be set as an input
357 */
358static void S24C16_read_byte(struct sym_device *np, u_char *read_data, u_char ack_data,
359			    u_char *gpreg, u_char *gpcntl)
360{
361	int x;
362	u_char read_bit;
363
364	*read_data = 0;
365	for (x = 0; x < 8; x++) {
366		S24C16_do_bit(np, &read_bit, 1, gpreg);
367		*read_data |= ((read_bit & 0x01) << (7 - x));
368	}
369
370	S24C16_write_ack(np, ack_data, gpreg, gpcntl);
371}
372
373#ifdef SYM_CONF_NVRAM_WRITE_SUPPORT
374/*
375 *  Write 'len' bytes starting at 'offset'.
376 */
377static int sym_write_S24C16_nvram(struct sym_device *np, int offset,
378		u_char *data, int len)
379{
380	u_char	gpcntl, gpreg;
381	u_char	old_gpcntl, old_gpreg;
382	u_char	ack_data;
383	int	x;
384
385	/* save current state of GPCNTL and GPREG */
386	old_gpreg	= INB(np, nc_gpreg);
387	old_gpcntl	= INB(np, nc_gpcntl);
388	gpcntl		= old_gpcntl & 0x1c;
389
390	/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
391	OUTB(np, nc_gpreg,  old_gpreg);
392	OUTB(np, nc_gpcntl, gpcntl);
393
394	/* this is to set NVRAM into a known state with GPIO0/1 both low */
395	gpreg = old_gpreg;
396	S24C16_set_bit(np, 0, &gpreg, CLR_CLK);
397	S24C16_set_bit(np, 0, &gpreg, CLR_BIT);
398
399	/* now set NVRAM inactive with GPIO0/1 both high */
400	S24C16_stop(np, &gpreg);
401
402	/* NVRAM has to be written in segments of 16 bytes */
403	for (x = 0; x < len ; x += 16) {
404		do {
405			S24C16_start(np, &gpreg);
406			S24C16_write_byte(np, &ack_data,
407					  0xa0 | (((offset+x) >> 7) & 0x0e),
408					  &gpreg, &gpcntl);
409		} while (ack_data & 0x01);
410
411		S24C16_write_byte(np, &ack_data, (offset+x) & 0xff,
412				  &gpreg, &gpcntl);
413
414		for (y = 0; y < 16; y++)
415			S24C16_write_byte(np, &ack_data, data[x+y],
416					  &gpreg, &gpcntl);
417		S24C16_stop(np, &gpreg);
418	}
419
420	/* return GPIO0/1 to original states after having accessed NVRAM */
421	OUTB(np, nc_gpcntl, old_gpcntl);
422	OUTB(np, nc_gpreg,  old_gpreg);
423
424	return 0;
425}
426#endif /* SYM_CONF_NVRAM_WRITE_SUPPORT */
427
428/*
429 *  Read 'len' bytes starting at 'offset'.
430 */
431static int sym_read_S24C16_nvram(struct sym_device *np, int offset, u_char *data, int len)
432{
433	u_char	gpcntl, gpreg;
434	u_char	old_gpcntl, old_gpreg;
435	u_char	ack_data;
436	int	retv = 1;
437	int	x;
438
439	/* save current state of GPCNTL and GPREG */
440	old_gpreg	= INB(np, nc_gpreg);
441	old_gpcntl	= INB(np, nc_gpcntl);
442	gpcntl		= old_gpcntl & 0x1c;
443
444	/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
445	OUTB(np, nc_gpreg,  old_gpreg);
446	OUTB(np, nc_gpcntl, gpcntl);
447
448	/* this is to set NVRAM into a known state with GPIO0/1 both low */
449	gpreg = old_gpreg;
450	S24C16_set_bit(np, 0, &gpreg, CLR_CLK);
451	S24C16_set_bit(np, 0, &gpreg, CLR_BIT);
452
453	/* now set NVRAM inactive with GPIO0/1 both high */
454	S24C16_stop(np, &gpreg);
455
456	/* activate NVRAM */
457	S24C16_start(np, &gpreg);
458
459	/* write device code and random address MSB */
460	S24C16_write_byte(np, &ack_data,
461		0xa0 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
462	if (ack_data & 0x01)
463		goto out;
464
465	/* write random address LSB */
466	S24C16_write_byte(np, &ack_data,
467		offset & 0xff, &gpreg, &gpcntl);
468	if (ack_data & 0x01)
469		goto out;
470
471	/* regenerate START state to set up for reading */
472	S24C16_start(np, &gpreg);
473
474	/* rewrite device code and address MSB with read bit set (lsb = 0x01) */
475	S24C16_write_byte(np, &ack_data,
476		0xa1 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
477	if (ack_data & 0x01)
478		goto out;
479
480	/* now set up GPIO0 for inputting data */
481	gpcntl |= 0x01;
482	OUTB(np, nc_gpcntl, gpcntl);
483
484	/* input all requested data - only part of total NVRAM */
485	for (x = 0; x < len; x++)
486		S24C16_read_byte(np, &data[x], (x == (len-1)), &gpreg, &gpcntl);
487
488	/* finally put NVRAM back in inactive mode */
489	gpcntl &= 0xfe;
490	OUTB(np, nc_gpcntl, gpcntl);
491	S24C16_stop(np, &gpreg);
492	retv = 0;
493out:
494	/* return GPIO0/1 to original states after having accessed NVRAM */
495	OUTB(np, nc_gpcntl, old_gpcntl);
496	OUTB(np, nc_gpreg,  old_gpreg);
497
498	return retv;
499}
500
501#undef SET_BIT
502#undef CLR_BIT
503#undef SET_CLK
504#undef CLR_CLK
505
506/*
507 *  Try reading Symbios NVRAM.
508 *  Return 0 if OK.
509 */
510static int sym_read_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram)
511{
512	static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0};
513	u_char *data = (u_char *) nvram;
514	int len  = sizeof(*nvram);
515	u_short	csum;
516	int x;
517
518	/* probe the 24c16 and read the SYMBIOS 24c16 area */
519	if (sym_read_S24C16_nvram (np, SYMBIOS_NVRAM_ADDRESS, data, len))
520		return 1;
521
522	/* check valid NVRAM signature, verify byte count and checksum */
523	if (nvram->type != 0 ||
524	    memcmp(nvram->trailer, Symbios_trailer, 6) ||
525	    nvram->byte_count != len - 12)
526		return 1;
527
528	/* verify checksum */
529	for (x = 6, csum = 0; x < len - 6; x++)
530		csum += data[x];
531	if (csum != nvram->checksum)
532		return 1;
533
534	return 0;
535}
536
537/*
538 *  93C46 EEPROM reading.
539 *
540 *  GPOI0 - data in
541 *  GPIO1 - data out
542 *  GPIO2 - clock
543 *  GPIO4 - chip select
544 *
545 *  Used by Tekram.
546 */
547
548/*
549 *  Pulse clock bit in GPIO0
550 */
551static void T93C46_Clk(struct sym_device *np, u_char *gpreg)
552{
553	OUTB(np, nc_gpreg, *gpreg | 0x04);
554	INB(np, nc_mbox1);
555	udelay(2);
556	OUTB(np, nc_gpreg, *gpreg);
557}
558
559/*
560 *  Read bit from NVRAM
561 */
562static void T93C46_Read_Bit(struct sym_device *np, u_char *read_bit, u_char *gpreg)
563{
564	udelay(2);
565	T93C46_Clk(np, gpreg);
566	*read_bit = INB(np, nc_gpreg);
567}
568
569/*
570 *  Write bit to GPIO0
571 */
572static void T93C46_Write_Bit(struct sym_device *np, u_char write_bit, u_char *gpreg)
573{
574	if (write_bit & 0x01)
575		*gpreg |= 0x02;
576	else
577		*gpreg &= 0xfd;
578
579	*gpreg |= 0x10;
580
581	OUTB(np, nc_gpreg, *gpreg);
582	INB(np, nc_mbox1);
583	udelay(2);
584
585	T93C46_Clk(np, gpreg);
586}
587
588/*
589 *  Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!!
590 */
591static void T93C46_Stop(struct sym_device *np, u_char *gpreg)
592{
593	*gpreg &= 0xef;
594	OUTB(np, nc_gpreg, *gpreg);
595	INB(np, nc_mbox1);
596	udelay(2);
597
598	T93C46_Clk(np, gpreg);
599}
600
601/*
602 *  Send read command and address to NVRAM
603 */
604static void T93C46_Send_Command(struct sym_device *np, u_short write_data,
605				u_char *read_bit, u_char *gpreg)
606{
607	int x;
608
609	/* send 9 bits, start bit (1), command (2), address (6)  */
610	for (x = 0; x < 9; x++)
611		T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg);
612
613	*read_bit = INB(np, nc_gpreg);
614}
615
616/*
617 *  READ 2 bytes from the NVRAM
618 */
619static void T93C46_Read_Word(struct sym_device *np,
620		unsigned short *nvram_data, unsigned char *gpreg)
621{
622	int x;
623	u_char read_bit;
624
625	*nvram_data = 0;
626	for (x = 0; x < 16; x++) {
627		T93C46_Read_Bit(np, &read_bit, gpreg);
628
629		if (read_bit & 0x01)
630			*nvram_data |=  (0x01 << (15 - x));
631		else
632			*nvram_data &= ~(0x01 << (15 - x));
633	}
634}
635
636/*
637 *  Read Tekram NvRAM data.
638 */
639static int T93C46_Read_Data(struct sym_device *np, unsigned short *data,
640		int len, unsigned char *gpreg)
641{
642	int x;
643
644	for (x = 0; x < len; x++)  {
645		unsigned char read_bit;
646		/* output read command and address */
647		T93C46_Send_Command(np, 0x180 | x, &read_bit, gpreg);
648		if (read_bit & 0x01)
649			return 1; /* Bad */
650		T93C46_Read_Word(np, &data[x], gpreg);
651		T93C46_Stop(np, gpreg);
652	}
653
654	return 0;
655}
656
657/*
658 *  Try reading 93C46 Tekram NVRAM.
659 */
660static int sym_read_T93C46_nvram(struct sym_device *np, Tekram_nvram *nvram)
661{
662	u_char gpcntl, gpreg;
663	u_char old_gpcntl, old_gpreg;
664	int retv = 1;
665
666	/* save current state of GPCNTL and GPREG */
667	old_gpreg	= INB(np, nc_gpreg);
668	old_gpcntl	= INB(np, nc_gpcntl);
669
670	/* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in,
671	   1/2/4 out */
672	gpreg = old_gpreg & 0xe9;
673	OUTB(np, nc_gpreg, gpreg);
674	gpcntl = (old_gpcntl & 0xe9) | 0x09;
675	OUTB(np, nc_gpcntl, gpcntl);
676
677	/* input all of NVRAM, 64 words */
678	retv = T93C46_Read_Data(np, (u_short *) nvram,
679				sizeof(*nvram) / sizeof(short), &gpreg);
680
681	/* return GPIO0/1/2/4 to original states after having accessed NVRAM */
682	OUTB(np, nc_gpcntl, old_gpcntl);
683	OUTB(np, nc_gpreg,  old_gpreg);
684
685	return retv;
686}
687
688/*
689 *  Try reading Tekram NVRAM.
690 *  Return 0 if OK.
691 */
692static int sym_read_Tekram_nvram (struct sym_device *np, Tekram_nvram *nvram)
693{
694	u_char *data = (u_char *) nvram;
695	int len = sizeof(*nvram);
696	u_short	csum;
697	int x;
698
699	switch (np->pdev->device) {
700	case PCI_DEVICE_ID_NCR_53C885:
701	case PCI_DEVICE_ID_NCR_53C895:
702	case PCI_DEVICE_ID_NCR_53C896:
703		x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
704					  data, len);
705		break;
706	case PCI_DEVICE_ID_NCR_53C875:
707		x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
708					  data, len);
709		if (!x)
710			break;
711	default:
712		x = sym_read_T93C46_nvram(np, nvram);
713		break;
714	}
715	if (x)
716		return 1;
717
718	/* verify checksum */
719	for (x = 0, csum = 0; x < len - 1; x += 2)
720		csum += data[x] + (data[x+1] << 8);
721	if (csum != 0x1234)
722		return 1;
723
724	return 0;
725}
726
727#ifdef CONFIG_PARISC
728/*
729 * Host firmware (PDC) keeps a table for altering SCSI capabilities.
730 * Many newer machines export one channel of 53c896 chip as SE, 50-pin HD.
731 * Also used for Multi-initiator SCSI clusters to set the SCSI Initiator ID.
732 */
733static int sym_read_parisc_pdc(struct sym_device *np, struct pdc_initiator *pdc)
734{
735	struct hardware_path hwpath;
736	get_pci_node_path(np->pdev, &hwpath);
737	if (!pdc_get_initiator(&hwpath, pdc))
738		return 0;
739
740	return SYM_PARISC_PDC;
741}
742#else
743static inline int sym_read_parisc_pdc(struct sym_device *np,
744					struct pdc_initiator *x)
745{
746	return 0;
747}
748#endif
749
750/*
751 *  Try reading Symbios or Tekram NVRAM
752 */
753int sym_read_nvram(struct sym_device *np, struct sym_nvram *nvp)
754{
755	if (!sym_read_Symbios_nvram(np, &nvp->data.Symbios)) {
756		nvp->type = SYM_SYMBIOS_NVRAM;
757		sym_display_Symbios_nvram(np, &nvp->data.Symbios);
758	} else if (!sym_read_Tekram_nvram(np, &nvp->data.Tekram)) {
759		nvp->type = SYM_TEKRAM_NVRAM;
760		sym_display_Tekram_nvram(np, &nvp->data.Tekram);
761	} else {
762		nvp->type = sym_read_parisc_pdc(np, &nvp->data.parisc);
763	}
764	return nvp->type;
765}
766
767char *sym_nvram_type(struct sym_nvram *nvp)
768{
769	switch (nvp->type) {
770	case SYM_SYMBIOS_NVRAM:
771		return "Symbios NVRAM";
772	case SYM_TEKRAM_NVRAM:
773		return "Tekram NVRAM";
774	case SYM_PARISC_PDC:
775		return "PA-RISC Firmware";
776	default:
777		return "No NVRAM";
778	}
779}
780