This source file includes following definitions.
- ql_zap
- ql_pdma
- ql_wai
- ql_icmd
- ql_pcmd
- ql_ihandl
- qlogicfas408_ihandl
- qlogicfas408_queuecommand_lck
- DEF_SCSI_QCMD
- qlogicfas408_abort
- qlogicfas408_host_reset
- qlogicfas408_info
- qlogicfas408_get_chip_type
- qlogicfas408_setup
- qlogicfas408_detect
- qlogicfas408_disable_ints
- qlogicfas408_init
- qlogicfas408_exit
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
39
40
41
42 #include <linux/module.h>
43 #include <linux/blkdev.h>
44 #include <linux/kernel.h>
45 #include <linux/string.h>
46 #include <linux/init.h>
47 #include <linux/interrupt.h>
48 #include <linux/ioport.h>
49 #include <linux/proc_fs.h>
50 #include <linux/unistd.h>
51 #include <linux/spinlock.h>
52 #include <linux/stat.h>
53
54 #include <asm/io.h>
55 #include <asm/irq.h>
56 #include <asm/dma.h>
57
58 #include "scsi.h"
59 #include <scsi/scsi_host.h>
60 #include "qlogicfas408.h"
61
62
63 static int qlcfg5 = (XTALFREQ << 5);
64 static int qlcfg6 = SYNCXFRPD;
65 static int qlcfg7 = SYNCOFFST;
66 static int qlcfg8 = (SLOWCABLE << 7) | (QL_ENABLE_PARITY << 4);
67 static int qlcfg9 = ((XTALFREQ + 4) / 5);
68 static int qlcfgc = (FASTCLK << 3) | (FASTSCSI << 4);
69
70
71
72
73
74
75
76
77
78 static void ql_zap(struct qlogicfas408_priv *priv)
79 {
80 int x;
81 int qbase = priv->qbase;
82 int int_type = priv->int_type;
83
84 x = inb(qbase + 0xd);
85 REG0;
86 outb(3, qbase + 3);
87 outb(2, qbase + 3);
88 if (x & 0x80)
89 REG1;
90 }
91
92
93
94
95
96 static int ql_pdma(struct qlogicfas408_priv *priv, int phase, char *request, int reqlen)
97 {
98 int j;
99 int qbase = priv->qbase;
100 j = 0;
101 if (phase & 1) {
102 #if QL_TURBO_PDMA
103 rtrc(4)
104
105 if (reqlen >= 128 && (inb(qbase + 8) & 2)) {
106 insl(qbase + 4, request, 32);
107 reqlen -= 128;
108 request += 128;
109 }
110 while (reqlen >= 84 && !(j & 0xc0))
111 if ((j = inb(qbase + 8)) & 4)
112 {
113 insl(qbase + 4, request, 21);
114 reqlen -= 84;
115 request += 84;
116 }
117 if (reqlen >= 44 && (inb(qbase + 8) & 8)) {
118 insl(qbase + 4, request, 11);
119 reqlen -= 44;
120 request += 44;
121 }
122 #endif
123
124 rtrc(7)
125 j = 0;
126 while (reqlen && !((j & 0x10) && (j & 0xc0)))
127 {
128
129 j &= 0xc0;
130 while (reqlen && !((j = inb(qbase + 8)) & 0x10))
131 {
132 *request++ = inb(qbase + 4);
133 reqlen--;
134 }
135 if (j & 0x10)
136 j = inb(qbase + 8);
137
138 }
139 } else {
140 #if QL_TURBO_PDMA
141 rtrc(4)
142 if (reqlen >= 128 && inb(qbase + 8) & 0x10) {
143 outsl(qbase + 4, request, 32);
144 reqlen -= 128;
145 request += 128;
146 }
147 while (reqlen >= 84 && !(j & 0xc0))
148 if (!((j = inb(qbase + 8)) & 8)) {
149 outsl(qbase + 4, request, 21);
150 reqlen -= 84;
151 request += 84;
152 }
153 if (reqlen >= 40 && !(inb(qbase + 8) & 4)) {
154 outsl(qbase + 4, request, 10);
155 reqlen -= 40;
156 request += 40;
157 }
158 #endif
159
160 rtrc(7)
161 j = 0;
162 while (reqlen && !((j & 2) && (j & 0xc0))) {
163
164 while (reqlen && !((j = inb(qbase + 8)) & 2))
165 {
166 outb(*request++, qbase + 4);
167 reqlen--;
168 }
169 if (j & 2)
170 j = inb(qbase + 8);
171 }
172 }
173
174 return inb(qbase + 8) & 0xc0;
175 }
176
177
178
179
180
181 static int ql_wai(struct qlogicfas408_priv *priv)
182 {
183 int k;
184 int qbase = priv->qbase;
185 unsigned long i;
186
187 k = 0;
188 i = jiffies + WATCHDOG;
189 while (time_before(jiffies, i) && !priv->qabort &&
190 !((k = inb(qbase + 4)) & 0xe0)) {
191 barrier();
192 cpu_relax();
193 }
194 if (time_after_eq(jiffies, i))
195 return (DID_TIME_OUT);
196 if (priv->qabort)
197 return (priv->qabort == 1 ? DID_ABORT : DID_RESET);
198 if (k & 0x60)
199 ql_zap(priv);
200 if (k & 0x20)
201 return (DID_PARITY);
202 if (k & 0x40)
203 return (DID_ERROR);
204 return 0;
205 }
206
207
208
209
210
211
212 static void ql_icmd(struct scsi_cmnd *cmd)
213 {
214 struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
215 int qbase = priv->qbase;
216 int int_type = priv->int_type;
217 unsigned int i;
218
219 priv->qabort = 0;
220
221 REG0;
222
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 outb(qlcfgc, qbase + 0xc);
239
240 outb(0x40 | qlcfg8 | priv->qinitid, qbase + 8);
241 outb(qlcfg7, qbase + 7);
242 outb(qlcfg6, qbase + 6);
243 outb(qlcfg5, qbase + 5);
244 outb(qlcfg9 & 7, qbase + 9);
245
246 outb(scmd_id(cmd), qbase + 4);
247
248 for (i = 0; i < cmd->cmd_len; i++)
249 outb(cmd->cmnd[i], qbase + 2);
250
251 priv->qlcmd = cmd;
252 outb(0x41, qbase + 3);
253 }
254
255
256
257
258
259 static unsigned int ql_pcmd(struct scsi_cmnd *cmd)
260 {
261 unsigned int i, j;
262 unsigned long k;
263 unsigned int result;
264 unsigned int status;
265 unsigned int message;
266 unsigned int phase;
267 unsigned int reqlen;
268 char *buf;
269 struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
270 int qbase = priv->qbase;
271 int int_type = priv->int_type;
272
273 rtrc(1)
274 j = inb(qbase + 6);
275 i = inb(qbase + 5);
276 if (i == 0x20) {
277 return (DID_NO_CONNECT << 16);
278 }
279 i |= inb(qbase + 5);
280 if (i != 0x18) {
281 printk(KERN_ERR "Ql:Bad Interrupt status:%02x\n", i);
282 ql_zap(priv);
283 return (DID_BAD_INTR << 16);
284 }
285 j &= 7;
286
287
288
289
290
291
292 if (j != 3 && j != 4) {
293 printk(KERN_ERR "Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n",
294 j, i, inb(qbase + 7) & 0x1f);
295 ql_zap(priv);
296 return (DID_ERROR << 16);
297 }
298 result = DID_OK;
299 if (inb(qbase + 7) & 0x1f)
300 outb(1, qbase + 3);
301
302 reqlen = scsi_bufflen(cmd);
303
304 if (reqlen && !((phase = inb(qbase + 4)) & 6)) {
305 struct scatterlist *sg;
306 rtrc(2)
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
314 scsi_for_each_sg(cmd, sg, scsi_sg_count(cmd), i) {
315 if (priv->qabort) {
316 REG0;
317 return ((priv->qabort == 1 ?
318 DID_ABORT : DID_RESET) << 16);
319 }
320 buf = sg_virt(sg);
321 if (ql_pdma(priv, phase, buf, sg->length))
322 break;
323 }
324 REG0;
325 rtrc(2)
326
327
328
329
330 if ((k = ql_wai(priv)))
331 return (k << 16);
332 k = inb(qbase + 5);
333 }
334
335
336
337
338
339 k = jiffies + WATCHDOG;
340
341 while (time_before(jiffies, k) && !priv->qabort &&
342 !(inb(qbase + 4) & 6))
343 cpu_relax();
344
345 if (time_after_eq(jiffies, k)) {
346 ql_zap(priv);
347 return (DID_TIME_OUT << 16);
348 }
349
350
351 while (inb(qbase + 5))
352 cpu_relax();
353
354 if (priv->qabort)
355 return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16);
356
357 outb(0x11, qbase + 3);
358 if ((k = ql_wai(priv)))
359 return (k << 16);
360 i = inb(qbase + 5);
361 j = inb(qbase + 7) & 0x1f;
362 status = inb(qbase + 2);
363 message = inb(qbase + 2);
364
365
366
367
368
369 if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) {
370 printk(KERN_ERR "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(1)
375 if ((k = ql_wai(priv)))
376 return (k << 16);
377
378
379
380
381
382 i = inb(qbase + 5);
383 while (!priv->qabort && ((i & 0x20) != 0x20)) {
384 barrier();
385 cpu_relax();
386 i |= inb(qbase + 5);
387 }
388 rtrc(0)
389
390 if (priv->qabort)
391 return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16);
392
393 return (result << 16) | (message << 8) | (status & STATUS_MASK);
394 }
395
396
397
398
399
400 static void ql_ihandl(void *dev_id)
401 {
402 struct scsi_cmnd *icmd;
403 struct Scsi_Host *host = dev_id;
404 struct qlogicfas408_priv *priv = get_priv_by_host(host);
405 int qbase = priv->qbase;
406 REG0;
407
408 if (!(inb(qbase + 4) & 0x80))
409 return;
410
411 if (priv->qlcmd == NULL) {
412 int i;
413 i = 16;
414 while (i-- && inb(qbase + 5));
415 return;
416 }
417 icmd = priv->qlcmd;
418 icmd->result = ql_pcmd(icmd);
419 priv->qlcmd = NULL;
420
421
422
423
424 (icmd->scsi_done) (icmd);
425 }
426
427 irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id)
428 {
429 unsigned long flags;
430 struct Scsi_Host *host = dev_id;
431
432 spin_lock_irqsave(host->host_lock, flags);
433 ql_ihandl(dev_id);
434 spin_unlock_irqrestore(host->host_lock, flags);
435 return IRQ_HANDLED;
436 }
437
438
439
440
441
442 static int qlogicfas408_queuecommand_lck(struct scsi_cmnd *cmd,
443 void (*done) (struct scsi_cmnd *))
444 {
445 struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
446 if (scmd_id(cmd) == priv->qinitid) {
447 cmd->result = DID_BAD_TARGET << 16;
448 done(cmd);
449 return 0;
450 }
451
452 cmd->scsi_done = done;
453
454 while (priv->qlcmd != NULL) {
455 barrier();
456 cpu_relax();
457 }
458 ql_icmd(cmd);
459 return 0;
460 }
461
462 DEF_SCSI_QCMD(qlogicfas408_queuecommand)
463
464
465
466
467
468 int qlogicfas408_biosparam(struct scsi_device *disk, struct block_device *dev,
469 sector_t capacity, int ip[])
470 {
471
472 ip[0] = 0x40;
473 ip[1] = 0x20;
474 ip[2] = (unsigned long) capacity / (ip[0] * ip[1]);
475 if (ip[2] > 1024) {
476 ip[0] = 0xff;
477 ip[1] = 0x3f;
478 ip[2] = (unsigned long) capacity / (ip[0] * ip[1]);
479 #if 0
480 if (ip[2] > 1023)
481 ip[2] = 1023;
482 #endif
483 }
484 return 0;
485 }
486
487
488
489
490
491 int qlogicfas408_abort(struct scsi_cmnd *cmd)
492 {
493 struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
494 priv->qabort = 1;
495 ql_zap(priv);
496 return SUCCESS;
497 }
498
499
500
501
502
503
504
505 int qlogicfas408_host_reset(struct scsi_cmnd *cmd)
506 {
507 struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
508 unsigned long flags;
509
510 priv->qabort = 2;
511
512 spin_lock_irqsave(cmd->device->host->host_lock, flags);
513 ql_zap(priv);
514 spin_unlock_irqrestore(cmd->device->host->host_lock, flags);
515
516 return SUCCESS;
517 }
518
519
520
521
522
523 const char *qlogicfas408_info(struct Scsi_Host *host)
524 {
525 struct qlogicfas408_priv *priv = get_priv_by_host(host);
526 return priv->qinfo;
527 }
528
529
530
531
532
533 int qlogicfas408_get_chip_type(int qbase, int int_type)
534 {
535 REG1;
536 return inb(qbase + 0xe) & 0xf8;
537 }
538
539
540
541
542
543 void qlogicfas408_setup(int qbase, int id, int int_type)
544 {
545 outb(1, qbase + 8);
546 REG0;
547 outb(0x40 | qlcfg8 | id, qbase + 8);
548 outb(qlcfg5, qbase + 5);
549 outb(qlcfg9, qbase + 9);
550
551 #if QL_RESET_AT_START
552 outb(3, qbase + 3);
553
554 REG1;
555
556 while (inb(qbase + 0xf) & 4)
557 cpu_relax();
558
559 REG0;
560 #endif
561 }
562
563
564
565
566
567 int qlogicfas408_detect(int qbase, int int_type)
568 {
569 REG1;
570 return (((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7) &&
571 ((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7));
572 }
573
574
575
576
577
578 void qlogicfas408_disable_ints(struct qlogicfas408_priv *priv)
579 {
580 int qbase = priv->qbase;
581 int int_type = priv->int_type;
582
583 REG1;
584 outb(0, qbase + 0xb);
585 }
586
587
588
589
590
591 static int __init qlogicfas408_init(void)
592 {
593 return 0;
594 }
595
596 static void __exit qlogicfas408_exit(void)
597 {
598
599 }
600
601 MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
602 MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers");
603 MODULE_LICENSE("GPL");
604 module_init(qlogicfas408_init);
605 module_exit(qlogicfas408_exit);
606
607 EXPORT_SYMBOL(qlogicfas408_info);
608 EXPORT_SYMBOL(qlogicfas408_queuecommand);
609 EXPORT_SYMBOL(qlogicfas408_abort);
610 EXPORT_SYMBOL(qlogicfas408_host_reset);
611 EXPORT_SYMBOL(qlogicfas408_biosparam);
612 EXPORT_SYMBOL(qlogicfas408_ihandl);
613 EXPORT_SYMBOL(qlogicfas408_get_chip_type);
614 EXPORT_SYMBOL(qlogicfas408_setup);
615 EXPORT_SYMBOL(qlogicfas408_detect);
616 EXPORT_SYMBOL(qlogicfas408_disable_ints);
617