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
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};
48 * Get host setup from NVRAM.
50 void sym_nvram_setup_host(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)
63 if (nvram->data.Symbios.flags1 & SYMBIOS_SCAN_HI_LO)
64 np->usrflags |= SYM_SCAN_TARGETS_HILO;
65 if (nvram->data.Symbios.flags2 & SYMBIOS_AVOID_BUS_RESET)
66 np->usrflags |= SYM_AVOID_BUS_RESET;
68 case SYM_TEKRAM_NVRAM:
69 np->myaddr = nvram->data.Tekram.host_id & 0x0f;
77 * Get target set-up from Symbios format NVRAM.
80 sym_Symbios_setup_target(struct sym_hcb *np, int target, Symbios_nvram *nvram)
82 struct sym_tcb *tp = &np->target[target];
83 Symbios_target *tn = &nvram->target[target];
86 (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? SYM_SETUP_MAX_TAG : 0;
88 if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE))
89 tp->usrflags &= ~SYM_DISC_ENABLED;
90 if (!(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME))
91 tp->usrflags |= SYM_SCAN_BOOT_DISABLED;
92 if (!(tn->flags & SYMBIOS_SCAN_LUNS))
93 tp->usrflags |= SYM_SCAN_LUNS_DISABLED;
97 * Get target set-up from Tekram format NVRAM.
100 sym_Tekram_setup_target(struct sym_hcb *np, int target, Tekram_nvram *nvram)
102 struct sym_tcb *tp = &np->target[target];
103 struct Tekram_target *tn = &nvram->target[target];
105 if (tn->flags & TEKRAM_TAGGED_COMMANDS) {
106 tp->usrtags = 2 << nvram->max_tags_index;
109 if (tn->flags & TEKRAM_DISCONNECT_ENABLE)
110 tp->usrflags |= SYM_DISC_ENABLED;
112 /* If any device does not support parity, we will not use this option */
113 if (!(tn->flags & TEKRAM_PARITY_CHECK))
114 np->rv_scntl0 &= ~0x0a; /* SCSI parity checking disabled */
118 * Get target setup from NVRAM.
120 void sym_nvram_setup_target(struct sym_hcb *np, int target, struct sym_nvram *nvp)
123 case SYM_SYMBIOS_NVRAM:
124 sym_Symbios_setup_target(np, target, &nvp->data.Symbios);
126 case SYM_TEKRAM_NVRAM:
127 sym_Tekram_setup_target(np, target, &nvp->data.Tekram);
134 #ifdef SYM_CONF_DEBUG_NVRAM
136 * Dump Symbios format NVRAM for debugging purpose.
138 static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram)
142 /* display Symbios nvram host data */
143 printf("%s: HOST ID=%d%s%s%s%s%s%s\n",
144 sym_name(np), nvram->host_id & 0x0f,
145 (nvram->flags & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"",
146 (nvram->flags & SYMBIOS_PARITY_ENABLE) ? " PARITY" :"",
147 (nvram->flags & SYMBIOS_VERBOSE_MSGS) ? " VERBOSE" :"",
148 (nvram->flags & SYMBIOS_CHS_MAPPING) ? " CHS_ALT" :"",
149 (nvram->flags2 & SYMBIOS_AVOID_BUS_RESET)?" NO_RESET" :"",
150 (nvram->flags1 & SYMBIOS_SCAN_HI_LO) ? " HI_LO" :"");
152 /* display Symbios nvram drive data */
153 for (i = 0 ; i < 15 ; i++) {
154 struct Symbios_target *tn = &nvram->target[i];
155 printf("%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n",
157 (tn->flags & SYMBIOS_DISCONNECT_ENABLE) ? " DISC" : "",
158 (tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME) ? " SCAN_BOOT" : "",
159 (tn->flags & SYMBIOS_SCAN_LUNS) ? " SCAN_LUNS" : "",
160 (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ" : "",
168 * Dump TEKRAM format NVRAM for debugging purpose.
170 static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram)
172 int i, tags, boot_delay;
175 /* display Tekram nvram host data */
176 tags = 2 << nvram->max_tags_index;
178 if (nvram->boot_delay_index < 6)
179 boot_delay = Tekram_boot_delay[nvram->boot_delay_index];
180 switch ((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6) {
182 case 0: rem = ""; break;
183 case 1: rem = " REMOVABLE=boot device"; break;
184 case 2: rem = " REMOVABLE=all"; break;
187 printf("%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n",
188 sym_name(np), nvram->host_id & 0x0f,
189 (nvram->flags1 & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"",
190 (nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES":"",
191 (nvram->flags & TEKRAM_DRIVES_SUP_1GB) ? " >1GB" :"",
192 (nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET" :"",
193 (nvram->flags & TEKRAM_ACTIVE_NEGATION) ? " ACT_NEG" :"",
194 (nvram->flags & TEKRAM_IMMEDIATE_SEEK) ? " IMM_SEEK" :"",
195 (nvram->flags & TEKRAM_SCAN_LUNS) ? " SCAN_LUNS" :"",
196 (nvram->flags1 & TEKRAM_F2_F6_ENABLED) ? " F2_F6" :"",
197 rem, boot_delay, tags);
199 /* display Tekram nvram drive data */
200 for (i = 0; i <= 15; i++) {
202 struct Tekram_target *tn = &nvram->target[i];
203 j = tn->sync_index & 0xf;
204 sync = Tekram_sync[j];
205 printf("%s-%d:%s%s%s%s%s%s PERIOD=%d\n",
207 (tn->flags & TEKRAM_PARITY_CHECK) ? " PARITY" : "",
208 (tn->flags & TEKRAM_SYNC_NEGO) ? " SYNC" : "",
209 (tn->flags & TEKRAM_DISCONNECT_ENABLE) ? " DISC" : "",
210 (tn->flags & TEKRAM_START_CMD) ? " START" : "",
211 (tn->flags & TEKRAM_TAGGED_COMMANDS) ? " TCQ" : "",
212 (tn->flags & TEKRAM_WIDE_NEGO) ? " WIDE" : "",
217 static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) { (void)np; (void)nvram; }
218 static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram) { (void)np; (void)nvram; }
219 #endif /* SYM_CONF_DEBUG_NVRAM */
223 * 24C16 EEPROM reading.
225 * GPOI0 - data in/data out
227 * Symbios NVRAM wiring now also used by Tekram.
236 * Set/clear data/clock bit in GPIO0
238 static void S24C16_set_bit(struct sym_device *np, u_char write_bit, u_char *gpreg,
257 OUTB (nc_gpreg, *gpreg);
262 * Send START condition to NVRAM to wake it up.
264 static void S24C16_start(struct sym_device *np, u_char *gpreg)
266 S24C16_set_bit(np, 1, gpreg, SET_BIT);
267 S24C16_set_bit(np, 0, gpreg, SET_CLK);
268 S24C16_set_bit(np, 0, gpreg, CLR_BIT);
269 S24C16_set_bit(np, 0, gpreg, CLR_CLK);
273 * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!!
275 static void S24C16_stop(struct sym_device *np, u_char *gpreg)
277 S24C16_set_bit(np, 0, gpreg, SET_CLK);
278 S24C16_set_bit(np, 1, gpreg, SET_BIT);
282 * Read or write a bit to the NVRAM,
283 * read if GPIO0 input else write if GPIO0 output
285 static void S24C16_do_bit(struct sym_device *np, u_char *read_bit, u_char write_bit,
288 S24C16_set_bit(np, write_bit, gpreg, SET_BIT);
289 S24C16_set_bit(np, 0, gpreg, SET_CLK);
291 *read_bit = INB (nc_gpreg);
292 S24C16_set_bit(np, 0, gpreg, CLR_CLK);
293 S24C16_set_bit(np, 0, gpreg, CLR_BIT);
297 * Output an ACK to the NVRAM after reading,
298 * change GPIO0 to output and when done back to an input
300 static void S24C16_write_ack(struct sym_device *np, u_char write_bit, u_char *gpreg,
303 OUTB (nc_gpcntl, *gpcntl & 0xfe);
304 S24C16_do_bit(np, NULL, write_bit, gpreg);
305 OUTB (nc_gpcntl, *gpcntl);
309 * Input an ACK from NVRAM after writing,
310 * change GPIO0 to input and when done back to an output
312 static void S24C16_read_ack(struct sym_device *np, u_char *read_bit, u_char *gpreg,
315 OUTB (nc_gpcntl, *gpcntl | 0x01);
316 S24C16_do_bit(np, read_bit, 1, gpreg);
317 OUTB (nc_gpcntl, *gpcntl);
321 * WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK,
322 * GPIO0 must already be set as an output
324 static void S24C16_write_byte(struct sym_device *np, u_char *ack_data, u_char write_data,
325 u_char *gpreg, u_char *gpcntl)
329 for (x = 0; x < 8; x++)
330 S24C16_do_bit(np, NULL, (write_data >> (7 - x)) & 0x01, gpreg);
332 S24C16_read_ack(np, ack_data, gpreg, gpcntl);
336 * READ a byte from the NVRAM and then send an ACK to say we have got it,
337 * GPIO0 must already be set as an input
339 static void S24C16_read_byte(struct sym_device *np, u_char *read_data, u_char ack_data,
340 u_char *gpreg, u_char *gpcntl)
346 for (x = 0; x < 8; x++) {
347 S24C16_do_bit(np, &read_bit, 1, gpreg);
348 *read_data |= ((read_bit & 0x01) << (7 - x));
351 S24C16_write_ack(np, ack_data, gpreg, gpcntl);
354 #if SYM_CONF_NVRAM_WRITE_SUPPORT
356 * Write 'len' bytes starting at 'offset'.
358 static int sym_write_S24C16_nvram(struct sym_device *np, int offset,
359 u_char *data, int len)
361 u_char gpcntl, gpreg;
362 u_char old_gpcntl, old_gpreg;
366 /* save current state of GPCNTL and GPREG */
367 old_gpreg = INB (nc_gpreg);
368 old_gpcntl = INB (nc_gpcntl);
369 gpcntl = old_gpcntl & 0x1c;
371 /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
372 OUTB (nc_gpreg, old_gpreg);
373 OUTB (nc_gpcntl, gpcntl);
375 /* this is to set NVRAM into a known state with GPIO0/1 both low */
377 S24C16_set_bit(np, 0, &gpreg, CLR_CLK);
378 S24C16_set_bit(np, 0, &gpreg, CLR_BIT);
380 /* now set NVRAM inactive with GPIO0/1 both high */
381 S24C16_stop(np, &gpreg);
383 /* NVRAM has to be written in segments of 16 bytes */
384 for (x = 0; x < len ; x += 16) {
386 S24C16_start(np, &gpreg);
387 S24C16_write_byte(np, &ack_data,
388 0xa0 | (((offset+x) >> 7) & 0x0e),
390 } while (ack_data & 0x01);
392 S24C16_write_byte(np, &ack_data, (offset+x) & 0xff,
395 for (y = 0; y < 16; y++)
396 S24C16_write_byte(np, &ack_data, data[x+y],
398 S24C16_stop(np, &gpreg);
401 /* return GPIO0/1 to original states after having accessed NVRAM */
402 OUTB (nc_gpcntl, old_gpcntl);
403 OUTB (nc_gpreg, old_gpreg);
407 #endif /* SYM_CONF_NVRAM_WRITE_SUPPORT */
410 * Read 'len' bytes starting at 'offset'.
412 static int sym_read_S24C16_nvram(struct sym_device *np, int offset, u_char *data, int len)
414 u_char gpcntl, gpreg;
415 u_char old_gpcntl, old_gpreg;
420 /* save current state of GPCNTL and GPREG */
421 old_gpreg = INB (nc_gpreg);
422 old_gpcntl = INB (nc_gpcntl);
423 gpcntl = old_gpcntl & 0x1c;
425 /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
426 OUTB (nc_gpreg, old_gpreg);
427 OUTB (nc_gpcntl, gpcntl);
429 /* this is to set NVRAM into a known state with GPIO0/1 both low */
431 S24C16_set_bit(np, 0, &gpreg, CLR_CLK);
432 S24C16_set_bit(np, 0, &gpreg, CLR_BIT);
434 /* now set NVRAM inactive with GPIO0/1 both high */
435 S24C16_stop(np, &gpreg);
438 S24C16_start(np, &gpreg);
440 /* write device code and random address MSB */
441 S24C16_write_byte(np, &ack_data,
442 0xa0 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
446 /* write random address LSB */
447 S24C16_write_byte(np, &ack_data,
448 offset & 0xff, &gpreg, &gpcntl);
452 /* regenerate START state to set up for reading */
453 S24C16_start(np, &gpreg);
455 /* rewrite device code and address MSB with read bit set (lsb = 0x01) */
456 S24C16_write_byte(np, &ack_data,
457 0xa1 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
461 /* now set up GPIO0 for inputting data */
463 OUTB (nc_gpcntl, gpcntl);
465 /* input all requested data - only part of total NVRAM */
466 for (x = 0; x < len; x++)
467 S24C16_read_byte(np, &data[x], (x == (len-1)), &gpreg, &gpcntl);
469 /* finally put NVRAM back in inactive mode */
471 OUTB (nc_gpcntl, gpcntl);
472 S24C16_stop(np, &gpreg);
475 /* return GPIO0/1 to original states after having accessed NVRAM */
476 OUTB (nc_gpcntl, old_gpcntl);
477 OUTB (nc_gpreg, old_gpreg);
488 * Try reading Symbios NVRAM.
491 static int sym_read_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram)
493 static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0};
494 u_char *data = (u_char *) nvram;
495 int len = sizeof(*nvram);
499 /* probe the 24c16 and read the SYMBIOS 24c16 area */
500 if (sym_read_S24C16_nvram (np, SYMBIOS_NVRAM_ADDRESS, data, len))
503 /* check valid NVRAM signature, verify byte count and checksum */
504 if (nvram->type != 0 ||
505 memcmp(nvram->trailer, Symbios_trailer, 6) ||
506 nvram->byte_count != len - 12)
509 /* verify checksum */
510 for (x = 6, csum = 0; x < len - 6; x++)
512 if (csum != nvram->checksum)
519 * 93C46 EEPROM reading.
524 * GPIO4 - chip select
530 * Pulse clock bit in GPIO0
532 static void T93C46_Clk(struct sym_device *np, u_char *gpreg)
534 OUTB (nc_gpreg, *gpreg | 0x04);
536 OUTB (nc_gpreg, *gpreg);
540 * Read bit from NVRAM
542 static void T93C46_Read_Bit(struct sym_device *np, u_char *read_bit, u_char *gpreg)
545 T93C46_Clk(np, gpreg);
546 *read_bit = INB (nc_gpreg);
552 static void T93C46_Write_Bit(struct sym_device *np, u_char write_bit, u_char *gpreg)
554 if (write_bit & 0x01)
561 OUTB (nc_gpreg, *gpreg);
564 T93C46_Clk(np, gpreg);
568 * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!!
570 static void T93C46_Stop(struct sym_device *np, u_char *gpreg)
573 OUTB (nc_gpreg, *gpreg);
576 T93C46_Clk(np, gpreg);
580 * Send read command and address to NVRAM
582 static void T93C46_Send_Command(struct sym_device *np, u_short write_data,
583 u_char *read_bit, u_char *gpreg)
587 /* send 9 bits, start bit (1), command (2), address (6) */
588 for (x = 0; x < 9; x++)
589 T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg);
591 *read_bit = INB (nc_gpreg);
595 * READ 2 bytes from the NVRAM
597 static void T93C46_Read_Word(struct sym_device *np,
598 unsigned short *nvram_data, unsigned char *gpreg)
604 for (x = 0; x < 16; x++) {
605 T93C46_Read_Bit(np, &read_bit, gpreg);
608 *nvram_data |= (0x01 << (15 - x));
610 *nvram_data &= ~(0x01 << (15 - x));
615 * Read Tekram NvRAM data.
617 static int T93C46_Read_Data(struct sym_device *np, unsigned short *data,
618 int len, unsigned char *gpreg)
622 for (x = 0; x < len; x++) {
623 unsigned char read_bit;
624 /* output read command and address */
625 T93C46_Send_Command(np, 0x180 | x, &read_bit, gpreg);
628 T93C46_Read_Word(np, &data[x], gpreg);
629 T93C46_Stop(np, gpreg);
636 * Try reading 93C46 Tekram NVRAM.
638 static int sym_read_T93C46_nvram(struct sym_device *np, Tekram_nvram *nvram)
640 u_char gpcntl, gpreg;
641 u_char old_gpcntl, old_gpreg;
644 /* save current state of GPCNTL and GPREG */
645 old_gpreg = INB (nc_gpreg);
646 old_gpcntl = INB (nc_gpcntl);
648 /* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in,
650 gpreg = old_gpreg & 0xe9;
651 OUTB (nc_gpreg, gpreg);
652 gpcntl = (old_gpcntl & 0xe9) | 0x09;
653 OUTB (nc_gpcntl, gpcntl);
655 /* input all of NVRAM, 64 words */
656 retv = T93C46_Read_Data(np, (u_short *) nvram,
657 sizeof(*nvram) / sizeof(short), &gpreg);
659 /* return GPIO0/1/2/4 to original states after having accessed NVRAM */
660 OUTB (nc_gpcntl, old_gpcntl);
661 OUTB (nc_gpreg, old_gpreg);
667 * Try reading Tekram NVRAM.
670 static int sym_read_Tekram_nvram (struct sym_device *np, Tekram_nvram *nvram)
672 u_char *data = (u_char *) nvram;
673 int len = sizeof(*nvram);
677 switch (np->device_id) {
678 case PCI_DEVICE_ID_NCR_53C885:
679 case PCI_DEVICE_ID_NCR_53C895:
680 case PCI_DEVICE_ID_NCR_53C896:
681 x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
684 case PCI_DEVICE_ID_NCR_53C875:
685 x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
690 x = sym_read_T93C46_nvram(np, nvram);
696 /* verify checksum */
697 for (x = 0, csum = 0; x < len - 1; x += 2)
698 csum += data[x] + (data[x+1] << 8);
706 * Try reading Symbios or Tekram NVRAM
708 int sym_read_nvram(struct sym_device *np, struct sym_nvram *nvp)
710 if (!sym_read_Symbios_nvram(np, &nvp->data.Symbios)) {
711 nvp->type = SYM_SYMBIOS_NVRAM;
712 sym_display_Symbios_nvram(np, &nvp->data.Symbios);
713 } else if (!sym_read_Tekram_nvram(np, &nvp->data.Tekram)) {
714 nvp->type = SYM_TEKRAM_NVRAM;
715 sym_display_Tekram_nvram(np, &nvp->data.Tekram);