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