blob: db337b998299b0941180bce973a509c8f415f4a9 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Oak Generic NCR5380 driver
3 *
4 * Copyright 1995-2002, Russell King
5 */
6
7#include <linux/module.h>
8#include <linux/signal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <linux/ioport.h>
10#include <linux/delay.h>
11#include <linux/blkdev.h>
12#include <linux/init.h>
13
14#include <asm/ecard.h>
15#include <asm/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <scsi/scsi_host.h>
18
Linus Torvalds1da177e2005-04-16 15:20:36 -070019/*#define PSEUDO_DMA*/
Arnd Bergmannea065f12012-04-30 16:26:31 +000020#define DONT_USE_INTR
Linus Torvalds1da177e2005-04-16 15:20:36 -070021
Russell King8b801ea2007-07-20 10:38:54 +010022#define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
Russell King8b801ea2007-07-20 10:38:54 +010023
Finn Thain54d8fe42016-01-03 16:05:06 +110024#define NCR5380_read(reg) \
25 readb(priv(instance)->base + ((reg) << 2))
26#define NCR5380_write(reg, value) \
27 writeb(value, priv(instance)->base + ((reg) << 2))
28
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#define NCR5380_queue_command oakscsi_queue_command
Finn Thain8c325132014-11-12 16:11:58 +110030#define NCR5380_info oakscsi_info
Al Virodd7ab712013-03-31 01:15:54 -040031#define NCR5380_show_info oakscsi_show_info
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
Russell King8b801ea2007-07-20 10:38:54 +010033#define NCR5380_implementation_fields \
34 void __iomem *base
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include "../NCR5380.h"
37
38#undef START_DMA_INITIATOR_RECEIVE_REG
Russell King8b801ea2007-07-20 10:38:54 +010039#define START_DMA_INITIATOR_RECEIVE_REG (128 + 7)
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
Russell King8b801ea2007-07-20 10:38:54 +010041#define STAT ((128 + 16) << 2)
42#define DATA ((128 + 8) << 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
44static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr,
45 int len)
46{
Russell King8b801ea2007-07-20 10:38:54 +010047 void __iomem *base = priv(instance)->base;
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049printk("writing %p len %d\n",addr, len);
50 if(!len) return -1;
51
52 while(1)
53 {
54 int status;
Russell King8b801ea2007-07-20 10:38:54 +010055 while (((status = readw(base + STAT)) & 0x100)==0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 }
57}
58
59static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr,
60 int len)
61{
Russell King8b801ea2007-07-20 10:38:54 +010062 void __iomem *base = priv(instance)->base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070063printk("reading %p len %d\n", addr, len);
64 while(len > 0)
65 {
Russell King8b801ea2007-07-20 10:38:54 +010066 unsigned int status, timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 unsigned long b;
68
69 timeout = 0x01FFFFFF;
70
Russell King8b801ea2007-07-20 10:38:54 +010071 while (((status = readw(base + STAT)) & 0x100)==0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 {
73 timeout--;
74 if(status & 0x200 || !timeout)
75 {
Russell King8b801ea2007-07-20 10:38:54 +010076 printk("status = %08X\n", status);
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 return 1;
78 }
79 }
Russell King8b801ea2007-07-20 10:38:54 +010080
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 if(len >= 128)
82 {
Russell King8b801ea2007-07-20 10:38:54 +010083 readsw(base + DATA, addr, 128);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 addr += 128;
85 len -= 128;
86 }
87 else
88 {
Russell King8b801ea2007-07-20 10:38:54 +010089 b = (unsigned long) readw(base + DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 *addr ++ = b;
91 len -= 1;
92 if(len)
93 *addr ++ = b>>8;
94 len -= 1;
95 }
96 }
97 return 0;
98}
99
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100#undef STAT
Russell King8b801ea2007-07-20 10:38:54 +0100101#undef DATA
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
103#include "../NCR5380.c"
104
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +0100105static struct scsi_host_template oakscsi_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 .module = THIS_MODULE,
Al Virodd7ab712013-03-31 01:15:54 -0400107 .show_info = oakscsi_show_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 .name = "Oak 16-bit SCSI",
109 .info = oakscsi_info,
110 .queuecommand = oakscsi_queue_command,
111 .eh_abort_handler = NCR5380_abort,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 .eh_bus_reset_handler = NCR5380_bus_reset,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 .can_queue = 16,
114 .this_id = 7,
115 .sg_tablesize = SG_ALL,
116 .cmd_per_lun = 2,
117 .use_clustering = DISABLE_CLUSTERING,
118 .proc_name = "oakscsi",
119};
120
Greg Kroah-Hartman6f039792012-12-21 13:08:55 -0800121static int oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122{
123 struct Scsi_Host *host;
124 int ret = -ENOMEM;
125
Russell King8b801ea2007-07-20 10:38:54 +0100126 ret = ecard_request_resources(ec);
127 if (ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 goto out;
129
Russell King8b801ea2007-07-20 10:38:54 +0100130 host = scsi_host_alloc(&oakscsi_template, sizeof(struct NCR5380_hostdata));
131 if (!host) {
132 ret = -ENOMEM;
133 goto release;
134 }
135
136 priv(host)->base = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
137 ecard_resource_len(ec, ECARD_RES_MEMC));
138 if (!priv(host)->base) {
139 ret = -ENOMEM;
140 goto unreg;
141 }
142
Finn Thain22f5f102014-11-12 16:11:56 +1100143 host->irq = NO_IRQ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 host->n_io_port = 255;
145
Finn Thain0ad0eff2016-01-03 16:05:21 +1100146 ret = NCR5380_init(host, 0);
147 if (ret)
148 goto out_unmap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
Finn Thainb6488f92016-01-03 16:05:08 +1100150 NCR5380_maybe_reset_bus(host);
151
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 ret = scsi_add_host(host, &ec->dev);
153 if (ret)
Finn Thain0ad0eff2016-01-03 16:05:21 +1100154 goto out_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
156 scsi_scan_host(host);
157 goto out;
158
Finn Thain0ad0eff2016-01-03 16:05:21 +1100159 out_exit:
160 NCR5380_exit(host);
Russell King8b801ea2007-07-20 10:38:54 +0100161 out_unmap:
162 iounmap(priv(host)->base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 unreg:
164 scsi_host_put(host);
Russell King8b801ea2007-07-20 10:38:54 +0100165 release:
166 ecard_release_resources(ec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 out:
168 return ret;
169}
170
Greg Kroah-Hartman6f039792012-12-21 13:08:55 -0800171static void oakscsi_remove(struct expansion_card *ec)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172{
173 struct Scsi_Host *host = ecard_get_drvdata(ec);
174
175 ecard_set_drvdata(ec, NULL);
176 scsi_remove_host(host);
177
178 NCR5380_exit(host);
Russell King8b801ea2007-07-20 10:38:54 +0100179 iounmap(priv(host)->base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 scsi_host_put(host);
Russell King8b801ea2007-07-20 10:38:54 +0100181 ecard_release_resources(ec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182}
183
184static const struct ecard_id oakscsi_cids[] = {
185 { MANU_OAK, PROD_OAK_SCSI },
186 { 0xffff, 0xffff }
187};
188
189static struct ecard_driver oakscsi_driver = {
190 .probe = oakscsi_probe,
Greg Kroah-Hartman6f039792012-12-21 13:08:55 -0800191 .remove = oakscsi_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 .id_table = oakscsi_cids,
193 .drv = {
194 .name = "oakscsi",
195 },
196};
197
198static int __init oakscsi_init(void)
199{
200 return ecard_register_driver(&oakscsi_driver);
201}
202
203static void __exit oakscsi_exit(void)
204{
205 ecard_remove_driver(&oakscsi_driver);
206}
207
208module_init(oakscsi_init);
209module_exit(oakscsi_exit);
210
211MODULE_AUTHOR("Russell King");
212MODULE_DESCRIPTION("Oak SCSI driver");
213MODULE_LICENSE("GPL");
214