Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Oak Generic NCR5380 driver
0004  *
0005  * Copyright 1995-2002, Russell King
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/ioport.h>
0010 #include <linux/blkdev.h>
0011 #include <linux/init.h>
0012 
0013 #include <asm/ecard.h>
0014 #include <asm/io.h>
0015 
0016 #include <scsi/scsi_host.h>
0017 
0018 #define priv(host)          ((struct NCR5380_hostdata *)(host)->hostdata)
0019 
0020 #define NCR5380_read(reg)           readb(hostdata->io + ((reg) << 2))
0021 #define NCR5380_write(reg, value)   writeb(value, hostdata->io + ((reg) << 2))
0022 
0023 #define NCR5380_dma_xfer_len        NCR5380_dma_xfer_none
0024 #define NCR5380_dma_recv_setup      oakscsi_pread
0025 #define NCR5380_dma_send_setup      oakscsi_pwrite
0026 #define NCR5380_dma_residual        NCR5380_dma_residual_none
0027 
0028 #define NCR5380_queue_command       oakscsi_queue_command
0029 #define NCR5380_info            oakscsi_info
0030 
0031 #define NCR5380_implementation_fields   /* none */
0032 
0033 #include "../NCR5380.h"
0034 
0035 #undef START_DMA_INITIATOR_RECEIVE_REG
0036 #define START_DMA_INITIATOR_RECEIVE_REG (128 + 7)
0037 
0038 #define STAT    ((128 + 16) << 2)
0039 #define DATA    ((128 + 8) << 2)
0040 
0041 static inline int oakscsi_pwrite(struct NCR5380_hostdata *hostdata,
0042                                  unsigned char *addr, int len)
0043 {
0044   u8 __iomem *base = hostdata->io;
0045 
0046 printk("writing %p len %d\n",addr, len);
0047 
0048   while(1)
0049   {
0050     int status;
0051     while (((status = readw(base + STAT)) & 0x100)==0);
0052   }
0053   return 0;
0054 }
0055 
0056 static inline int oakscsi_pread(struct NCR5380_hostdata *hostdata,
0057                                 unsigned char *addr, int len)
0058 {
0059   u8 __iomem *base = hostdata->io;
0060 
0061 printk("reading %p len %d\n", addr, len);
0062   while(len > 0)
0063   {
0064     unsigned int status, timeout;
0065     unsigned long b;
0066     
0067     timeout = 0x01FFFFFF;
0068     
0069     while (((status = readw(base + STAT)) & 0x100)==0)
0070     {
0071       timeout--;
0072       if(status & 0x200 || !timeout)
0073       {
0074         printk("status = %08X\n", status);
0075         return -1;
0076       }
0077     }
0078 
0079     if(len >= 128)
0080     {
0081       readsw(base + DATA, addr, 128);
0082       addr += 128;
0083       len -= 128;
0084     }
0085     else
0086     {
0087       b = (unsigned long) readw(base + DATA);
0088       *addr ++ = b;
0089       len -= 1;
0090       if(len)
0091         *addr ++ = b>>8;
0092       len -= 1;
0093     }
0094   }
0095   return 0;
0096 }
0097 
0098 #undef STAT
0099 #undef DATA
0100 
0101 #include "../NCR5380.c"
0102 
0103 static struct scsi_host_template oakscsi_template = {
0104     .module         = THIS_MODULE,
0105     .name           = "Oak 16-bit SCSI",
0106     .info           = oakscsi_info,
0107     .queuecommand       = oakscsi_queue_command,
0108     .eh_abort_handler   = NCR5380_abort,
0109     .eh_host_reset_handler  = NCR5380_host_reset,
0110     .can_queue      = 16,
0111     .this_id        = 7,
0112     .sg_tablesize       = SG_ALL,
0113     .cmd_per_lun        = 2,
0114     .dma_boundary       = PAGE_SIZE - 1,
0115     .proc_name      = "oakscsi",
0116     .cmd_size       = sizeof(struct NCR5380_cmd),
0117     .max_sectors        = 128,
0118 };
0119 
0120 static int oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
0121 {
0122     struct Scsi_Host *host;
0123     int ret;
0124 
0125     ret = ecard_request_resources(ec);
0126     if (ret)
0127         goto out;
0128 
0129     host = scsi_host_alloc(&oakscsi_template, sizeof(struct NCR5380_hostdata));
0130     if (!host) {
0131         ret = -ENOMEM;
0132         goto release;
0133     }
0134 
0135     priv(host)->io = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
0136                              ecard_resource_len(ec, ECARD_RES_MEMC));
0137     if (!priv(host)->io) {
0138         ret = -ENOMEM;
0139         goto unreg;
0140     }
0141 
0142     host->irq = NO_IRQ;
0143 
0144     ret = NCR5380_init(host, FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP);
0145     if (ret)
0146         goto out_unmap;
0147 
0148     NCR5380_maybe_reset_bus(host);
0149 
0150     ret = scsi_add_host(host, &ec->dev);
0151     if (ret)
0152         goto out_exit;
0153 
0154     scsi_scan_host(host);
0155     goto out;
0156 
0157  out_exit:
0158     NCR5380_exit(host);
0159  out_unmap:
0160     iounmap(priv(host)->io);
0161  unreg:
0162     scsi_host_put(host);
0163  release:
0164     ecard_release_resources(ec);
0165  out:
0166     return ret;
0167 }
0168 
0169 static void oakscsi_remove(struct expansion_card *ec)
0170 {
0171     struct Scsi_Host *host = ecard_get_drvdata(ec);
0172     void __iomem *base = priv(host)->io;
0173 
0174     ecard_set_drvdata(ec, NULL);
0175     scsi_remove_host(host);
0176 
0177     NCR5380_exit(host);
0178     scsi_host_put(host);
0179     iounmap(base);
0180     ecard_release_resources(ec);
0181 }
0182 
0183 static const struct ecard_id oakscsi_cids[] = {
0184     { MANU_OAK, PROD_OAK_SCSI },
0185     { 0xffff, 0xffff }
0186 };
0187 
0188 static struct ecard_driver oakscsi_driver = {
0189     .probe      = oakscsi_probe,
0190     .remove     = oakscsi_remove,
0191     .id_table   = oakscsi_cids,
0192     .drv = {
0193         .name       = "oakscsi",
0194     },
0195 };
0196 
0197 static int __init oakscsi_init(void)
0198 {
0199     return ecard_register_driver(&oakscsi_driver);
0200 }
0201 
0202 static void __exit oakscsi_exit(void)
0203 {
0204     ecard_remove_driver(&oakscsi_driver);
0205 }
0206 
0207 module_init(oakscsi_init);
0208 module_exit(oakscsi_exit);
0209 
0210 MODULE_AUTHOR("Russell King");
0211 MODULE_DESCRIPTION("Oak SCSI driver");
0212 MODULE_LICENSE("GPL");
0213