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