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