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