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