[ale] need to update scsi driver 2.2.x -> 2.4.x, source included as attachment............

Courtney Thomas ccthomas at flash.net
Mon May 27 10:36:12 EDT 2002


Greetings !

I have the scsi driver source for 2.2.x and need it updated to 2.4.x.

I'm aware that this is a 'significant' project but would be grateful if 
someone experienced in this area would take a cursory look at the source 
and indicate what "basically" would be required to accomplish such an 
update.

I also have copies of the header, Config, Makefile, hosts.c and 
attendant i2o files if desired but wanted to initially try to minimize 
the size of this posting.

Recommendations regarding information, suggested line of attack and on 
line help would also be appreciated, of course.

Thank you,
Courtney


/*
 * This driver supports the DPT SmartRAID V I2O boards.
 *
 * The driver was ported to Linux by Karen White while at Dell Computer.
 * Is was ported from Bob Pasteur's original non-Linux driver.  Mark Salyzyn
 * and Bob Pasteur answered many questions regarding the board, original
 * driver, and I2O issues.  They were also consulted with for debugging
 * suggestions.
 * 
 * The driver was originally ported to linux version 2.0.34.  The SMP
 * support was added and debugged in version 2.2.1 and 2.2.2.
 *
 * 2.0.34 anomalies and workarounds:  The dpt card can process so many 
 * messages at a time, that I was getting "Aiee: scheduling in interrupt"
 * messages while in the interrupt service routine.  The only way I could
 * get around this was to delay most of the processing of the returned
 * messages by having the interrupt service routine schedule the 
 * processing of the returned messages using a task
 * queue.  I had to use the scheduler queue as opposed to the immediate
 * queue in order to prevent the message above.  The schedule routine 
 * sets intr_count to 1 (in the 2.0.xx tree) before calling do_bottom_half().
 * Thus, I was still getting the "Aiee" message even when using the
 * immediate queue.  Using the scheduler queue got around this problem.
 *
 * The scsi layer was completely changed in the 2.2.xx versions, so I no
 * longer do delayed processing of the messages using a task queue.  In fact,
 * if you use the task queue, the driver does NOT work in the 2.2.xx tree.
 * 
 * scsi_register(), which is called from dpt_configcard, has a limitation
 * on the amount of memory it can allocate.  Consequently, you cannot store
 * copies of the outstanding messages in the dpt hba structure.  This is
 * why message copies are either stored in global tables are on the local
 * stack.
 *
 * The DPT card optimizes the order of processing commands.  Consequently,
 * a command may take up to 2 minutes to complete after it has been sent
 * to the board.  The scsi layer (scsi.c, sd.c), does not export the routines
 * that would allow me to reset the command timeout.  So, in 2.0.xx versions
 * of the driver, I set the field by hand.  In 2.2.xx versions of the driver,
 * I copied scsi_add_timer and called it dpt_add_timer, and use it to reset
 * the command timeout.
 *
 * The DPT firmware/card appears to continue writing to memory
 * AFTER an INQUIRY command that has been sent to the IOP has returned.  
 * A call to dpt_delay is made in dpt_detect after a card is
 * detected just to make sure the inquiry command has finished.
 *
 *
 * Driver Entry Points:
 *	The driver entry points are defined in dpt_i2o.h with the DPT_I2O define
 *	
 *	The first routine in the driver to be called is the dpt_detect
 *	routine.  It finds the cards and does I2O and card initialization.
 *
 */
#ifdef MODULE
#include <linux/module.h>

#if LINUX_VERSION_CODE >= 0x20100
char kernel_version[] = UTS_RELEASE;

MODULE_AUTHOR("Karen White:  Dell Computer, ported from Bob Pasteur's non-Linux driver, consulted with Mark Salyzyn");

MODULE_DESCRIPTION("DPT SmartRAID V I2O Driver");
#endif

#endif	/* MODULE */

#define DPT_C_VERSION	"1.06"

#include <linux/version.h>

/*
 *		I2O headers 
 */
#include "i2o/i2odep.h"
#include "i2o/i2obscsi.h"
#include "i2o/i2oexec.h"
#include "i2o/i2omsg.h"
#include "i2o/i2omstor.h"
#include "i2o/i2outil.h"
#include "i2o/i2oadptr.h"
#include "i2o/i2odpt.h"

#include <linux/stat.h>
#include <linux/malloc.h>        /* for kmalloc() */
#include <linux/config.h>        /* for CONFIG_PCI */
#include <linux/pci.h>		/* for PCI support */
#include <linux/proc_fs.h>
#include <linux/blk.h>
#include <linux/delay.h>	/* for udelay */
#include <linux/tqueue.h>
#include <linux/interrupt.h>

#include <asm/pgtable.h>
#if LINUX_VERSION_CODE < 0x020100
#include <asm/irq.h>
#endif

#if LINUX_VERSION_CODE >= 0x020100
#include <asm/spinlock.h>	/* for SMP support */
#endif

#include <asm/io.h>		/* for virt_to_bus, etc. */

/* 
 * LOCALREPLY: If LOCALREPLY is defined, the reply from the host bus
 *	adapter is stored in a global table, and a ptr to it is stored 
 *	in the dpt_msg.
 *
 * If LOCALREPLY is not defined, the reply from the host bus adapter is 
 *	stored in the dpt_msg.
 *
 * You don't want the reply stored in the dpt_msg because the dpt_msg gets
 * too large.
 * 
 * LOCALONSTACK:  If LOCALONSTACK is defined, the message to the board is
 *	built on the local stack of the procedure building the message.
 *
 * If LOCALONSTACK is not defined, the message is built in a global array
 * of messages (localmsgs).
 */

#define LOCALREPLY 1
#define LOCALONSTACK 1

#include "sd.h"
#include "scsi.h"
#include "hosts.h"
#include "dpt_i2o.h"

#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,92)
#include <linux/bios32.h>	/* for PCI support */
#endif

/*
 * dpti2oscsi2.c contains a table of scsi commands that is used to determine
 * the data direction of the command.  It is used in dpt_buildmsg to speed
 * up the building of the scsi message.
 */

#include "i2o/dpti2oscsi2.c"

#if LINUX_VERSION_CODE < 0x020100

#define ioremap vremap
#define iounmap vfree

#define	SPIN_LOCK_IRQSAVE(lock, flags)	{ save_flags(flags); cli(); }
#define	SPIN_UNLOCK_IRQRESTORE(lock, flags)	{ restore_flags(flags); }
#define SPIN_LOCK_INIT(lock)

#else	/* LINUX_VERSION_CODE is > 0x020100 */

#define	SPIN_LOCK_IRQSAVE(lock, flags)	spin_lock_irqsave(lock, flags);
#define	SPIN_UNLOCK_IRQRESTORE(lock, flags)	spin_unlock_irqrestore(lock, flags);
#define SPIN_LOCK_INIT(lock) spin_lock_init(lock);

void dpt_add_timer(Scsi_Cmnd * cmd, int timeout);

/************************************************************************
 * dpt_add_timer is called to set the scsi command timeout to timeout.
 * The command timeout is set in the scsi layer to be SD_TIMEOUT (in 2.2.2
 * this was 15 seconds).  Note, the timeout is set when scsi_do_cmd is 
 * called from requeue_sd_request (see sd.c).
 * For the dpt card, it needs to be set to 2 minutes.
 *
 * Called From:  dpt_buildmsg
 ************************************************************************/
void
dpt_add_timer(Scsi_Cmnd * cmd, int timeout)
{
	if( cmd->eh_timeout.function != NULL ) {
		del_timer(&cmd->eh_timeout);
	}

	cmd->eh_timeout.data = (unsigned long) cmd;
	cmd->eh_timeout.expires = jiffies + timeout;

	add_timer(&cmd->eh_timeout);
}

#endif	/* LINUX_VERSION_CODE < 0x020100 */


/*
 * The method for determining if PCI is present was changed in the 2.1.xx tree.
 * The PCI_PRESENT define is used in dpt_detect().
 */

#define NEWPCI_VERSION	KERNEL_VERSION(2,1,92)

#if LINUX_VERSION_CODE < NEWPCI_VERSION
#define	PCI_PRESENT	pcibios_present
#else
#define	PCI_PRESENT	pci_present
#endif	/* NEWPCI_VERSION */

#if LINUX_VERSION_CODE >= 0x020100
#define queue_task_irq queue_task
#endif	/* LINUX_VERSION_CODE >= 0x020100 */

//
// I2O table for the Set System Table Call
//
I2O_SYSTEM_TABLE_T *i2osystemtab = NULL;

//
// Structure for each physical HBA (dpt i2o card) found
//
STATIC pDPT_HBA_T dpti20cards[MAXADAPTERS];


#ifndef LOCALONSTACK
	UINT8 localmsgs[MAXADAPTERS][(MAX_TO_IOP_MESSAGES) * (MAX_MESSAGE_SIZE)];
#endif

#ifdef LOCALREPLY
volatile I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME reply[MAXADAPTERS][MAX_TO_IOP_MESSAGES];
#endif  /* LOCALREPLY */

/*
 * cardlist is a linked list of DPT I20 host bus adapter structures (DPT_HBA_T) .
 * The next field is used to construct the list.
 */
static pDPT_HBA_T cardlist = NULL;

#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
	volatile spinlock_t  cardlist_lock;
#else
	char cardlist_lock;
#endif

//
// Data buffer used during init
//
#define SCRATCHBUFSIZE 4000

#define SD_TIMEOUT (20 * HZ)

volatile UINT8 *scratchbuf;


/*
 * INTRLOCKS:  If INTRLOCKS is defined, the Hardware lock is used in the
 *	       interrupt handler.  I was using it for fine grain locking.
 *	       Currently, the 2.2.2 kernel uses coarse grain locking, so
 *	       you must grab the io_request_lock.  Thus, I don't define
 *	       INTRLOCKS at this time since it would be redundant.  If the
 *	       linux kernel ever gets switched to coarse grain locking, you
 *	       should define INTRLOCKS and get rid of the io_request_lock.
 *
 * QUEUELOCKS:  If QUEUELOCKS is defined, the ... lock is held in dpt_queue,
 *		etc. THIS MUST BE DEFINED for the 2.0.xx tree.  It is NOT
 *		needed for the 2.2.xx tree.
 */
#if LINUX_VERSION_CODE < 0x020100

#define QUEUELOCKS 1

#endif /* LINUX_VERSION_CODE < 0x020100 */

/*
 * The original version of ENQUEUE and DEQUEUE were taken from the 
 * megaraid driver (megaraid.c).
 */
#define	ENQUEUE(obj,type,list,next,lock) \
{ long enqflags; \
	SPIN_LOCK_IRQSAVE(&(lock), enqflags) \
	if (list.head == NULL ) { \
		list.head = (void *)(obj); \
		list.tail = (void *)(obj); \
		(type *)(obj)->##next = NULL; \
	} else { \
		((type *)(list.tail))->##next =  (void *)(obj); \
		list.tail = (void *)(obj); \
		(type *)(obj)->##next = NULL; \
	} \
	SPIN_UNLOCK_IRQRESTORE(&(lock), enqflags) \
}

#define DEQUEUE(obj,type,list,next,lock) \
{ long deqflags; \
	SPIN_LOCK_IRQSAVE(&(lock), deqflags) \
	if ((obj=(type *)(list).head) != NULL) {\
		(list).head = ((type *)((list).head))->##next; \
		if ((list).head == NULL) { \
			(list).tail = NULL; \
		} \
		(type *)(obj)->##next = NULL; \
  	} \
	SPIN_UNLOCK_IRQRESTORE(&(lock), deqflags) \
}

I2O_INITIATOR_CONTEXT uniqueid = 0;

/*
 * QUEUTASK indicates whether to use task queues or not.
 * Use task queues for post interrupt command processing in the 2.0.xx tree.
 * Don't use task queues in later versions
 */
#if LINUX_VERSION_CODE < 0x020100

#define QUEUETASK 1

#endif /* LINUX_VERSION_CODE < 0x020100 */

/*
 * doneq is a queue of commands completed by the interrupt handler
 */

dptqueue donetq;

#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
	volatile spinlock_t  donetq_lock;
#else
	char donetq_lock;
#endif

void dpt_dobh(void *dpthost);
void dpt_docmd(void *dpthost);

#ifdef QUEUETASK
static struct tq_struct dpt_intrtq = {
			0, 0, dpt_dobh, NULL
			};

static struct tq_struct dpt_sendtq = {
			0, 0, dpt_docmd, NULL
			};
#endif

/*
 * buffer used to hold reply from get status command
 *
 * have this instead of table I2O_DEVICE_T dptiI2oDeviceInfo[] - incorporate
 * rest of table into HBA structure
 */
I2O_EXEC_STATUS_GET_REPLY oldgetstatusreply;

#define defAlignLong(structure, name) \
	unsigned char name[sizeof(structure) + (sizeof(long) -1)]

#define getAlignLong(structure,name) ((structure *) \
	((((unsigned long)name) + (sizeof(long) - 1L)) & ~(sizeof(long) - 1L)))




struct proc_dir_entry proc_scsi_dptI2O = {
    PROC_SCSI_DPT_I2O, 3, "dpt-I2O",
    S_IFDIR | S_IRUGO | S_IXUGO, 2,
    0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};

int maxtoiopmsgs = MAX_TO_IOP_MESSAGES;

int dpt_doinquiry = 1;

#define	DPT_INQUIRY_DELAY 1000

#define DPTREPLYSPERINTERRUPT 512

#define	DEBUGMULTIPLEDEV 0

#ifdef DPTDEBUG
	int dbg_dptconfigcard = 0;
	int dbg_iopreset = 0;
	int dbg_dpti2ointr = 0;
	int dbg_dptinfo = 0;
	int dbg_dptdetect = 0;
	int dbg_dptqueue = 0;
	int dbg_initfromiopqueue = 0;
	int dbg_setsystab = 0;
	int dbg_sendpolledcommand = 0;
	int dbg_sendmessage = 0;
	int dbg_enablesys = 0;
	int dbg_builddevicelist = 0;
	int dbg_hrtget = 0;
	int dbg_lctnotify = 0;
	int dbg_paramsget = 0;
	int dbg_doreadcapacity = 0;
	int dbg_getreplymsg = 0;
	int dbg_buildmsg = 0;
	int dbg_buildsglist = 0;
	int dbg_procinfo = 0;
	int dbg_selectqueuedepths = 0;
	int dbg_adddevtotable = 0;
	int dbg_getdevfromtable = 0;
	int dbg_osrequestpost = 0;
	int dbg_dptdobh = 0;
	int dbg_drvrrequestpost = 0;
	int dbg_dptresethost = 0;
	int dbg_setdevflags = 0;
	int dbg_reset = 0;
	int dbg_resetscsibus = 0;
	int dbg_resetdevice = 0;
	int dbg_abortmsg = 0;
	int dbg_flush = 0;
	int dbg_dohrtget = 0;
	int dbg_biosparam = 0;
	int dbg_inquiry = 0;
	int dbg_release = 0;
	int dbg_getstatus = 0;
	int dbg_allocmsg = 0;
#define	KWDEBUG(flags, dothis)	if  ((flags)) { dothis }
#else
#define	KWDEBUG(flags, dothis)
#endif	/* DPTDEBUG */

//
// Debug flags to be put into the HBA flags field when initialized
//
// Make sure to enable DEBUG_PRINT for these flags to work
//
unsigned long DebugFlags =              // Variable to setup with above flags.
                           HBA_FLAGS_DBG_KERNEL_PRINT_B |
                           HBA_FLAGS_DBG_FW_PRINT_B |
                           HBA_FLAGS_DBG_FUNCTION_ENTRY_B |
                           HBA_FLAGS_DBG_FUNCTION_EXIT_B |
                           HBA_FLAGS_DBG_ERROR_B |
                           HBA_FLAGS_DBG_INIT_B |
                           HBA_FLAGS_DBG_OS_COMMANDS_B  |
                           HBA_FLAGS_DBG_SCAN_B |
                           HBA_FLAGS_DBG_FLAGS_MASK | 
0;


/*
 * Function Prototypes
 */
static void dpt_select_queue_depths(struct Scsi_Host *host, Scsi_Device *devicelist);
VOID dpt_flush(pDPT_HBA_T dpthost);
VOID dpt_inquiry(pDPT_HBA_T dpthost);
static int dpt_resethost(pDPT_HBA_T dpthost);
void dpt_setdevflags(pDPT_HBA_T dpthost, INT32 channel, UINT32 flagbits, 
			int set);
int dpt_reset(Scsi_Cmnd *cmd, unsigned int flags);
STATIC INT32 dpti_ResetScsiBus(pDPT_HBA_T dpthost, INT32 Channel, INT32 Poll);
STATIC INT32 dpti_ResetDevice(pDPT_HBA_T dpthost, INT32 Channel,
				INT32 Target, INT32 Lun,INT32 Poll);
STATIC INT32 dpt_abortmsg(pDPT_HBA_T dpthost, pDEVINFO_T dptdevice, 
				pDPT_MSG_T AbortDptMsg_P);


static void dpt_delay(int millisec);
STATIC int dpt_configcard(Scsi_Host_Template *sht, unsigned char pcibus, 
	unsigned char pcifn, struct pci_dev *pdev);
STATIC INT32 dpti_iopreset(pUINT8 VirtualBaseAddress_P);
STATIC INT32 dpti_I2oGetStatus(UINT8 *VirtualBaseAddress,
                             PI2O_EXEC_STATUS_GET_REPLY GetStatusBuffer);
STATIC INT32 dpti_I2oInitFromIopQueue(UINT8 *VirtualBaseAddress,
                          PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME FromIopMsg_P,
                          INT32 FromIopMsgCount);
STATIC INT32 dpti_I2oSetSysTab(pDPT_HBA_T dptcard, 
                             UINT8 *SysBuffer,INT32 SysBufferSize,
                             UINT8 *MemBuffer,INT32 MemBufferSize,
                             UINT8 *IoBuffer,INT32 IoBufferSize);
STATIC INT32 dpti_I2oEnableSys(pDPT_HBA_T dptcard);
STATIC INT32 dpti_BuildDeviceList(pDPT_HBA_T dptcard);
STATIC INT32 dpti_I2oLCTNotify(pDPT_HBA_T dptcard, UINT8 *Buffer,
						   INT32 BufferSize);
STATIC INT32 dpti_I2oHrtGet(pDPT_HBA_T dptcard, 
				pUINT8 Buffer_P, INT32 BufferSize);
STATIC INT32 dpti_I2oParamsGet(pDPT_HBA_T dptcard, UINT32 TID, 
			     UINT8 *OperationBuffer,
                             INT32 OperationBufferSize,
                             UINT8 *DataBuffer,
                             INT32 DataBufferSize);

STATIC pDPT_MSG_T 
dpti_SendPolledCommand(pDPT_HBA_T dptcard, pDPT_MSG_T DptMsg_P, INT32 SecondsToWait, int prnt);


STATIC INT32 dpti_DoReadCapacity(pDPT_HBA_T dptcard, UINT32 TID, UINT8 *Buffer);
STATIC INT32 dpti_DisableInterrupts(pDPT_HBA_T dptcard);
STATIC INT32 dpti_EnableInterrupts(pDPT_HBA_T dptcard);
static void dpt_deletedevs(pDPT_HBA_T dpthost);
STATIC VOID dpti_AddDevToTable(pDEVINFO_T Dev_P, pDPT_HBA_T dptcard);
STATIC pDEVINFO_T dpti_GetDevFromTable(pDPT_HBA_T dptcard, 
				INT32 Channel, INT32 Target, INT32 Lun);
void dpt_msgdone(pDPT_MSG_T dptmsg, pDPT_HBA_T dpthost);
static VOID dpti2o_intr(int irq, void *dev_id, struct pt_regs *regs);
STATIC pDPT_MSG_T dpt_getreplymsg(pDPT_HBA_T dptcard, I2O_INITIATOR_CONTEXT *return_unique);
STATIC INT32 dpti_OsRequestPost(pDPT_MSG_T DptMsg_P);
STATIC INT32 dpti_DrvrRequestPost(pDPT_MSG_T DptMsg_P);
static void dpt_finish_commands(pDPT_HBA_T dpthost);

/*
 * Put inline functions first - needed to prevent kernel stack overflow
 *
 * dpti_FreeDptMsg, dpti_AllocDptMsg, dpti_I2oSendMessage, dpt_buildsglist
 * dpt_buildmsg
 */



//-------------------------------------------------------------------------
//                    Function dpti_FreeDptMsg                             
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     HbaNum : Host Adapter Number                                        
//     DptMsg_P : DptMsg Structure Pointer To Be Set Free                  
//                                                                         
// This Function Will Return The Passed In MSG To The Free List            
//                                                                         
// Return : None                                                           
//-------------------------------------------------------------------------


STATIC inline VOID 
dpti_FreeDptMsg(pDPT_HBA_T dptcard, pDPT_MSG_T DptMsg_P)
{
	unsigned long	flags;

  //
  // Lock down the MSG list 
  //
	SPIN_LOCK_IRQSAVE(&dptcard->MsgListLock, flags)

  //
  // Remove The Msg From The Active List 
  //
	if(DptMsg_P->Next_P != (pDPT_MSG_T )NULL) {  
		DptMsg_P->Next_P->Previous_P = DptMsg_P->Previous_P;
	}
	if(DptMsg_P->Previous_P == (pDPT_MSG_T )NULL ) {
		dptcard->DptMsgActiveList_P = DptMsg_P->Next_P;
	} else {
		DptMsg_P->Previous_P->Next_P = DptMsg_P->Next_P;
	}

  //
  // Clean up some fields
  //
  DptMsg_P->Flags = 0;
  DptMsg_P->ToIopMsg_P = NULL;
  DptMsg_P->Previous_P = (pDPT_MSG_T )NULL;
  DptMsg_P->scsicmd = NULL; 
  DptMsg_P->unique = 0;

  //
  // Add the MSG to the head of free list
  // Set the free list head to this MSG and update the count
  //
  DptMsg_P->Next_P = dptcard->DptMsgFreeList_P;
  dptcard->DptMsgFreeList_P = DptMsg_P;
  --dptcard->OutstandingMsgs;	/* probably don't need this - KAREN */
 
  //
  // Free up the list lock
  //
	SPIN_UNLOCK_IRQRESTORE(&dptcard->MsgListLock, flags)
}



//-------------------------------------------------------------------------
//                    Function dpti_AllocDptMsg                            
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     dpthost : Host Adapter 
//                                                                         
// This function will allocate a MSG from the free list                    
//                                                                         
// Return : Pointer To The Msg Or NULL If None Available                   
//-------------------------------------------------------------------------

STATIC inline pDPT_MSG_T 
dpti_AllocDptMsg(pDPT_HBA_T dpthost)
{
	pDPT_MSG_T DptMsg_P;
	unsigned long	flags;	/* for SMP locking */

	/*
	 * Remove a MSG From The Free List And Adjust The Pointer. 
	 */ 
	KWDEBUG(dbg_allocmsg, printk("dpti_AllocDptMsg Entered\n");)

	SPIN_LOCK_IRQSAVE(&dpthost->MsgListLock, flags)
	DptMsg_P = dpthost->DptMsgFreeList_P;

	if (DptMsg_P != NULL) {

		dpthost->DptMsgFreeList_P = DptMsg_P->Next_P;
		/*
		 * Set the timeout value to 0 before we add it to the active 
		 * list
		 */
		DptMsg_P->TimeoutValue = 0;
		/*
		 * KEEP HbaNum field - is used to find dpthost in 
		 * dpti_DrvrRequestPost, etc.
	 	 */
		DptMsg_P->HbaNum = dpthost->cardidx;
		/*
		 * Add it to the MSG active list for sanity timer checking. 
		 * Active list is searched in reset code, etc.
		 */
		if((DptMsg_P->Next_P = dpthost->DptMsgActiveList_P) != NULL) {
			dpthost->DptMsgActiveList_P->Previous_P = DptMsg_P;
		}
		dpthost->DptMsgActiveList_P = DptMsg_P;
		++dpthost->OutstandingMsgs;
		if ((uniqueid) == 0) {
			uniqueid = 1;
		}
		DptMsg_P->unique = uniqueid++;

#if DEBUGMSGSEQUENCE
		printk("dpti_Alloc: uniqueid = 0x%x\n", DptMsg_P->unique);
#endif	/* DEBUGMSGSEQUENCE */

		SPIN_UNLOCK_IRQRESTORE(&dpthost->MsgListLock, flags) 
		/*
		 * TODO:  Probably DONT'T need to do HardWareLock
		 */
		/*
		 * Pull off a message offset and unlock the hardware
		 */
#ifdef ALLOCLOCKS
		SPIN_LOCK_IRQSAVE(&dpthost->HardwareLock, flags)	
#endif
		DptMsg_P->ToIopMsgOffset = *dpthost->ToIopFifo_P;
#ifdef ALLOCLOCKS
		SPIN_UNLOCK_IRQRESTORE(&dpthost->HardwareLock, flags)
#endif
		/*
		 * If we got a MSG, Try to allocate an I2O message for the 
		 * request
		 *
		 * If we have one, convert it to a virtual pointer
		 */
		if(DptMsg_P->ToIopMsgOffset != EMPTY_QUEUE) {
			DptMsg_P->ToIopMsg_P = (UINT8 *)
                               (dpthost->VirtualBaseAddress_P + 
                                                    DptMsg_P->ToIopMsgOffset);
#ifdef LOCALONSTACK
			DptMsg_P->LocalToIopMsg = NULL;
#else
			memset(DptMsg_P->LocalToIopMsg, 0 , MAX_MESSAGE_SIZE);
#endif
		} else {
			 /*
	  		 * No I2O Messages available, so free up the previously 
			 * allocated MSG and set up to return a NULL
	  		 */
			dpti_FreeDptMsg(dpthost,DptMsg_P);
			DptMsg_P = NULL;
		}
	} else {
		SPIN_UNLOCK_IRQRESTORE(&dpthost->MsgListLock, flags) 
	}
	KWDEBUG(dbg_allocmsg, printk("dpti_AllocDptMsg Exit\n");)
	return(DptMsg_P);
}


//-------------------------------------------------------------------------
//                     Function dpti_I2oSendMessage                        
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     dptcard : Host Adapter 
//     DptMsg_P : DptMsg Structure Pointer To Be Sent
//                                                                         
// This function will send off the passed in message to the passed in
// HBA.
//                                                                         
// Return : None                                                           
//-------------------------------------------------------------------------

STATIC inline VOID 
dpti_I2oSendMessage(pDPT_HBA_T dptcard, pDPT_MSG_T DptMsg_P)
{
	UINT32 Count;
#ifdef SENDMSGLOCK
	unsigned long   flags;  /* for SMP locking */
#endif

	KWDEBUG(dbg_sendmessage, printk("dpti_I2oSendMessage Entered\n");)

	/*
	 *  Don't need locking here.  Left the code with an ifdef around it.
	 */

  //
  // Lock down the HBA hardware
  //
#ifdef SENDMSGLOCK
	SPIN_LOCK_IRQSAVE(&dptcard->HardwareLock, flags)
#endif

     //
     // Copy the local copy of the request message to the memory mapped
     // location containing the real message address
     //
     Count = ((PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)(DptMsg_P->LocalToIopMsg))->
                         PrivateMessageFrame.StdMessageFrame.MessageSize << 2;
	/* memcpy(to, from, size) */
	memcpy((UINT8 *)DptMsg_P->ToIopMsg_P, DptMsg_P->LocalToIopMsg, Count);

     //
     // Put the physical offset of the message into the queue for
     // the HBA to pick up
     //
     *dptcard->ToIopFifo_P = DptMsg_P->ToIopMsgOffset;

     //
     // Turn off the lights on the way out
     //
#ifdef SENDMSGLOCK
	SPIN_UNLOCK_IRQRESTORE(&dptcard->HardwareLock, flags)
#endif
}



//-------------------------------------------------------------------------
//                    Function dpti_BuildSgList                                
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     cmd : Command to build Scatter Gather list for
//     SimpleSg_P : Pointer to a simple Scatter gather List                
//                                                                         
// This Function will  fill out an empty Scatter Gather list for the 
// passed in command
//                                                                         
// Return : total number of bytes to transfer
//-------------------------------------------------------------------------

STATIC inline INT32 
dpt_buildsglist(Scsi_Cmnd *cmd, PI2O_SGE_SIMPLE_ELEMENT SimpleSg_P)
{
	struct scatterlist *sgl;	/* ptr to scatter gather list */
	int i;
	int count = 0;			/* total byte count to be transferred */

	KWDEBUG(dbg_buildsglist, printk("dpt_buildsglist: Entered\n"););

	if (cmd->use_sg) {
		/*
		 * set up scatter gather list
		 */
		sgl = (struct scatterlist *)cmd->request_buffer;
		for (i = 0; i < cmd->use_sg; i++) {
			SimpleSg_P[i].FlagsCount.Count = sgl[i].length;
			SimpleSg_P[i].FlagsCount.Flags = 
                                       I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT;
			SimpleSg_P[i].PhysicalAddress = virt_to_phys(sgl[i].address);
			count += sgl[i].length;
		}
		/*
		 * set flag in  last element
		 */
		SimpleSg_P[cmd->use_sg - 1].FlagsCount.Flags |= 
                                   I2O_SGL_FLAGS_LAST_ELEMENT | 
                                   I2O_SGL_FLAGS_END_OF_BUFFER;
	} else if (cmd->request_bufflen) {
		/*
		 * set up one simple scatter gather element
		 */
		count = SimpleSg_P[0].FlagsCount.Count = 
				cmd->request_bufflen;
		SimpleSg_P[0].FlagsCount.Flags = 
                                       I2O_SGL_FLAGS_LAST_ELEMENT | 
                                       I2O_SGL_FLAGS_END_OF_BUFFER | 
                                       I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT;
		SimpleSg_P[0].PhysicalAddress = virt_to_phys(cmd->request_buffer);

	}
	return(count);
}



//-------------------------------------------------------------------------
//                    Function dpt_buildmsg                             
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     cmd : OS Request Packet Pointer For This Command            
//     DptMsg_P : Msg Structure Pointer For This Command                   
//     dptdevice : Device to build message for
//                                                                         
// This Function will build an I2O message and send it to the given device.
//                                                                         
// Return : 0                                                              
//-------------------------------------------------------------------------

