Back to home page

OSCL-LXR

 
 

    


0001 /*----------------------------------------------------------------*/
0002 /*
0003    Qlogic linux driver - work in progress. No Warranty express or implied.
0004    Use at your own risk.  Support Tort Reform so you won't have to read all
0005    these silly disclaimers.
0006 
0007    Copyright 1994, Tom Zerucha.
0008    tz@execpc.com
0009 
0010    Additional Code, and much appreciated help by
0011    Michael A. Griffith
0012    grif@cs.ucr.edu
0013 
0014    Thanks to Eric Youngdale and Dave Hinds for loadable module and PCMCIA
0015    help respectively, and for suffering through my foolishness during the
0016    debugging process.
0017 
0018    Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994
0019    (you can reference it, but it is incomplete and inaccurate in places)
0020 
0021    Version 0.46 1/30/97 - kernel 1.2.0+
0022 
0023    Functions as standalone, loadable, and PCMCIA driver, the latter from
0024    Dave Hinds' PCMCIA package.
0025 
0026    Cleaned up 26/10/2002 by Alan Cox <alan@lxorguk.ukuu.org.uk> as part of the 2.5
0027    SCSI driver cleanup and audit. This driver still needs work on the
0028    following
0029     -   Non terminating hardware waits
0030     -   Some layering violations with its pcmcia stub
0031 
0032    Redistributable under terms of the GNU General Public License
0033 
0034    For the avoidance of doubt the "preferred form" of this code is one which
0035    is in an open non patent encumbered format. Where cryptographic key signing
0036    forms part of the process of creating an executable the information
0037    including keys needed to generate an equivalently functional executable
0038    are deemed to be part of the source code.
0039 
0040 */
0041 
0042 #include <linux/module.h>
0043 #include <linux/blkdev.h>       /* to get disk capacity */
0044 #include <linux/kernel.h>
0045 #include <linux/string.h>
0046 #include <linux/init.h>
0047 #include <linux/interrupt.h>
0048 #include <linux/ioport.h>
0049 #include <linux/proc_fs.h>
0050 #include <linux/unistd.h>
0051 #include <linux/spinlock.h>
0052 #include <linux/stat.h>
0053 
0054 #include <asm/io.h>
0055 #include <asm/irq.h>
0056 #include <asm/dma.h>
0057 
0058 #include <scsi/scsi.h>
0059 #include <scsi/scsi_cmnd.h>
0060 #include <scsi/scsi_device.h>
0061 #include <scsi/scsi_eh.h>
0062 #include <scsi/scsi_host.h>
0063 #include <scsi/scsi_tcq.h>
0064 #include "qlogicfas408.h"
0065 
0066 /*----------------------------------------------------------------*/
0067 static int qlcfg5 = (XTALFREQ << 5);    /* 15625/512 */
0068 static int qlcfg6 = SYNCXFRPD;
0069 static int qlcfg7 = SYNCOFFST;
0070 static int qlcfg8 = (SLOWCABLE << 7) | (QL_ENABLE_PARITY << 4);
0071 static int qlcfg9 = ((XTALFREQ + 4) / 5);
0072 static int qlcfgc = (FASTCLK << 3) | (FASTSCSI << 4);
0073 
0074 /*----------------------------------------------------------------*/
0075 
0076 /*----------------------------------------------------------------*/
0077 /* local functions */
0078 /*----------------------------------------------------------------*/
0079 
0080 /* error recovery - reset everything */
0081 
0082 static void ql_zap(struct qlogicfas408_priv *priv)
0083 {
0084     int x;
0085     int qbase = priv->qbase;
0086     int int_type = priv->int_type;
0087 
0088     x = inb(qbase + 0xd);
0089     REG0;
0090     outb(3, qbase + 3); /* reset SCSI */
0091     outb(2, qbase + 3); /* reset chip */
0092     if (x & 0x80)
0093         REG1;
0094 }
0095 
0096 /*
0097  *  Do a pseudo-dma tranfer
0098  */
0099 
0100 static int ql_pdma(struct qlogicfas408_priv *priv, int phase, char *request,
0101            int reqlen)
0102 {
0103     int j;
0104     int qbase = priv->qbase;
0105     j = 0;
0106     if (phase & 1) {    /* in */
0107 #if QL_TURBO_PDMA
0108         rtrc(4)
0109         /* empty fifo in large chunks */
0110         if (reqlen >= 128 && (inb(qbase + 8) & 2)) {    /* full */
0111             insl(qbase + 4, request, 32);
0112             reqlen -= 128;
0113             request += 128;
0114         }
0115         while (reqlen >= 84 && !(j & 0xc0)) /* 2/3 */
0116             if ((j = inb(qbase + 8)) & 4)
0117             {
0118                 insl(qbase + 4, request, 21);
0119                 reqlen -= 84;
0120                 request += 84;
0121             }
0122         if (reqlen >= 44 && (inb(qbase + 8) & 8)) { /* 1/3 */
0123             insl(qbase + 4, request, 11);
0124             reqlen -= 44;
0125             request += 44;
0126         }
0127 #endif
0128         /* until both empty and int (or until reclen is 0) */
0129         rtrc(7)
0130         j = 0;
0131         while (reqlen && !((j & 0x10) && (j & 0xc0)))
0132         {
0133             /* while bytes to receive and not empty */
0134             j &= 0xc0;
0135             while (reqlen && !((j = inb(qbase + 8)) & 0x10))
0136             {
0137                 *request++ = inb(qbase + 4);
0138                 reqlen--;
0139             }
0140             if (j & 0x10)
0141                 j = inb(qbase + 8);
0142 
0143         }
0144     } else {        /* out */
0145 #if QL_TURBO_PDMA
0146         rtrc(4)
0147         if (reqlen >= 128 && inb(qbase + 8) & 0x10) {   /* empty */
0148             outsl(qbase + 4, request, 32);
0149             reqlen -= 128;
0150             request += 128;
0151         }
0152         while (reqlen >= 84 && !(j & 0xc0)) /* 1/3 */
0153             if (!((j = inb(qbase + 8)) & 8)) {
0154                 outsl(qbase + 4, request, 21);
0155                 reqlen -= 84;
0156                 request += 84;
0157             }
0158         if (reqlen >= 40 && !(inb(qbase + 8) & 4)) {    /* 2/3 */
0159             outsl(qbase + 4, request, 10);
0160             reqlen -= 40;
0161             request += 40;
0162         }
0163 #endif
0164         /* until full and int (or until reclen is 0) */
0165         rtrc(7)
0166             j = 0;
0167         while (reqlen && !((j & 2) && (j & 0xc0))) {
0168             /* while bytes to send and not full */
0169             while (reqlen && !((j = inb(qbase + 8)) & 2))
0170             {
0171                 outb(*request++, qbase + 4);
0172                 reqlen--;
0173             }
0174             if (j & 2)
0175                 j = inb(qbase + 8);
0176         }
0177     }
0178     /* maybe return reqlen */
0179     return inb(qbase + 8) & 0xc0;
0180 }
0181 
0182 /*
0183  *  Wait for interrupt flag (polled - not real hardware interrupt)
0184  */
0185 
0186 static int ql_wai(struct qlogicfas408_priv *priv)
0187 {
0188     int k;
0189     int qbase = priv->qbase;
0190     unsigned long i;
0191 
0192     k = 0;
0193     i = jiffies + WATCHDOG;
0194     while (time_before(jiffies, i) && !priv->qabort &&
0195                     !((k = inb(qbase + 4)) & 0xe0)) {
0196         barrier();
0197         cpu_relax();
0198     }
0199     if (time_after_eq(jiffies, i))
0200         return (DID_TIME_OUT);
0201     if (priv->qabort)
0202         return (priv->qabort == 1 ? DID_ABORT : DID_RESET);
0203     if (k & 0x60)
0204         ql_zap(priv);
0205     if (k & 0x20)
0206         return (DID_PARITY);
0207     if (k & 0x40)
0208         return (DID_ERROR);
0209     return 0;
0210 }
0211 
0212 /*
0213  *  Initiate scsi command - queueing handler
0214  *  caller must hold host lock
0215  */
0216 
0217 static void ql_icmd(struct scsi_cmnd *cmd)
0218 {
0219     struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
0220     int qbase = priv->qbase;
0221     int int_type = priv->int_type;
0222     unsigned int i;
0223 
0224     priv->qabort = 0;
0225 
0226     REG0;
0227     /* clearing of interrupts and the fifo is needed */
0228 
0229     inb(qbase + 5);     /* clear interrupts */
0230     if (inb(qbase + 5)) /* if still interrupting */
0231         outb(2, qbase + 3); /* reset chip */
0232     else if (inb(qbase + 7) & 0x1f)
0233         outb(1, qbase + 3); /* clear fifo */
0234     while (inb(qbase + 5)); /* clear ints */
0235     REG1;
0236     outb(1, qbase + 8); /* set for PIO pseudo DMA */
0237     outb(0, qbase + 0xb);   /* disable ints */
0238     inb(qbase + 8);     /* clear int bits */
0239     REG0;
0240     outb(0x40, qbase + 0xb);    /* enable features */
0241 
0242     /* configurables */
0243     outb(qlcfgc, qbase + 0xc);
0244     /* config: no reset interrupt, (initiator) bus id */
0245     outb(0x40 | qlcfg8 | priv->qinitid, qbase + 8);
0246     outb(qlcfg7, qbase + 7);
0247     outb(qlcfg6, qbase + 6);
0248     outb(qlcfg5, qbase + 5);    /* select timer */
0249     outb(qlcfg9 & 7, qbase + 9);    /* prescaler */
0250 /*  outb(0x99, qbase + 5);  */
0251     outb(scmd_id(cmd), qbase + 4);
0252 
0253     for (i = 0; i < cmd->cmd_len; i++)
0254         outb(cmd->cmnd[i], qbase + 2);
0255 
0256     priv->qlcmd = cmd;
0257     outb(0x41, qbase + 3);  /* select and send command */
0258 }
0259 
0260 /*
0261  *  Process scsi command - usually after interrupt
0262  */
0263 
0264 static void ql_pcmd(struct scsi_cmnd *cmd)
0265 {
0266     unsigned int i, j;
0267     unsigned long k;
0268     unsigned int status;    /* scsi returned status */
0269     unsigned int message;   /* scsi returned message */
0270     unsigned int phase; /* recorded scsi phase */
0271     unsigned int reqlen;    /* total length of transfer */
0272     char *buf;
0273     struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
0274     int qbase = priv->qbase;
0275     int int_type = priv->int_type;
0276 
0277     rtrc(1)
0278     j = inb(qbase + 6);
0279     i = inb(qbase + 5);
0280     if (i == 0x20) {
0281         set_host_byte(cmd, DID_NO_CONNECT);
0282         return;
0283     }
0284     i |= inb(qbase + 5);    /* the 0x10 bit can be set after the 0x08 */
0285     if (i != 0x18) {
0286         printk(KERN_ERR "Ql:Bad Interrupt status:%02x\n", i);
0287         ql_zap(priv);
0288         set_host_byte(cmd, DID_BAD_INTR);
0289         return;
0290     }
0291     j &= 7;         /* j = inb( qbase + 7 ) >> 5; */
0292 
0293     /* correct status is supposed to be step 4 */
0294     /* it sometimes returns step 3 but with 0 bytes left to send */
0295     /* We can try stuffing the FIFO with the max each time, but we will get a
0296        sequence of 3 if any bytes are left (but we do flush the FIFO anyway */
0297 
0298     if (j != 3 && j != 4) {
0299         printk(KERN_ERR "Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n",
0300              j, i, inb(qbase + 7) & 0x1f);
0301         ql_zap(priv);
0302         set_host_byte(cmd, DID_ERROR);
0303         return;
0304     }
0305 
0306     if (inb(qbase + 7) & 0x1f)  /* if some bytes in fifo */
0307         outb(1, qbase + 3); /* clear fifo */
0308     /* note that request_bufflen is the total xfer size when sg is used */
0309     reqlen = scsi_bufflen(cmd);
0310     /* note that it won't work if transfers > 16M are requested */
0311     if (reqlen && !((phase = inb(qbase + 4)) & 6)) {    /* data phase */
0312         struct scatterlist *sg;
0313         rtrc(2)
0314         outb(reqlen, qbase);    /* low-mid xfer cnt */
0315         outb(reqlen >> 8, qbase + 1);   /* low-mid xfer cnt */
0316         outb(reqlen >> 16, qbase + 0xe);    /* high xfer cnt */
0317         outb(0x90, qbase + 3);  /* command do xfer */
0318         /* PIO pseudo DMA to buffer or sglist */
0319         REG1;
0320 
0321         scsi_for_each_sg(cmd, sg, scsi_sg_count(cmd), i) {
0322             if (priv->qabort) {
0323                 REG0;
0324                 set_host_byte(cmd,
0325                           priv->qabort == 1 ?
0326                           DID_ABORT : DID_RESET);
0327             }
0328             buf = sg_virt(sg);
0329             if (ql_pdma(priv, phase, buf, sg->length))
0330                 break;
0331         }
0332         REG0;
0333         rtrc(2);
0334         /*
0335          *  Wait for irq (split into second state of irq handler
0336          *  if this can take time)
0337          */
0338         if ((k = ql_wai(priv))) {
0339             set_host_byte(cmd, k);
0340             return;
0341         }
0342         k = inb(qbase + 5); /* should be 0x10, bus service */
0343     }
0344 
0345     /*
0346      *  Enter Status (and Message In) Phase
0347      */
0348 
0349     k = jiffies + WATCHDOG;
0350 
0351     while (time_before(jiffies, k) && !priv->qabort &&
0352                         !(inb(qbase + 4) & 6))
0353         cpu_relax();    /* wait for status phase */
0354 
0355     if (time_after_eq(jiffies, k)) {
0356         ql_zap(priv);
0357         set_host_byte(cmd, DID_TIME_OUT);
0358         return;
0359     }
0360 
0361     /* FIXME: timeout ?? */
0362     while (inb(qbase + 5))
0363         cpu_relax();    /* clear pending ints */
0364 
0365     if (priv->qabort) {
0366         set_host_byte(cmd,
0367                   priv->qabort == 1 ? DID_ABORT : DID_RESET);
0368         return;
0369     }
0370 
0371     outb(0x11, qbase + 3);  /* get status and message */
0372     if ((k = ql_wai(priv))) {
0373         set_host_byte(cmd, k);
0374         return;
0375     }
0376     i = inb(qbase + 5); /* get chip irq stat */
0377     j = inb(qbase + 7) & 0x1f;  /* and bytes rec'd */
0378     status = inb(qbase + 2);
0379     message = inb(qbase + 2);
0380 
0381     /*
0382      *  Should get function complete int if Status and message, else
0383      *  bus serv if only status
0384      */
0385     if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) {
0386         printk(KERN_ERR "Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j);
0387         set_host_byte(cmd, DID_ERROR);
0388     }
0389     outb(0x12, qbase + 3);  /* done, disconnect */
0390     rtrc(1);
0391     if ((k = ql_wai(priv))) {
0392         set_host_byte(cmd, k);
0393         return;
0394     }
0395 
0396     /*
0397      *  Should get bus service interrupt and disconnect interrupt
0398      */
0399 
0400     i = inb(qbase + 5); /* should be bus service */
0401     while (!priv->qabort && ((i & 0x20) != 0x20)) {
0402         barrier();
0403         cpu_relax();
0404         i |= inb(qbase + 5);
0405     }
0406     rtrc(0);
0407 
0408     if (priv->qabort) {
0409         set_host_byte(cmd,
0410                   priv->qabort == 1 ? DID_ABORT : DID_RESET);
0411         return;
0412     }
0413 
0414     set_host_byte(cmd, DID_OK);
0415     if (message != COMMAND_COMPLETE)
0416         scsi_msg_to_host_byte(cmd, message);
0417     set_status_byte(cmd, status);
0418     return;
0419 }
0420 
0421 /*
0422  *  Interrupt handler
0423  */
0424 
0425 static void ql_ihandl(void *dev_id)
0426 {
0427     struct scsi_cmnd *icmd;
0428     struct Scsi_Host *host = dev_id;
0429     struct qlogicfas408_priv *priv = get_priv_by_host(host);
0430     int qbase = priv->qbase;
0431     REG0;
0432 
0433     if (!(inb(qbase + 4) & 0x80))   /* false alarm? */
0434         return;
0435 
0436     if (priv->qlcmd == NULL) {  /* no command to process? */
0437         int i;
0438         i = 16;
0439         while (i-- && inb(qbase + 5));  /* maybe also ql_zap() */
0440         return;
0441     }
0442     icmd = priv->qlcmd;
0443     ql_pcmd(icmd);
0444     priv->qlcmd = NULL;
0445     /*
0446      *  If result is CHECK CONDITION done calls qcommand to request
0447      *  sense
0448      */
0449     scsi_done(icmd);
0450 }
0451 
0452 irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id)
0453 {
0454     unsigned long flags;
0455     struct Scsi_Host *host = dev_id;
0456 
0457     spin_lock_irqsave(host->host_lock, flags);
0458     ql_ihandl(dev_id);
0459     spin_unlock_irqrestore(host->host_lock, flags);
0460     return IRQ_HANDLED;
0461 }
0462 
0463 /*
0464  *  Queued command
0465  */
0466 
0467 static int qlogicfas408_queuecommand_lck(struct scsi_cmnd *cmd)
0468 {
0469     void (*done)(struct scsi_cmnd *) = scsi_done;
0470     struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
0471 
0472     set_host_byte(cmd, DID_OK);
0473     set_status_byte(cmd, SAM_STAT_GOOD);
0474     if (scmd_id(cmd) == priv->qinitid) {
0475         set_host_byte(cmd, DID_BAD_TARGET);
0476         done(cmd);
0477         return 0;
0478     }
0479 
0480     /* wait for the last command's interrupt to finish */
0481     while (priv->qlcmd != NULL) {
0482         barrier();
0483         cpu_relax();
0484     }
0485     ql_icmd(cmd);
0486     return 0;
0487 }
0488 
0489 DEF_SCSI_QCMD(qlogicfas408_queuecommand)
0490 
0491 /*
0492  *  Return bios parameters
0493  */
0494 
0495 int qlogicfas408_biosparam(struct scsi_device *disk, struct block_device *dev,
0496                sector_t capacity, int ip[])
0497 {
0498 /* This should mimic the DOS Qlogic driver's behavior exactly */
0499     ip[0] = 0x40;
0500     ip[1] = 0x20;
0501     ip[2] = (unsigned long) capacity / (ip[0] * ip[1]);
0502     if (ip[2] > 1024) {
0503         ip[0] = 0xff;
0504         ip[1] = 0x3f;
0505         ip[2] = (unsigned long) capacity / (ip[0] * ip[1]);
0506 #if 0
0507         if (ip[2] > 1023)
0508             ip[2] = 1023;
0509 #endif
0510     }
0511     return 0;
0512 }
0513 
0514 /*
0515  *  Abort a command in progress
0516  */
0517 
0518 int qlogicfas408_abort(struct scsi_cmnd *cmd)
0519 {
0520     struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
0521     priv->qabort = 1;
0522     ql_zap(priv);
0523     return SUCCESS;
0524 }
0525 
0526 /*
0527  *  Reset SCSI bus
0528  *  FIXME: This function is invoked with cmd = NULL directly by
0529  *  the PCMCIA qlogic_stub code. This wants fixing
0530  */
0531 
0532 int qlogicfas408_host_reset(struct scsi_cmnd *cmd)
0533 {
0534     struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
0535     unsigned long flags;
0536 
0537     priv->qabort = 2;
0538 
0539     spin_lock_irqsave(cmd->device->host->host_lock, flags);
0540     ql_zap(priv);
0541     spin_unlock_irqrestore(cmd->device->host->host_lock, flags);
0542 
0543     return SUCCESS;
0544 }
0545 
0546 /*
0547  *  Return info string
0548  */
0549 
0550 const char *qlogicfas408_info(struct Scsi_Host *host)
0551 {
0552     struct qlogicfas408_priv *priv = get_priv_by_host(host);
0553     return priv->qinfo;
0554 }
0555 
0556 /*
0557  *  Get type of chip
0558  */
0559 
0560 int qlogicfas408_get_chip_type(int qbase, int int_type)
0561 {
0562     REG1;
0563     return inb(qbase + 0xe) & 0xf8;
0564 }
0565 
0566 /*
0567  *  Perform initialization tasks
0568  */
0569 
0570 void qlogicfas408_setup(int qbase, int id, int int_type)
0571 {
0572     outb(1, qbase + 8); /* set for PIO pseudo DMA */
0573     REG0;
0574     outb(0x40 | qlcfg8 | id, qbase + 8);    /* (ini) bus id, disable scsi rst */
0575     outb(qlcfg5, qbase + 5);    /* select timer */
0576     outb(qlcfg9, qbase + 9);    /* prescaler */
0577 
0578 #if QL_RESET_AT_START
0579     outb(3, qbase + 3);
0580 
0581     REG1;
0582     /* FIXME: timeout */
0583     while (inb(qbase + 0xf) & 4)
0584         cpu_relax();
0585 
0586     REG0;
0587 #endif
0588 }
0589 
0590 /*
0591  *  Checks if this is a QLogic FAS 408
0592  */
0593 
0594 int qlogicfas408_detect(int qbase, int int_type)
0595 {
0596     REG1;
0597     return (((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7) &&
0598         ((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7));
0599 }
0600 
0601 /*
0602  *  Disable interrupts
0603  */
0604 
0605 void qlogicfas408_disable_ints(struct qlogicfas408_priv *priv)
0606 {
0607     int qbase = priv->qbase;
0608     int int_type = priv->int_type;
0609 
0610     REG1;
0611     outb(0, qbase + 0xb);   /* disable ints */
0612 }
0613 
0614 /*
0615  *  Init and exit functions
0616  */
0617 
0618 static int __init qlogicfas408_init(void)
0619 {
0620     return 0;
0621 }
0622 
0623 static void __exit qlogicfas408_exit(void)
0624 {
0625 
0626 }
0627 
0628 MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
0629 MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers");
0630 MODULE_LICENSE("GPL");
0631 module_init(qlogicfas408_init);
0632 module_exit(qlogicfas408_exit);
0633 
0634 EXPORT_SYMBOL(qlogicfas408_info);
0635 EXPORT_SYMBOL(qlogicfas408_queuecommand);
0636 EXPORT_SYMBOL(qlogicfas408_abort);
0637 EXPORT_SYMBOL(qlogicfas408_host_reset);
0638 EXPORT_SYMBOL(qlogicfas408_biosparam);
0639 EXPORT_SYMBOL(qlogicfas408_ihandl);
0640 EXPORT_SYMBOL(qlogicfas408_get_chip_type);
0641 EXPORT_SYMBOL(qlogicfas408_setup);
0642 EXPORT_SYMBOL(qlogicfas408_detect);
0643 EXPORT_SYMBOL(qlogicfas408_disable_ints);
0644