File: /usr/src/linux/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;
430