Merge remote-tracking branch 'moduleh/module.h-split'
[linux-2.6/next.git] / drivers / scsi / sym53c8xx_2 / sym_nvram.c
blob5662fbb3ff60d40dd12e14cfcdd104400e4d2123
1 /*
2 * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
3 * of PCI-SCSI IO processors.
5 * Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr>
7 * This driver is derived from the Linux sym53c8xx driver.
8 * Copyright (C) 1998-2000 Gerard Roudier
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.
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
18 * Other major contributions:
20 * NVRAM detection and reading.
21 * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
23 *-----------------------------------------------------------------------------
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.
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.
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
40 #include "sym_glue.h"
41 #include "sym_nvram.h"
43 #ifdef SYM_CONF_DEBUG_NVRAM
44 static u_char Tekram_boot_delay[7] = {3, 5, 10, 20, 30, 60, 120};
45 #endif
48 * Get host setup from NVRAM.
50 void sym_nvram_setup_host(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram)
53 * Get parity checking, host ID, verbose mode
54 * and miscellaneous host flags from NVRAM.
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;
85 #endif
86 default:
87 break;
92 * Get target set-up from Symbios format NVRAM.
94 static void
95 sym_Symbios_setup_target(struct sym_tcb *tp, int target, Symbios_nvram *nvram)
97 Symbios_target *tn = &nvram->target[target];
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;
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
116 * Get target set-up from Tekram format NVRAM.
118 static void
119 sym_Tekram_setup_target(struct sym_tcb *tp, int target, Tekram_nvram *nvram)
121 struct Tekram_target *tn = &nvram->target[target];
123 if (tn->flags & TEKRAM_TAGGED_COMMANDS) {
124 tp->usrtags = 2 << nvram->max_tags_index;
127 if (tn->flags & TEKRAM_DISCONNECT_ENABLE)
128 tp->usrflags |= SYM_DISC_ENABLED;
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;
136 * Get target setup from NVRAM.
138 void sym_nvram_setup_target(struct sym_tcb *tp, int target, struct sym_nvram *nvp)
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;
152 #ifdef SYM_CONF_DEBUG_NVRAM
154 * Dump Symbios format NVRAM for debugging purpose.
156 static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram)
158 int i;
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" :"");
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);
186 * Dump TEKRAM format NVRAM for debugging purpose.
188 static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram)
190 int i, tags, boot_delay;
191 char *rem;
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;
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);
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);
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 */
241 * 24C16 EEPROM reading.
243 * GPOI0 - data in/data out
244 * GPIO1 - clock
245 * Symbios NVRAM wiring now also used by Tekram.
248 #define SET_BIT 0
249 #define CLR_BIT 1
250 #define SET_CLK 2
251 #define CLR_CLK 3
254 * Set/clear data/clock bit in GPIO0
256 static void S24C16_set_bit(struct sym_device *np, u_char write_bit, u_char *gpreg,
257 int bit_mode)
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;
275 OUTB(np, nc_gpreg, *gpreg);
276 INB(np, nc_mbox1);
277 udelay(5);
281 * Send START condition to NVRAM to wake it up.
283 static void S24C16_start(struct sym_device *np, u_char *gpreg)
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);
292 * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!!
294 static void S24C16_stop(struct sym_device *np, u_char *gpreg)
296 S24C16_set_bit(np, 0, gpreg, SET_CLK);
297 S24C16_set_bit(np, 1, gpreg, SET_BIT);
301 * Read or write a bit to the NVRAM,
302 * read if GPIO0 input else write if GPIO0 output
304 static void S24C16_do_bit(struct sym_device *np, u_char *read_bit, u_char write_bit,
305 u_char *gpreg)
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);
316 * Output an ACK to the NVRAM after reading,
317 * change GPIO0 to output and when done back to an input
319 static void S24C16_write_ack(struct sym_device *np, u_char write_bit, u_char *gpreg,
320 u_char *gpcntl)
322 OUTB(np, nc_gpcntl, *gpcntl & 0xfe);
323 S24C16_do_bit(np, NULL, write_bit, gpreg);
324 OUTB(np, nc_gpcntl, *gpcntl);
328 * Input an ACK from NVRAM after writing,
329 * change GPIO0 to input and when done back to an output
331 static void S24C16_read_ack(struct sym_device *np, u_char *read_bit, u_char *gpreg,
332 u_char *gpcntl)
334 OUTB(np, nc_gpcntl, *gpcntl | 0x01);
335 S24C16_do_bit(np, read_bit, 1, gpreg);
336 OUTB(np, nc_gpcntl, *gpcntl);
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
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)
346 int x;
348 for (x = 0; x < 8; x++)
349 S24C16_do_bit(np, NULL, (write_data >> (7 - x)) & 0x01, gpreg);
351 S24C16_read_ack(np, ack_data, gpreg, gpcntl);
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
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)
361 int x;
362 u_char read_bit;
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));
370 S24C16_write_ack(np, ack_data, gpreg, gpcntl);
373 #ifdef SYM_CONF_NVRAM_WRITE_SUPPORT
375 * Write 'len' bytes starting at 'offset'.
377 static int sym_write_S24C16_nvram(struct sym_device *np, int offset,
378 u_char *data, int len)
380 u_char gpcntl, gpreg;
381 u_char old_gpcntl, old_gpreg;
382 u_char ack_data;
383 int x;
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;
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);
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);
399 /* now set NVRAM inactive with GPIO0/1 both high */
400 S24C16_stop(np, &gpreg);
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);
411 S24C16_write_byte(np, &ack_data, (offset+x) & 0xff,
412 &gpreg, &gpcntl);
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);
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);
424 return 0;
426 #endif /* SYM_CONF_NVRAM_WRITE_SUPPORT */
429 * Read 'len' bytes starting at 'offset'.
431 static int sym_read_S24C16_nvram(struct sym_device *np, int offset, u_char *data, int len)
433 u_char gpcntl, gpreg;
434 u_char old_gpcntl, old_gpreg;
435 u_char ack_data;
436 int retv = 1;
437 int x;
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;
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);
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);
453 /* now set NVRAM inactive with GPIO0/1 both high */
454 S24C16_stop(np, &gpreg);
456 /* activate NVRAM */
457 S24C16_start(np, &gpreg);
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;
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;
471 /* regenerate START state to set up for reading */
472 S24C16_start(np, &gpreg);
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;
480 /* now set up GPIO0 for inputting data */
481 gpcntl |= 0x01;
482 OUTB(np, nc_gpcntl, gpcntl);
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);
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);
498 return retv;
501 #undef SET_BIT
502 #undef CLR_BIT
503 #undef SET_CLK
504 #undef CLR_CLK
507 * Try reading Symbios NVRAM.
508 * Return 0 if OK.
510 static int sym_read_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram)
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;
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;
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;
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;
534 return 0;
538 * 93C46 EEPROM reading.
540 * GPOI0 - data in
541 * GPIO1 - data out
542 * GPIO2 - clock
543 * GPIO4 - chip select
545 * Used by Tekram.
549 * Pulse clock bit in GPIO0
551 static void T93C46_Clk(struct sym_device *np, u_char *gpreg)
553 OUTB(np, nc_gpreg, *gpreg | 0x04);
554 INB(np, nc_mbox1);
555 udelay(2);
556 OUTB(np, nc_gpreg, *gpreg);
560 * Read bit from NVRAM
562 static void T93C46_Read_Bit(struct sym_device *np, u_char *read_bit, u_char *gpreg)
564 udelay(2);
565 T93C46_Clk(np, gpreg);
566 *read_bit = INB(np, nc_gpreg);
570 * Write bit to GPIO0
572 static void T93C46_Write_Bit(struct sym_device *np, u_char write_bit, u_char *gpreg)
574 if (write_bit & 0x01)
575 *gpreg |= 0x02;
576 else
577 *gpreg &= 0xfd;
579 *gpreg |= 0x10;
581 OUTB(np, nc_gpreg, *gpreg);
582 INB(np, nc_mbox1);
583 udelay(2);
585 T93C46_Clk(np, gpreg);
589 * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!!
591 static void T93C46_Stop(struct sym_device *np, u_char *gpreg)
593 *gpreg &= 0xef;
594 OUTB(np, nc_gpreg, *gpreg);
595 INB(np, nc_mbox1);
596 udelay(2);
598 T93C46_Clk(np, gpreg);
602 * Send read command and address to NVRAM
604 static void T93C46_Send_Command(struct sym_device *np, u_short write_data,
605 u_char *read_bit, u_char *gpreg)
607 int x;
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);
613 *read_bit = INB(np, nc_gpreg);
617 * READ 2 bytes from the NVRAM
619 static void T93C46_Read_Word(struct sym_device *np,
620 unsigned short *nvram_data, unsigned char *gpreg)
622 int x;
623 u_char read_bit;
625 *nvram_data = 0;
626 for (x = 0; x < 16; x++) {
627 T93C46_Read_Bit(np, &read_bit, gpreg);
629 if (read_bit & 0x01)
630 *nvram_data |= (0x01 << (15 - x));
631 else
632 *nvram_data &= ~(0x01 << (15 - x));
637 * Read Tekram NvRAM data.
639 static int T93C46_Read_Data(struct sym_device *np, unsigned short *data,
640 int len, unsigned char *gpreg)
642 int x;
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);
654 return 0;
658 * Try reading 93C46 Tekram NVRAM.
660 static int sym_read_T93C46_nvram(struct sym_device *np, Tekram_nvram *nvram)
662 u_char gpcntl, gpreg;
663 u_char old_gpcntl, old_gpreg;
664 int retv = 1;
666 /* save current state of GPCNTL and GPREG */
667 old_gpreg = INB(np, nc_gpreg);
668 old_gpcntl = INB(np, nc_gpcntl);
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);
677 /* input all of NVRAM, 64 words */
678 retv = T93C46_Read_Data(np, (u_short *) nvram,
679 sizeof(*nvram) / sizeof(short), &gpreg);
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);
685 return retv;
689 * Try reading Tekram NVRAM.
690 * Return 0 if OK.
692 static int sym_read_Tekram_nvram (struct sym_device *np, Tekram_nvram *nvram)
694 u_char *data = (u_char *) nvram;
695 int len = sizeof(*nvram);
696 u_short csum;
697 int x;
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;
715 if (x)
716 return 1;
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;
724 return 0;
727 #ifdef CONFIG_PARISC
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.
733 static int sym_read_parisc_pdc(struct sym_device *np, struct pdc_initiator *pdc)
735 struct hardware_path hwpath;
736 get_pci_node_path(np->pdev, &hwpath);
737 if (!pdc_get_initiator(&hwpath, pdc))
738 return 0;
740 return SYM_PARISC_PDC;
742 #else
743 static inline int sym_read_parisc_pdc(struct sym_device *np,
744 struct pdc_initiator *x)
746 return 0;
748 #endif
751 * Try reading Symbios or Tekram NVRAM
753 int sym_read_nvram(struct sym_device *np, struct sym_nvram *nvp)
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);
764 return nvp->type;
767 char *sym_nvram_type(struct sym_nvram *nvp)
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";