static inline INT32 
dpt_buildmsg(Scsi_Cmnd *cmd, pDPT_MSG_T DptMsg_P, pDEVINFO_T dptdevice)
{
	UINT16 MessageSize = (sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE) -
                    sizeof(I2O_SG_ELEMENT)) >> 2;
	UINT8 SglOffset = (UINT8)(MessageSize << 4);
	PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE ExecScsiMsg_P;
	pDPT_HBA_T	dpthost;	/* host bus adapter structure */
#ifdef LOCALONSTACK
	UINT8   localmsg[MAX_MESSAGE_SIZE];

	DptMsg_P->LocalToIopMsg = (UINT8 *)&localmsg;
        memset(&localmsg, 0, MAX_MESSAGE_SIZE);
#endif	/* LOCALONSTACK */
	ExecScsiMsg_P = (PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)(DptMsg_P->LocalToIopMsg);

	dpthost = (pDPT_HBA_T)cmd->host->hostdata;

	/*
	 * According to DPT (Mark), a scsi command can take up to 2 minutes to complete
	 * I would like to use update_timeout to reset the timeout, but the routine
	 * was declared statically, so it is not available.  If available, you would
	 * call update_timeout(120 * HZ)
	 */
#if LINUX_VERSION_CODE < 0x020100
	cmd->timeout = 120 * HZ;	/* set timeout to 2 minutes */
#else	/* LINUX_VERSION_CODE is > 0x020100 */
	dpt_add_timer(cmd, 120 * HZ);
#endif

	KWDEBUG(dbg_buildmsg, printk("dpt_buildmsg: Entered\n"););


  //
  // Clear the flags and save off the OS request packet
  //
  DptMsg_P->Flags = 0;
  DptMsg_P->scsicmd = cmd;


  //
  // Set up the standard header
  //
  ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.VersionOffset = 
                                               SglOffset | I2O_VERSION_11;
  ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.MsgFlags = 0;
  ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.TargetAddress = 
                                                  dptdevice->TID;
  ExecScsiMsg_P->TID = dptdevice->TID;
  ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.InitiatorAddress = 1;
  ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.Function = 
                                                          I2O_PRIVATE_MESSAGE;
  ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.InitiatorContext = DptMsg_P->unique;
  ExecScsiMsg_P->PrivateMessageFrame.TransactionContext = 
                                       (I2O_TRANSACTION_CONTEXT)DptMsg_P;
  ExecScsiMsg_P->PrivateMessageFrame.OrganizationID = DPT_ORGANIZATION_ID;
  ExecScsiMsg_P->PrivateMessageFrame.XFunctionCode = I2O_SCSI_SCB_EXEC;
  ExecScsiMsg_P->CDBLength = cmd->cmd_len;
  ExecScsiMsg_P->SCBFlags = I2O_SCB_FLAG_ENABLE_DISCONNECT | 
                            I2O_SCB_FLAG_SIMPLE_QUEUE_TAG |
                            I2O_SCB_FLAG_SENSE_DATA_IN_MESSAGE;

  //
  //DEBUG CODE : Until the Firmware clears the entire CDB, Zero it out
  //
	/*
	 * The CDB is 16 bytes, not 10
	 */
  memset((UINT8 *)&ExecScsiMsg_P->CDB, 0, I2O_SCSI_CDB_LENGTH);

  //
  // Copy In The SCSI CDB From The Request Packet 
  //
	if (cmd->cmd_len > I2O_SCSI_CDB_LENGTH) {
		printk("dpti2o: dpt_processmsg: cmd->cmd_len = %d is greater than max command length, which is %d\n", 
			cmd->cmd_len, I2O_SCSI_CDB_LENGTH);
	}
	memcpy(ExecScsiMsg_P->CDB, cmd->cmnd, cmd->cmd_len);	/* memcpy(to, from, size) */

	/*
	 * Set SCBFlags to indicate if data is being transferred
	 * in or out, or no data transfer
	 *
	 * Note:  Do not have to verify index is less than 0 since
	 * cmd->cmnd[0] is an unsigned char
	 */

	if (cmd->cmnd[0] < DISKXFERTBLSIZE) {

		switch (i2oscsi2diskxfer[cmd->cmnd[0]]) {

		case  DATAIN:
			ExecScsiMsg_P->SCBFlags |= I2O_SCB_FLAG_XFER_FROM_DEVICE;
			break;

		case DATAOUT:
			ExecScsiMsg_P->SCBFlags |= I2O_SCB_FLAG_XFER_TO_DEVICE;
			break;

		case NODATA:
			ExecScsiMsg_P->SCBFlags |= I2O_SCB_FLAG_NO_DATA_XFER;
			break;

		case NOSUPPORT:
		default:
				printk("dpti2o: dpt_buildmsg: scsi opcode 0x%x not supported.\n",
					cmd->cmnd[0]);
			break;

		}
	} else {
		printk("dpti2o: dpt_buildmsg: cmd->cmnd[0] = %d is greater than table size, which is %d\n", 
		cmd->cmnd[0], DISKXFERTBLSIZE);
	}

	/*
	 * ExecScsiMsg_P->ByteCount is set to amount of data to
	 * transfer.  If you have a SGL, it is the total of all
	 * the data (the sum of sg[].length,  NOT sglist_len in 
	 * scsi_cmnd
	 *
	 * dpt_buildsglist returns the bytecount to transfer
	 */
	if ((ExecScsiMsg_P->ByteCount = dpt_buildsglist(cmd, 
					&ExecScsiMsg_P->SGL.u.Simple[0]))) {
		/*
		 * Bump the message count of 32 bit words by the Number of 
		 * 32 bit words in the Scatter Gather list
		 */
		MessageSize += 2 * (cmd->use_sg ? cmd->use_sg : 1);
	}

  //
  // Set up the frame size in 32 bit words
  //
  ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.MessageSize = MessageSize;

  //
  // Set up the posting address and timeout value for this message
  //
  DptMsg_P->MSG_Post_P = dpti_OsRequestPost;

  //
  // Send it on it's merry way
  //
  dpti_I2oSendMessage(dpthost, DptMsg_P);
	KWDEBUG(dbg_buildmsg, printk("dpt_buildmsg: Exit\n"););

  return(0);

}



/*
 * End of inline functions
 */



int
dpt_abort(Scsi_Cmnd *cmd)
{
	pDPT_HBA_T	dpthost;	/* host bus adapter structure */
	unsigned long flags2;
	pDEVINFO_T	dptdevice;	/* dpt per device information */
	pDPT_MSG_T	dptmsg;
	int result = SCSI_ABORT_PENDING;

	dpthost = (pDPT_HBA_T)cmd->host->hostdata;

	if ((dptdevice = (pDEVINFO_T)(cmd->device->hostdata)) == NULL) {
		printk("dpti2o: dpt_abort: Unable to do abort: No device found in command\n");
		return(SCSI_ABORT_NOT_RUNNING);
		/* or ? SCSI_ABORT_ERROR */
	}
	/*
	 * If the serial number information is not correct, it is
	 * a different command.
	 */
	if (cmd->serial_number != cmd->serial_number_at_timeout) {
		printk("dpti2o: dpt_abort: Unable to reset channel %d, target %d lun %d.  Reset called with a finished or different command\n",
		cmd->channel, cmd->target, cmd->lun);
		result = SCSI_ABORT_NOT_RUNNING;
	}
	/*
	 * Loop through active messages to verify the message
	 * that timed out has not already been completed
	 */
	SPIN_LOCK_IRQSAVE(&dpthost->MsgListLock, flags2)
	for (dptmsg = dpthost->DptMsgActiveList_P; dptmsg != NULL; 
		dptmsg = dptmsg->Next_P) {
		if (dptmsg->scsicmd == cmd) {
			break;
		}
	}
	if (dptmsg == NULL) {
		printk("dpti2o: dpt_abort: Unable to reset channel %d, target %d lun %d.  No command found\n",
			cmd->channel, cmd->target, cmd->lun);
		result = SCSI_ABORT_NOT_RUNNING;
	}
	SPIN_UNLOCK_IRQRESTORE(&dpthost->MsgListLock, flags2) 
	/* even though the dptmsg ptr is stored in the command, since the
	 * dptmsgs are recycled, we cannot guarantee the ptr is the current
	 * command - thus, using the loop above to verify is current command
	 */
	dpt_abortmsg(dpthost, dptdevice, dptmsg);
	return(result);
}

const char *
dpt_info(struct Scsi_Host *host)
{
	pDPT_HBA_T	dpthost;

	KWDEBUG(dbg_dptinfo, printk("dpt_info: Entered\n"););

	dpthost = (DPT_HBA_T *)host->hostdata;
	return ((char *)(dpthost->name));
}


/*
 * dpt_proc_info is called from dispatch_scsi_info.  It provides the
 * support for the /proc file system.
 *
 * proc_readscsi and proc_writescsi (in fs/proc/scsi.c) call
 *  dispatch_scsi_info_ptr, which is set to dispatch_scsi_info in 
 * scsi_dev_init(). 
 *
 * dispatch_scsi_info (in scsi_proc.c) calls dpt_proc_info.
 */
int
dpt_proc_info(char *buffer, char **start, off_t offset,
                       int length, int hostno, int inout)
{
	pDEVINFO_T devp;
	int target, channel;
	int size  = 0;
	int len = 0;
	int begin = 0;
	int pos = 0;
	pDPT_HBA_T	dpthost;
	struct Scsi_Host *host;
	unsigned long	cardflags;


	KWDEBUG(dbg_procinfo, printk("dpt_proc_info: Entered\n"););

	*start = buffer;
	if(inout == TRUE) {
		/*
		 * The user has done a write and wants us to take the
		 * data in the buffer and do something with it.
		 * proc_scsiwrite calls us with inout = 1
		 *
		 * Read data from buffer (writing to us) - NOT SUPPORTED
		 */
		return (-ENOSYS);
	}

	/*
	 * inout = 0 means the user has done a read and wants information
	 * returned, so we write information about the cards into the buffer
	 * proc_scsiread() calls us with inout = 0
	 */

	/*
	 * We have returned buffer to (buffer + offset) in previous calls
	 * Set start to where we want the beginning of the new data to be.
	 */
	*start = buffer + offset;

	/*
	 * Find HBA (host bus adapter) we are looking for
	 */
	SPIN_LOCK_IRQSAVE(&cardlist_lock, cardflags)
	for (dpthost = cardlist; dpthost; dpthost = dpthost->next) {
		if (dpthost->host_no == hostno) {
			break;	/* found adapter */
		}
	}
	SPIN_UNLOCK_IRQRESTORE(&cardlist_lock, cardflags)
	if (dpthost == NULL) {
		return(0);
	}
	host = dpthost->host;

	if (dpt_doinquiry) {
		size = sprintf(buffer + len, "%s, scsi %d:\n\n", 
			dpthost->name, dpthost->host_no);
	} else {
		size = sprintf(buffer + len, "DPT SMARTRAID V, scsi %d:\n\n", 
			dpthost->host_no);
	}
	len += size;
	pos = begin + len;
	size = sprintf(buffer + len, "DPT I2O Driver Version: %s/%s:\n\n", 
			DPT_C_VERSION, DPT_H_VERSION);
	len += size;
	pos = begin + len;
	size = sprintf(buffer + len, "        cmd_per_lun = %d, max_id = %d, max_lun = %d, max_channel = %d\n",
		host->cmd_per_lun, host->max_id - 1, host->max_lun - 1, host->max_channel);
	len += size;
	pos = begin + len;

	size = sprintf(buffer + len, "        sg_tablesize = %d, irq = %d, OutstandingMsgs = %d\n",
		host->sg_tablesize, host->irq, (int) dpthost->OutstandingMsgs);
	len += size;
	pos = begin + len;
	size = sprintf(buffer + len, "        maxfromiopmsgs = %d, maxtoiopmsgs = %d\n\n",
		(int) dpthost->maxfromiopmsgs, host->can_queue);

	len += size;
	pos = begin + len;
	size = sprintf(buffer + len, "    Devices:\n");

	len += size;
	pos = begin + len;
	/*
	 * loop through all channel on the adapter
	 */
	for (channel = 0; channel < MAX_CHANNEL; channel++) {
		/*
		 * loop through all targets on the channel 
		 */
		for (target = 0; target < MAX_TARGET_ID; target++) {
			devp = dpthost->ScsiDeviceTable_P[channel][target];
			while (devp) {
				size = sprintf(buffer + len, "        Channel = %d, Target = %d, Lun = %d\n",
					(int) devp->ChannelNum, (int) devp->ScsiTargetID, (int) devp->ScsiLUN);
				len += size;
				pos = begin + len;
				devp = devp->NextLun_P;
			}
		}
		if (pos < offset) {
			/*
			 * If we haven't even written to where we last left
			 * off (the last time we were called), reset the 
			 * beginning pointer.
			 */
			len = 0;
			begin = pos;
		}
		if (pos > offset + length) {
			/*
			 * We have written past the end of the buffer 
			 * (proc_read/writescsi gives us 1K slop
			 *
			 * stop the output and calculate the correct length
			 */
			goto stop_output;
		}
	}
	/*
	 * begin is where we last checked our position with regards to offset
	 * begin is always less than offset.  len is relative to begin.  It
	 * is the number of bytes written past begin
	 *
	 */

stop_output:
	size = sprintf(buffer + len, "%c", '\0');
	len += size;

	len = len - (offset - begin);
	if (len > length) {
		len = length;
	}
	return(len);
}

/*
 * When dpt_release is called (from scsi_unregister_host, etc.), there are
 * no longer any scsi command or device structures for this host in the
 * upper-level scsi code - cannot send any commands up
 *
 * scsi_unregister will be called AFTER we return.  It frees up the dpthost
 * structure
 */
int
dpt_release(struct Scsi_Host *host)
{
	pDPT_HBA_T	dpthost;
	pDPT_HBA_T	prevdpthost, curdpthost;
	unsigned	long cardflags;

	dpthost = (DPT_HBA_T *)host->hostdata;

	KWDEBUG(dbg_release, printk("dpt_release: Entered\n");)

	/*
	 * according to the I2O spec, we should do an iopquiesce before
	 * doing an iopclear.  DPT does not support iopquiesce, so we
	 * are not doing it.  They do not support iopclear either.
	 * 
	 * Do an iopreset instead of quiesce if you have to reset something
	 */
	/*
	 * TESTED FLUSH and RESET - if adapter doesn't get test unit ready,
	 * sending the flush command hangs.  It timesout, but the iopreset
	 * fails.  It fails and you have to reboot the machine to recover
	 * the adapter.
	 * 
	 * So, cannot do flush and reset.
 	 */
#if 0
	dpt_flush(dpthost);
       /*
        * Reset the adapter, if it fails don't worry
        */
	if((error = dpti_iopreset(dpthost->VirtualBaseAddress_P))) {
		printk("dpti20: dpt_release:  Iop Reset Failed, Errno = %d\n", error);
	}
#endif

#if LINUX_VERSION_CODE < 0x020100
	/*
	 * Releaes any commands already on the done queue
	 */
	dpt_dobh(NULL);
#endif /* LINUX_VERSION_CODE < 0x020100 */
	/*
	 * Remove reference to host in our host table, and cardlist
	 */
	dpti20cards[dpthost->cardidx] = NULL;
	prevdpthost = NULL;
	SPIN_LOCK_IRQSAVE(&cardlist_lock, cardflags)
	for (curdpthost = cardlist; curdpthost; curdpthost = dpthost->next) {
		/*
		 * If found host, delete it from linked list
		 */
		if (curdpthost == dpthost) {
			if (cardlist == dpthost) {
				cardlist = dpthost->next;
			} else {
				/*
				 * not removing from beginning of list
				 */
				prevdpthost->next = dpthost->next;
			}
			break;
		}
		prevdpthost = curdpthost;
	}
	SPIN_UNLOCK_IRQRESTORE(&cardlist_lock, cardflags)
	/*
	 * TODO !!!! free devinfo structures
	 */
	/*
	 * Don't set donetq to null unless is last adapter to be released.
	 */
	if (cardlist == NULL) {
		KWDEBUG(dbg_release, printk("dpt_release: cardlist = NULL\n");)
		donetq.head = NULL;
		donetq.tail = NULL;
		kfree(i2osystemtab);
		i2osystemtab = NULL;
	}

	if (host->irq) {
		free_irq(host->irq, dpthost);
	}
	iounmap((void *)(((unsigned long)dpthost->VirtualBaseAddress_P) & PAGE_MASK));
	if (scratchbuf != NULL) {
		kfree((UINT8 *) scratchbuf);
		scratchbuf = NULL;
	}
	kfree(dpthost->dptmsgs);
	dpthost->dptmsgs = NULL;
	dpt_deletedevs(dpthost);
	return 0;
}

/**********************************************************************
 * dpt_inquiry sends an inquiry command to the IOP.  The response tells
 * us what type of adapter it is.  A TID of 0 indicates the inquiry
 * commands is for the IOP.
 * 
 * NOTE:  The dpt card appears to have a bug.  It seems to continue to
 * write to memory AFTER the inquiry command has been returned.  Thus,
 * I have added a delay of 2000 milliseconds (or 2 seconds) after calling 
 * dpt_inquiry.
 ***********************************************************************/
VOID
dpt_inquiry(pDPT_HBA_T dpthost)
{
  pDPT_MSG_T DptMsg_P;
  pDPT_MSG_T DptMsgReturn_P;
  PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE ExecScsiMsg_P;
#ifdef DPTDEBUG
  int wait;
#endif
  UINT16 MessageSize = (sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE) -
                    sizeof(I2O_SG_ELEMENT)) >> 2;
  UINT8 SglOffset = (UINT8)(MessageSize << 4);
#ifdef LOCALONSTACK
	UINT8   localmsg[MAX_MESSAGE_SIZE];
#endif

	KWDEBUG(dbg_inquiry, printk("dpt_inquiry: Entered\n");)


	memset((UINT8 *) scratchbuf, 0, SCRATCHBUFSIZE);
       //
       // Allocate a request message packet for the command
       //
        DptMsg_P = dpti_AllocDptMsg(dpthost);

        //
        // If we could not allocate a message exit this loop
        //
        if(DptMsg_P == NULL)
         {
                  return;
         }

#ifdef LOCALONSTACK
		DptMsg_P->LocalToIopMsg = (UINT8 *)&localmsg;
        	memset(&localmsg, 0, MAX_MESSAGE_SIZE);
#endif
               ExecScsiMsg_P = (PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)(DptMsg_P->LocalToIopMsg);
               DptMsg_P->Flags |=  MSG_FLAG_INQUIRY;
               DptMsg_P->scsicmd = NULL;

               //
               // Set up the standard header
               //
               ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.
                                    VersionOffset = SglOffset | I2O_VERSION_11;
               ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.MsgFlags = 0;
               ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.MessageSize =
                                                                   MessageSize; 
		/*
		 * A TID of 0 indicates the IOP
		 */
               ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.
                                     TargetAddress = 0;
               ExecScsiMsg_P->TID = 0;
               ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.
                                                      InitiatorAddress = 1;
               ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.Function = 
                                                        I2O_PRIVATE_MESSAGE;
               ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.
                                                       InitiatorContext = DptMsg_P->unique;

               //
               // Fill out the remaining fields of the message
               //
               ExecScsiMsg_P->PrivateMessageFrame.TransactionContext = 
                                       (I2O_TRANSACTION_CONTEXT)DptMsg_P;
               ExecScsiMsg_P->PrivateMessageFrame.OrganizationID = 
                                                     DPT_ORGANIZATION_ID;
               ExecScsiMsg_P->PrivateMessageFrame.XFunctionCode = 
                                                          I2O_SCSI_SCB_EXEC;
  		memset((UINT8 *)&ExecScsiMsg_P->CDB, 0, I2O_SCSI_CDB_LENGTH);
               ExecScsiMsg_P->CDBLength = 6;
  		ExecScsiMsg_P->SCBFlags = I2O_SCB_FLAG_ENABLE_DISCONNECT | 
					 I2O_SCB_FLAG_XFER_FROM_DEVICE |
                            I2O_SCB_FLAG_SIMPLE_QUEUE_TAG |
                            I2O_SCB_FLAG_SENSE_DATA_IN_MESSAGE;
               ExecScsiMsg_P->CDB[0] = INQUIRY;
               ExecScsiMsg_P->CDB[4] = 36;
               ExecScsiMsg_P->ByteCount = 36;
               ExecScsiMsg_P->Interpret = 1;

               //
               // Set up a single simple scatter gather element
               //
               ExecScsiMsg_P->SGL.u.Simple[0].FlagsCount.Count = 36;
               ExecScsiMsg_P->SGL.u.Simple[0].FlagsCount.Flags = 
                                          I2O_SGL_FLAGS_LAST_ELEMENT | 
                                          I2O_SGL_FLAGS_END_OF_BUFFER | 
                                          I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT;
               ExecScsiMsg_P->SGL.u.Simple[0].PhysicalAddress = 
					virt_to_phys(scratchbuf);

               //
               // Bump the message size by two to allow for the 
               // Scatter Gather entry
               //
               ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.
                                                          MessageSize += 2;

             DptMsg_P->MSG_Post_P = dpti_DrvrRequestPost;
               DptMsg_P->TimeoutValue = 0;

	/*
	 * wait up to 30 seconds
	 *
	 * Note:  tried to send this using regular interrupts.  It worked with one
	 * card but broke when adding multiple cards.
	 */
        DptMsgReturn_P = dpti_SendPolledCommand(dpthost,DptMsg_P, 30, 0);

	memset(&(dpthost->name), 0, sizeof(dpthost->name));
        //
        // Check to make sure that this is the one we sent out
        //
        if(DptMsgReturn_P == DptMsg_P) {

		/*	memcpy(to, from, size) */
		memcpy(&(dpthost->name), "Vendor: DPT ", 11);
		memcpy(&(dpthost->name[11]), " Model: ", 8);
		memcpy(&(dpthost->name[19]), (UINT8 *) &scratchbuf[16], 16);
		memcpy(&(dpthost->name[35]), " Rev: ", 6);
		memcpy(&(dpthost->name[41]), (UINT8 *) &scratchbuf[32], 4);
		dpthost->name[45] = '\0';	/* precautionary */
		KWDEBUG(dbg_inquiry, printk("dpt_inquiry:  name = %s\n", (dpthost->name));)
		KWDEBUG(dbg_inquiry, 
			printk("data = "); 
			for (wait = 0; wait < 36; wait++) { 
				if (scratchbuf[wait] >= 0x20) { 
					printk("%c ", scratchbuf[wait]); 
				} 
			} 
			printk("\n");)
 		dpti_FreeDptMsg(dpthost, DptMsg_P);
	} else {
		sprintf(dpthost->name, "DPT SmartRaid V");
		printk("dpt_inquiry: Timed Out\n");
	}
	return;

}


//-------------------------------------------------------------------------
//                         Function dpt_flush                               
//-------------------------------------------------------------------------
// There Are No Parameters Passed Into This Function                       
//                                                                         
// This function is called before resetting the board. A flush cache      
// command is issued to all devices.                                       
//                                                                         
// Return : None                                                           
//-------------------------------------------------------------------------

VOID 
dpt_flush(pDPT_HBA_T dpthost)
{
  INT32 Channel,Target,Lun;
  pDPT_MSG_T DptMsg_P;
  pDPT_MSG_T DptMsgReturn_P;
  PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE ExecScsiMsg_P;
  pDEVINFO_T DevInfo_P;  
  UINT16 MessageSize = (sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE) -
                    sizeof(I2O_SG_ELEMENT)) >> 2;
  UINT8 SglOffset = (UINT8)(MessageSize << 4);
#ifdef LOCALONSTACK
	UINT8   localmsg[MAX_MESSAGE_SIZE];
#endif


	KWDEBUG(dbg_flush, printk("dpt_flush: Entered\n");)


     //
     // Loop through all channels on this adapter 
     //
     for(Channel = 0; Channel <= dpthost->MaxChannel; ++Channel)
      {
   
        //
        // Loop Through All Target IDs On This Adapter 
        //
        for(Target = 0; Target <= dpthost->MaxID; ++Target) {

            //
            // If this is the HBA ID, move on
            //
            if(Target == dpthost->ChannelInfo[Channel].ScsiTargetID) {
               continue;
             }

            //
            // Loop Through All Luns On This Target ID 
            //
            for(Lun = 0; Lun <= dpthost->MaxLUN; ++Lun)
             {

               //
               // Get the device structure from the lookup table
               //
               DevInfo_P = dpti_GetDevFromTable(dpthost,Channel,Target,Lun);

               //
               // If there is no device at this LUN, continue
               //
               if(DevInfo_P == NULL)
                {
                  continue;
                }

               //
               // Allocate a request message packet for the command
               //
               DptMsg_P = dpti_AllocDptMsg(dpthost);

               //
               // If we could not allocate a message exit this loop
               //
               if(DptMsg_P == NULL)
                {
                  break;
                }

               //
               // Put the device info structure in the message packet
               //
               DptMsg_P->DevInfo_P = DevInfo_P;

               //
               // Fill out the local copy of the request message for a
               // synchronize cache SCSI command
               //
#ifdef LOCALONSTACK
		DptMsg_P->LocalToIopMsg = (UINT8 *)&localmsg;
        	memset(&localmsg, 0, MAX_MESSAGE_SIZE);
#endif
               ExecScsiMsg_P = (PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)(DptMsg_P->LocalToIopMsg);
               DptMsg_P->Flags = 0;
               DptMsg_P->scsicmd = NULL;

               //
               // Set up the standard header
               //
               ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.
                                    VersionOffset = SglOffset | I2O_VERSION_11;
               ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.MsgFlags = 0;
               ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.MessageSize =
                                                                   MessageSize; 
               ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.
                                     TargetAddress = DptMsg_P->DevInfo_P->TID;
               ExecScsiMsg_P->TID = DptMsg_P->DevInfo_P->TID;
               ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.
                                                      InitiatorAddress = 1;
               ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.Function = 
                                                        I2O_PRIVATE_MESSAGE;
               ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.
                                                       InitiatorContext = DptMsg_P->unique;

               //
               // Fill out the remaining fields of the message
               //
               ExecScsiMsg_P->PrivateMessageFrame.TransactionContext = 
                                       (I2O_TRANSACTION_CONTEXT)DptMsg_P;
               ExecScsiMsg_P->PrivateMessageFrame.OrganizationID = 
                                                     DPT_ORGANIZATION_ID;
               ExecScsiMsg_P->PrivateMessageFrame.XFunctionCode = 
                                                          I2O_SCSI_SCB_EXEC;
  		memset((UINT8 *)&ExecScsiMsg_P->CDB, 0, I2O_SCSI_CDB_LENGTH);
               ExecScsiMsg_P->CDBLength = 10;
               ExecScsiMsg_P->SCBFlags = I2O_SCB_FLAG_ENABLE_DISCONNECT | 
                                                I2O_SCB_FLAG_SIMPLE_QUEUE_TAG;
               ExecScsiMsg_P->CDB[0] = FLUSH_CACHE_CMD;
               ExecScsiMsg_P->ByteCount = 0;

               //
               // Set up a single simple scatter gather element
               //
               ExecScsiMsg_P->SGL.u.Simple[0].FlagsCount.Count = 0;
               ExecScsiMsg_P->SGL.u.Simple[0].FlagsCount.Flags = 
                                          I2O_SGL_FLAGS_LAST_ELEMENT | 
                                          I2O_SGL_FLAGS_END_OF_BUFFER | 
                                          I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT;
               ExecScsiMsg_P->SGL.u.Simple[0].PhysicalAddress = 0;

               //
               // Bump the message size by two to allow for the 
               // Scatter Gather entry
               //
               ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.
                                                          MessageSize += 2;

               //
               // No posting or timeout routine set up for this one
               //
               DptMsg_P->MSG_Post_P = 0;
               DptMsg_P->TimeoutValue = 0;

               //
               // Send off the command polled
               //
               DptMsgReturn_P = dpti_SendPolledCommand(dpthost,DptMsg_P,1, 0);

               //
               // Free up the message request and reply packet
               //
               if(DptMsgReturn_P != NULL)
                {
                  dpti_FreeDptMsg(dpthost, DptMsg_P);
                }

             } //for(Lun = 0; Lun <= dpthost->MaxLUN; ++Lun

         } //for(Target = 0; Target <= dpthost->MaxID; ++Target) 


      } //for(Channel = 0; Channel <= dpthost->MaxChannel; ++Channel)

  return;
}




/*
 * ASSUMPTIONS:  HBA_FLAGS_IN_RESET has already been set (but will
 *		 set it again just in case it hasn't)
 *
 * NOTE:  IN the 2.2.2 tree, dpt_reset is called with the io_request_lock
 * held.
 *
 * Strategy:
 *	1) send flush cache command to all devices
 *	2) send iopreset
 *	3) send initoutboundqueues
 *	4) send setsystab
 *	5) send enablesys
 *	6) send LCT notify
 *	7) fail commands
 *
 * RETURNS:
 * 	0 - success
 *	1 - failure
 */
