11da177e4SLinus Torvalds /* $Id$
21da177e4SLinus Torvalds * 1993/03/31
31da177e4SLinus Torvalds * linux/kernel/aha1740.c
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Based loosely on aha1542.c which is
61da177e4SLinus Torvalds * Copyright (C) 1992 Tommy Thorn and
71da177e4SLinus Torvalds * Modified by Eric Youngdale
81da177e4SLinus Torvalds *
91da177e4SLinus Torvalds * This file is aha1740.c, written and
101da177e4SLinus Torvalds * Copyright (C) 1992,1993 Brad McLean
111da177e4SLinus Torvalds * brad@saturn.gaylord.com or brad@bradpc.gaylord.com.
121da177e4SLinus Torvalds *
131da177e4SLinus Torvalds * Modifications to makecode and queuecommand
141da177e4SLinus Torvalds * for proper handling of multiple devices courteously
151da177e4SLinus Torvalds * provided by Michael Weller, March, 1993
161da177e4SLinus Torvalds *
171da177e4SLinus Torvalds * Multiple adapter support, extended translation detection,
181da177e4SLinus Torvalds * update to current scsi subsystem changes, proc fs support,
191da177e4SLinus Torvalds * working (!) module support based on patches from Andreas Arens,
201da177e4SLinus Torvalds * by Andreas Degert <ad@papyrus.hamburg.com>, 2/1997
211da177e4SLinus Torvalds *
221da177e4SLinus Torvalds * aha1740_makecode may still need even more work
231da177e4SLinus Torvalds * if it doesn't work for your devices, take a look.
241da177e4SLinus Torvalds *
25fa195afeSAlan Cox * Reworked for new_eh and new locking by Alan Cox <alan@lxorguk.ukuu.org.uk>
261da177e4SLinus Torvalds *
271da177e4SLinus Torvalds * Converted to EISA and generic DMA APIs by Marc Zyngier
281da177e4SLinus Torvalds * <maz@wild-wind.fr.eu.org>, 4/2003.
291da177e4SLinus Torvalds *
301da177e4SLinus Torvalds * Shared interrupt support added by Rask Ingemann Lambertsen
311da177e4SLinus Torvalds * <rask@sygehus.dk>, 10/2003
321da177e4SLinus Torvalds *
331da177e4SLinus Torvalds * For the avoidance of doubt the "preferred form" of this code is one which
341da177e4SLinus Torvalds * is in an open non patent encumbered format. Where cryptographic key signing
351da177e4SLinus Torvalds * forms part of the process of creating an executable the information
361da177e4SLinus Torvalds * including keys needed to generate an equivalently functional executable
371da177e4SLinus Torvalds * are deemed to be part of the source code.
381da177e4SLinus Torvalds */
391da177e4SLinus Torvalds
401da177e4SLinus Torvalds #include <linux/blkdev.h>
411da177e4SLinus Torvalds #include <linux/interrupt.h>
421da177e4SLinus Torvalds #include <linux/module.h>
431da177e4SLinus Torvalds #include <linux/kernel.h>
441da177e4SLinus Torvalds #include <linux/types.h>
451da177e4SLinus Torvalds #include <linux/string.h>
461da177e4SLinus Torvalds #include <linux/ioport.h>
471da177e4SLinus Torvalds #include <linux/proc_fs.h>
481da177e4SLinus Torvalds #include <linux/stat.h>
491da177e4SLinus Torvalds #include <linux/init.h>
501da177e4SLinus Torvalds #include <linux/device.h>
511da177e4SLinus Torvalds #include <linux/eisa.h>
521da177e4SLinus Torvalds #include <linux/dma-mapping.h>
535a0e3ad6STejun Heo #include <linux/gfp.h>
541da177e4SLinus Torvalds
551da177e4SLinus Torvalds #include <asm/dma.h>
561da177e4SLinus Torvalds #include <asm/io.h>
571da177e4SLinus Torvalds
5853555fb7SBart Van Assche #include <scsi/scsi.h>
5953555fb7SBart Van Assche #include <scsi/scsi_cmnd.h>
6053555fb7SBart Van Assche #include <scsi/scsi_device.h>
6153555fb7SBart Van Assche #include <scsi/scsi_eh.h>
621da177e4SLinus Torvalds #include <scsi/scsi_host.h>
6353555fb7SBart Van Assche #include <scsi/scsi_tcq.h>
641da177e4SLinus Torvalds #include "aha1740.h"
651da177e4SLinus Torvalds
661da177e4SLinus Torvalds /* IF YOU ARE HAVING PROBLEMS WITH THIS DRIVER, AND WANT TO WATCH
671da177e4SLinus Torvalds IT WORK, THEN:
681da177e4SLinus Torvalds #define DEBUG
691da177e4SLinus Torvalds */
701da177e4SLinus Torvalds #ifdef DEBUG
711da177e4SLinus Torvalds #define DEB(x) x
721da177e4SLinus Torvalds #else
731da177e4SLinus Torvalds #define DEB(x)
741da177e4SLinus Torvalds #endif
751da177e4SLinus Torvalds
761da177e4SLinus Torvalds struct aha1740_hostdata {
771da177e4SLinus Torvalds struct eisa_device *edev;
781da177e4SLinus Torvalds unsigned int translation;
791da177e4SLinus Torvalds unsigned int last_ecb_used;
801da177e4SLinus Torvalds dma_addr_t ecb_dma_addr;
811da177e4SLinus Torvalds struct ecb ecb[AHA1740_ECBS];
821da177e4SLinus Torvalds };
831da177e4SLinus Torvalds
841da177e4SLinus Torvalds struct aha1740_sg {
851da177e4SLinus Torvalds struct aha1740_chain sg_chain[AHA1740_SCATTER];
861da177e4SLinus Torvalds dma_addr_t sg_dma_addr;
871da177e4SLinus Torvalds dma_addr_t buf_dma_addr;
881da177e4SLinus Torvalds };
891da177e4SLinus Torvalds
901da177e4SLinus Torvalds #define HOSTDATA(host) ((struct aha1740_hostdata *) &host->hostdata)
911da177e4SLinus Torvalds
ecb_dma_to_cpu(struct Scsi_Host * host,dma_addr_t dma)921da177e4SLinus Torvalds static inline struct ecb *ecb_dma_to_cpu (struct Scsi_Host *host,
931da177e4SLinus Torvalds dma_addr_t dma)
941da177e4SLinus Torvalds {
951da177e4SLinus Torvalds struct aha1740_hostdata *hdata = HOSTDATA (host);
961da177e4SLinus Torvalds dma_addr_t offset;
971da177e4SLinus Torvalds
981da177e4SLinus Torvalds offset = dma - hdata->ecb_dma_addr;
991da177e4SLinus Torvalds
1001da177e4SLinus Torvalds return (struct ecb *)(((char *) hdata->ecb) + (unsigned int) offset);
1011da177e4SLinus Torvalds }
1021da177e4SLinus Torvalds
ecb_cpu_to_dma(struct Scsi_Host * host,void * cpu)1031da177e4SLinus Torvalds static inline dma_addr_t ecb_cpu_to_dma (struct Scsi_Host *host, void *cpu)
1041da177e4SLinus Torvalds {
1051da177e4SLinus Torvalds struct aha1740_hostdata *hdata = HOSTDATA (host);
1061da177e4SLinus Torvalds dma_addr_t offset;
1071da177e4SLinus Torvalds
1081da177e4SLinus Torvalds offset = (char *) cpu - (char *) hdata->ecb;
1091da177e4SLinus Torvalds
1101da177e4SLinus Torvalds return hdata->ecb_dma_addr + offset;
1111da177e4SLinus Torvalds }
1121da177e4SLinus Torvalds
aha1740_show_info(struct seq_file * m,struct Scsi_Host * shpnt)113e633c1e5SAl Viro static int aha1740_show_info(struct seq_file *m, struct Scsi_Host *shpnt)
1141da177e4SLinus Torvalds {
115e633c1e5SAl Viro struct aha1740_hostdata *host = HOSTDATA(shpnt);
116e633c1e5SAl Viro seq_printf(m, "aha174x at IO:%lx, IRQ %d, SLOT %d.\n"
1171da177e4SLinus Torvalds "Extended translation %sabled.\n",
1181da177e4SLinus Torvalds shpnt->io_port, shpnt->irq, host->edev->slot,
1191da177e4SLinus Torvalds host->translation ? "en" : "dis");
1201da177e4SLinus Torvalds return 0;
1211da177e4SLinus Torvalds }
1221da177e4SLinus Torvalds
aha1740_makecode(unchar * sense,unchar * status)1231da177e4SLinus Torvalds static int aha1740_makecode(unchar *sense, unchar *status)
1241da177e4SLinus Torvalds {
1251da177e4SLinus Torvalds struct statusword
1261da177e4SLinus Torvalds {
1271da177e4SLinus Torvalds ushort don:1, /* Command Done - No Error */
1281da177e4SLinus Torvalds du:1, /* Data underrun */
1291da177e4SLinus Torvalds :1, qf:1, /* Queue full */
1301da177e4SLinus Torvalds sc:1, /* Specification Check */
1311da177e4SLinus Torvalds dor:1, /* Data overrun */
1321da177e4SLinus Torvalds ch:1, /* Chaining Halted */
1331da177e4SLinus Torvalds intr:1, /* Interrupt issued */
1341da177e4SLinus Torvalds asa:1, /* Additional Status Available */
1351da177e4SLinus Torvalds sns:1, /* Sense information Stored */
1361da177e4SLinus Torvalds :1, ini:1, /* Initialization Required */
1371da177e4SLinus Torvalds me:1, /* Major error or exception */
1381da177e4SLinus Torvalds :1, eca:1, /* Extended Contingent alliance */
1391da177e4SLinus Torvalds :1;
1401da177e4SLinus Torvalds } status_word;
1411da177e4SLinus Torvalds int retval = DID_OK;
1421da177e4SLinus Torvalds
1431da177e4SLinus Torvalds status_word = * (struct statusword *) status;
1441da177e4SLinus Torvalds #ifdef DEBUG
1451da177e4SLinus Torvalds printk("makecode from %x,%x,%x,%x %x,%x,%x,%x",
1461da177e4SLinus Torvalds status[0], status[1], status[2], status[3],
1471da177e4SLinus Torvalds sense[0], sense[1], sense[2], sense[3]);
1481da177e4SLinus Torvalds #endif
1491da177e4SLinus Torvalds if (!status_word.don) { /* Anything abnormal was detected */
1501da177e4SLinus Torvalds if ( (status[1]&0x18) || status_word.sc ) {
1511da177e4SLinus Torvalds /*Additional info available*/
1521da177e4SLinus Torvalds /* Use the supplied info for further diagnostics */
1531da177e4SLinus Torvalds switch ( status[2] ) {
1541da177e4SLinus Torvalds case 0x12:
1551da177e4SLinus Torvalds if ( status_word.dor )
1561da177e4SLinus Torvalds retval=DID_ERROR; /* It's an Overrun */
1571da177e4SLinus Torvalds /* If not overrun, assume underrun and
1581da177e4SLinus Torvalds * ignore it! */
1595133dc47SGustavo A. R. Silva break;
1601da177e4SLinus Torvalds case 0x00: /* No info, assume no error, should
1611da177e4SLinus Torvalds * not occur */
1621da177e4SLinus Torvalds break;
1631da177e4SLinus Torvalds case 0x11:
1641da177e4SLinus Torvalds case 0x21:
1651da177e4SLinus Torvalds retval=DID_TIME_OUT;
1661da177e4SLinus Torvalds break;
1671da177e4SLinus Torvalds case 0x0a:
1681da177e4SLinus Torvalds retval=DID_BAD_TARGET;
1691da177e4SLinus Torvalds break;
1701da177e4SLinus Torvalds case 0x04:
1711da177e4SLinus Torvalds case 0x05:
1721da177e4SLinus Torvalds retval=DID_ABORT;
1731da177e4SLinus Torvalds /* Either by this driver or the
1741da177e4SLinus Torvalds * AHA1740 itself */
1751da177e4SLinus Torvalds break;
1761da177e4SLinus Torvalds default:
1771da177e4SLinus Torvalds retval=DID_ERROR; /* No further
1781da177e4SLinus Torvalds * diagnostics
1791da177e4SLinus Torvalds * possible */
1801da177e4SLinus Torvalds }
1811da177e4SLinus Torvalds } else {
1821da177e4SLinus Torvalds /* Michael suggests, and Brad concurs: */
1831da177e4SLinus Torvalds if ( status_word.qf ) {
1841da177e4SLinus Torvalds retval = DID_TIME_OUT; /* forces a redo */
1851da177e4SLinus Torvalds /* I think this specific one should
1861da177e4SLinus Torvalds * not happen -Brad */
1871da177e4SLinus Torvalds printk("aha1740.c: WARNING: AHA1740 queue overflow!\n");
1881da177e4SLinus Torvalds } else
1891da177e4SLinus Torvalds if ( status[0]&0x60 ) {
1901da177e4SLinus Torvalds /* Didn't find a better error */
1911da177e4SLinus Torvalds retval = DID_ERROR;
1921da177e4SLinus Torvalds }
1931da177e4SLinus Torvalds /* In any other case return DID_OK so for example
1941da177e4SLinus Torvalds CONDITION_CHECKS make it through to the appropriate
1951da177e4SLinus Torvalds device driver */
1961da177e4SLinus Torvalds }
1971da177e4SLinus Torvalds }
1981da177e4SLinus Torvalds /* Under all circumstances supply the target status -Michael */
1991da177e4SLinus Torvalds return status[3] | retval << 16;
2001da177e4SLinus Torvalds }
2011da177e4SLinus Torvalds
aha1740_test_port(unsigned int base)2021da177e4SLinus Torvalds static int aha1740_test_port(unsigned int base)
2031da177e4SLinus Torvalds {
2041da177e4SLinus Torvalds if ( inb(PORTADR(base)) & PORTADDR_ENH )
2051da177e4SLinus Torvalds return 1; /* Okay, we're all set */
2061da177e4SLinus Torvalds
2071da177e4SLinus Torvalds printk("aha174x: Board detected, but not in enhanced mode, so disabled it.\n");
2081da177e4SLinus Torvalds return 0;
2091da177e4SLinus Torvalds }
2101da177e4SLinus Torvalds
2111da177e4SLinus Torvalds /* A "high" level interrupt handler */
aha1740_intr_handle(int irq,void * dev_id)2127d12e780SDavid Howells static irqreturn_t aha1740_intr_handle(int irq, void *dev_id)
2131da177e4SLinus Torvalds {
2141da177e4SLinus Torvalds struct Scsi_Host *host = (struct Scsi_Host *) dev_id;
21591ebc1faSJohannes Thumshirn void (*my_done)(struct scsi_cmnd *);
2161da177e4SLinus Torvalds int errstatus, adapstat;
2171da177e4SLinus Torvalds int number_serviced;
2181da177e4SLinus Torvalds struct ecb *ecbptr;
21991ebc1faSJohannes Thumshirn struct scsi_cmnd *SCtmp;
2201da177e4SLinus Torvalds unsigned int base;
2211da177e4SLinus Torvalds unsigned long flags;
2221da177e4SLinus Torvalds int handled = 0;
2231da177e4SLinus Torvalds struct aha1740_sg *sgptr;
2241da177e4SLinus Torvalds struct eisa_device *edev;
2251da177e4SLinus Torvalds
2261da177e4SLinus Torvalds if (!host)
2271da177e4SLinus Torvalds panic("aha1740.c: Irq from unknown host!\n");
2281da177e4SLinus Torvalds spin_lock_irqsave(host->host_lock, flags);
2291da177e4SLinus Torvalds base = host->io_port;
2301da177e4SLinus Torvalds number_serviced = 0;
2311da177e4SLinus Torvalds edev = HOSTDATA(host)->edev;
2321da177e4SLinus Torvalds
2331da177e4SLinus Torvalds while(inb(G2STAT(base)) & G2STAT_INTPEND) {
2341da177e4SLinus Torvalds handled = 1;
2351da177e4SLinus Torvalds DEB(printk("aha1740_intr top of loop.\n"));
2361da177e4SLinus Torvalds adapstat = inb(G2INTST(base));
2371da177e4SLinus Torvalds ecbptr = ecb_dma_to_cpu (host, inl(MBOXIN0(base)));
2381da177e4SLinus Torvalds outb(G2CNTRL_IRST,G2CNTRL(base)); /* interrupt reset */
2391da177e4SLinus Torvalds
2401da177e4SLinus Torvalds switch ( adapstat & G2INTST_MASK ) {
2411da177e4SLinus Torvalds case G2INTST_CCBRETRY:
2421da177e4SLinus Torvalds case G2INTST_CCBERROR:
2431da177e4SLinus Torvalds case G2INTST_CCBGOOD:
2441da177e4SLinus Torvalds /* Host Ready -> Mailbox in complete */
2451da177e4SLinus Torvalds outb(G2CNTRL_HRDY,G2CNTRL(base));
2461da177e4SLinus Torvalds if (!ecbptr) {
2471da177e4SLinus Torvalds printk("Aha1740 null ecbptr in interrupt (%x,%x,%x,%d)\n",
2481da177e4SLinus Torvalds inb(G2STAT(base)),adapstat,
2491da177e4SLinus Torvalds inb(G2INTST(base)), number_serviced++);
2501da177e4SLinus Torvalds continue;
2511da177e4SLinus Torvalds }
2521da177e4SLinus Torvalds SCtmp = ecbptr->SCpnt;
2531da177e4SLinus Torvalds if (!SCtmp) {
2541da177e4SLinus Torvalds printk("Aha1740 null SCtmp in interrupt (%x,%x,%x,%d)\n",
2551da177e4SLinus Torvalds inb(G2STAT(base)),adapstat,
2561da177e4SLinus Torvalds inb(G2INTST(base)), number_serviced++);
2571da177e4SLinus Torvalds continue;
2581da177e4SLinus Torvalds }
2591da177e4SLinus Torvalds sgptr = (struct aha1740_sg *) SCtmp->host_scribble;
260c66cc13cSFUJITA Tomonori scsi_dma_unmap(SCtmp);
2611da177e4SLinus Torvalds
2621da177e4SLinus Torvalds /* Free the sg block */
2631da177e4SLinus Torvalds dma_free_coherent (&edev->dev,
2641da177e4SLinus Torvalds sizeof (struct aha1740_sg),
2651da177e4SLinus Torvalds SCtmp->host_scribble,
2661da177e4SLinus Torvalds sgptr->sg_dma_addr);
2671da177e4SLinus Torvalds
2681da177e4SLinus Torvalds /* Fetch the sense data, and tuck it away, in
2691da177e4SLinus Torvalds the required slot. The Adaptec
2701da177e4SLinus Torvalds automatically fetches it, and there is no
2711da177e4SLinus Torvalds guarantee that we will still have it in the
2721da177e4SLinus Torvalds cdb when we come back */
2731da177e4SLinus Torvalds if ( (adapstat & G2INTST_MASK) == G2INTST_CCBERROR ) {
274041761f4SKees Cook memcpy_and_pad(SCtmp->sense_buffer,
275041761f4SKees Cook SCSI_SENSE_BUFFERSIZE,
276041761f4SKees Cook ecbptr->sense,
277041761f4SKees Cook sizeof(ecbptr->sense),
278041761f4SKees Cook 0);
2791da177e4SLinus Torvalds errstatus = aha1740_makecode(ecbptr->sense,ecbptr->status);
2801da177e4SLinus Torvalds } else
2811da177e4SLinus Torvalds errstatus = 0;
2821da177e4SLinus Torvalds DEB(if (errstatus)
2831da177e4SLinus Torvalds printk("aha1740_intr_handle: returning %6x\n",
2841da177e4SLinus Torvalds errstatus));
2851da177e4SLinus Torvalds SCtmp->result = errstatus;
2861da177e4SLinus Torvalds my_done = ecbptr->done;
2871da177e4SLinus Torvalds memset(ecbptr,0,sizeof(struct ecb));
2881da177e4SLinus Torvalds if ( my_done )
2891da177e4SLinus Torvalds my_done(SCtmp);
2901da177e4SLinus Torvalds break;
2911da177e4SLinus Torvalds
2921da177e4SLinus Torvalds case G2INTST_HARDFAIL:
2931da177e4SLinus Torvalds printk(KERN_ALERT "aha1740 hardware failure!\n");
2941da177e4SLinus Torvalds panic("aha1740.c"); /* Goodbye */
2951da177e4SLinus Torvalds
2961da177e4SLinus Torvalds case G2INTST_ASNEVENT:
2971da177e4SLinus Torvalds printk("aha1740 asynchronous event: %02x %02x %02x %02x %02x\n",
2981da177e4SLinus Torvalds adapstat,
2991da177e4SLinus Torvalds inb(MBOXIN0(base)),
3001da177e4SLinus Torvalds inb(MBOXIN1(base)),
3011da177e4SLinus Torvalds inb(MBOXIN2(base)),
3021da177e4SLinus Torvalds inb(MBOXIN3(base))); /* Say What? */
3031da177e4SLinus Torvalds /* Host Ready -> Mailbox in complete */
3041da177e4SLinus Torvalds outb(G2CNTRL_HRDY,G2CNTRL(base));
3051da177e4SLinus Torvalds break;
3061da177e4SLinus Torvalds
3071da177e4SLinus Torvalds case G2INTST_CMDGOOD:
3081da177e4SLinus Torvalds /* set immediate command success flag here: */
3091da177e4SLinus Torvalds break;
3101da177e4SLinus Torvalds
3111da177e4SLinus Torvalds case G2INTST_CMDERROR:
3121da177e4SLinus Torvalds /* Set immediate command failure flag here: */
3131da177e4SLinus Torvalds break;
3141da177e4SLinus Torvalds }
3151da177e4SLinus Torvalds number_serviced++;
3161da177e4SLinus Torvalds }
3171da177e4SLinus Torvalds
3181da177e4SLinus Torvalds spin_unlock_irqrestore(host->host_lock, flags);
3191da177e4SLinus Torvalds return IRQ_RETVAL(handled);
3201da177e4SLinus Torvalds }
3211da177e4SLinus Torvalds
aha1740_queuecommand_lck(struct scsi_cmnd * SCpnt)322af049dfdSBart Van Assche static int aha1740_queuecommand_lck(struct scsi_cmnd *SCpnt)
3231da177e4SLinus Torvalds {
324af049dfdSBart Van Assche void (*done)(struct scsi_cmnd *) = scsi_done;
3251da177e4SLinus Torvalds unchar direction;
3261da177e4SLinus Torvalds unchar *cmd = (unchar *) SCpnt->cmnd;
327422c0d61SJeff Garzik unchar target = scmd_id(SCpnt);
3281da177e4SLinus Torvalds struct aha1740_hostdata *host = HOSTDATA(SCpnt->device->host);
3291da177e4SLinus Torvalds unsigned long flags;
3301da177e4SLinus Torvalds dma_addr_t sg_dma;
3311da177e4SLinus Torvalds struct aha1740_sg *sgptr;
332c66cc13cSFUJITA Tomonori int ecbno, nseg;
3331da177e4SLinus Torvalds DEB(int i);
3341da177e4SLinus Torvalds
3351da177e4SLinus Torvalds if(*cmd == REQUEST_SENSE) {
3361da177e4SLinus Torvalds SCpnt->result = 0;
3371da177e4SLinus Torvalds done(SCpnt);
3381da177e4SLinus Torvalds return 0;
3391da177e4SLinus Torvalds }
3401da177e4SLinus Torvalds
3411da177e4SLinus Torvalds #ifdef DEBUG
3421da177e4SLinus Torvalds if (*cmd == READ_10 || *cmd == WRITE_10)
3431da177e4SLinus Torvalds i = xscsi2int(cmd+2);
3441da177e4SLinus Torvalds else if (*cmd == READ_6 || *cmd == WRITE_6)
3451da177e4SLinus Torvalds i = scsi2int(cmd+2);
3461da177e4SLinus Torvalds else
3471da177e4SLinus Torvalds i = -1;
3481da177e4SLinus Torvalds printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ",
3491da177e4SLinus Torvalds target, *cmd, i, bufflen);
3501da177e4SLinus Torvalds printk("scsi cmd:");
3511da177e4SLinus Torvalds for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]);
3521da177e4SLinus Torvalds printk("\n");
3531da177e4SLinus Torvalds #endif
3541da177e4SLinus Torvalds
3551da177e4SLinus Torvalds /* locate an available ecb */
3561da177e4SLinus Torvalds spin_lock_irqsave(SCpnt->device->host->host_lock, flags);
3571da177e4SLinus Torvalds ecbno = host->last_ecb_used + 1; /* An optimization */
3581da177e4SLinus Torvalds if (ecbno >= AHA1740_ECBS)
3591da177e4SLinus Torvalds ecbno = 0;
3601da177e4SLinus Torvalds do {
3611da177e4SLinus Torvalds if (!host->ecb[ecbno].cmdw)
3621da177e4SLinus Torvalds break;
3631da177e4SLinus Torvalds ecbno++;
3641da177e4SLinus Torvalds if (ecbno >= AHA1740_ECBS)
3651da177e4SLinus Torvalds ecbno = 0;
3661da177e4SLinus Torvalds } while (ecbno != host->last_ecb_used);
3671da177e4SLinus Torvalds
3681da177e4SLinus Torvalds if (host->ecb[ecbno].cmdw)
3691da177e4SLinus Torvalds panic("Unable to find empty ecb for aha1740.\n");
3701da177e4SLinus Torvalds
3711da177e4SLinus Torvalds host->ecb[ecbno].cmdw = AHA1740CMD_INIT; /* SCSI Initiator Command
3721da177e4SLinus Torvalds doubles as reserved flag */
3731da177e4SLinus Torvalds
3741da177e4SLinus Torvalds host->last_ecb_used = ecbno;
3751da177e4SLinus Torvalds spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags);
3761da177e4SLinus Torvalds
3771da177e4SLinus Torvalds #ifdef DEBUG
3781da177e4SLinus Torvalds printk("Sending command (%d %x)...", ecbno, done);
3791da177e4SLinus Torvalds #endif
3801da177e4SLinus Torvalds
3811da177e4SLinus Torvalds host->ecb[ecbno].cdblen = SCpnt->cmd_len; /* SCSI Command
3821da177e4SLinus Torvalds * Descriptor Block
3831da177e4SLinus Torvalds * Length */
3841da177e4SLinus Torvalds
3851da177e4SLinus Torvalds direction = 0;
3861da177e4SLinus Torvalds if (*cmd == READ_10 || *cmd == READ_6)
3871da177e4SLinus Torvalds direction = 1;
3881da177e4SLinus Torvalds else if (*cmd == WRITE_10 || *cmd == WRITE_6)
3891da177e4SLinus Torvalds direction = 0;
3901da177e4SLinus Torvalds
3911da177e4SLinus Torvalds memcpy(host->ecb[ecbno].cdb, cmd, SCpnt->cmd_len);
3921da177e4SLinus Torvalds
3931da177e4SLinus Torvalds SCpnt->host_scribble = dma_alloc_coherent (&host->edev->dev,
3941da177e4SLinus Torvalds sizeof (struct aha1740_sg),
3951da177e4SLinus Torvalds &sg_dma, GFP_ATOMIC);
3961da177e4SLinus Torvalds if(SCpnt->host_scribble == NULL) {
3971da177e4SLinus Torvalds printk(KERN_WARNING "aha1740: out of memory in queuecommand!\n");
3981da177e4SLinus Torvalds return 1;
3991da177e4SLinus Torvalds }
4001da177e4SLinus Torvalds sgptr = (struct aha1740_sg *) SCpnt->host_scribble;
4011da177e4SLinus Torvalds sgptr->sg_dma_addr = sg_dma;
4021da177e4SLinus Torvalds
403c66cc13cSFUJITA Tomonori nseg = scsi_dma_map(SCpnt);
404c66cc13cSFUJITA Tomonori BUG_ON(nseg < 0);
405c66cc13cSFUJITA Tomonori if (nseg) {
406c66cc13cSFUJITA Tomonori struct scatterlist *sg;
4071da177e4SLinus Torvalds struct aha1740_chain * cptr;
408c66cc13cSFUJITA Tomonori int i;
4091da177e4SLinus Torvalds DEB(unsigned char * ptr);
4101da177e4SLinus Torvalds
4111da177e4SLinus Torvalds host->ecb[ecbno].sg = 1; /* SCSI Initiator Command
4121da177e4SLinus Torvalds * w/scatter-gather*/
4131da177e4SLinus Torvalds cptr = sgptr->sg_chain;
414c66cc13cSFUJITA Tomonori scsi_for_each_sg(SCpnt, sg, nseg, i) {
415c66cc13cSFUJITA Tomonori cptr[i].datalen = sg_dma_len (sg);
416c66cc13cSFUJITA Tomonori cptr[i].dataptr = sg_dma_address (sg);
4171da177e4SLinus Torvalds }
418c66cc13cSFUJITA Tomonori host->ecb[ecbno].datalen = nseg * sizeof(struct aha1740_chain);
4191da177e4SLinus Torvalds host->ecb[ecbno].dataptr = sg_dma;
4201da177e4SLinus Torvalds #ifdef DEBUG
4211da177e4SLinus Torvalds printk("cptr %x: ",cptr);
4221da177e4SLinus Torvalds ptr = (unsigned char *) cptr;
4231da177e4SLinus Torvalds for(i=0;i<24;i++) printk("%02x ", ptr[i]);
4241da177e4SLinus Torvalds #endif
4251da177e4SLinus Torvalds } else {
426c66cc13cSFUJITA Tomonori host->ecb[ecbno].datalen = 0;
427c66cc13cSFUJITA Tomonori host->ecb[ecbno].dataptr = 0;
4281da177e4SLinus Torvalds }
4291da177e4SLinus Torvalds host->ecb[ecbno].lun = SCpnt->device->lun;
4301da177e4SLinus Torvalds host->ecb[ecbno].ses = 1; /* Suppress underrun errors */
4311da177e4SLinus Torvalds host->ecb[ecbno].dir = direction;
4321da177e4SLinus Torvalds host->ecb[ecbno].ars = 1; /* Yes, get the sense on an error */
4331da177e4SLinus Torvalds host->ecb[ecbno].senselen = 12;
4341da177e4SLinus Torvalds host->ecb[ecbno].senseptr = ecb_cpu_to_dma (SCpnt->device->host,
4351da177e4SLinus Torvalds host->ecb[ecbno].sense);
4361da177e4SLinus Torvalds host->ecb[ecbno].statusptr = ecb_cpu_to_dma (SCpnt->device->host,
4371da177e4SLinus Torvalds host->ecb[ecbno].status);
4381da177e4SLinus Torvalds host->ecb[ecbno].done = done;
4391da177e4SLinus Torvalds host->ecb[ecbno].SCpnt = SCpnt;
4401da177e4SLinus Torvalds #ifdef DEBUG
4411da177e4SLinus Torvalds {
4421da177e4SLinus Torvalds int i;
4431da177e4SLinus Torvalds printk("aha1740_command: sending.. ");
4441da177e4SLinus Torvalds for (i = 0; i < sizeof(host->ecb[ecbno]) - 10; i++)
4451da177e4SLinus Torvalds printk("%02x ", ((unchar *)&host->ecb[ecbno])[i]);
4461da177e4SLinus Torvalds }
4471da177e4SLinus Torvalds printk("\n");
4481da177e4SLinus Torvalds #endif
4491da177e4SLinus Torvalds if (done) {
4501da177e4SLinus Torvalds /* The Adaptec Spec says the card is so fast that the loops
4511da177e4SLinus Torvalds will only be executed once in the code below. Even if this
4521da177e4SLinus Torvalds was true with the fastest processors when the spec was
45325985edcSLucas De Marchi written, it doesn't seem to be true with today's fast
4541da177e4SLinus Torvalds processors. We print a warning if the code is executed more
4551da177e4SLinus Torvalds often than LOOPCNT_WARN. If this happens, it should be
4561da177e4SLinus Torvalds investigated. If the count reaches LOOPCNT_MAX, we assume
4571da177e4SLinus Torvalds something is broken; since there is no way to return an
4581da177e4SLinus Torvalds error (the return value is ignored by the mid-level scsi
4591da177e4SLinus Torvalds layer) we have to panic (and maybe that's the best thing we
4601da177e4SLinus Torvalds can do then anyhow). */
4611da177e4SLinus Torvalds
4621da177e4SLinus Torvalds #define LOOPCNT_WARN 10 /* excessive mbxout wait -> syslog-msg */
4631da177e4SLinus Torvalds #define LOOPCNT_MAX 1000000 /* mbxout deadlock -> panic() after ~ 2 sec. */
4641da177e4SLinus Torvalds int loopcnt;
4651da177e4SLinus Torvalds unsigned int base = SCpnt->device->host->io_port;
4661da177e4SLinus Torvalds DEB(printk("aha1740[%d] critical section\n",ecbno));
4671da177e4SLinus Torvalds
4681da177e4SLinus Torvalds spin_lock_irqsave(SCpnt->device->host->host_lock, flags);
4691da177e4SLinus Torvalds for (loopcnt = 0; ; loopcnt++) {
4701da177e4SLinus Torvalds if (inb(G2STAT(base)) & G2STAT_MBXOUT) break;
4711da177e4SLinus Torvalds if (loopcnt == LOOPCNT_WARN) {
4721da177e4SLinus Torvalds printk("aha1740[%d]_mbxout wait!\n",ecbno);
4731da177e4SLinus Torvalds }
4741da177e4SLinus Torvalds if (loopcnt == LOOPCNT_MAX)
4751da177e4SLinus Torvalds panic("aha1740.c: mbxout busy!\n");
4761da177e4SLinus Torvalds }
4771da177e4SLinus Torvalds outl (ecb_cpu_to_dma (SCpnt->device->host, host->ecb + ecbno),
4781da177e4SLinus Torvalds MBOXOUT0(base));
4791da177e4SLinus Torvalds for (loopcnt = 0; ; loopcnt++) {
4801da177e4SLinus Torvalds if (! (inb(G2STAT(base)) & G2STAT_BUSY)) break;
4811da177e4SLinus Torvalds if (loopcnt == LOOPCNT_WARN) {
4821da177e4SLinus Torvalds printk("aha1740[%d]_attn wait!\n",ecbno);
4831da177e4SLinus Torvalds }
4841da177e4SLinus Torvalds if (loopcnt == LOOPCNT_MAX)
4851da177e4SLinus Torvalds panic("aha1740.c: attn wait failed!\n");
4861da177e4SLinus Torvalds }
4871da177e4SLinus Torvalds outb(ATTN_START | (target & 7), ATTN(base)); /* Start it up */
4881da177e4SLinus Torvalds spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags);
4891da177e4SLinus Torvalds DEB(printk("aha1740[%d] request queued.\n",ecbno));
4901da177e4SLinus Torvalds } else
4911da177e4SLinus Torvalds printk(KERN_ALERT "aha1740_queuecommand: done can't be NULL\n");
4921da177e4SLinus Torvalds return 0;
4931da177e4SLinus Torvalds }
4941da177e4SLinus Torvalds
DEF_SCSI_QCMD(aha1740_queuecommand)495f281233dSJeff Garzik static DEF_SCSI_QCMD(aha1740_queuecommand)
496f281233dSJeff Garzik
4971da177e4SLinus Torvalds /* Query the board for its irq_level and irq_type. Nothing else matters
4981da177e4SLinus Torvalds in enhanced mode on an EISA bus. */
4991da177e4SLinus Torvalds
5001da177e4SLinus Torvalds static void aha1740_getconfig(unsigned int base, unsigned int *irq_level,
5011da177e4SLinus Torvalds unsigned int *irq_type,
5021da177e4SLinus Torvalds unsigned int *translation)
5031da177e4SLinus Torvalds {
5041da177e4SLinus Torvalds static int intab[] = { 9, 10, 11, 12, 0, 14, 15, 0 };
5051da177e4SLinus Torvalds
5061da177e4SLinus Torvalds *irq_level = intab[inb(INTDEF(base)) & 0x7];
5071da177e4SLinus Torvalds *irq_type = (inb(INTDEF(base)) & 0x8) >> 3;
5081da177e4SLinus Torvalds *translation = inb(RESV1(base)) & 0x1;
5091da177e4SLinus Torvalds outb(inb(INTDEF(base)) | 0x10, INTDEF(base));
5101da177e4SLinus Torvalds }
5111da177e4SLinus Torvalds
aha1740_biosparam(struct scsi_device * sdev,struct block_device * dev,sector_t capacity,int * ip)5121da177e4SLinus Torvalds static int aha1740_biosparam(struct scsi_device *sdev,
5131da177e4SLinus Torvalds struct block_device *dev,
5141da177e4SLinus Torvalds sector_t capacity, int* ip)
5151da177e4SLinus Torvalds {
5161da177e4SLinus Torvalds int size = capacity;
5171da177e4SLinus Torvalds int extended = HOSTDATA(sdev->host)->translation;
5181da177e4SLinus Torvalds
5191da177e4SLinus Torvalds DEB(printk("aha1740_biosparam\n"));
5201da177e4SLinus Torvalds if (extended && (ip[2] > 1024)) {
5211da177e4SLinus Torvalds ip[0] = 255;
5221da177e4SLinus Torvalds ip[1] = 63;
5231da177e4SLinus Torvalds ip[2] = size / (255 * 63);
5241da177e4SLinus Torvalds } else {
5251da177e4SLinus Torvalds ip[0] = 64;
5261da177e4SLinus Torvalds ip[1] = 32;
5271da177e4SLinus Torvalds ip[2] = size >> 11;
5281da177e4SLinus Torvalds }
5291da177e4SLinus Torvalds return 0;
5301da177e4SLinus Torvalds }
5311da177e4SLinus Torvalds
aha1740_eh_abort_handler(struct scsi_cmnd * dummy)53291ebc1faSJohannes Thumshirn static int aha1740_eh_abort_handler (struct scsi_cmnd *dummy)
5331da177e4SLinus Torvalds {
5341da177e4SLinus Torvalds /*
5351da177e4SLinus Torvalds * From Alan Cox :
5361da177e4SLinus Torvalds * The AHA1740 has firmware handled abort/reset handling. The "head in
5371da177e4SLinus Torvalds * sand" kernel code is correct for once 8)
5381da177e4SLinus Torvalds *
5391da177e4SLinus Torvalds * So we define a dummy handler just to keep the kernel SCSI code as
5401da177e4SLinus Torvalds * quiet as possible...
5411da177e4SLinus Torvalds */
5421da177e4SLinus Torvalds
543b6c92b7eSHannes Reinecke return SUCCESS;
5441da177e4SLinus Torvalds }
5451da177e4SLinus Torvalds
546*4df23b30SBart Van Assche static const struct scsi_host_template aha1740_template = {
5471da177e4SLinus Torvalds .module = THIS_MODULE,
5481da177e4SLinus Torvalds .proc_name = "aha1740",
549e633c1e5SAl Viro .show_info = aha1740_show_info,
5501da177e4SLinus Torvalds .name = "Adaptec 174x (EISA)",
5511da177e4SLinus Torvalds .queuecommand = aha1740_queuecommand,
5521da177e4SLinus Torvalds .bios_param = aha1740_biosparam,
5531da177e4SLinus Torvalds .can_queue = AHA1740_ECBS,
5541da177e4SLinus Torvalds .this_id = 7,
5551da177e4SLinus Torvalds .sg_tablesize = AHA1740_SCATTER,
5561da177e4SLinus Torvalds .eh_abort_handler = aha1740_eh_abort_handler,
5571da177e4SLinus Torvalds };
5581da177e4SLinus Torvalds
aha1740_probe(struct device * dev)5591da177e4SLinus Torvalds static int aha1740_probe (struct device *dev)
5601da177e4SLinus Torvalds {
56108157cd0SJeff Garzik int slotbase, rc;
5621da177e4SLinus Torvalds unsigned int irq_level, irq_type, translation;
5631da177e4SLinus Torvalds struct Scsi_Host *shpnt;
5641da177e4SLinus Torvalds struct aha1740_hostdata *host;
5651da177e4SLinus Torvalds struct eisa_device *edev = to_eisa_device (dev);
5661da177e4SLinus Torvalds
5671da177e4SLinus Torvalds DEB(printk("aha1740_probe: \n"));
5681da177e4SLinus Torvalds
5691da177e4SLinus Torvalds slotbase = edev->base_addr + EISA_VENDOR_ID_OFFSET;
5701da177e4SLinus Torvalds if (!request_region(slotbase, SLOTSIZE, "aha1740")) /* See if in use */
5711da177e4SLinus Torvalds return -EBUSY;
5721da177e4SLinus Torvalds if (!aha1740_test_port(slotbase))
5731da177e4SLinus Torvalds goto err_release_region;
5741da177e4SLinus Torvalds aha1740_getconfig(slotbase,&irq_level,&irq_type,&translation);
5751da177e4SLinus Torvalds if ((inb(G2STAT(slotbase)) &
5761da177e4SLinus Torvalds (G2STAT_MBXOUT|G2STAT_BUSY)) != G2STAT_MBXOUT) {
5771da177e4SLinus Torvalds /* If the card isn't ready, hard reset it */
5781da177e4SLinus Torvalds outb(G2CNTRL_HRST, G2CNTRL(slotbase));
5791da177e4SLinus Torvalds outb(0, G2CNTRL(slotbase));
5801da177e4SLinus Torvalds }
5811da177e4SLinus Torvalds printk(KERN_INFO "Configuring slot %d at IO:%x, IRQ %u (%s)\n",
5821da177e4SLinus Torvalds edev->slot, slotbase, irq_level, irq_type ? "edge" : "level");
5831da177e4SLinus Torvalds printk(KERN_INFO "aha174x: Extended translation %sabled.\n",
5841da177e4SLinus Torvalds translation ? "en" : "dis");
5851da177e4SLinus Torvalds shpnt = scsi_host_alloc(&aha1740_template,
5861da177e4SLinus Torvalds sizeof(struct aha1740_hostdata));
5871da177e4SLinus Torvalds if(shpnt == NULL)
5881da177e4SLinus Torvalds goto err_release_region;
5891da177e4SLinus Torvalds
5901da177e4SLinus Torvalds shpnt->base = 0;
5911da177e4SLinus Torvalds shpnt->io_port = slotbase;
5921da177e4SLinus Torvalds shpnt->n_io_port = SLOTSIZE;
5931da177e4SLinus Torvalds shpnt->irq = irq_level;
5941da177e4SLinus Torvalds shpnt->dma_channel = 0xff;
5951da177e4SLinus Torvalds host = HOSTDATA(shpnt);
5961da177e4SLinus Torvalds host->edev = edev;
5971da177e4SLinus Torvalds host->translation = translation;
5981da177e4SLinus Torvalds host->ecb_dma_addr = dma_map_single (&edev->dev, host->ecb,
5991da177e4SLinus Torvalds sizeof (host->ecb),
6001da177e4SLinus Torvalds DMA_BIDIRECTIONAL);
6011da177e4SLinus Torvalds if (!host->ecb_dma_addr) {
6021da177e4SLinus Torvalds printk (KERN_ERR "aha1740_probe: Couldn't map ECB, giving up\n");
6031da177e4SLinus Torvalds goto err_host_put;
6041da177e4SLinus Torvalds }
6051da177e4SLinus Torvalds
6061da177e4SLinus Torvalds DEB(printk("aha1740_probe: enable interrupt channel %d\n",irq_level));
6071d6f359aSThomas Gleixner if (request_irq(irq_level,aha1740_intr_handle,irq_type ? 0 : IRQF_SHARED,
6081da177e4SLinus Torvalds "aha1740",shpnt)) {
6091da177e4SLinus Torvalds printk(KERN_ERR "aha1740_probe: Unable to allocate IRQ %d.\n",
6101da177e4SLinus Torvalds irq_level);
6111da177e4SLinus Torvalds goto err_unmap;
6121da177e4SLinus Torvalds }
6131da177e4SLinus Torvalds
6141da177e4SLinus Torvalds eisa_set_drvdata (edev, shpnt);
61508157cd0SJeff Garzik
61608157cd0SJeff Garzik rc = scsi_add_host (shpnt, dev);
61708157cd0SJeff Garzik if (rc)
61808157cd0SJeff Garzik goto err_irq;
61908157cd0SJeff Garzik
6201da177e4SLinus Torvalds scsi_scan_host (shpnt);
6211da177e4SLinus Torvalds return 0;
6221da177e4SLinus Torvalds
62308157cd0SJeff Garzik err_irq:
62408157cd0SJeff Garzik free_irq(irq_level, shpnt);
6251da177e4SLinus Torvalds err_unmap:
6261da177e4SLinus Torvalds dma_unmap_single (&edev->dev, host->ecb_dma_addr,
6271da177e4SLinus Torvalds sizeof (host->ecb), DMA_BIDIRECTIONAL);
6281da177e4SLinus Torvalds err_host_put:
6291da177e4SLinus Torvalds scsi_host_put (shpnt);
6301da177e4SLinus Torvalds err_release_region:
6311da177e4SLinus Torvalds release_region(slotbase, SLOTSIZE);
6321da177e4SLinus Torvalds
6331da177e4SLinus Torvalds return -ENODEV;
6341da177e4SLinus Torvalds }
6351da177e4SLinus Torvalds
aha1740_remove(struct device * dev)6366f039790SGreg Kroah-Hartman static int aha1740_remove (struct device *dev)
6371da177e4SLinus Torvalds {
63878c55d76SGreg Kroah-Hartman struct Scsi_Host *shpnt = dev_get_drvdata(dev);
6391da177e4SLinus Torvalds struct aha1740_hostdata *host = HOSTDATA (shpnt);
6401da177e4SLinus Torvalds
6411da177e4SLinus Torvalds scsi_remove_host(shpnt);
6421da177e4SLinus Torvalds
6431da177e4SLinus Torvalds free_irq (shpnt->irq, shpnt);
6441da177e4SLinus Torvalds dma_unmap_single (dev, host->ecb_dma_addr,
6451da177e4SLinus Torvalds sizeof (host->ecb), DMA_BIDIRECTIONAL);
6461da177e4SLinus Torvalds release_region (shpnt->io_port, SLOTSIZE);
6471da177e4SLinus Torvalds
6481da177e4SLinus Torvalds scsi_host_put (shpnt);
6491da177e4SLinus Torvalds
6501da177e4SLinus Torvalds return 0;
6511da177e4SLinus Torvalds }
6521da177e4SLinus Torvalds
6531da177e4SLinus Torvalds static struct eisa_device_id aha1740_ids[] = {
6541da177e4SLinus Torvalds { "ADP0000" }, /* 1740 */
6551da177e4SLinus Torvalds { "ADP0001" }, /* 1740A */
6561da177e4SLinus Torvalds { "ADP0002" }, /* 1742A */
6571da177e4SLinus Torvalds { "ADP0400" }, /* 1744 */
6581da177e4SLinus Torvalds { "" }
6591da177e4SLinus Torvalds };
66007563c71SMichael Tokarev MODULE_DEVICE_TABLE(eisa, aha1740_ids);
6611da177e4SLinus Torvalds
6621da177e4SLinus Torvalds static struct eisa_driver aha1740_driver = {
6631da177e4SLinus Torvalds .id_table = aha1740_ids,
6641da177e4SLinus Torvalds .driver = {
6651da177e4SLinus Torvalds .name = "aha1740",
6661da177e4SLinus Torvalds .probe = aha1740_probe,
6676f039790SGreg Kroah-Hartman .remove = aha1740_remove,
6681da177e4SLinus Torvalds },
6691da177e4SLinus Torvalds };
6701da177e4SLinus Torvalds
aha1740_init(void)6711da177e4SLinus Torvalds static __init int aha1740_init (void)
6721da177e4SLinus Torvalds {
6731da177e4SLinus Torvalds return eisa_driver_register (&aha1740_driver);
6741da177e4SLinus Torvalds }
6751da177e4SLinus Torvalds
aha1740_exit(void)6761da177e4SLinus Torvalds static __exit void aha1740_exit (void)
6771da177e4SLinus Torvalds {
6781da177e4SLinus Torvalds eisa_driver_unregister (&aha1740_driver);
6791da177e4SLinus Torvalds }
6801da177e4SLinus Torvalds
6811da177e4SLinus Torvalds module_init (aha1740_init);
6821da177e4SLinus Torvalds module_exit (aha1740_exit);
6831da177e4SLinus Torvalds
6841da177e4SLinus Torvalds MODULE_LICENSE("GPL");
685