Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Generic Generic NCR5380 driver | |
3 | * | |
4 | * Copyright 1993, Drew Eckhardt | |
5 | * Visionary Computing | |
6 | * (Unix and Linux consulting and custom programming) | |
7 | * drew@colorado.edu | |
8 | * +1 (303) 440-4894 | |
9 | * | |
10 | * NCR53C400 extensions (c) 1994,1995,1996, Kevin Lentin | |
11 | * K.Lentin@cs.monash.edu.au | |
12 | * | |
13 | * NCR53C400A extensions (c) 1996, Ingmar Baumgart | |
14 | * ingmar@gonzo.schwaben.de | |
15 | * | |
16 | * DTC3181E extensions (c) 1997, Ronald van Cuijlenborg | |
17 | * ronald.van.cuijlenborg@tip.nl or nutty@dds.nl | |
18 | * | |
19 | * Added ISAPNP support for DTC436 adapters, | |
20 | * Thomas Sailer, sailer@ife.ee.ethz.ch | |
1da177e4 LT |
21 | */ |
22 | ||
23 | /* | |
24 | * TODO : flesh out DMA support, find some one actually using this (I have | |
25 | * a memory mapped Trantor board that works fine) | |
26 | */ | |
27 | ||
28 | /* | |
1da177e4 LT |
29 | * The card is detected and initialized in one of several ways : |
30 | * 1. With command line overrides - NCR5380=port,irq may be | |
31 | * used on the LILO command line to override the defaults. | |
32 | * | |
33 | * 2. With the GENERIC_NCR5380_OVERRIDE compile time define. This is | |
34 | * specified as an array of address, irq, dma, board tuples. Ie, for | |
35 | * one board at 0x350, IRQ5, no dma, I could say | |
36 | * -DGENERIC_NCR5380_OVERRIDE={{0xcc000, 5, DMA_NONE, BOARD_NCR5380}} | |
37 | * | |
38 | * -1 should be specified for no or DMA interrupt, -2 to autoprobe for an | |
39 | * IRQ line if overridden on the command line. | |
40 | * | |
41 | * 3. When included as a module, with arguments passed on the command line: | |
42 | * ncr_irq=xx the interrupt | |
43 | * ncr_addr=xx the port or base address (for port or memory | |
44 | * mapped, resp.) | |
45 | * ncr_dma=xx the DMA | |
46 | * ncr_5380=1 to set up for a NCR5380 board | |
47 | * ncr_53c400=1 to set up for a NCR53C400 board | |
48 | * e.g. | |
49 | * modprobe g_NCR5380 ncr_irq=5 ncr_addr=0x350 ncr_5380=1 | |
50 | * for a port mapped NCR5380 board or | |
51 | * modprobe g_NCR5380 ncr_irq=255 ncr_addr=0xc8000 ncr_53c400=1 | |
52 | * for a memory mapped NCR53C400 board with interrupts disabled. | |
53 | * | |
54 | * 255 should be specified for no or DMA interrupt, 254 to autoprobe for an | |
55 | * IRQ line if overridden on the command line. | |
56 | * | |
57 | */ | |
58 | ||
1da177e4 | 59 | #define AUTOPROBE_IRQ |
1da177e4 LT |
60 | |
61 | #ifdef CONFIG_SCSI_GENERIC_NCR53C400 | |
1da177e4 | 62 | #define PSEUDO_DMA |
1da177e4 LT |
63 | #endif |
64 | ||
1da177e4 | 65 | #include <asm/io.h> |
1da177e4 | 66 | #include <linux/blkdev.h> |
161c0059 | 67 | #include <linux/module.h> |
1da177e4 LT |
68 | #include <scsi/scsi_host.h> |
69 | #include "g_NCR5380.h" | |
70 | #include "NCR5380.h" | |
1da177e4 LT |
71 | #include <linux/init.h> |
72 | #include <linux/ioport.h> | |
73 | #include <linux/isapnp.h> | |
1da177e4 LT |
74 | #include <linux/interrupt.h> |
75 | ||
c0965e63 FT |
76 | static int ncr_irq; |
77 | static int ncr_dma; | |
78 | static int ncr_addr; | |
79 | static int ncr_5380; | |
80 | static int ncr_53c400; | |
81 | static int ncr_53c400a; | |
82 | static int dtc_3181e; | |
c6084cbc | 83 | static int hp_c2502; |
1da177e4 LT |
84 | |
85 | static struct override { | |
c818cb64 | 86 | NCR5380_map_type NCR5380_map_name; |
1da177e4 LT |
87 | int irq; |
88 | int dma; | |
89 | int board; /* Use NCR53c400, Ricoh, etc. extensions ? */ | |
90 | } overrides | |
91 | #ifdef GENERIC_NCR5380_OVERRIDE | |
92 | [] __initdata = GENERIC_NCR5380_OVERRIDE; | |
93 | #else | |
94 | [1] __initdata = { { 0,},}; | |
95 | #endif | |
96 | ||
6391a113 | 97 | #define NO_OVERRIDES ARRAY_SIZE(overrides) |
1da177e4 | 98 | |
6391a113 | 99 | #ifndef MODULE |
1da177e4 LT |
100 | |
101 | /** | |
102 | * internal_setup - handle lilo command string override | |
103 | * @board: BOARD_* identifier for the board | |
104 | * @str: unused | |
105 | * @ints: numeric parameters | |
106 | * | |
107 | * Do LILO command line initialization of the overrides array. Display | |
108 | * errors when needed | |
109 | * | |
110 | * Locks: none | |
111 | */ | |
112 | ||
113 | static void __init internal_setup(int board, char *str, int *ints) | |
114 | { | |
d5f7e65d | 115 | static int commandline_current; |
1da177e4 LT |
116 | switch (board) { |
117 | case BOARD_NCR5380: | |
118 | if (ints[0] != 2 && ints[0] != 3) { | |
119 | printk(KERN_ERR "generic_NCR5380_setup : usage ncr5380=" STRVAL(NCR5380_map_name) ",irq,dma\n"); | |
120 | return; | |
121 | } | |
122 | break; | |
123 | case BOARD_NCR53C400: | |
124 | if (ints[0] != 2) { | |
125 | printk(KERN_ERR "generic_NCR53C400_setup : usage ncr53c400=" STRVAL(NCR5380_map_name) ",irq\n"); | |
126 | return; | |
127 | } | |
128 | break; | |
129 | case BOARD_NCR53C400A: | |
130 | if (ints[0] != 2) { | |
131 | printk(KERN_ERR "generic_NCR53C400A_setup : usage ncr53c400a=" STRVAL(NCR5380_map_name) ",irq\n"); | |
132 | return; | |
133 | } | |
134 | break; | |
135 | case BOARD_DTC3181E: | |
136 | if (ints[0] != 2) { | |
137 | printk("generic_DTC3181E_setup : usage dtc3181e=" STRVAL(NCR5380_map_name) ",irq\n"); | |
138 | return; | |
139 | } | |
140 | break; | |
141 | } | |
142 | ||
143 | if (commandline_current < NO_OVERRIDES) { | |
144 | overrides[commandline_current].NCR5380_map_name = (NCR5380_map_type) ints[1]; | |
145 | overrides[commandline_current].irq = ints[2]; | |
146 | if (ints[0] == 3) | |
147 | overrides[commandline_current].dma = ints[3]; | |
148 | else | |
149 | overrides[commandline_current].dma = DMA_NONE; | |
150 | overrides[commandline_current].board = board; | |
151 | ++commandline_current; | |
152 | } | |
153 | } | |
154 | ||
155 | ||
156 | /** | |
157 | * do_NCR53C80_setup - set up entry point | |
158 | * @str: unused | |
159 | * | |
160 | * Setup function invoked at boot to parse the ncr5380= command | |
161 | * line. | |
162 | */ | |
163 | ||
164 | static int __init do_NCR5380_setup(char *str) | |
165 | { | |
166 | int ints[10]; | |
167 | ||
6391a113 | 168 | get_options(str, ARRAY_SIZE(ints), ints); |
1da177e4 LT |
169 | internal_setup(BOARD_NCR5380, str, ints); |
170 | return 1; | |
171 | } | |
172 | ||
173 | /** | |
174 | * do_NCR53C400_setup - set up entry point | |
175 | * @str: unused | |
6391a113 | 176 | * @ints: integer parameters from kernel setup code |
1da177e4 LT |
177 | * |
178 | * Setup function invoked at boot to parse the ncr53c400= command | |
179 | * line. | |
180 | */ | |
181 | ||
182 | static int __init do_NCR53C400_setup(char *str) | |
183 | { | |
184 | int ints[10]; | |
185 | ||
6391a113 | 186 | get_options(str, ARRAY_SIZE(ints), ints); |
1da177e4 LT |
187 | internal_setup(BOARD_NCR53C400, str, ints); |
188 | return 1; | |
189 | } | |
190 | ||
191 | /** | |
192 | * do_NCR53C400A_setup - set up entry point | |
193 | * @str: unused | |
6391a113 | 194 | * @ints: integer parameters from kernel setup code |
1da177e4 LT |
195 | * |
196 | * Setup function invoked at boot to parse the ncr53c400a= command | |
197 | * line. | |
198 | */ | |
199 | ||
200 | static int __init do_NCR53C400A_setup(char *str) | |
201 | { | |
202 | int ints[10]; | |
203 | ||
6391a113 | 204 | get_options(str, ARRAY_SIZE(ints), ints); |
1da177e4 LT |
205 | internal_setup(BOARD_NCR53C400A, str, ints); |
206 | return 1; | |
207 | } | |
208 | ||
209 | /** | |
210 | * do_DTC3181E_setup - set up entry point | |
211 | * @str: unused | |
6391a113 | 212 | * @ints: integer parameters from kernel setup code |
1da177e4 LT |
213 | * |
214 | * Setup function invoked at boot to parse the dtc3181e= command | |
215 | * line. | |
216 | */ | |
217 | ||
218 | static int __init do_DTC3181E_setup(char *str) | |
219 | { | |
220 | int ints[10]; | |
221 | ||
6391a113 | 222 | get_options(str, ARRAY_SIZE(ints), ints); |
1da177e4 LT |
223 | internal_setup(BOARD_DTC3181E, str, ints); |
224 | return 1; | |
225 | } | |
226 | ||
227 | #endif | |
228 | ||
c6084cbc OZ |
229 | #ifndef SCSI_G_NCR5380_MEM |
230 | /* | |
231 | * Configure I/O address of 53C400A or DTC436 by writing magic numbers | |
232 | * to ports 0x779 and 0x379. | |
233 | */ | |
234 | static void magic_configure(int idx, u8 irq, u8 magic[]) | |
235 | { | |
236 | u8 cfg = 0; | |
237 | ||
238 | outb(magic[0], 0x779); | |
239 | outb(magic[1], 0x379); | |
240 | outb(magic[2], 0x379); | |
241 | outb(magic[3], 0x379); | |
242 | outb(magic[4], 0x379); | |
243 | ||
244 | /* allowed IRQs for HP C2502 */ | |
245 | if (irq != 2 && irq != 3 && irq != 4 && irq != 5 && irq != 7) | |
246 | irq = 0; | |
247 | if (idx >= 0 && idx <= 7) | |
248 | cfg = 0x80 | idx | (irq << 4); | |
249 | outb(cfg, 0x379); | |
250 | } | |
251 | #endif | |
252 | ||
1da177e4 LT |
253 | /** |
254 | * generic_NCR5380_detect - look for NCR5380 controllers | |
255 | * @tpnt: the scsi template | |
256 | * | |
257 | * Scan for the present of NCR5380, NCR53C400, NCR53C400A, DTC3181E | |
258 | * and DTC436(ISAPnP) controllers. If overrides have been set we use | |
259 | * them. | |
260 | * | |
1da177e4 LT |
261 | * Locks: none |
262 | */ | |
263 | ||
ed8b9e7f | 264 | static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt) |
1da177e4 | 265 | { |
d5f7e65d | 266 | static int current_override; |
702a98c6 | 267 | int count; |
1da177e4 | 268 | unsigned int *ports; |
c6084cbc | 269 | u8 *magic = NULL; |
702a98c6 OZ |
270 | #ifndef SCSI_G_NCR5380_MEM |
271 | int i; | |
c6084cbc | 272 | int port_idx = -1; |
1da177e4 | 273 | unsigned long region_size = 16; |
702a98c6 | 274 | #endif |
1da177e4 LT |
275 | static unsigned int __initdata ncr_53c400a_ports[] = { |
276 | 0x280, 0x290, 0x300, 0x310, 0x330, 0x340, 0x348, 0x350, 0 | |
277 | }; | |
278 | static unsigned int __initdata dtc_3181e_ports[] = { | |
279 | 0x220, 0x240, 0x280, 0x2a0, 0x2c0, 0x300, 0x320, 0x340, 0 | |
280 | }; | |
c6084cbc OZ |
281 | static u8 ncr_53c400a_magic[] __initdata = { /* 53C400A & DTC436 */ |
282 | 0x59, 0xb9, 0xc5, 0xae, 0xa6 | |
283 | }; | |
284 | static u8 hp_c2502_magic[] __initdata = { /* HP C2502 */ | |
285 | 0x0f, 0x22, 0xf0, 0x20, 0x80 | |
286 | }; | |
4d8c08c7 | 287 | int flags; |
1da177e4 | 288 | struct Scsi_Host *instance; |
12150797 | 289 | struct NCR5380_hostdata *hostdata; |
702a98c6 | 290 | #ifdef SCSI_G_NCR5380_MEM |
c818cb64 AV |
291 | unsigned long base; |
292 | void __iomem *iomem; | |
293 | #endif | |
1da177e4 | 294 | |
c0965e63 | 295 | if (ncr_irq) |
1da177e4 | 296 | overrides[0].irq = ncr_irq; |
c0965e63 | 297 | if (ncr_dma) |
1da177e4 | 298 | overrides[0].dma = ncr_dma; |
c0965e63 | 299 | if (ncr_addr) |
1da177e4 | 300 | overrides[0].NCR5380_map_name = (NCR5380_map_type) ncr_addr; |
c0965e63 | 301 | if (ncr_5380) |
1da177e4 | 302 | overrides[0].board = BOARD_NCR5380; |
c0965e63 | 303 | else if (ncr_53c400) |
1da177e4 | 304 | overrides[0].board = BOARD_NCR53C400; |
c0965e63 | 305 | else if (ncr_53c400a) |
1da177e4 | 306 | overrides[0].board = BOARD_NCR53C400A; |
c0965e63 | 307 | else if (dtc_3181e) |
1da177e4 | 308 | overrides[0].board = BOARD_DTC3181E; |
c6084cbc OZ |
309 | else if (hp_c2502) |
310 | overrides[0].board = BOARD_HP_C2502; | |
702a98c6 | 311 | #ifndef SCSI_G_NCR5380_MEM |
1da177e4 LT |
312 | if (!current_override && isapnp_present()) { |
313 | struct pnp_dev *dev = NULL; | |
314 | count = 0; | |
315 | while ((dev = pnp_find_dev(NULL, ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e), dev))) { | |
316 | if (count >= NO_OVERRIDES) | |
317 | break; | |
c94babba | 318 | if (pnp_device_attach(dev) < 0) |
1da177e4 | 319 | continue; |
1da177e4 LT |
320 | if (pnp_activate_dev(dev) < 0) { |
321 | printk(KERN_ERR "dtc436e probe: activate failed\n"); | |
322 | pnp_device_detach(dev); | |
323 | continue; | |
324 | } | |
325 | if (!pnp_port_valid(dev, 0)) { | |
326 | printk(KERN_ERR "dtc436e probe: no valid port\n"); | |
327 | pnp_device_detach(dev); | |
328 | continue; | |
329 | } | |
330 | if (pnp_irq_valid(dev, 0)) | |
331 | overrides[count].irq = pnp_irq(dev, 0); | |
332 | else | |
22f5f10d | 333 | overrides[count].irq = NO_IRQ; |
1da177e4 LT |
334 | if (pnp_dma_valid(dev, 0)) |
335 | overrides[count].dma = pnp_dma(dev, 0); | |
336 | else | |
337 | overrides[count].dma = DMA_NONE; | |
338 | overrides[count].NCR5380_map_name = (NCR5380_map_type) pnp_port_start(dev, 0); | |
339 | overrides[count].board = BOARD_DTC3181E; | |
340 | count++; | |
341 | } | |
342 | } | |
702a98c6 | 343 | #endif |
1da177e4 LT |
344 | |
345 | for (count = 0; current_override < NO_OVERRIDES; ++current_override) { | |
346 | if (!(overrides[current_override].NCR5380_map_name)) | |
347 | continue; | |
348 | ||
349 | ports = NULL; | |
4d8c08c7 | 350 | flags = 0; |
1da177e4 LT |
351 | switch (overrides[current_override].board) { |
352 | case BOARD_NCR5380: | |
353 | flags = FLAG_NO_PSEUDO_DMA; | |
354 | break; | |
355 | case BOARD_NCR53C400: | |
4d8c08c7 | 356 | #ifdef PSEUDO_DMA |
55181be8 | 357 | flags = FLAG_NO_DMA_FIXUP; |
4d8c08c7 | 358 | #endif |
1da177e4 LT |
359 | break; |
360 | case BOARD_NCR53C400A: | |
cecf3bee | 361 | flags = FLAG_NO_DMA_FIXUP; |
1da177e4 | 362 | ports = ncr_53c400a_ports; |
c6084cbc OZ |
363 | magic = ncr_53c400a_magic; |
364 | break; | |
365 | case BOARD_HP_C2502: | |
366 | flags = FLAG_NO_DMA_FIXUP; | |
367 | ports = ncr_53c400a_ports; | |
368 | magic = hp_c2502_magic; | |
1da177e4 LT |
369 | break; |
370 | case BOARD_DTC3181E: | |
aeb51152 | 371 | flags = FLAG_NO_DMA_FIXUP; |
1da177e4 | 372 | ports = dtc_3181e_ports; |
c6084cbc | 373 | magic = ncr_53c400a_magic; |
1da177e4 LT |
374 | break; |
375 | } | |
376 | ||
702a98c6 | 377 | #ifndef SCSI_G_NCR5380_MEM |
c6084cbc | 378 | if (ports && magic) { |
1da177e4 LT |
379 | /* wakeup sequence for the NCR53C400A and DTC3181E */ |
380 | ||
381 | /* Disable the adapter and look for a free io port */ | |
c6084cbc | 382 | magic_configure(-1, 0, magic); |
1da177e4 LT |
383 | |
384 | if (overrides[current_override].NCR5380_map_name != PORT_AUTO) | |
385 | for (i = 0; ports[i]; i++) { | |
386 | if (!request_region(ports[i], 16, "ncr53c80")) | |
387 | continue; | |
388 | if (overrides[current_override].NCR5380_map_name == ports[i]) | |
389 | break; | |
390 | release_region(ports[i], 16); | |
391 | } else | |
392 | for (i = 0; ports[i]; i++) { | |
393 | if (!request_region(ports[i], 16, "ncr53c80")) | |
394 | continue; | |
395 | if (inb(ports[i]) == 0xff) | |
396 | break; | |
397 | release_region(ports[i], 16); | |
398 | } | |
399 | if (ports[i]) { | |
400 | /* At this point we have our region reserved */ | |
c6084cbc | 401 | magic_configure(i, 0, magic); /* no IRQ yet */ |
1da177e4 LT |
402 | outb(0xc0, ports[i] + 9); |
403 | if (inb(ports[i] + 9) != 0x80) | |
404 | continue; | |
c6084cbc OZ |
405 | overrides[current_override].NCR5380_map_name = ports[i]; |
406 | port_idx = i; | |
1da177e4 LT |
407 | } else |
408 | continue; | |
409 | } | |
410 | else | |
411 | { | |
412 | /* Not a 53C400A style setup - just grab */ | |
413 | if(!(request_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size, "ncr5380"))) | |
414 | continue; | |
415 | region_size = NCR5380_region_size; | |
416 | } | |
417 | #else | |
c818cb64 AV |
418 | base = overrides[current_override].NCR5380_map_name; |
419 | if (!request_mem_region(base, NCR5380_region_size, "ncr5380")) | |
420 | continue; | |
421 | iomem = ioremap(base, NCR5380_region_size); | |
422 | if (!iomem) { | |
423 | release_mem_region(base, NCR5380_region_size); | |
1da177e4 | 424 | continue; |
c818cb64 | 425 | } |
1da177e4 LT |
426 | #endif |
427 | instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); | |
0ad0eff9 FT |
428 | if (instance == NULL) |
429 | goto out_release; | |
12150797 | 430 | hostdata = shost_priv(instance); |
1da177e4 | 431 | |
702a98c6 | 432 | #ifndef SCSI_G_NCR5380_MEM |
b01ec348 | 433 | instance->io_port = overrides[current_override].NCR5380_map_name; |
1da177e4 | 434 | instance->n_io_port = region_size; |
aeb51152 | 435 | hostdata->io_width = 1; /* 8-bit PDMA by default */ |
4d8c08c7 FT |
436 | |
437 | /* | |
438 | * On NCR53C400 boards, NCR5380 registers are mapped 8 past | |
439 | * the base address. | |
440 | */ | |
cecf3bee OZ |
441 | switch (overrides[current_override].board) { |
442 | case BOARD_NCR53C400: | |
4d8c08c7 | 443 | instance->io_port += 8; |
12150797 OZ |
444 | hostdata->c400_ctl_status = 0; |
445 | hostdata->c400_blk_cnt = 1; | |
446 | hostdata->c400_host_buf = 4; | |
cecf3bee | 447 | break; |
aeb51152 OZ |
448 | case BOARD_DTC3181E: |
449 | hostdata->io_width = 2; /* 16-bit PDMA */ | |
450 | /* fall through */ | |
cecf3bee | 451 | case BOARD_NCR53C400A: |
c6084cbc | 452 | case BOARD_HP_C2502: |
cecf3bee OZ |
453 | hostdata->c400_ctl_status = 9; |
454 | hostdata->c400_blk_cnt = 10; | |
455 | hostdata->c400_host_buf = 8; | |
456 | break; | |
12150797 | 457 | } |
c818cb64 | 458 | #else |
b01ec348 | 459 | instance->base = overrides[current_override].NCR5380_map_name; |
12150797 | 460 | hostdata->iomem = iomem; |
cecf3bee OZ |
461 | switch (overrides[current_override].board) { |
462 | case BOARD_NCR53C400: | |
12150797 OZ |
463 | hostdata->c400_ctl_status = 0x100; |
464 | hostdata->c400_blk_cnt = 0x101; | |
465 | hostdata->c400_host_buf = 0x104; | |
cecf3bee | 466 | break; |
aeb51152 | 467 | case BOARD_DTC3181E: |
cecf3bee | 468 | case BOARD_NCR53C400A: |
c6084cbc | 469 | case BOARD_HP_C2502: |
cecf3bee OZ |
470 | pr_err(DRV_MODULE_NAME ": unknown register offsets\n"); |
471 | goto out_unregister; | |
12150797 | 472 | } |
1da177e4 LT |
473 | #endif |
474 | ||
0ad0eff9 FT |
475 | if (NCR5380_init(instance, flags)) |
476 | goto out_unregister; | |
1da177e4 | 477 | |
cecf3bee OZ |
478 | switch (overrides[current_override].board) { |
479 | case BOARD_NCR53C400: | |
aeb51152 | 480 | case BOARD_DTC3181E: |
cecf3bee | 481 | case BOARD_NCR53C400A: |
c6084cbc | 482 | case BOARD_HP_C2502: |
12150797 | 483 | NCR5380_write(hostdata->c400_ctl_status, CSR_BASE); |
cecf3bee | 484 | } |
4d8c08c7 | 485 | |
b6488f97 FT |
486 | NCR5380_maybe_reset_bus(instance); |
487 | ||
1da177e4 LT |
488 | if (overrides[current_override].irq != IRQ_AUTO) |
489 | instance->irq = overrides[current_override].irq; | |
490 | else | |
491 | instance->irq = NCR5380_probe_irq(instance, 0xffff); | |
492 | ||
22f5f10d FT |
493 | /* Compatibility with documented NCR5380 kernel parameters */ |
494 | if (instance->irq == 255) | |
495 | instance->irq = NO_IRQ; | |
496 | ||
c6084cbc OZ |
497 | if (instance->irq != NO_IRQ) { |
498 | #ifndef SCSI_G_NCR5380_MEM | |
499 | /* set IRQ for HP C2502 */ | |
500 | if (overrides[current_override].board == BOARD_HP_C2502) | |
501 | magic_configure(port_idx, instance->irq, magic); | |
502 | #endif | |
1e641664 | 503 | if (request_irq(instance->irq, generic_NCR5380_intr, |
4909cc2b | 504 | 0, "NCR5380", instance)) { |
1da177e4 | 505 | printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); |
22f5f10d | 506 | instance->irq = NO_IRQ; |
1da177e4 | 507 | } |
c6084cbc | 508 | } |
1da177e4 | 509 | |
22f5f10d | 510 | if (instance->irq == NO_IRQ) { |
1da177e4 LT |
511 | printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); |
512 | printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); | |
513 | } | |
514 | ||
1da177e4 LT |
515 | ++current_override; |
516 | ++count; | |
517 | } | |
518 | return count; | |
0ad0eff9 FT |
519 | |
520 | out_unregister: | |
521 | scsi_unregister(instance); | |
522 | out_release: | |
523 | #ifndef SCSI_G_NCR5380_MEM | |
524 | release_region(overrides[current_override].NCR5380_map_name, region_size); | |
525 | #else | |
526 | iounmap(iomem); | |
527 | release_mem_region(base, NCR5380_region_size); | |
528 | #endif | |
529 | return count; | |
1da177e4 LT |
530 | } |
531 | ||
1da177e4 LT |
532 | /** |
533 | * generic_NCR5380_release_resources - free resources | |
534 | * @instance: host adapter to clean up | |
535 | * | |
536 | * Free the generic interface resources from this adapter. | |
537 | * | |
538 | * Locks: none | |
539 | */ | |
540 | ||
ed8b9e7f | 541 | static int generic_NCR5380_release_resources(struct Scsi_Host *instance) |
1da177e4 | 542 | { |
22f5f10d | 543 | if (instance->irq != NO_IRQ) |
1e641664 | 544 | free_irq(instance->irq, instance); |
1da177e4 | 545 | NCR5380_exit(instance); |
702a98c6 | 546 | #ifndef SCSI_G_NCR5380_MEM |
b01ec348 | 547 | release_region(instance->io_port, instance->n_io_port); |
1da177e4 | 548 | #else |
702a98c6 | 549 | iounmap(((struct NCR5380_hostdata *)instance->hostdata)->iomem); |
b01ec348 | 550 | release_mem_region(instance->base, NCR5380_region_size); |
1da177e4 | 551 | #endif |
1da177e4 LT |
552 | return 0; |
553 | } | |
554 | ||
555 | #ifdef BIOSPARAM | |
556 | /** | |
557 | * generic_NCR5380_biosparam | |
558 | * @disk: disk to compute geometry for | |
559 | * @dev: device identifier for this disk | |
560 | * @ip: sizes to fill in | |
561 | * | |
562 | * Generates a BIOS / DOS compatible H-C-S mapping for the specified | |
563 | * device / size. | |
564 | * | |
565 | * XXX Most SCSI boards use this mapping, I could be incorrect. Someone | |
566 | * using hard disks on a trantor should verify that this mapping | |
567 | * corresponds to that used by the BIOS / ASPI driver by running the linux | |
568 | * fdisk program and matching the H_C_S coordinates to what DOS uses. | |
569 | * | |
570 | * Locks: none | |
571 | */ | |
572 | ||
573 | static int | |
574 | generic_NCR5380_biosparam(struct scsi_device *sdev, struct block_device *bdev, | |
575 | sector_t capacity, int *ip) | |
576 | { | |
577 | ip[0] = 64; | |
578 | ip[1] = 32; | |
579 | ip[2] = capacity >> 11; | |
580 | return 0; | |
581 | } | |
582 | #endif | |
583 | ||
4d8c08c7 | 584 | #ifdef PSEUDO_DMA |
1da177e4 LT |
585 | |
586 | /** | |
587 | * NCR5380_pread - pseudo DMA read | |
588 | * @instance: adapter to read from | |
589 | * @dst: buffer to read into | |
590 | * @len: buffer length | |
591 | * | |
25985edc | 592 | * Perform a pseudo DMA mode read from an NCR53C400 or equivalent |
1da177e4 LT |
593 | * controller |
594 | */ | |
595 | ||
596 | static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len) | |
597 | { | |
54d8fe44 | 598 | struct NCR5380_hostdata *hostdata = shost_priv(instance); |
1da177e4 LT |
599 | int blocks = len / 128; |
600 | int start = 0; | |
1da177e4 | 601 | |
12150797 OZ |
602 | NCR5380_write(hostdata->c400_ctl_status, CSR_BASE | CSR_TRANS_DIR); |
603 | NCR5380_write(hostdata->c400_blk_cnt, blocks); | |
1da177e4 | 604 | while (1) { |
12150797 | 605 | if (NCR5380_read(hostdata->c400_blk_cnt) == 0) |
1da177e4 | 606 | break; |
12150797 | 607 | if (NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ) { |
1da177e4 LT |
608 | printk(KERN_ERR "53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks); |
609 | return -1; | |
610 | } | |
12150797 OZ |
611 | while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY) |
612 | ; /* FIXME - no timeout */ | |
1da177e4 | 613 | |
702a98c6 | 614 | #ifndef SCSI_G_NCR5380_MEM |
aeb51152 OZ |
615 | if (hostdata->io_width == 2) |
616 | insw(instance->io_port + hostdata->c400_host_buf, | |
617 | dst + start, 64); | |
618 | else | |
619 | insb(instance->io_port + hostdata->c400_host_buf, | |
12150797 | 620 | dst + start, 128); |
1da177e4 | 621 | #else |
702a98c6 | 622 | /* implies SCSI_G_NCR5380_MEM */ |
54d8fe44 FT |
623 | memcpy_fromio(dst + start, |
624 | hostdata->iomem + NCR53C400_host_buffer, 128); | |
1da177e4 LT |
625 | #endif |
626 | start += 128; | |
627 | blocks--; | |
628 | } | |
629 | ||
630 | if (blocks) { | |
12150797 OZ |
631 | while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY) |
632 | ; /* FIXME - no timeout */ | |
1da177e4 | 633 | |
702a98c6 | 634 | #ifndef SCSI_G_NCR5380_MEM |
aeb51152 OZ |
635 | if (hostdata->io_width == 2) |
636 | insw(instance->io_port + hostdata->c400_host_buf, | |
637 | dst + start, 64); | |
638 | else | |
639 | insb(instance->io_port + hostdata->c400_host_buf, | |
12150797 | 640 | dst + start, 128); |
1da177e4 | 641 | #else |
702a98c6 | 642 | /* implies SCSI_G_NCR5380_MEM */ |
54d8fe44 FT |
643 | memcpy_fromio(dst + start, |
644 | hostdata->iomem + NCR53C400_host_buffer, 128); | |
1da177e4 LT |
645 | #endif |
646 | start += 128; | |
647 | blocks--; | |
648 | } | |
649 | ||
12150797 | 650 | if (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ)) |
1da177e4 LT |
651 | printk("53C400r: no 53C80 gated irq after transfer"); |
652 | ||
42fc6370 OZ |
653 | /* wait for 53C80 registers to be available */ |
654 | while (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG)) | |
1da177e4 | 655 | ; |
42fc6370 | 656 | |
1da177e4 LT |
657 | if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) |
658 | printk(KERN_ERR "53C400r: no end dma signal\n"); | |
659 | ||
1da177e4 LT |
660 | return 0; |
661 | } | |
662 | ||
663 | /** | |
664 | * NCR5380_write - pseudo DMA write | |
665 | * @instance: adapter to read from | |
666 | * @dst: buffer to read into | |
667 | * @len: buffer length | |
668 | * | |
25985edc | 669 | * Perform a pseudo DMA mode read from an NCR53C400 or equivalent |
1da177e4 LT |
670 | * controller |
671 | */ | |
672 | ||
673 | static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len) | |
674 | { | |
54d8fe44 | 675 | struct NCR5380_hostdata *hostdata = shost_priv(instance); |
1da177e4 LT |
676 | int blocks = len / 128; |
677 | int start = 0; | |
1da177e4 | 678 | |
12150797 OZ |
679 | NCR5380_write(hostdata->c400_ctl_status, CSR_BASE); |
680 | NCR5380_write(hostdata->c400_blk_cnt, blocks); | |
1da177e4 | 681 | while (1) { |
12150797 | 682 | if (NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ) { |
1da177e4 LT |
683 | printk(KERN_ERR "53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks); |
684 | return -1; | |
685 | } | |
686 | ||
12150797 | 687 | if (NCR5380_read(hostdata->c400_blk_cnt) == 0) |
1da177e4 | 688 | break; |
12150797 | 689 | while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY) |
1da177e4 | 690 | ; // FIXME - timeout |
702a98c6 | 691 | #ifndef SCSI_G_NCR5380_MEM |
aeb51152 OZ |
692 | if (hostdata->io_width == 2) |
693 | outsw(instance->io_port + hostdata->c400_host_buf, | |
694 | src + start, 64); | |
695 | else | |
696 | outsb(instance->io_port + hostdata->c400_host_buf, | |
12150797 | 697 | src + start, 128); |
1da177e4 | 698 | #else |
702a98c6 | 699 | /* implies SCSI_G_NCR5380_MEM */ |
54d8fe44 FT |
700 | memcpy_toio(hostdata->iomem + NCR53C400_host_buffer, |
701 | src + start, 128); | |
1da177e4 LT |
702 | #endif |
703 | start += 128; | |
704 | blocks--; | |
705 | } | |
706 | if (blocks) { | |
12150797 | 707 | while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY) |
1da177e4 LT |
708 | ; // FIXME - no timeout |
709 | ||
702a98c6 | 710 | #ifndef SCSI_G_NCR5380_MEM |
aeb51152 OZ |
711 | if (hostdata->io_width == 2) |
712 | outsw(instance->io_port + hostdata->c400_host_buf, | |
713 | src + start, 64); | |
714 | else | |
715 | outsb(instance->io_port + hostdata->c400_host_buf, | |
12150797 | 716 | src + start, 128); |
1da177e4 | 717 | #else |
702a98c6 | 718 | /* implies SCSI_G_NCR5380_MEM */ |
54d8fe44 FT |
719 | memcpy_toio(hostdata->iomem + NCR53C400_host_buffer, |
720 | src + start, 128); | |
1da177e4 LT |
721 | #endif |
722 | start += 128; | |
723 | blocks--; | |
724 | } | |
725 | ||
42fc6370 OZ |
726 | /* wait for 53C80 registers to be available */ |
727 | while (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG)) { | |
aeb51152 OZ |
728 | udelay(4); /* DTC436 chip hangs without this */ |
729 | /* FIXME - no timeout */ | |
730 | } | |
1da177e4 | 731 | |
1da177e4 LT |
732 | if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) { |
733 | printk(KERN_ERR "53C400w: no end dma signal\n"); | |
734 | } | |
42fc6370 | 735 | |
1da177e4 LT |
736 | while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)) |
737 | ; // TIMEOUT | |
738 | return 0; | |
739 | } | |
ff3d4578 FT |
740 | |
741 | static int generic_NCR5380_dma_xfer_len(struct scsi_cmnd *cmd) | |
742 | { | |
743 | int transfersize = cmd->transfersize; | |
744 | ||
745 | /* Limit transfers to 32K, for xx400 & xx406 | |
746 | * pseudoDMA that transfers in 128 bytes blocks. | |
747 | */ | |
748 | if (transfersize > 32 * 1024 && cmd->SCp.this_residual && | |
749 | !(cmd->SCp.this_residual % transfersize)) | |
750 | transfersize = 32 * 1024; | |
751 | ||
f0394621 OZ |
752 | /* 53C400 datasheet: non-modulo-128-byte transfers should use PIO */ |
753 | if (transfersize % 128) | |
754 | transfersize = 0; | |
755 | ||
ff3d4578 FT |
756 | return transfersize; |
757 | } | |
758 | ||
4d8c08c7 | 759 | #endif /* PSEUDO_DMA */ |
1da177e4 LT |
760 | |
761 | /* | |
762 | * Include the NCR5380 core code that we build our driver around | |
763 | */ | |
764 | ||
765 | #include "NCR5380.c" | |
766 | ||
d0be4a7d | 767 | static struct scsi_host_template driver_template = { |
aa2e2cb1 | 768 | .proc_name = DRV_MODULE_NAME, |
aa2e2cb1 FT |
769 | .name = "Generic NCR5380/NCR53C400 SCSI", |
770 | .detect = generic_NCR5380_detect, | |
771 | .release = generic_NCR5380_release_resources, | |
772 | .info = generic_NCR5380_info, | |
773 | .queuecommand = generic_NCR5380_queue_command, | |
1da177e4 LT |
774 | .eh_abort_handler = generic_NCR5380_abort, |
775 | .eh_bus_reset_handler = generic_NCR5380_bus_reset, | |
aa2e2cb1 FT |
776 | .bios_param = NCR5380_BIOSPARAM, |
777 | .can_queue = 16, | |
778 | .this_id = 7, | |
779 | .sg_tablesize = SG_ALL, | |
780 | .cmd_per_lun = 2, | |
781 | .use_clustering = DISABLE_CLUSTERING, | |
32b26a10 | 782 | .cmd_size = NCR5380_CMD_SIZE, |
0a4e3612 | 783 | .max_sectors = 128, |
1da177e4 | 784 | }; |
161c0059 | 785 | |
1da177e4 LT |
786 | #include "scsi_module.c" |
787 | ||
788 | module_param(ncr_irq, int, 0); | |
789 | module_param(ncr_dma, int, 0); | |
790 | module_param(ncr_addr, int, 0); | |
791 | module_param(ncr_5380, int, 0); | |
792 | module_param(ncr_53c400, int, 0); | |
793 | module_param(ncr_53c400a, int, 0); | |
794 | module_param(dtc_3181e, int, 0); | |
c6084cbc | 795 | module_param(hp_c2502, int, 0); |
1da177e4 LT |
796 | MODULE_LICENSE("GPL"); |
797 | ||
b026e8ed | 798 | #if !defined(SCSI_G_NCR5380_MEM) && defined(MODULE) |
6f039790 | 799 | static struct isapnp_device_id id_table[] = { |
1da177e4 LT |
800 | { |
801 | ISAPNP_ANY_ID, ISAPNP_ANY_ID, | |
802 | ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e), | |
803 | 0}, | |
804 | {0} | |
805 | }; | |
806 | ||
807 | MODULE_DEVICE_TABLE(isapnp, id_table); | |
702a98c6 | 808 | #endif |
1da177e4 LT |
809 | |
810 | __setup("ncr5380=", do_NCR5380_setup); | |
811 | __setup("ncr53c400=", do_NCR53C400_setup); | |
812 | __setup("ncr53c400a=", do_NCR53C400A_setup); | |
813 | __setup("dtc3181e=", do_DTC3181E_setup); |