linux/drivers/scsi/g_NCR5380.c
<<
>>
Prefs
   1/*
   2 * Generic Generic NCR5380 driver
   3 *      
   4 * Copyright 1993, Drew Eckhardt
   5 *      Visionary Computing
   6 *      (Unix and Linux consulting and custom programming)
   7 *      drew@colorado.edu
   8 *      +1 (303) 440-4894
   9 *
  10 * NCR53C400 extensions (c) 1994,1995,1996, Kevin Lentin
  11 *    K.Lentin@cs.monash.edu.au
  12 *
  13 * NCR53C400A extensions (c) 1996, Ingmar Baumgart
  14 *    ingmar@gonzo.schwaben.de
  15 *
  16 * DTC3181E extensions (c) 1997, Ronald van Cuijlenborg
  17 * ronald.van.cuijlenborg@tip.nl or nutty@dds.nl
  18 *
  19 * Added ISAPNP support for DTC436 adapters,
  20 * Thomas Sailer, sailer@ife.ee.ethz.ch
  21 */
  22
  23/* 
  24 * TODO : flesh out DMA support, find some one actually using this (I have
  25 *      a memory mapped Trantor board that works fine)
  26 */
  27
  28/*
  29 * The card is detected and initialized in one of several ways : 
  30 * 1.  With command line overrides - NCR5380=port,irq may be 
  31 *     used on the LILO command line to override the defaults.
  32 *
  33 * 2.  With the GENERIC_NCR5380_OVERRIDE compile time define.  This is 
  34 *     specified as an array of address, irq, dma, board tuples.  Ie, for
  35 *     one board at 0x350, IRQ5, no dma, I could say  
  36 *     -DGENERIC_NCR5380_OVERRIDE={{0xcc000, 5, DMA_NONE, BOARD_NCR5380}}
  37 * 
  38 * -1 should be specified for no or DMA interrupt, -2 to autoprobe for an 
  39 *      IRQ line if overridden on the command line.
  40 *
  41 * 3.  When included as a module, with arguments passed on the command line:
  42 *         ncr_irq=xx   the interrupt
  43 *         ncr_addr=xx  the port or base address (for port or memory
  44 *                      mapped, resp.)
  45 *         ncr_dma=xx   the DMA
  46 *         ncr_5380=1   to set up for a NCR5380 board
  47 *         ncr_53c400=1 to set up for a NCR53C400 board
  48 *     e.g.
  49 *     modprobe g_NCR5380 ncr_irq=5 ncr_addr=0x350 ncr_5380=1
  50 *       for a port mapped NCR5380 board or
  51 *     modprobe g_NCR5380 ncr_irq=255 ncr_addr=0xc8000 ncr_53c400=1
  52 *       for a memory mapped NCR53C400 board with interrupts disabled.
  53 * 
  54 * 255 should be specified for no or DMA interrupt, 254 to autoprobe for an 
  55 *      IRQ line if overridden on the command line.
  56 *     
  57 */
  58
  59#define AUTOPROBE_IRQ
  60
  61#ifdef CONFIG_SCSI_GENERIC_NCR53C400
  62#define PSEUDO_DMA
  63#endif
  64
  65#include <asm/io.h>
  66#include <linux/blkdev.h>
  67#include <linux/module.h>
  68#include <scsi/scsi_host.h>
  69#include "g_NCR5380.h"
  70#include "NCR5380.h"
  71#include <linux/init.h>
  72#include <linux/ioport.h>
  73#include <linux/isapnp.h>
  74#include <linux/interrupt.h>
  75
  76static int ncr_irq;
  77static int ncr_dma;
  78static int ncr_addr;
  79static int ncr_5380;
  80static int ncr_53c400;
  81static int ncr_53c400a;
  82static int dtc_3181e;
  83static int hp_c2502;
  84
  85static struct override {
  86        NCR5380_map_type NCR5380_map_name;
  87        int irq;
  88        int dma;
  89        int board;              /* Use NCR53c400, Ricoh, etc. extensions ? */
  90} overrides
  91#ifdef GENERIC_NCR5380_OVERRIDE
  92[] __initdata = GENERIC_NCR5380_OVERRIDE;
  93#else
  94[1] __initdata = { { 0,},};
  95#endif
  96
  97#define NO_OVERRIDES ARRAY_SIZE(overrides)
  98
  99#ifndef MODULE
 100
 101/**
 102 *      internal_setup          -       handle lilo command string override
 103 *      @board: BOARD_* identifier for the board
 104 *      @str: unused
 105 *      @ints: numeric parameters
 106 *
 107 *      Do LILO command line initialization of the overrides array. Display
 108 *      errors when needed
 109 *
 110 *      Locks: none
 111 */
 112
 113static void __init internal_setup(int board, char *str, int *ints)
 114{
 115        static int commandline_current;
 116        switch (board) {
 117        case BOARD_NCR5380:
 118                if (ints[0] != 2 && ints[0] != 3) {
 119                        printk(KERN_ERR "generic_NCR5380_setup : usage ncr5380=" STRVAL(NCR5380_map_name) ",irq,dma\n");
 120                        return;
 121                }
 122                break;
 123        case BOARD_NCR53C400:
 124                if (ints[0] != 2) {
 125                        printk(KERN_ERR "generic_NCR53C400_setup : usage ncr53c400=" STRVAL(NCR5380_map_name) ",irq\n");
 126                        return;
 127                }
 128                break;
 129        case BOARD_NCR53C400A:
 130                if (ints[0] != 2) {
 131                        printk(KERN_ERR "generic_NCR53C400A_setup : usage ncr53c400a=" STRVAL(NCR5380_map_name) ",irq\n");
 132                        return;
 133                }
 134                break;
 135        case BOARD_DTC3181E:
 136                if (ints[0] != 2) {
 137                        printk("generic_DTC3181E_setup : usage dtc3181e=" STRVAL(NCR5380_map_name) ",irq\n");
 138                        return;
 139                }
 140                break;
 141        }
 142
 143        if (commandline_current < NO_OVERRIDES) {
 144                overrides[commandline_current].NCR5380_map_name = (NCR5380_map_type) ints[1];
 145                overrides[commandline_current].irq = ints[2];
 146                if (ints[0] == 3)
 147                        overrides[commandline_current].dma = ints[3];
 148                else
 149                        overrides[commandline_current].dma = DMA_NONE;
 150                overrides[commandline_current].board = board;
 151                ++commandline_current;
 152        }
 153}
 154
 155
 156/**
 157 *      do_NCR53C80_setup               -       set up entry point
 158 *      @str: unused
 159 *
 160 *      Setup function invoked at boot to parse the ncr5380= command
 161 *      line.
 162 */
 163
 164static int __init do_NCR5380_setup(char *str)
 165{
 166        int ints[10];
 167
 168        get_options(str, ARRAY_SIZE(ints), ints);
 169        internal_setup(BOARD_NCR5380, str, ints);
 170        return 1;
 171}
 172
 173/**
 174 *      do_NCR53C400_setup              -       set up entry point
 175 *      @str: unused
 176 *      @ints: integer parameters from kernel setup code
 177 *
 178 *      Setup function invoked at boot to parse the ncr53c400= command
 179 *      line.
 180 */
 181
 182static int __init do_NCR53C400_setup(char *str)
 183{
 184        int ints[10];
 185
 186        get_options(str, ARRAY_SIZE(ints), ints);
 187        internal_setup(BOARD_NCR53C400, str, ints);
 188        return 1;
 189}
 190
 191/**
 192 *      do_NCR53C400A_setup     -       set up entry point
 193 *      @str: unused
 194 *      @ints: integer parameters from kernel setup code
 195 *
 196 *      Setup function invoked at boot to parse the ncr53c400a= command
 197 *      line.
 198 */
 199
 200static int __init do_NCR53C400A_setup(char *str)
 201{
 202        int ints[10];
 203
 204        get_options(str, ARRAY_SIZE(ints), ints);
 205        internal_setup(BOARD_NCR53C400A, str, ints);
 206        return 1;
 207}
 208
 209/**
 210 *      do_DTC3181E_setup       -       set up entry point
 211 *      @str: unused
 212 *      @ints: integer parameters from kernel setup code
 213 *
 214 *      Setup function invoked at boot to parse the dtc3181e= command
 215 *      line.
 216 */
 217
 218static int __init do_DTC3181E_setup(char *str)
 219{
 220        int ints[10];
 221
 222        get_options(str, ARRAY_SIZE(ints), ints);
 223        internal_setup(BOARD_DTC3181E, str, ints);
 224        return 1;
 225}
 226
 227#endif
 228
 229#ifndef SCSI_G_NCR5380_MEM
 230/*
 231 * Configure I/O address of 53C400A or DTC436 by writing magic numbers
 232 * to ports 0x779 and 0x379.
 233 */
 234static void magic_configure(int idx, u8 irq, u8 magic[])
 235{
 236        u8 cfg = 0;
 237
 238        outb(magic[0], 0x779);
 239        outb(magic[1], 0x379);
 240        outb(magic[2], 0x379);
 241        outb(magic[3], 0x379);
 242        outb(magic[4], 0x379);
 243
 244        /* allowed IRQs for HP C2502 */
 245        if (irq != 2 && irq != 3 && irq != 4 && irq != 5 && irq != 7)
 246                irq = 0;
 247        if (idx >= 0 && idx <= 7)
 248                cfg = 0x80 | idx | (irq << 4);
 249        outb(cfg, 0x379);
 250}
 251#endif
 252
 253/**
 254 *      generic_NCR5380_detect  -       look for NCR5380 controllers
 255 *      @tpnt: the scsi template
 256 *
 257 *      Scan for the present of NCR5380, NCR53C400, NCR53C400A, DTC3181E
 258 *      and DTC436(ISAPnP) controllers. If overrides have been set we use
 259 *      them.
 260 *
 261 *      Locks: none
 262 */
 263
 264static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
 265{
 266        static int current_override;
 267        int count;
 268        unsigned int *ports;
 269        u8 *magic = NULL;
 270#ifndef SCSI_G_NCR5380_MEM
 271        int i;
 272        int port_idx = -1;
 273        unsigned long region_size = 16;
 274#endif
 275        static unsigned int __initdata ncr_53c400a_ports[] = {
 276                0x280, 0x290, 0x300, 0x310, 0x330, 0x340, 0x348, 0x350, 0
 277        };
 278        static unsigned int __initdata dtc_3181e_ports[] = {
 279                0x220, 0x240, 0x280, 0x2a0, 0x2c0, 0x300, 0x320, 0x340, 0
 280        };
 281        static u8 ncr_53c400a_magic[] __initdata = {    /* 53C400A & DTC436 */
 282                0x59, 0xb9, 0xc5, 0xae, 0xa6
 283        };
 284        static u8 hp_c2502_magic[] __initdata = {       /* HP C2502 */
 285                0x0f, 0x22, 0xf0, 0x20, 0x80
 286        };
 287        int flags;
 288        struct Scsi_Host *instance;
 289        struct NCR5380_hostdata *hostdata;
 290#ifdef SCSI_G_NCR5380_MEM
 291        unsigned long base;
 292        void __iomem *iomem;
 293#endif
 294
 295        if (ncr_irq)
 296                overrides[0].irq = ncr_irq;
 297        if (ncr_dma)
 298                overrides[0].dma = ncr_dma;
 299        if (ncr_addr)
 300                overrides[0].NCR5380_map_name = (NCR5380_map_type) ncr_addr;
 301        if (ncr_5380)
 302                overrides[0].board = BOARD_NCR5380;
 303        else if (ncr_53c400)
 304                overrides[0].board = BOARD_NCR53C400;
 305        else if (ncr_53c400a)
 306                overrides[0].board = BOARD_NCR53C400A;
 307        else if (dtc_3181e)
 308                overrides[0].board = BOARD_DTC3181E;
 309        else if (hp_c2502)
 310                overrides[0].board = BOARD_HP_C2502;
 311#ifndef SCSI_G_NCR5380_MEM
 312        if (!current_override && isapnp_present()) {
 313                struct pnp_dev *dev = NULL;
 314                count = 0;
 315                while ((dev = pnp_find_dev(NULL, ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e), dev))) {
 316                        if (count >= NO_OVERRIDES)
 317                                break;
 318                        if (pnp_device_attach(dev) < 0)
 319                                continue;
 320                        if (pnp_activate_dev(dev) < 0) {
 321                                printk(KERN_ERR "dtc436e probe: activate failed\n");
 322                                pnp_device_detach(dev);
 323                                continue;
 324                        }
 325                        if (!pnp_port_valid(dev, 0)) {
 326                                printk(KERN_ERR "dtc436e probe: no valid port\n");
 327                                pnp_device_detach(dev);
 328                                continue;
 329                        }
 330                        if (pnp_irq_valid(dev, 0))
 331                                overrides[count].irq = pnp_irq(dev, 0);
 332                        else
 333                                overrides[count].irq = NO_IRQ;
 334                        if (pnp_dma_valid(dev, 0))
 335                                overrides[count].dma = pnp_dma(dev, 0);
 336                        else
 337                                overrides[count].dma = DMA_NONE;
 338                        overrides[count].NCR5380_map_name = (NCR5380_map_type) pnp_port_start(dev, 0);
 339                        overrides[count].board = BOARD_DTC3181E;
 340                        count++;
 341                }
 342        }
 343#endif
 344
 345        for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
 346                if (!(overrides[current_override].NCR5380_map_name))
 347                        continue;
 348
 349                ports = NULL;
 350                flags = 0;
 351                switch (overrides[current_override].board) {
 352                case BOARD_NCR5380:
 353                        flags = FLAG_NO_PSEUDO_DMA;
 354                        break;
 355                case BOARD_NCR53C400:
 356#ifdef PSEUDO_DMA
 357                        flags = FLAG_NO_DMA_FIXUP;
 358#endif
 359                        break;
 360                case BOARD_NCR53C400A:
 361                        flags = FLAG_NO_DMA_FIXUP;
 362                        ports = ncr_53c400a_ports;
 363                        magic = ncr_53c400a_magic;
 364                        break;
 365                case BOARD_HP_C2502:
 366                        flags = FLAG_NO_DMA_FIXUP;
 367                        ports = ncr_53c400a_ports;
 368                        magic = hp_c2502_magic;
 369                        break;
 370                case BOARD_DTC3181E:
 371                        flags = FLAG_NO_DMA_FIXUP;
 372                        ports = dtc_3181e_ports;
 373                        magic = ncr_53c400a_magic;
 374                        break;
 375                }
 376
 377#ifndef SCSI_G_NCR5380_MEM
 378                if (ports && magic) {
 379                        /* wakeup sequence for the NCR53C400A and DTC3181E */
 380
 381                        /* Disable the adapter and look for a free io port */
 382                        magic_configure(-1, 0, magic);
 383
 384                        if (overrides[current_override].NCR5380_map_name != PORT_AUTO)
 385                                for (i = 0; ports[i]; i++) {
 386                                        if (!request_region(ports[i],  16, "ncr53c80"))
 387                                                continue;
 388                                        if (overrides[current_override].NCR5380_map_name == ports[i])
 389                                                break;
 390                                        release_region(ports[i], 16);
 391                        } else
 392                                for (i = 0; ports[i]; i++) {
 393                                        if (!request_region(ports[i],  16, "ncr53c80"))
 394                                                continue;
 395                                        if (inb(ports[i]) == 0xff)
 396                                                break;
 397                                        release_region(ports[i], 16);
 398                                }
 399                        if (ports[i]) {
 400                                /* At this point we have our region reserved */
 401                                magic_configure(i, 0, magic); /* no IRQ yet */
 402                                outb(0xc0, ports[i] + 9);
 403                                if (inb(ports[i] + 9) != 0x80)
 404                                        continue;
 405                                overrides[current_override].NCR5380_map_name = ports[i];
 406                                port_idx = i;
 407                        } else
 408                                continue;
 409                }
 410                else
 411                {
 412                        /* Not a 53C400A style setup - just grab */
 413                        if(!(request_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size, "ncr5380")))
 414                                continue;
 415                        region_size = NCR5380_region_size;
 416                }
 417#else
 418                base = overrides[current_override].NCR5380_map_name;
 419                if (!request_mem_region(base, NCR5380_region_size, "ncr5380"))
 420                        continue;
 421                iomem = ioremap(base, NCR5380_region_size);
 422                if (!iomem) {
 423                        release_mem_region(base, NCR5380_region_size);
 424                        continue;
 425                }
 426#endif
 427                instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata));
 428                if (instance == NULL)
 429                        goto out_release;
 430                hostdata = shost_priv(instance);
 431
 432#ifndef SCSI_G_NCR5380_MEM
 433                instance->io_port = overrides[current_override].NCR5380_map_name;
 434                instance->n_io_port = region_size;
 435                hostdata->io_width = 1; /* 8-bit PDMA by default */
 436
 437                /*
 438                 * On NCR53C400 boards, NCR5380 registers are mapped 8 past
 439                 * the base address.
 440                 */
 441                switch (overrides[current_override].board) {
 442                case BOARD_NCR53C400:
 443                        instance->io_port += 8;
 444                        hostdata->c400_ctl_status = 0;
 445                        hostdata->c400_blk_cnt = 1;
 446                        hostdata->c400_host_buf = 4;
 447                        break;
 448                case BOARD_DTC3181E:
 449                        hostdata->io_width = 2; /* 16-bit PDMA */
 450                        /* fall through */
 451                case BOARD_NCR53C400A:
 452                case BOARD_HP_C2502:
 453                        hostdata->c400_ctl_status = 9;
 454                        hostdata->c400_blk_cnt = 10;
 455                        hostdata->c400_host_buf = 8;
 456                        break;
 457                }
 458#else
 459                instance->base = overrides[current_override].NCR5380_map_name;
 460                hostdata->iomem = iomem;
 461                switch (overrides[current_override].board) {
 462                case BOARD_NCR53C400:
 463                        hostdata->c400_ctl_status = 0x100;
 464                        hostdata->c400_blk_cnt = 0x101;
 465                        hostdata->c400_host_buf = 0x104;
 466                        break;
 467                case BOARD_DTC3181E:
 468                case BOARD_NCR53C400A:
 469                case BOARD_HP_C2502:
 470                        pr_err(DRV_MODULE_NAME ": unknown register offsets\n");
 471                        goto out_unregister;
 472                }
 473#endif
 474
 475                if (NCR5380_init(instance, flags))
 476                        goto out_unregister;
 477
 478                switch (overrides[current_override].board) {
 479                case BOARD_NCR53C400:
 480                case BOARD_DTC3181E:
 481                case BOARD_NCR53C400A:
 482                case BOARD_HP_C2502:
 483                        NCR5380_write(hostdata->c400_ctl_status, CSR_BASE);
 484                }
 485
 486                NCR5380_maybe_reset_bus(instance);
 487
 488                if (overrides[current_override].irq != IRQ_AUTO)
 489                        instance->irq = overrides[current_override].irq;
 490                else
 491                        instance->irq = NCR5380_probe_irq(instance, 0xffff);
 492
 493                /* Compatibility with documented NCR5380 kernel parameters */
 494                if (instance->irq == 255)
 495                        instance->irq = NO_IRQ;
 496
 497                if (instance->irq != NO_IRQ) {
 498#ifndef SCSI_G_NCR5380_MEM
 499                        /* set IRQ for HP C2502 */
 500                        if (overrides[current_override].board == BOARD_HP_C2502)
 501                                magic_configure(port_idx, instance->irq, magic);
 502#endif
 503                        if (request_irq(instance->irq, generic_NCR5380_intr,
 504                                        0, "NCR5380", instance)) {
 505                                printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
 506                                instance->irq = NO_IRQ;
 507                        }
 508                }
 509
 510                if (instance->irq == NO_IRQ) {
 511                        printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
 512                        printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
 513                }
 514
 515                ++current_override;
 516                ++count;
 517        }
 518        return count;
 519
 520out_unregister:
 521        scsi_unregister(instance);
 522out_release:
 523#ifndef SCSI_G_NCR5380_MEM
 524        release_region(overrides[current_override].NCR5380_map_name, region_size);
 525#else
 526        iounmap(iomem);
 527        release_mem_region(base, NCR5380_region_size);
 528#endif
 529        return count;
 530}
 531
 532/**
 533 *      generic_NCR5380_release_resources       -       free resources
 534 *      @instance: host adapter to clean up 
 535 *
 536 *      Free the generic interface resources from this adapter.
 537 *
 538 *      Locks: none
 539 */
 540 
 541static int generic_NCR5380_release_resources(struct Scsi_Host *instance)
 542{
 543        if (instance->irq != NO_IRQ)
 544                free_irq(instance->irq, instance);
 545        NCR5380_exit(instance);
 546#ifndef SCSI_G_NCR5380_MEM
 547        release_region(instance->io_port, instance->n_io_port);
 548#else
 549        iounmap(((struct NCR5380_hostdata *)instance->hostdata)->iomem);
 550        release_mem_region(instance->base, NCR5380_region_size);
 551#endif
 552        return 0;
 553}
 554
 555#ifdef BIOSPARAM
 556/**
 557 *      generic_NCR5380_biosparam
 558 *      @disk: disk to compute geometry for
 559 *      @dev: device identifier for this disk
 560 *      @ip: sizes to fill in
 561 *
 562 *      Generates a BIOS / DOS compatible H-C-S mapping for the specified 
 563 *      device / size.
 564 * 
 565 *      XXX Most SCSI boards use this mapping, I could be incorrect.  Someone
 566 *      using hard disks on a trantor should verify that this mapping
 567 *      corresponds to that used by the BIOS / ASPI driver by running the linux
 568 *      fdisk program and matching the H_C_S coordinates to what DOS uses.
 569 *
 570 *      Locks: none
 571 */
 572
 573static int
 574generic_NCR5380_biosparam(struct scsi_device *sdev, struct block_device *bdev,
 575                          sector_t capacity, int *ip)
 576{
 577        ip[0] = 64;
 578        ip[1] = 32;
 579        ip[2] = capacity >> 11;
 580        return 0;
 581}
 582#endif
 583
 584#ifdef PSEUDO_DMA
 585
 586/**
 587 *      NCR5380_pread           -       pseudo DMA read
 588 *      @instance: adapter to read from
 589 *      @dst: buffer to read into
 590 *      @len: buffer length
 591 *
 592 *      Perform a pseudo DMA mode read from an NCR53C400 or equivalent
 593 *      controller
 594 */
 595 
 596static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len)
 597{
 598        struct NCR5380_hostdata *hostdata = shost_priv(instance);
 599        int blocks = len / 128;
 600        int start = 0;
 601
 602        NCR5380_write(hostdata->c400_ctl_status, CSR_BASE | CSR_TRANS_DIR);
 603        NCR5380_write(hostdata->c400_blk_cnt, blocks);
 604        while (1) {
 605                if (NCR5380_read(hostdata->c400_blk_cnt) == 0)
 606                        break;
 607                if (NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ) {
 608                        printk(KERN_ERR "53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
 609                        return -1;
 610                }
 611                while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
 612                        ; /* FIXME - no timeout */
 613
 614#ifndef SCSI_G_NCR5380_MEM
 615                if (hostdata->io_width == 2)
 616                        insw(instance->io_port + hostdata->c400_host_buf,
 617                                                        dst + start, 64);
 618                else
 619                        insb(instance->io_port + hostdata->c400_host_buf,
 620                                                        dst + start, 128);
 621#else
 622                /* implies SCSI_G_NCR5380_MEM */
 623                memcpy_fromio(dst + start,
 624                              hostdata->iomem + NCR53C400_host_buffer, 128);
 625#endif
 626                start += 128;
 627                blocks--;
 628        }
 629
 630        if (blocks) {
 631                while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
 632                        ; /* FIXME - no timeout */
 633
 634#ifndef SCSI_G_NCR5380_MEM
 635                if (hostdata->io_width == 2)
 636                        insw(instance->io_port + hostdata->c400_host_buf,
 637                                                        dst + start, 64);
 638                else
 639                        insb(instance->io_port + hostdata->c400_host_buf,
 640                                                        dst + start, 128);
 641#else
 642                /* implies SCSI_G_NCR5380_MEM */
 643                memcpy_fromio(dst + start,
 644                              hostdata->iomem + NCR53C400_host_buffer, 128);
 645#endif
 646                start += 128;
 647                blocks--;
 648        }
 649
 650        if (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ))
 651                printk("53C400r: no 53C80 gated irq after transfer");
 652
 653        /* wait for 53C80 registers to be available */
 654        while (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG))
 655                ;
 656
 657        if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER))
 658                printk(KERN_ERR "53C400r: no end dma signal\n");
 659                
 660        return 0;
 661}
 662
 663/**
 664 *      NCR5380_write           -       pseudo DMA write
 665 *      @instance: adapter to read from
 666 *      @dst: buffer to read into
 667 *      @len: buffer length
 668 *
 669 *      Perform a pseudo DMA mode read from an NCR53C400 or equivalent
 670 *      controller
 671 */
 672
 673static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len)
 674{
 675        struct NCR5380_hostdata *hostdata = shost_priv(instance);
 676        int blocks = len / 128;
 677        int start = 0;
 678
 679        NCR5380_write(hostdata->c400_ctl_status, CSR_BASE);
 680        NCR5380_write(hostdata->c400_blk_cnt, blocks);
 681        while (1) {
 682                if (NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ) {
 683                        printk(KERN_ERR "53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
 684                        return -1;
 685                }
 686
 687                if (NCR5380_read(hostdata->c400_blk_cnt) == 0)
 688                        break;
 689                while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
 690                        ; // FIXME - timeout
 691#ifndef SCSI_G_NCR5380_MEM
 692                if (hostdata->io_width == 2)
 693                        outsw(instance->io_port + hostdata->c400_host_buf,
 694                                                        src + start, 64);
 695                else
 696                        outsb(instance->io_port + hostdata->c400_host_buf,
 697                                                        src + start, 128);
 698#else
 699                /* implies SCSI_G_NCR5380_MEM */
 700                memcpy_toio(hostdata->iomem + NCR53C400_host_buffer,
 701                            src + start, 128);
 702#endif
 703                start += 128;
 704                blocks--;
 705        }
 706        if (blocks) {
 707                while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
 708                        ; // FIXME - no timeout
 709
 710#ifndef SCSI_G_NCR5380_MEM
 711                if (hostdata->io_width == 2)
 712                        outsw(instance->io_port + hostdata->c400_host_buf,
 713                                                        src + start, 64);
 714                else
 715                        outsb(instance->io_port + hostdata->c400_host_buf,
 716                                                        src + start, 128);
 717#else
 718                /* implies SCSI_G_NCR5380_MEM */
 719                memcpy_toio(hostdata->iomem + NCR53C400_host_buffer,
 720                            src + start, 128);
 721#endif
 722                start += 128;
 723                blocks--;
 724        }
 725
 726        /* wait for 53C80 registers to be available */
 727        while (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG)) {
 728                udelay(4); /* DTC436 chip hangs without this */
 729                /* FIXME - no timeout */
 730        }
 731
 732        if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) {
 733                printk(KERN_ERR "53C400w: no end dma signal\n");
 734        }
 735
 736        while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT))
 737                ;       // TIMEOUT
 738        return 0;
 739}
 740
 741static int generic_NCR5380_dma_xfer_len(struct scsi_cmnd *cmd)
 742{
 743        int transfersize = cmd->transfersize;
 744
 745        /* Limit transfers to 32K, for xx400 & xx406
 746         * pseudoDMA that transfers in 128 bytes blocks.
 747         */
 748        if (transfersize > 32 * 1024 && cmd->SCp.this_residual &&
 749            !(cmd->SCp.this_residual % transfersize))
 750                transfersize = 32 * 1024;
 751
 752        /* 53C400 datasheet: non-modulo-128-byte transfers should use PIO */
 753        if (transfersize % 128)
 754                transfersize = 0;
 755
 756        return transfersize;
 757}
 758
 759#endif /* PSEUDO_DMA */
 760
 761/*
 762 *      Include the NCR5380 core code that we build our driver around   
 763 */
 764 
 765#include "NCR5380.c"
 766
 767static struct scsi_host_template driver_template = {
 768        .proc_name              = DRV_MODULE_NAME,
 769        .name                   = "Generic NCR5380/NCR53C400 SCSI",
 770        .detect                 = generic_NCR5380_detect,
 771        .release                = generic_NCR5380_release_resources,
 772        .info                   = generic_NCR5380_info,
 773        .queuecommand           = generic_NCR5380_queue_command,
 774        .eh_abort_handler       = generic_NCR5380_abort,
 775        .eh_bus_reset_handler   = generic_NCR5380_bus_reset,
 776        .bios_param             = NCR5380_BIOSPARAM,
 777        .can_queue              = 16,
 778        .this_id                = 7,
 779        .sg_tablesize           = SG_ALL,
 780        .cmd_per_lun            = 2,
 781        .use_clustering         = DISABLE_CLUSTERING,
 782        .cmd_size               = NCR5380_CMD_SIZE,
 783        .max_sectors            = 128,
 784};
 785
 786#include "scsi_module.c"
 787
 788module_param(ncr_irq, int, 0);
 789module_param(ncr_dma, int, 0);
 790module_param(ncr_addr, int, 0);
 791module_param(ncr_5380, int, 0);
 792module_param(ncr_53c400, int, 0);
 793module_param(ncr_53c400a, int, 0);
 794module_param(dtc_3181e, int, 0);
 795module_param(hp_c2502, int, 0);
 796MODULE_LICENSE("GPL");
 797
 798#if !defined(SCSI_G_NCR5380_MEM) && defined(MODULE)
 799static struct isapnp_device_id id_table[] = {
 800        {
 801         ISAPNP_ANY_ID, ISAPNP_ANY_ID,
 802         ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e),
 803         0},
 804        {0}
 805};
 806
 807MODULE_DEVICE_TABLE(isapnp, id_table);
 808#endif
 809
 810__setup("ncr5380=", do_NCR5380_setup);
 811__setup("ncr53c400=", do_NCR53C400_setup);
 812__setup("ncr53c400a=", do_NCR53C400A_setup);
 813__setup("dtc3181e=", do_DTC3181E_setup);
 814