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