[SCSI] remove broken driver cpqfc
authorJames Bottomley <jejb@mulgrave.(none)>
Sat, 29 Oct 2005 15:01:24 +0000 (10:01 -0500)
committerJames Bottomley <jejb@mulgrave.(none)>
Sat, 29 Oct 2005 15:01:24 +0000 (10:01 -0500)
Hopefully there should be a brand new replacement driver for this heap
of junk by the beginning of next year.

Acked By: Martin K. Petersen <mkp@mkp.net>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
12 files changed:
drivers/scsi/Kconfig
drivers/scsi/Makefile
drivers/scsi/cpqfcTS.h [deleted file]
drivers/scsi/cpqfcTSchip.h [deleted file]
drivers/scsi/cpqfcTScontrol.c [deleted file]
drivers/scsi/cpqfcTSi2c.c [deleted file]
drivers/scsi/cpqfcTSinit.c [deleted file]
drivers/scsi/cpqfcTSioctl.h [deleted file]
drivers/scsi/cpqfcTSstructs.h [deleted file]
drivers/scsi/cpqfcTStrigger.c [deleted file]
drivers/scsi/cpqfcTStrigger.h [deleted file]
drivers/scsi/cpqfcTSworker.c [deleted file]

index 78c3318..afeca32 100644 (file)
@@ -620,19 +620,6 @@ config SCSI_OMIT_FLASHPOINT
          substantial, so users of MultiMaster Host Adapters may wish to omit
          it.
 
-#
-# This is marked broken because it uses over 4kB of stack in
-# just two routines:
-#     2076  CpqTsProcessIMQEntry
-#     2052  PeekIMQEntry
-#
-config SCSI_CPQFCTS
-       tristate "Compaq Fibre Channel 64-bit/66Mhz HBA support"
-       depends on PCI && SCSI && BROKEN
-       help
-         Say Y here to compile in support for the Compaq StorageWorks Fibre
-         Channel 64-bit/66Mhz Host Bus Adapter.
-
 config SCSI_DMX3191D
        tristate "DMX3191D SCSI support"
        depends on PCI && SCSI
index 8dfb988..b88b8c4 100644 (file)
@@ -120,7 +120,6 @@ obj-$(CONFIG_JAZZ_ESP)              += NCR53C9x.o   jazz_esp.o
 obj-$(CONFIG_SUN3X_ESP)                += NCR53C9x.o   sun3x_esp.o
 obj-$(CONFIG_SCSI_DEBUG)       += scsi_debug.o
 obj-$(CONFIG_SCSI_FCAL)                += fcal.o
-obj-$(CONFIG_SCSI_CPQFCTS)     += cpqfc.o
 obj-$(CONFIG_SCSI_LASI700)     += 53c700.o lasi700.o
 obj-$(CONFIG_SCSI_NSP32)       += nsp32.o
 obj-$(CONFIG_SCSI_IPR)         += ipr.o
@@ -165,8 +164,6 @@ ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \
 CFLAGS_ncr53c8xx.o     := $(ncr53c8xx-flags-y) $(ncr53c8xx-flags-m)
 zalon7xx-objs  := zalon.o ncr53c8xx.o
 NCR_Q720_mod-objs      := NCR_Q720.o ncr53c8xx.o
-cpqfc-objs     := cpqfcTSinit.o cpqfcTScontrol.o cpqfcTSi2c.o \
-                  cpqfcTSworker.o cpqfcTStrigger.o
 libata-objs    := libata-core.o libata-scsi.o
 
 # Files generated that shall be removed upon make clean
diff --git a/drivers/scsi/cpqfcTS.h b/drivers/scsi/cpqfcTS.h
deleted file mode 100644 (file)
index 7ce53d8..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef CPQFCTS_H
-#define CPQFCTS_H
-#include "cpqfcTSstructs.h"
-
-// These functions are required by the Linux SCSI layers
-extern int cpqfcTS_detect(Scsi_Host_Template *);
-extern int cpqfcTS_release(struct Scsi_Host *);
-extern const char * cpqfcTS_info(struct Scsi_Host *);
-extern int cpqfcTS_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
-extern int cpqfcTS_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
-extern int cpqfcTS_abort(Scsi_Cmnd *);
-extern int cpqfcTS_reset(Scsi_Cmnd *, unsigned int);
-extern int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd);
-extern int cpqfcTS_eh_device_reset(Scsi_Cmnd *);
-extern int cpqfcTS_biosparam(struct scsi_device *, struct block_device *,
-               sector_t, int[]);
-extern int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg);
-
-#endif /* CPQFCTS_H */ 
diff --git a/drivers/scsi/cpqfcTSchip.h b/drivers/scsi/cpqfcTSchip.h
deleted file mode 100644 (file)
index 14b8337..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-/* Copyright(c) 2000, Compaq Computer Corporation 
- * Fibre Channel Host Bus Adapter 
- * 64-bit, 66MHz PCI 
- * Originally developed and tested on:
- * (front): [chip] Tachyon TS HPFC-5166A/1.2  L2C1090 ...
- *          SP# P225CXCBFIEL6T, Rev XC
- *          SP# 161290-001, Rev XD
- * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- * Written by Don Zimmerman
-*/
-#ifndef CPQFCTSCHIP_H
-#define CPQFCTSCHIP_H
-#ifndef TACHYON_CHIP_INC
-
-// FC-PH (Physical) specification levels for Login payloads
-// NOTE: These are NOT strictly complied with by any FC vendors
-
-#define FC_PH42                        0x08
-#define FC_PH43                        0x09
-#define FC_PH3                 0x20
-
-#define TACHLITE_TS_RX_SIZE     1024  // max inbound frame size
-// "I" prefix is for Include
-
-#define IVENDID    0x00  // word
-#define IDEVID     0x02
-#define ITLCFGCMD 0x04
-#define IMEMBASE   0x18    // Tachyon
-#define ITLMEMBASE   0x1C  // Tachlite
-#define IIOBASEL   0x10    // Tachyon I/O base address, lower 256 bytes
-#define IIOBASEU   0x14    // Tachyon I/O base address, upper 256 bytes
-#define ITLIOBASEL   0x14  // TachLite I/O base address, lower 256 bytes
-#define ITLIOBASEU   0x18  // TachLite I/O base address, upper 256 bytes
-#define ITLRAMBASE   0x20  // TL on-board RAM start
-#define ISROMBASE  0x24
-#define IROMBASE   0x30
-
-#define ICFGCMD    0x04    // PCI config - PCI config access (word)
-#define ICFGSTAT   0x06    // PCI status (R - word)
-#define IRCTR_WCTR 0x1F2   // ROM control / pre-fetch wait counter
-#define IPCIMCTR   0x1F3   // PCI master control register
-#define IINTPEND   0x1FD   // Interrupt pending (I/O Upper - Tachyon & TL)
-#define IINTEN     0x1FE   // Interrupt enable  (I/O Upper - Tachyon & TL)
-#define IINTSTAT   0x1FF   // Interrupt status  (I/O Upper - Tachyon & TL)
-
-#define IMQ_BASE            0x80
-#define IMQ_LENGTH          0x84
-#define IMQ_CONSUMER_INDEX  0x88
-#define IMQ_PRODUCER_INDEX  0x8C   // Tach copies its INDX to bits 0-7 of value
-
-/*
-// IOBASE UPPER
-#define SFSBQ_BASE            0x00   // single-frame sequences
-#define SFSBQ_LENGTH          0x04
-#define SFSBQ_PRODUCER_INDEX  0x08
-#define SFSBQ_CONSUMER_INDEX  0x0C   // (R)
-#define SFS_BUFFER_LENGTH     0X10
-                              // SCSI-FCP hardware assists
-#define SEST_BASE             0x40   // SSCI Exchange State Table
-#define SEST_LENGTH           0x44
-#define SCSI_BUFFER_LENGTH    0x48
-#define SEST_LINKED_LIST      0x4C
-
-#define TACHYON_My_ID         0x6C
-#define TACHYON_CONFIGURATION 0x84   // (R/W) reset val 2
-#define TACHYON_CONTROL       0x88
-#define TACHYON_STATUS        0x8C   // (R)
-#define TACHYON_FLUSH_SEST    0x90   // (R/W)
-#define TACHYON_EE_CREDIT_TMR 0x94   // (R)
-#define TACHYON_BB_CREDIT_TMR 0x98   // (R)
-#define TACHYON_RCV_FRAME_ERR 0x9C   // (R)
-#define FRAME_MANAGER_CONFIG  0xC0   // (R/W)
-#define FRAME_MANAGER_CONTROL 0xC4
-#define FRAME_MANAGER_STATUS  0xC8   // (R)
-#define FRAME_MANAGER_ED_TOV  0xCC
-#define FRAME_MANAGER_LINK_ERR1 0xD0   // (R)
-#define FRAME_MANAGER_LINK_ERR2 0xD4   // (R)
-#define FRAME_MANAGER_TIMEOUT2  0xD8   // (W)
-#define FRAME_MANAGER_BB_CREDIT 0xDC   // (R)
-#define FRAME_MANAGER_WWN_HI    0xE0   // (R/W)
-#define FRAME_MANAGER_WWN_LO    0xE4   // (R/W)
-#define FRAME_MANAGER_RCV_AL_PA 0xE8   // (R)
-#define FRAME_MANAGER_PRIMITIVE 0xEC   // {K28.5} byte1 byte2 byte3
-*/
-                   
-#define TL_MEM_ERQ_BASE                    0x0 //ERQ Base
-#define TL_IO_ERQ_BASE                     0x0 //ERQ base
-
-#define TL_MEM_ERQ_LENGTH                  0x4 //ERQ Length
-#define TL_IO_ERQ_LENGTH                   0x4 //ERQ Length
-
-#define TL_MEM_ERQ_PRODUCER_INDEX          0x8 //ERQ Producer Index  register
-#define TL_IO_ERQ_PRODUCER_INDEX           0x8 //ERQ Producer Index  register
-
-#define TL_MEM_ERQ_CONSUMER_INDEX_ADR 0xC //ERQ Consumer Index address register
-#define TL_IO_ERQ_CONSUMER_INDEX_ADR  0xC //ERQ Consumer Index address register
-
-#define TL_MEM_ERQ_CONSUMER_INDEX     0xC //ERQ Consumer Index 
-#define TL_IO_ERQ_CONSUMER_INDEX      0xC //ERQ Consumer Index 
-
-#define TL_MEM_SFQ_BASE               0x50 //SFQ Base
-#define TL_IO_SFQ_BASE                0x50 //SFQ base
-
-#define TL_MEM_SFQ_LENGTH             0x54 //SFQ Length
-#define TL_IO_SFQ_LENGTH              0x54 //SFQ Length
-
-#define TL_MEM_SFQ_CONSUMER_INDEX     0x58 //SFQ Consumer Index
-#define TL_IO_SFQ_CONSUMER_INDEX      0x58 //SFQ Consumer Index
-
-#define TL_MEM_IMQ_BASE               0x80 //IMQ Base
-#define TL_IO_IMQ_BASE                0x80 //IMQ base
-
-#define TL_MEM_IMQ_LENGTH             0x84 //IMQ Length
-#define TL_IO_IMQ_LENGTH              0x84 //IMQ Length
-
-#define TL_MEM_IMQ_CONSUMER_INDEX     0x88 //IMQ Consumer Index
-#define TL_IO_IMQ_CONSUMER_INDEX      0x88 //IMQ Consumer Index
-
-#define TL_MEM_IMQ_PRODUCER_INDEX_ADR 0x8C //IMQ Producer Index address register
-#define TL_IO_IMQ_PRODUCER_INDEX_ADR  0x8C //IMQ Producer Index address register
-
-#define TL_MEM_SEST_BASE              0x140 //SFQ Base
-#define TL_IO_SEST_BASE               0x40 //SFQ base
-
-#define TL_MEM_SEST_LENGTH            0x144 //SFQ Length
-#define TL_IO_SEST_LENGTH             0x44 //SFQ Length
-
-#define TL_MEM_SEST_LINKED_LIST       0x14C
-
-#define TL_MEM_SEST_SG_PAGE           0x168  // Extended Scatter/Gather page size
-
-#define TL_MEM_TACH_My_ID             0x16C
-#define TL_IO_TACH_My_ID              0x6C //My AL_PA ID
-
-#define TL_MEM_TACH_CONFIG            0x184 //Tachlite Configuration register
-#define TL_IO_CONFIG                  0x84 //Tachlite Configuration register
-
-#define TL_MEM_TACH_CONTROL           0x188 //Tachlite Control register
-#define TL_IO_CTR                     0x88 //Tachlite Control register
-
-#define TL_MEM_TACH_STATUS            0x18C //Tachlite Status register
-#define TL_IO_STAT                    0x8C //Tachlite Status register
-
-#define TL_MEM_FM_CONFIG        0x1C0 //Frame Manager Configuration register
-#define TL_IO_FM_CONFIG         0xC0 //Frame Manager Configuration register
-
-#define TL_MEM_FM_CONTROL       0x1C4 //Frame Manager Control
-#define TL_IO_FM_CTL            0xC4 //Frame Manager Control
-
-#define TL_MEM_FM_STATUS        0x1C8 //Frame Manager Status
-#define TL_IO_FM_STAT           0xC8 //Frame Manager Status
-
-#define TL_MEM_FM_LINK_STAT1    0x1D0 //Frame Manager Link Status 1
-#define TL_IO_FM_LINK_STAT1     0xD0 //Frame Manager Link Status 1
-
-#define TL_MEM_FM_LINK_STAT2    0x1D4 //Frame Manager Link Status 2
-#define TL_IO_FM_LINK_STAT2     0xD4 //Frame Manager Link Status 2
-
-#define TL_MEM_FM_TIMEOUT2      0x1D8   // (W)
-
-#define TL_MEM_FM_BB_CREDIT0    0x1DC
-
-#define TL_MEM_FM_WWN_HI        0x1E0 //Frame Manager World Wide Name High
-#define TL_IO_FM_WWN_HI         0xE0 //Frame Manager World Wide Name High
-
-#define TL_MEM_FM_WWN_LO        0x1E4 //Frame Manager World Wide Name LOW
-#define TL_IO_FM_WWN_LO         0xE4 //Frame Manager World Wide Name Low
-
-#define TL_MEM_FM_RCV_AL_PA     0x1E8 //Frame Manager AL_PA Received register
-#define TL_IO_FM_ALPA           0xE8 //Frame Manager AL_PA Received register
-
-#define TL_MEM_FM_ED_TOV           0x1CC
-
-#define TL_IO_ROMCTR            0xFA //TL PCI ROM Control Register
-#define TL_IO_PCIMCTR           0xFB //TL PCI Master Control Register
-#define TL_IO_SOFTRST           0xFC //Tachlite Configuration register
-#define TL_MEM_SOFTRST          0x1FC //Tachlite Configuration register
-
-// completion message types (bit 8 set means Interrupt generated)
-// CM_Type
-#define OUTBOUND_COMPLETION        0
-#define ERROR_IDLE_COMPLETION   0x01
-#define OUT_HI_PRI_COMPLETION   0x01
-#define INBOUND_MFS_COMPLETION  0x02
-#define INBOUND_000_COMPLETION  0x03
-#define INBOUND_SFS_COMPLETION  0x04  // Tachyon & TachLite
-#define ERQ_FROZEN_COMPLETION   0x06  // TachLite
-#define INBOUND_C1_TIMEOUT      0x05
-#define INBOUND_BUSIED_FRAME    0x06
-#define SFS_BUF_WARN            0x07
-#define FCP_FROZEN_COMPLETION   0x07  // TachLite
-#define MFS_BUF_WARN            0x08
-#define IMQ_BUF_WARN            0x09
-#define FRAME_MGR_INTERRUPT     0x0A
-#define READ_STATUS             0x0B
-#define INBOUND_SCSI_DATA_COMPLETION  0x0C
-#define INBOUND_FCP_XCHG_COMPLETION   0x0C  // TachLite
-#define INBOUND_SCSI_DATA_COMMAND     0x0D
-#define BAD_SCSI_FRAME                0x0E
-#define INB_SCSI_STATUS_COMPLETION    0x0F
-#define BUFFER_PROCESSED_COMPLETION   0x11
-
-// FC-AL (Tachyon) Loop Port State Machine defs
-// (loop "Up" states)
-#define MONITORING 0x0
-#define ARBITRATING 0x1
-#define ARBITRAT_WON 0x2
-#define OPEN 0x3
-#define OPENED 0x4
-#define XMITTD_CLOSE 0x5
-#define RCVD_CLOSE 0x6
-#define TRANSFER 0x7
-
-// (loop "Down" states)
-#define INITIALIZING 0x8
-#define O_I_INIT 0x9
-#define O_I_PROTOCOL 0xa
-#define O_I_LIP_RCVD 0xb
-#define HOST_CONTROL 0xc
-#define LOOP_FAIL 0xd
-// (no 0xe)
-#define OLD_PORT 0xf
-
-
-
-#define TACHYON_CHIP_INC
-#endif
-#endif /* CPQFCTSCHIP_H */
diff --git a/drivers/scsi/cpqfcTScontrol.c b/drivers/scsi/cpqfcTScontrol.c
deleted file mode 100644 (file)
index bd94c70..0000000
+++ /dev/null
@@ -1,2231 +0,0 @@
-/* Copyright 2000, Compaq Computer Corporation 
- * Fibre Channel Host Bus Adapter 
- * 64-bit, 66MHz PCI 
- * Originally developed and tested on:
- * (front): [chip] Tachyon TS HPFC-5166A/1.2  L2C1090 ...
- *          SP# P225CXCBFIEL6T, Rev XC
- *          SP# 161290-001, Rev XD
- * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- * Written by Don Zimmerman
-*/
-/* These functions control the host bus adapter (HBA) hardware.  The main chip
-   control takes place in the interrupt handler where we process the IMQ 
-   (Inbound Message Queue).  The IMQ is Tachyon's way of communicating FC link
-   events and state information to the driver.  The Single Frame Queue (SFQ)
-   buffers incoming FC frames for processing by the driver.  References to 
-   "TL/TS UG" are for:
-   "HP HPFC-5100/5166 Tachyon TL/TS ICs User Guide", August 16, 1999, 1st Ed.
-   Hewlitt Packard Manual Part Number 5968-1083E.
-*/
-
-#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
-
-#include <linux/blkdev.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ioport.h>  // request_region() prototype
-#include <linux/sched.h>
-#include <linux/slab.h>  // need "kfree" for ext. S/G pages
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/unistd.h>
-#include <asm/io.h>  // struct pt_regs for IRQ handler & Port I/O
-#include <asm/irq.h>
-#include <linux/spinlock.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>   // Scsi_Host definition for INT handler
-#include "cpqfcTSchip.h"
-#include "cpqfcTSstructs.h"
-
-//#define IMQ_DEBUG 1
-
-static void fcParseLinkStatusCounters(TACHYON * fcChip);
-static void CpqTsGetSFQEntry(TACHYON * fcChip, 
-             USHORT pi, ULONG * buffr, BOOLEAN UpdateChip); 
-
-static void 
-cpqfc_free_dma_consistent(CPQFCHBA *cpqfcHBAdata)
-{
-       // free up the primary EXCHANGES struct and Link Q
-       PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-
-       if (fcChip->Exchanges != NULL)
-               pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_EXCHANGES),
-                       fcChip->Exchanges, fcChip->exch_dma_handle);
-       fcChip->Exchanges = NULL;
-       if (cpqfcHBAdata->fcLQ != NULL)
-               pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_LINK_QUE),
-                       cpqfcHBAdata->fcLQ, cpqfcHBAdata->fcLQ_dma_handle);
-       cpqfcHBAdata->fcLQ = NULL;
-}
-
-// Note special requirements for Q alignment!  (TL/TS UG pg. 190)
-// We place critical index pointers at end of QUE elements to assist
-// in non-symbolic (i.e. memory dump) debugging
-// opcode defines placement of Queues (e.g. local/external RAM)
-
-int CpqTsCreateTachLiteQues( void* pHBA, int opcode)
-{
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-
-  int iStatus=0;
-  unsigned long ulAddr;
-  dma_addr_t ERQdma, IMQdma, SPQdma, SESTdma;
-  int i;
-
-  // NOTE! fcMemManager() will return system virtual addresses.
-  // System (kernel) virtual addresses, though non-paged, still
-  // aren't physical addresses.  Convert to PHYSICAL_ADDRESS for Tachyon's
-  // DMA use.
-  ENTER("CreateTachLiteQues");
-
-
-  // Allocate primary EXCHANGES array...
-  fcChip->Exchanges = NULL;
-  cpqfcHBAdata->fcLQ = NULL;
-  
-  /* printk("Allocating %u for %u Exchanges ", 
-         (ULONG)sizeof(FC_EXCHANGES), TACH_MAX_XID); */
-  fcChip->Exchanges = pci_alloc_consistent(cpqfcHBAdata->PciDev, 
-                       sizeof(FC_EXCHANGES), &fcChip->exch_dma_handle);
-  /* printk("@ %p\n", fcChip->Exchanges); */
-
-  if( fcChip->Exchanges == NULL ) // fatal error!!
-  {
-    printk("pci_alloc_consistent failure on Exchanges: fatal error\n");
-    return -1;
-  }
-  // zero out the entire EXCHANGE space
-  memset( fcChip->Exchanges, 0, sizeof( FC_EXCHANGES));  
-
-
-  /* printk("Allocating %u for LinkQ ", (ULONG)sizeof(FC_LINK_QUE)); */
-  cpqfcHBAdata->fcLQ = pci_alloc_consistent(cpqfcHBAdata->PciDev,
-                                sizeof( FC_LINK_QUE), &cpqfcHBAdata->fcLQ_dma_handle);
-  /* printk("@ %p (%u elements)\n", cpqfcHBAdata->fcLQ, FC_LINKQ_DEPTH); */
-
-  if( cpqfcHBAdata->fcLQ == NULL ) // fatal error!!
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("pci_alloc_consistent() failure on fc Link Que: fatal error\n");
-    return -1;
-  }
-  // zero out the entire EXCHANGE space
-  memset( cpqfcHBAdata->fcLQ, 0, sizeof( FC_LINK_QUE));  
-  
-  // Verify that basic Tach I/O registers are not NULL  
-  if( !fcChip->Registers.ReMapMemBase )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("HBA base address NULL: fatal error\n");
-    return -1;
-  }
-
-
-  // Initialize the fcMemManager memory pairs (stores allocated/aligned
-  // pairs for future freeing)
-  memset( cpqfcHBAdata->dynamic_mem, 0, sizeof(cpqfcHBAdata->dynamic_mem));
-  
-
-  // Allocate Tach's Exchange Request Queue (each ERQ entry 32 bytes)
-  
-  fcChip->ERQ = fcMemManager( cpqfcHBAdata->PciDev, 
-                       &cpqfcHBAdata->dynamic_mem[0], 
-                       sizeof( TachLiteERQ ), 32*(ERQ_LEN), 0L, &ERQdma);
-  if( !fcChip->ERQ )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("pci_alloc_consistent/alignment failure on ERQ: fatal error\n");
-    return -1;
-  }
-  fcChip->ERQ->length = ERQ_LEN-1;
-  ulAddr = (ULONG) ERQdma; 
-#if BITS_PER_LONG > 32
-  if( (ulAddr >> 32) )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk(" FATAL! ERQ ptr %p exceeds Tachyon's 32-bit register size\n",
-                   (void*)ulAddr);
-    return -1;  // failed
-  }
-#endif
-  fcChip->ERQ->base = (ULONG)ulAddr;  // copy for quick reference
-
-
-  // Allocate Tach's Inbound Message Queue (32 bytes per entry)
-  
-  fcChip->IMQ = fcMemManager( cpqfcHBAdata->PciDev, 
-                 &cpqfcHBAdata->dynamic_mem[0],
-                 sizeof( TachyonIMQ ), 32*(IMQ_LEN), 0L, &IMQdma );
-  if( !fcChip->IMQ )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("pci_alloc_consistent/alignment failure on IMQ: fatal error\n");
-    return -1;
-  }
-  fcChip->IMQ->length = IMQ_LEN-1;
-
-  ulAddr = IMQdma;
-#if BITS_PER_LONG > 32
-  if( (ulAddr >> 32) )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n",
-                   (void*)ulAddr);
-    return -1;  // failed
-  }
-#endif
-  fcChip->IMQ->base = (ULONG)ulAddr;  // copy for quick reference
-
-
-  // Allocate Tach's  Single Frame Queue (64 bytes per entry)
-  fcChip->SFQ = fcMemManager( cpqfcHBAdata->PciDev, 
-                 &cpqfcHBAdata->dynamic_mem[0],
-                 sizeof( TachLiteSFQ ), 64*(SFQ_LEN),0L, &SPQdma );
-  if( !fcChip->SFQ )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("pci_alloc_consistent/alignment failure on SFQ: fatal error\n");
-    return -1;
-  }
-  fcChip->SFQ->length = SFQ_LEN-1;      // i.e. Que length [# entries -
-                                       // min. 32; max.  4096 (0xffff)]
-  
-  ulAddr = SPQdma;
-#if BITS_PER_LONG > 32
-  if( (ulAddr >> 32) )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n",
-                   (void*)ulAddr);
-    return -1;  // failed
-  }
-#endif
-  fcChip->SFQ->base = (ULONG)ulAddr;  // copy for quick reference
-
-
-  // Allocate SCSI Exchange State Table; aligned nearest @sizeof
-  // power-of-2 boundary
-  // LIVE DANGEROUSLY!  Assume the boundary for SEST mem will
-  // be on physical page (e.g. 4k) boundary.
-  /* printk("Allocating %u for TachSEST for %u Exchanges\n", 
-                (ULONG)sizeof(TachSEST), TACH_SEST_LEN); */
-  fcChip->SEST = fcMemManager( cpqfcHBAdata->PciDev,
-                 &cpqfcHBAdata->dynamic_mem[0],
-                 sizeof(TachSEST),  4, 0L, &SESTdma );
-//               sizeof(TachSEST),  64*TACH_SEST_LEN, 0L );
-  if( !fcChip->SEST )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("pci_alloc_consistent/alignment failure on SEST: fatal error\n");
-    return -1;
-  }
-
-  for( i=0; i < TACH_SEST_LEN; i++)  // for each exchange
-      fcChip->SEST->sgPages[i] = NULL;
-
-  fcChip->SEST->length = TACH_SEST_LEN;  // e.g. DON'T subtract one 
-                                       // (TL/TS UG, pg 153)
-
-  ulAddr = SESTdma; 
-#if BITS_PER_LONG > 32
-  if( (ulAddr >> 32) )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n",
-                   (void*)ulAddr);
-    return -1;  // failed
-  }
-#endif
-  fcChip->SEST->base = (ULONG)ulAddr;  // copy for quick reference
-
-
-                             // Now that structures are defined,
-                             // fill in Tachyon chip registers...
-
-                             // EEEEEEEE  EXCHANGE REQUEST QUEUE
-
-  writel( fcChip->ERQ->base, 
-    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
-      
-  writel( fcChip->ERQ->length,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_LENGTH));
-     
-
-  fcChip->ERQ->producerIndex = 0L;
-  writel( fcChip->ERQ->producerIndex,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX));
-      
-
-               // NOTE! write consumer index last, since the write
-               // causes Tachyon to process the other registers
-
-  ulAddr = ((unsigned long)&fcChip->ERQ->consumerIndex - 
-               (unsigned long)fcChip->ERQ) + (unsigned long) ERQdma;
-
-  // NOTE! Tachyon DMAs to the ERQ consumer Index host
-               // address; must be correctly aligned
-  writel( (ULONG)ulAddr,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_CONSUMER_INDEX_ADR));
-
-
-
-                                // IIIIIIIIIIIII  INBOUND MESSAGE QUEUE
-                                // Tell Tachyon where the Que starts
-
-  // set the Host's pointer for Tachyon to access
-
-  /* printk("  cpqfcTS: writing IMQ BASE %Xh  ", fcChip->IMQ->base ); */
-  writel( fcChip->IMQ->base, 
-    (fcChip->Registers.ReMapMemBase + IMQ_BASE));
-
-  writel( fcChip->IMQ->length,
-    (fcChip->Registers.ReMapMemBase + IMQ_LENGTH));
-
-  writel( fcChip->IMQ->consumerIndex,
-    (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
-
-
-               // NOTE: TachLite DMAs to the producerIndex host address
-               // must be correctly aligned with address bits 1-0 cleared
-    // Writing the BASE register clears the PI register, so write it last
-  ulAddr = ((unsigned long)&fcChip->IMQ->producerIndex - 
-               (unsigned long)fcChip->IMQ) + (unsigned long) IMQdma;
-
-#if BITS_PER_LONG > 32
-  if( (ulAddr >> 32) )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n",
-                   (void*)ulAddr);
-    return -1;  // failed
-  }
-#endif
-#if DBG
-  printk("  PI %Xh\n", (ULONG)ulAddr );
-#endif
-  writel( (ULONG)ulAddr, 
-    (fcChip->Registers.ReMapMemBase + IMQ_PRODUCER_INDEX));
-
-
-
-                                // SSSSSSSSSSSSSSS SINGLE FRAME SEQUENCE
-                                // Tell TachLite where the Que starts
-
-  writel( fcChip->SFQ->base, 
-    (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_BASE));
-
-  writel( fcChip->SFQ->length,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_LENGTH));
-
-
-         // tell TachLite where SEST table is & how long
-  writel( fcChip->SEST->base,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE));
-
-  /* printk("  cpqfcTS: SEST %p(virt): Wrote base %Xh @ %p\n",
-    fcChip->SEST, fcChip->SEST->base, 
-    fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE); */
-
-  writel( fcChip->SEST->length,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_LENGTH));
-      
-  writel( (TL_EXT_SG_PAGE_COUNT-1),
-    (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_SG_PAGE));
-
-
-  LEAVE("CreateTachLiteQues");
-
-  return iStatus;
-}
-
-
-
-// function to return TachLite to Power On state
-// 1st - reset tachyon ('SOFT' reset)
-// others - future
-
-int CpqTsResetTachLite(void *pHBA, int type)
-{
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  ULONG ulBuff, i;
-  int ret_status=0; // def. success
-
-  ENTER("ResetTach");
-  
-  switch(type)
-  {
-
-    case CLEAR_FCPORTS:
-
-      // in case he was running previously, mask Tach's interrupt
-      writeb( 0, (fcChip->Registers.ReMapMemBase + IINTEN));
-      
-     // de-allocate mem for any Logged in ports
-      // (e.g., our module is unloading)
-      // search the forward linked list, de-allocating
-      // the memory we allocated when the port was initially logged in
-      {
-        PFC_LOGGEDIN_PORT pLoggedInPort = fcChip->fcPorts.pNextPort;
-        PFC_LOGGEDIN_PORT ptr;
-//        printk("checking for allocated LoggedInPorts...\n");
-                       
-        while( pLoggedInPort )
-        {
-          ptr = pLoggedInPort;
-          pLoggedInPort = ptr->pNextPort;
-//       printk("kfree(%p) on FC LoggedInPort port_id 0x%06lX\n",
-//                       ptr, ptr->port_id);
-          kfree( ptr );
-        }
-      }
-      // (continue resetting hardware...)
-
-    case 1:                   // RESTART Tachyon (power-up state)
-
-      // in case he was running previously, mask Tach's interrupt
-      writeb( 0, (fcChip->Registers.ReMapMemBase + IINTEN));
-                             // turn OFF laser (NOTE: laser is turned
-                              // off during reset, because GPIO4 is cleared
-                              // to 0 by reset action - see TLUM, sec 7.22)
-                              // However, CPQ 64-bit HBAs have a "health
-                              // circuit" which keeps laser ON for a brief
-                              // period after it is turned off ( < 1s)
-      
-      fcChip->LaserControl( fcChip->Registers.ReMapMemBase, 0);
-  
-
-
-            // soft reset timing constraints require:
-            //   1. set RST to 1
-            //   2. read SOFTRST register 
-            //      (128 times per R. Callison code)
-            //   3. clear PCI ints
-            //   4. clear RST to 0
-      writel( 0xff000001L,
-        (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
-        
-      for( i=0; i<128; i++)
-        ulBuff = readl( fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST);
-
-        // clear the soft reset
-      for( i=0; i<8; i++)
-       writel( 0, (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
-
-               
-
-                              // clear out our copy of Tach regs,
-                              // because they must be invalid now,
-                              // since TachLite reset all his regs.
-      CpqTsDestroyTachLiteQues(cpqfcHBAdata,0); // remove Host-based Que structs
-      cpqfcTSClearLinkStatusCounters(fcChip);  // clear our s/w accumulators
-                               // lower bits give GBIC info
-      fcChip->Registers.TYstatus.value = 
-                     readl( fcChip->Registers.TYstatus.address );
-      break;
-
-/*
-    case 2:                   // freeze SCSI
-    case 3:                   // reset Outbound command que (ERQ)
-    case 4:                   // unfreeze OSM (Outbound Seq. Man.) 'er'
-    case 5:                   // report status
-
-    break;
-*/
-    default:
-      ret_status = -1;  // invalid option passed to RESET function
-      break;
-  }
-  LEAVE("ResetTach");
-  return ret_status;
-}
-
-
-
-
-
-
-// 'addrBase' is IOBaseU for both TachLite and (older) Tachyon
-int CpqTsLaserControl( void* addrBase, int opcode )
-{
-  ULONG dwBuff;
-
-  dwBuff = readl((addrBase + TL_MEM_TACH_CONTROL) ); // read TL Control reg
-                                                    // (change only bit 4)
-  if( opcode == 1)
-    dwBuff |= ~0xffffffefL; // set - ON
-  else
-    dwBuff &= 0xffffffefL;  // clear - OFF
-  writel( dwBuff, (addrBase + TL_MEM_TACH_CONTROL)); // write TL Control reg
-  return 0;
-}
-
-
-
-
-
-// Use controller's "Options" field to determine loopback mode (if any)
-//   internal loopback (silicon - no GBIC)
-//   external loopback (GBIC - no FC loop)
-//   no loopback: L_PORT, external cable from GBIC required
-
-int CpqTsInitializeFrameManager( void *pChip, int opcode)
-{
-  PTACHYON fcChip;
-  int iStatus;
-  ULONG wwnLo, wwnHi; // for readback verification
-
-  ENTER("InitializeFrameManager");
-  fcChip = (PTACHYON)pChip;
-  if( !fcChip->Registers.ReMapMemBase )   // undefined controller?
-    return -1;
-
-  // TL/TS UG, pg. 184
-  // 0x0065 = 100ms for RT_TOV
-  // 0x01f5 = 500ms for ED_TOV
-  // 0x07D1 = 2000ms 
-  fcChip->Registers.ed_tov.value = 0x006507D1; 
-  writel( fcChip->Registers.ed_tov.value,
-    (fcChip->Registers.ed_tov.address));
-      
-
-  // Set LP_TOV to the FC-AL2 specified 2 secs.
-  // TL/TS UG, pg. 185
-  writel( 0x07d00010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
-
-
-  // Now try to read the WWN from the adapter's NVRAM
-  iStatus = CpqTsReadWriteWWN( fcChip, 1); // '1' for READ
-
-  if( iStatus )   // NVRAM read failed?
-  {
-    printk(" WARNING! HBA NVRAM WWN read failed - make alias\n");
-    // make up a WWN.  If NULL or duplicated on loop, FC loop may hang!
-
-
-    fcChip->Registers.wwn_hi = (__u32)jiffies;
-    fcChip->Registers.wwn_hi |= 0x50000000L;
-    fcChip->Registers.wwn_lo = 0x44556677L;
-  }
-
-  
-  writel( fcChip->Registers.wwn_hi, 
-         fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI);
-  
-  writel( fcChip->Registers.wwn_lo, 
-         fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
-         
-
-  // readback for verification:
-  wwnHi = readl( fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI ); 
-          
-  wwnLo = readl( fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
-  // test for correct chip register WRITE/READ
-  DEBUG_PCI( printk("  WWN %08X%08X\n",
-    fcChip->Registers.wwn_hi, fcChip->Registers.wwn_lo ) );
-    
-  if( wwnHi != fcChip->Registers.wwn_hi ||
-      wwnLo != fcChip->Registers.wwn_lo )
-  {
-    printk( "cpqfcTS: WorldWideName register load failed\n");
-    return -1; // FAILED!
-  }
-
-
-
-                       // set Frame Manager Initialize command
-  fcChip->Registers.FMcontrol.value = 0x06;
-
-  // Note: for test/debug purposes, we may use "Hard" address,
-  // but we completely support "soft" addressing, including
-  // dynamically changing our address.
-  if( fcChip->Options.intLoopback == 1 )            // internal loopback
-    fcChip->Registers.FMconfig.value = 0x0f002080L;
-  else if( fcChip->Options.extLoopback == 1 )            // internal loopback
-    fcChip->Registers.FMconfig.value = 0x0f004080L;
-  else                  // L_Port
-    fcChip->Registers.FMconfig.value = 0x55000100L; // hard address (55h start)
-//    fcChip->Registers.FMconfig.value = 0x01000080L; // soft address (can't pick)
-//    fcChip->Registers.FMconfig.value = 0x55000100L; // hard address (55h start)
-               
-  // write config to FM
-
-  if( !fcChip->Options.intLoopback && !fcChip->Options.extLoopback )
-                               // (also need LASER for real LOOP)
-    fcChip->LaserControl( fcChip->Registers.ReMapMemBase, 1); // turn on LASER
-
-  writel( fcChip->Registers.FMconfig.value,
-    fcChip->Registers.FMconfig.address);
-    
-
-                              // issue INITIALIZE command to FM - ACTION!
-  writel( fcChip->Registers.FMcontrol.value,
-    fcChip->Registers.FMcontrol.address);
-    
-  LEAVE("InitializeFrameManager");
-  
-  return 0;
-}
-
-
-
-
-
-// This "look ahead" function examines the IMQ for occurrence of
-// "type".  Returns 1 if found, 0 if not.
-static int PeekIMQEntry( PTACHYON fcChip, ULONG type)
-{
-  ULONG CI = fcChip->IMQ->consumerIndex;
-  ULONG PI = fcChip->IMQ->producerIndex; // snapshot of IMQ indexes
-  
-  while( CI != PI )
-  {                             // proceed with search
-    if( (++CI) >= IMQ_LEN ) CI = 0; // rollover check
-    
-    switch( type )
-    {
-      case ELS_LILP_FRAME:
-      {
-      // first, we need to find an Inbound Completion message,
-      // If we find it, check the incoming frame payload (1st word)
-      // for LILP frame
-        if( (fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x104 )
-        { 
-          TachFCHDR_GCMND* fchs;
-#error This is too much stack
-          ULONG ulFibreFrame[2048/4];  // max DWORDS in incoming FC Frame
-         USHORT SFQpi = (USHORT)(fcChip->IMQ->QEntry[CI].word[0] & 0x0fffL);
-
-         CpqTsGetSFQEntry( fcChip,
-            SFQpi,        // SFQ producer ndx         
-           ulFibreFrame, // contiguous dest. buffer
-           FALSE);       // DON'T update chip--this is a "lookahead"
-          
-         fchs = (TachFCHDR_GCMND*)&ulFibreFrame;
-          if( fchs->pl[0] == ELS_LILP_FRAME)
-         {
-            return 1; // found the LILP frame!
-         }
-         else
-         {
-           // keep looking...
-         }
-       }  
-      }
-      break;
-
-      case OUTBOUND_COMPLETION:
-        if( (fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x00 )
-       {
-
-          // any OCM errors?
-          if( fcChip->IMQ->QEntry[CI].word[2] & 0x7a000000L )
-            return 1;              // found OCM error
-       }
-      break;
-
-
-      
-      default:
-      break;
-    }
-  }
-  return 0; // failed to find "type"
-}
-
-                       
-static void SetTachTOV( CPQFCHBA* cpqfcHBAdata)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip; 
-  
-  // TL/TS UG, pg. 184
-  // 0x0065 = 100ms for RT_TOV
-  // 0x01f5 = 500ms for ED_TOV
-  // 0x07d1 = 2000ms for ED_TOV
-
-  // SANMark Level 1 requires an "initialization backoff"
-  // (See "SANMark Test Suite Level 1":
-  // initialization_timeout.fcal.SANMark-1.fc)
-  // We have to use 2sec, 24sec, then 128sec when login/
-  // port discovery processes fail to complete.
-  
-  // when port discovery completes (logins done), we set
-  // ED_TOV to 500ms -- this is the normal operational case
-  // On the first Link Down, we'll move to 2 secs (7D1 ms)
-  if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x1f5)
-    fcChip->Registers.ed_tov.value = 0x006507D1; 
-  
-  // If we get another LST after we moved TOV to 2 sec,
-  // increase to 24 seconds (5DC1 ms) per SANMark!
-  else if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x7D1)
-    fcChip->Registers.ed_tov.value = 0x00655DC1; 
-
-  // If we get still another LST, set the max TOV (Tachyon
-  // has only 16 bits for ms timer, so the max is 65.5 sec)
-  else if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x5DC1)
-    fcChip->Registers.ed_tov.value = 0x0065FFFF; 
-
-  writel( fcChip->Registers.ed_tov.value,
-    (fcChip->Registers.ed_tov.address));
-  // keep the same 2sec LP_TOV 
-  writel( 0x07D00010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
-}      
-
-
-// The IMQ is an array with IMQ_LEN length, each element (QEntry)
-// with eight 32-bit words.  Tachyon PRODUCES a QEntry with each
-// message it wants to send to the host.  The host CONSUMES IMQ entries
-
-// This function copies the current
-// (or oldest not-yet-processed) QEntry to
-// the caller, clears/ re-enables the interrupt, and updates the
-// (Host) Consumer Index.
-// Return value:
-//  0   message processed, none remain (producer and consumer
-//        indexes match)
-//  1   message processed, more messages remain
-// -1   no message processed - none were available to process
-// Remarks:
-//   TL/TS UG specifices that the following actions for
-//   INTA_L handling:
-//   1. read PCI Interrupt Status register (0xff)
-//   2. all IMQ messages should be processed before writing the
-//      IMQ consumer index.
-
-
-int CpqTsProcessIMQEntry(void *host)
-{
-  struct Scsi_Host *HostAdapter = (struct Scsi_Host *)host;
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip; 
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  int iStatus;
-  USHORT i, RPCset, DPCset;
-  ULONG x_ID;
-  ULONG ulBuff, dwStatus;
-  TachFCHDR_GCMND* fchs;
-#error This is too much stack
-  ULONG ulFibreFrame[2048/4];  // max number of DWORDS in incoming Fibre Frame
-  UCHAR ucInboundMessageType;  // Inbound CM, dword 3 "type" field
-
-  ENTER("ProcessIMQEntry");
-   
-
-                               // check TachLite's IMQ producer index -
-                               // is a new message waiting for us?
-                               // equal indexes means empty que
-
-  if( fcChip->IMQ->producerIndex != fcChip->IMQ->consumerIndex )
-  {                             // need to process message
-
-
-#ifdef IMQ_DEBUG
-    printk("PI %X, CI %X  type: %X\n", 
-      fcChip->IMQ->producerIndex,fcChip->IMQ->consumerIndex,
-      fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type);
-#endif                                
-    // Examine Completion Messages in IMQ
-    // what CM_Type?
-    switch( (UCHAR)(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type
-                    & 0xffL) )
-    {
-    case OUTBOUND_COMPLETION:
-
-      // Remarks:
-      // x_IDs (OX_ID, RX_ID) are partitioned by SEST entries
-      // (starting at 0), and SFS entries (starting at
-      // SEST_LEN -- outside the SEST space).
-      // Psuedo code:
-      // x_ID (OX_ID or RX_ID) from message is Trans_ID or SEST index
-      // range check - x_ID
-      //   if x_ID outside 'Transactions' length, error - exit
-      // if any OCM error, copy error status to Exchange slot
-      // if FCP ASSIST transaction (x_ID within SEST),
-      //   call fcComplete (to App)
-      // ...
-
-
-      ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1];
-      x_ID = ulBuff & 0x7fffL;     // lower 14 bits SEST_Index/Trans_ID
-                                     // Range check CM OX/RX_ID value...
-      if( x_ID < TACH_MAX_XID )   // don't go beyond array space
-      {
-
-
-       if( ulBuff & 0x20000000L ) // RPC -Response Phase Complete?
-          RPCset = 1;              // (SEST transactions only)
-        else
-          RPCset = 0;
-
-        if( ulBuff & 0x40000000L ) // DPC -Data Phase Complete?
-          DPCset = 1;              // (SEST transactions only)
-        else
-          DPCset = 0;
-                // set the status for this Outbound transaction's ID
-        dwStatus = 0L;
-        if( ulBuff & 0x10000000L ) // SPE? (SEST Programming Error)
-            dwStatus |= SESTPROG_ERR;
-
-        ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2];
-        if( ulBuff & 0x7a000000L ) // any other errs?
-        {
-          if( ulBuff & 0x40000000L )
-            dwStatus |= INV_ENTRY;
-          if( ulBuff & 0x20000000L )
-            dwStatus |= FRAME_TO;        // FTO
-          if( ulBuff & 0x10000000L )
-            dwStatus |= HOSTPROG_ERR;
-          if( ulBuff & 0x08000000L )
-            dwStatus |= LINKFAIL_TX;
-          if( ulBuff & 0x02000000L )
-            dwStatus |= ABORTSEQ_NOTIFY;  // ASN
-        }
-
-         
-       if( dwStatus )          // any errors?
-        {
-                  // set the Outbound Completion status
-          Exchanges->fcExchange[ x_ID ].status |= dwStatus;
-
-          // if this Outbound frame was for a SEST entry, automatically
-          // reque it in the case of LINKFAIL (it will restart on PDISC)
-          if( x_ID < TACH_SEST_LEN )
-          {
-
-            printk(" #OCM error %Xh x_ID %X# ", 
-                   dwStatus, x_ID);
-
-           Exchanges->fcExchange[x_ID].timeOut = 30000; // seconds default
-                                                 
-
-           // We Q ABTS for each exchange.
-           // NOTE: We can get FRAME_TO on bad alpa (device gone).  Since
-           // bad alpa is reported before FRAME_TO, examine the status
-           // flags to see if the device is removed.  If so, DON'T
-           // post an ABTS, since it will be terminated by the bad alpa
-           // message.
-           if( dwStatus & FRAME_TO ) // check for device removed...
-           {
-             if( !(Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED) )
-             { 
-               // presumes device is still there: send ABTS.
-  
-                cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
-             }
-           }
-           else  // Abort all other errors
-           {
-              cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
-           }
-
-            // if the HPE bit is set, we have to CLose the LOOP
-            // (see TL/TS UG, pg. 239)
-
-            if( dwStatus &= HOSTPROG_ERR )
-            // set CL bit (see TL/TS UG, pg. 172)
-              writel( 4, fcChip->Registers.FMcontrol.address);
-          }
-        }
-          // NOTE: we don't necessarily care about ALL completion messages...
-                                      // SCSI resp. complete OR
-        if( ((x_ID < TACH_SEST_LEN) && RPCset)|| 
-             (x_ID >= TACH_SEST_LEN) )  // non-SCSI command
-        {
-              // exchange done; complete to upper levels with status
-              // (if necessary) and free the exchange slot
-            
-
-          if( x_ID >= TACH_SEST_LEN ) // Link Service Outbound frame?
-                                    // A Request or Reply has been sent
-          {                         // signal waiting WorkerThread
-
-            up( cpqfcHBAdata->TYOBcomplete);   // frame is OUT of Tach
-
-                                    // WorkerThread will complete Xchng
-          }
-          else  // X_ID is for FCP assist (SEST)
-          {
-              // TBD (target mode)
-//            fcCompleteExchange( fcChip, x_ID); // TRE completed
-          }
-        }
-      }
-      else  // ERROR CONDITION!  bogus x_ID in completion message
-      {
-
-        printk(" ProcessIMQ (OBCM) x_id out of range %Xh\n", x_ID);
-
-      }
-
-
-
-          // Load the Frame Manager's error counters.  We check them here
-          // because presumably the link is up and healthy enough for the
-          // counters to be meaningful (i.e., don't check them while loop
-          // is initializing).
-      fcChip->Registers.FMLinkStatus1.value =    // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus1.address);
-                  
-      fcChip->Registers.FMLinkStatus2.value =    // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus2.address);
-            
-
-      fcParseLinkStatusCounters( fcChip); // load into 6 s/w accumulators
-    break;
-
-
-
-    case ERROR_IDLE_COMPLETION:  // TachLite Error Idle...
-    
-    // We usually get this when the link goes down during heavy traffic.
-    // For now, presume that if SEST Exchanges are open, we will
-    // get this as our cue to INVALIDATE all SEST entries
-    // (and we OWN all the SEST entries).
-    // See TL/TS UG, pg. 53
-    
-      for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
-      {
-
-        // Does this VALid SEST entry need to be invalidated for Abort?
-        fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF; 
-      }
-      
-      CpqTsUnFreezeTachlite( fcChip, 2); // unfreeze Tachyon, if Link OK
-
-    break;
-
-
-    case INBOUND_SFS_COMPLETION:  //0x04
-          // NOTE! we must process this SFQ message to avoid SFQ filling
-          // up and stopping TachLite.  Incoming commands are placed here,
-          // as well as 'unknown' frames (e.g. LIP loop position data)
-          // write this CM's producer index to global...
-          // TL/TS UG, pg 234:
-          // Type: 0 - reserved
-          //       1 - Unassisted FCP
-          //       2 - BAD FCP
-          //       3 - Unkown Frame
-          //       4-F reserved
-
-
-      fcChip->SFQ->producerIndex = (USHORT)
-        (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] & 0x0fffL);
-
-
-      ucInboundMessageType = 0;  // default to useless frame
-
-        // we can only process two Types: 1, Unassisted FCP, and 3, Unknown
-        // Also, we aren't interested in processing frame fragments
-        // so don't Que anything with 'LKF' bit set
-      if( !(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] 
-        & 0x40000000) )  // 'LKF' link failure bit clear?
-      {
-        ucInboundMessageType = (UCHAR)  // ICM DWord3, "Type"
-        (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] & 0x0fL);
-      }
-      else
-      {
-       fcChip->fcStats.linkFailRX++;
-//        printk("LKF (link failure) bit set on inbound message\n");
-      }
-
-          // clears SFQ entry from Tachyon buffer; copies to contiguous ulBuff
-      CpqTsGetSFQEntry(
-        fcChip,                  // i.e. this Device Object
-        (USHORT)fcChip->SFQ->producerIndex,  // SFQ producer ndx         
-        ulFibreFrame, TRUE);    // contiguous destination buffer, update chip
-                     
-        // analyze the incoming frame outside the INT handler...
-        // (i.e., Worker)
-
-      if( ucInboundMessageType == 1 )
-      {
-        fchs = (TachFCHDR_GCMND*)ulFibreFrame; // cast to examine IB frame
-        // don't fill up our Q with garbage - only accept FCP-CMND  
-        // or XRDY frames
-        if( (fchs->d_id & 0xFF000000) == 0x06000000 ) // CMND
-        {
-         // someone sent us a SCSI command
-         
-//          fcPutScsiQue( cpqfcHBAdata, 
-//                        SFQ_UNASSISTED_FCP, ulFibreFrame); 
-       }
-       else if( ((fchs->d_id & 0xFF000000) == 0x07000000) || // RSP (status)
-            (fchs->d_id & 0xFF000000) == 0x05000000 )  // XRDY  
-       {
-         ULONG x_ID;
-         // Unfortunately, ABTS requires a Freeze on the chip so
-         // we can modify the shared memory SEST.  When frozen,
-         // any received Exchange frames cannot be processed by
-         // Tachyon, so they will be dumped in here.  It is too
-         // complex to attempt the reconstruct these frames in
-         // the correct Exchange context, so we simply seek to
-         // find status or transfer ready frames, and cause the
-         // exchange to complete with errors before the timeout
-         // expires.  We use a Linux Scsi Cmnd result code that
-         // causes immediate retry.
-         
-
-         // Do we have an open exchange that matches this s_id
-         // and ox_id?
-         for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
-         {
-            if( (fchs->s_id & 0xFFFFFF) == 
-                 (Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF) 
-                      &&
-                (fchs->ox_rx_id & 0xFFFF0000) == 
-                 (Exchanges->fcExchange[x_ID].fchs.ox_rx_id & 0xFFFF0000) )
-           {
-    //          printk(" #R/X frame x_ID %08X# ", fchs->ox_rx_id );
-              // simulate the anticipated error - since the
-             // SEST was frozen, frames were lost...
-              Exchanges->fcExchange[ x_ID ].status |= SFQ_FRAME;
-              
-             // presumes device is still there: send ABTS.
-              cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
-             break;  // done
-           }
-         }
-       }
-         
-      }
-          
-      else if( ucInboundMessageType == 3)
-      {
-        // FC Link Service frames (e.g. PLOGI, ACC) come in here.  
-        cpqfcTSPutLinkQue( cpqfcHBAdata, SFQ_UNKNOWN, ulFibreFrame); 
-                          
-      }
-
-      else if( ucInboundMessageType == 2 ) // "bad FCP"?
-      {
-#ifdef IMQ_DEBUG
-        printk("Bad FCP incoming frame discarded\n");
-#endif
-      }
-
-      else // don't know this type
-      {
-#ifdef IMQ_DEBUG 
-        printk("Incoming frame discarded, type: %Xh\n", ucInboundMessageType);
-#endif
-      }
-        
-        // Check the Frame Manager's error counters.  We check them here
-        // because presumably the link is up and healthy enough for the
-        // counters to be meaningful (i.e., don't check them while loop
-        // is initializing).
-      fcChip->Registers.FMLinkStatus1.value =    // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus1.address);
-                  
-
-      fcChip->Registers.FMLinkStatus2.value =    // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus2.address);
-                
-
-      break;
-
-
-
-
-                    // We get this CM because we issued a freeze
-                    // command to stop outbound frames.  We issue the
-                    // freeze command at Link Up time; when this message
-                    // is received, the ERQ base can be switched and PDISC
-                    // frames can be sent.
-
-      
-    case ERQ_FROZEN_COMPLETION:  // note: expect ERQ followed immediately
-                                 // by FCP when freezing TL
-      fcChip->Registers.TYstatus.value =         // read what's frozen
-        readl(fcChip->Registers.TYstatus.address);
-      // (do nothing; wait for FCP frozen message)
-      break;
-    case FCP_FROZEN_COMPLETION:
-      
-      fcChip->Registers.TYstatus.value =         // read what's frozen
-        readl(fcChip->Registers.TYstatus.address);
-      
-      // Signal the kernel thread to proceed with SEST modification
-      up( cpqfcHBAdata->TachFrozen);
-
-      break;
-
-
-
-    case INBOUND_C1_TIMEOUT:
-    case MFS_BUF_WARN:
-    case IMQ_BUF_WARN:
-    break;
-
-
-
-
-
-        // In older Tachyons, we 'clear' the internal 'core' interrupt state
-        // by reading the FMstatus register.  In newer TachLite (Tachyon),
-        // we must WRITE the register
-        // to clear the condition (TL/TS UG, pg 179)
-    case FRAME_MGR_INTERRUPT:
-    {
-      PFC_LOGGEDIN_PORT pLoggedInPort; 
-
-      fcChip->Registers.FMstatus.value = 
-        readl( fcChip->Registers.FMstatus.address );
-                
-      // PROBLEM: It is possible, especially with "dumb" hubs that
-      // don't automatically LIP on by-pass of ports that are going
-      // away, for the hub by-pass process to destroy critical 
-      // ordered sets of a frame.  The result of this is a hung LPSM
-      // (Loop Port State Machine), which on Tachyon results in a
-      // (default 2 sec) Loop State Timeout (LST) FM message.  We 
-      // want to avoid this relatively huge timeout by detecting
-      // likely scenarios which will result in LST.
-      // To do this, we could examine FMstatus for Loss of Synchronization
-      // and/or Elastic Store (ES) errors.  Of these, Elastic Store is better
-      // because we get this indication more quickly than the LOS.
-      // Not all ES errors are harmfull, so we don't want to LIP on every
-      // ES.  Instead, on every ES, detect whether our LPSM in in one
-      // of the LST states: ARBITRATING, OPEN, OPENED, XMITTED CLOSE,
-      // or RECEIVED CLOSE.  (See TL/TS UG, pg. 181)
-      // If any of these LPSM states are detected
-      // in combination with the LIP while LDn is not set, 
-      // send an FM init (LIP F7,F7 for loops)!
-      // It is critical to the physical link stability NOT to reset (LIP)
-      // more than absolutely necessary; this is a basic premise of the
-      // SANMark level 1 spec.
-      {
-       ULONG Lpsm = (fcChip->Registers.FMstatus.value & 0xF0) >>4;
-       
-       if( (fcChip->Registers.FMstatus.value & 0x400)  // ElasticStore?
-                      &&
-            !(fcChip->Registers.FMstatus.value & 0x100) // NOT LDn
-                     &&
-            !(fcChip->Registers.FMstatus.value & 0x1000)) // NOT LF
-       {
-         if( (Lpsm != 0) || // not MONITORING? or
-             !(Lpsm & 0x8) )// not already offline?
-         {
-         // now check the particular LST states...
-            if( (Lpsm == ARBITRATING) || (Lpsm == OPEN) ||
-             (Lpsm == OPENED)      || (Lpsm == XMITTD_CLOSE) ||
-             (Lpsm == RCVD_CLOSE) )
-           {
-             // re-init the loop before it hangs itself!
-              printk(" #req FMinit on E-S: LPSM %Xh# ",Lpsm);
-
-
-             fcChip->fcStats.FMinits++;
-              writel( 6, fcChip->Registers.FMcontrol.address); // LIP
-           }
-         }
-       }
-       else if( fcChip->Registers.FMstatus.value & 0x40000 ) // LST?
-       {
-          printk(" #req FMinit on LST, LPSM %Xh# ",Lpsm);
-        
-          fcChip->fcStats.FMinits++;
-          writel( 6, fcChip->Registers.FMcontrol.address);  // LIP
-       }  
-      }
-
-
-      // clear only the 'interrupting' type bits for this REG read
-      writel( (fcChip->Registers.FMstatus.value & 0xff3fff00L),
-        fcChip->Registers.FMstatus.address);
-                          
-
-               // copy frame manager status to unused ULONG slot
-      fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] =
-          fcChip->Registers.FMstatus.value; // (for debugging)
-
-
-          // Load the Frame Manager's error counters.  We check them here
-          // because presumably the link is up and healthy enough for the
-          // counters to be meaningful (i.e., don't check them while loop
-          // is initializing).
-      fcChip->Registers.FMLinkStatus1.value =   // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus1.address);
-            
-      fcChip->Registers.FMLinkStatus2.value =   // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus2.address);
-          
-          // Get FM BB_Credit Zero Reg - does not clear on READ
-      fcChip->Registers.FMBB_CreditZero.value =   // get TL's counter
-        readl(fcChip->Registers.FMBB_CreditZero.address);
-            
-
-
-      fcParseLinkStatusCounters( fcChip); // load into 6 s/w accumulators
-
-
-               // LINK DOWN
-
-      if( fcChip->Registers.FMstatus.value & 0x100L ) // Link DOWN bit
-      {                                 
-       
-#ifdef IMQ_DEBUG
-        printk("LinkDn\n");
-#endif
-        printk(" #LDn# ");
-        
-        fcChip->fcStats.linkDown++;
-        
-       SetTachTOV( cpqfcHBAdata);  // must set according to SANMark
-
-       // Check the ERQ - force it to be "empty" to prevent Tach
-       // from sending out frames before we do logins.
-
-
-       if( fcChip->ERQ->producerIndex != fcChip->ERQ->consumerIndex)
-       {
-//       printk("#ERQ PI != CI#");
-          CpqTsFreezeTachlite( fcChip, 1); // freeze ERQ only    
-         fcChip->ERQ->producerIndex = fcChip->ERQ->consumerIndex = 0;
-         writel( fcChip->ERQ->base, 
-           (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
-          // re-writing base forces ERQ PI to equal CI
-  
-       }
-               
-       // link down transition occurred -- port_ids can change
-        // on next LinkUp, so we must invalidate current logins
-        // (and any I/O in progress) until PDISC or PLOGI/PRLI
-        // completes
-        {
-          pLoggedInPort = &fcChip->fcPorts; 
-          while( pLoggedInPort ) // for all ports which are expecting
-                                 // PDISC after the next LIP, set the
-                                 // logoutTimer
-          {
-
-           if( pLoggedInPort->pdisc) // expecting PDISC within 2 sec?
-            {
-              pLoggedInPort->LOGO_timer = 3;  // we want 2 seconds
-                                              // but Timer granularity
-                                              // is 1 second
-            }
-                                // suspend any I/O in progress until
-                                // PDISC received...
-            pLoggedInPort->prli = FALSE;   // block FCP-SCSI commands
-           
-            pLoggedInPort = pLoggedInPort->pNextPort;
-          }  // ... all Previously known ports checked
-        }
-        
-       // since any hot plugging device may NOT support LILP frames
-       // (such as early Tachyon chips), clear this flag indicating
-       // we shouldn't use (our copy of) a LILP map.
-       // If we receive an LILP frame, we'll set it again.
-       fcChip->Options.LILPin = 0; // our LILPmap is invalid
-        cpqfcHBAdata->PortDiscDone = 0; // must re-validate FC ports!
-
-          // also, we want to invalidate (i.e. INITIATOR_ABORT) any
-          // open Login exchanges, in case the LinkDown happened in the
-          // middle of logins.  It's possible that some ports already
-          // ACCepted login commands which we have not processed before
-          // another LinkDown occurred.  Any accepted Login exhanges are
-          // invalidated by LinkDown, even before they are acknowledged.
-          // It's also possible for a port to have a Queued Reply or Request
-          // for login which was interrupted by LinkDown; it may come later,
-          // but it will be unacceptable to us.
-
-          // we must scan the entire exchange space, find every Login type
-          // originated by us, and abort it. This is NOT an abort due to
-          // timeout, so we don't actually send abort to the other port -
-          // we just complete it to free up the fcExchange slot.
-
-        for( i=TACH_SEST_LEN; i< TACH_MAX_XID; i++)
-        {                     // looking for Extended Link Serv.Exchanges
-          if( Exchanges->fcExchange[i].type == ELS_PDISC ||
-              Exchanges->fcExchange[i].type == ELS_PLOGI ||
-              Exchanges->fcExchange[i].type == ELS_PRLI ) 
-          {
-              // ABORT the exchange!
-#ifdef IMQ_DEBUG
-            printk("Originator ABORT x_id %Xh, type %Xh, port_id %Xh on LDn\n",
-              i, Exchanges->fcExchange[i].type,
-            Exchanges->fcExchange[i].fchs.d_id);
-#endif
-
-            Exchanges->fcExchange[i].status |= INITIATOR_ABORT;
-            cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, i); // abort on LDn
-          }
-        }
-
-      }
-
-             // ################   LINK UP   ##################
-      if( fcChip->Registers.FMstatus.value & 0x200L ) // Link Up bit
-      {                                 // AL_PA could have changed
-
-          // We need the following code, duplicated from LinkDn condition,
-          // because it's possible for the Tachyon to re-initialize (hard
-          // reset) without ever getting a LinkDn indication.
-        pLoggedInPort = &fcChip->fcPorts; 
-        while( pLoggedInPort )   // for all ports which are expecting
-                                 // PDISC after the next LIP, set the
-                                 // logoutTimer
-        {
-          if( pLoggedInPort->pdisc) // expecting PDISC within 2 sec?
-          {
-            pLoggedInPort->LOGO_timer = 3;  // we want 2 seconds
-                                              // but Timer granularity
-                                              // is 1 second
-             
-                                  // suspend any I/O in progress until
-                                  // PDISC received...
-
-          }
-          pLoggedInPort = pLoggedInPort->pNextPort;
-        }  // ... all Previously known ports checked
-          // CpqTs acquired AL_PA in register AL_PA (ACQ_ALPA)
-        fcChip->Registers.rcv_al_pa.value = 
-          readl(fcChip->Registers.rcv_al_pa.address);
-       // Now, if our acquired address is DIFFERENT from our
-        // previous one, we are not allow to do PDISC - we
-        // must go back to PLOGI, which will terminate I/O in
-        // progress for ALL logged in FC devices...
-       // (This is highly unlikely).
-
-       if( (fcChip->Registers.my_al_pa & 0xFF) != 
-           ((fcChip->Registers.rcv_al_pa.value >> 16) &0xFF) )
-       {
-
-//       printk(" #our HBA port_id changed!# "); // FC port_id changed!!       
-
-         pLoggedInPort = &fcChip->fcPorts; 
-          while( pLoggedInPort ) // for all ports which are expecting
-                                 // PDISC after the next LIP, set the
-                                 // logoutTimer
-          {
-           pLoggedInPort->pdisc  = FALSE;
-            pLoggedInPort->prli = FALSE;
-            pLoggedInPort = pLoggedInPort->pNextPort;
-          }  // ... all Previously known ports checked
-
-         // when the port_id changes, we must terminate
-         // all open exchanges.
-          cpqfcTSTerminateExchange( cpqfcHBAdata, NULL, PORTID_CHANGED);
-
-       }
-                      
-       // Replace the entire 24-bit port_id.  We only know the
-       // lower 8 bits (alpa) from Tachyon; if a FLOGI is done,
-       // we'll get the upper 16-bits from the FLOGI ACC frame.
-       // If someone plugs into Fabric switch, we'll do FLOGI and
-       // get full 24-bit port_id; someone could then remove and
-       // hot-plug us into a dumb hub.  If we send a 24-bit PLOGI
-       // to a "private" loop device, it might blow up.
-       // Consequently, we force the upper 16-bits of port_id to
-       // be re-set on every LinkUp transition
-        fcChip->Registers.my_al_pa =
-          (fcChip->Registers.rcv_al_pa.value >> 16) & 0xFF;
-
-              
-              // copy frame manager status to unused ULONG slot
-        fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] =
-          fcChip->Registers.my_al_pa; // (for debugging)
-
-              // for TachLite, we need to write the acquired al_pa
-              // back into the FMconfig register, because after
-              // first initialization, the AQ (prev. acq.) bit gets
-              // set, causing TL FM to use the AL_PA field in FMconfig.
-              // (In Tachyon, FM writes the acquired AL_PA for us.)
-        ulBuff = readl( fcChip->Registers.FMconfig.address);
-        ulBuff &= 0x00ffffffL;  // mask out current al_pa
-        ulBuff |= ( fcChip->Registers.my_al_pa << 24 ); // or in acq. al_pa
-        fcChip->Registers.FMconfig.value = ulBuff; // copy it back
-        writel( fcChip->Registers.FMconfig.value,  // put in TachLite
-          fcChip->Registers.FMconfig.address);
-            
-
-#ifdef IMQ_DEBUG
-        printk("#LUp %Xh, FMstat 0x%08X#", 
-               fcChip->Registers.my_al_pa, fcChip->Registers.FMstatus.value);
-#endif
-
-              // also set the WRITE-ONLY My_ID Register (for Fabric
-              // initialization)
-        writel( fcChip->Registers.my_al_pa,
-          fcChip->Registers.ReMapMemBase +TL_MEM_TACH_My_ID);
-          
-
-        fcChip->fcStats.linkUp++;
-
-                                     // reset TL statistics counters
-                                     // (we ignore these error counters
-                                     // while link is down)
-        ulBuff =                     // just reset TL's counter
-                 readl( fcChip->Registers.FMLinkStatus1.address);
-          
-        ulBuff =                     // just reset TL's counter
-                 readl( fcChip->Registers.FMLinkStatus2.address);
-
-          // for initiator, need to start verifying ports (e.g. PDISC)
-
-
-
-         
-      
-      
-       CpqTsUnFreezeTachlite( fcChip, 2); // unfreeze Tachlite, if Link OK
-       
-       // Tachyon creates an interesting problem for us on LILP frames.
-       // Instead of writing the incoming LILP frame into the SFQ before
-       // indicating LINK UP (the actual order of events), Tachyon tells
-       // us LINK UP, and later us the LILP.  So we delay, then examine the
-       // IMQ for an Inbound CM (x04); if found, we can set
-       // LINKACTIVE after processing the LILP.  Otherwise, just proceed.
-       // Since Tachyon imposes this time delay (and doesn't tell us
-       // what it is), we have to impose a delay before "Peeking" the IMQ
-       // for Tach hardware (DMA) delivery.
-       // Processing LILP is required by SANMark
-       udelay( 1000);  // microsec delay waiting for LILP (if it comes)
-        if( PeekIMQEntry( fcChip, ELS_LILP_FRAME) )
-       {  // found SFQ LILP, which will post LINKACTIVE          
-//       printk("skipping LINKACTIVE post\n");
-
-       }
-       else
-          cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, ulFibreFrame);  
-      }
-
-
-
-      // ******* Set Fabric Login indication ********
-      if( fcChip->Registers.FMstatus.value & 0x2000 )
-      {
-       printk(" #Fabric# ");
-        fcChip->Options.fabric = 1;
-      }
-      else
-        fcChip->Options.fabric = 0;
-
-      
-      
-                             // ******* LIP(F8,x) or BAD AL_PA? ********
-      if( fcChip->Registers.FMstatus.value & 0x30000L )
-      {
-                        // copy the error AL_PAs
-        fcChip->Registers.rcv_al_pa.value = 
-          readl(fcChip->Registers.rcv_al_pa.address);
-            
-                        // Bad AL_PA?
-        if( fcChip->Registers.FMstatus.value & 0x10000L )
-        {
-          PFC_LOGGEDIN_PORT pLoggedInPort;
-        
-                       // copy "BAD" al_pa field
-          fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] =
-              (fcChip->Registers.rcv_al_pa.value & 0xff00L) >> 8;
-
-         pLoggedInPort = fcFindLoggedInPort( fcChip,
-            NULL,     // DON'T search Scsi Nexus
-            fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1], // port id
-            NULL,     // DON'T search linked list for FC WWN
-            NULL);    // DON'T care about end of list
-         if( pLoggedInPort )
-         {
-            // Just in case we got this BAD_ALPA because a device
-           // quietly disappeared (can happen on non-managed hubs such 
-           // as the Vixel Rapport 1000),
-           // do an Implicit Logout.  We never expect this on a Logged
-           // in port (but do expect it on port discovery).
-           // (As a reasonable alternative, this could be changed to 
-           // simply start the implicit logout timer, giving the device
-           // several seconds to "come back".)
-           // 
-           printk(" #BAD alpa %Xh# ",
-                  fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1]);
-            cpqfcTSImplicitLogout( cpqfcHBAdata, pLoggedInPort);
-         }
-        }
-                        // LIP(f8,x)?
-        if( fcChip->Registers.FMstatus.value & 0x20000L )
-        {
-                        // for debugging, copy al_pa field
-          fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] =
-              (fcChip->Registers.rcv_al_pa.value & 0xffL);
-                        // get the other port's al_pa
-                        // (one that sent LIP(F8,?) )
-        }
-      }
-
-                             // Elastic store err
-      if( fcChip->Registers.FMstatus.value & 0x400L )
-      {
-            // don't count e-s if loop is down!
-        if( !(USHORT)(fcChip->Registers.FMstatus.value & 0x80) )
-          fcChip->fcStats.e_stores++;
-          
-      }
-    }
-    break;
-
-
-    case INBOUND_FCP_XCHG_COMPLETION:  // 0x0C
-
-    // Remarks:
-    // On Tachlite TL/TS, we get this message when the data phase
-    // of a SEST inbound transfer is complete.  For example, if a WRITE command
-    // was received with OX_ID 0, we might respond with XFER_RDY with
-    // RX_ID 8001.  This would start the SEST controlled data phases.  When
-    // all data frames are received, we get this inbound completion. This means
-    // we should send a status frame to complete the status phase of the 
-    // FCP-SCSI exchange, using the same OX_ID,RX_ID that we used for data
-    // frames.
-    // See Outbound CM discussion of x_IDs
-    // Psuedo Code
-    //   Get SEST index (x_ID)
-    //     x_ID out of range, return (err condition)
-    //   set status bits from 2nd dword
-    //   free transactionID & SEST entry
-    //   call fcComplete with transactionID & status
-
-      ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0];
-      x_ID = ulBuff & 0x7fffL;  // lower 14 bits SEST_Index/Trans_ID
-                                // (mask out MSB "direction" bit)
-                                // Range check CM OX/RX_ID value...
-      if( x_ID < TACH_SEST_LEN )  // don't go beyond SEST array space
-      {
-
-//#define FCP_COMPLETION_DBG 1
-#ifdef FCP_COMPLETION_DBG
-        printk(" FCP_CM x_ID %Xh, status %Xh, Cmnd %p\n", 
-          x_ID, ulBuff, Exchanges->fcExchange[x_ID].Cmnd);
-#endif
-        if( ulBuff & 0x08000000L ) // RPC -Response Phase Complete - or -
-                                   // time to send response frame?
-          RPCset = 1;             // (SEST transaction)
-        else
-          RPCset = 0;
-                // set the status for this Inbound SCSI transaction's ID
-        dwStatus = 0L;
-        if( ulBuff & 0x70000000L ) // any errs?
-        {
-          
-          if( ulBuff & 0x40000000L )
-            dwStatus |= LINKFAIL_RX;
-          
-         if( ulBuff & 0x20000000L )
-            dwStatus |= COUNT_ERROR;
-          
-          if( ulBuff & 0x10000000L )
-            dwStatus |= OVERFLOW;
-        }
-      
-       
-         // FCP transaction done - copy status
-        Exchanges->fcExchange[ x_ID ].status = dwStatus;
-
-
-        // Did the exchange get an FCP-RSP response frame?
-        // (Note the little endian/big endian FC payload difference)
-
-        if( RPCset )             // SEST transaction Response frame rec'd
-        {
-         // complete the command in our driver...
-          cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev,fcChip, x_ID);
-
-        }  // end "RPCset"
-       
-        else  // ("target" logic)
-        {
-            // Tachlite says all data frames have been received - now it's time
-            // to analyze data transfer (successful?), then send a response 
-            // frame for this exchange
-
-          ulFibreFrame[0] = x_ID; // copy for later reference
-
-          // if this was a TWE, we have to send satus response
-          if( Exchanges->fcExchange[ x_ID].type == SCSI_TWE )
-         {
-//            fcPutScsiQue( cpqfcHBAdata, 
-//                NEED_FCP_RSP, ulFibreFrame);  // (ulFibreFrame not used here)
-         }
-        }
-      }
-      else  // ERROR CONDITION!  bogus x_ID in completion message
-      {
-        printk("IN FCP_XCHG: bad x_ID: %Xh\n", x_ID);
-      }
-
-    break;
-
-
-
-
-    case INBOUND_SCSI_DATA_COMMAND:
-    case BAD_SCSI_FRAME:
-    case INB_SCSI_STATUS_COMPLETION:
-    case BUFFER_PROCESSED_COMPLETION:
-    break;
-    }
-
-                                          // Tachyon is producing;
-                                          // we are consuming
-    fcChip->IMQ->consumerIndex++;             // increment OUR consumerIndex
-    if( fcChip->IMQ->consumerIndex >= IMQ_LEN)// check for rollover
-      fcChip->IMQ->consumerIndex = 0L;        // reset it
-
-
-    if( fcChip->IMQ->producerIndex == fcChip->IMQ->consumerIndex )
-    {                           // all Messages are processed -
-      iStatus = 0;              // no more messages to process
-
-    }
-    else
-      iStatus = 1;              // more messages to process
-
-    // update TachLite's ConsumerIndex... (clears INTA_L)
-    // NOTE: according to TL/TS UG, the 
-    // "host must return completion messages in sequential order".
-    // Does this mean one at a time, in the order received?  We
-    // presume so.
-
-    writel( fcChip->IMQ->consumerIndex,
-      (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
-                   
-#if IMQ_DEBUG
-    printk("Process IMQ: writing consumer ndx %d\n ", 
-      fcChip->IMQ->consumerIndex);
-    printk("PI %X, CI %X\n", 
-    fcChip->IMQ->producerIndex,fcChip->IMQ->consumerIndex );
-#endif
-  
-
-
-  }
-  else
-  {
-   // hmmm... why did we get interrupted/called with no message?
-    iStatus = -1;               // nothing to process
-#if IMQ_DEBUG
-    printk("Process IMQ: no message PI %Xh  CI %Xh", 
-      fcChip->IMQ->producerIndex,
-      fcChip->IMQ->consumerIndex);
-#endif
-  }
-
-  LEAVE("ProcessIMQEntry");
-  
-  return iStatus;
-}
-
-
-
-
-
-// This routine initializes Tachyon according to the following
-// options (opcode1):
-// 1 - RESTART Tachyon, simulate power on condition by shutting
-//     down laser, resetting the hardware, de-allocating all buffers;
-//     continue
-// 2 - Config Tachyon / PCI registers;
-//     continue
-// 3 - Allocating memory and setting Tachyon queues (write Tachyon regs);
-//     continue
-// 4 - Config frame manager registers, initialize, turn on laser
-//
-// Returns:
-//  -1 on fatal error
-//   0 on success
-
-int CpqTsInitializeTachLite( void *pHBA, int opcode1, int opcode2)
-{
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  ULONG ulBuff;
-  UCHAR bBuff;
-  int iStatus=-1;  // assume failure
-
-  ENTER("InitializeTachLite");
-
-  // verify board's base address (sanity check)
-
-  if( !fcChip->Registers.ReMapMemBase)                // NULL address for card?
-    return -1;                         // FATAL error!
-
-
-
-  switch( opcode1 )
-  {
-    case 1:       // restore hardware to power-on (hard) restart
-
-
-      iStatus = fcChip->ResetTachyon( 
-                 cpqfcHBAdata, opcode2); // laser off, reset hardware
-                                     // de-allocate aligned buffers
-
-
-/* TBD      // reset FC link Q (producer and consumer = 0)
-      fcLinkQReset(cpqfcHBAdata); 
-
-*/
-
-      if( iStatus )
-        break;
-
-    case 2:       // Config PCI/Tachyon registers
-      // NOTE: For Tach TL/TS, bit 31 must be set to 1.  For TS chips, a read
-      // of bit 31 indicates state of M66EN signal; if 1, chip may run at 
-      // 33-66MHz  (see TL/TS UG, pg 159)
-
-      ulBuff = 0x80000000;  // TachLite Configuration Register
-
-      writel( ulBuff, fcChip->Registers.TYconfig.address);
-//      ulBuff = 0x0147L;  // CpqTs PCI CFGCMD register
-//      WritePCIConfiguration( fcChip->Backplane.bus,
-//                           fcChip->Backplane.slot, TLCFGCMD, ulBuff, 4);
-//      ulBuff = 0x0L;  // test!
-//      ReadPCIConfiguration( fcChip->Backplane.bus,
-//                           fcChip->Backplane.slot, TLCFGCMD, &ulBuff, 4);
-
-      // read back for reference...
-      fcChip->Registers.TYconfig.value = 
-         readl( fcChip->Registers.TYconfig.address );
-
-      // what is the PCI bus width?
-      pci_read_config_byte( cpqfcHBAdata->PciDev,
-                                0x43, // PCIMCTR offset
-                                &bBuff);
-      
-      fcChip->Registers.PCIMCTR = bBuff;
-
-      // set string identifying the chip on the circuit board
-
-      fcChip->Registers.TYstatus.value =
-        readl( fcChip->Registers.TYstatus.address);
-      
-      {
-// Now that we are supporting multiple boards, we need to change
-// this logic to check for PCI vendor/device IDs...
-// for now, quick & dirty is simply checking Chip rev
-       
-       ULONG RevId = (fcChip->Registers.TYstatus.value &0x3E0)>>5;
-       UCHAR Minor = (UCHAR)(RevId & 0x3);
-       UCHAR Major = (UCHAR)((RevId & 0x1C) >>2);
-  
-       /* printk("  HBA Tachyon RevId %d.%d\n", Major, Minor); */
-       if( (Major == 1) && (Minor == 2) )
-        {
-         sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE66_TS12);
-
-       }
-       else if( (Major == 1) && (Minor == 3) )
-        {
-         sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE66_TS13);
-       }
-       else if( (Major == 2) && (Minor == 1) )
-        {
-         sprintf( cpqfcHBAdata->fcChip.Name, SAGILENT_XL2_21);
-       }
-       else
-         sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE_UNKNOWN);
-      }
-
-
-
-    case 3:       // allocate mem, set Tachyon Que registers
-      iStatus = CpqTsCreateTachLiteQues( cpqfcHBAdata, opcode2);
-
-      if( iStatus )
-        break;
-
-      // now that the Queues exist, Tach can DMA to them, so
-      // we can begin processing INTs
-      // INTEN register - enable INT (TachLite interrupt)
-      writeb( 0x1F, fcChip->Registers.ReMapMemBase + IINTEN);
-
-       // Fall through
-    case 4:       // Config Fame Manager, Init Loop Command, laser on
-
-                 // L_PORT or loopback
-                 // depending on Options
-      iStatus = CpqTsInitializeFrameManager( fcChip,0 );
-      if( iStatus )
-      {
-           // failed to initialize Frame Manager
-             break;
-      }
-
-    default:
-      break;
-  }
-  LEAVE("InitializeTachLite");
-  
-  return iStatus;
-}
-
-
-
-
-// Depending on the type of platform memory allocation (e.g. dynamic),
-// it's probably best to free memory in opposite order as it was allocated.
-// Order of allocation: see other function
-
-
-int CpqTsDestroyTachLiteQues( void *pHBA, int opcode)
-{
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  USHORT i, iStatus=0;
-  void* vPtr;  // mem Align manager sets this to the freed address on success
-  unsigned long ulPtr;  // for 64-bit pointer cast (e.g. Alpa machine)
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  PSGPAGES j, next;
-
-  ENTER("DestroyTachLiteQues");
-
-  if( fcChip->SEST )
-  {
-                // search out and free Pool for Extended S/G list pages
-
-    for( i=0; i < TACH_SEST_LEN; i++)  // for each exchange
-    {
-      // It's possible that extended S/G pages were allocated, mapped, and
-      // not cleared due to error conditions or O/S driver termination.
-      // Make sure they're all gone.
-      if (Exchanges->fcExchange[i].Cmnd != NULL) 
-       cpqfc_pci_unmap(cpqfcHBAdata->PciDev, Exchanges->fcExchange[i].Cmnd, 
-                       fcChip, i); // undo DMA mappings.
-
-      for (j=fcChip->SEST->sgPages[i] ; j != NULL ; j = next) {
-               next = j->next;
-               kfree(j);
-      }
-      fcChip->SEST->sgPages[i] = NULL;
-    }
-    ulPtr = (unsigned long)fcChip->SEST;
-    vPtr = fcMemManager( cpqfcHBAdata->PciDev, 
-                   &cpqfcHBAdata->dynamic_mem[0],
-                   0,0, (ULONG)ulPtr, NULL ); // 'free' mem
-    fcChip->SEST = 0L;  // null invalid ptr
-    if( !vPtr )
-    {
-      printk("SEST mem not freed\n");
-      iStatus = -1;
-    }
-  }
-
-  if( fcChip->SFQ )
-  {
-
-    ulPtr = (unsigned long)fcChip->SFQ;
-    vPtr = fcMemManager( cpqfcHBAdata->PciDev, 
-                   &cpqfcHBAdata->dynamic_mem[0],
-                   0,0, (ULONG)ulPtr, NULL ); // 'free' mem
-    fcChip->SFQ = 0L;  // null invalid ptr
-    if( !vPtr )
-    {
-      printk("SFQ mem not freed\n");
-      iStatus = -2;
-    }
-  }
-
-
-  if( fcChip->IMQ )
-  {
-      // clear Indexes to show empty Queue
-    fcChip->IMQ->producerIndex = 0;
-    fcChip->IMQ->consumerIndex = 0;
-
-    ulPtr = (unsigned long)fcChip->IMQ;
-    vPtr = fcMemManager( cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0],
-                   0,0, (ULONG)ulPtr, NULL ); // 'free' mem
-    fcChip->IMQ = 0L;  // null invalid ptr
-    if( !vPtr )
-    {
-      printk("IMQ mem not freed\n");
-      iStatus = -3;
-    }
-  }
-
-  if( fcChip->ERQ )         // release memory blocks used by the queues
-  {
-    ulPtr = (unsigned long)fcChip->ERQ;
-    vPtr = fcMemManager( cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0],
-                   0,0, (ULONG)ulPtr, NULL ); // 'free' mem
-    fcChip->ERQ = 0L;  // null invalid ptr
-    if( !vPtr )
-    {
-      printk("ERQ mem not freed\n");
-      iStatus = -4;
-    }
-  }
-    
-  // free up the primary EXCHANGES struct and Link Q
-  cpqfc_free_dma_consistent(cpqfcHBAdata);
-  
-  LEAVE("DestroyTachLiteQues");
-  
-  return iStatus;     // non-zero (failed) if any memory not freed
-}
-
-
-
-
-
-// The SFQ is an array with SFQ_LEN length, each element (QEntry)
-// with eight 32-bit words.  TachLite places incoming FC frames (i.e.
-// a valid FC frame with our AL_PA ) in contiguous SFQ entries
-// and sends a completion message telling the host where the frame is
-// in the que.
-// This function copies the current (or oldest not-yet-processed) QEntry to
-// a caller's contiguous buffer and updates the Tachyon chip's consumer index
-//
-// NOTE:
-//   An FC frame may consume one or many SFQ entries.  We know the total
-//   length from the completion message.  The caller passes a buffer large
-//   enough for the complete message (max 2k).
-
-static void CpqTsGetSFQEntry(
-         PTACHYON fcChip,
-         USHORT producerNdx,
-         ULONG *ulDestPtr,            // contiguous destination buffer
-        BOOLEAN UpdateChip)
-{
-  ULONG total_bytes=0;
-  ULONG consumerIndex = fcChip->SFQ->consumerIndex;
-  
-                               // check passed copy of SFQ producer index -
-                               // is a new message waiting for us?
-                               // equal indexes means SFS is copied
-
-  while( producerNdx != consumerIndex )
-  {                             // need to process message
-    total_bytes += 64;   // maintain count to prevent writing past buffer
-                   // don't allow copies over Fibre Channel defined length!
-    if( total_bytes <= 2048 )
-    {
-      memcpy( ulDestPtr, 
-              &fcChip->SFQ->QEntry[consumerIndex],
-              64 );  // each SFQ entry is 64 bytes
-      ulDestPtr += 16;   // advance pointer to next 64 byte block
-    }
-                        // Tachyon is producing,
-                         // and we are consuming
-
-    if( ++consumerIndex >= SFQ_LEN)// check for rollover
-      consumerIndex = 0L;        // reset it
-  }
-
-  // if specified, update the Tachlite chip ConsumerIndex...
-  if( UpdateChip )
-  {
-    fcChip->SFQ->consumerIndex = consumerIndex;
-    writel( fcChip->SFQ->consumerIndex,
-      fcChip->Registers.SFQconsumerIndex.address);
-  }
-}
-
-
-
-// TachLite routinely freezes it's core ques - Outbound FIFO, Inbound FIFO,
-// and Exchange Request Queue (ERQ) on error recover - 
-// (e.g. whenever a LIP occurs).  Here
-// we routinely RESUME by clearing these bits, but only if the loop is up
-// to avoid ERROR IDLE messages forever.
-
-void CpqTsUnFreezeTachlite( void *pChip, int type )
-{
-  PTACHYON fcChip = (PTACHYON)pChip;
-  fcChip->Registers.TYcontrol.value = 
-    readl(fcChip->Registers.TYcontrol.address);
-            
-  // (bit 4 of value is GBIC LASER)
-  // if we 'unfreeze' the core machines before the loop is healthy
-  // (i.e. FLT, OS, LS failure bits set in FMstatus)
-  // we can get 'error idle' messages forever.  Verify that
-  // FMstatus (Link Status) is OK before unfreezing.
-
-  if( !(fcChip->Registers.FMstatus.value & 0x07000000L) && // bits clear?
-      !(fcChip->Registers.FMstatus.value & 0x80  ))  // Active LPSM?
-  {
-    fcChip->Registers.TYcontrol.value &=  ~0x300L; // clear FEQ, FFA
-    if( type == 1 )  // unfreeze ERQ only
-    {
-//      printk("Unfreezing ERQ\n");
-      fcChip->Registers.TYcontrol.value |= 0x10000L; // set REQ
-    }
-    else             // unfreeze both ERQ and FCP-ASSIST (SEST)
-    {
-//      printk("Unfreezing ERQ & FCP-ASSIST\n");
-
-                     // set ROF, RIF, REQ - resume Outbound FCP, Inbnd FCP, ERQ
-      fcChip->Registers.TYcontrol.value |= 0x70000L; // set ROF, RIF, REQ
-    }
-
-    writel( fcChip->Registers.TYcontrol.value,
-      fcChip->Registers.TYcontrol.address);
-              
-  }
-          // readback for verify (TachLite still frozen?)
-  fcChip->Registers.TYstatus.value = 
-    readl(fcChip->Registers.TYstatus.address);
-}
-
-
-// Whenever an FC Exchange Abort is required, we must manipulate the
-// Host/Tachyon shared memory SEST table.  Before doing this, we
-// must freeze Tachyon, which flushes certain buffers and ensure we
-// can manipulate the SEST without contention.
-// This freeze function will result in FCP & ERQ FROZEN completion
-// messages (per argument "type").
-
-void CpqTsFreezeTachlite( void *pChip, int type )
-{
-  PTACHYON fcChip = (PTACHYON)pChip;
-  fcChip->Registers.TYcontrol.value = 
-    readl(fcChip->Registers.TYcontrol.address);
-    
-                     //set FFA, FEQ - freezes SCSI assist and ERQ
-  if( type == 1)    // freeze ERQ only
-    fcChip->Registers.TYcontrol.value |= 0x100L; // (bit 4 is laser)
-  else              // freeze both FCP assists (SEST) and ERQ
-    fcChip->Registers.TYcontrol.value |= 0x300L; // (bit 4 is laser)
-  
-  writel( fcChip->Registers.TYcontrol.value,
-    fcChip->Registers.TYcontrol.address);
-              
-}
-
-
-
-
-// TL has two Frame Manager Link Status Registers, with three 8-bit
-// fields each. These eight bit counters are cleared after each read,
-// so we define six 32-bit accumulators for these TL counters. This
-// function breaks out each 8-bit field and adds the value to the existing
-// sum.  (s/w counters cleared independently)
-
-void fcParseLinkStatusCounters(PTACHYON fcChip)
-{
-  UCHAR bBuff;
-  ULONG ulBuff;
-
-
-// The BB0 timer usually increments when TL is initialized, resulting
-// in an initially bogus count.  If our own counter is ZERO, it means we
-// are reading this thing for the first time, so we ignore the first count.
-// Also, reading the register does not clear it, so we have to keep an
-// additional static counter to detect rollover (yuk).
-
-  if( fcChip->fcStats.lastBB0timer == 0L)  // TL was reset? (ignore 1st values)
-  {
-                           // get TL's register counter - the "last" count
-    fcChip->fcStats.lastBB0timer = 
-      fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
-  }
-  else  // subsequent pass - check for rollover
-  {
-                              // "this" count
-    ulBuff = fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
-    if( fcChip->fcStats.lastBB0timer > ulBuff ) // rollover happened
-    {
-                                // counter advanced to max...
-      fcChip->fcStats.BB0_Timer += (0x00FFFFFFL - fcChip->fcStats.lastBB0timer);
-      fcChip->fcStats.BB0_Timer += ulBuff;  // plus some more
-
-
-    }
-    else // no rollover -- more counts or no change
-    {
-      fcChip->fcStats.BB0_Timer +=  (ulBuff - fcChip->fcStats.lastBB0timer);
-
-    }
-
-    fcChip->fcStats.lastBB0timer = ulBuff;
-  }
-
-
-
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 24);
-  fcChip->fcStats.LossofSignal += bBuff;
-
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 16);
-  fcChip->fcStats.BadRXChar += bBuff;
-
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 8);
-  fcChip->fcStats.LossofSync += bBuff;
-
-
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 24);
-  fcChip->fcStats.Rx_EOFa += bBuff;
-
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 16);
-  fcChip->fcStats.Dis_Frm += bBuff;
-
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 8);
-  fcChip->fcStats.Bad_CRC += bBuff;
-}
-
-
-void cpqfcTSClearLinkStatusCounters(PTACHYON fcChip)
-{
-  ENTER("ClearLinkStatusCounters");
-  memset( &fcChip->fcStats, 0, sizeof( FCSTATS));
-  LEAVE("ClearLinkStatusCounters");
-
-}
-
-
-
-
-// The following function reads the I2C hardware to get the adapter's
-// World Wide Name (WWN).
-// If the WWN is "500805f1fadb43e8" (as printed on the card), the
-// Tachyon WWN_hi (32-bit) register is 500805f1, and WWN_lo register
-// is fadb43e8.
-// In the NVRAM, the bytes appear as:
-// [2d] ..
-// [2e] .. 
-// [2f] 50
-// [30] 08
-// [31] 05
-// [32] f1
-// [33] fa
-// [34] db
-// [35] 43
-// [36] e8
-//
-// In the Fibre Channel (Big Endian) format, the FC-AL LISM frame will
-// be correctly loaded by Tachyon silicon.  In the login payload, bytes
-// must be correctly swapped for Big Endian format.
-
-int CpqTsReadWriteWWN( PVOID pChip, int Read)
-{
-  PTACHYON fcChip = (PTACHYON)pChip;
-#define NVRAM_SIZE 512
-  unsigned short i, count = NVRAM_SIZE;
-  UCHAR nvRam[NVRAM_SIZE], WWNbuf[8];
-  ULONG ulBuff;
-  int iStatus=-1;  // assume failure
-  int WWNoffset;
-
-  ENTER("ReadWriteWWN");
-  // Now try to read the WWN from the adapter's NVRAM
-
-  if( Read )  // READing NVRAM WWN?
-  {
-    ulBuff = cpqfcTS_ReadNVRAM( fcChip->Registers.TYstatus.address,
-                              fcChip->Registers.TYcontrol.address,
-                              count, &nvRam[0] );
-
-    if( ulBuff )   // NVRAM read successful?
-    {
-      iStatus = 0; // success!
-      
-                   // for engineering/ prototype boards, the data may be
-                   // invalid (GIGO, usually all "FF"); this prevents the
-                   // parse routine from working correctly, which means
-                   // nothing will be written to our passed buffer.
-
-      WWNoffset = cpqfcTS_GetNVRAM_data( WWNbuf, nvRam );
-
-      if( !WWNoffset ) // uninitialized NVRAM -- copy bytes directly
-      {
-        printk( "CAUTION: Copying NVRAM data on fcChip\n");
-        for( i= 0; i < 8; i++)
-          WWNbuf[i] = nvRam[i +0x2f]; // dangerous! some formats won't work
-      }
-      
-      fcChip->Registers.wwn_hi = 0L;
-      fcChip->Registers.wwn_lo = 0L;
-      for( i=0; i<4; i++)  // WWN bytes are big endian in NVRAM
-      {
-        ulBuff = 0L;
-        ulBuff = (ULONG)(WWNbuf[i]) << (8 * (3-i));
-        fcChip->Registers.wwn_hi |= ulBuff;
-      }
-      for( i=0; i<4; i++)  // WWN bytes are big endian in NVRAM
-      {
-        ulBuff = 0L;
-        ulBuff = (ULONG)(WWNbuf[i+4]) << (8 * (3-i));
-        fcChip->Registers.wwn_lo |= ulBuff;
-      }
-    }  // done reading
-    else
-    {
-
-      printk( "cpqfcTS: NVRAM read failed\n");
-
-    }
-  }
-
-  else  // WRITE
-  {
-
-    // NOTE: WRITE not supported & not used in released driver.
-
-   
-    printk("ReadWriteNRAM: can't write NVRAM; aborting write\n");
-  }
-  
-  LEAVE("ReadWriteWWN");
-  return iStatus;
-}
-
-
-
-
-
-// The following function reads or writes the entire "NVRAM" contents of 
-// the I2C hardware (i.e. the NM24C03).  Note that HP's 5121A (TS 66Mhz)
-// adapter does not use the NM24C03 chip, so this function only works on
-// Compaq's adapters.
-
-int CpqTsReadWriteNVRAM( PVOID pChip, PVOID buf, int Read)
-{
-  PTACHYON fcChip = (PTACHYON)pChip;
-#define NVRAM_SIZE 512
-  ULONG ulBuff;
-  UCHAR *ucPtr = buf; // cast caller's void ptr to UCHAR array
-  int iStatus=-1;  // assume failure
-
-     
-  if( Read )  // READing NVRAM?
-  {
-    ulBuff = cpqfcTS_ReadNVRAM(   // TRUE on success
-                fcChip->Registers.TYstatus.address,
-                fcChip->Registers.TYcontrol.address,
-                256,            // bytes to write
-                ucPtr );        // source ptr
-
-
-    if( ulBuff )
-      iStatus = 0; // success
-    else
-    {
-#ifdef DBG
-      printk( "CAUTION: NVRAM read failed\n");
-#endif
-    }
-  }  // done reading
-
-  else  // WRITING NVRAM 
-  {
-
-    printk("cpqfcTS: WRITE of FC Controller's NVRAM disabled\n");
-  }
-    
-  return iStatus;
-}
diff --git a/drivers/scsi/cpqfcTSi2c.c b/drivers/scsi/cpqfcTSi2c.c
deleted file mode 100644 (file)
index b38a6a9..0000000
+++ /dev/null
@@ -1,493 +0,0 @@
-/* Copyright(c) 2000, Compaq Computer Corporation 
- * Fibre Channel Host Bus Adapter 
- * 64-bit, 66MHz PCI 
- * Originally developed and tested on:
- * (front): [chip] Tachyon TS HPFC-5166A/1.2  L2C1090 ...
- *          SP# P225CXCBFIEL6T, Rev XC
- *          SP# 161290-001, Rev XD
- * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- * Written by Don Zimmerman
-*/
-// These functions control the NVRAM I2C hardware on 
-// non-intelligent Fibre Host Adapters.
-// The primary purpose is to read the HBA's NVRAM to get adapter's 
-// manufactured WWN to copy into Tachyon chip registers
-// Orignal source author unknown
-
-#include <linux/types.h>
-enum boolean { FALSE, TRUE } ;
-
-
-#ifndef UCHAR
-typedef __u8 UCHAR;
-#endif
-#ifndef BOOLEAN
-typedef __u8 BOOLEAN;
-#endif
-#ifndef USHORT
-typedef __u16 USHORT;
-#endif
-#ifndef ULONG
-typedef __u32 ULONG;
-#endif
-
-
-#include <linux/string.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <asm/io.h>  // struct pt_regs for IRQ handler & Port I/O
-
-#include "cpqfcTSchip.h"
-
-static void tl_i2c_tx_byte( void* GPIOout, UCHAR data );
-/*static BOOLEAN tl_write_i2c_page_portion( void* GPIOin, void* GPIOout,
-  USHORT startOffset,  // e.g. 0x2f for WWN start
-  USHORT count,
-  UCHAR *buf );
-*/
-
-//
-// Tachlite GPIO2, GPIO3 (I2C) DEFINES
-// The NVRAM chip NM24C03 defines SCL (serial clock) and SDA (serial data)
-// GPIO2 drives SDA, and GPIO3 drives SCL
-// 
-// Since Tachlite inverts the state of the GPIO 0-3 outputs, SET writes 0
-// and clear writes 1. The input lines (read in TL status) is NOT inverted
-// This really helps confuse the code and debugging.
-
-#define SET_DATA_HI  0x0
-#define SET_DATA_LO  0x8
-#define SET_CLOCK_HI 0x0
-#define SET_CLOCK_LO 0x4
-
-#define SENSE_DATA_HI  0x8
-#define SENSE_DATA_LO  0x0
-#define SENSE_CLOCK_HI 0x4
-#define SENSE_CLOCK_LO 0x0
-
-#define SLAVE_READ_ADDRESS    0xA1
-#define SLAVE_WRITE_ADDRESS   0xA0
-                                             
-
-static void i2c_delay(ULONG mstime);
-static void tl_i2c_clock_pulse( UCHAR , void* GPIOout);
-static UCHAR tl_read_i2c_data( void* );
-
-
-//-----------------------------------------------------------------------------
-//
-//      Name:   I2C_RX_ACK
-//
-//      This routine receives an acknowledge over the I2C bus.
-//
-//-----------------------------------------------------------------------------
-static unsigned short tl_i2c_rx_ack( void* GPIOin, void* GPIOout )
-{
-  unsigned long value;
-
-       // do clock pulse, let data line float high
-  tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
-
-       // slave must drive data low for acknowledge
-  value = tl_read_i2c_data( GPIOin);
-  if (value & SENSE_DATA_HI )
-    return( FALSE );
-
-  return( TRUE );
-}
-//-----------------------------------------------------------------------------
-//
-//      Name:   READ_I2C_REG
-//
-//      This routine reads the I2C control register using the global
-//      IO address stored in gpioreg.
-//
-//-----------------------------------------------------------------------------
-static UCHAR tl_read_i2c_data( void* gpioreg )
-{
-  return( (UCHAR)(readl( gpioreg ) & 0x08L) ); // GPIO3
-}
-//-----------------------------------------------------------------------------
-//
-//      Name:   WRITE_I2C_REG
-//
-//      This routine writes the I2C control register using the global
-//      IO address stored in gpioreg.
-//      In Tachlite, we don't want to modify other bits in TL Control reg.
-//
-//-----------------------------------------------------------------------------
-static void tl_write_i2c_reg( void* gpioregOUT, UCHAR value )
-{
-  ULONG  temp;
-
-       // First read the register and clear out the old bits
-  temp = readl( gpioregOUT ) & 0xfffffff3L;
-
-       // Now or in the new data and send it back out
-  writel( temp | value, gpioregOUT);
-}
-//-----------------------------------------------------------------------------
-//
-//      Name:   I2C_TX_START
-//
-//      This routine transmits a start condition over the I2C bus.
-//      1. Set SCL (clock, GPIO2) HIGH, set SDA (data, GPIO3) HIGH,
-//      wait 5us to stabilize.
-//      2. With SCL still HIGH, drive SDA low.  The low transition marks
-//         the start condition to NM24Cxx (the chip)
-//      NOTE! In TL control reg., output 1 means chip sees LOW
-//
-//-----------------------------------------------------------------------------
-static unsigned short tl_i2c_tx_start( void* GPIOin, void* GPIOout )
-{
-  unsigned short i;
-  ULONG value;
-
-  if ( !(tl_read_i2c_data(GPIOin) & SENSE_DATA_HI))
-  {
-    // start with clock high, let data float high
-    tl_write_i2c_reg(  GPIOout, SET_DATA_HI | SET_CLOCK_HI );
-
-    // keep sending clock pulses if slave is driving data line
-    for (i = 0; i < 10; i++)
-    {
-      tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
-
-      if ( tl_read_i2c_data(GPIOin) & SENSE_DATA_HI )
-       break;
-    }
-
-               // if he's still driving data low after 10 clocks, abort
-    value = tl_read_i2c_data( GPIOin ); // read status
-    if (!(value & 0x08) )
-      return( FALSE );
-  }
-
-
-       // To START, bring data low while clock high
-  tl_write_i2c_reg(  GPIOout, SET_CLOCK_HI | SET_DATA_LO );
-
-  i2c_delay(0);
-
-  return( TRUE );                           // TX start successful
-}
-//-----------------------------------------------------------------------------
-//
-//      Name:   I2C_TX_STOP
-//
-//      This routine transmits a stop condition over the I2C bus.
-//
-//-----------------------------------------------------------------------------
-
-static unsigned short tl_i2c_tx_stop( void* GPIOin, void* GPIOout )
-{
-  int i;
-
-  for (i = 0; i < 10; i++) 
-  {
-  // Send clock pulse, drive data line low
-    tl_i2c_clock_pulse( SET_DATA_LO, GPIOout );
-
-  // To STOP, bring data high while clock high
-    tl_write_i2c_reg(  GPIOout, SET_DATA_HI | SET_CLOCK_HI );
-
-  // Give the data line time to float high
-    i2c_delay(0);
-
-  // If slave is driving data line low, there's a problem; retry
-    if ( tl_read_i2c_data(GPIOin) & SENSE_DATA_HI )
-      return( TRUE );  // TX STOP successful!
-  }
-
-  return( FALSE );                      // error
-}
-//-----------------------------------------------------------------------------
-//
-//      Name:   I2C_TX_uchar
-//
-//      This routine transmits a byte across the I2C bus.
-//
-//-----------------------------------------------------------------------------
-static void tl_i2c_tx_byte( void* GPIOout, UCHAR data )
-{
-  UCHAR bit;
-
-  for (bit = 0x80; bit; bit >>= 1)
-  {
-    if( data & bit )
-      tl_i2c_clock_pulse( (UCHAR)SET_DATA_HI, GPIOout);
-    else
-      tl_i2c_clock_pulse( (UCHAR)SET_DATA_LO, GPIOout);
-  }  
-}
-//-----------------------------------------------------------------------------
-//
-//      Name:   I2C_RX_uchar
-//
-//      This routine receives a byte across the I2C bus.
-//
-//-----------------------------------------------------------------------------
-static UCHAR tl_i2c_rx_byte( void* GPIOin, void* GPIOout )
-{
-  UCHAR bit;
-  UCHAR data = 0;
-
-
-  for (bit = 0x80; bit; bit >>= 1) {
-    // do clock pulse, let data line float high
-    tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
-
-    // read data line
-    if ( tl_read_i2c_data( GPIOin) & 0x08 )
-      data |= bit;
-  }
-
-  return (data);
-}
-//*****************************************************************************
-//*****************************************************************************
-// Function:   read_i2c_nvram
-// Arguments:  UCHAR count     number of bytes to read
-//             UCHAR *buf      area to store the bytes read
-// Returns:    0 - failed
-//             1 - success
-//*****************************************************************************
-//*****************************************************************************
-unsigned long cpqfcTS_ReadNVRAM( void* GPIOin, void* GPIOout , USHORT count,
-       UCHAR *buf )
-{
-  unsigned short i;
-
-  if( !( tl_i2c_tx_start(GPIOin, GPIOout) ))
-    return FALSE;
-
-  // Select the NVRAM for "dummy" write, to set the address
-  tl_i2c_tx_byte( GPIOout , SLAVE_WRITE_ADDRESS );
-  if ( !tl_i2c_rx_ack(GPIOin, GPIOout ) )
-    return( FALSE );
-
-  // Now send the address where we want to start reading  
-  tl_i2c_tx_byte( GPIOout , 0 );
-  if ( !tl_i2c_rx_ack(GPIOin, GPIOout ) )
-    return( FALSE );
-
-  // Send a repeated start condition and select the
-  //  slave for reading now.
-  if( tl_i2c_tx_start(GPIOin, GPIOout) )
-    tl_i2c_tx_byte( GPIOout, SLAVE_READ_ADDRESS );
-
-  if ( !tl_i2c_rx_ack(GPIOin, GPIOout) )
-    return( FALSE );
-
-  // this loop will now read out the data and store it
-  //  in the buffer pointed to by buf
-  for ( i=0; i<count; i++) 
-  {
-    *buf++ = tl_i2c_rx_byte(GPIOin, GPIOout);
-
-    // Send ACK by holding data line low for 1 clock
-    if ( i < (count-1) )
-      tl_i2c_clock_pulse( 0x08, GPIOout );
-    else {
-       // Don't send ack for final byte
-      tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
-    }
-  }
-
-  tl_i2c_tx_stop(GPIOin, GPIOout);
-
-  return( TRUE );
-}
-
-//****************************************************************
-//
-//
-//
-// routines to set and clear the data and clock bits
-//
-//
-//
-//****************************************************************
-
-static void tl_set_clock(void* gpioreg)
-{
-  ULONG ret_val;
-
-  ret_val = readl( gpioreg );
-  ret_val &= 0xffffffFBL;  // clear GPIO2 (SCL)
-  writel( ret_val, gpioreg);
-}
-
-static void tl_clr_clock(void* gpioreg)
-{
-  ULONG ret_val;
-
-  ret_val = readl( gpioreg );
-  ret_val |= SET_CLOCK_LO;
-  writel( ret_val, gpioreg);
-}
-
-//*****************************************************************
-//
-//
-// This routine will advance the clock by one period
-//
-//
-//*****************************************************************
-static void tl_i2c_clock_pulse( UCHAR value, void* GPIOout  )
-{
-  ULONG ret_val;
-
-  // clear the clock bit
-  tl_clr_clock( GPIOout );
-
-  i2c_delay(0);
-
-
-  // read the port to preserve non-I2C bits
-  ret_val = readl( GPIOout );
-
-  // clear the data & clock bits
-  ret_val &= 0xFFFFFFf3;
-
-  // write the value passed in...
-  // data can only change while clock is LOW!
-  ret_val |= value;           // the data
-  ret_val |= SET_CLOCK_LO;    // the clock
-  writel( ret_val, GPIOout );
-
-  i2c_delay(0);
-
-
-  //set clock bit
-  tl_set_clock( GPIOout);
-}
-
-
-
-
-//*****************************************************************
-//
-//
-// This routine returns the 64-bit WWN
-//
-//
-//*****************************************************************
-int cpqfcTS_GetNVRAM_data( UCHAR *wwnbuf, UCHAR *buf )
-{
-  ULONG len;
-  ULONG sub_len;
-  ULONG ptr_inc;
-  ULONG i;
-  ULONG j;
-  UCHAR *data_ptr;
-  UCHAR  z;
-  UCHAR  name;
-  UCHAR  sub_name;
-  UCHAR  done;
-  int iReturn=0;  // def. 0 offset is failure to find WWN field
-  
-
-         
-  data_ptr = (UCHAR *)buf;
-
-  done = FALSE;
-  i = 0;
-
-  while ( (i < 128) && (!done) ) 
-  {
-    z = data_ptr[i];\
-    if ( !(z & 0x80) )  
-    {  
-      len  = 1 + (z & 0x07);
-
-      name = (z & 0x78) >> 3;
-      if (name == 0x0F)
-        done = TRUE;
-    }
-    else 
-    {
-      name = z & 0x7F;
-      len  = 3 + data_ptr[i+1] + (data_ptr[i+2] << 8);
-           
-      switch (name) 
-      {
-      case 0x0D:
-       //
-         j = i + 3;
-         //
-         if ( data_ptr[j] == 0x3b ) {
-           len = 6;
-           break;
-         }
-
-         while ( j<(i+len) ) {
-           sub_name = (data_ptr[j] & 0x3f);
-           sub_len  = data_ptr[j+1] + 
-                      (data_ptr[j+2] << 8);
-            ptr_inc  = sub_len + 3; 
-           switch (sub_name) 
-           {
-           case 0x3C:
-              memcpy( wwnbuf, &data_ptr[j+3], 8);
-              iReturn = j+3;
-              break;
-            default:
-              break;
-           }
-           j += ptr_inc;
-          }
-         break;
-        default:
-         break;
-      }  
-    }  
-  //
-    i += len;
-  }  // end while 
-  return iReturn;
-}
-
-
-
-
-
-// define a short 5 micro sec delay, and longer (ms) delay
-
-static void i2c_delay(ULONG mstime)
-{
-  ULONG i;
-  
-// NOTE: we only expect to use these delays when reading
-// our adapter's NVRAM, which happens only during adapter reset.
-// Delay technique from "Linux Device Drivers", A. Rubini 
-// (1st Ed.) pg 137.
-
-//  printk(" delay %lx  ", mstime);
-  if( mstime ) // ms delay?
-  {
-    // delay technique
-    for( i=0; i < mstime; i++)
-      udelay(1000); // 1ms per loop
-       
-  }
-  else  // 5 micro sec delay
-  
-    udelay( 5 ); // micro secs
-  
-//  printk("done\n");
-}
-
-
-
diff --git a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c
deleted file mode 100644 (file)
index 3fda8d4..0000000
+++ /dev/null
@@ -1,2096 +0,0 @@
-/* Copyright(c) 2000, Compaq Computer Corporation 
- * Fibre Channel Host Bus Adapter 
- * 64-bit, 66MHz PCI 
- * Originally developed and tested on:
- * (front): [chip] Tachyon TS HPFC-5166A/1.2  L2C1090 ...
- *          SP# P225CXCBFIEL6T, Rev XC
- *          SP# 161290-001, Rev XD
- * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- * Written by Don Zimmerman
- * IOCTL and procfs added by Jouke Numan
- * SMP testing by Chel Van Gennip
- *
- * portions copied from:
- * QLogic CPQFCTS SCSI-FCP
- * Written by Erik H. Moe, ehm@cris.com
- * Copyright 1995, Erik H. Moe
- * Renamed and updated to 1.3.x by Michael Griffith <grif@cs.ucr.edu> 
- * Chris Loveland <cwl@iol.unh.edu> to support the isp2100 and isp2200
-*/
-
-
-#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
-
-#include <linux/config.h>  
-#include <linux/interrupt.h>  
-#include <linux/module.h>
-#include <linux/version.h> 
-#include <linux/blkdev.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/ioport.h>  // request_region() prototype
-#include <linux/completion.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>   // ioctl related
-#include <asm/irq.h>
-#include <linux/spinlock.h>
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_ioctl.h>
-#include "cpqfcTSchip.h"
-#include "cpqfcTSstructs.h"
-#include "cpqfcTStrigger.h"
-
-#include "cpqfcTS.h"
-
-/* Embedded module documentation macros - see module.h */
-MODULE_AUTHOR("Compaq Computer Corporation");
-MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA v. 2.5.4");
-MODULE_LICENSE("GPL");
-  
-int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, unsigned int reset_flags);
-
-// This struct was originally defined in 
-// /usr/src/linux/include/linux/proc_fs.h
-// since it's only partially implemented, we only use first
-// few fields...
-// NOTE: proc_fs changes in 2.4 kernel
-
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
-static struct proc_dir_entry proc_scsi_cpqfcTS =
-{
-  PROC_SCSI_CPQFCTS,           // ushort low_ino (enumerated list)
-  7,                           // ushort namelen
-  DEV_NAME,                    // const char* name
-  S_IFDIR | S_IRUGO | S_IXUGO, // mode_t mode
-  2                            // nlink_t nlink
-                              // etc. ...
-};
-
-
-#endif
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,7)
-#  define CPQFC_DECLARE_COMPLETION(x) DECLARE_COMPLETION(x)
-#  define CPQFC_WAITING waiting
-#  define CPQFC_COMPLETE(x) complete(x)
-#  define CPQFC_WAIT_FOR_COMPLETION(x) wait_for_completion(x);
-#else
-#  define CPQFC_DECLARE_COMPLETION(x) DECLARE_MUTEX_LOCKED(x)
-#  define CPQFC_WAITING sem
-#  define CPQFC_COMPLETE(x) up(x)
-#  define CPQFC_WAIT_FOR_COMPLETION(x) down(x)
-#endif
-
-static int cpqfc_alloc_private_data_pool(CPQFCHBA *hba);
-
-/* local function to load our per-HBA (local) data for chip
-   registers, FC link state, all FC exchanges, etc.
-
-   We allocate space and compute address offsets for the
-   most frequently accessed addresses; others (like World Wide
-   Name) are not necessary.
-*/
-static void Cpqfc_initHBAdata(CPQFCHBA *cpqfcHBAdata, struct pci_dev *PciDev )
-{
-             
-  cpqfcHBAdata->PciDev = PciDev; // copy PCI info ptr
-
-  // since x86 port space is 64k, we only need the lower 16 bits
-  cpqfcHBAdata->fcChip.Registers.IOBaseL = 
-    PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
-  
-  cpqfcHBAdata->fcChip.Registers.IOBaseU = 
-    PciDev->resource[2].start & PCI_BASE_ADDRESS_IO_MASK;
-  
-  // 32-bit memory addresses
-  cpqfcHBAdata->fcChip.Registers.MemBase = 
-    PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK;
-
-  cpqfcHBAdata->fcChip.Registers.ReMapMemBase = 
-    ioremap( PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK,
-             0x200);
-  
-  cpqfcHBAdata->fcChip.Registers.RAMBase = 
-    PciDev->resource[4].start;
-  
-  cpqfcHBAdata->fcChip.Registers.SROMBase =  // NULL for HP TS adapter
-    PciDev->resource[5].start;
-  
-  // now the Tachlite chip registers
-  // the REGISTER struct holds both the physical address & last
-  // written value (some TL registers are WRITE ONLY)
-
-  cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_SFQ_CONSUMER_INDEX;
-
-  cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX;
-      
-  // TL Frame Manager
-  cpqfcHBAdata->fcChip.Registers.FMconfig.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONFIG;
-  cpqfcHBAdata->fcChip.Registers.FMcontrol.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONTROL;
-  cpqfcHBAdata->fcChip.Registers.FMstatus.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_STATUS;
-  cpqfcHBAdata->fcChip.Registers.FMLinkStatus1.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT1;
-  cpqfcHBAdata->fcChip.Registers.FMLinkStatus2.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT2;
-  cpqfcHBAdata->fcChip.Registers.FMBB_CreditZero.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_BB_CREDIT0;
-      
-      // TL Control Regs
-  cpqfcHBAdata->fcChip.Registers.TYconfig.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONFIG;
-  cpqfcHBAdata->fcChip.Registers.TYcontrol.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONTROL;
-  cpqfcHBAdata->fcChip.Registers.TYstatus.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_STATUS;
-  cpqfcHBAdata->fcChip.Registers.rcv_al_pa.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_RCV_AL_PA;
-  cpqfcHBAdata->fcChip.Registers.ed_tov.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_ED_TOV;
-
-
-  cpqfcHBAdata->fcChip.Registers.INTEN.address = 
-               cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTEN;
-  cpqfcHBAdata->fcChip.Registers.INTPEND.address = 
-               cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTPEND;
-  cpqfcHBAdata->fcChip.Registers.INTSTAT.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTSTAT;
-
-  DEBUG_PCI(printk("  cpqfcHBAdata->fcChip.Registers. :\n"));
-  DEBUG_PCI(printk("    IOBaseL = %x\n", 
-    cpqfcHBAdata->fcChip.Registers.IOBaseL));
-  DEBUG_PCI(printk("    IOBaseU = %x\n", 
-    cpqfcHBAdata->fcChip.Registers.IOBaseU));
-  
-  /* printk(" ioremap'd Membase: %p\n", cpqfcHBAdata->fcChip.Registers.ReMapMemBase); */
-  
-  DEBUG_PCI(printk("    SFQconsumerIndex.address = %p\n", 
-    cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address));
-  DEBUG_PCI(printk("    ERQproducerIndex.address = %p\n", 
-    cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address));
-  DEBUG_PCI(printk("    TYconfig.address = %p\n", 
-    cpqfcHBAdata->fcChip.Registers.TYconfig.address));
-  DEBUG_PCI(printk("    FMconfig.address = %p\n", 
-    cpqfcHBAdata->fcChip.Registers.FMconfig.address));
-  DEBUG_PCI(printk("    FMcontrol.address = %p\n", 
-    cpqfcHBAdata->fcChip.Registers.FMcontrol.address));
-
-  // set default options for FC controller (chip)
-  cpqfcHBAdata->fcChip.Options.initiator = 1;  // default: SCSI initiator
-  cpqfcHBAdata->fcChip.Options.target = 0;     // default: SCSI target
-  cpqfcHBAdata->fcChip.Options.extLoopback = 0;// default: no loopback @GBIC
-  cpqfcHBAdata->fcChip.Options.intLoopback = 0;// default: no loopback inside chip
-
-  // set highest and lowest FC-PH version the adapter/driver supports
-  // (NOT strict compliance)
-  cpqfcHBAdata->fcChip.highest_FCPH_ver = FC_PH3;
-  cpqfcHBAdata->fcChip.lowest_FCPH_ver = FC_PH43;
-
-  // set function points for this controller / adapter
-  cpqfcHBAdata->fcChip.ResetTachyon = CpqTsResetTachLite;
-  cpqfcHBAdata->fcChip.FreezeTachyon = CpqTsFreezeTachlite;
-  cpqfcHBAdata->fcChip.UnFreezeTachyon = CpqTsUnFreezeTachlite;
-  cpqfcHBAdata->fcChip.CreateTachyonQues = CpqTsCreateTachLiteQues;
-  cpqfcHBAdata->fcChip.DestroyTachyonQues = CpqTsDestroyTachLiteQues;
-  cpqfcHBAdata->fcChip.InitializeTachyon = CpqTsInitializeTachLite;  
-  cpqfcHBAdata->fcChip.LaserControl = CpqTsLaserControl;  
-  cpqfcHBAdata->fcChip.ProcessIMQEntry = CpqTsProcessIMQEntry;
-  cpqfcHBAdata->fcChip.InitializeFrameManager = CpqTsInitializeFrameManager;
-  cpqfcHBAdata->fcChip.ReadWriteWWN = CpqTsReadWriteWWN;
-  cpqfcHBAdata->fcChip.ReadWriteNVRAM = CpqTsReadWriteNVRAM;
-
-      if (cpqfc_alloc_private_data_pool(cpqfcHBAdata) != 0) {
-               printk(KERN_WARNING 
-                       "cpqfc: unable to allocate pool for passthru ioctls.  "
-                       "Passthru ioctls disabled.\n");
-      }
-}
-
-
-/* (borrowed from linux/drivers/scsi/hosts.c) */
-static void launch_FCworker_thread(struct Scsi_Host *HostAdapter)
-{
-  DECLARE_MUTEX_LOCKED(sem);
-
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-
-  ENTER("launch_FC_worker_thread");
-             
-  cpqfcHBAdata->notify_wt = &sem;
-
-  /* must unlock before kernel_thread(), for it may cause a reschedule. */
-  spin_unlock_irq(HostAdapter->host_lock);
-  kernel_thread((int (*)(void *))cpqfcTSWorkerThread, 
-                          (void *) HostAdapter, 0);
-  /*
-   * Now wait for the kernel error thread to initialize itself
-
-   */
-  down (&sem);
-  spin_lock_irq(HostAdapter->host_lock);
-  cpqfcHBAdata->notify_wt = NULL;
-
-  LEAVE("launch_FC_worker_thread");
-}
-
-
-/* "Entry" point to discover if any supported PCI 
-   bus adapter can be found
-*/
-/* We're supporting:
- * Compaq 64-bit, 66MHz HBA with Tachyon TS
- * Agilent XL2 
- * HP Tachyon
- */
-#define HBA_TYPES 3
-
-#ifndef PCI_DEVICE_ID_COMPAQ_
-#define PCI_DEVICE_ID_COMPAQ_TACHYON   0xa0fc
-#endif
-
-static struct SupportedPCIcards cpqfc_boards[] __initdata = {
-       {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TACHYON},
-       {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_TACHLITE},
-       {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_TACHYON},
-};
-
-
-int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate)
-{
-  int NumberOfAdapters=0; // how many of our PCI adapters are found?
-  struct pci_dev *PciDev = NULL;
-  struct Scsi_Host *HostAdapter = NULL;
-  CPQFCHBA *cpqfcHBAdata = NULL; 
-  struct timer_list *cpqfcTStimer = NULL;
-  int i;
-
-  ENTER("cpqfcTS_detect");
-
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
-  ScsiHostTemplate->proc_dir = &proc_scsi_cpqfcTS;
-#else
-  ScsiHostTemplate->proc_name = "cpqfcTS";
-#endif
-
-  for( i=0; i < HBA_TYPES; i++)
-  {
-    // look for all HBAs of each type
-
-    while((PciDev = pci_find_device(cpqfc_boards[i].vendor_id,
-                                   cpqfc_boards[i].device_id, PciDev)))
-    {
-
-      if (pci_enable_device(PciDev)) {
-       printk(KERN_ERR
-               "cpqfc: can't enable PCI device at %s\n", pci_name(PciDev));
-       goto err_continue;
-      }
-
-      if (pci_set_dma_mask(PciDev, CPQFCTS_DMA_MASK) != 0) {
-       printk(KERN_WARNING 
-               "cpqfc: HBA cannot support required DMA mask, skipping.\n");
-       goto err_disable_dev;
-      }
-
-      // NOTE: (kernel 2.2.12-32) limits allocation to 128k bytes...
-      /* printk(" scsi_register allocating %d bytes for FC HBA\n",
-                     (ULONG)sizeof(CPQFCHBA)); */
-
-      HostAdapter = scsi_register( ScsiHostTemplate, sizeof( CPQFCHBA ) );
-      
-      if(HostAdapter == NULL) {
-       printk(KERN_WARNING
-               "cpqfc: can't register SCSI HBA, skipping.\n");
-       goto err_disable_dev;
-      }
-      DEBUG_PCI( printk("  HBA found!\n"));
-      DEBUG_PCI( printk("  HostAdapter->PciDev->irq = %u\n", PciDev->irq) );
-      DEBUG_PCI(printk("  PciDev->baseaddress[0]= %lx\n", 
-                               PciDev->resource[0].start));
-      DEBUG_PCI(printk("  PciDev->baseaddress[1]= %lx\n", 
-                               PciDev->resource[1].start));
-      DEBUG_PCI(printk("  PciDev->baseaddress[2]= %lx\n", 
-                               PciDev->resource[2].start));
-      DEBUG_PCI(printk("  PciDev->baseaddress[3]= %lx\n", 
-                               PciDev->resource[3].start));
-
-      HostAdapter->irq = PciDev->irq;  // copy for Scsi layers
-      
-      // HP Tachlite uses two (255-byte) ranges of Port I/O (lower & upper),
-      // for a total I/O port address space of 512 bytes.
-      // mask out the I/O port address (lower) & record
-      HostAdapter->io_port = (unsigned int)
-            PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
-      HostAdapter->n_io_port = 0xff;
-      
-      // i.e., expect 128 targets (arbitrary number), while the
-      //  RA-4000 supports 32 LUNs
-      HostAdapter->max_id =  0;   // incremented as devices log in    
-      HostAdapter->max_lun = CPQFCTS_MAX_LUN;         // LUNs per FC device
-      HostAdapter->max_channel = CPQFCTS_MAX_CHANNEL; // multiple busses?
-      
-      // get the pointer to our HBA specific data... (one for
-      // each HBA on the PCI bus(ses)).
-      cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-      
-      // make certain our data struct is clear
-      memset( cpqfcHBAdata, 0, sizeof( CPQFCHBA ) );
-
-
-      // initialize our HBA info
-      cpqfcHBAdata->HBAnum = NumberOfAdapters;
-
-      cpqfcHBAdata->HostAdapter = HostAdapter; // back ptr
-      Cpqfc_initHBAdata( cpqfcHBAdata, PciDev ); // fill MOST fields
-     
-      cpqfcHBAdata->HBAnum = NumberOfAdapters;
-      spin_lock_init(&cpqfcHBAdata->hba_spinlock);
-
-      // request necessary resources and check for conflicts
-      if( request_irq( HostAdapter->irq,
-                      cpqfcTS_intr_handler,
-                      SA_INTERRUPT | SA_SHIRQ,
-                      DEV_NAME,
-                      HostAdapter) )
-      {
-       printk(KERN_WARNING "cpqfc: IRQ %u already used\n", HostAdapter->irq);
-       goto err_unregister;
-      }
-
-      // Since we have two 256-byte I/O port ranges (upper
-      // and lower), check them both
-      if( !request_region( cpqfcHBAdata->fcChip.Registers.IOBaseU,
-                          0xff, DEV_NAME ) )
-      {
-       printk(KERN_WARNING "cpqfc: address in use: %x\n",
-                       cpqfcHBAdata->fcChip.Registers.IOBaseU);
-       goto err_free_irq;
-      }        
-      
-      if( !request_region( cpqfcHBAdata->fcChip.Registers.IOBaseL,
-                          0xff, DEV_NAME ) )
-      {
-       printk(KERN_WARNING "cpqfc: address in use: %x\n",
-                               cpqfcHBAdata->fcChip.Registers.IOBaseL);
-       goto err_release_region_U;
-      }        
-      
-      // OK, we have grabbed everything we need now.
-      DEBUG_PCI(printk("  Reserved 255 I/O addresses @ %x\n",
-        cpqfcHBAdata->fcChip.Registers.IOBaseL ));
-      DEBUG_PCI(printk("  Reserved 255 I/O addresses @ %x\n",
-        cpqfcHBAdata->fcChip.Registers.IOBaseU ));
-
-     
-      // start our kernel worker thread
-
-      spin_lock_irq(HostAdapter->host_lock);
-      launch_FCworker_thread(HostAdapter);
-
-
-      // start our TimerTask...
-
-      cpqfcTStimer = &cpqfcHBAdata->cpqfcTStimer;
-
-      init_timer( cpqfcTStimer); // Linux clears next/prev values
-      cpqfcTStimer->expires = jiffies + HZ; // one second
-      cpqfcTStimer->data = (unsigned long)cpqfcHBAdata; // this adapter
-      cpqfcTStimer->function = cpqfcTSheartbeat; // handles timeouts, housekeeping
-
-      add_timer( cpqfcTStimer);  // give it to Linux
-
-
-      // now initialize our hardware...
-      if (cpqfcHBAdata->fcChip.InitializeTachyon( cpqfcHBAdata, 1,1)) {
-       printk(KERN_WARNING "cpqfc: initialization of HBA hardware failed.\n");
-       goto err_release_region_L;
-      }
-
-      cpqfcHBAdata->fcStatsTime = jiffies;  // (for FC Statistics delta)
-      
-      // give our HBA time to initialize and login current devices...
-      {
-       // The Brocade switch (e.g. 2400, 2010, etc.) as of March 2000,
-       // has the following algorithm for FL_Port startup:
-       // Time(sec) Action
-       // 0:        Device Plugin and LIP(F7,F7) transmission
-       // 1.0       LIP incoming
-        // 1.027     LISA incoming, no CLS! (link not up)
-       // 1.028     NOS incoming (switch test for N_Port)
-        // 1.577     ED_TOV expired, transmit LIPs again       
-       // 3.0       LIP(F8,F7) incoming (switch passes Tach Prim.Sig)
-       // 3.028     LILP received, link up, FLOGI starts
-       // slowest(worst) case, measured on 1Gb Finisar GT analyzer
-       
-       unsigned long stop_time;
-
-       spin_unlock_irq(HostAdapter->host_lock);
-       stop_time = jiffies + 4*HZ;
-        while ( time_before(jiffies, stop_time) ) 
-               schedule();  // (our worker task needs to run)
-
-      }
-      
-      spin_lock_irq(HostAdapter->host_lock);
-      NumberOfAdapters++; 
-      spin_unlock_irq(HostAdapter->host_lock);
-
-      continue;
-
-err_release_region_L:
-      release_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff );
-err_release_region_U:
-      release_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff );
-err_free_irq:
-      free_irq( HostAdapter->irq, HostAdapter);
-err_unregister:
-      scsi_unregister( HostAdapter);
-err_disable_dev:
-      pci_disable_device( PciDev );
-err_continue:
-      continue;
-    } // end of while()
-  }
-
-  LEAVE("cpqfcTS_detect");
-  return NumberOfAdapters;
-}
-
-#ifdef SUPPORT_RESET
-static void my_ioctl_done (Scsi_Cmnd * SCpnt)
-{
-    struct request * req;
-    
-    req = SCpnt->request;
-    req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */
-  
-    if (req->CPQFC_WAITING != NULL)
-       CPQFC_COMPLETE(req->CPQFC_WAITING);
-}   
-#endif
-
-static int cpqfc_alloc_private_data_pool(CPQFCHBA *hba)
-{
-       hba->private_data_bits = NULL;
-       hba->private_data_pool = NULL;
-       hba->private_data_bits = 
-               kmalloc(((CPQFC_MAX_PASSTHRU_CMDS+BITS_PER_LONG-1) /
-                               BITS_PER_LONG)*sizeof(unsigned long), 
-                               GFP_KERNEL);
-       if (hba->private_data_bits == NULL)
-               return -1;
-       memset(hba->private_data_bits, 0,
-               ((CPQFC_MAX_PASSTHRU_CMDS+BITS_PER_LONG-1) /
-                               BITS_PER_LONG)*sizeof(unsigned long));
-       hba->private_data_pool = kmalloc(sizeof(cpqfc_passthru_private_t) *
-                       CPQFC_MAX_PASSTHRU_CMDS, GFP_KERNEL);
-       if (hba->private_data_pool == NULL) {
-               kfree(hba->private_data_bits);
-               hba->private_data_bits = NULL;
-               return -1;
-       }
-       return 0;
-}
-
-static void cpqfc_free_private_data_pool(CPQFCHBA *hba)
-{
-       kfree(hba->private_data_bits);
-       kfree(hba->private_data_pool);
-}
-
-int is_private_data_of_cpqfc(CPQFCHBA *hba, void *pointer)
-{
-       /* Is pointer within our private data pool?
-          We use Scsi_Request->upper_private_data (normally
-          reserved for upper layer drivers, e.g. the sg driver)
-          We check to see if the pointer is ours by looking at
-          its address.  Is this ok?   Hmm, it occurs to me that
-          a user app might do something bad by using sg to send
-          a cpqfc passthrough ioctl with upper_data_private
-          forged to be somewhere in our pool..., though they'd
-          normally have to be root already to do this.  */
-
-       return (pointer != NULL && 
-               pointer >= (void *) hba->private_data_pool && 
-               pointer < (void *) hba->private_data_pool + 
-                       sizeof(*hba->private_data_pool) * 
-                               CPQFC_MAX_PASSTHRU_CMDS);
-}
-
-cpqfc_passthru_private_t *cpqfc_alloc_private_data(CPQFCHBA *hba)
-{
-       int i;
-
-       do {
-               i = find_first_zero_bit(hba->private_data_bits, 
-                       CPQFC_MAX_PASSTHRU_CMDS);
-               if (i == CPQFC_MAX_PASSTHRU_CMDS)
-                       return NULL;
-       } while ( test_and_set_bit(i & (BITS_PER_LONG - 1), 
-                       hba->private_data_bits+(i/BITS_PER_LONG)) != 0);
-       return &hba->private_data_pool[i];
-}
-
-void cpqfc_free_private_data(CPQFCHBA *hba, cpqfc_passthru_private_t *data)
-{
-       int i;
-       i = data - hba->private_data_pool;
-       clear_bit(i&(BITS_PER_LONG-1), 
-                       hba->private_data_bits+(i/BITS_PER_LONG));
-}
-
-int cpqfcTS_ioctl( struct scsi_device *ScsiDev, int Cmnd, void *arg)
-{
-  int result = 0;
-  struct Scsi_Host *HostAdapter = ScsiDev->host;
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  PFC_LOGGEDIN_PORT pLoggedInPort = NULL;
-  struct scsi_cmnd *DumCmnd;
-  int i, j;
-  VENDOR_IOCTL_REQ ioc;
-  cpqfc_passthru_t *vendor_cmd;
-  Scsi_Device *SDpnt;
-  Scsi_Request *ScsiPassThruReq;
-  cpqfc_passthru_private_t *privatedata;
-
-  ENTER("cpqfcTS_ioctl ");
-
-    // printk("ioctl CMND %d", Cmnd);
-    switch (Cmnd) {
-      // Passthrough provides a mechanism to bypass the RAID
-      // or other controller and talk directly to the devices
-      // (e.g. physical disk drive)
-      // Passthrough commands, unfortunately, tend to be vendor
-      // specific; this is tailored to COMPAQ's RAID (RA4x00)
-      case CPQFCTS_SCSI_PASSTHRU:
-      {
-       void *buf = NULL; // for kernel space buffer for user data
-
-       /* Check that our pool got allocated ok. */
-       if (cpqfcHBAdata->private_data_pool == NULL)
-               return -ENOMEM;
-       
-       if( !arg)
-         return -EINVAL;
-
-       // must be super user to send stuff directly to the
-       // controller and/or physical drives...
-       if( !capable(CAP_SYS_RAWIO) )
-         return -EPERM;
-
-       // copy the caller's struct to our space.
-        if( copy_from_user( &ioc, arg, sizeof( VENDOR_IOCTL_REQ)))
-               return( -EFAULT);
-
-       vendor_cmd = ioc.argp;  // i.e., CPQ specific command struct
-
-       // If necessary, grab a kernel/DMA buffer
-       if( vendor_cmd->len)
-       {
-         buf = kmalloc( vendor_cmd->len, GFP_KERNEL);
-         if( !buf)
-           return -ENOMEM;
-       }
-        // Now build a Scsi_Request to pass down...
-        ScsiPassThruReq = scsi_allocate_request(ScsiDev, GFP_KERNEL);
-       if (ScsiPassThruReq == NULL) {
-               kfree(buf);
-               return -ENOMEM;
-       }
-       ScsiPassThruReq->upper_private_data = 
-                       cpqfc_alloc_private_data(cpqfcHBAdata);
-       if (ScsiPassThruReq->upper_private_data == NULL) {
-               kfree(buf);
-               scsi_release_request(ScsiPassThruReq); // "de-allocate"
-               return -ENOMEM;
-       }
-
-       if (vendor_cmd->rw_flag == VENDOR_WRITE_OPCODE) {
-               if (vendor_cmd->len) { // Need data from user?
-                       if (copy_from_user(buf, vendor_cmd->bufp, 
-                                               vendor_cmd->len)) {
-                               kfree(buf);
-                               cpqfc_free_private_data(cpqfcHBAdata, 
-                                       ScsiPassThruReq->upper_private_data);
-                               scsi_release_request(ScsiPassThruReq);
-                               return( -EFAULT);
-                       }
-               }
-               ScsiPassThruReq->sr_data_direction = DMA_TO_DEVICE; 
-       } else if (vendor_cmd->rw_flag == VENDOR_READ_OPCODE) {
-               ScsiPassThruReq->sr_data_direction = DMA_FROM_DEVICE;
-       } else
-               // maybe this means a bug in the user app
-               ScsiPassThruReq->sr_data_direction = DMA_BIDIRECTIONAL;
-           
-       ScsiPassThruReq->sr_cmd_len = 0; // set correctly by scsi_do_req()
-       ScsiPassThruReq->sr_sense_buffer[0] = 0;
-       ScsiPassThruReq->sr_sense_buffer[2] = 0;
-
-        // We copy the scheme used by sd.c:spinup_disk() to submit commands
-       // to our own HBA.  We do this in order to stall the
-       // thread calling the IOCTL until it completes, and use
-       // the same "_quecommand" function for synchronizing
-       // FC Link events with our "worker thread".
-
-       privatedata = ScsiPassThruReq->upper_private_data;
-       privatedata->bus = vendor_cmd->bus;
-       privatedata->pdrive = vendor_cmd->pdrive;
-       
-        // eventually gets us to our own _quecommand routine
-       scsi_wait_req(ScsiPassThruReq, 
-               &vendor_cmd->cdb[0], buf, vendor_cmd->len, 
-               10*HZ,  // timeout
-               1);     // retries
-        result = ScsiPassThruReq->sr_result;
-
-        // copy any sense data back to caller
-        if( result != 0 )
-       {
-         memcpy( vendor_cmd->sense_data, // see struct def - size=40
-                 ScsiPassThruReq->sr_sense_buffer, 
-                 sizeof(ScsiPassThruReq->sr_sense_buffer) <
-                  sizeof(vendor_cmd->sense_data)           ?
-                  sizeof(ScsiPassThruReq->sr_sense_buffer) :
-                  sizeof(vendor_cmd->sense_data)
-                ); 
-       }
-        SDpnt = ScsiPassThruReq->sr_device;
-       /* upper_private_data is already freed in call_scsi_done() */
-        scsi_release_request(ScsiPassThruReq); // "de-allocate"
-        ScsiPassThruReq = NULL;
-
-       // need to pass data back to user (space)?
-       if( (vendor_cmd->rw_flag == VENDOR_READ_OPCODE) &&
-            vendor_cmd->len )
-        if(  copy_to_user( vendor_cmd->bufp, buf, vendor_cmd->len))
-               result = -EFAULT;
-
-       kfree(buf);
-
-        return result;
-      }
-      
-      case CPQFCTS_GETPCIINFO:
-      {
-       cpqfc_pci_info_struct pciinfo;
-       
-       if( !arg)
-         return -EINVAL;
-
-               
-       
-        pciinfo.bus = cpqfcHBAdata->PciDev->bus->number;
-        pciinfo.dev_fn = cpqfcHBAdata->PciDev->devfn;  
-       pciinfo.board_id = cpqfcHBAdata->PciDev->device |
-                         (cpqfcHBAdata->PciDev->vendor <<16); 
-             
-        if(copy_to_user( arg, &pciinfo, sizeof(cpqfc_pci_info_struct)))
-               return( -EFAULT);
-        return 0;
-      }
-
-      case CPQFCTS_GETDRIVVER:
-      {
-       DriverVer_type DriverVer = 
-               CPQFCTS_DRIVER_VER( VER_MAJOR,VER_MINOR,VER_SUBMINOR);
-       
-       if( !arg)
-         return -EINVAL;
-
-        if(copy_to_user( arg, &DriverVer, sizeof(DriverVer)))
-               return( -EFAULT);
-        return 0;
-      }
-
-
-
-      case CPQFC_IOCTL_FC_TARGET_ADDRESS:
-       // can we find an FC device mapping to this SCSI target?
-/*     DumCmnd.channel = ScsiDev->channel; */          // For searching
-/*     DumCmnd.target  = ScsiDev->id; */
-/*     DumCmnd.lun     = ScsiDev->lun; */
-
-       DumCmnd = scsi_get_command (ScsiDev, GFP_KERNEL);
-       if (!DumCmnd)
-               return -ENOMEM;
-       
-       pLoggedInPort = fcFindLoggedInPort( fcChip,
-               DumCmnd, // search Scsi Nexus
-               0,        // DON'T search linked list for FC port id
-               NULL,     // DON'T search linked list for FC WWN
-               NULL);    // DON'T care about end of list
-       scsi_put_command (DumCmnd);
-       if (pLoggedInPort == NULL) {
-               result = -ENXIO;
-               break;
-       }
-       result = access_ok(VERIFY_WRITE, arg, sizeof(Scsi_FCTargAddress)) ? 0 : -EFAULT;
-       if (result) break;
-      put_user(pLoggedInPort->port_id,
-               &((Scsi_FCTargAddress *) arg)->host_port_id);
-      for( i=3,j=0; i>=0; i--)         // copy the LOGIN port's WWN
-        put_user(pLoggedInPort->u.ucWWN[i], 
-               &((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
-      for( i=7; i>3; i--)              // copy the LOGIN port's WWN
-        put_user(pLoggedInPort->u.ucWWN[i], 
-               &((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
-        break;
-
-
-      case CPQFC_IOCTL_FC_TDR:
-          
-        result = cpqfcTS_TargetDeviceReset( ScsiDev, 0);
-
-        break;
-
-
-
-
-    default:
-      result = -EINVAL;
-      break;
-    }
-
-  LEAVE("cpqfcTS_ioctl");
-  return result;
-}
-
-
-/* "Release" the Host Bus Adapter...
-   disable interrupts, stop the HBA, release the interrupt,
-   and free all resources */
-
-int cpqfcTS_release(struct Scsi_Host *HostAdapter)
-{
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; 
-
-
-  ENTER("cpqfcTS_release");
-       
-  DEBUG_PCI( printk(" cpqfcTS: delete timer...\n"));
-  del_timer( &cpqfcHBAdata->cpqfcTStimer);  
-    
-  // disable the hardware...
-  DEBUG_PCI( printk(" disable hardware, destroy queues, free mem\n"));
-  cpqfcHBAdata->fcChip.ResetTachyon( cpqfcHBAdata, CLEAR_FCPORTS);
-
-  // kill kernel thread
-  if( cpqfcHBAdata->worker_thread ) // (only if exists)
-  {
-    DECLARE_MUTEX_LOCKED(sem);  // synchronize thread kill
-
-    cpqfcHBAdata->notify_wt = &sem;
-    DEBUG_PCI( printk(" killing kernel thread\n"));
-    send_sig( SIGKILL, cpqfcHBAdata->worker_thread, 1);
-    down( &sem);
-    cpqfcHBAdata->notify_wt = NULL;
-    
-  }
-
-  cpqfc_free_private_data_pool(cpqfcHBAdata);
-  // free Linux resources
-  DEBUG_PCI( printk(" cpqfcTS: freeing resources...\n"));
-  free_irq( HostAdapter->irq, HostAdapter);
-  scsi_unregister( HostAdapter);
-  release_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff);
-  release_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff);
- /* we get "vfree: bad address" executing this - need to investigate... 
-  if( (void*)((unsigned long)cpqfcHBAdata->fcChip.Registers.MemBase) !=
-      cpqfcHBAdata->fcChip.Registers.ReMapMemBase)
-    vfree( cpqfcHBAdata->fcChip.Registers.ReMapMemBase);
-*/
-  pci_disable_device( cpqfcHBAdata->PciDev);
-
-  LEAVE("cpqfcTS_release");
-  return 0;
-}
-
-
-const char * cpqfcTS_info(struct Scsi_Host *HostAdapter)
-{
-  static char buf[300];
-  CPQFCHBA *cpqfcHBA;
-  int BusSpeed, BusWidth;
-  
-  // get the pointer to our Scsi layer HBA buffer  
-  cpqfcHBA = (CPQFCHBA *)HostAdapter->hostdata;
-
-  BusWidth = (cpqfcHBA->fcChip.Registers.PCIMCTR &0x4) > 0 ?
-               64 : 32;
-
-  if( cpqfcHBA->fcChip.Registers.TYconfig.value & 0x80000000)
-    BusSpeed = 66;
-  else
-    BusSpeed = 33;
-
-  sprintf(buf, 
-"%s: WWN %08X%08X\n on PCI bus %d device 0x%02x irq %d IObaseL 0x%x, MEMBASE 0x%x\nPCI bus width %d bits, bus speed %d MHz\nFCP-SCSI Driver v%d.%d.%d",
-      cpqfcHBA->fcChip.Name, 
-      cpqfcHBA->fcChip.Registers.wwn_hi,
-      cpqfcHBA->fcChip.Registers.wwn_lo,
-      cpqfcHBA->PciDev->bus->number,
-      cpqfcHBA->PciDev->device,  
-      HostAdapter->irq,
-      cpqfcHBA->fcChip.Registers.IOBaseL,
-      cpqfcHBA->fcChip.Registers.MemBase,
-      BusWidth,
-      BusSpeed,
-      VER_MAJOR, VER_MINOR, VER_SUBMINOR
-);
-
-  
-  cpqfcTSDecodeGBICtype( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
-  cpqfcTSGetLPSM( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
-  return buf;
-}
-
-//
-// /proc/scsi support. The following routines allow us to do 'normal'
-// sprintf like calls to return the currently requested piece (buflenght
-// chars, starting at bufoffset) of the file. Although procfs allows for
-// a 1 Kb bytes overflow after te supplied buffer, I consider it bad 
-// programming to use it to make programming a little simpler. This piece
-// of coding is borrowed from ncr53c8xx.c with some modifications 
-//
-struct info_str
-{
-        char *buffer;                  // Pointer to output buffer
-        int buflength;                 // It's length
-        int bufoffset;                 // File offset corresponding with buf[0]
-       int buffillen;                  // Current filled length 
-        int filpos;                    // Current file offset
-};
-
-static void copy_mem_info(struct info_str *info, char *data, int datalen)
-{
-
-  if (info->filpos < info->bufoffset) {        // Current offset before buffer offset
-    if (info->filpos + datalen <= info->bufoffset) {
-      info->filpos += datalen;                 // Discard if completely before buffer
-      return;
-    } else {                           // Partial copy, set to begin
-      data += (info->bufoffset - info->filpos);
-      datalen  -= (info->bufoffset - info->filpos);
-      info->filpos = info->bufoffset;
-    }
-  }
-
-  info->filpos += datalen;             // Update current offset
-
-  if (info->buffillen == info->buflength) // Buffer full, discard
-    return;
-
-  if (info->buflength - info->buffillen < datalen)  // Overflows buffer ?
-    datalen = info->buflength - info->buffillen;
-
-  memcpy(info->buffer + info->buffillen, data, datalen);
-  info->buffillen += datalen;
-}
-
-static int copy_info(struct info_str *info, char *fmt, ...)
-{
-        va_list args;
-        char buf[400];
-        int len;
-
-        va_start(args, fmt);
-        len = vsprintf(buf, fmt, args);
-        va_end(args);
-
-        copy_mem_info(info, buf, len);
-        return len;
-}
-
-
-// Routine to get data for /proc RAM filesystem
-//
-int cpqfcTS_proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, 
-                      int inout)
-{
-  struct scsi_cmnd *DumCmnd;
-  struct scsi_device *ScsiDev;
-  int Chan, Targ, i;
-  struct info_str info;
-  CPQFCHBA *cpqfcHBA;
-  PTACHYON fcChip;
-  PFC_LOGGEDIN_PORT pLoggedInPort;
-  char buf[81];
-
-  if (inout) return -EINVAL;
-
-  // get the pointer to our Scsi layer HBA buffer  
-  cpqfcHBA = (CPQFCHBA *)host->hostdata;
-  fcChip = &cpqfcHBA->fcChip;
-  
-  *start         = buffer;
-
-  info.buffer     = buffer;
-  info.buflength  = length;
-  info.bufoffset  = offset;
-  info.filpos     = 0;
-  info.buffillen  = 0;
-  copy_info(&info, "Driver version = %d.%d.%d", VER_MAJOR, VER_MINOR, VER_SUBMINOR); 
-  cpqfcTSDecodeGBICtype( &cpqfcHBA->fcChip, &buf[0]);
-  cpqfcTSGetLPSM( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
-  copy_info(&info, "%s\n", buf); 
-
-#define DISPLAY_WWN_INFO
-#ifdef DISPLAY_WWN_INFO
-  ScsiDev = scsi_get_host_dev (host);
-  if (!ScsiDev) 
-    return -ENOMEM;
-  DumCmnd = scsi_get_command (ScsiDev, GFP_KERNEL);
-  if (!DumCmnd) {
-    scsi_free_host_dev (ScsiDev);
-    return -ENOMEM;
-  }
-  copy_info(&info, "WWN database: (\"port_id: 000000\" means disconnected)\n");
-  for ( Chan=0; Chan <= host->max_channel; Chan++) {
-    DumCmnd->device->channel = Chan;
-    for (Targ=0; Targ <= host->max_id; Targ++) {
-      DumCmnd->device->id = Targ;
-      if ((pLoggedInPort = fcFindLoggedInPort( fcChip,
-                               DumCmnd,  // search Scsi Nexus
-                               0,        // DON'T search list for FC port id
-                               NULL,     // DON'T search list for FC WWN
-                               NULL))){   // DON'T care about end of list
-       copy_info(&info, "Host: scsi%d Channel: %02d TargetId: %02d -> WWN: ",
-                          host->host_no, Chan, Targ);
-        for( i=3; i>=0; i--)        // copy the LOGIN port's WWN
-          copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
-        for( i=7; i>3; i--)             // copy the LOGIN port's WWN
-          copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
-       copy_info(&info, " port_id: %06X\n", pLoggedInPort->port_id); 
-      }
-    }
-  }
-
-  scsi_put_command (DumCmnd);
-  scsi_free_host_dev (ScsiDev);
-#endif
-
-
-
-  
-  
-// Unfortunately, the proc_info buffer isn't big enough
-// for everything we would like...
-// For FC stats, compile this and turn off WWN stuff above  
-//#define DISPLAY_FC_STATS
-#ifdef DISPLAY_FC_STATS
-// get the Fibre Channel statistics
-  {
-    int DeltaSecs = (jiffies - cpqfcHBA->fcStatsTime) / HZ;
-    int days,hours,minutes,secs;
-    
-    days = DeltaSecs / (3600*24); // days
-    hours = (DeltaSecs% (3600*24)) / 3600; // hours
-    minutes = (DeltaSecs%3600 /60); // minutes
-    secs =  DeltaSecs%60;  // secs
-copy_info( &info, "Fibre Channel Stats (time dd:hh:mm:ss %02u:%02u:%02u:%02u\n",
-      days, hours, minutes, secs);
-  }
-    
-  cpqfcHBA->fcStatsTime = jiffies;  // (for next delta)
-
-  copy_info( &info, "  LinkUp           %9u     LinkDown      %u\n",
-        fcChip->fcStats.linkUp, fcChip->fcStats.linkDown);
-        
-  copy_info( &info, "  Loss of Signal   %9u     Loss of Sync  %u\n",
-    fcChip->fcStats.LossofSignal, fcChip->fcStats.LossofSync);
-                 
-  copy_info( &info, "  Discarded Frames %9u     Bad CRC Frame %u\n",
-    fcChip->fcStats.Dis_Frm, fcChip->fcStats.Bad_CRC);
-
-  copy_info( &info, "  TACH LinkFailTX  %9u     TACH LinkFailRX     %u\n",
-    fcChip->fcStats.linkFailTX, fcChip->fcStats.linkFailRX);
-  
-  copy_info( &info, "  TACH RxEOFa      %9u     TACH Elastic Store  %u\n",
-    fcChip->fcStats.Rx_EOFa, fcChip->fcStats.e_stores);
-
-  copy_info( &info, "  BufferCreditWait %9uus   TACH FM Inits %u\n",
-    fcChip->fcStats.BB0_Timer*10, fcChip->fcStats.FMinits );
-       
-  copy_info( &info, "  FC-2 Timeouts    %9u     FC-2 Logouts  %u\n",
-    fcChip->fcStats.timeouts, fcChip->fcStats.logouts); 
-        
-  copy_info( &info, "  FC-2 Aborts      %9u     FC-4 Aborts   %u\n",
-    fcChip->fcStats.FC2aborted, fcChip->fcStats.FC4aborted);
-   
-  // clear the counters
-  cpqfcTSClearLinkStatusCounters( fcChip);
-#endif
-       
-  return info.buffillen;
-}
-
-
-#if DEBUG_CMND
-
-UCHAR *ScsiToAscii( UCHAR ScsiCommand)
-{
-
-/*++
-
-Routine Description:
-
-   Converts a SCSI command to a text string for debugging purposes.
-
-
-Arguments:
-
-   ScsiCommand -- hex value SCSI Command
-
-
-Return Value:
-
-   An ASCII, null-terminated string if found, else returns NULL.
-
-Original code from M. McGowen, Compaq
---*/
-
-
-   switch (ScsiCommand)
-   {
-      case 0x00:
-         return( "Test Unit Ready" );
-
-      case 0x01:
-         return( "Rezero Unit or Rewind" );
-
-      case 0x02:
-         return( "Request Block Address" );
-
-      case 0x03:
-         return( "Requese Sense" );
-
-      case 0x04:
-         return( "Format Unit" );
-
-      case 0x05:
-         return( "Read Block Limits" );
-
-      case 0x07:
-         return( "Reassign Blocks" );
-
-      case 0x08:
-         return( "Read (6)" );
-
-      case 0x0a:
-         return( "Write (6)" );
-
-      case 0x0b:
-         return( "Seek (6)" );
-
-      case 0x12:
-         return( "Inquiry" );
-
-      case 0x15:
-         return( "Mode Select (6)" );
-
-      case 0x16:
-         return( "Reserve" );
-
-      case 0x17:
-         return( "Release" );
-
-      case 0x1a:
-         return( "ModeSen(6)" );
-
-      case 0x1b:
-         return( "Start/Stop Unit" );
-
-      case 0x1c:
-         return( "Receive Diagnostic Results" );
-
-      case 0x1d:
-         return( "Send Diagnostic" );
-
-      case 0x25:
-         return( "Read Capacity" );
-
-      case 0x28:
-         return( "Read (10)" );
-
-      case 0x2a:
-         return( "Write (10)" );
-
-      case 0x2b:
-         return( "Seek (10)" );
-
-      case 0x2e:
-         return( "Write and Verify" );
-
-      case 0x2f:
-         return( "Verify" );
-
-      case 0x34:
-         return( "Pre-Fetch" );
-
-      case 0x35:
-         return( "Synchronize Cache" );
-
-      case 0x37:
-         return( "Read Defect Data (10)" );
-
-      case 0x3b:
-         return( "Write Buffer" );
-
-      case 0x3c:
-         return( "Read Buffer" );
-
-      case 0x3e:
-         return( "Read Long" );
-
-      case 0x3f:
-         return( "Write Long" );
-
-      case 0x41:
-         return( "Write Same" );
-
-      case 0x4c:
-         return( "Log Select" );
-
-      case 0x4d:
-         return( "Log Sense" );
-
-      case 0x56:
-         return( "Reserve (10)" );
-
-      case 0x57:
-         return( "Release (10)" );
-
-      case 0xa0:
-         return( "ReportLuns" );
-
-      case 0xb7:
-         return( "Read Defect Data (12)" );
-
-      case 0xca:
-         return( "Peripheral Device Addressing SCSI Passthrough" );
-
-      case 0xcb:
-         return( "Compaq Array Firmware Passthrough" );
-
-      default:
-         return( NULL );
-   }
-
-} // end ScsiToAscii()
-
-void cpqfcTS_print_scsi_cmd(Scsi_Cmnd * cmd)
-{
-
-printk("cpqfcTS: (%s) chnl 0x%02x, trgt = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", 
-    ScsiToAscii( cmd->cmnd[0]), cmd->channel, cmd->target, cmd->lun, cmd->cmd_len);
-
-if( cmd->cmnd[0] == 0)   // Test Unit Ready?
-{
-  int i;
-
-  printk("Cmnd->request_bufflen = 0x%X, ->use_sg = %d, ->bufflen = %d\n",
-    cmd->request_bufflen, cmd->use_sg, cmd->bufflen);
-  printk("Cmnd->request_buffer = %p, ->sglist_len = %d, ->buffer = %p\n",
-    cmd->request_buffer, cmd->sglist_len, cmd->buffer);
-  for (i = 0; i < cmd->cmd_len; i++)
-    printk("0x%02x ", cmd->cmnd[i]);
-  printk("\n");
-}
-
-}
-
-#endif                         /* DEBUG_CMND */
-
-
-
-
-static void QueCmndOnBoardLock( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
-{
-  int i;
-
-  for( i=0; i< CPQFCTS_REQ_QUEUE_LEN; i++)
-  {    // find spare slot
-    if( cpqfcHBAdata->BoardLockCmnd[i] == NULL )
-    {
-      cpqfcHBAdata->BoardLockCmnd[i] = Cmnd;
-//      printk(" BoardLockCmnd[%d] %p Queued, chnl/target/lun %d/%d/%d\n",
-//        i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
-      break;
-    }
-  }
-  if( i >= CPQFCTS_REQ_QUEUE_LEN)
-  {
-    printk(" cpqfcTS WARNING: Lost Cmnd %p on BoardLock Q full!", Cmnd);
-  }
-
-}
-
-
-static void QueLinkDownCmnd( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
-{
-  int indx;
-
-  // Remember the command ptr so we can return; we'll complete when
-  // the device comes back, causing immediate retry
-  for( indx=0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++)//, SCptr++)
-  {
-    if( cpqfcHBAdata->LinkDnCmnd[indx] == NULL ) // available?
-    {
-#ifdef DUMMYCMND_DBG
-      printk(" @add Cmnd %p to LnkDnCmnd[%d]@ ", Cmnd,indx);
-#endif
-      cpqfcHBAdata->LinkDnCmnd[indx] = Cmnd;
-      break;
-    }
-  }
-
-  if( indx >= CPQFCTS_REQ_QUEUE_LEN ) // no space for Cmnd??
-  {
-    // this will result in an _abort call later (with possible trouble)
-    printk("no buffer for LinkDnCmnd!! %p\n", Cmnd);
-  }
-}
-
-
-
-
-
-// The file <scsi/scsi_host.h> says not to call scsi_done from
-// inside _queuecommand, so we'll do it from the heartbeat timer
-// (clarification: Turns out it's ok to call scsi_done from queuecommand 
-// for cases that don't go to the hardware like scsi cmds destined
-// for LUNs we know don't exist, so this code might be simplified...)
-
-static void QueBadTargetCmnd( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
-{
-  int i;
-    //    printk(" can't find target %d\n", Cmnd->target);
-
-  for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
-  {    // find spare slot
-    if( cpqfcHBAdata->BadTargetCmnd[i] == NULL )
-    {
-      cpqfcHBAdata->BadTargetCmnd[i] = Cmnd;
-//      printk(" BadTargetCmnd[%d] %p Queued, chnl/target/lun %d/%d/%d\n",
-//          i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
-      break;
-    }
-  }
-}
-
-
-// This is the "main" entry point for Linux Scsi commands --
-// it all starts here.
-
-int cpqfcTS_queuecommand(Scsi_Cmnd *Cmnd, void (* done)(Scsi_Cmnd *))
-{
-  struct Scsi_Host *HostAdapter = Cmnd->device->host;
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  TachFCHDR_GCMND fchs;  // only use for FC destination id field  
-  PFC_LOGGEDIN_PORT pLoggedInPort;
-  ULONG ulStatus, SESTtype;
-  LONG ExchangeID;
-
-
-
-
-  ENTER("cpqfcTS_queuecommand");
-      
-  PCI_TRACEO( (ULONG)Cmnd, 0x98)
-      
-  
-  Cmnd->scsi_done = done;
-#ifdef DEBUG_CMND  
-  cpqfcTS_print_scsi_cmd( Cmnd);
-#endif
-
-  // prevent board contention with kernel thread...  
-  
-   if( cpqfcHBAdata->BoardLock )
-  {
-//    printk(" @BrdLck Hld@ ");
-    QueCmndOnBoardLock( cpqfcHBAdata, Cmnd);
-  }
-  
-  else
-  {
-
-    // in the current system (2.2.12), this routine is called
-    // after spin_lock_irqsave(), so INTs are disabled. However,
-    // we might have something pending in the LinkQ, which
-    // might cause the WorkerTask to run.  In case that
-    // happens, make sure we lock it out.
-    
-    
-    
-    PCI_TRACE( 0x98) 
-    CPQ_SPINLOCK_HBA( cpqfcHBAdata)
-    PCI_TRACE( 0x98) 
-           
-  // can we find an FC device mapping to this SCSI target?
-    pLoggedInPort = fcFindLoggedInPort( fcChip,
-      Cmnd,     // search Scsi Nexus
-      0,        // DON'T search linked list for FC port id
-      NULL,     // DON'T search linked list for FC WWN
-      NULL);    // DON'T care about end of list
-    if( pLoggedInPort == NULL )      // not found!
-    {
-//    printk(" @Q bad targ cmnd %p@ ", Cmnd);
-      QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
-    }
-    else if (Cmnd->device->lun >= CPQFCTS_MAX_LUN)
-    {
-      printk(KERN_WARNING "cpqfc: Invalid LUN: %d\n", Cmnd->device->lun);
-      QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
-    } 
-
-    else  // we know what FC device to send to...
-    {
-
-      // does this device support FCP target functions?
-      // (determined by PRLI field)
-
-      if( !(pLoggedInPort->fcp_info & TARGET_FUNCTION) )
-      {
-        printk(" Doesn't support TARGET functions port_id %Xh\n",
-          pLoggedInPort->port_id );
-        QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
-      }
-
-    // In this case (previous login OK), the device is temporarily
-    // unavailable waiting for re-login, in which case we expect it
-    // to be back in between 25 - 500ms.  
-    // If the FC port doesn't log back in within several seconds
-    // (i.e. implicit "logout"), or we get an explicit logout,
-    // we set "device_blocked" in Scsi_Device struct; in this
-    // case 30 seconds will elapse before Linux/Scsi sends another
-    // command to the device.
-      else if( pLoggedInPort->prli != TRUE )
-      {
-//      printk("Device (Chnl/Target %d/%d) invalid PRLI, port_id %06lXh\n",
-//        Cmnd->channel, Cmnd->target, pLoggedInPort->port_id);
-        QueLinkDownCmnd( cpqfcHBAdata, Cmnd);
-//    Need to use "blocked" flag??     
-//     Cmnd->device->device_blocked = TRUE; // just let it timeout
-      }
-      else  // device supports TARGET functions, and is logged in...
-      {
-      // (context of fchs is to "reply" to...)
-        fchs.s_id = pLoggedInPort->port_id; // destination FC address
-
-      // what is the data direction?  For data TO the device,
-      // we need IWE (Intiator Write Entry).  Otherwise, IRE.
-
-        if( Cmnd->cmnd[0] == WRITE_10 ||
-         Cmnd->cmnd[0] == WRITE_6 ||
-         Cmnd->cmnd[0] == WRITE_BUFFER ||      
-         Cmnd->cmnd[0] == VENDOR_WRITE_OPCODE ||  // CPQ specific 
-         Cmnd->cmnd[0] == MODE_SELECT )
-        {
-          SESTtype = SCSI_IWE; // data from HBA to Device
-        }
-        else
-          SESTtype = SCSI_IRE; // data from Device to HBA
-         
-        ulStatus = cpqfcTSBuildExchange(
-          cpqfcHBAdata,
-          SESTtype,     // e.g. Initiator Read Entry (IRE)
-          &fchs,        // we are originator; only use d_id
-          Cmnd,         // Linux SCSI command (with scatter/gather list)
-          &ExchangeID );// fcController->fcExchanges index, -1 if failed
-
-        if( !ulStatus ) // Exchange setup?
-   
-        {
-          if( cpqfcHBAdata->BoardLock )
-          {
-    TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
-           printk(" @bl! %d, xID %Xh@ ", current->pid, ExchangeID);
-          }
-
-         ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
-         if( !ulStatus )
-          {
-            PCI_TRACEO( ExchangeID, 0xB8) 
-          // submitted to Tach's Outbound Que (ERQ PI incremented)
-          // waited for completion for ELS type (Login frames issued
-          // synchronously)
-         }
-          else
-            // check reason for Exchange not being started - we might
-            // want to Queue and start later, or fail with error
-          {
-            printk("quecommand: cpqfcTSStartExchange failed: %Xh\n", ulStatus );
-          }
-        }            // end good BuildExchange status
-        
-        else  // SEST table probably full  -- why? hardware hang?
-        {
-         printk("quecommand: cpqfcTSBuildExchange faild: %Xh\n", ulStatus);
-        }
-      }  // end can't do FCP-SCSI target functions
-    } // end can't find target (FC device)
-
-    CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
-  }
-       
-  PCI_TRACEO( (ULONG)Cmnd, 0x9C) 
-  LEAVE("cpqfcTS_queuecommand");
-  return 0;
-}    
-
-
-// Entry point for upper Scsi layer intiated abort.  Typically
-// this is called if the command (for hard disk) fails to complete
-// in 30 seconds.  This driver intends to complete all disk commands
-// within Exchange ".timeOut" seconds (now 7) with target status, or
-// in case of ".timeOut" expiration, a DID_SOFT_ERROR which causes
-// immediate retry.
-// If any disk commands get the _abort call, except for the case that
-// the physical device was removed or unavailable due to hardware
-// errors, it should be considered a driver error and reported to
-// the author.
-
-int cpqfcTS_abort(Scsi_Cmnd *Cmnd)
-{
-//     printk(" cpqfcTS_abort called?? \n");
-       return 0;
-}
-int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd)
-{
-
-  struct Scsi_Host *HostAdapter = Cmnd->device->host;
-  // get the pointer to our Scsi layer HBA buffer  
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  int i;
-  ENTER("cpqfcTS_eh_abort");
-
-  Cmnd->result = DID_ABORT <<16;  // assume we'll find it
-
-  printk(" @Linux _abort Scsi_Cmnd %p ", Cmnd);
-  // See if we can find a Cmnd pointer that matches...
-  // The most likely case is we accepted the command
-  // from Linux Scsi (e.g. ceated a SEST entry) and it
-  // got lost somehow.  If we can't find any reference
-  // to the passed pointer, we can only presume it
-  // got completed as far as our driver is concerned.
-  // If we found it, we will try to abort it through
-  // common mechanism.  If FC ABTS is successful (ACC)
-  // or is rejected (RJT) by target, we will call
-  // Scsi "done" quickly.  Otherwise, the ABTS will timeout
-  // and we'll call "done" later.
-
-  // Search the SEST exchanges for a matching Cmnd ptr.
-  for( i=0; i< TACH_SEST_LEN; i++)
-  {
-    if( Exchanges->fcExchange[i].Cmnd == Cmnd )
-    {
-      
-      // found it!
-      printk(" x_ID %Xh, type %Xh\n", i, Exchanges->fcExchange[i].type);
-
-      Exchanges->fcExchange[i].status = INITIATOR_ABORT; // seconds default
-      Exchanges->fcExchange[i].timeOut = 10; // seconds default (changed later)
-
-      // Since we need to immediately return the aborted Cmnd to Scsi 
-      // upper layers, we can't make future reference to any of its 
-      // fields (e.g the Nexus).
-
-      cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &i);
-
-      break;
-    }
-  }
-
-  if( i >= TACH_SEST_LEN ) // didn't find Cmnd ptr in chip's SEST?
-  {
-    // now search our non-SEST buffers (i.e. Cmnd waiting to
-    // start on the HBA or waiting to complete with error for retry).
-    
-    // first check BadTargetCmnd
-    for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
-    { 
-      if( cpqfcHBAdata->BadTargetCmnd[i] == Cmnd )
-      {
-        cpqfcHBAdata->BadTargetCmnd[i] = NULL;
-       printk("in BadTargetCmnd Q\n");
-       goto Done; // exit
-      }
-    }
-
-    // if not found above...
-
-    for( i=0; i < CPQFCTS_REQ_QUEUE_LEN; i++)
-    {
-      if( cpqfcHBAdata->LinkDnCmnd[i] == Cmnd ) 
-      {
-       cpqfcHBAdata->LinkDnCmnd[i] = NULL;
-       printk("in LinkDnCmnd Q\n");
-       goto Done;
-      }
-    }
-
-
-    for( i=0; i< CPQFCTS_REQ_QUEUE_LEN; i++)
-    {    // find spare slot
-      if( cpqfcHBAdata->BoardLockCmnd[i] == Cmnd )
-      {
-        cpqfcHBAdata->BoardLockCmnd[i] = NULL;
-       printk("in BoardLockCmnd Q\n");
-       goto Done;
-      }
-    }
-    
-    Cmnd->result = DID_ERROR <<16;  // Hmmm...
-    printk("Not found! ");
-//    panic("_abort");
-  }
-  
-Done:
-  
-//    panic("_abort");
-  LEAVE("cpqfcTS_eh_abort");
-  return 0;  // (see scsi.h)
-}    
-
-
-// FCP-SCSI Target Device Reset
-// See dpANS Fibre Channel Protocol for SCSI
-// X3.269-199X revision 12, pg 25
-
-#ifdef SUPPORT_RESET
-
-int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, 
-                               unsigned int reset_flags)
-{
-  int timeout = 10*HZ;
-  int retries = 1;
-  char scsi_cdb[12];
-  int result;
-  Scsi_Cmnd * SCpnt;
-  Scsi_Device * SDpnt;
-
-// FIXME, cpqfcTS_TargetDeviceReset needs to be fixed 
-// similarly to how the passthrough ioctl was fixed 
-// around the 2.5.30 kernel.  Scsi_Cmnd replaced with 
-// Scsi_Request, etc.
-// For now, so people don't fall into a hole...
-
-  // printk("   ENTERING cpqfcTS_TargetDeviceReset() - flag=%d \n",reset_flags);
-
-  if (ScsiDev->host->eh_active) return FAILED;
-
-  memset( scsi_cdb, 0, sizeof( scsi_cdb));
-
-  scsi_cdb[0] = RELEASE;
-
-  SCpnt = scsi_get_command(ScsiDev, GFP_KERNEL);
-  {
-    CPQFC_DECLARE_COMPLETION(wait);
-    
-    SCpnt->SCp.buffers_residual = FCP_TARGET_RESET;
-
-       // FIXME: this would panic, SCpnt->request would be NULL.
-       SCpnt->request->CPQFC_WAITING = &wait;
-       scsi_do_cmd(SCpnt,  scsi_cdb, NULL,  0, my_ioctl_done,  timeout, retries);
-       CPQFC_WAIT_FOR_COMPLETION(&wait);
-       SCpnt->request->CPQFC_WAITING = NULL;
-  }
-    
-
-      if(driver_byte(SCpnt->result) != 0)
-         switch(SCpnt->sense_buffer[2] & 0xf) {
-       case ILLEGAL_REQUEST:
-           if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0;
-           else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
-           break;
-       case NOT_READY: // This happens if there is no disc in drive 
-           if(dev->removable && (cmd[0] != TEST_UNIT_READY)){
-               printk(KERN_INFO "Device not ready.  Make sure there is a disc in the drive.\n");
-               break;
-           }
-       case UNIT_ATTENTION:
-           if (dev->removable){
-               dev->changed = 1;
-               SCpnt->result = 0; // This is no longer considered an error
-               // gag this error, VFS will log it anyway /axboe 
-               // printk(KERN_INFO "Disc change detected.\n"); 
-               break;
-           };
-       default: // Fall through for non-removable media
-           printk("SCSI error: host %d id %d lun %d return code = %x\n",
-                  dev->host->host_no,
-                  dev->id,
-                  dev->lun,
-                  SCpnt->result);
-           printk("\tSense class %x, sense error %x, extended sense %x\n",
-                  sense_class(SCpnt->sense_buffer[0]),
-                  sense_error(SCpnt->sense_buffer[0]),
-                  SCpnt->sense_buffer[2] & 0xf);
-           
-      };
-  result = SCpnt->result;
-
-  SDpnt = SCpnt->device;
-  scsi_put_command(SCpnt);
-  SCpnt = NULL;
-
-  // printk("   LEAVING cpqfcTS_TargetDeviceReset() - return SUCCESS \n");
-  return SUCCESS;
-}
-
-#else
-int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, 
-                               unsigned int reset_flags)
-{
-       return -ENOTSUPP;
-}
-
-#endif /* SUPPORT_RESET */
-
-int cpqfcTS_eh_device_reset(Scsi_Cmnd *Cmnd)
-{
-  int retval;
-  Scsi_Device *SDpnt = Cmnd->device;
-  // printk("   ENTERING cpqfcTS_eh_device_reset() \n");
-  spin_unlock_irq(Cmnd->device->host->host_lock);
-  retval = cpqfcTS_TargetDeviceReset( SDpnt, 0);
-  spin_lock_irq(Cmnd->device->host->host_lock);
-  return retval;
-}
-
-       
-int cpqfcTS_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags)
-{
-
-  ENTER("cpqfcTS_reset");
-
-  LEAVE("cpqfcTS_reset");
-  return SCSI_RESET_ERROR;      /* Bus Reset Not supported */
-}
-
-/* This function determines the bios parameters for a given
-   harddisk. These tend to be numbers that are made up by the
-   host adapter.  Parameters:
-   size, device number, list (heads, sectors,cylinders).
-   (from hosts.h)
-*/
-
-int cpqfcTS_biosparam(struct scsi_device *sdev, struct block_device *n,
-               sector_t capacity, int ip[])
-{
-  int size = capacity;
-  
-  ENTER("cpqfcTS_biosparam");
-  ip[0] = 64;
-  ip[1] = 32;
-  ip[2] = size >> 11;
-  
-  if( ip[2] > 1024 )
-  {
-    ip[0] = 255;
-    ip[1] = 63;
-    ip[2] = size / (ip[0] * ip[1]);
-  }
-
-  LEAVE("cpqfcTS_biosparam");
-  return 0;
-}    
-
-
-
-irqreturn_t cpqfcTS_intr_handler( int irq, 
-               void *dev_id, 
-               struct pt_regs *regs)
-{
-
-  unsigned long flags, InfLoopBrk=0;
-  struct Scsi_Host *HostAdapter = dev_id;
-  CPQFCHBA *cpqfcHBA = (CPQFCHBA *)HostAdapter->hostdata;
-  int MoreMessages = 1; // assume we have something to do
-  UCHAR IntPending;
-  int handled = 0;
-
-  ENTER("intr_handler");
-  spin_lock_irqsave( HostAdapter->host_lock, flags);
-  // is this our INT?
-  IntPending = readb( cpqfcHBA->fcChip.Registers.INTPEND.address);
-
-  // broken boards can generate messages forever, so
-  // prevent the infinite loop
-#define INFINITE_IMQ_BREAK 10000
-  if( IntPending )
-  {
-    handled = 1;
-    // mask our HBA interrupts until we handle it...
-    writeb( 0, cpqfcHBA->fcChip.Registers.INTEN.address);
-
-    if( IntPending & 0x4) // "INT" - Tach wrote to IMQ
-    {
-      while( (++InfLoopBrk < INFINITE_IMQ_BREAK) && (MoreMessages ==1) ) 
-      {
-        MoreMessages = CpqTsProcessIMQEntry( HostAdapter); // ret 0 when done
-      }
-      if( InfLoopBrk >= INFINITE_IMQ_BREAK )
-      {
-        printk("WARNING: Compaq FC adapter generating excessive INTs -REPLACE\n");
-        printk("or investigate alternate causes (e.g. physical FC layer)\n");
-      }
-
-      else  // working normally - re-enable INTs and continue
-        writeb( 0x1F, cpqfcHBA->fcChip.Registers.INTEN.address);
-    
-    }  // (...ProcessIMQEntry() clears INT by writing IMQ consumer)
-    else  // indications of errors or problems...
-          // these usually indicate critical system hardware problems.
-    {
-      if( IntPending & 0x10 )
-       printk(" cpqfcTS adapter external memory parity error detected\n");
-      if( IntPending & 0x8 )
-       printk(" cpqfcTS adapter PCI master address crossed 45-bit boundary\n");
-      if( IntPending & 0x2 )
-       printk(" cpqfcTS adapter DMA error detected\n");
-      if( IntPending & 0x1 ) {
-       UCHAR IntStat;
-       printk(" cpqfcTS adapter PCI error detected\n");
-       IntStat = readb( cpqfcHBA->fcChip.Registers.INTSTAT.address);
-       printk("cpqfc: ISR = 0x%02x\n", IntStat);
-       if (IntStat & 0x1) {
-               __u16 pcistat;
-               /* read the pci status register */
-               pci_read_config_word(cpqfcHBA->PciDev, 0x06, &pcistat);
-               printk("PCI status register is 0x%04x\n", pcistat);
-               if (pcistat & 0x8000) printk("Parity Error Detected.\n");
-               if (pcistat & 0x4000) printk("Signalled System Error\n");
-               if (pcistat & 0x2000) printk("Received Master Abort\n");
-               if (pcistat & 0x1000) printk("Received Target Abort\n");
-               if (pcistat & 0x0800) printk("Signalled Target Abort\n");
-       }
-       if (IntStat & 0x4) printk("(INT)\n");
-       if (IntStat & 0x8) 
-               printk("CRS: PCI master address crossed 46 bit bouandary\n");
-       if (IntStat & 0x10) printk("MRE: external memory parity error.\n");
-      }
-    }      
-  }
-  spin_unlock_irqrestore( HostAdapter->host_lock, flags);
-  LEAVE("intr_handler");
-  return IRQ_RETVAL(handled);
-}
-
-
-
-
-int cpqfcTSDecodeGBICtype( PTACHYON fcChip, char cErrorString[])
-{
-        // Verify GBIC type (if any) and correct Tachyon Port State Machine
-        // (GBIC) module definition is:
-        // GPIO1, GPIO0, GPIO4 for MD2, MD1, MD0.  The input states appear
-        // to be inverted -- i.e., a setting of 111 is read when there is NO
-        // GBIC present.  The Module Def (MD) spec says 000 is "no GBIC"
-        // Hard code the bit states to detect Copper, 
-        // Long wave (single mode), Short wave (multi-mode), and absent GBIC
-
-  ULONG ulBuff;
-
-  sprintf( cErrorString, "\nGBIC detected: ");
-
-  ulBuff = fcChip->Registers.TYstatus.value & 0x13; 
-  switch( ulBuff )
-  {
-  case 0x13:  // GPIO4, GPIO1, GPIO0 = 111; no GBIC!
-    sprintf( &cErrorString[ strlen( cErrorString)],
-            "NONE! ");
-    return FALSE;          
-          
-       
-  case 0x11:   // Copper GBIC detected
-    sprintf( &cErrorString[ strlen( cErrorString)],
-            "Copper. ");
-    break;
-
-  case 0x10:   // Long-wave (single mode) GBIC detected
-    sprintf( &cErrorString[ strlen( cErrorString)],
-        "Long-wave. ");
-    break;
-  case 0x1:    // Short-wave (multi mode) GBIC detected
-    sprintf( &cErrorString[ strlen( cErrorString)],
-        "Short-wave. ");
-    break;
-  default:     // unknown GBIC - presumably it will work (?)
-    sprintf( &cErrorString[ strlen( cErrorString)],
-            "Unknown. ");
-          
-    break;
-  }  // end switch GBIC detection
-
-  return TRUE;
-}
-
-
-
-
-
-
-int cpqfcTSGetLPSM( PTACHYON fcChip, char cErrorString[])
-{
-  // Tachyon's Frame Manager LPSM in LinkDown state?
-  // (For non-loop port, check PSM instead.)
-  // return string with state and FALSE is Link Down
-
-  int LinkUp;
-
-  if( fcChip->Registers.FMstatus.value & 0x80 ) 
-    LinkUp = FALSE;
-  else
-    LinkUp = TRUE;
-
-  sprintf( &cErrorString[ strlen( cErrorString)],
-    " LPSM %Xh ", 
-     (fcChip->Registers.FMstatus.value >>4) & 0xf );
-
-
-  switch( fcChip->Registers.FMstatus.value & 0xF0)
-  {
-                    // bits set in LPSM
-    case 0x10:
-      sprintf( &cErrorString[ strlen( cErrorString)], "ARB");
-      break;
-    case 0x20:
-      sprintf( &cErrorString[ strlen( cErrorString)], "ARBwon");
-      break;
-    case 0x30:
-      sprintf( &cErrorString[ strlen( cErrorString)], "OPEN");
-      break;
-    case 0x40:
-      sprintf( &cErrorString[ strlen( cErrorString)], "OPENed");
-      break;
-    case 0x50:
-      sprintf( &cErrorString[ strlen( cErrorString)], "XmitCLS");
-      break;
-    case 0x60:
-      sprintf( &cErrorString[ strlen( cErrorString)], "RxCLS");
-      break;
-    case 0x70:
-      sprintf( &cErrorString[ strlen( cErrorString)], "Xfer");
-      break;
-    case 0x80:
-      sprintf( &cErrorString[ strlen( cErrorString)], "Init");
-      break;
-    case 0x90:
-      sprintf( &cErrorString[ strlen( cErrorString)], "O-IInitFin");
-      break;
-    case 0xa0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "O-IProtocol");
-      break;
-    case 0xb0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "O-ILipRcvd");
-      break;
-    case 0xc0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "HostControl");
-      break;
-    case 0xd0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "LoopFail");
-      break;
-    case 0xe0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "Offline");
-      break;
-    case 0xf0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "OldPort");
-      break;
-    case 0:
-    default:
-      sprintf( &cErrorString[ strlen( cErrorString)], "Monitor");
-      break;
-
-  }
-
-  return LinkUp;
-}
-
-
-
-
-#include "linux/slab.h"
-
-// Dynamic memory allocation alignment routines
-// HP's Tachyon Fibre Channel Controller chips require
-// certain memory queues and register pointers to be aligned
-// on various boundaries, usually the size of the Queue in question.
-// Alignment might be on 2, 4, 8, ... or even 512 byte boundaries.
-// Since most O/Ss don't allow this (usually only Cache aligned -
-// 32-byte boundary), these routines provide generic alignment (after
-// O/S allocation) at any boundary, and store the original allocated
-// pointer for deletion (O/S free function).  Typically, we expect
-// these functions to only be called at HBA initialization and
-// removal time (load and unload times)
-// ALGORITHM notes:
-// Memory allocation varies by compiler and platform.  In the worst case,
-// we are only assured BYTE alignment, but in the best case, we can
-// request allocation on any desired boundary.  Our strategy: pad the
-// allocation request size (i.e. waste memory) so that we are assured
-// of passing desired boundary near beginning of contiguous space, then
-// mask out lower address bits.
-// We define the following algorithm:
-//   allocBoundary - compiler/platform specific address alignment
-//                   in number of bytes (default is single byte; i.e. 1)
-//   n_alloc       - number of bytes application wants @ aligned address
-//   ab            - alignment boundary, in bytes (e.g. 4, 32, ...)
-//   t_alloc       - total allocation needed to ensure desired boundary
-//   mask          - to clear least significant address bits for boundary
-//   Compute:
-//   t_alloc = n_alloc + (ab - allocBoundary)
-//   allocate t_alloc bytes @ alloc_address
-//   mask =  NOT (ab - 1)
-//       (e.g. if ab=32  _0001 1111  -> _1110 0000
-//   aligned_address = alloc_address & mask
-//   set n_alloc bytes to 0
-//   return aligned_address (NULL if failed)
-//
-// If u32_AlignedAddress is non-zero, then search for BaseAddress (stored
-// from previous allocation).  If found, invoke call to FREE the memory.
-// Return NULL if BaseAddress not found
-
-// we need about 8 allocations per HBA.  Figuring at most 10 HBAs per server
-// size the dynamic_mem array at 80.
-
-void* fcMemManager( struct pci_dev *pdev, ALIGNED_MEM *dynamic_mem, 
-                  ULONG n_alloc, ULONG ab, ULONG u32_AlignedAddress,
-                       dma_addr_t *dma_handle)
-{
-  USHORT allocBoundary=1;   // compiler specific - worst case 1
-                                  // best case - replace malloc() call
-                                  // with function that allocates exactly
-                                  // at desired boundary
-
-  unsigned long ulAddress;
-  ULONG t_alloc, i;
-  void *alloc_address = 0;  // def. error code / address not found
-  LONG mask;                // must be 32-bits wide!
-
-  ENTER("fcMemManager");
-  if( u32_AlignedAddress )          // are we freeing existing memory?
-  {
-//    printk(" freeing AlignedAddress %Xh\n", u32_AlignedAddress);
-    for( i=0; i<DYNAMIC_ALLOCATIONS; i++) // look for the base address
-    {
-//    printk("dynamic_mem[%u].AlignedAddress %lX\n", i, dynamic_mem[i].AlignedAddress);
-      if( dynamic_mem[i].AlignedAddress == u32_AlignedAddress )
-      {
-        alloc_address = dynamic_mem[i].BaseAllocated; // 'success' status
-       pci_free_consistent(pdev,dynamic_mem[i].size, 
-                               alloc_address, 
-                               dynamic_mem[i].dma_handle);
-        dynamic_mem[i].BaseAllocated = 0;   // clear for next use
-        dynamic_mem[i].AlignedAddress = 0;
-        dynamic_mem[i].size = 0;
-        break;                        // quit for loop; done
-      }
-    }
-  }
-  else if( n_alloc )                   // want new memory?
-  {
-    dma_addr_t handle;
-    t_alloc = n_alloc + (ab - allocBoundary); // pad bytes for alignment
-//    printk("pci_alloc_consistent() for Tach alignment: %ld bytes\n", t_alloc);
-
-// (would like to) allow thread block to free pages 
-    alloc_address =                  // total bytes (NumberOfBytes)
-      pci_alloc_consistent(pdev, t_alloc, &handle); 
-
-                                  // now mask off least sig. bits of address
-    if( alloc_address )           // (only if non-NULL)
-    {
-                                  // find place to store ptr, so we
-                                  // can free it later...
-
-      mask = (LONG)(ab - 1);            // mask all low-order bits
-      mask = ~mask;                            // invert bits
-      for( i=0; i<DYNAMIC_ALLOCATIONS; i++) // look for free slot
-      {
-        if( dynamic_mem[i].BaseAllocated == 0) // take 1st available
-        {
-          dynamic_mem[i].BaseAllocated = alloc_address;// address from O/S
-          dynamic_mem[i].dma_handle = handle;
-         if (dma_handle != NULL) 
-         {
-//             printk("handle = %p, ab=%d, boundary = %d, mask=0x%08x\n", 
-//                     handle, ab, allocBoundary, mask);
-           *dma_handle = (dma_addr_t) 
-               ((((ULONG)handle) + (ab - allocBoundary)) & mask);
-         }
-          dynamic_mem[i].size = t_alloc;
-          break;
-        }
-      }
-      ulAddress = (unsigned long)alloc_address;
-      
-      ulAddress += (ab - allocBoundary);    // add the alignment bytes-
-                                            // then truncate address...
-      alloc_address = (void*)(ulAddress & mask);
-      
-      dynamic_mem[i].AlignedAddress = 
-       (ULONG)(ulAddress & mask); // 32bit Tach address
-      memset( alloc_address, 0, n_alloc );  // clear new memory
-    }
-    else  // O/S dynamic mem alloc failed!
-      alloc_address = 0;  // (for debugging breakpt)
-
-  }
-
-  LEAVE("fcMemManager");
-  return alloc_address;  // good (or NULL) address
-}
-
-
-static Scsi_Host_Template driver_template = {
-       .detect                 = cpqfcTS_detect,
-       .release                = cpqfcTS_release,
-       .info                   = cpqfcTS_info,
-       .proc_info              = cpqfcTS_proc_info,
-       .ioctl                  = cpqfcTS_ioctl,
-       .queuecommand           = cpqfcTS_queuecommand,
-       .eh_device_reset_handler   = cpqfcTS_eh_device_reset,
-       .eh_abort_handler       = cpqfcTS_eh_abort, 
-       .bios_param             = cpqfcTS_biosparam, 
-       .can_queue              = CPQFCTS_REQ_QUEUE_LEN,
-       .this_id                = -1, 
-       .sg_tablesize           = SG_ALL, 
-       .cmd_per_lun            = CPQFCTS_CMD_PER_LUN,
-       .use_clustering         = ENABLE_CLUSTERING,
-};
-#include "scsi_module.c"
-
diff --git a/drivers/scsi/cpqfcTSioctl.h b/drivers/scsi/cpqfcTSioctl.h
deleted file mode 100644 (file)
index 8255369..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-// for user apps, make sure data size types are defined
-// with 
-
-
-#define CCPQFCTS_IOC_MAGIC 'Z'
-
-typedef struct 
-{
-  __u8 bus;
-  __u8 dev_fn;
-  __u32 board_id;
-} cpqfc_pci_info_struct;
-
-typedef __u32 DriverVer_type;
-/*
-typedef union
-{
-  struct  // Peripheral Unit Device
-  { 
-    __u8 Bus:6;
-    __u8 Mode:2;  // b00
-    __u8 Dev;
-  } PeripDev;
-  struct  // Volume Set Address
-  { 
-    __u8 DevMSB:6;
-    __u8 Mode:2;  // b01
-    __u8 DevLSB;
-  } LogDev;
-  struct  // Logical Unit Device (SCSI-3, SCC-2 defined)
-  { 
-    __u8 Targ:6;
-    __u8 Mode:2;  // b10
-    __u8 Dev:5;
-    __u8 Bus:3;
-
-  } LogUnit;
-} SCSI3Addr_struct;
-
-
-typedef struct
-{
-  SCSI3Addr_struct FCP_Nexus;
-  __u8 cdb[16];
-} PassThru_Command_struct;
-*/
-
-/* this is nearly duplicated in idashare.h */
-typedef struct {
-  int  lc;             /* Controller number */
-  int  node;           /* Node (box) number */
-  int  ld;             /* Logical Drive on this box, if required */
-  __u32 nexus;          /* SCSI Nexus */
-  void *argp;          /* Argument pointer */
-} VENDOR_IOCTL_REQ;
-
-
-typedef struct {
-  char cdb[16];        /* SCSI CDB for the pass-through */
-  ushort bus;          /* Target bus on the box */
-  ushort pdrive;       /* Physical drive on the box */
-  int len;              /* Length of the data area of the CDB */
-  int sense_len;       /* Length of the sense data */
-  char sense_data[40];  /* Sense data */
-  void *bufp;          /* Data area for the CDB */
-  char rw_flag;                /* Read CDB or Write CDB */
-} cpqfc_passthru_t;
-
-/*
-** Defines for the IOCTLS.
-*/
-
-#define VENDOR_READ_OPCODE                     0x26
-#define VENDOR_WRITE_OPCODE                    0x27
-
-#define CPQFCTS_GETPCIINFO _IOR( CCPQFCTS_IOC_MAGIC, 1, cpqfc_pci_info_struct)
-#define CPQFCTS_GETDRIVVER _IOR( CCPQFCTS_IOC_MAGIC, 9, DriverVer_type)
-
-#define CPQFCTS_SCSI_PASSTHRU _IOWR( CCPQFCTS_IOC_MAGIC,11, VENDOR_IOCTL_REQ)
-
-/* We would rather have equivalent generic, low-level driver agnostic 
-ioctls that do what CPQFC_IOCTL_FC_TARGET_ADDRESS and 
-CPQFC_IOCTL_FC_TDR 0x5388 do, but currently, we do not have them, 
-consequently applications would have to know they are talking to cpqfc. */
-   
-/* Used to get Fibre Channel WWN and port_id from device */
-// #define CPQFC_IOCTL_FC_TARGET_ADDRESS 0x5387
-#define CPQFC_IOCTL_FC_TARGET_ADDRESS \
-       _IOR( CCPQFCTS_IOC_MAGIC, 13, Scsi_FCTargAddress)
-
-/* Used to invoke Target Defice Reset for Fibre Channel */
-// #define CPQFC_IOCTL_FC_TDR 0x5388
-#define CPQFC_IOCTL_FC_TDR _IO( CCPQFCTS_IOC_MAGIC, 15)
-
diff --git a/drivers/scsi/cpqfcTSstructs.h b/drivers/scsi/cpqfcTSstructs.h
deleted file mode 100644 (file)
index 0bae329..0000000
+++ /dev/null
@@ -1,1530 +0,0 @@
-/* Copyright(c) 2000, Compaq Computer Corporation
- * Fibre Channel Host Bus Adapter 64-bit, 66MHz PCI 
- * Originally developed and tested on:
- * (front): [chip] Tachyon TS HPFC-5166A/1.2  L2C1090 ...
- *          SP# P225CXCBFIEL6T, Rev XC
- *          SP# 161290-001, Rev XD
- * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
- *  
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- * Written by Don Zimmerman
-*/
-#ifndef CPQFCTSSTRUCTS_H
-#define CPQFCTSSTRUCTS_H
-
-#include <linux/timer.h>  // timer declaration in our host data
-#include <linux/interrupt.h>
-#include <asm/atomic.h>
-#include "cpqfcTSioctl.h"
-
-#define DbgDelay(secs) { int wait_time; printk( " DbgDelay %ds ", secs); \
-                         for( wait_time=jiffies + (secs*HZ); \
-                        time_before(jiffies, wait_time) ;) ; }
-
-#define CPQFCTS_DRIVER_VER(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-// don't forget to also change MODULE_DESCRIPTION in cpqfcTSinit.c
-#define VER_MAJOR 2
-#define VER_MINOR 5
-#define VER_SUBMINOR 4
-
-// Macros for kernel (esp. SMP) tracing using a PCI analyzer
-// (e.g. x86).
-//#define PCI_KERNEL_TRACE
-#ifdef PCI_KERNEL_TRACE
-#define PCI_TRACE(x) inl( fcChip->Registers.IOBaseL +x);
-#define PCI_TRACEO(x,y) outl( x, (fcChip->Registers.IOBaseL +y));
-#else
-
-#define PCI_TRACE(x) 
-#define PCI_TRACEO(x,y)
-#endif
-
-                        
-//#define DEBUG_CMND 1   // debug output for Linux Scsi CDBs
-//#define DUMMYCMND_DBG 1
-
-//#define DEBUG_CPQFCTS 1
-//#undef DEBUG_CPQFCTS 
-#ifdef DEBUG_CPQFCTS
-#define ENTER(x)       printk("cpqfcts : entering %s()\n", x);
-#define LEAVE(x)       printk("cpqfcts : leaving %s()\n", x);
-#define DEBUG(x)       x
-#else
-#define ENTER(x)
-#define LEAVE(x)
-#define DEBUG(x)
-#endif                         /* DEBUG_CPQFCTS */
-
-//#define DEBUG_CPQFCTS_PCI 1
-//#undef DEBUG_CPQFCTS_PCI
-#if DEBUG_CPQFCTS_PCI
-#define DEBUG_PCI(x)   x
-#else
-#define DEBUG_PCI(x)
-#endif                         /* DEBUG_CPQFCTS_PCI */
-
-#define STACHLITE66_TS12  "Compaq FibreChannel HBA Tachyon TS HPFC-5166A/1.2"
-#define STACHLITE66_TS13  "Compaq FibreChannel HBA Tachyon TS HPFC-5166A/1.3"
-#define STACHLITE_UNKNOWN "Compaq FibreChannel HBA Tachyon Chip/Board Ver??"
-#define SAGILENT_XL2_21   "Agilent FC HBA, Tachyon XL2 HPFC-5200B/2.1"
-
-// PDA is Peripheral Device Address, VSA is Volume Set Addressing
-// Linux SCSI parameters
-#define CPQFCTS_MAX_TARGET_ID 64
-
-// Note, changing CPQFCTS_MAX_LUN to less than 32 (e.g, 8) will result in
-// strange behavior if a box with more than, e.g. 8, is on the loop.
-#define CPQFCTS_MAX_LUN 32    // The RA-4x00 supports 32 (Linux SCSI supports 8)
-#define CPQFCTS_MAX_CHANNEL 0 // One FC port on cpqfcTS HBA
-
-#define CPQFCTS_CMD_PER_LUN 15 // power of 2 -1, must be >0 
-#define CPQFCTS_REQ_QUEUE_LEN (TACH_SEST_LEN/2) // must be < TACH_SEST_LEN
-
-#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
-#ifndef DECLARE_MUTEX_LOCKED
-#define DECLARE_MUTEX_LOCKED(sem) struct semaphore sem = MUTEX_LOCKED
-#endif
-
-#define DEV_NAME "cpqfcTS"
-
-struct SupportedPCIcards
-{
-  __u16 vendor_id;
-  __u16 device_id;
-};
-                        
-// nn:nn denotes bit field
-                            // TachyonHeader struct def.
-                            // the fields shared with ODB
-                            // need to have same value
-
-
-
-
-#ifndef BYTE
-//typedef UCHAR BYTE;
-typedef __u8 BYTE;
-#endif
-#ifndef UCHAR
-typedef __u8 UCHAR;
-#endif
-#ifndef LONG
-typedef __s32 LONG;
-#endif
-#ifndef ULONG
-typedef __u32 ULONG;
-#endif
-#ifndef PVOID
-typedef void * PVOID;
-#endif
-#ifndef USHORT
-typedef __u16 USHORT;
-#endif
-#ifndef BOOLEAN
-typedef __u8 BOOLEAN;
-#endif
-
-
-// macro for FC-PH reject codes
-// payload format for LS_RJT (FC payloads are big endian):
-//     byte  0         1         2         3  (MSB)
-// DWORD 0   01        00        00        00
-// DWORD 1   resvd     code      expl.     vendor
-
-#define LS_RJT_REASON( code, expl) (( code<<8) | (expl <<16))
-
-
-#define TachLiteSTATUS 0x12
-
-// Fibre Channel EXCHANGE status codes for Tachyon chips/ driver software
-// 32-bit ERROR word defines
-#define INVALID_ARGS 0x1
-#define LNKDWN_OSLS  0x2
-#define LNKDWN_LASER 0x4
-#define OUTQUE_FULL  0x8
-#define DRIVERQ_FULL 0x10
-#define SEST_FULL    0x20
-#define BAD_ALPA     0x40
-#define OVERFLOW     0x80  // inbound CM
-#define COUNT_ERROR     0x100  // inbound CM
-#define LINKFAIL_RX     0x200  // inbound CM
-#define ABORTSEQ_NOTIFY 0x400  // outbound CM
-#define LINKFAIL_TX     0x800  // outbound CM
-#define HOSTPROG_ERR     0x1000  // outbound CM
-#define FRAME_TO         0x2000  // outbound CM
-#define INV_ENTRY        0x4000  // outbound CM
-#define SESTPROG_ERR     0x8000  // outbound CM
-#define OUTBOUND_TIMEOUT 0x10000L // timeout waiting for Tachyon outbound CM
-#define INITIATOR_ABORT  0x20000L // initiator exchange timeout or O/S ABORT
-#define MEMPOOL_FAIL     0x40000L // O/S memory pool allocation failed
-#define FC2_TIMEOUT      0x80000L // driver timeout for lost frames
-#define TARGET_ABORT     0x100000L // ABTS received from FC port
-#define EXCHANGE_QUEUED  0x200000L // e.g. Link State was LDn on fcStart
-#define PORTID_CHANGED   0x400000L // fc Port address changed
-#define DEVICE_REMOVED   0x800000L // fc Port address changed
-// Several error scenarios result in SEST Exchange frames 
-// unexpectedly arriving in the SFQ
-#define SFQ_FRAME        0x1000000L // SFQ frames from open Exchange
-
-// Maximum number of Host Bus Adapters (HBA) / controllers supported
-// only important for mem allocation dimensions - increase as necessary
-
-#define MAX_ADAPTERS 8
-#define MAX_RX_PAYLOAD 1024  // hardware dependent max frame payload
-// Tach header struc defines
-#define SOFi3 0x7
-#define SOFf  0x8
-#define SOFn3 0xB
-#define EOFn  0x5
-#define EOFt  0x6
-
-// FCP R_CTL defines
-#define FCP_CMND 0x6
-#define FCP_XFER_RDY 0x5
-#define FCP_RSP 0x7
-#define FCP_RESPONSE 0x777 // (arbitrary #)
-#define NEED_FCP_RSP 0x77  // (arbitrary #)
-#define FCP_DATA 0x1
-
-#define RESET_TACH 0x100 // Reset Tachyon/TachLite
-#define SCSI_IWE 0x2000  // initiator write entry (for SEST)
-#define SCSI_IRE 0x3000  // initiator read entry (for SEST)
-#define SCSI_TRE 0x400  // target read entry (for SEST)
-#define SCSI_TWE 0x500  // target write entry (for SEST)
-#define TOGGLE_LASER 0x800
-#define LIP 0x900
-#define CLEAR_FCPORTS 99 // (arbitrary #) free mem for Logged in ports
-#define FMINIT 0x707     // (arbitrary) for Frame Manager Init command
-
-// BLS == Basic Link Service
-// ELS == Extended Link Service
-#define BLS_NOP 4
-#define BLS_ABTS 0x10   // FC-PH Basic Link Service Abort Sequence
-#define BLS_ABTS_ACC 0x100  // FC-PH Basic Link Service Abort Sequence Accept
-#define BLS_ABTS_RJT 0x101  // FC-PH Basic Link Service Abort Sequence Reject
-#define ELS_PLOGI 0x03  // FC-PH Port Login (arbitrary assign)
-#define ELS_SCR   0x70  // (arb assign) State Change Registration (Fabric)
-#define FCS_NSR   0x72  // (arb assign) Name Service Request (Fabric)
-#define ELS_FLOGI 0x44  // (arb assign) Fabric Login
-#define ELS_FDISC 0x41  // (arb assign) Fabric Discovery (Login)
-#define ELS_PDISC 0x50  // FC-PH2 Port Discovery
-#define ELS_ABTX  0x06  // FC-PH Abort Exchange 
-#define ELS_LOGO 0x05   // FC-PH Port Logout
-#define ELS_PRLI 0x20   // FCP-SCSI Process Login
-#define ELS_PRLO 0x21   // FCP-SCSI Process Logout
-#define ELS_LOGO_ACC 0x07   // {FC-PH} Port Logout Accept
-#define ELS_PLOGI_ACC 0x08  // {FC-PH} Port Login Accept
-#define ELS_ACC 0x18        // {FC-PH} (generic) ACCept
-#define ELS_PRLI_ACC 0x22  // {FCP-SCSI} Process Login Accept
-#define ELS_RJT 0x1000000
-#define SCSI_REPORT_LUNS 0x0A0
-#define FCP_TARGET_RESET 0x200
-
-#define ELS_LILP_FRAME 0x00000711 // 1st payload word of LILP frame
-
-#define SFQ_UNASSISTED_FCP  1  // ICM, DWord3, "Type" unassisted FCP
-#define SFQ_UNKNOWN         0x31 // (arbitrary) ICM, DWord3, "Type" unknown
-
-// these "LINK" bits refer to loop or non-loop
-#define LINKACTIVE 0x2    // fcLinkQ type - LINK UP Tachyon FM 'Lup' bit set
-#define LINKDOWN 0xf2     // fcLinkQ type - LINK DOWN Tachyon FM 'Ldn' bit set
-
-//#define VOLUME_SET_ADDRESSING 1 // "channel" or "bus" 1
-
-typedef struct      // 32 bytes hdr ONLY (e.g. FCP_DATA buffer for SEST)
-{
-  ULONG reserved;   // dword 0 (don't use)
-  ULONG sof_eof;
-  ULONG d_id;       // dword 2 - 31:24 R_CTL, 23:0 D_ID
-  ULONG s_id;       // dword 3 - 31:24 CS_CTL, 23:0 S_ID
-  ULONG f_ctl;      // dword 4 - 31:24 Type,  23:0 F_CTL
-  ULONG seq_cnt;    // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
-  ULONG ox_rx_id;   // dword 6 - 31:16 OX_ID,  15:0 RX_ID
-  ULONG ro;         // dword 7 - relative offset
-} TachFCHDR;
-
-                    // NOTE!! the following struct MUST be 64 bytes.
-typedef struct      // 32 bytes hdr + 32 bytes payload
-{
-  ULONG reserved;   // dword 0 (don't use - must clear to 0)
-  ULONG sof_eof;    // dword 1 - 31:24 SOF:EOF, UAM,CLS, LCr, TFV, TimeStamp
-  ULONG d_id;       // dword 2 - 31:24 R_CTL, 23:0 D_ID
-  ULONG s_id;       // dword 3 - 31:24 CS_CTL, 23:0 S_ID
-  ULONG f_ctl;      // dword 4 - 31:24 Type,  23:0 F_CTL
-  ULONG seq_cnt;    // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
-  ULONG ox_rx_id;   // dword 6 - 31:16 OX_ID,  15:0 RX_ID
-  ULONG ro;  // dword 7 - relative offset
-//---------
-  __u32 pl[8];              // dwords 8-15 frame data payload
-} TachFCHDR_CMND;
-
-
-typedef struct      // 32 bytes hdr + 120 bytes payload
-{
-  ULONG reserved;   // dword 0 (don't use - must clear to 0)
-  ULONG sof_eof;    // dword 1 - 31:24 SOF:EOF, UAM,CLS, LCr, TFV, TimeStamp
-  ULONG d_id;       // dword 2 - 31:24 R_CTL, 23:0 D_ID
-  ULONG s_id;       // dword 3 - 31:24 CS_CTL, 23:0 S_ID
-  ULONG f_ctl;      // dword 4 - 31:24 Type,  23:0 F_CTL
-  ULONG seq_cnt;    // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
-  ULONG ox_rx_id;   // dword 6 - 31:16 OX_ID,  15:0 RX_ID
-  ULONG ro;  // dword 7 - relative offset
-//---------
-  __u32 pl[30];              // largest necessary payload (for LOGIN cmnds)
-} TachFCHDR_GCMND;
-
-typedef struct      // 32 bytes hdr + 64 bytes payload
-{
-  ULONG reserved;   // dword 0 (don't use)
-  ULONG sof_eof;
-  ULONG d_id;       // dword 2 - 31:24 R_CTL, 23:0 D_ID
-  ULONG s_id;       // dword 3 - 31:24 CS_CTL, 23:0 S_ID
-  ULONG f_ctl;      // dword 4 - 31:24 Type,  23:0 F_CTL
-  ULONG seq_cnt;    // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
-  ULONG ox_rx_id;   // dword 6 - 31:16 OX_ID,  15:0 RX_ID
-  ULONG ro;  // dword 7 - relative offset
-//---------
-  __u32 pl[18]; // payload for FCP-RSP (response buffer) RA-4x00 is 72bytes
-} TachFCHDR_RSP;
-
-
-
-
-
-
-// Inbound Message Queue structures...
-typedef struct              // each entry 8 words (32 bytes)
-{
-  ULONG type;               // IMQ completion message types
-  ULONG word[7];            // remainder of structure
-                            // interpreted by IMQ type
-} TachyonIMQE;
-
-
-// Queues for TachLite not in original Tachyon
-// ERQ       - Exchange Request Queue (for outbound commands)
-// SFQ       - Single Frame Queue (for incoming frames)
-
-                            // Define Tachyon Outbound Command Que
-                            // (Since many Tachyon registers are Read
-                            // only, maintain copies for debugging)
-                            // most Tach ques need power-of-2 sizes,
-                            // where registers are loaded with po2 -1
-#define TACH_SEST_LEN 512   // TachLite SEST
-
-#define ELS_EXCHANGES 64    // e.g. PLOGI, RSCN, ...
-// define the total number of outstanding (simultaneous) exchanges
-#define TACH_MAX_XID (TACH_SEST_LEN + ELS_EXCHANGES)  // ELS exchanges
-
-#define ERQ_LEN 128         // power of 2, max 4096
-
-// Inbound Message Queue structures...
-#define IMQ_LEN 512              // minimum 4 entries [(power of 2) - 1]
-typedef struct                   // 8 words - 32 bytes
-{
-  TachyonIMQE QEntry[IMQ_LEN];
-  ULONG producerIndex;   // IMQ Producer Index register
-                                 // @32 byte align
-  ULONG consumerIndex;   // Consumer Index register (in Tachyon)
-  ULONG length;          // Length register
-  ULONG base;
-} TachyonIMQ;                    // @ 32 * IMQ_LEN align
-
-
-
-typedef struct           // inbound completion message
-{
-  ULONG Type;
-  ULONG Index;
-  ULONG TransferLength;
-} TachyonInbCM;
-
-
-
-// arbitrary numeric tags for TL structures
-#define TL_FCHS 1  // TachLite Fibre Channel Header Structure
-#define TL_IWE 2  // initiator write entry (for SEST)
-#define TL_TWE 3  // target write entry (for SEST)
-#define TL_IRE 4  // initiator read entry (for SEST)
-#define TL_TRE 5  // target read entry (for SEST)
-#define TL_IRB 6  // I/O request block
-
-                                // for INCOMING frames
-#define SFQ_LEN 32              // minimum 32 entries, max 4096
-
-typedef struct                  // Single Frame Que
-{
-  TachFCHDR_CMND QEntry[SFQ_LEN]; // must be 64 bytes!!
-  ULONG producerIndex;   // IMQ Producer Index register
-                                 // @32 byte align
-  ULONG consumerIndex;   // Consumer Index register (in Tachyon)
-  ULONG length;          // Length register
-  ULONG base;
-} TachLiteSFQ;
-
-
-typedef struct                 // I/O Request Block flags
-{
-  UCHAR  BRD : 1;
-  UCHAR      : 1; // reserved
-  UCHAR  SFA : 1;
-  UCHAR  DNC : 1;
-  UCHAR  DIN : 1;
-  UCHAR  DCM : 1;
-  UCHAR  CTS : 1;
-  UCHAR  SBV : 1;  // IRB entry valid - IRB'B' only
-} IRBflags;
-
-typedef struct                  // I/O Request Block
-{                          // Request 'A'
-  ULONG Req_A_SFS_Len;     // total frame len (hdr + payload), min 32
-  ULONG Req_A_SFS_Addr;    // 32-bit pointer to FCHS struct (to be sent)
-  ULONG Req_A_SFS_D_ID;    // 24-bit FC destination (i.e. 8 bit al_pa)
-  ULONG Req_A_Trans_ID;    // X_ID (OX_ID or RX_ID) and/or Index in SEST
-                           // Request 'B'
-  ULONG Req_B_SFS_Len;     // total frame len (hdr + payload), min 32
-  ULONG Req_B_SFS_Addr;    // 32-bit pointer to FCHS struct (to be sent)
-  ULONG Req_B_SFS_D_ID;    // 24-bit FC destination (i.e. 8 bit al_pa)
-  ULONG Req_B_Trans_ID;    // X_ID (OX_ID or RX_ID) and/or Index in SEST
-} TachLiteIRB;
-
-
-typedef struct           // TachLite placeholder for IRBs
-{                        // aligned @sizeof(ERQ) for TachLite
-                         // MAX commands is sum of SEST len and ERQ
-                         // we know that each SEST entry requires an
-                         // IRB (ERQ) entry; in addition, we provide
-                         // ERQ_LEN
-  TachLiteIRB QEntry[ERQ_LEN]; // Base register; entries 32 bytes ea.
-  ULONG consumerIndex;   // Consumer Index register
-  ULONG producerIndex;   // ERQ Producer Index register
-  ULONG length;          // Length register
-  ULONG base;            // copy of base ptr for debug
-                         // struct is sized for largest expected cmnd (LOGIN)
-} TachLiteERQ;
-
-// for now, just 32 bit DMA, eventually 40something, with code changes
-#define CPQFCTS_DMA_MASK ((unsigned long) (0x00000000FFFFFFFF))
-
-#define TL_MAX_SG_ELEM_LEN 0x7ffff  // Max buffer length a single S/G entry
-                               // may represent (a hardware limitation).  The
-                               // only reason to ever change this is if you
-                               // want to exercise very-hard-to-reach code in
-                               // cpqfcTSworker.c:build_SEST_sglist().
-
-#define TL_DANGER_SGPAGES 7  // arbitrary high water mark for # of S/G pages
-                               // we must exceed to elicit a warning indicative
-                               // of EXTREMELY large data transfers or 
-                               // EXTREME memory fragmentation.
-                               // (means we just used up 2048 S/G elements,
-                               // Never seen this is real life, only in 
-                               // testing with tricked up driver.)
-
-#define TL_EXT_SG_PAGE_COUNT 256  // Number of Extended Scatter/Gather a/l PAIRS
-                                  // Tachyon register (IOBaseU 0x68)
-                                  // power-of-2 value ONLY!  4 min, 256 max
-
-                          // byte len is #Pairs * 2 ULONG/Pair * 4 bytes/ULONG
-#define TL_EXT_SG_PAGE_BYTELEN (TL_EXT_SG_PAGE_COUNT *2 *4)
-
-
-
-// SEST entry types: IWE, IRE, TWE, TRE
-typedef struct 
-{
-  ULONG Hdr_Len;
-  ULONG Hdr_Addr;
-  ULONG RSP_Len;
-  ULONG RSP_Addr;
-  ULONG Buff_Off;
-#define USES_EXTENDED_SGLIST(this_sest, x_ID) \
-       (!((this_sest)->u[ x_ID ].IWE.Buff_Off & 0x80000000))
-  ULONG Link;
-  ULONG RX_ID;
-  ULONG Data_Len;
-  ULONG Exp_RO;
-  ULONG Exp_Byte_Cnt;
-   // --- extended/local Gather Len/Address pairs
-  ULONG GLen1;
-  ULONG GAddr1;
-  ULONG GLen2;
-  ULONG GAddr2;
-  ULONG GLen3;
-  ULONG GAddr3;
-} TachLiteIWE;
-
-
-typedef struct 
-{
-  ULONG Seq_Accum;
-  ULONG reserved;       // must clear to 0
-  ULONG RSP_Len;
-  ULONG RSP_Addr;
-  ULONG Buff_Off;
-  ULONG Buff_Index;           // ULONG 5
-  ULONG Exp_RO;
-  ULONG Byte_Count;
-  ULONG reserved_;      // ULONG 8
-  ULONG Exp_Byte_Cnt;
-   // --- extended/local Scatter Len/Address pairs
-  ULONG SLen1;
-  ULONG SAddr1;
-  ULONG SLen2;
-  ULONG SAddr2;
-  ULONG SLen3;
-  ULONG SAddr3;
-} TachLiteIRE;
-
-
-typedef struct          // Target Write Entry
-{
-  ULONG Seq_Accum;      // dword 0
-  ULONG reserved;       // dword 1  must clear to 0
-  ULONG Remote_Node_ID;
-  ULONG reserved1;      // dword 3  must clear to 0
-  ULONG Buff_Off;
-  ULONG Buff_Index;     // ULONG 5
-  ULONG Exp_RO;
-  ULONG Byte_Count;
-  ULONG reserved_;      // ULONG 8
-  ULONG Exp_Byte_Cnt;
-   // --- extended/local Scatter Len/Address pairs
-  ULONG SLen1;
-  ULONG SAddr1;
-  ULONG SLen2;
-  ULONG SAddr2;
-  ULONG SLen3;
-  ULONG SAddr3;
-} TachLiteTWE;
-
-typedef struct      
-{
-  ULONG Hdr_Len;
-  ULONG Hdr_Addr;
-  ULONG RSP_Len;        // DWord 2
-  ULONG RSP_Addr;
-  ULONG Buff_Off;
-  ULONG Buff_Index;     // DWord 5
-  ULONG reserved;
-  ULONG Data_Len;
-  ULONG reserved_;
-  ULONG reserved__;
-   // --- extended/local Gather Len/Address pairs
-  ULONG GLen1;          // DWord A
-  ULONG GAddr1;
-  ULONG GLen2;
-  ULONG GAddr2;
-  ULONG GLen3;
-  ULONG GAddr3;
-} TachLiteTRE;
-
-typedef struct ext_sg_page_ptr_t *PSGPAGES;
-typedef struct ext_sg_page_ptr_t 
-{
-  unsigned char page[TL_EXT_SG_PAGE_BYTELEN * 2]; // 2x for alignment
-  dma_addr_t busaddr;  // need the bus addresses and
-  unsigned int maplen;  // lengths for later pci unmapping.
-  PSGPAGES next;
-} SGPAGES; // linked list of S/G pairs, by Exchange
-
-typedef struct                  // SCSI Exchange State Table
-{
-  union                         // Entry can be IWE, IRE, TWE, TRE
-  {                             // 64 bytes per entry
-    TachLiteIWE IWE;
-    TachLiteIRE IRE;
-    TachLiteTWE TWE;
-    TachLiteTRE TRE;
-  } u[TACH_SEST_LEN];
-
-  TachFCHDR DataHDR[TACH_SEST_LEN]; // for SEST FCP_DATA frame hdr (no pl)
-  TachFCHDR_RSP RspHDR[TACH_SEST_LEN]; // space for SEST FCP_RSP frame
-  PSGPAGES sgPages[TACH_SEST_LEN]; // head of linked list of Pool-allocations
-  ULONG length;          // Length register
-  ULONG base;            // copy of base ptr for debug
-} TachSEST;
-
-
-
-typedef struct                  // each register has it's own address
-                                // and value (used for write-only regs)
-{
-  void* address;
-  volatile ULONG value;
-} FCREGISTER;
-
-typedef struct         // Host copy - TachLite Registers
-{
-  ULONG IOBaseL, IOBaseU;  // I/O port lower and upper TL register addresses
-  ULONG MemBase;           // memory mapped register addresses
-  void* ReMapMemBase;      // O/S VM reference for MemBase
-  ULONG wwn_hi;            // WWN is set once at startup
-  ULONG wwn_lo;
-  ULONG my_al_pa;          // al_pa received after LIP()
-  ULONG ROMCTR;            // flags for on-board RAM/ROM
-  ULONG RAMBase;           // on-board RAM (i.e. some Tachlites)
-  ULONG SROMBase;          // on-board EEPROM (some Tachlites)
-  ULONG PCIMCTR;           // PCI Master Control Reg (has bus width)
-
-  FCREGISTER INTEN;        // copy of interrupt enable mask
-  FCREGISTER INTPEND;      // interrupt pending
-  FCREGISTER INTSTAT;      // interrupt status
-  FCREGISTER SFQconsumerIndex; 
-  FCREGISTER ERQproducerIndex; 
-  FCREGISTER TYconfig;   // TachYon (chip level)
-  FCREGISTER TYcontrol;
-  FCREGISTER TYstatus;
-  FCREGISTER FMconfig;   // Frame Manager (FC loop level)
-  FCREGISTER FMcontrol;
-  FCREGISTER FMstatus;
-  FCREGISTER FMLinkStatus1;
-  FCREGISTER FMLinkStatus2;
-  FCREGISTER FMBB_CreditZero;
-  FCREGISTER status;
-  FCREGISTER ed_tov;     // error detect time-out value
-  FCREGISTER rcv_al_pa;  // received arb. loop physical address
-  FCREGISTER primitive;  // e.g. LIP(), OPN(), ...
-} TL_REGISTERS;
-
-
-
-typedef struct 
-{
-  ULONG ok;
-  ULONG invalidArgs;
-  ULONG linkDown;
-  ULONG linkUp;
-  ULONG outQueFull;
-  ULONG SESTFull;
-  ULONG hpe;    // host programming err (from Tach)
-  ULONG FC4aborted; // aborts from Application or upper driver layer
-  ULONG FC2aborted; // aborts from our driver's timeouts
-  ULONG timeouts;   // our driver timeout (on individual exchanges)
-  ULONG logouts;    // explicit - sent LOGO; implicit - device removed
-  ULONG retries;
-  ULONG linkFailTX;
-  ULONG linkFailRX;
-  ULONG CntErrors;  // byte count expected != count received (typ. SEST)
-  ULONG e_stores;   // elastic store errs
-  ULONG resets;     // hard or soft controller resets
-  ULONG FMinits;    // TACH Frame Manager Init (e.g. LIPs)
-  ULONG lnkQueFull;  // too many LOGIN, loop commands
-  ULONG ScsiQueFull; // too many FCP-SCSI inbound frames
-  ULONG LossofSignal;   // FM link status 1 regs
-  ULONG BadRXChar;   // FM link status 1 regs
-  ULONG LossofSync;   // FM link status 1 regs
-  ULONG Rx_EOFa;   // FM link status 2 regs (received EOFa)
-  ULONG Dis_Frm;   // FM link status 2 regs (discarded frames)
-  ULONG Bad_CRC;   // FM link status 2 regs
-  ULONG BB0_Timer; //  FM BB_Credit Zero Timer Reg
-  ULONG loopBreaks; // infinite loop exits
-  ULONG lastBB0timer;  // static accum. buffer needed by Tachlite
-} FCSTATS;
-
-
-typedef struct               // Config Options
-{                            // LS Bit first
-  USHORT        : 1;           // bit0:
-  USHORT  flogi : 1;           // bit1: We sent FLOGI - wait for Fabric logins
-  USHORT  fabric: 1;           // bit2: Tachyon detected Fabric (FM stat LG)
-  USHORT  LILPin: 1;           // bit3: We can use an FC-AL LILP frame
-  USHORT  target: 1;           // bit4: this Port has SCSI target capability
-  USHORT  initiator:    1;     // bit5: this Port has SCSI initiator capability
-  USHORT  extLoopback:  1;     // bit6: loopback at GBIC
-  USHORT  intLoopback:  1;     // bit7: loopback in HP silicon
-  USHORT        : 1;           // bit8:
-  USHORT        : 1;           // bit9:
-  USHORT        : 1;           // bit10:
-  USHORT        : 1;           // bit11:
-  USHORT        : 1;           // bit12:
-  USHORT        : 1;           // bit13:
-  USHORT        : 1;           // bit14:
-  USHORT        : 1;           // bit15:
-} FC_OPTIONS;
-
-
-
-typedef struct dyn_mem_pair
-{
-  void *BaseAllocated;  // address as allocated from O/S;
-  unsigned long AlignedAddress; // aligned address (used by Tachyon DMA)
-  dma_addr_t dma_handle;
-  size_t size;
-} ALIGNED_MEM;
-
-
-
-
-// these structs contain only CRUCIAL (stuff we actually use) parameters
-// from FC-PH(n) logins.  (Don't save entire LOGIN payload to save mem.)
-
-// Implicit logout happens when the loop goes down - we require PDISC
-// to restore.  Explicit logout is when WE decide never to talk to someone,
-// or when a target refuses to talk to us, i.e. sends us a LOGO frame or
-// LS_RJT reject in response to our PLOGI request.
-
-#define IMPLICIT_LOGOUT 1
-#define EXPLICIT_LOGOUT 2
-
-typedef struct 
-{
-  UCHAR channel; // SCSI "bus"
-  UCHAR target;
-  UCHAR InqDeviceType;  // byte 0 from SCSI Inquiry response
-  UCHAR VolumeSetAddressing;  // FCP-SCSI LUN coding (40h for VSA)
-  UCHAR LunMasking;     // True if selective presentation supported
-  UCHAR lun[CPQFCTS_MAX_LUN];
-} SCSI_NEXUS;
-
-
-typedef struct        
-{
-  union 
-  {
-    UCHAR ucWWN[8];  // a FC 64-bit World Wide Name/ PortID of target
-                     // addressing of single target on single loop...
-    u64 liWWN;
-  } u;
-
-  ULONG port_id;     // a FC 24-bit address of port (lower 8 bits = al_pa)
-
-#define REPORT_LUNS_PL 256  
-  UCHAR ReportLunsPayload[REPORT_LUNS_PL];
-  
-  SCSI_NEXUS ScsiNexus; // LUNs per FC device
-
-  ULONG LOGO_counter; // might try several times before logging out for good
-  ULONG LOGO_timer;   // after LIP, ports expecting PDISC must time-out and
-                      // LOGOut if successful PDISC not completed in 2 secs
-
-  ULONG concurrent_seq;  // must be 1 or greater
-  ULONG rx_data_size;    // e.g. 128, 256, 1024, 2048 per FC-PH spec
-  ULONG BB_credit;
-  ULONG EE_credit;
-
-  ULONG fcp_info;        // from PRLI (i.e. INITIATOR/ TARGET flags)
-                         // flags for login process
-  BOOLEAN Originator;    // Login sequence Originated (if false, we
-                         // responded to another port's login sequence)
-  BOOLEAN plogi;         // PLOGI frame ACCepted (originated or responded)
-  BOOLEAN pdisc;         // PDISC frame was ORIGINATED (self-login logic)
-  BOOLEAN prli;          // PRLI frame ACCepted (originated or responded)
-  BOOLEAN flogi;         // FLOGI frame ACCepted (originated or responded)
-  BOOLEAN logo;          // port permanently logged out (invalid login param)
-  BOOLEAN flogiReq;      // Fabric login required (set in LIP process)
-  UCHAR highest_ver;
-  UCHAR lowest_ver;
-
-  
-  // when the "target" (actually FC Port) is waiting for login
-  // (e.g. after Link reset), set the device_blocked bit;
-  // after Port completes login, un-block target.
-  UCHAR device_blocked; // see Scsi_Device struct
-
-                    // define singly-linked list of logged-in ports
-                    // once a port_id is identified, it is remembered,
-                    // even if the port is removed indefinitely
-  PVOID pNextPort;  // actually, type PFC_LOGGEDIN_PORT; void for Compiler
-
-} FC_LOGGEDIN_PORT, *PFC_LOGGEDIN_PORT;
-
-
-
-// This serves as the ESB (Exchange Status Block),
-// and has timeout counter; used for ABORTs
-typedef struct                
-{                                  // FC-1 X_IDs
-  ULONG type;            // ELS_PLOGI, SCSI_IWE, ... (0 if free)
-  PFC_LOGGEDIN_PORT pLoggedInPort; // FC device on other end of Exchange
-  Scsi_Cmnd *Cmnd;       // Linux SCSI command packet includes S/G list
-  ULONG timeOut;         // units of ??, DEC by driver, Abort when 0
-  ULONG reTries;         // need one or more retries?
-  ULONG status;          // flags indicating errors (0 if none)
-  TachLiteIRB IRB;       // I/O Request Block, gets copied to ERQ
-  TachFCHDR_GCMND fchs;  // location of IRB's Req_A_SFS_Addr
-} FC_EXCHANGE, *PFC_EXCHANGE;
-
-// Unfortunately, Linux limits our kmalloc() allocations to 128k.
-// Because of this and the fact that our ScsiRegister allocation
-// is also constrained, we move this large structure out for
-// allocation after Scsi Register.
-// (In other words, this cumbersome indirection is necessary
-// because of kernel memory allocation constraints!)
-
-typedef struct // we will allocate this dynamically
-{
-  FC_EXCHANGE fcExchange[ TACH_MAX_XID ];
-} FC_EXCHANGES;
-
-
-
-
-
-
-
-
-
-
-
-typedef struct
-{
-  char Name[64]; // name of controller ("HP Tachlite TL Rev2.0, 33MHz, 64bit bus")
-  //PVOID  pAdapterDevExt; // back pointer to device object/extension
-  ULONG ChipType;        // local numeric key for Tachyon Type / Rev.
-  ULONG status;              // our Driver - logical status
-  
-  TL_REGISTERS Registers;    // reg addresses & host memory copies
-                             // FC-4 mapping of 'transaction' to X_IDs
-  UCHAR LILPmap[32*4];       // Loop Position Map of ALPAs (late FC-AL only)
-  FC_OPTIONS Options;        // e.g. Target, Initiator, loopback...
-  UCHAR highest_FCPH_ver;    // FC-PH version limits
-  UCHAR lowest_FCPH_ver;     // FC-PH version limits
-
-  FC_EXCHANGES *Exchanges;  
-  ULONG fcLsExchangeLRU;       // Least Recently Used counter (Link Service)
-  ULONG fcSestExchangeLRU;       // Least Recently Used counter (FCP-SCSI)
-  FC_LOGGEDIN_PORT fcPorts;  // linked list of every FC port ever seen
-  FCSTATS fcStats;           // FC comm err counters
-
-                             // Host memory QUEUE pointers
-  TachLiteERQ *ERQ;          // Exchange Request Que 
-  TachyonIMQ *IMQ;           // Inbound Message Que 
-  TachLiteSFQ *SFQ;          // Single Frame Queue
-  TachSEST *SEST;            // SCSI Exchange State Table
-
-  dma_addr_t exch_dma_handle;
-
-  // these function pointers are for "generic" functions, which are
-  // replaced with Host Bus Adapter types at
-  // runtime.
-  int (*CreateTachyonQues)( void* , int);
-  int (*DestroyTachyonQues)( void* , int);
-  int (*LaserControl)(void*, int );   // e.g. On/Off
-  int (*ResetTachyon)(void*, int );
-  void (*FreezeTachyon)(void*, int );
-  void (*UnFreezeTachyon)(void*, int );
-  int (*InitializeTachyon)(void*, int, int );
-  int (*InitializeFrameManager)(void*, int );
-  int (*ProcessIMQEntry)(void*);
-  int (*ReadWriteWWN)(void*, int ReadWrite);
-  int (*ReadWriteNVRAM)(void*, void*, int ReadWrite);
-
-} TACHYON, *PTACHYON;
-
-
-void cpqfcTSClearLinkStatusCounters(TACHYON * fcChip);
-
-int CpqTsCreateTachLiteQues( void* pHBA, int opcode);
-int CpqTsDestroyTachLiteQues( void* , int);
-int CpqTsInitializeTachLite( void *pHBA, int opcode1, int opcode2);
-
-int CpqTsProcessIMQEntry(void* pHBA);
-int CpqTsResetTachLite(void *pHBA, int type);
-void CpqTsFreezeTachlite(void *pHBA, int type);
-void CpqTsUnFreezeTachlite(void *pHBA, int type);
-int CpqTsInitializeFrameManager(void *pHBA, int);
-int CpqTsLaserControl( void* addrBase, int opcode );
-int CpqTsReadWriteWWN(void*, int ReadWrite);
-int CpqTsReadWriteNVRAM(void*, void* data, int ReadWrite);
-
-void cpqfcTS_WorkTask( struct Scsi_Host *HostAdapter);
-void cpqfcTSWorkerThread( void *host);
-
-int cpqfcTS_GetNVRAM_data( UCHAR *wwnbuf, UCHAR *buf );
-ULONG cpqfcTS_ReadNVRAM( void* GPIOin, void* GPIOout , USHORT count,
-       UCHAR *buf );
-
-BOOLEAN tl_write_i2c_nvram( void* GPIOin, void* GPIOout,
-  USHORT startOffset,  // e.g. 0x2f for WWN start
-  USHORT count,
-  UCHAR *buf );
-
-
-// define misc functions 
-int cpqfcTSGetLPSM( PTACHYON fcChip, char cErrorString[]);
-int cpqfcTSDecodeGBICtype( PTACHYON fcChip, char cErrorString[]);
-void* fcMemManager( struct pci_dev *pdev,
-               ALIGNED_MEM *dyn_mem_pair, ULONG n_alloc, ULONG ab,
-                   ULONG ulAlignedAddress, dma_addr_t *dma_handle);
-
-void BigEndianSwap(  UCHAR *source, UCHAR *dest,  USHORT cnt);
-
-//ULONG virt_to_phys( PVOID virtaddr );
-                  
-
-// Linux interrupt handler
-irqreturn_t cpqfcTS_intr_handler( int irq,void *dev_id,struct pt_regs *regs);
-void cpqfcTSheartbeat( unsigned long ptr );
-
-
-
-// The biggest Q element we deal with is Aborts - we
-// need 4 bytes for x_ID, and a Scsi_Cmnd (~284 bytes)
-//#define LINKQ_ITEM_SIZE ((4+sizeof(Scsi_Cmnd)+3)/4)
-#define LINKQ_ITEM_SIZE (3*16)
-typedef struct
-{
-  ULONG Type;              // e.g. LINKUP, SFQENTRY, PDISC, BLS_ABTS, ...
-  ULONG ulBuff[ LINKQ_ITEM_SIZE ];
-} LINKQ_ITEM;
-
-#define FC_LINKQ_DEPTH TACH_MAX_XID
-typedef struct
-{
-  ULONG producer;
-  ULONG consumer;  // when producer equals consumer, Q empty
-
-  LINKQ_ITEM Qitem[ FC_LINKQ_DEPTH ];
-
-} FC_LINK_QUE, *PFC_LINK_QUE;
-
-
-     // DPC routines post to here on Inbound SCSI frames
-     // User thread processes
-#define FC_SCSIQ_DEPTH 32
-
-typedef struct
-{
-  int Type;              // e.g. SCSI
-  ULONG ulBuff[ 3*16 ];
-} SCSIQ_ITEM;
-
-typedef struct
-{
-  ULONG producer;
-  ULONG consumer;  // when producer equals consumer, Q empty
-
-  SCSIQ_ITEM Qitem[ FC_SCSIQ_DEPTH ];
-
-} FC_SCSI_QUE, *PFC_SCSI_QUE;
-
-typedef struct {
-       /* This is tacked on to a Scsi_Request in upper_private_data 
-          for pasthrough ioctls, as a place to hold data that can't 
-          be stashed anywhere else in the Scsi_Request.  We differentiate
-          this from _real_ upper_private_data by checking if the virt addr
-          is within our special pool.  */
-       ushort bus;
-       ushort pdrive;
-} cpqfc_passthru_private_t;
-
-#define CPQFC_MAX_PASSTHRU_CMDS 100
-
-#define DYNAMIC_ALLOCATIONS 4  // Tachyon aligned allocations: ERQ,IMQ,SFQ,SEST
-
-// Linux space allocated per HBA (chip state, etc.)
-typedef struct 
-{
-  struct Scsi_Host *HostAdapter; // back pointer to Linux Scsi struct
-
-  TACHYON fcChip;    // All Tachyon registers, Queues, functions
-  ALIGNED_MEM dynamic_mem[DYNAMIC_ALLOCATIONS];
-
-  struct pci_dev *PciDev;
-  dma_addr_t fcLQ_dma_handle;
-
-  Scsi_Cmnd *LinkDnCmnd[CPQFCTS_REQ_QUEUE_LEN]; // collects Cmnds during LDn
-                                                // (for Acceptable targets)
-  Scsi_Cmnd *BoardLockCmnd[CPQFCTS_REQ_QUEUE_LEN]; // SEST was full
-  
-  Scsi_Cmnd *BadTargetCmnd[CPQFCTS_MAX_TARGET_ID]; // missing targets
-
-  u_char HBAnum;     // 0-based host number
-
-
-  struct timer_list cpqfcTStimer; // FC utility timer for implicit
-                                  // logouts, FC protocol timeouts, etc.
-  int fcStatsTime;  // Statistics delta reporting time
-
-  struct task_struct *worker_thread; // our kernel thread
-  int PortDiscDone;    // set by SendLogins(), cleared by LDn
-  
-  struct semaphore *TachFrozen;
-  struct semaphore *TYOBcomplete;    // handshake for Tach outbound frames
-  struct semaphore *fcQueReady;      // FibreChannel work for our kernel thread
-  struct semaphore *notify_wt;       // synchronizes kernel thread kill
-  struct semaphore *BoardLock;
-  
-  PFC_LINK_QUE fcLQ;             // the WorkerThread operates on this
-
-  spinlock_t hba_spinlock;           // held/released by WorkerThread
-  cpqfc_passthru_private_t *private_data_pool;
-  unsigned long *private_data_bits;
-
-} CPQFCHBA;
-
-#define        CPQ_SPINLOCK_HBA( x )   spin_lock(&x->hba_spinlock);
-#define CPQ_SPINUNLOCK_HBA(x)   spin_unlock(&x->hba_spinlock);
-
-
-
-void cpqfcTSImplicitLogout( CPQFCHBA* cpqfcHBAdata,
-               PFC_LOGGEDIN_PORT pFcPort);
-
-
-void cpqfcTSTerminateExchange( CPQFCHBA*, SCSI_NEXUS *target, int );
-
-PFC_LOGGEDIN_PORT fcPortLoggedIn( 
-   CPQFCHBA *cpqfcHBAdata, 
-   TachFCHDR_GCMND* fchs, 
-   BOOLEAN, 
-   BOOLEAN);
-void fcProcessLoggedIn( 
-   CPQFCHBA *cpqfcHBAdata, TachFCHDR_GCMND* fchs);
-
-
-ULONG cpqfcTSBuildExchange( 
-  CPQFCHBA *cpqfcHBAdata,
-  ULONG type, // e.g. PLOGI
-  TachFCHDR_GCMND* InFCHS,  // incoming FCHS
-  void *Data,               // the CDB, scatter/gather, etc.  
-  LONG *ExchangeID );       // allocated exchange ID
-
-ULONG cpqfcTSStartExchange( 
-  CPQFCHBA *cpqfcHBAdata,
-  LONG ExchangeID );
-
-void cpqfcTSCompleteExchange( 
-       struct pci_dev *pcidev,
-       PTACHYON fcChip, 
-       ULONG exchange_ID);
-
-
-PFC_LOGGEDIN_PORT  fcFindLoggedInPort( 
-  PTACHYON fcChip, 
-  Scsi_Cmnd *Cmnd,  // (We want the channel/target/lun Nexus from Cmnd)
-  ULONG port_id,  // search linked list for al_pa, or
-  UCHAR wwn[8],    // search linked list for WWN, or...
-  PFC_LOGGEDIN_PORT *pLastLoggedInPort
-);
-
-void cpqfcTSPutLinkQue( 
-  CPQFCHBA *cpqfcHBAdata, 
-  int Type, 
-  void *QueContent);
-
-void fcPutScsiQue( 
-  CPQFCHBA *cpqfcHBAdata, 
-  int Type, 
-  void *QueContent);
-
-void fcLinkQReset(
-   CPQFCHBA *);
-void fcScsiQReset(
-   CPQFCHBA *);
-void fcSestReset(
-   CPQFCHBA *);
-
-void cpqfc_pci_unmap(struct pci_dev *pcidev, 
-       Scsi_Cmnd *cmd, 
-       PTACHYON fcChip, 
-       ULONG x_ID);
-
-extern const UCHAR valid_al_pa[];
-extern const int number_of_al_pa;
-
-#define FCP_RESID_UNDER   0x80000
-#define FCP_RESID_OVER    0x40000
-#define FCP_SNS_LEN_VALID 0x20000
-#define FCP_RSP_LEN_VALID 0x10000
-
-// RSP_CODE definitions (dpANS Fibre Channel Protocol for SCSI, pg 34)
-#define FCP_DATA_LEN_NOT_BURST_LEN 0x1000000
-#define FCP_CMND_FIELD_INVALID     0x2000000
-#define FCP_DATA_RO_NOT_XRDY_RO    0x3000000
-#define FCP_TASKFUNCTION_NS        0x4000000
-#define FCP_TASKFUNCTION_FAIL      0x5000000
-
-// FCP-SCSI response status struct
-typedef struct  // see "TachFCHDR_RSP" definition - 64 bytes
-{
-  __u32 reserved;
-  __u32 reserved1;
-  __u32 fcp_status;    // field validity and SCSI status
-  __u32 fcp_resid;
-  __u32 fcp_sns_len;   // length of FCP_SNS_INFO field
-  __u32 fcp_rsp_len;   // length of FCP_RSP_INFO field (expect 8)
-  __u32 fcp_rsp_info;  // 4 bytes of FCP protocol response information
-  __u32 fcp_rsp_info2; // (4 more bytes, since most implementations use 8)
-  __u8  fcp_sns_info[36]; // bytes for SCSI sense (ASC, ASCQ)
-
-} FCP_STATUS_RESPONSE, *PFCP_STATUS_RESPONSE;
-
-
-// Fabric State Change Registration
-typedef struct scrpl
-{
-  __u32 command;
-  __u32 function;
-} SCR_PL;
-
-// Fabric Name Service Request
-typedef struct nsrpl
-{
-  __u32 CT_Rev;  // (& IN_ID)   WORD 0
-  __u32 FCS_Type;            // WORD 1
-  __u32 Command_code;        // WORD 2
-  __u32 reason_code;         // WORD 3
-  __u32 FCP;                 // WORD 4 (lower byte)
-  
-} NSR_PL;
-
-
-
-// "FC.H"
-#define MAX_RX_SIZE            0x800   // Max Receive Buffer Size is 2048
-#define MIN_RX_SIZE            0x100   // Min Size is 256, per FC-PLDA Spec
-#define        MAX_TARGET_RXIDS        SEST_DEPTH
-#define TARGET_RX_SIZE         SEST_BUFFER_LENGTH
-
-#define CLASS_1                        0x01
-#define CLASS_2                        0x02
-#define CLASS_3                        0x03
-
-#define FC_PH42                        0x08
-#define FC_PH43                        0x09
-#define FC_PH3                 0x20
-
-#define RR_TOV                 2       // Minimum Time for target to wait for
-                                       // PDISC after a LIP.
-#define E_D_TOV                        2       // Minimum Time to wait for Sequence
-                                       // Completion.
-#define R_A_TOV                        0       // Minimum Time for Target to wait 
-                                       // before reclaiming resources.
-//
-//     R_CTL Field
-//
-//     Routing Bits (31-28)
-//
-#define FC4_DEVICE_DATA                0x00000000
-#define EXT_LINK_DATA          0x20000000
-#define FC4_LINK_DATA          0x30000000
-#define VIDEO_DATA             0x40000000
-#define BASIC_LINK_DATA                0x80000000
-#define LINK_CONTROL           0xC0000000
-#define ROUTING_MASK           0xF0000000
-
-//
-//     Information Bits (27-24)
-//
-#define UNCAT_INFORMATION      0x00000000
-#define SOLICITED_DATA         0x01000000
-#define UNSOLICITED_CONTROL    0x02000000
-#define SOLICITED_CONTROL      0x03000000
-#define UNSOLICITED_DATA       0x04000000
-#define DATA_DESCRIPTOR                0x05000000
-#define UNSOLICITED_COMMAND    0x06000000
-#define COMMAND_STATUS         0x07000000
-#define INFO_MASK              0x0F000000
-//
-//     (Link Control Codes)
-//
-#define ACK_1                  0x00000000
-#define ACK_0_OR_N             0x01000000
-#define P_RJT                  0x02000000 
-#define F_RJT                  0x03000000 
-#define P_BSY                  0x04000000
-#define FABRIC_BUSY_TO_DF      0x05000000      // Fabric Busy to Data Frame
-#define FABRIC_BUSY_TO_LC      0x06000000      // Fabric Busy to Link Ctl Frame
-#define LINK_CREDIT_RESET      0x07000000
-//
-//     (Link Service Command Codes)
-//
-//#define LS_RJT                       0x01000000      // LS Reject
-
-#define LS_ACC                 0x02000000      // LS Accept
-#define LS_PLOGI               0x03000000      // N_PORT Login
-#define LS_FLOGI               0x04000000      // F_PORT Login
-#define LS_LOGO                        0x05000000      // Logout
-#define LS_ABTX                        0x06000000      // Abort Exchange
-#define LS_RCS                 0x07000000      // Read Connection Status
-#define LS_RES                 0x08000000      // Read Exchange Status
-#define LS_RSS                 0x09000000      // Read Sequence Status
-#define LS_RSI                 0x0A000000      // Request Seq Initiative
-#define LS_ESTS                        0x0B000000      // Establish Steaming
-#define LS_ESTC                        0x0C000000      // Estimate Credit
-#define LS_ADVC                        0x0D000000      // Advice Credit
-#define LS_RTV                 0x0E000000      // Read Timeout Value
-#define LS_RLS                 0x0F000000      // Read Link Status
-#define LS_ECHO                        0x10000000      // Echo
-#define LS_TEST                        0x11000000      // Test
-#define LS_RRQ                 0x12000000      // Reinstate Rec. Qual.
-#define LS_PRLI                        0x20000000      // Process Login
-#define LS_PRLO                        0x21000000      // Process Logout
-#define LS_TPRLO               0x24000000      // 3rd Party Process Logout
-#define LS_PDISC               0x50000000      // Process Discovery
-#define LS_FDISC               0x51000000      // Fabric Discovery
-#define LS_ADISC               0x52000000      // Discover Address
-#define LS_RNC                 0x53000000      // Report Node Capability
-#define LS_SCR                  0x62000000      // State Change Registration
-#define LS_MASK                        0xFF000000      
-
-//
-//     TYPE Bit Masks
-//
-#define BASIC_LINK_SERVICE     0x00000000
-#define EXT_LINK_SERVICE       0x01000000
-
-#define LLC                    0x04000000
-#define LLC_SNAP               0x05000000
-#define SCSI_FCP               0x08000000
-#define SCSI_GPP               0x09000000
-#define IPI3_MASTER            0x11000000
-#define IPI3_SLAVE             0x12000000
-#define IPI3_PEER              0x13000000
-#define CP_IPI3_MASTER         0x15000000
-#define CP_IPI3_SLAVE          0x16000000
-#define CP_IPI3_PEER           0x17000000
-#define SBCCS_CHANNEL          0x19000000
-#define SBCCS_CONTROL          0x1A000000
-#define FIBRE_SERVICES         0x20000000
-#define FC_FG                  0x21000000
-#define FC_XS                  0x22000000
-#define FC_AL                  0x23000000
-#define SNMP                   0x24000000
-#define HIPPI_FP               0x40000000
-#define TYPE_MASK              0xFF000000
-
-typedef struct {
-       UCHAR seq_id_valid;
-       UCHAR seq_id;
-       USHORT reserved;  // 2 bytes reserved
-       ULONG ox_rx_id;
-       USHORT low_seq_cnt;
-       USHORT high_seq_cnt;
-} BA_ACC_PAYLOAD;
-
-typedef struct {
-       UCHAR reserved;
-       UCHAR reason_code;
-       UCHAR reason_explain;
-       UCHAR vendor_unique;
-} BA_RJT_PAYLOAD;
-
-
-typedef struct {
-       ULONG   command_code;
-       ULONG   sid;
-       USHORT  ox_id;
-       USHORT  rx_id;
-} RRQ_MESSAGE;
-
-typedef struct {
-       ULONG command_code;
-       UCHAR vendor;
-       UCHAR explain;
-       UCHAR reason;
-       UCHAR reserved;
-} REJECT_MESSAGE;
-
-
-#define        N_OR_F_PORT             0x1000
-#define RANDOM_RELATIVE_OFFSET 0x4000
-#define CONTINUOSLY_INCREASING 0x8000
-
-#define CLASS_VALID            0x8000
-#define INTERMIX_MODE          0x4000
-#define TRANSPARENT_STACKED    0x2000
-#define LOCKDOWN_STACKED       0x1000
-#define SEQ_DELIVERY           0x800
-
-#define XID_NOT_SUPPORTED      0x00
-#define XID_SUPPORTED          0x4000
-#define XID_REQUIRED           0xC000
-
-#define ASSOCIATOR_NOT_SUPPORTED       0x00
-#define ASSOCIATOR_SUPPORTED   0x1000
-#define ASSOCIATOR_REQUIRED    0x3000
-
-#define        INIT_ACK0_SUPPORT       0x800
-#define INIT_ACKN_SUPPORT      0x400
-
-#define        RECIP_ACK0_SUPPORT      0x8000
-#define RECIP_ACKN_SUPPORT     0x4000
-
-#define X_ID_INTERLOCK         0x2000
-
-#define ERROR_POLICY           0x1800          // Error Policy Supported
-#define ERROR_DISCARD          0x00            // Only Discard Supported
-#define ERROR_DISC_PROCESS     0x02            // Discard and process supported
-
-#define NODE_ID                        0x01
-#define IEEE_EXT               0x20
-
-//
-// Categories Supported Per Sequence
-//
-#define        CATEGORIES_PER_SEQUENCE 0x300
-#define ONE_CATEGORY_SEQUENCE  0x00            // 1 Category per Sequence
-#define TWO_CATEGORY_SEQUENCE  0x01            // 2 Categories per Sequence
-#define MANY_CATEGORY_SEQUENCE 0x03            // > 2 Categories/Sequence
-
-typedef struct {
-
-       USHORT initiator_control;
-       USHORT service_options;
-
-       USHORT rx_data_size;
-       USHORT recipient_control;
-
-       USHORT ee_credit;
-       USHORT concurrent_sequences;
-
-       USHORT reserved;
-       USHORT open_sequences;
-
-} CLASS_PARAMETERS;
-
-typedef struct {
-       ULONG   login_cmd;
-       //
-       // Common Service Parameters
-       //
-       struct {
-
-               USHORT bb_credit;
-               UCHAR lowest_ver;
-               UCHAR highest_ver;
-
-               USHORT bb_rx_size;
-               USHORT common_features;
-
-               USHORT rel_offset;
-               USHORT concurrent_seq;
-
-
-               ULONG e_d_tov;
-       } cmn_services;
-
-       //
-       // Port Name
-       //
-       UCHAR port_name[8];
-
-       //
-       // Node/Fabric Name
-       //
-       UCHAR node_name[8];
-
-       //
-       // Class 1, 2 and 3 Service Parameters
-       //
-       CLASS_PARAMETERS        class1;
-       CLASS_PARAMETERS        class2;
-       CLASS_PARAMETERS        class3;
-
-       ULONG reserved[4];
-
-       //
-       // Vendor Version Level
-       //
-       UCHAR           vendor_id[2];
-       UCHAR           vendor_version[6];
-       ULONG           buffer_size;
-       USHORT          rxid_start;
-       USHORT          total_rxids;
-} LOGIN_PAYLOAD;
-
-
-typedef struct
-{
-  ULONG cmd;  // 4 bytes
-  UCHAR n_port_identifier[3];
-  UCHAR reserved;
-  UCHAR port_name[8];
-} LOGOUT_PAYLOAD;
-
-
-//
-//     PRLI Request Service Parameter Defines
-//
-#define PRLI_ACC                       0x01
-#define PRLI_REQ                       0x02
-#define ORIG_PROCESS_ASSOC_VALID       0x8000
-#define RESP_PROCESS_ASSOC_VALID       0x4000
-#define ESTABLISH_PAIR                 0x2000
-#define DATA_OVERLAY_ALLOWED           0x40
-#define        INITIATOR_FUNCTION              0x20
-#define        TARGET_FUNCTION                 0x10
-#define CMD_DATA_MIXED                 0x08
-#define DATA_RESP_MIXED                        0x04
-#define READ_XFER_RDY                  0x02
-#define WRITE_XFER_RDY                 0x01
-
-#define RESPONSE_CODE_MASK     0xF00
-#define REQUEST_EXECUTED       0x100
-#define NO_RESOURCES           0x200
-#define INIT_NOT_COMPLETE      0x300
-#define IMAGE_DOES_NOT_EXIST   0x400
-#define BAD_PREDEFINED_COND    0x500
-#define REQ_EXEC_COND          0x600
-#define NO_MULTI_PAGE          0x700
-
-typedef struct {
-       USHORT  payload_length;
-       UCHAR   page_length;
-       UCHAR   cmd;
-
-
-       ULONG   valid;
-
-       ULONG   orig_process_associator;
-
-       ULONG   resp_process_associator;
-       
-       ULONG   fcp_info;
-} PRLI_REQUEST;
-
-typedef struct {
-
-       USHORT  payload_length;
-       UCHAR   page_length;
-       UCHAR   cmd;
-
-       ULONG   valid;
-       ULONG   orig_process_associator;
-
-       ULONG   resp_process_associator;
-       ULONG   reserved;
-} PRLO_REQUEST;
-
-typedef struct {
-       ULONG   cmd;
-
-       ULONG   hard_address;
-       
-       UCHAR   port_name[8];
-
-       UCHAR   node_name[8];
-
-       ULONG   s_id;
-} ADISC_PAYLOAD;
-
-struct ext_sg_entry_t {
-       __u32 len:18;           /* buffer length, bits 0-17 */
-       __u32 uba:13;           /* upper bus address bits 18-31 */
-       __u32 lba;              /* lower bus address bits 0-31 */
-}; 
-
-
-// J. McCarty's LINK.H
-//
-//     LS_RJT Reason Codes
-//
-
-#define INVALID_COMMAND_CODE   0x01
-#define LOGICAL_ERROR          0x03
-#define LOGICAL_BUSY           0x05
-#define PROTOCOL_ERROR         0x07
-#define UNABLE_TO_PERFORM      0x09
-#define COMMAND_NOT_SUPPORTED  0x0B
-#define LS_VENDOR_UNIQUE       0xFF
-
-//
-//     LS_RJT Reason Codes Explanations
-//
-#define NO_REASON              0x00
-#define OPTIONS_ERROR          0x01
-#define INITIATOR_CTL_ERROR    0x03
-#define RECIPIENT_CTL_ERROR    0x05
-#define DATA_FIELD_SIZE_ERROR  0x07
-#define CONCURRENT_SEQ_ERROR   0x09
-#define CREDIT_ERROR           0x0B
-#define INVALID_PORT_NAME      0x0D
-#define INVALID_NODE_NAME      0x0E
-#define INVALID_CSP            0x0F    // Invalid Service Parameters
-#define INVALID_ASSOC_HDR      0x11    // Invalid Association Header
-#define ASSOC_HDR_REQUIRED     0x13    // Association Header Required
-#define LS_INVALID_S_ID                0x15
-#define INVALID_OX_RX_ID       0x17    // Invalid OX_ID RX_ID Combination
-#define CMD_IN_PROCESS         0x19
-#define INVALID_IDENTIFIER     0x1F    // Invalid N_PORT Identifier
-#define INVALID_SEQ_ID         0x21
-#define ABT_INVALID_XCHNG      0x23    // Attempt to Abort an invalid Exchange
-#define ABT_INACTIVE_XCHNG     0x25    // Attempt to Abort an inactive Exchange
-#define NEED_REC_QUAL          0x27    // Recovery Qualifier required
-#define NO_LOGIN_RESOURCES     0x29    // No resources to support login
-#define NO_DATA                        0x2A    // Unable to supply requested data
-#define        REQUEST_NOT_SUPPORTED   0x2C    // Request Not Supported
-
-//
-//     Link Control Codes
-//
-
-//
-//     P_BSY Action Codes
-//
-#define SEQUENCE_TERMINATED    0x01000000
-#define SEQUENCE_ACTIVE                0x02000000
-
-//
-//     P_BSY Reason Codes
-//
-#define PHYS_NPORT_BUSY                0x010000
-#define NPORT_RESOURCE_BUSY    0x020000
-
-//
-//     P_RJT, F_RJT Action Codes
-//
-
-#define RETRYABLE_ERROR                0x01000000
-#define NON_RETRYABLE_ERROR    0x02000000
-
-//
-//     P_RJT, F_RJT Reason Codes
-//
-#define INVALID_D_ID           0x010000
-#define INVALID_S_ID           0x020000
-#define NPORT_NOT_AVAIL_TMP    0x030000
-#define NPORT_NOT_AVAIL_PERM   0x040000
-#define CLASS_NOT_SUPPORTED    0x050000
-#define USAGE_ERROR            0x060000
-#define TYPE_NOT_SUPPORTED     0x070000
-#define INVAL_LINK_CONTROL     0x080000
-#define INVAL_R_CTL            0x090000
-#define INVAL_F_CTL            0x0A0000
-#define INVAL_OX_ID            0x0B0000
-#define INVAL_RX_ID            0x0C0000
-#define INVAL_SEQ_ID           0x0D0000
-#define INVAL_DF_CTL           0x0E0000
-#define INVAL_SEQ_CNT          0x0F0000
-#define INVAL_PARAMS           0x100000
-#define EXCHANGE_ERROR         0x110000
-#define LS_PROTOCOL_ERROR      0x120000
-#define INCORRECT_LENGTH       0x130000
-#define UNEXPECTED_ACK         0x140000
-#define LOGIN_REQ              0x160000
-#define EXCESSIVE_SEQ          0x170000
-#define NO_EXCHANGE            0x180000
-#define SEC_HDR_NOT_SUPPORTED  0x190000
-#define NO_FABRIC              0x1A0000
-#define P_VENDOR_UNIQUE                0xFF0000
-
-//
-//     BA_RJT Reason Codes
-//
-#define BA_INVALID_COMMAND     0x00010000
-#define BA_LOGICAL_ERROR       0x00030000
-#define BA_LOGICAL_BUSY                0x00050000
-#define BA_PROTOCOL_ERROR      0x00070000
-#define BA_UNABLE_TO_PERFORM   0x00090000
-
-//
-//     BA_RJT Reason Explanation Codes
-//
-#define BA_NO_REASON           0x00000000
-#define BA_INVALID_OX_RX       0x00000300
-#define BA_SEQUENCE_ABORTED    0x00000500
-
-
-
-#endif /* CPQFCTSSTRUCTS_H     */
-
diff --git a/drivers/scsi/cpqfcTStrigger.c b/drivers/scsi/cpqfcTStrigger.c
deleted file mode 100644 (file)
index dbb7e65..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-// Routine to trigger Finisar GTA analyzer. Runs of GPIO2
-// NOTE: DEBUG ONLY! Could interfere with FCMNGR/Miniport operation
-// since it writes directly to the Tachyon board.  This function
-// developed for Compaq HBA Tachyon TS v1.2 (Rev X5 PCB)
-
-#include "cpqfcTStrigger.h"
-#if TRIGGERABLE_HBA
-
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-
-void TriggerHBA( void* IOBaseUpper, int Print)
-{
-  __u32 long value;
-
-  // get initial value in hopes of not modifying any other GPIO line
-  IOBaseUpper += 0x188;  // TachTL/TS Control reg
-  
-  value = readl( IOBaseUpper);
-  // set HIGH to trigger external analyzer (tested on Dolche Finisar 1Gb GTA)
-  // The Finisar anaylzer triggers on low-to-high TTL transition
-  value |= 0x01; // set bit 0
-
-  writel( value, IOBaseUpper);
-
-  if( Print)
-    printk( " -GPIO0 set- ");
-}
-
-#endif
diff --git a/drivers/scsi/cpqfcTStrigger.h b/drivers/scsi/cpqfcTStrigger.h
deleted file mode 100644 (file)
index c961792..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// don't do this unless you have the right hardware!
-#define TRIGGERABLE_HBA 0
-#if TRIGGERABLE_HBA
-void TriggerHBA( void*, int);
-#else
-#define TriggerHBA(x, y)
-#endif
-
diff --git a/drivers/scsi/cpqfcTSworker.c b/drivers/scsi/cpqfcTSworker.c
deleted file mode 100644 (file)
index d822ddc..0000000
+++ /dev/null
@@ -1,6516 +0,0 @@
-/* Copyright(c) 2000, Compaq Computer Corporation 
- * Fibre Channel Host Bus Adapter 
- * 64-bit, 66MHz PCI 
- * Originally developed and tested on:
- * (front): [chip] Tachyon TS HPFC-5166A/1.2  L2C1090 ...
- *          SP# P225CXCBFIEL6T, Rev XC
- *          SP# 161290-001, Rev XD
- * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- * Written by Don Zimmerman
-*/
-
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/stat.h>
-#include <linux/blkdev.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/smp_lock.h>
-#include <linux/pci.h>
-
-#define SHUTDOWN_SIGS  (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM))
-
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/dma.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>   // struct Scsi_Host definition for T handler
-#include "cpqfcTSchip.h"
-#include "cpqfcTSstructs.h"
-#include "cpqfcTStrigger.h"
-
-//#define LOGIN_DBG 1
-
-// REMARKS:
-// Since Tachyon chips may be permitted to wait from 500ms up to 2 sec
-// to empty an outgoing frame from its FIFO to the Fibre Channel stream,
-// we cannot do everything we need to in the interrupt handler.  Specifically,
-// every time a link re-init (e.g. LIP) takes place, all SCSI I/O has to be
-// suspended until the login sequences have been completed.  Login commands
-// are frames just like SCSI commands are frames; they are subject to the same
-// timeout issues and delays.  Also, various specs provide up to 2 seconds for
-// devices to log back in (i.e. respond with ACC to a login frame), so I/O to
-// that device has to be suspended.
-// A serious problem here occurs on highly loaded FC-AL systems.  If our FC port
-// has a low priority (e.g. high arbitrated loop physical address, alpa), and
-// some other device is hogging bandwidth (permissible under FC-AL), we might
-// time out thinking the link is hung, when it's simply busy.  Many such
-// considerations complicate the design.  Although Tachyon assumes control
-// (in silicon) for many link-specific issues, the Linux driver is left with the
-// rest, which turns out to be a difficult, time critical chore.
-
-// These "worker" functions will handle things like FC Logins; all
-// processes with I/O to our device must wait for the Login to complete
-// and (if successful) I/O to resume.  In the event of a malfunctioning or  
-// very busy loop, it may take hundreds of millisecs or even seconds to complete
-// a frame send.  We don't want to hang up the entire server (and all
-// processes which don't depend on Fibre) during this wait.
-
-// The Tachyon chip can have around 30,000 I/O operations ("exchanges")
-// open at one time.  However, each exchange must be initiated 
-// synchronously (i.e. each of the 30k I/O had to be started one at a
-// time by sending a starting frame via Tachyon's outbound que).  
-
-// To accommodate kernel "module" build, this driver limits the exchanges
-// to 256, because of the contiguous physical memory limitation of 128M.
-
-// Typical FC Exchanges are opened presuming the FC frames start without errors,
-// while Exchange completion is handled in the interrupt handler.  This
-// optimizes performance for the "everything's working" case.
-// However, when we have FC related errors or hot plugging of FC ports, we pause
-// I/O and handle FC-specific tasks in the worker thread.  These FC-specific
-// functions will handle things like FC Logins and Aborts.  As the Login sequence
-// completes to each and every target, I/O can resume to that target.  
-
-// Our kernel "worker thread" must share the HBA with threads calling 
-// "queuecommand".  We define a "BoardLock" semaphore which indicates
-// to "queuecommand" that the HBA is unavailable, and Cmnds are added to a
-// board lock Q.  When the worker thread finishes with the board, the board
-// lock Q commands are completed with status causing immediate retry.
-// Typically, the board is locked while Logins are in progress after an
-// FC Link Down condition.  When Cmnds are re-queued after board lock, the
-// particular Scsi channel/target may or may not have logged back in.  When
-// the device is waiting for login, the "prli" flag is clear, in which case
-// commands are passed to a Link Down Q.  Whenever the login finally completes,
-// the LinkDown Q is completed, again with status causing immediate retry.
-// When FC devices are logged in, we build and start FC commands to the
-// devices.
-
-// NOTE!! As of May 2000, kernel 2.2.14, the error recovery logic for devices 
-// that never log back in (e.g. physically removed) is NOT completely
-// understood.  I've still seen instances of system hangs on failed Write 
-// commands (possibly from the ext2 layer?) on device removal.  Such special
-// cases need to be evaluated from a system/application view - e.g., how
-// exactly does the system want me to complete commands when the device is
-// physically removed??
-
-// local functions
-
-static void SetLoginFields(
-  PFC_LOGGEDIN_PORT pLoggedInPort,
-  TachFCHDR_GCMND* fchs,
-  BOOLEAN PDisc,
-  BOOLEAN Originator);
-
-static void AnalyzeIncomingFrame( 
-       CPQFCHBA *cpqfcHBAdata,
-       ULONG QNdx );
-
-static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds );
-
-static int verify_PLOGI( PTACHYON fcChip,
-      TachFCHDR_GCMND* fchs, ULONG* reject_explain);
-static int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain);
-
-static void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type);
-static void BuildLinkServicePayload( 
-              PTACHYON fcChip, ULONG type, void* payload);
-
-static void UnblockScsiDevice( struct Scsi_Host *HostAdapter, 
-        PFC_LOGGEDIN_PORT pLoggedInPort);
-
-static void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID);
-
-static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata);
-
-static void RevalidateSEST( struct Scsi_Host *HostAdapter, 
-                       PFC_LOGGEDIN_PORT pLoggedInPort);
-
-static void IssueReportLunsCommand( 
-              CPQFCHBA* cpqfcHBAdata, 
-             TachFCHDR_GCMND* fchs);
-
-// (see scsi_error.c comments on kernel task creation)
-
-void cpqfcTSWorkerThread( void *host)
-{
-  struct Scsi_Host *HostAdapter = (struct Scsi_Host*)host;
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; 
-#ifdef PCI_KERNEL_TRACE
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-#endif
-  DECLARE_MUTEX_LOCKED(fcQueReady);
-  DECLARE_MUTEX_LOCKED(fcTYOBcomplete); 
-  DECLARE_MUTEX_LOCKED(TachFrozen);  
-  DECLARE_MUTEX_LOCKED(BoardLock);  
-
-  ENTER("WorkerThread");
-
-  lock_kernel();
-  daemonize("cpqfcTS_wt_%d", HostAdapter->host_no);
-  siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
-
-
-  cpqfcHBAdata->fcQueReady = &fcQueReady;  // primary wait point
-  cpqfcHBAdata->TYOBcomplete = &fcTYOBcomplete;
-  cpqfcHBAdata->TachFrozen = &TachFrozen;
-    
-  cpqfcHBAdata->worker_thread = current;
-  
-  unlock_kernel();
-
-  if( cpqfcHBAdata->notify_wt != NULL )
-    up( cpqfcHBAdata->notify_wt); // OK to continue
-
-  while(1)
-  {
-    unsigned long flags;
-
-    down_interruptible( &fcQueReady);  // wait for something to do
-
-    if (signal_pending(current) )
-      break;
-    
-    PCI_TRACE( 0x90)
-    // first, take the IO lock so the SCSI upper layers can't call
-    // into our _quecommand function (this also disables INTs)
-    spin_lock_irqsave( HostAdapter->host_lock, flags); // STOP _que function
-    PCI_TRACE( 0x90)
-         
-    CPQ_SPINLOCK_HBA( cpqfcHBAdata)
-    // next, set this pointer to indicate to the _quecommand function
-    // that the board is in use, so it should que the command and 
-    // immediately return (we don't actually require the semaphore function
-    // in this driver rev)
-
-    cpqfcHBAdata->BoardLock = &BoardLock;
-
-    PCI_TRACE( 0x90)
-
-    // release the IO lock (and re-enable interrupts)
-    spin_unlock_irqrestore( HostAdapter->host_lock, flags);
-
-    // disable OUR HBA interrupt (keep them off as much as possible
-    // during error recovery)
-    disable_irq( cpqfcHBAdata->HostAdapter->irq);
-
-    // OK, let's process the Fibre Channel Link Q and do the work
-    cpqfcTS_WorkTask( HostAdapter);
-
-    // hopefully, no more "work" to do;
-    // re-enable our INTs for "normal" completion processing
-    enable_irq( cpqfcHBAdata->HostAdapter->irq);
-
-    cpqfcHBAdata->BoardLock = NULL; // allow commands to be queued
-    CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
-
-
-    // Now, complete any Cmnd we Q'd up while BoardLock was held
-
-    CompleteBoardLockCmnd( cpqfcHBAdata);
-  
-
-  }
-  // hopefully, the signal was for our module exit...
-  if( cpqfcHBAdata->notify_wt != NULL )
-    up( cpqfcHBAdata->notify_wt); // yep, we're outta here
-}
-
-
-// Freeze Tachyon routine.
-// If Tachyon is already frozen, return FALSE
-// If Tachyon is not frozen, call freeze function, return TRUE
-//
-static BOOLEAN FreezeTach( CPQFCHBA *cpqfcHBAdata)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  BOOLEAN FrozeTach = FALSE;
-  // It's possible that the chip is already frozen; if so,
-  // "Freezing" again will NOT! generate another Freeze
-  // Completion Message.
-
-  if( (fcChip->Registers.TYstatus.value & 0x70000) != 0x70000)
-  {  // (need to freeze...)
-    fcChip->FreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
-
-    // 2. Get Tach freeze confirmation
-    // (synchronize SEST manipulation with Freeze Completion Message)
-    // we need INTs on so semaphore can be set.        
-    enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Semaphore
-    down_interruptible( cpqfcHBAdata->TachFrozen); // wait for INT handler sem.
-    // can we TIMEOUT semaphore wait?? TBD
-    disable_irq( cpqfcHBAdata->HostAdapter->irq); 
-
-    FrozeTach = TRUE;
-  }  // (else, already frozen)
-  return FrozeTach;
-}  
-
-
-
-
-// This is the kernel worker thread task, which processes FC
-// tasks which were queued by the Interrupt handler or by
-// other WorkTask functions.
-
-#define DBG 1
-//#undef DBG
-void cpqfcTS_WorkTask( struct Scsi_Host *HostAdapter)
-{
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG QconsumerNdx;
-  LONG ExchangeID;
-  ULONG ulStatus=0;
-  TachFCHDR_GCMND fchs;
-  PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
-
-  ENTER("WorkTask");
-
-  // copy current index to work on
-  QconsumerNdx = fcLQ->consumer;
-
-  PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x90)
-  
-
-  // NOTE: when this switch completes, we will "consume" the Que item
-//  printk("Que type %Xh\n", fcLQ->Qitem[QconsumerNdx].Type);
-  switch( fcLQ->Qitem[QconsumerNdx].Type )
-  {
-      // incoming frame - link service (ACC, UNSOL REQ, etc.)
-      // or FCP-SCSI command
-    case SFQ_UNKNOWN:  
-      AnalyzeIncomingFrame( cpqfcHBAdata, QconsumerNdx );
-
-      break;
-  
-    
-    
-    case EXCHANGE_QUEUED:  // an Exchange (i.e. FCP-SCSI) was previously
-                           // Queued because the link was down.  The  
-                           // heartbeat timer detected it and Queued it here.
-                           // We attempt to start it again, and if
-                           // successful we clear the EXCHANGE_Q flag.
-                           // If the link doesn't come up, the Exchange
-                           // will eventually time-out.
-
-      ExchangeID = (LONG)  // x_ID copied from DPC timeout function
-                   fcLQ->Qitem[QconsumerNdx].ulBuff[0];
-
-      // It's possible that a Q'd exchange could have already
-      // been started by other logic (e.g. ABTS process)
-      // Don't start if already started (Q'd flag clear)
-
-      if( Exchanges->fcExchange[ExchangeID].status & EXCHANGE_QUEUED )
-      {
-//        printk(" *Start Q'd x_ID %Xh: type %Xh ", 
-//          ExchangeID, Exchanges->fcExchange[ExchangeID].type);
-      
-        ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID);
-        if( !ulStatus )
-        {
-//          printk("success* ");
-        }      
-        else
-        {
-#ifdef DBG
-      
-          if( ulStatus == EXCHANGE_QUEUED)
-            printk("Queued* ");
-          else
-            printk("failed* ");
-               
-#endif
-       } 
-      }
-      break;
-
-
-    case LINKDOWN:  
-      // (lots of things already done in INT handler) future here?
-      break;
-    
-    
-    case LINKACTIVE:   // Tachyon set the Lup bit in FM status
-                       // NOTE: some misbehaving FC ports (like Tach2.1)
-                       // can re-LIP immediately after a LIP completes.
-      
-      // if "initiator", need to verify LOGs with ports
-//      printk("\n*LNKUP* ");
-
-      if( fcChip->Options.initiator )
-        SendLogins( cpqfcHBAdata, NULL ); // PLOGI or PDISC, based on fcPort data
-                  // if SendLogins successfully completes, PortDiscDone
-                  // will be set.
-      
-      
-      // If SendLogins was successful, then we expect to get incoming
-      // ACCepts or REJECTs, which are handled below.
-
-      break;
-
-    // LinkService and Fabric request/reply processing
-    case ELS_FDISC:      // need to send Fabric Discovery (Login)
-    case ELS_FLOGI:      // need to send Fabric Login
-    case ELS_SCR:        // need to send State Change Registration
-    case FCS_NSR:        // need to send Name Service Request
-    case ELS_PLOGI:      // need to send PLOGI
-    case ELS_ACC:        // send generic ACCept
-    case ELS_PLOGI_ACC:  // need to send ELS ACCept frame to recv'd PLOGI
-    case ELS_PRLI_ACC:   // need to send ELS ACCept frame to recv'd PRLI
-    case ELS_LOGO:      // need to send ELS LOGO (logout)
-    case ELS_LOGO_ACC:  // need to send ELS ACCept frame to recv'd PLOGI
-    case ELS_RJT:         // ReJecT reply
-    case ELS_PRLI:       // need to send ELS PRLI
-    
-//      printk(" *ELS %Xh* ", fcLQ->Qitem[QconsumerNdx].Type);
-      // if PortDiscDone is not set, it means the SendLogins routine
-      // failed to complete -- assume that LDn occurred, so login frames
-      // are invalid
-      if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
-      {
-        printk("Discard Q'd ELS login frame\n");
-        break;  
-      }
-
-      ulStatus = cpqfcTSBuildExchange(
-          cpqfcHBAdata,
-          fcLQ->Qitem[QconsumerNdx].Type, // e.g. PLOGI
-          (TachFCHDR_GCMND*)
-            fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
-          NULL,         // no data (no scatter/gather list)
-          &ExchangeID );// fcController->fcExchanges index, -1 if failed
-
-      if( !ulStatus ) // Exchange setup?
-      {
-        ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
-        if( !ulStatus )
-        {
-          // submitted to Tach's Outbound Que (ERQ PI incremented)
-          // waited for completion for ELS type (Login frames issued
-          // synchronously)
-        }
-        else
-          // check reason for Exchange not being started - we might
-          // want to Queue and start later, or fail with error
-        {
-
-        }
-      }
-
-      else   // Xchange setup failed...
-        printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
-
-      break;
-
-    case SCSI_REPORT_LUNS:
-      // pass the incoming frame (actually, it's a PRLI frame)
-      // so we can send REPORT_LUNS, in order to determine VSA/PDU
-      // FCP-SCSI Lun address mode
-      IssueReportLunsCommand( cpqfcHBAdata, (TachFCHDR_GCMND*)
-            fcLQ->Qitem[QconsumerNdx].ulBuff); 
-
-      break;
-      
-
-
-
-    case BLS_ABTS:       // need to ABORT one or more exchanges
-    {
-      LONG x_ID = fcLQ->Qitem[QconsumerNdx].ulBuff[0];
-      BOOLEAN FrozeTach = FALSE;   
-     
-      if ( x_ID >= TACH_SEST_LEN )  // (in)sanity check
-      {
-//     printk( " cpqfcTS ERROR! BOGUS x_ID %Xh", x_ID);
-       break;
-      }
-
-
-      if( Exchanges->fcExchange[ x_ID].Cmnd == NULL ) // should be RARE
-      {
-//     printk(" ABTS %Xh Scsi Cmnd null! ", x_ID);
-       
-       break;  // nothing to abort!
-      }
-
-//#define ABTS_DBG
-#ifdef ABTS_DBG
-      printk("INV SEST[%X] ", x_ID); 
-      if( Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT)
-      {
-        printk("FC2TO");
-      }
-      if( Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)
-      {
-        printk("IA");
-      }
-      if( Exchanges->fcExchange[x_ID].status & PORTID_CHANGED)
-      {
-        printk("PORTID");
-      }
-      if( Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED)
-      {
-        printk("DEVRM");
-      }
-      if( Exchanges->fcExchange[x_ID].status & LINKFAIL_TX)
-      {
-        printk("LKF");
-      }
-      if( Exchanges->fcExchange[x_ID].status & FRAME_TO)
-      {
-        printk("FRMTO");
-      }
-      if( Exchanges->fcExchange[x_ID].status & ABORTSEQ_NOTIFY)
-      {
-        printk("ABSQ");
-      }
-      if( Exchanges->fcExchange[x_ID].status & SFQ_FRAME)
-      {
-        printk("SFQFR");
-      }
-
-      if( Exchanges->fcExchange[ x_ID].type == 0x2000)
-        printk(" WR");
-      else if( Exchanges->fcExchange[ x_ID].type == 0x3000)
-        printk(" RD");
-      else if( Exchanges->fcExchange[ x_ID].type == 0x10)
-        printk(" ABTS");
-      else
-        printk(" %Xh", Exchanges->fcExchange[ x_ID].type); 
-
-      if( !(Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT))
-      {
-       printk(" Cmd %p, ", 
-          Exchanges->fcExchange[ x_ID].Cmnd);
-
-        printk(" brd/chn/trg/lun %d/%d/%d/%d port_id %06X\n", 
-          cpqfcHBAdata->HBAnum,
-          Exchanges->fcExchange[ x_ID].Cmnd->channel,
-          Exchanges->fcExchange[ x_ID].Cmnd->target,
-          Exchanges->fcExchange[ x_ID].Cmnd->lun,
-          Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF);
-      }
-      else  // assume that Cmnd ptr is invalid on _abort()
-      {
-       printk(" Cmd ptr invalid\n");
-      }
-     
-#endif      
-
-      
-      // Steps to ABORT a SEST exchange:
-      // 1. Freeze TL SCSI assists & ERQ (everything)
-      // 2. Receive FROZEN inbound CM (must succeed!)
-      // 3. Invalidate x_ID SEST entry 
-      // 4. Resume TL SCSI assists & ERQ (everything)
-      // 5. Build/start on exchange - change "type" to BLS_ABTS,
-      //    timeout to X sec (RA_TOV from PLDA is actually 0)
-      // 6. Set Exchange Q'd status if ABTS cannot be started,
-      //    or simply complete Exchange in "Terminate" condition
-
-  PCI_TRACEO( x_ID, 0xB4)
-      
-      // 1 & 2 . Freeze Tach & get confirmation of freeze
-      FrozeTach = FreezeTach( cpqfcHBAdata);
-
-      // 3. OK, Tachyon is frozen, so we can invalidate SEST exchange.
-      // FC2_TIMEOUT means we are originating the abort, while
-      // TARGET_ABORT means we are ACCepting an abort.
-      // LINKFAIL_TX, ABORTSEQ_NOFITY, INV_ENTRY or FRAME_TO are 
-      // all from Tachyon:
-      // Exchange was corrupted by LDn or other FC physical failure
-      // INITIATOR_ABORT means the upper layer driver/application
-      // requested the abort.
-
-
-         
-      // clear bit 31 (VALid), to invalidate & take control from TL
-      fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
-
-
-      // examine and Tach's "Linked List" for IWEs that 
-      // received (nearly) simultaneous transfer ready (XRDY) 
-      // repair linked list if necessary (TBD!)
-      // (If we ignore the "Linked List", we will time out
-      // WRITE commands where we received the FCP-SCSI XFRDY
-      // frame (because Tachyon didn't processes it).  Linked List
-      // management should be done as an optimization.
-
-//       readl( fcChip->Registers.ReMapMemBase+TL_MEM_SEST_LINKED_LIST ));
-
-
-      
-
-      // 4. Resume all Tachlite functions (for other open Exchanges)
-      // as quickly as possible to allow other exchanges to other ports
-      // to resume.  Freezing Tachyon may cause cascading errors, because
-      // any received SEST frame cannot be processed by the SEST.
-      // Don't "unfreeze" unless Link is operational
-      if( FrozeTach )  // did we just freeze it (above)?
-        fcChip->UnFreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
-      
-
-  PCI_TRACEO( x_ID, 0xB4)
-
-      // Note there is no confirmation that the chip is "unfrozen".  Also,
-      // if the Link is down when unfreeze is called, it has no effect.
-      // Chip will unfreeze when the Link is back up.
-
-      // 5. Now send out Abort commands if possible
-      // Some Aborts can't be "sent" (Port_id changed or gone);
-      // if the device is gone, there is no port_id to send the ABTS to.
-
-      if( !(Exchanges->fcExchange[ x_ID].status & PORTID_CHANGED)
-                         &&
-          !(Exchanges->fcExchange[ x_ID].status & DEVICE_REMOVED) )
-      {
-        Exchanges->fcExchange[ x_ID].type = BLS_ABTS;
-        fchs.s_id = Exchanges->fcExchange[ x_ID].fchs.d_id;
-        ulStatus = cpqfcTSBuildExchange(
-          cpqfcHBAdata,
-          BLS_ABTS,
-          &fchs,        // (uses only s_id)
-          NULL,         // (no scatter/gather list for ABTS)
-          &x_ID );// ABTS on this Exchange ID
-
-        if( !ulStatus ) // Exchange setup build OK?
-        {
-
-            // ABTS may be needed because an Exchange was corrupted
-            // by a Link disruption.  If the Link is UP, we can
-           // presume that this ABTS can start immediately; otherwise,
-           // set Que'd status so the Login functions
-            // can restart it when the FC physical Link is restored
-          if( ((fcChip->Registers.FMstatus.value &0xF0) &0x80)) // loop init?
-          {                        
-//                printk(" *set Q status x_ID %Xh on LDn* ", x_ID);
-                Exchanges->fcExchange[ x_ID].status |= EXCHANGE_QUEUED;
-          }
-
-          else  // what FC device (port_id) does the Cmd belong to?
-          {
-            PFC_LOGGEDIN_PORT pLoggedInPort = 
-              Exchanges->fcExchange[ x_ID].pLoggedInPort;
-            
-            // if Port is logged in, we might start the abort.
-       
-            if( (pLoggedInPort != NULL) 
-                             &&
-                (pLoggedInPort->prli == TRUE) ) 
-            {
-              // it's possible that an Exchange has already been Queued
-              // to start after Login completes.  Check and don't
-             // start it (again) here if Q'd status set
-//         printk(" ABTS xchg %Xh ", x_ID);            
-             if( Exchanges->fcExchange[x_ID].status & EXCHANGE_QUEUED)
-             {
-//                 printk("already Q'd ");
-             }
-             else
-             {
-//                 printk("starting ");
-               
-                fcChip->fcStats.FC2aborted++; 
-                ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID );
-                if( !ulStatus )
-                {
-                    // OK
-                    // submitted to Tach's Outbound Que (ERQ PI incremented)
-                }
-                else
-                {
-/*                   printk("ABTS exchange start failed -status %Xh, x_ID %Xh ",
-                        ulStatus, x_ID);
-*/
-                } 
-             }
-           }
-           else
-           {
-/*               printk(" ABTS NOT starting xchg %Xh, %p ",
-                              x_ID, pLoggedInPort);
-                 if( pLoggedInPort )
-                   printk("prli %d ", pLoggedInPort->prli);
-*/
-           }           
-         }
-        }
-        else  // what the #@!
-        {  // how do we fail to build an Exchange for ABTS??
-              printk("ABTS exchange build failed -status %Xh, x_ID %Xh\n",
-                ulStatus, x_ID);
-        }
-      }
-      else   // abort without ABTS -- just complete exchange/Cmnd to Linux
-      {
-//            printk(" *Terminating x_ID %Xh on %Xh* ", 
-//                 x_ID, Exchanges->fcExchange[x_ID].status);
-        cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, x_ID);
-
-      }
-    } // end of ABTS case
-      break;
-
-
-
-    case BLS_ABTS_ACC:   // need to ACCept one ABTS
-                         // (NOTE! this code not updated for Linux yet..)
-      
-
-      printk(" *ABTS_ACC* ");
-      // 1. Freeze TL
-
-      fcChip->FreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
-
-      memcpy(  // copy the incoming ABTS frame
-        &fchs,
-        fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
-        sizeof( fchs));
-
-      // 3. OK, Tachyon is frozen so we can invalidate SEST entry 
-      // (if necessary)
-      // Status FC2_TIMEOUT means we are originating the abort, while
-      // TARGET_ABORT means we are ACCepting an abort
-      
-      ExchangeID = fchs.ox_rx_id & 0x7FFF; // RX_ID for exchange
-//      printk("ABTS ACC for Target ExchangeID %Xh\n", ExchangeID);
-
-
-      // sanity check on received ExchangeID
-      if( Exchanges->fcExchange[ ExchangeID].status == TARGET_ABORT )
-      {
-          // clear bit 31 (VALid), to invalidate & take control from TL
-//          printk("Invalidating SEST exchange %Xh\n", ExchangeID);
-          fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len &= 0x7FFFFFFF;
-      }
-
-
-      // 4. Resume all Tachlite functions (for other open Exchanges)
-      // as quickly as possible to allow other exchanges to other ports
-      // to resume.  Freezing Tachyon for too long may royally screw
-      // up everything!
-      fcChip->UnFreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
-      
-      // Note there is no confirmation that the chip is "unfrozen".  Also,
-      // if the Link is down when unfreeze is called, it has no effect.
-      // Chip will unfreeze when the Link is back up.
-
-      // 5. Now send out Abort ACC reply for this exchange
-      Exchanges->fcExchange[ ExchangeID].type = BLS_ABTS_ACC;
-      
-      fchs.s_id = Exchanges->fcExchange[ ExchangeID].fchs.d_id;
-      ulStatus = cpqfcTSBuildExchange(
-            cpqfcHBAdata,
-            BLS_ABTS_ACC,
-            &fchs,
-            NULL,         // no data (no scatter/gather list)
-            &ExchangeID );// fcController->fcExchanges index, -1 if failed
-
-      if( !ulStatus ) // Exchange setup?
-      {
-        ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
-        if( !ulStatus )
-        {
-          // submitted to Tach's Outbound Que (ERQ PI incremented)
-          // waited for completion for ELS type (Login frames issued
-          // synchronously)
-        }
-        else
-          // check reason for Exchange not being started - we might
-          // want to Queue and start later, or fail with error
-        {
-
-        } 
-      }
-      break;
-
-
-    case BLS_ABTS_RJT:   // need to ReJecT one ABTS; reject implies the
-                         // exchange doesn't exist in the TARGET context.
-                         // ExchangeID has to come from LinkService space.
-
-      printk(" *ABTS_RJT* ");
-      ulStatus = cpqfcTSBuildExchange(
-            cpqfcHBAdata,
-            BLS_ABTS_RJT,
-            (TachFCHDR_GCMND*)
-              fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
-            NULL,         // no data (no scatter/gather list)
-            &ExchangeID );// fcController->fcExchanges index, -1 if failed
-
-      if( !ulStatus ) // Exchange setup OK?
-      {
-        ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
-        // If it fails, we aren't required to retry.
-      }
-      if( ulStatus )
-      {
-        printk("Failed to send BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
-      }
-      else
-      {
-        printk("Sent BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
-      
-      }
-
-      break;
-
-
-
-    default:
-      break;
-  }                   // end switch
-//doNothing:
-    // done with this item - now set the NEXT index
-
-  if( QconsumerNdx+1 >= FC_LINKQ_DEPTH ) // rollover test
-  {
-    fcLQ->consumer = 0;
-  }
-  else
-  { 
-    fcLQ->consumer++;
-  }
-
-  PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x94)
-
-  LEAVE("WorkTask");
-  return;
-}
-
-
-
-
-// When Tachyon reports link down, bad al_pa, or Link Service (e.g. Login)
-// commands come in, post to the LinkQ so that action can be taken outside the
-// interrupt handler.  
-// This circular Q works like Tachyon's que - the producer points to the next
-// (unused) entry.  Called by Interrupt handler, WorkerThread, Timer
-// sputlinkq
-void cpqfcTSPutLinkQue( CPQFCHBA *cpqfcHBAdata,
-  int Type, 
-  void *QueContent)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-//  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
-  ULONG ndx;
-  
-  ENTER("cpqfcTSPutLinkQ");
-
-  ndx = fcLQ->producer;
-  
-  ndx += 1;  // test for Que full
-
-
-  
-  if( ndx >= FC_LINKQ_DEPTH ) // rollover test
-    ndx = 0;
-
-  if( ndx == fcLQ->consumer )   // QUE full test
-  {
-                       // QUE was full! lost LK command (fatal to logic)
-    fcChip->fcStats.lnkQueFull++;
-
-    printk("*LinkQ Full!*");
-    TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
-/*
-    {
-      int i;
-      printk("LinkQ PI %d, CI %d\n", fcLQ->producer,
-        fcLQ->consumer);
-                     
-      for( i=0; i< FC_LINKQ_DEPTH; )
-      {
-       printk(" [%d]%Xh ", i, fcLQ->Qitem[i].Type);
-       if( (++i %8) == 0) printk("\n");
-      }
-  
-    }
-*/    
-    printk( "cpqfcTS: WARNING!! PutLinkQue - FULL!\n"); // we're hung
-  }
-  else                        // QUE next element
-  {
-    // Prevent certain multiple (back-to-back) requests.
-    // This is important in that we don't want to issue multiple
-    // ABTS for the same Exchange, or do multiple FM inits, etc.
-    // We can never be sure of the timing of events reported to
-    // us by Tach's IMQ, which can depend on system/bus speeds,
-    // FC physical link circumstances, etc.
-     
-    if( (fcLQ->producer != fcLQ->consumer)
-           && 
-        (Type == FMINIT)  )
-    {
-      LONG lastNdx;  // compute previous producer index
-      if( fcLQ->producer)
-        lastNdx = fcLQ->producer- 1;
-      else
-       lastNdx = FC_LINKQ_DEPTH-1;
-
-
-      if( fcLQ->Qitem[lastNdx].Type == FMINIT)
-      {
-//        printk(" *skip FMINIT Q post* ");
-//        goto DoneWithPutQ;
-      }
-
-    }
-
-    // OK, add the Q'd item...
-    
-    fcLQ->Qitem[fcLQ->producer].Type = Type;
-   
-    memcpy(
-        fcLQ->Qitem[fcLQ->producer].ulBuff,
-        QueContent, 
-        sizeof(fcLQ->Qitem[fcLQ->producer].ulBuff));
-
-    fcLQ->producer = ndx;  // increment Que producer
-
-    // set semaphore to wake up Kernel (worker) thread
-    // 
-    up( cpqfcHBAdata->fcQueReady );
-  }
-
-//DoneWithPutQ:
-
-  LEAVE("cpqfcTSPutLinkQ");
-}
-
-
-
-
-// reset device ext FC link Q
-void cpqfcTSLinkQReset( CPQFCHBA *cpqfcHBAdata)
-   
-{
-  PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
-  fcLQ->producer = 0;
-  fcLQ->consumer = 0;
-
-}
-
-
-
-
-
-// When Tachyon gets an unassisted FCP-SCSI frame, post here so
-// an arbitrary context thread (e.g. IOCTL loopback test function)
-// can process it.
-
-// (NOTE: Not revised for Linux)
-// This Q works like Tachyon's que - the producer points to the next
-// (unused) entry.
-void cpqfcTSPutScsiQue( CPQFCHBA *cpqfcHBAdata,
-  int Type, 
-  void *QueContent)
-{
-//  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-//  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-
-//  ULONG ndx;
-
-//  ULONG *pExchangeID;
-//  LONG ExchangeID;
-
-/*
-  KeAcquireSpinLockAtDpcLevel( &pDevExt->fcScsiQueLock);
-  ndx = pDevExt->fcScsiQue.producer + 1;  // test for Que full
-
-  if( ndx >= FC_SCSIQ_DEPTH ) // rollover test
-    ndx = 0;
-
-  if( ndx == pDevExt->fcScsiQue.consumer )   // QUE full test
-  {
-                       // QUE was full! lost LK command (fatal to logic)
-    fcChip->fcStats.ScsiQueFull++;
-#ifdef DBG
-    printk( "fcPutScsiQue - FULL!\n");
-#endif
-
-  }
-  else                        // QUE next element
-  {
-    pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].Type = Type;
-    
-    if( Type == FCP_RSP )
-    {
-      // this TL inbound message type means that a TL SEST exchange has
-      // copied an FCP response frame into a buffer pointed to by the SEST
-      // entry.  That buffer is allocated in the SEST structure at ->RspHDR.
-      // Copy the RspHDR for use by the Que handler.
-      pExchangeID = (ULONG *)QueContent;
-      
-      memcpy(
-             pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,
-        &fcChip->SEST->RspHDR[ *pExchangeID ],
-             sizeof(pDevExt->fcScsiQue.Qitem[0].ulBuff)); // (any element for size)
-      
-    }
-    else
-    {
-      memcpy(
-             pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,
-        QueContent, 
-             sizeof(pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff));
-    }
-      
-    pDevExt->fcScsiQue.producer = ndx;  // increment Que
-
-
-    KeSetEvent( &pDevExt->TYIBscsi,  // signal any waiting thread
-       0,                    // no priority boost
-                  FALSE );              // no waiting later for this event
-  }
-  KeReleaseSpinLockFromDpcLevel( &pDevExt->fcScsiQueLock);
-*/
-}
-
-
-
-
-
-
-
-static void ProcessELS_Request( CPQFCHBA*,TachFCHDR_GCMND*);
-
-static void ProcessELS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
-
-static void ProcessFCS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
-
-void cpqfcTSImplicitLogout( CPQFCHBA* cpqfcHBAdata,
-               PFC_LOGGEDIN_PORT pFcPort)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-
-  if( pFcPort->port_id != 0xFFFC01 ) // don't care about Fabric
-  {
-    fcChip->fcStats.logouts++;
-    printk("cpqfcTS: Implicit logout of WWN %08X%08X, port_id %06X\n", 
-        (ULONG)pFcPort->u.liWWN,
-        (ULONG)(pFcPort->u.liWWN >>32),
-       pFcPort->port_id);
-
-  // Terminate I/O with this (Linux) Scsi target
-    cpqfcTSTerminateExchange( cpqfcHBAdata, 
-                            &pFcPort->ScsiNexus,
-                           DEVICE_REMOVED);
-  }
-                       
-  // Do an "implicit logout" - we can't really Logout the device
-  // (i.e. with LOGOut Request) because of port_id confusion
-  // (i.e. the Other port has no port_id).
-  // A new login for that WWN will have to re-write port_id (0 invalid)
-  pFcPort->port_id = 0;  // invalid!
-  pFcPort->pdisc = FALSE;
-  pFcPort->prli = FALSE;
-  pFcPort->plogi = FALSE;
-  pFcPort->flogi = FALSE;
-  pFcPort->LOGO_timer = 0;
-  pFcPort->device_blocked = TRUE; // block Scsi Requests
-  pFcPort->ScsiNexus.VolumeSetAddressing=0;    
-}
-
-  
-// On FC-AL, there is a chance that a previously known device can
-// be quietly removed (e.g. with non-managed hub), 
-// while a NEW device (with different WWN) took the same alpa or
-// even 24-bit port_id.  This chance is unlikely but we must always
-// check for it.
-static void TestDuplicatePortId( CPQFCHBA* cpqfcHBAdata,
-               PFC_LOGGEDIN_PORT pLoggedInPort)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  // set "other port" at beginning of fcPorts list
-  PFC_LOGGEDIN_PORT pOtherPortWithPortId = fcChip->fcPorts.pNextPort;
-  while( pOtherPortWithPortId ) 
-  {
-    if( (pOtherPortWithPortId->port_id == 
-         pLoggedInPort->port_id) 
-                   &&
-         (pOtherPortWithPortId != pLoggedInPort) )
-    {
-      // trouble!  (Implicitly) Log the other guy out
-      printk(" *port_id %Xh is duplicated!* ", 
-        pOtherPortWithPortId->port_id);
-      cpqfcTSImplicitLogout( cpqfcHBAdata, pOtherPortWithPortId); 
-   }
-    pOtherPortWithPortId = pOtherPortWithPortId->pNextPort;
-  }
-}
-
-
-
-
-
-
-// Dynamic Memory Allocation for newly discovered FC Ports.
-// For simplicity, maintain fcPorts structs for ALL
-// for discovered devices, including those we never do I/O with
-// (e.g. Fabric addresses)
-
-static PFC_LOGGEDIN_PORT CreateFcPort( 
-         CPQFCHBA* cpqfcHBAdata, 
-         PFC_LOGGEDIN_PORT pLastLoggedInPort, 
-         TachFCHDR_GCMND* fchs,
-         LOGIN_PAYLOAD* plogi)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  PFC_LOGGEDIN_PORT pNextLoggedInPort = NULL;
-  int i;
-
-
-  printk("cpqfcTS: New FC port %06Xh WWN: ", fchs->s_id);
-  for( i=3; i>=0; i--)   // copy the LOGIN port's WWN
-    printk("%02X", plogi->port_name[i]);
-  for( i=7; i>3; i--)   // copy the LOGIN port's WWN
-    printk("%02X", plogi->port_name[i]);
-
-
-  // allocate mem for new port
-  // (these are small and rare allocations...)
-  pNextLoggedInPort = kmalloc( sizeof( FC_LOGGEDIN_PORT), GFP_ATOMIC );
-
-    
-  // allocation succeeded?  Fill out NEW PORT
-  if( pNextLoggedInPort )
-  {    
-                              // clear out any garbage (sometimes exists)
-    memset( pNextLoggedInPort, 0, sizeof( FC_LOGGEDIN_PORT));
-
-
-    // If we login to a Fabric, we don't want to treat it
-    // as a SCSI device...
-    if( (fchs->s_id & 0xFFF000) != 0xFFF000)
-    {
-      int i;
-      
-      // create a unique "virtual" SCSI Nexus (for now, just a
-      // new target ID) -- we will update channel/target on REPORT_LUNS
-      // special case for very first SCSI target...
-      if( cpqfcHBAdata->HostAdapter->max_id == 0)
-      {
-        pNextLoggedInPort->ScsiNexus.target = 0;
-        fcChip->fcPorts.ScsiNexus.target = -1; // don't use "stub"
-      }
-      else
-      {
-        pNextLoggedInPort->ScsiNexus.target =
-          cpqfcHBAdata->HostAdapter->max_id;
-      }
-
-      // initialize the lun[] Nexus struct for lun masking      
-      for( i=0; i< CPQFCTS_MAX_LUN; i++)
-        pNextLoggedInPort->ScsiNexus.lun[i] = 0xFF; // init to NOT USED
-      
-      pNextLoggedInPort->ScsiNexus.channel = 0; // cpqfcTS has 1 FC port
-      
-      printk(" SCSI Chan/Trgt %d/%d", 
-          pNextLoggedInPort->ScsiNexus.channel,
-          pNextLoggedInPort->ScsiNexus.target);
-      // tell Scsi layers about the new target...
-      cpqfcHBAdata->HostAdapter->max_id++; 
-//    printk("HostAdapter->max_id = %d\n",
-//      cpqfcHBAdata->HostAdapter->max_id);                
-    }                          
-    else
-    {
-      // device is NOT SCSI (in case of Fabric)
-      pNextLoggedInPort->ScsiNexus.target = -1;  // invalid
-    }
-
-         // create forward link to new port
-    pLastLoggedInPort->pNextPort = pNextLoggedInPort;
-    printk("\n");
-
-  }     
-  return pNextLoggedInPort;  // NULL on allocation failure
-}   // end NEW PORT (WWN) logic
-
-
-
-// For certain cases, we want to terminate exchanges without
-// sending ABTS to the device.  Examples include when an FC
-// device changed it's port_id after Loop re-init, or when
-// the device sent us a logout.  In the case of changed port_id,
-// we want to complete the command and return SOFT_ERROR to
-// force a re-try.  In the case of LOGOut, we might return
-// BAD_TARGET if the device is really gone.
-// Since we must ensure that Tachyon is not operating on the
-// exchange, we have to freeze the chip
-// sterminateex
-void cpqfcTSTerminateExchange( 
-  CPQFCHBA* cpqfcHBAdata, SCSI_NEXUS *ScsiNexus, int TerminateStatus)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG x_ID;
-
-  if( ScsiNexus )
-  {
-//    printk("TerminateExchange: ScsiNexus chan/target %d/%d\n",
-//                 ScsiNexus->channel, ScsiNexus->target);
-
-  } 
-  
-  for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
-  {
-    if( Exchanges->fcExchange[x_ID].type )  // in use?
-    {
-      if( ScsiNexus == NULL ) // our HBA changed - term. all
-      {
-       Exchanges->fcExchange[x_ID].status = TerminateStatus;
-        cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID ); 
-      }
-      else
-      {
-       // If a device, according to WWN, has been removed, it's
-       // port_id may be used by another working device, so we
-       // have to terminate by SCSI target, NOT port_id.
-        if( Exchanges->fcExchange[x_ID].Cmnd) // Cmnd in progress?
-       {                        
-         if( (Exchanges->fcExchange[x_ID].Cmnd->device->id == ScsiNexus->target)
-                       &&
-            (Exchanges->fcExchange[x_ID].Cmnd->device->channel == ScsiNexus->channel)) 
-          {
-            Exchanges->fcExchange[x_ID].status = TerminateStatus;
-            cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID ); // timed-out
-          }
-       }
-
-       // (in case we ever need it...)
-       // all SEST structures have a remote node ID at SEST DWORD 2
-        //          if( (fcChip->SEST->u[ x_ID ].TWE.Remote_Node_ID >> 8)
-        //                ==  port_id)
-      } 
-    }
-  }
-}
-
-
-static void ProcessELS_Request( 
-              CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-//  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-//  ULONG ox_id = (fchs->ox_rx_id >>16);
-  PFC_LOGGEDIN_PORT pLoggedInPort=NULL, pLastLoggedInPort;
-  BOOLEAN NeedReject = FALSE;
-  ULONG ls_reject_code = 0; // default don'n know??
-
-
-  // Check the incoming frame for a supported ELS type
-  switch( fchs->pl[0] & 0xFFFF)
-  {
-  case 0x0050: //  PDISC?
-
-    // Payload for PLOGI and PDISC is identical (request & reply)
-    if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
-    {
-      LOGIN_PAYLOAD logi;       // FC-PH Port Login
-      
-      // PDISC payload OK. If critical login fields
-      // (e.g. WWN) matches last login for this port_id,
-      // we may resume any prior exchanges
-      // with the other port
-
-      
-      BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
-   
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-            NULL,     // don't search Scsi Nexus
-            0,        // don't search linked list for port_id
-             &logi.port_name[0],     // search linked list for WWN
-             &pLastLoggedInPort);  // must return non-NULL; when a port_id
-                                   // is not found, this pointer marks the
-                                   // end of the singly linked list
-    
-      if( pLoggedInPort != NULL)   // WWN found (prior login OK)
-      { 
-           
-       if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
-       {
-          // Yes.  We were expecting PDISC?
-          if( pLoggedInPort->pdisc )
-         {
-           // Yes; set fields accordingly.     (PDISC, not Originator)
-            SetLoginFields( pLoggedInPort, fchs, TRUE, FALSE);
-       
-            // send 'ACC' reply 
-            cpqfcTSPutLinkQue( cpqfcHBAdata, 
-                          ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
-                          fchs );
-
-           // OK to resume I/O...
-         }
-         else
-         {
-           printk("Not expecting PDISC (pdisc=FALSE)\n");
-           NeedReject = TRUE;
-           // set reject reason code 
-            ls_reject_code = 
-              LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
-         }
-       }
-       else
-       {
-         if( pLoggedInPort->port_id != 0)
-         {
-           printk("PDISC PortID change: old %Xh, new %Xh\n",
-              pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
-         }
-          NeedReject = TRUE;
-          // set reject reason code 
-          ls_reject_code = 
-           LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
-                 
-       }
-      }
-      else
-      {
-       printk("PDISC Request from unknown WWN\n");
-        NeedReject = TRUE;
-          
-       // set reject reason code 
-        ls_reject_code = 
-          LS_RJT_REASON( LOGICAL_ERROR, INVALID_PORT_NAME);
-      }
-
-    }
-    else // Payload unacceptable
-    {
-      printk("payload unacceptable\n");
-      NeedReject = TRUE;  // reject code already set
-      
-    }
-
-    if( NeedReject)
-    {
-      ULONG port_id;
-      // The PDISC failed.  Set login struct flags accordingly,
-      // terminate any I/O to this port, and Q a PLOGI
-      if( pLoggedInPort )
-      {
-        pLoggedInPort->pdisc = FALSE;
-        pLoggedInPort->prli = FALSE;
-        pLoggedInPort->plogi = FALSE;
-       
-        cpqfcTSTerminateExchange( cpqfcHBAdata, 
-          &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
-       port_id = pLoggedInPort->port_id;
-      }
-      else
-      {
-       port_id = fchs->s_id &0xFFFFFF;
-      }
-      fchs->reserved = ls_reject_code; // borrow this (unused) field
-      cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
-    }
-   
-    break;
-
-
-
-  case 0x0003: //  PLOGI?
-
-    // Payload for PLOGI and PDISC is identical (request & reply)
-    if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
-    {
-      LOGIN_PAYLOAD logi;       // FC-PH Port Login
-      BOOLEAN NeedReject = FALSE;
-      
-      // PDISC payload OK. If critical login fields
-      // (e.g. WWN) matches last login for this port_id,
-      // we may resume any prior exchanges
-      // with the other port
-
-      
-      BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
-   
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-            NULL,       // don't search Scsi Nexus
-            0,        // don't search linked list for port_id
-             &logi.port_name[0],     // search linked list for WWN
-             &pLastLoggedInPort);  // must return non-NULL; when a port_id
-                                   // is not found, this pointer marks the
-                                   // end of the singly linked list
-    
-      if( pLoggedInPort == NULL)   // WWN not found -New Port
-      { 
-       pLoggedInPort = CreateFcPort( 
-                         cpqfcHBAdata, 
-                         pLastLoggedInPort, 
-                         fchs,
-                         &logi);
-        if( pLoggedInPort == NULL )
-        {
-          printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
-          // Now Q a LOGOut Request, since we won't be talking to that device
-       
-          NeedReject = TRUE;  
-         
-          // set reject reason code 
-          ls_reject_code = 
-            LS_RJT_REASON( LOGICAL_ERROR, NO_LOGIN_RESOURCES);
-           
-       }
-      }
-      if( !NeedReject )
-      {
-      
-        // OK - we have valid fcPort ptr; set fields accordingly.   
-       //                         (not PDISC, not Originator)
-        SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE); 
-
-        // send 'ACC' reply 
-        cpqfcTSPutLinkQue( cpqfcHBAdata, 
-                      ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
-                      fchs );
-      }
-    }
-    else // Payload unacceptable
-    {
-      printk("payload unacceptable\n");
-      NeedReject = TRUE;  // reject code already set
-    }
-
-    if( NeedReject)
-    {
-      // The PDISC failed.  Set login struct flags accordingly,
-      // terminate any I/O to this port, and Q a PLOGI
-      pLoggedInPort->pdisc = FALSE;
-      pLoggedInPort->prli = FALSE;
-      pLoggedInPort->plogi = FALSE;
-       
-      fchs->reserved = ls_reject_code; // borrow this (unused) field
-
-      // send 'RJT' reply 
-      cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
-    }
-   
-    // terminate any exchanges with this device...
-    if( pLoggedInPort )
-    {
-      cpqfcTSTerminateExchange( cpqfcHBAdata, 
-        &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
-    }
-    break;
-
-
-
-  case 0x1020:  // PRLI?
-  {
-    BOOLEAN NeedReject = TRUE;
-    pLoggedInPort = fcFindLoggedInPort( 
-           fcChip, 
-           NULL,       // don't search Scsi Nexus
-          (fchs->s_id & 0xFFFFFF),  // search linked list for port_id
-           NULL,     // DON'T search linked list for WWN
-           NULL);    // don't care
-      
-    if( pLoggedInPort == NULL ) 
-    {
-      // huh?
-      printk(" Unexpected PRLI Request -not logged in!\n");
-
-      // set reject reason code 
-      ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
-      
-      // Q a LOGOut here?
-    }
-    else
-    {
-      // verify the PRLI ACC payload
-      if( !verify_PRLI( fchs, &ls_reject_code) )
-      {
-        // PRLI Reply is acceptable; were we expecting it?
-        if( pLoggedInPort->plogi ) 
-        { 
-         // yes, we expected the PRLI ACC  (not PDISC; not Originator)
-          SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
-
-          // Q an ACCept Reply
-         cpqfcTSPutLinkQue( cpqfcHBAdata,
-                        ELS_PRLI_ACC, 
-                        fchs );   
-         
-         NeedReject = FALSE;
-       }
-        else
-        {
-          // huh?
-          printk(" (unexpected) PRLI REQEST with plogi FALSE\n");
-
-          // set reject reason code 
-          ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
-    
-         // Q a LOGOut here?
-         
-        }
-      }
-      else
-      {
-        printk(" PRLI REQUEST payload failed verify\n");
-        // (reject code set by "verify")
-
-        // Q a LOGOut here?
-      }
-    }
-
-    if( NeedReject )
-    {
-      // Q a ReJecT Reply with reason code
-      fchs->reserved = ls_reject_code;
-      cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_RJT, // Q Type
-                    fchs );  
-    }
-  }
-    break;
-
-    
-
-  case  0x0005:  // LOGOut?
-  {
-  // was this LOGOUT because we sent a ELS_PDISC to an FC device
-  // with changed (or new) port_id, or does the port refuse 
-  // to communicate to us?
-  // We maintain a logout counter - if we get 3 consecutive LOGOuts,
-  // give up!
-    LOGOUT_PAYLOAD logo;
-    BOOLEAN GiveUpOnDevice = FALSE;
-    ULONG ls_reject_code = 0;
-    
-    BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logo, sizeof(logo));
-
-    pLoggedInPort = fcFindLoggedInPort( 
-           fcChip, 
-           NULL,     // don't search Scsi Nexus
-          0,        // don't search linked list for port_id
-           &logo.port_name[0],     // search linked list for WWN
-           NULL);    // don't care about end of list
-    
-    if( pLoggedInPort ) // found the device?
-    {
-      // Q an ACC reply 
-      cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_LOGO_ACC, // Q Type
-                    fchs );       // device to respond to
-
-      // set login struct fields (LOGO_counter increment)
-      SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
-      
-      // are we an Initiator?
-      if( fcChip->Options.initiator)  
-      {
-        // we're an Initiator, so check if we should 
-       // try (another?) login
-
-       // Fabrics routinely log out from us after
-       // getting device info - don't try to log them
-       // back in.
-       if( (fchs->s_id & 0xFFF000) == 0xFFF000 )
-       {
-         ; // do nothing
-       }
-       else if( pLoggedInPort->LOGO_counter <= 3)
-       {
-         // try (another) login (PLOGI request)
-         
-          cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_PLOGI, // Q Type
-                    fchs );  
-       
-         // Terminate I/O with "retry" potential
-         cpqfcTSTerminateExchange( cpqfcHBAdata, 
-                                   &pLoggedInPort->ScsiNexus,
-                                   PORTID_CHANGED);
-       }
-       else
-       {
-         printk(" Got 3 LOGOuts - terminating comm. with port_id %Xh\n",
-                         fchs->s_id &&0xFFFFFF);
-         GiveUpOnDevice = TRUE;
-       }
-      }
-      else
-      {
-       GiveUpOnDevice = TRUE;
-      }
-
-
-      if( GiveUpOnDevice == TRUE )
-      {
-        cpqfcTSTerminateExchange( cpqfcHBAdata, 
-                                 &pLoggedInPort->ScsiNexus,
-                                 DEVICE_REMOVED);
-      }
-    }  
-    else  // we don't know this WWN!
-    {
-      // Q a ReJecT Reply with reason code
-      fchs->reserved = ls_reject_code;
-      cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_RJT, // Q Type
-                    fchs );  
-    }
-  }
-    break;
-
-
-
-
-  // FABRIC only case
-  case 0x0461:  // ELS RSCN (Registered State Change Notification)?
-  {
-    int Ports;
-    int i;
-    __u32 Buff;
-    // Typically, one or more devices have been added to or dropped
-    // from the Fabric.
-    // The format of this frame is defined in FC-FLA (Rev 2.7, Aug 1997)
-    // The first 32-bit word has a 2-byte Payload Length, which
-    // includes the 4 bytes of the first word.  Consequently,
-    // this PL len must never be less than 4, must be a multiple of 4,
-    // and has a specified max value 256.
-    // (Endianess!)
-    Ports = ((fchs->pl[0] >>24) - 4) / 4;
-    Ports = Ports > 63 ? 63 : Ports;
-    
-    printk(" RSCN ports: %d\n", Ports);
-    if( Ports <= 0 )  // huh?
-    {
-      // ReJecT the command
-      fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM, 0);
-    
-      cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_RJT, // Q Type
-                    fchs ); 
-      
-      break;
-    }
-    else  // Accept the command
-    {
-       cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_ACC, // Q Type
-                    fchs ); 
-    }
-    
-      // Check the "address format" to determine action.
-      // We have 3 cases:
-      // 0 = Port Address; 24-bit address of affected device
-      // 1 = Area Address; MS 16 bits valid
-      // 2 = Domain Address; MS 8 bits valid
-    for( i=0; i<Ports; i++)
-    { 
-      BigEndianSwap( (UCHAR*)&fchs->pl[i+1],(UCHAR*)&Buff, 4);
-      switch( Buff & 0xFF000000)
-      {
-
-      case 0:  // Port Address?
-       
-      case 0x01000000: // Area Domain?
-      case 0x02000000: // Domain Address
-        // For example, "port_id" 0x201300 
-       // OK, let's try a Name Service Request (Query)
-      fchs->s_id = 0xFFFFFC;  // Name Server Address
-      cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
-
-      break;
-       
-       
-      default:  // huh? new value on version change?
-      break;
-      }
-    }
-  }    
-  break;    
-
-
-
-    
-  default:  // don't support this request (yet)
-    // set reject reason code 
-    fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM, 
-                                   REQUEST_NOT_SUPPORTED);
-    
-    cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_RJT, // Q Type
-                    fchs );     
-    break;  
-  }
-}
-
-
-static void ProcessELS_Reply( 
-               CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG ox_id = (fchs->ox_rx_id >>16);
-  ULONG ls_reject_code;
-  PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
-  
-  // If this is a valid reply, then we MUST have sent a request.
-  // Verify that we can find a valid request OX_ID corresponding to
-  // this reply
-
-  
-  if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
-  {
-    printk(" *Discarding ACC/RJT frame, xID %04X/%04X* ", 
-                   ox_id, fchs->ox_rx_id & 0xffff);
-    goto Quit;  // exit this routine
-  }
-
-
-  // Is the reply a RJT (reject)?
-  if( (fchs->pl[0] & 0xFFFFL) == 0x01) // Reject reply?
-  {
-//  ******  REJECT REPLY  ********
-    switch( Exchanges->fcExchange[ox_id].type )
-    {
-         
-    case ELS_FDISC:  // we sent out Fabric Discovery
-    case ELS_FLOGI:  // we sent out FLOGI
-
-      printk("RJT received on Fabric Login from %Xh, reason %Xh\n", 
-        fchs->s_id, fchs->pl[1]);    
-
-    break;
-
-    default:
-    break;
-    }
-      
-    goto Done;
-  }
-
-  // OK, we have an ACCept...
-  // What's the ACC type? (according to what we sent)
-  switch( Exchanges->fcExchange[ox_id].type )
-  {
-         
-  case ELS_PLOGI:  // we sent out PLOGI
-    if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
-    {
-      LOGIN_PAYLOAD logi;       // FC-PH Port Login
-      
-      // login ACC payload acceptable; search for WWN in our list
-      // of fcPorts
-      
-      BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
-   
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-            NULL,     // don't search Scsi Nexus
-            0,        // don't search linked list for port_id
-             &logi.port_name[0],     // search linked list for WWN
-             &pLastLoggedInPort);  // must return non-NULL; when a port_id
-                                   // is not found, this pointer marks the
-                                   // end of the singly linked list
-    
-      if( pLoggedInPort == NULL)         // WWN not found - new port
-      {
-
-       pLoggedInPort = CreateFcPort( 
-                         cpqfcHBAdata, 
-                         pLastLoggedInPort, 
-                         fchs,
-                         &logi);
-
-        if( pLoggedInPort == NULL )
-        {
-          printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
-          // Now Q a LOGOut Request, since we won't be talking to that device
-       
-          goto Done;  // exit with error! dropped login frame
-       }
-      }
-      else      // WWN was already known.  Ensure that any open
-               // exchanges for this WWN are terminated.
-       // NOTE: It's possible that a device can change its 
-       // 24-bit port_id after a Link init or Fabric change 
-       // (e.g. LIP or Fabric RSCN).  In that case, the old
-       // 24-bit port_id may be duplicated, or no longer exist.
-      {
-
-        cpqfcTSTerminateExchange( cpqfcHBAdata, 
-          &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
-      }
-
-      // We have an fcPort struct - set fields accordingly
-                                    // not PDISC, originator 
-      SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
-                       
-      // We just set a "port_id"; is it duplicated?
-      TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
-
-      // For Fabric operation, we issued PLOGI to 0xFFFFFC
-      // so we can send SCR (State Change Registration) 
-      // Check for this special case...
-      if( fchs->s_id == 0xFFFFFC ) 
-      {
-        // PLOGI ACC was a Fabric response... issue SCR
-       fchs->s_id = 0xFFFFFD;  // address for SCR
-        cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_SCR, fchs);
-      }
-
-      else
-      {
-      // Now we need a PRLI to enable FCP-SCSI operation
-      // set flags and Q up a ELS_PRLI
-        cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PRLI, fchs);
-      }
-    }
-    else
-    {
-      // login payload unacceptable - reason in ls_reject_code
-      // Q up a Logout Request
-      printk("Login Payload unacceptable\n");
-
-    }
-    break;
-
-
-  // PDISC logic very similar to PLOGI, except we never want
-  // to allocate mem for "new" port, and we set flags differently
-  // (might combine later with PLOGI logic for efficiency)  
-  case ELS_PDISC:  // we sent out PDISC
-    if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
-    {
-      LOGIN_PAYLOAD logi;       // FC-PH Port Login
-      BOOLEAN NeedLogin = FALSE;
-      
-      // login payload acceptable; search for WWN in our list
-      // of (previously seen) fcPorts
-      
-      BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
-   
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-            NULL,     // don't search Scsi Nexus
-            0,        // don't search linked list for port_id
-             &logi.port_name[0],     // search linked list for WWN
-             &pLastLoggedInPort);  // must return non-NULL; when a port_id
-                                   // is not found, this pointer marks the
-                                   // end of the singly linked list
-    
-      if( pLoggedInPort != NULL)   // WWN found?
-      {
-        // WWN has same port_id as last login?  (Of course, a properly
-       // working FC device should NEVER ACCept a PDISC if it's
-       // port_id changed, but check just in case...)
-       if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
-       {
-          // Yes.  We were expecting PDISC?
-          if( pLoggedInPort->pdisc )
-         {
-            int i;
-           
-           
-           // PDISC expected -- set fields.  (PDISC, Originator)
-            SetLoginFields( pLoggedInPort, fchs, TRUE, TRUE);
-
-           // We are ready to resume FCP-SCSI to this device...
-            // Do we need to start anything that was Queued?
-
-            for( i=0; i< TACH_SEST_LEN; i++)
-            {
-              // see if any exchange for this PDISC'd port was queued
-              if( ((fchs->s_id &0xFFFFFF) == 
-                   (Exchanges->fcExchange[i].fchs.d_id & 0xFFFFFF))
-                      &&
-                  (Exchanges->fcExchange[i].status & EXCHANGE_QUEUED))
-              {
-                fchs->reserved = i; // copy ExchangeID
-//                printk(" *Q x_ID %Xh after PDISC* ",i);
-
-                cpqfcTSPutLinkQue( cpqfcHBAdata, EXCHANGE_QUEUED, fchs );
-              }
-            }
-
-           // Complete commands Q'd while we were waiting for Login
-
-           UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
-         }
-         else
-         {
-           printk("Not expecting PDISC (pdisc=FALSE)\n");
-           NeedLogin = TRUE;
-         }
-       }
-       else
-       {
-         printk("PDISC PortID change: old %Xh, new %Xh\n",
-            pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
-          NeedLogin = TRUE;
-                 
-       }
-      }
-      else
-      {
-       printk("PDISC ACC from unknown WWN\n");
-        NeedLogin = TRUE;
-      }
-
-      if( NeedLogin)
-      {
-       
-        // The PDISC failed.  Set login struct flags accordingly,
-       // terminate any I/O to this port, and Q a PLOGI
-       if( pLoggedInPort )  // FC device previously known?
-       {
-
-          cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_LOGO, // Q Type
-                    fchs );   // has port_id to send to 
-
-         // There are a variety of error scenarios which can result
-         // in PDISC failure, so as a catchall, add the check for
-         // duplicate port_id.
-         TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
-
-//    TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
-          pLoggedInPort->pdisc = FALSE;
-          pLoggedInPort->prli = FALSE;
-          pLoggedInPort->plogi = FALSE;
-       
-          cpqfcTSTerminateExchange( cpqfcHBAdata, 
-           &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
-        }
-        cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs );
-      }
-    }
-    else
-    {
-      // login payload unacceptable - reason in ls_reject_code
-      // Q up a Logout Request
-      printk("ERROR: Login Payload unacceptable!\n");
-
-    }
-   
-    break;
-    
-
-
-  case ELS_PRLI:  // we sent out PRLI
-
-
-    pLoggedInPort = fcFindLoggedInPort( 
-           fcChip, 
-           NULL,       // don't search Scsi Nexus
-          (fchs->s_id & 0xFFFFFF),  // search linked list for port_id
-           NULL,     // DON'T search linked list for WWN
-           NULL);    // don't care
-      
-    if( pLoggedInPort == NULL ) 
-    {
-      // huh?
-      printk(" Unexpected PRLI ACCept frame!\n");
-
-      // Q a LOGOut here?
-
-      goto Done;
-    }
-
-    // verify the PRLI ACC payload
-    if( !verify_PRLI( fchs, &ls_reject_code) )
-    {
-      // PRLI Reply is acceptable; were we expecting it?
-      if( pLoggedInPort->plogi ) 
-      { 
-       // yes, we expected the PRLI ACC  (not PDISC; Originator)
-       SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
-
-        // OK, let's send a REPORT_LUNS command to determine
-       // whether VSA or PDA FCP-LUN addressing is used.
-       
-        cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
-       
-       // It's possible that a device we were talking to changed 
-       // port_id, and has logged back in.  This function ensures
-       // that I/O will resume.
-        UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
-
-      }
-      else
-      {
-        // huh?
-        printk(" (unexpected) PRLI ACCept with plogi FALSE\n");
-
-        // Q a LOGOut here?
-        goto Done;
-      }
-    }
-    else
-    {
-      printk(" PRLI ACCept payload failed verify\n");
-
-      // Q a LOGOut here?
-    }
-
-    break;
-  case ELS_FLOGI:  // we sent out FLOGI (Fabric Login)
-
-    // update the upper 16 bits of our port_id in Tachyon
-    // the switch adds those upper 16 bits when responding
-    // to us (i.e. we are the destination_id)
-    fcChip->Registers.my_al_pa = (fchs->d_id & 0xFFFFFF);
-    writel( fcChip->Registers.my_al_pa,  
-      fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
-
-    // now send out a PLOGI to the well known port_id 0xFFFFFC
-    fchs->s_id = 0xFFFFFC;
-    cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs);
-  
-   break; 
-
-
-  case ELS_FDISC:  // we sent out FDISC (Fabric Discovery (Login))
-
-   printk( " ELS_FDISC success ");
-   break;
-   
-
-  case ELS_SCR:  // we sent out State Change Registration
-    // now we can issue Name Service Request to find any
-    // Fabric-connected devices we might want to login to.
-   
-       
-    fchs->s_id = 0xFFFFFC;  // Name Server Address
-    cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
-    
-
-    break;
-
-    
-  default:
-    printk(" *Discarding unknown ACC frame, xID %04X/%04X* ", 
-                   ox_id, fchs->ox_rx_id & 0xffff);
-    break;
-  }
-
-  
-Done:
-  // Regardless of whether the Reply is valid or not, the
-  // the exchange is done - complete
-  cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, (fchs->ox_rx_id >>16)); 
-         
-Quit:    
-  return;
-}
-
-
-
-
-
-
-// ****************  Fibre Channel Services  **************
-// This is where we process the Directory (Name) Service Reply
-// to know which devices are on the Fabric
-
-static void ProcessFCS_Reply( 
-       CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG ox_id = (fchs->ox_rx_id >>16);
-//  ULONG ls_reject_code;
-//  PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
-  
-  // If this is a valid reply, then we MUST have sent a request.
-  // Verify that we can find a valid request OX_ID corresponding to
-  // this reply
-
-  if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
-  {
-    printk(" *Discarding Reply frame, xID %04X/%04X* ", 
-                   ox_id, fchs->ox_rx_id & 0xffff);
-    goto Quit;  // exit this routine
-  }
-
-
-  // OK, we were expecting it.  Now check to see if it's a
-  // "Name Service" Reply, and if so force a re-validation of
-  // Fabric device logins (i.e. Start the login timeout and
-  // send PDISC or PLOGI)
-  // (Endianess Byte Swap?)
-  if( fchs->pl[1] == 0x02FC )  // Name Service
-  {
-    // got a new (or NULL) list of Fabric attach devices... 
-    // Invalidate current logins
-    
-    PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
-    while( pLoggedInPort ) // for all ports which are expecting
-                           // PDISC after the next LIP, set the
-                           // logoutTimer
-    {
-
-      if( (pLoggedInPort->port_id & 0xFFFF00)  // Fabric device?
-                     &&
-          (pLoggedInPort->port_id != 0xFFFFFC) ) // NOT the F_Port
-      {
-        pLoggedInPort->LOGO_timer = 6;  // what's the Fabric timeout??
-                                // suspend any I/O in progress until
-                                // PDISC received...
-        pLoggedInPort->prli = FALSE;   // block FCP-SCSI commands
-      }
-           
-      pLoggedInPort = pLoggedInPort->pNextPort;
-    }
-    
-    if( fchs->pl[2] == 0x0280)  // ACCept?
-    {
-      // Send PLOGI or PDISC to these Fabric devices
-      SendLogins( cpqfcHBAdata, &fchs->pl[4] );  
-    }
-
-
-    // As of this writing, the only reason to reject is because NO
-    // devices are left on the Fabric.  We already started
-    // "logged out" timers; if the device(s) don't come
-    // back, we'll do the implicit logout in the heart beat 
-    // timer routine
-    else  // ReJecT
-    {
-      // this just means no Fabric device is visible at this instant
-    } 
-  }
-
-  // Regardless of whether the Reply is valid or not, the
-  // the exchange is done - complete
-  cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, (fchs->ox_rx_id >>16));
-         
-Quit:    
-  return;
-}
-
-
-
-
-
-
-
-static void AnalyzeIncomingFrame( 
-        CPQFCHBA *cpqfcHBAdata,
-        ULONG QNdx )
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
-  TachFCHDR_GCMND* fchs = 
-    (TachFCHDR_GCMND*)fcLQ->Qitem[QNdx].ulBuff;
-//  ULONG ls_reject_code;  // reason for rejecting login
-  LONG ExchangeID;
-//  FC_LOGGEDIN_PORT *pLoggedInPort;
-  BOOLEAN AbortAccept;  
-
-  ENTER("AnalyzeIncomingFrame");
-
-
-
-  switch( fcLQ->Qitem[QNdx].Type) // FCP or Unknown
-  {
-
-  case SFQ_UNKNOWN:  // unknown frame (e.g. LIP position frame, NOP, etc.)
-
-      // *********  FC-4 Device Data/ Fibre Channel Service *************
-    if( ((fchs->d_id &0xF0000000) == 0)   // R_CTL (upper nibble) 0x0?
-                &&   
-      (fchs->f_ctl & 0x20000000) )  // TYPE 20h is Fibre Channel Service
-    {
-
-      // ************** FCS Reply **********************
-
-      if( (fchs->d_id & 0xff000000L) == 0x03000000L)  // (31:23 R_CTL)
-      {
-       ProcessFCS_Reply( cpqfcHBAdata, fchs );
-
-      }  // end of  FCS logic
-
-    }
-    
-
-      // ***********  Extended Link Service **************
-
-    else if( fchs->d_id & 0x20000000   // R_CTL 0x2?
-                  &&   
-      (fchs->f_ctl & 0x01000000) )  // TYPE = 1
-    {
-
-                           // these frames are either a response to
-                           // something we sent (0x23) or "unsolicited"
-                           // frames (0x22).
-
-
-      // **************Extended Link REPLY **********************
-                           // R_CTL Solicited Control Reply
-
-      if( (fchs->d_id & 0xff000000L) == 0x23000000L)  // (31:23 R_CTL)
-      {
-
-       ProcessELS_Reply( cpqfcHBAdata, fchs );
-
-      }  // end of  "R_CTL Solicited Control Reply"
-
-
-
-
-       // **************Extended Link REQUEST **********************
-       // (unsolicited commands from another port or task...)
-
-                           // R_CTL Ext Link REQUEST
-      else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
-              (fchs->ox_rx_id != 0xFFFFFFFFL) ) // (ignore LIP frame)
-      {
-
-
-
-       ProcessELS_Request( cpqfcHBAdata, fchs );
-
-      }
-
-
-
-        // ************** LILP **********************
-      else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
-               (fchs->ox_rx_id == 0xFFFFFFFFL)) // (e.g., LIP frames)
-
-      {
-        // SANMark specifies that when available, we must use
-       // the LILP frame to determine which ALPAs to send Port Discovery
-       // to...
-
-        if( fchs->pl[0] == 0x0711L) //  ELS_PLOGI?
-       {
-//       UCHAR *ptr = (UCHAR*)&fchs->pl[1];
-//       printk(" %d ALPAs found\n", *ptr);
-         memcpy( fcChip->LILPmap, &fchs->pl[1], 32*4); // 32 DWORDs
-         fcChip->Options.LILPin = 1; // our LILPmap is valid!
-         // now post to make Port Discovery happen...
-          cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, fchs);  
-       }
-      }
-    }
-
-     
-    // *****************  BASIC LINK SERVICE *****************
-    
-    else if( fchs->d_id & 0x80000000  // R_CTL:
-                    &&           // Basic Link Service Request
-           !(fchs->f_ctl & 0xFF000000) )  // type=0 for BLS
-    {
-
-      // Check for ABTS (Abort Sequence)
-      if( (fchs->d_id & 0x8F000000) == 0x81000000)
-      {
-        // look for OX_ID, S_ID pair that matches in our
-        // fcExchanges table; if found, reply with ACCept and complete
-        // the exchange
-
-        // Per PLDA, an ABTS is sent by an initiator; therefore
-        // assume that if we have an exhange open to the port who
-        // sent ABTS, it will be the d_id of what we sent.  
-        for( ExchangeID = 0, AbortAccept=FALSE;
-             ExchangeID < TACH_SEST_LEN; ExchangeID++)
-        {
-            // Valid "target" exchange 24-bit port_id matches? 
-            // NOTE: For the case of handling Intiator AND Target
-            // functions on the same chip, we can have TWO Exchanges
-            // with the same OX_ID -- OX_ID/FFFF for the CMND, and
-            // OX_ID/RX_ID for the XRDY or DATA frame(s).  Ideally,
-            // we would like to support ABTS from Initiators or Targets,
-            // but it's not clear that can be supported on Tachyon for
-            // all cases (requires more investigation).
-            
-          if( (Exchanges->fcExchange[ ExchangeID].type == SCSI_TWE ||
-               Exchanges->fcExchange[ ExchangeID].type == SCSI_TRE)
-                  &&
-             ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
-             (fchs->s_id & 0xFFFFFF)) )
-          {
-              
-              // target xchnge port_id matches -- how about OX_ID?
-            if( (Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id &0xFFFF0000)
-                    == (fchs->ox_rx_id & 0xFFFF0000) )
-                    // yes! post ACCept response; will be completed by fcStart
-            {
-              Exchanges->fcExchange[ ExchangeID].status = TARGET_ABORT;
-                
-                // copy (add) rx_id field for simplified ACCept reply
-              fchs->ox_rx_id = 
-                Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id;
-                
-              cpqfcTSPutLinkQue( cpqfcHBAdata,
-                            BLS_ABTS_ACC, // Q Type 
-                            fchs );    // void QueContent
-              AbortAccept = TRUE;
-      printk("ACCepting ABTS for x_ID %8.8Xh, SEST pair %8.8Xh\n", 
-             fchs->ox_rx_id, Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id);
-              break;      // ABTS can affect only ONE exchange -exit loop
-            }
-          }
-        }  // end of FOR loop
-        if( !AbortAccept ) // can't ACCept ABTS - send Reject
-        {
-      printk("ReJecTing: can't find ExchangeID %8.8Xh for ABTS command\n", 
-            fchs->ox_rx_id);
-          if( Exchanges->fcExchange[ ExchangeID].type 
-                &&
-              !(fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len
-               & 0x80000000))
-          {
-            cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
-          }
-          else
-          {
-            printk("Unexpected ABTS ReJecT! SEST[%X] Dword 0: %Xh\n", 
-              ExchangeID, fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len);
-          }
-        }
-      }
-
-      // Check for BLS {ABTS? (Abort Sequence)} ACCept
-      else if( (fchs->d_id & 0x8F000000) == 0x84000000)
-      {
-        // target has responded with ACC for our ABTS;
-       // complete the indicated exchange with ABORTED status 
-        // Make no checks for correct RX_ID, since
-       // all we need to conform ABTS ACC is the OX_ID.
-        // Verify that the d_id matches!
-        ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
-//     printk("ABTS ACC x_ID 0x%04X 0x%04X, status %Xh\n", 
-//          fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff,
-//          Exchanges->fcExchange[ExchangeID].status);
-
-
-       
-        if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
-        {
-            // Does "target" exchange 24-bit port_id match? 
-            // (See "NOTE" above for handling Intiator AND Target in
-            // the same device driver)
-            // First, if this is a target response, then we originated
-           // (initiated) it with BLS_ABTS:
-         
-          if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
-
-                  &&
-           // Second, does the source of this ACC match the destination
-            // of who we originally sent it to?
-             ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
-             (fchs->s_id & 0xFFFFFF)) )
-          {
-            cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID );
-         }
-        }              
-      }
-      // Check for BLS {ABTS? (Abort Sequence)} ReJecT
-      else if( (fchs->d_id & 0x8F000000) == 0x85000000)
-      {
-        // target has responded with RJT for our ABTS;
-       // complete the indicated exchange with ABORTED status 
-        // Make no checks for correct RX_ID, since
-       // all we need to conform ABTS ACC is the OX_ID.
-        // Verify that the d_id matches!
-        ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
-//     printk("BLS_ABTS RJT on Exchange 0x%04X 0x%04X\n", 
-//          fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff);
-
-        if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
-       {  
-            // Does "target" exchange 24-bit port_id match? 
-            // (See "NOTE" above for handling Intiator AND Target in
-            // the same device driver)
-            // First, if this is a target response, then we originated
-           // (initiated) it with BLS_ABTS:
-                 
-          if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
-
-                  &&
-           // Second, does the source of this ACC match the destination
-            // of who we originally sent it to?
-             ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
-             (fchs->s_id & 0xFFFFFF)) )
-          {
-           // YES! NOTE: There is a bug in CPQ's RA-4000 box 
-           // where the "reason code" isn't returned in the payload
-           // For now, simply presume the reject is because the target
-           // already completed the exchange...
-           
-//            printk("complete x_ID %Xh on ABTS RJT\n", ExchangeID);
-            cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID );
-         }
-       } 
-      }  // end of ABTS check
-    }  // end of Basic Link Service Request
-    break;
-  
-    default:
-      printk("AnalyzeIncomingFrame: unknown type: %Xh(%d)\n",
-        fcLQ->Qitem[QNdx].Type,
-        fcLQ->Qitem[QNdx].Type);
-    break;
-  }
-}
-
-
-// Function for Port Discovery necessary after every FC 
-// initialization (e.g. LIP).
-// Also may be called if from Fabric Name Service logic.
-
-static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds )
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG ulStatus=0;
-  TachFCHDR_GCMND fchs;  // copy fields for transmission
-  int i;
-  ULONG loginType;
-  LONG ExchangeID;
-  PFC_LOGGEDIN_PORT pLoggedInPort;
-  __u32 PortIds[ number_of_al_pa];
-  int NumberOfPorts=0;
-
-  // We're going to presume (for now) that our limit of Fabric devices
-  // is the same as the number of alpa on a private loop (126 devices).
-  // (Of course this could be changed to support however many we have
-  // memory for).
-  memset( &PortIds[0], 0, sizeof(PortIds));
-   
-  // First, check if this login is for our own Link Initialization
-  // (e.g. LIP on FC-AL), or if we have knowledge of Fabric devices
-  // from a switch.  If we are logging into Fabric devices, we'll
-  // have a non-NULL FabricPortId pointer
-  
-  if( FabricPortIds != NULL) // may need logins
-  {
-    int LastPort=FALSE;
-    i = 0;
-    while( !LastPort)
-    {
-      // port IDs From NSR payload; byte swap needed?
-      BigEndianSwap( (UCHAR*)FabricPortIds, (UCHAR*)&PortIds[i], 4);
-//      printk("FPortId[%d] %Xh ", i, PortIds[i]);
-      if( PortIds[i] & 0x80000000)
-       LastPort = TRUE;
-      
-      PortIds[i] &= 0xFFFFFF; // get 24-bit port_id
-      // some non-Fabric devices (like the Crossroads Fibre/Scsi bridge)
-      // erroneously use ALPA 0.
-      if( PortIds[i]  ) // need non-zero port_id...
-        i++;
-      
-      if( i >= number_of_al_pa ) // (in)sanity check
-       break;
-      FabricPortIds++;  // next...
-    }
-
-    NumberOfPorts = i;
-//    printk("NumberOf Fabric ports %d", NumberOfPorts);
-  }
-  
-  else  // need to send logins on our "local" link
-  {
-  
-    // are we a loop port?  If so, check for reception of LILP frame,
-    // and if received use it (SANMark requirement)
-    if( fcChip->Options.LILPin )
-    {
-      int j=0;
-      // sanity check on number of ALPAs from LILP frame...
-      // For format of LILP frame, see FC-AL specs or 
-      // "Fibre Channel Bench Reference", J. Stai, 1995 (ISBN 1-879936-17-8)
-      // First byte is number of ALPAs
-      i = fcChip->LILPmap[0] >= (32*4) ? 32*4 : fcChip->LILPmap[0];
-      NumberOfPorts = i;
-//      printk(" LILP alpa count %d ", i);
-      while( i > 0)
-      {
-       PortIds[j] = fcChip->LILPmap[1+ j];
-       j++; i--;
-      }
-    }
-    else  // have to send login to everybody
-    {
-      int j=0;
-      i = number_of_al_pa;
-      NumberOfPorts = i;
-      while( i > 0)
-      {
-        PortIds[j] = valid_al_pa[j]; // all legal ALPAs
-       j++; i--;
-      }
-    }
-  }
-
-
-  // Now we have a copy of the port_ids (and how many)...
-  for( i = 0; i < NumberOfPorts; i++)
-  {
-    // 24-bit FC Port ID
-    fchs.s_id = PortIds[i];  // note: only 8-bits used for ALPA
-
-
-    // don't log into ourselves (Linux Scsi disk scan will stop on
-    // no TARGET support error on us, and quit trying for rest of devices)
-    if( (fchs.s_id & 0xFF ) == (fcChip->Registers.my_al_pa & 0xFF) )
-      continue;
-
-    // fabric login needed?
-    if( (fchs.s_id == 0) || 
-        (fcChip->Options.fabric == 1) )
-    {
-      fcChip->Options.flogi = 1;  // fabric needs longer for login
-      // Do we need FLOGI or FDISC?
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-             NULL,           // don't search SCSI Nexus
-             0xFFFFFC,       // search linked list for Fabric port_id
-             NULL,           // don't search WWN
-             NULL);          // (don't care about end of list)
-
-      if( pLoggedInPort )    // If found, we have prior experience with
-                             // this port -- check whether PDISC is needed
-      {
-        if( pLoggedInPort->flogi )
-       {
-         // does the switch support FDISC?? (FLOGI for now...)
-          loginType = ELS_FLOGI;  // prior FLOGI still valid
-       }
-        else
-          loginType = ELS_FLOGI;  // expired FLOGI
-      }
-      else                      // first FLOGI?
-        loginType = ELS_FLOGI;  
-
-
-      fchs.s_id = 0xFFFFFE;   // well known F_Port address
-
-      // Fabrics are not required to support FDISC, and
-      // it's not clear if that helps us anyway, since
-      // we'll want a Name Service Request to re-verify
-      // visible devices...
-      // Consequently, we always want our upper 16 bit
-      // port_id to be zero (we'll be rejected if we
-      // use our prior port_id if we've been plugged into
-      // a different switch port).
-      // Trick Tachyon to send to ALPA 0 (see TL/TS UG, pg 87)
-      // If our ALPA is 55h for instance, we want the FC frame
-      // s_id to be 0x000055, while Tach's my_al_pa register
-      // must be 0x000155, to force an OPN at ALPA 0 
-      // (the Fabric port)
-      fcChip->Registers.my_al_pa &= 0xFF; // only use ALPA for FLOGI
-      writel( fcChip->Registers.my_al_pa | 0x0100,  
-        fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
-    }
-
-    else // not FLOGI...
-    {
-      // should we send PLOGI or PDISC?  Check if any prior port_id
-      // (e.g. alpa) completed a PLOGI/PRLI exchange by checking 
-      // the pdisc flag.
-
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-             NULL,           // don't search SCSI Nexus
-             fchs.s_id,      // search linked list for al_pa
-             NULL,           // don't search WWN
-             NULL);          // (don't care about end of list)
-
-             
-
-      if( pLoggedInPort )      // If found, we have prior experience with
-                             // this port -- check whether PDISC is needed
-      {
-        if( pLoggedInPort->pdisc )
-       {
-          loginType = ELS_PDISC;  // prior PLOGI and PRLI maybe still valid
-           
-       }
-        else
-          loginType = ELS_PLOGI;  // prior knowledge, but can't use PDISC
-      }
-      else                      // never talked to this port_id before
-        loginType = ELS_PLOGI;  // prior knowledge, but can't use PDISC
-    }
-
-
-    
-    ulStatus = cpqfcTSBuildExchange(
-          cpqfcHBAdata,
-          loginType,            // e.g. PLOGI
-          &fchs,        // no incoming frame (we are originator)
-          NULL,         // no data (no scatter/gather list)
-          &ExchangeID );// fcController->fcExchanges index, -1 if failed
-
-    if( !ulStatus ) // Exchange setup OK?
-    {
-      ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
-      if( !ulStatus )
-      {
-          // submitted to Tach's Outbound Que (ERQ PI incremented)
-          // waited for completion for ELS type (Login frames issued
-          // synchronously)
-
-       if( loginType == ELS_PDISC )
-       {
-         // now, we really shouldn't Revalidate SEST exchanges until
-         // we get an ACC reply from our target and verify that
-         // the target address/WWN is unchanged.  However, when a fast
-         // target gets the PDISC, they can send SEST Exchange data
-         // before we even get around to processing the PDISC ACC.
-         // Consequently, we lose the I/O.
-         // To avoid this, go ahead and Revalidate when the PDISC goes
-         // out, anticipating that the ACC will be truly acceptable
-         // (this happens 99.9999....% of the time).
-         // If we revalidate a SEST write, and write data goes to a
-         // target that is NOT the one we originated the WRITE to,
-         // that target is required (FCP-SCSI specs, etc) to discard 
-         // our WRITE data.
-
-          // Re-validate SEST entries (Tachyon hardware assists)
-          RevalidateSEST( cpqfcHBAdata->HostAdapter, pLoggedInPort); 
-    //TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
-       }
-      }
-      else  // give up immediately on error
-      {
-#ifdef LOGIN_DBG
-        printk("SendLogins: fcStartExchange failed: %Xh\n", ulStatus );
-#endif
-        break;
-      }
-
-              
-      if( fcChip->Registers.FMstatus.value & 0x080 ) // LDn during Port Disc.
-      {
-        ulStatus = LNKDWN_OSLS;
-#ifdef LOGIN_DBG
-        printk("SendLogins: PortDisc aborted (LDn) @alpa %Xh\n", fchs.s_id);
-#endif
-        break;
-      }
-        // Check the exchange for bad status (i.e. FrameTimeOut),
-        // and complete on bad status (most likely due to BAD_ALPA)
-        // on LDn, DPC function may already complete (ABORT) a started
-        // exchange, so check type first (type = 0 on complete).
-      if( Exchanges->fcExchange[ExchangeID].status )
-      {
-#ifdef LOGIN_DBG 
-       printk("completing x_ID %X on status %Xh\n", 
-          ExchangeID, Exchanges->fcExchange[ExchangeID].status);
-#endif
-        cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
-      }
-    }
-    else   // Xchange setup failed...
-    {
-#ifdef LOGIN_DBG
-      printk("FC: cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
-#endif
-      break;
-    }
-  }
-  if( !ulStatus )
-  {
-    // set the event signifying that all ALPAs were sent out.
-#ifdef LOGIN_DBG
-    printk("SendLogins: PortDiscDone\n");
-#endif
-    cpqfcHBAdata->PortDiscDone = 1;
-
-
-    // TL/TS UG, pg. 184
-    // 0x0065 = 100ms for RT_TOV
-    // 0x01f5 = 500ms for ED_TOV
-    fcChip->Registers.ed_tov.value = 0x006501f5L; 
-    writel( fcChip->Registers.ed_tov.value,
-      (fcChip->Registers.ed_tov.address));
-
-    // set the LP_TOV back to ED_TOV (i.e. 500 ms)
-    writel( 0x00000010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
-  }
-  else
-  {
-    printk("SendLogins: failed at xchng %Xh, alpa %Xh, status %Xh\n", 
-      ExchangeID, fchs.s_id, ulStatus);
-  }
-  LEAVE("SendLogins");
-
-}
-
-
-// for REPORT_LUNS documentation, see "In-Depth Exploration of Scsi",
-// D. Deming, 1994, pg 7-19 (ISBN 1-879936-08-9)
-static void ScsiReportLunsDone(Scsi_Cmnd *Cmnd)
-{
-  struct Scsi_Host *HostAdapter = Cmnd->device->host;
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  PFC_LOGGEDIN_PORT pLoggedInPort; 
-  int LunListLen=0;
-  int i;
-  ULONG x_ID = 0xFFFFFFFF;
-  UCHAR *ucBuff = Cmnd->request_buffer;
-
-//  printk("cpqfcTS: ReportLunsDone \n");
-  // first, we need to find the Exchange for this command,
-  // so we can find the fcPort struct to make the indicated
-  // changes.
-  for( i=0; i< TACH_SEST_LEN; i++)
-  {
-    if( Exchanges->fcExchange[i].type   // exchange defined?
-                   &&
-       (Exchanges->fcExchange[i].Cmnd == Cmnd) ) // matches?
-             
-    {
-      x_ID = i;  // found exchange!
-      break;
-    }
-  }
-  if( x_ID == 0xFFFFFFFF)
-  {
-//    printk("cpqfcTS: ReportLuns failed - no FC Exchange\n");
-    goto Done;  // Report Luns FC Exchange gone; 
-                // exchange probably Terminated by Implicit logout
-  }
-
-
-  // search linked list for the port_id we sent INQUIRY to
-  pLoggedInPort = fcFindLoggedInPort( fcChip,
-    NULL,     // DON'T search Scsi Nexus (we will set it)
-    Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,        
-    NULL,     // DON'T search linked list for FC WWN
-    NULL);    // DON'T care about end of list
-  if( !pLoggedInPort )
-  {
-//    printk("cpqfcTS: ReportLuns failed - device gone\n");
-    goto Done; // error! can't find logged in Port
-  }    
-  LunListLen = ucBuff[3];
-  LunListLen += ucBuff[2]>>8;
-
-  if( !LunListLen )  // failed
-  {
-    // generically speaking, a soft error means we should retry...
-    if( (Cmnd->result >> 16) == DID_SOFT_ERROR )
-    {
-      if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
-               (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
-      {
-        TachFCHDR_GCMND *fchs = &Exchanges->fcExchange[ x_ID].fchs;
-      // did we fail because of "check condition, device reset?"
-      // e.g. the device was reset (i.e., at every power up)
-      // retry the Report Luns
-      
-      // who are we sending it to?
-      // we know this because we have a copy of the command
-      // frame from the original Report Lun command -
-      // switch the d_id/s_id fields, because the Exchange Build
-      // context is "reply to source".
-      
-        fchs->s_id = fchs->d_id; // (temporarily re-use the struct)
-        cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
-      }
-    }
-    else  // probably, the device doesn't support Report Luns
-      pLoggedInPort->ScsiNexus.VolumeSetAddressing = 0;  
-  }
-  else  // we have LUN info - check VSA mode
-  {
-    // for now, assume all LUNs will have same addr mode
-    // for VSA, payload byte 8 will be 0x40; otherwise, 0
-    pLoggedInPort->ScsiNexus.VolumeSetAddressing = ucBuff[8];  
-      
-    // Since we got a Report Luns answer, set lun masking flag
-    pLoggedInPort->ScsiNexus.LunMasking = 1;
-
-    if( LunListLen > 8*CPQFCTS_MAX_LUN)   // We expect CPQFCTS_MAX_LUN max
-      LunListLen = 8*CPQFCTS_MAX_LUN;
-
-/*   
-    printk("Device WWN %08X%08X Reports Luns @: ", 
-          (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF), 
-          (ULONG)(pLoggedInPort->u.liWWN>>32));
-           
-    for( i=8; i<LunListLen+8; i+=8)
-    {  
-      printk("%02X%02X ", ucBuff[i], ucBuff[i+1] );
-    }
-    printk("\n");
-*/
-    
-    // Since the device was kind enough to tell us where the
-    // LUNs are, lets ensure they are contiguous for Linux's
-    // SCSI driver scan, which expects them to start at 0.
-    // Since Linux only supports 8 LUNs, only copy the first
-    // eight from the report luns command
-
-    // e.g., the Compaq RA4x00 f/w Rev 2.54 and above may report
-    // LUNs 4001, 4004, etc., because other LUNs are masked from
-    // this HBA (owned by someone else).  We'll make those appear as
-    // LUN 0, 1... to Linux
-    {
-      int j;
-      int AppendLunList = 0;
-      // Walk through the LUN list.  The 'j' array number is
-      // Linux's lun #, while the value of .lun[j] is the target's
-      // lun #.
-      // Once we build a LUN list, it's possible for a known device 
-      // to go offline while volumes (LUNs) are added.  Later,
-      // the device will do another PLOGI ... Report Luns command,
-      // and we must not alter the existing Linux Lun map.
-      // (This will be very rare).
-      for( j=0; j < CPQFCTS_MAX_LUN; j++)
-      {
-        if( pLoggedInPort->ScsiNexus.lun[j] != 0xFF )
-       {
-         AppendLunList = 1;
-         break;
-       }
-      }
-      if( AppendLunList )
-      {
-       int k;
-        int FreeLunIndex;
-//        printk("cpqfcTS: AppendLunList\n");
-
-       // If we get a new Report Luns, we cannot change
-       // any existing LUN mapping! (Only additive entry)
-       // For all LUNs in ReportLun list
-       // if RL lun != ScsiNexus lun
-       //   if RL lun present in ScsiNexus lun[], continue
-       //   else find ScsiNexus lun[]==FF and add, continue
-       
-        for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
-       {
-          if( pLoggedInPort->ScsiNexus.lun[j] != ucBuff[i+1] )
-         {
-           // something changed from the last Report Luns
-           printk(" cpqfcTS: Report Lun change!\n");
-           for( k=0, FreeLunIndex=CPQFCTS_MAX_LUN; 
-                 k < CPQFCTS_MAX_LUN; k++)
-            {
-             if( pLoggedInPort->ScsiNexus.lun[k] == 0xFF)
-             {
-               FreeLunIndex = k;
-               break;
-             }
-              if( pLoggedInPort->ScsiNexus.lun[k] == ucBuff[i+1] )
-               break; // we already masked this lun
-           }
-           if( k >= CPQFCTS_MAX_LUN )
-           {
-             printk(" no room for new LUN %d\n", ucBuff[i+1]);
-           }
-           else if( k == FreeLunIndex )  // need to add LUN
-           {
-             pLoggedInPort->ScsiNexus.lun[k] = ucBuff[i+1];
-//           printk("add [%d]->%02d\n", k, pLoggedInPort->ScsiNexus.lun[k]);
-             
-           }
-           else
-           {
-             // lun already known
-           }
-           break;
-         }
-       }
-       // print out the new list...
-       for( j=0; j< CPQFCTS_MAX_LUN; j++)
-       {
-         if( pLoggedInPort->ScsiNexus.lun[j] == 0xFF)
-           break; // done
-//       printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
-       }
-      }
-      else
-      {
-//       printk("Linux SCSI LUNs[] -> Device LUNs: ");
-       // first time - this is easy
-        for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
-       {
-          pLoggedInPort->ScsiNexus.lun[j] = ucBuff[i+1];
-//       printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
-       }
-//     printk("\n");
-      }
-    }
-  }
-
-Done: ;
-}
-
-extern int is_private_data_of_cpqfc(CPQFCHBA *hba, void * pointer);
-extern void cpqfc_free_private_data(CPQFCHBA *hba, cpqfc_passthru_private_t *data);
-
-static void 
-call_scsi_done(Scsi_Cmnd *Cmnd)
-{
-       CPQFCHBA *hba;
-       hba = (CPQFCHBA *) Cmnd->device->host->hostdata;
-       // Was this command a cpqfc passthru ioctl ?
-        if (Cmnd->sc_request != NULL && Cmnd->device->host != NULL && 
-               Cmnd->device->host->hostdata != NULL &&
-               is_private_data_of_cpqfc((CPQFCHBA *) Cmnd->device->host->hostdata,
-                       Cmnd->sc_request->upper_private_data)) {
-               cpqfc_free_private_data(hba, 
-                       Cmnd->sc_request->upper_private_data);  
-               Cmnd->sc_request->upper_private_data = NULL;
-               Cmnd->result &= 0xff00ffff;
-               Cmnd->result |= (DID_PASSTHROUGH << 16);  // prevents retry
-       }
-       if (Cmnd->scsi_done != NULL)
-               (*Cmnd->scsi_done)(Cmnd);
-}
-
-// After successfully getting a "Process Login" (PRLI) from an
-// FC port, we want to Discover the LUNs so that we know the
-// addressing type (e.g., FCP-SCSI Volume Set Address, Peripheral
-// Unit Device), and whether SSP (Selective Storage Presentation or
-// Lun Masking) has made the LUN numbers non-zero based or 
-// non-contiguous.  To remain backward compatible with the SCSI-2
-// driver model, which expects a contiguous LUNs starting at 0,
-// will use the ReportLuns info to map from "device" to "Linux" 
-// LUNs.
-static void IssueReportLunsCommand( 
-              CPQFCHBA* cpqfcHBAdata, 
-             TachFCHDR_GCMND* fchs)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  PFC_LOGGEDIN_PORT pLoggedInPort; 
-  struct scsi_cmnd *Cmnd = NULL;
-  struct scsi_device *ScsiDev = NULL;
-  LONG x_ID;
-  ULONG ulStatus;
-  UCHAR *ucBuff;
-
-  if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
-  {
-    printk("Discard Q'd ReportLun command\n");
-    goto Done;
-  }
-
-  // find the device (from port_id) we're talking to
-  pLoggedInPort = fcFindLoggedInPort( fcChip,
-        NULL,     // DON'T search Scsi Nexus 
-       fchs->s_id & 0xFFFFFF,        
-       NULL,     // DON'T search linked list for FC WWN
-        NULL);    // DON'T care about end of list
-  if( pLoggedInPort ) // we'd BETTER find it!
-  {
-
-
-    if( !(pLoggedInPort->fcp_info & TARGET_FUNCTION) )
-      goto Done;  // forget it - FC device not a "target"
-
-    ScsiDev = scsi_get_host_dev (cpqfcHBAdata->HostAdapter);
-    if (!ScsiDev)
-      goto Done;
-    
-    Cmnd = scsi_get_command (ScsiDev, GFP_KERNEL);
-    if (!Cmnd) 
-      goto Done;
-
-    ucBuff = pLoggedInPort->ReportLunsPayload;
-    
-    memset( ucBuff, 0, REPORT_LUNS_PL);
-    
-    Cmnd->scsi_done = ScsiReportLunsDone;
-
-    Cmnd->request_buffer = pLoggedInPort->ReportLunsPayload; 
-    Cmnd->request_bufflen = REPORT_LUNS_PL; 
-           
-    Cmnd->cmnd[0] = 0xA0;
-    Cmnd->cmnd[8] = REPORT_LUNS_PL >> 8;
-    Cmnd->cmnd[9] = (UCHAR)REPORT_LUNS_PL;
-    Cmnd->cmd_len = 12;
-
-    Cmnd->device->channel = pLoggedInPort->ScsiNexus.channel;
-    Cmnd->device->id = pLoggedInPort->ScsiNexus.target;
-
-           
-    ulStatus = cpqfcTSBuildExchange(
-      cpqfcHBAdata,
-      SCSI_IRE, 
-      fchs,
-      Cmnd,         // buffer for Report Lun data
-      &x_ID );// fcController->fcExchanges index, -1 if failed
-
-    if( !ulStatus ) // Exchange setup?
-    {
-      ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID );
-      if( !ulStatus )
-      {
-        // submitted to Tach's Outbound Que (ERQ PI incremented)
-        // waited for completion for ELS type (Login frames issued
-        // synchronously)
-      }
-      else
-        // check reason for Exchange not being started - we might
-        // want to Queue and start later, or fail with error
-      {
-  
-      }
-    }
-
-    else   // Xchange setup failed...
-      printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
-  }
-  else     // like, we just got a PRLI ACC, and now the port is gone?
-  {
-    printk(" can't send ReportLuns - no login for port_id %Xh\n",
-           fchs->s_id & 0xFFFFFF);
-  }
-
-
-
-Done:
-
-  if (Cmnd)
-    scsi_put_command (Cmnd);
-  if (ScsiDev) 
-    scsi_free_host_dev (ScsiDev);
-}
-
-
-
-
-
-
-
-static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata)
-{
-  int i;
-  for( i = CPQFCTS_REQ_QUEUE_LEN-1; i>= 0; i--)
-  {
-    if( cpqfcHBAdata->BoardLockCmnd[i] != NULL )
-    {
-      Scsi_Cmnd *Cmnd = cpqfcHBAdata->BoardLockCmnd[i];
-      cpqfcHBAdata->BoardLockCmnd[i] = NULL;
-      Cmnd->result = (DID_SOFT_ERROR << 16);  // ask for retry
-//      printk(" BoardLockCmnd[%d] %p Complete, chnl/target/lun %d/%d/%d\n",
-//        i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
-      call_scsi_done(Cmnd);
-    }
-  }
-}
-
-
-
-
-
-
-// runs every 1 second for FC exchange timeouts and implicit FC device logouts
-
-void cpqfcTSheartbeat( unsigned long ptr )
-{
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)ptr;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts; 
-  ULONG i;
-  unsigned long flags;
-  DECLARE_MUTEX_LOCKED(BoardLock);
-  
-  PCI_TRACE( 0xA8)
-
-  if( cpqfcHBAdata->BoardLock) // Worker Task Running?
-    goto Skip;
-
-  // STOP _que function
-  spin_lock_irqsave( cpqfcHBAdata->HostAdapter->host_lock, flags); 
-
-  PCI_TRACE( 0xA8)
-
-
-  cpqfcHBAdata->BoardLock = &BoardLock; // stop Linux SCSI command queuing
-  
-  // release the IO lock (and re-enable interrupts)
-  spin_unlock_irqrestore( cpqfcHBAdata->HostAdapter->host_lock, flags);
-  
-  // Ensure no contention from  _quecommand or Worker process 
-  CPQ_SPINLOCK_HBA( cpqfcHBAdata)
-  
-  PCI_TRACE( 0xA8)
-  
-
-  disable_irq( cpqfcHBAdata->HostAdapter->irq);  // our IRQ
-
-  // Complete the "bad target" commands (normally only used during
-  // initialization, since we aren't supposed to call "scsi_done"
-  // inside the queuecommand() function).  (this is overly contorted,
-  // scsi_done can be safely called from queuecommand for
-  // this bad target case.  May want to simplify this later)
-
-  for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
-  {
-    if( cpqfcHBAdata->BadTargetCmnd[i] )
-    {
-      Scsi_Cmnd *Cmnd = cpqfcHBAdata->BadTargetCmnd[i];
-      cpqfcHBAdata->BadTargetCmnd[i] = NULL;
-      Cmnd->result = (DID_BAD_TARGET << 16);
-      call_scsi_done(Cmnd);
-    }
-    else
-      break;
-  }
-
-  
-  // logged in ports -- re-login check (ports required to verify login with
-  // PDISC after LIP within 2 secs)
-
-  // prevent contention
-  while( pLoggedInPort ) // for all ports which are expecting
-                         // PDISC after the next LIP, check to see if
-                         // time is up!
-  {
-      // Important: we only detect "timeout" condition on TRANSITION
-      // from non-zero to zero
-    if( pLoggedInPort->LOGO_timer )  // time-out "armed"?
-    {
-      if( !(--pLoggedInPort->LOGO_timer) ) // DEC from 1 to 0?
-      {
-          // LOGOUT time!  Per PLDA, PDISC hasn't complete in 2 secs, so
-          // issue LOGO request and destroy all I/O with other FC port(s).
-        
-/*          
-        printk(" ~cpqfcTS heartbeat: LOGOut!~ ");
-        printk("Linux SCSI Chanl/Target %d/%d (port_id %06Xh) WWN %08X%08X\n", 
-        pLoggedInPort->ScsiNexus.channel, 
-        pLoggedInPort->ScsiNexus.target, 
-       pLoggedInPort->port_id,
-          (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF), 
-          (ULONG)(pLoggedInPort->u.liWWN>>32));
-
-*/
-        cpqfcTSImplicitLogout( cpqfcHBAdata, pLoggedInPort);
-
-      }
-      // else simply decremented - maybe next time...
-    }
-    pLoggedInPort = pLoggedInPort->pNextPort;
-  }
-
-
-
-  
-  
-  // ************  FC EXCHANGE TIMEOUT CHECK **************
-  
-  for( i=0; i< TACH_MAX_XID; i++)
-  {
-    if( Exchanges->fcExchange[i].type )  // exchange defined?
-    {
-
-      if( !Exchanges->fcExchange[i].timeOut ) // time expired
-      {
-        // Set Exchange timeout status
-        Exchanges->fcExchange[i].status |= FC2_TIMEOUT;
-
-        if( i >= TACH_SEST_LEN ) // Link Service Exchange
-        {
-          cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, i);  // Don't "abort" LinkService
-        }
-        
-        else  // SEST Exchange TO -- may post ABTS to Worker Thread Que
-        {
-         // (Make sure we don't keep timing it out; let other functions
-         // complete it or set the timeOut as needed)
-         Exchanges->fcExchange[i].timeOut = 30000; // seconds default
-
-          if( Exchanges->fcExchange[i].type 
-                  & 
-              (BLS_ABTS | BLS_ABTS_ACC )  )
-          {
-           // For BLS_ABTS*, an upper level might still have
-           // an outstanding command waiting for low-level completion.
-           // Also, in the case of a WRITE, we MUST get confirmation
-           // of either ABTS ACC or RJT before re-using the Exchange.
-           // It's possible that the RAID cache algorithm can hang
-           // if we fail to complete a WRITE to a LBA, when a READ
-           // comes later to that same LBA.  Therefore, we must
-           // ensure that the target verifies receipt of ABTS for
-           // the exchange
-          
-           printk("~TO Q'd ABTS (x_ID %Xh)~ ", i); 
-//            TriggerHBA( fcChip->Registers.ReMapMemBase);
-
-           // On timeout of a ABTS exchange, check to
-           // see if the FC device has a current valid login.
-           // If so, restart it.
-           pLoggedInPort = fcFindLoggedInPort( fcChip,
-              Exchanges->fcExchange[i].Cmnd, // find Scsi Nexus
-              0,        // DON'T search linked list for FC port id
-             NULL,     // DON'T search linked list for FC WWN
-              NULL);    // DON'T care about end of list
-
-           // device exists?
-           if( pLoggedInPort ) // device exists?
-           {
-             if( pLoggedInPort->prli ) // logged in for FCP-SCSI?
-             {
-               // attempt to restart the ABTS
-               printk(" ~restarting ABTS~ ");
-                cpqfcTSStartExchange( cpqfcHBAdata, i );
-
-             }
-           }
-          }
-         else  // not an ABTS
-         { 
-           
-            // We expect the WorkerThread to change the xchng type to
-            // abort and set appropriate timeout.
-            cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &i ); // timed-out
-         }
-        }
-      }
-      else  // time not expired...
-      {
-        // decrement timeout: 1 or more seconds left
-        --Exchanges->fcExchange[i].timeOut;
-      }
-    }
-  }
-
-
-  enable_irq( cpqfcHBAdata->HostAdapter->irq);
-
-  CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
-
-  cpqfcHBAdata->BoardLock = NULL; // Linux SCSI commands may be queued
-
-  // Now, complete any Cmnd we Q'd up while BoardLock was held
-
-  CompleteBoardLockCmnd( cpqfcHBAdata);
-
-  // restart the timer to run again (1 sec later)
-Skip:
-  mod_timer( &cpqfcHBAdata->cpqfcTStimer, jiffies + HZ);
-  
-  PCI_TRACEO( i, 0xA8)
-  return;
-}
-
-
-// put valid FC-AL physical address in spec order
-static const UCHAR valid_al_pa[]={
-    0xef, 0xe8, 0xe4, 0xe2, 
-    0xe1, 0xE0, 0xDC, 0xDA, 
-    0xD9, 0xD6, 0xD5, 0xD4, 
-    0xD3, 0xD2, 0xD1, 0xCe, 
-    0xCd, 0xCc, 0xCb, 0xCa, 
-    0xC9, 0xC7, 0xC6, 0xC5, 
-    0xC3, 0xBc, 0xBa, 0xB9,
-    0xB6, 0xB5, 0xB4, 0xB3, 
-    0xB2, 0xB1, 0xae, 0xad,
-    0xAc, 0xAb, 0xAa, 0xA9, 
-
-    0xA7, 0xA6, 0xA5, 0xA3, 
-    0x9f, 0x9e, 0x9d, 0x9b, 
-    0x98, 0x97, 0x90, 0x8f, 
-    0x88, 0x84, 0x82, 0x81, 
-    0x80, 0x7c, 0x7a, 0x79, 
-    0x76, 0x75, 0x74, 0x73, 
-    0x72, 0x71, 0x6e, 0x6d, 
-    0x6c, 0x6b, 0x6a, 0x69, 
-    0x67, 0x66, 0x65, 0x63, 
-    0x5c, 0x5a, 0x59, 0x56, 
-    
-    0x55, 0x54, 0x53, 0x52, 
-    0x51, 0x4e, 0x4d, 0x4c, 
-    0x4b, 0x4a, 0x49, 0x47, 
-    0x46, 0x45, 0x43, 0x3c,
-    0x3a, 0x39, 0x36, 0x35, 
-    0x34, 0x33, 0x32, 0x31, 
-    0x2e, 0x2d, 0x2c, 0x2b, 
-    0x2a, 0x29, 0x27, 0x26, 
-    0x25, 0x23, 0x1f, 0x1E,
-    0x1d, 0x1b, 0x18, 0x17, 
-
-    0x10, 0x0f, 8, 4, 2, 1 }; // ALPA 0 (Fabric) is special case
-
-const int number_of_al_pa = (sizeof(valid_al_pa) );
-
-
-
-// this function looks up an al_pa from the table of valid al_pa's
-// we decrement from the last decimal loop ID, because soft al_pa
-// (our typical case) are assigned with highest priority (and high al_pa)
-// first.  See "In-Depth FC-AL", R. Kembel pg. 38
-// INPUTS:
-//   al_pa - 24 bit port identifier (8 bit al_pa on private loop)
-// RETURN:
-//  Loop ID - serves are index to array of logged in ports
-//  -1      - invalid al_pa (not all 8 bit values are legal)
-
-#if (0)
-static int GetLoopID( ULONG al_pa )
-{
-  int i;
-
-  for( i = number_of_al_pa -1; i >= 0; i--)  // dec.
-  {
-    if( valid_al_pa[i] == (UCHAR)al_pa )  // take lowest 8 bits
-      return i;  // success - found valid al_pa; return decimal LoopID
-  }
-  return -1; // failed - not found
-}
-#endif
-
-extern cpqfc_passthru_private_t *cpqfc_private(Scsi_Request *sr);
-
-// Search the singly (forward) linked list "fcPorts" looking for 
-// either the SCSI target (if != -1), port_id (if not NULL), 
-// or WWN (if not null), in that specific order.
-// If we find a SCSI nexus (from Cmnd arg), set the SCp.phase
-// field according to VSA or PDU
-// RETURNS:
-//   Ptr to logged in port struct if found
-//     (NULL if not found)
-//   pLastLoggedInPort - ptr to last struct (for adding new ones)
-// 
-PFC_LOGGEDIN_PORT  fcFindLoggedInPort( 
-  PTACHYON fcChip, 
-  Scsi_Cmnd *Cmnd, // search linked list for Scsi Nexus (channel/target/lun)
-  ULONG port_id,   // search linked list for al_pa, or
-  UCHAR wwn[8],    // search linked list for WWN, or...
-  PFC_LOGGEDIN_PORT *pLastLoggedInPort )
-             
-{
-  PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts; 
-  BOOLEAN target_id_valid=FALSE;
-  BOOLEAN port_id_valid=FALSE;
-  BOOLEAN wwn_valid=FALSE;
-  int i;
-
-
-  if( Cmnd != NULL )
-    target_id_valid = TRUE;
-  
-  else if( port_id ) // note! 24-bit NULL address is illegal
-    port_id_valid = TRUE;
-
-  else
-  {
-    if( wwn ) // non-null arg? (OK to pass NULL when not searching WWN)
-    {
-      for( i=0; i<8; i++)  // valid WWN passed?  NULL WWN invalid
-      {
-        if( wwn[i] != 0 )
-          wwn_valid = TRUE;  // any non-zero byte makes (presumably) valid
-      }
-    }
-  }
-                // check other options ...
-
-
-  // In case multiple search options are given, we use a priority
-  // scheme:
-  // While valid pLoggedIn Ptr
-  //   If port_id is valid
-  //     if port_id matches, return Ptr
-  //   If wwn is valid
-  //     if wwn matches, return Ptr
-  //   Next Ptr in list
-  //
-  // Return NULL (not found)
-      
-  while( pLoggedInPort ) // NULL marks end of list (1st ptr always valid)
-  {
-    if( pLastLoggedInPort ) // caller's pointer valid?
-      *pLastLoggedInPort = pLoggedInPort;  // end of linked list
-    
-    if( target_id_valid )
-    {
-      // check Linux Scsi Cmnd for channel/target Nexus match
-      // (all luns are accessed through matching "pLoggedInPort")
-      if( (pLoggedInPort->ScsiNexus.target == Cmnd->device->id)
-                &&
-          (pLoggedInPort->ScsiNexus.channel == Cmnd->device->channel))
-      {
-        // For "passthru" modes, the IOCTL caller is responsible
-       // for setting the FCP-LUN addressing
-       if (Cmnd->sc_request != NULL && Cmnd->device->host != NULL && 
-               Cmnd->device->host->hostdata != NULL &&
-               is_private_data_of_cpqfc((CPQFCHBA *) Cmnd->device->host->hostdata,
-                       Cmnd->sc_request->upper_private_data)) { 
-               /* This is a passthru... */
-               cpqfc_passthru_private_t *pd;
-               pd = Cmnd->sc_request->upper_private_data;
-               Cmnd->SCp.phase = pd->bus;
-               // Cmnd->SCp.have_data_in = pd->pdrive;
-               Cmnd->SCp.have_data_in = Cmnd->device->lun;
-       } else {
-         /* This is not a passthru... */
-       
-          // set the FCP-LUN addressing type
-          Cmnd->SCp.phase = pLoggedInPort->ScsiNexus.VolumeSetAddressing;      
-
-          // set the Device Type we got from the snooped INQUIRY string
-         Cmnd->SCp.Message = pLoggedInPort->ScsiNexus.InqDeviceType;
-
-         // handle LUN masking; if not "default" (illegal) lun value,
-         // the use it.  These lun values are set by a successful
-         // Report Luns command
-          if( pLoggedInPort->ScsiNexus.LunMasking == 1) 
-         {
-           if (Cmnd->device->lun > sizeof(pLoggedInPort->ScsiNexus.lun))
-               return NULL;
-            // we KNOW all the valid LUNs... 0xFF is invalid!
-            Cmnd->SCp.have_data_in = pLoggedInPort->ScsiNexus.lun[Cmnd->device->lun];
-           if (pLoggedInPort->ScsiNexus.lun[Cmnd->device->lun] == 0xFF)
-               return NULL;
-           // printk("xlating lun %d to 0x%02x\n", Cmnd->lun, 
-            // pLoggedInPort->ScsiNexus.lun[Cmnd->lun]);
-         }
-         else
-           Cmnd->SCp.have_data_in = Cmnd->device->lun; // Linux & target luns match
-       }
-       break; // found it!
-      }
-    }
-    
-    if( port_id_valid ) // look for alpa first
-    {
-      if( pLoggedInPort->port_id == port_id )
-          break;  // found it!
-    }
-    if( wwn_valid ) // look for wwn second
-    {
-
-      if( !memcmp( &pLoggedInPort->u.ucWWN[0], &wwn[0], 8))
-      {  
-                 // all 8 bytes of WWN match
-        break;   // found it!
-      }
-    }
-                
-    pLoggedInPort = pLoggedInPort->pNextPort; // try next port
-  }
-
-  return pLoggedInPort;
-}
-
-
-
-
-// 
-// We need to examine the SEST table and re-validate
-// any open Exchanges for this LoggedInPort
-// To make Tachyon pay attention, Freeze FCP assists,
-// set VAL bits, Unfreeze FCP assists
-static void RevalidateSEST( struct Scsi_Host *HostAdapter, 
-                       PFC_LOGGEDIN_PORT pLoggedInPort)
-{
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG x_ID;
-  BOOLEAN TachFroze = FALSE;
-  
-  
-  // re-validate any SEST exchanges that are permitted
-  // to survive the link down (e.g., good PDISC performed)
-  for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
-  {
-
-    // If the SEST entry port_id matches the pLoggedInPort,
-    // we need to re-validate
-    if( (Exchanges->fcExchange[ x_ID].type == SCSI_IRE)
-         || 
-       (Exchanges->fcExchange[ x_ID].type == SCSI_IWE))
-    {
-                    
-      if( (Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF)  // (24-bit port ID)
-            == pLoggedInPort->port_id) 
-      {
-//     printk(" re-val xID %Xh ", x_ID);
-        if( !TachFroze )  // freeze if not already frozen
-          TachFroze |= FreezeTach( cpqfcHBAdata);
-        fcChip->SEST->u[ x_ID].IWE.Hdr_Len |= 0x80000000; // set VAL bit
-      }
-    } 
-  }
-
-  if( TachFroze) 
-  { 
-    fcChip->UnFreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
-  }
-} 
-
-
-// Complete an Linux Cmnds that we Queued because
-// our FC link was down (cause immediate retry)
-
-static void UnblockScsiDevice( struct Scsi_Host *HostAdapter, 
-                       PFC_LOGGEDIN_PORT pLoggedInPort)
-{
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  Scsi_Cmnd* *SCptr = &cpqfcHBAdata->LinkDnCmnd[0];
-  Scsi_Cmnd *Cmnd;
-  int indx;
-
-  
-  // if the device was previously "blocked", make sure
-  // we unblock it so Linux SCSI will resume
-
-  pLoggedInPort->device_blocked = FALSE; // clear our flag
-
-  // check the Link Down command ptr buffer;
-  // we can complete now causing immediate retry
-  for( indx=0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++, SCptr++)
-  {
-    if( *SCptr != NULL ) // scsi command to complete?
-    {
-#ifdef DUMMYCMND_DBG
-      printk("complete Cmnd %p in LinkDnCmnd[%d]\n", *SCptr,indx);
-#endif
-      Cmnd = *SCptr;
-
-
-      // Are there any Q'd commands for this target?
-      if( (Cmnd->device->id == pLoggedInPort->ScsiNexus.target)
-              &&
-          (Cmnd->device->channel == pLoggedInPort->ScsiNexus.channel) )
-      {
-        Cmnd->result = (DID_SOFT_ERROR <<16); // force retry
-        if( Cmnd->scsi_done == NULL) 
-       {
-          printk("LinkDnCmnd scsi_done ptr null, port_id %Xh\n",
-                 pLoggedInPort->port_id);
-       }
-       else
-         call_scsi_done(Cmnd);
-        *SCptr = NULL;  // free this slot for next use
-      }
-    }
-  }
-}
-
-  
-//#define WWN_DBG 1
-
-static void SetLoginFields(
-  PFC_LOGGEDIN_PORT pLoggedInPort,
-  TachFCHDR_GCMND* fchs,
-  BOOLEAN PDisc,
-  BOOLEAN Originator)
-{
-  LOGIN_PAYLOAD logi;       // FC-PH Port Login
-  PRLI_REQUEST prli;  // copy for BIG ENDIAN switch
-  int i;
-#ifdef WWN_DBG
-  ULONG ulBuff;
-#endif
-
-  BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
-
-  pLoggedInPort->Originator = Originator;
-  pLoggedInPort->port_id = fchs->s_id & 0xFFFFFF;
-  
-  switch( fchs->pl[0] & 0xffff )
-  {
-  case 0x00000002:  //  PLOGI or PDISC ACCept?
-    if( PDisc )     // PDISC accept
-      goto PDISC_case;
-
-  case 0x00000003:  //  ELS_PLOGI or ELS_PLOGI_ACC
-
-  // Login BB_credit typically 0 for Tachyons
-    pLoggedInPort->BB_credit = logi.cmn_services.bb_credit;
-
-    // e.g. 128, 256, 1024, 2048 per FC-PH spec
-    // We have to use this when setting up SEST Writes,
-    // since that determines frame size we send.
-    pLoggedInPort->rx_data_size = logi.class3.rx_data_size;
-    pLoggedInPort->plogi = TRUE;
-    pLoggedInPort->pdisc = FALSE;
-    pLoggedInPort->prli = FALSE;    // ELS_PLOGI resets
-    pLoggedInPort->flogi = FALSE;   // ELS_PLOGI resets
-    pLoggedInPort->logo = FALSE;    // ELS_PLOGI resets
-    pLoggedInPort->LOGO_counter = 0;// ELS_PLOGI resets
-    pLoggedInPort->LOGO_timer = 0;// ELS_PLOGI resets
-
-    // was this PLOGI to a Fabric?
-    if( pLoggedInPort->port_id == 0xFFFFFC ) // well know address
-      pLoggedInPort->flogi = TRUE;
-
-
-    for( i=0; i<8; i++)   // copy the LOGIN port's WWN
-      pLoggedInPort->u.ucWWN[i] = logi.port_name[i];  
-
-#ifdef WWN_DBG
-    ulBuff = (ULONG)pLoggedInPort->u.liWWN;
-    if( pLoggedInPort->Originator)
-      printk("o");
-    else
-      printk("r");
-    printk("PLOGI port_id %Xh, WWN %08X",
-      pLoggedInPort->port_id, ulBuff);
-
-    ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
-    printk("%08Xh fcPort %p\n", ulBuff, pLoggedInPort);
-#endif
-    break;
-
-
-
-  
-  case 0x00000005:  //  ELS_LOGO (logout)
-
-
-    pLoggedInPort->plogi = FALSE;
-    pLoggedInPort->pdisc = FALSE;
-    pLoggedInPort->prli = FALSE;   // ELS_PLOGI resets
-    pLoggedInPort->flogi = FALSE;  // ELS_PLOGI resets
-    pLoggedInPort->logo = TRUE;    // ELS_PLOGI resets
-    pLoggedInPort->LOGO_counter++; // ELS_PLOGI resets
-    pLoggedInPort->LOGO_timer = 0;
-#ifdef WWN_DBG
-    ulBuff = (ULONG)pLoggedInPort->u.liWWN;
-    if( pLoggedInPort->Originator)
-      printk("o");
-    else
-      printk("r");
-    printk("LOGO port_id %Xh, WWN %08X",
-      pLoggedInPort->port_id, ulBuff);
-
-    ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
-    printk("%08Xh\n", ulBuff);
-#endif
-    break;
-
-
-
-PDISC_case:
-  case 0x00000050: //  ELS_PDISC or ELS_PDISC_ACC
-    pLoggedInPort->LOGO_timer = 0;  // stop the time-out
-      
-    pLoggedInPort->prli = TRUE;     // ready to accept FCP-SCSI I/O
-    
-
-      
-#ifdef WWN_DBG
-    ulBuff = (ULONG)pLoggedInPort->u.liWWN;
-    if( pLoggedInPort->Originator)
-      printk("o");
-    else
-      printk("r");
-    printk("PDISC port_id %Xh, WWN %08X",
-      pLoggedInPort->port_id, ulBuff);
-
-    ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
-    printk("%08Xh\n", ulBuff);
-#endif
-
-
-    
-    break;
-
-
-    
-  case  0x1020L: //  PRLI?
-  case  0x1002L: //  PRLI ACCept?
-    BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli, sizeof(prli));
-
-    pLoggedInPort->fcp_info = prli.fcp_info; // target/initiator flags
-    pLoggedInPort->prli = TRUE;  // PLOGI resets, PDISC doesn't
-
-    pLoggedInPort->pdisc = TRUE;  // expect to send (or receive) PDISC
-                                  // next time
-    pLoggedInPort->LOGO_timer = 0;  // will be set next LinkDown
-#ifdef WWN_DBG
-    ulBuff = (ULONG)pLoggedInPort->u.liWWN;
-    if( pLoggedInPort->Originator)
-      printk("o");
-    else
-      printk("r");
-    printk("PRLI port_id %Xh, WWN %08X",
-      pLoggedInPort->port_id, ulBuff);
-
-    ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
-      printk("%08Xh\n", ulBuff);
-#endif
-
-    break;
-
-  }
-
-  return;
-}
-
-
-
-
-
-
-static void BuildLinkServicePayload( PTACHYON fcChip, ULONG type, void* payload)
-{
-  LOGIN_PAYLOAD *plogi;  // FC-PH Port Login
-  LOGIN_PAYLOAD PlogiPayload;   // copy for BIG ENDIAN switch
-  PRLI_REQUEST  *prli;          // FCP-SCSI Process Login
-  PRLI_REQUEST  PrliPayload;    // copy for BIG ENDIAN switch
-  LOGOUT_PAYLOAD  *logo;
-  LOGOUT_PAYLOAD  LogoutPayload;
-//  PRLO_REQUEST  *prlo;
-//  PRLO_REQUEST  PrloPayload;
-  REJECT_MESSAGE rjt, *prjt;
-
-  memset( &PlogiPayload, 0, sizeof( PlogiPayload));
-  plogi = &PlogiPayload;    // load into stack buffer,
-                                // then BIG-ENDIAN switch a copy to caller
-
-
-  switch( type )  // payload type can be ELS_PLOGI, ELS_PRLI, ADISC, ...
-  {
-    case ELS_FDISC:
-    case ELS_FLOGI:
-    case ELS_PLOGI_ACC:   // FC-PH PORT Login Accept
-    case ELS_PLOGI:   // FC-PH PORT Login
-    case ELS_PDISC:   // FC-PH2 Port Discovery - same payload as ELS_PLOGI
-      plogi->login_cmd = LS_PLOGI;
-      if( type == ELS_PDISC)
-        plogi->login_cmd = LS_PDISC;
-      else if( type == ELS_PLOGI_ACC )
-        plogi->login_cmd = LS_ACC;
-
-      plogi->cmn_services.bb_credit = 0x00;
-      plogi->cmn_services.lowest_ver = fcChip->lowest_FCPH_ver;
-      plogi->cmn_services.highest_ver = fcChip->highest_FCPH_ver;
-      plogi->cmn_services.bb_rx_size = TACHLITE_TS_RX_SIZE;
-      plogi->cmn_services.common_features = CONTINUOSLY_INCREASING |
-              RANDOM_RELATIVE_OFFSET;
-
-             // fill in with World Wide Name based Port Name - 8 UCHARs
-             // get from Tach registers WWN hi & lo
-      LoadWWN( fcChip, plogi->port_name, 0);
-             // fill in with World Wide Name based Node/Fabric Name - 8 UCHARs
-             // get from Tach registers WWN hi & lo
-      LoadWWN( fcChip, plogi->node_name, 1);
-
-       // For Seagate Drives.
-       //
-      plogi->cmn_services.common_features |= 0x800;
-      plogi->cmn_services.rel_offset = 0xFE;
-      plogi->cmn_services.concurrent_seq = 1;
-      plogi->class1.service_options = 0x00;
-      plogi->class2.service_options = 0x00;
-      plogi->class3.service_options = CLASS_VALID;
-      plogi->class3.initiator_control = 0x00;
-      plogi->class3.rx_data_size = MAX_RX_PAYLOAD;
-      plogi->class3.recipient_control =
-             ERROR_DISCARD | ONE_CATEGORY_SEQUENCE;
-      plogi->class3.concurrent_sequences = 1;
-      plogi->class3.open_sequences = 1;
-      plogi->vendor_id[0] = 'C'; plogi->vendor_id[1] = 'Q';
-      plogi->vendor_version[0] = 'C'; plogi->vendor_version[1] = 'Q';
-      plogi->vendor_version[2] = ' '; plogi->vendor_version[3] = '0';
-      plogi->vendor_version[4] = '0'; plogi->vendor_version[5] = '0';
-
-
-      // FLOGI specific fields... (see FC-FLA, Rev 2.7, Aug 1999, sec 5.1)
-      if( (type == ELS_FLOGI) || (type == ELS_FDISC) )
-      {
-        if( type == ELS_FLOGI )
-         plogi->login_cmd = LS_FLOGI;  
-       else
-         plogi->login_cmd = LS_FDISC;  
-
-        plogi->cmn_services.lowest_ver = 0x20;
-        plogi->cmn_services.common_features = 0x0800;
-        plogi->cmn_services.rel_offset = 0;
-        plogi->cmn_services.concurrent_seq = 0;
-
-        plogi->class3.service_options = 0x8800;
-        plogi->class3.rx_data_size = 0;
-        plogi->class3.recipient_control = 0;
-        plogi->class3.concurrent_sequences = 0;
-        plogi->class3.open_sequences = 0;
-      }
-      
-              // copy back to caller's buff, w/ BIG ENDIAN swap
-      BigEndianSwap( (UCHAR*)&PlogiPayload, payload,  sizeof(PlogiPayload));
-      break;
-
-    
-    case ELS_ACC:       // generic Extended Link Service ACCept            
-      plogi->login_cmd = LS_ACC;
-              // copy back to caller's buff, w/ BIG ENDIAN swap
-      BigEndianSwap( (UCHAR*)&PlogiPayload, payload,  4);
-      break;
-
-
-      
-    case ELS_SCR:    // Fabric State Change Registration
-    {
-      SCR_PL scr;     // state change registration
-
-      memset( &scr, 0, sizeof(scr));
-
-      scr.command = LS_SCR;  // 0x62000000
-                             // see FC-FLA, Rev 2.7, Table A.22 (pg 82)
-      scr.function = 3;      // 1 = Events detected by Fabric
-                             // 2 = N_Port detected registration
-                             // 3 = Full registration
-      
-      // copy back to caller's buff, w/ BIG ENDIAN swap
-      BigEndianSwap( (UCHAR*)&scr, payload,  sizeof(SCR_PL));
-    }
-    
-    break;
-
-    
-    case FCS_NSR:    // Fabric Name Service Request
-    {
-      NSR_PL nsr;    // Name Server Req. payload
-
-      memset( &nsr, 0, sizeof(NSR_PL));
-
-                             // see Brocade Fabric Programming Guide,
-                             // Rev 1.3, pg 4-44
-      nsr.CT_Rev = 0x01000000;
-      nsr.FCS_Type = 0xFC020000;
-      nsr.Command_code = 0x01710000;
-      nsr.FCP = 8;
-     
-      // copy back to caller's buff, w/ BIG ENDIAN swap
-      BigEndianSwap( (UCHAR*)&nsr, payload,  sizeof(NSR_PL));
-    }
-    
-    break;
-
-
-
-    
-    case ELS_LOGO:   // FC-PH PORT LogOut
-      logo = &LogoutPayload;    // load into stack buffer,
-                                // then BIG-ENDIAN switch a copy to caller
-      logo->cmd = LS_LOGO;
-                                // load the 3 UCHARs of the node name
-                                // (if private loop, upper two UCHARs 0)
-      logo->reserved = 0;
-
-      logo->n_port_identifier[0] = (UCHAR)(fcChip->Registers.my_al_pa);
-      logo->n_port_identifier[1] =
-                     (UCHAR)(fcChip->Registers.my_al_pa>>8);
-      logo->n_port_identifier[2] =
-                     (UCHAR)(fcChip->Registers.my_al_pa>>16);
-             // fill in with World Wide Name based Port Name - 8 UCHARs
-             // get from Tach registers WWN hi & lo
-      LoadWWN( fcChip, logo->port_name, 0);
-
-      BigEndianSwap( (UCHAR*)&LogoutPayload,
-                     payload,  sizeof(LogoutPayload) );  // 16 UCHAR struct
-      break;
-
-
-    case ELS_LOGO_ACC:     // Logout Accept (FH-PH pg 149, table 74)
-      logo = &LogoutPayload;    // load into stack buffer,
-                                // then BIG-ENDIAN switch a copy to caller
-      logo->cmd = LS_ACC;
-      BigEndianSwap( (UCHAR*)&LogoutPayload, payload, 4 );  // 4 UCHAR cmnd
-      break;
-      
-
-    case ELS_RJT:          // ELS_RJT link service reject (FH-PH pg 155)
-
-      prjt = (REJECT_MESSAGE*)payload;  // pick up passed data
-      rjt.command_code = ELS_RJT;
-                       // reverse fields, because of Swap that follows...
-      rjt.vendor = prjt->reserved; // vendor specific
-      rjt.explain = prjt->reason; //
-      rjt.reason = prjt->explain; //
-      rjt.reserved = prjt->vendor; //
-                       // BIG-ENDIAN switch a copy to caller
-      BigEndianSwap( (UCHAR*)&rjt, payload, 8 );  // 8 UCHAR cmnd
-      break;
-
-
-
-
-
-    case ELS_PRLI_ACC:  // Process Login ACCept
-    case ELS_PRLI:  // Process Login
-    case ELS_PRLO:  // Process Logout
-      memset( &PrliPayload, 0, sizeof( PrliPayload));
-      prli = &PrliPayload;      // load into stack buffer,
-
-      if( type == ELS_PRLI )
-        prli->cmd = 0x20;  // Login
-      else if( type == ELS_PRLO )
-        prli->cmd = 0x21;  // Logout
-      else if( type == ELS_PRLI_ACC )
-      {
-        prli->cmd = 0x02;  // Login ACCept
-        prli->valid = REQUEST_EXECUTED;
-      }
-
-
-      prli->valid |= SCSI_FCP | ESTABLISH_PAIR;
-      prli->fcp_info = READ_XFER_RDY;
-      prli->page_length = 0x10;
-      prli->payload_length = 20;
-                                // Can be initiator AND target
-
-      if( fcChip->Options.initiator )
-        prli->fcp_info |= INITIATOR_FUNCTION;
-      if( fcChip->Options.target )
-        prli->fcp_info |= TARGET_FUNCTION;
-
-      BigEndianSwap( (UCHAR*)&PrliPayload, payload,  prli->payload_length);
-      break;
-
-
-
-    default:  // no can do - programming error
-      printk(" BuildLinkServicePayload unknown!\n");
-      break;
-  }
-}
-
-// loads 8 UCHARs for PORT name or NODE name base on
-// controller's WWN.
-void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type)
-{
-  UCHAR* bPtr, i;
-
-  switch( type )
-  {
-    case 0:  // Port_Name
-      bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
-      for( i =0; i<4; i++)
-        dest[i] = *bPtr++;
-      bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
-      for( i =4; i<8; i++)
-        dest[i] = *bPtr++;
-      break;
-    case 1:  // Node/Fabric _Name
-      bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
-      for( i =0; i<4; i++)
-        dest[i] = *bPtr++;
-      bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
-      for( i =4; i<8; i++)
-        dest[i] = *bPtr++;
-      break;
-  }
-  
-}
-
-
-
-// We check the Port Login payload for required values.  Note that
-// ELS_PLOGI and ELS_PDISC (Port DISCover) use the same payload.
-
-
-int verify_PLOGI( PTACHYON fcChip,
-                  TachFCHDR_GCMND* fchs, 
-                  ULONG* reject_explain)
-{
-  LOGIN_PAYLOAD        login;
-
-                  // source, dest, len (should be mult. of 4)
-  BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&login,  sizeof(login));
-
-                            // check FC version
-                            // if other port's highest supported version
-                            // is less than our lowest, and 
-                            // if other port's lowest
-  if( login.cmn_services.highest_ver < fcChip->lowest_FCPH_ver ||
-      login.cmn_services.lowest_ver > fcChip->highest_FCPH_ver )
-  {
-    *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
-    return LOGICAL_ERROR;
-  }
-
-                            // Receive Data Field Size must be >=128
-                            // per FC-PH
-  if (login.cmn_services.bb_rx_size < 128)
-  {
-    *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, DATA_FIELD_SIZE_ERROR);
-    return LOGICAL_ERROR;
-  }
-
-                            // Only check Class 3 params
-  if( login.class3.service_options & CLASS_VALID)
-  {
-    if (login.class3.rx_data_size < 128)
-    {
-      *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INVALID_CSP);
-      return LOGICAL_ERROR;
-    }
-    if( login.class3.initiator_control & XID_REQUIRED)
-    {
-      *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INITIATOR_CTL_ERROR);
-      return LOGICAL_ERROR;
-    }
-  }
-  return 0;   // success
-}
-
-
-
-
-int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain)
-{
-  PRLI_REQUEST prli;  // buffer for BIG ENDIAN
-
-                  // source, dest, len (should be mult. of 4)
-  BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli,  sizeof(prli));
-
-  if( prli.fcp_info == 0 )  // i.e., not target or initiator?
-  {
-    *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
-    return LOGICAL_ERROR;
-  }
-
-  return 0;  // success
-}
-
-
-// SWAP UCHARs as required by Fibre Channel (i.e. BIG ENDIAN)
-// INPUTS:
-//   source   - ptr to LITTLE ENDIAN ULONGS
-//   cnt      - number of UCHARs to switch (should be mult. of ULONG)
-// OUTPUTS:
-//   dest     - ptr to BIG ENDIAN copy
-// RETURN:
-//   none
-//
-void BigEndianSwap( UCHAR *source, UCHAR *dest,  USHORT cnt)
-{
-  int i,j;
-
-  source+=3;   // start at MSB of 1st ULONG
-  for( j=0; j < cnt; j+=4, source+=4, dest+=4)  // every ULONG
-  {
-    for( i=0; i<4; i++)  // every UCHAR in ULONG
-          *(dest+i) = *(source-i);
-  }
-}
-
-
-
-
-// Build FC Exchanges............
-
-static void  buildFCPstatus( 
-  PTACHYON fcChip, 
-  ULONG ExchangeID);
-
-static LONG FindFreeExchange( PTACHYON fcChip, ULONG type );
-
-static ULONG build_SEST_sgList( 
-  struct pci_dev *pcidev,
-  ULONG *SESTalPairStart,
-  Scsi_Cmnd *Cmnd,
-  ULONG *sgPairs,
-  PSGPAGES *sgPages_head  // link list of TL Ext. S/G pages from O/S Pool
-);
-
-static int build_FCP_payload( Scsi_Cmnd *Cmnd, 
-  UCHAR* payload, ULONG type, ULONG fcp_dl );
-
-
-/*
-                             IRB
-      ERQ           __________________
-  |          |   / | Req_A_SFS_Len    |        ____________________
-  |----------|  /  | Req_A_SFS_Addr   |------->|  Reserved         |
-  |   IRB    | /   | Req_A_D_ID       |        | SOF EOF TimeStamp |
-  |-----------/    | Req_A_SEST_Index |-+      | R_CTL |   D_ID    |
-  |   IRB    |     | Req_B...         | |      | CS_CTL|   S_ID    | 
-  |-----------\    |                  | |      | TYPE  |   F_CTL   |
-  |   IRB    | \   |                  | |      | SEQ_ID  | SEQ_CNT |
-  |-----------  \  |                  | +-->+--| OX_ID   | RX_ID   |
-  |          |   \ |__________________|     |  |       RO          |
-                                            |  | pl (payload/cmnd) |
-                                            |  |        .....      |
-                                            |  |___________________|
-                                            |
-                                            |
-+-------------------------------------------+
-|
-|
-|                        e.g. IWE    
-|    SEST           __________________             for FCP_DATA
-| |          |   / |       | Hdr_Len  |        ____________________
-| |----------|  /  |  Hdr_Addr_Addr   |------->|  Reserved         |
-| |   [0]    | /   |Remote_ID| RSP_Len|        | SOF EOF TimeStamp |
-| |-----------/    |   RSP_Addr       |---+    | R_CTL |   D_ID    |
-+->   [1]    |     |       | Buff_Off |   |    | CS_CTL|   S_ID    | 
-  |-----------\    |BuffIndex| Link   |   |    | TYPE  |   F_CTL   |
-  |   [2]    | \   | Rsvd  |   RX_ID  |   |    | SEQ_ID  | SEQ_CNT |
-  |-----------  \  |    Data_Len      |   |    | OX_ID   | RX_ID   |
-  |    ...   |   \ |     Exp_RO       |   |    |       RO          |
-  |----------|     |   Exp_Byte_Cnt   |   |    |___________________|
-  | SEST_LEN |  +--|    Len           |   |                                             
-  |__________|  |  |   Address        |   |                                              
-                |  |    ...           |   |         for FCP_RSP  
-                |  |__________________|   |    ____________________
-                |                         +----|  Reserved         |   
-                |                              | SOF EOF TimeStamp |
-                |                              | R_CTL |   D_ID    |
-                |                              | CS_CTL|   S_ID    | 
-                +--- local or extended         |     ....          |
-                     scatter/gather lists
-                     defining upper-layer
-                     data (e.g. from user's App)
-
-
-*/
-// All TachLite commands must start with a SFS (Single Frame Sequence)
-// command.  In the simplest case (a NOP Basic Link command),
-// only one frame header and ERQ entry is required.  The most complex
-// case is the SCSI assisted command, which requires an ERQ entry,
-// SEST entry, and several frame headers and data buffers all
-// logically linked together.
-// Inputs:
-//   cpqfcHBAdata  - controller struct
-//   type          - PLOGI, SCSI_IWE, etc.
-//   InFCHS        - Incoming Tachlite FCHS which prompted this exchange
-//                   (only s_id set if we are originating)
-//   Data          - PVOID to data struct consistent with "type"
-//   fcExchangeIndex - pointer to OX/RD ID value of built exchange
-// Return:
-//   fcExchangeIndex - OX/RD ID value if successful
-//   0    - success
-//  INVALID_ARGS    - NULL/ invalid passed args
-//  BAD_ALPA        - Bad source al_pa address
-//  LNKDWN_OSLS     - Link Down (according to this controller)
-//  OUTQUE_FULL     - Outbound Que full
-//  DRIVERQ_FULL    - controller's Exchange array full
-//  SEST_FULL       - SEST table full
-//
-// Remarks:
-// Psuedo code:
-// Check for NULL pointers / bad args
-// Build outgoing FCHS - the header/payload struct
-// Build IRB (for ERQ entry)
-// if SCSI command, build SEST entry (e.g. IWE, TRE,...)
-// return success
-
-//sbuildex
-ULONG cpqfcTSBuildExchange(
-  CPQFCHBA *cpqfcHBAdata,
-  ULONG type, // e.g. PLOGI
-  TachFCHDR_GCMND* InFCHS,  // incoming FCHS
-  void *Data,               // the CDB, scatter/gather, etc.  
-  LONG *fcExchangeIndex )   // points to allocated exchange, 
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG ulStatus = 0;  // assume OK
-  USHORT ox_ID, rx_ID=0xFFFF;
-  ULONG SfsLen=0L;
-  TachLiteIRB* pIRB;
-  IRBflags IRB_flags;
-  UCHAR *pIRB_flags = (UCHAR*)&IRB_flags;
-  TachFCHDR_GCMND* CMDfchs;
-  TachFCHDR* dataHDR;     // 32 byte HEADER ONLY FCP-DATA buffer
-  TachFCHDR_RSP* rspHDR;     // 32 byte header + RSP payload
-  Scsi_Cmnd *Cmnd = (Scsi_Cmnd*)Data;   // Linux Scsi CDB, S/G, ...
-  TachLiteIWE* pIWE;
-  TachLiteIRE* pIRE;
-  TachLiteTWE* pTWE;
-  TachLiteTRE* pTRE;
-  ULONG fcp_dl;           // total byte length of DATA transferred
-  ULONG fl;               // frame length (FC frame size, 128, 256, 512, 1024)
-  ULONG sgPairs;          // number of valid scatter/gather pairs
-  int FCP_SCSI_command;
-  BA_ACC_PAYLOAD *ba_acc;
-  BA_RJT_PAYLOAD *ba_rjt;
-
-                          // check passed ARGS
-  if( !fcChip->ERQ )      // NULL ptr means uninitialized Tachlite chip
-    return INVALID_ARGS;
-
-
-  if( type == SCSI_IRE ||
-      type == SCSI_TRE ||
-      type == SCSI_IWE ||
-      type == SCSI_TWE)
-    FCP_SCSI_command = 1;
-
-  else
-    FCP_SCSI_command = 0;
-
-
-                     // for commands that pass payload data (e.g. SCSI write)
-                     // examine command struct - verify that the
-                     // length of s/g buffers is adequate for total payload
-                     // length (end of list is NULL address)
-
-  if( FCP_SCSI_command )
-  {
-    if( Data )     // must have data descriptor (S/G list -- at least
-                   // one address with at least 1 byte of data)
-    {
-      // something to do (later)?
-    }
-
-    else
-      return INVALID_ARGS;  // invalid DATA ptr
-  }
-
-    
-
-         // we can build an Exchange for later Queuing (on the TL chip)
-         // if an empty slot is available in the DevExt for this controller
-         // look for available Exchange slot...
-
-  if( type != FCP_RESPONSE &&
-      type != BLS_ABTS &&
-      type != BLS_ABTS_ACC )  // already have Exchange slot!
-    *fcExchangeIndex = FindFreeExchange( fcChip, type );
-
-  if( *fcExchangeIndex != -1 )   // Exchange is available?
-  {
-                     // assign tmp ptr (shorthand)
-    CMDfchs = &Exchanges->fcExchange[ *fcExchangeIndex].fchs; 
-
-    if( Cmnd != NULL ) // (necessary for ABTS cases)
-    {
-      Exchanges->fcExchange[ *fcExchangeIndex].Cmnd = Cmnd; // Linux Scsi
-      Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort = 
-       fcFindLoggedInPort( fcChip,
-          Exchanges->fcExchange[ *fcExchangeIndex].Cmnd, // find Scsi Nexus
-          0,        // DON'T search linked list for FC port id
-         NULL,     // DON'T search linked list for FC WWN
-          NULL);    // DON'T care about end of list
-
-    }
-
-
-                     // Build the command frame header (& data) according
-                     // to command type
-
-                     // fields common for all SFS frame types
-    CMDfchs->reserved = 0L; // must clear
-    CMDfchs->sof_eof = 0x75000000L;  // SOFi3:EOFn  no UAM; LCr=0, no TS
-    
-             // get the destination port_id from incoming FCHS
-             // (initialized before calling if we're Originator)
-             // Frame goes to port it was from - the source_id
-    
-    CMDfchs->d_id = InFCHS->s_id &0xFFFFFF; // destination (add R_CTL later)
-    CMDfchs->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
-
-
-    // now enter command-specific fields
-    switch( type )
-    {
-
-    case BLS_NOP:   // FC defined basic link service command NO-OP
-                // ensure unique X_IDs! (use tracking function)
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 32L;        // add len to LSB (header only - no payload)
-
-                   // TYPE[31-24] 00 Basic Link Service
-                   // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
-      CMDfchs->d_id |= 0x80000000L;  // R_CTL = 80 for NOP (Basic Link Ser.)
-      CMDfchs->f_ctl = 0x00310000L;  // xchng originator, 1st seq,....
-      CMDfchs->seq_cnt = 0x0L;
-      CMDfchs->ox_rx_id = 0xFFFF;        // RX_ID for now; OX_ID on start
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-      CMDfchs->pl[0] = 0xaabbccddL;   // words 8-15 frame data payload (n/a)
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // seconds
-                                      // (NOP should complete ~instantly)
-      break;
-
-
-    
-    
-    case BLS_ABTS_ACC:  // Abort Sequence ACCept
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 32 + 12;    // add len to LSB (header + 3 DWORD payload)
-
-      CMDfchs->d_id |= 0x84000000L;  // R_CTL = 84 for BASIC ACCept
-                   // TYPE[31-24] 00 Basic Link Service
-                   // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
-      CMDfchs->f_ctl = 0x00910000L;  // xchnge responder, last seq, xfer SI
-                   // CMDfchs->seq_id & count might be set from DataHdr?
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
-                        // (Timeout in case of weird error)
-      
-      // now set the ACCept payload...
-      ba_acc = (BA_ACC_PAYLOAD*)&CMDfchs->pl[0];
-      memset( ba_acc, 0, sizeof( BA_ACC_PAYLOAD));
-      // Since PLDA requires (only) entire Exchange aborts, we don't need
-      // to worry about what the last sequence was.
-
-      // We expect that a "target" task is accepting the abort, so we
-      // can use the OX/RX ID pair 
-      ba_acc->ox_rx_id = CMDfchs->ox_rx_id;
-      // source, dest, #bytes
-      BigEndianSwap((UCHAR *)&CMDfchs->ox_rx_id, (UCHAR *)&ba_acc->ox_rx_id, 4);
-
-      ba_acc->low_seq_cnt = 0;
-      ba_acc->high_seq_cnt = 0xFFFF;
-
-
-      break;
-    
-
-    case BLS_ABTS_RJT:  // Abort Sequence ACCept
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 32 + 12;    // add len to LSB (header + 3 DWORD payload)
-
-      CMDfchs->d_id |= 0x85000000L;  // R_CTL = 85 for BASIC ReJecT
-                   // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
-                   // TYPE[31-24] 00 Basic Link Service
-      CMDfchs->f_ctl = 0x00910000L;  // xchnge responder, last seq, xfer SI
-                   // CMDfchs->seq_id & count might be set from DataHdr?
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
-                        // (Timeout in case of weird error)
-      
-      CMDfchs->ox_rx_id = InFCHS->ox_rx_id; // copy from sender!
-      
-      // now set the ReJecT payload...
-      ba_rjt = (BA_RJT_PAYLOAD*)&CMDfchs->pl[0];
-      memset( ba_rjt, 0, sizeof( BA_RJT_PAYLOAD));
-
-      // We expect that a "target" task couldn't find the Exhange in the
-      // array of active exchanges, so we use a new LinkService X_ID.
-      // See Reject payload description in FC-PH (Rev 4.3), pg. 140
-      ba_rjt->reason_code = 0x09; // "unable to perform command request"
-      ba_rjt->reason_explain = 0x03; // invalid OX/RX ID pair
-
-
-      break;
-    
-    
-    case BLS_ABTS:   // FC defined basic link service command ABTS 
-                     // Abort Sequence
-                     
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 32L;        // add len to LSB (header only - no payload)
-
-                   // TYPE[31-24] 00 Basic Link Service
-                   // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
-      CMDfchs->d_id |= 0x81000000L;  // R_CTL = 81 for ABTS
-      CMDfchs->f_ctl = 0x00110000L;  // xchnge originator, last seq, xfer SI
-                   // CMDfchs->seq_id & count might be set from DataHdr?
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
-                        // (ABTS must timeout when responder is gone)
-      break;
-
-    
-    
-    case FCS_NSR:    // Fabric Name Service Request
-       Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
-
-
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
-                         // OX_ID, linked to Driver Transaction ID
-                         // (fix-up at Queing time)
-      CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
-                                    // OX_ID set at ERQueing time
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += (32L + sizeof(NSR_PL)); // add len (header & NSR payload)
-
-      CMDfchs->d_id |= 0x02000000L;  // R_CTL = 02 for -
-                                   // Name Service Request: Unsolicited 
-                   // TYPE[31-24] 01 Extended Link Service
-                   // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
-      CMDfchs->f_ctl = 0x20210000L;
-                   // OX_ID will be fixed-up at Tachyon enqueing time
-      CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-      BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
-
-   
-    
-    
-    
-    
-      break;
-    
-    
-    
-    
-    case ELS_PLOGI:  // FC-PH extended link service command Port Login
-      // (May, 2000)
-      // NOTE! This special case facilitates SANMark testing.  The SANMark
-      // test script for initialization-timeout.fcal.SANMark-1.fc
-      // "eats" the OPN() primitive without issuing an R_RDY, causing
-      // Tachyon to report LST (loop state timeout), which causes a
-      // LIP.  To avoid this, simply send out the frame (i.e. assuming a
-      // buffer credit of 1) without waiting for R_RDY.  Many FC devices
-      // (other than Tachyon) have been doing this for years.  We don't
-      // ever want to do this for non-Link Service frames unless the
-      // other device really did report non-zero login BB credit (i.e.
-      // in the PLOGI ACCept frame).
-//      CMDfchs->sof_eof |= 0x00000400L;  // LCr=1
-    
-    case ELS_FDISC:  // Fabric Discovery (Login)
-    case ELS_FLOGI:  // Fabric Login
-    case ELS_SCR:    // Fabric State Change Registration
-    case ELS_LOGO:   // FC-PH extended link service command Port Logout
-    case ELS_PDISC:  // FC-PH extended link service cmnd Port Discovery
-    case ELS_PRLI:   // FC-PH extended link service cmnd Process Login
-
-      Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
-
-
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
-                         // OX_ID, linked to Driver Transaction ID
-                         // (fix-up at Queing time)
-      CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
-                                    // OX_ID set at ERQueing time
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      if( type == ELS_LOGO )
-        SfsLen += (32L + 16L); //  add len (header & PLOGI payload)
-      else if( type == ELS_PRLI )
-        SfsLen += (32L + 20L); //  add len (header & PRLI payload)
-      else if( type == ELS_SCR )
-        SfsLen += (32L + sizeof(SCR_PL)); //  add len (header & SCR payload)
-      else
-        SfsLen += (32L + 116L); //  add len (header & PLOGI payload)
-
-      CMDfchs->d_id |= 0x22000000L;  // R_CTL = 22 for -
-                                   // Extended Link_Data: Unsolicited Control
-                   // TYPE[31-24] 01 Extended Link Service
-                   // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
-      CMDfchs->f_ctl = 0x01210000L;
-                   // OX_ID will be fixed-up at Tachyon enqueing time
-      CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-      BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
-
-      break;
-
-
-
-    case ELS_LOGO_ACC: // FC-PH extended link service logout accept
-    case ELS_RJT:          // extended link service reject (add reason)
-    case ELS_ACC:      // ext. link service generic accept
-    case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
-    case ELS_PRLI_ACC: // ext. link service process login accept
-
-
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // assume done
-                // ensure unique X_IDs! (use tracking function)
-                // OX_ID from initiator cmd
-      ox_ID = (USHORT)(InFCHS->ox_rx_id >> 16); 
-      rx_ID = 0xFFFF; // RX_ID, linked to Driver Exchange ID
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      if( type == ELS_RJT )
-      {
-        SfsLen += (32L + 8L); //  add len (header + payload)
-
-        // ELS_RJT reason codes (utilize unused "reserved" field)
-        CMDfchs->pl[0] = 1;
-        CMDfchs->pl[1] = InFCHS->reserved;  
-          
-      }
-      else if( (type == ELS_LOGO_ACC) || (type == ELS_ACC)  )
-        SfsLen += (32L + 4L); //  add len (header + payload)
-      else if( type == ELS_PLOGI_ACC )
-        SfsLen += (32L + 116L); //  add len (header + payload)
-      else if( type == ELS_PRLI_ACC )
-        SfsLen += (32L + 20L); //  add len (header + payload)
-
-      CMDfchs->d_id |= 0x23000000L;  // R_CTL = 23 for -
-                                   // Extended Link_Data: Control Reply
-                   // TYPE[31-24] 01 Extended Link Service
-                   // f_ctl[23:0] exchg responder, last seq, e_s, tsi
-      CMDfchs->f_ctl = 0x01990000L;
-      CMDfchs->seq_cnt = 0x0L;
-      CMDfchs->ox_rx_id = 0L;        // clear
-      CMDfchs->ox_rx_id = ox_ID; // load upper 16 bits
-      CMDfchs->ox_rx_id <<= 16;      // shift them
-
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-      BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
-
-      break;
-
-
-                         // Fibre Channel SCSI 'originator' sequences...
-                         // (originator means 'initiator' in FCP-SCSI)
-
-    case SCSI_IWE: // TachLite Initiator Write Entry
-    {
-      PFC_LOGGEDIN_PORT pLoggedInPort = 
-        Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort;
-
-      Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // FC2 timeout
-                       
-      // first, build FCP_CMND
-      // unique X_ID fix-ups in StartExchange 
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS FCP-CMND (not SEST index)
-
-      // NOTE: unlike FC LinkService login frames, normal
-      // SCSI commands are sent without outgoing verification
-      IRB_flags.DCM = 1;    // Disable completion message for Cmnd frame
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 64L;        // add len to LSB (header & CMND payload)
-
-      CMDfchs->d_id |= (0x06000000L);  // R_CTL = 6 for command
-
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
-                   //             valid RO
-      CMDfchs->f_ctl = 0x08210008L;
-      CMDfchs->seq_cnt = 0x0L;
-      CMDfchs->ox_rx_id = 0L;        // clear for now (-or- in later)
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-                   // now, fill out FCP-DATA header
-                   // (use buffer inside SEST object)
-      dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
-      dataHDR->reserved = 0L; // must clear
-      dataHDR->sof_eof = 0x75002000L;  // SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
-      dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
-      dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] xfer S.I.| valid RO
-      dataHDR->f_ctl = 0x08010008L;
-      dataHDR->seq_cnt = 0x02000000L;  // sequence ID: df_ctl : seqence count
-      dataHDR->ox_rx_id = 0L;        // clear; fix-up dataHDR fields later
-      dataHDR->ro = 0x0L;    // relative offset (n/a)
-
-                   // Now setup the SEST entry
-      pIWE = &fcChip->SEST->u[ *fcExchangeIndex ].IWE;
-      
-                   // fill out the IWE:
-
-                // VALid entry:Dir outbound:DCM:enable CM:enal INT: FC frame len
-      pIWE->Hdr_Len = 0x8e000020L; // data frame Len always 32 bytes
-      
-      
-      // from login parameters with other port, what's the largest frame
-      // we can send? 
-      if( pLoggedInPort == NULL) 
-      {
-       ulStatus = INVALID_ARGS;  // failed! give up
-       break;
-      }
-      if( pLoggedInPort->rx_data_size  >= 2048)
-        fl = 0x00020000;  // 2048 code (only support 1024!)
-      else if( pLoggedInPort->rx_data_size  >= 1024)
-        fl = 0x00020000;  // 1024 code
-      else if( pLoggedInPort->rx_data_size  >= 512)
-        fl = 0x00010000;  // 512 code
-      else
-       fl = 0;  // 128 bytes -- should never happen
-      
-      
-      pIWE->Hdr_Len |= fl; // add xmit FC frame len for data phase
-      pIWE->Hdr_Addr = fcChip->SEST->base + 
-               ((unsigned long)&fcChip->SEST->DataHDR[*fcExchangeIndex] - 
-                       (unsigned long)fcChip->SEST);
-
-      pIWE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
-      pIWE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
-      
-      memset( &fcChip->SEST->RspHDR[ *fcExchangeIndex].pl, 0, 
-        sizeof( FCP_STATUS_RESPONSE) );  // clear out previous status
-      pIWE->RSP_Addr = fcChip->SEST->base + 
-               ((unsigned long)&fcChip->SEST->RspHDR[*fcExchangeIndex] - 
-                       (unsigned long)fcChip->SEST);
-
-                   // Do we need local or extended gather list?
-                   // depends on size - we can handle 3 len/addr pairs
-                   // locally.
-
-      fcp_dl = build_SEST_sgList( 
-       cpqfcHBAdata->PciDev,
-        &pIWE->GLen1, 
-        Cmnd,       // S/G list
-        &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
-        &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
-
-      if( !fcp_dl ) // error building S/G list?
-      {
-        ulStatus = MEMPOOL_FAIL;
-        break;      // give up
-      }
-
-                             // Now that we know total data length in
-                             // the passed S/G buffer, set FCP CMND frame
-      build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
-
-
-      
-      if( sgPairs > 3 )  // need extended s/g list
-        pIWE->Buff_Off = 0x78000000L; // extended data | (no offset)
-      else               // local data pointers (in SEST)
-        pIWE->Buff_Off = 0xf8000000L; // local data | (no offset)
-
-                              // ULONG 5
-      pIWE->Link = 0x0000ffffL;   // Buff_Index | Link
-
-      pIWE->RX_ID = 0x0L;     // DWord 6: RX_ID set by target XFER_RDY
-
-                                      // DWord 7
-      pIWE->Data_Len = 0L;    // TL enters rcv'd XFER_RDY BURST_LEN
-      pIWE->Exp_RO = 0L;      // DWord 8
-                              // DWord 9
-      pIWE->Exp_Byte_Cnt = fcp_dl;  // sum of gather buffers
-    }
-    break;
-
-
-
-
-
-    case SCSI_IRE: // TachLite Initiator Read Entry
-
-      if( Cmnd->timeout != 0)
-      {
-//     printk("Cmnd->timeout %d\n", Cmnd->timeout);
-       // per Linux Scsi
-        Exchanges->fcExchange[ *fcExchangeIndex].timeOut = Cmnd->timeout;
-      }
-      else  // use our best guess, based on FC & device
-      {
-
-        if( Cmnd->SCp.Message == 1 ) // Tape device? (from INQUIRY)    
-       {
-         // turn off our timeouts (for now...)
-          Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 0xFFFFFFFF; 
-       }
-       else
-       {
-          Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
-          Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // per SCSI req.
-       }
-      }
-
-  
-      // first, build FCP_CMND
-
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS FCP-CMND (not SEST index)
-                            // NOTE: unlike FC LinkService login frames,
-                            // normal SCSI commands are sent "open loop"
-      IRB_flags.DCM = 1;    // Disable completion message for Cmnd frame
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 64L;        // add len to LSB (header & CMND payload)
-
-      CMDfchs->d_id |= (0x06000000L);  // R_CTL = 6 for command
-
-             // TYPE[31-24] 8 for FCP SCSI
-             // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
-             //             valid RO
-      CMDfchs->f_ctl = 0x08210008L;
-      CMDfchs->seq_cnt = 0x0L;
-      // x_ID & data direction bit set later
-      CMDfchs->ox_rx_id = 0xFFFF;        // clear
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-
-
-                   // Now setup the SEST entry
-      pIRE = &fcChip->SEST->u[ *fcExchangeIndex ].IRE;
-
-      // fill out the IRE:
-      // VALid entry:Dir outbound:enable CM:enal INT:
-      pIRE->Seq_Accum = 0xCE000000L; // VAL,DIR inbound,DCM| INI,DAT,RSP
-
-      pIRE->reserved = 0L;
-      pIRE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
-      pIRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
-
-      pIRE->RSP_Addr = fcChip->SEST->base + 
-               ((unsigned long)&fcChip->SEST->RspHDR[*fcExchangeIndex] - 
-                       (unsigned long)fcChip->SEST);
-      
-                   // Do we need local or extended gather list?
-                   // depends on size - we can handle 3 len/addr pairs
-                   // locally.
-
-      fcp_dl = build_SEST_sgList( 
-       cpqfcHBAdata->PciDev,
-        &pIRE->SLen1, 
-        Cmnd,       // SCSI command Data desc. with S/G list
-        &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
-        &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
-      
-      
-      if( !fcp_dl ) // error building S/G list?
-      {
-       // It is permissible to have a ZERO LENGTH Read command.
-       // If there is the case, simply set fcp_dl (and Exp_Byte_Cnt)
-       // to 0 and continue.
-       if( Cmnd->request_bufflen == 0 )
-       {
-         fcp_dl = 0; // no FC DATA frames expected
-
-       }
-       else
-       {
-          ulStatus = MEMPOOL_FAIL;
-          break;      // give up
-       }
-      }
-
-      // now that we know the S/G length, build CMND payload
-      build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
-
-      
-      if( sgPairs > 3 )  // need extended s/g list
-        pIRE->Buff_Off = 0x00000000; // DWord 4: extended s/g list, no offset
-      else
-        pIRE->Buff_Off = 0x80000000; // local data, no offset
-      
-      pIRE->Buff_Index = 0x0L;    // DWord 5: Buff_Index | Reserved
-
-      pIRE->Exp_RO  = 0x0L;       // DWord 6: Expected Rel. Offset
-
-      pIRE->Byte_Count = 0;  // DWord 7: filled in by TL on err
-      pIRE->reserved_ = 0;   // DWord 8: reserved
-                             // NOTE: 0 length READ is OK.
-      pIRE->Exp_Byte_Cnt = fcp_dl;// DWord 9: sum of scatter buffers
-      
-      break;
-
-
-
-
-                         // Fibre Channel SCSI 'responder' sequences...
-                         // (originator means 'target' in FCP-SCSI)
-    case SCSI_TWE: // TachLite Target Write Entry
-
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
-
-                       // first, build FCP_CMND
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (XFER_RDY)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
-
-      CMDfchs->d_id |= (0x05000000L);  // R_CTL = 5 for XFER_RDY
-
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] exchg responder, 1st seq, xfer S.I.
-                //             valid RO
-      CMDfchs->f_ctl = 0x08810008L;
-      CMDfchs->seq_cnt = 0x01000000; // sequence ID: df_ctl: sequence count
-                       // use originator (other port's) OX_ID
-      CMDfchs->ox_rx_id = InFCHS->ox_rx_id;     // we want upper 16 bits
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-                   // now, fill out FCP-RSP header
-                   // (use buffer inside SEST object)
-
-      rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
-      rspHDR->reserved = 0L; // must clear
-      rspHDR->sof_eof = 0x75000000L;  // SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
-      rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
-      rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] responder|last seq| xfer S.I.
-      rspHDR->f_ctl = 0x08910000L;
-      rspHDR->seq_cnt = 0x03000000;  // sequence ID
-      rspHDR->ox_rx_id = InFCHS->ox_rx_id; // gives us OX_ID
-      rspHDR->ro = 0x0L;    // relative offset (n/a)
-
-
-                   // Now setup the SEST entry
-                   
-      pTWE = &fcChip->SEST->u[ *fcExchangeIndex ].TWE;
-
-      // fill out the TWE:
-
-      // VALid entry:Dir outbound:enable CM:enal INT:
-      pTWE->Seq_Accum = 0xC4000000L;  // upper word flags
-      pTWE->reserved = 0L;
-      pTWE->Remote_Node_ID = 0L; // no more auto RSP frame! (TL/TS change)
-      pTWE->Remote_Node_ID |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
-      
-
-                   // Do we need local or extended gather list?
-                   // depends on size - we can handle 3 len/addr pairs
-                   // locally.
-
-      fcp_dl = build_SEST_sgList( 
-       cpqfcHBAdata->PciDev,
-        &pTWE->SLen1, 
-        Cmnd,       // S/G list
-        &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
-        &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
-      
-      
-      if( !fcp_dl ) // error building S/G list?
-      {
-        ulStatus = MEMPOOL_FAIL;
-        break;      // give up
-      }
-
-      // now that we know the S/G length, build CMND payload
-      build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
-
-      
-      if( sgPairs > 3 )  // need extended s/g list
-        pTWE->Buff_Off = 0x00000000; // extended s/g list, no offset
-      else
-        pTWE->Buff_Off = 0x80000000; // local data, no offset
-      
-      pTWE->Buff_Index = 0;     // Buff_Index | Link
-      pTWE->Exp_RO = 0;
-      pTWE->Byte_Count = 0;  // filled in by TL on err
-      pTWE->reserved_ = 0;
-      pTWE->Exp_Byte_Cnt = fcp_dl;// sum of scatter buffers
-      
-      break;
-
-
-
-
-
-
-    case SCSI_TRE: // TachLite Target Read Entry
-
-      // It doesn't make much sense for us to "time-out" a READ,
-      // but we'll use it for design consistency and internal error recovery.
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
-
-      // I/O request block settings...
-      *pIRB_flags = 0;      // clear IRB flags
-                                  // check PRLI (process login) info
-                                  // to see if Initiator Requires XFER_RDY
-                                  // if not, don't send one!
-                                  // { PRLI check...}
-      IRB_flags.SFA = 0;    // don't send XFER_RDY - start data
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
-
-
-      
-      // now, fill out FCP-DATA header
-                   // (use buffer inside SEST object)
-      dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
-
-      dataHDR->reserved = 0L; // must clear
-      dataHDR->sof_eof = 0x75000000L;  // SOFi3:EOFn no UAM; no CLS,noLCr,no TS
-      dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
-      dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
-
-
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] exchg responder, not 1st seq, xfer S.I.
-                   //             valid RO
-      dataHDR->f_ctl = 0x08810008L;
-      dataHDR->seq_cnt = 0x01000000;  // sequence ID (no XRDY)
-      dataHDR->ox_rx_id = InFCHS->ox_rx_id & 0xFFFF0000; // we want upper 16 bits
-      dataHDR->ro = 0x0L;    // relative offset (n/a)
-
-                   // now, fill out FCP-RSP header
-                   // (use buffer inside SEST object)
-      rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
-
-      rspHDR->reserved = 0L; // must clear
-      rspHDR->sof_eof = 0x75000000L;  // SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
-      rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
-      rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] responder|last seq| xfer S.I.
-      rspHDR->f_ctl = 0x08910000L;
-      rspHDR->seq_cnt = 0x02000000;  // sequence ID: df_ctl: sequence count
-
-      rspHDR->ro = 0x0L;    // relative offset (n/a)
-
-
-      // Now setup the SEST entry
-      pTRE = &fcChip->SEST->u[ *fcExchangeIndex ].TRE;
-
-
-      // VALid entry:Dir outbound:enable CM:enal INT:
-      pTRE->Hdr_Len = 0x86010020L; // data frame Len always 32 bytes
-      pTRE->Hdr_Addr =  // bus address of dataHDR;
-            fcChip->SEST->base + 
-               ((unsigned long)&fcChip->SEST->DataHDR[ *fcExchangeIndex ] -
-                       (unsigned long)fcChip->SEST);
-       
-      pTRE->RSP_Len = 64L; // hdr+data (TL assisted RSP frame)
-      pTRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
-      pTRE->RSP_Addr = // bus address of rspHDR
-               fcChip->SEST->base + 
-                       ((unsigned long)&fcChip->SEST->RspHDR[ *fcExchangeIndex ] -
-                               (unsigned long)fcChip->SEST);
-
-                   // Do we need local or extended gather list?
-                   // depends on size - we can handle 3 len/addr pairs
-                   // locally.
-
-      fcp_dl = build_SEST_sgList( 
-       cpqfcHBAdata->PciDev,
-        &pTRE->GLen1, 
-        Cmnd,       // S/G list
-        &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
-        &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
-      
-      
-      if( !fcp_dl ) // error building S/G list?
-      {
-        ulStatus = MEMPOOL_FAIL;
-        break;      // give up
-      }
-
-      // no payload or command to build -- READ doesn't need XRDY
-
-      
-      if( sgPairs > 3 )  // need extended s/g list
-        pTRE->Buff_Off = 0x78000000L; // extended data | (no offset)
-      else               // local data pointers (in SEST)
-        pTRE->Buff_Off = 0xf8000000L; // local data | (no offset)
-
-                                            // ULONG 5
-      pTRE->Buff_Index = 0L;   // Buff_Index | reserved
-      pTRE->reserved = 0x0L;   // DWord 6
-
-                                     // DWord 7: NOTE: zero length will
-                                     // hang TachLite!
-      pTRE->Data_Len = fcp_dl; // e.g. sum of scatter buffers
-
-      pTRE->reserved_ = 0L;     // DWord 8
-      pTRE->reserved__ = 0L;    // DWord 9
-
-      break;
-
-
-
-
-
-    
-
-    case FCP_RESPONSE: 
-                  // Target response frame: this sequence uses an OX/RX ID
-                  // pair from a completed SEST exchange.  We built most
-                  // of the response frame when we created the TWE/TRE.
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (RSP)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += sizeof(TachFCHDR_RSP);// add SFS len (header & RSP payload)
-      
-
-      Exchanges->fcExchange[ *fcExchangeIndex].type = 
-        FCP_RESPONSE; // change Exchange type to "response" phase
-
-      // take advantage of prior knowledge of OX/RX_ID pair from
-      // previous XFER outbound frame (still in fchs of exchange)
-      fcChip->SEST->RspHDR[ *fcExchangeIndex ].ox_rx_id = 
-        CMDfchs->ox_rx_id;
-
-      // Check the status of the DATA phase of the exchange so we can report
-      // status to the initiator
-      buildFCPstatus( fcChip, *fcExchangeIndex); // set RSP payload fields
-
-      memcpy(
-        CMDfchs,  // re-use same XFER fchs for Response frame
-        &fcChip->SEST->RspHDR[ *fcExchangeIndex ],
-        sizeof( TachFCHDR_RSP ));
-      
-        
-      break;
-
-    default:
-      printk("cpqfcTS: don't know how to build FC type: %Xh(%d)\n", type,type);
-      break;
-
-    }
-
-    
-    
-    if( !ulStatus)  // no errors above?
-    {
-      // FCHS is built; now build IRB
-
-      // link the just built FCHS (the "command") to the IRB entry 
-      // for this Exchange.
-      pIRB = &Exchanges->fcExchange[ *fcExchangeIndex].IRB; 
-    
-                          // len & flags according to command type above
-      pIRB->Req_A_SFS_Len = SfsLen;  // includes IRB flags & len
-      pIRB->Req_A_SFS_Addr = // TL needs physical addr of frame to send
-               fcChip->exch_dma_handle + (unsigned long)CMDfchs - 
-                       (unsigned long)Exchanges;
-
-      pIRB->Req_A_SFS_D_ID = CMDfchs->d_id << 8; // Dest_ID must be consistent!
-
-    // Exchange is complete except for "fix-up" fields to be set
-    // at Tachyon Queuing time:
-    //    IRB->Req_A_Trans_ID (OX_ID/ RX_ID):  
-    //        for SEST entry, lower bits correspond to actual FC Exchange ID
-    //    fchs->OX_ID or RX_ID
-    }
-    else
-    {
-#ifdef DBG     
-      printk( "FC Error: SEST build Pool Allocation failed\n");
-#endif
-      // return resources...
-      cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, *fcExchangeIndex);  // SEST build failed
-    }
-  }
-  else  // no Exchanges available
-  {
-    ulStatus = SEST_FULL;
-    printk( "FC Error: no fcExchanges available\n");
-  }
-  return ulStatus;
-}
-
-
-
-
-
-
-// set RSP payload fields
-static void  buildFCPstatus( PTACHYON fcChip, ULONG ExchangeID) 
-{
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ExchangeID];  // shorthand
-  PFCP_STATUS_RESPONSE pFcpStatus;
-  
-  memset( &fcChip->SEST->RspHDR[ ExchangeID ].pl, 0,
-    sizeof( FCP_STATUS_RESPONSE) );
-  if( pExchange->status ) // something wrong?
-  {
-    pFcpStatus = (PFCP_STATUS_RESPONSE)  // cast RSP buffer for this xchng
-      &fcChip->SEST->RspHDR[ ExchangeID ].pl;
-    if( pExchange->status & COUNT_ERROR )
-    {
-      
-      // set FCP response len valid (so we can report count error)
-      pFcpStatus->fcp_status |= FCP_RSP_LEN_VALID;
-      pFcpStatus->fcp_rsp_len = 0x04000000;  // 4 byte len (BIG Endian)
-
-      pFcpStatus->fcp_rsp_info = FCP_DATA_LEN_NOT_BURST_LEN; // RSP_CODE
-    }
-  }
-}
-
-
-static dma_addr_t 
-cpqfc_pci_map_sg_page(
-               struct pci_dev *pcidev,
-               ULONG *hw_paddr,        // where to put phys addr for HW use
-               void *sgp_vaddr,        // the virtual address of the sg page 
-               dma_addr_t *umap_paddr, // where to put phys addr for unmap
-               unsigned int *maplen,   // where to store sg entry length
-               int PairCount)          // number of sg pairs used in the page. 
-{
-       unsigned long aligned_addr = (unsigned long) sgp_vaddr;
-
-       *maplen = PairCount * 8;
-        aligned_addr += TL_EXT_SG_PAGE_BYTELEN;
-        aligned_addr &= ~(TL_EXT_SG_PAGE_BYTELEN -1);
-       
-       *umap_paddr = pci_map_single(pcidev, (void *) aligned_addr, 
-                               *maplen, PCI_DMA_TODEVICE);
-       *hw_paddr = (ULONG) *umap_paddr;
-
-#       if BITS_PER_LONG > 32
-                       if( *umap_paddr >>32 ) {
-                               printk("cqpfcTS:Tach SG DMA addr %p>32 bits\n", 
-                               (void*)umap_paddr);
-                               return 0;
-                       }
-#       endif
-       return *umap_paddr;
-}
-
-static void
-cpqfc_undo_SEST_mappings(struct pci_dev *pcidev,
-                       unsigned long contigaddr, int len, int dir,
-                       struct scatterlist *sgl, int use_sg,
-                       PSGPAGES *sgPages_head,
-                       int allocated_pages)
-{
-       PSGPAGES i, next;
-
-       if (contigaddr != (unsigned long) NULL)
-               pci_unmap_single(pcidev, contigaddr, len, dir);
-
-       if (sgl != NULL)
-               pci_unmap_sg(pcidev, sgl, use_sg, dir);
-
-       for (i=*sgPages_head; i != NULL ;i = next)
-       {
-               pci_unmap_single(pcidev, i->busaddr, i->maplen, 
-                       PCI_DMA_TODEVICE);
-               i->busaddr = (dma_addr_t) NULL; 
-               i->maplen = 0L; 
-               next = i->next;
-               kfree(i); 
-       }
-       *sgPages_head = NULL;
-}
-
-// This routine builds scatter/gather lists into SEST entries
-// INPUTS:
-//   SESTalPair - SEST address @DWordA "Local Buffer Length"
-//   sgList     - Scatter/Gather linked list of Len/Address data buffers
-// OUTPUT:
-//   sgPairs - number of valid address/length pairs
-// Remarks:
-//   The SEST data buffer pointers only depend on number of
-//   length/ address pairs, NOT on the type (IWE, TRE,...)
-//   Up to 3 pairs can be referenced in the SEST - more than 3
-//   require this Extended S/G list page.  The page holds 4, 8, 16...
-//   len/addr pairs, per Scatter/Gather List Page Length Reg.
-//   TachLite allows pages to be linked to any depth.
-
-//#define DBG_SEST_SGLIST 1 // for printing out S/G pairs with Ext. pages
-
-static int ap_hi_water = TL_DANGER_SGPAGES;
-
-static ULONG build_SEST_sgList( 
-    struct pci_dev *pcidev,
-    ULONG *SESTalPairStart,  // the 3 len/address buffers in SEST
-    Scsi_Cmnd *Cmnd,
-    ULONG *sgPairs, 
-    PSGPAGES *sgPages_head)  // link list of TL Ext. S/G pages from O/S Pool
-    
-{
-  ULONG i, AllocatedPages=0; // Tach Ext. S/G page allocations
-  ULONG* alPair = SESTalPairStart;
-  ULONG* ext_sg_page_phys_addr_place = NULL;
-  int PairCount;
-  unsigned long ulBuff, contigaddr;
-  ULONG total_data_len=0; // (in bytes)
-  ULONG bytes_to_go = Cmnd->request_bufflen; // total xfer (S/G sum)
-  ULONG thisMappingLen;
-  struct scatterlist *sgl = NULL;  // S/G list (Linux format)
-  int sg_count, totalsgs; 
-  dma_addr_t busaddr;
-  unsigned long thislen, offset;
-  PSGPAGES *sgpage = sgPages_head;
-  PSGPAGES prev_page = NULL;
-
-# define WE_HAVE_SG_LIST (sgl != (unsigned long) NULL)
-  contigaddr = (unsigned long) NULL;
-
-  if( !Cmnd->use_sg )  // no S/G list?
-  {
-       if (bytes_to_go <= TL_MAX_SG_ELEM_LEN)
-       {
-               *sgPairs = 1;   // use "local" S/G pair in SEST entry
-                               // (for now, ignore address bits above #31)
-
-               *alPair++ = bytes_to_go; // bits 18-0, length
-
-               if (bytes_to_go != 0) {
-                       contigaddr = ulBuff = pci_map_single(pcidev, 
-                               Cmnd->request_buffer, 
-                               Cmnd->request_bufflen,
-                               Cmnd->sc_data_direction);
-                       // printk("ms %p ", ulBuff);
-               }
-               else {
-                       // No data transfer, (e.g.: Test Unit Ready)
-                       // printk("btg=0 ");
-                       *sgPairs = 0;
-                       memset(alPair, 0, sizeof(*alPair));
-                       return 0;
-               }
-
-#              if BITS_PER_LONG > 32
-                       if( ulBuff >>32 ) {
-                               printk("FATAL! Tachyon DMA address %p "
-                                       "exceeds 32 bits\n", (void*)ulBuff );
-                               return 0;
-                       }
-#              endif
-               *alPair = (ULONG)ulBuff;      
-               return bytes_to_go;
-       } 
-       else    // We have a single large (too big) contiguous buffer.
-       {       // We will have to break it up.  We'll use the scatter
-               // gather code way below, but use contigaddr instead
-               // of sg_dma_addr(). (this is a very rare case).
-
-               unsigned long btg;
-               contigaddr = pci_map_single(pcidev, Cmnd->request_buffer, 
-                               Cmnd->request_bufflen,
-                               Cmnd->sc_data_direction);
-
-               // printk("contigaddr = %p, len = %d\n", 
-               //      (void *) contigaddr, bytes_to_go);
-               totalsgs = 0;
-               for (btg = bytes_to_go; btg > 0; ) {
-                       btg -= ( btg > TL_MAX_SG_ELEM_LEN ? 
-                               TL_MAX_SG_ELEM_LEN : btg );
-                       totalsgs++;
-               }
-               sgl = NULL;
-               *sgPairs = totalsgs;
-       }
-  }
-  else  // we do have a scatter gather list
-  {
-       // [TBD - update for Linux to support > 32 bits addressing]
-       // since the format for local & extended S/G lists is different,
-       // check if S/G pairs exceeds 3.
-       // *sgPairs = Cmnd->use_sg; Nope, that's wrong.
-       sgl = (struct scatterlist*)Cmnd->request_buffer;  
-       sg_count = pci_map_sg(pcidev, sgl, Cmnd->use_sg, 
-               Cmnd->sc_data_direction);
-       if( sg_count <= 3 ) {
-
-       // we need to be careful here that no individual mapping
-       // is too large, and if any is, that breaking it up
-       // doesn't push us over 3 sgs, or, if it does, that we
-       // handle that case.  Tachyon can take 0x7FFFF bits for length,
-       // but sg structure uses "unsigned int", on the face of it, 
-       // up to 0xFFFFFFFF or even more.
-
-               int i;
-               unsigned long thislen;
-
-               totalsgs = 0;
-               for (i=0;i<sg_count;i++) {
-                       thislen = sg_dma_len(&sgl[i]);
-                       while (thislen >= TL_MAX_SG_ELEM_LEN) {
-                               totalsgs++;
-                               thislen -= TL_MAX_SG_ELEM_LEN;
-                       }
-                       if (thislen > 0) totalsgs++;
-               }
-               *sgPairs = totalsgs;
-       } else totalsgs = 999; // as a first estimate, definitely >3, 
-                             
-       // if (totalsgs != sg_count) 
-       //      printk("totalsgs = %d, sgcount=%d\n",totalsgs,sg_count);
-  }
-
-  if( totalsgs <= 3 ) // can (must) use "local" SEST list
-  {
-    while( bytes_to_go)
-    {
-      offset = 0L;
-
-      if ( WE_HAVE_SG_LIST ) 
-       thisMappingLen = sg_dma_len(sgl);
-      else                                     // or contiguous buffer?
-       thisMappingLen = bytes_to_go;
-
-      while (thisMappingLen > 0)
-      {  
-       thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ? 
-               TL_MAX_SG_ELEM_LEN : thisMappingLen;
-       bytes_to_go = bytes_to_go - thislen;
-
-       // we have L/A pair; L = thislen, A = physicalAddress
-       // load into SEST...
-
-       total_data_len += thislen;
-       *alPair = thislen; // bits 18-0, length
-
-       alPair++;
-
-       if ( WE_HAVE_SG_LIST ) 
-               ulBuff = sg_dma_address(sgl) + offset;
-       else
-               ulBuff = contigaddr + offset;
-
-       offset += thislen;
-
-#      if BITS_PER_LONG > 32
-               if( ulBuff >>32 ) {
-                       printk("cqpfcTS: 2Tach DMA address %p > 32 bits\n", 
-                               (void*)ulBuff );
-                   printk("%s = %p, offset = %ld\n", 
-                       WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr",
-                       WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr,
-                               offset);
-                       return 0;
-               }
-#      endif
-        *alPair++ = (ULONG)ulBuff; // lower 32 bits (31-0)
-       thisMappingLen -= thislen;
-      }
-
-      if ( WE_HAVE_SG_LIST ) ++sgl;  // next S/G pair
-       else if (bytes_to_go != 0) printk("BTG not zero!\n");
-
-#     ifdef DBG_SEST_SGLIST
-       printk("L=%d ", thisMappingLen);
-       printk("btg=%d ", bytes_to_go);
-#     endif
-
-    }
-    // printk("i:%d\n", *sgPairs);
-  }
-  else    // more than 3 pairs requires Extended S/G page (Pool Allocation)
-  {
-    // clear out SEST DWORDs (local S/G addr) C-F (A-B set in following logic)
-    for( i=2; i<6; i++)
-      alPair[i] = 0;
-
-    PairCount = TL_EXT_SG_PAGE_COUNT;    // forces initial page allocation
-    totalsgs = 0;
-    while( bytes_to_go )
-    {
-      // Per SEST format, we can support 524287 byte lengths per
-      // S/G pair.  Typical user buffers are 4k, and very rarely
-      // exceed 12k due to fragmentation of physical memory pages.
-      // However, on certain O/S system (not "user") buffers (on platforms 
-      // with huge memories), it's possible to exceed this
-      // length in a single S/G address/len mapping, so we have to handle
-      // that.
-
-      offset = 0L;
-      if ( WE_HAVE_SG_LIST ) 
-       thisMappingLen = sg_dma_len(sgl);
-      else
-       thisMappingLen = bytes_to_go;
-
-      while (thisMappingLen > 0)
-      {
-       thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ? 
-               TL_MAX_SG_ELEM_LEN : thisMappingLen;
-       // printk("%d/%d/%d\n", thislen, thisMappingLen, bytes_to_go);
-      
-       // should we load into "this" extended S/G page, or allocate
-       // new page?
-
-       if( PairCount >= TL_EXT_SG_PAGE_COUNT )
-       {
-         // Now, we have to map the previous page, (triggering buffer bounce)
-         // The first time thru the loop, there won't be a previous page.
-         if (prev_page != NULL) // is there a prev page? 
-         {
-               // this code is normally kind of hard to trigger, 
-               // you have to use up more than 256 scatter gather 
-               // elements to get here.  Cranking down TL_MAX_SG_ELEM_LEN
-               // to an absurdly low value (128 bytes or so) to artificially
-               // break i/o's into a zillion pieces is how I tested it. 
-               busaddr = cpqfc_pci_map_sg_page(pcidev,
-                               ext_sg_page_phys_addr_place,
-                               prev_page->page,
-                               &prev_page->busaddr,
-                               &prev_page->maplen,
-                               PairCount);
-          } 
-          // Allocate the TL Extended S/G list page.  We have
-          // to allocate twice what we want to ensure required TL alignment
-          // (Tachlite TL/TS User Man. Rev 6.0, p 168)
-          // We store the original allocated PVOID so we can free later
-         *sgpage = kmalloc( sizeof(SGPAGES), GFP_ATOMIC);
-         if ( ! *sgpage )
-          {
-               printk("cpqfc: Allocation failed @ %d S/G page allocations\n",
-                       AllocatedPages);
-               total_data_len = 0;  // failure!! Ext. S/G is All-or-none affair
-
-               // unmap the previous mappings, if any.
-
-               cpqfc_undo_SEST_mappings(pcidev, contigaddr, 
-                       Cmnd->request_bufflen,
-                       Cmnd->sc_data_direction,
-                       sgl, Cmnd->use_sg, sgPages_head, AllocatedPages+1);
-
-               // FIXME: testing shows that if we get here, 
-               // it's bad news.  (this has been this way for a long 
-               // time though, AFAIK.  Not that that excuses it.)
-
-               return 0; // give up (and probably hang the system)
-          }
-                               // clear out memory we just allocated
-         memset( (*sgpage)->page,0,TL_EXT_SG_PAGE_BYTELEN*2);
-         (*sgpage)->next = NULL;
-         (*sgpage)->busaddr = (dma_addr_t) NULL;
-         (*sgpage)->maplen = 0L;
-      
-         // align the memory - TL requires sizeof() Ext. S/G page alignment.
-         // We doubled the actual required size so we could mask off LSBs 
-         // to get desired offset 
-
-         ulBuff = (unsigned long) (*sgpage)->page;
-         ulBuff += TL_EXT_SG_PAGE_BYTELEN;
-         ulBuff &= ~(TL_EXT_SG_PAGE_BYTELEN -1);
-
-         // set pointer, in SEST if first Ext. S/G page, or in last pair
-         // of linked Ext. S/G pages... (Only 32-bit PVOIDs, so just 
-         // load lower 32 bits)
-         // NOTE: the Len field must be '0' if this is the first Ext. S/G
-         // pointer in SEST, and not 0 otherwise (we know thislen != 0).
-
-         *alPair = (alPair != SESTalPairStart) ? thislen : 0;
-
-#        ifdef DBG_SEST_SGLIST
-               printk("PairCount %d @%p even %Xh, ", 
-                       PairCount, alPair, *alPair);
-#        endif
-
-         // Save the place where we need to store the physical
-         // address of this scatter gather page which we get when we map it
-         // (and mapping we can do only after we fill it in.)
-         alPair++;  // next DWORD, will contain phys addr of the ext page
-         ext_sg_page_phys_addr_place = alPair;
-
-         // Now, set alPair = the virtual addr of the (Extended) S/G page
-         // which will accept the Len/ PhysicalAddress pairs
-         alPair = (ULONG *) ulBuff;
-
-         AllocatedPages++;
-         if (AllocatedPages >= ap_hi_water)
-         {
-               // This message should rarely, if ever, come out.
-               // Previously (cpqfc version <= 2.0.5) the driver would
-               // just puke if more than 4 SG pages were used, and nobody
-               // ever complained about that.  This only comes out if 
-               // more than 8 pages are used.
-
-               printk(KERN_WARNING
-               "cpqfc: Possible danger.  %d scatter gather pages used.\n"
-                       "cpqfc: detected seemingly extreme memory "
-                       "fragmentation or huge data transfers.\n", 
-                       AllocatedPages);
-               ap_hi_water = AllocatedPages+1;
-         }
-               
-         PairCount = 1;  // starting new Ext. S/G page
-         prev_page = (*sgpage);  // remember this page, for next time thru
-         sgpage = &((*sgpage)->next);
-       }  // end of new TL Ext. S/G page allocation
-
-       *alPair = thislen; // bits 18-0, length (range check above)
-      
-#      ifdef DBG_SEST_SGLIST
-         printk("PairCount %d @%p, even %Xh, ", PairCount, alPair, *alPair);
-#      endif
-
-       alPair++;    // next DWORD, physical address 
-
-       if ( WE_HAVE_SG_LIST ) 
-               ulBuff = sg_dma_address(sgl) + offset;
-       else
-               ulBuff = contigaddr + offset;
-       offset += thislen;
-
-#      if BITS_PER_LONG > 32
-          if( ulBuff >>32 )
-         {
-           printk("cqpfcTS: 1Tach DMA address %p > 32 bits\n", (void*)ulBuff );
-           printk("%s = %p, offset = %ld\n", 
-               WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr",
-               WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr,
-                       offset);
-           return 0;
-         }
-#      endif
-
-       *alPair = (ULONG) ulBuff; // lower 32 bits (31-0)
-
-#       ifdef DBG_SEST_SGLIST
-        printk("odd %Xh\n", *alPair);
-#       endif
-       alPair++;    // next DWORD, next address/length pair
-                                           
-       PairCount++; // next Length/Address pair
-
-       // if (PairCount > pc_hi_water)
-       // {
-               // printk("pc hi = %d ", PairCount);
-               // pc_hi_water = PairCount;
-       // }
-       bytes_to_go -= thislen;
-       total_data_len += thislen;  
-       thisMappingLen -= thislen;
-       totalsgs++;
-      } // while (thisMappingLen > 0)
-      if ( WE_HAVE_SG_LIST ) sgl++;  // next S/G pair
-    } // while (bytes_to_go)
-
-    // printk("Totalsgs=%d\n", totalsgs);
-    *sgPairs = totalsgs;
-
-    // PCI map (and bounce) the last (and usually only) extended SG page
-    busaddr = cpqfc_pci_map_sg_page(pcidev,
-               ext_sg_page_phys_addr_place,
-               prev_page->page, 
-               &prev_page->busaddr, 
-               &prev_page->maplen,
-               PairCount);
-  }
-  return total_data_len;
-}
-
-
-
-// The Tachlite SEST table is referenced to OX_ID (or RX_ID).  To optimize
-// performance and debuggability, we index the Exchange structure to FC X_ID
-// This enables us to build exchanges for later en-queing to Tachyon,
-// provided we have an open X_ID slot. At Tachyon queing time, we only 
-// need an ERQ slot; then "fix-up" references in the 
-// IRB, FCHS, etc. as needed.
-// RETURNS:
-// 0 if successful
-// non-zero on error
-//sstartex
-ULONG cpqfcTSStartExchange( 
-  CPQFCHBA *cpqfcHBAdata,                      
-  LONG ExchangeID )
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ ExchangeID ]; // shorthand
-  USHORT producer, consumer;
-  ULONG ulStatus=0;
-  short int ErqIndex;
-  BOOLEAN CompleteExchange = FALSE;  // e.g. ACC replies are complete
-  BOOLEAN SestType=FALSE;
-  ULONG InboundData=0;
-
-  // We will manipulate Tachlite chip registers here to successfully
-  // start exchanges. 
-
-  // Check that link is not down -- we can't start an exchange on a
-  // down link!
-
-  if( fcChip->Registers.FMstatus.value & 0x80) // LPSM offline?
-  {
-printk("fcStartExchange: PSM offline (%Xh), x_ID %Xh, type %Xh, port_id %Xh\n",
-         fcChip->Registers.FMstatus.value & 0xFF,
-         ExchangeID,
-         pExchange->type,
-         pExchange->fchs.d_id);
-
-    if( ExchangeID >= TACH_SEST_LEN )  // Link Service Outbound frame?
-    {
-      // Our most popular LinkService commands are port discovery types
-      // (PLOGI/ PDISC...), which are implicitly nullified by Link Down
-      // events, so it makes no sense to Que them.  However, ABTS should
-      // be queued, since exchange sequences are likely destroyed by
-      // Link Down events, and we want to notify other ports of broken
-      // sequences by aborting the corresponding exchanges.
-      if( pExchange->type != BLS_ABTS )
-      {
-       ulStatus = LNKDWN_OSLS;
-       goto Done;
-        // don't Que most LinkServ exchanges on LINK DOWN
-      }
-    }
-
-    printk("fcStartExchange: Que x_ID %Xh, type %Xh\n", 
-      ExchangeID, pExchange->type);
-    pExchange->status |= EXCHANGE_QUEUED;
-    ulStatus = EXCHANGE_QUEUED;
-    goto Done;
-  }
-
-  // Make sure ERQ has available space.
-  
-  producer = (USHORT)fcChip->ERQ->producerIndex; // copies for logical arith.
-  consumer = (USHORT)fcChip->ERQ->consumerIndex;
-  producer++;  // We are testing for full que by incrementing
-  
-  if( producer >= ERQ_LEN )  // rollover condition?
-    producer = 0;
-  if( consumer != producer ) // ERQ not full?
-  {
-    // ****************** Need Atomic access to chip registers!!********
-    
-    // remember ERQ PI for copying IRB
-    ErqIndex = (USHORT)fcChip->ERQ->producerIndex; 
-    fcChip->ERQ->producerIndex = producer; // this is written to Tachyon
-               // we have an ERQ slot! If SCSI command, need SEST slot
-               // otherwise we are done.
-
-    // Note that Tachyon requires that bit 15 of the OX_ID or RX_ID be
-    // set according to direction of data to/from Tachyon for SEST assists.
-    // For consistency, enforce this rule for Link Service (non-SEST)
-    // exchanges as well.
-
-    // fix-up the X_ID field in IRB
-    pExchange->IRB.Req_A_Trans_ID = ExchangeID & 0x7FFF; // 15-bit field
-
-    // fix-up the X_ID field in fchs -- depends on Originator or Responder,
-    // outgoing or incoming data?
-    switch( pExchange->type )
-    {
-               // ORIGINATOR types...  we're setting our OX_ID and
-               // defaulting the responder's RX_ID to 0xFFFF
-    
-    case SCSI_IRE:
-      // Requirement: set MSB of x_ID for Incoming TL data
-      // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
-      InboundData = 0x8000;
-
-    case SCSI_IWE:   
-      SestType = TRUE;
-      pExchange->fchs.ox_rx_id = (ExchangeID | InboundData);
-      pExchange->fchs.ox_rx_id <<= 16;     // MSW shift
-      pExchange->fchs.ox_rx_id |= 0xffff;  // add default RX_ID
-      
-      // now fix-up the Data HDR OX_ID (TL automatically does rx_id)
-      // (not necessary for IRE -- data buffer unused)
-      if( pExchange->type == SCSI_IWE)
-      {
-        fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id = 
-          pExchange->fchs.ox_rx_id;
-
-      }
-
-      break;
-
-
-    case FCS_NSR:  // ext. link service Name Service Request
-    case ELS_SCR:  // ext. link service State Change Registration
-    case ELS_FDISC:// ext. link service login
-    case ELS_FLOGI:// ext. link service login
-    case ELS_LOGO: // FC-PH extended link service logout
-    case BLS_NOP:  // Basic link service No OPeration
-    case ELS_PLOGI:// ext. link service login (PLOGI)
-    case ELS_PDISC:// ext. link service login (PDISC)
-    case ELS_PRLI: // ext. link service process login
-
-      pExchange->fchs.ox_rx_id = ExchangeID;
-      pExchange->fchs.ox_rx_id <<= 16;  // MSW shift
-      pExchange->fchs.ox_rx_id |= 0xffff;  // and RX_ID
-
-      break;
-      
-
-
-
-               // RESPONDER types... we must set our RX_ID while preserving
-               // sender's OX_ID
-               // outgoing (or no) data
-    case ELS_RJT:       // extended link service reject 
-    case ELS_LOGO_ACC: // FC-PH extended link service logout accept
-    case ELS_ACC:      // ext. generic link service accept
-    case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
-    case ELS_PRLI_ACC: // ext. link service process login accept
-
-      CompleteExchange = TRUE;   // Reply (ACC or RJT) is end of exchange
-      pExchange->fchs.ox_rx_id |= (ExchangeID & 0xFFFF);
-
-      break;
-
-
-      // since we are a Responder, OX_ID should already be set by
-      // cpqfcTSBuildExchange().  We need to -OR- in RX_ID
-    case SCSI_TWE:
-      SestType = TRUE;
-      // Requirement: set MSB of x_ID for Incoming TL data
-      // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
-
-      pExchange->fchs.ox_rx_id &= 0xFFFF0000;  // clear RX_ID
-      // Requirement: set MSB of RX_ID for Incoming TL data
-      // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
-      pExchange->fchs.ox_rx_id |= (ExchangeID | 0x8000);
-      break;
-          
-    
-    case SCSI_TRE:
-      SestType = TRUE;
-      
-      // there is no XRDY for SEST target read; the data
-      // header needs to be updated. Also update the RSP
-      // exchange IDs for the status frame, in case it is sent automatically
-      fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id |= ExchangeID;
-      fcChip->SEST->RspHDR[ ExchangeID ].ox_rx_id = 
-        fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
-      
-      // for easier FCP response logic (works for TWE and TRE), 
-      // copy exchange IDs.  (Not needed if TRE 'RSP' bit set)
-      pExchange->fchs.ox_rx_id =
-        fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
-
-      break;
-
-
-    case FCP_RESPONSE:  // using existing OX_ID/ RX_ID pair,
-                        // start SFS FCP-RESPONSE frame
-      // OX/RX_ID should already be set! (See "fcBuild" above)
-      CompleteExchange = TRUE;   // RSP is end of FCP-SCSI exchange
-
-      
-      break;
-
-
-    case BLS_ABTS_RJT:  // uses new RX_ID, since SEST x_ID non-existent
-    case BLS_ABTS_ACC:  // using existing OX_ID/ RX_ID pair from SEST entry
-      CompleteExchange = TRUE;   // ACC or RJT marks end of FCP-SCSI exchange
-    case BLS_ABTS:  // using existing OX_ID/ RX_ID pair from SEST entry
-
-
-      break;
-
-
-    default:
-      printk("Error on fcStartExchange: undefined type %Xh(%d)\n",
-        pExchange->type, pExchange->type);
-      return INVALID_ARGS;
-    }
-    
-    
-      // X_ID fields are entered -- copy IRB to Tachyon's ERQ
-    
-
-    memcpy(
-        &fcChip->ERQ->QEntry[ ErqIndex ],  // dest.
-        &pExchange->IRB,
-        32);  // fixed (hardware) length!
-
-    PCI_TRACEO( ExchangeID, 0xA0)
-
-    // ACTION!  May generate INT and IMQ entry
-    writel( fcChip->ERQ->producerIndex,
-          fcChip->Registers.ERQproducerIndex.address);
-
-  
-    if( ExchangeID >= TACH_SEST_LEN )  // Link Service Outbound frame?
-    {
-    
-      // wait for completion! (TDB -- timeout and chip reset)
-      
-
-  PCI_TRACEO( ExchangeID, 0xA4)
-  
-      enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Sem.
-      
-      down_interruptible( cpqfcHBAdata->TYOBcomplete); 
-  
-      disable_irq( cpqfcHBAdata->HostAdapter->irq);
-  PCI_TRACE( 0xA4)
-
-      // On login exchanges, BAD_ALPA (non-existent port_id) results in 
-      // FTO (Frame Time Out) on the Outbound Completion message.
-      // If we got an FTO status, complete the exchange (free up slot)
-      if( CompleteExchange ||   // flag from Reply frames
-          pExchange->status )   // typically, can get FRAME_TO
-      {
-       cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);  
-      }
-    }
-
-    else                         // SEST Exchange
-    {
-      ulStatus = 0;   // ship & pray success (e.g. FCP-SCSI)
-      
-      if( CompleteExchange )   // by Type of exchange (e.g. end-of-xchng)
-      {
-       cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);  
-      }
-       
-      else
-        pExchange->status &= ~EXCHANGE_QUEUED;  // clear ExchangeQueued flag 
-
-    }
-  }
-
-  
-  else                // ERQ 'producer' = 'consumer' and QUE is full
-  {
-    ulStatus = OUTQUE_FULL; // Outbound (ERQ) Que full
-  }
-Done: 
-  PCI_TRACE( 0xA0)
-  return ulStatus; 
-}
-
-
-
-
-
-// Scan fcController->fcExchanges array for a usuable index (a "free"
-// exchange).
-// Inputs:
-//   fcChip - pointer to TachLite chip structure
-// Return:
-//  index - exchange array element where exchange can be built
-//  -1    - exchange array is full
-// REMARKS:
-// Although this is a (yuk!) linear search, we presume
-// that the system will complete exchanges about as quickly as
-// they are submitted.  A full Exchange array (and hence, max linear
-// search time for free exchange slot) almost guarantees a Fibre problem 
-// of some sort.
-// In the interest of making exchanges easier to debug, we want a LRU
-// (Least Recently Used) scheme.
-
-
-static LONG FindFreeExchange( PTACHYON fcChip, ULONG type )
-{
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG i;
-  ULONG ulStatus=-1;  // assume failure
-
-
-  if( type == SCSI_IRE ||
-      type == SCSI_TRE ||
-      type == SCSI_IWE ||
-      type == SCSI_TWE)
-  {
-        // SCSI type - X_IDs should be from 0 to TACH_SEST_LEN-1
-    if( fcChip->fcSestExchangeLRU >= TACH_SEST_LEN) // rollover?
-      fcChip->fcSestExchangeLRU = 0;
-    i = fcChip->fcSestExchangeLRU; // typically it's already free!
-
-    if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
-    {
-      ulStatus = 0; // success!
-    }
-    
-    else
-    {         // YUK! we need to do a linear search for free element.
-              // Fragmentation of the fcExchange array is due to excessively
-              // long completions or timeouts.
-      
-      while( TRUE )
-      {
-        if( ++i >= TACH_SEST_LEN ) // rollover check
-          i = 0;  // beginning of SEST X_IDs
-
-//        printk( "looping for SCSI xchng ID: i=%d, type=%Xh\n", 
-//         i, Exchanges->fcExchange[i].type);
-
-        if( Exchanges->fcExchange[i].type == 0 ) // "free"?
-        {
-          ulStatus = 0; // success!
-          break;
-        }
-        if( i == fcChip->fcSestExchangeLRU ) // wrapped-around array?
-        {
-          printk( "SEST X_ID space full\n");
-          break;       // failed - prevent inf. loop
-        }
-      }
-    }
-    fcChip->fcSestExchangeLRU = i + 1; // next! (rollover check next pass)
-  }
-
-  
-  
-  else  // Link Service type - X_IDs should be from TACH_SEST_LEN 
-        // to TACH_MAX_XID
-  {
-    if( fcChip->fcLsExchangeLRU >= TACH_MAX_XID || // range check
-        fcChip->fcLsExchangeLRU < TACH_SEST_LEN ) // (e.g. startup)
-      fcChip->fcLsExchangeLRU = TACH_SEST_LEN;
-
-    i = fcChip->fcLsExchangeLRU; // typically it's already free!
-    if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
-    {
-      ulStatus = 0; // success!
-    }
-    
-    else
-    {         // YUK! we need to do a linear search for free element
-              // Fragmentation of the fcExchange array is due to excessively
-              // long completions or timeouts.
-      
-      while( TRUE )
-      {
-        if( ++i >= TACH_MAX_XID ) // rollover check
-          i = TACH_SEST_LEN;// beginning of Link Service X_IDs
-
-//        printk( "looping for xchng ID: i=%d, type=%Xh\n", 
-//         i, Exchanges->fcExchange[i].type);
-
-        if( Exchanges->fcExchange[i].type == 0 ) // "free"?
-        {
-          ulStatus = 0; // success!
-          break;
-        }
-        if( i == fcChip->fcLsExchangeLRU ) // wrapped-around array?
-        {
-          printk( "LinkService X_ID space full\n");
-          break;       // failed - prevent inf. loop
-        }
-      }
-    }
-    fcChip->fcLsExchangeLRU = i + 1; // next! (rollover check next pass)
-
-  }
-
-  if( !ulStatus )  // success?
-    Exchanges->fcExchange[i].type = type; // allocate it.
-  
-  else
-    i = -1;  // error - all exchanges "open"
-
-  return i;  
-}
-
-static void
-cpqfc_pci_unmap_extended_sg(struct pci_dev *pcidev,
-       PTACHYON fcChip,
-       ULONG x_ID)
-{
-       // Unmaps the memory regions used to hold the scatter gather lists
-
-       PSGPAGES i;
-
-       // Were there any such regions needing unmapping?
-       if (! USES_EXTENDED_SGLIST(fcChip->SEST, x_ID))
-               return; // No such regions, we're outta here.
-
-       // for each extended scatter gather region needing unmapping... 
-       for (i=fcChip->SEST->sgPages[x_ID] ; i != NULL ; i = i->next)
-               pci_unmap_single(pcidev, i->busaddr, i->maplen,
-                       PCI_DMA_TODEVICE);
-}
-
-// Called also from cpqfcTScontrol.o, so can't be static
-void
-cpqfc_pci_unmap(struct pci_dev *pcidev, 
-       Scsi_Cmnd *cmd, 
-       PTACHYON fcChip, 
-       ULONG x_ID)
-{
-       // Undo the DMA mappings
-       if (cmd->use_sg) {      // Used scatter gather list for data buffer?
-               cpqfc_pci_unmap_extended_sg(pcidev, fcChip, x_ID);
-               pci_unmap_sg(pcidev, cmd->buffer, cmd->use_sg,
-                       cmd->sc_data_direction);
-               // printk("umsg %d\n", cmd->use_sg);
-       }
-       else if (cmd->request_bufflen) {
-               // printk("ums %p ", fcChip->SEST->u[ x_ID ].IWE.GAddr1);
-               pci_unmap_single(pcidev, fcChip->SEST->u[ x_ID ].IWE.GAddr1,
-                       cmd->request_bufflen,
-                       cmd->sc_data_direction);
-       }        
-}
-
-// We call this routine to free an Exchange for any reason:
-// completed successfully, completed with error, aborted, etc.
-
-// returns FALSE if Exchange failed and "retry" is acceptable
-// returns TRUE if Exchange was successful, or retry is impossible
-// (e.g. port/device gone).
-//scompleteexchange
-
-void cpqfcTSCompleteExchange( 
-       struct pci_dev *pcidev,
-       PTACHYON fcChip, 
-       ULONG x_ID)
-{
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  int already_unmapped = 0;
-  
-  if( x_ID < TACH_SEST_LEN ) // SEST-based (or LinkServ for FCP exchange)
-  {
-    if( Exchanges->fcExchange[ x_ID ].Cmnd == NULL ) // what#@!
-    {
-//      TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
-      printk(" x_ID %Xh, type %Xh, NULL ptr!\n", x_ID,
-                       Exchanges->fcExchange[ x_ID ].type);
-
-      goto CleanUpSestResources;  // this path should be very rare.
-    }
-
-    // we have Linux Scsi Cmnd ptr..., now check our Exchange status
-    // to decide how to complete this SEST FCP exchange
-
-    if( Exchanges->fcExchange[ x_ID ].status ) // perhaps a Tach indicated problem,
-                                             // or abnormal exchange completion
-    {
-      // set FCP Link statistics
-     
-      if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT)
-        fcChip->fcStats.timeouts++;
-      if( Exchanges->fcExchange[ x_ID ].status & INITIATOR_ABORT)
-        fcChip->fcStats.FC4aborted++;
-      if( Exchanges->fcExchange[ x_ID ].status & COUNT_ERROR)
-        fcChip->fcStats.CntErrors++;
-      if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX)
-        fcChip->fcStats.linkFailTX++;
-      if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_RX)
-        fcChip->fcStats.linkFailRX++;
-      if( Exchanges->fcExchange[ x_ID ].status & OVERFLOW)
-        fcChip->fcStats.CntErrors++;
-
-      // First, see if the Scsi upper level initiated an ABORT on this
-      // exchange...
-      if( Exchanges->fcExchange[ x_ID ].status == INITIATOR_ABORT )
-      {
-        printk(" DID_ABORT, x_ID %Xh, Cmnd %p ", 
-            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
-        goto CleanUpSestResources;  // (we don't expect Linux _aborts)
-      }
-
-      // Did our driver timeout the Exchange, or did Tachyon indicate
-      // a failure during transmission?  Ask for retry with "SOFT_ERROR"
-      else if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT) 
-      {
-//        printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
-//            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
-        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
-      }
-      
-      // Did frame(s) for an open exchange arrive in the SFQ,
-      // meaning the SEST was unable to process them?
-      else if( Exchanges->fcExchange[ x_ID ].status & SFQ_FRAME) 
-      {
-//        printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
-//            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
-        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
-      }
-      
-      // Did our driver timeout the Exchange, or did Tachyon indicate
-      // a failure during transmission?  Ask for retry with "SOFT_ERROR"
-      else if( 
-               (Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX) ||
-               (Exchanges->fcExchange[ x_ID ].status & PORTID_CHANGED) ||
-              (Exchanges->fcExchange[ x_ID ].status & FRAME_TO)    ||
-              (Exchanges->fcExchange[ x_ID ].status & INV_ENTRY)    ||
-              (Exchanges->fcExchange[ x_ID ].status & ABORTSEQ_NOTIFY)    )
-
-
-      {
-//        printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
-//            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
-        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
-
-
-      }
-
-      // e.g., a LOGOut happened, or device never logged back in.
-      else if( Exchanges->fcExchange[ x_ID ].status & DEVICE_REMOVED) 
-      {
-//     printk(" *LOGOut or timeout on login!* ");
-       // trigger?
-//        TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
-
-        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_BAD_TARGET <<16);
-      }      
-               
-                     
-      // Did Tachyon indicate a CNT error?  We need further analysis
-      // to determine if the exchange is acceptable
-      else if( Exchanges->fcExchange[ x_ID ].status == COUNT_ERROR)
-      {
-        UCHAR ScsiStatus;
-        FCP_STATUS_RESPONSE *pFcpStatus = 
-         (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
-
-       ScsiStatus = pFcpStatus->fcp_status >>24;
-  
-       // If the command is a SCSI Read/Write type, we don't tolerate
-       // count errors of any kind; assume the count error is due to
-       // a dropped frame and ask for retry...
-       
-       if(( (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x8) ||
-           (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x28) ||            
-            (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0xA) ||
-            (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x2A) )
-                          &&
-                     ScsiStatus == 0 )
-       {
-          // ask for retry
-/*          printk("COUNT_ERROR retry, x_ID %Xh, status %Xh, Cmnd %p\n", 
-            x_ID, Exchanges->fcExchange[ x_ID ].status,
-            Exchanges->fcExchange[ x_ID ].Cmnd);*/
-          Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
-       }
-       
-       else  // need more analysis
-       {
-         cpqfcTSCheckandSnoopFCP(fcChip, x_ID);  // (will set ->result)
-       }
-      }
-      
-      // default: NOTE! We don't ever want to get here.  Getting here
-      // implies something new is happening that we've never had a test
-      // case for.  Need code maintenance!  Return "ERROR"
-      else
-      {
-       unsigned int stat = Exchanges->fcExchange[ x_ID ].status;
-        printk("DEFAULT result %Xh, x_ID %Xh, Cmnd %p", 
-          Exchanges->fcExchange[ x_ID ].status, x_ID, 
-         Exchanges->fcExchange[ x_ID ].Cmnd);
-
-       if (stat & INVALID_ARGS)        printk(" INVALID_ARGS ");
-       if (stat & LNKDWN_OSLS)         printk(" LNKDWN_OSLS ");
-       if (stat & LNKDWN_LASER)        printk(" LNKDWN_LASER ");
-       if (stat & OUTQUE_FULL)         printk(" OUTQUE_FULL ");
-       if (stat & DRIVERQ_FULL)        printk(" DRIVERQ_FULL ");
-       if (stat & SEST_FULL)           printk(" SEST_FULL ");
-       if (stat & BAD_ALPA)            printk(" BAD_ALPA ");
-       if (stat & OVERFLOW)            printk(" OVERFLOW ");
-       if (stat & COUNT_ERROR)         printk(" COUNT_ERROR ");
-       if (stat & LINKFAIL_RX)         printk(" LINKFAIL_RX ");
-       if (stat & ABORTSEQ_NOTIFY)     printk(" ABORTSEQ_NOTIFY ");
-       if (stat & LINKFAIL_TX)         printk(" LINKFAIL_TX ");
-       if (stat & HOSTPROG_ERR)        printk(" HOSTPROG_ERR ");
-       if (stat & FRAME_TO)            printk(" FRAME_TO ");
-       if (stat & INV_ENTRY)           printk(" INV_ENTRY ");
-       if (stat & SESTPROG_ERR)        printk(" SESTPROG_ERR ");
-       if (stat & OUTBOUND_TIMEOUT)    printk(" OUTBOUND_TIMEOUT ");
-       if (stat & INITIATOR_ABORT)     printk(" INITIATOR_ABORT ");
-       if (stat & MEMPOOL_FAIL)        printk(" MEMPOOL_FAIL ");
-       if (stat & FC2_TIMEOUT)         printk(" FC2_TIMEOUT ");
-       if (stat & TARGET_ABORT)        printk(" TARGET_ABORT ");
-       if (stat & EXCHANGE_QUEUED)     printk(" EXCHANGE_QUEUED ");
-       if (stat & PORTID_CHANGED)      printk(" PORTID_CHANGED ");
-       if (stat & DEVICE_REMOVED)      printk(" DEVICE_REMOVED ");
-       if (stat & SFQ_FRAME)           printk(" SFQ_FRAME ");
-       printk("\n");
-
-        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_ERROR <<16);
-      }
-    }
-    else    // definitely no Tach problem, but perhaps an FCP problem
-    {
-      // set FCP Link statistic
-      fcChip->fcStats.ok++;
-      cpqfcTSCheckandSnoopFCP( fcChip, x_ID);  // (will set ->result)    
-    }
-
-    cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd, 
-                       fcChip, x_ID); // undo DMA mappings.
-    already_unmapped = 1;
-
-    // OK, we've set the Scsi "->result" field, so proceed with calling
-    // Linux Scsi "done" (if not NULL), and free any kernel memory we
-    // may have allocated for the exchange.
-
-  PCI_TRACEO( (ULONG)Exchanges->fcExchange[x_ID].Cmnd, 0xAC);
-    // complete the command back to upper Scsi drivers
-    if( Exchanges->fcExchange[ x_ID ].Cmnd->scsi_done != NULL)
-    {
-      // Calling "done" on an Linux _abort() aborted
-      // Cmnd causes a kernel panic trying to re-free mem.
-      // Actually, we shouldn't do anything with an _abort CMND
-      if( Exchanges->fcExchange[ x_ID ].Cmnd->result != (DID_ABORT<<16) )
-      {
-        PCI_TRACE(0xAC)
-       call_scsi_done(Exchanges->fcExchange[ x_ID ].Cmnd);
-      }
-      else
-      {
-//     printk(" not calling scsi_done on x_ID %Xh, Cmnd %p\n",
-//                     x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
-      }
-    }
-    else{
-      printk(" x_ID %Xh, type %Xh, Cdb0 %Xh\n", x_ID,
-       Exchanges->fcExchange[ x_ID ].type, 
-       Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0]);         
-      printk(" cpqfcTS: Null scsi_done function pointer!\n");
-    }
-
-
-    // Now, clean up non-Scsi_Cmnd items...
-CleanUpSestResources:
-   
-    if (!already_unmapped) 
-       cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd, 
-                       fcChip, x_ID); // undo DMA mappings.
-
-    // Was an Extended Scatter/Gather page allocated?  We know
-    // this by checking DWORD 4, bit 31 ("LOC") of SEST entry
-    if( !(fcChip->SEST->u[ x_ID ].IWE.Buff_Off & 0x80000000))
-    {
-      PSGPAGES p, next;
-
-      // extended S/G list was used -- Free the allocated ext. S/G pages
-      for (p = fcChip->SEST->sgPages[x_ID]; p != NULL; p = next) {
-        next = p->next;
-        kfree(p);
-      }
-      fcChip->SEST->sgPages[x_ID] = NULL;
-    }
-  
-    Exchanges->fcExchange[ x_ID ].Cmnd = NULL; 
-  }  // Done with FCP (SEST) exchanges
-
-
-  // the remaining logic is common to ALL Exchanges: 
-  // FCP(SEST) and LinkServ.
-
-  Exchanges->fcExchange[ x_ID ].type = 0; // there -- FREE!  
-  Exchanges->fcExchange[ x_ID ].status = 0; 
-
-  PCI_TRACEO( x_ID, 0xAC)
-     
-  
-  return;
-}   // (END of CompleteExchange function)
-
-
-
-// Unfortunately, we must snoop all command completions in
-// order to manipulate certain return fields, and take note of
-// device types, etc., to facilitate the Fibre-Channel to SCSI
-// "mapping".  
-// (Watch for BIG Endian confusion on some payload fields)
-void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID)
-{
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  Scsi_Cmnd *Cmnd = Exchanges->fcExchange[ x_ID].Cmnd;
-  FCP_STATUS_RESPONSE *pFcpStatus = 
-    (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
-  UCHAR ScsiStatus;
-
-  ScsiStatus = pFcpStatus->fcp_status >>24;
-
-#ifdef FCP_COMPLETION_DBG
-  printk("ScsiStatus = 0x%X\n", ScsiStatus);
-#endif 
-
-  // First, check FCP status
-  if( pFcpStatus->fcp_status & FCP_RSP_LEN_VALID )
-  {
-    // check response code (RSP_CODE) -- most popular is bad len
-    // 1st 4 bytes of rsp info -- only byte 3 interesting
-    if( pFcpStatus->fcp_rsp_info & FCP_DATA_LEN_NOT_BURST_LEN )
-    { 
-
-      // do we EVER get here?
-      printk("cpqfcTS: FCP data len not burst len, x_ID %Xh\n", x_ID);
-    }
-  }
-
-  // for now, go by the ScsiStatus, and manipulate certain
-  // commands when necessary...
-  if( ScsiStatus == 0) // SCSI status byte "good"?
-  {
-    Cmnd->result = 0; // everything's OK
-
-    if( (Cmnd->cmnd[0] == INQUIRY)) 
-    {
-      UCHAR *InquiryData = Cmnd->request_buffer;
-      PFC_LOGGEDIN_PORT pLoggedInPort;
-
-      // We need to manipulate INQUIRY
-      // strings for COMPAQ RAID controllers to force
-      // Linux to scan additional LUNs.  Namely, set
-      // the Inquiry string byte 2 (ANSI-approved version)
-      // to 2.
-
-      if( !memcmp( &InquiryData[8], "COMPAQ", 6 ))
-      {
-        InquiryData[2] = 0x2;  // claim SCSI-2 compliance,
-                               // so multiple LUNs may be scanned.
-                               // (no SCSI-2 problems known in CPQ)
-      }
-        
-      // snoop the Inquiry to detect Disk, Tape, etc. type
-      // (search linked list for the port_id we sent INQUIRY to)
-      pLoggedInPort = fcFindLoggedInPort( fcChip,
-        NULL,     // DON'T search Scsi Nexus (we will set it)
-        Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,        
-        NULL,     // DON'T search linked list for FC WWN
-        NULL);    // DON'T care about end of list
-      if( pLoggedInPort )
-      {
-        pLoggedInPort->ScsiNexus.InqDeviceType = InquiryData[0];
-      }
-      else
-      {
-       printk("cpqfcTS: can't find LoggedIn FC port %06X for INQUIRY\n",
-          Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF);
-      }
-    }
-  }
-
-
-  // Scsi Status not good -- pass it back to caller 
-
-  else
-  {
-    Cmnd->result = ScsiStatus; // SCSI status byte is 1st
-    
-    // check for valid "sense" data
-
-    if( pFcpStatus->fcp_status & FCP_SNS_LEN_VALID ) 
-    {            // limit Scsi Sense field length!
-      int SenseLen = pFcpStatus->fcp_sns_len >>24; // (BigEndian) lower byte
-      
-      SenseLen = SenseLen > sizeof( Cmnd->sense_buffer) ? 
-        sizeof( Cmnd->sense_buffer) : SenseLen;
-          
-
-#ifdef FCP_COMPLETION_DBG          
-      printk("copy sense_buffer %p, len %d, result %Xh\n",
-        Cmnd->sense_buffer, SenseLen, Cmnd->result);
-#endif   
-
-      // NOTE: There is some dispute over the FCP response
-      // format.  Most FC devices assume that FCP_RSP_INFO
-      // is 8 bytes long, in spite of the fact that FCP_RSP_LEN
-      // is (virtually) always 0 and the field is "invalid".  
-      // Some other devices assume that
-      // the FCP_SNS_INFO begins after FCP_RSP_LEN bytes (i.e. 0)
-      // when the FCP_RSP is invalid (this almost appears to be
-      // one of those "religious" issues).
-      // Consequently, we test the usual position of FCP_SNS_INFO
-      // for 7Xh, since the SCSI sense format says the first
-      // byte ("error code") should be 0x70 or 0x71.  In practice,
-      // we find that every device does in fact have 0x70 or 0x71
-      // in the first byte position, so this test works for all
-      // FC devices.  
-      // (This logic is especially effective for the CPQ/DEC HSG80
-      // & HSG60 controllers).
-
-      if( (pFcpStatus->fcp_sns_info[0] & 0x70) == 0x70 )
-        memcpy( Cmnd->sense_buffer, 
-          &pFcpStatus->fcp_sns_info[0], SenseLen);
-      else
-      {
-        unsigned char *sbPtr = 
-               (unsigned char *)&pFcpStatus->fcp_sns_info[0];
-        sbPtr -= 8;  // back up 8 bytes hoping to find the
-                    // start of the sense buffer
-        memcpy( Cmnd->sense_buffer, sbPtr, SenseLen);
-      }
-
-      // in the special case of Device Reset, tell upper layer
-      // to immediately retry (with SOFT_ERROR status)
-      // look for Sense Key Unit Attention (0x6) with ASC Device
-      // Reset (0x29)
-      //           printk("SenseLen %d, Key = 0x%X, ASC = 0x%X\n",
-      //                   SenseLen, Cmnd->sense_buffer[2], 
-      //                   Cmnd->sense_buffer[12]);
-      if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
-               (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
-      {
-        Cmnd->result |= (DID_SOFT_ERROR << 16); // "Host" status byte 3rd
-      }
-      // check for SenseKey "HARDWARE ERROR", ASC InternalTargetFailure
-      else if(  ((Cmnd->sense_buffer[2] & 0xF) == 0x4) &&  // "hardware error"
-               (Cmnd->sense_buffer[12] == 0x44) ) // Addtl. Sense Code 
-      {
-//        printk("HARDWARE_ERROR, Channel/Target/Lun %d/%d/%d\n",
-//             Cmnd->channel, Cmnd->target, Cmnd->lun);
-       Cmnd->result |= (DID_ERROR << 16); // "Host" status byte 3rd
-      }
-      
-    }  // (end of sense len valid)
-
-    // there is no sense data to help out Linux's Scsi layers...
-    // We'll just return the Scsi status and hope he will "do the 
-    // right thing"
-    else
-    {
-      // as far as we know, the Scsi status is sufficient
-      Cmnd->result |= (DID_OK << 16); // "Host" status byte 3rd
-    }
-  }
-}
-
-
-
-//PPPPPPPPPPPPPPPPPPPPPPPPP  PAYLOAD  PPPPPPPPP
-// build data PAYLOAD; SCSI FCP_CMND I.U.
-// remember BIG ENDIAN payload - DWord values must be byte-reversed
-// (hence the affinity for byte pointer building).
-
-static int build_FCP_payload( Scsi_Cmnd *Cmnd, 
-      UCHAR* payload, ULONG type, ULONG fcp_dl )
-{
-  int i;
-
-  
-  switch( type)
-  {
-                 
-    case SCSI_IWE: 
-    case SCSI_IRE:        
-      // 8 bytes FCP_LUN
-      // Peripheral Device or Volume Set addressing, and LUN mapping
-      // When the FC port was looked up, we copied address mode
-      // and any LUN mask to the scratch pad SCp.phase & .mode
-
-      *payload++ = (UCHAR)Cmnd->SCp.phase;
-
-      // Now, because of "lun masking" 
-      // (aka selective storage presentation),
-      // the contiguous Linux Scsi lun number may not match the
-      // device's lun number, so we may have to "map".  
-      
-      *payload++ = (UCHAR)Cmnd->SCp.have_data_in;
-      
-      // We don't know of anyone in the FC business using these 
-      // extra "levels" of addressing.  In fact, confusion still exists
-      // just using the FIRST level... ;-)
-      
-      *payload++ = 0;  // 2nd level addressing
-      *payload++ = 0;
-      *payload++ = 0;  // 3rd level addressing
-      *payload++ = 0;
-      *payload++ = 0;  // 4th level addressing
-      *payload++ = 0;
-
-      // 4 bytes Control Field FCP_CNTL
-      *payload++ = 0;    // byte 0: (MSB) reserved
-      *payload++ = 0;    // byte 1: task codes
-
-                         // byte 2: task management flags
-      // another "use" of the spare field to accomplish TDR
-      // note combination needed
-      if( (Cmnd->cmnd[0] == RELEASE) &&
-          (Cmnd->SCp.buffers_residual == FCP_TARGET_RESET) )
-      {
-        Cmnd->cmnd[0] = 0;    // issue "Test Unit Ready" for TDR
-        *payload++ = 0x20;    // target device reset bit
-      }
-      else
-        *payload++ = 0;    // no TDR
-                     // byte 3: (LSB) execution management codes
-                     // bit 0 write, bit 1 read (don't set together)
-      
-      if( fcp_dl != 0 )
-      {
-        if( type == SCSI_IWE )         // WRITE
-          *payload++ = 1;
-        else                           // READ
-          *payload++ = 2;
-      }
-      else
-      {
-       // On some devices, if RD or WR bits are set,
-       // and fcp_dl is 0, they will generate an error on the command.
-       // (i.e., if direction is specified, they insist on a length).
-       *payload++ = 0;                // no data (necessary for CPQ)
-      }
-
-
-      // NOTE: clean this up if/when MAX_COMMAND_SIZE is increased to 16
-      // FCP_CDB allows 16 byte SCSI command descriptor blk;
-      // Linux SCSI CDB array is MAX_COMMAND_SIZE (12 at this time...)
-      for( i=0; (i < Cmnd->cmd_len) && i < MAX_COMMAND_SIZE; i++)
-       *payload++ = Cmnd->cmnd[i];
-
-      // if( Cmnd->cmd_len == 16 )
-      // {
-      //  memcpy( payload, &Cmnd->SCp.buffers_residual, 4);
-      // }
-      payload+= (16 - i);  
-
-                     // FCP_DL is largest number of expected data bytes
-                     // per CDB (i.e. read/write command)
-      *payload++ = (UCHAR)(fcp_dl >>24);  // (MSB) 8 bytes data len FCP_DL
-      *payload++ = (UCHAR)(fcp_dl >>16);
-      *payload++ = (UCHAR)(fcp_dl >>8);
-      *payload++ = (UCHAR)fcp_dl;    // (LSB)
-      break;
-
-    case SCSI_TWE:          // need FCP_XFER_RDY
-      *payload++ = 0;     // (4 bytes) DATA_RO (MSB byte 0)
-      *payload++ = 0;
-      *payload++ = 0;
-      *payload++ = 0;     // LSB (byte 3)
-                            // (4 bytes) BURST_LEN
-                            // size of following FCP_DATA payload
-      *payload++ = (UCHAR)(fcp_dl >>24);  // (MSB) 8 bytes data len FCP_DL
-      *payload++ = (UCHAR)(fcp_dl >>16);
-      *payload++ = (UCHAR)(fcp_dl >>8);
-      *payload++ = (UCHAR)fcp_dl;    // (LSB)
-                      // 4 bytes RESERVED
-      *payload++ = 0;
-      *payload++ = 0;
-      *payload++ = 0;
-      *payload++ = 0;
-      break;
-
-    default:
-      break;
-  }
-
-  return 0;
-}
-