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