static int
dpt_resethost(pDPT_HBA_T dpthost)
{
	pDPT_MSG_T	dptmsg;
	Scsi_Cmnd	*cmd;
	int		error = 0;
	unsigned	long flags2;

	/*
	 * TODO!!! use disable_irq instead of cli while calling interrupt
	 * service routine
	 */

	KWDEBUG(dbg_dptresethost,  printk("dpt_resethost: Entered\n");)

	SPIN_LOCK_IRQSAVE(&dpthost->flaglock, flags2)
	if (!(dpthost->Flags & HBA_FLAGS_IN_RESET)) {
		dpthost->Flags |= HBA_FLAGS_IN_RESET;
		printk("dpti2o: dpt_resethost: Warning - ASSERT - device does not have HBA_FLAGS_IN_RESET set: setting it now.\n");
	}
#if 0
	dpthost->Flags &= ~HBA_FLAGS_INSTALLED_B;
#endif
	SPIN_UNLOCK_IRQRESTORE(&dpthost->flaglock, flags2)
	/*
	 * Send a flush cache command to all devices.  This is done polled which
	 * allows for a time limit in the event the board cannot recover.
	 */
	dpt_flush(dpthost);

       /*
        * First try to reset the adapter, if it fails move on
        */
	if((error = dpti_iopreset(dpthost->VirtualBaseAddress_P))) {
		printk("dpti20: dpt_resethost:  Iop Reset Failed: Cannot reset host %d, Errno %d\n", dpthost->cardidx, error);
		SPIN_LOCK_IRQSAVE(&dpthost->flaglock, flags2)
		dpthost->Flags |= HBA_HOSTRESET_FAILED;
		SPIN_UNLOCK_IRQRESTORE(&dpthost->flaglock, flags2)
		error = 1;
		goto finish;
	}
	/*
	 * Initialize the From IOP Queue, if it fails move on
	 */
	if(dpti_I2oInitFromIopQueue(dpthost->VirtualBaseAddress_P, (PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME) dpthost->FromIopMsg,	
                       dpthost->maxfromiopmsgs)) {
		printk("dpti20: dpt_resethost:  dpti_I2oInitFromIopQueue failed: CANNOT RESET HOST %d \n", dpthost->cardidx);
		SPIN_LOCK_IRQSAVE(&dpthost->flaglock, flags2)
		dpthost->Flags |= HBA_HOSTRESET_FAILED;
		SPIN_UNLOCK_IRQRESTORE(&dpthost->flaglock, flags2)
		error = 1;
		goto finish;
	}
	/*
	 * Send down the I2O system table to the HBA. If it fails, print
	 * an error message and ignore the error.
	 */
	if((error = dpti_I2oSetSysTab(dpthost, (UINT8 *)i2osystemtab,
                              sizeof(I2O_SYSTEM_TABLE_T), 0,0,0,0))) {
		printk("dpt_resethost: Could Not Issue Set System Table For HBA %d : Error %d.  Trying to continue.\n",
			dpthost->cardidx, error);
	 }
	/*
	 * Send down the I2O Enable System command to the HBA. If it fails,
	 * print an error message and ignore the error.
	 */
	if((error = dpti_I2oEnableSys(dpthost))) {
		printk("Could Not Issue Enable System For HBA %d : Error %d\n",
			dpthost->cardidx, error);
		SPIN_LOCK_IRQSAVE(&dpthost->flaglock, flags2)
		dpthost->Flags |= HBA_HOSTRESET_FAILED;
		SPIN_UNLOCK_IRQRESTORE(&dpthost->flaglock, flags2)
		error = 1;
		goto finish;
	 }
	if((error = dpti_I2oLCTNotify(dpthost, NULL, 0))) {
		printk("Could Not Issue LCT Notify For HBA %d : Error %d\n",
			dpthost->cardidx, error);
		SPIN_LOCK_IRQSAVE(&dpthost->flaglock, flags2)
		dpthost->Flags |= HBA_HOSTRESET_FAILED;
		SPIN_UNLOCK_IRQRESTORE(&dpthost->flaglock, flags2)
		error = 1;
		goto finish;
	}


	/*
	 * Note:  the commands on the reset queue and sendq have already
	 * had a dptmsg allocated and have their cmd->scsi_done routine
	 * set correctly (these were set up in dpt_queue before the
	 * commands were enqueued)
	 *
	 * ALL commands must be removed from the reset and send queues
	 *	BEFORE calling dpt_finish_commands, or will get into
	 * 	infinite loop of requeuing and deleting commands.
	 * 
	 * MUST keep RESET flag set until removed everything from queues
	 */
	/*
	 * take them off of the reset queue and put them on the done queue.
	 */
finish:

	DEQUEUE(cmd, Scsi_Cmnd, dpthost->resetq, host_scribble, dpthost->resetq_lock)
	while (cmd) {
		/*
		 * IF cmd->host is dpthost, do error, else requeue
		 */
		dptmsg = (pDPT_MSG_T)cmd->SCp.ptr;
		cmd->SCp.ptr = NULL;    /* clear ptr to dptmsg */
		cmd->result = DID_RESET << 16;
           	dpti_FreeDptMsg(dpthost, dptmsg);
		ENQUEUE(cmd, Scsi_Cmnd, dpthost->doneq, host_scribble, dpthost->doneq_lock)
		DEQUEUE(cmd, Scsi_Cmnd, dpthost->resetq, host_scribble, dpthost->resetq_lock)
	}
	/*
	 * take them off of the sendq and put them on the done queue
	 */
	DEQUEUE(cmd, Scsi_Cmnd, dpthost->sendq, host_scribble, dpthost->sendq_lock)
	while (cmd) {
		dptmsg = (pDPT_MSG_T)cmd->SCp.ptr;
		cmd->SCp.ptr = NULL;    /* clear ptr to dptmsg */
		cmd->result = DID_RESET << 16;
           	dpti_FreeDptMsg(dpthost, dptmsg);
		ENQUEUE(cmd, Scsi_Cmnd, dpthost->doneq, host_scribble, dpthost->doneq_lock)
		DEQUEUE(cmd, Scsi_Cmnd, dpthost->sendq, host_scribble, dpthost->sendq_lock)
	}

	SPIN_LOCK_IRQSAVE(&dpthost->flaglock, flags2)
	if (error == 0) {
		/*
		 * If no error, mark the board as good.  dpt_queue and
		 * dpti2o_intr will work again
		 */
#if 0
		dpthost->Flags |= HBA_FLAGS_INSTALLED_B;
#endif
	}
	dpthost->Flags &= ~HBA_FLAGS_IN_RESET;
	SPIN_UNLOCK_IRQRESTORE(&dpthost->flaglock, flags2)

	/*
	 * NOTE: the io_request_lock is held when dpt_reset is called
	 */

	dpt_finish_commands(dpthost);

	KWDEBUG(dbg_dptresethost,  printk("dpt_resethost: Finished\n");)
	return(0);	/* return success */
}


/*
 * ASSUMPTIONS:  flaglock is held
 *
 * If set = 1, set the flag, if 0, clear the flag
 */
void
dpt_setdevflags(pDPT_HBA_T dpthost, INT32 channel, UINT32 flagbits, int set)
{
	pDEVINFO_T devp;
	int target;

	KWDEBUG(dbg_setdevflags,  printk("dpt_setdevflags: Entered\n");)

	/*
	 * loop through targets on the channel and set the device flag
	 */
	for (target = 0; target < dpthost->MaxID && target < MAX_TARGET_ID; target++) {
		/*
		 * If this is the HBA ID, skip it
		 */
		if (target == dpthost->ChannelInfo[channel].ScsiTargetID) {
			continue;
		}
		devp = dpthost->ScsiDeviceTable_P[channel][target];
		while (devp) {
			if (set) {
				devp->Flags |= flagbits;
			} else {
				devp->Flags &= ~flagbits;
			}
			devp = devp->NextLun_P;
		}
	}
}

/*
 * Strategy:
 *
 * NOTE:  IN the 2.2.2 tree, dpt_reset is called with the io_request_lock
 * held.
 *
 * Before processing the reset, we mark each device being reset as IN_RESET.
 * Then, we process any pending interrupts.  
 *
 * Note:  Must check for when the reset command is returned in the interrupt
 *	  handler and send a DID_RESET return to the layer above.  The 
 *	  reset command will succeed (if it is supported), and we don't want
 *	  to send success to the layer above, because the layer above would
 *	  think the cmd it sent down succeeded (it was only used as a 
 *	  place-holder to issue the reset command).  By sending back
 *	  DID_RESET, the command will be reissued (not the reset command,
 *	  but the real commmand). NO!! Se comment below.
 *
 * Note:  We are clearing the flag indicating we are in reset at the end
 *	  of the routine instead of in the interrupt handler to insure it
 *	  gets cleared.  If the reset doesn't work and we never come back
 *	  we don't want the flag set.  Also, in the interrupt handler, we
 *	  don't know which devices to clear.  Any outstanding commands will
 *	  eventually timeout in the upper scsi code.
 *
 * Note:  If the command is synchronous, there is no outstanding request to
 *	  the board with the command (no dptmsg), so return the command
 *	  with DID_RESET set at the end of this routine.  If the command
 *	  is asynchronous, there is an outstanding request to the board
 *	  (with a dptmsg), and the command will be returned from the board
 *	  AFTER the reset occurs, with an error (this is OK).  Either way,
 *	  a new dpdtmsg must be allocated when sending the reset.
 *
 * Note:  If there are no dptmsgs, send back failure.  The reset will be
 *	  escalated by the upper level scsi code to reset bus and then reset 
 *	  host.
 *
 * Note:  After receiving acknowledgment of the reset, we send the commands
 *	  on the reset queue to the board ??? unless I do it at end of 
 *	  routine
 *	 
 *
 * device reset:  A device reset happens quickly.  So, we do not need to 
 *	delay any after sending the device reset command (the command is
 *	not currently supported, but we send it anyway).
 *	After a device reset, outstanding commands on the board will be
 *	returned with a reset error.  So, we do not need to clean up and 
 *	return the commands ourselves.  We dequeue the waiting commands
 *	and send them to the board AFTER clearing the flag we are in reset
 *
 * bus reset:  A bus reset will be done by issuing the I20_HBA_BUS_RESET
 *	command.  It takes a while to take affect, so we must wait 1 second
 *	after issuing the command to ensure it has had time to complete.
 *	After a bus reset, outstanding commands on the board will be
 *	returned with a reset error.  So, we do not need to clean up and 
 *	return the commands ourselves.  We dequeue the waiting commands
 *	and send them to the board after waiting 1 second and AFTER clearing
 *	the flag indicating we are in reset.
 *	
 * host reset:  A host reset is accomplished by sending an IOPreset and
 *	many other commands.  outstanding commands on the board that have
 *	not been acked up to our interrupt handler will be lost, so we must
 *	clean up and return all outstanding commands to the scsi layer
 *	above with a DID_RESET error.
 */


int
dpt_reset(Scsi_Cmnd *cmd, unsigned int flags)
{
	pDPT_HBA_T	dpthost;	/* host bus adapter structure */
	unsigned long flags2;
	pDEVINFO_T	dptdevice;	/* dpt per device information */
	pDPT_MSG_T	dptmsg;
  	INT32 error = 0;
	int result = 0;
	int noerror = 1;	/* if true, no errors, dequeue commands */

	KWDEBUG(dbg_reset,  printk("dpt_reset: Entered\n");)

	dpthost = (pDPT_HBA_T)cmd->host->hostdata;

	if ((dptdevice = (pDEVINFO_T)(cmd->device->hostdata)) == NULL) {
		printk("dpti2o: dpt_reset: Unable to do reset: No device found in command\n");
		return(SCSI_RESET_ERROR);
	}
	/*
	 * First, set DEV_IN_RESET flag for all devices to be reset.  This
	 * MUST be done BEFORE clearing all interrupts, so no more requests
	 * will be sent to the adapter after clearing interrupts
	 */
	/* depending on flags, set the device, all devices on channel, etc. */
	/*
	 * Note:  if resetting the entire host, do not need to set device
	 * flag indicating are resetting because will be disabling the
	 * host during reset, so set the host flag HBA_FLAGS_IN_RESET.  This
	 * flag is checked for in dpt_queue.
	 */

	/*
	 * IF THE DEVICE OR HOST HAS RESET FLAG SET, SEND THIS BACK AS PENDING 
	 */

	SPIN_LOCK_IRQSAVE(&dpthost->flaglock, flags2)
	if ((dpthost->Flags & HBA_FLAGS_IN_RESET) || (dptdevice->Flags & DEV_IN_RESET)) {
		SPIN_UNLOCK_IRQRESTORE(&dpthost->flaglock, flags2)
		printk("dpt_reset: Reset Pending\n");
		return (SCSI_RESET_PENDING);
	}
	if (dpthost->Flags & HBA_HOSTRESET_FAILED) {
		SPIN_UNLOCK_IRQRESTORE(&dpthost->flaglock, flags2)
		printk("dpt_reset: HBA RESET FAILED\n");
		return (SCSI_RESET_ERROR);
	}
	if (flags & SCSI_RESET_SUGGEST_BUS_RESET) {
		dpt_setdevflags(dpthost, cmd->channel, DEV_IN_RESET, 1);
	} else if (flags & SCSI_RESET_SUGGEST_HOST_RESET) {
		dpthost->Flags |= HBA_FLAGS_IN_RESET;
	} else {
		/*
		 * just reset the device
		 */
		dptdevice->Flags |= DEV_IN_RESET;
	}
	SPIN_UNLOCK_IRQRESTORE(&dpthost->flaglock, flags2)
	
	/*
	 * Second, process any pending interrupts in case it will free
	 * up something that has timed out
	 */
	/*
	 * In the 2.2.xx tree, the io_request_lock is held.  Since the
	 * lock is grabbed in dpti2o_intr, we don't want to call it.
	 */
#if LINUX_VERSION_CODE < 0x020100
	disable_irq(dpthost->host->irq);
	dpti2o_intr(dpthost->host->irq, dpthost, (void *)NULL);
	enable_irq(dpthost->host->irq);
#endif

	/*
	 * If this is an Asynchronous Reset and this Command has already 
	 * completed, then no Reset is necessary.
	 *
	 * The Asynchronous requests are called from the scsi timeout code,
	 * thus the command may have completed, and had the timeout go off
	 * before it was cleared.
	 */
	if (flags & SCSI_RESET_ASYNCHRONOUS) {
		/*
		 * If the serial number information is not correct, it is
		 * a different command.
		 */
		if (cmd->serial_number != cmd->serial_number_at_timeout) {
			printk("dpti2o: dpt_reset: Unable to reset channel %d, target %d lun %d.  Reset called with a finished or different command\n",
			cmd->channel, cmd->target, cmd->lun);
			noerror = 0;
			result = SCSI_RESET_NOT_RUNNING;
		}
		/*
		 * Loop through active messages to verify the message
		 * that timed out has not already been completed
		 */
		SPIN_LOCK_IRQSAVE(&dpthost->MsgListLock, flags2)
		for (dptmsg = dpthost->DptMsgActiveList_P; dptmsg != NULL; 
			dptmsg = dptmsg->Next_P) {
			if (dptmsg->scsicmd == cmd) {
				break;
			}
		}
		if (dptmsg == NULL) {
			printk("dpti2o: dpt_reset: Unable to reset channel %d, target %d lun %d.  No command found\n",
				cmd->channel, cmd->target, cmd->lun);
			noerror = 0;
			result = SCSI_RESET_NOT_RUNNING;
		}
		SPIN_UNLOCK_IRQRESTORE(&dpthost->MsgListLock, flags2) 
	} else if (flags & SCSI_RESET_SYNCHRONOUS) {
		/*
		 * do nothing - in buslogic, they send scsi_reset_pending
		 * if this command is having a reset done on it
		 */
	} 
	if (!noerror) {
		goto cleanup;
	}
#if 0

	if not soon enough since last reset, send some error back?
#endif


	if (flags & SCSI_RESET_SUGGEST_BUS_RESET) {
		/*
		 * Do a device reset.  Must wait 1 second afterwards.
		 * delay 1 second so devices can settle out.
		 */
		if ((error = dpti_ResetScsiBus(dpthost, (UINT32)cmd->channel,0))
			 == 0x0ff) {
			/*
		 	 * we were out of messages, return an error
		 	 */
			noerror = 0;
			result = SCSI_RESET_ERROR;
		} else {
			result = SCSI_RESET_PENDING;
			/*
		 	 * NOTE:  dpt_delay must not have interrupts blocked
		 	 * when called, or it won't work
		 	 */
			dpt_delay(1000);	/* delay 1 second */
		}

	} else if (flags & SCSI_RESET_SUGGEST_HOST_RESET) {
		error = dpt_resethost(dpthost);
		result = (error == 0) ? SCSI_RESET_SUCCESS : SCSI_RESET_ERROR;  /* Must clear out queue */
	} else {
		/*
		 * Do a device reset.  Requires no waiting afterwards.
		 * Currently, the dpt card does not support device
		 * reset.  Am sending it anyway and setting return to
		 * SCSI_RESET_PENDING because the layer above will
		 * eventually retimeout and send a bus reset.  This way,
		 * if the card ever supports it, it will be called
		 * correctly
		 */
		error = dpti_ResetDevice(dpthost,
					(UINT32)cmd->channel, 
					(UINT32)cmd->target, 
					(UINT32)cmd->lun, 0);
		/*
	 	 * if error = 0x0ff, we were out of messages, return an error
	 	 */
		result = (error == 0x0ff) ? SCSI_RESET_ERROR : SCSI_RESET_PENDING;

	}
#if 0
	if not an error, reset the jiffies and timeout like dougs driver
	also reset jiffies in interrupt handler - doDriver - when request
		comes back as completed (if it was successful)

#endif

cleanup:

	SPIN_LOCK_IRQSAVE(&dpthost->flaglock, flags2)
	if (flags & SCSI_RESET_SUGGEST_BUS_RESET) {
		/*
		 * unset the flag for every device on the channel (bus)
		 * 0 indicates unset
		 */
		dpt_setdevflags(dpthost, cmd->channel, DEV_IN_RESET, 0);
	} else if (flags & SCSI_RESET_SUGGEST_HOST_RESET) {
		/*
		 * Note: HBA_FLAGS_IN_RESET must be cleared in dpt_resethost
		 * before dpt_resethost can return the outstanding commands
		 * back to the upper scsi level.  Do it again here just
		 * in case it wasn't cleared, but print a message it wasn't
		 * cleared.  Should really be an assert.
		 */
		if (dpthost->Flags & HBA_FLAGS_IN_RESET) {
			dpthost->Flags &= ~HBA_FLAGS_IN_RESET;
			printk("dpti2o: dpt_reset: Warning - ASSERT - device has HBA_FLAGS_IN_RESET set incorrectly: unsetting now.\n");
		}
	} else {
		/*
		 * just unset the device
		 */
		dptdevice->Flags &= ~DEV_IN_RESET;
	}

	/*
	 * dequeue reset commands, add them to send queue and send them
	 * off. Note: DEV_IN_RESET flag MUST be cleared before
	 * doing this
	 */
	/*
	 * May not have to check this flag if return under this case
	 * above.  Check is done to be safe
	 *
	 * send commands to board unless did a HOST RESET.
	 * 
	 * Note:  even if is an error, send them on.  Otherwise, they
	 * will timeout anyway
	 */
	if (noerror && (!(flags & SCSI_RESET_SUGGEST_HOST_RESET))) {
		DEQUEUE(cmd, Scsi_Cmnd, dpthost->resetq, host_scribble, dpthost->resetq_lock)
		while (cmd) {
			ENQUEUE(cmd, Scsi_Cmnd, dpthost->sendq, host_scribble, dpthost->sendq_lock)
			DEQUEUE(cmd, Scsi_Cmnd, dpthost->resetq, host_scribble, dpthost->resetq_lock)
		}
		SPIN_UNLOCK_IRQRESTORE(&dpthost->flaglock, flags2)
		dpt_docmd((void *)dpthost);
	} else {
		SPIN_UNLOCK_IRQRESTORE(&dpthost->flaglock, flags2)
	}
	
	/* If the command is synchronous, and the reset was successful, there 
	 * is no outstanding request to the board with the command (no dptmsg),
	 * so return the command with DID_RESET set.  If the command is 
	 * asynchronous, there is an outstanding request to the board 
	 * (with a dptmsg), and the command will be returned from the board 
	 * AFTER the reset occurs, with an error (which is what you want so 
	 * the command will be reissued).
	 */
	if (flags & SCSI_RESET_SYNCHRONOUS) {
		cmd->result = DID_RESET << 16;
		cmd->scsi_done(cmd);
	}

	return (result);
}



//-------------------------------------------------------------------------
//                     Function dpti_ResetScsiBus                          
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     HbaNum : Host Adapter Number                                        
//     Channel : HBA Channel Number                                        
//     Poll : Command Poll Flag
//                                                                         
// This function will send off a SCSI Bus Reset for the passed in HBA and
// channel number 
//                                                                         
// Return : 0 for success, error code otherwise
//-------------------------------------------------------------------------

STATIC INT32 
dpti_ResetScsiBus(pDPT_HBA_T dpthost, INT32 Channel, INT32 Poll)
{
  PI2O_HBA_BUS_RESET_MESSAGE BusResetMsg_P;
  pDPT_MSG_T DptMsg_P;
  pDPT_MSG_T DptMsgReturn_P;
  INT32 Rtnval = 0x0ff;
  UINT16 MessageSize = sizeof(I2O_HBA_BUS_RESET_MESSAGE) >> 2;
  UINT8 SglOffset = 0;
#ifdef LOCALONSTACK
	UINT8   localmsg[MAX_MESSAGE_SIZE];
#endif


	KWDEBUG(dbg_resetscsibus,  printk("dpti_ResetScsiBus: Entered\n");)

  //
  // Allocate a message packet
  //
  DptMsg_P = dpti_AllocDptMsg(dpthost);
  if(DptMsg_P != NULL) {
     //
     // Grab a pointer to the local message pointer
     //
#ifdef LOCALONSTACK
	DptMsg_P->LocalToIopMsg = &localmsg[0];
        memset(&localmsg, 0, MAX_MESSAGE_SIZE);
#endif
     BusResetMsg_P = (PI2O_HBA_BUS_RESET_MESSAGE)(DptMsg_P->LocalToIopMsg);
     //
     // Fill out the standard header
     //
     BusResetMsg_P->StdMessageFrame.VersionOffset = SglOffset | 
                                                          I2O_VERSION_11;
     BusResetMsg_P->StdMessageFrame.MsgFlags = 0;
     BusResetMsg_P->StdMessageFrame.MessageSize = MessageSize;
     BusResetMsg_P->StdMessageFrame.TargetAddress = 
                        dpthost->ChannelInfo[Channel].TID;
     BusResetMsg_P->StdMessageFrame.InitiatorAddress = 1;
     BusResetMsg_P->StdMessageFrame.Function = I2O_HBA_BUS_RESET;
     BusResetMsg_P->StdMessageFrame.InitiatorContext = DptMsg_P->unique;
     BusResetMsg_P->TransactionContext = (I2O_TRANSACTION_CONTEXT)DptMsg_P;

     //
     // If the Poll flag is set, send off the command and wait for the
     // return.
     //
     if(Poll) {
        //
        // Send off the command polled
        //
        DptMsgReturn_P = dpti_SendPolledCommand(dpthost,DptMsg_P,0, 0);

        //
        // Check to make sure that this is the one we sent out
        //
        if(DptMsgReturn_P == DptMsg_P) {
           //
           // Good return for a success
           //
           if(DptMsg_P->Reply->StdReplyFrame.ReqStatus == 
                                            I2O_REPLY_STATUS_SUCCESS) {
              Rtnval = 0;
            }
         
            //
            // Bad return, if the detailed status code is set up, we will
            // return that, otherwisw return a 1
            //
            else {
                   if(DptMsg_P->Reply->StdReplyFrame.DetailedStatusCode) {
                      Rtnval = DptMsg_P->Reply->StdReplyFrame.DetailedStatusCode;
                    } else {
                           Rtnval = 1;
                    }
            }

           //
           // Put the message packet back on the free list
           //
           dpti_FreeDptMsg(dpthost, DptMsg_P);

         } //if(DptMsgReturn_P == DptMsg_P)

         //
         // Wrong packet returned, print an error message and set up an error
         //
         else {
		printk("dpti_ResetScsiBus: Wrong message Returned\n");
         }

      } else {
      		//
      		// We are not polling so send it off and set up a good return
      		//
             DptMsg_P->Flags |= MSG_FLAG_IS_RESET;
             DptMsg_P->scsicmd = NULL;

             //
             // Set up the posting address and timeout value for this message
             //
		/*
		 * NOTE:  CANNOT post to  dpti_OsRequestPost() because it
		 * expects the scsicmd field to be good!!
		 */

             DptMsg_P->MSG_Post_P = dpti_DrvrRequestPost;
             dpti_I2oSendMessage(dpthost,DptMsg_P);
             Rtnval = 0;
      }

   } //if(DptMsg_P != NULL)

  return(Rtnval);
}

//-------------------------------------------------------------------------
//                     Function dpti_ResetDevice                           
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     HbaNum : Host Adapter Number                                        
//     Channel : HBA Channel Number                                        
//     Target : Target ID For The Command                                  
//     Lun : Logical Unit Number For The Commnand                          
//     Poll : Command Poll Flag
//                                                                         
// This function will send off a SCSI Device Reset for the passed in  
// SCSI device address
//                                                                         
// Return : 0 for success, error code otherwise
//-------------------------------------------------------------------------

STATIC INT32 
dpti_ResetDevice(pDPT_HBA_T dpthost, INT32 Channel,
				INT32 Target, INT32 Lun,INT32 Poll)
{
  PI2O_SCSI_DEVICE_RESET_MESSAGE DeviceResetMsg_P;
  pDPT_MSG_T DptMsg_P;
  pDPT_MSG_T DptMsgReturn_P;
  INT32 Rtnval = 0x0ff;
  UINT16 MessageSize = sizeof(I2O_SCSI_DEVICE_RESET_MESSAGE) >> 2;
  UINT8 SglOffset = 0;
#ifdef LOCALONSTACK
	UINT8   localmsg[MAX_MESSAGE_SIZE];
#endif

	KWDEBUG(dbg_resetdevice,  printk("dpti_ResetDevice: Entered\n");)

	/*
	 * Allocate a message packet
	 */
	DptMsg_P = dpti_AllocDptMsg(dpthost);
	if(DptMsg_P != NULL) {
     //
     // Get the device from the lookup table
     //
     DptMsg_P->DevInfo_P = dpti_GetDevFromTable(dpthost,Channel,Target,Lun);

     //
     // First get the device structure
     //
     if(DptMsg_P->DevInfo_P) {

        //
        // Grab a pointer to the local message pointer
        //
#ifdef LOCALONSTACK
	DptMsg_P->LocalToIopMsg = &localmsg[0];
       	memset(&localmsg, 0, MAX_MESSAGE_SIZE);
#endif
        DeviceResetMsg_P = (PI2O_SCSI_DEVICE_RESET_MESSAGE)(DptMsg_P->LocalToIopMsg);
        //
        // Fill out the standard header
        //
        DeviceResetMsg_P->StdMessageFrame.VersionOffset = SglOffset | 
                                                             I2O_VERSION_11;
        DeviceResetMsg_P->StdMessageFrame.MsgFlags = 0;
        DeviceResetMsg_P->StdMessageFrame.MessageSize = MessageSize;
        DeviceResetMsg_P->StdMessageFrame.TargetAddress = 
                                            DptMsg_P->DevInfo_P->TID;
        DeviceResetMsg_P->StdMessageFrame.InitiatorAddress = 1;
        DeviceResetMsg_P->StdMessageFrame.Function = I2O_SCSI_DEVICE_RESET;
        DeviceResetMsg_P->StdMessageFrame.InitiatorContext = DptMsg_P->unique;
        DeviceResetMsg_P->TransactionContext = 
                                       (I2O_TRANSACTION_CONTEXT)DptMsg_P;

        //
        // If the Poll flag is set, send off the command and wait for the
        // return.
        //
        if(Poll) {
           //
           // Send off the command polled
           //
           DptMsgReturn_P = dpti_SendPolledCommand(dpthost,DptMsg_P,0, 0);

           //
           // Check to make sure that this is the one we sent out
           //
           if(DptMsgReturn_P == DptMsg_P) {
              //
              // Good return for a success
              //
              if(DptMsg_P->Reply->StdReplyFrame.ReqStatus == 
                                               I2O_REPLY_STATUS_SUCCESS)
               {
                 Rtnval = 0;
               }
            
               //
               // Bad return, if the detailed status code is set up, we will
               // return that, otherwisw return a 1
               //
               else {
                      if(DptMsg_P->Reply->StdReplyFrame.DetailedStatusCode)
                       {
                         Rtnval = 
                          DptMsg_P->Reply->StdReplyFrame.DetailedStatusCode;
                       }
                       else {
                              Rtnval = 1;
                       }
               }

              //
              // Put the message packet back on the free list
              //
              dpti_FreeDptMsg(dpthost,DptMsg_P);

            } //if(DptMsgReturn_P == DptMsg_P)

            //
            // Wrong packet returned, print an error message and set up an error
            //
            else {
		printk("dpti_ResetDevice: Wrong message Returned\n");
            }

         } //if(Poll)

         //
         // We are not polling so send it off and set up a good return
         //
         else {
             	DptMsg_P->Flags |= MSG_FLAG_IS_RESET;
                DptMsg_P->scsicmd = NULL;

                //
                // Set up the posting address and timeout value for this message
                //
		/*
		 * NOTE:  CANNOT post to  dpti_OsRequestPost() because it
		 * expects the scsicmd field to be good!!
		 */

		DptMsg_P->MSG_Post_P = dpti_DrvrRequestPost;
                dpti_I2oSendMessage(dpthost,DptMsg_P);
                Rtnval = 0;

         } //if(Poll) else

      } //if(DptMsg_P->DevInfo_P)

   } //if(DptMsg_P != NULL)


  return(Rtnval);
}





//-------------------------------------------------------------------------
//                     Function dpti_AbortMsg
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     DptMsg_P : DptMsg Structure Pointer To Be Aborted                  
//                                                                         
// This function will send off an Abort for the passed in  
// DPT Message Structure.
//                                                                         
// Return : 0 for success, error code otherwise
//-------------------------------------------------------------------------

STATIC INT32 
dpt_abortmsg(pDPT_HBA_T dpthost, pDEVINFO_T dptdevice, pDPT_MSG_T AbortDptMsg_P)
{
  PI2O_SCSI_SCB_ABORT_MESSAGE ScbAbortMsg_P;
  pDPT_MSG_T DptMsg_P;
  INT32 Rtnval = 0x0ff;
  UINT16 MessageSize = sizeof(I2O_SCSI_SCB_ABORT_MESSAGE) >> 2;
  UINT8 SglOffset = 0;
#ifdef LOCALONSTACK
	UINT8   localmsg[MAX_MESSAGE_SIZE];
#endif

	KWDEBUG(dbg_abortmsg,  printk("dpt_abortmsg: Entered\n");)

  //
  // Allocate a message packet
  //
  DptMsg_P = dpti_AllocDptMsg(dpthost);
  if(DptMsg_P != NULL) {
     //
     // Grab a pointer to the local message pointer
     //
#ifdef LOCALONSTACK
	DptMsg_P->LocalToIopMsg = &localmsg[0];
       	memset(&localmsg, 0, MAX_MESSAGE_SIZE);
#endif
     ScbAbortMsg_P = (PI2O_SCSI_SCB_ABORT_MESSAGE)(DptMsg_P->LocalToIopMsg);
     //
     // Fill out the standard header
     //
     ScbAbortMsg_P->StdMessageFrame.VersionOffset = SglOffset | 
                                                          I2O_VERSION_11;
     ScbAbortMsg_P->StdMessageFrame.MsgFlags = 0;
     ScbAbortMsg_P->StdMessageFrame.MessageSize = MessageSize;
     ScbAbortMsg_P->StdMessageFrame.TargetAddress = 
                                         dptdevice->TID;
     ScbAbortMsg_P->StdMessageFrame.InitiatorAddress = 1;
     ScbAbortMsg_P->StdMessageFrame.Function = I2O_SCSI_SCB_ABORT;
     ScbAbortMsg_P->StdMessageFrame.InitiatorContext = DptMsg_P->unique;
     ScbAbortMsg_P->TransactionContext = 
                                    (I2O_TRANSACTION_CONTEXT)DptMsg_P;
     ScbAbortMsg_P->TransactionContextToAbort = 
                               (I2O_TRANSACTION_CONTEXT)AbortDptMsg_P;

     DptMsg_P->Flags = 0;
     DptMsg_P->scsicmd = NULL;

	/*
	 * MAKE SURE THE POST ROUTINE FREES THE DPTMSG - IT DOES
	 */

     //
     // Set up the posting address and timeout value for this message
     //
     DptMsg_P->MSG_Post_P = dpti_DrvrRequestPost;
     dpti_I2oSendMessage(dpthost,DptMsg_P);
     Rtnval = 0;

	}

	return(Rtnval);
}


