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