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