blob: a87b99c7fb9a7596810b3a7c4ecdddb4b3ff294f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Generic Generic NCR5380 driver
3 *
4 * Copyright 1995-2002, Russell King
5 */
6#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007#include <linux/ioport.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008#include <linux/blkdev.h>
9#include <linux/init.h>
10
11#include <asm/ecard.h>
12#include <asm/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <scsi/scsi_host.h>
15
Russell King8b801ea2007-07-20 10:38:54 +010016#define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
Finn Thain61e1ce52016-10-10 00:46:53 -040017#define NCR5380_read(reg) cumanascsi_read(hostdata, reg)
18#define NCR5380_write(reg, value) cumanascsi_write(hostdata, reg, value)
Finn Thainff3d4572016-01-03 16:05:25 +110019
Finn Thain4a98f892016-10-10 00:46:53 -040020#define NCR5380_dma_xfer_len cumanascsi_dma_xfer_len
Finn Thain6c4b88c2016-03-23 21:10:17 +110021#define NCR5380_dma_recv_setup cumanascsi_pread
22#define NCR5380_dma_send_setup cumanascsi_pwrite
Finn Thain4a98f892016-10-10 00:46:53 -040023#define NCR5380_dma_residual NCR5380_dma_residual_none
Finn Thainff3d4572016-01-03 16:05:25 +110024
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#define NCR5380_intr cumanascsi_intr
26#define NCR5380_queue_command cumanascsi_queue_command
Finn Thain8c325132014-11-12 16:11:58 +110027#define NCR5380_info cumanascsi_info
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
Russell King8b801ea2007-07-20 10:38:54 +010029#define NCR5380_implementation_fields \
Finn Thain820682b2016-10-10 00:46:53 -040030 unsigned ctrl
Russell King8b801ea2007-07-20 10:38:54 +010031
Finn Thain7c606632016-10-10 00:46:53 -040032struct NCR5380_hostdata;
33static u8 cumanascsi_read(struct NCR5380_hostdata *, unsigned int);
34static void cumanascsi_write(struct NCR5380_hostdata *, unsigned int, u8);
35
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include "../NCR5380.h"
37
Russell King8b801ea2007-07-20 10:38:54 +010038#define CTRL 0x16fc
39#define STAT 0x2004
40#define L(v) (((v)<<16)|((v) & 0x0000ffff))
41#define H(v) (((v)>>16)|((v) & 0xffff0000))
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
Finn Thain4a98f892016-10-10 00:46:53 -040043static inline int cumanascsi_pwrite(struct NCR5380_hostdata *hostdata,
Finn Thain6c4b88c2016-03-23 21:10:17 +110044 unsigned char *addr, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -070045{
Linus Torvalds1da177e2005-04-16 15:20:36 -070046 unsigned long *laddr;
Finn Thain4a98f892016-10-10 00:46:53 -040047 u8 __iomem *base = hostdata->io;
48 u8 __iomem *dma = hostdata->pdma_io + 0x2000;
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50 if(!len) return 0;
51
Finn Thain820682b2016-10-10 00:46:53 -040052 writeb(0x02, base + CTRL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 laddr = (unsigned long *)addr;
54 while(len >= 32)
55 {
Russell King8b801ea2007-07-20 10:38:54 +010056 unsigned int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 unsigned long v;
Finn Thain820682b2016-10-10 00:46:53 -040058 status = readb(base + STAT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 if(status & 0x80)
60 goto end;
61 if(!(status & 0x40))
62 continue;
Russell King8b801ea2007-07-20 10:38:54 +010063 v=*laddr++; writew(L(v), dma); writew(H(v), dma);
64 v=*laddr++; writew(L(v), dma); writew(H(v), dma);
65 v=*laddr++; writew(L(v), dma); writew(H(v), dma);
66 v=*laddr++; writew(L(v), dma); writew(H(v), dma);
67 v=*laddr++; writew(L(v), dma); writew(H(v), dma);
68 v=*laddr++; writew(L(v), dma); writew(H(v), dma);
69 v=*laddr++; writew(L(v), dma); writew(H(v), dma);
70 v=*laddr++; writew(L(v), dma); writew(H(v), dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 len -= 32;
72 if(len == 0)
73 break;
74 }
75
76 addr = (unsigned char *)laddr;
Finn Thain820682b2016-10-10 00:46:53 -040077 writeb(0x12, base + CTRL);
Russell King8b801ea2007-07-20 10:38:54 +010078
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 while(len > 0)
80 {
Russell King8b801ea2007-07-20 10:38:54 +010081 unsigned int status;
Finn Thain820682b2016-10-10 00:46:53 -040082 status = readb(base + STAT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 if(status & 0x80)
84 goto end;
85 if(status & 0x40)
86 {
Russell King8b801ea2007-07-20 10:38:54 +010087 writeb(*addr++, dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 if(--len == 0)
89 break;
90 }
91
Finn Thain820682b2016-10-10 00:46:53 -040092 status = readb(base + STAT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 if(status & 0x80)
94 goto end;
95 if(status & 0x40)
96 {
Russell King8b801ea2007-07-20 10:38:54 +010097 writeb(*addr++, dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 if(--len == 0)
99 break;
100 }
101 }
102end:
Finn Thain4a98f892016-10-10 00:46:53 -0400103 writeb(hostdata->ctrl | 0x40, base + CTRL);
Finn Thain438af512016-03-23 21:10:18 +1100104
105 if (len)
106 return -1;
107 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108}
109
Finn Thain4a98f892016-10-10 00:46:53 -0400110static inline int cumanascsi_pread(struct NCR5380_hostdata *hostdata,
Finn Thain6c4b88c2016-03-23 21:10:17 +1100111 unsigned char *addr, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 unsigned long *laddr;
Finn Thain4a98f892016-10-10 00:46:53 -0400114 u8 __iomem *base = hostdata->io;
115 u8 __iomem *dma = hostdata->pdma_io + 0x2000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
117 if(!len) return 0;
118
Finn Thain820682b2016-10-10 00:46:53 -0400119 writeb(0x00, base + CTRL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 laddr = (unsigned long *)addr;
121 while(len >= 32)
122 {
Russell King8b801ea2007-07-20 10:38:54 +0100123 unsigned int status;
Finn Thain820682b2016-10-10 00:46:53 -0400124 status = readb(base + STAT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 if(status & 0x80)
126 goto end;
127 if(!(status & 0x40))
128 continue;
Russell King8b801ea2007-07-20 10:38:54 +0100129 *laddr++ = readw(dma) | (readw(dma) << 16);
130 *laddr++ = readw(dma) | (readw(dma) << 16);
131 *laddr++ = readw(dma) | (readw(dma) << 16);
132 *laddr++ = readw(dma) | (readw(dma) << 16);
133 *laddr++ = readw(dma) | (readw(dma) << 16);
134 *laddr++ = readw(dma) | (readw(dma) << 16);
135 *laddr++ = readw(dma) | (readw(dma) << 16);
136 *laddr++ = readw(dma) | (readw(dma) << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 len -= 32;
138 if(len == 0)
139 break;
140 }
141
142 addr = (unsigned char *)laddr;
Finn Thain820682b2016-10-10 00:46:53 -0400143 writeb(0x10, base + CTRL);
Russell King8b801ea2007-07-20 10:38:54 +0100144
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 while(len > 0)
146 {
Russell King8b801ea2007-07-20 10:38:54 +0100147 unsigned int status;
Finn Thain820682b2016-10-10 00:46:53 -0400148 status = readb(base + STAT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 if(status & 0x80)
150 goto end;
151 if(status & 0x40)
152 {
Russell King8b801ea2007-07-20 10:38:54 +0100153 *addr++ = readb(dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 if(--len == 0)
155 break;
156 }
157
Finn Thain820682b2016-10-10 00:46:53 -0400158 status = readb(base + STAT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 if(status & 0x80)
160 goto end;
161 if(status & 0x40)
162 {
Russell King8b801ea2007-07-20 10:38:54 +0100163 *addr++ = readb(dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 if(--len == 0)
165 break;
166 }
167 }
168end:
Finn Thain4a98f892016-10-10 00:46:53 -0400169 writeb(hostdata->ctrl | 0x40, base + CTRL);
Finn Thain438af512016-03-23 21:10:18 +1100170
171 if (len)
172 return -1;
173 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174}
175
Finn Thain4a98f892016-10-10 00:46:53 -0400176static int cumanascsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,
177 struct scsi_cmnd *cmd)
178{
179 return cmd->transfersize;
180}
181
Finn Thain61e1ce52016-10-10 00:46:53 -0400182static u8 cumanascsi_read(struct NCR5380_hostdata *hostdata,
183 unsigned int reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184{
Finn Thain61e1ce52016-10-10 00:46:53 -0400185 u8 __iomem *base = hostdata->io;
186 u8 val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
Russell King8b801ea2007-07-20 10:38:54 +0100188 writeb(0, base + CTRL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
Russell King8b801ea2007-07-20 10:38:54 +0100190 val = readb(base + 0x2100 + (reg << 2));
191
Finn Thain61e1ce52016-10-10 00:46:53 -0400192 hostdata->ctrl = 0x40;
Russell King8b801ea2007-07-20 10:38:54 +0100193 writeb(0x40, base + CTRL);
194
195 return val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196}
197
Finn Thain61e1ce52016-10-10 00:46:53 -0400198static void cumanascsi_write(struct NCR5380_hostdata *hostdata,
199 unsigned int reg, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200{
Finn Thain61e1ce52016-10-10 00:46:53 -0400201 u8 __iomem *base = hostdata->io;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
Russell King8b801ea2007-07-20 10:38:54 +0100203 writeb(0, base + CTRL);
204
205 writeb(value, base + 0x2100 + (reg << 2));
206
Finn Thain61e1ce52016-10-10 00:46:53 -0400207 hostdata->ctrl = 0x40;
Russell King8b801ea2007-07-20 10:38:54 +0100208 writeb(0x40, base + CTRL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209}
210
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211#include "../NCR5380.c"
212
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +0100213static struct scsi_host_template cumanascsi_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 .module = THIS_MODULE,
215 .name = "Cumana 16-bit SCSI",
216 .info = cumanascsi_info,
217 .queuecommand = cumanascsi_queue_command,
218 .eh_abort_handler = NCR5380_abort,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 .eh_bus_reset_handler = NCR5380_bus_reset,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 .can_queue = 16,
221 .this_id = 7,
222 .sg_tablesize = SG_ALL,
223 .cmd_per_lun = 2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 .use_clustering = DISABLE_CLUSTERING,
225 .proc_name = "CumanaSCSI-1",
Finn Thain32b26a12016-01-03 16:05:58 +1100226 .cmd_size = NCR5380_CMD_SIZE,
Finn Thain0a4e3612016-01-03 16:06:07 +1100227 .max_sectors = 128,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228};
229
Greg Kroah-Hartman6f039792012-12-21 13:08:55 -0800230static int cumanascsi1_probe(struct expansion_card *ec,
231 const struct ecard_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232{
233 struct Scsi_Host *host;
Russell King8b801ea2007-07-20 10:38:54 +0100234 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235
Russell King8b801ea2007-07-20 10:38:54 +0100236 ret = ecard_request_resources(ec);
237 if (ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 goto out;
239
Russell King8b801ea2007-07-20 10:38:54 +0100240 host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata));
241 if (!host) {
242 ret = -ENOMEM;
243 goto out_release;
244 }
245
Finn Thain820682b2016-10-10 00:46:53 -0400246 priv(host)->io = ioremap(ecard_resource_start(ec, ECARD_RES_IOCSLOW),
247 ecard_resource_len(ec, ECARD_RES_IOCSLOW));
248 priv(host)->pdma_io = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
249 ecard_resource_len(ec, ECARD_RES_MEMC));
250 if (!priv(host)->io || !priv(host)->pdma_io) {
Russell King8b801ea2007-07-20 10:38:54 +0100251 ret = -ENOMEM;
252 goto out_unmap;
253 }
254
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 host->irq = ec->irq;
256
Finn Thain8053b0e2016-03-23 21:10:19 +1100257 ret = NCR5380_init(host, FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP);
Finn Thain0ad0eff2016-01-03 16:05:21 +1100258 if (ret)
259 goto out_unmap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260
Finn Thainb6488f92016-01-03 16:05:08 +1100261 NCR5380_maybe_reset_bus(host);
262
Russell King8b801ea2007-07-20 10:38:54 +0100263 priv(host)->ctrl = 0;
Finn Thain820682b2016-10-10 00:46:53 -0400264 writeb(0, priv(host)->io + CTRL);
Russell King8b801ea2007-07-20 10:38:54 +0100265
Michael Opdenacker4909cc22014-03-05 06:09:41 +0100266 ret = request_irq(host->irq, cumanascsi_intr, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 "CumanaSCSI-1", host);
268 if (ret) {
269 printk("scsi%d: IRQ%d not free: %d\n",
270 host->host_no, host->irq, ret);
Finn Thain0ad0eff2016-01-03 16:05:21 +1100271 goto out_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 }
273
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 ret = scsi_add_host(host, &ec->dev);
275 if (ret)
276 goto out_free_irq;
277
278 scsi_scan_host(host);
279 goto out;
280
281 out_free_irq:
282 free_irq(host->irq, host);
Finn Thain0ad0eff2016-01-03 16:05:21 +1100283 out_exit:
284 NCR5380_exit(host);
Russell King8b801ea2007-07-20 10:38:54 +0100285 out_unmap:
Finn Thain820682b2016-10-10 00:46:53 -0400286 iounmap(priv(host)->io);
287 iounmap(priv(host)->pdma_io);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 scsi_host_put(host);
Russell King8b801ea2007-07-20 10:38:54 +0100289 out_release:
290 ecard_release_resources(ec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 out:
292 return ret;
293}
294
Greg Kroah-Hartman6f039792012-12-21 13:08:55 -0800295static void cumanascsi1_remove(struct expansion_card *ec)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296{
297 struct Scsi_Host *host = ecard_get_drvdata(ec);
Finn Thain820682b2016-10-10 00:46:53 -0400298 void __iomem *base = priv(host)->io;
299 void __iomem *dma = priv(host)->pdma_io;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
301 ecard_set_drvdata(ec, NULL);
302
303 scsi_remove_host(host);
304 free_irq(host->irq, host);
305 NCR5380_exit(host);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 scsi_host_put(host);
Finn Thain820682b2016-10-10 00:46:53 -0400307 iounmap(base);
308 iounmap(dma);
Russell King8b801ea2007-07-20 10:38:54 +0100309 ecard_release_resources(ec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310}
311
312static const struct ecard_id cumanascsi1_cids[] = {
313 { MANU_CUMANA, PROD_CUMANA_SCSI_1 },
314 { 0xffff, 0xffff }
315};
316
317static struct ecard_driver cumanascsi1_driver = {
318 .probe = cumanascsi1_probe,
Greg Kroah-Hartman6f039792012-12-21 13:08:55 -0800319 .remove = cumanascsi1_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 .id_table = cumanascsi1_cids,
321 .drv = {
322 .name = "cumanascsi1",
323 },
324};
325
326static int __init cumanascsi_init(void)
327{
328 return ecard_register_driver(&cumanascsi1_driver);
329}
330
331static void __exit cumanascsi_exit(void)
332{
333 ecard_remove_driver(&cumanascsi1_driver);
334}
335
336module_init(cumanascsi_init);
337module_exit(cumanascsi_exit);
338
339MODULE_DESCRIPTION("Cumana SCSI-1 driver for Acorn machines");
340MODULE_LICENSE("GPL");