xref: /linux/drivers/scsi/aha1542.c (revision 88f06b76e462119cb694c3ff13d7d343c49d2569)
11d084d20SOndrej Zary /*
21d084d20SOndrej Zary  *  Driver for Adaptec AHA-1542 SCSI host adapters
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *  Copyright (C) 1992  Tommy Thorn
51da177e4SLinus Torvalds  *  Copyright (C) 1993, 1994, 1995 Eric Youngdale
61d084d20SOndrej Zary  *  Copyright (C) 2015 Ondrej Zary
71da177e4SLinus Torvalds  */
81da177e4SLinus Torvalds 
91da177e4SLinus Torvalds #include <linux/module.h>
101da177e4SLinus Torvalds #include <linux/interrupt.h>
111da177e4SLinus Torvalds #include <linux/kernel.h>
121da177e4SLinus Torvalds #include <linux/types.h>
131da177e4SLinus Torvalds #include <linux/string.h>
141da177e4SLinus Torvalds #include <linux/delay.h>
151da177e4SLinus Torvalds #include <linux/init.h>
161da177e4SLinus Torvalds #include <linux/spinlock.h>
17643a7c43SOndrej Zary #include <linux/isa.h>
18643a7c43SOndrej Zary #include <linux/pnp.h>
195a0e3ad6STejun Heo #include <linux/slab.h>
20954a9fd7SOndrej Zary #include <linux/io.h>
211da177e4SLinus Torvalds #include <asm/dma.h>
22954a9fd7SOndrej Zary #include <scsi/scsi_cmnd.h>
23954a9fd7SOndrej Zary #include <scsi/scsi_device.h>
241da177e4SLinus Torvalds #include <scsi/scsi_host.h>
251da177e4SLinus Torvalds #include "aha1542.h"
261da177e4SLinus Torvalds 
27f71429abSOndrej Zary #define MAXBOARDS 4
281da177e4SLinus Torvalds 
29f71429abSOndrej Zary static bool isapnp = 1;
301da177e4SLinus Torvalds module_param(isapnp, bool, 0);
31f71429abSOndrej Zary MODULE_PARM_DESC(isapnp, "enable PnP support (default=1)");
32f71429abSOndrej Zary 
33f71429abSOndrej Zary static int io[MAXBOARDS] = { 0x330, 0x334, 0, 0 };
34*88f06b76SDavid Howells module_param_hw_array(io, int, ioport, NULL, 0);
35f71429abSOndrej Zary MODULE_PARM_DESC(io, "base IO address of controller (0x130,0x134,0x230,0x234,0x330,0x334, default=0x330,0x334)");
36f71429abSOndrej Zary 
37f71429abSOndrej Zary /* time AHA spends on the AT-bus during data transfer */
38f71429abSOndrej Zary static int bus_on[MAXBOARDS] = { -1, -1, -1, -1 }; /* power-on default: 11us */
39f71429abSOndrej Zary module_param_array(bus_on, int, NULL, 0);
40f71429abSOndrej Zary MODULE_PARM_DESC(bus_on, "bus on time [us] (2-15, default=-1 [HW default: 11])");
41f71429abSOndrej Zary 
42f71429abSOndrej Zary /* time AHA spends off the bus (not to monopolize it) during data transfer  */
43f71429abSOndrej Zary static int bus_off[MAXBOARDS] = { -1, -1, -1, -1 }; /* power-on default: 4us */
44f71429abSOndrej Zary module_param_array(bus_off, int, NULL, 0);
45f71429abSOndrej Zary MODULE_PARM_DESC(bus_off, "bus off time [us] (1-64, default=-1 [HW default: 4])");
46f71429abSOndrej Zary 
47f71429abSOndrej Zary /* default is jumper selected (J1 on 1542A), factory default = 5 MB/s */
48f71429abSOndrej Zary static int dma_speed[MAXBOARDS] = { -1, -1, -1, -1 };
49f71429abSOndrej Zary module_param_array(dma_speed, int, NULL, 0);
50f71429abSOndrej Zary MODULE_PARM_DESC(dma_speed, "DMA speed [MB/s] (5,6,7,8,10, default=-1 [by jumper])");
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds #define BIOS_TRANSLATION_6432 1	/* Default case these days */
531da177e4SLinus Torvalds #define BIOS_TRANSLATION_25563 2	/* Big disk case */
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds struct aha1542_hostdata {
561da177e4SLinus Torvalds 	/* This will effectively start both of them at the first mailbox */
571da177e4SLinus Torvalds 	int bios_translation;	/* Mapping bios uses - for compatibility */
581da177e4SLinus Torvalds 	int aha1542_last_mbi_used;
591da177e4SLinus Torvalds 	int aha1542_last_mbo_used;
6055b28f9fSOndrej Zary 	struct scsi_cmnd *int_cmds[AHA1542_MAILBOXES];
611da177e4SLinus Torvalds 	struct mailbox mb[2 * AHA1542_MAILBOXES];
621da177e4SLinus Torvalds 	struct ccb ccb[AHA1542_MAILBOXES];
631da177e4SLinus Torvalds };
641da177e4SLinus Torvalds 
65f1bbef63SOndrej Zary static inline void aha1542_intr_reset(u16 base)
66f1bbef63SOndrej Zary {
67f1bbef63SOndrej Zary 	outb(IRST, CONTROL(base));
68f1bbef63SOndrej Zary }
691da177e4SLinus Torvalds 
702093bfa1SOndrej Zary static inline bool wait_mask(u16 port, u8 mask, u8 allof, u8 noneof, int timeout)
712093bfa1SOndrej Zary {
722093bfa1SOndrej Zary 	bool delayed = true;
732093bfa1SOndrej Zary 
742093bfa1SOndrej Zary 	if (timeout == 0) {
752093bfa1SOndrej Zary 		timeout = 3000000;
762093bfa1SOndrej Zary 		delayed = false;
771da177e4SLinus Torvalds 	}
781da177e4SLinus Torvalds 
792093bfa1SOndrej Zary 	while (1) {
802093bfa1SOndrej Zary 		u8 bits = inb(port) & mask;
812093bfa1SOndrej Zary 		if ((bits & allof) == allof && ((bits & noneof) == 0))
822093bfa1SOndrej Zary 			break;
832093bfa1SOndrej Zary 		if (delayed)
842093bfa1SOndrej Zary 			mdelay(1);
852093bfa1SOndrej Zary 		if (--timeout == 0)
862093bfa1SOndrej Zary 			return false;
872093bfa1SOndrej Zary 	}
882093bfa1SOndrej Zary 
892093bfa1SOndrej Zary 	return true;
901da177e4SLinus Torvalds }
911da177e4SLinus Torvalds 
92cad2fc72SOndrej Zary static int aha1542_outb(unsigned int base, u8 val)
931da177e4SLinus Torvalds {
942906b3ceSOndrej Zary 	if (!wait_mask(STATUS(base), CDF, 0, CDF, 0))
950c2b6481SOndrej Zary 		return 1;
96cad2fc72SOndrej Zary 	outb(val, DATA(base));
97eef77801SOndrej Zary 
981da177e4SLinus Torvalds 	return 0;
991da177e4SLinus Torvalds }
1000c2b6481SOndrej Zary 
101cad2fc72SOndrej Zary static int aha1542_out(unsigned int base, u8 *buf, int len)
1020c2b6481SOndrej Zary {
1031da177e4SLinus Torvalds 	while (len--) {
1041b0224b0SOndrej Zary 		if (!wait_mask(STATUS(base), CDF, 0, CDF, 0))
1051da177e4SLinus Torvalds 			return 1;
106cad2fc72SOndrej Zary 		outb(*buf++, DATA(base));
1070c2b6481SOndrej Zary 	}
10823e6940aSOndrej Zary 	if (!wait_mask(INTRFLAGS(base), INTRMASK, HACC, 0, 0))
10923e6940aSOndrej Zary 		return 1;
1100c2b6481SOndrej Zary 
1110c2b6481SOndrej Zary 	return 0;
1120c2b6481SOndrej Zary }
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds /* Only used at boot time, so we do not need to worry about latency as much
1151da177e4SLinus Torvalds    here */
1161da177e4SLinus Torvalds 
117cad2fc72SOndrej Zary static int aha1542_in(unsigned int base, u8 *buf, int len, int timeout)
1181da177e4SLinus Torvalds {
1191da177e4SLinus Torvalds 	while (len--) {
1201b0224b0SOndrej Zary 		if (!wait_mask(STATUS(base), DF, DF, 0, timeout))
1211da177e4SLinus Torvalds 			return 1;
122cad2fc72SOndrej Zary 		*buf++ = inb(DATA(base));
123a13b3722SOndrej Zary 	}
124a13b3722SOndrej Zary 	return 0;
125a13b3722SOndrej Zary }
1261da177e4SLinus Torvalds 
1271da177e4SLinus Torvalds static int makecode(unsigned hosterr, unsigned scsierr)
1281da177e4SLinus Torvalds {
1291da177e4SLinus Torvalds 	switch (hosterr) {
1301da177e4SLinus Torvalds 	case 0x0:
1311da177e4SLinus Torvalds 	case 0xa:		/* Linked command complete without error and linked normally */
1321da177e4SLinus Torvalds 	case 0xb:		/* Linked command complete without error, interrupt generated */
1331da177e4SLinus Torvalds 		hosterr = 0;
1341da177e4SLinus Torvalds 		break;
1351da177e4SLinus Torvalds 
1361da177e4SLinus Torvalds 	case 0x11:		/* Selection time out-The initiator selection or target
1371da177e4SLinus Torvalds 				   reselection was not complete within the SCSI Time out period */
1381da177e4SLinus Torvalds 		hosterr = DID_TIME_OUT;
1391da177e4SLinus Torvalds 		break;
1401da177e4SLinus Torvalds 
1411da177e4SLinus Torvalds 	case 0x12:		/* Data overrun/underrun-The target attempted to transfer more data
1421da177e4SLinus Torvalds 				   than was allocated by the Data Length field or the sum of the
1431da177e4SLinus Torvalds 				   Scatter / Gather Data Length fields. */
1441da177e4SLinus Torvalds 
1451da177e4SLinus Torvalds 	case 0x13:		/* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
1461da177e4SLinus Torvalds 
1471da177e4SLinus Torvalds 	case 0x15:		/* MBO command was not 00, 01 or 02-The first byte of the CB was
1481da177e4SLinus Torvalds 				   invalid. This usually indicates a software failure. */
1491da177e4SLinus Torvalds 
1501da177e4SLinus Torvalds 	case 0x16:		/* Invalid CCB Operation Code-The first byte of the CCB was invalid.
1511da177e4SLinus Torvalds 				   This usually indicates a software failure. */
1521da177e4SLinus Torvalds 
1531da177e4SLinus Torvalds 	case 0x17:		/* Linked CCB does not have the same LUN-A subsequent CCB of a set
1541da177e4SLinus Torvalds 				   of linked CCB's does not specify the same logical unit number as
1551da177e4SLinus Torvalds 				   the first. */
1561da177e4SLinus Torvalds 	case 0x18:		/* Invalid Target Direction received from Host-The direction of a
1571da177e4SLinus Torvalds 				   Target Mode CCB was invalid. */
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds 	case 0x19:		/* Duplicate CCB Received in Target Mode-More than once CCB was
1601da177e4SLinus Torvalds 				   received to service data transfer between the same target LUN
1611da177e4SLinus Torvalds 				   and initiator SCSI ID in the same direction. */
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds 	case 0x1a:		/* Invalid CCB or Segment List Parameter-A segment list with a zero
1641da177e4SLinus Torvalds 				   length segment or invalid segment list boundaries was received.
1651da177e4SLinus Torvalds 				   A CCB parameter was invalid. */
166fde1fb8aSOndrej Zary #ifdef DEBUG
167fde1fb8aSOndrej Zary 		printk("Aha1542: %x %x\n", hosterr, scsierr);
168fde1fb8aSOndrej Zary #endif
1691da177e4SLinus Torvalds 		hosterr = DID_ERROR;	/* Couldn't find any better */
1701da177e4SLinus Torvalds 		break;
1711da177e4SLinus Torvalds 
1721da177e4SLinus Torvalds 	case 0x14:		/* Target bus phase sequence failure-An invalid bus phase or bus
1731da177e4SLinus Torvalds 				   phase sequence was requested by the target. The host adapter
1741da177e4SLinus Torvalds 				   will generate a SCSI Reset Condition, notifying the host with
1751da177e4SLinus Torvalds 				   a SCRD interrupt */
1761da177e4SLinus Torvalds 		hosterr = DID_RESET;
1771da177e4SLinus Torvalds 		break;
1781da177e4SLinus Torvalds 	default:
1791da177e4SLinus Torvalds 		printk(KERN_ERR "aha1542: makecode: unknown hoststatus %x\n", hosterr);
1801da177e4SLinus Torvalds 		break;
1811da177e4SLinus Torvalds 	}
1821da177e4SLinus Torvalds 	return scsierr | (hosterr << 16);
1831da177e4SLinus Torvalds }
1841da177e4SLinus Torvalds 
18568ea9de3SOndrej Zary static int aha1542_test_port(struct Scsi_Host *sh)
1861da177e4SLinus Torvalds {
187cb5b570cSOndrej Zary 	u8 inquiry_result[4];
188cad2fc72SOndrej Zary 	int i;
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds 	/* Quick and dirty test for presence of the card. */
19168ea9de3SOndrej Zary 	if (inb(STATUS(sh->io_port)) == 0xff)
1921da177e4SLinus Torvalds 		return 0;
1931da177e4SLinus Torvalds 
1941da177e4SLinus Torvalds 	/* Reset the adapter. I ought to make a hard reset, but it's not really necessary */
1951da177e4SLinus Torvalds 
1961da177e4SLinus Torvalds 	/* In case some other card was probing here, reset interrupts */
19768ea9de3SOndrej Zary 	aha1542_intr_reset(sh->io_port);	/* reset interrupts, so they don't block */
1981da177e4SLinus Torvalds 
19968ea9de3SOndrej Zary 	outb(SRST | IRST /*|SCRST */ , CONTROL(sh->io_port));
2001da177e4SLinus Torvalds 
2011da177e4SLinus Torvalds 	mdelay(20);		/* Wait a little bit for things to settle down. */
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds 	/* Expect INIT and IDLE, any of the others are bad */
20468ea9de3SOndrej Zary 	if (!wait_mask(STATUS(sh->io_port), STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0))
205a13b3722SOndrej Zary 		return 0;
2061da177e4SLinus Torvalds 
2071da177e4SLinus Torvalds 	/* Shouldn't have generated any interrupts during reset */
20868ea9de3SOndrej Zary 	if (inb(INTRFLAGS(sh->io_port)) & INTRMASK)
209a13b3722SOndrej Zary 		return 0;
2101da177e4SLinus Torvalds 
2111da177e4SLinus Torvalds 	/* Perform a host adapter inquiry instead so we do not need to set
2121da177e4SLinus Torvalds 	   up the mailboxes ahead of time */
2131da177e4SLinus Torvalds 
21468ea9de3SOndrej Zary 	aha1542_outb(sh->io_port, CMD_INQUIRY);
2151da177e4SLinus Torvalds 
216cad2fc72SOndrej Zary 	for (i = 0; i < 4; i++) {
21768ea9de3SOndrej Zary 		if (!wait_mask(STATUS(sh->io_port), DF, DF, 0, 0))
218a13b3722SOndrej Zary 			return 0;
21968ea9de3SOndrej Zary 		inquiry_result[i] = inb(DATA(sh->io_port));
2201da177e4SLinus Torvalds 	}
2211da177e4SLinus Torvalds 
2221da177e4SLinus Torvalds 	/* Reading port should reset DF */
22368ea9de3SOndrej Zary 	if (inb(STATUS(sh->io_port)) & DF)
224a13b3722SOndrej Zary 		return 0;
2251da177e4SLinus Torvalds 
2261da177e4SLinus Torvalds 	/* When HACC, command is completed, and we're though testing */
22768ea9de3SOndrej Zary 	if (!wait_mask(INTRFLAGS(sh->io_port), HACC, HACC, 0, 0))
228a13b3722SOndrej Zary 		return 0;
2291da177e4SLinus Torvalds 
2301da177e4SLinus Torvalds 	/* Clear interrupts */
23168ea9de3SOndrej Zary 	outb(IRST, CONTROL(sh->io_port));
2321da177e4SLinus Torvalds 
233bdebe224SOndrej Zary 	return 1;
2341da177e4SLinus Torvalds }
2351da177e4SLinus Torvalds 
2361b0224b0SOndrej Zary static irqreturn_t aha1542_interrupt(int irq, void *dev_id)
2371da177e4SLinus Torvalds {
2381b0224b0SOndrej Zary 	struct Scsi_Host *sh = dev_id;
239c2532f68SOndrej Zary 	struct aha1542_hostdata *aha1542 = shost_priv(sh);
24055b28f9fSOndrej Zary 	void (*my_done)(struct scsi_cmnd *) = NULL;
2411da177e4SLinus Torvalds 	int errstatus, mbi, mbo, mbistatus;
2421da177e4SLinus Torvalds 	int number_serviced;
2431da177e4SLinus Torvalds 	unsigned long flags;
24455b28f9fSOndrej Zary 	struct scsi_cmnd *tmp_cmd;
2451da177e4SLinus Torvalds 	int flag;
246e98878f7SOndrej Zary 	struct mailbox *mb = aha1542->mb;
247e98878f7SOndrej Zary 	struct ccb *ccb = aha1542->ccb;
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds #ifdef DEBUG
2501da177e4SLinus Torvalds 	{
251c2532f68SOndrej Zary 		flag = inb(INTRFLAGS(sh->io_port));
2522906b3ceSOndrej Zary 		shost_printk(KERN_DEBUG, sh, "aha1542_intr_handle: ");
2531da177e4SLinus Torvalds 		if (!(flag & ANYINTR))
2541da177e4SLinus Torvalds 			printk("no interrupt?");
2551da177e4SLinus Torvalds 		if (flag & MBIF)
2561da177e4SLinus Torvalds 			printk("MBIF ");
2571da177e4SLinus Torvalds 		if (flag & MBOA)
2581da177e4SLinus Torvalds 			printk("MBOF ");
2591da177e4SLinus Torvalds 		if (flag & HACC)
2601da177e4SLinus Torvalds 			printk("HACC ");
2611da177e4SLinus Torvalds 		if (flag & SCRD)
2621da177e4SLinus Torvalds 			printk("SCRD ");
263c2532f68SOndrej Zary 		printk("status %02x\n", inb(STATUS(sh->io_port)));
2641da177e4SLinus Torvalds 	};
2651da177e4SLinus Torvalds #endif
2661da177e4SLinus Torvalds 	number_serviced = 0;
2671da177e4SLinus Torvalds 
2681b0224b0SOndrej Zary 	spin_lock_irqsave(sh->host_lock, flags);
2691b0224b0SOndrej Zary 	while (1) {
270c2532f68SOndrej Zary 		flag = inb(INTRFLAGS(sh->io_port));
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds 		/* Check for unusual interrupts.  If any of these happen, we should
2731da177e4SLinus Torvalds 		   probably do something special, but for now just printing a message
2741da177e4SLinus Torvalds 		   is sufficient.  A SCSI reset detected is something that we really
2751da177e4SLinus Torvalds 		   need to deal with in some way. */
2761da177e4SLinus Torvalds 		if (flag & ~MBIF) {
2771da177e4SLinus Torvalds 			if (flag & MBOA)
2781da177e4SLinus Torvalds 				printk("MBOF ");
2791da177e4SLinus Torvalds 			if (flag & HACC)
2801da177e4SLinus Torvalds 				printk("HACC ");
281dfd7c991SOndrej Zary 			if (flag & SCRD)
2821da177e4SLinus Torvalds 				printk("SCRD ");
2831da177e4SLinus Torvalds 		}
284c2532f68SOndrej Zary 		aha1542_intr_reset(sh->io_port);
2851da177e4SLinus Torvalds 
286e98878f7SOndrej Zary 		mbi = aha1542->aha1542_last_mbi_used + 1;
2871da177e4SLinus Torvalds 		if (mbi >= 2 * AHA1542_MAILBOXES)
2881da177e4SLinus Torvalds 			mbi = AHA1542_MAILBOXES;
2891da177e4SLinus Torvalds 
2901da177e4SLinus Torvalds 		do {
2911da177e4SLinus Torvalds 			if (mb[mbi].status != 0)
2921da177e4SLinus Torvalds 				break;
2931da177e4SLinus Torvalds 			mbi++;
2941da177e4SLinus Torvalds 			if (mbi >= 2 * AHA1542_MAILBOXES)
2951da177e4SLinus Torvalds 				mbi = AHA1542_MAILBOXES;
296e98878f7SOndrej Zary 		} while (mbi != aha1542->aha1542_last_mbi_used);
2971da177e4SLinus Torvalds 
2981da177e4SLinus Torvalds 		if (mb[mbi].status == 0) {
2991b0224b0SOndrej Zary 			spin_unlock_irqrestore(sh->host_lock, flags);
3001da177e4SLinus Torvalds 			/* Hmm, no mail.  Must have read it the last time around */
301dfd7c991SOndrej Zary 			if (!number_serviced)
3022906b3ceSOndrej Zary 				shost_printk(KERN_WARNING, sh, "interrupt received, but no mail.\n");
3031b0224b0SOndrej Zary 			return IRQ_HANDLED;
3041da177e4SLinus Torvalds 		};
3051da177e4SLinus Torvalds 
30610be6250SOndrej Zary 		mbo = (scsi2int(mb[mbi].ccbptr) - (isa_virt_to_bus(&ccb[0]))) / sizeof(struct ccb);
3071da177e4SLinus Torvalds 		mbistatus = mb[mbi].status;
3081da177e4SLinus Torvalds 		mb[mbi].status = 0;
309e98878f7SOndrej Zary 		aha1542->aha1542_last_mbi_used = mbi;
3101da177e4SLinus Torvalds 
3111da177e4SLinus Torvalds #ifdef DEBUG
3121da177e4SLinus Torvalds 		if (ccb[mbo].tarstat | ccb[mbo].hastat)
3132906b3ceSOndrej Zary 			shost_printk(KERN_DEBUG, sh, "aha1542_command: returning %x (status %d)\n",
3141da177e4SLinus Torvalds 			       ccb[mbo].tarstat + ((int) ccb[mbo].hastat << 16), mb[mbi].status);
3151da177e4SLinus Torvalds #endif
3161da177e4SLinus Torvalds 
3171da177e4SLinus Torvalds 		if (mbistatus == 3)
3181da177e4SLinus Torvalds 			continue;	/* Aborted command not found */
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds #ifdef DEBUG
3212906b3ceSOndrej Zary 		shost_printk(KERN_DEBUG, sh, "...done %d %d\n", mbo, mbi);
3221da177e4SLinus Torvalds #endif
3231da177e4SLinus Torvalds 
32455b28f9fSOndrej Zary 		tmp_cmd = aha1542->int_cmds[mbo];
3251da177e4SLinus Torvalds 
32655b28f9fSOndrej Zary 		if (!tmp_cmd || !tmp_cmd->scsi_done) {
3271b0224b0SOndrej Zary 			spin_unlock_irqrestore(sh->host_lock, flags);
3282906b3ceSOndrej Zary 			shost_printk(KERN_WARNING, sh, "Unexpected interrupt\n");
3292906b3ceSOndrej Zary 			shost_printk(KERN_WARNING, sh, "tarstat=%x, hastat=%x idlun=%x ccb#=%d\n", ccb[mbo].tarstat,
3301da177e4SLinus Torvalds 			       ccb[mbo].hastat, ccb[mbo].idlun, mbo);
3311b0224b0SOndrej Zary 			return IRQ_HANDLED;
3321da177e4SLinus Torvalds 		}
33355b28f9fSOndrej Zary 		my_done = tmp_cmd->scsi_done;
33455b28f9fSOndrej Zary 		kfree(tmp_cmd->host_scribble);
33555b28f9fSOndrej Zary 		tmp_cmd->host_scribble = NULL;
3361da177e4SLinus Torvalds 		/* Fetch the sense data, and tuck it away, in the required slot.  The
3371da177e4SLinus Torvalds 		   Adaptec automatically fetches it, and there is no guarantee that
3381da177e4SLinus Torvalds 		   we will still have it in the cdb when we come back */
3391da177e4SLinus Torvalds 		if (ccb[mbo].tarstat == 2)
34055b28f9fSOndrej Zary 			memcpy(tmp_cmd->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen],
341b80ca4f7SFUJITA Tomonori 			       SCSI_SENSE_BUFFERSIZE);
3421da177e4SLinus Torvalds 
3431da177e4SLinus Torvalds 
3441da177e4SLinus Torvalds 		/* is there mail :-) */
3451da177e4SLinus Torvalds 
3461da177e4SLinus Torvalds 		/* more error checking left out here */
3471da177e4SLinus Torvalds 		if (mbistatus != 1)
3481da177e4SLinus Torvalds 			/* This is surely wrong, but I don't know what's right */
3491da177e4SLinus Torvalds 			errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat);
3501da177e4SLinus Torvalds 		else
3511da177e4SLinus Torvalds 			errstatus = 0;
3521da177e4SLinus Torvalds 
3531da177e4SLinus Torvalds #ifdef DEBUG
3541da177e4SLinus Torvalds 		if (errstatus)
3552906b3ceSOndrej Zary 			shost_printk(KERN_DEBUG, sh, "(aha1542 error:%x %x %x) ", errstatus,
3561da177e4SLinus Torvalds 			       ccb[mbo].hastat, ccb[mbo].tarstat);
3576ddc8cf4SOndrej Zary 		if (ccb[mbo].tarstat == 2)
3586ddc8cf4SOndrej Zary 			print_hex_dump_bytes("sense: ", DUMP_PREFIX_NONE, &ccb[mbo].cdb[ccb[mbo].cdblen], 12);
359fde1fb8aSOndrej Zary 		if (errstatus)
360fde1fb8aSOndrej Zary 			printk("aha1542_intr_handle: returning %6x\n", errstatus);
361fde1fb8aSOndrej Zary #endif
36255b28f9fSOndrej Zary 		tmp_cmd->result = errstatus;
36355b28f9fSOndrej Zary 		aha1542->int_cmds[mbo] = NULL;	/* This effectively frees up the mailbox slot, as
3641da177e4SLinus Torvalds 						   far as queuecommand is concerned */
36555b28f9fSOndrej Zary 		my_done(tmp_cmd);
3661da177e4SLinus Torvalds 		number_serviced++;
3671da177e4SLinus Torvalds 	};
3681da177e4SLinus Torvalds }
3691da177e4SLinus Torvalds 
3701b0224b0SOndrej Zary static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
37109a44833SOndrej Zary {
3722906b3ceSOndrej Zary 	struct aha1542_hostdata *aha1542 = shost_priv(sh);
373cb5b570cSOndrej Zary 	u8 direction;
37455b28f9fSOndrej Zary 	u8 target = cmd->device->id;
37555b28f9fSOndrej Zary 	u8 lun = cmd->device->lun;
3761da177e4SLinus Torvalds 	unsigned long flags;
37755b28f9fSOndrej Zary 	int bufflen = scsi_bufflen(cmd);
3788c08a621SOndrej Zary 	int mbo, sg_count;
379e98878f7SOndrej Zary 	struct mailbox *mb = aha1542->mb;
380e98878f7SOndrej Zary 	struct ccb *ccb = aha1542->ccb;
3818c08a621SOndrej Zary 	struct chain *cptr;
3821da177e4SLinus Torvalds 
38355b28f9fSOndrej Zary 	if (*cmd->cmnd == REQUEST_SENSE) {
3841da177e4SLinus Torvalds 		/* Don't do the command - we have the sense data already */
38555b28f9fSOndrej Zary 		cmd->result = 0;
3861b0224b0SOndrej Zary 		cmd->scsi_done(cmd);
3871da177e4SLinus Torvalds 		return 0;
3881da177e4SLinus Torvalds 	}
3891da177e4SLinus Torvalds #ifdef DEBUG
390764a0c7eSOndrej Zary 	{
391764a0c7eSOndrej Zary 		int i = -1;
39255b28f9fSOndrej Zary 		if (*cmd->cmnd == READ_10 || *cmd->cmnd == WRITE_10)
39355b28f9fSOndrej Zary 			i = xscsi2int(cmd->cmnd + 2);
39455b28f9fSOndrej Zary 		else if (*cmd->cmnd == READ_6 || *cmd->cmnd == WRITE_6)
39555b28f9fSOndrej Zary 			i = scsi2int(cmd->cmnd + 2);
396764a0c7eSOndrej Zary 		shost_printk(KERN_DEBUG, sh, "aha1542_queuecommand: dev %d cmd %02x pos %d len %d",
397764a0c7eSOndrej Zary 						target, *cmd->cmnd, i, bufflen);
3986ddc8cf4SOndrej Zary 		print_hex_dump_bytes("command: ", DUMP_PREFIX_NONE, cmd->cmnd, cmd->cmd_len);
399764a0c7eSOndrej Zary 	}
4001da177e4SLinus Torvalds #endif
4018c08a621SOndrej Zary 	if (bufflen) {	/* allocate memory before taking host_lock */
4028c08a621SOndrej Zary 		sg_count = scsi_sg_count(cmd);
4038c08a621SOndrej Zary 		cptr = kmalloc(sizeof(*cptr) * sg_count, GFP_KERNEL | GFP_DMA);
4048c08a621SOndrej Zary 		if (!cptr)
4058c08a621SOndrej Zary 			return SCSI_MLQUEUE_HOST_BUSY;
406ec54adfbSArnd Bergmann 	} else {
407ec54adfbSArnd Bergmann 		sg_count = 0;
408ec54adfbSArnd Bergmann 		cptr = NULL;
4098c08a621SOndrej Zary 	}
4108c08a621SOndrej Zary 
4111da177e4SLinus Torvalds 	/* Use the outgoing mailboxes in a round-robin fashion, because this
4121da177e4SLinus Torvalds 	   is how the host adapter will scan for them */
4131da177e4SLinus Torvalds 
4141b0224b0SOndrej Zary 	spin_lock_irqsave(sh->host_lock, flags);
415e98878f7SOndrej Zary 	mbo = aha1542->aha1542_last_mbo_used + 1;
4161da177e4SLinus Torvalds 	if (mbo >= AHA1542_MAILBOXES)
4171da177e4SLinus Torvalds 		mbo = 0;
4181da177e4SLinus Torvalds 
4191da177e4SLinus Torvalds 	do {
42055b28f9fSOndrej Zary 		if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL)
4211da177e4SLinus Torvalds 			break;
4221da177e4SLinus Torvalds 		mbo++;
4231da177e4SLinus Torvalds 		if (mbo >= AHA1542_MAILBOXES)
4241da177e4SLinus Torvalds 			mbo = 0;
425e98878f7SOndrej Zary 	} while (mbo != aha1542->aha1542_last_mbo_used);
4261da177e4SLinus Torvalds 
42755b28f9fSOndrej Zary 	if (mb[mbo].status || aha1542->int_cmds[mbo])
4281da177e4SLinus Torvalds 		panic("Unable to find empty mailbox for aha1542.\n");
4291da177e4SLinus Torvalds 
43055b28f9fSOndrej Zary 	aha1542->int_cmds[mbo] = cmd;	/* This will effectively prevent someone else from
4311da177e4SLinus Torvalds 					   screwing with this cdb. */
4321da177e4SLinus Torvalds 
433e98878f7SOndrej Zary 	aha1542->aha1542_last_mbo_used = mbo;
4341da177e4SLinus Torvalds 
4351da177e4SLinus Torvalds #ifdef DEBUG
4361b0224b0SOndrej Zary 	shost_printk(KERN_DEBUG, sh, "Sending command (%d %p)...", mbo, cmd->scsi_done);
4371da177e4SLinus Torvalds #endif
4381da177e4SLinus Torvalds 
43910be6250SOndrej Zary 	any2scsi(mb[mbo].ccbptr, isa_virt_to_bus(&ccb[mbo]));	/* This gets trashed for some reason */
4401da177e4SLinus Torvalds 
4411da177e4SLinus Torvalds 	memset(&ccb[mbo], 0, sizeof(struct ccb));
4421da177e4SLinus Torvalds 
44355b28f9fSOndrej Zary 	ccb[mbo].cdblen = cmd->cmd_len;
4441da177e4SLinus Torvalds 
4451da177e4SLinus Torvalds 	direction = 0;
44655b28f9fSOndrej Zary 	if (*cmd->cmnd == READ_10 || *cmd->cmnd == READ_6)
4471da177e4SLinus Torvalds 		direction = 8;
44855b28f9fSOndrej Zary 	else if (*cmd->cmnd == WRITE_10 || *cmd->cmnd == WRITE_6)
4491da177e4SLinus Torvalds 		direction = 16;
4501da177e4SLinus Torvalds 
45155b28f9fSOndrej Zary 	memcpy(ccb[mbo].cdb, cmd->cmnd, ccb[mbo].cdblen);
4521da177e4SLinus Torvalds 
453fc3fdfccSBoaz Harrosh 	if (bufflen) {
45451cf2249SJens Axboe 		struct scatterlist *sg;
4558c08a621SOndrej Zary 		int i;
4566ddc8cf4SOndrej Zary 
4571da177e4SLinus Torvalds 		ccb[mbo].op = 2;	/* SCSI Initiator Command  w/scatter-gather */
4588c08a621SOndrej Zary 		cmd->host_scribble = (void *)cptr;
45955b28f9fSOndrej Zary 		scsi_for_each_sg(cmd, sg, sg_count, i) {
46010be6250SOndrej Zary 			any2scsi(cptr[i].dataptr, isa_page_to_bus(sg_page(sg))
46110be6250SOndrej Zary 								+ sg->offset);
46251cf2249SJens Axboe 			any2scsi(cptr[i].datalen, sg->length);
4631da177e4SLinus Torvalds 		};
464fc3fdfccSBoaz Harrosh 		any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain));
46510be6250SOndrej Zary 		any2scsi(ccb[mbo].dataptr, isa_virt_to_bus(cptr));
4661da177e4SLinus Torvalds #ifdef DEBUG
4676ddc8cf4SOndrej Zary 		shost_printk(KERN_DEBUG, sh, "cptr %p: ", cptr);
4686ddc8cf4SOndrej Zary 		print_hex_dump_bytes("cptr: ", DUMP_PREFIX_NONE, cptr, 18);
4691da177e4SLinus Torvalds #endif
4701da177e4SLinus Torvalds 	} else {
4711da177e4SLinus Torvalds 		ccb[mbo].op = 0;	/* SCSI Initiator Command */
47255b28f9fSOndrej Zary 		cmd->host_scribble = NULL;
473fc3fdfccSBoaz Harrosh 		any2scsi(ccb[mbo].datalen, 0);
474fc3fdfccSBoaz Harrosh 		any2scsi(ccb[mbo].dataptr, 0);
4751da177e4SLinus Torvalds 	};
4761da177e4SLinus Torvalds 	ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7);	/*SCSI Target Id */
4771da177e4SLinus Torvalds 	ccb[mbo].rsalen = 16;
4781da177e4SLinus Torvalds 	ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
4791da177e4SLinus Torvalds 	ccb[mbo].commlinkid = 0;
4801da177e4SLinus Torvalds 
4811da177e4SLinus Torvalds #ifdef DEBUG
4826ddc8cf4SOndrej Zary 	print_hex_dump_bytes("sending: ", DUMP_PREFIX_NONE, &ccb[mbo], sizeof(ccb[mbo]) - 10);
483fde1fb8aSOndrej Zary 	printk("aha1542_queuecommand: now waiting for interrupt ");
484fde1fb8aSOndrej Zary #endif
4851da177e4SLinus Torvalds 	mb[mbo].status = 1;
48655b28f9fSOndrej Zary 	aha1542_outb(cmd->device->host->io_port, CMD_START_SCSI);
4871b0224b0SOndrej Zary 	spin_unlock_irqrestore(sh->host_lock, flags);
4881da177e4SLinus Torvalds 
4891da177e4SLinus Torvalds 	return 0;
4901da177e4SLinus Torvalds }
4911da177e4SLinus Torvalds 
4921da177e4SLinus Torvalds /* Initialize mailboxes */
49368ea9de3SOndrej Zary static void setup_mailboxes(struct Scsi_Host *sh)
4941da177e4SLinus Torvalds {
495c2532f68SOndrej Zary 	struct aha1542_hostdata *aha1542 = shost_priv(sh);
4961da177e4SLinus Torvalds 	int i;
497e98878f7SOndrej Zary 	struct mailbox *mb = aha1542->mb;
498e98878f7SOndrej Zary 	struct ccb *ccb = aha1542->ccb;
4991da177e4SLinus Torvalds 
500cad2fc72SOndrej Zary 	u8 mb_cmd[5] = { CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0};
5011da177e4SLinus Torvalds 
5021da177e4SLinus Torvalds 	for (i = 0; i < AHA1542_MAILBOXES; i++) {
5031da177e4SLinus Torvalds 		mb[i].status = mb[AHA1542_MAILBOXES + i].status = 0;
50410be6250SOndrej Zary 		any2scsi(mb[i].ccbptr, isa_virt_to_bus(&ccb[i]));
5051da177e4SLinus Torvalds 	};
50668ea9de3SOndrej Zary 	aha1542_intr_reset(sh->io_port);	/* reset interrupts, so they don't block */
507cad2fc72SOndrej Zary 	any2scsi((mb_cmd + 2), isa_virt_to_bus(mb));
50868ea9de3SOndrej Zary 	if (aha1542_out(sh->io_port, mb_cmd, 5))
5092906b3ceSOndrej Zary 		shost_printk(KERN_ERR, sh, "failed setting up mailboxes\n");
51068ea9de3SOndrej Zary 	aha1542_intr_reset(sh->io_port);
5111da177e4SLinus Torvalds }
5121da177e4SLinus Torvalds 
51368ea9de3SOndrej Zary static int aha1542_getconfig(struct Scsi_Host *sh)
5141da177e4SLinus Torvalds {
515cb5b570cSOndrej Zary 	u8 inquiry_result[3];
5161da177e4SLinus Torvalds 	int i;
51768ea9de3SOndrej Zary 	i = inb(STATUS(sh->io_port));
5181da177e4SLinus Torvalds 	if (i & DF) {
51968ea9de3SOndrej Zary 		i = inb(DATA(sh->io_port));
5201da177e4SLinus Torvalds 	};
52168ea9de3SOndrej Zary 	aha1542_outb(sh->io_port, CMD_RETCONF);
52268ea9de3SOndrej Zary 	aha1542_in(sh->io_port, inquiry_result, 3, 0);
52368ea9de3SOndrej Zary 	if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0))
5242906b3ceSOndrej Zary 		shost_printk(KERN_ERR, sh, "error querying board settings\n");
52568ea9de3SOndrej Zary 	aha1542_intr_reset(sh->io_port);
5261da177e4SLinus Torvalds 	switch (inquiry_result[0]) {
5271da177e4SLinus Torvalds 	case 0x80:
52868ea9de3SOndrej Zary 		sh->dma_channel = 7;
5291da177e4SLinus Torvalds 		break;
5301da177e4SLinus Torvalds 	case 0x40:
53168ea9de3SOndrej Zary 		sh->dma_channel = 6;
5321da177e4SLinus Torvalds 		break;
5331da177e4SLinus Torvalds 	case 0x20:
53468ea9de3SOndrej Zary 		sh->dma_channel = 5;
5351da177e4SLinus Torvalds 		break;
5361da177e4SLinus Torvalds 	case 0x01:
53768ea9de3SOndrej Zary 		sh->dma_channel = 0;
5381da177e4SLinus Torvalds 		break;
5391da177e4SLinus Torvalds 	case 0:
5401da177e4SLinus Torvalds 		/* This means that the adapter, although Adaptec 1542 compatible, doesn't use a DMA channel.
5411da177e4SLinus Torvalds 		   Currently only aware of the BusLogic BT-445S VL-Bus adapter which needs this. */
54268ea9de3SOndrej Zary 		sh->dma_channel = 0xFF;
5431da177e4SLinus Torvalds 		break;
5441da177e4SLinus Torvalds 	default:
5452906b3ceSOndrej Zary 		shost_printk(KERN_ERR, sh, "Unable to determine DMA channel.\n");
5461da177e4SLinus Torvalds 		return -1;
5471da177e4SLinus Torvalds 	};
5481da177e4SLinus Torvalds 	switch (inquiry_result[1]) {
5491da177e4SLinus Torvalds 	case 0x40:
55068ea9de3SOndrej Zary 		sh->irq = 15;
5511da177e4SLinus Torvalds 		break;
5521da177e4SLinus Torvalds 	case 0x20:
55368ea9de3SOndrej Zary 		sh->irq = 14;
5541da177e4SLinus Torvalds 		break;
5551da177e4SLinus Torvalds 	case 0x8:
55668ea9de3SOndrej Zary 		sh->irq = 12;
5571da177e4SLinus Torvalds 		break;
5581da177e4SLinus Torvalds 	case 0x4:
55968ea9de3SOndrej Zary 		sh->irq = 11;
5601da177e4SLinus Torvalds 		break;
5611da177e4SLinus Torvalds 	case 0x2:
56268ea9de3SOndrej Zary 		sh->irq = 10;
5631da177e4SLinus Torvalds 		break;
5641da177e4SLinus Torvalds 	case 0x1:
56568ea9de3SOndrej Zary 		sh->irq = 9;
5661da177e4SLinus Torvalds 		break;
5671da177e4SLinus Torvalds 	default:
5682906b3ceSOndrej Zary 		shost_printk(KERN_ERR, sh, "Unable to determine IRQ level.\n");
5691da177e4SLinus Torvalds 		return -1;
5701da177e4SLinus Torvalds 	};
57168ea9de3SOndrej Zary 	sh->this_id = inquiry_result[2] & 7;
5721da177e4SLinus Torvalds 	return 0;
5731da177e4SLinus Torvalds }
5741da177e4SLinus Torvalds 
5751da177e4SLinus Torvalds /* This function should only be called for 1542C boards - we can detect
5761da177e4SLinus Torvalds    the special firmware settings and unlock the board */
5771da177e4SLinus Torvalds 
57868ea9de3SOndrej Zary static int aha1542_mbenable(struct Scsi_Host *sh)
5791da177e4SLinus Torvalds {
580cb5b570cSOndrej Zary 	static u8 mbenable_cmd[3];
581cb5b570cSOndrej Zary 	static u8 mbenable_result[2];
5821da177e4SLinus Torvalds 	int retval;
5831da177e4SLinus Torvalds 
5841da177e4SLinus Torvalds 	retval = BIOS_TRANSLATION_6432;
5851da177e4SLinus Torvalds 
58668ea9de3SOndrej Zary 	aha1542_outb(sh->io_port, CMD_EXTBIOS);
58768ea9de3SOndrej Zary 	if (aha1542_in(sh->io_port, mbenable_result, 2, 100))
5881da177e4SLinus Torvalds 		return retval;
58968ea9de3SOndrej Zary 	if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 100))
5902093bfa1SOndrej Zary 		goto fail;
59168ea9de3SOndrej Zary 	aha1542_intr_reset(sh->io_port);
5921da177e4SLinus Torvalds 
5931da177e4SLinus Torvalds 	if ((mbenable_result[0] & 0x08) || mbenable_result[1]) {
5941da177e4SLinus Torvalds 		mbenable_cmd[0] = CMD_MBENABLE;
5951da177e4SLinus Torvalds 		mbenable_cmd[1] = 0;
5961da177e4SLinus Torvalds 		mbenable_cmd[2] = mbenable_result[1];
5971da177e4SLinus Torvalds 
5981da177e4SLinus Torvalds 		if ((mbenable_result[0] & 0x08) && (mbenable_result[1] & 0x03))
5991da177e4SLinus Torvalds 			retval = BIOS_TRANSLATION_25563;
6001da177e4SLinus Torvalds 
60168ea9de3SOndrej Zary 		if (aha1542_out(sh->io_port, mbenable_cmd, 3))
6022093bfa1SOndrej Zary 			goto fail;
6031da177e4SLinus Torvalds 	};
6041da177e4SLinus Torvalds 	while (0) {
6051da177e4SLinus Torvalds fail:
6062906b3ceSOndrej Zary 		shost_printk(KERN_ERR, sh, "Mailbox init failed\n");
6071da177e4SLinus Torvalds 	}
60868ea9de3SOndrej Zary 	aha1542_intr_reset(sh->io_port);
6091da177e4SLinus Torvalds 	return retval;
6101da177e4SLinus Torvalds }
6111da177e4SLinus Torvalds 
6121da177e4SLinus Torvalds /* Query the board to find out if it is a 1542 or a 1740, or whatever. */
61368ea9de3SOndrej Zary static int aha1542_query(struct Scsi_Host *sh)
6141da177e4SLinus Torvalds {
61568ea9de3SOndrej Zary 	struct aha1542_hostdata *aha1542 = shost_priv(sh);
616cb5b570cSOndrej Zary 	u8 inquiry_result[4];
6171da177e4SLinus Torvalds 	int i;
61868ea9de3SOndrej Zary 	i = inb(STATUS(sh->io_port));
6191da177e4SLinus Torvalds 	if (i & DF) {
62068ea9de3SOndrej Zary 		i = inb(DATA(sh->io_port));
6211da177e4SLinus Torvalds 	};
62268ea9de3SOndrej Zary 	aha1542_outb(sh->io_port, CMD_INQUIRY);
62368ea9de3SOndrej Zary 	aha1542_in(sh->io_port, inquiry_result, 4, 0);
62468ea9de3SOndrej Zary 	if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0))
6252906b3ceSOndrej Zary 		shost_printk(KERN_ERR, sh, "error querying card type\n");
62668ea9de3SOndrej Zary 	aha1542_intr_reset(sh->io_port);
6271da177e4SLinus Torvalds 
62868ea9de3SOndrej Zary 	aha1542->bios_translation = BIOS_TRANSLATION_6432;	/* Default case */
6291da177e4SLinus Torvalds 
6301da177e4SLinus Torvalds 	/* For an AHA1740 series board, we ignore the board since there is a
6311da177e4SLinus Torvalds 	   hardware bug which can lead to wrong blocks being returned if the board
6321da177e4SLinus Torvalds 	   is operating in the 1542 emulation mode.  Since there is an extended mode
6331da177e4SLinus Torvalds 	   driver, we simply ignore the board and let the 1740 driver pick it up.
6341da177e4SLinus Torvalds 	 */
6351da177e4SLinus Torvalds 
6361da177e4SLinus Torvalds 	if (inquiry_result[0] == 0x43) {
6372906b3ceSOndrej Zary 		shost_printk(KERN_INFO, sh, "Emulation mode not supported for AHA-1740 hardware, use aha1740 driver instead.\n");
6381da177e4SLinus Torvalds 		return 1;
6391da177e4SLinus Torvalds 	};
6401da177e4SLinus Torvalds 
6411da177e4SLinus Torvalds 	/* Always call this - boards that do not support extended bios translation
6421da177e4SLinus Torvalds 	   will ignore the command, and we will set the proper default */
6431da177e4SLinus Torvalds 
64468ea9de3SOndrej Zary 	aha1542->bios_translation = aha1542_mbenable(sh);
6451da177e4SLinus Torvalds 
6461da177e4SLinus Torvalds 	return 0;
6471da177e4SLinus Torvalds }
6481da177e4SLinus Torvalds 
649f71429abSOndrej Zary static u8 dma_speed_hw(int dma_speed)
6501da177e4SLinus Torvalds {
651f71429abSOndrej Zary 	switch (dma_speed) {
6521da177e4SLinus Torvalds 	case 5:
653f71429abSOndrej Zary 		return 0x00;
6541da177e4SLinus Torvalds 	case 6:
655f71429abSOndrej Zary 		return 0x04;
6561da177e4SLinus Torvalds 	case 7:
657f71429abSOndrej Zary 		return 0x01;
6581da177e4SLinus Torvalds 	case 8:
659f71429abSOndrej Zary 		return 0x02;
6601da177e4SLinus Torvalds 	case 10:
661f71429abSOndrej Zary 		return 0x03;
6621da177e4SLinus Torvalds 	}
6631da177e4SLinus Torvalds 
664f71429abSOndrej Zary 	return 0xff;	/* invalid */
6651da177e4SLinus Torvalds }
6661da177e4SLinus Torvalds 
667b847fd0dSOndrej Zary /* Set the Bus on/off-times as not to ruin floppy performance */
66837d607bdSOndrej Zary static void aha1542_set_bus_times(struct Scsi_Host *sh, int bus_on, int bus_off, int dma_speed)
669b847fd0dSOndrej Zary {
67037d607bdSOndrej Zary 	if (bus_on > 0) {
67137d607bdSOndrej Zary 		u8 oncmd[] = { CMD_BUSON_TIME, clamp(bus_on, 2, 15) };
672b847fd0dSOndrej Zary 
67337d607bdSOndrej Zary 		aha1542_intr_reset(sh->io_port);
67437d607bdSOndrej Zary 		if (aha1542_out(sh->io_port, oncmd, 2))
675b847fd0dSOndrej Zary 			goto fail;
676f71429abSOndrej Zary 	}
677f71429abSOndrej Zary 
67837d607bdSOndrej Zary 	if (bus_off > 0) {
67937d607bdSOndrej Zary 		u8 offcmd[] = { CMD_BUSOFF_TIME, clamp(bus_off, 1, 64) };
680f71429abSOndrej Zary 
68137d607bdSOndrej Zary 		aha1542_intr_reset(sh->io_port);
68237d607bdSOndrej Zary 		if (aha1542_out(sh->io_port, offcmd, 2))
683b847fd0dSOndrej Zary 			goto fail;
684f71429abSOndrej Zary 	}
685f71429abSOndrej Zary 
68637d607bdSOndrej Zary 	if (dma_speed_hw(dma_speed) != 0xff) {
68737d607bdSOndrej Zary 		u8 dmacmd[] = { CMD_DMASPEED, dma_speed_hw(dma_speed) };
688f71429abSOndrej Zary 
68937d607bdSOndrej Zary 		aha1542_intr_reset(sh->io_port);
69037d607bdSOndrej Zary 		if (aha1542_out(sh->io_port, dmacmd, 2))
691b847fd0dSOndrej Zary 			goto fail;
692b847fd0dSOndrej Zary 	}
69337d607bdSOndrej Zary 	aha1542_intr_reset(sh->io_port);
694b847fd0dSOndrej Zary 	return;
695b847fd0dSOndrej Zary fail:
6962906b3ceSOndrej Zary 	shost_printk(KERN_ERR, sh, "setting bus on/off-time failed\n");
69737d607bdSOndrej Zary 	aha1542_intr_reset(sh->io_port);
698b847fd0dSOndrej Zary }
699b847fd0dSOndrej Zary 
7001da177e4SLinus Torvalds /* return non-zero on detection */
701643a7c43SOndrej Zary static struct Scsi_Host *aha1542_hw_init(struct scsi_host_template *tpnt, struct device *pdev, int indx)
7021da177e4SLinus Torvalds {
703f71429abSOndrej Zary 	unsigned int base_io = io[indx];
704c2532f68SOndrej Zary 	struct Scsi_Host *sh;
705e98878f7SOndrej Zary 	struct aha1542_hostdata *aha1542;
7062906b3ceSOndrej Zary 	char dma_info[] = "no DMA";
7071da177e4SLinus Torvalds 
7083a70c006SOndrej Zary 	if (base_io == 0)
709643a7c43SOndrej Zary 		return NULL;
7101da177e4SLinus Torvalds 
7113a70c006SOndrej Zary 	if (!request_region(base_io, AHA1542_REGION_SIZE, "aha1542"))
7123a70c006SOndrej Zary 		return NULL;
7133a70c006SOndrej Zary 
714c2532f68SOndrej Zary 	sh = scsi_host_alloc(tpnt, sizeof(struct aha1542_hostdata));
715c2532f68SOndrej Zary 	if (!sh)
7163a70c006SOndrej Zary 		goto release;
717c2532f68SOndrej Zary 	aha1542 = shost_priv(sh);
7183a70c006SOndrej Zary 
71968ea9de3SOndrej Zary 	sh->unique_id = base_io;
72068ea9de3SOndrej Zary 	sh->io_port = base_io;
72168ea9de3SOndrej Zary 	sh->n_io_port = AHA1542_REGION_SIZE;
72268ea9de3SOndrej Zary 	aha1542->aha1542_last_mbi_used = 2 * AHA1542_MAILBOXES - 1;
72368ea9de3SOndrej Zary 	aha1542->aha1542_last_mbo_used = AHA1542_MAILBOXES - 1;
72468ea9de3SOndrej Zary 
72568ea9de3SOndrej Zary 	if (!aha1542_test_port(sh))
7263a70c006SOndrej Zary 		goto unregister;
7271da177e4SLinus Torvalds 
72837d607bdSOndrej Zary 	aha1542_set_bus_times(sh, bus_on[indx], bus_off[indx], dma_speed[indx]);
72968ea9de3SOndrej Zary 	if (aha1542_query(sh))
7303a70c006SOndrej Zary 		goto unregister;
73168ea9de3SOndrej Zary 	if (aha1542_getconfig(sh) == -1)
7321da177e4SLinus Torvalds 		goto unregister;
7331da177e4SLinus Torvalds 
734c2532f68SOndrej Zary 	if (sh->dma_channel != 0xFF)
7352906b3ceSOndrej Zary 		snprintf(dma_info, sizeof(dma_info), "DMA %d", sh->dma_channel);
7362906b3ceSOndrej Zary 	shost_printk(KERN_INFO, sh, "Adaptec AHA-1542 (SCSI-ID %d) at IO 0x%x, IRQ %d, %s\n",
7372906b3ceSOndrej Zary 				sh->this_id, base_io, sh->irq, dma_info);
7383a70c006SOndrej Zary 	if (aha1542->bios_translation == BIOS_TRANSLATION_25563)
7392906b3ceSOndrej Zary 		shost_printk(KERN_INFO, sh, "Using extended bios translation\n");
7401da177e4SLinus Torvalds 
74168ea9de3SOndrej Zary 	setup_mailboxes(sh);
7421da177e4SLinus Torvalds 
7431b0224b0SOndrej Zary 	if (request_irq(sh->irq, aha1542_interrupt, 0, "aha1542", sh)) {
7442906b3ceSOndrej Zary 		shost_printk(KERN_ERR, sh, "Unable to allocate IRQ.\n");
7451da177e4SLinus Torvalds 		goto unregister;
7461da177e4SLinus Torvalds 	}
747c2532f68SOndrej Zary 	if (sh->dma_channel != 0xFF) {
748c2532f68SOndrej Zary 		if (request_dma(sh->dma_channel, "aha1542")) {
7492906b3ceSOndrej Zary 			shost_printk(KERN_ERR, sh, "Unable to allocate DMA channel.\n");
7503a70c006SOndrej Zary 			goto free_irq;
7511da177e4SLinus Torvalds 		}
752c2532f68SOndrej Zary 		if (sh->dma_channel == 0 || sh->dma_channel >= 5) {
753c2532f68SOndrej Zary 			set_dma_mode(sh->dma_channel, DMA_MODE_CASCADE);
754c2532f68SOndrej Zary 			enable_dma(sh->dma_channel);
7551da177e4SLinus Torvalds 		}
7561da177e4SLinus Torvalds 	}
75787c4d7bcSJeff Garzik 
758c2532f68SOndrej Zary 	if (scsi_add_host(sh, pdev))
7593a70c006SOndrej Zary 		goto free_dma;
7601da177e4SLinus Torvalds 
761c2532f68SOndrej Zary 	scsi_scan_host(sh);
7621da177e4SLinus Torvalds 
763c2532f68SOndrej Zary 	return sh;
7643a70c006SOndrej Zary free_dma:
765c2532f68SOndrej Zary 	if (sh->dma_channel != 0xff)
766c2532f68SOndrej Zary 		free_dma(sh->dma_channel);
7673a70c006SOndrej Zary free_irq:
768c2532f68SOndrej Zary 	free_irq(sh->irq, sh);
7691da177e4SLinus Torvalds unregister:
770c2532f68SOndrej Zary 	scsi_host_put(sh);
7713a70c006SOndrej Zary release:
7723a70c006SOndrej Zary 	release_region(base_io, AHA1542_REGION_SIZE);
7731da177e4SLinus Torvalds 
774643a7c43SOndrej Zary 	return NULL;
7751da177e4SLinus Torvalds }
7761da177e4SLinus Torvalds 
777c2532f68SOndrej Zary static int aha1542_release(struct Scsi_Host *sh)
7781da177e4SLinus Torvalds {
779c2532f68SOndrej Zary 	scsi_remove_host(sh);
780c2532f68SOndrej Zary 	if (sh->dma_channel != 0xff)
781c2532f68SOndrej Zary 		free_dma(sh->dma_channel);
782c2532f68SOndrej Zary 	if (sh->irq)
783c2532f68SOndrej Zary 		free_irq(sh->irq, sh);
784c2532f68SOndrej Zary 	if (sh->io_port && sh->n_io_port)
785c2532f68SOndrej Zary 		release_region(sh->io_port, sh->n_io_port);
786c2532f68SOndrej Zary 	scsi_host_put(sh);
7871da177e4SLinus Torvalds 	return 0;
7881da177e4SLinus Torvalds }
7891da177e4SLinus Torvalds 
7901da177e4SLinus Torvalds 
7911da177e4SLinus Torvalds /*
7921da177e4SLinus Torvalds  * This is a device reset.  This is handled by sending a special command
7931da177e4SLinus Torvalds  * to the device.
7941da177e4SLinus Torvalds  */
79555b28f9fSOndrej Zary static int aha1542_dev_reset(struct scsi_cmnd *cmd)
7961da177e4SLinus Torvalds {
7971b0224b0SOndrej Zary 	struct Scsi_Host *sh = cmd->device->host;
7981b0224b0SOndrej Zary 	struct aha1542_hostdata *aha1542 = shost_priv(sh);
7991da177e4SLinus Torvalds 	unsigned long flags;
800e98878f7SOndrej Zary 	struct mailbox *mb = aha1542->mb;
80155b28f9fSOndrej Zary 	u8 target = cmd->device->id;
80255b28f9fSOndrej Zary 	u8 lun = cmd->device->lun;
8031da177e4SLinus Torvalds 	int mbo;
804e98878f7SOndrej Zary 	struct ccb *ccb = aha1542->ccb;
8051da177e4SLinus Torvalds 
8061b0224b0SOndrej Zary 	spin_lock_irqsave(sh->host_lock, flags);
807e98878f7SOndrej Zary 	mbo = aha1542->aha1542_last_mbo_used + 1;
8081da177e4SLinus Torvalds 	if (mbo >= AHA1542_MAILBOXES)
8091da177e4SLinus Torvalds 		mbo = 0;
8101da177e4SLinus Torvalds 
8111da177e4SLinus Torvalds 	do {
81255b28f9fSOndrej Zary 		if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL)
8131da177e4SLinus Torvalds 			break;
8141da177e4SLinus Torvalds 		mbo++;
8151da177e4SLinus Torvalds 		if (mbo >= AHA1542_MAILBOXES)
8161da177e4SLinus Torvalds 			mbo = 0;
817e98878f7SOndrej Zary 	} while (mbo != aha1542->aha1542_last_mbo_used);
8181da177e4SLinus Torvalds 
81955b28f9fSOndrej Zary 	if (mb[mbo].status || aha1542->int_cmds[mbo])
8201da177e4SLinus Torvalds 		panic("Unable to find empty mailbox for aha1542.\n");
8211da177e4SLinus Torvalds 
82255b28f9fSOndrej Zary 	aha1542->int_cmds[mbo] = cmd;	/* This will effectively
8231da177e4SLinus Torvalds 					   prevent someone else from
8241da177e4SLinus Torvalds 					   screwing with this cdb. */
8251da177e4SLinus Torvalds 
826e98878f7SOndrej Zary 	aha1542->aha1542_last_mbo_used = mbo;
8271da177e4SLinus Torvalds 
82810be6250SOndrej Zary 	any2scsi(mb[mbo].ccbptr, isa_virt_to_bus(&ccb[mbo]));	/* This gets trashed for some reason */
8291da177e4SLinus Torvalds 
8301da177e4SLinus Torvalds 	memset(&ccb[mbo], 0, sizeof(struct ccb));
8311da177e4SLinus Torvalds 
8321da177e4SLinus Torvalds 	ccb[mbo].op = 0x81;	/* BUS DEVICE RESET */
8331da177e4SLinus Torvalds 
8341da177e4SLinus Torvalds 	ccb[mbo].idlun = (target & 7) << 5 | (lun & 7);		/*SCSI Target Id */
8351da177e4SLinus Torvalds 
8361da177e4SLinus Torvalds 	ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
8371da177e4SLinus Torvalds 	ccb[mbo].commlinkid = 0;
8381da177e4SLinus Torvalds 
8391da177e4SLinus Torvalds 	/*
8401da177e4SLinus Torvalds 	 * Now tell the 1542 to flush all pending commands for this
8411da177e4SLinus Torvalds 	 * target
8421da177e4SLinus Torvalds 	 */
8431b0224b0SOndrej Zary 	aha1542_outb(sh->io_port, CMD_START_SCSI);
8441b0224b0SOndrej Zary 	spin_unlock_irqrestore(sh->host_lock, flags);
8451da177e4SLinus Torvalds 
84655b28f9fSOndrej Zary 	scmd_printk(KERN_WARNING, cmd,
847017560fcSJeff Garzik 		"Trying device reset for target\n");
8481da177e4SLinus Torvalds 
8491da177e4SLinus Torvalds 	return SUCCESS;
8501da177e4SLinus Torvalds }
8511da177e4SLinus Torvalds 
85255b28f9fSOndrej Zary static int aha1542_reset(struct scsi_cmnd *cmd, u8 reset_cmd)
8531da177e4SLinus Torvalds {
8541b0224b0SOndrej Zary 	struct Scsi_Host *sh = cmd->device->host;
8551b0224b0SOndrej Zary 	struct aha1542_hostdata *aha1542 = shost_priv(sh);
8561b0224b0SOndrej Zary 	unsigned long flags;
8571da177e4SLinus Torvalds 	int i;
8581da177e4SLinus Torvalds 
8591b0224b0SOndrej Zary 	spin_lock_irqsave(sh->host_lock, flags);
8601da177e4SLinus Torvalds 	/*
8611da177e4SLinus Torvalds 	 * This does a scsi reset for all devices on the bus.
8621da177e4SLinus Torvalds 	 * In principle, we could also reset the 1542 - should
8631da177e4SLinus Torvalds 	 * we do this?  Try this first, and we can add that later
8641da177e4SLinus Torvalds 	 * if it turns out to be useful.
8651da177e4SLinus Torvalds 	 */
86655b28f9fSOndrej Zary 	outb(reset_cmd, CONTROL(cmd->device->host->io_port));
8671da177e4SLinus Torvalds 
86855b28f9fSOndrej Zary 	if (!wait_mask(STATUS(cmd->device->host->io_port),
8697061dec4SOndrej Zary 	     STATMASK, IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0)) {
8701b0224b0SOndrej Zary 		spin_unlock_irqrestore(sh->host_lock, flags);
871a13b3722SOndrej Zary 		return FAILED;
872a13b3722SOndrej Zary 	}
8731b0224b0SOndrej Zary 
8741da177e4SLinus Torvalds 	/*
8751da177e4SLinus Torvalds 	 * We need to do this too before the 1542 can interact with
8768537cba8SOndrej Zary 	 * us again after host reset.
8771da177e4SLinus Torvalds 	 */
8788537cba8SOndrej Zary 	if (reset_cmd & HRST)
87968ea9de3SOndrej Zary 		setup_mailboxes(cmd->device->host);
8801b0224b0SOndrej Zary 
8811da177e4SLinus Torvalds 	/*
8821da177e4SLinus Torvalds 	 * Now try to pick up the pieces.  For all pending commands,
8831da177e4SLinus Torvalds 	 * free any internal data structures, and basically clear things
8841da177e4SLinus Torvalds 	 * out.  We do not try and restart any commands or anything -
8851da177e4SLinus Torvalds 	 * the strategy handler takes care of that crap.
8861da177e4SLinus Torvalds 	 */
8872906b3ceSOndrej Zary 	shost_printk(KERN_WARNING, cmd->device->host, "Sent BUS RESET to scsi host %d\n", cmd->device->host->host_no);
8881da177e4SLinus Torvalds 
8891da177e4SLinus Torvalds 	for (i = 0; i < AHA1542_MAILBOXES; i++) {
89055b28f9fSOndrej Zary 		if (aha1542->int_cmds[i] != NULL) {
89155b28f9fSOndrej Zary 			struct scsi_cmnd *tmp_cmd;
89255b28f9fSOndrej Zary 			tmp_cmd = aha1542->int_cmds[i];
8931da177e4SLinus Torvalds 
89455b28f9fSOndrej Zary 			if (tmp_cmd->device->soft_reset) {
8951da177e4SLinus Torvalds 				/*
8961da177e4SLinus Torvalds 				 * If this device implements the soft reset option,
8971da177e4SLinus Torvalds 				 * then it is still holding onto the command, and
8981da177e4SLinus Torvalds 				 * may yet complete it.  In this case, we don't
8991da177e4SLinus Torvalds 				 * flush the data.
9001da177e4SLinus Torvalds 				 */
9011da177e4SLinus Torvalds 				continue;
9021da177e4SLinus Torvalds 			}
90355b28f9fSOndrej Zary 			kfree(tmp_cmd->host_scribble);
90455b28f9fSOndrej Zary 			tmp_cmd->host_scribble = NULL;
90555b28f9fSOndrej Zary 			aha1542->int_cmds[i] = NULL;
906e98878f7SOndrej Zary 			aha1542->mb[i].status = 0;
9071da177e4SLinus Torvalds 		}
9081da177e4SLinus Torvalds 	}
9091da177e4SLinus Torvalds 
9101b0224b0SOndrej Zary 	spin_unlock_irqrestore(sh->host_lock, flags);
9111da177e4SLinus Torvalds 	return SUCCESS;
9121da177e4SLinus Torvalds }
9131da177e4SLinus Torvalds 
91455b28f9fSOndrej Zary static int aha1542_bus_reset(struct scsi_cmnd *cmd)
9158537cba8SOndrej Zary {
91655b28f9fSOndrej Zary 	return aha1542_reset(cmd, SCRST);
9178537cba8SOndrej Zary }
9188537cba8SOndrej Zary 
91955b28f9fSOndrej Zary static int aha1542_host_reset(struct scsi_cmnd *cmd)
9208537cba8SOndrej Zary {
92155b28f9fSOndrej Zary 	return aha1542_reset(cmd, HRST | SCRST);
9228537cba8SOndrej Zary }
9238537cba8SOndrej Zary 
9241da177e4SLinus Torvalds static int aha1542_biosparam(struct scsi_device *sdev,
92517787a09SOndrej Zary 		struct block_device *bdev, sector_t capacity, int geom[])
9261da177e4SLinus Torvalds {
927e98878f7SOndrej Zary 	struct aha1542_hostdata *aha1542 = shost_priv(sdev->host);
9281da177e4SLinus Torvalds 
92917787a09SOndrej Zary 	if (capacity >= 0x200000 &&
93017787a09SOndrej Zary 			aha1542->bios_translation == BIOS_TRANSLATION_25563) {
9311da177e4SLinus Torvalds 		/* Please verify that this is the same as what DOS returns */
93217787a09SOndrej Zary 		geom[0] = 255;	/* heads */
93317787a09SOndrej Zary 		geom[1] = 63;	/* sectors */
9341da177e4SLinus Torvalds 	} else {
93517787a09SOndrej Zary 		geom[0] = 64;	/* heads */
93617787a09SOndrej Zary 		geom[1] = 32;	/* sectors */
9371da177e4SLinus Torvalds 	}
93817787a09SOndrej Zary 	geom[2] = sector_div(capacity, geom[0] * geom[1]);	/* cylinders */
9391da177e4SLinus Torvalds 
9401da177e4SLinus Torvalds 	return 0;
9411da177e4SLinus Torvalds }
9421da177e4SLinus Torvalds MODULE_LICENSE("GPL");
9431da177e4SLinus Torvalds 
944d0be4a7dSChristoph Hellwig static struct scsi_host_template driver_template = {
945643a7c43SOndrej Zary 	.module			= THIS_MODULE,
9461da177e4SLinus Torvalds 	.proc_name		= "aha1542",
9471da177e4SLinus Torvalds 	.name			= "Adaptec 1542",
9481da177e4SLinus Torvalds 	.queuecommand		= aha1542_queuecommand,
9491da177e4SLinus Torvalds 	.eh_device_reset_handler= aha1542_dev_reset,
9501da177e4SLinus Torvalds 	.eh_bus_reset_handler	= aha1542_bus_reset,
9511da177e4SLinus Torvalds 	.eh_host_reset_handler	= aha1542_host_reset,
9521da177e4SLinus Torvalds 	.bios_param		= aha1542_biosparam,
9531da177e4SLinus Torvalds 	.can_queue		= AHA1542_MAILBOXES,
9541da177e4SLinus Torvalds 	.this_id		= 7,
95510be6250SOndrej Zary 	.sg_tablesize		= 16,
9561da177e4SLinus Torvalds 	.unchecked_isa_dma	= 1,
9571da177e4SLinus Torvalds 	.use_clustering		= ENABLE_CLUSTERING,
9581da177e4SLinus Torvalds };
959643a7c43SOndrej Zary 
960643a7c43SOndrej Zary static int aha1542_isa_match(struct device *pdev, unsigned int ndev)
961643a7c43SOndrej Zary {
962643a7c43SOndrej Zary 	struct Scsi_Host *sh = aha1542_hw_init(&driver_template, pdev, ndev);
963643a7c43SOndrej Zary 
964643a7c43SOndrej Zary 	if (!sh)
965643a7c43SOndrej Zary 		return 0;
966643a7c43SOndrej Zary 
967643a7c43SOndrej Zary 	dev_set_drvdata(pdev, sh);
968643a7c43SOndrej Zary 	return 1;
969643a7c43SOndrej Zary }
970643a7c43SOndrej Zary 
971643a7c43SOndrej Zary static int aha1542_isa_remove(struct device *pdev,
972643a7c43SOndrej Zary 				    unsigned int ndev)
973643a7c43SOndrej Zary {
974643a7c43SOndrej Zary 	aha1542_release(dev_get_drvdata(pdev));
975643a7c43SOndrej Zary 	dev_set_drvdata(pdev, NULL);
976643a7c43SOndrej Zary 	return 0;
977643a7c43SOndrej Zary }
978643a7c43SOndrej Zary 
979643a7c43SOndrej Zary static struct isa_driver aha1542_isa_driver = {
980643a7c43SOndrej Zary 	.match		= aha1542_isa_match,
981643a7c43SOndrej Zary 	.remove		= aha1542_isa_remove,
982643a7c43SOndrej Zary 	.driver		= {
983643a7c43SOndrej Zary 		.name	= "aha1542"
984643a7c43SOndrej Zary 	},
985643a7c43SOndrej Zary };
986643a7c43SOndrej Zary static int isa_registered;
987643a7c43SOndrej Zary 
988643a7c43SOndrej Zary #ifdef CONFIG_PNP
989643a7c43SOndrej Zary static struct pnp_device_id aha1542_pnp_ids[] = {
990643a7c43SOndrej Zary 	{ .id = "ADP1542" },
991643a7c43SOndrej Zary 	{ .id = "" }
992643a7c43SOndrej Zary };
993643a7c43SOndrej Zary MODULE_DEVICE_TABLE(pnp, aha1542_pnp_ids);
994643a7c43SOndrej Zary 
995643a7c43SOndrej Zary static int aha1542_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *id)
996643a7c43SOndrej Zary {
997643a7c43SOndrej Zary 	int indx;
998643a7c43SOndrej Zary 	struct Scsi_Host *sh;
999643a7c43SOndrej Zary 
1000f71429abSOndrej Zary 	for (indx = 0; indx < ARRAY_SIZE(io); indx++) {
1001f71429abSOndrej Zary 		if (io[indx])
1002643a7c43SOndrej Zary 			continue;
1003643a7c43SOndrej Zary 
1004643a7c43SOndrej Zary 		if (pnp_activate_dev(pdev) < 0)
1005643a7c43SOndrej Zary 			continue;
1006643a7c43SOndrej Zary 
1007f71429abSOndrej Zary 		io[indx] = pnp_port_start(pdev, 0);
1008643a7c43SOndrej Zary 
1009643a7c43SOndrej Zary 		/* The card can be queried for its DMA, we have
1010643a7c43SOndrej Zary 		   the DMA set up that is enough */
1011643a7c43SOndrej Zary 
10122906b3ceSOndrej Zary 		dev_info(&pdev->dev, "ISAPnP found an AHA1535 at I/O 0x%03X", io[indx]);
1013643a7c43SOndrej Zary 	}
1014643a7c43SOndrej Zary 
1015643a7c43SOndrej Zary 	sh = aha1542_hw_init(&driver_template, &pdev->dev, indx);
1016643a7c43SOndrej Zary 	if (!sh)
1017643a7c43SOndrej Zary 		return -ENODEV;
1018643a7c43SOndrej Zary 
1019643a7c43SOndrej Zary 	pnp_set_drvdata(pdev, sh);
1020643a7c43SOndrej Zary 	return 0;
1021643a7c43SOndrej Zary }
1022643a7c43SOndrej Zary 
1023643a7c43SOndrej Zary static void aha1542_pnp_remove(struct pnp_dev *pdev)
1024643a7c43SOndrej Zary {
1025643a7c43SOndrej Zary 	aha1542_release(pnp_get_drvdata(pdev));
1026643a7c43SOndrej Zary 	pnp_set_drvdata(pdev, NULL);
1027643a7c43SOndrej Zary }
1028643a7c43SOndrej Zary 
1029643a7c43SOndrej Zary static struct pnp_driver aha1542_pnp_driver = {
1030643a7c43SOndrej Zary 	.name		= "aha1542",
1031643a7c43SOndrej Zary 	.id_table	= aha1542_pnp_ids,
1032643a7c43SOndrej Zary 	.probe		= aha1542_pnp_probe,
1033643a7c43SOndrej Zary 	.remove		= aha1542_pnp_remove,
1034643a7c43SOndrej Zary };
1035643a7c43SOndrej Zary static int pnp_registered;
1036643a7c43SOndrej Zary #endif /* CONFIG_PNP */
1037643a7c43SOndrej Zary 
1038643a7c43SOndrej Zary static int __init aha1542_init(void)
1039643a7c43SOndrej Zary {
1040643a7c43SOndrej Zary 	int ret = 0;
1041643a7c43SOndrej Zary 
1042643a7c43SOndrej Zary #ifdef CONFIG_PNP
1043643a7c43SOndrej Zary 	if (isapnp) {
1044643a7c43SOndrej Zary 		ret = pnp_register_driver(&aha1542_pnp_driver);
1045643a7c43SOndrej Zary 		if (!ret)
1046643a7c43SOndrej Zary 			pnp_registered = 1;
1047643a7c43SOndrej Zary 	}
1048643a7c43SOndrej Zary #endif
1049643a7c43SOndrej Zary 	ret = isa_register_driver(&aha1542_isa_driver, MAXBOARDS);
1050643a7c43SOndrej Zary 	if (!ret)
1051643a7c43SOndrej Zary 		isa_registered = 1;
1052643a7c43SOndrej Zary 
1053643a7c43SOndrej Zary #ifdef CONFIG_PNP
1054643a7c43SOndrej Zary 	if (pnp_registered)
1055643a7c43SOndrej Zary 		ret = 0;
1056643a7c43SOndrej Zary #endif
1057643a7c43SOndrej Zary 	if (isa_registered)
1058643a7c43SOndrej Zary 		ret = 0;
1059643a7c43SOndrej Zary 
1060643a7c43SOndrej Zary 	return ret;
1061643a7c43SOndrej Zary }
1062643a7c43SOndrej Zary 
1063643a7c43SOndrej Zary static void __exit aha1542_exit(void)
1064643a7c43SOndrej Zary {
1065643a7c43SOndrej Zary #ifdef CONFIG_PNP
1066643a7c43SOndrej Zary 	if (pnp_registered)
1067643a7c43SOndrej Zary 		pnp_unregister_driver(&aha1542_pnp_driver);
1068643a7c43SOndrej Zary #endif
1069643a7c43SOndrej Zary 	if (isa_registered)
1070643a7c43SOndrej Zary 		isa_unregister_driver(&aha1542_isa_driver);
1071643a7c43SOndrej Zary }
1072643a7c43SOndrej Zary 
1073643a7c43SOndrej Zary module_init(aha1542_init);
1074643a7c43SOndrej Zary module_exit(aha1542_exit);
1075