This source file includes following definitions.
- outw
- do_pause
- fdomain_make_bus_idle
- fdomain_is_valid_port
- fdomain_test_loopback
- fdomain_enable_interrupt
- fdomain_disable_interrupt
- fdomain_16x0_detect
- fdomain_16x0_info
- fdomain_arbitrate
- fdomain_select
- my_done
- fdomain_16x0_intr
- fdomain_16x0_queue
- fdomain_16x0_command
- fdomain_16x0_abort
- fdomain_16x0_reset
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 #include <linux/config.h>
41
42 #ifdef CONFIG_SCSI_FUTURE_DOMAIN
43
44 #include <linux/sched.h>
45 #include <asm/io.h>
46 #include "fdomain.h"
47 #include "scsi.h"
48 #include "hosts.h"
49 #if QUEUE
50 #include <asm/system.h>
51 #include <linux/errno.h>
52 #endif
53
54 #define VERSION "1.9"
55 #define DEBUG 1
56 #define SEND_IDENTIFY 0
57 #define USE_FIFO 1
58 #define FAST_SYNCH 1
59 #define ALLOW_ALL_IRQ 0
60 #define NEW_IRQ 1
61 #define DECREASE_IL 1
62
63 #if DEBUG
64 #define EVERY_ACCESS 0
65 #define ERRORS_ONLY 1
66 #define DEBUG_DETECT 0
67 #else
68 #define EVERY_ACCESS 0
69 #define ERRORS_ONLY 0
70 #define DEBUG_DETECT 0
71 #endif
72
73
74 #if EVERY_ACCESS
75 #undef ERRORS_ONLY
76 #define ERRORS_ONLY 0
77 #endif
78
79 static int port_base = 0;
80 static void *bios_base = NULL;
81 static int interrupt_level = 0;
82 static volatile int aborted = 0;
83
84 static int Data_Mode_Cntl_port;
85 static int FIFO_Data_Count_port;
86 static int Interrupt_Cntl_port;
87 static int Read_FIFO_port;
88 static int Read_SCSI_Data_port;
89 static int SCSI_Cntl_port;
90 static int SCSI_Status_port;
91 static int TMC_Cntl_port;
92 static int TMC_Status_port;
93 static int Write_FIFO_port;
94 static int Write_SCSI_Data_port;
95
96 #if QUEUE
97 static unsigned char current_target = 0;
98 static unsigned char current_cmnd[10] = { 0, };
99 static void *current_buff = NULL;
100 static int current_bufflen = 0;
101 static void (*current_done)(int,int) = NULL;
102
103 volatile static int in_command = 0;
104 volatile static int current_phase;
105 static int this_host = 0;
106
107 enum { in_arbitration, in_selection, in_other };
108
109 #if NEW_IRQ
110 extern void fdomain_16x0_intr( int unused );
111 #else
112 extern void fdomain_16x0_interrupt();
113 #endif
114
115 static const char *cmd_pt;
116 static const char *the_command;
117 static unsigned char *out_buf_pt;
118 static unsigned char *in_buf_pt;
119 volatile static int Status;
120 volatile static int Message;
121 volatile static unsigned data_sent;
122 volatile static int have_data_in;
123
124 volatile static int in_interrupt_code = 0;
125
126 #endif
127
128
129 enum in_port_type { Read_SCSI_Data = 0, SCSI_Status = 1, TMC_Status = 2,
130 LSB_ID_Code = 5, MSB_ID_Code = 6, Read_Loopback = 7,
131 SCSI_Data_NoACK = 8, Option_Select = 10,
132 Read_FIFO = 12, FIFO_Data_Count = 14 };
133
134 enum out_port_type { Write_SCSI_Data = 0, SCSI_Cntl = 1, Interrupt_Cntl = 2,
135 Data_Mode_Cntl = 3, TMC_Cntl = 4, Write_Loopback = 7,
136 Write_FIFO = 12 };
137
138 static void *addresses[] = {
139 (void *)0xc8000,
140 (void *)0xca000,
141 (void *)0xce000,
142 (void *)0xde000 };
143 #define ADDRESS_COUNT (sizeof( addresses ) / sizeof( unsigned ))
144
145 static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };
146 #define PORT_COUNT (sizeof( ports ) / sizeof( unsigned short ))
147
148 static unsigned short ints[] = { 3, 5, 10, 11, 12, 14, 15, 0 };
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184 struct signature {
185 char *signature;
186 int sig_offset;
187 int sig_length;
188 } signatures[] = {
189 { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.0 7/28/89", 5, 50 },
190 { "FUTURE DOMAIN CORP. (C) 1986-1990 1800", 5, 37 },
191
192 };
193
194 #define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature ))
195
196
197
198
199 #if 1
200 static unsigned short inline inw( unsigned short port )
201 {
202 unsigned short _v;
203
204 __asm__ volatile ("inw %1,%0"
205 :"=a" (_v):"d" ((unsigned short) port));
206 return _v;
207 }
208
209 static void inline outw( unsigned short value, unsigned short port )
210 {
211 __asm__ volatile ("outw %0,%1"
212 ::"a" ((unsigned short) value),
213 "d" ((unsigned short) port));
214 }
215 #else
216
217 #define inw( port ) \
218 ({ unsigned short _v; \
219 __asm__ volatile ("inw %1,%0" \
220 : "=a" (_v) : "d" ((unsigned short) port)); \
221 _v; })
222
223 #define outw( value ) \
224 __asm__ volatile \
225 ("outw %0,%1" : : "a" ((unsigned short) value), \
226 "d" ((unsigned short) port))
227 #endif
228
229
230
231
232 #define insw( buf, count, port ) \
233 __asm__ volatile \
234 ( "cld;rep;insw"::"d" (port),"D" (buf),"c" (count):"cx","di" )
235
236 #define outsw( buf, count, port) \
237 __asm__ volatile \
238 ("cld;rep;outsw"::"d" (port),"S" (buf),"c" (count):"cx","si")
239
240
241 static void do_pause( unsigned amount )
242 {
243 unsigned long the_time = jiffies + amount;
244
245 while (jiffies < the_time);
246 }
247
248 static void inline fdomain_make_bus_idle( void )
249 {
250 outb( 0, SCSI_Cntl_port );
251 outb( 0, Data_Mode_Cntl_port );
252 outb( 1, TMC_Cntl_port );
253 }
254
255 static int fdomain_is_valid_port( int port )
256 {
257 int options;
258
259 #if DEBUG_DETECT
260 printk( " (%x%x),",
261 inb( port + MSB_ID_Code ), inb( port + LSB_ID_Code ) );
262 #endif
263
264
265
266
267
268
269
270 if (inb( port + LSB_ID_Code ) != 0xe9) {
271 if (inb( port + LSB_ID_Code ) != 0x27) return 0;
272 if (inb( port + MSB_ID_Code ) != 0x61) return 0;
273 } else {
274 if (inb( port + MSB_ID_Code ) != 0x60) return 0;
275 }
276
277
278
279
280
281
282
283
284 options = inb( port + Option_Select );
285
286 #if DEBUG_DETECT
287 printk( " Options = %x,", options );
288 #endif
289
290 if (addresses[ (options & 0xc0) >> 6 ] != bios_base) return 0;
291 interrupt_level = ints[ (options & 0x0e) >> 1 ];
292
293 return 1;
294 }
295
296 static int fdomain_test_loopback( void )
297 {
298 int i;
299 int result;
300
301 for (i = 0; i < 255; i++) {
302 outb( i, port_base + Write_Loopback );
303 result = inb( port_base + Read_Loopback );
304 if (i != result) return 1;
305 }
306 return 0;
307 }
308
309 #if !NEW_IRQ
310 static void fdomain_enable_interrupt( void )
311 {
312 if (!interrupt_level) return;
313
314 #if ALLOW_ALL_IRQ
315 if (interrupt_level < 8) {
316 outb( inb_p( 0x21 ) & ~(1 << interrupt_level), 0x21 );
317 } else
318 #endif
319 {
320 outb( inb_p( 0xa1 ) & ~(1 << (interrupt_level - 8)), 0xa1 );
321 }
322 }
323
324 static void fdomain_disable_interrupt( void )
325 {
326 if (!interrupt_level) return;
327
328 #if ALLOW_ALL_IRQ
329 if (interrupt_level < 8) {
330 outb( inb_p( 0x21 ) | (1 << interrupt_level), 0x21 );
331 } else
332 #endif
333 {
334 outb( inb_p( 0xa1 ) | (1 << (interrupt_level - 8)), 0xa1 );
335 }
336 }
337 #endif
338
339 int fdomain_16x0_detect( int hostnum )
340 {
341 int i, j;
342 int flag;
343 unsigned char do_inquiry[] = { 0x12, 0, 0, 0, 255, 0 };
344 unsigned char do_request_sense[] = { 0x03, 0, 0, 0, 255, 0 };
345 unsigned char do_read_capacity[] = { 0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
346 unsigned char buf[256];
347 unsigned retcode;
348
349 #if DEBUG_DETECT
350 printk( "SCSI: fdomain_16x0_detect()," );
351 #endif
352
353 for (i = 0; !bios_base && i < ADDRESS_COUNT; i++) {
354 #if DEBUG_DETECT
355 printk( " %x(%x),", (unsigned)addresses[i], (unsigned)bios_base );
356 #endif
357 for (j = 0; !bios_base && j < SIGNATURE_COUNT; j++) {
358 if (!memcmp( ((char *)addresses[i] + signatures[j].sig_offset),
359 signatures[j].signature, signatures[j].sig_length )) {
360 bios_base = addresses[i];
361 }
362 }
363 }
364
365 if (!bios_base) {
366 #if DEBUG_DETECT
367 printk( " FAILED: NO BIOS\n" );
368 #endif
369 return 0;
370 }
371
372
373
374
375
376
377
378
379
380 port_base = *((char *)bios_base + 0x1fcc)
381 + (*((char *)bios_base + 0x1fcd) << 8);
382
383 #if DEBUG_DETECT
384 printk( " %x,", port_base );
385 #endif
386
387 for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) {
388 if (port_base == ports[i]) ++flag;
389 }
390
391 if (flag) flag = fdomain_is_valid_port( port_base );
392
393 if (!flag) {
394
395
396
397
398
399
400 #if DEBUG_DETECT
401 printk( " RAM FAILED, " );
402 #endif
403
404
405
406
407
408
409
410
411 for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) {
412 port_base = ports[i];
413 #if DEBUG_DETECT
414 printk( " %x,", port_base );
415 #endif
416 flag = fdomain_is_valid_port( port_base );
417 }
418 }
419
420 if (!flag) {
421 #if DEBUG_DETECT
422 printk( " FAILED: NO PORT\n" );
423 #endif
424 return 0;
425 }
426
427 #if DEBUG_DETECT
428 printk( "\n" );
429 printk( "SCSI: bios_base = %x, port_base = %x, interrupt_level = %d\n",
430 (unsigned)bios_base, port_base, interrupt_level );
431 #endif
432
433 if (interrupt_level) {
434 printk( "Future Domain BIOS at %x; port base at %x; using IRQ %d\n",
435 (unsigned)bios_base, port_base, interrupt_level );
436 } else {
437 printk( "Future Domain BIOS at %x; port base at %x; *NO* IRQ\n",
438 (unsigned)bios_base, port_base );
439 }
440
441 Data_Mode_Cntl_port = port_base + Data_Mode_Cntl;
442 FIFO_Data_Count_port = port_base + FIFO_Data_Count;
443 Interrupt_Cntl_port = port_base + Interrupt_Cntl;
444 Read_FIFO_port = port_base + Read_FIFO;
445 Read_SCSI_Data_port = port_base + Read_SCSI_Data;
446 SCSI_Cntl_port = port_base + SCSI_Cntl;
447 SCSI_Status_port = port_base + SCSI_Status;
448 TMC_Cntl_port = port_base + TMC_Cntl;
449 TMC_Status_port = port_base + TMC_Status;
450 Write_FIFO_port = port_base + Write_FIFO;
451 Write_SCSI_Data_port = port_base + Write_SCSI_Data;
452
453 fdomain_16x0_reset();
454
455 if (fdomain_test_loopback()) {
456 #if DEBUG_DETECT
457 printk( "SCSI: LOOPBACK TEST FAILED, FAILING DETECT!\n" );
458 #endif
459 return 0;
460 }
461
462
463
464
465
466
467 printk( "Future Domain detection routine scanning for devices:\n" );
468 for (i = 0; i < 8; i++) {
469 if (i == 6) continue;
470 retcode = fdomain_16x0_command( i, do_request_sense, buf, 255 );
471 if (!retcode) {
472 retcode = fdomain_16x0_command( i, do_inquiry, buf, 255 );
473 if (!retcode) {
474 printk( " SCSI ID %d: ", i );
475 for (j = 8; j < 32; j++) printk( "%c", buf[j] );
476 retcode = fdomain_16x0_command( i, do_read_capacity, buf, 255 );
477 if (!retcode) {
478 unsigned long blocks, size, capacity;
479
480 blocks = (buf[0] << 24) | (buf[1] << 16)
481 | (buf[2] << 8) | buf[3];
482 size = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
483 capacity = +(blocks * size * 10) / +(1024L * 1024L);
484
485 printk( "%lu MB (%lu byte blocks)",
486 ((capacity + 5L) / 10L), size );
487 }
488 printk ("\n" );
489 }
490 }
491 }
492
493 #if QUEUE
494 #if !ALLOW_ALL_IRQ
495 if (interrupt_level < 8) {
496 printk( "Future Domain: WILL NOT USE IRQ LESS THAN 8 FOR QUEUEING!\n" );
497 scsi_hosts[hostnum].can_queue = 0;
498 } else
499 #endif
500 #if NEW_IRQ
501 {
502 int retcode;
503 struct sigaction sa;
504
505 this_host = hostnum;
506
507 sa.sa_handler = fdomain_16x0_intr;
508 sa.sa_flags = SA_INTERRUPT;
509 sa.sa_mask = 0;
510 sa.sa_restorer = NULL;
511
512 retcode = irqaction( interrupt_level, &sa );
513
514 if (retcode < 0) {
515 if (retcode == -EINVAL) {
516 printk( "Future Domain: IRQ %d is bad!\n", interrupt_level );
517 printk( " This shouldn't happen: REPORT TO RIK!\n" );
518 } else if (retcode == -EBUSY) {
519 printk( "Future Domain: IRQ %d is already in use!\n",
520 interrupt_level );
521 printk( " Please use another IRQ for the FD card!\n" );
522 } else {
523 printk( "Future Domain: Error getting IRQ %d\n",
524 interrupt_level );
525 printk( " This shouldn't happen: REPORT TO RIK!\n" );
526 }
527 printk( " IRQs WILL NOT BE USED!\n" );
528
529 scsi_hosts[this_host].can_queue = 0;
530 } else {
531 printk( "Future Domain: IRQ %d selected with retcode = %d\n",
532 interrupt_level, retcode );
533 }
534 }
535 #else
536 {
537 this_host = hostnum;
538 set_intr_gate( 0x20 + interrupt_level, &fdomain_16x0_interrupt );
539 fdomain_enable_interrupt();
540 }
541 #endif
542 #endif
543
544 return 1;
545 }
546
547 char *fdomain_16x0_info(void)
548 {
549 static char buffer[] =
550 "Future Domain TMC-1660/TMC-1680 SCSI driver version "
551 VERSION
552 "\n";
553 return buffer;
554 }
555
556 static int fdomain_arbitrate( void )
557 {
558 int status = 0;
559 unsigned long timeout;
560
561 #if VERBOSE
562 printk( "SCSI: fdomain_arbitrate()\n" );
563 #endif
564
565 outb( 0x00, SCSI_Cntl_port );
566 outb( 0x40, port_base + SCSI_Data_NoACK );
567 outb( 0x04, TMC_Cntl_port );
568
569 timeout = jiffies + 50;
570 while (jiffies < timeout) {
571 status = inb( TMC_Status_port );
572 if (status & 0x02) return 0;
573 }
574
575
576 fdomain_make_bus_idle();
577
578 #if EVERY_ACCESS
579 printk( "Arbitration failed, status = %x\n", status );
580 #endif
581 #if ERRORS_ONLY
582 printk( "SCSI: Arbitration failed, status = %x", status );
583 #endif
584 return 1;
585 }
586
587 static int fdomain_select( int target )
588 {
589 int status;
590 unsigned long timeout;
591
592 outb( 0x80, SCSI_Cntl_port );
593 outb( 0x8a, SCSI_Cntl_port );
594
595
596 #if SEND_IDENTIFY
597 outb( 0x40 | (1 << target), port_base + SCSI_Data_NoACK );
598 #else
599 outb( (1 << target), port_base + SCSI_Data_NoACK );
600 #endif
601
602
603 outb( 0xc8, TMC_Cntl_port );
604
605 timeout = jiffies + 25;
606 while (jiffies < timeout) {
607 status = inb( SCSI_Status_port );
608 if (status & 1) {
609
610 #if SEND_IDENTIFY
611
612 outb( 0x88, SCSI_Cntl_port );
613 #else
614 outb( 0x80, SCSI_Cntl_port );
615 #endif
616 return 0;
617 }
618 }
619
620 fdomain_make_bus_idle();
621 #if EVERY_ACCESS
622 if (!target) printk( "Select failed\n" );
623 #endif
624 #if ERRORS_ONLY
625 if (!target) printk( "SCSI: Select failed" );
626 #endif
627 return 1;
628 }
629
630 #if QUEUE
631
632 #if !USE_FIFO
633 #pragma error QUEUE requires USE_FIFO
634 #endif
635
636 void my_done( int error )
637 {
638 if (in_command) {
639 in_command = 0;
640 in_interrupt_code = 0;
641 outb( 0x00, Interrupt_Cntl_port );
642 fdomain_make_bus_idle();
643 if (current_done) current_done( this_host, error );
644 else panic( "SCSI (Future Domain): current_done() == NULL" );
645 } else {
646 panic( "SCSI (Future Domain): my_done() called outside of command\n" );
647 }
648 }
649
650 #if NEW_IRQ
651 void fdomain_16x0_intr( int unused )
652 #else
653 void fdomain_16x0_intr( void )
654 #endif
655 {
656 int status;
657 int done = 0;
658 unsigned data_count;
659
660 #if NEW_IRQ
661 sti();
662 #endif
663
664 if (in_interrupt_code)
665 panic( "SCSI (Future Domain): fdomain_16x0_intr() NOT REENTRANT!\n" );
666 else
667 ++in_interrupt_code;
668
669 outb( 0x00, Interrupt_Cntl_port );
670
671 #if EVERY_ACCESS
672 printk( "aborted = %d, ", aborted );
673 #endif
674
675 if (aborted) {
676
677 if (current_phase == in_other)
678 my_done( DID_BUS_BUSY << 16 );
679 else
680 my_done( aborted << 16 );
681 #if NEW_IRQ && !DECREASE_IL
682 cli();
683 #endif
684 return;
685 }
686
687
688 if (!in_command) {
689 in_interrupt_code = 0;
690 #if NEW_IRQ && !DECREASE_IL
691 cli();
692 #endif
693 return;
694 }
695
696 if (current_phase == in_arbitration) {
697 status = inb( TMC_Status_port );
698 if (!(status & 0x02)) {
699 #if EVERY_ACCESS
700 printk( " AFAIL " );
701 #endif
702 my_done( DID_TIME_OUT << 16 );
703 #if NEW_IRQ && !DECREASE_IL
704 cli();
705 #endif
706 return;
707 }
708 current_phase = in_selection;
709
710 outb( 0x80, SCSI_Cntl_port );
711 outb( 0x8a, SCSI_Cntl_port );
712
713 outb( (1 << current_target), port_base + SCSI_Data_NoACK );
714
715 outb( 0x40, Interrupt_Cntl_port );
716
717 in_interrupt_code = 0;
718 outb( 0xd8, TMC_Cntl_port );
719 #if NEW_IRQ && !DECREASE_IL
720 cli();
721 #endif
722 return;
723 } else if (current_phase == in_selection) {
724 status = inb( SCSI_Status_port );
725 if (!(status & 0x01)) {
726 #if EVERY_ACCESS
727 printk( " SFAIL " );
728 #endif
729 my_done( DID_NO_CONNECT << 16 );
730 #if NEW_IRQ && !DECREASE_IL
731 cli();
732 #endif
733 return;
734 }
735 current_phase = in_other;
736 #if FAST_SYNCH
737 outb( 0xc0, Data_Mode_Cntl_port );
738 #endif
739 in_interrupt_code = 0;
740 outb( 0x90, Interrupt_Cntl_port );
741 outb( 0x80, SCSI_Cntl_port );
742 #if NEW_IRQ && !DECREASE_IL
743 cli();
744 #endif
745 return;
746 }
747
748
749
750 switch ((unsigned char)*the_command) {
751 case 0x04: case 0x07: case 0x0a: case 0x15: case 0x2a:
752 case 0x2e: case 0x3b: case 0xea: case 0x3f:
753 data_count = 0x2000 - inw( FIFO_Data_Count_port );
754 if (current_bufflen - data_sent < data_count)
755 data_count = current_bufflen - data_sent;
756 if (data_count > 0) {
757
758 #if EVERY_ACCESS
759 printk( "%d OUT, ", data_count );
760 #endif
761 if (data_count == 1) {
762 outb( *out_buf_pt++, Write_FIFO_port );
763 ++data_sent;
764 } else {
765 data_count >>= 1;
766 outsw( out_buf_pt, data_count, Write_FIFO_port );
767 out_buf_pt += 2 * data_count;
768 data_sent += 2 * data_count;
769 }
770 }
771 break;
772 default:
773 if (!have_data_in) {
774 outb( 0x98, TMC_Cntl_port );
775 ++have_data_in;
776 } else {
777 data_count = inw( FIFO_Data_Count_port );
778
779 if (data_count) {
780 #if EVERY_ACCESS
781 printk( "%d IN, ", data_count );
782 #endif
783 if (data_count == 1) {
784 *in_buf_pt++ = inb( Read_FIFO_port );
785 } else {
786 data_count >>= 1;
787 insw( in_buf_pt, data_count, Read_FIFO_port );
788 in_buf_pt += 2 * data_count;
789 }
790 }
791 }
792 break;
793 }
794
795 status = inb( SCSI_Status_port );
796
797 if (status & 0x10) {
798
799 switch (status & 0x0e) {
800 case 0x08:
801 outb( *cmd_pt++, Write_SCSI_Data_port );
802 #if EVERY_ACCESS
803 printk( "CMD = %x,", (unsigned char)cmd_pt[-1] );
804 #endif
805 break;
806 case 0x0c:
807 Status = inb( Read_SCSI_Data_port );
808 #if EVERY_ACCESS
809 printk( "Status = %x, ", Status );
810 #endif
811 #if ERRORS_ONLY
812 if (Status) {
813 printk( "SCSI: target = %d, command = %x, Status = %x\n",
814 current_target, (unsigned char)*the_command, Status );
815 }
816 #endif
817 break;
818 case 0x0a:
819 #if SEND_IDENTIFY
820
821 if (!sent_identify) {
822 outb( 0x80, SCSI_Cntl_port );
823 outb( 0x80, Write_SCSI_Data_port );
824 ++sent_identify;
825 } else
826 #else
827 outb( 0x07, Write_SCSI_Data_port );
828 #endif
829 break;
830 case 0x0e:
831 Message = inb( Read_SCSI_Data_port );
832 #if EVERY_ACCESS
833 printk( "Message = %x, ", Message );
834 #endif
835 if (!Message) ++done;
836 break;
837 }
838 }
839
840 if (done) {
841 #if EVERY_ACCESS
842 printk( " ** IN DONE ** " );
843 #endif
844
845 if (have_data_in) {
846 while (data_count = inw( FIFO_Data_Count_port )) {
847 if (data_count == 1) {
848 *in_buf_pt++ = inb( Read_FIFO_port );
849 } else {
850 data_count >>= 1;
851 insw( in_buf_pt, data_count, Read_FIFO_port );
852 in_buf_pt += 2 * data_count;
853 }
854 }
855 }
856 #if EVERY_ACCESS
857 printk( "AFTER DATA GET\n" );
858 #endif
859
860 #if ERRORS_ONLY
861 if (*the_command == REQUEST_SENSE && !Status) {
862 if ((unsigned char)(*((char *)current_buff + 2)) & 0x0f) {
863 printk( "SCSI REQUEST SENSE: Sense Key = %x, Sense Code = %x\n",
864 (unsigned char)(*((char *)current_buff + 2)) & 0x0f,
865 (unsigned char)(*((char *)current_buff + 12)) );
866 }
867 }
868 #endif
869 #if EVERY_ACCESS
870 printk( "BEFORE MY_DONE\n" );
871 #endif
872 my_done( (Status & 0xff) | ((Message & 0xff) << 8) | (DID_OK << 16) );
873 } else {
874 in_interrupt_code = 0;
875 outb( 0x90, Interrupt_Cntl_port );
876 }
877
878 #if NEW_IRQ && !DECREASE_IL
879 cli();
880 #endif
881 return;
882 }
883
884 int fdomain_16x0_queue( unsigned char target, const void *cmnd,
885 void *buff, int bufflen, void (*done)(int,int) )
886 {
887 if (in_command) {
888 panic( "SCSI (Future Domain): fdomain_16x0_queue() NOT REENTRANT!\n" );
889 }
890 #if EVERY_ACCESS
891 printk( "queue %d %x\n", target, *(unsigned char *)cmnd );
892 #endif
893
894 fdomain_make_bus_idle();
895
896 aborted = 0;
897 current_target = target;
898 memcpy( current_cmnd, cmnd, ((*(unsigned char *)cmnd) <= 0x1f ? 6 : 10 ) );
899 current_buff = buff;
900 current_bufflen = bufflen;
901 current_done = done;
902
903
904 cmd_pt = current_cmnd;
905 the_command = current_cmnd;
906 out_buf_pt = current_buff;
907 in_buf_pt = current_buff;
908
909 Status = 0;
910 Message = 0;
911 data_sent = 0;
912 have_data_in = 0;
913
914
915 current_phase = in_arbitration;
916 outb( 0x00, Interrupt_Cntl_port );
917 outb( 0x00, SCSI_Cntl_port );
918 outb( 0x40, port_base + SCSI_Data_NoACK );
919 ++in_command;
920 outb( 0x20, Interrupt_Cntl_port );
921 outb( 0x1c, TMC_Cntl_port );
922
923 return 0;
924 }
925 #endif
926
927 int fdomain_16x0_command( unsigned char target, const void *cmnd,
928 void *buff, int bufflen )
929 {
930 const char *cmd_pt = cmnd;
931 const char *the_command = cmnd;
932 unsigned char *out_buf_pt = buff;
933 unsigned char *in_buf_pt = buff;
934 int Status = 0;
935 int Message = 0;
936 int status;
937 int done = 0;
938 unsigned long timeout;
939 unsigned data_sent = 0;
940 unsigned data_count;
941 #if USE_FIFO
942 int have_data_in = 0;
943 #endif
944 #if SEND_IDENTITY
945 int sent_identify = 0;
946 #endif
947
948 #if EVERY_ACCESS
949 printk( "fdomain_command(%d, %x): ", target, (unsigned char)*the_command );
950 #endif
951
952 if (fdomain_arbitrate()) {
953 #if ERRORS_ONLY
954 printk( ", target = %d, command = %x\n",
955 target, (unsigned char)*the_command );
956 #endif
957 return DID_TIME_OUT << 16;
958 }
959
960 if (fdomain_select( target )) {
961 #if ERRORS_ONLY
962 if (!target) printk( ", target = %d, command = %x\n",
963 target, (unsigned char)*the_command );
964 #endif
965 return DID_NO_CONNECT << 16;
966 }
967
968 timeout = jiffies + 500;
969 aborted = 0;
970
971 #if FAST_SYNCH
972 outb( 0xc0, Data_Mode_Cntl_port );
973 #endif
974
975 #if USE_FIFO
976 switch ((unsigned char)*the_command) {
977 case 0x04: case 0x07: case 0x0a: case 0x15: case 0x2a:
978 case 0x2e: case 0x3b: case 0xea: case 0x3f:
979 data_count = 0x2000 - inw( FIFO_Data_Count_port );
980 if (bufflen - data_sent < data_count)
981 data_count = bufflen - data_sent;
982 if (data_count == 1) {
983 outb( *out_buf_pt++, Write_FIFO_port );
984 ++data_sent;
985 } else {
986 data_count >>= 1;
987 outsw( out_buf_pt, data_count, Write_FIFO_port );
988 out_buf_pt += 2 * data_count;
989 data_sent += 2 * data_count;
990 }
991 break;
992 default:
993 outb( 0x88, TMC_Cntl_port );
994 ++have_data_in;
995 break;
996 }
997 #endif
998
999 while (((status = inb( SCSI_Status_port )) & 1)
1000 && !done && !aborted && jiffies < timeout) {
1001
1002 if (status & 0x10) {
1003
1004 switch (status & 0x0e) {
1005 case 0x00:
1006 #if USE_FIFO
1007 data_count = 0x2000 - inw( FIFO_Data_Count_port );
1008 if (bufflen - data_sent < data_count)
1009 data_count = bufflen - data_sent;
1010 if (data_count == 1) {
1011 outb( *out_buf_pt++, Write_FIFO_port );
1012 ++data_sent;
1013 } else {
1014 data_count >>= 1;
1015 outsw( out_buf_pt, data_count, Write_FIFO_port );
1016 out_buf_pt += 2 * data_count;
1017 data_sent += 2 * data_count;
1018 }
1019 #else
1020 outb( *out_buf_pt++, Write_SCSI_Data_port );
1021 #endif
1022 break;
1023 case 0x04:
1024 #if USE_FIFO
1025 if (!have_data_in) {
1026 outb( 0x88, TMC_Cntl_port );
1027 ++have_data_in;
1028 }
1029 data_count = inw( FIFO_Data_Count_port );
1030 if (data_count == 1) {
1031 *in_buf_pt++ = inb( Read_FIFO_port );
1032 } else {
1033 data_count >>= 1;
1034 insw( in_buf_pt, data_count, Read_FIFO_port );
1035 in_buf_pt += 2 * data_count;
1036 }
1037 #else
1038 *in_buf_pt++ = inb( Read_SCSI_Data_port );
1039 #endif
1040 break;
1041 case 0x08:
1042 outb( *cmd_pt++, Write_SCSI_Data_port );
1043 #if EVERY_ACCESS
1044 printk( "%x,", (unsigned char)cmd_pt[-1] );
1045 #endif
1046 break;
1047 case 0x0c:
1048 Status = inb( Read_SCSI_Data_port );
1049 #if EVERY_ACCESS
1050 printk( "Status = %x, ", Status );
1051 #endif
1052 #if ERRORS_ONLY
1053 if (Status) {
1054 printk( "SCSI: target = %d, command = %x, Status = %x\n",
1055 target, (unsigned char)*the_command, Status );
1056 }
1057 #endif
1058 break;
1059 case 0x0a:
1060 #if SEND_IDENTIFY
1061
1062 if (!sent_identify) {
1063 outb( 0x80, SCSI_Cntl_port );
1064 outb( 0x80, Write_SCSI_Data_port );
1065 ++sent_identify;
1066 } else
1067 #else
1068 outb( 0x07, Write_SCSI_Data_port );
1069 #endif
1070 break;
1071 case 0x0e:
1072 Message = inb( Read_SCSI_Data_port );
1073 #if EVERY_ACCESS
1074 printk( "Message = %x, ", Message );
1075 #endif
1076 if (!Message) ++done;
1077 break;
1078 }
1079 }
1080 }
1081
1082 if (jiffies >= timeout) {
1083 #if EVERY_ACCESS
1084 printk( "Time out, status = %x\n", status );
1085 #endif
1086 #if ERRORS_ONLY
1087 printk( "SCSI: Time out, status = %x (target = %d, command = %x)\n",
1088 status, target, (unsigned char)*the_command );
1089 #endif
1090 fdomain_make_bus_idle();
1091 return DID_BUS_BUSY << 16;
1092 }
1093
1094 if (aborted) {
1095 #if EVERY_ACCESS
1096 printk( "Aborted\n" );
1097 #endif
1098 #if ONLY_ERRORS
1099 printk( "SCSI: Aborted (command = %x)\n", (unsigned char)*the_command );
1100 #endif
1101 fdomain_16x0_reset();
1102 return DID_ABORT << 16;
1103 }
1104
1105 #if USE_FIFO
1106 if (have_data_in) {
1107 while (data_count = inw( FIFO_Data_Count_port )) {
1108 if (data_count == 1) {
1109 *in_buf_pt++ = inb( Read_FIFO_port );
1110 } else {
1111 data_count >>= 1;
1112 insw( in_buf_pt, data_count, Read_FIFO_port );
1113 in_buf_pt += 2 * data_count;
1114 }
1115 }
1116 }
1117 #endif
1118
1119 fdomain_make_bus_idle();
1120
1121 #if EVERY_ACCESS
1122 printk( "Retcode = %x\n",
1123 (Status & 0xff) | ((Message & 0xff) << 8) | (DID_OK << 16) );
1124 #endif
1125 #if ERRORS_ONLY
1126 if (*the_command == REQUEST_SENSE && !Status) {
1127 if ((unsigned char)(*((char *)buff + 2)) & 0x0f) {
1128 printk( "SCSI REQUEST SENSE: Sense Key = %x, Sense Code = %x\n",
1129 (unsigned char)(*((char *)buff + 2)) & 0x0f,
1130 (unsigned char)(*((char *)buff + 12)) );
1131 }
1132 }
1133 #endif
1134
1135 return (Status & 0xff) | ((Message & 0xff) << 8) | (DID_OK << 16);
1136 }
1137
1138 int fdomain_16x0_abort( int code )
1139 {
1140
1141 #if EVERY_ACCESS
1142 printk( " ABORT " );
1143 #endif
1144
1145 #if QUEUE
1146 cli();
1147 if (!in_command) {
1148 sti();
1149 return 0;
1150 }
1151
1152 aborted = code ? code : DID_ABORT;
1153
1154 sti();
1155 fdomain_make_bus_idle();
1156 #else
1157 aborted = code ? code : DID_ABORT;
1158 #endif
1159
1160 return 0;
1161 }
1162
1163 int fdomain_16x0_reset( void )
1164 {
1165 outb( 1, SCSI_Cntl_port );
1166 do_pause( 2 );
1167 outb( 0, SCSI_Cntl_port );
1168 do_pause( 115 );
1169 outb( 0, Data_Mode_Cntl_port );
1170 outb( 0, TMC_Cntl_port );
1171
1172 aborted = DID_RESET;
1173
1174 return 0;
1175 }
1176
1177 #if QUEUE && !NEW_IRQ
1178
1179
1180
1181
1182 __asm__("
1183 _fdomain_16x0_interrupt:
1184 cld
1185 push %gs
1186 push %fs
1187 push %es
1188 push %ds
1189 pushl %eax
1190 pushl %ebp
1191 pushl %edi
1192 pushl %esi
1193 pushl %edx
1194 pushl %ecx
1195 pushl %ebx
1196 movl $0x10,%edx
1197 mov %dx,%ds
1198 mov %dx,%es
1199 movl $0x17,%edx
1200 mov %dx,%fs
1201
1202 movl $_fdomain_disable_interrupt,%edx
1203 call *%edx
1204
1205 movb $0x20,%al
1206 outb %al,$0xA0 # EOI to interrupt controller #1
1207 jmp 1f # give port chance to breathe
1208 1: jmp 1f
1209 1: outb %al,$0x20
1210
1211 sti
1212 movl $_fdomain_16x0_intr,%edx
1213 call *%edx # ``interesting'' way of handling intr.
1214 cli
1215
1216 movl $_fdomain_enable_interrupt,%edx
1217 call *%edx
1218
1219 popl %ebx
1220 popl %ecx
1221 popl %edx
1222 popl %esi
1223 popl %edi
1224 popl %ebp
1225 popl %eax
1226 pop %ds
1227 pop %es
1228 pop %fs
1229 pop %gs
1230 iret
1231 ");
1232 #endif
1233
1234 #endif