Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Generic Generic NCR5380 driver
0004  *
0005  * Copyright 1995-2002, Russell King
0006  */
0007 #include <linux/module.h>
0008 #include <linux/ioport.h>
0009 #include <linux/blkdev.h>
0010 #include <linux/init.h>
0011 
0012 #include <asm/ecard.h>
0013 #include <asm/io.h>
0014 
0015 #include <scsi/scsi_host.h>
0016 
0017 #define priv(host)          ((struct NCR5380_hostdata *)(host)->hostdata)
0018 #define NCR5380_read(reg)       cumanascsi_read(hostdata, reg)
0019 #define NCR5380_write(reg, value)   cumanascsi_write(hostdata, reg, value)
0020 
0021 #define NCR5380_dma_xfer_len        cumanascsi_dma_xfer_len
0022 #define NCR5380_dma_recv_setup      cumanascsi_pread
0023 #define NCR5380_dma_send_setup      cumanascsi_pwrite
0024 #define NCR5380_dma_residual        NCR5380_dma_residual_none
0025 
0026 #define NCR5380_intr            cumanascsi_intr
0027 #define NCR5380_queue_command       cumanascsi_queue_command
0028 #define NCR5380_info            cumanascsi_info
0029 
0030 #define NCR5380_implementation_fields   \
0031     unsigned ctrl
0032 
0033 struct NCR5380_hostdata;
0034 static u8 cumanascsi_read(struct NCR5380_hostdata *, unsigned int);
0035 static void cumanascsi_write(struct NCR5380_hostdata *, unsigned int, u8);
0036 
0037 #include "../NCR5380.h"
0038 
0039 #define CTRL    0x16fc
0040 #define STAT    0x2004
0041 #define L(v)    (((v)<<16)|((v) & 0x0000ffff))
0042 #define H(v)    (((v)>>16)|((v) & 0xffff0000))
0043 
0044 static inline int cumanascsi_pwrite(struct NCR5380_hostdata *hostdata,
0045                                     unsigned char *addr, int len)
0046 {
0047   unsigned long *laddr;
0048   u8 __iomem *base = hostdata->io;
0049   u8 __iomem *dma = hostdata->pdma_io + 0x2000;
0050 
0051   if(!len) return 0;
0052 
0053   writeb(0x02, base + CTRL);
0054   laddr = (unsigned long *)addr;
0055   while(len >= 32)
0056   {
0057     unsigned int status;
0058     unsigned long v;
0059     status = readb(base + STAT);
0060     if(status & 0x80)
0061       goto end;
0062     if(!(status & 0x40))
0063       continue;
0064     v=*laddr++; writew(L(v), dma); writew(H(v), dma);
0065     v=*laddr++; writew(L(v), dma); writew(H(v), dma);
0066     v=*laddr++; writew(L(v), dma); writew(H(v), dma);
0067     v=*laddr++; writew(L(v), dma); writew(H(v), dma);
0068     v=*laddr++; writew(L(v), dma); writew(H(v), dma);
0069     v=*laddr++; writew(L(v), dma); writew(H(v), dma);
0070     v=*laddr++; writew(L(v), dma); writew(H(v), dma);
0071     v=*laddr++; writew(L(v), dma); writew(H(v), dma);
0072     len -= 32;
0073     if(len == 0)
0074       break;
0075   }
0076 
0077   addr = (unsigned char *)laddr;
0078   writeb(0x12, base + CTRL);
0079 
0080   while(len > 0)
0081   {
0082     unsigned int status;
0083     status = readb(base + STAT);
0084     if(status & 0x80)
0085       goto end;
0086     if(status & 0x40)
0087     {
0088       writeb(*addr++, dma);
0089       if(--len == 0)
0090         break;
0091     }
0092 
0093     status = readb(base + STAT);
0094     if(status & 0x80)
0095       goto end;
0096     if(status & 0x40)
0097     {
0098       writeb(*addr++, dma);
0099       if(--len == 0)
0100         break;
0101     }
0102   }
0103 end:
0104   writeb(hostdata->ctrl | 0x40, base + CTRL);
0105 
0106     if (len)
0107         return -1;
0108     return 0;
0109 }
0110 
0111 static inline int cumanascsi_pread(struct NCR5380_hostdata *hostdata,
0112                                    unsigned char *addr, int len)
0113 {
0114   unsigned long *laddr;
0115   u8 __iomem *base = hostdata->io;
0116   u8 __iomem *dma = hostdata->pdma_io + 0x2000;
0117 
0118   if(!len) return 0;
0119 
0120   writeb(0x00, base + CTRL);
0121   laddr = (unsigned long *)addr;
0122   while(len >= 32)
0123   {
0124     unsigned int status;
0125     status = readb(base + STAT);
0126     if(status & 0x80)
0127       goto end;
0128     if(!(status & 0x40))
0129       continue;
0130     *laddr++ = readw(dma) | (readw(dma) << 16);
0131     *laddr++ = readw(dma) | (readw(dma) << 16);
0132     *laddr++ = readw(dma) | (readw(dma) << 16);
0133     *laddr++ = readw(dma) | (readw(dma) << 16);
0134     *laddr++ = readw(dma) | (readw(dma) << 16);
0135     *laddr++ = readw(dma) | (readw(dma) << 16);
0136     *laddr++ = readw(dma) | (readw(dma) << 16);
0137     *laddr++ = readw(dma) | (readw(dma) << 16);
0138     len -= 32;
0139     if(len == 0)
0140       break;
0141   }
0142 
0143   addr = (unsigned char *)laddr;
0144   writeb(0x10, base + CTRL);
0145 
0146   while(len > 0)
0147   {
0148     unsigned int status;
0149     status = readb(base + STAT);
0150     if(status & 0x80)
0151       goto end;
0152     if(status & 0x40)
0153     {
0154       *addr++ = readb(dma);
0155       if(--len == 0)
0156         break;
0157     }
0158 
0159     status = readb(base + STAT);
0160     if(status & 0x80)
0161       goto end;
0162     if(status & 0x40)
0163     {
0164       *addr++ = readb(dma);
0165       if(--len == 0)
0166         break;
0167     }
0168   }
0169 end:
0170   writeb(hostdata->ctrl | 0x40, base + CTRL);
0171 
0172     if (len)
0173         return -1;
0174     return 0;
0175 }
0176 
0177 static int cumanascsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,
0178                                    struct scsi_cmnd *cmd)
0179 {
0180     return cmd->transfersize;
0181 }
0182 
0183 static u8 cumanascsi_read(struct NCR5380_hostdata *hostdata,
0184                           unsigned int reg)
0185 {
0186     u8 __iomem *base = hostdata->io;
0187     u8 val;
0188 
0189     writeb(0, base + CTRL);
0190 
0191     val = readb(base + 0x2100 + (reg << 2));
0192 
0193     hostdata->ctrl = 0x40;
0194     writeb(0x40, base + CTRL);
0195 
0196     return val;
0197 }
0198 
0199 static void cumanascsi_write(struct NCR5380_hostdata *hostdata,
0200                              unsigned int reg, u8 value)
0201 {
0202     u8 __iomem *base = hostdata->io;
0203 
0204     writeb(0, base + CTRL);
0205 
0206     writeb(value, base + 0x2100 + (reg << 2));
0207 
0208     hostdata->ctrl = 0x40;
0209     writeb(0x40, base + CTRL);
0210 }
0211 
0212 #include "../NCR5380.c"
0213 
0214 static struct scsi_host_template cumanascsi_template = {
0215     .module         = THIS_MODULE,
0216     .name           = "Cumana 16-bit SCSI",
0217     .info           = cumanascsi_info,
0218     .queuecommand       = cumanascsi_queue_command,
0219     .eh_abort_handler   = NCR5380_abort,
0220     .eh_host_reset_handler  = NCR5380_host_reset,
0221     .can_queue      = 16,
0222     .this_id        = 7,
0223     .sg_tablesize       = SG_ALL,
0224     .cmd_per_lun        = 2,
0225     .proc_name      = "CumanaSCSI-1",
0226     .cmd_size       = sizeof(struct NCR5380_cmd),
0227     .max_sectors        = 128,
0228     .dma_boundary       = PAGE_SIZE - 1,
0229 };
0230 
0231 static int cumanascsi1_probe(struct expansion_card *ec,
0232                  const struct ecard_id *id)
0233 {
0234     struct Scsi_Host *host;
0235     int ret;
0236 
0237     ret = ecard_request_resources(ec);
0238     if (ret)
0239         goto out;
0240 
0241     host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata));
0242     if (!host) {
0243         ret = -ENOMEM;
0244         goto out_release;
0245     }
0246 
0247     priv(host)->io = ioremap(ecard_resource_start(ec, ECARD_RES_IOCSLOW),
0248                              ecard_resource_len(ec, ECARD_RES_IOCSLOW));
0249     priv(host)->pdma_io = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
0250                                   ecard_resource_len(ec, ECARD_RES_MEMC));
0251     if (!priv(host)->io || !priv(host)->pdma_io) {
0252         ret = -ENOMEM;
0253         goto out_unmap;
0254     }
0255 
0256     host->irq = ec->irq;
0257 
0258     ret = NCR5380_init(host, FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP);
0259     if (ret)
0260         goto out_unmap;
0261 
0262     NCR5380_maybe_reset_bus(host);
0263 
0264         priv(host)->ctrl = 0;
0265         writeb(0, priv(host)->io + CTRL);
0266 
0267     ret = request_irq(host->irq, cumanascsi_intr, 0,
0268               "CumanaSCSI-1", host);
0269     if (ret) {
0270         printk("scsi%d: IRQ%d not free: %d\n",
0271             host->host_no, host->irq, ret);
0272         goto out_exit;
0273     }
0274 
0275     ret = scsi_add_host(host, &ec->dev);
0276     if (ret)
0277         goto out_free_irq;
0278 
0279     scsi_scan_host(host);
0280     goto out;
0281 
0282  out_free_irq:
0283     free_irq(host->irq, host);
0284  out_exit:
0285     NCR5380_exit(host);
0286  out_unmap:
0287     iounmap(priv(host)->io);
0288     iounmap(priv(host)->pdma_io);
0289     scsi_host_put(host);
0290  out_release:
0291     ecard_release_resources(ec);
0292  out:
0293     return ret;
0294 }
0295 
0296 static void cumanascsi1_remove(struct expansion_card *ec)
0297 {
0298     struct Scsi_Host *host = ecard_get_drvdata(ec);
0299     void __iomem *base = priv(host)->io;
0300     void __iomem *dma = priv(host)->pdma_io;
0301 
0302     ecard_set_drvdata(ec, NULL);
0303 
0304     scsi_remove_host(host);
0305     free_irq(host->irq, host);
0306     NCR5380_exit(host);
0307     scsi_host_put(host);
0308     iounmap(base);
0309     iounmap(dma);
0310     ecard_release_resources(ec);
0311 }
0312 
0313 static const struct ecard_id cumanascsi1_cids[] = {
0314     { MANU_CUMANA, PROD_CUMANA_SCSI_1 },
0315     { 0xffff, 0xffff }
0316 };
0317 
0318 static struct ecard_driver cumanascsi1_driver = {
0319     .probe      = cumanascsi1_probe,
0320     .remove     = cumanascsi1_remove,
0321     .id_table   = cumanascsi1_cids,
0322     .drv = {
0323         .name       = "cumanascsi1",
0324     },
0325 };
0326 
0327 static int __init cumanascsi_init(void)
0328 {
0329     return ecard_register_driver(&cumanascsi1_driver);
0330 }
0331 
0332 static void __exit cumanascsi_exit(void)
0333 {
0334     ecard_remove_driver(&cumanascsi1_driver);
0335 }
0336 
0337 module_init(cumanascsi_init);
0338 module_exit(cumanascsi_exit);
0339 
0340 MODULE_DESCRIPTION("Cumana SCSI-1 driver for Acorn machines");
0341 MODULE_LICENSE("GPL");