162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci/* NCR (or Symbios) 53c700 and 53c700-66 Driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com
662306a36Sopenharmony_ci**-----------------------------------------------------------------------------
762306a36Sopenharmony_ci**
862306a36Sopenharmony_ci**
962306a36Sopenharmony_ci**-----------------------------------------------------------------------------
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/* Notes:
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * This driver is designed exclusively for these chips (virtually the
1562306a36Sopenharmony_ci * earliest of the scripts engine chips).  They need their own drivers
1662306a36Sopenharmony_ci * because they are missing so many of the scripts and snazzy register
1762306a36Sopenharmony_ci * features of their elder brothers (the 710, 720 and 770).
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * The 700 is the lowliest of the line, it can only do async SCSI.
2062306a36Sopenharmony_ci * The 700-66 can at least do synchronous SCSI up to 10MHz.
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * The 700 chip has no host bus interface logic of its own.  However,
2362306a36Sopenharmony_ci * it is usually mapped to a location with well defined register
2462306a36Sopenharmony_ci * offsets.  Therefore, if you can determine the base address and the
2562306a36Sopenharmony_ci * irq your board incorporating this chip uses, you can probably use
2662306a36Sopenharmony_ci * this driver to run it (although you'll probably have to write a
2762306a36Sopenharmony_ci * minimal wrapper for the purpose---see the NCR_D700 driver for
2862306a36Sopenharmony_ci * details about how to do this).
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci * TODO List:
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci * 1. Better statistics in the proc fs
3462306a36Sopenharmony_ci *
3562306a36Sopenharmony_ci * 2. Implement message queue (queues SCSI messages like commands) and make
3662306a36Sopenharmony_ci *    the abort and device reset functions use them.
3762306a36Sopenharmony_ci * */
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/* CHANGELOG
4062306a36Sopenharmony_ci *
4162306a36Sopenharmony_ci * Version 2.8
4262306a36Sopenharmony_ci *
4362306a36Sopenharmony_ci * Fixed bad bug affecting tag starvation processing (previously the
4462306a36Sopenharmony_ci * driver would hang the system if too many tags starved.  Also fixed
4562306a36Sopenharmony_ci * bad bug having to do with 10 byte command processing and REQUEST
4662306a36Sopenharmony_ci * SENSE (the command would loop forever getting a transfer length
4762306a36Sopenharmony_ci * mismatch in the CMD phase).
4862306a36Sopenharmony_ci *
4962306a36Sopenharmony_ci * Version 2.7
5062306a36Sopenharmony_ci *
5162306a36Sopenharmony_ci * Fixed scripts problem which caused certain devices (notably CDRWs)
5262306a36Sopenharmony_ci * to hang on initial INQUIRY.  Updated NCR_700_readl/writel to use
5362306a36Sopenharmony_ci * __raw_readl/writel for parisc compatibility (Thomas
5462306a36Sopenharmony_ci * Bogendoerfer). Added missing SCp->request_bufflen initialisation
5562306a36Sopenharmony_ci * for sense requests (Ryan Bradetich).
5662306a36Sopenharmony_ci *
5762306a36Sopenharmony_ci * Version 2.6
5862306a36Sopenharmony_ci *
5962306a36Sopenharmony_ci * Following test of the 64 bit parisc kernel by Richard Hirst,
6062306a36Sopenharmony_ci * several problems have now been corrected.  Also adds support for
6162306a36Sopenharmony_ci * consistent memory allocation.
6262306a36Sopenharmony_ci *
6362306a36Sopenharmony_ci * Version 2.5
6462306a36Sopenharmony_ci *
6562306a36Sopenharmony_ci * More Compatibility changes for 710 (now actually works).  Enhanced
6662306a36Sopenharmony_ci * support for odd clock speeds which constrain SDTR negotiations.
6762306a36Sopenharmony_ci * correct cacheline separation for scsi messages and status for
6862306a36Sopenharmony_ci * incoherent architectures.  Use of the pci mapping functions on
6962306a36Sopenharmony_ci * buffers to begin support for 64 bit drivers.
7062306a36Sopenharmony_ci *
7162306a36Sopenharmony_ci * Version 2.4
7262306a36Sopenharmony_ci *
7362306a36Sopenharmony_ci * Added support for the 53c710 chip (in 53c700 emulation mode only---no
7462306a36Sopenharmony_ci * special 53c710 instructions or registers are used).
7562306a36Sopenharmony_ci *
7662306a36Sopenharmony_ci * Version 2.3
7762306a36Sopenharmony_ci *
7862306a36Sopenharmony_ci * More endianness/cache coherency changes.
7962306a36Sopenharmony_ci *
8062306a36Sopenharmony_ci * Better bad device handling (handles devices lying about tag
8162306a36Sopenharmony_ci * queueing support and devices which fail to provide sense data on
8262306a36Sopenharmony_ci * contingent allegiance conditions)
8362306a36Sopenharmony_ci *
8462306a36Sopenharmony_ci * Many thanks to Richard Hirst <rhirst@linuxcare.com> for patiently
8562306a36Sopenharmony_ci * debugging this driver on the parisc architecture and suggesting
8662306a36Sopenharmony_ci * many improvements and bug fixes.
8762306a36Sopenharmony_ci *
8862306a36Sopenharmony_ci * Thanks also go to Linuxcare Inc. for providing several PARISC
8962306a36Sopenharmony_ci * machines for me to debug the driver on.
9062306a36Sopenharmony_ci *
9162306a36Sopenharmony_ci * Version 2.2
9262306a36Sopenharmony_ci *
9362306a36Sopenharmony_ci * Made the driver mem or io mapped; added endian invariance; added
9462306a36Sopenharmony_ci * dma cache flushing operations for architectures which need it;
9562306a36Sopenharmony_ci * added support for more varied clocking speeds.
9662306a36Sopenharmony_ci *
9762306a36Sopenharmony_ci * Version 2.1
9862306a36Sopenharmony_ci *
9962306a36Sopenharmony_ci * Initial modularisation from the D700.  See NCR_D700.c for the rest of
10062306a36Sopenharmony_ci * the changelog.
10162306a36Sopenharmony_ci * */
10262306a36Sopenharmony_ci#define NCR_700_VERSION "2.8"
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci#include <linux/kernel.h>
10562306a36Sopenharmony_ci#include <linux/types.h>
10662306a36Sopenharmony_ci#include <linux/string.h>
10762306a36Sopenharmony_ci#include <linux/slab.h>
10862306a36Sopenharmony_ci#include <linux/ioport.h>
10962306a36Sopenharmony_ci#include <linux/delay.h>
11062306a36Sopenharmony_ci#include <linux/spinlock.h>
11162306a36Sopenharmony_ci#include <linux/completion.h>
11262306a36Sopenharmony_ci#include <linux/init.h>
11362306a36Sopenharmony_ci#include <linux/proc_fs.h>
11462306a36Sopenharmony_ci#include <linux/blkdev.h>
11562306a36Sopenharmony_ci#include <linux/module.h>
11662306a36Sopenharmony_ci#include <linux/interrupt.h>
11762306a36Sopenharmony_ci#include <linux/device.h>
11862306a36Sopenharmony_ci#include <linux/pgtable.h>
11962306a36Sopenharmony_ci#include <asm/dma.h>
12062306a36Sopenharmony_ci#include <asm/io.h>
12162306a36Sopenharmony_ci#include <asm/byteorder.h>
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci#include <scsi/scsi.h>
12462306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h>
12562306a36Sopenharmony_ci#include <scsi/scsi_dbg.h>
12662306a36Sopenharmony_ci#include <scsi/scsi_eh.h>
12762306a36Sopenharmony_ci#include <scsi/scsi_host.h>
12862306a36Sopenharmony_ci#include <scsi/scsi_tcq.h>
12962306a36Sopenharmony_ci#include <scsi/scsi_transport.h>
13062306a36Sopenharmony_ci#include <scsi/scsi_transport_spi.h>
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci#include "53c700.h"
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci/* NOTE: For 64 bit drivers there are points in the code where we use
13562306a36Sopenharmony_ci * a non dereferenceable pointer to point to a structure in dma-able
13662306a36Sopenharmony_ci * memory (which is 32 bits) so that we can use all of the structure
13762306a36Sopenharmony_ci * operations but take the address at the end.  This macro allows us
13862306a36Sopenharmony_ci * to truncate the 64 bit pointer down to 32 bits without the compiler
13962306a36Sopenharmony_ci * complaining */
14062306a36Sopenharmony_ci#define to32bit(x)	((__u32)((unsigned long)(x)))
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci#ifdef NCR_700_DEBUG
14362306a36Sopenharmony_ci#define STATIC
14462306a36Sopenharmony_ci#else
14562306a36Sopenharmony_ci#define STATIC static
14662306a36Sopenharmony_ci#endif
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ciMODULE_AUTHOR("James Bottomley");
14962306a36Sopenharmony_ciMODULE_DESCRIPTION("53c700 and 53c700-66 Driver");
15062306a36Sopenharmony_ciMODULE_LICENSE("GPL");
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci/* This is the script */
15362306a36Sopenharmony_ci#include "53c700_d.h"
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ciSTATIC int NCR_700_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *);
15762306a36Sopenharmony_ciSTATIC int NCR_700_abort(struct scsi_cmnd * SCpnt);
15862306a36Sopenharmony_ciSTATIC int NCR_700_host_reset(struct scsi_cmnd * SCpnt);
15962306a36Sopenharmony_ciSTATIC void NCR_700_chip_setup(struct Scsi_Host *host);
16062306a36Sopenharmony_ciSTATIC void NCR_700_chip_reset(struct Scsi_Host *host);
16162306a36Sopenharmony_ciSTATIC int NCR_700_slave_alloc(struct scsi_device *SDpnt);
16262306a36Sopenharmony_ciSTATIC int NCR_700_slave_configure(struct scsi_device *SDpnt);
16362306a36Sopenharmony_ciSTATIC void NCR_700_slave_destroy(struct scsi_device *SDpnt);
16462306a36Sopenharmony_cistatic int NCR_700_change_queue_depth(struct scsi_device *SDpnt, int depth);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ciSTATIC const struct attribute_group *NCR_700_dev_groups[];
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ciSTATIC struct scsi_transport_template *NCR_700_transport_template = NULL;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic char *NCR_700_phase[] = {
17162306a36Sopenharmony_ci	"",
17262306a36Sopenharmony_ci	"after selection",
17362306a36Sopenharmony_ci	"before command phase",
17462306a36Sopenharmony_ci	"after command phase",
17562306a36Sopenharmony_ci	"after status phase",
17662306a36Sopenharmony_ci	"after data in phase",
17762306a36Sopenharmony_ci	"after data out phase",
17862306a36Sopenharmony_ci	"during data phase",
17962306a36Sopenharmony_ci};
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic char *NCR_700_condition[] = {
18262306a36Sopenharmony_ci	"",
18362306a36Sopenharmony_ci	"NOT MSG_OUT",
18462306a36Sopenharmony_ci	"UNEXPECTED PHASE",
18562306a36Sopenharmony_ci	"NOT MSG_IN",
18662306a36Sopenharmony_ci	"UNEXPECTED MSG",
18762306a36Sopenharmony_ci	"MSG_IN",
18862306a36Sopenharmony_ci	"SDTR_MSG RECEIVED",
18962306a36Sopenharmony_ci	"REJECT_MSG RECEIVED",
19062306a36Sopenharmony_ci	"DISCONNECT_MSG RECEIVED",
19162306a36Sopenharmony_ci	"MSG_OUT",
19262306a36Sopenharmony_ci	"DATA_IN",
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci};
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cistatic char *NCR_700_fatal_messages[] = {
19762306a36Sopenharmony_ci	"unexpected message after reselection",
19862306a36Sopenharmony_ci	"still MSG_OUT after message injection",
19962306a36Sopenharmony_ci	"not MSG_IN after selection",
20062306a36Sopenharmony_ci	"Illegal message length received",
20162306a36Sopenharmony_ci};
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic char *NCR_700_SBCL_bits[] = {
20462306a36Sopenharmony_ci	"IO ",
20562306a36Sopenharmony_ci	"CD ",
20662306a36Sopenharmony_ci	"MSG ",
20762306a36Sopenharmony_ci	"ATN ",
20862306a36Sopenharmony_ci	"SEL ",
20962306a36Sopenharmony_ci	"BSY ",
21062306a36Sopenharmony_ci	"ACK ",
21162306a36Sopenharmony_ci	"REQ ",
21262306a36Sopenharmony_ci};
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cistatic char *NCR_700_SBCL_to_phase[] = {
21562306a36Sopenharmony_ci	"DATA_OUT",
21662306a36Sopenharmony_ci	"DATA_IN",
21762306a36Sopenharmony_ci	"CMD_OUT",
21862306a36Sopenharmony_ci	"STATE",
21962306a36Sopenharmony_ci	"ILLEGAL PHASE",
22062306a36Sopenharmony_ci	"ILLEGAL PHASE",
22162306a36Sopenharmony_ci	"MSG OUT",
22262306a36Sopenharmony_ci	"MSG IN",
22362306a36Sopenharmony_ci};
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci/* This translates the SDTR message offset and period to a value
22662306a36Sopenharmony_ci * which can be loaded into the SXFER_REG.
22762306a36Sopenharmony_ci *
22862306a36Sopenharmony_ci * NOTE: According to SCSI-2, the true transfer period (in ns) is
22962306a36Sopenharmony_ci *       actually four times this period value */
23062306a36Sopenharmony_cistatic inline __u8
23162306a36Sopenharmony_ciNCR_700_offset_period_to_sxfer(struct NCR_700_Host_Parameters *hostdata,
23262306a36Sopenharmony_ci			       __u8 offset, __u8 period)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	int XFERP;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	__u8 min_xferp = (hostdata->chip710
23762306a36Sopenharmony_ci			  ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP);
23862306a36Sopenharmony_ci	__u8 max_offset = (hostdata->chip710
23962306a36Sopenharmony_ci			   ? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	if(offset == 0)
24262306a36Sopenharmony_ci		return 0;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	if(period < hostdata->min_period) {
24562306a36Sopenharmony_ci		printk(KERN_WARNING "53c700: Period %dns is less than this chip's minimum, setting to %d\n", period*4, NCR_700_MIN_PERIOD*4);
24662306a36Sopenharmony_ci		period = hostdata->min_period;
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci	XFERP = (period*4 * hostdata->sync_clock)/1000 - 4;
24962306a36Sopenharmony_ci	if(offset > max_offset) {
25062306a36Sopenharmony_ci		printk(KERN_WARNING "53c700: Offset %d exceeds chip maximum, setting to %d\n",
25162306a36Sopenharmony_ci		       offset, max_offset);
25262306a36Sopenharmony_ci		offset = max_offset;
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci	if(XFERP < min_xferp) {
25562306a36Sopenharmony_ci		XFERP =  min_xferp;
25662306a36Sopenharmony_ci	}
25762306a36Sopenharmony_ci	return (offset & 0x0f) | (XFERP & 0x07)<<4;
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic inline __u8
26162306a36Sopenharmony_ciNCR_700_get_SXFER(struct scsi_device *SDp)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	struct NCR_700_Host_Parameters *hostdata =
26462306a36Sopenharmony_ci		(struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	return NCR_700_offset_period_to_sxfer(hostdata,
26762306a36Sopenharmony_ci					      spi_offset(SDp->sdev_target),
26862306a36Sopenharmony_ci					      spi_period(SDp->sdev_target));
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic inline dma_addr_t virt_to_dma(struct NCR_700_Host_Parameters *h, void *p)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	return h->pScript + ((uintptr_t)p - (uintptr_t)h->script);
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic inline void dma_sync_to_dev(struct NCR_700_Host_Parameters *h,
27762306a36Sopenharmony_ci		void *addr, size_t size)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	if (h->noncoherent)
28062306a36Sopenharmony_ci		dma_sync_single_for_device(h->dev, virt_to_dma(h, addr),
28162306a36Sopenharmony_ci					   size, DMA_BIDIRECTIONAL);
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_cistatic inline void dma_sync_from_dev(struct NCR_700_Host_Parameters *h,
28562306a36Sopenharmony_ci		void *addr, size_t size)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	if (h->noncoherent)
28862306a36Sopenharmony_ci		dma_sync_single_for_device(h->dev, virt_to_dma(h, addr), size,
28962306a36Sopenharmony_ci					   DMA_BIDIRECTIONAL);
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_cistruct Scsi_Host *
29362306a36Sopenharmony_ciNCR_700_detect(struct scsi_host_template *tpnt,
29462306a36Sopenharmony_ci	       struct NCR_700_Host_Parameters *hostdata, struct device *dev)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	dma_addr_t pScript, pSlots;
29762306a36Sopenharmony_ci	__u8 *memory;
29862306a36Sopenharmony_ci	__u32 *script;
29962306a36Sopenharmony_ci	struct Scsi_Host *host;
30062306a36Sopenharmony_ci	static int banner = 0;
30162306a36Sopenharmony_ci	int j;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	if (tpnt->sdev_groups == NULL)
30462306a36Sopenharmony_ci		tpnt->sdev_groups = NCR_700_dev_groups;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	memory = dma_alloc_coherent(dev, TOTAL_MEM_SIZE, &pScript, GFP_KERNEL);
30762306a36Sopenharmony_ci	if (!memory) {
30862306a36Sopenharmony_ci		hostdata->noncoherent = 1;
30962306a36Sopenharmony_ci		memory = dma_alloc_noncoherent(dev, TOTAL_MEM_SIZE, &pScript,
31062306a36Sopenharmony_ci					 DMA_BIDIRECTIONAL, GFP_KERNEL);
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci	if (!memory) {
31362306a36Sopenharmony_ci		printk(KERN_ERR "53c700: Failed to allocate memory for driver, detaching\n");
31462306a36Sopenharmony_ci		return NULL;
31562306a36Sopenharmony_ci	}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	script = (__u32 *)memory;
31862306a36Sopenharmony_ci	hostdata->msgin = memory + MSGIN_OFFSET;
31962306a36Sopenharmony_ci	hostdata->msgout = memory + MSGOUT_OFFSET;
32062306a36Sopenharmony_ci	hostdata->status = memory + STATUS_OFFSET;
32162306a36Sopenharmony_ci	hostdata->slots = (struct NCR_700_command_slot *)(memory + SLOTS_OFFSET);
32262306a36Sopenharmony_ci	hostdata->dev = dev;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	pSlots = pScript + SLOTS_OFFSET;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	/* Fill in the missing routines from the host template */
32762306a36Sopenharmony_ci	tpnt->queuecommand = NCR_700_queuecommand;
32862306a36Sopenharmony_ci	tpnt->eh_abort_handler = NCR_700_abort;
32962306a36Sopenharmony_ci	tpnt->eh_host_reset_handler = NCR_700_host_reset;
33062306a36Sopenharmony_ci	tpnt->can_queue = NCR_700_COMMAND_SLOTS_PER_HOST;
33162306a36Sopenharmony_ci	tpnt->sg_tablesize = NCR_700_SG_SEGMENTS;
33262306a36Sopenharmony_ci	tpnt->cmd_per_lun = NCR_700_CMD_PER_LUN;
33362306a36Sopenharmony_ci	tpnt->slave_configure = NCR_700_slave_configure;
33462306a36Sopenharmony_ci	tpnt->slave_destroy = NCR_700_slave_destroy;
33562306a36Sopenharmony_ci	tpnt->slave_alloc = NCR_700_slave_alloc;
33662306a36Sopenharmony_ci	tpnt->change_queue_depth = NCR_700_change_queue_depth;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	if(tpnt->name == NULL)
33962306a36Sopenharmony_ci		tpnt->name = "53c700";
34062306a36Sopenharmony_ci	if(tpnt->proc_name == NULL)
34162306a36Sopenharmony_ci		tpnt->proc_name = "53c700";
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	host = scsi_host_alloc(tpnt, 4);
34462306a36Sopenharmony_ci	if (!host)
34562306a36Sopenharmony_ci		return NULL;
34662306a36Sopenharmony_ci	memset(hostdata->slots, 0, sizeof(struct NCR_700_command_slot)
34762306a36Sopenharmony_ci	       * NCR_700_COMMAND_SLOTS_PER_HOST);
34862306a36Sopenharmony_ci	for (j = 0; j < NCR_700_COMMAND_SLOTS_PER_HOST; j++) {
34962306a36Sopenharmony_ci		dma_addr_t offset = (dma_addr_t)((unsigned long)&hostdata->slots[j].SG[0]
35062306a36Sopenharmony_ci					  - (unsigned long)&hostdata->slots[0].SG[0]);
35162306a36Sopenharmony_ci		hostdata->slots[j].pSG = (struct NCR_700_SG_List *)((unsigned long)(pSlots + offset));
35262306a36Sopenharmony_ci		if(j == 0)
35362306a36Sopenharmony_ci			hostdata->free_list = &hostdata->slots[j];
35462306a36Sopenharmony_ci		else
35562306a36Sopenharmony_ci			hostdata->slots[j-1].ITL_forw = &hostdata->slots[j];
35662306a36Sopenharmony_ci		hostdata->slots[j].state = NCR_700_SLOT_FREE;
35762306a36Sopenharmony_ci	}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	for (j = 0; j < ARRAY_SIZE(SCRIPT); j++)
36062306a36Sopenharmony_ci		script[j] = bS_to_host(SCRIPT[j]);
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	/* adjust all labels to be bus physical */
36362306a36Sopenharmony_ci	for (j = 0; j < PATCHES; j++)
36462306a36Sopenharmony_ci		script[LABELPATCHES[j]] = bS_to_host(pScript + SCRIPT[LABELPATCHES[j]]);
36562306a36Sopenharmony_ci	/* now patch up fixed addresses. */
36662306a36Sopenharmony_ci	script_patch_32(hostdata, script, MessageLocation,
36762306a36Sopenharmony_ci			pScript + MSGOUT_OFFSET);
36862306a36Sopenharmony_ci	script_patch_32(hostdata, script, StatusAddress,
36962306a36Sopenharmony_ci			pScript + STATUS_OFFSET);
37062306a36Sopenharmony_ci	script_patch_32(hostdata, script, ReceiveMsgAddress,
37162306a36Sopenharmony_ci			pScript + MSGIN_OFFSET);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	hostdata->script = script;
37462306a36Sopenharmony_ci	hostdata->pScript = pScript;
37562306a36Sopenharmony_ci	dma_sync_single_for_device(hostdata->dev, pScript, sizeof(SCRIPT), DMA_TO_DEVICE);
37662306a36Sopenharmony_ci	hostdata->state = NCR_700_HOST_FREE;
37762306a36Sopenharmony_ci	hostdata->cmd = NULL;
37862306a36Sopenharmony_ci	host->max_id = 8;
37962306a36Sopenharmony_ci	host->max_lun = NCR_700_MAX_LUNS;
38062306a36Sopenharmony_ci	BUG_ON(NCR_700_transport_template == NULL);
38162306a36Sopenharmony_ci	host->transportt = NCR_700_transport_template;
38262306a36Sopenharmony_ci	host->unique_id = (unsigned long)hostdata->base;
38362306a36Sopenharmony_ci	hostdata->eh_complete = NULL;
38462306a36Sopenharmony_ci	host->hostdata[0] = (unsigned long)hostdata;
38562306a36Sopenharmony_ci	/* kick the chip */
38662306a36Sopenharmony_ci	NCR_700_writeb(0xff, host, CTEST9_REG);
38762306a36Sopenharmony_ci	if (hostdata->chip710)
38862306a36Sopenharmony_ci		hostdata->rev = (NCR_700_readb(host, CTEST8_REG)>>4) & 0x0f;
38962306a36Sopenharmony_ci	else
39062306a36Sopenharmony_ci		hostdata->rev = (NCR_700_readb(host, CTEST7_REG)>>4) & 0x0f;
39162306a36Sopenharmony_ci	hostdata->fast = (NCR_700_readb(host, CTEST9_REG) == 0);
39262306a36Sopenharmony_ci	if (banner == 0) {
39362306a36Sopenharmony_ci		printk(KERN_NOTICE "53c700: Version " NCR_700_VERSION " By James.Bottomley@HansenPartnership.com\n");
39462306a36Sopenharmony_ci		banner = 1;
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci	printk(KERN_NOTICE "scsi%d: %s rev %d %s\n", host->host_no,
39762306a36Sopenharmony_ci	       hostdata->chip710 ? "53c710" :
39862306a36Sopenharmony_ci	       (hostdata->fast ? "53c700-66" : "53c700"),
39962306a36Sopenharmony_ci	       hostdata->rev, hostdata->differential ?
40062306a36Sopenharmony_ci	       "(Differential)" : "");
40162306a36Sopenharmony_ci	/* reset the chip */
40262306a36Sopenharmony_ci	NCR_700_chip_reset(host);
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	if (scsi_add_host(host, dev)) {
40562306a36Sopenharmony_ci		dev_printk(KERN_ERR, dev, "53c700: scsi_add_host failed\n");
40662306a36Sopenharmony_ci		scsi_host_put(host);
40762306a36Sopenharmony_ci		return NULL;
40862306a36Sopenharmony_ci	}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	spi_signalling(host) = hostdata->differential ? SPI_SIGNAL_HVD :
41162306a36Sopenharmony_ci		SPI_SIGNAL_SE;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	return host;
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ciint
41762306a36Sopenharmony_ciNCR_700_release(struct Scsi_Host *host)
41862306a36Sopenharmony_ci{
41962306a36Sopenharmony_ci	struct NCR_700_Host_Parameters *hostdata =
42062306a36Sopenharmony_ci		(struct NCR_700_Host_Parameters *)host->hostdata[0];
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	if (hostdata->noncoherent)
42362306a36Sopenharmony_ci		dma_free_noncoherent(hostdata->dev, TOTAL_MEM_SIZE,
42462306a36Sopenharmony_ci				hostdata->script, hostdata->pScript,
42562306a36Sopenharmony_ci				DMA_BIDIRECTIONAL);
42662306a36Sopenharmony_ci	else
42762306a36Sopenharmony_ci		dma_free_coherent(hostdata->dev, TOTAL_MEM_SIZE,
42862306a36Sopenharmony_ci				  hostdata->script, hostdata->pScript);
42962306a36Sopenharmony_ci	return 1;
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_cistatic inline __u8
43362306a36Sopenharmony_ciNCR_700_identify(int can_disconnect, __u8 lun)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	return IDENTIFY_BASE |
43662306a36Sopenharmony_ci		((can_disconnect) ? 0x40 : 0) |
43762306a36Sopenharmony_ci		(lun & NCR_700_LUN_MASK);
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci/*
44162306a36Sopenharmony_ci * Function : static int data_residual (Scsi_Host *host)
44262306a36Sopenharmony_ci *
44362306a36Sopenharmony_ci * Purpose : return residual data count of what's in the chip.  If you
44462306a36Sopenharmony_ci * really want to know what this function is doing, it's almost a
44562306a36Sopenharmony_ci * direct transcription of the algorithm described in the 53c710
44662306a36Sopenharmony_ci * guide, except that the DBC and DFIFO registers are only 6 bits
44762306a36Sopenharmony_ci * wide on a 53c700.
44862306a36Sopenharmony_ci *
44962306a36Sopenharmony_ci * Inputs : host - SCSI host */
45062306a36Sopenharmony_cistatic inline int
45162306a36Sopenharmony_ciNCR_700_data_residual (struct Scsi_Host *host) {
45262306a36Sopenharmony_ci	struct NCR_700_Host_Parameters *hostdata =
45362306a36Sopenharmony_ci		(struct NCR_700_Host_Parameters *)host->hostdata[0];
45462306a36Sopenharmony_ci	int count, synchronous = 0;
45562306a36Sopenharmony_ci	unsigned int ddir;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	if(hostdata->chip710) {
45862306a36Sopenharmony_ci		count = ((NCR_700_readb(host, DFIFO_REG) & 0x7f) -
45962306a36Sopenharmony_ci			 (NCR_700_readl(host, DBC_REG) & 0x7f)) & 0x7f;
46062306a36Sopenharmony_ci	} else {
46162306a36Sopenharmony_ci		count = ((NCR_700_readb(host, DFIFO_REG) & 0x3f) -
46262306a36Sopenharmony_ci			 (NCR_700_readl(host, DBC_REG) & 0x3f)) & 0x3f;
46362306a36Sopenharmony_ci	}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	if(hostdata->fast)
46662306a36Sopenharmony_ci		synchronous = NCR_700_readb(host, SXFER_REG) & 0x0f;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	/* get the data direction */
46962306a36Sopenharmony_ci	ddir = NCR_700_readb(host, CTEST0_REG) & 0x01;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	if (ddir) {
47262306a36Sopenharmony_ci		/* Receive */
47362306a36Sopenharmony_ci		if (synchronous)
47462306a36Sopenharmony_ci			count += (NCR_700_readb(host, SSTAT2_REG) & 0xf0) >> 4;
47562306a36Sopenharmony_ci		else
47662306a36Sopenharmony_ci			if (NCR_700_readb(host, SSTAT1_REG) & SIDL_REG_FULL)
47762306a36Sopenharmony_ci				++count;
47862306a36Sopenharmony_ci	} else {
47962306a36Sopenharmony_ci		/* Send */
48062306a36Sopenharmony_ci		__u8 sstat = NCR_700_readb(host, SSTAT1_REG);
48162306a36Sopenharmony_ci		if (sstat & SODL_REG_FULL)
48262306a36Sopenharmony_ci			++count;
48362306a36Sopenharmony_ci		if (synchronous && (sstat & SODR_REG_FULL))
48462306a36Sopenharmony_ci			++count;
48562306a36Sopenharmony_ci	}
48662306a36Sopenharmony_ci#ifdef NCR_700_DEBUG
48762306a36Sopenharmony_ci	if(count)
48862306a36Sopenharmony_ci		printk("RESIDUAL IS %d (ddir %d)\n", count, ddir);
48962306a36Sopenharmony_ci#endif
49062306a36Sopenharmony_ci	return count;
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci/* print out the SCSI wires and corresponding phase from the SBCL register
49462306a36Sopenharmony_ci * in the chip */
49562306a36Sopenharmony_cistatic inline char *
49662306a36Sopenharmony_cisbcl_to_string(__u8 sbcl)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	int i;
49962306a36Sopenharmony_ci	static char ret[256];
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	ret[0]='\0';
50262306a36Sopenharmony_ci	for(i=0; i<8; i++) {
50362306a36Sopenharmony_ci		if((1<<i) & sbcl)
50462306a36Sopenharmony_ci			strcat(ret, NCR_700_SBCL_bits[i]);
50562306a36Sopenharmony_ci	}
50662306a36Sopenharmony_ci	strcat(ret, NCR_700_SBCL_to_phase[sbcl & 0x07]);
50762306a36Sopenharmony_ci	return ret;
50862306a36Sopenharmony_ci}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cistatic inline __u8
51162306a36Sopenharmony_cibitmap_to_number(__u8 bitmap)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	__u8 i;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	for(i=0; i<8 && !(bitmap &(1<<i)); i++)
51662306a36Sopenharmony_ci		;
51762306a36Sopenharmony_ci	return i;
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci/* Pull a slot off the free list */
52162306a36Sopenharmony_ciSTATIC struct NCR_700_command_slot *
52262306a36Sopenharmony_cifind_empty_slot(struct NCR_700_Host_Parameters *hostdata)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	struct NCR_700_command_slot *slot = hostdata->free_list;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	if(slot == NULL) {
52762306a36Sopenharmony_ci		/* sanity check */
52862306a36Sopenharmony_ci		if(hostdata->command_slot_count != NCR_700_COMMAND_SLOTS_PER_HOST)
52962306a36Sopenharmony_ci			printk(KERN_ERR "SLOTS FULL, but count is %d, should be %d\n", hostdata->command_slot_count, NCR_700_COMMAND_SLOTS_PER_HOST);
53062306a36Sopenharmony_ci		return NULL;
53162306a36Sopenharmony_ci	}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	if(slot->state != NCR_700_SLOT_FREE)
53462306a36Sopenharmony_ci		/* should panic! */
53562306a36Sopenharmony_ci		printk(KERN_ERR "BUSY SLOT ON FREE LIST!!!\n");
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	hostdata->free_list = slot->ITL_forw;
53962306a36Sopenharmony_ci	slot->ITL_forw = NULL;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	/* NOTE: set the state to busy here, not queued, since this
54362306a36Sopenharmony_ci	 * indicates the slot is in use and cannot be run by the IRQ
54462306a36Sopenharmony_ci	 * finish routine.  If we cannot queue the command when it
54562306a36Sopenharmony_ci	 * is properly build, we then change to NCR_700_SLOT_QUEUED */
54662306a36Sopenharmony_ci	slot->state = NCR_700_SLOT_BUSY;
54762306a36Sopenharmony_ci	slot->flags = 0;
54862306a36Sopenharmony_ci	hostdata->command_slot_count++;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	return slot;
55162306a36Sopenharmony_ci}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ciSTATIC void
55462306a36Sopenharmony_cifree_slot(struct NCR_700_command_slot *slot,
55562306a36Sopenharmony_ci	  struct NCR_700_Host_Parameters *hostdata)
55662306a36Sopenharmony_ci{
55762306a36Sopenharmony_ci	if((slot->state & NCR_700_SLOT_MASK) != NCR_700_SLOT_MAGIC) {
55862306a36Sopenharmony_ci		printk(KERN_ERR "53c700: SLOT %p is not MAGIC!!!\n", slot);
55962306a36Sopenharmony_ci	}
56062306a36Sopenharmony_ci	if(slot->state == NCR_700_SLOT_FREE) {
56162306a36Sopenharmony_ci		printk(KERN_ERR "53c700: SLOT %p is FREE!!!\n", slot);
56262306a36Sopenharmony_ci	}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	slot->resume_offset = 0;
56562306a36Sopenharmony_ci	slot->cmnd = NULL;
56662306a36Sopenharmony_ci	slot->state = NCR_700_SLOT_FREE;
56762306a36Sopenharmony_ci	slot->ITL_forw = hostdata->free_list;
56862306a36Sopenharmony_ci	hostdata->free_list = slot;
56962306a36Sopenharmony_ci	hostdata->command_slot_count--;
57062306a36Sopenharmony_ci}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci/* This routine really does very little.  The command is indexed on
57462306a36Sopenharmony_ci   the ITL and (if tagged) the ITLQ lists in _queuecommand */
57562306a36Sopenharmony_ciSTATIC void
57662306a36Sopenharmony_cisave_for_reselection(struct NCR_700_Host_Parameters *hostdata,
57762306a36Sopenharmony_ci		     struct scsi_cmnd *SCp, __u32 dsp)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci	/* Its just possible that this gets executed twice */
58062306a36Sopenharmony_ci	if(SCp != NULL) {
58162306a36Sopenharmony_ci		struct NCR_700_command_slot *slot =
58262306a36Sopenharmony_ci			(struct NCR_700_command_slot *)SCp->host_scribble;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci		slot->resume_offset = dsp;
58562306a36Sopenharmony_ci	}
58662306a36Sopenharmony_ci	hostdata->state = NCR_700_HOST_FREE;
58762306a36Sopenharmony_ci	hostdata->cmd = NULL;
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ciSTATIC inline void
59162306a36Sopenharmony_ciNCR_700_unmap(struct NCR_700_Host_Parameters *hostdata, struct scsi_cmnd *SCp,
59262306a36Sopenharmony_ci	      struct NCR_700_command_slot *slot)
59362306a36Sopenharmony_ci{
59462306a36Sopenharmony_ci	if(SCp->sc_data_direction != DMA_NONE &&
59562306a36Sopenharmony_ci	   SCp->sc_data_direction != DMA_BIDIRECTIONAL)
59662306a36Sopenharmony_ci		scsi_dma_unmap(SCp);
59762306a36Sopenharmony_ci}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ciSTATIC inline void
60062306a36Sopenharmony_ciNCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata,
60162306a36Sopenharmony_ci	       struct scsi_cmnd *SCp, int result)
60262306a36Sopenharmony_ci{
60362306a36Sopenharmony_ci	hostdata->state = NCR_700_HOST_FREE;
60462306a36Sopenharmony_ci	hostdata->cmd = NULL;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	if(SCp != NULL) {
60762306a36Sopenharmony_ci		struct NCR_700_command_slot *slot =
60862306a36Sopenharmony_ci			(struct NCR_700_command_slot *)SCp->host_scribble;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci		dma_unmap_single(hostdata->dev, slot->pCmd,
61162306a36Sopenharmony_ci				 MAX_COMMAND_SIZE, DMA_TO_DEVICE);
61262306a36Sopenharmony_ci		if (slot->flags == NCR_700_FLAG_AUTOSENSE) {
61362306a36Sopenharmony_ci			char *cmnd = NCR_700_get_sense_cmnd(SCp->device);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci			dma_unmap_single(hostdata->dev, slot->dma_handle,
61662306a36Sopenharmony_ci					 SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
61762306a36Sopenharmony_ci			/* restore the old result if the request sense was
61862306a36Sopenharmony_ci			 * successful */
61962306a36Sopenharmony_ci			if (result == 0)
62062306a36Sopenharmony_ci				result = cmnd[7];
62162306a36Sopenharmony_ci			/* restore the original length */
62262306a36Sopenharmony_ci			SCp->cmd_len = cmnd[8];
62362306a36Sopenharmony_ci		} else
62462306a36Sopenharmony_ci			NCR_700_unmap(hostdata, SCp, slot);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci		free_slot(slot, hostdata);
62762306a36Sopenharmony_ci#ifdef NCR_700_DEBUG
62862306a36Sopenharmony_ci		if(NCR_700_get_depth(SCp->device) == 0 ||
62962306a36Sopenharmony_ci		   NCR_700_get_depth(SCp->device) > SCp->device->queue_depth)
63062306a36Sopenharmony_ci			printk(KERN_ERR "Invalid depth in NCR_700_scsi_done(): %d\n",
63162306a36Sopenharmony_ci			       NCR_700_get_depth(SCp->device));
63262306a36Sopenharmony_ci#endif /* NCR_700_DEBUG */
63362306a36Sopenharmony_ci		NCR_700_set_depth(SCp->device, NCR_700_get_depth(SCp->device) - 1);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci		SCp->host_scribble = NULL;
63662306a36Sopenharmony_ci		SCp->result = result;
63762306a36Sopenharmony_ci		scsi_done(SCp);
63862306a36Sopenharmony_ci	} else {
63962306a36Sopenharmony_ci		printk(KERN_ERR "53c700: SCSI DONE HAS NULL SCp\n");
64062306a36Sopenharmony_ci	}
64162306a36Sopenharmony_ci}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ciSTATIC void
64562306a36Sopenharmony_ciNCR_700_internal_bus_reset(struct Scsi_Host *host)
64662306a36Sopenharmony_ci{
64762306a36Sopenharmony_ci	/* Bus reset */
64862306a36Sopenharmony_ci	NCR_700_writeb(ASSERT_RST, host, SCNTL1_REG);
64962306a36Sopenharmony_ci	udelay(50);
65062306a36Sopenharmony_ci	NCR_700_writeb(0, host, SCNTL1_REG);
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ciSTATIC void
65562306a36Sopenharmony_ciNCR_700_chip_setup(struct Scsi_Host *host)
65662306a36Sopenharmony_ci{
65762306a36Sopenharmony_ci	struct NCR_700_Host_Parameters *hostdata =
65862306a36Sopenharmony_ci		(struct NCR_700_Host_Parameters *)host->hostdata[0];
65962306a36Sopenharmony_ci	__u8 min_period;
66062306a36Sopenharmony_ci	__u8 min_xferp = (hostdata->chip710 ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP);
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	if(hostdata->chip710) {
66362306a36Sopenharmony_ci		__u8 burst_disable = 0;
66462306a36Sopenharmony_ci		__u8 burst_length = 0;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci		switch (hostdata->burst_length) {
66762306a36Sopenharmony_ci			case 1:
66862306a36Sopenharmony_ci			        burst_length = BURST_LENGTH_1;
66962306a36Sopenharmony_ci			        break;
67062306a36Sopenharmony_ci			case 2:
67162306a36Sopenharmony_ci			        burst_length = BURST_LENGTH_2;
67262306a36Sopenharmony_ci			        break;
67362306a36Sopenharmony_ci			case 4:
67462306a36Sopenharmony_ci			        burst_length = BURST_LENGTH_4;
67562306a36Sopenharmony_ci			        break;
67662306a36Sopenharmony_ci			case 8:
67762306a36Sopenharmony_ci			        burst_length = BURST_LENGTH_8;
67862306a36Sopenharmony_ci			        break;
67962306a36Sopenharmony_ci			default:
68062306a36Sopenharmony_ci			        burst_disable = BURST_DISABLE;
68162306a36Sopenharmony_ci			        break;
68262306a36Sopenharmony_ci		}
68362306a36Sopenharmony_ci		hostdata->dcntl_extra |= COMPAT_700_MODE;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci		NCR_700_writeb(hostdata->dcntl_extra, host, DCNTL_REG);
68662306a36Sopenharmony_ci		NCR_700_writeb(burst_length | hostdata->dmode_extra,
68762306a36Sopenharmony_ci			       host, DMODE_710_REG);
68862306a36Sopenharmony_ci		NCR_700_writeb(burst_disable | hostdata->ctest7_extra |
68962306a36Sopenharmony_ci			       (hostdata->differential ? DIFF : 0),
69062306a36Sopenharmony_ci			       host, CTEST7_REG);
69162306a36Sopenharmony_ci		NCR_700_writeb(BTB_TIMER_DISABLE, host, CTEST0_REG);
69262306a36Sopenharmony_ci		NCR_700_writeb(FULL_ARBITRATION | ENABLE_PARITY | PARITY
69362306a36Sopenharmony_ci			       | AUTO_ATN, host, SCNTL0_REG);
69462306a36Sopenharmony_ci	} else {
69562306a36Sopenharmony_ci		NCR_700_writeb(BURST_LENGTH_8 | hostdata->dmode_extra,
69662306a36Sopenharmony_ci			       host, DMODE_700_REG);
69762306a36Sopenharmony_ci		NCR_700_writeb(hostdata->differential ?
69862306a36Sopenharmony_ci			       DIFF : 0, host, CTEST7_REG);
69962306a36Sopenharmony_ci		if(hostdata->fast) {
70062306a36Sopenharmony_ci			/* this is for 700-66, does nothing on 700 */
70162306a36Sopenharmony_ci			NCR_700_writeb(LAST_DIS_ENBL | ENABLE_ACTIVE_NEGATION
70262306a36Sopenharmony_ci				       | GENERATE_RECEIVE_PARITY, host,
70362306a36Sopenharmony_ci				       CTEST8_REG);
70462306a36Sopenharmony_ci		} else {
70562306a36Sopenharmony_ci			NCR_700_writeb(FULL_ARBITRATION | ENABLE_PARITY
70662306a36Sopenharmony_ci				       | PARITY | AUTO_ATN, host, SCNTL0_REG);
70762306a36Sopenharmony_ci		}
70862306a36Sopenharmony_ci	}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	NCR_700_writeb(1 << host->this_id, host, SCID_REG);
71162306a36Sopenharmony_ci	NCR_700_writeb(0, host, SBCL_REG);
71262306a36Sopenharmony_ci	NCR_700_writeb(ASYNC_OPERATION, host, SXFER_REG);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	NCR_700_writeb(PHASE_MM_INT | SEL_TIMEOUT_INT | GROSS_ERR_INT | UX_DISC_INT
71562306a36Sopenharmony_ci	     | RST_INT | PAR_ERR_INT | SELECT_INT, host, SIEN_REG);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	NCR_700_writeb(ABORT_INT | INT_INST_INT | ILGL_INST_INT, host, DIEN_REG);
71862306a36Sopenharmony_ci	NCR_700_writeb(ENABLE_SELECT, host, SCNTL1_REG);
71962306a36Sopenharmony_ci	if(hostdata->clock > 75) {
72062306a36Sopenharmony_ci		printk(KERN_ERR "53c700: Clock speed %dMHz is too high: 75Mhz is the maximum this chip can be driven at\n", hostdata->clock);
72162306a36Sopenharmony_ci		/* do the best we can, but the async clock will be out
72262306a36Sopenharmony_ci		 * of spec: sync divider 2, async divider 3 */
72362306a36Sopenharmony_ci		DEBUG(("53c700: sync 2 async 3\n"));
72462306a36Sopenharmony_ci		NCR_700_writeb(SYNC_DIV_2_0, host, SBCL_REG);
72562306a36Sopenharmony_ci		NCR_700_writeb(ASYNC_DIV_3_0 | hostdata->dcntl_extra, host, DCNTL_REG);
72662306a36Sopenharmony_ci		hostdata->sync_clock = hostdata->clock/2;
72762306a36Sopenharmony_ci	} else	if(hostdata->clock > 50  && hostdata->clock <= 75) {
72862306a36Sopenharmony_ci		/* sync divider 1.5, async divider 3 */
72962306a36Sopenharmony_ci		DEBUG(("53c700: sync 1.5 async 3\n"));
73062306a36Sopenharmony_ci		NCR_700_writeb(SYNC_DIV_1_5, host, SBCL_REG);
73162306a36Sopenharmony_ci		NCR_700_writeb(ASYNC_DIV_3_0 | hostdata->dcntl_extra, host, DCNTL_REG);
73262306a36Sopenharmony_ci		hostdata->sync_clock = hostdata->clock*2;
73362306a36Sopenharmony_ci		hostdata->sync_clock /= 3;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	} else if(hostdata->clock > 37 && hostdata->clock <= 50) {
73662306a36Sopenharmony_ci		/* sync divider 1, async divider 2 */
73762306a36Sopenharmony_ci		DEBUG(("53c700: sync 1 async 2\n"));
73862306a36Sopenharmony_ci		NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
73962306a36Sopenharmony_ci		NCR_700_writeb(ASYNC_DIV_2_0 | hostdata->dcntl_extra, host, DCNTL_REG);
74062306a36Sopenharmony_ci		hostdata->sync_clock = hostdata->clock;
74162306a36Sopenharmony_ci	} else if(hostdata->clock > 25 && hostdata->clock <=37) {
74262306a36Sopenharmony_ci		/* sync divider 1, async divider 1.5 */
74362306a36Sopenharmony_ci		DEBUG(("53c700: sync 1 async 1.5\n"));
74462306a36Sopenharmony_ci		NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
74562306a36Sopenharmony_ci		NCR_700_writeb(ASYNC_DIV_1_5 | hostdata->dcntl_extra, host, DCNTL_REG);
74662306a36Sopenharmony_ci		hostdata->sync_clock = hostdata->clock;
74762306a36Sopenharmony_ci	} else {
74862306a36Sopenharmony_ci		DEBUG(("53c700: sync 1 async 1\n"));
74962306a36Sopenharmony_ci		NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
75062306a36Sopenharmony_ci		NCR_700_writeb(ASYNC_DIV_1_0 | hostdata->dcntl_extra, host, DCNTL_REG);
75162306a36Sopenharmony_ci		/* sync divider 1, async divider 1 */
75262306a36Sopenharmony_ci		hostdata->sync_clock = hostdata->clock;
75362306a36Sopenharmony_ci	}
75462306a36Sopenharmony_ci	/* Calculate the actual minimum period that can be supported
75562306a36Sopenharmony_ci	 * by our synchronous clock speed.  See the 710 manual for
75662306a36Sopenharmony_ci	 * exact details of this calculation which is based on a
75762306a36Sopenharmony_ci	 * setting of the SXFER register */
75862306a36Sopenharmony_ci	min_period = 1000*(4+min_xferp)/(4*hostdata->sync_clock);
75962306a36Sopenharmony_ci	hostdata->min_period = NCR_700_MIN_PERIOD;
76062306a36Sopenharmony_ci	if(min_period > NCR_700_MIN_PERIOD)
76162306a36Sopenharmony_ci		hostdata->min_period = min_period;
76262306a36Sopenharmony_ci}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ciSTATIC void
76562306a36Sopenharmony_ciNCR_700_chip_reset(struct Scsi_Host *host)
76662306a36Sopenharmony_ci{
76762306a36Sopenharmony_ci	struct NCR_700_Host_Parameters *hostdata =
76862306a36Sopenharmony_ci		(struct NCR_700_Host_Parameters *)host->hostdata[0];
76962306a36Sopenharmony_ci	if(hostdata->chip710) {
77062306a36Sopenharmony_ci		NCR_700_writeb(SOFTWARE_RESET_710, host, ISTAT_REG);
77162306a36Sopenharmony_ci		udelay(100);
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci		NCR_700_writeb(0, host, ISTAT_REG);
77462306a36Sopenharmony_ci	} else {
77562306a36Sopenharmony_ci		NCR_700_writeb(SOFTWARE_RESET, host, DCNTL_REG);
77662306a36Sopenharmony_ci		udelay(100);
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci		NCR_700_writeb(0, host, DCNTL_REG);
77962306a36Sopenharmony_ci	}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	mdelay(1000);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	NCR_700_chip_setup(host);
78462306a36Sopenharmony_ci}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci/* The heart of the message processing engine is that the instruction
78762306a36Sopenharmony_ci * immediately after the INT is the normal case (and so must be CLEAR
78862306a36Sopenharmony_ci * ACK).  If we want to do something else, we call that routine in
78962306a36Sopenharmony_ci * scripts and set temp to be the normal case + 8 (skipping the CLEAR
79062306a36Sopenharmony_ci * ACK) so that the routine returns correctly to resume its activity
79162306a36Sopenharmony_ci * */
79262306a36Sopenharmony_ciSTATIC __u32
79362306a36Sopenharmony_ciprocess_extended_message(struct Scsi_Host *host,
79462306a36Sopenharmony_ci			 struct NCR_700_Host_Parameters *hostdata,
79562306a36Sopenharmony_ci			 struct scsi_cmnd *SCp, __u32 dsp, __u32 dsps)
79662306a36Sopenharmony_ci{
79762306a36Sopenharmony_ci	__u32 resume_offset = dsp, temp = dsp + 8;
79862306a36Sopenharmony_ci	__u8 pun = 0xff, lun = 0xff;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	if(SCp != NULL) {
80162306a36Sopenharmony_ci		pun = SCp->device->id;
80262306a36Sopenharmony_ci		lun = SCp->device->lun;
80362306a36Sopenharmony_ci	}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	switch(hostdata->msgin[2]) {
80662306a36Sopenharmony_ci	case A_SDTR_MSG:
80762306a36Sopenharmony_ci		if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) {
80862306a36Sopenharmony_ci			struct scsi_target *starget = SCp->device->sdev_target;
80962306a36Sopenharmony_ci			__u8 period = hostdata->msgin[3];
81062306a36Sopenharmony_ci			__u8 offset = hostdata->msgin[4];
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci			if(offset == 0 || period == 0) {
81362306a36Sopenharmony_ci				offset = 0;
81462306a36Sopenharmony_ci				period = 0;
81562306a36Sopenharmony_ci			}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci			spi_offset(starget) = offset;
81862306a36Sopenharmony_ci			spi_period(starget) = period;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci			if(NCR_700_is_flag_set(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION)) {
82162306a36Sopenharmony_ci				spi_display_xfer_agreement(starget);
82262306a36Sopenharmony_ci				NCR_700_clear_flag(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION);
82362306a36Sopenharmony_ci			}
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci			NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
82662306a36Sopenharmony_ci			NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci			NCR_700_writeb(NCR_700_get_SXFER(SCp->device),
82962306a36Sopenharmony_ci				       host, SXFER_REG);
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci		} else {
83262306a36Sopenharmony_ci			/* SDTR message out of the blue, reject it */
83362306a36Sopenharmony_ci			shost_printk(KERN_WARNING, host,
83462306a36Sopenharmony_ci				"Unexpected SDTR msg\n");
83562306a36Sopenharmony_ci			hostdata->msgout[0] = A_REJECT_MSG;
83662306a36Sopenharmony_ci			dma_sync_to_dev(hostdata, hostdata->msgout, 1);
83762306a36Sopenharmony_ci			script_patch_16(hostdata, hostdata->script,
83862306a36Sopenharmony_ci			                MessageCount, 1);
83962306a36Sopenharmony_ci			/* SendMsgOut returns, so set up the return
84062306a36Sopenharmony_ci			 * address */
84162306a36Sopenharmony_ci			resume_offset = hostdata->pScript + Ent_SendMessageWithATN;
84262306a36Sopenharmony_ci		}
84362306a36Sopenharmony_ci		break;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	case A_WDTR_MSG:
84662306a36Sopenharmony_ci		printk(KERN_INFO "scsi%d: (%d:%d), Unsolicited WDTR after CMD, Rejecting\n",
84762306a36Sopenharmony_ci		       host->host_no, pun, lun);
84862306a36Sopenharmony_ci		hostdata->msgout[0] = A_REJECT_MSG;
84962306a36Sopenharmony_ci		dma_sync_to_dev(hostdata, hostdata->msgout, 1);
85062306a36Sopenharmony_ci		script_patch_16(hostdata, hostdata->script, MessageCount, 1);
85162306a36Sopenharmony_ci		resume_offset = hostdata->pScript + Ent_SendMessageWithATN;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci		break;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	default:
85662306a36Sopenharmony_ci		printk(KERN_INFO "scsi%d (%d:%d): Unexpected message %s: ",
85762306a36Sopenharmony_ci		       host->host_no, pun, lun,
85862306a36Sopenharmony_ci		       NCR_700_phase[(dsps & 0xf00) >> 8]);
85962306a36Sopenharmony_ci		spi_print_msg(hostdata->msgin);
86062306a36Sopenharmony_ci		printk("\n");
86162306a36Sopenharmony_ci		/* just reject it */
86262306a36Sopenharmony_ci		hostdata->msgout[0] = A_REJECT_MSG;
86362306a36Sopenharmony_ci		dma_sync_to_dev(hostdata, hostdata->msgout, 1);
86462306a36Sopenharmony_ci		script_patch_16(hostdata, hostdata->script, MessageCount, 1);
86562306a36Sopenharmony_ci		/* SendMsgOut returns, so set up the return
86662306a36Sopenharmony_ci		 * address */
86762306a36Sopenharmony_ci		resume_offset = hostdata->pScript + Ent_SendMessageWithATN;
86862306a36Sopenharmony_ci	}
86962306a36Sopenharmony_ci	NCR_700_writel(temp, host, TEMP_REG);
87062306a36Sopenharmony_ci	return resume_offset;
87162306a36Sopenharmony_ci}
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ciSTATIC __u32
87462306a36Sopenharmony_ciprocess_message(struct Scsi_Host *host,	struct NCR_700_Host_Parameters *hostdata,
87562306a36Sopenharmony_ci		struct scsi_cmnd *SCp, __u32 dsp, __u32 dsps)
87662306a36Sopenharmony_ci{
87762306a36Sopenharmony_ci	/* work out where to return to */
87862306a36Sopenharmony_ci	__u32 temp = dsp + 8, resume_offset = dsp;
87962306a36Sopenharmony_ci	__u8 pun = 0xff, lun = 0xff;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	if(SCp != NULL) {
88262306a36Sopenharmony_ci		pun = SCp->device->id;
88362306a36Sopenharmony_ci		lun = SCp->device->lun;
88462306a36Sopenharmony_ci	}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci#ifdef NCR_700_DEBUG
88762306a36Sopenharmony_ci	printk("scsi%d (%d:%d): message %s: ", host->host_no, pun, lun,
88862306a36Sopenharmony_ci	       NCR_700_phase[(dsps & 0xf00) >> 8]);
88962306a36Sopenharmony_ci	spi_print_msg(hostdata->msgin);
89062306a36Sopenharmony_ci	printk("\n");
89162306a36Sopenharmony_ci#endif
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	switch(hostdata->msgin[0]) {
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	case A_EXTENDED_MSG:
89662306a36Sopenharmony_ci		resume_offset =  process_extended_message(host, hostdata, SCp,
89762306a36Sopenharmony_ci							  dsp, dsps);
89862306a36Sopenharmony_ci		break;
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	case A_REJECT_MSG:
90162306a36Sopenharmony_ci		if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) {
90262306a36Sopenharmony_ci			/* Rejected our sync negotiation attempt */
90362306a36Sopenharmony_ci			spi_period(SCp->device->sdev_target) =
90462306a36Sopenharmony_ci				spi_offset(SCp->device->sdev_target) = 0;
90562306a36Sopenharmony_ci			NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
90662306a36Sopenharmony_ci			NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
90762306a36Sopenharmony_ci		} else if(SCp != NULL && NCR_700_get_tag_neg_state(SCp->device) == NCR_700_DURING_TAG_NEGOTIATION) {
90862306a36Sopenharmony_ci			/* rejected our first simple tag message */
90962306a36Sopenharmony_ci			scmd_printk(KERN_WARNING, SCp,
91062306a36Sopenharmony_ci				"Rejected first tag queue attempt, turning off tag queueing\n");
91162306a36Sopenharmony_ci			/* we're done negotiating */
91262306a36Sopenharmony_ci			NCR_700_set_tag_neg_state(SCp->device, NCR_700_FINISHED_TAG_NEGOTIATION);
91362306a36Sopenharmony_ci			hostdata->tag_negotiated &= ~(1<<scmd_id(SCp));
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci			SCp->device->tagged_supported = 0;
91662306a36Sopenharmony_ci			SCp->device->simple_tags = 0;
91762306a36Sopenharmony_ci			scsi_change_queue_depth(SCp->device, host->cmd_per_lun);
91862306a36Sopenharmony_ci		} else {
91962306a36Sopenharmony_ci			shost_printk(KERN_WARNING, host,
92062306a36Sopenharmony_ci				"(%d:%d) Unexpected REJECT Message %s\n",
92162306a36Sopenharmony_ci			       pun, lun,
92262306a36Sopenharmony_ci			       NCR_700_phase[(dsps & 0xf00) >> 8]);
92362306a36Sopenharmony_ci			/* however, just ignore it */
92462306a36Sopenharmony_ci		}
92562306a36Sopenharmony_ci		break;
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	case A_PARITY_ERROR_MSG:
92862306a36Sopenharmony_ci		printk(KERN_ERR "scsi%d (%d:%d) Parity Error!\n", host->host_no,
92962306a36Sopenharmony_ci		       pun, lun);
93062306a36Sopenharmony_ci		NCR_700_internal_bus_reset(host);
93162306a36Sopenharmony_ci		break;
93262306a36Sopenharmony_ci	case A_SIMPLE_TAG_MSG:
93362306a36Sopenharmony_ci		printk(KERN_INFO "scsi%d (%d:%d) SIMPLE TAG %d %s\n", host->host_no,
93462306a36Sopenharmony_ci		       pun, lun, hostdata->msgin[1],
93562306a36Sopenharmony_ci		       NCR_700_phase[(dsps & 0xf00) >> 8]);
93662306a36Sopenharmony_ci		/* just ignore it */
93762306a36Sopenharmony_ci		break;
93862306a36Sopenharmony_ci	default:
93962306a36Sopenharmony_ci		printk(KERN_INFO "scsi%d (%d:%d): Unexpected message %s: ",
94062306a36Sopenharmony_ci		       host->host_no, pun, lun,
94162306a36Sopenharmony_ci		       NCR_700_phase[(dsps & 0xf00) >> 8]);
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci		spi_print_msg(hostdata->msgin);
94462306a36Sopenharmony_ci		printk("\n");
94562306a36Sopenharmony_ci		/* just reject it */
94662306a36Sopenharmony_ci		hostdata->msgout[0] = A_REJECT_MSG;
94762306a36Sopenharmony_ci		dma_sync_to_dev(hostdata, hostdata->msgout, 1);
94862306a36Sopenharmony_ci		script_patch_16(hostdata, hostdata->script, MessageCount, 1);
94962306a36Sopenharmony_ci		/* SendMsgOut returns, so set up the return
95062306a36Sopenharmony_ci		 * address */
95162306a36Sopenharmony_ci		resume_offset = hostdata->pScript + Ent_SendMessageWithATN;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci		break;
95462306a36Sopenharmony_ci	}
95562306a36Sopenharmony_ci	NCR_700_writel(temp, host, TEMP_REG);
95662306a36Sopenharmony_ci	/* set us up to receive another message */
95762306a36Sopenharmony_ci	dma_sync_from_dev(hostdata, hostdata->msgin, MSG_ARRAY_SIZE);
95862306a36Sopenharmony_ci	return resume_offset;
95962306a36Sopenharmony_ci}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ciSTATIC __u32
96262306a36Sopenharmony_ciprocess_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
96362306a36Sopenharmony_ci			 struct Scsi_Host *host,
96462306a36Sopenharmony_ci			 struct NCR_700_Host_Parameters *hostdata)
96562306a36Sopenharmony_ci{
96662306a36Sopenharmony_ci	__u32 resume_offset = 0;
96762306a36Sopenharmony_ci	__u8 pun = 0xff, lun=0xff;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	if(SCp != NULL) {
97062306a36Sopenharmony_ci		pun = SCp->device->id;
97162306a36Sopenharmony_ci		lun = SCp->device->lun;
97262306a36Sopenharmony_ci	}
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	if(dsps == A_GOOD_STATUS_AFTER_STATUS) {
97562306a36Sopenharmony_ci		DEBUG(("  COMMAND COMPLETE, status=%02x\n",
97662306a36Sopenharmony_ci		       hostdata->status[0]));
97762306a36Sopenharmony_ci		/* OK, if TCQ still under negotiation, we now know it works */
97862306a36Sopenharmony_ci		if (NCR_700_get_tag_neg_state(SCp->device) == NCR_700_DURING_TAG_NEGOTIATION)
97962306a36Sopenharmony_ci			NCR_700_set_tag_neg_state(SCp->device,
98062306a36Sopenharmony_ci						  NCR_700_FINISHED_TAG_NEGOTIATION);
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci		/* check for contingent allegiance conditions */
98362306a36Sopenharmony_ci		if (hostdata->status[0] == SAM_STAT_CHECK_CONDITION ||
98462306a36Sopenharmony_ci		    hostdata->status[0] == SAM_STAT_COMMAND_TERMINATED) {
98562306a36Sopenharmony_ci			struct NCR_700_command_slot *slot =
98662306a36Sopenharmony_ci				(struct NCR_700_command_slot *)SCp->host_scribble;
98762306a36Sopenharmony_ci			if(slot->flags == NCR_700_FLAG_AUTOSENSE) {
98862306a36Sopenharmony_ci				/* OOPS: bad device, returning another
98962306a36Sopenharmony_ci				 * contingent allegiance condition */
99062306a36Sopenharmony_ci				scmd_printk(KERN_ERR, SCp,
99162306a36Sopenharmony_ci					"broken device is looping in contingent allegiance: ignoring\n");
99262306a36Sopenharmony_ci				NCR_700_scsi_done(hostdata, SCp, hostdata->status[0]);
99362306a36Sopenharmony_ci			} else {
99462306a36Sopenharmony_ci				char *cmnd =
99562306a36Sopenharmony_ci					NCR_700_get_sense_cmnd(SCp->device);
99662306a36Sopenharmony_ci#ifdef NCR_DEBUG
99762306a36Sopenharmony_ci				scsi_print_command(SCp);
99862306a36Sopenharmony_ci				printk("  cmd %p has status %d, requesting sense\n",
99962306a36Sopenharmony_ci				       SCp, hostdata->status[0]);
100062306a36Sopenharmony_ci#endif
100162306a36Sopenharmony_ci				/* we can destroy the command here
100262306a36Sopenharmony_ci				 * because the contingent allegiance
100362306a36Sopenharmony_ci				 * condition will cause a retry which
100462306a36Sopenharmony_ci				 * will re-copy the command from the
100562306a36Sopenharmony_ci				 * saved data_cmnd.  We also unmap any
100662306a36Sopenharmony_ci				 * data associated with the command
100762306a36Sopenharmony_ci				 * here */
100862306a36Sopenharmony_ci				NCR_700_unmap(hostdata, SCp, slot);
100962306a36Sopenharmony_ci				dma_unmap_single(hostdata->dev, slot->pCmd,
101062306a36Sopenharmony_ci						 MAX_COMMAND_SIZE,
101162306a36Sopenharmony_ci						 DMA_TO_DEVICE);
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci				cmnd[0] = REQUEST_SENSE;
101462306a36Sopenharmony_ci				cmnd[1] = (lun & 0x7) << 5;
101562306a36Sopenharmony_ci				cmnd[2] = 0;
101662306a36Sopenharmony_ci				cmnd[3] = 0;
101762306a36Sopenharmony_ci				cmnd[4] = SCSI_SENSE_BUFFERSIZE;
101862306a36Sopenharmony_ci				cmnd[5] = 0;
101962306a36Sopenharmony_ci				/* Here's a quiet hack: the
102062306a36Sopenharmony_ci				 * REQUEST_SENSE command is six bytes,
102162306a36Sopenharmony_ci				 * so store a flag indicating that
102262306a36Sopenharmony_ci				 * this was an internal sense request
102362306a36Sopenharmony_ci				 * and the original status at the end
102462306a36Sopenharmony_ci				 * of the command */
102562306a36Sopenharmony_ci				cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC;
102662306a36Sopenharmony_ci				cmnd[7] = hostdata->status[0];
102762306a36Sopenharmony_ci				cmnd[8] = SCp->cmd_len;
102862306a36Sopenharmony_ci				SCp->cmd_len = 6; /* command length for
102962306a36Sopenharmony_ci						   * REQUEST_SENSE */
103062306a36Sopenharmony_ci				slot->pCmd = dma_map_single(hostdata->dev, cmnd, MAX_COMMAND_SIZE, DMA_TO_DEVICE);
103162306a36Sopenharmony_ci				slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
103262306a36Sopenharmony_ci				slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | SCSI_SENSE_BUFFERSIZE);
103362306a36Sopenharmony_ci				slot->SG[0].pAddr = bS_to_host(slot->dma_handle);
103462306a36Sopenharmony_ci				slot->SG[1].ins = bS_to_host(SCRIPT_RETURN);
103562306a36Sopenharmony_ci				slot->SG[1].pAddr = 0;
103662306a36Sopenharmony_ci				slot->resume_offset = hostdata->pScript;
103762306a36Sopenharmony_ci				dma_sync_to_dev(hostdata, slot->SG, sizeof(slot->SG[0])*2);
103862306a36Sopenharmony_ci				dma_sync_from_dev(hostdata, SCp->sense_buffer, SCSI_SENSE_BUFFERSIZE);
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci				/* queue the command for reissue */
104162306a36Sopenharmony_ci				slot->state = NCR_700_SLOT_QUEUED;
104262306a36Sopenharmony_ci				slot->flags = NCR_700_FLAG_AUTOSENSE;
104362306a36Sopenharmony_ci				hostdata->state = NCR_700_HOST_FREE;
104462306a36Sopenharmony_ci				hostdata->cmd = NULL;
104562306a36Sopenharmony_ci			}
104662306a36Sopenharmony_ci		} else {
104762306a36Sopenharmony_ci			// Currently rely on the mid layer evaluation
104862306a36Sopenharmony_ci			// of the tag queuing capability
104962306a36Sopenharmony_ci			//
105062306a36Sopenharmony_ci			//if(status_byte(hostdata->status[0]) == GOOD &&
105162306a36Sopenharmony_ci			//   SCp->cmnd[0] == INQUIRY && SCp->use_sg == 0) {
105262306a36Sopenharmony_ci			//	/* Piggy back the tag queueing support
105362306a36Sopenharmony_ci			//	 * on this command */
105462306a36Sopenharmony_ci			//	dma_sync_single_for_cpu(hostdata->dev,
105562306a36Sopenharmony_ci			//			    slot->dma_handle,
105662306a36Sopenharmony_ci			//			    SCp->request_bufflen,
105762306a36Sopenharmony_ci			//			    DMA_FROM_DEVICE);
105862306a36Sopenharmony_ci			//	if(((char *)SCp->request_buffer)[7] & 0x02) {
105962306a36Sopenharmony_ci			//		scmd_printk(KERN_INFO, SCp,
106062306a36Sopenharmony_ci			//		     "Enabling Tag Command Queuing\n");
106162306a36Sopenharmony_ci			//		hostdata->tag_negotiated |= (1<<scmd_id(SCp));
106262306a36Sopenharmony_ci			//		NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
106362306a36Sopenharmony_ci			//	} else {
106462306a36Sopenharmony_ci			//		NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
106562306a36Sopenharmony_ci			//		hostdata->tag_negotiated &= ~(1<<scmd_id(SCp));
106662306a36Sopenharmony_ci			//	}
106762306a36Sopenharmony_ci			//}
106862306a36Sopenharmony_ci			NCR_700_scsi_done(hostdata, SCp, hostdata->status[0]);
106962306a36Sopenharmony_ci		}
107062306a36Sopenharmony_ci	} else if((dsps & 0xfffff0f0) == A_UNEXPECTED_PHASE) {
107162306a36Sopenharmony_ci		__u8 i = (dsps & 0xf00) >> 8;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci		scmd_printk(KERN_ERR, SCp, "UNEXPECTED PHASE %s (%s)\n",
107462306a36Sopenharmony_ci		       NCR_700_phase[i],
107562306a36Sopenharmony_ci		       sbcl_to_string(NCR_700_readb(host, SBCL_REG)));
107662306a36Sopenharmony_ci		scmd_printk(KERN_ERR, SCp, "         len = %d, cmd =",
107762306a36Sopenharmony_ci			SCp->cmd_len);
107862306a36Sopenharmony_ci		scsi_print_command(SCp);
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci		NCR_700_internal_bus_reset(host);
108162306a36Sopenharmony_ci	} else if((dsps & 0xfffff000) == A_FATAL) {
108262306a36Sopenharmony_ci		int i = (dsps & 0xfff);
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci		printk(KERN_ERR "scsi%d: (%d:%d) FATAL ERROR: %s\n",
108562306a36Sopenharmony_ci		       host->host_no, pun, lun, NCR_700_fatal_messages[i]);
108662306a36Sopenharmony_ci		if(dsps == A_FATAL_ILLEGAL_MSG_LENGTH) {
108762306a36Sopenharmony_ci			printk(KERN_ERR "     msg begins %02x %02x\n",
108862306a36Sopenharmony_ci			       hostdata->msgin[0], hostdata->msgin[1]);
108962306a36Sopenharmony_ci		}
109062306a36Sopenharmony_ci		NCR_700_internal_bus_reset(host);
109162306a36Sopenharmony_ci	} else if((dsps & 0xfffff0f0) == A_DISCONNECT) {
109262306a36Sopenharmony_ci#ifdef NCR_700_DEBUG
109362306a36Sopenharmony_ci		__u8 i = (dsps & 0xf00) >> 8;
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci		printk("scsi%d: (%d:%d), DISCONNECTED (%d) %s\n",
109662306a36Sopenharmony_ci		       host->host_no, pun, lun,
109762306a36Sopenharmony_ci		       i, NCR_700_phase[i]);
109862306a36Sopenharmony_ci#endif
109962306a36Sopenharmony_ci		save_for_reselection(hostdata, SCp, dsp);
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	} else if(dsps == A_RESELECTION_IDENTIFIED) {
110262306a36Sopenharmony_ci		__u8 lun;
110362306a36Sopenharmony_ci		struct NCR_700_command_slot *slot;
110462306a36Sopenharmony_ci		__u8 reselection_id = hostdata->reselection_id;
110562306a36Sopenharmony_ci		struct scsi_device *SDp;
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci		lun = hostdata->msgin[0] & 0x1f;
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci		hostdata->reselection_id = 0xff;
111062306a36Sopenharmony_ci		DEBUG(("scsi%d: (%d:%d) RESELECTED!\n",
111162306a36Sopenharmony_ci		       host->host_no, reselection_id, lun));
111262306a36Sopenharmony_ci		/* clear the reselection indicator */
111362306a36Sopenharmony_ci		SDp = __scsi_device_lookup(host, 0, reselection_id, lun);
111462306a36Sopenharmony_ci		if(unlikely(SDp == NULL)) {
111562306a36Sopenharmony_ci			printk(KERN_ERR "scsi%d: (%d:%d) HAS NO device\n",
111662306a36Sopenharmony_ci			       host->host_no, reselection_id, lun);
111762306a36Sopenharmony_ci			BUG();
111862306a36Sopenharmony_ci		}
111962306a36Sopenharmony_ci		if(hostdata->msgin[1] == A_SIMPLE_TAG_MSG) {
112062306a36Sopenharmony_ci			struct scsi_cmnd *SCp;
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci			SCp = scsi_host_find_tag(SDp->host, hostdata->msgin[2]);
112362306a36Sopenharmony_ci			if(unlikely(SCp == NULL)) {
112462306a36Sopenharmony_ci				printk(KERN_ERR "scsi%d: (%d:%d) no saved request for tag %d\n",
112562306a36Sopenharmony_ci				       host->host_no, reselection_id, lun, hostdata->msgin[2]);
112662306a36Sopenharmony_ci				BUG();
112762306a36Sopenharmony_ci			}
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci			slot = (struct NCR_700_command_slot *)SCp->host_scribble;
113062306a36Sopenharmony_ci			DDEBUG(KERN_DEBUG, SDp,
113162306a36Sopenharmony_ci				"reselection is tag %d, slot %p(%d)\n",
113262306a36Sopenharmony_ci				hostdata->msgin[2], slot, slot->tag);
113362306a36Sopenharmony_ci		} else {
113462306a36Sopenharmony_ci			struct NCR_700_Device_Parameters *p = SDp->hostdata;
113562306a36Sopenharmony_ci			struct scsi_cmnd *SCp = p->current_cmnd;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci			if(unlikely(SCp == NULL)) {
113862306a36Sopenharmony_ci				sdev_printk(KERN_ERR, SDp,
113962306a36Sopenharmony_ci					"no saved request for untagged cmd\n");
114062306a36Sopenharmony_ci				BUG();
114162306a36Sopenharmony_ci			}
114262306a36Sopenharmony_ci			slot = (struct NCR_700_command_slot *)SCp->host_scribble;
114362306a36Sopenharmony_ci		}
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci		if(slot == NULL) {
114662306a36Sopenharmony_ci			printk(KERN_ERR "scsi%d: (%d:%d) RESELECTED but no saved command (MSG = %02x %02x %02x)!!\n",
114762306a36Sopenharmony_ci			       host->host_no, reselection_id, lun,
114862306a36Sopenharmony_ci			       hostdata->msgin[0], hostdata->msgin[1],
114962306a36Sopenharmony_ci			       hostdata->msgin[2]);
115062306a36Sopenharmony_ci		} else {
115162306a36Sopenharmony_ci			if(hostdata->state != NCR_700_HOST_BUSY)
115262306a36Sopenharmony_ci				printk(KERN_ERR "scsi%d: FATAL, host not busy during valid reselection!\n",
115362306a36Sopenharmony_ci				       host->host_no);
115462306a36Sopenharmony_ci			resume_offset = slot->resume_offset;
115562306a36Sopenharmony_ci			hostdata->cmd = slot->cmnd;
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci			/* re-patch for this command */
115862306a36Sopenharmony_ci			script_patch_32_abs(hostdata, hostdata->script,
115962306a36Sopenharmony_ci			                    CommandAddress, slot->pCmd);
116062306a36Sopenharmony_ci			script_patch_16(hostdata, hostdata->script,
116162306a36Sopenharmony_ci					CommandCount, slot->cmnd->cmd_len);
116262306a36Sopenharmony_ci			script_patch_32_abs(hostdata, hostdata->script,
116362306a36Sopenharmony_ci			                    SGScriptStartAddress,
116462306a36Sopenharmony_ci					    to32bit(&slot->pSG[0].ins));
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci			/* Note: setting SXFER only works if we're
116762306a36Sopenharmony_ci			 * still in the MESSAGE phase, so it is vital
116862306a36Sopenharmony_ci			 * that ACK is still asserted when we process
116962306a36Sopenharmony_ci			 * the reselection message.  The resume offset
117062306a36Sopenharmony_ci			 * should therefore always clear ACK */
117162306a36Sopenharmony_ci			NCR_700_writeb(NCR_700_get_SXFER(hostdata->cmd->device),
117262306a36Sopenharmony_ci				       host, SXFER_REG);
117362306a36Sopenharmony_ci			dma_sync_from_dev(hostdata, hostdata->msgin,
117462306a36Sopenharmony_ci				       MSG_ARRAY_SIZE);
117562306a36Sopenharmony_ci			dma_sync_to_dev(hostdata, hostdata->msgout,
117662306a36Sopenharmony_ci				       MSG_ARRAY_SIZE);
117762306a36Sopenharmony_ci			/* I'm just being paranoid here, the command should
117862306a36Sopenharmony_ci			 * already have been flushed from the cache */
117962306a36Sopenharmony_ci			dma_sync_to_dev(hostdata, slot->cmnd->cmnd,
118062306a36Sopenharmony_ci				       slot->cmnd->cmd_len);
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci		}
118562306a36Sopenharmony_ci	} else if(dsps == A_RESELECTED_DURING_SELECTION) {
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci		/* This section is full of debugging code because I've
118862306a36Sopenharmony_ci		 * never managed to reach it.  I think what happens is
118962306a36Sopenharmony_ci		 * that, because the 700 runs with selection
119062306a36Sopenharmony_ci		 * interrupts enabled the whole time that we take a
119162306a36Sopenharmony_ci		 * selection interrupt before we manage to get to the
119262306a36Sopenharmony_ci		 * reselected script interrupt */
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci		__u8 reselection_id = NCR_700_readb(host, SFBR_REG);
119562306a36Sopenharmony_ci		struct NCR_700_command_slot *slot;
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci		/* Take out our own ID */
119862306a36Sopenharmony_ci		reselection_id &= ~(1<<host->this_id);
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci		/* I've never seen this happen, so keep this as a printk rather
120162306a36Sopenharmony_ci		 * than a debug */
120262306a36Sopenharmony_ci		printk(KERN_INFO "scsi%d: (%d:%d) RESELECTION DURING SELECTION, dsp=%08x[%04x] state=%d, count=%d\n",
120362306a36Sopenharmony_ci		       host->host_no, reselection_id, lun, dsp, dsp - hostdata->pScript, hostdata->state, hostdata->command_slot_count);
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci		{
120662306a36Sopenharmony_ci			/* FIXME: DEBUGGING CODE */
120762306a36Sopenharmony_ci			__u32 SG = (__u32)bS_to_cpu(hostdata->script[A_SGScriptStartAddress_used[0]]);
120862306a36Sopenharmony_ci			int i;
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci			for(i=0; i< NCR_700_COMMAND_SLOTS_PER_HOST; i++) {
121162306a36Sopenharmony_ci				if(SG >= to32bit(&hostdata->slots[i].pSG[0])
121262306a36Sopenharmony_ci				   && SG <= to32bit(&hostdata->slots[i].pSG[NCR_700_SG_SEGMENTS]))
121362306a36Sopenharmony_ci					break;
121462306a36Sopenharmony_ci			}
121562306a36Sopenharmony_ci			printk(KERN_INFO "IDENTIFIED SG segment as being %08x in slot %p, cmd %p, slot->resume_offset=%08x\n", SG, &hostdata->slots[i], hostdata->slots[i].cmnd, hostdata->slots[i].resume_offset);
121662306a36Sopenharmony_ci			SCp =  hostdata->slots[i].cmnd;
121762306a36Sopenharmony_ci		}
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci		if(SCp != NULL) {
122062306a36Sopenharmony_ci			slot = (struct NCR_700_command_slot *)SCp->host_scribble;
122162306a36Sopenharmony_ci			/* change slot from busy to queued to redo command */
122262306a36Sopenharmony_ci			slot->state = NCR_700_SLOT_QUEUED;
122362306a36Sopenharmony_ci		}
122462306a36Sopenharmony_ci		hostdata->cmd = NULL;
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci		if(reselection_id == 0) {
122762306a36Sopenharmony_ci			if(hostdata->reselection_id == 0xff) {
122862306a36Sopenharmony_ci				printk(KERN_ERR "scsi%d: Invalid reselection during selection!!\n", host->host_no);
122962306a36Sopenharmony_ci				return 0;
123062306a36Sopenharmony_ci			} else {
123162306a36Sopenharmony_ci				printk(KERN_ERR "scsi%d: script reselected and we took a selection interrupt\n",
123262306a36Sopenharmony_ci				       host->host_no);
123362306a36Sopenharmony_ci				reselection_id = hostdata->reselection_id;
123462306a36Sopenharmony_ci			}
123562306a36Sopenharmony_ci		} else {
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci			/* convert to real ID */
123862306a36Sopenharmony_ci			reselection_id = bitmap_to_number(reselection_id);
123962306a36Sopenharmony_ci		}
124062306a36Sopenharmony_ci		hostdata->reselection_id = reselection_id;
124162306a36Sopenharmony_ci		/* just in case we have a stale simple tag message, clear it */
124262306a36Sopenharmony_ci		hostdata->msgin[1] = 0;
124362306a36Sopenharmony_ci		dma_sync_to_dev(hostdata, hostdata->msgin, MSG_ARRAY_SIZE);
124462306a36Sopenharmony_ci		if(hostdata->tag_negotiated & (1<<reselection_id)) {
124562306a36Sopenharmony_ci			resume_offset = hostdata->pScript + Ent_GetReselectionWithTag;
124662306a36Sopenharmony_ci		} else {
124762306a36Sopenharmony_ci			resume_offset = hostdata->pScript + Ent_GetReselectionData;
124862306a36Sopenharmony_ci		}
124962306a36Sopenharmony_ci	} else if(dsps == A_COMPLETED_SELECTION_AS_TARGET) {
125062306a36Sopenharmony_ci		/* we've just disconnected from the bus, do nothing since
125162306a36Sopenharmony_ci		 * a return here will re-run the queued command slot
125262306a36Sopenharmony_ci		 * that may have been interrupted by the initial selection */
125362306a36Sopenharmony_ci		DEBUG((" SELECTION COMPLETED\n"));
125462306a36Sopenharmony_ci	} else if((dsps & 0xfffff0f0) == A_MSG_IN) {
125562306a36Sopenharmony_ci		resume_offset = process_message(host, hostdata, SCp,
125662306a36Sopenharmony_ci						dsp, dsps);
125762306a36Sopenharmony_ci	} else if((dsps &  0xfffff000) == 0) {
125862306a36Sopenharmony_ci		__u8 i = (dsps & 0xf0) >> 4, j = (dsps & 0xf00) >> 8;
125962306a36Sopenharmony_ci		printk(KERN_ERR "scsi%d: (%d:%d), unhandled script condition %s %s at %04x\n",
126062306a36Sopenharmony_ci		       host->host_no, pun, lun, NCR_700_condition[i],
126162306a36Sopenharmony_ci		       NCR_700_phase[j], dsp - hostdata->pScript);
126262306a36Sopenharmony_ci		if(SCp != NULL) {
126362306a36Sopenharmony_ci			struct scatterlist *sg;
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci			scsi_print_command(SCp);
126662306a36Sopenharmony_ci			scsi_for_each_sg(SCp, sg, scsi_sg_count(SCp) + 1, i) {
126762306a36Sopenharmony_ci				printk(KERN_INFO " SG[%d].length = %d, move_insn=%08x, addr %08x\n", i, sg->length, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].ins, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].pAddr);
126862306a36Sopenharmony_ci			}
126962306a36Sopenharmony_ci		}
127062306a36Sopenharmony_ci		NCR_700_internal_bus_reset(host);
127162306a36Sopenharmony_ci	} else if((dsps & 0xfffff000) == A_DEBUG_INTERRUPT) {
127262306a36Sopenharmony_ci		printk(KERN_NOTICE "scsi%d (%d:%d) DEBUG INTERRUPT %d AT %08x[%04x], continuing\n",
127362306a36Sopenharmony_ci		       host->host_no, pun, lun, dsps & 0xfff, dsp, dsp - hostdata->pScript);
127462306a36Sopenharmony_ci		resume_offset = dsp;
127562306a36Sopenharmony_ci	} else {
127662306a36Sopenharmony_ci		printk(KERN_ERR "scsi%d: (%d:%d), unidentified script interrupt 0x%x at %04x\n",
127762306a36Sopenharmony_ci		       host->host_no, pun, lun, dsps, dsp - hostdata->pScript);
127862306a36Sopenharmony_ci		NCR_700_internal_bus_reset(host);
127962306a36Sopenharmony_ci	}
128062306a36Sopenharmony_ci	return resume_offset;
128162306a36Sopenharmony_ci}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci/* We run the 53c700 with selection interrupts always enabled.  This
128462306a36Sopenharmony_ci * means that the chip may be selected as soon as the bus frees.  On a
128562306a36Sopenharmony_ci * busy bus, this can be before the scripts engine finishes its
128662306a36Sopenharmony_ci * processing.  Therefore, part of the selection processing has to be
128762306a36Sopenharmony_ci * to find out what the scripts engine is doing and complete the
128862306a36Sopenharmony_ci * function if necessary (i.e. process the pending disconnect or save
128962306a36Sopenharmony_ci * the interrupted initial selection */
129062306a36Sopenharmony_ciSTATIC inline __u32
129162306a36Sopenharmony_ciprocess_selection(struct Scsi_Host *host, __u32 dsp)
129262306a36Sopenharmony_ci{
129362306a36Sopenharmony_ci	__u8 id = 0;	/* Squash compiler warning */
129462306a36Sopenharmony_ci	int count = 0;
129562306a36Sopenharmony_ci	__u32 resume_offset = 0;
129662306a36Sopenharmony_ci	struct NCR_700_Host_Parameters *hostdata =
129762306a36Sopenharmony_ci		(struct NCR_700_Host_Parameters *)host->hostdata[0];
129862306a36Sopenharmony_ci	struct scsi_cmnd *SCp = hostdata->cmd;
129962306a36Sopenharmony_ci	__u8 sbcl;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	for(count = 0; count < 5; count++) {
130262306a36Sopenharmony_ci		id = NCR_700_readb(host, hostdata->chip710 ?
130362306a36Sopenharmony_ci				   CTEST9_REG : SFBR_REG);
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci		/* Take out our own ID */
130662306a36Sopenharmony_ci		id &= ~(1<<host->this_id);
130762306a36Sopenharmony_ci		if(id != 0)
130862306a36Sopenharmony_ci			break;
130962306a36Sopenharmony_ci		udelay(5);
131062306a36Sopenharmony_ci	}
131162306a36Sopenharmony_ci	sbcl = NCR_700_readb(host, SBCL_REG);
131262306a36Sopenharmony_ci	if((sbcl & SBCL_IO) == 0) {
131362306a36Sopenharmony_ci		/* mark as having been selected rather than reselected */
131462306a36Sopenharmony_ci		id = 0xff;
131562306a36Sopenharmony_ci	} else {
131662306a36Sopenharmony_ci		/* convert to real ID */
131762306a36Sopenharmony_ci		hostdata->reselection_id = id = bitmap_to_number(id);
131862306a36Sopenharmony_ci		DEBUG(("scsi%d:  Reselected by %d\n",
131962306a36Sopenharmony_ci		       host->host_no, id));
132062306a36Sopenharmony_ci	}
132162306a36Sopenharmony_ci	if(hostdata->state == NCR_700_HOST_BUSY && SCp != NULL) {
132262306a36Sopenharmony_ci		struct NCR_700_command_slot *slot =
132362306a36Sopenharmony_ci			(struct NCR_700_command_slot *)SCp->host_scribble;
132462306a36Sopenharmony_ci		DEBUG(("  ID %d WARNING: RESELECTION OF BUSY HOST, saving cmd %p, slot %p, addr %x [%04x], resume %x!\n", id, hostdata->cmd, slot, dsp, dsp - hostdata->pScript, resume_offset));
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci		switch(dsp - hostdata->pScript) {
132762306a36Sopenharmony_ci		case Ent_Disconnect1:
132862306a36Sopenharmony_ci		case Ent_Disconnect2:
132962306a36Sopenharmony_ci			save_for_reselection(hostdata, SCp, Ent_Disconnect2 + hostdata->pScript);
133062306a36Sopenharmony_ci			break;
133162306a36Sopenharmony_ci		case Ent_Disconnect3:
133262306a36Sopenharmony_ci		case Ent_Disconnect4:
133362306a36Sopenharmony_ci			save_for_reselection(hostdata, SCp, Ent_Disconnect4 + hostdata->pScript);
133462306a36Sopenharmony_ci			break;
133562306a36Sopenharmony_ci		case Ent_Disconnect5:
133662306a36Sopenharmony_ci		case Ent_Disconnect6:
133762306a36Sopenharmony_ci			save_for_reselection(hostdata, SCp, Ent_Disconnect6 + hostdata->pScript);
133862306a36Sopenharmony_ci			break;
133962306a36Sopenharmony_ci		case Ent_Disconnect7:
134062306a36Sopenharmony_ci		case Ent_Disconnect8:
134162306a36Sopenharmony_ci			save_for_reselection(hostdata, SCp, Ent_Disconnect8 + hostdata->pScript);
134262306a36Sopenharmony_ci			break;
134362306a36Sopenharmony_ci		case Ent_Finish1:
134462306a36Sopenharmony_ci		case Ent_Finish2:
134562306a36Sopenharmony_ci			process_script_interrupt(A_GOOD_STATUS_AFTER_STATUS, dsp, SCp, host, hostdata);
134662306a36Sopenharmony_ci			break;
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci		default:
134962306a36Sopenharmony_ci			slot->state = NCR_700_SLOT_QUEUED;
135062306a36Sopenharmony_ci			break;
135162306a36Sopenharmony_ci			}
135262306a36Sopenharmony_ci	}
135362306a36Sopenharmony_ci	hostdata->state = NCR_700_HOST_BUSY;
135462306a36Sopenharmony_ci	hostdata->cmd = NULL;
135562306a36Sopenharmony_ci	/* clear any stale simple tag message */
135662306a36Sopenharmony_ci	hostdata->msgin[1] = 0;
135762306a36Sopenharmony_ci	dma_sync_to_dev(hostdata, hostdata->msgin, MSG_ARRAY_SIZE);
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	if(id == 0xff) {
136062306a36Sopenharmony_ci		/* Selected as target, Ignore */
136162306a36Sopenharmony_ci		resume_offset = hostdata->pScript + Ent_SelectedAsTarget;
136262306a36Sopenharmony_ci	} else if(hostdata->tag_negotiated & (1<<id)) {
136362306a36Sopenharmony_ci		resume_offset = hostdata->pScript + Ent_GetReselectionWithTag;
136462306a36Sopenharmony_ci	} else {
136562306a36Sopenharmony_ci		resume_offset = hostdata->pScript + Ent_GetReselectionData;
136662306a36Sopenharmony_ci	}
136762306a36Sopenharmony_ci	return resume_offset;
136862306a36Sopenharmony_ci}
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_cistatic inline void
137162306a36Sopenharmony_ciNCR_700_clear_fifo(struct Scsi_Host *host) {
137262306a36Sopenharmony_ci	const struct NCR_700_Host_Parameters *hostdata
137362306a36Sopenharmony_ci		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
137462306a36Sopenharmony_ci	if(hostdata->chip710) {
137562306a36Sopenharmony_ci		NCR_700_writeb(CLR_FIFO_710, host, CTEST8_REG);
137662306a36Sopenharmony_ci	} else {
137762306a36Sopenharmony_ci		NCR_700_writeb(CLR_FIFO, host, DFIFO_REG);
137862306a36Sopenharmony_ci	}
137962306a36Sopenharmony_ci}
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_cistatic inline void
138262306a36Sopenharmony_ciNCR_700_flush_fifo(struct Scsi_Host *host) {
138362306a36Sopenharmony_ci	const struct NCR_700_Host_Parameters *hostdata
138462306a36Sopenharmony_ci		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
138562306a36Sopenharmony_ci	if(hostdata->chip710) {
138662306a36Sopenharmony_ci		NCR_700_writeb(FLUSH_DMA_FIFO_710, host, CTEST8_REG);
138762306a36Sopenharmony_ci		udelay(10);
138862306a36Sopenharmony_ci		NCR_700_writeb(0, host, CTEST8_REG);
138962306a36Sopenharmony_ci	} else {
139062306a36Sopenharmony_ci		NCR_700_writeb(FLUSH_DMA_FIFO, host, DFIFO_REG);
139162306a36Sopenharmony_ci		udelay(10);
139262306a36Sopenharmony_ci		NCR_700_writeb(0, host, DFIFO_REG);
139362306a36Sopenharmony_ci	}
139462306a36Sopenharmony_ci}
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci/* The queue lock with interrupts disabled must be held on entry to
139862306a36Sopenharmony_ci * this function */
139962306a36Sopenharmony_ciSTATIC int
140062306a36Sopenharmony_ciNCR_700_start_command(struct scsi_cmnd *SCp)
140162306a36Sopenharmony_ci{
140262306a36Sopenharmony_ci	struct NCR_700_command_slot *slot =
140362306a36Sopenharmony_ci		(struct NCR_700_command_slot *)SCp->host_scribble;
140462306a36Sopenharmony_ci	struct NCR_700_Host_Parameters *hostdata =
140562306a36Sopenharmony_ci		(struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0];
140662306a36Sopenharmony_ci	__u16 count = 1;	/* for IDENTIFY message */
140762306a36Sopenharmony_ci	u8 lun = SCp->device->lun;
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	if(hostdata->state != NCR_700_HOST_FREE) {
141062306a36Sopenharmony_ci		/* keep this inside the lock to close the race window where
141162306a36Sopenharmony_ci		 * the running command finishes on another CPU while we don't
141262306a36Sopenharmony_ci		 * change the state to queued on this one */
141362306a36Sopenharmony_ci		slot->state = NCR_700_SLOT_QUEUED;
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci		DEBUG(("scsi%d: host busy, queueing command %p, slot %p\n",
141662306a36Sopenharmony_ci		       SCp->device->host->host_no, slot->cmnd, slot));
141762306a36Sopenharmony_ci		return 0;
141862306a36Sopenharmony_ci	}
141962306a36Sopenharmony_ci	hostdata->state = NCR_700_HOST_BUSY;
142062306a36Sopenharmony_ci	hostdata->cmd = SCp;
142162306a36Sopenharmony_ci	slot->state = NCR_700_SLOT_BUSY;
142262306a36Sopenharmony_ci	/* keep interrupts disabled until we have the command correctly
142362306a36Sopenharmony_ci	 * set up so we cannot take a selection interrupt */
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	hostdata->msgout[0] = NCR_700_identify((SCp->cmnd[0] != REQUEST_SENSE &&
142662306a36Sopenharmony_ci						slot->flags != NCR_700_FLAG_AUTOSENSE),
142762306a36Sopenharmony_ci					       lun);
142862306a36Sopenharmony_ci	/* for INQUIRY or REQUEST_SENSE commands, we cannot be sure
142962306a36Sopenharmony_ci	 * if the negotiated transfer parameters still hold, so
143062306a36Sopenharmony_ci	 * always renegotiate them */
143162306a36Sopenharmony_ci	if(SCp->cmnd[0] == INQUIRY || SCp->cmnd[0] == REQUEST_SENSE ||
143262306a36Sopenharmony_ci	   slot->flags == NCR_700_FLAG_AUTOSENSE) {
143362306a36Sopenharmony_ci		NCR_700_clear_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
143462306a36Sopenharmony_ci	}
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	/* REQUEST_SENSE is asking for contingent I_T_L(_Q) status.
143762306a36Sopenharmony_ci	 * If a contingent allegiance condition exists, the device
143862306a36Sopenharmony_ci	 * will refuse all tags, so send the request sense as untagged
143962306a36Sopenharmony_ci	 * */
144062306a36Sopenharmony_ci	if((hostdata->tag_negotiated & (1<<scmd_id(SCp)))
144162306a36Sopenharmony_ci	   && (slot->tag != SCSI_NO_TAG && SCp->cmnd[0] != REQUEST_SENSE &&
144262306a36Sopenharmony_ci	       slot->flags != NCR_700_FLAG_AUTOSENSE)) {
144362306a36Sopenharmony_ci		count += spi_populate_tag_msg(&hostdata->msgout[count], SCp);
144462306a36Sopenharmony_ci	}
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	if(hostdata->fast &&
144762306a36Sopenharmony_ci	   NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC)) {
144862306a36Sopenharmony_ci		count += spi_populate_sync_msg(&hostdata->msgout[count],
144962306a36Sopenharmony_ci				spi_period(SCp->device->sdev_target),
145062306a36Sopenharmony_ci				spi_offset(SCp->device->sdev_target));
145162306a36Sopenharmony_ci		NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
145262306a36Sopenharmony_ci	}
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci	script_patch_16(hostdata, hostdata->script, MessageCount, count);
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	script_patch_ID(hostdata, hostdata->script, Device_ID, 1<<scmd_id(SCp));
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	script_patch_32_abs(hostdata, hostdata->script, CommandAddress,
145962306a36Sopenharmony_ci			    slot->pCmd);
146062306a36Sopenharmony_ci	script_patch_16(hostdata, hostdata->script, CommandCount, SCp->cmd_len);
146162306a36Sopenharmony_ci	/* finally plumb the beginning of the SG list into the script
146262306a36Sopenharmony_ci	 * */
146362306a36Sopenharmony_ci	script_patch_32_abs(hostdata, hostdata->script,
146462306a36Sopenharmony_ci	                    SGScriptStartAddress, to32bit(&slot->pSG[0].ins));
146562306a36Sopenharmony_ci	NCR_700_clear_fifo(SCp->device->host);
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	if(slot->resume_offset == 0)
146862306a36Sopenharmony_ci		slot->resume_offset = hostdata->pScript;
146962306a36Sopenharmony_ci	/* now perform all the writebacks and invalidates */
147062306a36Sopenharmony_ci	dma_sync_to_dev(hostdata, hostdata->msgout, count);
147162306a36Sopenharmony_ci	dma_sync_from_dev(hostdata, hostdata->msgin, MSG_ARRAY_SIZE);
147262306a36Sopenharmony_ci	dma_sync_to_dev(hostdata, SCp->cmnd, SCp->cmd_len);
147362306a36Sopenharmony_ci	dma_sync_from_dev(hostdata, hostdata->status, 1);
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	/* set the synchronous period/offset */
147662306a36Sopenharmony_ci	NCR_700_writeb(NCR_700_get_SXFER(SCp->device),
147762306a36Sopenharmony_ci		       SCp->device->host, SXFER_REG);
147862306a36Sopenharmony_ci	NCR_700_writel(slot->temp, SCp->device->host, TEMP_REG);
147962306a36Sopenharmony_ci	NCR_700_writel(slot->resume_offset, SCp->device->host, DSP_REG);
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	return 1;
148262306a36Sopenharmony_ci}
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ciirqreturn_t
148562306a36Sopenharmony_ciNCR_700_intr(int irq, void *dev_id)
148662306a36Sopenharmony_ci{
148762306a36Sopenharmony_ci	struct Scsi_Host *host = (struct Scsi_Host *)dev_id;
148862306a36Sopenharmony_ci	struct NCR_700_Host_Parameters *hostdata =
148962306a36Sopenharmony_ci		(struct NCR_700_Host_Parameters *)host->hostdata[0];
149062306a36Sopenharmony_ci	__u8 istat;
149162306a36Sopenharmony_ci	__u32 resume_offset = 0;
149262306a36Sopenharmony_ci	__u8 pun = 0xff, lun = 0xff;
149362306a36Sopenharmony_ci	unsigned long flags;
149462306a36Sopenharmony_ci	int handled = 0;
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	/* Use the host lock to serialise access to the 53c700
149762306a36Sopenharmony_ci	 * hardware.  Note: In future, we may need to take the queue
149862306a36Sopenharmony_ci	 * lock to enter the done routines.  When that happens, we
149962306a36Sopenharmony_ci	 * need to ensure that for this driver, the host lock and the
150062306a36Sopenharmony_ci	 * queue lock point to the same thing. */
150162306a36Sopenharmony_ci	spin_lock_irqsave(host->host_lock, flags);
150262306a36Sopenharmony_ci	if((istat = NCR_700_readb(host, ISTAT_REG))
150362306a36Sopenharmony_ci	      & (SCSI_INT_PENDING | DMA_INT_PENDING)) {
150462306a36Sopenharmony_ci		__u32 dsps;
150562306a36Sopenharmony_ci		__u8 sstat0 = 0, dstat = 0;
150662306a36Sopenharmony_ci		__u32 dsp;
150762306a36Sopenharmony_ci		struct scsi_cmnd *SCp = hostdata->cmd;
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci		handled = 1;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci		if(istat & SCSI_INT_PENDING) {
151262306a36Sopenharmony_ci			udelay(10);
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci			sstat0 = NCR_700_readb(host, SSTAT0_REG);
151562306a36Sopenharmony_ci		}
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci		if(istat & DMA_INT_PENDING) {
151862306a36Sopenharmony_ci			udelay(10);
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci			dstat = NCR_700_readb(host, DSTAT_REG);
152162306a36Sopenharmony_ci		}
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci		dsps = NCR_700_readl(host, DSPS_REG);
152462306a36Sopenharmony_ci		dsp = NCR_700_readl(host, DSP_REG);
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci		DEBUG(("scsi%d: istat %02x sstat0 %02x dstat %02x dsp %04x[%08x] dsps 0x%x\n",
152762306a36Sopenharmony_ci		       host->host_no, istat, sstat0, dstat,
152862306a36Sopenharmony_ci		       (dsp - (__u32)(hostdata->pScript))/4,
152962306a36Sopenharmony_ci		       dsp, dsps));
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci		if(SCp != NULL) {
153262306a36Sopenharmony_ci			pun = SCp->device->id;
153362306a36Sopenharmony_ci			lun = SCp->device->lun;
153462306a36Sopenharmony_ci		}
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci		if(sstat0 & SCSI_RESET_DETECTED) {
153762306a36Sopenharmony_ci			struct scsi_device *SDp;
153862306a36Sopenharmony_ci			int i;
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci			hostdata->state = NCR_700_HOST_BUSY;
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci			printk(KERN_ERR "scsi%d: Bus Reset detected, executing command %p, slot %p, dsp %08x[%04x]\n",
154362306a36Sopenharmony_ci			       host->host_no, SCp, SCp == NULL ? NULL : SCp->host_scribble, dsp, dsp - hostdata->pScript);
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci			scsi_report_bus_reset(host, 0);
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci			/* clear all the negotiated parameters */
154862306a36Sopenharmony_ci			__shost_for_each_device(SDp, host)
154962306a36Sopenharmony_ci				NCR_700_clear_flag(SDp, ~0);
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci			/* clear all the slots and their pending commands */
155262306a36Sopenharmony_ci			for(i = 0; i < NCR_700_COMMAND_SLOTS_PER_HOST; i++) {
155362306a36Sopenharmony_ci				struct scsi_cmnd *SCp;
155462306a36Sopenharmony_ci				struct NCR_700_command_slot *slot =
155562306a36Sopenharmony_ci					&hostdata->slots[i];
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci				if(slot->state == NCR_700_SLOT_FREE)
155862306a36Sopenharmony_ci					continue;
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci				SCp = slot->cmnd;
156162306a36Sopenharmony_ci				printk(KERN_ERR " failing command because of reset, slot %p, cmnd %p\n",
156262306a36Sopenharmony_ci				       slot, SCp);
156362306a36Sopenharmony_ci				free_slot(slot, hostdata);
156462306a36Sopenharmony_ci				SCp->host_scribble = NULL;
156562306a36Sopenharmony_ci				NCR_700_set_depth(SCp->device, 0);
156662306a36Sopenharmony_ci				/* NOTE: deadlock potential here: we
156762306a36Sopenharmony_ci				 * rely on mid-layer guarantees that
156862306a36Sopenharmony_ci				 * scsi_done won't try to issue the
156962306a36Sopenharmony_ci				 * command again otherwise we'll
157062306a36Sopenharmony_ci				 * deadlock on the
157162306a36Sopenharmony_ci				 * hostdata->state_lock */
157262306a36Sopenharmony_ci				SCp->result = DID_RESET << 16;
157362306a36Sopenharmony_ci				scsi_done(SCp);
157462306a36Sopenharmony_ci			}
157562306a36Sopenharmony_ci			mdelay(25);
157662306a36Sopenharmony_ci			NCR_700_chip_setup(host);
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci			hostdata->state = NCR_700_HOST_FREE;
157962306a36Sopenharmony_ci			hostdata->cmd = NULL;
158062306a36Sopenharmony_ci			/* signal back if this was an eh induced reset */
158162306a36Sopenharmony_ci			if(hostdata->eh_complete != NULL)
158262306a36Sopenharmony_ci				complete(hostdata->eh_complete);
158362306a36Sopenharmony_ci			goto out_unlock;
158462306a36Sopenharmony_ci		} else if(sstat0 & SELECTION_TIMEOUT) {
158562306a36Sopenharmony_ci			DEBUG(("scsi%d: (%d:%d) selection timeout\n",
158662306a36Sopenharmony_ci			       host->host_no, pun, lun));
158762306a36Sopenharmony_ci			NCR_700_scsi_done(hostdata, SCp, DID_NO_CONNECT<<16);
158862306a36Sopenharmony_ci		} else if(sstat0 & PHASE_MISMATCH) {
158962306a36Sopenharmony_ci			struct NCR_700_command_slot *slot = (SCp == NULL) ? NULL :
159062306a36Sopenharmony_ci				(struct NCR_700_command_slot *)SCp->host_scribble;
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci			if(dsp == Ent_SendMessage + 8 + hostdata->pScript) {
159362306a36Sopenharmony_ci				/* It wants to reply to some part of
159462306a36Sopenharmony_ci				 * our message */
159562306a36Sopenharmony_ci#ifdef NCR_700_DEBUG
159662306a36Sopenharmony_ci				__u32 temp = NCR_700_readl(host, TEMP_REG);
159762306a36Sopenharmony_ci				int count = (hostdata->script[Ent_SendMessage/4] & 0xffffff) - ((NCR_700_readl(host, DBC_REG) & 0xffffff) + NCR_700_data_residual(host));
159862306a36Sopenharmony_ci				printk("scsi%d (%d:%d) PHASE MISMATCH IN SEND MESSAGE %d remain, return %p[%04x], phase %s\n", host->host_no, pun, lun, count, (void *)temp, temp - hostdata->pScript, sbcl_to_string(NCR_700_readb(host, SBCL_REG)));
159962306a36Sopenharmony_ci#endif
160062306a36Sopenharmony_ci				resume_offset = hostdata->pScript + Ent_SendMessagePhaseMismatch;
160162306a36Sopenharmony_ci			} else if (slot && dsp >= to32bit(&slot->pSG[0].ins) &&
160262306a36Sopenharmony_ci				  dsp <= to32bit(&slot->pSG[NCR_700_SG_SEGMENTS].ins)) {
160362306a36Sopenharmony_ci				int data_transfer = NCR_700_readl(host, DBC_REG) & 0xffffff;
160462306a36Sopenharmony_ci				int SGcount = (dsp - to32bit(&slot->pSG[0].ins))/sizeof(struct NCR_700_SG_List);
160562306a36Sopenharmony_ci				int residual = NCR_700_data_residual(host);
160662306a36Sopenharmony_ci				int i;
160762306a36Sopenharmony_ci#ifdef NCR_700_DEBUG
160862306a36Sopenharmony_ci				__u32 naddr = NCR_700_readl(host, DNAD_REG);
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci				printk("scsi%d: (%d:%d) Expected phase mismatch in slot->SG[%d], transferred 0x%x\n",
161162306a36Sopenharmony_ci				       host->host_no, pun, lun,
161262306a36Sopenharmony_ci				       SGcount, data_transfer);
161362306a36Sopenharmony_ci				scsi_print_command(SCp);
161462306a36Sopenharmony_ci				if(residual) {
161562306a36Sopenharmony_ci					printk("scsi%d: (%d:%d) Expected phase mismatch in slot->SG[%d], transferred 0x%x, residual %d\n",
161662306a36Sopenharmony_ci				       host->host_no, pun, lun,
161762306a36Sopenharmony_ci				       SGcount, data_transfer, residual);
161862306a36Sopenharmony_ci				}
161962306a36Sopenharmony_ci#endif
162062306a36Sopenharmony_ci				data_transfer += residual;
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci				if(data_transfer != 0) {
162362306a36Sopenharmony_ci					int count;
162462306a36Sopenharmony_ci					__u32 pAddr;
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci					SGcount--;
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci					count = (bS_to_cpu(slot->SG[SGcount].ins) & 0x00ffffff);
162962306a36Sopenharmony_ci					DEBUG(("DATA TRANSFER MISMATCH, count = %d, transferred %d\n", count, count-data_transfer));
163062306a36Sopenharmony_ci					slot->SG[SGcount].ins &= bS_to_host(0xff000000);
163162306a36Sopenharmony_ci					slot->SG[SGcount].ins |= bS_to_host(data_transfer);
163262306a36Sopenharmony_ci					pAddr = bS_to_cpu(slot->SG[SGcount].pAddr);
163362306a36Sopenharmony_ci					pAddr += (count - data_transfer);
163462306a36Sopenharmony_ci#ifdef NCR_700_DEBUG
163562306a36Sopenharmony_ci					if(pAddr != naddr) {
163662306a36Sopenharmony_ci						printk("scsi%d (%d:%d) transfer mismatch pAddr=%lx, naddr=%lx, data_transfer=%d, residual=%d\n", host->host_no, pun, lun, (unsigned long)pAddr, (unsigned long)naddr, data_transfer, residual);
163762306a36Sopenharmony_ci					}
163862306a36Sopenharmony_ci#endif
163962306a36Sopenharmony_ci					slot->SG[SGcount].pAddr = bS_to_host(pAddr);
164062306a36Sopenharmony_ci				}
164162306a36Sopenharmony_ci				/* set the executed moves to nops */
164262306a36Sopenharmony_ci				for(i=0; i<SGcount; i++) {
164362306a36Sopenharmony_ci					slot->SG[i].ins = bS_to_host(SCRIPT_NOP);
164462306a36Sopenharmony_ci					slot->SG[i].pAddr = 0;
164562306a36Sopenharmony_ci				}
164662306a36Sopenharmony_ci				dma_sync_to_dev(hostdata, slot->SG, sizeof(slot->SG));
164762306a36Sopenharmony_ci				/* and pretend we disconnected after
164862306a36Sopenharmony_ci				 * the command phase */
164962306a36Sopenharmony_ci				resume_offset = hostdata->pScript + Ent_MsgInDuringData;
165062306a36Sopenharmony_ci				/* make sure all the data is flushed */
165162306a36Sopenharmony_ci				NCR_700_flush_fifo(host);
165262306a36Sopenharmony_ci			} else {
165362306a36Sopenharmony_ci				__u8 sbcl = NCR_700_readb(host, SBCL_REG);
165462306a36Sopenharmony_ci				printk(KERN_ERR "scsi%d: (%d:%d) phase mismatch at %04x, phase %s\n",
165562306a36Sopenharmony_ci				       host->host_no, pun, lun, dsp - hostdata->pScript, sbcl_to_string(sbcl));
165662306a36Sopenharmony_ci				NCR_700_internal_bus_reset(host);
165762306a36Sopenharmony_ci			}
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci		} else if(sstat0 & SCSI_GROSS_ERROR) {
166062306a36Sopenharmony_ci			printk(KERN_ERR "scsi%d: (%d:%d) GROSS ERROR\n",
166162306a36Sopenharmony_ci			       host->host_no, pun, lun);
166262306a36Sopenharmony_ci			NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16);
166362306a36Sopenharmony_ci		} else if(sstat0 & PARITY_ERROR) {
166462306a36Sopenharmony_ci			printk(KERN_ERR "scsi%d: (%d:%d) PARITY ERROR\n",
166562306a36Sopenharmony_ci			       host->host_no, pun, lun);
166662306a36Sopenharmony_ci			NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16);
166762306a36Sopenharmony_ci		} else if(dstat & SCRIPT_INT_RECEIVED) {
166862306a36Sopenharmony_ci			DEBUG(("scsi%d: (%d:%d) ====>SCRIPT INTERRUPT<====\n",
166962306a36Sopenharmony_ci			       host->host_no, pun, lun));
167062306a36Sopenharmony_ci			resume_offset = process_script_interrupt(dsps, dsp, SCp, host, hostdata);
167162306a36Sopenharmony_ci		} else if(dstat & (ILGL_INST_DETECTED)) {
167262306a36Sopenharmony_ci			printk(KERN_ERR "scsi%d: (%d:%d) Illegal Instruction detected at 0x%08x[0x%x]!!!\n"
167362306a36Sopenharmony_ci			       "         Please email James.Bottomley@HansenPartnership.com with the details\n",
167462306a36Sopenharmony_ci			       host->host_no, pun, lun,
167562306a36Sopenharmony_ci			       dsp, dsp - hostdata->pScript);
167662306a36Sopenharmony_ci			NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16);
167762306a36Sopenharmony_ci		} else if(dstat & (WATCH_DOG_INTERRUPT|ABORTED)) {
167862306a36Sopenharmony_ci			printk(KERN_ERR "scsi%d: (%d:%d) serious DMA problem, dstat=%02x\n",
167962306a36Sopenharmony_ci			       host->host_no, pun, lun, dstat);
168062306a36Sopenharmony_ci			NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16);
168162306a36Sopenharmony_ci		}
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci		/* NOTE: selection interrupt processing MUST occur
168562306a36Sopenharmony_ci		 * after script interrupt processing to correctly cope
168662306a36Sopenharmony_ci		 * with the case where we process a disconnect and
168762306a36Sopenharmony_ci		 * then get reselected before we process the
168862306a36Sopenharmony_ci		 * disconnection */
168962306a36Sopenharmony_ci		if(sstat0 & SELECTED) {
169062306a36Sopenharmony_ci			/* FIXME: It currently takes at least FOUR
169162306a36Sopenharmony_ci			 * interrupts to complete a command that
169262306a36Sopenharmony_ci			 * disconnects: one for the disconnect, one
169362306a36Sopenharmony_ci			 * for the reselection, one to get the
169462306a36Sopenharmony_ci			 * reselection data and one to complete the
169562306a36Sopenharmony_ci			 * command.  If we guess the reselected
169662306a36Sopenharmony_ci			 * command here and prepare it, we only need
169762306a36Sopenharmony_ci			 * to get a reselection data interrupt if we
169862306a36Sopenharmony_ci			 * guessed wrongly.  Since the interrupt
169962306a36Sopenharmony_ci			 * overhead is much greater than the command
170062306a36Sopenharmony_ci			 * setup, this would be an efficient
170162306a36Sopenharmony_ci			 * optimisation particularly as we probably
170262306a36Sopenharmony_ci			 * only have one outstanding command on a
170362306a36Sopenharmony_ci			 * target most of the time */
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci			resume_offset = process_selection(host, dsp);
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_ci		}
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci	}
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_ci	if(resume_offset) {
171262306a36Sopenharmony_ci		if(hostdata->state != NCR_700_HOST_BUSY) {
171362306a36Sopenharmony_ci			printk(KERN_ERR "scsi%d: Driver error: resume at 0x%08x [0x%04x] with non busy host!\n",
171462306a36Sopenharmony_ci			       host->host_no, resume_offset, resume_offset - hostdata->pScript);
171562306a36Sopenharmony_ci			hostdata->state = NCR_700_HOST_BUSY;
171662306a36Sopenharmony_ci		}
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci		DEBUG(("Attempting to resume at %x\n", resume_offset));
171962306a36Sopenharmony_ci		NCR_700_clear_fifo(host);
172062306a36Sopenharmony_ci		NCR_700_writel(resume_offset, host, DSP_REG);
172162306a36Sopenharmony_ci	}
172262306a36Sopenharmony_ci	/* There is probably a technical no-no about this: If we're a
172362306a36Sopenharmony_ci	 * shared interrupt and we got this interrupt because the
172462306a36Sopenharmony_ci	 * other device needs servicing not us, we're still going to
172562306a36Sopenharmony_ci	 * check our queued commands here---of course, there shouldn't
172662306a36Sopenharmony_ci	 * be any outstanding.... */
172762306a36Sopenharmony_ci	if(hostdata->state == NCR_700_HOST_FREE) {
172862306a36Sopenharmony_ci		int i;
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci		for(i = 0; i < NCR_700_COMMAND_SLOTS_PER_HOST; i++) {
173162306a36Sopenharmony_ci			/* fairness: always run the queue from the last
173262306a36Sopenharmony_ci			 * position we left off */
173362306a36Sopenharmony_ci			int j = (i + hostdata->saved_slot_position)
173462306a36Sopenharmony_ci				% NCR_700_COMMAND_SLOTS_PER_HOST;
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci			if(hostdata->slots[j].state != NCR_700_SLOT_QUEUED)
173762306a36Sopenharmony_ci				continue;
173862306a36Sopenharmony_ci			if(NCR_700_start_command(hostdata->slots[j].cmnd)) {
173962306a36Sopenharmony_ci				DEBUG(("scsi%d: Issuing saved command slot %p, cmd %p\t\n",
174062306a36Sopenharmony_ci				       host->host_no, &hostdata->slots[j],
174162306a36Sopenharmony_ci				       hostdata->slots[j].cmnd));
174262306a36Sopenharmony_ci				hostdata->saved_slot_position = j + 1;
174362306a36Sopenharmony_ci			}
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci			break;
174662306a36Sopenharmony_ci		}
174762306a36Sopenharmony_ci	}
174862306a36Sopenharmony_ci out_unlock:
174962306a36Sopenharmony_ci	spin_unlock_irqrestore(host->host_lock, flags);
175062306a36Sopenharmony_ci	return IRQ_RETVAL(handled);
175162306a36Sopenharmony_ci}
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_cistatic int NCR_700_queuecommand_lck(struct scsi_cmnd *SCp)
175462306a36Sopenharmony_ci{
175562306a36Sopenharmony_ci	struct NCR_700_Host_Parameters *hostdata =
175662306a36Sopenharmony_ci		(struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0];
175762306a36Sopenharmony_ci	__u32 move_ins;
175862306a36Sopenharmony_ci	struct NCR_700_command_slot *slot;
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	if(hostdata->command_slot_count >= NCR_700_COMMAND_SLOTS_PER_HOST) {
176162306a36Sopenharmony_ci		/* We're over our allocation, this should never happen
176262306a36Sopenharmony_ci		 * since we report the max allocation to the mid layer */
176362306a36Sopenharmony_ci		printk(KERN_WARNING "scsi%d: Command depth has gone over queue depth\n", SCp->device->host->host_no);
176462306a36Sopenharmony_ci		return 1;
176562306a36Sopenharmony_ci	}
176662306a36Sopenharmony_ci	/* check for untagged commands.  We cannot have any outstanding
176762306a36Sopenharmony_ci	 * commands if we accept them.  Commands could be untagged because:
176862306a36Sopenharmony_ci	 *
176962306a36Sopenharmony_ci	 * - The tag negotiated bitmap is clear
177062306a36Sopenharmony_ci	 * - The blk layer sent and untagged command
177162306a36Sopenharmony_ci	 */
177262306a36Sopenharmony_ci	if(NCR_700_get_depth(SCp->device) != 0
177362306a36Sopenharmony_ci	   && (!(hostdata->tag_negotiated & (1<<scmd_id(SCp)))
177462306a36Sopenharmony_ci	       || !(SCp->flags & SCMD_TAGGED))) {
177562306a36Sopenharmony_ci		CDEBUG(KERN_ERR, SCp, "has non zero depth %d\n",
177662306a36Sopenharmony_ci		       NCR_700_get_depth(SCp->device));
177762306a36Sopenharmony_ci		return SCSI_MLQUEUE_DEVICE_BUSY;
177862306a36Sopenharmony_ci	}
177962306a36Sopenharmony_ci	if(NCR_700_get_depth(SCp->device) >= SCp->device->queue_depth) {
178062306a36Sopenharmony_ci		CDEBUG(KERN_ERR, SCp, "has max tag depth %d\n",
178162306a36Sopenharmony_ci		       NCR_700_get_depth(SCp->device));
178262306a36Sopenharmony_ci		return SCSI_MLQUEUE_DEVICE_BUSY;
178362306a36Sopenharmony_ci	}
178462306a36Sopenharmony_ci	NCR_700_set_depth(SCp->device, NCR_700_get_depth(SCp->device) + 1);
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci	/* begin the command here */
178762306a36Sopenharmony_ci	/* no need to check for NULL, test for command_slot_count above
178862306a36Sopenharmony_ci	 * ensures a slot is free */
178962306a36Sopenharmony_ci	slot = find_empty_slot(hostdata);
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci	slot->cmnd = SCp;
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	SCp->host_scribble = (unsigned char *)slot;
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci#ifdef NCR_700_DEBUG
179662306a36Sopenharmony_ci	printk("53c700: scsi%d, command ", SCp->device->host->host_no);
179762306a36Sopenharmony_ci	scsi_print_command(SCp);
179862306a36Sopenharmony_ci#endif
179962306a36Sopenharmony_ci	if ((SCp->flags & SCMD_TAGGED)
180062306a36Sopenharmony_ci	   && (hostdata->tag_negotiated &(1<<scmd_id(SCp))) == 0
180162306a36Sopenharmony_ci	   && NCR_700_get_tag_neg_state(SCp->device) == NCR_700_START_TAG_NEGOTIATION) {
180262306a36Sopenharmony_ci		scmd_printk(KERN_ERR, SCp, "Enabling Tag Command Queuing\n");
180362306a36Sopenharmony_ci		hostdata->tag_negotiated |= (1<<scmd_id(SCp));
180462306a36Sopenharmony_ci		NCR_700_set_tag_neg_state(SCp->device, NCR_700_DURING_TAG_NEGOTIATION);
180562306a36Sopenharmony_ci	}
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	/* here we may have to process an untagged command.  The gate
180862306a36Sopenharmony_ci	 * above ensures that this will be the only one outstanding,
180962306a36Sopenharmony_ci	 * so clear the tag negotiated bit.
181062306a36Sopenharmony_ci	 *
181162306a36Sopenharmony_ci	 * FIXME: This will royally screw up on multiple LUN devices
181262306a36Sopenharmony_ci	 * */
181362306a36Sopenharmony_ci	if (!(SCp->flags & SCMD_TAGGED)
181462306a36Sopenharmony_ci	   && (hostdata->tag_negotiated &(1<<scmd_id(SCp)))) {
181562306a36Sopenharmony_ci		scmd_printk(KERN_INFO, SCp, "Disabling Tag Command Queuing\n");
181662306a36Sopenharmony_ci		hostdata->tag_negotiated &= ~(1<<scmd_id(SCp));
181762306a36Sopenharmony_ci	}
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	if ((hostdata->tag_negotiated & (1<<scmd_id(SCp))) &&
182062306a36Sopenharmony_ci	    SCp->device->simple_tags) {
182162306a36Sopenharmony_ci		slot->tag = scsi_cmd_to_rq(SCp)->tag;
182262306a36Sopenharmony_ci		CDEBUG(KERN_DEBUG, SCp, "sending out tag %d, slot %p\n",
182362306a36Sopenharmony_ci		       slot->tag, slot);
182462306a36Sopenharmony_ci	} else {
182562306a36Sopenharmony_ci		struct NCR_700_Device_Parameters *p = SCp->device->hostdata;
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci		slot->tag = SCSI_NO_TAG;
182862306a36Sopenharmony_ci		/* save current command for reselection */
182962306a36Sopenharmony_ci		p->current_cmnd = SCp;
183062306a36Sopenharmony_ci	}
183162306a36Sopenharmony_ci	/* sanity check: some of the commands generated by the mid-layer
183262306a36Sopenharmony_ci	 * have an eccentric idea of their sc_data_direction */
183362306a36Sopenharmony_ci	if(!scsi_sg_count(SCp) && !scsi_bufflen(SCp) &&
183462306a36Sopenharmony_ci	   SCp->sc_data_direction != DMA_NONE) {
183562306a36Sopenharmony_ci#ifdef NCR_700_DEBUG
183662306a36Sopenharmony_ci		printk("53c700: Command");
183762306a36Sopenharmony_ci		scsi_print_command(SCp);
183862306a36Sopenharmony_ci		printk("Has wrong data direction %d\n", SCp->sc_data_direction);
183962306a36Sopenharmony_ci#endif
184062306a36Sopenharmony_ci		SCp->sc_data_direction = DMA_NONE;
184162306a36Sopenharmony_ci	}
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci	switch (SCp->cmnd[0]) {
184462306a36Sopenharmony_ci	case REQUEST_SENSE:
184562306a36Sopenharmony_ci		/* clear the internal sense magic */
184662306a36Sopenharmony_ci		SCp->cmnd[6] = 0;
184762306a36Sopenharmony_ci		fallthrough;
184862306a36Sopenharmony_ci	default:
184962306a36Sopenharmony_ci		/* OK, get it from the command */
185062306a36Sopenharmony_ci		switch(SCp->sc_data_direction) {
185162306a36Sopenharmony_ci		case DMA_BIDIRECTIONAL:
185262306a36Sopenharmony_ci		default:
185362306a36Sopenharmony_ci			printk(KERN_ERR "53c700: Unknown command for data direction ");
185462306a36Sopenharmony_ci			scsi_print_command(SCp);
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci			move_ins = 0;
185762306a36Sopenharmony_ci			break;
185862306a36Sopenharmony_ci		case DMA_NONE:
185962306a36Sopenharmony_ci			move_ins = 0;
186062306a36Sopenharmony_ci			break;
186162306a36Sopenharmony_ci		case DMA_FROM_DEVICE:
186262306a36Sopenharmony_ci			move_ins = SCRIPT_MOVE_DATA_IN;
186362306a36Sopenharmony_ci			break;
186462306a36Sopenharmony_ci		case DMA_TO_DEVICE:
186562306a36Sopenharmony_ci			move_ins = SCRIPT_MOVE_DATA_OUT;
186662306a36Sopenharmony_ci			break;
186762306a36Sopenharmony_ci		}
186862306a36Sopenharmony_ci	}
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	/* now build the scatter gather list */
187162306a36Sopenharmony_ci	if(move_ins != 0) {
187262306a36Sopenharmony_ci		int i;
187362306a36Sopenharmony_ci		int sg_count;
187462306a36Sopenharmony_ci		dma_addr_t vPtr = 0;
187562306a36Sopenharmony_ci		struct scatterlist *sg;
187662306a36Sopenharmony_ci		__u32 count = 0;
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci		sg_count = scsi_dma_map(SCp);
187962306a36Sopenharmony_ci		BUG_ON(sg_count < 0);
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci		scsi_for_each_sg(SCp, sg, sg_count, i) {
188262306a36Sopenharmony_ci			vPtr = sg_dma_address(sg);
188362306a36Sopenharmony_ci			count = sg_dma_len(sg);
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci			slot->SG[i].ins = bS_to_host(move_ins | count);
188662306a36Sopenharmony_ci			DEBUG((" scatter block %d: move %d[%08x] from 0x%lx\n",
188762306a36Sopenharmony_ci			       i, count, slot->SG[i].ins, (unsigned long)vPtr));
188862306a36Sopenharmony_ci			slot->SG[i].pAddr = bS_to_host(vPtr);
188962306a36Sopenharmony_ci		}
189062306a36Sopenharmony_ci		slot->SG[i].ins = bS_to_host(SCRIPT_RETURN);
189162306a36Sopenharmony_ci		slot->SG[i].pAddr = 0;
189262306a36Sopenharmony_ci		dma_sync_to_dev(hostdata, slot->SG, sizeof(slot->SG));
189362306a36Sopenharmony_ci		DEBUG((" SETTING %p to %x\n",
189462306a36Sopenharmony_ci		       (&slot->pSG[i].ins),
189562306a36Sopenharmony_ci		       slot->SG[i].ins));
189662306a36Sopenharmony_ci	}
189762306a36Sopenharmony_ci	slot->resume_offset = 0;
189862306a36Sopenharmony_ci	slot->pCmd = dma_map_single(hostdata->dev, SCp->cmnd,
189962306a36Sopenharmony_ci				    MAX_COMMAND_SIZE, DMA_TO_DEVICE);
190062306a36Sopenharmony_ci	NCR_700_start_command(SCp);
190162306a36Sopenharmony_ci	return 0;
190262306a36Sopenharmony_ci}
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ciSTATIC DEF_SCSI_QCMD(NCR_700_queuecommand)
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ciSTATIC int
190762306a36Sopenharmony_ciNCR_700_abort(struct scsi_cmnd * SCp)
190862306a36Sopenharmony_ci{
190962306a36Sopenharmony_ci	struct NCR_700_command_slot *slot;
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci	scmd_printk(KERN_INFO, SCp, "abort command\n");
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	slot = (struct NCR_700_command_slot *)SCp->host_scribble;
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ci	if(slot == NULL)
191662306a36Sopenharmony_ci		/* no outstanding command to abort */
191762306a36Sopenharmony_ci		return SUCCESS;
191862306a36Sopenharmony_ci	if(SCp->cmnd[0] == TEST_UNIT_READY) {
191962306a36Sopenharmony_ci		/* FIXME: This is because of a problem in the new
192062306a36Sopenharmony_ci		 * error handler.  When it is in error recovery, it
192162306a36Sopenharmony_ci		 * will send a TUR to a device it thinks may still be
192262306a36Sopenharmony_ci		 * showing a problem.  If the TUR isn't responded to,
192362306a36Sopenharmony_ci		 * it will abort it and mark the device off line.
192462306a36Sopenharmony_ci		 * Unfortunately, it does no other error recovery, so
192562306a36Sopenharmony_ci		 * this would leave us with an outstanding command
192662306a36Sopenharmony_ci		 * occupying a slot.  Rather than allow this to
192762306a36Sopenharmony_ci		 * happen, we issue a bus reset to force all
192862306a36Sopenharmony_ci		 * outstanding commands to terminate here. */
192962306a36Sopenharmony_ci		NCR_700_internal_bus_reset(SCp->device->host);
193062306a36Sopenharmony_ci		/* still drop through and return failed */
193162306a36Sopenharmony_ci	}
193262306a36Sopenharmony_ci	return FAILED;
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci}
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ciSTATIC int
193762306a36Sopenharmony_ciNCR_700_host_reset(struct scsi_cmnd * SCp)
193862306a36Sopenharmony_ci{
193962306a36Sopenharmony_ci	DECLARE_COMPLETION_ONSTACK(complete);
194062306a36Sopenharmony_ci	struct NCR_700_Host_Parameters *hostdata =
194162306a36Sopenharmony_ci		(struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0];
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci	scmd_printk(KERN_INFO, SCp,
194462306a36Sopenharmony_ci		"New error handler wants HOST reset, cmd %p\n\t", SCp);
194562306a36Sopenharmony_ci	scsi_print_command(SCp);
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci	/* In theory, eh_complete should always be null because the
194862306a36Sopenharmony_ci	 * eh is single threaded, but just in case we're handling a
194962306a36Sopenharmony_ci	 * reset via sg or something */
195062306a36Sopenharmony_ci	spin_lock_irq(SCp->device->host->host_lock);
195162306a36Sopenharmony_ci	while (hostdata->eh_complete != NULL) {
195262306a36Sopenharmony_ci		spin_unlock_irq(SCp->device->host->host_lock);
195362306a36Sopenharmony_ci		msleep_interruptible(100);
195462306a36Sopenharmony_ci		spin_lock_irq(SCp->device->host->host_lock);
195562306a36Sopenharmony_ci	}
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci	hostdata->eh_complete = &complete;
195862306a36Sopenharmony_ci	NCR_700_internal_bus_reset(SCp->device->host);
195962306a36Sopenharmony_ci	NCR_700_chip_reset(SCp->device->host);
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci	spin_unlock_irq(SCp->device->host->host_lock);
196262306a36Sopenharmony_ci	wait_for_completion(&complete);
196362306a36Sopenharmony_ci	spin_lock_irq(SCp->device->host->host_lock);
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	hostdata->eh_complete = NULL;
196662306a36Sopenharmony_ci	/* Revalidate the transport parameters of the failing device */
196762306a36Sopenharmony_ci	if(hostdata->fast)
196862306a36Sopenharmony_ci		spi_schedule_dv_device(SCp->device);
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	spin_unlock_irq(SCp->device->host->host_lock);
197162306a36Sopenharmony_ci	return SUCCESS;
197262306a36Sopenharmony_ci}
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ciSTATIC void
197562306a36Sopenharmony_ciNCR_700_set_period(struct scsi_target *STp, int period)
197662306a36Sopenharmony_ci{
197762306a36Sopenharmony_ci	struct Scsi_Host *SHp = dev_to_shost(STp->dev.parent);
197862306a36Sopenharmony_ci	struct NCR_700_Host_Parameters *hostdata =
197962306a36Sopenharmony_ci		(struct NCR_700_Host_Parameters *)SHp->hostdata[0];
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci	if(!hostdata->fast)
198262306a36Sopenharmony_ci		return;
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_ci	if(period < hostdata->min_period)
198562306a36Sopenharmony_ci		period = hostdata->min_period;
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_ci	spi_period(STp) = period;
198862306a36Sopenharmony_ci	spi_flags(STp) &= ~(NCR_700_DEV_NEGOTIATED_SYNC |
198962306a36Sopenharmony_ci			    NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
199062306a36Sopenharmony_ci	spi_flags(STp) |= NCR_700_DEV_PRINT_SYNC_NEGOTIATION;
199162306a36Sopenharmony_ci}
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_ciSTATIC void
199462306a36Sopenharmony_ciNCR_700_set_offset(struct scsi_target *STp, int offset)
199562306a36Sopenharmony_ci{
199662306a36Sopenharmony_ci	struct Scsi_Host *SHp = dev_to_shost(STp->dev.parent);
199762306a36Sopenharmony_ci	struct NCR_700_Host_Parameters *hostdata =
199862306a36Sopenharmony_ci		(struct NCR_700_Host_Parameters *)SHp->hostdata[0];
199962306a36Sopenharmony_ci	int max_offset = hostdata->chip710
200062306a36Sopenharmony_ci		? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET;
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci	if(!hostdata->fast)
200362306a36Sopenharmony_ci		return;
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci	if(offset > max_offset)
200662306a36Sopenharmony_ci		offset = max_offset;
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_ci	/* if we're currently async, make sure the period is reasonable */
200962306a36Sopenharmony_ci	if(spi_offset(STp) == 0 && (spi_period(STp) < hostdata->min_period ||
201062306a36Sopenharmony_ci				    spi_period(STp) > 0xff))
201162306a36Sopenharmony_ci		spi_period(STp) = hostdata->min_period;
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci	spi_offset(STp) = offset;
201462306a36Sopenharmony_ci	spi_flags(STp) &= ~(NCR_700_DEV_NEGOTIATED_SYNC |
201562306a36Sopenharmony_ci			    NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
201662306a36Sopenharmony_ci	spi_flags(STp) |= NCR_700_DEV_PRINT_SYNC_NEGOTIATION;
201762306a36Sopenharmony_ci}
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ciSTATIC int
202062306a36Sopenharmony_ciNCR_700_slave_alloc(struct scsi_device *SDp)
202162306a36Sopenharmony_ci{
202262306a36Sopenharmony_ci	SDp->hostdata = kzalloc(sizeof(struct NCR_700_Device_Parameters),
202362306a36Sopenharmony_ci				GFP_KERNEL);
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci	if (!SDp->hostdata)
202662306a36Sopenharmony_ci		return -ENOMEM;
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	return 0;
202962306a36Sopenharmony_ci}
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ciSTATIC int
203262306a36Sopenharmony_ciNCR_700_slave_configure(struct scsi_device *SDp)
203362306a36Sopenharmony_ci{
203462306a36Sopenharmony_ci	struct NCR_700_Host_Parameters *hostdata =
203562306a36Sopenharmony_ci		(struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	/* to do here: allocate memory; build a queue_full list */
203862306a36Sopenharmony_ci	if(SDp->tagged_supported) {
203962306a36Sopenharmony_ci		scsi_change_queue_depth(SDp, NCR_700_DEFAULT_TAGS);
204062306a36Sopenharmony_ci		NCR_700_set_tag_neg_state(SDp, NCR_700_START_TAG_NEGOTIATION);
204162306a36Sopenharmony_ci	}
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	if(hostdata->fast) {
204462306a36Sopenharmony_ci		/* Find the correct offset and period via domain validation */
204562306a36Sopenharmony_ci		if (!spi_initial_dv(SDp->sdev_target))
204662306a36Sopenharmony_ci			spi_dv_device(SDp);
204762306a36Sopenharmony_ci	} else {
204862306a36Sopenharmony_ci		spi_offset(SDp->sdev_target) = 0;
204962306a36Sopenharmony_ci		spi_period(SDp->sdev_target) = 0;
205062306a36Sopenharmony_ci	}
205162306a36Sopenharmony_ci	return 0;
205262306a36Sopenharmony_ci}
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_ciSTATIC void
205562306a36Sopenharmony_ciNCR_700_slave_destroy(struct scsi_device *SDp)
205662306a36Sopenharmony_ci{
205762306a36Sopenharmony_ci	kfree(SDp->hostdata);
205862306a36Sopenharmony_ci	SDp->hostdata = NULL;
205962306a36Sopenharmony_ci}
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_cistatic int
206262306a36Sopenharmony_ciNCR_700_change_queue_depth(struct scsi_device *SDp, int depth)
206362306a36Sopenharmony_ci{
206462306a36Sopenharmony_ci	if (depth > NCR_700_MAX_TAGS)
206562306a36Sopenharmony_ci		depth = NCR_700_MAX_TAGS;
206662306a36Sopenharmony_ci	return scsi_change_queue_depth(SDp, depth);
206762306a36Sopenharmony_ci}
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_cistatic ssize_t
207062306a36Sopenharmony_ciNCR_700_show_active_tags(struct device *dev, struct device_attribute *attr, char *buf)
207162306a36Sopenharmony_ci{
207262306a36Sopenharmony_ci	struct scsi_device *SDp = to_scsi_device(dev);
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci	return snprintf(buf, 20, "%d\n", NCR_700_get_depth(SDp));
207562306a36Sopenharmony_ci}
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_cistatic struct device_attribute NCR_700_active_tags_attr = {
207862306a36Sopenharmony_ci	.attr = {
207962306a36Sopenharmony_ci		.name =		"active_tags",
208062306a36Sopenharmony_ci		.mode =		S_IRUGO,
208162306a36Sopenharmony_ci	},
208262306a36Sopenharmony_ci	.show = NCR_700_show_active_tags,
208362306a36Sopenharmony_ci};
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_ciSTATIC struct attribute *NCR_700_dev_attrs[] = {
208662306a36Sopenharmony_ci	&NCR_700_active_tags_attr.attr,
208762306a36Sopenharmony_ci	NULL,
208862306a36Sopenharmony_ci};
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_ciATTRIBUTE_GROUPS(NCR_700_dev);
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ciEXPORT_SYMBOL(NCR_700_detect);
209362306a36Sopenharmony_ciEXPORT_SYMBOL(NCR_700_release);
209462306a36Sopenharmony_ciEXPORT_SYMBOL(NCR_700_intr);
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_cistatic struct spi_function_template NCR_700_transport_functions =  {
209762306a36Sopenharmony_ci	.set_period	= NCR_700_set_period,
209862306a36Sopenharmony_ci	.show_period	= 1,
209962306a36Sopenharmony_ci	.set_offset	= NCR_700_set_offset,
210062306a36Sopenharmony_ci	.show_offset	= 1,
210162306a36Sopenharmony_ci};
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_cistatic int __init NCR_700_init(void)
210462306a36Sopenharmony_ci{
210562306a36Sopenharmony_ci	NCR_700_transport_template = spi_attach_transport(&NCR_700_transport_functions);
210662306a36Sopenharmony_ci	if(!NCR_700_transport_template)
210762306a36Sopenharmony_ci		return -ENODEV;
210862306a36Sopenharmony_ci	return 0;
210962306a36Sopenharmony_ci}
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_cistatic void __exit NCR_700_exit(void)
211262306a36Sopenharmony_ci{
211362306a36Sopenharmony_ci	spi_release_transport(NCR_700_transport_template);
211462306a36Sopenharmony_ci}
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_cimodule_init(NCR_700_init);
211762306a36Sopenharmony_cimodule_exit(NCR_700_exit);
211862306a36Sopenharmony_ci
2119