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