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