xref: /openbmc/linux/drivers/scsi/arm/cumana_1.c (revision 12e5fc66)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Generic Generic NCR5380 driver
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Copyright 1995-2002, Russell King
51da177e4SLinus Torvalds  */
61da177e4SLinus Torvalds #include <linux/module.h>
71da177e4SLinus Torvalds #include <linux/ioport.h>
81da177e4SLinus Torvalds #include <linux/blkdev.h>
91da177e4SLinus Torvalds #include <linux/init.h>
101da177e4SLinus Torvalds 
111da177e4SLinus Torvalds #include <asm/ecard.h>
121da177e4SLinus Torvalds #include <asm/io.h>
131da177e4SLinus Torvalds 
141da177e4SLinus Torvalds #include <scsi/scsi_host.h>
151da177e4SLinus Torvalds 
168b801eadSRussell King #define priv(host)			((struct NCR5380_hostdata *)(host)->hostdata)
1761e1ce58SFinn Thain #define NCR5380_read(reg)		cumanascsi_read(hostdata, reg)
1861e1ce58SFinn Thain #define NCR5380_write(reg, value)	cumanascsi_write(hostdata, reg, value)
19ff3d4578SFinn Thain 
204a98f896SFinn Thain #define NCR5380_dma_xfer_len		cumanascsi_dma_xfer_len
216c4b88caSFinn Thain #define NCR5380_dma_recv_setup		cumanascsi_pread
226c4b88caSFinn Thain #define NCR5380_dma_send_setup		cumanascsi_pwrite
234a98f896SFinn Thain #define NCR5380_dma_residual		NCR5380_dma_residual_none
24ff3d4578SFinn Thain 
251da177e4SLinus Torvalds #define NCR5380_intr			cumanascsi_intr
261da177e4SLinus Torvalds #define NCR5380_queue_command		cumanascsi_queue_command
278c32513bSFinn Thain #define NCR5380_info			cumanascsi_info
281da177e4SLinus Torvalds 
298b801eadSRussell King #define NCR5380_implementation_fields	\
30820682b1SFinn Thain 	unsigned ctrl
318b801eadSRussell King 
327c606631SFinn Thain struct NCR5380_hostdata;
337c606631SFinn Thain static u8 cumanascsi_read(struct NCR5380_hostdata *, unsigned int);
347c606631SFinn Thain static void cumanascsi_write(struct NCR5380_hostdata *, unsigned int, u8);
357c606631SFinn Thain 
361da177e4SLinus Torvalds #include "../NCR5380.h"
371da177e4SLinus Torvalds 
388b801eadSRussell King #define CTRL	0x16fc
398b801eadSRussell King #define STAT	0x2004
401da177e4SLinus Torvalds #define L(v)	(((v)<<16)|((v) & 0x0000ffff))
411da177e4SLinus Torvalds #define H(v)	(((v)>>16)|((v) & 0xffff0000))
421da177e4SLinus Torvalds 
434a98f896SFinn Thain static inline int cumanascsi_pwrite(struct NCR5380_hostdata *hostdata,
446c4b88caSFinn Thain                                     unsigned char *addr, int len)
451da177e4SLinus Torvalds {
461da177e4SLinus Torvalds   unsigned long *laddr;
474a98f896SFinn Thain   u8 __iomem *base = hostdata->io;
484a98f896SFinn Thain   u8 __iomem *dma = hostdata->pdma_io + 0x2000;
491da177e4SLinus Torvalds 
501da177e4SLinus Torvalds   if(!len) return 0;
511da177e4SLinus Torvalds 
52820682b1SFinn Thain   writeb(0x02, base + CTRL);
531da177e4SLinus Torvalds   laddr = (unsigned long *)addr;
541da177e4SLinus Torvalds   while(len >= 32)
551da177e4SLinus Torvalds   {
568b801eadSRussell King     unsigned int status;
571da177e4SLinus Torvalds     unsigned long v;
58820682b1SFinn Thain     status = readb(base + STAT);
591da177e4SLinus Torvalds     if(status & 0x80)
601da177e4SLinus Torvalds       goto end;
611da177e4SLinus Torvalds     if(!(status & 0x40))
621da177e4SLinus Torvalds       continue;
638b801eadSRussell King     v=*laddr++; writew(L(v), dma); writew(H(v), dma);
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);
711da177e4SLinus Torvalds     len -= 32;
721da177e4SLinus Torvalds     if(len == 0)
731da177e4SLinus Torvalds       break;
741da177e4SLinus Torvalds   }
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds   addr = (unsigned char *)laddr;
77820682b1SFinn Thain   writeb(0x12, base + CTRL);
788b801eadSRussell King 
791da177e4SLinus Torvalds   while(len > 0)
801da177e4SLinus Torvalds   {
818b801eadSRussell King     unsigned int status;
82820682b1SFinn Thain     status = readb(base + STAT);
831da177e4SLinus Torvalds     if(status & 0x80)
841da177e4SLinus Torvalds       goto end;
851da177e4SLinus Torvalds     if(status & 0x40)
861da177e4SLinus Torvalds     {
878b801eadSRussell King       writeb(*addr++, dma);
881da177e4SLinus Torvalds       if(--len == 0)
891da177e4SLinus Torvalds         break;
901da177e4SLinus Torvalds     }
911da177e4SLinus Torvalds 
92820682b1SFinn Thain     status = readb(base + STAT);
931da177e4SLinus Torvalds     if(status & 0x80)
941da177e4SLinus Torvalds       goto end;
951da177e4SLinus Torvalds     if(status & 0x40)
961da177e4SLinus Torvalds     {
978b801eadSRussell King       writeb(*addr++, dma);
981da177e4SLinus Torvalds       if(--len == 0)
991da177e4SLinus Torvalds         break;
1001da177e4SLinus Torvalds     }
1011da177e4SLinus Torvalds   }
1021da177e4SLinus Torvalds end:
1034a98f896SFinn Thain   writeb(hostdata->ctrl | 0x40, base + CTRL);
104438af51cSFinn Thain 
105438af51cSFinn Thain 	if (len)
106438af51cSFinn Thain 		return -1;
107438af51cSFinn Thain 	return 0;
1081da177e4SLinus Torvalds }
1091da177e4SLinus Torvalds 
1104a98f896SFinn Thain static inline int cumanascsi_pread(struct NCR5380_hostdata *hostdata,
1116c4b88caSFinn Thain                                    unsigned char *addr, int len)
1121da177e4SLinus Torvalds {
1131da177e4SLinus Torvalds   unsigned long *laddr;
1144a98f896SFinn Thain   u8 __iomem *base = hostdata->io;
1154a98f896SFinn Thain   u8 __iomem *dma = hostdata->pdma_io + 0x2000;
1161da177e4SLinus Torvalds 
1171da177e4SLinus Torvalds   if(!len) return 0;
1181da177e4SLinus Torvalds 
119820682b1SFinn Thain   writeb(0x00, base + CTRL);
1201da177e4SLinus Torvalds   laddr = (unsigned long *)addr;
1211da177e4SLinus Torvalds   while(len >= 32)
1221da177e4SLinus Torvalds   {
1238b801eadSRussell King     unsigned int status;
124820682b1SFinn Thain     status = readb(base + STAT);
1251da177e4SLinus Torvalds     if(status & 0x80)
1261da177e4SLinus Torvalds       goto end;
1271da177e4SLinus Torvalds     if(!(status & 0x40))
1281da177e4SLinus Torvalds       continue;
1298b801eadSRussell King     *laddr++ = readw(dma) | (readw(dma) << 16);
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);
1371da177e4SLinus Torvalds     len -= 32;
1381da177e4SLinus Torvalds     if(len == 0)
1391da177e4SLinus Torvalds       break;
1401da177e4SLinus Torvalds   }
1411da177e4SLinus Torvalds 
1421da177e4SLinus Torvalds   addr = (unsigned char *)laddr;
143820682b1SFinn Thain   writeb(0x10, base + CTRL);
1448b801eadSRussell King 
1451da177e4SLinus Torvalds   while(len > 0)
1461da177e4SLinus Torvalds   {
1478b801eadSRussell King     unsigned int status;
148820682b1SFinn Thain     status = readb(base + STAT);
1491da177e4SLinus Torvalds     if(status & 0x80)
1501da177e4SLinus Torvalds       goto end;
1511da177e4SLinus Torvalds     if(status & 0x40)
1521da177e4SLinus Torvalds     {
1538b801eadSRussell King       *addr++ = readb(dma);
1541da177e4SLinus Torvalds       if(--len == 0)
1551da177e4SLinus Torvalds         break;
1561da177e4SLinus Torvalds     }
1571da177e4SLinus Torvalds 
158820682b1SFinn Thain     status = readb(base + STAT);
1591da177e4SLinus Torvalds     if(status & 0x80)
1601da177e4SLinus Torvalds       goto end;
1611da177e4SLinus Torvalds     if(status & 0x40)
1621da177e4SLinus Torvalds     {
1638b801eadSRussell King       *addr++ = readb(dma);
1641da177e4SLinus Torvalds       if(--len == 0)
1651da177e4SLinus Torvalds         break;
1661da177e4SLinus Torvalds     }
1671da177e4SLinus Torvalds   }
1681da177e4SLinus Torvalds end:
1694a98f896SFinn Thain   writeb(hostdata->ctrl | 0x40, base + CTRL);
170438af51cSFinn Thain 
171438af51cSFinn Thain 	if (len)
172438af51cSFinn Thain 		return -1;
173438af51cSFinn Thain 	return 0;
1741da177e4SLinus Torvalds }
1751da177e4SLinus Torvalds 
1764a98f896SFinn Thain static int cumanascsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,
1774a98f896SFinn Thain                                    struct scsi_cmnd *cmd)
1784a98f896SFinn Thain {
1794a98f896SFinn Thain 	return cmd->transfersize;
1804a98f896SFinn Thain }
1814a98f896SFinn Thain 
18261e1ce58SFinn Thain static u8 cumanascsi_read(struct NCR5380_hostdata *hostdata,
18361e1ce58SFinn Thain                           unsigned int reg)
1841da177e4SLinus Torvalds {
18561e1ce58SFinn Thain 	u8 __iomem *base = hostdata->io;
18661e1ce58SFinn Thain 	u8 val;
1871da177e4SLinus Torvalds 
1888b801eadSRussell King 	writeb(0, base + CTRL);
1891da177e4SLinus Torvalds 
1908b801eadSRussell King 	val = readb(base + 0x2100 + (reg << 2));
1918b801eadSRussell King 
19261e1ce58SFinn Thain 	hostdata->ctrl = 0x40;
1938b801eadSRussell King 	writeb(0x40, base + CTRL);
1948b801eadSRussell King 
1958b801eadSRussell King 	return val;
1961da177e4SLinus Torvalds }
1971da177e4SLinus Torvalds 
19861e1ce58SFinn Thain static void cumanascsi_write(struct NCR5380_hostdata *hostdata,
19961e1ce58SFinn Thain                              unsigned int reg, u8 value)
2001da177e4SLinus Torvalds {
20161e1ce58SFinn Thain 	u8 __iomem *base = hostdata->io;
2021da177e4SLinus Torvalds 
2038b801eadSRussell King 	writeb(0, base + CTRL);
2048b801eadSRussell King 
2058b801eadSRussell King 	writeb(value, base + 0x2100 + (reg << 2));
2068b801eadSRussell King 
20761e1ce58SFinn Thain 	hostdata->ctrl = 0x40;
2088b801eadSRussell King 	writeb(0x40, base + CTRL);
2091da177e4SLinus Torvalds }
2101da177e4SLinus Torvalds 
2111da177e4SLinus Torvalds #include "../NCR5380.c"
2121da177e4SLinus Torvalds 
213d0be4a7dSChristoph Hellwig static struct scsi_host_template cumanascsi_template = {
2141da177e4SLinus Torvalds 	.module			= THIS_MODULE,
2151da177e4SLinus Torvalds 	.name			= "Cumana 16-bit SCSI",
2161da177e4SLinus Torvalds 	.info			= cumanascsi_info,
2171da177e4SLinus Torvalds 	.queuecommand		= cumanascsi_queue_command,
2181da177e4SLinus Torvalds 	.eh_abort_handler	= NCR5380_abort,
21912e5fc66SHannes Reinecke 	.eh_host_reset_handler	= NCR5380_host_reset,
2201da177e4SLinus Torvalds 	.can_queue		= 16,
2211da177e4SLinus Torvalds 	.this_id		= 7,
2221da177e4SLinus Torvalds 	.sg_tablesize		= SG_ALL,
2231da177e4SLinus Torvalds 	.cmd_per_lun		= 2,
2241da177e4SLinus Torvalds 	.use_clustering		= DISABLE_CLUSTERING,
2251da177e4SLinus Torvalds 	.proc_name		= "CumanaSCSI-1",
22632b26a10SFinn Thain 	.cmd_size		= NCR5380_CMD_SIZE,
2270a4e3612SFinn Thain 	.max_sectors		= 128,
2281da177e4SLinus Torvalds };
2291da177e4SLinus Torvalds 
2306f039790SGreg Kroah-Hartman static int cumanascsi1_probe(struct expansion_card *ec,
2316f039790SGreg Kroah-Hartman 			     const struct ecard_id *id)
2321da177e4SLinus Torvalds {
2331da177e4SLinus Torvalds 	struct Scsi_Host *host;
2348b801eadSRussell King 	int ret;
2351da177e4SLinus Torvalds 
2368b801eadSRussell King 	ret = ecard_request_resources(ec);
2378b801eadSRussell King 	if (ret)
2381da177e4SLinus Torvalds 		goto out;
2391da177e4SLinus Torvalds 
2408b801eadSRussell King 	host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata));
2418b801eadSRussell King 	if (!host) {
2428b801eadSRussell King 		ret = -ENOMEM;
2438b801eadSRussell King 		goto out_release;
2448b801eadSRussell King 	}
2458b801eadSRussell King 
246820682b1SFinn Thain 	priv(host)->io = ioremap(ecard_resource_start(ec, ECARD_RES_IOCSLOW),
2478b801eadSRussell King 	                         ecard_resource_len(ec, ECARD_RES_IOCSLOW));
248820682b1SFinn Thain 	priv(host)->pdma_io = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
2498b801eadSRussell King 	                              ecard_resource_len(ec, ECARD_RES_MEMC));
250820682b1SFinn Thain 	if (!priv(host)->io || !priv(host)->pdma_io) {
2518b801eadSRussell King 		ret = -ENOMEM;
2528b801eadSRussell King 		goto out_unmap;
2538b801eadSRussell King 	}
2548b801eadSRussell King 
2551da177e4SLinus Torvalds 	host->irq = ec->irq;
2561da177e4SLinus Torvalds 
2578053b0eeSFinn Thain 	ret = NCR5380_init(host, FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP);
2580ad0eff9SFinn Thain 	if (ret)
2590ad0eff9SFinn Thain 		goto out_unmap;
2601da177e4SLinus Torvalds 
261b6488f97SFinn Thain 	NCR5380_maybe_reset_bus(host);
262b6488f97SFinn Thain 
2638b801eadSRussell King         priv(host)->ctrl = 0;
264820682b1SFinn Thain         writeb(0, priv(host)->io + CTRL);
2658b801eadSRussell King 
2664909cc2bSMichael Opdenacker 	ret = request_irq(host->irq, cumanascsi_intr, 0,
2671da177e4SLinus Torvalds 			  "CumanaSCSI-1", host);
2681da177e4SLinus Torvalds 	if (ret) {
2691da177e4SLinus Torvalds 		printk("scsi%d: IRQ%d not free: %d\n",
2701da177e4SLinus Torvalds 		    host->host_no, host->irq, ret);
2710ad0eff9SFinn Thain 		goto out_exit;
2721da177e4SLinus Torvalds 	}
2731da177e4SLinus Torvalds 
2741da177e4SLinus Torvalds 	ret = scsi_add_host(host, &ec->dev);
2751da177e4SLinus Torvalds 	if (ret)
2761da177e4SLinus Torvalds 		goto out_free_irq;
2771da177e4SLinus Torvalds 
2781da177e4SLinus Torvalds 	scsi_scan_host(host);
2791da177e4SLinus Torvalds 	goto out;
2801da177e4SLinus Torvalds 
2811da177e4SLinus Torvalds  out_free_irq:
2821da177e4SLinus Torvalds 	free_irq(host->irq, host);
2830ad0eff9SFinn Thain  out_exit:
2840ad0eff9SFinn Thain 	NCR5380_exit(host);
2858b801eadSRussell King  out_unmap:
286820682b1SFinn Thain 	iounmap(priv(host)->io);
287820682b1SFinn Thain 	iounmap(priv(host)->pdma_io);
2881da177e4SLinus Torvalds 	scsi_host_put(host);
2898b801eadSRussell King  out_release:
2908b801eadSRussell King 	ecard_release_resources(ec);
2911da177e4SLinus Torvalds  out:
2921da177e4SLinus Torvalds 	return ret;
2931da177e4SLinus Torvalds }
2941da177e4SLinus Torvalds 
2956f039790SGreg Kroah-Hartman static void cumanascsi1_remove(struct expansion_card *ec)
2961da177e4SLinus Torvalds {
2971da177e4SLinus Torvalds 	struct Scsi_Host *host = ecard_get_drvdata(ec);
298820682b1SFinn Thain 	void __iomem *base = priv(host)->io;
299820682b1SFinn Thain 	void __iomem *dma = priv(host)->pdma_io;
3001da177e4SLinus Torvalds 
3011da177e4SLinus Torvalds 	ecard_set_drvdata(ec, NULL);
3021da177e4SLinus Torvalds 
3031da177e4SLinus Torvalds 	scsi_remove_host(host);
3041da177e4SLinus Torvalds 	free_irq(host->irq, host);
3051da177e4SLinus Torvalds 	NCR5380_exit(host);
3061da177e4SLinus Torvalds 	scsi_host_put(host);
307820682b1SFinn Thain 	iounmap(base);
308820682b1SFinn Thain 	iounmap(dma);
3098b801eadSRussell King 	ecard_release_resources(ec);
3101da177e4SLinus Torvalds }
3111da177e4SLinus Torvalds 
3121da177e4SLinus Torvalds static const struct ecard_id cumanascsi1_cids[] = {
3131da177e4SLinus Torvalds 	{ MANU_CUMANA, PROD_CUMANA_SCSI_1 },
3141da177e4SLinus Torvalds 	{ 0xffff, 0xffff }
3151da177e4SLinus Torvalds };
3161da177e4SLinus Torvalds 
3171da177e4SLinus Torvalds static struct ecard_driver cumanascsi1_driver = {
3181da177e4SLinus Torvalds 	.probe		= cumanascsi1_probe,
3196f039790SGreg Kroah-Hartman 	.remove		= cumanascsi1_remove,
3201da177e4SLinus Torvalds 	.id_table	= cumanascsi1_cids,
3211da177e4SLinus Torvalds 	.drv = {
3221da177e4SLinus Torvalds 		.name		= "cumanascsi1",
3231da177e4SLinus Torvalds 	},
3241da177e4SLinus Torvalds };
3251da177e4SLinus Torvalds 
3261da177e4SLinus Torvalds static int __init cumanascsi_init(void)
3271da177e4SLinus Torvalds {
3281da177e4SLinus Torvalds 	return ecard_register_driver(&cumanascsi1_driver);
3291da177e4SLinus Torvalds }
3301da177e4SLinus Torvalds 
3311da177e4SLinus Torvalds static void __exit cumanascsi_exit(void)
3321da177e4SLinus Torvalds {
3331da177e4SLinus Torvalds 	ecard_remove_driver(&cumanascsi1_driver);
3341da177e4SLinus Torvalds }
3351da177e4SLinus Torvalds 
3361da177e4SLinus Torvalds module_init(cumanascsi_init);
3371da177e4SLinus Torvalds module_exit(cumanascsi_exit);
3381da177e4SLinus Torvalds 
3391da177e4SLinus Torvalds MODULE_DESCRIPTION("Cumana SCSI-1 driver for Acorn machines");
3401da177e4SLinus Torvalds MODULE_LICENSE("GPL");
341