11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*----------------------------------------------------------------*/ 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Qlogic linux driver - work in progress. No Warranty express or implied. 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Use at your own risk. Support Tort Reform so you won't have to read all 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds these silly disclaimers. 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Copyright 1994, Tom Zerucha. 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tz@execpc.com 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Additional Code, and much appreciated help by 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Michael A. Griffith 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds grif@cs.ucr.edu 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Thanks to Eric Youngdale and Dave Hinds for loadable module and PCMCIA 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds help respectively, and for suffering through my foolishness during the 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds debugging process. 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (you can reference it, but it is incomplete and inaccurate in places) 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Version 0.46 1/30/97 - kernel 1.2.0+ 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Functions as standalone, loadable, and PCMCIA driver, the latter from 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Dave Hinds' PCMCIA package. 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26fa195afe4ad3f6d85a9b7cc236ae85c05ca8db03Alan Cox Cleaned up 26/10/2002 by Alan Cox <alan@lxorguk.ukuu.org.uk> as part of the 2.5 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCSI driver cleanup and audit. This driver still needs work on the 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds following 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - Non terminating hardware waits 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - Some layering violations with its pcmcia stub 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Redistributable under terms of the GNU General Public License 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds For the avoidance of doubt the "preferred form" of this code is one which 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds is in an open non patent encumbered format. Where cryptographic key signing 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds forms part of the process of creating an executable the information 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds including keys needed to generate an equivalently functional executable 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds are deemed to be part of the source code. 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h> /* to get disk capacity */ 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/unistd.h> 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/stat.h> 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h> 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/dma.h> 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "scsi.h" 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_host.h> 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "qlogicfas408.h" 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*----------------------------------------------------------------*/ 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qlcfg5 = (XTALFREQ << 5); /* 15625/512 */ 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qlcfg6 = SYNCXFRPD; 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qlcfg7 = SYNCOFFST; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qlcfg8 = (SLOWCABLE << 7) | (QL_ENABLE_PARITY << 4); 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qlcfg9 = ((XTALFREQ + 4) / 5); 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qlcfgc = (FASTCLK << 3) | (FASTSCSI << 4); 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*----------------------------------------------------------------*/ 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*----------------------------------------------------------------*/ 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* local functions */ 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*----------------------------------------------------------------*/ 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* error recovery - reset everything */ 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ql_zap(struct qlogicfas408_priv *priv) 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int x; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int qbase = priv->qbase; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int int_type = priv->int_type; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x = inb(qbase + 0xd); 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REG0; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(3, qbase + 3); /* reset SCSI */ 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(2, qbase + 3); /* reset chip */ 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (x & 0x80) 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REG1; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Do a pseudo-dma tranfer 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ql_pdma(struct qlogicfas408_priv *priv, int phase, char *request, int reqlen) 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int j; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int qbase = priv->qbase; 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds j = 0; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (phase & 1) { /* in */ 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if QL_TURBO_PDMA 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtrc(4) 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* empty fifo in large chunks */ 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reqlen >= 128 && (inb(qbase + 8) & 2)) { /* full */ 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds insl(qbase + 4, request, 32); 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reqlen -= 128; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request += 128; 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (reqlen >= 84 && !(j & 0xc0)) /* 2/3 */ 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((j = inb(qbase + 8)) & 4) 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds insl(qbase + 4, request, 21); 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reqlen -= 84; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request += 84; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reqlen >= 44 && (inb(qbase + 8) & 8)) { /* 1/3 */ 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds insl(qbase + 4, request, 11); 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reqlen -= 44; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request += 44; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* until both empty and int (or until reclen is 0) */ 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtrc(7) 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds j = 0; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (reqlen && !((j & 0x10) && (j & 0xc0))) 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* while bytes to receive and not empty */ 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds j &= 0xc0; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (reqlen && !((j = inb(qbase + 8)) & 0x10)) 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *request++ = inb(qbase + 4); 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reqlen--; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (j & 0x10) 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds j = inb(qbase + 8); 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { /* out */ 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if QL_TURBO_PDMA 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtrc(4) 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reqlen >= 128 && inb(qbase + 8) & 0x10) { /* empty */ 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outsl(qbase + 4, request, 32); 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reqlen -= 128; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request += 128; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (reqlen >= 84 && !(j & 0xc0)) /* 1/3 */ 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!((j = inb(qbase + 8)) & 8)) { 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outsl(qbase + 4, request, 21); 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reqlen -= 84; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request += 84; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reqlen >= 40 && !(inb(qbase + 8) & 4)) { /* 2/3 */ 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outsl(qbase + 4, request, 10); 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reqlen -= 40; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request += 40; 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* until full and int (or until reclen is 0) */ 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtrc(7) 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds j = 0; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (reqlen && !((j & 2) && (j & 0xc0))) { 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* while bytes to send and not full */ 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (reqlen && !((j = inb(qbase + 8)) & 2)) 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(*request++, qbase + 4); 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reqlen--; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (j & 2) 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds j = inb(qbase + 8); 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* maybe return reqlen */ 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return inb(qbase + 8) & 0xc0; 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait for interrupt flag (polled - not real hardware interrupt) 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ql_wai(struct qlogicfas408_priv *priv) 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int k; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int qbase = priv->qbase; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long i; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds k = 0; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = jiffies + WATCHDOG; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (time_before(jiffies, i) && !priv->qabort && 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !((k = inb(qbase + 4)) & 0xe0)) { 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds barrier(); 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu_relax(); 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (time_after_eq(jiffies, i)) 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (DID_TIME_OUT); 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (priv->qabort) 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (priv->qabort == 1 ? DID_ABORT : DID_RESET); 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (k & 0x60) 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ql_zap(priv); 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (k & 0x20) 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (DID_PARITY); 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (k & 0x40) 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (DID_ERROR); 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initiate scsi command - queueing handler 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * caller must hold host lock 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 212a24342b90c9c829fc5fea9ee01b127f81bca18efHenrik Kretzschmarstatic void ql_icmd(struct scsi_cmnd *cmd) 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd); 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int qbase = priv->qbase; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int int_type = priv->int_type; 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int i; 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->qabort = 0; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REG0; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* clearing of interrupts and the fifo is needed */ 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inb(qbase + 5); /* clear interrupts */ 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (inb(qbase + 5)) /* if still interrupting */ 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(2, qbase + 3); /* reset chip */ 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (inb(qbase + 7) & 0x1f) 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(1, qbase + 3); /* clear fifo */ 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (inb(qbase + 5)); /* clear ints */ 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REG1; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(1, qbase + 8); /* set for PIO pseudo DMA */ 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0, qbase + 0xb); /* disable ints */ 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inb(qbase + 8); /* clear int bits */ 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REG0; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x40, qbase + 0xb); /* enable features */ 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* configurables */ 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(qlcfgc, qbase + 0xc); 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* config: no reset interrupt, (initiator) bus id */ 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x40 | qlcfg8 | priv->qinitid, qbase + 8); 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(qlcfg7, qbase + 7); 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(qlcfg6, qbase + 6); 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /**/ outb(qlcfg5, qbase + 5); /* select timer */ 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(qlcfg9 & 7, qbase + 9); /* prescaler */ 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* outb(0x99, qbase + 5); */ 246422c0d61d591cbfb70f029e13505fb437e169d68Jeff Garzik outb(scmd_id(cmd), qbase + 4); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < cmd->cmd_len; i++) 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(cmd->cmnd[i], qbase + 2); 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->qlcmd = cmd; 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x41, qbase + 3); /* select and send command */ 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Process scsi command - usually after interrupt 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 259a24342b90c9c829fc5fea9ee01b127f81bca18efHenrik Kretzschmarstatic unsigned int ql_pcmd(struct scsi_cmnd *cmd) 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int i, j; 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long k; 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int result; /* ultimate return result */ 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status; /* scsi returned status */ 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int message; /* scsi returned message */ 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int phase; /* recorded scsi phase */ 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int reqlen; /* total length of transfer */ 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *buf; 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd); 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int qbase = priv->qbase; 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int int_type = priv->int_type; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtrc(1) 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds j = inb(qbase + 6); 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = inb(qbase + 5); 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i == 0x20) { 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (DID_NO_CONNECT << 16); 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i |= inb(qbase + 5); /* the 0x10 bit can be set after the 0x08 */ 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i != 0x18) { 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "Ql:Bad Interrupt status:%02x\n", i); 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ql_zap(priv); 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (DID_BAD_INTR << 16); 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds j &= 7; /* j = inb( qbase + 7 ) >> 5; */ 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* correct status is supposed to be step 4 */ 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* it sometimes returns step 3 but with 0 bytes left to send */ 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We can try stuffing the FIFO with the max each time, but we will get a 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sequence of 3 if any bytes are left (but we do flush the FIFO anyway */ 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (j != 3 && j != 4) { 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n", 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds j, i, inb(qbase + 7) & 0x1f); 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ql_zap(priv); 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (DID_ERROR << 16); 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = DID_OK; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (inb(qbase + 7) & 0x1f) /* if some bytes in fifo */ 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(1, qbase + 3); /* clear fifo */ 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* note that request_bufflen is the total xfer size when sg is used */ 302bc1ebfba1a3a27122462fd342d11216e3faea53fFUJITA Tomonori reqlen = scsi_bufflen(cmd); 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* note that it won't work if transfers > 16M are requested */ 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reqlen && !((phase = inb(qbase + 4)) & 6)) { /* data phase */ 305bc1ebfba1a3a27122462fd342d11216e3faea53fFUJITA Tomonori struct scatterlist *sg; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtrc(2) 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(reqlen, qbase); /* low-mid xfer cnt */ 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(reqlen >> 8, qbase + 1); /* low-mid xfer cnt */ 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(reqlen >> 16, qbase + 0xe); /* high xfer cnt */ 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x90, qbase + 3); /* command do xfer */ 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* PIO pseudo DMA to buffer or sglist */ 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REG1; 313bc1ebfba1a3a27122462fd342d11216e3faea53fFUJITA Tomonori 314bc1ebfba1a3a27122462fd342d11216e3faea53fFUJITA Tomonori scsi_for_each_sg(cmd, sg, scsi_sg_count(cmd), i) { 315bc1ebfba1a3a27122462fd342d11216e3faea53fFUJITA Tomonori if (priv->qabort) { 316bc1ebfba1a3a27122462fd342d11216e3faea53fFUJITA Tomonori REG0; 317bc1ebfba1a3a27122462fd342d11216e3faea53fFUJITA Tomonori return ((priv->qabort == 1 ? 318bc1ebfba1a3a27122462fd342d11216e3faea53fFUJITA Tomonori DID_ABORT : DID_RESET) << 16); 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32045711f1af6eff1a6d010703b4862e0d2b9afd056Jens Axboe buf = sg_virt(sg); 321bc1ebfba1a3a27122462fd342d11216e3faea53fFUJITA Tomonori if (ql_pdma(priv, phase, buf, sg->length)) 322bc1ebfba1a3a27122462fd342d11216e3faea53fFUJITA Tomonori break; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REG0; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtrc(2) 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait for irq (split into second state of irq handler 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if this can take time) 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((k = ql_wai(priv))) 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (k << 16); 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds k = inb(qbase + 5); /* should be 0x10, bus service */ 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Enter Status (and Message In) Phase 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds k = jiffies + WATCHDOG; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (time_before(jiffies, k) && !priv->qabort && 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !(inb(qbase + 4) & 6)) 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu_relax(); /* wait for status phase */ 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (time_after_eq(jiffies, k)) { 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ql_zap(priv); 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (DID_TIME_OUT << 16); 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME: timeout ?? */ 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (inb(qbase + 5)) 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu_relax(); /* clear pending ints */ 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (priv->qabort) 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16); 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x11, qbase + 3); /* get status and message */ 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((k = ql_wai(priv))) 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (k << 16); 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = inb(qbase + 5); /* get chip irq stat */ 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds j = inb(qbase + 7) & 0x1f; /* and bytes rec'd */ 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = inb(qbase + 2); 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds message = inb(qbase + 2); 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Should get function complete int if Status and message, else 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bus serv if only status 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) { 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j); 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = DID_ERROR; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x12, qbase + 3); /* done, disconnect */ 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtrc(1) 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((k = ql_wai(priv))) 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (k << 16); 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Should get bus service interrupt and disconnect interrupt 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = inb(qbase + 5); /* should be bus service */ 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!priv->qabort && ((i & 0x20) != 0x20)) { 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds barrier(); 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu_relax(); 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i |= inb(qbase + 5); 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rtrc(0) 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (priv->qabort) 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16); 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (result << 16) | (message << 8) | (status & STATUS_MASK); 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Interrupt handler 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 400c7bec5aba52392aa8d675b8722735caf4a8b7265Jeff Garzikstatic void ql_ihandl(void *dev_id) 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 402a24342b90c9c829fc5fea9ee01b127f81bca18efHenrik Kretzschmar struct scsi_cmnd *icmd; 403c7bec5aba52392aa8d675b8722735caf4a8b7265Jeff Garzik struct Scsi_Host *host = dev_id; 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct qlogicfas408_priv *priv = get_priv_by_host(host); 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int qbase = priv->qbase; 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REG0; 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(inb(qbase + 4) & 0x80)) /* false alarm? */ 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (priv->qlcmd == NULL) { /* no command to process? */ 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = 16; 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (i-- && inb(qbase + 5)); /* maybe also ql_zap() */ 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds icmd = priv->qlcmd; 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds icmd->result = ql_pcmd(icmd); 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->qlcmd = NULL; 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If result is CHECK CONDITION done calls qcommand to request 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sense 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (icmd->scsi_done) (icmd); 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4277d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsirqreturn_t qlogicfas408_ihandl(int irq, void *dev_id) 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Scsi_Host *host = dev_id; 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(host->host_lock, flags); 433c7bec5aba52392aa8d675b8722735caf4a8b7265Jeff Garzik ql_ihandl(dev_id); 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(host->host_lock, flags); 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Queued command 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 442f281233d3eba15fb225d21ae2e228fd4553d824aJeff Garzikstatic int qlogicfas408_queuecommand_lck(struct scsi_cmnd *cmd, 443a24342b90c9c829fc5fea9ee01b127f81bca18efHenrik Kretzschmar void (*done) (struct scsi_cmnd *)) 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd); 446422c0d61d591cbfb70f029e13505fb437e169d68Jeff Garzik if (scmd_id(cmd) == priv->qinitid) { 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->result = DID_BAD_TARGET << 16; 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds done(cmd); 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->scsi_done = done; 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wait for the last command's interrupt to finish */ 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (priv->qlcmd != NULL) { 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds barrier(); 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu_relax(); 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ql_icmd(cmd); 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 462f281233d3eba15fb225d21ae2e228fd4553d824aJeff GarzikDEF_SCSI_QCMD(qlogicfas408_queuecommand) 463f281233d3eba15fb225d21ae2e228fd4553d824aJeff Garzik 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return bios parameters 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 468a24342b90c9c829fc5fea9ee01b127f81bca18efHenrik Kretzschmarint qlogicfas408_biosparam(struct scsi_device *disk, struct block_device *dev, 469a24342b90c9c829fc5fea9ee01b127f81bca18efHenrik Kretzschmar sector_t capacity, int ip[]) 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This should mimic the DOS Qlogic driver's behavior exactly */ 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[0] = 0x40; 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[1] = 0x20; 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[2] = (unsigned long) capacity / (ip[0] * ip[1]); 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ip[2] > 1024) { 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[0] = 0xff; 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[1] = 0x3f; 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[2] = (unsigned long) capacity / (ip[0] * ip[1]); 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ip[2] > 1023) 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[2] = 1023; 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Abort a command in progress 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 491a24342b90c9c829fc5fea9ee01b127f81bca18efHenrik Kretzschmarint qlogicfas408_abort(struct scsi_cmnd *cmd) 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd); 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->qabort = 1; 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ql_zap(priv); 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return SUCCESS; 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reset SCSI bus 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FIXME: This function is invoked with cmd = NULL directly by 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the PCMCIA qlogic_stub code. This wants fixing 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 505a24342b90c9c829fc5fea9ee01b127f81bca18efHenrik Kretzschmarint qlogicfas408_bus_reset(struct scsi_cmnd *cmd) 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd); 50868b3aa7c9805aee9005a8ca53c5e99177961fbb9Jeff Garzik unsigned long flags; 50968b3aa7c9805aee9005a8ca53c5e99177961fbb9Jeff Garzik 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->qabort = 2; 51168b3aa7c9805aee9005a8ca53c5e99177961fbb9Jeff Garzik 51268b3aa7c9805aee9005a8ca53c5e99177961fbb9Jeff Garzik spin_lock_irqsave(cmd->device->host->host_lock, flags); 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ql_zap(priv); 51468b3aa7c9805aee9005a8ca53c5e99177961fbb9Jeff Garzik spin_unlock_irqrestore(cmd->device->host->host_lock, flags); 51568b3aa7c9805aee9005a8ca53c5e99177961fbb9Jeff Garzik 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return SUCCESS; 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return info string 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsconst char *qlogicfas408_info(struct Scsi_Host *host) 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct qlogicfas408_priv *priv = get_priv_by_host(host); 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return priv->qinfo; 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get type of chip 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint qlogicfas408_get_chip_type(int qbase, int int_type) 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REG1; 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return inb(qbase + 0xe) & 0xf8; 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Perform initialization tasks 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid qlogicfas408_setup(int qbase, int id, int int_type) 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(1, qbase + 8); /* set for PIO pseudo DMA */ 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REG0; 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x40 | qlcfg8 | id, qbase + 8); /* (ini) bus id, disable scsi rst */ 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(qlcfg5, qbase + 5); /* select timer */ 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(qlcfg9, qbase + 9); /* prescaler */ 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if QL_RESET_AT_START 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(3, qbase + 3); 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REG1; 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME: timeout */ 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (inb(qbase + 0xf) & 4) 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu_relax(); 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REG0; 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Checks if this is a QLogic FAS 408 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint qlogicfas408_detect(int qbase, int int_type) 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REG1; 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7) && 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7)); 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Disable interrupts 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid qlogicfas408_disable_ints(struct qlogicfas408_priv *priv) 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int qbase = priv->qbase; 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int int_type = priv->int_type; 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REG1; 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0, qbase + 0xb); /* disable ints */ 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Init and exit functions 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init qlogicfas408_init(void) 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit qlogicfas408_exit(void) 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Tom Zerucha, Michael Griffith"); 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers"); 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(qlogicfas408_init); 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(qlogicfas408_exit); 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(qlogicfas408_info); 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(qlogicfas408_queuecommand); 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(qlogicfas408_abort); 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(qlogicfas408_bus_reset); 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(qlogicfas408_biosparam); 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(qlogicfas408_ihandl); 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(qlogicfas408_get_chip_type); 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(qlogicfas408_setup); 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(qlogicfas408_detect); 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(qlogicfas408_disable_ints); 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 618