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