/*
 * Note: dpt_select_queue_depths is called AFTER the dpt_detect routine
 * has been called.  This guarantees the ScsiDeviceTable_P[] for the
 * host adapter has been filled in (via calling dpti_AddDevToTable)
 */
static void
dpt_select_queue_depths(struct Scsi_Host *host, Scsi_Device *devicelist)
{
	Scsi_Device	*device;	/* scsi layer per device information */
	pDPT_HBA_T	dpthost;
	pDEVINFO_T	dptdevice;	/* dpt per device information */
	int		numdev = 0;		/* number of devices attached to card */
	int		numluns = 1;	/* number of luns - assume they */
					/* are assigned incrementally - need */
					/* to verify this */

	KWDEBUG(dbg_selectqueuedepths, printk("dpt_select_queue_depths: Entered\n"););

	dpthost = (DPT_HBA_T *)host->hostdata;

	/*
	 * Note:  dpt_queue is called with a TEST_UNIT_READY command
	 * from scsn_scsis_single before dpt_select_queue_depth is called.
	 * So, the dptdevice should already be stored in the device's
	 * hostdata field (it should have been set in dpt_queue).  In
	 * case it wasn't, we set it here.
	 *
	 * Save a pointer to the dpt specific device information so we
	 * can retrieve the I2O TID of the device when requests are passed
	 * in to dpt_queue
	 */
	for (device = devicelist; device != NULL; device = device->next) {
		/*
		 * If the device is not attached to this adapter, skip it
		 */
		if (device->host != host) {
			continue;
		}
		numdev++;
		if (device->lun >= numluns) {
			numluns = device->lun + 1;
		}
		if ((dptdevice = dpti_GetDevFromTable(dpthost, 
				     (UINT32)device->channel,
                                     (UINT32)device->id, (UINT32)device->lun))
						!= NULL) {
			if (device->hostdata != dptdevice) {
				printk("dpti2o: dpt_select_queue_depths: dpti_GetDevFromTable returned device 0x%x, device->hostdata = 0x%x:  they don't match\n",
					(unsigned int) dptdevice, (unsigned int) device->hostdata);
			printk(" chan = %d, id = %d, lun = %d\n",
				device->channel, (unsigned int) device->id, (unsigned int) device->lun);
			}
			device->hostdata = (void *)dptdevice;
		} else {
			printk("dpti2o: dpt_select_queue_depths: dpti_GetDevFromTable returned NULL, chan = %d, id = %d, lun = %d\n",
				device->channel, device->id, device->lun);
		}
	}
	/*
	 * Loop through the devices and set the queue depth, now that we
	 * have counted the number of luns
	 */
	for (device = devicelist; device != NULL; device = device->next) {
		/*
		 * If the device is not attached to this adapter, skip it
		 */
		if (device->host != host) {
			continue;
		}
		if (numluns && host->can_queue) {
			/*
			 * set queue_depth to maxoutstanding commands divided by
			 * number of luns
			 * 
			 * maxoutstanding commands is stored in can_queue, or
			 * dpthost->QueueDepth = ToIopMessageCount
			 */
			device->queue_depth = host->can_queue / numluns;
			KWDEBUG(dbg_selectqueuedepths, printk("dpti2o: dpt_select_queue_depths: queue_depth = %dnumdev = %d, numluns = %d\n", device->queue_depth, numdev, numluns);)
		} else {
			device->queue_depth = 1;
			printk("dpti2o: dpt_select_queue_depths: numluns = 0\n");
		}
	}
	if (host->can_queue > 0) {
		host->cmd_per_lun = host->can_queue / numluns;
	} else {
		host->cmd_per_lun =  1;
	}

	KWDEBUG(dbg_selectqueuedepths, printk("dpti2o: dpt_select_queue_depths: cmd_per_lun  = %d, can_queue = %d\n", host->cmd_per_lun, host->can_queue);)
}





//-------------------------------------------------------------------------
//                      Function dpt_detect                                  
//-------------------------------------------------------------------------
// There Are No Parameters Passed Into This Function                       
//                                                                         
// This function is called by the OS at initalization time. The system  
// is scanned For HBAs. Once an HBA is found various structures are
// set up for the HBA and a list of all devices on the HBA is generated.
// Once all HBAs are found, a device lookup table is set up and then
// each HBA is enabled and presented to the OS.
//                                                                         
// Return : None                                                           
//-------------------------------------------------------------------------

int
dpt_detect(Scsi_Host_Template *sht)
{
	unsigned char	pcibus, pcifn;
	int		numcards = 0;	/* number of host adapters found */
	int		i;
	int 		error;
	struct pci_dev *pdev = NULL;

#if LINUX_VERSION_CODE < NEWPCI_VERSION
	int index = 0;
#endif	/* NEWPCI_VERSION */


	KWDEBUG(dbg_dptdetect, printk("DPT I2O: dpt_detect: entered.\n");)

	for (i = 0; i < MAXADAPTERS; i++) {
		dpti20cards[i] = NULL;
	}

#ifdef CONFIG_PCI

	if (!(PCI_PRESENT)()) {
		printk("DPT I2O:  PCI bios not present\n");
		return 0;
	}

#else	/* CONFIG_PCI */
	/*
	 * return failure if no PCI support 
	 */
	printk("DPT I2O:  PCI support not configured in this kernel\n");
	return 0;	

#endif	/* CONFIG_PCI */

	/* 
	 * fill in entry to support /proc file system
	 */
	sht->proc_dir = &proc_scsi_dptI2O;

	/*
	 * Zero out the I2O System Table 
	 * 	(dpt_configcard fills it in)
	 */
	if (i2osystemtab == NULL ) {

		if ((i2osystemtab = (I2O_SYSTEM_TABLE_T *)kmalloc(sizeof(I2O_SYSTEM_TABLE_T), GFP_ATOMIC)) == NULL) {
			printk("dpt_detect:  Could Not allocate I2o System Table\n");
			return(0);
		}
	}
	memset((UINT8 *)i2osystemtab, 0, sizeof(I2O_SYSTEM_TABLE_T));

	/*
	 * scratchbuf is needed for GetHrt call and LctNotify call
	 */
	if ((scratchbuf = (UINT8 *)kmalloc(SCRATCHBUFSIZE, GFP_ATOMIC)) == NULL) {
		kfree(i2osystemtab);
		i2osystemtab = NULL;
		printk("dpt_configcard:  could not allocate scratchbuf\n");
		return(0);	/* return failure */
	}
	memset((void *) scratchbuf, 0, SCRATCHBUFSIZE);

	KWDEBUG(dbg_dptdetect, printk("dbg_dptdetect:  scratchbuf = 0x%x, virt_to_phys(scratchbuf) = 0x%x, *scratch = 0x%x\n", (unsigned int) scratchbuf, (unsigned int) virt_to_phys(scratchbuf), *scratchbuf);)
  
	
	/*
	 * search for all DPT I2O SmartRAID V cards
	 */

#if LINUX_VERSION_CODE < NEWPCI_VERSION
	index = 0;
	while (!(pcibios_find_device((UINT16)PCI_DPT_VENDOR_ID,
                                   (UINT16)PCI_DPT_DEVICE_ID,
                                   index++, &pcibus, &pcifn)) ) {
#else	/* NEWPCI_VERSION */

	while ((pdev = pci_find_device((UINT16)PCI_DPT_VENDOR_ID,
                                     (UINT16)PCI_DPT_DEVICE_ID,
                                     pdev))) {
		pcibus = pdev->bus->number;
		pcifn  = pdev->devfn;

#endif	/* NEWPCI_VERSION */
	

		/*
		 * read pci configuration information and setup card
		 */
		numcards += dpt_configcard(sht, pcibus, pcifn, pdev);  /* was dpti_FindI2Ocard */
		dpt_delay(2000);	/* precaution due to inquiry command */
		memset((void *) scratchbuf, 0, SCRATCHBUFSIZE);
		KWDEBUG(dbg_dptdetect, printk("DPT I2O: dpt_detect: card configured: numcards = %d.\n", numcards);)
	}
	/*
	 * free scratchbuf after detecting cards.  If need to do hrtget
	 * or lctnotify later, must reallocate scratch buf
	 * See if not freeing scratch buf helps with dpt_inquiry
	 */
#if 0
	if (scratchbuf != NULL) {
		kfree(scratchbuf);
		scratchbuf = NULL;
	}
#endif
	/*
         * Send down the completed I2O system table to the HBA. We did this 
	 * initially, but now we have the complete system table.  If it fails, 
	 * print an error message and ignore the error.
	 */
	for (i = 0; i < numcards; i++) {
		if((error = dpti_I2oSetSysTab(dpti20cards[i], (UINT8 *)&i2osystemtab,
                                sizeof(I2O_SYSTEM_TABLE_T), 0,0,0,0))) {
			printk("dpt_detect: Could Not Issue Set System Table For HBA %d : Error %d\n",
                 i, error);
		}
	}
	KWDEBUG(dbg_dptdetect, printk("DPT I2O: dpt_detect: card configured: returning numcards = %d.\n", numcards);)
	return (numcards);	/* return failure while debugging */
}


/*
 * DID_ERROR will retry the command a few times and then abort it.
 * DID_BUS_BUSY will always retry the command.  You could get in an
 * infinite loop - so don't use it
 */
int
dpt_queue(Scsi_Cmnd *cmd, void (*cmdcomplete)(Scsi_Cmnd *))
{
	pDPT_HBA_T	dpthost;	/* host bus adapter structure */
	pDPT_MSG_T	dptmsg;
	pDEVINFO_T	dptdevice;	/* dpt per device information */
	unsigned long	flags2;
#ifdef QUEUELOCKS
	unsigned long	flags5;
#endif

	KWDEBUG(dbg_dptqueue, printk("dpt_queue: Entered\n"););

	/*
	 * SCSI REQUEST_SENSE commands will be executed automatically by the 
	 * Host Adapter for any errors, so they should not be executed 
	 * explicitly unless the Sense Data is zero indicating that no error 
	 * occurred.
	 */

	if ((cmd->cmnd[0] == REQUEST_SENSE) && (cmd->sense_buffer[0] != 0)) {
		KWDEBUG(dbg_dptqueue, printk("dpt_queue: requesting sense when it is already filled \n");)
		cmd->result = (DID_OK << 16);
		cmdcomplete(cmd);
		return(0);
	}

#if DEBUGMULTIPLEDEV 
	if ((cmd->cmnd[0] == TEST_UNIT_READY) ||  (cmd->cmnd[0] == INQUIRY)) {  
		if (cmd->target < 5) {
	 		printk("dpt_queue: READY or INQUIRY: chan = %d, target = %d, lun = %d, cmd->cmnd[0] = 0x%02x\n", cmd->channel, cmd->target, cmd->lun, cmd->cmnd[0]);
		}
	}
#endif

	KWDEBUG(dbg_dptqueue, printk("dpt_queue: chan = %d, target = %d, lun = %d, cmd->cmnd[0] = 0x%02x\n", cmd->channel, cmd->target, cmd->lun, cmd->cmnd[0]);)
	dpthost = (pDPT_HBA_T)cmd->host->hostdata;

	/*
	 * Make sure that this HBA is installed and working correctly
	 */
	if (!(dpthost->Flags & HBA_FLAGS_INSTALLED_B) ||
	    (dpthost->Flags & HBA_FLAGS_IN_RESET)) {
		cmd->result = (DID_NO_CONNECT << 16);	/* return DID_BAD_TARGET ??? */
		KWDEBUG(dbg_dptqueue, printk("dpt_queue: HBA not Installed or in reset: flags = 0x%x\n", (unsigned int) dpthost->Flags););
		cmdcomplete(cmd);
		return(0);
	}

	/*
	 * set timeout to 2 MINUTES for dpt commands (Mark).  If have
	 * time, read timeout information with a getioparams call during board
	 * configuration.  Are setting the timeout to 2 minutes in dpt_buildmsg.
	 * Are resetting the timeout here because the scsi layer above can sleep
	 * AFTER setting the timeout, but before we are called.
	 */
#if LINUX_VERSION_CODE < 0x020100
	cmd->timeout = SD_TIMEOUT * 3;
#else	/* LINUX_VERSION_CODE is > 0x020100 */
	dpt_add_timer(cmd, SD_TIMEOUT *3);
#endif

#ifdef QUEUELOCKS
	SPIN_LOCK_IRQSAVE(&dpthost->driverlock, flags5)	
#endif /* QUEUELOCKS */

	/*
	 * Get a free message.  If there isn't one, return
	 */
	if ((dptmsg = dpti_AllocDptMsg(dpthost)) == NULL) {
		cmd->result = (DID_ERROR << 16);
		KWDEBUG(dbg_dptqueue, printk("dpt_queue: no free message\n"););
#ifdef QUEUELOCKS
		SPIN_UNLOCK_IRQRESTORE(&dpthost->driverlock, flags5)
#endif /* QUEUELOCKS */
		cmdcomplete(cmd);
		return(0);
	}
	if ((dptdevice = (pDEVINFO_T)(cmd->device->hostdata)) == NULL) {
		/*
		 * If no dpt device is found in command, search for device
		 * in table and print warning message. 
		 *
		 * Note:  the cmd->channel, target, and lun fields were set up
		 * in scsi_build_commandblocks
		 */
		if ((dptdevice = dpti_GetDevFromTable(dpthost,
				(UINT32)cmd->channel, 
				(UINT32)cmd->target, 
				(UINT32)cmd->lun)) == NULL) {

			dpti_FreeDptMsg(dpthost, dptmsg);
			cmd->result = (DID_NO_CONNECT << 16);	/* no device at the address specified */
			KWDEBUG(dbg_dptqueue, printk("dpti2o: dpt_queue: No device found in table\n");)

#ifdef QUEUELOCKS
			SPIN_UNLOCK_IRQRESTORE(&dpthost->driverlock, flags5)
#endif /* QUEUELOCKS */
			cmdcomplete(cmd);
			return(0);
		}
	KWDEBUG(dbg_dptqueue, printk("dpt_queue: After dpti_GetDevFromTable\n"););
		/*
		 * First command request for this device.  Set up a pointer
		 * to the device structure.  This should be a TEST_UNIT_READY
		 * command from scan_scsis_single.
		 *
		 * The hostdata field will be verified in dpt_select_queue_depth
		 */
		cmd->device->hostdata = (void *)dptdevice;
			
	}
	KWDEBUG(dbg_dptqueue, printk("dpt_queue: chan = %d, target = %d, lun = %d, cmd->cmnd[0] = 0x%02x\n", cmd->channel, cmd->target, cmd->lun, cmd->cmnd[0]);)

	/*
	 * Now is OK to build and send message (dpt_buildmsg)
	 */
	cmd->scsi_done = cmdcomplete;	/* set Mid-level done function */
	cmd->SCp.ptr = (char *)dptmsg;	/* store ptr to dptmsg so can */
					/* retrieve later */
	cmd->host_scribble = NULL;	/* used later for queueing */

	/*
	 * The flag lock must be held when checking and queuing the reset
	 * queue.  The reset queue will be handled at the end of dpt_reset
	 *
	 * If we are being called from when the device is being reset, 
	 * delay processing of the command until later.
	 *
	 */
	SPIN_LOCK_IRQSAVE(&dpthost->flaglock, flags2)
	if (!(dptdevice->Flags & DEV_IN_RESET)) { 
		SPIN_UNLOCK_IRQRESTORE(&dpthost->flaglock, flags2)
		dpt_buildmsg(cmd, dptmsg, dptdevice);  
	} else {
		ENQUEUE(cmd, Scsi_Cmnd, dpthost->resetq, host_scribble, dpthost->resetq_lock)
		SPIN_UNLOCK_IRQRESTORE(&dpthost->flaglock, flags2)
	}
#ifdef QUEUELOCKS
	SPIN_UNLOCK_IRQRESTORE(&dpthost->driverlock, flags5)
#endif /* QUEUELOCKS */

	return(0);
}

/*
 * Take commands off of the send queue, build a dpt I20 message and send
 * the command to the board
 */
void
dpt_docmd(void *dpth)
{
	pDPT_MSG_T dptmsg = NULL;
	Scsi_Cmnd *cmd = NULL;
	pDEVINFO_T	dptdevice;	/* dpt per device information */
	pDPT_HBA_T	dpthost = (pDPT_HBA_T)dpth;
#ifdef QUEUELOCKS
	unsigned long flags;
#endif

	DEQUEUE(cmd, Scsi_Cmnd, dpthost->sendq, host_scribble, dpthost->sendq_lock)
#ifdef QUEUELOCKS
	SPIN_LOCK_IRQSAVE(&dpthost->driverlock, flags)	
#endif
	while (cmd) {
		cmd->host_scribble = NULL;
		dptmsg = (pDPT_MSG_T)cmd->SCp.ptr;
		dptdevice = (pDEVINFO_T)cmd->device->hostdata;
		dpt_buildmsg(cmd, dptmsg, dptdevice);  
		DEQUEUE(cmd, Scsi_Cmnd, dpthost->sendq, host_scribble, dpthost->sendq_lock)
	}
#ifdef QUEUELOCKS
	SPIN_UNLOCK_IRQRESTORE(&dpthost->driverlock, flags) 
#endif
}

void
dpt_docmdallhosts(void *dpth)
{
	pDPT_MSG_T dptmsg = NULL;
	Scsi_Cmnd *cmd = NULL;
	pDEVINFO_T	dptdevice;	/* dpt per device information */
	pDPT_HBA_T	dpthost;
#ifdef QUEUELOCKS
	unsigned long flags;
#endif
	int i;
	int more = 1;

	for (i = 0; i < i2osystemtab->Header.NumberEntries; i++) {
		dpthost = dpti20cards[i];
		if (dpthost != NULL) {
#ifdef QUEUELOCKS
			SPIN_LOCK_IRQSAVE(&dpthost->driverlock, flags)	
#endif
		}
	}
	while (more) {
		more = 0;
		for (i = 0; i < i2osystemtab->Header.NumberEntries; i++) {
			dpthost = dpti20cards[i];
			DEQUEUE(cmd, Scsi_Cmnd, dpthost->sendq, host_scribble, dpthost->sendq_lock)
			if (cmd) {
				more = 1;
				cmd->host_scribble = NULL;
				dptmsg = (pDPT_MSG_T)cmd->SCp.ptr;
				dptdevice = (pDEVINFO_T)cmd->device->hostdata;
				dpt_buildmsg(cmd, dptmsg, dptdevice);  
			} 
		}
	}
	for (i = 0; i < i2osystemtab->Header.NumberEntries; i++) {
		dpthost = dpti20cards[i];
		if (dpthost != NULL) {
#ifdef QUEUELOCKS
			SPIN_UNLOCK_IRQRESTORE(&dpthost->driverlock, flags) 
#endif
		}
	}
}


/*
 * look at BusLogic.c (BusLogic_BIOSDiskParameters) and 
 * scsicam.c (scsicam_bios_param) for examples
 *
 * dpt_biosparm is called from lilo via ioctl(HDIO_GETGEO).  This calls 
 * into the kernel: sd_ioctl->host->hostt->bios_param()
 *		scsi_ioctl
 *
 * dpt_biosparm is also called from fdisk.
 *
 * part of this code came from dpti_DriveTranslationBand the rest is
 * from Geometry.c
 */
int
dpt_biosparam(Disk *disk, kdev_t dev, int geom[])
{
	int heads, sectors, cylinders;
	struct buffer_head *bh;

	KWDEBUG(dbg_biosparam,  printk("dpt_biosparam: entered.\n");)
	KWDEBUG(dbg_biosparam,  printk("dpt_biosparam: major = %d, minor = %d.\n", MAJOR(dev), MINOR(dev)&~0xf);)

      //
      // If the capacity is less than 1G, use  64 x 32 parameters 
      //
	if(disk->capacity < 0x200000) {
		heads   = 64;
		sectors = 32;
	} else {

		//
		// All other calculations use 63 sectors per track 
		//
		sectors = 63;

		//
		// If the capacity is less than 2G, use  65 x 63 parameters 
		//
		if(disk->capacity < 0x400000) {
			heads = 65;
		} else if(disk->capacity < 0x800000) {  

			//
			// If the capacity is less than 4G, use  128 x 63 parameters 
			//
			heads = 128;
		} else {

			//
			// If the capacity is 8G or more, use  255 x 63
			// parameters 
			//
			heads = 255;
		}
	} 

	cylinders = disk->capacity / (heads * sectors);

	geom[0] = heads;
	geom[1] = sectors;
	geom[2] = cylinders;

	KWDEBUG(dbg_biosparam,  printk("dpt_biosparam: geom[0] = 0x%x, geom[1] = 0x%x, geom[2] = 0x%x.\n", geom[0], geom[1], geom[2]);)
	/*
	 * Try to read the partition table to get information
	 */
	if (!(bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, 1024))) {
        	return(0);
	}

	return(0);
}


/**************************************************************************
 * dpt_delay delays the number of milliseconds given.  To delay 1 second,
 * use 1000 milliseconds.
 **************************************************************************/
static void
dpt_delay(int millisec)
{
	int i;

	for (i = 0; i < millisec; i++) {
		udelay(1000);		/* delay for one millisecond */
	}
}


//-------------------------------------------------------------------------
//                     Function dpt_configcard                           
//-------------------------------------------------------------------------
// There Are No Parameters Passed Into This Function                       
//
// Returns a 1 if card is successfully found and configured, a 0 otherwise
//                                                                         
// This Function Looks For A DPT I2O HBA.                           
//                                                                         
// This function should only be called at init time
//                                                                         
// Return :                                                                
//-------------------------------------------------------------------------

