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