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 * Redistribution and use in source and binary forms, with or without
26 * modification, are permitted provided that the following conditions
27 * are met:
28 * 1. Redistributions of source code must retain the above copyright
29 * notice, this list of conditions and the following disclaimer.
30 * 2. The name of the author may not be used to endorse or promote products
31 * derived from this software without specific prior written permission.
32 *
33 * Where this Software is combined with software released under the terms of
34 * the GNU Public License ("GPL") and the terms of the GPL would require the
35 * combined work to also be released under the terms of the GPL, the terms
36 * and conditions of this License will apply in addition to those of the
37 * GPL with the exception of any terms or conditions of this License that
38 * conflict with, or are expressly prohibited by, the GPL.
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
44 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 * SUCH DAMAGE.
51 */
52
53 #ifdef __FreeBSD__
54 #include <dev/sym/sym_glue.h>
55 #else
56 #include "sym_glue.h"
57 #endif
58
59 /*
60 * Some poor and bogus sync table that refers to Tekram NVRAM layout.
61 */
62 #if SYM_CONF_NVRAM_SUPPORT
63 static u_char Tekram_sync[16] =
64 {25,31,37,43, 50,62,75,125, 12,15,18,21, 6,7,9,10};
65 #ifdef SYM_CONF_DEBUG_NVRAM
66 static u_char Tekram_boot_delay[7] = {3, 5, 10, 20, 30, 60, 120};
67 #endif
68 #endif
69
70 /*
71 * Get host setup from NVRAM.
72 */
sym_nvram_setup_host(hcb_p np,struct sym_nvram * nvram)73 void sym_nvram_setup_host (hcb_p np, struct sym_nvram *nvram)
74 {
75 #if SYM_CONF_NVRAM_SUPPORT
76 /*
77 * Get parity checking, host ID, verbose mode
78 * and miscellaneous host flags from NVRAM.
79 */
80 switch(nvram->type) {
81 case SYM_SYMBIOS_NVRAM:
82 if (!(nvram->data.Symbios.flags & SYMBIOS_PARITY_ENABLE))
83 np->rv_scntl0 &= ~0x0a;
84 np->myaddr = nvram->data.Symbios.host_id & 0x0f;
85 if (nvram->data.Symbios.flags & SYMBIOS_VERBOSE_MSGS)
86 np->verbose += 1;
87 if (nvram->data.Symbios.flags1 & SYMBIOS_SCAN_HI_LO)
88 np->usrflags |= SYM_SCAN_TARGETS_HILO;
89 if (nvram->data.Symbios.flags2 & SYMBIOS_AVOID_BUS_RESET)
90 np->usrflags |= SYM_AVOID_BUS_RESET;
91 break;
92 case SYM_TEKRAM_NVRAM:
93 np->myaddr = nvram->data.Tekram.host_id & 0x0f;
94 break;
95 default:
96 break;
97 }
98 #endif
99 }
100
101 /*
102 * Get target setup from NVRAM.
103 */
104 #if SYM_CONF_NVRAM_SUPPORT
105 static void sym_Symbios_setup_target(hcb_p np,int target, Symbios_nvram *nvram);
106 static void sym_Tekram_setup_target(hcb_p np,int target, Tekram_nvram *nvram);
107 #endif
108
sym_nvram_setup_target(hcb_p np,int target,struct sym_nvram * nvp)109 void sym_nvram_setup_target (hcb_p np, int target, struct sym_nvram *nvp)
110 {
111 #if SYM_CONF_NVRAM_SUPPORT
112 switch(nvp->type) {
113 case SYM_SYMBIOS_NVRAM:
114 sym_Symbios_setup_target (np, target, &nvp->data.Symbios);
115 break;
116 case SYM_TEKRAM_NVRAM:
117 sym_Tekram_setup_target (np, target, &nvp->data.Tekram);
118 break;
119 default:
120 break;
121 }
122 #endif
123 }
124
125 #if SYM_CONF_NVRAM_SUPPORT
126 /*
127 * Get target set-up from Symbios format NVRAM.
128 */
129 static void
sym_Symbios_setup_target(hcb_p np,int target,Symbios_nvram * nvram)130 sym_Symbios_setup_target(hcb_p np, int target, Symbios_nvram *nvram)
131 {
132 tcb_p tp = &np->target[target];
133 Symbios_target *tn = &nvram->target[target];
134
135 tp->tinfo.user.period = tn->sync_period ? (tn->sync_period + 3) / 4 : 0;
136 tp->tinfo.user.width = tn->bus_width == 0x10 ? BUS_16_BIT : BUS_8_BIT;
137 tp->usrtags =
138 (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? SYM_SETUP_MAX_TAG : 0;
139
140 if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE))
141 tp->usrflags &= ~SYM_DISC_ENABLED;
142 if (!(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME))
143 tp->usrflags |= SYM_SCAN_BOOT_DISABLED;
144 if (!(tn->flags & SYMBIOS_SCAN_LUNS))
145 tp->usrflags |= SYM_SCAN_LUNS_DISABLED;
146 }
147
148 /*
149 * Get target set-up from Tekram format NVRAM.
150 */
151 static void
sym_Tekram_setup_target(hcb_p np,int target,Tekram_nvram * nvram)152 sym_Tekram_setup_target(hcb_p np, int target, Tekram_nvram *nvram)
153 {
154 tcb_p tp = &np->target[target];
155 struct Tekram_target *tn = &nvram->target[target];
156 int i;
157
158 if (tn->flags & TEKRAM_SYNC_NEGO) {
159 i = tn->sync_index & 0xf;
160 tp->tinfo.user.period = Tekram_sync[i];
161 }
162
163 tp->tinfo.user.width =
164 (tn->flags & TEKRAM_WIDE_NEGO) ? BUS_16_BIT : BUS_8_BIT;
165
166 if (tn->flags & TEKRAM_TAGGED_COMMANDS) {
167 tp->usrtags = 2 << nvram->max_tags_index;
168 }
169
170 if (tn->flags & TEKRAM_DISCONNECT_ENABLE)
171 tp->usrflags |= SYM_DISC_ENABLED;
172
173 /* If any device does not support parity, we will not use this option */
174 if (!(tn->flags & TEKRAM_PARITY_CHECK))
175 np->rv_scntl0 &= ~0x0a; /* SCSI parity checking disabled */
176 }
177
178 #ifdef SYM_CONF_DEBUG_NVRAM
179 /*
180 * Dump Symbios format NVRAM for debugging purpose.
181 */
sym_display_Symbios_nvram(sdev_p np,Symbios_nvram * nvram)182 static void sym_display_Symbios_nvram(sdev_p np, Symbios_nvram *nvram)
183 {
184 int i;
185
186 /* display Symbios nvram host data */
187 printf("%s: HOST ID=%d%s%s%s%s%s%s\n",
188 sym_name(np), nvram->host_id & 0x0f,
189 (nvram->flags & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"",
190 (nvram->flags & SYMBIOS_PARITY_ENABLE) ? " PARITY" :"",
191 (nvram->flags & SYMBIOS_VERBOSE_MSGS) ? " VERBOSE" :"",
192 (nvram->flags & SYMBIOS_CHS_MAPPING) ? " CHS_ALT" :"",
193 (nvram->flags2 & SYMBIOS_AVOID_BUS_RESET)?" NO_RESET" :"",
194 (nvram->flags1 & SYMBIOS_SCAN_HI_LO) ? " HI_LO" :"");
195
196 /* display Symbios nvram drive data */
197 for (i = 0 ; i < 15 ; i++) {
198 struct Symbios_target *tn = &nvram->target[i];
199 printf("%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n",
200 sym_name(np), i,
201 (tn->flags & SYMBIOS_DISCONNECT_ENABLE) ? " DISC" : "",
202 (tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME) ? " SCAN_BOOT" : "",
203 (tn->flags & SYMBIOS_SCAN_LUNS) ? " SCAN_LUNS" : "",
204 (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ" : "",
205 tn->bus_width,
206 tn->sync_period / 4,
207 tn->timeout);
208 }
209 }
210
211 /*
212 * Dump TEKRAM format NVRAM for debugging purpose.
213 */
sym_display_Tekram_nvram(sdev_p np,Tekram_nvram * nvram)214 static void sym_display_Tekram_nvram(sdev_p np, Tekram_nvram *nvram)
215 {
216 int i, tags, boot_delay;
217 char *rem;
218
219 /* display Tekram nvram host data */
220 tags = 2 << nvram->max_tags_index;
221 boot_delay = 0;
222 if (nvram->boot_delay_index < 6)
223 boot_delay = Tekram_boot_delay[nvram->boot_delay_index];
224 switch((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6) {
225 default:
226 case 0: rem = ""; break;
227 case 1: rem = " REMOVABLE=boot device"; break;
228 case 2: rem = " REMOVABLE=all"; break;
229 }
230
231 printf("%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n",
232 sym_name(np), nvram->host_id & 0x0f,
233 (nvram->flags1 & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"",
234 (nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES":"",
235 (nvram->flags & TEKRAM_DRIVES_SUP_1GB) ? " >1GB" :"",
236 (nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET" :"",
237 (nvram->flags & TEKRAM_ACTIVE_NEGATION) ? " ACT_NEG" :"",
238 (nvram->flags & TEKRAM_IMMEDIATE_SEEK) ? " IMM_SEEK" :"",
239 (nvram->flags & TEKRAM_SCAN_LUNS) ? " SCAN_LUNS" :"",
240 (nvram->flags1 & TEKRAM_F2_F6_ENABLED) ? " F2_F6" :"",
241 rem, boot_delay, tags);
242
243 /* display Tekram nvram drive data */
244 for (i = 0; i <= 15; i++) {
245 int sync, j;
246 struct Tekram_target *tn = &nvram->target[i];
247 j = tn->sync_index & 0xf;
248 sync = Tekram_sync[j];
249 printf("%s-%d:%s%s%s%s%s%s PERIOD=%d\n",
250 sym_name(np), i,
251 (tn->flags & TEKRAM_PARITY_CHECK) ? " PARITY" : "",
252 (tn->flags & TEKRAM_SYNC_NEGO) ? " SYNC" : "",
253 (tn->flags & TEKRAM_DISCONNECT_ENABLE) ? " DISC" : "",
254 (tn->flags & TEKRAM_START_CMD) ? " START" : "",
255 (tn->flags & TEKRAM_TAGGED_COMMANDS) ? " TCQ" : "",
256 (tn->flags & TEKRAM_WIDE_NEGO) ? " WIDE" : "",
257 sync);
258 }
259 }
260 #endif /* SYM_CONF_DEBUG_NVRAM */
261 #endif /* SYM_CONF_NVRAM_SUPPORT */
262
263
264 /*
265 * Try reading Symbios or Tekram NVRAM
266 */
267 #if SYM_CONF_NVRAM_SUPPORT
268 static int sym_read_Symbios_nvram (sdev_p np, Symbios_nvram *nvram);
269 static int sym_read_Tekram_nvram (sdev_p np, Tekram_nvram *nvram);
270 #endif
271
sym_read_nvram(sdev_p np,struct sym_nvram * nvp)272 int sym_read_nvram (sdev_p np, struct sym_nvram *nvp)
273 {
274 #if SYM_CONF_NVRAM_SUPPORT
275 /*
276 * Try to read SYMBIOS nvram.
277 * Try to read TEKRAM nvram if Symbios nvram not found.
278 */
279 if (SYM_SETUP_SYMBIOS_NVRAM &&
280 !sym_read_Symbios_nvram (np, &nvp->data.Symbios)) {
281 nvp->type = SYM_SYMBIOS_NVRAM;
282 #ifdef SYM_CONF_DEBUG_NVRAM
283 sym_display_Symbios_nvram(np, &nvp->data.Symbios);
284 #endif
285 }
286 else if (SYM_SETUP_TEKRAM_NVRAM &&
287 !sym_read_Tekram_nvram (np, &nvp->data.Tekram)) {
288 nvp->type = SYM_TEKRAM_NVRAM;
289 #ifdef SYM_CONF_DEBUG_NVRAM
290 sym_display_Tekram_nvram(np, &nvp->data.Tekram);
291 #endif
292 }
293 else
294 nvp->type = 0;
295 #else
296 nvp->type = 0;
297 #endif
298 return nvp->type;
299 }
300
301
302 #if SYM_CONF_NVRAM_SUPPORT
303 /*
304 * 24C16 EEPROM reading.
305 *
306 * GPOI0 - data in/data out
307 * GPIO1 - clock
308 * Symbios NVRAM wiring now also used by Tekram.
309 */
310
311 #define SET_BIT 0
312 #define CLR_BIT 1
313 #define SET_CLK 2
314 #define CLR_CLK 3
315
316 /*
317 * Set/clear data/clock bit in GPIO0
318 */
S24C16_set_bit(sdev_p np,u_char write_bit,u_char * gpreg,int bit_mode)319 static void S24C16_set_bit(sdev_p np, u_char write_bit, u_char *gpreg,
320 int bit_mode)
321 {
322 UDELAY (5);
323 switch (bit_mode){
324 case SET_BIT:
325 *gpreg |= write_bit;
326 break;
327 case CLR_BIT:
328 *gpreg &= 0xfe;
329 break;
330 case SET_CLK:
331 *gpreg |= 0x02;
332 break;
333 case CLR_CLK:
334 *gpreg &= 0xfd;
335 break;
336
337 }
338 OUTB (nc_gpreg, *gpreg);
339 UDELAY (5);
340 }
341
342 /*
343 * Send START condition to NVRAM to wake it up.
344 */
S24C16_start(sdev_p np,u_char * gpreg)345 static void S24C16_start(sdev_p np, u_char *gpreg)
346 {
347 S24C16_set_bit(np, 1, gpreg, SET_BIT);
348 S24C16_set_bit(np, 0, gpreg, SET_CLK);
349 S24C16_set_bit(np, 0, gpreg, CLR_BIT);
350 S24C16_set_bit(np, 0, gpreg, CLR_CLK);
351 }
352
353 /*
354 * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!!
355 */
S24C16_stop(sdev_p np,u_char * gpreg)356 static void S24C16_stop(sdev_p np, u_char *gpreg)
357 {
358 S24C16_set_bit(np, 0, gpreg, SET_CLK);
359 S24C16_set_bit(np, 1, gpreg, SET_BIT);
360 }
361
362 /*
363 * Read or write a bit to the NVRAM,
364 * read if GPIO0 input else write if GPIO0 output
365 */
S24C16_do_bit(sdev_p np,u_char * read_bit,u_char write_bit,u_char * gpreg)366 static void S24C16_do_bit(sdev_p np, u_char *read_bit, u_char write_bit,
367 u_char *gpreg)
368 {
369 S24C16_set_bit(np, write_bit, gpreg, SET_BIT);
370 S24C16_set_bit(np, 0, gpreg, SET_CLK);
371 if (read_bit)
372 *read_bit = INB (nc_gpreg);
373 S24C16_set_bit(np, 0, gpreg, CLR_CLK);
374 S24C16_set_bit(np, 0, gpreg, CLR_BIT);
375 }
376
377 /*
378 * Output an ACK to the NVRAM after reading,
379 * change GPIO0 to output and when done back to an input
380 */
S24C16_write_ack(sdev_p np,u_char write_bit,u_char * gpreg,u_char * gpcntl)381 static void S24C16_write_ack(sdev_p np, u_char write_bit, u_char *gpreg,
382 u_char *gpcntl)
383 {
384 OUTB (nc_gpcntl, *gpcntl & 0xfe);
385 S24C16_do_bit(np, 0, write_bit, gpreg);
386 OUTB (nc_gpcntl, *gpcntl);
387 }
388
389 /*
390 * Input an ACK from NVRAM after writing,
391 * change GPIO0 to input and when done back to an output
392 */
S24C16_read_ack(sdev_p np,u_char * read_bit,u_char * gpreg,u_char * gpcntl)393 static void S24C16_read_ack(sdev_p np, u_char *read_bit, u_char *gpreg,
394 u_char *gpcntl)
395 {
396 OUTB (nc_gpcntl, *gpcntl | 0x01);
397 S24C16_do_bit(np, read_bit, 1, gpreg);
398 OUTB (nc_gpcntl, *gpcntl);
399 }
400
401 /*
402 * WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK,
403 * GPIO0 must already be set as an output
404 */
S24C16_write_byte(sdev_p np,u_char * ack_data,u_char write_data,u_char * gpreg,u_char * gpcntl)405 static void S24C16_write_byte(sdev_p np, u_char *ack_data, u_char write_data,
406 u_char *gpreg, u_char *gpcntl)
407 {
408 int x;
409
410 for (x = 0; x < 8; x++)
411 S24C16_do_bit(np, 0, (write_data >> (7 - x)) & 0x01, gpreg);
412
413 S24C16_read_ack(np, ack_data, gpreg, gpcntl);
414 }
415
416 /*
417 * READ a byte from the NVRAM and then send an ACK to say we have got it,
418 * GPIO0 must already be set as an input
419 */
S24C16_read_byte(sdev_p np,u_char * read_data,u_char ack_data,u_char * gpreg,u_char * gpcntl)420 static void S24C16_read_byte(sdev_p np, u_char *read_data, u_char ack_data,
421 u_char *gpreg, u_char *gpcntl)
422 {
423 int x;
424 u_char read_bit;
425
426 *read_data = 0;
427 for (x = 0; x < 8; x++) {
428 S24C16_do_bit(np, &read_bit, 1, gpreg);
429 *read_data |= ((read_bit & 0x01) << (7 - x));
430 }
431
432 S24C16_write_ack(np, ack_data, gpreg, gpcntl);
433 }
434
435 /*
436 * Read 'len' bytes starting at 'offset'.
437 */
sym_read_S24C16_nvram(sdev_p np,int offset,u_char * data,int len)438 static int sym_read_S24C16_nvram (sdev_p np, int offset, u_char *data, int len)
439 {
440 u_char gpcntl, gpreg;
441 u_char old_gpcntl, old_gpreg;
442 u_char ack_data;
443 int retv = 1;
444 int x;
445
446 /* save current state of GPCNTL and GPREG */
447 old_gpreg = INB (nc_gpreg);
448 old_gpcntl = INB (nc_gpcntl);
449 gpcntl = old_gpcntl & 0x1c;
450
451 /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
452 OUTB (nc_gpreg, old_gpreg);
453 OUTB (nc_gpcntl, gpcntl);
454
455 /* this is to set NVRAM into a known state with GPIO0/1 both low */
456 gpreg = old_gpreg;
457 S24C16_set_bit(np, 0, &gpreg, CLR_CLK);
458 S24C16_set_bit(np, 0, &gpreg, CLR_BIT);
459
460 /* now set NVRAM inactive with GPIO0/1 both high */
461 S24C16_stop(np, &gpreg);
462
463 /* activate NVRAM */
464 S24C16_start(np, &gpreg);
465
466 /* write device code and random address MSB */
467 S24C16_write_byte(np, &ack_data,
468 0xa0 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
469 if (ack_data & 0x01)
470 goto out;
471
472 /* write random address LSB */
473 S24C16_write_byte(np, &ack_data,
474 offset & 0xff, &gpreg, &gpcntl);
475 if (ack_data & 0x01)
476 goto out;
477
478 /* regenerate START state to set up for reading */
479 S24C16_start(np, &gpreg);
480
481 /* rewrite device code and address MSB with read bit set (lsb = 0x01) */
482 S24C16_write_byte(np, &ack_data,
483 0xa1 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
484 if (ack_data & 0x01)
485 goto out;
486
487 /* now set up GPIO0 for inputting data */
488 gpcntl |= 0x01;
489 OUTB (nc_gpcntl, gpcntl);
490
491 /* input all requested data - only part of total NVRAM */
492 for (x = 0; x < len; x++)
493 S24C16_read_byte(np, &data[x], (x == (len-1)), &gpreg, &gpcntl);
494
495 /* finally put NVRAM back in inactive mode */
496 gpcntl &= 0xfe;
497 OUTB (nc_gpcntl, gpcntl);
498 S24C16_stop(np, &gpreg);
499 retv = 0;
500 out:
501 /* return GPIO0/1 to original states after having accessed NVRAM */
502 OUTB (nc_gpcntl, old_gpcntl);
503 OUTB (nc_gpreg, old_gpreg);
504
505 return retv;
506 }
507
508 #undef SET_BIT
509 #undef CLR_BIT
510 #undef SET_CLK
511 #undef CLR_CLK
512
513 /*
514 * Try reading Symbios NVRAM.
515 * Return 0 if OK.
516 */
sym_read_Symbios_nvram(sdev_p np,Symbios_nvram * nvram)517 static int sym_read_Symbios_nvram (sdev_p np, Symbios_nvram *nvram)
518 {
519 static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0};
520 u_char *data = (u_char *) nvram;
521 int len = sizeof(*nvram);
522 u_short csum;
523 int x;
524
525 /* probe the 24c16 and read the SYMBIOS 24c16 area */
526 if (sym_read_S24C16_nvram (np, SYMBIOS_NVRAM_ADDRESS, data, len))
527 return 1;
528
529 /* check valid NVRAM signature, verify byte count and checksum */
530 if (nvram->type != 0 ||
531 bcmp(nvram->trailer, Symbios_trailer, 6) ||
532 nvram->byte_count != len - 12)
533 return 1;
534
535 /* verify checksum */
536 for (x = 6, csum = 0; x < len - 6; x++)
537 csum += data[x];
538 if (csum != nvram->checksum)
539 return 1;
540
541 return 0;
542 }
543
544 /*
545 * 93C46 EEPROM reading.
546 *
547 * GPOI0 - data in
548 * GPIO1 - data out
549 * GPIO2 - clock
550 * GPIO4 - chip select
551 *
552 * Used by Tekram.
553 */
554
555 /*
556 * Pulse clock bit in GPIO0
557 */
T93C46_Clk(sdev_p np,u_char * gpreg)558 static void T93C46_Clk(sdev_p np, u_char *gpreg)
559 {
560 OUTB (nc_gpreg, *gpreg | 0x04);
561 UDELAY (2);
562 OUTB (nc_gpreg, *gpreg);
563 }
564
565 /*
566 * Read bit from NVRAM
567 */
T93C46_Read_Bit(sdev_p np,u_char * read_bit,u_char * gpreg)568 static void T93C46_Read_Bit(sdev_p np, u_char *read_bit, u_char *gpreg)
569 {
570 UDELAY (2);
571 T93C46_Clk(np, gpreg);
572 *read_bit = INB (nc_gpreg);
573 }
574
575 /*
576 * Write bit to GPIO0
577 */
T93C46_Write_Bit(sdev_p np,u_char write_bit,u_char * gpreg)578 static void T93C46_Write_Bit(sdev_p np, u_char write_bit, u_char *gpreg)
579 {
580 if (write_bit & 0x01)
581 *gpreg |= 0x02;
582 else
583 *gpreg &= 0xfd;
584
585 *gpreg |= 0x10;
586
587 OUTB (nc_gpreg, *gpreg);
588 UDELAY (2);
589
590 T93C46_Clk(np, gpreg);
591 }
592
593 /*
594 * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!!
595 */
T93C46_Stop(sdev_p np,u_char * gpreg)596 static void T93C46_Stop(sdev_p np, u_char *gpreg)
597 {
598 *gpreg &= 0xef;
599 OUTB (nc_gpreg, *gpreg);
600 UDELAY (2);
601
602 T93C46_Clk(np, gpreg);
603 }
604
605 /*
606 * Send read command and address to NVRAM
607 */
T93C46_Send_Command(sdev_p np,u_short write_data,u_char * read_bit,u_char * gpreg)608 static void T93C46_Send_Command(sdev_p np, u_short write_data,
609 u_char *read_bit, u_char *gpreg)
610 {
611 int x;
612
613 /* send 9 bits, start bit (1), command (2), address (6) */
614 for (x = 0; x < 9; x++)
615 T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg);
616
617 *read_bit = INB (nc_gpreg);
618 }
619
620 /*
621 * READ 2 bytes from the NVRAM
622 */
T93C46_Read_Word(sdev_p np,u_short * nvram_data,u_char * gpreg)623 static void T93C46_Read_Word(sdev_p np, u_short *nvram_data, u_char *gpreg)
624 {
625 int x;
626 u_char read_bit;
627
628 *nvram_data = 0;
629 for (x = 0; x < 16; x++) {
630 T93C46_Read_Bit(np, &read_bit, gpreg);
631
632 if (read_bit & 0x01)
633 *nvram_data |= (0x01 << (15 - x));
634 else
635 *nvram_data &= ~(0x01 << (15 - x));
636 }
637 }
638
639 /*
640 * Read Tekram NvRAM data.
641 */
T93C46_Read_Data(sdev_p np,u_short * data,int len,u_char * gpreg)642 static int T93C46_Read_Data(sdev_p np, u_short *data,int len,u_char *gpreg)
643 {
644 u_char read_bit;
645 int x;
646
647 for (x = 0; x < len; x++) {
648
649 /* output read command and address */
650 T93C46_Send_Command(np, 0x180 | x, &read_bit, gpreg);
651 if (read_bit & 0x01)
652 return 1; /* Bad */
653 T93C46_Read_Word(np, &data[x], gpreg);
654 T93C46_Stop(np, gpreg);
655 }
656
657 return 0;
658 }
659
660 /*
661 * Try reading 93C46 Tekram NVRAM.
662 */
sym_read_T93C46_nvram(sdev_p np,Tekram_nvram * nvram)663 static int sym_read_T93C46_nvram (sdev_p np, Tekram_nvram *nvram)
664 {
665 u_char gpcntl, gpreg;
666 u_char old_gpcntl, old_gpreg;
667 int retv = 1;
668
669 /* save current state of GPCNTL and GPREG */
670 old_gpreg = INB (nc_gpreg);
671 old_gpcntl = INB (nc_gpcntl);
672
673 /* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in,
674 1/2/4 out */
675 gpreg = old_gpreg & 0xe9;
676 OUTB (nc_gpreg, gpreg);
677 gpcntl = (old_gpcntl & 0xe9) | 0x09;
678 OUTB (nc_gpcntl, gpcntl);
679
680 /* input all of NVRAM, 64 words */
681 retv = T93C46_Read_Data(np, (u_short *) nvram,
682 sizeof(*nvram) / sizeof(short), &gpreg);
683
684 /* return GPIO0/1/2/4 to original states after having accessed NVRAM */
685 OUTB (nc_gpcntl, old_gpcntl);
686 OUTB (nc_gpreg, old_gpreg);
687
688 return retv;
689 }
690
691 /*
692 * Try reading Tekram NVRAM.
693 * Return 0 if OK.
694 */
sym_read_Tekram_nvram(sdev_p np,Tekram_nvram * nvram)695 static int sym_read_Tekram_nvram (sdev_p np, Tekram_nvram *nvram)
696 {
697 u_char *data = (u_char *) nvram;
698 int len = sizeof(*nvram);
699 u_short csum;
700 int x;
701
702 switch (np->device_id) {
703 case PCI_ID_SYM53C885:
704 case PCI_ID_SYM53C895:
705 case PCI_ID_SYM53C896:
706 x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
707 data, len);
708 break;
709 case PCI_ID_SYM53C875:
710 x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
711 data, len);
712 if (!x)
713 break;
714 default:
715 x = sym_read_T93C46_nvram(np, nvram);
716 break;
717 }
718 if (x)
719 return 1;
720
721 /* verify checksum */
722 for (x = 0, csum = 0; x < len - 1; x += 2)
723 csum += data[x] + (data[x+1] << 8);
724 if (csum != 0x1234)
725 return 1;
726
727 return 0;
728 }
729
730 #endif /* SYM_CONF_NVRAM_SUPPORT */
731