linux/drivers/scsi/arm/cumana_1.c
<<
>>
Prefs
   1/*
   2 * Generic Generic NCR5380 driver
   3 *
   4 * Copyright 1995-2002, Russell King
   5 */
   6#include <linux/module.h>
   7#include <linux/signal.h>
   8#include <linux/ioport.h>
   9#include <linux/delay.h>
  10#include <linux/blkdev.h>
  11#include <linux/init.h>
  12
  13#include <asm/ecard.h>
  14#include <asm/io.h>
  15
  16#include "../scsi.h"
  17#include <scsi/scsi_host.h>
  18
  19#include <scsi/scsicam.h>
  20
  21#define AUTOSENSE
  22#define PSEUDO_DMA
  23
  24#define CUMANASCSI_PUBLIC_RELEASE 1
  25
  26#define priv(host)                      ((struct NCR5380_hostdata *)(host)->hostdata)
  27#define NCR5380_local_declare()         struct Scsi_Host *_instance
  28#define NCR5380_setup(instance)         _instance = instance
  29#define NCR5380_read(reg)               cumanascsi_read(_instance, reg)
  30#define NCR5380_write(reg, value)       cumanascsi_write(_instance, reg, value)
  31#define NCR5380_intr                    cumanascsi_intr
  32#define NCR5380_queue_command           cumanascsi_queue_command
  33#define NCR5380_proc_info               cumanascsi_proc_info
  34
  35#define NCR5380_implementation_fields   \
  36        unsigned ctrl;                  \
  37        void __iomem *base;             \
  38        void __iomem *dma
  39
  40#define BOARD_NORMAL    0
  41#define BOARD_NCR53C400 1
  42
  43#include "../NCR5380.h"
  44
  45void cumanascsi_setup(char *str, int *ints)
  46{
  47}
  48
  49const char *cumanascsi_info(struct Scsi_Host *spnt)
  50{
  51        return "";
  52}
  53
  54#define CTRL    0x16fc
  55#define STAT    0x2004
  56#define L(v)    (((v)<<16)|((v) & 0x0000ffff))
  57#define H(v)    (((v)>>16)|((v) & 0xffff0000))
  58
  59static inline int
  60NCR5380_pwrite(struct Scsi_Host *host, unsigned char *addr, int len)
  61{
  62  unsigned long *laddr;
  63  void __iomem *dma = priv(host)->dma + 0x2000;
  64
  65  if(!len) return 0;
  66
  67  writeb(0x02, priv(host)->base + CTRL);
  68  laddr = (unsigned long *)addr;
  69  while(len >= 32)
  70  {
  71    unsigned int status;
  72    unsigned long v;
  73    status = readb(priv(host)->base + STAT);
  74    if(status & 0x80)
  75      goto end;
  76    if(!(status & 0x40))
  77      continue;
  78    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
  79    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
  80    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
  81    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
  82    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
  83    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
  84    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
  85    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
  86    len -= 32;
  87    if(len == 0)
  88      break;
  89  }
  90
  91  addr = (unsigned char *)laddr;
  92  writeb(0x12, priv(host)->base + CTRL);
  93
  94  while(len > 0)
  95  {
  96    unsigned int status;
  97    status = readb(priv(host)->base + STAT);
  98    if(status & 0x80)
  99      goto end;
 100    if(status & 0x40)
 101    {
 102      writeb(*addr++, dma);
 103      if(--len == 0)
 104        break;
 105    }
 106
 107    status = readb(priv(host)->base + STAT);
 108    if(status & 0x80)
 109      goto end;
 110    if(status & 0x40)
 111    {
 112      writeb(*addr++, dma);
 113      if(--len == 0)
 114        break;
 115    }
 116  }
 117end:
 118  writeb(priv(host)->ctrl | 0x40, priv(host)->base + CTRL);
 119  return len;
 120}
 121
 122static inline int
 123NCR5380_pread(struct Scsi_Host *host, unsigned char *addr, int len)
 124{
 125  unsigned long *laddr;
 126  void __iomem *dma = priv(host)->dma + 0x2000;
 127
 128  if(!len) return 0;
 129
 130  writeb(0x00, priv(host)->base + CTRL);
 131  laddr = (unsigned long *)addr;
 132  while(len >= 32)
 133  {
 134    unsigned int status;
 135    status = readb(priv(host)->base + STAT);
 136    if(status & 0x80)
 137      goto end;
 138    if(!(status & 0x40))
 139      continue;
 140    *laddr++ = readw(dma) | (readw(dma) << 16);
 141    *laddr++ = readw(dma) | (readw(dma) << 16);
 142    *laddr++ = readw(dma) | (readw(dma) << 16);
 143    *laddr++ = readw(dma) | (readw(dma) << 16);
 144    *laddr++ = readw(dma) | (readw(dma) << 16);
 145    *laddr++ = readw(dma) | (readw(dma) << 16);
 146    *laddr++ = readw(dma) | (readw(dma) << 16);
 147    *laddr++ = readw(dma) | (readw(dma) << 16);
 148    len -= 32;
 149    if(len == 0)
 150      break;
 151  }
 152
 153  addr = (unsigned char *)laddr;
 154  writeb(0x10, priv(host)->base + CTRL);
 155
 156  while(len > 0)
 157  {
 158    unsigned int status;
 159    status = readb(priv(host)->base + STAT);
 160    if(status & 0x80)
 161      goto end;
 162    if(status & 0x40)
 163    {
 164      *addr++ = readb(dma);
 165      if(--len == 0)
 166        break;
 167    }
 168
 169    status = readb(priv(host)->base + STAT);
 170    if(status & 0x80)
 171      goto end;
 172    if(status & 0x40)
 173    {
 174      *addr++ = readb(dma);
 175      if(--len == 0)
 176        break;
 177    }
 178  }
 179end:
 180  writeb(priv(host)->ctrl | 0x40, priv(host)->base + CTRL);
 181  return len;
 182}
 183
 184static unsigned char cumanascsi_read(struct Scsi_Host *host, unsigned int reg)
 185{
 186        void __iomem *base = priv(host)->base;
 187        unsigned char val;
 188
 189        writeb(0, base + CTRL);
 190
 191        val = readb(base + 0x2100 + (reg << 2));
 192
 193        priv(host)->ctrl = 0x40;
 194        writeb(0x40, base + CTRL);
 195
 196        return val;
 197}
 198
 199static void cumanascsi_write(struct Scsi_Host *host, unsigned int reg, unsigned int value)
 200{
 201        void __iomem *base = priv(host)->base;
 202
 203        writeb(0, base + CTRL);
 204
 205        writeb(value, base + 0x2100 + (reg << 2));
 206
 207        priv(host)->ctrl = 0x40;
 208        writeb(0x40, base + CTRL);
 209}
 210
 211#include "../NCR5380.c"
 212
 213static struct scsi_host_template cumanascsi_template = {
 214        .module                 = THIS_MODULE,
 215        .name                   = "Cumana 16-bit SCSI",
 216        .info                   = cumanascsi_info,
 217        .queuecommand           = cumanascsi_queue_command,
 218        .eh_abort_handler       = NCR5380_abort,
 219        .eh_bus_reset_handler   = NCR5380_bus_reset,
 220        .can_queue              = 16,
 221        .this_id                = 7,
 222        .sg_tablesize           = SG_ALL,
 223        .cmd_per_lun            = 2,
 224        .use_clustering         = DISABLE_CLUSTERING,
 225        .proc_name              = "CumanaSCSI-1",
 226};
 227
 228static int __devinit
 229cumanascsi1_probe(struct expansion_card *ec, const struct ecard_id *id)
 230{
 231        struct Scsi_Host *host;
 232        int ret;
 233
 234        ret = ecard_request_resources(ec);
 235        if (ret)
 236                goto out;
 237
 238        host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata));
 239        if (!host) {
 240                ret = -ENOMEM;
 241                goto out_release;
 242        }
 243
 244        priv(host)->base = ioremap(ecard_resource_start(ec, ECARD_RES_IOCSLOW),
 245                                   ecard_resource_len(ec, ECARD_RES_IOCSLOW));
 246        priv(host)->dma = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
 247                                  ecard_resource_len(ec, ECARD_RES_MEMC));
 248        if (!priv(host)->base || !priv(host)->dma) {
 249                ret = -ENOMEM;
 250                goto out_unmap;
 251        }
 252
 253        host->irq = ec->irq;
 254
 255        NCR5380_init(host, 0);
 256
 257        priv(host)->ctrl = 0;
 258        writeb(0, priv(host)->base + CTRL);
 259
 260        host->n_io_port = 255;
 261        if (!(request_region(host->io_port, host->n_io_port, "CumanaSCSI-1"))) {
 262                ret = -EBUSY;
 263                goto out_unmap;
 264        }
 265
 266        ret = request_irq(host->irq, cumanascsi_intr, IRQF_DISABLED,
 267                          "CumanaSCSI-1", host);
 268        if (ret) {
 269                printk("scsi%d: IRQ%d not free: %d\n",
 270                    host->host_no, host->irq, ret);
 271                goto out_unmap;
 272        }
 273
 274        printk("scsi%d: at port 0x%08lx irq %d",
 275                host->host_no, host->io_port, host->irq);
 276        printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
 277                host->can_queue, host->cmd_per_lun, CUMANASCSI_PUBLIC_RELEASE);
 278        printk("\nscsi%d:", host->host_no);
 279        NCR5380_print_options(host);
 280        printk("\n");
 281
 282        ret = scsi_add_host(host, &ec->dev);
 283        if (ret)
 284                goto out_free_irq;
 285
 286        scsi_scan_host(host);
 287        goto out;
 288
 289 out_free_irq:
 290        free_irq(host->irq, host);
 291 out_unmap:
 292        iounmap(priv(host)->base);
 293        iounmap(priv(host)->dma);
 294        scsi_host_put(host);
 295 out_release:
 296        ecard_release_resources(ec);
 297 out:
 298        return ret;
 299}
 300
 301static void __devexit cumanascsi1_remove(struct expansion_card *ec)
 302{
 303        struct Scsi_Host *host = ecard_get_drvdata(ec);
 304
 305        ecard_set_drvdata(ec, NULL);
 306
 307        scsi_remove_host(host);
 308        free_irq(host->irq, host);
 309        NCR5380_exit(host);
 310        iounmap(priv(host)->base);
 311        iounmap(priv(host)->dma);
 312        scsi_host_put(host);
 313        ecard_release_resources(ec);
 314}
 315
 316static const struct ecard_id cumanascsi1_cids[] = {
 317        { MANU_CUMANA, PROD_CUMANA_SCSI_1 },
 318        { 0xffff, 0xffff }
 319};
 320
 321static struct ecard_driver cumanascsi1_driver = {
 322        .probe          = cumanascsi1_probe,
 323        .remove         = __devexit_p(cumanascsi1_remove),
 324        .id_table       = cumanascsi1_cids,
 325        .drv = {
 326                .name           = "cumanascsi1",
 327        },
 328};
 329
 330static int __init cumanascsi_init(void)
 331{
 332        return ecard_register_driver(&cumanascsi1_driver);
 333}
 334
 335static void __exit cumanascsi_exit(void)
 336{
 337        ecard_remove_driver(&cumanascsi1_driver);
 338}
 339
 340module_init(cumanascsi_init);
 341module_exit(cumanascsi_exit);
 342
 343MODULE_DESCRIPTION("Cumana SCSI-1 driver for Acorn machines");
 344MODULE_LICENSE("GPL");
 345