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