18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/***************************************************************************
38c2ecf20Sopenharmony_ci                          dpti.c  -  description
48c2ecf20Sopenharmony_ci                             -------------------
58c2ecf20Sopenharmony_ci    begin                : Thu Sep 7 2000
68c2ecf20Sopenharmony_ci    copyright            : (C) 2000 by Adaptec
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci			   July 30, 2001 First version being submitted
98c2ecf20Sopenharmony_ci			   for inclusion in the kernel.  V2.4
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci    See Documentation/scsi/dpti.rst for history, notes, license info
128c2ecf20Sopenharmony_ci    and credits
138c2ecf20Sopenharmony_ci ***************************************************************************/
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci/***************************************************************************
168c2ecf20Sopenharmony_ci *                                                                         *
178c2ecf20Sopenharmony_ci *                                                                         *
188c2ecf20Sopenharmony_ci ***************************************************************************/
198c2ecf20Sopenharmony_ci/***************************************************************************
208c2ecf20Sopenharmony_ci * Sat Dec 20 2003 Go Taniguchi <go@turbolinux.co.jp>
218c2ecf20Sopenharmony_ci - Support 2.6 kernel and DMA-mapping
228c2ecf20Sopenharmony_ci - ioctl fix for raid tools
238c2ecf20Sopenharmony_ci - use schedule_timeout in long long loop
248c2ecf20Sopenharmony_ci **************************************************************************/
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/*#define DEBUG 1 */
278c2ecf20Sopenharmony_ci/*#define UARTDELAY 1 */
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#include <linux/module.h>
308c2ecf20Sopenharmony_ci#include <linux/pgtable.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ciMODULE_AUTHOR("Deanna Bonds, with _lots_ of help from Mark Salyzyn");
338c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Adaptec I2O RAID Driver");
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci////////////////////////////////////////////////////////////////
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#include <linux/ioctl.h>	/* For SCSI-Passthrough */
388c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#include <linux/stat.h>
418c2ecf20Sopenharmony_ci#include <linux/slab.h>		/* for kmalloc() */
428c2ecf20Sopenharmony_ci#include <linux/pci.h>		/* for PCI support */
438c2ecf20Sopenharmony_ci#include <linux/proc_fs.h>
448c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
458c2ecf20Sopenharmony_ci#include <linux/delay.h>	/* for udelay */
468c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
478c2ecf20Sopenharmony_ci#include <linux/kernel.h>	/* for printk */
488c2ecf20Sopenharmony_ci#include <linux/sched.h>
498c2ecf20Sopenharmony_ci#include <linux/reboot.h>
508c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
518c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#include <linux/timer.h>
548c2ecf20Sopenharmony_ci#include <linux/string.h>
558c2ecf20Sopenharmony_ci#include <linux/ioport.h>
568c2ecf20Sopenharmony_ci#include <linux/mutex.h>
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci#include <asm/processor.h>	/* for boot_cpu_data */
598c2ecf20Sopenharmony_ci#include <asm/io.h>
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci#include <scsi/scsi.h>
628c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h>
638c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h>
648c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h>
658c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h>
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci#include "dpt/dptsig.h"
688c2ecf20Sopenharmony_ci#include "dpti.h"
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci/*============================================================================
718c2ecf20Sopenharmony_ci * Create a binary signature - this is read by dptsig
728c2ecf20Sopenharmony_ci * Needed for our management apps
738c2ecf20Sopenharmony_ci *============================================================================
748c2ecf20Sopenharmony_ci */
758c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(adpt_mutex);
768c2ecf20Sopenharmony_cistatic dpt_sig_S DPTI_sig = {
778c2ecf20Sopenharmony_ci	{'d', 'P', 't', 'S', 'i', 'G'}, SIG_VERSION,
788c2ecf20Sopenharmony_ci#ifdef __i386__
798c2ecf20Sopenharmony_ci	PROC_INTEL, PROC_386 | PROC_486 | PROC_PENTIUM | PROC_SEXIUM,
808c2ecf20Sopenharmony_ci#elif defined(__ia64__)
818c2ecf20Sopenharmony_ci	PROC_INTEL, PROC_IA64,
828c2ecf20Sopenharmony_ci#elif defined(__sparc__)
838c2ecf20Sopenharmony_ci	PROC_ULTRASPARC, PROC_ULTRASPARC,
848c2ecf20Sopenharmony_ci#elif defined(__alpha__)
858c2ecf20Sopenharmony_ci	PROC_ALPHA, PROC_ALPHA,
868c2ecf20Sopenharmony_ci#else
878c2ecf20Sopenharmony_ci	(-1),(-1),
888c2ecf20Sopenharmony_ci#endif
898c2ecf20Sopenharmony_ci	 FT_HBADRVR, 0, OEM_DPT, OS_LINUX, CAP_OVERLAP, DEV_ALL,
908c2ecf20Sopenharmony_ci	ADF_ALL_SC5, 0, 0, DPT_VERSION, DPT_REVISION, DPT_SUBREVISION,
918c2ecf20Sopenharmony_ci	DPT_MONTH, DPT_DAY, DPT_YEAR, "Adaptec Linux I2O RAID Driver"
928c2ecf20Sopenharmony_ci};
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/*============================================================================
988c2ecf20Sopenharmony_ci * Globals
998c2ecf20Sopenharmony_ci *============================================================================
1008c2ecf20Sopenharmony_ci */
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(adpt_configuration_lock);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic struct i2o_sys_tbl *sys_tbl;
1058c2ecf20Sopenharmony_cistatic dma_addr_t sys_tbl_pa;
1068c2ecf20Sopenharmony_cistatic int sys_tbl_ind;
1078c2ecf20Sopenharmony_cistatic int sys_tbl_len;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic adpt_hba* hba_chain = NULL;
1108c2ecf20Sopenharmony_cistatic int hba_count = 0;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic struct class *adpt_sysfs_class;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic long adpt_unlocked_ioctl(struct file *, unsigned int, unsigned long);
1158c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT
1168c2ecf20Sopenharmony_cistatic long compat_adpt_ioctl(struct file *, unsigned int, unsigned long);
1178c2ecf20Sopenharmony_ci#endif
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic const struct file_operations adpt_fops = {
1208c2ecf20Sopenharmony_ci	.unlocked_ioctl	= adpt_unlocked_ioctl,
1218c2ecf20Sopenharmony_ci	.open		= adpt_open,
1228c2ecf20Sopenharmony_ci	.release	= adpt_close,
1238c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT
1248c2ecf20Sopenharmony_ci	.compat_ioctl	= compat_adpt_ioctl,
1258c2ecf20Sopenharmony_ci#endif
1268c2ecf20Sopenharmony_ci	.llseek		= noop_llseek,
1278c2ecf20Sopenharmony_ci};
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci/* Structures and definitions for synchronous message posting.
1308c2ecf20Sopenharmony_ci * See adpt_i2o_post_wait() for description
1318c2ecf20Sopenharmony_ci * */
1328c2ecf20Sopenharmony_cistruct adpt_i2o_post_wait_data
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	int status;
1358c2ecf20Sopenharmony_ci	u32 id;
1368c2ecf20Sopenharmony_ci	adpt_wait_queue_head_t *wq;
1378c2ecf20Sopenharmony_ci	struct adpt_i2o_post_wait_data *next;
1388c2ecf20Sopenharmony_ci};
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic struct adpt_i2o_post_wait_data *adpt_post_wait_queue = NULL;
1418c2ecf20Sopenharmony_cistatic u32 adpt_post_wait_id = 0;
1428c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(adpt_post_wait_lock);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci/*============================================================================
1468c2ecf20Sopenharmony_ci * 				Functions
1478c2ecf20Sopenharmony_ci *============================================================================
1488c2ecf20Sopenharmony_ci */
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic inline int dpt_dma64(adpt_hba *pHba)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	return (sizeof(dma_addr_t) > 4 && (pHba)->dma64);
1538c2ecf20Sopenharmony_ci}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistatic inline u32 dma_high(dma_addr_t addr)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	return upper_32_bits(addr);
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic inline u32 dma_low(dma_addr_t addr)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	return (u32)addr;
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic u8 adpt_read_blink_led(adpt_hba* host)
1668c2ecf20Sopenharmony_ci{
1678c2ecf20Sopenharmony_ci	if (host->FwDebugBLEDflag_P) {
1688c2ecf20Sopenharmony_ci		if( readb(host->FwDebugBLEDflag_P) == 0xbc ){
1698c2ecf20Sopenharmony_ci			return readb(host->FwDebugBLEDvalue_P);
1708c2ecf20Sopenharmony_ci		}
1718c2ecf20Sopenharmony_ci	}
1728c2ecf20Sopenharmony_ci	return 0;
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci/*============================================================================
1768c2ecf20Sopenharmony_ci * Scsi host template interface functions
1778c2ecf20Sopenharmony_ci *============================================================================
1788c2ecf20Sopenharmony_ci */
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci#ifdef MODULE
1818c2ecf20Sopenharmony_cistatic struct pci_device_id dptids[] = {
1828c2ecf20Sopenharmony_ci	{ PCI_DPT_VENDOR_ID, PCI_DPT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
1838c2ecf20Sopenharmony_ci	{ PCI_DPT_VENDOR_ID, PCI_DPT_RAPTOR_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
1848c2ecf20Sopenharmony_ci	{ 0, }
1858c2ecf20Sopenharmony_ci};
1868c2ecf20Sopenharmony_ci#endif
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci,dptids);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistatic int adpt_detect(struct scsi_host_template* sht)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	struct pci_dev *pDev = NULL;
1938c2ecf20Sopenharmony_ci	adpt_hba *pHba;
1948c2ecf20Sopenharmony_ci	adpt_hba *next;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	PINFO("Detecting Adaptec I2O RAID controllers...\n");
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci        /* search for all Adatpec I2O RAID cards */
1998c2ecf20Sopenharmony_ci	while ((pDev = pci_get_device( PCI_DPT_VENDOR_ID, PCI_ANY_ID, pDev))) {
2008c2ecf20Sopenharmony_ci		if(pDev->device == PCI_DPT_DEVICE_ID ||
2018c2ecf20Sopenharmony_ci		   pDev->device == PCI_DPT_RAPTOR_DEVICE_ID){
2028c2ecf20Sopenharmony_ci			if(adpt_install_hba(sht, pDev) ){
2038c2ecf20Sopenharmony_ci				PERROR("Could not Init an I2O RAID device\n");
2048c2ecf20Sopenharmony_ci				PERROR("Will not try to detect others.\n");
2058c2ecf20Sopenharmony_ci				return hba_count-1;
2068c2ecf20Sopenharmony_ci			}
2078c2ecf20Sopenharmony_ci			pci_dev_get(pDev);
2088c2ecf20Sopenharmony_ci		}
2098c2ecf20Sopenharmony_ci	}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	/* In INIT state, Activate IOPs */
2128c2ecf20Sopenharmony_ci	for (pHba = hba_chain; pHba; pHba = next) {
2138c2ecf20Sopenharmony_ci		next = pHba->next;
2148c2ecf20Sopenharmony_ci		// Activate does get status , init outbound, and get hrt
2158c2ecf20Sopenharmony_ci		if (adpt_i2o_activate_hba(pHba) < 0) {
2168c2ecf20Sopenharmony_ci			adpt_i2o_delete_hba(pHba);
2178c2ecf20Sopenharmony_ci		}
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	/* Active IOPs in HOLD state */
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cirebuild_sys_tab:
2248c2ecf20Sopenharmony_ci	if (hba_chain == NULL)
2258c2ecf20Sopenharmony_ci		return 0;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	/*
2288c2ecf20Sopenharmony_ci	 * If build_sys_table fails, we kill everything and bail
2298c2ecf20Sopenharmony_ci	 * as we can't init the IOPs w/o a system table
2308c2ecf20Sopenharmony_ci	 */
2318c2ecf20Sopenharmony_ci	if (adpt_i2o_build_sys_table() < 0) {
2328c2ecf20Sopenharmony_ci		adpt_i2o_sys_shutdown();
2338c2ecf20Sopenharmony_ci		return 0;
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	PDEBUG("HBA's in HOLD state\n");
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	/* If IOP don't get online, we need to rebuild the System table */
2398c2ecf20Sopenharmony_ci	for (pHba = hba_chain; pHba; pHba = pHba->next) {
2408c2ecf20Sopenharmony_ci		if (adpt_i2o_online_hba(pHba) < 0) {
2418c2ecf20Sopenharmony_ci			adpt_i2o_delete_hba(pHba);
2428c2ecf20Sopenharmony_ci			goto rebuild_sys_tab;
2438c2ecf20Sopenharmony_ci		}
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	/* Active IOPs now in OPERATIONAL state */
2478c2ecf20Sopenharmony_ci	PDEBUG("HBA's in OPERATIONAL state\n");
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	printk("dpti: If you have a lot of devices this could take a few minutes.\n");
2508c2ecf20Sopenharmony_ci	for (pHba = hba_chain; pHba; pHba = next) {
2518c2ecf20Sopenharmony_ci		next = pHba->next;
2528c2ecf20Sopenharmony_ci		printk(KERN_INFO"%s: Reading the hardware resource table.\n", pHba->name);
2538c2ecf20Sopenharmony_ci		if (adpt_i2o_lct_get(pHba) < 0){
2548c2ecf20Sopenharmony_ci			adpt_i2o_delete_hba(pHba);
2558c2ecf20Sopenharmony_ci			continue;
2568c2ecf20Sopenharmony_ci		}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci		if (adpt_i2o_parse_lct(pHba) < 0){
2598c2ecf20Sopenharmony_ci			adpt_i2o_delete_hba(pHba);
2608c2ecf20Sopenharmony_ci			continue;
2618c2ecf20Sopenharmony_ci		}
2628c2ecf20Sopenharmony_ci		adpt_inquiry(pHba);
2638c2ecf20Sopenharmony_ci	}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	adpt_sysfs_class = class_create(THIS_MODULE, "dpt_i2o");
2668c2ecf20Sopenharmony_ci	if (IS_ERR(adpt_sysfs_class)) {
2678c2ecf20Sopenharmony_ci		printk(KERN_WARNING"dpti: unable to create dpt_i2o class\n");
2688c2ecf20Sopenharmony_ci		adpt_sysfs_class = NULL;
2698c2ecf20Sopenharmony_ci	}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	for (pHba = hba_chain; pHba; pHba = next) {
2728c2ecf20Sopenharmony_ci		next = pHba->next;
2738c2ecf20Sopenharmony_ci		if (adpt_scsi_host_alloc(pHba, sht) < 0){
2748c2ecf20Sopenharmony_ci			adpt_i2o_delete_hba(pHba);
2758c2ecf20Sopenharmony_ci			continue;
2768c2ecf20Sopenharmony_ci		}
2778c2ecf20Sopenharmony_ci		pHba->initialized = TRUE;
2788c2ecf20Sopenharmony_ci		pHba->state &= ~DPTI_STATE_RESET;
2798c2ecf20Sopenharmony_ci		if (adpt_sysfs_class) {
2808c2ecf20Sopenharmony_ci			struct device *dev = device_create(adpt_sysfs_class,
2818c2ecf20Sopenharmony_ci				NULL, MKDEV(DPTI_I2O_MAJOR, pHba->unit), NULL,
2828c2ecf20Sopenharmony_ci				"dpti%d", pHba->unit);
2838c2ecf20Sopenharmony_ci			if (IS_ERR(dev)) {
2848c2ecf20Sopenharmony_ci				printk(KERN_WARNING"dpti%d: unable to "
2858c2ecf20Sopenharmony_ci					"create device in dpt_i2o class\n",
2868c2ecf20Sopenharmony_ci					pHba->unit);
2878c2ecf20Sopenharmony_ci			}
2888c2ecf20Sopenharmony_ci		}
2898c2ecf20Sopenharmony_ci	}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	// Register our control device node
2928c2ecf20Sopenharmony_ci	// nodes will need to be created in /dev to access this
2938c2ecf20Sopenharmony_ci	// the nodes can not be created from within the driver
2948c2ecf20Sopenharmony_ci	if (hba_count && register_chrdev(DPTI_I2O_MAJOR, DPT_DRIVER, &adpt_fops)) {
2958c2ecf20Sopenharmony_ci		adpt_i2o_sys_shutdown();
2968c2ecf20Sopenharmony_ci		return 0;
2978c2ecf20Sopenharmony_ci	}
2988c2ecf20Sopenharmony_ci	return hba_count;
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_cistatic void adpt_release(adpt_hba *pHba)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = pHba->host;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	scsi_remove_host(shost);
3078c2ecf20Sopenharmony_ci//	adpt_i2o_quiesce_hba(pHba);
3088c2ecf20Sopenharmony_ci	adpt_i2o_delete_hba(pHba);
3098c2ecf20Sopenharmony_ci	scsi_host_put(shost);
3108c2ecf20Sopenharmony_ci}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistatic void adpt_inquiry(adpt_hba* pHba)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	u32 msg[17];
3168c2ecf20Sopenharmony_ci	u32 *mptr;
3178c2ecf20Sopenharmony_ci	u32 *lenptr;
3188c2ecf20Sopenharmony_ci	int direction;
3198c2ecf20Sopenharmony_ci	int scsidir;
3208c2ecf20Sopenharmony_ci	u32 len;
3218c2ecf20Sopenharmony_ci	u32 reqlen;
3228c2ecf20Sopenharmony_ci	u8* buf;
3238c2ecf20Sopenharmony_ci	dma_addr_t addr;
3248c2ecf20Sopenharmony_ci	u8  scb[16];
3258c2ecf20Sopenharmony_ci	s32 rcode;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	memset(msg, 0, sizeof(msg));
3288c2ecf20Sopenharmony_ci	buf = dma_alloc_coherent(&pHba->pDev->dev, 80, &addr, GFP_KERNEL);
3298c2ecf20Sopenharmony_ci	if(!buf){
3308c2ecf20Sopenharmony_ci		printk(KERN_ERR"%s: Could not allocate buffer\n",pHba->name);
3318c2ecf20Sopenharmony_ci		return;
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci	memset((void*)buf, 0, 36);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	len = 36;
3368c2ecf20Sopenharmony_ci	direction = 0x00000000;
3378c2ecf20Sopenharmony_ci	scsidir  =0x40000000;	// DATA IN  (iop<--dev)
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (dpt_dma64(pHba))
3408c2ecf20Sopenharmony_ci		reqlen = 17;		// SINGLE SGE, 64 bit
3418c2ecf20Sopenharmony_ci	else
3428c2ecf20Sopenharmony_ci		reqlen = 14;		// SINGLE SGE, 32 bit
3438c2ecf20Sopenharmony_ci	/* Stick the headers on */
3448c2ecf20Sopenharmony_ci	msg[0] = reqlen<<16 | SGL_OFFSET_12;
3458c2ecf20Sopenharmony_ci	msg[1] = (0xff<<24|HOST_TID<<12|ADAPTER_TID);
3468c2ecf20Sopenharmony_ci	msg[2] = 0;
3478c2ecf20Sopenharmony_ci	msg[3]  = 0;
3488c2ecf20Sopenharmony_ci	// Adaptec/DPT Private stuff
3498c2ecf20Sopenharmony_ci	msg[4] = I2O_CMD_SCSI_EXEC|DPT_ORGANIZATION_ID<<16;
3508c2ecf20Sopenharmony_ci	msg[5] = ADAPTER_TID | 1<<16 /* Interpret*/;
3518c2ecf20Sopenharmony_ci	/* Direction, disconnect ok | sense data | simple queue , CDBLen */
3528c2ecf20Sopenharmony_ci	// I2O_SCB_FLAG_ENABLE_DISCONNECT |
3538c2ecf20Sopenharmony_ci	// I2O_SCB_FLAG_SIMPLE_QUEUE_TAG |
3548c2ecf20Sopenharmony_ci	// I2O_SCB_FLAG_SENSE_DATA_IN_MESSAGE;
3558c2ecf20Sopenharmony_ci	msg[6] = scsidir|0x20a00000| 6 /* cmd len*/;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	mptr=msg+7;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	memset(scb, 0, sizeof(scb));
3608c2ecf20Sopenharmony_ci	// Write SCSI command into the message - always 16 byte block
3618c2ecf20Sopenharmony_ci	scb[0] = INQUIRY;
3628c2ecf20Sopenharmony_ci	scb[1] = 0;
3638c2ecf20Sopenharmony_ci	scb[2] = 0;
3648c2ecf20Sopenharmony_ci	scb[3] = 0;
3658c2ecf20Sopenharmony_ci	scb[4] = 36;
3668c2ecf20Sopenharmony_ci	scb[5] = 0;
3678c2ecf20Sopenharmony_ci	// Don't care about the rest of scb
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	memcpy(mptr, scb, sizeof(scb));
3708c2ecf20Sopenharmony_ci	mptr+=4;
3718c2ecf20Sopenharmony_ci	lenptr=mptr++;		/* Remember me - fill in when we know */
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	/* Now fill in the SGList and command */
3748c2ecf20Sopenharmony_ci	*lenptr = len;
3758c2ecf20Sopenharmony_ci	if (dpt_dma64(pHba)) {
3768c2ecf20Sopenharmony_ci		*mptr++ = (0x7C<<24)+(2<<16)+0x02; /* Enable 64 bit */
3778c2ecf20Sopenharmony_ci		*mptr++ = 1 << PAGE_SHIFT;
3788c2ecf20Sopenharmony_ci		*mptr++ = 0xD0000000|direction|len;
3798c2ecf20Sopenharmony_ci		*mptr++ = dma_low(addr);
3808c2ecf20Sopenharmony_ci		*mptr++ = dma_high(addr);
3818c2ecf20Sopenharmony_ci	} else {
3828c2ecf20Sopenharmony_ci		*mptr++ = 0xD0000000|direction|len;
3838c2ecf20Sopenharmony_ci		*mptr++ = addr;
3848c2ecf20Sopenharmony_ci	}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	// Send it on it's way
3878c2ecf20Sopenharmony_ci	rcode = adpt_i2o_post_wait(pHba, msg, reqlen<<2, 120);
3888c2ecf20Sopenharmony_ci	if (rcode != 0) {
3898c2ecf20Sopenharmony_ci		sprintf(pHba->detail, "Adaptec I2O RAID");
3908c2ecf20Sopenharmony_ci		printk(KERN_INFO "%s: Inquiry Error (%d)\n",pHba->name,rcode);
3918c2ecf20Sopenharmony_ci		if (rcode != -ETIME && rcode != -EINTR)
3928c2ecf20Sopenharmony_ci			dma_free_coherent(&pHba->pDev->dev, 80, buf, addr);
3938c2ecf20Sopenharmony_ci	} else {
3948c2ecf20Sopenharmony_ci		memset(pHba->detail, 0, sizeof(pHba->detail));
3958c2ecf20Sopenharmony_ci		memcpy(&(pHba->detail), "Vendor: Adaptec ", 16);
3968c2ecf20Sopenharmony_ci		memcpy(&(pHba->detail[16]), " Model: ", 8);
3978c2ecf20Sopenharmony_ci		memcpy(&(pHba->detail[24]), (u8*) &buf[16], 16);
3988c2ecf20Sopenharmony_ci		memcpy(&(pHba->detail[40]), " FW: ", 4);
3998c2ecf20Sopenharmony_ci		memcpy(&(pHba->detail[44]), (u8*) &buf[32], 4);
4008c2ecf20Sopenharmony_ci		pHba->detail[48] = '\0';	/* precautionary */
4018c2ecf20Sopenharmony_ci		dma_free_coherent(&pHba->pDev->dev, 80, buf, addr);
4028c2ecf20Sopenharmony_ci	}
4038c2ecf20Sopenharmony_ci	adpt_i2o_status_get(pHba);
4048c2ecf20Sopenharmony_ci	return ;
4058c2ecf20Sopenharmony_ci}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_cistatic int adpt_slave_configure(struct scsi_device * device)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	struct Scsi_Host *host = device->host;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	if (host->can_queue && device->tagged_supported) {
4138c2ecf20Sopenharmony_ci		scsi_change_queue_depth(device,
4148c2ecf20Sopenharmony_ci				host->can_queue - 1);
4158c2ecf20Sopenharmony_ci	}
4168c2ecf20Sopenharmony_ci	return 0;
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_cistatic int adpt_queue_lck(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *))
4208c2ecf20Sopenharmony_ci{
4218c2ecf20Sopenharmony_ci	adpt_hba* pHba = NULL;
4228c2ecf20Sopenharmony_ci	struct adpt_device* pDev = NULL;	/* dpt per device information */
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	cmd->scsi_done = done;
4258c2ecf20Sopenharmony_ci	/*
4268c2ecf20Sopenharmony_ci	 * SCSI REQUEST_SENSE commands will be executed automatically by the
4278c2ecf20Sopenharmony_ci	 * Host Adapter for any errors, so they should not be executed
4288c2ecf20Sopenharmony_ci	 * explicitly unless the Sense Data is zero indicating that no error
4298c2ecf20Sopenharmony_ci	 * occurred.
4308c2ecf20Sopenharmony_ci	 */
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	if ((cmd->cmnd[0] == REQUEST_SENSE) && (cmd->sense_buffer[0] != 0)) {
4338c2ecf20Sopenharmony_ci		cmd->result = (DID_OK << 16);
4348c2ecf20Sopenharmony_ci		cmd->scsi_done(cmd);
4358c2ecf20Sopenharmony_ci		return 0;
4368c2ecf20Sopenharmony_ci	}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	pHba = (adpt_hba*)cmd->device->host->hostdata[0];
4398c2ecf20Sopenharmony_ci	if (!pHba) {
4408c2ecf20Sopenharmony_ci		return FAILED;
4418c2ecf20Sopenharmony_ci	}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	rmb();
4448c2ecf20Sopenharmony_ci	if ((pHba->state) & DPTI_STATE_RESET)
4458c2ecf20Sopenharmony_ci		return SCSI_MLQUEUE_HOST_BUSY;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	// TODO if the cmd->device if offline then I may need to issue a bus rescan
4488c2ecf20Sopenharmony_ci	// followed by a get_lct to see if the device is there anymore
4498c2ecf20Sopenharmony_ci	if((pDev = (struct adpt_device*) (cmd->device->hostdata)) == NULL) {
4508c2ecf20Sopenharmony_ci		/*
4518c2ecf20Sopenharmony_ci		 * First command request for this device.  Set up a pointer
4528c2ecf20Sopenharmony_ci		 * to the device structure.  This should be a TEST_UNIT_READY
4538c2ecf20Sopenharmony_ci		 * command from scan_scsis_single.
4548c2ecf20Sopenharmony_ci		 */
4558c2ecf20Sopenharmony_ci		if ((pDev = adpt_find_device(pHba, (u32)cmd->device->channel, (u32)cmd->device->id, cmd->device->lun)) == NULL) {
4568c2ecf20Sopenharmony_ci			// TODO: if any luns are at this bus, scsi id then fake a TEST_UNIT_READY and INQUIRY response
4578c2ecf20Sopenharmony_ci			// with type 7F (for all luns less than the max for this bus,id) so the lun scan will continue.
4588c2ecf20Sopenharmony_ci			cmd->result = (DID_NO_CONNECT << 16);
4598c2ecf20Sopenharmony_ci			cmd->scsi_done(cmd);
4608c2ecf20Sopenharmony_ci			return 0;
4618c2ecf20Sopenharmony_ci		}
4628c2ecf20Sopenharmony_ci		cmd->device->hostdata = pDev;
4638c2ecf20Sopenharmony_ci	}
4648c2ecf20Sopenharmony_ci	pDev->pScsi_dev = cmd->device;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	/*
4678c2ecf20Sopenharmony_ci	 * If we are being called from when the device is being reset,
4688c2ecf20Sopenharmony_ci	 * delay processing of the command until later.
4698c2ecf20Sopenharmony_ci	 */
4708c2ecf20Sopenharmony_ci	if (pDev->state & DPTI_DEV_RESET ) {
4718c2ecf20Sopenharmony_ci		return FAILED;
4728c2ecf20Sopenharmony_ci	}
4738c2ecf20Sopenharmony_ci	return adpt_scsi_to_i2o(pHba, cmd, pDev);
4748c2ecf20Sopenharmony_ci}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_cistatic DEF_SCSI_QCMD(adpt_queue)
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_cistatic int adpt_bios_param(struct scsi_device *sdev, struct block_device *dev,
4798c2ecf20Sopenharmony_ci		sector_t capacity, int geom[])
4808c2ecf20Sopenharmony_ci{
4818c2ecf20Sopenharmony_ci	int heads=-1;
4828c2ecf20Sopenharmony_ci	int sectors=-1;
4838c2ecf20Sopenharmony_ci	int cylinders=-1;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	// *** First lets set the default geometry ****
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	// If the capacity is less than ox2000
4888c2ecf20Sopenharmony_ci	if (capacity < 0x2000 ) {	// floppy
4898c2ecf20Sopenharmony_ci		heads = 18;
4908c2ecf20Sopenharmony_ci		sectors = 2;
4918c2ecf20Sopenharmony_ci	}
4928c2ecf20Sopenharmony_ci	// else if between 0x2000 and 0x20000
4938c2ecf20Sopenharmony_ci	else if (capacity < 0x20000) {
4948c2ecf20Sopenharmony_ci		heads = 64;
4958c2ecf20Sopenharmony_ci		sectors = 32;
4968c2ecf20Sopenharmony_ci	}
4978c2ecf20Sopenharmony_ci	// else if between 0x20000 and 0x40000
4988c2ecf20Sopenharmony_ci	else if (capacity < 0x40000) {
4998c2ecf20Sopenharmony_ci		heads = 65;
5008c2ecf20Sopenharmony_ci		sectors = 63;
5018c2ecf20Sopenharmony_ci	}
5028c2ecf20Sopenharmony_ci	// else if between 0x4000 and 0x80000
5038c2ecf20Sopenharmony_ci	else if (capacity < 0x80000) {
5048c2ecf20Sopenharmony_ci		heads = 128;
5058c2ecf20Sopenharmony_ci		sectors = 63;
5068c2ecf20Sopenharmony_ci	}
5078c2ecf20Sopenharmony_ci	// else if greater than 0x80000
5088c2ecf20Sopenharmony_ci	else {
5098c2ecf20Sopenharmony_ci		heads = 255;
5108c2ecf20Sopenharmony_ci		sectors = 63;
5118c2ecf20Sopenharmony_ci	}
5128c2ecf20Sopenharmony_ci	cylinders = sector_div(capacity, heads * sectors);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	// Special case if CDROM
5158c2ecf20Sopenharmony_ci	if(sdev->type == 5) {  // CDROM
5168c2ecf20Sopenharmony_ci		heads = 252;
5178c2ecf20Sopenharmony_ci		sectors = 63;
5188c2ecf20Sopenharmony_ci		cylinders = 1111;
5198c2ecf20Sopenharmony_ci	}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	geom[0] = heads;
5228c2ecf20Sopenharmony_ci	geom[1] = sectors;
5238c2ecf20Sopenharmony_ci	geom[2] = cylinders;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	PDEBUG("adpt_bios_param: exit\n");
5268c2ecf20Sopenharmony_ci	return 0;
5278c2ecf20Sopenharmony_ci}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_cistatic const char *adpt_info(struct Scsi_Host *host)
5318c2ecf20Sopenharmony_ci{
5328c2ecf20Sopenharmony_ci	adpt_hba* pHba;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	pHba = (adpt_hba *) host->hostdata[0];
5358c2ecf20Sopenharmony_ci	return (char *) (pHba->detail);
5368c2ecf20Sopenharmony_ci}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_cistatic int adpt_show_info(struct seq_file *m, struct Scsi_Host *host)
5398c2ecf20Sopenharmony_ci{
5408c2ecf20Sopenharmony_ci	struct adpt_device* d;
5418c2ecf20Sopenharmony_ci	int id;
5428c2ecf20Sopenharmony_ci	int chan;
5438c2ecf20Sopenharmony_ci	adpt_hba* pHba;
5448c2ecf20Sopenharmony_ci	int unit;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	// Find HBA (host bus adapter) we are looking for
5478c2ecf20Sopenharmony_ci	mutex_lock(&adpt_configuration_lock);
5488c2ecf20Sopenharmony_ci	for (pHba = hba_chain; pHba; pHba = pHba->next) {
5498c2ecf20Sopenharmony_ci		if (pHba->host == host) {
5508c2ecf20Sopenharmony_ci			break;	/* found adapter */
5518c2ecf20Sopenharmony_ci		}
5528c2ecf20Sopenharmony_ci	}
5538c2ecf20Sopenharmony_ci	mutex_unlock(&adpt_configuration_lock);
5548c2ecf20Sopenharmony_ci	if (pHba == NULL) {
5558c2ecf20Sopenharmony_ci		return 0;
5568c2ecf20Sopenharmony_ci	}
5578c2ecf20Sopenharmony_ci	host = pHba->host;
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	seq_printf(m, "Adaptec I2O RAID Driver Version: %s\n\n", DPT_I2O_VERSION);
5608c2ecf20Sopenharmony_ci	seq_printf(m, "%s\n", pHba->detail);
5618c2ecf20Sopenharmony_ci	seq_printf(m, "SCSI Host=scsi%d  Control Node=/dev/%s  irq=%d\n",
5628c2ecf20Sopenharmony_ci			pHba->host->host_no, pHba->name, host->irq);
5638c2ecf20Sopenharmony_ci	seq_printf(m, "\tpost fifo size  = %d\n\treply fifo size = %d\n\tsg table size   = %d\n\n",
5648c2ecf20Sopenharmony_ci			host->can_queue, (int) pHba->reply_fifo_size , host->sg_tablesize);
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	seq_puts(m, "Devices:\n");
5678c2ecf20Sopenharmony_ci	for(chan = 0; chan < MAX_CHANNEL; chan++) {
5688c2ecf20Sopenharmony_ci		for(id = 0; id < MAX_ID; id++) {
5698c2ecf20Sopenharmony_ci			d = pHba->channel[chan].device[id];
5708c2ecf20Sopenharmony_ci			while(d) {
5718c2ecf20Sopenharmony_ci				seq_printf(m,"\t%-24.24s", d->pScsi_dev->vendor);
5728c2ecf20Sopenharmony_ci				seq_printf(m," Rev: %-8.8s\n", d->pScsi_dev->rev);
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci				unit = d->pI2o_dev->lct_data.tid;
5758c2ecf20Sopenharmony_ci				seq_printf(m, "\tTID=%d, (Channel=%d, Target=%d, Lun=%llu)  (%s)\n\n",
5768c2ecf20Sopenharmony_ci					       unit, (int)d->scsi_channel, (int)d->scsi_id, d->scsi_lun,
5778c2ecf20Sopenharmony_ci					       scsi_device_online(d->pScsi_dev)? "online":"offline");
5788c2ecf20Sopenharmony_ci				d = d->next_lun;
5798c2ecf20Sopenharmony_ci			}
5808c2ecf20Sopenharmony_ci		}
5818c2ecf20Sopenharmony_ci	}
5828c2ecf20Sopenharmony_ci	return 0;
5838c2ecf20Sopenharmony_ci}
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci/*===========================================================================
5868c2ecf20Sopenharmony_ci * Error Handling routines
5878c2ecf20Sopenharmony_ci *===========================================================================
5888c2ecf20Sopenharmony_ci */
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_cistatic int adpt_abort(struct scsi_cmnd * cmd)
5918c2ecf20Sopenharmony_ci{
5928c2ecf20Sopenharmony_ci	adpt_hba* pHba = NULL;	/* host bus adapter structure */
5938c2ecf20Sopenharmony_ci	struct adpt_device* dptdevice;	/* dpt per device information */
5948c2ecf20Sopenharmony_ci	u32 msg[5];
5958c2ecf20Sopenharmony_ci	int rcode;
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	pHba = (adpt_hba*) cmd->device->host->hostdata[0];
5988c2ecf20Sopenharmony_ci	printk(KERN_INFO"%s: Trying to Abort\n",pHba->name);
5998c2ecf20Sopenharmony_ci	if ((dptdevice = (void*) (cmd->device->hostdata)) == NULL) {
6008c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Unable to abort: No device in cmnd\n",pHba->name);
6018c2ecf20Sopenharmony_ci		return FAILED;
6028c2ecf20Sopenharmony_ci	}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	memset(msg, 0, sizeof(msg));
6058c2ecf20Sopenharmony_ci	msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
6068c2ecf20Sopenharmony_ci	msg[1] = I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|dptdevice->tid;
6078c2ecf20Sopenharmony_ci	msg[2] = 0;
6088c2ecf20Sopenharmony_ci	msg[3]= 0;
6098c2ecf20Sopenharmony_ci	/* Add 1 to avoid firmware treating it as invalid command */
6108c2ecf20Sopenharmony_ci	msg[4] = cmd->request->tag + 1;
6118c2ecf20Sopenharmony_ci	if (pHba->host)
6128c2ecf20Sopenharmony_ci		spin_lock_irq(pHba->host->host_lock);
6138c2ecf20Sopenharmony_ci	rcode = adpt_i2o_post_wait(pHba, msg, sizeof(msg), FOREVER);
6148c2ecf20Sopenharmony_ci	if (pHba->host)
6158c2ecf20Sopenharmony_ci		spin_unlock_irq(pHba->host->host_lock);
6168c2ecf20Sopenharmony_ci	if (rcode != 0) {
6178c2ecf20Sopenharmony_ci		if(rcode == -EOPNOTSUPP ){
6188c2ecf20Sopenharmony_ci			printk(KERN_INFO"%s: Abort cmd not supported\n",pHba->name);
6198c2ecf20Sopenharmony_ci			return FAILED;
6208c2ecf20Sopenharmony_ci		}
6218c2ecf20Sopenharmony_ci		printk(KERN_INFO"%s: Abort failed.\n",pHba->name);
6228c2ecf20Sopenharmony_ci		return FAILED;
6238c2ecf20Sopenharmony_ci	}
6248c2ecf20Sopenharmony_ci	printk(KERN_INFO"%s: Abort complete.\n",pHba->name);
6258c2ecf20Sopenharmony_ci	return SUCCESS;
6268c2ecf20Sopenharmony_ci}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci#define I2O_DEVICE_RESET 0x27
6308c2ecf20Sopenharmony_ci// This is the same for BLK and SCSI devices
6318c2ecf20Sopenharmony_ci// NOTE this is wrong in the i2o.h definitions
6328c2ecf20Sopenharmony_ci// This is not currently supported by our adapter but we issue it anyway
6338c2ecf20Sopenharmony_cistatic int adpt_device_reset(struct scsi_cmnd* cmd)
6348c2ecf20Sopenharmony_ci{
6358c2ecf20Sopenharmony_ci	adpt_hba* pHba;
6368c2ecf20Sopenharmony_ci	u32 msg[4];
6378c2ecf20Sopenharmony_ci	u32 rcode;
6388c2ecf20Sopenharmony_ci	int old_state;
6398c2ecf20Sopenharmony_ci	struct adpt_device* d = cmd->device->hostdata;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	pHba = (void*) cmd->device->host->hostdata[0];
6428c2ecf20Sopenharmony_ci	printk(KERN_INFO"%s: Trying to reset device\n",pHba->name);
6438c2ecf20Sopenharmony_ci	if (!d) {
6448c2ecf20Sopenharmony_ci		printk(KERN_INFO"%s: Reset Device: Device Not found\n",pHba->name);
6458c2ecf20Sopenharmony_ci		return FAILED;
6468c2ecf20Sopenharmony_ci	}
6478c2ecf20Sopenharmony_ci	memset(msg, 0, sizeof(msg));
6488c2ecf20Sopenharmony_ci	msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
6498c2ecf20Sopenharmony_ci	msg[1] = (I2O_DEVICE_RESET<<24|HOST_TID<<12|d->tid);
6508c2ecf20Sopenharmony_ci	msg[2] = 0;
6518c2ecf20Sopenharmony_ci	msg[3] = 0;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	if (pHba->host)
6548c2ecf20Sopenharmony_ci		spin_lock_irq(pHba->host->host_lock);
6558c2ecf20Sopenharmony_ci	old_state = d->state;
6568c2ecf20Sopenharmony_ci	d->state |= DPTI_DEV_RESET;
6578c2ecf20Sopenharmony_ci	rcode = adpt_i2o_post_wait(pHba, msg,sizeof(msg), FOREVER);
6588c2ecf20Sopenharmony_ci	d->state = old_state;
6598c2ecf20Sopenharmony_ci	if (pHba->host)
6608c2ecf20Sopenharmony_ci		spin_unlock_irq(pHba->host->host_lock);
6618c2ecf20Sopenharmony_ci	if (rcode != 0) {
6628c2ecf20Sopenharmony_ci		if(rcode == -EOPNOTSUPP ){
6638c2ecf20Sopenharmony_ci			printk(KERN_INFO"%s: Device reset not supported\n",pHba->name);
6648c2ecf20Sopenharmony_ci			return FAILED;
6658c2ecf20Sopenharmony_ci		}
6668c2ecf20Sopenharmony_ci		printk(KERN_INFO"%s: Device reset failed\n",pHba->name);
6678c2ecf20Sopenharmony_ci		return FAILED;
6688c2ecf20Sopenharmony_ci	} else {
6698c2ecf20Sopenharmony_ci		printk(KERN_INFO"%s: Device reset successful\n",pHba->name);
6708c2ecf20Sopenharmony_ci		return SUCCESS;
6718c2ecf20Sopenharmony_ci	}
6728c2ecf20Sopenharmony_ci}
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci#define I2O_HBA_BUS_RESET 0x87
6768c2ecf20Sopenharmony_ci// This version of bus reset is called by the eh_error handler
6778c2ecf20Sopenharmony_cistatic int adpt_bus_reset(struct scsi_cmnd* cmd)
6788c2ecf20Sopenharmony_ci{
6798c2ecf20Sopenharmony_ci	adpt_hba* pHba;
6808c2ecf20Sopenharmony_ci	u32 msg[4];
6818c2ecf20Sopenharmony_ci	u32 rcode;
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	pHba = (adpt_hba*)cmd->device->host->hostdata[0];
6848c2ecf20Sopenharmony_ci	memset(msg, 0, sizeof(msg));
6858c2ecf20Sopenharmony_ci	printk(KERN_WARNING"%s: Bus reset: SCSI Bus %d: tid: %d\n",pHba->name, cmd->device->channel,pHba->channel[cmd->device->channel].tid );
6868c2ecf20Sopenharmony_ci	msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
6878c2ecf20Sopenharmony_ci	msg[1] = (I2O_HBA_BUS_RESET<<24|HOST_TID<<12|pHba->channel[cmd->device->channel].tid);
6888c2ecf20Sopenharmony_ci	msg[2] = 0;
6898c2ecf20Sopenharmony_ci	msg[3] = 0;
6908c2ecf20Sopenharmony_ci	if (pHba->host)
6918c2ecf20Sopenharmony_ci		spin_lock_irq(pHba->host->host_lock);
6928c2ecf20Sopenharmony_ci	rcode = adpt_i2o_post_wait(pHba, msg,sizeof(msg), FOREVER);
6938c2ecf20Sopenharmony_ci	if (pHba->host)
6948c2ecf20Sopenharmony_ci		spin_unlock_irq(pHba->host->host_lock);
6958c2ecf20Sopenharmony_ci	if (rcode != 0) {
6968c2ecf20Sopenharmony_ci		printk(KERN_WARNING"%s: Bus reset failed.\n",pHba->name);
6978c2ecf20Sopenharmony_ci		return FAILED;
6988c2ecf20Sopenharmony_ci	} else {
6998c2ecf20Sopenharmony_ci		printk(KERN_WARNING"%s: Bus reset success.\n",pHba->name);
7008c2ecf20Sopenharmony_ci		return SUCCESS;
7018c2ecf20Sopenharmony_ci	}
7028c2ecf20Sopenharmony_ci}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci// This version of reset is called by the eh_error_handler
7058c2ecf20Sopenharmony_cistatic int __adpt_reset(struct scsi_cmnd* cmd)
7068c2ecf20Sopenharmony_ci{
7078c2ecf20Sopenharmony_ci	adpt_hba* pHba;
7088c2ecf20Sopenharmony_ci	int rcode;
7098c2ecf20Sopenharmony_ci	char name[32];
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	pHba = (adpt_hba*)cmd->device->host->hostdata[0];
7128c2ecf20Sopenharmony_ci	strncpy(name, pHba->name, sizeof(name));
7138c2ecf20Sopenharmony_ci	printk(KERN_WARNING"%s: Hba Reset: scsi id %d: tid: %d\n", name, cmd->device->channel, pHba->channel[cmd->device->channel].tid);
7148c2ecf20Sopenharmony_ci	rcode =  adpt_hba_reset(pHba);
7158c2ecf20Sopenharmony_ci	if(rcode == 0){
7168c2ecf20Sopenharmony_ci		printk(KERN_WARNING"%s: HBA reset complete\n", name);
7178c2ecf20Sopenharmony_ci		return SUCCESS;
7188c2ecf20Sopenharmony_ci	} else {
7198c2ecf20Sopenharmony_ci		printk(KERN_WARNING"%s: HBA reset failed (%x)\n", name, rcode);
7208c2ecf20Sopenharmony_ci		return FAILED;
7218c2ecf20Sopenharmony_ci	}
7228c2ecf20Sopenharmony_ci}
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_cistatic int adpt_reset(struct scsi_cmnd* cmd)
7258c2ecf20Sopenharmony_ci{
7268c2ecf20Sopenharmony_ci	int rc;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	spin_lock_irq(cmd->device->host->host_lock);
7298c2ecf20Sopenharmony_ci	rc = __adpt_reset(cmd);
7308c2ecf20Sopenharmony_ci	spin_unlock_irq(cmd->device->host->host_lock);
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	return rc;
7338c2ecf20Sopenharmony_ci}
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci// This version of reset is called by the ioctls and indirectly from eh_error_handler via adpt_reset
7368c2ecf20Sopenharmony_cistatic int adpt_hba_reset(adpt_hba* pHba)
7378c2ecf20Sopenharmony_ci{
7388c2ecf20Sopenharmony_ci	int rcode;
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	pHba->state |= DPTI_STATE_RESET;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	// Activate does get status , init outbound, and get hrt
7438c2ecf20Sopenharmony_ci	if ((rcode=adpt_i2o_activate_hba(pHba)) < 0) {
7448c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Could not activate\n", pHba->name);
7458c2ecf20Sopenharmony_ci		adpt_i2o_delete_hba(pHba);
7468c2ecf20Sopenharmony_ci		return rcode;
7478c2ecf20Sopenharmony_ci	}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	if ((rcode=adpt_i2o_build_sys_table()) < 0) {
7508c2ecf20Sopenharmony_ci		adpt_i2o_delete_hba(pHba);
7518c2ecf20Sopenharmony_ci		return rcode;
7528c2ecf20Sopenharmony_ci	}
7538c2ecf20Sopenharmony_ci	PDEBUG("%s: in HOLD state\n",pHba->name);
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	if ((rcode=adpt_i2o_online_hba(pHba)) < 0) {
7568c2ecf20Sopenharmony_ci		adpt_i2o_delete_hba(pHba);
7578c2ecf20Sopenharmony_ci		return rcode;
7588c2ecf20Sopenharmony_ci	}
7598c2ecf20Sopenharmony_ci	PDEBUG("%s: in OPERATIONAL state\n",pHba->name);
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	if ((rcode=adpt_i2o_lct_get(pHba)) < 0){
7628c2ecf20Sopenharmony_ci		adpt_i2o_delete_hba(pHba);
7638c2ecf20Sopenharmony_ci		return rcode;
7648c2ecf20Sopenharmony_ci	}
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	if ((rcode=adpt_i2o_reparse_lct(pHba)) < 0){
7678c2ecf20Sopenharmony_ci		adpt_i2o_delete_hba(pHba);
7688c2ecf20Sopenharmony_ci		return rcode;
7698c2ecf20Sopenharmony_ci	}
7708c2ecf20Sopenharmony_ci	pHba->state &= ~DPTI_STATE_RESET;
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	scsi_host_complete_all_commands(pHba->host, DID_RESET);
7738c2ecf20Sopenharmony_ci	return 0;	/* return success */
7748c2ecf20Sopenharmony_ci}
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci/*===========================================================================
7778c2ecf20Sopenharmony_ci *
7788c2ecf20Sopenharmony_ci *===========================================================================
7798c2ecf20Sopenharmony_ci */
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_cistatic void adpt_i2o_sys_shutdown(void)
7838c2ecf20Sopenharmony_ci{
7848c2ecf20Sopenharmony_ci	adpt_hba *pHba, *pNext;
7858c2ecf20Sopenharmony_ci	struct adpt_i2o_post_wait_data *p1, *old;
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	printk(KERN_INFO "Shutting down Adaptec I2O controllers.\n");
7888c2ecf20Sopenharmony_ci	printk(KERN_INFO "   This could take a few minutes if there are many devices attached\n");
7898c2ecf20Sopenharmony_ci	/* Delete all IOPs from the controller chain */
7908c2ecf20Sopenharmony_ci	/* They should have already been released by the
7918c2ecf20Sopenharmony_ci	 * scsi-core
7928c2ecf20Sopenharmony_ci	 */
7938c2ecf20Sopenharmony_ci	for (pHba = hba_chain; pHba; pHba = pNext) {
7948c2ecf20Sopenharmony_ci		pNext = pHba->next;
7958c2ecf20Sopenharmony_ci		adpt_i2o_delete_hba(pHba);
7968c2ecf20Sopenharmony_ci	}
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	/* Remove any timedout entries from the wait queue.  */
7998c2ecf20Sopenharmony_ci//	spin_lock_irqsave(&adpt_post_wait_lock, flags);
8008c2ecf20Sopenharmony_ci	/* Nothing should be outstanding at this point so just
8018c2ecf20Sopenharmony_ci	 * free them
8028c2ecf20Sopenharmony_ci	 */
8038c2ecf20Sopenharmony_ci	for(p1 = adpt_post_wait_queue; p1;) {
8048c2ecf20Sopenharmony_ci		old = p1;
8058c2ecf20Sopenharmony_ci		p1 = p1->next;
8068c2ecf20Sopenharmony_ci		kfree(old);
8078c2ecf20Sopenharmony_ci	}
8088c2ecf20Sopenharmony_ci//	spin_unlock_irqrestore(&adpt_post_wait_lock, flags);
8098c2ecf20Sopenharmony_ci	adpt_post_wait_queue = NULL;
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	printk(KERN_INFO "Adaptec I2O controllers down.\n");
8128c2ecf20Sopenharmony_ci}
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_cistatic int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev)
8158c2ecf20Sopenharmony_ci{
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	adpt_hba* pHba = NULL;
8188c2ecf20Sopenharmony_ci	adpt_hba* p = NULL;
8198c2ecf20Sopenharmony_ci	ulong base_addr0_phys = 0;
8208c2ecf20Sopenharmony_ci	ulong base_addr1_phys = 0;
8218c2ecf20Sopenharmony_ci	u32 hba_map0_area_size = 0;
8228c2ecf20Sopenharmony_ci	u32 hba_map1_area_size = 0;
8238c2ecf20Sopenharmony_ci	void __iomem *base_addr_virt = NULL;
8248c2ecf20Sopenharmony_ci	void __iomem *msg_addr_virt = NULL;
8258c2ecf20Sopenharmony_ci	int dma64 = 0;
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	int raptorFlag = FALSE;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	if(pci_enable_device(pDev)) {
8308c2ecf20Sopenharmony_ci		return -EINVAL;
8318c2ecf20Sopenharmony_ci	}
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	if (pci_request_regions(pDev, "dpt_i2o")) {
8348c2ecf20Sopenharmony_ci		PERROR("dpti: adpt_config_hba: pci request region failed\n");
8358c2ecf20Sopenharmony_ci		return -EINVAL;
8368c2ecf20Sopenharmony_ci	}
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	pci_set_master(pDev);
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	/*
8418c2ecf20Sopenharmony_ci	 *	See if we should enable dma64 mode.
8428c2ecf20Sopenharmony_ci	 */
8438c2ecf20Sopenharmony_ci	if (sizeof(dma_addr_t) > 4 &&
8448c2ecf20Sopenharmony_ci	    dma_get_required_mask(&pDev->dev) > DMA_BIT_MASK(32) &&
8458c2ecf20Sopenharmony_ci	    dma_set_mask(&pDev->dev, DMA_BIT_MASK(64)) == 0)
8468c2ecf20Sopenharmony_ci		dma64 = 1;
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	if (!dma64 && dma_set_mask(&pDev->dev, DMA_BIT_MASK(32)) != 0)
8498c2ecf20Sopenharmony_ci		return -EINVAL;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	/* adapter only supports message blocks below 4GB */
8528c2ecf20Sopenharmony_ci	dma_set_coherent_mask(&pDev->dev, DMA_BIT_MASK(32));
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	base_addr0_phys = pci_resource_start(pDev,0);
8558c2ecf20Sopenharmony_ci	hba_map0_area_size = pci_resource_len(pDev,0);
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	// Check if standard PCI card or single BAR Raptor
8588c2ecf20Sopenharmony_ci	if(pDev->device == PCI_DPT_DEVICE_ID){
8598c2ecf20Sopenharmony_ci		if(pDev->subsystem_device >=0xc032 && pDev->subsystem_device <= 0xc03b){
8608c2ecf20Sopenharmony_ci			// Raptor card with this device id needs 4M
8618c2ecf20Sopenharmony_ci			hba_map0_area_size = 0x400000;
8628c2ecf20Sopenharmony_ci		} else { // Not Raptor - it is a PCI card
8638c2ecf20Sopenharmony_ci			if(hba_map0_area_size > 0x100000 ){
8648c2ecf20Sopenharmony_ci				hba_map0_area_size = 0x100000;
8658c2ecf20Sopenharmony_ci			}
8668c2ecf20Sopenharmony_ci		}
8678c2ecf20Sopenharmony_ci	} else {// Raptor split BAR config
8688c2ecf20Sopenharmony_ci		// Use BAR1 in this configuration
8698c2ecf20Sopenharmony_ci		base_addr1_phys = pci_resource_start(pDev,1);
8708c2ecf20Sopenharmony_ci		hba_map1_area_size = pci_resource_len(pDev,1);
8718c2ecf20Sopenharmony_ci		raptorFlag = TRUE;
8728c2ecf20Sopenharmony_ci	}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci#if BITS_PER_LONG == 64
8758c2ecf20Sopenharmony_ci	/*
8768c2ecf20Sopenharmony_ci	 *	The original Adaptec 64 bit driver has this comment here:
8778c2ecf20Sopenharmony_ci	 *	"x86_64 machines need more optimal mappings"
8788c2ecf20Sopenharmony_ci	 *
8798c2ecf20Sopenharmony_ci	 *	I assume some HBAs report ridiculously large mappings
8808c2ecf20Sopenharmony_ci	 *	and we need to limit them on platforms with IOMMUs.
8818c2ecf20Sopenharmony_ci	 */
8828c2ecf20Sopenharmony_ci	if (raptorFlag == TRUE) {
8838c2ecf20Sopenharmony_ci		if (hba_map0_area_size > 128)
8848c2ecf20Sopenharmony_ci			hba_map0_area_size = 128;
8858c2ecf20Sopenharmony_ci		if (hba_map1_area_size > 524288)
8868c2ecf20Sopenharmony_ci			hba_map1_area_size = 524288;
8878c2ecf20Sopenharmony_ci	} else {
8888c2ecf20Sopenharmony_ci		if (hba_map0_area_size > 524288)
8898c2ecf20Sopenharmony_ci			hba_map0_area_size = 524288;
8908c2ecf20Sopenharmony_ci	}
8918c2ecf20Sopenharmony_ci#endif
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	base_addr_virt = ioremap(base_addr0_phys,hba_map0_area_size);
8948c2ecf20Sopenharmony_ci	if (!base_addr_virt) {
8958c2ecf20Sopenharmony_ci		pci_release_regions(pDev);
8968c2ecf20Sopenharmony_ci		PERROR("dpti: adpt_config_hba: io remap failed\n");
8978c2ecf20Sopenharmony_ci		return -EINVAL;
8988c2ecf20Sopenharmony_ci	}
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci        if(raptorFlag == TRUE) {
9018c2ecf20Sopenharmony_ci		msg_addr_virt = ioremap(base_addr1_phys, hba_map1_area_size );
9028c2ecf20Sopenharmony_ci		if (!msg_addr_virt) {
9038c2ecf20Sopenharmony_ci			PERROR("dpti: adpt_config_hba: io remap failed on BAR1\n");
9048c2ecf20Sopenharmony_ci			iounmap(base_addr_virt);
9058c2ecf20Sopenharmony_ci			pci_release_regions(pDev);
9068c2ecf20Sopenharmony_ci			return -EINVAL;
9078c2ecf20Sopenharmony_ci		}
9088c2ecf20Sopenharmony_ci	} else {
9098c2ecf20Sopenharmony_ci		msg_addr_virt = base_addr_virt;
9108c2ecf20Sopenharmony_ci	}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	// Allocate and zero the data structure
9138c2ecf20Sopenharmony_ci	pHba = kzalloc(sizeof(adpt_hba), GFP_KERNEL);
9148c2ecf20Sopenharmony_ci	if (!pHba) {
9158c2ecf20Sopenharmony_ci		if (msg_addr_virt != base_addr_virt)
9168c2ecf20Sopenharmony_ci			iounmap(msg_addr_virt);
9178c2ecf20Sopenharmony_ci		iounmap(base_addr_virt);
9188c2ecf20Sopenharmony_ci		pci_release_regions(pDev);
9198c2ecf20Sopenharmony_ci		return -ENOMEM;
9208c2ecf20Sopenharmony_ci	}
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	mutex_lock(&adpt_configuration_lock);
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	if(hba_chain != NULL){
9258c2ecf20Sopenharmony_ci		for(p = hba_chain; p->next; p = p->next);
9268c2ecf20Sopenharmony_ci		p->next = pHba;
9278c2ecf20Sopenharmony_ci	} else {
9288c2ecf20Sopenharmony_ci		hba_chain = pHba;
9298c2ecf20Sopenharmony_ci	}
9308c2ecf20Sopenharmony_ci	pHba->next = NULL;
9318c2ecf20Sopenharmony_ci	pHba->unit = hba_count;
9328c2ecf20Sopenharmony_ci	sprintf(pHba->name, "dpti%d", hba_count);
9338c2ecf20Sopenharmony_ci	hba_count++;
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	mutex_unlock(&adpt_configuration_lock);
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	pHba->pDev = pDev;
9388c2ecf20Sopenharmony_ci	pHba->base_addr_phys = base_addr0_phys;
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	// Set up the Virtual Base Address of the I2O Device
9418c2ecf20Sopenharmony_ci	pHba->base_addr_virt = base_addr_virt;
9428c2ecf20Sopenharmony_ci	pHba->msg_addr_virt = msg_addr_virt;
9438c2ecf20Sopenharmony_ci	pHba->irq_mask = base_addr_virt+0x30;
9448c2ecf20Sopenharmony_ci	pHba->post_port = base_addr_virt+0x40;
9458c2ecf20Sopenharmony_ci	pHba->reply_port = base_addr_virt+0x44;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	pHba->hrt = NULL;
9488c2ecf20Sopenharmony_ci	pHba->lct = NULL;
9498c2ecf20Sopenharmony_ci	pHba->lct_size = 0;
9508c2ecf20Sopenharmony_ci	pHba->status_block = NULL;
9518c2ecf20Sopenharmony_ci	pHba->post_count = 0;
9528c2ecf20Sopenharmony_ci	pHba->state = DPTI_STATE_RESET;
9538c2ecf20Sopenharmony_ci	pHba->pDev = pDev;
9548c2ecf20Sopenharmony_ci	pHba->devices = NULL;
9558c2ecf20Sopenharmony_ci	pHba->dma64 = dma64;
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	// Initializing the spinlocks
9588c2ecf20Sopenharmony_ci	spin_lock_init(&pHba->state_lock);
9598c2ecf20Sopenharmony_ci	spin_lock_init(&adpt_post_wait_lock);
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	if(raptorFlag == 0){
9628c2ecf20Sopenharmony_ci		printk(KERN_INFO "Adaptec I2O RAID controller"
9638c2ecf20Sopenharmony_ci				 " %d at %p size=%x irq=%d%s\n",
9648c2ecf20Sopenharmony_ci			hba_count-1, base_addr_virt,
9658c2ecf20Sopenharmony_ci			hba_map0_area_size, pDev->irq,
9668c2ecf20Sopenharmony_ci			dma64 ? " (64-bit DMA)" : "");
9678c2ecf20Sopenharmony_ci	} else {
9688c2ecf20Sopenharmony_ci		printk(KERN_INFO"Adaptec I2O RAID controller %d irq=%d%s\n",
9698c2ecf20Sopenharmony_ci			hba_count-1, pDev->irq,
9708c2ecf20Sopenharmony_ci			dma64 ? " (64-bit DMA)" : "");
9718c2ecf20Sopenharmony_ci		printk(KERN_INFO"     BAR0 %p - size= %x\n",base_addr_virt,hba_map0_area_size);
9728c2ecf20Sopenharmony_ci		printk(KERN_INFO"     BAR1 %p - size= %x\n",msg_addr_virt,hba_map1_area_size);
9738c2ecf20Sopenharmony_ci	}
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	if (request_irq (pDev->irq, adpt_isr, IRQF_SHARED, pHba->name, pHba)) {
9768c2ecf20Sopenharmony_ci		printk(KERN_ERR"%s: Couldn't register IRQ %d\n", pHba->name, pDev->irq);
9778c2ecf20Sopenharmony_ci		adpt_i2o_delete_hba(pHba);
9788c2ecf20Sopenharmony_ci		return -EINVAL;
9798c2ecf20Sopenharmony_ci	}
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	return 0;
9828c2ecf20Sopenharmony_ci}
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_cistatic void adpt_i2o_delete_hba(adpt_hba* pHba)
9868c2ecf20Sopenharmony_ci{
9878c2ecf20Sopenharmony_ci	adpt_hba* p1;
9888c2ecf20Sopenharmony_ci	adpt_hba* p2;
9898c2ecf20Sopenharmony_ci	struct i2o_device* d;
9908c2ecf20Sopenharmony_ci	struct i2o_device* next;
9918c2ecf20Sopenharmony_ci	int i;
9928c2ecf20Sopenharmony_ci	int j;
9938c2ecf20Sopenharmony_ci	struct adpt_device* pDev;
9948c2ecf20Sopenharmony_ci	struct adpt_device* pNext;
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	mutex_lock(&adpt_configuration_lock);
9988c2ecf20Sopenharmony_ci	if(pHba->host){
9998c2ecf20Sopenharmony_ci		free_irq(pHba->host->irq, pHba);
10008c2ecf20Sopenharmony_ci	}
10018c2ecf20Sopenharmony_ci	p2 = NULL;
10028c2ecf20Sopenharmony_ci	for( p1 = hba_chain; p1; p2 = p1,p1=p1->next){
10038c2ecf20Sopenharmony_ci		if(p1 == pHba) {
10048c2ecf20Sopenharmony_ci			if(p2) {
10058c2ecf20Sopenharmony_ci				p2->next = p1->next;
10068c2ecf20Sopenharmony_ci			} else {
10078c2ecf20Sopenharmony_ci				hba_chain = p1->next;
10088c2ecf20Sopenharmony_ci			}
10098c2ecf20Sopenharmony_ci			break;
10108c2ecf20Sopenharmony_ci		}
10118c2ecf20Sopenharmony_ci	}
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	hba_count--;
10148c2ecf20Sopenharmony_ci	mutex_unlock(&adpt_configuration_lock);
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	iounmap(pHba->base_addr_virt);
10178c2ecf20Sopenharmony_ci	pci_release_regions(pHba->pDev);
10188c2ecf20Sopenharmony_ci	if(pHba->msg_addr_virt != pHba->base_addr_virt){
10198c2ecf20Sopenharmony_ci		iounmap(pHba->msg_addr_virt);
10208c2ecf20Sopenharmony_ci	}
10218c2ecf20Sopenharmony_ci	if(pHba->FwDebugBuffer_P)
10228c2ecf20Sopenharmony_ci	   	iounmap(pHba->FwDebugBuffer_P);
10238c2ecf20Sopenharmony_ci	if(pHba->hrt) {
10248c2ecf20Sopenharmony_ci		dma_free_coherent(&pHba->pDev->dev,
10258c2ecf20Sopenharmony_ci			pHba->hrt->num_entries * pHba->hrt->entry_len << 2,
10268c2ecf20Sopenharmony_ci			pHba->hrt, pHba->hrt_pa);
10278c2ecf20Sopenharmony_ci	}
10288c2ecf20Sopenharmony_ci	if(pHba->lct) {
10298c2ecf20Sopenharmony_ci		dma_free_coherent(&pHba->pDev->dev, pHba->lct_size,
10308c2ecf20Sopenharmony_ci			pHba->lct, pHba->lct_pa);
10318c2ecf20Sopenharmony_ci	}
10328c2ecf20Sopenharmony_ci	if(pHba->status_block) {
10338c2ecf20Sopenharmony_ci		dma_free_coherent(&pHba->pDev->dev, sizeof(i2o_status_block),
10348c2ecf20Sopenharmony_ci			pHba->status_block, pHba->status_block_pa);
10358c2ecf20Sopenharmony_ci	}
10368c2ecf20Sopenharmony_ci	if(pHba->reply_pool) {
10378c2ecf20Sopenharmony_ci		dma_free_coherent(&pHba->pDev->dev,
10388c2ecf20Sopenharmony_ci			pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4,
10398c2ecf20Sopenharmony_ci			pHba->reply_pool, pHba->reply_pool_pa);
10408c2ecf20Sopenharmony_ci	}
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci	for(d = pHba->devices; d ; d = next){
10438c2ecf20Sopenharmony_ci		next = d->next;
10448c2ecf20Sopenharmony_ci		kfree(d);
10458c2ecf20Sopenharmony_ci	}
10468c2ecf20Sopenharmony_ci	for(i = 0 ; i < pHba->top_scsi_channel ; i++){
10478c2ecf20Sopenharmony_ci		for(j = 0; j < MAX_ID; j++){
10488c2ecf20Sopenharmony_ci			if(pHba->channel[i].device[j] != NULL){
10498c2ecf20Sopenharmony_ci				for(pDev = pHba->channel[i].device[j]; pDev; pDev = pNext){
10508c2ecf20Sopenharmony_ci					pNext = pDev->next_lun;
10518c2ecf20Sopenharmony_ci					kfree(pDev);
10528c2ecf20Sopenharmony_ci				}
10538c2ecf20Sopenharmony_ci			}
10548c2ecf20Sopenharmony_ci		}
10558c2ecf20Sopenharmony_ci	}
10568c2ecf20Sopenharmony_ci	pci_dev_put(pHba->pDev);
10578c2ecf20Sopenharmony_ci	if (adpt_sysfs_class)
10588c2ecf20Sopenharmony_ci		device_destroy(adpt_sysfs_class,
10598c2ecf20Sopenharmony_ci				MKDEV(DPTI_I2O_MAJOR, pHba->unit));
10608c2ecf20Sopenharmony_ci	kfree(pHba);
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	if(hba_count <= 0){
10638c2ecf20Sopenharmony_ci		unregister_chrdev(DPTI_I2O_MAJOR, DPT_DRIVER);
10648c2ecf20Sopenharmony_ci		if (adpt_sysfs_class) {
10658c2ecf20Sopenharmony_ci			class_destroy(adpt_sysfs_class);
10668c2ecf20Sopenharmony_ci			adpt_sysfs_class = NULL;
10678c2ecf20Sopenharmony_ci		}
10688c2ecf20Sopenharmony_ci	}
10698c2ecf20Sopenharmony_ci}
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_cistatic struct adpt_device* adpt_find_device(adpt_hba* pHba, u32 chan, u32 id, u64 lun)
10728c2ecf20Sopenharmony_ci{
10738c2ecf20Sopenharmony_ci	struct adpt_device* d;
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	if (chan >= MAX_CHANNEL)
10768c2ecf20Sopenharmony_ci		return NULL;
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	d = pHba->channel[chan].device[id];
10798c2ecf20Sopenharmony_ci	if(!d || d->tid == 0) {
10808c2ecf20Sopenharmony_ci		return NULL;
10818c2ecf20Sopenharmony_ci	}
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	/* If it is the only lun at that address then this should match*/
10848c2ecf20Sopenharmony_ci	if(d->scsi_lun == lun){
10858c2ecf20Sopenharmony_ci		return d;
10868c2ecf20Sopenharmony_ci	}
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci	/* else we need to look through all the luns */
10898c2ecf20Sopenharmony_ci	for(d=d->next_lun ; d ; d = d->next_lun){
10908c2ecf20Sopenharmony_ci		if(d->scsi_lun == lun){
10918c2ecf20Sopenharmony_ci			return d;
10928c2ecf20Sopenharmony_ci		}
10938c2ecf20Sopenharmony_ci	}
10948c2ecf20Sopenharmony_ci	return NULL;
10958c2ecf20Sopenharmony_ci}
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_cistatic int adpt_i2o_post_wait(adpt_hba* pHba, u32* msg, int len, int timeout)
10998c2ecf20Sopenharmony_ci{
11008c2ecf20Sopenharmony_ci	// I used my own version of the WAIT_QUEUE_HEAD
11018c2ecf20Sopenharmony_ci	// to handle some version differences
11028c2ecf20Sopenharmony_ci	// When embedded in the kernel this could go back to the vanilla one
11038c2ecf20Sopenharmony_ci	ADPT_DECLARE_WAIT_QUEUE_HEAD(adpt_wq_i2o_post);
11048c2ecf20Sopenharmony_ci	int status = 0;
11058c2ecf20Sopenharmony_ci	ulong flags = 0;
11068c2ecf20Sopenharmony_ci	struct adpt_i2o_post_wait_data *p1, *p2;
11078c2ecf20Sopenharmony_ci	struct adpt_i2o_post_wait_data *wait_data =
11088c2ecf20Sopenharmony_ci		kmalloc(sizeof(struct adpt_i2o_post_wait_data), GFP_ATOMIC);
11098c2ecf20Sopenharmony_ci	DECLARE_WAITQUEUE(wait, current);
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	if (!wait_data)
11128c2ecf20Sopenharmony_ci		return -ENOMEM;
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	/*
11158c2ecf20Sopenharmony_ci	 * The spin locking is needed to keep anyone from playing
11168c2ecf20Sopenharmony_ci	 * with the queue pointers and id while we do the same
11178c2ecf20Sopenharmony_ci	 */
11188c2ecf20Sopenharmony_ci	spin_lock_irqsave(&adpt_post_wait_lock, flags);
11198c2ecf20Sopenharmony_ci       // TODO we need a MORE unique way of getting ids
11208c2ecf20Sopenharmony_ci       // to support async LCT get
11218c2ecf20Sopenharmony_ci	wait_data->next = adpt_post_wait_queue;
11228c2ecf20Sopenharmony_ci	adpt_post_wait_queue = wait_data;
11238c2ecf20Sopenharmony_ci	adpt_post_wait_id++;
11248c2ecf20Sopenharmony_ci	adpt_post_wait_id &= 0x7fff;
11258c2ecf20Sopenharmony_ci	wait_data->id =  adpt_post_wait_id;
11268c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&adpt_post_wait_lock, flags);
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci	wait_data->wq = &adpt_wq_i2o_post;
11298c2ecf20Sopenharmony_ci	wait_data->status = -ETIMEDOUT;
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	add_wait_queue(&adpt_wq_i2o_post, &wait);
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci	msg[2] |= 0x80000000 | ((u32)wait_data->id);
11348c2ecf20Sopenharmony_ci	timeout *= HZ;
11358c2ecf20Sopenharmony_ci	if((status = adpt_i2o_post_this(pHba, msg, len)) == 0){
11368c2ecf20Sopenharmony_ci		set_current_state(TASK_INTERRUPTIBLE);
11378c2ecf20Sopenharmony_ci		if(pHba->host)
11388c2ecf20Sopenharmony_ci			spin_unlock_irq(pHba->host->host_lock);
11398c2ecf20Sopenharmony_ci		if (!timeout)
11408c2ecf20Sopenharmony_ci			schedule();
11418c2ecf20Sopenharmony_ci		else{
11428c2ecf20Sopenharmony_ci			timeout = schedule_timeout(timeout);
11438c2ecf20Sopenharmony_ci			if (timeout == 0) {
11448c2ecf20Sopenharmony_ci				// I/O issued, but cannot get result in
11458c2ecf20Sopenharmony_ci				// specified time. Freeing resorces is
11468c2ecf20Sopenharmony_ci				// dangerous.
11478c2ecf20Sopenharmony_ci				status = -ETIME;
11488c2ecf20Sopenharmony_ci			}
11498c2ecf20Sopenharmony_ci		}
11508c2ecf20Sopenharmony_ci		if(pHba->host)
11518c2ecf20Sopenharmony_ci			spin_lock_irq(pHba->host->host_lock);
11528c2ecf20Sopenharmony_ci	}
11538c2ecf20Sopenharmony_ci	remove_wait_queue(&adpt_wq_i2o_post, &wait);
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci	if(status == -ETIMEDOUT){
11568c2ecf20Sopenharmony_ci		printk(KERN_INFO"dpti%d: POST WAIT TIMEOUT\n",pHba->unit);
11578c2ecf20Sopenharmony_ci		// We will have to free the wait_data memory during shutdown
11588c2ecf20Sopenharmony_ci		return status;
11598c2ecf20Sopenharmony_ci	}
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	/* Remove the entry from the queue.  */
11628c2ecf20Sopenharmony_ci	p2 = NULL;
11638c2ecf20Sopenharmony_ci	spin_lock_irqsave(&adpt_post_wait_lock, flags);
11648c2ecf20Sopenharmony_ci	for(p1 = adpt_post_wait_queue; p1; p2 = p1, p1 = p1->next) {
11658c2ecf20Sopenharmony_ci		if(p1 == wait_data) {
11668c2ecf20Sopenharmony_ci			if(p1->status == I2O_DETAIL_STATUS_UNSUPPORTED_FUNCTION ) {
11678c2ecf20Sopenharmony_ci				status = -EOPNOTSUPP;
11688c2ecf20Sopenharmony_ci			}
11698c2ecf20Sopenharmony_ci			if(p2) {
11708c2ecf20Sopenharmony_ci				p2->next = p1->next;
11718c2ecf20Sopenharmony_ci			} else {
11728c2ecf20Sopenharmony_ci				adpt_post_wait_queue = p1->next;
11738c2ecf20Sopenharmony_ci			}
11748c2ecf20Sopenharmony_ci			break;
11758c2ecf20Sopenharmony_ci		}
11768c2ecf20Sopenharmony_ci	}
11778c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&adpt_post_wait_lock, flags);
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci	kfree(wait_data);
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	return status;
11828c2ecf20Sopenharmony_ci}
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_cistatic s32 adpt_i2o_post_this(adpt_hba* pHba, u32* data, int len)
11868c2ecf20Sopenharmony_ci{
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	u32 m = EMPTY_QUEUE;
11898c2ecf20Sopenharmony_ci	u32 __iomem *msg;
11908c2ecf20Sopenharmony_ci	ulong timeout = jiffies + 30*HZ;
11918c2ecf20Sopenharmony_ci	do {
11928c2ecf20Sopenharmony_ci		rmb();
11938c2ecf20Sopenharmony_ci		m = readl(pHba->post_port);
11948c2ecf20Sopenharmony_ci		if (m != EMPTY_QUEUE) {
11958c2ecf20Sopenharmony_ci			break;
11968c2ecf20Sopenharmony_ci		}
11978c2ecf20Sopenharmony_ci		if(time_after(jiffies,timeout)){
11988c2ecf20Sopenharmony_ci			printk(KERN_WARNING"dpti%d: Timeout waiting for message frame!\n", pHba->unit);
11998c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
12008c2ecf20Sopenharmony_ci		}
12018c2ecf20Sopenharmony_ci		schedule_timeout_uninterruptible(1);
12028c2ecf20Sopenharmony_ci	} while(m == EMPTY_QUEUE);
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci	msg = pHba->msg_addr_virt + m;
12058c2ecf20Sopenharmony_ci	memcpy_toio(msg, data, len);
12068c2ecf20Sopenharmony_ci	wmb();
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	//post message
12098c2ecf20Sopenharmony_ci	writel(m, pHba->post_port);
12108c2ecf20Sopenharmony_ci	wmb();
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	return 0;
12138c2ecf20Sopenharmony_ci}
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_cistatic void adpt_i2o_post_wait_complete(u32 context, int status)
12178c2ecf20Sopenharmony_ci{
12188c2ecf20Sopenharmony_ci	struct adpt_i2o_post_wait_data *p1 = NULL;
12198c2ecf20Sopenharmony_ci	/*
12208c2ecf20Sopenharmony_ci	 * We need to search through the adpt_post_wait
12218c2ecf20Sopenharmony_ci	 * queue to see if the given message is still
12228c2ecf20Sopenharmony_ci	 * outstanding.  If not, it means that the IOP
12238c2ecf20Sopenharmony_ci	 * took longer to respond to the message than we
12248c2ecf20Sopenharmony_ci	 * had allowed and timer has already expired.
12258c2ecf20Sopenharmony_ci	 * Not much we can do about that except log
12268c2ecf20Sopenharmony_ci	 * it for debug purposes, increase timeout, and recompile
12278c2ecf20Sopenharmony_ci	 *
12288c2ecf20Sopenharmony_ci	 * Lock needed to keep anyone from moving queue pointers
12298c2ecf20Sopenharmony_ci	 * around while we're looking through them.
12308c2ecf20Sopenharmony_ci	 */
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci	context &= 0x7fff;
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	spin_lock(&adpt_post_wait_lock);
12358c2ecf20Sopenharmony_ci	for(p1 = adpt_post_wait_queue; p1; p1 = p1->next) {
12368c2ecf20Sopenharmony_ci		if(p1->id == context) {
12378c2ecf20Sopenharmony_ci			p1->status = status;
12388c2ecf20Sopenharmony_ci			spin_unlock(&adpt_post_wait_lock);
12398c2ecf20Sopenharmony_ci			wake_up_interruptible(p1->wq);
12408c2ecf20Sopenharmony_ci			return;
12418c2ecf20Sopenharmony_ci		}
12428c2ecf20Sopenharmony_ci	}
12438c2ecf20Sopenharmony_ci	spin_unlock(&adpt_post_wait_lock);
12448c2ecf20Sopenharmony_ci        // If this happens we lose commands that probably really completed
12458c2ecf20Sopenharmony_ci	printk(KERN_DEBUG"dpti: Could Not find task %d in wait queue\n",context);
12468c2ecf20Sopenharmony_ci	printk(KERN_DEBUG"      Tasks in wait queue:\n");
12478c2ecf20Sopenharmony_ci	for(p1 = adpt_post_wait_queue; p1; p1 = p1->next) {
12488c2ecf20Sopenharmony_ci		printk(KERN_DEBUG"           %d\n",p1->id);
12498c2ecf20Sopenharmony_ci	}
12508c2ecf20Sopenharmony_ci	return;
12518c2ecf20Sopenharmony_ci}
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_cistatic s32 adpt_i2o_reset_hba(adpt_hba* pHba)
12548c2ecf20Sopenharmony_ci{
12558c2ecf20Sopenharmony_ci	u32 msg[8];
12568c2ecf20Sopenharmony_ci	u8* status;
12578c2ecf20Sopenharmony_ci	dma_addr_t addr;
12588c2ecf20Sopenharmony_ci	u32 m = EMPTY_QUEUE ;
12598c2ecf20Sopenharmony_ci	ulong timeout = jiffies + (TMOUT_IOPRESET*HZ);
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	if(pHba->initialized  == FALSE) {	// First time reset should be quick
12628c2ecf20Sopenharmony_ci		timeout = jiffies + (25*HZ);
12638c2ecf20Sopenharmony_ci	} else {
12648c2ecf20Sopenharmony_ci		adpt_i2o_quiesce_hba(pHba);
12658c2ecf20Sopenharmony_ci	}
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci	do {
12688c2ecf20Sopenharmony_ci		rmb();
12698c2ecf20Sopenharmony_ci		m = readl(pHba->post_port);
12708c2ecf20Sopenharmony_ci		if (m != EMPTY_QUEUE) {
12718c2ecf20Sopenharmony_ci			break;
12728c2ecf20Sopenharmony_ci		}
12738c2ecf20Sopenharmony_ci		if(time_after(jiffies,timeout)){
12748c2ecf20Sopenharmony_ci			printk(KERN_WARNING"Timeout waiting for message!\n");
12758c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
12768c2ecf20Sopenharmony_ci		}
12778c2ecf20Sopenharmony_ci		schedule_timeout_uninterruptible(1);
12788c2ecf20Sopenharmony_ci	} while (m == EMPTY_QUEUE);
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_ci	status = dma_alloc_coherent(&pHba->pDev->dev, 4, &addr, GFP_KERNEL);
12818c2ecf20Sopenharmony_ci	if(status == NULL) {
12828c2ecf20Sopenharmony_ci		adpt_send_nop(pHba, m);
12838c2ecf20Sopenharmony_ci		printk(KERN_ERR"IOP reset failed - no free memory.\n");
12848c2ecf20Sopenharmony_ci		return -ENOMEM;
12858c2ecf20Sopenharmony_ci	}
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0;
12888c2ecf20Sopenharmony_ci	msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID;
12898c2ecf20Sopenharmony_ci	msg[2]=0;
12908c2ecf20Sopenharmony_ci	msg[3]=0;
12918c2ecf20Sopenharmony_ci	msg[4]=0;
12928c2ecf20Sopenharmony_ci	msg[5]=0;
12938c2ecf20Sopenharmony_ci	msg[6]=dma_low(addr);
12948c2ecf20Sopenharmony_ci	msg[7]=dma_high(addr);
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci	memcpy_toio(pHba->msg_addr_virt+m, msg, sizeof(msg));
12978c2ecf20Sopenharmony_ci	wmb();
12988c2ecf20Sopenharmony_ci	writel(m, pHba->post_port);
12998c2ecf20Sopenharmony_ci	wmb();
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci	while(*status == 0){
13028c2ecf20Sopenharmony_ci		if(time_after(jiffies,timeout)){
13038c2ecf20Sopenharmony_ci			printk(KERN_WARNING"%s: IOP Reset Timeout\n",pHba->name);
13048c2ecf20Sopenharmony_ci			/* We lose 4 bytes of "status" here, but we cannot
13058c2ecf20Sopenharmony_ci			   free these because controller may awake and corrupt
13068c2ecf20Sopenharmony_ci			   those bytes at any time */
13078c2ecf20Sopenharmony_ci			/* dma_free_coherent(&pHba->pDev->dev, 4, buf, addr); */
13088c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
13098c2ecf20Sopenharmony_ci		}
13108c2ecf20Sopenharmony_ci		rmb();
13118c2ecf20Sopenharmony_ci		schedule_timeout_uninterruptible(1);
13128c2ecf20Sopenharmony_ci	}
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	if(*status == 0x01 /*I2O_EXEC_IOP_RESET_IN_PROGRESS*/) {
13158c2ecf20Sopenharmony_ci		PDEBUG("%s: Reset in progress...\n", pHba->name);
13168c2ecf20Sopenharmony_ci		// Here we wait for message frame to become available
13178c2ecf20Sopenharmony_ci		// indicated that reset has finished
13188c2ecf20Sopenharmony_ci		do {
13198c2ecf20Sopenharmony_ci			rmb();
13208c2ecf20Sopenharmony_ci			m = readl(pHba->post_port);
13218c2ecf20Sopenharmony_ci			if (m != EMPTY_QUEUE) {
13228c2ecf20Sopenharmony_ci				break;
13238c2ecf20Sopenharmony_ci			}
13248c2ecf20Sopenharmony_ci			if(time_after(jiffies,timeout)){
13258c2ecf20Sopenharmony_ci				printk(KERN_ERR "%s:Timeout waiting for IOP Reset.\n",pHba->name);
13268c2ecf20Sopenharmony_ci				/* We lose 4 bytes of "status" here, but we
13278c2ecf20Sopenharmony_ci				   cannot free these because controller may
13288c2ecf20Sopenharmony_ci				   awake and corrupt those bytes at any time */
13298c2ecf20Sopenharmony_ci				/* dma_free_coherent(&pHba->pDev->dev, 4, buf, addr); */
13308c2ecf20Sopenharmony_ci				return -ETIMEDOUT;
13318c2ecf20Sopenharmony_ci			}
13328c2ecf20Sopenharmony_ci			schedule_timeout_uninterruptible(1);
13338c2ecf20Sopenharmony_ci		} while (m == EMPTY_QUEUE);
13348c2ecf20Sopenharmony_ci		// Flush the offset
13358c2ecf20Sopenharmony_ci		adpt_send_nop(pHba, m);
13368c2ecf20Sopenharmony_ci	}
13378c2ecf20Sopenharmony_ci	adpt_i2o_status_get(pHba);
13388c2ecf20Sopenharmony_ci	if(*status == 0x02 ||
13398c2ecf20Sopenharmony_ci			pHba->status_block->iop_state != ADAPTER_STATE_RESET) {
13408c2ecf20Sopenharmony_ci		printk(KERN_WARNING"%s: Reset reject, trying to clear\n",
13418c2ecf20Sopenharmony_ci				pHba->name);
13428c2ecf20Sopenharmony_ci	} else {
13438c2ecf20Sopenharmony_ci		PDEBUG("%s: Reset completed.\n", pHba->name);
13448c2ecf20Sopenharmony_ci	}
13458c2ecf20Sopenharmony_ci
13468c2ecf20Sopenharmony_ci	dma_free_coherent(&pHba->pDev->dev, 4, status, addr);
13478c2ecf20Sopenharmony_ci#ifdef UARTDELAY
13488c2ecf20Sopenharmony_ci	// This delay is to allow someone attached to the card through the debug UART to
13498c2ecf20Sopenharmony_ci	// set up the dump levels that they want before the rest of the initialization sequence
13508c2ecf20Sopenharmony_ci	adpt_delay(20000);
13518c2ecf20Sopenharmony_ci#endif
13528c2ecf20Sopenharmony_ci	return 0;
13538c2ecf20Sopenharmony_ci}
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_cistatic int adpt_i2o_parse_lct(adpt_hba* pHba)
13578c2ecf20Sopenharmony_ci{
13588c2ecf20Sopenharmony_ci	int i;
13598c2ecf20Sopenharmony_ci	int max;
13608c2ecf20Sopenharmony_ci	int tid;
13618c2ecf20Sopenharmony_ci	struct i2o_device *d;
13628c2ecf20Sopenharmony_ci	i2o_lct *lct = pHba->lct;
13638c2ecf20Sopenharmony_ci	u8 bus_no = 0;
13648c2ecf20Sopenharmony_ci	s16 scsi_id;
13658c2ecf20Sopenharmony_ci	u64 scsi_lun;
13668c2ecf20Sopenharmony_ci	u32 buf[10]; // larger than 7, or 8 ...
13678c2ecf20Sopenharmony_ci	struct adpt_device* pDev;
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_ci	if (lct == NULL) {
13708c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: LCT is empty???\n",pHba->name);
13718c2ecf20Sopenharmony_ci		return -1;
13728c2ecf20Sopenharmony_ci	}
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	max = lct->table_size;
13758c2ecf20Sopenharmony_ci	max -= 3;
13768c2ecf20Sopenharmony_ci	max /= 9;
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	for(i=0;i<max;i++) {
13798c2ecf20Sopenharmony_ci		if( lct->lct_entry[i].user_tid != 0xfff){
13808c2ecf20Sopenharmony_ci			/*
13818c2ecf20Sopenharmony_ci			 * If we have hidden devices, we need to inform the upper layers about
13828c2ecf20Sopenharmony_ci			 * the possible maximum id reference to handle device access when
13838c2ecf20Sopenharmony_ci			 * an array is disassembled. This code has no other purpose but to
13848c2ecf20Sopenharmony_ci			 * allow us future access to devices that are currently hidden
13858c2ecf20Sopenharmony_ci			 * behind arrays, hotspares or have not been configured (JBOD mode).
13868c2ecf20Sopenharmony_ci			 */
13878c2ecf20Sopenharmony_ci			if( lct->lct_entry[i].class_id != I2O_CLASS_RANDOM_BLOCK_STORAGE &&
13888c2ecf20Sopenharmony_ci			    lct->lct_entry[i].class_id != I2O_CLASS_SCSI_PERIPHERAL &&
13898c2ecf20Sopenharmony_ci			    lct->lct_entry[i].class_id != I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL ){
13908c2ecf20Sopenharmony_ci			    	continue;
13918c2ecf20Sopenharmony_ci			}
13928c2ecf20Sopenharmony_ci			tid = lct->lct_entry[i].tid;
13938c2ecf20Sopenharmony_ci			// I2O_DPT_DEVICE_INFO_GROUP_NO;
13948c2ecf20Sopenharmony_ci			if(adpt_i2o_query_scalar(pHba, tid, 0x8000, -1, buf, 32)<0) {
13958c2ecf20Sopenharmony_ci				continue;
13968c2ecf20Sopenharmony_ci			}
13978c2ecf20Sopenharmony_ci			bus_no = buf[0]>>16;
13988c2ecf20Sopenharmony_ci			scsi_id = buf[1];
13998c2ecf20Sopenharmony_ci			scsi_lun = scsilun_to_int((struct scsi_lun *)&buf[2]);
14008c2ecf20Sopenharmony_ci			if(bus_no >= MAX_CHANNEL) {	// Something wrong skip it
14018c2ecf20Sopenharmony_ci				printk(KERN_WARNING"%s: Channel number %d out of range \n", pHba->name, bus_no);
14028c2ecf20Sopenharmony_ci				continue;
14038c2ecf20Sopenharmony_ci			}
14048c2ecf20Sopenharmony_ci			if (scsi_id >= MAX_ID){
14058c2ecf20Sopenharmony_ci				printk(KERN_WARNING"%s: SCSI ID %d out of range \n", pHba->name, bus_no);
14068c2ecf20Sopenharmony_ci				continue;
14078c2ecf20Sopenharmony_ci			}
14088c2ecf20Sopenharmony_ci			if(bus_no > pHba->top_scsi_channel){
14098c2ecf20Sopenharmony_ci				pHba->top_scsi_channel = bus_no;
14108c2ecf20Sopenharmony_ci			}
14118c2ecf20Sopenharmony_ci			if(scsi_id > pHba->top_scsi_id){
14128c2ecf20Sopenharmony_ci				pHba->top_scsi_id = scsi_id;
14138c2ecf20Sopenharmony_ci			}
14148c2ecf20Sopenharmony_ci			if(scsi_lun > pHba->top_scsi_lun){
14158c2ecf20Sopenharmony_ci				pHba->top_scsi_lun = scsi_lun;
14168c2ecf20Sopenharmony_ci			}
14178c2ecf20Sopenharmony_ci			continue;
14188c2ecf20Sopenharmony_ci		}
14198c2ecf20Sopenharmony_ci		d = kmalloc(sizeof(struct i2o_device), GFP_KERNEL);
14208c2ecf20Sopenharmony_ci		if(d==NULL)
14218c2ecf20Sopenharmony_ci		{
14228c2ecf20Sopenharmony_ci			printk(KERN_CRIT"%s: Out of memory for I2O device data.\n",pHba->name);
14238c2ecf20Sopenharmony_ci			return -ENOMEM;
14248c2ecf20Sopenharmony_ci		}
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci		d->controller = pHba;
14278c2ecf20Sopenharmony_ci		d->next = NULL;
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci		memcpy(&d->lct_data, &lct->lct_entry[i], sizeof(i2o_lct_entry));
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci		d->flags = 0;
14328c2ecf20Sopenharmony_ci		tid = d->lct_data.tid;
14338c2ecf20Sopenharmony_ci		adpt_i2o_report_hba_unit(pHba, d);
14348c2ecf20Sopenharmony_ci		adpt_i2o_install_device(pHba, d);
14358c2ecf20Sopenharmony_ci	}
14368c2ecf20Sopenharmony_ci	bus_no = 0;
14378c2ecf20Sopenharmony_ci	for(d = pHba->devices; d ; d = d->next) {
14388c2ecf20Sopenharmony_ci		if(d->lct_data.class_id  == I2O_CLASS_BUS_ADAPTER_PORT ||
14398c2ecf20Sopenharmony_ci		   d->lct_data.class_id  == I2O_CLASS_FIBRE_CHANNEL_PORT){
14408c2ecf20Sopenharmony_ci			tid = d->lct_data.tid;
14418c2ecf20Sopenharmony_ci			// TODO get the bus_no from hrt-but for now they are in order
14428c2ecf20Sopenharmony_ci			//bus_no =
14438c2ecf20Sopenharmony_ci			if(bus_no > pHba->top_scsi_channel){
14448c2ecf20Sopenharmony_ci				pHba->top_scsi_channel = bus_no;
14458c2ecf20Sopenharmony_ci			}
14468c2ecf20Sopenharmony_ci			pHba->channel[bus_no].type = d->lct_data.class_id;
14478c2ecf20Sopenharmony_ci			pHba->channel[bus_no].tid = tid;
14488c2ecf20Sopenharmony_ci			if(adpt_i2o_query_scalar(pHba, tid, 0x0200, -1, buf, 28)>=0)
14498c2ecf20Sopenharmony_ci			{
14508c2ecf20Sopenharmony_ci				pHba->channel[bus_no].scsi_id = buf[1];
14518c2ecf20Sopenharmony_ci				PDEBUG("Bus %d - SCSI ID %d.\n", bus_no, buf[1]);
14528c2ecf20Sopenharmony_ci			}
14538c2ecf20Sopenharmony_ci			// TODO remove - this is just until we get from hrt
14548c2ecf20Sopenharmony_ci			bus_no++;
14558c2ecf20Sopenharmony_ci			if(bus_no >= MAX_CHANNEL) {	// Something wrong skip it
14568c2ecf20Sopenharmony_ci				printk(KERN_WARNING"%s: Channel number %d out of range - LCT\n", pHba->name, bus_no);
14578c2ecf20Sopenharmony_ci				break;
14588c2ecf20Sopenharmony_ci			}
14598c2ecf20Sopenharmony_ci		}
14608c2ecf20Sopenharmony_ci	}
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_ci	// Setup adpt_device table
14638c2ecf20Sopenharmony_ci	for(d = pHba->devices; d ; d = d->next) {
14648c2ecf20Sopenharmony_ci		if(d->lct_data.class_id  == I2O_CLASS_RANDOM_BLOCK_STORAGE ||
14658c2ecf20Sopenharmony_ci		   d->lct_data.class_id  == I2O_CLASS_SCSI_PERIPHERAL ||
14668c2ecf20Sopenharmony_ci		   d->lct_data.class_id  == I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL ){
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci			tid = d->lct_data.tid;
14698c2ecf20Sopenharmony_ci			scsi_id = -1;
14708c2ecf20Sopenharmony_ci			// I2O_DPT_DEVICE_INFO_GROUP_NO;
14718c2ecf20Sopenharmony_ci			if(adpt_i2o_query_scalar(pHba, tid, 0x8000, -1, buf, 32)>=0) {
14728c2ecf20Sopenharmony_ci				bus_no = buf[0]>>16;
14738c2ecf20Sopenharmony_ci				scsi_id = buf[1];
14748c2ecf20Sopenharmony_ci				scsi_lun = scsilun_to_int((struct scsi_lun *)&buf[2]);
14758c2ecf20Sopenharmony_ci				if(bus_no >= MAX_CHANNEL) {	// Something wrong skip it
14768c2ecf20Sopenharmony_ci					continue;
14778c2ecf20Sopenharmony_ci				}
14788c2ecf20Sopenharmony_ci				if (scsi_id >= MAX_ID) {
14798c2ecf20Sopenharmony_ci					continue;
14808c2ecf20Sopenharmony_ci				}
14818c2ecf20Sopenharmony_ci				if( pHba->channel[bus_no].device[scsi_id] == NULL){
14828c2ecf20Sopenharmony_ci					pDev =  kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
14838c2ecf20Sopenharmony_ci					if(pDev == NULL) {
14848c2ecf20Sopenharmony_ci						return -ENOMEM;
14858c2ecf20Sopenharmony_ci					}
14868c2ecf20Sopenharmony_ci					pHba->channel[bus_no].device[scsi_id] = pDev;
14878c2ecf20Sopenharmony_ci				} else {
14888c2ecf20Sopenharmony_ci					for( pDev = pHba->channel[bus_no].device[scsi_id];
14898c2ecf20Sopenharmony_ci							pDev->next_lun; pDev = pDev->next_lun){
14908c2ecf20Sopenharmony_ci					}
14918c2ecf20Sopenharmony_ci					pDev->next_lun = kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
14928c2ecf20Sopenharmony_ci					if(pDev->next_lun == NULL) {
14938c2ecf20Sopenharmony_ci						return -ENOMEM;
14948c2ecf20Sopenharmony_ci					}
14958c2ecf20Sopenharmony_ci					pDev = pDev->next_lun;
14968c2ecf20Sopenharmony_ci				}
14978c2ecf20Sopenharmony_ci				pDev->tid = tid;
14988c2ecf20Sopenharmony_ci				pDev->scsi_channel = bus_no;
14998c2ecf20Sopenharmony_ci				pDev->scsi_id = scsi_id;
15008c2ecf20Sopenharmony_ci				pDev->scsi_lun = scsi_lun;
15018c2ecf20Sopenharmony_ci				pDev->pI2o_dev = d;
15028c2ecf20Sopenharmony_ci				d->owner = pDev;
15038c2ecf20Sopenharmony_ci				pDev->type = (buf[0])&0xff;
15048c2ecf20Sopenharmony_ci				pDev->flags = (buf[0]>>8)&0xff;
15058c2ecf20Sopenharmony_ci				if(scsi_id > pHba->top_scsi_id){
15068c2ecf20Sopenharmony_ci					pHba->top_scsi_id = scsi_id;
15078c2ecf20Sopenharmony_ci				}
15088c2ecf20Sopenharmony_ci				if(scsi_lun > pHba->top_scsi_lun){
15098c2ecf20Sopenharmony_ci					pHba->top_scsi_lun = scsi_lun;
15108c2ecf20Sopenharmony_ci				}
15118c2ecf20Sopenharmony_ci			}
15128c2ecf20Sopenharmony_ci			if(scsi_id == -1){
15138c2ecf20Sopenharmony_ci				printk(KERN_WARNING"Could not find SCSI ID for %s\n",
15148c2ecf20Sopenharmony_ci						d->lct_data.identity_tag);
15158c2ecf20Sopenharmony_ci			}
15168c2ecf20Sopenharmony_ci		}
15178c2ecf20Sopenharmony_ci	}
15188c2ecf20Sopenharmony_ci	return 0;
15198c2ecf20Sopenharmony_ci}
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci/*
15238c2ecf20Sopenharmony_ci *	Each I2O controller has a chain of devices on it - these match
15248c2ecf20Sopenharmony_ci *	the useful parts of the LCT of the board.
15258c2ecf20Sopenharmony_ci */
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_cistatic int adpt_i2o_install_device(adpt_hba* pHba, struct i2o_device *d)
15288c2ecf20Sopenharmony_ci{
15298c2ecf20Sopenharmony_ci	mutex_lock(&adpt_configuration_lock);
15308c2ecf20Sopenharmony_ci	d->controller=pHba;
15318c2ecf20Sopenharmony_ci	d->owner=NULL;
15328c2ecf20Sopenharmony_ci	d->next=pHba->devices;
15338c2ecf20Sopenharmony_ci	d->prev=NULL;
15348c2ecf20Sopenharmony_ci	if (pHba->devices != NULL){
15358c2ecf20Sopenharmony_ci		pHba->devices->prev=d;
15368c2ecf20Sopenharmony_ci	}
15378c2ecf20Sopenharmony_ci	pHba->devices=d;
15388c2ecf20Sopenharmony_ci	*d->dev_name = 0;
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci	mutex_unlock(&adpt_configuration_lock);
15418c2ecf20Sopenharmony_ci	return 0;
15428c2ecf20Sopenharmony_ci}
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_cistatic int adpt_open(struct inode *inode, struct file *file)
15458c2ecf20Sopenharmony_ci{
15468c2ecf20Sopenharmony_ci	int minor;
15478c2ecf20Sopenharmony_ci	adpt_hba* pHba;
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ci	mutex_lock(&adpt_mutex);
15508c2ecf20Sopenharmony_ci	//TODO check for root access
15518c2ecf20Sopenharmony_ci	//
15528c2ecf20Sopenharmony_ci	minor = iminor(inode);
15538c2ecf20Sopenharmony_ci	if (minor >= hba_count) {
15548c2ecf20Sopenharmony_ci		mutex_unlock(&adpt_mutex);
15558c2ecf20Sopenharmony_ci		return -ENXIO;
15568c2ecf20Sopenharmony_ci	}
15578c2ecf20Sopenharmony_ci	mutex_lock(&adpt_configuration_lock);
15588c2ecf20Sopenharmony_ci	for (pHba = hba_chain; pHba; pHba = pHba->next) {
15598c2ecf20Sopenharmony_ci		if (pHba->unit == minor) {
15608c2ecf20Sopenharmony_ci			break;	/* found adapter */
15618c2ecf20Sopenharmony_ci		}
15628c2ecf20Sopenharmony_ci	}
15638c2ecf20Sopenharmony_ci	if (pHba == NULL) {
15648c2ecf20Sopenharmony_ci		mutex_unlock(&adpt_configuration_lock);
15658c2ecf20Sopenharmony_ci		mutex_unlock(&adpt_mutex);
15668c2ecf20Sopenharmony_ci		return -ENXIO;
15678c2ecf20Sopenharmony_ci	}
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci//	if(pHba->in_use){
15708c2ecf20Sopenharmony_ci	//	mutex_unlock(&adpt_configuration_lock);
15718c2ecf20Sopenharmony_ci//		return -EBUSY;
15728c2ecf20Sopenharmony_ci//	}
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci	pHba->in_use = 1;
15758c2ecf20Sopenharmony_ci	mutex_unlock(&adpt_configuration_lock);
15768c2ecf20Sopenharmony_ci	mutex_unlock(&adpt_mutex);
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci	return 0;
15798c2ecf20Sopenharmony_ci}
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_cistatic int adpt_close(struct inode *inode, struct file *file)
15828c2ecf20Sopenharmony_ci{
15838c2ecf20Sopenharmony_ci	int minor;
15848c2ecf20Sopenharmony_ci	adpt_hba* pHba;
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci	minor = iminor(inode);
15878c2ecf20Sopenharmony_ci	if (minor >= hba_count) {
15888c2ecf20Sopenharmony_ci		return -ENXIO;
15898c2ecf20Sopenharmony_ci	}
15908c2ecf20Sopenharmony_ci	mutex_lock(&adpt_configuration_lock);
15918c2ecf20Sopenharmony_ci	for (pHba = hba_chain; pHba; pHba = pHba->next) {
15928c2ecf20Sopenharmony_ci		if (pHba->unit == minor) {
15938c2ecf20Sopenharmony_ci			break;	/* found adapter */
15948c2ecf20Sopenharmony_ci		}
15958c2ecf20Sopenharmony_ci	}
15968c2ecf20Sopenharmony_ci	mutex_unlock(&adpt_configuration_lock);
15978c2ecf20Sopenharmony_ci	if (pHba == NULL) {
15988c2ecf20Sopenharmony_ci		return -ENXIO;
15998c2ecf20Sopenharmony_ci	}
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci	pHba->in_use = 0;
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_ci	return 0;
16048c2ecf20Sopenharmony_ci}
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci#if defined __ia64__
16078c2ecf20Sopenharmony_cistatic void adpt_ia64_info(sysInfo_S* si)
16088c2ecf20Sopenharmony_ci{
16098c2ecf20Sopenharmony_ci	// This is all the info we need for now
16108c2ecf20Sopenharmony_ci	// We will add more info as our new
16118c2ecf20Sopenharmony_ci	// managmenent utility requires it
16128c2ecf20Sopenharmony_ci	si->processorType = PROC_IA64;
16138c2ecf20Sopenharmony_ci}
16148c2ecf20Sopenharmony_ci#endif
16158c2ecf20Sopenharmony_ci
16168c2ecf20Sopenharmony_ci#if defined __sparc__
16178c2ecf20Sopenharmony_cistatic void adpt_sparc_info(sysInfo_S* si)
16188c2ecf20Sopenharmony_ci{
16198c2ecf20Sopenharmony_ci	// This is all the info we need for now
16208c2ecf20Sopenharmony_ci	// We will add more info as our new
16218c2ecf20Sopenharmony_ci	// managmenent utility requires it
16228c2ecf20Sopenharmony_ci	si->processorType = PROC_ULTRASPARC;
16238c2ecf20Sopenharmony_ci}
16248c2ecf20Sopenharmony_ci#endif
16258c2ecf20Sopenharmony_ci#if defined __alpha__
16268c2ecf20Sopenharmony_cistatic void adpt_alpha_info(sysInfo_S* si)
16278c2ecf20Sopenharmony_ci{
16288c2ecf20Sopenharmony_ci	// This is all the info we need for now
16298c2ecf20Sopenharmony_ci	// We will add more info as our new
16308c2ecf20Sopenharmony_ci	// managmenent utility requires it
16318c2ecf20Sopenharmony_ci	si->processorType = PROC_ALPHA;
16328c2ecf20Sopenharmony_ci}
16338c2ecf20Sopenharmony_ci#endif
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci#if defined __i386__
16368c2ecf20Sopenharmony_ci
16378c2ecf20Sopenharmony_ci#include <uapi/asm/vm86.h>
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_cistatic void adpt_i386_info(sysInfo_S* si)
16408c2ecf20Sopenharmony_ci{
16418c2ecf20Sopenharmony_ci	// This is all the info we need for now
16428c2ecf20Sopenharmony_ci	// We will add more info as our new
16438c2ecf20Sopenharmony_ci	// managmenent utility requires it
16448c2ecf20Sopenharmony_ci	switch (boot_cpu_data.x86) {
16458c2ecf20Sopenharmony_ci	case CPU_386:
16468c2ecf20Sopenharmony_ci		si->processorType = PROC_386;
16478c2ecf20Sopenharmony_ci		break;
16488c2ecf20Sopenharmony_ci	case CPU_486:
16498c2ecf20Sopenharmony_ci		si->processorType = PROC_486;
16508c2ecf20Sopenharmony_ci		break;
16518c2ecf20Sopenharmony_ci	case CPU_586:
16528c2ecf20Sopenharmony_ci		si->processorType = PROC_PENTIUM;
16538c2ecf20Sopenharmony_ci		break;
16548c2ecf20Sopenharmony_ci	default:  // Just in case
16558c2ecf20Sopenharmony_ci		si->processorType = PROC_PENTIUM;
16568c2ecf20Sopenharmony_ci		break;
16578c2ecf20Sopenharmony_ci	}
16588c2ecf20Sopenharmony_ci}
16598c2ecf20Sopenharmony_ci#endif
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_ci/*
16628c2ecf20Sopenharmony_ci * This routine returns information about the system.  This does not effect
16638c2ecf20Sopenharmony_ci * any logic and if the info is wrong - it doesn't matter.
16648c2ecf20Sopenharmony_ci */
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci/* Get all the info we can not get from kernel services */
16678c2ecf20Sopenharmony_cistatic int adpt_system_info(void __user *buffer)
16688c2ecf20Sopenharmony_ci{
16698c2ecf20Sopenharmony_ci	sysInfo_S si;
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci	memset(&si, 0, sizeof(si));
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci	si.osType = OS_LINUX;
16748c2ecf20Sopenharmony_ci	si.osMajorVersion = 0;
16758c2ecf20Sopenharmony_ci	si.osMinorVersion = 0;
16768c2ecf20Sopenharmony_ci	si.osRevision = 0;
16778c2ecf20Sopenharmony_ci	si.busType = SI_PCI_BUS;
16788c2ecf20Sopenharmony_ci	si.processorFamily = DPTI_sig.dsProcessorFamily;
16798c2ecf20Sopenharmony_ci
16808c2ecf20Sopenharmony_ci#if defined __i386__
16818c2ecf20Sopenharmony_ci	adpt_i386_info(&si);
16828c2ecf20Sopenharmony_ci#elif defined (__ia64__)
16838c2ecf20Sopenharmony_ci	adpt_ia64_info(&si);
16848c2ecf20Sopenharmony_ci#elif defined(__sparc__)
16858c2ecf20Sopenharmony_ci	adpt_sparc_info(&si);
16868c2ecf20Sopenharmony_ci#elif defined (__alpha__)
16878c2ecf20Sopenharmony_ci	adpt_alpha_info(&si);
16888c2ecf20Sopenharmony_ci#else
16898c2ecf20Sopenharmony_ci	si.processorType = 0xff ;
16908c2ecf20Sopenharmony_ci#endif
16918c2ecf20Sopenharmony_ci	if (copy_to_user(buffer, &si, sizeof(si))){
16928c2ecf20Sopenharmony_ci		printk(KERN_WARNING"dpti: Could not copy buffer TO user\n");
16938c2ecf20Sopenharmony_ci		return -EFAULT;
16948c2ecf20Sopenharmony_ci	}
16958c2ecf20Sopenharmony_ci
16968c2ecf20Sopenharmony_ci	return 0;
16978c2ecf20Sopenharmony_ci}
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_cistatic int adpt_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
17008c2ecf20Sopenharmony_ci{
17018c2ecf20Sopenharmony_ci	int minor;
17028c2ecf20Sopenharmony_ci	int error = 0;
17038c2ecf20Sopenharmony_ci	adpt_hba* pHba;
17048c2ecf20Sopenharmony_ci	ulong flags = 0;
17058c2ecf20Sopenharmony_ci	void __user *argp = (void __user *)arg;
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_ci	minor = iminor(inode);
17088c2ecf20Sopenharmony_ci	if (minor >= DPTI_MAX_HBA){
17098c2ecf20Sopenharmony_ci		return -ENXIO;
17108c2ecf20Sopenharmony_ci	}
17118c2ecf20Sopenharmony_ci	mutex_lock(&adpt_configuration_lock);
17128c2ecf20Sopenharmony_ci	for (pHba = hba_chain; pHba; pHba = pHba->next) {
17138c2ecf20Sopenharmony_ci		if (pHba->unit == minor) {
17148c2ecf20Sopenharmony_ci			break;	/* found adapter */
17158c2ecf20Sopenharmony_ci		}
17168c2ecf20Sopenharmony_ci	}
17178c2ecf20Sopenharmony_ci	mutex_unlock(&adpt_configuration_lock);
17188c2ecf20Sopenharmony_ci	if(pHba == NULL){
17198c2ecf20Sopenharmony_ci		return -ENXIO;
17208c2ecf20Sopenharmony_ci	}
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci	while((volatile u32) pHba->state & DPTI_STATE_RESET )
17238c2ecf20Sopenharmony_ci		schedule_timeout_uninterruptible(2);
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_ci	switch (cmd) {
17268c2ecf20Sopenharmony_ci	// TODO: handle 3 cases
17278c2ecf20Sopenharmony_ci	case DPT_SIGNATURE:
17288c2ecf20Sopenharmony_ci		if (copy_to_user(argp, &DPTI_sig, sizeof(DPTI_sig))) {
17298c2ecf20Sopenharmony_ci			return -EFAULT;
17308c2ecf20Sopenharmony_ci		}
17318c2ecf20Sopenharmony_ci		break;
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_ci	case DPT_CTRLINFO:{
17348c2ecf20Sopenharmony_ci		drvrHBAinfo_S HbaInfo;
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_ci#define FLG_OSD_PCI_VALID 0x0001
17378c2ecf20Sopenharmony_ci#define FLG_OSD_DMA	  0x0002
17388c2ecf20Sopenharmony_ci#define FLG_OSD_I2O	  0x0004
17398c2ecf20Sopenharmony_ci		memset(&HbaInfo, 0, sizeof(HbaInfo));
17408c2ecf20Sopenharmony_ci		HbaInfo.drvrHBAnum = pHba->unit;
17418c2ecf20Sopenharmony_ci		HbaInfo.baseAddr = (ulong) pHba->base_addr_phys;
17428c2ecf20Sopenharmony_ci		HbaInfo.blinkState = adpt_read_blink_led(pHba);
17438c2ecf20Sopenharmony_ci		HbaInfo.pciBusNum =  pHba->pDev->bus->number;
17448c2ecf20Sopenharmony_ci		HbaInfo.pciDeviceNum=PCI_SLOT(pHba->pDev->devfn);
17458c2ecf20Sopenharmony_ci		HbaInfo.Interrupt = pHba->pDev->irq;
17468c2ecf20Sopenharmony_ci		HbaInfo.hbaFlags = FLG_OSD_PCI_VALID | FLG_OSD_DMA | FLG_OSD_I2O;
17478c2ecf20Sopenharmony_ci		if(copy_to_user(argp, &HbaInfo, sizeof(HbaInfo))){
17488c2ecf20Sopenharmony_ci			printk(KERN_WARNING"%s: Could not copy HbaInfo TO user\n",pHba->name);
17498c2ecf20Sopenharmony_ci			return -EFAULT;
17508c2ecf20Sopenharmony_ci		}
17518c2ecf20Sopenharmony_ci		break;
17528c2ecf20Sopenharmony_ci		}
17538c2ecf20Sopenharmony_ci	case DPT_SYSINFO:
17548c2ecf20Sopenharmony_ci		return adpt_system_info(argp);
17558c2ecf20Sopenharmony_ci	case DPT_BLINKLED:{
17568c2ecf20Sopenharmony_ci		u32 value;
17578c2ecf20Sopenharmony_ci		value = (u32)adpt_read_blink_led(pHba);
17588c2ecf20Sopenharmony_ci		if (copy_to_user(argp, &value, sizeof(value))) {
17598c2ecf20Sopenharmony_ci			return -EFAULT;
17608c2ecf20Sopenharmony_ci		}
17618c2ecf20Sopenharmony_ci		break;
17628c2ecf20Sopenharmony_ci		}
17638c2ecf20Sopenharmony_ci	case I2ORESETCMD: {
17648c2ecf20Sopenharmony_ci		struct Scsi_Host *shost = pHba->host;
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci		if (shost)
17678c2ecf20Sopenharmony_ci			spin_lock_irqsave(shost->host_lock, flags);
17688c2ecf20Sopenharmony_ci		adpt_hba_reset(pHba);
17698c2ecf20Sopenharmony_ci		if (shost)
17708c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(shost->host_lock, flags);
17718c2ecf20Sopenharmony_ci		break;
17728c2ecf20Sopenharmony_ci	}
17738c2ecf20Sopenharmony_ci	case I2ORESCANCMD:
17748c2ecf20Sopenharmony_ci		adpt_rescan(pHba);
17758c2ecf20Sopenharmony_ci		break;
17768c2ecf20Sopenharmony_ci	default:
17778c2ecf20Sopenharmony_ci		return -EINVAL;
17788c2ecf20Sopenharmony_ci	}
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci	return error;
17818c2ecf20Sopenharmony_ci}
17828c2ecf20Sopenharmony_ci
17838c2ecf20Sopenharmony_cistatic long adpt_unlocked_ioctl(struct file *file, uint cmd, ulong arg)
17848c2ecf20Sopenharmony_ci{
17858c2ecf20Sopenharmony_ci	struct inode *inode;
17868c2ecf20Sopenharmony_ci	long ret;
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_ci	inode = file_inode(file);
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci	mutex_lock(&adpt_mutex);
17918c2ecf20Sopenharmony_ci	ret = adpt_ioctl(inode, file, cmd, arg);
17928c2ecf20Sopenharmony_ci	mutex_unlock(&adpt_mutex);
17938c2ecf20Sopenharmony_ci
17948c2ecf20Sopenharmony_ci	return ret;
17958c2ecf20Sopenharmony_ci}
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT
17988c2ecf20Sopenharmony_cistatic long compat_adpt_ioctl(struct file *file,
17998c2ecf20Sopenharmony_ci				unsigned int cmd, unsigned long arg)
18008c2ecf20Sopenharmony_ci{
18018c2ecf20Sopenharmony_ci	struct inode *inode;
18028c2ecf20Sopenharmony_ci	long ret;
18038c2ecf20Sopenharmony_ci
18048c2ecf20Sopenharmony_ci	inode = file_inode(file);
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci	mutex_lock(&adpt_mutex);
18078c2ecf20Sopenharmony_ci
18088c2ecf20Sopenharmony_ci	switch(cmd) {
18098c2ecf20Sopenharmony_ci		case DPT_SIGNATURE:
18108c2ecf20Sopenharmony_ci		case I2OUSRCMD:
18118c2ecf20Sopenharmony_ci		case DPT_CTRLINFO:
18128c2ecf20Sopenharmony_ci		case DPT_SYSINFO:
18138c2ecf20Sopenharmony_ci		case DPT_BLINKLED:
18148c2ecf20Sopenharmony_ci		case I2ORESETCMD:
18158c2ecf20Sopenharmony_ci		case I2ORESCANCMD:
18168c2ecf20Sopenharmony_ci		case (DPT_TARGET_BUSY & 0xFFFF):
18178c2ecf20Sopenharmony_ci		case DPT_TARGET_BUSY:
18188c2ecf20Sopenharmony_ci			ret = adpt_ioctl(inode, file, cmd, arg);
18198c2ecf20Sopenharmony_ci			break;
18208c2ecf20Sopenharmony_ci		default:
18218c2ecf20Sopenharmony_ci			ret =  -ENOIOCTLCMD;
18228c2ecf20Sopenharmony_ci	}
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_ci	mutex_unlock(&adpt_mutex);
18258c2ecf20Sopenharmony_ci
18268c2ecf20Sopenharmony_ci	return ret;
18278c2ecf20Sopenharmony_ci}
18288c2ecf20Sopenharmony_ci#endif
18298c2ecf20Sopenharmony_ci
18308c2ecf20Sopenharmony_cistatic irqreturn_t adpt_isr(int irq, void *dev_id)
18318c2ecf20Sopenharmony_ci{
18328c2ecf20Sopenharmony_ci	struct scsi_cmnd* cmd;
18338c2ecf20Sopenharmony_ci	adpt_hba* pHba = dev_id;
18348c2ecf20Sopenharmony_ci	u32 m;
18358c2ecf20Sopenharmony_ci	void __iomem *reply;
18368c2ecf20Sopenharmony_ci	u32 status=0;
18378c2ecf20Sopenharmony_ci	u32 context;
18388c2ecf20Sopenharmony_ci	ulong flags = 0;
18398c2ecf20Sopenharmony_ci	int handled = 0;
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ci	if (pHba == NULL){
18428c2ecf20Sopenharmony_ci		printk(KERN_WARNING"adpt_isr: NULL dev_id\n");
18438c2ecf20Sopenharmony_ci		return IRQ_NONE;
18448c2ecf20Sopenharmony_ci	}
18458c2ecf20Sopenharmony_ci	if(pHba->host)
18468c2ecf20Sopenharmony_ci		spin_lock_irqsave(pHba->host->host_lock, flags);
18478c2ecf20Sopenharmony_ci
18488c2ecf20Sopenharmony_ci	while( readl(pHba->irq_mask) & I2O_INTERRUPT_PENDING_B) {
18498c2ecf20Sopenharmony_ci		m = readl(pHba->reply_port);
18508c2ecf20Sopenharmony_ci		if(m == EMPTY_QUEUE){
18518c2ecf20Sopenharmony_ci			// Try twice then give up
18528c2ecf20Sopenharmony_ci			rmb();
18538c2ecf20Sopenharmony_ci			m = readl(pHba->reply_port);
18548c2ecf20Sopenharmony_ci			if(m == EMPTY_QUEUE){
18558c2ecf20Sopenharmony_ci				// This really should not happen
18568c2ecf20Sopenharmony_ci				printk(KERN_ERR"dpti: Could not get reply frame\n");
18578c2ecf20Sopenharmony_ci				goto out;
18588c2ecf20Sopenharmony_ci			}
18598c2ecf20Sopenharmony_ci		}
18608c2ecf20Sopenharmony_ci		if (pHba->reply_pool_pa <= m &&
18618c2ecf20Sopenharmony_ci		    m < pHba->reply_pool_pa +
18628c2ecf20Sopenharmony_ci			(pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4)) {
18638c2ecf20Sopenharmony_ci			reply = (u8 *)pHba->reply_pool +
18648c2ecf20Sopenharmony_ci						(m - pHba->reply_pool_pa);
18658c2ecf20Sopenharmony_ci		} else {
18668c2ecf20Sopenharmony_ci			/* Ick, we should *never* be here */
18678c2ecf20Sopenharmony_ci			printk(KERN_ERR "dpti: reply frame not from pool\n");
18688c2ecf20Sopenharmony_ci			continue;
18698c2ecf20Sopenharmony_ci		}
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_ci		if (readl(reply) & MSG_FAIL) {
18728c2ecf20Sopenharmony_ci			u32 old_m = readl(reply+28);
18738c2ecf20Sopenharmony_ci			void __iomem *msg;
18748c2ecf20Sopenharmony_ci			u32 old_context;
18758c2ecf20Sopenharmony_ci			PDEBUG("%s: Failed message\n",pHba->name);
18768c2ecf20Sopenharmony_ci			if(old_m >= 0x100000){
18778c2ecf20Sopenharmony_ci				printk(KERN_ERR"%s: Bad preserved MFA (%x)- dropping frame\n",pHba->name,old_m);
18788c2ecf20Sopenharmony_ci				writel(m,pHba->reply_port);
18798c2ecf20Sopenharmony_ci				continue;
18808c2ecf20Sopenharmony_ci			}
18818c2ecf20Sopenharmony_ci			// Transaction context is 0 in failed reply frame
18828c2ecf20Sopenharmony_ci			msg = pHba->msg_addr_virt + old_m;
18838c2ecf20Sopenharmony_ci			old_context = readl(msg+12);
18848c2ecf20Sopenharmony_ci			writel(old_context, reply+12);
18858c2ecf20Sopenharmony_ci			adpt_send_nop(pHba, old_m);
18868c2ecf20Sopenharmony_ci		}
18878c2ecf20Sopenharmony_ci		context = readl(reply+8);
18888c2ecf20Sopenharmony_ci		if(context & 0x80000000){ // Post wait message
18898c2ecf20Sopenharmony_ci			status = readl(reply+16);
18908c2ecf20Sopenharmony_ci			if(status  >> 24){
18918c2ecf20Sopenharmony_ci				status &=  0xffff; /* Get detail status */
18928c2ecf20Sopenharmony_ci			} else {
18938c2ecf20Sopenharmony_ci				status = I2O_POST_WAIT_OK;
18948c2ecf20Sopenharmony_ci			}
18958c2ecf20Sopenharmony_ci			/*
18968c2ecf20Sopenharmony_ci			 * The request tag is one less than the command tag
18978c2ecf20Sopenharmony_ci			 * as the firmware might treat a 0 tag as invalid
18988c2ecf20Sopenharmony_ci			 */
18998c2ecf20Sopenharmony_ci			cmd = scsi_host_find_tag(pHba->host,
19008c2ecf20Sopenharmony_ci						 readl(reply + 12) - 1);
19018c2ecf20Sopenharmony_ci			if(cmd != NULL) {
19028c2ecf20Sopenharmony_ci				printk(KERN_WARNING"%s: Apparent SCSI cmd in Post Wait Context - cmd=%p context=%x\n", pHba->name, cmd, context);
19038c2ecf20Sopenharmony_ci			}
19048c2ecf20Sopenharmony_ci			adpt_i2o_post_wait_complete(context, status);
19058c2ecf20Sopenharmony_ci		} else { // SCSI message
19068c2ecf20Sopenharmony_ci			/*
19078c2ecf20Sopenharmony_ci			 * The request tag is one less than the command tag
19088c2ecf20Sopenharmony_ci			 * as the firmware might treat a 0 tag as invalid
19098c2ecf20Sopenharmony_ci			 */
19108c2ecf20Sopenharmony_ci			cmd = scsi_host_find_tag(pHba->host,
19118c2ecf20Sopenharmony_ci						 readl(reply + 12) - 1);
19128c2ecf20Sopenharmony_ci			if(cmd != NULL){
19138c2ecf20Sopenharmony_ci				scsi_dma_unmap(cmd);
19148c2ecf20Sopenharmony_ci				adpt_i2o_scsi_complete(reply, cmd);
19158c2ecf20Sopenharmony_ci			}
19168c2ecf20Sopenharmony_ci		}
19178c2ecf20Sopenharmony_ci		writel(m, pHba->reply_port);
19188c2ecf20Sopenharmony_ci		wmb();
19198c2ecf20Sopenharmony_ci		rmb();
19208c2ecf20Sopenharmony_ci	}
19218c2ecf20Sopenharmony_ci	handled = 1;
19228c2ecf20Sopenharmony_ciout:	if(pHba->host)
19238c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(pHba->host->host_lock, flags);
19248c2ecf20Sopenharmony_ci	return IRQ_RETVAL(handled);
19258c2ecf20Sopenharmony_ci}
19268c2ecf20Sopenharmony_ci
19278c2ecf20Sopenharmony_cistatic s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_device* d)
19288c2ecf20Sopenharmony_ci{
19298c2ecf20Sopenharmony_ci	int i;
19308c2ecf20Sopenharmony_ci	u32 msg[MAX_MESSAGE_SIZE];
19318c2ecf20Sopenharmony_ci	u32* mptr;
19328c2ecf20Sopenharmony_ci	u32* lptr;
19338c2ecf20Sopenharmony_ci	u32 *lenptr;
19348c2ecf20Sopenharmony_ci	int direction;
19358c2ecf20Sopenharmony_ci	int scsidir;
19368c2ecf20Sopenharmony_ci	int nseg;
19378c2ecf20Sopenharmony_ci	u32 len;
19388c2ecf20Sopenharmony_ci	u32 reqlen;
19398c2ecf20Sopenharmony_ci	s32 rcode;
19408c2ecf20Sopenharmony_ci	dma_addr_t addr;
19418c2ecf20Sopenharmony_ci
19428c2ecf20Sopenharmony_ci	memset(msg, 0 , sizeof(msg));
19438c2ecf20Sopenharmony_ci	len = scsi_bufflen(cmd);
19448c2ecf20Sopenharmony_ci	direction = 0x00000000;
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_ci	scsidir = 0x00000000;			// DATA NO XFER
19478c2ecf20Sopenharmony_ci	if(len) {
19488c2ecf20Sopenharmony_ci		/*
19498c2ecf20Sopenharmony_ci		 * Set SCBFlags to indicate if data is being transferred
19508c2ecf20Sopenharmony_ci		 * in or out, or no data transfer
19518c2ecf20Sopenharmony_ci		 * Note:  Do not have to verify index is less than 0 since
19528c2ecf20Sopenharmony_ci		 * cmd->cmnd[0] is an unsigned char
19538c2ecf20Sopenharmony_ci		 */
19548c2ecf20Sopenharmony_ci		switch(cmd->sc_data_direction){
19558c2ecf20Sopenharmony_ci		case DMA_FROM_DEVICE:
19568c2ecf20Sopenharmony_ci			scsidir  =0x40000000;	// DATA IN  (iop<--dev)
19578c2ecf20Sopenharmony_ci			break;
19588c2ecf20Sopenharmony_ci		case DMA_TO_DEVICE:
19598c2ecf20Sopenharmony_ci			direction=0x04000000;	// SGL OUT
19608c2ecf20Sopenharmony_ci			scsidir  =0x80000000;	// DATA OUT (iop-->dev)
19618c2ecf20Sopenharmony_ci			break;
19628c2ecf20Sopenharmony_ci		case DMA_NONE:
19638c2ecf20Sopenharmony_ci			break;
19648c2ecf20Sopenharmony_ci		case DMA_BIDIRECTIONAL:
19658c2ecf20Sopenharmony_ci			scsidir  =0x40000000;	// DATA IN  (iop<--dev)
19668c2ecf20Sopenharmony_ci			// Assume In - and continue;
19678c2ecf20Sopenharmony_ci			break;
19688c2ecf20Sopenharmony_ci		default:
19698c2ecf20Sopenharmony_ci			printk(KERN_WARNING"%s: scsi opcode 0x%x not supported.\n",
19708c2ecf20Sopenharmony_ci			     pHba->name, cmd->cmnd[0]);
19718c2ecf20Sopenharmony_ci			cmd->result = (DID_OK <<16) | (INITIATOR_ERROR << 8);
19728c2ecf20Sopenharmony_ci			cmd->scsi_done(cmd);
19738c2ecf20Sopenharmony_ci			return 	0;
19748c2ecf20Sopenharmony_ci		}
19758c2ecf20Sopenharmony_ci	}
19768c2ecf20Sopenharmony_ci	// msg[0] is set later
19778c2ecf20Sopenharmony_ci	// I2O_CMD_SCSI_EXEC
19788c2ecf20Sopenharmony_ci	msg[1] = ((0xff<<24)|(HOST_TID<<12)|d->tid);
19798c2ecf20Sopenharmony_ci	msg[2] = 0;
19808c2ecf20Sopenharmony_ci	/* Add 1 to avoid firmware treating it as invalid command */
19818c2ecf20Sopenharmony_ci	msg[3] = cmd->request->tag + 1;
19828c2ecf20Sopenharmony_ci	// Our cards use the transaction context as the tag for queueing
19838c2ecf20Sopenharmony_ci	// Adaptec/DPT Private stuff
19848c2ecf20Sopenharmony_ci	msg[4] = I2O_CMD_SCSI_EXEC|(DPT_ORGANIZATION_ID<<16);
19858c2ecf20Sopenharmony_ci	msg[5] = d->tid;
19868c2ecf20Sopenharmony_ci	/* Direction, disconnect ok | sense data | simple queue , CDBLen */
19878c2ecf20Sopenharmony_ci	// I2O_SCB_FLAG_ENABLE_DISCONNECT |
19888c2ecf20Sopenharmony_ci	// I2O_SCB_FLAG_SIMPLE_QUEUE_TAG |
19898c2ecf20Sopenharmony_ci	// I2O_SCB_FLAG_SENSE_DATA_IN_MESSAGE;
19908c2ecf20Sopenharmony_ci	msg[6] = scsidir|0x20a00000|cmd->cmd_len;
19918c2ecf20Sopenharmony_ci
19928c2ecf20Sopenharmony_ci	mptr=msg+7;
19938c2ecf20Sopenharmony_ci
19948c2ecf20Sopenharmony_ci	// Write SCSI command into the message - always 16 byte block
19958c2ecf20Sopenharmony_ci	memset(mptr, 0,  16);
19968c2ecf20Sopenharmony_ci	memcpy(mptr, cmd->cmnd, cmd->cmd_len);
19978c2ecf20Sopenharmony_ci	mptr+=4;
19988c2ecf20Sopenharmony_ci	lenptr=mptr++;		/* Remember me - fill in when we know */
19998c2ecf20Sopenharmony_ci	if (dpt_dma64(pHba)) {
20008c2ecf20Sopenharmony_ci		reqlen = 16;		// SINGLE SGE
20018c2ecf20Sopenharmony_ci		*mptr++ = (0x7C<<24)+(2<<16)+0x02; /* Enable 64 bit */
20028c2ecf20Sopenharmony_ci		*mptr++ = 1 << PAGE_SHIFT;
20038c2ecf20Sopenharmony_ci	} else {
20048c2ecf20Sopenharmony_ci		reqlen = 14;		// SINGLE SGE
20058c2ecf20Sopenharmony_ci	}
20068c2ecf20Sopenharmony_ci	/* Now fill in the SGList and command */
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci	nseg = scsi_dma_map(cmd);
20098c2ecf20Sopenharmony_ci	BUG_ON(nseg < 0);
20108c2ecf20Sopenharmony_ci	if (nseg) {
20118c2ecf20Sopenharmony_ci		struct scatterlist *sg;
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_ci		len = 0;
20148c2ecf20Sopenharmony_ci		scsi_for_each_sg(cmd, sg, nseg, i) {
20158c2ecf20Sopenharmony_ci			lptr = mptr;
20168c2ecf20Sopenharmony_ci			*mptr++ = direction|0x10000000|sg_dma_len(sg);
20178c2ecf20Sopenharmony_ci			len+=sg_dma_len(sg);
20188c2ecf20Sopenharmony_ci			addr = sg_dma_address(sg);
20198c2ecf20Sopenharmony_ci			*mptr++ = dma_low(addr);
20208c2ecf20Sopenharmony_ci			if (dpt_dma64(pHba))
20218c2ecf20Sopenharmony_ci				*mptr++ = dma_high(addr);
20228c2ecf20Sopenharmony_ci			/* Make this an end of list */
20238c2ecf20Sopenharmony_ci			if (i == nseg - 1)
20248c2ecf20Sopenharmony_ci				*lptr = direction|0xD0000000|sg_dma_len(sg);
20258c2ecf20Sopenharmony_ci		}
20268c2ecf20Sopenharmony_ci		reqlen = mptr - msg;
20278c2ecf20Sopenharmony_ci		*lenptr = len;
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci		if(cmd->underflow && len != cmd->underflow){
20308c2ecf20Sopenharmony_ci			printk(KERN_WARNING"Cmd len %08X Cmd underflow %08X\n",
20318c2ecf20Sopenharmony_ci				len, cmd->underflow);
20328c2ecf20Sopenharmony_ci		}
20338c2ecf20Sopenharmony_ci	} else {
20348c2ecf20Sopenharmony_ci		*lenptr = len = 0;
20358c2ecf20Sopenharmony_ci		reqlen = 12;
20368c2ecf20Sopenharmony_ci	}
20378c2ecf20Sopenharmony_ci
20388c2ecf20Sopenharmony_ci	/* Stick the headers on */
20398c2ecf20Sopenharmony_ci	msg[0] = reqlen<<16 | ((reqlen > 12) ? SGL_OFFSET_12 : SGL_OFFSET_0);
20408c2ecf20Sopenharmony_ci
20418c2ecf20Sopenharmony_ci	// Send it on it's way
20428c2ecf20Sopenharmony_ci	rcode = adpt_i2o_post_this(pHba, msg, reqlen<<2);
20438c2ecf20Sopenharmony_ci	if (rcode == 0) {
20448c2ecf20Sopenharmony_ci		return 0;
20458c2ecf20Sopenharmony_ci	}
20468c2ecf20Sopenharmony_ci	return rcode;
20478c2ecf20Sopenharmony_ci}
20488c2ecf20Sopenharmony_ci
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_cistatic s32 adpt_scsi_host_alloc(adpt_hba* pHba, struct scsi_host_template *sht)
20518c2ecf20Sopenharmony_ci{
20528c2ecf20Sopenharmony_ci	struct Scsi_Host *host;
20538c2ecf20Sopenharmony_ci
20548c2ecf20Sopenharmony_ci	host = scsi_host_alloc(sht, sizeof(adpt_hba*));
20558c2ecf20Sopenharmony_ci	if (host == NULL) {
20568c2ecf20Sopenharmony_ci		printk("%s: scsi_host_alloc returned NULL\n", pHba->name);
20578c2ecf20Sopenharmony_ci		return -1;
20588c2ecf20Sopenharmony_ci	}
20598c2ecf20Sopenharmony_ci	host->hostdata[0] = (unsigned long)pHba;
20608c2ecf20Sopenharmony_ci	pHba->host = host;
20618c2ecf20Sopenharmony_ci
20628c2ecf20Sopenharmony_ci	host->irq = pHba->pDev->irq;
20638c2ecf20Sopenharmony_ci	/* no IO ports, so don't have to set host->io_port and
20648c2ecf20Sopenharmony_ci	 * host->n_io_port
20658c2ecf20Sopenharmony_ci	 */
20668c2ecf20Sopenharmony_ci	host->io_port = 0;
20678c2ecf20Sopenharmony_ci	host->n_io_port = 0;
20688c2ecf20Sopenharmony_ci				/* see comments in scsi_host.h */
20698c2ecf20Sopenharmony_ci	host->max_id = 16;
20708c2ecf20Sopenharmony_ci	host->max_lun = 256;
20718c2ecf20Sopenharmony_ci	host->max_channel = pHba->top_scsi_channel + 1;
20728c2ecf20Sopenharmony_ci	host->cmd_per_lun = 1;
20738c2ecf20Sopenharmony_ci	host->unique_id = (u32)sys_tbl_pa + pHba->unit;
20748c2ecf20Sopenharmony_ci	host->sg_tablesize = pHba->sg_tablesize;
20758c2ecf20Sopenharmony_ci	host->can_queue = pHba->post_fifo_size;
20768c2ecf20Sopenharmony_ci
20778c2ecf20Sopenharmony_ci	return 0;
20788c2ecf20Sopenharmony_ci}
20798c2ecf20Sopenharmony_ci
20808c2ecf20Sopenharmony_ci
20818c2ecf20Sopenharmony_cistatic void adpt_i2o_scsi_complete(void __iomem *reply, struct scsi_cmnd *cmd)
20828c2ecf20Sopenharmony_ci{
20838c2ecf20Sopenharmony_ci	adpt_hba* pHba;
20848c2ecf20Sopenharmony_ci	u32 hba_status;
20858c2ecf20Sopenharmony_ci	u32 dev_status;
20868c2ecf20Sopenharmony_ci	u32 reply_flags = readl(reply) & 0xff00; // Leave it shifted up 8 bits
20878c2ecf20Sopenharmony_ci	// I know this would look cleaner if I just read bytes
20888c2ecf20Sopenharmony_ci	// but the model I have been using for all the rest of the
20898c2ecf20Sopenharmony_ci	// io is in 4 byte words - so I keep that model
20908c2ecf20Sopenharmony_ci	u16 detailed_status = readl(reply+16) &0xffff;
20918c2ecf20Sopenharmony_ci	dev_status = (detailed_status & 0xff);
20928c2ecf20Sopenharmony_ci	hba_status = detailed_status >> 8;
20938c2ecf20Sopenharmony_ci
20948c2ecf20Sopenharmony_ci	// calculate resid for sg
20958c2ecf20Sopenharmony_ci	scsi_set_resid(cmd, scsi_bufflen(cmd) - readl(reply+20));
20968c2ecf20Sopenharmony_ci
20978c2ecf20Sopenharmony_ci	pHba = (adpt_hba*) cmd->device->host->hostdata[0];
20988c2ecf20Sopenharmony_ci
20998c2ecf20Sopenharmony_ci	cmd->sense_buffer[0] = '\0';  // initialize sense valid flag to false
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_ci	if(!(reply_flags & MSG_FAIL)) {
21028c2ecf20Sopenharmony_ci		switch(detailed_status & I2O_SCSI_DSC_MASK) {
21038c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_SUCCESS:
21048c2ecf20Sopenharmony_ci			cmd->result = (DID_OK << 16);
21058c2ecf20Sopenharmony_ci			// handle underflow
21068c2ecf20Sopenharmony_ci			if (readl(reply+20) < cmd->underflow) {
21078c2ecf20Sopenharmony_ci				cmd->result = (DID_ERROR <<16);
21088c2ecf20Sopenharmony_ci				printk(KERN_WARNING"%s: SCSI CMD underflow\n",pHba->name);
21098c2ecf20Sopenharmony_ci			}
21108c2ecf20Sopenharmony_ci			break;
21118c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_REQUEST_ABORTED:
21128c2ecf20Sopenharmony_ci			cmd->result = (DID_ABORT << 16);
21138c2ecf20Sopenharmony_ci			break;
21148c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_PATH_INVALID:
21158c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_DEVICE_NOT_PRESENT:
21168c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_SELECTION_TIMEOUT:
21178c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_COMMAND_TIMEOUT:
21188c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_NO_ADAPTER:
21198c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_RESOURCE_UNAVAILABLE:
21208c2ecf20Sopenharmony_ci			printk(KERN_WARNING"%s: SCSI Timeout-Device (%d,%d,%llu) hba status=0x%x, dev status=0x%x, cmd=0x%x\n",
21218c2ecf20Sopenharmony_ci				pHba->name, (u32)cmd->device->channel, (u32)cmd->device->id, cmd->device->lun, hba_status, dev_status, cmd->cmnd[0]);
21228c2ecf20Sopenharmony_ci			cmd->result = (DID_TIME_OUT << 16);
21238c2ecf20Sopenharmony_ci			break;
21248c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_ADAPTER_BUSY:
21258c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_BUS_BUSY:
21268c2ecf20Sopenharmony_ci			cmd->result = (DID_BUS_BUSY << 16);
21278c2ecf20Sopenharmony_ci			break;
21288c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_SCSI_BUS_RESET:
21298c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_BDR_MESSAGE_SENT:
21308c2ecf20Sopenharmony_ci			cmd->result = (DID_RESET << 16);
21318c2ecf20Sopenharmony_ci			break;
21328c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_PARITY_ERROR_FAILURE:
21338c2ecf20Sopenharmony_ci			printk(KERN_WARNING"%s: SCSI CMD parity error\n",pHba->name);
21348c2ecf20Sopenharmony_ci			cmd->result = (DID_PARITY << 16);
21358c2ecf20Sopenharmony_ci			break;
21368c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_UNABLE_TO_ABORT:
21378c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_COMPLETE_WITH_ERROR:
21388c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_UNABLE_TO_TERMINATE:
21398c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_MR_MESSAGE_RECEIVED:
21408c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_AUTOSENSE_FAILED:
21418c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_DATA_OVERRUN:
21428c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_UNEXPECTED_BUS_FREE:
21438c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_SEQUENCE_FAILURE:
21448c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_REQUEST_LENGTH_ERROR:
21458c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_PROVIDE_FAILURE:
21468c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_REQUEST_TERMINATED:
21478c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_IDE_MESSAGE_SENT:
21488c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_UNACKNOWLEDGED_EVENT:
21498c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_MESSAGE_RECEIVED:
21508c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_INVALID_CDB:
21518c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_LUN_INVALID:
21528c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_SCSI_TID_INVALID:
21538c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_FUNCTION_UNAVAILABLE:
21548c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_NO_NEXUS:
21558c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_CDB_RECEIVED:
21568c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_LUN_ALREADY_ENABLED:
21578c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_QUEUE_FROZEN:
21588c2ecf20Sopenharmony_ci		case I2O_SCSI_DSC_REQUEST_INVALID:
21598c2ecf20Sopenharmony_ci		default:
21608c2ecf20Sopenharmony_ci			printk(KERN_WARNING"%s: SCSI error %0x-Device(%d,%d,%llu) hba_status=0x%x, dev_status=0x%x, cmd=0x%x\n",
21618c2ecf20Sopenharmony_ci				pHba->name, detailed_status & I2O_SCSI_DSC_MASK, (u32)cmd->device->channel, (u32)cmd->device->id, cmd->device->lun,
21628c2ecf20Sopenharmony_ci			       hba_status, dev_status, cmd->cmnd[0]);
21638c2ecf20Sopenharmony_ci			cmd->result = (DID_ERROR << 16);
21648c2ecf20Sopenharmony_ci			break;
21658c2ecf20Sopenharmony_ci		}
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_ci		// copy over the request sense data if it was a check
21688c2ecf20Sopenharmony_ci		// condition status
21698c2ecf20Sopenharmony_ci		if (dev_status == SAM_STAT_CHECK_CONDITION) {
21708c2ecf20Sopenharmony_ci			u32 len = min(SCSI_SENSE_BUFFERSIZE, 40);
21718c2ecf20Sopenharmony_ci			// Copy over the sense data
21728c2ecf20Sopenharmony_ci			memcpy_fromio(cmd->sense_buffer, (reply+28) , len);
21738c2ecf20Sopenharmony_ci			if(cmd->sense_buffer[0] == 0x70 /* class 7 */ &&
21748c2ecf20Sopenharmony_ci			   cmd->sense_buffer[2] == DATA_PROTECT ){
21758c2ecf20Sopenharmony_ci				/* This is to handle an array failed */
21768c2ecf20Sopenharmony_ci				cmd->result = (DID_TIME_OUT << 16);
21778c2ecf20Sopenharmony_ci				printk(KERN_WARNING"%s: SCSI Data Protect-Device (%d,%d,%llu) hba_status=0x%x, dev_status=0x%x, cmd=0x%x\n",
21788c2ecf20Sopenharmony_ci					pHba->name, (u32)cmd->device->channel, (u32)cmd->device->id, cmd->device->lun,
21798c2ecf20Sopenharmony_ci					hba_status, dev_status, cmd->cmnd[0]);
21808c2ecf20Sopenharmony_ci
21818c2ecf20Sopenharmony_ci			}
21828c2ecf20Sopenharmony_ci		}
21838c2ecf20Sopenharmony_ci	} else {
21848c2ecf20Sopenharmony_ci		/* In this condtion we could not talk to the tid
21858c2ecf20Sopenharmony_ci		 * the card rejected it.  We should signal a retry
21868c2ecf20Sopenharmony_ci		 * for a limitted number of retries.
21878c2ecf20Sopenharmony_ci		 */
21888c2ecf20Sopenharmony_ci		cmd->result = (DID_TIME_OUT << 16);
21898c2ecf20Sopenharmony_ci		printk(KERN_WARNING"%s: I2O MSG_FAIL - Device (%d,%d,%llu) tid=%d, cmd=0x%x\n",
21908c2ecf20Sopenharmony_ci			pHba->name, (u32)cmd->device->channel, (u32)cmd->device->id, cmd->device->lun,
21918c2ecf20Sopenharmony_ci			((struct adpt_device*)(cmd->device->hostdata))->tid, cmd->cmnd[0]);
21928c2ecf20Sopenharmony_ci	}
21938c2ecf20Sopenharmony_ci
21948c2ecf20Sopenharmony_ci	cmd->result |= (dev_status);
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_ci	if(cmd->scsi_done != NULL){
21978c2ecf20Sopenharmony_ci		cmd->scsi_done(cmd);
21988c2ecf20Sopenharmony_ci	}
21998c2ecf20Sopenharmony_ci}
22008c2ecf20Sopenharmony_ci
22018c2ecf20Sopenharmony_ci
22028c2ecf20Sopenharmony_cistatic s32 adpt_rescan(adpt_hba* pHba)
22038c2ecf20Sopenharmony_ci{
22048c2ecf20Sopenharmony_ci	s32 rcode;
22058c2ecf20Sopenharmony_ci	ulong flags = 0;
22068c2ecf20Sopenharmony_ci
22078c2ecf20Sopenharmony_ci	if(pHba->host)
22088c2ecf20Sopenharmony_ci		spin_lock_irqsave(pHba->host->host_lock, flags);
22098c2ecf20Sopenharmony_ci	if ((rcode=adpt_i2o_lct_get(pHba)) < 0)
22108c2ecf20Sopenharmony_ci		goto out;
22118c2ecf20Sopenharmony_ci	if ((rcode=adpt_i2o_reparse_lct(pHba)) < 0)
22128c2ecf20Sopenharmony_ci		goto out;
22138c2ecf20Sopenharmony_ci	rcode = 0;
22148c2ecf20Sopenharmony_ciout:	if(pHba->host)
22158c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(pHba->host->host_lock, flags);
22168c2ecf20Sopenharmony_ci	return rcode;
22178c2ecf20Sopenharmony_ci}
22188c2ecf20Sopenharmony_ci
22198c2ecf20Sopenharmony_ci
22208c2ecf20Sopenharmony_cistatic s32 adpt_i2o_reparse_lct(adpt_hba* pHba)
22218c2ecf20Sopenharmony_ci{
22228c2ecf20Sopenharmony_ci	int i;
22238c2ecf20Sopenharmony_ci	int max;
22248c2ecf20Sopenharmony_ci	int tid;
22258c2ecf20Sopenharmony_ci	struct i2o_device *d;
22268c2ecf20Sopenharmony_ci	i2o_lct *lct = pHba->lct;
22278c2ecf20Sopenharmony_ci	u8 bus_no = 0;
22288c2ecf20Sopenharmony_ci	s16 scsi_id;
22298c2ecf20Sopenharmony_ci	u64 scsi_lun;
22308c2ecf20Sopenharmony_ci	u32 buf[10]; // at least 8 u32's
22318c2ecf20Sopenharmony_ci	struct adpt_device* pDev = NULL;
22328c2ecf20Sopenharmony_ci	struct i2o_device* pI2o_dev = NULL;
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_ci	if (lct == NULL) {
22358c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: LCT is empty???\n",pHba->name);
22368c2ecf20Sopenharmony_ci		return -1;
22378c2ecf20Sopenharmony_ci	}
22388c2ecf20Sopenharmony_ci
22398c2ecf20Sopenharmony_ci	max = lct->table_size;
22408c2ecf20Sopenharmony_ci	max -= 3;
22418c2ecf20Sopenharmony_ci	max /= 9;
22428c2ecf20Sopenharmony_ci
22438c2ecf20Sopenharmony_ci	// Mark each drive as unscanned
22448c2ecf20Sopenharmony_ci	for (d = pHba->devices; d; d = d->next) {
22458c2ecf20Sopenharmony_ci		pDev =(struct adpt_device*) d->owner;
22468c2ecf20Sopenharmony_ci		if(!pDev){
22478c2ecf20Sopenharmony_ci			continue;
22488c2ecf20Sopenharmony_ci		}
22498c2ecf20Sopenharmony_ci		pDev->state |= DPTI_DEV_UNSCANNED;
22508c2ecf20Sopenharmony_ci	}
22518c2ecf20Sopenharmony_ci
22528c2ecf20Sopenharmony_ci	printk(KERN_INFO "%s: LCT has %d entries.\n", pHba->name,max);
22538c2ecf20Sopenharmony_ci
22548c2ecf20Sopenharmony_ci	for(i=0;i<max;i++) {
22558c2ecf20Sopenharmony_ci		if( lct->lct_entry[i].user_tid != 0xfff){
22568c2ecf20Sopenharmony_ci			continue;
22578c2ecf20Sopenharmony_ci		}
22588c2ecf20Sopenharmony_ci
22598c2ecf20Sopenharmony_ci		if( lct->lct_entry[i].class_id == I2O_CLASS_RANDOM_BLOCK_STORAGE ||
22608c2ecf20Sopenharmony_ci		    lct->lct_entry[i].class_id == I2O_CLASS_SCSI_PERIPHERAL ||
22618c2ecf20Sopenharmony_ci		    lct->lct_entry[i].class_id == I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL ){
22628c2ecf20Sopenharmony_ci			tid = lct->lct_entry[i].tid;
22638c2ecf20Sopenharmony_ci			if(adpt_i2o_query_scalar(pHba, tid, 0x8000, -1, buf, 32)<0) {
22648c2ecf20Sopenharmony_ci				printk(KERN_ERR"%s: Could not query device\n",pHba->name);
22658c2ecf20Sopenharmony_ci				continue;
22668c2ecf20Sopenharmony_ci			}
22678c2ecf20Sopenharmony_ci			bus_no = buf[0]>>16;
22688c2ecf20Sopenharmony_ci			if (bus_no >= MAX_CHANNEL) {	/* Something wrong skip it */
22698c2ecf20Sopenharmony_ci				printk(KERN_WARNING
22708c2ecf20Sopenharmony_ci					"%s: Channel number %d out of range\n",
22718c2ecf20Sopenharmony_ci					pHba->name, bus_no);
22728c2ecf20Sopenharmony_ci				continue;
22738c2ecf20Sopenharmony_ci			}
22748c2ecf20Sopenharmony_ci
22758c2ecf20Sopenharmony_ci			scsi_id = buf[1];
22768c2ecf20Sopenharmony_ci			scsi_lun = scsilun_to_int((struct scsi_lun *)&buf[2]);
22778c2ecf20Sopenharmony_ci			pDev = pHba->channel[bus_no].device[scsi_id];
22788c2ecf20Sopenharmony_ci			/* da lun */
22798c2ecf20Sopenharmony_ci			while(pDev) {
22808c2ecf20Sopenharmony_ci				if(pDev->scsi_lun == scsi_lun) {
22818c2ecf20Sopenharmony_ci					break;
22828c2ecf20Sopenharmony_ci				}
22838c2ecf20Sopenharmony_ci				pDev = pDev->next_lun;
22848c2ecf20Sopenharmony_ci			}
22858c2ecf20Sopenharmony_ci			if(!pDev ) { // Something new add it
22868c2ecf20Sopenharmony_ci				d = kmalloc(sizeof(struct i2o_device),
22878c2ecf20Sopenharmony_ci					    GFP_ATOMIC);
22888c2ecf20Sopenharmony_ci				if(d==NULL)
22898c2ecf20Sopenharmony_ci				{
22908c2ecf20Sopenharmony_ci					printk(KERN_CRIT "Out of memory for I2O device data.\n");
22918c2ecf20Sopenharmony_ci					return -ENOMEM;
22928c2ecf20Sopenharmony_ci				}
22938c2ecf20Sopenharmony_ci
22948c2ecf20Sopenharmony_ci				d->controller = pHba;
22958c2ecf20Sopenharmony_ci				d->next = NULL;
22968c2ecf20Sopenharmony_ci
22978c2ecf20Sopenharmony_ci				memcpy(&d->lct_data, &lct->lct_entry[i], sizeof(i2o_lct_entry));
22988c2ecf20Sopenharmony_ci
22998c2ecf20Sopenharmony_ci				d->flags = 0;
23008c2ecf20Sopenharmony_ci				adpt_i2o_report_hba_unit(pHba, d);
23018c2ecf20Sopenharmony_ci				adpt_i2o_install_device(pHba, d);
23028c2ecf20Sopenharmony_ci
23038c2ecf20Sopenharmony_ci				pDev = pHba->channel[bus_no].device[scsi_id];
23048c2ecf20Sopenharmony_ci				if( pDev == NULL){
23058c2ecf20Sopenharmony_ci					pDev =
23068c2ecf20Sopenharmony_ci					  kzalloc(sizeof(struct adpt_device),
23078c2ecf20Sopenharmony_ci						  GFP_ATOMIC);
23088c2ecf20Sopenharmony_ci					if(pDev == NULL) {
23098c2ecf20Sopenharmony_ci						return -ENOMEM;
23108c2ecf20Sopenharmony_ci					}
23118c2ecf20Sopenharmony_ci					pHba->channel[bus_no].device[scsi_id] = pDev;
23128c2ecf20Sopenharmony_ci				} else {
23138c2ecf20Sopenharmony_ci					while (pDev->next_lun) {
23148c2ecf20Sopenharmony_ci						pDev = pDev->next_lun;
23158c2ecf20Sopenharmony_ci					}
23168c2ecf20Sopenharmony_ci					pDev = pDev->next_lun =
23178c2ecf20Sopenharmony_ci					  kzalloc(sizeof(struct adpt_device),
23188c2ecf20Sopenharmony_ci						  GFP_ATOMIC);
23198c2ecf20Sopenharmony_ci					if(pDev == NULL) {
23208c2ecf20Sopenharmony_ci						return -ENOMEM;
23218c2ecf20Sopenharmony_ci					}
23228c2ecf20Sopenharmony_ci				}
23238c2ecf20Sopenharmony_ci				pDev->tid = d->lct_data.tid;
23248c2ecf20Sopenharmony_ci				pDev->scsi_channel = bus_no;
23258c2ecf20Sopenharmony_ci				pDev->scsi_id = scsi_id;
23268c2ecf20Sopenharmony_ci				pDev->scsi_lun = scsi_lun;
23278c2ecf20Sopenharmony_ci				pDev->pI2o_dev = d;
23288c2ecf20Sopenharmony_ci				d->owner = pDev;
23298c2ecf20Sopenharmony_ci				pDev->type = (buf[0])&0xff;
23308c2ecf20Sopenharmony_ci				pDev->flags = (buf[0]>>8)&0xff;
23318c2ecf20Sopenharmony_ci				// Too late, SCSI system has made up it's mind, but what the hey ...
23328c2ecf20Sopenharmony_ci				if(scsi_id > pHba->top_scsi_id){
23338c2ecf20Sopenharmony_ci					pHba->top_scsi_id = scsi_id;
23348c2ecf20Sopenharmony_ci				}
23358c2ecf20Sopenharmony_ci				if(scsi_lun > pHba->top_scsi_lun){
23368c2ecf20Sopenharmony_ci					pHba->top_scsi_lun = scsi_lun;
23378c2ecf20Sopenharmony_ci				}
23388c2ecf20Sopenharmony_ci				continue;
23398c2ecf20Sopenharmony_ci			} // end of new i2o device
23408c2ecf20Sopenharmony_ci
23418c2ecf20Sopenharmony_ci			// We found an old device - check it
23428c2ecf20Sopenharmony_ci			while(pDev) {
23438c2ecf20Sopenharmony_ci				if(pDev->scsi_lun == scsi_lun) {
23448c2ecf20Sopenharmony_ci					if(!scsi_device_online(pDev->pScsi_dev)) {
23458c2ecf20Sopenharmony_ci						printk(KERN_WARNING"%s: Setting device (%d,%d,%llu) back online\n",
23468c2ecf20Sopenharmony_ci								pHba->name,bus_no,scsi_id,scsi_lun);
23478c2ecf20Sopenharmony_ci						if (pDev->pScsi_dev) {
23488c2ecf20Sopenharmony_ci							scsi_device_set_state(pDev->pScsi_dev, SDEV_RUNNING);
23498c2ecf20Sopenharmony_ci						}
23508c2ecf20Sopenharmony_ci					}
23518c2ecf20Sopenharmony_ci					d = pDev->pI2o_dev;
23528c2ecf20Sopenharmony_ci					if(d->lct_data.tid != tid) { // something changed
23538c2ecf20Sopenharmony_ci						pDev->tid = tid;
23548c2ecf20Sopenharmony_ci						memcpy(&d->lct_data, &lct->lct_entry[i], sizeof(i2o_lct_entry));
23558c2ecf20Sopenharmony_ci						if (pDev->pScsi_dev) {
23568c2ecf20Sopenharmony_ci							pDev->pScsi_dev->changed = TRUE;
23578c2ecf20Sopenharmony_ci							pDev->pScsi_dev->removable = TRUE;
23588c2ecf20Sopenharmony_ci						}
23598c2ecf20Sopenharmony_ci					}
23608c2ecf20Sopenharmony_ci					// Found it - mark it scanned
23618c2ecf20Sopenharmony_ci					pDev->state = DPTI_DEV_ONLINE;
23628c2ecf20Sopenharmony_ci					break;
23638c2ecf20Sopenharmony_ci				}
23648c2ecf20Sopenharmony_ci				pDev = pDev->next_lun;
23658c2ecf20Sopenharmony_ci			}
23668c2ecf20Sopenharmony_ci		}
23678c2ecf20Sopenharmony_ci	}
23688c2ecf20Sopenharmony_ci	for (pI2o_dev = pHba->devices; pI2o_dev; pI2o_dev = pI2o_dev->next) {
23698c2ecf20Sopenharmony_ci		pDev =(struct adpt_device*) pI2o_dev->owner;
23708c2ecf20Sopenharmony_ci		if(!pDev){
23718c2ecf20Sopenharmony_ci			continue;
23728c2ecf20Sopenharmony_ci		}
23738c2ecf20Sopenharmony_ci		// Drive offline drives that previously existed but could not be found
23748c2ecf20Sopenharmony_ci		// in the LCT table
23758c2ecf20Sopenharmony_ci		if (pDev->state & DPTI_DEV_UNSCANNED){
23768c2ecf20Sopenharmony_ci			pDev->state = DPTI_DEV_OFFLINE;
23778c2ecf20Sopenharmony_ci			printk(KERN_WARNING"%s: Device (%d,%d,%llu) offline\n",pHba->name,pDev->scsi_channel,pDev->scsi_id,pDev->scsi_lun);
23788c2ecf20Sopenharmony_ci			if (pDev->pScsi_dev) {
23798c2ecf20Sopenharmony_ci				scsi_device_set_state(pDev->pScsi_dev, SDEV_OFFLINE);
23808c2ecf20Sopenharmony_ci			}
23818c2ecf20Sopenharmony_ci		}
23828c2ecf20Sopenharmony_ci	}
23838c2ecf20Sopenharmony_ci	return 0;
23848c2ecf20Sopenharmony_ci}
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci/*============================================================================
23878c2ecf20Sopenharmony_ci *  Routines from i2o subsystem
23888c2ecf20Sopenharmony_ci *============================================================================
23898c2ecf20Sopenharmony_ci */
23908c2ecf20Sopenharmony_ci
23918c2ecf20Sopenharmony_ci
23928c2ecf20Sopenharmony_ci
23938c2ecf20Sopenharmony_ci/*
23948c2ecf20Sopenharmony_ci *	Bring an I2O controller into HOLD state. See the spec.
23958c2ecf20Sopenharmony_ci */
23968c2ecf20Sopenharmony_cistatic int adpt_i2o_activate_hba(adpt_hba* pHba)
23978c2ecf20Sopenharmony_ci{
23988c2ecf20Sopenharmony_ci	int rcode;
23998c2ecf20Sopenharmony_ci
24008c2ecf20Sopenharmony_ci	if(pHba->initialized ) {
24018c2ecf20Sopenharmony_ci		if (adpt_i2o_status_get(pHba) < 0) {
24028c2ecf20Sopenharmony_ci			if((rcode = adpt_i2o_reset_hba(pHba)) != 0){
24038c2ecf20Sopenharmony_ci				printk(KERN_WARNING"%s: Could NOT reset.\n", pHba->name);
24048c2ecf20Sopenharmony_ci				return rcode;
24058c2ecf20Sopenharmony_ci			}
24068c2ecf20Sopenharmony_ci			if (adpt_i2o_status_get(pHba) < 0) {
24078c2ecf20Sopenharmony_ci				printk(KERN_INFO "HBA not responding.\n");
24088c2ecf20Sopenharmony_ci				return -1;
24098c2ecf20Sopenharmony_ci			}
24108c2ecf20Sopenharmony_ci		}
24118c2ecf20Sopenharmony_ci
24128c2ecf20Sopenharmony_ci		if(pHba->status_block->iop_state == ADAPTER_STATE_FAULTED) {
24138c2ecf20Sopenharmony_ci			printk(KERN_CRIT "%s: hardware fault\n", pHba->name);
24148c2ecf20Sopenharmony_ci			return -1;
24158c2ecf20Sopenharmony_ci		}
24168c2ecf20Sopenharmony_ci
24178c2ecf20Sopenharmony_ci		if (pHba->status_block->iop_state == ADAPTER_STATE_READY ||
24188c2ecf20Sopenharmony_ci		    pHba->status_block->iop_state == ADAPTER_STATE_OPERATIONAL ||
24198c2ecf20Sopenharmony_ci		    pHba->status_block->iop_state == ADAPTER_STATE_HOLD ||
24208c2ecf20Sopenharmony_ci		    pHba->status_block->iop_state == ADAPTER_STATE_FAILED) {
24218c2ecf20Sopenharmony_ci			adpt_i2o_reset_hba(pHba);
24228c2ecf20Sopenharmony_ci			if (adpt_i2o_status_get(pHba) < 0 || pHba->status_block->iop_state != ADAPTER_STATE_RESET) {
24238c2ecf20Sopenharmony_ci				printk(KERN_ERR "%s: Failed to initialize.\n", pHba->name);
24248c2ecf20Sopenharmony_ci				return -1;
24258c2ecf20Sopenharmony_ci			}
24268c2ecf20Sopenharmony_ci		}
24278c2ecf20Sopenharmony_ci	} else {
24288c2ecf20Sopenharmony_ci		if((rcode = adpt_i2o_reset_hba(pHba)) != 0){
24298c2ecf20Sopenharmony_ci			printk(KERN_WARNING"%s: Could NOT reset.\n", pHba->name);
24308c2ecf20Sopenharmony_ci			return rcode;
24318c2ecf20Sopenharmony_ci		}
24328c2ecf20Sopenharmony_ci
24338c2ecf20Sopenharmony_ci	}
24348c2ecf20Sopenharmony_ci
24358c2ecf20Sopenharmony_ci	if (adpt_i2o_init_outbound_q(pHba) < 0) {
24368c2ecf20Sopenharmony_ci		return -1;
24378c2ecf20Sopenharmony_ci	}
24388c2ecf20Sopenharmony_ci
24398c2ecf20Sopenharmony_ci	/* In HOLD state */
24408c2ecf20Sopenharmony_ci
24418c2ecf20Sopenharmony_ci	if (adpt_i2o_hrt_get(pHba) < 0) {
24428c2ecf20Sopenharmony_ci		return -1;
24438c2ecf20Sopenharmony_ci	}
24448c2ecf20Sopenharmony_ci
24458c2ecf20Sopenharmony_ci	return 0;
24468c2ecf20Sopenharmony_ci}
24478c2ecf20Sopenharmony_ci
24488c2ecf20Sopenharmony_ci/*
24498c2ecf20Sopenharmony_ci *	Bring a controller online into OPERATIONAL state.
24508c2ecf20Sopenharmony_ci */
24518c2ecf20Sopenharmony_ci
24528c2ecf20Sopenharmony_cistatic int adpt_i2o_online_hba(adpt_hba* pHba)
24538c2ecf20Sopenharmony_ci{
24548c2ecf20Sopenharmony_ci	if (adpt_i2o_systab_send(pHba) < 0)
24558c2ecf20Sopenharmony_ci		return -1;
24568c2ecf20Sopenharmony_ci	/* In READY state */
24578c2ecf20Sopenharmony_ci
24588c2ecf20Sopenharmony_ci	if (adpt_i2o_enable_hba(pHba) < 0)
24598c2ecf20Sopenharmony_ci		return -1;
24608c2ecf20Sopenharmony_ci
24618c2ecf20Sopenharmony_ci	/* In OPERATIONAL state  */
24628c2ecf20Sopenharmony_ci	return 0;
24638c2ecf20Sopenharmony_ci}
24648c2ecf20Sopenharmony_ci
24658c2ecf20Sopenharmony_cistatic s32 adpt_send_nop(adpt_hba*pHba,u32 m)
24668c2ecf20Sopenharmony_ci{
24678c2ecf20Sopenharmony_ci	u32 __iomem *msg;
24688c2ecf20Sopenharmony_ci	ulong timeout = jiffies + 5*HZ;
24698c2ecf20Sopenharmony_ci
24708c2ecf20Sopenharmony_ci	while(m == EMPTY_QUEUE){
24718c2ecf20Sopenharmony_ci		rmb();
24728c2ecf20Sopenharmony_ci		m = readl(pHba->post_port);
24738c2ecf20Sopenharmony_ci		if(m != EMPTY_QUEUE){
24748c2ecf20Sopenharmony_ci			break;
24758c2ecf20Sopenharmony_ci		}
24768c2ecf20Sopenharmony_ci		if(time_after(jiffies,timeout)){
24778c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: Timeout waiting for message frame!\n",pHba->name);
24788c2ecf20Sopenharmony_ci			return 2;
24798c2ecf20Sopenharmony_ci		}
24808c2ecf20Sopenharmony_ci		schedule_timeout_uninterruptible(1);
24818c2ecf20Sopenharmony_ci	}
24828c2ecf20Sopenharmony_ci	msg = (u32 __iomem *)(pHba->msg_addr_virt + m);
24838c2ecf20Sopenharmony_ci	writel( THREE_WORD_MSG_SIZE | SGL_OFFSET_0,&msg[0]);
24848c2ecf20Sopenharmony_ci	writel( I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0,&msg[1]);
24858c2ecf20Sopenharmony_ci	writel( 0,&msg[2]);
24868c2ecf20Sopenharmony_ci	wmb();
24878c2ecf20Sopenharmony_ci
24888c2ecf20Sopenharmony_ci	writel(m, pHba->post_port);
24898c2ecf20Sopenharmony_ci	wmb();
24908c2ecf20Sopenharmony_ci	return 0;
24918c2ecf20Sopenharmony_ci}
24928c2ecf20Sopenharmony_ci
24938c2ecf20Sopenharmony_cistatic s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
24948c2ecf20Sopenharmony_ci{
24958c2ecf20Sopenharmony_ci	u8 *status;
24968c2ecf20Sopenharmony_ci	dma_addr_t addr;
24978c2ecf20Sopenharmony_ci	u32 __iomem *msg = NULL;
24988c2ecf20Sopenharmony_ci	int i;
24998c2ecf20Sopenharmony_ci	ulong timeout = jiffies + TMOUT_INITOUTBOUND*HZ;
25008c2ecf20Sopenharmony_ci	u32 m;
25018c2ecf20Sopenharmony_ci
25028c2ecf20Sopenharmony_ci	do {
25038c2ecf20Sopenharmony_ci		rmb();
25048c2ecf20Sopenharmony_ci		m = readl(pHba->post_port);
25058c2ecf20Sopenharmony_ci		if (m != EMPTY_QUEUE) {
25068c2ecf20Sopenharmony_ci			break;
25078c2ecf20Sopenharmony_ci		}
25088c2ecf20Sopenharmony_ci
25098c2ecf20Sopenharmony_ci		if(time_after(jiffies,timeout)){
25108c2ecf20Sopenharmony_ci			printk(KERN_WARNING"%s: Timeout waiting for message frame\n",pHba->name);
25118c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
25128c2ecf20Sopenharmony_ci		}
25138c2ecf20Sopenharmony_ci		schedule_timeout_uninterruptible(1);
25148c2ecf20Sopenharmony_ci	} while(m == EMPTY_QUEUE);
25158c2ecf20Sopenharmony_ci
25168c2ecf20Sopenharmony_ci	msg=(u32 __iomem *)(pHba->msg_addr_virt+m);
25178c2ecf20Sopenharmony_ci
25188c2ecf20Sopenharmony_ci	status = dma_alloc_coherent(&pHba->pDev->dev, 4, &addr, GFP_KERNEL);
25198c2ecf20Sopenharmony_ci	if (!status) {
25208c2ecf20Sopenharmony_ci		adpt_send_nop(pHba, m);
25218c2ecf20Sopenharmony_ci		printk(KERN_WARNING"%s: IOP reset failed - no free memory.\n",
25228c2ecf20Sopenharmony_ci			pHba->name);
25238c2ecf20Sopenharmony_ci		return -ENOMEM;
25248c2ecf20Sopenharmony_ci	}
25258c2ecf20Sopenharmony_ci
25268c2ecf20Sopenharmony_ci	writel(EIGHT_WORD_MSG_SIZE| SGL_OFFSET_6, &msg[0]);
25278c2ecf20Sopenharmony_ci	writel(I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID, &msg[1]);
25288c2ecf20Sopenharmony_ci	writel(0, &msg[2]);
25298c2ecf20Sopenharmony_ci	writel(0x0106, &msg[3]);	/* Transaction context */
25308c2ecf20Sopenharmony_ci	writel(4096, &msg[4]);		/* Host page frame size */
25318c2ecf20Sopenharmony_ci	writel((REPLY_FRAME_SIZE)<<16|0x80, &msg[5]);	/* Outbound msg frame size and Initcode */
25328c2ecf20Sopenharmony_ci	writel(0xD0000004, &msg[6]);		/* Simple SG LE, EOB */
25338c2ecf20Sopenharmony_ci	writel((u32)addr, &msg[7]);
25348c2ecf20Sopenharmony_ci
25358c2ecf20Sopenharmony_ci	writel(m, pHba->post_port);
25368c2ecf20Sopenharmony_ci	wmb();
25378c2ecf20Sopenharmony_ci
25388c2ecf20Sopenharmony_ci	// Wait for the reply status to come back
25398c2ecf20Sopenharmony_ci	do {
25408c2ecf20Sopenharmony_ci		if (*status) {
25418c2ecf20Sopenharmony_ci			if (*status != 0x01 /*I2O_EXEC_OUTBOUND_INIT_IN_PROGRESS*/) {
25428c2ecf20Sopenharmony_ci				break;
25438c2ecf20Sopenharmony_ci			}
25448c2ecf20Sopenharmony_ci		}
25458c2ecf20Sopenharmony_ci		rmb();
25468c2ecf20Sopenharmony_ci		if(time_after(jiffies,timeout)){
25478c2ecf20Sopenharmony_ci			printk(KERN_WARNING"%s: Timeout Initializing\n",pHba->name);
25488c2ecf20Sopenharmony_ci			/* We lose 4 bytes of "status" here, but we
25498c2ecf20Sopenharmony_ci			   cannot free these because controller may
25508c2ecf20Sopenharmony_ci			   awake and corrupt those bytes at any time */
25518c2ecf20Sopenharmony_ci			/* dma_free_coherent(&pHba->pDev->dev, 4, status, addr); */
25528c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
25538c2ecf20Sopenharmony_ci		}
25548c2ecf20Sopenharmony_ci		schedule_timeout_uninterruptible(1);
25558c2ecf20Sopenharmony_ci	} while (1);
25568c2ecf20Sopenharmony_ci
25578c2ecf20Sopenharmony_ci	// If the command was successful, fill the fifo with our reply
25588c2ecf20Sopenharmony_ci	// message packets
25598c2ecf20Sopenharmony_ci	if(*status != 0x04 /*I2O_EXEC_OUTBOUND_INIT_COMPLETE*/) {
25608c2ecf20Sopenharmony_ci		dma_free_coherent(&pHba->pDev->dev, 4, status, addr);
25618c2ecf20Sopenharmony_ci		return -2;
25628c2ecf20Sopenharmony_ci	}
25638c2ecf20Sopenharmony_ci	dma_free_coherent(&pHba->pDev->dev, 4, status, addr);
25648c2ecf20Sopenharmony_ci
25658c2ecf20Sopenharmony_ci	if(pHba->reply_pool != NULL) {
25668c2ecf20Sopenharmony_ci		dma_free_coherent(&pHba->pDev->dev,
25678c2ecf20Sopenharmony_ci			pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4,
25688c2ecf20Sopenharmony_ci			pHba->reply_pool, pHba->reply_pool_pa);
25698c2ecf20Sopenharmony_ci	}
25708c2ecf20Sopenharmony_ci
25718c2ecf20Sopenharmony_ci	pHba->reply_pool = dma_alloc_coherent(&pHba->pDev->dev,
25728c2ecf20Sopenharmony_ci				pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4,
25738c2ecf20Sopenharmony_ci				&pHba->reply_pool_pa, GFP_KERNEL);
25748c2ecf20Sopenharmony_ci	if (!pHba->reply_pool) {
25758c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Could not allocate reply pool\n", pHba->name);
25768c2ecf20Sopenharmony_ci		return -ENOMEM;
25778c2ecf20Sopenharmony_ci	}
25788c2ecf20Sopenharmony_ci
25798c2ecf20Sopenharmony_ci	for(i = 0; i < pHba->reply_fifo_size; i++) {
25808c2ecf20Sopenharmony_ci		writel(pHba->reply_pool_pa + (i * REPLY_FRAME_SIZE * 4),
25818c2ecf20Sopenharmony_ci			pHba->reply_port);
25828c2ecf20Sopenharmony_ci		wmb();
25838c2ecf20Sopenharmony_ci	}
25848c2ecf20Sopenharmony_ci	adpt_i2o_status_get(pHba);
25858c2ecf20Sopenharmony_ci	return 0;
25868c2ecf20Sopenharmony_ci}
25878c2ecf20Sopenharmony_ci
25888c2ecf20Sopenharmony_ci
25898c2ecf20Sopenharmony_ci/*
25908c2ecf20Sopenharmony_ci * I2O System Table.  Contains information about
25918c2ecf20Sopenharmony_ci * all the IOPs in the system.  Used to inform IOPs
25928c2ecf20Sopenharmony_ci * about each other's existence.
25938c2ecf20Sopenharmony_ci *
25948c2ecf20Sopenharmony_ci * sys_tbl_ver is the CurrentChangeIndicator that is
25958c2ecf20Sopenharmony_ci * used by IOPs to track changes.
25968c2ecf20Sopenharmony_ci */
25978c2ecf20Sopenharmony_ci
25988c2ecf20Sopenharmony_ci
25998c2ecf20Sopenharmony_ci
26008c2ecf20Sopenharmony_cistatic s32 adpt_i2o_status_get(adpt_hba* pHba)
26018c2ecf20Sopenharmony_ci{
26028c2ecf20Sopenharmony_ci	ulong timeout;
26038c2ecf20Sopenharmony_ci	u32 m;
26048c2ecf20Sopenharmony_ci	u32 __iomem *msg;
26058c2ecf20Sopenharmony_ci	u8 *status_block=NULL;
26068c2ecf20Sopenharmony_ci
26078c2ecf20Sopenharmony_ci	if(pHba->status_block == NULL) {
26088c2ecf20Sopenharmony_ci		pHba->status_block = dma_alloc_coherent(&pHba->pDev->dev,
26098c2ecf20Sopenharmony_ci					sizeof(i2o_status_block),
26108c2ecf20Sopenharmony_ci					&pHba->status_block_pa, GFP_KERNEL);
26118c2ecf20Sopenharmony_ci		if(pHba->status_block == NULL) {
26128c2ecf20Sopenharmony_ci			printk(KERN_ERR
26138c2ecf20Sopenharmony_ci			"dpti%d: Get Status Block failed; Out of memory. \n",
26148c2ecf20Sopenharmony_ci			pHba->unit);
26158c2ecf20Sopenharmony_ci			return -ENOMEM;
26168c2ecf20Sopenharmony_ci		}
26178c2ecf20Sopenharmony_ci	}
26188c2ecf20Sopenharmony_ci	memset(pHba->status_block, 0, sizeof(i2o_status_block));
26198c2ecf20Sopenharmony_ci	status_block = (u8*)(pHba->status_block);
26208c2ecf20Sopenharmony_ci	timeout = jiffies+TMOUT_GETSTATUS*HZ;
26218c2ecf20Sopenharmony_ci	do {
26228c2ecf20Sopenharmony_ci		rmb();
26238c2ecf20Sopenharmony_ci		m = readl(pHba->post_port);
26248c2ecf20Sopenharmony_ci		if (m != EMPTY_QUEUE) {
26258c2ecf20Sopenharmony_ci			break;
26268c2ecf20Sopenharmony_ci		}
26278c2ecf20Sopenharmony_ci		if(time_after(jiffies,timeout)){
26288c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: Timeout waiting for message !\n",
26298c2ecf20Sopenharmony_ci					pHba->name);
26308c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
26318c2ecf20Sopenharmony_ci		}
26328c2ecf20Sopenharmony_ci		schedule_timeout_uninterruptible(1);
26338c2ecf20Sopenharmony_ci	} while(m==EMPTY_QUEUE);
26348c2ecf20Sopenharmony_ci
26358c2ecf20Sopenharmony_ci
26368c2ecf20Sopenharmony_ci	msg=(u32 __iomem *)(pHba->msg_addr_virt+m);
26378c2ecf20Sopenharmony_ci
26388c2ecf20Sopenharmony_ci	writel(NINE_WORD_MSG_SIZE|SGL_OFFSET_0, &msg[0]);
26398c2ecf20Sopenharmony_ci	writel(I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID, &msg[1]);
26408c2ecf20Sopenharmony_ci	writel(1, &msg[2]);
26418c2ecf20Sopenharmony_ci	writel(0, &msg[3]);
26428c2ecf20Sopenharmony_ci	writel(0, &msg[4]);
26438c2ecf20Sopenharmony_ci	writel(0, &msg[5]);
26448c2ecf20Sopenharmony_ci	writel( dma_low(pHba->status_block_pa), &msg[6]);
26458c2ecf20Sopenharmony_ci	writel( dma_high(pHba->status_block_pa), &msg[7]);
26468c2ecf20Sopenharmony_ci	writel(sizeof(i2o_status_block), &msg[8]); // 88 bytes
26478c2ecf20Sopenharmony_ci
26488c2ecf20Sopenharmony_ci	//post message
26498c2ecf20Sopenharmony_ci	writel(m, pHba->post_port);
26508c2ecf20Sopenharmony_ci	wmb();
26518c2ecf20Sopenharmony_ci
26528c2ecf20Sopenharmony_ci	while(status_block[87]!=0xff){
26538c2ecf20Sopenharmony_ci		if(time_after(jiffies,timeout)){
26548c2ecf20Sopenharmony_ci			printk(KERN_ERR"dpti%d: Get status timeout.\n",
26558c2ecf20Sopenharmony_ci				pHba->unit);
26568c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
26578c2ecf20Sopenharmony_ci		}
26588c2ecf20Sopenharmony_ci		rmb();
26598c2ecf20Sopenharmony_ci		schedule_timeout_uninterruptible(1);
26608c2ecf20Sopenharmony_ci	}
26618c2ecf20Sopenharmony_ci
26628c2ecf20Sopenharmony_ci	// Set up our number of outbound and inbound messages
26638c2ecf20Sopenharmony_ci	pHba->post_fifo_size = pHba->status_block->max_inbound_frames;
26648c2ecf20Sopenharmony_ci	if (pHba->post_fifo_size > MAX_TO_IOP_MESSAGES) {
26658c2ecf20Sopenharmony_ci		pHba->post_fifo_size = MAX_TO_IOP_MESSAGES;
26668c2ecf20Sopenharmony_ci	}
26678c2ecf20Sopenharmony_ci
26688c2ecf20Sopenharmony_ci	pHba->reply_fifo_size = pHba->status_block->max_outbound_frames;
26698c2ecf20Sopenharmony_ci	if (pHba->reply_fifo_size > MAX_FROM_IOP_MESSAGES) {
26708c2ecf20Sopenharmony_ci		pHba->reply_fifo_size = MAX_FROM_IOP_MESSAGES;
26718c2ecf20Sopenharmony_ci	}
26728c2ecf20Sopenharmony_ci
26738c2ecf20Sopenharmony_ci	// Calculate the Scatter Gather list size
26748c2ecf20Sopenharmony_ci	if (dpt_dma64(pHba)) {
26758c2ecf20Sopenharmony_ci		pHba->sg_tablesize
26768c2ecf20Sopenharmony_ci		  = ((pHba->status_block->inbound_frame_size * 4
26778c2ecf20Sopenharmony_ci		  - 14 * sizeof(u32))
26788c2ecf20Sopenharmony_ci		  / (sizeof(struct sg_simple_element) + sizeof(u32)));
26798c2ecf20Sopenharmony_ci	} else {
26808c2ecf20Sopenharmony_ci		pHba->sg_tablesize
26818c2ecf20Sopenharmony_ci		  = ((pHba->status_block->inbound_frame_size * 4
26828c2ecf20Sopenharmony_ci		  - 12 * sizeof(u32))
26838c2ecf20Sopenharmony_ci		  / sizeof(struct sg_simple_element));
26848c2ecf20Sopenharmony_ci	}
26858c2ecf20Sopenharmony_ci	if (pHba->sg_tablesize > SG_LIST_ELEMENTS) {
26868c2ecf20Sopenharmony_ci		pHba->sg_tablesize = SG_LIST_ELEMENTS;
26878c2ecf20Sopenharmony_ci	}
26888c2ecf20Sopenharmony_ci
26898c2ecf20Sopenharmony_ci
26908c2ecf20Sopenharmony_ci#ifdef DEBUG
26918c2ecf20Sopenharmony_ci	printk("dpti%d: State = ",pHba->unit);
26928c2ecf20Sopenharmony_ci	switch(pHba->status_block->iop_state) {
26938c2ecf20Sopenharmony_ci		case 0x01:
26948c2ecf20Sopenharmony_ci			printk("INIT\n");
26958c2ecf20Sopenharmony_ci			break;
26968c2ecf20Sopenharmony_ci		case 0x02:
26978c2ecf20Sopenharmony_ci			printk("RESET\n");
26988c2ecf20Sopenharmony_ci			break;
26998c2ecf20Sopenharmony_ci		case 0x04:
27008c2ecf20Sopenharmony_ci			printk("HOLD\n");
27018c2ecf20Sopenharmony_ci			break;
27028c2ecf20Sopenharmony_ci		case 0x05:
27038c2ecf20Sopenharmony_ci			printk("READY\n");
27048c2ecf20Sopenharmony_ci			break;
27058c2ecf20Sopenharmony_ci		case 0x08:
27068c2ecf20Sopenharmony_ci			printk("OPERATIONAL\n");
27078c2ecf20Sopenharmony_ci			break;
27088c2ecf20Sopenharmony_ci		case 0x10:
27098c2ecf20Sopenharmony_ci			printk("FAILED\n");
27108c2ecf20Sopenharmony_ci			break;
27118c2ecf20Sopenharmony_ci		case 0x11:
27128c2ecf20Sopenharmony_ci			printk("FAULTED\n");
27138c2ecf20Sopenharmony_ci			break;
27148c2ecf20Sopenharmony_ci		default:
27158c2ecf20Sopenharmony_ci			printk("%x (unknown!!)\n",pHba->status_block->iop_state);
27168c2ecf20Sopenharmony_ci	}
27178c2ecf20Sopenharmony_ci#endif
27188c2ecf20Sopenharmony_ci	return 0;
27198c2ecf20Sopenharmony_ci}
27208c2ecf20Sopenharmony_ci
27218c2ecf20Sopenharmony_ci/*
27228c2ecf20Sopenharmony_ci * Get the IOP's Logical Configuration Table
27238c2ecf20Sopenharmony_ci */
27248c2ecf20Sopenharmony_cistatic int adpt_i2o_lct_get(adpt_hba* pHba)
27258c2ecf20Sopenharmony_ci{
27268c2ecf20Sopenharmony_ci	u32 msg[8];
27278c2ecf20Sopenharmony_ci	int ret;
27288c2ecf20Sopenharmony_ci	u32 buf[16];
27298c2ecf20Sopenharmony_ci
27308c2ecf20Sopenharmony_ci	if ((pHba->lct_size == 0) || (pHba->lct == NULL)){
27318c2ecf20Sopenharmony_ci		pHba->lct_size = pHba->status_block->expected_lct_size;
27328c2ecf20Sopenharmony_ci	}
27338c2ecf20Sopenharmony_ci	do {
27348c2ecf20Sopenharmony_ci		if (pHba->lct == NULL) {
27358c2ecf20Sopenharmony_ci			pHba->lct = dma_alloc_coherent(&pHba->pDev->dev,
27368c2ecf20Sopenharmony_ci					pHba->lct_size, &pHba->lct_pa,
27378c2ecf20Sopenharmony_ci					GFP_ATOMIC);
27388c2ecf20Sopenharmony_ci			if(pHba->lct == NULL) {
27398c2ecf20Sopenharmony_ci				printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n",
27408c2ecf20Sopenharmony_ci					pHba->name);
27418c2ecf20Sopenharmony_ci				return -ENOMEM;
27428c2ecf20Sopenharmony_ci			}
27438c2ecf20Sopenharmony_ci		}
27448c2ecf20Sopenharmony_ci		memset(pHba->lct, 0, pHba->lct_size);
27458c2ecf20Sopenharmony_ci
27468c2ecf20Sopenharmony_ci		msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6;
27478c2ecf20Sopenharmony_ci		msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID;
27488c2ecf20Sopenharmony_ci		msg[2] = 0;
27498c2ecf20Sopenharmony_ci		msg[3] = 0;
27508c2ecf20Sopenharmony_ci		msg[4] = 0xFFFFFFFF;	/* All devices */
27518c2ecf20Sopenharmony_ci		msg[5] = 0x00000000;	/* Report now */
27528c2ecf20Sopenharmony_ci		msg[6] = 0xD0000000|pHba->lct_size;
27538c2ecf20Sopenharmony_ci		msg[7] = (u32)pHba->lct_pa;
27548c2ecf20Sopenharmony_ci
27558c2ecf20Sopenharmony_ci		if ((ret=adpt_i2o_post_wait(pHba, msg, sizeof(msg), 360))) {
27568c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: LCT Get failed (status=%#10x.\n",
27578c2ecf20Sopenharmony_ci				pHba->name, ret);
27588c2ecf20Sopenharmony_ci			printk(KERN_ERR"Adaptec: Error Reading Hardware.\n");
27598c2ecf20Sopenharmony_ci			return ret;
27608c2ecf20Sopenharmony_ci		}
27618c2ecf20Sopenharmony_ci
27628c2ecf20Sopenharmony_ci		if ((pHba->lct->table_size << 2) > pHba->lct_size) {
27638c2ecf20Sopenharmony_ci			pHba->lct_size = pHba->lct->table_size << 2;
27648c2ecf20Sopenharmony_ci			dma_free_coherent(&pHba->pDev->dev, pHba->lct_size,
27658c2ecf20Sopenharmony_ci					pHba->lct, pHba->lct_pa);
27668c2ecf20Sopenharmony_ci			pHba->lct = NULL;
27678c2ecf20Sopenharmony_ci		}
27688c2ecf20Sopenharmony_ci	} while (pHba->lct == NULL);
27698c2ecf20Sopenharmony_ci
27708c2ecf20Sopenharmony_ci	PDEBUG("%s: Hardware resource table read.\n", pHba->name);
27718c2ecf20Sopenharmony_ci
27728c2ecf20Sopenharmony_ci
27738c2ecf20Sopenharmony_ci	// I2O_DPT_EXEC_IOP_BUFFERS_GROUP_NO;
27748c2ecf20Sopenharmony_ci	if(adpt_i2o_query_scalar(pHba, 0 , 0x8000, -1, buf, sizeof(buf))>=0) {
27758c2ecf20Sopenharmony_ci		pHba->FwDebugBufferSize = buf[1];
27768c2ecf20Sopenharmony_ci		pHba->FwDebugBuffer_P = ioremap(pHba->base_addr_phys + buf[0],
27778c2ecf20Sopenharmony_ci						pHba->FwDebugBufferSize);
27788c2ecf20Sopenharmony_ci		if (pHba->FwDebugBuffer_P) {
27798c2ecf20Sopenharmony_ci			pHba->FwDebugFlags_P     = pHba->FwDebugBuffer_P +
27808c2ecf20Sopenharmony_ci							FW_DEBUG_FLAGS_OFFSET;
27818c2ecf20Sopenharmony_ci			pHba->FwDebugBLEDvalue_P = pHba->FwDebugBuffer_P +
27828c2ecf20Sopenharmony_ci							FW_DEBUG_BLED_OFFSET;
27838c2ecf20Sopenharmony_ci			pHba->FwDebugBLEDflag_P  = pHba->FwDebugBLEDvalue_P + 1;
27848c2ecf20Sopenharmony_ci			pHba->FwDebugStrLength_P = pHba->FwDebugBuffer_P +
27858c2ecf20Sopenharmony_ci						FW_DEBUG_STR_LENGTH_OFFSET;
27868c2ecf20Sopenharmony_ci			pHba->FwDebugBuffer_P += buf[2];
27878c2ecf20Sopenharmony_ci			pHba->FwDebugFlags = 0;
27888c2ecf20Sopenharmony_ci		}
27898c2ecf20Sopenharmony_ci	}
27908c2ecf20Sopenharmony_ci
27918c2ecf20Sopenharmony_ci	return 0;
27928c2ecf20Sopenharmony_ci}
27938c2ecf20Sopenharmony_ci
27948c2ecf20Sopenharmony_cistatic int adpt_i2o_build_sys_table(void)
27958c2ecf20Sopenharmony_ci{
27968c2ecf20Sopenharmony_ci	adpt_hba* pHba = hba_chain;
27978c2ecf20Sopenharmony_ci	int count = 0;
27988c2ecf20Sopenharmony_ci
27998c2ecf20Sopenharmony_ci	if (sys_tbl)
28008c2ecf20Sopenharmony_ci		dma_free_coherent(&pHba->pDev->dev, sys_tbl_len,
28018c2ecf20Sopenharmony_ci					sys_tbl, sys_tbl_pa);
28028c2ecf20Sopenharmony_ci
28038c2ecf20Sopenharmony_ci	sys_tbl_len = sizeof(struct i2o_sys_tbl) +	// Header + IOPs
28048c2ecf20Sopenharmony_ci				(hba_count) * sizeof(struct i2o_sys_tbl_entry);
28058c2ecf20Sopenharmony_ci
28068c2ecf20Sopenharmony_ci	sys_tbl = dma_alloc_coherent(&pHba->pDev->dev,
28078c2ecf20Sopenharmony_ci				sys_tbl_len, &sys_tbl_pa, GFP_KERNEL);
28088c2ecf20Sopenharmony_ci	if (!sys_tbl) {
28098c2ecf20Sopenharmony_ci		printk(KERN_WARNING "SysTab Set failed. Out of memory.\n");
28108c2ecf20Sopenharmony_ci		return -ENOMEM;
28118c2ecf20Sopenharmony_ci	}
28128c2ecf20Sopenharmony_ci
28138c2ecf20Sopenharmony_ci	sys_tbl->num_entries = hba_count;
28148c2ecf20Sopenharmony_ci	sys_tbl->version = I2OVERSION;
28158c2ecf20Sopenharmony_ci	sys_tbl->change_ind = sys_tbl_ind++;
28168c2ecf20Sopenharmony_ci
28178c2ecf20Sopenharmony_ci	for(pHba = hba_chain; pHba; pHba = pHba->next) {
28188c2ecf20Sopenharmony_ci		u64 addr;
28198c2ecf20Sopenharmony_ci		// Get updated Status Block so we have the latest information
28208c2ecf20Sopenharmony_ci		if (adpt_i2o_status_get(pHba)) {
28218c2ecf20Sopenharmony_ci			sys_tbl->num_entries--;
28228c2ecf20Sopenharmony_ci			continue; // try next one
28238c2ecf20Sopenharmony_ci		}
28248c2ecf20Sopenharmony_ci
28258c2ecf20Sopenharmony_ci		sys_tbl->iops[count].org_id = pHba->status_block->org_id;
28268c2ecf20Sopenharmony_ci		sys_tbl->iops[count].iop_id = pHba->unit + 2;
28278c2ecf20Sopenharmony_ci		sys_tbl->iops[count].seg_num = 0;
28288c2ecf20Sopenharmony_ci		sys_tbl->iops[count].i2o_version = pHba->status_block->i2o_version;
28298c2ecf20Sopenharmony_ci		sys_tbl->iops[count].iop_state = pHba->status_block->iop_state;
28308c2ecf20Sopenharmony_ci		sys_tbl->iops[count].msg_type = pHba->status_block->msg_type;
28318c2ecf20Sopenharmony_ci		sys_tbl->iops[count].frame_size = pHba->status_block->inbound_frame_size;
28328c2ecf20Sopenharmony_ci		sys_tbl->iops[count].last_changed = sys_tbl_ind - 1; // ??
28338c2ecf20Sopenharmony_ci		sys_tbl->iops[count].iop_capabilities = pHba->status_block->iop_capabilities;
28348c2ecf20Sopenharmony_ci		addr = pHba->base_addr_phys + 0x40;
28358c2ecf20Sopenharmony_ci		sys_tbl->iops[count].inbound_low = dma_low(addr);
28368c2ecf20Sopenharmony_ci		sys_tbl->iops[count].inbound_high = dma_high(addr);
28378c2ecf20Sopenharmony_ci
28388c2ecf20Sopenharmony_ci		count++;
28398c2ecf20Sopenharmony_ci	}
28408c2ecf20Sopenharmony_ci
28418c2ecf20Sopenharmony_ci#ifdef DEBUG
28428c2ecf20Sopenharmony_ci{
28438c2ecf20Sopenharmony_ci	u32 *table = (u32*)sys_tbl;
28448c2ecf20Sopenharmony_ci	printk(KERN_DEBUG"sys_tbl_len=%d in 32bit words\n",(sys_tbl_len >>2));
28458c2ecf20Sopenharmony_ci	for(count = 0; count < (sys_tbl_len >>2); count++) {
28468c2ecf20Sopenharmony_ci		printk(KERN_INFO "sys_tbl[%d] = %0#10x\n",
28478c2ecf20Sopenharmony_ci			count, table[count]);
28488c2ecf20Sopenharmony_ci	}
28498c2ecf20Sopenharmony_ci}
28508c2ecf20Sopenharmony_ci#endif
28518c2ecf20Sopenharmony_ci
28528c2ecf20Sopenharmony_ci	return 0;
28538c2ecf20Sopenharmony_ci}
28548c2ecf20Sopenharmony_ci
28558c2ecf20Sopenharmony_ci
28568c2ecf20Sopenharmony_ci/*
28578c2ecf20Sopenharmony_ci *	 Dump the information block associated with a given unit (TID)
28588c2ecf20Sopenharmony_ci */
28598c2ecf20Sopenharmony_ci
28608c2ecf20Sopenharmony_cistatic void adpt_i2o_report_hba_unit(adpt_hba* pHba, struct i2o_device *d)
28618c2ecf20Sopenharmony_ci{
28628c2ecf20Sopenharmony_ci	char buf[64];
28638c2ecf20Sopenharmony_ci	int unit = d->lct_data.tid;
28648c2ecf20Sopenharmony_ci
28658c2ecf20Sopenharmony_ci	printk(KERN_INFO "TID %3.3d ", unit);
28668c2ecf20Sopenharmony_ci
28678c2ecf20Sopenharmony_ci	if(adpt_i2o_query_scalar(pHba, unit, 0xF100, 3, buf, 16)>=0)
28688c2ecf20Sopenharmony_ci	{
28698c2ecf20Sopenharmony_ci		buf[16]=0;
28708c2ecf20Sopenharmony_ci		printk(" Vendor: %-12.12s", buf);
28718c2ecf20Sopenharmony_ci	}
28728c2ecf20Sopenharmony_ci	if(adpt_i2o_query_scalar(pHba, unit, 0xF100, 4, buf, 16)>=0)
28738c2ecf20Sopenharmony_ci	{
28748c2ecf20Sopenharmony_ci		buf[16]=0;
28758c2ecf20Sopenharmony_ci		printk(" Device: %-12.12s", buf);
28768c2ecf20Sopenharmony_ci	}
28778c2ecf20Sopenharmony_ci	if(adpt_i2o_query_scalar(pHba, unit, 0xF100, 6, buf, 8)>=0)
28788c2ecf20Sopenharmony_ci	{
28798c2ecf20Sopenharmony_ci		buf[8]=0;
28808c2ecf20Sopenharmony_ci		printk(" Rev: %-12.12s\n", buf);
28818c2ecf20Sopenharmony_ci	}
28828c2ecf20Sopenharmony_ci#ifdef DEBUG
28838c2ecf20Sopenharmony_ci	 printk(KERN_INFO "\tClass: %.21s\n", adpt_i2o_get_class_name(d->lct_data.class_id));
28848c2ecf20Sopenharmony_ci	 printk(KERN_INFO "\tSubclass: 0x%04X\n", d->lct_data.sub_class);
28858c2ecf20Sopenharmony_ci	 printk(KERN_INFO "\tFlags: ");
28868c2ecf20Sopenharmony_ci
28878c2ecf20Sopenharmony_ci	 if(d->lct_data.device_flags&(1<<0))
28888c2ecf20Sopenharmony_ci		  printk("C");	     // ConfigDialog requested
28898c2ecf20Sopenharmony_ci	 if(d->lct_data.device_flags&(1<<1))
28908c2ecf20Sopenharmony_ci		  printk("U");	     // Multi-user capable
28918c2ecf20Sopenharmony_ci	 if(!(d->lct_data.device_flags&(1<<4)))
28928c2ecf20Sopenharmony_ci		  printk("P");	     // Peer service enabled!
28938c2ecf20Sopenharmony_ci	 if(!(d->lct_data.device_flags&(1<<5)))
28948c2ecf20Sopenharmony_ci		  printk("M");	     // Mgmt service enabled!
28958c2ecf20Sopenharmony_ci	 printk("\n");
28968c2ecf20Sopenharmony_ci#endif
28978c2ecf20Sopenharmony_ci}
28988c2ecf20Sopenharmony_ci
28998c2ecf20Sopenharmony_ci#ifdef DEBUG
29008c2ecf20Sopenharmony_ci/*
29018c2ecf20Sopenharmony_ci *	Do i2o class name lookup
29028c2ecf20Sopenharmony_ci */
29038c2ecf20Sopenharmony_cistatic const char *adpt_i2o_get_class_name(int class)
29048c2ecf20Sopenharmony_ci{
29058c2ecf20Sopenharmony_ci	int idx = 16;
29068c2ecf20Sopenharmony_ci	static char *i2o_class_name[] = {
29078c2ecf20Sopenharmony_ci		"Executive",
29088c2ecf20Sopenharmony_ci		"Device Driver Module",
29098c2ecf20Sopenharmony_ci		"Block Device",
29108c2ecf20Sopenharmony_ci		"Tape Device",
29118c2ecf20Sopenharmony_ci		"LAN Interface",
29128c2ecf20Sopenharmony_ci		"WAN Interface",
29138c2ecf20Sopenharmony_ci		"Fibre Channel Port",
29148c2ecf20Sopenharmony_ci		"Fibre Channel Device",
29158c2ecf20Sopenharmony_ci		"SCSI Device",
29168c2ecf20Sopenharmony_ci		"ATE Port",
29178c2ecf20Sopenharmony_ci		"ATE Device",
29188c2ecf20Sopenharmony_ci		"Floppy Controller",
29198c2ecf20Sopenharmony_ci		"Floppy Device",
29208c2ecf20Sopenharmony_ci		"Secondary Bus Port",
29218c2ecf20Sopenharmony_ci		"Peer Transport Agent",
29228c2ecf20Sopenharmony_ci		"Peer Transport",
29238c2ecf20Sopenharmony_ci		"Unknown"
29248c2ecf20Sopenharmony_ci	};
29258c2ecf20Sopenharmony_ci
29268c2ecf20Sopenharmony_ci	switch(class&0xFFF) {
29278c2ecf20Sopenharmony_ci	case I2O_CLASS_EXECUTIVE:
29288c2ecf20Sopenharmony_ci		idx = 0; break;
29298c2ecf20Sopenharmony_ci	case I2O_CLASS_DDM:
29308c2ecf20Sopenharmony_ci		idx = 1; break;
29318c2ecf20Sopenharmony_ci	case I2O_CLASS_RANDOM_BLOCK_STORAGE:
29328c2ecf20Sopenharmony_ci		idx = 2; break;
29338c2ecf20Sopenharmony_ci	case I2O_CLASS_SEQUENTIAL_STORAGE:
29348c2ecf20Sopenharmony_ci		idx = 3; break;
29358c2ecf20Sopenharmony_ci	case I2O_CLASS_LAN:
29368c2ecf20Sopenharmony_ci		idx = 4; break;
29378c2ecf20Sopenharmony_ci	case I2O_CLASS_WAN:
29388c2ecf20Sopenharmony_ci		idx = 5; break;
29398c2ecf20Sopenharmony_ci	case I2O_CLASS_FIBRE_CHANNEL_PORT:
29408c2ecf20Sopenharmony_ci		idx = 6; break;
29418c2ecf20Sopenharmony_ci	case I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL:
29428c2ecf20Sopenharmony_ci		idx = 7; break;
29438c2ecf20Sopenharmony_ci	case I2O_CLASS_SCSI_PERIPHERAL:
29448c2ecf20Sopenharmony_ci		idx = 8; break;
29458c2ecf20Sopenharmony_ci	case I2O_CLASS_ATE_PORT:
29468c2ecf20Sopenharmony_ci		idx = 9; break;
29478c2ecf20Sopenharmony_ci	case I2O_CLASS_ATE_PERIPHERAL:
29488c2ecf20Sopenharmony_ci		idx = 10; break;
29498c2ecf20Sopenharmony_ci	case I2O_CLASS_FLOPPY_CONTROLLER:
29508c2ecf20Sopenharmony_ci		idx = 11; break;
29518c2ecf20Sopenharmony_ci	case I2O_CLASS_FLOPPY_DEVICE:
29528c2ecf20Sopenharmony_ci		idx = 12; break;
29538c2ecf20Sopenharmony_ci	case I2O_CLASS_BUS_ADAPTER_PORT:
29548c2ecf20Sopenharmony_ci		idx = 13; break;
29558c2ecf20Sopenharmony_ci	case I2O_CLASS_PEER_TRANSPORT_AGENT:
29568c2ecf20Sopenharmony_ci		idx = 14; break;
29578c2ecf20Sopenharmony_ci	case I2O_CLASS_PEER_TRANSPORT:
29588c2ecf20Sopenharmony_ci		idx = 15; break;
29598c2ecf20Sopenharmony_ci	}
29608c2ecf20Sopenharmony_ci	return i2o_class_name[idx];
29618c2ecf20Sopenharmony_ci}
29628c2ecf20Sopenharmony_ci#endif
29638c2ecf20Sopenharmony_ci
29648c2ecf20Sopenharmony_ci
29658c2ecf20Sopenharmony_cistatic s32 adpt_i2o_hrt_get(adpt_hba* pHba)
29668c2ecf20Sopenharmony_ci{
29678c2ecf20Sopenharmony_ci	u32 msg[6];
29688c2ecf20Sopenharmony_ci	int ret, size = sizeof(i2o_hrt);
29698c2ecf20Sopenharmony_ci
29708c2ecf20Sopenharmony_ci	do {
29718c2ecf20Sopenharmony_ci		if (pHba->hrt == NULL) {
29728c2ecf20Sopenharmony_ci			pHba->hrt = dma_alloc_coherent(&pHba->pDev->dev,
29738c2ecf20Sopenharmony_ci					size, &pHba->hrt_pa, GFP_KERNEL);
29748c2ecf20Sopenharmony_ci			if (pHba->hrt == NULL) {
29758c2ecf20Sopenharmony_ci				printk(KERN_CRIT "%s: Hrt Get failed; Out of memory.\n", pHba->name);
29768c2ecf20Sopenharmony_ci				return -ENOMEM;
29778c2ecf20Sopenharmony_ci			}
29788c2ecf20Sopenharmony_ci		}
29798c2ecf20Sopenharmony_ci
29808c2ecf20Sopenharmony_ci		msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4;
29818c2ecf20Sopenharmony_ci		msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID;
29828c2ecf20Sopenharmony_ci		msg[2]= 0;
29838c2ecf20Sopenharmony_ci		msg[3]= 0;
29848c2ecf20Sopenharmony_ci		msg[4]= (0xD0000000 | size);    /* Simple transaction */
29858c2ecf20Sopenharmony_ci		msg[5]= (u32)pHba->hrt_pa;	/* Dump it here */
29868c2ecf20Sopenharmony_ci
29878c2ecf20Sopenharmony_ci		if ((ret = adpt_i2o_post_wait(pHba, msg, sizeof(msg),20))) {
29888c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: Unable to get HRT (status=%#10x)\n", pHba->name, ret);
29898c2ecf20Sopenharmony_ci			return ret;
29908c2ecf20Sopenharmony_ci		}
29918c2ecf20Sopenharmony_ci
29928c2ecf20Sopenharmony_ci		if (pHba->hrt->num_entries * pHba->hrt->entry_len << 2 > size) {
29938c2ecf20Sopenharmony_ci			int newsize = pHba->hrt->num_entries * pHba->hrt->entry_len << 2;
29948c2ecf20Sopenharmony_ci			dma_free_coherent(&pHba->pDev->dev, size,
29958c2ecf20Sopenharmony_ci				pHba->hrt, pHba->hrt_pa);
29968c2ecf20Sopenharmony_ci			size = newsize;
29978c2ecf20Sopenharmony_ci			pHba->hrt = NULL;
29988c2ecf20Sopenharmony_ci		}
29998c2ecf20Sopenharmony_ci	} while(pHba->hrt == NULL);
30008c2ecf20Sopenharmony_ci	return 0;
30018c2ecf20Sopenharmony_ci}
30028c2ecf20Sopenharmony_ci
30038c2ecf20Sopenharmony_ci/*
30048c2ecf20Sopenharmony_ci *	 Query one scalar group value or a whole scalar group.
30058c2ecf20Sopenharmony_ci */
30068c2ecf20Sopenharmony_cistatic int adpt_i2o_query_scalar(adpt_hba* pHba, int tid,
30078c2ecf20Sopenharmony_ci			int group, int field, void *buf, int buflen)
30088c2ecf20Sopenharmony_ci{
30098c2ecf20Sopenharmony_ci	u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field };
30108c2ecf20Sopenharmony_ci	u8 *opblk_va;
30118c2ecf20Sopenharmony_ci	dma_addr_t opblk_pa;
30128c2ecf20Sopenharmony_ci	u8 *resblk_va;
30138c2ecf20Sopenharmony_ci	dma_addr_t resblk_pa;
30148c2ecf20Sopenharmony_ci
30158c2ecf20Sopenharmony_ci	int size;
30168c2ecf20Sopenharmony_ci
30178c2ecf20Sopenharmony_ci	/* 8 bytes for header */
30188c2ecf20Sopenharmony_ci	resblk_va = dma_alloc_coherent(&pHba->pDev->dev,
30198c2ecf20Sopenharmony_ci			sizeof(u8) * (8 + buflen), &resblk_pa, GFP_KERNEL);
30208c2ecf20Sopenharmony_ci	if (resblk_va == NULL) {
30218c2ecf20Sopenharmony_ci		printk(KERN_CRIT "%s: query scalar failed; Out of memory.\n", pHba->name);
30228c2ecf20Sopenharmony_ci		return -ENOMEM;
30238c2ecf20Sopenharmony_ci	}
30248c2ecf20Sopenharmony_ci
30258c2ecf20Sopenharmony_ci	opblk_va = dma_alloc_coherent(&pHba->pDev->dev,
30268c2ecf20Sopenharmony_ci			sizeof(opblk), &opblk_pa, GFP_KERNEL);
30278c2ecf20Sopenharmony_ci	if (opblk_va == NULL) {
30288c2ecf20Sopenharmony_ci		dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen),
30298c2ecf20Sopenharmony_ci			resblk_va, resblk_pa);
30308c2ecf20Sopenharmony_ci		printk(KERN_CRIT "%s: query operation failed; Out of memory.\n",
30318c2ecf20Sopenharmony_ci			pHba->name);
30328c2ecf20Sopenharmony_ci		return -ENOMEM;
30338c2ecf20Sopenharmony_ci	}
30348c2ecf20Sopenharmony_ci	if (field == -1)  		/* whole group */
30358c2ecf20Sopenharmony_ci			opblk[4] = -1;
30368c2ecf20Sopenharmony_ci
30378c2ecf20Sopenharmony_ci	memcpy(opblk_va, opblk, sizeof(opblk));
30388c2ecf20Sopenharmony_ci	size = adpt_i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, pHba, tid,
30398c2ecf20Sopenharmony_ci		opblk_va, opblk_pa, sizeof(opblk),
30408c2ecf20Sopenharmony_ci		resblk_va, resblk_pa, sizeof(u8)*(8+buflen));
30418c2ecf20Sopenharmony_ci	dma_free_coherent(&pHba->pDev->dev, sizeof(opblk), opblk_va, opblk_pa);
30428c2ecf20Sopenharmony_ci	if (size == -ETIME) {
30438c2ecf20Sopenharmony_ci		dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen),
30448c2ecf20Sopenharmony_ci							resblk_va, resblk_pa);
30458c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: issue params failed; Timed out.\n", pHba->name);
30468c2ecf20Sopenharmony_ci		return -ETIME;
30478c2ecf20Sopenharmony_ci	} else if (size == -EINTR) {
30488c2ecf20Sopenharmony_ci		dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen),
30498c2ecf20Sopenharmony_ci							resblk_va, resblk_pa);
30508c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: issue params failed; Interrupted.\n", pHba->name);
30518c2ecf20Sopenharmony_ci		return -EINTR;
30528c2ecf20Sopenharmony_ci	}
30538c2ecf20Sopenharmony_ci
30548c2ecf20Sopenharmony_ci	memcpy(buf, resblk_va+8, buflen);  /* cut off header */
30558c2ecf20Sopenharmony_ci
30568c2ecf20Sopenharmony_ci	dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen),
30578c2ecf20Sopenharmony_ci						resblk_va, resblk_pa);
30588c2ecf20Sopenharmony_ci	if (size < 0)
30598c2ecf20Sopenharmony_ci		return size;
30608c2ecf20Sopenharmony_ci
30618c2ecf20Sopenharmony_ci	return buflen;
30628c2ecf20Sopenharmony_ci}
30638c2ecf20Sopenharmony_ci
30648c2ecf20Sopenharmony_ci
30658c2ecf20Sopenharmony_ci/*	Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET
30668c2ecf20Sopenharmony_ci *
30678c2ecf20Sopenharmony_ci *	This function can be used for all UtilParamsGet/Set operations.
30688c2ecf20Sopenharmony_ci *	The OperationBlock is given in opblk-buffer,
30698c2ecf20Sopenharmony_ci *	and results are returned in resblk-buffer.
30708c2ecf20Sopenharmony_ci *	Note that the minimum sized resblk is 8 bytes and contains
30718c2ecf20Sopenharmony_ci *	ResultCount, ErrorInfoSize, BlockStatus and BlockSize.
30728c2ecf20Sopenharmony_ci */
30738c2ecf20Sopenharmony_cistatic int adpt_i2o_issue_params(int cmd, adpt_hba* pHba, int tid,
30748c2ecf20Sopenharmony_ci		  void *opblk_va,  dma_addr_t opblk_pa, int oplen,
30758c2ecf20Sopenharmony_ci		void *resblk_va, dma_addr_t resblk_pa, int reslen)
30768c2ecf20Sopenharmony_ci{
30778c2ecf20Sopenharmony_ci	u32 msg[9];
30788c2ecf20Sopenharmony_ci	u32 *res = (u32 *)resblk_va;
30798c2ecf20Sopenharmony_ci	int wait_status;
30808c2ecf20Sopenharmony_ci
30818c2ecf20Sopenharmony_ci	msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5;
30828c2ecf20Sopenharmony_ci	msg[1] = cmd << 24 | HOST_TID << 12 | tid;
30838c2ecf20Sopenharmony_ci	msg[2] = 0;
30848c2ecf20Sopenharmony_ci	msg[3] = 0;
30858c2ecf20Sopenharmony_ci	msg[4] = 0;
30868c2ecf20Sopenharmony_ci	msg[5] = 0x54000000 | oplen;	/* OperationBlock */
30878c2ecf20Sopenharmony_ci	msg[6] = (u32)opblk_pa;
30888c2ecf20Sopenharmony_ci	msg[7] = 0xD0000000 | reslen;	/* ResultBlock */
30898c2ecf20Sopenharmony_ci	msg[8] = (u32)resblk_pa;
30908c2ecf20Sopenharmony_ci
30918c2ecf20Sopenharmony_ci	if ((wait_status = adpt_i2o_post_wait(pHba, msg, sizeof(msg), 20))) {
30928c2ecf20Sopenharmony_ci		printk("adpt_i2o_issue_params: post_wait failed (%p)\n", resblk_va);
30938c2ecf20Sopenharmony_ci   		return wait_status; 	/* -DetailedStatus */
30948c2ecf20Sopenharmony_ci	}
30958c2ecf20Sopenharmony_ci
30968c2ecf20Sopenharmony_ci	if (res[1]&0x00FF0000) { 	/* BlockStatus != SUCCESS */
30978c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: %s - Error:\n  ErrorInfoSize = 0x%02x, "
30988c2ecf20Sopenharmony_ci			"BlockStatus = 0x%02x, BlockSize = 0x%04x\n",
30998c2ecf20Sopenharmony_ci			pHba->name,
31008c2ecf20Sopenharmony_ci			(cmd == I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET"
31018c2ecf20Sopenharmony_ci							 : "PARAMS_GET",
31028c2ecf20Sopenharmony_ci			res[1]>>24, (res[1]>>16)&0xFF, res[1]&0xFFFF);
31038c2ecf20Sopenharmony_ci		return -((res[1] >> 16) & 0xFF); /* -BlockStatus */
31048c2ecf20Sopenharmony_ci	}
31058c2ecf20Sopenharmony_ci
31068c2ecf20Sopenharmony_ci	return 4 + ((res[1] & 0x0000FFFF) << 2); /* bytes used in resblk */
31078c2ecf20Sopenharmony_ci}
31088c2ecf20Sopenharmony_ci
31098c2ecf20Sopenharmony_ci
31108c2ecf20Sopenharmony_cistatic s32 adpt_i2o_quiesce_hba(adpt_hba* pHba)
31118c2ecf20Sopenharmony_ci{
31128c2ecf20Sopenharmony_ci	u32 msg[4];
31138c2ecf20Sopenharmony_ci	int ret;
31148c2ecf20Sopenharmony_ci
31158c2ecf20Sopenharmony_ci	adpt_i2o_status_get(pHba);
31168c2ecf20Sopenharmony_ci
31178c2ecf20Sopenharmony_ci	/* SysQuiesce discarded if IOP not in READY or OPERATIONAL state */
31188c2ecf20Sopenharmony_ci
31198c2ecf20Sopenharmony_ci	if((pHba->status_block->iop_state != ADAPTER_STATE_READY) &&
31208c2ecf20Sopenharmony_ci   	   (pHba->status_block->iop_state != ADAPTER_STATE_OPERATIONAL)){
31218c2ecf20Sopenharmony_ci		return 0;
31228c2ecf20Sopenharmony_ci	}
31238c2ecf20Sopenharmony_ci
31248c2ecf20Sopenharmony_ci	msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
31258c2ecf20Sopenharmony_ci	msg[1] = I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID;
31268c2ecf20Sopenharmony_ci	msg[2] = 0;
31278c2ecf20Sopenharmony_ci	msg[3] = 0;
31288c2ecf20Sopenharmony_ci
31298c2ecf20Sopenharmony_ci	if((ret = adpt_i2o_post_wait(pHba, msg, sizeof(msg), 240))) {
31308c2ecf20Sopenharmony_ci		printk(KERN_INFO"dpti%d: Unable to quiesce (status=%#x).\n",
31318c2ecf20Sopenharmony_ci				pHba->unit, -ret);
31328c2ecf20Sopenharmony_ci	} else {
31338c2ecf20Sopenharmony_ci		printk(KERN_INFO"dpti%d: Quiesced.\n",pHba->unit);
31348c2ecf20Sopenharmony_ci	}
31358c2ecf20Sopenharmony_ci
31368c2ecf20Sopenharmony_ci	adpt_i2o_status_get(pHba);
31378c2ecf20Sopenharmony_ci	return ret;
31388c2ecf20Sopenharmony_ci}
31398c2ecf20Sopenharmony_ci
31408c2ecf20Sopenharmony_ci
31418c2ecf20Sopenharmony_ci/*
31428c2ecf20Sopenharmony_ci * Enable IOP. Allows the IOP to resume external operations.
31438c2ecf20Sopenharmony_ci */
31448c2ecf20Sopenharmony_cistatic int adpt_i2o_enable_hba(adpt_hba* pHba)
31458c2ecf20Sopenharmony_ci{
31468c2ecf20Sopenharmony_ci	u32 msg[4];
31478c2ecf20Sopenharmony_ci	int ret;
31488c2ecf20Sopenharmony_ci
31498c2ecf20Sopenharmony_ci	adpt_i2o_status_get(pHba);
31508c2ecf20Sopenharmony_ci	if(!pHba->status_block){
31518c2ecf20Sopenharmony_ci		return -ENOMEM;
31528c2ecf20Sopenharmony_ci	}
31538c2ecf20Sopenharmony_ci	/* Enable only allowed on READY state */
31548c2ecf20Sopenharmony_ci	if(pHba->status_block->iop_state == ADAPTER_STATE_OPERATIONAL)
31558c2ecf20Sopenharmony_ci		return 0;
31568c2ecf20Sopenharmony_ci
31578c2ecf20Sopenharmony_ci	if(pHba->status_block->iop_state != ADAPTER_STATE_READY)
31588c2ecf20Sopenharmony_ci		return -EINVAL;
31598c2ecf20Sopenharmony_ci
31608c2ecf20Sopenharmony_ci	msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
31618c2ecf20Sopenharmony_ci	msg[1]=I2O_CMD_SYS_ENABLE<<24|HOST_TID<<12|ADAPTER_TID;
31628c2ecf20Sopenharmony_ci	msg[2]= 0;
31638c2ecf20Sopenharmony_ci	msg[3]= 0;
31648c2ecf20Sopenharmony_ci
31658c2ecf20Sopenharmony_ci	if ((ret = adpt_i2o_post_wait(pHba, msg, sizeof(msg), 240))) {
31668c2ecf20Sopenharmony_ci		printk(KERN_WARNING"%s: Could not enable (status=%#10x).\n",
31678c2ecf20Sopenharmony_ci			pHba->name, ret);
31688c2ecf20Sopenharmony_ci	} else {
31698c2ecf20Sopenharmony_ci		PDEBUG("%s: Enabled.\n", pHba->name);
31708c2ecf20Sopenharmony_ci	}
31718c2ecf20Sopenharmony_ci
31728c2ecf20Sopenharmony_ci	adpt_i2o_status_get(pHba);
31738c2ecf20Sopenharmony_ci	return ret;
31748c2ecf20Sopenharmony_ci}
31758c2ecf20Sopenharmony_ci
31768c2ecf20Sopenharmony_ci
31778c2ecf20Sopenharmony_cistatic int adpt_i2o_systab_send(adpt_hba* pHba)
31788c2ecf20Sopenharmony_ci{
31798c2ecf20Sopenharmony_ci	u32 msg[12];
31808c2ecf20Sopenharmony_ci	int ret;
31818c2ecf20Sopenharmony_ci
31828c2ecf20Sopenharmony_ci	msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6;
31838c2ecf20Sopenharmony_ci	msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID;
31848c2ecf20Sopenharmony_ci	msg[2] = 0;
31858c2ecf20Sopenharmony_ci	msg[3] = 0;
31868c2ecf20Sopenharmony_ci	msg[4] = (0<<16) | ((pHba->unit+2) << 12); /* Host 0 IOP ID (unit + 2) */
31878c2ecf20Sopenharmony_ci	msg[5] = 0;				   /* Segment 0 */
31888c2ecf20Sopenharmony_ci
31898c2ecf20Sopenharmony_ci	/*
31908c2ecf20Sopenharmony_ci	 * Provide three SGL-elements:
31918c2ecf20Sopenharmony_ci	 * System table (SysTab), Private memory space declaration and
31928c2ecf20Sopenharmony_ci	 * Private i/o space declaration
31938c2ecf20Sopenharmony_ci	 */
31948c2ecf20Sopenharmony_ci	msg[6] = 0x54000000 | sys_tbl_len;
31958c2ecf20Sopenharmony_ci	msg[7] = (u32)sys_tbl_pa;
31968c2ecf20Sopenharmony_ci	msg[8] = 0x54000000 | 0;
31978c2ecf20Sopenharmony_ci	msg[9] = 0;
31988c2ecf20Sopenharmony_ci	msg[10] = 0xD4000000 | 0;
31998c2ecf20Sopenharmony_ci	msg[11] = 0;
32008c2ecf20Sopenharmony_ci
32018c2ecf20Sopenharmony_ci	if ((ret=adpt_i2o_post_wait(pHba, msg, sizeof(msg), 120))) {
32028c2ecf20Sopenharmony_ci		printk(KERN_INFO "%s: Unable to set SysTab (status=%#10x).\n",
32038c2ecf20Sopenharmony_ci			pHba->name, ret);
32048c2ecf20Sopenharmony_ci	}
32058c2ecf20Sopenharmony_ci#ifdef DEBUG
32068c2ecf20Sopenharmony_ci	else {
32078c2ecf20Sopenharmony_ci		PINFO("%s: SysTab set.\n", pHba->name);
32088c2ecf20Sopenharmony_ci	}
32098c2ecf20Sopenharmony_ci#endif
32108c2ecf20Sopenharmony_ci
32118c2ecf20Sopenharmony_ci	return ret;
32128c2ecf20Sopenharmony_ci}
32138c2ecf20Sopenharmony_ci
32148c2ecf20Sopenharmony_ci
32158c2ecf20Sopenharmony_ci/*============================================================================
32168c2ecf20Sopenharmony_ci *
32178c2ecf20Sopenharmony_ci *============================================================================
32188c2ecf20Sopenharmony_ci */
32198c2ecf20Sopenharmony_ci
32208c2ecf20Sopenharmony_ci
32218c2ecf20Sopenharmony_ci#ifdef UARTDELAY
32228c2ecf20Sopenharmony_ci
32238c2ecf20Sopenharmony_cistatic static void adpt_delay(int millisec)
32248c2ecf20Sopenharmony_ci{
32258c2ecf20Sopenharmony_ci	int i;
32268c2ecf20Sopenharmony_ci	for (i = 0; i < millisec; i++) {
32278c2ecf20Sopenharmony_ci		udelay(1000);	/* delay for one millisecond */
32288c2ecf20Sopenharmony_ci	}
32298c2ecf20Sopenharmony_ci}
32308c2ecf20Sopenharmony_ci
32318c2ecf20Sopenharmony_ci#endif
32328c2ecf20Sopenharmony_ci
32338c2ecf20Sopenharmony_cistatic struct scsi_host_template driver_template = {
32348c2ecf20Sopenharmony_ci	.module			= THIS_MODULE,
32358c2ecf20Sopenharmony_ci	.name			= "dpt_i2o",
32368c2ecf20Sopenharmony_ci	.proc_name		= "dpt_i2o",
32378c2ecf20Sopenharmony_ci	.show_info		= adpt_show_info,
32388c2ecf20Sopenharmony_ci	.info			= adpt_info,
32398c2ecf20Sopenharmony_ci	.queuecommand		= adpt_queue,
32408c2ecf20Sopenharmony_ci	.eh_abort_handler	= adpt_abort,
32418c2ecf20Sopenharmony_ci	.eh_device_reset_handler = adpt_device_reset,
32428c2ecf20Sopenharmony_ci	.eh_bus_reset_handler	= adpt_bus_reset,
32438c2ecf20Sopenharmony_ci	.eh_host_reset_handler	= adpt_reset,
32448c2ecf20Sopenharmony_ci	.bios_param		= adpt_bios_param,
32458c2ecf20Sopenharmony_ci	.slave_configure	= adpt_slave_configure,
32468c2ecf20Sopenharmony_ci	.can_queue		= MAX_TO_IOP_MESSAGES,
32478c2ecf20Sopenharmony_ci	.this_id		= 7,
32488c2ecf20Sopenharmony_ci};
32498c2ecf20Sopenharmony_ci
32508c2ecf20Sopenharmony_cistatic int __init adpt_init(void)
32518c2ecf20Sopenharmony_ci{
32528c2ecf20Sopenharmony_ci	int		error;
32538c2ecf20Sopenharmony_ci	adpt_hba	*pHba, *next;
32548c2ecf20Sopenharmony_ci
32558c2ecf20Sopenharmony_ci	printk("Loading Adaptec I2O RAID: Version " DPT_I2O_VERSION "\n");
32568c2ecf20Sopenharmony_ci
32578c2ecf20Sopenharmony_ci	error = adpt_detect(&driver_template);
32588c2ecf20Sopenharmony_ci	if (error < 0)
32598c2ecf20Sopenharmony_ci		return error;
32608c2ecf20Sopenharmony_ci	if (hba_chain == NULL)
32618c2ecf20Sopenharmony_ci		return -ENODEV;
32628c2ecf20Sopenharmony_ci
32638c2ecf20Sopenharmony_ci	for (pHba = hba_chain; pHba; pHba = pHba->next) {
32648c2ecf20Sopenharmony_ci		error = scsi_add_host(pHba->host, &pHba->pDev->dev);
32658c2ecf20Sopenharmony_ci		if (error)
32668c2ecf20Sopenharmony_ci			goto fail;
32678c2ecf20Sopenharmony_ci		scsi_scan_host(pHba->host);
32688c2ecf20Sopenharmony_ci	}
32698c2ecf20Sopenharmony_ci	return 0;
32708c2ecf20Sopenharmony_cifail:
32718c2ecf20Sopenharmony_ci	for (pHba = hba_chain; pHba; pHba = next) {
32728c2ecf20Sopenharmony_ci		next = pHba->next;
32738c2ecf20Sopenharmony_ci		scsi_remove_host(pHba->host);
32748c2ecf20Sopenharmony_ci	}
32758c2ecf20Sopenharmony_ci	return error;
32768c2ecf20Sopenharmony_ci}
32778c2ecf20Sopenharmony_ci
32788c2ecf20Sopenharmony_cistatic void __exit adpt_exit(void)
32798c2ecf20Sopenharmony_ci{
32808c2ecf20Sopenharmony_ci	adpt_hba	*pHba, *next;
32818c2ecf20Sopenharmony_ci
32828c2ecf20Sopenharmony_ci	for (pHba = hba_chain; pHba; pHba = next) {
32838c2ecf20Sopenharmony_ci		next = pHba->next;
32848c2ecf20Sopenharmony_ci		adpt_release(pHba);
32858c2ecf20Sopenharmony_ci	}
32868c2ecf20Sopenharmony_ci}
32878c2ecf20Sopenharmony_ci
32888c2ecf20Sopenharmony_cimodule_init(adpt_init);
32898c2ecf20Sopenharmony_cimodule_exit(adpt_exit);
32908c2ecf20Sopenharmony_ci
32918c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
3292