18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Driver for Adaptec AHA-1542 SCSI host adapters
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 1992  Tommy Thorn
68c2ecf20Sopenharmony_ci *  Copyright (C) 1993, 1994, 1995 Eric Youngdale
78c2ecf20Sopenharmony_ci *  Copyright (C) 2015 Ondrej Zary
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/types.h>
148c2ecf20Sopenharmony_ci#include <linux/string.h>
158c2ecf20Sopenharmony_ci#include <linux/delay.h>
168c2ecf20Sopenharmony_ci#include <linux/init.h>
178c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
188c2ecf20Sopenharmony_ci#include <linux/isa.h>
198c2ecf20Sopenharmony_ci#include <linux/pnp.h>
208c2ecf20Sopenharmony_ci#include <linux/slab.h>
218c2ecf20Sopenharmony_ci#include <linux/io.h>
228c2ecf20Sopenharmony_ci#include <asm/dma.h>
238c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h>
248c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h>
258c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h>
268c2ecf20Sopenharmony_ci#include "aha1542.h"
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define MAXBOARDS 4
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic bool isapnp = 1;
318c2ecf20Sopenharmony_cimodule_param(isapnp, bool, 0);
328c2ecf20Sopenharmony_ciMODULE_PARM_DESC(isapnp, "enable PnP support (default=1)");
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic int io[MAXBOARDS] = { 0x330, 0x334, 0, 0 };
358c2ecf20Sopenharmony_cimodule_param_hw_array(io, int, ioport, NULL, 0);
368c2ecf20Sopenharmony_ciMODULE_PARM_DESC(io, "base IO address of controller (0x130,0x134,0x230,0x234,0x330,0x334, default=0x330,0x334)");
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/* time AHA spends on the AT-bus during data transfer */
398c2ecf20Sopenharmony_cistatic int bus_on[MAXBOARDS] = { -1, -1, -1, -1 }; /* power-on default: 11us */
408c2ecf20Sopenharmony_cimodule_param_array(bus_on, int, NULL, 0);
418c2ecf20Sopenharmony_ciMODULE_PARM_DESC(bus_on, "bus on time [us] (2-15, default=-1 [HW default: 11])");
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci/* time AHA spends off the bus (not to monopolize it) during data transfer  */
448c2ecf20Sopenharmony_cistatic int bus_off[MAXBOARDS] = { -1, -1, -1, -1 }; /* power-on default: 4us */
458c2ecf20Sopenharmony_cimodule_param_array(bus_off, int, NULL, 0);
468c2ecf20Sopenharmony_ciMODULE_PARM_DESC(bus_off, "bus off time [us] (1-64, default=-1 [HW default: 4])");
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/* default is jumper selected (J1 on 1542A), factory default = 5 MB/s */
498c2ecf20Sopenharmony_cistatic int dma_speed[MAXBOARDS] = { -1, -1, -1, -1 };
508c2ecf20Sopenharmony_cimodule_param_array(dma_speed, int, NULL, 0);
518c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dma_speed, "DMA speed [MB/s] (5,6,7,8,10, default=-1 [by jumper])");
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define BIOS_TRANSLATION_6432 1	/* Default case these days */
548c2ecf20Sopenharmony_ci#define BIOS_TRANSLATION_25563 2	/* Big disk case */
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistruct aha1542_hostdata {
578c2ecf20Sopenharmony_ci	/* This will effectively start both of them at the first mailbox */
588c2ecf20Sopenharmony_ci	int bios_translation;	/* Mapping bios uses - for compatibility */
598c2ecf20Sopenharmony_ci	int aha1542_last_mbi_used;
608c2ecf20Sopenharmony_ci	int aha1542_last_mbo_used;
618c2ecf20Sopenharmony_ci	struct scsi_cmnd *int_cmds[AHA1542_MAILBOXES];
628c2ecf20Sopenharmony_ci	struct mailbox *mb;
638c2ecf20Sopenharmony_ci	dma_addr_t mb_handle;
648c2ecf20Sopenharmony_ci	struct ccb *ccb;
658c2ecf20Sopenharmony_ci	dma_addr_t ccb_handle;
668c2ecf20Sopenharmony_ci};
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistruct aha1542_cmd {
698c2ecf20Sopenharmony_ci	struct chain *chain;
708c2ecf20Sopenharmony_ci	dma_addr_t chain_handle;
718c2ecf20Sopenharmony_ci};
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic inline void aha1542_intr_reset(u16 base)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	outb(IRST, CONTROL(base));
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic inline bool wait_mask(u16 port, u8 mask, u8 allof, u8 noneof, int timeout)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	bool delayed = true;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	if (timeout == 0) {
838c2ecf20Sopenharmony_ci		timeout = 3000000;
848c2ecf20Sopenharmony_ci		delayed = false;
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	while (1) {
888c2ecf20Sopenharmony_ci		u8 bits = inb(port) & mask;
898c2ecf20Sopenharmony_ci		if ((bits & allof) == allof && ((bits & noneof) == 0))
908c2ecf20Sopenharmony_ci			break;
918c2ecf20Sopenharmony_ci		if (delayed)
928c2ecf20Sopenharmony_ci			mdelay(1);
938c2ecf20Sopenharmony_ci		if (--timeout == 0)
948c2ecf20Sopenharmony_ci			return false;
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	return true;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic int aha1542_outb(unsigned int base, u8 val)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	if (!wait_mask(STATUS(base), CDF, 0, CDF, 0))
1038c2ecf20Sopenharmony_ci		return 1;
1048c2ecf20Sopenharmony_ci	outb(val, DATA(base));
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	return 0;
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic int aha1542_out(unsigned int base, u8 *buf, int len)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	while (len--) {
1128c2ecf20Sopenharmony_ci		if (!wait_mask(STATUS(base), CDF, 0, CDF, 0))
1138c2ecf20Sopenharmony_ci			return 1;
1148c2ecf20Sopenharmony_ci		outb(*buf++, DATA(base));
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci	if (!wait_mask(INTRFLAGS(base), INTRMASK, HACC, 0, 0))
1178c2ecf20Sopenharmony_ci		return 1;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	return 0;
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci/* Only used at boot time, so we do not need to worry about latency as much
1238c2ecf20Sopenharmony_ci   here */
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic int aha1542_in(unsigned int base, u8 *buf, int len, int timeout)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	while (len--) {
1288c2ecf20Sopenharmony_ci		if (!wait_mask(STATUS(base), DF, DF, 0, timeout))
1298c2ecf20Sopenharmony_ci			return 1;
1308c2ecf20Sopenharmony_ci		*buf++ = inb(DATA(base));
1318c2ecf20Sopenharmony_ci	}
1328c2ecf20Sopenharmony_ci	return 0;
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic int makecode(unsigned hosterr, unsigned scsierr)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	switch (hosterr) {
1388c2ecf20Sopenharmony_ci	case 0x0:
1398c2ecf20Sopenharmony_ci	case 0xa:		/* Linked command complete without error and linked normally */
1408c2ecf20Sopenharmony_ci	case 0xb:		/* Linked command complete without error, interrupt generated */
1418c2ecf20Sopenharmony_ci		hosterr = 0;
1428c2ecf20Sopenharmony_ci		break;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	case 0x11:		/* Selection time out-The initiator selection or target
1458c2ecf20Sopenharmony_ci				   reselection was not complete within the SCSI Time out period */
1468c2ecf20Sopenharmony_ci		hosterr = DID_TIME_OUT;
1478c2ecf20Sopenharmony_ci		break;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	case 0x12:		/* Data overrun/underrun-The target attempted to transfer more data
1508c2ecf20Sopenharmony_ci				   than was allocated by the Data Length field or the sum of the
1518c2ecf20Sopenharmony_ci				   Scatter / Gather Data Length fields. */
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	case 0x13:		/* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	case 0x15:		/* MBO command was not 00, 01 or 02-The first byte of the CB was
1568c2ecf20Sopenharmony_ci				   invalid. This usually indicates a software failure. */
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	case 0x16:		/* Invalid CCB Operation Code-The first byte of the CCB was invalid.
1598c2ecf20Sopenharmony_ci				   This usually indicates a software failure. */
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	case 0x17:		/* Linked CCB does not have the same LUN-A subsequent CCB of a set
1628c2ecf20Sopenharmony_ci				   of linked CCB's does not specify the same logical unit number as
1638c2ecf20Sopenharmony_ci				   the first. */
1648c2ecf20Sopenharmony_ci	case 0x18:		/* Invalid Target Direction received from Host-The direction of a
1658c2ecf20Sopenharmony_ci				   Target Mode CCB was invalid. */
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	case 0x19:		/* Duplicate CCB Received in Target Mode-More than once CCB was
1688c2ecf20Sopenharmony_ci				   received to service data transfer between the same target LUN
1698c2ecf20Sopenharmony_ci				   and initiator SCSI ID in the same direction. */
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	case 0x1a:		/* Invalid CCB or Segment List Parameter-A segment list with a zero
1728c2ecf20Sopenharmony_ci				   length segment or invalid segment list boundaries was received.
1738c2ecf20Sopenharmony_ci				   A CCB parameter was invalid. */
1748c2ecf20Sopenharmony_ci#ifdef DEBUG
1758c2ecf20Sopenharmony_ci		printk("Aha1542: %x %x\n", hosterr, scsierr);
1768c2ecf20Sopenharmony_ci#endif
1778c2ecf20Sopenharmony_ci		hosterr = DID_ERROR;	/* Couldn't find any better */
1788c2ecf20Sopenharmony_ci		break;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	case 0x14:		/* Target bus phase sequence failure-An invalid bus phase or bus
1818c2ecf20Sopenharmony_ci				   phase sequence was requested by the target. The host adapter
1828c2ecf20Sopenharmony_ci				   will generate a SCSI Reset Condition, notifying the host with
1838c2ecf20Sopenharmony_ci				   a SCRD interrupt */
1848c2ecf20Sopenharmony_ci		hosterr = DID_RESET;
1858c2ecf20Sopenharmony_ci		break;
1868c2ecf20Sopenharmony_ci	default:
1878c2ecf20Sopenharmony_ci		printk(KERN_ERR "aha1542: makecode: unknown hoststatus %x\n", hosterr);
1888c2ecf20Sopenharmony_ci		break;
1898c2ecf20Sopenharmony_ci	}
1908c2ecf20Sopenharmony_ci	return scsierr | (hosterr << 16);
1918c2ecf20Sopenharmony_ci}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_cistatic int aha1542_test_port(struct Scsi_Host *sh)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	u8 inquiry_result[4];
1968c2ecf20Sopenharmony_ci	int i;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	/* Quick and dirty test for presence of the card. */
1998c2ecf20Sopenharmony_ci	if (inb(STATUS(sh->io_port)) == 0xff)
2008c2ecf20Sopenharmony_ci		return 0;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	/* Reset the adapter. I ought to make a hard reset, but it's not really necessary */
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	/* In case some other card was probing here, reset interrupts */
2058c2ecf20Sopenharmony_ci	aha1542_intr_reset(sh->io_port);	/* reset interrupts, so they don't block */
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	outb(SRST | IRST /*|SCRST */ , CONTROL(sh->io_port));
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	mdelay(20);		/* Wait a little bit for things to settle down. */
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	/* Expect INIT and IDLE, any of the others are bad */
2128c2ecf20Sopenharmony_ci	if (!wait_mask(STATUS(sh->io_port), STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0))
2138c2ecf20Sopenharmony_ci		return 0;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	/* Shouldn't have generated any interrupts during reset */
2168c2ecf20Sopenharmony_ci	if (inb(INTRFLAGS(sh->io_port)) & INTRMASK)
2178c2ecf20Sopenharmony_ci		return 0;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	/* Perform a host adapter inquiry instead so we do not need to set
2208c2ecf20Sopenharmony_ci	   up the mailboxes ahead of time */
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	aha1542_outb(sh->io_port, CMD_INQUIRY);
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++) {
2258c2ecf20Sopenharmony_ci		if (!wait_mask(STATUS(sh->io_port), DF, DF, 0, 0))
2268c2ecf20Sopenharmony_ci			return 0;
2278c2ecf20Sopenharmony_ci		inquiry_result[i] = inb(DATA(sh->io_port));
2288c2ecf20Sopenharmony_ci	}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	/* Reading port should reset DF */
2318c2ecf20Sopenharmony_ci	if (inb(STATUS(sh->io_port)) & DF)
2328c2ecf20Sopenharmony_ci		return 0;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	/* When HACC, command is completed, and we're though testing */
2358c2ecf20Sopenharmony_ci	if (!wait_mask(INTRFLAGS(sh->io_port), HACC, HACC, 0, 0))
2368c2ecf20Sopenharmony_ci		return 0;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	/* Clear interrupts */
2398c2ecf20Sopenharmony_ci	outb(IRST, CONTROL(sh->io_port));
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	return 1;
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic void aha1542_free_cmd(struct scsi_cmnd *cmd)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	struct aha1542_cmd *acmd = scsi_cmd_priv(cmd);
2478c2ecf20Sopenharmony_ci	struct device *dev = cmd->device->host->dma_dev;
2488c2ecf20Sopenharmony_ci	size_t len = scsi_sg_count(cmd) * sizeof(struct chain);
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	if (acmd->chain) {
2518c2ecf20Sopenharmony_ci		dma_unmap_single(dev, acmd->chain_handle, len, DMA_TO_DEVICE);
2528c2ecf20Sopenharmony_ci		kfree(acmd->chain);
2538c2ecf20Sopenharmony_ci	}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	acmd->chain = NULL;
2568c2ecf20Sopenharmony_ci	scsi_dma_unmap(cmd);
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_cistatic irqreturn_t aha1542_interrupt(int irq, void *dev_id)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	struct Scsi_Host *sh = dev_id;
2628c2ecf20Sopenharmony_ci	struct aha1542_hostdata *aha1542 = shost_priv(sh);
2638c2ecf20Sopenharmony_ci	void (*my_done)(struct scsi_cmnd *) = NULL;
2648c2ecf20Sopenharmony_ci	int errstatus, mbi, mbo, mbistatus;
2658c2ecf20Sopenharmony_ci	int number_serviced;
2668c2ecf20Sopenharmony_ci	unsigned long flags;
2678c2ecf20Sopenharmony_ci	struct scsi_cmnd *tmp_cmd;
2688c2ecf20Sopenharmony_ci	int flag;
2698c2ecf20Sopenharmony_ci	struct mailbox *mb = aha1542->mb;
2708c2ecf20Sopenharmony_ci	struct ccb *ccb = aha1542->ccb;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci#ifdef DEBUG
2738c2ecf20Sopenharmony_ci	{
2748c2ecf20Sopenharmony_ci		flag = inb(INTRFLAGS(sh->io_port));
2758c2ecf20Sopenharmony_ci		shost_printk(KERN_DEBUG, sh, "aha1542_intr_handle: ");
2768c2ecf20Sopenharmony_ci		if (!(flag & ANYINTR))
2778c2ecf20Sopenharmony_ci			printk("no interrupt?");
2788c2ecf20Sopenharmony_ci		if (flag & MBIF)
2798c2ecf20Sopenharmony_ci			printk("MBIF ");
2808c2ecf20Sopenharmony_ci		if (flag & MBOA)
2818c2ecf20Sopenharmony_ci			printk("MBOF ");
2828c2ecf20Sopenharmony_ci		if (flag & HACC)
2838c2ecf20Sopenharmony_ci			printk("HACC ");
2848c2ecf20Sopenharmony_ci		if (flag & SCRD)
2858c2ecf20Sopenharmony_ci			printk("SCRD ");
2868c2ecf20Sopenharmony_ci		printk("status %02x\n", inb(STATUS(sh->io_port)));
2878c2ecf20Sopenharmony_ci	};
2888c2ecf20Sopenharmony_ci#endif
2898c2ecf20Sopenharmony_ci	number_serviced = 0;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	spin_lock_irqsave(sh->host_lock, flags);
2928c2ecf20Sopenharmony_ci	while (1) {
2938c2ecf20Sopenharmony_ci		flag = inb(INTRFLAGS(sh->io_port));
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci		/* Check for unusual interrupts.  If any of these happen, we should
2968c2ecf20Sopenharmony_ci		   probably do something special, but for now just printing a message
2978c2ecf20Sopenharmony_ci		   is sufficient.  A SCSI reset detected is something that we really
2988c2ecf20Sopenharmony_ci		   need to deal with in some way. */
2998c2ecf20Sopenharmony_ci		if (flag & ~MBIF) {
3008c2ecf20Sopenharmony_ci			if (flag & MBOA)
3018c2ecf20Sopenharmony_ci				printk("MBOF ");
3028c2ecf20Sopenharmony_ci			if (flag & HACC)
3038c2ecf20Sopenharmony_ci				printk("HACC ");
3048c2ecf20Sopenharmony_ci			if (flag & SCRD)
3058c2ecf20Sopenharmony_ci				printk("SCRD ");
3068c2ecf20Sopenharmony_ci		}
3078c2ecf20Sopenharmony_ci		aha1542_intr_reset(sh->io_port);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci		mbi = aha1542->aha1542_last_mbi_used + 1;
3108c2ecf20Sopenharmony_ci		if (mbi >= 2 * AHA1542_MAILBOXES)
3118c2ecf20Sopenharmony_ci			mbi = AHA1542_MAILBOXES;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci		do {
3148c2ecf20Sopenharmony_ci			if (mb[mbi].status != 0)
3158c2ecf20Sopenharmony_ci				break;
3168c2ecf20Sopenharmony_ci			mbi++;
3178c2ecf20Sopenharmony_ci			if (mbi >= 2 * AHA1542_MAILBOXES)
3188c2ecf20Sopenharmony_ci				mbi = AHA1542_MAILBOXES;
3198c2ecf20Sopenharmony_ci		} while (mbi != aha1542->aha1542_last_mbi_used);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci		if (mb[mbi].status == 0) {
3228c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(sh->host_lock, flags);
3238c2ecf20Sopenharmony_ci			/* Hmm, no mail.  Must have read it the last time around */
3248c2ecf20Sopenharmony_ci			if (!number_serviced)
3258c2ecf20Sopenharmony_ci				shost_printk(KERN_WARNING, sh, "interrupt received, but no mail.\n");
3268c2ecf20Sopenharmony_ci			return IRQ_HANDLED;
3278c2ecf20Sopenharmony_ci		};
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci		mbo = (scsi2int(mb[mbi].ccbptr) - (unsigned long)aha1542->ccb_handle) / sizeof(struct ccb);
3308c2ecf20Sopenharmony_ci		mbistatus = mb[mbi].status;
3318c2ecf20Sopenharmony_ci		mb[mbi].status = 0;
3328c2ecf20Sopenharmony_ci		aha1542->aha1542_last_mbi_used = mbi;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci#ifdef DEBUG
3358c2ecf20Sopenharmony_ci		if (ccb[mbo].tarstat | ccb[mbo].hastat)
3368c2ecf20Sopenharmony_ci			shost_printk(KERN_DEBUG, sh, "aha1542_command: returning %x (status %d)\n",
3378c2ecf20Sopenharmony_ci			       ccb[mbo].tarstat + ((int) ccb[mbo].hastat << 16), mb[mbi].status);
3388c2ecf20Sopenharmony_ci#endif
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci		if (mbistatus == 3)
3418c2ecf20Sopenharmony_ci			continue;	/* Aborted command not found */
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci#ifdef DEBUG
3448c2ecf20Sopenharmony_ci		shost_printk(KERN_DEBUG, sh, "...done %d %d\n", mbo, mbi);
3458c2ecf20Sopenharmony_ci#endif
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci		tmp_cmd = aha1542->int_cmds[mbo];
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci		if (!tmp_cmd || !tmp_cmd->scsi_done) {
3508c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(sh->host_lock, flags);
3518c2ecf20Sopenharmony_ci			shost_printk(KERN_WARNING, sh, "Unexpected interrupt\n");
3528c2ecf20Sopenharmony_ci			shost_printk(KERN_WARNING, sh, "tarstat=%x, hastat=%x idlun=%x ccb#=%d\n", ccb[mbo].tarstat,
3538c2ecf20Sopenharmony_ci			       ccb[mbo].hastat, ccb[mbo].idlun, mbo);
3548c2ecf20Sopenharmony_ci			return IRQ_HANDLED;
3558c2ecf20Sopenharmony_ci		}
3568c2ecf20Sopenharmony_ci		my_done = tmp_cmd->scsi_done;
3578c2ecf20Sopenharmony_ci		aha1542_free_cmd(tmp_cmd);
3588c2ecf20Sopenharmony_ci		/* Fetch the sense data, and tuck it away, in the required slot.  The
3598c2ecf20Sopenharmony_ci		   Adaptec automatically fetches it, and there is no guarantee that
3608c2ecf20Sopenharmony_ci		   we will still have it in the cdb when we come back */
3618c2ecf20Sopenharmony_ci		if (ccb[mbo].tarstat == 2)
3628c2ecf20Sopenharmony_ci			memcpy(tmp_cmd->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen],
3638c2ecf20Sopenharmony_ci			       SCSI_SENSE_BUFFERSIZE);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci		/* is there mail :-) */
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci		/* more error checking left out here */
3698c2ecf20Sopenharmony_ci		if (mbistatus != 1)
3708c2ecf20Sopenharmony_ci			/* This is surely wrong, but I don't know what's right */
3718c2ecf20Sopenharmony_ci			errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat);
3728c2ecf20Sopenharmony_ci		else
3738c2ecf20Sopenharmony_ci			errstatus = 0;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci#ifdef DEBUG
3768c2ecf20Sopenharmony_ci		if (errstatus)
3778c2ecf20Sopenharmony_ci			shost_printk(KERN_DEBUG, sh, "(aha1542 error:%x %x %x) ", errstatus,
3788c2ecf20Sopenharmony_ci			       ccb[mbo].hastat, ccb[mbo].tarstat);
3798c2ecf20Sopenharmony_ci		if (ccb[mbo].tarstat == 2)
3808c2ecf20Sopenharmony_ci			print_hex_dump_bytes("sense: ", DUMP_PREFIX_NONE, &ccb[mbo].cdb[ccb[mbo].cdblen], 12);
3818c2ecf20Sopenharmony_ci		if (errstatus)
3828c2ecf20Sopenharmony_ci			printk("aha1542_intr_handle: returning %6x\n", errstatus);
3838c2ecf20Sopenharmony_ci#endif
3848c2ecf20Sopenharmony_ci		tmp_cmd->result = errstatus;
3858c2ecf20Sopenharmony_ci		aha1542->int_cmds[mbo] = NULL;	/* This effectively frees up the mailbox slot, as
3868c2ecf20Sopenharmony_ci						   far as queuecommand is concerned */
3878c2ecf20Sopenharmony_ci		my_done(tmp_cmd);
3888c2ecf20Sopenharmony_ci		number_serviced++;
3898c2ecf20Sopenharmony_ci	};
3908c2ecf20Sopenharmony_ci}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_cistatic int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
3938c2ecf20Sopenharmony_ci{
3948c2ecf20Sopenharmony_ci	struct aha1542_cmd *acmd = scsi_cmd_priv(cmd);
3958c2ecf20Sopenharmony_ci	struct aha1542_hostdata *aha1542 = shost_priv(sh);
3968c2ecf20Sopenharmony_ci	u8 direction;
3978c2ecf20Sopenharmony_ci	u8 target = cmd->device->id;
3988c2ecf20Sopenharmony_ci	u8 lun = cmd->device->lun;
3998c2ecf20Sopenharmony_ci	unsigned long flags;
4008c2ecf20Sopenharmony_ci	int bufflen = scsi_bufflen(cmd);
4018c2ecf20Sopenharmony_ci	int mbo, sg_count;
4028c2ecf20Sopenharmony_ci	struct mailbox *mb = aha1542->mb;
4038c2ecf20Sopenharmony_ci	struct ccb *ccb = aha1542->ccb;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	if (*cmd->cmnd == REQUEST_SENSE) {
4068c2ecf20Sopenharmony_ci		/* Don't do the command - we have the sense data already */
4078c2ecf20Sopenharmony_ci		cmd->result = 0;
4088c2ecf20Sopenharmony_ci		cmd->scsi_done(cmd);
4098c2ecf20Sopenharmony_ci		return 0;
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci#ifdef DEBUG
4128c2ecf20Sopenharmony_ci	{
4138c2ecf20Sopenharmony_ci		int i = -1;
4148c2ecf20Sopenharmony_ci		if (*cmd->cmnd == READ_10 || *cmd->cmnd == WRITE_10)
4158c2ecf20Sopenharmony_ci			i = xscsi2int(cmd->cmnd + 2);
4168c2ecf20Sopenharmony_ci		else if (*cmd->cmnd == READ_6 || *cmd->cmnd == WRITE_6)
4178c2ecf20Sopenharmony_ci			i = scsi2int(cmd->cmnd + 2);
4188c2ecf20Sopenharmony_ci		shost_printk(KERN_DEBUG, sh, "aha1542_queuecommand: dev %d cmd %02x pos %d len %d",
4198c2ecf20Sopenharmony_ci						target, *cmd->cmnd, i, bufflen);
4208c2ecf20Sopenharmony_ci		print_hex_dump_bytes("command: ", DUMP_PREFIX_NONE, cmd->cmnd, cmd->cmd_len);
4218c2ecf20Sopenharmony_ci	}
4228c2ecf20Sopenharmony_ci#endif
4238c2ecf20Sopenharmony_ci	sg_count = scsi_dma_map(cmd);
4248c2ecf20Sopenharmony_ci	if (sg_count) {
4258c2ecf20Sopenharmony_ci		size_t len = sg_count * sizeof(struct chain);
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci		acmd->chain = kmalloc(len, GFP_DMA);
4288c2ecf20Sopenharmony_ci		if (!acmd->chain)
4298c2ecf20Sopenharmony_ci			goto out_unmap;
4308c2ecf20Sopenharmony_ci		acmd->chain_handle = dma_map_single(sh->dma_dev, acmd->chain,
4318c2ecf20Sopenharmony_ci				len, DMA_TO_DEVICE);
4328c2ecf20Sopenharmony_ci		if (dma_mapping_error(sh->dma_dev, acmd->chain_handle))
4338c2ecf20Sopenharmony_ci			goto out_free_chain;
4348c2ecf20Sopenharmony_ci	}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	/* Use the outgoing mailboxes in a round-robin fashion, because this
4378c2ecf20Sopenharmony_ci	   is how the host adapter will scan for them */
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	spin_lock_irqsave(sh->host_lock, flags);
4408c2ecf20Sopenharmony_ci	mbo = aha1542->aha1542_last_mbo_used + 1;
4418c2ecf20Sopenharmony_ci	if (mbo >= AHA1542_MAILBOXES)
4428c2ecf20Sopenharmony_ci		mbo = 0;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	do {
4458c2ecf20Sopenharmony_ci		if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL)
4468c2ecf20Sopenharmony_ci			break;
4478c2ecf20Sopenharmony_ci		mbo++;
4488c2ecf20Sopenharmony_ci		if (mbo >= AHA1542_MAILBOXES)
4498c2ecf20Sopenharmony_ci			mbo = 0;
4508c2ecf20Sopenharmony_ci	} while (mbo != aha1542->aha1542_last_mbo_used);
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	if (mb[mbo].status || aha1542->int_cmds[mbo])
4538c2ecf20Sopenharmony_ci		panic("Unable to find empty mailbox for aha1542.\n");
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	aha1542->int_cmds[mbo] = cmd;	/* This will effectively prevent someone else from
4568c2ecf20Sopenharmony_ci					   screwing with this cdb. */
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	aha1542->aha1542_last_mbo_used = mbo;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci#ifdef DEBUG
4618c2ecf20Sopenharmony_ci	shost_printk(KERN_DEBUG, sh, "Sending command (%d %p)...", mbo, cmd->scsi_done);
4628c2ecf20Sopenharmony_ci#endif
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	/* This gets trashed for some reason */
4658c2ecf20Sopenharmony_ci	any2scsi(mb[mbo].ccbptr, aha1542->ccb_handle + mbo * sizeof(*ccb));
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	memset(&ccb[mbo], 0, sizeof(struct ccb));
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	ccb[mbo].cdblen = cmd->cmd_len;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	direction = 0;
4728c2ecf20Sopenharmony_ci	if (*cmd->cmnd == READ_10 || *cmd->cmnd == READ_6)
4738c2ecf20Sopenharmony_ci		direction = 8;
4748c2ecf20Sopenharmony_ci	else if (*cmd->cmnd == WRITE_10 || *cmd->cmnd == WRITE_6)
4758c2ecf20Sopenharmony_ci		direction = 16;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	memcpy(ccb[mbo].cdb, cmd->cmnd, ccb[mbo].cdblen);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	if (bufflen) {
4808c2ecf20Sopenharmony_ci		struct scatterlist *sg;
4818c2ecf20Sopenharmony_ci		int i;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci		ccb[mbo].op = 2;	/* SCSI Initiator Command  w/scatter-gather */
4848c2ecf20Sopenharmony_ci		scsi_for_each_sg(cmd, sg, sg_count, i) {
4858c2ecf20Sopenharmony_ci			any2scsi(acmd->chain[i].dataptr, sg_dma_address(sg));
4868c2ecf20Sopenharmony_ci			any2scsi(acmd->chain[i].datalen, sg_dma_len(sg));
4878c2ecf20Sopenharmony_ci		};
4888c2ecf20Sopenharmony_ci		any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain));
4898c2ecf20Sopenharmony_ci		any2scsi(ccb[mbo].dataptr, acmd->chain_handle);
4908c2ecf20Sopenharmony_ci#ifdef DEBUG
4918c2ecf20Sopenharmony_ci		shost_printk(KERN_DEBUG, sh, "cptr %p: ", acmd->chain);
4928c2ecf20Sopenharmony_ci		print_hex_dump_bytes("cptr: ", DUMP_PREFIX_NONE, acmd->chain, 18);
4938c2ecf20Sopenharmony_ci#endif
4948c2ecf20Sopenharmony_ci	} else {
4958c2ecf20Sopenharmony_ci		ccb[mbo].op = 0;	/* SCSI Initiator Command */
4968c2ecf20Sopenharmony_ci		any2scsi(ccb[mbo].datalen, 0);
4978c2ecf20Sopenharmony_ci		any2scsi(ccb[mbo].dataptr, 0);
4988c2ecf20Sopenharmony_ci	};
4998c2ecf20Sopenharmony_ci	ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7);	/*SCSI Target Id */
5008c2ecf20Sopenharmony_ci	ccb[mbo].rsalen = 16;
5018c2ecf20Sopenharmony_ci	ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
5028c2ecf20Sopenharmony_ci	ccb[mbo].commlinkid = 0;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci#ifdef DEBUG
5058c2ecf20Sopenharmony_ci	print_hex_dump_bytes("sending: ", DUMP_PREFIX_NONE, &ccb[mbo], sizeof(ccb[mbo]) - 10);
5068c2ecf20Sopenharmony_ci	printk("aha1542_queuecommand: now waiting for interrupt ");
5078c2ecf20Sopenharmony_ci#endif
5088c2ecf20Sopenharmony_ci	mb[mbo].status = 1;
5098c2ecf20Sopenharmony_ci	aha1542_outb(cmd->device->host->io_port, CMD_START_SCSI);
5108c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(sh->host_lock, flags);
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	return 0;
5138c2ecf20Sopenharmony_ciout_free_chain:
5148c2ecf20Sopenharmony_ci	kfree(acmd->chain);
5158c2ecf20Sopenharmony_ci	acmd->chain = NULL;
5168c2ecf20Sopenharmony_ciout_unmap:
5178c2ecf20Sopenharmony_ci	scsi_dma_unmap(cmd);
5188c2ecf20Sopenharmony_ci	return SCSI_MLQUEUE_HOST_BUSY;
5198c2ecf20Sopenharmony_ci}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci/* Initialize mailboxes */
5228c2ecf20Sopenharmony_cistatic void setup_mailboxes(struct Scsi_Host *sh)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	struct aha1542_hostdata *aha1542 = shost_priv(sh);
5258c2ecf20Sopenharmony_ci	u8 mb_cmd[5] = { CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0};
5268c2ecf20Sopenharmony_ci	int i;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	for (i = 0; i < AHA1542_MAILBOXES; i++) {
5298c2ecf20Sopenharmony_ci		aha1542->mb[i].status = 0;
5308c2ecf20Sopenharmony_ci		any2scsi(aha1542->mb[i].ccbptr,
5318c2ecf20Sopenharmony_ci			 aha1542->ccb_handle + i * sizeof(struct ccb));
5328c2ecf20Sopenharmony_ci		aha1542->mb[AHA1542_MAILBOXES + i].status = 0;
5338c2ecf20Sopenharmony_ci	};
5348c2ecf20Sopenharmony_ci	aha1542_intr_reset(sh->io_port);	/* reset interrupts, so they don't block */
5358c2ecf20Sopenharmony_ci	any2scsi(mb_cmd + 2, aha1542->mb_handle);
5368c2ecf20Sopenharmony_ci	if (aha1542_out(sh->io_port, mb_cmd, 5))
5378c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, sh, "failed setting up mailboxes\n");
5388c2ecf20Sopenharmony_ci	aha1542_intr_reset(sh->io_port);
5398c2ecf20Sopenharmony_ci}
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_cistatic int aha1542_getconfig(struct Scsi_Host *sh)
5428c2ecf20Sopenharmony_ci{
5438c2ecf20Sopenharmony_ci	u8 inquiry_result[3];
5448c2ecf20Sopenharmony_ci	int i;
5458c2ecf20Sopenharmony_ci	i = inb(STATUS(sh->io_port));
5468c2ecf20Sopenharmony_ci	if (i & DF) {
5478c2ecf20Sopenharmony_ci		i = inb(DATA(sh->io_port));
5488c2ecf20Sopenharmony_ci	};
5498c2ecf20Sopenharmony_ci	aha1542_outb(sh->io_port, CMD_RETCONF);
5508c2ecf20Sopenharmony_ci	aha1542_in(sh->io_port, inquiry_result, 3, 0);
5518c2ecf20Sopenharmony_ci	if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0))
5528c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, sh, "error querying board settings\n");
5538c2ecf20Sopenharmony_ci	aha1542_intr_reset(sh->io_port);
5548c2ecf20Sopenharmony_ci	switch (inquiry_result[0]) {
5558c2ecf20Sopenharmony_ci	case 0x80:
5568c2ecf20Sopenharmony_ci		sh->dma_channel = 7;
5578c2ecf20Sopenharmony_ci		break;
5588c2ecf20Sopenharmony_ci	case 0x40:
5598c2ecf20Sopenharmony_ci		sh->dma_channel = 6;
5608c2ecf20Sopenharmony_ci		break;
5618c2ecf20Sopenharmony_ci	case 0x20:
5628c2ecf20Sopenharmony_ci		sh->dma_channel = 5;
5638c2ecf20Sopenharmony_ci		break;
5648c2ecf20Sopenharmony_ci	case 0x01:
5658c2ecf20Sopenharmony_ci		sh->dma_channel = 0;
5668c2ecf20Sopenharmony_ci		break;
5678c2ecf20Sopenharmony_ci	case 0:
5688c2ecf20Sopenharmony_ci		/* This means that the adapter, although Adaptec 1542 compatible, doesn't use a DMA channel.
5698c2ecf20Sopenharmony_ci		   Currently only aware of the BusLogic BT-445S VL-Bus adapter which needs this. */
5708c2ecf20Sopenharmony_ci		sh->dma_channel = 0xFF;
5718c2ecf20Sopenharmony_ci		break;
5728c2ecf20Sopenharmony_ci	default:
5738c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, sh, "Unable to determine DMA channel.\n");
5748c2ecf20Sopenharmony_ci		return -1;
5758c2ecf20Sopenharmony_ci	};
5768c2ecf20Sopenharmony_ci	switch (inquiry_result[1]) {
5778c2ecf20Sopenharmony_ci	case 0x40:
5788c2ecf20Sopenharmony_ci		sh->irq = 15;
5798c2ecf20Sopenharmony_ci		break;
5808c2ecf20Sopenharmony_ci	case 0x20:
5818c2ecf20Sopenharmony_ci		sh->irq = 14;
5828c2ecf20Sopenharmony_ci		break;
5838c2ecf20Sopenharmony_ci	case 0x8:
5848c2ecf20Sopenharmony_ci		sh->irq = 12;
5858c2ecf20Sopenharmony_ci		break;
5868c2ecf20Sopenharmony_ci	case 0x4:
5878c2ecf20Sopenharmony_ci		sh->irq = 11;
5888c2ecf20Sopenharmony_ci		break;
5898c2ecf20Sopenharmony_ci	case 0x2:
5908c2ecf20Sopenharmony_ci		sh->irq = 10;
5918c2ecf20Sopenharmony_ci		break;
5928c2ecf20Sopenharmony_ci	case 0x1:
5938c2ecf20Sopenharmony_ci		sh->irq = 9;
5948c2ecf20Sopenharmony_ci		break;
5958c2ecf20Sopenharmony_ci	default:
5968c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, sh, "Unable to determine IRQ level.\n");
5978c2ecf20Sopenharmony_ci		return -1;
5988c2ecf20Sopenharmony_ci	};
5998c2ecf20Sopenharmony_ci	sh->this_id = inquiry_result[2] & 7;
6008c2ecf20Sopenharmony_ci	return 0;
6018c2ecf20Sopenharmony_ci}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci/* This function should only be called for 1542C boards - we can detect
6048c2ecf20Sopenharmony_ci   the special firmware settings and unlock the board */
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_cistatic int aha1542_mbenable(struct Scsi_Host *sh)
6078c2ecf20Sopenharmony_ci{
6088c2ecf20Sopenharmony_ci	static u8 mbenable_cmd[3];
6098c2ecf20Sopenharmony_ci	static u8 mbenable_result[2];
6108c2ecf20Sopenharmony_ci	int retval;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	retval = BIOS_TRANSLATION_6432;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	aha1542_outb(sh->io_port, CMD_EXTBIOS);
6158c2ecf20Sopenharmony_ci	if (aha1542_in(sh->io_port, mbenable_result, 2, 100))
6168c2ecf20Sopenharmony_ci		return retval;
6178c2ecf20Sopenharmony_ci	if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 100))
6188c2ecf20Sopenharmony_ci		goto fail;
6198c2ecf20Sopenharmony_ci	aha1542_intr_reset(sh->io_port);
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	if ((mbenable_result[0] & 0x08) || mbenable_result[1]) {
6228c2ecf20Sopenharmony_ci		mbenable_cmd[0] = CMD_MBENABLE;
6238c2ecf20Sopenharmony_ci		mbenable_cmd[1] = 0;
6248c2ecf20Sopenharmony_ci		mbenable_cmd[2] = mbenable_result[1];
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci		if ((mbenable_result[0] & 0x08) && (mbenable_result[1] & 0x03))
6278c2ecf20Sopenharmony_ci			retval = BIOS_TRANSLATION_25563;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci		if (aha1542_out(sh->io_port, mbenable_cmd, 3))
6308c2ecf20Sopenharmony_ci			goto fail;
6318c2ecf20Sopenharmony_ci	};
6328c2ecf20Sopenharmony_ci	while (0) {
6338c2ecf20Sopenharmony_cifail:
6348c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, sh, "Mailbox init failed\n");
6358c2ecf20Sopenharmony_ci	}
6368c2ecf20Sopenharmony_ci	aha1542_intr_reset(sh->io_port);
6378c2ecf20Sopenharmony_ci	return retval;
6388c2ecf20Sopenharmony_ci}
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci/* Query the board to find out if it is a 1542 or a 1740, or whatever. */
6418c2ecf20Sopenharmony_cistatic int aha1542_query(struct Scsi_Host *sh)
6428c2ecf20Sopenharmony_ci{
6438c2ecf20Sopenharmony_ci	struct aha1542_hostdata *aha1542 = shost_priv(sh);
6448c2ecf20Sopenharmony_ci	u8 inquiry_result[4];
6458c2ecf20Sopenharmony_ci	int i;
6468c2ecf20Sopenharmony_ci	i = inb(STATUS(sh->io_port));
6478c2ecf20Sopenharmony_ci	if (i & DF) {
6488c2ecf20Sopenharmony_ci		i = inb(DATA(sh->io_port));
6498c2ecf20Sopenharmony_ci	};
6508c2ecf20Sopenharmony_ci	aha1542_outb(sh->io_port, CMD_INQUIRY);
6518c2ecf20Sopenharmony_ci	aha1542_in(sh->io_port, inquiry_result, 4, 0);
6528c2ecf20Sopenharmony_ci	if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0))
6538c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, sh, "error querying card type\n");
6548c2ecf20Sopenharmony_ci	aha1542_intr_reset(sh->io_port);
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	aha1542->bios_translation = BIOS_TRANSLATION_6432;	/* Default case */
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	/* For an AHA1740 series board, we ignore the board since there is a
6598c2ecf20Sopenharmony_ci	   hardware bug which can lead to wrong blocks being returned if the board
6608c2ecf20Sopenharmony_ci	   is operating in the 1542 emulation mode.  Since there is an extended mode
6618c2ecf20Sopenharmony_ci	   driver, we simply ignore the board and let the 1740 driver pick it up.
6628c2ecf20Sopenharmony_ci	 */
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	if (inquiry_result[0] == 0x43) {
6658c2ecf20Sopenharmony_ci		shost_printk(KERN_INFO, sh, "Emulation mode not supported for AHA-1740 hardware, use aha1740 driver instead.\n");
6668c2ecf20Sopenharmony_ci		return 1;
6678c2ecf20Sopenharmony_ci	};
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	/* Always call this - boards that do not support extended bios translation
6708c2ecf20Sopenharmony_ci	   will ignore the command, and we will set the proper default */
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	aha1542->bios_translation = aha1542_mbenable(sh);
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	return 0;
6758c2ecf20Sopenharmony_ci}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_cistatic u8 dma_speed_hw(int dma_speed)
6788c2ecf20Sopenharmony_ci{
6798c2ecf20Sopenharmony_ci	switch (dma_speed) {
6808c2ecf20Sopenharmony_ci	case 5:
6818c2ecf20Sopenharmony_ci		return 0x00;
6828c2ecf20Sopenharmony_ci	case 6:
6838c2ecf20Sopenharmony_ci		return 0x04;
6848c2ecf20Sopenharmony_ci	case 7:
6858c2ecf20Sopenharmony_ci		return 0x01;
6868c2ecf20Sopenharmony_ci	case 8:
6878c2ecf20Sopenharmony_ci		return 0x02;
6888c2ecf20Sopenharmony_ci	case 10:
6898c2ecf20Sopenharmony_ci		return 0x03;
6908c2ecf20Sopenharmony_ci	}
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	return 0xff;	/* invalid */
6938c2ecf20Sopenharmony_ci}
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci/* Set the Bus on/off-times as not to ruin floppy performance */
6968c2ecf20Sopenharmony_cistatic void aha1542_set_bus_times(struct Scsi_Host *sh, int bus_on, int bus_off, int dma_speed)
6978c2ecf20Sopenharmony_ci{
6988c2ecf20Sopenharmony_ci	if (bus_on > 0) {
6998c2ecf20Sopenharmony_ci		u8 oncmd[] = { CMD_BUSON_TIME, clamp(bus_on, 2, 15) };
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci		aha1542_intr_reset(sh->io_port);
7028c2ecf20Sopenharmony_ci		if (aha1542_out(sh->io_port, oncmd, 2))
7038c2ecf20Sopenharmony_ci			goto fail;
7048c2ecf20Sopenharmony_ci	}
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	if (bus_off > 0) {
7078c2ecf20Sopenharmony_ci		u8 offcmd[] = { CMD_BUSOFF_TIME, clamp(bus_off, 1, 64) };
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci		aha1542_intr_reset(sh->io_port);
7108c2ecf20Sopenharmony_ci		if (aha1542_out(sh->io_port, offcmd, 2))
7118c2ecf20Sopenharmony_ci			goto fail;
7128c2ecf20Sopenharmony_ci	}
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	if (dma_speed_hw(dma_speed) != 0xff) {
7158c2ecf20Sopenharmony_ci		u8 dmacmd[] = { CMD_DMASPEED, dma_speed_hw(dma_speed) };
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci		aha1542_intr_reset(sh->io_port);
7188c2ecf20Sopenharmony_ci		if (aha1542_out(sh->io_port, dmacmd, 2))
7198c2ecf20Sopenharmony_ci			goto fail;
7208c2ecf20Sopenharmony_ci	}
7218c2ecf20Sopenharmony_ci	aha1542_intr_reset(sh->io_port);
7228c2ecf20Sopenharmony_ci	return;
7238c2ecf20Sopenharmony_cifail:
7248c2ecf20Sopenharmony_ci	shost_printk(KERN_ERR, sh, "setting bus on/off-time failed\n");
7258c2ecf20Sopenharmony_ci	aha1542_intr_reset(sh->io_port);
7268c2ecf20Sopenharmony_ci}
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci/* return non-zero on detection */
7298c2ecf20Sopenharmony_cistatic struct Scsi_Host *aha1542_hw_init(struct scsi_host_template *tpnt, struct device *pdev, int indx)
7308c2ecf20Sopenharmony_ci{
7318c2ecf20Sopenharmony_ci	unsigned int base_io = io[indx];
7328c2ecf20Sopenharmony_ci	struct Scsi_Host *sh;
7338c2ecf20Sopenharmony_ci	struct aha1542_hostdata *aha1542;
7348c2ecf20Sopenharmony_ci	char dma_info[] = "no DMA";
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	if (base_io == 0)
7378c2ecf20Sopenharmony_ci		return NULL;
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	if (!request_region(base_io, AHA1542_REGION_SIZE, "aha1542"))
7408c2ecf20Sopenharmony_ci		return NULL;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	sh = scsi_host_alloc(tpnt, sizeof(struct aha1542_hostdata));
7438c2ecf20Sopenharmony_ci	if (!sh)
7448c2ecf20Sopenharmony_ci		goto release;
7458c2ecf20Sopenharmony_ci	aha1542 = shost_priv(sh);
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	sh->unique_id = base_io;
7488c2ecf20Sopenharmony_ci	sh->io_port = base_io;
7498c2ecf20Sopenharmony_ci	sh->n_io_port = AHA1542_REGION_SIZE;
7508c2ecf20Sopenharmony_ci	aha1542->aha1542_last_mbi_used = 2 * AHA1542_MAILBOXES - 1;
7518c2ecf20Sopenharmony_ci	aha1542->aha1542_last_mbo_used = AHA1542_MAILBOXES - 1;
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	if (!aha1542_test_port(sh))
7548c2ecf20Sopenharmony_ci		goto unregister;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	aha1542_set_bus_times(sh, bus_on[indx], bus_off[indx], dma_speed[indx]);
7578c2ecf20Sopenharmony_ci	if (aha1542_query(sh))
7588c2ecf20Sopenharmony_ci		goto unregister;
7598c2ecf20Sopenharmony_ci	if (aha1542_getconfig(sh) == -1)
7608c2ecf20Sopenharmony_ci		goto unregister;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	if (sh->dma_channel != 0xFF)
7638c2ecf20Sopenharmony_ci		snprintf(dma_info, sizeof(dma_info), "DMA %d", sh->dma_channel);
7648c2ecf20Sopenharmony_ci	shost_printk(KERN_INFO, sh, "Adaptec AHA-1542 (SCSI-ID %d) at IO 0x%x, IRQ %d, %s\n",
7658c2ecf20Sopenharmony_ci				sh->this_id, base_io, sh->irq, dma_info);
7668c2ecf20Sopenharmony_ci	if (aha1542->bios_translation == BIOS_TRANSLATION_25563)
7678c2ecf20Sopenharmony_ci		shost_printk(KERN_INFO, sh, "Using extended bios translation\n");
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	if (dma_set_mask_and_coherent(pdev, DMA_BIT_MASK(24)) < 0)
7708c2ecf20Sopenharmony_ci		goto unregister;
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	aha1542->mb = dma_alloc_coherent(pdev,
7738c2ecf20Sopenharmony_ci			AHA1542_MAILBOXES * 2 * sizeof(struct mailbox),
7748c2ecf20Sopenharmony_ci			&aha1542->mb_handle, GFP_KERNEL);
7758c2ecf20Sopenharmony_ci	if (!aha1542->mb)
7768c2ecf20Sopenharmony_ci		goto unregister;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	aha1542->ccb = dma_alloc_coherent(pdev,
7798c2ecf20Sopenharmony_ci			AHA1542_MAILBOXES * sizeof(struct ccb),
7808c2ecf20Sopenharmony_ci			&aha1542->ccb_handle, GFP_KERNEL);
7818c2ecf20Sopenharmony_ci	if (!aha1542->ccb)
7828c2ecf20Sopenharmony_ci		goto free_mb;
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	setup_mailboxes(sh);
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	if (request_irq(sh->irq, aha1542_interrupt, 0, "aha1542", sh)) {
7878c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, sh, "Unable to allocate IRQ.\n");
7888c2ecf20Sopenharmony_ci		goto free_ccb;
7898c2ecf20Sopenharmony_ci	}
7908c2ecf20Sopenharmony_ci	if (sh->dma_channel != 0xFF) {
7918c2ecf20Sopenharmony_ci		if (request_dma(sh->dma_channel, "aha1542")) {
7928c2ecf20Sopenharmony_ci			shost_printk(KERN_ERR, sh, "Unable to allocate DMA channel.\n");
7938c2ecf20Sopenharmony_ci			goto free_irq;
7948c2ecf20Sopenharmony_ci		}
7958c2ecf20Sopenharmony_ci		if (sh->dma_channel == 0 || sh->dma_channel >= 5) {
7968c2ecf20Sopenharmony_ci			set_dma_mode(sh->dma_channel, DMA_MODE_CASCADE);
7978c2ecf20Sopenharmony_ci			enable_dma(sh->dma_channel);
7988c2ecf20Sopenharmony_ci		}
7998c2ecf20Sopenharmony_ci	}
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	if (scsi_add_host(sh, pdev))
8028c2ecf20Sopenharmony_ci		goto free_dma;
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	scsi_scan_host(sh);
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	return sh;
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_cifree_dma:
8098c2ecf20Sopenharmony_ci	if (sh->dma_channel != 0xff)
8108c2ecf20Sopenharmony_ci		free_dma(sh->dma_channel);
8118c2ecf20Sopenharmony_cifree_irq:
8128c2ecf20Sopenharmony_ci	free_irq(sh->irq, sh);
8138c2ecf20Sopenharmony_cifree_ccb:
8148c2ecf20Sopenharmony_ci	dma_free_coherent(pdev, AHA1542_MAILBOXES * sizeof(struct ccb),
8158c2ecf20Sopenharmony_ci			  aha1542->ccb, aha1542->ccb_handle);
8168c2ecf20Sopenharmony_cifree_mb:
8178c2ecf20Sopenharmony_ci	dma_free_coherent(pdev, AHA1542_MAILBOXES * 2 * sizeof(struct mailbox),
8188c2ecf20Sopenharmony_ci			  aha1542->mb, aha1542->mb_handle);
8198c2ecf20Sopenharmony_ciunregister:
8208c2ecf20Sopenharmony_ci	scsi_host_put(sh);
8218c2ecf20Sopenharmony_cirelease:
8228c2ecf20Sopenharmony_ci	release_region(base_io, AHA1542_REGION_SIZE);
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	return NULL;
8258c2ecf20Sopenharmony_ci}
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_cistatic int aha1542_release(struct Scsi_Host *sh)
8288c2ecf20Sopenharmony_ci{
8298c2ecf20Sopenharmony_ci	struct aha1542_hostdata *aha1542 = shost_priv(sh);
8308c2ecf20Sopenharmony_ci	struct device *dev = sh->dma_dev;
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	scsi_remove_host(sh);
8338c2ecf20Sopenharmony_ci	if (sh->dma_channel != 0xff)
8348c2ecf20Sopenharmony_ci		free_dma(sh->dma_channel);
8358c2ecf20Sopenharmony_ci	dma_free_coherent(dev, AHA1542_MAILBOXES * sizeof(struct ccb),
8368c2ecf20Sopenharmony_ci			  aha1542->ccb, aha1542->ccb_handle);
8378c2ecf20Sopenharmony_ci	dma_free_coherent(dev, AHA1542_MAILBOXES * 2 * sizeof(struct mailbox),
8388c2ecf20Sopenharmony_ci			  aha1542->mb, aha1542->mb_handle);
8398c2ecf20Sopenharmony_ci	if (sh->irq)
8408c2ecf20Sopenharmony_ci		free_irq(sh->irq, sh);
8418c2ecf20Sopenharmony_ci	if (sh->io_port && sh->n_io_port)
8428c2ecf20Sopenharmony_ci		release_region(sh->io_port, sh->n_io_port);
8438c2ecf20Sopenharmony_ci	scsi_host_put(sh);
8448c2ecf20Sopenharmony_ci	return 0;
8458c2ecf20Sopenharmony_ci}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci/*
8498c2ecf20Sopenharmony_ci * This is a device reset.  This is handled by sending a special command
8508c2ecf20Sopenharmony_ci * to the device.
8518c2ecf20Sopenharmony_ci */
8528c2ecf20Sopenharmony_cistatic int aha1542_dev_reset(struct scsi_cmnd *cmd)
8538c2ecf20Sopenharmony_ci{
8548c2ecf20Sopenharmony_ci	struct Scsi_Host *sh = cmd->device->host;
8558c2ecf20Sopenharmony_ci	struct aha1542_hostdata *aha1542 = shost_priv(sh);
8568c2ecf20Sopenharmony_ci	unsigned long flags;
8578c2ecf20Sopenharmony_ci	struct mailbox *mb = aha1542->mb;
8588c2ecf20Sopenharmony_ci	u8 target = cmd->device->id;
8598c2ecf20Sopenharmony_ci	u8 lun = cmd->device->lun;
8608c2ecf20Sopenharmony_ci	int mbo;
8618c2ecf20Sopenharmony_ci	struct ccb *ccb = aha1542->ccb;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	spin_lock_irqsave(sh->host_lock, flags);
8648c2ecf20Sopenharmony_ci	mbo = aha1542->aha1542_last_mbo_used + 1;
8658c2ecf20Sopenharmony_ci	if (mbo >= AHA1542_MAILBOXES)
8668c2ecf20Sopenharmony_ci		mbo = 0;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	do {
8698c2ecf20Sopenharmony_ci		if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL)
8708c2ecf20Sopenharmony_ci			break;
8718c2ecf20Sopenharmony_ci		mbo++;
8728c2ecf20Sopenharmony_ci		if (mbo >= AHA1542_MAILBOXES)
8738c2ecf20Sopenharmony_ci			mbo = 0;
8748c2ecf20Sopenharmony_ci	} while (mbo != aha1542->aha1542_last_mbo_used);
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	if (mb[mbo].status || aha1542->int_cmds[mbo])
8778c2ecf20Sopenharmony_ci		panic("Unable to find empty mailbox for aha1542.\n");
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	aha1542->int_cmds[mbo] = cmd;	/* This will effectively
8808c2ecf20Sopenharmony_ci					   prevent someone else from
8818c2ecf20Sopenharmony_ci					   screwing with this cdb. */
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	aha1542->aha1542_last_mbo_used = mbo;
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	/* This gets trashed for some reason */
8868c2ecf20Sopenharmony_ci	any2scsi(mb[mbo].ccbptr, aha1542->ccb_handle + mbo * sizeof(*ccb));
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	memset(&ccb[mbo], 0, sizeof(struct ccb));
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	ccb[mbo].op = 0x81;	/* BUS DEVICE RESET */
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	ccb[mbo].idlun = (target & 7) << 5 | (lun & 7);		/*SCSI Target Id */
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
8958c2ecf20Sopenharmony_ci	ccb[mbo].commlinkid = 0;
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	/*
8988c2ecf20Sopenharmony_ci	 * Now tell the 1542 to flush all pending commands for this
8998c2ecf20Sopenharmony_ci	 * target
9008c2ecf20Sopenharmony_ci	 */
9018c2ecf20Sopenharmony_ci	aha1542_outb(sh->io_port, CMD_START_SCSI);
9028c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(sh->host_lock, flags);
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	scmd_printk(KERN_WARNING, cmd,
9058c2ecf20Sopenharmony_ci		"Trying device reset for target\n");
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	return SUCCESS;
9088c2ecf20Sopenharmony_ci}
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_cistatic int aha1542_reset(struct scsi_cmnd *cmd, u8 reset_cmd)
9118c2ecf20Sopenharmony_ci{
9128c2ecf20Sopenharmony_ci	struct Scsi_Host *sh = cmd->device->host;
9138c2ecf20Sopenharmony_ci	struct aha1542_hostdata *aha1542 = shost_priv(sh);
9148c2ecf20Sopenharmony_ci	unsigned long flags;
9158c2ecf20Sopenharmony_ci	int i;
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	spin_lock_irqsave(sh->host_lock, flags);
9188c2ecf20Sopenharmony_ci	/*
9198c2ecf20Sopenharmony_ci	 * This does a scsi reset for all devices on the bus.
9208c2ecf20Sopenharmony_ci	 * In principle, we could also reset the 1542 - should
9218c2ecf20Sopenharmony_ci	 * we do this?  Try this first, and we can add that later
9228c2ecf20Sopenharmony_ci	 * if it turns out to be useful.
9238c2ecf20Sopenharmony_ci	 */
9248c2ecf20Sopenharmony_ci	outb(reset_cmd, CONTROL(cmd->device->host->io_port));
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	if (!wait_mask(STATUS(cmd->device->host->io_port),
9278c2ecf20Sopenharmony_ci	     STATMASK, IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0)) {
9288c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(sh->host_lock, flags);
9298c2ecf20Sopenharmony_ci		return FAILED;
9308c2ecf20Sopenharmony_ci	}
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	/*
9338c2ecf20Sopenharmony_ci	 * We need to do this too before the 1542 can interact with
9348c2ecf20Sopenharmony_ci	 * us again after host reset.
9358c2ecf20Sopenharmony_ci	 */
9368c2ecf20Sopenharmony_ci	if (reset_cmd & HRST)
9378c2ecf20Sopenharmony_ci		setup_mailboxes(cmd->device->host);
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	/*
9408c2ecf20Sopenharmony_ci	 * Now try to pick up the pieces.  For all pending commands,
9418c2ecf20Sopenharmony_ci	 * free any internal data structures, and basically clear things
9428c2ecf20Sopenharmony_ci	 * out.  We do not try and restart any commands or anything -
9438c2ecf20Sopenharmony_ci	 * the strategy handler takes care of that crap.
9448c2ecf20Sopenharmony_ci	 */
9458c2ecf20Sopenharmony_ci	shost_printk(KERN_WARNING, cmd->device->host, "Sent BUS RESET to scsi host %d\n", cmd->device->host->host_no);
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	for (i = 0; i < AHA1542_MAILBOXES; i++) {
9488c2ecf20Sopenharmony_ci		if (aha1542->int_cmds[i] != NULL) {
9498c2ecf20Sopenharmony_ci			struct scsi_cmnd *tmp_cmd;
9508c2ecf20Sopenharmony_ci			tmp_cmd = aha1542->int_cmds[i];
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci			if (tmp_cmd->device->soft_reset) {
9538c2ecf20Sopenharmony_ci				/*
9548c2ecf20Sopenharmony_ci				 * If this device implements the soft reset option,
9558c2ecf20Sopenharmony_ci				 * then it is still holding onto the command, and
9568c2ecf20Sopenharmony_ci				 * may yet complete it.  In this case, we don't
9578c2ecf20Sopenharmony_ci				 * flush the data.
9588c2ecf20Sopenharmony_ci				 */
9598c2ecf20Sopenharmony_ci				continue;
9608c2ecf20Sopenharmony_ci			}
9618c2ecf20Sopenharmony_ci			aha1542_free_cmd(tmp_cmd);
9628c2ecf20Sopenharmony_ci			aha1542->int_cmds[i] = NULL;
9638c2ecf20Sopenharmony_ci			aha1542->mb[i].status = 0;
9648c2ecf20Sopenharmony_ci		}
9658c2ecf20Sopenharmony_ci	}
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(sh->host_lock, flags);
9688c2ecf20Sopenharmony_ci	return SUCCESS;
9698c2ecf20Sopenharmony_ci}
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_cistatic int aha1542_bus_reset(struct scsi_cmnd *cmd)
9728c2ecf20Sopenharmony_ci{
9738c2ecf20Sopenharmony_ci	return aha1542_reset(cmd, SCRST);
9748c2ecf20Sopenharmony_ci}
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_cistatic int aha1542_host_reset(struct scsi_cmnd *cmd)
9778c2ecf20Sopenharmony_ci{
9788c2ecf20Sopenharmony_ci	return aha1542_reset(cmd, HRST | SCRST);
9798c2ecf20Sopenharmony_ci}
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_cistatic int aha1542_biosparam(struct scsi_device *sdev,
9828c2ecf20Sopenharmony_ci		struct block_device *bdev, sector_t capacity, int geom[])
9838c2ecf20Sopenharmony_ci{
9848c2ecf20Sopenharmony_ci	struct aha1542_hostdata *aha1542 = shost_priv(sdev->host);
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	if (capacity >= 0x200000 &&
9878c2ecf20Sopenharmony_ci			aha1542->bios_translation == BIOS_TRANSLATION_25563) {
9888c2ecf20Sopenharmony_ci		/* Please verify that this is the same as what DOS returns */
9898c2ecf20Sopenharmony_ci		geom[0] = 255;	/* heads */
9908c2ecf20Sopenharmony_ci		geom[1] = 63;	/* sectors */
9918c2ecf20Sopenharmony_ci	} else {
9928c2ecf20Sopenharmony_ci		geom[0] = 64;	/* heads */
9938c2ecf20Sopenharmony_ci		geom[1] = 32;	/* sectors */
9948c2ecf20Sopenharmony_ci	}
9958c2ecf20Sopenharmony_ci	geom[2] = sector_div(capacity, geom[0] * geom[1]);	/* cylinders */
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	return 0;
9988c2ecf20Sopenharmony_ci}
9998c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_cistatic struct scsi_host_template driver_template = {
10028c2ecf20Sopenharmony_ci	.module			= THIS_MODULE,
10038c2ecf20Sopenharmony_ci	.proc_name		= "aha1542",
10048c2ecf20Sopenharmony_ci	.name			= "Adaptec 1542",
10058c2ecf20Sopenharmony_ci	.cmd_size		= sizeof(struct aha1542_cmd),
10068c2ecf20Sopenharmony_ci	.queuecommand		= aha1542_queuecommand,
10078c2ecf20Sopenharmony_ci	.eh_device_reset_handler= aha1542_dev_reset,
10088c2ecf20Sopenharmony_ci	.eh_bus_reset_handler	= aha1542_bus_reset,
10098c2ecf20Sopenharmony_ci	.eh_host_reset_handler	= aha1542_host_reset,
10108c2ecf20Sopenharmony_ci	.bios_param		= aha1542_biosparam,
10118c2ecf20Sopenharmony_ci	.can_queue		= AHA1542_MAILBOXES,
10128c2ecf20Sopenharmony_ci	.this_id		= 7,
10138c2ecf20Sopenharmony_ci	.sg_tablesize		= 16,
10148c2ecf20Sopenharmony_ci	.unchecked_isa_dma	= 1,
10158c2ecf20Sopenharmony_ci};
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_cistatic int aha1542_isa_match(struct device *pdev, unsigned int ndev)
10188c2ecf20Sopenharmony_ci{
10198c2ecf20Sopenharmony_ci	struct Scsi_Host *sh = aha1542_hw_init(&driver_template, pdev, ndev);
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	if (!sh)
10228c2ecf20Sopenharmony_ci		return 0;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	dev_set_drvdata(pdev, sh);
10258c2ecf20Sopenharmony_ci	return 1;
10268c2ecf20Sopenharmony_ci}
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_cistatic int aha1542_isa_remove(struct device *pdev,
10298c2ecf20Sopenharmony_ci				    unsigned int ndev)
10308c2ecf20Sopenharmony_ci{
10318c2ecf20Sopenharmony_ci	aha1542_release(dev_get_drvdata(pdev));
10328c2ecf20Sopenharmony_ci	dev_set_drvdata(pdev, NULL);
10338c2ecf20Sopenharmony_ci	return 0;
10348c2ecf20Sopenharmony_ci}
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_cistatic struct isa_driver aha1542_isa_driver = {
10378c2ecf20Sopenharmony_ci	.match		= aha1542_isa_match,
10388c2ecf20Sopenharmony_ci	.remove		= aha1542_isa_remove,
10398c2ecf20Sopenharmony_ci	.driver		= {
10408c2ecf20Sopenharmony_ci		.name	= "aha1542"
10418c2ecf20Sopenharmony_ci	},
10428c2ecf20Sopenharmony_ci};
10438c2ecf20Sopenharmony_cistatic int isa_registered;
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci#ifdef CONFIG_PNP
10468c2ecf20Sopenharmony_cistatic const struct pnp_device_id aha1542_pnp_ids[] = {
10478c2ecf20Sopenharmony_ci	{ .id = "ADP1542" },
10488c2ecf20Sopenharmony_ci	{ .id = "" }
10498c2ecf20Sopenharmony_ci};
10508c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pnp, aha1542_pnp_ids);
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_cistatic int aha1542_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *id)
10538c2ecf20Sopenharmony_ci{
10548c2ecf20Sopenharmony_ci	int indx;
10558c2ecf20Sopenharmony_ci	struct Scsi_Host *sh;
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	for (indx = 0; indx < ARRAY_SIZE(io); indx++) {
10588c2ecf20Sopenharmony_ci		if (io[indx])
10598c2ecf20Sopenharmony_ci			continue;
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci		if (pnp_activate_dev(pdev) < 0)
10628c2ecf20Sopenharmony_ci			continue;
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci		io[indx] = pnp_port_start(pdev, 0);
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci		/* The card can be queried for its DMA, we have
10678c2ecf20Sopenharmony_ci		   the DMA set up that is enough */
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci		dev_info(&pdev->dev, "ISAPnP found an AHA1535 at I/O 0x%03X", io[indx]);
10708c2ecf20Sopenharmony_ci	}
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	sh = aha1542_hw_init(&driver_template, &pdev->dev, indx);
10738c2ecf20Sopenharmony_ci	if (!sh)
10748c2ecf20Sopenharmony_ci		return -ENODEV;
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	pnp_set_drvdata(pdev, sh);
10778c2ecf20Sopenharmony_ci	return 0;
10788c2ecf20Sopenharmony_ci}
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_cistatic void aha1542_pnp_remove(struct pnp_dev *pdev)
10818c2ecf20Sopenharmony_ci{
10828c2ecf20Sopenharmony_ci	aha1542_release(pnp_get_drvdata(pdev));
10838c2ecf20Sopenharmony_ci	pnp_set_drvdata(pdev, NULL);
10848c2ecf20Sopenharmony_ci}
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_cistatic struct pnp_driver aha1542_pnp_driver = {
10878c2ecf20Sopenharmony_ci	.name		= "aha1542",
10888c2ecf20Sopenharmony_ci	.id_table	= aha1542_pnp_ids,
10898c2ecf20Sopenharmony_ci	.probe		= aha1542_pnp_probe,
10908c2ecf20Sopenharmony_ci	.remove		= aha1542_pnp_remove,
10918c2ecf20Sopenharmony_ci};
10928c2ecf20Sopenharmony_cistatic int pnp_registered;
10938c2ecf20Sopenharmony_ci#endif /* CONFIG_PNP */
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_cistatic int __init aha1542_init(void)
10968c2ecf20Sopenharmony_ci{
10978c2ecf20Sopenharmony_ci	int ret = 0;
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci#ifdef CONFIG_PNP
11008c2ecf20Sopenharmony_ci	if (isapnp) {
11018c2ecf20Sopenharmony_ci		ret = pnp_register_driver(&aha1542_pnp_driver);
11028c2ecf20Sopenharmony_ci		if (!ret)
11038c2ecf20Sopenharmony_ci			pnp_registered = 1;
11048c2ecf20Sopenharmony_ci	}
11058c2ecf20Sopenharmony_ci#endif
11068c2ecf20Sopenharmony_ci	ret = isa_register_driver(&aha1542_isa_driver, MAXBOARDS);
11078c2ecf20Sopenharmony_ci	if (!ret)
11088c2ecf20Sopenharmony_ci		isa_registered = 1;
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci#ifdef CONFIG_PNP
11118c2ecf20Sopenharmony_ci	if (pnp_registered)
11128c2ecf20Sopenharmony_ci		ret = 0;
11138c2ecf20Sopenharmony_ci#endif
11148c2ecf20Sopenharmony_ci	if (isa_registered)
11158c2ecf20Sopenharmony_ci		ret = 0;
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	return ret;
11188c2ecf20Sopenharmony_ci}
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_cistatic void __exit aha1542_exit(void)
11218c2ecf20Sopenharmony_ci{
11228c2ecf20Sopenharmony_ci#ifdef CONFIG_PNP
11238c2ecf20Sopenharmony_ci	if (pnp_registered)
11248c2ecf20Sopenharmony_ci		pnp_unregister_driver(&aha1542_pnp_driver);
11258c2ecf20Sopenharmony_ci#endif
11268c2ecf20Sopenharmony_ci	if (isa_registered)
11278c2ecf20Sopenharmony_ci		isa_unregister_driver(&aha1542_isa_driver);
11288c2ecf20Sopenharmony_ci}
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_cimodule_init(aha1542_init);
11318c2ecf20Sopenharmony_cimodule_exit(aha1542_exit);
1132