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->proc_info = &dtc_proc_info;
 220
 221        for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
 222                addr = 0;
 223                base = NULL;
 224
 225                if (overrides[current_override].address) {
 226                        addr = overrides[current_override].address;
 227                        base = ioremap(addr, 0x2000);
 228                        if (!base)
 229                                addr = 0;
 230                } else
 231                        for (; !addr && (current_base < NO_BASES); ++current_base) {
 232#if (DTCDEBUG & DTCDEBUG_INIT)
 233                                printk(KERN_DEBUG "scsi-dtc : probing address %08x\n", bases[current_base].address);
 234#endif
 235                                if (bases[current_base].noauto)
 236                                        continue;
 237                                base = ioremap(bases[current_base].address, 0x2000);
 238                                if (!base)
 239                                        continue;
 240                                for (sig = 0; sig < NO_SIGNATURES; ++sig) {
 241                                        if (check_signature(base + signatures[sig].offset, signatures[sig].string, strlen(signatures[sig].string))) {
 242                                                addr = bases[current_base].address;
 243#if (DTCDEBUG & DTCDEBUG_INIT)
 244                                                printk(KERN_DEBUG "scsi-dtc : detected board.\n");
 245#endif
 246                                                goto found;
 247                                        }
 248                                }
 249                                iounmap(base);
 250                        }
 251
 252#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT)
 253                printk(KERN_DEBUG "scsi-dtc : base = %08x\n", addr);
 254#endif
 255
 256                if (!addr)
 257                        break;
 258
 259found:
 260                instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata));
 261                if (instance == NULL)
 262                        break;
 263
 264                instance->base = addr;
 265                ((struct NCR5380_hostdata *)(instance)->hostdata)->base = base;
 266
 267                NCR5380_init(instance, 0);
 268
 269                NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR);  /* Enable int's */
 270                if (overrides[current_override].irq != IRQ_AUTO)
 271                        instance->irq = overrides[current_override].irq;
 272                else
 273                        instance->irq = NCR5380_probe_irq(instance, DTC_IRQS);
 274
 275#ifndef DONT_USE_INTR
 276                /* With interrupts enabled, it will sometimes hang when doing heavy
 277                 * reads. So better not enable them until I finger it out. */
 278                if (instance->irq != SCSI_IRQ_NONE)
 279                        if (request_irq(instance->irq, dtc_intr, IRQF_DISABLED,
 280                                        "dtc", instance)) {
 281                                printk(KERN_ERR "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
 282                                instance->irq = SCSI_IRQ_NONE;
 283                        }
 284
 285                if (instance->irq == SCSI_IRQ_NONE) {
 286                        printk(KERN_WARNING "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
 287                        printk(KERN_WARNING "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
 288                }
 289#else
 290                if (instance->irq != SCSI_IRQ_NONE)
 291                        printk(KERN_WARNING "scsi%d : interrupts not used. Might as well not jumper it.\n", instance->host_no);
 292                instance->irq = SCSI_IRQ_NONE;
 293#endif
 294#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT)
 295                printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
 296#endif
 297
 298                printk(KERN_INFO "scsi%d : at 0x%05X", instance->host_no, (int) instance->base);
 299                if (instance->irq == SCSI_IRQ_NONE)
 300                        printk(" interrupts disabled");
 301                else
 302                        printk(" irq %d", instance->irq);
 303                printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, DTC_PUBLIC_RELEASE);
 304                NCR5380_print_options(instance);
 305                printk("\n");
 306
 307                ++current_override;
 308                ++count;
 309        }
 310        return count;
 311}
 312
 313/*
 314 * Function : int dtc_biosparam(Disk * disk, struct block_device *dev, int *ip)
 315 *
 316 * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for 
 317 *      the specified device / size.
 318 * 
 319 * Inputs : size = size of device in sectors (512 bytes), dev = block device
 320 *      major / minor, ip[] = {heads, sectors, cylinders}  
 321 *
 322 * Returns : always 0 (success), initializes ip
 323 *      
 324*/
 325
 326/* 
 327 * XXX Most SCSI boards use this mapping, I could be incorrect.  Some one
 328 * using hard disks on a trantor should verify that this mapping corresponds
 329 * to that used by the BIOS / ASPI driver by running the linux fdisk program
 330 * and matching the H_C_S coordinates to what DOS uses.
 331*/
 332
 333static int dtc_biosparam(struct scsi_device *sdev, struct block_device *dev,
 334                         sector_t capacity, int *ip)
 335{
 336        int size = capacity;
 337
 338        ip[0] = 64;
 339        ip[1] = 32;
 340        ip[2] = size >> 11;
 341        return 0;
 342}
 343
 344
 345/****************************************************************
 346 * Function : int NCR5380_pread (struct Scsi_Host *instance, 
 347 *      unsigned char *dst, int len)
 348 *
 349 * Purpose : Fast 5380 pseudo-dma read function, reads len bytes to 
 350 *      dst
 351 * 
 352 * Inputs : dst = destination, len = length in bytes
 353 *
 354 * Returns : 0 on success, non zero on a failure such as a watchdog 
 355 *      timeout.
 356*/
 357
 358static int dtc_maxi = 0;
 359static int dtc_wmaxi = 0;
 360
 361static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len)
 362{
 363        unsigned char *d = dst;
 364        int i;                  /* For counting time spent in the poll-loop */
 365        NCR5380_local_declare();
 366        NCR5380_setup(instance);
 367
 368        i = 0;
 369        NCR5380_read(RESET_PARITY_INTERRUPT_REG);
 370        NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
 371        if (instance->irq == SCSI_IRQ_NONE)
 372                NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ);
 373        else
 374                NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ | CSR_INT_BASE);
 375        NCR5380_write(DTC_BLK_CNT, len >> 7);   /* Block count */
 376        rtrc(1);
 377        while (len > 0) {
 378                rtrc(2);
 379                while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY)
 380                        ++i;
 381                rtrc(3);
 382                memcpy_fromio(d, base + DTC_DATA_BUF, 128);
 383                d += 128;
 384                len -= 128;
 385                rtrc(7);
 386                /*** with int's on, it sometimes hangs after here.
 387                 * Looks like something makes HBNR go away. */
 388        }
 389        rtrc(4);
 390        while (!(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS))
 391                ++i;
 392        NCR5380_write(MODE_REG, 0);     /* Clear the operating mode */
 393        rtrc(0);
 394        NCR5380_read(RESET_PARITY_INTERRUPT_REG);
 395        if (i > dtc_maxi)
 396                dtc_maxi = i;
 397        return (0);
 398}
 399
 400/****************************************************************
 401 * Function : int NCR5380_pwrite (struct Scsi_Host *instance, 
 402 *      unsigned char *src, int len)
 403 *
 404 * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from
 405 *      src
 406 * 
 407 * Inputs : src = source, len = length in bytes
 408 *
 409 * Returns : 0 on success, non zero on a failure such as a watchdog 
 410 *      timeout.
 411*/
 412
 413static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len)
 414{
 415        int i;
 416        NCR5380_local_declare();
 417        NCR5380_setup(instance);
 418
 419        NCR5380_read(RESET_PARITY_INTERRUPT_REG);
 420        NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
 421        /* set direction (write) */
 422        if (instance->irq == SCSI_IRQ_NONE)
 423                NCR5380_write(DTC_CONTROL_REG, 0);
 424        else
 425                NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR);
 426        NCR5380_write(DTC_BLK_CNT, len >> 7);   /* Block count */
 427        for (i = 0; len > 0; ++i) {
 428                rtrc(5);
 429                /* Poll until the host buffer can accept data. */
 430                while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY)
 431                        ++i;
 432                rtrc(3);
 433                memcpy_toio(base + DTC_DATA_BUF, src, 128);
 434                src += 128;
 435                len -= 128;
 436        }
 437        rtrc(4);
 438        while (!(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS))
 439                ++i;
 440        rtrc(6);
 441        /* Wait until the last byte has been sent to the disk */
 442        while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT))
 443                ++i;
 444        rtrc(7);
 445        /* Check for parity error here. fixme. */
 446        NCR5380_write(MODE_REG, 0);     /* Clear the operating mode */
 447        rtrc(0);
 448        if (i > dtc_wmaxi)
 449                dtc_wmaxi = i;
 450        return (0);
 451}
 452
 453MODULE_LICENSE("GPL");
 454
 455#include "NCR5380.c"
 456
 457static int dtc_release(struct Scsi_Host *shost)
 458{
 459        NCR5380_local_declare();
 460        NCR5380_setup(shost);
 461        if (shost->irq)
 462                free_irq(shost->irq, shost);
 463        NCR5380_exit(shost);
 464        if (shost->io_port && shost->n_io_port)
 465                release_region(shost->io_port, shost->n_io_port);
 466        scsi_unregister(shost);
 467        iounmap(base);
 468        return 0;
 469}
 470
 471static struct scsi_host_template driver_template = {
 472        .name                           = "DTC 3180/3280 ",
 473        .detect                         = dtc_detect,
 474        .release                        = dtc_release,
 475        .queuecommand                   = dtc_queue_command,
 476        .eh_abort_handler               = dtc_abort,
 477        .eh_bus_reset_handler           = dtc_bus_reset,
 478        .bios_param                     = dtc_biosparam,
 479        .can_queue                      = CAN_QUEUE,
 480        .this_id                        = 7,
 481        .sg_tablesize                   = SG_ALL,
 482        .cmd_per_lun                    = CMD_PER_LUN,
 483        .use_clustering                 = DISABLE_CLUSTERING,
 484};
 485#include "scsi_module.c"
 486
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.