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