/* STATIC pI2O_DEVICE_T dpti_FindI2Ocard(VOID) */
STATIC int 
dpt_configcard(Scsi_Host_Template *sht, unsigned char pcibus, 
	unsigned char pcifn, struct pci_dev *pdev)
{
	unsigned int	physbase, memsize;	/* was PhysicalBaseAddrss */
	int i, j;
	unsigned short	command;	/* command is 16 bits */
	unsigned char	dptirq;		/* was Vect */
	unsigned long	page_offset, page_base, virtbaseaddr;
	int cardidx	= 0;	/* index of card into I2oSystemTable */
	pDPT_HBA_T	dpthost;
	pDPT_HBA_T	newdpthost;
	struct Scsi_Host *host;
  	int		result = 0;
	INT32 NumDevices,ToIopMessageCount,FromIopMessageCount = 0;
	volatile unsigned long   flags;  /* for SMP locking */
	pDPT_MSG_T dptmsg;
#ifndef LOCALONSTACK
	UINT8	*localptr;	/* used to assign localmsgs */
#endif
	PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME replyptr;
	volatile I2O_EXEC_STATUS_GET_REPLY getstatusreply; 

	KWDEBUG(dbg_dptconfigcard,  printk("DPT I2O: dpt_configcard: entered.\n");)

        //
        // Read in the command register and make sure that the device is 
        // enabled and set up for bus master                             
        //
	pcibios_read_config_word(pcibus, pcifn,PCI_REG_COMMAND,&command);
	if(!((command & PCI_CMD_MEMORY_ENABLED)&&
	      (command & PCI_CMD_BUSMASTER))) {

		printk("dpti2o:  dptconfigcard: device not memory enable or bus master.\n");

		return(result);
	}

#if LINUX_VERSION_CODE < NEWPCI_VERSION
        //
        // Read in the vector register and save it off 
        //
	pcibios_read_config_byte(pcibus, pcifn, PCI_INTERRUPT_LINE,
                             &dptirq);

	KWDEBUG(dbg_dptconfigcard, printk("dpti2o: dptconfigcard:  dptirq is  0x%x\n", dptirq);)
        //
        // Read in the Memory Base address 
        //
	pcibios_read_config_dword(pcibus, pcifn, PCI_BASE_ADDRESS_0, &physbase);

#else	/* LINUX_VERSION_CODE >= NEWPCI_VERSION */

	dptirq = pdev->irq;
	physbase = pdev->base_address[0];

#endif	/* LINUX_VERSION_CODE < NEWPCI_VERSION */


        
        //
        // To get the size of the memory space taken we have to write out
        // all ones to the base register and then read it back. The lower
        // 4 bits are ignored. All of the "don't care" bits will be set to
        // 0 and are used to determine the size of memory space used and all
        // other upper bits will be set to ones. If we take the negative of
        // this number, AND in a 0x0f for the lower four bits and add one
        // it will give us the memory size. We must also write the original
        // Base address back out to reset it up.
        //  
	pcibios_write_config_dword(pcibus, pcifn, PCI_BASE_ADDRESS_0, ~0);
	pcibios_read_config_dword(pcibus, pcifn, PCI_BASE_ADDRESS_0, &memsize);
           //
           // Restore the base address
           //
	pcibios_write_config_dword(pcibus, pcifn, PCI_BASE_ADDRESS_0, physbase);
	physbase &= PCI_BASE_ADDRESS_MEM_MASK;


        //
        // Take the negative, disreguare the bottem four bits and add 1
        //
	memsize &= PCI_BASE_ADDRESS_MEM_MASK;
	memsize = ~memsize +1;
	KWDEBUG(dbg_dptconfigcard, printk("dpti2o: dptconfigcard:  memsize is %d, 0x%x\n", memsize, memsize);)
        //
        // Firmware has guaranteed that the memory we share with them will
        // always fall within this range, so if the card uses more than we
        // need to map in, scale it down.
        //
#if 0
        if(memsize > MAX_RANGE_LENGTH) {
           memsize = MAX_RANGE_LENGTH;
         }
	/*
	 * 0x400000 WORKS with 20 toiop and 16 fromiop
	 */
        if(memsize > MAX_RANGE_LENGTH) {
           memsize = 0x400000;
         }
        if(memsize > MAX_RANGE_LENGTH) {
           memsize = 0x1000000;
         }
#endif

        //
        // Map the physicall address into a virtual address
        //

	page_base =  physbase & PAGE_MASK;
	page_offset = physbase - page_base;
	virtbaseaddr = (unsigned long) ioremap(page_base, page_offset + memsize);

	KWDEBUG(dbg_dptconfigcard, printk("dpti2o: dptconfigcard:  memsize is 0x%x, physbase = 0x%x, page_base = 0x%x, page_offset = 0x%x, virtbase = 0x%x\n", memsize, physbase, (unsigned int) page_base, (unsigned int) page_offset, (unsigned int) virtbaseaddr);)

	virtbaseaddr += page_offset;




       //
       // First try to reset the adapter, if it fails move on
       //
	if((i = dpti_iopreset((pUINT8) virtbaseaddr))) {
		printk("dpti20: dpt_configcard:  Iop Reset Failed, Errno %d\n", i);
		iounmap((void *)(virtbaseaddr & PAGE_MASK));
		return(result); 
	} else {
		KWDEBUG(dbg_dptconfigcard, printk("dpti20: dpt_configcard:  Iop Reset worked, Errno %d\n", i);)
	}

#if WORKS
	*((UINT32 *)(virtbaseaddr + INT_MASK_OFFSET)) |= I2O_INTERRUPTS_DISABLED_B;
#endif
        //
        // Send off the I2O Get Status Command
        //
	if(dpti_I2oGetStatus((UINT8 *) virtbaseaddr, (PI2O_EXEC_STATUS_GET_REPLY) &getstatusreply)) {
		/*
		 * if the command failed, return an error
		 */
		iounmap((void *)(virtbaseaddr & PAGE_MASK));
		printk("dpti20: dpt_configcard:  Iop Get Status Failed\n");
		return(result); 
	} else {
		KWDEBUG(dbg_dptconfigcard, printk("dpt_configcard:  dpti_I2oGetStatus worked\n");)
	}
#if WORKS

	*((UINT32 *)(virtbaseaddr + INT_MASK_OFFSET)) |= I2O_INTERRUPTS_DISABLED_B;
#endif

	/*
	 * Add this device to the System Table
	 */
	/*
	 * index into table is one less than number of cards
	 *  (cardidx is original code's HbaNum)
	 */
	cardidx = i2osystemtab->Header.NumberEntries;	
	KWDEBUG(dbg_dptconfigcard, printk("dpt_configcard:  cardidx = %d\n", cardidx);)

     ++i2osystemtab->Header.NumberEntries;


     i2osystemtab->SysTabEntry[cardidx].OrganizationID = 
                      getstatusreply.OrganizationID;
     i2osystemtab->SysTabEntry[cardidx].IOP_ID = 
                      getstatusreply.IOP_ID;
     i2osystemtab->SysTabEntry[cardidx].I2oVersion = 
                      getstatusreply.I2oVersion;
     i2osystemtab->SysTabEntry[cardidx].IopState = 
                      getstatusreply.IopState;
     i2osystemtab->SysTabEntry[cardidx].MessengerType = 
                      getstatusreply.MessengerType;
     i2osystemtab->SysTabEntry[cardidx].InboundMessageFrameSize = 
                      getstatusreply.InboundMFrameSize;

     i2osystemtab->SysTabEntry[cardidx].MessengerInfo.
                                        InboundMessagePortAddressLow = 
               physbase + TO_IOP_FIFO_OFFSET;

	KWDEBUG(dbg_dptconfigcard, printk("dpt_configcard, getstatusreply fields: orgid = %d, iop_id = %d, iopstat = %d, messtype = 0x%x, inboundsize = %d\n", getstatusreply.OrganizationID, getstatusreply.IOP_ID, (int) getstatusreply.IopState, (unsigned int) getstatusreply.MessengerType, getstatusreply.InboundMFrameSize);)

   
     //
     // Set up our number of outbound and inbound messages
     //
     ToIopMessageCount = getstatusreply.MaxInboundMFrames;
#if ORIG
     if(ToIopMessageCount > MAX_TO_IOP_MESSAGES) {
        ToIopMessageCount = MAX_TO_IOP_MESSAGES;
      }
#endif
     if(ToIopMessageCount > maxtoiopmsgs) {
        ToIopMessageCount = maxtoiopmsgs;
      }
     FromIopMessageCount = getstatusreply.MaxOutboundMFrames;
     if(FromIopMessageCount > MAX_FROM_IOP_MESSAGES) {
        FromIopMessageCount = MAX_FROM_IOP_MESSAGES;
      }

	KWDEBUG(dbg_dptconfigcard, printk("ToIopMessageCount = %d, sizeof(DPT_MSG_T) = %d\n", (int) ToIopMessageCount, sizeof(DPT_MSG_T));)

	KWDEBUG(dbg_dptconfigcard, printk("dpt_configcard:  ToIopMessageCount = %d, FromIopMessageCount = %d, getstatustoiop = %d\n", (int) ToIopMessageCount, (int) FromIopMessageCount, (int) getstatusreply.MaxInboundMFrames);)

	/*
	 * Allocate a temporary dpthost structure until we can have one
	 * returned from scsi_register
	 */

	if ((dpthost = kmalloc(sizeof(DPT_HBA_T), GFP_ATOMIC)) == NULL) {
		KWDEBUG(dbg_dptconfigcard, printk("dpt_configcard:  kmalloc returned NULL\n");)
		iounmap((void *)(virtbaseaddr & PAGE_MASK));
     		i2osystemtab->Header.NumberEntries--;
		return(result);
	}
	memset(dpthost, 0, sizeof(DPT_HBA_T));

	dpthost->cardidx = cardidx;
	dpthost->maxfromiopmsgs = FromIopMessageCount;

     //
     // Set up the Virtual Base Address of the I2O Device
     //
     dpthost->VirtualBaseAddress_P = (UINT8 *) virtbaseaddr;

     //
     // Set up the FIFO addresses  
     //
     dpthost->ToIopFifo_P   = (UINT32 *)(virtbaseaddr + TO_IOP_FIFO_OFFSET);
     dpthost->FromIopFifo_P = (UINT32 *)(virtbaseaddr + FROM_IOP_FIFO_OFFSET);
     //
     // Set up the Interrupt register addresses  
     //
     dpthost->IntStatusReg_P = (UINT32 *)(virtbaseaddr + INT_STATUS_OFFSET);
     dpthost->IntMaskReg_P   = (UINT32 *)(virtbaseaddr + INT_MASK_OFFSET);

     //
     // Initialize the From IOP Queue, if it fails move on
     //
     if(dpti_I2oInitFromIopQueue((UINT8 *) virtbaseaddr, (PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME) dpthost->FromIopMsg,
                       FromIopMessageCount)) {
		printk("dpti20: dpt_configcard:  dpti_I2oInitFromIopQueue failed \n");
     		i2osystemtab->Header.NumberEntries--;
		kfree(dpthost);
		dpthost = NULL;
		iounmap((void *)(virtbaseaddr & PAGE_MASK));
		return(result); 
      } else {
		KWDEBUG(dbg_dptconfigcard, printk("dpt_configcard:  dpti_I2oInitFromIopQueue  successful\n");)
	}

     //
     // Set up the Default SCSI Channel, Target ID and LUN configuration info
     //
     dpthost->MaxID = 16;	/* note, for linux, is 16 */
     dpthost->MaxLUN = 8;	/* note, for linux, is 8 */
     dpthost->MaxChannel = 0;
     dpthost->ChannelInfo[0].ScsiTargetID = 7;
     dpthost->ChannelInfo[1].ScsiTargetID = 7;
     dpthost->ChannelInfo[2].ScsiTargetID = 7;
     dpthost->ChannelInfo[3].ScsiTargetID = 7;
     
     //
     // Calculate the Scatter Gather list size
     //
     dpthost->SgListSize = (getstatusreply.InboundMFrameSize * 4 - 40 ) /
             sizeof(I2O_SG_ELEMENT);


	if(dpthost->SgListSize > SG_LIST_ELEMENTS) {
		dpthost->SgListSize = SG_LIST_ELEMENTS;
	}

	KWDEBUG(dbg_dptconfigcard, printk("dpt_configcard:  SgListSize = %d\n", (int) dpthost->SgListSize);)
    
     //
     // Set up the HBA Queue depth
     //
     dpthost->QueueDepth = ToIopMessageCount;

     //
     // Initialize our MSG Free List
     //
     dpthost->OutstandingMsgs = 0;
     dpthost->DptMsgActiveList_P = (pDPT_MSG_T )NULL;
     dpthost->DptMsgFreeList_P = (pDPT_MSG_T )NULL;

	if ((dpthost->dptmsgs = (pDPT_MSG_T)kmalloc(ToIopMessageCount * sizeof(DPT_MSG_T), 
			GFP_ATOMIC)) == NULL) {
		KWDEBUG(dbg_dptconfigcard, printk("dpt_configcard:  Could not allocate DPT msgs: kmalloc returned NULL\n");)
     		i2osystemtab->Header.NumberEntries--;
		kfree(dpthost);
		dpthost = NULL;
		iounmap((void *)(virtbaseaddr & PAGE_MASK));
		return(result);
	}
	memset(dpthost->dptmsgs, 0, ToIopMessageCount * sizeof(DPT_MSG_T));

#ifndef LOCALONSTACK
	memset(localmsgs[cardidx], 0, (MAX_TO_IOP_MESSAGES) * (MAX_MESSAGE_SIZE));
	localptr = localmsgs[cardidx];
#endif

	memset((void *) reply[cardidx], 0, (MAX_TO_IOP_MESSAGES) * (sizeof(I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME)));
	replyptr = (PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME) reply[cardidx];
	dptmsg = dpthost->dptmsgs;
     for(j = 0; j < dpthost->QueueDepth; j++, dptmsg++, replyptr++) {
        dptmsg->Next_P = dpthost->DptMsgFreeList_P;
        dpthost->DptMsgFreeList_P = dptmsg;
#ifndef LOCALONSTACK
	dptmsg->LocalToIopMsg = localptr;
	localptr += (MAX_MESSAGE_SIZE);
#endif
	dptmsg->Reply = replyptr;
      }

	/*
	 * Send off the HRT Get Command
	 */
	memset((void *) scratchbuf, 0, SCRATCHBUFSIZE);
	if(dpti_I2oHrtGet(dpthost, (pUINT8) scratchbuf, SCRATCHBUFSIZE)) {
		printk("dpti20: dpt_configcard:  dpti_I2oHrtGet Failed\n");
     		i2osystemtab->Header.NumberEntries--;
		kfree(dpthost->dptmsgs);
		dpthost->dptmsgs = NULL;
		kfree(dpthost);
		dpthost = NULL;
		iounmap((void *)(virtbaseaddr & PAGE_MASK));
		return(result);
	}

     //
     // Send down the I2O system table to the HBA. If it fails, print
     // an error message and ignore the error.
     //
     if((j = dpti_I2oSetSysTab(dpthost, (UINT8 *)i2osystemtab,
                              sizeof(I2O_SYSTEM_TABLE_T),
                              0,0,0,0))) {
		printk("dpt_configcard: Could Not Issue Set System Table For HBA %d : Error %d\n",
                 cardidx,j);
      } else {
		KWDEBUG(dbg_dptconfigcard, printk("dpt_configcard:  dpti_I2oSetSysTab  successful\n");)
	}
   
     //
     // Send down the I2O Enable System command to the HBA. If it fails,
     // print an error message and ignore the error.
     //
     if((j = dpti_I2oEnableSys(dpthost))) {
		printk("Could Not Issue Enable System For HBA %d : Error %d\n",
                    cardidx,j);
      } else {
		KWDEBUG(dbg_dptconfigcard, printk("dpt_configcard:  dpti_I2oEnableSys  successful\n");)
	}

     //
     // Get the devices for this HBA
     //
     NumDevices = dpti_BuildDeviceList(dpthost);
	KWDEBUG(dbg_dptconfigcard, printk("dpt_configcard:  returned from dpti_BuildDeviceList, NumDevices = %d\n", (int) NumDevices);)

	if (NumDevices <= 0) {
		printk("dpti20: dpt_configcard:  Found no devices on DPT HBA %d\n", cardidx);
     		i2osystemtab->Header.NumberEntries--;
		kfree(dpthost->dptmsgs);
		dpthost->dptmsgs = NULL;
		kfree(dpthost);
		dpthost = NULL;
		iounmap((void *)(virtbaseaddr & PAGE_MASK));
		return(result);
	}

	/*
	 * NOTE:  MUST SET THIS FLAG BEFORE CALLING scsi_register.  
	 * scsi_register calls the dpt_queue routine
	 */
	dpthost->Flags = HBA_FLAGS_INSTALLED_B;

	/*
	 * Note: scsi_register has a limit on how much memory it can allocate
	 */
	host = scsi_register(sht, sizeof(DPT_HBA_T));
	if (host == NULL) {
		printk("dpti20: dpt_configcard:  scsi_register returned NULL\n");
     		i2osystemtab->Header.NumberEntries--;
		kfree(dpthost->dptmsgs);
		dpthost->dptmsgs = NULL;
		kfree(dpthost);
		dpthost = NULL;
		iounmap((void *)(virtbaseaddr & PAGE_MASK));
		return(result);
	} else {
		KWDEBUG(dbg_dptconfigcard, printk("dpt_configcard:  scsi_register successful\n");)
	}
	newdpthost = (DPT_HBA_T *)host->hostdata;
	memset(newdpthost, 0, sizeof(DPT_HBA_T));

/*	memcpy(to, from, size) */
	/* 
	 * copy the contents of the temporary dpthost structure into the true
	 * dpthost structure returned from scsi_register
	 */
	/*
	 * Lock on the old lock in case the messages are being removed from the list
	 * Note: If you do NOT have this lock, you will get a stack overflow because
	 * the message lists get corrupted
	 */
	SPIN_LOCK_IRQSAVE(&dpthost->MsgListLock, flags)
	memcpy((void *)newdpthost, dpthost, sizeof(DPT_HBA_T));
	SPIN_UNLOCK_IRQRESTORE(&dpthost->MsgListLock, flags) 
	/*
	 * NOTE:  Originally I kfree'ed dpthost here.  If you kfree it here,
	 *	  you WILL get a stack overflow. So I never free it.
	 */
#ifdef ORIG
	kfree(dpthost);		/* free up temporary structure - CANNOT, still has outstanding message */ 
#endif
	dpthost = NULL;
	/*
	 * fill in any fields not filled in yet
	 */
	newdpthost->next = cardlist;
	cardlist = newdpthost;

	newdpthost->host = host;

	dpti20cards[cardidx] = newdpthost;
	/*
	 * store unique host_no.  Is used in dpt_proc_info
	 */
	newdpthost->host_no = host->host_no;
	SPIN_LOCK_INIT(&newdpthost->driverlock);
	SPIN_LOCK_INIT(&newdpthost->flaglock);
	SPIN_LOCK_INIT(&newdpthost->MsgListLock);

	host->irq = dptirq;
	/*
	 * no IO ports, so don't have to set host->io_port and 
	 * host->n_io_port
	 */
	host->n_io_port = 0;
	host->max_id = 16;	/* MaxID is 15, but must set it to 1 higher */
				/* see comments in hosts.h */
	host->max_lun = 8;	/* max lun is 7, but must set to 1 higher */
				/* see comments in hosts.h */
	host->max_channel = 0;	/* dpti_BuildDeviceList will set this correctly */
	host->cmd_per_lun = 1;	/* no tagged queueing - same as in SHT */
	host->unique_id = (unsigned int) newdpthost;

	host->select_queue_depths = dpt_select_queue_depths;

	host->sg_tablesize = newdpthost->SgListSize;

	/*
	 * can_queue is set to the maximum number of simultaneous commands
	 * a given host adapter will accept (see hosts.h)
	 */
	host->can_queue = ToIopMessageCount;
	/*
	 * Note:  newdpthost->MaxChannel is set in dpti_BuildDeviceList, so
	 * cannot set host->max_channel until AFTER call to dpti_BuildDeviceList
	 */
	host->max_channel = newdpthost->MaxChannel;

	if (dpt_doinquiry) {
		dpt_inquiry(newdpthost);
	}
	/*
	 * request_irq must be called AFTER scsi_register
	 */
	if (request_irq(dptirq, dpti2o_intr, SA_SHIRQ, "dptI2O", newdpthost)) {
		printk(KERN_WARNING "dpti2o: dpt_configcard:  Couldn't register IRQ %d\n",
			dptirq);
     			i2osystemtab->Header.NumberEntries--;
			kfree(newdpthost->dptmsgs);
			newdpthost->dptmsgs = NULL;
			iounmap((void *)(virtbaseaddr & PAGE_MASK));
			scsi_unregister((struct Scsi_Host *) newdpthost); 
			return (result);
	} else {
		KWDEBUG(dbg_dptconfigcard, printk("dpt_configcard:  request_irq successful\n");)
	}
	result = 1;
	KWDEBUG(dbg_dptconfigcard, printk("dpt_configcard: host->max_id = %d, host->max_lun = %d, host->max_channel = %d\n", host->max_id, host->max_lun, host->max_channel);)

	return(result);
}




//-------------------------------------------------------------------------
//                     Function dpti_IopReset
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     VirtualBaseAddress : Virtual base address for the HBA               
//                                                                         
// This Function will send off the I2O Reset IOP command to the I2O
// device found at the passed in base virtual address.
//
// This function should only be called at init time
//                                                                         
// Return : 0 for success, error code otherwise                  
//-------------------------------------------------------------------------

STATIC INT32 
dpti_iopreset(pUINT8 VirtualBaseAddress_P)
{
  PI2O_EXEC_IOP_RESET_MESSAGE IopResetMsg_P;
  volatile I2O_EXEC_IOP_RESET_STATUS StatusBuffer;
  UINT32 MsgOffset,Index = 0;
  INT32 Rtnval = 1;
  UINT16 MessageSize = sizeof(I2O_EXEC_IOP_RESET_MESSAGE) >> 2;
  pUINT32 ToIopFifo_P = (pUINT32)(VirtualBaseAddress_P + TO_IOP_FIFO_OFFSET);
  volatile pUINT8 Buffer_P;
  
	KWDEBUG(dbg_iopreset,  printk("DPT I2O: dpti_iopreset: entered. virtbase = 0x%x\n", (unsigned int) VirtualBaseAddress_P);)

  //
  // Pull off a message offset 
  //
  MsgOffset = *ToIopFifo_P;

  //
  // If we got a message request offset, fill it out and send it off
  //
  if(MsgOffset != EMPTY_QUEUE) {
/*
	KWDEBUG(dbg_iopreset,  printk("DPT I2O: dpti_iopreset: MsgOffset = 0x%x\n", MsgOffset);)
     //
*/
     // Convert it to a virtual address
     //
     IopResetMsg_P = (PI2O_EXEC_IOP_RESET_MESSAGE)(VirtualBaseAddress_P + 
                                                               MsgOffset);
	memset(IopResetMsg_P, 0, sizeof(I2O_EXEC_IOP_RESET_MESSAGE));

     //
     // Fill out the standard header
     //
     IopResetMsg_P->VersionOffset = I2O_VERSION_11;
     IopResetMsg_P->MsgFlags = 0;
     IopResetMsg_P->MessageSize = MessageSize;
     IopResetMsg_P->TargetAddress = 0;
     IopResetMsg_P->InitiatorAddress = 1;
     IopResetMsg_P->Function = I2O_EXEC_IOP_RESET;
     Buffer_P = (pUINT8)&StatusBuffer;
/*
	KWDEBUG(dbg_iopreset,  printk("DPT I2O: dpti_iopreset: Buffer_P = 0x%x. virt_to_bus(Buffer_P) = 0x%x\n", Buffer_P, virt_to_bus(Buffer_P));)
*/

     //
     // Set up the reply buffer physical address
     //
     IopResetMsg_P->StatusWordLowAddress = virt_to_bus(Buffer_P);
		
/*
	KWDEBUG(dbg_iopreset,  printk("dpti_iopreset: IopResetMsg_P->StatusWordLowAddress = 0x%x\n", IopResetMsg_P->StatusWordLowAddress);)

*/
     //
     // Make sure the address converted OK
     //
     if(IopResetMsg_P->StatusWordLowAddress != 0) {
        //
        // Clear out the status buffer
        //
        IopResetMsg_P->StatusWordHighAddress = 0;
        memset(Buffer_P, 0, sizeof(I2O_EXEC_IOP_RESET_STATUS));

        //
        // Put it into the HBAs queue to be processed
        //
        *ToIopFifo_P = MsgOffset;

        //
        // Due to some suspected cache coherency problems,we will
        // wait 5 milliseconds before polling the status word
        //
	dpt_delay(5);

        for(Index = 0; Index < WAIT_FOR_IOP_RESET; ++Index) {
           if(StatusBuffer.ResetStatus != 0) {
              break;
            }
		udelay(1); 
         }

        //
        // If the Reset status is set, check the value 
        //
        if(Index < WAIT_FOR_IOP_RESET) {
           //
           // If the reset was a success, wait for about a second and return
           // a good status
           //
           if(StatusBuffer.ResetStatus == I2O_EXEC_IOP_RESET_IN_PROGRESS) {
		dpt_delay(1000);
              Rtnval = 0;
            }
           //
           // Bad status returned, return an error
           //
            else {
                    Rtnval = 2;
            }

         } //if(Index < WAIT_FOR_IOP_RESET)
		else {
			KWDEBUG(dbg_iopreset,  printk("dpti_iopreset: Index >= WAIT_FOR_IOP_RESET = %d, Rtnval = %d\n", (int) Index, (int) Rtnval);)
		}

      } //if(IopResetMsg_P->StatusWordLowAddress != 0)
		else {
			KWDEBUG(dbg_iopreset,  printk("dpti_iopreset: IopResetMsg_P->StatusWordLowAddress  = 0x%x, Rtnval = %d\n", (unsigned int) Index, (int) Rtnval);)
		}

   } //if(MsgOffset != EMPTY_QUEUE)
	else {
		
		KWDEBUG(dbg_iopreset,  printk("DPT I2O: dpti_iopreset: MsgOffset = EMPTY_QUEUE = 0x%x\n", (unsigned int) MsgOffset);)
	}

	KWDEBUG(dbg_iopreset,  printk("dpti_iopreset: Index = %d, Rtnval = %d\n", (int) Index, (int) Rtnval);)
	KWDEBUG(dbg_iopreset,  printk("DPT I2O: dpti_iopreset: Buffer_P = 0x%x. virt_to_bus(Buffer_P) = 0x%x\n", (unsigned int) Buffer_P, (unsigned int) virt_to_bus(Buffer_P));)

  return(Rtnval);

} /* dpti_IopReset */




//-------------------------------------------------------------------------
//                     Function dpti_I2oGetStatus                          
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     VirtualBaseAddress : Virtual base address for the HBA               
//     GetStatusBuffer : Pointer to a buffer for the return data
//                                                                         
// This Function will send off the I2O Get Status command to the I2O
// device found at the passed in base virtual address.
//
// This function should only be called at init time
//                                                                         
// Return : 0 for success, error code otherwise                            
//-------------------------------------------------------------------------

STATIC INT32 
dpti_I2oGetStatus(UINT8 *VirtualBaseAddress,
                             PI2O_EXEC_STATUS_GET_REPLY GetStatusBuffer)
{
  PI2O_EXEC_STATUS_GET_MESSAGE GetStatusMsg_P;
  UINT32 MsgOffset,Count,j;
  volatile UINT8 *Buffer = (UINT8 *)GetStatusBuffer;
  UINT32 BufferSize = sizeof(I2O_EXEC_STATUS_GET_REPLY);
  UINT32 *ToIopFifo_P = (UINT32 *)(VirtualBaseAddress + TO_IOP_FIFO_OFFSET);
  INT32 Rtnval = 1;
  UINT16 MessageSize = sizeof(I2O_EXEC_STATUS_GET_MESSAGE) >> 2;
  UINT8 SglOffset = 0;

  //
  // Set up some sort of a timeout loop
  //
  for(Count = 0; Count < MAX_GET_STATUS_RETRY; ++Count) {
     //
     // Pull off a message offset 
     //
     MsgOffset = *ToIopFifo_P;
     
     //
     // If we got a message request offset, fill it out and send it off
     //
     if(MsgOffset != EMPTY_QUEUE) {
        //
        // Convert it to a virtual address
        //
        GetStatusMsg_P = (PI2O_EXEC_STATUS_GET_MESSAGE)(VirtualBaseAddress + 
                                                                  MsgOffset);
        //
        // Fill out the standard header
        //
        GetStatusMsg_P->VersionOffset = SglOffset | I2O_VERSION_11;
        GetStatusMsg_P->MsgFlags = 0;
        GetStatusMsg_P->MessageSize = MessageSize;
        GetStatusMsg_P->TargetAddress = 0;
        GetStatusMsg_P->InitiatorAddress = 1;
        GetStatusMsg_P->Function = I2O_EXEC_STATUS_GET;
        for(j = 0; j < I2O_EXEC_STATUS_GET_RESERVED_SZ; ++j) {
           GetStatusMsg_P->Reserved[j] = 0;
         }
       
        //
        // Set up the reply buffer physical address and init the buffer
        //
        GetStatusMsg_P->ReplyBufferAddressLow = (U32)virt_to_bus(Buffer);
        GetStatusMsg_P->ReplyBufferAddressHigh = 0;
        GetStatusMsg_P->ReplyBufferLength = BufferSize;
        memset((void *) Buffer, 0, BufferSize);

        //
        // Put it into the HBAs queue to be processed
        //
        *ToIopFifo_P = MsgOffset;

        //
        // Due to some suspected cache coherency problems,we will
        // wait 5 milliseconds before polling the status word
        //
	dpt_delay(5);

        //
        // Set up a timeout loop polling the packet by waiting for the 
        // last byte of the buffer to go to a non zero value 
        //
        for(j = 0; j < WAIT_FOR_GET_STATUS; ++j) {
           if(Buffer[BufferSize - 1] != 0) {
              break;
            }
		udelay(1);
         }

        //
        // If the reply returned with a good status, exit the loop with a
        // good status
        // 
        if(j < WAIT_FOR_GET_STATUS) {
           if((GetStatusBuffer->IopState == I2O_IOP_STATE_RESET) ||
             (GetStatusBuffer->IopState == I2O_IOP_STATE_HOLD) ||
             (GetStatusBuffer->IopState == I2O_IOP_STATE_READY) ||
             (GetStatusBuffer->IopState == I2O_IOP_STATE_OPERATIONAL)) {
              Rtnval = 0;
		KWDEBUG(dbg_getstatus, printk("dpti_I2oGetStatus: count = %d\n", (int) Count);)
              break;
            }
         }  

      } //if(MsgOffset != EMPTY_QUEUE)

	udelay(1);

   } //for(Count = 0; Count < MAX_GET_STATUS_RETRY; ++Count)

  return(Rtnval);

}



//-------------------------------------------------------------------------
//                     Function dpti_I2oInitFromIopQueue                   
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     VirtualBaseAddress : Virtual base address for the HBA               
//     FromIopMsg_P : List of reply messages to set up on the HBA
//     FromIopMsgCount : Number of reply messages in the list
//                                                                         
// This Function will issue the I2O Init Outbound Fifo command, and if
// the command is successful, will initialize the outbound fifo with
// the passed in list of reply message packets
//
// This function should only be called at init time
//                                                                         
// Return : 0 for success, error code otherwise                            
//-------------------------------------------------------------------------

STATIC INT32 
dpti_I2oInitFromIopQueue(UINT8 *VirtualBaseAddress,
                          PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME FromIopMsg_P,
                          INT32 FromIopMsgCount)
{
  PI2O_EXEC_OUTBOUND_INIT_MESSAGE InitOutboundMsg_P;
  UINT32 MsgOffset,Count;
	volatile UINT32 StatusWord;
  UINT32 *ToIopFifo_P = (UINT32 *)(VirtualBaseAddress + TO_IOP_FIFO_OFFSET);
  UINT32 *FromIopFifo_P = (UINT32 *)(VirtualBaseAddress + FROM_IOP_FIFO_OFFSET);
  INT32 Rtnval = 1;
  UINT16 MessageSize = (sizeof(I2O_EXEC_OUTBOUND_INIT_MESSAGE) -
                      sizeof(I2O_SG_ELEMENT)) >> 2;
  UINT8 SglOffset = (UINT8)(MessageSize << 4);

	KWDEBUG(dbg_initfromiopqueue, printk("DPT I2O: dpti_I2oInitFromIopQueue: entered.\n");)

  //
  // Pull off a message offset 
  //
  MsgOffset = *ToIopFifo_P;
   
  //
  // If we got a message request offset, fill it out and send it off
  //
  if(MsgOffset != EMPTY_QUEUE) {
     //
     // Convert it to a virtual address
     //
     InitOutboundMsg_P = (PI2O_EXEC_OUTBOUND_INIT_MESSAGE)(VirtualBaseAddress + 
                                                                  MsgOffset);
     //
     // Fill out the standard header
     //
     InitOutboundMsg_P->StdMessageFrame.VersionOffset = SglOffset | 
                                                           I2O_VERSION_11;
     InitOutboundMsg_P->StdMessageFrame.MsgFlags = 0;
     InitOutboundMsg_P->StdMessageFrame.MessageSize = MessageSize;
     InitOutboundMsg_P->StdMessageFrame.TargetAddress = 0;
     InitOutboundMsg_P->StdMessageFrame.InitiatorAddress = 1;
     InitOutboundMsg_P->StdMessageFrame.Function = I2O_EXEC_OUTBOUND_INIT;
     InitOutboundMsg_P->StdMessageFrame.InitiatorContext = uniqueid++;
     InitOutboundMsg_P->TransactionContext = 0;
     InitOutboundMsg_P->HostPageFrameSize = 4096;
     InitOutboundMsg_P->OutboundMFrameSize = 
                             sizeof(PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME);
     InitOutboundMsg_P->InitCode = 0;
     InitOutboundMsg_P->reserved = 0;
     InitOutboundMsg_P->SGL.u.Simple[0].FlagsCount.Count = 4;
     InitOutboundMsg_P->SGL.u.Simple[0].FlagsCount.Flags = 
                                      I2O_SGL_FLAGS_LAST_ELEMENT | 
                                      I2O_SGL_FLAGS_END_OF_BUFFER | 
                                      I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT;
     InitOutboundMsg_P->SGL.u.Simple[0].PhysicalAddress =
                                          (U32)virt_to_bus((UINT8 *)&StatusWord);
     //
     // Bump the message size by two to allow for the 
     // Scatter Gather entry
     //
     InitOutboundMsg_P->StdMessageFrame.MessageSize += 2;

     //
     // Initialize the Reply status word and send off the message
     //
     StatusWord = 0;
     *ToIopFifo_P = MsgOffset;

     //
     // Due to some suspected cache coherency problems,we will
     // wait 5 milliseconds before polling the status word
     //
	dpt_delay(5);

     //
     // Wait for the reply status to come back
     //
     for(Count = 0; Count < WAIT_FOR_GET_STATUS; ++Count) {
        if(StatusWord) {
           if(StatusWord != I2O_EXEC_OUTBOUND_INIT_IN_PROGRESS) {
              break;
            }
         }
	udelay(1);

      } //for(Count = 0; Count < WAIT_FOR_GET_STATUS; ++Count)

     //
     // If the command was successful, fill the fifo with our reply
     // message packets
     //
     if(StatusWord == I2O_EXEC_OUTBOUND_INIT_COMPLETE) {
        for(Count = 0; Count < FromIopMsgCount; ++Count) {
           *FromIopFifo_P = (UINT32)virt_to_bus((UINT8 *)FromIopMsg_P);
           ++FromIopMsg_P;
         }
        Rtnval = 0;

      } //if(StatusWord == I2O_EXEC_OUTBOUND_INIT_COMPLETE)

     //
     // Bad status from the command, return an error
     //
     else Rtnval = 2;

   } //if(MsgOffset != EMPTY_QUEUE)

  //
  // Could not get a message off of the queue so return an error
  // 
   else {
          Rtnval = 3;
   }

  return(Rtnval);
}



//-------------------------------------------------------------------------
//                     Function dpti_I2oSetSysTab                          
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     HbaNum : Host Adapter Number	(SCO)                              
//	dptcard - ptr to per card structure
//     SysBuffer : I/O system table
//     SysBufferSize : I/O system table size
//     MemBuffer : Public memory space table
//     MemBufferSize : Public memory space table size
//     IoBuffer : Public I/O space table
//     IoBufferSize : Public I/O space table size
//                                                                         
// This Function                                                           
//                                                                         
// Return :                                                                
//-------------------------------------------------------------------------

