linux/drivers/scsi/arm/eesox.c
<<
>>
Prefs
   1/*
   2 *  linux/drivers/acorn/scsi/eesox.c
   3 *
   4 *  Copyright (C) 1997-2005 Russell King
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 *
  10 *  This driver is based on experimentation.  Hence, it may have made
  11 *  assumptions about the particular card that I have available, and
  12 *  may not be reliable!
  13 *
  14 *  Changelog:
  15 *   01-10-1997 RMK             Created, READONLY version
  16 *   15-02-1998 RMK             READ/WRITE version
  17 *                              added DMA support and hardware definitions
  18 *   14-03-1998 RMK             Updated DMA support
  19 *                              Added terminator control
  20 *   15-04-1998 RMK             Only do PIO if FAS216 will allow it.
  21 *   27-06-1998 RMK             Changed asm/delay.h to linux/delay.h
  22 *   02-04-2000 RMK     0.0.3   Fixed NO_IRQ/NO_DMA problem, updated for new
  23 *                              error handling code.
  24 */
  25#include <linux/module.h>
  26#include <linux/blkdev.h>
  27#include <linux/kernel.h>
  28#include <linux/string.h>
  29#include <linux/ioport.h>
  30#include <linux/proc_fs.h>
  31#include <linux/delay.h>
  32#include <linux/interrupt.h>
  33#include <linux/init.h>
  34#include <linux/dma-mapping.h>
  35
  36#include <asm/io.h>
  37#include <asm/dma.h>
  38#include <asm/ecard.h>
  39#include <asm/pgtable.h>
  40
  41#include "../scsi.h"
  42#include <scsi/scsi_host.h>
  43#include "fas216.h"
  44#include "scsi.h"
  45
  46#include <scsi/scsicam.h>
  47
  48#define EESOX_FAS216_OFFSET     0x3000
  49#define EESOX_FAS216_SHIFT      5
  50
  51#define EESOX_DMASTAT           0x2800
  52#define EESOX_STAT_INTR         0x01
  53#define EESOX_STAT_DMA          0x02
  54
  55#define EESOX_CONTROL           0x2800
  56#define EESOX_INTR_ENABLE       0x04
  57#define EESOX_TERM_ENABLE       0x02
  58#define EESOX_RESET             0x01
  59
  60#define EESOX_DMADATA           0x3800
  61
  62#define VERSION "1.10 (17/01/2003 2.5.59)"
  63
  64/*
  65 * Use term=0,1,0,0,0 to turn terminators on/off
  66 */
  67static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 };
  68
  69#define NR_SG   256
  70
  71struct eesoxscsi_info {
  72        FAS216_Info             info;
  73        struct expansion_card   *ec;
  74        void __iomem            *base;
  75        void __iomem            *ctl_port;
  76        unsigned int            control;
  77        struct scatterlist      sg[NR_SG];      /* Scatter DMA list     */
  78};
  79
  80/* Prototype: void eesoxscsi_irqenable(ec, irqnr)
  81 * Purpose  : Enable interrupts on EESOX SCSI card
  82 * Params   : ec    - expansion card structure
  83 *          : irqnr - interrupt number
  84 */
  85static void
  86eesoxscsi_irqenable(struct expansion_card *ec, int irqnr)
  87{
  88        struct eesoxscsi_info *info = (struct eesoxscsi_info *)ec->irq_data;
  89
  90        info->control |= EESOX_INTR_ENABLE;
  91
  92        writeb(info->control, info->ctl_port);
  93}
  94
  95/* Prototype: void eesoxscsi_irqdisable(ec, irqnr)
  96 * Purpose  : Disable interrupts on EESOX SCSI card
  97 * Params   : ec    - expansion card structure
  98 *          : irqnr - interrupt number
  99 */
 100static void
 101eesoxscsi_irqdisable(struct expansion_card *ec, int irqnr)
 102{
 103        struct eesoxscsi_info *info = (struct eesoxscsi_info *)ec->irq_data;
 104
 105        info->control &= ~EESOX_INTR_ENABLE;
 106
 107        writeb(info->control, info->ctl_port);
 108}
 109
 110static const expansioncard_ops_t eesoxscsi_ops = {
 111        .irqenable      = eesoxscsi_irqenable,
 112        .irqdisable     = eesoxscsi_irqdisable,
 113};
 114
 115/* Prototype: void eesoxscsi_terminator_ctl(*host, on_off)
 116 * Purpose  : Turn the EESOX SCSI terminators on or off
 117 * Params   : host   - card to turn on/off
 118 *          : on_off - !0 to turn on, 0 to turn off
 119 */
 120static void
 121eesoxscsi_terminator_ctl(struct Scsi_Host *host, int on_off)
 122{
 123        struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
 124        unsigned long flags;
 125
 126        spin_lock_irqsave(host->host_lock, flags);
 127        if (on_off)
 128                info->control |= EESOX_TERM_ENABLE;
 129        else
 130                info->control &= ~EESOX_TERM_ENABLE;
 131
 132        writeb(info->control, info->ctl_port);
 133        spin_unlock_irqrestore(host->host_lock, flags);
 134}
 135
 136/* Prototype: void eesoxscsi_intr(irq, *dev_id, *regs)
 137 * Purpose  : handle interrupts from EESOX SCSI card
 138 * Params   : irq    - interrupt number
 139 *            dev_id - user-defined (Scsi_Host structure)
 140 */
 141static irqreturn_t
 142eesoxscsi_intr(int irq, void *dev_id)
 143{
 144        struct eesoxscsi_info *info = dev_id;
 145
 146        return fas216_intr(&info->info);
 147}
 148
 149/* Prototype: fasdmatype_t eesoxscsi_dma_setup(host, SCpnt, direction, min_type)
 150 * Purpose  : initialises DMA/PIO
 151 * Params   : host      - host
 152 *            SCpnt     - command
 153 *            direction - DMA on to/off of card
 154 *            min_type  - minimum DMA support that we must have for this transfer
 155 * Returns  : type of transfer to be performed
 156 */
 157static fasdmatype_t
 158eesoxscsi_dma_setup(struct Scsi_Host *host, struct scsi_pointer *SCp,
 159                       fasdmadir_t direction, fasdmatype_t min_type)
 160{
 161        struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
 162        struct device *dev = scsi_get_device(host);
 163        int dmach = info->info.scsi.dma;
 164
 165        if (dmach != NO_DMA &&
 166            (min_type == fasdma_real_all || SCp->this_residual >= 512)) {
 167                int bufs, map_dir, dma_dir;
 168
 169                bufs = copy_SCp_to_sg(&info->sg[0], SCp, NR_SG);
 170
 171                if (direction == DMA_OUT)
 172                        map_dir = DMA_TO_DEVICE,
 173                        dma_dir = DMA_MODE_WRITE;
 174                else
 175                        map_dir = DMA_FROM_DEVICE,
 176                        dma_dir = DMA_MODE_READ;
 177
 178                dma_map_sg(dev, info->sg, bufs, map_dir);
 179
 180                disable_dma(dmach);
 181                set_dma_sg(dmach, info->sg, bufs);
 182                set_dma_mode(dmach, dma_dir);
 183                enable_dma(dmach);
 184                return fasdma_real_all;
 185        }
 186        /*
 187         * We don't do DMA, we only do slow PIO
 188         *
 189         * Some day, we will do Pseudo DMA
 190         */
 191        return fasdma_pseudo;
 192}
 193
 194static void eesoxscsi_buffer_in(void *buf, int length, void __iomem *base)
 195{
 196        const void __iomem *reg_fas = base + EESOX_FAS216_OFFSET;
 197        const void __iomem *reg_dmastat = base + EESOX_DMASTAT;
 198        const void __iomem *reg_dmadata = base + EESOX_DMADATA;
 199        register const unsigned long mask = 0xffff;
 200
 201        do {
 202                unsigned int status;
 203
 204                /*
 205                 * Interrupt request?
 206                 */
 207                status = readb(reg_fas + (REG_STAT << EESOX_FAS216_SHIFT));
 208                if (status & STAT_INT)
 209                        break;
 210
 211                /*
 212                 * DMA request active?
 213                 */
 214                status = readb(reg_dmastat);
 215                if (!(status & EESOX_STAT_DMA))
 216                        continue;
 217
 218                /*
 219                 * Get number of bytes in FIFO
 220                 */
 221                status = readb(reg_fas + (REG_CFIS << EESOX_FAS216_SHIFT)) & CFIS_CF;
 222                if (status > 16)
 223                        status = 16;
 224                if (status > length)
 225                        status = length;
 226
 227                /*
 228                 * Align buffer.
 229                 */
 230                if (((u32)buf) & 2 && status >= 2) {
 231                        *(u16 *)buf = readl(reg_dmadata);
 232                        buf += 2;
 233                        status -= 2;
 234                        length -= 2;
 235                }
 236
 237                if (status >= 8) {
 238                        unsigned long l1, l2;
 239
 240                        l1 = readl(reg_dmadata) & mask;
 241                        l1 |= readl(reg_dmadata) << 16;
 242                        l2 = readl(reg_dmadata) & mask;
 243                        l2 |= readl(reg_dmadata) << 16;
 244                        *(u32 *)buf = l1;
 245                        buf += 4;
 246                        *(u32 *)buf = l2;
 247                        buf += 4;
 248                        length -= 8;
 249                        continue;
 250                }
 251
 252                if (status >= 4) {
 253                        unsigned long l1;
 254
 255                        l1 = readl(reg_dmadata) & mask;
 256                        l1 |= readl(reg_dmadata) << 16;
 257
 258                        *(u32 *)buf = l1;
 259                        buf += 4;
 260                        length -= 4;
 261                        continue;
 262                }
 263
 264                if (status >= 2) {
 265                        *(u16 *)buf = readl(reg_dmadata);
 266                        buf += 2;
 267                        length -= 2;
 268                }
 269        } while (length);
 270}
 271
 272static void eesoxscsi_buffer_out(void *buf, int length, void __iomem *base)
 273{
 274        const void __iomem *reg_fas = base + EESOX_FAS216_OFFSET;
 275        const void __iomem *reg_dmastat = base + EESOX_DMASTAT;
 276        void __iomem *reg_dmadata = base + EESOX_DMADATA;
 277
 278        do {
 279                unsigned int status;
 280
 281                /*
 282                 * Interrupt request?
 283                 */
 284                status = readb(reg_fas + (REG_STAT << EESOX_FAS216_SHIFT));
 285                if (status & STAT_INT)
 286                        break;
 287
 288                /*
 289                 * DMA request active?
 290                 */
 291                status = readb(reg_dmastat);
 292                if (!(status & EESOX_STAT_DMA))
 293                        continue;
 294
 295                /*
 296                 * Get number of bytes in FIFO
 297                 */
 298                status = readb(reg_fas + (REG_CFIS << EESOX_FAS216_SHIFT)) & CFIS_CF;
 299                if (status > 16)
 300                        status = 16;
 301                status = 16 - status;
 302                if (status > length)
 303                        status = length;
 304                status &= ~1;
 305
 306                /*
 307                 * Align buffer.
 308                 */
 309                if (((u32)buf) & 2 && status >= 2) {
 310                        writel(*(u16 *)buf << 16, reg_dmadata);
 311                        buf += 2;
 312                        status -= 2;
 313                        length -= 2;
 314                }
 315
 316                if (status >= 8) {
 317                        unsigned long l1, l2;
 318
 319                        l1 = *(u32 *)buf;
 320                        buf += 4;
 321                        l2 = *(u32 *)buf;
 322                        buf += 4;
 323
 324                        writel(l1 << 16, reg_dmadata);
 325                        writel(l1, reg_dmadata);
 326                        writel(l2 << 16, reg_dmadata);
 327                        writel(l2, reg_dmadata);
 328                        length -= 8;
 329                        continue;
 330                }
 331
 332                if (status >= 4) {
 333                        unsigned long l1;
 334
 335                        l1 = *(u32 *)buf;
 336                        buf += 4;
 337
 338                        writel(l1 << 16, reg_dmadata);
 339                        writel(l1, reg_dmadata);
 340                        length -= 4;
 341                        continue;
 342                }
 343
 344                if (status >= 2) {
 345                        writel(*(u16 *)buf << 16, reg_dmadata);
 346                        buf += 2;
 347                        length -= 2;
 348                }
 349        } while (length);
 350}
 351
 352static void
 353eesoxscsi_dma_pseudo(struct Scsi_Host *host, struct scsi_pointer *SCp,
 354                     fasdmadir_t dir, int transfer_size)
 355{
 356        struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
 357        if (dir == DMA_IN) {
 358                eesoxscsi_buffer_in(SCp->ptr, SCp->this_residual, info->base);
 359        } else {
 360                eesoxscsi_buffer_out(SCp->ptr, SCp->this_residual, info->base);
 361        }
 362}
 363
 364/* Prototype: int eesoxscsi_dma_stop(host, SCpnt)
 365 * Purpose  : stops DMA/PIO
 366 * Params   : host  - host
 367 *            SCpnt - command
 368 */
 369static void
 370eesoxscsi_dma_stop(struct Scsi_Host *host, struct scsi_pointer *SCp)
 371{
 372        struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
 373        if (info->info.scsi.dma != NO_DMA)
 374                disable_dma(info->info.scsi.dma);
 375}
 376
 377/* Prototype: const char *eesoxscsi_info(struct Scsi_Host * host)
 378 * Purpose  : returns a descriptive string about this interface,
 379 * Params   : host - driver host structure to return info for.
 380 * Returns  : pointer to a static buffer containing null terminated string.
 381 */
 382const char *eesoxscsi_info(struct Scsi_Host *host)
 383{
 384        struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
 385        static char string[150];
 386
 387        sprintf(string, "%s (%s) in slot %d v%s terminators o%s",
 388                host->hostt->name, info->info.scsi.type, info->ec->slot_no,
 389                VERSION, info->control & EESOX_TERM_ENABLE ? "n" : "ff");
 390
 391        return string;
 392}
 393
 394/* Prototype: int eesoxscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
 395 * Purpose  : Set a driver specific function
 396 * Params   : host   - host to setup
 397 *          : buffer - buffer containing string describing operation
 398 *          : length - length of string
 399 * Returns  : -EINVAL, or 0
 400 */
 401static int
 402eesoxscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
 403{
 404        int ret = length;
 405
 406        if (length >= 9 && strncmp(buffer, "EESOXSCSI", 9) == 0) {
 407                buffer += 9;
 408                length -= 9;
 409
 410                if (length >= 5 && strncmp(buffer, "term=", 5) == 0) {
 411                        if (buffer[5] == '1')
 412                                eesoxscsi_terminator_ctl(host, 1);
 413                        else if (buffer[5] == '0')
 414                                eesoxscsi_terminator_ctl(host, 0);
 415                        else
 416                                ret = -EINVAL;
 417                } else
 418                        ret = -EINVAL;
 419        } else
 420                ret = -EINVAL;
 421
 422        return ret;
 423}
 424
 425static int eesoxscsi_show_info(struct seq_file *m, struct Scsi_Host *host)
 426{
 427        struct eesoxscsi_info *info;
 428
 429        info = (struct eesoxscsi_info *)host->hostdata;
 430
 431        seq_printf(m, "EESOX SCSI driver v%s\n", VERSION);
 432        fas216_print_host(&info->info, m);
 433        seq_printf(m, "Term    : o%s\n",
 434                        info->control & EESOX_TERM_ENABLE ? "n" : "ff");
 435
 436        fas216_print_stats(&info->info, m);
 437        fas216_print_devices(&info->info, m);
 438        return 0;
 439}
 440
 441static ssize_t eesoxscsi_show_term(struct device *dev, struct device_attribute *attr, char *buf)
 442{
 443        struct expansion_card *ec = ECARD_DEV(dev);
 444        struct Scsi_Host *host = ecard_get_drvdata(ec);
 445        struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
 446
 447        return sprintf(buf, "%d\n", info->control & EESOX_TERM_ENABLE ? 1 : 0);
 448}
 449
 450static ssize_t eesoxscsi_store_term(struct device *dev, struct device_attribute *attr, const char *buf, size_t len)
 451{
 452        struct expansion_card *ec = ECARD_DEV(dev);
 453        struct Scsi_Host *host = ecard_get_drvdata(ec);
 454        struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
 455        unsigned long flags;
 456
 457        if (len > 1) {
 458                spin_lock_irqsave(host->host_lock, flags);
 459                if (buf[0] != '0') {
 460                        info->control |= EESOX_TERM_ENABLE;
 461                } else {
 462                        info->control &= ~EESOX_TERM_ENABLE;
 463                }
 464                writeb(info->control, info->ctl_port);
 465                spin_unlock_irqrestore(host->host_lock, flags);
 466        }
 467
 468        return len;
 469}
 470
 471static DEVICE_ATTR(bus_term, S_IRUGO | S_IWUSR,
 472                   eesoxscsi_show_term, eesoxscsi_store_term);
 473
 474static struct scsi_host_template eesox_template = {
 475        .module                         = THIS_MODULE,
 476        .show_info                      = eesoxscsi_show_info,
 477        .write_info                     = eesoxscsi_set_proc_info,
 478        .name                           = "EESOX SCSI",
 479        .info                           = eesoxscsi_info,
 480        .queuecommand                   = fas216_queue_command,
 481        .eh_host_reset_handler          = fas216_eh_host_reset,
 482        .eh_bus_reset_handler           = fas216_eh_bus_reset,
 483        .eh_device_reset_handler        = fas216_eh_device_reset,
 484        .eh_abort_handler               = fas216_eh_abort,
 485        .can_queue                      = 1,
 486        .this_id                        = 7,
 487        .sg_tablesize                   = SCSI_MAX_SG_CHAIN_SEGMENTS,
 488        .dma_boundary                   = IOMD_DMA_BOUNDARY,
 489        .use_clustering                 = DISABLE_CLUSTERING,
 490        .proc_name                      = "eesox",
 491};
 492
 493static int eesoxscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
 494{
 495        struct Scsi_Host *host;
 496        struct eesoxscsi_info *info;
 497        void __iomem *base;
 498        int ret;
 499
 500        ret = ecard_request_resources(ec);
 501        if (ret)
 502                goto out;
 503
 504        base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
 505        if (!base) {
 506                ret = -ENOMEM;
 507                goto out_region;
 508        }
 509
 510        host = scsi_host_alloc(&eesox_template,
 511                               sizeof(struct eesoxscsi_info));
 512        if (!host) {
 513                ret = -ENOMEM;
 514                goto out_region;
 515        }
 516
 517        ecard_set_drvdata(ec, host);
 518
 519        info = (struct eesoxscsi_info *)host->hostdata;
 520        info->ec        = ec;
 521        info->base      = base;
 522        info->ctl_port  = base + EESOX_CONTROL;
 523        info->control   = term[ec->slot_no] ? EESOX_TERM_ENABLE : 0;
 524        writeb(info->control, info->ctl_port);
 525
 526        info->info.scsi.io_base         = base + EESOX_FAS216_OFFSET;
 527        info->info.scsi.io_shift        = EESOX_FAS216_SHIFT;
 528        info->info.scsi.irq             = ec->irq;
 529        info->info.scsi.dma             = ec->dma;
 530        info->info.ifcfg.clockrate      = 40; /* MHz */
 531        info->info.ifcfg.select_timeout = 255;
 532        info->info.ifcfg.asyncperiod    = 200; /* ns */
 533        info->info.ifcfg.sync_max_depth = 7;
 534        info->info.ifcfg.cntl3          = CNTL3_FASTSCSI | CNTL3_FASTCLK;
 535        info->info.ifcfg.disconnect_ok  = 1;
 536        info->info.ifcfg.wide_max_size  = 0;
 537        info->info.ifcfg.capabilities   = FASCAP_PSEUDODMA;
 538        info->info.dma.setup            = eesoxscsi_dma_setup;
 539        info->info.dma.pseudo           = eesoxscsi_dma_pseudo;
 540        info->info.dma.stop             = eesoxscsi_dma_stop;
 541
 542        ec->irqaddr     = base + EESOX_DMASTAT;
 543        ec->irqmask     = EESOX_STAT_INTR;
 544
 545        ecard_setirq(ec, &eesoxscsi_ops, info);
 546
 547        device_create_file(&ec->dev, &dev_attr_bus_term);
 548
 549        ret = fas216_init(host);
 550        if (ret)
 551                goto out_free;
 552
 553        ret = request_irq(ec->irq, eesoxscsi_intr, 0, "eesoxscsi", info);
 554        if (ret) {
 555                printk("scsi%d: IRQ%d not free: %d\n",
 556                       host->host_no, ec->irq, ret);
 557                goto out_remove;
 558        }
 559
 560        if (info->info.scsi.dma != NO_DMA) {
 561                if (request_dma(info->info.scsi.dma, "eesox")) {
 562                        printk("scsi%d: DMA%d not free, DMA disabled\n",
 563                               host->host_no, info->info.scsi.dma);
 564                        info->info.scsi.dma = NO_DMA;
 565                } else {
 566                        set_dma_speed(info->info.scsi.dma, 180);
 567                        info->info.ifcfg.capabilities |= FASCAP_DMA;
 568                        info->info.ifcfg.cntl3 |= CNTL3_BS8;
 569                }
 570        }
 571
 572        ret = fas216_add(host, &ec->dev);
 573        if (ret == 0)
 574                goto out;
 575
 576        if (info->info.scsi.dma != NO_DMA)
 577                free_dma(info->info.scsi.dma);
 578        free_irq(ec->irq, host);
 579
 580 out_remove:
 581        fas216_remove(host);
 582
 583 out_free:
 584        device_remove_file(&ec->dev, &dev_attr_bus_term);
 585        scsi_host_put(host);
 586
 587 out_region:
 588        ecard_release_resources(ec);
 589
 590 out:
 591        return ret;
 592}
 593
 594static void eesoxscsi_remove(struct expansion_card *ec)
 595{
 596        struct Scsi_Host *host = ecard_get_drvdata(ec);
 597        struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
 598
 599        ecard_set_drvdata(ec, NULL);
 600        fas216_remove(host);
 601
 602        if (info->info.scsi.dma != NO_DMA)
 603                free_dma(info->info.scsi.dma);
 604        free_irq(ec->irq, info);
 605
 606        device_remove_file(&ec->dev, &dev_attr_bus_term);
 607
 608        fas216_release(host);
 609        scsi_host_put(host);
 610        ecard_release_resources(ec);
 611}
 612
 613static const struct ecard_id eesoxscsi_cids[] = {
 614        { MANU_EESOX, PROD_EESOX_SCSI2 },
 615        { 0xffff, 0xffff },
 616};
 617
 618static struct ecard_driver eesoxscsi_driver = {
 619        .probe          = eesoxscsi_probe,
 620        .remove         = eesoxscsi_remove,
 621        .id_table       = eesoxscsi_cids,
 622        .drv = {
 623                .name           = "eesoxscsi",
 624        },
 625};
 626
 627static int __init eesox_init(void)
 628{
 629        return ecard_register_driver(&eesoxscsi_driver);
 630}
 631
 632static void __exit eesox_exit(void)
 633{
 634        ecard_remove_driver(&eesoxscsi_driver);
 635}
 636
 637module_init(eesox_init);
 638module_exit(eesox_exit);
 639
 640MODULE_AUTHOR("Russell King");
 641MODULE_DESCRIPTION("EESOX 'Fast' SCSI driver for Acorn machines");
 642module_param_array(term, int, NULL, 0);
 643MODULE_PARM_DESC(term, "SCSI bus termination");
 644MODULE_LICENSE("GPL");
 645