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