STATIC INT32 
dpti_I2oSetSysTab(pDPT_HBA_T dptcard, 
                             UINT8 *SysBuffer,INT32 SysBufferSize,
                             UINT8 *MemBuffer,INT32 MemBufferSize,
                             UINT8 *IoBuffer,INT32 IoBufferSize)
{
  PI2O_EXEC_SYS_TAB_SET_MESSAGE SysTabMsg_P;
  volatile pDPT_MSG_T DptMsg_P;
  pDPT_MSG_T DptMsgReturn_P;
  INT32 Rtnval = 1;
  UINT16 MessageSize = (sizeof(I2O_EXEC_SYS_TAB_SET_MESSAGE) -
                        sizeof(I2O_SG_ELEMENT)) >> 2;
/* see next TODO 
  UINT8 SglOffset = (UINT8)(MessageSize << 4);
*/
#ifdef LOCALONSTACK
	UINT8   localmsg[MAX_MESSAGE_SIZE];
#endif

#ifdef DEBUG_PRINT
  if(DebugFlags &  HBA_FLAGS_DBG_FUNCTION_ENTRY_B) {
     dpti_Printf(NULL, "\ndpti_I2oSetSysTab : Enter");
   }
#endif 

	KWDEBUG(dbg_setsystab, printk("DPT I2O: dpti_I2oSetSysTab: entered.\n");)
	KWDEBUG(dbg_setsystab, printk("DPT I2O: dpti_I2oSetSysTab: SysBuffer = 0x%x, virt_to_bus(SysBuffer) = 0x%x.\n", (unsigned int) SysBuffer, (unsigned int) virt_to_bus(SysBuffer));)
  //
  // Allocate a message packet
  //
  DptMsg_P = dpti_AllocDptMsg(dptcard);
  if(DptMsg_P != NULL) {
     //
     // Grab a pointer to the local message pointer
     //
#ifdef LOCALONSTACK
	DptMsg_P->LocalToIopMsg = &localmsg[0];
       	memset(&localmsg, 0, MAX_MESSAGE_SIZE);
#endif
     SysTabMsg_P = (PI2O_EXEC_SYS_TAB_SET_MESSAGE)(DptMsg_P->LocalToIopMsg);

	/*
	 * ??? TODO:  shouldn't VersionOffset be (sgloffset | I2O_VERSION_11)

	 */
     //
     // Fill out the standard header
     //
     SysTabMsg_P->StdMessageFrame.VersionOffset = 0;
     SysTabMsg_P->StdMessageFrame.MsgFlags = 0;
     SysTabMsg_P->StdMessageFrame.MessageSize = MessageSize;
     SysTabMsg_P->StdMessageFrame.TargetAddress = 0;
     SysTabMsg_P->StdMessageFrame.InitiatorAddress = 1;
     SysTabMsg_P->StdMessageFrame.Function = I2O_EXEC_SYS_TAB_SET;
     SysTabMsg_P->StdMessageFrame.InitiatorContext = DptMsg_P->unique;
     //
     // Set up the buffers as scatter gather elements
     //
     SysTabMsg_P->TransactionContext = (I2O_TRANSACTION_CONTEXT)DptMsg_P;
     SysTabMsg_P->SGL.u.Simple[0].FlagsCount.Count = SysBufferSize;
     SysTabMsg_P->SGL.u.Simple[0].FlagsCount.Flags = 
                                     I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT;
     if(SysBuffer != NULL) {
        SysTabMsg_P->SGL.u.Simple[0].PhysicalAddress = virt_to_bus(SysBuffer);
      } else {
             SysTabMsg_P->SGL.u.Simple[0].PhysicalAddress = 0;
      }
     SysTabMsg_P->SGL.u.Simple[1].FlagsCount.Count = MemBufferSize;
     SysTabMsg_P->SGL.u.Simple[1].FlagsCount.Flags = 
                                     I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT;
     if(MemBuffer != NULL) {
        SysTabMsg_P->SGL.u.Simple[1].PhysicalAddress = virt_to_bus(MemBuffer);
      } else {
             SysTabMsg_P->SGL.u.Simple[1].PhysicalAddress = 0;
      }
     SysTabMsg_P->SGL.u.Simple[2].FlagsCount.Count = IoBufferSize;
     SysTabMsg_P->SGL.u.Simple[2].FlagsCount.Flags = 
                                     I2O_SGL_FLAGS_LAST_ELEMENT | 
                                     I2O_SGL_FLAGS_END_OF_BUFFER | 
                                     I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT;
     if(IoBuffer != NULL) {
        SysTabMsg_P->SGL.u.Simple[2].PhysicalAddress = virt_to_bus(IoBuffer);
      }
      else {
             SysTabMsg_P->SGL.u.Simple[2].PhysicalAddress = 0;
      }

     //
     // Bump the message size by six to allow for the 
     // Scatter Gather entries
     //
     SysTabMsg_P->StdMessageFrame.MessageSize += 6;

     //
     // Send off the command polled
     //
	KWDEBUG(dbg_setsystab, printk("DPT I2O: dpti_I2oSetSysTab: sending polled command.\n");)

     DptMsgReturn_P = dpti_SendPolledCommand(dptcard,DptMsg_P,0, 0);

	KWDEBUG(dbg_setsystab, printk("DPT I2O: dpti_I2oSetSysTab: return from polled command.\n");)

     //
     // Check to make sure that this is the one we sent out
     //
     if(DptMsgReturn_P == DptMsg_P) {
        //
        // Good return for a success
        //
        if(DptMsg_P->Reply->StdReplyFrame.ReqStatus == I2O_REPLY_STATUS_SUCCESS) {
           Rtnval = 0;
         }
         
         //
         // Bad return, if the detailed status code is set up, we will
         // return that, otherwisw return a 1
         //
         else {
                if(DptMsg_P->Reply->StdReplyFrame.DetailedStatusCode)
                 {
                   Rtnval = DptMsg_P->Reply->StdReplyFrame.DetailedStatusCode;
                 }
                 else {
                        Rtnval = 1;
                 }
         }

        //
        // Put the message packet back on the free list
        //
        dpti_FreeDptMsg(dptcard,DptMsg_P);

      } //if(DptMsgReturn_P == DptMsg_P)

      //
      // Wrong packet returned, print an error message and set up an error
      //
      else {
		printk("dpti_I2oSetSysTab: Wrong message Returned\n");
      }

   } //if(DptMsg_P != NULL)

	KWDEBUG(dbg_setsystab, printk("DPT I2O: dpti_I2oSetSysTab: exit.\n");)

  return(Rtnval);

}




//-------------------------------------------------------------------------
//                     Function dpti_I2oEnableSys                          
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     HbaNum : Host Adapter Number                                        
//                                                                         
// This function will send off the I2O Enable Sys message to the passed
// in HBA number
//                                                                         
// This function should only be called at init time
//                                                                         
// Return : 0 for success, error code otherwise                            
//-------------------------------------------------------------------------

STATIC INT32 
dpti_I2oEnableSys(pDPT_HBA_T dptcard)
{
  PI2O_EXEC_SYS_ENABLE_MESSAGE EnableSysMsg_P;
  pDPT_MSG_T DptMsg_P;
  pDPT_MSG_T DptMsgReturn_P;
  INT32 Rtnval = 0x0ff;
  UINT16 MessageSize = sizeof(I2O_EXEC_SYS_ENABLE_MESSAGE) >> 2;
  UINT8 SglOffset = 0;
#ifdef LOCALONSTACK
	UINT8   localmsg[MAX_MESSAGE_SIZE];
#endif

#ifdef DEBUG_PRINT
  if(DebugFlags &  HBA_FLAGS_DBG_FUNCTION_ENTRY_B)
   {
     dpti_Printf(NULL, "\ndpti_I2oEnableSys : Enter");
   }
#endif 
	KWDEBUG(dbg_enablesys, printk("DPT I2O: dpti_I2oEnableSys: entered.\n");)

  //
  // Allocate a message packet
  //
  DptMsg_P = dpti_AllocDptMsg(dptcard);
  if(DptMsg_P != NULL) {
     //
     // Grab a pointer to the local message pointer
     //
#ifdef LOCALONSTACK
	DptMsg_P->LocalToIopMsg = &localmsg[0];
       	memset(&localmsg, 0, MAX_MESSAGE_SIZE);
#endif
     EnableSysMsg_P = (PI2O_EXEC_SYS_ENABLE_MESSAGE)(DptMsg_P->LocalToIopMsg);

     //
     // Fill out the standard header
     //
     EnableSysMsg_P->StdMessageFrame.VersionOffset = SglOffset | I2O_VERSION_11;
     EnableSysMsg_P->StdMessageFrame.MsgFlags = 0;
     EnableSysMsg_P->StdMessageFrame.MessageSize = MessageSize;
     EnableSysMsg_P->StdMessageFrame.TargetAddress = 0;
     EnableSysMsg_P->StdMessageFrame.InitiatorAddress = 1;
     EnableSysMsg_P->StdMessageFrame.Function = I2O_EXEC_SYS_ENABLE;
     EnableSysMsg_P->StdMessageFrame.InitiatorContext = DptMsg_P->unique;
     EnableSysMsg_P->TransactionContext = (I2O_TRANSACTION_CONTEXT)DptMsg_P;

     //
     // Send off the command polled
     //
     DptMsgReturn_P = dpti_SendPolledCommand(dptcard,DptMsg_P,0, 0);

     //
     // Check to make sure that this is the one we sent out
     //
     if(DptMsgReturn_P == DptMsg_P)
      {
        //
        // Good return for a success
        //
        if(DptMsg_P->Reply->StdReplyFrame.ReqStatus == I2O_REPLY_STATUS_SUCCESS)
         {
           Rtnval = 0;
         }
         
         //
         // Bad return, if the detailed status code is set up, we will
         // return that, otherwisw return a 1
         //
         else {
                if(DptMsg_P->Reply->StdReplyFrame.DetailedStatusCode)
                 {
                   Rtnval = DptMsg_P->Reply->StdReplyFrame.DetailedStatusCode;
                 }
                 else {
                        Rtnval = 1;
                 }
         }

        //
        // Put the message packet back on the free list
        //
        dpti_FreeDptMsg(dptcard, DptMsg_P);

      } //if(DptMsgReturn_P == DptMsg_P)

      //
      // Wrong packet returned, print an error message and set up an error
      //
      else {
		printk("dpti_I2oEnableSys: Wrong message Returned\n");
      }

   } //if(DptMsg_P != NULL)

  return(Rtnval);

} 

//-------------------------------------------------------------------------
//                     Function dpti_BuildDeviceList                       
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     HbaNum : Host Adapter Number                                        
//                                                                         
// This function will find all of the devices for the passed in HBA number
// and build a linked list of device info structures
//                                                                         
// This function should only be called at init time
//                                                                         
// Return : Number of devices found
//-------------------------------------------------------------------------

STATIC INT32 
dpti_BuildDeviceList(pDPT_HBA_T dptcard)
{
  pDEVINFO_T Dev_P;
  PI2O_LCT Lct_P;
  PI2O_LCT_ENTRY LctEntry_P;
  UINT8 Buffer[100];
  INT32 Count,NumEntries,i,Index;
  INT32 NumChannels = 0; 
  INT32 NumDevices = 0;
  UINT8 *Ptr;
  UINT8 OperationBuffer[100];
  PI2O_PARAM_OPERATIONS_LIST_HEADER OperationHeader_P;
  PI2O_PARAM_OPERATION_ALL_TEMPLATE OperationBlock_P;
  PI2O_PARAM_RESULTS_LIST_HEADER ResultHeader_P;
  PI2O_DPT_DEVICE_INFO_SCALAR ScsiDeviceParams_P;
  PI2O_HBA_SCSI_CONTROLLER_INFO_SCALAR PortParams_P;
  PI2O_DPT_EXEC_IOP_BUFFERS_SCALAR BufferParamsInfo_P;
  UINT16 ChannelTIDs[10];
  UINT8 ChannelInfoValid = FALSE;

	KWDEBUG(dbg_builddevicelist, printk("DPT I2O: dpti_BuildDeviceList: entered.\n");)

	memset((void *) scratchbuf, 0, SCRATCHBUFSIZE);
	memset(ChannelTIDs, 0, sizeof(ChannelTIDs));
	memset(OperationBuffer, 0, sizeof(OperationBuffer));
	memset(Buffer, 0, sizeof(Buffer));

  //
  // Set up the ParamsGet structure pointers
  //
  OperationHeader_P = (PI2O_PARAM_OPERATIONS_LIST_HEADER)OperationBuffer;
  OperationBlock_P = (PI2O_PARAM_OPERATION_ALL_TEMPLATE)(OperationBuffer +
                     sizeof(I2O_PARAM_OPERATIONS_LIST_HEADER));
  ResultHeader_P = (PI2O_PARAM_RESULTS_LIST_HEADER)Buffer;
  PortParams_P = (PI2O_HBA_SCSI_CONTROLLER_INFO_SCALAR) (Buffer +
                     sizeof(I2O_PARAM_RESULTS_LIST_HEADER) +
                     sizeof(I2O_PARAM_READ_OPERATION_RESULT));
  ScsiDeviceParams_P = (PI2O_DPT_DEVICE_INFO_SCALAR) (Buffer +
                     sizeof(I2O_PARAM_RESULTS_LIST_HEADER) +
                     sizeof(I2O_PARAM_READ_OPERATION_RESULT));

	memset((void *) scratchbuf, 0, SCRATCHBUFSIZE);
  //
  // Send off the I2O LCT Notify Command to get the device list
  //
  if(!dpti_I2oLCTNotify(dptcard, (UINT8 *) scratchbuf, SCRATCHBUFSIZE))
   {
		KWDEBUG(dbg_builddevicelist, printk("dpti_BuildDeviceList: dpti_I2oLCTNotify returned successful.\n");)
     //
     // Grab a pointer to the LCT table and a pointer to the first device
     // entry in the table
     //
     Lct_P = (PI2O_LCT)scratchbuf;
     LctEntry_P = Lct_P->LCTEntry;
	KWDEBUG(dbg_builddevicelist, printk("dpti_BuildDeviceList: TableSize = %d, TableEntrySize = %d.\n", (int) Lct_P->TableSize, (int) LctEntry_P->TableEntrySize);)

     //
     // Calculate the number of device entries in the table
     //
	if (Lct_P->TableSize <= 3) {
		printk("dpti_BuildDeviceLlist: No table returned from dpti_I2oLCTNotify, TableSize = 0x%x\n", (unsigned int) Lct_P->TableSize);
		return (0);	/* return 0 devices */
	}
     NumEntries = (Lct_P->TableSize - 3) * 4 / sizeof(I2O_LCT_ENTRY);

	KWDEBUG(dbg_builddevicelist, printk("dpti_BuildDeviceList: NumEntries after calling I2oLCTNotify = %d.\n", (int) NumEntries);)

     //
     // Set up the operations list header
     //
     OperationHeader_P->OperationCount = 1;
     OperationHeader_P->Reserved = 0;

     // Set up the operations block to get all of the fields for
     // the params get message
     //
     OperationBlock_P->Operation = I2O_PARAMS_OPERATION_FIELD_GET;
     OperationBlock_P->GroupNumber =
                   I2O_DPT_EXEC_IOP_BUFFERS_GROUP_NO;
     OperationBlock_P->FieldCount = 0xffff;

     BufferParamsInfo_P = (PI2O_DPT_EXEC_IOP_BUFFERS_SCALAR) PortParams_P;

     //
     // Send of an I2O Params Get Message to get the debug buffer // information
     //
     if(!dpti_I2oParamsGet(dptcard, 0,
                          OperationBuffer,
                          sizeof(I2O_PARAM_OPERATIONS_LIST_HEADER) +
                          sizeof(I2O_PARAM_OPERATION_ALL_TEMPLATE),
                          Buffer,64))
      {
		KWDEBUG(dbg_builddevicelist, printk("dpti_BuildDeviceList: dpti_I2oParamsGet returned successful.\n");)
        //
        // Make sure we have a result count first
        //
		KWDEBUG(dbg_builddevicelist, printk("dpti_BuildDeviceList: ResultHeader_P->ResultCount = %d\n", ResultHeader_P->ResultCount);)
        if(ResultHeader_P->ResultCount)
         {

           //
           // Set up the debug buffer fields in the HBA structure
           // from the data returned
           //
           dptcard->FwDebugBufferSize =
                                BufferParamsInfo_P->SerialOutputSize;
           dptcard->FwDebugBuffer_P = dptcard->VirtualBaseAddress_P +
                                BufferParamsInfo_P->SerialOutputOffset;
           dptcard->FwDebugFlags_P =
                            (pUINT32)(dptcard->FwDebugBuffer_P +
                                      FW_DEBUG_FLAGS_OFFSET);
           dptcard->FwDebugStrLength_P =
                                 (pUINT32)(dptcard->FwDebugBuffer_P +
                                           FW_DEBUG_STR_LENGTH_OFFSET);
           dptcard->FwDebugBuffer_P +=
                                BufferParamsInfo_P->SerialHeaderSize;
           dptcard->FwDebugFlags = 0;
           dptcard->Flags |= DebugFlags;

#ifdef DEBUG_PRINT
           dpti_Printf(DptHba_P,"DPTI2O.SYS v%d.%c%c %d/%d/%d %s",
                       DPT_VERSION,DPT_REVISION,DPT_SUBREVISION,
                       DPT_MONTH,DPT_DAY,1980 + DPT_YEAR,
                       DPTI_Sig.dsDescription);
#endif
         } //if(ResultHeader_P->ResultCount)
      
      }  // if(!dpti_I2oParamsGet(HbaNum,LctEntry_P->LocalTID,
	else {
		KWDEBUG(dbg_builddevicelist, printk("dpti_BuildDeviceList: dpti_I2oParamsGet Failed: return 0.\n");)
		return(0);
	}

#ifdef DEBUG_PRINT 
  if(DebugFlags & HBA_FLAGS_DBG_INIT_B)
   {
     dpti_PrintI2oLctTable(dptcard,Lct_P,0);
     dpti_Printf(dptcard,"\nLCT NumEntries = %d",NumEntries);
   }
#endif

     //
     // Loop through all of the table entries and find the port (channel)
     // entries. Pull out the necessary information for these and set
     // up the number of channels on this HBA
     //
     for(Count = 0; Count < NumEntries; ++Count)
      {
#if 0
	KWDEBUG(dbg_builddevicelist, printk("class = 0x%x, ", LctEntry_P->ClassID.Class);)
#endif
        //
        // If this is a SCSI Port class, it is a channel to us
        //
        if(LctEntry_P->ClassID.Class == I2O_CLASS_BUS_ADAPTER_PORT)
         {
             
#ifdef DEBUG_PRINT 
           if(DebugFlags & HBA_FLAGS_DBG_INIT_B)
            {
              dpti_Printf(dptiHbaList_P[HbaNum],"\nProcess a Port class device");
            }
#endif
             
           //
           // If the channel TID was successfully obtained from the 
           // HRT, grab the correct device info structure for that
           // channel so we can set up the number and TID
           //
           Dev_P = NULL;
           if(ChannelInfoValid)
            {
              for(Index = 0; Index < MAX_CHANNEL; ++Index)
               {
                 if(ChannelTIDs[Index] == LctEntry_P->LocalTID)
                  {
                    Dev_P = &(dptcard->ChannelInfo[Index]);
                    Dev_P->ChannelNum = Index;
                    break;
                  }
               }
            }

           //
           // The channel info was invalid so we will assume the LCT has 
           // the channel entries set up in the correct order and do the
           // channel numbers and TIDs that way
           //
           if(Dev_P == NULL)
            {
              Dev_P = &(dptcard->ChannelInfo[NumChannels]);
              Dev_P->ChannelNum = NumChannels;
            }

           //
           // Save off the TID and other SCSI info for this port
           //
           Dev_P->TID = LctEntry_P->LocalTID;

	/*
	 * !!! Do NOT need Dev_P->HbaNum field.  Was only used in
	 * dpti_AddDevToTable to find the dptcard.  Pass in dptcard
	 * with it
	 *
	 * If decide to use it later.  Set it to dptcard->cardidx as
	 * commented out below
	 */
/*           Dev_P->HbaNum = HbaNum; */
           Dev_P->ScsiLUN = 0;
           Dev_P->DevType = I2O_SCSI_DEVICE_TYPE_PROCESSOR;
           Dev_P->Flags |= DEVINFO_FLAGS_SCSI_PORT_B;

           //
           // Update the Max channel number for this HBA
           //
           dptcard->MaxChannel = NumChannels;

	memset(OperationBuffer, 0, sizeof(OperationBuffer));
	memset(Buffer, 0, sizeof(Buffer));
           //
           // Set up the operations list header
           //
           OperationHeader_P->OperationCount = 1;
           OperationHeader_P->Reserved = 0;
          
           // Set up the operations block to get all of the fields for
           // the params get message 
           //
           OperationBlock_P->Operation = I2O_PARAMS_OPERATION_FIELD_GET;
           OperationBlock_P->GroupNumber = 
                         I2O_HBA_SCSI_CONTROLLER_INFO_GROUP_NO;
           OperationBlock_P->FieldCount = 0xffff;

           //
           // Send of an I2O Params Get Message to get SCSI information 
           // for this channel
           //
           if(!dpti_I2oParamsGet(dptcard,LctEntry_P->LocalTID,
                                OperationBuffer,
                                sizeof(I2O_PARAM_OPERATIONS_LIST_HEADER) +
                                sizeof(I2O_PARAM_OPERATION_ALL_TEMPLATE),
                                Buffer,64))
            {
		KWDEBUG(dbg_builddevicelist, printk("dpti_BuildDeviceList: dpti_I2oParamsGet second place returned successful.\n");)
              //
              // Make sure we have a result count first
              //
              if(ResultHeader_P->ResultCount)
               {
                 //
                 // Save off the SCSI ID LUN and Device Type for this channel
                 //
                 Dev_P->ScsiTargetID = PortParams_P->InitiatorID;

                 //
                 // Save off the Max Target ID for this channel
                 //
                 dptcard->MaxID = PortParams_P->MaxDataWidth - 1;

               } //if(ResultHeader_P->ResultCount)
              
            }  // if(!dpti_I2oParamsGet(HbaNum,LctEntry_P->LocalTID,

#ifdef DEBUG_PRINT
            else if (DebugFlags & HBA_FLAGS_DBG_ERROR_B ) {
                   dpti_Printf(dptiHbaList_P[HbaNum],
                          "\ndpti_BuildDeviceList : Params Get Message Failed");
            }
#endif
           //
           // Update the number of channels found for this HBA
           //
           ++NumChannels;

         } //if(LctEntry_P->ClassID.Class == I2O_CLASS_BUS_ADAPTER_PORT)

        //
        // Bump the device entry pointer to the next entry
        //
        LctEntry_P = (PI2O_LCT_ENTRY) ((UINT8 *)LctEntry_P + 
                        (LctEntry_P->TableEntrySize * 4));

      } //for(Count = 0; Count < NumEntries; ++Count)

#if 0
	KWDEBUG(dbg_builddevicelist, printk("\n");)
#endif
     //
     // Loop through all of the table entries again and find all unclaimed
     // Peripheral entries. Pull out the necessary information for these 
     //
     LctEntry_P = Lct_P->LCTEntry;
     for(Count = 0; Count < NumEntries; ++Count)
      {
        //
        // If this one is a SCSI or block device and doesn't have a
        // valid User TID, process it.
        //
        if(((LctEntry_P->ClassID.Class == I2O_CLASS_SCSI_PERIPHERAL)||
          (LctEntry_P->ClassID.Class == I2O_CLASS_RANDOM_BLOCK_STORAGE))&&
          ((LctEntry_P->UserTID == 0xfff)||(LctEntry_P->UserTID == 1)))
         {
           //
           // If we can't allocate memory for this device structure,
           // move on
           //
           if(!(Dev_P = (pDEVINFO_T )kmalloc(sizeof(DEVINFO_T), GFP_ATOMIC))) {
		 printk("dpti2o:  dpti_BuildDeviceList: could not allocate DEVINFO_T.\n");

		break;
            }
 	   memset(Dev_P, 0, sizeof(DEVINFO_T));

           //
           // Save off the TID for the device, the TID for the channel
           // and the HBA number
           //
           Dev_P->TID = LctEntry_P->LocalTID;

	/*
	 * !!! Do NOT need Dev_P->HbaNum field.  Was only used in
	 * dpti_AddDevToTable to find the dptcard.  Pass in dptcard
	 * with it
	 *
	 * If decide to use it later.  Set it to dptcard->cardidx as
	 * commented out below
	 */

/*           Dev_P->HbaNum = dptcard->cardidx; */
           if(LctEntry_P->ClassID.Class == I2O_CLASS_SCSI_PERIPHERAL)
            {
              Dev_P->Flags |= DEVINFO_FLAGS_SCSI_DEVICE_B;
            }
            else {
                   Dev_P->Flags |= DEVINFO_FLAGS_BLOCK_DEVICE_B;
            }
	memset(OperationBuffer, 0, sizeof(OperationBuffer));
	memset(Buffer, 0, sizeof(Buffer));

           //
           // Set up the operations list header
           //
           OperationHeader_P->OperationCount = 1;
           OperationHeader_P->Reserved = 0;
          
           // Set up the operations block to get all of the fields for
           // the params get message 
           //
           OperationBlock_P->Operation = I2O_PARAMS_OPERATION_FIELD_GET;
           OperationBlock_P->GroupNumber = I2O_DPT_DEVICE_INFO_GROUP_NO;
           OperationBlock_P->FieldCount = 0xffff;

           //
           // Send of an I2O Params Get Message to get SCSI information 
           // for this device
           //
           if(!dpti_I2oParamsGet(dptcard,LctEntry_P->LocalTID,
                                OperationBuffer,
                                sizeof(I2O_PARAM_OPERATIONS_LIST_HEADER) +
                                sizeof(I2O_PARAM_OPERATION_ALL_TEMPLATE),
                                Buffer,64))
            {
		KWDEBUG(dbg_builddevicelist, printk("dpti_BuildDeviceList: dpti_I2oParamsGet third place returned successful.\n");)
              //
              // Make sure we have a result count first
              //
              if(ResultHeader_P->ResultCount)
               {

                 //
                 // Save off the SCSI Device Information
                 //
                 Dev_P->ChannelNum = ScsiDeviceParams_P->Bus;
                 Dev_P->ScsiTargetID = ScsiDeviceParams_P->Identifier;
                 Dev_P->ScsiLUN = ScsiDeviceParams_P->LunInfo[1];
                 Dev_P->DevType = ScsiDeviceParams_P->DeviceType;
                 if((Dev_P->DevType == I2O_SCSI_DEVICE_TYPE_DIRECT) ||
                    (Dev_P->DevType == I2O_SCSI_DEVICE_TYPE_OPTICAL))
                  {
			memset(Buffer, 0, sizeof(Buffer));
                    if(!dpti_DoReadCapacity(dptcard,LctEntry_P->LocalTID,Buffer))
                     {
				KWDEBUG(dbg_builddevicelist, printk("dpti_BuildDeviceList: dpti_DoReadCapacity third place returned successful.\n");)
                       Ptr = (UINT8 *)&Dev_P->Capacity;
                       for(i = 0; i < 4; ++i)
                        {
                          Ptr[i] = Buffer[3 - i];
                        }
                       Ptr = (UINT8 *)&Dev_P->BlockSize;
                       for(i = 0; i < 4; ++i)
                        {
                          Ptr[i] = Buffer[7 - i];
                        }

                     } //if(!dpti_DoReadCapacity(HbaNum,LctEntry_P->LocalTID,

                  } //if((Dev_P->DevType == I2O_SCSI_DEVICE_TYPE_DIRECT) ||

               } //if(ResultHeader_P->ResultCount)

            } // if(!dpti_I2oParamsGet(HbaNum,LctEntry_P->LocalTID,

#ifdef DEBUG_PRINT
            else if (DebugFlags & HBA_FLAGS_DBG_ERROR_B ) {
                   dpti_Printf(dptiHbaList_P[HbaNum],
                           "\nI2oParamsGet Failed For HBA %d TID %d",
                           HbaNum,LctEntry_P->LocalTID);
            }
#endif
           //
           // Add the device to the HBAs device list 
           //
           Dev_P->NextDevice_P = dptcard->DeviceList_P;
           dptcard->DeviceList_P = Dev_P;

           //
           // into the look up table.
           //
           ++NumDevices;
           dpti_AddDevToTable(Dev_P, dptcard);

#ifdef DEBUG_PRINT 
           if(DebugFlags & HBA_FLAGS_DBG_SCAN_B)
            {
              dpti_Printf(dptiHbaList_P[HbaNum],"\nPrint The Dev Info");
              dpti_PrintDevInfo(dptiHbaList_P[HbaNum],Dev_P,0);
            }
#endif

         } //if(LctEntry_P->ClassID.Class == I2O_CLASS_SCSI_PERIPHERAL)

        //
        // Bump the device entry pointer to the next entry
        //
        LctEntry_P = (PI2O_LCT_ENTRY) ((UINT8 *)LctEntry_P + 
                        (LctEntry_P->TableEntrySize * 4));

      } //for(Count = 0; Count < NumEntries; ++Count)

   } //if(!dpti_I2oLCTNotify(HbaNum,dptiScratchBuffer,SCRATCH_BUFFER_SIZE))
	else {
		KWDEBUG(dbg_builddevicelist, printk("dpti_BuildDeviceList: dpti_I2oLCTNotify Failed: return 0.\n");)
		return(0);
	}


#ifdef DEBUG_PRINT
   else if (DebugFlags & HBA_FLAGS_DBG_ERROR_B ) {
          dpti_Printf(NULL, "\ndpti_BuildDeviceList : I2oLCTNotify Failed");
   }
#endif

#ifdef DEBUG_PRINT
  if(DebugFlags &  HBA_FLAGS_DBG_FUNCTION_EXIT_B)
   {
     dpti_Printf(NULL, "\ndpti_BuildDeviceList : Exit, Rtnval = %x",NumDevices);
   }
#endif

  return(NumDevices);

} //STATIC INT32 dpti_BuildDeviceList(INT32 HbaNum)





//-------------------------------------------------------------------------
//                     Function dpti_I2oLCTNotify                          
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     HbaNum : Host Adapter Number                                        
//	dptcard:  host card
//     Buffer : Buffer for the logical configuration table
//     BufferSize : Size of the passed in buffer
//                                                                         
// This Function                                                           
//                                                                         
// Return :                                                                
//-------------------------------------------------------------------------

