This source file includes following definitions.
- inw
- outw
- in2000_test_port
- in2000_txcnt
- in2000_fifo_out
- in2000_fifo_in
- in2000_intr_handle
- in2000_queuecommand
- internal_done
- in2000_command
- in2000_detect
- in2000_abort
- delay
- in2000_reset
- in2000_biosparam
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 #ifdef MODULE
58 #include <linux/module.h>
59 #endif
60
61 #include <linux/kernel.h>
62 #include <linux/head.h>
63 #include <linux/types.h>
64 #include <linux/string.h>
65 #include <linux/sched.h>
66 #include <linux/proc_fs.h>
67 #include <asm/dma.h>
68 #include <asm/system.h>
69 #include <asm/io.h>
70 #include <linux/blk.h>
71 #include "scsi.h"
72 #include "hosts.h"
73 #include "sd.h"
74
75 #include "in2000.h"
76 #include<linux/stat.h>
77
78 struct proc_dir_entry proc_scsi_in2000 = {
79 PROC_SCSI_IN2000, 6, "in2000",
80 S_IFDIR | S_IRUGO | S_IXUGO, 2
81 };
82
83
84
85
86 #ifdef DEBUG
87 #define DEB(x) x
88 #else
89 #define DEB(x)
90 #endif
91
92
93 #ifndef inw
94 inline static unsigned short inw( unsigned short port )
95 {
96 unsigned short _v;
97
98 __asm__ volatile ("inw %1,%0"
99 :"=a" (_v):"d" ((unsigned short) port));
100 return _v;
101 }
102 #endif
103
104 #ifndef outw
105 inline static void outw( unsigned short value, unsigned short port )
106 {
107 __asm__ volatile ("outw %0,%1"
108 :
109 :"a" ((unsigned short) value),
110 "d" ((unsigned short) port));
111 }
112 #endif
113
114
115
116 #define port_read(port,buf,nr) \
117 __asm__("cld;rep;insw": :"d" (port),"D" (buf),"c" (nr):"cx","di")
118
119 #define port_write(port,buf,nr) \
120 __asm__("cld;rep;outsw": :"d" (port),"S" (buf),"c" (nr):"cx","si")
121
122 static unsigned int base;
123 static unsigned int ficmsk;
124 static unsigned char irq_level;
125 static int in2000_datalen;
126 static unsigned int in2000_nsegment;
127 static unsigned int in2000_current_segment;
128 static unsigned short *in2000_dataptr;
129 static char in2000_datawrite;
130 static struct scatterlist * in2000_scatter;
131 static Scsi_Cmnd *in2000_SCptr = 0;
132
133 static void (*in2000_done)(Scsi_Cmnd *);
134
135 static int in2000_test_port(int index)
136 {
137 static const int *bios_tab[] = {
138 (int *) 0xc8000, (int *) 0xd0000, (int *) 0xd8000 };
139 int i;
140 char tmp;
141
142 tmp = inb(INFLED);
143
144
145 if ( ((~tmp & 0x3) != index ) || (tmp & 0x80) || !(tmp & 0x4) )
146 return 0;
147 printk("IN-2000 probe got dip setting of %02X\n", tmp);
148 tmp = inb(INVERS);
149
150 for(i=0; i < 3; i++)
151 if(*(bios_tab[i]+0x04) == 0x41564f4e ||
152 *(bios_tab[i]+0xc) == 0x61776c41) {
153 printk("IN-2000 probe found hdw. vers. %02x, BIOS at %06x\n",
154 tmp, (unsigned int)bios_tab[i]);
155 return 1;
156 }
157 printk("in2000 BIOS not found.\n");
158 return 0;
159 }
160
161
162
163
164
165
166 static unsigned in2000_txcnt(void)
167 {
168 unsigned total=0;
169
170 if(inb(INSTAT) & 0x20) return 0xffffff;
171 outb(TXCNTH,INSTAT);
172 total = (inb(INDATA) & 0xff) << 16;
173 outb(TXCNTM,INSTAT);
174 total += (inb(INDATA) & 0xff) << 8;
175 outb(TXCNTL,INSTAT);
176 total += (inb(INDATA) & 0xff);
177 return total;
178 }
179
180
181
182
183
184
185
186
187 static void in2000_fifo_out(void)
188 {
189 unsigned count, infcnt, txcnt;
190
191 infcnt = inb(INFCNT)& 0xfe;
192 do {
193 txcnt = in2000_txcnt();
194
195 count = (infcnt << 3) - 32;
196 if ( count > in2000_datalen )
197 count = in2000_datalen;
198 count >>= 1;
199 #ifdef FAST_FIFO_IO
200 if ( count ) {
201 port_write(INFIFO, in2000_dataptr, count);
202 in2000_datalen -= (count<<1);
203 }
204 #else
205 while ( count-- )
206 {
207 outw(*in2000_dataptr++, INFIFO);
208 in2000_datalen -= 2;
209 }
210 #endif
211 } while((in2000_datalen > 0) && ((infcnt = (inb(INFCNT)) & 0xfe) >= 0x20) );
212
213 if( !in2000_datalen && ++in2000_current_segment < in2000_nsegment)
214 {
215 in2000_scatter++;
216 in2000_datalen = in2000_scatter->length;
217 in2000_dataptr = (unsigned short*)in2000_scatter->address;
218 }
219 if ( in2000_datalen <= 0 )
220 {
221 ficmsk = 0;
222 count = 32;
223 while ( count-- )
224 outw(0, INFIFO);
225 outb(2, ININTR);
226 }
227 }
228
229 static void in2000_fifo_in(void)
230 {
231 unsigned fic, count, count2;
232
233 count = inb(INFCNT) & 0xe1;
234 do{
235 count2 = count;
236 count = (fic = inb(INFCNT)) & 0xe1;
237 } while ( count != count2 );
238 DEB(printk("FIir:%d %02x %08x\n", in2000_datalen,fic,(unsigned int )in2000_dataptr));
239 do {
240 count2 = in2000_txcnt();
241 DEB(printk("FIr:%d %02x %08x %08x\n", in2000_datalen,fic,count2,(unsigned int)in2000_dataptr));
242 if(count2 > 65536) count2 = 0;
243 if(fic > 128) count = 1024;
244 else if(fic > 64) count = 512;
245 else if (fic > 32) count = 256;
246 else if ( count2 < in2000_datalen )
247 count = in2000_datalen - count2;
248 if ( count > in2000_datalen )
249 count2 = in2000_datalen >> 1;
250 else
251 count2 = count >> 1;
252 count >>= 1;
253 count -= count2;
254 #ifdef FAST_FIFO_IO
255 if ( count2 ) {
256 port_read(INFIFO, in2000_dataptr, count2);
257 in2000_datalen -= (count2<<1);
258 }
259 #else
260 while ( count2-- )
261 {
262 *in2000_dataptr++ = inw(INFIFO);
263 in2000_datalen -=2;
264 }
265 #endif
266 } while((in2000_datalen > 0) && (fic = inb(INFCNT)) );
267 DEB(printk("FIer:%d %02x %08x\n", in2000_datalen,fic,(unsigned int )in2000_dataptr));
268
269
270 if( !in2000_datalen && ++in2000_current_segment < in2000_nsegment)
271 {
272 in2000_scatter++;
273 in2000_datalen = in2000_scatter->length;
274 in2000_dataptr = (unsigned short*)in2000_scatter->address;
275 }
276 if ( ! in2000_datalen ){
277 outb(2, ININTR);
278 ficmsk = 0;}
279 }
280
281 static void in2000_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
282 {
283 int result=0;
284 unsigned int count,auxstatus,scsistatus,cmdphase,scsibyte;
285 int action=0;
286 Scsi_Cmnd *SCptr;
287
288 DEB(printk("INT:%d %02x %08x\n", in2000_datalen, inb(INFCNT),(unsigned int)in2000_dataptr));
289
290 if (( (ficmsk & (count = inb(INFCNT))) == 0xfe ) ||
291 ( (inb(INSTAT) & 0x8c) == 0x80))
292 {
293 auxstatus = inb(INSTAT);
294 outb(SCSIST,INSTAT);
295 scsistatus = inb(INDATA);
296 outb(TARGETU,INSTAT);
297 scsibyte = inb(INDATA);
298 outb(CMDPHAS,INSTAT);
299 cmdphase = inb(INDATA);
300 DEB(printk("(int2000:%02x %02x %02x %02x %02x)\n",count,auxstatus,
301 scsistatus,cmdphase,scsibyte));
302
303
304 if ( in2000_datalen )
305 {
306 if ( in2000_dataptr == NULL )
307 printk("int2000: dataptr=NULL datalen=%d\n",
308 in2000_datalen);
309 else if ( in2000_datawrite )
310 in2000_fifo_out();
311 else
312 in2000_fifo_in();
313 }
314 if ( (auxstatus & 0x8c) == 0x80 )
315 {
316 outb(2,ININTR);
317 ficmsk = 0;
318 result = DID_OK << 16;
319
320 if ((scsistatus != 0x16) && (scsistatus != 0x85)
321 && (scsistatus != 0x42)){
322
323
324
325
326 ;
327 }
328 switch ( scsistatus & 0xf0 )
329 {
330 case 0x00:
331 action = 3;
332 break;
333 case 0x10:
334 if ( scsistatus & 0x8 )
335 action = 1;
336 break;
337 case 0x20:
338 if ( (scsistatus & 0x8) )
339 action = 1;
340 else if ( (scsistatus & 7) < 2 )
341 action = 2;
342 else
343 result = DID_ABORT << 16;
344 break;
345 case 0x40:
346 if ( scsistatus & 0x8 )
347 action = 1;
348 else if ( (scsistatus & 7) > 2 )
349 action = 2;
350 else
351 result = DID_TIME_OUT << 16;
352 break;
353 case 0x80:
354 if ( scsistatus & 0x8 )
355 action = 1;
356 else
357 action = 2;
358 break;
359 }
360 outb(0,INFLED);
361 switch ( action )
362 {
363 case 0x02:
364 outb(COMMAND,INSTAT);
365 outb(1,INDATA);
366 result = DID_ABORT << 16;
367 case 0x00:
368 if ( ! in2000_SCptr )
369 return;
370 in2000_SCptr->result = result | scsibyte;
371 SCptr = in2000_SCptr;
372 in2000_SCptr = 0;
373 if ( in2000_done )
374 (*in2000_done)(SCptr);
375 break;
376 case 0x01:
377 outb(CMDPHAS,INSTAT);
378 switch ( scsistatus & 7 )
379 {
380 case 0:
381 case 1:
382 case 4:
383 case 5:
384 case 6:
385 case 7:
386 outb(0x41,INDATA);
387 break;
388 case 2:
389 outb(0x30,INDATA);
390 break;
391 case 3:
392 outb(0x45,INDATA);
393 outb(TXCNTH,INSTAT);
394 outb(0,INDATA);
395 outb(0,INDATA);
396 outb(0,INDATA);
397 in2000_datalen = 0;
398 in2000_dataptr = 0;
399 break;
400 }
401 outb(COMMAND,INSTAT);
402 outb(8,INDATA);
403 break;
404 case 0x03:
405 outb(TIMEOUT,INSTAT);
406
407 outb(IN2000_TMOUT,INDATA);
408 outb(CONTROL,INSTAT);
409 outb(0,INDATA);
410 outb(SYNCTXR,INSTAT);
411 outb(0x40,INDATA);
412 break;
413 }
414 }
415 }
416 }
417
418 int in2000_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
419 {
420 unchar direction;
421 unchar *cmd = (unchar *) SCpnt->cmnd;
422 unchar target = SCpnt->target;
423 void *buff = SCpnt->request_buffer;
424 unsigned long flags;
425 int bufflen = SCpnt->request_bufflen;
426 int timeout, size, loop;
427 int i;
428
429
430
431
432
433
434
435
436 if ( *cmd == TEST_UNIT_READY )
437 bufflen = 0;
438
439
440
441
442 if (*cmd == READ_10 || *cmd == WRITE_10) {
443 i = xscsi2int((cmd+1));
444 } else if (*cmd == READ_6 || *cmd == WRITE_6) {
445 i = scsi2int((cmd+1));
446 } else {
447 i = -1;
448 }
449 #ifdef DEBUG
450 printk("in2000qcmd: pos %d len %d ", i, bufflen);
451 printk("scsi cmd:");
452 for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]);
453 printk("\n");
454 #endif
455 direction = 1;
456 if (*cmd == WRITE_10 || *cmd == WRITE_6)
457 direction = 0;
458 size = SCpnt->cmd_len;
459
460
461
462
463
464
465
466
467
468
469
470
471 if ( in2000_SCptr )
472 {
473 printk("in2000_queue_command waiting for free command block!\n");
474 while ( in2000_SCptr )
475 barrier();
476 }
477 for ( timeout = jiffies + 5; timeout > jiffies; )
478 {
479 if ( ! ( inb(INSTAT) & 0xb0 ) )
480 {
481 timeout = 0;
482 break;
483 }
484 else
485 {
486 inb(INSTAT);
487 outb(SCSIST,INSTAT);
488 inb(INDATA);
489 outb(TARGETU,INSTAT);
490 inb(INDATA);
491 inb(INDATA);
492 }
493 }
494 if ( timeout )
495 {
496 printk("in2000_queue_command timeout!\n");
497 SCpnt->result = DID_TIME_OUT << 16;
498 (*done)(SCpnt);
499 return 1;
500 }
501
502 in2000_nsegment = SCpnt->use_sg;
503 in2000_current_segment = 0;
504 if(SCpnt->use_sg){
505 in2000_scatter = (struct scatterlist *) buff;
506 in2000_datalen = in2000_scatter->length;
507 in2000_dataptr = (unsigned short*)in2000_scatter->address;
508 } else {
509 in2000_scatter = NULL;
510 in2000_datalen = bufflen;
511 in2000_dataptr = (unsigned short*) buff;
512 };
513 in2000_done = done;
514 in2000_SCptr = SCpnt;
515
516
517
518 outb(TOTSECT, INSTAT);
519 for ( loop=0; loop < size; loop++ )
520 outb(cmd[loop],INDATA);
521 outb(TARGETU,INSTAT);
522 outb(SCpnt->lun & 7,INDATA);
523 SCpnt->host_scribble = NULL;
524 outb(TXCNTH,INSTAT);
525 outb(bufflen>>16,INDATA);
526 outb(bufflen>>8,INDATA);
527 outb(bufflen,INDATA);
528 outb(target&7,INDATA);
529
530
531
532 save_flags(flags);
533 cli();
534 outb(0,INFRST);
535 if ( direction == 1 )
536 {
537 in2000_datawrite = 0;
538 outb(0,INFWRT);
539 }
540 else
541 {
542 in2000_datawrite = 1;
543 for ( loop=16; --loop; )
544 {
545 outw(*in2000_dataptr++,INFIFO);
546 if(in2000_datalen > 0) in2000_datalen-=2;
547 }
548 }
549 ficmsk = 0xff;
550
551
552
553 outb(CONTROL,INSTAT);
554 outb(0x4C,INDATA);
555 if ( in2000_datalen )
556 outb(0,ININTR);
557 outb(COMMAND,INSTAT);
558 outb(0,INNLED);
559 outb(8,INDATA);
560 restore_flags(flags);
561 return 0;
562 }
563
564 static volatile int internal_done_flag = 0;
565 static volatile int internal_done_errcode = 0;
566
567 static void internal_done(Scsi_Cmnd * SCpnt)
568 {
569 internal_done_errcode = SCpnt->result;
570 ++internal_done_flag;
571 }
572
573 int in2000_command(Scsi_Cmnd * SCpnt)
574 {
575 in2000_queuecommand(SCpnt, internal_done);
576
577 while (!internal_done_flag);
578 internal_done_flag = 0;
579 return internal_done_errcode;
580 }
581
582 int in2000_detect(Scsi_Host_Template * tpnt)
583 {
584
585 int base_tab[] = { 0x220,0x200,0x110,0x100 };
586 int int_tab[] = { 15,14,11,10 };
587 struct Scsi_Host * shpnt;
588 int loop, tmp;
589
590 DEB(printk("in2000_detect: \n"));
591
592 tpnt->proc_dir = &proc_scsi_in2000;
593
594 for ( loop=0; loop < 4; loop++ )
595 {
596 base = base_tab[loop];
597 if ( in2000_test_port(loop)) break;
598 }
599 if ( loop == 4 )
600 return 0;
601
602
603
604 tmp = inb(INFLED);
605
606
607 if ( (tmp & 0x4) == 0 ) {
608 printk("The IN-2000 is not configured for interrupt operation\n");
609 printk("Change the DIP switch settings to enable interrupt operation\n");
610 }
611
612
613 printk("IN-2000 probe found floppy controller on IN-2000 ");
614 if ( (tmp & 0x40) == 0)
615 printk("enabled\n");
616 else
617 printk("disabled\n");
618
619
620 printk("IN-2000 probe found IN-2000 in ");
621 if ( (tmp & 0x20) == 0)
622 printk("synchronous mode\n");
623 else
624 printk("asynchronous mode\n");
625
626 irq_level = int_tab [ ((~inb(INFLED)>>3)&0x3) ];
627
628 printk("Configuring IN2000 at IO:%x, IRQ %d"
629 #ifdef FAST_FIFO_IO
630 " (using fast FIFO I/O code)"
631 #endif
632 "\n",base, irq_level);
633
634 outb(2,ININTR);
635 if (request_irq(irq_level,in2000_intr_handle, 0, "in2000", NULL))
636 {
637 printk("in2000_detect: Unable to allocate IRQ.\n");
638 return 0;
639 }
640 outb(0,INFWRT);
641 outb(SCSIST,INSTAT);
642 inb(INDATA);
643 outb(OWNID,INSTAT);
644 outb(0x7,INDATA);
645 outb(COMMAND,INSTAT);
646 outb(0,INDATA);
647 shpnt = scsi_register(tpnt, 0);
648
649 shpnt->io_port = base;
650 shpnt->n_io_port = 12;
651 shpnt->irq = irq_level;
652 request_region(base, 12,"in2000");
653 return 1;
654 }
655
656 int in2000_abort(Scsi_Cmnd * SCpnt)
657 {
658 DEB(printk("in2000_abort\n"));
659
660
661
662 outb(COMMAND,INSTAT);
663 outb(1,INDATA);
664 return 0;
665 }
666
667 static inline void delay( unsigned how_long )
668 {
669 unsigned long time = jiffies + how_long;
670 while (jiffies < time) ;
671 }
672
673 int in2000_reset(Scsi_Cmnd * SCpnt)
674 {
675 DEB(printk("in2000_reset called\n"));
676
677
678
679 outb(0,INFWRT);
680 outb(SCSIST,INSTAT);
681 inb(INDATA);
682 outb(OWNID,INSTAT);
683 outb(0x7,INDATA);
684 outb(COMMAND,INSTAT);
685 outb(0,INDATA);
686 delay(2);
687 #ifdef SCSI_RESET_PENDING
688 return SCSI_RESET_PENDING;
689 #else
690 if(SCpnt) SCpnt->flags |= NEEDS_JUMPSTART;
691 return 0;
692 #endif
693 }
694
695 int in2000_biosparam(Disk * disk, kdev_t dev, int* iinfo)
696 {
697 int size = disk->capacity;
698 DEB(printk("in2000_biosparam\n"));
699 iinfo[0] = 64;
700 iinfo[1] = 32;
701 iinfo[2] = size >> 11;
702
703
704
705 if (iinfo[2] > 1024) {
706 iinfo[0] = 64;
707 iinfo[1] = 63;
708 iinfo[2] = disk->capacity / (iinfo[0] * iinfo[1]);
709 }
710 if (iinfo[2] > 1024) {
711 iinfo[0] = 128;
712 iinfo[1] = 63;
713 iinfo[2] = disk->capacity / (iinfo[0] * iinfo[1]);
714 }
715 if (iinfo[2] > 1024) {
716 iinfo[0] = 255;
717 iinfo[1] = 63;
718 iinfo[2] = disk->capacity / (iinfo[0] * iinfo[1]);
719 if (iinfo[2] > 1023)
720 iinfo[2] = 1023;
721 }
722 return 0;
723 }
724
725 #ifdef MODULE
726
727 Scsi_Host_Template driver_template = IN2000;
728
729 #include "scsi_module.c"
730 #endif
731