xref: /openbmc/linux/drivers/scsi/aha1542.c (revision 7061dec40c07265f819ae0a6842846f74f889aa9)
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 };
34f71429abSOndrej Zary module_param_array(io, int, 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 {
940c2b6481SOndrej Zary 	while (1) {
952906b3ceSOndrej Zary 		if (!wait_mask(STATUS(base), CDF, 0, CDF, 0))
960c2b6481SOndrej Zary 			return 1;
971b0224b0SOndrej Zary 		if (inb(STATUS(base)) & CDF)
981da177e4SLinus Torvalds 			continue;
99cad2fc72SOndrej Zary 		outb(val, DATA(base));
1001da177e4SLinus Torvalds 		return 0;
1011da177e4SLinus Torvalds 	}
1020c2b6481SOndrej Zary }
1030c2b6481SOndrej Zary 
104cad2fc72SOndrej Zary static int aha1542_out(unsigned int base, u8 *buf, int len)
1050c2b6481SOndrej Zary {
1061da177e4SLinus Torvalds 	while (len--) {
1071b0224b0SOndrej Zary 		if (!wait_mask(STATUS(base), CDF, 0, CDF, 0))
1081da177e4SLinus Torvalds 			return 1;
109cad2fc72SOndrej Zary 		outb(*buf++, DATA(base));
1100c2b6481SOndrej Zary 	}
11123e6940aSOndrej Zary 	if (!wait_mask(INTRFLAGS(base), INTRMASK, HACC, 0, 0))
11223e6940aSOndrej Zary 		return 1;
1130c2b6481SOndrej Zary 
1140c2b6481SOndrej Zary 	return 0;
1150c2b6481SOndrej Zary }
1161da177e4SLinus Torvalds 
1171da177e4SLinus Torvalds /* Only used at boot time, so we do not need to worry about latency as much
1181da177e4SLinus Torvalds    here */
1191da177e4SLinus Torvalds 
120cad2fc72SOndrej Zary static int aha1542_in(unsigned int base, u8 *buf, int len, int timeout)
1211da177e4SLinus Torvalds {
1221da177e4SLinus Torvalds 	while (len--) {
1231b0224b0SOndrej Zary 		if (!wait_mask(STATUS(base), DF, DF, 0, timeout))
1241da177e4SLinus Torvalds 			return 1;
125cad2fc72SOndrej Zary 		*buf++ = inb(DATA(base));
126a13b3722SOndrej Zary 	}
127a13b3722SOndrej Zary 	return 0;
128a13b3722SOndrej Zary }
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds static int makecode(unsigned hosterr, unsigned scsierr)
1311da177e4SLinus Torvalds {
1321da177e4SLinus Torvalds 	switch (hosterr) {
1331da177e4SLinus Torvalds 	case 0x0:
1341da177e4SLinus Torvalds 	case 0xa:		/* Linked command complete without error and linked normally */
1351da177e4SLinus Torvalds 	case 0xb:		/* Linked command complete without error, interrupt generated */
1361da177e4SLinus Torvalds 		hosterr = 0;
1371da177e4SLinus Torvalds 		break;
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds 	case 0x11:		/* Selection time out-The initiator selection or target
1401da177e4SLinus Torvalds 				   reselection was not complete within the SCSI Time out period */
1411da177e4SLinus Torvalds 		hosterr = DID_TIME_OUT;
1421da177e4SLinus Torvalds 		break;
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds 	case 0x12:		/* Data overrun/underrun-The target attempted to transfer more data
1451da177e4SLinus Torvalds 				   than was allocated by the Data Length field or the sum of the
1461da177e4SLinus Torvalds 				   Scatter / Gather Data Length fields. */
1471da177e4SLinus Torvalds 
1481da177e4SLinus Torvalds 	case 0x13:		/* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
1491da177e4SLinus Torvalds 
1501da177e4SLinus Torvalds 	case 0x15:		/* MBO command was not 00, 01 or 02-The first byte of the CB was
1511da177e4SLinus Torvalds 				   invalid. This usually indicates a software failure. */
1521da177e4SLinus Torvalds 
1531da177e4SLinus Torvalds 	case 0x16:		/* Invalid CCB Operation Code-The first byte of the CCB was invalid.
1541da177e4SLinus Torvalds 				   This usually indicates a software failure. */
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds 	case 0x17:		/* Linked CCB does not have the same LUN-A subsequent CCB of a set
1571da177e4SLinus Torvalds 				   of linked CCB's does not specify the same logical unit number as
1581da177e4SLinus Torvalds 				   the first. */
1591da177e4SLinus Torvalds 	case 0x18:		/* Invalid Target Direction received from Host-The direction of a
1601da177e4SLinus Torvalds 				   Target Mode CCB was invalid. */
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds 	case 0x19:		/* Duplicate CCB Received in Target Mode-More than once CCB was
1631da177e4SLinus Torvalds 				   received to service data transfer between the same target LUN
1641da177e4SLinus Torvalds 				   and initiator SCSI ID in the same direction. */
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds 	case 0x1a:		/* Invalid CCB or Segment List Parameter-A segment list with a zero
1671da177e4SLinus Torvalds 				   length segment or invalid segment list boundaries was received.
1681da177e4SLinus Torvalds 				   A CCB parameter was invalid. */
169fde1fb8aSOndrej Zary #ifdef DEBUG
170fde1fb8aSOndrej Zary 		printk("Aha1542: %x %x\n", hosterr, scsierr);
171fde1fb8aSOndrej Zary #endif
1721da177e4SLinus Torvalds 		hosterr = DID_ERROR;	/* Couldn't find any better */
1731da177e4SLinus Torvalds 		break;
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds 	case 0x14:		/* Target bus phase sequence failure-An invalid bus phase or bus
1761da177e4SLinus Torvalds 				   phase sequence was requested by the target. The host adapter
1771da177e4SLinus Torvalds 				   will generate a SCSI Reset Condition, notifying the host with
1781da177e4SLinus Torvalds 				   a SCRD interrupt */
1791da177e4SLinus Torvalds 		hosterr = DID_RESET;
1801da177e4SLinus Torvalds 		break;
1811da177e4SLinus Torvalds 	default:
1821da177e4SLinus Torvalds 		printk(KERN_ERR "aha1542: makecode: unknown hoststatus %x\n", hosterr);
1831da177e4SLinus Torvalds 		break;
1841da177e4SLinus Torvalds 	}
1851da177e4SLinus Torvalds 	return scsierr | (hosterr << 16);
1861da177e4SLinus Torvalds }
1871da177e4SLinus Torvalds 
18868ea9de3SOndrej Zary static int aha1542_test_port(struct Scsi_Host *sh)
1891da177e4SLinus Torvalds {
190cb5b570cSOndrej Zary 	u8 inquiry_result[4];
191cad2fc72SOndrej Zary 	int i;
1921da177e4SLinus Torvalds 
1931da177e4SLinus Torvalds 	/* Quick and dirty test for presence of the card. */
19468ea9de3SOndrej Zary 	if (inb(STATUS(sh->io_port)) == 0xff)
1951da177e4SLinus Torvalds 		return 0;
1961da177e4SLinus Torvalds 
1971da177e4SLinus Torvalds 	/* Reset the adapter. I ought to make a hard reset, but it's not really necessary */
1981da177e4SLinus Torvalds 
1991da177e4SLinus Torvalds 	/* In case some other card was probing here, reset interrupts */
20068ea9de3SOndrej Zary 	aha1542_intr_reset(sh->io_port);	/* reset interrupts, so they don't block */
2011da177e4SLinus Torvalds 
20268ea9de3SOndrej Zary 	outb(SRST | IRST /*|SCRST */ , CONTROL(sh->io_port));
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds 	mdelay(20);		/* Wait a little bit for things to settle down. */
2051da177e4SLinus Torvalds 
2061da177e4SLinus Torvalds 	/* Expect INIT and IDLE, any of the others are bad */
20768ea9de3SOndrej Zary 	if (!wait_mask(STATUS(sh->io_port), STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0))
208a13b3722SOndrej Zary 		return 0;
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds 	/* Shouldn't have generated any interrupts during reset */
21168ea9de3SOndrej Zary 	if (inb(INTRFLAGS(sh->io_port)) & INTRMASK)
212a13b3722SOndrej Zary 		return 0;
2131da177e4SLinus Torvalds 
2141da177e4SLinus Torvalds 	/* Perform a host adapter inquiry instead so we do not need to set
2151da177e4SLinus Torvalds 	   up the mailboxes ahead of time */
2161da177e4SLinus Torvalds 
21768ea9de3SOndrej Zary 	aha1542_outb(sh->io_port, CMD_INQUIRY);
2181da177e4SLinus Torvalds 
219cad2fc72SOndrej Zary 	for (i = 0; i < 4; i++) {
22068ea9de3SOndrej Zary 		if (!wait_mask(STATUS(sh->io_port), DF, DF, 0, 0))
221a13b3722SOndrej Zary 			return 0;
22268ea9de3SOndrej Zary 		inquiry_result[i] = inb(DATA(sh->io_port));
2231da177e4SLinus Torvalds 	}
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds 	/* Reading port should reset DF */
22668ea9de3SOndrej Zary 	if (inb(STATUS(sh->io_port)) & DF)
227a13b3722SOndrej Zary 		return 0;
2281da177e4SLinus Torvalds 
2291da177e4SLinus Torvalds 	/* When HACC, command is completed, and we're though testing */
23068ea9de3SOndrej Zary 	if (!wait_mask(INTRFLAGS(sh->io_port), HACC, HACC, 0, 0))
231a13b3722SOndrej Zary 		return 0;
2321da177e4SLinus Torvalds 
2331da177e4SLinus Torvalds 	/* Clear interrupts */
23468ea9de3SOndrej Zary 	outb(IRST, CONTROL(sh->io_port));
2351da177e4SLinus Torvalds 
236bdebe224SOndrej Zary 	return 1;
2371da177e4SLinus Torvalds }
2381da177e4SLinus Torvalds 
2391b0224b0SOndrej Zary static irqreturn_t aha1542_interrupt(int irq, void *dev_id)
2401da177e4SLinus Torvalds {
2411b0224b0SOndrej Zary 	struct Scsi_Host *sh = dev_id;
242c2532f68SOndrej Zary 	struct aha1542_hostdata *aha1542 = shost_priv(sh);
24355b28f9fSOndrej Zary 	void (*my_done)(struct scsi_cmnd *) = NULL;
2441da177e4SLinus Torvalds 	int errstatus, mbi, mbo, mbistatus;
2451da177e4SLinus Torvalds 	int number_serviced;
2461da177e4SLinus Torvalds 	unsigned long flags;
24755b28f9fSOndrej Zary 	struct scsi_cmnd *tmp_cmd;
2481da177e4SLinus Torvalds 	int flag;
249e98878f7SOndrej Zary 	struct mailbox *mb = aha1542->mb;
250e98878f7SOndrej Zary 	struct ccb *ccb = aha1542->ccb;
2511da177e4SLinus Torvalds 
2521da177e4SLinus Torvalds #ifdef DEBUG
2531da177e4SLinus Torvalds 	{
254c2532f68SOndrej Zary 		flag = inb(INTRFLAGS(sh->io_port));
2552906b3ceSOndrej Zary 		shost_printk(KERN_DEBUG, sh, "aha1542_intr_handle: ");
2561da177e4SLinus Torvalds 		if (!(flag & ANYINTR))
2571da177e4SLinus Torvalds 			printk("no interrupt?");
2581da177e4SLinus Torvalds 		if (flag & MBIF)
2591da177e4SLinus Torvalds 			printk("MBIF ");
2601da177e4SLinus Torvalds 		if (flag & MBOA)
2611da177e4SLinus Torvalds 			printk("MBOF ");
2621da177e4SLinus Torvalds 		if (flag & HACC)
2631da177e4SLinus Torvalds 			printk("HACC ");
2641da177e4SLinus Torvalds 		if (flag & SCRD)
2651da177e4SLinus Torvalds 			printk("SCRD ");
266c2532f68SOndrej Zary 		printk("status %02x\n", inb(STATUS(sh->io_port)));
2671da177e4SLinus Torvalds 	};
2681da177e4SLinus Torvalds #endif
2691da177e4SLinus Torvalds 	number_serviced = 0;
2701da177e4SLinus Torvalds 
2711b0224b0SOndrej Zary 	spin_lock_irqsave(sh->host_lock, flags);
2721b0224b0SOndrej Zary 	while (1) {
273c2532f68SOndrej Zary 		flag = inb(INTRFLAGS(sh->io_port));
2741da177e4SLinus Torvalds 
2751da177e4SLinus Torvalds 		/* Check for unusual interrupts.  If any of these happen, we should
2761da177e4SLinus Torvalds 		   probably do something special, but for now just printing a message
2771da177e4SLinus Torvalds 		   is sufficient.  A SCSI reset detected is something that we really
2781da177e4SLinus Torvalds 		   need to deal with in some way. */
2791da177e4SLinus Torvalds 		if (flag & ~MBIF) {
2801da177e4SLinus Torvalds 			if (flag & MBOA)
2811da177e4SLinus Torvalds 				printk("MBOF ");
2821da177e4SLinus Torvalds 			if (flag & HACC)
2831da177e4SLinus Torvalds 				printk("HACC ");
284dfd7c991SOndrej Zary 			if (flag & SCRD)
2851da177e4SLinus Torvalds 				printk("SCRD ");
2861da177e4SLinus Torvalds 		}
287c2532f68SOndrej Zary 		aha1542_intr_reset(sh->io_port);
2881da177e4SLinus Torvalds 
289e98878f7SOndrej Zary 		mbi = aha1542->aha1542_last_mbi_used + 1;
2901da177e4SLinus Torvalds 		if (mbi >= 2 * AHA1542_MAILBOXES)
2911da177e4SLinus Torvalds 			mbi = AHA1542_MAILBOXES;
2921da177e4SLinus Torvalds 
2931da177e4SLinus Torvalds 		do {
2941da177e4SLinus Torvalds 			if (mb[mbi].status != 0)
2951da177e4SLinus Torvalds 				break;
2961da177e4SLinus Torvalds 			mbi++;
2971da177e4SLinus Torvalds 			if (mbi >= 2 * AHA1542_MAILBOXES)
2981da177e4SLinus Torvalds 				mbi = AHA1542_MAILBOXES;
299e98878f7SOndrej Zary 		} while (mbi != aha1542->aha1542_last_mbi_used);
3001da177e4SLinus Torvalds 
3011da177e4SLinus Torvalds 		if (mb[mbi].status == 0) {
3021b0224b0SOndrej Zary 			spin_unlock_irqrestore(sh->host_lock, flags);
3031da177e4SLinus Torvalds 			/* Hmm, no mail.  Must have read it the last time around */
304dfd7c991SOndrej Zary 			if (!number_serviced)
3052906b3ceSOndrej Zary 				shost_printk(KERN_WARNING, sh, "interrupt received, but no mail.\n");
3061b0224b0SOndrej Zary 			return IRQ_HANDLED;
3071da177e4SLinus Torvalds 		};
3081da177e4SLinus Torvalds 
30910be6250SOndrej Zary 		mbo = (scsi2int(mb[mbi].ccbptr) - (isa_virt_to_bus(&ccb[0]))) / sizeof(struct ccb);
3101da177e4SLinus Torvalds 		mbistatus = mb[mbi].status;
3111da177e4SLinus Torvalds 		mb[mbi].status = 0;
312e98878f7SOndrej Zary 		aha1542->aha1542_last_mbi_used = mbi;
3131da177e4SLinus Torvalds 
3141da177e4SLinus Torvalds #ifdef DEBUG
3151da177e4SLinus Torvalds 		if (ccb[mbo].tarstat | ccb[mbo].hastat)
3162906b3ceSOndrej Zary 			shost_printk(KERN_DEBUG, sh, "aha1542_command: returning %x (status %d)\n",
3171da177e4SLinus Torvalds 			       ccb[mbo].tarstat + ((int) ccb[mbo].hastat << 16), mb[mbi].status);
3181da177e4SLinus Torvalds #endif
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds 		if (mbistatus == 3)
3211da177e4SLinus Torvalds 			continue;	/* Aborted command not found */
3221da177e4SLinus Torvalds 
3231da177e4SLinus Torvalds #ifdef DEBUG
3242906b3ceSOndrej Zary 		shost_printk(KERN_DEBUG, sh, "...done %d %d\n", mbo, mbi);
3251da177e4SLinus Torvalds #endif
3261da177e4SLinus Torvalds 
32755b28f9fSOndrej Zary 		tmp_cmd = aha1542->int_cmds[mbo];
3281da177e4SLinus Torvalds 
32955b28f9fSOndrej Zary 		if (!tmp_cmd || !tmp_cmd->scsi_done) {
3301b0224b0SOndrej Zary 			spin_unlock_irqrestore(sh->host_lock, flags);
3312906b3ceSOndrej Zary 			shost_printk(KERN_WARNING, sh, "Unexpected interrupt\n");
3322906b3ceSOndrej Zary 			shost_printk(KERN_WARNING, sh, "tarstat=%x, hastat=%x idlun=%x ccb#=%d\n", ccb[mbo].tarstat,
3331da177e4SLinus Torvalds 			       ccb[mbo].hastat, ccb[mbo].idlun, mbo);
3341b0224b0SOndrej Zary 			return IRQ_HANDLED;
3351da177e4SLinus Torvalds 		}
33655b28f9fSOndrej Zary 		my_done = tmp_cmd->scsi_done;
33755b28f9fSOndrej Zary 		kfree(tmp_cmd->host_scribble);
33855b28f9fSOndrej Zary 		tmp_cmd->host_scribble = NULL;
3391da177e4SLinus Torvalds 		/* Fetch the sense data, and tuck it away, in the required slot.  The
3401da177e4SLinus Torvalds 		   Adaptec automatically fetches it, and there is no guarantee that
3411da177e4SLinus Torvalds 		   we will still have it in the cdb when we come back */
3421da177e4SLinus Torvalds 		if (ccb[mbo].tarstat == 2)
34355b28f9fSOndrej Zary 			memcpy(tmp_cmd->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen],
344b80ca4f7SFUJITA Tomonori 			       SCSI_SENSE_BUFFERSIZE);
3451da177e4SLinus Torvalds 
3461da177e4SLinus Torvalds 
3471da177e4SLinus Torvalds 		/* is there mail :-) */
3481da177e4SLinus Torvalds 
3491da177e4SLinus Torvalds 		/* more error checking left out here */
3501da177e4SLinus Torvalds 		if (mbistatus != 1)
3511da177e4SLinus Torvalds 			/* This is surely wrong, but I don't know what's right */
3521da177e4SLinus Torvalds 			errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat);
3531da177e4SLinus Torvalds 		else
3541da177e4SLinus Torvalds 			errstatus = 0;
3551da177e4SLinus Torvalds 
3561da177e4SLinus Torvalds #ifdef DEBUG
3571da177e4SLinus Torvalds 		if (errstatus)
3582906b3ceSOndrej Zary 			shost_printk(KERN_DEBUG, sh, "(aha1542 error:%x %x %x) ", errstatus,
3591da177e4SLinus Torvalds 			       ccb[mbo].hastat, ccb[mbo].tarstat);
3606ddc8cf4SOndrej Zary 		if (ccb[mbo].tarstat == 2)
3616ddc8cf4SOndrej Zary 			print_hex_dump_bytes("sense: ", DUMP_PREFIX_NONE, &ccb[mbo].cdb[ccb[mbo].cdblen], 12);
362fde1fb8aSOndrej Zary 		if (errstatus)
363fde1fb8aSOndrej Zary 			printk("aha1542_intr_handle: returning %6x\n", errstatus);
364fde1fb8aSOndrej Zary #endif
36555b28f9fSOndrej Zary 		tmp_cmd->result = errstatus;
36655b28f9fSOndrej Zary 		aha1542->int_cmds[mbo] = NULL;	/* This effectively frees up the mailbox slot, as
3671da177e4SLinus Torvalds 						   far as queuecommand is concerned */
36855b28f9fSOndrej Zary 		my_done(tmp_cmd);
3691da177e4SLinus Torvalds 		number_serviced++;
3701da177e4SLinus Torvalds 	};
3711da177e4SLinus Torvalds }
3721da177e4SLinus Torvalds 
3731b0224b0SOndrej Zary static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
37409a44833SOndrej Zary {
3752906b3ceSOndrej Zary 	struct aha1542_hostdata *aha1542 = shost_priv(sh);
376cb5b570cSOndrej Zary 	u8 direction;
37755b28f9fSOndrej Zary 	u8 target = cmd->device->id;
37855b28f9fSOndrej Zary 	u8 lun = cmd->device->lun;
3791da177e4SLinus Torvalds 	unsigned long flags;
38055b28f9fSOndrej Zary 	int bufflen = scsi_bufflen(cmd);
3811da177e4SLinus Torvalds 	int mbo;
382e98878f7SOndrej Zary 	struct mailbox *mb = aha1542->mb;
383e98878f7SOndrej Zary 	struct ccb *ccb = aha1542->ccb;
3841da177e4SLinus Torvalds 
38555b28f9fSOndrej Zary 	if (*cmd->cmnd == REQUEST_SENSE) {
3861da177e4SLinus Torvalds 		/* Don't do the command - we have the sense data already */
38755b28f9fSOndrej Zary 		cmd->result = 0;
3881b0224b0SOndrej Zary 		cmd->scsi_done(cmd);
3891da177e4SLinus Torvalds 		return 0;
3901da177e4SLinus Torvalds 	}
3911da177e4SLinus Torvalds #ifdef DEBUG
392764a0c7eSOndrej Zary 	{
393764a0c7eSOndrej Zary 		int i = -1;
39455b28f9fSOndrej Zary 		if (*cmd->cmnd == READ_10 || *cmd->cmnd == WRITE_10)
39555b28f9fSOndrej Zary 			i = xscsi2int(cmd->cmnd + 2);
39655b28f9fSOndrej Zary 		else if (*cmd->cmnd == READ_6 || *cmd->cmnd == WRITE_6)
39755b28f9fSOndrej Zary 			i = scsi2int(cmd->cmnd + 2);
398764a0c7eSOndrej Zary 		shost_printk(KERN_DEBUG, sh, "aha1542_queuecommand: dev %d cmd %02x pos %d len %d",
399764a0c7eSOndrej Zary 						target, *cmd->cmnd, i, bufflen);
4006ddc8cf4SOndrej Zary 		print_hex_dump_bytes("command: ", DUMP_PREFIX_NONE, cmd->cmnd, cmd->cmd_len);
401764a0c7eSOndrej Zary 	}
4021da177e4SLinus Torvalds #endif
4031da177e4SLinus Torvalds 	/* Use the outgoing mailboxes in a round-robin fashion, because this
4041da177e4SLinus Torvalds 	   is how the host adapter will scan for them */
4051da177e4SLinus Torvalds 
4061b0224b0SOndrej Zary 	spin_lock_irqsave(sh->host_lock, flags);
407e98878f7SOndrej Zary 	mbo = aha1542->aha1542_last_mbo_used + 1;
4081da177e4SLinus Torvalds 	if (mbo >= AHA1542_MAILBOXES)
4091da177e4SLinus Torvalds 		mbo = 0;
4101da177e4SLinus Torvalds 
4111da177e4SLinus Torvalds 	do {
41255b28f9fSOndrej Zary 		if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL)
4131da177e4SLinus Torvalds 			break;
4141da177e4SLinus Torvalds 		mbo++;
4151da177e4SLinus Torvalds 		if (mbo >= AHA1542_MAILBOXES)
4161da177e4SLinus Torvalds 			mbo = 0;
417e98878f7SOndrej Zary 	} while (mbo != aha1542->aha1542_last_mbo_used);
4181da177e4SLinus Torvalds 
41955b28f9fSOndrej Zary 	if (mb[mbo].status || aha1542->int_cmds[mbo])
4201da177e4SLinus Torvalds 		panic("Unable to find empty mailbox for aha1542.\n");
4211da177e4SLinus Torvalds 
42255b28f9fSOndrej Zary 	aha1542->int_cmds[mbo] = cmd;	/* This will effectively prevent someone else from
4231da177e4SLinus Torvalds 					   screwing with this cdb. */
4241da177e4SLinus Torvalds 
425e98878f7SOndrej Zary 	aha1542->aha1542_last_mbo_used = mbo;
4261da177e4SLinus Torvalds 
4271da177e4SLinus Torvalds #ifdef DEBUG
4281b0224b0SOndrej Zary 	shost_printk(KERN_DEBUG, sh, "Sending command (%d %p)...", mbo, cmd->scsi_done);
4291da177e4SLinus Torvalds #endif
4301da177e4SLinus Torvalds 
43110be6250SOndrej Zary 	any2scsi(mb[mbo].ccbptr, isa_virt_to_bus(&ccb[mbo]));	/* This gets trashed for some reason */
4321da177e4SLinus Torvalds 
4331da177e4SLinus Torvalds 	memset(&ccb[mbo], 0, sizeof(struct ccb));
4341da177e4SLinus Torvalds 
43555b28f9fSOndrej Zary 	ccb[mbo].cdblen = cmd->cmd_len;
4361da177e4SLinus Torvalds 
4371da177e4SLinus Torvalds 	direction = 0;
43855b28f9fSOndrej Zary 	if (*cmd->cmnd == READ_10 || *cmd->cmnd == READ_6)
4391da177e4SLinus Torvalds 		direction = 8;
44055b28f9fSOndrej Zary 	else if (*cmd->cmnd == WRITE_10 || *cmd->cmnd == WRITE_6)
4411da177e4SLinus Torvalds 		direction = 16;
4421da177e4SLinus Torvalds 
44355b28f9fSOndrej Zary 	memcpy(ccb[mbo].cdb, cmd->cmnd, ccb[mbo].cdblen);
4441da177e4SLinus Torvalds 
445fc3fdfccSBoaz Harrosh 	if (bufflen) {
44651cf2249SJens Axboe 		struct scatterlist *sg;
4471da177e4SLinus Torvalds 		struct chain *cptr;
44855b28f9fSOndrej Zary 		int i, sg_count = scsi_sg_count(cmd);
4496ddc8cf4SOndrej Zary 
4501da177e4SLinus Torvalds 		ccb[mbo].op = 2;	/* SCSI Initiator Command  w/scatter-gather */
45155b28f9fSOndrej Zary 		cmd->host_scribble = kmalloc(sizeof(*cptr)*sg_count,
452fc3fdfccSBoaz Harrosh 		                                         GFP_KERNEL | GFP_DMA);
45355b28f9fSOndrej Zary 		cptr = (struct chain *) cmd->host_scribble;
4541da177e4SLinus Torvalds 		if (cptr == NULL) {
4551da177e4SLinus Torvalds 			/* free the claimed mailbox slot */
45655b28f9fSOndrej Zary 			aha1542->int_cmds[mbo] = NULL;
4571b0224b0SOndrej Zary 			spin_unlock_irqrestore(sh->host_lock, flags);
4581da177e4SLinus Torvalds 			return SCSI_MLQUEUE_HOST_BUSY;
4591da177e4SLinus Torvalds 		}
46055b28f9fSOndrej Zary 		scsi_for_each_sg(cmd, sg, sg_count, i) {
46110be6250SOndrej Zary 			any2scsi(cptr[i].dataptr, isa_page_to_bus(sg_page(sg))
46210be6250SOndrej Zary 								+ sg->offset);
46351cf2249SJens Axboe 			any2scsi(cptr[i].datalen, sg->length);
4641da177e4SLinus Torvalds 		};
465fc3fdfccSBoaz Harrosh 		any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain));
46610be6250SOndrej Zary 		any2scsi(ccb[mbo].dataptr, isa_virt_to_bus(cptr));
4671da177e4SLinus Torvalds #ifdef DEBUG
4686ddc8cf4SOndrej Zary 		shost_printk(KERN_DEBUG, sh, "cptr %p: ", cptr);
4696ddc8cf4SOndrej Zary 		print_hex_dump_bytes("cptr: ", DUMP_PREFIX_NONE, cptr, 18);
4701da177e4SLinus Torvalds #endif
4711da177e4SLinus Torvalds 	} else {
4721da177e4SLinus Torvalds 		ccb[mbo].op = 0;	/* SCSI Initiator Command */
47355b28f9fSOndrej Zary 		cmd->host_scribble = NULL;
474fc3fdfccSBoaz Harrosh 		any2scsi(ccb[mbo].datalen, 0);
475fc3fdfccSBoaz Harrosh 		any2scsi(ccb[mbo].dataptr, 0);
4761da177e4SLinus Torvalds 	};
4771da177e4SLinus Torvalds 	ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7);	/*SCSI Target Id */
4781da177e4SLinus Torvalds 	ccb[mbo].rsalen = 16;
4791da177e4SLinus Torvalds 	ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
4801da177e4SLinus Torvalds 	ccb[mbo].commlinkid = 0;
4811da177e4SLinus Torvalds 
4821da177e4SLinus Torvalds #ifdef DEBUG
4836ddc8cf4SOndrej Zary 	print_hex_dump_bytes("sending: ", DUMP_PREFIX_NONE, &ccb[mbo], sizeof(ccb[mbo]) - 10);
484fde1fb8aSOndrej Zary 	printk("aha1542_queuecommand: now waiting for interrupt ");
485fde1fb8aSOndrej Zary #endif
4861da177e4SLinus Torvalds 	mb[mbo].status = 1;
48755b28f9fSOndrej Zary 	aha1542_outb(cmd->device->host->io_port, CMD_START_SCSI);
4881b0224b0SOndrej Zary 	spin_unlock_irqrestore(sh->host_lock, flags);
4891da177e4SLinus Torvalds 
4901da177e4SLinus Torvalds 	return 0;
4911da177e4SLinus Torvalds }
4921da177e4SLinus Torvalds 
4931da177e4SLinus Torvalds /* Initialize mailboxes */
49468ea9de3SOndrej Zary static void setup_mailboxes(struct Scsi_Host *sh)
4951da177e4SLinus Torvalds {
496c2532f68SOndrej Zary 	struct aha1542_hostdata *aha1542 = shost_priv(sh);
4971da177e4SLinus Torvalds 	int i;
498e98878f7SOndrej Zary 	struct mailbox *mb = aha1542->mb;
499e98878f7SOndrej Zary 	struct ccb *ccb = aha1542->ccb;
5001da177e4SLinus Torvalds 
501cad2fc72SOndrej Zary 	u8 mb_cmd[5] = { CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0};
5021da177e4SLinus Torvalds 
5031da177e4SLinus Torvalds 	for (i = 0; i < AHA1542_MAILBOXES; i++) {
5041da177e4SLinus Torvalds 		mb[i].status = mb[AHA1542_MAILBOXES + i].status = 0;
50510be6250SOndrej Zary 		any2scsi(mb[i].ccbptr, isa_virt_to_bus(&ccb[i]));
5061da177e4SLinus Torvalds 	};
50768ea9de3SOndrej Zary 	aha1542_intr_reset(sh->io_port);	/* reset interrupts, so they don't block */
508cad2fc72SOndrej Zary 	any2scsi((mb_cmd + 2), isa_virt_to_bus(mb));
50968ea9de3SOndrej Zary 	if (aha1542_out(sh->io_port, mb_cmd, 5))
5102906b3ceSOndrej Zary 		shost_printk(KERN_ERR, sh, "failed setting up mailboxes\n");
51168ea9de3SOndrej Zary 	aha1542_intr_reset(sh->io_port);
5121da177e4SLinus Torvalds }
5131da177e4SLinus Torvalds 
51468ea9de3SOndrej Zary static int aha1542_getconfig(struct Scsi_Host *sh)
5151da177e4SLinus Torvalds {
516cb5b570cSOndrej Zary 	u8 inquiry_result[3];
5171da177e4SLinus Torvalds 	int i;
51868ea9de3SOndrej Zary 	i = inb(STATUS(sh->io_port));
5191da177e4SLinus Torvalds 	if (i & DF) {
52068ea9de3SOndrej Zary 		i = inb(DATA(sh->io_port));
5211da177e4SLinus Torvalds 	};
52268ea9de3SOndrej Zary 	aha1542_outb(sh->io_port, CMD_RETCONF);
52368ea9de3SOndrej Zary 	aha1542_in(sh->io_port, inquiry_result, 3, 0);
52468ea9de3SOndrej Zary 	if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0))
5252906b3ceSOndrej Zary 		shost_printk(KERN_ERR, sh, "error querying board settings\n");
52668ea9de3SOndrej Zary 	aha1542_intr_reset(sh->io_port);
5271da177e4SLinus Torvalds 	switch (inquiry_result[0]) {
5281da177e4SLinus Torvalds 	case 0x80:
52968ea9de3SOndrej Zary 		sh->dma_channel = 7;
5301da177e4SLinus Torvalds 		break;
5311da177e4SLinus Torvalds 	case 0x40:
53268ea9de3SOndrej Zary 		sh->dma_channel = 6;
5331da177e4SLinus Torvalds 		break;
5341da177e4SLinus Torvalds 	case 0x20:
53568ea9de3SOndrej Zary 		sh->dma_channel = 5;
5361da177e4SLinus Torvalds 		break;
5371da177e4SLinus Torvalds 	case 0x01:
53868ea9de3SOndrej Zary 		sh->dma_channel = 0;
5391da177e4SLinus Torvalds 		break;
5401da177e4SLinus Torvalds 	case 0:
5411da177e4SLinus Torvalds 		/* This means that the adapter, although Adaptec 1542 compatible, doesn't use a DMA channel.
5421da177e4SLinus Torvalds 		   Currently only aware of the BusLogic BT-445S VL-Bus adapter which needs this. */
54368ea9de3SOndrej Zary 		sh->dma_channel = 0xFF;
5441da177e4SLinus Torvalds 		break;
5451da177e4SLinus Torvalds 	default:
5462906b3ceSOndrej Zary 		shost_printk(KERN_ERR, sh, "Unable to determine DMA channel.\n");
5471da177e4SLinus Torvalds 		return -1;
5481da177e4SLinus Torvalds 	};
5491da177e4SLinus Torvalds 	switch (inquiry_result[1]) {
5501da177e4SLinus Torvalds 	case 0x40:
55168ea9de3SOndrej Zary 		sh->irq = 15;
5521da177e4SLinus Torvalds 		break;
5531da177e4SLinus Torvalds 	case 0x20:
55468ea9de3SOndrej Zary 		sh->irq = 14;
5551da177e4SLinus Torvalds 		break;
5561da177e4SLinus Torvalds 	case 0x8:
55768ea9de3SOndrej Zary 		sh->irq = 12;
5581da177e4SLinus Torvalds 		break;
5591da177e4SLinus Torvalds 	case 0x4:
56068ea9de3SOndrej Zary 		sh->irq = 11;
5611da177e4SLinus Torvalds 		break;
5621da177e4SLinus Torvalds 	case 0x2:
56368ea9de3SOndrej Zary 		sh->irq = 10;
5641da177e4SLinus Torvalds 		break;
5651da177e4SLinus Torvalds 	case 0x1:
56668ea9de3SOndrej Zary 		sh->irq = 9;
5671da177e4SLinus Torvalds 		break;
5681da177e4SLinus Torvalds 	default:
5692906b3ceSOndrej Zary 		shost_printk(KERN_ERR, sh, "Unable to determine IRQ level.\n");
5701da177e4SLinus Torvalds 		return -1;
5711da177e4SLinus Torvalds 	};
57268ea9de3SOndrej Zary 	sh->this_id = inquiry_result[2] & 7;
5731da177e4SLinus Torvalds 	return 0;
5741da177e4SLinus Torvalds }
5751da177e4SLinus Torvalds 
5761da177e4SLinus Torvalds /* This function should only be called for 1542C boards - we can detect
5771da177e4SLinus Torvalds    the special firmware settings and unlock the board */
5781da177e4SLinus Torvalds 
57968ea9de3SOndrej Zary static int aha1542_mbenable(struct Scsi_Host *sh)
5801da177e4SLinus Torvalds {
581cb5b570cSOndrej Zary 	static u8 mbenable_cmd[3];
582cb5b570cSOndrej Zary 	static u8 mbenable_result[2];
5831da177e4SLinus Torvalds 	int retval;
5841da177e4SLinus Torvalds 
5851da177e4SLinus Torvalds 	retval = BIOS_TRANSLATION_6432;
5861da177e4SLinus Torvalds 
58768ea9de3SOndrej Zary 	aha1542_outb(sh->io_port, CMD_EXTBIOS);
58868ea9de3SOndrej Zary 	if (aha1542_in(sh->io_port, mbenable_result, 2, 100))
5891da177e4SLinus Torvalds 		return retval;
59068ea9de3SOndrej Zary 	if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 100))
5912093bfa1SOndrej Zary 		goto fail;
59268ea9de3SOndrej Zary 	aha1542_intr_reset(sh->io_port);
5931da177e4SLinus Torvalds 
5941da177e4SLinus Torvalds 	if ((mbenable_result[0] & 0x08) || mbenable_result[1]) {
5951da177e4SLinus Torvalds 		mbenable_cmd[0] = CMD_MBENABLE;
5961da177e4SLinus Torvalds 		mbenable_cmd[1] = 0;
5971da177e4SLinus Torvalds 		mbenable_cmd[2] = mbenable_result[1];
5981da177e4SLinus Torvalds 
5991da177e4SLinus Torvalds 		if ((mbenable_result[0] & 0x08) && (mbenable_result[1] & 0x03))
6001da177e4SLinus Torvalds 			retval = BIOS_TRANSLATION_25563;
6011da177e4SLinus Torvalds 
60268ea9de3SOndrej Zary 		if (aha1542_out(sh->io_port, mbenable_cmd, 3))
6032093bfa1SOndrej Zary 			goto fail;
6041da177e4SLinus Torvalds 	};
6051da177e4SLinus Torvalds 	while (0) {
6061da177e4SLinus Torvalds fail:
6072906b3ceSOndrej Zary 		shost_printk(KERN_ERR, sh, "Mailbox init failed\n");
6081da177e4SLinus Torvalds 	}
60968ea9de3SOndrej Zary 	aha1542_intr_reset(sh->io_port);
6101da177e4SLinus Torvalds 	return retval;
6111da177e4SLinus Torvalds }
6121da177e4SLinus Torvalds 
6131da177e4SLinus Torvalds /* Query the board to find out if it is a 1542 or a 1740, or whatever. */
61468ea9de3SOndrej Zary static int aha1542_query(struct Scsi_Host *sh)
6151da177e4SLinus Torvalds {
61668ea9de3SOndrej Zary 	struct aha1542_hostdata *aha1542 = shost_priv(sh);
617cb5b570cSOndrej Zary 	u8 inquiry_result[4];
6181da177e4SLinus Torvalds 	int i;
61968ea9de3SOndrej Zary 	i = inb(STATUS(sh->io_port));
6201da177e4SLinus Torvalds 	if (i & DF) {
62168ea9de3SOndrej Zary 		i = inb(DATA(sh->io_port));
6221da177e4SLinus Torvalds 	};
62368ea9de3SOndrej Zary 	aha1542_outb(sh->io_port, CMD_INQUIRY);
62468ea9de3SOndrej Zary 	aha1542_in(sh->io_port, inquiry_result, 4, 0);
62568ea9de3SOndrej Zary 	if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0))
6262906b3ceSOndrej Zary 		shost_printk(KERN_ERR, sh, "error querying card type\n");
62768ea9de3SOndrej Zary 	aha1542_intr_reset(sh->io_port);
6281da177e4SLinus Torvalds 
62968ea9de3SOndrej Zary 	aha1542->bios_translation = BIOS_TRANSLATION_6432;	/* Default case */
6301da177e4SLinus Torvalds 
6311da177e4SLinus Torvalds 	/* For an AHA1740 series board, we ignore the board since there is a
6321da177e4SLinus Torvalds 	   hardware bug which can lead to wrong blocks being returned if the board
6331da177e4SLinus Torvalds 	   is operating in the 1542 emulation mode.  Since there is an extended mode
6341da177e4SLinus Torvalds 	   driver, we simply ignore the board and let the 1740 driver pick it up.
6351da177e4SLinus Torvalds 	 */
6361da177e4SLinus Torvalds 
6371da177e4SLinus Torvalds 	if (inquiry_result[0] == 0x43) {
6382906b3ceSOndrej Zary 		shost_printk(KERN_INFO, sh, "Emulation mode not supported for AHA-1740 hardware, use aha1740 driver instead.\n");
6391da177e4SLinus Torvalds 		return 1;
6401da177e4SLinus Torvalds 	};
6411da177e4SLinus Torvalds 
6421da177e4SLinus Torvalds 	/* Always call this - boards that do not support extended bios translation
6431da177e4SLinus Torvalds 	   will ignore the command, and we will set the proper default */
6441da177e4SLinus Torvalds 
64568ea9de3SOndrej Zary 	aha1542->bios_translation = aha1542_mbenable(sh);
6461da177e4SLinus Torvalds 
6471da177e4SLinus Torvalds 	return 0;
6481da177e4SLinus Torvalds }
6491da177e4SLinus Torvalds 
650f71429abSOndrej Zary static u8 dma_speed_hw(int dma_speed)
6511da177e4SLinus Torvalds {
652f71429abSOndrej Zary 	switch (dma_speed) {
6531da177e4SLinus Torvalds 	case 5:
654f71429abSOndrej Zary 		return 0x00;
6551da177e4SLinus Torvalds 	case 6:
656f71429abSOndrej Zary 		return 0x04;
6571da177e4SLinus Torvalds 	case 7:
658f71429abSOndrej Zary 		return 0x01;
6591da177e4SLinus Torvalds 	case 8:
660f71429abSOndrej Zary 		return 0x02;
6611da177e4SLinus Torvalds 	case 10:
662f71429abSOndrej Zary 		return 0x03;
6631da177e4SLinus Torvalds 	}
6641da177e4SLinus Torvalds 
665f71429abSOndrej Zary 	return 0xff;	/* invalid */
6661da177e4SLinus Torvalds }
6671da177e4SLinus Torvalds 
668b847fd0dSOndrej Zary /* Set the Bus on/off-times as not to ruin floppy performance */
66937d607bdSOndrej Zary static void aha1542_set_bus_times(struct Scsi_Host *sh, int bus_on, int bus_off, int dma_speed)
670b847fd0dSOndrej Zary {
67137d607bdSOndrej Zary 	if (bus_on > 0) {
67237d607bdSOndrej Zary 		u8 oncmd[] = { CMD_BUSON_TIME, clamp(bus_on, 2, 15) };
673b847fd0dSOndrej Zary 
67437d607bdSOndrej Zary 		aha1542_intr_reset(sh->io_port);
67537d607bdSOndrej Zary 		if (aha1542_out(sh->io_port, oncmd, 2))
676b847fd0dSOndrej Zary 			goto fail;
677f71429abSOndrej Zary 	}
678f71429abSOndrej Zary 
67937d607bdSOndrej Zary 	if (bus_off > 0) {
68037d607bdSOndrej Zary 		u8 offcmd[] = { CMD_BUSOFF_TIME, clamp(bus_off, 1, 64) };
681f71429abSOndrej Zary 
68237d607bdSOndrej Zary 		aha1542_intr_reset(sh->io_port);
68337d607bdSOndrej Zary 		if (aha1542_out(sh->io_port, offcmd, 2))
684b847fd0dSOndrej Zary 			goto fail;
685f71429abSOndrej Zary 	}
686f71429abSOndrej Zary 
68737d607bdSOndrej Zary 	if (dma_speed_hw(dma_speed) != 0xff) {
68837d607bdSOndrej Zary 		u8 dmacmd[] = { CMD_DMASPEED, dma_speed_hw(dma_speed) };
689f71429abSOndrej Zary 
69037d607bdSOndrej Zary 		aha1542_intr_reset(sh->io_port);
69137d607bdSOndrej Zary 		if (aha1542_out(sh->io_port, dmacmd, 2))
692b847fd0dSOndrej Zary 			goto fail;
693b847fd0dSOndrej Zary 	}
69437d607bdSOndrej Zary 	aha1542_intr_reset(sh->io_port);
695b847fd0dSOndrej Zary 	return;
696b847fd0dSOndrej Zary fail:
6972906b3ceSOndrej Zary 	shost_printk(KERN_ERR, sh, "setting bus on/off-time failed\n");
69837d607bdSOndrej Zary 	aha1542_intr_reset(sh->io_port);
699b847fd0dSOndrej Zary }
700b847fd0dSOndrej Zary 
7011da177e4SLinus Torvalds /* return non-zero on detection */
702643a7c43SOndrej Zary static struct Scsi_Host *aha1542_hw_init(struct scsi_host_template *tpnt, struct device *pdev, int indx)
7031da177e4SLinus Torvalds {
704f71429abSOndrej Zary 	unsigned int base_io = io[indx];
705c2532f68SOndrej Zary 	struct Scsi_Host *sh;
706e98878f7SOndrej Zary 	struct aha1542_hostdata *aha1542;
7072906b3ceSOndrej Zary 	char dma_info[] = "no DMA";
7081da177e4SLinus Torvalds 
7093a70c006SOndrej Zary 	if (base_io == 0)
710643a7c43SOndrej Zary 		return NULL;
7111da177e4SLinus Torvalds 
7123a70c006SOndrej Zary 	if (!request_region(base_io, AHA1542_REGION_SIZE, "aha1542"))
7133a70c006SOndrej Zary 		return NULL;
7143a70c006SOndrej Zary 
715c2532f68SOndrej Zary 	sh = scsi_host_alloc(tpnt, sizeof(struct aha1542_hostdata));
716c2532f68SOndrej Zary 	if (!sh)
7173a70c006SOndrej Zary 		goto release;
718c2532f68SOndrej Zary 	aha1542 = shost_priv(sh);
7193a70c006SOndrej Zary 
72068ea9de3SOndrej Zary 	sh->unique_id = base_io;
72168ea9de3SOndrej Zary 	sh->io_port = base_io;
72268ea9de3SOndrej Zary 	sh->n_io_port = AHA1542_REGION_SIZE;
72368ea9de3SOndrej Zary 	aha1542->aha1542_last_mbi_used = 2 * AHA1542_MAILBOXES - 1;
72468ea9de3SOndrej Zary 	aha1542->aha1542_last_mbo_used = AHA1542_MAILBOXES - 1;
72568ea9de3SOndrej Zary 
72668ea9de3SOndrej Zary 	if (!aha1542_test_port(sh))
7273a70c006SOndrej Zary 		goto unregister;
7281da177e4SLinus Torvalds 
72937d607bdSOndrej Zary 	aha1542_set_bus_times(sh, bus_on[indx], bus_off[indx], dma_speed[indx]);
73068ea9de3SOndrej Zary 	if (aha1542_query(sh))
7313a70c006SOndrej Zary 		goto unregister;
73268ea9de3SOndrej Zary 	if (aha1542_getconfig(sh) == -1)
7331da177e4SLinus Torvalds 		goto unregister;
7341da177e4SLinus Torvalds 
735c2532f68SOndrej Zary 	if (sh->dma_channel != 0xFF)
7362906b3ceSOndrej Zary 		snprintf(dma_info, sizeof(dma_info), "DMA %d", sh->dma_channel);
7372906b3ceSOndrej Zary 	shost_printk(KERN_INFO, sh, "Adaptec AHA-1542 (SCSI-ID %d) at IO 0x%x, IRQ %d, %s\n",
7382906b3ceSOndrej Zary 				sh->this_id, base_io, sh->irq, dma_info);
7393a70c006SOndrej Zary 	if (aha1542->bios_translation == BIOS_TRANSLATION_25563)
7402906b3ceSOndrej Zary 		shost_printk(KERN_INFO, sh, "Using extended bios translation\n");
7411da177e4SLinus Torvalds 
74268ea9de3SOndrej Zary 	setup_mailboxes(sh);
7431da177e4SLinus Torvalds 
7441b0224b0SOndrej Zary 	if (request_irq(sh->irq, aha1542_interrupt, 0, "aha1542", sh)) {
7452906b3ceSOndrej Zary 		shost_printk(KERN_ERR, sh, "Unable to allocate IRQ.\n");
7461da177e4SLinus Torvalds 		goto unregister;
7471da177e4SLinus Torvalds 	}
748c2532f68SOndrej Zary 	if (sh->dma_channel != 0xFF) {
749c2532f68SOndrej Zary 		if (request_dma(sh->dma_channel, "aha1542")) {
7502906b3ceSOndrej Zary 			shost_printk(KERN_ERR, sh, "Unable to allocate DMA channel.\n");
7513a70c006SOndrej Zary 			goto free_irq;
7521da177e4SLinus Torvalds 		}
753c2532f68SOndrej Zary 		if (sh->dma_channel == 0 || sh->dma_channel >= 5) {
754c2532f68SOndrej Zary 			set_dma_mode(sh->dma_channel, DMA_MODE_CASCADE);
755c2532f68SOndrej Zary 			enable_dma(sh->dma_channel);
7561da177e4SLinus Torvalds 		}
7571da177e4SLinus Torvalds 	}
75887c4d7bcSJeff Garzik 
759c2532f68SOndrej Zary 	if (scsi_add_host(sh, pdev))
7603a70c006SOndrej Zary 		goto free_dma;
7611da177e4SLinus Torvalds 
762c2532f68SOndrej Zary 	scsi_scan_host(sh);
7631da177e4SLinus Torvalds 
764c2532f68SOndrej Zary 	return sh;
7653a70c006SOndrej Zary free_dma:
766c2532f68SOndrej Zary 	if (sh->dma_channel != 0xff)
767c2532f68SOndrej Zary 		free_dma(sh->dma_channel);
7683a70c006SOndrej Zary free_irq:
769c2532f68SOndrej Zary 	free_irq(sh->irq, sh);
7701da177e4SLinus Torvalds unregister:
771c2532f68SOndrej Zary 	scsi_host_put(sh);
7723a70c006SOndrej Zary release:
7733a70c006SOndrej Zary 	release_region(base_io, AHA1542_REGION_SIZE);
7741da177e4SLinus Torvalds 
775643a7c43SOndrej Zary 	return NULL;
7761da177e4SLinus Torvalds }
7771da177e4SLinus Torvalds 
778c2532f68SOndrej Zary static int aha1542_release(struct Scsi_Host *sh)
7791da177e4SLinus Torvalds {
780c2532f68SOndrej Zary 	scsi_remove_host(sh);
781c2532f68SOndrej Zary 	if (sh->dma_channel != 0xff)
782c2532f68SOndrej Zary 		free_dma(sh->dma_channel);
783c2532f68SOndrej Zary 	if (sh->irq)
784c2532f68SOndrej Zary 		free_irq(sh->irq, sh);
785c2532f68SOndrej Zary 	if (sh->io_port && sh->n_io_port)
786c2532f68SOndrej Zary 		release_region(sh->io_port, sh->n_io_port);
787c2532f68SOndrej Zary 	scsi_host_put(sh);
7881da177e4SLinus Torvalds 	return 0;
7891da177e4SLinus Torvalds }
7901da177e4SLinus Torvalds 
7911da177e4SLinus Torvalds 
7921da177e4SLinus Torvalds /*
7931da177e4SLinus Torvalds  * This is a device reset.  This is handled by sending a special command
7941da177e4SLinus Torvalds  * to the device.
7951da177e4SLinus Torvalds  */
79655b28f9fSOndrej Zary static int aha1542_dev_reset(struct scsi_cmnd *cmd)
7971da177e4SLinus Torvalds {
7981b0224b0SOndrej Zary 	struct Scsi_Host *sh = cmd->device->host;
7991b0224b0SOndrej Zary 	struct aha1542_hostdata *aha1542 = shost_priv(sh);
8001da177e4SLinus Torvalds 	unsigned long flags;
801e98878f7SOndrej Zary 	struct mailbox *mb = aha1542->mb;
80255b28f9fSOndrej Zary 	u8 target = cmd->device->id;
80355b28f9fSOndrej Zary 	u8 lun = cmd->device->lun;
8041da177e4SLinus Torvalds 	int mbo;
805e98878f7SOndrej Zary 	struct ccb *ccb = aha1542->ccb;
8061da177e4SLinus Torvalds 
8071b0224b0SOndrej Zary 	spin_lock_irqsave(sh->host_lock, flags);
808e98878f7SOndrej Zary 	mbo = aha1542->aha1542_last_mbo_used + 1;
8091da177e4SLinus Torvalds 	if (mbo >= AHA1542_MAILBOXES)
8101da177e4SLinus Torvalds 		mbo = 0;
8111da177e4SLinus Torvalds 
8121da177e4SLinus Torvalds 	do {
81355b28f9fSOndrej Zary 		if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL)
8141da177e4SLinus Torvalds 			break;
8151da177e4SLinus Torvalds 		mbo++;
8161da177e4SLinus Torvalds 		if (mbo >= AHA1542_MAILBOXES)
8171da177e4SLinus Torvalds 			mbo = 0;
818e98878f7SOndrej Zary 	} while (mbo != aha1542->aha1542_last_mbo_used);
8191da177e4SLinus Torvalds 
82055b28f9fSOndrej Zary 	if (mb[mbo].status || aha1542->int_cmds[mbo])
8211da177e4SLinus Torvalds 		panic("Unable to find empty mailbox for aha1542.\n");
8221da177e4SLinus Torvalds 
82355b28f9fSOndrej Zary 	aha1542->int_cmds[mbo] = cmd;	/* This will effectively
8241da177e4SLinus Torvalds 					   prevent someone else from
8251da177e4SLinus Torvalds 					   screwing with this cdb. */
8261da177e4SLinus Torvalds 
827e98878f7SOndrej Zary 	aha1542->aha1542_last_mbo_used = mbo;
8281da177e4SLinus Torvalds 
82910be6250SOndrej Zary 	any2scsi(mb[mbo].ccbptr, isa_virt_to_bus(&ccb[mbo]));	/* This gets trashed for some reason */
8301da177e4SLinus Torvalds 
8311da177e4SLinus Torvalds 	memset(&ccb[mbo], 0, sizeof(struct ccb));
8321da177e4SLinus Torvalds 
8331da177e4SLinus Torvalds 	ccb[mbo].op = 0x81;	/* BUS DEVICE RESET */
8341da177e4SLinus Torvalds 
8351da177e4SLinus Torvalds 	ccb[mbo].idlun = (target & 7) << 5 | (lun & 7);		/*SCSI Target Id */
8361da177e4SLinus Torvalds 
8371da177e4SLinus Torvalds 	ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
8381da177e4SLinus Torvalds 	ccb[mbo].commlinkid = 0;
8391da177e4SLinus Torvalds 
8401da177e4SLinus Torvalds 	/*
8411da177e4SLinus Torvalds 	 * Now tell the 1542 to flush all pending commands for this
8421da177e4SLinus Torvalds 	 * target
8431da177e4SLinus Torvalds 	 */
8441b0224b0SOndrej Zary 	aha1542_outb(sh->io_port, CMD_START_SCSI);
8451b0224b0SOndrej Zary 	spin_unlock_irqrestore(sh->host_lock, flags);
8461da177e4SLinus Torvalds 
84755b28f9fSOndrej Zary 	scmd_printk(KERN_WARNING, cmd,
848017560fcSJeff Garzik 		"Trying device reset for target\n");
8491da177e4SLinus Torvalds 
8501da177e4SLinus Torvalds 	return SUCCESS;
8511da177e4SLinus Torvalds }
8521da177e4SLinus Torvalds 
85355b28f9fSOndrej Zary static int aha1542_reset(struct scsi_cmnd *cmd, u8 reset_cmd)
8541da177e4SLinus Torvalds {
8551b0224b0SOndrej Zary 	struct Scsi_Host *sh = cmd->device->host;
8561b0224b0SOndrej Zary 	struct aha1542_hostdata *aha1542 = shost_priv(sh);
8571b0224b0SOndrej Zary 	unsigned long flags;
8581da177e4SLinus Torvalds 	int i;
8591da177e4SLinus Torvalds 
8601b0224b0SOndrej Zary 	spin_lock_irqsave(sh->host_lock, flags);
8611da177e4SLinus Torvalds 	/*
8621da177e4SLinus Torvalds 	 * This does a scsi reset for all devices on the bus.
8631da177e4SLinus Torvalds 	 * In principle, we could also reset the 1542 - should
8641da177e4SLinus Torvalds 	 * we do this?  Try this first, and we can add that later
8651da177e4SLinus Torvalds 	 * if it turns out to be useful.
8661da177e4SLinus Torvalds 	 */
86755b28f9fSOndrej Zary 	outb(reset_cmd, CONTROL(cmd->device->host->io_port));
8681da177e4SLinus Torvalds 
86955b28f9fSOndrej Zary 	if (!wait_mask(STATUS(cmd->device->host->io_port),
870*7061dec4SOndrej Zary 	     STATMASK, IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0)) {
8711b0224b0SOndrej Zary 		spin_unlock_irqrestore(sh->host_lock, flags);
872a13b3722SOndrej Zary 		return FAILED;
873a13b3722SOndrej Zary 	}
8741b0224b0SOndrej Zary 
8751da177e4SLinus Torvalds 	/*
8761da177e4SLinus Torvalds 	 * We need to do this too before the 1542 can interact with
8778537cba8SOndrej Zary 	 * us again after host reset.
8781da177e4SLinus Torvalds 	 */
8798537cba8SOndrej Zary 	if (reset_cmd & HRST)
88068ea9de3SOndrej Zary 		setup_mailboxes(cmd->device->host);
8811b0224b0SOndrej Zary 
8821da177e4SLinus Torvalds 	/*
8831da177e4SLinus Torvalds 	 * Now try to pick up the pieces.  For all pending commands,
8841da177e4SLinus Torvalds 	 * free any internal data structures, and basically clear things
8851da177e4SLinus Torvalds 	 * out.  We do not try and restart any commands or anything -
8861da177e4SLinus Torvalds 	 * the strategy handler takes care of that crap.
8871da177e4SLinus Torvalds 	 */
8882906b3ceSOndrej Zary 	shost_printk(KERN_WARNING, cmd->device->host, "Sent BUS RESET to scsi host %d\n", cmd->device->host->host_no);
8891da177e4SLinus Torvalds 
8901da177e4SLinus Torvalds 	for (i = 0; i < AHA1542_MAILBOXES; i++) {
89155b28f9fSOndrej Zary 		if (aha1542->int_cmds[i] != NULL) {
89255b28f9fSOndrej Zary 			struct scsi_cmnd *tmp_cmd;
89355b28f9fSOndrej Zary 			tmp_cmd = aha1542->int_cmds[i];
8941da177e4SLinus Torvalds 
89555b28f9fSOndrej Zary 			if (tmp_cmd->device->soft_reset) {
8961da177e4SLinus Torvalds 				/*
8971da177e4SLinus Torvalds 				 * If this device implements the soft reset option,
8981da177e4SLinus Torvalds 				 * then it is still holding onto the command, and
8991da177e4SLinus Torvalds 				 * may yet complete it.  In this case, we don't
9001da177e4SLinus Torvalds 				 * flush the data.
9011da177e4SLinus Torvalds 				 */
9021da177e4SLinus Torvalds 				continue;
9031da177e4SLinus Torvalds 			}
90455b28f9fSOndrej Zary 			kfree(tmp_cmd->host_scribble);
90555b28f9fSOndrej Zary 			tmp_cmd->host_scribble = NULL;
90655b28f9fSOndrej Zary 			aha1542->int_cmds[i] = NULL;
907e98878f7SOndrej Zary 			aha1542->mb[i].status = 0;
9081da177e4SLinus Torvalds 		}
9091da177e4SLinus Torvalds 	}
9101da177e4SLinus Torvalds 
9111b0224b0SOndrej Zary 	spin_unlock_irqrestore(sh->host_lock, flags);
9121da177e4SLinus Torvalds 	return SUCCESS;
9131da177e4SLinus Torvalds }
9141da177e4SLinus Torvalds 
91555b28f9fSOndrej Zary static int aha1542_bus_reset(struct scsi_cmnd *cmd)
9168537cba8SOndrej Zary {
91755b28f9fSOndrej Zary 	return aha1542_reset(cmd, SCRST);
9188537cba8SOndrej Zary }
9198537cba8SOndrej Zary 
92055b28f9fSOndrej Zary static int aha1542_host_reset(struct scsi_cmnd *cmd)
9218537cba8SOndrej Zary {
92255b28f9fSOndrej Zary 	return aha1542_reset(cmd, HRST | SCRST);
9238537cba8SOndrej Zary }
9248537cba8SOndrej Zary 
9251da177e4SLinus Torvalds static int aha1542_biosparam(struct scsi_device *sdev,
92617787a09SOndrej Zary 		struct block_device *bdev, sector_t capacity, int geom[])
9271da177e4SLinus Torvalds {
928e98878f7SOndrej Zary 	struct aha1542_hostdata *aha1542 = shost_priv(sdev->host);
9291da177e4SLinus Torvalds 
93017787a09SOndrej Zary 	if (capacity >= 0x200000 &&
93117787a09SOndrej Zary 			aha1542->bios_translation == BIOS_TRANSLATION_25563) {
9321da177e4SLinus Torvalds 		/* Please verify that this is the same as what DOS returns */
93317787a09SOndrej Zary 		geom[0] = 255;	/* heads */
93417787a09SOndrej Zary 		geom[1] = 63;	/* sectors */
9351da177e4SLinus Torvalds 	} else {
93617787a09SOndrej Zary 		geom[0] = 64;	/* heads */
93717787a09SOndrej Zary 		geom[1] = 32;	/* sectors */
9381da177e4SLinus Torvalds 	}
93917787a09SOndrej Zary 	geom[2] = sector_div(capacity, geom[0] * geom[1]);	/* cylinders */
9401da177e4SLinus Torvalds 
9411da177e4SLinus Torvalds 	return 0;
9421da177e4SLinus Torvalds }
9431da177e4SLinus Torvalds MODULE_LICENSE("GPL");
9441da177e4SLinus Torvalds 
945d0be4a7dSChristoph Hellwig static struct scsi_host_template driver_template = {
946643a7c43SOndrej Zary 	.module			= THIS_MODULE,
9471da177e4SLinus Torvalds 	.proc_name		= "aha1542",
9481da177e4SLinus Torvalds 	.name			= "Adaptec 1542",
9491da177e4SLinus Torvalds 	.queuecommand		= aha1542_queuecommand,
9501da177e4SLinus Torvalds 	.eh_device_reset_handler= aha1542_dev_reset,
9511da177e4SLinus Torvalds 	.eh_bus_reset_handler	= aha1542_bus_reset,
9521da177e4SLinus Torvalds 	.eh_host_reset_handler	= aha1542_host_reset,
9531da177e4SLinus Torvalds 	.bios_param		= aha1542_biosparam,
9541da177e4SLinus Torvalds 	.can_queue		= AHA1542_MAILBOXES,
9551da177e4SLinus Torvalds 	.this_id		= 7,
95610be6250SOndrej Zary 	.sg_tablesize		= 16,
95710be6250SOndrej Zary 	.cmd_per_lun		= 1,
9581da177e4SLinus Torvalds 	.unchecked_isa_dma	= 1,
9591da177e4SLinus Torvalds 	.use_clustering		= ENABLE_CLUSTERING,
9601da177e4SLinus Torvalds };
961643a7c43SOndrej Zary 
962643a7c43SOndrej Zary static int aha1542_isa_match(struct device *pdev, unsigned int ndev)
963643a7c43SOndrej Zary {
964643a7c43SOndrej Zary 	struct Scsi_Host *sh = aha1542_hw_init(&driver_template, pdev, ndev);
965643a7c43SOndrej Zary 
966643a7c43SOndrej Zary 	if (!sh)
967643a7c43SOndrej Zary 		return 0;
968643a7c43SOndrej Zary 
969643a7c43SOndrej Zary 	dev_set_drvdata(pdev, sh);
970643a7c43SOndrej Zary 	return 1;
971643a7c43SOndrej Zary }
972643a7c43SOndrej Zary 
973643a7c43SOndrej Zary static int aha1542_isa_remove(struct device *pdev,
974643a7c43SOndrej Zary 				    unsigned int ndev)
975643a7c43SOndrej Zary {
976643a7c43SOndrej Zary 	aha1542_release(dev_get_drvdata(pdev));
977643a7c43SOndrej Zary 	dev_set_drvdata(pdev, NULL);
978643a7c43SOndrej Zary 	return 0;
979643a7c43SOndrej Zary }
980643a7c43SOndrej Zary 
981643a7c43SOndrej Zary static struct isa_driver aha1542_isa_driver = {
982643a7c43SOndrej Zary 	.match		= aha1542_isa_match,
983643a7c43SOndrej Zary 	.remove		= aha1542_isa_remove,
984643a7c43SOndrej Zary 	.driver		= {
985643a7c43SOndrej Zary 		.name	= "aha1542"
986643a7c43SOndrej Zary 	},
987643a7c43SOndrej Zary };
988643a7c43SOndrej Zary static int isa_registered;
989643a7c43SOndrej Zary 
990643a7c43SOndrej Zary #ifdef CONFIG_PNP
991643a7c43SOndrej Zary static struct pnp_device_id aha1542_pnp_ids[] = {
992643a7c43SOndrej Zary 	{ .id = "ADP1542" },
993643a7c43SOndrej Zary 	{ .id = "" }
994643a7c43SOndrej Zary };
995643a7c43SOndrej Zary MODULE_DEVICE_TABLE(pnp, aha1542_pnp_ids);
996643a7c43SOndrej Zary 
997643a7c43SOndrej Zary static int aha1542_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *id)
998643a7c43SOndrej Zary {
999643a7c43SOndrej Zary 	int indx;
1000643a7c43SOndrej Zary 	struct Scsi_Host *sh;
1001643a7c43SOndrej Zary 
1002f71429abSOndrej Zary 	for (indx = 0; indx < ARRAY_SIZE(io); indx++) {
1003f71429abSOndrej Zary 		if (io[indx])
1004643a7c43SOndrej Zary 			continue;
1005643a7c43SOndrej Zary 
1006643a7c43SOndrej Zary 		if (pnp_activate_dev(pdev) < 0)
1007643a7c43SOndrej Zary 			continue;
1008643a7c43SOndrej Zary 
1009f71429abSOndrej Zary 		io[indx] = pnp_port_start(pdev, 0);
1010643a7c43SOndrej Zary 
1011643a7c43SOndrej Zary 		/* The card can be queried for its DMA, we have
1012643a7c43SOndrej Zary 		   the DMA set up that is enough */
1013643a7c43SOndrej Zary 
10142906b3ceSOndrej Zary 		dev_info(&pdev->dev, "ISAPnP found an AHA1535 at I/O 0x%03X", io[indx]);
1015643a7c43SOndrej Zary 	}
1016643a7c43SOndrej Zary 
1017643a7c43SOndrej Zary 	sh = aha1542_hw_init(&driver_template, &pdev->dev, indx);
1018643a7c43SOndrej Zary 	if (!sh)
1019643a7c43SOndrej Zary 		return -ENODEV;
1020643a7c43SOndrej Zary 
1021643a7c43SOndrej Zary 	pnp_set_drvdata(pdev, sh);
1022643a7c43SOndrej Zary 	return 0;
1023643a7c43SOndrej Zary }
1024643a7c43SOndrej Zary 
1025643a7c43SOndrej Zary static void aha1542_pnp_remove(struct pnp_dev *pdev)
1026643a7c43SOndrej Zary {
1027643a7c43SOndrej Zary 	aha1542_release(pnp_get_drvdata(pdev));
1028643a7c43SOndrej Zary 	pnp_set_drvdata(pdev, NULL);
1029643a7c43SOndrej Zary }
1030643a7c43SOndrej Zary 
1031643a7c43SOndrej Zary static struct pnp_driver aha1542_pnp_driver = {
1032643a7c43SOndrej Zary 	.name		= "aha1542",
1033643a7c43SOndrej Zary 	.id_table	= aha1542_pnp_ids,
1034643a7c43SOndrej Zary 	.probe		= aha1542_pnp_probe,
1035643a7c43SOndrej Zary 	.remove		= aha1542_pnp_remove,
1036643a7c43SOndrej Zary };
1037643a7c43SOndrej Zary static int pnp_registered;
1038643a7c43SOndrej Zary #endif /* CONFIG_PNP */
1039643a7c43SOndrej Zary 
1040643a7c43SOndrej Zary static int __init aha1542_init(void)
1041643a7c43SOndrej Zary {
1042643a7c43SOndrej Zary 	int ret = 0;
1043643a7c43SOndrej Zary 
1044643a7c43SOndrej Zary #ifdef CONFIG_PNP
1045643a7c43SOndrej Zary 	if (isapnp) {
1046643a7c43SOndrej Zary 		ret = pnp_register_driver(&aha1542_pnp_driver);
1047643a7c43SOndrej Zary 		if (!ret)
1048643a7c43SOndrej Zary 			pnp_registered = 1;
1049643a7c43SOndrej Zary 	}
1050643a7c43SOndrej Zary #endif
1051643a7c43SOndrej Zary 	ret = isa_register_driver(&aha1542_isa_driver, MAXBOARDS);
1052643a7c43SOndrej Zary 	if (!ret)
1053643a7c43SOndrej Zary 		isa_registered = 1;
1054643a7c43SOndrej Zary 
1055643a7c43SOndrej Zary #ifdef CONFIG_PNP
1056643a7c43SOndrej Zary 	if (pnp_registered)
1057643a7c43SOndrej Zary 		ret = 0;
1058643a7c43SOndrej Zary #endif
1059643a7c43SOndrej Zary 	if (isa_registered)
1060643a7c43SOndrej Zary 		ret = 0;
1061643a7c43SOndrej Zary 
1062643a7c43SOndrej Zary 	return ret;
1063643a7c43SOndrej Zary }
1064643a7c43SOndrej Zary 
1065643a7c43SOndrej Zary static void __exit aha1542_exit(void)
1066643a7c43SOndrej Zary {
1067643a7c43SOndrej Zary #ifdef CONFIG_PNP
1068643a7c43SOndrej Zary 	if (pnp_registered)
1069643a7c43SOndrej Zary 		pnp_unregister_driver(&aha1542_pnp_driver);
1070643a7c43SOndrej Zary #endif
1071643a7c43SOndrej Zary 	if (isa_registered)
1072643a7c43SOndrej Zary 		isa_unregister_driver(&aha1542_isa_driver);
1073643a7c43SOndrej Zary }
1074643a7c43SOndrej Zary 
1075643a7c43SOndrej Zary module_init(aha1542_init);
1076643a7c43SOndrej Zary module_exit(aha1542_exit);
1077