STATIC INT32 
dpti_I2oLCTNotify(pDPT_HBA_T dptcard, UINT8 *Buffer,INT32 BufferSize)
{
  PI2O_EXEC_LCT_NOTIFY_MESSAGE LCTNotifyMsg_P;
  pDPT_MSG_T DptMsg_P;
  pDPT_MSG_T DptMsgReturn_P;
  INT32 Rtnval = 1;
  UINT16 MessageSize = (sizeof(I2O_EXEC_LCT_NOTIFY_MESSAGE) -
                      sizeof(I2O_SG_ELEMENT)) >> 2;
  UINT8 SglOffset = (UINT8)(MessageSize << 4);
#ifdef LOCALONSTACK
	UINT8   localmsg[MAX_MESSAGE_SIZE];
#endif

	KWDEBUG(dbg_lctnotify, printk("DPT I2O: dpti_I2oLCTNotify: entered.\n");)

  //
  // Allocate a message packet
  //
  DptMsg_P = dpti_AllocDptMsg(dptcard);
  if(DptMsg_P != NULL) {
     //
     // Grab a pointer to the local message pointer
     //
#ifdef LOCALONSTACK
	DptMsg_P->LocalToIopMsg = &localmsg[0];
       	memset(&localmsg, 0, MAX_MESSAGE_SIZE);
#endif
     LCTNotifyMsg_P = (PI2O_EXEC_LCT_NOTIFY_MESSAGE)(DptMsg_P->LocalToIopMsg);

     //
     // Fill out the standard header
     //
     LCTNotifyMsg_P->StdMessageFrame.VersionOffset = SglOffset | I2O_VERSION_11;
     LCTNotifyMsg_P->StdMessageFrame.MsgFlags = 0;
     LCTNotifyMsg_P->StdMessageFrame.MessageSize = MessageSize;
     LCTNotifyMsg_P->StdMessageFrame.TargetAddress = 0;
     LCTNotifyMsg_P->StdMessageFrame.InitiatorAddress = 1;
     LCTNotifyMsg_P->StdMessageFrame.Function = I2O_EXEC_LCT_NOTIFY;
     LCTNotifyMsg_P->StdMessageFrame.InitiatorContext = DptMsg_P->unique;
     LCTNotifyMsg_P->TransactionContext = (I2O_TRANSACTION_CONTEXT)DptMsg_P;

	/*
	 * If the Buffer is NULL, we are calling this from dpt_resethost, and
	 * we do not want the table returned
	 */

	if (Buffer != NULL) {

		//
		// Set it up to return all of the entries in the table
		//
		LCTNotifyMsg_P->ClassIdentifier = I2O_CLASS_MATCH_ANYCLASS;
		LCTNotifyMsg_P->LastReportedChangeIndicator = 0;
		LCTNotifyMsg_P->SGL.u.Simple[0].FlagsCount.Count = BufferSize;
		LCTNotifyMsg_P->SGL.u.Simple[0].FlagsCount.Flags = 
                                      I2O_SGL_FLAGS_LAST_ELEMENT | 
                                      I2O_SGL_FLAGS_END_OF_BUFFER | 
                                      I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT;
		LCTNotifyMsg_P->SGL.u.Simple[0].PhysicalAddress = virt_to_bus(Buffer);

		//
		// Bump the message size by two to allow for the 
		// Scatter Gather entry
		//
		LCTNotifyMsg_P->StdMessageFrame.MessageSize += 2;
	}

     //
     // Send off the command polled
     //
	printk("DPT: Reading the hardware resource table.  This could take up to 5 minutes\n");
     DptMsgReturn_P = dpti_SendPolledCommand(dptcard, DptMsg_P, 300, 0);
	printk("DPT: Hardware resource table read.\n");

     //
     // Check to make sure that this is the one we sent out
     //
     if(DptMsgReturn_P == DptMsg_P)
      {
        //
        // Good return for a success
        //
        if(DptMsg_P->Reply->StdReplyFrame.ReqStatus == I2O_REPLY_STATUS_SUCCESS)
         {
           Rtnval = 0;
         }
         
         //
         // Bad return, if the detailed status code is set up, we will
         // return that, otherwisw return a 1
         //
         else {
                if(DptMsg_P->Reply->StdReplyFrame.DetailedStatusCode)
                 {
                   Rtnval = DptMsg_P->Reply->StdReplyFrame.DetailedStatusCode;
                 }
                 else {
                        Rtnval = 1;
                 }
         }

        //
        // Put the message packet back on the free list
        //
        dpti_FreeDptMsg(dptcard, DptMsg_P);

      } //if(DptMsgReturn_P == DptMsg_P)

      //
      // Wrong packet returned, print an error message and set up an error
      //
      else {
		printk("dpti_I2oLCTNotify: Wrong message Returned\n");
      }

   } //if(DptMsg_P != NULL)

#ifdef DEBUG_PRINT
  if(DebugFlags &  HBA_FLAGS_DBG_FUNCTION_EXIT_B)
   {
     dpti_Printf(NULL, "\ndpti_I2oLCTNotify : Exit, Rtnval = %x",Rtnval);
   }
#endif

  return(Rtnval);

} //STATIC INT32 dpti_I2oLCTNotify(INT32 HbaNum,UINT8 *Buffer,INT32 BufferSize)


//-------------------------------------------------------------------------
//                     Function dpti_I2oHrtGet                             
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     HbaNum : Host Adapter Number                                        
//	dptcard: host card (adapter)
//     Buffer_P : Buffer for the logical configuration table
//     BufferSize : Size of the passed in buffer
//                                                                         
// This Function will send off the HRT Get command to the passed
// in HBA
//                                                                         
// Return : 0 for success, error code otherwise                            
//-------------------------------------------------------------------------

STATIC INT32 
dpti_I2oHrtGet(pDPT_HBA_T dptcard, pUINT8 Buffer_P, INT32 BufferSize)
{
  PI2O_EXEC_HRT_GET_MESSAGE HrtGetMsg_P;
  pDPT_MSG_T DptMsg_P;
  pDPT_MSG_T DptMsgReturn_P;
  INT32 Rtnval = 1;
  UINT16 MessageSize = (sizeof(I2O_EXEC_HRT_GET_MESSAGE) -
                      sizeof(I2O_SG_ELEMENT)) >> 2;
  UINT8 SglOffset = (UINT8)(MessageSize << 4);
#ifdef LOCALONSTACK
	UINT8   localmsg[MAX_MESSAGE_SIZE];
#endif

	KWDEBUG(dbg_hrtget, printk("DPT I2O: dpti_I2oHrtGet: entered.\n");)
	KWDEBUG(dbg_hrtget, printk("dpti_I2oHrtGet: Buffer_P = 0x%x, virt_to_bus(Buffer_P) = 0x%x.\n", (unsigned int) Buffer_P, (unsigned int) virt_to_bus(Buffer_P));)

  //
  // Allocate a message packet
  //
  DptMsg_P = dpti_AllocDptMsg(dptcard);
  if(DptMsg_P != NULL) {
     //
     // Grab a pointer to the local message pointer
     //
#ifdef LOCALONSTACK
	DptMsg_P->LocalToIopMsg = &localmsg[0];
       	memset(&localmsg, 0, MAX_MESSAGE_SIZE);
#endif
     HrtGetMsg_P = (PI2O_EXEC_HRT_GET_MESSAGE)(DptMsg_P->LocalToIopMsg);

     //
     // Fill out the standard header
     //
     HrtGetMsg_P->StdMessageFrame.VersionOffset = SglOffset | I2O_VERSION_11;
     HrtGetMsg_P->StdMessageFrame.MsgFlags = 0;
     HrtGetMsg_P->StdMessageFrame.MessageSize = MessageSize;
     HrtGetMsg_P->StdMessageFrame.TargetAddress = 0;
     HrtGetMsg_P->StdMessageFrame.InitiatorAddress = 1;
     HrtGetMsg_P->StdMessageFrame.Function = I2O_EXEC_HRT_GET;
     HrtGetMsg_P->StdMessageFrame.InitiatorContext = DptMsg_P->unique;
     HrtGetMsg_P->TransactionContext = (I2O_TRANSACTION_CONTEXT)DptMsg_P;

     //
     // Set it up to return all of the entries in the table
     //
     HrtGetMsg_P->SGL.u.Simple[0].FlagsCount.Count = BufferSize;
     HrtGetMsg_P->SGL.u.Simple[0].FlagsCount.Flags = 
                                      I2O_SGL_FLAGS_LAST_ELEMENT | 
                                      I2O_SGL_FLAGS_END_OF_BUFFER | 
                                      I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT;
     HrtGetMsg_P->SGL.u.Simple[0].PhysicalAddress = virt_to_bus(Buffer_P);

     //
     // Bump the message size by two to allow for the 
     // Scatter Gather entry
     //
     HrtGetMsg_P->StdMessageFrame.MessageSize += 2;

     //
     // Send off the command polled
     //
     DptMsgReturn_P = dpti_SendPolledCommand(dptcard,DptMsg_P,0, 0);

     //
     // Check to make sure that this is the one we sent out
     //
     if(DptMsgReturn_P == DptMsg_P)
      {
        //
        // Good return for a success
        //
        if(DptMsg_P->Reply->StdReplyFrame.ReqStatus == I2O_REPLY_STATUS_SUCCESS)
         {
           Rtnval = 0;
         }
         
         //
         // Bad return, if the detailed status code is set up, we will
         // return that, otherwisw return a 1
         //
         else {
                if(DptMsg_P->Reply->StdReplyFrame.DetailedStatusCode)
                 {
                   Rtnval = DptMsg_P->Reply->StdReplyFrame.DetailedStatusCode;
                 }
                 else {
                        Rtnval = 1;
                 }
         }

        //
        // Put the message packet back on the free list
        //
        dpti_FreeDptMsg(dptcard, DptMsg_P);

      } //if(DptMsgReturn_P == DptMsg_P)

      //
      // Wrong packet returned, print an error message and set up an error
      //
      else {
		printk("dpti_I2oHrtGet: Wrong message Returned\n");
      }

   } //if(DptMsg_P != NULL)

  return(Rtnval);

} //STATIC INT32 dpti_I2oHrtGet(INT32 HbaNum,

//-------------------------------------------------------------------------
//                     Function dpti_I2oParamsGet
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     HbaNum : Host Adapter Number                                        
//	dptcard: host card (adapter)
//     TID : TID of the device to send the command to
//     OperationBuffer : Buffer for the params information
//     OperationBufferSize : Size of the passed in buffer
//     DataBuffer : Buffer for the params information
//     DataBufferSize : Size of the passed in buffer
//                                                                         
// This Function                                                           
//                                                                         
// Return :                                                                
//-------------------------------------------------------------------------

STATIC INT32 
dpti_I2oParamsGet(pDPT_HBA_T dptcard, UINT32 TID, UINT8 *OperationBuffer,
                             INT32 OperationBufferSize,
                             UINT8 *DataBuffer,
                             INT32 DataBufferSize)
{

  PI2O_UTIL_PARAMS_GET_MESSAGE ParamsGetMsg_P;
  pDPT_MSG_T DptMsg_P;
  pDPT_MSG_T DptMsgReturn_P;
  INT32 Rtnval = 1;
  UINT16 MessageSize = (sizeof(I2O_UTIL_PARAMS_GET_MESSAGE) -
                    sizeof(I2O_SG_ELEMENT)) >> 2;
  UINT8 SglOffset = (UINT8)(MessageSize << 4);
#ifdef LOCALONSTACK
	UINT8   localmsg[MAX_MESSAGE_SIZE];
#endif

	KWDEBUG(dbg_paramsget, printk("DPT I2O: dpti_I2oParamsGet: entered.\n");)

  //
  // Allocate a message packet
  //
  DptMsg_P = dpti_AllocDptMsg(dptcard);
  if(DptMsg_P != NULL)
   {
     //
     // Grab a pointer to the local message pointer
     //
#ifdef LOCALONSTACK
	DptMsg_P->LocalToIopMsg = &localmsg[0];
       	memset(&localmsg, 0, MAX_MESSAGE_SIZE);
#endif
     ParamsGetMsg_P = (PI2O_UTIL_PARAMS_GET_MESSAGE)(DptMsg_P->LocalToIopMsg);

     //
     // Fill out the standard header
     //
     ParamsGetMsg_P->StdMessageFrame.VersionOffset = SglOffset | I2O_VERSION_11;
     ParamsGetMsg_P->StdMessageFrame.MsgFlags = 0;

     //
     // Add 4 to the Message size to account for the 2 Scatter Gather Entries
     //
     ParamsGetMsg_P->StdMessageFrame.MessageSize = MessageSize;
     ParamsGetMsg_P->StdMessageFrame.TargetAddress = TID;
     ParamsGetMsg_P->StdMessageFrame.InitiatorAddress = 1;
     ParamsGetMsg_P->StdMessageFrame.Function = I2O_UTIL_PARAMS_GET;
     ParamsGetMsg_P->StdMessageFrame.InitiatorContext = DptMsg_P->unique;
     ParamsGetMsg_P->TransactionContext = (I2O_TRANSACTION_CONTEXT)DptMsg_P;
     ParamsGetMsg_P->SGL.u.Simple[0].FlagsCount.Count = OperationBufferSize;
     ParamsGetMsg_P->SGL.u.Simple[0].FlagsCount.Flags = 
                                         I2O_SGL_FLAGS_END_OF_BUFFER |
                                         I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT;
     ParamsGetMsg_P->SGL.u.Simple[0].PhysicalAddress = virt_to_bus(OperationBuffer);
     ParamsGetMsg_P->SGL.u.Simple[1].FlagsCount.Count = DataBufferSize;
     ParamsGetMsg_P->SGL.u.Simple[1].FlagsCount.Flags = 
                                         I2O_SGL_FLAGS_LAST_ELEMENT | 
                                         I2O_SGL_FLAGS_END_OF_BUFFER | 
                                         I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT;
     ParamsGetMsg_P->SGL.u.Simple[1].PhysicalAddress = virt_to_bus(DataBuffer);

     //
     // Bump the message size by four to allow for the 
     // Scatter Gather entries
     //
     ParamsGetMsg_P->StdMessageFrame.MessageSize += 4;

     //
     // Send off the command polled
     //
     DptMsgReturn_P = dpti_SendPolledCommand(dptcard, DptMsg_P,0, 0);

     //
     // Check to make sure that this is the one we sent out
     //
     if(DptMsgReturn_P == DptMsg_P)
      {
        //
        // Good return for a success
        //
        if(DptMsg_P->Reply->StdReplyFrame.ReqStatus == I2O_REPLY_STATUS_SUCCESS)
         {
           Rtnval = 0;
         }
         
         //
         // Bad return, if the detailed status code is set up, we will
         // return that, otherwisw return a 1
         //
         else {
                if(DptMsg_P->Reply->StdReplyFrame.DetailedStatusCode)
                 {
                   Rtnval = DptMsg_P->Reply->StdReplyFrame.DetailedStatusCode;
                 }
                 else {
                        Rtnval = 1;
                 }
         }

        //
        // Put the message packet back on the free list
        //
        dpti_FreeDptMsg(dptcard, DptMsg_P);

      } //if(DptMsgReturn_P == DptMsg_P)

      //
      // Wrong packet returned, print an error message and set up an error
      //
      else {
		printk("dpti_I2oParamsGet: Wrong message Returned\n");
      }

   } //if(DptMsg_P != NULL)

  return(Rtnval);

} // STATIC INT32 dpti_I2oParamsGet(INT32 HbaNum, UINT32 TID, 



//-------------------------------------------------------------------------
//                     Function dpti_SendPolledCommand                    
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     dptcard : Host Adapter 
//     DptMsg_P : Msg Structure Pointer For This Command                   
//     SecondsToWait : Number of seconds to wait for command to complete
//                                                                         
// This function will send off the passed in message to the passed in HBA
// and poll until the command has completed or the command times out.
//                                                                         
// Return : The return reply packet or null if timed out.
//-------------------------------------------------------------------------

STATIC pDPT_MSG_T 
dpti_SendPolledCommand(pDPT_HBA_T dptcard, pDPT_MSG_T DptMsg_P, INT32 SecondsToWait, int prnt)
{
  pDPT_MSG_T DptMsgReturn_P;
  I2O_INITIATOR_CONTEXT unique_returned;
	int i = 1000 * SecondsToWait;

	KWDEBUG(dbg_sendpolledcommand, printk("dpti_SendPolledCommand Entered\n");)

  //
  // Disable the interrupts to the system and send off
  // the command
  //
  dpti_DisableInterrupts(dptcard);
  dpti_I2oSendMessage(dptcard,DptMsg_P);

  //
  // Poll for the interrupt pending bit being set
  //
#if DEBUGMSGSEQUENCE
tryagain:
#endif
	if (SecondsToWait > 0) {
 		while(!(*dptcard->IntStatusReg_P & I2O_INTERRUPT_PENDING_B) && (i > 0)) {
			i--;
			dpt_delay(1);	/* delay 1 ms */
			if (prnt && ((i % 1000) == 0)) {
				printk(".");
			}
		}
 		if(!(*dptcard->IntStatusReg_P & I2O_INTERRUPT_PENDING_B)) {
			/* 
			 * if no interrupt, return NULL
			 */	
  			dpti_EnableInterrupts(dptcard);
			printk("dpti_SendPolledCommand: TIMED OUT!\n");
			return (NULL);
		}
	} else {
		/* 
		 * wait indefinitely for command to come back
		 */
 		 while(!(*dptcard->IntStatusReg_P & I2O_INTERRUPT_PENDING_B)) barrier();
	}

  //
  // Pull off the reply packet from the queue and enable system interrupts
  //
  DptMsgReturn_P = dpt_getreplymsg(dptcard, &unique_returned);

#if DEBUGMSGSEQUENCE

	if (DptMsg_P->unique != unique_returned) {
		printk("dpti_SendPolled: received unexpected message: unique_returned = 0x%x, unique sent = 0x%x\n",
		unique_returned, DptMsg_P->unique);
		if (SecondsToWait > 0) {
			goto tryagain;
		} else {
			dpt_msgdone(DptMsgReturn_P, dptcard);
		}
	} else {
		printk("dpti_SendPolled: received expected message: unique_returned = 0x%x, unique sent = 0x%x\n",
		unique_returned, DptMsg_P->unique);
	}
#endif /* DEBUGMSGSEQUENCE */

  dpti_EnableInterrupts(dptcard);

  return(DptMsgReturn_P);
}



//-------------------------------------------------------------------------
//                         Function dpti_DoReadCapacity
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     HbaNum : Host Adapter Number                                        
//	dptcard: host card (adapter)
//     TID : TID of the device to send the command to
//     Buffer : Pointer to a buffer for the inquiry data
//                                                                         
// This function is called to send off a read capacity for the passed in 
// device. This is a single threaded init function and interrupts will 
// be disabled.
//                                                                         
// Return : 0 for success, error code otherwise
//-------------------------------------------------------------------------

/*
 * Note: sd_init_onedisk() already has read the capacity
 */
STATIC INT32 
dpti_DoReadCapacity(pDPT_HBA_T dptcard, UINT32 TID, UINT8 *Buffer)
{
  volatile pDPT_MSG_T DptMsg_P;
  pDPT_MSG_T DptMsgReturn_P;
  PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE ExecScsiMsg_P;
  INT32 Rtnval = 1;
  UINT16 MessageSize = (sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE) -
                    sizeof(I2O_SG_ELEMENT)) >> 2;
  UINT8 SglOffset = (UINT8)(MessageSize << 4);
#ifdef LOCALONSTACK
	UINT8   localmsg[MAX_MESSAGE_SIZE];
#endif

#ifdef DEBUG_PRINT
  if(dptiHbaList_P[HbaNum]->Flags &  HBA_FLAGS_DBG_FUNCTION_ENTRY_B)
   {
     dpti_Printf(dptiHbaList_P[HbaNum], "\ndpti_DoReadCapacity : Enter");
   }
#endif 

	KWDEBUG(dbg_doreadcapacity, printk("DPT I2O: dpti_DoReadCapacity: entered.\n");)

  //
  // Allocate a request message packet for the command
  //
  DptMsg_P = dpti_AllocDptMsg(dptcard);

  if(DptMsg_P != NULL) {
     //
     // Fill out the local copy of the request message for an
     // Inquiry SCSI command
     //
#ifdef LOCALONSTACK
	DptMsg_P->LocalToIopMsg = &localmsg[0];
       	memset(&localmsg, 0, MAX_MESSAGE_SIZE);
#endif
     ExecScsiMsg_P = (PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)(DptMsg_P->LocalToIopMsg);

     DptMsg_P->Flags = 0;
     DptMsg_P->scsicmd = NULL;
   
     //
     // Set up the standard header
     //
     ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.VersionOffset = 
                                                 SglOffset | I2O_VERSION_11;
     ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.MsgFlags = 0;
     ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.MessageSize = 
                                                                MessageSize;
     ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.TargetAddress = TID;
     ExecScsiMsg_P->TID = TID;
     ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.InitiatorAddress = 1;
     ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.Function = 
                                                          I2O_PRIVATE_MESSAGE;
     ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.InitiatorContext = DptMsg_P->unique;
     ExecScsiMsg_P->PrivateMessageFrame.TransactionContext = 
                                       (I2O_TRANSACTION_CONTEXT)DptMsg_P;
     ExecScsiMsg_P->PrivateMessageFrame.OrganizationID = DPT_ORGANIZATION_ID;
     ExecScsiMsg_P->PrivateMessageFrame.XFunctionCode = I2O_SCSI_SCB_EXEC;
   
  memset((UINT8 *)&ExecScsiMsg_P->CDB, 0, I2O_SCSI_CDB_LENGTH);
     ExecScsiMsg_P->CDBLength = 10;
     ExecScsiMsg_P->SCBFlags = I2O_SCB_FLAG_ENABLE_DISCONNECT | 
                               I2O_SCB_FLAG_SIMPLE_QUEUE_TAG;
     ExecScsiMsg_P->CDB[0] = READ_CAPACITY;	/* see sd_init_onedisk() */
     ExecScsiMsg_P->ByteCount = 8;
     ExecScsiMsg_P->SCBFlags |= I2O_SCB_FLAG_XFER_FROM_DEVICE;
   
     //
     // Set up a single simple scatter gather element
     //
     ExecScsiMsg_P->SGL.u.Simple[0].FlagsCount.Count = 8;
     ExecScsiMsg_P->SGL.u.Simple[0].FlagsCount.Flags = 
                                     I2O_SGL_FLAGS_LAST_ELEMENT | 
                                     I2O_SGL_FLAGS_END_OF_BUFFER | 
                                     I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT;
     ExecScsiMsg_P->SGL.u.Simple[0].PhysicalAddress = virt_to_bus(Buffer);

     //
     // Bump the message size by two to allow for the 
     // Scatter Gather entry
     //
     ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.MessageSize += 2;
   
     //
     // No posting or timeout routine set up for this one
     //
     DptMsg_P->MSG_Post_P = 0;
     DptMsg_P->TimeoutValue = 0;
   
     //
     // Send off the command polled
     //
     DptMsgReturn_P = dpti_SendPolledCommand(dptcard, DptMsg_P, 0, 0);

     //
     // Check to make sure that this is the one we sent out
     //
     if(DptMsgReturn_P == DptMsg_P)
      {
        //
        // Good return for a success
        //
        if(DptMsg_P->Reply->StdReplyFrame.ReqStatus == I2O_REPLY_STATUS_SUCCESS)
         {
           Rtnval = 0;
         }
            
         //
         // Bad return, if the detailed status code is set up, we will
         // return that, otherwisw return a 1
         //
         else {
                if(DptMsg_P->Reply->StdReplyFrame.DetailedStatusCode)
                 {
                   Rtnval = DptMsg_P->Reply->StdReplyFrame.DetailedStatusCode;
                 }
                 else {
                        Rtnval = 2;
                 }
         }
   
        //
        // Put the message packet back on the free list
        //
        dpti_FreeDptMsg(dptcard, DptMsg_P);

      } //if(DptMsgReturn_P == DptMsg_P)

     //
     // Wrong packet returned, print an error message and set up an error
     //
      else {
		printk("dpti_DoReadCapacity: Wrong message Returned\n");
      }

   } //if(DptMsg_P != NULL)

   else {
          Rtnval = 2;
   }
   
  return(Rtnval);
}

//-------------------------------------------------------------------------
//                     Function dpti_DisableInterrupts                     
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     HbaNum : Host Adapter Number                                        
//	dptcard: host card (adapter)
//                                                                         
// This function will disable interrupts to the system for the passed
// in HBA
//                                                                         
// Return : None
//-------------------------------------------------------------------------

STATIC INT32 
dpti_DisableInterrupts(pDPT_HBA_T dptcard)
{
  INT32 Rtnval = 0;

  *dptcard->IntMaskReg_P |= I2O_INTERRUPTS_DISABLED_B;

  return(Rtnval);
}

//-------------------------------------------------------------------------
//                     Function dpti_EnableInterrupts                     
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     HbaNum : Host Adapter Number                                        
//	dptcard:  host card (adapter)
//                                                                         
// This function will enable interrupts to the system for the passed
// in HBA
//                                                                         
// Return : None
//-------------------------------------------------------------------------

STATIC INT32 
dpti_EnableInterrupts(pDPT_HBA_T dptcard)
{
  INT32 Rtnval = 0;


  *dptcard->IntMaskReg_P &= ~I2O_INTERRUPTS_DISABLED_B;

  return(Rtnval);
}



/**********************************************************************
 * dpt_deletedevs is called from the reset code to free all of the
 * device structures stored in the  host bus adapter's ScsiDeviceTable_P
 **********************************************************************/
static void
dpt_deletedevs(pDPT_HBA_T dpthost)
{
	pDEVINFO_T devp, nextdevp;
	int target, channel;

	/*
	 * loop through all channels on the adapter
	 */
	for (channel = 0; channel < MAX_CHANNEL; channel++) {
		/*
		 * loop through all targets on the channel 
		 */
		for (target = 0; target < MAX_TARGET_ID; target++) {
			devp = dpthost->ScsiDeviceTable_P[channel][target];
			/*
			 * free device structure
			 */
			while (devp) {
				nextdevp = devp->NextLun_P;
				devp->NextLun_P = NULL;	/* precautionary */
				kfree(devp);
				devp = nextdevp;
			}
			dpthost->ScsiDeviceTable_P[channel][target] = NULL;
		}
	}
}


//-------------------------------------------------------------------------
//                     Function dpti_AddDevToTable                   
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     Dev_P : Pointer To A Filled Out Dev Structure                       
//                                                                         
// This function will add the passed in dev pointer to the device lookup   
// table. If there is an element found at the HBA:BUS:TARGET position in   
// the list, the dev will be added to the end of the LUN linked list that  
// starts with the element found here.                                     
//                                                                         
// Return : NONE                                                           
//-------------------------------------------------------------------------

STATIC VOID 
dpti_AddDevToTable(pDEVINFO_T Dev_P, pDPT_HBA_T dptcard)
{
  pDEVINFO_T Table_P;

	KWDEBUG(dbg_adddevtotable,  printk("dpti_AddDevToTable: Entered\n");)

  //
  // First check to see if anybody lives here yet 
  //
  Table_P = dptcard->ScsiDeviceTable_P[Dev_P->ChannelNum][Dev_P->ScsiTargetID];
  //
  // If nobody is home, move in 
  //
  if(Table_P == NULL)
   {
     dptcard->ScsiDeviceTable_P[Dev_P->ChannelNum][Dev_P->ScsiTargetID] = Dev_P;
   }

  //
  // Somebody was home so find the end of the list and add him on 
  //
   else {
          while(Table_P->NextLun_P != NULL)
           {
             Table_P = Table_P->NextLun_P;
           }

          //
          // First check for no dupes
          //
          if(Table_P->ScsiLUN != Dev_P->ScsiLUN)
           {
             Table_P->NextLun_P = Dev_P;
           }
   }  
}



//-------------------------------------------------------------------------
//                     Function dpti_GetDevFromTable                       
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     HbaNum : Host Adapter Number                                        
//     Channel : HBA Channel Number                                        
//     Target : Target ID For The Command                                  
//     Lun : Logical Unit Number For The Commnand                          
//                                                                         
// This function will retrieve the Dev pointer from the device lookup Table 
// for the SCSI address passed in. If no Dev is found, NULL is returned.   
//                                                                         
// Return : Pointer To The Dev If Found, NULL If Not Found                 
//-------------------------------------------------------------------------

STATIC pDEVINFO_T 
dpti_GetDevFromTable(pDPT_HBA_T dptcard, INT32 Channel, INT32 Target, INT32 Lun)
{
  pDEVINFO_T Table_P;

	KWDEBUG(dbg_getdevfromtable,  printk("dpti_GetDevFromTable: Entered\n");)

  //
  // Grab the head of the LUN list for this address 
  //
  Table_P = dptcard->ScsiDeviceTable_P[Channel][Target];

  //
  // Now go through the list until we find the LUN we are looking for 
  //
  while((Table_P != NULL)&&(Table_P->ScsiLUN != Lun))
   {
     Table_P = Table_P->NextLun_P;
   }

  return(Table_P);
}
  

/*
 * ASSUMPTIONS:  Must be called with io_request_lock held in the 2.2.xx tree.
 * NOTE: io_request_lock must be obtained before calling cmd->scsi_done
 */
static void
dpt_finish_commands(pDPT_HBA_T dpthost)
{
	Scsi_Cmnd *cmd = NULL;


	DEQUEUE(cmd, Scsi_Cmnd, dpthost->doneq, host_scribble, dpthost->doneq_lock)
	while (cmd) {
		cmd->host_scribble = NULL;
		cmd->scsi_done(cmd);
		DEQUEUE(cmd, Scsi_Cmnd, dpthost->doneq, host_scribble, dpthost->doneq_lock)
	}
}


/*
 * dpt_msgdone is called from some debugging code in dpti_SendPolledCommand
 *
 * TODO:  Should call this routine from dpti_SendPolledCommand even if
 *	  not in debugging code, but receive the wrong packet.
 */
void
dpt_msgdone(pDPT_MSG_T dptmsg, pDPT_HBA_T dpthost)
{
	unsigned long reqlockflags = 0;

	if(dptmsg  == (pDPT_MSG_T )NULL) {
		printk("dpt_msgdone: dpt_getreplymsg returned NULL when I2O_INTERRUPT_PENDING_B was set\n"); 
			return;
	}
	/*
	 * NOTE: if the message was a reset, etc., the scsicmd field
	 * will be NULL, so cannot enqueue because field is NULL
	 */
	if (dptmsg->scsicmd != NULL) {
		ENQUEUE((dptmsg->scsicmd), Scsi_Cmnd, donetq, host_scribble, donetq_lock)
	} else {
		/* 
		 * processing a command that was not sent from layer
		 * above, so can process it immediately
		 */
		if(dptmsg->MSG_Post_P) {
			(*dptmsg->MSG_Post_P)(dptmsg);
		} else {
			/* 
			 * no routine to call, so free message and
			 * print a message stating don't know what to do
			 */
			dpti_FreeDptMsg(dpthost, dptmsg);
			printk("dpt_msgdone: (1)received message with no post routine set\n");
		}
	}
#ifdef QUEUETASK
	queue_task_irq(&dpt_intrtq, &tq_scheduler); 
#else	/* QUEUETASK */

#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
	SPIN_LOCK_IRQSAVE(&io_request_lock, reqlockflags)
#endif	/* LINUX_VERSION_CODE ... */

	dpt_finish_commands(dpthost);

#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
	SPIN_UNLOCK_IRQRESTORE(&io_request_lock, reqlockflags)
#endif	/* LINUX_VERSION_CODE ... */

#endif	/* QUEUETASK */
}


