blob: 8e9cfe8f22f505d9865aa8a870dcde9d94234826 [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 Thain54d8fe42016-01-03 16:05:06 +110017#define NCR5380_read(reg) cumanascsi_read(instance, reg)
18#define NCR5380_write(reg, value) cumanascsi_write(instance, reg, value)
Finn Thainff3d4572016-01-03 16:05:25 +110019
20#define NCR5380_dma_xfer_len(instance, cmd, phase) (cmd->transfersize)
Finn Thain6c4b88c2016-03-23 21:10:17 +110021#define NCR5380_dma_recv_setup cumanascsi_pread
22#define NCR5380_dma_send_setup cumanascsi_pwrite
Finn Thain8053b0e2016-03-23 21:10:19 +110023#define NCR5380_dma_residual(instance) (0)
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 \
30 unsigned ctrl; \
31 void __iomem *base; \
32 void __iomem *dma
33
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include "../NCR5380.h"
35
36void cumanascsi_setup(char *str, int *ints)
37{
38}
39
Russell King8b801ea2007-07-20 10:38:54 +010040#define CTRL 0x16fc
41#define STAT 0x2004
42#define L(v) (((v)<<16)|((v) & 0x0000ffff))
43#define H(v) (((v)>>16)|((v) & 0xffff0000))
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
Finn Thain6c4b88c2016-03-23 21:10:17 +110045static inline int cumanascsi_pwrite(struct Scsi_Host *host,
46 unsigned char *addr, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -070047{
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 unsigned long *laddr;
Russell King8b801ea2007-07-20 10:38:54 +010049 void __iomem *dma = priv(host)->dma + 0x2000;
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
51 if(!len) return 0;
52
Russell King8b801ea2007-07-20 10:38:54 +010053 writeb(0x02, priv(host)->base + CTRL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 laddr = (unsigned long *)addr;
55 while(len >= 32)
56 {
Russell King8b801ea2007-07-20 10:38:54 +010057 unsigned int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 unsigned long v;
Russell King8b801ea2007-07-20 10:38:54 +010059 status = readb(priv(host)->base + STAT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 if(status & 0x80)
61 goto end;
62 if(!(status & 0x40))
63 continue;
Russell King8b801ea2007-07-20 10:38:54 +010064 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);
71 v=*laddr++; writew(L(v), dma); writew(H(v), dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 len -= 32;
73 if(len == 0)
74 break;
75 }
76
77 addr = (unsigned char *)laddr;
Russell King8b801ea2007-07-20 10:38:54 +010078 writeb(0x12, priv(host)->base + CTRL);
79
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 while(len > 0)
81 {
Russell King8b801ea2007-07-20 10:38:54 +010082 unsigned int status;
83 status = readb(priv(host)->base + STAT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 if(status & 0x80)
85 goto end;
86 if(status & 0x40)
87 {
Russell King8b801ea2007-07-20 10:38:54 +010088 writeb(*addr++, dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 if(--len == 0)
90 break;
91 }
92
Russell King8b801ea2007-07-20 10:38:54 +010093 status = readb(priv(host)->base + STAT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 if(status & 0x80)
95 goto end;
96 if(status & 0x40)
97 {
Russell King8b801ea2007-07-20 10:38:54 +010098 writeb(*addr++, dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 if(--len == 0)
100 break;
101 }
102 }
103end:
Russell King8b801ea2007-07-20 10:38:54 +0100104 writeb(priv(host)->ctrl | 0x40, priv(host)->base + CTRL);
Finn Thain438af512016-03-23 21:10:18 +1100105
106 if (len)
107 return -1;
108 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109}
110
Finn Thain6c4b88c2016-03-23 21:10:17 +1100111static inline int cumanascsi_pread(struct Scsi_Host *host,
112 unsigned char *addr, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 unsigned long *laddr;
Russell King8b801ea2007-07-20 10:38:54 +0100115 void __iomem *dma = priv(host)->dma + 0x2000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
117 if(!len) return 0;
118
Russell King8b801ea2007-07-20 10:38:54 +0100119 writeb(0x00, priv(host)->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;
124 status = readb(priv(host)->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;
Russell King8b801ea2007-07-20 10:38:54 +0100143 writeb(0x10, priv(host)->base + CTRL);
144
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 while(len > 0)
146 {
Russell King8b801ea2007-07-20 10:38:54 +0100147 unsigned int status;
148 status = readb(priv(host)->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
Russell King8b801ea2007-07-20 10:38:54 +0100158 status = readb(priv(host)->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:
Russell King8b801ea2007-07-20 10:38:54 +0100169 writeb(priv(host)->ctrl | 0x40, priv(host)->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
Russell King8b801ea2007-07-20 10:38:54 +0100176static unsigned char cumanascsi_read(struct Scsi_Host *host, unsigned int reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177{
Russell King8b801ea2007-07-20 10:38:54 +0100178 void __iomem *base = priv(host)->base;
179 unsigned char val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
Russell King8b801ea2007-07-20 10:38:54 +0100181 writeb(0, base + CTRL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
Russell King8b801ea2007-07-20 10:38:54 +0100183 val = readb(base + 0x2100 + (reg << 2));
184
185 priv(host)->ctrl = 0x40;
186 writeb(0x40, base + CTRL);
187
188 return val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189}
190
Russell King8b801ea2007-07-20 10:38:54 +0100191static void cumanascsi_write(struct Scsi_Host *host, unsigned int reg, unsigned int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192{
Russell King8b801ea2007-07-20 10:38:54 +0100193 void __iomem *base = priv(host)->base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Russell King8b801ea2007-07-20 10:38:54 +0100195 writeb(0, base + CTRL);
196
197 writeb(value, base + 0x2100 + (reg << 2));
198
199 priv(host)->ctrl = 0x40;
200 writeb(0x40, base + CTRL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201}
202
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203#include "../NCR5380.c"
204
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +0100205static struct scsi_host_template cumanascsi_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 .module = THIS_MODULE,
207 .name = "Cumana 16-bit SCSI",
208 .info = cumanascsi_info,
209 .queuecommand = cumanascsi_queue_command,
210 .eh_abort_handler = NCR5380_abort,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 .eh_bus_reset_handler = NCR5380_bus_reset,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 .can_queue = 16,
213 .this_id = 7,
214 .sg_tablesize = SG_ALL,
215 .cmd_per_lun = 2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 .use_clustering = DISABLE_CLUSTERING,
217 .proc_name = "CumanaSCSI-1",
Finn Thain32b26a12016-01-03 16:05:58 +1100218 .cmd_size = NCR5380_CMD_SIZE,
Finn Thain0a4e3612016-01-03 16:06:07 +1100219 .max_sectors = 128,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220};
221
Greg Kroah-Hartman6f039792012-12-21 13:08:55 -0800222static int cumanascsi1_probe(struct expansion_card *ec,
223 const struct ecard_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224{
225 struct Scsi_Host *host;
Russell King8b801ea2007-07-20 10:38:54 +0100226 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227
Russell King8b801ea2007-07-20 10:38:54 +0100228 ret = ecard_request_resources(ec);
229 if (ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 goto out;
231
Russell King8b801ea2007-07-20 10:38:54 +0100232 host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata));
233 if (!host) {
234 ret = -ENOMEM;
235 goto out_release;
236 }
237
238 priv(host)->base = ioremap(ecard_resource_start(ec, ECARD_RES_IOCSLOW),
239 ecard_resource_len(ec, ECARD_RES_IOCSLOW));
240 priv(host)->dma = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
241 ecard_resource_len(ec, ECARD_RES_MEMC));
242 if (!priv(host)->base || !priv(host)->dma) {
243 ret = -ENOMEM;
244 goto out_unmap;
245 }
246
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 host->irq = ec->irq;
248
Finn Thain8053b0e2016-03-23 21:10:19 +1100249 ret = NCR5380_init(host, FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP);
Finn Thain0ad0eff2016-01-03 16:05:21 +1100250 if (ret)
251 goto out_unmap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
Finn Thainb6488f92016-01-03 16:05:08 +1100253 NCR5380_maybe_reset_bus(host);
254
Russell King8b801ea2007-07-20 10:38:54 +0100255 priv(host)->ctrl = 0;
256 writeb(0, priv(host)->base + CTRL);
257
Michael Opdenacker4909cc22014-03-05 06:09:41 +0100258 ret = request_irq(host->irq, cumanascsi_intr, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 "CumanaSCSI-1", host);
260 if (ret) {
261 printk("scsi%d: IRQ%d not free: %d\n",
262 host->host_no, host->irq, ret);
Finn Thain0ad0eff2016-01-03 16:05:21 +1100263 goto out_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 }
265
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 ret = scsi_add_host(host, &ec->dev);
267 if (ret)
268 goto out_free_irq;
269
270 scsi_scan_host(host);
271 goto out;
272
273 out_free_irq:
274 free_irq(host->irq, host);
Finn Thain0ad0eff2016-01-03 16:05:21 +1100275 out_exit:
276 NCR5380_exit(host);
Russell King8b801ea2007-07-20 10:38:54 +0100277 out_unmap:
278 iounmap(priv(host)->base);
279 iounmap(priv(host)->dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 scsi_host_put(host);
Russell King8b801ea2007-07-20 10:38:54 +0100281 out_release:
282 ecard_release_resources(ec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 out:
284 return ret;
285}
286
Greg Kroah-Hartman6f039792012-12-21 13:08:55 -0800287static void cumanascsi1_remove(struct expansion_card *ec)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288{
289 struct Scsi_Host *host = ecard_get_drvdata(ec);
290
291 ecard_set_drvdata(ec, NULL);
292
293 scsi_remove_host(host);
294 free_irq(host->irq, host);
295 NCR5380_exit(host);
Russell King8b801ea2007-07-20 10:38:54 +0100296 iounmap(priv(host)->base);
297 iounmap(priv(host)->dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 scsi_host_put(host);
Russell King8b801ea2007-07-20 10:38:54 +0100299 ecard_release_resources(ec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300}
301
302static const struct ecard_id cumanascsi1_cids[] = {
303 { MANU_CUMANA, PROD_CUMANA_SCSI_1 },
304 { 0xffff, 0xffff }
305};
306
307static struct ecard_driver cumanascsi1_driver = {
308 .probe = cumanascsi1_probe,
Greg Kroah-Hartman6f039792012-12-21 13:08:55 -0800309 .remove = cumanascsi1_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 .id_table = cumanascsi1_cids,
311 .drv = {
312 .name = "cumanascsi1",
313 },
314};
315
316static int __init cumanascsi_init(void)
317{
318 return ecard_register_driver(&cumanascsi1_driver);
319}
320
321static void __exit cumanascsi_exit(void)
322{
323 ecard_remove_driver(&cumanascsi1_driver);
324}
325
326module_init(cumanascsi_init);
327module_exit(cumanascsi_exit);
328
329MODULE_DESCRIPTION("Cumana SCSI-1 driver for Acorn machines");
330MODULE_LICENSE("GPL");