linux/drivers/scsi/dtc.c
<<
>>
Prefs
   1
   2#define AUTOSENSE
   3#define PSEUDO_DMA
   4#define DONT_USE_INTR
   5#define UNSAFE                  /* Leave interrupts enabled during pseudo-dma I/O */
   6#define xNDEBUG (NDEBUG_INTR+NDEBUG_RESELECTION+\
   7                 NDEBUG_SELECTION+NDEBUG_ARBITRATION)
   8#define DMA_WORKS_RIGHT
   9
  10
  11/*
  12 * DTC 3180/3280 driver, by
  13 *      Ray Van Tassle  rayvt@comm.mot.com
  14 *
  15 *      taken from ...
  16 *      Trantor T128/T128F/T228 driver by...
  17 *
  18 *      Drew Eckhardt
  19 *      Visionary Computing
  20 *      (Unix and Linux consulting and custom programming)
  21 *      drew@colorado.edu
  22 *      +1 (303) 440-4894
  23 *
  24 * DISTRIBUTION RELEASE 1.
  25 *
  26 * For more information, please consult 
  27 *
  28 * NCR 5380 Family
  29 * SCSI Protocol Controller
  30 * Databook
  31*/
  32
  33/*
  34 * Options : 
  35 * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
  36 *      for commands that return with a CHECK CONDITION status. 
  37 *
  38 * PSEUDO_DMA - enables PSEUDO-DMA hardware, should give a 3-4X performance
  39 * increase compared to polled I/O.
  40 *
  41 * PARITY - enable parity checking.  Not supported.
  42 *
  43 * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. 
  44 *              You probably want this.
  45 *
  46 * The card is detected and initialized in one of several ways : 
  47 * 1.  Autoprobe (default) - since the board is memory mapped, 
  48 *     a BIOS signature is scanned for to locate the registers.
  49 *     An interrupt is triggered to autoprobe for the interrupt
  50 *     line.
  51 *
  52 * 2.  With command line overrides - dtc=address,irq may be 
  53 *     used on the LILO command line to override the defaults.
  54 * 
  55*/
  56
  57/*----------------------------------------------------------------*/
  58/* the following will set the monitor border color (useful to find
  59 where something crashed or gets stuck at */
  60/* 1 = blue
  61 2 = green
  62 3 = cyan
  63 4 = red
  64 5 = magenta
  65 6 = yellow
  66 7 = white
  67*/
  68#if 0
  69#define rtrc(i) {inb(0x3da); outb(0x31, 0x3c0); outb((i), 0x3c0);}
  70#else
  71#define rtrc(i) {}
  72#endif
  73
  74
  75#include <linux/module.h>
  76#include <linux/signal.h>
  77#include <linux/blkdev.h>
  78#include <linux/delay.h>
  79#include <linux/stat.h>
  80#include <linux/string.h>
  81#include <linux/init.h>
  82#include <linux/interrupt.h>
  83#include <linux/io.h>
  84#include "scsi.h"
  85#include <scsi/scsi_host.h>
  86#include "dtc.h"
  87#define AUTOPROBE_IRQ
  88#include "NCR5380.h"
  89
  90
  91#define DTC_PUBLIC_RELEASE 2
  92
  93/*
  94 * The DTC3180 & 3280 boards are memory mapped.
  95 * 
  96 */
  97
  98/*
  99 */
 100/* Offset from DTC_5380_OFFSET */
 101#define DTC_CONTROL_REG         0x100   /* rw */
 102#define D_CR_ACCESS             0x80    /* ro set=can access 3280 registers */
 103#define CSR_DIR_READ            0x40    /* rw direction, 1 = read 0 = write */
 104
 105#define CSR_RESET              0x80     /* wo  Resets 53c400 */
 106#define CSR_5380_REG           0x80     /* ro  5380 registers can be accessed */
 107#define CSR_TRANS_DIR          0x40     /* rw  Data transfer direction */
 108#define CSR_SCSI_BUFF_INTR     0x20     /* rw  Enable int on transfer ready */
 109#define CSR_5380_INTR          0x10     /* rw  Enable 5380 interrupts */
 110#define CSR_SHARED_INTR        0x08     /* rw  Interrupt sharing */
 111#define CSR_HOST_BUF_NOT_RDY   0x04     /* ro  Host buffer not ready */
 112#define CSR_SCSI_BUF_RDY       0x02     /* ro  SCSI buffer ready */
 113#define CSR_GATED_5380_IRQ     0x01     /* ro  Last block xferred */
 114#define CSR_INT_BASE (CSR_SCSI_BUFF_INTR | CSR_5380_INTR)
 115
 116
 117#define DTC_BLK_CNT             0x101   /* rw 
 118                                         * # of 128-byte blocks to transfer */
 119
 120
 121#define D_CR_ACCESS             0x80    /* ro set=can access 3280 registers */
 122
 123#define DTC_SWITCH_REG          0x3982  /* ro - DIP switches */
 124#define DTC_RESUME_XFER         0x3982  /* wo - resume data xfer 
 125                                         * after disconnect/reconnect*/
 126
 127#define DTC_5380_OFFSET         0x3880  /* 8 registers here, see NCR5380.h */
 128
 129/*!!!! for dtc, it's a 128 byte buffer at 3900 !!! */
 130#define DTC_DATA_BUF            0x3900  /* rw 128 bytes long */
 131
 132static struct override {
 133        unsigned int address;
 134        int irq;
 135} overrides
 136#ifdef OVERRIDE
 137[] __initdata = OVERRIDE;
 138#else
 139[4] __initdata = {
 140        { 0, IRQ_AUTO }, { 0, IRQ_AUTO }, { 0, IRQ_AUTO }, { 0, IRQ_AUTO }
 141};
 142#endif
 143
 144#define NO_OVERRIDES ARRAY_SIZE(overrides)
 145
 146static struct base {
 147        unsigned long address;
 148        int noauto;
 149} bases[] __initdata = {
 150        { 0xcc000, 0 },
 151        { 0xc8000, 0 },
 152        { 0xdc000, 0 },
 153        { 0xd8000, 0 }
 154};
 155
 156#define NO_BASES ARRAY_SIZE(bases)
 157
 158static const struct signature {
 159        const char *string;
 160        int offset;
 161} signatures[] = {
 162        {"DATA TECHNOLOGY CORPORATION BIOS", 0x25},
 163};
 164
 165#define NO_SIGNATURES ARRAY_SIZE(signatures)
 166
 167#ifndef MODULE
 168/*
 169 * Function : dtc_setup(char *str, int *ints)
 170 *
 171 * Purpose : LILO command line initialization of the overrides array,
 172 *
 173 * Inputs : str - unused, ints - array of integer parameters with ints[0]
 174 *      equal to the number of ints.
 175 *
 176 */
 177
 178static void __init dtc_setup(char *str, int *ints)
 179{
 180        static int commandline_current = 0;
 181        int i;
 182        if (ints[0] != 2)
 183                printk("dtc_setup: usage dtc=address,irq\n");
 184        else if (commandline_current < NO_OVERRIDES) {
 185                overrides[commandline_current].address = ints[1];
 186                overrides[commandline_current].irq = ints[2];
 187                for (i = 0; i < NO_BASES; ++i)
 188                        if (bases[i].address == ints[1]) {
 189                                bases[i].noauto = 1;
 190                                break;
 191                        }
 192                ++commandline_current;
 193        }
 194}
 195#endif
 196
 197/* 
 198 * Function : int dtc_detect(struct scsi_host_template * tpnt)
 199 *
 200 * Purpose : detects and initializes DTC 3180/3280 controllers
 201 *      that were autoprobed, overridden on the LILO command line, 
 202 *      or specified at compile time.
 203 *
 204 * Inputs : tpnt - template for this SCSI adapter.
 205 * 
 206 * Returns : 1 if a host adapter was found, 0 if not.
 207 *
 208*/
 209
 210static int __init dtc_detect(struct scsi_host_template * tpnt)
 211{
 212        static int current_override = 0, current_base = 0;
 213        struct Scsi_Host *instance;
 214        unsigned int addr;
 215        void __iomem *base;
 216        int sig, count;
 217
 218        tpnt->proc_name = "dtc3x80";
 219        tpnt->show_info = dtc_show_info;
 220        tpnt->write_info = dtc_write_info;
 221
 222        for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
 223                addr = 0;
 224                base = NULL;
 225
 226                if (overrides[current_override].address) {
 227                        addr = overrides[current_override].address;
 228                        base = ioremap(addr, 0x2000);
 229                        if (!base)
 230                                addr = 0;
 231                } else
 232                        for (; !addr && (current_base < NO_BASES); ++current_base) {
 233#if (DTCDEBUG & DTCDEBUG_INIT)
 234                                printk(KERN_DEBUG "scsi-dtc : probing address %08x\n", bases[current_base].address);
 235#endif
 236                                if (bases[current_base].noauto)
 237                                        continue;
 238                                base = ioremap(bases[current_base].address, 0x2000);
 239                                if (!base)
 240                                        continue;
 241                                for (sig = 0; sig < NO_SIGNATURES; ++sig) {
 242                                        if (check_signature(base + signatures[sig].offset, signatures[sig].string, strlen(signatures[sig].string))) {
 243                                                addr = bases[current_base].address;
 244#if (DTCDEBUG & DTCDEBUG_INIT)
 245                                                printk(KERN_DEBUG "scsi-dtc : detected board.\n");
 246#endif
 247                                                goto found;
 248                                        }
 249                                }
 250                                iounmap(base);
 251                        }
 252
 253#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT)
 254                printk(KERN_DEBUG "scsi-dtc : base = %08x\n", addr);
 255#endif
 256
 257                if (!addr)
 258                        break;
 259
 260found:
 261                instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata));
 262                if (instance == NULL)
 263                        break;
 264
 265                instance->base = addr;
 266                ((struct NCR5380_hostdata *)(instance)->hostdata)->base = base;
 267
 268                NCR5380_init(instance, 0);
 269
 270                NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR);  /* Enable int's */
 271                if (overrides[current_override].irq != IRQ_AUTO)
 272                        instance->irq = overrides[current_override].irq;
 273                else
 274                        instance->irq = NCR5380_probe_irq(instance, DTC_IRQS);
 275
 276#ifndef DONT_USE_INTR
 277                /* With interrupts enabled, it will sometimes hang when doing heavy
 278                 * reads. So better not enable them until I finger it out. */
 279                if (instance->irq != SCSI_IRQ_NONE)
 280                        if (request_irq(instance->irq, dtc_intr, IRQF_DISABLED,
 281                                        "dtc", instance)) {
 282                                printk(KERN_ERR "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
 283                                instance->irq = SCSI_IRQ_NONE;
 284                        }
 285
 286                if (instance->irq == SCSI_IRQ_NONE) {
 287                        printk(KERN_WARNING "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
 288                        printk(KERN_WARNING "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
 289                }
 290#else
 291                if (instance->irq != SCSI_IRQ_NONE)
 292                        printk(KERN_WARNING "scsi%d : interrupts not used. Might as well not jumper it.\n", instance->host_no);
 293                instance->irq = SCSI_IRQ_NONE;
 294#endif
 295#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT)
 296                printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
 297#endif
 298
 299                printk(KERN_INFO "scsi%d : at 0x%05X", instance->host_no, (int) instance->base);
 300                if (instance->irq == SCSI_IRQ_NONE)
 301                        printk(" interrupts disabled");
 302                else
 303                        printk(" irq %d", instance->irq);
 304                printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, DTC_PUBLIC_RELEASE);
 305                NCR5380_print_options(instance);
 306                printk("\n");
 307
 308                ++current_override;
 309                ++count;
 310        }
 311        return count;
 312}
 313
 314/*
 315 * Function : int dtc_biosparam(Disk * disk, struct block_device *dev, int *ip)
 316 *
 317 * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for 
 318 *      the specified device / size.
 319 * 
 320 * Inputs : size = size of device in sectors (512 bytes), dev = block device
 321 *      major / minor, ip[] = {heads, sectors, cylinders}  
 322 *
 323 * Returns : always 0 (success), initializes ip
 324 *      
 325*/
 326
 327/* 
 328 * XXX Most SCSI boards use this mapping, I could be incorrect.  Some one
 329 * using hard disks on a trantor should verify that this mapping corresponds
 330 * to that used by the BIOS / ASPI driver by running the linux fdisk program
 331 * and matching the H_C_S coordinates to what DOS uses.
 332*/
 333
 334static int dtc_biosparam(struct scsi_device *sdev, struct block_device *dev,
 335                         sector_t capacity, int *ip)
 336{
 337        int size = capacity;
 338
 339        ip[0] = 64;
 340        ip[1] = 32;
 341        ip[2] = size >> 11;
 342        return 0;
 343}
 344
 345
 346/****************************************************************
 347 * Function : int NCR5380_pread (struct Scsi_Host *instance, 
 348 *      unsigned char *dst, int len)
 349 *
 350 * Purpose : Fast 5380 pseudo-dma read function, reads len bytes to 
 351 *      dst
 352 * 
 353 * Inputs : dst = destination, len = length in bytes
 354 *
 355 * Returns : 0 on success, non zero on a failure such as a watchdog 
 356 *      timeout.
 357*/
 358
 359static int dtc_maxi = 0;
 360static int dtc_wmaxi = 0;
 361
 362static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len)
 363{
 364        unsigned char *d = dst;
 365        int i;                  /* For counting time spent in the poll-loop */
 366        NCR5380_local_declare();
 367        NCR5380_setup(instance);
 368
 369        i = 0;
 370        NCR5380_read(RESET_PARITY_INTERRUPT_REG);
 371        NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
 372        if (instance->irq == SCSI_IRQ_NONE)
 373                NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ);
 374        else
 375                NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ | CSR_INT_BASE);
 376        NCR5380_write(DTC_BLK_CNT, len >> 7);   /* Block count */
 377        rtrc(1);
 378        while (len > 0) {
 379                rtrc(2);
 380                while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY)
 381                        ++i;
 382                rtrc(3);
 383                memcpy_fromio(d, base + DTC_DATA_BUF, 128);
 384                d += 128;
 385                len -= 128;
 386                rtrc(7);
 387                /*** with int's on, it sometimes hangs after here.
 388                 * Looks like something makes HBNR go away. */
 389        }
 390        rtrc(4);
 391        while (!(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS))
 392                ++i;
 393        NCR5380_write(MODE_REG, 0);     /* Clear the operating mode */
 394        rtrc(0);
 395        NCR5380_read(RESET_PARITY_INTERRUPT_REG);
 396        if (i > dtc_maxi)
 397                dtc_maxi = i;
 398        return (0);
 399}
 400
 401/****************************************************************
 402 * Function : int NCR5380_pwrite (struct Scsi_Host *instance, 
 403 *      unsigned char *src, int len)
 404 *
 405 * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from
 406 *      src
 407 * 
 408 * Inputs : src = source, len = length in bytes
 409 *
 410 * Returns : 0 on success, non zero on a failure such as a watchdog 
 411 *      timeout.
 412*/
 413
 414static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len)
 415{
 416        int i;
 417        NCR5380_local_declare();
 418        NCR5380_setup(instance);
 419
 420        NCR5380_read(RESET_PARITY_INTERRUPT_REG);
 421        NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
 422        /* set direction (write) */
 423        if (instance->irq == SCSI_IRQ_NONE)
 424                NCR5380_write(DTC_CONTROL_REG, 0);
 425        else
 426                NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR);
 427        NCR5380_write(DTC_BLK_CNT, len >> 7);   /* Block count */
 428        for (i = 0; len > 0; ++i) {
 429                rtrc(5);
 430                /* Poll until the host buffer can accept data. */
 431                while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY)
 432                        ++i;
 433                rtrc(3);
 434                memcpy_toio(base + DTC_DATA_BUF, src, 128);
 435                src += 128;
 436                len -= 128;
 437        }
 438        rtrc(4);
 439        while (!(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS))
 440                ++i;
 441        rtrc(6);
 442        /* Wait until the last byte has been sent to the disk */
 443        while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT))
 444                ++i;
 445        rtrc(7);
 446        /* Check for parity error here. fixme. */
 447        NCR5380_write(MODE_REG, 0);     /* Clear the operating mode */
 448        rtrc(0);
 449        if (i > dtc_wmaxi)
 450                dtc_wmaxi = i;
 451        return (0);
 452}
 453
 454MODULE_LICENSE("GPL");
 455
 456#include "NCR5380.c"
 457
 458static int dtc_release(struct Scsi_Host *shost)
 459{
 460        NCR5380_local_declare();
 461        NCR5380_setup(shost);
 462        if (shost->irq)
 463                free_irq(shost->irq, shost);
 464        NCR5380_exit(shost);
 465        if (shost->io_port && shost->n_io_port)
 466                release_region(shost->io_port, shost->n_io_port);
 467        scsi_unregister(shost);
 468        iounmap(base);
 469        return 0;
 470}
 471
 472static struct scsi_host_template driver_template = {
 473        .name                           = "DTC 3180/3280 ",
 474        .detect                         = dtc_detect,
 475        .release                        = dtc_release,
 476        .queuecommand                   = dtc_queue_command,
 477        .eh_abort_handler               = dtc_abort,
 478        .eh_bus_reset_handler           = dtc_bus_reset,
 479        .bios_param                     = dtc_biosparam,
 480        .can_queue                      = CAN_QUEUE,
 481        .this_id                        = 7,
 482        .sg_tablesize                   = SG_ALL,
 483        .cmd_per_lun                    = CMD_PER_LUN,
 484        .use_clustering                 = DISABLE_CLUSTERING,
 485};
 486#include "scsi_module.c"
 487