1 /*----------------------------------------------------------------*/
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.
7 Copyright 1994, Tom Zerucha.
10 Additional Code, and much appreciated help by
14 Thanks to Eric Youngdale and Dave Hinds for loadable module and PCMCIA
15 help respectively, and for suffering through my foolishness during the
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)
21 Version 0.46 1/30/97 - kernel 1.2.0+
23 Functions as standalone, loadable, and PCMCIA driver, the latter from
24 Dave Hinds' PCMCIA package.
26 Cleaned up 26/10/2002 by Alan Cox <alan@redhat.com> as part of the 2.5
27 SCSI driver cleanup and audit. This driver still needs work on the
29 - Non terminating hardware waits
30 - Some layering violations with its pcmcia stub
32 Redistributable under terms of the GNU General Public License
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.
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>
59 #include <scsi/scsi_host.h>
60 #include "qlogicfas408.h"
62 /*----------------------------------------------------------------*/
63 static int qlcfg5 = (XTALFREQ << 5); /* 15625/512 */
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);
70 /*----------------------------------------------------------------*/
72 /*----------------------------------------------------------------*/
74 /*----------------------------------------------------------------*/
76 /* error recovery - reset everything */
78 static void ql_zap(struct qlogicfas408_priv *priv)
81 int qbase = priv->qbase;
82 int int_type = priv->int_type;
86 outb(3, qbase + 3); /* reset SCSI */
87 outb(2, qbase + 3); /* reset chip */
93 * Do a pseudo-dma tranfer
96 static int ql_pdma(struct qlogicfas408_priv *priv, int phase, char *request, int reqlen)
99 int qbase = priv->qbase;
101 if (phase & 1) { /* in */
104 /* empty fifo in large chunks */
105 if (reqlen >= 128 && (inb(qbase + 8) & 2)) { /* full */
106 insl(qbase + 4, request, 32);
110 while (reqlen >= 84 && !(j & 0xc0)) /* 2/3 */
111 if ((j = inb(qbase + 8)) & 4)
113 insl(qbase + 4, request, 21);
117 if (reqlen >= 44 && (inb(qbase + 8) & 8)) { /* 1/3 */
118 insl(qbase + 4, request, 11);
123 /* until both empty and int (or until reclen is 0) */
126 while (reqlen && !((j & 0x10) && (j & 0xc0)))
128 /* while bytes to receive and not empty */
130 while (reqlen && !((j = inb(qbase + 8)) & 0x10))
132 *request++ = inb(qbase + 4);
142 if (reqlen >= 128 && inb(qbase + 8) & 0x10) { /* empty */
143 outsl(qbase + 4, request, 32);
147 while (reqlen >= 84 && !(j & 0xc0)) /* 1/3 */
148 if (!((j = inb(qbase + 8)) & 8)) {
149 outsl(qbase + 4, request, 21);
153 if (reqlen >= 40 && !(inb(qbase + 8) & 4)) { /* 2/3 */
154 outsl(qbase + 4, request, 10);
159 /* until full and int (or until reclen is 0) */
162 while (reqlen && !((j & 2) && (j & 0xc0))) {
163 /* while bytes to send and not full */
164 while (reqlen && !((j = inb(qbase + 8)) & 2))
166 outb(*request++, qbase + 4);
173 /* maybe return reqlen */
174 return inb(qbase + 8) & 0xc0;
178 * Wait for interrupt flag (polled - not real hardware interrupt)
181 static int ql_wai(struct qlogicfas408_priv *priv)
184 int qbase = priv->qbase;
188 i = jiffies + WATCHDOG;
189 while (time_before(jiffies, i) && !priv->qabort &&
190 !((k = inb(qbase + 4)) & 0xe0)) {
194 if (time_after_eq(jiffies, i))
195 return (DID_TIME_OUT);
197 return (priv->qabort == 1 ? DID_ABORT : DID_RESET);
208 * Initiate scsi command - queueing handler
209 * caller must hold host lock
212 static void ql_icmd(Scsi_Cmnd * cmd)
214 struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
215 int qbase = priv->qbase;
216 int int_type = priv->int_type;
222 /* clearing of interrupts and the fifo is needed */
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 */
231 outb(1, qbase + 8); /* set for PIO pseudo DMA */
232 outb(0, qbase + 0xb); /* disable ints */
233 inb(qbase + 8); /* clear int bits */
235 outb(0x40, qbase + 0xb); /* enable features */
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(cmd->device->id, qbase + 4);
248 for (i = 0; i < cmd->cmd_len; i++)
249 outb(cmd->cmnd[i], qbase + 2);
252 outb(0x41, qbase + 3); /* select and send command */
256 * Process scsi command - usually after interrupt
259 static unsigned int ql_pcmd(Scsi_Cmnd * cmd)
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 struct scatterlist *sglist; /* scatter-gather list pointer */
269 unsigned int sgcount; /* sg counter */
271 struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
272 int qbase = priv->qbase;
273 int int_type = priv->int_type;
279 return (DID_NO_CONNECT << 16);
281 i |= inb(qbase + 5); /* the 0x10 bit can be set after the 0x08 */
283 printk(KERN_ERR "Ql:Bad Interrupt status:%02x\n", i);
285 return (DID_BAD_INTR << 16);
287 j &= 7; /* j = inb( qbase + 7 ) >> 5; */
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 */
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);
298 return (DID_ERROR << 16);
301 if (inb(qbase + 7) & 0x1f) /* if some bytes in fifo */
302 outb(1, qbase + 3); /* clear fifo */
303 /* note that request_bufflen is the total xfer size when sg is used */
304 reqlen = cmd->request_bufflen;
305 /* note that it won't work if transfers > 16M are requested */
306 if (reqlen && !((phase = inb(qbase + 4)) & 6)) { /* data phase */
308 outb(reqlen, qbase); /* low-mid xfer cnt */
309 outb(reqlen >> 8, qbase + 1); /* low-mid xfer cnt */
310 outb(reqlen >> 16, qbase + 0xe); /* high xfer cnt */
311 outb(0x90, qbase + 3); /* command do xfer */
312 /* PIO pseudo DMA to buffer or sglist */
315 ql_pdma(priv, phase, cmd->request_buffer,
316 cmd->request_bufflen);
318 sgcount = cmd->use_sg;
319 sglist = cmd->request_buffer;
323 return ((priv->qabort == 1 ?
324 DID_ABORT : DID_RESET) << 16);
326 buf = page_address(sglist->page) + sglist->offset;
327 if (ql_pdma(priv, phase, buf, sglist->length))
335 * Wait for irq (split into second state of irq handler
336 * if this can take time)
338 if ((k = ql_wai(priv)))
340 k = inb(qbase + 5); /* should be 0x10, bus service */
344 * Enter Status (and Message In) Phase
347 k = jiffies + WATCHDOG;
349 while (time_before(jiffies, k) && !priv->qabort &&
350 !(inb(qbase + 4) & 6))
351 cpu_relax(); /* wait for status phase */
353 if (time_after_eq(jiffies, k)) {
355 return (DID_TIME_OUT << 16);
358 /* FIXME: timeout ?? */
359 while (inb(qbase + 5))
360 cpu_relax(); /* clear pending ints */
363 return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16);
365 outb(0x11, qbase + 3); /* get status and message */
366 if ((k = ql_wai(priv)))
368 i = inb(qbase + 5); /* get chip irq stat */
369 j = inb(qbase + 7) & 0x1f; /* and bytes rec'd */
370 status = inb(qbase + 2);
371 message = inb(qbase + 2);
374 * Should get function complete int if Status and message, else
375 * bus serv if only status
377 if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) {
378 printk(KERN_ERR "Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j);
381 outb(0x12, qbase + 3); /* done, disconnect */
383 if ((k = ql_wai(priv)))
387 * Should get bus service interrupt and disconnect interrupt
390 i = inb(qbase + 5); /* should be bus service */
391 while (!priv->qabort && ((i & 0x20) != 0x20)) {
399 return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16);
401 return (result << 16) | (message << 8) | (status & STATUS_MASK);
408 static void ql_ihandl(int irq, void *dev_id, struct pt_regs *regs)
411 struct Scsi_Host *host = (struct Scsi_Host *)dev_id;
412 struct qlogicfas408_priv *priv = get_priv_by_host(host);
413 int qbase = priv->qbase;
416 if (!(inb(qbase + 4) & 0x80)) /* false alarm? */
419 if (priv->qlcmd == NULL) { /* no command to process? */
422 while (i-- && inb(qbase + 5)); /* maybe also ql_zap() */
426 icmd->result = ql_pcmd(icmd);
429 * If result is CHECK CONDITION done calls qcommand to request
432 (icmd->scsi_done) (icmd);
435 irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id, struct pt_regs *regs)
438 struct Scsi_Host *host = dev_id;
440 spin_lock_irqsave(host->host_lock, flags);
441 ql_ihandl(irq, dev_id, regs);
442 spin_unlock_irqrestore(host->host_lock, flags);
450 int qlogicfas408_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
452 struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
453 if (cmd->device->id == priv->qinitid) {
454 cmd->result = DID_BAD_TARGET << 16;
459 cmd->scsi_done = done;
460 /* wait for the last command's interrupt to finish */
461 while (priv->qlcmd != NULL) {
470 * Return bios parameters
473 int qlogicfas408_biosparam(struct scsi_device * disk,
474 struct block_device *dev,
475 sector_t capacity, int ip[])
477 /* This should mimic the DOS Qlogic driver's behavior exactly */
480 ip[2] = (unsigned long) capacity / (ip[0] * ip[1]);
484 ip[2] = (unsigned long) capacity / (ip[0] * ip[1]);
494 * Abort a command in progress
497 int qlogicfas408_abort(Scsi_Cmnd * cmd)
499 struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
507 * FIXME: This function is invoked with cmd = NULL directly by
508 * the PCMCIA qlogic_stub code. This wants fixing
511 int qlogicfas408_bus_reset(Scsi_Cmnd * cmd)
513 struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
520 * Reset SCSI host controller
523 int qlogicfas408_host_reset(Scsi_Cmnd * cmd)
532 int qlogicfas408_device_reset(Scsi_Cmnd * cmd)
541 const char *qlogicfas408_info(struct Scsi_Host *host)
543 struct qlogicfas408_priv *priv = get_priv_by_host(host);
551 int qlogicfas408_get_chip_type(int qbase, int int_type)
554 return inb(qbase + 0xe) & 0xf8;
558 * Perform initialization tasks
561 void qlogicfas408_setup(int qbase, int id, int int_type)
563 outb(1, qbase + 8); /* set for PIO pseudo DMA */
565 outb(0x40 | qlcfg8 | id, qbase + 8); /* (ini) bus id, disable scsi rst */
566 outb(qlcfg5, qbase + 5); /* select timer */
567 outb(qlcfg9, qbase + 9); /* prescaler */
569 #if QL_RESET_AT_START
574 while (inb(qbase + 0xf) & 4)
582 * Checks if this is a QLogic FAS 408
585 int qlogicfas408_detect(int qbase, int int_type)
588 return (((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7) &&
589 ((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7));
596 void qlogicfas408_disable_ints(struct qlogicfas408_priv *priv)
598 int qbase = priv->qbase;
599 int int_type = priv->int_type;
602 outb(0, qbase + 0xb); /* disable ints */
606 * Init and exit functions
609 static int __init qlogicfas408_init(void)
614 static void __exit qlogicfas408_exit(void)
619 MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
620 MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers");
621 MODULE_LICENSE("GPL");
622 module_init(qlogicfas408_init);
623 module_exit(qlogicfas408_exit);
625 EXPORT_SYMBOL(qlogicfas408_info);
626 EXPORT_SYMBOL(qlogicfas408_queuecommand);
627 EXPORT_SYMBOL(qlogicfas408_abort);
628 EXPORT_SYMBOL(qlogicfas408_bus_reset);
629 EXPORT_SYMBOL(qlogicfas408_device_reset);
630 EXPORT_SYMBOL(qlogicfas408_host_reset);
631 EXPORT_SYMBOL(qlogicfas408_biosparam);
632 EXPORT_SYMBOL(qlogicfas408_ihandl);
633 EXPORT_SYMBOL(qlogicfas408_get_chip_type);
634 EXPORT_SYMBOL(qlogicfas408_setup);
635 EXPORT_SYMBOL(qlogicfas408_detect);
636 EXPORT_SYMBOL(qlogicfas408_disable_ints);