18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * dc395x.c
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Device Driver for Tekram DC395(U/UW/F), DC315(U)
58c2ecf20Sopenharmony_ci * PCI SCSI Bus Master Host Adapter
68c2ecf20Sopenharmony_ci * (SCSI chip set used Tekram ASIC TRM-S1040)
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Authors:
98c2ecf20Sopenharmony_ci *  C.L. Huang <ching@tekram.com.tw>
108c2ecf20Sopenharmony_ci *  Erich Chen <erich@tekram.com.tw>
118c2ecf20Sopenharmony_ci *  (C) Copyright 1995-1999 Tekram Technology Co., Ltd.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci *  Kurt Garloff <garloff@suse.de>
148c2ecf20Sopenharmony_ci *  (C) 1999-2000 Kurt Garloff
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci *  Oliver Neukum <oliver@neukum.name>
178c2ecf20Sopenharmony_ci *  Ali Akcaagac <aliakc@web.de>
188c2ecf20Sopenharmony_ci *  Jamie Lenehan <lenehan@twibble.org>
198c2ecf20Sopenharmony_ci *  (C) 2003
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * License: GNU GPL
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci *************************************************************************
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
268c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions
278c2ecf20Sopenharmony_ci * are met:
288c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
298c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer.
308c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
318c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
328c2ecf20Sopenharmony_ci *    documentation and/or other materials provided with the distribution.
338c2ecf20Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products
348c2ecf20Sopenharmony_ci *    derived from this software without specific prior written permission.
358c2ecf20Sopenharmony_ci *
368c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
378c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
388c2ecf20Sopenharmony_ci * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
398c2ecf20Sopenharmony_ci * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
408c2ecf20Sopenharmony_ci * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
418c2ecf20Sopenharmony_ci * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
428c2ecf20Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
438c2ecf20Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
448c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
458c2ecf20Sopenharmony_ci * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
468c2ecf20Sopenharmony_ci *
478c2ecf20Sopenharmony_ci ************************************************************************
488c2ecf20Sopenharmony_ci */
498c2ecf20Sopenharmony_ci#include <linux/module.h>
508c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
518c2ecf20Sopenharmony_ci#include <linux/delay.h>
528c2ecf20Sopenharmony_ci#include <linux/ctype.h>
538c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
548c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
558c2ecf20Sopenharmony_ci#include <linux/init.h>
568c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
578c2ecf20Sopenharmony_ci#include <linux/pci.h>
588c2ecf20Sopenharmony_ci#include <linux/list.h>
598c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
608c2ecf20Sopenharmony_ci#include <linux/slab.h>
618c2ecf20Sopenharmony_ci#include <asm/io.h>
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci#include <scsi/scsi.h>
648c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h>
658c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h>
668c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h>
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci#include "dc395x.h"
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci#define DC395X_NAME	"dc395x"
718c2ecf20Sopenharmony_ci#define DC395X_BANNER	"Tekram DC395(U/UW/F), DC315(U) - ASIC TRM-S1040"
728c2ecf20Sopenharmony_ci#define DC395X_VERSION	"v2.05, 2004/03/08"
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci/*---------------------------------------------------------------------------
758c2ecf20Sopenharmony_ci                                  Features
768c2ecf20Sopenharmony_ci ---------------------------------------------------------------------------*/
778c2ecf20Sopenharmony_ci/*
788c2ecf20Sopenharmony_ci * Set to disable parts of the driver
798c2ecf20Sopenharmony_ci */
808c2ecf20Sopenharmony_ci/*#define DC395x_NO_DISCONNECT*/
818c2ecf20Sopenharmony_ci/*#define DC395x_NO_TAGQ*/
828c2ecf20Sopenharmony_ci/*#define DC395x_NO_SYNC*/
838c2ecf20Sopenharmony_ci/*#define DC395x_NO_WIDE*/
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci/*---------------------------------------------------------------------------
868c2ecf20Sopenharmony_ci                                  Debugging
878c2ecf20Sopenharmony_ci ---------------------------------------------------------------------------*/
888c2ecf20Sopenharmony_ci/*
898c2ecf20Sopenharmony_ci * Types of debugging that can be enabled and disabled
908c2ecf20Sopenharmony_ci */
918c2ecf20Sopenharmony_ci#define DBG_KG		0x0001
928c2ecf20Sopenharmony_ci#define DBG_0		0x0002
938c2ecf20Sopenharmony_ci#define DBG_1		0x0004
948c2ecf20Sopenharmony_ci#define DBG_SG		0x0020
958c2ecf20Sopenharmony_ci#define DBG_FIFO	0x0040
968c2ecf20Sopenharmony_ci#define DBG_PIO		0x0080
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci/*
1008c2ecf20Sopenharmony_ci * Set set of things to output debugging for.
1018c2ecf20Sopenharmony_ci * Undefine to remove all debugging
1028c2ecf20Sopenharmony_ci */
1038c2ecf20Sopenharmony_ci/*#define DEBUG_MASK (DBG_0|DBG_1|DBG_SG|DBG_FIFO|DBG_PIO)*/
1048c2ecf20Sopenharmony_ci/*#define  DEBUG_MASK	DBG_0*/
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci/*
1088c2ecf20Sopenharmony_ci * Output a kernel mesage at the specified level and append the
1098c2ecf20Sopenharmony_ci * driver name and a ": " to the start of the message
1108c2ecf20Sopenharmony_ci */
1118c2ecf20Sopenharmony_ci#define dprintkl(level, format, arg...)  \
1128c2ecf20Sopenharmony_ci    printk(level DC395X_NAME ": " format , ## arg)
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci#ifdef DEBUG_MASK
1168c2ecf20Sopenharmony_ci/*
1178c2ecf20Sopenharmony_ci * print a debug message - this is formated with KERN_DEBUG, then the
1188c2ecf20Sopenharmony_ci * driver name followed by a ": " and then the message is output.
1198c2ecf20Sopenharmony_ci * This also checks that the specified debug level is enabled before
1208c2ecf20Sopenharmony_ci * outputing the message
1218c2ecf20Sopenharmony_ci */
1228c2ecf20Sopenharmony_ci#define dprintkdbg(type, format, arg...) \
1238c2ecf20Sopenharmony_ci	do { \
1248c2ecf20Sopenharmony_ci		if ((type) & (DEBUG_MASK)) \
1258c2ecf20Sopenharmony_ci			dprintkl(KERN_DEBUG , format , ## arg); \
1268c2ecf20Sopenharmony_ci	} while (0)
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci/*
1298c2ecf20Sopenharmony_ci * Check if the specified type of debugging is enabled
1308c2ecf20Sopenharmony_ci */
1318c2ecf20Sopenharmony_ci#define debug_enabled(type)	((DEBUG_MASK) & (type))
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci#else
1348c2ecf20Sopenharmony_ci/*
1358c2ecf20Sopenharmony_ci * No debugging. Do nothing
1368c2ecf20Sopenharmony_ci */
1378c2ecf20Sopenharmony_ci#define dprintkdbg(type, format, arg...) \
1388c2ecf20Sopenharmony_ci	do {} while (0)
1398c2ecf20Sopenharmony_ci#define debug_enabled(type)	(0)
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci#endif
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci#ifndef PCI_VENDOR_ID_TEKRAM
1458c2ecf20Sopenharmony_ci#define PCI_VENDOR_ID_TEKRAM                    0x1DE1	/* Vendor ID    */
1468c2ecf20Sopenharmony_ci#endif
1478c2ecf20Sopenharmony_ci#ifndef PCI_DEVICE_ID_TEKRAM_TRMS1040
1488c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_TEKRAM_TRMS1040           0x0391	/* Device ID    */
1498c2ecf20Sopenharmony_ci#endif
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci#define DC395x_LOCK_IO(dev,flags)		spin_lock_irqsave(((struct Scsi_Host *)dev)->host_lock, flags)
1538c2ecf20Sopenharmony_ci#define DC395x_UNLOCK_IO(dev,flags)		spin_unlock_irqrestore(((struct Scsi_Host *)dev)->host_lock, flags)
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci#define DC395x_read8(acb,address)		(u8)(inb(acb->io_port_base + (address)))
1568c2ecf20Sopenharmony_ci#define DC395x_read16(acb,address)		(u16)(inw(acb->io_port_base + (address)))
1578c2ecf20Sopenharmony_ci#define DC395x_read32(acb,address)		(u32)(inl(acb->io_port_base + (address)))
1588c2ecf20Sopenharmony_ci#define DC395x_write8(acb,address,value)	outb((value), acb->io_port_base + (address))
1598c2ecf20Sopenharmony_ci#define DC395x_write16(acb,address,value)	outw((value), acb->io_port_base + (address))
1608c2ecf20Sopenharmony_ci#define DC395x_write32(acb,address,value)	outl((value), acb->io_port_base + (address))
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci/* cmd->result */
1638c2ecf20Sopenharmony_ci#define RES_TARGET		0x000000FF	/* Target State */
1648c2ecf20Sopenharmony_ci#define RES_TARGET_LNX  STATUS_MASK	/* Only official ... */
1658c2ecf20Sopenharmony_ci#define RES_ENDMSG		0x0000FF00	/* End Message */
1668c2ecf20Sopenharmony_ci#define RES_DID			0x00FF0000	/* DID_ codes */
1678c2ecf20Sopenharmony_ci#define RES_DRV			0xFF000000	/* DRIVER_ codes */
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci#define MK_RES(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt))
1708c2ecf20Sopenharmony_ci#define MK_RES_LNX(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt)<<1)
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci#define SET_RES_TARGET(who,tgt) { who &= ~RES_TARGET; who |= (int)(tgt); }
1738c2ecf20Sopenharmony_ci#define SET_RES_TARGET_LNX(who,tgt) { who &= ~RES_TARGET_LNX; who |= (int)(tgt) << 1; }
1748c2ecf20Sopenharmony_ci#define SET_RES_MSG(who,msg) { who &= ~RES_ENDMSG; who |= (int)(msg) << 8; }
1758c2ecf20Sopenharmony_ci#define SET_RES_DID(who,did) { who &= ~RES_DID; who |= (int)(did) << 16; }
1768c2ecf20Sopenharmony_ci#define SET_RES_DRV(who,drv) { who &= ~RES_DRV; who |= (int)(drv) << 24; }
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci#define TAG_NONE 255
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci/*
1818c2ecf20Sopenharmony_ci * srb->segement_x is the hw sg list. It is always allocated as a
1828c2ecf20Sopenharmony_ci * DC395x_MAX_SG_LISTENTRY entries in a linear block which does not
1838c2ecf20Sopenharmony_ci * cross a page boundy.
1848c2ecf20Sopenharmony_ci */
1858c2ecf20Sopenharmony_ci#define SEGMENTX_LEN	(sizeof(struct SGentry)*DC395x_MAX_SG_LISTENTRY)
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistruct SGentry {
1898c2ecf20Sopenharmony_ci	u32 address;		/* bus! address */
1908c2ecf20Sopenharmony_ci	u32 length;
1918c2ecf20Sopenharmony_ci};
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci/* The SEEPROM structure for TRM_S1040 */
1948c2ecf20Sopenharmony_cistruct NVRamTarget {
1958c2ecf20Sopenharmony_ci	u8 cfg0;		/* Target configuration byte 0  */
1968c2ecf20Sopenharmony_ci	u8 period;		/* Target period                */
1978c2ecf20Sopenharmony_ci	u8 cfg2;		/* Target configuration byte 2  */
1988c2ecf20Sopenharmony_ci	u8 cfg3;		/* Target configuration byte 3  */
1998c2ecf20Sopenharmony_ci};
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cistruct NvRamType {
2028c2ecf20Sopenharmony_ci	u8 sub_vendor_id[2];	/* 0,1  Sub Vendor ID   */
2038c2ecf20Sopenharmony_ci	u8 sub_sys_id[2];	/* 2,3  Sub System ID   */
2048c2ecf20Sopenharmony_ci	u8 sub_class;		/* 4    Sub Class       */
2058c2ecf20Sopenharmony_ci	u8 vendor_id[2];	/* 5,6  Vendor ID       */
2068c2ecf20Sopenharmony_ci	u8 device_id[2];	/* 7,8  Device ID       */
2078c2ecf20Sopenharmony_ci	u8 reserved;		/* 9    Reserved        */
2088c2ecf20Sopenharmony_ci	struct NVRamTarget target[DC395x_MAX_SCSI_ID];
2098c2ecf20Sopenharmony_ci						/** 10,11,12,13
2108c2ecf20Sopenharmony_ci						 ** 14,15,16,17
2118c2ecf20Sopenharmony_ci						 ** ....
2128c2ecf20Sopenharmony_ci						 ** ....
2138c2ecf20Sopenharmony_ci						 ** 70,71,72,73
2148c2ecf20Sopenharmony_ci						 */
2158c2ecf20Sopenharmony_ci	u8 scsi_id;		/* 74 Host Adapter SCSI ID      */
2168c2ecf20Sopenharmony_ci	u8 channel_cfg;		/* 75 Channel configuration     */
2178c2ecf20Sopenharmony_ci	u8 delay_time;		/* 76 Power on delay time       */
2188c2ecf20Sopenharmony_ci	u8 max_tag;		/* 77 Maximum tags              */
2198c2ecf20Sopenharmony_ci	u8 reserved0;		/* 78  */
2208c2ecf20Sopenharmony_ci	u8 boot_target;		/* 79  */
2218c2ecf20Sopenharmony_ci	u8 boot_lun;		/* 80  */
2228c2ecf20Sopenharmony_ci	u8 reserved1;		/* 81  */
2238c2ecf20Sopenharmony_ci	u16 reserved2[22];	/* 82,..125 */
2248c2ecf20Sopenharmony_ci	u16 cksum;		/* 126,127 */
2258c2ecf20Sopenharmony_ci};
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistruct ScsiReqBlk {
2288c2ecf20Sopenharmony_ci	struct list_head list;		/* next/prev ptrs for srb lists */
2298c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb;
2308c2ecf20Sopenharmony_ci	struct scsi_cmnd *cmd;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	struct SGentry *segment_x;	/* Linear array of hw sg entries (up to 64 entries) */
2338c2ecf20Sopenharmony_ci	dma_addr_t sg_bus_addr;	        /* Bus address of sg list (ie, of segment_x) */
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	u8 sg_count;			/* No of HW sg entries for this request */
2368c2ecf20Sopenharmony_ci	u8 sg_index;			/* Index of HW sg entry for this request */
2378c2ecf20Sopenharmony_ci	size_t total_xfer_length;	/* Total number of bytes remaining to be transferred */
2388c2ecf20Sopenharmony_ci	size_t request_length;		/* Total number of bytes in this request */
2398c2ecf20Sopenharmony_ci	/*
2408c2ecf20Sopenharmony_ci	 * The sense buffer handling function, request_sense, uses
2418c2ecf20Sopenharmony_ci	 * the first hw sg entry (segment_x[0]) and the transfer
2428c2ecf20Sopenharmony_ci	 * length (total_xfer_length). While doing this it stores the
2438c2ecf20Sopenharmony_ci	 * original values into the last sg hw list
2448c2ecf20Sopenharmony_ci	 * (srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1] and the
2458c2ecf20Sopenharmony_ci	 * total_xfer_length in xferred. These values are restored in
2468c2ecf20Sopenharmony_ci	 * pci_unmap_srb_sense. This is the only place xferred is used.
2478c2ecf20Sopenharmony_ci	 */
2488c2ecf20Sopenharmony_ci	size_t xferred;		        /* Saved copy of total_xfer_length */
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	u16 state;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	u8 msgin_buf[6];
2538c2ecf20Sopenharmony_ci	u8 msgout_buf[6];
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	u8 adapter_status;
2568c2ecf20Sopenharmony_ci	u8 target_status;
2578c2ecf20Sopenharmony_ci	u8 msg_count;
2588c2ecf20Sopenharmony_ci	u8 end_message;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	u8 tag_number;
2618c2ecf20Sopenharmony_ci	u8 status;
2628c2ecf20Sopenharmony_ci	u8 retry_count;
2638c2ecf20Sopenharmony_ci	u8 flag;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	u8 scsi_phase;
2668c2ecf20Sopenharmony_ci};
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cistruct DeviceCtlBlk {
2698c2ecf20Sopenharmony_ci	struct list_head list;		/* next/prev ptrs for the dcb list */
2708c2ecf20Sopenharmony_ci	struct AdapterCtlBlk *acb;
2718c2ecf20Sopenharmony_ci	struct list_head srb_going_list;	/* head of going srb list */
2728c2ecf20Sopenharmony_ci	struct list_head srb_waiting_list;	/* head of waiting srb list */
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	struct ScsiReqBlk *active_srb;
2758c2ecf20Sopenharmony_ci	u32 tag_mask;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	u16 max_command;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	u8 target_id;		/* SCSI Target ID  (SCSI Only) */
2808c2ecf20Sopenharmony_ci	u8 target_lun;		/* SCSI Log.  Unit (SCSI Only) */
2818c2ecf20Sopenharmony_ci	u8 identify_msg;
2828c2ecf20Sopenharmony_ci	u8 dev_mode;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	u8 inquiry7;		/* To store Inquiry flags */
2858c2ecf20Sopenharmony_ci	u8 sync_mode;		/* 0:async mode */
2868c2ecf20Sopenharmony_ci	u8 min_nego_period;	/* for nego. */
2878c2ecf20Sopenharmony_ci	u8 sync_period;		/* for reg.  */
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	u8 sync_offset;		/* for reg. and nego.(low nibble) */
2908c2ecf20Sopenharmony_ci	u8 flag;
2918c2ecf20Sopenharmony_ci	u8 dev_type;
2928c2ecf20Sopenharmony_ci	u8 init_tcq_flag;
2938c2ecf20Sopenharmony_ci};
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_cistruct AdapterCtlBlk {
2968c2ecf20Sopenharmony_ci	struct Scsi_Host *scsi_host;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	unsigned long io_port_base;
2998c2ecf20Sopenharmony_ci	unsigned long io_port_len;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	struct list_head dcb_list;		/* head of going dcb list */
3028c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb_run_robin;
3038c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *active_dcb;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	struct list_head srb_free_list;		/* head of free srb list */
3068c2ecf20Sopenharmony_ci	struct ScsiReqBlk *tmp_srb;
3078c2ecf20Sopenharmony_ci	struct timer_list waiting_timer;
3088c2ecf20Sopenharmony_ci	struct timer_list selto_timer;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	unsigned long last_reset;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	u16 srb_count;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	u8 sel_timeout;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	unsigned int irq_level;
3178c2ecf20Sopenharmony_ci	u8 tag_max_num;
3188c2ecf20Sopenharmony_ci	u8 acb_flag;
3198c2ecf20Sopenharmony_ci	u8 gmode2;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	u8 config;
3228c2ecf20Sopenharmony_ci	u8 lun_chk;
3238c2ecf20Sopenharmony_ci	u8 scan_devices;
3248c2ecf20Sopenharmony_ci	u8 hostid_bit;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	u8 dcb_map[DC395x_MAX_SCSI_ID];
3278c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *children[DC395x_MAX_SCSI_ID][32];
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	struct pci_dev *dev;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	u8 msg_len;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	struct ScsiReqBlk srb_array[DC395x_MAX_SRB_CNT];
3348c2ecf20Sopenharmony_ci	struct ScsiReqBlk srb;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	struct NvRamType eeprom;	/* eeprom settings for this adapter */
3378c2ecf20Sopenharmony_ci};
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci/*---------------------------------------------------------------------------
3418c2ecf20Sopenharmony_ci                            Forward declarations
3428c2ecf20Sopenharmony_ci ---------------------------------------------------------------------------*/
3438c2ecf20Sopenharmony_cistatic void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
3448c2ecf20Sopenharmony_ci		u16 *pscsi_status);
3458c2ecf20Sopenharmony_cistatic void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
3468c2ecf20Sopenharmony_ci		u16 *pscsi_status);
3478c2ecf20Sopenharmony_cistatic void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
3488c2ecf20Sopenharmony_ci		u16 *pscsi_status);
3498c2ecf20Sopenharmony_cistatic void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
3508c2ecf20Sopenharmony_ci		u16 *pscsi_status);
3518c2ecf20Sopenharmony_cistatic void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
3528c2ecf20Sopenharmony_ci		u16 *pscsi_status);
3538c2ecf20Sopenharmony_cistatic void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
3548c2ecf20Sopenharmony_ci		u16 *pscsi_status);
3558c2ecf20Sopenharmony_cistatic void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
3568c2ecf20Sopenharmony_ci		u16 *pscsi_status);
3578c2ecf20Sopenharmony_cistatic void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
3588c2ecf20Sopenharmony_ci		u16 *pscsi_status);
3598c2ecf20Sopenharmony_cistatic void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
3608c2ecf20Sopenharmony_ci		u16 *pscsi_status);
3618c2ecf20Sopenharmony_cistatic void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
3628c2ecf20Sopenharmony_ci		u16 *pscsi_status);
3638c2ecf20Sopenharmony_cistatic void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
3648c2ecf20Sopenharmony_ci		u16 *pscsi_status);
3658c2ecf20Sopenharmony_cistatic void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
3668c2ecf20Sopenharmony_ci		u16 *pscsi_status);
3678c2ecf20Sopenharmony_cistatic void nop0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
3688c2ecf20Sopenharmony_ci		u16 *pscsi_status);
3698c2ecf20Sopenharmony_cistatic void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
3708c2ecf20Sopenharmony_ci		u16 *pscsi_status);
3718c2ecf20Sopenharmony_cistatic void set_basic_config(struct AdapterCtlBlk *acb);
3728c2ecf20Sopenharmony_cistatic void cleanup_after_transfer(struct AdapterCtlBlk *acb,
3738c2ecf20Sopenharmony_ci		struct ScsiReqBlk *srb);
3748c2ecf20Sopenharmony_cistatic void reset_scsi_bus(struct AdapterCtlBlk *acb);
3758c2ecf20Sopenharmony_cistatic void data_io_transfer(struct AdapterCtlBlk *acb,
3768c2ecf20Sopenharmony_ci		struct ScsiReqBlk *srb, u16 io_dir);
3778c2ecf20Sopenharmony_cistatic void disconnect(struct AdapterCtlBlk *acb);
3788c2ecf20Sopenharmony_cistatic void reselect(struct AdapterCtlBlk *acb);
3798c2ecf20Sopenharmony_cistatic u8 start_scsi(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
3808c2ecf20Sopenharmony_ci		struct ScsiReqBlk *srb);
3818c2ecf20Sopenharmony_cistatic inline void enable_msgout_abort(struct AdapterCtlBlk *acb,
3828c2ecf20Sopenharmony_ci		struct ScsiReqBlk *srb);
3838c2ecf20Sopenharmony_cistatic void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
3848c2ecf20Sopenharmony_ci		struct ScsiReqBlk *srb);
3858c2ecf20Sopenharmony_cistatic void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_code,
3868c2ecf20Sopenharmony_ci		struct scsi_cmnd *cmd, u8 force);
3878c2ecf20Sopenharmony_cistatic void scsi_reset_detect(struct AdapterCtlBlk *acb);
3888c2ecf20Sopenharmony_cistatic void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb);
3898c2ecf20Sopenharmony_cistatic void pci_unmap_srb_sense(struct AdapterCtlBlk *acb,
3908c2ecf20Sopenharmony_ci		struct ScsiReqBlk *srb);
3918c2ecf20Sopenharmony_cistatic void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
3928c2ecf20Sopenharmony_ci		struct ScsiReqBlk *srb);
3938c2ecf20Sopenharmony_cistatic void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
3948c2ecf20Sopenharmony_ci		struct ScsiReqBlk *srb);
3958c2ecf20Sopenharmony_cistatic void set_xfer_rate(struct AdapterCtlBlk *acb,
3968c2ecf20Sopenharmony_ci		struct DeviceCtlBlk *dcb);
3978c2ecf20Sopenharmony_cistatic void waiting_timeout(struct timer_list *t);
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci/*---------------------------------------------------------------------------
4018c2ecf20Sopenharmony_ci                                 Static Data
4028c2ecf20Sopenharmony_ci ---------------------------------------------------------------------------*/
4038c2ecf20Sopenharmony_cistatic u16 current_sync_offset = 0;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_cistatic void *dc395x_scsi_phase0[] = {
4068c2ecf20Sopenharmony_ci	data_out_phase0,/* phase:0 */
4078c2ecf20Sopenharmony_ci	data_in_phase0,	/* phase:1 */
4088c2ecf20Sopenharmony_ci	command_phase0,	/* phase:2 */
4098c2ecf20Sopenharmony_ci	status_phase0,	/* phase:3 */
4108c2ecf20Sopenharmony_ci	nop0,		/* phase:4 PH_BUS_FREE .. initial phase */
4118c2ecf20Sopenharmony_ci	nop0,		/* phase:5 PH_BUS_FREE .. initial phase */
4128c2ecf20Sopenharmony_ci	msgout_phase0,	/* phase:6 */
4138c2ecf20Sopenharmony_ci	msgin_phase0,	/* phase:7 */
4148c2ecf20Sopenharmony_ci};
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_cistatic void *dc395x_scsi_phase1[] = {
4178c2ecf20Sopenharmony_ci	data_out_phase1,/* phase:0 */
4188c2ecf20Sopenharmony_ci	data_in_phase1,	/* phase:1 */
4198c2ecf20Sopenharmony_ci	command_phase1,	/* phase:2 */
4208c2ecf20Sopenharmony_ci	status_phase1,	/* phase:3 */
4218c2ecf20Sopenharmony_ci	nop1,		/* phase:4 PH_BUS_FREE .. initial phase */
4228c2ecf20Sopenharmony_ci	nop1,		/* phase:5 PH_BUS_FREE .. initial phase */
4238c2ecf20Sopenharmony_ci	msgout_phase1,	/* phase:6 */
4248c2ecf20Sopenharmony_ci	msgin_phase1,	/* phase:7 */
4258c2ecf20Sopenharmony_ci};
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci/*
4288c2ecf20Sopenharmony_ci *Fast20:	000	 50ns, 20.0 MHz
4298c2ecf20Sopenharmony_ci *		001	 75ns, 13.3 MHz
4308c2ecf20Sopenharmony_ci *		010	100ns, 10.0 MHz
4318c2ecf20Sopenharmony_ci *		011	125ns,  8.0 MHz
4328c2ecf20Sopenharmony_ci *		100	150ns,  6.6 MHz
4338c2ecf20Sopenharmony_ci *		101	175ns,  5.7 MHz
4348c2ecf20Sopenharmony_ci *		110	200ns,  5.0 MHz
4358c2ecf20Sopenharmony_ci *		111	250ns,  4.0 MHz
4368c2ecf20Sopenharmony_ci *
4378c2ecf20Sopenharmony_ci *Fast40(LVDS):	000	 25ns, 40.0 MHz
4388c2ecf20Sopenharmony_ci *		001	 50ns, 20.0 MHz
4398c2ecf20Sopenharmony_ci *		010	 75ns, 13.3 MHz
4408c2ecf20Sopenharmony_ci *		011	100ns, 10.0 MHz
4418c2ecf20Sopenharmony_ci *		100	125ns,  8.0 MHz
4428c2ecf20Sopenharmony_ci *		101	150ns,  6.6 MHz
4438c2ecf20Sopenharmony_ci *		110	175ns,  5.7 MHz
4448c2ecf20Sopenharmony_ci *		111	200ns,  5.0 MHz
4458c2ecf20Sopenharmony_ci */
4468c2ecf20Sopenharmony_ci/*static u8	clock_period[] = {12,19,25,31,37,44,50,62};*/
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci/* real period:48ns,76ns,100ns,124ns,148ns,176ns,200ns,248ns */
4498c2ecf20Sopenharmony_cistatic u8 clock_period[] = { 12, 18, 25, 31, 37, 43, 50, 62 };
4508c2ecf20Sopenharmony_cistatic u16 clock_speed[] = { 200, 133, 100, 80, 67, 58, 50, 40 };
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci/*---------------------------------------------------------------------------
4548c2ecf20Sopenharmony_ci                                Configuration
4558c2ecf20Sopenharmony_ci  ---------------------------------------------------------------------------*/
4568c2ecf20Sopenharmony_ci/*
4578c2ecf20Sopenharmony_ci * Module/boot parameters currently effect *all* instances of the
4588c2ecf20Sopenharmony_ci * card in the system.
4598c2ecf20Sopenharmony_ci */
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci/*
4628c2ecf20Sopenharmony_ci * Command line parameters are stored in a structure below.
4638c2ecf20Sopenharmony_ci * These are the index's into the structure for the various
4648c2ecf20Sopenharmony_ci * command line options.
4658c2ecf20Sopenharmony_ci */
4668c2ecf20Sopenharmony_ci#define CFG_ADAPTER_ID		0
4678c2ecf20Sopenharmony_ci#define CFG_MAX_SPEED		1
4688c2ecf20Sopenharmony_ci#define CFG_DEV_MODE		2
4698c2ecf20Sopenharmony_ci#define CFG_ADAPTER_MODE	3
4708c2ecf20Sopenharmony_ci#define CFG_TAGS		4
4718c2ecf20Sopenharmony_ci#define CFG_RESET_DELAY		5
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci#define CFG_NUM			6	/* number of configuration items */
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci/*
4778c2ecf20Sopenharmony_ci * Value used to indicate that a command line override
4788c2ecf20Sopenharmony_ci * hasn't been used to modify the value.
4798c2ecf20Sopenharmony_ci */
4808c2ecf20Sopenharmony_ci#define CFG_PARAM_UNSET -1
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci/*
4848c2ecf20Sopenharmony_ci * Hold command line parameters.
4858c2ecf20Sopenharmony_ci */
4868c2ecf20Sopenharmony_cistruct ParameterData {
4878c2ecf20Sopenharmony_ci	int value;		/* value of this setting */
4888c2ecf20Sopenharmony_ci	int min;		/* minimum value */
4898c2ecf20Sopenharmony_ci	int max;		/* maximum value */
4908c2ecf20Sopenharmony_ci	int def;		/* default value */
4918c2ecf20Sopenharmony_ci	int safe;		/* safe value */
4928c2ecf20Sopenharmony_ci};
4938c2ecf20Sopenharmony_cistatic struct ParameterData cfg_data[] = {
4948c2ecf20Sopenharmony_ci	{ /* adapter id */
4958c2ecf20Sopenharmony_ci		CFG_PARAM_UNSET,
4968c2ecf20Sopenharmony_ci		0,
4978c2ecf20Sopenharmony_ci		15,
4988c2ecf20Sopenharmony_ci		7,
4998c2ecf20Sopenharmony_ci		7
5008c2ecf20Sopenharmony_ci	},
5018c2ecf20Sopenharmony_ci	{ /* max speed */
5028c2ecf20Sopenharmony_ci		CFG_PARAM_UNSET,
5038c2ecf20Sopenharmony_ci		  0,
5048c2ecf20Sopenharmony_ci		  7,
5058c2ecf20Sopenharmony_ci		  1,	/* 13.3Mhz */
5068c2ecf20Sopenharmony_ci		  4,	/*  6.7Hmz */
5078c2ecf20Sopenharmony_ci	},
5088c2ecf20Sopenharmony_ci	{ /* dev mode */
5098c2ecf20Sopenharmony_ci		CFG_PARAM_UNSET,
5108c2ecf20Sopenharmony_ci		0,
5118c2ecf20Sopenharmony_ci		0x3f,
5128c2ecf20Sopenharmony_ci		NTC_DO_PARITY_CHK | NTC_DO_DISCONNECT | NTC_DO_SYNC_NEGO |
5138c2ecf20Sopenharmony_ci			NTC_DO_WIDE_NEGO | NTC_DO_TAG_QUEUEING |
5148c2ecf20Sopenharmony_ci			NTC_DO_SEND_START,
5158c2ecf20Sopenharmony_ci		NTC_DO_PARITY_CHK | NTC_DO_SEND_START
5168c2ecf20Sopenharmony_ci	},
5178c2ecf20Sopenharmony_ci	{ /* adapter mode */
5188c2ecf20Sopenharmony_ci		CFG_PARAM_UNSET,
5198c2ecf20Sopenharmony_ci		0,
5208c2ecf20Sopenharmony_ci		0x2f,
5218c2ecf20Sopenharmony_ci		NAC_SCANLUN |
5228c2ecf20Sopenharmony_ci		NAC_GT2DRIVES | NAC_GREATER_1G | NAC_POWERON_SCSI_RESET
5238c2ecf20Sopenharmony_ci			/*| NAC_ACTIVE_NEG*/,
5248c2ecf20Sopenharmony_ci		NAC_GT2DRIVES | NAC_GREATER_1G | NAC_POWERON_SCSI_RESET | 0x08
5258c2ecf20Sopenharmony_ci	},
5268c2ecf20Sopenharmony_ci	{ /* tags */
5278c2ecf20Sopenharmony_ci		CFG_PARAM_UNSET,
5288c2ecf20Sopenharmony_ci		0,
5298c2ecf20Sopenharmony_ci		5,
5308c2ecf20Sopenharmony_ci		3,	/* 16 tags (??) */
5318c2ecf20Sopenharmony_ci		2,
5328c2ecf20Sopenharmony_ci	},
5338c2ecf20Sopenharmony_ci	{ /* reset delay */
5348c2ecf20Sopenharmony_ci		CFG_PARAM_UNSET,
5358c2ecf20Sopenharmony_ci		0,
5368c2ecf20Sopenharmony_ci		180,
5378c2ecf20Sopenharmony_ci		1,	/* 1 second */
5388c2ecf20Sopenharmony_ci		10,	/* 10 seconds */
5398c2ecf20Sopenharmony_ci	}
5408c2ecf20Sopenharmony_ci};
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci/*
5448c2ecf20Sopenharmony_ci * Safe settings. If set to zero the BIOS/default values with
5458c2ecf20Sopenharmony_ci * command line overrides will be used. If set to 1 then safe and
5468c2ecf20Sopenharmony_ci * slow settings will be used.
5478c2ecf20Sopenharmony_ci */
5488c2ecf20Sopenharmony_cistatic bool use_safe_settings = 0;
5498c2ecf20Sopenharmony_cimodule_param_named(safe, use_safe_settings, bool, 0);
5508c2ecf20Sopenharmony_ciMODULE_PARM_DESC(safe, "Use safe and slow settings only. Default: false");
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_cimodule_param_named(adapter_id, cfg_data[CFG_ADAPTER_ID].value, int, 0);
5548c2ecf20Sopenharmony_ciMODULE_PARM_DESC(adapter_id, "Adapter SCSI ID. Default 7 (0-15)");
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_cimodule_param_named(max_speed, cfg_data[CFG_MAX_SPEED].value, int, 0);
5578c2ecf20Sopenharmony_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");
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_cimodule_param_named(dev_mode, cfg_data[CFG_DEV_MODE].value, int, 0);
5608c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dev_mode, "Device mode.");
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_cimodule_param_named(adapter_mode, cfg_data[CFG_ADAPTER_MODE].value, int, 0);
5638c2ecf20Sopenharmony_ciMODULE_PARM_DESC(adapter_mode, "Adapter mode.");
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_cimodule_param_named(tags, cfg_data[CFG_TAGS].value, int, 0);
5668c2ecf20Sopenharmony_ciMODULE_PARM_DESC(tags, "Number of tags (1<<x). Default 3 (0-5)");
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_cimodule_param_named(reset_delay, cfg_data[CFG_RESET_DELAY].value, int, 0);
5698c2ecf20Sopenharmony_ciMODULE_PARM_DESC(reset_delay, "Reset delay in seconds. Default 1 (0-180)");
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci/**
5738c2ecf20Sopenharmony_ci * set_safe_settings - if the use_safe_settings option is set then
5748c2ecf20Sopenharmony_ci * set all values to the safe and slow values.
5758c2ecf20Sopenharmony_ci **/
5768c2ecf20Sopenharmony_cistatic void set_safe_settings(void)
5778c2ecf20Sopenharmony_ci{
5788c2ecf20Sopenharmony_ci	if (use_safe_settings)
5798c2ecf20Sopenharmony_ci	{
5808c2ecf20Sopenharmony_ci		int i;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci		dprintkl(KERN_INFO, "Using safe settings.\n");
5838c2ecf20Sopenharmony_ci		for (i = 0; i < CFG_NUM; i++)
5848c2ecf20Sopenharmony_ci		{
5858c2ecf20Sopenharmony_ci			cfg_data[i].value = cfg_data[i].safe;
5868c2ecf20Sopenharmony_ci		}
5878c2ecf20Sopenharmony_ci	}
5888c2ecf20Sopenharmony_ci}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci/**
5928c2ecf20Sopenharmony_ci * fix_settings - reset any boot parameters which are out of range
5938c2ecf20Sopenharmony_ci * back to the default values.
5948c2ecf20Sopenharmony_ci **/
5958c2ecf20Sopenharmony_cistatic void fix_settings(void)
5968c2ecf20Sopenharmony_ci{
5978c2ecf20Sopenharmony_ci	int i;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	dprintkdbg(DBG_1,
6008c2ecf20Sopenharmony_ci		"setup: AdapterId=%08x MaxSpeed=%08x DevMode=%08x "
6018c2ecf20Sopenharmony_ci		"AdapterMode=%08x Tags=%08x ResetDelay=%08x\n",
6028c2ecf20Sopenharmony_ci		cfg_data[CFG_ADAPTER_ID].value,
6038c2ecf20Sopenharmony_ci		cfg_data[CFG_MAX_SPEED].value,
6048c2ecf20Sopenharmony_ci		cfg_data[CFG_DEV_MODE].value,
6058c2ecf20Sopenharmony_ci		cfg_data[CFG_ADAPTER_MODE].value,
6068c2ecf20Sopenharmony_ci		cfg_data[CFG_TAGS].value,
6078c2ecf20Sopenharmony_ci		cfg_data[CFG_RESET_DELAY].value);
6088c2ecf20Sopenharmony_ci	for (i = 0; i < CFG_NUM; i++)
6098c2ecf20Sopenharmony_ci	{
6108c2ecf20Sopenharmony_ci		if (cfg_data[i].value < cfg_data[i].min
6118c2ecf20Sopenharmony_ci		    || cfg_data[i].value > cfg_data[i].max)
6128c2ecf20Sopenharmony_ci			cfg_data[i].value = cfg_data[i].def;
6138c2ecf20Sopenharmony_ci	}
6148c2ecf20Sopenharmony_ci}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci/*
6198c2ecf20Sopenharmony_ci * Mapping from the eeprom delay index value (index into this array)
6208c2ecf20Sopenharmony_ci * to the number of actual seconds that the delay should be for.
6218c2ecf20Sopenharmony_ci */
6228c2ecf20Sopenharmony_cistatic char eeprom_index_to_delay_map[] =
6238c2ecf20Sopenharmony_ci	{ 1, 3, 5, 10, 16, 30, 60, 120 };
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci/**
6278c2ecf20Sopenharmony_ci * eeprom_index_to_delay - Take the eeprom delay setting and convert it
6288c2ecf20Sopenharmony_ci * into a number of seconds.
6298c2ecf20Sopenharmony_ci *
6308c2ecf20Sopenharmony_ci * @eeprom: The eeprom structure in which we find the delay index to map.
6318c2ecf20Sopenharmony_ci **/
6328c2ecf20Sopenharmony_cistatic void eeprom_index_to_delay(struct NvRamType *eeprom)
6338c2ecf20Sopenharmony_ci{
6348c2ecf20Sopenharmony_ci	eeprom->delay_time = eeprom_index_to_delay_map[eeprom->delay_time];
6358c2ecf20Sopenharmony_ci}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci/**
6398c2ecf20Sopenharmony_ci * delay_to_eeprom_index - Take a delay in seconds and return the
6408c2ecf20Sopenharmony_ci * closest eeprom index which will delay for at least that amount of
6418c2ecf20Sopenharmony_ci * seconds.
6428c2ecf20Sopenharmony_ci *
6438c2ecf20Sopenharmony_ci * @delay: The delay, in seconds, to find the eeprom index for.
6448c2ecf20Sopenharmony_ci **/
6458c2ecf20Sopenharmony_cistatic int delay_to_eeprom_index(int delay)
6468c2ecf20Sopenharmony_ci{
6478c2ecf20Sopenharmony_ci	u8 idx = 0;
6488c2ecf20Sopenharmony_ci	while (idx < 7 && eeprom_index_to_delay_map[idx] < delay)
6498c2ecf20Sopenharmony_ci		idx++;
6508c2ecf20Sopenharmony_ci	return idx;
6518c2ecf20Sopenharmony_ci}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci/**
6558c2ecf20Sopenharmony_ci * eeprom_override - Override the eeprom settings, in the provided
6568c2ecf20Sopenharmony_ci * eeprom structure, with values that have been set on the command
6578c2ecf20Sopenharmony_ci * line.
6588c2ecf20Sopenharmony_ci *
6598c2ecf20Sopenharmony_ci * @eeprom: The eeprom data to override with command line options.
6608c2ecf20Sopenharmony_ci **/
6618c2ecf20Sopenharmony_cistatic void eeprom_override(struct NvRamType *eeprom)
6628c2ecf20Sopenharmony_ci{
6638c2ecf20Sopenharmony_ci	u8 id;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	/* Adapter Settings */
6668c2ecf20Sopenharmony_ci	if (cfg_data[CFG_ADAPTER_ID].value != CFG_PARAM_UNSET)
6678c2ecf20Sopenharmony_ci		eeprom->scsi_id = (u8)cfg_data[CFG_ADAPTER_ID].value;
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	if (cfg_data[CFG_ADAPTER_MODE].value != CFG_PARAM_UNSET)
6708c2ecf20Sopenharmony_ci		eeprom->channel_cfg = (u8)cfg_data[CFG_ADAPTER_MODE].value;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	if (cfg_data[CFG_RESET_DELAY].value != CFG_PARAM_UNSET)
6738c2ecf20Sopenharmony_ci		eeprom->delay_time = delay_to_eeprom_index(
6748c2ecf20Sopenharmony_ci					cfg_data[CFG_RESET_DELAY].value);
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	if (cfg_data[CFG_TAGS].value != CFG_PARAM_UNSET)
6778c2ecf20Sopenharmony_ci		eeprom->max_tag = (u8)cfg_data[CFG_TAGS].value;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	/* Device Settings */
6808c2ecf20Sopenharmony_ci	for (id = 0; id < DC395x_MAX_SCSI_ID; id++) {
6818c2ecf20Sopenharmony_ci		if (cfg_data[CFG_DEV_MODE].value != CFG_PARAM_UNSET)
6828c2ecf20Sopenharmony_ci			eeprom->target[id].cfg0 =
6838c2ecf20Sopenharmony_ci				(u8)cfg_data[CFG_DEV_MODE].value;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci		if (cfg_data[CFG_MAX_SPEED].value != CFG_PARAM_UNSET)
6868c2ecf20Sopenharmony_ci			eeprom->target[id].period =
6878c2ecf20Sopenharmony_ci				(u8)cfg_data[CFG_MAX_SPEED].value;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	}
6908c2ecf20Sopenharmony_ci}
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci/*---------------------------------------------------------------------------
6948c2ecf20Sopenharmony_ci ---------------------------------------------------------------------------*/
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_cistatic unsigned int list_size(struct list_head *head)
6978c2ecf20Sopenharmony_ci{
6988c2ecf20Sopenharmony_ci	unsigned int count = 0;
6998c2ecf20Sopenharmony_ci	struct list_head *pos;
7008c2ecf20Sopenharmony_ci	list_for_each(pos, head)
7018c2ecf20Sopenharmony_ci		count++;
7028c2ecf20Sopenharmony_ci	return count;
7038c2ecf20Sopenharmony_ci}
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_cistatic struct DeviceCtlBlk *dcb_get_next(struct list_head *head,
7078c2ecf20Sopenharmony_ci		struct DeviceCtlBlk *pos)
7088c2ecf20Sopenharmony_ci{
7098c2ecf20Sopenharmony_ci	int use_next = 0;
7108c2ecf20Sopenharmony_ci	struct DeviceCtlBlk* next = NULL;
7118c2ecf20Sopenharmony_ci	struct DeviceCtlBlk* i;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	if (list_empty(head))
7148c2ecf20Sopenharmony_ci		return NULL;
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci	/* find supplied dcb and then select the next one */
7178c2ecf20Sopenharmony_ci	list_for_each_entry(i, head, list)
7188c2ecf20Sopenharmony_ci		if (use_next) {
7198c2ecf20Sopenharmony_ci			next = i;
7208c2ecf20Sopenharmony_ci			break;
7218c2ecf20Sopenharmony_ci		} else if (i == pos) {
7228c2ecf20Sopenharmony_ci			use_next = 1;
7238c2ecf20Sopenharmony_ci		}
7248c2ecf20Sopenharmony_ci	/* if no next one take the head one (ie, wraparound) */
7258c2ecf20Sopenharmony_ci	if (!next)
7268c2ecf20Sopenharmony_ci        	list_for_each_entry(i, head, list) {
7278c2ecf20Sopenharmony_ci        		next = i;
7288c2ecf20Sopenharmony_ci        		break;
7298c2ecf20Sopenharmony_ci        	}
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	return next;
7328c2ecf20Sopenharmony_ci}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_cistatic void free_tag(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
7368c2ecf20Sopenharmony_ci{
7378c2ecf20Sopenharmony_ci	if (srb->tag_number < 255) {
7388c2ecf20Sopenharmony_ci		dcb->tag_mask &= ~(1 << srb->tag_number);	/* free tag mask */
7398c2ecf20Sopenharmony_ci		srb->tag_number = 255;
7408c2ecf20Sopenharmony_ci	}
7418c2ecf20Sopenharmony_ci}
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci/* Find cmd in SRB list */
7458c2ecf20Sopenharmony_cistatic inline struct ScsiReqBlk *find_cmd(struct scsi_cmnd *cmd,
7468c2ecf20Sopenharmony_ci		struct list_head *head)
7478c2ecf20Sopenharmony_ci{
7488c2ecf20Sopenharmony_ci	struct ScsiReqBlk *i;
7498c2ecf20Sopenharmony_ci	list_for_each_entry(i, head, list)
7508c2ecf20Sopenharmony_ci		if (i->cmd == cmd)
7518c2ecf20Sopenharmony_ci			return i;
7528c2ecf20Sopenharmony_ci	return NULL;
7538c2ecf20Sopenharmony_ci}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci/* Sets the timer to wake us up */
7568c2ecf20Sopenharmony_cistatic void waiting_set_timer(struct AdapterCtlBlk *acb, unsigned long to)
7578c2ecf20Sopenharmony_ci{
7588c2ecf20Sopenharmony_ci	if (timer_pending(&acb->waiting_timer))
7598c2ecf20Sopenharmony_ci		return;
7608c2ecf20Sopenharmony_ci	if (time_before(jiffies + to, acb->last_reset - HZ / 2))
7618c2ecf20Sopenharmony_ci		acb->waiting_timer.expires =
7628c2ecf20Sopenharmony_ci		    acb->last_reset - HZ / 2 + 1;
7638c2ecf20Sopenharmony_ci	else
7648c2ecf20Sopenharmony_ci		acb->waiting_timer.expires = jiffies + to + 1;
7658c2ecf20Sopenharmony_ci	add_timer(&acb->waiting_timer);
7668c2ecf20Sopenharmony_ci}
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci/* Send the next command from the waiting list to the bus */
7708c2ecf20Sopenharmony_cistatic void waiting_process_next(struct AdapterCtlBlk *acb)
7718c2ecf20Sopenharmony_ci{
7728c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *start = NULL;
7738c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *pos;
7748c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb;
7758c2ecf20Sopenharmony_ci	struct ScsiReqBlk *srb;
7768c2ecf20Sopenharmony_ci	struct list_head *dcb_list_head = &acb->dcb_list;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	if (acb->active_dcb
7798c2ecf20Sopenharmony_ci	    || (acb->acb_flag & (RESET_DETECT + RESET_DONE + RESET_DEV)))
7808c2ecf20Sopenharmony_ci		return;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	if (timer_pending(&acb->waiting_timer))
7838c2ecf20Sopenharmony_ci		del_timer(&acb->waiting_timer);
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	if (list_empty(dcb_list_head))
7868c2ecf20Sopenharmony_ci		return;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	/*
7898c2ecf20Sopenharmony_ci	 * Find the starting dcb. Need to find it again in the list
7908c2ecf20Sopenharmony_ci	 * since the list may have changed since we set the ptr to it
7918c2ecf20Sopenharmony_ci	 */
7928c2ecf20Sopenharmony_ci	list_for_each_entry(dcb, dcb_list_head, list)
7938c2ecf20Sopenharmony_ci		if (dcb == acb->dcb_run_robin) {
7948c2ecf20Sopenharmony_ci			start = dcb;
7958c2ecf20Sopenharmony_ci			break;
7968c2ecf20Sopenharmony_ci		}
7978c2ecf20Sopenharmony_ci	if (!start) {
7988c2ecf20Sopenharmony_ci		/* This can happen! */
7998c2ecf20Sopenharmony_ci		start = list_entry(dcb_list_head->next, typeof(*start), list);
8008c2ecf20Sopenharmony_ci		acb->dcb_run_robin = start;
8018c2ecf20Sopenharmony_ci	}
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	/*
8058c2ecf20Sopenharmony_ci	 * Loop over the dcb, but we start somewhere (potentially) in
8068c2ecf20Sopenharmony_ci	 * the middle of the loop so we need to manully do this.
8078c2ecf20Sopenharmony_ci	 */
8088c2ecf20Sopenharmony_ci	pos = start;
8098c2ecf20Sopenharmony_ci	do {
8108c2ecf20Sopenharmony_ci		struct list_head *waiting_list_head = &pos->srb_waiting_list;
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci		/* Make sure, the next another device gets scheduled ... */
8138c2ecf20Sopenharmony_ci		acb->dcb_run_robin = dcb_get_next(dcb_list_head,
8148c2ecf20Sopenharmony_ci						  acb->dcb_run_robin);
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci		if (list_empty(waiting_list_head) ||
8178c2ecf20Sopenharmony_ci		    pos->max_command <= list_size(&pos->srb_going_list)) {
8188c2ecf20Sopenharmony_ci			/* move to next dcb */
8198c2ecf20Sopenharmony_ci			pos = dcb_get_next(dcb_list_head, pos);
8208c2ecf20Sopenharmony_ci		} else {
8218c2ecf20Sopenharmony_ci			srb = list_entry(waiting_list_head->next,
8228c2ecf20Sopenharmony_ci					 struct ScsiReqBlk, list);
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci			/* Try to send to the bus */
8258c2ecf20Sopenharmony_ci			if (!start_scsi(acb, pos, srb))
8268c2ecf20Sopenharmony_ci				list_move(&srb->list, &pos->srb_going_list);
8278c2ecf20Sopenharmony_ci			else
8288c2ecf20Sopenharmony_ci				waiting_set_timer(acb, HZ/50);
8298c2ecf20Sopenharmony_ci			break;
8308c2ecf20Sopenharmony_ci		}
8318c2ecf20Sopenharmony_ci	} while (pos != start);
8328c2ecf20Sopenharmony_ci}
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci/* Wake up waiting queue */
8368c2ecf20Sopenharmony_cistatic void waiting_timeout(struct timer_list *t)
8378c2ecf20Sopenharmony_ci{
8388c2ecf20Sopenharmony_ci	unsigned long flags;
8398c2ecf20Sopenharmony_ci	struct AdapterCtlBlk *acb = from_timer(acb, t, waiting_timer);
8408c2ecf20Sopenharmony_ci	dprintkdbg(DBG_1,
8418c2ecf20Sopenharmony_ci		"waiting_timeout: Queue woken up by timer. acb=%p\n", acb);
8428c2ecf20Sopenharmony_ci	DC395x_LOCK_IO(acb->scsi_host, flags);
8438c2ecf20Sopenharmony_ci	waiting_process_next(acb);
8448c2ecf20Sopenharmony_ci	DC395x_UNLOCK_IO(acb->scsi_host, flags);
8458c2ecf20Sopenharmony_ci}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci/* Get the DCB for a given ID/LUN combination */
8498c2ecf20Sopenharmony_cistatic struct DeviceCtlBlk *find_dcb(struct AdapterCtlBlk *acb, u8 id, u8 lun)
8508c2ecf20Sopenharmony_ci{
8518c2ecf20Sopenharmony_ci	return acb->children[id][lun];
8528c2ecf20Sopenharmony_ci}
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci/* Send SCSI Request Block (srb) to adapter (acb) */
8568c2ecf20Sopenharmony_cistatic void send_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
8578c2ecf20Sopenharmony_ci{
8588c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb = srb->dcb;
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	if (dcb->max_command <= list_size(&dcb->srb_going_list) ||
8618c2ecf20Sopenharmony_ci	    acb->active_dcb ||
8628c2ecf20Sopenharmony_ci	    (acb->acb_flag & (RESET_DETECT + RESET_DONE + RESET_DEV))) {
8638c2ecf20Sopenharmony_ci		list_add_tail(&srb->list, &dcb->srb_waiting_list);
8648c2ecf20Sopenharmony_ci		waiting_process_next(acb);
8658c2ecf20Sopenharmony_ci		return;
8668c2ecf20Sopenharmony_ci	}
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	if (!start_scsi(acb, dcb, srb)) {
8698c2ecf20Sopenharmony_ci		list_add_tail(&srb->list, &dcb->srb_going_list);
8708c2ecf20Sopenharmony_ci	} else {
8718c2ecf20Sopenharmony_ci		list_add(&srb->list, &dcb->srb_waiting_list);
8728c2ecf20Sopenharmony_ci		waiting_set_timer(acb, HZ / 50);
8738c2ecf20Sopenharmony_ci	}
8748c2ecf20Sopenharmony_ci}
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci/* Prepare SRB for being sent to Device DCB w/ command *cmd */
8778c2ecf20Sopenharmony_cistatic void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
8788c2ecf20Sopenharmony_ci		struct ScsiReqBlk *srb)
8798c2ecf20Sopenharmony_ci{
8808c2ecf20Sopenharmony_ci	int nseg;
8818c2ecf20Sopenharmony_ci	enum dma_data_direction dir = cmd->sc_data_direction;
8828c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "build_srb: (0x%p) <%02i-%i>\n",
8838c2ecf20Sopenharmony_ci		cmd, dcb->target_id, dcb->target_lun);
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	srb->dcb = dcb;
8868c2ecf20Sopenharmony_ci	srb->cmd = cmd;
8878c2ecf20Sopenharmony_ci	srb->sg_count = 0;
8888c2ecf20Sopenharmony_ci	srb->total_xfer_length = 0;
8898c2ecf20Sopenharmony_ci	srb->sg_bus_addr = 0;
8908c2ecf20Sopenharmony_ci	srb->sg_index = 0;
8918c2ecf20Sopenharmony_ci	srb->adapter_status = 0;
8928c2ecf20Sopenharmony_ci	srb->target_status = 0;
8938c2ecf20Sopenharmony_ci	srb->msg_count = 0;
8948c2ecf20Sopenharmony_ci	srb->status = 0;
8958c2ecf20Sopenharmony_ci	srb->flag = 0;
8968c2ecf20Sopenharmony_ci	srb->state = 0;
8978c2ecf20Sopenharmony_ci	srb->retry_count = 0;
8988c2ecf20Sopenharmony_ci	srb->tag_number = TAG_NONE;
8998c2ecf20Sopenharmony_ci	srb->scsi_phase = PH_BUS_FREE;	/* initial phase */
9008c2ecf20Sopenharmony_ci	srb->end_message = 0;
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	nseg = scsi_dma_map(cmd);
9038c2ecf20Sopenharmony_ci	BUG_ON(nseg < 0);
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	if (dir == DMA_NONE || !nseg) {
9068c2ecf20Sopenharmony_ci		dprintkdbg(DBG_0,
9078c2ecf20Sopenharmony_ci			"build_srb: [0] len=%d buf=%p use_sg=%d !MAP=%08x\n",
9088c2ecf20Sopenharmony_ci			   cmd->bufflen, scsi_sglist(cmd), scsi_sg_count(cmd),
9098c2ecf20Sopenharmony_ci			   srb->segment_x[0].address);
9108c2ecf20Sopenharmony_ci	} else {
9118c2ecf20Sopenharmony_ci		int i;
9128c2ecf20Sopenharmony_ci		u32 reqlen = scsi_bufflen(cmd);
9138c2ecf20Sopenharmony_ci		struct scatterlist *sg;
9148c2ecf20Sopenharmony_ci		struct SGentry *sgp = srb->segment_x;
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci		srb->sg_count = nseg;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci		dprintkdbg(DBG_0,
9198c2ecf20Sopenharmony_ci			   "build_srb: [n] len=%d buf=%p use_sg=%d segs=%d\n",
9208c2ecf20Sopenharmony_ci			   reqlen, scsi_sglist(cmd), scsi_sg_count(cmd),
9218c2ecf20Sopenharmony_ci			   srb->sg_count);
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci		scsi_for_each_sg(cmd, sg, srb->sg_count, i) {
9248c2ecf20Sopenharmony_ci			u32 busaddr = (u32)sg_dma_address(sg);
9258c2ecf20Sopenharmony_ci			u32 seglen = (u32)sg->length;
9268c2ecf20Sopenharmony_ci			sgp[i].address = busaddr;
9278c2ecf20Sopenharmony_ci			sgp[i].length = seglen;
9288c2ecf20Sopenharmony_ci			srb->total_xfer_length += seglen;
9298c2ecf20Sopenharmony_ci		}
9308c2ecf20Sopenharmony_ci		sgp += srb->sg_count - 1;
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci		/*
9338c2ecf20Sopenharmony_ci		 * adjust last page if too big as it is allocated
9348c2ecf20Sopenharmony_ci		 * on even page boundaries
9358c2ecf20Sopenharmony_ci		 */
9368c2ecf20Sopenharmony_ci		if (srb->total_xfer_length > reqlen) {
9378c2ecf20Sopenharmony_ci			sgp->length -= (srb->total_xfer_length - reqlen);
9388c2ecf20Sopenharmony_ci			srb->total_xfer_length = reqlen;
9398c2ecf20Sopenharmony_ci		}
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci		/* Fixup for WIDE padding - make sure length is even */
9428c2ecf20Sopenharmony_ci		if (dcb->sync_period & WIDE_SYNC &&
9438c2ecf20Sopenharmony_ci		    srb->total_xfer_length % 2) {
9448c2ecf20Sopenharmony_ci			srb->total_xfer_length++;
9458c2ecf20Sopenharmony_ci			sgp->length++;
9468c2ecf20Sopenharmony_ci		}
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci		srb->sg_bus_addr = dma_map_single(&dcb->acb->dev->dev,
9498c2ecf20Sopenharmony_ci				srb->segment_x, SEGMENTX_LEN, DMA_TO_DEVICE);
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci		dprintkdbg(DBG_SG, "build_srb: [n] map sg %p->%08x(%05x)\n",
9528c2ecf20Sopenharmony_ci			srb->segment_x, srb->sg_bus_addr, SEGMENTX_LEN);
9538c2ecf20Sopenharmony_ci	}
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	srb->request_length = srb->total_xfer_length;
9568c2ecf20Sopenharmony_ci}
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci/**
9608c2ecf20Sopenharmony_ci * dc395x_queue_command - queue scsi command passed from the mid
9618c2ecf20Sopenharmony_ci * layer, invoke 'done' on completion
9628c2ecf20Sopenharmony_ci *
9638c2ecf20Sopenharmony_ci * @cmd: pointer to scsi command object
9648c2ecf20Sopenharmony_ci * @done: function pointer to be invoked on completion
9658c2ecf20Sopenharmony_ci *
9668c2ecf20Sopenharmony_ci * Returns 1 if the adapter (host) is busy, else returns 0. One
9678c2ecf20Sopenharmony_ci * reason for an adapter to be busy is that the number
9688c2ecf20Sopenharmony_ci * of outstanding queued commands is already equal to
9698c2ecf20Sopenharmony_ci * struct Scsi_Host::can_queue .
9708c2ecf20Sopenharmony_ci *
9718c2ecf20Sopenharmony_ci * Required: if struct Scsi_Host::can_queue is ever non-zero
9728c2ecf20Sopenharmony_ci *           then this function is required.
9738c2ecf20Sopenharmony_ci *
9748c2ecf20Sopenharmony_ci * Locks: struct Scsi_Host::host_lock held on entry (with "irqsave")
9758c2ecf20Sopenharmony_ci *        and is expected to be held on return.
9768c2ecf20Sopenharmony_ci *
9778c2ecf20Sopenharmony_ci **/
9788c2ecf20Sopenharmony_cistatic int dc395x_queue_command_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
9798c2ecf20Sopenharmony_ci{
9808c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb;
9818c2ecf20Sopenharmony_ci	struct ScsiReqBlk *srb;
9828c2ecf20Sopenharmony_ci	struct AdapterCtlBlk *acb =
9838c2ecf20Sopenharmony_ci	    (struct AdapterCtlBlk *)cmd->device->host->hostdata;
9848c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "queue_command: (0x%p) <%02i-%i> cmnd=0x%02x\n",
9858c2ecf20Sopenharmony_ci		cmd, cmd->device->id, (u8)cmd->device->lun, cmd->cmnd[0]);
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	/* Assume BAD_TARGET; will be cleared later */
9888c2ecf20Sopenharmony_ci	cmd->result = DID_BAD_TARGET << 16;
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	/* ignore invalid targets */
9918c2ecf20Sopenharmony_ci	if (cmd->device->id >= acb->scsi_host->max_id ||
9928c2ecf20Sopenharmony_ci	    cmd->device->lun >= acb->scsi_host->max_lun ||
9938c2ecf20Sopenharmony_ci	    cmd->device->lun >31) {
9948c2ecf20Sopenharmony_ci		goto complete;
9958c2ecf20Sopenharmony_ci	}
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	/* does the specified lun on the specified device exist */
9988c2ecf20Sopenharmony_ci	if (!(acb->dcb_map[cmd->device->id] & (1 << cmd->device->lun))) {
9998c2ecf20Sopenharmony_ci		dprintkl(KERN_INFO, "queue_command: Ignore target <%02i-%i>\n",
10008c2ecf20Sopenharmony_ci			cmd->device->id, (u8)cmd->device->lun);
10018c2ecf20Sopenharmony_ci		goto complete;
10028c2ecf20Sopenharmony_ci	}
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	/* do we have a DCB for the device */
10058c2ecf20Sopenharmony_ci	dcb = find_dcb(acb, cmd->device->id, cmd->device->lun);
10068c2ecf20Sopenharmony_ci	if (!dcb) {
10078c2ecf20Sopenharmony_ci		/* should never happen */
10088c2ecf20Sopenharmony_ci		dprintkl(KERN_ERR, "queue_command: No such device <%02i-%i>",
10098c2ecf20Sopenharmony_ci			cmd->device->id, (u8)cmd->device->lun);
10108c2ecf20Sopenharmony_ci		goto complete;
10118c2ecf20Sopenharmony_ci	}
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	/* set callback and clear result in the command */
10148c2ecf20Sopenharmony_ci	cmd->scsi_done = done;
10158c2ecf20Sopenharmony_ci	cmd->result = 0;
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	srb = list_first_entry_or_null(&acb->srb_free_list,
10188c2ecf20Sopenharmony_ci			struct ScsiReqBlk, list);
10198c2ecf20Sopenharmony_ci	if (!srb) {
10208c2ecf20Sopenharmony_ci		/*
10218c2ecf20Sopenharmony_ci		 * Return 1 since we are unable to queue this command at this
10228c2ecf20Sopenharmony_ci		 * point in time.
10238c2ecf20Sopenharmony_ci		 */
10248c2ecf20Sopenharmony_ci		dprintkdbg(DBG_0, "queue_command: No free srb's\n");
10258c2ecf20Sopenharmony_ci		return 1;
10268c2ecf20Sopenharmony_ci	}
10278c2ecf20Sopenharmony_ci	list_del(&srb->list);
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	build_srb(cmd, dcb, srb);
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci	if (!list_empty(&dcb->srb_waiting_list)) {
10328c2ecf20Sopenharmony_ci		/* append to waiting queue */
10338c2ecf20Sopenharmony_ci		list_add_tail(&srb->list, &dcb->srb_waiting_list);
10348c2ecf20Sopenharmony_ci		waiting_process_next(acb);
10358c2ecf20Sopenharmony_ci	} else {
10368c2ecf20Sopenharmony_ci		/* process immediately */
10378c2ecf20Sopenharmony_ci		send_srb(acb, srb);
10388c2ecf20Sopenharmony_ci	}
10398c2ecf20Sopenharmony_ci	dprintkdbg(DBG_1, "queue_command: (0x%p) done\n", cmd);
10408c2ecf20Sopenharmony_ci	return 0;
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_cicomplete:
10438c2ecf20Sopenharmony_ci	/*
10448c2ecf20Sopenharmony_ci	 * Complete the command immediatey, and then return 0 to
10458c2ecf20Sopenharmony_ci	 * indicate that we have handled the command. This is usually
10468c2ecf20Sopenharmony_ci	 * done when the commad is for things like non existent
10478c2ecf20Sopenharmony_ci	 * devices.
10488c2ecf20Sopenharmony_ci	 */
10498c2ecf20Sopenharmony_ci	done(cmd);
10508c2ecf20Sopenharmony_ci	return 0;
10518c2ecf20Sopenharmony_ci}
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_cistatic DEF_SCSI_QCMD(dc395x_queue_command)
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_cistatic void dump_register_info(struct AdapterCtlBlk *acb,
10568c2ecf20Sopenharmony_ci		struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
10578c2ecf20Sopenharmony_ci{
10588c2ecf20Sopenharmony_ci	u16 pstat;
10598c2ecf20Sopenharmony_ci	struct pci_dev *dev = acb->dev;
10608c2ecf20Sopenharmony_ci	pci_read_config_word(dev, PCI_STATUS, &pstat);
10618c2ecf20Sopenharmony_ci	if (!dcb)
10628c2ecf20Sopenharmony_ci		dcb = acb->active_dcb;
10638c2ecf20Sopenharmony_ci	if (!srb && dcb)
10648c2ecf20Sopenharmony_ci		srb = dcb->active_srb;
10658c2ecf20Sopenharmony_ci	if (srb) {
10668c2ecf20Sopenharmony_ci		if (!srb->cmd)
10678c2ecf20Sopenharmony_ci			dprintkl(KERN_INFO, "dump: srb=%p cmd=%p OOOPS!\n",
10688c2ecf20Sopenharmony_ci				srb, srb->cmd);
10698c2ecf20Sopenharmony_ci		else
10708c2ecf20Sopenharmony_ci			dprintkl(KERN_INFO, "dump: srb=%p cmd=%p "
10718c2ecf20Sopenharmony_ci				 "cmnd=0x%02x <%02i-%i>\n",
10728c2ecf20Sopenharmony_ci				srb, srb->cmd,
10738c2ecf20Sopenharmony_ci				srb->cmd->cmnd[0], srb->cmd->device->id,
10748c2ecf20Sopenharmony_ci				(u8)srb->cmd->device->lun);
10758c2ecf20Sopenharmony_ci		printk("  sglist=%p cnt=%i idx=%i len=%zu\n",
10768c2ecf20Sopenharmony_ci		       srb->segment_x, srb->sg_count, srb->sg_index,
10778c2ecf20Sopenharmony_ci		       srb->total_xfer_length);
10788c2ecf20Sopenharmony_ci		printk("  state=0x%04x status=0x%02x phase=0x%02x (%sconn.)\n",
10798c2ecf20Sopenharmony_ci		       srb->state, srb->status, srb->scsi_phase,
10808c2ecf20Sopenharmony_ci		       (acb->active_dcb) ? "" : "not");
10818c2ecf20Sopenharmony_ci	}
10828c2ecf20Sopenharmony_ci	dprintkl(KERN_INFO, "dump: SCSI{status=0x%04x fifocnt=0x%02x "
10838c2ecf20Sopenharmony_ci		"signals=0x%02x irqstat=0x%02x sync=0x%02x target=0x%02x "
10848c2ecf20Sopenharmony_ci		"rselid=0x%02x ctr=0x%08x irqen=0x%02x config=0x%04x "
10858c2ecf20Sopenharmony_ci		"config2=0x%02x cmd=0x%02x selto=0x%02x}\n",
10868c2ecf20Sopenharmony_ci		DC395x_read16(acb, TRM_S1040_SCSI_STATUS),
10878c2ecf20Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
10888c2ecf20Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL),
10898c2ecf20Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS),
10908c2ecf20Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_SYNC),
10918c2ecf20Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_TARGETID),
10928c2ecf20Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_IDMSG),
10938c2ecf20Sopenharmony_ci		DC395x_read32(acb, TRM_S1040_SCSI_COUNTER),
10948c2ecf20Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_INTEN),
10958c2ecf20Sopenharmony_ci		DC395x_read16(acb, TRM_S1040_SCSI_CONFIG0),
10968c2ecf20Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_CONFIG2),
10978c2ecf20Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_COMMAND),
10988c2ecf20Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_TIMEOUT));
10998c2ecf20Sopenharmony_ci	dprintkl(KERN_INFO, "dump: DMA{cmd=0x%04x fifocnt=0x%02x fstat=0x%02x "
11008c2ecf20Sopenharmony_ci		"irqstat=0x%02x irqen=0x%02x cfg=0x%04x tctr=0x%08x "
11018c2ecf20Sopenharmony_ci		"ctctr=0x%08x addr=0x%08x:0x%08x}\n",
11028c2ecf20Sopenharmony_ci		DC395x_read16(acb, TRM_S1040_DMA_COMMAND),
11038c2ecf20Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
11048c2ecf20Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
11058c2ecf20Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_DMA_STATUS),
11068c2ecf20Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_DMA_INTEN),
11078c2ecf20Sopenharmony_ci		DC395x_read16(acb, TRM_S1040_DMA_CONFIG),
11088c2ecf20Sopenharmony_ci		DC395x_read32(acb, TRM_S1040_DMA_XCNT),
11098c2ecf20Sopenharmony_ci		DC395x_read32(acb, TRM_S1040_DMA_CXCNT),
11108c2ecf20Sopenharmony_ci		DC395x_read32(acb, TRM_S1040_DMA_XHIGHADDR),
11118c2ecf20Sopenharmony_ci		DC395x_read32(acb, TRM_S1040_DMA_XLOWADDR));
11128c2ecf20Sopenharmony_ci	dprintkl(KERN_INFO, "dump: gen{gctrl=0x%02x gstat=0x%02x gtmr=0x%02x} "
11138c2ecf20Sopenharmony_ci		"pci{status=0x%04x}\n",
11148c2ecf20Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_GEN_CONTROL),
11158c2ecf20Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_GEN_STATUS),
11168c2ecf20Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_GEN_TIMER),
11178c2ecf20Sopenharmony_ci		pstat);
11188c2ecf20Sopenharmony_ci}
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_cistatic inline void clear_fifo(struct AdapterCtlBlk *acb, char *txt)
11228c2ecf20Sopenharmony_ci{
11238c2ecf20Sopenharmony_ci#if debug_enabled(DBG_FIFO)
11248c2ecf20Sopenharmony_ci	u8 lines = DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL);
11258c2ecf20Sopenharmony_ci	u8 fifocnt = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT);
11268c2ecf20Sopenharmony_ci	if (!(fifocnt & 0x40))
11278c2ecf20Sopenharmony_ci		dprintkdbg(DBG_FIFO,
11288c2ecf20Sopenharmony_ci			"clear_fifo: (%i bytes) on phase %02x in %s\n",
11298c2ecf20Sopenharmony_ci			fifocnt & 0x3f, lines, txt);
11308c2ecf20Sopenharmony_ci#endif
11318c2ecf20Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRFIFO);
11328c2ecf20Sopenharmony_ci}
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_cistatic void reset_dev_param(struct AdapterCtlBlk *acb)
11368c2ecf20Sopenharmony_ci{
11378c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb;
11388c2ecf20Sopenharmony_ci	struct NvRamType *eeprom = &acb->eeprom;
11398c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "reset_dev_param: acb=%p\n", acb);
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci	list_for_each_entry(dcb, &acb->dcb_list, list) {
11428c2ecf20Sopenharmony_ci		u8 period_index;
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci		dcb->sync_mode &= ~(SYNC_NEGO_DONE + WIDE_NEGO_DONE);
11458c2ecf20Sopenharmony_ci		dcb->sync_period = 0;
11468c2ecf20Sopenharmony_ci		dcb->sync_offset = 0;
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci		dcb->dev_mode = eeprom->target[dcb->target_id].cfg0;
11498c2ecf20Sopenharmony_ci		period_index = eeprom->target[dcb->target_id].period & 0x07;
11508c2ecf20Sopenharmony_ci		dcb->min_nego_period = clock_period[period_index];
11518c2ecf20Sopenharmony_ci		if (!(dcb->dev_mode & NTC_DO_WIDE_NEGO)
11528c2ecf20Sopenharmony_ci		    || !(acb->config & HCC_WIDE_CARD))
11538c2ecf20Sopenharmony_ci			dcb->sync_mode &= ~WIDE_NEGO_ENABLE;
11548c2ecf20Sopenharmony_ci	}
11558c2ecf20Sopenharmony_ci}
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci/*
11598c2ecf20Sopenharmony_ci * perform a hard reset on the SCSI bus
11608c2ecf20Sopenharmony_ci * @cmd - some command for this host (for fetching hooks)
11618c2ecf20Sopenharmony_ci * Returns: SUCCESS (0x2002) on success, else FAILED (0x2003).
11628c2ecf20Sopenharmony_ci */
11638c2ecf20Sopenharmony_cistatic int __dc395x_eh_bus_reset(struct scsi_cmnd *cmd)
11648c2ecf20Sopenharmony_ci{
11658c2ecf20Sopenharmony_ci	struct AdapterCtlBlk *acb =
11668c2ecf20Sopenharmony_ci		(struct AdapterCtlBlk *)cmd->device->host->hostdata;
11678c2ecf20Sopenharmony_ci	dprintkl(KERN_INFO,
11688c2ecf20Sopenharmony_ci		"eh_bus_reset: (0%p) target=<%02i-%i> cmd=%p\n",
11698c2ecf20Sopenharmony_ci		cmd, cmd->device->id, (u8)cmd->device->lun, cmd);
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	if (timer_pending(&acb->waiting_timer))
11728c2ecf20Sopenharmony_ci		del_timer(&acb->waiting_timer);
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci	/*
11758c2ecf20Sopenharmony_ci	 * disable interrupt
11768c2ecf20Sopenharmony_ci	 */
11778c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_DMA_INTEN, 0x00);
11788c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_INTEN, 0x00);
11798c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_CONTROL, DO_RSTMODULE);
11808c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_DMA_CONTROL, DMARESETMODULE);
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	reset_scsi_bus(acb);
11838c2ecf20Sopenharmony_ci	udelay(500);
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	/* We may be in serious trouble. Wait some seconds */
11868c2ecf20Sopenharmony_ci	acb->last_reset =
11878c2ecf20Sopenharmony_ci	    jiffies + 3 * HZ / 2 +
11888c2ecf20Sopenharmony_ci	    HZ * acb->eeprom.delay_time;
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	/*
11918c2ecf20Sopenharmony_ci	 * re-enable interrupt
11928c2ecf20Sopenharmony_ci	 */
11938c2ecf20Sopenharmony_ci	/* Clear SCSI FIFO          */
11948c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO);
11958c2ecf20Sopenharmony_ci	clear_fifo(acb, "eh_bus_reset");
11968c2ecf20Sopenharmony_ci	/* Delete pending IRQ */
11978c2ecf20Sopenharmony_ci	DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS);
11988c2ecf20Sopenharmony_ci	set_basic_config(acb);
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	reset_dev_param(acb);
12018c2ecf20Sopenharmony_ci	doing_srb_done(acb, DID_RESET, cmd, 0);
12028c2ecf20Sopenharmony_ci	acb->active_dcb = NULL;
12038c2ecf20Sopenharmony_ci	acb->acb_flag = 0;	/* RESET_DETECT, RESET_DONE ,RESET_DEV */
12048c2ecf20Sopenharmony_ci	waiting_process_next(acb);
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	return SUCCESS;
12078c2ecf20Sopenharmony_ci}
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_cistatic int dc395x_eh_bus_reset(struct scsi_cmnd *cmd)
12108c2ecf20Sopenharmony_ci{
12118c2ecf20Sopenharmony_ci	int rc;
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	spin_lock_irq(cmd->device->host->host_lock);
12148c2ecf20Sopenharmony_ci	rc = __dc395x_eh_bus_reset(cmd);
12158c2ecf20Sopenharmony_ci	spin_unlock_irq(cmd->device->host->host_lock);
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci	return rc;
12188c2ecf20Sopenharmony_ci}
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_ci/*
12218c2ecf20Sopenharmony_ci * abort an errant SCSI command
12228c2ecf20Sopenharmony_ci * @cmd - command to be aborted
12238c2ecf20Sopenharmony_ci * Returns: SUCCESS (0x2002) on success, else FAILED (0x2003).
12248c2ecf20Sopenharmony_ci */
12258c2ecf20Sopenharmony_cistatic int dc395x_eh_abort(struct scsi_cmnd *cmd)
12268c2ecf20Sopenharmony_ci{
12278c2ecf20Sopenharmony_ci	/*
12288c2ecf20Sopenharmony_ci	 * Look into our command queues: If it has not been sent already,
12298c2ecf20Sopenharmony_ci	 * we remove it and return success. Otherwise fail.
12308c2ecf20Sopenharmony_ci	 */
12318c2ecf20Sopenharmony_ci	struct AdapterCtlBlk *acb =
12328c2ecf20Sopenharmony_ci	    (struct AdapterCtlBlk *)cmd->device->host->hostdata;
12338c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb;
12348c2ecf20Sopenharmony_ci	struct ScsiReqBlk *srb;
12358c2ecf20Sopenharmony_ci	dprintkl(KERN_INFO, "eh_abort: (0x%p) target=<%02i-%i> cmd=%p\n",
12368c2ecf20Sopenharmony_ci		cmd, cmd->device->id, (u8)cmd->device->lun, cmd);
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci	dcb = find_dcb(acb, cmd->device->id, cmd->device->lun);
12398c2ecf20Sopenharmony_ci	if (!dcb) {
12408c2ecf20Sopenharmony_ci		dprintkl(KERN_DEBUG, "eh_abort: No such device\n");
12418c2ecf20Sopenharmony_ci		return FAILED;
12428c2ecf20Sopenharmony_ci	}
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci	srb = find_cmd(cmd, &dcb->srb_waiting_list);
12458c2ecf20Sopenharmony_ci	if (srb) {
12468c2ecf20Sopenharmony_ci		list_del(&srb->list);
12478c2ecf20Sopenharmony_ci		pci_unmap_srb_sense(acb, srb);
12488c2ecf20Sopenharmony_ci		pci_unmap_srb(acb, srb);
12498c2ecf20Sopenharmony_ci		free_tag(dcb, srb);
12508c2ecf20Sopenharmony_ci		list_add_tail(&srb->list, &acb->srb_free_list);
12518c2ecf20Sopenharmony_ci		dprintkl(KERN_DEBUG, "eh_abort: Command was waiting\n");
12528c2ecf20Sopenharmony_ci		cmd->result = DID_ABORT << 16;
12538c2ecf20Sopenharmony_ci		return SUCCESS;
12548c2ecf20Sopenharmony_ci	}
12558c2ecf20Sopenharmony_ci	srb = find_cmd(cmd, &dcb->srb_going_list);
12568c2ecf20Sopenharmony_ci	if (srb) {
12578c2ecf20Sopenharmony_ci		dprintkl(KERN_DEBUG, "eh_abort: Command in progress\n");
12588c2ecf20Sopenharmony_ci		/* XXX: Should abort the command here */
12598c2ecf20Sopenharmony_ci	} else {
12608c2ecf20Sopenharmony_ci		dprintkl(KERN_DEBUG, "eh_abort: Command not found\n");
12618c2ecf20Sopenharmony_ci	}
12628c2ecf20Sopenharmony_ci	return FAILED;
12638c2ecf20Sopenharmony_ci}
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci/* SDTR */
12678c2ecf20Sopenharmony_cistatic void build_sdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
12688c2ecf20Sopenharmony_ci		struct ScsiReqBlk *srb)
12698c2ecf20Sopenharmony_ci{
12708c2ecf20Sopenharmony_ci	u8 *ptr = srb->msgout_buf + srb->msg_count;
12718c2ecf20Sopenharmony_ci	if (srb->msg_count > 1) {
12728c2ecf20Sopenharmony_ci		dprintkl(KERN_INFO,
12738c2ecf20Sopenharmony_ci			"build_sdtr: msgout_buf BUSY (%i: %02x %02x)\n",
12748c2ecf20Sopenharmony_ci			srb->msg_count, srb->msgout_buf[0],
12758c2ecf20Sopenharmony_ci			srb->msgout_buf[1]);
12768c2ecf20Sopenharmony_ci		return;
12778c2ecf20Sopenharmony_ci	}
12788c2ecf20Sopenharmony_ci	if (!(dcb->dev_mode & NTC_DO_SYNC_NEGO)) {
12798c2ecf20Sopenharmony_ci		dcb->sync_offset = 0;
12808c2ecf20Sopenharmony_ci		dcb->min_nego_period = 200 >> 2;
12818c2ecf20Sopenharmony_ci	} else if (dcb->sync_offset == 0)
12828c2ecf20Sopenharmony_ci		dcb->sync_offset = SYNC_NEGO_OFFSET;
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	*ptr++ = MSG_EXTENDED;	/* (01h) */
12858c2ecf20Sopenharmony_ci	*ptr++ = 3;		/* length */
12868c2ecf20Sopenharmony_ci	*ptr++ = EXTENDED_SDTR;	/* (01h) */
12878c2ecf20Sopenharmony_ci	*ptr++ = dcb->min_nego_period;	/* Transfer period (in 4ns) */
12888c2ecf20Sopenharmony_ci	*ptr++ = dcb->sync_offset;	/* Transfer period (max. REQ/ACK dist) */
12898c2ecf20Sopenharmony_ci	srb->msg_count += 5;
12908c2ecf20Sopenharmony_ci	srb->state |= SRB_DO_SYNC_NEGO;
12918c2ecf20Sopenharmony_ci}
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci/* WDTR */
12958c2ecf20Sopenharmony_cistatic void build_wdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
12968c2ecf20Sopenharmony_ci		struct ScsiReqBlk *srb)
12978c2ecf20Sopenharmony_ci{
12988c2ecf20Sopenharmony_ci	u8 wide = ((dcb->dev_mode & NTC_DO_WIDE_NEGO) &
12998c2ecf20Sopenharmony_ci		   (acb->config & HCC_WIDE_CARD)) ? 1 : 0;
13008c2ecf20Sopenharmony_ci	u8 *ptr = srb->msgout_buf + srb->msg_count;
13018c2ecf20Sopenharmony_ci	if (srb->msg_count > 1) {
13028c2ecf20Sopenharmony_ci		dprintkl(KERN_INFO,
13038c2ecf20Sopenharmony_ci			"build_wdtr: msgout_buf BUSY (%i: %02x %02x)\n",
13048c2ecf20Sopenharmony_ci			srb->msg_count, srb->msgout_buf[0],
13058c2ecf20Sopenharmony_ci			srb->msgout_buf[1]);
13068c2ecf20Sopenharmony_ci		return;
13078c2ecf20Sopenharmony_ci	}
13088c2ecf20Sopenharmony_ci	*ptr++ = MSG_EXTENDED;	/* (01h) */
13098c2ecf20Sopenharmony_ci	*ptr++ = 2;		/* length */
13108c2ecf20Sopenharmony_ci	*ptr++ = EXTENDED_WDTR;	/* (03h) */
13118c2ecf20Sopenharmony_ci	*ptr++ = wide;
13128c2ecf20Sopenharmony_ci	srb->msg_count += 4;
13138c2ecf20Sopenharmony_ci	srb->state |= SRB_DO_WIDE_NEGO;
13148c2ecf20Sopenharmony_ci}
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci#if 0
13188c2ecf20Sopenharmony_ci/* Timer to work around chip flaw: When selecting and the bus is
13198c2ecf20Sopenharmony_ci * busy, we sometimes miss a Selection timeout IRQ */
13208c2ecf20Sopenharmony_civoid selection_timeout_missed(unsigned long ptr);
13218c2ecf20Sopenharmony_ci/* Sets the timer to wake us up */
13228c2ecf20Sopenharmony_cistatic void selto_timer(struct AdapterCtlBlk *acb)
13238c2ecf20Sopenharmony_ci{
13248c2ecf20Sopenharmony_ci	if (timer_pending(&acb->selto_timer))
13258c2ecf20Sopenharmony_ci		return;
13268c2ecf20Sopenharmony_ci	acb->selto_timer.function = selection_timeout_missed;
13278c2ecf20Sopenharmony_ci	acb->selto_timer.data = (unsigned long) acb;
13288c2ecf20Sopenharmony_ci	if (time_before
13298c2ecf20Sopenharmony_ci	    (jiffies + HZ, acb->last_reset + HZ / 2))
13308c2ecf20Sopenharmony_ci		acb->selto_timer.expires =
13318c2ecf20Sopenharmony_ci		    acb->last_reset + HZ / 2 + 1;
13328c2ecf20Sopenharmony_ci	else
13338c2ecf20Sopenharmony_ci		acb->selto_timer.expires = jiffies + HZ + 1;
13348c2ecf20Sopenharmony_ci	add_timer(&acb->selto_timer);
13358c2ecf20Sopenharmony_ci}
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_civoid selection_timeout_missed(unsigned long ptr)
13398c2ecf20Sopenharmony_ci{
13408c2ecf20Sopenharmony_ci	unsigned long flags;
13418c2ecf20Sopenharmony_ci	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)ptr;
13428c2ecf20Sopenharmony_ci	struct ScsiReqBlk *srb;
13438c2ecf20Sopenharmony_ci	dprintkl(KERN_DEBUG, "Chip forgot to produce SelTO IRQ!\n");
13448c2ecf20Sopenharmony_ci	if (!acb->active_dcb || !acb->active_dcb->active_srb) {
13458c2ecf20Sopenharmony_ci		dprintkl(KERN_DEBUG, "... but no cmd pending? Oops!\n");
13468c2ecf20Sopenharmony_ci		return;
13478c2ecf20Sopenharmony_ci	}
13488c2ecf20Sopenharmony_ci	DC395x_LOCK_IO(acb->scsi_host, flags);
13498c2ecf20Sopenharmony_ci	srb = acb->active_dcb->active_srb;
13508c2ecf20Sopenharmony_ci	disconnect(acb);
13518c2ecf20Sopenharmony_ci	DC395x_UNLOCK_IO(acb->scsi_host, flags);
13528c2ecf20Sopenharmony_ci}
13538c2ecf20Sopenharmony_ci#endif
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_cistatic u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
13578c2ecf20Sopenharmony_ci		struct ScsiReqBlk* srb)
13588c2ecf20Sopenharmony_ci{
13598c2ecf20Sopenharmony_ci	u16 s_stat2, return_code;
13608c2ecf20Sopenharmony_ci	u8 s_stat, scsicommand, i, identify_message;
13618c2ecf20Sopenharmony_ci	u8 *ptr;
13628c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "start_scsi: (0x%p) <%02i-%i> srb=%p\n",
13638c2ecf20Sopenharmony_ci		dcb->target_id, dcb->target_lun, srb);
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	srb->tag_number = TAG_NONE;	/* acb->tag_max_num: had error read in eeprom */
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	s_stat = DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL);
13688c2ecf20Sopenharmony_ci	s_stat2 = 0;
13698c2ecf20Sopenharmony_ci	s_stat2 = DC395x_read16(acb, TRM_S1040_SCSI_STATUS);
13708c2ecf20Sopenharmony_ci#if 1
13718c2ecf20Sopenharmony_ci	if (s_stat & 0x20 /* s_stat2 & 0x02000 */ ) {
13728c2ecf20Sopenharmony_ci		dprintkdbg(DBG_KG, "start_scsi: (0x%p) BUSY %02x %04x\n",
13738c2ecf20Sopenharmony_ci			s_stat, s_stat2);
13748c2ecf20Sopenharmony_ci		/*
13758c2ecf20Sopenharmony_ci		 * Try anyway?
13768c2ecf20Sopenharmony_ci		 *
13778c2ecf20Sopenharmony_ci		 * We could, BUT: Sometimes the TRM_S1040 misses to produce a Selection
13788c2ecf20Sopenharmony_ci		 * Timeout, a Disconnect or a Reselection IRQ, so we would be screwed!
13798c2ecf20Sopenharmony_ci		 * (This is likely to be a bug in the hardware. Obviously, most people
13808c2ecf20Sopenharmony_ci		 *  only have one initiator per SCSI bus.)
13818c2ecf20Sopenharmony_ci		 * Instead let this fail and have the timer make sure the command is
13828c2ecf20Sopenharmony_ci		 * tried again after a short time
13838c2ecf20Sopenharmony_ci		 */
13848c2ecf20Sopenharmony_ci		/*selto_timer (acb); */
13858c2ecf20Sopenharmony_ci		return 1;
13868c2ecf20Sopenharmony_ci	}
13878c2ecf20Sopenharmony_ci#endif
13888c2ecf20Sopenharmony_ci	if (acb->active_dcb) {
13898c2ecf20Sopenharmony_ci		dprintkl(KERN_DEBUG, "start_scsi: (0x%p) Attempt to start a"
13908c2ecf20Sopenharmony_ci			"command while another command (0x%p) is active.",
13918c2ecf20Sopenharmony_ci			srb->cmd,
13928c2ecf20Sopenharmony_ci			acb->active_dcb->active_srb ?
13938c2ecf20Sopenharmony_ci			    acb->active_dcb->active_srb->cmd : 0);
13948c2ecf20Sopenharmony_ci		return 1;
13958c2ecf20Sopenharmony_ci	}
13968c2ecf20Sopenharmony_ci	if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) {
13978c2ecf20Sopenharmony_ci		dprintkdbg(DBG_KG, "start_scsi: (0x%p) Failed (busy)\n", srb->cmd);
13988c2ecf20Sopenharmony_ci		return 1;
13998c2ecf20Sopenharmony_ci	}
14008c2ecf20Sopenharmony_ci	/* Allow starting of SCSI commands half a second before we allow the mid-level
14018c2ecf20Sopenharmony_ci	 * to queue them again after a reset */
14028c2ecf20Sopenharmony_ci	if (time_before(jiffies, acb->last_reset - HZ / 2)) {
14038c2ecf20Sopenharmony_ci		dprintkdbg(DBG_KG, "start_scsi: Refuse cmds (reset wait)\n");
14048c2ecf20Sopenharmony_ci		return 1;
14058c2ecf20Sopenharmony_ci	}
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci	/* Flush FIFO */
14088c2ecf20Sopenharmony_ci	clear_fifo(acb, "start_scsi");
14098c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_HOSTID, acb->scsi_host->this_id);
14108c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id);
14118c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_SYNC, dcb->sync_period);
14128c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, dcb->sync_offset);
14138c2ecf20Sopenharmony_ci	srb->scsi_phase = PH_BUS_FREE;	/* initial phase */
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	identify_message = dcb->identify_msg;
14168c2ecf20Sopenharmony_ci	/*DC395x_TRM_write8(TRM_S1040_SCSI_IDMSG, identify_message); */
14178c2ecf20Sopenharmony_ci	/* Don't allow disconnection for AUTO_REQSENSE: Cont.All.Cond.! */
14188c2ecf20Sopenharmony_ci	if (srb->flag & AUTO_REQSENSE)
14198c2ecf20Sopenharmony_ci		identify_message &= 0xBF;
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	if (((srb->cmd->cmnd[0] == INQUIRY)
14228c2ecf20Sopenharmony_ci	     || (srb->cmd->cmnd[0] == REQUEST_SENSE)
14238c2ecf20Sopenharmony_ci	     || (srb->flag & AUTO_REQSENSE))
14248c2ecf20Sopenharmony_ci	    && (((dcb->sync_mode & WIDE_NEGO_ENABLE)
14258c2ecf20Sopenharmony_ci		 && !(dcb->sync_mode & WIDE_NEGO_DONE))
14268c2ecf20Sopenharmony_ci		|| ((dcb->sync_mode & SYNC_NEGO_ENABLE)
14278c2ecf20Sopenharmony_ci		    && !(dcb->sync_mode & SYNC_NEGO_DONE)))
14288c2ecf20Sopenharmony_ci	    && (dcb->target_lun == 0)) {
14298c2ecf20Sopenharmony_ci		srb->msgout_buf[0] = identify_message;
14308c2ecf20Sopenharmony_ci		srb->msg_count = 1;
14318c2ecf20Sopenharmony_ci		scsicommand = SCMD_SEL_ATNSTOP;
14328c2ecf20Sopenharmony_ci		srb->state = SRB_MSGOUT;
14338c2ecf20Sopenharmony_ci#ifndef SYNC_FIRST
14348c2ecf20Sopenharmony_ci		if (dcb->sync_mode & WIDE_NEGO_ENABLE
14358c2ecf20Sopenharmony_ci		    && dcb->inquiry7 & SCSI_INQ_WBUS16) {
14368c2ecf20Sopenharmony_ci			build_wdtr(acb, dcb, srb);
14378c2ecf20Sopenharmony_ci			goto no_cmd;
14388c2ecf20Sopenharmony_ci		}
14398c2ecf20Sopenharmony_ci#endif
14408c2ecf20Sopenharmony_ci		if (dcb->sync_mode & SYNC_NEGO_ENABLE
14418c2ecf20Sopenharmony_ci		    && dcb->inquiry7 & SCSI_INQ_SYNC) {
14428c2ecf20Sopenharmony_ci			build_sdtr(acb, dcb, srb);
14438c2ecf20Sopenharmony_ci			goto no_cmd;
14448c2ecf20Sopenharmony_ci		}
14458c2ecf20Sopenharmony_ci		if (dcb->sync_mode & WIDE_NEGO_ENABLE
14468c2ecf20Sopenharmony_ci		    && dcb->inquiry7 & SCSI_INQ_WBUS16) {
14478c2ecf20Sopenharmony_ci			build_wdtr(acb, dcb, srb);
14488c2ecf20Sopenharmony_ci			goto no_cmd;
14498c2ecf20Sopenharmony_ci		}
14508c2ecf20Sopenharmony_ci		srb->msg_count = 0;
14518c2ecf20Sopenharmony_ci	}
14528c2ecf20Sopenharmony_ci	/* Send identify message */
14538c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_FIFO, identify_message);
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci	scsicommand = SCMD_SEL_ATN;
14568c2ecf20Sopenharmony_ci	srb->state = SRB_START_;
14578c2ecf20Sopenharmony_ci#ifndef DC395x_NO_TAGQ
14588c2ecf20Sopenharmony_ci	if ((dcb->sync_mode & EN_TAG_QUEUEING)
14598c2ecf20Sopenharmony_ci	    && (identify_message & 0xC0)) {
14608c2ecf20Sopenharmony_ci		/* Send Tag message */
14618c2ecf20Sopenharmony_ci		u32 tag_mask = 1;
14628c2ecf20Sopenharmony_ci		u8 tag_number = 0;
14638c2ecf20Sopenharmony_ci		while (tag_mask & dcb->tag_mask
14648c2ecf20Sopenharmony_ci		       && tag_number < dcb->max_command) {
14658c2ecf20Sopenharmony_ci			tag_mask = tag_mask << 1;
14668c2ecf20Sopenharmony_ci			tag_number++;
14678c2ecf20Sopenharmony_ci		}
14688c2ecf20Sopenharmony_ci		if (tag_number >= dcb->max_command) {
14698c2ecf20Sopenharmony_ci			dprintkl(KERN_WARNING, "start_scsi: (0x%p) "
14708c2ecf20Sopenharmony_ci				"Out of tags target=<%02i-%i>)\n",
14718c2ecf20Sopenharmony_ci				srb->cmd, srb->cmd->device->id,
14728c2ecf20Sopenharmony_ci				(u8)srb->cmd->device->lun);
14738c2ecf20Sopenharmony_ci			srb->state = SRB_READY;
14748c2ecf20Sopenharmony_ci			DC395x_write16(acb, TRM_S1040_SCSI_CONTROL,
14758c2ecf20Sopenharmony_ci				       DO_HWRESELECT);
14768c2ecf20Sopenharmony_ci			return 1;
14778c2ecf20Sopenharmony_ci		}
14788c2ecf20Sopenharmony_ci		/* Send Tag id */
14798c2ecf20Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, MSG_SIMPLE_QTAG);
14808c2ecf20Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, tag_number);
14818c2ecf20Sopenharmony_ci		dcb->tag_mask |= tag_mask;
14828c2ecf20Sopenharmony_ci		srb->tag_number = tag_number;
14838c2ecf20Sopenharmony_ci		scsicommand = SCMD_SEL_ATN3;
14848c2ecf20Sopenharmony_ci		srb->state = SRB_START_;
14858c2ecf20Sopenharmony_ci	}
14868c2ecf20Sopenharmony_ci#endif
14878c2ecf20Sopenharmony_ci/*polling:*/
14888c2ecf20Sopenharmony_ci	/* Send CDB ..command block ......... */
14898c2ecf20Sopenharmony_ci	dprintkdbg(DBG_KG, "start_scsi: (0x%p) <%02i-%i> cmnd=0x%02x tag=%i\n",
14908c2ecf20Sopenharmony_ci		srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun,
14918c2ecf20Sopenharmony_ci		srb->cmd->cmnd[0], srb->tag_number);
14928c2ecf20Sopenharmony_ci	if (srb->flag & AUTO_REQSENSE) {
14938c2ecf20Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, REQUEST_SENSE);
14948c2ecf20Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5));
14958c2ecf20Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
14968c2ecf20Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
14978c2ecf20Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, SCSI_SENSE_BUFFERSIZE);
14988c2ecf20Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
14998c2ecf20Sopenharmony_ci	} else {
15008c2ecf20Sopenharmony_ci		ptr = (u8 *)srb->cmd->cmnd;
15018c2ecf20Sopenharmony_ci		for (i = 0; i < srb->cmd->cmd_len; i++)
15028c2ecf20Sopenharmony_ci			DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr++);
15038c2ecf20Sopenharmony_ci	}
15048c2ecf20Sopenharmony_ci      no_cmd:
15058c2ecf20Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL,
15068c2ecf20Sopenharmony_ci		       DO_HWRESELECT | DO_DATALATCH);
15078c2ecf20Sopenharmony_ci	if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) {
15088c2ecf20Sopenharmony_ci		/*
15098c2ecf20Sopenharmony_ci		 * If start_scsi return 1:
15108c2ecf20Sopenharmony_ci		 * we caught an interrupt (must be reset or reselection ... )
15118c2ecf20Sopenharmony_ci		 * : Let's process it first!
15128c2ecf20Sopenharmony_ci		 */
15138c2ecf20Sopenharmony_ci		dprintkdbg(DBG_0, "start_scsi: (0x%p) <%02i-%i> Failed - busy\n",
15148c2ecf20Sopenharmony_ci			srb->cmd, dcb->target_id, dcb->target_lun);
15158c2ecf20Sopenharmony_ci		srb->state = SRB_READY;
15168c2ecf20Sopenharmony_ci		free_tag(dcb, srb);
15178c2ecf20Sopenharmony_ci		srb->msg_count = 0;
15188c2ecf20Sopenharmony_ci		return_code = 1;
15198c2ecf20Sopenharmony_ci		/* This IRQ should NOT get lost, as we did not acknowledge it */
15208c2ecf20Sopenharmony_ci	} else {
15218c2ecf20Sopenharmony_ci		/*
15228c2ecf20Sopenharmony_ci		 * If start_scsi returns 0:
15238c2ecf20Sopenharmony_ci		 * we know that the SCSI processor is free
15248c2ecf20Sopenharmony_ci		 */
15258c2ecf20Sopenharmony_ci		srb->scsi_phase = PH_BUS_FREE;	/* initial phase */
15268c2ecf20Sopenharmony_ci		dcb->active_srb = srb;
15278c2ecf20Sopenharmony_ci		acb->active_dcb = dcb;
15288c2ecf20Sopenharmony_ci		return_code = 0;
15298c2ecf20Sopenharmony_ci		/* it's important for atn stop */
15308c2ecf20Sopenharmony_ci		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL,
15318c2ecf20Sopenharmony_ci			       DO_DATALATCH | DO_HWRESELECT);
15328c2ecf20Sopenharmony_ci		/* SCSI command */
15338c2ecf20Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, scsicommand);
15348c2ecf20Sopenharmony_ci	}
15358c2ecf20Sopenharmony_ci	return return_code;
15368c2ecf20Sopenharmony_ci}
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci#define DC395x_ENABLE_MSGOUT \
15408c2ecf20Sopenharmony_ci DC395x_write16 (acb, TRM_S1040_SCSI_CONTROL, DO_SETATN); \
15418c2ecf20Sopenharmony_ci srb->state |= SRB_MSGOUT
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_ci/* abort command */
15458c2ecf20Sopenharmony_cistatic inline void enable_msgout_abort(struct AdapterCtlBlk *acb,
15468c2ecf20Sopenharmony_ci		struct ScsiReqBlk *srb)
15478c2ecf20Sopenharmony_ci{
15488c2ecf20Sopenharmony_ci	srb->msgout_buf[0] = ABORT;
15498c2ecf20Sopenharmony_ci	srb->msg_count = 1;
15508c2ecf20Sopenharmony_ci	DC395x_ENABLE_MSGOUT;
15518c2ecf20Sopenharmony_ci	srb->state &= ~SRB_MSGIN;
15528c2ecf20Sopenharmony_ci	srb->state |= SRB_MSGOUT;
15538c2ecf20Sopenharmony_ci}
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci/**
15578c2ecf20Sopenharmony_ci * dc395x_handle_interrupt - Handle an interrupt that has been confirmed to
15588c2ecf20Sopenharmony_ci *                           have been triggered for this card.
15598c2ecf20Sopenharmony_ci *
15608c2ecf20Sopenharmony_ci * @acb:	 a pointer to the adpter control block
15618c2ecf20Sopenharmony_ci * @scsi_status: the status return when we checked the card
15628c2ecf20Sopenharmony_ci **/
15638c2ecf20Sopenharmony_cistatic void dc395x_handle_interrupt(struct AdapterCtlBlk *acb,
15648c2ecf20Sopenharmony_ci		u16 scsi_status)
15658c2ecf20Sopenharmony_ci{
15668c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb;
15678c2ecf20Sopenharmony_ci	struct ScsiReqBlk *srb;
15688c2ecf20Sopenharmony_ci	u16 phase;
15698c2ecf20Sopenharmony_ci	u8 scsi_intstatus;
15708c2ecf20Sopenharmony_ci	unsigned long flags;
15718c2ecf20Sopenharmony_ci	void (*dc395x_statev)(struct AdapterCtlBlk *, struct ScsiReqBlk *,
15728c2ecf20Sopenharmony_ci			      u16 *);
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci	DC395x_LOCK_IO(acb->scsi_host, flags);
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_ci	/* This acknowledges the IRQ */
15778c2ecf20Sopenharmony_ci	scsi_intstatus = DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS);
15788c2ecf20Sopenharmony_ci	if ((scsi_status & 0x2007) == 0x2002)
15798c2ecf20Sopenharmony_ci		dprintkl(KERN_DEBUG,
15808c2ecf20Sopenharmony_ci			"COP after COP completed? %04x\n", scsi_status);
15818c2ecf20Sopenharmony_ci	if (debug_enabled(DBG_KG)) {
15828c2ecf20Sopenharmony_ci		if (scsi_intstatus & INT_SELTIMEOUT)
15838c2ecf20Sopenharmony_ci			dprintkdbg(DBG_KG, "handle_interrupt: Selection timeout\n");
15848c2ecf20Sopenharmony_ci	}
15858c2ecf20Sopenharmony_ci	/*dprintkl(KERN_DEBUG, "handle_interrupt: intstatus = 0x%02x ", scsi_intstatus); */
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci	if (timer_pending(&acb->selto_timer))
15888c2ecf20Sopenharmony_ci		del_timer(&acb->selto_timer);
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci	if (scsi_intstatus & (INT_SELTIMEOUT | INT_DISCONNECT)) {
15918c2ecf20Sopenharmony_ci		disconnect(acb);	/* bus free interrupt  */
15928c2ecf20Sopenharmony_ci		goto out_unlock;
15938c2ecf20Sopenharmony_ci	}
15948c2ecf20Sopenharmony_ci	if (scsi_intstatus & INT_RESELECTED) {
15958c2ecf20Sopenharmony_ci		reselect(acb);
15968c2ecf20Sopenharmony_ci		goto out_unlock;
15978c2ecf20Sopenharmony_ci	}
15988c2ecf20Sopenharmony_ci	if (scsi_intstatus & INT_SELECT) {
15998c2ecf20Sopenharmony_ci		dprintkl(KERN_INFO, "Host does not support target mode!\n");
16008c2ecf20Sopenharmony_ci		goto out_unlock;
16018c2ecf20Sopenharmony_ci	}
16028c2ecf20Sopenharmony_ci	if (scsi_intstatus & INT_SCSIRESET) {
16038c2ecf20Sopenharmony_ci		scsi_reset_detect(acb);
16048c2ecf20Sopenharmony_ci		goto out_unlock;
16058c2ecf20Sopenharmony_ci	}
16068c2ecf20Sopenharmony_ci	if (scsi_intstatus & (INT_BUSSERVICE | INT_CMDDONE)) {
16078c2ecf20Sopenharmony_ci		dcb = acb->active_dcb;
16088c2ecf20Sopenharmony_ci		if (!dcb) {
16098c2ecf20Sopenharmony_ci			dprintkl(KERN_DEBUG,
16108c2ecf20Sopenharmony_ci				"Oops: BusService (%04x %02x) w/o ActiveDCB!\n",
16118c2ecf20Sopenharmony_ci				scsi_status, scsi_intstatus);
16128c2ecf20Sopenharmony_ci			goto out_unlock;
16138c2ecf20Sopenharmony_ci		}
16148c2ecf20Sopenharmony_ci		srb = dcb->active_srb;
16158c2ecf20Sopenharmony_ci		if (dcb->flag & ABORT_DEV_) {
16168c2ecf20Sopenharmony_ci			dprintkdbg(DBG_0, "MsgOut Abort Device.....\n");
16178c2ecf20Sopenharmony_ci			enable_msgout_abort(acb, srb);
16188c2ecf20Sopenharmony_ci		}
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci		/* software sequential machine */
16218c2ecf20Sopenharmony_ci		phase = (u16)srb->scsi_phase;
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci		/*
16248c2ecf20Sopenharmony_ci		 * 62037 or 62137
16258c2ecf20Sopenharmony_ci		 * call  dc395x_scsi_phase0[]... "phase entry"
16268c2ecf20Sopenharmony_ci		 * handle every phase before start transfer
16278c2ecf20Sopenharmony_ci		 */
16288c2ecf20Sopenharmony_ci		/* data_out_phase0,	phase:0 */
16298c2ecf20Sopenharmony_ci		/* data_in_phase0,	phase:1 */
16308c2ecf20Sopenharmony_ci		/* command_phase0,	phase:2 */
16318c2ecf20Sopenharmony_ci		/* status_phase0,	phase:3 */
16328c2ecf20Sopenharmony_ci		/* nop0,		phase:4 PH_BUS_FREE .. initial phase */
16338c2ecf20Sopenharmony_ci		/* nop0,		phase:5 PH_BUS_FREE .. initial phase */
16348c2ecf20Sopenharmony_ci		/* msgout_phase0,	phase:6 */
16358c2ecf20Sopenharmony_ci		/* msgin_phase0,	phase:7 */
16368c2ecf20Sopenharmony_ci		dc395x_statev = dc395x_scsi_phase0[phase];
16378c2ecf20Sopenharmony_ci		dc395x_statev(acb, srb, &scsi_status);
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci		/*
16408c2ecf20Sopenharmony_ci		 * if there were any exception occurred scsi_status
16418c2ecf20Sopenharmony_ci		 * will be modify to bus free phase new scsi_status
16428c2ecf20Sopenharmony_ci		 * transfer out from ... previous dc395x_statev
16438c2ecf20Sopenharmony_ci		 */
16448c2ecf20Sopenharmony_ci		srb->scsi_phase = scsi_status & PHASEMASK;
16458c2ecf20Sopenharmony_ci		phase = (u16)scsi_status & PHASEMASK;
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci		/*
16488c2ecf20Sopenharmony_ci		 * call  dc395x_scsi_phase1[]... "phase entry" handle
16498c2ecf20Sopenharmony_ci		 * every phase to do transfer
16508c2ecf20Sopenharmony_ci		 */
16518c2ecf20Sopenharmony_ci		/* data_out_phase1,	phase:0 */
16528c2ecf20Sopenharmony_ci		/* data_in_phase1,	phase:1 */
16538c2ecf20Sopenharmony_ci		/* command_phase1,	phase:2 */
16548c2ecf20Sopenharmony_ci		/* status_phase1,	phase:3 */
16558c2ecf20Sopenharmony_ci		/* nop1,		phase:4 PH_BUS_FREE .. initial phase */
16568c2ecf20Sopenharmony_ci		/* nop1,		phase:5 PH_BUS_FREE .. initial phase */
16578c2ecf20Sopenharmony_ci		/* msgout_phase1,	phase:6 */
16588c2ecf20Sopenharmony_ci		/* msgin_phase1,	phase:7 */
16598c2ecf20Sopenharmony_ci		dc395x_statev = dc395x_scsi_phase1[phase];
16608c2ecf20Sopenharmony_ci		dc395x_statev(acb, srb, &scsi_status);
16618c2ecf20Sopenharmony_ci	}
16628c2ecf20Sopenharmony_ci      out_unlock:
16638c2ecf20Sopenharmony_ci	DC395x_UNLOCK_IO(acb->scsi_host, flags);
16648c2ecf20Sopenharmony_ci}
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_cistatic irqreturn_t dc395x_interrupt(int irq, void *dev_id)
16688c2ecf20Sopenharmony_ci{
16698c2ecf20Sopenharmony_ci	struct AdapterCtlBlk *acb = dev_id;
16708c2ecf20Sopenharmony_ci	u16 scsi_status;
16718c2ecf20Sopenharmony_ci	u8 dma_status;
16728c2ecf20Sopenharmony_ci	irqreturn_t handled = IRQ_NONE;
16738c2ecf20Sopenharmony_ci
16748c2ecf20Sopenharmony_ci	/*
16758c2ecf20Sopenharmony_ci	 * Check for pending interrupt
16768c2ecf20Sopenharmony_ci	 */
16778c2ecf20Sopenharmony_ci	scsi_status = DC395x_read16(acb, TRM_S1040_SCSI_STATUS);
16788c2ecf20Sopenharmony_ci	dma_status = DC395x_read8(acb, TRM_S1040_DMA_STATUS);
16798c2ecf20Sopenharmony_ci	if (scsi_status & SCSIINTERRUPT) {
16808c2ecf20Sopenharmony_ci		/* interrupt pending - let's process it! */
16818c2ecf20Sopenharmony_ci		dc395x_handle_interrupt(acb, scsi_status);
16828c2ecf20Sopenharmony_ci		handled = IRQ_HANDLED;
16838c2ecf20Sopenharmony_ci	}
16848c2ecf20Sopenharmony_ci	else if (dma_status & 0x20) {
16858c2ecf20Sopenharmony_ci		/* Error from the DMA engine */
16868c2ecf20Sopenharmony_ci		dprintkl(KERN_INFO, "Interrupt from DMA engine: 0x%02x!\n", dma_status);
16878c2ecf20Sopenharmony_ci#if 0
16888c2ecf20Sopenharmony_ci		dprintkl(KERN_INFO, "This means DMA error! Try to handle ...\n");
16898c2ecf20Sopenharmony_ci		if (acb->active_dcb) {
16908c2ecf20Sopenharmony_ci			acb->active_dcb-> flag |= ABORT_DEV_;
16918c2ecf20Sopenharmony_ci			if (acb->active_dcb->active_srb)
16928c2ecf20Sopenharmony_ci				enable_msgout_abort(acb, acb->active_dcb->active_srb);
16938c2ecf20Sopenharmony_ci		}
16948c2ecf20Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_DMA_CONTROL, ABORTXFER | CLRXFIFO);
16958c2ecf20Sopenharmony_ci#else
16968c2ecf20Sopenharmony_ci		dprintkl(KERN_INFO, "Ignoring DMA error (probably a bad thing) ...\n");
16978c2ecf20Sopenharmony_ci		acb = NULL;
16988c2ecf20Sopenharmony_ci#endif
16998c2ecf20Sopenharmony_ci		handled = IRQ_HANDLED;
17008c2ecf20Sopenharmony_ci	}
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_ci	return handled;
17038c2ecf20Sopenharmony_ci}
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_cistatic void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
17078c2ecf20Sopenharmony_ci		u16 *pscsi_status)
17088c2ecf20Sopenharmony_ci{
17098c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "msgout_phase0: (0x%p)\n", srb->cmd);
17108c2ecf20Sopenharmony_ci	if (srb->state & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT))
17118c2ecf20Sopenharmony_ci		*pscsi_status = PH_BUS_FREE;	/*.. initial phase */
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
17148c2ecf20Sopenharmony_ci	srb->state &= ~SRB_MSGOUT;
17158c2ecf20Sopenharmony_ci}
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_cistatic void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
17198c2ecf20Sopenharmony_ci		u16 *pscsi_status)
17208c2ecf20Sopenharmony_ci{
17218c2ecf20Sopenharmony_ci	u16 i;
17228c2ecf20Sopenharmony_ci	u8 *ptr;
17238c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "msgout_phase1: (0x%p)\n", srb->cmd);
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_ci	clear_fifo(acb, "msgout_phase1");
17268c2ecf20Sopenharmony_ci	if (!(srb->state & SRB_MSGOUT)) {
17278c2ecf20Sopenharmony_ci		srb->state |= SRB_MSGOUT;
17288c2ecf20Sopenharmony_ci		dprintkl(KERN_DEBUG,
17298c2ecf20Sopenharmony_ci			"msgout_phase1: (0x%p) Phase unexpected\n",
17308c2ecf20Sopenharmony_ci			srb->cmd);	/* So what ? */
17318c2ecf20Sopenharmony_ci	}
17328c2ecf20Sopenharmony_ci	if (!srb->msg_count) {
17338c2ecf20Sopenharmony_ci		dprintkdbg(DBG_0, "msgout_phase1: (0x%p) NOP msg\n",
17348c2ecf20Sopenharmony_ci			srb->cmd);
17358c2ecf20Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, MSG_NOP);
17368c2ecf20Sopenharmony_ci		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
17378c2ecf20Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
17388c2ecf20Sopenharmony_ci		return;
17398c2ecf20Sopenharmony_ci	}
17408c2ecf20Sopenharmony_ci	ptr = (u8 *)srb->msgout_buf;
17418c2ecf20Sopenharmony_ci	for (i = 0; i < srb->msg_count; i++)
17428c2ecf20Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr++);
17438c2ecf20Sopenharmony_ci	srb->msg_count = 0;
17448c2ecf20Sopenharmony_ci	if (srb->msgout_buf[0] == MSG_ABORT)
17458c2ecf20Sopenharmony_ci		srb->state = SRB_ABORT_SENT;
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
17488c2ecf20Sopenharmony_ci}
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_cistatic void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
17528c2ecf20Sopenharmony_ci		u16 *pscsi_status)
17538c2ecf20Sopenharmony_ci{
17548c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "command_phase0: (0x%p)\n", srb->cmd);
17558c2ecf20Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
17568c2ecf20Sopenharmony_ci}
17578c2ecf20Sopenharmony_ci
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_cistatic void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
17608c2ecf20Sopenharmony_ci		u16 *pscsi_status)
17618c2ecf20Sopenharmony_ci{
17628c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb;
17638c2ecf20Sopenharmony_ci	u8 *ptr;
17648c2ecf20Sopenharmony_ci	u16 i;
17658c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "command_phase1: (0x%p)\n", srb->cmd);
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_ci	clear_fifo(acb, "command_phase1");
17688c2ecf20Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRATN);
17698c2ecf20Sopenharmony_ci	if (!(srb->flag & AUTO_REQSENSE)) {
17708c2ecf20Sopenharmony_ci		ptr = (u8 *)srb->cmd->cmnd;
17718c2ecf20Sopenharmony_ci		for (i = 0; i < srb->cmd->cmd_len; i++) {
17728c2ecf20Sopenharmony_ci			DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr);
17738c2ecf20Sopenharmony_ci			ptr++;
17748c2ecf20Sopenharmony_ci		}
17758c2ecf20Sopenharmony_ci	} else {
17768c2ecf20Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, REQUEST_SENSE);
17778c2ecf20Sopenharmony_ci		dcb = acb->active_dcb;
17788c2ecf20Sopenharmony_ci		/* target id */
17798c2ecf20Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5));
17808c2ecf20Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
17818c2ecf20Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
17828c2ecf20Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, SCSI_SENSE_BUFFERSIZE);
17838c2ecf20Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
17848c2ecf20Sopenharmony_ci	}
17858c2ecf20Sopenharmony_ci	srb->state |= SRB_COMMAND;
17868c2ecf20Sopenharmony_ci	/* it's important for atn stop */
17878c2ecf20Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
17888c2ecf20Sopenharmony_ci	/* SCSI command */
17898c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
17908c2ecf20Sopenharmony_ci}
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ci
17938c2ecf20Sopenharmony_ci/*
17948c2ecf20Sopenharmony_ci * Verify that the remaining space in the hw sg lists is the same as
17958c2ecf20Sopenharmony_ci * the count of remaining bytes in srb->total_xfer_length
17968c2ecf20Sopenharmony_ci */
17978c2ecf20Sopenharmony_cistatic void sg_verify_length(struct ScsiReqBlk *srb)
17988c2ecf20Sopenharmony_ci{
17998c2ecf20Sopenharmony_ci	if (debug_enabled(DBG_SG)) {
18008c2ecf20Sopenharmony_ci		unsigned len = 0;
18018c2ecf20Sopenharmony_ci		unsigned idx = srb->sg_index;
18028c2ecf20Sopenharmony_ci		struct SGentry *psge = srb->segment_x + idx;
18038c2ecf20Sopenharmony_ci		for (; idx < srb->sg_count; psge++, idx++)
18048c2ecf20Sopenharmony_ci			len += psge->length;
18058c2ecf20Sopenharmony_ci		if (len != srb->total_xfer_length)
18068c2ecf20Sopenharmony_ci			dprintkdbg(DBG_SG,
18078c2ecf20Sopenharmony_ci			       "Inconsistent SRB S/G lengths (Tot=%i, Count=%i) !!\n",
18088c2ecf20Sopenharmony_ci			       srb->total_xfer_length, len);
18098c2ecf20Sopenharmony_ci	}
18108c2ecf20Sopenharmony_ci}
18118c2ecf20Sopenharmony_ci
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_ci/*
18148c2ecf20Sopenharmony_ci * Compute the next Scatter Gather list index and adjust its length
18158c2ecf20Sopenharmony_ci * and address if necessary
18168c2ecf20Sopenharmony_ci */
18178c2ecf20Sopenharmony_cistatic void sg_update_list(struct ScsiReqBlk *srb, u32 left)
18188c2ecf20Sopenharmony_ci{
18198c2ecf20Sopenharmony_ci	u8 idx;
18208c2ecf20Sopenharmony_ci	u32 xferred = srb->total_xfer_length - left; /* bytes transferred */
18218c2ecf20Sopenharmony_ci	struct SGentry *psge = srb->segment_x + srb->sg_index;
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0,
18248c2ecf20Sopenharmony_ci		"sg_update_list: Transferred %i of %i bytes, %i remain\n",
18258c2ecf20Sopenharmony_ci		xferred, srb->total_xfer_length, left);
18268c2ecf20Sopenharmony_ci	if (xferred == 0) {
18278c2ecf20Sopenharmony_ci		/* nothing to update since we did not transfer any data */
18288c2ecf20Sopenharmony_ci		return;
18298c2ecf20Sopenharmony_ci	}
18308c2ecf20Sopenharmony_ci
18318c2ecf20Sopenharmony_ci	sg_verify_length(srb);
18328c2ecf20Sopenharmony_ci	srb->total_xfer_length = left;	/* update remaining count */
18338c2ecf20Sopenharmony_ci	for (idx = srb->sg_index; idx < srb->sg_count; idx++) {
18348c2ecf20Sopenharmony_ci		if (xferred >= psge->length) {
18358c2ecf20Sopenharmony_ci			/* Complete SG entries done */
18368c2ecf20Sopenharmony_ci			xferred -= psge->length;
18378c2ecf20Sopenharmony_ci		} else {
18388c2ecf20Sopenharmony_ci			/* Partial SG entry done */
18398c2ecf20Sopenharmony_ci			dma_sync_single_for_cpu(&srb->dcb->acb->dev->dev,
18408c2ecf20Sopenharmony_ci					srb->sg_bus_addr, SEGMENTX_LEN,
18418c2ecf20Sopenharmony_ci					DMA_TO_DEVICE);
18428c2ecf20Sopenharmony_ci			psge->length -= xferred;
18438c2ecf20Sopenharmony_ci			psge->address += xferred;
18448c2ecf20Sopenharmony_ci			srb->sg_index = idx;
18458c2ecf20Sopenharmony_ci			dma_sync_single_for_device(&srb->dcb->acb->dev->dev,
18468c2ecf20Sopenharmony_ci					srb->sg_bus_addr, SEGMENTX_LEN,
18478c2ecf20Sopenharmony_ci					DMA_TO_DEVICE);
18488c2ecf20Sopenharmony_ci			break;
18498c2ecf20Sopenharmony_ci		}
18508c2ecf20Sopenharmony_ci		psge++;
18518c2ecf20Sopenharmony_ci	}
18528c2ecf20Sopenharmony_ci	sg_verify_length(srb);
18538c2ecf20Sopenharmony_ci}
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ci
18568c2ecf20Sopenharmony_ci/*
18578c2ecf20Sopenharmony_ci * We have transferred a single byte (PIO mode?) and need to update
18588c2ecf20Sopenharmony_ci * the count of bytes remaining (total_xfer_length) and update the sg
18598c2ecf20Sopenharmony_ci * entry to either point to next byte in the current sg entry, or of
18608c2ecf20Sopenharmony_ci * already at the end to point to the start of the next sg entry
18618c2ecf20Sopenharmony_ci */
18628c2ecf20Sopenharmony_cistatic void sg_subtract_one(struct ScsiReqBlk *srb)
18638c2ecf20Sopenharmony_ci{
18648c2ecf20Sopenharmony_ci	sg_update_list(srb, srb->total_xfer_length - 1);
18658c2ecf20Sopenharmony_ci}
18668c2ecf20Sopenharmony_ci
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_ci/*
18698c2ecf20Sopenharmony_ci * cleanup_after_transfer
18708c2ecf20Sopenharmony_ci *
18718c2ecf20Sopenharmony_ci * Makes sure, DMA and SCSI engine are empty, after the transfer has finished
18728c2ecf20Sopenharmony_ci * KG: Currently called from  StatusPhase1 ()
18738c2ecf20Sopenharmony_ci * Should probably also be called from other places
18748c2ecf20Sopenharmony_ci * Best might be to call it in DataXXPhase0, if new phase will differ
18758c2ecf20Sopenharmony_ci */
18768c2ecf20Sopenharmony_cistatic void cleanup_after_transfer(struct AdapterCtlBlk *acb,
18778c2ecf20Sopenharmony_ci		struct ScsiReqBlk *srb)
18788c2ecf20Sopenharmony_ci{
18798c2ecf20Sopenharmony_ci	/*DC395x_write8 (TRM_S1040_DMA_STATUS, FORCEDMACOMP); */
18808c2ecf20Sopenharmony_ci	if (DC395x_read16(acb, TRM_S1040_DMA_COMMAND) & 0x0001) {	/* read */
18818c2ecf20Sopenharmony_ci		if (!(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x40))
18828c2ecf20Sopenharmony_ci			clear_fifo(acb, "cleanup/in");
18838c2ecf20Sopenharmony_ci		if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80))
18848c2ecf20Sopenharmony_ci			DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO);
18858c2ecf20Sopenharmony_ci	} else {		/* write */
18868c2ecf20Sopenharmony_ci		if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80))
18878c2ecf20Sopenharmony_ci			DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO);
18888c2ecf20Sopenharmony_ci		if (!(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x40))
18898c2ecf20Sopenharmony_ci			clear_fifo(acb, "cleanup/out");
18908c2ecf20Sopenharmony_ci	}
18918c2ecf20Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
18928c2ecf20Sopenharmony_ci}
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci
18958c2ecf20Sopenharmony_ci/*
18968c2ecf20Sopenharmony_ci * Those no of bytes will be transferred w/ PIO through the SCSI FIFO
18978c2ecf20Sopenharmony_ci * Seems to be needed for unknown reasons; could be a hardware bug :-(
18988c2ecf20Sopenharmony_ci */
18998c2ecf20Sopenharmony_ci#define DC395x_LASTPIO 4
19008c2ecf20Sopenharmony_ci
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_cistatic void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
19038c2ecf20Sopenharmony_ci		u16 *pscsi_status)
19048c2ecf20Sopenharmony_ci{
19058c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb = srb->dcb;
19068c2ecf20Sopenharmony_ci	u16 scsi_status = *pscsi_status;
19078c2ecf20Sopenharmony_ci	u32 d_left_counter = 0;
19088c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "data_out_phase0: (0x%p) <%02i-%i>\n",
19098c2ecf20Sopenharmony_ci		srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun);
19108c2ecf20Sopenharmony_ci
19118c2ecf20Sopenharmony_ci	/*
19128c2ecf20Sopenharmony_ci	 * KG: We need to drain the buffers before we draw any conclusions!
19138c2ecf20Sopenharmony_ci	 * This means telling the DMA to push the rest into SCSI, telling
19148c2ecf20Sopenharmony_ci	 * SCSI to push the rest to the bus.
19158c2ecf20Sopenharmony_ci	 * However, the device might have been the one to stop us (phase
19168c2ecf20Sopenharmony_ci	 * change), and the data in transit just needs to be accounted so
19178c2ecf20Sopenharmony_ci	 * it can be retransmitted.)
19188c2ecf20Sopenharmony_ci	 */
19198c2ecf20Sopenharmony_ci	/*
19208c2ecf20Sopenharmony_ci	 * KG: Stop DMA engine pushing more data into the SCSI FIFO
19218c2ecf20Sopenharmony_ci	 * If we need more data, the DMA SG list will be freshly set up, anyway
19228c2ecf20Sopenharmony_ci	 */
19238c2ecf20Sopenharmony_ci	dprintkdbg(DBG_PIO, "data_out_phase0: "
19248c2ecf20Sopenharmony_ci		"DMA{fifocnt=0x%02x fifostat=0x%02x} "
19258c2ecf20Sopenharmony_ci		"SCSI{fifocnt=0x%02x cnt=0x%06x status=0x%04x} total=0x%06x\n",
19268c2ecf20Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
19278c2ecf20Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
19288c2ecf20Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
19298c2ecf20Sopenharmony_ci		DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), scsi_status,
19308c2ecf20Sopenharmony_ci		srb->total_xfer_length);
19318c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_DMA_CONTROL, STOPDMAXFER | CLRXFIFO);
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_ci	if (!(srb->state & SRB_XFERPAD)) {
19348c2ecf20Sopenharmony_ci		if (scsi_status & PARITYERROR)
19358c2ecf20Sopenharmony_ci			srb->status |= PARITY_ERROR;
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_ci		/*
19388c2ecf20Sopenharmony_ci		 * KG: Right, we can't just rely on the SCSI_COUNTER, because this
19398c2ecf20Sopenharmony_ci		 * is the no of bytes it got from the DMA engine not the no it
19408c2ecf20Sopenharmony_ci		 * transferred successfully to the device. (And the difference could
19418c2ecf20Sopenharmony_ci		 * be as much as the FIFO size, I guess ...)
19428c2ecf20Sopenharmony_ci		 */
19438c2ecf20Sopenharmony_ci		if (!(scsi_status & SCSIXFERDONE)) {
19448c2ecf20Sopenharmony_ci			/*
19458c2ecf20Sopenharmony_ci			 * when data transfer from DMA FIFO to SCSI FIFO
19468c2ecf20Sopenharmony_ci			 * if there was some data left in SCSI FIFO
19478c2ecf20Sopenharmony_ci			 */
19488c2ecf20Sopenharmony_ci			d_left_counter =
19498c2ecf20Sopenharmony_ci			    (u32)(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) &
19508c2ecf20Sopenharmony_ci				  0x1F);
19518c2ecf20Sopenharmony_ci			if (dcb->sync_period & WIDE_SYNC)
19528c2ecf20Sopenharmony_ci				d_left_counter <<= 1;
19538c2ecf20Sopenharmony_ci
19548c2ecf20Sopenharmony_ci			dprintkdbg(DBG_KG, "data_out_phase0: FIFO contains %i %s\n"
19558c2ecf20Sopenharmony_ci				"SCSI{fifocnt=0x%02x cnt=0x%08x} "
19568c2ecf20Sopenharmony_ci				"DMA{fifocnt=0x%04x cnt=0x%02x ctr=0x%08x}\n",
19578c2ecf20Sopenharmony_ci				DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
19588c2ecf20Sopenharmony_ci				(dcb->sync_period & WIDE_SYNC) ? "words" : "bytes",
19598c2ecf20Sopenharmony_ci				DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
19608c2ecf20Sopenharmony_ci				DC395x_read32(acb, TRM_S1040_SCSI_COUNTER),
19618c2ecf20Sopenharmony_ci				DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
19628c2ecf20Sopenharmony_ci				DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
19638c2ecf20Sopenharmony_ci				DC395x_read32(acb, TRM_S1040_DMA_CXCNT));
19648c2ecf20Sopenharmony_ci		}
19658c2ecf20Sopenharmony_ci		/*
19668c2ecf20Sopenharmony_ci		 * calculate all the residue data that not yet tranfered
19678c2ecf20Sopenharmony_ci		 * SCSI transfer counter + left in SCSI FIFO data
19688c2ecf20Sopenharmony_ci		 *
19698c2ecf20Sopenharmony_ci		 * .....TRM_S1040_SCSI_COUNTER (24bits)
19708c2ecf20Sopenharmony_ci		 * The counter always decrement by one for every SCSI byte transfer.
19718c2ecf20Sopenharmony_ci		 * .....TRM_S1040_SCSI_FIFOCNT ( 5bits)
19728c2ecf20Sopenharmony_ci		 * The counter is SCSI FIFO offset counter (in units of bytes or! words)
19738c2ecf20Sopenharmony_ci		 */
19748c2ecf20Sopenharmony_ci		if (srb->total_xfer_length > DC395x_LASTPIO)
19758c2ecf20Sopenharmony_ci			d_left_counter +=
19768c2ecf20Sopenharmony_ci			    DC395x_read32(acb, TRM_S1040_SCSI_COUNTER);
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci		/* Is this a good idea? */
19798c2ecf20Sopenharmony_ci		/*clear_fifo(acb, "DOP1"); */
19808c2ecf20Sopenharmony_ci		/* KG: What is this supposed to be useful for? WIDE padding stuff? */
19818c2ecf20Sopenharmony_ci		if (d_left_counter == 1 && dcb->sync_period & WIDE_SYNC
19828c2ecf20Sopenharmony_ci		    && scsi_bufflen(srb->cmd) % 2) {
19838c2ecf20Sopenharmony_ci			d_left_counter = 0;
19848c2ecf20Sopenharmony_ci			dprintkl(KERN_INFO,
19858c2ecf20Sopenharmony_ci				"data_out_phase0: Discard 1 byte (0x%02x)\n",
19868c2ecf20Sopenharmony_ci				scsi_status);
19878c2ecf20Sopenharmony_ci		}
19888c2ecf20Sopenharmony_ci		/*
19898c2ecf20Sopenharmony_ci		 * KG: Oops again. Same thinko as above: The SCSI might have been
19908c2ecf20Sopenharmony_ci		 * faster than the DMA engine, so that it ran out of data.
19918c2ecf20Sopenharmony_ci		 * In that case, we have to do just nothing!
19928c2ecf20Sopenharmony_ci		 * But: Why the interrupt: No phase change. No XFERCNT_2_ZERO. Or?
19938c2ecf20Sopenharmony_ci		 */
19948c2ecf20Sopenharmony_ci		/*
19958c2ecf20Sopenharmony_ci		 * KG: This is nonsense: We have been WRITING data to the bus
19968c2ecf20Sopenharmony_ci		 * If the SCSI engine has no bytes left, how should the DMA engine?
19978c2ecf20Sopenharmony_ci		 */
19988c2ecf20Sopenharmony_ci		if (d_left_counter == 0) {
19998c2ecf20Sopenharmony_ci			srb->total_xfer_length = 0;
20008c2ecf20Sopenharmony_ci		} else {
20018c2ecf20Sopenharmony_ci			/*
20028c2ecf20Sopenharmony_ci			 * if transfer not yet complete
20038c2ecf20Sopenharmony_ci			 * there were some data residue in SCSI FIFO or
20048c2ecf20Sopenharmony_ci			 * SCSI transfer counter not empty
20058c2ecf20Sopenharmony_ci			 */
20068c2ecf20Sopenharmony_ci			long oldxferred =
20078c2ecf20Sopenharmony_ci			    srb->total_xfer_length - d_left_counter;
20088c2ecf20Sopenharmony_ci			const int diff =
20098c2ecf20Sopenharmony_ci			    (dcb->sync_period & WIDE_SYNC) ? 2 : 1;
20108c2ecf20Sopenharmony_ci			sg_update_list(srb, d_left_counter);
20118c2ecf20Sopenharmony_ci			/* KG: Most ugly hack! Apparently, this works around a chip bug */
20128c2ecf20Sopenharmony_ci			if ((srb->segment_x[srb->sg_index].length ==
20138c2ecf20Sopenharmony_ci			     diff && scsi_sg_count(srb->cmd))
20148c2ecf20Sopenharmony_ci			    || ((oldxferred & ~PAGE_MASK) ==
20158c2ecf20Sopenharmony_ci				(PAGE_SIZE - diff))
20168c2ecf20Sopenharmony_ci			    ) {
20178c2ecf20Sopenharmony_ci				dprintkl(KERN_INFO, "data_out_phase0: "
20188c2ecf20Sopenharmony_ci					"Work around chip bug (%i)?\n", diff);
20198c2ecf20Sopenharmony_ci				d_left_counter =
20208c2ecf20Sopenharmony_ci				    srb->total_xfer_length - diff;
20218c2ecf20Sopenharmony_ci				sg_update_list(srb, d_left_counter);
20228c2ecf20Sopenharmony_ci				/*srb->total_xfer_length -= diff; */
20238c2ecf20Sopenharmony_ci				/*srb->virt_addr += diff; */
20248c2ecf20Sopenharmony_ci				/*if (srb->cmd->use_sg) */
20258c2ecf20Sopenharmony_ci				/*      srb->sg_index++; */
20268c2ecf20Sopenharmony_ci			}
20278c2ecf20Sopenharmony_ci		}
20288c2ecf20Sopenharmony_ci	}
20298c2ecf20Sopenharmony_ci	if ((*pscsi_status & PHASEMASK) != PH_DATA_OUT) {
20308c2ecf20Sopenharmony_ci		cleanup_after_transfer(acb, srb);
20318c2ecf20Sopenharmony_ci	}
20328c2ecf20Sopenharmony_ci}
20338c2ecf20Sopenharmony_ci
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_cistatic void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
20368c2ecf20Sopenharmony_ci		u16 *pscsi_status)
20378c2ecf20Sopenharmony_ci{
20388c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "data_out_phase1: (0x%p) <%02i-%i>\n",
20398c2ecf20Sopenharmony_ci		srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun);
20408c2ecf20Sopenharmony_ci	clear_fifo(acb, "data_out_phase1");
20418c2ecf20Sopenharmony_ci	/* do prepare before transfer when data out phase */
20428c2ecf20Sopenharmony_ci	data_io_transfer(acb, srb, XFERDATAOUT);
20438c2ecf20Sopenharmony_ci}
20448c2ecf20Sopenharmony_ci
20458c2ecf20Sopenharmony_cistatic void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
20468c2ecf20Sopenharmony_ci		u16 *pscsi_status)
20478c2ecf20Sopenharmony_ci{
20488c2ecf20Sopenharmony_ci	u16 scsi_status = *pscsi_status;
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "data_in_phase0: (0x%p) <%02i-%i>\n",
20518c2ecf20Sopenharmony_ci		srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun);
20528c2ecf20Sopenharmony_ci
20538c2ecf20Sopenharmony_ci	/*
20548c2ecf20Sopenharmony_ci	 * KG: DataIn is much more tricky than DataOut. When the device is finished
20558c2ecf20Sopenharmony_ci	 * and switches to another phase, the SCSI engine should be finished too.
20568c2ecf20Sopenharmony_ci	 * But: There might still be bytes left in its FIFO to be fetched by the DMA
20578c2ecf20Sopenharmony_ci	 * engine and transferred to memory.
20588c2ecf20Sopenharmony_ci	 * We should wait for the FIFOs to be emptied by that (is there any way to
20598c2ecf20Sopenharmony_ci	 * enforce this?) and then stop the DMA engine, because it might think, that
20608c2ecf20Sopenharmony_ci	 * there are more bytes to follow. Yes, the device might disconnect prior to
20618c2ecf20Sopenharmony_ci	 * having all bytes transferred!
20628c2ecf20Sopenharmony_ci	 * Also we should make sure that all data from the DMA engine buffer's really
20638c2ecf20Sopenharmony_ci	 * made its way to the system memory! Some documentation on this would not
20648c2ecf20Sopenharmony_ci	 * seem to be a bad idea, actually.
20658c2ecf20Sopenharmony_ci	 */
20668c2ecf20Sopenharmony_ci	if (!(srb->state & SRB_XFERPAD)) {
20678c2ecf20Sopenharmony_ci		u32 d_left_counter;
20688c2ecf20Sopenharmony_ci		unsigned int sc, fc;
20698c2ecf20Sopenharmony_ci
20708c2ecf20Sopenharmony_ci		if (scsi_status & PARITYERROR) {
20718c2ecf20Sopenharmony_ci			dprintkl(KERN_INFO, "data_in_phase0: (0x%p) "
20728c2ecf20Sopenharmony_ci				"Parity Error\n", srb->cmd);
20738c2ecf20Sopenharmony_ci			srb->status |= PARITY_ERROR;
20748c2ecf20Sopenharmony_ci		}
20758c2ecf20Sopenharmony_ci		/*
20768c2ecf20Sopenharmony_ci		 * KG: We should wait for the DMA FIFO to be empty ...
20778c2ecf20Sopenharmony_ci		 * but: it would be better to wait first for the SCSI FIFO and then the
20788c2ecf20Sopenharmony_ci		 * the DMA FIFO to become empty? How do we know, that the device not already
20798c2ecf20Sopenharmony_ci		 * sent data to the FIFO in a MsgIn phase, eg.?
20808c2ecf20Sopenharmony_ci		 */
20818c2ecf20Sopenharmony_ci		if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80)) {
20828c2ecf20Sopenharmony_ci#if 0
20838c2ecf20Sopenharmony_ci			int ctr = 6000000;
20848c2ecf20Sopenharmony_ci			dprintkl(KERN_DEBUG,
20858c2ecf20Sopenharmony_ci				"DIP0: Wait for DMA FIFO to flush ...\n");
20868c2ecf20Sopenharmony_ci			/*DC395x_write8  (TRM_S1040_DMA_CONTROL, STOPDMAXFER); */
20878c2ecf20Sopenharmony_ci			/*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 7); */
20888c2ecf20Sopenharmony_ci			/*DC395x_write8  (TRM_S1040_SCSI_COMMAND, SCMD_DMA_IN); */
20898c2ecf20Sopenharmony_ci			while (!
20908c2ecf20Sopenharmony_ci			       (DC395x_read16(acb, TRM_S1040_DMA_FIFOSTAT) &
20918c2ecf20Sopenharmony_ci				0x80) && --ctr);
20928c2ecf20Sopenharmony_ci			if (ctr < 6000000 - 1)
20938c2ecf20Sopenharmony_ci				dprintkl(KERN_DEBUG
20948c2ecf20Sopenharmony_ci				       "DIP0: Had to wait for DMA ...\n");
20958c2ecf20Sopenharmony_ci			if (!ctr)
20968c2ecf20Sopenharmony_ci				dprintkl(KERN_ERR,
20978c2ecf20Sopenharmony_ci				       "Deadlock in DIP0 waiting for DMA FIFO empty!!\n");
20988c2ecf20Sopenharmony_ci			/*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 0); */
20998c2ecf20Sopenharmony_ci#endif
21008c2ecf20Sopenharmony_ci			dprintkdbg(DBG_KG, "data_in_phase0: "
21018c2ecf20Sopenharmony_ci				"DMA{fifocnt=0x%02x fifostat=0x%02x}\n",
21028c2ecf20Sopenharmony_ci				DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
21038c2ecf20Sopenharmony_ci				DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT));
21048c2ecf20Sopenharmony_ci		}
21058c2ecf20Sopenharmony_ci		/* Now: Check remainig data: The SCSI counters should tell us ... */
21068c2ecf20Sopenharmony_ci		sc = DC395x_read32(acb, TRM_S1040_SCSI_COUNTER);
21078c2ecf20Sopenharmony_ci		fc = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT);
21088c2ecf20Sopenharmony_ci		d_left_counter = sc + ((fc & 0x1f)
21098c2ecf20Sopenharmony_ci		       << ((srb->dcb->sync_period & WIDE_SYNC) ? 1 :
21108c2ecf20Sopenharmony_ci			   0));
21118c2ecf20Sopenharmony_ci		dprintkdbg(DBG_KG, "data_in_phase0: "
21128c2ecf20Sopenharmony_ci			"SCSI{fifocnt=0x%02x%s ctr=0x%08x} "
21138c2ecf20Sopenharmony_ci			"DMA{fifocnt=0x%02x fifostat=0x%02x ctr=0x%08x} "
21148c2ecf20Sopenharmony_ci			"Remain{totxfer=%i scsi_fifo+ctr=%i}\n",
21158c2ecf20Sopenharmony_ci			fc,
21168c2ecf20Sopenharmony_ci			(srb->dcb->sync_period & WIDE_SYNC) ? "words" : "bytes",
21178c2ecf20Sopenharmony_ci			sc,
21188c2ecf20Sopenharmony_ci			fc,
21198c2ecf20Sopenharmony_ci			DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
21208c2ecf20Sopenharmony_ci			DC395x_read32(acb, TRM_S1040_DMA_CXCNT),
21218c2ecf20Sopenharmony_ci			srb->total_xfer_length, d_left_counter);
21228c2ecf20Sopenharmony_ci#if DC395x_LASTPIO
21238c2ecf20Sopenharmony_ci		/* KG: Less than or equal to 4 bytes can not be transferred via DMA, it seems. */
21248c2ecf20Sopenharmony_ci		if (d_left_counter
21258c2ecf20Sopenharmony_ci		    && srb->total_xfer_length <= DC395x_LASTPIO) {
21268c2ecf20Sopenharmony_ci			size_t left_io = srb->total_xfer_length;
21278c2ecf20Sopenharmony_ci
21288c2ecf20Sopenharmony_ci			/*u32 addr = (srb->segment_x[srb->sg_index].address); */
21298c2ecf20Sopenharmony_ci			/*sg_update_list (srb, d_left_counter); */
21308c2ecf20Sopenharmony_ci			dprintkdbg(DBG_PIO, "data_in_phase0: PIO (%i %s) "
21318c2ecf20Sopenharmony_ci				   "for remaining %i bytes:",
21328c2ecf20Sopenharmony_ci				fc & 0x1f,
21338c2ecf20Sopenharmony_ci				(srb->dcb->sync_period & WIDE_SYNC) ?
21348c2ecf20Sopenharmony_ci				    "words" : "bytes",
21358c2ecf20Sopenharmony_ci				srb->total_xfer_length);
21368c2ecf20Sopenharmony_ci			if (srb->dcb->sync_period & WIDE_SYNC)
21378c2ecf20Sopenharmony_ci				DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2,
21388c2ecf20Sopenharmony_ci					      CFG2_WIDEFIFO);
21398c2ecf20Sopenharmony_ci			while (left_io) {
21408c2ecf20Sopenharmony_ci				unsigned char *virt, *base = NULL;
21418c2ecf20Sopenharmony_ci				unsigned long flags = 0;
21428c2ecf20Sopenharmony_ci				size_t len = left_io;
21438c2ecf20Sopenharmony_ci				size_t offset = srb->request_length - left_io;
21448c2ecf20Sopenharmony_ci
21458c2ecf20Sopenharmony_ci				local_irq_save(flags);
21468c2ecf20Sopenharmony_ci				/* Assumption: it's inside one page as it's at most 4 bytes and
21478c2ecf20Sopenharmony_ci				   I just assume it's on a 4-byte boundary */
21488c2ecf20Sopenharmony_ci				base = scsi_kmap_atomic_sg(scsi_sglist(srb->cmd),
21498c2ecf20Sopenharmony_ci							   srb->sg_count, &offset, &len);
21508c2ecf20Sopenharmony_ci				virt = base + offset;
21518c2ecf20Sopenharmony_ci
21528c2ecf20Sopenharmony_ci				left_io -= len;
21538c2ecf20Sopenharmony_ci
21548c2ecf20Sopenharmony_ci				while (len) {
21558c2ecf20Sopenharmony_ci					u8 byte;
21568c2ecf20Sopenharmony_ci					byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
21578c2ecf20Sopenharmony_ci					*virt++ = byte;
21588c2ecf20Sopenharmony_ci
21598c2ecf20Sopenharmony_ci					if (debug_enabled(DBG_PIO))
21608c2ecf20Sopenharmony_ci						printk(" %02x", byte);
21618c2ecf20Sopenharmony_ci
21628c2ecf20Sopenharmony_ci					d_left_counter--;
21638c2ecf20Sopenharmony_ci					sg_subtract_one(srb);
21648c2ecf20Sopenharmony_ci
21658c2ecf20Sopenharmony_ci					len--;
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_ci					fc = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT);
21688c2ecf20Sopenharmony_ci
21698c2ecf20Sopenharmony_ci					if (fc == 0x40) {
21708c2ecf20Sopenharmony_ci						left_io = 0;
21718c2ecf20Sopenharmony_ci						break;
21728c2ecf20Sopenharmony_ci					}
21738c2ecf20Sopenharmony_ci				}
21748c2ecf20Sopenharmony_ci
21758c2ecf20Sopenharmony_ci				WARN_ON((fc != 0x40) == !d_left_counter);
21768c2ecf20Sopenharmony_ci
21778c2ecf20Sopenharmony_ci				if (fc == 0x40 && (srb->dcb->sync_period & WIDE_SYNC)) {
21788c2ecf20Sopenharmony_ci					/* Read the last byte ... */
21798c2ecf20Sopenharmony_ci					if (srb->total_xfer_length > 0) {
21808c2ecf20Sopenharmony_ci						u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
21818c2ecf20Sopenharmony_ci
21828c2ecf20Sopenharmony_ci						*virt++ = byte;
21838c2ecf20Sopenharmony_ci						srb->total_xfer_length--;
21848c2ecf20Sopenharmony_ci						if (debug_enabled(DBG_PIO))
21858c2ecf20Sopenharmony_ci							printk(" %02x", byte);
21868c2ecf20Sopenharmony_ci					}
21878c2ecf20Sopenharmony_ci
21888c2ecf20Sopenharmony_ci					DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0);
21898c2ecf20Sopenharmony_ci				}
21908c2ecf20Sopenharmony_ci
21918c2ecf20Sopenharmony_ci				scsi_kunmap_atomic_sg(base);
21928c2ecf20Sopenharmony_ci				local_irq_restore(flags);
21938c2ecf20Sopenharmony_ci			}
21948c2ecf20Sopenharmony_ci			/*printk(" %08x", *(u32*)(bus_to_virt (addr))); */
21958c2ecf20Sopenharmony_ci			/*srb->total_xfer_length = 0; */
21968c2ecf20Sopenharmony_ci			if (debug_enabled(DBG_PIO))
21978c2ecf20Sopenharmony_ci				printk("\n");
21988c2ecf20Sopenharmony_ci		}
21998c2ecf20Sopenharmony_ci#endif				/* DC395x_LASTPIO */
22008c2ecf20Sopenharmony_ci
22018c2ecf20Sopenharmony_ci#if 0
22028c2ecf20Sopenharmony_ci		/*
22038c2ecf20Sopenharmony_ci		 * KG: This was in DATAOUT. Does it also belong here?
22048c2ecf20Sopenharmony_ci		 * Nobody seems to know what counter and fifo_cnt count exactly ...
22058c2ecf20Sopenharmony_ci		 */
22068c2ecf20Sopenharmony_ci		if (!(scsi_status & SCSIXFERDONE)) {
22078c2ecf20Sopenharmony_ci			/*
22088c2ecf20Sopenharmony_ci			 * when data transfer from DMA FIFO to SCSI FIFO
22098c2ecf20Sopenharmony_ci			 * if there was some data left in SCSI FIFO
22108c2ecf20Sopenharmony_ci			 */
22118c2ecf20Sopenharmony_ci			d_left_counter =
22128c2ecf20Sopenharmony_ci			    (u32)(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) &
22138c2ecf20Sopenharmony_ci				  0x1F);
22148c2ecf20Sopenharmony_ci			if (srb->dcb->sync_period & WIDE_SYNC)
22158c2ecf20Sopenharmony_ci				d_left_counter <<= 1;
22168c2ecf20Sopenharmony_ci			/*
22178c2ecf20Sopenharmony_ci			 * if WIDE scsi SCSI FIFOCNT unit is word !!!
22188c2ecf20Sopenharmony_ci			 * so need to *= 2
22198c2ecf20Sopenharmony_ci			 * KG: Seems to be correct ...
22208c2ecf20Sopenharmony_ci			 */
22218c2ecf20Sopenharmony_ci		}
22228c2ecf20Sopenharmony_ci#endif
22238c2ecf20Sopenharmony_ci		/* KG: This should not be needed any more! */
22248c2ecf20Sopenharmony_ci		if (d_left_counter == 0
22258c2ecf20Sopenharmony_ci		    || (scsi_status & SCSIXFERCNT_2_ZERO)) {
22268c2ecf20Sopenharmony_ci#if 0
22278c2ecf20Sopenharmony_ci			int ctr = 6000000;
22288c2ecf20Sopenharmony_ci			u8 TempDMAstatus;
22298c2ecf20Sopenharmony_ci			do {
22308c2ecf20Sopenharmony_ci				TempDMAstatus =
22318c2ecf20Sopenharmony_ci				    DC395x_read8(acb, TRM_S1040_DMA_STATUS);
22328c2ecf20Sopenharmony_ci			} while (!(TempDMAstatus & DMAXFERCOMP) && --ctr);
22338c2ecf20Sopenharmony_ci			if (!ctr)
22348c2ecf20Sopenharmony_ci				dprintkl(KERN_ERR,
22358c2ecf20Sopenharmony_ci				       "Deadlock in DataInPhase0 waiting for DMA!!\n");
22368c2ecf20Sopenharmony_ci			srb->total_xfer_length = 0;
22378c2ecf20Sopenharmony_ci#endif
22388c2ecf20Sopenharmony_ci			srb->total_xfer_length = d_left_counter;
22398c2ecf20Sopenharmony_ci		} else {	/* phase changed */
22408c2ecf20Sopenharmony_ci			/*
22418c2ecf20Sopenharmony_ci			 * parsing the case:
22428c2ecf20Sopenharmony_ci			 * when a transfer not yet complete
22438c2ecf20Sopenharmony_ci			 * but be disconnected by target
22448c2ecf20Sopenharmony_ci			 * if transfer not yet complete
22458c2ecf20Sopenharmony_ci			 * there were some data residue in SCSI FIFO or
22468c2ecf20Sopenharmony_ci			 * SCSI transfer counter not empty
22478c2ecf20Sopenharmony_ci			 */
22488c2ecf20Sopenharmony_ci			sg_update_list(srb, d_left_counter);
22498c2ecf20Sopenharmony_ci		}
22508c2ecf20Sopenharmony_ci	}
22518c2ecf20Sopenharmony_ci	/* KG: The target may decide to disconnect: Empty FIFO before! */
22528c2ecf20Sopenharmony_ci	if ((*pscsi_status & PHASEMASK) != PH_DATA_IN) {
22538c2ecf20Sopenharmony_ci		cleanup_after_transfer(acb, srb);
22548c2ecf20Sopenharmony_ci	}
22558c2ecf20Sopenharmony_ci}
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_ci
22588c2ecf20Sopenharmony_cistatic void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
22598c2ecf20Sopenharmony_ci		u16 *pscsi_status)
22608c2ecf20Sopenharmony_ci{
22618c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "data_in_phase1: (0x%p) <%02i-%i>\n",
22628c2ecf20Sopenharmony_ci		srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun);
22638c2ecf20Sopenharmony_ci	data_io_transfer(acb, srb, XFERDATAIN);
22648c2ecf20Sopenharmony_ci}
22658c2ecf20Sopenharmony_ci
22668c2ecf20Sopenharmony_ci
22678c2ecf20Sopenharmony_cistatic void data_io_transfer(struct AdapterCtlBlk *acb,
22688c2ecf20Sopenharmony_ci		struct ScsiReqBlk *srb, u16 io_dir)
22698c2ecf20Sopenharmony_ci{
22708c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb = srb->dcb;
22718c2ecf20Sopenharmony_ci	u8 bval;
22728c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0,
22738c2ecf20Sopenharmony_ci		"data_io_transfer: (0x%p) <%02i-%i> %c len=%i, sg=(%i/%i)\n",
22748c2ecf20Sopenharmony_ci		srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun,
22758c2ecf20Sopenharmony_ci		((io_dir & DMACMD_DIR) ? 'r' : 'w'),
22768c2ecf20Sopenharmony_ci		srb->total_xfer_length, srb->sg_index, srb->sg_count);
22778c2ecf20Sopenharmony_ci	if (srb == acb->tmp_srb)
22788c2ecf20Sopenharmony_ci		dprintkl(KERN_ERR, "data_io_transfer: Using tmp_srb!\n");
22798c2ecf20Sopenharmony_ci	if (srb->sg_index >= srb->sg_count) {
22808c2ecf20Sopenharmony_ci		/* can't happen? out of bounds error */
22818c2ecf20Sopenharmony_ci		return;
22828c2ecf20Sopenharmony_ci	}
22838c2ecf20Sopenharmony_ci
22848c2ecf20Sopenharmony_ci	if (srb->total_xfer_length > DC395x_LASTPIO) {
22858c2ecf20Sopenharmony_ci		u8 dma_status = DC395x_read8(acb, TRM_S1040_DMA_STATUS);
22868c2ecf20Sopenharmony_ci		/*
22878c2ecf20Sopenharmony_ci		 * KG: What should we do: Use SCSI Cmd 0x90/0x92?
22888c2ecf20Sopenharmony_ci		 * Maybe, even ABORTXFER would be appropriate
22898c2ecf20Sopenharmony_ci		 */
22908c2ecf20Sopenharmony_ci		if (dma_status & XFERPENDING) {
22918c2ecf20Sopenharmony_ci			dprintkl(KERN_DEBUG, "data_io_transfer: Xfer pending! "
22928c2ecf20Sopenharmony_ci				"Expect trouble!\n");
22938c2ecf20Sopenharmony_ci			dump_register_info(acb, dcb, srb);
22948c2ecf20Sopenharmony_ci			DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO);
22958c2ecf20Sopenharmony_ci		}
22968c2ecf20Sopenharmony_ci		/* clear_fifo(acb, "IO"); */
22978c2ecf20Sopenharmony_ci		/*
22988c2ecf20Sopenharmony_ci		 * load what physical address of Scatter/Gather list table
22998c2ecf20Sopenharmony_ci		 * want to be transfer
23008c2ecf20Sopenharmony_ci		 */
23018c2ecf20Sopenharmony_ci		srb->state |= SRB_DATA_XFER;
23028c2ecf20Sopenharmony_ci		DC395x_write32(acb, TRM_S1040_DMA_XHIGHADDR, 0);
23038c2ecf20Sopenharmony_ci		if (scsi_sg_count(srb->cmd)) {	/* with S/G */
23048c2ecf20Sopenharmony_ci			io_dir |= DMACMD_SG;
23058c2ecf20Sopenharmony_ci			DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR,
23068c2ecf20Sopenharmony_ci				       srb->sg_bus_addr +
23078c2ecf20Sopenharmony_ci				       sizeof(struct SGentry) *
23088c2ecf20Sopenharmony_ci				       srb->sg_index);
23098c2ecf20Sopenharmony_ci			/* load how many bytes in the sg list table */
23108c2ecf20Sopenharmony_ci			DC395x_write32(acb, TRM_S1040_DMA_XCNT,
23118c2ecf20Sopenharmony_ci				       ((u32)(srb->sg_count -
23128c2ecf20Sopenharmony_ci					      srb->sg_index) << 3));
23138c2ecf20Sopenharmony_ci		} else {	/* without S/G */
23148c2ecf20Sopenharmony_ci			io_dir &= ~DMACMD_SG;
23158c2ecf20Sopenharmony_ci			DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR,
23168c2ecf20Sopenharmony_ci				       srb->segment_x[0].address);
23178c2ecf20Sopenharmony_ci			DC395x_write32(acb, TRM_S1040_DMA_XCNT,
23188c2ecf20Sopenharmony_ci				       srb->segment_x[0].length);
23198c2ecf20Sopenharmony_ci		}
23208c2ecf20Sopenharmony_ci		/* load total transfer length (24bits) max value 16Mbyte */
23218c2ecf20Sopenharmony_ci		DC395x_write32(acb, TRM_S1040_SCSI_COUNTER,
23228c2ecf20Sopenharmony_ci			       srb->total_xfer_length);
23238c2ecf20Sopenharmony_ci		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
23248c2ecf20Sopenharmony_ci		if (io_dir & DMACMD_DIR) {	/* read */
23258c2ecf20Sopenharmony_ci			DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
23268c2ecf20Sopenharmony_ci				      SCMD_DMA_IN);
23278c2ecf20Sopenharmony_ci			DC395x_write16(acb, TRM_S1040_DMA_COMMAND, io_dir);
23288c2ecf20Sopenharmony_ci		} else {
23298c2ecf20Sopenharmony_ci			DC395x_write16(acb, TRM_S1040_DMA_COMMAND, io_dir);
23308c2ecf20Sopenharmony_ci			DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
23318c2ecf20Sopenharmony_ci				      SCMD_DMA_OUT);
23328c2ecf20Sopenharmony_ci		}
23338c2ecf20Sopenharmony_ci
23348c2ecf20Sopenharmony_ci	}
23358c2ecf20Sopenharmony_ci#if DC395x_LASTPIO
23368c2ecf20Sopenharmony_ci	else if (srb->total_xfer_length > 0) {	/* The last four bytes: Do PIO */
23378c2ecf20Sopenharmony_ci		/*
23388c2ecf20Sopenharmony_ci		 * load what physical address of Scatter/Gather list table
23398c2ecf20Sopenharmony_ci		 * want to be transfer
23408c2ecf20Sopenharmony_ci		 */
23418c2ecf20Sopenharmony_ci		srb->state |= SRB_DATA_XFER;
23428c2ecf20Sopenharmony_ci		/* load total transfer length (24bits) max value 16Mbyte */
23438c2ecf20Sopenharmony_ci		DC395x_write32(acb, TRM_S1040_SCSI_COUNTER,
23448c2ecf20Sopenharmony_ci			       srb->total_xfer_length);
23458c2ecf20Sopenharmony_ci		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
23468c2ecf20Sopenharmony_ci		if (io_dir & DMACMD_DIR) {	/* read */
23478c2ecf20Sopenharmony_ci			DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
23488c2ecf20Sopenharmony_ci				      SCMD_FIFO_IN);
23498c2ecf20Sopenharmony_ci		} else {	/* write */
23508c2ecf20Sopenharmony_ci			int ln = srb->total_xfer_length;
23518c2ecf20Sopenharmony_ci			size_t left_io = srb->total_xfer_length;
23528c2ecf20Sopenharmony_ci
23538c2ecf20Sopenharmony_ci			if (srb->dcb->sync_period & WIDE_SYNC)
23548c2ecf20Sopenharmony_ci				DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2,
23558c2ecf20Sopenharmony_ci				     CFG2_WIDEFIFO);
23568c2ecf20Sopenharmony_ci
23578c2ecf20Sopenharmony_ci			while (left_io) {
23588c2ecf20Sopenharmony_ci				unsigned char *virt, *base = NULL;
23598c2ecf20Sopenharmony_ci				unsigned long flags = 0;
23608c2ecf20Sopenharmony_ci				size_t len = left_io;
23618c2ecf20Sopenharmony_ci				size_t offset = srb->request_length - left_io;
23628c2ecf20Sopenharmony_ci
23638c2ecf20Sopenharmony_ci				local_irq_save(flags);
23648c2ecf20Sopenharmony_ci				/* Again, max 4 bytes */
23658c2ecf20Sopenharmony_ci				base = scsi_kmap_atomic_sg(scsi_sglist(srb->cmd),
23668c2ecf20Sopenharmony_ci							   srb->sg_count, &offset, &len);
23678c2ecf20Sopenharmony_ci				virt = base + offset;
23688c2ecf20Sopenharmony_ci
23698c2ecf20Sopenharmony_ci				left_io -= len;
23708c2ecf20Sopenharmony_ci
23718c2ecf20Sopenharmony_ci				while (len--) {
23728c2ecf20Sopenharmony_ci					if (debug_enabled(DBG_PIO))
23738c2ecf20Sopenharmony_ci						printk(" %02x", *virt);
23748c2ecf20Sopenharmony_ci
23758c2ecf20Sopenharmony_ci					DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *virt++);
23768c2ecf20Sopenharmony_ci
23778c2ecf20Sopenharmony_ci					sg_subtract_one(srb);
23788c2ecf20Sopenharmony_ci				}
23798c2ecf20Sopenharmony_ci
23808c2ecf20Sopenharmony_ci				scsi_kunmap_atomic_sg(base);
23818c2ecf20Sopenharmony_ci				local_irq_restore(flags);
23828c2ecf20Sopenharmony_ci			}
23838c2ecf20Sopenharmony_ci			if (srb->dcb->sync_period & WIDE_SYNC) {
23848c2ecf20Sopenharmony_ci				if (ln % 2) {
23858c2ecf20Sopenharmony_ci					DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
23868c2ecf20Sopenharmony_ci					if (debug_enabled(DBG_PIO))
23878c2ecf20Sopenharmony_ci						printk(" |00");
23888c2ecf20Sopenharmony_ci				}
23898c2ecf20Sopenharmony_ci				DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0);
23908c2ecf20Sopenharmony_ci			}
23918c2ecf20Sopenharmony_ci			/*DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, ln); */
23928c2ecf20Sopenharmony_ci			if (debug_enabled(DBG_PIO))
23938c2ecf20Sopenharmony_ci				printk("\n");
23948c2ecf20Sopenharmony_ci			DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
23958c2ecf20Sopenharmony_ci					  SCMD_FIFO_OUT);
23968c2ecf20Sopenharmony_ci		}
23978c2ecf20Sopenharmony_ci	}
23988c2ecf20Sopenharmony_ci#endif				/* DC395x_LASTPIO */
23998c2ecf20Sopenharmony_ci	else {		/* xfer pad */
24008c2ecf20Sopenharmony_ci		u8 data = 0, data2 = 0;
24018c2ecf20Sopenharmony_ci		if (srb->sg_count) {
24028c2ecf20Sopenharmony_ci			srb->adapter_status = H_OVER_UNDER_RUN;
24038c2ecf20Sopenharmony_ci			srb->status |= OVER_RUN;
24048c2ecf20Sopenharmony_ci		}
24058c2ecf20Sopenharmony_ci		/*
24068c2ecf20Sopenharmony_ci		 * KG: despite the fact that we are using 16 bits I/O ops
24078c2ecf20Sopenharmony_ci		 * the SCSI FIFO is only 8 bits according to the docs
24088c2ecf20Sopenharmony_ci		 * (we can set bit 1 in 0x8f to serialize FIFO access ...)
24098c2ecf20Sopenharmony_ci		 */
24108c2ecf20Sopenharmony_ci		if (dcb->sync_period & WIDE_SYNC) {
24118c2ecf20Sopenharmony_ci			DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 2);
24128c2ecf20Sopenharmony_ci			DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2,
24138c2ecf20Sopenharmony_ci				      CFG2_WIDEFIFO);
24148c2ecf20Sopenharmony_ci			if (io_dir & DMACMD_DIR) {
24158c2ecf20Sopenharmony_ci				data = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
24168c2ecf20Sopenharmony_ci				data2 = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
24178c2ecf20Sopenharmony_ci			} else {
24188c2ecf20Sopenharmony_ci				/* Danger, Robinson: If you find KGs
24198c2ecf20Sopenharmony_ci				 * scattered over the wide disk, the driver
24208c2ecf20Sopenharmony_ci				 * or chip is to blame :-( */
24218c2ecf20Sopenharmony_ci				DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'K');
24228c2ecf20Sopenharmony_ci				DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'G');
24238c2ecf20Sopenharmony_ci			}
24248c2ecf20Sopenharmony_ci			DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0);
24258c2ecf20Sopenharmony_ci		} else {
24268c2ecf20Sopenharmony_ci			DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1);
24278c2ecf20Sopenharmony_ci			/* Danger, Robinson: If you find a collection of Ks on your disk
24288c2ecf20Sopenharmony_ci			 * something broke :-( */
24298c2ecf20Sopenharmony_ci			if (io_dir & DMACMD_DIR)
24308c2ecf20Sopenharmony_ci				data = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
24318c2ecf20Sopenharmony_ci			else
24328c2ecf20Sopenharmony_ci				DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'K');
24338c2ecf20Sopenharmony_ci		}
24348c2ecf20Sopenharmony_ci		srb->state |= SRB_XFERPAD;
24358c2ecf20Sopenharmony_ci		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
24368c2ecf20Sopenharmony_ci		/* SCSI command */
24378c2ecf20Sopenharmony_ci		bval = (io_dir & DMACMD_DIR) ? SCMD_FIFO_IN : SCMD_FIFO_OUT;
24388c2ecf20Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, bval);
24398c2ecf20Sopenharmony_ci	}
24408c2ecf20Sopenharmony_ci}
24418c2ecf20Sopenharmony_ci
24428c2ecf20Sopenharmony_ci
24438c2ecf20Sopenharmony_cistatic void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
24448c2ecf20Sopenharmony_ci		u16 *pscsi_status)
24458c2ecf20Sopenharmony_ci{
24468c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "status_phase0: (0x%p) <%02i-%i>\n",
24478c2ecf20Sopenharmony_ci		srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun);
24488c2ecf20Sopenharmony_ci	srb->target_status = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
24498c2ecf20Sopenharmony_ci	srb->end_message = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);	/* get message */
24508c2ecf20Sopenharmony_ci	srb->state = SRB_COMPLETED;
24518c2ecf20Sopenharmony_ci	*pscsi_status = PH_BUS_FREE;	/*.. initial phase */
24528c2ecf20Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
24538c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT);
24548c2ecf20Sopenharmony_ci}
24558c2ecf20Sopenharmony_ci
24568c2ecf20Sopenharmony_ci
24578c2ecf20Sopenharmony_cistatic void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
24588c2ecf20Sopenharmony_ci		u16 *pscsi_status)
24598c2ecf20Sopenharmony_ci{
24608c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "status_phase1: (0x%p) <%02i-%i>\n",
24618c2ecf20Sopenharmony_ci		srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun);
24628c2ecf20Sopenharmony_ci	srb->state = SRB_STATUS;
24638c2ecf20Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
24648c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_COMP);
24658c2ecf20Sopenharmony_ci}
24668c2ecf20Sopenharmony_ci
24678c2ecf20Sopenharmony_ci
24688c2ecf20Sopenharmony_ci/* Check if the message is complete */
24698c2ecf20Sopenharmony_cistatic inline u8 msgin_completed(u8 * msgbuf, u32 len)
24708c2ecf20Sopenharmony_ci{
24718c2ecf20Sopenharmony_ci	if (*msgbuf == EXTENDED_MESSAGE) {
24728c2ecf20Sopenharmony_ci		if (len < 2)
24738c2ecf20Sopenharmony_ci			return 0;
24748c2ecf20Sopenharmony_ci		if (len < msgbuf[1] + 2)
24758c2ecf20Sopenharmony_ci			return 0;
24768c2ecf20Sopenharmony_ci	} else if (*msgbuf >= 0x20 && *msgbuf <= 0x2f)	/* two byte messages */
24778c2ecf20Sopenharmony_ci		if (len < 2)
24788c2ecf20Sopenharmony_ci			return 0;
24798c2ecf20Sopenharmony_ci	return 1;
24808c2ecf20Sopenharmony_ci}
24818c2ecf20Sopenharmony_ci
24828c2ecf20Sopenharmony_ci/* reject_msg */
24838c2ecf20Sopenharmony_cistatic inline void msgin_reject(struct AdapterCtlBlk *acb,
24848c2ecf20Sopenharmony_ci		struct ScsiReqBlk *srb)
24858c2ecf20Sopenharmony_ci{
24868c2ecf20Sopenharmony_ci	srb->msgout_buf[0] = MESSAGE_REJECT;
24878c2ecf20Sopenharmony_ci	srb->msg_count = 1;
24888c2ecf20Sopenharmony_ci	DC395x_ENABLE_MSGOUT;
24898c2ecf20Sopenharmony_ci	srb->state &= ~SRB_MSGIN;
24908c2ecf20Sopenharmony_ci	srb->state |= SRB_MSGOUT;
24918c2ecf20Sopenharmony_ci	dprintkl(KERN_INFO, "msgin_reject: 0x%02x <%02i-%i>\n",
24928c2ecf20Sopenharmony_ci		srb->msgin_buf[0],
24938c2ecf20Sopenharmony_ci		srb->dcb->target_id, srb->dcb->target_lun);
24948c2ecf20Sopenharmony_ci}
24958c2ecf20Sopenharmony_ci
24968c2ecf20Sopenharmony_ci
24978c2ecf20Sopenharmony_cistatic struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb,
24988c2ecf20Sopenharmony_ci		struct DeviceCtlBlk *dcb, u8 tag)
24998c2ecf20Sopenharmony_ci{
25008c2ecf20Sopenharmony_ci	struct ScsiReqBlk *srb = NULL;
25018c2ecf20Sopenharmony_ci	struct ScsiReqBlk *i;
25028c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "msgin_qtag: (0x%p) tag=%i srb=%p\n",
25038c2ecf20Sopenharmony_ci		   srb->cmd, tag, srb);
25048c2ecf20Sopenharmony_ci
25058c2ecf20Sopenharmony_ci	if (!(dcb->tag_mask & (1 << tag)))
25068c2ecf20Sopenharmony_ci		dprintkl(KERN_DEBUG,
25078c2ecf20Sopenharmony_ci			"msgin_qtag: tag_mask=0x%08x does not reserve tag %i!\n",
25088c2ecf20Sopenharmony_ci			dcb->tag_mask, tag);
25098c2ecf20Sopenharmony_ci
25108c2ecf20Sopenharmony_ci	if (list_empty(&dcb->srb_going_list))
25118c2ecf20Sopenharmony_ci		goto mingx0;
25128c2ecf20Sopenharmony_ci	list_for_each_entry(i, &dcb->srb_going_list, list) {
25138c2ecf20Sopenharmony_ci		if (i->tag_number == tag) {
25148c2ecf20Sopenharmony_ci			srb = i;
25158c2ecf20Sopenharmony_ci			break;
25168c2ecf20Sopenharmony_ci		}
25178c2ecf20Sopenharmony_ci	}
25188c2ecf20Sopenharmony_ci	if (!srb)
25198c2ecf20Sopenharmony_ci		goto mingx0;
25208c2ecf20Sopenharmony_ci
25218c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "msgin_qtag: (0x%p) <%02i-%i>\n",
25228c2ecf20Sopenharmony_ci		srb->cmd, srb->dcb->target_id, srb->dcb->target_lun);
25238c2ecf20Sopenharmony_ci	if (dcb->flag & ABORT_DEV_) {
25248c2ecf20Sopenharmony_ci		/*srb->state = SRB_ABORT_SENT; */
25258c2ecf20Sopenharmony_ci		enable_msgout_abort(acb, srb);
25268c2ecf20Sopenharmony_ci	}
25278c2ecf20Sopenharmony_ci
25288c2ecf20Sopenharmony_ci	if (!(srb->state & SRB_DISCONNECT))
25298c2ecf20Sopenharmony_ci		goto mingx0;
25308c2ecf20Sopenharmony_ci
25318c2ecf20Sopenharmony_ci	memcpy(srb->msgin_buf, dcb->active_srb->msgin_buf, acb->msg_len);
25328c2ecf20Sopenharmony_ci	srb->state |= dcb->active_srb->state;
25338c2ecf20Sopenharmony_ci	srb->state |= SRB_DATA_XFER;
25348c2ecf20Sopenharmony_ci	dcb->active_srb = srb;
25358c2ecf20Sopenharmony_ci	/* How can we make the DORS happy? */
25368c2ecf20Sopenharmony_ci	return srb;
25378c2ecf20Sopenharmony_ci
25388c2ecf20Sopenharmony_ci      mingx0:
25398c2ecf20Sopenharmony_ci	srb = acb->tmp_srb;
25408c2ecf20Sopenharmony_ci	srb->state = SRB_UNEXPECT_RESEL;
25418c2ecf20Sopenharmony_ci	dcb->active_srb = srb;
25428c2ecf20Sopenharmony_ci	srb->msgout_buf[0] = MSG_ABORT_TAG;
25438c2ecf20Sopenharmony_ci	srb->msg_count = 1;
25448c2ecf20Sopenharmony_ci	DC395x_ENABLE_MSGOUT;
25458c2ecf20Sopenharmony_ci	dprintkl(KERN_DEBUG, "msgin_qtag: Unknown tag %i - abort\n", tag);
25468c2ecf20Sopenharmony_ci	return srb;
25478c2ecf20Sopenharmony_ci}
25488c2ecf20Sopenharmony_ci
25498c2ecf20Sopenharmony_ci
25508c2ecf20Sopenharmony_cistatic inline void reprogram_regs(struct AdapterCtlBlk *acb,
25518c2ecf20Sopenharmony_ci		struct DeviceCtlBlk *dcb)
25528c2ecf20Sopenharmony_ci{
25538c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id);
25548c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_SYNC, dcb->sync_period);
25558c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, dcb->sync_offset);
25568c2ecf20Sopenharmony_ci	set_xfer_rate(acb, dcb);
25578c2ecf20Sopenharmony_ci}
25588c2ecf20Sopenharmony_ci
25598c2ecf20Sopenharmony_ci
25608c2ecf20Sopenharmony_ci/* set async transfer mode */
25618c2ecf20Sopenharmony_cistatic void msgin_set_async(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
25628c2ecf20Sopenharmony_ci{
25638c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb = srb->dcb;
25648c2ecf20Sopenharmony_ci	dprintkl(KERN_DEBUG, "msgin_set_async: No sync transfers <%02i-%i>\n",
25658c2ecf20Sopenharmony_ci		dcb->target_id, dcb->target_lun);
25668c2ecf20Sopenharmony_ci
25678c2ecf20Sopenharmony_ci	dcb->sync_mode &= ~(SYNC_NEGO_ENABLE);
25688c2ecf20Sopenharmony_ci	dcb->sync_mode |= SYNC_NEGO_DONE;
25698c2ecf20Sopenharmony_ci	/*dcb->sync_period &= 0; */
25708c2ecf20Sopenharmony_ci	dcb->sync_offset = 0;
25718c2ecf20Sopenharmony_ci	dcb->min_nego_period = 200 >> 2;	/* 200ns <=> 5 MHz */
25728c2ecf20Sopenharmony_ci	srb->state &= ~SRB_DO_SYNC_NEGO;
25738c2ecf20Sopenharmony_ci	reprogram_regs(acb, dcb);
25748c2ecf20Sopenharmony_ci	if ((dcb->sync_mode & WIDE_NEGO_ENABLE)
25758c2ecf20Sopenharmony_ci	    && !(dcb->sync_mode & WIDE_NEGO_DONE)) {
25768c2ecf20Sopenharmony_ci		build_wdtr(acb, dcb, srb);
25778c2ecf20Sopenharmony_ci		DC395x_ENABLE_MSGOUT;
25788c2ecf20Sopenharmony_ci		dprintkdbg(DBG_0, "msgin_set_async(rej): Try WDTR anyway\n");
25798c2ecf20Sopenharmony_ci	}
25808c2ecf20Sopenharmony_ci}
25818c2ecf20Sopenharmony_ci
25828c2ecf20Sopenharmony_ci
25838c2ecf20Sopenharmony_ci/* set sync transfer mode */
25848c2ecf20Sopenharmony_cistatic void msgin_set_sync(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
25858c2ecf20Sopenharmony_ci{
25868c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb = srb->dcb;
25878c2ecf20Sopenharmony_ci	u8 bval;
25888c2ecf20Sopenharmony_ci	int fact;
25898c2ecf20Sopenharmony_ci	dprintkdbg(DBG_1, "msgin_set_sync: <%02i> Sync: %ins "
25908c2ecf20Sopenharmony_ci		"(%02i.%01i MHz) Offset %i\n",
25918c2ecf20Sopenharmony_ci		dcb->target_id, srb->msgin_buf[3] << 2,
25928c2ecf20Sopenharmony_ci		(250 / srb->msgin_buf[3]),
25938c2ecf20Sopenharmony_ci		((250 % srb->msgin_buf[3]) * 10) / srb->msgin_buf[3],
25948c2ecf20Sopenharmony_ci		srb->msgin_buf[4]);
25958c2ecf20Sopenharmony_ci
25968c2ecf20Sopenharmony_ci	if (srb->msgin_buf[4] > 15)
25978c2ecf20Sopenharmony_ci		srb->msgin_buf[4] = 15;
25988c2ecf20Sopenharmony_ci	if (!(dcb->dev_mode & NTC_DO_SYNC_NEGO))
25998c2ecf20Sopenharmony_ci		dcb->sync_offset = 0;
26008c2ecf20Sopenharmony_ci	else if (dcb->sync_offset == 0)
26018c2ecf20Sopenharmony_ci		dcb->sync_offset = srb->msgin_buf[4];
26028c2ecf20Sopenharmony_ci	if (srb->msgin_buf[4] > dcb->sync_offset)
26038c2ecf20Sopenharmony_ci		srb->msgin_buf[4] = dcb->sync_offset;
26048c2ecf20Sopenharmony_ci	else
26058c2ecf20Sopenharmony_ci		dcb->sync_offset = srb->msgin_buf[4];
26068c2ecf20Sopenharmony_ci	bval = 0;
26078c2ecf20Sopenharmony_ci	while (bval < 7 && (srb->msgin_buf[3] > clock_period[bval]
26088c2ecf20Sopenharmony_ci			    || dcb->min_nego_period >
26098c2ecf20Sopenharmony_ci			    clock_period[bval]))
26108c2ecf20Sopenharmony_ci		bval++;
26118c2ecf20Sopenharmony_ci	if (srb->msgin_buf[3] < clock_period[bval])
26128c2ecf20Sopenharmony_ci		dprintkl(KERN_INFO,
26138c2ecf20Sopenharmony_ci			"msgin_set_sync: Increase sync nego period to %ins\n",
26148c2ecf20Sopenharmony_ci			clock_period[bval] << 2);
26158c2ecf20Sopenharmony_ci	srb->msgin_buf[3] = clock_period[bval];
26168c2ecf20Sopenharmony_ci	dcb->sync_period &= 0xf0;
26178c2ecf20Sopenharmony_ci	dcb->sync_period |= ALT_SYNC | bval;
26188c2ecf20Sopenharmony_ci	dcb->min_nego_period = srb->msgin_buf[3];
26198c2ecf20Sopenharmony_ci
26208c2ecf20Sopenharmony_ci	if (dcb->sync_period & WIDE_SYNC)
26218c2ecf20Sopenharmony_ci		fact = 500;
26228c2ecf20Sopenharmony_ci	else
26238c2ecf20Sopenharmony_ci		fact = 250;
26248c2ecf20Sopenharmony_ci
26258c2ecf20Sopenharmony_ci	dprintkl(KERN_INFO,
26268c2ecf20Sopenharmony_ci		"Target %02i: %s Sync: %ins Offset %i (%02i.%01i MB/s)\n",
26278c2ecf20Sopenharmony_ci		dcb->target_id, (fact == 500) ? "Wide16" : "",
26288c2ecf20Sopenharmony_ci		dcb->min_nego_period << 2, dcb->sync_offset,
26298c2ecf20Sopenharmony_ci		(fact / dcb->min_nego_period),
26308c2ecf20Sopenharmony_ci		((fact % dcb->min_nego_period) * 10 +
26318c2ecf20Sopenharmony_ci		dcb->min_nego_period / 2) / dcb->min_nego_period);
26328c2ecf20Sopenharmony_ci
26338c2ecf20Sopenharmony_ci	if (!(srb->state & SRB_DO_SYNC_NEGO)) {
26348c2ecf20Sopenharmony_ci		/* Reply with corrected SDTR Message */
26358c2ecf20Sopenharmony_ci		dprintkl(KERN_DEBUG, "msgin_set_sync: answer w/%ins %i\n",
26368c2ecf20Sopenharmony_ci			srb->msgin_buf[3] << 2, srb->msgin_buf[4]);
26378c2ecf20Sopenharmony_ci
26388c2ecf20Sopenharmony_ci		memcpy(srb->msgout_buf, srb->msgin_buf, 5);
26398c2ecf20Sopenharmony_ci		srb->msg_count = 5;
26408c2ecf20Sopenharmony_ci		DC395x_ENABLE_MSGOUT;
26418c2ecf20Sopenharmony_ci		dcb->sync_mode |= SYNC_NEGO_DONE;
26428c2ecf20Sopenharmony_ci	} else {
26438c2ecf20Sopenharmony_ci		if ((dcb->sync_mode & WIDE_NEGO_ENABLE)
26448c2ecf20Sopenharmony_ci		    && !(dcb->sync_mode & WIDE_NEGO_DONE)) {
26458c2ecf20Sopenharmony_ci			build_wdtr(acb, dcb, srb);
26468c2ecf20Sopenharmony_ci			DC395x_ENABLE_MSGOUT;
26478c2ecf20Sopenharmony_ci			dprintkdbg(DBG_0, "msgin_set_sync: Also try WDTR\n");
26488c2ecf20Sopenharmony_ci		}
26498c2ecf20Sopenharmony_ci	}
26508c2ecf20Sopenharmony_ci	srb->state &= ~SRB_DO_SYNC_NEGO;
26518c2ecf20Sopenharmony_ci	dcb->sync_mode |= SYNC_NEGO_DONE | SYNC_NEGO_ENABLE;
26528c2ecf20Sopenharmony_ci
26538c2ecf20Sopenharmony_ci	reprogram_regs(acb, dcb);
26548c2ecf20Sopenharmony_ci}
26558c2ecf20Sopenharmony_ci
26568c2ecf20Sopenharmony_ci
26578c2ecf20Sopenharmony_cistatic inline void msgin_set_nowide(struct AdapterCtlBlk *acb,
26588c2ecf20Sopenharmony_ci		struct ScsiReqBlk *srb)
26598c2ecf20Sopenharmony_ci{
26608c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb = srb->dcb;
26618c2ecf20Sopenharmony_ci	dprintkdbg(DBG_1, "msgin_set_nowide: <%02i>\n", dcb->target_id);
26628c2ecf20Sopenharmony_ci
26638c2ecf20Sopenharmony_ci	dcb->sync_period &= ~WIDE_SYNC;
26648c2ecf20Sopenharmony_ci	dcb->sync_mode &= ~(WIDE_NEGO_ENABLE);
26658c2ecf20Sopenharmony_ci	dcb->sync_mode |= WIDE_NEGO_DONE;
26668c2ecf20Sopenharmony_ci	srb->state &= ~SRB_DO_WIDE_NEGO;
26678c2ecf20Sopenharmony_ci	reprogram_regs(acb, dcb);
26688c2ecf20Sopenharmony_ci	if ((dcb->sync_mode & SYNC_NEGO_ENABLE)
26698c2ecf20Sopenharmony_ci	    && !(dcb->sync_mode & SYNC_NEGO_DONE)) {
26708c2ecf20Sopenharmony_ci		build_sdtr(acb, dcb, srb);
26718c2ecf20Sopenharmony_ci		DC395x_ENABLE_MSGOUT;
26728c2ecf20Sopenharmony_ci		dprintkdbg(DBG_0, "msgin_set_nowide: Rejected. Try SDTR anyway\n");
26738c2ecf20Sopenharmony_ci	}
26748c2ecf20Sopenharmony_ci}
26758c2ecf20Sopenharmony_ci
26768c2ecf20Sopenharmony_cistatic void msgin_set_wide(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
26778c2ecf20Sopenharmony_ci{
26788c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb = srb->dcb;
26798c2ecf20Sopenharmony_ci	u8 wide = (dcb->dev_mode & NTC_DO_WIDE_NEGO
26808c2ecf20Sopenharmony_ci		   && acb->config & HCC_WIDE_CARD) ? 1 : 0;
26818c2ecf20Sopenharmony_ci	dprintkdbg(DBG_1, "msgin_set_wide: <%02i>\n", dcb->target_id);
26828c2ecf20Sopenharmony_ci
26838c2ecf20Sopenharmony_ci	if (srb->msgin_buf[3] > wide)
26848c2ecf20Sopenharmony_ci		srb->msgin_buf[3] = wide;
26858c2ecf20Sopenharmony_ci	/* Completed */
26868c2ecf20Sopenharmony_ci	if (!(srb->state & SRB_DO_WIDE_NEGO)) {
26878c2ecf20Sopenharmony_ci		dprintkl(KERN_DEBUG,
26888c2ecf20Sopenharmony_ci			"msgin_set_wide: Wide nego initiated <%02i>\n",
26898c2ecf20Sopenharmony_ci			dcb->target_id);
26908c2ecf20Sopenharmony_ci		memcpy(srb->msgout_buf, srb->msgin_buf, 4);
26918c2ecf20Sopenharmony_ci		srb->msg_count = 4;
26928c2ecf20Sopenharmony_ci		srb->state |= SRB_DO_WIDE_NEGO;
26938c2ecf20Sopenharmony_ci		DC395x_ENABLE_MSGOUT;
26948c2ecf20Sopenharmony_ci	}
26958c2ecf20Sopenharmony_ci
26968c2ecf20Sopenharmony_ci	dcb->sync_mode |= (WIDE_NEGO_ENABLE | WIDE_NEGO_DONE);
26978c2ecf20Sopenharmony_ci	if (srb->msgin_buf[3] > 0)
26988c2ecf20Sopenharmony_ci		dcb->sync_period |= WIDE_SYNC;
26998c2ecf20Sopenharmony_ci	else
27008c2ecf20Sopenharmony_ci		dcb->sync_period &= ~WIDE_SYNC;
27018c2ecf20Sopenharmony_ci	srb->state &= ~SRB_DO_WIDE_NEGO;
27028c2ecf20Sopenharmony_ci	/*dcb->sync_mode &= ~(WIDE_NEGO_ENABLE+WIDE_NEGO_DONE); */
27038c2ecf20Sopenharmony_ci	dprintkdbg(DBG_1,
27048c2ecf20Sopenharmony_ci		"msgin_set_wide: Wide (%i bit) negotiated <%02i>\n",
27058c2ecf20Sopenharmony_ci		(8 << srb->msgin_buf[3]), dcb->target_id);
27068c2ecf20Sopenharmony_ci	reprogram_regs(acb, dcb);
27078c2ecf20Sopenharmony_ci	if ((dcb->sync_mode & SYNC_NEGO_ENABLE)
27088c2ecf20Sopenharmony_ci	    && !(dcb->sync_mode & SYNC_NEGO_DONE)) {
27098c2ecf20Sopenharmony_ci		build_sdtr(acb, dcb, srb);
27108c2ecf20Sopenharmony_ci		DC395x_ENABLE_MSGOUT;
27118c2ecf20Sopenharmony_ci		dprintkdbg(DBG_0, "msgin_set_wide: Also try SDTR.\n");
27128c2ecf20Sopenharmony_ci	}
27138c2ecf20Sopenharmony_ci}
27148c2ecf20Sopenharmony_ci
27158c2ecf20Sopenharmony_ci
27168c2ecf20Sopenharmony_ci/*
27178c2ecf20Sopenharmony_ci * extended message codes:
27188c2ecf20Sopenharmony_ci *
27198c2ecf20Sopenharmony_ci *	code	description
27208c2ecf20Sopenharmony_ci *
27218c2ecf20Sopenharmony_ci *	02h	Reserved
27228c2ecf20Sopenharmony_ci *	00h	MODIFY DATA  POINTER
27238c2ecf20Sopenharmony_ci *	01h	SYNCHRONOUS DATA TRANSFER REQUEST
27248c2ecf20Sopenharmony_ci *	03h	WIDE DATA TRANSFER REQUEST
27258c2ecf20Sopenharmony_ci *   04h - 7Fh	Reserved
27268c2ecf20Sopenharmony_ci *   80h - FFh	Vendor specific
27278c2ecf20Sopenharmony_ci */
27288c2ecf20Sopenharmony_cistatic void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
27298c2ecf20Sopenharmony_ci		u16 *pscsi_status)
27308c2ecf20Sopenharmony_ci{
27318c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb = acb->active_dcb;
27328c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "msgin_phase0: (0x%p)\n", srb->cmd);
27338c2ecf20Sopenharmony_ci
27348c2ecf20Sopenharmony_ci	srb->msgin_buf[acb->msg_len++] = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
27358c2ecf20Sopenharmony_ci	if (msgin_completed(srb->msgin_buf, acb->msg_len)) {
27368c2ecf20Sopenharmony_ci		/* Now eval the msg */
27378c2ecf20Sopenharmony_ci		switch (srb->msgin_buf[0]) {
27388c2ecf20Sopenharmony_ci		case DISCONNECT:
27398c2ecf20Sopenharmony_ci			srb->state = SRB_DISCONNECT;
27408c2ecf20Sopenharmony_ci			break;
27418c2ecf20Sopenharmony_ci
27428c2ecf20Sopenharmony_ci		case SIMPLE_QUEUE_TAG:
27438c2ecf20Sopenharmony_ci		case HEAD_OF_QUEUE_TAG:
27448c2ecf20Sopenharmony_ci		case ORDERED_QUEUE_TAG:
27458c2ecf20Sopenharmony_ci			srb =
27468c2ecf20Sopenharmony_ci			    msgin_qtag(acb, dcb,
27478c2ecf20Sopenharmony_ci					      srb->msgin_buf[1]);
27488c2ecf20Sopenharmony_ci			break;
27498c2ecf20Sopenharmony_ci
27508c2ecf20Sopenharmony_ci		case MESSAGE_REJECT:
27518c2ecf20Sopenharmony_ci			DC395x_write16(acb, TRM_S1040_SCSI_CONTROL,
27528c2ecf20Sopenharmony_ci				       DO_CLRATN | DO_DATALATCH);
27538c2ecf20Sopenharmony_ci			/* A sync nego message was rejected ! */
27548c2ecf20Sopenharmony_ci			if (srb->state & SRB_DO_SYNC_NEGO) {
27558c2ecf20Sopenharmony_ci				msgin_set_async(acb, srb);
27568c2ecf20Sopenharmony_ci				break;
27578c2ecf20Sopenharmony_ci			}
27588c2ecf20Sopenharmony_ci			/* A wide nego message was rejected ! */
27598c2ecf20Sopenharmony_ci			if (srb->state & SRB_DO_WIDE_NEGO) {
27608c2ecf20Sopenharmony_ci				msgin_set_nowide(acb, srb);
27618c2ecf20Sopenharmony_ci				break;
27628c2ecf20Sopenharmony_ci			}
27638c2ecf20Sopenharmony_ci			enable_msgout_abort(acb, srb);
27648c2ecf20Sopenharmony_ci			/*srb->state |= SRB_ABORT_SENT */
27658c2ecf20Sopenharmony_ci			break;
27668c2ecf20Sopenharmony_ci
27678c2ecf20Sopenharmony_ci		case EXTENDED_MESSAGE:
27688c2ecf20Sopenharmony_ci			/* SDTR */
27698c2ecf20Sopenharmony_ci			if (srb->msgin_buf[1] == 3
27708c2ecf20Sopenharmony_ci			    && srb->msgin_buf[2] == EXTENDED_SDTR) {
27718c2ecf20Sopenharmony_ci				msgin_set_sync(acb, srb);
27728c2ecf20Sopenharmony_ci				break;
27738c2ecf20Sopenharmony_ci			}
27748c2ecf20Sopenharmony_ci			/* WDTR */
27758c2ecf20Sopenharmony_ci			if (srb->msgin_buf[1] == 2
27768c2ecf20Sopenharmony_ci			    && srb->msgin_buf[2] == EXTENDED_WDTR
27778c2ecf20Sopenharmony_ci			    && srb->msgin_buf[3] <= 2) { /* sanity check ... */
27788c2ecf20Sopenharmony_ci				msgin_set_wide(acb, srb);
27798c2ecf20Sopenharmony_ci				break;
27808c2ecf20Sopenharmony_ci			}
27818c2ecf20Sopenharmony_ci			msgin_reject(acb, srb);
27828c2ecf20Sopenharmony_ci			break;
27838c2ecf20Sopenharmony_ci
27848c2ecf20Sopenharmony_ci		case MSG_IGNOREWIDE:
27858c2ecf20Sopenharmony_ci			/* Discard  wide residual */
27868c2ecf20Sopenharmony_ci			dprintkdbg(DBG_0, "msgin_phase0: Ignore Wide Residual!\n");
27878c2ecf20Sopenharmony_ci			break;
27888c2ecf20Sopenharmony_ci
27898c2ecf20Sopenharmony_ci		case COMMAND_COMPLETE:
27908c2ecf20Sopenharmony_ci			/* nothing has to be done */
27918c2ecf20Sopenharmony_ci			break;
27928c2ecf20Sopenharmony_ci
27938c2ecf20Sopenharmony_ci		case SAVE_POINTERS:
27948c2ecf20Sopenharmony_ci			/*
27958c2ecf20Sopenharmony_ci			 * SAVE POINTER may be ignored as we have the struct
27968c2ecf20Sopenharmony_ci			 * ScsiReqBlk* associated with the scsi command.
27978c2ecf20Sopenharmony_ci			 */
27988c2ecf20Sopenharmony_ci			dprintkdbg(DBG_0, "msgin_phase0: (0x%p) "
27998c2ecf20Sopenharmony_ci				"SAVE POINTER rem=%i Ignore\n",
28008c2ecf20Sopenharmony_ci				srb->cmd, srb->total_xfer_length);
28018c2ecf20Sopenharmony_ci			break;
28028c2ecf20Sopenharmony_ci
28038c2ecf20Sopenharmony_ci		case RESTORE_POINTERS:
28048c2ecf20Sopenharmony_ci			dprintkdbg(DBG_0, "msgin_phase0: RESTORE POINTER. Ignore\n");
28058c2ecf20Sopenharmony_ci			break;
28068c2ecf20Sopenharmony_ci
28078c2ecf20Sopenharmony_ci		case ABORT:
28088c2ecf20Sopenharmony_ci			dprintkdbg(DBG_0, "msgin_phase0: (0x%p) "
28098c2ecf20Sopenharmony_ci				"<%02i-%i> ABORT msg\n",
28108c2ecf20Sopenharmony_ci				srb->cmd, dcb->target_id,
28118c2ecf20Sopenharmony_ci				dcb->target_lun);
28128c2ecf20Sopenharmony_ci			dcb->flag |= ABORT_DEV_;
28138c2ecf20Sopenharmony_ci			enable_msgout_abort(acb, srb);
28148c2ecf20Sopenharmony_ci			break;
28158c2ecf20Sopenharmony_ci
28168c2ecf20Sopenharmony_ci		default:
28178c2ecf20Sopenharmony_ci			/* reject unknown messages */
28188c2ecf20Sopenharmony_ci			if (srb->msgin_buf[0] & IDENTIFY_BASE) {
28198c2ecf20Sopenharmony_ci				dprintkdbg(DBG_0, "msgin_phase0: Identify msg\n");
28208c2ecf20Sopenharmony_ci				srb->msg_count = 1;
28218c2ecf20Sopenharmony_ci				srb->msgout_buf[0] = dcb->identify_msg;
28228c2ecf20Sopenharmony_ci				DC395x_ENABLE_MSGOUT;
28238c2ecf20Sopenharmony_ci				srb->state |= SRB_MSGOUT;
28248c2ecf20Sopenharmony_ci				/*break; */
28258c2ecf20Sopenharmony_ci			}
28268c2ecf20Sopenharmony_ci			msgin_reject(acb, srb);
28278c2ecf20Sopenharmony_ci		}
28288c2ecf20Sopenharmony_ci
28298c2ecf20Sopenharmony_ci		/* Clear counter and MsgIn state */
28308c2ecf20Sopenharmony_ci		srb->state &= ~SRB_MSGIN;
28318c2ecf20Sopenharmony_ci		acb->msg_len = 0;
28328c2ecf20Sopenharmony_ci	}
28338c2ecf20Sopenharmony_ci	*pscsi_status = PH_BUS_FREE;
28348c2ecf20Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important ... you know! */
28358c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT);
28368c2ecf20Sopenharmony_ci}
28378c2ecf20Sopenharmony_ci
28388c2ecf20Sopenharmony_ci
28398c2ecf20Sopenharmony_cistatic void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
28408c2ecf20Sopenharmony_ci		u16 *pscsi_status)
28418c2ecf20Sopenharmony_ci{
28428c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "msgin_phase1: (0x%p)\n", srb->cmd);
28438c2ecf20Sopenharmony_ci	clear_fifo(acb, "msgin_phase1");
28448c2ecf20Sopenharmony_ci	DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1);
28458c2ecf20Sopenharmony_ci	if (!(srb->state & SRB_MSGIN)) {
28468c2ecf20Sopenharmony_ci		srb->state &= ~SRB_DISCONNECT;
28478c2ecf20Sopenharmony_ci		srb->state |= SRB_MSGIN;
28488c2ecf20Sopenharmony_ci	}
28498c2ecf20Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
28508c2ecf20Sopenharmony_ci	/* SCSI command */
28518c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_IN);
28528c2ecf20Sopenharmony_ci}
28538c2ecf20Sopenharmony_ci
28548c2ecf20Sopenharmony_ci
28558c2ecf20Sopenharmony_cistatic void nop0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
28568c2ecf20Sopenharmony_ci		u16 *pscsi_status)
28578c2ecf20Sopenharmony_ci{
28588c2ecf20Sopenharmony_ci}
28598c2ecf20Sopenharmony_ci
28608c2ecf20Sopenharmony_ci
28618c2ecf20Sopenharmony_cistatic void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
28628c2ecf20Sopenharmony_ci		u16 *pscsi_status)
28638c2ecf20Sopenharmony_ci{
28648c2ecf20Sopenharmony_ci}
28658c2ecf20Sopenharmony_ci
28668c2ecf20Sopenharmony_ci
28678c2ecf20Sopenharmony_cistatic void set_xfer_rate(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb)
28688c2ecf20Sopenharmony_ci{
28698c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *i;
28708c2ecf20Sopenharmony_ci
28718c2ecf20Sopenharmony_ci	/* set all lun device's  period, offset */
28728c2ecf20Sopenharmony_ci	if (dcb->identify_msg & 0x07)
28738c2ecf20Sopenharmony_ci		return;
28748c2ecf20Sopenharmony_ci
28758c2ecf20Sopenharmony_ci	if (acb->scan_devices) {
28768c2ecf20Sopenharmony_ci		current_sync_offset = dcb->sync_offset;
28778c2ecf20Sopenharmony_ci		return;
28788c2ecf20Sopenharmony_ci	}
28798c2ecf20Sopenharmony_ci
28808c2ecf20Sopenharmony_ci	list_for_each_entry(i, &acb->dcb_list, list)
28818c2ecf20Sopenharmony_ci		if (i->target_id == dcb->target_id) {
28828c2ecf20Sopenharmony_ci			i->sync_period = dcb->sync_period;
28838c2ecf20Sopenharmony_ci			i->sync_offset = dcb->sync_offset;
28848c2ecf20Sopenharmony_ci			i->sync_mode = dcb->sync_mode;
28858c2ecf20Sopenharmony_ci			i->min_nego_period = dcb->min_nego_period;
28868c2ecf20Sopenharmony_ci		}
28878c2ecf20Sopenharmony_ci}
28888c2ecf20Sopenharmony_ci
28898c2ecf20Sopenharmony_ci
28908c2ecf20Sopenharmony_cistatic void disconnect(struct AdapterCtlBlk *acb)
28918c2ecf20Sopenharmony_ci{
28928c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb = acb->active_dcb;
28938c2ecf20Sopenharmony_ci	struct ScsiReqBlk *srb;
28948c2ecf20Sopenharmony_ci
28958c2ecf20Sopenharmony_ci	if (!dcb) {
28968c2ecf20Sopenharmony_ci		dprintkl(KERN_ERR, "disconnect: No such device\n");
28978c2ecf20Sopenharmony_ci		udelay(500);
28988c2ecf20Sopenharmony_ci		/* Suspend queue for a while */
28998c2ecf20Sopenharmony_ci		acb->last_reset =
29008c2ecf20Sopenharmony_ci		    jiffies + HZ / 2 +
29018c2ecf20Sopenharmony_ci		    HZ * acb->eeprom.delay_time;
29028c2ecf20Sopenharmony_ci		clear_fifo(acb, "disconnectEx");
29038c2ecf20Sopenharmony_ci		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT);
29048c2ecf20Sopenharmony_ci		return;
29058c2ecf20Sopenharmony_ci	}
29068c2ecf20Sopenharmony_ci	srb = dcb->active_srb;
29078c2ecf20Sopenharmony_ci	acb->active_dcb = NULL;
29088c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "disconnect: (0x%p)\n", srb->cmd);
29098c2ecf20Sopenharmony_ci
29108c2ecf20Sopenharmony_ci	srb->scsi_phase = PH_BUS_FREE;	/* initial phase */
29118c2ecf20Sopenharmony_ci	clear_fifo(acb, "disconnect");
29128c2ecf20Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT);
29138c2ecf20Sopenharmony_ci	if (srb->state & SRB_UNEXPECT_RESEL) {
29148c2ecf20Sopenharmony_ci		dprintkl(KERN_ERR,
29158c2ecf20Sopenharmony_ci			"disconnect: Unexpected reselection <%02i-%i>\n",
29168c2ecf20Sopenharmony_ci			dcb->target_id, dcb->target_lun);
29178c2ecf20Sopenharmony_ci		srb->state = 0;
29188c2ecf20Sopenharmony_ci		waiting_process_next(acb);
29198c2ecf20Sopenharmony_ci	} else if (srb->state & SRB_ABORT_SENT) {
29208c2ecf20Sopenharmony_ci		dcb->flag &= ~ABORT_DEV_;
29218c2ecf20Sopenharmony_ci		acb->last_reset = jiffies + HZ / 2 + 1;
29228c2ecf20Sopenharmony_ci		dprintkl(KERN_ERR, "disconnect: SRB_ABORT_SENT\n");
29238c2ecf20Sopenharmony_ci		doing_srb_done(acb, DID_ABORT, srb->cmd, 1);
29248c2ecf20Sopenharmony_ci		waiting_process_next(acb);
29258c2ecf20Sopenharmony_ci	} else {
29268c2ecf20Sopenharmony_ci		if ((srb->state & (SRB_START_ + SRB_MSGOUT))
29278c2ecf20Sopenharmony_ci		    || !(srb->
29288c2ecf20Sopenharmony_ci			 state & (SRB_DISCONNECT + SRB_COMPLETED))) {
29298c2ecf20Sopenharmony_ci			/*
29308c2ecf20Sopenharmony_ci			 * Selection time out
29318c2ecf20Sopenharmony_ci			 * SRB_START_ || SRB_MSGOUT || (!SRB_DISCONNECT && !SRB_COMPLETED)
29328c2ecf20Sopenharmony_ci			 */
29338c2ecf20Sopenharmony_ci			/* Unexp. Disc / Sel Timeout */
29348c2ecf20Sopenharmony_ci			if (srb->state != SRB_START_
29358c2ecf20Sopenharmony_ci			    && srb->state != SRB_MSGOUT) {
29368c2ecf20Sopenharmony_ci				srb->state = SRB_READY;
29378c2ecf20Sopenharmony_ci				dprintkl(KERN_DEBUG,
29388c2ecf20Sopenharmony_ci					"disconnect: (0x%p) Unexpected\n",
29398c2ecf20Sopenharmony_ci					srb->cmd);
29408c2ecf20Sopenharmony_ci				srb->target_status = SCSI_STAT_SEL_TIMEOUT;
29418c2ecf20Sopenharmony_ci				goto disc1;
29428c2ecf20Sopenharmony_ci			} else {
29438c2ecf20Sopenharmony_ci				/* Normal selection timeout */
29448c2ecf20Sopenharmony_ci				dprintkdbg(DBG_KG, "disconnect: (0x%p) "
29458c2ecf20Sopenharmony_ci					"<%02i-%i> SelTO\n", srb->cmd,
29468c2ecf20Sopenharmony_ci					dcb->target_id, dcb->target_lun);
29478c2ecf20Sopenharmony_ci				if (srb->retry_count++ > DC395x_MAX_RETRIES
29488c2ecf20Sopenharmony_ci				    || acb->scan_devices) {
29498c2ecf20Sopenharmony_ci					srb->target_status =
29508c2ecf20Sopenharmony_ci					    SCSI_STAT_SEL_TIMEOUT;
29518c2ecf20Sopenharmony_ci					goto disc1;
29528c2ecf20Sopenharmony_ci				}
29538c2ecf20Sopenharmony_ci				free_tag(dcb, srb);
29548c2ecf20Sopenharmony_ci				list_move(&srb->list, &dcb->srb_waiting_list);
29558c2ecf20Sopenharmony_ci				dprintkdbg(DBG_KG,
29568c2ecf20Sopenharmony_ci					"disconnect: (0x%p) Retry\n",
29578c2ecf20Sopenharmony_ci					srb->cmd);
29588c2ecf20Sopenharmony_ci				waiting_set_timer(acb, HZ / 20);
29598c2ecf20Sopenharmony_ci			}
29608c2ecf20Sopenharmony_ci		} else if (srb->state & SRB_DISCONNECT) {
29618c2ecf20Sopenharmony_ci			u8 bval = DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL);
29628c2ecf20Sopenharmony_ci			/*
29638c2ecf20Sopenharmony_ci			 * SRB_DISCONNECT (This is what we expect!)
29648c2ecf20Sopenharmony_ci			 */
29658c2ecf20Sopenharmony_ci			if (bval & 0x40) {
29668c2ecf20Sopenharmony_ci				dprintkdbg(DBG_0, "disconnect: SCSI bus stat "
29678c2ecf20Sopenharmony_ci					" 0x%02x: ACK set! Other controllers?\n",
29688c2ecf20Sopenharmony_ci					bval);
29698c2ecf20Sopenharmony_ci				/* It could come from another initiator, therefore don't do much ! */
29708c2ecf20Sopenharmony_ci			} else
29718c2ecf20Sopenharmony_ci				waiting_process_next(acb);
29728c2ecf20Sopenharmony_ci		} else if (srb->state & SRB_COMPLETED) {
29738c2ecf20Sopenharmony_ci		      disc1:
29748c2ecf20Sopenharmony_ci			/*
29758c2ecf20Sopenharmony_ci			 ** SRB_COMPLETED
29768c2ecf20Sopenharmony_ci			 */
29778c2ecf20Sopenharmony_ci			free_tag(dcb, srb);
29788c2ecf20Sopenharmony_ci			dcb->active_srb = NULL;
29798c2ecf20Sopenharmony_ci			srb->state = SRB_FREE;
29808c2ecf20Sopenharmony_ci			srb_done(acb, dcb, srb);
29818c2ecf20Sopenharmony_ci		}
29828c2ecf20Sopenharmony_ci	}
29838c2ecf20Sopenharmony_ci}
29848c2ecf20Sopenharmony_ci
29858c2ecf20Sopenharmony_ci
29868c2ecf20Sopenharmony_cistatic void reselect(struct AdapterCtlBlk *acb)
29878c2ecf20Sopenharmony_ci{
29888c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb = acb->active_dcb;
29898c2ecf20Sopenharmony_ci	struct ScsiReqBlk *srb = NULL;
29908c2ecf20Sopenharmony_ci	u16 rsel_tar_lun_id;
29918c2ecf20Sopenharmony_ci	u8 id, lun;
29928c2ecf20Sopenharmony_ci	u8 arblostflag = 0;
29938c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "reselect: acb=%p\n", acb);
29948c2ecf20Sopenharmony_ci
29958c2ecf20Sopenharmony_ci	clear_fifo(acb, "reselect");
29968c2ecf20Sopenharmony_ci	/*DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT | DO_DATALATCH); */
29978c2ecf20Sopenharmony_ci	/* Read Reselected Target ID and LUN */
29988c2ecf20Sopenharmony_ci	rsel_tar_lun_id = DC395x_read16(acb, TRM_S1040_SCSI_TARGETID);
29998c2ecf20Sopenharmony_ci	if (dcb) {		/* Arbitration lost but Reselection win */
30008c2ecf20Sopenharmony_ci		srb = dcb->active_srb;
30018c2ecf20Sopenharmony_ci		if (!srb) {
30028c2ecf20Sopenharmony_ci			dprintkl(KERN_DEBUG, "reselect: Arb lost Resel won, "
30038c2ecf20Sopenharmony_ci				"but active_srb == NULL\n");
30048c2ecf20Sopenharmony_ci			DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
30058c2ecf20Sopenharmony_ci			return;
30068c2ecf20Sopenharmony_ci		}
30078c2ecf20Sopenharmony_ci		/* Why the if ? */
30088c2ecf20Sopenharmony_ci		if (!acb->scan_devices) {
30098c2ecf20Sopenharmony_ci			dprintkdbg(DBG_KG, "reselect: (0x%p) <%02i-%i> "
30108c2ecf20Sopenharmony_ci				"Arb lost but Resel win rsel=%i stat=0x%04x\n",
30118c2ecf20Sopenharmony_ci				srb->cmd, dcb->target_id,
30128c2ecf20Sopenharmony_ci				dcb->target_lun, rsel_tar_lun_id,
30138c2ecf20Sopenharmony_ci				DC395x_read16(acb, TRM_S1040_SCSI_STATUS));
30148c2ecf20Sopenharmony_ci			arblostflag = 1;
30158c2ecf20Sopenharmony_ci			/*srb->state |= SRB_DISCONNECT; */
30168c2ecf20Sopenharmony_ci
30178c2ecf20Sopenharmony_ci			srb->state = SRB_READY;
30188c2ecf20Sopenharmony_ci			free_tag(dcb, srb);
30198c2ecf20Sopenharmony_ci			list_move(&srb->list, &dcb->srb_waiting_list);
30208c2ecf20Sopenharmony_ci			waiting_set_timer(acb, HZ / 20);
30218c2ecf20Sopenharmony_ci
30228c2ecf20Sopenharmony_ci			/* return; */
30238c2ecf20Sopenharmony_ci		}
30248c2ecf20Sopenharmony_ci	}
30258c2ecf20Sopenharmony_ci	/* Read Reselected Target Id and LUN */
30268c2ecf20Sopenharmony_ci	if (!(rsel_tar_lun_id & (IDENTIFY_BASE << 8)))
30278c2ecf20Sopenharmony_ci		dprintkl(KERN_DEBUG, "reselect: Expects identify msg. "
30288c2ecf20Sopenharmony_ci			"Got %i!\n", rsel_tar_lun_id);
30298c2ecf20Sopenharmony_ci	id = rsel_tar_lun_id & 0xff;
30308c2ecf20Sopenharmony_ci	lun = (rsel_tar_lun_id >> 8) & 7;
30318c2ecf20Sopenharmony_ci	dcb = find_dcb(acb, id, lun);
30328c2ecf20Sopenharmony_ci	if (!dcb) {
30338c2ecf20Sopenharmony_ci		dprintkl(KERN_ERR, "reselect: From non existent device "
30348c2ecf20Sopenharmony_ci			"<%02i-%i>\n", id, lun);
30358c2ecf20Sopenharmony_ci		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
30368c2ecf20Sopenharmony_ci		return;
30378c2ecf20Sopenharmony_ci	}
30388c2ecf20Sopenharmony_ci	acb->active_dcb = dcb;
30398c2ecf20Sopenharmony_ci
30408c2ecf20Sopenharmony_ci	if (!(dcb->dev_mode & NTC_DO_DISCONNECT))
30418c2ecf20Sopenharmony_ci		dprintkl(KERN_DEBUG, "reselect: in spite of forbidden "
30428c2ecf20Sopenharmony_ci			"disconnection? <%02i-%i>\n",
30438c2ecf20Sopenharmony_ci			dcb->target_id, dcb->target_lun);
30448c2ecf20Sopenharmony_ci
30458c2ecf20Sopenharmony_ci	if (dcb->sync_mode & EN_TAG_QUEUEING /*&& !arblostflag */) {
30468c2ecf20Sopenharmony_ci		srb = acb->tmp_srb;
30478c2ecf20Sopenharmony_ci		dcb->active_srb = srb;
30488c2ecf20Sopenharmony_ci	} else {
30498c2ecf20Sopenharmony_ci		/* There can be only one! */
30508c2ecf20Sopenharmony_ci		srb = dcb->active_srb;
30518c2ecf20Sopenharmony_ci		if (!srb || !(srb->state & SRB_DISCONNECT)) {
30528c2ecf20Sopenharmony_ci			/*
30538c2ecf20Sopenharmony_ci			 * abort command
30548c2ecf20Sopenharmony_ci			 */
30558c2ecf20Sopenharmony_ci			dprintkl(KERN_DEBUG,
30568c2ecf20Sopenharmony_ci				"reselect: w/o disconnected cmds <%02i-%i>\n",
30578c2ecf20Sopenharmony_ci				dcb->target_id, dcb->target_lun);
30588c2ecf20Sopenharmony_ci			srb = acb->tmp_srb;
30598c2ecf20Sopenharmony_ci			srb->state = SRB_UNEXPECT_RESEL;
30608c2ecf20Sopenharmony_ci			dcb->active_srb = srb;
30618c2ecf20Sopenharmony_ci			enable_msgout_abort(acb, srb);
30628c2ecf20Sopenharmony_ci		} else {
30638c2ecf20Sopenharmony_ci			if (dcb->flag & ABORT_DEV_) {
30648c2ecf20Sopenharmony_ci				/*srb->state = SRB_ABORT_SENT; */
30658c2ecf20Sopenharmony_ci				enable_msgout_abort(acb, srb);
30668c2ecf20Sopenharmony_ci			} else
30678c2ecf20Sopenharmony_ci				srb->state = SRB_DATA_XFER;
30688c2ecf20Sopenharmony_ci
30698c2ecf20Sopenharmony_ci		}
30708c2ecf20Sopenharmony_ci	}
30718c2ecf20Sopenharmony_ci	srb->scsi_phase = PH_BUS_FREE;	/* initial phase */
30728c2ecf20Sopenharmony_ci
30738c2ecf20Sopenharmony_ci	/* Program HA ID, target ID, period and offset */
30748c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "reselect: select <%i>\n", dcb->target_id);
30758c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_HOSTID, acb->scsi_host->this_id);	/* host   ID */
30768c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id);		/* target ID */
30778c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, dcb->sync_offset);		/* offset    */
30788c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_SYNC, dcb->sync_period);		/* sync period, wide */
30798c2ecf20Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);		/* it's important for atn stop */
30808c2ecf20Sopenharmony_ci	/* SCSI command */
30818c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT);
30828c2ecf20Sopenharmony_ci}
30838c2ecf20Sopenharmony_ci
30848c2ecf20Sopenharmony_ci
30858c2ecf20Sopenharmony_cistatic inline u8 tagq_blacklist(char *name)
30868c2ecf20Sopenharmony_ci{
30878c2ecf20Sopenharmony_ci#ifndef DC395x_NO_TAGQ
30888c2ecf20Sopenharmony_ci#if 0
30898c2ecf20Sopenharmony_ci	u8 i;
30908c2ecf20Sopenharmony_ci	for (i = 0; i < BADDEVCNT; i++)
30918c2ecf20Sopenharmony_ci		if (memcmp(name, DC395x_baddevname1[i], 28) == 0)
30928c2ecf20Sopenharmony_ci			return 1;
30938c2ecf20Sopenharmony_ci#endif
30948c2ecf20Sopenharmony_ci	return 0;
30958c2ecf20Sopenharmony_ci#else
30968c2ecf20Sopenharmony_ci	return 1;
30978c2ecf20Sopenharmony_ci#endif
30988c2ecf20Sopenharmony_ci}
30998c2ecf20Sopenharmony_ci
31008c2ecf20Sopenharmony_ci
31018c2ecf20Sopenharmony_cistatic void disc_tagq_set(struct DeviceCtlBlk *dcb, struct ScsiInqData *ptr)
31028c2ecf20Sopenharmony_ci{
31038c2ecf20Sopenharmony_ci	/* Check for SCSI format (ANSI and Response data format) */
31048c2ecf20Sopenharmony_ci	if ((ptr->Vers & 0x07) >= 2 || (ptr->RDF & 0x0F) == 2) {
31058c2ecf20Sopenharmony_ci		if ((ptr->Flags & SCSI_INQ_CMDQUEUE)
31068c2ecf20Sopenharmony_ci		    && (dcb->dev_mode & NTC_DO_TAG_QUEUEING) &&
31078c2ecf20Sopenharmony_ci		    /*(dcb->dev_mode & NTC_DO_DISCONNECT) */
31088c2ecf20Sopenharmony_ci		    /* ((dcb->dev_type == TYPE_DISK)
31098c2ecf20Sopenharmony_ci		       || (dcb->dev_type == TYPE_MOD)) && */
31108c2ecf20Sopenharmony_ci		    !tagq_blacklist(((char *)ptr) + 8)) {
31118c2ecf20Sopenharmony_ci			if (dcb->max_command == 1)
31128c2ecf20Sopenharmony_ci				dcb->max_command =
31138c2ecf20Sopenharmony_ci				    dcb->acb->tag_max_num;
31148c2ecf20Sopenharmony_ci			dcb->sync_mode |= EN_TAG_QUEUEING;
31158c2ecf20Sopenharmony_ci			/*dcb->tag_mask = 0; */
31168c2ecf20Sopenharmony_ci		} else
31178c2ecf20Sopenharmony_ci			dcb->max_command = 1;
31188c2ecf20Sopenharmony_ci	}
31198c2ecf20Sopenharmony_ci}
31208c2ecf20Sopenharmony_ci
31218c2ecf20Sopenharmony_ci
31228c2ecf20Sopenharmony_cistatic void add_dev(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
31238c2ecf20Sopenharmony_ci		struct ScsiInqData *ptr)
31248c2ecf20Sopenharmony_ci{
31258c2ecf20Sopenharmony_ci	u8 bval1 = ptr->DevType & SCSI_DEVTYPE;
31268c2ecf20Sopenharmony_ci	dcb->dev_type = bval1;
31278c2ecf20Sopenharmony_ci	/* if (bval1 == TYPE_DISK || bval1 == TYPE_MOD) */
31288c2ecf20Sopenharmony_ci	disc_tagq_set(dcb, ptr);
31298c2ecf20Sopenharmony_ci}
31308c2ecf20Sopenharmony_ci
31318c2ecf20Sopenharmony_ci
31328c2ecf20Sopenharmony_ci/* unmap mapped pci regions from SRB */
31338c2ecf20Sopenharmony_cistatic void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
31348c2ecf20Sopenharmony_ci{
31358c2ecf20Sopenharmony_ci	struct scsi_cmnd *cmd = srb->cmd;
31368c2ecf20Sopenharmony_ci	enum dma_data_direction dir = cmd->sc_data_direction;
31378c2ecf20Sopenharmony_ci
31388c2ecf20Sopenharmony_ci	if (scsi_sg_count(cmd) && dir != DMA_NONE) {
31398c2ecf20Sopenharmony_ci		/* unmap DC395x SG list */
31408c2ecf20Sopenharmony_ci		dprintkdbg(DBG_SG, "pci_unmap_srb: list=%08x(%05x)\n",
31418c2ecf20Sopenharmony_ci			srb->sg_bus_addr, SEGMENTX_LEN);
31428c2ecf20Sopenharmony_ci		dma_unmap_single(&acb->dev->dev, srb->sg_bus_addr, SEGMENTX_LEN,
31438c2ecf20Sopenharmony_ci				DMA_TO_DEVICE);
31448c2ecf20Sopenharmony_ci		dprintkdbg(DBG_SG, "pci_unmap_srb: segs=%i buffer=%p\n",
31458c2ecf20Sopenharmony_ci			   scsi_sg_count(cmd), scsi_bufflen(cmd));
31468c2ecf20Sopenharmony_ci		/* unmap the sg segments */
31478c2ecf20Sopenharmony_ci		scsi_dma_unmap(cmd);
31488c2ecf20Sopenharmony_ci	}
31498c2ecf20Sopenharmony_ci}
31508c2ecf20Sopenharmony_ci
31518c2ecf20Sopenharmony_ci
31528c2ecf20Sopenharmony_ci/* unmap mapped pci sense buffer from SRB */
31538c2ecf20Sopenharmony_cistatic void pci_unmap_srb_sense(struct AdapterCtlBlk *acb,
31548c2ecf20Sopenharmony_ci		struct ScsiReqBlk *srb)
31558c2ecf20Sopenharmony_ci{
31568c2ecf20Sopenharmony_ci	if (!(srb->flag & AUTO_REQSENSE))
31578c2ecf20Sopenharmony_ci		return;
31588c2ecf20Sopenharmony_ci	/* Unmap sense buffer */
31598c2ecf20Sopenharmony_ci	dprintkdbg(DBG_SG, "pci_unmap_srb_sense: buffer=%08x\n",
31608c2ecf20Sopenharmony_ci	       srb->segment_x[0].address);
31618c2ecf20Sopenharmony_ci	dma_unmap_single(&acb->dev->dev, srb->segment_x[0].address,
31628c2ecf20Sopenharmony_ci			 srb->segment_x[0].length, DMA_FROM_DEVICE);
31638c2ecf20Sopenharmony_ci	/* Restore SG stuff */
31648c2ecf20Sopenharmony_ci	srb->total_xfer_length = srb->xferred;
31658c2ecf20Sopenharmony_ci	srb->segment_x[0].address =
31668c2ecf20Sopenharmony_ci	    srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].address;
31678c2ecf20Sopenharmony_ci	srb->segment_x[0].length =
31688c2ecf20Sopenharmony_ci	    srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].length;
31698c2ecf20Sopenharmony_ci}
31708c2ecf20Sopenharmony_ci
31718c2ecf20Sopenharmony_ci
31728c2ecf20Sopenharmony_ci/*
31738c2ecf20Sopenharmony_ci * Complete execution of a SCSI command
31748c2ecf20Sopenharmony_ci * Signal completion to the generic SCSI driver
31758c2ecf20Sopenharmony_ci */
31768c2ecf20Sopenharmony_cistatic void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
31778c2ecf20Sopenharmony_ci		struct ScsiReqBlk *srb)
31788c2ecf20Sopenharmony_ci{
31798c2ecf20Sopenharmony_ci	u8 tempcnt, status;
31808c2ecf20Sopenharmony_ci	struct scsi_cmnd *cmd = srb->cmd;
31818c2ecf20Sopenharmony_ci	enum dma_data_direction dir = cmd->sc_data_direction;
31828c2ecf20Sopenharmony_ci	int ckc_only = 1;
31838c2ecf20Sopenharmony_ci
31848c2ecf20Sopenharmony_ci	dprintkdbg(DBG_1, "srb_done: (0x%p) <%02i-%i>\n", srb->cmd,
31858c2ecf20Sopenharmony_ci		srb->cmd->device->id, (u8)srb->cmd->device->lun);
31868c2ecf20Sopenharmony_ci	dprintkdbg(DBG_SG, "srb_done: srb=%p sg=%i(%i/%i) buf=%p\n",
31878c2ecf20Sopenharmony_ci		   srb, scsi_sg_count(cmd), srb->sg_index, srb->sg_count,
31888c2ecf20Sopenharmony_ci		   scsi_sgtalbe(cmd));
31898c2ecf20Sopenharmony_ci	status = srb->target_status;
31908c2ecf20Sopenharmony_ci	if (srb->flag & AUTO_REQSENSE) {
31918c2ecf20Sopenharmony_ci		dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE1\n");
31928c2ecf20Sopenharmony_ci		pci_unmap_srb_sense(acb, srb);
31938c2ecf20Sopenharmony_ci		/*
31948c2ecf20Sopenharmony_ci		 ** target status..........................
31958c2ecf20Sopenharmony_ci		 */
31968c2ecf20Sopenharmony_ci		srb->flag &= ~AUTO_REQSENSE;
31978c2ecf20Sopenharmony_ci		srb->adapter_status = 0;
31988c2ecf20Sopenharmony_ci		srb->target_status = CHECK_CONDITION << 1;
31998c2ecf20Sopenharmony_ci		if (debug_enabled(DBG_1)) {
32008c2ecf20Sopenharmony_ci			switch (cmd->sense_buffer[2] & 0x0f) {
32018c2ecf20Sopenharmony_ci			case NOT_READY:
32028c2ecf20Sopenharmony_ci				dprintkl(KERN_DEBUG,
32038c2ecf20Sopenharmony_ci				     "ReqSense: NOT_READY cmnd=0x%02x <%02i-%i> stat=%i scan=%i ",
32048c2ecf20Sopenharmony_ci				     cmd->cmnd[0], dcb->target_id,
32058c2ecf20Sopenharmony_ci				     dcb->target_lun, status, acb->scan_devices);
32068c2ecf20Sopenharmony_ci				break;
32078c2ecf20Sopenharmony_ci			case UNIT_ATTENTION:
32088c2ecf20Sopenharmony_ci				dprintkl(KERN_DEBUG,
32098c2ecf20Sopenharmony_ci				     "ReqSense: UNIT_ATTENTION cmnd=0x%02x <%02i-%i> stat=%i scan=%i ",
32108c2ecf20Sopenharmony_ci				     cmd->cmnd[0], dcb->target_id,
32118c2ecf20Sopenharmony_ci				     dcb->target_lun, status, acb->scan_devices);
32128c2ecf20Sopenharmony_ci				break;
32138c2ecf20Sopenharmony_ci			case ILLEGAL_REQUEST:
32148c2ecf20Sopenharmony_ci				dprintkl(KERN_DEBUG,
32158c2ecf20Sopenharmony_ci				     "ReqSense: ILLEGAL_REQUEST cmnd=0x%02x <%02i-%i> stat=%i scan=%i ",
32168c2ecf20Sopenharmony_ci				     cmd->cmnd[0], dcb->target_id,
32178c2ecf20Sopenharmony_ci				     dcb->target_lun, status, acb->scan_devices);
32188c2ecf20Sopenharmony_ci				break;
32198c2ecf20Sopenharmony_ci			case MEDIUM_ERROR:
32208c2ecf20Sopenharmony_ci				dprintkl(KERN_DEBUG,
32218c2ecf20Sopenharmony_ci				     "ReqSense: MEDIUM_ERROR cmnd=0x%02x <%02i-%i> stat=%i scan=%i ",
32228c2ecf20Sopenharmony_ci				     cmd->cmnd[0], dcb->target_id,
32238c2ecf20Sopenharmony_ci				     dcb->target_lun, status, acb->scan_devices);
32248c2ecf20Sopenharmony_ci				break;
32258c2ecf20Sopenharmony_ci			case HARDWARE_ERROR:
32268c2ecf20Sopenharmony_ci				dprintkl(KERN_DEBUG,
32278c2ecf20Sopenharmony_ci				     "ReqSense: HARDWARE_ERROR cmnd=0x%02x <%02i-%i> stat=%i scan=%i ",
32288c2ecf20Sopenharmony_ci				     cmd->cmnd[0], dcb->target_id,
32298c2ecf20Sopenharmony_ci				     dcb->target_lun, status, acb->scan_devices);
32308c2ecf20Sopenharmony_ci				break;
32318c2ecf20Sopenharmony_ci			}
32328c2ecf20Sopenharmony_ci			if (cmd->sense_buffer[7] >= 6)
32338c2ecf20Sopenharmony_ci				printk("sense=0x%02x ASC=0x%02x ASCQ=0x%02x "
32348c2ecf20Sopenharmony_ci					"(0x%08x 0x%08x)\n",
32358c2ecf20Sopenharmony_ci					cmd->sense_buffer[2], cmd->sense_buffer[12],
32368c2ecf20Sopenharmony_ci					cmd->sense_buffer[13],
32378c2ecf20Sopenharmony_ci					*((unsigned int *)(cmd->sense_buffer + 3)),
32388c2ecf20Sopenharmony_ci					*((unsigned int *)(cmd->sense_buffer + 8)));
32398c2ecf20Sopenharmony_ci			else
32408c2ecf20Sopenharmony_ci				printk("sense=0x%02x No ASC/ASCQ (0x%08x)\n",
32418c2ecf20Sopenharmony_ci					cmd->sense_buffer[2],
32428c2ecf20Sopenharmony_ci					*((unsigned int *)(cmd->sense_buffer + 3)));
32438c2ecf20Sopenharmony_ci		}
32448c2ecf20Sopenharmony_ci
32458c2ecf20Sopenharmony_ci		if (status == (CHECK_CONDITION << 1)) {
32468c2ecf20Sopenharmony_ci			cmd->result = DID_BAD_TARGET << 16;
32478c2ecf20Sopenharmony_ci			goto ckc_e;
32488c2ecf20Sopenharmony_ci		}
32498c2ecf20Sopenharmony_ci		dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE2\n");
32508c2ecf20Sopenharmony_ci
32518c2ecf20Sopenharmony_ci		if (srb->total_xfer_length
32528c2ecf20Sopenharmony_ci		    && srb->total_xfer_length >= cmd->underflow)
32538c2ecf20Sopenharmony_ci			cmd->result =
32548c2ecf20Sopenharmony_ci			    MK_RES_LNX(DRIVER_SENSE, DID_OK,
32558c2ecf20Sopenharmony_ci				       srb->end_message, CHECK_CONDITION);
32568c2ecf20Sopenharmony_ci		/*SET_RES_DID(cmd->result,DID_OK) */
32578c2ecf20Sopenharmony_ci		else
32588c2ecf20Sopenharmony_ci			cmd->result =
32598c2ecf20Sopenharmony_ci			    MK_RES_LNX(DRIVER_SENSE, DID_OK,
32608c2ecf20Sopenharmony_ci				       srb->end_message, CHECK_CONDITION);
32618c2ecf20Sopenharmony_ci
32628c2ecf20Sopenharmony_ci		goto ckc_e;
32638c2ecf20Sopenharmony_ci	}
32648c2ecf20Sopenharmony_ci
32658c2ecf20Sopenharmony_ci/*************************************************************/
32668c2ecf20Sopenharmony_ci	if (status) {
32678c2ecf20Sopenharmony_ci		/*
32688c2ecf20Sopenharmony_ci		 * target status..........................
32698c2ecf20Sopenharmony_ci		 */
32708c2ecf20Sopenharmony_ci		if (status_byte(status) == CHECK_CONDITION) {
32718c2ecf20Sopenharmony_ci			request_sense(acb, dcb, srb);
32728c2ecf20Sopenharmony_ci			return;
32738c2ecf20Sopenharmony_ci		} else if (status_byte(status) == QUEUE_FULL) {
32748c2ecf20Sopenharmony_ci			tempcnt = (u8)list_size(&dcb->srb_going_list);
32758c2ecf20Sopenharmony_ci			dprintkl(KERN_INFO, "QUEUE_FULL for dev <%02i-%i> with %i cmnds\n",
32768c2ecf20Sopenharmony_ci			     dcb->target_id, dcb->target_lun, tempcnt);
32778c2ecf20Sopenharmony_ci			if (tempcnt > 1)
32788c2ecf20Sopenharmony_ci				tempcnt--;
32798c2ecf20Sopenharmony_ci			dcb->max_command = tempcnt;
32808c2ecf20Sopenharmony_ci			free_tag(dcb, srb);
32818c2ecf20Sopenharmony_ci			list_move(&srb->list, &dcb->srb_waiting_list);
32828c2ecf20Sopenharmony_ci			waiting_set_timer(acb, HZ / 20);
32838c2ecf20Sopenharmony_ci			srb->adapter_status = 0;
32848c2ecf20Sopenharmony_ci			srb->target_status = 0;
32858c2ecf20Sopenharmony_ci			return;
32868c2ecf20Sopenharmony_ci		} else if (status == SCSI_STAT_SEL_TIMEOUT) {
32878c2ecf20Sopenharmony_ci			srb->adapter_status = H_SEL_TIMEOUT;
32888c2ecf20Sopenharmony_ci			srb->target_status = 0;
32898c2ecf20Sopenharmony_ci			cmd->result = DID_NO_CONNECT << 16;
32908c2ecf20Sopenharmony_ci		} else {
32918c2ecf20Sopenharmony_ci			srb->adapter_status = 0;
32928c2ecf20Sopenharmony_ci			SET_RES_DID(cmd->result, DID_ERROR);
32938c2ecf20Sopenharmony_ci			SET_RES_MSG(cmd->result, srb->end_message);
32948c2ecf20Sopenharmony_ci			SET_RES_TARGET(cmd->result, status);
32958c2ecf20Sopenharmony_ci
32968c2ecf20Sopenharmony_ci		}
32978c2ecf20Sopenharmony_ci	} else {
32988c2ecf20Sopenharmony_ci		/*
32998c2ecf20Sopenharmony_ci		 ** process initiator status..........................
33008c2ecf20Sopenharmony_ci		 */
33018c2ecf20Sopenharmony_ci		status = srb->adapter_status;
33028c2ecf20Sopenharmony_ci		if (status & H_OVER_UNDER_RUN) {
33038c2ecf20Sopenharmony_ci			srb->target_status = 0;
33048c2ecf20Sopenharmony_ci			SET_RES_DID(cmd->result, DID_OK);
33058c2ecf20Sopenharmony_ci			SET_RES_MSG(cmd->result, srb->end_message);
33068c2ecf20Sopenharmony_ci		} else if (srb->status & PARITY_ERROR) {
33078c2ecf20Sopenharmony_ci			SET_RES_DID(cmd->result, DID_PARITY);
33088c2ecf20Sopenharmony_ci			SET_RES_MSG(cmd->result, srb->end_message);
33098c2ecf20Sopenharmony_ci		} else {	/* No error */
33108c2ecf20Sopenharmony_ci
33118c2ecf20Sopenharmony_ci			srb->adapter_status = 0;
33128c2ecf20Sopenharmony_ci			srb->target_status = 0;
33138c2ecf20Sopenharmony_ci			SET_RES_DID(cmd->result, DID_OK);
33148c2ecf20Sopenharmony_ci		}
33158c2ecf20Sopenharmony_ci	}
33168c2ecf20Sopenharmony_ci
33178c2ecf20Sopenharmony_ci	ckc_only = 0;
33188c2ecf20Sopenharmony_ci/* Check Error Conditions */
33198c2ecf20Sopenharmony_ci      ckc_e:
33208c2ecf20Sopenharmony_ci
33218c2ecf20Sopenharmony_ci	pci_unmap_srb(acb, srb);
33228c2ecf20Sopenharmony_ci
33238c2ecf20Sopenharmony_ci	if (cmd->cmnd[0] == INQUIRY) {
33248c2ecf20Sopenharmony_ci		unsigned char *base = NULL;
33258c2ecf20Sopenharmony_ci		struct ScsiInqData *ptr;
33268c2ecf20Sopenharmony_ci		unsigned long flags = 0;
33278c2ecf20Sopenharmony_ci		struct scatterlist* sg = scsi_sglist(cmd);
33288c2ecf20Sopenharmony_ci		size_t offset = 0, len = sizeof(struct ScsiInqData);
33298c2ecf20Sopenharmony_ci
33308c2ecf20Sopenharmony_ci		local_irq_save(flags);
33318c2ecf20Sopenharmony_ci		base = scsi_kmap_atomic_sg(sg, scsi_sg_count(cmd), &offset, &len);
33328c2ecf20Sopenharmony_ci		ptr = (struct ScsiInqData *)(base + offset);
33338c2ecf20Sopenharmony_ci
33348c2ecf20Sopenharmony_ci		if (!ckc_only && (cmd->result & RES_DID) == 0
33358c2ecf20Sopenharmony_ci		    && cmd->cmnd[2] == 0 && scsi_bufflen(cmd) >= 8
33368c2ecf20Sopenharmony_ci		    && dir != DMA_NONE && ptr && (ptr->Vers & 0x07) >= 2)
33378c2ecf20Sopenharmony_ci			dcb->inquiry7 = ptr->Flags;
33388c2ecf20Sopenharmony_ci
33398c2ecf20Sopenharmony_ci	/*if( srb->cmd->cmnd[0] == INQUIRY && */
33408c2ecf20Sopenharmony_ci	/*  (host_byte(cmd->result) == DID_OK || status_byte(cmd->result) & CHECK_CONDITION) ) */
33418c2ecf20Sopenharmony_ci		if ((cmd->result == (DID_OK << 16) ||
33428c2ecf20Sopenharmony_ci		     status_byte(cmd->result) == CHECK_CONDITION)) {
33438c2ecf20Sopenharmony_ci			if (!dcb->init_tcq_flag) {
33448c2ecf20Sopenharmony_ci				add_dev(acb, dcb, ptr);
33458c2ecf20Sopenharmony_ci				dcb->init_tcq_flag = 1;
33468c2ecf20Sopenharmony_ci			}
33478c2ecf20Sopenharmony_ci		}
33488c2ecf20Sopenharmony_ci
33498c2ecf20Sopenharmony_ci		scsi_kunmap_atomic_sg(base);
33508c2ecf20Sopenharmony_ci		local_irq_restore(flags);
33518c2ecf20Sopenharmony_ci	}
33528c2ecf20Sopenharmony_ci
33538c2ecf20Sopenharmony_ci	/* Here is the info for Doug Gilbert's sg3 ... */
33548c2ecf20Sopenharmony_ci	scsi_set_resid(cmd, srb->total_xfer_length);
33558c2ecf20Sopenharmony_ci	/* This may be interpreted by sb. or not ... */
33568c2ecf20Sopenharmony_ci	cmd->SCp.this_residual = srb->total_xfer_length;
33578c2ecf20Sopenharmony_ci	cmd->SCp.buffers_residual = 0;
33588c2ecf20Sopenharmony_ci	if (debug_enabled(DBG_KG)) {
33598c2ecf20Sopenharmony_ci		if (srb->total_xfer_length)
33608c2ecf20Sopenharmony_ci			dprintkdbg(DBG_KG, "srb_done: (0x%p) <%02i-%i> "
33618c2ecf20Sopenharmony_ci				"cmnd=0x%02x Missed %i bytes\n",
33628c2ecf20Sopenharmony_ci				cmd, cmd->device->id, (u8)cmd->device->lun,
33638c2ecf20Sopenharmony_ci				cmd->cmnd[0], srb->total_xfer_length);
33648c2ecf20Sopenharmony_ci	}
33658c2ecf20Sopenharmony_ci
33668c2ecf20Sopenharmony_ci	if (srb != acb->tmp_srb) {
33678c2ecf20Sopenharmony_ci		/* Add to free list */
33688c2ecf20Sopenharmony_ci		dprintkdbg(DBG_0, "srb_done: (0x%p) done result=0x%08x\n",
33698c2ecf20Sopenharmony_ci			cmd, cmd->result);
33708c2ecf20Sopenharmony_ci		list_move_tail(&srb->list, &acb->srb_free_list);
33718c2ecf20Sopenharmony_ci	} else {
33728c2ecf20Sopenharmony_ci		dprintkl(KERN_ERR, "srb_done: ERROR! Completed cmd with tmp_srb\n");
33738c2ecf20Sopenharmony_ci	}
33748c2ecf20Sopenharmony_ci
33758c2ecf20Sopenharmony_ci	cmd->scsi_done(cmd);
33768c2ecf20Sopenharmony_ci	waiting_process_next(acb);
33778c2ecf20Sopenharmony_ci}
33788c2ecf20Sopenharmony_ci
33798c2ecf20Sopenharmony_ci
33808c2ecf20Sopenharmony_ci/* abort all cmds in our queues */
33818c2ecf20Sopenharmony_cistatic void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag,
33828c2ecf20Sopenharmony_ci		struct scsi_cmnd *cmd, u8 force)
33838c2ecf20Sopenharmony_ci{
33848c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb;
33858c2ecf20Sopenharmony_ci	dprintkl(KERN_INFO, "doing_srb_done: pids ");
33868c2ecf20Sopenharmony_ci
33878c2ecf20Sopenharmony_ci	list_for_each_entry(dcb, &acb->dcb_list, list) {
33888c2ecf20Sopenharmony_ci		struct ScsiReqBlk *srb;
33898c2ecf20Sopenharmony_ci		struct ScsiReqBlk *tmp;
33908c2ecf20Sopenharmony_ci		struct scsi_cmnd *p;
33918c2ecf20Sopenharmony_ci
33928c2ecf20Sopenharmony_ci		list_for_each_entry_safe(srb, tmp, &dcb->srb_going_list, list) {
33938c2ecf20Sopenharmony_ci			enum dma_data_direction dir;
33948c2ecf20Sopenharmony_ci			int result;
33958c2ecf20Sopenharmony_ci
33968c2ecf20Sopenharmony_ci			p = srb->cmd;
33978c2ecf20Sopenharmony_ci			dir = p->sc_data_direction;
33988c2ecf20Sopenharmony_ci			result = MK_RES(0, did_flag, 0, 0);
33998c2ecf20Sopenharmony_ci			printk("G:%p(%02i-%i) ", p,
34008c2ecf20Sopenharmony_ci			       p->device->id, (u8)p->device->lun);
34018c2ecf20Sopenharmony_ci			list_del(&srb->list);
34028c2ecf20Sopenharmony_ci			free_tag(dcb, srb);
34038c2ecf20Sopenharmony_ci			list_add_tail(&srb->list, &acb->srb_free_list);
34048c2ecf20Sopenharmony_ci			p->result = result;
34058c2ecf20Sopenharmony_ci			pci_unmap_srb_sense(acb, srb);
34068c2ecf20Sopenharmony_ci			pci_unmap_srb(acb, srb);
34078c2ecf20Sopenharmony_ci			if (force) {
34088c2ecf20Sopenharmony_ci				/* For new EH, we normally don't need to give commands back,
34098c2ecf20Sopenharmony_ci				 * as they all complete or all time out */
34108c2ecf20Sopenharmony_ci				p->scsi_done(p);
34118c2ecf20Sopenharmony_ci			}
34128c2ecf20Sopenharmony_ci		}
34138c2ecf20Sopenharmony_ci		if (!list_empty(&dcb->srb_going_list))
34148c2ecf20Sopenharmony_ci			dprintkl(KERN_DEBUG,
34158c2ecf20Sopenharmony_ci			       "How could the ML send cmnds to the Going queue? <%02i-%i>\n",
34168c2ecf20Sopenharmony_ci			       dcb->target_id, dcb->target_lun);
34178c2ecf20Sopenharmony_ci		if (dcb->tag_mask)
34188c2ecf20Sopenharmony_ci			dprintkl(KERN_DEBUG,
34198c2ecf20Sopenharmony_ci			       "tag_mask for <%02i-%i> should be empty, is %08x!\n",
34208c2ecf20Sopenharmony_ci			       dcb->target_id, dcb->target_lun,
34218c2ecf20Sopenharmony_ci			       dcb->tag_mask);
34228c2ecf20Sopenharmony_ci
34238c2ecf20Sopenharmony_ci		/* Waiting queue */
34248c2ecf20Sopenharmony_ci		list_for_each_entry_safe(srb, tmp, &dcb->srb_waiting_list, list) {
34258c2ecf20Sopenharmony_ci			int result;
34268c2ecf20Sopenharmony_ci			p = srb->cmd;
34278c2ecf20Sopenharmony_ci
34288c2ecf20Sopenharmony_ci			result = MK_RES(0, did_flag, 0, 0);
34298c2ecf20Sopenharmony_ci			printk("W:%p<%02i-%i>", p, p->device->id,
34308c2ecf20Sopenharmony_ci			       (u8)p->device->lun);
34318c2ecf20Sopenharmony_ci			list_move_tail(&srb->list, &acb->srb_free_list);
34328c2ecf20Sopenharmony_ci			p->result = result;
34338c2ecf20Sopenharmony_ci			pci_unmap_srb_sense(acb, srb);
34348c2ecf20Sopenharmony_ci			pci_unmap_srb(acb, srb);
34358c2ecf20Sopenharmony_ci			if (force) {
34368c2ecf20Sopenharmony_ci				/* For new EH, we normally don't need to give commands back,
34378c2ecf20Sopenharmony_ci				 * as they all complete or all time out */
34388c2ecf20Sopenharmony_ci				cmd->scsi_done(cmd);
34398c2ecf20Sopenharmony_ci			}
34408c2ecf20Sopenharmony_ci		}
34418c2ecf20Sopenharmony_ci		if (!list_empty(&dcb->srb_waiting_list))
34428c2ecf20Sopenharmony_ci			dprintkl(KERN_DEBUG, "ML queued %i cmnds again to <%02i-%i>\n",
34438c2ecf20Sopenharmony_ci			     list_size(&dcb->srb_waiting_list), dcb->target_id,
34448c2ecf20Sopenharmony_ci			     dcb->target_lun);
34458c2ecf20Sopenharmony_ci		dcb->flag &= ~ABORT_DEV_;
34468c2ecf20Sopenharmony_ci	}
34478c2ecf20Sopenharmony_ci	printk("\n");
34488c2ecf20Sopenharmony_ci}
34498c2ecf20Sopenharmony_ci
34508c2ecf20Sopenharmony_ci
34518c2ecf20Sopenharmony_cistatic void reset_scsi_bus(struct AdapterCtlBlk *acb)
34528c2ecf20Sopenharmony_ci{
34538c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "reset_scsi_bus: acb=%p\n", acb);
34548c2ecf20Sopenharmony_ci	acb->acb_flag |= RESET_DEV;	/* RESET_DETECT, RESET_DONE, RESET_DEV */
34558c2ecf20Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_RSTSCSI);
34568c2ecf20Sopenharmony_ci
34578c2ecf20Sopenharmony_ci	while (!(DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET))
34588c2ecf20Sopenharmony_ci		/* nothing */;
34598c2ecf20Sopenharmony_ci}
34608c2ecf20Sopenharmony_ci
34618c2ecf20Sopenharmony_ci
34628c2ecf20Sopenharmony_cistatic void set_basic_config(struct AdapterCtlBlk *acb)
34638c2ecf20Sopenharmony_ci{
34648c2ecf20Sopenharmony_ci	u8 bval;
34658c2ecf20Sopenharmony_ci	u16 wval;
34668c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_TIMEOUT, acb->sel_timeout);
34678c2ecf20Sopenharmony_ci	if (acb->config & HCC_PARITY)
34688c2ecf20Sopenharmony_ci		bval = PHASELATCH | INITIATOR | BLOCKRST | PARITYCHECK;
34698c2ecf20Sopenharmony_ci	else
34708c2ecf20Sopenharmony_ci		bval = PHASELATCH | INITIATOR | BLOCKRST;
34718c2ecf20Sopenharmony_ci
34728c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_CONFIG0, bval);
34738c2ecf20Sopenharmony_ci
34748c2ecf20Sopenharmony_ci	/* program configuration 1: Act_Neg (+ Act_Neg_Enh? + Fast_Filter? + DataDis?) */
34758c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_CONFIG1, 0x03);	/* was 0x13: default */
34768c2ecf20Sopenharmony_ci	/* program Host ID                  */
34778c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_HOSTID, acb->scsi_host->this_id);
34788c2ecf20Sopenharmony_ci	/* set ansynchronous transfer       */
34798c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, 0x00);
34808c2ecf20Sopenharmony_ci	/* Turn LED control off */
34818c2ecf20Sopenharmony_ci	wval = DC395x_read16(acb, TRM_S1040_GEN_CONTROL) & 0x7F;
34828c2ecf20Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_GEN_CONTROL, wval);
34838c2ecf20Sopenharmony_ci	/* DMA config          */
34848c2ecf20Sopenharmony_ci	wval = DC395x_read16(acb, TRM_S1040_DMA_CONFIG) & ~DMA_FIFO_CTRL;
34858c2ecf20Sopenharmony_ci	wval |=
34868c2ecf20Sopenharmony_ci	    DMA_FIFO_HALF_HALF | DMA_ENHANCE /*| DMA_MEM_MULTI_READ */ ;
34878c2ecf20Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_DMA_CONFIG, wval);
34888c2ecf20Sopenharmony_ci	/* Clear pending interrupt status */
34898c2ecf20Sopenharmony_ci	DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS);
34908c2ecf20Sopenharmony_ci	/* Enable SCSI interrupt    */
34918c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_INTEN, 0x7F);
34928c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_DMA_INTEN, EN_SCSIINTR | EN_DMAXFERERROR
34938c2ecf20Sopenharmony_ci		      /*| EN_DMAXFERABORT | EN_DMAXFERCOMP | EN_FORCEDMACOMP */
34948c2ecf20Sopenharmony_ci		      );
34958c2ecf20Sopenharmony_ci}
34968c2ecf20Sopenharmony_ci
34978c2ecf20Sopenharmony_ci
34988c2ecf20Sopenharmony_cistatic void scsi_reset_detect(struct AdapterCtlBlk *acb)
34998c2ecf20Sopenharmony_ci{
35008c2ecf20Sopenharmony_ci	dprintkl(KERN_INFO, "scsi_reset_detect: acb=%p\n", acb);
35018c2ecf20Sopenharmony_ci	/* delay half a second */
35028c2ecf20Sopenharmony_ci	if (timer_pending(&acb->waiting_timer))
35038c2ecf20Sopenharmony_ci		del_timer(&acb->waiting_timer);
35048c2ecf20Sopenharmony_ci
35058c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_CONTROL, DO_RSTMODULE);
35068c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_DMA_CONTROL, DMARESETMODULE);
35078c2ecf20Sopenharmony_ci	/*DC395x_write8(acb, TRM_S1040_DMA_CONTROL,STOPDMAXFER); */
35088c2ecf20Sopenharmony_ci	udelay(500);
35098c2ecf20Sopenharmony_ci	/* Maybe we locked up the bus? Then lets wait even longer ... */
35108c2ecf20Sopenharmony_ci	acb->last_reset =
35118c2ecf20Sopenharmony_ci	    jiffies + 5 * HZ / 2 +
35128c2ecf20Sopenharmony_ci	    HZ * acb->eeprom.delay_time;
35138c2ecf20Sopenharmony_ci
35148c2ecf20Sopenharmony_ci	clear_fifo(acb, "scsi_reset_detect");
35158c2ecf20Sopenharmony_ci	set_basic_config(acb);
35168c2ecf20Sopenharmony_ci	/*1.25 */
35178c2ecf20Sopenharmony_ci	/*DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT); */
35188c2ecf20Sopenharmony_ci
35198c2ecf20Sopenharmony_ci	if (acb->acb_flag & RESET_DEV) {	/* RESET_DETECT, RESET_DONE, RESET_DEV */
35208c2ecf20Sopenharmony_ci		acb->acb_flag |= RESET_DONE;
35218c2ecf20Sopenharmony_ci	} else {
35228c2ecf20Sopenharmony_ci		acb->acb_flag |= RESET_DETECT;
35238c2ecf20Sopenharmony_ci		reset_dev_param(acb);
35248c2ecf20Sopenharmony_ci		doing_srb_done(acb, DID_RESET, NULL, 1);
35258c2ecf20Sopenharmony_ci		/*DC395x_RecoverSRB( acb ); */
35268c2ecf20Sopenharmony_ci		acb->active_dcb = NULL;
35278c2ecf20Sopenharmony_ci		acb->acb_flag = 0;
35288c2ecf20Sopenharmony_ci		waiting_process_next(acb);
35298c2ecf20Sopenharmony_ci	}
35308c2ecf20Sopenharmony_ci}
35318c2ecf20Sopenharmony_ci
35328c2ecf20Sopenharmony_ci
35338c2ecf20Sopenharmony_cistatic void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
35348c2ecf20Sopenharmony_ci		struct ScsiReqBlk *srb)
35358c2ecf20Sopenharmony_ci{
35368c2ecf20Sopenharmony_ci	struct scsi_cmnd *cmd = srb->cmd;
35378c2ecf20Sopenharmony_ci	dprintkdbg(DBG_1, "request_sense: (0x%p) <%02i-%i>\n",
35388c2ecf20Sopenharmony_ci		cmd, cmd->device->id, (u8)cmd->device->lun);
35398c2ecf20Sopenharmony_ci
35408c2ecf20Sopenharmony_ci	srb->flag |= AUTO_REQSENSE;
35418c2ecf20Sopenharmony_ci	srb->adapter_status = 0;
35428c2ecf20Sopenharmony_ci	srb->target_status = 0;
35438c2ecf20Sopenharmony_ci
35448c2ecf20Sopenharmony_ci	/* KG: Can this prevent crap sense data ? */
35458c2ecf20Sopenharmony_ci	memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
35468c2ecf20Sopenharmony_ci
35478c2ecf20Sopenharmony_ci	/* Save some data */
35488c2ecf20Sopenharmony_ci	srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].address =
35498c2ecf20Sopenharmony_ci	    srb->segment_x[0].address;
35508c2ecf20Sopenharmony_ci	srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].length =
35518c2ecf20Sopenharmony_ci	    srb->segment_x[0].length;
35528c2ecf20Sopenharmony_ci	srb->xferred = srb->total_xfer_length;
35538c2ecf20Sopenharmony_ci	/* srb->segment_x : a one entry of S/G list table */
35548c2ecf20Sopenharmony_ci	srb->total_xfer_length = SCSI_SENSE_BUFFERSIZE;
35558c2ecf20Sopenharmony_ci	srb->segment_x[0].length = SCSI_SENSE_BUFFERSIZE;
35568c2ecf20Sopenharmony_ci	/* Map sense buffer */
35578c2ecf20Sopenharmony_ci	srb->segment_x[0].address = dma_map_single(&acb->dev->dev,
35588c2ecf20Sopenharmony_ci			cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE,
35598c2ecf20Sopenharmony_ci			DMA_FROM_DEVICE);
35608c2ecf20Sopenharmony_ci	dprintkdbg(DBG_SG, "request_sense: map buffer %p->%08x(%05x)\n",
35618c2ecf20Sopenharmony_ci	       cmd->sense_buffer, srb->segment_x[0].address,
35628c2ecf20Sopenharmony_ci	       SCSI_SENSE_BUFFERSIZE);
35638c2ecf20Sopenharmony_ci	srb->sg_count = 1;
35648c2ecf20Sopenharmony_ci	srb->sg_index = 0;
35658c2ecf20Sopenharmony_ci
35668c2ecf20Sopenharmony_ci	if (start_scsi(acb, dcb, srb)) {	/* Should only happen, if sb. else grabs the bus */
35678c2ecf20Sopenharmony_ci		dprintkl(KERN_DEBUG,
35688c2ecf20Sopenharmony_ci			"request_sense: (0x%p) failed <%02i-%i>\n",
35698c2ecf20Sopenharmony_ci			srb->cmd, dcb->target_id, dcb->target_lun);
35708c2ecf20Sopenharmony_ci		list_move(&srb->list, &dcb->srb_waiting_list);
35718c2ecf20Sopenharmony_ci		waiting_set_timer(acb, HZ / 100);
35728c2ecf20Sopenharmony_ci	}
35738c2ecf20Sopenharmony_ci}
35748c2ecf20Sopenharmony_ci
35758c2ecf20Sopenharmony_ci
35768c2ecf20Sopenharmony_ci/**
35778c2ecf20Sopenharmony_ci * device_alloc - Allocate a new device instance. This create the
35788c2ecf20Sopenharmony_ci * devices instance and sets up all the data items. The adapter
35798c2ecf20Sopenharmony_ci * instance is required to obtain confiuration information for this
35808c2ecf20Sopenharmony_ci * device. This does *not* add this device to the adapters device
35818c2ecf20Sopenharmony_ci * list.
35828c2ecf20Sopenharmony_ci *
35838c2ecf20Sopenharmony_ci * @acb: The adapter to obtain configuration information from.
35848c2ecf20Sopenharmony_ci * @target: The target for the new device.
35858c2ecf20Sopenharmony_ci * @lun: The lun for the new device.
35868c2ecf20Sopenharmony_ci *
35878c2ecf20Sopenharmony_ci * Return the new device if successful or NULL on failure.
35888c2ecf20Sopenharmony_ci **/
35898c2ecf20Sopenharmony_cistatic struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb,
35908c2ecf20Sopenharmony_ci		u8 target, u8 lun)
35918c2ecf20Sopenharmony_ci{
35928c2ecf20Sopenharmony_ci	struct NvRamType *eeprom = &acb->eeprom;
35938c2ecf20Sopenharmony_ci	u8 period_index = eeprom->target[target].period & 0x07;
35948c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb;
35958c2ecf20Sopenharmony_ci
35968c2ecf20Sopenharmony_ci	dcb = kmalloc(sizeof(struct DeviceCtlBlk), GFP_ATOMIC);
35978c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "device_alloc: <%02i-%i>\n", target, lun);
35988c2ecf20Sopenharmony_ci	if (!dcb)
35998c2ecf20Sopenharmony_ci		return NULL;
36008c2ecf20Sopenharmony_ci	dcb->acb = NULL;
36018c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&dcb->srb_going_list);
36028c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&dcb->srb_waiting_list);
36038c2ecf20Sopenharmony_ci	dcb->active_srb = NULL;
36048c2ecf20Sopenharmony_ci	dcb->tag_mask = 0;
36058c2ecf20Sopenharmony_ci	dcb->max_command = 1;
36068c2ecf20Sopenharmony_ci	dcb->target_id = target;
36078c2ecf20Sopenharmony_ci	dcb->target_lun = lun;
36088c2ecf20Sopenharmony_ci	dcb->dev_mode = eeprom->target[target].cfg0;
36098c2ecf20Sopenharmony_ci#ifndef DC395x_NO_DISCONNECT
36108c2ecf20Sopenharmony_ci	dcb->identify_msg =
36118c2ecf20Sopenharmony_ci	    IDENTIFY(dcb->dev_mode & NTC_DO_DISCONNECT, lun);
36128c2ecf20Sopenharmony_ci#else
36138c2ecf20Sopenharmony_ci	dcb->identify_msg = IDENTIFY(0, lun);
36148c2ecf20Sopenharmony_ci#endif
36158c2ecf20Sopenharmony_ci	dcb->inquiry7 = 0;
36168c2ecf20Sopenharmony_ci	dcb->sync_mode = 0;
36178c2ecf20Sopenharmony_ci	dcb->min_nego_period = clock_period[period_index];
36188c2ecf20Sopenharmony_ci	dcb->sync_period = 0;
36198c2ecf20Sopenharmony_ci	dcb->sync_offset = 0;
36208c2ecf20Sopenharmony_ci	dcb->flag = 0;
36218c2ecf20Sopenharmony_ci
36228c2ecf20Sopenharmony_ci#ifndef DC395x_NO_WIDE
36238c2ecf20Sopenharmony_ci	if ((dcb->dev_mode & NTC_DO_WIDE_NEGO)
36248c2ecf20Sopenharmony_ci	    && (acb->config & HCC_WIDE_CARD))
36258c2ecf20Sopenharmony_ci		dcb->sync_mode |= WIDE_NEGO_ENABLE;
36268c2ecf20Sopenharmony_ci#endif
36278c2ecf20Sopenharmony_ci#ifndef DC395x_NO_SYNC
36288c2ecf20Sopenharmony_ci	if (dcb->dev_mode & NTC_DO_SYNC_NEGO)
36298c2ecf20Sopenharmony_ci		if (!(lun) || current_sync_offset)
36308c2ecf20Sopenharmony_ci			dcb->sync_mode |= SYNC_NEGO_ENABLE;
36318c2ecf20Sopenharmony_ci#endif
36328c2ecf20Sopenharmony_ci	if (dcb->target_lun != 0) {
36338c2ecf20Sopenharmony_ci		/* Copy settings */
36348c2ecf20Sopenharmony_ci		struct DeviceCtlBlk *p = NULL, *iter;
36358c2ecf20Sopenharmony_ci
36368c2ecf20Sopenharmony_ci		list_for_each_entry(iter, &acb->dcb_list, list)
36378c2ecf20Sopenharmony_ci			if (iter->target_id == dcb->target_id) {
36388c2ecf20Sopenharmony_ci				p = iter;
36398c2ecf20Sopenharmony_ci				break;
36408c2ecf20Sopenharmony_ci			}
36418c2ecf20Sopenharmony_ci
36428c2ecf20Sopenharmony_ci		if (!p) {
36438c2ecf20Sopenharmony_ci			kfree(dcb);
36448c2ecf20Sopenharmony_ci			return NULL;
36458c2ecf20Sopenharmony_ci		}
36468c2ecf20Sopenharmony_ci
36478c2ecf20Sopenharmony_ci		dprintkdbg(DBG_1,
36488c2ecf20Sopenharmony_ci		       "device_alloc: <%02i-%i> copy from <%02i-%i>\n",
36498c2ecf20Sopenharmony_ci		       dcb->target_id, dcb->target_lun,
36508c2ecf20Sopenharmony_ci		       p->target_id, p->target_lun);
36518c2ecf20Sopenharmony_ci		dcb->sync_mode = p->sync_mode;
36528c2ecf20Sopenharmony_ci		dcb->sync_period = p->sync_period;
36538c2ecf20Sopenharmony_ci		dcb->min_nego_period = p->min_nego_period;
36548c2ecf20Sopenharmony_ci		dcb->sync_offset = p->sync_offset;
36558c2ecf20Sopenharmony_ci		dcb->inquiry7 = p->inquiry7;
36568c2ecf20Sopenharmony_ci	}
36578c2ecf20Sopenharmony_ci	return dcb;
36588c2ecf20Sopenharmony_ci}
36598c2ecf20Sopenharmony_ci
36608c2ecf20Sopenharmony_ci
36618c2ecf20Sopenharmony_ci/**
36628c2ecf20Sopenharmony_ci * adapter_add_device - Adds the device instance to the adaptor instance.
36638c2ecf20Sopenharmony_ci *
36648c2ecf20Sopenharmony_ci * @acb: The adapter device to be updated
36658c2ecf20Sopenharmony_ci * @dcb: A newly created and initialised device instance to add.
36668c2ecf20Sopenharmony_ci **/
36678c2ecf20Sopenharmony_cistatic void adapter_add_device(struct AdapterCtlBlk *acb,
36688c2ecf20Sopenharmony_ci		struct DeviceCtlBlk *dcb)
36698c2ecf20Sopenharmony_ci{
36708c2ecf20Sopenharmony_ci	/* backpointer to adapter */
36718c2ecf20Sopenharmony_ci	dcb->acb = acb;
36728c2ecf20Sopenharmony_ci
36738c2ecf20Sopenharmony_ci	/* set run_robin to this device if it is currently empty */
36748c2ecf20Sopenharmony_ci	if (list_empty(&acb->dcb_list))
36758c2ecf20Sopenharmony_ci		acb->dcb_run_robin = dcb;
36768c2ecf20Sopenharmony_ci
36778c2ecf20Sopenharmony_ci	/* add device to list */
36788c2ecf20Sopenharmony_ci	list_add_tail(&dcb->list, &acb->dcb_list);
36798c2ecf20Sopenharmony_ci
36808c2ecf20Sopenharmony_ci	/* update device maps */
36818c2ecf20Sopenharmony_ci	acb->dcb_map[dcb->target_id] |= (1 << dcb->target_lun);
36828c2ecf20Sopenharmony_ci	acb->children[dcb->target_id][dcb->target_lun] = dcb;
36838c2ecf20Sopenharmony_ci}
36848c2ecf20Sopenharmony_ci
36858c2ecf20Sopenharmony_ci
36868c2ecf20Sopenharmony_ci/**
36878c2ecf20Sopenharmony_ci * adapter_remove_device - Removes the device instance from the adaptor
36888c2ecf20Sopenharmony_ci * instance. The device instance is not check in any way or freed by this.
36898c2ecf20Sopenharmony_ci * The caller is expected to take care of that. This will simply remove the
36908c2ecf20Sopenharmony_ci * device from the adapters data strcutures.
36918c2ecf20Sopenharmony_ci *
36928c2ecf20Sopenharmony_ci * @acb: The adapter device to be updated
36938c2ecf20Sopenharmony_ci * @dcb: A device that has previously been added to the adapter.
36948c2ecf20Sopenharmony_ci **/
36958c2ecf20Sopenharmony_cistatic void adapter_remove_device(struct AdapterCtlBlk *acb,
36968c2ecf20Sopenharmony_ci		struct DeviceCtlBlk *dcb)
36978c2ecf20Sopenharmony_ci{
36988c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *i;
36998c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *tmp;
37008c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "adapter_remove_device: <%02i-%i>\n",
37018c2ecf20Sopenharmony_ci		dcb->target_id, dcb->target_lun);
37028c2ecf20Sopenharmony_ci
37038c2ecf20Sopenharmony_ci	/* fix up any pointers to this device that we have in the adapter */
37048c2ecf20Sopenharmony_ci	if (acb->active_dcb == dcb)
37058c2ecf20Sopenharmony_ci		acb->active_dcb = NULL;
37068c2ecf20Sopenharmony_ci	if (acb->dcb_run_robin == dcb)
37078c2ecf20Sopenharmony_ci		acb->dcb_run_robin = dcb_get_next(&acb->dcb_list, dcb);
37088c2ecf20Sopenharmony_ci
37098c2ecf20Sopenharmony_ci	/* unlink from list */
37108c2ecf20Sopenharmony_ci	list_for_each_entry_safe(i, tmp, &acb->dcb_list, list)
37118c2ecf20Sopenharmony_ci		if (dcb == i) {
37128c2ecf20Sopenharmony_ci			list_del(&i->list);
37138c2ecf20Sopenharmony_ci			break;
37148c2ecf20Sopenharmony_ci		}
37158c2ecf20Sopenharmony_ci
37168c2ecf20Sopenharmony_ci	/* clear map and children */
37178c2ecf20Sopenharmony_ci	acb->dcb_map[dcb->target_id] &= ~(1 << dcb->target_lun);
37188c2ecf20Sopenharmony_ci	acb->children[dcb->target_id][dcb->target_lun] = NULL;
37198c2ecf20Sopenharmony_ci	dcb->acb = NULL;
37208c2ecf20Sopenharmony_ci}
37218c2ecf20Sopenharmony_ci
37228c2ecf20Sopenharmony_ci
37238c2ecf20Sopenharmony_ci/**
37248c2ecf20Sopenharmony_ci * adapter_remove_and_free_device - Removes a single device from the adapter
37258c2ecf20Sopenharmony_ci * and then frees the device information.
37268c2ecf20Sopenharmony_ci *
37278c2ecf20Sopenharmony_ci * @acb: The adapter device to be updated
37288c2ecf20Sopenharmony_ci * @dcb: A device that has previously been added to the adapter.
37298c2ecf20Sopenharmony_ci */
37308c2ecf20Sopenharmony_cistatic void adapter_remove_and_free_device(struct AdapterCtlBlk *acb,
37318c2ecf20Sopenharmony_ci		struct DeviceCtlBlk *dcb)
37328c2ecf20Sopenharmony_ci{
37338c2ecf20Sopenharmony_ci	if (list_size(&dcb->srb_going_list) > 1) {
37348c2ecf20Sopenharmony_ci		dprintkdbg(DBG_1, "adapter_remove_and_free_device: <%02i-%i> "
37358c2ecf20Sopenharmony_ci		           "Won't remove because of %i active requests.\n",
37368c2ecf20Sopenharmony_ci			   dcb->target_id, dcb->target_lun,
37378c2ecf20Sopenharmony_ci			   list_size(&dcb->srb_going_list));
37388c2ecf20Sopenharmony_ci		return;
37398c2ecf20Sopenharmony_ci	}
37408c2ecf20Sopenharmony_ci	adapter_remove_device(acb, dcb);
37418c2ecf20Sopenharmony_ci	kfree(dcb);
37428c2ecf20Sopenharmony_ci}
37438c2ecf20Sopenharmony_ci
37448c2ecf20Sopenharmony_ci
37458c2ecf20Sopenharmony_ci/**
37468c2ecf20Sopenharmony_ci * adapter_remove_and_free_all_devices - Removes and frees all of the
37478c2ecf20Sopenharmony_ci * devices associated with the specified adapter.
37488c2ecf20Sopenharmony_ci *
37498c2ecf20Sopenharmony_ci * @acb: The adapter from which all devices should be removed.
37508c2ecf20Sopenharmony_ci **/
37518c2ecf20Sopenharmony_cistatic void adapter_remove_and_free_all_devices(struct AdapterCtlBlk* acb)
37528c2ecf20Sopenharmony_ci{
37538c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb;
37548c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *tmp;
37558c2ecf20Sopenharmony_ci	dprintkdbg(DBG_1, "adapter_remove_and_free_all_devices: num=%i\n",
37568c2ecf20Sopenharmony_ci		   list_size(&acb->dcb_list));
37578c2ecf20Sopenharmony_ci
37588c2ecf20Sopenharmony_ci	list_for_each_entry_safe(dcb, tmp, &acb->dcb_list, list)
37598c2ecf20Sopenharmony_ci		adapter_remove_and_free_device(acb, dcb);
37608c2ecf20Sopenharmony_ci}
37618c2ecf20Sopenharmony_ci
37628c2ecf20Sopenharmony_ci
37638c2ecf20Sopenharmony_ci/**
37648c2ecf20Sopenharmony_ci * dc395x_slave_alloc - Called by the scsi mid layer to tell us about a new
37658c2ecf20Sopenharmony_ci * scsi device that we need to deal with. We allocate a new device and then
37668c2ecf20Sopenharmony_ci * insert that device into the adapters device list.
37678c2ecf20Sopenharmony_ci *
37688c2ecf20Sopenharmony_ci * @scsi_device: The new scsi device that we need to handle.
37698c2ecf20Sopenharmony_ci **/
37708c2ecf20Sopenharmony_cistatic int dc395x_slave_alloc(struct scsi_device *scsi_device)
37718c2ecf20Sopenharmony_ci{
37728c2ecf20Sopenharmony_ci	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)scsi_device->host->hostdata;
37738c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb;
37748c2ecf20Sopenharmony_ci
37758c2ecf20Sopenharmony_ci	dcb = device_alloc(acb, scsi_device->id, scsi_device->lun);
37768c2ecf20Sopenharmony_ci	if (!dcb)
37778c2ecf20Sopenharmony_ci		return -ENOMEM;
37788c2ecf20Sopenharmony_ci	adapter_add_device(acb, dcb);
37798c2ecf20Sopenharmony_ci
37808c2ecf20Sopenharmony_ci	return 0;
37818c2ecf20Sopenharmony_ci}
37828c2ecf20Sopenharmony_ci
37838c2ecf20Sopenharmony_ci
37848c2ecf20Sopenharmony_ci/**
37858c2ecf20Sopenharmony_ci * dc395x_slave_destroy - Called by the scsi mid layer to tell us about a
37868c2ecf20Sopenharmony_ci * device that is going away.
37878c2ecf20Sopenharmony_ci *
37888c2ecf20Sopenharmony_ci * @scsi_device: The new scsi device that we need to handle.
37898c2ecf20Sopenharmony_ci **/
37908c2ecf20Sopenharmony_cistatic void dc395x_slave_destroy(struct scsi_device *scsi_device)
37918c2ecf20Sopenharmony_ci{
37928c2ecf20Sopenharmony_ci	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)scsi_device->host->hostdata;
37938c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb = find_dcb(acb, scsi_device->id, scsi_device->lun);
37948c2ecf20Sopenharmony_ci	if (dcb)
37958c2ecf20Sopenharmony_ci		adapter_remove_and_free_device(acb, dcb);
37968c2ecf20Sopenharmony_ci}
37978c2ecf20Sopenharmony_ci
37988c2ecf20Sopenharmony_ci
37998c2ecf20Sopenharmony_ci
38008c2ecf20Sopenharmony_ci
38018c2ecf20Sopenharmony_ci/**
38028c2ecf20Sopenharmony_ci * trms1040_wait_30us: wait for 30 us
38038c2ecf20Sopenharmony_ci *
38048c2ecf20Sopenharmony_ci * Waits for 30us (using the chip by the looks of it..)
38058c2ecf20Sopenharmony_ci *
38068c2ecf20Sopenharmony_ci * @io_port: base I/O address
38078c2ecf20Sopenharmony_ci **/
38088c2ecf20Sopenharmony_cistatic void trms1040_wait_30us(unsigned long io_port)
38098c2ecf20Sopenharmony_ci{
38108c2ecf20Sopenharmony_ci	/* ScsiPortStallExecution(30); wait 30 us */
38118c2ecf20Sopenharmony_ci	outb(5, io_port + TRM_S1040_GEN_TIMER);
38128c2ecf20Sopenharmony_ci	while (!(inb(io_port + TRM_S1040_GEN_STATUS) & GTIMEOUT))
38138c2ecf20Sopenharmony_ci		/* nothing */ ;
38148c2ecf20Sopenharmony_ci}
38158c2ecf20Sopenharmony_ci
38168c2ecf20Sopenharmony_ci
38178c2ecf20Sopenharmony_ci/**
38188c2ecf20Sopenharmony_ci * trms1040_write_cmd - write the secified command and address to
38198c2ecf20Sopenharmony_ci * chip
38208c2ecf20Sopenharmony_ci *
38218c2ecf20Sopenharmony_ci * @io_port:	base I/O address
38228c2ecf20Sopenharmony_ci * @cmd:	SB + op code (command) to send
38238c2ecf20Sopenharmony_ci * @addr:	address to send
38248c2ecf20Sopenharmony_ci **/
38258c2ecf20Sopenharmony_cistatic void trms1040_write_cmd(unsigned long io_port, u8 cmd, u8 addr)
38268c2ecf20Sopenharmony_ci{
38278c2ecf20Sopenharmony_ci	int i;
38288c2ecf20Sopenharmony_ci	u8 send_data;
38298c2ecf20Sopenharmony_ci
38308c2ecf20Sopenharmony_ci	/* program SB + OP code */
38318c2ecf20Sopenharmony_ci	for (i = 0; i < 3; i++, cmd <<= 1) {
38328c2ecf20Sopenharmony_ci		send_data = NVR_SELECT;
38338c2ecf20Sopenharmony_ci		if (cmd & 0x04)	/* Start from bit 2 */
38348c2ecf20Sopenharmony_ci			send_data |= NVR_BITOUT;
38358c2ecf20Sopenharmony_ci
38368c2ecf20Sopenharmony_ci		outb(send_data, io_port + TRM_S1040_GEN_NVRAM);
38378c2ecf20Sopenharmony_ci		trms1040_wait_30us(io_port);
38388c2ecf20Sopenharmony_ci		outb((send_data | NVR_CLOCK),
38398c2ecf20Sopenharmony_ci		     io_port + TRM_S1040_GEN_NVRAM);
38408c2ecf20Sopenharmony_ci		trms1040_wait_30us(io_port);
38418c2ecf20Sopenharmony_ci	}
38428c2ecf20Sopenharmony_ci
38438c2ecf20Sopenharmony_ci	/* send address */
38448c2ecf20Sopenharmony_ci	for (i = 0; i < 7; i++, addr <<= 1) {
38458c2ecf20Sopenharmony_ci		send_data = NVR_SELECT;
38468c2ecf20Sopenharmony_ci		if (addr & 0x40)	/* Start from bit 6 */
38478c2ecf20Sopenharmony_ci			send_data |= NVR_BITOUT;
38488c2ecf20Sopenharmony_ci
38498c2ecf20Sopenharmony_ci		outb(send_data, io_port + TRM_S1040_GEN_NVRAM);
38508c2ecf20Sopenharmony_ci		trms1040_wait_30us(io_port);
38518c2ecf20Sopenharmony_ci		outb((send_data | NVR_CLOCK),
38528c2ecf20Sopenharmony_ci		     io_port + TRM_S1040_GEN_NVRAM);
38538c2ecf20Sopenharmony_ci		trms1040_wait_30us(io_port);
38548c2ecf20Sopenharmony_ci	}
38558c2ecf20Sopenharmony_ci	outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM);
38568c2ecf20Sopenharmony_ci	trms1040_wait_30us(io_port);
38578c2ecf20Sopenharmony_ci}
38588c2ecf20Sopenharmony_ci
38598c2ecf20Sopenharmony_ci
38608c2ecf20Sopenharmony_ci/**
38618c2ecf20Sopenharmony_ci * trms1040_set_data - store a single byte in the eeprom
38628c2ecf20Sopenharmony_ci *
38638c2ecf20Sopenharmony_ci * Called from write all to write a single byte into the SSEEPROM
38648c2ecf20Sopenharmony_ci * Which is done one bit at a time.
38658c2ecf20Sopenharmony_ci *
38668c2ecf20Sopenharmony_ci * @io_port:	base I/O address
38678c2ecf20Sopenharmony_ci * @addr:	offset into EEPROM
38688c2ecf20Sopenharmony_ci * @byte:	bytes to write
38698c2ecf20Sopenharmony_ci **/
38708c2ecf20Sopenharmony_cistatic void trms1040_set_data(unsigned long io_port, u8 addr, u8 byte)
38718c2ecf20Sopenharmony_ci{
38728c2ecf20Sopenharmony_ci	int i;
38738c2ecf20Sopenharmony_ci	u8 send_data;
38748c2ecf20Sopenharmony_ci
38758c2ecf20Sopenharmony_ci	/* Send write command & address */
38768c2ecf20Sopenharmony_ci	trms1040_write_cmd(io_port, 0x05, addr);
38778c2ecf20Sopenharmony_ci
38788c2ecf20Sopenharmony_ci	/* Write data */
38798c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++, byte <<= 1) {
38808c2ecf20Sopenharmony_ci		send_data = NVR_SELECT;
38818c2ecf20Sopenharmony_ci		if (byte & 0x80)	/* Start from bit 7 */
38828c2ecf20Sopenharmony_ci			send_data |= NVR_BITOUT;
38838c2ecf20Sopenharmony_ci
38848c2ecf20Sopenharmony_ci		outb(send_data, io_port + TRM_S1040_GEN_NVRAM);
38858c2ecf20Sopenharmony_ci		trms1040_wait_30us(io_port);
38868c2ecf20Sopenharmony_ci		outb((send_data | NVR_CLOCK), io_port + TRM_S1040_GEN_NVRAM);
38878c2ecf20Sopenharmony_ci		trms1040_wait_30us(io_port);
38888c2ecf20Sopenharmony_ci	}
38898c2ecf20Sopenharmony_ci	outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM);
38908c2ecf20Sopenharmony_ci	trms1040_wait_30us(io_port);
38918c2ecf20Sopenharmony_ci
38928c2ecf20Sopenharmony_ci	/* Disable chip select */
38938c2ecf20Sopenharmony_ci	outb(0, io_port + TRM_S1040_GEN_NVRAM);
38948c2ecf20Sopenharmony_ci	trms1040_wait_30us(io_port);
38958c2ecf20Sopenharmony_ci
38968c2ecf20Sopenharmony_ci	outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM);
38978c2ecf20Sopenharmony_ci	trms1040_wait_30us(io_port);
38988c2ecf20Sopenharmony_ci
38998c2ecf20Sopenharmony_ci	/* Wait for write ready */
39008c2ecf20Sopenharmony_ci	while (1) {
39018c2ecf20Sopenharmony_ci		outb((NVR_SELECT | NVR_CLOCK), io_port + TRM_S1040_GEN_NVRAM);
39028c2ecf20Sopenharmony_ci		trms1040_wait_30us(io_port);
39038c2ecf20Sopenharmony_ci
39048c2ecf20Sopenharmony_ci		outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM);
39058c2ecf20Sopenharmony_ci		trms1040_wait_30us(io_port);
39068c2ecf20Sopenharmony_ci
39078c2ecf20Sopenharmony_ci		if (inb(io_port + TRM_S1040_GEN_NVRAM) & NVR_BITIN)
39088c2ecf20Sopenharmony_ci			break;
39098c2ecf20Sopenharmony_ci	}
39108c2ecf20Sopenharmony_ci
39118c2ecf20Sopenharmony_ci	/*  Disable chip select */
39128c2ecf20Sopenharmony_ci	outb(0, io_port + TRM_S1040_GEN_NVRAM);
39138c2ecf20Sopenharmony_ci}
39148c2ecf20Sopenharmony_ci
39158c2ecf20Sopenharmony_ci
39168c2ecf20Sopenharmony_ci/**
39178c2ecf20Sopenharmony_ci * trms1040_write_all - write 128 bytes to the eeprom
39188c2ecf20Sopenharmony_ci *
39198c2ecf20Sopenharmony_ci * Write the supplied 128 bytes to the chips SEEPROM
39208c2ecf20Sopenharmony_ci *
39218c2ecf20Sopenharmony_ci * @eeprom:	the data to write
39228c2ecf20Sopenharmony_ci * @io_port:	the base io port
39238c2ecf20Sopenharmony_ci **/
39248c2ecf20Sopenharmony_cistatic void trms1040_write_all(struct NvRamType *eeprom, unsigned long io_port)
39258c2ecf20Sopenharmony_ci{
39268c2ecf20Sopenharmony_ci	u8 *b_eeprom = (u8 *)eeprom;
39278c2ecf20Sopenharmony_ci	u8 addr;
39288c2ecf20Sopenharmony_ci
39298c2ecf20Sopenharmony_ci	/* Enable SEEPROM */
39308c2ecf20Sopenharmony_ci	outb((inb(io_port + TRM_S1040_GEN_CONTROL) | EN_EEPROM),
39318c2ecf20Sopenharmony_ci	     io_port + TRM_S1040_GEN_CONTROL);
39328c2ecf20Sopenharmony_ci
39338c2ecf20Sopenharmony_ci	/* write enable */
39348c2ecf20Sopenharmony_ci	trms1040_write_cmd(io_port, 0x04, 0xFF);
39358c2ecf20Sopenharmony_ci	outb(0, io_port + TRM_S1040_GEN_NVRAM);
39368c2ecf20Sopenharmony_ci	trms1040_wait_30us(io_port);
39378c2ecf20Sopenharmony_ci
39388c2ecf20Sopenharmony_ci	/* write */
39398c2ecf20Sopenharmony_ci	for (addr = 0; addr < 128; addr++, b_eeprom++)
39408c2ecf20Sopenharmony_ci		trms1040_set_data(io_port, addr, *b_eeprom);
39418c2ecf20Sopenharmony_ci
39428c2ecf20Sopenharmony_ci	/* write disable */
39438c2ecf20Sopenharmony_ci	trms1040_write_cmd(io_port, 0x04, 0x00);
39448c2ecf20Sopenharmony_ci	outb(0, io_port + TRM_S1040_GEN_NVRAM);
39458c2ecf20Sopenharmony_ci	trms1040_wait_30us(io_port);
39468c2ecf20Sopenharmony_ci
39478c2ecf20Sopenharmony_ci	/* Disable SEEPROM */
39488c2ecf20Sopenharmony_ci	outb((inb(io_port + TRM_S1040_GEN_CONTROL) & ~EN_EEPROM),
39498c2ecf20Sopenharmony_ci	     io_port + TRM_S1040_GEN_CONTROL);
39508c2ecf20Sopenharmony_ci}
39518c2ecf20Sopenharmony_ci
39528c2ecf20Sopenharmony_ci
39538c2ecf20Sopenharmony_ci/**
39548c2ecf20Sopenharmony_ci * trms1040_get_data - get a single byte from the eeprom
39558c2ecf20Sopenharmony_ci *
39568c2ecf20Sopenharmony_ci * Called from read all to read a single byte into the SSEEPROM
39578c2ecf20Sopenharmony_ci * Which is done one bit at a time.
39588c2ecf20Sopenharmony_ci *
39598c2ecf20Sopenharmony_ci * @io_port:	base I/O address
39608c2ecf20Sopenharmony_ci * @addr:	offset into SEEPROM
39618c2ecf20Sopenharmony_ci *
39628c2ecf20Sopenharmony_ci * Returns the byte read.
39638c2ecf20Sopenharmony_ci **/
39648c2ecf20Sopenharmony_cistatic u8 trms1040_get_data(unsigned long io_port, u8 addr)
39658c2ecf20Sopenharmony_ci{
39668c2ecf20Sopenharmony_ci	int i;
39678c2ecf20Sopenharmony_ci	u8 read_byte;
39688c2ecf20Sopenharmony_ci	u8 result = 0;
39698c2ecf20Sopenharmony_ci
39708c2ecf20Sopenharmony_ci	/* Send read command & address */
39718c2ecf20Sopenharmony_ci	trms1040_write_cmd(io_port, 0x06, addr);
39728c2ecf20Sopenharmony_ci
39738c2ecf20Sopenharmony_ci	/* read data */
39748c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++) {
39758c2ecf20Sopenharmony_ci		outb((NVR_SELECT | NVR_CLOCK), io_port + TRM_S1040_GEN_NVRAM);
39768c2ecf20Sopenharmony_ci		trms1040_wait_30us(io_port);
39778c2ecf20Sopenharmony_ci		outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM);
39788c2ecf20Sopenharmony_ci
39798c2ecf20Sopenharmony_ci		/* Get data bit while falling edge */
39808c2ecf20Sopenharmony_ci		read_byte = inb(io_port + TRM_S1040_GEN_NVRAM);
39818c2ecf20Sopenharmony_ci		result <<= 1;
39828c2ecf20Sopenharmony_ci		if (read_byte & NVR_BITIN)
39838c2ecf20Sopenharmony_ci			result |= 1;
39848c2ecf20Sopenharmony_ci
39858c2ecf20Sopenharmony_ci		trms1040_wait_30us(io_port);
39868c2ecf20Sopenharmony_ci	}
39878c2ecf20Sopenharmony_ci
39888c2ecf20Sopenharmony_ci	/* Disable chip select */
39898c2ecf20Sopenharmony_ci	outb(0, io_port + TRM_S1040_GEN_NVRAM);
39908c2ecf20Sopenharmony_ci	return result;
39918c2ecf20Sopenharmony_ci}
39928c2ecf20Sopenharmony_ci
39938c2ecf20Sopenharmony_ci
39948c2ecf20Sopenharmony_ci/**
39958c2ecf20Sopenharmony_ci * trms1040_read_all - read all bytes from the eeprom
39968c2ecf20Sopenharmony_ci *
39978c2ecf20Sopenharmony_ci * Read the 128 bytes from the SEEPROM.
39988c2ecf20Sopenharmony_ci *
39998c2ecf20Sopenharmony_ci * @eeprom:	where to store the data
40008c2ecf20Sopenharmony_ci * @io_port:	the base io port
40018c2ecf20Sopenharmony_ci **/
40028c2ecf20Sopenharmony_cistatic void trms1040_read_all(struct NvRamType *eeprom, unsigned long io_port)
40038c2ecf20Sopenharmony_ci{
40048c2ecf20Sopenharmony_ci	u8 *b_eeprom = (u8 *)eeprom;
40058c2ecf20Sopenharmony_ci	u8 addr;
40068c2ecf20Sopenharmony_ci
40078c2ecf20Sopenharmony_ci	/* Enable SEEPROM */
40088c2ecf20Sopenharmony_ci	outb((inb(io_port + TRM_S1040_GEN_CONTROL) | EN_EEPROM),
40098c2ecf20Sopenharmony_ci	     io_port + TRM_S1040_GEN_CONTROL);
40108c2ecf20Sopenharmony_ci
40118c2ecf20Sopenharmony_ci	/* read details */
40128c2ecf20Sopenharmony_ci	for (addr = 0; addr < 128; addr++, b_eeprom++)
40138c2ecf20Sopenharmony_ci		*b_eeprom = trms1040_get_data(io_port, addr);
40148c2ecf20Sopenharmony_ci
40158c2ecf20Sopenharmony_ci	/* Disable SEEPROM */
40168c2ecf20Sopenharmony_ci	outb((inb(io_port + TRM_S1040_GEN_CONTROL) & ~EN_EEPROM),
40178c2ecf20Sopenharmony_ci	     io_port + TRM_S1040_GEN_CONTROL);
40188c2ecf20Sopenharmony_ci}
40198c2ecf20Sopenharmony_ci
40208c2ecf20Sopenharmony_ci
40218c2ecf20Sopenharmony_ci
40228c2ecf20Sopenharmony_ci/**
40238c2ecf20Sopenharmony_ci * check_eeprom - get and check contents of the eeprom
40248c2ecf20Sopenharmony_ci *
40258c2ecf20Sopenharmony_ci * Read seeprom 128 bytes into the memory provider in eeprom.
40268c2ecf20Sopenharmony_ci * Checks the checksum and if it's not correct it uses a set of default
40278c2ecf20Sopenharmony_ci * values.
40288c2ecf20Sopenharmony_ci *
40298c2ecf20Sopenharmony_ci * @eeprom:	caller allocated strcuture to read the eeprom data into
40308c2ecf20Sopenharmony_ci * @io_port:	io port to read from
40318c2ecf20Sopenharmony_ci **/
40328c2ecf20Sopenharmony_cistatic void check_eeprom(struct NvRamType *eeprom, unsigned long io_port)
40338c2ecf20Sopenharmony_ci{
40348c2ecf20Sopenharmony_ci	u16 *w_eeprom = (u16 *)eeprom;
40358c2ecf20Sopenharmony_ci	u16 w_addr;
40368c2ecf20Sopenharmony_ci	u16 cksum;
40378c2ecf20Sopenharmony_ci	u32 d_addr;
40388c2ecf20Sopenharmony_ci	u32 *d_eeprom;
40398c2ecf20Sopenharmony_ci
40408c2ecf20Sopenharmony_ci	trms1040_read_all(eeprom, io_port);	/* read eeprom */
40418c2ecf20Sopenharmony_ci
40428c2ecf20Sopenharmony_ci	cksum = 0;
40438c2ecf20Sopenharmony_ci	for (w_addr = 0, w_eeprom = (u16 *)eeprom; w_addr < 64;
40448c2ecf20Sopenharmony_ci	     w_addr++, w_eeprom++)
40458c2ecf20Sopenharmony_ci		cksum += *w_eeprom;
40468c2ecf20Sopenharmony_ci	if (cksum != 0x1234) {
40478c2ecf20Sopenharmony_ci		/*
40488c2ecf20Sopenharmony_ci		 * Checksum is wrong.
40498c2ecf20Sopenharmony_ci		 * Load a set of defaults into the eeprom buffer
40508c2ecf20Sopenharmony_ci		 */
40518c2ecf20Sopenharmony_ci		dprintkl(KERN_WARNING,
40528c2ecf20Sopenharmony_ci			"EEProm checksum error: using default values and options.\n");
40538c2ecf20Sopenharmony_ci		eeprom->sub_vendor_id[0] = (u8)PCI_VENDOR_ID_TEKRAM;
40548c2ecf20Sopenharmony_ci		eeprom->sub_vendor_id[1] = (u8)(PCI_VENDOR_ID_TEKRAM >> 8);
40558c2ecf20Sopenharmony_ci		eeprom->sub_sys_id[0] = (u8)PCI_DEVICE_ID_TEKRAM_TRMS1040;
40568c2ecf20Sopenharmony_ci		eeprom->sub_sys_id[1] =
40578c2ecf20Sopenharmony_ci		    (u8)(PCI_DEVICE_ID_TEKRAM_TRMS1040 >> 8);
40588c2ecf20Sopenharmony_ci		eeprom->sub_class = 0x00;
40598c2ecf20Sopenharmony_ci		eeprom->vendor_id[0] = (u8)PCI_VENDOR_ID_TEKRAM;
40608c2ecf20Sopenharmony_ci		eeprom->vendor_id[1] = (u8)(PCI_VENDOR_ID_TEKRAM >> 8);
40618c2ecf20Sopenharmony_ci		eeprom->device_id[0] = (u8)PCI_DEVICE_ID_TEKRAM_TRMS1040;
40628c2ecf20Sopenharmony_ci		eeprom->device_id[1] =
40638c2ecf20Sopenharmony_ci		    (u8)(PCI_DEVICE_ID_TEKRAM_TRMS1040 >> 8);
40648c2ecf20Sopenharmony_ci		eeprom->reserved = 0x00;
40658c2ecf20Sopenharmony_ci
40668c2ecf20Sopenharmony_ci		for (d_addr = 0, d_eeprom = (u32 *)eeprom->target;
40678c2ecf20Sopenharmony_ci		     d_addr < 16; d_addr++, d_eeprom++)
40688c2ecf20Sopenharmony_ci			*d_eeprom = 0x00000077;	/* cfg3,cfg2,period,cfg0 */
40698c2ecf20Sopenharmony_ci
40708c2ecf20Sopenharmony_ci		*d_eeprom++ = 0x04000F07;	/* max_tag,delay_time,channel_cfg,scsi_id */
40718c2ecf20Sopenharmony_ci		*d_eeprom++ = 0x00000015;	/* reserved1,boot_lun,boot_target,reserved0 */
40728c2ecf20Sopenharmony_ci		for (d_addr = 0; d_addr < 12; d_addr++, d_eeprom++)
40738c2ecf20Sopenharmony_ci			*d_eeprom = 0x00;
40748c2ecf20Sopenharmony_ci
40758c2ecf20Sopenharmony_ci		/* Now load defaults (maybe set by boot/module params) */
40768c2ecf20Sopenharmony_ci		set_safe_settings();
40778c2ecf20Sopenharmony_ci		fix_settings();
40788c2ecf20Sopenharmony_ci		eeprom_override(eeprom);
40798c2ecf20Sopenharmony_ci
40808c2ecf20Sopenharmony_ci		eeprom->cksum = 0x00;
40818c2ecf20Sopenharmony_ci		for (w_addr = 0, cksum = 0, w_eeprom = (u16 *)eeprom;
40828c2ecf20Sopenharmony_ci		     w_addr < 63; w_addr++, w_eeprom++)
40838c2ecf20Sopenharmony_ci			cksum += *w_eeprom;
40848c2ecf20Sopenharmony_ci
40858c2ecf20Sopenharmony_ci		*w_eeprom = 0x1234 - cksum;
40868c2ecf20Sopenharmony_ci		trms1040_write_all(eeprom, io_port);
40878c2ecf20Sopenharmony_ci		eeprom->delay_time = cfg_data[CFG_RESET_DELAY].value;
40888c2ecf20Sopenharmony_ci	} else {
40898c2ecf20Sopenharmony_ci		set_safe_settings();
40908c2ecf20Sopenharmony_ci		eeprom_index_to_delay(eeprom);
40918c2ecf20Sopenharmony_ci		eeprom_override(eeprom);
40928c2ecf20Sopenharmony_ci	}
40938c2ecf20Sopenharmony_ci}
40948c2ecf20Sopenharmony_ci
40958c2ecf20Sopenharmony_ci
40968c2ecf20Sopenharmony_ci/**
40978c2ecf20Sopenharmony_ci * print_eeprom_settings - output the eeprom settings
40988c2ecf20Sopenharmony_ci * to the kernel log so people can see what they were.
40998c2ecf20Sopenharmony_ci *
41008c2ecf20Sopenharmony_ci * @eeprom: The eeprom data strucutre to show details for.
41018c2ecf20Sopenharmony_ci **/
41028c2ecf20Sopenharmony_cistatic void print_eeprom_settings(struct NvRamType *eeprom)
41038c2ecf20Sopenharmony_ci{
41048c2ecf20Sopenharmony_ci	dprintkl(KERN_INFO, "Used settings: AdapterID=%02i, Speed=%i(%02i.%01iMHz), dev_mode=0x%02x\n",
41058c2ecf20Sopenharmony_ci		eeprom->scsi_id,
41068c2ecf20Sopenharmony_ci		eeprom->target[0].period,
41078c2ecf20Sopenharmony_ci		clock_speed[eeprom->target[0].period] / 10,
41088c2ecf20Sopenharmony_ci		clock_speed[eeprom->target[0].period] % 10,
41098c2ecf20Sopenharmony_ci		eeprom->target[0].cfg0);
41108c2ecf20Sopenharmony_ci	dprintkl(KERN_INFO, "               AdaptMode=0x%02x, Tags=%i(%02i), DelayReset=%is\n",
41118c2ecf20Sopenharmony_ci		eeprom->channel_cfg, eeprom->max_tag,
41128c2ecf20Sopenharmony_ci		1 << eeprom->max_tag, eeprom->delay_time);
41138c2ecf20Sopenharmony_ci}
41148c2ecf20Sopenharmony_ci
41158c2ecf20Sopenharmony_ci
41168c2ecf20Sopenharmony_ci/* Free SG tables */
41178c2ecf20Sopenharmony_cistatic void adapter_sg_tables_free(struct AdapterCtlBlk *acb)
41188c2ecf20Sopenharmony_ci{
41198c2ecf20Sopenharmony_ci	int i;
41208c2ecf20Sopenharmony_ci	const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN;
41218c2ecf20Sopenharmony_ci
41228c2ecf20Sopenharmony_ci	for (i = 0; i < DC395x_MAX_SRB_CNT; i += srbs_per_page)
41238c2ecf20Sopenharmony_ci		kfree(acb->srb_array[i].segment_x);
41248c2ecf20Sopenharmony_ci}
41258c2ecf20Sopenharmony_ci
41268c2ecf20Sopenharmony_ci
41278c2ecf20Sopenharmony_ci/*
41288c2ecf20Sopenharmony_ci * Allocate SG tables; as we have to pci_map them, an SG list (struct SGentry*)
41298c2ecf20Sopenharmony_ci * should never cross a page boundary */
41308c2ecf20Sopenharmony_cistatic int adapter_sg_tables_alloc(struct AdapterCtlBlk *acb)
41318c2ecf20Sopenharmony_ci{
41328c2ecf20Sopenharmony_ci	const unsigned mem_needed = (DC395x_MAX_SRB_CNT+1)
41338c2ecf20Sopenharmony_ci	                            *SEGMENTX_LEN;
41348c2ecf20Sopenharmony_ci	int pages = (mem_needed+(PAGE_SIZE-1))/PAGE_SIZE;
41358c2ecf20Sopenharmony_ci	const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN;
41368c2ecf20Sopenharmony_ci	int srb_idx = 0;
41378c2ecf20Sopenharmony_ci	unsigned i = 0;
41388c2ecf20Sopenharmony_ci	struct SGentry *ptr;
41398c2ecf20Sopenharmony_ci
41408c2ecf20Sopenharmony_ci	for (i = 0; i < DC395x_MAX_SRB_CNT; i++)
41418c2ecf20Sopenharmony_ci		acb->srb_array[i].segment_x = NULL;
41428c2ecf20Sopenharmony_ci
41438c2ecf20Sopenharmony_ci	dprintkdbg(DBG_1, "Allocate %i pages for SG tables\n", pages);
41448c2ecf20Sopenharmony_ci	while (pages--) {
41458c2ecf20Sopenharmony_ci		ptr = kmalloc(PAGE_SIZE, GFP_KERNEL);
41468c2ecf20Sopenharmony_ci		if (!ptr) {
41478c2ecf20Sopenharmony_ci			adapter_sg_tables_free(acb);
41488c2ecf20Sopenharmony_ci			return 1;
41498c2ecf20Sopenharmony_ci		}
41508c2ecf20Sopenharmony_ci		dprintkdbg(DBG_1, "Allocate %li bytes at %p for SG segments %i\n",
41518c2ecf20Sopenharmony_ci			PAGE_SIZE, ptr, srb_idx);
41528c2ecf20Sopenharmony_ci		i = 0;
41538c2ecf20Sopenharmony_ci		while (i < srbs_per_page && srb_idx < DC395x_MAX_SRB_CNT)
41548c2ecf20Sopenharmony_ci			acb->srb_array[srb_idx++].segment_x =
41558c2ecf20Sopenharmony_ci			    ptr + (i++ * DC395x_MAX_SG_LISTENTRY);
41568c2ecf20Sopenharmony_ci	}
41578c2ecf20Sopenharmony_ci	if (i < srbs_per_page)
41588c2ecf20Sopenharmony_ci		acb->srb.segment_x =
41598c2ecf20Sopenharmony_ci		    ptr + (i * DC395x_MAX_SG_LISTENTRY);
41608c2ecf20Sopenharmony_ci	else
41618c2ecf20Sopenharmony_ci		dprintkl(KERN_DEBUG, "No space for tmsrb SG table reserved?!\n");
41628c2ecf20Sopenharmony_ci	return 0;
41638c2ecf20Sopenharmony_ci}
41648c2ecf20Sopenharmony_ci
41658c2ecf20Sopenharmony_ci
41668c2ecf20Sopenharmony_ci
41678c2ecf20Sopenharmony_ci/**
41688c2ecf20Sopenharmony_ci * adapter_print_config - print adapter connection and termination
41698c2ecf20Sopenharmony_ci * config
41708c2ecf20Sopenharmony_ci *
41718c2ecf20Sopenharmony_ci * The io port in the adapter needs to have been set before calling
41728c2ecf20Sopenharmony_ci * this function.
41738c2ecf20Sopenharmony_ci *
41748c2ecf20Sopenharmony_ci * @acb: The adapter to print the information for.
41758c2ecf20Sopenharmony_ci **/
41768c2ecf20Sopenharmony_cistatic void adapter_print_config(struct AdapterCtlBlk *acb)
41778c2ecf20Sopenharmony_ci{
41788c2ecf20Sopenharmony_ci	u8 bval;
41798c2ecf20Sopenharmony_ci
41808c2ecf20Sopenharmony_ci	bval = DC395x_read8(acb, TRM_S1040_GEN_STATUS);
41818c2ecf20Sopenharmony_ci	dprintkl(KERN_INFO, "%sConnectors: ",
41828c2ecf20Sopenharmony_ci		((bval & WIDESCSI) ? "(Wide) " : ""));
41838c2ecf20Sopenharmony_ci	if (!(bval & CON5068))
41848c2ecf20Sopenharmony_ci		printk("ext%s ", !(bval & EXT68HIGH) ? "68" : "50");
41858c2ecf20Sopenharmony_ci	if (!(bval & CON68))
41868c2ecf20Sopenharmony_ci		printk("int68%s ", !(bval & INT68HIGH) ? "" : "(50)");
41878c2ecf20Sopenharmony_ci	if (!(bval & CON50))
41888c2ecf20Sopenharmony_ci		printk("int50 ");
41898c2ecf20Sopenharmony_ci	if ((bval & (CON5068 | CON50 | CON68)) ==
41908c2ecf20Sopenharmony_ci	    0 /*(CON5068 | CON50 | CON68) */ )
41918c2ecf20Sopenharmony_ci		printk(" Oops! (All 3?) ");
41928c2ecf20Sopenharmony_ci	bval = DC395x_read8(acb, TRM_S1040_GEN_CONTROL);
41938c2ecf20Sopenharmony_ci	printk(" Termination: ");
41948c2ecf20Sopenharmony_ci	if (bval & DIS_TERM)
41958c2ecf20Sopenharmony_ci		printk("Disabled\n");
41968c2ecf20Sopenharmony_ci	else {
41978c2ecf20Sopenharmony_ci		if (bval & AUTOTERM)
41988c2ecf20Sopenharmony_ci			printk("Auto ");
41998c2ecf20Sopenharmony_ci		if (bval & LOW8TERM)
42008c2ecf20Sopenharmony_ci			printk("Low ");
42018c2ecf20Sopenharmony_ci		if (bval & UP8TERM)
42028c2ecf20Sopenharmony_ci			printk("High ");
42038c2ecf20Sopenharmony_ci		printk("\n");
42048c2ecf20Sopenharmony_ci	}
42058c2ecf20Sopenharmony_ci}
42068c2ecf20Sopenharmony_ci
42078c2ecf20Sopenharmony_ci
42088c2ecf20Sopenharmony_ci/**
42098c2ecf20Sopenharmony_ci * adapter_init_params - Initialize the various parameters in the
42108c2ecf20Sopenharmony_ci * adapter structure. Note that the pointer to the scsi_host is set
42118c2ecf20Sopenharmony_ci * early (when this instance is created) and the io_port and irq
42128c2ecf20Sopenharmony_ci * values are set later after they have been reserved. This just gets
42138c2ecf20Sopenharmony_ci * everything set to a good starting position.
42148c2ecf20Sopenharmony_ci *
42158c2ecf20Sopenharmony_ci * The eeprom structure in the adapter needs to have been set before
42168c2ecf20Sopenharmony_ci * calling this function.
42178c2ecf20Sopenharmony_ci *
42188c2ecf20Sopenharmony_ci * @acb: The adapter to initialize.
42198c2ecf20Sopenharmony_ci **/
42208c2ecf20Sopenharmony_cistatic void adapter_init_params(struct AdapterCtlBlk *acb)
42218c2ecf20Sopenharmony_ci{
42228c2ecf20Sopenharmony_ci	struct NvRamType *eeprom = &acb->eeprom;
42238c2ecf20Sopenharmony_ci	int i;
42248c2ecf20Sopenharmony_ci
42258c2ecf20Sopenharmony_ci	/* NOTE: acb->scsi_host is set at scsi_host/acb creation time */
42268c2ecf20Sopenharmony_ci	/* NOTE: acb->io_port_base is set at port registration time */
42278c2ecf20Sopenharmony_ci	/* NOTE: acb->io_port_len is set at port registration time */
42288c2ecf20Sopenharmony_ci
42298c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&acb->dcb_list);
42308c2ecf20Sopenharmony_ci	acb->dcb_run_robin = NULL;
42318c2ecf20Sopenharmony_ci	acb->active_dcb = NULL;
42328c2ecf20Sopenharmony_ci
42338c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&acb->srb_free_list);
42348c2ecf20Sopenharmony_ci	/*  temp SRB for Q tag used or abort command used  */
42358c2ecf20Sopenharmony_ci	acb->tmp_srb = &acb->srb;
42368c2ecf20Sopenharmony_ci	timer_setup(&acb->waiting_timer, waiting_timeout, 0);
42378c2ecf20Sopenharmony_ci	timer_setup(&acb->selto_timer, NULL, 0);
42388c2ecf20Sopenharmony_ci
42398c2ecf20Sopenharmony_ci	acb->srb_count = DC395x_MAX_SRB_CNT;
42408c2ecf20Sopenharmony_ci
42418c2ecf20Sopenharmony_ci	acb->sel_timeout = DC395x_SEL_TIMEOUT;	/* timeout=250ms */
42428c2ecf20Sopenharmony_ci	/* NOTE: acb->irq_level is set at IRQ registration time */
42438c2ecf20Sopenharmony_ci
42448c2ecf20Sopenharmony_ci	acb->tag_max_num = 1 << eeprom->max_tag;
42458c2ecf20Sopenharmony_ci	if (acb->tag_max_num > 30)
42468c2ecf20Sopenharmony_ci		acb->tag_max_num = 30;
42478c2ecf20Sopenharmony_ci
42488c2ecf20Sopenharmony_ci	acb->acb_flag = 0;	/* RESET_DETECT, RESET_DONE, RESET_DEV */
42498c2ecf20Sopenharmony_ci	acb->gmode2 = eeprom->channel_cfg;
42508c2ecf20Sopenharmony_ci	acb->config = 0;	/* NOTE: actually set in adapter_init_chip */
42518c2ecf20Sopenharmony_ci
42528c2ecf20Sopenharmony_ci	if (eeprom->channel_cfg & NAC_SCANLUN)
42538c2ecf20Sopenharmony_ci		acb->lun_chk = 1;
42548c2ecf20Sopenharmony_ci	acb->scan_devices = 1;
42558c2ecf20Sopenharmony_ci
42568c2ecf20Sopenharmony_ci	acb->scsi_host->this_id = eeprom->scsi_id;
42578c2ecf20Sopenharmony_ci	acb->hostid_bit = (1 << acb->scsi_host->this_id);
42588c2ecf20Sopenharmony_ci
42598c2ecf20Sopenharmony_ci	for (i = 0; i < DC395x_MAX_SCSI_ID; i++)
42608c2ecf20Sopenharmony_ci		acb->dcb_map[i] = 0;
42618c2ecf20Sopenharmony_ci
42628c2ecf20Sopenharmony_ci	acb->msg_len = 0;
42638c2ecf20Sopenharmony_ci
42648c2ecf20Sopenharmony_ci	/* link static array of srbs into the srb free list */
42658c2ecf20Sopenharmony_ci	for (i = 0; i < acb->srb_count - 1; i++)
42668c2ecf20Sopenharmony_ci		list_add_tail(&acb->srb_array[i].list, &acb->srb_free_list);
42678c2ecf20Sopenharmony_ci}
42688c2ecf20Sopenharmony_ci
42698c2ecf20Sopenharmony_ci
42708c2ecf20Sopenharmony_ci/**
42718c2ecf20Sopenharmony_ci * adapter_init_host - Initialize the scsi host instance based on
42728c2ecf20Sopenharmony_ci * values that we have already stored in the adapter instance. There's
42738c2ecf20Sopenharmony_ci * some mention that a lot of these are deprecated, so we won't use
42748c2ecf20Sopenharmony_ci * them (we'll use the ones in the adapter instance) but we'll fill
42758c2ecf20Sopenharmony_ci * them in in case something else needs them.
42768c2ecf20Sopenharmony_ci *
42778c2ecf20Sopenharmony_ci * The eeprom structure, irq and io ports in the adapter need to have
42788c2ecf20Sopenharmony_ci * been set before calling this function.
42798c2ecf20Sopenharmony_ci *
42808c2ecf20Sopenharmony_ci * @host: The scsi host instance to fill in the values for.
42818c2ecf20Sopenharmony_ci **/
42828c2ecf20Sopenharmony_cistatic void adapter_init_scsi_host(struct Scsi_Host *host)
42838c2ecf20Sopenharmony_ci{
42848c2ecf20Sopenharmony_ci        struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)host->hostdata;
42858c2ecf20Sopenharmony_ci	struct NvRamType *eeprom = &acb->eeprom;
42868c2ecf20Sopenharmony_ci
42878c2ecf20Sopenharmony_ci	host->max_cmd_len = 24;
42888c2ecf20Sopenharmony_ci	host->can_queue = DC395x_MAX_CMD_QUEUE;
42898c2ecf20Sopenharmony_ci	host->cmd_per_lun = DC395x_MAX_CMD_PER_LUN;
42908c2ecf20Sopenharmony_ci	host->this_id = (int)eeprom->scsi_id;
42918c2ecf20Sopenharmony_ci	host->io_port = acb->io_port_base;
42928c2ecf20Sopenharmony_ci	host->n_io_port = acb->io_port_len;
42938c2ecf20Sopenharmony_ci	host->dma_channel = -1;
42948c2ecf20Sopenharmony_ci	host->unique_id = acb->io_port_base;
42958c2ecf20Sopenharmony_ci	host->irq = acb->irq_level;
42968c2ecf20Sopenharmony_ci	acb->last_reset = jiffies;
42978c2ecf20Sopenharmony_ci
42988c2ecf20Sopenharmony_ci	host->max_id = 16;
42998c2ecf20Sopenharmony_ci	if (host->max_id - 1 == eeprom->scsi_id)
43008c2ecf20Sopenharmony_ci		host->max_id--;
43018c2ecf20Sopenharmony_ci
43028c2ecf20Sopenharmony_ci	if (eeprom->channel_cfg & NAC_SCANLUN)
43038c2ecf20Sopenharmony_ci		host->max_lun = 8;
43048c2ecf20Sopenharmony_ci	else
43058c2ecf20Sopenharmony_ci		host->max_lun = 1;
43068c2ecf20Sopenharmony_ci}
43078c2ecf20Sopenharmony_ci
43088c2ecf20Sopenharmony_ci
43098c2ecf20Sopenharmony_ci/**
43108c2ecf20Sopenharmony_ci * adapter_init_chip - Get the chip into a know state and figure out
43118c2ecf20Sopenharmony_ci * some of the settings that apply to this adapter.
43128c2ecf20Sopenharmony_ci *
43138c2ecf20Sopenharmony_ci * The io port in the adapter needs to have been set before calling
43148c2ecf20Sopenharmony_ci * this function. The config will be configured correctly on return.
43158c2ecf20Sopenharmony_ci *
43168c2ecf20Sopenharmony_ci * @acb: The adapter which we are to init.
43178c2ecf20Sopenharmony_ci **/
43188c2ecf20Sopenharmony_cistatic void adapter_init_chip(struct AdapterCtlBlk *acb)
43198c2ecf20Sopenharmony_ci{
43208c2ecf20Sopenharmony_ci        struct NvRamType *eeprom = &acb->eeprom;
43218c2ecf20Sopenharmony_ci
43228c2ecf20Sopenharmony_ci        /* Mask all the interrupt */
43238c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_DMA_INTEN, 0x00);
43248c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_INTEN, 0x00);
43258c2ecf20Sopenharmony_ci
43268c2ecf20Sopenharmony_ci	/* Reset SCSI module */
43278c2ecf20Sopenharmony_ci	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_RSTMODULE);
43288c2ecf20Sopenharmony_ci
43298c2ecf20Sopenharmony_ci	/* Reset PCI/DMA module */
43308c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_DMA_CONTROL, DMARESETMODULE);
43318c2ecf20Sopenharmony_ci	udelay(20);
43328c2ecf20Sopenharmony_ci
43338c2ecf20Sopenharmony_ci	/* program configuration 0 */
43348c2ecf20Sopenharmony_ci	acb->config = HCC_AUTOTERM | HCC_PARITY;
43358c2ecf20Sopenharmony_ci	if (DC395x_read8(acb, TRM_S1040_GEN_STATUS) & WIDESCSI)
43368c2ecf20Sopenharmony_ci		acb->config |= HCC_WIDE_CARD;
43378c2ecf20Sopenharmony_ci
43388c2ecf20Sopenharmony_ci	if (eeprom->channel_cfg & NAC_POWERON_SCSI_RESET)
43398c2ecf20Sopenharmony_ci		acb->config |= HCC_SCSI_RESET;
43408c2ecf20Sopenharmony_ci
43418c2ecf20Sopenharmony_ci	if (acb->config & HCC_SCSI_RESET) {
43428c2ecf20Sopenharmony_ci		dprintkl(KERN_INFO, "Performing initial SCSI bus reset\n");
43438c2ecf20Sopenharmony_ci		DC395x_write8(acb, TRM_S1040_SCSI_CONTROL, DO_RSTSCSI);
43448c2ecf20Sopenharmony_ci
43458c2ecf20Sopenharmony_ci		/*while (!( DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET )); */
43468c2ecf20Sopenharmony_ci		/*spin_unlock_irq (&io_request_lock); */
43478c2ecf20Sopenharmony_ci		udelay(500);
43488c2ecf20Sopenharmony_ci
43498c2ecf20Sopenharmony_ci		acb->last_reset =
43508c2ecf20Sopenharmony_ci		    jiffies + HZ / 2 +
43518c2ecf20Sopenharmony_ci		    HZ * acb->eeprom.delay_time;
43528c2ecf20Sopenharmony_ci
43538c2ecf20Sopenharmony_ci		/*spin_lock_irq (&io_request_lock); */
43548c2ecf20Sopenharmony_ci	}
43558c2ecf20Sopenharmony_ci}
43568c2ecf20Sopenharmony_ci
43578c2ecf20Sopenharmony_ci
43588c2ecf20Sopenharmony_ci/**
43598c2ecf20Sopenharmony_ci * init_adapter - Grab the resource for the card, setup the adapter
43608c2ecf20Sopenharmony_ci * information, set the card into a known state, create the various
43618c2ecf20Sopenharmony_ci * tables etc etc. This basically gets all adapter information all up
43628c2ecf20Sopenharmony_ci * to date, initialised and gets the chip in sync with it.
43638c2ecf20Sopenharmony_ci *
43648c2ecf20Sopenharmony_ci * @host:	This hosts adapter structure
43658c2ecf20Sopenharmony_ci * @io_port:	The base I/O port
43668c2ecf20Sopenharmony_ci * @irq:	IRQ
43678c2ecf20Sopenharmony_ci *
43688c2ecf20Sopenharmony_ci * Returns 0 if the initialization succeeds, any other value on
43698c2ecf20Sopenharmony_ci * failure.
43708c2ecf20Sopenharmony_ci **/
43718c2ecf20Sopenharmony_cistatic int adapter_init(struct AdapterCtlBlk *acb, unsigned long io_port,
43728c2ecf20Sopenharmony_ci			u32 io_port_len, unsigned int irq)
43738c2ecf20Sopenharmony_ci{
43748c2ecf20Sopenharmony_ci	if (!request_region(io_port, io_port_len, DC395X_NAME)) {
43758c2ecf20Sopenharmony_ci		dprintkl(KERN_ERR, "Failed to reserve IO region 0x%lx\n", io_port);
43768c2ecf20Sopenharmony_ci		goto failed;
43778c2ecf20Sopenharmony_ci	}
43788c2ecf20Sopenharmony_ci	/* store port base to indicate we have registered it */
43798c2ecf20Sopenharmony_ci	acb->io_port_base = io_port;
43808c2ecf20Sopenharmony_ci	acb->io_port_len = io_port_len;
43818c2ecf20Sopenharmony_ci
43828c2ecf20Sopenharmony_ci	if (request_irq(irq, dc395x_interrupt, IRQF_SHARED, DC395X_NAME, acb)) {
43838c2ecf20Sopenharmony_ci	    	/* release the region we just claimed */
43848c2ecf20Sopenharmony_ci		dprintkl(KERN_INFO, "Failed to register IRQ\n");
43858c2ecf20Sopenharmony_ci		goto failed;
43868c2ecf20Sopenharmony_ci	}
43878c2ecf20Sopenharmony_ci	/* store irq to indicate we have registered it */
43888c2ecf20Sopenharmony_ci	acb->irq_level = irq;
43898c2ecf20Sopenharmony_ci
43908c2ecf20Sopenharmony_ci	/* get eeprom configuration information and command line settings etc */
43918c2ecf20Sopenharmony_ci	check_eeprom(&acb->eeprom, io_port);
43928c2ecf20Sopenharmony_ci 	print_eeprom_settings(&acb->eeprom);
43938c2ecf20Sopenharmony_ci
43948c2ecf20Sopenharmony_ci	/* setup adapter control block */
43958c2ecf20Sopenharmony_ci	adapter_init_params(acb);
43968c2ecf20Sopenharmony_ci
43978c2ecf20Sopenharmony_ci	/* display card connectors/termination settings */
43988c2ecf20Sopenharmony_ci 	adapter_print_config(acb);
43998c2ecf20Sopenharmony_ci
44008c2ecf20Sopenharmony_ci	if (adapter_sg_tables_alloc(acb)) {
44018c2ecf20Sopenharmony_ci		dprintkl(KERN_DEBUG, "Memory allocation for SG tables failed\n");
44028c2ecf20Sopenharmony_ci		goto failed;
44038c2ecf20Sopenharmony_ci	}
44048c2ecf20Sopenharmony_ci	adapter_init_scsi_host(acb->scsi_host);
44058c2ecf20Sopenharmony_ci	adapter_init_chip(acb);
44068c2ecf20Sopenharmony_ci	set_basic_config(acb);
44078c2ecf20Sopenharmony_ci
44088c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0,
44098c2ecf20Sopenharmony_ci		"adapter_init: acb=%p, pdcb_map=%p psrb_array=%p "
44108c2ecf20Sopenharmony_ci		"size{acb=0x%04x dcb=0x%04x srb=0x%04x}\n",
44118c2ecf20Sopenharmony_ci		acb, acb->dcb_map, acb->srb_array, sizeof(struct AdapterCtlBlk),
44128c2ecf20Sopenharmony_ci		sizeof(struct DeviceCtlBlk), sizeof(struct ScsiReqBlk));
44138c2ecf20Sopenharmony_ci	return 0;
44148c2ecf20Sopenharmony_ci
44158c2ecf20Sopenharmony_cifailed:
44168c2ecf20Sopenharmony_ci	if (acb->irq_level)
44178c2ecf20Sopenharmony_ci		free_irq(acb->irq_level, acb);
44188c2ecf20Sopenharmony_ci	if (acb->io_port_base)
44198c2ecf20Sopenharmony_ci		release_region(acb->io_port_base, acb->io_port_len);
44208c2ecf20Sopenharmony_ci	adapter_sg_tables_free(acb);
44218c2ecf20Sopenharmony_ci
44228c2ecf20Sopenharmony_ci	return 1;
44238c2ecf20Sopenharmony_ci}
44248c2ecf20Sopenharmony_ci
44258c2ecf20Sopenharmony_ci
44268c2ecf20Sopenharmony_ci/**
44278c2ecf20Sopenharmony_ci * adapter_uninit_chip - cleanly shut down the scsi controller chip,
44288c2ecf20Sopenharmony_ci * stopping all operations and disabling interrupt generation on the
44298c2ecf20Sopenharmony_ci * card.
44308c2ecf20Sopenharmony_ci *
44318c2ecf20Sopenharmony_ci * @acb: The adapter which we are to shutdown.
44328c2ecf20Sopenharmony_ci **/
44338c2ecf20Sopenharmony_cistatic void adapter_uninit_chip(struct AdapterCtlBlk *acb)
44348c2ecf20Sopenharmony_ci{
44358c2ecf20Sopenharmony_ci	/* disable interrupts */
44368c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_DMA_INTEN, 0);
44378c2ecf20Sopenharmony_ci	DC395x_write8(acb, TRM_S1040_SCSI_INTEN, 0);
44388c2ecf20Sopenharmony_ci
44398c2ecf20Sopenharmony_ci	/* reset the scsi bus */
44408c2ecf20Sopenharmony_ci	if (acb->config & HCC_SCSI_RESET)
44418c2ecf20Sopenharmony_ci		reset_scsi_bus(acb);
44428c2ecf20Sopenharmony_ci
44438c2ecf20Sopenharmony_ci	/* clear any pending interrupt state */
44448c2ecf20Sopenharmony_ci	DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS);
44458c2ecf20Sopenharmony_ci}
44468c2ecf20Sopenharmony_ci
44478c2ecf20Sopenharmony_ci
44488c2ecf20Sopenharmony_ci
44498c2ecf20Sopenharmony_ci/**
44508c2ecf20Sopenharmony_ci * adapter_uninit - Shut down the chip and release any resources that
44518c2ecf20Sopenharmony_ci * we had allocated. Once this returns the adapter should not be used
44528c2ecf20Sopenharmony_ci * anymore.
44538c2ecf20Sopenharmony_ci *
44548c2ecf20Sopenharmony_ci * @acb: The adapter which we are to un-initialize.
44558c2ecf20Sopenharmony_ci **/
44568c2ecf20Sopenharmony_cistatic void adapter_uninit(struct AdapterCtlBlk *acb)
44578c2ecf20Sopenharmony_ci{
44588c2ecf20Sopenharmony_ci	unsigned long flags;
44598c2ecf20Sopenharmony_ci	DC395x_LOCK_IO(acb->scsi_host, flags);
44608c2ecf20Sopenharmony_ci
44618c2ecf20Sopenharmony_ci	/* remove timers */
44628c2ecf20Sopenharmony_ci	if (timer_pending(&acb->waiting_timer))
44638c2ecf20Sopenharmony_ci		del_timer(&acb->waiting_timer);
44648c2ecf20Sopenharmony_ci	if (timer_pending(&acb->selto_timer))
44658c2ecf20Sopenharmony_ci		del_timer(&acb->selto_timer);
44668c2ecf20Sopenharmony_ci
44678c2ecf20Sopenharmony_ci	adapter_uninit_chip(acb);
44688c2ecf20Sopenharmony_ci	adapter_remove_and_free_all_devices(acb);
44698c2ecf20Sopenharmony_ci	DC395x_UNLOCK_IO(acb->scsi_host, flags);
44708c2ecf20Sopenharmony_ci
44718c2ecf20Sopenharmony_ci	if (acb->irq_level)
44728c2ecf20Sopenharmony_ci		free_irq(acb->irq_level, acb);
44738c2ecf20Sopenharmony_ci	if (acb->io_port_base)
44748c2ecf20Sopenharmony_ci		release_region(acb->io_port_base, acb->io_port_len);
44758c2ecf20Sopenharmony_ci
44768c2ecf20Sopenharmony_ci	adapter_sg_tables_free(acb);
44778c2ecf20Sopenharmony_ci}
44788c2ecf20Sopenharmony_ci
44798c2ecf20Sopenharmony_ci
44808c2ecf20Sopenharmony_ci#undef YESNO
44818c2ecf20Sopenharmony_ci#define YESNO(YN) \
44828c2ecf20Sopenharmony_ci if (YN) seq_printf(m, " Yes ");\
44838c2ecf20Sopenharmony_ci else seq_printf(m, " No  ")
44848c2ecf20Sopenharmony_ci
44858c2ecf20Sopenharmony_cistatic int dc395x_show_info(struct seq_file *m, struct Scsi_Host *host)
44868c2ecf20Sopenharmony_ci{
44878c2ecf20Sopenharmony_ci	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)host->hostdata;
44888c2ecf20Sopenharmony_ci	int spd, spd1;
44898c2ecf20Sopenharmony_ci	struct DeviceCtlBlk *dcb;
44908c2ecf20Sopenharmony_ci	unsigned long flags;
44918c2ecf20Sopenharmony_ci	int dev;
44928c2ecf20Sopenharmony_ci
44938c2ecf20Sopenharmony_ci	seq_puts(m, DC395X_BANNER " PCI SCSI Host Adapter\n"
44948c2ecf20Sopenharmony_ci		" Driver Version " DC395X_VERSION "\n");
44958c2ecf20Sopenharmony_ci
44968c2ecf20Sopenharmony_ci	DC395x_LOCK_IO(acb->scsi_host, flags);
44978c2ecf20Sopenharmony_ci
44988c2ecf20Sopenharmony_ci	seq_printf(m, "SCSI Host Nr %i, ", host->host_no);
44998c2ecf20Sopenharmony_ci	seq_printf(m, "DC395U/UW/F DC315/U %s\n",
45008c2ecf20Sopenharmony_ci		(acb->config & HCC_WIDE_CARD) ? "Wide" : "");
45018c2ecf20Sopenharmony_ci	seq_printf(m, "io_port_base 0x%04lx, ", acb->io_port_base);
45028c2ecf20Sopenharmony_ci	seq_printf(m, "irq_level 0x%04x, ", acb->irq_level);
45038c2ecf20Sopenharmony_ci	seq_printf(m, " SelTimeout %ims\n", (1638 * acb->sel_timeout) / 1000);
45048c2ecf20Sopenharmony_ci
45058c2ecf20Sopenharmony_ci	seq_printf(m, "MaxID %i, MaxLUN %llu, ", host->max_id, host->max_lun);
45068c2ecf20Sopenharmony_ci	seq_printf(m, "AdapterID %i\n", host->this_id);
45078c2ecf20Sopenharmony_ci
45088c2ecf20Sopenharmony_ci	seq_printf(m, "tag_max_num %i", acb->tag_max_num);
45098c2ecf20Sopenharmony_ci	/*seq_printf(m, ", DMA_Status %i\n", DC395x_read8(acb, TRM_S1040_DMA_STATUS)); */
45108c2ecf20Sopenharmony_ci	seq_printf(m, ", FilterCfg 0x%02x",
45118c2ecf20Sopenharmony_ci		DC395x_read8(acb, TRM_S1040_SCSI_CONFIG1));
45128c2ecf20Sopenharmony_ci	seq_printf(m, ", DelayReset %is\n", acb->eeprom.delay_time);
45138c2ecf20Sopenharmony_ci	/*seq_printf(m, "\n"); */
45148c2ecf20Sopenharmony_ci
45158c2ecf20Sopenharmony_ci	seq_printf(m, "Nr of DCBs: %i\n", list_size(&acb->dcb_list));
45168c2ecf20Sopenharmony_ci	seq_printf(m, "Map of attached LUNs: %8ph\n", &acb->dcb_map[0]);
45178c2ecf20Sopenharmony_ci	seq_printf(m, "                      %8ph\n", &acb->dcb_map[8]);
45188c2ecf20Sopenharmony_ci
45198c2ecf20Sopenharmony_ci	seq_puts(m,
45208c2ecf20Sopenharmony_ci		 "Un ID LUN Prty Sync Wide DsCn SndS TagQ nego_period SyncFreq SyncOffs MaxCmd\n");
45218c2ecf20Sopenharmony_ci
45228c2ecf20Sopenharmony_ci	dev = 0;
45238c2ecf20Sopenharmony_ci	list_for_each_entry(dcb, &acb->dcb_list, list) {
45248c2ecf20Sopenharmony_ci		int nego_period;
45258c2ecf20Sopenharmony_ci		seq_printf(m, "%02i %02i  %02i ", dev, dcb->target_id,
45268c2ecf20Sopenharmony_ci			dcb->target_lun);
45278c2ecf20Sopenharmony_ci		YESNO(dcb->dev_mode & NTC_DO_PARITY_CHK);
45288c2ecf20Sopenharmony_ci		YESNO(dcb->sync_offset);
45298c2ecf20Sopenharmony_ci		YESNO(dcb->sync_period & WIDE_SYNC);
45308c2ecf20Sopenharmony_ci		YESNO(dcb->dev_mode & NTC_DO_DISCONNECT);
45318c2ecf20Sopenharmony_ci		YESNO(dcb->dev_mode & NTC_DO_SEND_START);
45328c2ecf20Sopenharmony_ci		YESNO(dcb->sync_mode & EN_TAG_QUEUEING);
45338c2ecf20Sopenharmony_ci		nego_period = clock_period[dcb->sync_period & 0x07] << 2;
45348c2ecf20Sopenharmony_ci		if (dcb->sync_offset)
45358c2ecf20Sopenharmony_ci			seq_printf(m, "  %03i ns ", nego_period);
45368c2ecf20Sopenharmony_ci		else
45378c2ecf20Sopenharmony_ci			seq_printf(m, " (%03i ns)", (dcb->min_nego_period << 2));
45388c2ecf20Sopenharmony_ci
45398c2ecf20Sopenharmony_ci		if (dcb->sync_offset & 0x0f) {
45408c2ecf20Sopenharmony_ci			spd = 1000 / (nego_period);
45418c2ecf20Sopenharmony_ci			spd1 = 1000 % (nego_period);
45428c2ecf20Sopenharmony_ci			spd1 = (spd1 * 10 + nego_period / 2) / (nego_period);
45438c2ecf20Sopenharmony_ci			seq_printf(m, "   %2i.%1i M     %02i ", spd, spd1,
45448c2ecf20Sopenharmony_ci				(dcb->sync_offset & 0x0f));
45458c2ecf20Sopenharmony_ci		} else
45468c2ecf20Sopenharmony_ci			seq_puts(m, "                 ");
45478c2ecf20Sopenharmony_ci
45488c2ecf20Sopenharmony_ci		/* Add more info ... */
45498c2ecf20Sopenharmony_ci		seq_printf(m, "     %02i\n", dcb->max_command);
45508c2ecf20Sopenharmony_ci		dev++;
45518c2ecf20Sopenharmony_ci	}
45528c2ecf20Sopenharmony_ci
45538c2ecf20Sopenharmony_ci	if (timer_pending(&acb->waiting_timer))
45548c2ecf20Sopenharmony_ci		seq_puts(m, "Waiting queue timer running\n");
45558c2ecf20Sopenharmony_ci	else
45568c2ecf20Sopenharmony_ci		seq_putc(m, '\n');
45578c2ecf20Sopenharmony_ci
45588c2ecf20Sopenharmony_ci	list_for_each_entry(dcb, &acb->dcb_list, list) {
45598c2ecf20Sopenharmony_ci		struct ScsiReqBlk *srb;
45608c2ecf20Sopenharmony_ci		if (!list_empty(&dcb->srb_waiting_list))
45618c2ecf20Sopenharmony_ci			seq_printf(m, "DCB (%02i-%i): Waiting: %i:",
45628c2ecf20Sopenharmony_ci				dcb->target_id, dcb->target_lun,
45638c2ecf20Sopenharmony_ci				list_size(&dcb->srb_waiting_list));
45648c2ecf20Sopenharmony_ci                list_for_each_entry(srb, &dcb->srb_waiting_list, list)
45658c2ecf20Sopenharmony_ci			seq_printf(m, " %p", srb->cmd);
45668c2ecf20Sopenharmony_ci		if (!list_empty(&dcb->srb_going_list))
45678c2ecf20Sopenharmony_ci			seq_printf(m, "\nDCB (%02i-%i): Going  : %i:",
45688c2ecf20Sopenharmony_ci				dcb->target_id, dcb->target_lun,
45698c2ecf20Sopenharmony_ci				list_size(&dcb->srb_going_list));
45708c2ecf20Sopenharmony_ci		list_for_each_entry(srb, &dcb->srb_going_list, list)
45718c2ecf20Sopenharmony_ci			seq_printf(m, " %p", srb->cmd);
45728c2ecf20Sopenharmony_ci		if (!list_empty(&dcb->srb_waiting_list) || !list_empty(&dcb->srb_going_list))
45738c2ecf20Sopenharmony_ci			seq_putc(m, '\n');
45748c2ecf20Sopenharmony_ci	}
45758c2ecf20Sopenharmony_ci
45768c2ecf20Sopenharmony_ci	if (debug_enabled(DBG_1)) {
45778c2ecf20Sopenharmony_ci		seq_printf(m, "DCB list for ACB %p:\n", acb);
45788c2ecf20Sopenharmony_ci		list_for_each_entry(dcb, &acb->dcb_list, list) {
45798c2ecf20Sopenharmony_ci			seq_printf(m, "%p -> ", dcb);
45808c2ecf20Sopenharmony_ci		}
45818c2ecf20Sopenharmony_ci		seq_puts(m, "END\n");
45828c2ecf20Sopenharmony_ci	}
45838c2ecf20Sopenharmony_ci
45848c2ecf20Sopenharmony_ci	DC395x_UNLOCK_IO(acb->scsi_host, flags);
45858c2ecf20Sopenharmony_ci	return 0;
45868c2ecf20Sopenharmony_ci}
45878c2ecf20Sopenharmony_ci
45888c2ecf20Sopenharmony_ci
45898c2ecf20Sopenharmony_cistatic struct scsi_host_template dc395x_driver_template = {
45908c2ecf20Sopenharmony_ci	.module                 = THIS_MODULE,
45918c2ecf20Sopenharmony_ci	.proc_name              = DC395X_NAME,
45928c2ecf20Sopenharmony_ci	.show_info              = dc395x_show_info,
45938c2ecf20Sopenharmony_ci	.name                   = DC395X_BANNER " " DC395X_VERSION,
45948c2ecf20Sopenharmony_ci	.queuecommand           = dc395x_queue_command,
45958c2ecf20Sopenharmony_ci	.slave_alloc            = dc395x_slave_alloc,
45968c2ecf20Sopenharmony_ci	.slave_destroy          = dc395x_slave_destroy,
45978c2ecf20Sopenharmony_ci	.can_queue              = DC395x_MAX_CAN_QUEUE,
45988c2ecf20Sopenharmony_ci	.this_id                = 7,
45998c2ecf20Sopenharmony_ci	.sg_tablesize           = DC395x_MAX_SG_TABLESIZE,
46008c2ecf20Sopenharmony_ci	.cmd_per_lun            = DC395x_MAX_CMD_PER_LUN,
46018c2ecf20Sopenharmony_ci	.eh_abort_handler       = dc395x_eh_abort,
46028c2ecf20Sopenharmony_ci	.eh_bus_reset_handler   = dc395x_eh_bus_reset,
46038c2ecf20Sopenharmony_ci	.dma_boundary		= PAGE_SIZE - 1,
46048c2ecf20Sopenharmony_ci};
46058c2ecf20Sopenharmony_ci
46068c2ecf20Sopenharmony_ci
46078c2ecf20Sopenharmony_ci/**
46088c2ecf20Sopenharmony_ci * banner_display - Display banner on first instance of driver
46098c2ecf20Sopenharmony_ci * initialized.
46108c2ecf20Sopenharmony_ci **/
46118c2ecf20Sopenharmony_cistatic void banner_display(void)
46128c2ecf20Sopenharmony_ci{
46138c2ecf20Sopenharmony_ci	static int banner_done = 0;
46148c2ecf20Sopenharmony_ci	if (!banner_done)
46158c2ecf20Sopenharmony_ci	{
46168c2ecf20Sopenharmony_ci		dprintkl(KERN_INFO, "%s %s\n", DC395X_BANNER, DC395X_VERSION);
46178c2ecf20Sopenharmony_ci		banner_done = 1;
46188c2ecf20Sopenharmony_ci	}
46198c2ecf20Sopenharmony_ci}
46208c2ecf20Sopenharmony_ci
46218c2ecf20Sopenharmony_ci
46228c2ecf20Sopenharmony_ci/**
46238c2ecf20Sopenharmony_ci * dc395x_init_one - Initialise a single instance of the adapter.
46248c2ecf20Sopenharmony_ci *
46258c2ecf20Sopenharmony_ci * The PCI layer will call this once for each instance of the adapter
46268c2ecf20Sopenharmony_ci * that it finds in the system. The pci_dev strcuture indicates which
46278c2ecf20Sopenharmony_ci * instance we are being called from.
46288c2ecf20Sopenharmony_ci *
46298c2ecf20Sopenharmony_ci * @dev: The PCI device to initialize.
46308c2ecf20Sopenharmony_ci * @id: Looks like a pointer to the entry in our pci device table
46318c2ecf20Sopenharmony_ci * that was actually matched by the PCI subsystem.
46328c2ecf20Sopenharmony_ci *
46338c2ecf20Sopenharmony_ci * Returns 0 on success, or an error code (-ve) on failure.
46348c2ecf20Sopenharmony_ci **/
46358c2ecf20Sopenharmony_cistatic int dc395x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
46368c2ecf20Sopenharmony_ci{
46378c2ecf20Sopenharmony_ci	struct Scsi_Host *scsi_host = NULL;
46388c2ecf20Sopenharmony_ci	struct AdapterCtlBlk *acb = NULL;
46398c2ecf20Sopenharmony_ci	unsigned long io_port_base;
46408c2ecf20Sopenharmony_ci	unsigned int io_port_len;
46418c2ecf20Sopenharmony_ci	unsigned int irq;
46428c2ecf20Sopenharmony_ci
46438c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "Init one instance (%s)\n", pci_name(dev));
46448c2ecf20Sopenharmony_ci	banner_display();
46458c2ecf20Sopenharmony_ci
46468c2ecf20Sopenharmony_ci	if (pci_enable_device(dev))
46478c2ecf20Sopenharmony_ci	{
46488c2ecf20Sopenharmony_ci		dprintkl(KERN_INFO, "PCI Enable device failed.\n");
46498c2ecf20Sopenharmony_ci		return -ENODEV;
46508c2ecf20Sopenharmony_ci	}
46518c2ecf20Sopenharmony_ci	io_port_base = pci_resource_start(dev, 0) & PCI_BASE_ADDRESS_IO_MASK;
46528c2ecf20Sopenharmony_ci	io_port_len = pci_resource_len(dev, 0);
46538c2ecf20Sopenharmony_ci	irq = dev->irq;
46548c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "IO_PORT=0x%04lx, IRQ=0x%x\n", io_port_base, dev->irq);
46558c2ecf20Sopenharmony_ci
46568c2ecf20Sopenharmony_ci	/* allocate scsi host information (includes out adapter) */
46578c2ecf20Sopenharmony_ci	scsi_host = scsi_host_alloc(&dc395x_driver_template,
46588c2ecf20Sopenharmony_ci				    sizeof(struct AdapterCtlBlk));
46598c2ecf20Sopenharmony_ci	if (!scsi_host) {
46608c2ecf20Sopenharmony_ci		dprintkl(KERN_INFO, "scsi_host_alloc failed\n");
46618c2ecf20Sopenharmony_ci		goto fail;
46628c2ecf20Sopenharmony_ci	}
46638c2ecf20Sopenharmony_ci 	acb = (struct AdapterCtlBlk*)scsi_host->hostdata;
46648c2ecf20Sopenharmony_ci 	acb->scsi_host = scsi_host;
46658c2ecf20Sopenharmony_ci 	acb->dev = dev;
46668c2ecf20Sopenharmony_ci
46678c2ecf20Sopenharmony_ci	/* initialise the adapter and everything we need */
46688c2ecf20Sopenharmony_ci 	if (adapter_init(acb, io_port_base, io_port_len, irq)) {
46698c2ecf20Sopenharmony_ci		dprintkl(KERN_INFO, "adapter init failed\n");
46708c2ecf20Sopenharmony_ci		acb = NULL;
46718c2ecf20Sopenharmony_ci		goto fail;
46728c2ecf20Sopenharmony_ci	}
46738c2ecf20Sopenharmony_ci
46748c2ecf20Sopenharmony_ci	pci_set_master(dev);
46758c2ecf20Sopenharmony_ci
46768c2ecf20Sopenharmony_ci	/* get the scsi mid level to scan for new devices on the bus */
46778c2ecf20Sopenharmony_ci	if (scsi_add_host(scsi_host, &dev->dev)) {
46788c2ecf20Sopenharmony_ci		dprintkl(KERN_ERR, "scsi_add_host failed\n");
46798c2ecf20Sopenharmony_ci		goto fail;
46808c2ecf20Sopenharmony_ci	}
46818c2ecf20Sopenharmony_ci	pci_set_drvdata(dev, scsi_host);
46828c2ecf20Sopenharmony_ci	scsi_scan_host(scsi_host);
46838c2ecf20Sopenharmony_ci
46848c2ecf20Sopenharmony_ci	return 0;
46858c2ecf20Sopenharmony_ci
46868c2ecf20Sopenharmony_cifail:
46878c2ecf20Sopenharmony_ci	if (acb != NULL)
46888c2ecf20Sopenharmony_ci		adapter_uninit(acb);
46898c2ecf20Sopenharmony_ci	if (scsi_host != NULL)
46908c2ecf20Sopenharmony_ci		scsi_host_put(scsi_host);
46918c2ecf20Sopenharmony_ci	pci_disable_device(dev);
46928c2ecf20Sopenharmony_ci	return -ENODEV;
46938c2ecf20Sopenharmony_ci}
46948c2ecf20Sopenharmony_ci
46958c2ecf20Sopenharmony_ci
46968c2ecf20Sopenharmony_ci/**
46978c2ecf20Sopenharmony_ci * dc395x_remove_one - Called to remove a single instance of the
46988c2ecf20Sopenharmony_ci * adapter.
46998c2ecf20Sopenharmony_ci *
47008c2ecf20Sopenharmony_ci * @dev: The PCI device to initialize.
47018c2ecf20Sopenharmony_ci **/
47028c2ecf20Sopenharmony_cistatic void dc395x_remove_one(struct pci_dev *dev)
47038c2ecf20Sopenharmony_ci{
47048c2ecf20Sopenharmony_ci	struct Scsi_Host *scsi_host = pci_get_drvdata(dev);
47058c2ecf20Sopenharmony_ci	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)(scsi_host->hostdata);
47068c2ecf20Sopenharmony_ci
47078c2ecf20Sopenharmony_ci	dprintkdbg(DBG_0, "dc395x_remove_one: acb=%p\n", acb);
47088c2ecf20Sopenharmony_ci
47098c2ecf20Sopenharmony_ci	scsi_remove_host(scsi_host);
47108c2ecf20Sopenharmony_ci	adapter_uninit(acb);
47118c2ecf20Sopenharmony_ci	pci_disable_device(dev);
47128c2ecf20Sopenharmony_ci	scsi_host_put(scsi_host);
47138c2ecf20Sopenharmony_ci}
47148c2ecf20Sopenharmony_ci
47158c2ecf20Sopenharmony_ci
47168c2ecf20Sopenharmony_cistatic struct pci_device_id dc395x_pci_table[] = {
47178c2ecf20Sopenharmony_ci	{
47188c2ecf20Sopenharmony_ci		.vendor		= PCI_VENDOR_ID_TEKRAM,
47198c2ecf20Sopenharmony_ci		.device		= PCI_DEVICE_ID_TEKRAM_TRMS1040,
47208c2ecf20Sopenharmony_ci		.subvendor	= PCI_ANY_ID,
47218c2ecf20Sopenharmony_ci		.subdevice	= PCI_ANY_ID,
47228c2ecf20Sopenharmony_ci	 },
47238c2ecf20Sopenharmony_ci	{}			/* Terminating entry */
47248c2ecf20Sopenharmony_ci};
47258c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, dc395x_pci_table);
47268c2ecf20Sopenharmony_ci
47278c2ecf20Sopenharmony_ci
47288c2ecf20Sopenharmony_cistatic struct pci_driver dc395x_driver = {
47298c2ecf20Sopenharmony_ci	.name           = DC395X_NAME,
47308c2ecf20Sopenharmony_ci	.id_table       = dc395x_pci_table,
47318c2ecf20Sopenharmony_ci	.probe          = dc395x_init_one,
47328c2ecf20Sopenharmony_ci	.remove         = dc395x_remove_one,
47338c2ecf20Sopenharmony_ci};
47348c2ecf20Sopenharmony_cimodule_pci_driver(dc395x_driver);
47358c2ecf20Sopenharmony_ci
47368c2ecf20Sopenharmony_ciMODULE_AUTHOR("C.L. Huang / Erich Chen / Kurt Garloff");
47378c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SCSI host adapter driver for Tekram TRM-S1040 based adapters: Tekram DC395 and DC315 series");
47388c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
4739