Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
new file mode 100644
index 0000000..e9920a0
--- /dev/null
+++ b/drivers/scsi/aha1542.c
@@ -0,0 +1,1832 @@
+/* $Id: aha1542.c,v 1.1 1992/07/24 06:27:38 root Exp root $
+ *  linux/kernel/aha1542.c
+ *
+ *  Copyright (C) 1992  Tommy Thorn
+ *  Copyright (C) 1993, 1994, 1995 Eric Youngdale
+ *
+ *  Modified by Eric Youngdale
+ *        Use request_irq and request_dma to help prevent unexpected conflicts
+ *        Set up on-board DMA controller, such that we do not have to
+ *        have the bios enabled to use the aha1542.
+ *  Modified by David Gentzel
+ *        Don't call request_dma if dma mask is 0 (for BusLogic BT-445S VL-Bus
+ *        controller).
+ *  Modified by Matti Aarnio
+ *        Accept parameters from LILO cmd-line. -- 1-Oct-94
+ *  Modified by Mike McLagan <mike.mclagan@linux.org>
+ *        Recognise extended mode on AHA1542CP, different bit than 1542CF
+ *        1-Jan-97
+ *  Modified by Bjorn L. Thordarson and Einar Thor Einarsson
+ *        Recognize that DMA0 is valid DMA channel -- 13-Jul-98
+ *  Modified by Chris Faulhaber <jedgar@fxp.org>
+ *        Added module command-line options
+ *        19-Jul-99
+ *  Modified by Adam Fritzler <mid@auk.cx>
+ *        Added proper detection of the AHA-1640 (MCA version of AHA-1540)
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/isapnp.h>
+#include <linux/blkdev.h>
+#include <linux/mca.h>
+#include <linux/mca-legacy.h>
+
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "aha1542.h"
+
+#define SCSI_BUF_PA(address)	isa_virt_to_bus(address)
+#define SCSI_SG_PA(sgent)	(isa_page_to_bus((sgent)->page) + (sgent)->offset)
+
+static void BAD_DMA(void *address, unsigned int length)
+{
+	printk(KERN_CRIT "buf vaddress %p paddress 0x%lx length %d\n",
+	       address,
+	       SCSI_BUF_PA(address),
+	       length);
+	panic("Buffer at physical address > 16Mb used for aha1542");
+}
+
+static void BAD_SG_DMA(Scsi_Cmnd * SCpnt,
+		       struct scatterlist *sgpnt,
+		       int nseg,
+		       int badseg)
+{
+	printk(KERN_CRIT "sgpnt[%d:%d] page %p/0x%llx length %u\n",
+	       badseg, nseg,
+	       page_address(sgpnt[badseg].page) + sgpnt[badseg].offset,
+	       (unsigned long long)SCSI_SG_PA(&sgpnt[badseg]),
+	       sgpnt[badseg].length);
+
+	/*
+	 * Not safe to continue.
+	 */
+	panic("Buffer at physical address > 16Mb used for aha1542");
+}
+
+#include<linux/stat.h>
+
+#ifdef DEBUG
+#define DEB(x) x
+#else
+#define DEB(x)
+#endif
+
+/*
+   static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/aha1542.c,v 1.1 1992/07/24 06:27:38 root Exp root $";
+ */
+
+/* The adaptec can be configured for quite a number of addresses, but
+   I generally do not want the card poking around at random.  We allow
+   two addresses - this allows people to use the Adaptec with a Midi
+   card, which also used 0x330 -- can be overridden with LILO! */
+
+#define MAXBOARDS 4		/* Increase this and the sizes of the
+				   arrays below, if you need more.. */
+
+/* Boards 3,4 slots are reserved for ISAPnP/MCA scans */
+
+static unsigned int bases[MAXBOARDS] __initdata = {0x330, 0x334, 0, 0};
+
+/* set by aha1542_setup according to the command line; they also may
+   be marked __initdata, but require zero initializers then */
+
+static int setup_called[MAXBOARDS];
+static int setup_buson[MAXBOARDS];
+static int setup_busoff[MAXBOARDS];
+static int setup_dmaspeed[MAXBOARDS] __initdata = { -1, -1, -1, -1 };
+
+/*
+ * LILO/Module params:  aha1542=<PORTBASE>[,<BUSON>,<BUSOFF>[,<DMASPEED>]]
+ *
+ * Where:  <PORTBASE> is any of the valid AHA addresses:
+ *                      0x130, 0x134, 0x230, 0x234, 0x330, 0x334
+ *         <BUSON>  is the time (in microsecs) that AHA spends on the AT-bus
+ *                  when transferring data.  1542A power-on default is 11us,
+ *                  valid values are in range: 2..15 (decimal)
+ *         <BUSOFF> is the time that AHA spends OFF THE BUS after while
+ *                  it is transferring data (not to monopolize the bus).
+ *                  Power-on default is 4us, valid range: 1..64 microseconds.
+ *         <DMASPEED> Default is jumper selected (1542A: on the J1),
+ *                  but experimenter can alter it with this.
+ *                  Valid values: 5, 6, 7, 8, 10 (MB/s)
+ *                  Factory default is 5 MB/s.
+ */
+
+#if defined(MODULE)
+static int isapnp = 0;
+static int aha1542[] = {0x330, 11, 4, -1};
+module_param_array(aha1542, int, NULL, 0);
+module_param(isapnp, bool, 0);
+
+static struct isapnp_device_id id_table[] __initdata = {
+	{
+		ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1542),
+		0
+	},
+	{0}
+};
+
+MODULE_DEVICE_TABLE(isapnp, id_table);
+
+#else
+static int isapnp = 1;
+#endif
+
+#define BIOS_TRANSLATION_1632 0	/* Used by some old 1542A boards */
+#define BIOS_TRANSLATION_6432 1	/* Default case these days */
+#define BIOS_TRANSLATION_25563 2	/* Big disk case */
+
+struct aha1542_hostdata {
+	/* This will effectively start both of them at the first mailbox */
+	int bios_translation;	/* Mapping bios uses - for compatibility */
+	int aha1542_last_mbi_used;
+	int aha1542_last_mbo_used;
+	Scsi_Cmnd *SCint[AHA1542_MAILBOXES];
+	struct mailbox mb[2 * AHA1542_MAILBOXES];
+	struct ccb ccb[AHA1542_MAILBOXES];
+};
+
+#define HOSTDATA(host) ((struct aha1542_hostdata *) &host->hostdata)
+
+static struct Scsi_Host *aha_host[7];	/* One for each IRQ level (9-15) */
+
+static DEFINE_SPINLOCK(aha1542_lock);
+
+
+
+#define WAITnexttimeout 3000000
+
+static void setup_mailboxes(int base_io, struct Scsi_Host *shpnt);
+static int aha1542_restart(struct Scsi_Host *shost);
+static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id, struct pt_regs *regs);
+static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id,
+					struct pt_regs *regs);
+
+#define aha1542_intr_reset(base)  outb(IRST, CONTROL(base))
+
+#define WAIT(port, mask, allof, noneof)					\
+ { register int WAITbits;						\
+   register int WAITtimeout = WAITnexttimeout;				\
+   while (1) {								\
+     WAITbits = inb(port) & (mask);					\
+     if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \
+       break;                                                         	\
+     if (--WAITtimeout == 0) goto fail;					\
+   }									\
+ }
+
+/* Similar to WAIT, except we use the udelay call to regulate the
+   amount of time we wait.  */
+#define WAITd(port, mask, allof, noneof, timeout)			\
+ { register int WAITbits;						\
+   register int WAITtimeout = timeout;					\
+   while (1) {								\
+     WAITbits = inb(port) & (mask);					\
+     if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \
+       break;                                                         	\
+     mdelay(1);							\
+     if (--WAITtimeout == 0) goto fail;					\
+   }									\
+ }
+
+static void aha1542_stat(void)
+{
+/*	int s = inb(STATUS), i = inb(INTRFLAGS);
+	printk("status=%x intrflags=%x\n", s, i, WAITnexttimeout-WAITtimeout); */
+}
+
+/* This is a bit complicated, but we need to make sure that an interrupt
+   routine does not send something out while we are in the middle of this.
+   Fortunately, it is only at boot time that multi-byte messages
+   are ever sent. */
+static int aha1542_out(unsigned int base, unchar * cmdp, int len)
+{
+	unsigned long flags = 0;
+	int got_lock;
+
+	if (len == 1) {
+		got_lock = 0;
+		while (1 == 1) {
+			WAIT(STATUS(base), CDF, 0, CDF);
+			spin_lock_irqsave(&aha1542_lock, flags);
+			if (inb(STATUS(base)) & CDF) {
+				spin_unlock_irqrestore(&aha1542_lock, flags);
+				continue;
+			}
+			outb(*cmdp, DATA(base));
+			spin_unlock_irqrestore(&aha1542_lock, flags);
+			return 0;
+		}
+	} else {
+		spin_lock_irqsave(&aha1542_lock, flags);
+		got_lock = 1;
+		while (len--) {
+			WAIT(STATUS(base), CDF, 0, CDF);
+			outb(*cmdp++, DATA(base));
+		}
+		spin_unlock_irqrestore(&aha1542_lock, flags);
+	}
+	return 0;
+fail:
+	if (got_lock)
+		spin_unlock_irqrestore(&aha1542_lock, flags);
+	printk(KERN_ERR "aha1542_out failed(%d): ", len + 1);
+	aha1542_stat();
+	return 1;
+}
+
+/* Only used at boot time, so we do not need to worry about latency as much
+   here */
+
+static int __init aha1542_in(unsigned int base, unchar * cmdp, int len)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&aha1542_lock, flags);
+	while (len--) {
+		WAIT(STATUS(base), DF, DF, 0);
+		*cmdp++ = inb(DATA(base));
+	}
+	spin_unlock_irqrestore(&aha1542_lock, flags);
+	return 0;
+fail:
+	spin_unlock_irqrestore(&aha1542_lock, flags);
+	printk(KERN_ERR "aha1542_in failed(%d): ", len + 1);
+	aha1542_stat();
+	return 1;
+}
+
+/* Similar to aha1542_in, except that we wait a very short period of time.
+   We use this if we know the board is alive and awake, but we are not sure
+   if the board will respond to the command we are about to send or not */
+static int __init aha1542_in1(unsigned int base, unchar * cmdp, int len)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&aha1542_lock, flags);
+	while (len--) {
+		WAITd(STATUS(base), DF, DF, 0, 100);
+		*cmdp++ = inb(DATA(base));
+	}
+	spin_unlock_irqrestore(&aha1542_lock, flags);
+	return 0;
+fail:
+	spin_unlock_irqrestore(&aha1542_lock, flags);
+	return 1;
+}
+
+static int makecode(unsigned hosterr, unsigned scsierr)
+{
+	switch (hosterr) {
+	case 0x0:
+	case 0xa:		/* Linked command complete without error and linked normally */
+	case 0xb:		/* Linked command complete without error, interrupt generated */
+		hosterr = 0;
+		break;
+
+	case 0x11:		/* Selection time out-The initiator selection or target
+				   reselection was not complete within the SCSI Time out period */
+		hosterr = DID_TIME_OUT;
+		break;
+
+	case 0x12:		/* Data overrun/underrun-The target attempted to transfer more data
+				   than was allocated by the Data Length field or the sum of the
+				   Scatter / Gather Data Length fields. */
+
+	case 0x13:		/* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
+
+	case 0x15:		/* MBO command was not 00, 01 or 02-The first byte of the CB was
+				   invalid. This usually indicates a software failure. */
+
+	case 0x16:		/* Invalid CCB Operation Code-The first byte of the CCB was invalid.
+				   This usually indicates a software failure. */
+
+	case 0x17:		/* Linked CCB does not have the same LUN-A subsequent CCB of a set
+				   of linked CCB's does not specify the same logical unit number as
+				   the first. */
+	case 0x18:		/* Invalid Target Direction received from Host-The direction of a
+				   Target Mode CCB was invalid. */
+
+	case 0x19:		/* Duplicate CCB Received in Target Mode-More than once CCB was
+				   received to service data transfer between the same target LUN
+				   and initiator SCSI ID in the same direction. */
+
+	case 0x1a:		/* Invalid CCB or Segment List Parameter-A segment list with a zero
+				   length segment or invalid segment list boundaries was received.
+				   A CCB parameter was invalid. */
+		DEB(printk("Aha1542: %x %x\n", hosterr, scsierr));
+		hosterr = DID_ERROR;	/* Couldn't find any better */
+		break;
+
+	case 0x14:		/* Target bus phase sequence failure-An invalid bus phase or bus
+				   phase sequence was requested by the target. The host adapter
+				   will generate a SCSI Reset Condition, notifying the host with
+				   a SCRD interrupt */
+		hosterr = DID_RESET;
+		break;
+	default:
+		printk(KERN_ERR "aha1542: makecode: unknown hoststatus %x\n", hosterr);
+		break;
+	}
+	return scsierr | (hosterr << 16);
+}
+
+static int __init aha1542_test_port(int bse, struct Scsi_Host *shpnt)
+{
+	unchar inquiry_cmd[] = {CMD_INQUIRY};
+	unchar inquiry_result[4];
+	unchar *cmdp;
+	int len;
+	volatile int debug = 0;
+
+	/* Quick and dirty test for presence of the card. */
+	if (inb(STATUS(bse)) == 0xff)
+		return 0;
+
+	/* Reset the adapter. I ought to make a hard reset, but it's not really necessary */
+
+	/*  DEB(printk("aha1542_test_port called \n")); */
+
+	/* In case some other card was probing here, reset interrupts */
+	aha1542_intr_reset(bse);	/* reset interrupts, so they don't block */
+
+	outb(SRST | IRST /*|SCRST */ , CONTROL(bse));
+
+	mdelay(20);		/* Wait a little bit for things to settle down. */
+
+	debug = 1;
+	/* Expect INIT and IDLE, any of the others are bad */
+	WAIT(STATUS(bse), STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF);
+
+	debug = 2;
+	/* Shouldn't have generated any interrupts during reset */
+	if (inb(INTRFLAGS(bse)) & INTRMASK)
+		goto fail;
+
+
+	/* Perform a host adapter inquiry instead so we do not need to set
+	   up the mailboxes ahead of time */
+
+	aha1542_out(bse, inquiry_cmd, 1);
+
+	debug = 3;
+	len = 4;
+	cmdp = &inquiry_result[0];
+
+	while (len--) {
+		WAIT(STATUS(bse), DF, DF, 0);
+		*cmdp++ = inb(DATA(bse));
+	}
+
+	debug = 8;
+	/* Reading port should reset DF */
+	if (inb(STATUS(bse)) & DF)
+		goto fail;
+
+	debug = 9;
+	/* When HACC, command is completed, and we're though testing */
+	WAIT(INTRFLAGS(bse), HACC, HACC, 0);
+	/* now initialize adapter */
+
+	debug = 10;
+	/* Clear interrupts */
+	outb(IRST, CONTROL(bse));
+
+	debug = 11;
+
+	return debug;		/* 1 = ok */
+fail:
+	return 0;		/* 0 = not ok */
+}
+
+/* A quick wrapper for do_aha1542_intr_handle to grab the spin lock */
+static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id,
+					struct pt_regs *regs)
+{
+	unsigned long flags;
+	struct Scsi_Host *shost;
+
+	shost = aha_host[irq - 9];
+	if (!shost)
+		panic("Splunge!");
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	aha1542_intr_handle(shost, dev_id, regs);
+	spin_unlock_irqrestore(shost->host_lock, flags);
+	return IRQ_HANDLED;
+}
+
+/* A "high" level interrupt handler */
+static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id, struct pt_regs *regs)
+{
+	void (*my_done) (Scsi_Cmnd *) = NULL;
+	int errstatus, mbi, mbo, mbistatus;
+	int number_serviced;
+	unsigned long flags;
+	Scsi_Cmnd *SCtmp;
+	int flag;
+	int needs_restart;
+	struct mailbox *mb;
+	struct ccb *ccb;
+
+	mb = HOSTDATA(shost)->mb;
+	ccb = HOSTDATA(shost)->ccb;
+
+#ifdef DEBUG
+	{
+		flag = inb(INTRFLAGS(shost->io_port));
+		printk(KERN_DEBUG "aha1542_intr_handle: ");
+		if (!(flag & ANYINTR))
+			printk("no interrupt?");
+		if (flag & MBIF)
+			printk("MBIF ");
+		if (flag & MBOA)
+			printk("MBOF ");
+		if (flag & HACC)
+			printk("HACC ");
+		if (flag & SCRD)
+			printk("SCRD ");
+		printk("status %02x\n", inb(STATUS(shost->io_port)));
+	};
+#endif
+	number_serviced = 0;
+	needs_restart = 0;
+
+	while (1 == 1) {
+		flag = inb(INTRFLAGS(shost->io_port));
+
+		/* Check for unusual interrupts.  If any of these happen, we should
+		   probably do something special, but for now just printing a message
+		   is sufficient.  A SCSI reset detected is something that we really
+		   need to deal with in some way. */
+		if (flag & ~MBIF) {
+			if (flag & MBOA)
+				printk("MBOF ");
+			if (flag & HACC)
+				printk("HACC ");
+			if (flag & SCRD) {
+				needs_restart = 1;
+				printk("SCRD ");
+			}
+		}
+		aha1542_intr_reset(shost->io_port);
+
+		spin_lock_irqsave(&aha1542_lock, flags);
+		mbi = HOSTDATA(shost)->aha1542_last_mbi_used + 1;
+		if (mbi >= 2 * AHA1542_MAILBOXES)
+			mbi = AHA1542_MAILBOXES;
+
+		do {
+			if (mb[mbi].status != 0)
+				break;
+			mbi++;
+			if (mbi >= 2 * AHA1542_MAILBOXES)
+				mbi = AHA1542_MAILBOXES;
+		} while (mbi != HOSTDATA(shost)->aha1542_last_mbi_used);
+
+		if (mb[mbi].status == 0) {
+			spin_unlock_irqrestore(&aha1542_lock, flags);
+			/* Hmm, no mail.  Must have read it the last time around */
+			if (!number_serviced && !needs_restart)
+				printk(KERN_WARNING "aha1542.c: interrupt received, but no mail.\n");
+			/* We detected a reset.  Restart all pending commands for
+			   devices that use the hard reset option */
+			if (needs_restart)
+				aha1542_restart(shost);
+			return;
+		};
+
+		mbo = (scsi2int(mb[mbi].ccbptr) - (SCSI_BUF_PA(&ccb[0]))) / sizeof(struct ccb);
+		mbistatus = mb[mbi].status;
+		mb[mbi].status = 0;
+		HOSTDATA(shost)->aha1542_last_mbi_used = mbi;
+		spin_unlock_irqrestore(&aha1542_lock, flags);
+
+#ifdef DEBUG
+		{
+			if (ccb[mbo].tarstat | ccb[mbo].hastat)
+				printk(KERN_DEBUG "aha1542_command: returning %x (status %d)\n",
+				       ccb[mbo].tarstat + ((int) ccb[mbo].hastat << 16), mb[mbi].status);
+		};
+#endif
+
+		if (mbistatus == 3)
+			continue;	/* Aborted command not found */
+
+#ifdef DEBUG
+		printk(KERN_DEBUG "...done %d %d\n", mbo, mbi);
+#endif
+
+		SCtmp = HOSTDATA(shost)->SCint[mbo];
+
+		if (!SCtmp || !SCtmp->scsi_done) {
+			printk(KERN_WARNING "aha1542_intr_handle: Unexpected interrupt\n");
+			printk(KERN_WARNING "tarstat=%x, hastat=%x idlun=%x ccb#=%d \n", ccb[mbo].tarstat,
+			       ccb[mbo].hastat, ccb[mbo].idlun, mbo);
+			return;
+		}
+		my_done = SCtmp->scsi_done;
+		if (SCtmp->host_scribble) {
+			kfree(SCtmp->host_scribble);
+			SCtmp->host_scribble = NULL;
+		}
+		/* Fetch the sense data, and tuck it away, in the required slot.  The
+		   Adaptec automatically fetches it, and there is no guarantee that
+		   we will still have it in the cdb when we come back */
+		if (ccb[mbo].tarstat == 2)
+			memcpy(SCtmp->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen],
+			       sizeof(SCtmp->sense_buffer));
+
+
+		/* is there mail :-) */
+
+		/* more error checking left out here */
+		if (mbistatus != 1)
+			/* This is surely wrong, but I don't know what's right */
+			errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat);
+		else
+			errstatus = 0;
+
+#ifdef DEBUG
+		if (errstatus)
+			printk(KERN_DEBUG "(aha1542 error:%x %x %x) ", errstatus,
+			       ccb[mbo].hastat, ccb[mbo].tarstat);
+#endif
+
+		if (ccb[mbo].tarstat == 2) {
+#ifdef DEBUG
+			int i;
+#endif
+			DEB(printk("aha1542_intr_handle: sense:"));
+#ifdef DEBUG
+			for (i = 0; i < 12; i++)
+				printk("%02x ", ccb[mbo].cdb[ccb[mbo].cdblen + i]);
+			printk("\n");
+#endif
+			/*
+			   DEB(printk("aha1542_intr_handle: buf:"));
+			   for (i = 0; i < bufflen; i++)
+			   printk("%02x ", ((unchar *)buff)[i]);
+			   printk("\n");
+			 */
+		}
+		DEB(if (errstatus) printk("aha1542_intr_handle: returning %6x\n", errstatus));
+		SCtmp->result = errstatus;
+		HOSTDATA(shost)->SCint[mbo] = NULL;	/* This effectively frees up the mailbox slot, as
+							   far as queuecommand is concerned */
+		my_done(SCtmp);
+		number_serviced++;
+	};
+}
+
+static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+{
+	unchar ahacmd = CMD_START_SCSI;
+	unchar direction;
+	unchar *cmd = (unchar *) SCpnt->cmnd;
+	unchar target = SCpnt->device->id;
+	unchar lun = SCpnt->device->lun;
+	unsigned long flags;
+	void *buff = SCpnt->request_buffer;
+	int bufflen = SCpnt->request_bufflen;
+	int mbo;
+	struct mailbox *mb;
+	struct ccb *ccb;
+
+	DEB(int i);
+
+	mb = HOSTDATA(SCpnt->device->host)->mb;
+	ccb = HOSTDATA(SCpnt->device->host)->ccb;
+
+	DEB(if (target > 1) {
+	    SCpnt->result = DID_TIME_OUT << 16;
+	    done(SCpnt); return 0;
+	    }
+	);
+
+	if (*cmd == REQUEST_SENSE) {
+		/* Don't do the command - we have the sense data already */
+#if 0
+		/* scsi_request_sense() provides a buffer of size 256,
+		   so there is no reason to expect equality */
+		if (bufflen != sizeof(SCpnt->sense_buffer))
+			printk(KERN_CRIT "aha1542: Wrong buffer length supplied "
+			       "for request sense (%d)\n", bufflen);
+#endif
+		SCpnt->result = 0;
+		done(SCpnt);
+		return 0;
+	}
+#ifdef DEBUG
+	if (*cmd == READ_10 || *cmd == WRITE_10)
+		i = xscsi2int(cmd + 2);
+	else if (*cmd == READ_6 || *cmd == WRITE_6)
+		i = scsi2int(cmd + 2);
+	else
+		i = -1;
+	if (done)
+		printk(KERN_DEBUG "aha1542_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
+	else
+		printk(KERN_DEBUG "aha1542_command: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
+	aha1542_stat();
+	printk(KERN_DEBUG "aha1542_queuecommand: dumping scsi cmd:");
+	for (i = 0; i < SCpnt->cmd_len; i++)
+		printk("%02x ", cmd[i]);
+	printk("\n");
+	if (*cmd == WRITE_10 || *cmd == WRITE_6)
+		return 0;	/* we are still testing, so *don't* write */
+#endif
+	/* Use the outgoing mailboxes in a round-robin fashion, because this
+	   is how the host adapter will scan for them */
+
+	spin_lock_irqsave(&aha1542_lock, flags);
+	mbo = HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used + 1;
+	if (mbo >= AHA1542_MAILBOXES)
+		mbo = 0;
+
+	do {
+		if (mb[mbo].status == 0 && HOSTDATA(SCpnt->device->host)->SCint[mbo] == NULL)
+			break;
+		mbo++;
+		if (mbo >= AHA1542_MAILBOXES)
+			mbo = 0;
+	} while (mbo != HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used);
+
+	if (mb[mbo].status || HOSTDATA(SCpnt->device->host)->SCint[mbo])
+		panic("Unable to find empty mailbox for aha1542.\n");
+
+	HOSTDATA(SCpnt->device->host)->SCint[mbo] = SCpnt;	/* This will effectively prevent someone else from
+							   screwing with this cdb. */
+
+	HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used = mbo;
+	spin_unlock_irqrestore(&aha1542_lock, flags);
+
+#ifdef DEBUG
+	printk(KERN_DEBUG "Sending command (%d %x)...", mbo, done);
+#endif
+
+	any2scsi(mb[mbo].ccbptr, SCSI_BUF_PA(&ccb[mbo]));	/* This gets trashed for some reason */
+
+	memset(&ccb[mbo], 0, sizeof(struct ccb));
+
+	ccb[mbo].cdblen = SCpnt->cmd_len;
+
+	direction = 0;
+	if (*cmd == READ_10 || *cmd == READ_6)
+		direction = 8;
+	else if (*cmd == WRITE_10 || *cmd == WRITE_6)
+		direction = 16;
+
+	memcpy(ccb[mbo].cdb, cmd, ccb[mbo].cdblen);
+
+	if (SCpnt->use_sg) {
+		struct scatterlist *sgpnt;
+		struct chain *cptr;
+#ifdef DEBUG
+		unsigned char *ptr;
+#endif
+		int i;
+		ccb[mbo].op = 2;	/* SCSI Initiator Command  w/scatter-gather */
+		SCpnt->host_scribble = (unsigned char *) kmalloc(512, GFP_KERNEL | GFP_DMA);
+		sgpnt = (struct scatterlist *) SCpnt->request_buffer;
+		cptr = (struct chain *) SCpnt->host_scribble;
+		if (cptr == NULL) {
+			/* free the claimed mailbox slot */
+			HOSTDATA(SCpnt->device->host)->SCint[mbo] = NULL;
+			return SCSI_MLQUEUE_HOST_BUSY;
+		}
+		for (i = 0; i < SCpnt->use_sg; i++) {
+			if (sgpnt[i].length == 0 || SCpnt->use_sg > 16 ||
+			    (((int) sgpnt[i].offset) & 1) || (sgpnt[i].length & 1)) {
+				unsigned char *ptr;
+				printk(KERN_CRIT "Bad segment list supplied to aha1542.c (%d, %d)\n", SCpnt->use_sg, i);
+				for (i = 0; i < SCpnt->use_sg; i++) {
+					printk(KERN_CRIT "%d: %p %d\n", i,
+					       (page_address(sgpnt[i].page) +
+						sgpnt[i].offset),
+					       sgpnt[i].length);
+				};
+				printk(KERN_CRIT "cptr %x: ", (unsigned int) cptr);
+				ptr = (unsigned char *) &cptr[i];
+				for (i = 0; i < 18; i++)
+					printk("%02x ", ptr[i]);
+				panic("Foooooooood fight!");
+			};
+			any2scsi(cptr[i].dataptr, SCSI_SG_PA(&sgpnt[i]));
+			if (SCSI_SG_PA(&sgpnt[i]) + sgpnt[i].length - 1 > ISA_DMA_THRESHOLD)
+				BAD_SG_DMA(SCpnt, sgpnt, SCpnt->use_sg, i);
+			any2scsi(cptr[i].datalen, sgpnt[i].length);
+		};
+		any2scsi(ccb[mbo].datalen, SCpnt->use_sg * sizeof(struct chain));
+		any2scsi(ccb[mbo].dataptr, SCSI_BUF_PA(cptr));
+#ifdef DEBUG
+		printk("cptr %x: ", cptr);
+		ptr = (unsigned char *) cptr;
+		for (i = 0; i < 18; i++)
+			printk("%02x ", ptr[i]);
+#endif
+	} else {
+		ccb[mbo].op = 0;	/* SCSI Initiator Command */
+		SCpnt->host_scribble = NULL;
+		any2scsi(ccb[mbo].datalen, bufflen);
+		if (buff && SCSI_BUF_PA(buff + bufflen - 1) > ISA_DMA_THRESHOLD)
+			BAD_DMA(buff, bufflen);
+		any2scsi(ccb[mbo].dataptr, SCSI_BUF_PA(buff));
+	};
+	ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7);	/*SCSI Target Id */
+	ccb[mbo].rsalen = 16;
+	ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
+	ccb[mbo].commlinkid = 0;
+
+#ifdef DEBUG
+	{
+		int i;
+		printk(KERN_DEBUG "aha1542_command: sending.. ");
+		for (i = 0; i < sizeof(ccb[mbo]) - 10; i++)
+			printk("%02x ", ((unchar *) & ccb[mbo])[i]);
+	};
+#endif
+
+	if (done) {
+		DEB(printk("aha1542_queuecommand: now waiting for interrupt ");
+		    aha1542_stat());
+		SCpnt->scsi_done = done;
+		mb[mbo].status = 1;
+		aha1542_out(SCpnt->device->host->io_port, &ahacmd, 1);	/* start scsi command */
+		DEB(aha1542_stat());
+	} else
+		printk("aha1542_queuecommand: done can't be NULL\n");
+
+	return 0;
+}
+
+/* Initialize mailboxes */
+static void setup_mailboxes(int bse, struct Scsi_Host *shpnt)
+{
+	int i;
+	struct mailbox *mb;
+	struct ccb *ccb;
+
+	unchar cmd[5] = { CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0};
+
+	mb = HOSTDATA(shpnt)->mb;
+	ccb = HOSTDATA(shpnt)->ccb;
+
+	for (i = 0; i < AHA1542_MAILBOXES; i++) {
+		mb[i].status = mb[AHA1542_MAILBOXES + i].status = 0;
+		any2scsi(mb[i].ccbptr, SCSI_BUF_PA(&ccb[i]));
+	};
+	aha1542_intr_reset(bse);	/* reset interrupts, so they don't block */
+	any2scsi((cmd + 2), SCSI_BUF_PA(mb));
+	aha1542_out(bse, cmd, 5);
+	WAIT(INTRFLAGS(bse), INTRMASK, HACC, 0);
+	while (0) {
+fail:
+		printk(KERN_ERR "aha1542_detect: failed setting up mailboxes\n");
+	}
+	aha1542_intr_reset(bse);
+}
+
+static int __init aha1542_getconfig(int base_io, unsigned char *irq_level, unsigned char *dma_chan, unsigned char *scsi_id)
+{
+	unchar inquiry_cmd[] = {CMD_RETCONF};
+	unchar inquiry_result[3];
+	int i;
+	i = inb(STATUS(base_io));
+	if (i & DF) {
+		i = inb(DATA(base_io));
+	};
+	aha1542_out(base_io, inquiry_cmd, 1);
+	aha1542_in(base_io, inquiry_result, 3);
+	WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+	while (0) {
+fail:
+		printk(KERN_ERR "aha1542_detect: query board settings\n");
+	}
+	aha1542_intr_reset(base_io);
+	switch (inquiry_result[0]) {
+	case 0x80:
+		*dma_chan = 7;
+		break;
+	case 0x40:
+		*dma_chan = 6;
+		break;
+	case 0x20:
+		*dma_chan = 5;
+		break;
+	case 0x01:
+		*dma_chan = 0;
+		break;
+	case 0:
+		/* This means that the adapter, although Adaptec 1542 compatible, doesn't use a DMA channel.
+		   Currently only aware of the BusLogic BT-445S VL-Bus adapter which needs this. */
+		*dma_chan = 0xFF;
+		break;
+	default:
+		printk(KERN_ERR "Unable to determine Adaptec DMA priority.  Disabling board\n");
+		return -1;
+	};
+	switch (inquiry_result[1]) {
+	case 0x40:
+		*irq_level = 15;
+		break;
+	case 0x20:
+		*irq_level = 14;
+		break;
+	case 0x8:
+		*irq_level = 12;
+		break;
+	case 0x4:
+		*irq_level = 11;
+		break;
+	case 0x2:
+		*irq_level = 10;
+		break;
+	case 0x1:
+		*irq_level = 9;
+		break;
+	default:
+		printk(KERN_ERR "Unable to determine Adaptec IRQ level.  Disabling board\n");
+		return -1;
+	};
+	*scsi_id = inquiry_result[2] & 7;
+	return 0;
+}
+
+/* This function should only be called for 1542C boards - we can detect
+   the special firmware settings and unlock the board */
+
+static int __init aha1542_mbenable(int base)
+{
+	static unchar mbenable_cmd[3];
+	static unchar mbenable_result[2];
+	int retval;
+
+	retval = BIOS_TRANSLATION_6432;
+
+	mbenable_cmd[0] = CMD_EXTBIOS;
+	aha1542_out(base, mbenable_cmd, 1);
+	if (aha1542_in1(base, mbenable_result, 2))
+		return retval;
+	WAITd(INTRFLAGS(base), INTRMASK, HACC, 0, 100);
+	aha1542_intr_reset(base);
+
+	if ((mbenable_result[0] & 0x08) || mbenable_result[1]) {
+		mbenable_cmd[0] = CMD_MBENABLE;
+		mbenable_cmd[1] = 0;
+		mbenable_cmd[2] = mbenable_result[1];
+
+		if ((mbenable_result[0] & 0x08) && (mbenable_result[1] & 0x03))
+			retval = BIOS_TRANSLATION_25563;
+
+		aha1542_out(base, mbenable_cmd, 3);
+		WAIT(INTRFLAGS(base), INTRMASK, HACC, 0);
+	};
+	while (0) {
+fail:
+		printk(KERN_ERR "aha1542_mbenable: Mailbox init failed\n");
+	}
+	aha1542_intr_reset(base);
+	return retval;
+}
+
+/* Query the board to find out if it is a 1542 or a 1740, or whatever. */
+static int __init aha1542_query(int base_io, int *transl)
+{
+	unchar inquiry_cmd[] = {CMD_INQUIRY};
+	unchar inquiry_result[4];
+	int i;
+	i = inb(STATUS(base_io));
+	if (i & DF) {
+		i = inb(DATA(base_io));
+	};
+	aha1542_out(base_io, inquiry_cmd, 1);
+	aha1542_in(base_io, inquiry_result, 4);
+	WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+	while (0) {
+fail:
+		printk(KERN_ERR "aha1542_detect: query card type\n");
+	}
+	aha1542_intr_reset(base_io);
+
+	*transl = BIOS_TRANSLATION_6432;	/* Default case */
+
+	/* For an AHA1740 series board, we ignore the board since there is a
+	   hardware bug which can lead to wrong blocks being returned if the board
+	   is operating in the 1542 emulation mode.  Since there is an extended mode
+	   driver, we simply ignore the board and let the 1740 driver pick it up.
+	 */
+
+	if (inquiry_result[0] == 0x43) {
+		printk(KERN_INFO "aha1542.c: Emulation mode not supported for AHA 174N hardware.\n");
+		return 1;
+	};
+
+	/* Always call this - boards that do not support extended bios translation
+	   will ignore the command, and we will set the proper default */
+
+	*transl = aha1542_mbenable(base_io);
+
+	return 0;
+}
+
+#ifndef MODULE
+static char *setup_str[MAXBOARDS] __initdata;
+static int setup_idx = 0;
+
+static void __init aha1542_setup(char *str, int *ints)
+{
+	const char *ahausage = "aha1542: usage: aha1542=<PORTBASE>[,<BUSON>,<BUSOFF>[,<DMASPEED>]]\n";
+	int setup_portbase;
+
+	if (setup_idx >= MAXBOARDS) {
+		printk(KERN_ERR "aha1542: aha1542_setup called too many times! Bad LILO params ?\n");
+		printk(KERN_ERR "   Entryline 1: %s\n", setup_str[0]);
+		printk(KERN_ERR "   Entryline 2: %s\n", setup_str[1]);
+		printk(KERN_ERR "   This line:   %s\n", str);
+		return;
+	}
+	if (ints[0] < 1 || ints[0] > 4) {
+		printk(KERN_ERR "aha1542: %s\n", str);
+		printk(ahausage);
+		printk(KERN_ERR "aha1542: Wrong parameters may cause system malfunction.. We try anyway..\n");
+	}
+	setup_called[setup_idx] = ints[0];
+	setup_str[setup_idx] = str;
+
+	setup_portbase = ints[0] >= 1 ? ints[1] : 0;	/* Preserve the default value.. */
+	setup_buson[setup_idx] = ints[0] >= 2 ? ints[2] : 7;
+	setup_busoff[setup_idx] = ints[0] >= 3 ? ints[3] : 5;
+	if (ints[0] >= 4) 
+	{
+		int atbt = -1;
+		switch (ints[4]) {
+		case 5:
+			atbt = 0x00;
+			break;
+		case 6:
+			atbt = 0x04;
+			break;
+		case 7:
+			atbt = 0x01;
+			break;
+		case 8:
+			atbt = 0x02;
+			break;
+		case 10:
+			atbt = 0x03;
+			break;
+		default:
+			printk(KERN_ERR "aha1542: %s\n", str);
+			printk(ahausage);
+			printk(KERN_ERR "aha1542: Valid values for DMASPEED are 5-8, 10 MB/s.  Using jumper defaults.\n");
+			break;
+		}
+		setup_dmaspeed[setup_idx] = atbt;
+	}
+	if (setup_portbase != 0)
+		bases[setup_idx] = setup_portbase;
+
+	++setup_idx;
+}
+
+static int __init do_setup(char *str)
+{
+	int ints[5];
+
+	int count=setup_idx;
+
+	get_options(str, sizeof(ints)/sizeof(int), ints);
+	aha1542_setup(str,ints);
+
+	return count<setup_idx;
+}
+
+__setup("aha1542=",do_setup);
+#endif
+
+/* return non-zero on detection */
+static int __init aha1542_detect(Scsi_Host_Template * tpnt)
+{
+	unsigned char dma_chan;
+	unsigned char irq_level;
+	unsigned char scsi_id;
+	unsigned long flags;
+	unsigned int base_io;
+	int trans;
+	struct Scsi_Host *shpnt = NULL;
+	int count = 0;
+	int indx;
+
+	DEB(printk("aha1542_detect: \n"));
+
+	tpnt->proc_name = "aha1542";
+
+#ifdef MODULE
+	bases[0] = aha1542[0];
+	setup_buson[0] = aha1542[1];
+	setup_busoff[0] = aha1542[2];
+	{
+		int atbt = -1;
+		switch (aha1542[3]) {
+		case 5:
+			atbt = 0x00;
+			break;
+		case 6:
+			atbt = 0x04;
+			break;
+		case 7:
+			atbt = 0x01;
+			break;
+		case 8:
+			atbt = 0x02;
+			break;
+		case 10:
+			atbt = 0x03;
+			break;
+		};
+		setup_dmaspeed[0] = atbt;
+	}
+#endif
+
+	/*
+	 *	Find MicroChannel cards (AHA1640)
+	 */
+#ifdef CONFIG_MCA_LEGACY
+	if(MCA_bus) {
+		int slot = 0;
+		int pos = 0;
+
+		for (indx = 0; (slot !=  MCA_NOTFOUND) && 
+			     (indx < sizeof(bases)/sizeof(bases[0])); indx++) {
+
+			if (bases[indx])
+				continue;
+
+			/* Detect only AHA-1640 cards -- MCA ID 0F1F */
+			slot = mca_find_unused_adapter(0x0f1f, slot);
+			if (slot == MCA_NOTFOUND)
+				break;
+
+			
+			/* Found one */
+			pos = mca_read_stored_pos(slot, 3);
+			
+			/* Decode address */
+			if (pos & 0x80) {
+				if (pos & 0x02) {
+					if (pos & 0x01)
+						bases[indx] = 0x334;
+					else
+						bases[indx] = 0x234;
+				} else {
+					if (pos & 0x01)
+						bases[indx] = 0x134;
+				}
+			} else {
+				if (pos & 0x02) {
+					if (pos & 0x01)
+						bases[indx] = 0x330;
+					else
+						bases[indx] = 0x230;
+				} else {
+					if (pos & 0x01)
+						bases[indx] = 0x130;
+				}
+			}
+
+			/* No need to decode IRQ and Arb level -- those are
+			 * read off the card later.
+			 */
+			printk(KERN_INFO "Found an AHA-1640 in MCA slot %d, I/O 0x%04x\n", slot, bases[indx]);
+
+			mca_set_adapter_name(slot, "Adapter AHA-1640");
+			mca_set_adapter_procfn(slot, NULL, NULL);
+			mca_mark_as_used(slot);
+			
+			/* Go on */
+			slot++;
+		}
+		
+	}
+#endif
+
+	/*
+	 *	Hunt for ISA Plug'n'Pray Adaptecs (AHA1535)
+	 */
+	 
+	if(isapnp)
+	{
+		struct pnp_dev *pdev = NULL;
+		for(indx = 0; indx <sizeof(bases)/sizeof(bases[0]);indx++)
+		{
+			if(bases[indx])
+				continue;
+			pdev = pnp_find_dev(NULL, ISAPNP_VENDOR('A', 'D', 'P'), 
+				ISAPNP_FUNCTION(0x1542), pdev);
+			if(pdev==NULL)
+				break;
+			/*
+			 *	Activate the PnP card
+			 */
+			 
+			if(pnp_device_attach(pdev)<0)
+				continue;
+			
+			if(pnp_activate_dev(pdev)<0) {
+				pnp_device_detach(pdev);
+				continue;
+			}
+			
+			if(!pnp_port_valid(pdev, 0)) {
+				pnp_device_detach(pdev);
+				continue;
+			}
+				
+			bases[indx] = pnp_port_start(pdev, 0);
+			
+			/* The card can be queried for its DMA, we have 
+			   the DMA set up that is enough */
+			   
+			printk(KERN_INFO "ISAPnP found an AHA1535 at I/O 0x%03X\n", bases[indx]);
+		}
+	}
+	for (indx = 0; indx < sizeof(bases) / sizeof(bases[0]); indx++)
+		if (bases[indx] != 0 && request_region(bases[indx], 4, "aha1542")) {
+			shpnt = scsi_register(tpnt,
+					sizeof(struct aha1542_hostdata));
+
+			if(shpnt==NULL) {
+				release_region(bases[indx], 4);
+				continue;
+			}
+			/* For now we do this - until kmalloc is more intelligent
+			   we are resigned to stupid hacks like this */
+			if (SCSI_BUF_PA(shpnt) >= ISA_DMA_THRESHOLD) {
+				printk(KERN_ERR "Invalid address for shpnt with 1542.\n");
+				goto unregister;
+			}
+			if (!aha1542_test_port(bases[indx], shpnt))
+				goto unregister;
+
+
+			base_io = bases[indx];
+
+			/* Set the Bus on/off-times as not to ruin floppy performance */
+			{
+				unchar oncmd[] = {CMD_BUSON_TIME, 7};
+				unchar offcmd[] = {CMD_BUSOFF_TIME, 5};
+
+				if (setup_called[indx]) {
+					oncmd[1] = setup_buson[indx];
+					offcmd[1] = setup_busoff[indx];
+				}
+				aha1542_intr_reset(base_io);
+				aha1542_out(base_io, oncmd, 2);
+				WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+				aha1542_intr_reset(base_io);
+				aha1542_out(base_io, offcmd, 2);
+				WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+				if (setup_dmaspeed[indx] >= 0) {
+					unchar dmacmd[] = {CMD_DMASPEED, 0};
+					dmacmd[1] = setup_dmaspeed[indx];
+					aha1542_intr_reset(base_io);
+					aha1542_out(base_io, dmacmd, 2);
+					WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+				}
+				while (0) {
+fail:
+					printk(KERN_ERR "aha1542_detect: setting bus on/off-time failed\n");
+				}
+				aha1542_intr_reset(base_io);
+			}
+			if (aha1542_query(base_io, &trans))
+				goto unregister;
+
+			if (aha1542_getconfig(base_io, &irq_level, &dma_chan, &scsi_id) == -1)
+				goto unregister;
+
+			printk(KERN_INFO "Configuring Adaptec (SCSI-ID %d) at IO:%x, IRQ %d", scsi_id, base_io, irq_level);
+			if (dma_chan != 0xFF)
+				printk(", DMA priority %d", dma_chan);
+			printk("\n");
+
+			DEB(aha1542_stat());
+			setup_mailboxes(base_io, shpnt);
+
+			DEB(aha1542_stat());
+
+			DEB(printk("aha1542_detect: enable interrupt channel %d\n", irq_level));
+			spin_lock_irqsave(&aha1542_lock, flags);
+			if (request_irq(irq_level, do_aha1542_intr_handle, 0, "aha1542", NULL)) {
+				printk(KERN_ERR "Unable to allocate IRQ for adaptec controller.\n");
+				spin_unlock_irqrestore(&aha1542_lock, flags);
+				goto unregister;
+			}
+			if (dma_chan != 0xFF) {
+				if (request_dma(dma_chan, "aha1542")) {
+					printk(KERN_ERR "Unable to allocate DMA channel for Adaptec.\n");
+					free_irq(irq_level, NULL);
+					spin_unlock_irqrestore(&aha1542_lock, flags);
+					goto unregister;
+				}
+				if (dma_chan == 0 || dma_chan >= 5) {
+					set_dma_mode(dma_chan, DMA_MODE_CASCADE);
+					enable_dma(dma_chan);
+				}
+			}
+			aha_host[irq_level - 9] = shpnt;
+			shpnt->this_id = scsi_id;
+			shpnt->unique_id = base_io;
+			shpnt->io_port = base_io;
+			shpnt->n_io_port = 4;	/* Number of bytes of I/O space used */
+			shpnt->dma_channel = dma_chan;
+			shpnt->irq = irq_level;
+			HOSTDATA(shpnt)->bios_translation = trans;
+			if (trans == BIOS_TRANSLATION_25563)
+				printk(KERN_INFO "aha1542.c: Using extended bios translation\n");
+			HOSTDATA(shpnt)->aha1542_last_mbi_used = (2 * AHA1542_MAILBOXES - 1);
+			HOSTDATA(shpnt)->aha1542_last_mbo_used = (AHA1542_MAILBOXES - 1);
+			memset(HOSTDATA(shpnt)->SCint, 0, sizeof(HOSTDATA(shpnt)->SCint));
+			spin_unlock_irqrestore(&aha1542_lock, flags);
+#if 0
+			DEB(printk(" *** READ CAPACITY ***\n"));
+
+			{
+				unchar buf[8];
+				static unchar cmd[] = { READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+				int i;
+
+				for (i = 0; i < sizeof(buf); ++i)
+					buf[i] = 0x87;
+				for (i = 0; i < 2; ++i)
+					if (!aha1542_command(i, cmd, buf, sizeof(buf))) {
+						printk(KERN_DEBUG "aha_detect: LU %d sector_size %d device_size %d\n",
+						       i, xscsi2int(buf + 4), xscsi2int(buf));
+					}
+			}
+
+			DEB(printk(" *** NOW RUNNING MY OWN TEST *** \n"));
+
+			for (i = 0; i < 4; ++i) {
+				unsigned char cmd[10];
+				static buffer[512];
+
+				cmd[0] = READ_10;
+				cmd[1] = 0;
+				xany2scsi(cmd + 2, i);
+				cmd[6] = 0;
+				cmd[7] = 0;
+				cmd[8] = 1;
+				cmd[9] = 0;
+				aha1542_command(0, cmd, buffer, 512);
+			}
+#endif
+			count++;
+			continue;
+unregister:
+			release_region(bases[indx], 4);
+			scsi_unregister(shpnt);
+			continue;
+
+		};
+
+	return count;
+}
+
+static int aha1542_release(struct Scsi_Host *shost)
+{
+	if (shost->irq)
+		free_irq(shost->irq, NULL);
+	if (shost->dma_channel != 0xff)
+		free_dma(shost->dma_channel);
+	if (shost->io_port && shost->n_io_port)
+		release_region(shost->io_port, shost->n_io_port);
+	scsi_unregister(shost);
+	return 0;
+}
+
+static int aha1542_restart(struct Scsi_Host *shost)
+{
+	int i;
+	int count = 0;
+#if 0
+	unchar ahacmd = CMD_START_SCSI;
+#endif
+
+	for (i = 0; i < AHA1542_MAILBOXES; i++)
+		if (HOSTDATA(shost)->SCint[i] &&
+		    !(HOSTDATA(shost)->SCint[i]->device->soft_reset)) {
+#if 0
+			HOSTDATA(shost)->mb[i].status = 1;	/* Indicate ready to restart... */
+#endif
+			count++;
+		}
+	printk(KERN_DEBUG "Potential to restart %d stalled commands...\n", count);
+#if 0
+	/* start scsi command */
+	if (count)
+		aha1542_out(shost->io_port, &ahacmd, 1);
+#endif
+	return 0;
+}
+
+static int aha1542_abort(Scsi_Cmnd * SCpnt)
+{
+
+	/*
+	 * The abort command does not leave the device in a clean state where
+	 *  it is available to be used again.  Until this gets worked out, we
+	 * will leave it commented out.  
+	 */
+
+	printk(KERN_ERR "aha1542.c: Unable to abort command for target %d\n",
+	       SCpnt->device->id);
+	return FAILED;
+}
+
+/*
+ * This is a device reset.  This is handled by sending a special command
+ * to the device.
+ */
+static int aha1542_dev_reset(Scsi_Cmnd * SCpnt)
+{
+	unsigned long flags;
+	struct mailbox *mb;
+	unchar target = SCpnt->device->id;
+	unchar lun = SCpnt->device->lun;
+	int mbo;
+	struct ccb *ccb;
+	unchar ahacmd = CMD_START_SCSI;
+
+	ccb = HOSTDATA(SCpnt->device->host)->ccb;
+	mb = HOSTDATA(SCpnt->device->host)->mb;
+
+	spin_lock_irqsave(&aha1542_lock, flags);
+	mbo = HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used + 1;
+	if (mbo >= AHA1542_MAILBOXES)
+		mbo = 0;
+
+	do {
+		if (mb[mbo].status == 0 && HOSTDATA(SCpnt->device->host)->SCint[mbo] == NULL)
+			break;
+		mbo++;
+		if (mbo >= AHA1542_MAILBOXES)
+			mbo = 0;
+	} while (mbo != HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used);
+
+	if (mb[mbo].status || HOSTDATA(SCpnt->device->host)->SCint[mbo])
+		panic("Unable to find empty mailbox for aha1542.\n");
+
+	HOSTDATA(SCpnt->device->host)->SCint[mbo] = SCpnt;	/* This will effectively
+							   prevent someone else from
+							   screwing with this cdb. */
+
+	HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used = mbo;
+	spin_unlock_irqrestore(&aha1542_lock, flags);
+
+	any2scsi(mb[mbo].ccbptr, SCSI_BUF_PA(&ccb[mbo]));	/* This gets trashed for some reason */
+
+	memset(&ccb[mbo], 0, sizeof(struct ccb));
+
+	ccb[mbo].op = 0x81;	/* BUS DEVICE RESET */
+
+	ccb[mbo].idlun = (target & 7) << 5 | (lun & 7);		/*SCSI Target Id */
+
+	ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
+	ccb[mbo].commlinkid = 0;
+
+	/* 
+	 * Now tell the 1542 to flush all pending commands for this 
+	 * target 
+	 */
+	aha1542_out(SCpnt->device->host->io_port, &ahacmd, 1);
+
+	printk(KERN_WARNING "aha1542.c: Trying device reset for target %d\n", SCpnt->device->id);
+
+	return SUCCESS;
+
+
+#ifdef ERIC_neverdef
+	/* 
+	 * With the 1542 we apparently never get an interrupt to
+	 * acknowledge a device reset being sent.  Then again, Leonard
+	 * says we are doing this wrong in the first place...
+	 *
+	 * Take a wait and see attitude.  If we get spurious interrupts,
+	 * then the device reset is doing something sane and useful, and
+	 * we will wait for the interrupt to post completion.
+	 */
+	printk(KERN_WARNING "Sent BUS DEVICE RESET to target %d\n", SCpnt->target);
+
+	/*
+	 * Free the command block for all commands running on this 
+	 * target... 
+	 */
+	for (i = 0; i < AHA1542_MAILBOXES; i++) {
+		if (HOSTDATA(SCpnt->host)->SCint[i] &&
+		    HOSTDATA(SCpnt->host)->SCint[i]->target == SCpnt->target) {
+			Scsi_Cmnd *SCtmp;
+			SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+			if (SCtmp->host_scribble) {
+				kfree(SCtmp->host_scribble);
+				SCtmp->host_scribble = NULL;
+			}
+			HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+			HOSTDATA(SCpnt->host)->mb[i].status = 0;
+		}
+	}
+	return SUCCESS;
+
+	return FAILED;
+#endif				/* ERIC_neverdef */
+}
+
+static int aha1542_bus_reset(Scsi_Cmnd * SCpnt)
+{
+	int i;
+
+	/* 
+	 * This does a scsi reset for all devices on the bus.
+	 * In principle, we could also reset the 1542 - should
+	 * we do this?  Try this first, and we can add that later
+	 * if it turns out to be useful.
+	 */
+	outb(SCRST, CONTROL(SCpnt->device->host->io_port));
+
+	/*
+	 * Wait for the thing to settle down a bit.  Unfortunately
+	 * this is going to basically lock up the machine while we
+	 * wait for this to complete.  To be 100% correct, we need to
+	 * check for timeout, and if we are doing something like this
+	 * we are pretty desperate anyways.
+	 */
+	spin_unlock_irq(SCpnt->device->host->host_lock);
+	ssleep(4);
+	spin_lock_irq(SCpnt->device->host->host_lock);
+
+	WAIT(STATUS(SCpnt->device->host->io_port),
+	     STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF);
+
+	/*
+	 * Now try to pick up the pieces.  For all pending commands,
+	 * free any internal data structures, and basically clear things
+	 * out.  We do not try and restart any commands or anything - 
+	 * the strategy handler takes care of that crap.
+	 */
+	printk(KERN_WARNING "Sent BUS RESET to scsi host %d\n", SCpnt->device->host->host_no);
+
+	for (i = 0; i < AHA1542_MAILBOXES; i++) {
+		if (HOSTDATA(SCpnt->device->host)->SCint[i] != NULL) {
+			Scsi_Cmnd *SCtmp;
+			SCtmp = HOSTDATA(SCpnt->device->host)->SCint[i];
+
+
+			if (SCtmp->device->soft_reset) {
+				/*
+				 * If this device implements the soft reset option,
+				 * then it is still holding onto the command, and
+				 * may yet complete it.  In this case, we don't
+				 * flush the data.
+				 */
+				continue;
+			}
+			if (SCtmp->host_scribble) {
+				kfree(SCtmp->host_scribble);
+				SCtmp->host_scribble = NULL;
+			}
+			HOSTDATA(SCpnt->device->host)->SCint[i] = NULL;
+			HOSTDATA(SCpnt->device->host)->mb[i].status = 0;
+		}
+	}
+
+	return SUCCESS;
+
+fail:
+	return FAILED;
+}
+
+static int aha1542_host_reset(Scsi_Cmnd * SCpnt)
+{
+	int i;
+
+	/* 
+	 * This does a scsi reset for all devices on the bus.
+	 * In principle, we could also reset the 1542 - should
+	 * we do this?  Try this first, and we can add that later
+	 * if it turns out to be useful.
+	 */
+	outb(HRST | SCRST, CONTROL(SCpnt->device->host->io_port));
+
+	/*
+	 * Wait for the thing to settle down a bit.  Unfortunately
+	 * this is going to basically lock up the machine while we
+	 * wait for this to complete.  To be 100% correct, we need to
+	 * check for timeout, and if we are doing something like this
+	 * we are pretty desperate anyways.
+	 */
+	spin_unlock_irq(SCpnt->device->host->host_lock);
+	ssleep(4);
+	spin_lock_irq(SCpnt->device->host->host_lock);
+
+	WAIT(STATUS(SCpnt->device->host->io_port),
+	     STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF);
+
+	/*
+	 * We need to do this too before the 1542 can interact with
+	 * us again.
+	 */
+	setup_mailboxes(SCpnt->device->host->io_port, SCpnt->device->host);
+
+	/*
+	 * Now try to pick up the pieces.  For all pending commands,
+	 * free any internal data structures, and basically clear things
+	 * out.  We do not try and restart any commands or anything - 
+	 * the strategy handler takes care of that crap.
+	 */
+	printk(KERN_WARNING "Sent BUS RESET to scsi host %d\n", SCpnt->device->host->host_no);
+
+	for (i = 0; i < AHA1542_MAILBOXES; i++) {
+		if (HOSTDATA(SCpnt->device->host)->SCint[i] != NULL) {
+			Scsi_Cmnd *SCtmp;
+			SCtmp = HOSTDATA(SCpnt->device->host)->SCint[i];
+
+			if (SCtmp->device->soft_reset) {
+				/*
+				 * If this device implements the soft reset option,
+				 * then it is still holding onto the command, and
+				 * may yet complete it.  In this case, we don't
+				 * flush the data.
+				 */
+				continue;
+			}
+			if (SCtmp->host_scribble) {
+				kfree(SCtmp->host_scribble);
+				SCtmp->host_scribble = NULL;
+			}
+			HOSTDATA(SCpnt->device->host)->SCint[i] = NULL;
+			HOSTDATA(SCpnt->device->host)->mb[i].status = 0;
+		}
+	}
+
+	return SUCCESS;
+
+fail:
+	return FAILED;
+}
+
+#if 0
+/*
+ * These are the old error handling routines.  They are only temporarily
+ * here while we play with the new error handling code.
+ */
+static int aha1542_old_abort(Scsi_Cmnd * SCpnt)
+{
+#if 0
+	unchar ahacmd = CMD_START_SCSI;
+	unsigned long flags;
+	struct mailbox *mb;
+	int mbi, mbo, i;
+
+	printk(KERN_DEBUG "In aha1542_abort: %x %x\n",
+	       inb(STATUS(SCpnt->host->io_port)),
+	       inb(INTRFLAGS(SCpnt->host->io_port)));
+
+	spin_lock_irqsave(&aha1542_lock, flags);
+	mb = HOSTDATA(SCpnt->host)->mb;
+	mbi = HOSTDATA(SCpnt->host)->aha1542_last_mbi_used + 1;
+	if (mbi >= 2 * AHA1542_MAILBOXES)
+		mbi = AHA1542_MAILBOXES;
+
+	do {
+		if (mb[mbi].status != 0)
+			break;
+		mbi++;
+		if (mbi >= 2 * AHA1542_MAILBOXES)
+			mbi = AHA1542_MAILBOXES;
+	} while (mbi != HOSTDATA(SCpnt->host)->aha1542_last_mbi_used);
+	spin_unlock_irqrestore(&aha1542_lock, flags);
+
+	if (mb[mbi].status) {
+		printk(KERN_ERR "Lost interrupt discovered on irq %d - attempting to recover\n",
+		       SCpnt->host->irq);
+		aha1542_intr_handle(SCpnt->host, NULL);
+		return 0;
+	}
+	/* OK, no lost interrupt.  Try looking to see how many pending commands
+	   we think we have. */
+
+	for (i = 0; i < AHA1542_MAILBOXES; i++)
+		if (HOSTDATA(SCpnt->host)->SCint[i]) {
+			if (HOSTDATA(SCpnt->host)->SCint[i] == SCpnt) {
+				printk(KERN_ERR "Timed out command pending for %s\n",
+				       SCpnt->request->rq_disk ?
+				       SCpnt->request->rq_disk->disk_name : "?"
+				       );
+				if (HOSTDATA(SCpnt->host)->mb[i].status) {
+					printk(KERN_ERR "OGMB still full - restarting\n");
+					aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
+				};
+			} else
+				printk(KERN_ERR "Other pending command %s\n",
+				       SCpnt->request->rq_disk ?
+				       SCpnt->request->rq_disk->disk_name : "?"
+				       );
+		}
+#endif
+
+	DEB(printk("aha1542_abort\n"));
+#if 0
+	spin_lock_irqsave(&aha1542_lock, flags);
+	for (mbo = 0; mbo < AHA1542_MAILBOXES; mbo++) {
+		if (SCpnt == HOSTDATA(SCpnt->host)->SCint[mbo]) {
+			mb[mbo].status = 2;	/* Abort command */
+			aha1542_out(SCpnt->host->io_port, &ahacmd, 1);	/* start scsi command */
+			spin_unlock_irqrestore(&aha1542_lock, flags);
+			break;
+		}
+	}
+	if (AHA1542_MAILBOXES == mbo)
+		spin_unlock_irqrestore(&aha1542_lock, flags);
+#endif
+	return SCSI_ABORT_SNOOZE;
+}
+
+/* We do not implement a reset function here, but the upper level code
+   assumes that it will get some kind of response for the command in
+   SCpnt.  We must oblige, or the command will hang the scsi system.
+   For a first go, we assume that the 1542 notifies us with all of the
+   pending commands (it does implement soft reset, after all). */
+
+static int aha1542_old_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
+{
+	unchar ahacmd = CMD_START_SCSI;
+	int i;
+
+	/*
+	 * See if a bus reset was suggested.
+	 */
+	if (reset_flags & SCSI_RESET_SUGGEST_BUS_RESET) {
+		/* 
+		 * This does a scsi reset for all devices on the bus.
+		 * In principle, we could also reset the 1542 - should
+		 * we do this?  Try this first, and we can add that later
+		 * if it turns out to be useful.
+		 */
+		outb(HRST | SCRST, CONTROL(SCpnt->host->io_port));
+
+		/*
+		 * Wait for the thing to settle down a bit.  Unfortunately
+		 * this is going to basically lock up the machine while we
+		 * wait for this to complete.  To be 100% correct, we need to
+		 * check for timeout, and if we are doing something like this
+		 * we are pretty desperate anyways.
+		 */
+		WAIT(STATUS(SCpnt->host->io_port),
+		STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF);
+
+		/*
+		 * We need to do this too before the 1542 can interact with
+		 * us again.
+		 */
+		setup_mailboxes(SCpnt->host->io_port, SCpnt->host);
+
+		/*
+		 * Now try to pick up the pieces.  Restart all commands
+		 * that are currently active on the bus, and reset all of
+		 * the datastructures.  We have some time to kill while
+		 * things settle down, so print a nice message.
+		 */
+		printk(KERN_WARNING "Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no);
+
+		for (i = 0; i < AHA1542_MAILBOXES; i++)
+			if (HOSTDATA(SCpnt->host)->SCint[i] != NULL) {
+				Scsi_Cmnd *SCtmp;
+				SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+				SCtmp->result = DID_RESET << 16;
+				if (SCtmp->host_scribble) {
+					kfree(SCtmp->host_scribble);
+					SCtmp->host_scribble = NULL;
+				}
+				printk(KERN_WARNING "Sending DID_RESET for target %d\n", SCpnt->target);
+				SCtmp->scsi_done(SCpnt);
+
+				HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+				HOSTDATA(SCpnt->host)->mb[i].status = 0;
+			}
+		/*
+		 * Now tell the mid-level code what we did here.  Since
+		 * we have restarted all of the outstanding commands,
+		 * then report SUCCESS.
+		 */
+		return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET);
+fail:
+		printk(KERN_CRIT "aha1542.c: Unable to perform hard reset.\n");
+		printk(KERN_CRIT "Power cycle machine to reset\n");
+		return (SCSI_RESET_ERROR | SCSI_RESET_BUS_RESET);
+
+
+	} else {
+		/* This does a selective reset of just the one device */
+		/* First locate the ccb for this command */
+		for (i = 0; i < AHA1542_MAILBOXES; i++)
+			if (HOSTDATA(SCpnt->host)->SCint[i] == SCpnt) {
+				HOSTDATA(SCpnt->host)->ccb[i].op = 0x81;	/* BUS DEVICE RESET */
+				/* Now tell the 1542 to flush all pending commands for this target */
+				aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
+
+				/* Here is the tricky part.  What to do next.  Do we get an interrupt
+				   for the commands that we aborted with the specified target, or
+				   do we generate this on our own?  Try it without first and see
+				   what happens */
+				printk(KERN_WARNING "Sent BUS DEVICE RESET to target %d\n", SCpnt->target);
+
+				/* If the first does not work, then try the second.  I think the
+				   first option is more likely to be correct. Free the command
+				   block for all commands running on this target... */
+				for (i = 0; i < AHA1542_MAILBOXES; i++)
+					if (HOSTDATA(SCpnt->host)->SCint[i] &&
+					    HOSTDATA(SCpnt->host)->SCint[i]->target == SCpnt->target) {
+						Scsi_Cmnd *SCtmp;
+						SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+						SCtmp->result = DID_RESET << 16;
+						if (SCtmp->host_scribble) {
+							kfree(SCtmp->host_scribble);
+							SCtmp->host_scribble = NULL;
+						}
+						printk(KERN_WARNING "Sending DID_RESET for target %d\n", SCpnt->target);
+						SCtmp->scsi_done(SCpnt);
+
+						HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+						HOSTDATA(SCpnt->host)->mb[i].status = 0;
+					}
+				return SCSI_RESET_SUCCESS;
+			}
+	}
+	/* No active command at this time, so this means that each time we got
+	   some kind of response the last time through.  Tell the mid-level code
+	   to request sense information in order to decide what to do next. */
+	return SCSI_RESET_PUNT;
+}
+#endif    /* end of big comment block around old_abort + old_reset */
+
+static int aha1542_biosparam(struct scsi_device *sdev,
+		struct block_device *bdev, sector_t capacity, int *ip)
+{
+	int translation_algorithm;
+	int size = capacity;
+
+	translation_algorithm = HOSTDATA(sdev->host)->bios_translation;
+
+	if ((size >> 11) > 1024 && translation_algorithm == BIOS_TRANSLATION_25563) {
+		/* Please verify that this is the same as what DOS returns */
+		ip[0] = 255;
+		ip[1] = 63;
+		ip[2] = size / 255 / 63;
+	} else {
+		ip[0] = 64;
+		ip[1] = 32;
+		ip[2] = size >> 11;
+	}
+
+	return 0;
+}
+MODULE_LICENSE("GPL");
+
+
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "aha1542",
+	.name			= "Adaptec 1542",
+	.detect			= aha1542_detect,
+	.release		= aha1542_release,
+	.queuecommand		= aha1542_queuecommand,
+	.eh_abort_handler	= aha1542_abort,
+	.eh_device_reset_handler= aha1542_dev_reset,
+	.eh_bus_reset_handler	= aha1542_bus_reset,
+	.eh_host_reset_handler	= aha1542_host_reset,
+	.bios_param		= aha1542_biosparam,
+	.can_queue		= AHA1542_MAILBOXES, 
+	.this_id		= 7,
+	.sg_tablesize		= AHA1542_SCATTER,
+	.cmd_per_lun		= AHA1542_CMDLUN,
+	.unchecked_isa_dma	= 1, 
+	.use_clustering		= ENABLE_CLUSTERING,
+};
+#include "scsi_module.c"