162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * dc395x.c
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Device Driver for Tekram DC395(U/UW/F), DC315(U)
562306a36Sopenharmony_ci * PCI SCSI Bus Master Host Adapter
662306a36Sopenharmony_ci * (SCSI chip set used Tekram ASIC TRM-S1040)
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Authors:
962306a36Sopenharmony_ci *  C.L. Huang <ching@tekram.com.tw>
1062306a36Sopenharmony_ci *  Erich Chen <erich@tekram.com.tw>
1162306a36Sopenharmony_ci *  (C) Copyright 1995-1999 Tekram Technology Co., Ltd.
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci *  Kurt Garloff <garloff@suse.de>
1462306a36Sopenharmony_ci *  (C) 1999-2000 Kurt Garloff
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci *  Oliver Neukum <oliver@neukum.name>
1762306a36Sopenharmony_ci *  Ali Akcaagac <aliakc@web.de>
1862306a36Sopenharmony_ci *  Jamie Lenehan <lenehan@twibble.org>
1962306a36Sopenharmony_ci *  (C) 2003
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * License: GNU GPL
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci *************************************************************************
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
2662306a36Sopenharmony_ci * modification, are permitted provided that the following conditions
2762306a36Sopenharmony_ci * are met:
2862306a36Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
2962306a36Sopenharmony_ci *    notice, this list of conditions and the following disclaimer.
3062306a36Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
3162306a36Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
3262306a36Sopenharmony_ci *    documentation and/or other materials provided with the distribution.
3362306a36Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products
3462306a36Sopenharmony_ci *    derived from this software without specific prior written permission.
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
3762306a36Sopenharmony_ci * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
3862306a36Sopenharmony_ci * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
3962306a36Sopenharmony_ci * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
4062306a36Sopenharmony_ci * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
4162306a36Sopenharmony_ci * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4262306a36Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4362306a36Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4462306a36Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
4562306a36Sopenharmony_ci * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4662306a36Sopenharmony_ci *
4762306a36Sopenharmony_ci ************************************************************************
4862306a36Sopenharmony_ci */
4962306a36Sopenharmony_ci#include <linux/module.h>
5062306a36Sopenharmony_ci#include <linux/moduleparam.h>
5162306a36Sopenharmony_ci#include <linux/delay.h>
5262306a36Sopenharmony_ci#include <linux/ctype.h>
5362306a36Sopenharmony_ci#include <linux/blkdev.h>
5462306a36Sopenharmony_ci#include <linux/interrupt.h>
5562306a36Sopenharmony_ci#include <linux/init.h>
5662306a36Sopenharmony_ci#include <linux/spinlock.h>
5762306a36Sopenharmony_ci#include <linux/pci.h>
5862306a36Sopenharmony_ci#include <linux/list.h>
5962306a36Sopenharmony_ci#include <linux/vmalloc.h>
6062306a36Sopenharmony_ci#include <linux/slab.h>
6162306a36Sopenharmony_ci#include <asm/io.h>
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#include <scsi/scsi.h>
6462306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h>
6562306a36Sopenharmony_ci#include <scsi/scsi_device.h>
6662306a36Sopenharmony_ci#include <scsi/scsi_host.h>
6762306a36Sopenharmony_ci#include <scsi/scsi_transport_spi.h>
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci#include "dc395x.h"
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#define DC395X_NAME	"dc395x"
7262306a36Sopenharmony_ci#define DC395X_BANNER	"Tekram DC395(U/UW/F), DC315(U) - ASIC TRM-S1040"
7362306a36Sopenharmony_ci#define DC395X_VERSION	"v2.05, 2004/03/08"
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci/*---------------------------------------------------------------------------
7662306a36Sopenharmony_ci                                  Features
7762306a36Sopenharmony_ci ---------------------------------------------------------------------------*/
7862306a36Sopenharmony_ci/*
7962306a36Sopenharmony_ci * Set to disable parts of the driver
8062306a36Sopenharmony_ci */
8162306a36Sopenharmony_ci/*#define DC395x_NO_DISCONNECT*/
8262306a36Sopenharmony_ci/*#define DC395x_NO_TAGQ*/
8362306a36Sopenharmony_ci/*#define DC395x_NO_SYNC*/
8462306a36Sopenharmony_ci/*#define DC395x_NO_WIDE*/
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci/*---------------------------------------------------------------------------
8762306a36Sopenharmony_ci                                  Debugging
8862306a36Sopenharmony_ci ---------------------------------------------------------------------------*/
8962306a36Sopenharmony_ci/*
9062306a36Sopenharmony_ci * Types of debugging that can be enabled and disabled
9162306a36Sopenharmony_ci */
9262306a36Sopenharmony_ci#define DBG_KG		0x0001
9362306a36Sopenharmony_ci#define DBG_0		0x0002
9462306a36Sopenharmony_ci#define DBG_1		0x0004
9562306a36Sopenharmony_ci#define DBG_SG		0x0020
9662306a36Sopenharmony_ci#define DBG_FIFO	0x0040
9762306a36Sopenharmony_ci#define DBG_PIO		0x0080
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/*
10162306a36Sopenharmony_ci * Set set of things to output debugging for.
10262306a36Sopenharmony_ci * Undefine to remove all debugging
10362306a36Sopenharmony_ci */
10462306a36Sopenharmony_ci/*#define DEBUG_MASK (DBG_0|DBG_1|DBG_SG|DBG_FIFO|DBG_PIO)*/
10562306a36Sopenharmony_ci/*#define  DEBUG_MASK	DBG_0*/
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci/*
10962306a36Sopenharmony_ci * Output a kernel mesage at the specified level and append the
11062306a36Sopenharmony_ci * driver name and a ": " to the start of the message
11162306a36Sopenharmony_ci */
11262306a36Sopenharmony_ci#define dprintkl(level, format, arg...)  \
11362306a36Sopenharmony_ci    printk(level DC395X_NAME ": " format , ## arg)
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci#ifdef DEBUG_MASK
11762306a36Sopenharmony_ci/*
11862306a36Sopenharmony_ci * print a debug message - this is formated with KERN_DEBUG, then the
11962306a36Sopenharmony_ci * driver name followed by a ": " and then the message is output.
12062306a36Sopenharmony_ci * This also checks that the specified debug level is enabled before
12162306a36Sopenharmony_ci * outputing the message
12262306a36Sopenharmony_ci */
12362306a36Sopenharmony_ci#define dprintkdbg(type, format, arg...) \
12462306a36Sopenharmony_ci	do { \
12562306a36Sopenharmony_ci		if ((type) & (DEBUG_MASK)) \
12662306a36Sopenharmony_ci			dprintkl(KERN_DEBUG , format , ## arg); \
12762306a36Sopenharmony_ci	} while (0)
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci/*
13062306a36Sopenharmony_ci * Check if the specified type of debugging is enabled
13162306a36Sopenharmony_ci */
13262306a36Sopenharmony_ci#define debug_enabled(type)	((DEBUG_MASK) & (type))
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci#else
13562306a36Sopenharmony_ci/*
13662306a36Sopenharmony_ci * No debugging. Do nothing
13762306a36Sopenharmony_ci */
13862306a36Sopenharmony_ci#define dprintkdbg(type, format, arg...) \
13962306a36Sopenharmony_ci	do {} while (0)
14062306a36Sopenharmony_ci#define debug_enabled(type)	(0)
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci#endif
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci#ifndef PCI_VENDOR_ID_TEKRAM
14662306a36Sopenharmony_ci#define PCI_VENDOR_ID_TEKRAM                    0x1DE1	/* Vendor ID    */
14762306a36Sopenharmony_ci#endif
14862306a36Sopenharmony_ci#ifndef PCI_DEVICE_ID_TEKRAM_TRMS1040
14962306a36Sopenharmony_ci#define PCI_DEVICE_ID_TEKRAM_TRMS1040           0x0391	/* Device ID    */
15062306a36Sopenharmony_ci#endif
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci#define DC395x_LOCK_IO(dev,flags)		spin_lock_irqsave(((struct Scsi_Host *)dev)->host_lock, flags)
15462306a36Sopenharmony_ci#define DC395x_UNLOCK_IO(dev,flags)		spin_unlock_irqrestore(((struct Scsi_Host *)dev)->host_lock, flags)
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci#define DC395x_read8(acb,address)		(u8)(inb(acb->io_port_base + (address)))
15762306a36Sopenharmony_ci#define DC395x_read16(acb,address)		(u16)(inw(acb->io_port_base + (address)))
15862306a36Sopenharmony_ci#define DC395x_read32(acb,address)		(u32)(inl(acb->io_port_base + (address)))
15962306a36Sopenharmony_ci#define DC395x_write8(acb,address,value)	outb((value), acb->io_port_base + (address))
16062306a36Sopenharmony_ci#define DC395x_write16(acb,address,value)	outw((value), acb->io_port_base + (address))
16162306a36Sopenharmony_ci#define DC395x_write32(acb,address,value)	outl((value), acb->io_port_base + (address))
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci#define TAG_NONE 255
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci/*
16662306a36Sopenharmony_ci * srb->segement_x is the hw sg list. It is always allocated as a
16762306a36Sopenharmony_ci * DC395x_MAX_SG_LISTENTRY entries in a linear block which does not
16862306a36Sopenharmony_ci * cross a page boundy.
16962306a36Sopenharmony_ci */
17062306a36Sopenharmony_ci#define SEGMENTX_LEN	(sizeof(struct SGentry)*DC395x_MAX_SG_LISTENTRY)
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistruct SGentry {
17462306a36Sopenharmony_ci	u32 address;		/* bus! address */
17562306a36Sopenharmony_ci	u32 length;
17662306a36Sopenharmony_ci};
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci/* The SEEPROM structure for TRM_S1040 */
17962306a36Sopenharmony_cistruct NVRamTarget {
18062306a36Sopenharmony_ci	u8 cfg0;		/* Target configuration byte 0  */
18162306a36Sopenharmony_ci	u8 period;		/* Target period                */
18262306a36Sopenharmony_ci	u8 cfg2;		/* Target configuration byte 2  */
18362306a36Sopenharmony_ci	u8 cfg3;		/* Target configuration byte 3  */
18462306a36Sopenharmony_ci};
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistruct NvRamType {
18762306a36Sopenharmony_ci	u8 sub_vendor_id[2];	/* 0,1  Sub Vendor ID   */
18862306a36Sopenharmony_ci	u8 sub_sys_id[2];	/* 2,3  Sub System ID   */
18962306a36Sopenharmony_ci	u8 sub_class;		/* 4    Sub Class       */
19062306a36Sopenharmony_ci	u8 vendor_id[2];	/* 5,6  Vendor ID       */
19162306a36Sopenharmony_ci	u8 device_id[2];	/* 7,8  Device ID       */
19262306a36Sopenharmony_ci	u8 reserved;		/* 9    Reserved        */
19362306a36Sopenharmony_ci	struct NVRamTarget target[DC395x_MAX_SCSI_ID];
19462306a36Sopenharmony_ci						/** 10,11,12,13
19562306a36Sopenharmony_ci						 ** 14,15,16,17
19662306a36Sopenharmony_ci						 ** ....
19762306a36Sopenharmony_ci						 ** ....
19862306a36Sopenharmony_ci						 ** 70,71,72,73
19962306a36Sopenharmony_ci						 */
20062306a36Sopenharmony_ci	u8 scsi_id;		/* 74 Host Adapter SCSI ID      */
20162306a36Sopenharmony_ci	u8 channel_cfg;		/* 75 Channel configuration     */
20262306a36Sopenharmony_ci	u8 delay_time;		/* 76 Power on delay time       */
20362306a36Sopenharmony_ci	u8 max_tag;		/* 77 Maximum tags              */
20462306a36Sopenharmony_ci	u8 reserved0;		/* 78  */
20562306a36Sopenharmony_ci	u8 boot_target;		/* 79  */
20662306a36Sopenharmony_ci	u8 boot_lun;		/* 80  */
20762306a36Sopenharmony_ci	u8 reserved1;		/* 81  */
20862306a36Sopenharmony_ci	u16 reserved2[22];	/* 82,..125 */
20962306a36Sopenharmony_ci	u16 cksum;		/* 126,127 */
21062306a36Sopenharmony_ci};
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistruct ScsiReqBlk {
21362306a36Sopenharmony_ci	struct list_head list;		/* next/prev ptrs for srb lists */
21462306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb;
21562306a36Sopenharmony_ci	struct scsi_cmnd *cmd;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	struct SGentry *segment_x;	/* Linear array of hw sg entries (up to 64 entries) */
21862306a36Sopenharmony_ci	dma_addr_t sg_bus_addr;	        /* Bus address of sg list (ie, of segment_x) */
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	u8 sg_count;			/* No of HW sg entries for this request */
22162306a36Sopenharmony_ci	u8 sg_index;			/* Index of HW sg entry for this request */
22262306a36Sopenharmony_ci	size_t total_xfer_length;	/* Total number of bytes remaining to be transferred */
22362306a36Sopenharmony_ci	size_t request_length;		/* Total number of bytes in this request */
22462306a36Sopenharmony_ci	/*
22562306a36Sopenharmony_ci	 * The sense buffer handling function, request_sense, uses
22662306a36Sopenharmony_ci	 * the first hw sg entry (segment_x[0]) and the transfer
22762306a36Sopenharmony_ci	 * length (total_xfer_length). While doing this it stores the
22862306a36Sopenharmony_ci	 * original values into the last sg hw list
22962306a36Sopenharmony_ci	 * (srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1] and the
23062306a36Sopenharmony_ci	 * total_xfer_length in xferred. These values are restored in
23162306a36Sopenharmony_ci	 * pci_unmap_srb_sense. This is the only place xferred is used.
23262306a36Sopenharmony_ci	 */
23362306a36Sopenharmony_ci	size_t xferred;		        /* Saved copy of total_xfer_length */
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	u16 state;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	u8 msgin_buf[6];
23862306a36Sopenharmony_ci	u8 msgout_buf[6];
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	u8 adapter_status;
24162306a36Sopenharmony_ci	u8 target_status;
24262306a36Sopenharmony_ci	u8 msg_count;
24362306a36Sopenharmony_ci	u8 end_message;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	u8 tag_number;
24662306a36Sopenharmony_ci	u8 status;
24762306a36Sopenharmony_ci	u8 retry_count;
24862306a36Sopenharmony_ci	u8 flag;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	u8 scsi_phase;
25162306a36Sopenharmony_ci};
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistruct DeviceCtlBlk {
25462306a36Sopenharmony_ci	struct list_head list;		/* next/prev ptrs for the dcb list */
25562306a36Sopenharmony_ci	struct AdapterCtlBlk *acb;
25662306a36Sopenharmony_ci	struct list_head srb_going_list;	/* head of going srb list */
25762306a36Sopenharmony_ci	struct list_head srb_waiting_list;	/* head of waiting srb list */
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	struct ScsiReqBlk *active_srb;
26062306a36Sopenharmony_ci	u32 tag_mask;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	u16 max_command;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	u8 target_id;		/* SCSI Target ID  (SCSI Only) */
26562306a36Sopenharmony_ci	u8 target_lun;		/* SCSI Log.  Unit (SCSI Only) */
26662306a36Sopenharmony_ci	u8 identify_msg;
26762306a36Sopenharmony_ci	u8 dev_mode;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	u8 inquiry7;		/* To store Inquiry flags */
27062306a36Sopenharmony_ci	u8 sync_mode;		/* 0:async mode */
27162306a36Sopenharmony_ci	u8 min_nego_period;	/* for nego. */
27262306a36Sopenharmony_ci	u8 sync_period;		/* for reg.  */
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	u8 sync_offset;		/* for reg. and nego.(low nibble) */
27562306a36Sopenharmony_ci	u8 flag;
27662306a36Sopenharmony_ci	u8 dev_type;
27762306a36Sopenharmony_ci	u8 init_tcq_flag;
27862306a36Sopenharmony_ci};
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cistruct AdapterCtlBlk {
28162306a36Sopenharmony_ci	struct Scsi_Host *scsi_host;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	unsigned long io_port_base;
28462306a36Sopenharmony_ci	unsigned long io_port_len;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	struct list_head dcb_list;		/* head of going dcb list */
28762306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb_run_robin;
28862306a36Sopenharmony_ci	struct DeviceCtlBlk *active_dcb;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	struct list_head srb_free_list;		/* head of free srb list */
29162306a36Sopenharmony_ci	struct ScsiReqBlk *tmp_srb;
29262306a36Sopenharmony_ci	struct timer_list waiting_timer;
29362306a36Sopenharmony_ci	struct timer_list selto_timer;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	unsigned long last_reset;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	u16 srb_count;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	u8 sel_timeout;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	unsigned int irq_level;
30262306a36Sopenharmony_ci	u8 tag_max_num;
30362306a36Sopenharmony_ci	u8 acb_flag;
30462306a36Sopenharmony_ci	u8 gmode2;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	u8 config;
30762306a36Sopenharmony_ci	u8 lun_chk;
30862306a36Sopenharmony_ci	u8 scan_devices;
30962306a36Sopenharmony_ci	u8 hostid_bit;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	u8 dcb_map[DC395x_MAX_SCSI_ID];
31262306a36Sopenharmony_ci	struct DeviceCtlBlk *children[DC395x_MAX_SCSI_ID][32];
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	struct pci_dev *dev;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	u8 msg_len;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	struct ScsiReqBlk srb_array[DC395x_MAX_SRB_CNT];
31962306a36Sopenharmony_ci	struct ScsiReqBlk srb;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	struct NvRamType eeprom;	/* eeprom settings for this adapter */
32262306a36Sopenharmony_ci};
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci/*---------------------------------------------------------------------------
32662306a36Sopenharmony_ci                            Forward declarations
32762306a36Sopenharmony_ci ---------------------------------------------------------------------------*/
32862306a36Sopenharmony_cistatic void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
32962306a36Sopenharmony_ci		u16 *pscsi_status);
33062306a36Sopenharmony_cistatic void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
33162306a36Sopenharmony_ci		u16 *pscsi_status);
33262306a36Sopenharmony_cistatic void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
33362306a36Sopenharmony_ci		u16 *pscsi_status);
33462306a36Sopenharmony_cistatic void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
33562306a36Sopenharmony_ci		u16 *pscsi_status);
33662306a36Sopenharmony_cistatic void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
33762306a36Sopenharmony_ci		u16 *pscsi_status);
33862306a36Sopenharmony_cistatic void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
33962306a36Sopenharmony_ci		u16 *pscsi_status);
34062306a36Sopenharmony_cistatic void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
34162306a36Sopenharmony_ci		u16 *pscsi_status);
34262306a36Sopenharmony_cistatic void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
34362306a36Sopenharmony_ci		u16 *pscsi_status);
34462306a36Sopenharmony_cistatic void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
34562306a36Sopenharmony_ci		u16 *pscsi_status);
34662306a36Sopenharmony_cistatic void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
34762306a36Sopenharmony_ci		u16 *pscsi_status);
34862306a36Sopenharmony_cistatic void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
34962306a36Sopenharmony_ci		u16 *pscsi_status);
35062306a36Sopenharmony_cistatic void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
35162306a36Sopenharmony_ci		u16 *pscsi_status);
35262306a36Sopenharmony_cistatic void nop0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
35362306a36Sopenharmony_ci		u16 *pscsi_status);
35462306a36Sopenharmony_cistatic void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
35562306a36Sopenharmony_ci		u16 *pscsi_status);
35662306a36Sopenharmony_cistatic void set_basic_config(struct AdapterCtlBlk *acb);
35762306a36Sopenharmony_cistatic void cleanup_after_transfer(struct AdapterCtlBlk *acb,
35862306a36Sopenharmony_ci		struct ScsiReqBlk *srb);
35962306a36Sopenharmony_cistatic void reset_scsi_bus(struct AdapterCtlBlk *acb);
36062306a36Sopenharmony_cistatic void data_io_transfer(struct AdapterCtlBlk *acb,
36162306a36Sopenharmony_ci		struct ScsiReqBlk *srb, u16 io_dir);
36262306a36Sopenharmony_cistatic void disconnect(struct AdapterCtlBlk *acb);
36362306a36Sopenharmony_cistatic void reselect(struct AdapterCtlBlk *acb);
36462306a36Sopenharmony_cistatic u8 start_scsi(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
36562306a36Sopenharmony_ci		struct ScsiReqBlk *srb);
36662306a36Sopenharmony_cistatic inline void enable_msgout_abort(struct AdapterCtlBlk *acb,
36762306a36Sopenharmony_ci		struct ScsiReqBlk *srb);
36862306a36Sopenharmony_cistatic void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
36962306a36Sopenharmony_ci		struct ScsiReqBlk *srb);
37062306a36Sopenharmony_cistatic void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_code,
37162306a36Sopenharmony_ci		struct scsi_cmnd *cmd, u8 force);
37262306a36Sopenharmony_cistatic void scsi_reset_detect(struct AdapterCtlBlk *acb);
37362306a36Sopenharmony_cistatic void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb);
37462306a36Sopenharmony_cistatic void pci_unmap_srb_sense(struct AdapterCtlBlk *acb,
37562306a36Sopenharmony_ci		struct ScsiReqBlk *srb);
37662306a36Sopenharmony_cistatic void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
37762306a36Sopenharmony_ci		struct ScsiReqBlk *srb);
37862306a36Sopenharmony_cistatic void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
37962306a36Sopenharmony_ci		struct ScsiReqBlk *srb);
38062306a36Sopenharmony_cistatic void set_xfer_rate(struct AdapterCtlBlk *acb,
38162306a36Sopenharmony_ci		struct DeviceCtlBlk *dcb);
38262306a36Sopenharmony_cistatic void waiting_timeout(struct timer_list *t);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci/*---------------------------------------------------------------------------
38662306a36Sopenharmony_ci                                 Static Data
38762306a36Sopenharmony_ci ---------------------------------------------------------------------------*/
38862306a36Sopenharmony_cistatic u16 current_sync_offset = 0;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_cistatic void *dc395x_scsi_phase0[] = {
39162306a36Sopenharmony_ci	data_out_phase0,/* phase:0 */
39262306a36Sopenharmony_ci	data_in_phase0,	/* phase:1 */
39362306a36Sopenharmony_ci	command_phase0,	/* phase:2 */
39462306a36Sopenharmony_ci	status_phase0,	/* phase:3 */
39562306a36Sopenharmony_ci	nop0,		/* phase:4 PH_BUS_FREE .. initial phase */
39662306a36Sopenharmony_ci	nop0,		/* phase:5 PH_BUS_FREE .. initial phase */
39762306a36Sopenharmony_ci	msgout_phase0,	/* phase:6 */
39862306a36Sopenharmony_ci	msgin_phase0,	/* phase:7 */
39962306a36Sopenharmony_ci};
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_cistatic void *dc395x_scsi_phase1[] = {
40262306a36Sopenharmony_ci	data_out_phase1,/* phase:0 */
40362306a36Sopenharmony_ci	data_in_phase1,	/* phase:1 */
40462306a36Sopenharmony_ci	command_phase1,	/* phase:2 */
40562306a36Sopenharmony_ci	status_phase1,	/* phase:3 */
40662306a36Sopenharmony_ci	nop1,		/* phase:4 PH_BUS_FREE .. initial phase */
40762306a36Sopenharmony_ci	nop1,		/* phase:5 PH_BUS_FREE .. initial phase */
40862306a36Sopenharmony_ci	msgout_phase1,	/* phase:6 */
40962306a36Sopenharmony_ci	msgin_phase1,	/* phase:7 */
41062306a36Sopenharmony_ci};
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci/*
41362306a36Sopenharmony_ci *Fast20:	000	 50ns, 20.0 MHz
41462306a36Sopenharmony_ci *		001	 75ns, 13.3 MHz
41562306a36Sopenharmony_ci *		010	100ns, 10.0 MHz
41662306a36Sopenharmony_ci *		011	125ns,  8.0 MHz
41762306a36Sopenharmony_ci *		100	150ns,  6.6 MHz
41862306a36Sopenharmony_ci *		101	175ns,  5.7 MHz
41962306a36Sopenharmony_ci *		110	200ns,  5.0 MHz
42062306a36Sopenharmony_ci *		111	250ns,  4.0 MHz
42162306a36Sopenharmony_ci *
42262306a36Sopenharmony_ci *Fast40(LVDS):	000	 25ns, 40.0 MHz
42362306a36Sopenharmony_ci *		001	 50ns, 20.0 MHz
42462306a36Sopenharmony_ci *		010	 75ns, 13.3 MHz
42562306a36Sopenharmony_ci *		011	100ns, 10.0 MHz
42662306a36Sopenharmony_ci *		100	125ns,  8.0 MHz
42762306a36Sopenharmony_ci *		101	150ns,  6.6 MHz
42862306a36Sopenharmony_ci *		110	175ns,  5.7 MHz
42962306a36Sopenharmony_ci *		111	200ns,  5.0 MHz
43062306a36Sopenharmony_ci */
43162306a36Sopenharmony_ci/*static u8	clock_period[] = {12,19,25,31,37,44,50,62};*/
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci/* real period:48ns,76ns,100ns,124ns,148ns,176ns,200ns,248ns */
43462306a36Sopenharmony_cistatic u8 clock_period[] = { 12, 18, 25, 31, 37, 43, 50, 62 };
43562306a36Sopenharmony_cistatic u16 clock_speed[] = { 200, 133, 100, 80, 67, 58, 50, 40 };
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci/*---------------------------------------------------------------------------
43962306a36Sopenharmony_ci                                Configuration
44062306a36Sopenharmony_ci  ---------------------------------------------------------------------------*/
44162306a36Sopenharmony_ci/*
44262306a36Sopenharmony_ci * Module/boot parameters currently effect *all* instances of the
44362306a36Sopenharmony_ci * card in the system.
44462306a36Sopenharmony_ci */
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci/*
44762306a36Sopenharmony_ci * Command line parameters are stored in a structure below.
44862306a36Sopenharmony_ci * These are the index's into the structure for the various
44962306a36Sopenharmony_ci * command line options.
45062306a36Sopenharmony_ci */
45162306a36Sopenharmony_ci#define CFG_ADAPTER_ID		0
45262306a36Sopenharmony_ci#define CFG_MAX_SPEED		1
45362306a36Sopenharmony_ci#define CFG_DEV_MODE		2
45462306a36Sopenharmony_ci#define CFG_ADAPTER_MODE	3
45562306a36Sopenharmony_ci#define CFG_TAGS		4
45662306a36Sopenharmony_ci#define CFG_RESET_DELAY		5
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci#define CFG_NUM			6	/* number of configuration items */
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci/*
46262306a36Sopenharmony_ci * Value used to indicate that a command line override
46362306a36Sopenharmony_ci * hasn't been used to modify the value.
46462306a36Sopenharmony_ci */
46562306a36Sopenharmony_ci#define CFG_PARAM_UNSET -1
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci/*
46962306a36Sopenharmony_ci * Hold command line parameters.
47062306a36Sopenharmony_ci */
47162306a36Sopenharmony_cistruct ParameterData {
47262306a36Sopenharmony_ci	int value;		/* value of this setting */
47362306a36Sopenharmony_ci	int min;		/* minimum value */
47462306a36Sopenharmony_ci	int max;		/* maximum value */
47562306a36Sopenharmony_ci	int def;		/* default value */
47662306a36Sopenharmony_ci	int safe;		/* safe value */
47762306a36Sopenharmony_ci};
47862306a36Sopenharmony_cistatic struct ParameterData cfg_data[] = {
47962306a36Sopenharmony_ci	{ /* adapter id */
48062306a36Sopenharmony_ci		CFG_PARAM_UNSET,
48162306a36Sopenharmony_ci		0,
48262306a36Sopenharmony_ci		15,
48362306a36Sopenharmony_ci		7,
48462306a36Sopenharmony_ci		7
48562306a36Sopenharmony_ci	},
48662306a36Sopenharmony_ci	{ /* max speed */
48762306a36Sopenharmony_ci		CFG_PARAM_UNSET,
48862306a36Sopenharmony_ci		  0,
48962306a36Sopenharmony_ci		  7,
49062306a36Sopenharmony_ci		  1,	/* 13.3Mhz */
49162306a36Sopenharmony_ci		  4,	/*  6.7Hmz */
49262306a36Sopenharmony_ci	},
49362306a36Sopenharmony_ci	{ /* dev mode */
49462306a36Sopenharmony_ci		CFG_PARAM_UNSET,
49562306a36Sopenharmony_ci		0,
49662306a36Sopenharmony_ci		0x3f,
49762306a36Sopenharmony_ci		NTC_DO_PARITY_CHK | NTC_DO_DISCONNECT | NTC_DO_SYNC_NEGO |
49862306a36Sopenharmony_ci			NTC_DO_WIDE_NEGO | NTC_DO_TAG_QUEUEING |
49962306a36Sopenharmony_ci			NTC_DO_SEND_START,
50062306a36Sopenharmony_ci		NTC_DO_PARITY_CHK | NTC_DO_SEND_START
50162306a36Sopenharmony_ci	},
50262306a36Sopenharmony_ci	{ /* adapter mode */
50362306a36Sopenharmony_ci		CFG_PARAM_UNSET,
50462306a36Sopenharmony_ci		0,
50562306a36Sopenharmony_ci		0x2f,
50662306a36Sopenharmony_ci		NAC_SCANLUN |
50762306a36Sopenharmony_ci		NAC_GT2DRIVES | NAC_GREATER_1G | NAC_POWERON_SCSI_RESET
50862306a36Sopenharmony_ci			/*| NAC_ACTIVE_NEG*/,
50962306a36Sopenharmony_ci		NAC_GT2DRIVES | NAC_GREATER_1G | NAC_POWERON_SCSI_RESET | 0x08
51062306a36Sopenharmony_ci	},
51162306a36Sopenharmony_ci	{ /* tags */
51262306a36Sopenharmony_ci		CFG_PARAM_UNSET,
51362306a36Sopenharmony_ci		0,
51462306a36Sopenharmony_ci		5,
51562306a36Sopenharmony_ci		3,	/* 16 tags (??) */
51662306a36Sopenharmony_ci		2,
51762306a36Sopenharmony_ci	},
51862306a36Sopenharmony_ci	{ /* reset delay */
51962306a36Sopenharmony_ci		CFG_PARAM_UNSET,
52062306a36Sopenharmony_ci		0,
52162306a36Sopenharmony_ci		180,
52262306a36Sopenharmony_ci		1,	/* 1 second */
52362306a36Sopenharmony_ci		10,	/* 10 seconds */
52462306a36Sopenharmony_ci	}
52562306a36Sopenharmony_ci};
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci/*
52962306a36Sopenharmony_ci * Safe settings. If set to zero the BIOS/default values with
53062306a36Sopenharmony_ci * command line overrides will be used. If set to 1 then safe and
53162306a36Sopenharmony_ci * slow settings will be used.
53262306a36Sopenharmony_ci */
53362306a36Sopenharmony_cistatic bool use_safe_settings = 0;
53462306a36Sopenharmony_cimodule_param_named(safe, use_safe_settings, bool, 0);
53562306a36Sopenharmony_ciMODULE_PARM_DESC(safe, "Use safe and slow settings only. Default: false");
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_cimodule_param_named(adapter_id, cfg_data[CFG_ADAPTER_ID].value, int, 0);
53962306a36Sopenharmony_ciMODULE_PARM_DESC(adapter_id, "Adapter SCSI ID. Default 7 (0-15)");
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cimodule_param_named(max_speed, cfg_data[CFG_MAX_SPEED].value, int, 0);
54262306a36Sopenharmony_ciMODULE_PARM_DESC(max_speed, "Maximum bus speed. Default 1 (0-7) Speeds: 0=20, 1=13.3, 2=10, 3=8, 4=6.7, 5=5.8, 6=5, 7=4 Mhz");
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_cimodule_param_named(dev_mode, cfg_data[CFG_DEV_MODE].value, int, 0);
54562306a36Sopenharmony_ciMODULE_PARM_DESC(dev_mode, "Device mode.");
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_cimodule_param_named(adapter_mode, cfg_data[CFG_ADAPTER_MODE].value, int, 0);
54862306a36Sopenharmony_ciMODULE_PARM_DESC(adapter_mode, "Adapter mode.");
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_cimodule_param_named(tags, cfg_data[CFG_TAGS].value, int, 0);
55162306a36Sopenharmony_ciMODULE_PARM_DESC(tags, "Number of tags (1<<x). Default 3 (0-5)");
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_cimodule_param_named(reset_delay, cfg_data[CFG_RESET_DELAY].value, int, 0);
55462306a36Sopenharmony_ciMODULE_PARM_DESC(reset_delay, "Reset delay in seconds. Default 1 (0-180)");
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci/**
55862306a36Sopenharmony_ci * set_safe_settings - if the use_safe_settings option is set then
55962306a36Sopenharmony_ci * set all values to the safe and slow values.
56062306a36Sopenharmony_ci **/
56162306a36Sopenharmony_cistatic void set_safe_settings(void)
56262306a36Sopenharmony_ci{
56362306a36Sopenharmony_ci	if (use_safe_settings)
56462306a36Sopenharmony_ci	{
56562306a36Sopenharmony_ci		int i;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci		dprintkl(KERN_INFO, "Using safe settings.\n");
56862306a36Sopenharmony_ci		for (i = 0; i < CFG_NUM; i++)
56962306a36Sopenharmony_ci		{
57062306a36Sopenharmony_ci			cfg_data[i].value = cfg_data[i].safe;
57162306a36Sopenharmony_ci		}
57262306a36Sopenharmony_ci	}
57362306a36Sopenharmony_ci}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci/**
57762306a36Sopenharmony_ci * fix_settings - reset any boot parameters which are out of range
57862306a36Sopenharmony_ci * back to the default values.
57962306a36Sopenharmony_ci **/
58062306a36Sopenharmony_cistatic void fix_settings(void)
58162306a36Sopenharmony_ci{
58262306a36Sopenharmony_ci	int i;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	dprintkdbg(DBG_1,
58562306a36Sopenharmony_ci		"setup: AdapterId=%08x MaxSpeed=%08x DevMode=%08x "
58662306a36Sopenharmony_ci		"AdapterMode=%08x Tags=%08x ResetDelay=%08x\n",
58762306a36Sopenharmony_ci		cfg_data[CFG_ADAPTER_ID].value,
58862306a36Sopenharmony_ci		cfg_data[CFG_MAX_SPEED].value,
58962306a36Sopenharmony_ci		cfg_data[CFG_DEV_MODE].value,
59062306a36Sopenharmony_ci		cfg_data[CFG_ADAPTER_MODE].value,
59162306a36Sopenharmony_ci		cfg_data[CFG_TAGS].value,
59262306a36Sopenharmony_ci		cfg_data[CFG_RESET_DELAY].value);
59362306a36Sopenharmony_ci	for (i = 0; i < CFG_NUM; i++)
59462306a36Sopenharmony_ci	{
59562306a36Sopenharmony_ci		if (cfg_data[i].value < cfg_data[i].min
59662306a36Sopenharmony_ci		    || cfg_data[i].value > cfg_data[i].max)
59762306a36Sopenharmony_ci			cfg_data[i].value = cfg_data[i].def;
59862306a36Sopenharmony_ci	}
59962306a36Sopenharmony_ci}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci/*
60462306a36Sopenharmony_ci * Mapping from the eeprom delay index value (index into this array)
60562306a36Sopenharmony_ci * to the number of actual seconds that the delay should be for.
60662306a36Sopenharmony_ci */
60762306a36Sopenharmony_cistatic char eeprom_index_to_delay_map[] =
60862306a36Sopenharmony_ci	{ 1, 3, 5, 10, 16, 30, 60, 120 };
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci/**
61262306a36Sopenharmony_ci * eeprom_index_to_delay - Take the eeprom delay setting and convert it
61362306a36Sopenharmony_ci * into a number of seconds.
61462306a36Sopenharmony_ci *
61562306a36Sopenharmony_ci * @eeprom: The eeprom structure in which we find the delay index to map.
61662306a36Sopenharmony_ci **/
61762306a36Sopenharmony_cistatic void eeprom_index_to_delay(struct NvRamType *eeprom)
61862306a36Sopenharmony_ci{
61962306a36Sopenharmony_ci	eeprom->delay_time = eeprom_index_to_delay_map[eeprom->delay_time];
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci/**
62462306a36Sopenharmony_ci * delay_to_eeprom_index - Take a delay in seconds and return the
62562306a36Sopenharmony_ci * closest eeprom index which will delay for at least that amount of
62662306a36Sopenharmony_ci * seconds.
62762306a36Sopenharmony_ci *
62862306a36Sopenharmony_ci * @delay: The delay, in seconds, to find the eeprom index for.
62962306a36Sopenharmony_ci **/
63062306a36Sopenharmony_cistatic int delay_to_eeprom_index(int delay)
63162306a36Sopenharmony_ci{
63262306a36Sopenharmony_ci	u8 idx = 0;
63362306a36Sopenharmony_ci	while (idx < 7 && eeprom_index_to_delay_map[idx] < delay)
63462306a36Sopenharmony_ci		idx++;
63562306a36Sopenharmony_ci	return idx;
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci/**
64062306a36Sopenharmony_ci * eeprom_override - Override the eeprom settings, in the provided
64162306a36Sopenharmony_ci * eeprom structure, with values that have been set on the command
64262306a36Sopenharmony_ci * line.
64362306a36Sopenharmony_ci *
64462306a36Sopenharmony_ci * @eeprom: The eeprom data to override with command line options.
64562306a36Sopenharmony_ci **/
64662306a36Sopenharmony_cistatic void eeprom_override(struct NvRamType *eeprom)
64762306a36Sopenharmony_ci{
64862306a36Sopenharmony_ci	u8 id;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	/* Adapter Settings */
65162306a36Sopenharmony_ci	if (cfg_data[CFG_ADAPTER_ID].value != CFG_PARAM_UNSET)
65262306a36Sopenharmony_ci		eeprom->scsi_id = (u8)cfg_data[CFG_ADAPTER_ID].value;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	if (cfg_data[CFG_ADAPTER_MODE].value != CFG_PARAM_UNSET)
65562306a36Sopenharmony_ci		eeprom->channel_cfg = (u8)cfg_data[CFG_ADAPTER_MODE].value;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	if (cfg_data[CFG_RESET_DELAY].value != CFG_PARAM_UNSET)
65862306a36Sopenharmony_ci		eeprom->delay_time = delay_to_eeprom_index(
65962306a36Sopenharmony_ci					cfg_data[CFG_RESET_DELAY].value);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	if (cfg_data[CFG_TAGS].value != CFG_PARAM_UNSET)
66262306a36Sopenharmony_ci		eeprom->max_tag = (u8)cfg_data[CFG_TAGS].value;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	/* Device Settings */
66562306a36Sopenharmony_ci	for (id = 0; id < DC395x_MAX_SCSI_ID; id++) {
66662306a36Sopenharmony_ci		if (cfg_data[CFG_DEV_MODE].value != CFG_PARAM_UNSET)
66762306a36Sopenharmony_ci			eeprom->target[id].cfg0 =
66862306a36Sopenharmony_ci				(u8)cfg_data[CFG_DEV_MODE].value;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci		if (cfg_data[CFG_MAX_SPEED].value != CFG_PARAM_UNSET)
67162306a36Sopenharmony_ci			eeprom->target[id].period =
67262306a36Sopenharmony_ci				(u8)cfg_data[CFG_MAX_SPEED].value;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	}
67562306a36Sopenharmony_ci}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci/*---------------------------------------------------------------------------
67962306a36Sopenharmony_ci ---------------------------------------------------------------------------*/
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_cistatic unsigned int list_size(struct list_head *head)
68262306a36Sopenharmony_ci{
68362306a36Sopenharmony_ci	unsigned int count = 0;
68462306a36Sopenharmony_ci	struct list_head *pos;
68562306a36Sopenharmony_ci	list_for_each(pos, head)
68662306a36Sopenharmony_ci		count++;
68762306a36Sopenharmony_ci	return count;
68862306a36Sopenharmony_ci}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_cistatic struct DeviceCtlBlk *dcb_get_next(struct list_head *head,
69262306a36Sopenharmony_ci		struct DeviceCtlBlk *pos)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	int use_next = 0;
69562306a36Sopenharmony_ci	struct DeviceCtlBlk* next = NULL;
69662306a36Sopenharmony_ci	struct DeviceCtlBlk* i;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	if (list_empty(head))
69962306a36Sopenharmony_ci		return NULL;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	/* find supplied dcb and then select the next one */
70262306a36Sopenharmony_ci	list_for_each_entry(i, head, list)
70362306a36Sopenharmony_ci		if (use_next) {
70462306a36Sopenharmony_ci			next = i;
70562306a36Sopenharmony_ci			break;
70662306a36Sopenharmony_ci		} else if (i == pos) {
70762306a36Sopenharmony_ci			use_next = 1;
70862306a36Sopenharmony_ci		}
70962306a36Sopenharmony_ci	/* if no next one take the head one (ie, wraparound) */
71062306a36Sopenharmony_ci	if (!next)
71162306a36Sopenharmony_ci        	list_for_each_entry(i, head, list) {
71262306a36Sopenharmony_ci        		next = i;
71362306a36Sopenharmony_ci        		break;
71462306a36Sopenharmony_ci        	}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	return next;
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_cistatic void free_tag(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
72162306a36Sopenharmony_ci{
72262306a36Sopenharmony_ci	if (srb->tag_number < 255) {
72362306a36Sopenharmony_ci		dcb->tag_mask &= ~(1 << srb->tag_number);	/* free tag mask */
72462306a36Sopenharmony_ci		srb->tag_number = 255;
72562306a36Sopenharmony_ci	}
72662306a36Sopenharmony_ci}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci/* Find cmd in SRB list */
73062306a36Sopenharmony_cistatic inline struct ScsiReqBlk *find_cmd(struct scsi_cmnd *cmd,
73162306a36Sopenharmony_ci		struct list_head *head)
73262306a36Sopenharmony_ci{
73362306a36Sopenharmony_ci	struct ScsiReqBlk *i;
73462306a36Sopenharmony_ci	list_for_each_entry(i, head, list)
73562306a36Sopenharmony_ci		if (i->cmd == cmd)
73662306a36Sopenharmony_ci			return i;
73762306a36Sopenharmony_ci	return NULL;
73862306a36Sopenharmony_ci}
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci/* Sets the timer to wake us up */
74162306a36Sopenharmony_cistatic void waiting_set_timer(struct AdapterCtlBlk *acb, unsigned long to)
74262306a36Sopenharmony_ci{
74362306a36Sopenharmony_ci	if (timer_pending(&acb->waiting_timer))
74462306a36Sopenharmony_ci		return;
74562306a36Sopenharmony_ci	if (time_before(jiffies + to, acb->last_reset - HZ / 2))
74662306a36Sopenharmony_ci		acb->waiting_timer.expires =
74762306a36Sopenharmony_ci		    acb->last_reset - HZ / 2 + 1;
74862306a36Sopenharmony_ci	else
74962306a36Sopenharmony_ci		acb->waiting_timer.expires = jiffies + to + 1;
75062306a36Sopenharmony_ci	add_timer(&acb->waiting_timer);
75162306a36Sopenharmony_ci}
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci/* Send the next command from the waiting list to the bus */
75562306a36Sopenharmony_cistatic void waiting_process_next(struct AdapterCtlBlk *acb)
75662306a36Sopenharmony_ci{
75762306a36Sopenharmony_ci	struct DeviceCtlBlk *start = NULL;
75862306a36Sopenharmony_ci	struct DeviceCtlBlk *pos;
75962306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb;
76062306a36Sopenharmony_ci	struct ScsiReqBlk *srb;
76162306a36Sopenharmony_ci	struct list_head *dcb_list_head = &acb->dcb_list;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	if (acb->active_dcb
76462306a36Sopenharmony_ci	    || (acb->acb_flag & (RESET_DETECT + RESET_DONE + RESET_DEV)))
76562306a36Sopenharmony_ci		return;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	if (timer_pending(&acb->waiting_timer))
76862306a36Sopenharmony_ci		del_timer(&acb->waiting_timer);
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	if (list_empty(dcb_list_head))
77162306a36Sopenharmony_ci		return;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	/*
77462306a36Sopenharmony_ci	 * Find the starting dcb. Need to find it again in the list
77562306a36Sopenharmony_ci	 * since the list may have changed since we set the ptr to it
77662306a36Sopenharmony_ci	 */
77762306a36Sopenharmony_ci	list_for_each_entry(dcb, dcb_list_head, list)
77862306a36Sopenharmony_ci		if (dcb == acb->dcb_run_robin) {
77962306a36Sopenharmony_ci			start = dcb;
78062306a36Sopenharmony_ci			break;
78162306a36Sopenharmony_ci		}
78262306a36Sopenharmony_ci	if (!start) {
78362306a36Sopenharmony_ci		/* This can happen! */
78462306a36Sopenharmony_ci		start = list_entry(dcb_list_head->next, typeof(*start), list);
78562306a36Sopenharmony_ci		acb->dcb_run_robin = start;
78662306a36Sopenharmony_ci	}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	/*
79062306a36Sopenharmony_ci	 * Loop over the dcb, but we start somewhere (potentially) in
79162306a36Sopenharmony_ci	 * the middle of the loop so we need to manully do this.
79262306a36Sopenharmony_ci	 */
79362306a36Sopenharmony_ci	pos = start;
79462306a36Sopenharmony_ci	do {
79562306a36Sopenharmony_ci		struct list_head *waiting_list_head = &pos->srb_waiting_list;
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci		/* Make sure, the next another device gets scheduled ... */
79862306a36Sopenharmony_ci		acb->dcb_run_robin = dcb_get_next(dcb_list_head,
79962306a36Sopenharmony_ci						  acb->dcb_run_robin);
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci		if (list_empty(waiting_list_head) ||
80262306a36Sopenharmony_ci		    pos->max_command <= list_size(&pos->srb_going_list)) {
80362306a36Sopenharmony_ci			/* move to next dcb */
80462306a36Sopenharmony_ci			pos = dcb_get_next(dcb_list_head, pos);
80562306a36Sopenharmony_ci		} else {
80662306a36Sopenharmony_ci			srb = list_entry(waiting_list_head->next,
80762306a36Sopenharmony_ci					 struct ScsiReqBlk, list);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci			/* Try to send to the bus */
81062306a36Sopenharmony_ci			if (!start_scsi(acb, pos, srb))
81162306a36Sopenharmony_ci				list_move(&srb->list, &pos->srb_going_list);
81262306a36Sopenharmony_ci			else
81362306a36Sopenharmony_ci				waiting_set_timer(acb, HZ/50);
81462306a36Sopenharmony_ci			break;
81562306a36Sopenharmony_ci		}
81662306a36Sopenharmony_ci	} while (pos != start);
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci/* Wake up waiting queue */
82162306a36Sopenharmony_cistatic void waiting_timeout(struct timer_list *t)
82262306a36Sopenharmony_ci{
82362306a36Sopenharmony_ci	unsigned long flags;
82462306a36Sopenharmony_ci	struct AdapterCtlBlk *acb = from_timer(acb, t, waiting_timer);
82562306a36Sopenharmony_ci	dprintkdbg(DBG_1,
82662306a36Sopenharmony_ci		"waiting_timeout: Queue woken up by timer. acb=%p\n", acb);
82762306a36Sopenharmony_ci	DC395x_LOCK_IO(acb->scsi_host, flags);
82862306a36Sopenharmony_ci	waiting_process_next(acb);
82962306a36Sopenharmony_ci	DC395x_UNLOCK_IO(acb->scsi_host, flags);
83062306a36Sopenharmony_ci}
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci/* Get the DCB for a given ID/LUN combination */
83462306a36Sopenharmony_cistatic struct DeviceCtlBlk *find_dcb(struct AdapterCtlBlk *acb, u8 id, u8 lun)
83562306a36Sopenharmony_ci{
83662306a36Sopenharmony_ci	return acb->children[id][lun];
83762306a36Sopenharmony_ci}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci/* Send SCSI Request Block (srb) to adapter (acb) */
84162306a36Sopenharmony_cistatic void send_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
84262306a36Sopenharmony_ci{
84362306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb = srb->dcb;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	if (dcb->max_command <= list_size(&dcb->srb_going_list) ||
84662306a36Sopenharmony_ci	    acb->active_dcb ||
84762306a36Sopenharmony_ci	    (acb->acb_flag & (RESET_DETECT + RESET_DONE + RESET_DEV))) {
84862306a36Sopenharmony_ci		list_add_tail(&srb->list, &dcb->srb_waiting_list);
84962306a36Sopenharmony_ci		waiting_process_next(acb);
85062306a36Sopenharmony_ci		return;
85162306a36Sopenharmony_ci	}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	if (!start_scsi(acb, dcb, srb)) {
85462306a36Sopenharmony_ci		list_add_tail(&srb->list, &dcb->srb_going_list);
85562306a36Sopenharmony_ci	} else {
85662306a36Sopenharmony_ci		list_add(&srb->list, &dcb->srb_waiting_list);
85762306a36Sopenharmony_ci		waiting_set_timer(acb, HZ / 50);
85862306a36Sopenharmony_ci	}
85962306a36Sopenharmony_ci}
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci/* Prepare SRB for being sent to Device DCB w/ command *cmd */
86262306a36Sopenharmony_cistatic void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
86362306a36Sopenharmony_ci		struct ScsiReqBlk *srb)
86462306a36Sopenharmony_ci{
86562306a36Sopenharmony_ci	int nseg;
86662306a36Sopenharmony_ci	enum dma_data_direction dir = cmd->sc_data_direction;
86762306a36Sopenharmony_ci	dprintkdbg(DBG_0, "build_srb: (0x%p) <%02i-%i>\n",
86862306a36Sopenharmony_ci		cmd, dcb->target_id, dcb->target_lun);
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	srb->dcb = dcb;
87162306a36Sopenharmony_ci	srb->cmd = cmd;
87262306a36Sopenharmony_ci	srb->sg_count = 0;
87362306a36Sopenharmony_ci	srb->total_xfer_length = 0;
87462306a36Sopenharmony_ci	srb->sg_bus_addr = 0;
87562306a36Sopenharmony_ci	srb->sg_index = 0;
87662306a36Sopenharmony_ci	srb->adapter_status = 0;
87762306a36Sopenharmony_ci	srb->target_status = 0;
87862306a36Sopenharmony_ci	srb->msg_count = 0;
87962306a36Sopenharmony_ci	srb->status = 0;
88062306a36Sopenharmony_ci	srb->flag = 0;
88162306a36Sopenharmony_ci	srb->state = 0;
88262306a36Sopenharmony_ci	srb->retry_count = 0;
88362306a36Sopenharmony_ci	srb->tag_number = TAG_NONE;
88462306a36Sopenharmony_ci	srb->scsi_phase = PH_BUS_FREE;	/* initial phase */
88562306a36Sopenharmony_ci	srb->end_message = 0;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	nseg = scsi_dma_map(cmd);
88862306a36Sopenharmony_ci	BUG_ON(nseg < 0);
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	if (dir == DMA_NONE || !nseg) {
89162306a36Sopenharmony_ci		dprintkdbg(DBG_0,
89262306a36Sopenharmony_ci			"build_srb: [0] len=%d buf=%p use_sg=%d !MAP=%08x\n",
89362306a36Sopenharmony_ci			   cmd->bufflen, scsi_sglist(cmd), scsi_sg_count(cmd),
89462306a36Sopenharmony_ci			   srb->segment_x[0].address);
89562306a36Sopenharmony_ci	} else {
89662306a36Sopenharmony_ci		int i;
89762306a36Sopenharmony_ci		u32 reqlen = scsi_bufflen(cmd);
89862306a36Sopenharmony_ci		struct scatterlist *sg;
89962306a36Sopenharmony_ci		struct SGentry *sgp = srb->segment_x;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci		srb->sg_count = nseg;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci		dprintkdbg(DBG_0,
90462306a36Sopenharmony_ci			   "build_srb: [n] len=%d buf=%p use_sg=%d segs=%d\n",
90562306a36Sopenharmony_ci			   reqlen, scsi_sglist(cmd), scsi_sg_count(cmd),
90662306a36Sopenharmony_ci			   srb->sg_count);
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci		scsi_for_each_sg(cmd, sg, srb->sg_count, i) {
90962306a36Sopenharmony_ci			u32 busaddr = (u32)sg_dma_address(sg);
91062306a36Sopenharmony_ci			u32 seglen = (u32)sg->length;
91162306a36Sopenharmony_ci			sgp[i].address = busaddr;
91262306a36Sopenharmony_ci			sgp[i].length = seglen;
91362306a36Sopenharmony_ci			srb->total_xfer_length += seglen;
91462306a36Sopenharmony_ci		}
91562306a36Sopenharmony_ci		sgp += srb->sg_count - 1;
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci		/*
91862306a36Sopenharmony_ci		 * adjust last page if too big as it is allocated
91962306a36Sopenharmony_ci		 * on even page boundaries
92062306a36Sopenharmony_ci		 */
92162306a36Sopenharmony_ci		if (srb->total_xfer_length > reqlen) {
92262306a36Sopenharmony_ci			sgp->length -= (srb->total_xfer_length - reqlen);
92362306a36Sopenharmony_ci			srb->total_xfer_length = reqlen;
92462306a36Sopenharmony_ci		}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci		/* Fixup for WIDE padding - make sure length is even */
92762306a36Sopenharmony_ci		if (dcb->sync_period & WIDE_SYNC &&
92862306a36Sopenharmony_ci		    srb->total_xfer_length % 2) {
92962306a36Sopenharmony_ci			srb->total_xfer_length++;
93062306a36Sopenharmony_ci			sgp->length++;
93162306a36Sopenharmony_ci		}
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci		srb->sg_bus_addr = dma_map_single(&dcb->acb->dev->dev,
93462306a36Sopenharmony_ci				srb->segment_x, SEGMENTX_LEN, DMA_TO_DEVICE);
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci		dprintkdbg(DBG_SG, "build_srb: [n] map sg %p->%08x(%05x)\n",
93762306a36Sopenharmony_ci			srb->segment_x, srb->sg_bus_addr, SEGMENTX_LEN);
93862306a36Sopenharmony_ci	}
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	srb->request_length = srb->total_xfer_length;
94162306a36Sopenharmony_ci}
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci/**
94562306a36Sopenharmony_ci * dc395x_queue_command_lck - queue scsi command passed from the mid
94662306a36Sopenharmony_ci * layer, invoke 'done' on completion
94762306a36Sopenharmony_ci *
94862306a36Sopenharmony_ci * @cmd: pointer to scsi command object
94962306a36Sopenharmony_ci *
95062306a36Sopenharmony_ci * Returns 1 if the adapter (host) is busy, else returns 0. One
95162306a36Sopenharmony_ci * reason for an adapter to be busy is that the number
95262306a36Sopenharmony_ci * of outstanding queued commands is already equal to
95362306a36Sopenharmony_ci * struct Scsi_Host::can_queue .
95462306a36Sopenharmony_ci *
95562306a36Sopenharmony_ci * Required: if struct Scsi_Host::can_queue is ever non-zero
95662306a36Sopenharmony_ci *           then this function is required.
95762306a36Sopenharmony_ci *
95862306a36Sopenharmony_ci * Locks: struct Scsi_Host::host_lock held on entry (with "irqsave")
95962306a36Sopenharmony_ci *        and is expected to be held on return.
96062306a36Sopenharmony_ci *
96162306a36Sopenharmony_ci */
96262306a36Sopenharmony_cistatic int dc395x_queue_command_lck(struct scsi_cmnd *cmd)
96362306a36Sopenharmony_ci{
96462306a36Sopenharmony_ci	void (*done)(struct scsi_cmnd *) = scsi_done;
96562306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb;
96662306a36Sopenharmony_ci	struct ScsiReqBlk *srb;
96762306a36Sopenharmony_ci	struct AdapterCtlBlk *acb =
96862306a36Sopenharmony_ci	    (struct AdapterCtlBlk *)cmd->device->host->hostdata;
96962306a36Sopenharmony_ci	dprintkdbg(DBG_0, "queue_command: (0x%p) <%02i-%i> cmnd=0x%02x\n",
97062306a36Sopenharmony_ci		cmd, cmd->device->id, (u8)cmd->device->lun, cmd->cmnd[0]);
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	/* Assume BAD_TARGET; will be cleared later */
97362306a36Sopenharmony_ci	set_host_byte(cmd, DID_BAD_TARGET);
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	/* ignore invalid targets */
97662306a36Sopenharmony_ci	if (cmd->device->id >= acb->scsi_host->max_id ||
97762306a36Sopenharmony_ci	    cmd->device->lun >= acb->scsi_host->max_lun ||
97862306a36Sopenharmony_ci	    cmd->device->lun >31) {
97962306a36Sopenharmony_ci		goto complete;
98062306a36Sopenharmony_ci	}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	/* does the specified lun on the specified device exist */
98362306a36Sopenharmony_ci	if (!(acb->dcb_map[cmd->device->id] & (1 << cmd->device->lun))) {
98462306a36Sopenharmony_ci		dprintkl(KERN_INFO, "queue_command: Ignore target <%02i-%i>\n",
98562306a36Sopenharmony_ci			cmd->device->id, (u8)cmd->device->lun);
98662306a36Sopenharmony_ci		goto complete;
98762306a36Sopenharmony_ci	}
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	/* do we have a DCB for the device */
99062306a36Sopenharmony_ci	dcb = find_dcb(acb, cmd->device->id, cmd->device->lun);
99162306a36Sopenharmony_ci	if (!dcb) {
99262306a36Sopenharmony_ci		/* should never happen */
99362306a36Sopenharmony_ci		dprintkl(KERN_ERR, "queue_command: No such device <%02i-%i>",
99462306a36Sopenharmony_ci			cmd->device->id, (u8)cmd->device->lun);
99562306a36Sopenharmony_ci		goto complete;
99662306a36Sopenharmony_ci	}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	set_host_byte(cmd, DID_OK);
99962306a36Sopenharmony_ci	set_status_byte(cmd, SAM_STAT_GOOD);
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	srb = list_first_entry_or_null(&acb->srb_free_list,
100262306a36Sopenharmony_ci			struct ScsiReqBlk, list);
100362306a36Sopenharmony_ci	if (!srb) {
100462306a36Sopenharmony_ci		/*
100562306a36Sopenharmony_ci		 * Return 1 since we are unable to queue this command at this
100662306a36Sopenharmony_ci		 * point in time.
100762306a36Sopenharmony_ci		 */
100862306a36Sopenharmony_ci		dprintkdbg(DBG_0, "queue_command: No free srb's\n");
100962306a36Sopenharmony_ci		return 1;
101062306a36Sopenharmony_ci	}
101162306a36Sopenharmony_ci	list_del(&srb->list);
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	build_srb(cmd, dcb, srb);
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	if (!list_empty(&dcb->srb_waiting_list)) {
101662306a36Sopenharmony_ci		/* append to waiting queue */
101762306a36Sopenharmony_ci		list_add_tail(&srb->list, &dcb->srb_waiting_list);
101862306a36Sopenharmony_ci		waiting_process_next(acb);
101962306a36Sopenharmony_ci	} else {
102062306a36Sopenharmony_ci		/* process immediately */
102162306a36Sopenharmony_ci		send_srb(acb, srb);
102262306a36Sopenharmony_ci	}
102362306a36Sopenharmony_ci	dprintkdbg(DBG_1, "queue_command: (0x%p) done\n", cmd);
102462306a36Sopenharmony_ci	return 0;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_cicomplete:
102762306a36Sopenharmony_ci	/*
102862306a36Sopenharmony_ci	 * Complete the command immediatey, and then return 0 to
102962306a36Sopenharmony_ci	 * indicate that we have handled the command. This is usually
103062306a36Sopenharmony_ci	 * done when the commad is for things like non existent
103162306a36Sopenharmony_ci	 * devices.
103262306a36Sopenharmony_ci	 */
103362306a36Sopenharmony_ci	done(cmd);
103462306a36Sopenharmony_ci	return 0;
103562306a36Sopenharmony_ci}
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_cistatic DEF_SCSI_QCMD(dc395x_queue_command)
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_cistatic void dump_register_info(struct AdapterCtlBlk *acb,
104062306a36Sopenharmony_ci		struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
104162306a36Sopenharmony_ci{
104262306a36Sopenharmony_ci	u16 pstat;
104362306a36Sopenharmony_ci	struct pci_dev *dev = acb->dev;
104462306a36Sopenharmony_ci	pci_read_config_word(dev, PCI_STATUS, &pstat);
104562306a36Sopenharmony_ci	if (!dcb)
104662306a36Sopenharmony_ci		dcb = acb->active_dcb;
104762306a36Sopenharmony_ci	if (!srb && dcb)
104862306a36Sopenharmony_ci		srb = dcb->active_srb;
104962306a36Sopenharmony_ci	if (srb) {
105062306a36Sopenharmony_ci		if (!srb->cmd)
105162306a36Sopenharmony_ci			dprintkl(KERN_INFO, "dump: srb=%p cmd=%p OOOPS!\n",
105262306a36Sopenharmony_ci				srb, srb->cmd);
105362306a36Sopenharmony_ci		else
105462306a36Sopenharmony_ci			dprintkl(KERN_INFO, "dump: srb=%p cmd=%p "
105562306a36Sopenharmony_ci				 "cmnd=0x%02x <%02i-%i>\n",
105662306a36Sopenharmony_ci				srb, srb->cmd,
105762306a36Sopenharmony_ci				srb->cmd->cmnd[0], srb->cmd->device->id,
105862306a36Sopenharmony_ci				(u8)srb->cmd->device->lun);
105962306a36Sopenharmony_ci		printk("  sglist=%p cnt=%i idx=%i len=%zu\n",
106062306a36Sopenharmony_ci		       srb->segment_x, srb->sg_count, srb->sg_index,
106162306a36Sopenharmony_ci		       srb->total_xfer_length);
106262306a36Sopenharmony_ci		printk("  state=0x%04x status=0x%02x phase=0x%02x (%sconn.)\n",
106362306a36Sopenharmony_ci		       srb->state, srb->status, srb->scsi_phase,
106462306a36Sopenharmony_ci		       (acb->active_dcb) ? "" : "not");
106562306a36Sopenharmony_ci	}
106662306a36Sopenharmony_ci	dprintkl(KERN_INFO, "dump: SCSI{status=0x%04x fifocnt=0x%02x "
106762306a36Sopenharmony_ci		"signals=0x%02x irqstat=0x%02x sync=0x%02x target=0x%02x "
106862306a36Sopenharmony_ci		"rselid=0x%02x ctr=0x%08x irqen=0x%02x config=0x%04x "
106962306a36Sopenharmony_ci		"config2=0x%02x cmd=0x%02x selto=0x%02x}\n",
107062306a36Sopenharmony_ci		DC395x_read16(acb, TRM_S1040_SCSI_STATUS),
107162306a36Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
107262306a36Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL),
107362306a36Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS),
107462306a36Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_SYNC),
107562306a36Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_TARGETID),
107662306a36Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_IDMSG),
107762306a36Sopenharmony_ci		DC395x_read32(acb, TRM_S1040_SCSI_COUNTER),
107862306a36Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_INTEN),
107962306a36Sopenharmony_ci		DC395x_read16(acb, TRM_S1040_SCSI_CONFIG0),
108062306a36Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_CONFIG2),
108162306a36Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_COMMAND),
108262306a36Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_TIMEOUT));
108362306a36Sopenharmony_ci	dprintkl(KERN_INFO, "dump: DMA{cmd=0x%04x fifocnt=0x%02x fstat=0x%02x "
108462306a36Sopenharmony_ci		"irqstat=0x%02x irqen=0x%02x cfg=0x%04x tctr=0x%08x "
108562306a36Sopenharmony_ci		"ctctr=0x%08x addr=0x%08x:0x%08x}\n",
108662306a36Sopenharmony_ci		DC395x_read16(acb, TRM_S1040_DMA_COMMAND),
108762306a36Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
108862306a36Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
108962306a36Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_DMA_STATUS),
109062306a36Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_DMA_INTEN),
109162306a36Sopenharmony_ci		DC395x_read16(acb, TRM_S1040_DMA_CONFIG),
109262306a36Sopenharmony_ci		DC395x_read32(acb, TRM_S1040_DMA_XCNT),
109362306a36Sopenharmony_ci		DC395x_read32(acb, TRM_S1040_DMA_CXCNT),
109462306a36Sopenharmony_ci		DC395x_read32(acb, TRM_S1040_DMA_XHIGHADDR),
109562306a36Sopenharmony_ci		DC395x_read32(acb, TRM_S1040_DMA_XLOWADDR));
109662306a36Sopenharmony_ci	dprintkl(KERN_INFO, "dump: gen{gctrl=0x%02x gstat=0x%02x gtmr=0x%02x} "
109762306a36Sopenharmony_ci		"pci{status=0x%04x}\n",
109862306a36Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_GEN_CONTROL),
109962306a36Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_GEN_STATUS),
110062306a36Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_GEN_TIMER),
110162306a36Sopenharmony_ci		pstat);
110262306a36Sopenharmony_ci}
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_cistatic inline void clear_fifo(struct AdapterCtlBlk *acb, char *txt)
110662306a36Sopenharmony_ci{
110762306a36Sopenharmony_ci#if debug_enabled(DBG_FIFO)
110862306a36Sopenharmony_ci	u8 lines = DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL);
110962306a36Sopenharmony_ci	u8 fifocnt = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT);
111062306a36Sopenharmony_ci	if (!(fifocnt & 0x40))
111162306a36Sopenharmony_ci		dprintkdbg(DBG_FIFO,
111262306a36Sopenharmony_ci			"clear_fifo: (%i bytes) on phase %02x in %s\n",
111362306a36Sopenharmony_ci			fifocnt & 0x3f, lines, txt);
111462306a36Sopenharmony_ci#endif
111562306a36Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRFIFO);
111662306a36Sopenharmony_ci}
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_cistatic void reset_dev_param(struct AdapterCtlBlk *acb)
112062306a36Sopenharmony_ci{
112162306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb;
112262306a36Sopenharmony_ci	struct NvRamType *eeprom = &acb->eeprom;
112362306a36Sopenharmony_ci	dprintkdbg(DBG_0, "reset_dev_param: acb=%p\n", acb);
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	list_for_each_entry(dcb, &acb->dcb_list, list) {
112662306a36Sopenharmony_ci		u8 period_index;
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci		dcb->sync_mode &= ~(SYNC_NEGO_DONE + WIDE_NEGO_DONE);
112962306a36Sopenharmony_ci		dcb->sync_period = 0;
113062306a36Sopenharmony_ci		dcb->sync_offset = 0;
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci		dcb->dev_mode = eeprom->target[dcb->target_id].cfg0;
113362306a36Sopenharmony_ci		period_index = eeprom->target[dcb->target_id].period & 0x07;
113462306a36Sopenharmony_ci		dcb->min_nego_period = clock_period[period_index];
113562306a36Sopenharmony_ci		if (!(dcb->dev_mode & NTC_DO_WIDE_NEGO)
113662306a36Sopenharmony_ci		    || !(acb->config & HCC_WIDE_CARD))
113762306a36Sopenharmony_ci			dcb->sync_mode &= ~WIDE_NEGO_ENABLE;
113862306a36Sopenharmony_ci	}
113962306a36Sopenharmony_ci}
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci/*
114362306a36Sopenharmony_ci * perform a hard reset on the SCSI bus
114462306a36Sopenharmony_ci * @cmd - some command for this host (for fetching hooks)
114562306a36Sopenharmony_ci * Returns: SUCCESS (0x2002) on success, else FAILED (0x2003).
114662306a36Sopenharmony_ci */
114762306a36Sopenharmony_cistatic int __dc395x_eh_bus_reset(struct scsi_cmnd *cmd)
114862306a36Sopenharmony_ci{
114962306a36Sopenharmony_ci	struct AdapterCtlBlk *acb =
115062306a36Sopenharmony_ci		(struct AdapterCtlBlk *)cmd->device->host->hostdata;
115162306a36Sopenharmony_ci	dprintkl(KERN_INFO,
115262306a36Sopenharmony_ci		"eh_bus_reset: (0%p) target=<%02i-%i> cmd=%p\n",
115362306a36Sopenharmony_ci		cmd, cmd->device->id, (u8)cmd->device->lun, cmd);
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	if (timer_pending(&acb->waiting_timer))
115662306a36Sopenharmony_ci		del_timer(&acb->waiting_timer);
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	/*
115962306a36Sopenharmony_ci	 * disable interrupt
116062306a36Sopenharmony_ci	 */
116162306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_DMA_INTEN, 0x00);
116262306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_INTEN, 0x00);
116362306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_CONTROL, DO_RSTMODULE);
116462306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_DMA_CONTROL, DMARESETMODULE);
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	reset_scsi_bus(acb);
116762306a36Sopenharmony_ci	udelay(500);
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	/* We may be in serious trouble. Wait some seconds */
117062306a36Sopenharmony_ci	acb->last_reset =
117162306a36Sopenharmony_ci	    jiffies + 3 * HZ / 2 +
117262306a36Sopenharmony_ci	    HZ * acb->eeprom.delay_time;
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	/*
117562306a36Sopenharmony_ci	 * re-enable interrupt
117662306a36Sopenharmony_ci	 */
117762306a36Sopenharmony_ci	/* Clear SCSI FIFO          */
117862306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO);
117962306a36Sopenharmony_ci	clear_fifo(acb, "eh_bus_reset");
118062306a36Sopenharmony_ci	/* Delete pending IRQ */
118162306a36Sopenharmony_ci	DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS);
118262306a36Sopenharmony_ci	set_basic_config(acb);
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	reset_dev_param(acb);
118562306a36Sopenharmony_ci	doing_srb_done(acb, DID_RESET, cmd, 0);
118662306a36Sopenharmony_ci	acb->active_dcb = NULL;
118762306a36Sopenharmony_ci	acb->acb_flag = 0;	/* RESET_DETECT, RESET_DONE ,RESET_DEV */
118862306a36Sopenharmony_ci	waiting_process_next(acb);
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	return SUCCESS;
119162306a36Sopenharmony_ci}
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_cistatic int dc395x_eh_bus_reset(struct scsi_cmnd *cmd)
119462306a36Sopenharmony_ci{
119562306a36Sopenharmony_ci	int rc;
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	spin_lock_irq(cmd->device->host->host_lock);
119862306a36Sopenharmony_ci	rc = __dc395x_eh_bus_reset(cmd);
119962306a36Sopenharmony_ci	spin_unlock_irq(cmd->device->host->host_lock);
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	return rc;
120262306a36Sopenharmony_ci}
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci/*
120562306a36Sopenharmony_ci * abort an errant SCSI command
120662306a36Sopenharmony_ci * @cmd - command to be aborted
120762306a36Sopenharmony_ci * Returns: SUCCESS (0x2002) on success, else FAILED (0x2003).
120862306a36Sopenharmony_ci */
120962306a36Sopenharmony_cistatic int dc395x_eh_abort(struct scsi_cmnd *cmd)
121062306a36Sopenharmony_ci{
121162306a36Sopenharmony_ci	/*
121262306a36Sopenharmony_ci	 * Look into our command queues: If it has not been sent already,
121362306a36Sopenharmony_ci	 * we remove it and return success. Otherwise fail.
121462306a36Sopenharmony_ci	 */
121562306a36Sopenharmony_ci	struct AdapterCtlBlk *acb =
121662306a36Sopenharmony_ci	    (struct AdapterCtlBlk *)cmd->device->host->hostdata;
121762306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb;
121862306a36Sopenharmony_ci	struct ScsiReqBlk *srb;
121962306a36Sopenharmony_ci	dprintkl(KERN_INFO, "eh_abort: (0x%p) target=<%02i-%i> cmd=%p\n",
122062306a36Sopenharmony_ci		cmd, cmd->device->id, (u8)cmd->device->lun, cmd);
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	dcb = find_dcb(acb, cmd->device->id, cmd->device->lun);
122362306a36Sopenharmony_ci	if (!dcb) {
122462306a36Sopenharmony_ci		dprintkl(KERN_DEBUG, "eh_abort: No such device\n");
122562306a36Sopenharmony_ci		return FAILED;
122662306a36Sopenharmony_ci	}
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	srb = find_cmd(cmd, &dcb->srb_waiting_list);
122962306a36Sopenharmony_ci	if (srb) {
123062306a36Sopenharmony_ci		list_del(&srb->list);
123162306a36Sopenharmony_ci		pci_unmap_srb_sense(acb, srb);
123262306a36Sopenharmony_ci		pci_unmap_srb(acb, srb);
123362306a36Sopenharmony_ci		free_tag(dcb, srb);
123462306a36Sopenharmony_ci		list_add_tail(&srb->list, &acb->srb_free_list);
123562306a36Sopenharmony_ci		dprintkl(KERN_DEBUG, "eh_abort: Command was waiting\n");
123662306a36Sopenharmony_ci		set_host_byte(cmd, DID_ABORT);
123762306a36Sopenharmony_ci		return SUCCESS;
123862306a36Sopenharmony_ci	}
123962306a36Sopenharmony_ci	srb = find_cmd(cmd, &dcb->srb_going_list);
124062306a36Sopenharmony_ci	if (srb) {
124162306a36Sopenharmony_ci		dprintkl(KERN_DEBUG, "eh_abort: Command in progress\n");
124262306a36Sopenharmony_ci		/* XXX: Should abort the command here */
124362306a36Sopenharmony_ci	} else {
124462306a36Sopenharmony_ci		dprintkl(KERN_DEBUG, "eh_abort: Command not found\n");
124562306a36Sopenharmony_ci	}
124662306a36Sopenharmony_ci	return FAILED;
124762306a36Sopenharmony_ci}
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci/* SDTR */
125162306a36Sopenharmony_cistatic void build_sdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
125262306a36Sopenharmony_ci		struct ScsiReqBlk *srb)
125362306a36Sopenharmony_ci{
125462306a36Sopenharmony_ci	u8 *ptr = srb->msgout_buf + srb->msg_count;
125562306a36Sopenharmony_ci	if (srb->msg_count > 1) {
125662306a36Sopenharmony_ci		dprintkl(KERN_INFO,
125762306a36Sopenharmony_ci			"build_sdtr: msgout_buf BUSY (%i: %02x %02x)\n",
125862306a36Sopenharmony_ci			srb->msg_count, srb->msgout_buf[0],
125962306a36Sopenharmony_ci			srb->msgout_buf[1]);
126062306a36Sopenharmony_ci		return;
126162306a36Sopenharmony_ci	}
126262306a36Sopenharmony_ci	if (!(dcb->dev_mode & NTC_DO_SYNC_NEGO)) {
126362306a36Sopenharmony_ci		dcb->sync_offset = 0;
126462306a36Sopenharmony_ci		dcb->min_nego_period = 200 >> 2;
126562306a36Sopenharmony_ci	} else if (dcb->sync_offset == 0)
126662306a36Sopenharmony_ci		dcb->sync_offset = SYNC_NEGO_OFFSET;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	srb->msg_count += spi_populate_sync_msg(ptr, dcb->min_nego_period,
126962306a36Sopenharmony_ci						dcb->sync_offset);
127062306a36Sopenharmony_ci	srb->state |= SRB_DO_SYNC_NEGO;
127162306a36Sopenharmony_ci}
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci/* WDTR */
127562306a36Sopenharmony_cistatic void build_wdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
127662306a36Sopenharmony_ci		struct ScsiReqBlk *srb)
127762306a36Sopenharmony_ci{
127862306a36Sopenharmony_ci	u8 wide = ((dcb->dev_mode & NTC_DO_WIDE_NEGO) &
127962306a36Sopenharmony_ci		   (acb->config & HCC_WIDE_CARD)) ? 1 : 0;
128062306a36Sopenharmony_ci	u8 *ptr = srb->msgout_buf + srb->msg_count;
128162306a36Sopenharmony_ci	if (srb->msg_count > 1) {
128262306a36Sopenharmony_ci		dprintkl(KERN_INFO,
128362306a36Sopenharmony_ci			"build_wdtr: msgout_buf BUSY (%i: %02x %02x)\n",
128462306a36Sopenharmony_ci			srb->msg_count, srb->msgout_buf[0],
128562306a36Sopenharmony_ci			srb->msgout_buf[1]);
128662306a36Sopenharmony_ci		return;
128762306a36Sopenharmony_ci	}
128862306a36Sopenharmony_ci	srb->msg_count += spi_populate_width_msg(ptr, wide);
128962306a36Sopenharmony_ci	srb->state |= SRB_DO_WIDE_NEGO;
129062306a36Sopenharmony_ci}
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci#if 0
129462306a36Sopenharmony_ci/* Timer to work around chip flaw: When selecting and the bus is
129562306a36Sopenharmony_ci * busy, we sometimes miss a Selection timeout IRQ */
129662306a36Sopenharmony_civoid selection_timeout_missed(unsigned long ptr);
129762306a36Sopenharmony_ci/* Sets the timer to wake us up */
129862306a36Sopenharmony_cistatic void selto_timer(struct AdapterCtlBlk *acb)
129962306a36Sopenharmony_ci{
130062306a36Sopenharmony_ci	if (timer_pending(&acb->selto_timer))
130162306a36Sopenharmony_ci		return;
130262306a36Sopenharmony_ci	acb->selto_timer.function = selection_timeout_missed;
130362306a36Sopenharmony_ci	acb->selto_timer.data = (unsigned long) acb;
130462306a36Sopenharmony_ci	if (time_before
130562306a36Sopenharmony_ci	    (jiffies + HZ, acb->last_reset + HZ / 2))
130662306a36Sopenharmony_ci		acb->selto_timer.expires =
130762306a36Sopenharmony_ci		    acb->last_reset + HZ / 2 + 1;
130862306a36Sopenharmony_ci	else
130962306a36Sopenharmony_ci		acb->selto_timer.expires = jiffies + HZ + 1;
131062306a36Sopenharmony_ci	add_timer(&acb->selto_timer);
131162306a36Sopenharmony_ci}
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_civoid selection_timeout_missed(unsigned long ptr)
131562306a36Sopenharmony_ci{
131662306a36Sopenharmony_ci	unsigned long flags;
131762306a36Sopenharmony_ci	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)ptr;
131862306a36Sopenharmony_ci	struct ScsiReqBlk *srb;
131962306a36Sopenharmony_ci	dprintkl(KERN_DEBUG, "Chip forgot to produce SelTO IRQ!\n");
132062306a36Sopenharmony_ci	if (!acb->active_dcb || !acb->active_dcb->active_srb) {
132162306a36Sopenharmony_ci		dprintkl(KERN_DEBUG, "... but no cmd pending? Oops!\n");
132262306a36Sopenharmony_ci		return;
132362306a36Sopenharmony_ci	}
132462306a36Sopenharmony_ci	DC395x_LOCK_IO(acb->scsi_host, flags);
132562306a36Sopenharmony_ci	srb = acb->active_dcb->active_srb;
132662306a36Sopenharmony_ci	disconnect(acb);
132762306a36Sopenharmony_ci	DC395x_UNLOCK_IO(acb->scsi_host, flags);
132862306a36Sopenharmony_ci}
132962306a36Sopenharmony_ci#endif
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_cistatic u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
133362306a36Sopenharmony_ci		struct ScsiReqBlk* srb)
133462306a36Sopenharmony_ci{
133562306a36Sopenharmony_ci	u16 __maybe_unused s_stat2, return_code;
133662306a36Sopenharmony_ci	u8 s_stat, scsicommand, i, identify_message;
133762306a36Sopenharmony_ci	u8 *ptr;
133862306a36Sopenharmony_ci	dprintkdbg(DBG_0, "start_scsi: (0x%p) <%02i-%i> srb=%p\n",
133962306a36Sopenharmony_ci		dcb->target_id, dcb->target_lun, srb);
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	srb->tag_number = TAG_NONE;	/* acb->tag_max_num: had error read in eeprom */
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	s_stat = DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL);
134462306a36Sopenharmony_ci	s_stat2 = 0;
134562306a36Sopenharmony_ci	s_stat2 = DC395x_read16(acb, TRM_S1040_SCSI_STATUS);
134662306a36Sopenharmony_ci#if 1
134762306a36Sopenharmony_ci	if (s_stat & 0x20 /* s_stat2 & 0x02000 */ ) {
134862306a36Sopenharmony_ci		dprintkdbg(DBG_KG, "start_scsi: (0x%p) BUSY %02x %04x\n",
134962306a36Sopenharmony_ci			s_stat, s_stat2);
135062306a36Sopenharmony_ci		/*
135162306a36Sopenharmony_ci		 * Try anyway?
135262306a36Sopenharmony_ci		 *
135362306a36Sopenharmony_ci		 * We could, BUT: Sometimes the TRM_S1040 misses to produce a Selection
135462306a36Sopenharmony_ci		 * Timeout, a Disconnect or a Reselection IRQ, so we would be screwed!
135562306a36Sopenharmony_ci		 * (This is likely to be a bug in the hardware. Obviously, most people
135662306a36Sopenharmony_ci		 *  only have one initiator per SCSI bus.)
135762306a36Sopenharmony_ci		 * Instead let this fail and have the timer make sure the command is
135862306a36Sopenharmony_ci		 * tried again after a short time
135962306a36Sopenharmony_ci		 */
136062306a36Sopenharmony_ci		/*selto_timer (acb); */
136162306a36Sopenharmony_ci		return 1;
136262306a36Sopenharmony_ci	}
136362306a36Sopenharmony_ci#endif
136462306a36Sopenharmony_ci	if (acb->active_dcb) {
136562306a36Sopenharmony_ci		dprintkl(KERN_DEBUG, "start_scsi: (0x%p) Attempt to start a"
136662306a36Sopenharmony_ci			"command while another command (0x%p) is active.",
136762306a36Sopenharmony_ci			srb->cmd,
136862306a36Sopenharmony_ci			acb->active_dcb->active_srb ?
136962306a36Sopenharmony_ci			    acb->active_dcb->active_srb->cmd : 0);
137062306a36Sopenharmony_ci		return 1;
137162306a36Sopenharmony_ci	}
137262306a36Sopenharmony_ci	if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) {
137362306a36Sopenharmony_ci		dprintkdbg(DBG_KG, "start_scsi: (0x%p) Failed (busy)\n", srb->cmd);
137462306a36Sopenharmony_ci		return 1;
137562306a36Sopenharmony_ci	}
137662306a36Sopenharmony_ci	/* Allow starting of SCSI commands half a second before we allow the mid-level
137762306a36Sopenharmony_ci	 * to queue them again after a reset */
137862306a36Sopenharmony_ci	if (time_before(jiffies, acb->last_reset - HZ / 2)) {
137962306a36Sopenharmony_ci		dprintkdbg(DBG_KG, "start_scsi: Refuse cmds (reset wait)\n");
138062306a36Sopenharmony_ci		return 1;
138162306a36Sopenharmony_ci	}
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	/* Flush FIFO */
138462306a36Sopenharmony_ci	clear_fifo(acb, "start_scsi");
138562306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_HOSTID, acb->scsi_host->this_id);
138662306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id);
138762306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_SYNC, dcb->sync_period);
138862306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, dcb->sync_offset);
138962306a36Sopenharmony_ci	srb->scsi_phase = PH_BUS_FREE;	/* initial phase */
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	identify_message = dcb->identify_msg;
139262306a36Sopenharmony_ci	/*DC395x_TRM_write8(TRM_S1040_SCSI_IDMSG, identify_message); */
139362306a36Sopenharmony_ci	/* Don't allow disconnection for AUTO_REQSENSE: Cont.All.Cond.! */
139462306a36Sopenharmony_ci	if (srb->flag & AUTO_REQSENSE)
139562306a36Sopenharmony_ci		identify_message &= 0xBF;
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	if (((srb->cmd->cmnd[0] == INQUIRY)
139862306a36Sopenharmony_ci	     || (srb->cmd->cmnd[0] == REQUEST_SENSE)
139962306a36Sopenharmony_ci	     || (srb->flag & AUTO_REQSENSE))
140062306a36Sopenharmony_ci	    && (((dcb->sync_mode & WIDE_NEGO_ENABLE)
140162306a36Sopenharmony_ci		 && !(dcb->sync_mode & WIDE_NEGO_DONE))
140262306a36Sopenharmony_ci		|| ((dcb->sync_mode & SYNC_NEGO_ENABLE)
140362306a36Sopenharmony_ci		    && !(dcb->sync_mode & SYNC_NEGO_DONE)))
140462306a36Sopenharmony_ci	    && (dcb->target_lun == 0)) {
140562306a36Sopenharmony_ci		srb->msgout_buf[0] = identify_message;
140662306a36Sopenharmony_ci		srb->msg_count = 1;
140762306a36Sopenharmony_ci		scsicommand = SCMD_SEL_ATNSTOP;
140862306a36Sopenharmony_ci		srb->state = SRB_MSGOUT;
140962306a36Sopenharmony_ci#ifndef SYNC_FIRST
141062306a36Sopenharmony_ci		if (dcb->sync_mode & WIDE_NEGO_ENABLE
141162306a36Sopenharmony_ci		    && dcb->inquiry7 & SCSI_INQ_WBUS16) {
141262306a36Sopenharmony_ci			build_wdtr(acb, dcb, srb);
141362306a36Sopenharmony_ci			goto no_cmd;
141462306a36Sopenharmony_ci		}
141562306a36Sopenharmony_ci#endif
141662306a36Sopenharmony_ci		if (dcb->sync_mode & SYNC_NEGO_ENABLE
141762306a36Sopenharmony_ci		    && dcb->inquiry7 & SCSI_INQ_SYNC) {
141862306a36Sopenharmony_ci			build_sdtr(acb, dcb, srb);
141962306a36Sopenharmony_ci			goto no_cmd;
142062306a36Sopenharmony_ci		}
142162306a36Sopenharmony_ci		if (dcb->sync_mode & WIDE_NEGO_ENABLE
142262306a36Sopenharmony_ci		    && dcb->inquiry7 & SCSI_INQ_WBUS16) {
142362306a36Sopenharmony_ci			build_wdtr(acb, dcb, srb);
142462306a36Sopenharmony_ci			goto no_cmd;
142562306a36Sopenharmony_ci		}
142662306a36Sopenharmony_ci		srb->msg_count = 0;
142762306a36Sopenharmony_ci	}
142862306a36Sopenharmony_ci	/* Send identify message */
142962306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_FIFO, identify_message);
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	scsicommand = SCMD_SEL_ATN;
143262306a36Sopenharmony_ci	srb->state = SRB_START_;
143362306a36Sopenharmony_ci#ifndef DC395x_NO_TAGQ
143462306a36Sopenharmony_ci	if ((dcb->sync_mode & EN_TAG_QUEUEING)
143562306a36Sopenharmony_ci	    && (identify_message & 0xC0)) {
143662306a36Sopenharmony_ci		/* Send Tag message */
143762306a36Sopenharmony_ci		u32 tag_mask = 1;
143862306a36Sopenharmony_ci		u8 tag_number = 0;
143962306a36Sopenharmony_ci		while (tag_mask & dcb->tag_mask
144062306a36Sopenharmony_ci		       && tag_number < dcb->max_command) {
144162306a36Sopenharmony_ci			tag_mask = tag_mask << 1;
144262306a36Sopenharmony_ci			tag_number++;
144362306a36Sopenharmony_ci		}
144462306a36Sopenharmony_ci		if (tag_number >= dcb->max_command) {
144562306a36Sopenharmony_ci			dprintkl(KERN_WARNING, "start_scsi: (0x%p) "
144662306a36Sopenharmony_ci				"Out of tags target=<%02i-%i>)\n",
144762306a36Sopenharmony_ci				srb->cmd, srb->cmd->device->id,
144862306a36Sopenharmony_ci				(u8)srb->cmd->device->lun);
144962306a36Sopenharmony_ci			srb->state = SRB_READY;
145062306a36Sopenharmony_ci			DC395x_write16(acb, TRM_S1040_SCSI_CONTROL,
145162306a36Sopenharmony_ci				       DO_HWRESELECT);
145262306a36Sopenharmony_ci			return 1;
145362306a36Sopenharmony_ci		}
145462306a36Sopenharmony_ci		/* Send Tag id */
145562306a36Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, SIMPLE_QUEUE_TAG);
145662306a36Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, tag_number);
145762306a36Sopenharmony_ci		dcb->tag_mask |= tag_mask;
145862306a36Sopenharmony_ci		srb->tag_number = tag_number;
145962306a36Sopenharmony_ci		scsicommand = SCMD_SEL_ATN3;
146062306a36Sopenharmony_ci		srb->state = SRB_START_;
146162306a36Sopenharmony_ci	}
146262306a36Sopenharmony_ci#endif
146362306a36Sopenharmony_ci/*polling:*/
146462306a36Sopenharmony_ci	/* Send CDB ..command block ......... */
146562306a36Sopenharmony_ci	dprintkdbg(DBG_KG, "start_scsi: (0x%p) <%02i-%i> cmnd=0x%02x tag=%i\n",
146662306a36Sopenharmony_ci		srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun,
146762306a36Sopenharmony_ci		srb->cmd->cmnd[0], srb->tag_number);
146862306a36Sopenharmony_ci	if (srb->flag & AUTO_REQSENSE) {
146962306a36Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, REQUEST_SENSE);
147062306a36Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5));
147162306a36Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
147262306a36Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
147362306a36Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, SCSI_SENSE_BUFFERSIZE);
147462306a36Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
147562306a36Sopenharmony_ci	} else {
147662306a36Sopenharmony_ci		ptr = (u8 *)srb->cmd->cmnd;
147762306a36Sopenharmony_ci		for (i = 0; i < srb->cmd->cmd_len; i++)
147862306a36Sopenharmony_ci			DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr++);
147962306a36Sopenharmony_ci	}
148062306a36Sopenharmony_ci      no_cmd:
148162306a36Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL,
148262306a36Sopenharmony_ci		       DO_HWRESELECT | DO_DATALATCH);
148362306a36Sopenharmony_ci	if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) {
148462306a36Sopenharmony_ci		/*
148562306a36Sopenharmony_ci		 * If start_scsi return 1:
148662306a36Sopenharmony_ci		 * we caught an interrupt (must be reset or reselection ... )
148762306a36Sopenharmony_ci		 * : Let's process it first!
148862306a36Sopenharmony_ci		 */
148962306a36Sopenharmony_ci		dprintkdbg(DBG_0, "start_scsi: (0x%p) <%02i-%i> Failed - busy\n",
149062306a36Sopenharmony_ci			srb->cmd, dcb->target_id, dcb->target_lun);
149162306a36Sopenharmony_ci		srb->state = SRB_READY;
149262306a36Sopenharmony_ci		free_tag(dcb, srb);
149362306a36Sopenharmony_ci		srb->msg_count = 0;
149462306a36Sopenharmony_ci		return_code = 1;
149562306a36Sopenharmony_ci		/* This IRQ should NOT get lost, as we did not acknowledge it */
149662306a36Sopenharmony_ci	} else {
149762306a36Sopenharmony_ci		/*
149862306a36Sopenharmony_ci		 * If start_scsi returns 0:
149962306a36Sopenharmony_ci		 * we know that the SCSI processor is free
150062306a36Sopenharmony_ci		 */
150162306a36Sopenharmony_ci		srb->scsi_phase = PH_BUS_FREE;	/* initial phase */
150262306a36Sopenharmony_ci		dcb->active_srb = srb;
150362306a36Sopenharmony_ci		acb->active_dcb = dcb;
150462306a36Sopenharmony_ci		return_code = 0;
150562306a36Sopenharmony_ci		/* it's important for atn stop */
150662306a36Sopenharmony_ci		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL,
150762306a36Sopenharmony_ci			       DO_DATALATCH | DO_HWRESELECT);
150862306a36Sopenharmony_ci		/* SCSI command */
150962306a36Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, scsicommand);
151062306a36Sopenharmony_ci	}
151162306a36Sopenharmony_ci	return return_code;
151262306a36Sopenharmony_ci}
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci#define DC395x_ENABLE_MSGOUT \
151662306a36Sopenharmony_ci DC395x_write16 (acb, TRM_S1040_SCSI_CONTROL, DO_SETATN); \
151762306a36Sopenharmony_ci srb->state |= SRB_MSGOUT
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci/* abort command */
152162306a36Sopenharmony_cistatic inline void enable_msgout_abort(struct AdapterCtlBlk *acb,
152262306a36Sopenharmony_ci		struct ScsiReqBlk *srb)
152362306a36Sopenharmony_ci{
152462306a36Sopenharmony_ci	srb->msgout_buf[0] = ABORT;
152562306a36Sopenharmony_ci	srb->msg_count = 1;
152662306a36Sopenharmony_ci	DC395x_ENABLE_MSGOUT;
152762306a36Sopenharmony_ci	srb->state &= ~SRB_MSGIN;
152862306a36Sopenharmony_ci	srb->state |= SRB_MSGOUT;
152962306a36Sopenharmony_ci}
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci/**
153362306a36Sopenharmony_ci * dc395x_handle_interrupt - Handle an interrupt that has been confirmed to
153462306a36Sopenharmony_ci *                           have been triggered for this card.
153562306a36Sopenharmony_ci *
153662306a36Sopenharmony_ci * @acb:	 a pointer to the adpter control block
153762306a36Sopenharmony_ci * @scsi_status: the status return when we checked the card
153862306a36Sopenharmony_ci **/
153962306a36Sopenharmony_cistatic void dc395x_handle_interrupt(struct AdapterCtlBlk *acb,
154062306a36Sopenharmony_ci		u16 scsi_status)
154162306a36Sopenharmony_ci{
154262306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb;
154362306a36Sopenharmony_ci	struct ScsiReqBlk *srb;
154462306a36Sopenharmony_ci	u16 phase;
154562306a36Sopenharmony_ci	u8 scsi_intstatus;
154662306a36Sopenharmony_ci	unsigned long flags;
154762306a36Sopenharmony_ci	void (*dc395x_statev)(struct AdapterCtlBlk *, struct ScsiReqBlk *,
154862306a36Sopenharmony_ci			      u16 *);
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	DC395x_LOCK_IO(acb->scsi_host, flags);
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	/* This acknowledges the IRQ */
155362306a36Sopenharmony_ci	scsi_intstatus = DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS);
155462306a36Sopenharmony_ci	if ((scsi_status & 0x2007) == 0x2002)
155562306a36Sopenharmony_ci		dprintkl(KERN_DEBUG,
155662306a36Sopenharmony_ci			"COP after COP completed? %04x\n", scsi_status);
155762306a36Sopenharmony_ci	if (debug_enabled(DBG_KG)) {
155862306a36Sopenharmony_ci		if (scsi_intstatus & INT_SELTIMEOUT)
155962306a36Sopenharmony_ci			dprintkdbg(DBG_KG, "handle_interrupt: Selection timeout\n");
156062306a36Sopenharmony_ci	}
156162306a36Sopenharmony_ci	/*dprintkl(KERN_DEBUG, "handle_interrupt: intstatus = 0x%02x ", scsi_intstatus); */
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	if (timer_pending(&acb->selto_timer))
156462306a36Sopenharmony_ci		del_timer(&acb->selto_timer);
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	if (scsi_intstatus & (INT_SELTIMEOUT | INT_DISCONNECT)) {
156762306a36Sopenharmony_ci		disconnect(acb);	/* bus free interrupt  */
156862306a36Sopenharmony_ci		goto out_unlock;
156962306a36Sopenharmony_ci	}
157062306a36Sopenharmony_ci	if (scsi_intstatus & INT_RESELECTED) {
157162306a36Sopenharmony_ci		reselect(acb);
157262306a36Sopenharmony_ci		goto out_unlock;
157362306a36Sopenharmony_ci	}
157462306a36Sopenharmony_ci	if (scsi_intstatus & INT_SELECT) {
157562306a36Sopenharmony_ci		dprintkl(KERN_INFO, "Host does not support target mode!\n");
157662306a36Sopenharmony_ci		goto out_unlock;
157762306a36Sopenharmony_ci	}
157862306a36Sopenharmony_ci	if (scsi_intstatus & INT_SCSIRESET) {
157962306a36Sopenharmony_ci		scsi_reset_detect(acb);
158062306a36Sopenharmony_ci		goto out_unlock;
158162306a36Sopenharmony_ci	}
158262306a36Sopenharmony_ci	if (scsi_intstatus & (INT_BUSSERVICE | INT_CMDDONE)) {
158362306a36Sopenharmony_ci		dcb = acb->active_dcb;
158462306a36Sopenharmony_ci		if (!dcb) {
158562306a36Sopenharmony_ci			dprintkl(KERN_DEBUG,
158662306a36Sopenharmony_ci				"Oops: BusService (%04x %02x) w/o ActiveDCB!\n",
158762306a36Sopenharmony_ci				scsi_status, scsi_intstatus);
158862306a36Sopenharmony_ci			goto out_unlock;
158962306a36Sopenharmony_ci		}
159062306a36Sopenharmony_ci		srb = dcb->active_srb;
159162306a36Sopenharmony_ci		if (dcb->flag & ABORT_DEV_) {
159262306a36Sopenharmony_ci			dprintkdbg(DBG_0, "MsgOut Abort Device.....\n");
159362306a36Sopenharmony_ci			enable_msgout_abort(acb, srb);
159462306a36Sopenharmony_ci		}
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci		/* software sequential machine */
159762306a36Sopenharmony_ci		phase = (u16)srb->scsi_phase;
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci		/*
160062306a36Sopenharmony_ci		 * 62037 or 62137
160162306a36Sopenharmony_ci		 * call  dc395x_scsi_phase0[]... "phase entry"
160262306a36Sopenharmony_ci		 * handle every phase before start transfer
160362306a36Sopenharmony_ci		 */
160462306a36Sopenharmony_ci		/* data_out_phase0,	phase:0 */
160562306a36Sopenharmony_ci		/* data_in_phase0,	phase:1 */
160662306a36Sopenharmony_ci		/* command_phase0,	phase:2 */
160762306a36Sopenharmony_ci		/* status_phase0,	phase:3 */
160862306a36Sopenharmony_ci		/* nop0,		phase:4 PH_BUS_FREE .. initial phase */
160962306a36Sopenharmony_ci		/* nop0,		phase:5 PH_BUS_FREE .. initial phase */
161062306a36Sopenharmony_ci		/* msgout_phase0,	phase:6 */
161162306a36Sopenharmony_ci		/* msgin_phase0,	phase:7 */
161262306a36Sopenharmony_ci		dc395x_statev = dc395x_scsi_phase0[phase];
161362306a36Sopenharmony_ci		dc395x_statev(acb, srb, &scsi_status);
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci		/*
161662306a36Sopenharmony_ci		 * if there were any exception occurred scsi_status
161762306a36Sopenharmony_ci		 * will be modify to bus free phase new scsi_status
161862306a36Sopenharmony_ci		 * transfer out from ... previous dc395x_statev
161962306a36Sopenharmony_ci		 */
162062306a36Sopenharmony_ci		srb->scsi_phase = scsi_status & PHASEMASK;
162162306a36Sopenharmony_ci		phase = (u16)scsi_status & PHASEMASK;
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci		/*
162462306a36Sopenharmony_ci		 * call  dc395x_scsi_phase1[]... "phase entry" handle
162562306a36Sopenharmony_ci		 * every phase to do transfer
162662306a36Sopenharmony_ci		 */
162762306a36Sopenharmony_ci		/* data_out_phase1,	phase:0 */
162862306a36Sopenharmony_ci		/* data_in_phase1,	phase:1 */
162962306a36Sopenharmony_ci		/* command_phase1,	phase:2 */
163062306a36Sopenharmony_ci		/* status_phase1,	phase:3 */
163162306a36Sopenharmony_ci		/* nop1,		phase:4 PH_BUS_FREE .. initial phase */
163262306a36Sopenharmony_ci		/* nop1,		phase:5 PH_BUS_FREE .. initial phase */
163362306a36Sopenharmony_ci		/* msgout_phase1,	phase:6 */
163462306a36Sopenharmony_ci		/* msgin_phase1,	phase:7 */
163562306a36Sopenharmony_ci		dc395x_statev = dc395x_scsi_phase1[phase];
163662306a36Sopenharmony_ci		dc395x_statev(acb, srb, &scsi_status);
163762306a36Sopenharmony_ci	}
163862306a36Sopenharmony_ci      out_unlock:
163962306a36Sopenharmony_ci	DC395x_UNLOCK_IO(acb->scsi_host, flags);
164062306a36Sopenharmony_ci}
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_cistatic irqreturn_t dc395x_interrupt(int irq, void *dev_id)
164462306a36Sopenharmony_ci{
164562306a36Sopenharmony_ci	struct AdapterCtlBlk *acb = dev_id;
164662306a36Sopenharmony_ci	u16 scsi_status;
164762306a36Sopenharmony_ci	u8 dma_status;
164862306a36Sopenharmony_ci	irqreturn_t handled = IRQ_NONE;
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	/*
165162306a36Sopenharmony_ci	 * Check for pending interrupt
165262306a36Sopenharmony_ci	 */
165362306a36Sopenharmony_ci	scsi_status = DC395x_read16(acb, TRM_S1040_SCSI_STATUS);
165462306a36Sopenharmony_ci	dma_status = DC395x_read8(acb, TRM_S1040_DMA_STATUS);
165562306a36Sopenharmony_ci	if (scsi_status & SCSIINTERRUPT) {
165662306a36Sopenharmony_ci		/* interrupt pending - let's process it! */
165762306a36Sopenharmony_ci		dc395x_handle_interrupt(acb, scsi_status);
165862306a36Sopenharmony_ci		handled = IRQ_HANDLED;
165962306a36Sopenharmony_ci	}
166062306a36Sopenharmony_ci	else if (dma_status & 0x20) {
166162306a36Sopenharmony_ci		/* Error from the DMA engine */
166262306a36Sopenharmony_ci		dprintkl(KERN_INFO, "Interrupt from DMA engine: 0x%02x!\n", dma_status);
166362306a36Sopenharmony_ci#if 0
166462306a36Sopenharmony_ci		dprintkl(KERN_INFO, "This means DMA error! Try to handle ...\n");
166562306a36Sopenharmony_ci		if (acb->active_dcb) {
166662306a36Sopenharmony_ci			acb->active_dcb-> flag |= ABORT_DEV_;
166762306a36Sopenharmony_ci			if (acb->active_dcb->active_srb)
166862306a36Sopenharmony_ci				enable_msgout_abort(acb, acb->active_dcb->active_srb);
166962306a36Sopenharmony_ci		}
167062306a36Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_DMA_CONTROL, ABORTXFER | CLRXFIFO);
167162306a36Sopenharmony_ci#else
167262306a36Sopenharmony_ci		dprintkl(KERN_INFO, "Ignoring DMA error (probably a bad thing) ...\n");
167362306a36Sopenharmony_ci		acb = NULL;
167462306a36Sopenharmony_ci#endif
167562306a36Sopenharmony_ci		handled = IRQ_HANDLED;
167662306a36Sopenharmony_ci	}
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	return handled;
167962306a36Sopenharmony_ci}
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_cistatic void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
168362306a36Sopenharmony_ci		u16 *pscsi_status)
168462306a36Sopenharmony_ci{
168562306a36Sopenharmony_ci	dprintkdbg(DBG_0, "msgout_phase0: (0x%p)\n", srb->cmd);
168662306a36Sopenharmony_ci	if (srb->state & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT))
168762306a36Sopenharmony_ci		*pscsi_status = PH_BUS_FREE;	/*.. initial phase */
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
169062306a36Sopenharmony_ci	srb->state &= ~SRB_MSGOUT;
169162306a36Sopenharmony_ci}
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_cistatic void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
169562306a36Sopenharmony_ci		u16 *pscsi_status)
169662306a36Sopenharmony_ci{
169762306a36Sopenharmony_ci	u16 i;
169862306a36Sopenharmony_ci	u8 *ptr;
169962306a36Sopenharmony_ci	dprintkdbg(DBG_0, "msgout_phase1: (0x%p)\n", srb->cmd);
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	clear_fifo(acb, "msgout_phase1");
170262306a36Sopenharmony_ci	if (!(srb->state & SRB_MSGOUT)) {
170362306a36Sopenharmony_ci		srb->state |= SRB_MSGOUT;
170462306a36Sopenharmony_ci		dprintkl(KERN_DEBUG,
170562306a36Sopenharmony_ci			"msgout_phase1: (0x%p) Phase unexpected\n",
170662306a36Sopenharmony_ci			srb->cmd);	/* So what ? */
170762306a36Sopenharmony_ci	}
170862306a36Sopenharmony_ci	if (!srb->msg_count) {
170962306a36Sopenharmony_ci		dprintkdbg(DBG_0, "msgout_phase1: (0x%p) NOP msg\n",
171062306a36Sopenharmony_ci			srb->cmd);
171162306a36Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, NOP);
171262306a36Sopenharmony_ci		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
171362306a36Sopenharmony_ci		/* it's important for atn stop */
171462306a36Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
171562306a36Sopenharmony_ci		return;
171662306a36Sopenharmony_ci	}
171762306a36Sopenharmony_ci	ptr = (u8 *)srb->msgout_buf;
171862306a36Sopenharmony_ci	for (i = 0; i < srb->msg_count; i++)
171962306a36Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr++);
172062306a36Sopenharmony_ci	srb->msg_count = 0;
172162306a36Sopenharmony_ci	if (srb->msgout_buf[0] == ABORT_TASK_SET)
172262306a36Sopenharmony_ci		srb->state = SRB_ABORT_SENT;
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
172562306a36Sopenharmony_ci}
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_cistatic void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
172962306a36Sopenharmony_ci		u16 *pscsi_status)
173062306a36Sopenharmony_ci{
173162306a36Sopenharmony_ci	dprintkdbg(DBG_0, "command_phase0: (0x%p)\n", srb->cmd);
173262306a36Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
173362306a36Sopenharmony_ci}
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_cistatic void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
173762306a36Sopenharmony_ci		u16 *pscsi_status)
173862306a36Sopenharmony_ci{
173962306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb;
174062306a36Sopenharmony_ci	u8 *ptr;
174162306a36Sopenharmony_ci	u16 i;
174262306a36Sopenharmony_ci	dprintkdbg(DBG_0, "command_phase1: (0x%p)\n", srb->cmd);
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci	clear_fifo(acb, "command_phase1");
174562306a36Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRATN);
174662306a36Sopenharmony_ci	if (!(srb->flag & AUTO_REQSENSE)) {
174762306a36Sopenharmony_ci		ptr = (u8 *)srb->cmd->cmnd;
174862306a36Sopenharmony_ci		for (i = 0; i < srb->cmd->cmd_len; i++) {
174962306a36Sopenharmony_ci			DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr);
175062306a36Sopenharmony_ci			ptr++;
175162306a36Sopenharmony_ci		}
175262306a36Sopenharmony_ci	} else {
175362306a36Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, REQUEST_SENSE);
175462306a36Sopenharmony_ci		dcb = acb->active_dcb;
175562306a36Sopenharmony_ci		/* target id */
175662306a36Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5));
175762306a36Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
175862306a36Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
175962306a36Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, SCSI_SENSE_BUFFERSIZE);
176062306a36Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
176162306a36Sopenharmony_ci	}
176262306a36Sopenharmony_ci	srb->state |= SRB_COMMAND;
176362306a36Sopenharmony_ci	/* it's important for atn stop */
176462306a36Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
176562306a36Sopenharmony_ci	/* SCSI command */
176662306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
176762306a36Sopenharmony_ci}
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci/*
177162306a36Sopenharmony_ci * Verify that the remaining space in the hw sg lists is the same as
177262306a36Sopenharmony_ci * the count of remaining bytes in srb->total_xfer_length
177362306a36Sopenharmony_ci */
177462306a36Sopenharmony_cistatic void sg_verify_length(struct ScsiReqBlk *srb)
177562306a36Sopenharmony_ci{
177662306a36Sopenharmony_ci	if (debug_enabled(DBG_SG)) {
177762306a36Sopenharmony_ci		unsigned len = 0;
177862306a36Sopenharmony_ci		unsigned idx = srb->sg_index;
177962306a36Sopenharmony_ci		struct SGentry *psge = srb->segment_x + idx;
178062306a36Sopenharmony_ci		for (; idx < srb->sg_count; psge++, idx++)
178162306a36Sopenharmony_ci			len += psge->length;
178262306a36Sopenharmony_ci		if (len != srb->total_xfer_length)
178362306a36Sopenharmony_ci			dprintkdbg(DBG_SG,
178462306a36Sopenharmony_ci			       "Inconsistent SRB S/G lengths (Tot=%i, Count=%i) !!\n",
178562306a36Sopenharmony_ci			       srb->total_xfer_length, len);
178662306a36Sopenharmony_ci	}
178762306a36Sopenharmony_ci}
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci/*
179162306a36Sopenharmony_ci * Compute the next Scatter Gather list index and adjust its length
179262306a36Sopenharmony_ci * and address if necessary
179362306a36Sopenharmony_ci */
179462306a36Sopenharmony_cistatic void sg_update_list(struct ScsiReqBlk *srb, u32 left)
179562306a36Sopenharmony_ci{
179662306a36Sopenharmony_ci	u8 idx;
179762306a36Sopenharmony_ci	u32 xferred = srb->total_xfer_length - left; /* bytes transferred */
179862306a36Sopenharmony_ci	struct SGentry *psge = srb->segment_x + srb->sg_index;
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	dprintkdbg(DBG_0,
180162306a36Sopenharmony_ci		"sg_update_list: Transferred %i of %i bytes, %i remain\n",
180262306a36Sopenharmony_ci		xferred, srb->total_xfer_length, left);
180362306a36Sopenharmony_ci	if (xferred == 0) {
180462306a36Sopenharmony_ci		/* nothing to update since we did not transfer any data */
180562306a36Sopenharmony_ci		return;
180662306a36Sopenharmony_ci	}
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci	sg_verify_length(srb);
180962306a36Sopenharmony_ci	srb->total_xfer_length = left;	/* update remaining count */
181062306a36Sopenharmony_ci	for (idx = srb->sg_index; idx < srb->sg_count; idx++) {
181162306a36Sopenharmony_ci		if (xferred >= psge->length) {
181262306a36Sopenharmony_ci			/* Complete SG entries done */
181362306a36Sopenharmony_ci			xferred -= psge->length;
181462306a36Sopenharmony_ci		} else {
181562306a36Sopenharmony_ci			/* Partial SG entry done */
181662306a36Sopenharmony_ci			dma_sync_single_for_cpu(&srb->dcb->acb->dev->dev,
181762306a36Sopenharmony_ci					srb->sg_bus_addr, SEGMENTX_LEN,
181862306a36Sopenharmony_ci					DMA_TO_DEVICE);
181962306a36Sopenharmony_ci			psge->length -= xferred;
182062306a36Sopenharmony_ci			psge->address += xferred;
182162306a36Sopenharmony_ci			srb->sg_index = idx;
182262306a36Sopenharmony_ci			dma_sync_single_for_device(&srb->dcb->acb->dev->dev,
182362306a36Sopenharmony_ci					srb->sg_bus_addr, SEGMENTX_LEN,
182462306a36Sopenharmony_ci					DMA_TO_DEVICE);
182562306a36Sopenharmony_ci			break;
182662306a36Sopenharmony_ci		}
182762306a36Sopenharmony_ci		psge++;
182862306a36Sopenharmony_ci	}
182962306a36Sopenharmony_ci	sg_verify_length(srb);
183062306a36Sopenharmony_ci}
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci/*
183462306a36Sopenharmony_ci * We have transferred a single byte (PIO mode?) and need to update
183562306a36Sopenharmony_ci * the count of bytes remaining (total_xfer_length) and update the sg
183662306a36Sopenharmony_ci * entry to either point to next byte in the current sg entry, or of
183762306a36Sopenharmony_ci * already at the end to point to the start of the next sg entry
183862306a36Sopenharmony_ci */
183962306a36Sopenharmony_cistatic void sg_subtract_one(struct ScsiReqBlk *srb)
184062306a36Sopenharmony_ci{
184162306a36Sopenharmony_ci	sg_update_list(srb, srb->total_xfer_length - 1);
184262306a36Sopenharmony_ci}
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci/*
184662306a36Sopenharmony_ci * cleanup_after_transfer
184762306a36Sopenharmony_ci *
184862306a36Sopenharmony_ci * Makes sure, DMA and SCSI engine are empty, after the transfer has finished
184962306a36Sopenharmony_ci * KG: Currently called from  StatusPhase1 ()
185062306a36Sopenharmony_ci * Should probably also be called from other places
185162306a36Sopenharmony_ci * Best might be to call it in DataXXPhase0, if new phase will differ
185262306a36Sopenharmony_ci */
185362306a36Sopenharmony_cistatic void cleanup_after_transfer(struct AdapterCtlBlk *acb,
185462306a36Sopenharmony_ci		struct ScsiReqBlk *srb)
185562306a36Sopenharmony_ci{
185662306a36Sopenharmony_ci	/*DC395x_write8 (TRM_S1040_DMA_STATUS, FORCEDMACOMP); */
185762306a36Sopenharmony_ci	if (DC395x_read16(acb, TRM_S1040_DMA_COMMAND) & 0x0001) {	/* read */
185862306a36Sopenharmony_ci		if (!(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x40))
185962306a36Sopenharmony_ci			clear_fifo(acb, "cleanup/in");
186062306a36Sopenharmony_ci		if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80))
186162306a36Sopenharmony_ci			DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO);
186262306a36Sopenharmony_ci	} else {		/* write */
186362306a36Sopenharmony_ci		if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80))
186462306a36Sopenharmony_ci			DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO);
186562306a36Sopenharmony_ci		if (!(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x40))
186662306a36Sopenharmony_ci			clear_fifo(acb, "cleanup/out");
186762306a36Sopenharmony_ci	}
186862306a36Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
186962306a36Sopenharmony_ci}
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_ci/*
187362306a36Sopenharmony_ci * Those no of bytes will be transferred w/ PIO through the SCSI FIFO
187462306a36Sopenharmony_ci * Seems to be needed for unknown reasons; could be a hardware bug :-(
187562306a36Sopenharmony_ci */
187662306a36Sopenharmony_ci#define DC395x_LASTPIO 4
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_cistatic void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
188062306a36Sopenharmony_ci		u16 *pscsi_status)
188162306a36Sopenharmony_ci{
188262306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb = srb->dcb;
188362306a36Sopenharmony_ci	u16 scsi_status = *pscsi_status;
188462306a36Sopenharmony_ci	u32 d_left_counter = 0;
188562306a36Sopenharmony_ci	dprintkdbg(DBG_0, "data_out_phase0: (0x%p) <%02i-%i>\n",
188662306a36Sopenharmony_ci		srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun);
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ci	/*
188962306a36Sopenharmony_ci	 * KG: We need to drain the buffers before we draw any conclusions!
189062306a36Sopenharmony_ci	 * This means telling the DMA to push the rest into SCSI, telling
189162306a36Sopenharmony_ci	 * SCSI to push the rest to the bus.
189262306a36Sopenharmony_ci	 * However, the device might have been the one to stop us (phase
189362306a36Sopenharmony_ci	 * change), and the data in transit just needs to be accounted so
189462306a36Sopenharmony_ci	 * it can be retransmitted.)
189562306a36Sopenharmony_ci	 */
189662306a36Sopenharmony_ci	/*
189762306a36Sopenharmony_ci	 * KG: Stop DMA engine pushing more data into the SCSI FIFO
189862306a36Sopenharmony_ci	 * If we need more data, the DMA SG list will be freshly set up, anyway
189962306a36Sopenharmony_ci	 */
190062306a36Sopenharmony_ci	dprintkdbg(DBG_PIO, "data_out_phase0: "
190162306a36Sopenharmony_ci		"DMA{fifocnt=0x%02x fifostat=0x%02x} "
190262306a36Sopenharmony_ci		"SCSI{fifocnt=0x%02x cnt=0x%06x status=0x%04x} total=0x%06x\n",
190362306a36Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
190462306a36Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
190562306a36Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
190662306a36Sopenharmony_ci		DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), scsi_status,
190762306a36Sopenharmony_ci		srb->total_xfer_length);
190862306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_DMA_CONTROL, STOPDMAXFER | CLRXFIFO);
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci	if (!(srb->state & SRB_XFERPAD)) {
191162306a36Sopenharmony_ci		if (scsi_status & PARITYERROR)
191262306a36Sopenharmony_ci			srb->status |= PARITY_ERROR;
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_ci		/*
191562306a36Sopenharmony_ci		 * KG: Right, we can't just rely on the SCSI_COUNTER, because this
191662306a36Sopenharmony_ci		 * is the no of bytes it got from the DMA engine not the no it
191762306a36Sopenharmony_ci		 * transferred successfully to the device. (And the difference could
191862306a36Sopenharmony_ci		 * be as much as the FIFO size, I guess ...)
191962306a36Sopenharmony_ci		 */
192062306a36Sopenharmony_ci		if (!(scsi_status & SCSIXFERDONE)) {
192162306a36Sopenharmony_ci			/*
192262306a36Sopenharmony_ci			 * when data transfer from DMA FIFO to SCSI FIFO
192362306a36Sopenharmony_ci			 * if there was some data left in SCSI FIFO
192462306a36Sopenharmony_ci			 */
192562306a36Sopenharmony_ci			d_left_counter =
192662306a36Sopenharmony_ci			    (u32)(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) &
192762306a36Sopenharmony_ci				  0x1F);
192862306a36Sopenharmony_ci			if (dcb->sync_period & WIDE_SYNC)
192962306a36Sopenharmony_ci				d_left_counter <<= 1;
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ci			dprintkdbg(DBG_KG, "data_out_phase0: FIFO contains %i %s\n"
193262306a36Sopenharmony_ci				"SCSI{fifocnt=0x%02x cnt=0x%08x} "
193362306a36Sopenharmony_ci				"DMA{fifocnt=0x%04x cnt=0x%02x ctr=0x%08x}\n",
193462306a36Sopenharmony_ci				DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
193562306a36Sopenharmony_ci				(dcb->sync_period & WIDE_SYNC) ? "words" : "bytes",
193662306a36Sopenharmony_ci				DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
193762306a36Sopenharmony_ci				DC395x_read32(acb, TRM_S1040_SCSI_COUNTER),
193862306a36Sopenharmony_ci				DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
193962306a36Sopenharmony_ci				DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
194062306a36Sopenharmony_ci				DC395x_read32(acb, TRM_S1040_DMA_CXCNT));
194162306a36Sopenharmony_ci		}
194262306a36Sopenharmony_ci		/*
194362306a36Sopenharmony_ci		 * calculate all the residue data that not yet tranfered
194462306a36Sopenharmony_ci		 * SCSI transfer counter + left in SCSI FIFO data
194562306a36Sopenharmony_ci		 *
194662306a36Sopenharmony_ci		 * .....TRM_S1040_SCSI_COUNTER (24bits)
194762306a36Sopenharmony_ci		 * The counter always decrement by one for every SCSI byte transfer.
194862306a36Sopenharmony_ci		 * .....TRM_S1040_SCSI_FIFOCNT ( 5bits)
194962306a36Sopenharmony_ci		 * The counter is SCSI FIFO offset counter (in units of bytes or! words)
195062306a36Sopenharmony_ci		 */
195162306a36Sopenharmony_ci		if (srb->total_xfer_length > DC395x_LASTPIO)
195262306a36Sopenharmony_ci			d_left_counter +=
195362306a36Sopenharmony_ci			    DC395x_read32(acb, TRM_S1040_SCSI_COUNTER);
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci		/* Is this a good idea? */
195662306a36Sopenharmony_ci		/*clear_fifo(acb, "DOP1"); */
195762306a36Sopenharmony_ci		/* KG: What is this supposed to be useful for? WIDE padding stuff? */
195862306a36Sopenharmony_ci		if (d_left_counter == 1 && dcb->sync_period & WIDE_SYNC
195962306a36Sopenharmony_ci		    && scsi_bufflen(srb->cmd) % 2) {
196062306a36Sopenharmony_ci			d_left_counter = 0;
196162306a36Sopenharmony_ci			dprintkl(KERN_INFO,
196262306a36Sopenharmony_ci				"data_out_phase0: Discard 1 byte (0x%02x)\n",
196362306a36Sopenharmony_ci				scsi_status);
196462306a36Sopenharmony_ci		}
196562306a36Sopenharmony_ci		/*
196662306a36Sopenharmony_ci		 * KG: Oops again. Same thinko as above: The SCSI might have been
196762306a36Sopenharmony_ci		 * faster than the DMA engine, so that it ran out of data.
196862306a36Sopenharmony_ci		 * In that case, we have to do just nothing!
196962306a36Sopenharmony_ci		 * But: Why the interrupt: No phase change. No XFERCNT_2_ZERO. Or?
197062306a36Sopenharmony_ci		 */
197162306a36Sopenharmony_ci		/*
197262306a36Sopenharmony_ci		 * KG: This is nonsense: We have been WRITING data to the bus
197362306a36Sopenharmony_ci		 * If the SCSI engine has no bytes left, how should the DMA engine?
197462306a36Sopenharmony_ci		 */
197562306a36Sopenharmony_ci		if (d_left_counter == 0) {
197662306a36Sopenharmony_ci			srb->total_xfer_length = 0;
197762306a36Sopenharmony_ci		} else {
197862306a36Sopenharmony_ci			/*
197962306a36Sopenharmony_ci			 * if transfer not yet complete
198062306a36Sopenharmony_ci			 * there were some data residue in SCSI FIFO or
198162306a36Sopenharmony_ci			 * SCSI transfer counter not empty
198262306a36Sopenharmony_ci			 */
198362306a36Sopenharmony_ci			long oldxferred =
198462306a36Sopenharmony_ci			    srb->total_xfer_length - d_left_counter;
198562306a36Sopenharmony_ci			const int diff =
198662306a36Sopenharmony_ci			    (dcb->sync_period & WIDE_SYNC) ? 2 : 1;
198762306a36Sopenharmony_ci			sg_update_list(srb, d_left_counter);
198862306a36Sopenharmony_ci			/* KG: Most ugly hack! Apparently, this works around a chip bug */
198962306a36Sopenharmony_ci			if ((srb->segment_x[srb->sg_index].length ==
199062306a36Sopenharmony_ci			     diff && scsi_sg_count(srb->cmd))
199162306a36Sopenharmony_ci			    || ((oldxferred & ~PAGE_MASK) ==
199262306a36Sopenharmony_ci				(PAGE_SIZE - diff))
199362306a36Sopenharmony_ci			    ) {
199462306a36Sopenharmony_ci				dprintkl(KERN_INFO, "data_out_phase0: "
199562306a36Sopenharmony_ci					"Work around chip bug (%i)?\n", diff);
199662306a36Sopenharmony_ci				d_left_counter =
199762306a36Sopenharmony_ci				    srb->total_xfer_length - diff;
199862306a36Sopenharmony_ci				sg_update_list(srb, d_left_counter);
199962306a36Sopenharmony_ci				/*srb->total_xfer_length -= diff; */
200062306a36Sopenharmony_ci				/*srb->virt_addr += diff; */
200162306a36Sopenharmony_ci				/*if (srb->cmd->use_sg) */
200262306a36Sopenharmony_ci				/*      srb->sg_index++; */
200362306a36Sopenharmony_ci			}
200462306a36Sopenharmony_ci		}
200562306a36Sopenharmony_ci	}
200662306a36Sopenharmony_ci	if ((*pscsi_status & PHASEMASK) != PH_DATA_OUT) {
200762306a36Sopenharmony_ci		cleanup_after_transfer(acb, srb);
200862306a36Sopenharmony_ci	}
200962306a36Sopenharmony_ci}
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_cistatic void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
201362306a36Sopenharmony_ci		u16 *pscsi_status)
201462306a36Sopenharmony_ci{
201562306a36Sopenharmony_ci	dprintkdbg(DBG_0, "data_out_phase1: (0x%p) <%02i-%i>\n",
201662306a36Sopenharmony_ci		srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun);
201762306a36Sopenharmony_ci	clear_fifo(acb, "data_out_phase1");
201862306a36Sopenharmony_ci	/* do prepare before transfer when data out phase */
201962306a36Sopenharmony_ci	data_io_transfer(acb, srb, XFERDATAOUT);
202062306a36Sopenharmony_ci}
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_cistatic void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
202362306a36Sopenharmony_ci		u16 *pscsi_status)
202462306a36Sopenharmony_ci{
202562306a36Sopenharmony_ci	u16 scsi_status = *pscsi_status;
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci	dprintkdbg(DBG_0, "data_in_phase0: (0x%p) <%02i-%i>\n",
202862306a36Sopenharmony_ci		srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun);
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	/*
203162306a36Sopenharmony_ci	 * KG: DataIn is much more tricky than DataOut. When the device is finished
203262306a36Sopenharmony_ci	 * and switches to another phase, the SCSI engine should be finished too.
203362306a36Sopenharmony_ci	 * But: There might still be bytes left in its FIFO to be fetched by the DMA
203462306a36Sopenharmony_ci	 * engine and transferred to memory.
203562306a36Sopenharmony_ci	 * We should wait for the FIFOs to be emptied by that (is there any way to
203662306a36Sopenharmony_ci	 * enforce this?) and then stop the DMA engine, because it might think, that
203762306a36Sopenharmony_ci	 * there are more bytes to follow. Yes, the device might disconnect prior to
203862306a36Sopenharmony_ci	 * having all bytes transferred!
203962306a36Sopenharmony_ci	 * Also we should make sure that all data from the DMA engine buffer's really
204062306a36Sopenharmony_ci	 * made its way to the system memory! Some documentation on this would not
204162306a36Sopenharmony_ci	 * seem to be a bad idea, actually.
204262306a36Sopenharmony_ci	 */
204362306a36Sopenharmony_ci	if (!(srb->state & SRB_XFERPAD)) {
204462306a36Sopenharmony_ci		u32 d_left_counter;
204562306a36Sopenharmony_ci		unsigned int sc, fc;
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci		if (scsi_status & PARITYERROR) {
204862306a36Sopenharmony_ci			dprintkl(KERN_INFO, "data_in_phase0: (0x%p) "
204962306a36Sopenharmony_ci				"Parity Error\n", srb->cmd);
205062306a36Sopenharmony_ci			srb->status |= PARITY_ERROR;
205162306a36Sopenharmony_ci		}
205262306a36Sopenharmony_ci		/*
205362306a36Sopenharmony_ci		 * KG: We should wait for the DMA FIFO to be empty ...
205462306a36Sopenharmony_ci		 * but: it would be better to wait first for the SCSI FIFO and then the
205562306a36Sopenharmony_ci		 * the DMA FIFO to become empty? How do we know, that the device not already
205662306a36Sopenharmony_ci		 * sent data to the FIFO in a MsgIn phase, eg.?
205762306a36Sopenharmony_ci		 */
205862306a36Sopenharmony_ci		if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80)) {
205962306a36Sopenharmony_ci#if 0
206062306a36Sopenharmony_ci			int ctr = 6000000;
206162306a36Sopenharmony_ci			dprintkl(KERN_DEBUG,
206262306a36Sopenharmony_ci				"DIP0: Wait for DMA FIFO to flush ...\n");
206362306a36Sopenharmony_ci			/*DC395x_write8  (TRM_S1040_DMA_CONTROL, STOPDMAXFER); */
206462306a36Sopenharmony_ci			/*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 7); */
206562306a36Sopenharmony_ci			/*DC395x_write8  (TRM_S1040_SCSI_COMMAND, SCMD_DMA_IN); */
206662306a36Sopenharmony_ci			while (!
206762306a36Sopenharmony_ci			       (DC395x_read16(acb, TRM_S1040_DMA_FIFOSTAT) &
206862306a36Sopenharmony_ci				0x80) && --ctr);
206962306a36Sopenharmony_ci			if (ctr < 6000000 - 1)
207062306a36Sopenharmony_ci				dprintkl(KERN_DEBUG
207162306a36Sopenharmony_ci				       "DIP0: Had to wait for DMA ...\n");
207262306a36Sopenharmony_ci			if (!ctr)
207362306a36Sopenharmony_ci				dprintkl(KERN_ERR,
207462306a36Sopenharmony_ci				       "Deadlock in DIP0 waiting for DMA FIFO empty!!\n");
207562306a36Sopenharmony_ci			/*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 0); */
207662306a36Sopenharmony_ci#endif
207762306a36Sopenharmony_ci			dprintkdbg(DBG_KG, "data_in_phase0: "
207862306a36Sopenharmony_ci				"DMA{fifocnt=0x%02x fifostat=0x%02x}\n",
207962306a36Sopenharmony_ci				DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
208062306a36Sopenharmony_ci				DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT));
208162306a36Sopenharmony_ci		}
208262306a36Sopenharmony_ci		/* Now: Check remainig data: The SCSI counters should tell us ... */
208362306a36Sopenharmony_ci		sc = DC395x_read32(acb, TRM_S1040_SCSI_COUNTER);
208462306a36Sopenharmony_ci		fc = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT);
208562306a36Sopenharmony_ci		d_left_counter = sc + ((fc & 0x1f)
208662306a36Sopenharmony_ci		       << ((srb->dcb->sync_period & WIDE_SYNC) ? 1 :
208762306a36Sopenharmony_ci			   0));
208862306a36Sopenharmony_ci		dprintkdbg(DBG_KG, "data_in_phase0: "
208962306a36Sopenharmony_ci			"SCSI{fifocnt=0x%02x%s ctr=0x%08x} "
209062306a36Sopenharmony_ci			"DMA{fifocnt=0x%02x fifostat=0x%02x ctr=0x%08x} "
209162306a36Sopenharmony_ci			"Remain{totxfer=%i scsi_fifo+ctr=%i}\n",
209262306a36Sopenharmony_ci			fc,
209362306a36Sopenharmony_ci			(srb->dcb->sync_period & WIDE_SYNC) ? "words" : "bytes",
209462306a36Sopenharmony_ci			sc,
209562306a36Sopenharmony_ci			fc,
209662306a36Sopenharmony_ci			DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
209762306a36Sopenharmony_ci			DC395x_read32(acb, TRM_S1040_DMA_CXCNT),
209862306a36Sopenharmony_ci			srb->total_xfer_length, d_left_counter);
209962306a36Sopenharmony_ci#if DC395x_LASTPIO
210062306a36Sopenharmony_ci		/* KG: Less than or equal to 4 bytes can not be transferred via DMA, it seems. */
210162306a36Sopenharmony_ci		if (d_left_counter
210262306a36Sopenharmony_ci		    && srb->total_xfer_length <= DC395x_LASTPIO) {
210362306a36Sopenharmony_ci			size_t left_io = srb->total_xfer_length;
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci			/*u32 addr = (srb->segment_x[srb->sg_index].address); */
210662306a36Sopenharmony_ci			/*sg_update_list (srb, d_left_counter); */
210762306a36Sopenharmony_ci			dprintkdbg(DBG_PIO, "data_in_phase0: PIO (%i %s) "
210862306a36Sopenharmony_ci				   "for remaining %i bytes:",
210962306a36Sopenharmony_ci				fc & 0x1f,
211062306a36Sopenharmony_ci				(srb->dcb->sync_period & WIDE_SYNC) ?
211162306a36Sopenharmony_ci				    "words" : "bytes",
211262306a36Sopenharmony_ci				srb->total_xfer_length);
211362306a36Sopenharmony_ci			if (srb->dcb->sync_period & WIDE_SYNC)
211462306a36Sopenharmony_ci				DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2,
211562306a36Sopenharmony_ci					      CFG2_WIDEFIFO);
211662306a36Sopenharmony_ci			while (left_io) {
211762306a36Sopenharmony_ci				unsigned char *virt, *base = NULL;
211862306a36Sopenharmony_ci				unsigned long flags = 0;
211962306a36Sopenharmony_ci				size_t len = left_io;
212062306a36Sopenharmony_ci				size_t offset = srb->request_length - left_io;
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_ci				local_irq_save(flags);
212362306a36Sopenharmony_ci				/* Assumption: it's inside one page as it's at most 4 bytes and
212462306a36Sopenharmony_ci				   I just assume it's on a 4-byte boundary */
212562306a36Sopenharmony_ci				base = scsi_kmap_atomic_sg(scsi_sglist(srb->cmd),
212662306a36Sopenharmony_ci							   srb->sg_count, &offset, &len);
212762306a36Sopenharmony_ci				virt = base + offset;
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci				left_io -= len;
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci				while (len) {
213262306a36Sopenharmony_ci					u8 byte;
213362306a36Sopenharmony_ci					byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
213462306a36Sopenharmony_ci					*virt++ = byte;
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_ci					if (debug_enabled(DBG_PIO))
213762306a36Sopenharmony_ci						printk(" %02x", byte);
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_ci					d_left_counter--;
214062306a36Sopenharmony_ci					sg_subtract_one(srb);
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_ci					len--;
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci					fc = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT);
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci					if (fc == 0x40) {
214762306a36Sopenharmony_ci						left_io = 0;
214862306a36Sopenharmony_ci						break;
214962306a36Sopenharmony_ci					}
215062306a36Sopenharmony_ci				}
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ci				WARN_ON((fc != 0x40) == !d_left_counter);
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci				if (fc == 0x40 && (srb->dcb->sync_period & WIDE_SYNC)) {
215562306a36Sopenharmony_ci					/* Read the last byte ... */
215662306a36Sopenharmony_ci					if (srb->total_xfer_length > 0) {
215762306a36Sopenharmony_ci						u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci						*virt++ = byte;
216062306a36Sopenharmony_ci						srb->total_xfer_length--;
216162306a36Sopenharmony_ci						if (debug_enabled(DBG_PIO))
216262306a36Sopenharmony_ci							printk(" %02x", byte);
216362306a36Sopenharmony_ci					}
216462306a36Sopenharmony_ci
216562306a36Sopenharmony_ci					DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0);
216662306a36Sopenharmony_ci				}
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci				scsi_kunmap_atomic_sg(base);
216962306a36Sopenharmony_ci				local_irq_restore(flags);
217062306a36Sopenharmony_ci			}
217162306a36Sopenharmony_ci			/*printk(" %08x", *(u32*)(bus_to_virt (addr))); */
217262306a36Sopenharmony_ci			/*srb->total_xfer_length = 0; */
217362306a36Sopenharmony_ci			if (debug_enabled(DBG_PIO))
217462306a36Sopenharmony_ci				printk("\n");
217562306a36Sopenharmony_ci		}
217662306a36Sopenharmony_ci#endif				/* DC395x_LASTPIO */
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_ci#if 0
217962306a36Sopenharmony_ci		/*
218062306a36Sopenharmony_ci		 * KG: This was in DATAOUT. Does it also belong here?
218162306a36Sopenharmony_ci		 * Nobody seems to know what counter and fifo_cnt count exactly ...
218262306a36Sopenharmony_ci		 */
218362306a36Sopenharmony_ci		if (!(scsi_status & SCSIXFERDONE)) {
218462306a36Sopenharmony_ci			/*
218562306a36Sopenharmony_ci			 * when data transfer from DMA FIFO to SCSI FIFO
218662306a36Sopenharmony_ci			 * if there was some data left in SCSI FIFO
218762306a36Sopenharmony_ci			 */
218862306a36Sopenharmony_ci			d_left_counter =
218962306a36Sopenharmony_ci			    (u32)(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) &
219062306a36Sopenharmony_ci				  0x1F);
219162306a36Sopenharmony_ci			if (srb->dcb->sync_period & WIDE_SYNC)
219262306a36Sopenharmony_ci				d_left_counter <<= 1;
219362306a36Sopenharmony_ci			/*
219462306a36Sopenharmony_ci			 * if WIDE scsi SCSI FIFOCNT unit is word !!!
219562306a36Sopenharmony_ci			 * so need to *= 2
219662306a36Sopenharmony_ci			 * KG: Seems to be correct ...
219762306a36Sopenharmony_ci			 */
219862306a36Sopenharmony_ci		}
219962306a36Sopenharmony_ci#endif
220062306a36Sopenharmony_ci		/* KG: This should not be needed any more! */
220162306a36Sopenharmony_ci		if (d_left_counter == 0
220262306a36Sopenharmony_ci		    || (scsi_status & SCSIXFERCNT_2_ZERO)) {
220362306a36Sopenharmony_ci#if 0
220462306a36Sopenharmony_ci			int ctr = 6000000;
220562306a36Sopenharmony_ci			u8 TempDMAstatus;
220662306a36Sopenharmony_ci			do {
220762306a36Sopenharmony_ci				TempDMAstatus =
220862306a36Sopenharmony_ci				    DC395x_read8(acb, TRM_S1040_DMA_STATUS);
220962306a36Sopenharmony_ci			} while (!(TempDMAstatus & DMAXFERCOMP) && --ctr);
221062306a36Sopenharmony_ci			if (!ctr)
221162306a36Sopenharmony_ci				dprintkl(KERN_ERR,
221262306a36Sopenharmony_ci				       "Deadlock in DataInPhase0 waiting for DMA!!\n");
221362306a36Sopenharmony_ci			srb->total_xfer_length = 0;
221462306a36Sopenharmony_ci#endif
221562306a36Sopenharmony_ci			srb->total_xfer_length = d_left_counter;
221662306a36Sopenharmony_ci		} else {	/* phase changed */
221762306a36Sopenharmony_ci			/*
221862306a36Sopenharmony_ci			 * parsing the case:
221962306a36Sopenharmony_ci			 * when a transfer not yet complete
222062306a36Sopenharmony_ci			 * but be disconnected by target
222162306a36Sopenharmony_ci			 * if transfer not yet complete
222262306a36Sopenharmony_ci			 * there were some data residue in SCSI FIFO or
222362306a36Sopenharmony_ci			 * SCSI transfer counter not empty
222462306a36Sopenharmony_ci			 */
222562306a36Sopenharmony_ci			sg_update_list(srb, d_left_counter);
222662306a36Sopenharmony_ci		}
222762306a36Sopenharmony_ci	}
222862306a36Sopenharmony_ci	/* KG: The target may decide to disconnect: Empty FIFO before! */
222962306a36Sopenharmony_ci	if ((*pscsi_status & PHASEMASK) != PH_DATA_IN) {
223062306a36Sopenharmony_ci		cleanup_after_transfer(acb, srb);
223162306a36Sopenharmony_ci	}
223262306a36Sopenharmony_ci}
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_cistatic void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
223662306a36Sopenharmony_ci		u16 *pscsi_status)
223762306a36Sopenharmony_ci{
223862306a36Sopenharmony_ci	dprintkdbg(DBG_0, "data_in_phase1: (0x%p) <%02i-%i>\n",
223962306a36Sopenharmony_ci		srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun);
224062306a36Sopenharmony_ci	data_io_transfer(acb, srb, XFERDATAIN);
224162306a36Sopenharmony_ci}
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci
224462306a36Sopenharmony_cistatic void data_io_transfer(struct AdapterCtlBlk *acb,
224562306a36Sopenharmony_ci		struct ScsiReqBlk *srb, u16 io_dir)
224662306a36Sopenharmony_ci{
224762306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb = srb->dcb;
224862306a36Sopenharmony_ci	u8 bval;
224962306a36Sopenharmony_ci	dprintkdbg(DBG_0,
225062306a36Sopenharmony_ci		"data_io_transfer: (0x%p) <%02i-%i> %c len=%i, sg=(%i/%i)\n",
225162306a36Sopenharmony_ci		srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun,
225262306a36Sopenharmony_ci		((io_dir & DMACMD_DIR) ? 'r' : 'w'),
225362306a36Sopenharmony_ci		srb->total_xfer_length, srb->sg_index, srb->sg_count);
225462306a36Sopenharmony_ci	if (srb == acb->tmp_srb)
225562306a36Sopenharmony_ci		dprintkl(KERN_ERR, "data_io_transfer: Using tmp_srb!\n");
225662306a36Sopenharmony_ci	if (srb->sg_index >= srb->sg_count) {
225762306a36Sopenharmony_ci		/* can't happen? out of bounds error */
225862306a36Sopenharmony_ci		return;
225962306a36Sopenharmony_ci	}
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ci	if (srb->total_xfer_length > DC395x_LASTPIO) {
226262306a36Sopenharmony_ci		u8 dma_status = DC395x_read8(acb, TRM_S1040_DMA_STATUS);
226362306a36Sopenharmony_ci		/*
226462306a36Sopenharmony_ci		 * KG: What should we do: Use SCSI Cmd 0x90/0x92?
226562306a36Sopenharmony_ci		 * Maybe, even ABORTXFER would be appropriate
226662306a36Sopenharmony_ci		 */
226762306a36Sopenharmony_ci		if (dma_status & XFERPENDING) {
226862306a36Sopenharmony_ci			dprintkl(KERN_DEBUG, "data_io_transfer: Xfer pending! "
226962306a36Sopenharmony_ci				"Expect trouble!\n");
227062306a36Sopenharmony_ci			dump_register_info(acb, dcb, srb);
227162306a36Sopenharmony_ci			DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO);
227262306a36Sopenharmony_ci		}
227362306a36Sopenharmony_ci		/* clear_fifo(acb, "IO"); */
227462306a36Sopenharmony_ci		/*
227562306a36Sopenharmony_ci		 * load what physical address of Scatter/Gather list table
227662306a36Sopenharmony_ci		 * want to be transfer
227762306a36Sopenharmony_ci		 */
227862306a36Sopenharmony_ci		srb->state |= SRB_DATA_XFER;
227962306a36Sopenharmony_ci		DC395x_write32(acb, TRM_S1040_DMA_XHIGHADDR, 0);
228062306a36Sopenharmony_ci		if (scsi_sg_count(srb->cmd)) {	/* with S/G */
228162306a36Sopenharmony_ci			io_dir |= DMACMD_SG;
228262306a36Sopenharmony_ci			DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR,
228362306a36Sopenharmony_ci				       srb->sg_bus_addr +
228462306a36Sopenharmony_ci				       sizeof(struct SGentry) *
228562306a36Sopenharmony_ci				       srb->sg_index);
228662306a36Sopenharmony_ci			/* load how many bytes in the sg list table */
228762306a36Sopenharmony_ci			DC395x_write32(acb, TRM_S1040_DMA_XCNT,
228862306a36Sopenharmony_ci				       ((u32)(srb->sg_count -
228962306a36Sopenharmony_ci					      srb->sg_index) << 3));
229062306a36Sopenharmony_ci		} else {	/* without S/G */
229162306a36Sopenharmony_ci			io_dir &= ~DMACMD_SG;
229262306a36Sopenharmony_ci			DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR,
229362306a36Sopenharmony_ci				       srb->segment_x[0].address);
229462306a36Sopenharmony_ci			DC395x_write32(acb, TRM_S1040_DMA_XCNT,
229562306a36Sopenharmony_ci				       srb->segment_x[0].length);
229662306a36Sopenharmony_ci		}
229762306a36Sopenharmony_ci		/* load total transfer length (24bits) max value 16Mbyte */
229862306a36Sopenharmony_ci		DC395x_write32(acb, TRM_S1040_SCSI_COUNTER,
229962306a36Sopenharmony_ci			       srb->total_xfer_length);
230062306a36Sopenharmony_ci		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
230162306a36Sopenharmony_ci		if (io_dir & DMACMD_DIR) {	/* read */
230262306a36Sopenharmony_ci			DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
230362306a36Sopenharmony_ci				      SCMD_DMA_IN);
230462306a36Sopenharmony_ci			DC395x_write16(acb, TRM_S1040_DMA_COMMAND, io_dir);
230562306a36Sopenharmony_ci		} else {
230662306a36Sopenharmony_ci			DC395x_write16(acb, TRM_S1040_DMA_COMMAND, io_dir);
230762306a36Sopenharmony_ci			DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
230862306a36Sopenharmony_ci				      SCMD_DMA_OUT);
230962306a36Sopenharmony_ci		}
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci	}
231262306a36Sopenharmony_ci#if DC395x_LASTPIO
231362306a36Sopenharmony_ci	else if (srb->total_xfer_length > 0) {	/* The last four bytes: Do PIO */
231462306a36Sopenharmony_ci		/*
231562306a36Sopenharmony_ci		 * load what physical address of Scatter/Gather list table
231662306a36Sopenharmony_ci		 * want to be transfer
231762306a36Sopenharmony_ci		 */
231862306a36Sopenharmony_ci		srb->state |= SRB_DATA_XFER;
231962306a36Sopenharmony_ci		/* load total transfer length (24bits) max value 16Mbyte */
232062306a36Sopenharmony_ci		DC395x_write32(acb, TRM_S1040_SCSI_COUNTER,
232162306a36Sopenharmony_ci			       srb->total_xfer_length);
232262306a36Sopenharmony_ci		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
232362306a36Sopenharmony_ci		if (io_dir & DMACMD_DIR) {	/* read */
232462306a36Sopenharmony_ci			DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
232562306a36Sopenharmony_ci				      SCMD_FIFO_IN);
232662306a36Sopenharmony_ci		} else {	/* write */
232762306a36Sopenharmony_ci			int ln = srb->total_xfer_length;
232862306a36Sopenharmony_ci			size_t left_io = srb->total_xfer_length;
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci			if (srb->dcb->sync_period & WIDE_SYNC)
233162306a36Sopenharmony_ci				DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2,
233262306a36Sopenharmony_ci				     CFG2_WIDEFIFO);
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci			while (left_io) {
233562306a36Sopenharmony_ci				unsigned char *virt, *base = NULL;
233662306a36Sopenharmony_ci				unsigned long flags = 0;
233762306a36Sopenharmony_ci				size_t len = left_io;
233862306a36Sopenharmony_ci				size_t offset = srb->request_length - left_io;
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_ci				local_irq_save(flags);
234162306a36Sopenharmony_ci				/* Again, max 4 bytes */
234262306a36Sopenharmony_ci				base = scsi_kmap_atomic_sg(scsi_sglist(srb->cmd),
234362306a36Sopenharmony_ci							   srb->sg_count, &offset, &len);
234462306a36Sopenharmony_ci				virt = base + offset;
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci				left_io -= len;
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci				while (len--) {
234962306a36Sopenharmony_ci					if (debug_enabled(DBG_PIO))
235062306a36Sopenharmony_ci						printk(" %02x", *virt);
235162306a36Sopenharmony_ci
235262306a36Sopenharmony_ci					DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *virt++);
235362306a36Sopenharmony_ci
235462306a36Sopenharmony_ci					sg_subtract_one(srb);
235562306a36Sopenharmony_ci				}
235662306a36Sopenharmony_ci
235762306a36Sopenharmony_ci				scsi_kunmap_atomic_sg(base);
235862306a36Sopenharmony_ci				local_irq_restore(flags);
235962306a36Sopenharmony_ci			}
236062306a36Sopenharmony_ci			if (srb->dcb->sync_period & WIDE_SYNC) {
236162306a36Sopenharmony_ci				if (ln % 2) {
236262306a36Sopenharmony_ci					DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
236362306a36Sopenharmony_ci					if (debug_enabled(DBG_PIO))
236462306a36Sopenharmony_ci						printk(" |00");
236562306a36Sopenharmony_ci				}
236662306a36Sopenharmony_ci				DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0);
236762306a36Sopenharmony_ci			}
236862306a36Sopenharmony_ci			/*DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, ln); */
236962306a36Sopenharmony_ci			if (debug_enabled(DBG_PIO))
237062306a36Sopenharmony_ci				printk("\n");
237162306a36Sopenharmony_ci			DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
237262306a36Sopenharmony_ci					  SCMD_FIFO_OUT);
237362306a36Sopenharmony_ci		}
237462306a36Sopenharmony_ci	}
237562306a36Sopenharmony_ci#endif				/* DC395x_LASTPIO */
237662306a36Sopenharmony_ci	else {		/* xfer pad */
237762306a36Sopenharmony_ci		if (srb->sg_count) {
237862306a36Sopenharmony_ci			srb->adapter_status = H_OVER_UNDER_RUN;
237962306a36Sopenharmony_ci			srb->status |= OVER_RUN;
238062306a36Sopenharmony_ci		}
238162306a36Sopenharmony_ci		/*
238262306a36Sopenharmony_ci		 * KG: despite the fact that we are using 16 bits I/O ops
238362306a36Sopenharmony_ci		 * the SCSI FIFO is only 8 bits according to the docs
238462306a36Sopenharmony_ci		 * (we can set bit 1 in 0x8f to serialize FIFO access ...)
238562306a36Sopenharmony_ci		 */
238662306a36Sopenharmony_ci		if (dcb->sync_period & WIDE_SYNC) {
238762306a36Sopenharmony_ci			DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 2);
238862306a36Sopenharmony_ci			DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2,
238962306a36Sopenharmony_ci				      CFG2_WIDEFIFO);
239062306a36Sopenharmony_ci			if (io_dir & DMACMD_DIR) {
239162306a36Sopenharmony_ci				DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
239262306a36Sopenharmony_ci				DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
239362306a36Sopenharmony_ci			} else {
239462306a36Sopenharmony_ci				/* Danger, Robinson: If you find KGs
239562306a36Sopenharmony_ci				 * scattered over the wide disk, the driver
239662306a36Sopenharmony_ci				 * or chip is to blame :-( */
239762306a36Sopenharmony_ci				DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'K');
239862306a36Sopenharmony_ci				DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'G');
239962306a36Sopenharmony_ci			}
240062306a36Sopenharmony_ci			DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0);
240162306a36Sopenharmony_ci		} else {
240262306a36Sopenharmony_ci			DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1);
240362306a36Sopenharmony_ci			/* Danger, Robinson: If you find a collection of Ks on your disk
240462306a36Sopenharmony_ci			 * something broke :-( */
240562306a36Sopenharmony_ci			if (io_dir & DMACMD_DIR)
240662306a36Sopenharmony_ci				DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
240762306a36Sopenharmony_ci			else
240862306a36Sopenharmony_ci				DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'K');
240962306a36Sopenharmony_ci		}
241062306a36Sopenharmony_ci		srb->state |= SRB_XFERPAD;
241162306a36Sopenharmony_ci		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
241262306a36Sopenharmony_ci		/* SCSI command */
241362306a36Sopenharmony_ci		bval = (io_dir & DMACMD_DIR) ? SCMD_FIFO_IN : SCMD_FIFO_OUT;
241462306a36Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, bval);
241562306a36Sopenharmony_ci	}
241662306a36Sopenharmony_ci}
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_ci
241962306a36Sopenharmony_cistatic void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
242062306a36Sopenharmony_ci		u16 *pscsi_status)
242162306a36Sopenharmony_ci{
242262306a36Sopenharmony_ci	dprintkdbg(DBG_0, "status_phase0: (0x%p) <%02i-%i>\n",
242362306a36Sopenharmony_ci		srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun);
242462306a36Sopenharmony_ci	srb->target_status = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
242562306a36Sopenharmony_ci	srb->end_message = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);	/* get message */
242662306a36Sopenharmony_ci	srb->state = SRB_COMPLETED;
242762306a36Sopenharmony_ci	*pscsi_status = PH_BUS_FREE;	/*.. initial phase */
242862306a36Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
242962306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT);
243062306a36Sopenharmony_ci}
243162306a36Sopenharmony_ci
243262306a36Sopenharmony_ci
243362306a36Sopenharmony_cistatic void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
243462306a36Sopenharmony_ci		u16 *pscsi_status)
243562306a36Sopenharmony_ci{
243662306a36Sopenharmony_ci	dprintkdbg(DBG_0, "status_phase1: (0x%p) <%02i-%i>\n",
243762306a36Sopenharmony_ci		srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun);
243862306a36Sopenharmony_ci	srb->state = SRB_STATUS;
243962306a36Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
244062306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_COMP);
244162306a36Sopenharmony_ci}
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci/* Check if the message is complete */
244562306a36Sopenharmony_cistatic inline u8 msgin_completed(u8 * msgbuf, u32 len)
244662306a36Sopenharmony_ci{
244762306a36Sopenharmony_ci	if (*msgbuf == EXTENDED_MESSAGE) {
244862306a36Sopenharmony_ci		if (len < 2)
244962306a36Sopenharmony_ci			return 0;
245062306a36Sopenharmony_ci		if (len < msgbuf[1] + 2)
245162306a36Sopenharmony_ci			return 0;
245262306a36Sopenharmony_ci	} else if (*msgbuf >= 0x20 && *msgbuf <= 0x2f)	/* two byte messages */
245362306a36Sopenharmony_ci		if (len < 2)
245462306a36Sopenharmony_ci			return 0;
245562306a36Sopenharmony_ci	return 1;
245662306a36Sopenharmony_ci}
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ci/* reject_msg */
245962306a36Sopenharmony_cistatic inline void msgin_reject(struct AdapterCtlBlk *acb,
246062306a36Sopenharmony_ci		struct ScsiReqBlk *srb)
246162306a36Sopenharmony_ci{
246262306a36Sopenharmony_ci	srb->msgout_buf[0] = MESSAGE_REJECT;
246362306a36Sopenharmony_ci	srb->msg_count = 1;
246462306a36Sopenharmony_ci	DC395x_ENABLE_MSGOUT;
246562306a36Sopenharmony_ci	srb->state &= ~SRB_MSGIN;
246662306a36Sopenharmony_ci	srb->state |= SRB_MSGOUT;
246762306a36Sopenharmony_ci	dprintkl(KERN_INFO, "msgin_reject: 0x%02x <%02i-%i>\n",
246862306a36Sopenharmony_ci		srb->msgin_buf[0],
246962306a36Sopenharmony_ci		srb->dcb->target_id, srb->dcb->target_lun);
247062306a36Sopenharmony_ci}
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_ci
247362306a36Sopenharmony_cistatic struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb,
247462306a36Sopenharmony_ci		struct DeviceCtlBlk *dcb, u8 tag)
247562306a36Sopenharmony_ci{
247662306a36Sopenharmony_ci	struct ScsiReqBlk *srb = NULL;
247762306a36Sopenharmony_ci	struct ScsiReqBlk *i;
247862306a36Sopenharmony_ci	dprintkdbg(DBG_0, "msgin_qtag: (0x%p) tag=%i srb=%p\n",
247962306a36Sopenharmony_ci		   srb->cmd, tag, srb);
248062306a36Sopenharmony_ci
248162306a36Sopenharmony_ci	if (!(dcb->tag_mask & (1 << tag)))
248262306a36Sopenharmony_ci		dprintkl(KERN_DEBUG,
248362306a36Sopenharmony_ci			"msgin_qtag: tag_mask=0x%08x does not reserve tag %i!\n",
248462306a36Sopenharmony_ci			dcb->tag_mask, tag);
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_ci	if (list_empty(&dcb->srb_going_list))
248762306a36Sopenharmony_ci		goto mingx0;
248862306a36Sopenharmony_ci	list_for_each_entry(i, &dcb->srb_going_list, list) {
248962306a36Sopenharmony_ci		if (i->tag_number == tag) {
249062306a36Sopenharmony_ci			srb = i;
249162306a36Sopenharmony_ci			break;
249262306a36Sopenharmony_ci		}
249362306a36Sopenharmony_ci	}
249462306a36Sopenharmony_ci	if (!srb)
249562306a36Sopenharmony_ci		goto mingx0;
249662306a36Sopenharmony_ci
249762306a36Sopenharmony_ci	dprintkdbg(DBG_0, "msgin_qtag: (0x%p) <%02i-%i>\n",
249862306a36Sopenharmony_ci		srb->cmd, srb->dcb->target_id, srb->dcb->target_lun);
249962306a36Sopenharmony_ci	if (dcb->flag & ABORT_DEV_) {
250062306a36Sopenharmony_ci		/*srb->state = SRB_ABORT_SENT; */
250162306a36Sopenharmony_ci		enable_msgout_abort(acb, srb);
250262306a36Sopenharmony_ci	}
250362306a36Sopenharmony_ci
250462306a36Sopenharmony_ci	if (!(srb->state & SRB_DISCONNECT))
250562306a36Sopenharmony_ci		goto mingx0;
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_ci	memcpy(srb->msgin_buf, dcb->active_srb->msgin_buf, acb->msg_len);
250862306a36Sopenharmony_ci	srb->state |= dcb->active_srb->state;
250962306a36Sopenharmony_ci	srb->state |= SRB_DATA_XFER;
251062306a36Sopenharmony_ci	dcb->active_srb = srb;
251162306a36Sopenharmony_ci	/* How can we make the DORS happy? */
251262306a36Sopenharmony_ci	return srb;
251362306a36Sopenharmony_ci
251462306a36Sopenharmony_ci      mingx0:
251562306a36Sopenharmony_ci	srb = acb->tmp_srb;
251662306a36Sopenharmony_ci	srb->state = SRB_UNEXPECT_RESEL;
251762306a36Sopenharmony_ci	dcb->active_srb = srb;
251862306a36Sopenharmony_ci	srb->msgout_buf[0] = ABORT_TASK;
251962306a36Sopenharmony_ci	srb->msg_count = 1;
252062306a36Sopenharmony_ci	DC395x_ENABLE_MSGOUT;
252162306a36Sopenharmony_ci	dprintkl(KERN_DEBUG, "msgin_qtag: Unknown tag %i - abort\n", tag);
252262306a36Sopenharmony_ci	return srb;
252362306a36Sopenharmony_ci}
252462306a36Sopenharmony_ci
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_cistatic inline void reprogram_regs(struct AdapterCtlBlk *acb,
252762306a36Sopenharmony_ci		struct DeviceCtlBlk *dcb)
252862306a36Sopenharmony_ci{
252962306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id);
253062306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_SYNC, dcb->sync_period);
253162306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, dcb->sync_offset);
253262306a36Sopenharmony_ci	set_xfer_rate(acb, dcb);
253362306a36Sopenharmony_ci}
253462306a36Sopenharmony_ci
253562306a36Sopenharmony_ci
253662306a36Sopenharmony_ci/* set async transfer mode */
253762306a36Sopenharmony_cistatic void msgin_set_async(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
253862306a36Sopenharmony_ci{
253962306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb = srb->dcb;
254062306a36Sopenharmony_ci	dprintkl(KERN_DEBUG, "msgin_set_async: No sync transfers <%02i-%i>\n",
254162306a36Sopenharmony_ci		dcb->target_id, dcb->target_lun);
254262306a36Sopenharmony_ci
254362306a36Sopenharmony_ci	dcb->sync_mode &= ~(SYNC_NEGO_ENABLE);
254462306a36Sopenharmony_ci	dcb->sync_mode |= SYNC_NEGO_DONE;
254562306a36Sopenharmony_ci	/*dcb->sync_period &= 0; */
254662306a36Sopenharmony_ci	dcb->sync_offset = 0;
254762306a36Sopenharmony_ci	dcb->min_nego_period = 200 >> 2;	/* 200ns <=> 5 MHz */
254862306a36Sopenharmony_ci	srb->state &= ~SRB_DO_SYNC_NEGO;
254962306a36Sopenharmony_ci	reprogram_regs(acb, dcb);
255062306a36Sopenharmony_ci	if ((dcb->sync_mode & WIDE_NEGO_ENABLE)
255162306a36Sopenharmony_ci	    && !(dcb->sync_mode & WIDE_NEGO_DONE)) {
255262306a36Sopenharmony_ci		build_wdtr(acb, dcb, srb);
255362306a36Sopenharmony_ci		DC395x_ENABLE_MSGOUT;
255462306a36Sopenharmony_ci		dprintkdbg(DBG_0, "msgin_set_async(rej): Try WDTR anyway\n");
255562306a36Sopenharmony_ci	}
255662306a36Sopenharmony_ci}
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci
255962306a36Sopenharmony_ci/* set sync transfer mode */
256062306a36Sopenharmony_cistatic void msgin_set_sync(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
256162306a36Sopenharmony_ci{
256262306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb = srb->dcb;
256362306a36Sopenharmony_ci	u8 bval;
256462306a36Sopenharmony_ci	int fact;
256562306a36Sopenharmony_ci	dprintkdbg(DBG_1, "msgin_set_sync: <%02i> Sync: %ins "
256662306a36Sopenharmony_ci		"(%02i.%01i MHz) Offset %i\n",
256762306a36Sopenharmony_ci		dcb->target_id, srb->msgin_buf[3] << 2,
256862306a36Sopenharmony_ci		(250 / srb->msgin_buf[3]),
256962306a36Sopenharmony_ci		((250 % srb->msgin_buf[3]) * 10) / srb->msgin_buf[3],
257062306a36Sopenharmony_ci		srb->msgin_buf[4]);
257162306a36Sopenharmony_ci
257262306a36Sopenharmony_ci	if (srb->msgin_buf[4] > 15)
257362306a36Sopenharmony_ci		srb->msgin_buf[4] = 15;
257462306a36Sopenharmony_ci	if (!(dcb->dev_mode & NTC_DO_SYNC_NEGO))
257562306a36Sopenharmony_ci		dcb->sync_offset = 0;
257662306a36Sopenharmony_ci	else if (dcb->sync_offset == 0)
257762306a36Sopenharmony_ci		dcb->sync_offset = srb->msgin_buf[4];
257862306a36Sopenharmony_ci	if (srb->msgin_buf[4] > dcb->sync_offset)
257962306a36Sopenharmony_ci		srb->msgin_buf[4] = dcb->sync_offset;
258062306a36Sopenharmony_ci	else
258162306a36Sopenharmony_ci		dcb->sync_offset = srb->msgin_buf[4];
258262306a36Sopenharmony_ci	bval = 0;
258362306a36Sopenharmony_ci	while (bval < 7 && (srb->msgin_buf[3] > clock_period[bval]
258462306a36Sopenharmony_ci			    || dcb->min_nego_period >
258562306a36Sopenharmony_ci			    clock_period[bval]))
258662306a36Sopenharmony_ci		bval++;
258762306a36Sopenharmony_ci	if (srb->msgin_buf[3] < clock_period[bval])
258862306a36Sopenharmony_ci		dprintkl(KERN_INFO,
258962306a36Sopenharmony_ci			"msgin_set_sync: Increase sync nego period to %ins\n",
259062306a36Sopenharmony_ci			clock_period[bval] << 2);
259162306a36Sopenharmony_ci	srb->msgin_buf[3] = clock_period[bval];
259262306a36Sopenharmony_ci	dcb->sync_period &= 0xf0;
259362306a36Sopenharmony_ci	dcb->sync_period |= ALT_SYNC | bval;
259462306a36Sopenharmony_ci	dcb->min_nego_period = srb->msgin_buf[3];
259562306a36Sopenharmony_ci
259662306a36Sopenharmony_ci	if (dcb->sync_period & WIDE_SYNC)
259762306a36Sopenharmony_ci		fact = 500;
259862306a36Sopenharmony_ci	else
259962306a36Sopenharmony_ci		fact = 250;
260062306a36Sopenharmony_ci
260162306a36Sopenharmony_ci	dprintkl(KERN_INFO,
260262306a36Sopenharmony_ci		"Target %02i: %s Sync: %ins Offset %i (%02i.%01i MB/s)\n",
260362306a36Sopenharmony_ci		dcb->target_id, (fact == 500) ? "Wide16" : "",
260462306a36Sopenharmony_ci		dcb->min_nego_period << 2, dcb->sync_offset,
260562306a36Sopenharmony_ci		(fact / dcb->min_nego_period),
260662306a36Sopenharmony_ci		((fact % dcb->min_nego_period) * 10 +
260762306a36Sopenharmony_ci		dcb->min_nego_period / 2) / dcb->min_nego_period);
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_ci	if (!(srb->state & SRB_DO_SYNC_NEGO)) {
261062306a36Sopenharmony_ci		/* Reply with corrected SDTR Message */
261162306a36Sopenharmony_ci		dprintkl(KERN_DEBUG, "msgin_set_sync: answer w/%ins %i\n",
261262306a36Sopenharmony_ci			srb->msgin_buf[3] << 2, srb->msgin_buf[4]);
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci		memcpy(srb->msgout_buf, srb->msgin_buf, 5);
261562306a36Sopenharmony_ci		srb->msg_count = 5;
261662306a36Sopenharmony_ci		DC395x_ENABLE_MSGOUT;
261762306a36Sopenharmony_ci		dcb->sync_mode |= SYNC_NEGO_DONE;
261862306a36Sopenharmony_ci	} else {
261962306a36Sopenharmony_ci		if ((dcb->sync_mode & WIDE_NEGO_ENABLE)
262062306a36Sopenharmony_ci		    && !(dcb->sync_mode & WIDE_NEGO_DONE)) {
262162306a36Sopenharmony_ci			build_wdtr(acb, dcb, srb);
262262306a36Sopenharmony_ci			DC395x_ENABLE_MSGOUT;
262362306a36Sopenharmony_ci			dprintkdbg(DBG_0, "msgin_set_sync: Also try WDTR\n");
262462306a36Sopenharmony_ci		}
262562306a36Sopenharmony_ci	}
262662306a36Sopenharmony_ci	srb->state &= ~SRB_DO_SYNC_NEGO;
262762306a36Sopenharmony_ci	dcb->sync_mode |= SYNC_NEGO_DONE | SYNC_NEGO_ENABLE;
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci	reprogram_regs(acb, dcb);
263062306a36Sopenharmony_ci}
263162306a36Sopenharmony_ci
263262306a36Sopenharmony_ci
263362306a36Sopenharmony_cistatic inline void msgin_set_nowide(struct AdapterCtlBlk *acb,
263462306a36Sopenharmony_ci		struct ScsiReqBlk *srb)
263562306a36Sopenharmony_ci{
263662306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb = srb->dcb;
263762306a36Sopenharmony_ci	dprintkdbg(DBG_1, "msgin_set_nowide: <%02i>\n", dcb->target_id);
263862306a36Sopenharmony_ci
263962306a36Sopenharmony_ci	dcb->sync_period &= ~WIDE_SYNC;
264062306a36Sopenharmony_ci	dcb->sync_mode &= ~(WIDE_NEGO_ENABLE);
264162306a36Sopenharmony_ci	dcb->sync_mode |= WIDE_NEGO_DONE;
264262306a36Sopenharmony_ci	srb->state &= ~SRB_DO_WIDE_NEGO;
264362306a36Sopenharmony_ci	reprogram_regs(acb, dcb);
264462306a36Sopenharmony_ci	if ((dcb->sync_mode & SYNC_NEGO_ENABLE)
264562306a36Sopenharmony_ci	    && !(dcb->sync_mode & SYNC_NEGO_DONE)) {
264662306a36Sopenharmony_ci		build_sdtr(acb, dcb, srb);
264762306a36Sopenharmony_ci		DC395x_ENABLE_MSGOUT;
264862306a36Sopenharmony_ci		dprintkdbg(DBG_0, "msgin_set_nowide: Rejected. Try SDTR anyway\n");
264962306a36Sopenharmony_ci	}
265062306a36Sopenharmony_ci}
265162306a36Sopenharmony_ci
265262306a36Sopenharmony_cistatic void msgin_set_wide(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
265362306a36Sopenharmony_ci{
265462306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb = srb->dcb;
265562306a36Sopenharmony_ci	u8 wide = (dcb->dev_mode & NTC_DO_WIDE_NEGO
265662306a36Sopenharmony_ci		   && acb->config & HCC_WIDE_CARD) ? 1 : 0;
265762306a36Sopenharmony_ci	dprintkdbg(DBG_1, "msgin_set_wide: <%02i>\n", dcb->target_id);
265862306a36Sopenharmony_ci
265962306a36Sopenharmony_ci	if (srb->msgin_buf[3] > wide)
266062306a36Sopenharmony_ci		srb->msgin_buf[3] = wide;
266162306a36Sopenharmony_ci	/* Completed */
266262306a36Sopenharmony_ci	if (!(srb->state & SRB_DO_WIDE_NEGO)) {
266362306a36Sopenharmony_ci		dprintkl(KERN_DEBUG,
266462306a36Sopenharmony_ci			"msgin_set_wide: Wide nego initiated <%02i>\n",
266562306a36Sopenharmony_ci			dcb->target_id);
266662306a36Sopenharmony_ci		memcpy(srb->msgout_buf, srb->msgin_buf, 4);
266762306a36Sopenharmony_ci		srb->msg_count = 4;
266862306a36Sopenharmony_ci		srb->state |= SRB_DO_WIDE_NEGO;
266962306a36Sopenharmony_ci		DC395x_ENABLE_MSGOUT;
267062306a36Sopenharmony_ci	}
267162306a36Sopenharmony_ci
267262306a36Sopenharmony_ci	dcb->sync_mode |= (WIDE_NEGO_ENABLE | WIDE_NEGO_DONE);
267362306a36Sopenharmony_ci	if (srb->msgin_buf[3] > 0)
267462306a36Sopenharmony_ci		dcb->sync_period |= WIDE_SYNC;
267562306a36Sopenharmony_ci	else
267662306a36Sopenharmony_ci		dcb->sync_period &= ~WIDE_SYNC;
267762306a36Sopenharmony_ci	srb->state &= ~SRB_DO_WIDE_NEGO;
267862306a36Sopenharmony_ci	/*dcb->sync_mode &= ~(WIDE_NEGO_ENABLE+WIDE_NEGO_DONE); */
267962306a36Sopenharmony_ci	dprintkdbg(DBG_1,
268062306a36Sopenharmony_ci		"msgin_set_wide: Wide (%i bit) negotiated <%02i>\n",
268162306a36Sopenharmony_ci		(8 << srb->msgin_buf[3]), dcb->target_id);
268262306a36Sopenharmony_ci	reprogram_regs(acb, dcb);
268362306a36Sopenharmony_ci	if ((dcb->sync_mode & SYNC_NEGO_ENABLE)
268462306a36Sopenharmony_ci	    && !(dcb->sync_mode & SYNC_NEGO_DONE)) {
268562306a36Sopenharmony_ci		build_sdtr(acb, dcb, srb);
268662306a36Sopenharmony_ci		DC395x_ENABLE_MSGOUT;
268762306a36Sopenharmony_ci		dprintkdbg(DBG_0, "msgin_set_wide: Also try SDTR.\n");
268862306a36Sopenharmony_ci	}
268962306a36Sopenharmony_ci}
269062306a36Sopenharmony_ci
269162306a36Sopenharmony_ci
269262306a36Sopenharmony_ci/*
269362306a36Sopenharmony_ci * extended message codes:
269462306a36Sopenharmony_ci *
269562306a36Sopenharmony_ci *	code	description
269662306a36Sopenharmony_ci *
269762306a36Sopenharmony_ci *	02h	Reserved
269862306a36Sopenharmony_ci *	00h	MODIFY DATA  POINTER
269962306a36Sopenharmony_ci *	01h	SYNCHRONOUS DATA TRANSFER REQUEST
270062306a36Sopenharmony_ci *	03h	WIDE DATA TRANSFER REQUEST
270162306a36Sopenharmony_ci *   04h - 7Fh	Reserved
270262306a36Sopenharmony_ci *   80h - FFh	Vendor specific
270362306a36Sopenharmony_ci */
270462306a36Sopenharmony_cistatic void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
270562306a36Sopenharmony_ci		u16 *pscsi_status)
270662306a36Sopenharmony_ci{
270762306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb = acb->active_dcb;
270862306a36Sopenharmony_ci	dprintkdbg(DBG_0, "msgin_phase0: (0x%p)\n", srb->cmd);
270962306a36Sopenharmony_ci
271062306a36Sopenharmony_ci	srb->msgin_buf[acb->msg_len++] = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
271162306a36Sopenharmony_ci	if (msgin_completed(srb->msgin_buf, acb->msg_len)) {
271262306a36Sopenharmony_ci		/* Now eval the msg */
271362306a36Sopenharmony_ci		switch (srb->msgin_buf[0]) {
271462306a36Sopenharmony_ci		case DISCONNECT:
271562306a36Sopenharmony_ci			srb->state = SRB_DISCONNECT;
271662306a36Sopenharmony_ci			break;
271762306a36Sopenharmony_ci
271862306a36Sopenharmony_ci		case SIMPLE_QUEUE_TAG:
271962306a36Sopenharmony_ci		case HEAD_OF_QUEUE_TAG:
272062306a36Sopenharmony_ci		case ORDERED_QUEUE_TAG:
272162306a36Sopenharmony_ci			srb =
272262306a36Sopenharmony_ci			    msgin_qtag(acb, dcb,
272362306a36Sopenharmony_ci					      srb->msgin_buf[1]);
272462306a36Sopenharmony_ci			break;
272562306a36Sopenharmony_ci
272662306a36Sopenharmony_ci		case MESSAGE_REJECT:
272762306a36Sopenharmony_ci			DC395x_write16(acb, TRM_S1040_SCSI_CONTROL,
272862306a36Sopenharmony_ci				       DO_CLRATN | DO_DATALATCH);
272962306a36Sopenharmony_ci			/* A sync nego message was rejected ! */
273062306a36Sopenharmony_ci			if (srb->state & SRB_DO_SYNC_NEGO) {
273162306a36Sopenharmony_ci				msgin_set_async(acb, srb);
273262306a36Sopenharmony_ci				break;
273362306a36Sopenharmony_ci			}
273462306a36Sopenharmony_ci			/* A wide nego message was rejected ! */
273562306a36Sopenharmony_ci			if (srb->state & SRB_DO_WIDE_NEGO) {
273662306a36Sopenharmony_ci				msgin_set_nowide(acb, srb);
273762306a36Sopenharmony_ci				break;
273862306a36Sopenharmony_ci			}
273962306a36Sopenharmony_ci			enable_msgout_abort(acb, srb);
274062306a36Sopenharmony_ci			/*srb->state |= SRB_ABORT_SENT */
274162306a36Sopenharmony_ci			break;
274262306a36Sopenharmony_ci
274362306a36Sopenharmony_ci		case EXTENDED_MESSAGE:
274462306a36Sopenharmony_ci			/* SDTR */
274562306a36Sopenharmony_ci			if (srb->msgin_buf[1] == 3
274662306a36Sopenharmony_ci			    && srb->msgin_buf[2] == EXTENDED_SDTR) {
274762306a36Sopenharmony_ci				msgin_set_sync(acb, srb);
274862306a36Sopenharmony_ci				break;
274962306a36Sopenharmony_ci			}
275062306a36Sopenharmony_ci			/* WDTR */
275162306a36Sopenharmony_ci			if (srb->msgin_buf[1] == 2
275262306a36Sopenharmony_ci			    && srb->msgin_buf[2] == EXTENDED_WDTR
275362306a36Sopenharmony_ci			    && srb->msgin_buf[3] <= 2) { /* sanity check ... */
275462306a36Sopenharmony_ci				msgin_set_wide(acb, srb);
275562306a36Sopenharmony_ci				break;
275662306a36Sopenharmony_ci			}
275762306a36Sopenharmony_ci			msgin_reject(acb, srb);
275862306a36Sopenharmony_ci			break;
275962306a36Sopenharmony_ci
276062306a36Sopenharmony_ci		case IGNORE_WIDE_RESIDUE:
276162306a36Sopenharmony_ci			/* Discard  wide residual */
276262306a36Sopenharmony_ci			dprintkdbg(DBG_0, "msgin_phase0: Ignore Wide Residual!\n");
276362306a36Sopenharmony_ci			break;
276462306a36Sopenharmony_ci
276562306a36Sopenharmony_ci		case COMMAND_COMPLETE:
276662306a36Sopenharmony_ci			/* nothing has to be done */
276762306a36Sopenharmony_ci			break;
276862306a36Sopenharmony_ci
276962306a36Sopenharmony_ci		case SAVE_POINTERS:
277062306a36Sopenharmony_ci			/*
277162306a36Sopenharmony_ci			 * SAVE POINTER may be ignored as we have the struct
277262306a36Sopenharmony_ci			 * ScsiReqBlk* associated with the scsi command.
277362306a36Sopenharmony_ci			 */
277462306a36Sopenharmony_ci			dprintkdbg(DBG_0, "msgin_phase0: (0x%p) "
277562306a36Sopenharmony_ci				"SAVE POINTER rem=%i Ignore\n",
277662306a36Sopenharmony_ci				srb->cmd, srb->total_xfer_length);
277762306a36Sopenharmony_ci			break;
277862306a36Sopenharmony_ci
277962306a36Sopenharmony_ci		case RESTORE_POINTERS:
278062306a36Sopenharmony_ci			dprintkdbg(DBG_0, "msgin_phase0: RESTORE POINTER. Ignore\n");
278162306a36Sopenharmony_ci			break;
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_ci		case ABORT:
278462306a36Sopenharmony_ci			dprintkdbg(DBG_0, "msgin_phase0: (0x%p) "
278562306a36Sopenharmony_ci				"<%02i-%i> ABORT msg\n",
278662306a36Sopenharmony_ci				srb->cmd, dcb->target_id,
278762306a36Sopenharmony_ci				dcb->target_lun);
278862306a36Sopenharmony_ci			dcb->flag |= ABORT_DEV_;
278962306a36Sopenharmony_ci			enable_msgout_abort(acb, srb);
279062306a36Sopenharmony_ci			break;
279162306a36Sopenharmony_ci
279262306a36Sopenharmony_ci		default:
279362306a36Sopenharmony_ci			/* reject unknown messages */
279462306a36Sopenharmony_ci			if (srb->msgin_buf[0] & IDENTIFY_BASE) {
279562306a36Sopenharmony_ci				dprintkdbg(DBG_0, "msgin_phase0: Identify msg\n");
279662306a36Sopenharmony_ci				srb->msg_count = 1;
279762306a36Sopenharmony_ci				srb->msgout_buf[0] = dcb->identify_msg;
279862306a36Sopenharmony_ci				DC395x_ENABLE_MSGOUT;
279962306a36Sopenharmony_ci				srb->state |= SRB_MSGOUT;
280062306a36Sopenharmony_ci				/*break; */
280162306a36Sopenharmony_ci			}
280262306a36Sopenharmony_ci			msgin_reject(acb, srb);
280362306a36Sopenharmony_ci		}
280462306a36Sopenharmony_ci
280562306a36Sopenharmony_ci		/* Clear counter and MsgIn state */
280662306a36Sopenharmony_ci		srb->state &= ~SRB_MSGIN;
280762306a36Sopenharmony_ci		acb->msg_len = 0;
280862306a36Sopenharmony_ci	}
280962306a36Sopenharmony_ci	*pscsi_status = PH_BUS_FREE;
281062306a36Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important ... you know! */
281162306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT);
281262306a36Sopenharmony_ci}
281362306a36Sopenharmony_ci
281462306a36Sopenharmony_ci
281562306a36Sopenharmony_cistatic void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
281662306a36Sopenharmony_ci		u16 *pscsi_status)
281762306a36Sopenharmony_ci{
281862306a36Sopenharmony_ci	dprintkdbg(DBG_0, "msgin_phase1: (0x%p)\n", srb->cmd);
281962306a36Sopenharmony_ci	clear_fifo(acb, "msgin_phase1");
282062306a36Sopenharmony_ci	DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1);
282162306a36Sopenharmony_ci	if (!(srb->state & SRB_MSGIN)) {
282262306a36Sopenharmony_ci		srb->state &= ~SRB_DISCONNECT;
282362306a36Sopenharmony_ci		srb->state |= SRB_MSGIN;
282462306a36Sopenharmony_ci	}
282562306a36Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
282662306a36Sopenharmony_ci	/* SCSI command */
282762306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_IN);
282862306a36Sopenharmony_ci}
282962306a36Sopenharmony_ci
283062306a36Sopenharmony_ci
283162306a36Sopenharmony_cistatic void nop0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
283262306a36Sopenharmony_ci		u16 *pscsi_status)
283362306a36Sopenharmony_ci{
283462306a36Sopenharmony_ci}
283562306a36Sopenharmony_ci
283662306a36Sopenharmony_ci
283762306a36Sopenharmony_cistatic void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
283862306a36Sopenharmony_ci		u16 *pscsi_status)
283962306a36Sopenharmony_ci{
284062306a36Sopenharmony_ci}
284162306a36Sopenharmony_ci
284262306a36Sopenharmony_ci
284362306a36Sopenharmony_cistatic void set_xfer_rate(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb)
284462306a36Sopenharmony_ci{
284562306a36Sopenharmony_ci	struct DeviceCtlBlk *i;
284662306a36Sopenharmony_ci
284762306a36Sopenharmony_ci	/* set all lun device's  period, offset */
284862306a36Sopenharmony_ci	if (dcb->identify_msg & 0x07)
284962306a36Sopenharmony_ci		return;
285062306a36Sopenharmony_ci
285162306a36Sopenharmony_ci	if (acb->scan_devices) {
285262306a36Sopenharmony_ci		current_sync_offset = dcb->sync_offset;
285362306a36Sopenharmony_ci		return;
285462306a36Sopenharmony_ci	}
285562306a36Sopenharmony_ci
285662306a36Sopenharmony_ci	list_for_each_entry(i, &acb->dcb_list, list)
285762306a36Sopenharmony_ci		if (i->target_id == dcb->target_id) {
285862306a36Sopenharmony_ci			i->sync_period = dcb->sync_period;
285962306a36Sopenharmony_ci			i->sync_offset = dcb->sync_offset;
286062306a36Sopenharmony_ci			i->sync_mode = dcb->sync_mode;
286162306a36Sopenharmony_ci			i->min_nego_period = dcb->min_nego_period;
286262306a36Sopenharmony_ci		}
286362306a36Sopenharmony_ci}
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci
286662306a36Sopenharmony_cistatic void disconnect(struct AdapterCtlBlk *acb)
286762306a36Sopenharmony_ci{
286862306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb = acb->active_dcb;
286962306a36Sopenharmony_ci	struct ScsiReqBlk *srb;
287062306a36Sopenharmony_ci
287162306a36Sopenharmony_ci	if (!dcb) {
287262306a36Sopenharmony_ci		dprintkl(KERN_ERR, "disconnect: No such device\n");
287362306a36Sopenharmony_ci		udelay(500);
287462306a36Sopenharmony_ci		/* Suspend queue for a while */
287562306a36Sopenharmony_ci		acb->last_reset =
287662306a36Sopenharmony_ci		    jiffies + HZ / 2 +
287762306a36Sopenharmony_ci		    HZ * acb->eeprom.delay_time;
287862306a36Sopenharmony_ci		clear_fifo(acb, "disconnectEx");
287962306a36Sopenharmony_ci		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT);
288062306a36Sopenharmony_ci		return;
288162306a36Sopenharmony_ci	}
288262306a36Sopenharmony_ci	srb = dcb->active_srb;
288362306a36Sopenharmony_ci	acb->active_dcb = NULL;
288462306a36Sopenharmony_ci	dprintkdbg(DBG_0, "disconnect: (0x%p)\n", srb->cmd);
288562306a36Sopenharmony_ci
288662306a36Sopenharmony_ci	srb->scsi_phase = PH_BUS_FREE;	/* initial phase */
288762306a36Sopenharmony_ci	clear_fifo(acb, "disconnect");
288862306a36Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT);
288962306a36Sopenharmony_ci	if (srb->state & SRB_UNEXPECT_RESEL) {
289062306a36Sopenharmony_ci		dprintkl(KERN_ERR,
289162306a36Sopenharmony_ci			"disconnect: Unexpected reselection <%02i-%i>\n",
289262306a36Sopenharmony_ci			dcb->target_id, dcb->target_lun);
289362306a36Sopenharmony_ci		srb->state = 0;
289462306a36Sopenharmony_ci		waiting_process_next(acb);
289562306a36Sopenharmony_ci	} else if (srb->state & SRB_ABORT_SENT) {
289662306a36Sopenharmony_ci		dcb->flag &= ~ABORT_DEV_;
289762306a36Sopenharmony_ci		acb->last_reset = jiffies + HZ / 2 + 1;
289862306a36Sopenharmony_ci		dprintkl(KERN_ERR, "disconnect: SRB_ABORT_SENT\n");
289962306a36Sopenharmony_ci		doing_srb_done(acb, DID_ABORT, srb->cmd, 1);
290062306a36Sopenharmony_ci		waiting_process_next(acb);
290162306a36Sopenharmony_ci	} else {
290262306a36Sopenharmony_ci		if ((srb->state & (SRB_START_ + SRB_MSGOUT))
290362306a36Sopenharmony_ci		    || !(srb->
290462306a36Sopenharmony_ci			 state & (SRB_DISCONNECT | SRB_COMPLETED))) {
290562306a36Sopenharmony_ci			/*
290662306a36Sopenharmony_ci			 * Selection time out
290762306a36Sopenharmony_ci			 * SRB_START_ || SRB_MSGOUT || (!SRB_DISCONNECT && !SRB_COMPLETED)
290862306a36Sopenharmony_ci			 */
290962306a36Sopenharmony_ci			/* Unexp. Disc / Sel Timeout */
291062306a36Sopenharmony_ci			if (srb->state != SRB_START_
291162306a36Sopenharmony_ci			    && srb->state != SRB_MSGOUT) {
291262306a36Sopenharmony_ci				srb->state = SRB_READY;
291362306a36Sopenharmony_ci				dprintkl(KERN_DEBUG,
291462306a36Sopenharmony_ci					"disconnect: (0x%p) Unexpected\n",
291562306a36Sopenharmony_ci					srb->cmd);
291662306a36Sopenharmony_ci				srb->target_status = SCSI_STAT_SEL_TIMEOUT;
291762306a36Sopenharmony_ci				goto disc1;
291862306a36Sopenharmony_ci			} else {
291962306a36Sopenharmony_ci				/* Normal selection timeout */
292062306a36Sopenharmony_ci				dprintkdbg(DBG_KG, "disconnect: (0x%p) "
292162306a36Sopenharmony_ci					"<%02i-%i> SelTO\n", srb->cmd,
292262306a36Sopenharmony_ci					dcb->target_id, dcb->target_lun);
292362306a36Sopenharmony_ci				if (srb->retry_count++ > DC395x_MAX_RETRIES
292462306a36Sopenharmony_ci				    || acb->scan_devices) {
292562306a36Sopenharmony_ci					srb->target_status =
292662306a36Sopenharmony_ci					    SCSI_STAT_SEL_TIMEOUT;
292762306a36Sopenharmony_ci					goto disc1;
292862306a36Sopenharmony_ci				}
292962306a36Sopenharmony_ci				free_tag(dcb, srb);
293062306a36Sopenharmony_ci				list_move(&srb->list, &dcb->srb_waiting_list);
293162306a36Sopenharmony_ci				dprintkdbg(DBG_KG,
293262306a36Sopenharmony_ci					"disconnect: (0x%p) Retry\n",
293362306a36Sopenharmony_ci					srb->cmd);
293462306a36Sopenharmony_ci				waiting_set_timer(acb, HZ / 20);
293562306a36Sopenharmony_ci			}
293662306a36Sopenharmony_ci		} else if (srb->state & SRB_DISCONNECT) {
293762306a36Sopenharmony_ci			u8 bval = DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL);
293862306a36Sopenharmony_ci			/*
293962306a36Sopenharmony_ci			 * SRB_DISCONNECT (This is what we expect!)
294062306a36Sopenharmony_ci			 */
294162306a36Sopenharmony_ci			if (bval & 0x40) {
294262306a36Sopenharmony_ci				dprintkdbg(DBG_0, "disconnect: SCSI bus stat "
294362306a36Sopenharmony_ci					" 0x%02x: ACK set! Other controllers?\n",
294462306a36Sopenharmony_ci					bval);
294562306a36Sopenharmony_ci				/* It could come from another initiator, therefore don't do much ! */
294662306a36Sopenharmony_ci			} else
294762306a36Sopenharmony_ci				waiting_process_next(acb);
294862306a36Sopenharmony_ci		} else if (srb->state & SRB_COMPLETED) {
294962306a36Sopenharmony_ci		      disc1:
295062306a36Sopenharmony_ci			/*
295162306a36Sopenharmony_ci			 ** SRB_COMPLETED
295262306a36Sopenharmony_ci			 */
295362306a36Sopenharmony_ci			free_tag(dcb, srb);
295462306a36Sopenharmony_ci			dcb->active_srb = NULL;
295562306a36Sopenharmony_ci			srb->state = SRB_FREE;
295662306a36Sopenharmony_ci			srb_done(acb, dcb, srb);
295762306a36Sopenharmony_ci		}
295862306a36Sopenharmony_ci	}
295962306a36Sopenharmony_ci}
296062306a36Sopenharmony_ci
296162306a36Sopenharmony_ci
296262306a36Sopenharmony_cistatic void reselect(struct AdapterCtlBlk *acb)
296362306a36Sopenharmony_ci{
296462306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb = acb->active_dcb;
296562306a36Sopenharmony_ci	struct ScsiReqBlk *srb = NULL;
296662306a36Sopenharmony_ci	u16 rsel_tar_lun_id;
296762306a36Sopenharmony_ci	u8 id, lun;
296862306a36Sopenharmony_ci	dprintkdbg(DBG_0, "reselect: acb=%p\n", acb);
296962306a36Sopenharmony_ci
297062306a36Sopenharmony_ci	clear_fifo(acb, "reselect");
297162306a36Sopenharmony_ci	/*DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT | DO_DATALATCH); */
297262306a36Sopenharmony_ci	/* Read Reselected Target ID and LUN */
297362306a36Sopenharmony_ci	rsel_tar_lun_id = DC395x_read16(acb, TRM_S1040_SCSI_TARGETID);
297462306a36Sopenharmony_ci	if (dcb) {		/* Arbitration lost but Reselection win */
297562306a36Sopenharmony_ci		srb = dcb->active_srb;
297662306a36Sopenharmony_ci		if (!srb) {
297762306a36Sopenharmony_ci			dprintkl(KERN_DEBUG, "reselect: Arb lost Resel won, "
297862306a36Sopenharmony_ci				"but active_srb == NULL\n");
297962306a36Sopenharmony_ci			DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
298062306a36Sopenharmony_ci			return;
298162306a36Sopenharmony_ci		}
298262306a36Sopenharmony_ci		/* Why the if ? */
298362306a36Sopenharmony_ci		if (!acb->scan_devices) {
298462306a36Sopenharmony_ci			dprintkdbg(DBG_KG, "reselect: (0x%p) <%02i-%i> "
298562306a36Sopenharmony_ci				"Arb lost but Resel win rsel=%i stat=0x%04x\n",
298662306a36Sopenharmony_ci				srb->cmd, dcb->target_id,
298762306a36Sopenharmony_ci				dcb->target_lun, rsel_tar_lun_id,
298862306a36Sopenharmony_ci				DC395x_read16(acb, TRM_S1040_SCSI_STATUS));
298962306a36Sopenharmony_ci			/*srb->state |= SRB_DISCONNECT; */
299062306a36Sopenharmony_ci
299162306a36Sopenharmony_ci			srb->state = SRB_READY;
299262306a36Sopenharmony_ci			free_tag(dcb, srb);
299362306a36Sopenharmony_ci			list_move(&srb->list, &dcb->srb_waiting_list);
299462306a36Sopenharmony_ci			waiting_set_timer(acb, HZ / 20);
299562306a36Sopenharmony_ci
299662306a36Sopenharmony_ci			/* return; */
299762306a36Sopenharmony_ci		}
299862306a36Sopenharmony_ci	}
299962306a36Sopenharmony_ci	/* Read Reselected Target Id and LUN */
300062306a36Sopenharmony_ci	if (!(rsel_tar_lun_id & (IDENTIFY_BASE << 8)))
300162306a36Sopenharmony_ci		dprintkl(KERN_DEBUG, "reselect: Expects identify msg. "
300262306a36Sopenharmony_ci			"Got %i!\n", rsel_tar_lun_id);
300362306a36Sopenharmony_ci	id = rsel_tar_lun_id & 0xff;
300462306a36Sopenharmony_ci	lun = (rsel_tar_lun_id >> 8) & 7;
300562306a36Sopenharmony_ci	dcb = find_dcb(acb, id, lun);
300662306a36Sopenharmony_ci	if (!dcb) {
300762306a36Sopenharmony_ci		dprintkl(KERN_ERR, "reselect: From non existent device "
300862306a36Sopenharmony_ci			"<%02i-%i>\n", id, lun);
300962306a36Sopenharmony_ci		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
301062306a36Sopenharmony_ci		return;
301162306a36Sopenharmony_ci	}
301262306a36Sopenharmony_ci	acb->active_dcb = dcb;
301362306a36Sopenharmony_ci
301462306a36Sopenharmony_ci	if (!(dcb->dev_mode & NTC_DO_DISCONNECT))
301562306a36Sopenharmony_ci		dprintkl(KERN_DEBUG, "reselect: in spite of forbidden "
301662306a36Sopenharmony_ci			"disconnection? <%02i-%i>\n",
301762306a36Sopenharmony_ci			dcb->target_id, dcb->target_lun);
301862306a36Sopenharmony_ci
301962306a36Sopenharmony_ci	if (dcb->sync_mode & EN_TAG_QUEUEING) {
302062306a36Sopenharmony_ci		srb = acb->tmp_srb;
302162306a36Sopenharmony_ci		dcb->active_srb = srb;
302262306a36Sopenharmony_ci	} else {
302362306a36Sopenharmony_ci		/* There can be only one! */
302462306a36Sopenharmony_ci		srb = dcb->active_srb;
302562306a36Sopenharmony_ci		if (!srb || !(srb->state & SRB_DISCONNECT)) {
302662306a36Sopenharmony_ci			/*
302762306a36Sopenharmony_ci			 * abort command
302862306a36Sopenharmony_ci			 */
302962306a36Sopenharmony_ci			dprintkl(KERN_DEBUG,
303062306a36Sopenharmony_ci				"reselect: w/o disconnected cmds <%02i-%i>\n",
303162306a36Sopenharmony_ci				dcb->target_id, dcb->target_lun);
303262306a36Sopenharmony_ci			srb = acb->tmp_srb;
303362306a36Sopenharmony_ci			srb->state = SRB_UNEXPECT_RESEL;
303462306a36Sopenharmony_ci			dcb->active_srb = srb;
303562306a36Sopenharmony_ci			enable_msgout_abort(acb, srb);
303662306a36Sopenharmony_ci		} else {
303762306a36Sopenharmony_ci			if (dcb->flag & ABORT_DEV_) {
303862306a36Sopenharmony_ci				/*srb->state = SRB_ABORT_SENT; */
303962306a36Sopenharmony_ci				enable_msgout_abort(acb, srb);
304062306a36Sopenharmony_ci			} else
304162306a36Sopenharmony_ci				srb->state = SRB_DATA_XFER;
304262306a36Sopenharmony_ci
304362306a36Sopenharmony_ci		}
304462306a36Sopenharmony_ci	}
304562306a36Sopenharmony_ci	srb->scsi_phase = PH_BUS_FREE;	/* initial phase */
304662306a36Sopenharmony_ci
304762306a36Sopenharmony_ci	/* Program HA ID, target ID, period and offset */
304862306a36Sopenharmony_ci	dprintkdbg(DBG_0, "reselect: select <%i>\n", dcb->target_id);
304962306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_HOSTID, acb->scsi_host->this_id);	/* host   ID */
305062306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id);		/* target ID */
305162306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, dcb->sync_offset);		/* offset    */
305262306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_SYNC, dcb->sync_period);		/* sync period, wide */
305362306a36Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);		/* it's important for atn stop */
305462306a36Sopenharmony_ci	/* SCSI command */
305562306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT);
305662306a36Sopenharmony_ci}
305762306a36Sopenharmony_ci
305862306a36Sopenharmony_ci
305962306a36Sopenharmony_cistatic inline u8 tagq_blacklist(char *name)
306062306a36Sopenharmony_ci{
306162306a36Sopenharmony_ci#ifndef DC395x_NO_TAGQ
306262306a36Sopenharmony_ci#if 0
306362306a36Sopenharmony_ci	u8 i;
306462306a36Sopenharmony_ci	for (i = 0; i < BADDEVCNT; i++)
306562306a36Sopenharmony_ci		if (memcmp(name, DC395x_baddevname1[i], 28) == 0)
306662306a36Sopenharmony_ci			return 1;
306762306a36Sopenharmony_ci#endif
306862306a36Sopenharmony_ci	return 0;
306962306a36Sopenharmony_ci#else
307062306a36Sopenharmony_ci	return 1;
307162306a36Sopenharmony_ci#endif
307262306a36Sopenharmony_ci}
307362306a36Sopenharmony_ci
307462306a36Sopenharmony_ci
307562306a36Sopenharmony_cistatic void disc_tagq_set(struct DeviceCtlBlk *dcb, struct ScsiInqData *ptr)
307662306a36Sopenharmony_ci{
307762306a36Sopenharmony_ci	/* Check for SCSI format (ANSI and Response data format) */
307862306a36Sopenharmony_ci	if ((ptr->Vers & 0x07) >= 2 || (ptr->RDF & 0x0F) == 2) {
307962306a36Sopenharmony_ci		if ((ptr->Flags & SCSI_INQ_CMDQUEUE)
308062306a36Sopenharmony_ci		    && (dcb->dev_mode & NTC_DO_TAG_QUEUEING) &&
308162306a36Sopenharmony_ci		    /*(dcb->dev_mode & NTC_DO_DISCONNECT) */
308262306a36Sopenharmony_ci		    /* ((dcb->dev_type == TYPE_DISK)
308362306a36Sopenharmony_ci		       || (dcb->dev_type == TYPE_MOD)) && */
308462306a36Sopenharmony_ci		    !tagq_blacklist(((char *)ptr) + 8)) {
308562306a36Sopenharmony_ci			if (dcb->max_command == 1)
308662306a36Sopenharmony_ci				dcb->max_command =
308762306a36Sopenharmony_ci				    dcb->acb->tag_max_num;
308862306a36Sopenharmony_ci			dcb->sync_mode |= EN_TAG_QUEUEING;
308962306a36Sopenharmony_ci			/*dcb->tag_mask = 0; */
309062306a36Sopenharmony_ci		} else
309162306a36Sopenharmony_ci			dcb->max_command = 1;
309262306a36Sopenharmony_ci	}
309362306a36Sopenharmony_ci}
309462306a36Sopenharmony_ci
309562306a36Sopenharmony_ci
309662306a36Sopenharmony_cistatic void add_dev(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
309762306a36Sopenharmony_ci		struct ScsiInqData *ptr)
309862306a36Sopenharmony_ci{
309962306a36Sopenharmony_ci	u8 bval1 = ptr->DevType & SCSI_DEVTYPE;
310062306a36Sopenharmony_ci	dcb->dev_type = bval1;
310162306a36Sopenharmony_ci	/* if (bval1 == TYPE_DISK || bval1 == TYPE_MOD) */
310262306a36Sopenharmony_ci	disc_tagq_set(dcb, ptr);
310362306a36Sopenharmony_ci}
310462306a36Sopenharmony_ci
310562306a36Sopenharmony_ci
310662306a36Sopenharmony_ci/* unmap mapped pci regions from SRB */
310762306a36Sopenharmony_cistatic void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
310862306a36Sopenharmony_ci{
310962306a36Sopenharmony_ci	struct scsi_cmnd *cmd = srb->cmd;
311062306a36Sopenharmony_ci	enum dma_data_direction dir = cmd->sc_data_direction;
311162306a36Sopenharmony_ci
311262306a36Sopenharmony_ci	if (scsi_sg_count(cmd) && dir != DMA_NONE) {
311362306a36Sopenharmony_ci		/* unmap DC395x SG list */
311462306a36Sopenharmony_ci		dprintkdbg(DBG_SG, "pci_unmap_srb: list=%08x(%05x)\n",
311562306a36Sopenharmony_ci			srb->sg_bus_addr, SEGMENTX_LEN);
311662306a36Sopenharmony_ci		dma_unmap_single(&acb->dev->dev, srb->sg_bus_addr, SEGMENTX_LEN,
311762306a36Sopenharmony_ci				DMA_TO_DEVICE);
311862306a36Sopenharmony_ci		dprintkdbg(DBG_SG, "pci_unmap_srb: segs=%i buffer=%p\n",
311962306a36Sopenharmony_ci			   scsi_sg_count(cmd), scsi_bufflen(cmd));
312062306a36Sopenharmony_ci		/* unmap the sg segments */
312162306a36Sopenharmony_ci		scsi_dma_unmap(cmd);
312262306a36Sopenharmony_ci	}
312362306a36Sopenharmony_ci}
312462306a36Sopenharmony_ci
312562306a36Sopenharmony_ci
312662306a36Sopenharmony_ci/* unmap mapped pci sense buffer from SRB */
312762306a36Sopenharmony_cistatic void pci_unmap_srb_sense(struct AdapterCtlBlk *acb,
312862306a36Sopenharmony_ci		struct ScsiReqBlk *srb)
312962306a36Sopenharmony_ci{
313062306a36Sopenharmony_ci	if (!(srb->flag & AUTO_REQSENSE))
313162306a36Sopenharmony_ci		return;
313262306a36Sopenharmony_ci	/* Unmap sense buffer */
313362306a36Sopenharmony_ci	dprintkdbg(DBG_SG, "pci_unmap_srb_sense: buffer=%08x\n",
313462306a36Sopenharmony_ci	       srb->segment_x[0].address);
313562306a36Sopenharmony_ci	dma_unmap_single(&acb->dev->dev, srb->segment_x[0].address,
313662306a36Sopenharmony_ci			 srb->segment_x[0].length, DMA_FROM_DEVICE);
313762306a36Sopenharmony_ci	/* Restore SG stuff */
313862306a36Sopenharmony_ci	srb->total_xfer_length = srb->xferred;
313962306a36Sopenharmony_ci	srb->segment_x[0].address =
314062306a36Sopenharmony_ci	    srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].address;
314162306a36Sopenharmony_ci	srb->segment_x[0].length =
314262306a36Sopenharmony_ci	    srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].length;
314362306a36Sopenharmony_ci}
314462306a36Sopenharmony_ci
314562306a36Sopenharmony_ci
314662306a36Sopenharmony_ci/*
314762306a36Sopenharmony_ci * Complete execution of a SCSI command
314862306a36Sopenharmony_ci * Signal completion to the generic SCSI driver
314962306a36Sopenharmony_ci */
315062306a36Sopenharmony_cistatic void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
315162306a36Sopenharmony_ci		struct ScsiReqBlk *srb)
315262306a36Sopenharmony_ci{
315362306a36Sopenharmony_ci	u8 tempcnt, status;
315462306a36Sopenharmony_ci	struct scsi_cmnd *cmd = srb->cmd;
315562306a36Sopenharmony_ci	enum dma_data_direction dir = cmd->sc_data_direction;
315662306a36Sopenharmony_ci	int ckc_only = 1;
315762306a36Sopenharmony_ci
315862306a36Sopenharmony_ci	dprintkdbg(DBG_1, "srb_done: (0x%p) <%02i-%i>\n", srb->cmd,
315962306a36Sopenharmony_ci		srb->cmd->device->id, (u8)srb->cmd->device->lun);
316062306a36Sopenharmony_ci	dprintkdbg(DBG_SG, "srb_done: srb=%p sg=%i(%i/%i) buf=%p\n",
316162306a36Sopenharmony_ci		   srb, scsi_sg_count(cmd), srb->sg_index, srb->sg_count,
316262306a36Sopenharmony_ci		   scsi_sgtalbe(cmd));
316362306a36Sopenharmony_ci	status = srb->target_status;
316462306a36Sopenharmony_ci	set_host_byte(cmd, DID_OK);
316562306a36Sopenharmony_ci	set_status_byte(cmd, SAM_STAT_GOOD);
316662306a36Sopenharmony_ci	if (srb->flag & AUTO_REQSENSE) {
316762306a36Sopenharmony_ci		dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE1\n");
316862306a36Sopenharmony_ci		pci_unmap_srb_sense(acb, srb);
316962306a36Sopenharmony_ci		/*
317062306a36Sopenharmony_ci		 ** target status..........................
317162306a36Sopenharmony_ci		 */
317262306a36Sopenharmony_ci		srb->flag &= ~AUTO_REQSENSE;
317362306a36Sopenharmony_ci		srb->adapter_status = 0;
317462306a36Sopenharmony_ci		srb->target_status = SAM_STAT_CHECK_CONDITION;
317562306a36Sopenharmony_ci		if (debug_enabled(DBG_1)) {
317662306a36Sopenharmony_ci			switch (cmd->sense_buffer[2] & 0x0f) {
317762306a36Sopenharmony_ci			case NOT_READY:
317862306a36Sopenharmony_ci				dprintkl(KERN_DEBUG,
317962306a36Sopenharmony_ci				     "ReqSense: NOT_READY cmnd=0x%02x <%02i-%i> stat=%i scan=%i ",
318062306a36Sopenharmony_ci				     cmd->cmnd[0], dcb->target_id,
318162306a36Sopenharmony_ci				     dcb->target_lun, status, acb->scan_devices);
318262306a36Sopenharmony_ci				break;
318362306a36Sopenharmony_ci			case UNIT_ATTENTION:
318462306a36Sopenharmony_ci				dprintkl(KERN_DEBUG,
318562306a36Sopenharmony_ci				     "ReqSense: UNIT_ATTENTION cmnd=0x%02x <%02i-%i> stat=%i scan=%i ",
318662306a36Sopenharmony_ci				     cmd->cmnd[0], dcb->target_id,
318762306a36Sopenharmony_ci				     dcb->target_lun, status, acb->scan_devices);
318862306a36Sopenharmony_ci				break;
318962306a36Sopenharmony_ci			case ILLEGAL_REQUEST:
319062306a36Sopenharmony_ci				dprintkl(KERN_DEBUG,
319162306a36Sopenharmony_ci				     "ReqSense: ILLEGAL_REQUEST cmnd=0x%02x <%02i-%i> stat=%i scan=%i ",
319262306a36Sopenharmony_ci				     cmd->cmnd[0], dcb->target_id,
319362306a36Sopenharmony_ci				     dcb->target_lun, status, acb->scan_devices);
319462306a36Sopenharmony_ci				break;
319562306a36Sopenharmony_ci			case MEDIUM_ERROR:
319662306a36Sopenharmony_ci				dprintkl(KERN_DEBUG,
319762306a36Sopenharmony_ci				     "ReqSense: MEDIUM_ERROR cmnd=0x%02x <%02i-%i> stat=%i scan=%i ",
319862306a36Sopenharmony_ci				     cmd->cmnd[0], dcb->target_id,
319962306a36Sopenharmony_ci				     dcb->target_lun, status, acb->scan_devices);
320062306a36Sopenharmony_ci				break;
320162306a36Sopenharmony_ci			case HARDWARE_ERROR:
320262306a36Sopenharmony_ci				dprintkl(KERN_DEBUG,
320362306a36Sopenharmony_ci				     "ReqSense: HARDWARE_ERROR cmnd=0x%02x <%02i-%i> stat=%i scan=%i ",
320462306a36Sopenharmony_ci				     cmd->cmnd[0], dcb->target_id,
320562306a36Sopenharmony_ci				     dcb->target_lun, status, acb->scan_devices);
320662306a36Sopenharmony_ci				break;
320762306a36Sopenharmony_ci			}
320862306a36Sopenharmony_ci			if (cmd->sense_buffer[7] >= 6)
320962306a36Sopenharmony_ci				printk("sense=0x%02x ASC=0x%02x ASCQ=0x%02x "
321062306a36Sopenharmony_ci					"(0x%08x 0x%08x)\n",
321162306a36Sopenharmony_ci					cmd->sense_buffer[2], cmd->sense_buffer[12],
321262306a36Sopenharmony_ci					cmd->sense_buffer[13],
321362306a36Sopenharmony_ci					*((unsigned int *)(cmd->sense_buffer + 3)),
321462306a36Sopenharmony_ci					*((unsigned int *)(cmd->sense_buffer + 8)));
321562306a36Sopenharmony_ci			else
321662306a36Sopenharmony_ci				printk("sense=0x%02x No ASC/ASCQ (0x%08x)\n",
321762306a36Sopenharmony_ci					cmd->sense_buffer[2],
321862306a36Sopenharmony_ci					*((unsigned int *)(cmd->sense_buffer + 3)));
321962306a36Sopenharmony_ci		}
322062306a36Sopenharmony_ci
322162306a36Sopenharmony_ci		if (status == SAM_STAT_CHECK_CONDITION) {
322262306a36Sopenharmony_ci			set_host_byte(cmd, DID_BAD_TARGET);
322362306a36Sopenharmony_ci			goto ckc_e;
322462306a36Sopenharmony_ci		}
322562306a36Sopenharmony_ci		dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE2\n");
322662306a36Sopenharmony_ci
322762306a36Sopenharmony_ci		set_status_byte(cmd, SAM_STAT_CHECK_CONDITION);
322862306a36Sopenharmony_ci
322962306a36Sopenharmony_ci		goto ckc_e;
323062306a36Sopenharmony_ci	}
323162306a36Sopenharmony_ci
323262306a36Sopenharmony_ci/*************************************************************/
323362306a36Sopenharmony_ci	if (status) {
323462306a36Sopenharmony_ci		/*
323562306a36Sopenharmony_ci		 * target status..........................
323662306a36Sopenharmony_ci		 */
323762306a36Sopenharmony_ci		if (status == SAM_STAT_CHECK_CONDITION) {
323862306a36Sopenharmony_ci			request_sense(acb, dcb, srb);
323962306a36Sopenharmony_ci			return;
324062306a36Sopenharmony_ci		} else if (status == SAM_STAT_TASK_SET_FULL) {
324162306a36Sopenharmony_ci			tempcnt = (u8)list_size(&dcb->srb_going_list);
324262306a36Sopenharmony_ci			dprintkl(KERN_INFO, "QUEUE_FULL for dev <%02i-%i> with %i cmnds\n",
324362306a36Sopenharmony_ci			     dcb->target_id, dcb->target_lun, tempcnt);
324462306a36Sopenharmony_ci			if (tempcnt > 1)
324562306a36Sopenharmony_ci				tempcnt--;
324662306a36Sopenharmony_ci			dcb->max_command = tempcnt;
324762306a36Sopenharmony_ci			free_tag(dcb, srb);
324862306a36Sopenharmony_ci			list_move(&srb->list, &dcb->srb_waiting_list);
324962306a36Sopenharmony_ci			waiting_set_timer(acb, HZ / 20);
325062306a36Sopenharmony_ci			srb->adapter_status = 0;
325162306a36Sopenharmony_ci			srb->target_status = 0;
325262306a36Sopenharmony_ci			return;
325362306a36Sopenharmony_ci		} else if (status == SCSI_STAT_SEL_TIMEOUT) {
325462306a36Sopenharmony_ci			srb->adapter_status = H_SEL_TIMEOUT;
325562306a36Sopenharmony_ci			srb->target_status = 0;
325662306a36Sopenharmony_ci			set_host_byte(cmd, DID_NO_CONNECT);
325762306a36Sopenharmony_ci		} else {
325862306a36Sopenharmony_ci			srb->adapter_status = 0;
325962306a36Sopenharmony_ci			set_host_byte(cmd, DID_ERROR);
326062306a36Sopenharmony_ci			set_status_byte(cmd, status);
326162306a36Sopenharmony_ci		}
326262306a36Sopenharmony_ci	} else {
326362306a36Sopenharmony_ci		/*
326462306a36Sopenharmony_ci		 ** process initiator status..........................
326562306a36Sopenharmony_ci		 */
326662306a36Sopenharmony_ci		status = srb->adapter_status;
326762306a36Sopenharmony_ci		if (status & H_OVER_UNDER_RUN) {
326862306a36Sopenharmony_ci			srb->target_status = 0;
326962306a36Sopenharmony_ci			scsi_msg_to_host_byte(cmd, srb->end_message);
327062306a36Sopenharmony_ci		} else if (srb->status & PARITY_ERROR) {
327162306a36Sopenharmony_ci			set_host_byte(cmd, DID_PARITY);
327262306a36Sopenharmony_ci		} else {	/* No error */
327362306a36Sopenharmony_ci
327462306a36Sopenharmony_ci			srb->adapter_status = 0;
327562306a36Sopenharmony_ci			srb->target_status = 0;
327662306a36Sopenharmony_ci		}
327762306a36Sopenharmony_ci	}
327862306a36Sopenharmony_ci
327962306a36Sopenharmony_ci	ckc_only = 0;
328062306a36Sopenharmony_ci/* Check Error Conditions */
328162306a36Sopenharmony_ci      ckc_e:
328262306a36Sopenharmony_ci
328362306a36Sopenharmony_ci	pci_unmap_srb(acb, srb);
328462306a36Sopenharmony_ci
328562306a36Sopenharmony_ci	if (cmd->cmnd[0] == INQUIRY) {
328662306a36Sopenharmony_ci		unsigned char *base = NULL;
328762306a36Sopenharmony_ci		struct ScsiInqData *ptr;
328862306a36Sopenharmony_ci		unsigned long flags = 0;
328962306a36Sopenharmony_ci		struct scatterlist* sg = scsi_sglist(cmd);
329062306a36Sopenharmony_ci		size_t offset = 0, len = sizeof(struct ScsiInqData);
329162306a36Sopenharmony_ci
329262306a36Sopenharmony_ci		local_irq_save(flags);
329362306a36Sopenharmony_ci		base = scsi_kmap_atomic_sg(sg, scsi_sg_count(cmd), &offset, &len);
329462306a36Sopenharmony_ci		ptr = (struct ScsiInqData *)(base + offset);
329562306a36Sopenharmony_ci
329662306a36Sopenharmony_ci		if (!ckc_only && get_host_byte(cmd) == DID_OK
329762306a36Sopenharmony_ci		    && cmd->cmnd[2] == 0 && scsi_bufflen(cmd) >= 8
329862306a36Sopenharmony_ci		    && dir != DMA_NONE && ptr && (ptr->Vers & 0x07) >= 2)
329962306a36Sopenharmony_ci			dcb->inquiry7 = ptr->Flags;
330062306a36Sopenharmony_ci
330162306a36Sopenharmony_ci	/*if( srb->cmd->cmnd[0] == INQUIRY && */
330262306a36Sopenharmony_ci	/*  (host_byte(cmd->result) == DID_OK || status_byte(cmd->result) & CHECK_CONDITION) ) */
330362306a36Sopenharmony_ci		if ((get_host_byte(cmd) == DID_OK) ||
330462306a36Sopenharmony_ci		    (get_status_byte(cmd) == SAM_STAT_CHECK_CONDITION)) {
330562306a36Sopenharmony_ci			if (!dcb->init_tcq_flag) {
330662306a36Sopenharmony_ci				add_dev(acb, dcb, ptr);
330762306a36Sopenharmony_ci				dcb->init_tcq_flag = 1;
330862306a36Sopenharmony_ci			}
330962306a36Sopenharmony_ci		}
331062306a36Sopenharmony_ci
331162306a36Sopenharmony_ci		scsi_kunmap_atomic_sg(base);
331262306a36Sopenharmony_ci		local_irq_restore(flags);
331362306a36Sopenharmony_ci	}
331462306a36Sopenharmony_ci
331562306a36Sopenharmony_ci	/* Here is the info for Doug Gilbert's sg3 ... */
331662306a36Sopenharmony_ci	scsi_set_resid(cmd, srb->total_xfer_length);
331762306a36Sopenharmony_ci	if (debug_enabled(DBG_KG)) {
331862306a36Sopenharmony_ci		if (srb->total_xfer_length)
331962306a36Sopenharmony_ci			dprintkdbg(DBG_KG, "srb_done: (0x%p) <%02i-%i> "
332062306a36Sopenharmony_ci				"cmnd=0x%02x Missed %i bytes\n",
332162306a36Sopenharmony_ci				cmd, cmd->device->id, (u8)cmd->device->lun,
332262306a36Sopenharmony_ci				cmd->cmnd[0], srb->total_xfer_length);
332362306a36Sopenharmony_ci	}
332462306a36Sopenharmony_ci
332562306a36Sopenharmony_ci	if (srb != acb->tmp_srb) {
332662306a36Sopenharmony_ci		/* Add to free list */
332762306a36Sopenharmony_ci		dprintkdbg(DBG_0, "srb_done: (0x%p) done result=0x%08x\n",
332862306a36Sopenharmony_ci			   cmd, cmd->result);
332962306a36Sopenharmony_ci		list_move_tail(&srb->list, &acb->srb_free_list);
333062306a36Sopenharmony_ci	} else {
333162306a36Sopenharmony_ci		dprintkl(KERN_ERR, "srb_done: ERROR! Completed cmd with tmp_srb\n");
333262306a36Sopenharmony_ci	}
333362306a36Sopenharmony_ci
333462306a36Sopenharmony_ci	scsi_done(cmd);
333562306a36Sopenharmony_ci	waiting_process_next(acb);
333662306a36Sopenharmony_ci}
333762306a36Sopenharmony_ci
333862306a36Sopenharmony_ci
333962306a36Sopenharmony_ci/* abort all cmds in our queues */
334062306a36Sopenharmony_cistatic void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag,
334162306a36Sopenharmony_ci		struct scsi_cmnd *cmd, u8 force)
334262306a36Sopenharmony_ci{
334362306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb;
334462306a36Sopenharmony_ci	dprintkl(KERN_INFO, "doing_srb_done: pids ");
334562306a36Sopenharmony_ci
334662306a36Sopenharmony_ci	list_for_each_entry(dcb, &acb->dcb_list, list) {
334762306a36Sopenharmony_ci		struct ScsiReqBlk *srb;
334862306a36Sopenharmony_ci		struct ScsiReqBlk *tmp;
334962306a36Sopenharmony_ci		struct scsi_cmnd *p;
335062306a36Sopenharmony_ci
335162306a36Sopenharmony_ci		list_for_each_entry_safe(srb, tmp, &dcb->srb_going_list, list) {
335262306a36Sopenharmony_ci			p = srb->cmd;
335362306a36Sopenharmony_ci			printk("G:%p(%02i-%i) ", p,
335462306a36Sopenharmony_ci			       p->device->id, (u8)p->device->lun);
335562306a36Sopenharmony_ci			list_del(&srb->list);
335662306a36Sopenharmony_ci			free_tag(dcb, srb);
335762306a36Sopenharmony_ci			list_add_tail(&srb->list, &acb->srb_free_list);
335862306a36Sopenharmony_ci			set_host_byte(p, did_flag);
335962306a36Sopenharmony_ci			set_status_byte(p, SAM_STAT_GOOD);
336062306a36Sopenharmony_ci			pci_unmap_srb_sense(acb, srb);
336162306a36Sopenharmony_ci			pci_unmap_srb(acb, srb);
336262306a36Sopenharmony_ci			if (force) {
336362306a36Sopenharmony_ci				/* For new EH, we normally don't need to give commands back,
336462306a36Sopenharmony_ci				 * as they all complete or all time out */
336562306a36Sopenharmony_ci				scsi_done(p);
336662306a36Sopenharmony_ci			}
336762306a36Sopenharmony_ci		}
336862306a36Sopenharmony_ci		if (!list_empty(&dcb->srb_going_list))
336962306a36Sopenharmony_ci			dprintkl(KERN_DEBUG,
337062306a36Sopenharmony_ci			       "How could the ML send cmnds to the Going queue? <%02i-%i>\n",
337162306a36Sopenharmony_ci			       dcb->target_id, dcb->target_lun);
337262306a36Sopenharmony_ci		if (dcb->tag_mask)
337362306a36Sopenharmony_ci			dprintkl(KERN_DEBUG,
337462306a36Sopenharmony_ci			       "tag_mask for <%02i-%i> should be empty, is %08x!\n",
337562306a36Sopenharmony_ci			       dcb->target_id, dcb->target_lun,
337662306a36Sopenharmony_ci			       dcb->tag_mask);
337762306a36Sopenharmony_ci
337862306a36Sopenharmony_ci		/* Waiting queue */
337962306a36Sopenharmony_ci		list_for_each_entry_safe(srb, tmp, &dcb->srb_waiting_list, list) {
338062306a36Sopenharmony_ci			p = srb->cmd;
338162306a36Sopenharmony_ci
338262306a36Sopenharmony_ci			printk("W:%p<%02i-%i>", p, p->device->id,
338362306a36Sopenharmony_ci			       (u8)p->device->lun);
338462306a36Sopenharmony_ci			list_move_tail(&srb->list, &acb->srb_free_list);
338562306a36Sopenharmony_ci			set_host_byte(p, did_flag);
338662306a36Sopenharmony_ci			set_status_byte(p, SAM_STAT_GOOD);
338762306a36Sopenharmony_ci			pci_unmap_srb_sense(acb, srb);
338862306a36Sopenharmony_ci			pci_unmap_srb(acb, srb);
338962306a36Sopenharmony_ci			if (force) {
339062306a36Sopenharmony_ci				/* For new EH, we normally don't need to give commands back,
339162306a36Sopenharmony_ci				 * as they all complete or all time out */
339262306a36Sopenharmony_ci				scsi_done(cmd);
339362306a36Sopenharmony_ci			}
339462306a36Sopenharmony_ci		}
339562306a36Sopenharmony_ci		if (!list_empty(&dcb->srb_waiting_list))
339662306a36Sopenharmony_ci			dprintkl(KERN_DEBUG, "ML queued %i cmnds again to <%02i-%i>\n",
339762306a36Sopenharmony_ci			     list_size(&dcb->srb_waiting_list), dcb->target_id,
339862306a36Sopenharmony_ci			     dcb->target_lun);
339962306a36Sopenharmony_ci		dcb->flag &= ~ABORT_DEV_;
340062306a36Sopenharmony_ci	}
340162306a36Sopenharmony_ci	printk("\n");
340262306a36Sopenharmony_ci}
340362306a36Sopenharmony_ci
340462306a36Sopenharmony_ci
340562306a36Sopenharmony_cistatic void reset_scsi_bus(struct AdapterCtlBlk *acb)
340662306a36Sopenharmony_ci{
340762306a36Sopenharmony_ci	dprintkdbg(DBG_0, "reset_scsi_bus: acb=%p\n", acb);
340862306a36Sopenharmony_ci	acb->acb_flag |= RESET_DEV;	/* RESET_DETECT, RESET_DONE, RESET_DEV */
340962306a36Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_RSTSCSI);
341062306a36Sopenharmony_ci
341162306a36Sopenharmony_ci	while (!(DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET))
341262306a36Sopenharmony_ci		/* nothing */;
341362306a36Sopenharmony_ci}
341462306a36Sopenharmony_ci
341562306a36Sopenharmony_ci
341662306a36Sopenharmony_cistatic void set_basic_config(struct AdapterCtlBlk *acb)
341762306a36Sopenharmony_ci{
341862306a36Sopenharmony_ci	u8 bval;
341962306a36Sopenharmony_ci	u16 wval;
342062306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_TIMEOUT, acb->sel_timeout);
342162306a36Sopenharmony_ci	if (acb->config & HCC_PARITY)
342262306a36Sopenharmony_ci		bval = PHASELATCH | INITIATOR | BLOCKRST | PARITYCHECK;
342362306a36Sopenharmony_ci	else
342462306a36Sopenharmony_ci		bval = PHASELATCH | INITIATOR | BLOCKRST;
342562306a36Sopenharmony_ci
342662306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_CONFIG0, bval);
342762306a36Sopenharmony_ci
342862306a36Sopenharmony_ci	/* program configuration 1: Act_Neg (+ Act_Neg_Enh? + Fast_Filter? + DataDis?) */
342962306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_CONFIG1, 0x03);	/* was 0x13: default */
343062306a36Sopenharmony_ci	/* program Host ID                  */
343162306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_HOSTID, acb->scsi_host->this_id);
343262306a36Sopenharmony_ci	/* set ansynchronous transfer       */
343362306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, 0x00);
343462306a36Sopenharmony_ci	/* Turn LED control off */
343562306a36Sopenharmony_ci	wval = DC395x_read16(acb, TRM_S1040_GEN_CONTROL) & 0x7F;
343662306a36Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_GEN_CONTROL, wval);
343762306a36Sopenharmony_ci	/* DMA config          */
343862306a36Sopenharmony_ci	wval = DC395x_read16(acb, TRM_S1040_DMA_CONFIG) & ~DMA_FIFO_CTRL;
343962306a36Sopenharmony_ci	wval |=
344062306a36Sopenharmony_ci	    DMA_FIFO_HALF_HALF | DMA_ENHANCE /*| DMA_MEM_MULTI_READ */ ;
344162306a36Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_DMA_CONFIG, wval);
344262306a36Sopenharmony_ci	/* Clear pending interrupt status */
344362306a36Sopenharmony_ci	DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS);
344462306a36Sopenharmony_ci	/* Enable SCSI interrupt    */
344562306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_INTEN, 0x7F);
344662306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_DMA_INTEN, EN_SCSIINTR | EN_DMAXFERERROR
344762306a36Sopenharmony_ci		      /*| EN_DMAXFERABORT | EN_DMAXFERCOMP | EN_FORCEDMACOMP */
344862306a36Sopenharmony_ci		      );
344962306a36Sopenharmony_ci}
345062306a36Sopenharmony_ci
345162306a36Sopenharmony_ci
345262306a36Sopenharmony_cistatic void scsi_reset_detect(struct AdapterCtlBlk *acb)
345362306a36Sopenharmony_ci{
345462306a36Sopenharmony_ci	dprintkl(KERN_INFO, "scsi_reset_detect: acb=%p\n", acb);
345562306a36Sopenharmony_ci	/* delay half a second */
345662306a36Sopenharmony_ci	if (timer_pending(&acb->waiting_timer))
345762306a36Sopenharmony_ci		del_timer(&acb->waiting_timer);
345862306a36Sopenharmony_ci
345962306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_CONTROL, DO_RSTMODULE);
346062306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_DMA_CONTROL, DMARESETMODULE);
346162306a36Sopenharmony_ci	/*DC395x_write8(acb, TRM_S1040_DMA_CONTROL,STOPDMAXFER); */
346262306a36Sopenharmony_ci	udelay(500);
346362306a36Sopenharmony_ci	/* Maybe we locked up the bus? Then lets wait even longer ... */
346462306a36Sopenharmony_ci	acb->last_reset =
346562306a36Sopenharmony_ci	    jiffies + 5 * HZ / 2 +
346662306a36Sopenharmony_ci	    HZ * acb->eeprom.delay_time;
346762306a36Sopenharmony_ci
346862306a36Sopenharmony_ci	clear_fifo(acb, "scsi_reset_detect");
346962306a36Sopenharmony_ci	set_basic_config(acb);
347062306a36Sopenharmony_ci	/*1.25 */
347162306a36Sopenharmony_ci	/*DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT); */
347262306a36Sopenharmony_ci
347362306a36Sopenharmony_ci	if (acb->acb_flag & RESET_DEV) {	/* RESET_DETECT, RESET_DONE, RESET_DEV */
347462306a36Sopenharmony_ci		acb->acb_flag |= RESET_DONE;
347562306a36Sopenharmony_ci	} else {
347662306a36Sopenharmony_ci		acb->acb_flag |= RESET_DETECT;
347762306a36Sopenharmony_ci		reset_dev_param(acb);
347862306a36Sopenharmony_ci		doing_srb_done(acb, DID_RESET, NULL, 1);
347962306a36Sopenharmony_ci		/*DC395x_RecoverSRB( acb ); */
348062306a36Sopenharmony_ci		acb->active_dcb = NULL;
348162306a36Sopenharmony_ci		acb->acb_flag = 0;
348262306a36Sopenharmony_ci		waiting_process_next(acb);
348362306a36Sopenharmony_ci	}
348462306a36Sopenharmony_ci}
348562306a36Sopenharmony_ci
348662306a36Sopenharmony_ci
348762306a36Sopenharmony_cistatic void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
348862306a36Sopenharmony_ci		struct ScsiReqBlk *srb)
348962306a36Sopenharmony_ci{
349062306a36Sopenharmony_ci	struct scsi_cmnd *cmd = srb->cmd;
349162306a36Sopenharmony_ci	dprintkdbg(DBG_1, "request_sense: (0x%p) <%02i-%i>\n",
349262306a36Sopenharmony_ci		cmd, cmd->device->id, (u8)cmd->device->lun);
349362306a36Sopenharmony_ci
349462306a36Sopenharmony_ci	srb->flag |= AUTO_REQSENSE;
349562306a36Sopenharmony_ci	srb->adapter_status = 0;
349662306a36Sopenharmony_ci	srb->target_status = 0;
349762306a36Sopenharmony_ci
349862306a36Sopenharmony_ci	/* KG: Can this prevent crap sense data ? */
349962306a36Sopenharmony_ci	memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
350062306a36Sopenharmony_ci
350162306a36Sopenharmony_ci	/* Save some data */
350262306a36Sopenharmony_ci	srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].address =
350362306a36Sopenharmony_ci	    srb->segment_x[0].address;
350462306a36Sopenharmony_ci	srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].length =
350562306a36Sopenharmony_ci	    srb->segment_x[0].length;
350662306a36Sopenharmony_ci	srb->xferred = srb->total_xfer_length;
350762306a36Sopenharmony_ci	/* srb->segment_x : a one entry of S/G list table */
350862306a36Sopenharmony_ci	srb->total_xfer_length = SCSI_SENSE_BUFFERSIZE;
350962306a36Sopenharmony_ci	srb->segment_x[0].length = SCSI_SENSE_BUFFERSIZE;
351062306a36Sopenharmony_ci	/* Map sense buffer */
351162306a36Sopenharmony_ci	srb->segment_x[0].address = dma_map_single(&acb->dev->dev,
351262306a36Sopenharmony_ci			cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE,
351362306a36Sopenharmony_ci			DMA_FROM_DEVICE);
351462306a36Sopenharmony_ci	dprintkdbg(DBG_SG, "request_sense: map buffer %p->%08x(%05x)\n",
351562306a36Sopenharmony_ci	       cmd->sense_buffer, srb->segment_x[0].address,
351662306a36Sopenharmony_ci	       SCSI_SENSE_BUFFERSIZE);
351762306a36Sopenharmony_ci	srb->sg_count = 1;
351862306a36Sopenharmony_ci	srb->sg_index = 0;
351962306a36Sopenharmony_ci
352062306a36Sopenharmony_ci	if (start_scsi(acb, dcb, srb)) {	/* Should only happen, if sb. else grabs the bus */
352162306a36Sopenharmony_ci		dprintkl(KERN_DEBUG,
352262306a36Sopenharmony_ci			"request_sense: (0x%p) failed <%02i-%i>\n",
352362306a36Sopenharmony_ci			srb->cmd, dcb->target_id, dcb->target_lun);
352462306a36Sopenharmony_ci		list_move(&srb->list, &dcb->srb_waiting_list);
352562306a36Sopenharmony_ci		waiting_set_timer(acb, HZ / 100);
352662306a36Sopenharmony_ci	}
352762306a36Sopenharmony_ci}
352862306a36Sopenharmony_ci
352962306a36Sopenharmony_ci
353062306a36Sopenharmony_ci/**
353162306a36Sopenharmony_ci * device_alloc - Allocate a new device instance. This create the
353262306a36Sopenharmony_ci * devices instance and sets up all the data items. The adapter
353362306a36Sopenharmony_ci * instance is required to obtain confiuration information for this
353462306a36Sopenharmony_ci * device. This does *not* add this device to the adapters device
353562306a36Sopenharmony_ci * list.
353662306a36Sopenharmony_ci *
353762306a36Sopenharmony_ci * @acb: The adapter to obtain configuration information from.
353862306a36Sopenharmony_ci * @target: The target for the new device.
353962306a36Sopenharmony_ci * @lun: The lun for the new device.
354062306a36Sopenharmony_ci *
354162306a36Sopenharmony_ci * Return the new device if successful or NULL on failure.
354262306a36Sopenharmony_ci **/
354362306a36Sopenharmony_cistatic struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb,
354462306a36Sopenharmony_ci		u8 target, u8 lun)
354562306a36Sopenharmony_ci{
354662306a36Sopenharmony_ci	struct NvRamType *eeprom = &acb->eeprom;
354762306a36Sopenharmony_ci	u8 period_index = eeprom->target[target].period & 0x07;
354862306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb;
354962306a36Sopenharmony_ci
355062306a36Sopenharmony_ci	dcb = kmalloc(sizeof(struct DeviceCtlBlk), GFP_ATOMIC);
355162306a36Sopenharmony_ci	dprintkdbg(DBG_0, "device_alloc: <%02i-%i>\n", target, lun);
355262306a36Sopenharmony_ci	if (!dcb)
355362306a36Sopenharmony_ci		return NULL;
355462306a36Sopenharmony_ci	dcb->acb = NULL;
355562306a36Sopenharmony_ci	INIT_LIST_HEAD(&dcb->srb_going_list);
355662306a36Sopenharmony_ci	INIT_LIST_HEAD(&dcb->srb_waiting_list);
355762306a36Sopenharmony_ci	dcb->active_srb = NULL;
355862306a36Sopenharmony_ci	dcb->tag_mask = 0;
355962306a36Sopenharmony_ci	dcb->max_command = 1;
356062306a36Sopenharmony_ci	dcb->target_id = target;
356162306a36Sopenharmony_ci	dcb->target_lun = lun;
356262306a36Sopenharmony_ci	dcb->dev_mode = eeprom->target[target].cfg0;
356362306a36Sopenharmony_ci#ifndef DC395x_NO_DISCONNECT
356462306a36Sopenharmony_ci	dcb->identify_msg =
356562306a36Sopenharmony_ci	    IDENTIFY(dcb->dev_mode & NTC_DO_DISCONNECT, lun);
356662306a36Sopenharmony_ci#else
356762306a36Sopenharmony_ci	dcb->identify_msg = IDENTIFY(0, lun);
356862306a36Sopenharmony_ci#endif
356962306a36Sopenharmony_ci	dcb->inquiry7 = 0;
357062306a36Sopenharmony_ci	dcb->sync_mode = 0;
357162306a36Sopenharmony_ci	dcb->min_nego_period = clock_period[period_index];
357262306a36Sopenharmony_ci	dcb->sync_period = 0;
357362306a36Sopenharmony_ci	dcb->sync_offset = 0;
357462306a36Sopenharmony_ci	dcb->flag = 0;
357562306a36Sopenharmony_ci
357662306a36Sopenharmony_ci#ifndef DC395x_NO_WIDE
357762306a36Sopenharmony_ci	if ((dcb->dev_mode & NTC_DO_WIDE_NEGO)
357862306a36Sopenharmony_ci	    && (acb->config & HCC_WIDE_CARD))
357962306a36Sopenharmony_ci		dcb->sync_mode |= WIDE_NEGO_ENABLE;
358062306a36Sopenharmony_ci#endif
358162306a36Sopenharmony_ci#ifndef DC395x_NO_SYNC
358262306a36Sopenharmony_ci	if (dcb->dev_mode & NTC_DO_SYNC_NEGO)
358362306a36Sopenharmony_ci		if (!(lun) || current_sync_offset)
358462306a36Sopenharmony_ci			dcb->sync_mode |= SYNC_NEGO_ENABLE;
358562306a36Sopenharmony_ci#endif
358662306a36Sopenharmony_ci	if (dcb->target_lun != 0) {
358762306a36Sopenharmony_ci		/* Copy settings */
358862306a36Sopenharmony_ci		struct DeviceCtlBlk *p = NULL, *iter;
358962306a36Sopenharmony_ci
359062306a36Sopenharmony_ci		list_for_each_entry(iter, &acb->dcb_list, list)
359162306a36Sopenharmony_ci			if (iter->target_id == dcb->target_id) {
359262306a36Sopenharmony_ci				p = iter;
359362306a36Sopenharmony_ci				break;
359462306a36Sopenharmony_ci			}
359562306a36Sopenharmony_ci
359662306a36Sopenharmony_ci		if (!p) {
359762306a36Sopenharmony_ci			kfree(dcb);
359862306a36Sopenharmony_ci			return NULL;
359962306a36Sopenharmony_ci		}
360062306a36Sopenharmony_ci
360162306a36Sopenharmony_ci		dprintkdbg(DBG_1,
360262306a36Sopenharmony_ci		       "device_alloc: <%02i-%i> copy from <%02i-%i>\n",
360362306a36Sopenharmony_ci		       dcb->target_id, dcb->target_lun,
360462306a36Sopenharmony_ci		       p->target_id, p->target_lun);
360562306a36Sopenharmony_ci		dcb->sync_mode = p->sync_mode;
360662306a36Sopenharmony_ci		dcb->sync_period = p->sync_period;
360762306a36Sopenharmony_ci		dcb->min_nego_period = p->min_nego_period;
360862306a36Sopenharmony_ci		dcb->sync_offset = p->sync_offset;
360962306a36Sopenharmony_ci		dcb->inquiry7 = p->inquiry7;
361062306a36Sopenharmony_ci	}
361162306a36Sopenharmony_ci	return dcb;
361262306a36Sopenharmony_ci}
361362306a36Sopenharmony_ci
361462306a36Sopenharmony_ci
361562306a36Sopenharmony_ci/**
361662306a36Sopenharmony_ci * adapter_add_device - Adds the device instance to the adaptor instance.
361762306a36Sopenharmony_ci *
361862306a36Sopenharmony_ci * @acb: The adapter device to be updated
361962306a36Sopenharmony_ci * @dcb: A newly created and initialised device instance to add.
362062306a36Sopenharmony_ci **/
362162306a36Sopenharmony_cistatic void adapter_add_device(struct AdapterCtlBlk *acb,
362262306a36Sopenharmony_ci		struct DeviceCtlBlk *dcb)
362362306a36Sopenharmony_ci{
362462306a36Sopenharmony_ci	/* backpointer to adapter */
362562306a36Sopenharmony_ci	dcb->acb = acb;
362662306a36Sopenharmony_ci
362762306a36Sopenharmony_ci	/* set run_robin to this device if it is currently empty */
362862306a36Sopenharmony_ci	if (list_empty(&acb->dcb_list))
362962306a36Sopenharmony_ci		acb->dcb_run_robin = dcb;
363062306a36Sopenharmony_ci
363162306a36Sopenharmony_ci	/* add device to list */
363262306a36Sopenharmony_ci	list_add_tail(&dcb->list, &acb->dcb_list);
363362306a36Sopenharmony_ci
363462306a36Sopenharmony_ci	/* update device maps */
363562306a36Sopenharmony_ci	acb->dcb_map[dcb->target_id] |= (1 << dcb->target_lun);
363662306a36Sopenharmony_ci	acb->children[dcb->target_id][dcb->target_lun] = dcb;
363762306a36Sopenharmony_ci}
363862306a36Sopenharmony_ci
363962306a36Sopenharmony_ci
364062306a36Sopenharmony_ci/**
364162306a36Sopenharmony_ci * adapter_remove_device - Removes the device instance from the adaptor
364262306a36Sopenharmony_ci * instance. The device instance is not check in any way or freed by this.
364362306a36Sopenharmony_ci * The caller is expected to take care of that. This will simply remove the
364462306a36Sopenharmony_ci * device from the adapters data strcutures.
364562306a36Sopenharmony_ci *
364662306a36Sopenharmony_ci * @acb: The adapter device to be updated
364762306a36Sopenharmony_ci * @dcb: A device that has previously been added to the adapter.
364862306a36Sopenharmony_ci **/
364962306a36Sopenharmony_cistatic void adapter_remove_device(struct AdapterCtlBlk *acb,
365062306a36Sopenharmony_ci		struct DeviceCtlBlk *dcb)
365162306a36Sopenharmony_ci{
365262306a36Sopenharmony_ci	struct DeviceCtlBlk *i;
365362306a36Sopenharmony_ci	struct DeviceCtlBlk *tmp;
365462306a36Sopenharmony_ci	dprintkdbg(DBG_0, "adapter_remove_device: <%02i-%i>\n",
365562306a36Sopenharmony_ci		dcb->target_id, dcb->target_lun);
365662306a36Sopenharmony_ci
365762306a36Sopenharmony_ci	/* fix up any pointers to this device that we have in the adapter */
365862306a36Sopenharmony_ci	if (acb->active_dcb == dcb)
365962306a36Sopenharmony_ci		acb->active_dcb = NULL;
366062306a36Sopenharmony_ci	if (acb->dcb_run_robin == dcb)
366162306a36Sopenharmony_ci		acb->dcb_run_robin = dcb_get_next(&acb->dcb_list, dcb);
366262306a36Sopenharmony_ci
366362306a36Sopenharmony_ci	/* unlink from list */
366462306a36Sopenharmony_ci	list_for_each_entry_safe(i, tmp, &acb->dcb_list, list)
366562306a36Sopenharmony_ci		if (dcb == i) {
366662306a36Sopenharmony_ci			list_del(&i->list);
366762306a36Sopenharmony_ci			break;
366862306a36Sopenharmony_ci		}
366962306a36Sopenharmony_ci
367062306a36Sopenharmony_ci	/* clear map and children */
367162306a36Sopenharmony_ci	acb->dcb_map[dcb->target_id] &= ~(1 << dcb->target_lun);
367262306a36Sopenharmony_ci	acb->children[dcb->target_id][dcb->target_lun] = NULL;
367362306a36Sopenharmony_ci	dcb->acb = NULL;
367462306a36Sopenharmony_ci}
367562306a36Sopenharmony_ci
367662306a36Sopenharmony_ci
367762306a36Sopenharmony_ci/**
367862306a36Sopenharmony_ci * adapter_remove_and_free_device - Removes a single device from the adapter
367962306a36Sopenharmony_ci * and then frees the device information.
368062306a36Sopenharmony_ci *
368162306a36Sopenharmony_ci * @acb: The adapter device to be updated
368262306a36Sopenharmony_ci * @dcb: A device that has previously been added to the adapter.
368362306a36Sopenharmony_ci */
368462306a36Sopenharmony_cistatic void adapter_remove_and_free_device(struct AdapterCtlBlk *acb,
368562306a36Sopenharmony_ci		struct DeviceCtlBlk *dcb)
368662306a36Sopenharmony_ci{
368762306a36Sopenharmony_ci	if (list_size(&dcb->srb_going_list) > 1) {
368862306a36Sopenharmony_ci		dprintkdbg(DBG_1, "adapter_remove_and_free_device: <%02i-%i> "
368962306a36Sopenharmony_ci		           "Won't remove because of %i active requests.\n",
369062306a36Sopenharmony_ci			   dcb->target_id, dcb->target_lun,
369162306a36Sopenharmony_ci			   list_size(&dcb->srb_going_list));
369262306a36Sopenharmony_ci		return;
369362306a36Sopenharmony_ci	}
369462306a36Sopenharmony_ci	adapter_remove_device(acb, dcb);
369562306a36Sopenharmony_ci	kfree(dcb);
369662306a36Sopenharmony_ci}
369762306a36Sopenharmony_ci
369862306a36Sopenharmony_ci
369962306a36Sopenharmony_ci/**
370062306a36Sopenharmony_ci * adapter_remove_and_free_all_devices - Removes and frees all of the
370162306a36Sopenharmony_ci * devices associated with the specified adapter.
370262306a36Sopenharmony_ci *
370362306a36Sopenharmony_ci * @acb: The adapter from which all devices should be removed.
370462306a36Sopenharmony_ci **/
370562306a36Sopenharmony_cistatic void adapter_remove_and_free_all_devices(struct AdapterCtlBlk* acb)
370662306a36Sopenharmony_ci{
370762306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb;
370862306a36Sopenharmony_ci	struct DeviceCtlBlk *tmp;
370962306a36Sopenharmony_ci	dprintkdbg(DBG_1, "adapter_remove_and_free_all_devices: num=%i\n",
371062306a36Sopenharmony_ci		   list_size(&acb->dcb_list));
371162306a36Sopenharmony_ci
371262306a36Sopenharmony_ci	list_for_each_entry_safe(dcb, tmp, &acb->dcb_list, list)
371362306a36Sopenharmony_ci		adapter_remove_and_free_device(acb, dcb);
371462306a36Sopenharmony_ci}
371562306a36Sopenharmony_ci
371662306a36Sopenharmony_ci
371762306a36Sopenharmony_ci/**
371862306a36Sopenharmony_ci * dc395x_slave_alloc - Called by the scsi mid layer to tell us about a new
371962306a36Sopenharmony_ci * scsi device that we need to deal with. We allocate a new device and then
372062306a36Sopenharmony_ci * insert that device into the adapters device list.
372162306a36Sopenharmony_ci *
372262306a36Sopenharmony_ci * @scsi_device: The new scsi device that we need to handle.
372362306a36Sopenharmony_ci **/
372462306a36Sopenharmony_cistatic int dc395x_slave_alloc(struct scsi_device *scsi_device)
372562306a36Sopenharmony_ci{
372662306a36Sopenharmony_ci	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)scsi_device->host->hostdata;
372762306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb;
372862306a36Sopenharmony_ci
372962306a36Sopenharmony_ci	dcb = device_alloc(acb, scsi_device->id, scsi_device->lun);
373062306a36Sopenharmony_ci	if (!dcb)
373162306a36Sopenharmony_ci		return -ENOMEM;
373262306a36Sopenharmony_ci	adapter_add_device(acb, dcb);
373362306a36Sopenharmony_ci
373462306a36Sopenharmony_ci	return 0;
373562306a36Sopenharmony_ci}
373662306a36Sopenharmony_ci
373762306a36Sopenharmony_ci
373862306a36Sopenharmony_ci/**
373962306a36Sopenharmony_ci * dc395x_slave_destroy - Called by the scsi mid layer to tell us about a
374062306a36Sopenharmony_ci * device that is going away.
374162306a36Sopenharmony_ci *
374262306a36Sopenharmony_ci * @scsi_device: The new scsi device that we need to handle.
374362306a36Sopenharmony_ci **/
374462306a36Sopenharmony_cistatic void dc395x_slave_destroy(struct scsi_device *scsi_device)
374562306a36Sopenharmony_ci{
374662306a36Sopenharmony_ci	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)scsi_device->host->hostdata;
374762306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb = find_dcb(acb, scsi_device->id, scsi_device->lun);
374862306a36Sopenharmony_ci	if (dcb)
374962306a36Sopenharmony_ci		adapter_remove_and_free_device(acb, dcb);
375062306a36Sopenharmony_ci}
375162306a36Sopenharmony_ci
375262306a36Sopenharmony_ci
375362306a36Sopenharmony_ci
375462306a36Sopenharmony_ci
375562306a36Sopenharmony_ci/**
375662306a36Sopenharmony_ci * trms1040_wait_30us: wait for 30 us
375762306a36Sopenharmony_ci *
375862306a36Sopenharmony_ci * Waits for 30us (using the chip by the looks of it..)
375962306a36Sopenharmony_ci *
376062306a36Sopenharmony_ci * @io_port: base I/O address
376162306a36Sopenharmony_ci **/
376262306a36Sopenharmony_cistatic void trms1040_wait_30us(unsigned long io_port)
376362306a36Sopenharmony_ci{
376462306a36Sopenharmony_ci	/* ScsiPortStallExecution(30); wait 30 us */
376562306a36Sopenharmony_ci	outb(5, io_port + TRM_S1040_GEN_TIMER);
376662306a36Sopenharmony_ci	while (!(inb(io_port + TRM_S1040_GEN_STATUS) & GTIMEOUT))
376762306a36Sopenharmony_ci		/* nothing */ ;
376862306a36Sopenharmony_ci}
376962306a36Sopenharmony_ci
377062306a36Sopenharmony_ci
377162306a36Sopenharmony_ci/**
377262306a36Sopenharmony_ci * trms1040_write_cmd - write the secified command and address to
377362306a36Sopenharmony_ci * chip
377462306a36Sopenharmony_ci *
377562306a36Sopenharmony_ci * @io_port:	base I/O address
377662306a36Sopenharmony_ci * @cmd:	SB + op code (command) to send
377762306a36Sopenharmony_ci * @addr:	address to send
377862306a36Sopenharmony_ci **/
377962306a36Sopenharmony_cistatic void trms1040_write_cmd(unsigned long io_port, u8 cmd, u8 addr)
378062306a36Sopenharmony_ci{
378162306a36Sopenharmony_ci	int i;
378262306a36Sopenharmony_ci	u8 send_data;
378362306a36Sopenharmony_ci
378462306a36Sopenharmony_ci	/* program SB + OP code */
378562306a36Sopenharmony_ci	for (i = 0; i < 3; i++, cmd <<= 1) {
378662306a36Sopenharmony_ci		send_data = NVR_SELECT;
378762306a36Sopenharmony_ci		if (cmd & 0x04)	/* Start from bit 2 */
378862306a36Sopenharmony_ci			send_data |= NVR_BITOUT;
378962306a36Sopenharmony_ci
379062306a36Sopenharmony_ci		outb(send_data, io_port + TRM_S1040_GEN_NVRAM);
379162306a36Sopenharmony_ci		trms1040_wait_30us(io_port);
379262306a36Sopenharmony_ci		outb((send_data | NVR_CLOCK),
379362306a36Sopenharmony_ci		     io_port + TRM_S1040_GEN_NVRAM);
379462306a36Sopenharmony_ci		trms1040_wait_30us(io_port);
379562306a36Sopenharmony_ci	}
379662306a36Sopenharmony_ci
379762306a36Sopenharmony_ci	/* send address */
379862306a36Sopenharmony_ci	for (i = 0; i < 7; i++, addr <<= 1) {
379962306a36Sopenharmony_ci		send_data = NVR_SELECT;
380062306a36Sopenharmony_ci		if (addr & 0x40)	/* Start from bit 6 */
380162306a36Sopenharmony_ci			send_data |= NVR_BITOUT;
380262306a36Sopenharmony_ci
380362306a36Sopenharmony_ci		outb(send_data, io_port + TRM_S1040_GEN_NVRAM);
380462306a36Sopenharmony_ci		trms1040_wait_30us(io_port);
380562306a36Sopenharmony_ci		outb((send_data | NVR_CLOCK),
380662306a36Sopenharmony_ci		     io_port + TRM_S1040_GEN_NVRAM);
380762306a36Sopenharmony_ci		trms1040_wait_30us(io_port);
380862306a36Sopenharmony_ci	}
380962306a36Sopenharmony_ci	outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM);
381062306a36Sopenharmony_ci	trms1040_wait_30us(io_port);
381162306a36Sopenharmony_ci}
381262306a36Sopenharmony_ci
381362306a36Sopenharmony_ci
381462306a36Sopenharmony_ci/**
381562306a36Sopenharmony_ci * trms1040_set_data - store a single byte in the eeprom
381662306a36Sopenharmony_ci *
381762306a36Sopenharmony_ci * Called from write all to write a single byte into the SSEEPROM
381862306a36Sopenharmony_ci * Which is done one bit at a time.
381962306a36Sopenharmony_ci *
382062306a36Sopenharmony_ci * @io_port:	base I/O address
382162306a36Sopenharmony_ci * @addr:	offset into EEPROM
382262306a36Sopenharmony_ci * @byte:	bytes to write
382362306a36Sopenharmony_ci **/
382462306a36Sopenharmony_cistatic void trms1040_set_data(unsigned long io_port, u8 addr, u8 byte)
382562306a36Sopenharmony_ci{
382662306a36Sopenharmony_ci	int i;
382762306a36Sopenharmony_ci	u8 send_data;
382862306a36Sopenharmony_ci
382962306a36Sopenharmony_ci	/* Send write command & address */
383062306a36Sopenharmony_ci	trms1040_write_cmd(io_port, 0x05, addr);
383162306a36Sopenharmony_ci
383262306a36Sopenharmony_ci	/* Write data */
383362306a36Sopenharmony_ci	for (i = 0; i < 8; i++, byte <<= 1) {
383462306a36Sopenharmony_ci		send_data = NVR_SELECT;
383562306a36Sopenharmony_ci		if (byte & 0x80)	/* Start from bit 7 */
383662306a36Sopenharmony_ci			send_data |= NVR_BITOUT;
383762306a36Sopenharmony_ci
383862306a36Sopenharmony_ci		outb(send_data, io_port + TRM_S1040_GEN_NVRAM);
383962306a36Sopenharmony_ci		trms1040_wait_30us(io_port);
384062306a36Sopenharmony_ci		outb((send_data | NVR_CLOCK), io_port + TRM_S1040_GEN_NVRAM);
384162306a36Sopenharmony_ci		trms1040_wait_30us(io_port);
384262306a36Sopenharmony_ci	}
384362306a36Sopenharmony_ci	outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM);
384462306a36Sopenharmony_ci	trms1040_wait_30us(io_port);
384562306a36Sopenharmony_ci
384662306a36Sopenharmony_ci	/* Disable chip select */
384762306a36Sopenharmony_ci	outb(0, io_port + TRM_S1040_GEN_NVRAM);
384862306a36Sopenharmony_ci	trms1040_wait_30us(io_port);
384962306a36Sopenharmony_ci
385062306a36Sopenharmony_ci	outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM);
385162306a36Sopenharmony_ci	trms1040_wait_30us(io_port);
385262306a36Sopenharmony_ci
385362306a36Sopenharmony_ci	/* Wait for write ready */
385462306a36Sopenharmony_ci	while (1) {
385562306a36Sopenharmony_ci		outb((NVR_SELECT | NVR_CLOCK), io_port + TRM_S1040_GEN_NVRAM);
385662306a36Sopenharmony_ci		trms1040_wait_30us(io_port);
385762306a36Sopenharmony_ci
385862306a36Sopenharmony_ci		outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM);
385962306a36Sopenharmony_ci		trms1040_wait_30us(io_port);
386062306a36Sopenharmony_ci
386162306a36Sopenharmony_ci		if (inb(io_port + TRM_S1040_GEN_NVRAM) & NVR_BITIN)
386262306a36Sopenharmony_ci			break;
386362306a36Sopenharmony_ci	}
386462306a36Sopenharmony_ci
386562306a36Sopenharmony_ci	/*  Disable chip select */
386662306a36Sopenharmony_ci	outb(0, io_port + TRM_S1040_GEN_NVRAM);
386762306a36Sopenharmony_ci}
386862306a36Sopenharmony_ci
386962306a36Sopenharmony_ci
387062306a36Sopenharmony_ci/**
387162306a36Sopenharmony_ci * trms1040_write_all - write 128 bytes to the eeprom
387262306a36Sopenharmony_ci *
387362306a36Sopenharmony_ci * Write the supplied 128 bytes to the chips SEEPROM
387462306a36Sopenharmony_ci *
387562306a36Sopenharmony_ci * @eeprom:	the data to write
387662306a36Sopenharmony_ci * @io_port:	the base io port
387762306a36Sopenharmony_ci **/
387862306a36Sopenharmony_cistatic void trms1040_write_all(struct NvRamType *eeprom, unsigned long io_port)
387962306a36Sopenharmony_ci{
388062306a36Sopenharmony_ci	u8 *b_eeprom = (u8 *)eeprom;
388162306a36Sopenharmony_ci	u8 addr;
388262306a36Sopenharmony_ci
388362306a36Sopenharmony_ci	/* Enable SEEPROM */
388462306a36Sopenharmony_ci	outb((inb(io_port + TRM_S1040_GEN_CONTROL) | EN_EEPROM),
388562306a36Sopenharmony_ci	     io_port + TRM_S1040_GEN_CONTROL);
388662306a36Sopenharmony_ci
388762306a36Sopenharmony_ci	/* write enable */
388862306a36Sopenharmony_ci	trms1040_write_cmd(io_port, 0x04, 0xFF);
388962306a36Sopenharmony_ci	outb(0, io_port + TRM_S1040_GEN_NVRAM);
389062306a36Sopenharmony_ci	trms1040_wait_30us(io_port);
389162306a36Sopenharmony_ci
389262306a36Sopenharmony_ci	/* write */
389362306a36Sopenharmony_ci	for (addr = 0; addr < 128; addr++, b_eeprom++)
389462306a36Sopenharmony_ci		trms1040_set_data(io_port, addr, *b_eeprom);
389562306a36Sopenharmony_ci
389662306a36Sopenharmony_ci	/* write disable */
389762306a36Sopenharmony_ci	trms1040_write_cmd(io_port, 0x04, 0x00);
389862306a36Sopenharmony_ci	outb(0, io_port + TRM_S1040_GEN_NVRAM);
389962306a36Sopenharmony_ci	trms1040_wait_30us(io_port);
390062306a36Sopenharmony_ci
390162306a36Sopenharmony_ci	/* Disable SEEPROM */
390262306a36Sopenharmony_ci	outb((inb(io_port + TRM_S1040_GEN_CONTROL) & ~EN_EEPROM),
390362306a36Sopenharmony_ci	     io_port + TRM_S1040_GEN_CONTROL);
390462306a36Sopenharmony_ci}
390562306a36Sopenharmony_ci
390662306a36Sopenharmony_ci
390762306a36Sopenharmony_ci/**
390862306a36Sopenharmony_ci * trms1040_get_data - get a single byte from the eeprom
390962306a36Sopenharmony_ci *
391062306a36Sopenharmony_ci * Called from read all to read a single byte into the SSEEPROM
391162306a36Sopenharmony_ci * Which is done one bit at a time.
391262306a36Sopenharmony_ci *
391362306a36Sopenharmony_ci * @io_port:	base I/O address
391462306a36Sopenharmony_ci * @addr:	offset into SEEPROM
391562306a36Sopenharmony_ci *
391662306a36Sopenharmony_ci * Returns the byte read.
391762306a36Sopenharmony_ci **/
391862306a36Sopenharmony_cistatic u8 trms1040_get_data(unsigned long io_port, u8 addr)
391962306a36Sopenharmony_ci{
392062306a36Sopenharmony_ci	int i;
392162306a36Sopenharmony_ci	u8 read_byte;
392262306a36Sopenharmony_ci	u8 result = 0;
392362306a36Sopenharmony_ci
392462306a36Sopenharmony_ci	/* Send read command & address */
392562306a36Sopenharmony_ci	trms1040_write_cmd(io_port, 0x06, addr);
392662306a36Sopenharmony_ci
392762306a36Sopenharmony_ci	/* read data */
392862306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
392962306a36Sopenharmony_ci		outb((NVR_SELECT | NVR_CLOCK), io_port + TRM_S1040_GEN_NVRAM);
393062306a36Sopenharmony_ci		trms1040_wait_30us(io_port);
393162306a36Sopenharmony_ci		outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM);
393262306a36Sopenharmony_ci
393362306a36Sopenharmony_ci		/* Get data bit while falling edge */
393462306a36Sopenharmony_ci		read_byte = inb(io_port + TRM_S1040_GEN_NVRAM);
393562306a36Sopenharmony_ci		result <<= 1;
393662306a36Sopenharmony_ci		if (read_byte & NVR_BITIN)
393762306a36Sopenharmony_ci			result |= 1;
393862306a36Sopenharmony_ci
393962306a36Sopenharmony_ci		trms1040_wait_30us(io_port);
394062306a36Sopenharmony_ci	}
394162306a36Sopenharmony_ci
394262306a36Sopenharmony_ci	/* Disable chip select */
394362306a36Sopenharmony_ci	outb(0, io_port + TRM_S1040_GEN_NVRAM);
394462306a36Sopenharmony_ci	return result;
394562306a36Sopenharmony_ci}
394662306a36Sopenharmony_ci
394762306a36Sopenharmony_ci
394862306a36Sopenharmony_ci/**
394962306a36Sopenharmony_ci * trms1040_read_all - read all bytes from the eeprom
395062306a36Sopenharmony_ci *
395162306a36Sopenharmony_ci * Read the 128 bytes from the SEEPROM.
395262306a36Sopenharmony_ci *
395362306a36Sopenharmony_ci * @eeprom:	where to store the data
395462306a36Sopenharmony_ci * @io_port:	the base io port
395562306a36Sopenharmony_ci **/
395662306a36Sopenharmony_cistatic void trms1040_read_all(struct NvRamType *eeprom, unsigned long io_port)
395762306a36Sopenharmony_ci{
395862306a36Sopenharmony_ci	u8 *b_eeprom = (u8 *)eeprom;
395962306a36Sopenharmony_ci	u8 addr;
396062306a36Sopenharmony_ci
396162306a36Sopenharmony_ci	/* Enable SEEPROM */
396262306a36Sopenharmony_ci	outb((inb(io_port + TRM_S1040_GEN_CONTROL) | EN_EEPROM),
396362306a36Sopenharmony_ci	     io_port + TRM_S1040_GEN_CONTROL);
396462306a36Sopenharmony_ci
396562306a36Sopenharmony_ci	/* read details */
396662306a36Sopenharmony_ci	for (addr = 0; addr < 128; addr++, b_eeprom++)
396762306a36Sopenharmony_ci		*b_eeprom = trms1040_get_data(io_port, addr);
396862306a36Sopenharmony_ci
396962306a36Sopenharmony_ci	/* Disable SEEPROM */
397062306a36Sopenharmony_ci	outb((inb(io_port + TRM_S1040_GEN_CONTROL) & ~EN_EEPROM),
397162306a36Sopenharmony_ci	     io_port + TRM_S1040_GEN_CONTROL);
397262306a36Sopenharmony_ci}
397362306a36Sopenharmony_ci
397462306a36Sopenharmony_ci
397562306a36Sopenharmony_ci
397662306a36Sopenharmony_ci/**
397762306a36Sopenharmony_ci * check_eeprom - get and check contents of the eeprom
397862306a36Sopenharmony_ci *
397962306a36Sopenharmony_ci * Read seeprom 128 bytes into the memory provider in eeprom.
398062306a36Sopenharmony_ci * Checks the checksum and if it's not correct it uses a set of default
398162306a36Sopenharmony_ci * values.
398262306a36Sopenharmony_ci *
398362306a36Sopenharmony_ci * @eeprom:	caller allocated strcuture to read the eeprom data into
398462306a36Sopenharmony_ci * @io_port:	io port to read from
398562306a36Sopenharmony_ci **/
398662306a36Sopenharmony_cistatic void check_eeprom(struct NvRamType *eeprom, unsigned long io_port)
398762306a36Sopenharmony_ci{
398862306a36Sopenharmony_ci	u16 *w_eeprom = (u16 *)eeprom;
398962306a36Sopenharmony_ci	u16 w_addr;
399062306a36Sopenharmony_ci	u16 cksum;
399162306a36Sopenharmony_ci	u32 d_addr;
399262306a36Sopenharmony_ci	u32 *d_eeprom;
399362306a36Sopenharmony_ci
399462306a36Sopenharmony_ci	trms1040_read_all(eeprom, io_port);	/* read eeprom */
399562306a36Sopenharmony_ci
399662306a36Sopenharmony_ci	cksum = 0;
399762306a36Sopenharmony_ci	for (w_addr = 0, w_eeprom = (u16 *)eeprom; w_addr < 64;
399862306a36Sopenharmony_ci	     w_addr++, w_eeprom++)
399962306a36Sopenharmony_ci		cksum += *w_eeprom;
400062306a36Sopenharmony_ci	if (cksum != 0x1234) {
400162306a36Sopenharmony_ci		/*
400262306a36Sopenharmony_ci		 * Checksum is wrong.
400362306a36Sopenharmony_ci		 * Load a set of defaults into the eeprom buffer
400462306a36Sopenharmony_ci		 */
400562306a36Sopenharmony_ci		dprintkl(KERN_WARNING,
400662306a36Sopenharmony_ci			"EEProm checksum error: using default values and options.\n");
400762306a36Sopenharmony_ci		eeprom->sub_vendor_id[0] = (u8)PCI_VENDOR_ID_TEKRAM;
400862306a36Sopenharmony_ci		eeprom->sub_vendor_id[1] = (u8)(PCI_VENDOR_ID_TEKRAM >> 8);
400962306a36Sopenharmony_ci		eeprom->sub_sys_id[0] = (u8)PCI_DEVICE_ID_TEKRAM_TRMS1040;
401062306a36Sopenharmony_ci		eeprom->sub_sys_id[1] =
401162306a36Sopenharmony_ci		    (u8)(PCI_DEVICE_ID_TEKRAM_TRMS1040 >> 8);
401262306a36Sopenharmony_ci		eeprom->sub_class = 0x00;
401362306a36Sopenharmony_ci		eeprom->vendor_id[0] = (u8)PCI_VENDOR_ID_TEKRAM;
401462306a36Sopenharmony_ci		eeprom->vendor_id[1] = (u8)(PCI_VENDOR_ID_TEKRAM >> 8);
401562306a36Sopenharmony_ci		eeprom->device_id[0] = (u8)PCI_DEVICE_ID_TEKRAM_TRMS1040;
401662306a36Sopenharmony_ci		eeprom->device_id[1] =
401762306a36Sopenharmony_ci		    (u8)(PCI_DEVICE_ID_TEKRAM_TRMS1040 >> 8);
401862306a36Sopenharmony_ci		eeprom->reserved = 0x00;
401962306a36Sopenharmony_ci
402062306a36Sopenharmony_ci		for (d_addr = 0, d_eeprom = (u32 *)eeprom->target;
402162306a36Sopenharmony_ci		     d_addr < 16; d_addr++, d_eeprom++)
402262306a36Sopenharmony_ci			*d_eeprom = 0x00000077;	/* cfg3,cfg2,period,cfg0 */
402362306a36Sopenharmony_ci
402462306a36Sopenharmony_ci		*d_eeprom++ = 0x04000F07;	/* max_tag,delay_time,channel_cfg,scsi_id */
402562306a36Sopenharmony_ci		*d_eeprom++ = 0x00000015;	/* reserved1,boot_lun,boot_target,reserved0 */
402662306a36Sopenharmony_ci		for (d_addr = 0; d_addr < 12; d_addr++, d_eeprom++)
402762306a36Sopenharmony_ci			*d_eeprom = 0x00;
402862306a36Sopenharmony_ci
402962306a36Sopenharmony_ci		/* Now load defaults (maybe set by boot/module params) */
403062306a36Sopenharmony_ci		set_safe_settings();
403162306a36Sopenharmony_ci		fix_settings();
403262306a36Sopenharmony_ci		eeprom_override(eeprom);
403362306a36Sopenharmony_ci
403462306a36Sopenharmony_ci		eeprom->cksum = 0x00;
403562306a36Sopenharmony_ci		for (w_addr = 0, cksum = 0, w_eeprom = (u16 *)eeprom;
403662306a36Sopenharmony_ci		     w_addr < 63; w_addr++, w_eeprom++)
403762306a36Sopenharmony_ci			cksum += *w_eeprom;
403862306a36Sopenharmony_ci
403962306a36Sopenharmony_ci		*w_eeprom = 0x1234 - cksum;
404062306a36Sopenharmony_ci		trms1040_write_all(eeprom, io_port);
404162306a36Sopenharmony_ci		eeprom->delay_time = cfg_data[CFG_RESET_DELAY].value;
404262306a36Sopenharmony_ci	} else {
404362306a36Sopenharmony_ci		set_safe_settings();
404462306a36Sopenharmony_ci		eeprom_index_to_delay(eeprom);
404562306a36Sopenharmony_ci		eeprom_override(eeprom);
404662306a36Sopenharmony_ci	}
404762306a36Sopenharmony_ci}
404862306a36Sopenharmony_ci
404962306a36Sopenharmony_ci
405062306a36Sopenharmony_ci/**
405162306a36Sopenharmony_ci * print_eeprom_settings - output the eeprom settings
405262306a36Sopenharmony_ci * to the kernel log so people can see what they were.
405362306a36Sopenharmony_ci *
405462306a36Sopenharmony_ci * @eeprom: The eeprom data strucutre to show details for.
405562306a36Sopenharmony_ci **/
405662306a36Sopenharmony_cistatic void print_eeprom_settings(struct NvRamType *eeprom)
405762306a36Sopenharmony_ci{
405862306a36Sopenharmony_ci	dprintkl(KERN_INFO, "Used settings: AdapterID=%02i, Speed=%i(%02i.%01iMHz), dev_mode=0x%02x\n",
405962306a36Sopenharmony_ci		eeprom->scsi_id,
406062306a36Sopenharmony_ci		eeprom->target[0].period,
406162306a36Sopenharmony_ci		clock_speed[eeprom->target[0].period] / 10,
406262306a36Sopenharmony_ci		clock_speed[eeprom->target[0].period] % 10,
406362306a36Sopenharmony_ci		eeprom->target[0].cfg0);
406462306a36Sopenharmony_ci	dprintkl(KERN_INFO, "               AdaptMode=0x%02x, Tags=%i(%02i), DelayReset=%is\n",
406562306a36Sopenharmony_ci		eeprom->channel_cfg, eeprom->max_tag,
406662306a36Sopenharmony_ci		1 << eeprom->max_tag, eeprom->delay_time);
406762306a36Sopenharmony_ci}
406862306a36Sopenharmony_ci
406962306a36Sopenharmony_ci
407062306a36Sopenharmony_ci/* Free SG tables */
407162306a36Sopenharmony_cistatic void adapter_sg_tables_free(struct AdapterCtlBlk *acb)
407262306a36Sopenharmony_ci{
407362306a36Sopenharmony_ci	int i;
407462306a36Sopenharmony_ci	const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN;
407562306a36Sopenharmony_ci
407662306a36Sopenharmony_ci	for (i = 0; i < DC395x_MAX_SRB_CNT; i += srbs_per_page)
407762306a36Sopenharmony_ci		kfree(acb->srb_array[i].segment_x);
407862306a36Sopenharmony_ci}
407962306a36Sopenharmony_ci
408062306a36Sopenharmony_ci
408162306a36Sopenharmony_ci/*
408262306a36Sopenharmony_ci * Allocate SG tables; as we have to pci_map them, an SG list (struct SGentry*)
408362306a36Sopenharmony_ci * should never cross a page boundary */
408462306a36Sopenharmony_cistatic int adapter_sg_tables_alloc(struct AdapterCtlBlk *acb)
408562306a36Sopenharmony_ci{
408662306a36Sopenharmony_ci	const unsigned mem_needed = (DC395x_MAX_SRB_CNT+1)
408762306a36Sopenharmony_ci	                            *SEGMENTX_LEN;
408862306a36Sopenharmony_ci	int pages = (mem_needed+(PAGE_SIZE-1))/PAGE_SIZE;
408962306a36Sopenharmony_ci	const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN;
409062306a36Sopenharmony_ci	int srb_idx = 0;
409162306a36Sopenharmony_ci	unsigned i = 0;
409262306a36Sopenharmony_ci	struct SGentry *ptr;
409362306a36Sopenharmony_ci
409462306a36Sopenharmony_ci	for (i = 0; i < DC395x_MAX_SRB_CNT; i++)
409562306a36Sopenharmony_ci		acb->srb_array[i].segment_x = NULL;
409662306a36Sopenharmony_ci
409762306a36Sopenharmony_ci	dprintkdbg(DBG_1, "Allocate %i pages for SG tables\n", pages);
409862306a36Sopenharmony_ci	while (pages--) {
409962306a36Sopenharmony_ci		ptr = kmalloc(PAGE_SIZE, GFP_KERNEL);
410062306a36Sopenharmony_ci		if (!ptr) {
410162306a36Sopenharmony_ci			adapter_sg_tables_free(acb);
410262306a36Sopenharmony_ci			return 1;
410362306a36Sopenharmony_ci		}
410462306a36Sopenharmony_ci		dprintkdbg(DBG_1, "Allocate %li bytes at %p for SG segments %i\n",
410562306a36Sopenharmony_ci			PAGE_SIZE, ptr, srb_idx);
410662306a36Sopenharmony_ci		i = 0;
410762306a36Sopenharmony_ci		while (i < srbs_per_page && srb_idx < DC395x_MAX_SRB_CNT)
410862306a36Sopenharmony_ci			acb->srb_array[srb_idx++].segment_x =
410962306a36Sopenharmony_ci			    ptr + (i++ * DC395x_MAX_SG_LISTENTRY);
411062306a36Sopenharmony_ci	}
411162306a36Sopenharmony_ci	if (i < srbs_per_page)
411262306a36Sopenharmony_ci		acb->srb.segment_x =
411362306a36Sopenharmony_ci		    ptr + (i * DC395x_MAX_SG_LISTENTRY);
411462306a36Sopenharmony_ci	else
411562306a36Sopenharmony_ci		dprintkl(KERN_DEBUG, "No space for tmsrb SG table reserved?!\n");
411662306a36Sopenharmony_ci	return 0;
411762306a36Sopenharmony_ci}
411862306a36Sopenharmony_ci
411962306a36Sopenharmony_ci
412062306a36Sopenharmony_ci
412162306a36Sopenharmony_ci/**
412262306a36Sopenharmony_ci * adapter_print_config - print adapter connection and termination
412362306a36Sopenharmony_ci * config
412462306a36Sopenharmony_ci *
412562306a36Sopenharmony_ci * The io port in the adapter needs to have been set before calling
412662306a36Sopenharmony_ci * this function.
412762306a36Sopenharmony_ci *
412862306a36Sopenharmony_ci * @acb: The adapter to print the information for.
412962306a36Sopenharmony_ci **/
413062306a36Sopenharmony_cistatic void adapter_print_config(struct AdapterCtlBlk *acb)
413162306a36Sopenharmony_ci{
413262306a36Sopenharmony_ci	u8 bval;
413362306a36Sopenharmony_ci
413462306a36Sopenharmony_ci	bval = DC395x_read8(acb, TRM_S1040_GEN_STATUS);
413562306a36Sopenharmony_ci	dprintkl(KERN_INFO, "%sConnectors: ",
413662306a36Sopenharmony_ci		((bval & WIDESCSI) ? "(Wide) " : ""));
413762306a36Sopenharmony_ci	if (!(bval & CON5068))
413862306a36Sopenharmony_ci		printk("ext%s ", !(bval & EXT68HIGH) ? "68" : "50");
413962306a36Sopenharmony_ci	if (!(bval & CON68))
414062306a36Sopenharmony_ci		printk("int68%s ", !(bval & INT68HIGH) ? "" : "(50)");
414162306a36Sopenharmony_ci	if (!(bval & CON50))
414262306a36Sopenharmony_ci		printk("int50 ");
414362306a36Sopenharmony_ci	if ((bval & (CON5068 | CON50 | CON68)) ==
414462306a36Sopenharmony_ci	    0 /*(CON5068 | CON50 | CON68) */ )
414562306a36Sopenharmony_ci		printk(" Oops! (All 3?) ");
414662306a36Sopenharmony_ci	bval = DC395x_read8(acb, TRM_S1040_GEN_CONTROL);
414762306a36Sopenharmony_ci	printk(" Termination: ");
414862306a36Sopenharmony_ci	if (bval & DIS_TERM)
414962306a36Sopenharmony_ci		printk("Disabled\n");
415062306a36Sopenharmony_ci	else {
415162306a36Sopenharmony_ci		if (bval & AUTOTERM)
415262306a36Sopenharmony_ci			printk("Auto ");
415362306a36Sopenharmony_ci		if (bval & LOW8TERM)
415462306a36Sopenharmony_ci			printk("Low ");
415562306a36Sopenharmony_ci		if (bval & UP8TERM)
415662306a36Sopenharmony_ci			printk("High ");
415762306a36Sopenharmony_ci		printk("\n");
415862306a36Sopenharmony_ci	}
415962306a36Sopenharmony_ci}
416062306a36Sopenharmony_ci
416162306a36Sopenharmony_ci
416262306a36Sopenharmony_ci/**
416362306a36Sopenharmony_ci * adapter_init_params - Initialize the various parameters in the
416462306a36Sopenharmony_ci * adapter structure. Note that the pointer to the scsi_host is set
416562306a36Sopenharmony_ci * early (when this instance is created) and the io_port and irq
416662306a36Sopenharmony_ci * values are set later after they have been reserved. This just gets
416762306a36Sopenharmony_ci * everything set to a good starting position.
416862306a36Sopenharmony_ci *
416962306a36Sopenharmony_ci * The eeprom structure in the adapter needs to have been set before
417062306a36Sopenharmony_ci * calling this function.
417162306a36Sopenharmony_ci *
417262306a36Sopenharmony_ci * @acb: The adapter to initialize.
417362306a36Sopenharmony_ci **/
417462306a36Sopenharmony_cistatic void adapter_init_params(struct AdapterCtlBlk *acb)
417562306a36Sopenharmony_ci{
417662306a36Sopenharmony_ci	struct NvRamType *eeprom = &acb->eeprom;
417762306a36Sopenharmony_ci	int i;
417862306a36Sopenharmony_ci
417962306a36Sopenharmony_ci	/* NOTE: acb->scsi_host is set at scsi_host/acb creation time */
418062306a36Sopenharmony_ci	/* NOTE: acb->io_port_base is set at port registration time */
418162306a36Sopenharmony_ci	/* NOTE: acb->io_port_len is set at port registration time */
418262306a36Sopenharmony_ci
418362306a36Sopenharmony_ci	INIT_LIST_HEAD(&acb->dcb_list);
418462306a36Sopenharmony_ci	acb->dcb_run_robin = NULL;
418562306a36Sopenharmony_ci	acb->active_dcb = NULL;
418662306a36Sopenharmony_ci
418762306a36Sopenharmony_ci	INIT_LIST_HEAD(&acb->srb_free_list);
418862306a36Sopenharmony_ci	/*  temp SRB for Q tag used or abort command used  */
418962306a36Sopenharmony_ci	acb->tmp_srb = &acb->srb;
419062306a36Sopenharmony_ci	timer_setup(&acb->waiting_timer, waiting_timeout, 0);
419162306a36Sopenharmony_ci	timer_setup(&acb->selto_timer, NULL, 0);
419262306a36Sopenharmony_ci
419362306a36Sopenharmony_ci	acb->srb_count = DC395x_MAX_SRB_CNT;
419462306a36Sopenharmony_ci
419562306a36Sopenharmony_ci	acb->sel_timeout = DC395x_SEL_TIMEOUT;	/* timeout=250ms */
419662306a36Sopenharmony_ci	/* NOTE: acb->irq_level is set at IRQ registration time */
419762306a36Sopenharmony_ci
419862306a36Sopenharmony_ci	acb->tag_max_num = 1 << eeprom->max_tag;
419962306a36Sopenharmony_ci	if (acb->tag_max_num > 30)
420062306a36Sopenharmony_ci		acb->tag_max_num = 30;
420162306a36Sopenharmony_ci
420262306a36Sopenharmony_ci	acb->acb_flag = 0;	/* RESET_DETECT, RESET_DONE, RESET_DEV */
420362306a36Sopenharmony_ci	acb->gmode2 = eeprom->channel_cfg;
420462306a36Sopenharmony_ci	acb->config = 0;	/* NOTE: actually set in adapter_init_chip */
420562306a36Sopenharmony_ci
420662306a36Sopenharmony_ci	if (eeprom->channel_cfg & NAC_SCANLUN)
420762306a36Sopenharmony_ci		acb->lun_chk = 1;
420862306a36Sopenharmony_ci	acb->scan_devices = 1;
420962306a36Sopenharmony_ci
421062306a36Sopenharmony_ci	acb->scsi_host->this_id = eeprom->scsi_id;
421162306a36Sopenharmony_ci	acb->hostid_bit = (1 << acb->scsi_host->this_id);
421262306a36Sopenharmony_ci
421362306a36Sopenharmony_ci	for (i = 0; i < DC395x_MAX_SCSI_ID; i++)
421462306a36Sopenharmony_ci		acb->dcb_map[i] = 0;
421562306a36Sopenharmony_ci
421662306a36Sopenharmony_ci	acb->msg_len = 0;
421762306a36Sopenharmony_ci
421862306a36Sopenharmony_ci	/* link static array of srbs into the srb free list */
421962306a36Sopenharmony_ci	for (i = 0; i < acb->srb_count - 1; i++)
422062306a36Sopenharmony_ci		list_add_tail(&acb->srb_array[i].list, &acb->srb_free_list);
422162306a36Sopenharmony_ci}
422262306a36Sopenharmony_ci
422362306a36Sopenharmony_ci
422462306a36Sopenharmony_ci/**
422562306a36Sopenharmony_ci * adapter_init_scsi_host - Initialize the scsi host instance based on
422662306a36Sopenharmony_ci * values that we have already stored in the adapter instance. There's
422762306a36Sopenharmony_ci * some mention that a lot of these are deprecated, so we won't use
422862306a36Sopenharmony_ci * them (we'll use the ones in the adapter instance) but we'll fill
422962306a36Sopenharmony_ci * them in in case something else needs them.
423062306a36Sopenharmony_ci *
423162306a36Sopenharmony_ci * The eeprom structure, irq and io ports in the adapter need to have
423262306a36Sopenharmony_ci * been set before calling this function.
423362306a36Sopenharmony_ci *
423462306a36Sopenharmony_ci * @host: The scsi host instance to fill in the values for.
423562306a36Sopenharmony_ci **/
423662306a36Sopenharmony_cistatic void adapter_init_scsi_host(struct Scsi_Host *host)
423762306a36Sopenharmony_ci{
423862306a36Sopenharmony_ci        struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)host->hostdata;
423962306a36Sopenharmony_ci	struct NvRamType *eeprom = &acb->eeprom;
424062306a36Sopenharmony_ci
424162306a36Sopenharmony_ci	host->max_cmd_len = 24;
424262306a36Sopenharmony_ci	host->can_queue = DC395x_MAX_CMD_QUEUE;
424362306a36Sopenharmony_ci	host->cmd_per_lun = DC395x_MAX_CMD_PER_LUN;
424462306a36Sopenharmony_ci	host->this_id = (int)eeprom->scsi_id;
424562306a36Sopenharmony_ci	host->io_port = acb->io_port_base;
424662306a36Sopenharmony_ci	host->n_io_port = acb->io_port_len;
424762306a36Sopenharmony_ci	host->dma_channel = -1;
424862306a36Sopenharmony_ci	host->unique_id = acb->io_port_base;
424962306a36Sopenharmony_ci	host->irq = acb->irq_level;
425062306a36Sopenharmony_ci	acb->last_reset = jiffies;
425162306a36Sopenharmony_ci
425262306a36Sopenharmony_ci	host->max_id = 16;
425362306a36Sopenharmony_ci	if (host->max_id - 1 == eeprom->scsi_id)
425462306a36Sopenharmony_ci		host->max_id--;
425562306a36Sopenharmony_ci
425662306a36Sopenharmony_ci	if (eeprom->channel_cfg & NAC_SCANLUN)
425762306a36Sopenharmony_ci		host->max_lun = 8;
425862306a36Sopenharmony_ci	else
425962306a36Sopenharmony_ci		host->max_lun = 1;
426062306a36Sopenharmony_ci}
426162306a36Sopenharmony_ci
426262306a36Sopenharmony_ci
426362306a36Sopenharmony_ci/**
426462306a36Sopenharmony_ci * adapter_init_chip - Get the chip into a know state and figure out
426562306a36Sopenharmony_ci * some of the settings that apply to this adapter.
426662306a36Sopenharmony_ci *
426762306a36Sopenharmony_ci * The io port in the adapter needs to have been set before calling
426862306a36Sopenharmony_ci * this function. The config will be configured correctly on return.
426962306a36Sopenharmony_ci *
427062306a36Sopenharmony_ci * @acb: The adapter which we are to init.
427162306a36Sopenharmony_ci **/
427262306a36Sopenharmony_cistatic void adapter_init_chip(struct AdapterCtlBlk *acb)
427362306a36Sopenharmony_ci{
427462306a36Sopenharmony_ci        struct NvRamType *eeprom = &acb->eeprom;
427562306a36Sopenharmony_ci
427662306a36Sopenharmony_ci        /* Mask all the interrupt */
427762306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_DMA_INTEN, 0x00);
427862306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_INTEN, 0x00);
427962306a36Sopenharmony_ci
428062306a36Sopenharmony_ci	/* Reset SCSI module */
428162306a36Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_RSTMODULE);
428262306a36Sopenharmony_ci
428362306a36Sopenharmony_ci	/* Reset PCI/DMA module */
428462306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_DMA_CONTROL, DMARESETMODULE);
428562306a36Sopenharmony_ci	udelay(20);
428662306a36Sopenharmony_ci
428762306a36Sopenharmony_ci	/* program configuration 0 */
428862306a36Sopenharmony_ci	acb->config = HCC_AUTOTERM | HCC_PARITY;
428962306a36Sopenharmony_ci	if (DC395x_read8(acb, TRM_S1040_GEN_STATUS) & WIDESCSI)
429062306a36Sopenharmony_ci		acb->config |= HCC_WIDE_CARD;
429162306a36Sopenharmony_ci
429262306a36Sopenharmony_ci	if (eeprom->channel_cfg & NAC_POWERON_SCSI_RESET)
429362306a36Sopenharmony_ci		acb->config |= HCC_SCSI_RESET;
429462306a36Sopenharmony_ci
429562306a36Sopenharmony_ci	if (acb->config & HCC_SCSI_RESET) {
429662306a36Sopenharmony_ci		dprintkl(KERN_INFO, "Performing initial SCSI bus reset\n");
429762306a36Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_CONTROL, DO_RSTSCSI);
429862306a36Sopenharmony_ci
429962306a36Sopenharmony_ci		/*while (!( DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET )); */
430062306a36Sopenharmony_ci		/*spin_unlock_irq (&io_request_lock); */
430162306a36Sopenharmony_ci		udelay(500);
430262306a36Sopenharmony_ci
430362306a36Sopenharmony_ci		acb->last_reset =
430462306a36Sopenharmony_ci		    jiffies + HZ / 2 +
430562306a36Sopenharmony_ci		    HZ * acb->eeprom.delay_time;
430662306a36Sopenharmony_ci
430762306a36Sopenharmony_ci		/*spin_lock_irq (&io_request_lock); */
430862306a36Sopenharmony_ci	}
430962306a36Sopenharmony_ci}
431062306a36Sopenharmony_ci
431162306a36Sopenharmony_ci
431262306a36Sopenharmony_ci/**
431362306a36Sopenharmony_ci * adapter_init - Grab the resource for the card, setup the adapter
431462306a36Sopenharmony_ci * information, set the card into a known state, create the various
431562306a36Sopenharmony_ci * tables etc etc. This basically gets all adapter information all up
431662306a36Sopenharmony_ci * to date, initialised and gets the chip in sync with it.
431762306a36Sopenharmony_ci *
431862306a36Sopenharmony_ci * @acb:	The adapter which we are to init.
431962306a36Sopenharmony_ci * @io_port:	The base I/O port
432062306a36Sopenharmony_ci * @io_port_len: The I/O port size
432162306a36Sopenharmony_ci * @irq:	IRQ
432262306a36Sopenharmony_ci *
432362306a36Sopenharmony_ci * Returns 0 if the initialization succeeds, any other value on
432462306a36Sopenharmony_ci * failure.
432562306a36Sopenharmony_ci **/
432662306a36Sopenharmony_cistatic int adapter_init(struct AdapterCtlBlk *acb, unsigned long io_port,
432762306a36Sopenharmony_ci			u32 io_port_len, unsigned int irq)
432862306a36Sopenharmony_ci{
432962306a36Sopenharmony_ci	if (!request_region(io_port, io_port_len, DC395X_NAME)) {
433062306a36Sopenharmony_ci		dprintkl(KERN_ERR, "Failed to reserve IO region 0x%lx\n", io_port);
433162306a36Sopenharmony_ci		goto failed;
433262306a36Sopenharmony_ci	}
433362306a36Sopenharmony_ci	/* store port base to indicate we have registered it */
433462306a36Sopenharmony_ci	acb->io_port_base = io_port;
433562306a36Sopenharmony_ci	acb->io_port_len = io_port_len;
433662306a36Sopenharmony_ci
433762306a36Sopenharmony_ci	if (request_irq(irq, dc395x_interrupt, IRQF_SHARED, DC395X_NAME, acb)) {
433862306a36Sopenharmony_ci	    	/* release the region we just claimed */
433962306a36Sopenharmony_ci		dprintkl(KERN_INFO, "Failed to register IRQ\n");
434062306a36Sopenharmony_ci		goto failed;
434162306a36Sopenharmony_ci	}
434262306a36Sopenharmony_ci	/* store irq to indicate we have registered it */
434362306a36Sopenharmony_ci	acb->irq_level = irq;
434462306a36Sopenharmony_ci
434562306a36Sopenharmony_ci	/* get eeprom configuration information and command line settings etc */
434662306a36Sopenharmony_ci	check_eeprom(&acb->eeprom, io_port);
434762306a36Sopenharmony_ci 	print_eeprom_settings(&acb->eeprom);
434862306a36Sopenharmony_ci
434962306a36Sopenharmony_ci	/* setup adapter control block */
435062306a36Sopenharmony_ci	adapter_init_params(acb);
435162306a36Sopenharmony_ci
435262306a36Sopenharmony_ci	/* display card connectors/termination settings */
435362306a36Sopenharmony_ci 	adapter_print_config(acb);
435462306a36Sopenharmony_ci
435562306a36Sopenharmony_ci	if (adapter_sg_tables_alloc(acb)) {
435662306a36Sopenharmony_ci		dprintkl(KERN_DEBUG, "Memory allocation for SG tables failed\n");
435762306a36Sopenharmony_ci		goto failed;
435862306a36Sopenharmony_ci	}
435962306a36Sopenharmony_ci	adapter_init_scsi_host(acb->scsi_host);
436062306a36Sopenharmony_ci	adapter_init_chip(acb);
436162306a36Sopenharmony_ci	set_basic_config(acb);
436262306a36Sopenharmony_ci
436362306a36Sopenharmony_ci	dprintkdbg(DBG_0,
436462306a36Sopenharmony_ci		"adapter_init: acb=%p, pdcb_map=%p psrb_array=%p "
436562306a36Sopenharmony_ci		"size{acb=0x%04x dcb=0x%04x srb=0x%04x}\n",
436662306a36Sopenharmony_ci		acb, acb->dcb_map, acb->srb_array, sizeof(struct AdapterCtlBlk),
436762306a36Sopenharmony_ci		sizeof(struct DeviceCtlBlk), sizeof(struct ScsiReqBlk));
436862306a36Sopenharmony_ci	return 0;
436962306a36Sopenharmony_ci
437062306a36Sopenharmony_cifailed:
437162306a36Sopenharmony_ci	if (acb->irq_level)
437262306a36Sopenharmony_ci		free_irq(acb->irq_level, acb);
437362306a36Sopenharmony_ci	if (acb->io_port_base)
437462306a36Sopenharmony_ci		release_region(acb->io_port_base, acb->io_port_len);
437562306a36Sopenharmony_ci	adapter_sg_tables_free(acb);
437662306a36Sopenharmony_ci
437762306a36Sopenharmony_ci	return 1;
437862306a36Sopenharmony_ci}
437962306a36Sopenharmony_ci
438062306a36Sopenharmony_ci
438162306a36Sopenharmony_ci/**
438262306a36Sopenharmony_ci * adapter_uninit_chip - cleanly shut down the scsi controller chip,
438362306a36Sopenharmony_ci * stopping all operations and disabling interrupt generation on the
438462306a36Sopenharmony_ci * card.
438562306a36Sopenharmony_ci *
438662306a36Sopenharmony_ci * @acb: The adapter which we are to shutdown.
438762306a36Sopenharmony_ci **/
438862306a36Sopenharmony_cistatic void adapter_uninit_chip(struct AdapterCtlBlk *acb)
438962306a36Sopenharmony_ci{
439062306a36Sopenharmony_ci	/* disable interrupts */
439162306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_DMA_INTEN, 0);
439262306a36Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_INTEN, 0);
439362306a36Sopenharmony_ci
439462306a36Sopenharmony_ci	/* reset the scsi bus */
439562306a36Sopenharmony_ci	if (acb->config & HCC_SCSI_RESET)
439662306a36Sopenharmony_ci		reset_scsi_bus(acb);
439762306a36Sopenharmony_ci
439862306a36Sopenharmony_ci	/* clear any pending interrupt state */
439962306a36Sopenharmony_ci	DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS);
440062306a36Sopenharmony_ci}
440162306a36Sopenharmony_ci
440262306a36Sopenharmony_ci
440362306a36Sopenharmony_ci
440462306a36Sopenharmony_ci/**
440562306a36Sopenharmony_ci * adapter_uninit - Shut down the chip and release any resources that
440662306a36Sopenharmony_ci * we had allocated. Once this returns the adapter should not be used
440762306a36Sopenharmony_ci * anymore.
440862306a36Sopenharmony_ci *
440962306a36Sopenharmony_ci * @acb: The adapter which we are to un-initialize.
441062306a36Sopenharmony_ci **/
441162306a36Sopenharmony_cistatic void adapter_uninit(struct AdapterCtlBlk *acb)
441262306a36Sopenharmony_ci{
441362306a36Sopenharmony_ci	unsigned long flags;
441462306a36Sopenharmony_ci	DC395x_LOCK_IO(acb->scsi_host, flags);
441562306a36Sopenharmony_ci
441662306a36Sopenharmony_ci	/* remove timers */
441762306a36Sopenharmony_ci	if (timer_pending(&acb->waiting_timer))
441862306a36Sopenharmony_ci		del_timer(&acb->waiting_timer);
441962306a36Sopenharmony_ci	if (timer_pending(&acb->selto_timer))
442062306a36Sopenharmony_ci		del_timer(&acb->selto_timer);
442162306a36Sopenharmony_ci
442262306a36Sopenharmony_ci	adapter_uninit_chip(acb);
442362306a36Sopenharmony_ci	adapter_remove_and_free_all_devices(acb);
442462306a36Sopenharmony_ci	DC395x_UNLOCK_IO(acb->scsi_host, flags);
442562306a36Sopenharmony_ci
442662306a36Sopenharmony_ci	if (acb->irq_level)
442762306a36Sopenharmony_ci		free_irq(acb->irq_level, acb);
442862306a36Sopenharmony_ci	if (acb->io_port_base)
442962306a36Sopenharmony_ci		release_region(acb->io_port_base, acb->io_port_len);
443062306a36Sopenharmony_ci
443162306a36Sopenharmony_ci	adapter_sg_tables_free(acb);
443262306a36Sopenharmony_ci}
443362306a36Sopenharmony_ci
443462306a36Sopenharmony_ci
443562306a36Sopenharmony_ci#undef YESNO
443662306a36Sopenharmony_ci#define YESNO(YN) \
443762306a36Sopenharmony_ci if (YN) seq_printf(m, " Yes ");\
443862306a36Sopenharmony_ci else seq_printf(m, " No  ")
443962306a36Sopenharmony_ci
444062306a36Sopenharmony_cistatic int dc395x_show_info(struct seq_file *m, struct Scsi_Host *host)
444162306a36Sopenharmony_ci{
444262306a36Sopenharmony_ci	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)host->hostdata;
444362306a36Sopenharmony_ci	int spd, spd1;
444462306a36Sopenharmony_ci	struct DeviceCtlBlk *dcb;
444562306a36Sopenharmony_ci	unsigned long flags;
444662306a36Sopenharmony_ci	int dev;
444762306a36Sopenharmony_ci
444862306a36Sopenharmony_ci	seq_puts(m, DC395X_BANNER " PCI SCSI Host Adapter\n"
444962306a36Sopenharmony_ci		" Driver Version " DC395X_VERSION "\n");
445062306a36Sopenharmony_ci
445162306a36Sopenharmony_ci	DC395x_LOCK_IO(acb->scsi_host, flags);
445262306a36Sopenharmony_ci
445362306a36Sopenharmony_ci	seq_printf(m, "SCSI Host Nr %i, ", host->host_no);
445462306a36Sopenharmony_ci	seq_printf(m, "DC395U/UW/F DC315/U %s\n",
445562306a36Sopenharmony_ci		(acb->config & HCC_WIDE_CARD) ? "Wide" : "");
445662306a36Sopenharmony_ci	seq_printf(m, "io_port_base 0x%04lx, ", acb->io_port_base);
445762306a36Sopenharmony_ci	seq_printf(m, "irq_level 0x%04x, ", acb->irq_level);
445862306a36Sopenharmony_ci	seq_printf(m, " SelTimeout %ims\n", (1638 * acb->sel_timeout) / 1000);
445962306a36Sopenharmony_ci
446062306a36Sopenharmony_ci	seq_printf(m, "MaxID %i, MaxLUN %llu, ", host->max_id, host->max_lun);
446162306a36Sopenharmony_ci	seq_printf(m, "AdapterID %i\n", host->this_id);
446262306a36Sopenharmony_ci
446362306a36Sopenharmony_ci	seq_printf(m, "tag_max_num %i", acb->tag_max_num);
446462306a36Sopenharmony_ci	/*seq_printf(m, ", DMA_Status %i\n", DC395x_read8(acb, TRM_S1040_DMA_STATUS)); */
446562306a36Sopenharmony_ci	seq_printf(m, ", FilterCfg 0x%02x",
446662306a36Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_CONFIG1));
446762306a36Sopenharmony_ci	seq_printf(m, ", DelayReset %is\n", acb->eeprom.delay_time);
446862306a36Sopenharmony_ci	/*seq_printf(m, "\n"); */
446962306a36Sopenharmony_ci
447062306a36Sopenharmony_ci	seq_printf(m, "Nr of DCBs: %i\n", list_size(&acb->dcb_list));
447162306a36Sopenharmony_ci	seq_printf(m, "Map of attached LUNs: %8ph\n", &acb->dcb_map[0]);
447262306a36Sopenharmony_ci	seq_printf(m, "                      %8ph\n", &acb->dcb_map[8]);
447362306a36Sopenharmony_ci
447462306a36Sopenharmony_ci	seq_puts(m,
447562306a36Sopenharmony_ci		 "Un ID LUN Prty Sync Wide DsCn SndS TagQ nego_period SyncFreq SyncOffs MaxCmd\n");
447662306a36Sopenharmony_ci
447762306a36Sopenharmony_ci	dev = 0;
447862306a36Sopenharmony_ci	list_for_each_entry(dcb, &acb->dcb_list, list) {
447962306a36Sopenharmony_ci		int nego_period;
448062306a36Sopenharmony_ci		seq_printf(m, "%02i %02i  %02i ", dev, dcb->target_id,
448162306a36Sopenharmony_ci			dcb->target_lun);
448262306a36Sopenharmony_ci		YESNO(dcb->dev_mode & NTC_DO_PARITY_CHK);
448362306a36Sopenharmony_ci		YESNO(dcb->sync_offset);
448462306a36Sopenharmony_ci		YESNO(dcb->sync_period & WIDE_SYNC);
448562306a36Sopenharmony_ci		YESNO(dcb->dev_mode & NTC_DO_DISCONNECT);
448662306a36Sopenharmony_ci		YESNO(dcb->dev_mode & NTC_DO_SEND_START);
448762306a36Sopenharmony_ci		YESNO(dcb->sync_mode & EN_TAG_QUEUEING);
448862306a36Sopenharmony_ci		nego_period = clock_period[dcb->sync_period & 0x07] << 2;
448962306a36Sopenharmony_ci		if (dcb->sync_offset)
449062306a36Sopenharmony_ci			seq_printf(m, "  %03i ns ", nego_period);
449162306a36Sopenharmony_ci		else
449262306a36Sopenharmony_ci			seq_printf(m, " (%03i ns)", (dcb->min_nego_period << 2));
449362306a36Sopenharmony_ci
449462306a36Sopenharmony_ci		if (dcb->sync_offset & 0x0f) {
449562306a36Sopenharmony_ci			spd = 1000 / (nego_period);
449662306a36Sopenharmony_ci			spd1 = 1000 % (nego_period);
449762306a36Sopenharmony_ci			spd1 = (spd1 * 10 + nego_period / 2) / (nego_period);
449862306a36Sopenharmony_ci			seq_printf(m, "   %2i.%1i M     %02i ", spd, spd1,
449962306a36Sopenharmony_ci				(dcb->sync_offset & 0x0f));
450062306a36Sopenharmony_ci		} else
450162306a36Sopenharmony_ci			seq_puts(m, "                 ");
450262306a36Sopenharmony_ci
450362306a36Sopenharmony_ci		/* Add more info ... */
450462306a36Sopenharmony_ci		seq_printf(m, "     %02i\n", dcb->max_command);
450562306a36Sopenharmony_ci		dev++;
450662306a36Sopenharmony_ci	}
450762306a36Sopenharmony_ci
450862306a36Sopenharmony_ci	if (timer_pending(&acb->waiting_timer))
450962306a36Sopenharmony_ci		seq_puts(m, "Waiting queue timer running\n");
451062306a36Sopenharmony_ci	else
451162306a36Sopenharmony_ci		seq_putc(m, '\n');
451262306a36Sopenharmony_ci
451362306a36Sopenharmony_ci	list_for_each_entry(dcb, &acb->dcb_list, list) {
451462306a36Sopenharmony_ci		struct ScsiReqBlk *srb;
451562306a36Sopenharmony_ci		if (!list_empty(&dcb->srb_waiting_list))
451662306a36Sopenharmony_ci			seq_printf(m, "DCB (%02i-%i): Waiting: %i:",
451762306a36Sopenharmony_ci				dcb->target_id, dcb->target_lun,
451862306a36Sopenharmony_ci				list_size(&dcb->srb_waiting_list));
451962306a36Sopenharmony_ci                list_for_each_entry(srb, &dcb->srb_waiting_list, list)
452062306a36Sopenharmony_ci			seq_printf(m, " %p", srb->cmd);
452162306a36Sopenharmony_ci		if (!list_empty(&dcb->srb_going_list))
452262306a36Sopenharmony_ci			seq_printf(m, "\nDCB (%02i-%i): Going  : %i:",
452362306a36Sopenharmony_ci				dcb->target_id, dcb->target_lun,
452462306a36Sopenharmony_ci				list_size(&dcb->srb_going_list));
452562306a36Sopenharmony_ci		list_for_each_entry(srb, &dcb->srb_going_list, list)
452662306a36Sopenharmony_ci			seq_printf(m, " %p", srb->cmd);
452762306a36Sopenharmony_ci		if (!list_empty(&dcb->srb_waiting_list) || !list_empty(&dcb->srb_going_list))
452862306a36Sopenharmony_ci			seq_putc(m, '\n');
452962306a36Sopenharmony_ci	}
453062306a36Sopenharmony_ci
453162306a36Sopenharmony_ci	if (debug_enabled(DBG_1)) {
453262306a36Sopenharmony_ci		seq_printf(m, "DCB list for ACB %p:\n", acb);
453362306a36Sopenharmony_ci		list_for_each_entry(dcb, &acb->dcb_list, list) {
453462306a36Sopenharmony_ci			seq_printf(m, "%p -> ", dcb);
453562306a36Sopenharmony_ci		}
453662306a36Sopenharmony_ci		seq_puts(m, "END\n");
453762306a36Sopenharmony_ci	}
453862306a36Sopenharmony_ci
453962306a36Sopenharmony_ci	DC395x_UNLOCK_IO(acb->scsi_host, flags);
454062306a36Sopenharmony_ci	return 0;
454162306a36Sopenharmony_ci}
454262306a36Sopenharmony_ci
454362306a36Sopenharmony_ci
454462306a36Sopenharmony_cistatic const struct scsi_host_template dc395x_driver_template = {
454562306a36Sopenharmony_ci	.module                 = THIS_MODULE,
454662306a36Sopenharmony_ci	.proc_name              = DC395X_NAME,
454762306a36Sopenharmony_ci	.show_info              = dc395x_show_info,
454862306a36Sopenharmony_ci	.name                   = DC395X_BANNER " " DC395X_VERSION,
454962306a36Sopenharmony_ci	.queuecommand           = dc395x_queue_command,
455062306a36Sopenharmony_ci	.slave_alloc            = dc395x_slave_alloc,
455162306a36Sopenharmony_ci	.slave_destroy          = dc395x_slave_destroy,
455262306a36Sopenharmony_ci	.can_queue              = DC395x_MAX_CAN_QUEUE,
455362306a36Sopenharmony_ci	.this_id                = 7,
455462306a36Sopenharmony_ci	.sg_tablesize           = DC395x_MAX_SG_TABLESIZE,
455562306a36Sopenharmony_ci	.cmd_per_lun            = DC395x_MAX_CMD_PER_LUN,
455662306a36Sopenharmony_ci	.eh_abort_handler       = dc395x_eh_abort,
455762306a36Sopenharmony_ci	.eh_bus_reset_handler   = dc395x_eh_bus_reset,
455862306a36Sopenharmony_ci	.dma_boundary		= PAGE_SIZE - 1,
455962306a36Sopenharmony_ci};
456062306a36Sopenharmony_ci
456162306a36Sopenharmony_ci
456262306a36Sopenharmony_ci/**
456362306a36Sopenharmony_ci * banner_display - Display banner on first instance of driver
456462306a36Sopenharmony_ci * initialized.
456562306a36Sopenharmony_ci **/
456662306a36Sopenharmony_cistatic void banner_display(void)
456762306a36Sopenharmony_ci{
456862306a36Sopenharmony_ci	static int banner_done = 0;
456962306a36Sopenharmony_ci	if (!banner_done)
457062306a36Sopenharmony_ci	{
457162306a36Sopenharmony_ci		dprintkl(KERN_INFO, "%s %s\n", DC395X_BANNER, DC395X_VERSION);
457262306a36Sopenharmony_ci		banner_done = 1;
457362306a36Sopenharmony_ci	}
457462306a36Sopenharmony_ci}
457562306a36Sopenharmony_ci
457662306a36Sopenharmony_ci
457762306a36Sopenharmony_ci/**
457862306a36Sopenharmony_ci * dc395x_init_one - Initialise a single instance of the adapter.
457962306a36Sopenharmony_ci *
458062306a36Sopenharmony_ci * The PCI layer will call this once for each instance of the adapter
458162306a36Sopenharmony_ci * that it finds in the system. The pci_dev strcuture indicates which
458262306a36Sopenharmony_ci * instance we are being called from.
458362306a36Sopenharmony_ci *
458462306a36Sopenharmony_ci * @dev: The PCI device to initialize.
458562306a36Sopenharmony_ci * @id: Looks like a pointer to the entry in our pci device table
458662306a36Sopenharmony_ci * that was actually matched by the PCI subsystem.
458762306a36Sopenharmony_ci *
458862306a36Sopenharmony_ci * Returns 0 on success, or an error code (-ve) on failure.
458962306a36Sopenharmony_ci **/
459062306a36Sopenharmony_cistatic int dc395x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
459162306a36Sopenharmony_ci{
459262306a36Sopenharmony_ci	struct Scsi_Host *scsi_host = NULL;
459362306a36Sopenharmony_ci	struct AdapterCtlBlk *acb = NULL;
459462306a36Sopenharmony_ci	unsigned long io_port_base;
459562306a36Sopenharmony_ci	unsigned int io_port_len;
459662306a36Sopenharmony_ci	unsigned int irq;
459762306a36Sopenharmony_ci
459862306a36Sopenharmony_ci	dprintkdbg(DBG_0, "Init one instance (%s)\n", pci_name(dev));
459962306a36Sopenharmony_ci	banner_display();
460062306a36Sopenharmony_ci
460162306a36Sopenharmony_ci	if (pci_enable_device(dev))
460262306a36Sopenharmony_ci	{
460362306a36Sopenharmony_ci		dprintkl(KERN_INFO, "PCI Enable device failed.\n");
460462306a36Sopenharmony_ci		return -ENODEV;
460562306a36Sopenharmony_ci	}
460662306a36Sopenharmony_ci	io_port_base = pci_resource_start(dev, 0) & PCI_BASE_ADDRESS_IO_MASK;
460762306a36Sopenharmony_ci	io_port_len = pci_resource_len(dev, 0);
460862306a36Sopenharmony_ci	irq = dev->irq;
460962306a36Sopenharmony_ci	dprintkdbg(DBG_0, "IO_PORT=0x%04lx, IRQ=0x%x\n", io_port_base, dev->irq);
461062306a36Sopenharmony_ci
461162306a36Sopenharmony_ci	/* allocate scsi host information (includes out adapter) */
461262306a36Sopenharmony_ci	scsi_host = scsi_host_alloc(&dc395x_driver_template,
461362306a36Sopenharmony_ci				    sizeof(struct AdapterCtlBlk));
461462306a36Sopenharmony_ci	if (!scsi_host) {
461562306a36Sopenharmony_ci		dprintkl(KERN_INFO, "scsi_host_alloc failed\n");
461662306a36Sopenharmony_ci		goto fail;
461762306a36Sopenharmony_ci	}
461862306a36Sopenharmony_ci 	acb = (struct AdapterCtlBlk*)scsi_host->hostdata;
461962306a36Sopenharmony_ci 	acb->scsi_host = scsi_host;
462062306a36Sopenharmony_ci 	acb->dev = dev;
462162306a36Sopenharmony_ci
462262306a36Sopenharmony_ci	/* initialise the adapter and everything we need */
462362306a36Sopenharmony_ci 	if (adapter_init(acb, io_port_base, io_port_len, irq)) {
462462306a36Sopenharmony_ci		dprintkl(KERN_INFO, "adapter init failed\n");
462562306a36Sopenharmony_ci		acb = NULL;
462662306a36Sopenharmony_ci		goto fail;
462762306a36Sopenharmony_ci	}
462862306a36Sopenharmony_ci
462962306a36Sopenharmony_ci	pci_set_master(dev);
463062306a36Sopenharmony_ci
463162306a36Sopenharmony_ci	/* get the scsi mid level to scan for new devices on the bus */
463262306a36Sopenharmony_ci	if (scsi_add_host(scsi_host, &dev->dev)) {
463362306a36Sopenharmony_ci		dprintkl(KERN_ERR, "scsi_add_host failed\n");
463462306a36Sopenharmony_ci		goto fail;
463562306a36Sopenharmony_ci	}
463662306a36Sopenharmony_ci	pci_set_drvdata(dev, scsi_host);
463762306a36Sopenharmony_ci	scsi_scan_host(scsi_host);
463862306a36Sopenharmony_ci
463962306a36Sopenharmony_ci	return 0;
464062306a36Sopenharmony_ci
464162306a36Sopenharmony_cifail:
464262306a36Sopenharmony_ci	if (acb != NULL)
464362306a36Sopenharmony_ci		adapter_uninit(acb);
464462306a36Sopenharmony_ci	if (scsi_host != NULL)
464562306a36Sopenharmony_ci		scsi_host_put(scsi_host);
464662306a36Sopenharmony_ci	pci_disable_device(dev);
464762306a36Sopenharmony_ci	return -ENODEV;
464862306a36Sopenharmony_ci}
464962306a36Sopenharmony_ci
465062306a36Sopenharmony_ci
465162306a36Sopenharmony_ci/**
465262306a36Sopenharmony_ci * dc395x_remove_one - Called to remove a single instance of the
465362306a36Sopenharmony_ci * adapter.
465462306a36Sopenharmony_ci *
465562306a36Sopenharmony_ci * @dev: The PCI device to initialize.
465662306a36Sopenharmony_ci **/
465762306a36Sopenharmony_cistatic void dc395x_remove_one(struct pci_dev *dev)
465862306a36Sopenharmony_ci{
465962306a36Sopenharmony_ci	struct Scsi_Host *scsi_host = pci_get_drvdata(dev);
466062306a36Sopenharmony_ci	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)(scsi_host->hostdata);
466162306a36Sopenharmony_ci
466262306a36Sopenharmony_ci	dprintkdbg(DBG_0, "dc395x_remove_one: acb=%p\n", acb);
466362306a36Sopenharmony_ci
466462306a36Sopenharmony_ci	scsi_remove_host(scsi_host);
466562306a36Sopenharmony_ci	adapter_uninit(acb);
466662306a36Sopenharmony_ci	pci_disable_device(dev);
466762306a36Sopenharmony_ci	scsi_host_put(scsi_host);
466862306a36Sopenharmony_ci}
466962306a36Sopenharmony_ci
467062306a36Sopenharmony_ci
467162306a36Sopenharmony_cistatic struct pci_device_id dc395x_pci_table[] = {
467262306a36Sopenharmony_ci	{
467362306a36Sopenharmony_ci		.vendor		= PCI_VENDOR_ID_TEKRAM,
467462306a36Sopenharmony_ci		.device		= PCI_DEVICE_ID_TEKRAM_TRMS1040,
467562306a36Sopenharmony_ci		.subvendor	= PCI_ANY_ID,
467662306a36Sopenharmony_ci		.subdevice	= PCI_ANY_ID,
467762306a36Sopenharmony_ci	 },
467862306a36Sopenharmony_ci	{}			/* Terminating entry */
467962306a36Sopenharmony_ci};
468062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, dc395x_pci_table);
468162306a36Sopenharmony_ci
468262306a36Sopenharmony_ci
468362306a36Sopenharmony_cistatic struct pci_driver dc395x_driver = {
468462306a36Sopenharmony_ci	.name           = DC395X_NAME,
468562306a36Sopenharmony_ci	.id_table       = dc395x_pci_table,
468662306a36Sopenharmony_ci	.probe          = dc395x_init_one,
468762306a36Sopenharmony_ci	.remove         = dc395x_remove_one,
468862306a36Sopenharmony_ci};
468962306a36Sopenharmony_cimodule_pci_driver(dc395x_driver);
469062306a36Sopenharmony_ci
469162306a36Sopenharmony_ciMODULE_AUTHOR("C.L. Huang / Erich Chen / Kurt Garloff");
469262306a36Sopenharmony_ciMODULE_DESCRIPTION("SCSI host adapter driver for Tekram TRM-S1040 based adapters: Tekram DC395 and DC315 series");
469362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
4694