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