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