update atp870u driver to 0.78 from D-Link source
[linux-2.4.git] / drivers / acorn / scsi / cumana_1.c
1 #define AUTOSENSE
2 #define PSEUDO_DMA
3
4 /*
5  * Generic Generic NCR5380 driver
6  *
7  * Copyright 1995, Russell King
8  *
9  * ALPHA RELEASE 1.
10  *
11  * For more information, please consult
12  *
13  * NCR 5380 Family
14  * SCSI Protocol Controller
15  * Databook
16  *
17  * NCR Microelectronics
18  * 1635 Aeroplaza Drive
19  * Colorado Springs, CO 80916
20  * 1+ (719) 578-3400
21  * 1+ (800) 334-5454
22  */
23
24
25 /*
26  * Options :
27  *
28  * PARITY - enable parity checking.  Not supported.
29  *
30  * SCSI2 - enable support for SCSI-II tagged queueing.  Untested.
31  *
32  * USLEEP - enable support for devices that don't disconnect.  Untested.
33  */
34
35 /*
36  * $Log: cumana_1.c,v $
37  * Revision 1.3  1998/05/03 20:45:32  alan
38  * ARM SCSI update. This adds the eesox driver and massively updates the
39  * Cumana driver. The folks who bought cumana arent anal retentive all
40  * docs are secret weenies so now there are docs ..
41  *
42  * Revision 1.2  1998/03/08 05:49:46  davem
43  * Merge to 2.1.89
44  *
45  * Revision 1.1  1998/02/23 02:45:22  davem
46  * Merge to 2.1.88
47  *
48  */
49
50 #include <linux/module.h>
51 #include <linux/signal.h>
52 #include <linux/sched.h>
53 #include <linux/ioport.h>
54 #include <linux/blk.h>
55 #include <linux/init.h>
56
57 #include <asm/ecard.h>
58 #include <asm/io.h>
59 #include <asm/irq.h>
60 #include <asm/system.h>
61
62 #include "../../scsi/scsi.h"
63 #include "../../scsi/hosts.h"
64 #include "../../scsi/constants.h"
65
66 #include <scsi/scsicam.h>
67
68 #define CUMANASCSI_PUBLIC_RELEASE 1
69
70 static const card_ids cumanascsi_cids[] = {
71         { MANU_CUMANA, PROD_CUMANA_SCSI_1 },
72         { 0xffff, 0xffff }
73 };
74
75 #define NCR5380_implementation_fields \
76     int port, ctrl
77
78 #define NCR5380_local_declare() \
79         struct Scsi_Host *_instance
80
81 #define NCR5380_setup(instance) \
82         _instance = instance
83
84 #define NCR5380_read(reg) cumanascsi_read(_instance, reg)
85 #define NCR5380_write(reg, value) cumanascsi_write(_instance, reg, value)
86
87 #define do_NCR5380_intr do_cumanascsi_intr
88 #define NCR5380_queue_command cumanascsi_queue_command
89 #define NCR5380_abort cumanascsi_abort
90 #define NCR5380_reset cumanascsi_reset
91 #define NCR5380_proc_info cumanascsi_proc_info
92
93 int NCR5380_proc_info(char *buffer, char **start, off_t offset,
94                       int length, int hostno, int inout);
95
96 #define BOARD_NORMAL    0
97 #define BOARD_NCR53C400 1
98
99 #include "../../scsi/NCR5380.h"
100
101 /*
102  * Function : cumanascsi_setup(char *str, int *ints)
103  *
104  * Purpose : LILO command line initialization of the overrides array,
105  *
106  * Inputs : str - unused, ints - array of integer parameters with ints[0]
107  *      equal to the number of ints.
108  *
109  */
110
111 void cumanascsi_setup(char *str, int *ints)
112 {
113 }
114
115 #define CUMANA_ADDRESS(card) (ecard_address((card), ECARD_IOC, ECARD_SLOW) + 0x800)
116 #define CUMANA_IRQ(card)     ((card)->irq)
117 /*
118  * Function : int cumanascsi_detect(Scsi_Host_Template * tpnt)
119  *
120  * Purpose : initializes cumana NCR5380 driver based on the
121  *      command line / compile time port and irq definitions.
122  *
123  * Inputs : tpnt - template for this SCSI adapter.
124  *
125  * Returns : 1 if a host adapter was found, 0 if not.
126  *
127  */
128 static struct expansion_card *ecs[4];
129  
130 int cumanascsi_detect(Scsi_Host_Template * tpnt)
131 {
132     int count = 0;
133     struct Scsi_Host *instance;
134
135     tpnt->proc_name = "CumanaSCSI-1";
136
137     memset (ecs, 0, sizeof (ecs));
138
139     while(1) {
140         if((ecs[count] = ecard_find(0, cumanascsi_cids)) == NULL)
141                 break;
142
143         instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
144         instance->io_port = CUMANA_ADDRESS(ecs[count]);
145         instance->irq = CUMANA_IRQ(ecs[count]);
146
147         NCR5380_init(instance, 0);
148         ecard_claim(ecs[count]);
149
150         instance->n_io_port = 255;
151         request_region (instance->io_port, instance->n_io_port, "CumanaSCSI-1");
152
153         ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
154         outb(0x00, instance->io_port - 577);
155
156         if (instance->irq != IRQ_NONE)
157             if (request_irq(instance->irq, do_cumanascsi_intr, SA_INTERRUPT, "CumanaSCSI-1", NULL)) {
158                 printk("scsi%d: IRQ%d not free, interrupts disabled\n",
159                     instance->host_no, instance->irq);
160                 instance->irq = IRQ_NONE;
161             }
162
163         if (instance->irq == IRQ_NONE) {
164             printk("scsi%d: interrupts not enabled. for better interactive performance,\n", instance->host_no);
165             printk("scsi%d: please jumper the board for a free IRQ.\n", instance->host_no);
166         }
167
168         printk("scsi%d: at port %lX irq", instance->host_no, instance->io_port);
169         if (instance->irq == IRQ_NONE)
170             printk ("s disabled");
171         else
172             printk (" %d", instance->irq);
173         printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
174             tpnt->can_queue, tpnt->cmd_per_lun, CUMANASCSI_PUBLIC_RELEASE);
175         printk("\nscsi%d:", instance->host_no);
176         NCR5380_print_options(instance);
177         printk("\n");
178
179         ++count;
180     }
181     return count;
182 }
183
184 int cumanascsi_release (struct Scsi_Host *shpnt)
185 {
186         int i;
187
188         if (shpnt->irq != IRQ_NONE)
189                 free_irq (shpnt->irq, NULL);
190         if (shpnt->io_port)
191                 release_region (shpnt->io_port, shpnt->n_io_port);
192
193         for (i = 0; i < 4; i++)
194                 if (shpnt->io_port == CUMANA_ADDRESS(ecs[i]))
195                         ecard_release (ecs[i]);
196         return 0;
197 }
198
199 const char * cumanascsi_info (struct Scsi_Host *spnt) {
200     return "";
201 }
202
203 #ifdef NOT_EFFICIENT
204 #define CTRL(p,v)     outb(*ctrl = (v), (p) - 577)
205 #define STAT(p)       inb((p)+1)
206 #define IN(p)         inb((p))
207 #define OUT(v,p)      outb((v), (p))
208 #else
209 #define CTRL(p,v)       (p[-2308] = (*ctrl = (v)))
210 #define STAT(p)         (p[4])
211 #define IN(p)           (*(p))
212 #define IN2(p)          ((unsigned short)(*(volatile unsigned long *)(p)))
213 #define OUT(v,p)        (*(p) = (v))
214 #define OUT2(v,p)       (*((volatile unsigned long *)(p)) = (v))
215 #endif
216 #define L(v)            (((v)<<16)|((v) & 0x0000ffff))
217 #define H(v)            (((v)>>16)|((v) & 0xffff0000))
218
219 static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr,
220               int len)
221 {
222   int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
223   int oldctrl = *ctrl;
224   unsigned long *laddr;
225 #ifdef NOT_EFFICIENT
226   int iobase = instance->io_port;
227   int dma_io = iobase & ~(0x3C0000>>2);
228 #else
229   volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port);
230   volatile unsigned char *dma_io = (unsigned char *)((int)iobase & ~0x3C0000);
231 #endif
232
233   if(!len) return 0;
234
235   CTRL(iobase, 0x02);
236   laddr = (unsigned long *)addr;
237   while(len >= 32)
238   {
239     int status;
240     unsigned long v;
241     status = STAT(iobase);
242     if(status & 0x80)
243       goto end;
244     if(!(status & 0x40))
245       continue;
246     v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
247     v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
248     v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
249     v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
250     v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
251     v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
252     v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
253     v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
254     len -= 32;
255     if(len == 0)
256       break;
257   }
258
259   addr = (unsigned char *)laddr;
260   CTRL(iobase, 0x12);
261   while(len > 0)
262   {
263     int status;
264     status = STAT(iobase);
265     if(status & 0x80)
266       goto end;
267     if(status & 0x40)
268     {
269       OUT(*addr++, dma_io);
270       if(--len == 0)
271         break;
272     }
273
274     status = STAT(iobase);
275     if(status & 0x80)
276       goto end;
277     if(status & 0x40)
278     {
279       OUT(*addr++, dma_io);
280       if(--len == 0)
281         break;
282     }
283   }
284 end:
285   CTRL(iobase, oldctrl|0x40);
286   return len;
287 }
288
289 static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr,
290               int len)
291 {
292   int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
293   int oldctrl = *ctrl;
294   unsigned long *laddr;
295 #ifdef NOT_EFFICIENT
296   int iobase = instance->io_port;
297   int dma_io = iobase & ~(0x3C0000>>2);
298 #else
299   volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port);
300   volatile unsigned char *dma_io = (unsigned char *)((int)iobase & ~0x3C0000);
301 #endif
302
303   if(!len) return 0;
304
305   CTRL(iobase, 0x00);
306   laddr = (unsigned long *)addr;
307   while(len >= 32)
308   {
309     int status;
310     status = STAT(iobase);
311     if(status & 0x80)
312       goto end;
313     if(!(status & 0x40))
314       continue;
315     *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
316     *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
317     *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
318     *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
319     *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
320     *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
321     *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
322     *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
323     len -= 32;
324     if(len == 0)
325       break;
326   }
327
328   addr = (unsigned char *)laddr;
329   CTRL(iobase, 0x10);
330   while(len > 0)
331   {
332     int status;
333     status = STAT(iobase);
334     if(status & 0x80)
335       goto end;
336     if(status & 0x40)
337     {
338       *addr++ = IN(dma_io);
339       if(--len == 0)
340         break;
341     }
342
343     status = STAT(iobase);
344     if(status & 0x80)
345       goto end;
346     if(status & 0x40)
347     {
348       *addr++ = IN(dma_io);
349       if(--len == 0)
350         break;
351     }
352   }
353 end:
354   CTRL(iobase, oldctrl|0x40);
355   return len;
356 }
357
358 #undef STAT
359 #undef CTRL
360 #undef IN
361 #undef OUT
362
363 #define CTRL(p,v) outb(*ctrl = (v), (p) - 577)
364
365 static char cumanascsi_read(struct Scsi_Host *instance, int reg)
366 {
367   int iobase = instance->io_port;
368   int i;
369   int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
370
371   CTRL(iobase, 0);
372   i = inb(iobase + 64 + reg);
373   CTRL(iobase, 0x40);
374
375   return i;
376 }
377
378 static void cumanascsi_write(struct Scsi_Host *instance, int reg, int value)
379 {
380   int iobase = instance->io_port;
381   int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
382
383   CTRL(iobase, 0);
384   outb(value, iobase + 64 + reg);
385   CTRL(iobase, 0x40);
386 }
387
388 #undef CTRL
389
390 #include "../../scsi/NCR5380.c"
391
392 static Scsi_Host_Template cumanascsi_template = {
393         module:                 THIS_MODULE,
394         name:                   "Cumana 16-bit SCSI",
395         detect:                 cumanascsi_detect,
396         release:                cumanascsi_release,
397         info:                   cumanascsi_info,
398         queuecommand:           cumanascsi_queue_command,
399         abort:                  cumanascsi_abort,
400         reset:                  cumanascsi_reset,
401         bios_param:             scsicam_bios_param,
402         can_queue:              16,
403         this_id:                7,
404         sg_tablesize:           SG_ALL,
405         cmd_per_lun:            2,
406         unchecked_isa_dma:      0,
407         use_clustering:         DISABLE_CLUSTERING
408 };
409
410 static int __init cumanascsi_init(void)
411 {
412         scsi_register_module(MODULE_SCSI_HA, &cumanascsi_template);
413         if (cumanascsi_template.present)
414                 return 0;
415
416         scsi_unregister_module(MODULE_SCSI_HA, &cumanascsi_template);
417         return -ENODEV;
418 }
419
420 static void __exit cumanascsi_exit(void)
421 {
422         scsi_unregister_module(MODULE_SCSI_HA, &cumanascsi_template);
423 }
424
425 module_init(cumanascsi_init);
426 module_exit(cumanascsi_exit);
427
428 MODULE_LICENSE("GPL");
429 EXPORT_NO_SYMBOLS;