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