1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29#include <linux/module.h>
30#include <linux/slab.h>
31
32#include <linux/blkdev.h>
33#include <linux/device.h>
34#include <linux/init.h>
35#include <linux/mca.h>
36#include <linux/eisa.h>
37#include <linux/interrupt.h>
38#include <scsi/scsi_host.h>
39#include <scsi/scsi_device.h>
40#include <scsi/scsi_transport.h>
41#include <scsi/scsi_transport_spi.h>
42
43#include "53c700.h"
44
45
46
47#define MAX_SLOTS 8
48static __u8 __initdata id_array[MAX_SLOTS] = { [0 ... MAX_SLOTS-1] = 7 };
49
50static char *sim710;
51
52MODULE_AUTHOR("Richard Hirst");
53MODULE_DESCRIPTION("Simple NCR53C710 driver");
54MODULE_LICENSE("GPL");
55
56module_param(sim710, charp, 0);
57
58#ifdef MODULE
59#define ARG_SEP ' '
60#else
61#define ARG_SEP ','
62#endif
63
64static __init int
65param_setup(char *str)
66{
67 char *pos = str, *next;
68 int slot = -1;
69
70 while(pos != NULL && (next = strchr(pos, ':')) != NULL) {
71 int val = (int)simple_strtoul(++next, NULL, 0);
72
73 if(!strncmp(pos, "slot:", 5))
74 slot = val;
75 else if(!strncmp(pos, "id:", 3)) {
76 if(slot == -1) {
77 printk(KERN_WARNING "sim710: Must specify slot for id parameter\n");
78 } else if(slot >= MAX_SLOTS) {
79 printk(KERN_WARNING "sim710: Illegal slot %d for id %d\n", slot, val);
80 } else {
81 id_array[slot] = val;
82 }
83 }
84 if((pos = strchr(pos, ARG_SEP)) != NULL)
85 pos++;
86 }
87 return 1;
88}
89__setup("sim710=", param_setup);
90
91static struct scsi_host_template sim710_driver_template = {
92 .name = "LSI (Symbios) 710 MCA/EISA",
93 .proc_name = "sim710",
94 .this_id = 7,
95 .module = THIS_MODULE,
96};
97
98static __devinit int
99sim710_probe_common(struct device *dev, unsigned long base_addr,
100 int irq, int clock, int differential, int scsi_id)
101{
102 struct Scsi_Host * host = NULL;
103 struct NCR_700_Host_Parameters *hostdata =
104 kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
105
106 printk(KERN_NOTICE "sim710: %s\n", dev_name(dev));
107 printk(KERN_NOTICE "sim710: irq = %d, clock = %d, base = 0x%lx, scsi_id = %d\n",
108 irq, clock, base_addr, scsi_id);
109
110 if(hostdata == NULL) {
111 printk(KERN_ERR "sim710: Failed to allocate host data\n");
112 goto out;
113 }
114
115 if(request_region(base_addr, 64, "sim710") == NULL) {
116 printk(KERN_ERR "sim710: Failed to reserve IO region 0x%lx\n",
117 base_addr);
118 goto out_free;
119 }
120
121
122 hostdata->base = ioport_map(base_addr, 64);
123 hostdata->differential = differential;
124 hostdata->clock = clock;
125 hostdata->chip710 = 1;
126 hostdata->burst_length = 8;
127
128
129 if((host = NCR_700_detect(&sim710_driver_template, hostdata, dev))
130 == NULL) {
131 printk(KERN_ERR "sim710: No host detected; card configuration problem?\n");
132 goto out_release;
133 }
134 host->this_id = scsi_id;
135 host->base = base_addr;
136 host->irq = irq;
137 if (request_irq(irq, NCR_700_intr, IRQF_SHARED, "sim710", host)) {
138 printk(KERN_ERR "sim710: request_irq failed\n");
139 goto out_put_host;
140 }
141
142 dev_set_drvdata(dev, host);
143 scsi_scan_host(host);
144
145 return 0;
146
147 out_put_host:
148 scsi_host_put(host);
149 out_release:
150 release_region(base_addr, 64);
151 out_free:
152 kfree(hostdata);
153 out:
154 return -ENODEV;
155}
156
157static __devexit int
158sim710_device_remove(struct device *dev)
159{
160 struct Scsi_Host *host = dev_get_drvdata(dev);
161 struct NCR_700_Host_Parameters *hostdata =
162 (struct NCR_700_Host_Parameters *)host->hostdata[0];
163
164 scsi_remove_host(host);
165 NCR_700_release(host);
166 kfree(hostdata);
167 free_irq(host->irq, host);
168 release_region(host->base, 64);
169 return 0;
170}
171
172#ifdef CONFIG_MCA
173
174
175#define MCA_01BB_IO_PORTS { 0x0000, 0x0000, 0x0800, 0x0C00, 0x1000, 0x1400, \
176 0x1800, 0x1C00, 0x2000, 0x2400, 0x2800, \
177 0x2C00, 0x3000, 0x3400, 0x3800, 0x3C00, \
178 0x4000, 0x4400, 0x4800, 0x4C00, 0x5000 }
179
180#define MCA_01BB_IRQS { 3, 5, 11, 14 }
181
182
183#define MCA_004F_IO_PORTS { 0x0000, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600 }
184#define MCA_004F_IRQS { 5, 9, 14 }
185
186static short sim710_mca_id_table[] = { 0x01bb, 0x01ba, 0x004f, 0};
187
188static __init int
189sim710_mca_probe(struct device *dev)
190{
191 struct mca_device *mca_dev = to_mca_device(dev);
192 int slot = mca_dev->slot;
193 int pos[3];
194 unsigned int base;
195 int irq_vector;
196 short id = sim710_mca_id_table[mca_dev->index];
197 static int io_004f_by_pos[] = MCA_004F_IO_PORTS;
198 static int irq_004f_by_pos[] = MCA_004F_IRQS;
199 static int io_01bb_by_pos[] = MCA_01BB_IO_PORTS;
200 static int irq_01bb_by_pos[] = MCA_01BB_IRQS;
201 char *name;
202 int clock;
203
204 pos[0] = mca_device_read_stored_pos(mca_dev, 2);
205 pos[1] = mca_device_read_stored_pos(mca_dev, 3);
206 pos[2] = mca_device_read_stored_pos(mca_dev, 4);
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240 if (id == 0x01bb || id == 0x01ba) {
241 base = io_01bb_by_pos[(pos[2] & 0xFC) >> 2];
242 irq_vector =
243 irq_01bb_by_pos[((pos[0] & 0xC0) >> 6)];
244
245 clock = 50;
246 if (id == 0x01bb)
247 name = "NCR 3360/3430 SCSI SubSystem";
248 else
249 name = "NCR Dual SIOP SCSI Host Adapter Board";
250 } else if ( id == 0x004f ) {
251 base = io_004f_by_pos[((pos[0] & 0x0E) >> 1)];
252 irq_vector =
253 irq_004f_by_pos[((pos[0] & 0x70) >> 4) - 4];
254 clock = 50;
255 name = "NCR 53c710 SCSI Host Adapter Board";
256 } else {
257 return -ENODEV;
258 }
259 mca_device_set_name(mca_dev, name);
260 mca_device_set_claim(mca_dev, 1);
261 base = mca_device_transform_ioport(mca_dev, base);
262 irq_vector = mca_device_transform_irq(mca_dev, irq_vector);
263
264 return sim710_probe_common(dev, base, irq_vector, clock,
265 0, id_array[slot]);
266}
267
268static struct mca_driver sim710_mca_driver = {
269 .id_table = sim710_mca_id_table,
270 .driver = {
271 .name = "sim710",
272 .bus = &mca_bus_type,
273 .probe = sim710_mca_probe,
274 .remove = __devexit_p(sim710_device_remove),
275 },
276};
277
278#endif
279
280#ifdef CONFIG_EISA
281static struct eisa_device_id sim710_eisa_ids[] = {
282 { "CPQ4410" },
283 { "CPQ4411" },
284 { "HWP0C80" },
285 { "" }
286};
287MODULE_DEVICE_TABLE(eisa, sim710_eisa_ids);
288
289static __init int
290sim710_eisa_probe(struct device *dev)
291{
292 struct eisa_device *edev = to_eisa_device(dev);
293 unsigned long io_addr = edev->base_addr;
294 char eisa_cpq_irqs[] = { 11, 14, 15, 10, 9, 0 };
295 char eisa_hwp_irqs[] = { 3, 4, 5, 7, 12, 10, 11, 0};
296 char *eisa_irqs;
297 unsigned char irq_index;
298 unsigned char irq, differential = 0, scsi_id = 7;
299
300 if(strcmp(edev->id.sig, "HWP0C80") == 0) {
301 __u8 val;
302 eisa_irqs = eisa_hwp_irqs;
303 irq_index = (inb(io_addr + 0xc85) & 0x7) - 1;
304
305 val = inb(io_addr + 0x4);
306 scsi_id = ffs(val) - 1;
307
308 if(scsi_id > 7 || (val & ~(1<<scsi_id)) != 0) {
309 printk(KERN_ERR "sim710.c, EISA card %s has incorrect scsi_id, setting to 7\n", dev_name(dev));
310 scsi_id = 7;
311 }
312 } else {
313 eisa_irqs = eisa_cpq_irqs;
314 irq_index = inb(io_addr + 0xc88) & 0x07;
315 }
316
317 if(irq_index >= strlen(eisa_irqs)) {
318 printk("sim710.c: irq nasty\n");
319 return -ENODEV;
320 }
321
322 irq = eisa_irqs[irq_index];
323
324 return sim710_probe_common(dev, io_addr, irq, 50,
325 differential, scsi_id);
326}
327
328static struct eisa_driver sim710_eisa_driver = {
329 .id_table = sim710_eisa_ids,
330 .driver = {
331 .name = "sim710",
332 .probe = sim710_eisa_probe,
333 .remove = __devexit_p(sim710_device_remove),
334 },
335};
336#endif
337
338static int __init sim710_init(void)
339{
340 int err = -ENODEV;
341
342#ifdef MODULE
343 if (sim710)
344 param_setup(sim710);
345#endif
346
347#ifdef CONFIG_MCA
348 err = mca_register_driver(&sim710_mca_driver);
349#endif
350
351#ifdef CONFIG_EISA
352 err = eisa_driver_register(&sim710_eisa_driver);
353#endif
354
355
356
357
358
359 return 0;
360}
361
362static void __exit sim710_exit(void)
363{
364#ifdef CONFIG_MCA
365 if (MCA_bus)
366 mca_unregister_driver(&sim710_mca_driver);
367#endif
368
369#ifdef CONFIG_EISA
370 eisa_driver_unregister(&sim710_eisa_driver);
371#endif
372}
373
374module_init(sim710_init);
375module_exit(sim710_exit);
376