109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Oak Generic NCR5380 driver
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Copyright 1995-2002, Russell King
61da177e4SLinus Torvalds */
71da177e4SLinus Torvalds
81da177e4SLinus Torvalds #include <linux/module.h>
91da177e4SLinus Torvalds #include <linux/ioport.h>
101da177e4SLinus Torvalds #include <linux/blkdev.h>
111da177e4SLinus Torvalds #include <linux/init.h>
121da177e4SLinus Torvalds
131da177e4SLinus Torvalds #include <asm/ecard.h>
141da177e4SLinus Torvalds #include <asm/io.h>
151da177e4SLinus Torvalds
161da177e4SLinus Torvalds #include <scsi/scsi_host.h>
171da177e4SLinus Torvalds
188b801eadSRussell King #define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
198b801eadSRussell King
2061e1ce58SFinn Thain #define NCR5380_read(reg) readb(hostdata->io + ((reg) << 2))
2161e1ce58SFinn Thain #define NCR5380_write(reg, value) writeb(value, hostdata->io + ((reg) << 2))
2254d8fe44SFinn Thain
234a98f896SFinn Thain #define NCR5380_dma_xfer_len NCR5380_dma_xfer_none
246c4b88caSFinn Thain #define NCR5380_dma_recv_setup oakscsi_pread
256c4b88caSFinn Thain #define NCR5380_dma_send_setup oakscsi_pwrite
264a98f896SFinn Thain #define NCR5380_dma_residual NCR5380_dma_residual_none
27ff3d4578SFinn Thain
281da177e4SLinus Torvalds #define NCR5380_queue_command oakscsi_queue_command
298c32513bSFinn Thain #define NCR5380_info oakscsi_info
301da177e4SLinus Torvalds
31820682b1SFinn Thain #define NCR5380_implementation_fields /* none */
321da177e4SLinus Torvalds
331da177e4SLinus Torvalds #include "../NCR5380.h"
341da177e4SLinus Torvalds
351da177e4SLinus Torvalds #undef START_DMA_INITIATOR_RECEIVE_REG
368b801eadSRussell King #define START_DMA_INITIATOR_RECEIVE_REG (128 + 7)
371da177e4SLinus Torvalds
388b801eadSRussell King #define STAT ((128 + 16) << 2)
398b801eadSRussell King #define DATA ((128 + 8) << 2)
401da177e4SLinus Torvalds
oakscsi_pwrite(struct NCR5380_hostdata * hostdata,unsigned char * addr,int len)414a98f896SFinn Thain static inline int oakscsi_pwrite(struct NCR5380_hostdata *hostdata,
426c4b88caSFinn Thain unsigned char *addr, int len)
431da177e4SLinus Torvalds {
444a98f896SFinn Thain u8 __iomem *base = hostdata->io;
458b801eadSRussell King
461da177e4SLinus Torvalds printk("writing %p len %d\n",addr, len);
471da177e4SLinus Torvalds
481da177e4SLinus Torvalds while(1)
491da177e4SLinus Torvalds {
501da177e4SLinus Torvalds int status;
518b801eadSRussell King while (((status = readw(base + STAT)) & 0x100)==0);
521da177e4SLinus Torvalds }
53438af51cSFinn Thain return 0;
541da177e4SLinus Torvalds }
551da177e4SLinus Torvalds
oakscsi_pread(struct NCR5380_hostdata * hostdata,unsigned char * addr,int len)564a98f896SFinn Thain static inline int oakscsi_pread(struct NCR5380_hostdata *hostdata,
576c4b88caSFinn Thain unsigned char *addr, int len)
581da177e4SLinus Torvalds {
594a98f896SFinn Thain u8 __iomem *base = hostdata->io;
604a98f896SFinn Thain
611da177e4SLinus Torvalds printk("reading %p len %d\n", addr, len);
621da177e4SLinus Torvalds while(len > 0)
631da177e4SLinus Torvalds {
648b801eadSRussell King unsigned int status, timeout;
651da177e4SLinus Torvalds unsigned long b;
661da177e4SLinus Torvalds
671da177e4SLinus Torvalds timeout = 0x01FFFFFF;
681da177e4SLinus Torvalds
698b801eadSRussell King while (((status = readw(base + STAT)) & 0x100)==0)
701da177e4SLinus Torvalds {
711da177e4SLinus Torvalds timeout--;
721da177e4SLinus Torvalds if(status & 0x200 || !timeout)
731da177e4SLinus Torvalds {
741da177e4SLinus Torvalds printk("status = %08X\n", status);
75438af51cSFinn Thain return -1;
761da177e4SLinus Torvalds }
771da177e4SLinus Torvalds }
788b801eadSRussell King
791da177e4SLinus Torvalds if(len >= 128)
801da177e4SLinus Torvalds {
818b801eadSRussell King readsw(base + DATA, addr, 128);
821da177e4SLinus Torvalds addr += 128;
831da177e4SLinus Torvalds len -= 128;
841da177e4SLinus Torvalds }
851da177e4SLinus Torvalds else
861da177e4SLinus Torvalds {
878b801eadSRussell King b = (unsigned long) readw(base + DATA);
881da177e4SLinus Torvalds *addr ++ = b;
891da177e4SLinus Torvalds len -= 1;
901da177e4SLinus Torvalds if(len)
911da177e4SLinus Torvalds *addr ++ = b>>8;
921da177e4SLinus Torvalds len -= 1;
931da177e4SLinus Torvalds }
941da177e4SLinus Torvalds }
951da177e4SLinus Torvalds return 0;
961da177e4SLinus Torvalds }
971da177e4SLinus Torvalds
981da177e4SLinus Torvalds #undef STAT
998b801eadSRussell King #undef DATA
1001da177e4SLinus Torvalds
1011da177e4SLinus Torvalds #include "../NCR5380.c"
1021da177e4SLinus Torvalds
103*644d8d77SBart Van Assche static const struct scsi_host_template oakscsi_template = {
1041da177e4SLinus Torvalds .module = THIS_MODULE,
1051da177e4SLinus Torvalds .name = "Oak 16-bit SCSI",
1061da177e4SLinus Torvalds .info = oakscsi_info,
1071da177e4SLinus Torvalds .queuecommand = oakscsi_queue_command,
1081da177e4SLinus Torvalds .eh_abort_handler = NCR5380_abort,
10912e5fc66SHannes Reinecke .eh_host_reset_handler = NCR5380_host_reset,
1101da177e4SLinus Torvalds .can_queue = 16,
1111da177e4SLinus Torvalds .this_id = 7,
1121da177e4SLinus Torvalds .sg_tablesize = SG_ALL,
1131da177e4SLinus Torvalds .cmd_per_lun = 2,
1144af14d11SChristoph Hellwig .dma_boundary = PAGE_SIZE - 1,
1151da177e4SLinus Torvalds .proc_name = "oakscsi",
116cd614642SBart Van Assche .cmd_size = sizeof(struct NCR5380_cmd),
1170a4e3612SFinn Thain .max_sectors = 128,
1181da177e4SLinus Torvalds };
1191da177e4SLinus Torvalds
oakscsi_probe(struct expansion_card * ec,const struct ecard_id * id)1206f039790SGreg Kroah-Hartman static int oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
1211da177e4SLinus Torvalds {
1221da177e4SLinus Torvalds struct Scsi_Host *host;
123713a8468SJing Xiangfeng int ret;
1241da177e4SLinus Torvalds
1258b801eadSRussell King ret = ecard_request_resources(ec);
1268b801eadSRussell King if (ret)
1271da177e4SLinus Torvalds goto out;
1281da177e4SLinus Torvalds
1298b801eadSRussell King host = scsi_host_alloc(&oakscsi_template, sizeof(struct NCR5380_hostdata));
1308b801eadSRussell King if (!host) {
1318b801eadSRussell King ret = -ENOMEM;
1328b801eadSRussell King goto release;
1338b801eadSRussell King }
1348b801eadSRussell King
135820682b1SFinn Thain priv(host)->io = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
1368b801eadSRussell King ecard_resource_len(ec, ECARD_RES_MEMC));
137820682b1SFinn Thain if (!priv(host)->io) {
1388b801eadSRussell King ret = -ENOMEM;
1398b801eadSRussell King goto unreg;
1408b801eadSRussell King }
1418b801eadSRussell King
14222f5f10dSFinn Thain host->irq = NO_IRQ;
1431da177e4SLinus Torvalds
1448053b0eeSFinn Thain ret = NCR5380_init(host, FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP);
1450ad0eff9SFinn Thain if (ret)
1460ad0eff9SFinn Thain goto out_unmap;
1471da177e4SLinus Torvalds
148b6488f97SFinn Thain NCR5380_maybe_reset_bus(host);
149b6488f97SFinn Thain
1501da177e4SLinus Torvalds ret = scsi_add_host(host, &ec->dev);
1511da177e4SLinus Torvalds if (ret)
1520ad0eff9SFinn Thain goto out_exit;
1531da177e4SLinus Torvalds
1541da177e4SLinus Torvalds scsi_scan_host(host);
1551da177e4SLinus Torvalds goto out;
1561da177e4SLinus Torvalds
1570ad0eff9SFinn Thain out_exit:
1580ad0eff9SFinn Thain NCR5380_exit(host);
1598b801eadSRussell King out_unmap:
160820682b1SFinn Thain iounmap(priv(host)->io);
1611da177e4SLinus Torvalds unreg:
1621da177e4SLinus Torvalds scsi_host_put(host);
1638b801eadSRussell King release:
1648b801eadSRussell King ecard_release_resources(ec);
1651da177e4SLinus Torvalds out:
1661da177e4SLinus Torvalds return ret;
1671da177e4SLinus Torvalds }
1681da177e4SLinus Torvalds
oakscsi_remove(struct expansion_card * ec)1696f039790SGreg Kroah-Hartman static void oakscsi_remove(struct expansion_card *ec)
1701da177e4SLinus Torvalds {
1711da177e4SLinus Torvalds struct Scsi_Host *host = ecard_get_drvdata(ec);
172820682b1SFinn Thain void __iomem *base = priv(host)->io;
1731da177e4SLinus Torvalds
1741da177e4SLinus Torvalds ecard_set_drvdata(ec, NULL);
1751da177e4SLinus Torvalds scsi_remove_host(host);
1761da177e4SLinus Torvalds
1771da177e4SLinus Torvalds NCR5380_exit(host);
1781da177e4SLinus Torvalds scsi_host_put(host);
179820682b1SFinn Thain iounmap(base);
1808b801eadSRussell King ecard_release_resources(ec);
1811da177e4SLinus Torvalds }
1821da177e4SLinus Torvalds
1831da177e4SLinus Torvalds static const struct ecard_id oakscsi_cids[] = {
1841da177e4SLinus Torvalds { MANU_OAK, PROD_OAK_SCSI },
1851da177e4SLinus Torvalds { 0xffff, 0xffff }
1861da177e4SLinus Torvalds };
1871da177e4SLinus Torvalds
1881da177e4SLinus Torvalds static struct ecard_driver oakscsi_driver = {
1891da177e4SLinus Torvalds .probe = oakscsi_probe,
1906f039790SGreg Kroah-Hartman .remove = oakscsi_remove,
1911da177e4SLinus Torvalds .id_table = oakscsi_cids,
1921da177e4SLinus Torvalds .drv = {
1931da177e4SLinus Torvalds .name = "oakscsi",
1941da177e4SLinus Torvalds },
1951da177e4SLinus Torvalds };
1961da177e4SLinus Torvalds
oakscsi_init(void)1971da177e4SLinus Torvalds static int __init oakscsi_init(void)
1981da177e4SLinus Torvalds {
1991da177e4SLinus Torvalds return ecard_register_driver(&oakscsi_driver);
2001da177e4SLinus Torvalds }
2011da177e4SLinus Torvalds
oakscsi_exit(void)2021da177e4SLinus Torvalds static void __exit oakscsi_exit(void)
2031da177e4SLinus Torvalds {
2041da177e4SLinus Torvalds ecard_remove_driver(&oakscsi_driver);
2051da177e4SLinus Torvalds }
2061da177e4SLinus Torvalds
2071da177e4SLinus Torvalds module_init(oakscsi_init);
2081da177e4SLinus Torvalds module_exit(oakscsi_exit);
2091da177e4SLinus Torvalds
2101da177e4SLinus Torvalds MODULE_AUTHOR("Russell King");
2111da177e4SLinus Torvalds MODULE_DESCRIPTION("Oak SCSI driver");
2121da177e4SLinus Torvalds MODULE_LICENSE("GPL");
2131da177e4SLinus Torvalds
214