linux/drivers/scsi/aic7xxx/aic7770.c
<<
>>
Prefs
   1/*
   2 * Product specific probe and attach routines for:
   3 *      27/284X and aic7770 motherboard SCSI controllers
   4 *
   5 * Copyright (c) 1994-1998, 2000, 2001 Justin T. Gibbs.
   6 * All rights reserved.
   7 *
   8 * Redistribution and use in source and binary forms, with or without
   9 * modification, are permitted provided that the following conditions
  10 * are met:
  11 * 1. Redistributions of source code must retain the above copyright
  12 *    notice, this list of conditions, and the following disclaimer,
  13 *    without modification.
  14 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
  15 *    substantially similar to the "NO WARRANTY" disclaimer below
  16 *    ("Disclaimer") and any redistribution must be conditioned upon
  17 *    including a substantially similar Disclaimer requirement for further
  18 *    binary redistribution.
  19 * 3. Neither the names of the above-listed copyright holders nor the names
  20 *    of any contributors may be used to endorse or promote products derived
  21 *    from this software without specific prior written permission.
  22 *
  23 * Alternatively, this software may be distributed under the terms of the
  24 * GNU General Public License ("GPL") version 2 as published by the Free
  25 * Software Foundation.
  26 *
  27 * NO WARRANTY
  28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
  31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  32 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  37 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  38 * POSSIBILITY OF SUCH DAMAGES.
  39 *
  40 * $Id: //depot/aic7xxx/aic7xxx/aic7770.c#32 $
  41 *
  42 * $FreeBSD$
  43 */
  44
  45#ifdef __linux__
  46#include "aic7xxx_osm.h"
  47#include "aic7xxx_inline.h"
  48#include "aic7xxx_93cx6.h"
  49#else
  50#include <dev/aic7xxx/aic7xxx_osm.h>
  51#include <dev/aic7xxx/aic7xxx_inline.h>
  52#include <dev/aic7xxx/aic7xxx_93cx6.h>
  53#endif
  54
  55#define ID_AIC7770      0x04907770
  56#define ID_AHA_274x     0x04907771
  57#define ID_AHA_284xB    0x04907756 /* BIOS enabled */
  58#define ID_AHA_284x     0x04907757 /* BIOS disabled*/
  59#define ID_OLV_274x     0x04907782 /* Olivetti OEM */
  60#define ID_OLV_274xD    0x04907783 /* Olivetti OEM (Differential) */
  61
  62static int aic7770_chip_init(struct ahc_softc *ahc);
  63static int aha2840_load_seeprom(struct ahc_softc *ahc);
  64static ahc_device_setup_t ahc_aic7770_VL_setup;
  65static ahc_device_setup_t ahc_aic7770_EISA_setup;
  66static ahc_device_setup_t ahc_aic7770_setup;
  67
  68struct aic7770_identity aic7770_ident_table[] =
  69{
  70        {
  71                ID_AHA_274x,
  72                0xFFFFFFFF,
  73                "Adaptec 274X SCSI adapter",
  74                ahc_aic7770_EISA_setup
  75        },
  76        {
  77                ID_AHA_284xB,
  78                0xFFFFFFFE,
  79                "Adaptec 284X SCSI adapter",
  80                ahc_aic7770_VL_setup
  81        },
  82        {
  83                ID_AHA_284x,
  84                0xFFFFFFFE,
  85                "Adaptec 284X SCSI adapter (BIOS Disabled)",
  86                ahc_aic7770_VL_setup
  87        },
  88        {
  89                ID_OLV_274x,
  90                0xFFFFFFFF,
  91                "Adaptec (Olivetti OEM) 274X SCSI adapter",
  92                ahc_aic7770_EISA_setup
  93        },
  94        {
  95                ID_OLV_274xD,
  96                0xFFFFFFFF,
  97                "Adaptec (Olivetti OEM) 274X Differential SCSI adapter",
  98                ahc_aic7770_EISA_setup
  99        },
 100        /* Generic chip probes for devices we don't know 'exactly' */
 101        {
 102                ID_AIC7770,
 103                0xFFFFFFFF,
 104                "Adaptec aic7770 SCSI adapter",
 105                ahc_aic7770_EISA_setup
 106        }
 107};
 108const int ahc_num_aic7770_devs = ARRAY_SIZE(aic7770_ident_table);
 109
 110struct aic7770_identity *
 111aic7770_find_device(uint32_t id)
 112{
 113        struct  aic7770_identity *entry;
 114        int     i;
 115
 116        for (i = 0; i < ahc_num_aic7770_devs; i++) {
 117                entry = &aic7770_ident_table[i];
 118                if (entry->full_id == (id & entry->id_mask))
 119                        return (entry);
 120        }
 121        return (NULL);
 122}
 123
 124int
 125aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
 126{
 127        int     error;
 128        int     have_seeprom;
 129        u_int   hostconf;
 130        u_int   irq;
 131        u_int   intdef;
 132
 133        error = entry->setup(ahc);
 134        have_seeprom = 0;
 135        if (error != 0)
 136                return (error);
 137
 138        error = aic7770_map_registers(ahc, io);
 139        if (error != 0)
 140                return (error);
 141
 142        /*
 143         * Before we continue probing the card, ensure that
 144         * its interrupts are *disabled*.  We don't want
 145         * a misstep to hang the machine in an interrupt
 146         * storm.
 147         */
 148        ahc_intr_enable(ahc, FALSE);
 149
 150        ahc->description = entry->name;
 151        error = ahc_softc_init(ahc);
 152        if (error != 0)
 153                return (error);
 154
 155        ahc->bus_chip_init = aic7770_chip_init;
 156
 157        error = ahc_reset(ahc, /*reinit*/FALSE);
 158        if (error != 0)
 159                return (error);
 160
 161        /* Make sure we have a valid interrupt vector */
 162        intdef = ahc_inb(ahc, INTDEF);
 163        irq = intdef & VECTOR;
 164        switch (irq) {
 165        case 9:
 166        case 10:
 167        case 11:
 168        case 12:
 169        case 14:
 170        case 15:
 171                break;
 172        default:
 173                printk("aic7770_config: invalid irq setting %d\n", intdef);
 174                return (ENXIO);
 175        }
 176
 177        if ((intdef & EDGE_TRIG) != 0)
 178                ahc->flags |= AHC_EDGE_INTERRUPT;
 179
 180        switch (ahc->chip & (AHC_EISA|AHC_VL)) {
 181        case AHC_EISA:
 182        {
 183                u_int biosctrl;
 184                u_int scsiconf;
 185                u_int scsiconf1;
 186
 187                biosctrl = ahc_inb(ahc, HA_274_BIOSCTRL);
 188                scsiconf = ahc_inb(ahc, SCSICONF);
 189                scsiconf1 = ahc_inb(ahc, SCSICONF + 1);
 190
 191                /* Get the primary channel information */
 192                if ((biosctrl & CHANNEL_B_PRIMARY) != 0)
 193                        ahc->flags |= 1;
 194
 195                if ((biosctrl & BIOSMODE) == BIOSDISABLED) {
 196                        ahc->flags |= AHC_USEDEFAULTS;
 197                } else {
 198                        if ((ahc->features & AHC_WIDE) != 0) {
 199                                ahc->our_id = scsiconf1 & HWSCSIID;
 200                                if (scsiconf & TERM_ENB)
 201                                        ahc->flags |= AHC_TERM_ENB_A;
 202                        } else {
 203                                ahc->our_id = scsiconf & HSCSIID;
 204                                ahc->our_id_b = scsiconf1 & HSCSIID;
 205                                if (scsiconf & TERM_ENB)
 206                                        ahc->flags |= AHC_TERM_ENB_A;
 207                                if (scsiconf1 & TERM_ENB)
 208                                        ahc->flags |= AHC_TERM_ENB_B;
 209                        }
 210                }
 211                if ((ahc_inb(ahc, HA_274_BIOSGLOBAL) & HA_274_EXTENDED_TRANS))
 212                        ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B;
 213                break;
 214        }
 215        case AHC_VL:
 216        {
 217                have_seeprom = aha2840_load_seeprom(ahc);
 218                break;
 219        }
 220        default:
 221                break;
 222        }
 223        if (have_seeprom == 0) {
 224                kfree(ahc->seep_config);
 225                ahc->seep_config = NULL;
 226        }
 227
 228        /*
 229         * Ensure autoflush is enabled
 230         */
 231        ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~AUTOFLUSHDIS);
 232
 233        /* Setup the FIFO threshold and the bus off time */
 234        hostconf = ahc_inb(ahc, HOSTCONF);
 235        ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH);
 236        ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF);
 237
 238        ahc->bus_softc.aic7770_softc.busspd = hostconf & DFTHRSH;
 239        ahc->bus_softc.aic7770_softc.bustime = (hostconf << 2) & BOFF;
 240
 241        /*
 242         * Generic aic7xxx initialization.
 243         */
 244        error = ahc_init(ahc);
 245        if (error != 0)
 246                return (error);
 247
 248        error = aic7770_map_int(ahc, irq);
 249        if (error != 0)
 250                return (error);
 251
 252        ahc->init_level++;
 253
 254        /*
 255         * Enable the board's BUS drivers
 256         */
 257        ahc_outb(ahc, BCTL, ENABLE);
 258        return (0);
 259}
 260
 261static int
 262aic7770_chip_init(struct ahc_softc *ahc)
 263{
 264        ahc_outb(ahc, BUSSPD, ahc->bus_softc.aic7770_softc.busspd);
 265        ahc_outb(ahc, BUSTIME, ahc->bus_softc.aic7770_softc.bustime);
 266        ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~AUTOFLUSHDIS);
 267        ahc_outb(ahc, BCTL, ENABLE);
 268        return (ahc_chip_init(ahc));
 269}
 270
 271/*
 272 * Read the 284x SEEPROM.
 273 */
 274static int
 275aha2840_load_seeprom(struct ahc_softc *ahc)
 276{
 277        struct  seeprom_descriptor sd;
 278        struct  seeprom_config *sc;
 279        int     have_seeprom;
 280        uint8_t scsi_conf;
 281
 282        sd.sd_ahc = ahc;
 283        sd.sd_control_offset = SEECTL_2840;
 284        sd.sd_status_offset = STATUS_2840;
 285        sd.sd_dataout_offset = STATUS_2840;             
 286        sd.sd_chip = C46;
 287        sd.sd_MS = 0;
 288        sd.sd_RDY = EEPROM_TF;
 289        sd.sd_CS = CS_2840;
 290        sd.sd_CK = CK_2840;
 291        sd.sd_DO = DO_2840;
 292        sd.sd_DI = DI_2840;
 293        sc = ahc->seep_config;
 294
 295        if (bootverbose)
 296                printk("%s: Reading SEEPROM...", ahc_name(ahc));
 297        have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)sc,
 298                                        /*start_addr*/0, sizeof(*sc)/2);
 299
 300        if (have_seeprom) {
 301
 302                if (ahc_verify_cksum(sc) == 0) {
 303                        if(bootverbose)
 304                                printk ("checksum error\n");
 305                        have_seeprom = 0;
 306                } else if (bootverbose) {
 307                        printk("done.\n");
 308                }
 309        }
 310
 311        if (!have_seeprom) {
 312                if (bootverbose)
 313                        printk("%s: No SEEPROM available\n", ahc_name(ahc));
 314                ahc->flags |= AHC_USEDEFAULTS;
 315        } else {
 316                /*
 317                 * Put the data we've collected down into SRAM
 318                 * where ahc_init will find it.
 319                 */
 320                int      i;
 321                int      max_targ;
 322                uint16_t discenable;
 323
 324                max_targ = (ahc->features & AHC_WIDE) != 0 ? 16 : 8;
 325                discenable = 0;
 326                for (i = 0; i < max_targ; i++){
 327                        uint8_t target_settings;
 328
 329                        target_settings = (sc->device_flags[i] & CFXFER) << 4;
 330                        if (sc->device_flags[i] & CFSYNCH)
 331                                target_settings |= SOFS;
 332                        if (sc->device_flags[i] & CFWIDEB)
 333                                target_settings |= WIDEXFER;
 334                        if (sc->device_flags[i] & CFDISC)
 335                                discenable |= (0x01 << i);
 336                        ahc_outb(ahc, TARG_SCSIRATE + i, target_settings);
 337                }
 338                ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff));
 339                ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff));
 340
 341                ahc->our_id = sc->brtime_id & CFSCSIID;
 342
 343                scsi_conf = (ahc->our_id & 0x7);
 344                if (sc->adapter_control & CFSPARITY)
 345                        scsi_conf |= ENSPCHK;
 346                if (sc->adapter_control & CFRESETB)
 347                        scsi_conf |= RESET_SCSI;
 348
 349                if (sc->bios_control & CF284XEXTEND)            
 350                        ahc->flags |= AHC_EXTENDED_TRANS_A;
 351                /* Set SCSICONF info */
 352                ahc_outb(ahc, SCSICONF, scsi_conf);
 353
 354                if (sc->adapter_control & CF284XSTERM)
 355                        ahc->flags |= AHC_TERM_ENB_A;
 356        }
 357        return (have_seeprom);
 358}
 359
 360static int
 361ahc_aic7770_VL_setup(struct ahc_softc *ahc)
 362{
 363        int error;
 364
 365        error = ahc_aic7770_setup(ahc);
 366        ahc->chip |= AHC_VL;
 367        return (error);
 368}
 369
 370static int
 371ahc_aic7770_EISA_setup(struct ahc_softc *ahc)
 372{
 373        int error;
 374
 375        error = ahc_aic7770_setup(ahc);
 376        ahc->chip |= AHC_EISA;
 377        return (error);
 378}
 379
 380static int
 381ahc_aic7770_setup(struct ahc_softc *ahc)
 382{
 383        ahc->channel = 'A';
 384        ahc->channel_b = 'B';
 385        ahc->chip = AHC_AIC7770;
 386        ahc->features = AHC_AIC7770_FE;
 387        ahc->bugs |= AHC_TMODE_WIDEODD_BUG;
 388        ahc->flags |= AHC_PAGESCBS;
 389        ahc->instruction_ram_size = 448;
 390        return (0);
 391}
 392