|
|
1.1 root 1: /*
2: * Generic Generic NCR5380 driver
3: *
4: * Copyright 1993, Drew Eckhardt
5: * Visionary Computing
6: * (Unix and Linux consulting and custom programming)
7: * [email protected]
8: * +1 (303) 440-4894
9: *
10: * NCR53C400 extensions (c) 1994,1995,1996, Kevin Lentin
11: * [email protected]
12: *
13: * ALPHA RELEASE 1.
14: *
15: * For more information, please consult
16: *
17: * NCR 5380 Family
18: * SCSI Protocol Controller
19: * Databook
20: *
21: * NCR Microelectronics
22: * 1635 Aeroplaza Drive
23: * Colorado Springs, CO 80916
24: * 1+ (719) 578-3400
25: * 1+ (800) 334-5454
26: */
27:
28: /*
29: * TODO : flesh out DMA support, find some one actually using this (I have
30: * a memory mapped Trantor board that works fine)
31: */
32:
33: /*
34: * Options :
35: *
36: * PARITY - enable parity checking. Not supported.
37: *
38: * SCSI2 - enable support for SCSI-II tagged queueing. Untested.
39: *
40: * USLEEP - enable support for devices that don't disconnect. Untested.
41: *
42: * The card is detected and initialized in one of several ways :
43: * 1. With command line overrides - NCR5380=port,irq may be
44: * used on the LILO command line to override the defaults.
45: *
46: * 2. With the GENERIC_NCR5380_OVERRIDE compile time define. This is
47: * specified as an array of address, irq, dma, board tuples. Ie, for
48: * one board at 0x350, IRQ5, no dma, I could say
49: * -DGENERIC_NCR5380_OVERRIDE={{0xcc000, 5, DMA_NONE, BOARD_NCR5380}}
50: *
51: * -1 should be specified for no or DMA interrupt, -2 to autoprobe for an
52: * IRQ line if overridden on the command line.
53: */
54:
55: /*
56: * $Log: g_NCR5380.c,v $
57: * Revision 1.1.1.1 1997/02/25 21:27:49 thomas
58: * Initial source
59: *
60: * Revision 1.1.1.1 1996/10/30 01:40:05 thomas
61: * Imported from UK22
62: *
63: * Revision 1.1 1996/03/25 20:25:35 goel
64: * Linux driver merge.
65: *
66: */
67:
68: #define AUTOPROBE_IRQ
69: #define AUTOSENSE
70:
71: #include <linux/config.h>
72:
73: #ifdef MACH
74: #define CONFIG_SCSI_G_NCR5380_MEM
75: #endif
76:
77: #ifdef CONFIG_SCSI_GENERIC_NCR53C400
78: #define NCR53C400_PSEUDO_DMA 1
79: #define PSEUDO_DMA
80: #define NCR53C400
81: #endif
82: #if defined(CONFIG_SCSI_G_NCR5380_PORT) && defined(CONFIG_SCSI_G_NCR5380_MEM)
83: #error You can not configure the Generic NCR 5380 SCSI Driver for memory mapped I/O and port mapped I/O at the same time (yet)
84: #endif
85: #if !defined(CONFIG_SCSI_G_NCR5380_PORT) && !defined(CONFIG_SCSI_G_NCR5380_MEM)
86: #error You must configure the Generic NCR 5380 SCSI Driver for one of memory mapped I/O and port mapped I/O.
87: #endif
88:
89: #include <asm/system.h>
90: #include <asm/io.h>
91: #include <linux/signal.h>
92: #include <linux/sched.h>
93: #include <linux/blk.h>
94: #include "scsi.h"
95: #include "hosts.h"
96: #include "g_NCR5380.h"
97: #include "NCR5380.h"
98: #include "constants.h"
99: #include "sd.h"
100: #include<linux/stat.h>
101:
102: struct proc_dir_entry proc_scsi_g_ncr5380 = {
103: PROC_SCSI_GENERIC_NCR5380, 9, "g_NCR5380",
104: S_IFDIR | S_IRUGO | S_IXUGO, 2
105: };
106:
107: static struct override {
108: NCR5380_implementation_fields;
109: int irq;
110: int dma;
111: int board; /* Use NCR53c400, Ricoh, etc. extensions ? */
112: } overrides
113: #ifdef GENERIC_NCR5380_OVERRIDE
114: [] = GENERIC_NCR5380_OVERRIDE
115: #else
116: [1] = {{0,},};
117: #endif
118:
119: #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override))
120:
121: /*
122: * Function : static internal_setup(int board, char *str, int *ints)
123: *
124: * Purpose : LILO command line initialization of the overrides array,
125: *
126: * Inputs : board - either BOARD_NCR5380 for a normal NCR5380 board,
127: * or BOARD_NCR53C400 for a NCR53C400 board. str - unused, ints -
128: * array of integer parameters with ints[0] equal to the number of ints.
129: *
130: */
131:
132: static void internal_setup(int board, char *str, int *ints) {
133: static int commandline_current = 0;
134: switch (board) {
135: case BOARD_NCR5380:
136: if (ints[0] != 2 && ints[0] != 3)
137: printk("generic_NCR5380_setup : usage ncr5380=" STRVAL(NCR5380_map_name) ",irq,dma\n");
138: return;
139: case BOARD_NCR53C400:
140: if (ints[0] != 2)
141: printk("generic_NCR53C400_setup : usage ncr53c400= " STRVAL(NCR5380_map_name) ",irq\n");
142: return;
143: }
144:
145: if (commandline_current < NO_OVERRIDES) {
146: overrides[commandline_current].NCR5380_map_name = (NCR5380_map_type)ints[1];
147: overrides[commandline_current].irq = ints[2];
148: if (ints[0] == 3)
149: overrides[commandline_current].dma = ints[3];
150: else
151: overrides[commandline_current].dma = DMA_NONE;
152: overrides[commandline_current].board = board;
153: ++commandline_current;
154: }
155: }
156:
157: /*
158: * Function : generic_NCR5380_setup (char *str, int *ints)
159: *
160: * Purpose : LILO command line initialization of the overrides array,
161: *
162: * Inputs : str - unused, ints - array of integer paramters with ints[0]
163: * equal to the number of ints.
164: */
165:
166: void generic_NCR5380_setup (char *str, int *ints) {
167: internal_setup (BOARD_NCR5380, str, ints);
168: }
169:
170: /*
171: * Function : generic_NCR53C400_setup (char *str, int *ints)
172: *
173: * Purpose : LILO command line initialization of the overrides array,
174: *
175: * Inputs : str - unused, ints - array of integer paramters with ints[0]
176: * equal to the number of ints.
177: */
178:
179: void generic_NCR53C400_setup (char *str, int *ints) {
180: internal_setup (BOARD_NCR53C400, str, ints);
181: }
182:
183: /*
184: * Function : int generic_NCR5380_detect(Scsi_Host_Template * tpnt)
185: *
186: * Purpose : initializes generic NCR5380 driver based on the
187: * command line / compile time port and irq definitions.
188: *
189: * Inputs : tpnt - template for this SCSI adapter.
190: *
191: * Returns : 1 if a host adapter was found, 0 if not.
192: *
193: */
194:
195: int generic_NCR5380_detect(Scsi_Host_Template * tpnt) {
196: static int current_override = 0;
197: int count;
198: int flags = 0;
199: struct Scsi_Host *instance;
200:
201: tpnt->proc_dir = &proc_scsi_g_ncr5380;
202:
203: for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
204: if (!(overrides[current_override].NCR5380_map_name))
205: continue;
206:
207: switch (overrides[current_override].board) {
208: case BOARD_NCR5380:
209: flags = FLAG_NO_PSEUDO_DMA;
210: break;
211: case BOARD_NCR53C400:
212: flags = FLAG_NCR53C400;
213: break;
214: }
215:
216: instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
217: instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name;
218:
219: NCR5380_init(instance, flags);
220:
221: if (overrides[current_override].irq != IRQ_AUTO)
222: instance->irq = overrides[current_override].irq;
223: else
224: instance->irq = NCR5380_probe_irq(instance, 0xffff);
225:
226: if (instance->irq != IRQ_NONE)
227: if (request_irq(instance->irq, generic_NCR5380_intr, SA_INTERRUPT, "NCR5380")) {
228: printk("scsi%d : IRQ%d not free, interrupts disabled\n",
229: instance->host_no, instance->irq);
230: instance->irq = IRQ_NONE;
231: }
232:
233: if (instance->irq == IRQ_NONE) {
234: printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
235: printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
236: }
237:
238: printk("scsi%d : at " STRVAL(NCR5380_map_name) " 0x%x", instance->host_no, (unsigned int)instance->NCR5380_instance_name);
239: if (instance->irq == IRQ_NONE)
240: printk (" interrupts disabled");
241: else
242: printk (" irq %d", instance->irq);
243: printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
244: CAN_QUEUE, CMD_PER_LUN, GENERIC_NCR5380_PUBLIC_RELEASE);
245: NCR5380_print_options(instance);
246: printk("\n");
247:
248: ++current_override;
249: ++count;
250: }
251: return count;
252: }
253:
254: const char * generic_NCR5380_info (void) {
255: static const char string[]="Generic NCR5380/53C400 Info";
256: return string;
257: }
258:
259: int generic_NCR5380_release_resources(struct Scsi_Host * instance)
260: {
261: NCR5380_local_declare();
262:
263: NCR5380_setup(instance);
264:
265: free_irq(instance->irq);
266:
267: return 0;
268: }
269:
270: #ifdef BIOSPARAM
271: /*
272: * Function : int generic_NCR5380_biosparam(Disk * disk, kdev_t dev, int *ip)
273: *
274: * Purpose : Generates a BIOS / DOS compatable H-C-S mapping for
275: * the specified device / size.
276: *
277: * Inputs : size = size of device in sectors (512 bytes), dev = block device
278: * major / minor, ip[] = {heads, sectors, cylinders}
279: *
280: * Returns : allways 0 (success), initializes ip
281: *
282: */
283:
284: /*
285: * XXX Most SCSI boards use this mapping, I could be incorrect. Some one
286: * using hard disks on a trantor should verify that this mapping corresponds
287: * to that used by the BIOS / ASPI driver by running the linux fdisk program
288: * and matching the H_C_S coordinates to what DOS uses.
289: */
290:
291: int generic_NCR5380_biosparam(Disk * disk, kdev_t dev, int *ip)
292: {
293: int size = disk->capacity;
294: ip[0] = 64;
295: ip[1] = 32;
296: ip[2] = size >> 11;
297: return 0;
298: }
299: #endif
300:
301: int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int length, int hostno, int inout)
302: {
303: int len = 0;
304: struct Scsi_Host *scsi_ptr;
305:
306: for (scsi_ptr = first_instance; scsi_ptr; scsi_ptr=scsi_ptr->next)
307: if (scsi_ptr->host_no == hostno)
308: break;
309:
310: len += sprintf(buffer+len, "SCSI host number %d : %s\n", scsi_ptr->host_no, scsi_ptr->hostt->name);
311: len += sprintf(buffer+len, "Generic NCR5380 driver version %d\n", GENERIC_NCR5380_PUBLIC_RELEASE);
312: len += sprintf(buffer+len, "NCR5380 driver core version %d\n", NCR5380_PUBLIC_RELEASE);
313: #ifdef NCR53C400
314: len += sprintf(buffer+len, "NCR53C400 driver extension version %d\n", NCR53C400_PUBLIC_RELEASE);
315: len += sprintf(buffer+len, "NCR53C400 card%s detected\n", (((struct NCR5380_hostdata *)scsi_ptr->hostdata)->flags & FLAG_NCR53C400)?"":" not");
316: # if NCR53C400_PSEUDO_DMA
317: len += sprintf(buffer+len, "NCR53C400 pseudo DMA being used\n");
318: # endif
319: #else
320: len += sprintf(buffer+len, "NO NCR53C400 driver extensions\n");
321: #endif
322: len += sprintf(buffer+len, "Using %s mapping at %s 0x%x, ", STRVAL(NCR5380_map_config), STRVAL(NCR5380_map_name), scsi_ptr->NCR5380_instance_name);
323: if (scsi_ptr->irq == IRQ_NONE)
324: len += sprintf(buffer+len, "interrupts disabled\n");
325: else
326: len += sprintf(buffer+len, "on interrupt %d\n", scsi_ptr->irq);
327:
328: *start = buffer + offset;
329: len -= offset;
330: if (len > length)
331: len = length;
332: return len;
333: }
334:
335: #if NCR53C400_PSEUDO_DMA
336: static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst, int len)
337: {
338: int blocks = len / 128;
339: int start = 0;
340: int i;
341: int bl;
342: NCR5380_local_declare();
343:
344: NCR5380_setup(instance);
345:
346: #if (NDEBUG & NDEBUG_C400_PREAD)
347: printk("53C400r: About to read %d blocks for %d bytes\n", blocks, len);
348: #endif
349:
350: NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE | CSR_TRANS_DIR);
351: NCR5380_write(C400_BLOCK_COUNTER_REG, blocks);
352: while (1) {
353:
354: #if (NDEBUG & NDEBUG_C400_PREAD)
355: printk("53C400r: %d blocks left\n", blocks);
356: #endif
357:
358: if ((bl=NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) {
359: #if (NDEBUG & NDEBUG_C400_PREAD)
360: if (blocks)
361: printk("53C400r: blocks still == %d\n", blocks);
362: else
363: printk("53C400r: Exiting loop\n");
364: #endif
365: break;
366: }
367:
368: #if 1
369: if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) {
370: printk("53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
371: return -1;
372: }
373: #endif
374:
375: #if (NDEBUG & NDEBUG_C400_PREAD)
376: printk("53C400r: Waiting for buffer, bl=%d\n", bl);
377: #endif
378:
379: while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
380: ;
381: #if (NDEBUG & NDEBUG_C400_PREAD)
382: printk("53C400r: Transferring 128 bytes\n");
383: #endif
384:
385: #ifdef CONFIG_SCSI_G_NCR5380_PORT
386: for (i=0; i<128; i++)
387: dst[start+i] = NCR5380_read(C400_HOST_BUFFER);
388: #else
389: /* implies CONFIG_SCSI_G_NCR5380_MEM */
390: memmove(dst+start,NCR53C400_host_buffer+NCR5380_map_name,128);
391: #endif
392: start+=128;
393: blocks--;
394: }
395:
396: #if (NDEBUG & NDEBUG_C400_PREAD)
397: printk("53C400r: EXTRA: Waiting for buffer\n");
398: #endif
399: while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
400: ;
401:
402: #if (NDEBUG & NDEBUG_C400_PREAD)
403: printk("53C400r: Transferring EXTRA 128 bytes\n");
404: #endif
405: #ifdef CONFIG_SCSI_G_NCR5380_PORT
406: for (i=0; i<128; i++)
407: dst[start+i] = NCR5380_read(C400_HOST_BUFFER);
408: #else
409: /* implies CONFIG_SCSI_G_NCR5380_MEM */
410: memmove(dst+start,NCR53C400_host_buffer+NCR5380_map_name,128);
411: #endif
412: start+=128;
413: blocks--;
414:
415: #if (NDEBUG & NDEBUG_C400_PREAD)
416: printk("53C400r: Final values: blocks=%d start=%d\n", blocks, start);
417: #endif
418:
419: if (!(NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ))
420: printk("53C400r: no 53C80 gated irq after transfer");
421: #if (NDEBUG & NDEBUG_C400_PREAD)
422: else
423: printk("53C400r: Got 53C80 interupt and tried to clear it\n");
424: #endif
425:
426: /* DON'T DO THIS - THEY NEVER ARRIVE!
427: printk("53C400r: Waiting for 53C80 registers\n");
428: while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG)
429: ;
430: */
431:
432: if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER))
433: printk("53C400r: no end dma signal\n");
434: #if (NDEBUG & NDEBUG_C400_PREAD)
435: else
436: printk("53C400r: end dma as expected\n");
437: #endif
438:
439: NCR5380_write(MODE_REG, MR_BASE);
440: NCR5380_read(RESET_PARITY_INTERRUPT_REG);
441: return 0;
442: }
443:
444: static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src, int len)
445: {
446: int blocks = len / 128;
447: int start = 0;
448: int i;
449: int bl;
450: NCR5380_local_declare();
451:
452: NCR5380_setup(instance);
453:
454: #if (NDEBUG & NDEBUG_C400_PWRITE)
455: printk("53C400w: About to write %d blocks for %d bytes\n", blocks, len);
456: #endif
457:
458: NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE);
459: NCR5380_write(C400_BLOCK_COUNTER_REG, blocks);
460: while (1) {
461: if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) {
462: printk("53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
463: return -1;
464: }
465:
466: if ((bl=NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) {
467: #if (NDEBUG & NDEBUG_C400_PWRITE)
468: if (blocks)
469: printk("53C400w: exiting loop, blocks still == %d\n", blocks);
470: else
471: printk("53C400w: exiting loop\n");
472: #endif
473: break;
474: }
475:
476: #if (NDEBUG & NDEBUG_C400_PWRITE)
477: printk("53C400w: %d blocks left\n", blocks);
478:
479: printk("53C400w: waiting for buffer, bl=%d\n", bl);
480: #endif
481: while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
482: ;
483:
484: #if (NDEBUG & NDEBUG_C400_PWRITE)
485: printk("53C400w: transferring 128 bytes\n");
486: #endif
487: #ifdef CONFIG_SCSI_G_NCR5380_PORT
488: for (i=0; i<128; i++)
489: NCR5380_write(C400_HOST_BUFFER, src[start+i]);
490: #else
491: /* implies CONFIG_SCSI_G_NCR5380_MEM */
492: memmove(NCR53C400_host_buffer+NCR5380_map_name,src+start,128);
493: #endif
494: start+=128;
495: blocks--;
496: }
497: if (blocks) {
498: #if (NDEBUG & NDEBUG_C400_PWRITE)
499: printk("53C400w: EXTRA waiting for buffer\n");
500: #endif
501: while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
502: ;
503:
504: #if (NDEBUG & NDEBUG_C400_PWRITE)
505: printk("53C400w: transferring EXTRA 128 bytes\n");
506: #endif
507: #ifdef CONFIG_SCSI_G_NCR5380_PORT
508: for (i=0; i<128; i++)
509: NCR5380_write(C400_HOST_BUFFER, src[start+i]);
510: #else
511: /* implies CONFIG_SCSI_G_NCR5380_MEM */
512: memmove(NCR53C400_host_buffer+NCR5380_map_name,src+start,128);
513: #endif
514: start+=128;
515: blocks--;
516: }
517: #if (NDEBUG & NDEBUG_C400_PWRITE)
518: else
519: printk("53C400w: No EXTRA required\n");
520: #endif
521:
522: #if (NDEBUG & NDEBUG_C400_PWRITE)
523: printk("53C400w: Final values: blocks=%d start=%d\n", blocks, start);
524: #endif
525:
526: #if 0
527: printk("53C400w: waiting for registers to be available\n");
528: THEY NEVER DO!
529: while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG)
530: ;
531: printk("53C400w: Got em\n");
532: #endif
533:
534: /* Let's wait for this instead - could be ugly */
535: /* All documentation says to check for this. Maybe my hardware is too
536: * fast. Waiting for it seems to work fine! KLL
537: */
538: while (!(i = NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ))
539: ;
540:
541: /*
542: * I know. i is certainly != 0 here but the loop is new. See previous
543: * comment.
544: */
545: if (i) {
546: #if (NDEBUG & NDEBUG_C400_PWRITE)
547: prink("53C400w: got 53C80 gated irq (last block)\n");
548: #endif
549: if (!((i=NCR5380_read(BUS_AND_STATUS_REG)) & BASR_END_DMA_TRANSFER))
550: printk("53C400w: No END OF DMA bit - WHOOPS! BASR=%0x\n",i);
551: #if (NDEBUG & NDEBUG_C400_PWRITE)
552: else
553: printk("53C400w: Got END OF DMA\n");
554: #endif
555: }
556: else
557: printk("53C400w: no 53C80 gated irq after transfer (last block)\n");
558:
559: #if 0
560: if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) {
561: printk("53C400w: no end dma signal\n");
562: }
563: #endif
564:
565: #if (NDEBUG & NDEBUG_C400_PWRITE)
566: printk("53C400w: waiting for last byte...\n");
567: #endif
568: while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT))
569: ;
570:
571: #if (NDEBUG & NDEBUG_C400_PWRITE)
572: printk("53C400w: got last byte.\n");
573: printk("53C400w: pwrite exiting with status 0, whoopee!\n");
574: #endif
575: return 0;
576: }
577: #endif /* PSEUDO_DMA */
578:
579: #ifdef MACH
580: #include "NCR5380.src"
581: #else
582: #include "NCR5380.c"
583: #endif
584:
585: #ifdef MODULE
586: /* Eventually this will go into an include file, but this will be later */
587: Scsi_Host_Template driver_template = GENERIC_NCR5380;
588:
589: #include <linux/module.h>
590: #include "scsi_module.c"
591: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.