xref: /openbmc/linux/drivers/scsi/arm/oak.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
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