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