linux/drivers/scsi/sym53c8xx_2/sym_nvram.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 
   4 * of PCI-SCSI IO processors.
   5 *
   6 * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
   7 *
   8 * This driver is derived from the Linux sym53c8xx driver.
   9 * Copyright (C) 1998-2000  Gerard Roudier
  10 *
  11 * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 
  12 * a port of the FreeBSD ncr driver to Linux-1.2.13.
  13 *
  14 * The original ncr driver has been written for 386bsd and FreeBSD by
  15 *         Wolfgang Stanglmeier        <wolf@cologne.de>
  16 *         Stefan Esser                <se@mi.Uni-Koeln.de>
  17 * Copyright (C) 1994  Wolfgang Stanglmeier
  18 *
  19 * Other major contributions:
  20 *
  21 * NVRAM detection and reading.
  22 * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
  23 *
  24 *-----------------------------------------------------------------------------
  25 */
  26
  27#include "sym_glue.h"
  28#include "sym_nvram.h"
  29
  30#ifdef  SYM_CONF_DEBUG_NVRAM
  31static u_char Tekram_boot_delay[7] = {3, 5, 10, 20, 30, 60, 120};
  32#endif
  33
  34/*
  35 *  Get host setup from NVRAM.
  36 */
  37void sym_nvram_setup_host(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram)
  38{
  39        /*
  40         *  Get parity checking, host ID, verbose mode 
  41         *  and miscellaneous host flags from NVRAM.
  42         */
  43        switch (nvram->type) {
  44        case SYM_SYMBIOS_NVRAM:
  45                if (!(nvram->data.Symbios.flags & SYMBIOS_PARITY_ENABLE))
  46                        np->rv_scntl0  &= ~0x0a;
  47                np->myaddr = nvram->data.Symbios.host_id & 0x0f;
  48                if (nvram->data.Symbios.flags & SYMBIOS_VERBOSE_MSGS)
  49                        np->verbose += 1;
  50                if (nvram->data.Symbios.flags1 & SYMBIOS_SCAN_HI_LO)
  51                        shost->reverse_ordering = 1;
  52                if (nvram->data.Symbios.flags2 & SYMBIOS_AVOID_BUS_RESET)
  53                        np->usrflags |= SYM_AVOID_BUS_RESET;
  54                break;
  55        case SYM_TEKRAM_NVRAM:
  56                np->myaddr = nvram->data.Tekram.host_id & 0x0f;
  57                break;
  58#ifdef CONFIG_PARISC
  59        case SYM_PARISC_PDC:
  60                if (nvram->data.parisc.host_id != -1)
  61                        np->myaddr = nvram->data.parisc.host_id;
  62                if (nvram->data.parisc.factor != -1)
  63                        np->minsync = nvram->data.parisc.factor;
  64                if (nvram->data.parisc.width != -1)
  65                        np->maxwide = nvram->data.parisc.width;
  66                switch (nvram->data.parisc.mode) {
  67                        case 0: np->scsi_mode = SMODE_SE; break;
  68                        case 1: np->scsi_mode = SMODE_HVD; break;
  69                        case 2: np->scsi_mode = SMODE_LVD; break;
  70                        default: break;
  71                }
  72#endif
  73        default:
  74                break;
  75        }
  76}
  77
  78/*
  79 *  Get target set-up from Symbios format NVRAM.
  80 */
  81static void
  82sym_Symbios_setup_target(struct sym_tcb *tp, int target, Symbios_nvram *nvram)
  83{
  84        Symbios_target *tn = &nvram->target[target];
  85
  86        if (!(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED))
  87                tp->usrtags = 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;
  94        tp->usr_period = (tn->sync_period + 3) / 4;
  95        tp->usr_width = (tn->bus_width == 0x8) ? 0 : 1;
  96}
  97
  98static const unsigned char Tekram_sync[16] = {
  99        25, 31, 37, 43, 50, 62, 75, 125, 12, 15, 18, 21, 6, 7, 9, 10
 100};
 101
 102/*
 103 *  Get target set-up from Tekram format NVRAM.
 104 */
 105static void
 106sym_Tekram_setup_target(struct sym_tcb *tp, int target, Tekram_nvram *nvram)
 107{
 108        struct Tekram_target *tn = &nvram->target[target];
 109
 110        if (tn->flags & TEKRAM_TAGGED_COMMANDS) {
 111                tp->usrtags = 2 << nvram->max_tags_index;
 112        }
 113
 114        if (tn->flags & TEKRAM_DISCONNECT_ENABLE)
 115                tp->usrflags |= SYM_DISC_ENABLED;
 116 
 117        if (tn->flags & TEKRAM_SYNC_NEGO)
 118                tp->usr_period = Tekram_sync[tn->sync_index & 0xf];
 119        tp->usr_width = (tn->flags & TEKRAM_WIDE_NEGO) ? 1 : 0;
 120}
 121
 122/*
 123 *  Get target setup from NVRAM.
 124 */
 125void sym_nvram_setup_target(struct sym_tcb *tp, int target, struct sym_nvram *nvp)
 126{
 127        switch (nvp->type) {
 128        case SYM_SYMBIOS_NVRAM:
 129                sym_Symbios_setup_target(tp, target, &nvp->data.Symbios);
 130                break;
 131        case SYM_TEKRAM_NVRAM:
 132                sym_Tekram_setup_target(tp, target, &nvp->data.Tekram);
 133                break;
 134        default:
 135                break;
 136        }
 137}
 138
 139#ifdef  SYM_CONF_DEBUG_NVRAM
 140/*
 141 *  Dump Symbios format NVRAM for debugging purpose.
 142 */
 143static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram)
 144{
 145        int i;
 146
 147        /* display Symbios nvram host data */
 148        printf("%s: HOST ID=%d%s%s%s%s%s%s\n",
 149                sym_name(np), nvram->host_id & 0x0f,
 150                (nvram->flags  & SYMBIOS_SCAM_ENABLE)   ? " SCAM"       :"",
 151                (nvram->flags  & SYMBIOS_PARITY_ENABLE) ? " PARITY"     :"",
 152                (nvram->flags  & SYMBIOS_VERBOSE_MSGS)  ? " VERBOSE"    :"", 
 153                (nvram->flags  & SYMBIOS_CHS_MAPPING)   ? " CHS_ALT"    :"", 
 154                (nvram->flags2 & SYMBIOS_AVOID_BUS_RESET)?" NO_RESET"   :"",
 155                (nvram->flags1 & SYMBIOS_SCAN_HI_LO)    ? " HI_LO"      :"");
 156
 157        /* display Symbios nvram drive data */
 158        for (i = 0 ; i < 15 ; i++) {
 159                struct Symbios_target *tn = &nvram->target[i];
 160                printf("%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n",
 161                sym_name(np), i,
 162                (tn->flags & SYMBIOS_DISCONNECT_ENABLE) ? " DISC"       : "",
 163                (tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME) ? " SCAN_BOOT"  : "",
 164                (tn->flags & SYMBIOS_SCAN_LUNS)         ? " SCAN_LUNS"  : "",
 165                (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ"        : "",
 166                tn->bus_width,
 167                tn->sync_period / 4,
 168                tn->timeout);
 169        }
 170}
 171
 172/*
 173 *  Dump TEKRAM format NVRAM for debugging purpose.
 174 */
 175static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram)
 176{
 177        int i, tags, boot_delay;
 178        char *rem;
 179
 180        /* display Tekram nvram host data */
 181        tags = 2 << nvram->max_tags_index;
 182        boot_delay = 0;
 183        if (nvram->boot_delay_index < 6)
 184                boot_delay = Tekram_boot_delay[nvram->boot_delay_index];
 185        switch ((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6) {
 186        default:
 187        case 0: rem = "";                       break;
 188        case 1: rem = " REMOVABLE=boot device"; break;
 189        case 2: rem = " REMOVABLE=all";         break;
 190        }
 191
 192        printf("%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n",
 193                sym_name(np), nvram->host_id & 0x0f,
 194                (nvram->flags1 & SYMBIOS_SCAM_ENABLE)   ? " SCAM"       :"",
 195                (nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES":"",
 196                (nvram->flags & TEKRAM_DRIVES_SUP_1GB)  ? " >1GB"       :"",
 197                (nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET"    :"",
 198                (nvram->flags & TEKRAM_ACTIVE_NEGATION) ? " ACT_NEG"    :"",
 199                (nvram->flags & TEKRAM_IMMEDIATE_SEEK)  ? " IMM_SEEK"   :"",
 200                (nvram->flags & TEKRAM_SCAN_LUNS)       ? " SCAN_LUNS"  :"",
 201                (nvram->flags1 & TEKRAM_F2_F6_ENABLED)  ? " F2_F6"      :"",
 202                rem, boot_delay, tags);
 203
 204        /* display Tekram nvram drive data */
 205        for (i = 0; i <= 15; i++) {
 206                int sync, j;
 207                struct Tekram_target *tn = &nvram->target[i];
 208                j = tn->sync_index & 0xf;
 209                sync = Tekram_sync[j];
 210                printf("%s-%d:%s%s%s%s%s%s PERIOD=%d\n",
 211                sym_name(np), i,
 212                (tn->flags & TEKRAM_PARITY_CHECK)       ? " PARITY"     : "",
 213                (tn->flags & TEKRAM_SYNC_NEGO)          ? " SYNC"       : "",
 214                (tn->flags & TEKRAM_DISCONNECT_ENABLE)  ? " DISC"       : "",
 215                (tn->flags & TEKRAM_START_CMD)          ? " START"      : "",
 216                (tn->flags & TEKRAM_TAGGED_COMMANDS)    ? " TCQ"        : "",
 217                (tn->flags & TEKRAM_WIDE_NEGO)          ? " WIDE"       : "",
 218                sync);
 219        }
 220}
 221#else
 222static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) { (void)np; (void)nvram; }
 223static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram) { (void)np; (void)nvram; }
 224#endif  /* SYM_CONF_DEBUG_NVRAM */
 225
 226
 227/*
 228 *  24C16 EEPROM reading.
 229 *
 230 *  GPIO0 - data in/data out
 231 *  GPIO1 - clock
 232 *  Symbios NVRAM wiring now also used by Tekram.
 233 */
 234
 235#define SET_BIT 0
 236#define CLR_BIT 1
 237#define SET_CLK 2
 238#define CLR_CLK 3
 239
 240/*
 241 *  Set/clear data/clock bit in GPIO0
 242 */
 243static void S24C16_set_bit(struct sym_device *np, u_char write_bit, u_char *gpreg, 
 244                          int bit_mode)
 245{
 246        udelay(5);
 247        switch (bit_mode) {
 248        case SET_BIT:
 249                *gpreg |= write_bit;
 250                break;
 251        case CLR_BIT:
 252                *gpreg &= 0xfe;
 253                break;
 254        case SET_CLK:
 255                *gpreg |= 0x02;
 256                break;
 257        case CLR_CLK:
 258                *gpreg &= 0xfd;
 259                break;
 260
 261        }
 262        OUTB(np, nc_gpreg, *gpreg);
 263        INB(np, nc_mbox1);
 264        udelay(5);
 265}
 266
 267/*
 268 *  Send START condition to NVRAM to wake it up.
 269 */
 270static void S24C16_start(struct sym_device *np, u_char *gpreg)
 271{
 272        S24C16_set_bit(np, 1, gpreg, SET_BIT);
 273        S24C16_set_bit(np, 0, gpreg, SET_CLK);
 274        S24C16_set_bit(np, 0, gpreg, CLR_BIT);
 275        S24C16_set_bit(np, 0, gpreg, CLR_CLK);
 276}
 277
 278/*
 279 *  Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!!
 280 */
 281static void S24C16_stop(struct sym_device *np, u_char *gpreg)
 282{
 283        S24C16_set_bit(np, 0, gpreg, SET_CLK);
 284        S24C16_set_bit(np, 1, gpreg, SET_BIT);
 285}
 286
 287/*
 288 *  Read or write a bit to the NVRAM,
 289 *  read if GPIO0 input else write if GPIO0 output
 290 */
 291static void S24C16_do_bit(struct sym_device *np, u_char *read_bit, u_char write_bit, 
 292                         u_char *gpreg)
 293{
 294        S24C16_set_bit(np, write_bit, gpreg, SET_BIT);
 295        S24C16_set_bit(np, 0, gpreg, SET_CLK);
 296        if (read_bit)
 297                *read_bit = INB(np, nc_gpreg);
 298        S24C16_set_bit(np, 0, gpreg, CLR_CLK);
 299        S24C16_set_bit(np, 0, gpreg, CLR_BIT);
 300}
 301
 302/*
 303 *  Output an ACK to the NVRAM after reading,
 304 *  change GPIO0 to output and when done back to an input
 305 */
 306static void S24C16_write_ack(struct sym_device *np, u_char write_bit, u_char *gpreg, 
 307                            u_char *gpcntl)
 308{
 309        OUTB(np, nc_gpcntl, *gpcntl & 0xfe);
 310        S24C16_do_bit(np, NULL, write_bit, gpreg);
 311        OUTB(np, nc_gpcntl, *gpcntl);
 312}
 313
 314/*
 315 *  Input an ACK from NVRAM after writing,
 316 *  change GPIO0 to input and when done back to an output
 317 */
 318static void S24C16_read_ack(struct sym_device *np, u_char *read_bit, u_char *gpreg, 
 319                           u_char *gpcntl)
 320{
 321        OUTB(np, nc_gpcntl, *gpcntl | 0x01);
 322        S24C16_do_bit(np, read_bit, 1, gpreg);
 323        OUTB(np, nc_gpcntl, *gpcntl);
 324}
 325
 326/*
 327 *  WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK,
 328 *  GPIO0 must already be set as an output
 329 */
 330static void S24C16_write_byte(struct sym_device *np, u_char *ack_data, u_char write_data, 
 331                             u_char *gpreg, u_char *gpcntl)
 332{
 333        int x;
 334        
 335        for (x = 0; x < 8; x++)
 336                S24C16_do_bit(np, NULL, (write_data >> (7 - x)) & 0x01, gpreg);
 337                
 338        S24C16_read_ack(np, ack_data, gpreg, gpcntl);
 339}
 340
 341/*
 342 *  READ a byte from the NVRAM and then send an ACK to say we have got it,
 343 *  GPIO0 must already be set as an input
 344 */
 345static void S24C16_read_byte(struct sym_device *np, u_char *read_data, u_char ack_data, 
 346                            u_char *gpreg, u_char *gpcntl)
 347{
 348        int x;
 349        u_char read_bit;
 350
 351        *read_data = 0;
 352        for (x = 0; x < 8; x++) {
 353                S24C16_do_bit(np, &read_bit, 1, gpreg);
 354                *read_data |= ((read_bit & 0x01) << (7 - x));
 355        }
 356
 357        S24C16_write_ack(np, ack_data, gpreg, gpcntl);
 358}
 359
 360#ifdef SYM_CONF_NVRAM_WRITE_SUPPORT
 361/*
 362 *  Write 'len' bytes starting at 'offset'.
 363 */
 364static int sym_write_S24C16_nvram(struct sym_device *np, int offset,
 365                u_char *data, int len)
 366{
 367        u_char  gpcntl, gpreg;
 368        u_char  old_gpcntl, old_gpreg;
 369        u_char  ack_data;
 370        int     x;
 371
 372        /* save current state of GPCNTL and GPREG */
 373        old_gpreg       = INB(np, nc_gpreg);
 374        old_gpcntl      = INB(np, nc_gpcntl);
 375        gpcntl          = old_gpcntl & 0x1c;
 376
 377        /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
 378        OUTB(np, nc_gpreg,  old_gpreg);
 379        OUTB(np, nc_gpcntl, gpcntl);
 380
 381        /* this is to set NVRAM into a known state with GPIO0/1 both low */
 382        gpreg = old_gpreg;
 383        S24C16_set_bit(np, 0, &gpreg, CLR_CLK);
 384        S24C16_set_bit(np, 0, &gpreg, CLR_BIT);
 385                
 386        /* now set NVRAM inactive with GPIO0/1 both high */
 387        S24C16_stop(np, &gpreg);
 388
 389        /* NVRAM has to be written in segments of 16 bytes */
 390        for (x = 0; x < len ; x += 16) {
 391                do {
 392                        S24C16_start(np, &gpreg);
 393                        S24C16_write_byte(np, &ack_data,
 394                                          0xa0 | (((offset+x) >> 7) & 0x0e),
 395                                          &gpreg, &gpcntl);
 396                } while (ack_data & 0x01);
 397
 398                S24C16_write_byte(np, &ack_data, (offset+x) & 0xff, 
 399                                  &gpreg, &gpcntl);
 400
 401                for (y = 0; y < 16; y++)
 402                        S24C16_write_byte(np, &ack_data, data[x+y], 
 403                                          &gpreg, &gpcntl);
 404                S24C16_stop(np, &gpreg);
 405        }
 406
 407        /* return GPIO0/1 to original states after having accessed NVRAM */
 408        OUTB(np, nc_gpcntl, old_gpcntl);
 409        OUTB(np, nc_gpreg,  old_gpreg);
 410
 411        return 0;
 412}
 413#endif /* SYM_CONF_NVRAM_WRITE_SUPPORT */
 414
 415/*
 416 *  Read 'len' bytes starting at 'offset'.
 417 */
 418static int sym_read_S24C16_nvram(struct sym_device *np, int offset, u_char *data, int len)
 419{
 420        u_char  gpcntl, gpreg;
 421        u_char  old_gpcntl, old_gpreg;
 422        u_char  ack_data;
 423        int     retv = 1;
 424        int     x;
 425
 426        /* save current state of GPCNTL and GPREG */
 427        old_gpreg       = INB(np, nc_gpreg);
 428        old_gpcntl      = INB(np, nc_gpcntl);
 429        gpcntl          = old_gpcntl & 0x1c;
 430
 431        /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
 432        OUTB(np, nc_gpreg,  old_gpreg);
 433        OUTB(np, nc_gpcntl, gpcntl);
 434
 435        /* this is to set NVRAM into a known state with GPIO0/1 both low */
 436        gpreg = old_gpreg;
 437        S24C16_set_bit(np, 0, &gpreg, CLR_CLK);
 438        S24C16_set_bit(np, 0, &gpreg, CLR_BIT);
 439                
 440        /* now set NVRAM inactive with GPIO0/1 both high */
 441        S24C16_stop(np, &gpreg);
 442        
 443        /* activate NVRAM */
 444        S24C16_start(np, &gpreg);
 445
 446        /* write device code and random address MSB */
 447        S24C16_write_byte(np, &ack_data,
 448                0xa0 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
 449        if (ack_data & 0x01)
 450                goto out;
 451
 452        /* write random address LSB */
 453        S24C16_write_byte(np, &ack_data,
 454                offset & 0xff, &gpreg, &gpcntl);
 455        if (ack_data & 0x01)
 456                goto out;
 457
 458        /* regenerate START state to set up for reading */
 459        S24C16_start(np, &gpreg);
 460        
 461        /* rewrite device code and address MSB with read bit set (lsb = 0x01) */
 462        S24C16_write_byte(np, &ack_data,
 463                0xa1 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
 464        if (ack_data & 0x01)
 465                goto out;
 466
 467        /* now set up GPIO0 for inputting data */
 468        gpcntl |= 0x01;
 469        OUTB(np, nc_gpcntl, gpcntl);
 470                
 471        /* input all requested data - only part of total NVRAM */
 472        for (x = 0; x < len; x++) 
 473                S24C16_read_byte(np, &data[x], (x == (len-1)), &gpreg, &gpcntl);
 474
 475        /* finally put NVRAM back in inactive mode */
 476        gpcntl &= 0xfe;
 477        OUTB(np, nc_gpcntl, gpcntl);
 478        S24C16_stop(np, &gpreg);
 479        retv = 0;
 480out:
 481        /* return GPIO0/1 to original states after having accessed NVRAM */
 482        OUTB(np, nc_gpcntl, old_gpcntl);
 483        OUTB(np, nc_gpreg,  old_gpreg);
 484
 485        return retv;
 486}
 487
 488#undef SET_BIT
 489#undef CLR_BIT
 490#undef SET_CLK
 491#undef CLR_CLK
 492
 493/*
 494 *  Try reading Symbios NVRAM.
 495 *  Return 0 if OK.
 496 */
 497static int sym_read_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram)
 498{
 499        static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0};
 500        u_char *data = (u_char *) nvram;
 501        int len  = sizeof(*nvram);
 502        u_short csum;
 503        int x;
 504
 505        /* probe the 24c16 and read the SYMBIOS 24c16 area */
 506        if (sym_read_S24C16_nvram (np, SYMBIOS_NVRAM_ADDRESS, data, len))
 507                return 1;
 508
 509        /* check valid NVRAM signature, verify byte count and checksum */
 510        if (nvram->type != 0 ||
 511            memcmp(nvram->trailer, Symbios_trailer, 6) ||
 512            nvram->byte_count != len - 12)
 513                return 1;
 514
 515        /* verify checksum */
 516        for (x = 6, csum = 0; x < len - 6; x++)
 517                csum += data[x];
 518        if (csum != nvram->checksum)
 519                return 1;
 520
 521        return 0;
 522}
 523
 524/*
 525 *  93C46 EEPROM reading.
 526 *
 527 *  GPIO0 - data in
 528 *  GPIO1 - data out
 529 *  GPIO2 - clock
 530 *  GPIO4 - chip select
 531 *
 532 *  Used by Tekram.
 533 */
 534
 535/*
 536 *  Pulse clock bit in GPIO0
 537 */
 538static void T93C46_Clk(struct sym_device *np, u_char *gpreg)
 539{
 540        OUTB(np, nc_gpreg, *gpreg | 0x04);
 541        INB(np, nc_mbox1);
 542        udelay(2);
 543        OUTB(np, nc_gpreg, *gpreg);
 544}
 545
 546/* 
 547 *  Read bit from NVRAM
 548 */
 549static void T93C46_Read_Bit(struct sym_device *np, u_char *read_bit, u_char *gpreg)
 550{
 551        udelay(2);
 552        T93C46_Clk(np, gpreg);
 553        *read_bit = INB(np, nc_gpreg);
 554}
 555
 556/*
 557 *  Write bit to GPIO0
 558 */
 559static void T93C46_Write_Bit(struct sym_device *np, u_char write_bit, u_char *gpreg)
 560{
 561        if (write_bit & 0x01)
 562                *gpreg |= 0x02;
 563        else
 564                *gpreg &= 0xfd;
 565                
 566        *gpreg |= 0x10;
 567                
 568        OUTB(np, nc_gpreg, *gpreg);
 569        INB(np, nc_mbox1);
 570        udelay(2);
 571
 572        T93C46_Clk(np, gpreg);
 573}
 574
 575/*
 576 *  Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!!
 577 */
 578static void T93C46_Stop(struct sym_device *np, u_char *gpreg)
 579{
 580        *gpreg &= 0xef;
 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 read command and address to NVRAM
 590 */
 591static void T93C46_Send_Command(struct sym_device *np, u_short write_data, 
 592                                u_char *read_bit, u_char *gpreg)
 593{
 594        int x;
 595
 596        /* send 9 bits, start bit (1), command (2), address (6)  */
 597        for (x = 0; x < 9; x++)
 598                T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg);
 599
 600        *read_bit = INB(np, nc_gpreg);
 601}
 602
 603/*
 604 *  READ 2 bytes from the NVRAM
 605 */
 606static void T93C46_Read_Word(struct sym_device *np,
 607                unsigned short *nvram_data, unsigned char *gpreg)
 608{
 609        int x;
 610        u_char read_bit;
 611
 612        *nvram_data = 0;
 613        for (x = 0; x < 16; x++) {
 614                T93C46_Read_Bit(np, &read_bit, gpreg);
 615
 616                if (read_bit & 0x01)
 617                        *nvram_data |=  (0x01 << (15 - x));
 618                else
 619                        *nvram_data &= ~(0x01 << (15 - x));
 620        }
 621}
 622
 623/*
 624 *  Read Tekram NvRAM data.
 625 */
 626static int T93C46_Read_Data(struct sym_device *np, unsigned short *data,
 627                int len, unsigned char *gpreg)
 628{
 629        int x;
 630
 631        for (x = 0; x < len; x++)  {
 632                unsigned char read_bit;
 633                /* output read command and address */
 634                T93C46_Send_Command(np, 0x180 | x, &read_bit, gpreg);
 635                if (read_bit & 0x01)
 636                        return 1; /* Bad */
 637                T93C46_Read_Word(np, &data[x], gpreg);
 638                T93C46_Stop(np, gpreg);
 639        }
 640
 641        return 0;
 642}
 643
 644/*
 645 *  Try reading 93C46 Tekram NVRAM.
 646 */
 647static int sym_read_T93C46_nvram(struct sym_device *np, Tekram_nvram *nvram)
 648{
 649        u_char gpcntl, gpreg;
 650        u_char old_gpcntl, old_gpreg;
 651        int retv;
 652
 653        /* save current state of GPCNTL and GPREG */
 654        old_gpreg       = INB(np, nc_gpreg);
 655        old_gpcntl      = INB(np, nc_gpcntl);
 656
 657        /* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in,
 658           1/2/4 out */
 659        gpreg = old_gpreg & 0xe9;
 660        OUTB(np, nc_gpreg, gpreg);
 661        gpcntl = (old_gpcntl & 0xe9) | 0x09;
 662        OUTB(np, nc_gpcntl, gpcntl);
 663
 664        /* input all of NVRAM, 64 words */
 665        retv = T93C46_Read_Data(np, (u_short *) nvram,
 666                                sizeof(*nvram) / sizeof(short), &gpreg);
 667        
 668        /* return GPIO0/1/2/4 to original states after having accessed NVRAM */
 669        OUTB(np, nc_gpcntl, old_gpcntl);
 670        OUTB(np, nc_gpreg,  old_gpreg);
 671
 672        return retv;
 673}
 674
 675/*
 676 *  Try reading Tekram NVRAM.
 677 *  Return 0 if OK.
 678 */
 679static int sym_read_Tekram_nvram (struct sym_device *np, Tekram_nvram *nvram)
 680{
 681        u_char *data = (u_char *) nvram;
 682        int len = sizeof(*nvram);
 683        u_short csum;
 684        int x;
 685
 686        switch (np->pdev->device) {
 687        case PCI_DEVICE_ID_NCR_53C885:
 688        case PCI_DEVICE_ID_NCR_53C895:
 689        case PCI_DEVICE_ID_NCR_53C896:
 690                x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
 691                                          data, len);
 692                break;
 693        case PCI_DEVICE_ID_NCR_53C875:
 694                x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
 695                                          data, len);
 696                if (!x)
 697                        break;
 698                /* fall through */
 699        default:
 700                x = sym_read_T93C46_nvram(np, nvram);
 701                break;
 702        }
 703        if (x)
 704                return 1;
 705
 706        /* verify checksum */
 707        for (x = 0, csum = 0; x < len - 1; x += 2)
 708                csum += data[x] + (data[x+1] << 8);
 709        if (csum != 0x1234)
 710                return 1;
 711
 712        return 0;
 713}
 714
 715#ifdef CONFIG_PARISC
 716/*
 717 * Host firmware (PDC) keeps a table for altering SCSI capabilities.
 718 * Many newer machines export one channel of 53c896 chip as SE, 50-pin HD.
 719 * Also used for Multi-initiator SCSI clusters to set the SCSI Initiator ID.
 720 */
 721static int sym_read_parisc_pdc(struct sym_device *np, struct pdc_initiator *pdc)
 722{
 723        struct hardware_path hwpath;
 724        get_pci_node_path(np->pdev, &hwpath);
 725        if (!pdc_get_initiator(&hwpath, pdc))
 726                return 0;
 727
 728        return SYM_PARISC_PDC;
 729}
 730#else
 731static inline int sym_read_parisc_pdc(struct sym_device *np,
 732                                        struct pdc_initiator *x)
 733{
 734        return 0;
 735}
 736#endif
 737
 738/*
 739 *  Try reading Symbios or Tekram NVRAM
 740 */
 741int sym_read_nvram(struct sym_device *np, struct sym_nvram *nvp)
 742{
 743        if (!sym_read_Symbios_nvram(np, &nvp->data.Symbios)) {
 744                nvp->type = SYM_SYMBIOS_NVRAM;
 745                sym_display_Symbios_nvram(np, &nvp->data.Symbios);
 746        } else if (!sym_read_Tekram_nvram(np, &nvp->data.Tekram)) {
 747                nvp->type = SYM_TEKRAM_NVRAM;
 748                sym_display_Tekram_nvram(np, &nvp->data.Tekram);
 749        } else {
 750                nvp->type = sym_read_parisc_pdc(np, &nvp->data.parisc);
 751        }
 752        return nvp->type;
 753}
 754
 755char *sym_nvram_type(struct sym_nvram *nvp)
 756{
 757        switch (nvp->type) {
 758        case SYM_SYMBIOS_NVRAM:
 759                return "Symbios NVRAM";
 760        case SYM_TEKRAM_NVRAM:
 761                return "Tekram NVRAM";
 762        case SYM_PARISC_PDC:
 763                return "PA-RISC Firmware";
 764        default:
 765                return "No NVRAM";
 766        }
 767}
 768