Loading...
1/*----------------------------------------------------------------*/
2/*
3 Qlogic linux driver - work in progress. No Warranty express or implied.
4 Use at your own risk. Support Tort Reform so you won't have to read all
5 these silly disclaimers.
6
7 Copyright 1994, Tom Zerucha.
8 tz@execpc.com
9
10 Additional Code, and much appreciated help by
11 Michael A. Griffith
12 grif@cs.ucr.edu
13
14 Thanks to Eric Youngdale and Dave Hinds for loadable module and PCMCIA
15 help respectively, and for suffering through my foolishness during the
16 debugging process.
17
18 Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994
19 (you can reference it, but it is incomplete and inaccurate in places)
20
21 Version 0.46 1/30/97 - kernel 1.2.0+
22
23 Functions as standalone, loadable, and PCMCIA driver, the latter from
24 Dave Hinds' PCMCIA package.
25
26 Cleaned up 26/10/2002 by Alan Cox <alan@lxorguk.ukuu.org.uk> as part of the 2.5
27 SCSI driver cleanup and audit. This driver still needs work on the
28 following
29 - Non terminating hardware waits
30 - Some layering violations with its pcmcia stub
31
32 Redistributable under terms of the GNU General Public License
33
34 For the avoidance of doubt the "preferred form" of this code is one which
35 is in an open non patent encumbered format. Where cryptographic key signing
36 forms part of the process of creating an executable the information
37 including keys needed to generate an equivalently functional executable
38 are deemed to be part of the source code.
39
40*/
41
42#include <linux/module.h>
43#include <linux/blkdev.h> /* to get disk capacity */
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); /* 15625/512 */
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/* local functions */
74/*----------------------------------------------------------------*/
75
76/* error recovery - reset everything */
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); /* reset SCSI */
87 outb(2, qbase + 3); /* reset chip */
88 if (x & 0x80)
89 REG1;
90}
91
92/*
93 * Do a pseudo-dma tranfer
94 */
95
96static 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) { /* in */
102#if QL_TURBO_PDMA
103 rtrc(4)
104 /* empty fifo in large chunks */
105 if (reqlen >= 128 && (inb(qbase + 8) & 2)) { /* full */
106 insl(qbase + 4, request, 32);
107 reqlen -= 128;
108 request += 128;
109 }
110 while (reqlen >= 84 && !(j & 0xc0)) /* 2/3 */
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)) { /* 1/3 */
118 insl(qbase + 4, request, 11);
119 reqlen -= 44;
120 request += 44;
121 }
122#endif
123 /* until both empty and int (or until reclen is 0) */
124 rtrc(7)
125 j = 0;
126 while (reqlen && !((j & 0x10) && (j & 0xc0)))
127 {
128 /* while bytes to receive and not empty */
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 { /* out */
140#if QL_TURBO_PDMA
141 rtrc(4)
142 if (reqlen >= 128 && inb(qbase + 8) & 0x10) { /* empty */
143 outsl(qbase + 4, request, 32);
144 reqlen -= 128;
145 request += 128;
146 }
147 while (reqlen >= 84 && !(j & 0xc0)) /* 1/3 */
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)) { /* 2/3 */
154 outsl(qbase + 4, request, 10);
155 reqlen -= 40;
156 request += 40;
157 }
158#endif
159 /* until full and int (or until reclen is 0) */
160 rtrc(7)
161 j = 0;
162 while (reqlen && !((j & 2) && (j & 0xc0))) {
163 /* while bytes to send and not full */
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 /* maybe return reqlen */
174 return inb(qbase + 8) & 0xc0;
175}
176
177/*
178 * Wait for interrupt flag (polled - not real hardware interrupt)
179 */
180
181static 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 * Initiate scsi command - queueing handler
209 * caller must hold host lock
210 */
211
212static 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 /* clearing of interrupts and the fifo is needed */
223
224 inb(qbase + 5); /* clear interrupts */
225 if (inb(qbase + 5)) /* if still interrupting */
226 outb(2, qbase + 3); /* reset chip */
227 else if (inb(qbase + 7) & 0x1f)
228 outb(1, qbase + 3); /* clear fifo */
229 while (inb(qbase + 5)); /* clear ints */
230 REG1;
231 outb(1, qbase + 8); /* set for PIO pseudo DMA */
232 outb(0, qbase + 0xb); /* disable ints */
233 inb(qbase + 8); /* clear int bits */
234 REG0;
235 outb(0x40, qbase + 0xb); /* enable features */
236
237 /* configurables */
238 outb(qlcfgc, qbase + 0xc);
239 /* config: no reset interrupt, (initiator) bus id */
240 outb(0x40 | qlcfg8 | priv->qinitid, qbase + 8);
241 outb(qlcfg7, qbase + 7);
242 outb(qlcfg6, qbase + 6);
243 /**/ outb(qlcfg5, qbase + 5); /* select timer */
244 outb(qlcfg9 & 7, qbase + 9); /* prescaler */
245/* outb(0x99, qbase + 5); */
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); /* select and send command */
253}
254
255/*
256 * Process scsi command - usually after interrupt
257 */
258
259static unsigned int ql_pcmd(struct scsi_cmnd *cmd)
260{
261 unsigned int i, j;
262 unsigned long k;
263 unsigned int result; /* ultimate return result */
264 unsigned int status; /* scsi returned status */
265 unsigned int message; /* scsi returned message */
266 unsigned int phase; /* recorded scsi phase */
267 unsigned int reqlen; /* total length of transfer */
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); /* the 0x10 bit can be set after the 0x08 */
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; /* j = inb( qbase + 7 ) >> 5; */
286
287 /* correct status is supposed to be step 4 */
288 /* it sometimes returns step 3 but with 0 bytes left to send */
289 /* We can try stuffing the FIFO with the max each time, but we will get a
290 sequence of 3 if any bytes are left (but we do flush the FIFO anyway */
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) /* if some bytes in fifo */
300 outb(1, qbase + 3); /* clear fifo */
301 /* note that request_bufflen is the total xfer size when sg is used */
302 reqlen = scsi_bufflen(cmd);
303 /* note that it won't work if transfers > 16M are requested */
304 if (reqlen && !((phase = inb(qbase + 4)) & 6)) { /* data phase */
305 struct scatterlist *sg;
306 rtrc(2)
307 outb(reqlen, qbase); /* low-mid xfer cnt */
308 outb(reqlen >> 8, qbase + 1); /* low-mid xfer cnt */
309 outb(reqlen >> 16, qbase + 0xe); /* high xfer cnt */
310 outb(0x90, qbase + 3); /* command do xfer */
311 /* PIO pseudo DMA to buffer or sglist */
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 * Wait for irq (split into second state of irq handler
328 * if this can take time)
329 */
330 if ((k = ql_wai(priv)))
331 return (k << 16);
332 k = inb(qbase + 5); /* should be 0x10, bus service */
333 }
334
335 /*
336 * Enter Status (and Message In) Phase
337 */
338
339 k = jiffies + WATCHDOG;
340
341 while (time_before(jiffies, k) && !priv->qabort &&
342 !(inb(qbase + 4) & 6))
343 cpu_relax(); /* wait for status phase */
344
345 if (time_after_eq(jiffies, k)) {
346 ql_zap(priv);
347 return (DID_TIME_OUT << 16);
348 }
349
350 /* FIXME: timeout ?? */
351 while (inb(qbase + 5))
352 cpu_relax(); /* clear pending ints */
353
354 if (priv->qabort)
355 return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16);
356
357 outb(0x11, qbase + 3); /* get status and message */
358 if ((k = ql_wai(priv)))
359 return (k << 16);
360 i = inb(qbase + 5); /* get chip irq stat */
361 j = inb(qbase + 7) & 0x1f; /* and bytes rec'd */
362 status = inb(qbase + 2);
363 message = inb(qbase + 2);
364
365 /*
366 * Should get function complete int if Status and message, else
367 * bus serv if only status
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); /* done, disconnect */
374 rtrc(1)
375 if ((k = ql_wai(priv)))
376 return (k << 16);
377
378 /*
379 * Should get bus service interrupt and disconnect interrupt
380 */
381
382 i = inb(qbase + 5); /* should be bus service */
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 * Interrupt handler
398 */
399
400static 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)) /* false alarm? */
409 return;
410
411 if (priv->qlcmd == NULL) { /* no command to process? */
412 int i;
413 i = 16;
414 while (i-- && inb(qbase + 5)); /* maybe also ql_zap() */
415 return;
416 }
417 icmd = priv->qlcmd;
418 icmd->result = ql_pcmd(icmd);
419 priv->qlcmd = NULL;
420 /*
421 * If result is CHECK CONDITION done calls qcommand to request
422 * sense
423 */
424 (icmd->scsi_done) (icmd);
425}
426
427irqreturn_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 * Queued command
440 */
441
442static 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 /* wait for the last command's interrupt to finish */
454 while (priv->qlcmd != NULL) {
455 barrier();
456 cpu_relax();
457 }
458 ql_icmd(cmd);
459 return 0;
460}
461
462DEF_SCSI_QCMD(qlogicfas408_queuecommand)
463
464/*
465 * Return bios parameters
466 */
467
468int qlogicfas408_biosparam(struct scsi_device *disk, struct block_device *dev,
469 sector_t capacity, int ip[])
470{
471/* This should mimic the DOS Qlogic driver's behavior exactly */
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 * Abort a command in progress
489 */
490
491int 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 * Reset SCSI bus
501 * FIXME: This function is invoked with cmd = NULL directly by
502 * the PCMCIA qlogic_stub code. This wants fixing
503 */
504
505int qlogicfas408_bus_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 * Return info string
521 */
522
523const 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 * Get type of chip
531 */
532
533int qlogicfas408_get_chip_type(int qbase, int int_type)
534{
535 REG1;
536 return inb(qbase + 0xe) & 0xf8;
537}
538
539/*
540 * Perform initialization tasks
541 */
542
543void qlogicfas408_setup(int qbase, int id, int int_type)
544{
545 outb(1, qbase + 8); /* set for PIO pseudo DMA */
546 REG0;
547 outb(0x40 | qlcfg8 | id, qbase + 8); /* (ini) bus id, disable scsi rst */
548 outb(qlcfg5, qbase + 5); /* select timer */
549 outb(qlcfg9, qbase + 9); /* prescaler */
550
551#if QL_RESET_AT_START
552 outb(3, qbase + 3);
553
554 REG1;
555 /* FIXME: timeout */
556 while (inb(qbase + 0xf) & 4)
557 cpu_relax();
558
559 REG0;
560#endif
561}
562
563/*
564 * Checks if this is a QLogic FAS 408
565 */
566
567int 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 * Disable interrupts
576 */
577
578void 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); /* disable ints */
585}
586
587/*
588 * Init and exit functions
589 */
590
591static int __init qlogicfas408_init(void)
592{
593 return 0;
594}
595
596static void __exit qlogicfas408_exit(void)
597{
598
599}
600
601MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
602MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers");
603MODULE_LICENSE("GPL");
604module_init(qlogicfas408_init);
605module_exit(qlogicfas408_exit);
606
607EXPORT_SYMBOL(qlogicfas408_info);
608EXPORT_SYMBOL(qlogicfas408_queuecommand);
609EXPORT_SYMBOL(qlogicfas408_abort);
610EXPORT_SYMBOL(qlogicfas408_bus_reset);
611EXPORT_SYMBOL(qlogicfas408_biosparam);
612EXPORT_SYMBOL(qlogicfas408_ihandl);
613EXPORT_SYMBOL(qlogicfas408_get_chip_type);
614EXPORT_SYMBOL(qlogicfas408_setup);
615EXPORT_SYMBOL(qlogicfas408_detect);
616EXPORT_SYMBOL(qlogicfas408_disable_ints);
617
1/*----------------------------------------------------------------*/
2/*
3 Qlogic linux driver - work in progress. No Warranty express or implied.
4 Use at your own risk. Support Tort Reform so you won't have to read all
5 these silly disclaimers.
6
7 Copyright 1994, Tom Zerucha.
8 tz@execpc.com
9
10 Additional Code, and much appreciated help by
11 Michael A. Griffith
12 grif@cs.ucr.edu
13
14 Thanks to Eric Youngdale and Dave Hinds for loadable module and PCMCIA
15 help respectively, and for suffering through my foolishness during the
16 debugging process.
17
18 Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994
19 (you can reference it, but it is incomplete and inaccurate in places)
20
21 Version 0.46 1/30/97 - kernel 1.2.0+
22
23 Functions as standalone, loadable, and PCMCIA driver, the latter from
24 Dave Hinds' PCMCIA package.
25
26 Cleaned up 26/10/2002 by Alan Cox <alan@lxorguk.ukuu.org.uk> as part of the 2.5
27 SCSI driver cleanup and audit. This driver still needs work on the
28 following
29 - Non terminating hardware waits
30 - Some layering violations with its pcmcia stub
31
32 Redistributable under terms of the GNU General Public License
33
34 For the avoidance of doubt the "preferred form" of this code is one which
35 is in an open non patent encumbered format. Where cryptographic key signing
36 forms part of the process of creating an executable the information
37 including keys needed to generate an equivalently functional executable
38 are deemed to be part of the source code.
39
40*/
41
42#include <linux/module.h>
43#include <linux/blkdev.h> /* to get disk capacity */
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); /* 15625/512 */
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/* local functions */
74/*----------------------------------------------------------------*/
75
76/* error recovery - reset everything */
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); /* reset SCSI */
87 outb(2, qbase + 3); /* reset chip */
88 if (x & 0x80)
89 REG1;
90}
91
92/*
93 * Do a pseudo-dma tranfer
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) { /* in */
103#if QL_TURBO_PDMA
104 rtrc(4)
105 /* empty fifo in large chunks */
106 if (reqlen >= 128 && (inb(qbase + 8) & 2)) { /* full */
107 insl(qbase + 4, request, 32);
108 reqlen -= 128;
109 request += 128;
110 }
111 while (reqlen >= 84 && !(j & 0xc0)) /* 2/3 */
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)) { /* 1/3 */
119 insl(qbase + 4, request, 11);
120 reqlen -= 44;
121 request += 44;
122 }
123#endif
124 /* until both empty and int (or until reclen is 0) */
125 rtrc(7)
126 j = 0;
127 while (reqlen && !((j & 0x10) && (j & 0xc0)))
128 {
129 /* while bytes to receive and not empty */
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 { /* out */
141#if QL_TURBO_PDMA
142 rtrc(4)
143 if (reqlen >= 128 && inb(qbase + 8) & 0x10) { /* empty */
144 outsl(qbase + 4, request, 32);
145 reqlen -= 128;
146 request += 128;
147 }
148 while (reqlen >= 84 && !(j & 0xc0)) /* 1/3 */
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)) { /* 2/3 */
155 outsl(qbase + 4, request, 10);
156 reqlen -= 40;
157 request += 40;
158 }
159#endif
160 /* until full and int (or until reclen is 0) */
161 rtrc(7)
162 j = 0;
163 while (reqlen && !((j & 2) && (j & 0xc0))) {
164 /* while bytes to send and not full */
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 /* maybe return reqlen */
175 return inb(qbase + 8) & 0xc0;
176}
177
178/*
179 * Wait for interrupt flag (polled - not real hardware interrupt)
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 * Initiate scsi command - queueing handler
210 * caller must hold host lock
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 /* clearing of interrupts and the fifo is needed */
224
225 inb(qbase + 5); /* clear interrupts */
226 if (inb(qbase + 5)) /* if still interrupting */
227 outb(2, qbase + 3); /* reset chip */
228 else if (inb(qbase + 7) & 0x1f)
229 outb(1, qbase + 3); /* clear fifo */
230 while (inb(qbase + 5)); /* clear ints */
231 REG1;
232 outb(1, qbase + 8); /* set for PIO pseudo DMA */
233 outb(0, qbase + 0xb); /* disable ints */
234 inb(qbase + 8); /* clear int bits */
235 REG0;
236 outb(0x40, qbase + 0xb); /* enable features */
237
238 /* configurables */
239 outb(qlcfgc, qbase + 0xc);
240 /* config: no reset interrupt, (initiator) bus id */
241 outb(0x40 | qlcfg8 | priv->qinitid, qbase + 8);
242 outb(qlcfg7, qbase + 7);
243 outb(qlcfg6, qbase + 6);
244 outb(qlcfg5, qbase + 5); /* select timer */
245 outb(qlcfg9 & 7, qbase + 9); /* prescaler */
246/* outb(0x99, qbase + 5); */
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); /* select and send command */
254}
255
256/*
257 * Process scsi command - usually after interrupt
258 */
259
260static void ql_pcmd(struct scsi_cmnd *cmd)
261{
262 unsigned int i, j;
263 unsigned long k;
264 unsigned int status; /* scsi returned status */
265 unsigned int message; /* scsi returned message */
266 unsigned int phase; /* recorded scsi phase */
267 unsigned int reqlen; /* total length of transfer */
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); /* the 0x10 bit can be set after the 0x08 */
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; /* j = inb( qbase + 7 ) >> 5; */
288
289 /* correct status is supposed to be step 4 */
290 /* it sometimes returns step 3 but with 0 bytes left to send */
291 /* We can try stuffing the FIFO with the max each time, but we will get a
292 sequence of 3 if any bytes are left (but we do flush the FIFO anyway */
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) /* if some bytes in fifo */
303 outb(1, qbase + 3); /* clear fifo */
304 /* note that request_bufflen is the total xfer size when sg is used */
305 reqlen = scsi_bufflen(cmd);
306 /* note that it won't work if transfers > 16M are requested */
307 if (reqlen && !((phase = inb(qbase + 4)) & 6)) { /* data phase */
308 struct scatterlist *sg;
309 rtrc(2)
310 outb(reqlen, qbase); /* low-mid xfer cnt */
311 outb(reqlen >> 8, qbase + 1); /* low-mid xfer cnt */
312 outb(reqlen >> 16, qbase + 0xe); /* high xfer cnt */
313 outb(0x90, qbase + 3); /* command do xfer */
314 /* PIO pseudo DMA to buffer or sglist */
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 * Wait for irq (split into second state of irq handler
332 * if this can take time)
333 */
334 if ((k = ql_wai(priv))) {
335 set_host_byte(cmd, k);
336 return;
337 }
338 k = inb(qbase + 5); /* should be 0x10, bus service */
339 }
340
341 /*
342 * Enter Status (and Message In) Phase
343 */
344
345 k = jiffies + WATCHDOG;
346
347 while (time_before(jiffies, k) && !priv->qabort &&
348 !(inb(qbase + 4) & 6))
349 cpu_relax(); /* wait for status phase */
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 /* FIXME: timeout ?? */
358 while (inb(qbase + 5))
359 cpu_relax(); /* clear pending ints */
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); /* get status and message */
368 if ((k = ql_wai(priv))) {
369 set_host_byte(cmd, k);
370 return;
371 }
372 i = inb(qbase + 5); /* get chip irq stat */
373 j = inb(qbase + 7) & 0x1f; /* and bytes rec'd */
374 status = inb(qbase + 2);
375 message = inb(qbase + 2);
376
377 /*
378 * Should get function complete int if Status and message, else
379 * bus serv if only status
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); /* done, disconnect */
386 rtrc(1);
387 if ((k = ql_wai(priv))) {
388 set_host_byte(cmd, k);
389 return;
390 }
391
392 /*
393 * Should get bus service interrupt and disconnect interrupt
394 */
395
396 i = inb(qbase + 5); /* should be bus service */
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 * Interrupt handler
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)) /* false alarm? */
430 return;
431
432 if (priv->qlcmd == NULL) { /* no command to process? */
433 int i;
434 i = 16;
435 while (i-- && inb(qbase + 5)); /* maybe also ql_zap() */
436 return;
437 }
438 icmd = priv->qlcmd;
439 ql_pcmd(icmd);
440 priv->qlcmd = NULL;
441 /*
442 * If result is CHECK CONDITION done calls qcommand to request
443 * sense
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 * Queued command
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 /* wait for the last command's interrupt to finish */
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 * Return bios parameters
490 */
491
492int qlogicfas408_biosparam(struct scsi_device *disk, struct block_device *dev,
493 sector_t capacity, int ip[])
494{
495/* This should mimic the DOS Qlogic driver's behavior exactly */
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 * Abort a command in progress
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 * Reset SCSI bus
525 * FIXME: This function is invoked with cmd = NULL directly by
526 * the PCMCIA qlogic_stub code. This wants fixing
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 * Return info string
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 * Get type of chip
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 * Perform initialization tasks
565 */
566
567void qlogicfas408_setup(int qbase, int id, int int_type)
568{
569 outb(1, qbase + 8); /* set for PIO pseudo DMA */
570 REG0;
571 outb(0x40 | qlcfg8 | id, qbase + 8); /* (ini) bus id, disable scsi rst */
572 outb(qlcfg5, qbase + 5); /* select timer */
573 outb(qlcfg9, qbase + 9); /* prescaler */
574
575#if QL_RESET_AT_START
576 outb(3, qbase + 3);
577
578 REG1;
579 /* FIXME: timeout */
580 while (inb(qbase + 0xf) & 4)
581 cpu_relax();
582
583 REG0;
584#endif
585}
586
587/*
588 * Checks if this is a QLogic FAS 408
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 * Disable interrupts
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); /* disable ints */
609}
610
611/*
612 * Init and exit functions
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