root/drivers/scsi/qlogicfas408.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ql_zap
  2. ql_pdma
  3. ql_wai
  4. ql_icmd
  5. ql_pcmd
  6. ql_ihandl
  7. qlogicfas408_ihandl
  8. qlogicfas408_queuecommand_lck
  9. DEF_SCSI_QCMD
  10. qlogicfas408_abort
  11. qlogicfas408_host_reset
  12. qlogicfas408_info
  13. qlogicfas408_get_chip_type
  14. qlogicfas408_setup
  15. qlogicfas408_detect
  16. qlogicfas408_disable_ints
  17. qlogicfas408_init
  18. qlogicfas408_exit

   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 /*----------------------------------------------------------------*/
  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);
  69 
  70 /*----------------------------------------------------------------*/
  71 
  72 /*----------------------------------------------------------------*/
  73 /* local functions */
  74 /*----------------------------------------------------------------*/
  75 
  76 /* error recovery - reset everything */
  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);     /* 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  
  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) {        /* 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 
 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  *      Initiate scsi command - queueing handler 
 209  *      caller must hold host lock
 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         /* 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 
 259 static 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 
 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))   /* 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 
 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  *      Queued command
 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         /* 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 
 462 DEF_SCSI_QCMD(qlogicfas408_queuecommand)
 463 
 464 /* 
 465  *      Return bios parameters 
 466  */
 467 
 468 int 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  
 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  *      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 
 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  *      Return info string
 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  *      Get type of chip
 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  *      Perform initialization tasks
 541  */
 542 
 543 void 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 
 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  *      Disable interrupts
 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);   /* disable ints */
 585 }
 586 
 587 /*
 588  *      Init and exit functions
 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 

/* [<][>][^][v][top][bottom][index][help] */