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