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 
cumanascsi_setup(char * str,int * ints)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 
cumanascsi_detect(Scsi_Host_Template * tpnt)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 
cumanascsi_release(struct Scsi_Host * shpnt)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 
cumanascsi_info(struct Scsi_Host * spnt)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 
NCR5380_pwrite(struct Scsi_Host * instance,unsigned char * addr,int len)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 
NCR5380_pread(struct Scsi_Host * instance,unsigned char * addr,int len)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 
cumanascsi_read(struct Scsi_Host * instance,int reg)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 
cumanascsi_write(struct Scsi_Host * instance,int reg,int value)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 
cumanascsi_init(void)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 
cumanascsi_exit(void)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