//-------------------------------------------------------------------------
//                        Function dptiintr                                
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     InterruptVector : Vector Number That Interrupted
//                                                                         
// This function is the interrupt handler for all HBAs supported by    
// this driver. Loop through all HBAs handling all outstanding requests
// until all requests are processed or the limmit has been reached.
//                                                                         
// Return : None                                                           
//-------------------------------------------------------------------------

static VOID 
dpti2o_intr(int irq, void *dev_id, struct pt_regs *regs)
{
  pDPT_MSG_T DptMsg_P = NULL;
	pDPT_HBA_T      dpthost;	/* ptr to per card structure */
  I2O_INITIATOR_CONTEXT unique_returned;
	int replycnt = 0;
#ifdef INTRLOCKS
	unsigned long flags3;
#endif
	unsigned long reqlockflags = 0;

	KWDEBUG(dbg_dpti2ointr,  printk("dpti20_intr: Entered\n");)

	dpthost = (pDPT_HBA_T)dev_id;
	if ((dpthost == NULL) || (!(dpthost->Flags & HBA_FLAGS_INSTALLED_B))) {
		printk("dpti2o_intr: called with NULL dev_id, or card not installed: dev_id = 0x%x\n",
			(unsigned int) dpthost);
		return;
	}
	SPIN_LOCK_IRQSAVE(&io_request_lock, reqlockflags)

morecommands:
	/*
	 * Note p. 4-5
	 */
	/* probably lock here */
#ifdef INTRLOCKS
	SPIN_LOCK_IRQSAVE(&dpthost->HardwareLock, flags3)
#endif	/* INTRLOCKS */
        while ((*dpthost->IntStatusReg_P & I2O_INTERRUPT_PENDING_B) &&
		(replycnt++ < DPTREPLYSPERINTERRUPT)) {
		if((DptMsg_P = dpt_getreplymsg(dpthost, &unique_returned)) == (pDPT_MSG_T )NULL) {
			printk(KERN_WARNING "dpti2o_intr: dpt_getreplymsg returned NULL when I2O_INTERRUPT_PENDING_B was set\n"); 
			SPIN_UNLOCK_IRQRESTORE(&io_request_lock, reqlockflags)
#ifdef INTRLOCKS
			SPIN_UNLOCK_IRQRESTORE(&dpthost->HardwareLock, flags3)
#endif	/* INTRLOCKS */
			return;
		}

#if QUEUETASK
		/*
		 * NOTE: if the message was a reset, etc., the scsicmd field
		 * will be NULL, so cannot enqueue because field is NULL
		 */
		if (DptMsg_P->scsicmd != NULL) {
			ENQUEUE((DptMsg_P->scsicmd), Scsi_Cmnd, donetq, host_scribble, donetq_lock)
		} else {
			/* 
			 * processing a command that was not sent from layer
			 * above, so can process it immediately
			 */
			if(DptMsg_P->MSG_Post_P) {
				(*DptMsg_P->MSG_Post_P)(DptMsg_P);
			} else {
				/* 
				 * no routine to call, so free message and
				 * print a message stating don't know what to do
				 */
				dpti_FreeDptMsg(dpthost, DptMsg_P);
				printk("dpti2o_intr: (1)received message with no post routine set\n");
			}
		}

#else
		/*
		 * call dpti_OsRequestPost, or driverpost
		 */
		if(DptMsg_P->MSG_Post_P) {
			(*DptMsg_P->MSG_Post_P)(DptMsg_P);
		} else {
			/* 
			 * no routine to call, so free message and
			 * print a message stating don't know what to do
			 */
			dpti_FreeDptMsg(dpthost, DptMsg_P);
			printk("dpti2o_intr: (2)received message with no post routine set\n");
		}
#endif	/* QUEUETASK */
		
	}

	if (replycnt >= DPTREPLYSPERINTERRUPT) {
		printk("dpti20_intr: replycnt = %d\n", replycnt);
	}
#ifdef QUEUETASK
	queue_task_irq(&dpt_intrtq, &tq_scheduler); 
#ifdef INTRLOCKS
	SPIN_UNLOCK_IRQRESTORE(&dpthost->HardwareLock, flags3)
#endif	/* INTRLOCKS */
	SPIN_UNLOCK_IRQRESTORE(&io_request_lock, reqlockflags)

#else	/* QUEUETASK */
#ifdef INTRLOCKS
	SPIN_UNLOCK_IRQRESTORE(&dpthost->HardwareLock, flags3)
#endif	/* INTRLOCKS */

	dpt_finish_commands(dpthost);
	dpt_docmd((void *)dpthost);
        if ((*dpthost->IntStatusReg_P & I2O_INTERRUPT_PENDING_B)) {
		goto morecommands;
	}
	SPIN_UNLOCK_IRQRESTORE(&io_request_lock, reqlockflags)
#endif	/* QUEUETASK */

  return;

}

/***********************************************************************
 * dpt_dobh is the bottom half handler for the interrupt service routine.
 * It is called when the scheduler task queue is scheduled (see sched.c)
 *
 * NOTE: It is only used in the 2.0.xx tree.
 * NOTE: The scsi layer above MUST NOT be called with interrupts blocked.
 **********************************************************************/
void
dpt_dobh(void *dpth)
{
	pDPT_MSG_T dptmsg = NULL;
	Scsi_Cmnd *cmd = NULL;
	volatile pDPT_HBA_T dpthost;
	unsigned long cardflags = 0;


	KWDEBUG(dbg_dptdobh, printk("dpt_dobh Entered\n");)

	DEQUEUE(cmd, Scsi_Cmnd, donetq, host_scribble, donetq_lock)
	while (cmd) {
		dptmsg = (pDPT_MSG_T)cmd->SCp.ptr;
		dpthost = (pDPT_HBA_T)cmd->host->hostdata;
		/*
		 * call dpti_OsRequestPost, or driverpost
		 */
		if(dptmsg->MSG_Post_P) {
			(*dptmsg->MSG_Post_P)(dptmsg);
		} else {
			/*
			 * Don't have anything to do, free message
			 */
			dpti_FreeDptMsg(dpthost, dptmsg);
			printk("dpt_dobh: received message with no post routine set\n");
		}
		DEQUEUE(cmd, Scsi_Cmnd, donetq, host_scribble, donetq_lock)
	}

	SPIN_LOCK_IRQSAVE(&cardlist_lock, cardflags)
	for (dpthost = cardlist; dpthost; dpthost = dpthost->next) {
#ifndef FAIRQUEUE
		dpt_docmd((void *)dpthost);
#endif
	}
	SPIN_UNLOCK_IRQRESTORE(&cardlist_lock, cardflags)
#if FAIRQUEUE
	dpt_docmdallhosts(NULL);
#endif
}


//-------------------------------------------------------------------------
//                     Function dpt_getreplymsg                           
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     dptcard : Host Adapter Number                                        
//                                                                         
// This function will attempt to pull a reply message off of the fifo.
// If there is a message there, it will pull out the original message 
// pointer, copy the reply packet info into the original message, and 
// return the reply packet back to the HBA fifo.
//                                                                         
// Return : Original message pointer if there is a reply pending,
//          Null otherwise 
//-------------------------------------------------------------------------

STATIC pDPT_MSG_T 
dpt_getreplymsg(pDPT_HBA_T dptcard, I2O_INITIATOR_CONTEXT *return_unique)
{
  volatile pDPT_MSG_T DptMsg_P;
  volatile UINT32 PhysReplyAddr;
  UINT32 MsgOffset;
  PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE ExecScsiMsg_P;
  PI2O_FAILURE_REPLY_MESSAGE_FRAME FailedReply_P;
  PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME Reply_P;

#if DEBUGMSGSEQUENCE
  I2O_INITIATOR_CONTEXT unique_returned;
#endif /* DEBUGMSGSEQUENCE */


	KWDEBUG(dbg_getreplymsg, printk("dpt_getreplymsg Entered\n");)
   

  //
  // Pull off a reply message physical address
  //
	/* !!! Checks TWICE FOR EMPTY QUEUE (Intel workaround) */
  PhysReplyAddr = *dptcard->FromIopFifo_P;
  if(PhysReplyAddr == EMPTY_QUEUE) {
     PhysReplyAddr = *dptcard->FromIopFifo_P;
   }

  //
  // If there was one there, process it
  //
  if(PhysReplyAddr != EMPTY_QUEUE)
   {
     //
     // Convert the physical address to a virtual reply pointer
     //
     Reply_P = (PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME)bus_to_virt(PhysReplyAddr);

     //
     // If we have a failed message, our virtual pointer will not be 
     // returned but the offset of the I2O message will, so we must get
     // our virtual pointer from that.
     //
     if(Reply_P->StdReplyFrame.StdMessageFrame.MsgFlags & 
                                               I2O_MESSAGE_FLAGS_FAIL)
      {
#ifdef DEBUG_PRINT 
        if(DebugFlags & HBA_FLAGS_DBG_ERROR_B)
         {
           dpti_Printf(dptiHbaList_P[HbaNum],"\nWe Have A Failed Message!!!");
         }
#endif
	KWDEBUG(dbg_getreplymsg, printk("dpt_getreplymsg: We Have A Failed Message!!!\n");)

        // 
        // Set up a failed reply packet pointer
        //
        FailedReply_P = (PI2O_FAILURE_REPLY_MESSAGE_FRAME)Reply_P;

        //
        // Get the offset into the memory mapped space of the original
        // I2O message and convert it to a virtual pointer
        //
        MsgOffset = (UINT32)FailedReply_P->PreservedMFA;
        ExecScsiMsg_P = 
          (PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)(dptcard->
                                         VirtualBaseAddress_P + MsgOffset);
        //
        // Grab the DPT Message pointer from the original I2O message
        //
        DptMsg_P = 
         (pDPT_MSG_T )ExecScsiMsg_P->PrivateMessageFrame.TransactionContext;

#if DEBUGMSGSEQUENCE

	unique_returned = ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.InitiatorContext;
	printk("dpt_getreplymsg failed: unique_returned = 0x%x\n", unique_returned);
	*return_unique = unique_returned;

#endif /* DEBUGMSGSEQUENCE */

        //
        // Now we have to return the I2O message back to the HBA by 
        // sending out a NOP function. This should not generate an
        // interrupt, and we already have the lock so do it here
        //
        // Set up the standard header
        //
        ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.
                                          VersionOffset = I2O_VERSION_11;
        ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.MsgFlags = 0;
        ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.MessageSize = 
                           sizeof(I2O_UTIL_NOP_MESSAGE) >> 2;
        ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.TargetAddress = 0;
        ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.InitiatorAddress = 1;
        ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.Function = 
                                                                I2O_UTIL_NOP;
        ExecScsiMsg_P->PrivateMessageFrame.StdMessageFrame.InitiatorContext = 0;

        //
        // Put the physical offset of the message into the queue for
        // the HBA to pick up
        //
        *dptcard->ToIopFifo_P = MsgOffset;

      } //if(Reply_P->StdReplyFrame.StdMessageFrame.MsgFlags & I2O_MESSAGE_

     // 
     // This one is not a fail so just pull out the DPT Message pointer
     //
      else {
             //
             // Pull out the original request packet pointer
             //
             DptMsg_P = (pDPT_MSG_T)(Reply_P->StdReplyFrame.TransactionContext);

#if DEBUGMSGSEQUENCE
		unique_returned = DptMsg_P->unique;
		printk("dpt_getreplymsg not failed: unique_returned = 0x%x\n", unique_returned);
		*return_unique = unique_returned;

#endif /* DEBUGMSGSEQUENCE */

      }

     //
     // Copy the reply message contents into the original request
     //
	/* memcpy(to, from, size) */

#ifdef LOCALREPLY
     memcpy((UINT8 *)DptMsg_P->Reply, (UINT8 *)Reply_P,
            sizeof(I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME));
#else
     memcpy((UINT8 *)&DptMsg_P->Reply, (UINT8 *)Reply_P,
            sizeof(I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME));
#endif	/* LOCALREPLY */

     //
     // Return the reply packet to the HBA Fifo
     //
     *dptcard->FromIopFifo_P = PhysReplyAddr;

   } //if(PhysReplyAddr != EMPTY_QUEUE)

  //
  // The fifo was empty so set up a NULL return
  //
   else  {

	 printk("dpt_getreplymsg: No Reply On The Queue\n");

          DptMsg_P = NULL;
   }

  return(DptMsg_P);
}

//-------------------------------------------------------------------------
//                    Function dpti_OsRequestPost                          
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     DptMsg_P : DPT message structure to be processed
//                                                                         
// This Function Will Set Up The Return Status And Post The OS Request     
// Packet Found In The Passed In MSG                                       
//                                                                         
// Return : 0                                                              
//-------------------------------------------------------------------------
/*
 * If do bottom and top half driver, do this in top half in a loop for
 * every msg queued up
 */

STATIC INT32 
dpti_OsRequestPost(pDPT_MSG_T DptMsg_P)
{
  UINT32 Length;
	Scsi_Cmnd *cmd;
	pDPT_HBA_T	dpthost;	/* host bus adapter structure */
	unsigned char adapterstatus;	/* is Bob's host_sts */
	unsigned char devicestatus;	/* is Bob's target_sts */

	KWDEBUG(dbg_osrequestpost, printk("dpti_OsRequestPost Entered\n");)

  //
  // Save off the SCSI target status and the host status in the 
  // OS request packet
  //
#ifdef LOCALREPLY
	devicestatus =  DptMsg_P->Reply->StdReplyFrame.DetailedStatusCode  
				& I2O_SCSI_DEVICE_DSC_MASK;

	adapterstatus =  (DptMsg_P->Reply->StdReplyFrame.DetailedStatusCode  
				& I2O_SCSI_HBA_DSC_MASK) >> 8;
#else
	devicestatus =  DptMsg_P->Reply.StdReplyFrame.DetailedStatusCode  
				& I2O_SCSI_DEVICE_DSC_MASK;

	adapterstatus =  (DptMsg_P->Reply.StdReplyFrame.DetailedStatusCode  
				& I2O_SCSI_HBA_DSC_MASK) >> 8;

#endif	/* LOCALREPLY */

	cmd = DptMsg_P->scsicmd;

	/*
	 * If there is no command, are probably in wrong post routine
	 */
	if (cmd == NULL) {
		printk("dpti2: dpti_OsRequestPost: no command to post, are probably in wrong post routine\n");
		dpthost = dpti20cards[DptMsg_P->HbaNum];
		dpti_FreeDptMsg(dpthost, DptMsg_P);
		return(0);
	}
	dpthost = (pDPT_HBA_T)cmd->host->hostdata;
	/*
	 * clear timeout fields so layer above won't time this command out
	 */
#if LINUX_VERSION_CODE < 0x020100
	cmd->timeout = SD_TIMEOUT;
#else	/* LINUX_VERSION_CODE is > 0x020100 */
	dpt_add_timer(cmd, SD_TIMEOUT);
#endif

	cmd->SCp.ptr = NULL;	/* clear ptr to dptmsg */

  //
  // Proccess the return request status if the message did not fail 
  //
  if(!(DptMsg_P->Reply->StdReplyFrame.StdMessageFrame.MsgFlags & 
                                                   I2O_MESSAGE_FLAGS_FAIL))
   {
     //
     // If we have some sort of an error status, set up the proper
     // OS status associated with it.
     //
     if(DptMsg_P->Reply->StdReplyFrame.ReqStatus)
      {
#ifdef DEBUG_PRINT 
        if(dptiHbaList_P[DptMsg_P->HbaNum]->Flags & HBA_FLAGS_DBG_ERROR_B)
         {
           dpti_Printf(dptiHbaList_P[DptMsg_P->HbaNum],
               "\nError In OsRequestPost, ReqStatus = %x, DetailedStatusCode = %x",
                DptMsg_P->Reply.StdReplyFrame.ReqStatus,
                DptMsg_P->Reply.StdReplyFrame.DetailedStatusCode);
           dpti_Printf(dptiHbaList_P[DptMsg_P->HbaNum],"\ndevice (%d,%d,%d,%d)",
                        DptMsg_P->HbaNum, OsRequest_P->bus_num,
                        OsRequest_P->id, OsRequest_P->lun);
           dpti_Printf(dptiHbaList_P[DptMsg_P->HbaNum],"\nCDB OpCode = %x",
                       OsRequest_P->opcode);
           dpti_PrintDptMsg(dptiHbaList_P[DptMsg_P->HbaNum],DptMsg_P ,0);
         }
#endif

        switch(DptMsg_P->Reply->StdReplyFrame.DetailedStatusCode &
                                                   I2O_SCSI_HBA_DSC_MASK) {
           case I2O_SCSI_HBA_DSC_SUCCESS :
		cmd->result = (DID_OK << 16);
                break;
           case I2O_SCSI_HBA_DSC_REQUEST_ABORTED :
		cmd->result = (DID_ABORT << 16);
                break;
           case I2O_SCSI_HBA_DSC_UNABLE_TO_ABORT :
           case I2O_SCSI_HBA_DSC_COMPLETE_WITH_ERROR :
           case I2O_SCSI_HBA_DSC_UNABLE_TO_TERMINATE :
           case I2O_SCSI_HBA_DSC_MR_MESSAGE_RECEIVED :
           case I2O_SCSI_HBA_DSC_AUTOSENSE_FAILED :
           case I2O_SCSI_HBA_DSC_DATA_OVERRUN :
           case I2O_SCSI_HBA_DSC_UNEXPECTED_BUS_FREE :
           case I2O_SCSI_HBA_DSC_SEQUENCE_FAILURE :
           case I2O_SCSI_HBA_DSC_REQUEST_LENGTH_ERROR :
           case I2O_SCSI_HBA_DSC_PROVIDE_FAILURE :
           case I2O_SCSI_HBA_DSC_REQUEST_TERMINATED :	/* ??? correct */
           case I2O_SCSI_HBA_DSC_IDE_MESSAGE_SENT :
           case I2O_SCSI_HBA_DSC_UNACKNOWLEDGED_EVENT :
           case I2O_SCSI_HBA_DSC_MESSAGE_RECEIVED :
           case I2O_SCSI_HBA_DSC_INVALID_CDB :
           case I2O_SCSI_HBA_DSC_LUN_INVALID :
           case I2O_SCSI_HBA_DSC_SCSI_TID_INVALID :
           case I2O_SCSI_HBA_DSC_FUNCTION_UNAVAILABLE :
           case I2O_SCSI_HBA_DSC_NO_NEXUS :
           case I2O_SCSI_HBA_DSC_SCSI_IID_INVALID :
           case I2O_SCSI_HBA_DSC_CDB_RECEIVED :
           case I2O_SCSI_HBA_DSC_LUN_ALREADY_ENABLED :	/* ??? correct */
           case I2O_SCSI_HBA_DSC_QUEUE_FROZEN :
		cmd->result = (DID_ERROR << 16);
                break;
           case I2O_SCSI_HBA_DSC_ADAPTER_BUSY :
           case I2O_SCSI_HBA_DSC_BUS_BUSY :
		cmd->result = (DID_BUS_BUSY << 16);
                break;
           case I2O_SCSI_HBA_DSC_REQUEST_INVALID :
		cmd->result = (DID_ERROR << 16);
                break;
           case I2O_SCSI_HBA_DSC_PATH_INVALID :
		cmd->result = (DID_ERROR << 16);
                break;
           case I2O_SCSI_HBA_DSC_DEVICE_NOT_PRESENT :
		cmd->result = (DID_NO_CONNECT << 16);
                break;
           case I2O_SCSI_HBA_DSC_SELECTION_TIMEOUT :
           case I2O_SCSI_HBA_DSC_COMMAND_TIMEOUT :
           case I2O_SCSI_HBA_DSC_NO_ADAPTER :
           case I2O_SCSI_HBA_DSC_RESOURCE_UNAVAILABLE :	/* ??? correct */
		cmd->result = (DID_TIME_OUT << 16);
                break;
           case I2O_SCSI_HBA_DSC_SCSI_BUS_RESET :
           case I2O_SCSI_HBA_DSC_BDR_MESSAGE_SENT :	/* ??? correct */
		cmd->result = (DID_RESET << 16);
                break;
           case I2O_SCSI_HBA_DSC_PARITY_ERROR_FAILURE :
/*		cmd->result = (DID_PARITY << 16); */
		/* ??? SHould this be DID_ERROR - don't want it to retry */
		cmd->result = (DID_ERROR << 16);
                break;

           default :
		cmd->result = (DID_ERROR << 16);
                break;

         }

        //
        // If there is a SCSI target status, save it off in the OS request 
        // packet and copy over the request sense data if it was a check
        // condition status
        //
        if(devicestatus == I2O_SCSI_DSC_CHECK_CONDITION) {

		Length = sizeof(cmd->sense_buffer);
		Length = (Length > I2O_SCSI_SENSE_DATA_SZ) ? I2O_SCSI_SENSE_DATA_SZ : Length;

           //
           // Copy over the sense data
           //
	/* memcpy(to, from, size) */

#ifdef LOCALREPLY 
		memcpy(cmd->sense_buffer, (pUINT8)&DptMsg_P->Reply->SenseData,
			Length);

#else
		memcpy(cmd->sense_buffer, (pUINT8)&DptMsg_P->Reply.SenseData,
			Length);
#endif	/* LOCALREPLY */

	KWDEBUG(dbg_osrequestpost, printk("dpti_OsRequestPost CHECK CONDITION set\n");)

 
         } //if(OsRequest_P->target_sts == I2O_SCSI_DSC_CHECK_CONDITION)


      } 

      //
      // All is well in paradise
      //
      else {
		cmd->result = (DID_OK << 16);
      }

   } 

   //
   // Message failed, return a selection time out
   //
   else {
#ifdef DEBUG_PRINT 
          if(dptiHbaList_P[DptMsg_P->HbaNum]->Flags & HBA_FLAGS_DBG_ERROR_B)
           {
             dpti_Printf(dptiHbaList_P[DptMsg_P->HbaNum],"\nThe Message Failed");
             dpti_PrintDptMsg(dptiHbaList_P[DptMsg_P->HbaNum],DptMsg_P ,0);
           }
#endif

		/*
		 * ??? CHECK THIS and MAKE SURE is CORRECT RETURN
		 */
		/*
		 * A selection timeout should return DID_TIME-OUT
		 
		 *  cmd->result = (DID_TIME_OUT << 16);

		 */
		 cmd->result = (DID_TIME_OUT << 16);

   }

	if ((cmd->result == (DID_ERROR << 16)) || (cmd->result == (DID_TIME_OUT << 16))) {
		printk("dpt cmd result = 0x%x, adapterstatus = 0x%x, devicestatus = 0x%x, cmd = 0x%x\n", cmd->result, adapterstatus, devicestatus, cmd->cmnd[0]);
	}
	cmd->result |= (devicestatus);
	KWDEBUG(dbg_osrequestpost, printk("dpti_OsRequestPost cmd result = 0x%x\n", cmd->result);)

  //
  // Free the MSG packet
  //
	dpti_FreeDptMsg(dpthost, DptMsg_P);

  //
  // If there is an OS request post routine, call it
  //
#if QUEUETASK
	cmd->scsi_done(cmd);
#else
	ENQUEUE(cmd, Scsi_Cmnd, dpthost->doneq, host_scribble, dpthost->doneq_lock)

#endif

	KWDEBUG(dbg_osrequestpost, printk("dpti_OsRequestPost Finished\n");)

  return(0);
}



//-------------------------------------------------------------------------
//                    Function dpti_DrvrRequestPost                          
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     DptMsg_P : DPT message structure to be processed
//                                                                         
// This Function Will 
// 
//                                                                         
// Return : 0                                                              
//-------------------------------------------------------------------------

STATIC INT32 
dpti_DrvrRequestPost(pDPT_MSG_T DptMsg_P)
{
	pDPT_HBA_T	dpthost;	/* host bus adapter structure */
	unsigned long flags;

	KWDEBUG(dbg_drvrrequestpost, printk("dpti_DrvrRequestPost Entered\n");)

	dpthost = dpti20cards[DptMsg_P->HbaNum];

	SPIN_LOCK_IRQSAVE(&dpthost->flaglock, flags)
	if (DptMsg_P->Flags & MSG_FLAG_IS_RESET) {
		DptMsg_P->Flags &= ~MSG_FLAG_IS_RESET;
		KWDEBUG(dbg_drvrrequestpost, printk("dpti_DrvrRequestPost: reset command completed\n");)
	}
	SPIN_UNLOCK_IRQRESTORE(&dpthost->flaglock, flags)

  //
  // Process the return request status if the message did not fail 
  //
  if(!(DptMsg_P->Reply->StdReplyFrame.StdMessageFrame.MsgFlags & 
                                                   I2O_MESSAGE_FLAGS_FAIL))
   {
     switch(DptMsg_P->Reply->StdReplyFrame.ReqStatus)
      {
        //
        // Good Return
        //
        case I2O_REPLY_STATUS_SUCCESS :
             break;

        //
        // Intermediate status report
        // (Currently Not Supported)
        //
        case I2O_REPLY_STATUS_PROGRESS_REPORT :
             break;

        //
        // Error on command, set up an error status
        //
        case I2O_REPLY_STATUS_ERROR_NO_DATA_TRANSFER :
        case I2O_REPLY_STATUS_ERROR_PARTIAL_TRANSFER :
             break;

        //
        // Command aborted, set up an aborted error
        //
        case I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER :
        case I2O_REPLY_STATUS_ABORT_PARTIAL_TRANSFER :
             break;

        //
        // All other status values will return an error
        //
        default :
             break;

      } //switch(DptMsg_P->Reply.StdReplyFrame.ReqStatus)

   } //if(!(DptMsg_P->Reply.StdReplyFrame.StdMessageFrame.MsgFlags & 

   //
   // Message failed, return a selection time out
   //
   else {
	/*
	 * for now, do nothing.  If ever am polling on a return value,
	 * set it here
	 */
   }

  if((DptMsg_P->Flags & MSG_FLAG_INQUIRY))
   {
     DptMsg_P->Flags &= ~MSG_FLAG_INQUIRY;
     KWDEBUG(dbg_drvrrequestpost, printk("dpti_DrvrRequestPost Inquiry returned\n");)
   }

  //
  // Free the MSG packet
  //
  dpti_FreeDptMsg(dpthost, DptMsg_P);

  return(0);
}

#ifdef DEBUG_PRINT
//-------------------------------------------------------------------------
//                   Function dpti_PrintI2oLctEntry                            
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     I2oLctEntry_P : Pointer To An I2O LCT Entry
//     Wait : Wait Flag                                                    
//                                                                         
// This Function Prints Out The Passed In I2O LCT Entry Structure
//                                                                         
// Return : NONE                                                           
//-------------------------------------------------------------------------

STATIC VOID dpti_PrintI2oLctEntry(pDPT_HBA_T dptcard,
                                  PI2O_LCT_ENTRY I2oLctEntry_P,
                                  INT32 Wait)
{
  INT32 i;
  UINT8 Buffer[100];

  printk("\nTableEntrySize = %x",(unsigned int) I2oLctEntry_P->TableEntrySize);
  printk("\nLocalTID = %x",I2oLctEntry_P->LocalTID);
  printk("\nreserved = %x",I2oLctEntry_P->reserved);
  printk("\nChangeIndicator = %x",(unsigned int) I2oLctEntry_P->ChangeIndicator);
  printk("\nDeviceFlags = %x",(unsigned int) I2oLctEntry_P->DeviceFlags);
  printk("\nClassID.Class = %x",I2oLctEntry_P->ClassID.Class);
  printk("\nClassID.Version = %x",I2oLctEntry_P->ClassID.Version);
  printk("\nClassID.OrganizationID = %x",
              (unsigned int) I2oLctEntry_P->ClassID.OrganizationID);
  printk("\nSubClassInfo = %x",(unsigned int) I2oLctEntry_P->SubClassInfo);
  printk("\nUserTID = %x",I2oLctEntry_P->UserTID);
  printk("\nParentTID = %x",I2oLctEntry_P->ParentTID);
  printk("\nBiosInfo = %x",(unsigned int) I2oLctEntry_P->BiosInfo);

  sprintf(Buffer, "\nIdentifyTag : ");
  for(i = 0; i < I2O_IDENTITY_TAG_SZ; ++i)
   {
     sprintf(Buffer, "%.2x ",I2oLctEntry_P->IdentityTag[i]);
   }
  printk("%s", (INT8 *) Buffer);
  printk("\nEventCapabilities = %x",
              (unsigned int) I2oLctEntry_P->EventCapabilities);
}

//-------------------------------------------------------------------------
//                   Function dpti_PrintI2oLctTable                            
//-------------------------------------------------------------------------
// The Parameters Passed To This Function Are :                            
//     I2oLct_P : Pointer To An I2O LCT Table
//     Wait : Wait Flag                                                    
//                                                                         
// This Function Prints Out The Passed In I2O LCT Table
//                                                                         
// Return : NONE                                                           
//-------------------------------------------------------------------------

STATIC VOID dpti_PrintI2oLctTable(pDPT_HBA_T dptcard,
                                  PI2O_LCT I2oLct_P,
                                  INT32 Wait)
{
  INT32 NumEntries,i;

  printk("\nTableSize = %x",(unsigned int) I2oLct_P->TableSize);  
  printk("\nBootDeviceTID = %x",I2oLct_P->BootDeviceTID);
  printk("\nLctVer = %x",I2oLct_P->LctVer);
  printk("\nIopFlags = %x",(unsigned int) I2oLct_P->IopFlags);
  printk("\nCurrentChangeIndicator = %x",
              (unsigned int) I2oLct_P->CurrentChangeIndicator);

  //
  // Calculate the number of device entries in the table
  //
  NumEntries = (I2oLct_P->TableSize - 3) * 4 / sizeof(I2O_LCT_ENTRY);
  printk("\nNumber Of LCT Entries = %x",(unsigned int) NumEntries);
  printk("\n-----------------------");
  printk("\nLctEntries : ");
  printk("\n-----------------------");
  for(i = 0; i < NumEntries; ++i)
   {
     dpti_PrintI2oLctEntry(dptcard, &I2oLct_P->LCTEntry[i] ,Wait);
     printk("\n-----------------------");
   }
}
#endif



#ifdef MODULE
Scsi_Host_Template driver_template = DPT_I2O;

#include "scsi_module.c"

#endif	/* MODULE */



---
This message has been sent through the ALE general discussion list.
See http://www.ale.org/mailing-lists.shtml for more info. Problems should be 
sent to listmaster at ale dot org.




More information about the Ale mailing list