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