linux/drivers/scsi/sym53c8xx_2/sym_nvram.c
<<
>>
Prefs
   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
  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
  95sym_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
 111static 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 */
 118static void
 119sym_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 */
 138void 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 */
 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);
 276        INB(np, nc_mbox1);
 277        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
 373#ifdef SYM_CONF_NVRAM_WRITE_SUPPORT
 374/*
 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);
 554        INB(np, nc_mbox1);
 555        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);
 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 */
 591static 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 */
 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
 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 */
 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
 743static 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 */
 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}
 780