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/ioport.h>
   8#include <linux/blkdev.h>
   9#include <linux/init.h>
  10
  11#include <asm/ecard.h>
  12#include <asm/io.h>
  13
  14#include <scsi/scsi_host.h>
  15
  16#define priv(host)                      ((struct NCR5380_hostdata *)(host)->hostdata)
  17#define NCR5380_read(reg)               cumanascsi_read(hostdata, reg)
  18#define NCR5380_write(reg, value)       cumanascsi_write(hostdata, reg, value)
  19
  20#define NCR5380_dma_xfer_len            cumanascsi_dma_xfer_len
  21#define NCR5380_dma_recv_setup          cumanascsi_pread
  22#define NCR5380_dma_send_setup          cumanascsi_pwrite
  23#define NCR5380_dma_residual            NCR5380_dma_residual_none
  24
  25#define NCR5380_intr                    cumanascsi_intr
  26#define NCR5380_queue_command           cumanascsi_queue_command
  27#define NCR5380_info                    cumanascsi_info
  28
  29#define NCR5380_implementation_fields   \
  30        unsigned ctrl
  31
  32struct NCR5380_hostdata;
  33static u8 cumanascsi_read(struct NCR5380_hostdata *, unsigned int);
  34static void cumanascsi_write(struct NCR5380_hostdata *, unsigned int, u8);
  35
  36#include "../NCR5380.h"
  37
  38#define CTRL    0x16fc
  39#define STAT    0x2004
  40#define L(v)    (((v)<<16)|((v) & 0x0000ffff))
  41#define H(v)    (((v)>>16)|((v) & 0xffff0000))
  42
  43static inline int cumanascsi_pwrite(struct NCR5380_hostdata *hostdata,
  44                                    unsigned char *addr, int len)
  45{
  46  unsigned long *laddr;
  47  u8 __iomem *base = hostdata->io;
  48  u8 __iomem *dma = hostdata->pdma_io + 0x2000;
  49
  50  if(!len) return 0;
  51
  52  writeb(0x02, base + CTRL);
  53  laddr = (unsigned long *)addr;
  54  while(len >= 32)
  55  {
  56    unsigned int status;
  57    unsigned long v;
  58    status = readb(base + STAT);
  59    if(status & 0x80)
  60      goto end;
  61    if(!(status & 0x40))
  62      continue;
  63    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
  64    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
  65    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
  66    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
  67    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
  68    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
  69    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
  70    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
  71    len -= 32;
  72    if(len == 0)
  73      break;
  74  }
  75
  76  addr = (unsigned char *)laddr;
  77  writeb(0x12, base + CTRL);
  78
  79  while(len > 0)
  80  {
  81    unsigned int status;
  82    status = readb(base + STAT);
  83    if(status & 0x80)
  84      goto end;
  85    if(status & 0x40)
  86    {
  87      writeb(*addr++, dma);
  88      if(--len == 0)
  89        break;
  90    }
  91
  92    status = readb(base + STAT);
  93    if(status & 0x80)
  94      goto end;
  95    if(status & 0x40)
  96    {
  97      writeb(*addr++, dma);
  98      if(--len == 0)
  99        break;
 100    }
 101  }
 102end:
 103  writeb(hostdata->ctrl | 0x40, base + CTRL);
 104
 105        if (len)
 106                return -1;
 107        return 0;
 108}
 109
 110static inline int cumanascsi_pread(struct NCR5380_hostdata *hostdata,
 111                                   unsigned char *addr, int len)
 112{
 113  unsigned long *laddr;
 114  u8 __iomem *base = hostdata->io;
 115  u8 __iomem *dma = hostdata->pdma_io + 0x2000;
 116
 117  if(!len) return 0;
 118
 119  writeb(0x00, base + CTRL);
 120  laddr = (unsigned long *)addr;
 121  while(len >= 32)
 122  {
 123    unsigned int status;
 124    status = readb(base + STAT);
 125    if(status & 0x80)
 126      goto end;
 127    if(!(status & 0x40))
 128      continue;
 129    *laddr++ = readw(dma) | (readw(dma) << 16);
 130    *laddr++ = readw(dma) | (readw(dma) << 16);
 131    *laddr++ = readw(dma) | (readw(dma) << 16);
 132    *laddr++ = readw(dma) | (readw(dma) << 16);
 133    *laddr++ = readw(dma) | (readw(dma) << 16);
 134    *laddr++ = readw(dma) | (readw(dma) << 16);
 135    *laddr++ = readw(dma) | (readw(dma) << 16);
 136    *laddr++ = readw(dma) | (readw(dma) << 16);
 137    len -= 32;
 138    if(len == 0)
 139      break;
 140  }
 141
 142  addr = (unsigned char *)laddr;
 143  writeb(0x10, base + CTRL);
 144
 145  while(len > 0)
 146  {
 147    unsigned int status;
 148    status = readb(base + STAT);
 149    if(status & 0x80)
 150      goto end;
 151    if(status & 0x40)
 152    {
 153      *addr++ = readb(dma);
 154      if(--len == 0)
 155        break;
 156    }
 157
 158    status = readb(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  }
 168end:
 169  writeb(hostdata->ctrl | 0x40, base + CTRL);
 170
 171        if (len)
 172                return -1;
 173        return 0;
 174}
 175
 176static int cumanascsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,
 177                                   struct scsi_cmnd *cmd)
 178{
 179        return cmd->transfersize;
 180}
 181
 182static u8 cumanascsi_read(struct NCR5380_hostdata *hostdata,
 183                          unsigned int reg)
 184{
 185        u8 __iomem *base = hostdata->io;
 186        u8 val;
 187
 188        writeb(0, base + CTRL);
 189
 190        val = readb(base + 0x2100 + (reg << 2));
 191
 192        hostdata->ctrl = 0x40;
 193        writeb(0x40, base + CTRL);
 194
 195        return val;
 196}
 197
 198static void cumanascsi_write(struct NCR5380_hostdata *hostdata,
 199                             unsigned int reg, u8 value)
 200{
 201        u8 __iomem *base = hostdata->io;
 202
 203        writeb(0, base + CTRL);
 204
 205        writeb(value, base + 0x2100 + (reg << 2));
 206
 207        hostdata->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_host_reset_handler  = NCR5380_host_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        .cmd_size               = NCR5380_CMD_SIZE,
 227        .max_sectors            = 128,
 228};
 229
 230static int cumanascsi1_probe(struct expansion_card *ec,
 231                             const struct ecard_id *id)
 232{
 233        struct Scsi_Host *host;
 234        int ret;
 235
 236        ret = ecard_request_resources(ec);
 237        if (ret)
 238                goto out;
 239
 240        host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata));
 241        if (!host) {
 242                ret = -ENOMEM;
 243                goto out_release;
 244        }
 245
 246        priv(host)->io = ioremap(ecard_resource_start(ec, ECARD_RES_IOCSLOW),
 247                                 ecard_resource_len(ec, ECARD_RES_IOCSLOW));
 248        priv(host)->pdma_io = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
 249                                      ecard_resource_len(ec, ECARD_RES_MEMC));
 250        if (!priv(host)->io || !priv(host)->pdma_io) {
 251                ret = -ENOMEM;
 252                goto out_unmap;
 253        }
 254
 255        host->irq = ec->irq;
 256
 257        ret = NCR5380_init(host, FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP);
 258        if (ret)
 259                goto out_unmap;
 260
 261        NCR5380_maybe_reset_bus(host);
 262
 263        priv(host)->ctrl = 0;
 264        writeb(0, priv(host)->io + CTRL);
 265
 266        ret = request_irq(host->irq, cumanascsi_intr, 0,
 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_exit;
 272        }
 273
 274        ret = scsi_add_host(host, &ec->dev);
 275        if (ret)
 276                goto out_free_irq;
 277
 278        scsi_scan_host(host);
 279        goto out;
 280
 281 out_free_irq:
 282        free_irq(host->irq, host);
 283 out_exit:
 284        NCR5380_exit(host);
 285 out_unmap:
 286        iounmap(priv(host)->io);
 287        iounmap(priv(host)->pdma_io);
 288        scsi_host_put(host);
 289 out_release:
 290        ecard_release_resources(ec);
 291 out:
 292        return ret;
 293}
 294
 295static void cumanascsi1_remove(struct expansion_card *ec)
 296{
 297        struct Scsi_Host *host = ecard_get_drvdata(ec);
 298        void __iomem *base = priv(host)->io;
 299        void __iomem *dma = priv(host)->pdma_io;
 300
 301        ecard_set_drvdata(ec, NULL);
 302
 303        scsi_remove_host(host);
 304        free_irq(host->irq, host);
 305        NCR5380_exit(host);
 306        scsi_host_put(host);
 307        iounmap(base);
 308        iounmap(dma);
 309        ecard_release_resources(ec);
 310}
 311
 312static const struct ecard_id cumanascsi1_cids[] = {
 313        { MANU_CUMANA, PROD_CUMANA_SCSI_1 },
 314        { 0xffff, 0xffff }
 315};
 316
 317static struct ecard_driver cumanascsi1_driver = {
 318        .probe          = cumanascsi1_probe,
 319        .remove         = cumanascsi1_remove,
 320        .id_table       = cumanascsi1_cids,
 321        .drv = {
 322                .name           = "cumanascsi1",
 323        },
 324};
 325
 326static int __init cumanascsi_init(void)
 327{
 328        return ecard_register_driver(&cumanascsi1_driver);
 329}
 330
 331static void __exit cumanascsi_exit(void)
 332{
 333        ecard_remove_driver(&cumanascsi1_driver);
 334}
 335
 336module_init(cumanascsi_init);
 337module_exit(cumanascsi_exit);
 338
 339MODULE_DESCRIPTION("Cumana SCSI-1 driver for Acorn machines");
 340MODULE_LICENSE("GPL");
 341