Merge branch 'x86-setup-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6] / drivers / scsi / sym53c8xx_2 / sym_nvram.c
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
44 static u_char Tekram_boot_delay[7] = {3, 5, 10, 20, 30, 60, 120};
45 #endif
46
47 /*
48  *  Get host setup from NVRAM.
49  */
50 void 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  */
94 static void
95 sym_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
111 static 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  */
118 static void
119 sym_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  */
138 void 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  */
156 static 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  */
188 static 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
235 static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) { (void)np; (void)nvram; }
236 static 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  */
256 static 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  */
283 static 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  */
294 static 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  */
304 static 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  */
319 static 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  */
331 static 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  */
343 static 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  */
358 static 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  */
377 static 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  */
431 static 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;
493 out:
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  */
510 static 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  */
551 static 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  */
562 static 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  */
572 static 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  */
591 static 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  */
604 static 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  */
619 static 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  */
639 static 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  */
660 static 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  */
692 static 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  */
733 static 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
743 static 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  */
753 int 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
767 char *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 }