This source file includes following definitions.
- ql_zap
- ql_pdma
- ql_wai
- ql_icmd
- ql_pcmd
- ql_ihandl
- qlidone
- qlogic_command
- qlogic_queuecommand
- qlogic_queuecommand
- qlogic_preset
- qlogic_detect
- qlogic_biosparam
- qlogic_abort
- qlogic_reset
- qlogic_info
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 #define QL_INT_ACTIVE_HIGH 2
36
37
38
39 #define QL_USE_IRQ 1
40
41
42
43 #define QL_TURBO_PDMA 1
44
45
46 #define QL_ENABLE_PARITY 1
47
48
49
50
51
52
53
54 #define QL_RESET_AT_START 0
55
56
57
58
59 #define XTALFREQ 40
60
61
62
63
64
65
66
67
68
69
70
71
72
73 #define SLOWCABLE 1
74
75
76
77
78
79 #define FASTSCSI 0
80
81
82 #define FASTCLK 0
83
84
85
86
87
88
89
90 #define SYNCXFRPD 5
91
92
93
94
95
96
97
98
99
100 #define SYNCOFFST 0
101
102
103
104
105
106
107 #ifdef PCMCIA
108 #undef QL_INT_ACTIVE_HIGH
109 #define QL_INT_ACTIVE_HIGH 0
110 #define MODULE
111 #endif
112
113 #if defined(MODULE)
114 #include <linux/config.h>
115 #include <linux/module.h>
116 #endif
117
118 #ifdef PCMCIA
119 #undef MODULE
120 #endif
121
122 #include "../block/blk.h"
123 #include <linux/kernel.h>
124 #include <linux/string.h>
125 #include <linux/ioport.h>
126 #include <linux/sched.h>
127 #include <unistd.h>
128 #include <asm/io.h>
129 #include <asm/irq.h>
130 #include "sd.h"
131 #include "hosts.h"
132 #include "qlogic.h"
133
134
135
136 static int qbase = 0;
137 static int qinitid;
138 static int qabort;
139 static int qlirq = -1;
140 static char qinfo[80];
141 static Scsi_Cmnd *qlcmd;
142
143 static int qlcfg5 = ( XTALFREQ << 5 );
144 static int qlcfg6 = SYNCXFRPD;
145 static int qlcfg7 = SYNCOFFST;
146 static int qlcfg8 = ( SLOWCABLE << 7 ) | ( QL_ENABLE_PARITY << 4 );
147 static int qlcfg9 = ( ( XTALFREQ + 4 ) / 5 );
148 static int qlcfgc = ( FASTCLK << 3 ) | ( FASTSCSI << 4 );
149
150
151
152 #define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd ))
153 #define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd ))
154
155
156 #define WATCHDOG 5000000
157
158
159
160
161
162 #if 0
163 #define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);}
164 #else
165 #define rtrc(i) {}
166 #endif
167
168
169
170
171 static void ql_zap(void);
172
173 void ql_zap()
174 {
175 int x;
176 unsigned long flags;
177 save_flags( flags );
178 cli();
179 x = inb(qbase + 0xd);
180 REG0;
181 outb(3, qbase + 3);
182 outb(2, qbase + 3);
183 if (x & 0x80)
184 REG1;
185 restore_flags( flags );
186 }
187
188
189
190 static int ql_pdma(int phase, char *request, int reqlen)
191 {
192 int j;
193 j = 0;
194 if (phase & 1) {
195 #if QL_TURBO_PDMA
196 rtrc(4)
197
198 if( reqlen >= 128 && (inb( qbase + 8 ) & 2) ) {
199 insl( qbase + 4, request, 32 );
200 reqlen -= 128;
201 request += 128;
202 }
203 while( reqlen >= 84 && !( j & 0xc0 ) )
204 if( (j=inb( qbase + 8 )) & 4 ) {
205 insl( qbase + 4, request, 21 );
206 reqlen -= 84;
207 request += 84;
208 }
209 if( reqlen >= 44 && (inb( qbase + 8 ) & 8) ) {
210 insl( qbase + 4, request, 11 );
211 reqlen -= 44;
212 request += 44;
213 }
214 #endif
215
216 rtrc(7)
217 j = 0;
218 while( reqlen && !( (j & 0x10) && (j & 0xc0) ) ) {
219
220 j &= 0xc0;
221 while ( reqlen && !( (j=inb(qbase + 8)) & 0x10 ) ) {
222 *request++ = inb(qbase + 4);
223 reqlen--;
224 }
225 if( j & 0x10 )
226 j = inb(qbase+8);
227
228 }
229 }
230 else {
231 #if QL_TURBO_PDMA
232 rtrc(4)
233 if( reqlen >= 128 && inb( qbase + 8 ) & 0x10 ) {
234 outsl(qbase + 4, request, 32 );
235 reqlen -= 128;
236 request += 128;
237 }
238 while( reqlen >= 84 && !( j & 0xc0 ) )
239 if( !((j=inb( qbase + 8 )) & 8) ) {
240 outsl( qbase + 4, request, 21 );
241 reqlen -= 84;
242 request += 84;
243 }
244 if( reqlen >= 40 && !(inb( qbase + 8 ) & 4 ) ) {
245 outsl( qbase + 4, request, 10 );
246 reqlen -= 40;
247 request += 40;
248 }
249 #endif
250
251 rtrc(7)
252 j = 0;
253 while( reqlen && !( (j & 2) && (j & 0xc0) ) ) {
254
255 while ( reqlen && !( (j=inb(qbase + 8)) & 2 ) ) {
256 outb(*request++, qbase + 4);
257 reqlen--;
258 }
259 if( j & 2 )
260 j = inb(qbase+8);
261 }
262 }
263
264 return inb( qbase + 8 ) & 0xc0;
265 }
266
267
268
269 static int ql_wai(void)
270 {
271 int i,k;
272 k = 0;
273 i = jiffies + WATCHDOG;
274 while ( i > jiffies && !qabort && !((k = inb(qbase + 4)) & 0xe0))
275 barrier();
276 if (i <= jiffies)
277 return (DID_TIME_OUT);
278 if (qabort)
279 return (qabort == 1 ? DID_ABORT : DID_RESET);
280 if (k & 0x60)
281 ql_zap();
282 if (k & 0x20)
283 return (DID_PARITY);
284 if (k & 0x40)
285 return (DID_ERROR);
286 return 0;
287 }
288
289
290
291 static void ql_icmd(Scsi_Cmnd * cmd)
292 {
293 unsigned int i;
294 unsigned long flags;
295
296 qabort = 0;
297
298 save_flags( flags );
299 cli();
300 REG0;
301
302 inb(qbase + 5);
303 if (inb(qbase + 5))
304 outb(2, qbase + 3);
305 else if (inb(qbase + 7) & 0x1f)
306 outb(1, qbase + 3);
307 while (inb(qbase + 5));
308 REG1;
309 outb(1, qbase + 8);
310 outb(0, qbase + 0xb);
311 inb(qbase + 8);
312 REG0;
313 outb(0x40, qbase + 0xb);
314
315
316 outb( qlcfgc , qbase + 0xc);
317
318 outb( 0x40 | qlcfg8 | qinitid, qbase + 8);
319 outb( qlcfg7 , qbase + 7 );
320 outb( qlcfg6 , qbase + 6 );
321
322 outb(qlcfg5, qbase + 5);
323 outb(qlcfg9 & 7, qbase + 9);
324
325 outb(cmd->target, qbase + 4);
326
327 for (i = 0; i < cmd->cmd_len; i++)
328 outb(cmd->cmnd[i], qbase + 2);
329 qlcmd = cmd;
330 outb(0x41, qbase + 3);
331 restore_flags( flags );
332 }
333
334
335 static unsigned int ql_pcmd(Scsi_Cmnd * cmd)
336 {
337 unsigned int i, j, k;
338 unsigned int result;
339 unsigned int status;
340 unsigned int message;
341 unsigned int phase;
342 unsigned int reqlen;
343 struct scatterlist *sglist;
344 unsigned int sgcount;
345
346 rtrc(1)
347 j = inb(qbase + 6);
348 i = inb(qbase + 5);
349 if (i == 0x20) {
350 return (DID_NO_CONNECT << 16);
351 }
352 i |= inb(qbase + 5);
353 if (i != 0x18) {
354 printk("Ql:Bad Interrupt status:%02x\n", i);
355 ql_zap();
356 return (DID_BAD_INTR << 16);
357 }
358 j &= 7;
359
360
361
362
363 if(j != 3 && j != 4) {
364 printk("Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n", j, i, inb( qbase+7 ) & 0x1f );
365 ql_zap();
366 return (DID_ERROR << 16);
367 }
368 result = DID_OK;
369 if (inb(qbase + 7) & 0x1f)
370 outb(1, qbase + 3);
371
372 reqlen = cmd->request_bufflen;
373
374 if (reqlen && !((phase = inb(qbase + 4)) & 6)) {
375 rtrc(2)
376 outb(reqlen, qbase);
377 outb(reqlen >> 8, qbase+1);
378 outb(reqlen >> 16, qbase + 0xe);
379 outb(0x90, qbase + 3);
380
381 REG1;
382 if (!cmd->use_sg)
383 ql_pdma(phase, cmd->request_buffer, cmd->request_bufflen);
384 else {
385 sgcount = cmd->use_sg;
386 sglist = cmd->request_buffer;
387 while (sgcount--) {
388 if (qabort) {
389 REG0;
390 return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
391 }
392 if (ql_pdma(phase, sglist->address, sglist->length))
393 break;
394 sglist++;
395 }
396 }
397 REG0;
398 rtrc(2)
399
400 if ((k = ql_wai()))
401 return (k << 16);
402 k = inb(qbase + 5);
403 }
404
405 k = jiffies + WATCHDOG;
406 while ( k > jiffies && !qabort && !(inb(qbase + 4) & 6));
407 if ( k <= jiffies ) {
408 ql_zap();
409 return (DID_TIME_OUT << 16);
410 }
411 while (inb(qbase + 5));
412 if (qabort)
413 return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
414 outb(0x11, qbase + 3);
415 if ((k = ql_wai()))
416 return (k << 16);
417 i = inb(qbase + 5);
418 j = inb(qbase + 7) & 0x1f;
419 status = inb(qbase + 2);
420 message = inb(qbase + 2);
421
422 if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) {
423 printk("Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j);
424 result = DID_ERROR;
425 }
426 outb(0x12, qbase + 3);
427 rtrc(1)
428 if ((k = ql_wai()))
429 return (k << 16);
430
431 i = inb(qbase + 5);
432 while (!qabort && ((i & 0x20) != 0x20)) {
433 barrier();
434 i |= inb(qbase + 5);
435 }
436 rtrc(0)
437 if (qabort)
438 return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
439 return (result << 16) | (message << 8) | (status & STATUS_MASK);
440 }
441
442 #if QL_USE_IRQ
443
444
445 static void ql_ihandl(int irq, struct pt_regs * regs)
446 {
447 Scsi_Cmnd *icmd;
448 REG0;
449 if (!(inb(qbase + 4) & 0x80))
450 return;
451 if (qlcmd == NULL) {
452 int i;
453 i = 16;
454 while (i-- && inb(qbase + 5));
455 return;
456 }
457 icmd = qlcmd;
458 icmd->result = ql_pcmd(icmd);
459 qlcmd = NULL;
460
461 (icmd->scsi_done) (icmd);
462 }
463 #endif
464
465
466
467
468
469 #if QL_USE_IRQ
470 static void qlidone(Scsi_Cmnd * cmd) {};
471 #endif
472
473
474 int qlogic_command(Scsi_Cmnd * cmd)
475 {
476 int k;
477 #if QL_USE_IRQ
478 if (qlirq >= 0) {
479 qlogic_queuecommand(cmd, qlidone);
480 while (qlcmd != NULL);
481 return cmd->result;
482 }
483 #endif
484
485 if (cmd->target == qinitid)
486 return (DID_BAD_TARGET << 16);
487 ql_icmd(cmd);
488 if ((k = ql_wai()))
489 return (k << 16);
490 return ql_pcmd(cmd);
491
492 }
493
494 #if QL_USE_IRQ
495
496
497 int qlogic_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
498 {
499 if(cmd->target == qinitid) {
500 cmd->result = DID_BAD_TARGET << 16;
501 done(cmd);
502 return 0;
503 }
504
505 cmd->scsi_done = done;
506
507 while (qlcmd != NULL)
508 barrier();
509 ql_icmd(cmd);
510 return 0;
511 }
512 #else
513 int qlogic_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
514 {
515 return 1;
516 }
517 #endif
518
519 #ifdef PCMCIA
520
521
522
523 void qlogic_preset(int port, int irq)
524 {
525 qbase=port;
526 qlirq=irq;
527 }
528 #endif
529
530
531
532 int qlogic_detect(Scsi_Host_Template * host)
533 {
534 int i, j;
535 int qltyp;
536 struct Scsi_Host *hreg;
537 unsigned long flags;
538
539
540
541
542
543
544
545
546
547 if( !qbase ) {
548 for (qbase = 0x230; qbase < 0x430; qbase += 0x100) {
549 if( check_region( qbase , 0x10 ) )
550 continue;
551 REG1;
552 if ( ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 )
553 && ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 ) )
554 break;
555 }
556 if (qbase == 0x430)
557 return 0;
558 }
559 else
560 printk( "Ql: Using preset base address of %03x\n", qbase );
561
562 qltyp = inb(qbase + 0xe) & 0xf8;
563 qinitid = host->this_id;
564 if (qinitid < 0)
565 qinitid = 7;
566 outb(1, qbase + 8);
567 REG0;
568 outb(0x40 | qlcfg8 | qinitid, qbase + 8);
569 outb(qlcfg5, qbase + 5);
570 outb(qlcfg9, qbase + 9);
571 #if QL_RESET_AT_START
572 outb( 3 , qbase + 3 );
573 REG1;
574 while( inb( qbase + 0xf ) & 4 );
575 REG0;
576 #endif
577 #if QL_USE_IRQ
578
579
580 if( qlirq == -1 ) {
581 save_flags( flags );
582 cli();
583 i = 0xffff;
584 j = 3;
585 outb(0x90, qbase + 3);
586 REG1;
587 outb(10, 0x20);
588 outb(10, 0xa0);
589 while (j--) {
590 outb(0xb0 | QL_INT_ACTIVE_HIGH , qbase + 0xd);
591 i &= ~(inb(0x20) | (inb(0xa0) << 8));
592 outb(0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd);
593 i &= inb(0x20) | (inb(0xa0) << 8);
594 }
595 REG0;
596 while (inb(qbase + 5));
597 j = -1;
598 while (i)
599 i >>= 1, j++;
600 qlirq = j;
601 restore_flags( flags );
602 }
603 else
604 printk( "Ql: Using preset IRQ %d\n", qlirq );
605
606 if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, 0, "qlogic"))
607 host->can_queue = 1;
608 #endif
609 request_region( qbase , 0x10 ,"qlogic");
610 hreg = scsi_register( host , 0 );
611 hreg->io_port = qbase;
612 hreg->n_io_port = 16;
613 hreg->dma_channel = -1;
614 if( qlirq != -1 )
615 hreg->irq = qlirq;
616
617 sprintf(qinfo, "Qlogic Driver version 0.43, chip %02X at %03X, IRQ %d, TPdma:%d",
618 qltyp, qbase, qlirq, QL_TURBO_PDMA );
619 host->name = qinfo;
620
621 return 1;
622 }
623
624
625
626 int qlogic_biosparam(Disk * disk, int dev, int ip[])
627 {
628
629 ip[0] = 0x40;
630 ip[1] = 0x20;
631 ip[2] = disk->capacity / (ip[0] * ip[1]);
632 if (ip[2] > 1024) {
633 ip[0] = 0xff;
634 ip[1] = 0x3f;
635 ip[2] = disk->capacity / (ip[0] * ip[1]);
636 if (ip[2] > 1023)
637 ip[2] = 1023;
638 }
639 return 0;
640 }
641
642
643
644 int qlogic_abort(Scsi_Cmnd * cmd)
645 {
646 qabort = 1;
647 ql_zap();
648 return 0;
649 }
650
651
652
653 int qlogic_reset(Scsi_Cmnd * cmd)
654 {
655 qabort = 2;
656 ql_zap();
657 return 1;
658 }
659
660
661
662 const char *qlogic_info(struct Scsi_Host * host)
663 {
664 return qinfo;
665 }
666
667 #ifdef MODULE
668
669 Scsi_Host_Template driver_template = QLOGIC;
670
671 #include "scsi_module.c"
672 #endif