1/*
2 * Oak Generic NCR5380 driver
3 *
4 * Copyright 1995-2002, Russell King
5 */
6
7#include <linux/module.h>
8#include <linux/signal.h>
9#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>
16
17#include <scsi/scsi_host.h>
18
19/*#define PSEUDO_DMA*/
20#define DONT_USE_INTR
21
22#define priv(host)			((struct NCR5380_hostdata *)(host)->hostdata)
23#define NCR5380_local_declare()		void __iomem *_base
24#define NCR5380_setup(host)		_base = priv(host)->base
25
26#define NCR5380_read(reg)		readb(_base + ((reg) << 2))
27#define NCR5380_write(reg, value)	writeb(value, _base + ((reg) << 2))
28#define NCR5380_queue_command		oakscsi_queue_command
29#define NCR5380_info			oakscsi_info
30#define NCR5380_show_info		oakscsi_show_info
31
32#define NCR5380_implementation_fields	\
33	void __iomem *base
34
35#include "../NCR5380.h"
36
37#undef START_DMA_INITIATOR_RECEIVE_REG
38#define START_DMA_INITIATOR_RECEIVE_REG	(128 + 7)
39
40#define STAT	((128 + 16) << 2)
41#define DATA	((128 + 8) << 2)
42
43static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr,
44              int len)
45{
46  void __iomem *base = priv(instance)->base;
47
48printk("writing %p len %d\n",addr, len);
49  if(!len) return -1;
50
51  while(1)
52  {
53    int status;
54    while (((status = readw(base + STAT)) & 0x100)==0);
55  }
56}
57
58static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr,
59              int len)
60{
61  void __iomem *base = priv(instance)->base;
62printk("reading %p len %d\n", addr, len);
63  while(len > 0)
64  {
65    unsigned int status, timeout;
66    unsigned long b;
67
68    timeout = 0x01FFFFFF;
69
70    while (((status = readw(base + STAT)) & 0x100)==0)
71    {
72      timeout--;
73      if(status & 0x200 || !timeout)
74      {
75        printk("status = %08X\n", status);
76        return 1;
77      }
78    }
79
80    if(len >= 128)
81    {
82      readsw(base + DATA, addr, 128);
83      addr += 128;
84      len -= 128;
85    }
86    else
87    {
88      b = (unsigned long) readw(base + DATA);
89      *addr ++ = b;
90      len -= 1;
91      if(len)
92        *addr ++ = b>>8;
93      len -= 1;
94    }
95  }
96  return 0;
97}
98
99#undef STAT
100#undef DATA
101
102#include "../NCR5380.c"
103
104static struct scsi_host_template oakscsi_template = {
105	.module			= THIS_MODULE,
106	.show_info		= oakscsi_show_info,
107	.name			= "Oak 16-bit SCSI",
108	.info			= oakscsi_info,
109	.queuecommand		= oakscsi_queue_command,
110	.eh_abort_handler	= NCR5380_abort,
111	.eh_bus_reset_handler	= NCR5380_bus_reset,
112	.can_queue		= 16,
113	.this_id		= 7,
114	.sg_tablesize		= SG_ALL,
115	.cmd_per_lun		= 2,
116	.use_clustering		= DISABLE_CLUSTERING,
117	.proc_name		= "oakscsi",
118};
119
120static int oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
121{
122	struct Scsi_Host *host;
123	int ret = -ENOMEM;
124
125	ret = ecard_request_resources(ec);
126	if (ret)
127		goto out;
128
129	host = scsi_host_alloc(&oakscsi_template, sizeof(struct NCR5380_hostdata));
130	if (!host) {
131		ret = -ENOMEM;
132		goto release;
133	}
134
135	priv(host)->base = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
136				   ecard_resource_len(ec, ECARD_RES_MEMC));
137	if (!priv(host)->base) {
138		ret = -ENOMEM;
139		goto unreg;
140	}
141
142	host->irq = NO_IRQ;
143	host->n_io_port = 255;
144
145	NCR5380_init(host, 0);
146
147	ret = scsi_add_host(host, &ec->dev);
148	if (ret)
149		goto out_unmap;
150
151	scsi_scan_host(host);
152	goto out;
153
154 out_unmap:
155	iounmap(priv(host)->base);
156 unreg:
157	scsi_host_put(host);
158 release:
159	ecard_release_resources(ec);
160 out:
161	return ret;
162}
163
164static void oakscsi_remove(struct expansion_card *ec)
165{
166	struct Scsi_Host *host = ecard_get_drvdata(ec);
167
168	ecard_set_drvdata(ec, NULL);
169	scsi_remove_host(host);
170
171	NCR5380_exit(host);
172	iounmap(priv(host)->base);
173	scsi_host_put(host);
174	ecard_release_resources(ec);
175}
176
177static const struct ecard_id oakscsi_cids[] = {
178	{ MANU_OAK, PROD_OAK_SCSI },
179	{ 0xffff, 0xffff }
180};
181
182static struct ecard_driver oakscsi_driver = {
183	.probe		= oakscsi_probe,
184	.remove		= oakscsi_remove,
185	.id_table	= oakscsi_cids,
186	.drv = {
187		.name		= "oakscsi",
188	},
189};
190
191static int __init oakscsi_init(void)
192{
193	return ecard_register_driver(&oakscsi_driver);
194}
195
196static void __exit oakscsi_exit(void)
197{
198	ecard_remove_driver(&oakscsi_driver);
199}
200
201module_init(oakscsi_init);
202module_exit(oakscsi_exit);
203
204MODULE_AUTHOR("Russell King");
205MODULE_DESCRIPTION("Oak SCSI driver");
206MODULE_LICENSE("GPL");
207
208