xref: /openbmc/linux/drivers/scsi/arm/cumana_1.c (revision 202423c5)
109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * Generic Generic NCR5380 driver
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Copyright 1995-2002, Russell King
61da177e4SLinus Torvalds  */
71da177e4SLinus Torvalds #include <linux/module.h>
81da177e4SLinus Torvalds #include <linux/ioport.h>
91da177e4SLinus Torvalds #include <linux/blkdev.h>
101da177e4SLinus Torvalds #include <linux/init.h>
111da177e4SLinus Torvalds 
121da177e4SLinus Torvalds #include <asm/ecard.h>
131da177e4SLinus Torvalds #include <asm/io.h>
141da177e4SLinus Torvalds 
151da177e4SLinus Torvalds #include <scsi/scsi_host.h>
161da177e4SLinus Torvalds 
178b801eadSRussell King #define priv(host)			((struct NCR5380_hostdata *)(host)->hostdata)
1861e1ce58SFinn Thain #define NCR5380_read(reg)		cumanascsi_read(hostdata, reg)
1961e1ce58SFinn Thain #define NCR5380_write(reg, value)	cumanascsi_write(hostdata, reg, value)
20ff3d4578SFinn Thain 
214a98f896SFinn Thain #define NCR5380_dma_xfer_len		cumanascsi_dma_xfer_len
226c4b88caSFinn Thain #define NCR5380_dma_recv_setup		cumanascsi_pread
236c4b88caSFinn Thain #define NCR5380_dma_send_setup		cumanascsi_pwrite
244a98f896SFinn Thain #define NCR5380_dma_residual		NCR5380_dma_residual_none
25ff3d4578SFinn Thain 
261da177e4SLinus Torvalds #define NCR5380_intr			cumanascsi_intr
271da177e4SLinus Torvalds #define NCR5380_queue_command		cumanascsi_queue_command
288c32513bSFinn Thain #define NCR5380_info			cumanascsi_info
291da177e4SLinus Torvalds 
308b801eadSRussell King #define NCR5380_implementation_fields	\
31820682b1SFinn Thain 	unsigned ctrl
328b801eadSRussell King 
337c606631SFinn Thain struct NCR5380_hostdata;
347c606631SFinn Thain static u8 cumanascsi_read(struct NCR5380_hostdata *, unsigned int);
357c606631SFinn Thain static void cumanascsi_write(struct NCR5380_hostdata *, unsigned int, u8);
367c606631SFinn Thain 
371da177e4SLinus Torvalds #include "../NCR5380.h"
381da177e4SLinus Torvalds 
398b801eadSRussell King #define CTRL	0x16fc
408b801eadSRussell King #define STAT	0x2004
411da177e4SLinus Torvalds #define L(v)	(((v)<<16)|((v) & 0x0000ffff))
421da177e4SLinus Torvalds #define H(v)	(((v)>>16)|((v) & 0xffff0000))
431da177e4SLinus Torvalds 
cumanascsi_pwrite(struct NCR5380_hostdata * hostdata,unsigned char * addr,int len)444a98f896SFinn Thain static inline int cumanascsi_pwrite(struct NCR5380_hostdata *hostdata,
456c4b88caSFinn Thain                                     unsigned char *addr, int len)
461da177e4SLinus Torvalds {
471da177e4SLinus Torvalds   unsigned long *laddr;
484a98f896SFinn Thain   u8 __iomem *base = hostdata->io;
494a98f896SFinn Thain   u8 __iomem *dma = hostdata->pdma_io + 0x2000;
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds   if(!len) return 0;
521da177e4SLinus Torvalds 
53820682b1SFinn Thain   writeb(0x02, base + CTRL);
541da177e4SLinus Torvalds   laddr = (unsigned long *)addr;
551da177e4SLinus Torvalds   while(len >= 32)
561da177e4SLinus Torvalds   {
578b801eadSRussell King     unsigned int status;
581da177e4SLinus Torvalds     unsigned long v;
59820682b1SFinn Thain     status = readb(base + STAT);
601da177e4SLinus Torvalds     if(status & 0x80)
611da177e4SLinus Torvalds       goto end;
621da177e4SLinus Torvalds     if(!(status & 0x40))
631da177e4SLinus Torvalds       continue;
648b801eadSRussell King     v=*laddr++; writew(L(v), dma); writew(H(v), dma);
658b801eadSRussell King     v=*laddr++; writew(L(v), dma); writew(H(v), dma);
668b801eadSRussell King     v=*laddr++; writew(L(v), dma); writew(H(v), dma);
678b801eadSRussell King     v=*laddr++; writew(L(v), dma); writew(H(v), dma);
688b801eadSRussell King     v=*laddr++; writew(L(v), dma); writew(H(v), dma);
698b801eadSRussell King     v=*laddr++; writew(L(v), dma); writew(H(v), dma);
708b801eadSRussell King     v=*laddr++; writew(L(v), dma); writew(H(v), dma);
718b801eadSRussell King     v=*laddr++; writew(L(v), dma); writew(H(v), dma);
721da177e4SLinus Torvalds     len -= 32;
731da177e4SLinus Torvalds     if(len == 0)
741da177e4SLinus Torvalds       break;
751da177e4SLinus Torvalds   }
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds   addr = (unsigned char *)laddr;
78820682b1SFinn Thain   writeb(0x12, base + CTRL);
798b801eadSRussell King 
801da177e4SLinus Torvalds   while(len > 0)
811da177e4SLinus Torvalds   {
828b801eadSRussell King     unsigned int status;
83820682b1SFinn Thain     status = readb(base + STAT);
841da177e4SLinus Torvalds     if(status & 0x80)
851da177e4SLinus Torvalds       goto end;
861da177e4SLinus Torvalds     if(status & 0x40)
871da177e4SLinus Torvalds     {
888b801eadSRussell King       writeb(*addr++, dma);
891da177e4SLinus Torvalds       if(--len == 0)
901da177e4SLinus Torvalds         break;
911da177e4SLinus Torvalds     }
921da177e4SLinus Torvalds 
93820682b1SFinn Thain     status = readb(base + STAT);
941da177e4SLinus Torvalds     if(status & 0x80)
951da177e4SLinus Torvalds       goto end;
961da177e4SLinus Torvalds     if(status & 0x40)
971da177e4SLinus Torvalds     {
988b801eadSRussell King       writeb(*addr++, dma);
991da177e4SLinus Torvalds       if(--len == 0)
1001da177e4SLinus Torvalds         break;
1011da177e4SLinus Torvalds     }
1021da177e4SLinus Torvalds   }
1031da177e4SLinus Torvalds end:
1044a98f896SFinn Thain   writeb(hostdata->ctrl | 0x40, base + CTRL);
105438af51cSFinn Thain 
106438af51cSFinn Thain 	if (len)
107438af51cSFinn Thain 		return -1;
108438af51cSFinn Thain 	return 0;
1091da177e4SLinus Torvalds }
1101da177e4SLinus Torvalds 
cumanascsi_pread(struct NCR5380_hostdata * hostdata,unsigned char * addr,int len)1114a98f896SFinn Thain static inline int cumanascsi_pread(struct NCR5380_hostdata *hostdata,
1126c4b88caSFinn Thain                                    unsigned char *addr, int len)
1131da177e4SLinus Torvalds {
1141da177e4SLinus Torvalds   unsigned long *laddr;
1154a98f896SFinn Thain   u8 __iomem *base = hostdata->io;
1164a98f896SFinn Thain   u8 __iomem *dma = hostdata->pdma_io + 0x2000;
1171da177e4SLinus Torvalds 
1181da177e4SLinus Torvalds   if(!len) return 0;
1191da177e4SLinus Torvalds 
120820682b1SFinn Thain   writeb(0x00, base + CTRL);
1211da177e4SLinus Torvalds   laddr = (unsigned long *)addr;
1221da177e4SLinus Torvalds   while(len >= 32)
1231da177e4SLinus Torvalds   {
1248b801eadSRussell King     unsigned int status;
125820682b1SFinn Thain     status = readb(base + STAT);
1261da177e4SLinus Torvalds     if(status & 0x80)
1271da177e4SLinus Torvalds       goto end;
1281da177e4SLinus Torvalds     if(!(status & 0x40))
1291da177e4SLinus Torvalds       continue;
1308b801eadSRussell King     *laddr++ = readw(dma) | (readw(dma) << 16);
1318b801eadSRussell King     *laddr++ = readw(dma) | (readw(dma) << 16);
1328b801eadSRussell King     *laddr++ = readw(dma) | (readw(dma) << 16);
1338b801eadSRussell King     *laddr++ = readw(dma) | (readw(dma) << 16);
1348b801eadSRussell King     *laddr++ = readw(dma) | (readw(dma) << 16);
1358b801eadSRussell King     *laddr++ = readw(dma) | (readw(dma) << 16);
1368b801eadSRussell King     *laddr++ = readw(dma) | (readw(dma) << 16);
1378b801eadSRussell King     *laddr++ = readw(dma) | (readw(dma) << 16);
1381da177e4SLinus Torvalds     len -= 32;
1391da177e4SLinus Torvalds     if(len == 0)
1401da177e4SLinus Torvalds       break;
1411da177e4SLinus Torvalds   }
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds   addr = (unsigned char *)laddr;
144820682b1SFinn Thain   writeb(0x10, base + CTRL);
1458b801eadSRussell King 
1461da177e4SLinus Torvalds   while(len > 0)
1471da177e4SLinus Torvalds   {
1488b801eadSRussell King     unsigned int status;
149820682b1SFinn Thain     status = readb(base + STAT);
1501da177e4SLinus Torvalds     if(status & 0x80)
1511da177e4SLinus Torvalds       goto end;
1521da177e4SLinus Torvalds     if(status & 0x40)
1531da177e4SLinus Torvalds     {
1548b801eadSRussell King       *addr++ = readb(dma);
1551da177e4SLinus Torvalds       if(--len == 0)
1561da177e4SLinus Torvalds         break;
1571da177e4SLinus Torvalds     }
1581da177e4SLinus Torvalds 
159820682b1SFinn Thain     status = readb(base + STAT);
1601da177e4SLinus Torvalds     if(status & 0x80)
1611da177e4SLinus Torvalds       goto end;
1621da177e4SLinus Torvalds     if(status & 0x40)
1631da177e4SLinus Torvalds     {
1648b801eadSRussell King       *addr++ = readb(dma);
1651da177e4SLinus Torvalds       if(--len == 0)
1661da177e4SLinus Torvalds         break;
1671da177e4SLinus Torvalds     }
1681da177e4SLinus Torvalds   }
1691da177e4SLinus Torvalds end:
1704a98f896SFinn Thain   writeb(hostdata->ctrl | 0x40, base + CTRL);
171438af51cSFinn Thain 
172438af51cSFinn Thain 	if (len)
173438af51cSFinn Thain 		return -1;
174438af51cSFinn Thain 	return 0;
1751da177e4SLinus Torvalds }
1761da177e4SLinus Torvalds 
cumanascsi_dma_xfer_len(struct NCR5380_hostdata * hostdata,struct scsi_cmnd * cmd)1774a98f896SFinn Thain static int cumanascsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,
1784a98f896SFinn Thain                                    struct scsi_cmnd *cmd)
1794a98f896SFinn Thain {
1804a98f896SFinn Thain 	return cmd->transfersize;
1814a98f896SFinn Thain }
1824a98f896SFinn Thain 
cumanascsi_read(struct NCR5380_hostdata * hostdata,unsigned int reg)18361e1ce58SFinn Thain static u8 cumanascsi_read(struct NCR5380_hostdata *hostdata,
18461e1ce58SFinn Thain                           unsigned int reg)
1851da177e4SLinus Torvalds {
18661e1ce58SFinn Thain 	u8 __iomem *base = hostdata->io;
18761e1ce58SFinn Thain 	u8 val;
1881da177e4SLinus Torvalds 
1898b801eadSRussell King 	writeb(0, base + CTRL);
1901da177e4SLinus Torvalds 
1918b801eadSRussell King 	val = readb(base + 0x2100 + (reg << 2));
1928b801eadSRussell King 
19361e1ce58SFinn Thain 	hostdata->ctrl = 0x40;
1948b801eadSRussell King 	writeb(0x40, base + CTRL);
1958b801eadSRussell King 
1968b801eadSRussell King 	return val;
1971da177e4SLinus Torvalds }
1981da177e4SLinus Torvalds 
cumanascsi_write(struct NCR5380_hostdata * hostdata,unsigned int reg,u8 value)19961e1ce58SFinn Thain static void cumanascsi_write(struct NCR5380_hostdata *hostdata,
20061e1ce58SFinn Thain                              unsigned int reg, u8 value)
2011da177e4SLinus Torvalds {
20261e1ce58SFinn Thain 	u8 __iomem *base = hostdata->io;
2031da177e4SLinus Torvalds 
2048b801eadSRussell King 	writeb(0, base + CTRL);
2058b801eadSRussell King 
2068b801eadSRussell King 	writeb(value, base + 0x2100 + (reg << 2));
2078b801eadSRussell King 
20861e1ce58SFinn Thain 	hostdata->ctrl = 0x40;
2098b801eadSRussell King 	writeb(0x40, base + CTRL);
2101da177e4SLinus Torvalds }
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds #include "../NCR5380.c"
2131da177e4SLinus Torvalds 
214*202423c5SBart Van Assche static const struct scsi_host_template cumanascsi_template = {
2151da177e4SLinus Torvalds 	.module			= THIS_MODULE,
2161da177e4SLinus Torvalds 	.name			= "Cumana 16-bit SCSI",
2171da177e4SLinus Torvalds 	.info			= cumanascsi_info,
2181da177e4SLinus Torvalds 	.queuecommand		= cumanascsi_queue_command,
2191da177e4SLinus Torvalds 	.eh_abort_handler	= NCR5380_abort,
22012e5fc66SHannes Reinecke 	.eh_host_reset_handler	= NCR5380_host_reset,
2211da177e4SLinus Torvalds 	.can_queue		= 16,
2221da177e4SLinus Torvalds 	.this_id		= 7,
2231da177e4SLinus Torvalds 	.sg_tablesize		= SG_ALL,
2241da177e4SLinus Torvalds 	.cmd_per_lun		= 2,
2251da177e4SLinus Torvalds 	.proc_name		= "CumanaSCSI-1",
226cd614642SBart Van Assche 	.cmd_size		= sizeof(struct NCR5380_cmd),
2270a4e3612SFinn Thain 	.max_sectors		= 128,
2284af14d11SChristoph Hellwig 	.dma_boundary		= PAGE_SIZE - 1,
2291da177e4SLinus Torvalds };
2301da177e4SLinus Torvalds 
cumanascsi1_probe(struct expansion_card * ec,const struct ecard_id * id)2316f039790SGreg Kroah-Hartman static int cumanascsi1_probe(struct expansion_card *ec,
2326f039790SGreg Kroah-Hartman 			     const struct ecard_id *id)
2331da177e4SLinus Torvalds {
2341da177e4SLinus Torvalds 	struct Scsi_Host *host;
2358b801eadSRussell King 	int ret;
2361da177e4SLinus Torvalds 
2378b801eadSRussell King 	ret = ecard_request_resources(ec);
2388b801eadSRussell King 	if (ret)
2391da177e4SLinus Torvalds 		goto out;
2401da177e4SLinus Torvalds 
2418b801eadSRussell King 	host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata));
2428b801eadSRussell King 	if (!host) {
2438b801eadSRussell King 		ret = -ENOMEM;
2448b801eadSRussell King 		goto out_release;
2458b801eadSRussell King 	}
2468b801eadSRussell King 
247820682b1SFinn Thain 	priv(host)->io = ioremap(ecard_resource_start(ec, ECARD_RES_IOCSLOW),
2488b801eadSRussell King 	                         ecard_resource_len(ec, ECARD_RES_IOCSLOW));
249820682b1SFinn Thain 	priv(host)->pdma_io = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
2508b801eadSRussell King 	                              ecard_resource_len(ec, ECARD_RES_MEMC));
251820682b1SFinn Thain 	if (!priv(host)->io || !priv(host)->pdma_io) {
2528b801eadSRussell King 		ret = -ENOMEM;
2538b801eadSRussell King 		goto out_unmap;
2548b801eadSRussell King 	}
2558b801eadSRussell King 
2561da177e4SLinus Torvalds 	host->irq = ec->irq;
2571da177e4SLinus Torvalds 
2588053b0eeSFinn Thain 	ret = NCR5380_init(host, FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP);
2590ad0eff9SFinn Thain 	if (ret)
2600ad0eff9SFinn Thain 		goto out_unmap;
2611da177e4SLinus Torvalds 
262b6488f97SFinn Thain 	NCR5380_maybe_reset_bus(host);
263b6488f97SFinn Thain 
2648b801eadSRussell King         priv(host)->ctrl = 0;
265820682b1SFinn Thain         writeb(0, priv(host)->io + CTRL);
2668b801eadSRussell King 
2674909cc2bSMichael Opdenacker 	ret = request_irq(host->irq, cumanascsi_intr, 0,
2681da177e4SLinus Torvalds 			  "CumanaSCSI-1", host);
2691da177e4SLinus Torvalds 	if (ret) {
2701da177e4SLinus Torvalds 		printk("scsi%d: IRQ%d not free: %d\n",
2711da177e4SLinus Torvalds 		    host->host_no, host->irq, ret);
2720ad0eff9SFinn Thain 		goto out_exit;
2731da177e4SLinus Torvalds 	}
2741da177e4SLinus Torvalds 
2751da177e4SLinus Torvalds 	ret = scsi_add_host(host, &ec->dev);
2761da177e4SLinus Torvalds 	if (ret)
2771da177e4SLinus Torvalds 		goto out_free_irq;
2781da177e4SLinus Torvalds 
2791da177e4SLinus Torvalds 	scsi_scan_host(host);
2801da177e4SLinus Torvalds 	goto out;
2811da177e4SLinus Torvalds 
2821da177e4SLinus Torvalds  out_free_irq:
2831da177e4SLinus Torvalds 	free_irq(host->irq, host);
2840ad0eff9SFinn Thain  out_exit:
2850ad0eff9SFinn Thain 	NCR5380_exit(host);
2868b801eadSRussell King  out_unmap:
287820682b1SFinn Thain 	iounmap(priv(host)->io);
288820682b1SFinn Thain 	iounmap(priv(host)->pdma_io);
2891da177e4SLinus Torvalds 	scsi_host_put(host);
2908b801eadSRussell King  out_release:
2918b801eadSRussell King 	ecard_release_resources(ec);
2921da177e4SLinus Torvalds  out:
2931da177e4SLinus Torvalds 	return ret;
2941da177e4SLinus Torvalds }
2951da177e4SLinus Torvalds 
cumanascsi1_remove(struct expansion_card * ec)2966f039790SGreg Kroah-Hartman static void cumanascsi1_remove(struct expansion_card *ec)
2971da177e4SLinus Torvalds {
2981da177e4SLinus Torvalds 	struct Scsi_Host *host = ecard_get_drvdata(ec);
299820682b1SFinn Thain 	void __iomem *base = priv(host)->io;
300820682b1SFinn Thain 	void __iomem *dma = priv(host)->pdma_io;
3011da177e4SLinus Torvalds 
3021da177e4SLinus Torvalds 	ecard_set_drvdata(ec, NULL);
3031da177e4SLinus Torvalds 
3041da177e4SLinus Torvalds 	scsi_remove_host(host);
3051da177e4SLinus Torvalds 	free_irq(host->irq, host);
3061da177e4SLinus Torvalds 	NCR5380_exit(host);
3071da177e4SLinus Torvalds 	scsi_host_put(host);
308820682b1SFinn Thain 	iounmap(base);
309820682b1SFinn Thain 	iounmap(dma);
3108b801eadSRussell King 	ecard_release_resources(ec);
3111da177e4SLinus Torvalds }
3121da177e4SLinus Torvalds 
3131da177e4SLinus Torvalds static const struct ecard_id cumanascsi1_cids[] = {
3141da177e4SLinus Torvalds 	{ MANU_CUMANA, PROD_CUMANA_SCSI_1 },
3151da177e4SLinus Torvalds 	{ 0xffff, 0xffff }
3161da177e4SLinus Torvalds };
3171da177e4SLinus Torvalds 
3181da177e4SLinus Torvalds static struct ecard_driver cumanascsi1_driver = {
3191da177e4SLinus Torvalds 	.probe		= cumanascsi1_probe,
3206f039790SGreg Kroah-Hartman 	.remove		= cumanascsi1_remove,
3211da177e4SLinus Torvalds 	.id_table	= cumanascsi1_cids,
3221da177e4SLinus Torvalds 	.drv = {
3231da177e4SLinus Torvalds 		.name		= "cumanascsi1",
3241da177e4SLinus Torvalds 	},
3251da177e4SLinus Torvalds };
3261da177e4SLinus Torvalds 
cumanascsi_init(void)3271da177e4SLinus Torvalds static int __init cumanascsi_init(void)
3281da177e4SLinus Torvalds {
3291da177e4SLinus Torvalds 	return ecard_register_driver(&cumanascsi1_driver);
3301da177e4SLinus Torvalds }
3311da177e4SLinus Torvalds 
cumanascsi_exit(void)3321da177e4SLinus Torvalds static void __exit cumanascsi_exit(void)
3331da177e4SLinus Torvalds {
3341da177e4SLinus Torvalds 	ecard_remove_driver(&cumanascsi1_driver);
3351da177e4SLinus Torvalds }
3361da177e4SLinus Torvalds 
3371da177e4SLinus Torvalds module_init(cumanascsi_init);
3381da177e4SLinus Torvalds module_exit(cumanascsi_exit);
3391da177e4SLinus Torvalds 
3401da177e4SLinus Torvalds MODULE_DESCRIPTION("Cumana SCSI-1 driver for Acorn machines");
3411da177e4SLinus Torvalds MODULE_LICENSE("GPL");
342