blob: 5662fbb3ff60d40dd12e14cfcdd104400e4d2123 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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
Matthew Wilcoxb37df482005-11-29 23:08:44 -050095sym_Symbios_setup_target(struct sym_tcb *tp, int target, Symbios_nvram *nvram)
Linus Torvalds1da177e2005-04-16 15:20:36 -070096{
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 Symbios_target *tn = &nvram->target[target];
98
Matthew Wilcoxb37df482005-11-29 23:08:44 -050099 if (!(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED))
100 tp->usrtags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 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;
Matthew Wilcoxb37df482005-11-29 23:08:44 -0500107 tp->usr_period = (tn->sync_period + 3) / 4;
108 tp->usr_width = (tn->bus_width == 0x8) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109}
110
Matthew Wilcoxb37df482005-11-29 23:08:44 -0500111static 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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115/*
116 * Get target set-up from Tekram format NVRAM.
117 */
118static void
Matthew Wilcoxb37df482005-11-29 23:08:44 -0500119sym_Tekram_setup_target(struct sym_tcb *tp, int target, Tekram_nvram *nvram)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 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
Matthew Wilcoxb37df482005-11-29 23:08:44 -0500130 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133}
134
135/*
136 * Get target setup from NVRAM.
137 */
Matthew Wilcoxb37df482005-11-29 23:08:44 -0500138void sym_nvram_setup_target(struct sym_tcb *tp, int target, struct sym_nvram *nvp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139{
140 switch (nvp->type) {
141 case SYM_SYMBIOS_NVRAM:
Matthew Wilcoxb37df482005-11-29 23:08:44 -0500142 sym_Symbios_setup_target(tp, target, &nvp->data.Symbios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 break;
144 case SYM_TEKRAM_NVRAM:
Matthew Wilcoxb37df482005-11-29 23:08:44 -0500145 sym_Tekram_setup_target(tp, target, &nvp->data.Tekram);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 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);
Matthew Wilcox 53222b92005-05-20 19:15:43 +0100276 INB(np, nc_mbox1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 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
Olaf Hering44456d32005-07-27 11:45:17 -0700373#ifdef SYM_CONF_NVRAM_WRITE_SUPPORT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374/*
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);
Matthew Wilcox 53222b92005-05-20 19:15:43 +0100554 INB(np, nc_mbox1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 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);
Matthew Wilcox 53222b92005-05-20 19:15:43 +0100582 INB(np, nc_mbox1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 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);
Matthew Wilcox 53222b92005-05-20 19:15:43 +0100595 INB(np, nc_mbox1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 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
Matthew Wilcoxe58bc062007-10-05 15:55:06 -0400699 switch (np->pdev->device) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 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
Matthew Wilcox 53222b92005-05-20 19:15:43 +0100743static inline int sym_read_parisc_pdc(struct sym_device *np,
744 struct pdc_initiator *x)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745{
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}