diff -BburN linux.orig/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- linux.orig/drivers/scsi/Config.in	Sun Dec 10 18:49:42 2000
+++ linux/drivers/scsi/Config.in	Fri Feb  9 15:27:45 2001
@@ -26,6 +26,7 @@
 dep_tristate 'Adaptec AHA152X/2825 support' CONFIG_SCSI_AHA152X $CONFIG_SCSI
 dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI
 dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI
+dep_tristate 'Adaptec RAID Controller support' CONFIG_SCSI_AACRAID $CONFIG_SCSI
 dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
 if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
     bool '   Enable Tagged Command Queueing (TCQ) by default' CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
diff -BburN linux.orig/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- linux.orig/drivers/scsi/Makefile	Sun Dec 10 18:49:42 2000
+++ linux/drivers/scsi/Makefile	Fri Feb  9 15:29:08 2001
@@ -359,6 +359,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_SCSI_AACRAID),y)
+L_OBJS += aacraid.o
+else
+  ifeq ($(CONFIG_SCSI_AACRAID),m)
+  M_OBJS += aacraid.o
+  endif
+endif
+
 ifeq ($(CONFIG_SCSI_AIC7XXX),y)
 L_OBJS += aic7xxx.o
 else
@@ -741,3 +749,5 @@
 sd_mod.o: sd.o sd_ioctl.o
 	$(LD) $(LD_RFLAG) -r -o $@ sd.o sd_ioctl.o
 
+aacraid.o:
+	cd aacraid; make
diff -BburN linux.orig/drivers/scsi/aacraid/Makefile linux/drivers/scsi/aacraid/Makefile
--- linux.orig/drivers/scsi/aacraid/Makefile	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/Makefile	Fri Feb  9 15:27:45 2001
@@ -0,0 +1,171 @@
+#
+# Makefile aacraid Raid Controller
+#
+
+###############################################################################
+### SOURCE FILES DEFINES
+###############################################################################
+
+CFILES_DRIVER=\
+	./aachba.c \
+	./aacid.c \
+	./commctrl.c \
+	./comminit.c \
+	./commsup.c \
+	./dpcsup.c \
+	./linit.c \
+	./osddi.c \
+	./osfuncs.c \
+	./ossup.c \
+	./port.c \
+	./rx.c \
+	./sap1sup.c
+
+IFILES_DRIVER=\
+	./include/AacGenericTypes.h \
+	./include/aac_unix_defs.h \
+	./include/adapter.h \
+	./include/afacomm.h \
+	./include/aifstruc.h \
+	./include/build_number.h \
+	./include/commdata.h \
+	./include/commerr.h \
+	./include/commfibcontext.h \
+	./include/comprocs.h \
+	./include/comproto.h \
+	./include/comstruc.h \
+	./include/comsup.h \
+	./include/fsact.h \
+	./include/fsafs.h  \
+	./include/fsaioctl.h \
+	./include/fsaport.h \
+	./include/fsatypes.h \
+	./include/linit.h \
+	./include/monkerapi.h \
+	./include/nodetype.h \
+	./include/nvramioctl.h \
+	./include/osheaders.h \
+	./include/ostypes.h \
+	./include/pcisup.h \
+	./include/perfpack.h \
+	./include/port.h \
+	./include/protocol.h \
+	./include/revision.h \
+	./include/rxcommon.h \
+	./include/rx.h \
+	./include/sap1common.h \
+	./include/sap1.h \
+	./include/version.h
+
+ALL_SOURCE=\
+	${CFILES_DRIVER} \
+	${IFILES_DRIVER} 
+
+###############################################################################
+### OBJECT FILES DEFINES
+###############################################################################
+
+
+OFILES_DRIVER=\
+	linit.o \
+	osfuncs.o \
+	osddi.o \
+	aachba.o \
+	commctrl.o \
+	comminit.o \
+	commsup.o \
+	dpcsup.o \
+	ossup.o \
+	port.o \
+	rx.o \
+	sap1sup.o
+
+TARGET_OFILES= ${OFILES_DRIVER} aacid.o
+
+###############################################################################
+### GENERAL DEFINES
+###############################################################################
+
+#  Remember that we're doing a chdir one level lower, so we need an extra ../
+INCS= \
+	-I./include \
+	-I../../../include -I.. \
+	-I/usr/src/linux/include -I/usr/src/linux/drivers/scsi 
+
+WARNINGS= -w -Wall -Wno-unused -Wno-switch -Wno-missing-prototypes -Wno-implicit
+
+COMMON_FLAGS=\
+	-D__KERNEL__=1 -DUNIX -DCVLOCK_USE_SPINLOCK -DLINUX \
+	-Wall -Wstrict-prototypes \
+	${INCS} \
+	${WARNINGS} \
+	-O2 -fomit-frame-pointer
+
+AACFLAGS=${CFLAGS} ${COMMON_FLAGS} ${EXTRA_FLAGS}
+
+###############################################################################
+### DO GENERAL STUFF
+###############################################################################
+
+.SUFFIXES:
+.SUFFIXES: .c .o .h .a
+
+all: source ${TARGET_OFILES} aacraid.o
+
+source: ${ALL_SOURCE}
+
+clean:
+	rm *.o
+
+###############################################################################
+### DRIVER LINKS
+###############################################################################
+
+aacraid.o: source ${TARGET_OFILES}
+	ld -r -o $@ $(TARGET_OFILES)
+	cp -r aacraid.o ../
+
+###############################################################################
+### SIMPLE COMPILES
+###############################################################################
+
+linit.o: ./linit.c
+	$(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o linit.o ./linit.c
+
+aachba.o: ./aachba.c
+	$(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o aachba.o ./aachba.c
+
+osddi.o: ./osddi.c
+	$(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o osddi.o ./osddi.c
+
+osfuncs.o: ./osfuncs.c
+	$(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o osfuncs.o ./osfuncs.c
+
+commctrl.o:  ./commctrl.c
+	$(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o commctrl.o ./commctrl.c
+
+comminit.o:  ./comminit.c
+	$(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o comminit.o ./comminit.c
+
+commsup.o:  ./commsup.c
+	$(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o commsup.o ./commsup.c
+
+dpcsup.o:  ./dpcsup.c
+	$(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o dpcsup.o ./dpcsup.c
+
+aacid.o:  ./aacid.c
+	$(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o aacid.o ./aacid.c
+
+port.o:  ./port.c
+	$(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o port.o ./port.c
+
+ossup.o:  ./ossup.c
+	$(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o ossup.o ./ossup.c
+
+rx.o:  ./rx.c
+	$(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o rx.o ./rx.c
+
+sap1sup.o: ./sap1sup.c
+	$(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o sap1sup.o ./sap1sup.c
+
+
diff -BburN linux.orig/drivers/scsi/aacraid/README linux/drivers/scsi/aacraid/README
--- linux.orig/drivers/scsi/aacraid/README	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/README	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,28 @@
+				AACRAID Driver for Linux
+
+Introduction
+-------------------------
+The aacraid driver adds support for Adaptec (http://www.adaptec.com)
+OEM based RAID controllers.
+
+Supported Cards/Chipsets
+-------------------------
+	Dell Computer Corporation PERC 2 Quad Channel
+	Dell Computer Corporation PERC 3/Di
+	Dell Computer Corporation PERC 3/Si
+	HP NetRAID-4M
+
+Not Supported Devices
+-------------------------
+	Any and All Adaptec branded raid controllers.
+
+People
+-------------------------
+	Brian M. Boerner
+
+Mailing List
+-------------------------
+There is currently a mailing list being created for aacraid.
+
+$Revision: 1.1 $
+Modified by Brian Boerner 2000
diff -BburN linux.orig/drivers/scsi/aacraid/aachba.c linux/drivers/scsi/aacraid/aachba.c
--- linux.orig/drivers/scsi/aacraid/aachba.c	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/aachba.c	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,1854 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   aachba.c
+ *
+ * Abstract: driver...
+ *
+--*/
+/*------------------------------------------------------------------------------
+ *              I N C L U D E S
+ *----------------------------------------------------------------------------*/
+#include "osheaders.h"
+#include "AacGenericTypes.h"
+#include "aac_unix_defs.h"
+#include "comstruc.h"
+#include "monkerapi.h"
+#include "protocol.h"
+#include "fsafs.h"
+#include "fsact.h"
+#include "fsaioctl.h"
+
+#include "sap1common.h"
+#include "fsaport.h"
+#include "pcisup.h"
+#include "sap1.h"
+#include "nodetype.h"
+#include "comsup.h"
+#include "afacomm.h"
+#include "adapter.h"
+
+/*------------------------------------------------------------------------------
+ *              D E F I N E S
+ *----------------------------------------------------------------------------*/
+/*	SCSI Commands */
+#define	SS_TEST			0x00	/* Test unit ready */
+#define SS_REZERO		0x01	/* Rezero unit */
+#define	SS_REQSEN		0x03	/* Request Sense */
+#define SS_REASGN		0x07	/* Reassign blocks */
+#define	SS_READ			0x08	/* Read 6   */
+#define	SS_WRITE		0x0A	/* Write 6  */
+#define	SS_INQUIR		0x12	/* inquiry */
+#define	SS_ST_SP		0x1B	/* Start/Stop unit */
+#define	SS_LOCK			0x1E	/* prevent/allow medium removal */
+#define SS_RESERV		0x16	/* Reserve */
+#define SS_RELES		0x17	/* Release */
+#define SS_MODESEN		0x1A	/* Mode Sense 6 */
+#define	SS_RDCAP		0x25	/* Read Capacity */
+#define	SM_READ			0x28	/* Read 10  */
+#define	SM_WRITE		0x2A	/* Write 10 */
+#define SS_SEEK			0x2B	/* Seek */
+
+/* values for inqd_pdt: Peripheral device type in plain English */
+#define	INQD_PDT_DA	0x00	/* Direct-access (DISK) device */
+#define	INQD_PDT_PROC	0x03	/* Processor device */
+#define	INQD_PDT_CHNGR	0x08	/* Changer (jukebox, scsi2) */
+#define	INQD_PDT_COMM	0x09	/* Communication device (scsi2) */
+#define	INQD_PDT_NOLUN2 0x1f	/* Unknown Device (scsi2) */
+#define	INQD_PDT_NOLUN	0x7f	/* Logical Unit Not Present */
+
+#define	INQD_PDT_DMASK	0x1F	/* Peripheral Device Type Mask */
+#define	INQD_PDT_QMASK	0xE0	/* Peripheral Device Qualifer Mask */
+
+#define	TARGET_LUN_TO_CONTAINER(Target, Lun)    (((Lun) << 4) | Target)
+#define CONTAINER_TO_TARGET(Container)          ((Container) & 0xf)
+#define CONTAINER_TO_LUN(Container)             ((Container) >> 4)
+
+#define MAX_FIB_DATA (sizeof(FIB) - sizeof(FIB_HEADER))
+
+#define MAX_DRIVER_SG_SEGMENT_COUNT 17
+
+// ------------------------------------------------------
+// Sense keys
+//
+#define SENKEY_NO_SENSE      0x00 //
+#define SENKEY_UNDEFINED     0x01 //
+#define SENKEY_NOT_READY     0x02 //
+#define SENKEY_MEDIUM_ERR    0x03 //
+#define SENKEY_HW_ERR        0x04 //
+#define SENKEY_ILLEGAL       0x05 //
+#define SENKEY_ATTENTION     0x06 //
+#define SENKEY_PROTECTED     0x07 //
+#define SENKEY_BLANK         0x08 //
+#define SENKEY_V_UNIQUE      0x09 //
+#define SENKEY_CPY_ABORT     0x0A //
+#define SENKEY_ABORT         0x0B //
+#define SENKEY_EQUAL         0x0C //
+#define SENKEY_VOL_OVERFLOW  0x0D //
+#define SENKEY_MISCOMP       0x0E //
+#define SENKEY_RESERVED      0x0F //
+
+// ------------------------------------------------------
+// Sense codes
+//
+#define SENCODE_NO_SENSE                        0x00
+#define SENCODE_END_OF_DATA                     0x00
+#define SENCODE_BECOMING_READY                  0x04
+#define SENCODE_INIT_CMD_REQUIRED               0x04
+#define SENCODE_PARAM_LIST_LENGTH_ERROR         0x1A
+#define SENCODE_INVALID_COMMAND                 0x20
+#define SENCODE_LBA_OUT_OF_RANGE                0x21
+#define SENCODE_INVALID_CDB_FIELD               0x24
+#define SENCODE_LUN_NOT_SUPPORTED               0x25
+#define SENCODE_INVALID_PARAM_FIELD             0x26
+#define SENCODE_PARAM_NOT_SUPPORTED             0x26
+#define SENCODE_PARAM_VALUE_INVALID             0x26
+#define SENCODE_RESET_OCCURRED                  0x29
+#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET     0x3E
+#define SENCODE_INQUIRY_DATA_CHANGED            0x3F
+#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED     0x39
+#define SENCODE_DIAGNOSTIC_FAILURE              0x40
+#define SENCODE_INTERNAL_TARGET_FAILURE         0x44
+#define SENCODE_INVALID_MESSAGE_ERROR           0x49
+#define SENCODE_LUN_FAILED_SELF_CONFIG          0x4c
+#define SENCODE_OVERLAPPED_COMMAND              0x4E
+
+// ------------------------------------------------------
+// Additional sense codes
+//
+#define ASENCODE_NO_SENSE                       0x00
+#define ASENCODE_END_OF_DATA                    0x05
+#define ASENCODE_BECOMING_READY                 0x01
+#define ASENCODE_INIT_CMD_REQUIRED              0x02
+#define ASENCODE_PARAM_LIST_LENGTH_ERROR        0x00
+#define ASENCODE_INVALID_COMMAND                0x00
+#define ASENCODE_LBA_OUT_OF_RANGE               0x00
+#define ASENCODE_INVALID_CDB_FIELD              0x00
+#define ASENCODE_LUN_NOT_SUPPORTED              0x00
+#define ASENCODE_INVALID_PARAM_FIELD            0x00
+#define ASENCODE_PARAM_NOT_SUPPORTED            0x01
+#define ASENCODE_PARAM_VALUE_INVALID            0x02
+#define ASENCODE_RESET_OCCURRED                 0x00
+#define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET    0x00
+#define ASENCODE_INQUIRY_DATA_CHANGED           0x03
+#define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED    0x00
+#define ASENCODE_DIAGNOSTIC_FAILURE             0x80
+#define ASENCODE_INTERNAL_TARGET_FAILURE        0x00
+#define ASENCODE_INVALID_MESSAGE_ERROR          0x00
+#define ASENCODE_LUN_FAILED_SELF_CONFIG         0x00
+#define ASENCODE_OVERLAPPED_COMMAND             0x00
+
+#define BYTE0( x ) ( unsigned char )( x )
+#define BYTE1( x ) ( unsigned char )( x >> 8  )
+#define BYTE2( x ) ( unsigned char )( x >> 16 )
+#define BYTE3( x ) ( unsigned char )( x >> 24 )
+
+/*------------------------------------------------------------------------------
+ *              S T R U C T S / T Y P E D E F S
+ *----------------------------------------------------------------------------*/
+/* SCSI inquiry data */
+struct inquiry_data {
+	unchar inqd_pdt;     /* Peripheral qualifier | Peripheral Device Type  */
+	unchar inqd_dtq;     /* RMB | Device Type Qualifier  */
+	unchar inqd_ver;     /* ISO version | ECMA version | ANSI-approved version */
+	unchar inqd_rdf;     /* AENC | TrmIOP | Response data format */
+	unchar inqd_len;     /* Additional length (n-4) */
+	unchar inqd_pad1[2]; /* Reserved - must be zero */
+	unchar inqd_pad2;    /* RelAdr | WBus32 | WBus16 |  Sync  | Linked |Reserved| CmdQue | SftRe */
+	unchar inqd_vid[8];  /* Vendor ID */
+	unchar inqd_pid[16]; /* Product ID */
+	unchar inqd_prl[4];  /* Product Revision Level */
+};
+
+struct sense_data {
+	unchar error_code;		// 70h (current errors), 71h(deferred errors)
+	unchar valid:1;			// A valid bit of one indicates that the information 
+					// field contains valid information as defined in the
+					// SCSI-2 Standard.
+	
+	unchar segment_number;	// Only used for COPY, COMPARE, or COPY AND VERIFY 
+				// commands
+	
+	unchar sense_key:4;		// Sense Key
+	unchar reserved:1;
+	unchar ILI:1;			// Incorrect Length Indicator
+	unchar EOM:1;			// End Of Medium - reserved for random access devices
+	unchar filemark:1;		// Filemark - reserved for random access devices
+	
+	unchar information[4];	// for direct-access devices, contains the unsigned 
+				// logical block address or residue associated with 
+				// the sense key 
+	unchar add_sense_len;	// number of additional sense bytes to follow this field
+	unchar cmnd_info[4];	// not used
+	unchar ASC;		// Additional Sense Code
+	unchar ASCQ;		// Additional Sense Code Qualifier
+	unchar FRUC;		// Field Replaceable Unit Code - not used
+	
+	unchar bit_ptr:3;	// indicates which byte of the CDB or parameter data
+				// was in error
+	unchar BPV:1;		// bit pointer valid (BPV): 1- indicates that 
+				// the bit_ptr field has valid value
+	unchar reserved2:2;
+	unchar CD:1;		// command data bit: 1- illegal parameter in CDB.
+				//                   0- illegal parameter in data.
+	unchar SKSV:1;
+	
+	unchar field_ptr[2];	// byte of the CDB or parameter data in error
+};
+
+/*------------------------------------------------------------------------------
+ *              G L O B A L S
+ *----------------------------------------------------------------------------*/
+/*------------------------------------------------------------------------------
+ *              M O D U L E   G L O B A L S
+ *----------------------------------------------------------------------------*/
+static fsadev_t *g_fsa_dev_array[8];	// SCSI Device Instance Pointers
+static struct sense_data g_sense_data[MAXIMUM_NUM_CONTAINERS];
+
+/*------------------------------------------------------------------------------
+ *              F U N C T I O N   P R O T O T Y P E S
+ *----------------------------------------------------------------------------*/
+AAC_STATUS AacHba_OpenAdapter( PVOID AdapterArg);
+AAC_STATUS AacHba_CloseAdapter( PVOID AdapterArg);
+BOOLEAN AacHba_HandleAif( PVOID AdapterArg, PFIB_CONTEXT FibContext);
+BOOLEAN AacHba_AdapterDeviceControl ( PVOID AdapterArg, 
+	PAFA_IOCTL_CMD IoctlCmdPtr, int * ReturnStatus);
+
+void AacHba_CompleteScsi( 
+	Scsi_Cmnd *scsi_cmnd_ptr );
+
+void AacHba_CompleteScsiNoLock( 
+	Scsi_Cmnd *scsi_cmnd_ptr );
+
+static void AacHba_ReadCallback( 
+	void *Context, 
+	PFIB_CONTEXT FibContext, 
+	int FibStatus );
+
+static void AacHba_WriteCallback( 
+	void *Context, 
+	PFIB_CONTEXT FibContext, 
+	int FibStatus );
+
+int AacHba_DoScsiRead(
+	Scsi_Cmnd *scsi_cmnd_ptr,
+	int ContainerId,
+	int wait );
+
+int AacHba_DoScsiWrite(
+	Scsi_Cmnd *scsi_cmnd_ptr,
+	int ContainerId,
+	int wait );
+
+int AacHba_QueryDisk(
+	PVOID AdapterArg,		// CommonExtensionPtr
+	IN PAFA_IOCTL_CMD IoctlCmdPtr );
+
+int AacHba_ForceDeleteDisk(
+	PVOID AdapterArg,		// CommonExtensionPtr
+	IN PAFA_IOCTL_CMD IoctlCmdPtr );
+
+int AacHba_DeleteDisk(
+	PVOID AdapterArg,
+	IN PAFA_IOCTL_CMD IoctlCmdPtr );
+
+void AacHba_DetachAdapter(
+	IN PVOID AdapterArg );
+
+BOOLEAN AacCommDetachAdapter(
+	IN PAFA_COMM_ADAPTER Adapter );
+
+void AacHba_SetSenseData(
+	char * sense_buf,
+	unchar sense_key,
+	unchar sense_code,
+	unchar a_sense_code,
+	unchar incorrect_length,
+	unchar bit_pointer,
+	unsigned field_pointer,
+	unsigned long residue );
+
+static void get_sd_devname(
+	long disknum, 
+	char * buffer);
+
+// Keep these here for the time being - #REVIEW#
+int
+AfaCommAdapterDeviceControl (
+	IN PVOID AdapterArg,
+	IN PAFA_IOCTL_CMD	IoctlCmdPtr
+	);
+
+AAC_STATUS
+AfaCommRegisterNewClassDriver(
+	IN PAFA_COMM_ADAPTER	Adapter,
+	IN PAFA_NEW_CLASS_DRIVER	NewClassDriver,
+	OUT PAFA_NEW_CLASS_DRIVER_RESPONSE NewClassDriverResponse
+	);
+
+void
+SetInqDataStr (int, void *, int);
+/*------------------------------------------------------------------------------
+ *              F U N C T I O N S
+ *----------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------------
+	AacHba_ClassDriverInit()
+
+		Setup 'core' class driver to answer ioctl's
+ *----------------------------------------------------------------------------*/
+int AacHba_ClassDriverInit(
+	PCI_MINIPORT_COMMON_EXTENSION * CommonExtensionPtr)
+/*----------------------------------------------------------------------------*/
+{
+    AFA_NEW_CLASS_DRIVER				NewClassDriver;
+	AFA_NEW_CLASS_DRIVER_RESPONSE		NewClassDriverResponse;
+	PAFA_COMM_ADAPTER					Adapter;
+
+	Adapter = (AFA_COMM_ADAPTER *)CommonExtensionPtr->Adapter;
+
+	RtlZeroMemory( &NewClassDriver, sizeof( AFA_NEW_CLASS_DRIVER ) );
+	
+	// ClassDriverExtension is the first argument passed to class driver functions below
+	NewClassDriver.ClassDriverExtension = CommonExtensionPtr;
+	
+	NewClassDriver.OpenAdapter = AacHba_OpenAdapter;
+	NewClassDriver.CloseAdapter = AacHba_CloseAdapter;
+	NewClassDriver.DeviceControl = AacHba_AdapterDeviceControl;
+	NewClassDriver.HandleAif = AacHba_HandleAif;
+	AfaCommRegisterNewClassDriver( Adapter, &NewClassDriver, &NewClassDriverResponse );
+
+	return(0);
+}
+
+
+/*------------------------------------------------------------------------------
+	AacHba_ProbeContainers()
+
+		Make a list of all containers in the system.
+ *----------------------------------------------------------------------------*/
+int AacHba_ProbeContainers( 
+	PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr )
+/*----------------------------------------------------------------------------*/
+{
+	fsadev_t						*fsa_dev_ptr;
+    int								Index, Status;
+    PMNTINFO						DiskInfo;
+    PMNTINFORESPONSE				DiskInfoResponse;
+	PFIB_CONTEXT 					FibContext;
+	AFA_COMM_ADAPTER				*Adapter;
+	unsigned						instance;
+	
+	Adapter = ( AFA_COMM_ADAPTER * )CommonExtensionPtr->Adapter;
+	fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev );
+	instance = CommonExtensionPtr->OsDep.scsi_host_ptr->unique_id;
+
+	if( !( FibContext = Adapter->CommFuncs.AllocateFib( Adapter ) ) )
+	{
+		cmn_err( CE_WARN, "AacHba_ProbeContainers: AllocateFib failed" );
+		return( STATUS_UNSUCCESSFUL );
+	}
+
+    for ( Index = 0; Index < MAXIMUM_NUM_CONTAINERS; Index++ ) 
+	{
+		Adapter->CommFuncs.InitializeFib( FibContext );
+
+		DiskInfo = ( PMNTINFO )Adapter->CommFuncs.GetFibData( FibContext );
+
+		DiskInfo->Command  = VM_NameServe;
+		DiskInfo->MntCount = Index;
+		DiskInfo->MntType  = FT_FILESYS;
+		
+		Status =  Adapter->CommFuncs.SendFib(	ContainerCommand,
+												FibContext,
+												sizeof(MNTINFO),
+												FsaNormal,
+												TRUE,
+												NULL,
+												TRUE,
+												NULL,
+												NULL );
+		if ( Status ) 
+		{
+			cmn_err( CE_WARN, "ProbeContainers: SendFIb Failed" );
+			break;
+		}
+
+		DiskInfoResponse = ( PMNTINFORESPONSE )Adapter->CommFuncs.GetFibData( FibContext );
+		
+
+		if ( ( DiskInfoResponse->Status == ST_OK ) &&
+			( DiskInfoResponse->MntTable[0].VolType != CT_NONE ) ) 
+		{
+
+
+			fsa_dev_ptr->ContainerValid[Index] = TRUE;
+			fsa_dev_ptr->ContainerType[Index]  = DiskInfoResponse->MntTable[0].VolType;
+			fsa_dev_ptr->ContainerSize[Index]  = DiskInfoResponse->MntTable[0].Capacity;
+
+			if (DiskInfoResponse->MntTable[0].ContentState & FSCS_READONLY)
+				fsa_dev_ptr->ContainerReadOnly[Index] = TRUE;
+		}
+		
+		Adapter->CommFuncs.CompleteFib( FibContext );
+
+		// If there are no more containers, then stop asking.
+		if ((Index + 1) >= DiskInfoResponse->MntRespCount)
+			break;
+    } // end for()
+
+	Adapter->CommFuncs.FreeFib( FibContext );
+
+	g_fsa_dev_array[instance] = fsa_dev_ptr;
+
+	return( Status );
+}
+
+
+/*------------------------------------------------------------------------------
+	AacHba_ProbeContainer()
+
+		Probe a single container.
+ *----------------------------------------------------------------------------*/
+int AacHba_ProbeContainer( 
+	PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr,
+	int ContainerId )
+/*----------------------------------------------------------------------------*/
+{
+	fsadev_t						*fsa_dev_ptr;
+    int								Status;
+    PMNTINFO						DiskInfo;
+    PMNTINFORESPONSE				DiskInfoResponse;
+	PFIB_CONTEXT 					FibContext;
+	AFA_COMM_ADAPTER				*Adapter;
+	unsigned						instance;
+	
+	Adapter = ( AFA_COMM_ADAPTER * )CommonExtensionPtr->Adapter;
+	fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev );
+	instance = CommonExtensionPtr->OsDep.scsi_host_ptr->unique_id;
+
+	if( !( FibContext = Adapter->CommFuncs.AllocateFib( Adapter ) ) )
+	{
+		cmn_err( CE_WARN, "AacHba_ProbeContainers: AllocateFib failed" );
+		return( STATUS_UNSUCCESSFUL );
+	}
+
+	Adapter->CommFuncs.InitializeFib( FibContext );
+
+	DiskInfo = ( PMNTINFO )Adapter->CommFuncs.GetFibData( FibContext );
+
+	DiskInfo->Command  = VM_NameServe;
+	DiskInfo->MntCount = ContainerId;
+	DiskInfo->MntType  = FT_FILESYS;
+		
+	Status =  Adapter->CommFuncs.SendFib(	ContainerCommand,
+											FibContext,
+											sizeof(MNTINFO),
+											FsaNormal,
+											TRUE,
+											NULL,
+											TRUE,
+											NULL,
+											NULL );
+	if ( Status ) 
+	{
+		cmn_err( CE_WARN, "ProbeContainers: SendFIb Failed" );
+		Adapter->CommFuncs.CompleteFib( FibContext );
+		Adapter->CommFuncs.FreeFib( FibContext );
+		return( Status );
+	}
+
+	DiskInfoResponse = ( PMNTINFORESPONSE )Adapter->CommFuncs.GetFibData( FibContext );
+		
+
+	if ( ( DiskInfoResponse->Status == ST_OK ) &&
+		( DiskInfoResponse->MntTable[0].VolType != CT_NONE ) ) 
+	{
+
+		fsa_dev_ptr->ContainerValid[ContainerId] = TRUE;
+		fsa_dev_ptr->ContainerType[ContainerId]  = DiskInfoResponse->MntTable[0].VolType;
+		fsa_dev_ptr->ContainerSize[ContainerId]  = DiskInfoResponse->MntTable[0].Capacity;
+		if (DiskInfoResponse->MntTable[0].ContentState & FSCS_READONLY)
+			fsa_dev_ptr->ContainerReadOnly[ContainerId] = TRUE;
+	}
+		
+	Adapter->CommFuncs.CompleteFib( FibContext );
+	Adapter->CommFuncs.FreeFib( FibContext );
+
+	return( Status );
+}
+
+
+/*------------------------------------------------------------------------------
+	AacHba_CompleteScsi()
+
+		Call SCSI completion routine after acquiring io_request_lock
+
+  	Preconditions:
+	Postconditions:
+ *----------------------------------------------------------------------------*/
+void AacHba_CompleteScsi( 
+	Scsi_Cmnd *scsi_cmnd_ptr )
+{
+	unsigned long cpu_flags;
+
+	spin_lock_irqsave( &io_request_lock, cpu_flags );
+	scsi_cmnd_ptr->scsi_done( scsi_cmnd_ptr );
+	spin_unlock_irqrestore( &io_request_lock, cpu_flags );
+}
+
+
+/*------------------------------------------------------------------------------
+	AacHba_CompleteScsiNoLock()
+
+		Call SCSI completion routine
+
+  	Preconditions:
+	Postconditions:
+ *----------------------------------------------------------------------------*/
+void AacHba_CompleteScsiNoLock( 
+	Scsi_Cmnd *scsi_cmnd_ptr )
+{
+	scsi_cmnd_ptr->scsi_done( scsi_cmnd_ptr );
+}
+
+/*------------------------------------------------------------------------------
+	AacHba_DoScsiCmd()
+
+		Process SCSI command
+
+  	Preconditions:
+	Postconditions:
+		Returns 0 on success, -1 on failure
+ *----------------------------------------------------------------------------*/
+int AacHba_DoScsiCmd(
+	Scsi_Cmnd *scsi_cmnd_ptr,
+	int wait )
+/*----------------------------------------------------------------------------*/
+{
+	int			ContainerId = 0;
+	fsadev_t	*fsa_dev_ptr;
+	PCI_MINIPORT_COMMON_EXTENSION	*CommonExtensionPtr;
+	int MiniPortIndex;
+
+	CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata );
+	MiniPortIndex = CommonExtensionPtr->OsDep.MiniPortIndex;
+
+	fsa_dev_ptr = g_fsa_dev_array[ scsi_cmnd_ptr->host->unique_id ];
+
+	// If the bus, target or lun is out of range, return fail
+	// Test does not apply to ID 16, the pseudo id for the controller itself.
+	if ( scsi_cmnd_ptr->target != scsi_cmnd_ptr->host->this_id ) 
+	{
+		if( ( scsi_cmnd_ptr->channel > 0 ) ||
+			( scsi_cmnd_ptr->target > 15 ) || 
+			( scsi_cmnd_ptr->lun > 7 ) )
+		{
+			cmn_err( CE_DEBUG, "The bus, target or lun is out of range = %d, %d, %d",
+				scsi_cmnd_ptr->channel,
+				scsi_cmnd_ptr->target, 
+				scsi_cmnd_ptr->lun );
+			scsi_cmnd_ptr->result = DID_BAD_TARGET << 16;
+
+			AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+
+			return ( -1 );
+		}
+
+		ContainerId = TARGET_LUN_TO_CONTAINER( scsi_cmnd_ptr->target, scsi_cmnd_ptr->lun );
+
+
+		// If the target container doesn't exist, it may have been newly created
+		if( fsa_dev_ptr->ContainerValid[ContainerId] == 0 )
+		{	
+			switch( scsi_cmnd_ptr->cmnd[0] )
+			{
+				case SS_INQUIR:
+				case SS_RDCAP:
+				case SS_TEST:
+					spin_unlock_irq( &io_request_lock );
+					AacHba_ProbeContainer( CommonExtensionPtr, ContainerId );		
+					spin_lock_irq( &io_request_lock );
+				default:
+					break;
+			}
+		}
+
+		// If the target container still doesn't exist, return failure
+		if( fsa_dev_ptr->ContainerValid[ContainerId] == 0 )
+		{	
+			cmn_err( CE_DEBUG, "Target container %d doesn't exist", ContainerId );
+			scsi_cmnd_ptr->result = DID_BAD_TARGET << 16;
+			AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+
+			return ( -1 );
+		}
+	}
+	else	// the command is for the controller itself
+		if( ( scsi_cmnd_ptr->cmnd[0] != SS_INQUIR )	&& // only INQUIRY & TUR cmnd supported for controller 
+			( scsi_cmnd_ptr->cmnd[0] != SS_TEST ) )
+		{
+			cmn_err( CE_WARN, "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x", 
+				scsi_cmnd_ptr->cmnd[0] );
+
+			scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
+			
+			AacHba_SetSenseData( (char *)&g_sense_data[ ContainerId ],
+				SENKEY_ILLEGAL, SENCODE_INVALID_COMMAND, ASENCODE_INVALID_COMMAND, 
+				0, 0, 0, 0 );
+
+			AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+
+			return ( -1 );
+		}
+
+	// Handle commands here that don't really require going out to the adapter
+	switch ( scsi_cmnd_ptr->cmnd[0] ) 
+	{
+		case SS_INQUIR:
+		{
+			struct inquiry_data *inq_data_ptr;
+		
+			cmn_err( CE_DEBUG, "INQUIRY command, ID: %d", scsi_cmnd_ptr->target );
+			inq_data_ptr = ( struct inquiry_data * )scsi_cmnd_ptr->request_buffer;
+			bzero( inq_data_ptr, sizeof( struct inquiry_data ) );
+
+			inq_data_ptr->inqd_ver = 2;		// claim compliance to SCSI-2
+
+			inq_data_ptr->inqd_dtq = 0x80;	// set RMB bit to one indicating 
+											// that the medium is removable
+			inq_data_ptr->inqd_rdf = 2;		// A response data format value of
+											// two indicates that the data shall 
+											// be in the format specified in SCSI-2
+			inq_data_ptr->inqd_len = 31;
+
+			// Set the Vendor, Product, and Revision Level see: <vendor>.c i.e. aac.c
+			SetInqDataStr(	MiniPortIndex, 
+							(void *)(inq_data_ptr->inqd_vid),
+							fsa_dev_ptr->ContainerType[ContainerId]);
+
+			if ( scsi_cmnd_ptr->target == scsi_cmnd_ptr->host->this_id )
+				inq_data_ptr->inqd_pdt = INQD_PDT_PROC;	// Processor device
+			else
+				inq_data_ptr->inqd_pdt = INQD_PDT_DA;	// Direct/random access device
+
+			scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+			AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+
+			return ( 0 );
+		}
+
+		case SS_RDCAP:
+		{
+			int capacity;
+			char *cp;
+
+			cmn_err( CE_DEBUG, "READ CAPACITY command" );
+			capacity = fsa_dev_ptr->ContainerSize[ContainerId];
+			cp = scsi_cmnd_ptr->request_buffer;
+			cp[0] = ( capacity >> 24 ) & 0xff;
+			cp[1] = ( capacity >> 16 ) & 0xff;
+			cp[2] = ( capacity >>  8 ) & 0xff;
+			cp[3] = ( capacity >>  0 ) & 0xff;
+			cp[4] = 0;
+			cp[5] = 0;
+			cp[6] = 2;
+			cp[7] = 0;
+	
+			scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+			AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+
+			return ( 0 );
+		}
+
+		case SS_MODESEN:
+		{
+			char *mode_buf;
+
+			cmn_err( CE_DEBUG, "MODE SENSE command" );
+			mode_buf = scsi_cmnd_ptr->request_buffer;
+			mode_buf[0] = 0;	// Mode data length (MSB)
+			mode_buf[1] = 6;	// Mode data length (LSB)
+			mode_buf[2] = 0;	// Medium type - default
+			mode_buf[3] = 0;	// Device-specific param, bit 8: 0/1 = write enabled/protected
+			mode_buf[4] = 0;	// reserved
+			mode_buf[5] = 0;	// reserved
+			mode_buf[6] = 0;	// Block descriptor length (MSB)
+			mode_buf[7] = 0;	// Block descriptor length (LSB)
+	
+			scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+			AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+
+			return ( 0 );
+		}
+
+
+		// These commands are all No-Ops
+		case SS_TEST:
+			cmn_err( CE_DEBUG, "TEST UNIT READY command" );
+			scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+			AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+			return ( 0 );
+
+		case SS_REQSEN:
+			cmn_err( CE_DEBUG, "REQUEST SENSE command" );
+
+			memcpy( scsi_cmnd_ptr->sense_buffer, &g_sense_data[ContainerId],
+				sizeof( struct sense_data ) );
+			bzero( &g_sense_data[ContainerId], sizeof( struct sense_data ) );
+
+			scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+			AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+			return ( 0 );
+
+		case SS_LOCK:
+			cmn_err(CE_DEBUG, "LOCK command");
+
+			if( scsi_cmnd_ptr->cmnd[4] )
+				fsa_dev_ptr->ContainerLocked[ContainerId] = 1;
+			else
+				fsa_dev_ptr->ContainerLocked[ContainerId] = 0;
+
+			scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+			AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+			return ( 0 );
+
+		case SS_RESERV:
+			cmn_err( CE_DEBUG, "RESERVE command" );
+			scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+			AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+			return ( 0 );
+
+		case SS_RELES:
+			cmn_err( CE_DEBUG, "RELEASE command" );
+			scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+			AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+			return ( 0 );
+
+		case SS_REZERO:
+			cmn_err( CE_DEBUG, "REZERO command" );
+			scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+			AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+			return ( 0 );
+
+		case SS_REASGN:
+			cmn_err( CE_DEBUG, "REASSIGN command" );
+			scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+			AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+			return ( 0 );
+
+		case SS_SEEK:
+			cmn_err( CE_DEBUG, "SEEK command" );
+			scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+			AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+			return ( 0 );
+
+		case SS_ST_SP:
+			cmn_err( CE_DEBUG, "START/STOP command" );
+			scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+			AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+			return ( 0 );
+	}
+
+	switch ( scsi_cmnd_ptr->cmnd[0] ) 
+	{
+		case SS_READ:
+		case SM_READ:
+			// Hack to keep track of ordinal number of the device that corresponds
+			// to a container. Needed to convert containers to /dev/sd device names
+			fsa_dev_ptr->ContainerDevNo[ContainerId] = 
+				DEVICE_NR( scsi_cmnd_ptr->request.rq_dev );
+			
+			return( AacHba_DoScsiRead( scsi_cmnd_ptr, ContainerId,  wait ) );
+			break;
+
+		case SS_WRITE:
+		case SM_WRITE:
+			return( AacHba_DoScsiWrite( scsi_cmnd_ptr, ContainerId,  wait ) );
+			break;
+	}
+	//
+	// Unhandled commands
+	//
+	cmn_err( CE_WARN, "Unhandled SCSI Command: 0x%x", scsi_cmnd_ptr->cmnd[0] );
+	scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
+
+	AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ],
+		SENKEY_ILLEGAL, SENCODE_INVALID_COMMAND, ASENCODE_INVALID_COMMAND, 
+		0, 0, 0, 0 );
+
+	AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+	return ( -1 );
+}
+
+
+/*------------------------------------------------------------------------------
+	AacHba_DoScsiRead()
+		
+		Handles SCSI READ requests
+
+  	Preconditions:
+	Postconditions:
+		Returns 0 on success, -1 on failure
+ *----------------------------------------------------------------------------*/
+int AacHba_DoScsiRead(
+	Scsi_Cmnd *scsi_cmnd_ptr,
+	int ContainerId,
+	int wait )
+/*----------------------------------------------------------------------------*/
+{
+	u_long				lba;
+	u_long				count;
+	u_long				byte_count;
+	int					Status;
+
+	PBLOCKREAD			BlockReadDisk;
+	PBLOCKREADRESPONSE	BlockReadResponse;
+	uint16_t			FibSize;
+	PCI_MINIPORT_COMMON_EXTENSION	*CommonExtension;
+	AFA_COMM_ADAPTER				*Adapter;
+	PFIB_CONTEXT					cmd_fibcontext;
+
+	CommonExtension = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata );
+	Adapter         = ( AFA_COMM_ADAPTER * )CommonExtension->Adapter;
+
+	// Get block address and transfer length
+	if ( scsi_cmnd_ptr->cmnd[0] == SS_READ ) // 6 byte command
+	{
+		cmn_err( CE_DEBUG, "aachba: received a read(6) command on target %d", ContainerId );
+
+		lba = ( ( scsi_cmnd_ptr->cmnd[1] & 0x1F ) << 16 ) | 
+			( scsi_cmnd_ptr->cmnd[2] << 8 ) |
+			scsi_cmnd_ptr->cmnd[3];
+		count = scsi_cmnd_ptr->cmnd[4];
+
+		if ( count == 0 )
+			count = 256;
+	} 
+	else 
+	{		
+		cmn_err( CE_DEBUG, "aachba: received a read(10) command on target %d", ContainerId );
+		
+		lba = ( scsi_cmnd_ptr->cmnd[2] << 24 ) | ( scsi_cmnd_ptr->cmnd[3] << 16 ) | 
+			( scsi_cmnd_ptr->cmnd[4] << 8 ) | scsi_cmnd_ptr->cmnd[5];
+
+		count = ( scsi_cmnd_ptr->cmnd[7] << 8 ) | scsi_cmnd_ptr->cmnd[8];
+	}	
+	cmn_err( CE_DEBUG, "AacHba_DoScsiRead[cpu %d]: lba = %lu, t = %ld", smp_processor_id(), lba, jiffies );
+
+	//-------------------------------------------------------------------------
+	// Alocate and initialize a Fib
+	//  Setup BlockRead command
+	if( !( cmd_fibcontext = Adapter->CommFuncs.AllocateFib( Adapter ) ) )
+	{
+		cmn_err( CE_WARN, "AacHba_DoScsiRead: AllocateFib failed\n" );
+		scsi_cmnd_ptr->result = DID_ERROR << 16;
+		AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+		return ( -1 );
+	}
+
+    Adapter->CommFuncs.InitializeFib( cmd_fibcontext );
+
+	BlockReadDisk = ( PBLOCKREAD )Adapter->CommFuncs.GetFibData( cmd_fibcontext );
+	BlockReadDisk->Command     = VM_CtBlockRead;
+	BlockReadDisk->ContainerId = ContainerId;
+	BlockReadDisk->BlockNumber = lba;
+	BlockReadDisk->ByteCount   = count * 512;
+	BlockReadDisk->SgMap.SgCount = 1;
+
+	if( BlockReadDisk->ByteCount > ( 64 * 1024 ) )
+	{
+		cmn_err( CE_WARN, "AacHba_DoScsiRead: READ request is larger than 64K" );
+		scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
+
+		AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ],
+				SENKEY_ILLEGAL, SENCODE_INVALID_CDB_FIELD, ASENCODE_INVALID_CDB_FIELD, 
+				0, 0, 7, 0 );
+
+		goto err_return;
+	}
+
+	//-------------------------------------------------------------------------
+	// Build Scatter/Gather list
+	//
+	if ( scsi_cmnd_ptr->use_sg )	// use scatter/gather list
+	{
+		struct scatterlist *scatterlist_ptr;
+		int segment;
+		
+		scatterlist_ptr = ( struct scatterlist * )scsi_cmnd_ptr->request_buffer;
+
+		byte_count = 0;
+		for( segment = 0; segment< scsi_cmnd_ptr->use_sg; segment++ ) 
+		{
+			BlockReadDisk->SgMap.SgEntry[segment].SgAddress = 
+				( void * )OsVirtToPhys( scatterlist_ptr[segment].address );
+			BlockReadDisk->SgMap.SgEntry[segment].SgByteCount = 
+				scatterlist_ptr[segment].length;
+
+#ifdef DEBUG_SGBUFFER
+			memset( scatterlist_ptr[segment].address, 0xa5, 
+				scatterlist_ptr[segment].length );
+#endif
+
+			byte_count += scatterlist_ptr[segment].length;
+			
+			if( BlockReadDisk->SgMap.SgEntry[segment].SgByteCount > ( 64 * 1024 ) )
+			{
+				cmn_err( CE_WARN, "AacHba_DoScsiRead: Segment byte count is larger than 64K" );
+				scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
+
+				AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ],
+					SENKEY_ILLEGAL, SENCODE_INVALID_CDB_FIELD, ASENCODE_INVALID_CDB_FIELD, 
+					0, 0, 7, 0 );
+
+				goto err_return;
+			}
+			/*
+			cmn_err(CE_DEBUG, "SgEntry[%d].SgAddress = 0x%x, Byte count = 0x%x", 
+					segment,
+					BlockReadDisk->SgMap.SgEntry[segment].SgAddress,
+					BlockReadDisk->SgMap.SgEntry[segment].SgByteCount);
+			*/
+		}
+		BlockReadDisk->SgMap.SgCount = scsi_cmnd_ptr->use_sg;
+
+		if( BlockReadDisk->SgMap.SgCount > MAX_DRIVER_SG_SEGMENT_COUNT ) 
+		{
+			cmn_err( CE_WARN, "AacHba_DoScsiRead: READ request with SgCount > %d", 
+				MAX_DRIVER_SG_SEGMENT_COUNT );
+			scsi_cmnd_ptr->result = DID_ERROR << 16;
+			goto err_return;
+		}
+	} 	
+	else		// one piece of contiguous phys mem
+	{
+		BlockReadDisk->SgMap.SgEntry[0].SgAddress = 
+			( void * )OsVirtToPhys( scsi_cmnd_ptr->request_buffer );
+		BlockReadDisk->SgMap.SgEntry[0].SgByteCount = scsi_cmnd_ptr->request_bufflen;
+
+		byte_count = scsi_cmnd_ptr->request_bufflen;
+
+		if( BlockReadDisk->SgMap.SgEntry[0].SgByteCount > ( 64 * 1024 ) )
+		{
+			cmn_err( CE_WARN, "AacHba_DoScsiRead: Single segment byte count is larger than 64K" );
+			scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
+
+			AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ],
+				SENKEY_ILLEGAL, SENCODE_INVALID_CDB_FIELD, ASENCODE_INVALID_CDB_FIELD, 
+				0, 0, 7, 0 );
+
+			goto err_return;
+		}
+	}
+
+	if( byte_count != BlockReadDisk->ByteCount )
+		cmn_err( CE_WARN, "AacHba_DoScsiRead: byte_count != BlockReadDisk->ByteCount" );
+
+	//-------------------------------------------------------------------------
+	// Now send the Fib to the adapter
+	//
+	FibSize = sizeof( BLOCKREAD ) + ( ( BlockReadDisk->SgMap.SgCount - 1 ) * sizeof( SGENTRY ) );
+
+	if( wait ) 
+	{
+		Status = Adapter->CommFuncs.SendFib( ContainerCommand,
+											 cmd_fibcontext,
+											 FibSize,
+											 FsaNormal,
+											 TRUE,
+											 NULL,
+											 TRUE,
+											 NULL,
+											 NULL);
+
+		BlockReadResponse = ( PBLOCKREADRESPONSE )
+			Adapter->CommFuncs.GetFibData( cmd_fibcontext );	
+
+		Adapter->CommFuncs.CompleteFib( cmd_fibcontext );
+		Adapter->CommFuncs.FreeFib( cmd_fibcontext );
+		
+		if( BlockReadResponse->Status != ST_OK )
+		{
+			cmn_err( CE_WARN, "AacHba_DoScsiRead: BlockReadCommand failed with status: %d", 
+				BlockReadResponse->Status );
+			scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
+
+			AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ],
+				SENKEY_HW_ERR, SENCODE_INTERNAL_TARGET_FAILURE, ASENCODE_INTERNAL_TARGET_FAILURE, 
+				0, 0, 0, 0 );
+
+			AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+			return ( -1 );
+		}
+		else
+			scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+
+		AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+		return ( 0 );
+	} 
+	else 
+	{
+		Status = Adapter->CommFuncs.SendFib( ContainerCommand,
+											 cmd_fibcontext,
+											 FibSize,
+											 FsaNormal,
+											 FALSE,
+											 NULL,
+											 TRUE,
+											 ( PFIB_CALLBACK )AacHba_ReadCallback,
+											 ( void *)scsi_cmnd_ptr );
+		// don't call done func here
+		return ( 0 );
+	}
+
+err_return:
+	AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+
+	Adapter->CommFuncs.CompleteFib( cmd_fibcontext );
+	Adapter->CommFuncs.FreeFib( cmd_fibcontext );
+
+	return ( -1 );
+}
+
+
+/*------------------------------------------------------------------------------
+	AacHba_DoScsiWrite()
+
+		Handles SCSI WRITE requests
+  	
+	Preconditions:
+	Postconditions:
+		Returns 0 on success, -1 on failure
+ *----------------------------------------------------------------------------*/
+int AacHba_DoScsiWrite(
+	Scsi_Cmnd *scsi_cmnd_ptr,
+	int ContainerId,
+	int wait )
+/*----------------------------------------------------------------------------*/
+{
+	u_long				lba;
+	u_long				count;
+	u_long				byte_count;
+	int					Status;
+
+	PBLOCKWRITE						BlockWriteDisk;
+	PBLOCKWRITERESPONSE				BlockWriteResponse;
+	uint16_t						FibSize;
+	PCI_MINIPORT_COMMON_EXTENSION	*CommonExtension;
+	AFA_COMM_ADAPTER				*Adapter;
+	PFIB_CONTEXT					cmd_fibcontext;
+
+	CommonExtension = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata );
+	Adapter         = ( AFA_COMM_ADAPTER * )CommonExtension->Adapter;
+
+	// Get block address and transfer length
+	if ( scsi_cmnd_ptr->cmnd[0] == SS_WRITE ) // 6 byte command
+	{
+		lba = ( ( scsi_cmnd_ptr->cmnd[1] & 0x1F ) << 16 ) | 
+			( scsi_cmnd_ptr->cmnd[2] << 8 ) |
+			scsi_cmnd_ptr->cmnd[3];
+		count = scsi_cmnd_ptr->cmnd[4];
+
+
+		if ( count == 0 )
+			count = 256;
+	} 
+	else 
+	{		
+		cmn_err( CE_DEBUG, "aachba: received a write(10) command on target %d", ContainerId );
+		
+		lba = ( scsi_cmnd_ptr->cmnd[2] << 24 ) | ( scsi_cmnd_ptr->cmnd[3] << 16 ) | 
+			( scsi_cmnd_ptr->cmnd[4] << 8 ) | scsi_cmnd_ptr->cmnd[5];
+
+		count = ( scsi_cmnd_ptr->cmnd[7] << 8 ) | scsi_cmnd_ptr->cmnd[8];
+	}	
+	cmn_err( CE_DEBUG, "AacHba_DoScsiWrite[cpu %d]: lba = %lu, t = %ld", smp_processor_id(), lba, jiffies );
+
+	//-------------------------------------------------------------------------
+	// Alocate and initialize a Fib
+	//  Setup BlockWrite command
+	if( !( cmd_fibcontext = Adapter->CommFuncs.AllocateFib( Adapter ) ) ) 
+	{
+		cmn_err( CE_WARN, "AacHba_DoScsiWrite: AllocateFib failed\n" );
+		scsi_cmnd_ptr->result = DID_ERROR << 16;
+		AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+		return ( -1 );
+	}
+
+    Adapter->CommFuncs.InitializeFib( cmd_fibcontext );
+
+	BlockWriteDisk = (PBLOCKWRITE) Adapter->CommFuncs.GetFibData( cmd_fibcontext );
+	BlockWriteDisk->Command     = VM_CtBlockWrite;
+	BlockWriteDisk->ContainerId = ContainerId;
+	BlockWriteDisk->BlockNumber = lba;
+	BlockWriteDisk->ByteCount   = count * 512;
+	BlockWriteDisk->SgMap.SgCount = 1;
+
+	if ( BlockWriteDisk->ByteCount > ( 64 * 1024 ) )
+	{
+		cmn_err( CE_WARN, "AacHba_DoScsiWrite: WRITE request is larger than 64K" );
+		scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
+
+		AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ],
+				SENKEY_ILLEGAL, SENCODE_INVALID_CDB_FIELD, ASENCODE_INVALID_CDB_FIELD, 
+				0, 0, 7, 0 );
+
+		goto err_return;
+	}
+
+	//-------------------------------------------------------------------------
+	// Build Scatter/Gather list
+	//
+	if ( scsi_cmnd_ptr->use_sg )	// use scatter/gather list
+	{
+		struct scatterlist *scatterlist_ptr;
+		int segment;
+		
+		scatterlist_ptr = ( struct scatterlist * )scsi_cmnd_ptr->request_buffer;
+
+		byte_count = 0;
+		for( segment = 0; segment< scsi_cmnd_ptr->use_sg; segment++ ) 
+		{
+			BlockWriteDisk->SgMap.SgEntry[segment].SgAddress = 
+				( HOSTADDRESS )OsVirtToPhys( scatterlist_ptr[segment].address );
+			BlockWriteDisk->SgMap.SgEntry[segment].SgByteCount = 
+				scatterlist_ptr[segment].length;
+			
+			byte_count += scatterlist_ptr[segment].length;
+
+			if ( BlockWriteDisk->SgMap.SgEntry[segment].SgByteCount > ( 64 * 1024 ) )
+			{
+				cmn_err( CE_WARN, "AacHba_DoScsiWrite: Segment byte count is larger than 64K" );
+				scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
+
+				AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ],
+					SENKEY_ILLEGAL, SENCODE_INVALID_CDB_FIELD, ASENCODE_INVALID_CDB_FIELD, 
+					0, 0, 7, 0 );
+
+				goto err_return;
+			}
+
+			/*
+			cmn_err(CE_DEBUG, "SgEntry[%d].SgAddress = 0x%x, Byte count = 0x%x", 
+					segment,
+					BlockWriteDisk->SgMap.SgEntry[segment].SgAddress,
+					BlockWriteDisk->SgMap.SgEntry[segment].SgByteCount); 
+			*/
+		}
+		BlockWriteDisk->SgMap.SgCount = scsi_cmnd_ptr->use_sg;
+
+		if( BlockWriteDisk->SgMap.SgCount > MAX_DRIVER_SG_SEGMENT_COUNT ) 
+		{
+			cmn_err( CE_WARN, "AacHba_DoScsiWrite: WRITE request with SgCount > %d", 
+				MAX_DRIVER_SG_SEGMENT_COUNT );
+			scsi_cmnd_ptr->result = DID_ERROR << 16;
+			goto err_return;
+		}
+	} 
+	else		// one piece of contiguous phys mem
+	{
+		BlockWriteDisk->SgMap.SgEntry[0].SgAddress = 
+			( HOSTADDRESS )OsVirtToPhys( scsi_cmnd_ptr->request_buffer );
+		BlockWriteDisk->SgMap.SgEntry[0].SgByteCount = scsi_cmnd_ptr->request_bufflen;
+
+		byte_count = scsi_cmnd_ptr->request_bufflen;
+
+		if ( BlockWriteDisk->SgMap.SgEntry[0].SgByteCount > ( 64 * 1024 ) )
+		{
+			cmn_err( CE_WARN, "AacHba_DoScsiWrite: Single segment byte count is larger than 64K" );
+
+			scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
+			AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ],
+				SENKEY_ILLEGAL, SENCODE_INVALID_CDB_FIELD, ASENCODE_INVALID_CDB_FIELD, 
+				0, 0, 7, 0 );
+
+			goto err_return;
+		}
+	}
+
+	if( byte_count != BlockWriteDisk->ByteCount )
+		cmn_err( CE_WARN, "AacHba_DoScsiWrite: byte_count != BlockReadDisk->ByteCount" );
+
+	//-------------------------------------------------------------------------
+	// Now send the Fib to the adapter
+	//
+	FibSize = sizeof( BLOCKWRITE ) + ( ( BlockWriteDisk->SgMap.SgCount - 1 ) * sizeof( SGENTRY ) );
+
+	if( wait ) 
+	{
+		Status = Adapter->CommFuncs.SendFib( ContainerCommand,
+											 cmd_fibcontext,
+											 FibSize,
+											 FsaNormal,
+											 TRUE,
+											 NULL,
+											 TRUE,
+											 NULL,
+											 NULL );
+
+		BlockWriteResponse = ( PBLOCKWRITERESPONSE ) 
+			Adapter->CommFuncs.GetFibData( cmd_fibcontext );	
+
+		Adapter->CommFuncs.CompleteFib(  cmd_fibcontext );
+		Adapter->CommFuncs.FreeFib(  cmd_fibcontext );
+
+		if( BlockWriteResponse->Status != ST_OK )
+		{
+			cmn_err( CE_WARN, "AacHba_DoScsiWrite: BlockWriteCommand failed with status: %d\n", 
+				BlockWriteResponse->Status );
+			scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;;
+			AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ],
+				SENKEY_HW_ERR, SENCODE_INTERNAL_TARGET_FAILURE, ASENCODE_INTERNAL_TARGET_FAILURE, 
+				0, 0, 0, 0 );
+			AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+			return ( -1 );
+		}
+		else
+			scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+
+		AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+		return ( 0 );
+	} 
+	else 
+	{
+		Status = Adapter->CommFuncs.SendFib( ContainerCommand,
+											 cmd_fibcontext,
+											 FibSize,
+											 FsaNormal,
+											 FALSE,
+											 NULL,
+											 TRUE,
+											 ( PFIB_CALLBACK )AacHba_WriteCallback,
+											 ( void * )scsi_cmnd_ptr );
+
+		// don't call done func here - it should be called by the WriteCallback
+		return ( 0 );
+	}
+
+err_return:
+	AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
+
+	Adapter->CommFuncs.CompleteFib( cmd_fibcontext );
+	Adapter->CommFuncs.FreeFib( cmd_fibcontext );
+
+	return ( -1 );
+}
+
+
+/*------------------------------------------------------------------------------
+	AacHba_ReadCallback()
+ *----------------------------------------------------------------------------*/
+void AacHba_ReadCallback(  
+	VOID    		*Context,
+	PFIB_CONTEXT	FibContext,
+	int				FibStatus )
+/*----------------------------------------------------------------------------*/
+{
+	PCI_MINIPORT_COMMON_EXTENSION	*CommonExtension;
+	AFA_COMM_ADAPTER				*Adapter;
+	BLOCKREADRESPONSE				*BlockReadResponse;
+	Scsi_Cmnd * scsi_cmnd_ptr;
+	u_long							lba;
+	int			ContainerId;
+
+	scsi_cmnd_ptr = ( Scsi_Cmnd * )Context;
+
+	CommonExtension = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata );
+	Adapter         = ( AFA_COMM_ADAPTER * )CommonExtension->Adapter;
+
+	ContainerId = TARGET_LUN_TO_CONTAINER( scsi_cmnd_ptr->target, scsi_cmnd_ptr->lun );
+	
+	lba = ( ( scsi_cmnd_ptr->cmnd[1] & 0x1F ) << 16 ) | 
+			( scsi_cmnd_ptr->cmnd[2] << 8 ) |
+			scsi_cmnd_ptr->cmnd[3];
+	cmn_err( CE_DEBUG, "AacHba_ReadCallback[cpu %d]: lba = %ld, t = %ld", smp_processor_id(), lba, jiffies );
+
+	if( FibContext == 0 ) 
+	{
+		cmn_err( CE_WARN, "AacHba_ReadCallback: no fib context" );
+		scsi_cmnd_ptr->result = DID_ERROR << 16;
+		AacHba_CompleteScsi( scsi_cmnd_ptr );
+		return;
+	}
+
+    BlockReadResponse = ( PBLOCKREADRESPONSE )Adapter->CommFuncs.GetFibData( FibContext );
+
+	if ( BlockReadResponse->Status == ST_OK ) 
+		scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+	else 
+	{
+		cmn_err( CE_WARN, "AacHba_ReadCallback: read failed, status = %d\n", 
+			BlockReadResponse->Status );
+		scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
+		AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ],
+			SENKEY_HW_ERR, SENCODE_INTERNAL_TARGET_FAILURE, ASENCODE_INTERNAL_TARGET_FAILURE, 
+			0, 0, 0, 0 );
+	}
+
+#ifdef DEBUG_SGBUFFER
+	if ( scsi_cmnd_ptr->use_sg )	// use scatter/gather list
+	{
+		struct scatterlist *scatterlist_ptr;
+		int i, segment, count;
+		char *ptr;
+		
+		scatterlist_ptr = ( struct scatterlist * )scsi_cmnd_ptr->request_buffer;
+
+		for( segment = 0; segment < scsi_cmnd_ptr->use_sg; segment++ ) 
+		{
+			count = 0;
+			ptr = scatterlist_ptr[segment].address;
+			for( i = 0; i < scatterlist_ptr[segment].length; i++ )
+			{
+				if( *( ptr++ ) == 0xa5 )
+					count++;
+			}
+			if( count == scatterlist_ptr[segment].length )
+				cmn_err( CE_WARN, "AacHba_ReadCallback: segment %d not filled", segment );
+
+		}
+	}
+#endif
+
+	Adapter->CommFuncs.CompleteFib( FibContext );
+	Adapter->CommFuncs.FreeFib( FibContext );
+
+	AacHba_CompleteScsi( scsi_cmnd_ptr );
+}
+
+/*------------------------------------------------------------------------------
+	AacHba_WriteCallback()
+ *----------------------------------------------------------------------------*/
+void AacHba_WriteCallback(  
+	VOID    		*Context,
+	PFIB_CONTEXT	FibContext,
+	int				FibStatus )
+/*----------------------------------------------------------------------------*/
+{
+	PCI_MINIPORT_COMMON_EXTENSION	*CommonExtension;
+	AFA_COMM_ADAPTER				*Adapter;
+	BLOCKWRITERESPONSE				*BlockWriteResponse;
+	Scsi_Cmnd						*scsi_cmnd_ptr;
+	u_long							lba;
+	int			ContainerId;
+
+	scsi_cmnd_ptr = ( Scsi_Cmnd * )Context;
+
+	CommonExtension = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata );
+	Adapter         = ( AFA_COMM_ADAPTER * )CommonExtension->Adapter;
+	
+	ContainerId = TARGET_LUN_TO_CONTAINER( scsi_cmnd_ptr->target, scsi_cmnd_ptr->lun );
+
+	lba = ( ( scsi_cmnd_ptr->cmnd[1] & 0x1F ) << 16 ) | 
+			( scsi_cmnd_ptr->cmnd[2] << 8 ) |
+			scsi_cmnd_ptr->cmnd[3];
+	cmn_err( CE_DEBUG, "AacHba_WriteCallback[cpu %d]: lba = %ld, t = %ld", smp_processor_id(), lba, jiffies );
+	if( FibContext == 0 ) 
+	{
+		cmn_err( CE_WARN, "AacHba_WriteCallback: no fib context" );
+		scsi_cmnd_ptr->result = DID_ERROR << 16;
+		AacHba_CompleteScsi( scsi_cmnd_ptr );
+		return;
+	}
+
+    BlockWriteResponse = (PBLOCKWRITERESPONSE) Adapter->CommFuncs.GetFibData( FibContext );
+	if (BlockWriteResponse->Status == ST_OK) 
+		scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
+	else 
+	{
+		cmn_err( CE_WARN, "AacHba_WriteCallback: write failed, status = %d\n", 
+			BlockWriteResponse->Status );
+		scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
+		AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ],
+			SENKEY_HW_ERR, SENCODE_INTERNAL_TARGET_FAILURE, ASENCODE_INTERNAL_TARGET_FAILURE, 
+			0, 0, 0, 0 );
+	}
+
+	Adapter->CommFuncs.CompleteFib( FibContext );
+	Adapter->CommFuncs.FreeFib( FibContext );
+
+	AacHba_CompleteScsi( scsi_cmnd_ptr );
+}
+
+
+/*------------------------------------------------------------------------------
+	AacHba_Ioctl()
+
+		Handle IOCTL requests
+
+	Preconditions:
+	Postconditions:
+ *----------------------------------------------------------------------------*/
+int AacHba_Ioctl(
+	PCI_MINIPORT_COMMON_EXTENSION *CommonExtension,
+	int cmd,
+	void * arg )
+/*----------------------------------------------------------------------------*/
+{
+	Sa_ADAPTER_EXTENSION		  *AdapterExtension;
+	AFA_IOCTL_CMD IoctlCmd;
+	int status;
+	
+	AdapterExtension = ( Sa_ADAPTER_EXTENSION * )CommonExtension->MiniPort;
+
+	cmn_err( CE_DEBUG, "AacHba_Ioctl, type = %d", cmd );
+	switch( cmd )
+	{
+	  case FSACTL_SENDFIB:
+		  cmn_err( CE_DEBUG, "FSACTL_SENDFIB" );
+		break;
+
+	  case FSACTL_AIF_THREAD:
+		  cmn_err( CE_DEBUG, "FSACTL_AIF_THREAD" );
+		break;
+
+	  case FSACTL_NULL_IO_TEST:
+		  cmn_err( CE_DEBUG, "FSACTL_NULL_IO_TEST" );
+		break;
+
+	  case FSACTL_SIM_IO_TEST:
+		  cmn_err( CE_DEBUG, "FSACTL_SIM_IO_TEST" );
+		break;
+
+	  case FSACTL_GET_FIBTIMES:
+		  cmn_err( CE_DEBUG, "FSACTL_GET_FIBTIMES" );
+		break;
+
+	  case FSACTL_ZERO_FIBTIMES:
+		  cmn_err( CE_DEBUG, "FSACTL_ZERO_FIBTIMES");
+		break;
+
+	  case FSACTL_GET_VAR:
+		  cmn_err( CE_DEBUG, "FSACTL_GET_VAR" );
+		break;
+
+	  case FSACTL_SET_VAR:
+		  cmn_err( CE_DEBUG, "FSACTL_SET_VAR" );
+		break;
+
+	  case FSACTL_OPEN_ADAPTER_CONFIG:
+		  cmn_err( CE_DEBUG, "FSACTL_OPEN_ADAPTER_CONFIG" );
+		break;	
+
+	  case FSACTL_CLOSE_ADAPTER_CONFIG:
+		  cmn_err( CE_DEBUG, "FSACTL_CLOSE_ADAPTER_CONFIG" );
+		break;
+
+	  case FSACTL_QUERY_ADAPTER_CONFIG:
+		  cmn_err( CE_DEBUG, "FSACTL_QUERY_ADAPTER_CONFIG" );
+		break;
+
+	  case FSACTL_OPEN_GET_ADAPTER_FIB:
+		  cmn_err( CE_DEBUG, "FSACTL_OPEN_GET_ADAPTER_FIB" );
+		break;
+
+	  case FSACTL_GET_NEXT_ADAPTER_FIB:
+		  cmn_err( CE_DEBUG, "FSACTL_GET_NEXT_ADAPTER_FIB" );
+		break;
+
+	  case FSACTL_CLOSE_GET_ADAPTER_FIB:
+		  cmn_err( CE_DEBUG, "FSACTL_CLOSE_GET_ADAPTER_FIB" );
+		break;
+
+	  case FSACTL_MINIPORT_REV_CHECK:
+		  cmn_err( CE_DEBUG, "FSACTL_MINIPORT_REV_CHECK" );
+		break;
+
+	  case FSACTL_OPENCLS_COMM_PERF_DATA:
+		  cmn_err( CE_DEBUG, "FSACTL_OPENCLS_COMM_PERF_DATA" );
+		break;
+	
+	  case FSACTL_GET_COMM_PERF_DATA:
+		  cmn_err( CE_DEBUG, "FSACTL_GET_COMM_PERF_DATA" );
+		break;
+
+	  case FSACTL_QUERY_DISK:
+		  cmn_err( CE_DEBUG, "FSACTL_QUERY_DISK" );
+		break;
+		
+	  case FSACTL_DELETE_DISK:
+		  cmn_err( CE_DEBUG, "FSACTL_DELETE_DISK" );
+		break;
+
+	  default:
+		  cmn_err( CE_DEBUG, "Unknown ioctl: 0x%x", cmd );
+	}
+
+	IoctlCmd.cmd = cmd;
+	IoctlCmd.arg = ( intptr_t )arg;
+	IoctlCmd.flag = 0;
+	IoctlCmd.cred_p = 0;
+	IoctlCmd.rval_p = 0;
+
+	status = AfaCommAdapterDeviceControl( CommonExtension->Adapter, &IoctlCmd );
+	cmn_err( CE_DEBUG, "AAC_Ioctl, completion status = %d", status );
+	return( status );
+}
+
+
+/*------------------------------------------------------------------------------
+	AacHba_AdapterDeviceControl()
+
+	Preconditions:
+	Postconditions:
+		Returns TRUE if ioctl handled, FALSE otherwise
+		*ReturnStatus set to completion status
+ *----------------------------------------------------------------------------*/
+BOOLEAN AacHba_AdapterDeviceControl (
+	PVOID AdapterArg,		// CommonExtensionPtr
+	IN PAFA_IOCTL_CMD IoctlCmdPtr,
+	OUT int * ReturnStatus )
+/*----------------------------------------------------------------------------*/
+{
+	BOOLEAN Handled = TRUE;	// start out handling it.
+	int Status = EFAULT;
+
+	switch( IoctlCmdPtr->cmd )
+	{
+		case FSACTL_QUERY_DISK:
+			Status = AacHba_QueryDisk( AdapterArg, IoctlCmdPtr );
+			break;
+
+		case FSACTL_DELETE_DISK:
+			Status = AacHba_DeleteDisk( AdapterArg, IoctlCmdPtr );
+			break;
+
+		case FSACTL_FORCE_DELETE_DISK:
+			Status = AacHba_ForceDeleteDisk( AdapterArg, IoctlCmdPtr );
+			break;
+
+		case 2131:
+			if( AacHba_ProbeContainers( ( PCI_MINIPORT_COMMON_EXTENSION * )AdapterArg ) )
+				Status = -EFAULT;
+			break;
+
+		default:
+			Handled = FALSE;
+			break;
+	}
+
+	*ReturnStatus = Status;
+
+	return( Handled );
+}
+
+
+/*------------------------------------------------------------------------------
+	AacHba_QueryDisk()
+
+	Postconditions:
+		Return values
+		0       = OK
+		-EFAULT = Bad address
+		-EINVAL = Bad container number
+ *----------------------------------------------------------------------------*/
+int AacHba_QueryDisk(
+	PVOID AdapterArg,		// CommonExtensionPtr
+	IN PAFA_IOCTL_CMD IoctlCmdPtr )
+/*----------------------------------------------------------------------------*/
+{
+	UNIX_QUERY_DISK QueryDisk;
+	PCI_MINIPORT_COMMON_EXTENSION	*CommonExtensionPtr;
+	fsadev_t						*fsa_dev_ptr;
+
+	CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )AdapterArg;
+	fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev );
+
+	if( copyin( IoctlCmdPtr->arg, &QueryDisk, sizeof( UNIX_QUERY_DISK ) ) )
+		return( -EFAULT );
+
+	if (QueryDisk.ContainerNumber == -1)
+		QueryDisk.ContainerNumber = TARGET_LUN_TO_CONTAINER( QueryDisk.Target, QueryDisk.Lun );
+	else 
+		if( ( QueryDisk.Bus == -1 ) && ( QueryDisk.Target == -1 ) && ( QueryDisk.Lun == -1 ) )
+		{
+			if( QueryDisk.ContainerNumber > MAXIMUM_NUM_CONTAINERS )
+				return( -EINVAL );
+
+			QueryDisk.Instance = CommonExtensionPtr->OsDep.scsi_host_ptr->host_no;
+			QueryDisk.Bus = 0;
+			QueryDisk.Target = CONTAINER_TO_TARGET( QueryDisk.ContainerNumber );
+			QueryDisk.Lun = CONTAINER_TO_LUN( QueryDisk.ContainerNumber );
+		}
+		else 
+			return( -EINVAL );
+
+	QueryDisk.Valid = fsa_dev_ptr->ContainerValid[QueryDisk.ContainerNumber];
+	QueryDisk.Locked = fsa_dev_ptr->ContainerLocked[QueryDisk.ContainerNumber];
+	QueryDisk.Deleted = fsa_dev_ptr->ContainerDeleted[QueryDisk.ContainerNumber];
+
+	if( fsa_dev_ptr->ContainerDevNo[QueryDisk.ContainerNumber] == -1 )
+		QueryDisk.UnMapped = TRUE;
+	else
+		QueryDisk.UnMapped = FALSE;
+
+	get_sd_devname( fsa_dev_ptr->ContainerDevNo[QueryDisk.ContainerNumber], 
+		QueryDisk.diskDeviceName );
+
+	if( copyout( &QueryDisk, IoctlCmdPtr->arg, sizeof( UNIX_QUERY_DISK ) ) )
+		return( -EFAULT );
+
+	return( 0 );
+}
+
+
+/*------------------------------------------------------------------------------
+	get_sd_devname()
+ *----------------------------------------------------------------------------*/
+static void get_sd_devname(
+	long disknum, 
+	char * buffer)
+/*----------------------------------------------------------------------------*/
+{
+ 	if( disknum < 0 )
+	{
+        sprintf(buffer, "%s", "");
+		return;
+	}
+
+   if( disknum < 26 )
+        sprintf(buffer, "sd%c", 'a' + disknum);
+    else {
+        unsigned int min1;
+        unsigned int min2;
+        /*
+         * For larger numbers of disks, we need to go to a new
+         * naming scheme.
+         */
+        min1 = disknum / 26;
+        min2 = disknum % 26;
+        sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2);
+    }
+}
+
+
+/*------------------------------------------------------------------------------
+	AacHba_ForceDeleteDisk()
+
+	Postconditions:
+		Return values
+		0       = OK
+		-EFAULT = Bad address
+		-EINVAL = Bad container number
+ *----------------------------------------------------------------------------*/
+int AacHba_ForceDeleteDisk(
+	PVOID AdapterArg,		// CommonExtensionPtr
+	IN PAFA_IOCTL_CMD IoctlCmdPtr )
+/*----------------------------------------------------------------------------*/
+{
+	DELETE_DISK	 DeleteDisk;
+	PCI_MINIPORT_COMMON_EXTENSION	*CommonExtensionPtr;
+	fsadev_t						*fsa_dev_ptr;
+
+	CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )AdapterArg;
+	fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev );
+
+	if ( copyin( IoctlCmdPtr->arg,  &DeleteDisk, sizeof( DELETE_DISK ) ) )
+		return( -EFAULT );
+
+	if ( DeleteDisk.ContainerNumber > MAXIMUM_NUM_CONTAINERS ) 
+		return( -EINVAL );
+	
+	// Mark this container as being deleted.
+	fsa_dev_ptr->ContainerDeleted[DeleteDisk.ContainerNumber] = TRUE;
+
+	// Mark the container as no longer valid
+	fsa_dev_ptr->ContainerValid[DeleteDisk.ContainerNumber] = 0;
+
+	return( 0 );
+}
+
+
+/*------------------------------------------------------------------------------
+	AacHba_DeleteDisk()
+
+	Postconditions:
+		Return values
+		0       = OK
+		-EFAULT = Bad address
+		-EINVAL = Bad container number
+		-EBUSY  = Device locked
+ *----------------------------------------------------------------------------*/
+int AacHba_DeleteDisk(
+	PVOID AdapterArg,
+	IN PAFA_IOCTL_CMD IoctlCmdPtr )
+/*----------------------------------------------------------------------------*/
+{
+	DELETE_DISK DeleteDisk;
+	PCI_MINIPORT_COMMON_EXTENSION	*CommonExtensionPtr;
+	fsadev_t						*fsa_dev_ptr;
+
+	CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )AdapterArg;
+	fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev );
+
+	if( copyin( IoctlCmdPtr->arg, &DeleteDisk, sizeof( DELETE_DISK ) ) ) 
+		return( -EFAULT );
+
+	if( DeleteDisk.ContainerNumber > MAXIMUM_NUM_CONTAINERS )
+		return( -EINVAL );
+	
+	// If the container is locked, it can not be deleted by the API.
+	if( fsa_dev_ptr->ContainerLocked[DeleteDisk.ContainerNumber] )
+		return( -EBUSY );
+	else 
+	{	
+		// Mark the container as no longer being valid.
+		fsa_dev_ptr->ContainerValid[DeleteDisk.ContainerNumber] = 0;
+		fsa_dev_ptr->ContainerDevNo[DeleteDisk.ContainerNumber] = -1;
+		return(0);
+	}	
+}
+
+
+/*------------------------------------------------------------------------------
+	AacHba_OpenAdapter()
+ *----------------------------------------------------------------------------*/
+AAC_STATUS AacHba_OpenAdapter(
+	IN PVOID AdapterArg )
+/*----------------------------------------------------------------------------*/
+{
+	return( STATUS_SUCCESS );
+}
+
+
+/*------------------------------------------------------------------------------
+	AacHba_CloseAdapter()
+ *----------------------------------------------------------------------------*/
+AAC_STATUS AacHba_CloseAdapter(
+	IN PVOID AdapterArg )
+/*----------------------------------------------------------------------------*/
+{
+	return( STATUS_SUCCESS );
+}
+
+
+/*------------------------------------------------------------------------------
+	AacHba_DetachAdapter()
+ *----------------------------------------------------------------------------*/
+void AacHba_DetachAdapter(
+	IN PVOID AdapterArg )
+/*----------------------------------------------------------------------------*/
+{
+	AacCommDetachAdapter( AdapterArg );
+}
+
+
+/*------------------------------------------------------------------------------
+	AacHba_AbortScsiCommand()
+ *----------------------------------------------------------------------------*/
+void AacHba_AbortScsiCommand(
+	Scsi_Cmnd *scsi_cmnd_ptr )
+/*----------------------------------------------------------------------------*/
+{
+	u_short interrupt_status;
+	PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr;
+
+	CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata );
+	interrupt_status = Sa_READ_USHORT( ( PSa_ADAPTER_EXTENSION )( CommonExtensionPtr->MiniPort ),
+		DoorbellReg_p );
+	cmn_err( CE_WARN, "interrupt_status = %d", interrupt_status );
+	
+	if( interrupt_status & DOORBELL_1) {	// Adapter -> Host Normal Command Ready
+		cmn_err( CE_WARN, "DOORBELL_1: Adapter -> Host Normal Command Ready" );
+	} 
+
+	if( interrupt_status & DOORBELL_2) {	// Adapter -> Host Normal Response Ready
+		cmn_err( CE_WARN, "DOORBELL_2: Adapter -> Host Normal Response Ready" );
+	}
+
+	if ( interrupt_status & DOORBELL_3) {	// Adapter -> Host Normal Command Not Full
+		cmn_err( CE_WARN, "DOORBELL_3: Adapter -> Host Normal Command Not Full" );
+	}
+
+	if ( interrupt_status & DOORBELL_4) {	// Adapter -> Host Normal Response Not Full
+		cmn_err( CE_WARN, "DOORBELL_4: Adapter -> Host Normal Response Not Full" );
+	}
+
+}
+
+
+/*------------------------------------------------------------------------------
+	AacHba_HandleAif()
+ *----------------------------------------------------------------------------*/
+BOOLEAN AacHba_HandleAif(
+	IN PVOID AdapterArg,
+	IN PFIB_CONTEXT FibContext )
+/*----------------------------------------------------------------------------*/
+{
+	return( FALSE );
+}
+
+
+/*------------------------------------------------------------------------------
+	AacHba_SetSenseData()
+		Fill in the sense data.
+	Preconditions:
+	Postconditions:
+ *----------------------------------------------------------------------------*/
+void AacHba_SetSenseData(
+	char * sense_buf,
+	unchar sense_key,
+	unchar sense_code,
+	unchar a_sense_code,
+	unchar incorrect_length,
+	unchar bit_pointer,
+	unsigned field_pointer,
+	unsigned long residue )
+/*----------------------------------------------------------------------------*/
+{
+	sense_buf[0] = 0xF0;                	// Sense data valid, err code 70h (current error)
+	sense_buf[1] = 0;								// Segment number, always zero
+
+	if( incorrect_length )
+	{
+		sense_buf[2] = sense_key | 0x20;		// Set the ILI bit | sense key
+		sense_buf[3] = BYTE3(residue);
+		sense_buf[4] = BYTE2(residue);
+		sense_buf[5] = BYTE1(residue);
+		sense_buf[6] = BYTE0(residue);
+	}
+	else
+		sense_buf[2] = sense_key;				// Sense key
+
+	if( sense_key == SENKEY_ILLEGAL )
+		sense_buf[7] = 10;						// Additional sense length
+	else
+		sense_buf[7] = 6;						// Additional sense length
+
+	sense_buf[12] = sense_code; 				// Additional sense code
+	sense_buf[13] = a_sense_code;				// Additional sense code qualifier
+	if( sense_key == SENKEY_ILLEGAL )
+	{
+		sense_buf[15] = 0;
+
+		if( sense_code == SENCODE_INVALID_PARAM_FIELD )
+			sense_buf[15] = 0x80; 				// Std sense key specific field
+												// Illegal parameter is in the parameter block
+
+		if( sense_code == SENCODE_INVALID_CDB_FIELD )
+			sense_buf[15] = 0xc0; 				// Std sense key specific field
+												// Illegal parameter is in the CDB block
+		sense_buf[15] |= bit_pointer;
+		sense_buf[16] = field_pointer >> 8;	// MSB
+		sense_buf[17] = field_pointer;		// LSB
+	}
+}
+
diff -BburN linux.orig/drivers/scsi/aacraid/aacid.c linux/drivers/scsi/aacraid/aacid.c
--- linux.orig/drivers/scsi/aacraid/aacid.c	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/aacid.c	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,151 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  aac.c
+ *
+ * Abstract: Data structures for controller specific info.
+ *
+--*/
+
+#include "osheaders.h"
+
+#include "AacGenericTypes.h"
+
+#include "aac_unix_defs.h"
+
+#include "fsatypes.h"
+#include "comstruc.h"
+#include "fsaport.h"
+#include "pcisup.h"
+
+#include "version.h"
+
+
+/* Function Prototypes */
+void InqStrCopy(char *a, char *b); /* ossup.c */
+
+/* Device name used to register and unregister
+   the device in linit.c */
+char devicestr[]="aac";
+
+char *container_types[] = {
+        "None",
+        "Volume",
+        "Mirror",
+        "Stripe",
+        "RAID5",
+        "SSRW",
+        "SSRO",
+        "Morph",
+        "Legacy",
+        "RAID4",
+        "RAID10",             
+        "RAID00",             
+        "V-MIRRORS",          
+        "PSEUDO R4",          
+	"RAID50",
+        "Unknown"
+};
+
+/* Local Structure to set SCSI inquiry data strings */
+typedef struct _INQSTR {
+  char vid[8];         /* Vendor ID */
+  char pid[16];        /* Product ID */
+  char prl[4];         /* Product Revision Level */
+} INQSTR, *INQSTRP;
+
+FSA_MINIPORT MiniPorts[];
+
+/* Function: SetInqDataStr
+ *
+ * Arguments: [1] pointer to void [1] int
+ *
+ * Purpose: Sets SCSI inquiry data strings for vendor, product
+ * and revision level. Allows strings to be set in platform dependant
+ * files instead of in OS dependant driver source.
+ */
+void
+SetInqDataStr (
+  int MiniPortIndex,
+  void *dataPtr,
+  int tindex)
+{
+  INQSTRP InqStrPtr;
+   char *findit;
+   FSA_MINIPORT   *mp;
+
+   mp = &MiniPorts[MiniPortIndex];
+   
+    InqStrPtr = (INQSTRP)(dataPtr); /* cast dataPtr to type INQSTRP */
+
+    InqStrCopy (mp->Vendor, InqStrPtr->vid); 
+    InqStrCopy (mp->Model,  InqStrPtr->pid); /* last six chars reserved for vol type */
+
+    findit = InqStrPtr->pid;
+
+    for ( ; *findit != ' '; findit++); /* walk till we find a space then incr by 1 */
+        findit++;
+	
+    if (tindex < (sizeof(container_types)/sizeof(char *))){
+      InqStrCopy (container_types[tindex], findit);
+    }
+   InqStrCopy ("0001", InqStrPtr->prl);
+}
+
+int
+SaInitDevice(
+	IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension,
+	IN ULONG AdapterNumber,
+	IN ULONG PciBus,
+	IN ULONG PciSlot
+);
+
+int
+RxInitDevice(
+	IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension,
+	IN ULONG AdapterNumber,
+	IN ULONG PciBus,
+	IN ULONG PciSlot
+);
+
+
+/*
+ * Because of the way Linux names scsi devices, the order in this table has
+ * become important.  Check for on-board Raid first, add-in cards second.
+ */
+
+FSA_MINIPORT MiniPorts[] = {
+	{ 0x1028, 0x0001, 0x1028, 0x0001, "afa", RxInitDevice, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Si */
+	{ 0x1028, 0x0002, 0x1028, 0x0002, "afa", RxInitDevice, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Di */
+	{ 0x1028, 0x0003, 0x1028, 0x0003, "afa", RxInitDevice, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Si */
+	{ 0x1028, 0x0004, 0x1028, 0x00d0, "afa", RxInitDevice, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Si */
+	{ 0x1028, 0x0005, 0x1028, 0x00d1, "afa", RxInitDevice, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Di */
+	{ 0x1028, 0x0006, 0x1028, 0x00d9, "afa", RxInitDevice, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Di */
+	{ 0x1028, 0x0008, 0x1028, 0x00cf, "afa", RxInitDevice, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Di */
+	{ 0x1011, 0x0046, 0x9005, 0x1364, "afa", SaInitDevice, "percraid", "DELL    ", "PERCRAID        " }, /* Dell PERC2 "Quad Channel */
+	{ 0x1011, 0x0046, 0x103c, 0x10c2, "hpn", SaInitDevice, "hpnraid",  "HP      ", "NetRAID-4M      " }  /* HP NetRAID-4M */
+};
+
+
+#define NUM_MINIPORTS	(sizeof(MiniPorts) / sizeof(FSA_MINIPORT))
+
+int NumMiniPorts = NUM_MINIPORTS;
+
+char DescriptionString[] =	"AACxxx Raid Controller" FSA_VERSION_STRING ;
diff -BburN linux.orig/drivers/scsi/aacraid/commctrl.c linux/drivers/scsi/aacraid/commctrl.c
--- linux.orig/drivers/scsi/aacraid/commctrl.c	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/commctrl.c	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,1049 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  commctrl.c
+ *
+ * Abstract: Contains all routines for control of the AFA comm layer
+ *
+--*/
+
+#include "comprocs.h"
+#include "osheaders.h"
+#include "ostypes.h"
+
+
+
+
+
+typedef BOOLEAN BOOL;
+#define inline /* _inline */
+
+#include <revision.h>
+AAC_STATUS
+FsaCtlCheckRevision(
+	IN PAFA_COMM_ADAPTER	Adapter,
+	IN PAFA_IOCTL_CMD		IoctlCmdPtr
+	)
+/*++
+
+Routine Description:
+
+	This routine validates the revision of the caller with the current revision
+	of the filesystem.
+
+Arguments:
+
+	Adapter - Supplies which adapter is being processed.
+
+    Irp - Supplies the Irp being processed.
+
+	IrpContext - Supplies the IrpContext.
+
+Return Value:
+
+	AAC_STATUS
+
+--*/
+
+{
+	RevCheck APIRevCheck;
+	RevCheckResp APIRevCheckResp;
+	RevComponent APICallingComponent;
+	ULONG APIBuildNumber;
+
+	if (COPYIN( (caddr_t) IoctlCmdPtr->arg, (caddr_t) &APIRevCheck, sizeof(RevCheck), IoctlCmdPtr->flag )) {
+		return (EFAULT);
+	}
+
+	APICallingComponent = APIRevCheck.callingComponent;
+	APIBuildNumber = APIRevCheck.callingRevision.buildNumber;
+
+	APIRevCheckResp.possiblyCompatible = RevCheckCompatibility( RevMiniportDriver , APICallingComponent, APIBuildNumber );
+
+	APIRevCheckResp.adapterSWRevision.external.ul = RevGetExternalRev();
+	APIRevCheckResp.adapterSWRevision.buildNumber = RevGetBuildNumber();
+
+	if (COPYOUT( (caddr_t) &APIRevCheckResp, (caddr_t) IoctlCmdPtr->arg, sizeof(RevCheckResp), IoctlCmdPtr->flag )) {
+		return (EFAULT);
+	}
+
+	return (0);
+}
+
+
+int
+AfaCommAdapterDeviceControl(
+	IN PVOID AdapterArg,
+	IN PAFA_IOCTL_CMD IoctlCmdPtr
+	)
+{
+	PAFA_COMM_ADAPTER Adapter = (PAFA_COMM_ADAPTER) AdapterArg;
+    int Status = ENOTTY;
+//    PIO_STACK_LOCATION IrpSp;
+	PAFA_CLASS_DRIVER ClassDriver;
+
+	//
+	// First loop through all of the class drivers to give them a chance to handle
+	// the Device control first.
+	//
+
+	ClassDriver = Adapter->ClassDriverList;
+
+	while (ClassDriver) {
+
+		if (ClassDriver->DeviceControl) {
+
+			if (ClassDriver->DeviceControl( ClassDriver->ClassDriverExtension, IoctlCmdPtr, &Status ) ) {
+
+				return (Status);
+
+			}
+		}
+
+		ClassDriver = ClassDriver->Next;
+	}
+
+    switch (IoctlCmdPtr->cmd) {
+
+
+	  case FSACTL_SENDFIB:
+
+		Status = AfaCommCtlSendFib( Adapter, IoctlCmdPtr );
+		break;
+
+	  case FSACTL_AIF_THREAD:
+
+	  	Status = AfaCommCtlAifThread( Adapter, IoctlCmdPtr );	
+		break;
+
+
+	  case FSACTL_OPEN_GET_ADAPTER_FIB:
+
+		Status = FsaCtlOpenGetAdapterFib( Adapter, IoctlCmdPtr );
+		break;
+
+	  case FSACTL_GET_NEXT_ADAPTER_FIB:
+
+		Status = FsaCtlGetNextAdapterFib( Adapter, IoctlCmdPtr );
+		break;
+
+	  case FSACTL_CLOSE_GET_ADAPTER_FIB:
+
+		Status = FsaCtlCloseGetAdapterFib( Adapter, IoctlCmdPtr );
+		break;
+
+	  case FSACTL_MINIPORT_REV_CHECK:
+        
+		Status = FsaCtlCheckRevision( Adapter , IoctlCmdPtr );
+		break;
+
+
+      default:
+	  
+	  	Status = ENOTTY;
+	  	break;	
+
+	}
+
+
+	return (Status);
+}
+
+AAC_STATUS
+AfaCommRegisterNewClassDriver(
+	IN PAFA_COMM_ADAPTER	Adapter,
+	IN PAFA_NEW_CLASS_DRIVER	NewClassDriver,
+	OUT PAFA_NEW_CLASS_DRIVER_RESPONSE NewClassDriverResponse
+	)
+/*++
+
+Routine Description:
+
+	This routine registers a new class driver for the comm layer.
+
+	It will return a pointer to the communication functions for the class driver
+	to use.
+
+Arguments:
+
+	Adapter - Supplies which adapter is being processed.
+
+    Irp - Supplies the Irp being processed.
+
+Return Value:
+
+	STATUS_SUCCESS		 - Everything OK.
+
+--*/
+{
+	AAC_STATUS Status;
+	PAFA_CLASS_DRIVER ClassDriver;
+
+
+	ClassDriver = (PAFA_CLASS_DRIVER) OsAllocMemory( sizeof(AFA_CLASS_DRIVER), OS_ALLOC_MEM_SLEEP );
+
+	if (ClassDriver == NULL) {
+
+		Status = STATUS_INSUFFICIENT_RESOURCES;
+
+		return Status;
+	}
+
+	//
+	// If the class driver has sent in user Vars, then copy them into the global
+	// area.
+	//
+
+	if (NewClassDriver->NumUserVars) {
+
+		PFSA_USER_VAR	NewUserVars;
+
+		NewUserVars = OsAllocMemory( (FsaCommData.NumUserVars +
+								   NewClassDriver->NumUserVars) * sizeof(FSA_USER_VAR), OS_ALLOC_MEM_SLEEP );
+
+		//
+		// First copy the existing into the new area.
+		//
+
+		RtlCopyMemory( NewUserVars, FsaCommData.UserVars, FsaCommData.NumUserVars * sizeof(FSA_USER_VAR) );
+
+		//
+		// Next copy the new vars passed in from class driver.
+		//
+
+		RtlCopyMemory( (NewUserVars + FsaCommData.NumUserVars),
+					   NewClassDriver->UserVars,
+					   NewClassDriver->NumUserVars * sizeof(FSA_USER_VAR) );
+
+		//
+		// Free up the old user vars.
+		//
+
+		OsFreeMemory( FsaCommData.UserVars, FsaCommData.NumUserVars * sizeof(FSA_USER_VAR) );
+
+		//
+		// Point the global to the new area.
+		//
+
+		FsaCommData.UserVars = NewUserVars;
+
+		//
+		// Update the total count.
+		//
+
+		FsaCommData.NumUserVars += NewClassDriver->NumUserVars;
+
+	}
+
+	ClassDriver->OpenAdapter = NewClassDriver->OpenAdapter;
+	ClassDriver->CloseAdapter = NewClassDriver->CloseAdapter;
+	ClassDriver->DeviceControl = NewClassDriver->DeviceControl;
+	ClassDriver->HandleAif = NewClassDriver->HandleAif;
+	ClassDriver->ClassDriverExtension = NewClassDriver->ClassDriverExtension;
+
+	ClassDriver->Next = Adapter->ClassDriverList;
+	Adapter->ClassDriverList = ClassDriver;
+
+	//
+	// Now return the information needed by the class driver to communicate to us.
+	//
+
+	NewClassDriverResponse->CommFuncs = &Adapter->CommFuncs;
+	NewClassDriverResponse->CommPortExtension = Adapter;
+	NewClassDriverResponse->MiniPortExtension = Adapter->AdapterExtension;
+	NewClassDriverResponse->SpinLockCookie = Adapter->SpinLockCookie;
+	NewClassDriverResponse->Dip = Adapter->Dip;
+
+	return (STATUS_SUCCESS);
+
+
+}
+
+int
+AfaCommCtlSendFib(
+	IN PAFA_COMM_ADAPTER	Adapter,
+	IN PAFA_IOCTL_CMD		IoctlCmdPtr
+)
+/*++
+
+Routine Description:
+
+	This routine sends a fib to the adapter on behalf of a user level
+	program.
+
+Arguments:
+
+	Adapter - Supplies which adapter is being processed.
+
+	IoctlCmdPtr - Pointer to the arguments to the IOCTL call
+
+Return Value:
+
+	STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer.
+
+	STATUS_INSUFFICIENT_RESOURCES - If a memory allocation failed.
+
+	STATUS_SUCCESS		 - Everything OK.
+
+--*/
+{
+    PFIB KFib;
+//    PMDL DmaMdl = NULL;
+	PCOMM_FIB_CONTEXT FibContext;
+	PSGMAP_CONTEXT SgMapContext;
+	SGMAP_CONTEXT _SgMapContext;
+    QUEUE_TYPES WhichQueue;
+    PVOID UsersAddress;
+	AAC_STATUS Status;
+
+	FibContext = AllocateFib( Adapter );
+
+    KFib = FibContext->Fib;
+
+	//
+	// First copy in the header so that we can check the size field.
+	//
+
+	if (COPYIN( (caddr_t) IoctlCmdPtr->arg, (caddr_t) KFib, sizeof(FIB_HEADER), IoctlCmdPtr->flag )) {
+		FreeFib( FibContext );
+		Status = EFAULT;
+		return (Status);
+	}
+
+	//
+	//	Since we copy based on the fib header size, make sure that we
+	//	will not overrun the buffer when we copy the memory. Return
+	//	an error if we would.
+	//
+
+	if (KFib->Header.Size > sizeof(FIB) - sizeof(FIB_HEADER)) {
+		FreeFib( FibContext );
+		Status = EINVAL;
+		return Status;
+
+	}
+
+	if (COPYIN( (caddr_t) IoctlCmdPtr->arg, (caddr_t) KFib, KFib->Header.Size + sizeof(FIB_HEADER), IoctlCmdPtr->flag )) {
+		FreeFib( FibContext );
+		Status = EFAULT;
+		return (Status);
+	}
+
+    WhichQueue = AdapNormCmdQueue;
+
+
+	if (KFib->Header.Command == TakeABreakPt) {
+
+		InterruptAdapter(Adapter);
+
+		//
+		// Since we didn't really send a fib, zero out the state to allow 
+		// cleanup code not to assert.
+		//
+
+		KFib->Header.XferState = 0;
+
+
+	} else {
+	
+		if (SendFib(KFib->Header.Command, FibContext, KFib->Header.Size , FsaNormal,
+					TRUE, NULL, TRUE, NULL, NULL) != FSA_SUCCESS) {
+	        FsaCommPrint("User SendFib failed!.\n");
+
+
+			FreeFib( FibContext );
+			return (ENXIO);
+		}
+
+	    if (CompleteFib(FibContext) != FSA_SUCCESS) {
+	        FsaCommPrint("User Complete FIB failed.\n");
+
+			FreeFib( FibContext );
+			return (ENXIO);
+		}
+
+
+    }
+
+
+	//
+	//	Make sure that the size returned by the adapter (which includes
+	//	the header) is less than or equal to the size of a fib, so we
+	//	don't corrupt application data. Then copy that size to the user
+	//	buffer. (Don't try to add the header information again, since it
+	//	was already included by the adapter.)
+	//
+    ASSERT(KFib->Header.Size <= sizeof(FIB));
+
+	if (COPYOUT( (caddr_t) KFib, (caddr_t) IoctlCmdPtr->arg, KFib->Header.Size, IoctlCmdPtr->flag )) {
+		FreeFib( FibContext );
+		Status = EFAULT;
+		return (Status);
+	}
+
+	FreeFib( FibContext );
+
+    return (0);
+
+}
+
+int
+AfaCommCtlAifThread(
+	IN PAFA_COMM_ADAPTER	Adapter,
+	IN PAFA_IOCTL_CMD		IoctlCmdPtr
+)
+/*++
+
+Routine Description:
+
+	This routine will act as the AIF thread for this adapter.
+
+Arguments:
+
+	Adapter - Supplies which adapter is being processed.
+
+	IoctlCmdPtr - Pointer to the arguments to the IOCTL call
+
+Return Value:
+
+	STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer.
+
+	STATUS_INSUFFICIENT_RESOURCES - If a memory allocation failed.
+
+	STATUS_SUCCESS		 - Everything OK.
+
+--*/
+{
+	return (NormCommandThread(Adapter));
+}
+
+
+
+#ifdef GATHER_FIB_TIMES
+AAC_STATUS
+AfaCommGetFibTimes(
+	IN PAFA_COMM_ADAPTER	Adapter,
+	IN PIRP					Irp
+	)
+/*++
+
+Routine Description:
+
+	This routine returns the gathered fibtimes to the user.
+
+Arguments:
+
+	Adapter - Supplies which adapter is being processed.
+
+    Irp - Supplies the Irp being processed.
+
+Return Value:
+
+	STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer.
+
+	STATUS_INSUFFICIENT_RESOURCES - If a memory allocation failed.
+
+	STATUS_SUCCESS		 - Everything OK.
+
+--*/
+{
+	PALL_FIB_TIMES AllFibTimes;
+	PLARGE_INTEGER FreqPtr;
+    PIO_STACK_LOCATION IrpSp;
+
+    //
+    //  Get a pointer to the current Irp stack location
+    //
+
+    IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+	FreqPtr = (PLARGE_INTEGER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
+
+	*FreqPtr = Adapter->FibTimesFrequency;
+
+	AllFibTimes = (PALL_FIB_TIMES)((PUCHAR)FreqPtr + sizeof(LARGE_INTEGER));
+
+	RtlCopyMemory(AllFibTimes, Adapter->FibTimes, sizeof(ALL_FIB_TIMES));
+
+	Irp->IoStatus.Information = 0;
+
+	return (STATUS_SUCCESS);
+
+}
+
+AAC_STATUS
+AfaCommZeroFibTimes(
+	IN PAFA_COMM_ADAPTER	Adapter,
+	IN PIRP					Irp
+	)
+/*++
+
+Routine Description:
+
+	This routine zero's the FibTimes structure within the adapter structure.
+
+Arguments:
+
+	Adapter - Supplies which adapter is being processed.
+
+    Irp - Supplies the Irp being processed.
+
+Return Value:
+
+	STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer.
+
+	STATUS_INSUFFICIENT_RESOURCES - If a memory allocation failed.
+
+	STATUS_SUCCESS		 - Everything OK.
+
+--*/
+{
+	PFIB_TIMES FibTimesPtr;
+	int i;
+    PIO_STACK_LOCATION IrpSp;
+
+    //
+    //  Get a pointer to the current Irp stack location
+    //
+
+    IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+	//
+	// Initialize the Fib timing data structures
+	//
+	RtlZeroMemory(Adapter->FibTimes, sizeof(ALL_FIB_TIMES));
+
+	for (i = 0; i < MAX_FSACOMMAND_NUM; i++) {
+
+		FibTimesPtr = &Adapter->FibTimes->FileSys[i];
+
+		FibTimesPtr->Minimum.LowPart = 0xffffffff;
+		FibTimesPtr->Minimum.HighPart = 0x7fffffff;
+		FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff;
+		FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff;
+	}
+	for (i = 0; i < MAX_RW_FIB_TIMES; i++) {
+
+		FibTimesPtr = &Adapter->FibTimes->Read[i];
+
+		FibTimesPtr->Minimum.LowPart = 0xffffffff;
+		FibTimesPtr->Minimum.HighPart = 0x7fffffff;
+		FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff;
+		FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff;
+	}
+	for (i = 0; i < MAX_RW_FIB_TIMES; i++) {
+
+		FibTimesPtr = &Adapter->FibTimes->Write[i];
+
+		FibTimesPtr->Minimum.LowPart = 0xffffffff;
+		FibTimesPtr->Minimum.HighPart = 0x7fffffff;
+		FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff;
+		FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff;
+	}
+
+	FibTimesPtr = &Adapter->FibTimes->Other;
+
+	FibTimesPtr->Minimum.LowPart = 0xffffffff;
+	FibTimesPtr->Minimum.HighPart = 0x7fffffff;
+	FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff;
+	FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff;
+
+	Irp->IoStatus.Information = 0;
+
+	return (STATUS_SUCCESS);
+
+}
+#endif	// GATHER_FIB_TIMES
+
+#ifndef unix_aif
+int
+FsaCtlOpenGetAdapterFib(
+	IN PAFA_COMM_ADAPTER	Adapter,
+	IN PAFA_IOCTL_CMD		IoctlCmdPtr
+	)
+/*++
+
+Routine Description:
+
+    This routine will get the next Fib, if available, from the AdapterFibContext
+	passed in from the user.
+
+Arguments:
+
+	Adapter - Supplies which adapter is being processed.
+
+    Irp - Supplies the Irp being processed.
+
+Return Value:
+
+	STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer.
+
+	STATUS_INSUFFICIENT_RESOURCES - If a memory allocation failed.
+
+	STATUS_SUCCESS		 - Everything OK.
+
+--*/
+{
+	PGET_ADAPTER_FIB_CONTEXT AdapterFibContext;
+//	HANDLE Event;
+//    PKEVENT eventObject = (PKEVENT) NULL;
+	int Status;
+
+	//
+	// The context must be allocated from NonPagedPool because we need to use MmIsAddressValid.
+	//
+
+	AdapterFibContext = OsAllocMemory(sizeof(GET_ADAPTER_FIB_CONTEXT), OS_ALLOC_MEM_SLEEP);
+
+	if (AdapterFibContext == NULL) {
+
+		Status = ENOMEM;
+
+	} else {
+
+		AdapterFibContext->NodeTypeCode = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT;
+		AdapterFibContext->NodeByteSize = sizeof(GET_ADAPTER_FIB_CONTEXT);
+
+
+		//
+		// Initialize the conditional variable use to wait for the next AIF.
+		//
+
+		OsCv_init( &AdapterFibContext->UserEvent);
+
+		//
+		// Set WaitingForFib to FALSE to indicate we are not in a WaitForSingleObject
+		//
+
+		AdapterFibContext->WaitingForFib = FALSE;
+
+		//
+		// Initialize the FibList and set the count of fibs on the list to 0.
+		//
+
+		AdapterFibContext->FibCount = 0;
+		InitializeListHead(&AdapterFibContext->FibList);
+
+		//
+		// Now add this context onto the adapter's AdapterFibContext list.
+		//
+
+		OsCvLockAcquire(Adapter->AdapterFibMutex);
+
+		InsertTailList(&Adapter->AdapterFibContextList, &AdapterFibContext->NextContext);
+
+		OsCvLockRelease(Adapter->AdapterFibMutex);
+
+		if (COPYOUT( &AdapterFibContext, (caddr_t) IoctlCmdPtr->arg, sizeof(PGET_ADAPTER_FIB_CONTEXT), 
+						 IoctlCmdPtr->flag )) {
+
+			Status = EFAULT;
+			
+		} else {
+		
+			Status = 0;
+
+		}	
+
+	}
+
+	return (Status);
+}
+
+int
+FsaCtlGetNextAdapterFib(
+	IN PAFA_COMM_ADAPTER	Adapter,
+	IN PAFA_IOCTL_CMD		IoctlCmdPtr
+	)
+/*++
+
+Routine Description:
+
+    This routine will get the next Fib, if available, from the AdapterFibContext
+	passed in from the user.
+
+Arguments:
+
+	Adapter - Supplies which adapter is being processed.
+
+    Irp - Supplies the Irp being processed.
+
+Return Value:
+
+	STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer.
+
+	STATUS_NO_MORE_ENTRIES - There are no more Fibs for this AdapterFibContext.
+
+	STATUS_SUCCESS		 - Everything OK.
+
+--*/
+{
+	GET_ADAPTER_FIB_IOCTL AdapterFibIoctl;
+	PGET_ADAPTER_FIB_CONTEXT AdapterFibContext;
+	PFIB Fib;
+	int Status;
+
+	if (COPYIN( (caddr_t) IoctlCmdPtr->arg, (caddr_t) &AdapterFibIoctl,
+					sizeof(GET_ADAPTER_FIB_IOCTL), IoctlCmdPtr->flag )) {
+		return (EFAULT);
+	}
+
+	//
+	// Extract the AdapterFibContext from the Input parameters.
+	//
+
+	AdapterFibContext = (PGET_ADAPTER_FIB_CONTEXT) AdapterFibIoctl.AdapterFibContext;
+
+	//
+	// Verify that the HANDLE passed in was a valid AdapterFibContext
+	//
+	// rpbfix : determine if there is a way to validate the AdapterFibContext address.
+	//
+
+	if ( (AdapterFibContext->NodeTypeCode != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) ||
+		 (AdapterFibContext->NodeByteSize != sizeof(GET_ADAPTER_FIB_CONTEXT)) ) {
+
+		return ( EINVAL );
+
+	}
+
+	Status = STATUS_SUCCESS;
+
+	OsCvLockAcquire(Adapter->AdapterFibMutex);
+
+	//
+	// If there are no fibs to send back, then either wait or return EAGAIN
+	//
+return_fib:
+
+	if (!IsListEmpty(&AdapterFibContext->FibList)) {
+
+		PLIST_ENTRY Entry;
+
+		//
+		// Pull the next fib from the FibList
+		//
+		Entry = RemoveHeadList(&AdapterFibContext->FibList);
+
+		Fib = CONTAINING_RECORD( Entry, FIB, Header.FibLinks );
+
+		AdapterFibContext->FibCount--;
+
+		if (COPYOUT( Fib, AdapterFibIoctl.AifFib, sizeof(FIB), IoctlCmdPtr->flag )) {
+
+			OsCvLockRelease( Adapter->AdapterFibMutex );
+			OsFreeMemory( Fib, sizeof(Fib) );
+			return (EFAULT);
+
+		}	
+
+		//
+		// Free the space occupied by this copy of the fib.
+		//
+
+		OsFreeMemory(Fib, sizeof(FIB));
+
+        Status = 0;
+
+	} else {
+
+		if (AdapterFibIoctl.Wait) {
+			
+			if (OsCv_wait_sig( &AdapterFibContext->UserEvent, Adapter->AdapterFibMutex ) == 0) {
+
+				Status = EINTR;
+
+			} else {
+			
+				goto return_fib;
+				
+			}
+		} else {
+					
+			Status = EAGAIN;
+
+		}	
+
+	}
+	OsCvLockRelease( Adapter->AdapterFibMutex );
+
+	return (Status);
+}
+
+int
+FsaCtlCloseGetAdapterFib(
+	IN PAFA_COMM_ADAPTER	Adapter,
+	IN PAFA_IOCTL_CMD		IoctlCmdPtr
+	)
+/*++
+
+Routine Description:
+
+    This routine will close down the AdapterFibContext passed in from the user.
+
+Arguments:
+
+	Adapter - Supplies which adapter is being processed.
+
+    Irp - Supplies the Irp being processed.
+
+Return Value:
+
+	STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer.
+
+	STATUS_SUCCESS		 - Everything OK.
+
+--*/
+{
+	PGET_ADAPTER_FIB_CONTEXT AdapterFibContext;
+	AAC_STATUS Status;
+
+	//
+	// Extract the AdapterFibContext from the Input parameters
+	//
+
+	AdapterFibContext = (PGET_ADAPTER_FIB_CONTEXT) IoctlCmdPtr->arg;
+
+	if (AdapterFibContext == 0) {
+		cmn_err(CE_WARN, "FsaCtlCloseGetAdapterFib: AdapterFibContext is NULL");
+		return(EINVAL);
+	}
+
+	//
+	// Verify that the HANDLE passed in was a valid AdapterFibContext
+	//
+	//	rpbfix : verify pointer sent in from user.
+	//
+
+	if ( (AdapterFibContext->NodeTypeCode != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) ||
+		 (AdapterFibContext->NodeByteSize != sizeof(GET_ADAPTER_FIB_CONTEXT)) ) {
+
+		return (EINVAL);
+
+	}
+
+	OsCvLockAcquire(Adapter->AdapterFibMutex);
+
+	Status = FsaCloseAdapterFibContext(Adapter, AdapterFibContext);
+
+	OsCvLockRelease(Adapter->AdapterFibMutex);
+
+	return (Status);
+}
+
+int
+FsaCloseAdapterFibContext(
+	IN PAFA_COMM_ADAPTER			Adapter,
+	IN PGET_ADAPTER_FIB_CONTEXT		AdapterFibContext
+	)
+{
+	int Status;
+	PFIB Fib;
+
+	//
+	// First free any FIBs that have not been consumed yet.
+	//
+
+	while (!IsListEmpty(&AdapterFibContext->FibList)) {
+
+		PLIST_ENTRY Entry;
+
+		//
+		// Pull the next fib from the FibList
+		//
+
+		Entry = RemoveHeadList(&AdapterFibContext->FibList);
+
+		Fib = CONTAINING_RECORD( Entry, FIB, Header.FibLinks );
+
+		AdapterFibContext->FibCount--;
+
+		//
+		// Free the space occupied by this copy of the fib.
+		//
+
+		OsFreeMemory(Fib, sizeof(FIB));
+	}
+
+	//
+	// Remove the Context from the AdapterFibContext List
+	//
+
+	RemoveEntryList(&AdapterFibContext->NextContext);
+
+	OsCv_destroy( &AdapterFibContext->UserEvent );
+
+	//
+	// Invalidate context
+	//
+
+	AdapterFibContext->NodeTypeCode = 0;
+
+	//
+	// Free the space occupied by the Context
+	//
+
+	OsFreeMemory(AdapterFibContext, sizeof(GET_ADAPTER_FIB_CONTEXT));
+
+	Status = STATUS_SUCCESS;
+
+    return Status;
+}
+#endif 
+
+AAC_STATUS
+AfaCommOpenAdapter(
+	IN PVOID Arg
+	)
+/*++
+
+Routine Description:
+
+	The routine will get called by the miniport each time a user issues a CreateFile on the DeviceObject
+	for the adapter.
+
+	The main purpose of this routine is to set up any data structures that may be needed
+	to handle any requests made on this DeviceObject.
+
+Arguments:
+
+	Adapter - Pointer to which adapter miniport was opened.
+
+
+Return Value:
+
+	STATUS_SUCCESS
+
+--*/
+
+{
+	PAFA_COMM_ADAPTER	Adapter = (PAFA_COMM_ADAPTER) Arg;
+	AAC_STATUS Status = STATUS_SUCCESS;
+	PAFA_CLASS_DRIVER ClassDriver;
+
+	ClassDriver = Adapter->ClassDriverList;
+
+	while (ClassDriver) {
+
+		if (ClassDriver->OpenAdapter) {
+
+			Status = ClassDriver->OpenAdapter( ClassDriver->ClassDriverExtension );
+
+			if (Status != STATUS_SUCCESS)
+				break;
+		}
+
+		ClassDriver = ClassDriver->Next;
+	}
+
+	return ( Status );
+}
+
+AAC_STATUS
+AfaCommCloseAdapter(
+	IN PVOID Arg
+	)
+/*++
+
+Routine Description:
+
+	This routine will get called by the miniport each time a user issues a CloseHandle on the DeviceObject
+	for the adapter.
+
+	The main purpose of this routine is to cleanup any data structures that have been set up
+	while this FileObject has been opened.
+
+	This routine loops through all of the AdapterFibContext structures to determine if any need
+	to be deleted for this FileObject.
+
+Arguments:
+
+	Adapter - Pointer to adapter miniport
+
+	Irp - Pointer to Irp that caused this close
+
+Return Value:
+
+	Status value returned from File system driver AdapterClose
+
+--*/
+{
+	PAFA_COMM_ADAPTER	Adapter = (PAFA_COMM_ADAPTER) Arg;
+	PLIST_ENTRY Entry, NextEntry;
+	PGET_ADAPTER_FIB_CONTEXT AdapterFibContext;
+	AAC_STATUS Status = STATUS_SUCCESS;
+	PAFA_CLASS_DRIVER ClassDriver;
+
+	OsCvLockAcquire(Adapter->AdapterFibMutex);
+
+	Entry = Adapter->AdapterFibContextList.Flink;
+
+	//
+	// Loop through all of the AdapterFibContext, looking for any that
+	// were created with the FileObject that is being closed.
+	//
+	while (Entry != &Adapter->AdapterFibContextList) {
+
+		//
+		// Extract the AdapterFibContext
+		//
+		AdapterFibContext = CONTAINING_RECORD( Entry, GET_ADAPTER_FIB_CONTEXT, NextContext );
+
+		// 
+		// Save the next entry because CloseAdapterFibContext will delete the AdapterFibContext
+		//
+		NextEntry = Entry->Flink;
+
+		Entry = NextEntry;
+
+	}
+
+#ifdef unix_config_file
+	//
+	// If this FileObject had the adapter open for configuration, then release it.
+	//
+	if ( Adapter->AdapterConfigFileObject == IrpSp->FileObject ) {
+
+		Adapter->AdapterConfigFileObject = NULL;
+
+	}
+#endif
+
+	OsCvLockRelease(Adapter->AdapterFibMutex);
+
+	ClassDriver = Adapter->ClassDriverList;
+
+	while (ClassDriver) {
+
+		if (ClassDriver->CloseAdapter) {
+
+			Status = ClassDriver->CloseAdapter( ClassDriver->ClassDriverExtension );
+
+			if (Status != STATUS_SUCCESS)
+				break;
+		}
+
+		ClassDriver = ClassDriver->Next;
+	}
+
+	return ( Status );
+
+}
+
diff -BburN linux.orig/drivers/scsi/aacraid/comminit.c linux/drivers/scsi/aacraid/comminit.c
--- linux.orig/drivers/scsi/aacraid/comminit.c	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/comminit.c	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,1263 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  comminit.c
+ *
+ * Abstract: This supports the initialization of the host adapter commuication interface.
+ *    This is a platform dependent module for the pci cyclone board.
+ *
+ --*/
+#include "comprocs.h"
+
+#define BugCheckFileId                   (FSAFS_BUG_CHECK_COMMINIT)
+
+VOID
+AfaCommBugcheckHandler(
+		IN PVOID Buffer,
+		IN ULONG Length
+		);
+
+VOID
+ThrottlePeriodEndDpcRtn(
+	IN PKDPC Dpc,
+	IN PVOID DeferredContext,
+	IN PVOID SystemArgument1,
+	IN PVOID SystemArgument2);
+
+FSA_COMM_DATA FsaCommData;
+
+AAC_STATUS
+HardInterruptModeration1Changed(
+	IN PVOID AdapterContext,
+	IN ULONG NewValue
+	)
+{
+	PAFA_COMM_ADAPTER Adapter = AdapterContext;
+
+	//
+	// If we are using interrupt moderation, then disable the interrupt
+	// until we need to use it.
+	//
+	if (FsaCommData.HardInterruptModeration1)
+		DisableInterrupt( Adapter, AdapNormCmdNotFull, FALSE );
+	else
+		EnableInterrupt( Adapter, AdapNormCmdNotFull, FALSE );
+
+	return (STATUS_SUCCESS);
+}
+
+AAC_STATUS
+FsaFibTimeoutChanged(
+	IN PVOID AdapterContext,
+	IN ULONG NewValue
+	)
+{
+	//
+	// scale the new timeout from seconds to 100 nsec units
+	//
+//	FsaCommData.AdapterTimeout = RtlConvertLongToLargeInteger(-10*1000*1000*NewValue);
+
+	return (STATUS_SUCCESS);
+}
+
+#ifdef GATHER_FIB_TIMES
+extern int GatherFibTimes;
+#endif
+
+FSA_USER_VAR FsaCommUserVars[] = {
+#ifdef FIB_CHECKSUMS
+    { "do_fib_checksums", (PULONG)&FsaCommData.do_fib_checksums, NULL },
+#endif
+#ifdef GATHER_FIB_TIMES
+	{ "GatherFibTimes", (PULONG)&GatherFibTimes, NULL },
+#endif
+	{ "EnableAdapterTimeouts", (PULONG)&FsaCommData.EnableAdapterTimeouts, NULL},
+	{ "EnableInterruptModeration", (PULONG)&FsaCommData.EnableInterruptModeration, NULL },
+	{ "FsaDataFibsSent", (PULONG) &FsaCommData.FibsSent, NULL },
+	{ "FsaDataFibRecved", (PULONG) &FsaCommData.FibRecved, NULL },
+	{ "HardInterruptModeration", (PULONG)&FsaCommData.HardInterruptModeration, NULL},
+	{ "HardInterruptModeration1", (PULONG)&FsaCommData.HardInterruptModeration1, HardInterruptModeration1Changed},
+	{ "EnableFibTimeoutBreak", (PULONG)&FsaCommData.EnableFibTimeoutBreak, NULL},
+	{ "PeakFibsConsumed", (PULONG)&FsaCommData.PeakFibsConsumed, NULL },
+	{ "ZeroFibsConsumed", (PULONG)&FsaCommData.ZeroFibsConsumed, NULL },
+	{ "FibTimeoutSeconds", (PULONG) &FsaCommData.FibTimeoutSeconds, FsaFibTimeoutChanged },
+};
+
+#define NUM_COMM_USER_VARS	(sizeof(FsaCommUserVars) / sizeof(FSA_USER_VAR) )
+
+
+AAC_STATUS
+AacCommDriverEntry(
+    )
+
+/*++
+
+Routine Description:
+
+    This is the initialization routine for the FileArray Comm layer device driver.
+
+Arguments:
+
+    DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+    AAC_STATUS - The function value is the final status from the initialization
+        operation.
+
+--*/
+
+{
+    AAC_STATUS Status;
+	PVOID BugCheckBuffer;
+
+	RtlZeroMemory( &FsaCommData, sizeof(FSA_COMM_DATA) );
+
+
+    //
+    // Load the global timeout value for the adapter timeout
+    // Also init the global that enables or disables adapter timeouts
+    //
+
+//	FsaCommData.AdapterTimeout = RtlConvertLongToLargeInteger(-10*1000*1000*180);
+
+	FsaCommData.FibTimeoutSeconds = 180;
+
+	FsaCommData.EnableAdapterTimeouts = TRUE; 
+
+//	FsaCommData.QueueFreeTimeout = RtlConvertLongToLargeInteger(QUEUE_ENTRY_FREE_TIMEOUT);
+
+#ifdef unix_fib_timeout
+	FsaCommData.FibTimeoutIncrement = (180 * 1000 * 1000 * 10) / KeQueryTimeIncrement();
+#endif
+
+	FsaCommData.EnableInterruptModeration = FALSE;
+
+	//
+	// Preload UserVars with all variables from the comm layer.  The class layers will
+	// include theirs when they register.
+	//
+
+	FsaCommData.UserVars = OsAllocMemory(NUM_COMM_USER_VARS * sizeof(FSA_USER_VAR), OS_ALLOC_MEM_SLEEP );
+	FsaCommData.NumUserVars = NUM_COMM_USER_VARS;
+
+	RtlCopyMemory( FsaCommData.UserVars, &FsaCommUserVars, NUM_COMM_USER_VARS * sizeof(FSA_USER_VAR) );
+
+
+#ifdef AACDISK
+	//
+	// Call the disk driver to initialize itself.
+	//
+
+	AacDiskDriverEntry();
+
+#endif
+
+
+
+	return (STATUS_SUCCESS);
+}
+
+
+VOID
+DetachNTQueue(
+	IN PAFA_COMM_ADAPTER Adapter,
+    IN OUT PCOMM_QUE Queue,
+    IN QUEUE_TYPES WhichQueue
+    )
+/*++
+
+Routine Description:
+
+	This routine will release all of the resources used by a given queue.
+
+Arguments:
+
+	Adapter - Which adapter the queue belongs to
+	Queue - Pointer to the queue itself
+	WhichQueue - Identifies which of the host queues this is.
+
+Return Value:
+
+	NONE.
+
+--*/
+{
+    switch (WhichQueue) {
+
+        case HostNormCmdQueue:
+
+			Os_remove_softintr( Queue->ConsumerRoutine );
+			OsSpinLockDestroy( Queue->QueueLock );
+			OsCv_destroy( &Queue->CommandReady );
+				
+            break;
+
+        case HostHighCmdQueue:
+
+			Os_remove_softintr( Queue->ConsumerRoutine );
+			OsSpinLockDestroy( Queue->QueueLock );
+			OsCv_destroy( &Queue->CommandReady );
+				
+            break;
+
+        case HostNormRespQueue:
+
+			Os_remove_softintr( Queue->ConsumerRoutine );
+			OsSpinLockDestroy( Queue->QueueLock );
+            break;
+
+        case HostHighRespQueue:
+
+			Os_remove_softintr( Queue->ConsumerRoutine );
+			OsSpinLockDestroy( Queue->QueueLock );
+            break;
+
+        case AdapNormCmdQueue:
+        case AdapHighCmdQueue:
+        case AdapNormRespQueue:
+        case AdapHighRespQueue:
+			OsCv_destroy( &Queue->QueueFull );
+            break;
+    }
+}
+    
+VOID
+InitializeNTQueue(
+	IN PAFA_COMM_ADAPTER Adapter,
+    IN OUT PCOMM_QUE Queue,
+    IN QUEUE_TYPES WhichQueue
+    )
+/*++
+
+Routine Description:
+
+    Will initialize all entries in the queue that is NT specific.
+
+Arguments:
+
+Return Value:
+
+    Nothing there is nothing to allocate so nothing should fail
+
+--*/
+{
+    
+	Queue->NumOutstandingIos = 0;
+
+	//
+	// Store a pointer to the adapter structure.
+	//
+
+	Queue->Adapter = Adapter;
+
+	InitializeListHead( &Queue->OutstandingIoQueue );
+	    
+    switch (WhichQueue) {
+
+        case HostNormCmdQueue:
+
+			OsCv_init( &Queue->CommandReady);
+			OsSpinLockInit( Queue->QueueLock, Adapter->SpinLockCookie);
+			if (ddi_add_softintr( Adapter->Dip, DDI_SOFTINT_HIGH, &Queue->ConsumerRoutine, NULL,
+								  NULL, (PUNIX_INTR_HANDLER)HostCommandNormDpc,
+								  (caddr_t)Queue ) != DDI_SUCCESS) {
+
+				cmn_err(CE_CONT, "OS_addr_intr failed\n");					
+			}					
+
+            InitializeListHead(&Queue->CommandQueue);
+
+            break;
+
+        case HostHighCmdQueue:
+
+			OsCv_init( &Queue->CommandReady);
+			OsSpinLockInit( Queue->QueueLock, Adapter->SpinLockCookie);
+			if (ddi_add_softintr( Adapter->Dip, DDI_SOFTINT_HIGH, &Queue->ConsumerRoutine, NULL,
+								  NULL, (PUNIX_INTR_HANDLER)HostCommandHighDpc,
+								  (caddr_t) Queue ) != DDI_SUCCESS) {
+
+				cmn_err(CE_CONT, "OS_addr_intr failed\n");					
+			}					
+
+            InitializeListHead(&Queue->CommandQueue);
+            break;
+
+        case HostNormRespQueue:
+
+			OsSpinLockInit( Queue->QueueLock, Adapter->SpinLockCookie);
+			if (ddi_add_softintr( Adapter->Dip, DDI_SOFTINT_HIGH, &Queue->ConsumerRoutine, NULL,
+								  NULL, (PUNIX_INTR_HANDLER)HostResponseNormalDpc, 
+								  (caddr_t) Queue ) != DDI_SUCCESS) {
+
+				cmn_err(CE_CONT, "OS_addr_intr failed\n");					
+			}					
+            break;
+
+        case HostHighRespQueue:
+
+
+			OsSpinLockInit( Queue->QueueLock, Adapter->SpinLockCookie);
+			if (ddi_add_softintr( Adapter->Dip, DDI_SOFTINT_HIGH, &Queue->ConsumerRoutine, NULL,
+								  NULL, (PUNIX_INTR_HANDLER)HostResponseHighDpc, 
+								  (caddr_t) Queue ) != DDI_SUCCESS) {
+
+				cmn_err(CE_CONT, "OS_addr_intr failed\n");					
+			}					
+            break;
+
+        case AdapNormCmdQueue:
+        case AdapHighCmdQueue:
+        case AdapNormRespQueue:
+        case AdapHighRespQueue:
+
+			OsCv_init( &Queue->QueueFull);
+            break;
+    }
+}
+
+BOOLEAN
+StartFsaCommandThreads(PAFA_COMM_ADAPTER Adapter)
+/*++
+
+Routine Description:
+
+    Create and start the command receiver threads.
+
+Arguments:
+
+
+Return Value:
+
+    Nothing
+
+--*/
+
+{
+    return(TRUE);
+}
+
+VOID
+AfaCommTimeoutFib(
+	PAFA_COMM_ADAPTER	Adapter,
+	PCOMM_FIB_CONTEXT	FibContext
+	)
+/*++
+
+Routine Description:
+
+	This routine will do all of the work necessary to timeout the given fib.
+
+Arguments:
+
+	Adapter - Pointer to an adapter structure.
+
+	FibContext - Pointer to the context to time out.
+
+Return Value:
+
+    Nothing.
+
+--*/
+{
+	PFIB Fib = FibContext->Fib;
+
+
+#ifdef unix_fib_timeout
+	if (Fib->Header.XferState & Async) {
+
+		FibContext->FibCallback(FibContext->FibCallbackContext, FibContext, STATUS_IO_TIMEOUT);
+
+	} else {
+
+		KeSetEvent(&FibContext->FsaEvent, 0, FALSE);
+
+	}
+#endif
+}
+
+VOID
+AfaCommTimeoutRoutine(
+	PKDPC	Dpc,
+	PVOID	NullArgument,
+	PVOID	Argument1,
+	PVOID	Argument2
+	)
+/*++
+
+Routine Description:
+
+	This DPC routine is executed by the expiration of a periodic timer.  The purpose of this routine
+	is to check for fib's that should be timed out.
+
+Arguments:
+
+    Dpc - Pointer to this routine.
+
+
+Return Value:
+
+    Nothing.
+
+--*/
+{
+#ifdef unix_fib_timeout
+	PCOMM_QUE OurQueue;
+	PLIST_ENTRY Entry, NextEntry;
+	LIST_ENTRY TimeoutQueue;
+	PCOMM_FIB_CONTEXT FibContext;
+	LARGE_INTEGER TickCount;
+	PAFA_COMM_ADAPTER Adapter;
+
+	Adapter = FsaCommData.AdapterList;
+
+	while (Adapter) {
+
+		InitializeListHead( &TimeoutQueue );
+
+		OurQueue = &Adapter->CommRegion->AdapNormCmdQue;
+
+	//	DbgPrint("AfaCommTimeoutRoutine called, outstanding fibs = %d\n", OurQueue->NumOutstandingIos);
+
+//		KeAcquireSpinLockAtDpcLevel( OurQueue->QueueLock );
+		OsSpinLockAcquire( OurQueue->QueueLock );
+
+		KeQueryTickCount(&TickCount);
+
+		Entry = OurQueue->OutstandingIoQueue.Flink;
+
+		while (Entry != &OurQueue->OutstandingIoQueue) {
+
+			FibContext = CONTAINING_RECORD( Entry, COMM_FIB_CONTEXT, QueueEntry );
+
+			//
+			// If the current tick count if less than the first fib on the queue, then
+			// none of the fib's have timed out.
+			//
+
+			if (TickCount.QuadPart <= FibContext->TimeoutValue.QuadPart) {
+
+				break;
+
+			}	
+
+			//
+			// First, grab the next entry, then put this entry onto the queue to be timed out.
+			//
+
+			NextEntry = Entry->Flink;
+
+			//
+			// Mark the FibContext as timed out while we have the SpinLock.
+			//
+
+			FibContext = CONTAINING_RECORD( Entry, COMM_FIB_CONTEXT, QueueEntry );
+
+			FibContext->Flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
+			FibContext->Fib->Header.XferState |= TimedOut;
+
+			RemoveEntryList( Entry );
+			OurQueue->NumOutstandingIos--;	
+
+			InsertTailList( &TimeoutQueue, Entry );	
+
+			
+			Entry = NextEntry;
+
+		}
+			
+//		KeReleaseSpinLockFromDpcLevel( OurQueue->QueueLock );
+		OsSpinLockRelease( OurQueue->QueueLock );
+
+		//
+		// Now walk through all fibs that need to be timed out.
+		//
+
+		while (!IsListEmpty( &TimeoutQueue )) {
+
+			Entry = RemoveHeadList( &TimeoutQueue );
+
+			FibContext = CONTAINING_RECORD( Entry, COMM_FIB_CONTEXT, QueueEntry );
+
+			AfaCommTimeoutFib( Adapter, FibContext );
+
+		}
+
+		Adapter = Adapter->NextAdapter;
+	}
+#endif
+}
+
+BOOLEAN
+AacCommDetachAdapter(
+	IN PAFA_COMM_ADAPTER	Adapter
+	)
+/*++
+
+Routine Description:
+
+	This routine gets called to detach all resources that have been allocated for 
+	this adapter.
+
+Arguments:
+
+	Adapter - Pointer to the adapter structure to detach.
+
+Return Value:
+
+    TRUE - All resources have been properly released.
+    FALSE - An error occured while trying to release resources.
+--*/
+{
+	PAFA_CLASS_DRIVER ClassDriver;
+	//
+	// First remove this adapter from the list of adapters.
+	//
+
+	if (FsaCommData.AdapterList == Adapter) {
+		
+		FsaCommData.AdapterList = Adapter->NextAdapter;
+
+	} else {
+
+		PAFA_COMM_ADAPTER CurrentAdapter, NextAdapter;
+	
+		CurrentAdapter = FsaCommData.AdapterList;
+		NextAdapter = CurrentAdapter->NextAdapter;
+
+		while (NextAdapter) {
+				
+			if (NextAdapter == Adapter) {
+
+				CurrentAdapter->NextAdapter = NextAdapter->NextAdapter;
+				break;
+			 
+			}
+			
+			CurrentAdapter = NextAdapter;
+			NextAdapter = CurrentAdapter->NextAdapter;
+		}
+	}			
+		
+	//
+	// First send a shutdown to the adapter.
+	//
+
+	AfaCommShutdown( Adapter );
+
+	//
+	// Destroy the FibContextZone for this adapter.  This will free up all
+	// of the fib space used by this adapter.
+	//
+	
+	FsaFreeFibContextZone( Adapter );
+
+	//
+	// Destroy the mutex used for synch'ing adapter fibs.
+	//
+
+	OsCvLockDestroy( Adapter->AdapterFibMutex );
+
+	//
+	// Detach all of the host queues.
+	//
+
+    DetachNTQueue( Adapter, &Adapter->CommRegion->AdapHighRespQue, AdapHighRespQueue );
+    DetachNTQueue( Adapter, &Adapter->CommRegion->AdapNormRespQue, AdapNormRespQueue );
+    DetachNTQueue( Adapter, &Adapter->CommRegion->HostHighRespQue, HostHighRespQueue );
+    DetachNTQueue( Adapter, &Adapter->CommRegion->HostNormRespQue, HostNormRespQueue );
+    DetachNTQueue( Adapter, &Adapter->CommRegion->AdapHighCmdQue, AdapHighCmdQueue );
+    DetachNTQueue( Adapter, &Adapter->CommRegion->AdapNormCmdQue, AdapNormCmdQueue );
+    DetachNTQueue( Adapter, &Adapter->CommRegion->HostHighCmdQue, HostHighCmdQueue );
+	DetachNTQueue( Adapter, &Adapter->CommRegion->HostNormCmdQue, HostNormCmdQueue );
+
+	//
+	// Destroy the mutex used to protect the FibContextZone
+	//
+
+	OsSpinLockDestroy( Adapter->FibContextZoneSpinLock );
+
+	//
+	// Call the miniport to free the space allocated for the shared comm queues
+	// between the host and the adapter.
+	//
+
+	FsaFreeAdapterCommArea( Adapter );
+
+	//
+	// Free the memory used by the comm region for this adapter
+	//
+
+	OsFreeMemory( Adapter->CommRegion, sizeof(COMM_REGION) );
+
+	//
+	// Free the memory used by the adapter structure.
+	//
+	ClassDriver = Adapter->ClassDriverList;
+	Adapter->ClassDriverList = Adapter->ClassDriverList->Next;
+	OsFreeMemory( ClassDriver, sizeof(AFA_CLASS_DRIVER) );
+	
+	OsFreeMemory( Adapter, sizeof(AFA_COMM_ADAPTER) );
+
+	return (TRUE);
+}
+
+PVOID
+AfaCommInitNewAdapter(
+	IN PFSA_NEW_ADAPTER NewAdapter
+	)
+{
+	PVOID BugCheckBuffer;
+	PAFA_COMM_ADAPTER Adapter;
+	MAPFIB_CONTEXT MapFibContext;
+	LARGE_INTEGER Time;
+	char ErrorBuffer[60];
+
+//	Adapter = (PAFA_COMM_ADAPTER)ExAllocatePool(NonPagedPoolMustSucceed, sizeof(AFA_COMM_ADAPTER));
+	Adapter = (PAFA_COMM_ADAPTER) OsAllocMemory( sizeof(AFA_COMM_ADAPTER) , OS_ALLOC_MEM_SLEEP );
+
+	if (Adapter == NULL)
+		return (NULL);
+
+	RtlZeroMemory(Adapter, sizeof(AFA_COMM_ADAPTER));
+
+
+	//
+	// Save the current adapter number and increment the total number.
+	//
+
+	Adapter->AdapterNumber = FsaCommData.TotalAdapters++;
+
+
+	//
+	// Fill in the pointer back to the device specific structures.
+	// The device specific driver has also passed a pointer for us to 
+	// fill in with the Adapter object that we have created.
+	//
+
+	Adapter->AdapterExtension = NewAdapter->AdapterExtension;
+	Adapter->AdapterFuncs = NewAdapter->AdapterFuncs;
+	Adapter->InterruptsBelowDpc = NewAdapter->AdapterInterruptsBelowDpc;
+	Adapter->AdapterUserVars = NewAdapter->AdapterUserVars;
+	Adapter->AdapterUserVarsSize = NewAdapter->AdapterUserVarsSize;
+
+	Adapter->Dip = NewAdapter->Dip;
+
+	//
+	// Fill in Our address into the function dispatch table
+	//
+
+	NewAdapter->AdapterFuncs->InterruptHost = AfaCommInterruptHost;
+	NewAdapter->AdapterFuncs->OpenAdapter = AfaCommOpenAdapter;
+	NewAdapter->AdapterFuncs->CloseAdapter = AfaCommCloseAdapter;
+	NewAdapter->AdapterFuncs->DeviceControl = AfaCommAdapterDeviceControl;
+
+	//
+	// Ok now init the communication subsystem
+	//
+
+	Adapter->CommRegion = (PCOMM_REGION) OsAllocMemory(sizeof(COMM_REGION), OS_ALLOC_MEM_SLEEP);
+	if (Adapter->CommRegion == NULL) {
+		cmn_err(CE_WARN, "Error could not allocate comm region.\n");
+		return (NULL);
+	}
+	RtlZeroMemory(Adapter->CommRegion, sizeof(COMM_REGION));
+
+	//
+	// Get a pointer to the iblock_cookie
+	//
+
+	ddi_get_soft_iblock_cookie( Adapter->Dip, DDI_SOFTINT_HIGH, &Adapter->SpinLockCookie );
+
+	if (!CommInit(Adapter)) {
+		FsaCommPrint("Failed to init the commuication subsystem.\n");
+		return(NULL);
+	}
+
+
+#ifdef unix_fib_timeout
+	//
+	// If this is the first adapter, then start the timeout routine timer.
+	//
+
+	if (Adapter->AdapterNumber == 0) {
+
+		//
+		// Initialize the DPC used to check for Fib timeouts.
+		//
+
+		KeInitializeDpc( &FsaCommData.TimeoutDPC, AfaCommTimeoutRoutine, NULL );
+
+		//
+		// Initialize the Timer used to check for Fib Timeouts.
+		//
+
+		KeInitializeTimer( &FsaCommData.TimeoutTimer );
+
+		//
+		// Set the timer to go off every 15 seconds.
+		//
+
+		Time.QuadPart = - (15 * 10 * 1000 * 1000);
+
+		KeSetTimerEx( &FsaCommData.TimeoutTimer, Time, (15 * 1000), &FsaCommData.TimeoutDPC );
+
+	}	
+#endif
+
+
+	//
+	// Initialize the list of AdapterFibContext's.
+	//
+
+	InitializeListHead(&Adapter->AdapterFibContextList);
+
+	//
+	// Initialize the fast mutex used for synchronization of the adapter fibs
+	//
+
+	Adapter->AdapterFibMutex = OsCvLockAlloc();
+	OsCvLockInit(Adapter->AdapterFibMutex, NULL);
+
+    //
+    // Allocate and start the FSA command threads. These threads will handle
+    // command requests from the adapter. They will wait on an event then pull
+    // all CDBs off the thread's queue. Each CDB will be given to a worker thread
+    // upto a defined limit. When that limit is reached wait a event will be waited
+    // on till a worker thread is finished.
+    //
+
+    if (!StartFsaCommandThreads(Adapter)) {
+   	    FsaCommPrint("Fsainit could not initilize the command receiver threads.\n");
+		return (NULL);
+    }
+
+#ifdef unix_crash_dump
+	//
+	// Allocate and map a fib for use by the synch path, which is used for crash
+	// dumps.
+	//
+	// Allocate an entire page so that alignment is correct.
+	//
+
+	Adapter->SyncFib = OsAllocMemory( PAGE_SIZE, OS_ALLOC_MEM_SLEEP );
+	MapFibContext.Fib = Adapter->SyncFib;
+	MapFibContext.Size = sizeof(FIB);
+	MapFib( Adapter, &MapFibContext );
+	Adapter->SyncFibPhysicalAddress = MapFibContext.LogicalFibAddress.LowPart;
+#endif
+
+	Adapter->CommFuncs.SizeOfAfaCommFuncs = sizeof(AFACOMM_FUNCS);
+
+	Adapter->CommFuncs.AllocateFib = AllocateFib;
+
+	Adapter->CommFuncs.FreeFib = FreeFib;
+	Adapter->CommFuncs.FreeFibFromDpc = FreeFibFromDpc;
+	Adapter->CommFuncs.DeallocateFib = DeallocateFib;
+
+	Adapter->CommFuncs.InitializeFib = InitializeFib;
+	Adapter->CommFuncs.GetFibData = FsaGetFibData;
+	Adapter->CommFuncs.SendFib = SendFib;
+	Adapter->CommFuncs.CompleteFib = CompleteFib;
+	Adapter->CommFuncs.CompleteAdapterFib = CompleteAdapterFib;
+
+	Adapter->CommFuncs.SendSynchFib = SendSynchFib;
+
+	Adapter->CommFuncs.FreeDmaResources = Adapter->AdapterFuncs->FreeDmaResources;
+	Adapter->CommFuncs.BuildSgMap = Adapter->AdapterFuncs->BuildSgMap;
+
+#ifdef GATHER_FIB_TIMES
+	//
+	// Initialize the Fib timing data structures
+	//
+	{
+		PFIB_TIMES FibTimesPtr;
+		int i;
+
+		KeQueryPerformanceCounter(&Adapter->FibTimesFrequency);
+
+		Adapter->FibTimesFrequency.QuadPart >>= 7;
+
+		Adapter->FibTimes = (PALL_FIB_TIMES)ExAllocatePool(NonPagedPool, sizeof(ALL_FIB_TIMES));
+		RtlZeroMemory(Adapter->FibTimes, sizeof(ALL_FIB_TIMES));
+
+		for (i = 0; i < MAX_FSACOMMAND_NUM; i++) {
+
+			FibTimesPtr = &Adapter->FibTimes->FileSys[i];
+
+			FibTimesPtr->Minimum.LowPart = 0xffffffff;
+			FibTimesPtr->Minimum.HighPart = 0x7fffffff;
+			FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff;
+			FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff;
+		}
+		for (i = 0; i < MAX_RW_FIB_TIMES; i++) {
+
+			FibTimesPtr = &Adapter->FibTimes->Read[i];
+
+			FibTimesPtr->Minimum.LowPart = 0xffffffff;
+			FibTimesPtr->Minimum.HighPart = 0x7fffffff;
+			FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff;
+			FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff;
+		}
+		for (i = 0; i < MAX_RW_FIB_TIMES; i++) {
+
+			FibTimesPtr = &Adapter->FibTimes->Write[i];
+
+			FibTimesPtr->Minimum.LowPart = 0xffffffff;
+			FibTimesPtr->Minimum.HighPart = 0x7fffffff;
+			FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff;
+			FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff;
+		}
+
+		FibTimesPtr = &Adapter->FibTimes->Other;
+
+		FibTimesPtr->Minimum.LowPart = 0xffffffff;
+		FibTimesPtr->Minimum.HighPart = 0x7fffffff;
+		FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff;
+		FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff;
+	}
+#endif
+
+	//
+	// Add this adapter in to our Adapter List.
+	//
+
+	Adapter->NextAdapter = FsaCommData.AdapterList;
+	FsaCommData.AdapterList = Adapter;
+
+	NewAdapter->Adapter = Adapter;
+
+//	AfaDiskInitNewAdapter( Adapter->AdapterNumber, Adapter );
+
+	return (Adapter);
+}
+
+AAC_STATUS
+CommInitialize(
+	PAFA_COMM_ADAPTER Adapter
+	)
+{
+    //
+    //  Now allocate and initialize the zone structures used as our pool
+    //  of FIB context records.  The size of the zone is based on the
+    //  system memory size.  We also initialize the mutex used to protect
+    //  the zone.
+    //
+	Adapter->FibContextZoneSpinLock= OsSpinLockAlloc();
+	OsSpinLockInit( Adapter->FibContextZoneSpinLock, Adapter->SpinLockCookie );
+
+    Adapter->FibContextZoneExtendSize = 64;
+
+	return (STATUS_SUCCESS);
+}
+
+
+    
+BOOLEAN
+CommInit(PAFA_COMM_ADAPTER Adapter)
+/*++
+
+Routine Description:
+
+    Initializes the data structures that are required for the FSA commuication
+    interface to operate.
+
+Arguments:
+
+    None - all global or allocated data.
+
+Return Value:
+
+    TRUE - if we were able to init the commuication interface.
+    FALSE - If there were errors initing. This is a fatal error.
+--*/
+{
+    
+    ULONG SizeOfHeaders = (sizeof(QUEUE_INDEX) * NUMBER_OF_COMM_QUEUES) * 2;
+    ULONG SizeOfQueues = sizeof(QUEUE_ENTRY) * TOTAL_QUEUE_ENTRIES;
+    PQUEUE_INDEX Headers;
+    PQUEUE_ENTRY Queues;
+	ULONG TotalSize;
+	PCOMM_REGION CommRegion = Adapter->CommRegion;
+
+	CommInitialize( Adapter );
+
+	FsaCommPrint("CommInit: Queue entry size is 0x%x, Queue index size is 0x%x, Number of total entries is 0x%x, # queues = 0x%x.\n",
+			  sizeof(QUEUE_ENTRY), sizeof(QUEUE_INDEX), TOTAL_QUEUE_ENTRIES, NUMBER_OF_COMM_QUEUES);
+	//
+	//
+	// Allocate the physically contigous space for the commuication queue
+	// headers. 
+	//
+
+	TotalSize = SizeOfHeaders + SizeOfQueues;
+
+	if (!FsaAllocateAdapterCommArea(Adapter, (PVOID *)&Headers, TotalSize, QUEUE_ALIGNMENT))
+		return (FALSE);
+
+#ifdef API_THROTTLE
+	//
+	// Initialize the throttle semaphore.
+	// Its a counted semaphore so we can allow a
+	// number of threads to be signalled by it at once.
+	//
+
+	CommRegion->ThrottleLimit = THROTTLE_MAX_DATA_FIBS;
+	CommRegion->ThrottleTimeout = RtlConvertLongToLargeInteger(THROTTLE_PERIOD_DURATION);
+	CommRegion->ThrottleWaitTimeout = RtlConvertLongToLargeInteger(THROTTLE_WAIT_DURATION);
+	CommRegion->ThrottleActive = FALSE;						// Is there a current throttle active period ?
+	CommRegion->ThrottleTimerFires = 0;						// No fires of throttle timer yet.
+	CommRegion->ThrottleTimerSets = 0;
+
+	CommRegion->ThrottledFibs = 0;
+	CommRegion->ThrottleTimedoutFibs = 0;
+	CommRegion->ApiFibs = 0;
+	CommRegion->NonPassiveFibs = 0;
+	CommRegion->TotalFibs = 0;
+	CommRegion->FSInfoFibs = 0;
+	CommRegion->ThrottleTimedoutFibs = 0;
+
+	//
+	// Initialize the semaphore controlling I/Os to the adapter.
+	// We set it not signalled with a maximum signalled count
+	// representing the maximum number of I/Os we'll allow at
+	// once at the adapter.
+	//
+	KeInitializeSemaphore(&CommRegion->ThrottleReleaseSema,
+						  CommRegion->ThrottleLimit,
+						  CommRegion->ThrottleLimit);
+	//
+	// Initialize the Timer and Dpc for the Throttle timeout routine.
+	//
+	KeInitializeTimer(&CommRegion->ThrottleTimer);
+	KeInitializeDpc(&CommRegion->ThrottleDpc,
+					(PKDEFERRED_ROUTINE) &ThrottlePeriodEndDpcRtn,
+					(PVOID) Adapter);
+
+#endif // #ifdef API_THROTTLE
+
+    Queues = (PQUEUE_ENTRY)((PUCHAR)Headers + SizeOfHeaders);
+
+
+
+	if (ddi_add_softintr( Adapter->Dip, DDI_SOFTINT_HIGH, &CommRegion->QueueNotFullDpc, NULL,
+						  NULL, (PUNIX_INTR_HANDLER)CommonNotFullDpc,
+						  (caddr_t)CommRegion ) != DDI_SUCCESS) {
+
+		cmn_err(CE_CONT, "Os_addr_intr failed\n");					
+	}					
+
+
+    // Adapter to Host normal priority Command queue
+
+
+    CommRegion->HostNormCmdQue.Headers.ProducerIndex = Headers++;
+    CommRegion->HostNormCmdQue.Headers.ConsumerIndex = Headers++;
+    *CommRegion->HostNormCmdQue.Headers.ProducerIndex = HOST_NORM_CMD_ENTRIES;
+    *CommRegion->HostNormCmdQue.Headers.ConsumerIndex = HOST_NORM_CMD_ENTRIES;
+
+    CommRegion->HostNormCmdQue.SavedIrql = 0;
+    CommRegion->HostNormCmdQue.BaseAddress = Queues;
+    CommRegion->HostNormCmdQue.QueueEntries = HOST_NORM_CMD_ENTRIES;
+
+	CommRegion->HostNormCmdQue.QueueLock = OsSpinLockAlloc();
+	if (CommRegion->HostNormCmdQue.QueueLock == NULL) {
+		return (FALSE);
+	}
+    InitializeNTQueue(Adapter, &CommRegion->HostNormCmdQue, HostNormCmdQueue);
+
+    
+    Queues += HOST_NORM_CMD_ENTRIES;
+
+    // Adapter to Host high priority command queue
+    
+    CommRegion->HostHighCmdQue.Headers.ProducerIndex = Headers++;
+    CommRegion->HostHighCmdQue.Headers.ConsumerIndex = Headers++;
+    *CommRegion->HostHighCmdQue.Headers.ProducerIndex = HOST_HIGH_CMD_ENTRIES;
+    *CommRegion->HostHighCmdQue.Headers.ConsumerIndex = HOST_HIGH_CMD_ENTRIES;
+
+    CommRegion->HostHighCmdQue.SavedIrql = 0;
+    CommRegion->HostHighCmdQue.BaseAddress = Queues;
+    CommRegion->HostHighCmdQue.QueueEntries = HOST_HIGH_CMD_ENTRIES;
+//	CommRegion->HostHighCmdQue.QueueLock = (PKSPIN_LOCK) ExAllocatePool(NonPagedPool, sizeof(KSPIN_LOCK));
+	CommRegion->HostHighCmdQue.QueueLock = OsSpinLockAlloc();
+	if (CommRegion->HostHighCmdQue.QueueLock == NULL) {
+		return (FALSE);
+	}
+    InitializeNTQueue(Adapter, &CommRegion->HostHighCmdQue, HostHighCmdQueue);
+    
+    Queues += HOST_HIGH_CMD_ENTRIES;
+
+    // Host to adapter normal priority command queue
+    
+    CommRegion->AdapNormCmdQue.Headers.ProducerIndex = Headers++;
+    CommRegion->AdapNormCmdQue.Headers.ConsumerIndex = Headers++;
+    *CommRegion->AdapNormCmdQue.Headers.ProducerIndex = ADAP_NORM_CMD_ENTRIES;
+    *CommRegion->AdapNormCmdQue.Headers.ConsumerIndex = ADAP_NORM_CMD_ENTRIES;
+
+    CommRegion->AdapNormCmdQue.SavedIrql = 0;    
+    CommRegion->AdapNormCmdQue.BaseAddress = Queues;
+    CommRegion->AdapNormCmdQue.QueueEntries = ADAP_NORM_CMD_ENTRIES;
+    InitializeNTQueue(Adapter, &CommRegion->AdapNormCmdQue, AdapNormCmdQueue);
+    
+    Queues += ADAP_NORM_CMD_ENTRIES;
+
+    // host to adapter high priority command queue
+    
+    CommRegion->AdapHighCmdQue.Headers.ProducerIndex = Headers++;
+    CommRegion->AdapHighCmdQue.Headers.ConsumerIndex = Headers++;
+    *CommRegion->AdapHighCmdQue.Headers.ProducerIndex = ADAP_HIGH_CMD_ENTRIES;
+    *CommRegion->AdapHighCmdQue.Headers.ConsumerIndex = ADAP_HIGH_CMD_ENTRIES;
+
+    CommRegion->AdapHighCmdQue.SavedIrql = 0;    
+    CommRegion->AdapHighCmdQue.BaseAddress = Queues;
+    CommRegion->AdapHighCmdQue.QueueEntries = ADAP_HIGH_CMD_ENTRIES;
+    InitializeNTQueue(Adapter, &CommRegion->AdapHighCmdQue, AdapHighCmdQueue);
+    
+    Queues += ADAP_HIGH_CMD_ENTRIES;
+
+    // adapter to host normal priority response queue
+    
+    CommRegion->HostNormRespQue.Headers.ProducerIndex = Headers++;
+    CommRegion->HostNormRespQue.Headers.ConsumerIndex = Headers++;
+    *CommRegion->HostNormRespQue.Headers.ProducerIndex = HOST_NORM_RESP_ENTRIES;
+    *CommRegion->HostNormRespQue.Headers.ConsumerIndex = HOST_NORM_RESP_ENTRIES;
+
+    CommRegion->HostNormRespQue.SavedIrql = 0;    
+    CommRegion->HostNormRespQue.BaseAddress = Queues;
+    CommRegion->HostNormRespQue.QueueEntries = HOST_NORM_RESP_ENTRIES;
+//	CommRegion->HostNormRespQue.QueueLock = (PKSPIN_LOCK) ExAllocatePool(NonPagedPool, sizeof(KSPIN_LOCK));
+	CommRegion->HostNormRespQue.QueueLock = OsSpinLockAlloc();
+	if (CommRegion->HostNormRespQue.QueueLock == NULL) {
+		return (FALSE);
+	}
+    InitializeNTQueue(Adapter, &CommRegion->HostNormRespQue, HostNormRespQueue);
+    
+    Queues += HOST_NORM_RESP_ENTRIES;
+
+    // adapter to host high priority response queue
+    
+    CommRegion->HostHighRespQue.Headers.ProducerIndex = Headers++;
+    CommRegion->HostHighRespQue.Headers.ConsumerIndex = Headers++;
+    *CommRegion->HostHighRespQue.Headers.ProducerIndex = HOST_HIGH_RESP_ENTRIES;
+    *CommRegion->HostHighRespQue.Headers.ConsumerIndex = HOST_HIGH_RESP_ENTRIES;
+
+    CommRegion->HostHighRespQue.SavedIrql = 0;    
+    CommRegion->HostHighRespQue.BaseAddress = Queues;
+    CommRegion->HostHighRespQue.QueueEntries = HOST_HIGH_RESP_ENTRIES;
+//	CommRegion->HostHighRespQue.QueueLock = (PKSPIN_LOCK) ExAllocatePool(NonPagedPool, sizeof(KSPIN_LOCK));
+	CommRegion->HostHighRespQue.QueueLock = OsSpinLockAlloc();
+	if (CommRegion->HostHighRespQue.QueueLock == NULL) {
+		return (FALSE);
+	}
+    InitializeNTQueue(Adapter, &CommRegion->HostHighRespQue, HostHighRespQueue);
+    
+    Queues += HOST_HIGH_RESP_ENTRIES;
+
+    // host to adapter normal priority response queue
+    
+    CommRegion->AdapNormRespQue.Headers.ProducerIndex = Headers++;
+    CommRegion->AdapNormRespQue.Headers.ConsumerIndex = Headers++;
+    *CommRegion->AdapNormRespQue.Headers.ProducerIndex = ADAP_NORM_RESP_ENTRIES;
+    *CommRegion->AdapNormRespQue.Headers.ConsumerIndex = ADAP_NORM_RESP_ENTRIES;
+
+    CommRegion->AdapNormRespQue.SavedIrql = 0;    
+    CommRegion->AdapNormRespQue.BaseAddress = Queues;
+    CommRegion->AdapNormRespQue.QueueEntries = ADAP_NORM_RESP_ENTRIES;
+    InitializeNTQueue(Adapter, &CommRegion->AdapNormRespQue, AdapNormRespQueue);
+    
+    Queues += ADAP_NORM_RESP_ENTRIES;
+
+    // host to adapter high priority response queue
+    
+    CommRegion->AdapHighRespQue.Headers.ProducerIndex = Headers++;
+    CommRegion->AdapHighRespQue.Headers.ConsumerIndex = Headers++;
+    *CommRegion->AdapHighRespQue.Headers.ProducerIndex = ADAP_HIGH_RESP_ENTRIES;
+    *CommRegion->AdapHighRespQue.Headers.ConsumerIndex = ADAP_HIGH_RESP_ENTRIES;
+
+    CommRegion->AdapHighRespQue.SavedIrql = 0;    
+    CommRegion->AdapHighRespQue.BaseAddress = Queues;
+    CommRegion->AdapHighRespQue.QueueEntries = ADAP_HIGH_RESP_ENTRIES;
+    InitializeNTQueue(Adapter, &CommRegion->AdapHighRespQue, AdapHighRespQueue);
+
+	CommRegion->AdapNormCmdQue.QueueLock = CommRegion->HostNormRespQue.QueueLock;
+	CommRegion->AdapHighCmdQue.QueueLock = CommRegion->HostHighRespQue.QueueLock;
+	CommRegion->AdapNormRespQue.QueueLock = CommRegion->HostNormCmdQue.QueueLock;
+	CommRegion->AdapHighRespQue.QueueLock = CommRegion->HostHighCmdQue.QueueLock;
+
+    return(TRUE);
+}
+
+AAC_STATUS
+AfaCommShutdown(
+	PAFA_COMM_ADAPTER Adapter
+	)
+/*++
+
+Routine Description:
+
+	This routine will send a shutdown request to each adapter.
+
+Arguments:
+
+	Adapter - which adapter to send the shutdown to.
+
+Return Value:
+
+    NT Status success.
+
+--*/
+
+{
+	PFIB_CONTEXT FibContext;
+	PCLOSECOMMAND CloseCommand;
+	AAC_STATUS Status;
+
+	FibContext = AllocateFib( Adapter );
+
+	InitializeFib( FibContext );
+
+	CloseCommand = (PCLOSECOMMAND) FsaGetFibData( FibContext );
+
+	CloseCommand->Command = VM_CloseAll;
+	CloseCommand->ContainerId = 0xffffffff;
+
+	Status = SendFib( ContainerCommand, FibContext, sizeof(CLOSECOMMAND), FsaNormal, TRUE, NULL, TRUE, NULL, NULL );
+
+	if (Status != STATUS_SUCCESS) {
+
+		FreeFib( FibContext );
+
+		goto ret;
+
+	}
+
+	CompleteFib( FibContext );
+
+	FreeFib( FibContext );
+
+
+	Status = STATUS_SUCCESS;
+
+ret:
+
+	return (Status);
+
+}
+
+VOID
+AfaCommBugcheckHandler(
+		IN PVOID Buffer,
+		IN ULONG Length
+		)
+/*++
+
+Routine Description:
+
+	This routine will shutdown the adapter if there is a bugcheck and
+	copy the shutdown data from the adapter response into the buffer
+	so it will show up in the host dump file.
+p
+Arguments:
+
+	Buffer - This buffer will be written to the host dump by nt for us.
+
+	Length - The size of the buffer.
+
+Return Value:
+
+	N/A
+
+--*/
+{
+	PAFA_COMM_ADAPTER Adapter = FsaCommData.AdapterList;
+
+	while (Adapter) {
+
+		NotifyAdapter(Adapter, HostShutdown);
+
+		Adapter = Adapter->NextAdapter;
+
+	}
+
+}	
+
+VOID
+FsaCommLogEvent(
+	PFIB_CONTEXT FibContext, 
+	PDEVICE_OBJECT DeviceObject,
+	AAC_STATUS FsaStatus,
+	AAC_STATUS AacStatus,
+	ULONG LocationCode,
+	USHORT Category,
+	PUCHAR String,
+	BOOLEAN DumpFib
+)
+{
+}
+
+AfaCommProbeDisks(
+	PAFA_COMM_ADAPTER	Adapter
+	)
+{
+    PMNTINFO DiskInfo;
+    PMNTINFORESPONSE DiskInfoResponse;
+	AAC_STATUS Status;
+	PCOMM_FIB_CONTEXT FibContext;
+    
+	FibContext = AllocateFib( Adapter );
+
+	InitializeFib( FibContext );
+
+	DiskInfo = (PMNTINFO) FibContext->Fib->data;
+	DiskInfo->Command = VM_NameServe;
+	DiskInfo->MntCount = 0;
+	DiskInfo->MntType = FT_FILESYS;
+
+    Status = SendFib(ContainerCommand,
+		             FibContext,
+	                 sizeof(MNTINFO),
+	                 FsaNormal,
+	                 TRUE,
+	                 NULL,
+	                 TRUE,
+	                 NULL,
+	                 NULL);
+
+	DiskInfoResponse = (PMNTINFORESPONSE) FibContext->Fib->data;
+
+	if (DiskInfoResponse->MntRespCount) {
+
+		cmn_err(CE_CONT, "container found on adapter, size = 0x%x blocks\n", 
+				DiskInfoResponse->MntTable[0].Capacity);
+				
+	} else {
+	
+		cmn_err(CE_CONT, "no containers found on adapter\n");
+		
+	}
+					
+	CompleteFib( FibContext );
+	
+	FreeFib( FibContext );				 
+}
+
+
diff -BburN linux.orig/drivers/scsi/aacraid/commsup.c linux/drivers/scsi/aacraid/commsup.c
--- linux.orig/drivers/scsi/aacraid/commsup.c	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/commsup.c	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,2294 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  commsup.c
+ *
+ * Abstract: Contain all routines that are required for FSA host/adapter
+ *    commuication.
+ *
+ *
+ --*/
+#include "comprocs.h"
+
+#define BugCheckFileId                   (FSAFS_BUG_CHECK_COMMSUP)
+
+int CommPrinting;
+
+void
+ThrottleExceptionHandler(
+	IN PCOMM_REGION CommRegion,
+	AAC_STATUS		Status
+	);
+
+void ThrottlePeriodEndDpcRtn(
+    IN PKDPC Dpc,
+    IN PVOID DeferredContext,
+    IN PVOID SystemArgument1,
+    IN PVOID SystemArgument2
+    );
+
+BOOLEAN
+FsaFreeFibContextSegment(
+	PAFA_COMM_ADAPTER Adapter,
+	PFIB_CONTEXT_ZONE_SEGMENT	ZoneSegment
+	)
+/*++
+
+Routine Description:
+
+	This routine will free all resources used by a given FibContextSegment.
+
+Arguments:
+
+	Adapter - The adapter that this COMM_FIB_CONTEXT will communicate with.
+	ZoneSegment - The segment to release resources from.
+
+Return Value:
+
+	TRUE - All resources were properly freed.
+	FALSE - An Error occured while freeing resources.
+
+--*/
+
+{
+	PCOMM_FIB_CONTEXT FibContext;
+	int i;
+	
+	// Account for the ZONE_SEGMENT_HEADER before the first actual FibContext.
+
+	for (i = 0, FibContext = (PCOMM_FIB_CONTEXT)((PUCHAR)ZoneSegment->FibContextSegment + sizeof(ZONE_SEGMENT_HEADER));
+		 i < ZoneSegment->ExtendSize; i++, FibContext++) {
+
+		OsCvLockDestroy( FibContext->FsaEventMutex );
+		OsCv_destroy( &FibContext->FsaEvent );
+
+	}
+
+	UnmapAndFreeFibSpace( Adapter, &ZoneSegment->MapFibContext );
+
+	OsFreeMemory( ZoneSegment->FibContextSegment, ZoneSegment->FibContextSegmentSize );
+
+	OsFreeMemory( ZoneSegment, sizeof( FIB_CONTEXT_ZONE_SEGMENT ) );
+
+	return (TRUE);
+}
+
+BOOLEAN
+FsaFreeFibContextZone(
+	PAFA_COMM_ADAPTER Adapter
+	)
+/*++
+
+Routine Description:
+
+	This routine will walk through the FibContextSegmentList and free up all
+	resources used by the FibContextZone.
+
+Arguments:
+
+	Adapter - The adapter that this COMM_FIB_CONTEXT will communicate with.
+
+Return Value:
+
+	TRUE - All resources were properly freed.
+	FALSE - An Error occured while freeing resources.
+
+--*/
+
+{
+	PFIB_CONTEXT_ZONE_SEGMENT ZoneSegment, NextZoneSegment;
+
+	ZoneSegment = Adapter->FibContextSegmentList;
+
+	while (ZoneSegment) {
+
+		NextZoneSegment = ZoneSegment->Next;
+
+		FsaFreeFibContextSegment( Adapter, ZoneSegment );
+
+		ZoneSegment = NextZoneSegment;
+	}
+
+	return (TRUE);
+}
+
+	
+
+BOOLEAN
+FsaExtendFibContextZone(
+	IN PAFA_COMM_ADAPTER Adapter
+	)
+{
+    int ExtendSize;
+    KIRQL SavedIrql;
+	ULONG ZoneSegmentAllocSize, FibAllocSize;
+	PVOID FibContextSegment;
+	PCOMM_FIB_CONTEXT FibContext;
+	PFIB Fib;
+	PVOID FibPhysicalAddress;
+	int i;
+	PFIB_CONTEXT_ZONE_SEGMENT ZoneSegment;
+	
+	//
+	// Allocate space to describe this zone segment.
+	//
+
+	ZoneSegment = OsAllocMemory( sizeof( FIB_CONTEXT_ZONE_SEGMENT ), OS_ALLOC_MEM_SLEEP );
+
+	ExtendSize = Adapter->FibContextZoneExtendSize;
+	ZoneSegmentAllocSize = (ExtendSize * sizeof(COMM_FIB_CONTEXT)) + sizeof(ZONE_SEGMENT_HEADER);
+
+	FibContextSegment = OsAllocMemory( ZoneSegmentAllocSize, OS_ALLOC_MEM_SLEEP );
+
+	if (FibContextSegment == NULL) {
+		return (FALSE);
+	}	
+
+	RtlZeroMemory( FibContextSegment, ZoneSegmentAllocSize );
+
+	ZoneSegment->FibContextSegment = FibContextSegment;
+	ZoneSegment->FibContextSegmentSize = ZoneSegmentAllocSize;
+	ZoneSegment->ExtendSize = ExtendSize;
+
+	FibAllocSize = ExtendSize * sizeof(FIB);
+
+
+	ZoneSegment->MapFibContext.Size = FibAllocSize;
+
+	AllocateAndMapFibSpace( Adapter, &ZoneSegment->MapFibContext );
+
+	Fib = ZoneSegment->MapFibContext.FibVirtualAddress;
+	FibPhysicalAddress = ZoneSegment->MapFibContext.FibPhysicalAddress;
+
+	RtlZeroMemory( Fib, FibAllocSize );
+
+	// Account for the ZONE_SEGMENT_HEADER before the first actual FibContext.
+
+	for (i = 0, FibContext = (PCOMM_FIB_CONTEXT)((PUCHAR)FibContextSegment + sizeof(ZONE_SEGMENT_HEADER));
+		 i < ExtendSize; i++, FibContext++) {
+
+		FibContext->Adapter = Adapter;
+
+		FibContext->Fib = Fib;
+		FibContext->FibData = (PVOID) FibContext->Fib->data;
+
+		OsCv_init( &FibContext->FsaEvent);
+		FibContext->FsaEventMutex = OsCvLockAlloc();
+		OsCvLockInit( FibContext->FsaEventMutex, Adapter->SpinLockCookie );
+
+		Fib->Header.XferState = 0xffffffff;
+		Fib->Header.SenderSize = sizeof(FIB);
+
+		FibContext->LogicalFibAddress.LowPart = (ULONG) FibPhysicalAddress;
+
+		Fib = (PFIB)((PUCHAR)Fib + sizeof(FIB));
+		FibPhysicalAddress = (PVOID)((PUCHAR)FibPhysicalAddress + sizeof(FIB));
+	}
+
+	//
+	// If FibContextZone.TotalSegmentSize is non-zero, then a zone has already been
+	// initialized, we just need to extend it.
+	//
+
+	if (Adapter->FibContextZone.TotalSegmentSize) {
+
+		OsSpinLockAcquire( Adapter->FibContextZoneSpinLock );
+
+		ExExtendZone( &Adapter->FibContextZone,
+					  FibContextSegment,
+					  ZoneSegmentAllocSize );
+
+		OsSpinLockRelease( Adapter->FibContextZoneSpinLock );
+
+	} else {
+
+	    if (ExInitializeZone( &Adapter->FibContextZone,
+							  sizeof(COMM_FIB_CONTEXT),
+    	                      FibContextSegment,
+	                          ZoneSegmentAllocSize ) != STATUS_SUCCESS)
+			FsaBugCheck(0,0,0);
+
+	}
+
+	//
+	// Add this segment to the adapter's list of segments
+	//
+
+	ZoneSegment->Next = Adapter->FibContextSegmentList;
+	Adapter->FibContextSegmentList = ZoneSegment;
+
+	return (TRUE);
+}
+
+
+
+PFIB_CONTEXT
+AllocateFib (
+	IN PVOID AdapterArg
+    )
+
+/*++
+
+Routine Description:
+
+    This routine creates a new COMM_FIB_CONTEXT record
+
+Arguments:
+
+	Adapter - The adapter that this COMM_FIB_CONTEXT will communicate with.
+
+Return Value:
+
+    PCOMM_FIB_CONTEXT - returns a pointer to the newly allocate COMM_FIB_CONTEXT Record
+
+--*/
+
+{
+	PAFA_COMM_ADAPTER Adapter = (PAFA_COMM_ADAPTER) AdapterArg;
+    KIRQL SavedIrql;
+    PCOMM_FIB_CONTEXT FibContext;
+	int FullZoneLoopCounter = 0;
+
+    //
+	// Acquire the zone spin lock, and check to see if the zone is full.
+	// If it is, then release the spin lock and allocate more fibs for the 
+	// zone.  The ExtendFibZone routine will re-acquire the spin lock to add
+	// the new fibs onto the zone.
+    //
+
+    OsSpinLockAcquire( Adapter->FibContextZoneSpinLock );
+
+    while (ExIsFullZone( &Adapter->FibContextZone )) {
+
+		if (++FullZoneLoopCounter >  10)
+			FsaBugCheck(0,0,0);
+
+		OsSpinLockRelease( Adapter->FibContextZoneSpinLock );
+
+		if (FsaExtendFibContextZone(Adapter) == FALSE) {
+			return (NULL);
+		}
+
+	    OsSpinLockAcquire( Adapter->FibContextZoneSpinLock );
+
+	}
+
+    //
+	//  At this point we now know that the zone has at least one more
+    //  IRP context record available.  So allocate from the zone and
+    //  then release the mutex.
+    //
+
+    FibContext = (PCOMM_FIB_CONTEXT) ExAllocateFromZone( &Adapter->FibContextZone );
+
+	OsSpinLockRelease( Adapter->FibContextZoneSpinLock );
+
+    //
+    //  Set the proper node type code and node byte size
+    //
+
+    FibContext->NodeTypeCode = FSAFS_NTC_FIB_CONTEXT;
+    FibContext->NodeByteSize = sizeof( COMM_FIB_CONTEXT );
+
+	// 
+	// Null out fields that depend on being zero at the start of each I/O
+	//
+
+	FibContext->Fib->Header.XferState = 0;
+	FibContext->FibCallback = NULL;
+	FibContext->FibCallbackContext = NULL;
+
+
+    //
+    //  return and tell the caller
+    //
+
+    return ((PFIB_CONTEXT) FibContext);
+}
+
+
+VOID
+FreeFib (
+    IN PFIB_CONTEXT Context
+    )
+
+/*++
+
+Routine Description:
+
+    This routine deallocates and removes the specified COMM_FIB_CONTEXT record
+    from the Fsafs in memory data structures.  It should only be called
+    by FsaCompleteRequest.
+
+Arguments:
+
+   	FibContext - Supplies the COMM_FIB_CONTEXT to remove
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    KIRQL SavedIrql;
+	PCOMM_FIB_CONTEXT FibContext = Context;
+
+    ASSERT(FibContext->NodeTypeCode == FSAFS_NTC_FIB_CONTEXT);
+
+    OsSpinLockAcquire( FibContext->Adapter->FibContextZoneSpinLock );
+
+	if (FibContext->Flags & FIB_CONTEXT_FLAG_TIMED_OUT) {
+
+		FsaCommData.TimedOutFibs++;
+
+		FibContext->Next = FibContext->Adapter->FibContextTimedOutList;
+		FibContext->Adapter->FibContextTimedOutList = FibContext;
+
+	} else {
+
+	    ASSERT(FibContext->Fib->Header.XferState == 0);
+
+		if (FibContext->Fib->Header.XferState != 0) {
+				cmn_err(CE_WARN, "FreeFib, XferState != 0, FibContext = 0x%x, XferState = 0x%x\n", 
+					 FibContext, FibContext->Fib->Header.XferState);
+		}
+
+	    ExFreeToZone( &FibContext->Adapter->FibContextZone, FibContext );
+
+	}	
+
+	OsSpinLockRelease( FibContext->Adapter->FibContextZoneSpinLock );
+
+    //
+    //  return and tell the caller
+    //
+
+    return;
+}
+
+
+VOID
+FreeFibFromDpc(
+    IN PFIB_CONTEXT Context
+    )
+
+/*++
+
+Routine Description:
+
+    This routine deallocates and removes the specified COMM_FIB_CONTEXT record
+    from the Fsafs in memory data structures.  It should only be called
+    from the dpc routines to from dpc to free an FibContext from an async or
+	no response io
+
+Arguments:
+
+    FibContext - Supplies the COMM_FIB_CONTEXT to remove
+
+Return Value:
+
+    None
+
+--*/
+
+{
+    PCOMM_FIB_CONTEXT FibContext = (PCOMM_FIB_CONTEXT) Context;
+
+    ASSERT(FibContext->NodeTypeCode == FSAFS_NTC_FIB_CONTEXT);
+
+    OsSpinLockAcquire(FibContext->Adapter->FibContextZoneSpinLock);
+
+	if (FibContext->Flags & FIB_CONTEXT_FLAG_TIMED_OUT) {
+
+		FsaCommData.TimedOutFibs++;
+
+		FibContext->Next = FibContext->Adapter->FibContextTimedOutList;
+		FibContext->Adapter->FibContextTimedOutList = FibContext;
+
+	} else {
+
+	    ASSERT(FibContext->Fib->Header.XferState == 0);
+
+		if (FibContext->Fib->Header.XferState != 0) {
+				cmn_err(CE_WARN, "FreeFibFromDpc, XferState != 0, FibContext = 0x%x, XferState = 0x%x\n", 
+					 FibContext, FibContext->Fib->Header.XferState);
+		}
+
+
+	    ExFreeToZone( &FibContext->Adapter->FibContextZone, FibContext );
+
+	}
+		
+	OsSpinLockRelease(FibContext->Adapter->FibContextZoneSpinLock);
+
+    //
+    //  return and tell the caller
+    //
+
+    return;
+}
+
+
+
+AAC_STATUS
+InitializeFib(
+	IN PFIB_CONTEXT Context
+    )
+/*++
+
+Routine Description:
+
+    Will initialize a FIB of the requested size.
+    
+Arguments:
+
+    Fib is a pointer to a location which will receive the address of the allocated
+        FIB.
+
+    Size is the size of the Fib to allocate.
+
+Return Value:
+
+    NT_SUCCESS if a Fib was returned to the caller.
+    NT_ERROR if event was an invalid event. 
+
+--*/
+{
+    PCOMM_FIB_CONTEXT FibContext = (PCOMM_FIB_CONTEXT) Context;
+	PFIB Fib = FibContext->Fib;
+
+    Fib->Header.StructType = TFib;
+    Fib->Header.Size = sizeof(FIB);
+//    if (Fib->Header.XferState & AllocatedFromPool)
+//        Fib->Header.XferState = HostOwned | FibInitialized | FibEmpty | AllocatedFromPool;
+//    else
+        Fib->Header.XferState = HostOwned | FibInitialized | FibEmpty | FastResponseCapable;
+    Fib->Header.SenderFibAddress = 0;
+    Fib->Header.ReceiverFibAddress = 0;
+    Fib->Header.SenderSize = sizeof(FIB);
+
+    return(STATUS_SUCCESS);
+}
+    
+AAC_STATUS
+AllocatePoolFib(
+    OUT PFIB *Fib,
+    IN USHORT Size
+     )
+/*++
+
+Routine Description:
+
+    Will allocate and initialize a FIB of the requested size and return a
+    pointer to the structure. The size allocated may be larger than the size
+    requested due to allocation performace optimizations.
+    
+Arguments:
+
+    Fib is a pointer to a location which will receive the address of the allocated
+        FIB.
+
+    Size is the size of the Fib to allocate.
+
+    JustInitialize is a boolean which indicates a Fib has been allocated most likly in an
+        imbedded structure the FS always allocates. So just initiaize it and return.
+    
+Return Value:
+
+    NT_SUCCESS if a Fib was returned to the caller.
+    NT_ERROR if event was an invalid event. 
+
+--*/
+{
+
+}
+    
+AAC_STATUS
+DeallocateFib(
+    PFIB_CONTEXT Context
+    )
+/*++
+
+Routine Description:
+
+    Will deallocate and return to the free pool the FIB pointed to by the
+    caller. Upon return accessing locations pointed to by the FIB parameter
+    could cause system access faults.
+
+Arguments:
+
+    Fib is a pointer to the FIB that caller wishes to deallocate.
+    
+Return Value:
+
+    NT_SUCCESS if a Fib was returned to the caller.
+    NT_ERROR if event was an invalid event. 
+
+--*/
+{
+    PCOMM_FIB_CONTEXT FibContext = (PCOMM_FIB_CONTEXT) Context;
+	PFIB Fib = FibContext->Fib;
+
+    if ( Fib->Header.StructType != TFib ) {
+        FsaCommPrint("Error CompleteFib called with a non Fib structure.\n");
+        return(STATUS_UNSUCCESSFUL);
+    }
+
+
+    Fib->Header.XferState = 0;        
+        
+    return(STATUS_SUCCESS);
+
+}
+
+
+AAC_STATUS
+GetResponse(
+    IN PCOMM_QUE ResponseQueue,
+    OUT PFIB Fib
+    )
+/*++
+
+Routine Description:
+
+    Gets a QE off the requested response queue and gets the response FIB into
+    host memory. The FIB may already be in host memory depending on the bus
+    interface, or may require the host to DMA it over from the adapter. The routine
+    will return the FIB to the caller.
+
+Arguments:
+
+    ResponseQueue - Is the queue the caller wishes to have the response gotten from.
+    Fib - Is the Fib which was the response from the adapter
+
+Return Value:
+
+    NT_SUCCESS if a Fib was returned to the caller.
+    NT_ERROR if there was no Fib to return to the caller.
+    bkpfix - add in all the other possible errors ect
+
+--*/
+{
+return(STATUS_UNSUCCESSFUL);
+}
+
+//
+// Commuication primitives define and support the queuing method we use to
+// support host to adapter commuication. All queue accesses happen through
+// these routines and are the only routines which have a knowledge of the
+// how these queues are implemented.
+//
+
+BOOLEAN
+GetEntry(
+	IN PAFA_COMM_ADAPTER Adapter,
+    IN QUEUE_TYPES WhichQueue,
+    OUT PQUEUE_ENTRY *Entry,
+    OUT PQUEUE_INDEX Index,
+	OUT ULONG *DontInterrupt
+    )
+/*++
+
+Routine Description:
+
+    With a priority the routine returns a queue entry if the queue has free entries. If the queue
+    is full(no free entries) than no entry is returned and the function returns FALSE otherwise TRUE is
+    returned.
+
+Arguments:
+
+    Priority is an enumerated type which determines which priority level
+        command queue the QE is going to be queued on.
+
+    Entry is a pointer to the address of where to return the address of
+        the queue entry from the requested command queue.
+
+    Index is a pointer to the address of where to store the index of the new
+        queue entry returned.
+
+	DontInterrupt - We set this true if the queue state is such that we don't
+		need to interrupt the adapter for this queue entry.
+
+Return Value:
+
+    TRUE - If a queue entry is returned
+    FALSE - If there are no free queue entries on the requested command queue.
+
+--*/
+{
+    ULONG QueueOffset;
+	BOOLEAN status;
+	PCOMM_REGION CommRegion;
+
+	CommRegion = Adapter->CommRegion;
+
+    //
+    // All of the queues wrap when they reach the end, so we check to see if they
+    // have reached the end and if they have we just set the index back to zero.
+    // This is a wrap. You could or off the high bits in all updates but this is
+    // a bit faster I think.
+    //
+
+    if (WhichQueue == AdapHighCmdQueue) {
+        *Index = *(CommRegion->AdapHighCmdQue.Headers.ProducerIndex);
+
+		if (*Index - 2 == *(CommRegion->AdapHighCmdQue.Headers.ConsumerIndex))
+			*DontInterrupt = TRUE; 
+
+        if (*Index >= ADAP_HIGH_CMD_ENTRIES)
+            *Index = 0;
+
+        if (*Index + 1 == *(CommRegion->AdapHighCmdQue.Headers.ConsumerIndex)) { // Queue is full
+			status = FALSE;
+			cmn_err(CE_WARN, "Adapter High Command Queue full, %d outstanding",
+					CommRegion->AdapHighCmdQue.NumOutstandingIos);
+		} else {
+	        QueueOffset = sizeof(QUEUE_ENTRY) * (*Index);
+	        *Entry = QueueOffset + CommRegion->AdapHighCmdQue.BaseAddress;
+
+			status = TRUE;
+		}
+    } else if (WhichQueue == AdapNormCmdQueue) {
+
+        *Index = *(CommRegion->AdapNormCmdQue.Headers.ProducerIndex);
+
+		if (*Index - 2 == *(CommRegion->AdapNormCmdQue.Headers.ConsumerIndex))
+			*DontInterrupt = TRUE; 
+
+		//
+		// If we are at the end of the QUEUE then wrap back to 
+		// the beginning.
+        //
+
+        if (*Index >= ADAP_NORM_CMD_ENTRIES) 
+            *Index = 0; // Wrap to front of the Producer Queue.
+
+		//
+        // The IEEE spec says that it the producer is one behind the consumer then
+        // the queue is full.
+        //       
+
+		ASSERT(*(CommRegion->AdapNormCmdQue.Headers.ConsumerIndex) != 0);
+
+        if (*Index + 1 == *(CommRegion->AdapNormCmdQue.Headers.ConsumerIndex)) { // Queue is full
+			cmn_err(CE_WARN, "Adapter Norm Command Queue full, %d outstanding",
+					CommRegion->AdapNormCmdQue.NumOutstandingIos);
+			status = FALSE;
+		} else {        
+	       	//
+			// The success case just falls through and returns the a valid queue entry.
+			//
+
+#ifdef commdebug
+	        FsaCommPrint("queue entry = %x.\n",CommRegion->AdapNormCmdQue.BaseAddress + *Index);
+	        FsaCommPrint("GetEntry: Index = %d, QueueOffset = %x, Entry = %x, *Entry = %x.\n",
+	                     *Index, QueueOffset, Entry, *Entry);
+#endif
+	        *Entry = CommRegion->AdapNormCmdQue.BaseAddress + *Index;
+
+			status = TRUE;
+		}
+    } else if (WhichQueue == AdapHighRespQueue) {
+
+        *Index = *(CommRegion->AdapHighRespQue.Headers.ProducerIndex);
+
+		if (*Index - 2 == *(CommRegion->AdapHighRespQue.Headers.ConsumerIndex))
+			*DontInterrupt = TRUE; 
+
+        if (*Index >= ADAP_HIGH_RESP_ENTRIES)
+            *Index = 0;
+
+        if (*Index + 1 == *(CommRegion->AdapHighRespQue.Headers.ConsumerIndex)) { // Queue is full
+			status = FALSE;
+			cmn_err(CE_WARN, "Adapter High Resp Queue full, %d outstanding",
+					CommRegion->AdapHighRespQue.NumOutstandingIos);
+		} else {							
+	        *Entry = CommRegion->AdapHighRespQue.BaseAddress + *Index;
+    		status = TRUE;
+		} 
+    } else if (WhichQueue == AdapNormRespQueue) {
+
+        *Index = *(CommRegion->AdapNormRespQue.Headers.ProducerIndex);
+
+		if (*Index - 2 == *(CommRegion->AdapNormRespQue.Headers.ConsumerIndex))
+			*DontInterrupt = TRUE; 
+
+		//
+		// If we are at the end of the QUEUE then wrap back to 
+		// the beginning.
+        //
+
+        if (*Index >= ADAP_NORM_RESP_ENTRIES) 
+            *Index = 0; // Wrap to front of the Producer Queue.
+
+		//
+        // The IEEE spec says that it the producer is one behind the consumer then
+        // the queue is full.
+        //       
+
+        if (*Index + 1 == *(CommRegion->AdapNormRespQue.Headers.ConsumerIndex)) { // Queue is full
+			status = FALSE; 
+			cmn_err(CE_WARN, "Adapter Norm Resp Queue full, %d outstanding",
+					CommRegion->AdapNormRespQue.NumOutstandingIos);
+		} else {        
+	       	//
+			// The success case just falls through and returns the a valid queue entry.
+			//
+
+	        *Entry = CommRegion->AdapNormRespQue.BaseAddress + *Index;
+
+#ifdef commdebug
+	        FsaCommPrint("queue entry = %x.\n",CommRegion->AdapNormRespQue.BaseAddress + *Index);
+	        FsaCommPrint("GetEntry: Index = %d, Entry = %x, *Entry = %x.\n",*Index, Entry, *Entry);
+#endif
+			status = TRUE;
+		}     
+    } else {
+		cmn_err(CE_PANIC, "GetEntry: invalid queue %d", WhichQueue);
+	}
+
+
+	return (status);
+}
+   
+
+
+#ifdef API_THROTTLE
+
+void ThrottleCheck(
+	IN PAFA_COMM_ADAPTER Adapter,
+	IN PFIB Fib
+	)
+/*++
+
+Routine Description:
+
+    This routine implements data I/O throttling. Throttling occurs when
+	a CLI FIB is detected. To ensure the CLI responds quickly (the user
+	is waiting for the response), this mechanism restricts the queue
+	depth of data IOs at the adapter for a period of time (called the
+	Throttle Period, default 5 seconds).
+
+    The mechanism uses a counted semaphore to place threads into a wait
+	state should there be too many data I/Os outstanding.
+
+	At the start of a throttle period (indicated by the first CLI FIB)
+	a timer is started. When the timer expires, new requests can go to
+	the adapter freely. Throttled requests gradually drain to the
+	adapter as each outstanding throttle I/O completes.
+
+    To avoid hurting regular I/O performance, we use a flag in the FIB
+	header to mark FIBs involved in throttling. This means we only need
+	take the extra spinlock in the response DPC routine for FIBs who
+	were subject to throttling. If no throttling is occurring, the cost
+	to the regular code paths is a handful of instructions.
+
+Arguments:
+
+	Adapter - Pointer to per-adapter context. This is used to locate the
+			  throttle information for this adapter.
+	
+	Fib		- Pointer to the header for the fib being sent.
+
+Return Value:
+
+	None.
+
+--*/
+{
+	PCOMM_REGION CommRegion = Adapter->CommRegion;
+	AAC_STATUS	 Status;
+
+	//
+	// This routine is called under protection of the queue spinlock.
+	// As such we are allowed to check and change the counts for the
+	// throttle.
+	// Check the FIB. If its not a data operation, send it on without
+	// throttle check. If it is a data operation, check for throttle.
+	//
+
+	CommRegion->TotalFibs++;							// Keep statistics
+
+	if ((Fib->Header.XferState & ApiFib) != 0) {
+
+		CommRegion->ApiFibs++;							// Keep statistics
+
+		//
+		// Its an API fib. If the throttle is not already active,
+		// make it so. This will prevent new data Fibs being sent
+		// if they exceed the throttle check.
+		//
+
+		if (!CommRegion->ThrottleActive) {
+			BOOLEAN		 InQue;
+
+			CommRegion->ThrottleActive = TRUE;			// This causes new data I/Os to be throttled
+
+			//
+			// Schedule a timer for the throttle active period. When
+			// it expires, we'll be called back at routine ThrottleDpcRoutine
+			// above. This will signify the throttle active period ended
+			// and any waiting threads will be signalled to restart.
+			//
+
+			FsaCommPrint("Throttle Period Start - CommRegion: %x\n", CommRegion);
+			CommRegion->ThrottleTimerSets++;
+			InQue = KeSetTimer( &CommRegion->ThrottleTimer,
+								CommRegion->ThrottleTimeout,
+								&CommRegion->ThrottleDpc);
+			ASSERT(InQue == FALSE);
+		}
+
+		return;
+	}
+
+	//
+	// Its a non-API fib, so subject to throttle checks.
+	// The following are exempt from throttling:
+	//		o FIBs marked as "throttle exempt" by upper layers.
+	//		o I/Os issued from a raised IRQL. We can't suspend
+	//		  a thread when at raised IRQL so throttling is exempt.
+	//
+
+	if (CommRegion->AdapNormCmdQue.SavedIrql != PASSIVE_LEVEL) {
+
+		CommRegion->NonPassiveFibs++;
+		FsaCommPrint("ThrottleCheck: Non-Passive level FIB bypasses throttle: %x\n", Fib);
+		return;
+
+	}
+
+	if (CommRegion->ThrottleActive) {
+
+		//
+		// Throttle is active.
+		// Check if the FIB is a read or write. If so, and its to the
+		// file system information area, let it through without throttling.
+		//
+
+		if (Fib->Header.Command == ContainerCommand) {
+			PBLOCKREAD BlockDisk = (PBLOCKREAD) &Fib->data;
+
+			//
+			// *** Note *** We are using read and write command formats
+			// interchangably here. This is ok for this purpose as the
+			// command is in the same place for both. Read and write command
+			// formats are different at higher offsets though.
+			//
+
+			if ( ((BlockDisk->Command == VM_CtBlockRead) ||
+				  (BlockDisk->Command == VM_CtBlockWrite)) &&
+				  (BlockDisk->BlockNumber <= FILESYSTEM_INFO_MAX_BLKNO)) {
+
+				CommRegion->FSInfoFibs++;							// Keep statistics
+				return;
+
+			}
+
+		}
+
+		//
+		// Throttle the FIB.
+		// Mark it as throttle active so that it can signal a waiter
+		// when it completes.
+
+		CommRegion->ThrottledFibs++;
+		Fib->Header.Flags |= ThrottledFib;
+		
+		//
+		// Release the spinlock so we can wait the thread if necessary.
+		// Since we specify a timeout, check the caller is at passive level.
+		//
+
+		OsSpinLockRelease((CommRegion->AdapNormCmdQue.QueueLock), CommRegion->AdapNormCmdQue.SavedIrql);
+
+		FsaCommPrint("ThrottleCheck - Thread Suspension - FIB: %x\n", Fib);
+
+		Status = KeWaitForSingleObject(&CommRegion->ThrottleReleaseSema,
+										Executive,							// Don't allow user APCs to wake us
+										KernelMode,							// Wait in kernel mode
+										FALSE,								// Not alertable
+										&CommRegion->ThrottleWaitTimeout);	// Timeout after this time
+
+		//
+		// Check the signal status. If we've timed out, clear the throttle
+		// flag on the FIB to avoid us signalling the semaphore on completion.
+		// We never acquired the semaphore.
+		//
+		if (Status == STATUS_TIMEOUT) {
+
+			CommRegion->ThrottleTimedoutFibs++;
+			FsaCommPrint("ThrottledFib Timed Out - FIB: %x\n", Fib);
+			Fib->Header.Flags &= ~ThrottledFib;						// Clear the throttledfib flag
+
+		} else {
+
+			ASSERT(Status == STATUS_SUCCESS);						// No other return is possible
+
+		}
+
+		//
+		// We've been woken up and can now send the FIB to the adapter.
+		// Acquire the spinlock again so we can get a queue entry. This
+		// returns to GetQueueEntry.
+		//
+
+		FsaCommPrint("ThrottleCheck - Thread Resume - FIB: %x\n", Fib);
+		KeAcquireSpinLock((CommRegion->AdapNormCmdQue.QueueLock), &(CommRegion->AdapNormCmdQue.SavedIrql));
+		CommRegion->ThrottleOutstandingFibs++;		// There's another throttle controlled FIB going.
+		return;
+
+	}
+}
+
+#endif //#ifdef API_THROTTLE
+
+int GetQueueEntryTimeouts = 0;
+
+AAC_STATUS
+GetQueueEntry(
+	IN PAFA_COMM_ADAPTER Adapter,
+    OUT PQUEUE_INDEX Index,
+    IN QUEUE_TYPES WhichQueue,
+    IN PFIB Fib,
+    IN BOOLEAN Wait,
+    IN PCOMM_FIB_CONTEXT FibContext,
+	OUT ULONG *DontInterrupt
+    )
+/*++
+
+Routine Description:
+
+    Gets the next free QE off the requested priorty adapter command queue and
+    associates the Fib with the QE. The QE represented by index is ready to
+     insert on the queue when this routine returns success.
+
+Arguments:
+
+    Index is the returned value which represents the QE which is ready to
+        insert on the adapter's command queue.
+
+    Priority is an enumerated type which determines which priority level
+        command queue the QE is going to be queued on.
+
+    Fib is a pointer to the FIB the caller wishes to have associated with the
+        QE.
+
+    Wait is a boolean which determines if the routine will wait if there are
+        no free QEs on the requested priority command queue.
+
+    FibContext is where the driver stores all system resources required to execute the
+        command requested from the calling thread. This includes mapping resources for
+        the FIB and the 'users' buffer.
+
+	DontInterrupt - We set this true if the queue state is such that we don't
+		need to interrupt the adapter for this queue entry.
+
+Return Value:
+
+    NT_SUCCESS if a Fib was returned to the caller.
+    NT_ERROR if event was an invalid event. 
+
+--*/
+{
+    PQUEUE_ENTRY QueueEntry = NULL;
+    BOOLEAN MapAddress = FALSE;
+	int timeouts = 0;
+	AAC_STATUS Status;
+	PCOMM_REGION CommRegion;
+
+	CommRegion = Adapter->CommRegion;
+
+    //
+    // Get the spinlock for the queue we are putting a command on
+    //
+
+    if (WhichQueue == AdapHighCmdQueue) 
+        OsSpinLockAcquire(CommRegion->AdapHighCmdQue.QueueLock);
+    else if (WhichQueue == AdapNormCmdQueue)
+        OsSpinLockAcquire(CommRegion->AdapNormCmdQue.QueueLock);
+    else if (WhichQueue == AdapHighRespQueue)
+        OsSpinLockAcquire(CommRegion->AdapHighRespQue.QueueLock);
+    else if (WhichQueue == AdapNormRespQueue)
+        OsSpinLockAcquire(CommRegion->AdapNormRespQue.QueueLock);
+    else {
+        FsaCommPrint("Invalid queue priority passed to GetQueueEntry.\n");
+        return(FSA_INVALID_QUEUE);
+    }
+    
+    //
+    // Get the pointers to a queue entry on the queue the caller wishes to queue
+    // a command request on. If there are no entries then wait if that is what the
+    // caller requested. 
+    //
+
+    if (WhichQueue == AdapHighCmdQueue) {
+
+        while ( !GetEntry(Adapter, AdapHighCmdQueue, &QueueEntry, Index, DontInterrupt) ) { // if no entries wait for some if caller wants to
+			cmn_err(CE_PANIC, "GetEntries failed (1)\n");
+		}
+
+        //
+        // Setup queue entry with a command, status and Fib mapped
+        //
+
+        QueueEntry->Size = Fib->Header.Size;
+        MapAddress = TRUE;
+	
+    } else if (WhichQueue == AdapNormCmdQueue) {
+
+#ifdef API_THROTTLE
+		//
+		// Check if this is a data I/O that may be throttled. Throttling
+		// occurs if FAST is trying to issue FIBs to the adapter for management
+		// commands. If a FAST FIB is detected by ThrottleCheck it is allowed
+		// to go to the adapter (barring no queue entries being available). If
+		// the FAST fib is the first FAST fib to be detected, a data I/O throttle
+		// period is started. New incoming data I/Os are restricted so that only
+		// a few can be outstanding to the adapter at once. This prevents the
+		// FAST FIBs being starved out from the disks. Once the period has ended,
+		// normal service is resumed.
+		// New data FIBs (i.e. non-FAST FIB) can be initiated so long as they
+		// don't exceed the throttle maximum of outstanding FIBs. If the new FIB
+		// *would* exceed the maximum, the thread is put to sleep, waiting on the
+		// data I/O throttle synchronization semaphore. When the first data FIB completes
+		// that takes the outstanding count to below the threshold, the throttle
+		// synchronization semaphore is signalled once. It is signaled for each completing
+		// FIB until the throttle period ends and all throttled FIBs have completed.
+		//
+		ThrottleCheck(Adapter, Fib);					// Thread may be suspended here with spinlock released !
+#endif	// #ifdef API_THROTTLE
+
+#ifdef commdebug
+        FsaCommPrint("Requesting a qe address in address %x.\n", &QueueEntry);
+#endif
+        while ( !GetEntry(Adapter, AdapNormCmdQueue, &QueueEntry, Index, DontInterrupt) ) { // if no entries wait for some if caller wants to
+
+			cmn_err(CE_PANIC, "GetEntries failed (2)\n");
+		}
+ 
+        //
+        // Setup queue entry with command, status and Fib mapped
+        //
+
+#ifdef commdebug
+        FsaCommPrint("We got a QE from the normal command queue address of %x, Index returned = %d\n",
+                  *QueueEntry, *Index);
+#endif
+        QueueEntry->Size = Fib->Header.Size;
+        MapAddress = TRUE;
+        
+     } else if (WhichQueue == AdapHighRespQueue) {
+
+        while ( !GetEntry(Adapter, AdapHighRespQueue, &QueueEntry, Index, DontInterrupt) ) { // if no entries wait for some if caller wants to
+		}
+
+        //
+        // Setup queue entry with command, status and Fib mapped
+        //
+
+        QueueEntry->Size = Fib->Header.Size;
+        QueueEntry->FibAddress = Fib->Header.SenderFibAddress;     			// Restore adapters pointer to the FIB
+		Fib->Header.ReceiverFibAddress = Fib->Header.SenderFibAddress;		// Let the adapter now where to find its data
+        MapAddress = FALSE;
+        
+     } else if (WhichQueue == AdapNormRespQueue) {
+        while ( !GetEntry(Adapter, AdapNormRespQueue, &QueueEntry, Index, DontInterrupt) ) { // if no entries wait for some if caller wants to
+		}
+
+		//
+		// Setup queue entry with command, status, adapter's pointer to the Fib it sent
+		//
+	
+        QueueEntry->Size = Fib->Header.Size;
+        QueueEntry->FibAddress = Fib->Header.SenderFibAddress;     			// Restore adapters pointer to the FIB
+		Fib->Header.ReceiverFibAddress = Fib->Header.SenderFibAddress;		// Let the adapter now where to find its data
+        MapAddress = FALSE;
+     }
+                
+    //
+    // If MapFib is true than we need to map the Fib and put pointers in the queue entry.
+    //
+
+    if (MapAddress) {
+		QueueEntry->FibAddress = (ULONG)(FibContext->LogicalFibAddress.LowPart);
+    }
+    
+    //
+    // Return
+    //
+#ifdef commdebug    
+    FsaCommPrint("Queue Entry contents:.\n");
+    FsaCommPrint("  Command =               %d.\n", QueueEntry->Command);
+    FsaCommPrint("  Status  =               %x.\n", QueueEntry->Status);
+    FsaCommPrint("  Rec Fib address low =   %x.\n", QueueEntry->FibAddressLow);        
+    FsaCommPrint("  Fib size in bytes =     %d.\n", QueueEntry->Size);
+#endif
+
+    return(FSA_SUCCESS);
+}
+
+AAC_STATUS
+InsertQueueEntry(
+	IN PAFA_COMM_ADAPTER Adapter,
+    IN QUEUE_INDEX Index,
+    IN QUEUE_TYPES WhichQueue,
+	IN ULONG DontInterrupt
+    )
+/*++
+
+Routine Description:
+
+    Gets the next free QE off the requested priorty adapter command queue and
+      associates the Fib with the QE. The QE represented by index is ready to
+    insert on the queue when this routine returns success.
+
+Arguments:
+
+    Index is the returned value which represents the QE which is ready to
+        insert on the adapter's command queue.
+
+    WhichQueue tells us which queue the caller wishes to have the entry put.
+        
+Return Value:
+
+    NT_SUCCESS if a Fib was returned to the caller.
+    NT_ERROR if event was an invalid event. 
+
+--*/
+{
+	PCOMM_REGION CommRegion;
+    
+	CommRegion = Adapter->CommRegion;
+
+    //
+    // We have already verified the queue in getentry, but we still have to make
+    // sure we don't wrap here too.
+    //
+
+    if (WhichQueue == AdapHighCmdQueue) {
+
+        *(CommRegion->AdapHighCmdQue.Headers.ProducerIndex) = Index + 1;
+            
+        OsSpinLockRelease(CommRegion->AdapHighCmdQue.QueueLock);
+
+		if (!DontInterrupt)
+	        NotifyAdapter(Adapter, AdapHighCmdQue);
+        
+    } else if (WhichQueue == AdapNormCmdQueue) {
+
+#ifdef commdebug
+        FsaCommPrint("InsertQueueEntry: Inerting with an index of %d.\n",Index);
+#endif
+        *(CommRegion->AdapNormCmdQue.Headers.ProducerIndex) = Index + 1;
+	
+        OsSpinLockRelease(CommRegion->AdapNormCmdQue.QueueLock);
+
+		if (!DontInterrupt)
+	        NotifyAdapter(Adapter, AdapNormCmdQue);
+
+    } else if (WhichQueue == AdapHighRespQueue) {
+
+        *(CommRegion->AdapHighRespQue.Headers.ProducerIndex) = Index + 1;
+
+        OsSpinLockRelease(CommRegion->AdapHighRespQue.QueueLock);
+
+		if (!DontInterrupt)
+	        NotifyAdapter(Adapter, AdapHighRespQue);
+
+    } else if (WhichQueue == AdapNormRespQueue) {
+
+        *(CommRegion->AdapNormRespQue.Headers.ProducerIndex) = Index + 1;
+
+        OsSpinLockRelease(CommRegion->AdapNormRespQue.QueueLock);
+
+		if (!DontInterrupt)
+	        NotifyAdapter(Adapter, AdapNormRespQue);
+
+    } else {        
+        FsaCommPrint("Invalid queue priority passed to InsertQueueEntry.\n");
+        return(FSA_INVALID_QUEUE_PRIORITY);
+    }
+
+    return(FSA_SUCCESS);                
+}
+
+extern int GatherFibTimes;
+
+BOOLEAN
+SendSynchFib(
+	PVOID			Arg,
+	FIB_COMMAND  	Command,
+	PVOID			Data,
+	USHORT		 	Size,
+	PVOID			Response,
+	USHORT		 	*ResponseSize
+	)
+/*++
+
+Routine Description:
+
+	This routine will send a synchronous FIB to the adapter and wait for its
+	completion.
+
+Arguments:
+
+	DeviceExtension - Pointer to adapter extension structure.
+
+
+Return Value:
+
+	BOOLEAN
+
+--*/
+{
+	PAFA_COMM_ADAPTER Adapter = Arg;
+	FIB *Fib;
+	ULONG returnStatus;
+
+	Fib = Adapter->SyncFib;
+
+    Fib->Header.StructType = TFib;
+    Fib->Header.Size = sizeof(FIB);
+    Fib->Header.XferState = HostOwned | FibInitialized | FibEmpty;
+    Fib->Header.ReceiverFibAddress = 0;
+    Fib->Header.SenderSize = sizeof(FIB);
+    Fib->Header.SenderFibAddress = (ULONG)Fib;
+    Fib->Header.Command = Command;
+
+	//
+	// Copy the Data portion into the Fib.
+	//
+
+	RtlCopyMemory( Fib->data, Data, Size );
+
+
+    Fib->Header.XferState |= (SentFromHost | NormalPriority);
+    
+	//
+    // Set the size of the Fib we want to send to the adapter
+	//
+
+    Fib->Header.Size = sizeof(FIB_HEADER) + Size;
+
+	if (!Adapter->AdapterFuncs->SendSynchFib( Adapter->AdapterExtension,
+				  							  Adapter->SyncFibPhysicalAddress )) {
+
+			return (FALSE);
+
+	}
+
+	//
+	// Copy the response back to the caller's buffer.
+	//
+
+	RtlCopyMemory( Response, Fib->data, Fib->Header.Size - sizeof(FIB_HEADER) );
+
+	*ResponseSize = Fib->Header.Size - sizeof(FIB_HEADER);
+
+	//
+	// Indicate success
+	//
+
+	return (TRUE);
+}
+
+//
+// Define the highest level of host to adapter communication routines. These
+// routines will support host to adapter FS commuication. These routines have
+// no knowledge of the commuication method used. This level sends and receives
+// FIBs. This level has no knowledge of how these FIBs get passed back and forth.
+//
+
+AAC_STATUS
+SendFib(
+    IN FIB_COMMAND Command, 
+	IN PFIB_CONTEXT Context,
+    IN ULONG Size,
+    IN COMM_PRIORITIES Priority,
+    IN BOOLEAN Wait,
+    IN PVOID WaitOn,
+    IN BOOLEAN ResponseExpected,
+	IN PFIB_CALLBACK FibCallback,
+	IN PVOID FibCallbackContext
+    )
+/*++
+
+Routine Description:
+
+    Sends the requested FIB to the adapter and optionally will wait for a
+     response FIB. If the caller does not wish to wait for a response than
+    an event to wait on must be supplied. This event will be set when a
+    response FIB is received from the adapter.
+
+Arguments:
+
+    Fib is a pointer to the FIB the caller wishes to send to the adapter.
+    
+    Size - Size of the data portion of the Fib.
+    
+    Priority is an enumerated type which determines which priority level
+        the caller wishes to send this command at. 
+
+    Wait is a boolean which determines if the routine will wait for the
+        completion Fib to be returned(TRUE), or return when the Fib has been
+        successfully received by the adapter(FALSE).
+
+    WaitOn is only vaild when Wait is FALSE. The Event will be set when the response
+        FIB has been returned by the adapter.
+
+    ReturnFib is an optional pointer to a FIB that if present the response FIB will
+        copied to.     
+        
+Return Value:
+
+    NT_SUCCESS if a Fib was returned to the caller.
+    NT_ERROR if event was an invalid event. 
+
+--*/
+{
+    PCOMM_FIB_CONTEXT FibContext = (PCOMM_FIB_CONTEXT) Context;
+    QUEUE_INDEX Index;
+    QUEUE_TYPES WhichQueue;
+    LARGE_INTEGER Timeout;
+    AAC_STATUS Status;
+	PAFA_COMM_ADAPTER Adapter = FibContext->Adapter;
+	ULONG DontInterrupt = FALSE;
+	PFIB Fib = FibContext->Fib;
+    IN PCOMM_QUE OurQueue;
+
+//	cmn_err( CE_NOTE, "^SendFib entered\n");
+
+    Timeout = FsaCommData.AdapterTimeout;
+
+    if (!(Fib->Header.XferState & HostOwned)) {
+        FsaCommPrint("SendFib was called with a xfer state not set to HostOwned!\n");
+		FsaCommLogEvent(FibContext,
+						FsaCommData.DeviceObject, 
+						FSAFS_FIB_INVALID, 
+						STATUS_UNSUCCESSFUL, 
+						BugCheckFileId | __LINE__,
+						FACILITY_FSAFS_ERROR_CODE,
+						NULL,
+						TRUE);			
+
+        return(STATUS_UNSUCCESSFUL);
+
+    }
+    
+    //
+    // There are 5 cases with the wait and reponse requested flags. The only invalid cases
+    // are if the caller requests to wait and  does not request a response and if the
+    // caller does not want a response and the Fib is not allocated from pool. If a response
+    // is not requesed the Fib will just be deallocaed by the DPC routine when the response
+    // comes back from the adapter. No further processing will be done besides deleting the
+    // Fib. We will have a debug mode where the adapter can notify the host it had a problem
+    // and the host can log that fact.
+
+    if (Wait && !ResponseExpected) {
+
+		FsaCommLogEvent(FibContext,
+						FsaCommData.DeviceObject, 
+						FSAFS_FIB_INVALID, 
+						STATUS_UNSUCCESSFUL, 
+						BugCheckFileId | __LINE__,
+						FACILITY_FSAFS_ERROR_CODE,
+						NULL,
+						TRUE);			
+
+        return(STATUS_UNSUCCESSFUL);
+
+    } else if (!Wait && ResponseExpected) {
+		Fib->Header.XferState |= (Async | ResponseExpected);
+		FIB_COUNTER_INCREMENT(FsaCommData.AsyncSent);
+	} else if (!Wait && !ResponseExpected) {
+		Fib->Header.XferState |= NoResponseExpected;
+		FIB_COUNTER_INCREMENT(FsaCommData.NoResponseSent);
+    } else if (Wait && ResponseExpected) {
+//        OsCv_init(&FibContext->FsaEvent, NULL, CV_DRIVER, NULL);
+        Fib->Header.XferState |= ResponseExpected;
+		FIB_COUNTER_INCREMENT(FsaCommData.NormalSent);
+    } 
+
+    Fib->Header.SenderData = (ULONG)FibContext; // so we can complete the io in the dpc routine
+
+    //
+    // Set FIB state to indicate where it came from and if we want a response from the
+    // adapter. Also load the command from the caller.
+    //
+
+    Fib->Header.SenderFibAddress = (ULONG)Fib;
+    Fib->Header.Command = Command;
+    Fib->Header.XferState |= SentFromHost;
+	FibContext->Fib->Header.Flags = 0;				// Zero the flags field - its internal only...
+    
+    //
+    // Set the size of the Fib we want to send to the adapter
+    //
+
+    Fib->Header.Size = sizeof(FIB_HEADER) + Size;
+    if (Fib->Header.Size > Fib->Header.SenderSize) {
+        return(STATUS_BUFFER_OVERFLOW);
+    }                
+
+    //
+    // Get a queue entry connect the FIB to it and send an notify the adapter a command is ready.
+    //
+            
+    if (Priority == FsaHigh) {
+        Fib->Header.XferState |= HighPriority;
+        WhichQueue = AdapHighCmdQueue;
+		OurQueue = &Adapter->CommRegion->AdapHighCmdQue;
+    } else {
+        Fib->Header.XferState |= NormalPriority;
+        WhichQueue = AdapNormCmdQueue;
+		OurQueue = &Adapter->CommRegion->AdapNormCmdQue;
+    }
+
+#ifdef GATHER_FIB_TIMES
+	if (GatherFibTimes) {
+		
+		if (Command == NuFileSystem) {
+		
+			FSACOMMAND FsaCommand;
+			PREAD ReadCommand;
+			PWRITE WriteCommand;
+			int Index;
+			
+			FsaCommand = (FSACOMMAND)Fib->data[0];
+			
+			switch (FsaCommand) {
+			
+				case Read:
+
+					ReadCommand = (PREAD)Fib->data;
+
+					Index = ReadCommand->ByteCount >> 9;		// divide by 512
+
+					FibContext->FibTimesPtr = &Adapter->FibTimes->Read[Index];
+
+					break;
+
+				case Write:
+				
+					WriteCommand = (PWRITE)Fib->data;
+					
+					Index = WriteCommand->ByteCount >> 9;		// divide by 512
+					
+					FibContext->FibTimesPtr = &Adapter->FibTimes->Write[Index];
+
+					break;
+
+				default:
+
+					FibContext->FibTimesPtr = &Adapter->FibTimes->FileSys[FsaCommand];
+
+					break;
+			}
+		} else {
+
+			FibContext->FibTimesPtr = &Adapter->FibTimes->Other;
+
+		}
+	}
+#endif
+
+#ifdef FIB_CHECKSUMS
+	if (FsaCommData.do_fib_checksums) {
+		int i;
+		unsigned char *pFib;
+		ULONG CheckSum = 0;
+
+		Fib->Header.FibCheckSum = 0;	// Zero out checksum before computing
+
+		pFib = (unsigned char *)Fib;
+		for (i = 0; i < Fib->Header.Size; i++) {
+			CheckSum += *pFib++;
+		}
+		Fib->Header.FibCheckSum = CheckSum;
+	}
+#endif
+
+
+    if ( GetQueueEntry( Adapter, &Index, WhichQueue, Fib, TRUE, FibContext, &DontInterrupt) != FSA_SUCCESS ) {
+
+
+        return(STATUS_UNSUCCESSFUL);
+        //FsaBugCheck(IrpContext, Index, WhichQueue);
+    }
+
+#ifdef commdebug
+    FsaCommPrint("SendFib: inserting a queue entry at index %d.\n",Index);
+    FsaCommPrint("Fib contents:.\n");
+    FsaCommPrint("  Command =               %d.\n", Fib->Header.Command);
+    FsaCommPrint("  XferState  =            %x.\n", Fib->Header.XferState );
+    FsaCommPrint("  Send Fib low address =  %x.\n", Fib->Header.SenderFibAddressLow);
+    FsaCommPrint("  Send Fib high address = %x.\n",  Fib->Header.SenderFibAddressHigh);
+	FsaCommPrint("  Sender data low =		%x.\n", Fib->Header.SenderDataLow);
+	FsaCommPrint("  Sender data High =		%x.\n", Fib->Header.SenderDataHigh);    	
+    FsaCommPrint("  Rec Fib address low =   %x.\n", Fib->Header.ReceiverFibAddressLow);        
+#endif
+
+	//
+	// Fill in the Callback and CallbackContext if we are not going to wait.
+	//
+
+	if (!Wait) {
+
+		FibContext->FibCallback = FibCallback;
+		FibContext->FibCallbackContext = FibCallbackContext;
+
+	}
+
+#ifdef GATHER_FIB_TIMES    
+	if (GatherFibTimes) {
+		FibContext->FibTimeStamp.QuadPart = KeQueryPerformanceCounter(NULL).QuadPart >> 7;
+	}
+#endif // GATHER_FIB_TIMES
+
+    FIB_COUNTER_INCREMENT(FsaCommData.FibsSent);
+
+#ifdef unix_fib_timeout
+	// 
+	// Put this fib onto the Outstanding I/O queue and increment the number of outstanding fibs.
+	//
+
+	KeQueryTickCount( &FibContext->TimeoutValue );
+	FibContext->TimeoutValue.QuadPart += FsaCommData.FibTimeoutIncrement;
+#endif
+
+	InsertTailList( &OurQueue->OutstandingIoQueue, &FibContext->QueueEntry );
+	OurQueue->NumOutstandingIos++;
+
+	FibContext->FibComplete = 0;
+
+    if ( InsertQueueEntry( Adapter, Index, WhichQueue, (DontInterrupt & FsaCommData.EnableInterruptModeration)) != FSA_SUCCESS ) {
+
+        return(STATUS_UNSUCCESSFUL);
+        //FsaBugCheck(IrpContext, Index, WhichQueue);
+    }
+
+    //
+    // If the caller wanted us to wait for response wait now. 
+    // If Timeouts are enabled than set the timeout otherwise wait forever.
+	//
+    
+    FSA_DO_PERF_INC(FibsSent)
+
+    if (Wait) {
+
+		OsCvLockAcquire( FibContext->FsaEventMutex );
+
+		while (FibContext->FibComplete == 0) {
+
+			OsCv_wait( &FibContext->FsaEvent, FibContext->FsaEventMutex );
+
+		}	
+
+		OsCvLockRelease( FibContext->FsaEventMutex );
+
+		if ( (FibContext->Flags & FIB_CONTEXT_FLAG_TIMED_OUT) ) {
+
+            return(STATUS_IO_TIMEOUT);
+
+        } else {
+
+            return(STATUS_SUCCESS);
+		}
+    }
+
+    //
+    // If the user does not want a response than return success otherwise return pending
+    // 
+
+	ASSERT( FibCallback );
+
+    if (ResponseExpected)
+        return(STATUS_PENDING);
+    else
+        return(STATUS_SUCCESS);
+}
+
+BOOLEAN
+GetConsumerEntry(
+	IN PAFA_COMM_ADAPTER Adapter,
+    PCOMM_QUE OurQueue,
+    OUT PQUEUE_ENTRY *Entry
+    )
+/*++
+
+Routine Description:
+
+    Will return a pointer to the entry on the top of the queue requested that we are a consumer
+    of, and return the address of the queue entry. It does not change the state of the queue. 
+
+Arguments:
+
+    OurQueue - is the queue the queue entry should be removed from.
+
+    Entry - is a pointer where the address  of the queue entry should be returned.    
+    
+Return Value:
+
+    TRUE if there was a queue entry on the response queue for the host to consume.
+    FALSE if there were no queue entries to consume.
+    
+--*/
+
+{
+    QUEUE_INDEX Index;
+	BOOLEAN status;
+
+    if (*OurQueue->Headers.ProducerIndex == *OurQueue->Headers.ConsumerIndex) {
+		status = FALSE;
+	} else {
+
+	    //
+	    // The consumer index must be wrapped if we have reached the end of
+	    // the queue. 
+	    // Else we just use the entry pointed to by the header index
+	    //
+	    
+	    if (*OurQueue->Headers.ConsumerIndex >= OurQueue->QueueEntries) 
+			Index = 0;		
+	    else
+	        Index = *OurQueue->Headers.ConsumerIndex;
+	    
+	    *Entry = OurQueue->BaseAddress + Index;
+
+#ifdef commdebug
+	    FsaCommPrint("Got a QE at Index %d, QE Addrss of %x.\n",Index,*Entry);
+#endif
+		status = TRUE;
+	}
+
+    return(status);
+}
+
+BOOLEAN
+ConsumerEntryAvailable(
+	IN PAFA_COMM_ADAPTER Adapter,
+    PCOMM_QUE OurQueue
+	)
+{
+    return (*OurQueue->Headers.ProducerIndex != *OurQueue->Headers.ConsumerIndex);
+}
+
+VOID
+FreeConsumerEntry(
+	IN PAFA_COMM_ADAPTER Adapter,
+    PCOMM_QUE OurQueue,
+    QUEUE_TYPES WhichQueue
+    )
+/*++
+
+Routine Description:
+
+    Frees up the current top of the queue we are a consumer of. If the queue was full
+    notify the producer that the queue is no longer full.
+
+Arguments:
+
+    OurQueue - is the queue we will free the current consumer entry on.
+
+Return Value:
+
+    TRUE if there was a queue entry on the response queue for the host to consume.
+    FALSE if there were no queue entries to consume.
+    
+--*/
+
+{
+    BOOLEAN WasFull = FALSE;
+    HOST_2_ADAP_EVENT Notify;
+
+    if (*OurQueue->Headers.ProducerIndex+1 == *OurQueue->Headers.ConsumerIndex)
+        WasFull = TRUE;
+        
+    if (*OurQueue->Headers.ConsumerIndex >= OurQueue->QueueEntries)
+        *OurQueue->Headers.ConsumerIndex = 1;
+    else
+        *OurQueue->Headers.ConsumerIndex += 1;
+        
+    if (WasFull) {
+        switch (WhichQueue) {
+
+            case HostNormCmdQueue:
+                Notify = HostNormCmdNotFull;
+                break;
+            case HostHighCmdQueue:
+                Notify = HostHighCmdNotFull;
+                break;
+
+            case HostNormRespQueue:
+                Notify = HostNormRespNotFull;
+                break;
+
+            case HostHighRespQueue:
+                Notify = HostHighRespNotFull;
+                break;
+
+        }
+        NotifyAdapter(Adapter, Notify);
+    }
+
+}        
+
+AAC_STATUS
+CompleteAdapterFib(
+	IN PFIB_CONTEXT Context,
+    IN USHORT Size
+    )
+/*++
+
+Routine Description:
+
+    Will do all necessary work to complete a FIB that was sent from the adapter.
+
+Arguments:
+
+    Fib is a pointer to the FIB that caller wishes to complete processing on. 
+
+    Size - Size of the completion Packet(Opitional). If not present than the current
+           largest size in the Fib will be used
+    
+	Adapter - Pointer to which adapter sent this FIB
+
+Return Value:
+
+    NT_SUCCESS if a Fib was returned to the caller.
+    NT_ERROR if event was an invalid event. 
+
+--*/
+{
+	PCOMM_FIB_CONTEXT FibContext = Context;
+    PFIB Fib = FibContext->Fib;
+	PAFA_COMM_ADAPTER Adapter = FibContext->Adapter;
+    ULONG DontInterrupt = FALSE;
+
+    if (Fib->Header.XferState == 0)
+        return(STATUS_SUCCESS);
+
+    //
+    // If we plan to do anything check the structure type first.
+    // 
+
+    if ( Fib->Header.StructType != TFib ) {
+        FsaCommPrint("Error CompleteFib called with a non Fib structure.\n");
+        return(STATUS_UNSUCCESSFUL);
+    }
+
+    //
+    // This block handles the case where the adapter had sent us a command and we
+    // have finished processing the command. We call completeFib when we are done
+    // processing the command and want to send a response back to the adapter. This
+    // will send the completed cdb to the adapter.
+    //
+
+    if (Fib->Header.XferState & SentFromAdapter) {
+        Fib->Header.XferState |= HostProcessed;
+        if (Fib->Header.XferState & HighPriority) {
+            QUEUE_INDEX Index;
+            
+            if (Size) {
+                Size += sizeof(FIB_HEADER);
+                if (Size > Fib->Header.SenderSize) 
+                    return(STATUS_BUFFER_OVERFLOW);
+                Fib->Header.Size = Size;
+            }
+
+            if (GetQueueEntry(Adapter, &Index, AdapHighRespQueue, Fib, TRUE, NULL, &DontInterrupt) != STATUS_SUCCESS) {
+                FsaCommPrint("CompleteFib got an error geting a queue entry for a response.\n");
+                return(FSA_FATAL);
+            }
+            if (InsertQueueEntry(Adapter, 
+            					Index, 
+            					AdapHighRespQueue, 
+            					(DontInterrupt & (BOOLEAN)FsaCommData.EnableInterruptModeration)) != STATUS_SUCCESS) {
+                FsaCommPrint("CompleteFib failed while inserting entry on the queue.\n");
+            }
+        } else if (Fib->Header.XferState & NormalPriority) {
+            QUEUE_INDEX Index;
+
+            if (Size) {
+                Size += sizeof(FIB_HEADER);
+                if (Size > Fib->Header.SenderSize) 
+                    return(STATUS_BUFFER_OVERFLOW);
+                Fib->Header.Size = Size;
+            }
+            
+            if (GetQueueEntry(Adapter, &Index, AdapNormRespQueue, Fib, TRUE, NULL, &DontInterrupt) != STATUS_SUCCESS) {
+                FsaCommPrint("CompleteFib got an error geting a queue entry for a response.\n");
+                return(FSA_FATAL);
+            }
+            if (InsertQueueEntry(Adapter, 
+            					Index, 
+            					AdapNormRespQueue, 
+            					(DontInterrupt & (BOOLEAN)FsaCommData.EnableInterruptModeration)) != STATUS_SUCCESS) {
+                FsaCommPrint("CompleteFib failed while inserting entry on the queue.\n");
+            }
+		}
+    } else {
+        cmn_err(CE_WARN, "CompleteFib: Unknown xferstate detected.\n");
+		FsaBugCheck(0,0,0);
+    }   
+    return(STATUS_SUCCESS);
+}
+
+AAC_STATUS
+CompleteFib(
+	IN PFIB_CONTEXT Context
+    )
+/*++
+
+Routine Description:
+
+    Will do all necessary work to complete a FIB. If the caller wishes to
+    reuse the FIB after post processing has been completed Reinitialize
+    should be called set to TRUE, otherwise the FIB will be returned to the
+    free FIB pool. If Reinitialize is set to TRUE then the FIB header is
+    reinitialzied and is ready for reuse on return from this routine.
+
+Arguments:
+
+    Fib is a pointer to the FIB that caller wishes to complete processing on. 
+
+    Size - Size of the completion Packet(Opitional). If not present than the current
+           largest size in the Fib will be used
+    
+    Reinitialize is a boolean which determines if the routine will ready the
+        completed FIB for reuse(TRUE) or not(FALSE).
+
+Return Value:
+
+    NT_SUCCESS if a Fib was returned to the caller.
+    NT_ERROR if event was an invalid event. 
+
+--*/
+{
+    PCOMM_FIB_CONTEXT FibContext = (PCOMM_FIB_CONTEXT) Context;
+	PAFA_COMM_ADAPTER Adapter = FibContext->Adapter;
+	PFIB Fib = FibContext->Fib;
+
+    //
+    // Check for a fib which has already been completed
+    //
+
+//	ASSERT(Fib->Header.XferState & AdapterProcessed);
+    if (Fib->Header.XferState == 0)
+        return(STATUS_SUCCESS);
+
+    //
+    // If we plan to do anything check the structure type first.
+    // 
+
+    if ( Fib->Header.StructType != TFib ) {
+        FsaCommPrint("Error CompleteFib called with a non Fib structure.\n");
+        return(STATUS_UNSUCCESSFUL);
+    }
+
+#if 0
+//#if FSA_ADAPTER_METER
+	//
+	// Meter the completion
+	//
+	fsaMeterEnd(						// meter the end of an operation
+		&(Adapter->FibMeter),			// .. the meter
+		IrpContext->FibMeterType,		// .. type of operation
+		&(IrpContext->FibStartTime),	// .. ptr to operation start timestamp
+		FibGetMeterSize(Fib,			// .. number of bytes in operation
+				IrpContext->FibMeterType, 
+				IrpContext->FibSubCommand));
+#endif // FSA_ADAPTER_METER
+	
+    //
+    // This block completes a cdb which orginated on the host and we just need
+    // to deallocate the cdb or reinit it. At this point the command is complete
+    // that we had sent to the adapter and this cdb could be reused.
+    //
+	
+    if ( (Fib->Header.XferState & SentFromHost) &&
+         (Fib->Header.XferState & AdapterProcessed)) {
+        
+        ASSERT(FibContext->LogicalFibAddress.LowPart != 0);
+
+        return( DeallocateFib(FibContext) ); 
+	
+    //
+    // This handles the case when the host has aborted the I/O to the
+    // adapter because the adapter is not responding
+    //
+
+    } else if (Fib->Header.XferState & SentFromHost) {
+
+        ASSERT(FibContext->LogicalFibAddress.LowPart != 0);
+
+
+        return( DeallocateFib(FibContext) ); 
+
+    } else if (Fib->Header.XferState & HostOwned) {
+
+        return(DeallocateFib(FibContext));
+
+    } else {
+        cmn_err(CE_WARN, "CompleteFib: Unknown xferstate detected.\n");
+		FsaBugCheck(0,0,0);
+    }   
+    return(STATUS_SUCCESS);
+}
+
+VOID
+HandleDriverAif(
+    IN PAFA_COMM_ADAPTER Adapter,
+	IN PCOMM_FIB_CONTEXT FibContext
+    )
+/*++
+
+Routine Description:
+
+	This routine handles a driver notify fib from the adapter and dispatches it to 
+	the appropriate routine for handling.
+
+Arguments:
+
+	Adapter - Which adapter this fib is from
+	FibContext - Pointer to FibContext from adapter.
+    
+Return Value:
+
+    Nothing.
+    
+--*/
+{
+	PFIB Fib = FibContext->Fib;
+	PAFA_CLASS_DRIVER ClassDriver;
+	BOOLEAN Handled = FALSE;
+
+
+	//
+	// First loop through all of the class drivers to give them a chance to handle
+	// the Fib.
+	//
+
+	ClassDriver = Adapter->ClassDriverList;
+
+	while (ClassDriver) {
+
+		if (ClassDriver->HandleAif) {
+
+			if (ClassDriver->HandleAif( ClassDriver->ClassDriverExtension, FibContext ) ) {
+
+				Handled = TRUE;
+				break;
+
+			}
+		}
+
+		ClassDriver = ClassDriver->Next;
+	}
+
+	if (!Handled) {
+
+		//
+		// Set the status of this FIB to be Invalid parameter.
+		//
+
+//		*(FSASTATUS *)Fib->data = ST_INVAL;
+		*(FSASTATUS *)Fib->data = ST_OK;
+
+
+		CompleteAdapterFib(FibContext, sizeof(FSASTATUS));
+
+	}
+}
+
+int
+NormCommandThread(
+    IN PAFA_COMM_ADAPTER Adapter
+    )
+/*++
+
+Routine Description:
+
+    Waits on the commandready event in it's queue. When the event gets set it will
+    pull FIBs off it's queue. It will continue to pull FIBs off till the queue is empty.
+    When the queue is empty it will wait for more FIBs.
+
+Arguments:
+
+    Context is used. All data os global
+    
+Return Value:
+    Nothing.
+    
+--*/
+{
+    PFIB Fib, NewFib;
+	COMM_FIB_CONTEXT FibContext; // for error logging
+    KIRQL SavedIrql;
+	PCOMM_REGION CommRegion = Adapter->CommRegion;
+	PLIST_ENTRY Entry;
+	PGET_ADAPTER_FIB_CONTEXT AdapterFibContext;
+
+	//
+	// We can only have one thread per adapter for AIF's.
+	//
+
+	if (Adapter->AifThreadStarted) {
+		return (EINVAL);
+	}
+
+// cmn_err(CE_NOTE, "AIF thread started");
+
+	//
+	// Let the DPC know it has a place to send the AIF's to.
+	//
+
+	Adapter->AifThreadStarted = TRUE;
+
+	RtlZeroMemory(&FibContext, sizeof(COMM_FIB_CONTEXT));
+
+	OsSpinLockAcquire(CommRegion->HostNormCmdQue.QueueLock);
+
+    while (TRUE) {
+
+		//
+		// NOTE : the QueueLock is held at the top of each loop.
+		//
+
+		ASSERT(OsSpinLockOwned(CommRegion->HostNormCmdQue.QueueLock));
+
+		while (!IsListEmpty(&(CommRegion->HostNormCmdQue.CommandQueue))) {
+			PLIST_ENTRY Entry;
+			PAIFCOMMANDTOHOST AifCommandToHost;
+
+			Entry = RemoveHeadList(&(CommRegion->HostNormCmdQue.CommandQueue));
+
+			OsSpinLockRelease(CommRegion->HostNormCmdQue.QueueLock);
+
+			Fib = CONTAINING_RECORD( Entry, FIB, Header.FibLinks );
+						
+			//
+			// We will process the FIB here or pass it to a worker thread that is TBD. We Really
+			// can't do anything at this point since we don't have anything defined for this thread to
+			// do.
+			//
+			
+			// cmn_err(CE_NOTE, "Got Fib from the adapter with a NORMAL priority, command 0x%x.\n", Fib->Header.Command);
+
+			RtlZeroMemory( &FibContext, sizeof(COMM_FIB_CONTEXT) );
+
+
+		    FibContext.NodeTypeCode = FSAFS_NTC_FIB_CONTEXT;
+		    FibContext.NodeByteSize = sizeof( COMM_FIB_CONTEXT );
+			FibContext.Fib = Fib;
+			FibContext.FibData = Fib->data;
+			FibContext.Adapter = Adapter;
+
+			
+			//
+			// We only handle AifRequest fibs from the adapter.
+			//
+
+			ASSERT(Fib->Header.Command == AifRequest);
+
+
+			AifCommandToHost = (PAIFCOMMANDTOHOST) Fib->data;
+
+			if (AifCommandToHost->command == AifCmdDriverNotify) {
+
+
+
+				HandleDriverAif( Adapter, &FibContext );
+
+			} else {
+			
+
+				OsCvLockAcquire(Adapter->AdapterFibMutex);
+
+				Entry = Adapter->AdapterFibContextList.Flink;
+
+				//
+				// For each Context that is on the AdapterFibContextList, make a copy of the
+				// fib, and then set the event to wake up the thread that is waiting for it.
+				//
+
+				while (Entry != &Adapter->AdapterFibContextList) {
+
+					//
+					// Extract the AdapterFibContext
+					//
+
+					AdapterFibContext = CONTAINING_RECORD( Entry, GET_ADAPTER_FIB_CONTEXT, NextContext );
+
+//  Warning: sleep possible while holding spinlock
+					NewFib = OsAllocMemory(sizeof(FIB), OS_ALLOC_MEM_SLEEP);
+
+					if (NewFib) {
+
+						//
+						// Make the copy of the FIB
+						//
+
+						RtlCopyMemory(NewFib, Fib, sizeof(FIB));
+
+						//
+						// Put the FIB onto the AdapterFibContext's FibList
+						//
+
+						InsertTailList(&AdapterFibContext->FibList, &NewFib->Header.FibLinks);
+						AdapterFibContext->FibCount++;
+
+						// 
+						// Set the event to wake up the thread that will waiting.
+						//
+
+						OsCv_signal(&AdapterFibContext->UserEvent);
+
+					} else {
+
+
+					}
+
+					Entry = Entry->Flink;
+				}
+
+				//
+				// Set the status of this FIB
+				//
+
+				*(FSASTATUS *)Fib->data = ST_OK;
+				
+				CompleteAdapterFib( &FibContext, sizeof(FSASTATUS) );
+
+				OsCvLockRelease(Adapter->AdapterFibMutex);
+
+			}
+
+			OsSpinLockAcquire(CommRegion->HostNormCmdQue.QueueLock);
+
+		}
+
+		//
+		// There are no more AIF's,  call cv_wait_sig to wait for more
+		// to process.
+		//
+
+		// cmn_err(CE_NOTE, "no more AIF's going to sleep\n");
+
+		if (OsCv_wait_sig( &(CommRegion->HostNormCmdQue.CommandReady), 
+						 CommRegion->HostNormCmdQue.QueueLock ) == 0) {
+
+			OsSpinLockRelease(CommRegion->HostNormCmdQue.QueueLock);
+
+			Adapter->AifThreadStarted = FALSE;
+
+			// cmn_err(CE_NOTE, "AifThread awoken by a signal\n");
+			
+			return (EINTR);
+			
+		}				 
+
+		// cmn_err(CE_NOTE, "^Aif thread awake, going to look for more AIF's\n");
+
+	}
+}
+    
+
+PVOID
+FsaGetFibData(
+	IN PFIB_CONTEXT Context
+	)
+{
+    PCOMM_FIB_CONTEXT FibContext = (PCOMM_FIB_CONTEXT) Context;
+
+	return ((PVOID)FibContext->Fib->data);
+}	    
+                              
+
+#ifdef API_THROTTLE
+
+void ThrottlePeriodEndDpcRtn(
+    IN PKDPC Dpc,
+    IN PVOID DeferredContext,
+    IN PVOID SystemArgument1,
+    IN PVOID SystemArgument2
+    )
+/*++
+
+Routine Description:
+
+    This routine is called as a DPC when a throttle period expires. It
+	restarts all threads suspended due to the throttling flow control.
+	
+	The throttling counted semaphore is signalled for all waiting threads
+	and the indicator of throttling active is cleared.
+
+Arguments:
+
+    Dpc				- Pointer to Dpc structure. Not used.
+	DefferedContext - Pointer to per-adapter context. This is used to locate the
+					  throttle information for this adapter.
+    SystemArgument1	- Not used
+	SystemArgument2 - Not used
+	
+Return Value:
+
+	None.
+
+--*/
+{
+	PCOMM_REGION CommRegion;
+	PAFA_COMM_ADAPTER Adapter = (PAFA_COMM_ADAPTER) DeferredContext;
+
+	CommRegion = Adapter->CommRegion;
+
+	//
+	// Acquire the spinlock protecting the throttle status.
+	//
+	OsSpinLockAcquire(CommRegion->AdapNormCmdQue.QueueLock);
+
+	FsaCommPrint("ThrottlePeriodEndDpc\n");
+
+	//
+	// Check that the timer has fired as many times as it was set !
+	//
+
+	CommRegion->ThrottleTimerFires++;
+	ASSERT(CommRegion->ThrottleTimerFires == CommRegion->ThrottleTimerSets);
+
+	//
+	// The throttle period is now over. Restart all threads waiting
+	// on the throttle being released.
+	// Clear the throttle active indicator. This will allow new FIBs
+	// to be sent to the adapter once we release the spinlock on exiting
+	// the DPC. This means all restarted threads will be runnable
+	// threads by then.
+	//
+
+	ASSERT(CommRegion->ThrottleActive == TRUE);		// The throttle had better be on !
+	CommRegion->ThrottleActive = FALSE;				// This allows new data FIBs to go to the adapter on dpc exit
+
+	OsSpinLockRelease(CommRegion->AdapNormCmdQue.QueueLock);
+}
+
+#endif // #ifdef API_THROTTLE
+
diff -BburN linux.orig/drivers/scsi/aacraid/dpcsup.c linux/drivers/scsi/aacraid/dpcsup.c
--- linux.orig/drivers/scsi/aacraid/dpcsup.c	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/dpcsup.c	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,553 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  dpcsup.c
+ *
+ * Abstract: All DPC processing routines for the cyclone board occur here.
+ *
+ *
+ --*/
+#include "comprocs.h"
+
+
+//
+//  The Bug check file id for this module
+//
+
+#define BugCheckFileId                   (FSAFS_BUG_CHECK_DPCSUP)
+
+#define Dbg                              (DEBUG_TRACE_DPCSUP)
+
+u_int
+CommonNotFullDpc(
+	IN PCOMM_REGION CommRegion
+    )
+/*++
+
+Routine Description:
+
+    This DPC routine will be queued when the adapter interrupts us to let us know the queue is
+    no longer full. The Isr will pass the queue that we will set the not full event.
+
+Arguments:
+
+    Dpc - Pointer to this routine.
+
+    Dummy - is a pointer to the comm region which is global so we don't need it anyway
+
+    Queue is a pointer to the queue structure we will operate on.
+
+    MoreData2 are DPC parameters we don't need for this function. Maybe we can add some accounting
+        stuff in here.
+
+Return Value:
+    Nothing.
+
+--*/
+{
+
+#ifdef unix_queue_full
+    KeSetEvent(&Queue->QueueFull, 0, FALSE);
+#endif
+
+}
+
+int GatherFibTimes = 0;
+
+// XXX - hack this in until I figure out which header file should contain it. <smb>
+extern ULONG
+FibGetMeterSize(
+    PFIB pFib,
+	ULONG MeterType,
+	char SubCommand
+	);
+
+u_int
+HostResponseNormalDpc(
+    IN PCOMM_QUE OurQueue
+    )
+/*++
+
+Routine Description:
+
+    This DPC routine will be queued when the adapter interrupts us to let us know there
+    is a response on our normal priority queue. We will pull off all QE there are and wake
+    up all the waiters before exiting. We will take a spinlock out on the queue before operating
+    on it.
+
+Arguments:
+
+    Dpc - Pointer to this routine.
+
+    OurQueue is a pointer to the queue structure we will operate on.
+
+    MoreData1&2 are DPC parameters we don't need for this function. Maybe we can add some accounting
+        stuff in here.
+
+Return Value:
+    Nothing.
+
+--*/
+{
+    PAFA_COMM_ADAPTER Adapter = OurQueue->Adapter;
+    PQUEUE_ENTRY QueueEntry;
+    PFIB Fib;
+	PCOMM_FIB_CONTEXT FibContext;
+    int Consumed = 0;
+	KIRQL OldIrql;
+
+	LARGE_INTEGER ResponseAllocSize;
+
+#ifdef commdebug
+    FsaCommPrint("entering the host normal reponse dpc routine.\n");
+#endif
+
+//	cmn_err( CE_CONT, "^HostNormalResponseDpc entered\n");
+
+	OsSpinLockAcquire( OurQueue->QueueLock );	
+
+    //
+    // Keep pulling response QEs off the response queue and waking
+    // up the waiters until there are no more QEs. We then return
+    // back to the system. If no response was requesed we just
+    // deallocate the Fib here and continue.
+    //
+
+ loop:
+    while ( GetConsumerEntry( Adapter, OurQueue, &QueueEntry) ) {
+
+		int IsFastResponse;
+
+		IsFastResponse = (int) (QueueEntry->FibAddress & 0x01);
+		Fib = (PFIB) (QueueEntry->FibAddress & ~0x01);
+
+		FreeConsumerEntry(Adapter, OurQueue, HostNormRespQueue);
+
+#ifdef API_THROTTLE
+		//
+		// Throttling support to improve CLI responsiveness under load.
+		// Check if this FIB was participating in throttle I/O.
+		// If so, take the spinlock to protect the throttle values
+		// and count the completion. Then signal the next waiting
+		// thread.
+		//
+
+		if ((Fib->Header.Flags & ThrottledFib) != 0) {
+			PCOMM_REGION CommRegion = Adapter->CommRegion;
+
+			FsaCommPrint("NormResponseDpc Throttled FIB Completion - FIB: %x, ThrottledFibs: %d\n",
+						Fib, CommRegion->ThrottleOutstandingFibs);
+
+			//
+			// Account for the completion.
+			//
+
+			ASSERT(CommRegion->ThrottleOutstandingFibs > 0);
+			CommRegion->ThrottleOutstandingFibs--;									// One less FIB outstanding
+
+			KeReleaseSemaphore(&CommRegion->ThrottleReleaseSema,
+							   0,
+							   1,						// Release a waiting thread.
+							   FALSE);
+
+		
+		}	// End of throttle code
+#endif		// #ifdef API_THROTTLE
+
+		FibContext = (PCOMM_FIB_CONTEXT)Fib->Header.SenderData;
+
+		ASSERT(FibContext->Fib == Fib);
+
+		//
+		// Remove this FibContext from the Outstanding I/O queue.
+		// But only if it has not already been timed out.
+		//
+		// If the fib has been timed out already, then just continue.
+		// The caller has already been notified that the fib timed out.
+		//
+
+		if (!(FibContext->Flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
+
+			RemoveEntryList( &FibContext->QueueEntry );
+			Adapter->CommRegion->AdapNormCmdQue.NumOutstandingIos--;
+
+		} else {
+
+			FsaCommLogEvent(FibContext,
+							FsaCommData.DeviceObject, 
+							FSAFS_TIMED_OUT_FIB_COMPLETED,
+							STATUS_UNSUCCESSFUL, 
+							BugCheckFileId | __LINE__,
+							FACILITY_FSAFS_ERROR_CODE,
+							NULL,
+							TRUE);			
+
+			continue;
+
+		}
+
+		OsSpinLockRelease( OurQueue->QueueLock );
+
+		if (IsFastResponse) {
+
+			//
+			// doctor the fib
+			//
+
+			*(FSASTATUS *)Fib->data = ST_OK;
+
+			Fib->Header.XferState |= AdapterProcessed;
+
+		}
+
+#ifdef GATHER_FIB_TIMES
+		if (GatherFibTimes) {
+
+			LARGE_INTEGER FibTime, FibTimeDelta;
+			LARGE_INTEGER AdapterFibTimeDelta;
+			PFIB_TIMES FibTimesPtr;
+			ULONG Index;
+			ULONG LowAdapterFibTimeDelta;
+
+			FibTimesPtr = FibContext->FibTimesPtr;
+
+			FibTime.QuadPart = KeQueryPerformanceCounter(NULL).QuadPart >> 7;
+
+			FibTimeDelta = RtlLargeIntegerSubtract(FibTime, FibContext->FibTimeStamp);
+
+			if (RtlLargeIntegerLessThan(FibTimeDelta, FibTimesPtr->Minimum)) {
+				FibTimesPtr->Minimum = FibTimeDelta;
+			}
+			if (RtlLargeIntegerGreaterThan(FibTimeDelta, FibTimesPtr->Maximum)) {
+				FibTimesPtr->Maximum = FibTimeDelta;
+			}
+
+			FibTimesPtr->TotalTime = RtlLargeIntegerAdd(FibTimesPtr->TotalTime, FibTimeDelta);
+			FibTimesPtr->TotalFibs = RtlLargeIntegerAdd(FibTimesPtr->TotalFibs, RtlConvertLongToLargeInteger(1));
+
+			if (Fib->Header.ReceiverTimeDone > Fib->Header.ReceiverTimeStart) {
+				AdapterFibTimeDelta = RtlConvertLongToLargeInteger(Fib->Header.ReceiverTimeDone - Fib->Header.ReceiverTimeStart);
+			} else {
+				AdapterFibTimeDelta = RtlConvertLongToLargeInteger(Fib->Header.ReceiverTimeDone + 
+																   ((ULONG)(0xffffffff) - Fib->Header.ReceiverTimeStart));
+			}
+
+			if (RtlLargeIntegerLessThan(AdapterFibTimeDelta, FibTimesPtr->AdapterMinimum)) {
+				FibTimesPtr->AdapterMinimum = AdapterFibTimeDelta;
+			}
+			if (RtlLargeIntegerGreaterThan(AdapterFibTimeDelta, FibTimesPtr->AdapterMaximum)) {
+				FibTimesPtr->AdapterMaximum = AdapterFibTimeDelta;
+			}
+
+			FibTimesPtr->AdapterTotalTime = RtlLargeIntegerAdd(FibTimesPtr->AdapterTotalTime, AdapterFibTimeDelta);
+
+			if (GatherFibTimes == 1) {
+				LowAdapterFibTimeDelta = AdapterFibTimeDelta.LowPart;
+			} else {
+				LowAdapterFibTimeDelta = FibTimeDelta.LowPart;
+			}
+
+			if ((LowAdapterFibTimeDelta & 0xffffff00) == 0) {
+
+				Index = (LowAdapterFibTimeDelta & 0xf0) >> 4;
+
+			} else if ((LowAdapterFibTimeDelta & 0xfffff000) == 0) {
+
+				Index = 16 + ((LowAdapterFibTimeDelta & 0xf00) >> 8);
+
+			} else if ((LowAdapterFibTimeDelta & 0xffff0000) == 0) {
+
+				Index = 32 + ((LowAdapterFibTimeDelta & 0xf000) >> 12);
+
+			} else if ((LowAdapterFibTimeDelta & 0xfff00000) == 0) {
+
+				Index = 48 + ((LowAdapterFibTimeDelta & 0xf0000) >> 16);
+
+			} else {
+				Index = 64;
+			}
+
+			FibTimesPtr->AdapterBuckets[Index]++;
+
+		}
+#endif
+
+		ASSERT((Fib->Header.XferState & (AdapterProcessed | HostOwned | SentFromHost)) == (AdapterProcessed | HostOwned | SentFromHost));
+
+		FIB_COUNTER_INCREMENT(FsaCommData.FibRecved);
+
+		ASSERT(FsaCommData.FibsSent >= FsaCommData.FibRecved);
+
+
+		if (Fib->Header.Command == NuFileSystem) {
+
+			FSASTATUS *pStatus = (FSASTATUS *)Fib->data;
+
+			if (*pStatus & 0xffff0000) {
+
+				ULONG Hint = *pStatus;
+
+				*pStatus = ST_OK;
+
+/*
+				DbgPrint("Replacing hint in fid (drive = %d, f1 = 0x%x, f2 = 0x%x, hint = 0x%x, new_hint = 0x%x)\n", 
+						 IrpContext->NonPaged->FileId.fid_driveno,
+						 IrpContext->NonPaged->FileId.fid_f1,
+						 IrpContext->NonPaged->FileId.fid_f2,
+						 IrpContext->NonPaged->FileId.fid_hint,
+						 Hint);
+*/
+
+			}
+
+		}
+
+		if (Fib->Header.XferState & (NoResponseExpected | Async) ) {
+
+			ASSERT(FibContext->FibCallback);
+
+        	if (Fib->Header.XferState & NoResponseExpected)
+				FIB_COUNTER_INCREMENT(FsaCommData.NoResponseRecved);
+			else 
+				FIB_COUNTER_INCREMENT(FsaCommData.AsyncRecved);
+
+			//
+			// NOTE:  we can not touch the FibContext after this call, because it may have been
+			// deallocated.
+			//
+
+			FibContext->FibCallback(FibContext->FibCallbackContext, FibContext, STATUS_SUCCESS);
+
+		} else {
+
+			OsCvLockAcquire( FibContext->FsaEventMutex);
+
+			FibContext->FibComplete = 1;
+
+			OsCv_signal( &FibContext->FsaEvent );
+
+			OsCvLockRelease( FibContext->FsaEventMutex );
+
+			FIB_COUNTER_INCREMENT(FsaCommData.NormalRecved);
+			
+		}
+
+
+		Consumed++;
+
+		OsSpinLockAcquire( OurQueue->QueueLock );
+		
+    }
+
+	if (Consumed > FsaCommData.PeakFibsConsumed)
+		FsaCommData.PeakFibsConsumed = Consumed;
+
+	if (Consumed == 0) 
+		FsaCommData.ZeroFibsConsumed++;
+
+	if (FsaCommData.HardInterruptModeration) {
+
+		//
+		// Re-Enable the interrupt from the adapter, then recheck to see if anything has 
+		// been put on the queue.  This removes the race condition that exists between the
+		// last time we checked the queue, and when we re-enabled the interrupt.
+		//
+		// If there is something on the queue, then go handle it.
+		//
+
+		EnableInterrupt( Adapter, HostNormRespQue, FALSE );
+
+		if (ConsumerEntryAvailable( Adapter, OurQueue ) ) {
+
+			DisableInterrupt( Adapter, HostNormRespQue, FALSE );
+
+			goto loop;
+
+		}
+	}
+
+#ifdef commdebug
+    FsaCommPrint("Exiting host normal reponse dpc routine after consuming %d QE(s).\n",Consumed);
+#endif
+
+	OsSpinLockRelease( OurQueue->QueueLock );
+
+}
+
+u_int
+HostResponseHighDpc(
+    IN PCOMM_QUE OurQueue
+    )
+/*++
+
+Routine Description:
+
+    This DPC routine wiol be queued when the adapter interrupts us to let us know there
+    is a response on our high priority queue. We will pull off all QE there are and wake
+    up all the waiters before exiting. We will take a spinlock out on the queue before operating
+    on it.
+
+Arguments:
+
+    Dpc - Pointer to this routine.
+
+    OurQueue is a pointer to the queue structure we will operate on.
+
+    MoreData1&2 are DPC parameters we don't need for this function. Maybe we can add some accounting
+        stuff in here.
+
+Return Value:
+    Nothing.
+
+--*/
+{
+}
+
+u_int
+HostCommandHighDpc(
+    IN PCOMM_QUE OurQueue
+    )
+/*++
+
+Routine Description:
+
+    This DPC routine will be queued when the adapter interrupts us to let us know there
+    is a command on our high priority queue. We will pull off all QE there are and wake
+    up all the waiters before exiting. We will take a spinlock out on the queue before operating
+    on it.
+
+Arguments:
+
+    Dpc - Pointer to this routine.
+
+    OurQueue is a pointer to the queue structure we will operate on.
+
+    MoreData1&2 are DPC parameters we don't need for this function. Maybe we can add some accounting
+        stuff in here.
+
+Return Value:
+    Nothing.
+
+--*/
+{
+}
+
+
+u_int
+HostCommandNormDpc(
+    IN PCOMM_QUE OurQueue
+    )
+/*++
+
+Routine Description:
+
+    This DPC routine will be queued when the adapter interrupts us to let us know there
+    is a command on our normal priority queue. We will pull off all QE there are and wake
+    up all the waiters before exiting. We will take a spinlock out on the queue before operating
+    on it.
+
+Arguments:
+
+    Dpc - Pointer to this routine.
+
+    OurQueue is a pointer to the queue structure we will operate on.
+
+    MoreData1&2 are DPC parameters we don't need for this function. Maybe we can add some accounting
+        stuff in here.
+
+Return Value:
+    Nothing.
+
+--*/
+{
+    PAFA_COMM_ADAPTER Adapter = OurQueue->Adapter;
+    PQUEUE_ENTRY QueueEntry;
+
+	OsSpinLockAcquire( OurQueue->QueueLock );
+
+    //
+    // Keep pulling response QEs off the response queue and waking
+    // up the waiters until there are no more QEs. We then return
+    // back to the system.
+    //
+
+    while ( GetConsumerEntry( Adapter, OurQueue, &QueueEntry) ) {
+
+		PFIB Fib;
+
+		Fib = (PFIB)QueueEntry->FibAddress;
+
+
+		if (Adapter->AifThreadStarted) {
+
+
+//			cmn_err(CE_CONT, "^Received AIF, putting onto command queue\n");
+
+
+	        InsertTailList(&OurQueue->CommandQueue, &Fib->Header.FibLinks);
+ 	        FreeConsumerEntry(Adapter, OurQueue, HostNormCmdQueue);
+	        OsCv_signal(&OurQueue->CommandReady);
+
+
+
+		} else {
+
+
+
+			COMM_FIB_CONTEXT FibContext;
+
+		
+
+ 	        FreeConsumerEntry(Adapter, OurQueue, HostNormCmdQueue);
+
+
+
+			OsSpinLockRelease( OurQueue->QueueLock );
+
+
+
+//			cmn_err(CE_CONT, "^Received AIF, thread not started\n");
+
+
+			RtlZeroMemory( &FibContext, sizeof(COMM_FIB_CONTEXT) );
+
+		    FibContext.NodeTypeCode = FSAFS_NTC_FIB_CONTEXT;
+		    FibContext.NodeByteSize = sizeof( COMM_FIB_CONTEXT );
+			FibContext.Fib = Fib;
+			FibContext.FibData = Fib->data;
+			FibContext.Adapter = Adapter;
+
+			//
+			// Set the status of this FIB
+			//
+
+			*(FSASTATUS *)Fib->data = ST_OK;
+				
+			CompleteAdapterFib( &FibContext, sizeof(FSASTATUS) );
+
+
+
+			OsSpinLockAcquire( OurQueue->QueueLock );
+		}		
+    }
+
+	OsSpinLockRelease( OurQueue->QueueLock );
+
+}
diff -BburN linux.orig/drivers/scsi/aacraid/include/AacGenericTypes.h linux/drivers/scsi/aacraid/include/AacGenericTypes.h
--- linux.orig/drivers/scsi/aacraid/include/AacGenericTypes.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/AacGenericTypes.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,54 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *
+ *  AacGenericTypes.h
+ *
+ * Abstract:
+ *
+ *     The module defines the generic data types that all of the other header files
+ *     depend upon.
+ --*/
+#ifndef _AAC_GENERIC_TYPES
+#define _AAC_GENERIC_TYPES
+
+typedef	char			AAC_INT8, *PAAC_INT8;
+typedef short			AAC_INT16, *PAAC_INT16;
+typedef int			AAC_INT32, *PAAC_INT32;
+typedef long long		AAC_INT64, *PAAC_INT64;
+
+typedef unsigned char	AAC_UINT8, *PAAC_UINT8;
+typedef unsigned short	AAC_UINT16, *PAAC_UINT16;
+typedef unsigned int	AAC_UINT32, *PAAC_UINT32;
+typedef unsigned long long	AAC_UINT64, *PAAC_UINT64;
+
+typedef void			AAC_VOID, *PAAC_VOID;
+
+//
+// this compiler uses 32 bit enum data types
+//
+
+#define	AAC_32BIT_ENUMS	1
+#define FAILURE 1
+#define INTR_UNCLAIMED 1
+#define INTR_CLAIMED 0
+
+#endif // _AAC_GENERIC_TYPES
+
diff -BburN linux.orig/drivers/scsi/aacraid/include/aac_unix_defs.h linux/drivers/scsi/aacraid/include/aac_unix_defs.h
--- linux.orig/drivers/scsi/aacraid/include/aac_unix_defs.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/aac_unix_defs.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,298 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *
+ *  aac_unix_defs.h
+ *
+ * Abstract:
+ *
+ *     Macro definition and typedefs
+ *
+ --*/
+
+#ifndef _AAC_UNIX_DEFS
+#define _AAC_UNIX_DEFS
+
+#define 	AAC_MAX_ADAPTERS	64
+
+#ifndef	TRUE
+#define TRUE	1
+#define FALSE	0
+#endif
+
+#define PAGE_SIZE	4096
+
+typedef	void	VOID;
+typedef VOID	*PVOID;
+
+typedef char		CHAR, *PCHAR;
+typedef unsigned char 	UCHAR, *PUCHAR;
+typedef short		SHORT, *PSHORT;
+typedef short		CSHORT, *PCSHORT;
+typedef unsigned short 	USHORT, *PUSHORT;
+typedef unsigned long 	ULONG, *PULONG;
+typedef long		LONG, *PLONG;
+
+typedef unsigned long	BOOLEAN;
+
+typedef unsigned long	AAC_STATUS, *PNT_STATUS;
+
+typedef struct {
+	unsigned long	LowPart;
+	unsigned long	HighPart;
+} LARGE_INTEGER;
+
+typedef LARGE_INTEGER	PHYSICAL_ADDRESS;
+
+
+typedef struct _AFA_IOCTL_CMD {
+	int		cmd;
+	intptr_t	arg;
+	int		flag;
+	cred_t		*cred_p;
+	int		*rval_p;
+} AFA_IOCTL_CMD, *PAFA_IOCTL_CMD;
+
+
+//
+//  Singly linked list structure. Can be used as either a list head, or
+//  as link words.
+//
+
+typedef struct _SINGLE_LIST_ENTRY {
+    struct _SINGLE_LIST_ENTRY *Next;
+} SINGLE_LIST_ENTRY, *PSINGLE_LIST_ENTRY;
+
+
+//
+// Calculate the address of the base of the structure given its type, and an
+// address of a field within the structure.
+//
+
+#define CONTAINING_RECORD(address, type, field) ((type *)( \
+                                                  (PCHAR)(address) - \
+                                                  (PCHAR)(&((type *)0)->field)))
+
+typedef	PVOID	PMDL;
+typedef PVOID	PDEVICE_OBJECT;
+typedef PVOID	PADAPTER_OBJECT;
+typedef ULONG	KIRQL;
+typedef PVOID	HANDLE;
+typedef PVOID	KDPC, *PKDPC;
+typedef PVOID	PFILE_OBJECT;
+typedef PVOID	PIRP;
+typedef PVOID	PDRIVER_OBJECT;
+typedef ULONG	KTIMER;
+
+
+#define	STATUS_SUCCESS		0x00000000
+#define STATUS_PENDING		0x40000001
+#define STATUS_IO_TIMEOUT			0xc0000001
+#define STATUS_UNSUCCESSFUL			0xc0000002
+#define STATUS_INSUFFICIENT_RESOURCES	0xc0000005
+#define STATUS_BUFFER_OVERFLOW		0xc0000003
+
+
+#define OUT
+
+
+
+typedef u_int
+(*PUNIX_INTR_HANDLER)(caddr_t Arg);
+
+//
+// Zone Allocation
+//
+
+typedef struct _ZONE_SEGMENT_HEADER {
+    SINGLE_LIST_ENTRY SegmentList;
+    PVOID Reserved;
+} ZONE_SEGMENT_HEADER, *PZONE_SEGMENT_HEADER;
+
+typedef struct _ZONE_HEADER {
+    SINGLE_LIST_ENTRY FreeList;
+    SINGLE_LIST_ENTRY SegmentList;
+    ULONG BlockSize;
+    ULONG TotalSegmentSize;
+} ZONE_HEADER, *PZONE_HEADER;
+
+
+//++
+//
+// PVOID
+// ExAllocateFromZone(
+//     IN PZONE_HEADER Zone
+//     )
+//
+// Routine Description:
+//
+//     This routine removes an entry from the zone and returns a pointer to it.
+//
+// Arguments:
+//
+//     Zone - Pointer to the zone header controlling the storage from which the
+//         entry is to be allocated.
+//
+// Return Value:
+//
+//     The function value is a pointer to the storage allocated from the zone.
+//
+//--
+
+#define ExAllocateFromZone(Zone) \
+    (PVOID)((Zone)->FreeList.Next); \
+    if ( (Zone)->FreeList.Next ) (Zone)->FreeList.Next = (Zone)->FreeList.Next->Next
+
+//++
+//
+// PVOID
+// ExFreeToZone(
+//     IN PZONE_HEADER Zone,
+//     IN PVOID Block
+//     )
+//
+// Routine Description:
+//
+//     This routine places the specified block of storage back onto the free
+//     list in the specified zone.
+//
+// Arguments:
+//
+//     Zone - Pointer to the zone header controlling the storage to which the
+//         entry is to be inserted.
+//
+//     Block - Pointer to the block of storage to be freed back to the zone.
+//
+// Return Value:
+//
+//     Pointer to previous block of storage that was at the head of the free
+//         list.  NULL implies the zone went from no available free blocks to
+//         at least one free block.
+//
+//--
+
+#define ExFreeToZone(Zone,Block)                                    \
+    ( ((PSINGLE_LIST_ENTRY)(Block))->Next = (Zone)->FreeList.Next,  \
+      (Zone)->FreeList.Next = ((PSINGLE_LIST_ENTRY)(Block)),        \
+      ((PSINGLE_LIST_ENTRY)(Block))->Next                           \
+    )
+
+//++
+//
+// BOOLEAN
+// ExIsFullZone(
+//     IN PZONE_HEADER Zone
+//     )
+//
+// Routine Description:
+//
+//     This routine determines if the specified zone is full or not.  A zone
+//     is considered full if the free list is empty.
+//
+// Arguments:
+//
+//     Zone - Pointer to the zone header to be tested.
+//
+// Return Value:
+//
+//     TRUE if the zone is full and FALSE otherwise.
+//
+//--
+
+#define ExIsFullZone(Zone) \
+    ( (Zone)->FreeList.Next == (PSINGLE_LIST_ENTRY)NULL )
+
+
+#define RtlCopyMemory( Destination, Source, Size )	bcopy( (Source), (Destination), (Size) )
+#define RtlZeroMemory( Destination, Size )			bzero( (Destination), (Size) )
+
+//
+//  Doubly-linked list manipulation routines.  Implemented as macros
+//  but logically these are procedures.
+//
+
+//
+//  VOID
+//  InitializeListHead(
+//      PLIST_ENTRY ListHead
+//      );
+//
+
+#define InitializeListHead(ListHead) (\
+    (ListHead)->Flink = (ListHead)->Blink = (ListHead))
+
+//
+//  BOOLEAN
+//  IsListEmpty(
+//      PLIST_ENTRY ListHead
+//      );
+//
+
+#define IsListEmpty(ListHead) \
+    ((ListHead)->Flink == (ListHead))
+
+//
+//  PLIST_ENTRY
+//  RemoveHeadList(
+//      PLIST_ENTRY ListHead
+//      );
+//
+
+#define RemoveHeadList(ListHead) \
+    (ListHead)->Flink;\
+    {RemoveEntryList((ListHead)->Flink)}
+
+
+//
+//  VOID
+//  RemoveEntryList(
+//      PLIST_ENTRY Entry
+//      );
+//
+
+#define RemoveEntryList(Entry) {\
+    PLIST_ENTRY _EX_Blink;\
+    PLIST_ENTRY _EX_Flink;\
+    _EX_Flink = (Entry)->Flink;\
+    _EX_Blink = (Entry)->Blink;\
+    _EX_Blink->Flink = _EX_Flink;\
+    _EX_Flink->Blink = _EX_Blink;\
+    }
+
+//
+//  VOID
+//  InsertTailList(
+//      PLIST_ENTRY ListHead,
+//      PLIST_ENTRY Entry
+//      );
+//
+
+#define InsertTailList(ListHead,Entry) {\
+    PLIST_ENTRY _EX_Blink;\
+    PLIST_ENTRY _EX_ListHead;\
+    _EX_ListHead = (ListHead);\
+    _EX_Blink = _EX_ListHead->Blink;\
+    (Entry)->Flink = _EX_ListHead;\
+    (Entry)->Blink = _EX_Blink;\
+    _EX_Blink->Flink = (Entry);\
+    _EX_ListHead->Blink = (Entry);\
+    }
+
+#endif /* AAC_UNIX_DEFS */
diff -BburN linux.orig/drivers/scsi/aacraid/include/adapter.h linux/drivers/scsi/aacraid/include/adapter.h
--- linux.orig/drivers/scsi/aacraid/include/adapter.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/adapter.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,175 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *
+ *   Adapter.h
+ *
+ * Abstract:
+ *   The module contains the definitions for a comm layer view of the adapter.
+ *
+ *
+ *
+ --*/
+
+#ifndef _ADAPTER_
+#define _ADAPTER_
+
+
+typedef struct _GET_ADAPTER_FIB_CONTEXT {
+
+	NODE_TYPE_CODE 		NodeTypeCode;	// used for verification of structure	
+	NODE_BYTE_SIZE 		NodeByteSize;
+	PFILE_OBJECT		FileObject;	// used for cleanup
+	LIST_ENTRY		NextContext;	// used to link context's into a linked list
+	OS_CV_T 		UserEvent;	// this is used to wait for the next fib to arrive.
+	BOOLEAN			WaitingForFib;	// Set to true when thread is in WaitForSingleObject
+	ULONG			FibCount;	// total number of FIBs on FibList
+	LIST_ENTRY		FibList;
+} GET_ADAPTER_FIB_CONTEXT;
+typedef GET_ADAPTER_FIB_CONTEXT *PGET_ADAPTER_FIB_CONTEXT;
+
+
+typedef struct _FIB_CONTEXT_ZONE_SEGMENT {
+
+	struct _FIB_CONTEXT_ZONE_SEGMENT	*Next;
+	ULONG					FibContextSegmentSize;
+	PVOID					FibContextSegment;
+	ULONG					ExtendSize;
+	MAPFIB_CONTEXT				MapFibContext;
+
+} FIB_CONTEXT_ZONE_SEGMENT;
+typedef FIB_CONTEXT_ZONE_SEGMENT *PFIB_CONTEXT_ZONE_SEGMENT;
+
+typedef struct _AFA_COMM_ADAPTER {
+
+	struct _AFA_COMM_ADAPTER	*NextAdapter;
+
+    //
+    //  The following fields are used to allocate FIB context structures
+    //  using the zone allocator, and other fixed sized structures from a
+    //  small cache.  The mutex protects access to the zone/lists
+    //
+
+    ZONE_HEADER 		FibContextZone;
+	OS_SPINLOCK			*FibContextZoneSpinLock;
+	int 				FibContextZoneExtendSize;
+
+	PFIB_CONTEXT_ZONE_SEGMENT	FibContextSegmentList;
+
+	PVOID				FibContextTimedOutList;
+
+	PFIB				SyncFib;
+	ULONG				SyncFibPhysicalAddress;
+
+	PCOMM_REGION 		CommRegion;
+
+	OS_SPINLOCK_COOKIE	SpinLockCookie;
+
+//	UNICODE_STRING		TimeoutString;
+
+#ifdef GATHER_FIB_TIMES
+	//
+	// The following contains detailed timings of round trip to the adapter
+	// depending on which Fib type
+	//
+
+	PALL_FIB_TIMES		FibTimes;
+	LARGE_INTEGER 		FibTimesFrequency;
+#endif
+
+	//
+	// The user API will use an IOCTL to register itself to receive FIBs
+	// from the adapter.  The following list is used to keep track of all
+	// the threads that have requested these FIBs.  The mutex is used to 
+	// synchronize access to all data associated with the adapter fibs.
+	//
+	LIST_ENTRY			AdapterFibContextList;
+	OS_CVLOCK			*AdapterFibMutex;
+
+	//
+	// The following holds which FileObject is allow to send configuration
+	// commands to the adapter that would modify the configuration.
+	//
+	// This is controlled by the FSACTL_OPEN_ADAPTER_CONFIG and FSACTL_CLOSE_ADAPTER_CONFIG
+	// ioctls.
+	//
+	PFILE_OBJECT		AdapterConfigFileObject;
+
+	//
+	// The following is really here because of the simulator
+	//
+	BOOLEAN				InterruptsBelowDpc;
+
+	//
+	// The following is the device specific extension.
+	//
+	PVOID			AdapterExtension;	
+	PFSAPORT_FUNCS		AdapterFuncs;
+	void			*Dip;
+
+	//
+	// The following are user variables that are specific to the mini port.
+	//
+	PFSA_USER_VAR		AdapterUserVars;
+	ULONG			AdapterUserVarsSize;
+
+	//
+	// The following is the number of the individual adapter..i.e. \Device\Afa0
+	//
+	LONG			AdapterNumber;
+
+	AFACOMM_FUNCS		CommFuncs;
+
+	PAFA_CLASS_DRIVER	ClassDriverList;
+
+	BOOLEAN			AifThreadStarted;
+
+} AFA_COMM_ADAPTER;
+
+typedef AFA_COMM_ADAPTER *PAFA_COMM_ADAPTER;
+
+
+#define FsaAllocateAdapterCommArea(Adapter, BaseAddress, Size, Alignment) \
+	Adapter->AdapterFuncs->AllocateAdapterCommArea(Adapter->AdapterExtension, BaseAddress, Size, Alignment)
+
+#define FsaFreeAdapterCommArea(Adapter) \
+	Adapter->AdapterFuncs->FreeAdapterCommArea(Adapter->AdapterExtension)
+
+
+#define AllocateAndMapFibSpace(Adapter, MapFibContext) \
+	Adapter->AdapterFuncs->AllocateAndMapFibSpace(Adapter->AdapterExtension, MapFibContext)
+
+#define UnmapAndFreeFibSpace(Adapter, MapFibContext) \
+	Adapter->AdapterFuncs->UnmapAndFreeFibSpace(Adapter->AdapterExtension, MapFibContext)
+
+#define InterruptAdapter(Adapter) \
+	Adapter->AdapterFuncs->InterruptAdapter(Adapter->AdapterExtension)
+
+#define NotifyAdapter(Adapter, AdapterEvent) \
+	Adapter->AdapterFuncs->NotifyAdapter(Adapter->AdapterExtension, AdapterEvent)
+
+#define EnableInterrupt(Adapter, AdapterEvent, AtDeviceIrq) \
+	Adapter->AdapterFuncs->EnableInterrupt(Adapter->AdapterExtension, AdapterEvent, AtDeviceIrq)
+
+#define DisableInterrupt(Adapter, AdapterEvent, AtDeviceIrq) \
+	Adapter->AdapterFuncs->DisableInterrupt(Adapter->AdapterExtension, AdapterEvent, AtDeviceIrq)
+
+
+#endif // _ADAPTER_
diff -BburN linux.orig/drivers/scsi/aacraid/include/afacomm.h linux/drivers/scsi/aacraid/include/afacomm.h
--- linux.orig/drivers/scsi/aacraid/include/afacomm.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/afacomm.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,189 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   AfaComm.h
+ *
+ * Abstract:
+ *   This module defines all of the external interfaces to the AFA comm layer.
+ *
+ *
+ *
+ --*/
+#ifndef _AFACOMM_
+#define _AFACOMM_
+
+#include "fsaport.h"
+
+typedef void	*PFIB_CONTEXT;
+
+typedef VOID
+(*PFIB_CALLBACK)(
+	PVOID		FibCallbackContext,
+	PFIB_CONTEXT	FibContext,
+	AAC_STATUS	Status
+	);
+
+
+typedef PFIB_CONTEXT
+(*PAFA_COMM_ALLOCATE_FIB) (
+	IN PVOID AdapterExtension
+    );
+
+typedef VOID
+(*PAFA_COMM_FREE_FIB) (
+    IN PFIB_CONTEXT FibContext
+    );
+
+
+typedef AAC_STATUS
+(*PAFA_COMM_DEALLOCATE_FIB) (
+    IN PFIB_CONTEXT FibContext
+    );
+
+
+typedef VOID
+(*PAFA_COMM_FREE_FIB_FROM_DPC) (
+    IN PFIB_CONTEXT FibContext
+    );
+
+typedef AAC_STATUS
+(*PAFA_COMM_INITIALIZE_FIB) (
+	IN PFIB_CONTEXT FibContext
+    );
+
+typedef PVOID
+(*PAFA_COMM_GET_FIB_DATA) (
+	IN PFIB_CONTEXT FibContext
+	);
+
+typedef AAC_STATUS
+(*PAFA_COMM_SEND_FIB) (
+    IN FIB_COMMAND Command, 
+	IN PFIB_CONTEXT FibContext,
+    IN ULONG Size,
+    IN COMM_PRIORITIES Priority,
+    IN BOOLEAN Wait,
+    IN PVOID WaitOn,
+    IN BOOLEAN ResponseExpected,
+	IN PFIB_CALLBACK FibCallback,
+	IN PVOID FibCallbackContext
+    );
+
+typedef AAC_STATUS
+(*PAFA_COMM_COMPLETE_FIB) (
+	IN PFIB_CONTEXT FibContext
+    );
+
+typedef AAC_STATUS
+(*PAFA_COMM_COMPLETE_ADAPTER_FIB) (
+	IN PFIB_CONTEXT FibContext,
+	IN USHORT Size
+    );
+
+typedef BOOLEAN
+(*PAFA_COMM_SEND_SYNCH_FIB) (
+	PVOID 			AdapterExtension,
+	FIB_COMMAND  	Command,
+	PVOID			Data,
+	USHORT		 	Size,
+	PVOID			Response,
+	USHORT		 	*ResponseSize
+	);
+
+
+typedef struct _AFACOMM_FUNCS {
+	ULONG					SizeOfAfaCommFuncs;
+	PAFA_COMM_ALLOCATE_FIB			AllocateFib;
+	PAFA_COMM_FREE_FIB			FreeFib;
+	PAFA_COMM_FREE_FIB_FROM_DPC		FreeFibFromDpc;
+	PAFA_COMM_DEALLOCATE_FIB		DeallocateFib;
+	PAFA_COMM_INITIALIZE_FIB		InitializeFib;
+	PAFA_COMM_GET_FIB_DATA			GetFibData;
+	PAFA_COMM_SEND_FIB			SendFib;
+	PAFA_COMM_COMPLETE_FIB			CompleteFib;
+	PAFA_COMM_COMPLETE_ADAPTER_FIB		CompleteAdapterFib;
+	PAFA_COMM_SEND_SYNCH_FIB		SendSynchFib;
+	PFSA_FREE_DMA_RESOURCES			FreeDmaResources;
+	PFSA_BUILD_SGMAP			BuildSgMap;
+	PFSA_ADAPTER_ADDR_TO_SYSTEM_ADDR	AdapterAddressToSystemAddress;
+} AFACOMM_FUNCS;
+typedef AFACOMM_FUNCS *PAFACOMM_FUNCS;
+
+
+typedef AAC_STATUS
+(*PAFA_CLASS_OPEN_ADAPTER) (
+	IN PVOID Adapter
+	);
+
+
+typedef AAC_STATUS
+(*PAFA_CLASS_CLOSE_ADAPTER) (
+	IN PVOID Adapter
+	);
+
+
+typedef BOOLEAN
+(*PAFA_CLASS_DEV_CONTROL) (
+	IN PVOID Adapter,
+	IN PAFA_IOCTL_CMD	IoctlCmdPtr,
+	OUT int * Status
+	);
+
+typedef BOOLEAN
+(*PAFA_CLASS_HANDLE_AIF) (
+	IN PVOID Adapter,
+	IN PFIB_CONTEXT FibContext
+	);
+
+
+typedef struct _AFA_NEW_CLASS_DRIVER {
+	PVOID			        ClassDriverExtension;
+	PAFA_CLASS_OPEN_ADAPTER	        OpenAdapter;
+        PAFA_CLASS_CLOSE_ADAPTER	CloseAdapter;
+        PAFA_CLASS_DEV_CONTROL 	        DeviceControl;
+	PAFA_CLASS_HANDLE_AIF	        HandleAif;
+	PFSA_USER_VAR			UserVars;
+	ULONG				NumUserVars;
+} AFA_NEW_CLASS_DRIVER;
+typedef AFA_NEW_CLASS_DRIVER *PAFA_NEW_CLASS_DRIVER;
+
+
+typedef struct _AFA_NEW_CLASS_DRIVER_RESPONSE {
+	PAFACOMM_FUNCS		CommFuncs;
+	PVOID			CommPortExtension;
+	PVOID			MiniPortExtension;
+	OS_SPINLOCK_COOKIE	SpinLockCookie;
+	void			*Dip;
+} AFA_NEW_CLASS_DRIVER_RESPONSE;
+typedef AFA_NEW_CLASS_DRIVER_RESPONSE *PAFA_NEW_CLASS_DRIVER_RESPONSE;
+
+
+typedef struct _AFA_CLASS_DRIVER {
+	struct _AFA_CLASS_DRIVER	*Next;
+	PVOID				ClassDriverExtension;
+	PAFA_CLASS_OPEN_ADAPTER		OpenAdapter;
+	PAFA_CLASS_CLOSE_ADAPTER	CloseAdapter;
+	PAFA_CLASS_DEV_CONTROL 		DeviceControl;
+	PAFA_CLASS_HANDLE_AIF		HandleAif;
+} AFA_CLASS_DRIVER;
+typedef AFA_CLASS_DRIVER *PAFA_CLASS_DRIVER;
+
+
+#endif // _AFACOMM_
diff -BburN linux.orig/drivers/scsi/aacraid/include/aifstruc.h linux/drivers/scsi/aacraid/include/aifstruc.h
--- linux.orig/drivers/scsi/aacraid/include/aifstruc.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/aifstruc.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,317 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   Aifstruc.h
+ *
+ * Abstract:
+ *   Define all shared data types relating to
+ *   the set of features utilizing Adapter
+ *   Initiated Fibs.
+ *
+ *
+ *
+ --*/
+#ifndef _AIFSTRUC_H
+#define _AIFSTRUC_H
+
+#include <protocol.h>
+
+//
+//	Progress report structure definitions
+//
+typedef enum {
+	AifJobStsSuccess = 1,
+	AifJobStsFinished,
+	AifJobStsAborted,
+	AifJobStsFailed,
+	AifJobStsLastReportMarker = 100, // All before mean last report
+	AifJobStsSuspended,
+	AifJobStsRunning
+} _E_AifJobStatus;
+
+#ifdef AAC_32BIT_ENUMS
+typedef	_E_AifJobStatus	AifJobStatus;
+#else
+typedef	AAC_UINT32		AifJobStatus;
+#endif
+
+
+typedef enum {
+	AifJobScsiMin = 1,		// Minimum value for Scsi operation
+	AifJobScsiZero,			// SCSI device clear operation
+	AifJobScsiVerify,		// SCSI device Verify operation NO REPAIR
+	AifJobScsiExercise,		// SCSI device Exercise operation
+	AifJobScsiVerifyRepair,	// SCSI device Verify operation WITH repair
+	// Add new SCSI task types above this line
+	AifJobScsiMax = 99,		// Max Scsi value
+	AifJobCtrMin,			// Min Ctr op value
+	AifJobCtrZero,			// Container clear operation
+	AifJobCtrCopy,			// Container copy operation
+	AifJobCtrCreateMirror,	// Container Create Mirror operation
+	AifJobCtrMergeMirror,	// Container Merge Mirror operation
+	AifJobCtrScrubMirror,	// Container Scrub Mirror operation
+	AifJobCtrRebuildRaid5,	// Container Rebuild Raid5 operation
+	AifJobCtrScrubRaid5,	// Container Scrub Raid5 operation
+	AifJobCtrMorph,			// Container morph operation
+	AifJobCtrPartCopy,		// Container Partition copy operation
+	AifJobCtrRebuildMirror,	// Container Rebuild Mirror operation
+	AifJobCtrCrazyCache,		// crazy cache
+	// Add new container task types above this line
+	AifJobCtrMax = 199,		// Max Ctr type operation
+	AifJobFsMin,			// Min Fs type operation
+	AifJobFsCreate,			// File System Create operation
+	AifJobFsVerify,			// File System Verify operation
+	AifJobFsExtend,			// File System Extend operation
+	// Add new file system task types above this line
+	AifJobFsMax = 299,		// Max Fs type operation
+	// Add new API task types here
+	AifJobApiFormatNTFS,	// Format a drive to NTFS
+	AifJobApiFormatFAT,		// Format a drive to FAT
+	AifJobApiUpdateSnapshot, // update the read/write half of a snapshot
+	AifJobApiFormatFAT32,	// Format a drive to FAT32
+	AifJobApiMax = 399,		// Max API type operation
+	AifJobCtlContinuousCtrVerify,	// Controller operation
+	AifJobCtlMax = 499		// Max Controller type operation
+
+} _E_AifJobType;
+
+#ifdef AAC_32BIT_ENUMS
+typedef	_E_AifJobType	AifJobType;
+#else
+typedef	AAC_UINT32		AifJobType;
+#endif
+
+union SrcContainer {
+	AAC_UINT32 from;
+	AAC_UINT32 master;
+	AAC_UINT32 container;
+};
+
+union DstContainer {
+	AAC_UINT32 to;
+	AAC_UINT32 slave;
+	AAC_UINT32 container;
+};
+
+
+struct AifContainers {
+	union SrcContainer src;
+	union DstContainer dst;
+};
+
+union AifJobClient {
+	
+	struct AifContainers container;	// For Container nd file system progress ops;
+	AAC_INT32 scsi_dh;			// For SCSI progress ops
+};
+
+struct AifJobDesc {
+	AAC_UINT32 jobID;			// DO NOT FILL IN! Will be filled in by AIF
+	AifJobType type;		// Operation that is being performed
+	union AifJobClient client; // Details
+};
+
+struct AifJobProgressReport {
+	struct AifJobDesc jd;
+	AifJobStatus status;
+	AAC_UINT32 finalTick;
+	AAC_UINT32 currentTick;
+	AAC_UINT32 jobSpecificData1;
+	AAC_UINT32 jobSpecificData2;
+};
+
+//
+//	Notification of events structure definition starts here
+//
+typedef enum {
+	// General application notifies start here
+	AifEnGeneric = 1,			// Generic notification
+	AifEnTaskComplete,			// Task has completed
+	AifEnConfigChange,			// Adapter configuration change occurred
+	AifEnContainerChange,		// Adapter specific container configuration change
+	AifEnDeviceFailure,			// SCSI device failed
+	AifEnMirrorFailover,		// Mirror failover started
+	AifEnContainerEvent,		// Significant container event
+	AifEnFileSystemChange,		// File system changed
+	AifEnConfigPause,			// Container pause event
+	AifEnConfigResume,			// Container resume event
+	AifEnFailoverChange,		// Failover space assignment changed
+	AifEnRAID5RebuildDone,		// RAID5 rebuild finished
+	AifEnEnclosureManagement,	// Enclosure management event
+	AifEnBatteryEvent,			// Significant NV battery event
+	AifEnAddContainer,			// A new container was created.
+	AifEnDeleteContainer,		// A container was deleted.
+	AifEnSMARTEvent,            // SMART Event
+	AifEnBatteryNeedsRecond,	// The battery needs reconditioning
+	AifEnClusterEvent,			// Some cluster event
+	AifEnDiskSetEvent,			// A disk set event occured.
+	// Add general application notifies above this comment
+	AifDriverNotifyStart=199,	// Notifies for host driver go here
+	// Host driver notifications start here
+	AifDenMorphComplete, 		// A morph operation completed
+	AifDenVolumeExtendComplete 	// A volume expand operation completed
+	// Add host driver notifications above this comment
+} _E_AifEventNotifyType;
+
+#ifdef AAC_32BIT_ENUMS
+typedef _E_AifEventNotifyType	AifEventNotifyType;
+#else
+typedef	AAC_UINT32				AifEventNotifyType;
+#endif
+
+struct AifEnsGeneric {
+	AAC_INT8 text[132];				// Generic text
+};
+
+struct AifEnsDeviceFailure {
+	AAC_INT32 deviceHandle;	// SCSI device handle
+};
+
+struct AifEnsMirrorFailover {
+	AAC_UINT32 container;		// Container with failed element
+	AAC_UINT32 failedSlice;		// Old slice which failed
+	AAC_UINT32 creatingSlice;	// New slice used for auto-create
+};
+
+struct AifEnsContainerChange {
+	AAC_UINT32 container[2];		// container that changed, -1 if no container
+};
+
+struct AifEnsContainerEvent {
+	AAC_UINT32 container;		// container number 
+	AAC_UINT32 eventType;		// event type
+};
+
+struct AifEnsEnclosureEvent {
+	AAC_UINT32 empID;				// enclosure management processor number 
+	AAC_UINT32 unitID;			// unitId, fan id, power supply id, slot id, tempsensor id. 
+	AAC_UINT32 eventType;		// event type
+};
+
+
+struct AifEnsBatteryEvent {
+	NVBATT_TRANSITION transition_type;	// e.g. from low to ok
+	NVBATTSTATUS current_state;			// current battery state
+	NVBATTSTATUS prior_state;			// previous battery state
+};
+
+struct AifEnsDiskSetEvent {
+	AAC_UINT32	eventType;
+	AAC_UINT32	DsNum[2];
+	AAC_UINT32	CreatorId[2];
+};
+
+
+
+typedef enum _CLUSTER_AIF_EVENT {
+	CLUSTER_NULL_EVENT = 0,
+	CLUSTER_PARTNER_NAME_EVENT,		// change in partner hostname or adaptername from NULL to non-NULL
+									// (partner's agent may be up)
+	CLUSTER_PARTNER_NULL_NAME_EVENT	// change in partner hostname or adaptername from non-null to NULL
+									// (partner has rebooted)
+} _E_CLUSTER_AIF_EVENT;
+
+#ifdef AAC_32BIT_ENUMS
+typedef	_E_CLUSTER_AIF_EVENT	CLUSTER_AIF_EVENT;
+#else
+typedef	AAC_UINT32				CLUSTER_AIF_EVENT;
+#endif
+
+struct AifEnsClusterEvent {
+	CLUSTER_AIF_EVENT   eventType;
+};
+
+struct AifEventNotify {
+	AifEventNotifyType	type;
+	union {
+		struct AifEnsGeneric		EG;
+		struct AifEnsDeviceFailure	EDF;
+		struct AifEnsMirrorFailover EMF;
+		struct AifEnsContainerChange ECC;
+		struct AifEnsContainerEvent ECE;
+		struct AifEnsEnclosureEvent EEE;
+		struct AifEnsBatteryEvent	EBE;
+		struct AifEnsDiskSetEvent	EDS;
+#ifdef BRIDGE
+		struct AifEnsSMARTEvent ES;
+#endif
+		struct AifEnsClusterEvent ECLE;
+	} data;
+};
+
+//
+//	Generic API structure
+//
+#define AIF_API_REPORT_MAX_SIZE 64
+typedef AAC_INT8 AifApiReport[AIF_API_REPORT_MAX_SIZE];
+
+
+
+//
+//	For FIB communication, we need all of the following things
+//	to send back to the user.
+//
+typedef enum {
+	AifCmdEventNotify = 1,	// Notify of event
+	AifCmdJobProgress,		// Progress report
+	AifCmdAPIReport,		// Report from other user of API
+	AifCmdDriverNotify,		// Notify host driver of event
+	AifReqJobList = 100,	// Gets back complete job list
+	AifReqJobsForCtr,		// Gets back jobs for specific container
+	AifReqJobsForScsi,		// Gets back jobs for specific SCSI device
+	AifReqJobReport,		// Gets back a specific job report or list of them
+	AifReqTerminateJob,		// Terminates job
+	AifReqSuspendJob,		// Suspends a job
+	AifReqResumeJob,		// Resumes a job
+	AifReqSendAPIReport,	// API generic report requests
+	AifReqAPIJobStart,		// Start a job from the API
+	AifReqAPIJobUpdate,		// Update a job report from the API
+	AifReqAPIJobFinish		// Finish a job from the API
+} _E_AIFCOMMAND;
+
+#ifdef AAC_32BIT_ENUMS
+typedef _E_AIFCOMMAND	AIFCOMMAND;
+#else
+typedef	AAC_UINT32		AIFCOMMAND;
+#endif
+
+
+
+//
+//	Adapter Initiated FIB command structures. Start with the adapter
+//	initiated FIBs that really come from the adapter, and get responded
+//	to by the host.
+//
+typedef struct _AIFCOMMANDTOHOST {
+	AIFCOMMAND command;			// Tell host what type of notify this is
+	AAC_UINT32 seqNumber;	// To allow ordering of reports (if necessary)
+	union {
+		// First define data going to the adapter
+		struct AifEventNotify EN;	// Event notify structure
+		struct AifJobProgressReport PR[1]; // Progress report
+		AifApiReport AR;
+	} data;
+} AIFCOMMANDTOHOST, *PAIFCOMMANDTOHOST;
+
+
+#endif // _AIFSTRUC_H
+
+
+
diff -BburN linux.orig/drivers/scsi/aacraid/include/build_number.h linux/drivers/scsi/aacraid/include/build_number.h
--- linux.orig/drivers/scsi/aacraid/include/build_number.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/build_number.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,38 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   build_number.h
+ *
+ * Abstract:
+ *   DThis module contains the single location where the build number
+ *   is kept.
+ *
+ *
+ *
+ --*/
+#ifndef _BUILD_NUMBER_H 
+#define _BUILD_NUMBER_H 
+
+
+#define REV_BUILD_NUMBER 3911 
+
+
+#endif  // _BUILD_NUMBER_H 
+
diff -BburN linux.orig/drivers/scsi/aacraid/include/commdata.h linux/drivers/scsi/aacraid/include/commdata.h
--- linux.orig/drivers/scsi/aacraid/include/commdata.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/commdata.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,110 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   commdata.h
+ *
+ * Abstract: Define the communication layer of the adapter
+ *
+ *
+ *
+ --*/
+#ifndef _COMMDATA_
+#define _COMMDATA_
+
+typedef struct _FSA_COMM_DATA {
+  
+  //
+  //  A pointer to the Driver and Device object we were initialized with
+  //
+  
+  PDRIVER_OBJECT DriverObject;
+  PDEVICE_OBJECT DeviceObject;
+  
+  //
+  // A list of all adapters we have configured.
+  // 
+  
+  PAFA_COMM_ADAPTER AdapterList;
+  ULONG		  TotalAdapters;
+  
+  //
+  // Adapter timeout support. This is the default timeout to wait for the
+  // adapter to respond(setup in initfs.c), and a boolean to indicate if
+  // we should timeout requests to the adapter or not.
+  //
+
+  LARGE_INTEGER QueueFreeTimeout;
+  LARGE_INTEGER AdapterTimeout;
+  BOOLEAN EnableAdapterTimeouts;
+
+  ULONG	FibTimeoutIncrement;
+  
+  ULONG FibsSent;
+  ULONG FibRecved;
+  ULONG NoResponseSent;
+  ULONG NoResponseRecved;
+  ULONG AsyncSent;
+  ULONG AsyncRecved;
+  ULONG NormalSent;
+  ULONG NormalRecved;
+  
+  ULONG TimedOutFibs;
+  
+  KDPC		TimeoutDPC;
+  KTIMER	TimeoutTimer;
+  
+  // 
+  // If this value is set to 1 then interrupt moderation will occur 
+  // in the base commuication support.
+  //
+
+  ULONG EnableInterruptModeration;
+
+  int HardInterruptModeration;
+  int HardInterruptModeration1;
+  int PeakFibsConsumed;
+  int ZeroFibsConsumed;
+  int EnableFibTimeoutBreak;
+  ULONG FibTimeoutSeconds;
+  
+  //
+  // The following holds all of the available user settable variables.
+  // This includes all for the comm layer as well as any from the class
+  // drivers as well.
+  //
+  
+  FSA_USER_VAR	*UserVars;
+  ULONG			NumUserVars;
+  
+  
+  ULONG           MeterFlag;
+  
+#ifdef FIB_CHECKSUMS
+  int do_fib_checksums;
+#endif
+  
+} FSA_COMM_DATA;
+typedef FSA_COMM_DATA *PFSA_COMM_DATA;
+
+extern FSA_COMM_DATA FsaCommData;
+
+
+#endif // _COMMDATA_
+
diff -BburN linux.orig/drivers/scsi/aacraid/include/commerr.h linux/drivers/scsi/aacraid/include/commerr.h
--- linux.orig/drivers/scsi/aacraid/include/commerr.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/commerr.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,122 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   commerr.h
+ *
+ * Abstract: This file defines all errors that are unique to the Adaptec Fsa Filesystem
+ *
+ *
+ *
+ --*/
+
+#ifndef _FSAERR_
+#define _FSAERR_
+//
+//  Note: comments in the .mc file must use both ";" and "//".
+//
+//  Status values are 32 bit values layed out as follows:
+//
+//   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+//   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+//  +---+-+-------------------------+-------------------------------+
+//  |Sev|C|       Facility          |               Code            |
+//  +---+-+-------------------------+-------------------------------+
+//
+//  where
+//
+//      Sev - is the severity code
+//
+//          00 - Success
+//          01 - Informational
+//          10 - Warning
+//          11 - Error
+//
+//      C - is the Customer code flag
+//
+//      Facility - is the facility code
+//
+//      Code - is the facility's status code
+//
+
+
+//
+// %1 is reserved by the IO Manager. If IoAllocateErrorLogEntry is
+// called with a device, the name of the device will be inserted into
+// the message at %1. Otherwise, the place of %1 will be left empty.
+// In either case, the insertion strings from the driver's error log
+// entry starts at %2. In other words, the first insertion string goes
+// to %2, the second to %3 and so on.
+//
+
+//
+//  Values are 32 bit values layed out as follows:
+//
+//   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+//   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+//  +---+-+-+-----------------------+-------------------------------+
+//  |Sev|C|R|     Facility          |               Code            |
+//  +---+-+-+-----------------------+-------------------------------+
+//
+//  where
+//
+//      Sev - is the severity code
+//
+//          00 - Success
+//          01 - Informational
+//          10 - Warning
+//          11 - Error
+//
+//      C - is the Customer code flag
+//
+//      R - is a reserved bit
+//
+//      Facility - is the facility code
+//
+//      Code - is the facility's status code
+//
+//
+// Define the facility codes
+//
+
+
+#define FACILITY_FSAFS_ERROR_CODE        0x7
+
+
+
+//
+// MessageId: FSAFS_FIB_INVALID
+//
+// MessageText:
+//
+//  A communication packet was detected to be formatted poorly. Please Contact Adaptec support.
+//
+#define FSAFS_FIB_INVALID                ((AAC_STATUS)0xE0070009L)
+
+
+//
+// MessageId: FSAFS_TIMED_OUT_FIB_COMPLETED
+//
+// MessageText:
+//
+//  A Fib previously timed out by host has been completed by the adapter. (\\.\Afa%2)
+//
+#define FSAFS_TIMED_OUT_FIB_COMPLETED    ((AAC_STATUS)0xA007000EL)
+
+#endif _FSAERR_
diff -BburN linux.orig/drivers/scsi/aacraid/include/commfibcontext.h linux/drivers/scsi/aacraid/include/commfibcontext.h
--- linux.orig/drivers/scsi/aacraid/include/commfibcontext.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/commfibcontext.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,96 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   commfibcontext.h
+ *
+ * Abstract: defines the _COMM_FIB_CONTEXT strcuture
+ *
+ *
+ *
+ --*/
+#ifndef _COMM_FIB_CONTEXT_
+#define _COMM_FIB_CONTEXT_
+
+typedef struct _COMM_FIB_CONTEXT {
+
+	PVOID		Next;	// this is used by the zone allocation
+
+    //
+    //  Type and size of this record (must be FSA_NTC_FIB_CONTEXT)
+    //
+    //  NOTE:  THIS STRUCTURE MUST REMAIN 64-bit ALIGNED IN SIZE, SINCE
+    //         IT IS ZONE ALLOCATED, AND REPINNED_BCBS_ARRAY_SIZE AFFECTS
+    //         ITS SIZE.
+    //
+
+    NODE_TYPE_CODE NodeTypeCode;
+    NODE_BYTE_SIZE NodeByteSize;
+
+	//
+	//	The Adapter that this I/O is destined for.
+	//
+
+	PAFA_COMM_ADAPTER Adapter;
+
+    PHYSICAL_ADDRESS LogicalFibAddress;
+
+    //
+    // This is the event the sendfib routine will wait on if the
+    // caller did not pass one and this is synch io.
+    //
+
+    OS_CV_T 	FsaEvent;
+	OS_CVLOCK	*FsaEventMutex;
+
+	ULONG	FibComplete;	// gets set to 1 when fib is complete
+    
+	PFIB_CALLBACK FibCallback;
+	PVOID FibCallbackContext;
+
+	ULONG	Flags;
+
+
+#ifdef GATHER_FIB_TIMES
+	LARGE_INTEGER 	FibTimeStamp;
+	PFIB_TIMES		FibTimesPtr;
+#endif
+
+	//
+	// The following is used to put this fib context onto the Outstanding I/O queue.
+	//
+		
+	LIST_ENTRY	QueueEntry;	
+
+	//
+	// The following is used to timeout a fib to the adapter.
+	//
+
+	LARGE_INTEGER	TimeoutValue;
+
+	PVOID	FibData;
+
+    PFIB Fib;
+
+} COMM_FIB_CONTEXT;
+typedef COMM_FIB_CONTEXT *PCOMM_FIB_CONTEXT;
+
+#define FIB_CONTEXT_FLAG_TIMED_OUT		(0x00000001)
+
+#endif /* _COMM_FIB_CONTEXT_ */
diff -BburN linux.orig/drivers/scsi/aacraid/include/comprocs.h linux/drivers/scsi/aacraid/include/comprocs.h
--- linux.orig/drivers/scsi/aacraid/include/comprocs.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/comprocs.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,91 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   comprocs.h
+ *
+ * Abstract: This module defines all of the globally used procedures in the Afa comm layer
+ *
+ *
+ *
+ --*/
+#ifndef _COMPROCS_
+#define _COMPROCS_
+
+#include "osheaders.h"
+
+#include "AacGenericTypes.h"
+
+#include "aac_unix_defs.h"
+
+#include "nodetype.h"
+
+// #define GATHER_FIB_TIMES
+
+#include "fsatypes.h"
+
+#include "perfpack.h"
+
+#include "comstruc.h"
+
+//#include "unix_protocol.h"
+
+#include "fsact.h"
+
+#include "protocol.h"
+
+#include "fsaioctl.h"
+
+#undef GATHER_FIB_TIMES
+
+#include "aifstruc.h"
+
+#include "fsaport.h"
+#include "comsup.h"
+#include "afacomm.h"
+#include "adapter.h"
+
+#include "commfibcontext.h"
+#include "comproto.h"
+#include "commdata.h"
+#include "commerr.h"
+
+
+
+
+//
+// The following macro is used when sending and receiving FIBs.  It is only used for
+// debugging.
+
+#if DBG
+#define	FIB_COUNTER_INCREMENT(Counter)		InterlockedIncrement(&(Counter))
+#else
+#define	FIB_COUNTER_INCREMENT(Counter)		
+#endif
+
+
+
+int
+AfaCommAdapterDeviceControl (
+	IN PVOID AdapterArg,
+	IN PAFA_IOCTL_CMD	IoctlCmdPtr
+	);
+
+
+#endif // _COMPROCS_
diff -BburN linux.orig/drivers/scsi/aacraid/include/comproto.h linux/drivers/scsi/aacraid/include/comproto.h
--- linux.orig/drivers/scsi/aacraid/include/comproto.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/comproto.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,168 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   comproto.h
+ *
+ * Abstract: Global routines for the commuication interface that are device
+ *           independant.
+ *
+ *
+ *
+ --*/
+#ifndef _COMM_PROTO
+#define _COMM_PROTO
+
+//
+// define the routines we need so we can commuicate with the
+// fsa adapter
+//
+
+//
+// The following 4 dpc routines will support commuication from the adapter to the
+// host. There is one DPC routine to deal with each type of queue that supports
+// commuication from the adapter. (adapter to host resposes, adapter to host commands)
+// These routines will simply pull off the QE and set an event. In the case of a
+// adapter to host command they will also put the FIB on a queue to be processed by
+// a FS thread running at passive level.
+//
+
+// Handle queue not full notification to the file system thread waiting for a queue entry
+
+u_int
+CommonNotFullDpc(
+	IN PCOMM_REGION CommRegion
+    );
+
+// Adapter to host normal priority responses
+
+u_int
+HostResponseNormalDpc(
+    IN PCOMM_QUE OurQueue
+    );
+
+// Adapter to host high priority responses
+u_int
+HostResponseHighDpc(
+    IN PCOMM_QUE OurQueue
+    );
+
+// Adapter to host high priority commands
+u_int
+HostCommandHighDpc(
+    IN PCOMM_QUE OurQueue
+    );
+    
+
+// Adapter to host normal priority commands
+u_int
+HostCommandNormDpc(
+    IN PCOMM_QUE OurQueue
+    );
+
+
+
+BOOLEAN
+SendSynchFib(
+	PVOID			Arg,
+	FIB_COMMAND  	Command,
+	PVOID			Data,
+	USHORT		 	Size,
+	PVOID			Response,
+	USHORT		 	*ResponseSize
+	);
+
+PFIB_CONTEXT
+AllocateFib (
+	IN PVOID Adapter
+    );
+
+VOID
+FreeFib (
+    IN PFIB_CONTEXT FibContext
+    );
+
+VOID
+FreeFibFromDpc(
+    IN PFIB_CONTEXT FibContext
+    );
+
+AAC_STATUS
+DeallocateFib(
+    IN PFIB_CONTEXT FibContext
+    );
+
+
+
+AAC_STATUS
+SendFib(
+    IN FIB_COMMAND Command, 
+	IN PFIB_CONTEXT FibContext,
+    IN ULONG Size,
+    IN COMM_PRIORITIES Priority,
+    IN BOOLEAN Wait,
+    IN PVOID WaitOn,
+    IN BOOLEAN ResponseExpected,
+	IN PFIB_CALLBACK FibCallback,
+	IN PVOID FibCallbackContext
+    );
+
+AAC_STATUS
+CompleteFib(
+	IN PFIB_CONTEXT FibContext
+    );
+
+AAC_STATUS
+CompleteAdapterFib(
+	IN PFIB_CONTEXT FibContext,
+    IN USHORT Size
+    );
+
+AAC_STATUS
+InitializeFib(
+	IN PFIB_CONTEXT FibContext
+    );
+
+
+PVOID
+FsaGetFibData(
+	IN PFIB_CONTEXT FibContext
+	);
+
+
+
+AAC_STATUS
+AfaCommOpenAdapter (
+	IN PVOID AdapterArg
+	);
+
+AAC_STATUS
+AfaCommCloseAdapter (
+	IN PVOID AdapterArg
+	);
+
+
+VOID
+AfaCommInterruptHost(
+	PVOID	Adapter,
+	ADAPTER_EVENT	AdapterEvent
+	);
+
+
+#endif // _COMM_PROTO
diff -BburN linux.orig/drivers/scsi/aacraid/include/comstruc.h linux/drivers/scsi/aacraid/include/comstruc.h
--- linux.orig/drivers/scsi/aacraid/include/comstruc.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/comstruc.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,412 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   comstruc.h
+ *
+ * Abstract: This module defines the data structures that make up the communication
+ *           region for the FSA filesystem. This region is how the host based code
+ *           communicates both control and data to the adapter based code.
+ *
+ *
+ *
+ --*/
+#ifndef _COMM_STRUCT
+#define _COMM_STRUCT
+
+//
+// Define all the constants needed for the communication interface
+//
+
+// Define how many queue entries each queue will have and the total number of
+// entries for the entire communication interface. Also define how many queues
+// we support.
+
+#define NUMBER_OF_COMM_QUEUES  8   // 4 command; 4 response
+
+#define HOST_HIGH_CMD_ENTRIES  4
+#define HOST_NORM_CMD_ENTRIES  8
+#define ADAP_HIGH_CMD_ENTRIES  4
+#define ADAP_NORM_CMD_ENTRIES  512
+#define HOST_HIGH_RESP_ENTRIES 4
+#define HOST_NORM_RESP_ENTRIES 512
+#define ADAP_HIGH_RESP_ENTRIES 4
+#define ADAP_NORM_RESP_ENTRIES 8
+
+#define TOTAL_QUEUE_ENTRIES  \
+    (HOST_NORM_CMD_ENTRIES + HOST_HIGH_CMD_ENTRIES + ADAP_NORM_CMD_ENTRIES + ADAP_HIGH_CMD_ENTRIES + \
+	    HOST_NORM_RESP_ENTRIES + HOST_HIGH_RESP_ENTRIES + ADAP_NORM_RESP_ENTRIES + ADAP_HIGH_RESP_ENTRIES)
+
+
+
+
+// Set the queues on a 16 byte alignment
+#define QUEUE_ALIGNMENT		16
+
+
+//
+// The queue headers define the Communication Region queues. These
+// are physically contiguous and accessible by both the adapter and the
+// host. Even though all queue headers are in the same contiguous block they will be
+// represented as individual units in the data structures.
+//
+
+typedef AAC_UINT32 QUEUE_INDEX;
+
+typedef QUEUE_INDEX *PQUEUE_INDEX;
+
+typedef struct _QUEUE_ENTRY {
+
+    AAC_UINT32 Size;                     // Size in bytes of the Fib which this QE points to
+    AAC_UINT32 FibAddress;            	// Receiver addressable address of the FIB (low 32 address bits)
+
+} QUEUE_ENTRY;
+
+typedef QUEUE_ENTRY *PQUEUE_ENTRY;
+
+
+
+// The adapter assumes the ProducerIndex and ConsumerIndex are grouped
+// adjacently and in that order.
+//
+typedef struct _QUEUE_HEADERS {
+
+    PHYSICAL_ADDRESS LogicalHeaderAddress;  // Address to hand the adapter to access to this queue head
+    PQUEUE_INDEX ProducerIndex;              // The producer index for this queue (host address)
+    PQUEUE_INDEX ConsumerIndex;              // The consumer index for this queue (host address)
+
+} QUEUE_HEADERS;
+typedef QUEUE_HEADERS *PQUEUE_HEADERS;
+
+//
+// Define all the events which the adapter would like to notify
+// the host of.
+//
+typedef enum _ADAPTER_EVENT {
+    HostNormCmdQue = 1,         // Change in host normal priority command queue
+    HostHighCmdQue,             // Change in host high priority command queue
+    HostNormRespQue,            // Change in host normal priority response queue
+    HostHighRespQue,            // Change in host high priority response queue
+    AdapNormRespNotFull,
+    AdapHighRespNotFull,
+    AdapNormCmdNotFull,
+    AdapHighCmdNotFull,
+	SynchCommandComplete,
+    AdapInternalError = 0xfe    // The adapter detected an internal error shutting down
+
+} _E_ADAPTER_EVENT;
+
+#ifdef AAC_32BIT_ENUMS
+typedef _E_ADAPTER_EVENT	ADAPTER_EVENT;
+#else
+typedef AAC_UINT32			ADAPTER_EVENT;
+#endif
+
+//
+// Define all the events the host wishes to notify the
+// adapter of.
+//
+typedef enum _HOST_2_ADAP_EVENT {
+    AdapNormCmdQue = 1,
+    AdapHighCmdQue,
+    AdapNormRespQue,
+    AdapHighRespQue,
+    HostShutdown,
+    HostPowerFail,
+    FatalCommError,
+    HostNormRespNotFull,
+    HostHighRespNotFull,
+    HostNormCmdNotFull,
+    HostHighCmdNotFull,
+	FastIo,
+	AdapPrintfDone
+} _E_HOST_2_ADAP_EVENT;
+
+#ifdef AAC_32BIT_ENUMS
+typedef _E_HOST_2_ADAP_EVENT	HOST_2_ADAP_EVENT;
+#else
+typedef	AAC_UINT32				HOST_2_ADAP_EVENT;
+#endif
+
+//
+// Define all the queues that the adapter and host use to communicate
+//
+
+typedef enum _QUEUE_TYPES {
+        HostNormCmdQueue = 1,       // Adapter to host normal priority command traffic
+        HostHighCmdQueue,           // Adapter to host high priority command traffic
+        AdapNormRespQueue,          // Host to adapter normal priority response traffic
+        AdapHighRespQueue,          // Host to adapter high priority response traffic
+        AdapNormCmdQueue,           // Host to adapter normal priority command traffic
+        AdapHighCmdQueue,           // Host to adapter high priority command traffic
+        HostNormRespQueue,          // Adapter to host normal priority response traffic
+        HostHighRespQueue           // Adapter to host high priority response traffic
+} _E_QUEUE_TYPES;
+
+#ifdef AAC_32BIT_ENUMS
+typedef _E_QUEUE_TYPES		QUEUE_TYPES;
+#else
+typedef	AAC_UINT32			QUEUE_TYPES;
+#endif
+
+
+//
+// Assign type values to the FSA communication data structures
+//
+
+typedef enum _STRUCT_TYPES {
+    TFib = 1,
+    TQe,
+	TCtPerf
+} _E_STRUCT_TYPES;
+
+#ifdef AAC_32BIT_ENUMS
+typedef	_E_STRUCT_TYPES	STRUCT_TYPES;
+#else
+typedef	AAC_UINT32		STRUCT_TYPES;
+#endif
+
+//
+// Define the priority levels the FSA communication routines support.
+//
+
+typedef enum _COMM_PRIORITIES {
+    FsaNormal = 1,
+    FsaHigh
+} _E_COMM_PRIORITIES;
+
+#ifdef AAC_32BIT_ENUMS
+typedef _E_COMM_PRIORITIES	COMM_PRIORITIES;
+#else
+typedef	AAC_UINT32			COMM_PRIORITIES;
+#endif
+
+
+
+//
+// Define the LIST_ENTRY structure.  This structure is used on the NT side to link
+// the FIBs together in a linked list.  Since this structure gets compiled on the adapter
+// as well, we need to define this structure for the adapter's use.  If '_NT_DEF_'
+// is defined, then this header is being included from the NT side, and therefore LIST_ENTRY
+// is already defined.
+#if !defined(_NTDEF_) && !defined(_WINNT_)
+typedef struct _LIST_ENTRY {
+   struct _LIST_ENTRY *Flink;
+   struct _LIST_ENTRY *Blink;
+} LIST_ENTRY;
+typedef LIST_ENTRY *PLIST_ENTRY;
+#endif
+
+
+//
+// Define the FIB. The FIB is the where all the requested data and
+// command information are put to the application on the FSA adapter.
+//
+
+typedef struct _FIB_HEADER {
+    AAC_UINT32 XferState;                    // Current transfer state for this CCB
+    AAC_UINT16 Command;                     // Routing information for the destination
+    AAC_UINT8 StructType;                   // Type FIB
+	AAC_UINT8 Flags;						  // Flags for FIB
+    AAC_UINT16 Size;                        // Size of this FIB in bytes
+    AAC_UINT16 SenderSize;                  // Size of the FIB in the sender (for response sizing)
+    AAC_UINT32 SenderFibAddress;          	// Host defined data in the FIB
+    AAC_UINT32 ReceiverFibAddress;        	// Logical address of this FIB for the adapter
+    AAC_UINT32 SenderData;                	// Place holder for the sender to store data
+#ifndef __midl
+	union {
+		struct {
+		    AAC_UINT32 _ReceiverTimeStart; 	// Timestamp for receipt of fib
+		    AAC_UINT32 _ReceiverTimeDone;	// Timestamp for completion of fib
+		} _s;
+		LIST_ENTRY _FibLinks;			// Used to link Adapter Initiated Fibs on the host
+	} _u;
+#else				// The MIDL compiler does not support unions without a discriminant.
+	struct {		// Since nothing during the midl compile actually looks into this
+		struct {	// structure, this shoudl be ok.
+			AAC_UINT32 _ReceiverTimeStart; 	// Timestamp for receipt of fib
+		    AAC_UINT32 _ReceiverTimeDone;	// Timestamp for completion of fib
+		} _s;
+	} _u;
+#endif
+} FIB_HEADER;
+
+
+#define FibLinks			_u._FibLinks
+
+
+#define FIB_DATA_SIZE_IN_BYTES (512 - sizeof(FIB_HEADER))
+
+
+typedef struct _FIB {
+
+#ifdef BRIDGE //rma
+	DLQUE link;
+#endif
+    FIB_HEADER Header;
+
+    AAC_UINT8 data[FIB_DATA_SIZE_IN_BYTES];		// Command specific data
+
+} FIB;
+typedef FIB *PFIB;
+
+
+
+//
+// FIB commands
+//
+
+typedef enum _FIB_COMMANDS {
+    TestCommandResponse = 			1,
+    TestAdapterCommand = 			2,
+
+	// Lowlevel and comm commands
+
+    LastTestCommand = 				100,
+    ReinitHostNormCommandQueue = 	101,
+    ReinitHostHighCommandQueue = 	102,
+    ReinitHostHighRespQueue = 		103,
+    ReinitHostNormRespQueue = 		104,
+    ReinitAdapNormCommandQueue = 	105,
+    ReinitAdapHighCommandQueue = 	107,
+    ReinitAdapHighRespQueue = 		108,
+    ReinitAdapNormRespQueue = 		109,
+    InterfaceShutdown = 			110,
+    DmaCommandFib = 				120,
+    StartProfile = 					121,
+    TermProfile = 					122,
+    SpeedTest = 					123,
+    TakeABreakPt = 					124,
+    RequestPerfData =				125,
+    SetInterruptDefTimer=           126,
+    SetInterruptDefCount=           127,
+    GetInterruptDefStatus=          128,
+    LastCommCommand = 				129,
+
+	// Filesystem commands
+
+    NuFileSystem = 					300,
+    UFS = 							301,
+    HostFileSystem =				302,
+    LastFileSystemCommand = 		303,
+
+	// Container Commands
+
+    ContainerCommand = 				500,
+	ContainerCommand64 =			501,
+
+	// Cluster Commands
+
+    ClusterCommand = 				550,
+
+	// Scsi Port commands (scsi passthrough)
+
+    ScsiPortCommand = 				600,
+
+	// misc house keeping and generic adapter initiated commands
+
+    AifRequest =					700,
+    CheckRevision =					701,
+    FsaHostShutdown = 				702,
+    RequestAdapterInfo = 			703,
+    IsAdapterPaused =				704,
+    SendHostTime =					705,
+    LastMiscCommand =				706
+
+} _E_FIB_COMMANDS;
+
+
+
+typedef AAC_UINT16 FIB_COMMAND;
+
+//
+// Commands that will target the failover level on the FSA adapter
+//
+
+typedef enum _FIB_XFER_STATE {
+    HostOwned 				= (1<<0),
+    AdapterOwned 			= (1<<1),
+    FibInitialized 			= (1<<2),
+    FibEmpty 				= (1<<3),
+    AllocatedFromPool 		= (1<<4),
+    SentFromHost 			= (1<<5),
+    SentFromAdapter 		= (1<<6),
+    ResponseExpected 		= (1<<7),
+    NoResponseExpected 		= (1<<8),
+    AdapterProcessed 		= (1<<9),
+    HostProcessed 			= (1<<10),
+    HighPriority 			= (1<<11),
+    NormalPriority 			= (1<<12),
+    Async					= (1<<13),
+    AsyncIo					= (1<<13),	// rpbfix: remove with new regime
+    PageFileIo				= (1<<14),	// rpbfix: remove with new regime
+    ShutdownRequest			= (1<<15),
+    LazyWrite				= (1<<16),	// rpbfix: remove with new regime
+    AdapterMicroFib			= (1<<17),
+    BIOSFibPath				= (1<<18),
+    FastResponseCapable		= (1<<19),
+	ApiFib					= (1<<20)	// Its an API Fib.
+
+} _E_FIB_XFER_STATE;
+
+
+typedef enum _FSA_ERRORS {
+    FSA_NORMAL                  = 0,
+    FSA_SUCCESS                 = 0,
+    FSA_PENDING                 = 0x01,
+    FSA_FATAL                   = 0x02,
+    FSA_INVALID_QUEUE           = 0x03,
+    FSA_NOENTRIES               = 0x04,
+    FSA_SENDFAILED              = 0x05,
+    FSA_INVALID_QUEUE_PRIORITY  = 0x06,
+    FSA_FIB_ALLOCATION_FAILED   = 0x07,
+    FSA_FIB_DEALLOCATION_FAILED = 0x08
+
+} _E_FSA_ERRORS;
+
+
+//
+// The following defines needs to be updated any time there is an incompatible change made
+// to the ADAPTER_INIT_STRUCT structure.
+//
+#define ADAPTER_INIT_STRUCT_REVISION		3
+
+typedef struct _ADAPTER_INIT_STRUCT {
+	AAC_UINT32		InitStructRevision;
+	AAC_UINT32		MiniPortRevision;
+	AAC_UINT32		FilesystemRevision;
+	PAAC_VOID		CommHeaderAddress;
+	PAAC_VOID		FastIoCommAreaAddress;
+	PAAC_VOID		AdapterFibsPhysicalAddress;
+	PAAC_VOID		AdapterFibsVirtualAddress;
+	AAC_UINT32		AdapterFibsSize;
+	AAC_UINT32		AdapterFibAlign;
+	PAAC_VOID		PrintfBufferAddress;
+	AAC_UINT32		PrintfBufferSize;
+	AAC_UINT32		HostPhysMemPages;		// number of 4k pages of host physical memory
+	AAC_UINT32		HostElapsedSeconds;		// number of seconds since 1970.
+} ADAPTER_INIT_STRUCT;
+typedef ADAPTER_INIT_STRUCT *PADAPTER_INIT_STRUCT;
+
+
+
+
+#endif //_COMM_STRUCT
+
+
diff -BburN linux.orig/drivers/scsi/aacraid/include/comsup.h linux/drivers/scsi/aacraid/include/comsup.h
--- linux.orig/drivers/scsi/aacraid/include/comsup.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/comsup.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,131 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   comsup.h
+ *
+ * Abstract: This module defines the data structures that make up the 
+ *           commuication region for the FSA filesystem. This region is
+ *           how the host based code commuicates both control and data
+ *           to the adapter based code. 
+ *
+ *
+ *
+ --*/
+#ifndef _COMM_SUP_DEF
+#define _COMM_SUP_DEF
+
+
+//
+// The adapter interface specs all queues to be located in the same physically
+// contigous block. The host structure that defines the commuication queues will
+// assume they are each a seperate physically contigous memory region that will
+// support them all being one big contigous block.
+// There is a command and response queue for each level and direction of
+// commuication. These regions are accessed by both the host and adapter.
+//
+typedef struct _COMM_QUE {
+
+    PHYSICAL_ADDRESS LogicalAddress;    // This is the address we give the adapter
+    
+    PQUEUE_ENTRY 	BaseAddress;        // This is the system virtual address 
+    QUEUE_HEADERS 	Headers;            // A pointer to the producer and consumer queue headers for this queue
+    ULONG 			QueueEntries;       // Number of queue entries on this queue
+    OS_CV_T			QueueFull;          // Event to wait on if the queue is full
+    OS_CV_T			CommandReady;       // Indicates there is a Command ready from the adapter on this queue.
+                                        // This is only valid for adapter to host command queues.                                        
+    OS_SPINLOCK	 	*QueueLock;         // Spinlock for this queue must take this lock before accessing the lock
+    KIRQL 			SavedIrql;          // Previous IRQL when the spin lock is taken
+    ddi_softintr_t	ConsumerRoutine;    // The DPC routine which will consume entries off this queue
+                                        // Only queues which the host will be the consumer will this field be valid
+    LIST_ENTRY 		CommandQueue;       // A queue of FIBs which need to be prcessed by the FS thread. This is
+                                        // only valid for command queues which receive entries from the adapter.
+	LIST_ENTRY		OutstandingIoQueue;	// A queue of outstanding fib's to the adapter.
+	ULONG			NumOutstandingIos;	// Number of entries on outstanding queue.
+
+	PVOID			Adapter;			// Back pointer to adapter structure
+
+} COMM_QUE;
+typedef COMM_QUE *PCOMM_QUE;
+
+
+typedef struct _COMM_REGION {
+
+    COMM_QUE HostNormCmdQue;	        // Command queue for normal priority commands from the host
+    COMM_QUE HostNormRespQue;           // A response for normal priority adapter responses
+    
+    COMM_QUE HostHighCmdQue;            // Command queue for high priority commands from the host
+    COMM_QUE HostHighRespQue;           // A response for normal priority adapter responses
+    
+    COMM_QUE AdapNormCmdQue;            // Command queue for normal priority command from the adapter
+    COMM_QUE AdapNormRespQue;           // A response for normal priority host responses
+
+    COMM_QUE AdapHighCmdQue;            // Command queue for high priority command from the adapter
+    COMM_QUE AdapHighRespQue;           // A response for high priority host responses
+
+    //
+    // The 2 threads below are the threads which handle command traffic from the
+    // the adapter. There is one for normal priority and one for high priority queues.
+    // These threads will wait on the commandready event for it's queue.
+    //
+
+    HANDLE NormCommandThread;
+    HANDLE HighCommandThread;
+
+    //
+    // This dpc routine will handle the setting the of not full event when the adapter
+    // lets us know the queue is not longer full via interrupt
+    //
+
+    KDPC QueueNotFullDpc;
+
+#ifdef API_THROTTLE
+	//
+	// Support for data I/O throttling to improve CLI performance
+	// while the system is under load.
+	// This is the throttling mechanism built into the COMM layer.
+	// Look in commsup.c, dpcsup.c and comminit.c for use.
+	//
+
+	int				ThrottleLimit;				// Max queue depth of data ops allowed during throttle
+	int				ThrottleOutstandingFibs;	// Number of data FIBs outstanding to adapter
+	LARGE_INTEGER	ThrottleTimeout;			// Duration of a a throttle period
+	LARGE_INTEGER	ThrottleWaitTimeout;		// Timeout for a suspended threads to wait
+	BOOLEAN			ThrottleActive;				// Is there a current throttle active period ?
+	KTIMER			ThrottleTimer;				// Throttle timer to end a throttle period.
+	KDPC			ThrottleDpc;				// Throttle timer timeout DPC routine.
+	KSEMAPHORE		ThrottleReleaseSema;		// Semaphore callers of SendFib wait on during a throttle.
+
+	unsigned int	ThrottleExceptionsCount;	// Number of times throttle exception handler executed (0!)
+	unsigned int	ThrottleTimerFires;			// Debug info - #times throttle timer Dpc has fired
+	unsigned int	ThrottleTimerSets;			// Debug info - #times throttle timer was set
+
+	unsigned int	ThrottledFibs;
+	unsigned int	ThrottleTimedoutFibs;
+	unsigned int	ApiFibs;
+	unsigned int	NonPassiveFibs;
+	unsigned int	TotalFibs;
+	unsigned int	FSInfoFibs;
+
+#endif // #ifdef API_THROTTLE
+
+} COMM_REGION;
+typedef COMM_REGION *PCOMM_REGION;
+
+#endif // _COMM_SUP
diff -BburN linux.orig/drivers/scsi/aacraid/include/fsact.h linux/drivers/scsi/aacraid/include/fsact.h
--- linux.orig/drivers/scsi/aacraid/include/fsact.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/fsact.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,163 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   fsact.h
+ *
+ * Abstract:  Common container structures that are required to be
+ *            known on both the host and adapter.
+ *
+ *
+ --*/
+#ifndef _FSACT_H_
+#define	_FSACT_H_
+
+//#include <comstruc.h>
+//#include <fsatypes.h>
+#include <protocol.h> // definitions for FSASTATUS
+
+
+/*
+ * Object-Server / Volume-Manager Dispatch Classes
+ */
+typedef enum _VM_COMMANDS {
+   VM_Null = 0,
+   VM_NameServe,
+   VM_ContainerConfig,
+   VM_Ioctl,
+   VM_FilesystemIoctl,
+   VM_CloseAll,
+   VM_CtBlockRead,		// see protocol.h for BlockRead command layout
+   VM_CtBlockWrite,		// see protocol.h for BlockWrite command layout
+   VM_SliceBlockRead,	// raw access to configured "storage objects"
+   VM_SliceBlockWrite,
+   VM_DriveBlockRead,	// raw access to physical devices
+   VM_DriveBlockWrite,
+   VM_EnclosureMgt,		// enclosure management
+   VM_Unused,			// used to be diskset management
+   VM_CtBlockVerify,	// see protocol.h for BlockVerify command layout
+   VM_CtPerf,			// performance test
+   VM_CtBlockRead64,	// see protocol.h for BlockRead64 command layout
+   VM_CtBlockWrite64,	// see protocol.h for BlockWrite64 command layout
+   VM_CtBlockVerify64,	// see protocol.h for BlockVerify64 command layout   
+   MAX_VMCOMMAND_NUM	// used for sizing stats array - leave last
+} _E_VMCOMMAND;
+
+#ifdef AAC_32BIT_ENUMS
+typedef _E_VMCOMMAND	VMCOMMAND;
+#else
+typedef	AAC_UINT32		VMCOMMAND;
+#endif
+
+
+
+//
+// Descriptive information (eg, vital stats)
+// that a content manager might report.  The
+// FileArray filesystem component is one example
+// of a content manager.  Raw mode might be
+// another.
+//
+
+struct FileSysInfo {
+/*
+	a) DOS usage - THINK ABOUT WHERE THIS MIGHT GO -- THXXX
+	b) FSA usage (implemented by ObjType and ContentState fields)
+	c) Block size
+	d) Frag size
+	e) Max file system extension size - (fsMaxExtendSize * fsSpaceUnits)
+	f) I-node density - (computed from other fields)
+*/
+	AAC_UINT32  fsTotalSize;	// consumed by fs, incl. metadata
+	AAC_UINT32  fsBlockSize;
+	AAC_UINT32  fsFragSize;
+	AAC_UINT32  fsMaxExtendSize;
+	AAC_UINT32  fsSpaceUnits;
+	AAC_UINT32  fsMaxNumFiles;
+	AAC_UINT32  fsNumFreeFiles;
+	AAC_UINT32  fsInodeDensity;
+};	// valid iff ObjType == FT_FILESYS && !(ContentState & FSCS_NOTCLEAN)
+
+union ContentManagerInfo {
+	struct FileSysInfo FileSys;	// valid iff ObjType == FT_FILESYS && !(ContentState & FSCS_NOTCLEAN)
+};
+
+//
+// Query for "mountable" objects, ie, objects that are typically
+// associated with a drive letter on the client (host) side.
+//
+
+typedef struct _MNTOBJ {
+
+   AAC_UINT32    ObjectId;
+   FSASTRING  FileSystemName;   // if applicable
+   ContainerCreationInfo   CreateInfo; // if applicable
+   AAC_UINT32    Capacity;
+   FSAVOLTYPE VolType;          // substrate structure
+   FTYPE      ObjType;          // FT_FILESYS, FT_DATABASE, etc.
+   AAC_UINT32     ContentState;     // unready for mounting, readonly, etc.
+
+   union ContentManagerInfo
+              ObjExtension;     // Info specific to content manager (eg, filesystem)
+
+   AAC_UINT32    AlterEgoId;       // != ObjectId <==> snapshot or broken mirror exists
+
+} MNTOBJ;
+
+
+#define FSCS_READONLY	0x0002	// possible result of broken mirror
+
+
+
+typedef struct _MNTINFO {
+
+   VMCOMMAND  Command;
+   FTYPE      MntType;
+   AAC_UINT32     MntCount;
+
+} MNTINFO;
+typedef MNTINFO *PMNTINFO;
+
+typedef struct _MNTINFORESPONSE {
+
+   FSASTATUS Status;
+   FTYPE     MntType;           // should be same as that requested
+   AAC_UINT32    MntRespCount;
+   MNTOBJ    MntTable[1];
+
+} MNTINFORESPONSE;
+typedef MNTINFORESPONSE *PMNTINFORESPONSE;
+
+
+//
+// The following command is sent to shut down each container.
+//
+
+typedef struct _CLOSECOMMAND {
+
+   VMCOMMAND  Command;
+   AAC_UINT32	  ContainerId;
+
+} CLOSECOMMAND;
+typedef CLOSECOMMAND *PCLOSECOMMAND;
+
+
+#endif /* _FSACT_H_ */
+
+
diff -BburN linux.orig/drivers/scsi/aacraid/include/fsafs.h linux/drivers/scsi/aacraid/include/fsafs.h
--- linux.orig/drivers/scsi/aacraid/include/fsafs.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/fsafs.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,77 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   fsafs.h
+ *
+ * Abstract: Common file system structures that are required to be
+ *           known on both the host and adapter
+ *
+ *
+ *
+ --*/
+
+#ifndef _FSAFS_H_
+#define	_FSAFS_H_ 1
+
+
+#include <fsatypes.h>   // core types, shared by client and server, eg, u_long
+
+/*
+ *  Maximum number of filesystems.
+ */
+#define NFILESYS   24
+
+/*
+ * File identifier.
+ * These are unique and self validating within a filesystem
+ * on a single machine and can persist across reboots.
+ * The hint field may be volatile and is not guaranteed to persist
+ * across reboots but is used to speed up the FID to file object translation
+ * if possible. The opaque f1 and f2 fields are guaranteed to uniquely identify
+ * the file object (assuming a filesystem context, i.e. driveno).
+ */
+typedef struct {
+				AAC_UINT32  hint; // last used hint for fast reclaim
+				AAC_UINT32  f1;	  // opaque
+				AAC_UINT32  f2;   // opaque
+			} fileid_t;		/* intra-filesystem file ID type */
+
+	
+/*
+ * Generic file handle
+ */
+struct fhandle {
+	fsid_t	 fh_fsid;	/* File system id of mount point */
+	fileid_t fh_fid;	/* File sys specific file id */
+};
+typedef struct fhandle fhandle_t;
+
+#define	FIDSIZE		sizeof(fhandle_t)
+
+typedef struct {
+	union {
+		AAC_INT8	fid_data[FIDSIZE];
+		struct	fhandle fsafid;
+	} fidu;
+} FSAFID;					/* FSA File ID type */
+
+								
+#endif /* _FSAFS_H_ */
+
diff -BburN linux.orig/drivers/scsi/aacraid/include/fsaioctl.h linux/drivers/scsi/aacraid/include/fsaioctl.h
--- linux.orig/drivers/scsi/aacraid/include/fsaioctl.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/fsaioctl.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,157 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   fsaioctl.h
+ *
+ * Abstract: Defines the interface structures between user mode applications
+ *           and the fsa driver.  This structures are used in 
+ *           DeviceIoControl() calls.
+ *
+ *
+ *
+ --*/
+#ifndef _FSAIOCTL_H_
+#define _FSAIOCTL_H_
+
+#ifndef IOTRACEUSER
+
+#ifndef CTL_CODE
+
+
+#define FILE_DEVICE_CONTROLLER          0x00000004
+
+//
+// Macro definition for defining IOCTL and FSCTL function control codes.  Note
+// that function codes 0-2047 are reserved for Microsoft Corporation, and
+// 2048-4095 are reserved for customers.
+//
+
+#define CTL_CODE( DeviceType, Function, Method, Access ) (                 \
+    ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
+)
+
+//
+// Define the method codes for how buffers are passed for I/O and FS controls
+//
+
+#define METHOD_BUFFERED                 0
+
+
+#define METHOD_NEITHER                  3
+
+//
+// Define the access check value for any access
+//
+//
+// The FILE_READ_ACCESS and FILE_WRITE_ACCESS constants are also defined in
+// ntioapi.h as FILE_READ_DATA and FILE_WRITE_DATA. The values for these
+// constants *MUST* always be in sync.
+//
+#define FILE_ANY_ACCESS                 0
+
+
+
+#endif
+
+
+
+typedef struct _UNIX_QUERY_DISK {
+	AAC_INT32	ContainerNumber;
+	AAC_INT32	Bus;
+	AAC_INT32	Target;
+	AAC_INT32	Lun;
+	AAC_BOOLEAN	Valid;
+	AAC_BOOLEAN	Locked;
+	AAC_BOOLEAN	Deleted;
+	AAC_INT32	Instance;
+	AAC_INT8	diskDeviceName[10];
+	AAC_BOOLEAN UnMapped;
+} UNIX_QUERY_DISK;
+typedef UNIX_QUERY_DISK *PUNIX_QUERY_DISK;
+
+
+typedef struct _DELETE_DISK {
+	AAC_UINT32	NtDiskNumber;
+	AAC_UINT32	ContainerNumber;
+} DELETE_DISK;
+typedef DELETE_DISK *PDELETE_DISK;
+
+
+#endif /*IOTRACEUSER*/
+
+#define FSACTL_NULL_IO_TEST             0x43    // CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2048, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define FSACTL_SIM_IO_TEST              0x53    // CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2049, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+
+#define FSACTL_SENDFIB                  CTL_CODE(FILE_DEVICE_CONTROLLER, 2050, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+
+#define FSACTL_GET_VAR					0x93
+#define FSACTL_SET_VAR					0xa3
+#define FSACTL_GET_FIBTIMES				0xb3
+#define FSACTL_ZERO_FIBTIMES			0xc3
+
+
+#define FSACTL_DELETE_DISK				0x163
+#define FSACTL_QUERY_DISK				0x173
+
+
+// AfaComm perfmon ioctls
+#define FSACTL_GET_COMM_PERF_DATA		CTL_CODE(FILE_DEVICE_CONTROLLER, 2084, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+
+#define FSACTL_OPENCLS_COMM_PERF_DATA	CTL_CODE(FILE_DEVICE_CONTROLLER, 2085, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+
+typedef struct _GET_ADAPTER_FIB_IOCTL {
+	char	*AdapterFibContext;
+	int	  	Wait;
+	char	*AifFib;
+} GET_ADAPTER_FIB_IOCTL, *PGET_ADAPTER_FIB_IOCTL;
+
+//
+// filesystem ioctls
+//
+#define FSACTL_OPEN_GET_ADAPTER_FIB		CTL_CODE(FILE_DEVICE_CONTROLLER, 2100, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define FSACTL_GET_NEXT_ADAPTER_FIB		CTL_CODE(FILE_DEVICE_CONTROLLER, 2101, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define FSACTL_CLOSE_GET_ADAPTER_FIB	CTL_CODE(FILE_DEVICE_CONTROLLER, 2102, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define FSACTL_OPEN_ADAPTER_CONFIG		CTL_CODE(FILE_DEVICE_CONTROLLER, 2103, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+#define FSACTL_CLOSE_ADAPTER_CONFIG		CTL_CODE(FILE_DEVICE_CONTROLLER, 2104, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+
+#define FSACTL_MINIPORT_REV_CHECK		CTL_CODE(FILE_DEVICE_CONTROLLER, 2107, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+
+#define FSACTL_QUERY_ADAPTER_CONFIG		CTL_CODE(FILE_DEVICE_CONTROLLER, 2113, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+
+#define FSACTL_FORCE_DELETE_DISK		CTL_CODE(FILE_DEVICE_CONTROLLER, 2120, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+
+#define FSACTL_AIF_THREAD				CTL_CODE(FILE_DEVICE_CONTROLLER, 2127, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+
+#endif // _FSAIOCTL_H_
+
+
diff -BburN linux.orig/drivers/scsi/aacraid/include/fsaport.h linux/drivers/scsi/aacraid/include/fsaport.h
--- linux.orig/drivers/scsi/aacraid/include/fsaport.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/fsaport.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,221 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   fsaport.h
+ *
+ * Abstract: This module defines all of the globally used procedures in the FSA
+ *           file system.
+ *
+ *
+ *
+ --*/
+#ifndef _FSAPORT_
+#define _FSAPORT_
+
+//
+// The scatter/gather map context is the information we 
+// we need to keep the map and transfer data to and from the
+// adapter.
+//
+
+typedef struct _SGMAP_CONTEXT {
+	
+	caddr_t		BaseAddress;
+    PVOID 		MapRegBase;
+    ULONG 		NumberMapRegs;
+	PSGMAP		SgMapPtr;
+	ULONG		ByteCount;		// Used to check the Mdl length.
+	BOOLEAN		WriteToDevice;
+
+	struct buf	*bp;
+
+
+} SGMAP_CONTEXT;
+typedef SGMAP_CONTEXT *PSGMAP_CONTEXT;
+
+typedef struct _MAPFIB_CONTEXT {
+	PMDL		Mdl;    
+    PVOID 		MapRegBase;
+    ULONG 		NumberMapRegs;
+	PVOID		FibVirtualAddress;
+	ULONG		Size;
+	PVOID	    FibPhysicalAddress;
+
+
+} MAPFIB_CONTEXT;
+typedef MAPFIB_CONTEXT *PMAPFIB_CONTEXT;
+
+typedef BOOLEAN
+(*PFSA_ALLOCATE_ADAPTER_COMM_AREA)(
+	PVOID AdapterExtension,
+	IN OUT PVOID	*BaseAddress,
+	IN ULONG		Size,
+	IN ULONG		Alignment
+	);
+
+typedef BOOLEAN
+(*PFSA_FREE_ADAPTER_COMM_AREA)(
+	PVOID	AdapterExtension
+	);
+
+typedef VOID
+(*PFSA_FREE_DMA_RESOURCES)(	 
+	IN PVOID AdapterExtension,
+    IN PSGMAP_CONTEXT SgMapContext
+    );
+
+typedef BOOLEAN
+(*PFSA_ALLOCATE_AND_MAP_FIB_SPACE)(
+	IN PVOID AdapterExtension, 
+	IN PMAPFIB_CONTEXT MapFibContext
+    );
+
+typedef BOOLEAN
+(*PFSA_UNMAP_AND_FREE_FIB_SPACE)(
+	IN PVOID AdapterExtension, 
+	IN PMAPFIB_CONTEXT MapFibContext
+    );
+
+typedef VOID
+(*PFSA_INTERRUPT_ADAPTER)(
+	IN PVOID AdapterExtension
+	);
+
+typedef VOID
+(*PFSA_NOTIFY_ADAPTER)(
+	IN PVOID AdapterExtension,
+    IN HOST_2_ADAP_EVENT AdapterEvent
+    );
+
+typedef VOID
+(*PFSA_RESET_DEVICE)(
+	PVOID AdapterExtension
+	);
+
+typedef AAC_STATUS
+(*PFSA_BUILD_SGMAP)(  
+	IN PVOID AdapterExtension,
+	IN PSGMAP_CONTEXT SgMapContext
+	);
+
+typedef PVOID
+(*PFSA_ADAPTER_ADDR_TO_SYSTEM_ADDR)(  
+	IN PVOID AdapterExtension,
+	IN PVOID AdapterAddress
+	);
+
+typedef VOID
+(*PFSA_INTERRUPT_HOST)(
+	PVOID			Adapter,
+	ADAPTER_EVENT	AdapterEvent
+	);
+
+typedef VOID
+(*PFSA_ENABLE_INTERRUPT)(
+	PVOID			Adapter,
+	ADAPTER_EVENT	AdapterEvent,
+	BOOLEAN			AtDeviceIrq
+	);
+
+
+typedef VOID
+(*PFSA_DISABLE_INTERRUPT)(
+	PVOID			Adapter,
+	ADAPTER_EVENT	AdapterEvent,
+	BOOLEAN			AtDeviceIrq
+	);
+
+typedef AAC_STATUS
+(*PFSA_OPEN_ADAPTER) (
+	IN PVOID Adapter
+	);
+
+typedef int
+(*PFSA_DEVICE_CONTROL) (
+	IN PVOID Adapter,
+	IN PAFA_IOCTL_CMD IoctlCmdPtr
+	);
+
+typedef AAC_STATUS
+(*PFSA_CLOSE_ADAPTER) (
+	IN PVOID Adapter
+	);
+
+typedef BOOLEAN
+(*PFSA_SEND_SYNCH_FIB) (
+	IN PVOID Adapter,
+	IN ULONG FibPhysicalAddress
+	);
+
+typedef struct _FSAPORT_FUNCS {
+	ULONG								SizeOfFsaPortFuncs;
+
+	PFSA_ALLOCATE_ADAPTER_COMM_AREA		AllocateAdapterCommArea;
+	PFSA_FREE_ADAPTER_COMM_AREA			FreeAdapterCommArea;
+	PFSA_FREE_DMA_RESOURCES				FreeDmaResources;
+	PFSA_ALLOCATE_AND_MAP_FIB_SPACE		AllocateAndMapFibSpace;
+	PFSA_UNMAP_AND_FREE_FIB_SPACE		UnmapAndFreeFibSpace;
+	PFSA_INTERRUPT_ADAPTER				InterruptAdapter;
+	PFSA_NOTIFY_ADAPTER					NotifyAdapter;
+	PFSA_ENABLE_INTERRUPT				EnableInterrupt;
+	PFSA_DISABLE_INTERRUPT				DisableInterrupt;
+	PFSA_RESET_DEVICE					ResetDevice;
+	PFSA_BUILD_SGMAP					BuildSgMap;
+	PFSA_ADAPTER_ADDR_TO_SYSTEM_ADDR	AdapterAddressToSystemAddress;
+
+	PFSA_INTERRUPT_HOST					InterruptHost;
+	PFSA_OPEN_ADAPTER					OpenAdapter;
+	PFSA_DEVICE_CONTROL					DeviceControl;
+	PFSA_CLOSE_ADAPTER					CloseAdapter;
+
+	PFSA_SEND_SYNCH_FIB					SendSynchFib;
+
+} FSAPORT_FUNCS;
+typedef FSAPORT_FUNCS *PFSAPORT_FUNCS;
+
+typedef AAC_STATUS
+(*PFSA_SETVAR_CALLBACK) (
+	IN PVOID Adapter,
+	IN ULONG NewValue
+	);
+
+typedef struct _FSA_USER_VAR {
+	char					Name[32];
+	ULONG					*Address;
+	PFSA_SETVAR_CALLBACK	SetVarCallback;
+} FSA_USER_VAR;
+
+typedef FSA_USER_VAR *PFSA_USER_VAR;
+
+typedef struct _FSA_NEW_ADAPTER {
+	PVOID				AdapterExtension;
+	PFSAPORT_FUNCS		AdapterFuncs;
+	PVOID				Adapter;
+	BOOLEAN				AdapterInterruptsBelowDpc;
+	PFSA_USER_VAR		AdapterUserVars;
+	ULONG				AdapterUserVarsSize;
+	void				*Dip;
+} FSA_NEW_ADAPTER;
+typedef FSA_NEW_ADAPTER *PFSA_NEW_ADAPTER;
+
+#define	FSAFS_GET_NEXT_ADAPTER			CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2048, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define	FSAFS_INIT_NEW_ADAPTER			CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2049, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+#endif
diff -BburN linux.orig/drivers/scsi/aacraid/include/fsatypes.h linux/drivers/scsi/aacraid/include/fsatypes.h
--- linux.orig/drivers/scsi/aacraid/include/fsatypes.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/fsatypes.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,214 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   fsatypes.h
+ *
+ * Abstract: Define all shared data types here, ie, those
+ *           types shared among several components, such
+ *           as host (driver + apps), adapter, and BIOS.
+ *
+ *
+ --*/
+#ifndef _FSATYPES_H
+#define _FSATYPES_H
+
+
+
+typedef	AAC_UINT32		AAC_BOOLEAN;
+
+//
+// Define a 64-bit address structure for use on
+// a 32-bit processor architecture.
+//
+typedef struct {
+	AAC_UINT32		lo32;
+	AAC_UINT32		hi32;
+} AAC_UINT64S, *PAAC_UINT64S;
+
+
+
+//
+// Container Types
+//
+typedef struct {
+   AAC_UINT32 data[2];  // RMA FIX, make this a real serial number when we
+	                    // know what it looks like.  Note, BIOS sees this
+	                    // definition and it must be coded in such a way
+	                    // that it appears to be 64 bits.  ints are 16 bits
+	                    // in BIOS land; fortunately, longs are 32 bits.
+} SerialNumberT;
+
+
+
+//
+//	***********************
+//	DON'T CHANGE THE ORDER, ctdevsw use this order to map the drivers
+//	***********************
+//	drivers for CT_NONE to CT_PASSTHRU
+//
+typedef enum _FSAVOLTYPE {
+	CT_NONE = 0,				
+	CT_VOLUME,					
+	CT_MIRROR,
+	CT_STRIPE,
+	CT_RAID5,
+	CT_SSRW,
+	CT_SSRO,
+	CT_MORPH,
+	CT_PASSTHRU,
+	CT_RAID4,
+	CT_RAID10,					// stripe of mirror
+	CT_RAID00,					// stripe of stripe
+	CT_VOLUME_OF_MIRRORS,		// volume of mirror
+	CT_PSEUDO_RAID3,			// really raid4
+
+	CT_LAST_VOLUME_TYPE
+
+} _E_FSAVOLTYPE;
+
+#ifdef AAC_32BIT_ENUMS
+typedef	_E_FSAVOLTYPE	FSAVOLTYPE;
+#else
+typedef	AAC_UINT32		FSAVOLTYPE;
+#endif
+
+
+//
+// Types of objects addressable in some fashion by the client.
+// This is a superset of those objects handled just by the filesystem
+// and includes "raw" objects that an administrator would use to
+// configure containers and filesystems.
+//
+typedef enum _FTYPE {
+    FT_REG = 1,     // regular file
+    FT_DIR,         // directory
+    FT_BLK,         // "block" device - reserved
+    FT_CHR,         // "character special" device - reserved
+    FT_LNK,         // symbolic link
+    FT_SOCK,        // socket
+    FT_FIFO,        // fifo
+    FT_FILESYS,     // ADAPTEC's "FSA"(tm) filesystem
+    FT_DRIVE,       // physical disk - addressable in scsi by bus/target/lun
+    FT_SLICE,       // virtual disk - raw volume - slice
+    FT_PARTITION,   // FSA partition - carved out of a slice - building block for containers
+    FT_VOLUME,      // Container - Volume Set
+    FT_STRIPE,      // Container - Stripe Set
+    FT_MIRROR,      // Container - Mirror Set
+    FT_RAID5,       // Container - Raid 5 Set
+    FT_DATABASE     // Storage object with "foreign" content manager
+} _E_FTYPE;
+
+#ifdef AAC_32BIT_ENUMS
+typedef	_E_FTYPE	FTYPE;
+#else
+typedef	AAC_UINT32	FTYPE;
+#endif
+
+
+
+//
+// Host side memory scatter gather list
+// Used by the adapter for read, write, and readdirplus operations
+//
+typedef  PAAC_UINT8 HOSTADDRESS;
+
+typedef struct _SGENTRY {
+	HOSTADDRESS 		SgAddress;		/* 32-bit Base address. */
+	AAC_UINT32			SgByteCount;	/* Length. */
+} SGENTRY;
+typedef SGENTRY *PSGENTRY;
+
+
+
+//
+// SGMAP
+//
+// This is the SGMAP structure for all commands that use
+// 32-bit addressing.
+//
+// Note that the upper 16 bits of SgCount are used as flags.
+// Only the lower 16 bits of SgCount are actually used as the
+// SG element count.
+//
+typedef struct _SGMAP {
+	AAC_UINT32		SgCount;
+	SGENTRY			SgEntry[1];
+} SGMAP;
+typedef SGMAP *PSGMAP;
+
+
+
+//
+// SGMAP64
+//
+// This is the SGMAP structure for 64-bit container commands.
+//
+typedef struct _SGMAP64 {
+	AAC_UINT8	SgCount;
+	AAC_UINT8	SgSectorsPerPage;
+	AAC_UINT16	SgByteOffset; // For the first page 
+	AAC_UINT64S	SgEntry[1];	// Must be last entry
+} SGMAP64;
+typedef SGMAP64 *PSGMAP64;
+
+
+
+
+//
+// attempt at common time structure across host and adapter
+//
+typedef struct __TIME_T {
+
+	AAC_UINT32	tv_sec;		/* seconds (maybe, depends upon host) */
+	AAC_UINT32	tv_usec;	/* and nanoseconds (maybe, depends upon host)*/
+
+} TIME_T;
+typedef TIME_T *PTIME_T;
+
+#ifndef _TIME_T
+#define timespec __TIME_T
+#define ts_sec	tv_sec
+#define ts_nsec	tv_usec
+#endif
+
+
+
+
+typedef struct _ContainerCreationInfo
+{
+
+	AAC_UINT8 		ViaBuildNumber;		// e.g., 588
+	AAC_UINT8 		MicroSecond;		// e.g., 588
+	AAC_UINT8	 	Via;				// e.g.,	1 = FSU,
+										//			2 = API,
+	AAC_UINT8	 	YearsSince1900; 	// e.g., 1997 = 97
+	AAC_UINT32		Date;			//
+										// unsigned 	Month		:4;		// 1 - 12
+										// unsigned 	Day			:6;		// 1 - 32
+										// unsigned 	Hour		:6;		// 0 - 23
+										// unsigned 	Minute		:6;		// 0 - 60
+										// unsigned 	Second		:6;		// 0 - 60
+	SerialNumberT	ViaAdapterSerialNumber;	// e.g., 0x1DEADB0BFAFAF001
+} ContainerCreationInfo;
+
+
+#endif // _FSATYPES_H
+
+
diff -BburN linux.orig/drivers/scsi/aacraid/include/linit.h linux/drivers/scsi/aacraid/include/linit.h
--- linux.orig/drivers/scsi/aacraid/include/linit.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/linit.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,112 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   linit.h
+ *
+ * Abstract: Header file for Linux Driver for Adaptec RAID Array Controller
+ *
+ --*/
+/*------------------------------------------------------------------------------
+ *              I N C L U D E S
+ *----------------------------------------------------------------------------*/
+
+#ifndef _LINIT_H_
+#define _LINIT_H_
+
+#include <linux/config.h>
+
+/*------------------------------------------------------------------------------
+ *              D E F I N E S
+ *----------------------------------------------------------------------------*/
+/* Define the AAC SCSI Host Template structure. */
+#define AAC_HOST_TEMPLATE_ENTRY	\
+  { proc_dir:       &AAC_ProcDirectoryEntry, /* ProcFS Directory Entry */ \
+    proc_info:      AAC_ProcDirectoryInfo,   /* ProcFS Info Function   */ \
+    name:           "AAC",                   /* Driver Name            */ \
+    detect:         AAC_DetectHostAdapter,   /* Detect Host Adapter    */ \
+    release:        AAC_ReleaseHostAdapter,  /* Release Host Adapter   */ \
+    info:           AAC_DriverInfo,          /* Driver Info Function   */ \
+    ioctl:          AAC_Ioctl,               /* ioctl Interface        */ \
+    command:        AAC_Command,             /* unqueued command       */ \
+    queuecommand:   AAC_QueueCommand,        /* Queue Command Function */ \
+    abort:          AAC_AbortCommand,        /* Abort Command Function */ \
+    reset:          AAC_ResetCommand,        /* Reset Command Function */ \
+    bios_param:     AAC_BIOSDiskParameters,  /* BIOS Disk Parameters   */ \
+    can_queue:      1,                       /* Default initial value  */ \
+    this_id:        0,                       /* Default initial value  */ \
+    sg_tablesize:   0,                       /* Default initial value  */ \
+    cmd_per_lun:    0,                       /* Default initial value  */ \
+    present:        0,                       /* Default initial value  */ \
+    unchecked_isa_dma: 0,                    /* Default Initial Value  */ \
+    use_new_eh_code:         0,                  /* Default initial value      */ \
+    eh_abort_handler:        AAC_AbortCommand,   /* New Abort Command func     */ \
+    eh_strategy_handler:     NULL,               /* New Strategy Error Handler */ \
+    eh_device_reset_handler: NULL,               /* New Device Reset Handler   */ \
+    eh_bus_reset_handler:    NULL,               /* New Bus Reset Handler      */ \
+    eh_host_reset_handler:   NULL,               /* New Host reset Handler     */ \
+    use_clustering: ENABLE_CLUSTERING        /* Disable Clustering      */ \
+  }
+
+
+/*------------------------------------------------------------------------------
+ *              T Y P E D E F S / S T R U C T S
+ *----------------------------------------------------------------------------*/
+typedef struct	proc_dir_entry proc_dir_entry_t;
+
+
+
+typedef struct AAC_BIOS_DiskParameters
+{
+	int heads;
+	int sectors;
+	int cylinders;
+} AAC_BIOS_DiskParameters_T;
+
+
+/*------------------------------------------------------------------------------
+ *              P R O G R A M   G L O B A L S
+ *----------------------------------------------------------------------------*/
+
+const char *AAC_DriverInfo( struct Scsi_Host * );
+
+extern proc_dir_entry_t AAC_ProcDirectoryEntry;
+
+
+
+/*------------------------------------------------------------------------------
+ *              F U N C T I O N   P R O T O T Y P E S
+ *----------------------------------------------------------------------------*/
+/* Define prototypes for the AAC Driver Interface Functions. */
+int AAC_DetectHostAdapter( Scsi_Host_Template * );
+int AAC_ReleaseHostAdapter( struct Scsi_Host * );
+int AAC_QueueCommand( Scsi_Cmnd *, void ( *CompletionRoutine )( Scsi_Cmnd * ) );
+int AAC_Command( Scsi_Cmnd * );
+int AAC_ResetCommand( Scsi_Cmnd *, unsigned int );
+int AAC_BIOSDiskParameters( Disk *, kdev_t, int * );
+int AAC_ProcDirectoryInfo( char *, char **, off_t, int, int, int );
+int AAC_Ioctl( Scsi_Device *, int, void * );
+
+
+void AAC_SelectQueueDepths(	struct Scsi_Host *, Scsi_Device * );
+
+
+int AAC_AbortCommand( Scsi_Cmnd *scsi_cmnd_ptr );
+
+#endif /* _LINIT_H_ */
diff -BburN linux.orig/drivers/scsi/aacraid/include/monkerapi.h linux/drivers/scsi/aacraid/include/monkerapi.h
--- linux.orig/drivers/scsi/aacraid/include/monkerapi.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/monkerapi.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,97 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   monkerapi.h
+ *
+ * Abstract: This module contains the definitions used by the Host Adapter
+ *      Communications interface.
+ *      This is the interface used for by host programs and the Adapter 
+ *      to communicate via synchronous commands via a shared set of registers
+ *      on a platform (typically doorbells and mailboxes).
+ *
+ --*/
+//**********************************************************************
+//
+//	Monitor / Kernel API
+//
+//	03/24/1998 Bob Peret	Initial creation
+//
+//**********************************************************************
+
+#ifndef MONKER_H
+#define MONKER_H
+
+
+#define	BREAKPOINT_REQUEST					0x00000004
+#define	INIT_STRUCT_BASE_ADDRESS			0x00000005
+
+
+#define	SEND_SYNCHRONOUS_FIB				0x0000000c
+
+
+
+//
+//	Adapter Status Register
+//
+//  Phase Staus mailbox is 32bits:
+//	<31:16> = Phase Status
+//	<15:0>  = Phase
+//
+//  The adapter reports is present state through the phase.  Only
+//  a single phase should be ever be set.  Each phase can have multiple
+//	phase status bits to provide more detailed information about the 
+//	state of the board.  Care should be taken to ensure that any phase status 
+//  bits that are set when changing the phase are also valid for the new phase
+//  or be cleared out.  Adapter software (monitor, iflash, kernel) is responsible
+//  for properly maintining the phase status mailbox when it is running.
+
+//											
+// MONKER_API Phases							
+//
+// Phases are bit oriented.  It is NOT valid 
+// to have multiple bits set						
+//					
+
+
+#define	SELF_TEST_FAILED					0x00000004
+
+
+#define	KERNEL_UP_AND_RUNNING				0x00000080
+#define	KERNEL_PANIC						0x00000100
+
+
+
+//
+// Doorbell bit defines
+//
+
+
+#define DoorBellPrintfDone				(1<<5)	// Host -> Adapter
+
+
+#define DoorBellAdapterNormCmdReady		(1<<1)	// Adapter -> Host
+#define DoorBellAdapterNormRespReady	(1<<2)	// Adapter -> Host
+#define DoorBellAdapterNormCmdNotFull	(1<<3)	// Adapter -> Host
+#define DoorBellAdapterNormRespNotFull	(1<<4)	// Adapter -> Host
+#define DoorBellPrintfReady				(1<<5)	// Adapter -> Host
+
+
+#endif // MONKER_H
+
diff -BburN linux.orig/drivers/scsi/aacraid/include/nodetype.h linux/drivers/scsi/aacraid/include/nodetype.h
--- linux.orig/drivers/scsi/aacraid/include/nodetype.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/nodetype.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,64 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   nodetype.h
+ *
+ * Abstract:     This module defines all of the node type codes used in this development
+ *  shell.  Every major data structure in the file system is assigned a node
+ *  type code that is.  This code is the first CSHORT in the structure and is
+ *  followed by a CSHORT containing the size, in bytes, of the structure.
+ *
+ --*/
+#ifndef _NODETYPE_
+#define _NODETYPE_
+
+typedef CSHORT NODE_TYPE_CODE;
+
+
+#define FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT ((NODE_TYPE_CODE)0x030b)
+#define FSAFS_NTC_FIB_CONTEXT            ((NODE_TYPE_CODE)0x030c)
+
+
+typedef CSHORT NODE_BYTE_SIZE;
+
+
+//
+//  The following definitions are used to generate meaningful blue bugcheck
+//  screens.  On a bugcheck the file system can output 4 ulongs of useful
+//  information.  The first ulong will have encoded in it a source file id
+//  (in the high word) and the line number of the bugcheck (in the low word).
+//  The other values can be whatever the caller of the bugcheck routine deems
+//  necessary.
+//
+//  Each individual file that calls bugcheck needs to have defined at the
+//  start of the file a constant called BugCheckFileId with one of the
+//  FSAFS_BUG_CHECK_ values defined below and then use FsaBugCheck to bugcheck
+//  the system.
+//
+
+
+#define FSAFS_BUG_CHECK_COMMSUP           (0X001e0000)
+#define FSAFS_BUG_CHECK_DPCSUP            (0X001f0000)
+
+
+#define FsaBugCheck(A,B,C) { cmn_err( CE_PANIC, "aacdisk: module %x, line %x, 0x%x, 0x%x, 0x%x ", BugCheckFileId, __LINE__, A, B, C); }
+
+
+#endif // _NODETYPE_
diff -BburN linux.orig/drivers/scsi/aacraid/include/nvramioctl.h linux/drivers/scsi/aacraid/include/nvramioctl.h
--- linux.orig/drivers/scsi/aacraid/include/nvramioctl.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/nvramioctl.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,112 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   nvramioctl.h
+ *
+ * Abstract: This file defines the data structures related to querying
+ *    and controlling the FSA NVRAM/WriteCache subsystem via the NVRAMIOCTL FIB.
+ *
+ --*/
+#ifndef _NVRAMIOCTL_H_
+#define _NVRAMIOCTL_H_ 1
+
+
+
+/*
+ * NVRAM/Write Cache subsystem states
+ */
+typedef enum _NVSTATUS {
+	NVSTATUS_DISABLED = 0,	// present, clean, not being used
+	NVSTATUS_ENABLED,		// present, possibly dirty, ready for use
+	NVSTATUS_ERROR,			// present, dirty, contains dirty data
+							// for bad/missing device
+	NVSTATUS_BATTERY,		// present, bad or low battery, may contain dirty data
+							// for bad/missing device
+	NVSTATUS_UNKNOWN		// present?????
+} _E_NVSTATUS;
+
+#ifdef AAC_32BIT_ENUMS
+typedef _E_NVSTATUS	NVSTATUS;
+#else
+typedef AAC_UINT32	NVSTATUS;
+#endif
+
+/*
+ * NVRAM/Write Cache subsystem battery component states
+ *
+ */
+//NB: this enum should be identical to battery_status in nvram.h
+//	  or else collapsed into one enum someday
+typedef enum _NVBATTSTATUS {
+	NVBATTSTATUS_NONE = 0,	// battery has no power or is not present
+	NVBATTSTATUS_LOW,		// battery is low on power
+	NVBATTSTATUS_OK,			// battery is okay - normal operation possible only in this state
+	NVBATTSTATUS_RECONDITIONING	// no battery present - reconditioning in process
+} _E_NVBATTSTATUS;
+
+#ifdef AAC_32BIT_ENUMS
+typedef	_E_NVBATTSTATUS	NVBATTSTATUS;
+#else
+typedef AAC_UINT32		NVBATTSTATUS;
+#endif
+
+/*
+ * battery transition type
+ */
+typedef enum _NVBATT_TRANSITION {
+	NVBATT_TRANSITION_NONE = 0,	// battery now has no power or is not present
+	NVBATT_TRANSITION_LOW,		// battery is now low on power
+	NVBATT_TRANSITION_OK		// battery is now okay - normal operation possible only in this state
+} _E_NVBATT_TRANSITION;
+
+#ifdef AAC_32BIT_ENUMS
+typedef _E_NVBATT_TRANSITION	NVBATT_TRANSITION;
+#else
+typedef	AAC_UINT32				NVBATT_TRANSITION;
+#endif
+
+/*
+ * NVRAM Info structure returned for NVRAM_GetInfo call
+ */
+typedef struct _NVRAMDEVINFO {
+	AAC_UINT32		NV_Enabled;		/* write caching enabled */
+	AAC_UINT32		NV_Error;		/* device in error state */
+	AAC_UINT32		NV_NDirty;		/* count of dirty NVRAM buffers */
+	AAC_UINT32		NV_NActive;		/* count of NVRAM buffers being written */
+} NVRAMDEVINFO, *PNVRAMDEVINFO;
+
+typedef struct _NVRAMINFO {
+	NVSTATUS		NV_Status;				/* nvram subsystem status */
+	NVBATTSTATUS	NV_BattStatus;			/* battery status */
+	AAC_UINT32		NV_Size;				/* size of WriteCache NVRAM in bytes */
+	AAC_UINT32		NV_BufSize;				/* size of NVRAM buffers in bytes */
+	AAC_UINT32		NV_NBufs;				/* number of NVRAM buffers */
+	AAC_UINT32		NV_NDirty;				/* count of dirty NVRAM buffers */
+	AAC_UINT32		NV_NClean;				/* count of clean NVRAM buffers */
+	AAC_UINT32		NV_NActive;				/* count of NVRAM buffers being written */
+	AAC_UINT32		NV_NBrokered;			/* count of brokered NVRAM buffers */
+	NVRAMDEVINFO	NV_DevInfo[NFILESYS];	/* per device info */
+	AAC_UINT32		NV_BattNeedsReconditioning;	/* boolean */
+	AAC_UINT32		NV_TotalSize;			/* total size of all non-volatile memories in bytes */
+} NVRAMINFO, *PNVRAMINFO;
+
+#endif /* !_NVRAMIOCTL_H_ */
+
+
diff -BburN linux.orig/drivers/scsi/aacraid/include/osheaders.h linux/drivers/scsi/aacraid/include/osheaders.h
--- linux.orig/drivers/scsi/aacraid/include/osheaders.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/osheaders.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,138 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   osheaders.h
+ *
+ * Abstract: Holds all of the header file includes for a particular O/S flavor.
+ *
+ --*/
+#ifndef _OSHEADERS_H_
+#define _OSHEADERS_H_
+
+#include <linux/autoconf.h>	// retrieve the kernel configuration info
+#if defined( CONFIG_MODVERSIONS ) && !defined( MODVERSIONS )
+#define MODVERSIONS	// force it on
+#endif
+
+#include <linux/version.h>
+
+#if defined( MODVERSIONS ) && defined( MODULE )
+#if DRIVER_KERNEL_CODE >= KERNEL_VERSION(2,2,12)
+#ifdef __SMP__
+#include <linux/modversions-smp.h>
+#elif defined( BOOT_DRIVER ) 
+#include <linux/modversions-BOOT.h>
+#else 
+#include <linux/modversions-up.h>
+#endif // ifdef __SMP__
+#else
+#include <linux/modversions.h>
+#endif
+#endif
+
+
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/blk.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/spinlock.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <linux/wait.h>
+#include <linux/malloc.h>
+#include <linux/tqueue.h>
+#include <linux/tasks.h>
+#include <ostypes.h>
+#include "scsi.h"
+#include "hosts.h"
+
+#ifndef intptr_t
+#define intptr_t void *
+#endif
+
+#ifndef cred_t
+#define cred_t void
+#endif
+
+#ifndef paddr32_t
+#define paddr32_t unsigned
+#endif
+
+#ifndef bzero 
+#define bzero(b,len) memset(b,0,len)
+#endif
+
+#ifndef bcopy
+#define bcopy(src,dst,len) memcpy(dst,src,len )
+#endif
+
+#ifndef DEVICE_NR
+#define DEVICE_NR(device) ( ( ( MAJOR( device ) & 7 ) << 4 ) + ( MINOR( device ) >> 4 ) )
+#endif
+
+typedef unsigned uint_t;
+
+typedef enum
+{
+	CE_PANIC = 0,
+	CE_WARN,
+	CE_NOTE, 
+	CE_CONT, 
+	CE_DEBUG,
+	CE_DEBUG2,
+	CE_TAIL
+} CE_ENUM_T;
+
+#define CMN_ERR_LEVEL CE_WARN
+
+#ifndef IN
+#define IN
+#endif
+
+// usage of READ & WRITE as a typedefs in protocol.h
+// conflicts with <linux/fs.h> definition.
+#ifdef READ
+#undef READ
+#endif
+
+#ifdef WRITE
+#undef WRITE
+#endif
+
+typedef struct aac_options
+{
+	int message_level;
+	int reverse_scan; 
+} aac_options_t;
+
+#endif // _OSHEADERS_H_
+
diff -BburN linux.orig/drivers/scsi/aacraid/include/ostypes.h linux/drivers/scsi/aacraid/include/ostypes.h
--- linux.orig/drivers/scsi/aacraid/include/ostypes.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/ostypes.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,147 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   ostypes.h
+ *
+ * Abstract: Holds all of the O/S specific types.
+ *
+ --*/
+/*------------------------------------------------------------------------------
+ *              D E F I N E S
+ *----------------------------------------------------------------------------*/
+#ifndef _OSTYPES_H_
+#define _OSTYPES_H_
+
+#include <linux/types.h>
+
+#define MAXIMUM_NUM_CONTAINERS	64		// 4 Luns * 16 Targets
+#define MAXIMUM_NUM_ADAPTERS	8
+
+#define OS_ALLOC_MEM_SLEEP		GFP_KERNEL
+
+#define Os_remove_softintr OsSoftInterruptRemove
+#define OsPrintf printk
+#define FsaCommPrint OsPrintf
+
+// the return values for copy_from_user & copy_to_user is the 
+// number of bytes not transferred. Thus if an internal error 
+// occurs, the return value is greater than zero.
+#define COPYIN(SRC,DST,COUNT,FLAGS)  copy_from_user(DST,SRC,COUNT)
+#define COPYOUT(SRC,DST,COUNT,FLAGS) copy_to_user(DST,SRC,COUNT)
+
+#define copyin(SRC,DST,COUNT) copy_from_user(DST,SRC,COUNT)
+#define copyout(SRC,DST,COUNT) copy_to_user(DST,SRC,COUNT)
+
+/*------------------------------------------------------------------------------
+ *              S T R U C T S / T Y P E D E F S
+ *----------------------------------------------------------------------------*/
+typedef struct OS_MUTEX
+{
+	unsigned long lock_var;
+	struct wait_queue * wq_ptr;
+	unsigned owner;
+} OS_MUTEX;
+
+typedef	struct OS_SPINLOCK
+{
+	spinlock_t	spin_lock;
+	unsigned cpu_lock_count[NR_CPUS];
+	long cpu_flag;
+	long lockout_count;
+} OS_SPINLOCK;
+
+#ifdef CVLOCK_USE_SPINLOCK
+	typedef OS_SPINLOCK OS_CVLOCK;
+#else
+	typedef OS_MUTEX OS_CVLOCK;
+#endif
+
+typedef size_t		OS_SIZE_T;
+
+typedef	struct OS_CV_T
+{
+	unsigned long lock_var;
+	unsigned long type;
+	struct wait_queue *wq_ptr;	
+} OS_CV_T;
+
+struct fsa_scsi_hba {
+	void				*CommonExtension;
+	unsigned long		ContainerSize[MAXIMUM_NUM_CONTAINERS];
+	unsigned long		ContainerType[MAXIMUM_NUM_CONTAINERS];
+	unsigned char		ContainerValid[MAXIMUM_NUM_CONTAINERS];
+	unsigned char		ContainerReadOnly[MAXIMUM_NUM_CONTAINERS];
+	unsigned char		ContainerLocked[MAXIMUM_NUM_CONTAINERS];
+	unsigned char		ContainerDeleted[MAXIMUM_NUM_CONTAINERS];
+	long				ContainerDevNo[MAXIMUM_NUM_CONTAINERS];
+};
+
+typedef struct fsa_scsi_hba fsadev_t;
+
+typedef struct OsKI
+{
+	struct Scsi_Host *scsi_host_ptr;
+	void * dip;	// #REVISIT#
+	fsadev_t fsa_dev;
+	int thread_pid;
+  int    MiniPortIndex;
+} OsKI_t;
+
+#define dev_info_t	fsadev_t
+
+typedef int	OS_SPINLOCK_COOKIE;
+
+typedef unsigned int	OS_STATUS;
+
+typedef struct tq_struct OS_SOFTINTR;
+
+typedef	OS_SOFTINTR	*ddi_softintr_t;
+
+
+
+//-----------------------------------------------------------------------------
+// Conditional variable functions
+
+void OsCv_init ( 
+	OS_CV_T *cv_ptr );
+
+
+//-----------------------------------------------------------------------------
+// Printing functions
+void printk_err(int flag, char *fmt, ...);
+
+#define cmn_err printk_err
+
+
+//
+// just ignore these solaris ddi functions in the code
+//
+#define DDI_SUCCESS 						0
+
+#define ddi_add_softintr(A,B,C,D,E,F,G)		OsSoftInterruptAdd(C,F,G)
+
+//#REVIEW#
+#define ddi_remove_softintr(A)				0
+#define ddi_get_soft_iblock_cookie(A, B, C)	0
+
+#define ASSERT(expr) ((void) 0)
+#define drv_usecwait udelay
+
+#endif // _OSTYPES_H_
diff -BburN linux.orig/drivers/scsi/aacraid/include/pcisup.h linux/drivers/scsi/aacraid/include/pcisup.h
--- linux.orig/drivers/scsi/aacraid/include/pcisup.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/pcisup.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,102 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   pcisup.h
+ *
+ * Abstract: This module defines functions that are defined in PciSup.c
+ *
+ --*/
+#ifndef _PCISUP_
+#define _PCISUP_
+
+
+
+	
+/*
+ * define which interrupt handler needs to be installed
+ */
+
+#define SaISR	1
+#define RxISR	2
+
+typedef struct _PCI_MINIPORT_COMMON_EXTENSION {
+	ULONG					AdapterNumber;			// Which FSA# this miniport is
+	
+	ULONG					PciBusNumber;			// Which PCI bus we are located on
+	ULONG					PciSlotNumber;			// Whiat PCI slot we are in
+	
+	PVOID					Adapter;				// Back pointer to Fsa adapter object
+	ULONG					AdapterIndex;			// Index into PlxAdapterTypes array
+	PDEVICE_OBJECT			DeviceObject;			// Pointer to our device object
+	
+	FSAPORT_FUNCS			AdapterFuncs;
+	ULONG					FilesystemRevision; 	// Main driver's revision number
+	
+// 	KIRQL 					IsrIrql;				// irql our isr runs at
+//	PKINTERRUPT				IsrObject;				// Our Interrupt object
+//	ULONG					NumMapRegs; 			// Max amount map regs per dma allowed by the system
+//	PADAPTER_OBJECT 		NtAdapter;				// The adapter object for the cyclone board
+	
+	PADAPTER_INIT_STRUCT	InitStruct;				// Holds initialization info to communicate with adapter
+	PVOID					PhysicalInitStruct; 	// Holds physical address of the init struct
+	
+//	PFASTIO_STRUCT			FastIoCommArea; 		// pointer to common buffer used for FastIo communication (Host view)
+	
+	PVOID					PrintfBufferAddress;	// pointer to buffer used for printf's from the adapter
+	
+	BOOLEAN 				AdapterPrintfsToScreen; 		
+	BOOLEAN 				AdapterConfigured;		// set to true when we know adapter can take FIBs
+	
+	void *					MiniPort;
+	
+	caddr_t					CommAddress;	// Base address of Comm area
+	paddr32_t				CommPhysAddr;	// Physical Address of Comm area
+	size_t					CommSize;
+
+	OsKI_t 					OsDep;			// OS dependent kernel interfaces
+
+	
+} PCI_MINIPORT_COMMON_EXTENSION;
+
+typedef PCI_MINIPORT_COMMON_EXTENSION *PPCI_MINIPORT_COMMON_EXTENSION;
+
+typedef int
+(*PFSA_MINIPORT_INIT) (
+	IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension,
+	IN ULONG AdapterNumber,
+	IN ULONG PciBus,
+	IN ULONG PciSlot
+	);
+
+typedef struct _FSA_MINIPORT {
+	USHORT				VendorId;
+	USHORT				DeviceId;
+	USHORT				SubVendorId;
+	USHORT				SubSystemId;
+	PCHAR				DevicePrefix;
+	PFSA_MINIPORT_INIT	InitRoutine;
+  PCHAR               DeviceName;
+  PCHAR               Vendor;
+  PCHAR               Model;
+} FSA_MINIPORT;
+typedef FSA_MINIPORT *PFSA_MINIPORT;
+
+
+#endif // _PCISUP_
diff -BburN linux.orig/drivers/scsi/aacraid/include/perfpack.h linux/drivers/scsi/aacraid/include/perfpack.h
--- linux.orig/drivers/scsi/aacraid/include/perfpack.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/perfpack.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,109 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   perfpack.h
+ *
+ * Abstract: This file defines the layout of the performance data that is passed
+ *           back from the FSA filesystem driver.
+ *
+ *	
+ --*/
+
+#ifndef _FSA_PERFPACK_H_
+#define _FSA_PERFPACK_H_	1
+
+
+//#define FSA_DO_PERF		1		/* enable the engineering counters */
+
+#ifdef FSA_DO_PERF
+//
+// engineering counters
+//
+typedef struct _FSA_PERF_DATA {
+			ULONG FibsSent;
+			ULONG ReadDirs;
+			ULONG GetAttrs;
+			ULONG SetAttrs;
+			ULONG Lookups;
+			ULONG ReadFibs;
+			ULONG WriteFibs;
+			ULONG CreateFibs;
+			ULONG MakeDirs;
+			ULONG RemoveFibs;
+			ULONG RemoveDirs;
+			ULONG RenameFibs;
+			ULONG ReadDirPlus;
+			ULONG FsStat;
+			ULONG WriteBytes;
+			ULONG ReadBytes;
+// NT FSA entry points
+			ULONG FsaFsdCreateCount;
+			ULONG FsaFsdCloseCount;
+			ULONG FsaFsdReadCount;
+			ULONG FsaFsdWriteCount;
+			ULONG FsaFsdQueryInformationCount;
+
+			struct _FsaFsdSetInfomation{
+				ULONG FsaSetAllocationInfoCount;
+				ULONG FsaSetBasicInfoCount;
+				ULONG FsaSetDispositionInfoCount;
+				ULONG FsaSetEndOfFileInfoCount;
+				ULONG FsaSetPositionInfoCount;
+				ULONG FsaSetRenameInfoCount;
+				ULONG FsaClearArchiveBitCount;
+			};
+
+			ULONG FsaFsdFlushBuffersCount;
+			ULONG FsaFsdQueryVolumeInfoCount;
+			ULONG FsaFsdSetVolumeInfoCount;
+			ULONG FsaFsdCleanupCount;
+			ULONG FsaFsdDirectoryControlCount;
+			ULONG FsaFsdFileSystemControlCount;
+			ULONG FsaFsdLockControlCount;
+			ULONG FsaFsdDeviceControlCount;
+			ULONG FsaFsdShutdownCount;
+			ULONG FsaFsdQuerySecurityInfo;
+			ULONG FsaFsdSetSecurityInfo;
+			ULONG FastIoCheckIfPossibleCount;
+			ULONG FastIoReadCount;
+			ULONG FastIoWriteCount;
+			ULONG FastIoQueryBasicInfoCount;
+			ULONG FastIoQueryStandardInfoCount;
+			ULONG FastIoLockCount;
+			ULONG FastIoUnlockSingleCount;
+			ULONG FastIoUnlockAllCount;
+			ULONG FastIoUnlockAllByKeyCount;
+			ULONG FastIoDeviceControlCount;
+ } FSA_PERF_DATA;
+
+typedef FSA_PERF_DATA *PFSA_PERF_DATA;
+
+
+#else /* FSA_DO_PERF */
+
+//
+// engineering performance counters are disabled
+//
+#define FSA_DO_PERF_INC(Counter)		/* */
+#define FSA_DO_FSP_PERF_INC(Counter)	/* */
+
+#endif /* FSA_DO_PERF */
+
+#endif // _FSA_PERFPACK_H_
diff -BburN linux.orig/drivers/scsi/aacraid/include/port.h linux/drivers/scsi/aacraid/include/port.h
--- linux.orig/drivers/scsi/aacraid/include/port.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/port.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,86 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   port.h
+ *
+ * Abstract: This module defines functions and structures that are in common among all miniports
+ *
+ *	
+ --*/
+
+#ifndef _PORT_
+#define _PORT_
+
+
+#ifdef DBG
+#define AfaPortPrint if (AfaPortPrinting) DbgPrint
+extern int AfaPortPrinting;
+#else
+#define AfaPortPrint 
+#endif DBG
+
+extern int AfaPortPrinting;
+
+
+BOOLEAN
+AfaPortAllocateAdapterCommArea(
+	IN PVOID		Arg1,
+	IN OUT PVOID	*CommHeaderAddress,
+	IN ULONG		CommAreaSize,
+	IN ULONG		CommAreaAlignment
+	);
+
+
+BOOLEAN
+AfaPortFreeAdapterCommArea(
+	IN PVOID		Arg1
+	);
+
+
+AAC_STATUS
+AfaPortBuildSgMap(
+	PVOID Arg1,
+	IN PSGMAP_CONTEXT SgMapContext
+	);
+
+
+VOID
+AfaPortFreeDmaResources(
+	PVOID Arg1,
+    IN PSGMAP_CONTEXT SgMapContext
+    );
+
+
+BOOLEAN
+AfaPortAllocateAndMapFibSpace(
+	PVOID Arg1,
+    IN PMAPFIB_CONTEXT MapFibContext
+    );
+
+
+BOOLEAN
+AfaPortUnmapAndFreeFibSpace(
+	PVOID Arg1,
+    IN PMAPFIB_CONTEXT MapFibContext
+    );
+
+
+#endif // _PORT_
+
diff -BburN linux.orig/drivers/scsi/aacraid/include/protocol.h linux/drivers/scsi/aacraid/include/protocol.h
--- linux.orig/drivers/scsi/aacraid/include/protocol.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/protocol.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,248 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   protocol.h
+ *
+ * Abstract: Defines the commands and command data which enables the nt
+ *    filesystem driver to be the client of the fsa adapter
+ *    filesystem. This protocol is largely modeled after the NFS
+ *    V3 protocol with modifications allowed due to the unique
+ *    client/server model FSA works under.
+ *
+ *
+ *	
+ --*/
+
+#ifndef _PROTOCOL_H_
+#define _PROTOCOL_H_
+
+
+#include <fsafs.h>      // definition of FSAFID; includes fsatypes.h
+#include <nvramioctl.h> // for NVRAMINFO definition
+
+// #define MDL_READ_WRITE
+
+//
+// Define the command values
+//
+typedef enum _FSA_COMMANDS {
+        Null = 0,
+        GetAttributes,
+        SetAttributes,
+        Lookup,
+        ReadLink,
+        Read,
+        Write,
+        Create,
+        MakeDirectory,
+        SymbolicLink,
+        MakeNode,
+        Removex,
+        RemoveDirectoryx, // bkpfix added x to this because already defined in nt
+        Rename,
+        Link,
+        ReadDirectory,
+        ReadDirectoryPlus,
+        FileSystemStatus,
+        FileSystemInfo,
+        PathConfigure,
+        Commit,
+        Mount,
+        UnMount,
+        Newfs,
+        FsCheck,
+        FsSync,
+		SimReadWrite,
+		SetFileSystemStatus,
+		BlockRead,
+		BlockWrite,
+		NvramIoctl,
+		FsSyncWait,
+		ClearArchiveBit,
+#ifdef MDL_READ_WRITE
+		MdlReadComplete,
+		MdlWriteComplete,
+		MdlRead,			// these are used solely for stats, Mdl really controlled by 
+		MdlWrite,			// flags field in Fib.
+#endif
+		SetAcl,
+		GetAcl,
+		AssignAcl,
+		FaultInsertion,		// Fault Insertion Command
+		CrazyCache,			// crazycache
+		MAX_FSACOMMAND_NUM	//CJ: used for sizing stats array - leave last
+} _E_FSACOMMAND;
+
+#ifdef AAC_32BIT_ENUMS
+typedef	_E_FSACOMMAND	FSACOMMAND;
+#else
+typedef AAC_UINT32		FSACOMMAND;
+#endif
+
+
+
+//
+// Define the status returns
+//
+// See include\comm\errno.h for adapter kernel errno's
+typedef enum _FSASTATUS {
+	ST_OK = 0,
+	ST_PERM = 1,
+	ST_NOENT = 2,
+	ST_IO = 5,
+	ST_NXIO = 6,
+	ST_E2BIG = 7,
+	ST_ACCES = 13,
+	ST_EXIST = 17,
+	ST_XDEV = 18,
+	ST_NODEV = 19,
+	ST_NOTDIR = 20,
+	ST_ISDIR = 21,
+	ST_INVAL = 22,
+	ST_FBIG = 27,
+	ST_NOSPC = 28,
+	ST_ROFS = 30,
+	ST_MLINK = 31,
+	ST_WOULDBLOCK = 35,
+	ST_NAMETOOLONG = 63,
+	ST_NOTEMPTY = 66,
+	ST_DQUOT = 69,
+	ST_STALE = 70,
+	ST_REMOTE = 71,
+	ST_BADHANDLE = 10001,
+	ST_NOT_SYNC = 10002,
+	ST_BAD_COOKIE = 10003,
+	ST_NOTSUPP = 10004,
+	ST_TOOSMALL = 10005,
+	ST_SERVERFAULT = 10006,
+	ST_BADTYPE = 10007,
+	ST_JUKEBOX = 10008,
+	ST_NOTMOUNTED = 10009,
+	ST_MAINTMODE = 10010,
+	ST_STALEACL = 10011
+} _E_FSASTATUS;
+
+#ifdef AAC_32BIT_ENUMS
+typedef _E_FSASTATUS	FSASTATUS;
+#else
+typedef	AAC_UINT32		FSASTATUS;
+#endif
+
+//
+// On writes how does the client want the data written.
+//
+
+typedef enum _CACHELEVEL {
+	CSTABLE = 1,
+    CUNSTABLE
+} _E_CACHELEVEL;
+
+#ifdef AAC_32BIT_ENUMS
+typedef _E_CACHELEVEL	CACHELEVEL;
+#else
+typedef	AAC_UINT32		CACHELEVEL;
+#endif
+
+//
+// Lets the client know at which level the data was commited on a write request
+//
+
+typedef enum _COMMITLEVEL {
+    CMFILE_SYNCH_NVRAM = 1,
+    CMDATA_SYNCH_NVRAM,
+    CMFILE_SYNCH,
+    CMDATA_SYNCH,
+    CMUNSTABLE
+} _E_COMMITLEVEL;
+
+#ifdef AAC_32BIT_ENUMS
+typedef _E_COMMITLEVEL	COMMITLEVEL;
+#else
+typedef AAC_UINT32		COMMITLEVEL;
+#endif
+
+
+
+//
+// The following are all the different commands or FIBs which can be sent to the
+// FSA filesystem. We will define a required subset which cannot return STATUS_NOT_IMPLEMENTED,
+// but others outside that subset are allowed to return not implemented. The client is then
+// responsible for dealing with the fact it is not implemented.
+//
+typedef AAC_INT8 FSASTRING[16];
+
+
+typedef AAC_UINT32	BYTECOUNT;	// only 32 bit-ism
+
+
+
+//
+// BlockRead
+//
+
+typedef struct _BLOCKREAD { // variable size struct
+
+    FSACOMMAND 		Command;
+    AAC_UINT32 		ContainerId;
+    BYTECOUNT 		BlockNumber;
+    BYTECOUNT 		ByteCount;
+	SGMAP			SgMap;	// Must be last in struct because it is variable
+
+} BLOCKREAD;
+typedef BLOCKREAD *PBLOCKREAD;
+
+typedef struct _BLOCKREADRESPONSE {
+
+    FSASTATUS 		Status;
+    BYTECOUNT 		ByteCount;
+
+} BLOCKREADRESPONSE;
+typedef BLOCKREADRESPONSE *PBLOCKREADRESPONSE;
+
+//
+// BlockWrite
+//
+
+typedef struct _BLOCKWRITE {	// variable size struct
+
+    FSACOMMAND 		Command;
+    AAC_UINT32 		ContainerId;
+    BYTECOUNT 		BlockNumber;
+    BYTECOUNT 		ByteCount;
+    CACHELEVEL 		Stable;
+	SGMAP			SgMap;	// Must be last in struct because it is variable
+
+} BLOCKWRITE;
+typedef BLOCKWRITE *PBLOCKWRITE;
+
+
+typedef struct _BLOCKWRITERESPONSE {
+
+    FSASTATUS 		Status;
+    BYTECOUNT 		ByteCount;
+    COMMITLEVEL 	Committed;
+
+} BLOCKWRITERESPONSE;
+typedef BLOCKWRITERESPONSE *PBLOCKWRITERESPONSE;
+
+
+
+#endif // _PROTOCOL_H_
+
diff -BburN linux.orig/drivers/scsi/aacraid/include/revision.h linux/drivers/scsi/aacraid/include/revision.h
--- linux.orig/drivers/scsi/aacraid/include/revision.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/revision.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,349 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   revision.h
+ *
+ * Abstract: This module contains all of the revision information for
+ *	the FSA product, as well as the support routines for
+ *	checking module compatibility.
+ *
+ *	Before editing anything in this module, make sure that
+ *	you read the comments. Some lines are changed automatically
+ *	as part of the build, and should never be changed by hand.
+ *
+ * Routines (all inlines):
+ *
+ *	RevGetBuildNumber - Retrieve current build number
+ *	RevGetExternalRev - Retrieve revision for external use
+ *	RevGetFullRevision - Retrieve full revision structure
+ *
+ *	RevCheckCompatibility - Checks compatibility base on internal table
+ *
+ * 	RevCheckCompatibilityFullInfo - Check for static component
+ *	RevGetCompInfoTableSize - Get size for static component table
+ *	RevGetCompInfoTable - Get actual table to place on static component
+ *	RevGetBuildNumberFromInfo - Get build number for static component.
+ *
+ *
+ *	
+ --*/
+
+#ifndef _REVISION_H
+#define _REVISION_H
+
+
+#include "version.h" // revision numbers kept separate so they can be used by resource compiler as well
+
+typedef int REV_BOOL;
+
+#define REV_TRUE 1
+#define REV_FALSE 0
+
+//
+//	Define Revision Levels for this product
+//
+//  IMPORTANT: Do NOT modify BUILD_NUMBER define, this is modified
+//			   automatically by the build.
+//
+//  Version is VMAJOR.MINOR-DASH TYPE (Build BUILD_NUMBER)
+//
+//	IMPORTANT: Don't access these revisions directly. They can be
+//			   accessed via, the RevGetXxxxx rouines.
+//
+
+
+#define REV_AS_LONGWORD \
+	((REV_MAJOR << 24) | (REV_MINOR << 16) | (REV_TYPE << 8) | (REV_DASH))
+
+
+
+#ifndef BIOS
+
+//
+//	Enumerate the types of product levels we can have
+//
+enum {
+	RevType_Devo=1,		// Development mode, testing all of latest
+	RevType_Alpha,		// Alpha - Internal field test
+	RevType_Beta,		// Beta - External field test
+	RevType_Release		// Release - Retail version
+};
+
+//
+//	Define the basic structure for all revision information. Note
+//	that the ordering of the components is such that they should
+//	always increase. dash will be updated the most, then the version
+//	type, then minor and major.
+//
+typedef struct {
+	union {
+		struct {
+			unsigned char dash;	// Dash version number
+			unsigned char type;	// Type, 1=Devo, 2=Alpha, 3=Beta, 4=Release
+			unsigned char minor;// Minor version minor
+			unsigned char major;// Major version number
+		} comp;				// Components to external viewed rev number
+		unsigned long ul;	// External revision as single 32-bit value
+	} external;			// External revision number (union)
+	unsigned long buildNumber; // Automatically generated build number
+} FsaRevision;
+
+
+//
+//	Define simple routines to get basic revision information. The
+//	definitions should never be accessed directly. These routines
+//	are meant to be used to access all relevant information no matter
+//	how simple.
+//
+static inline unsigned long RevGetBuildNumber() {return REV_BUILD_NUMBER;}
+
+static inline unsigned long RevGetExternalRev() {return REV_AS_LONGWORD;}
+
+
+//
+//	Enumerate different components that may have to check
+//	compatibility. This list of components can be changed
+//	at any time.
+//
+//	IMPORTANT: ONLY add to the END of this enum structure. Otherwise,
+//			   incompatibilities between component rev checking will
+//			   cause wrong checking results.
+//
+typedef enum {
+	RevApplication = 1,	// Any user End application
+	RevDkiCli,			// ADAPTEC proprietary interface (knows FIBs)
+	RevNetService,		// Network Service Revision (under API)
+	RevApi,				// ADAPTEC User mode API
+	RevFileSysDriver,	// FSA File System Driver
+	RevMiniportDriver,	// FSA File System Miniport Driver
+	RevAdapterSW,		// Adapter Software (or NT Simulator)
+	RevMonitor,			// Monitor for adapter hardware (MON960 for now)
+	RevRemoteApi		// The remote API.
+	// ALWAYS ADD NEW COMPONENTS HERE - AT END
+} RevComponent;
+
+//
+//	Define a structure so that we can create a compatibility table.
+//
+typedef struct {
+	RevComponent A,B;
+	unsigned long BuildNumOfB_RequiredByA;
+	unsigned long BuildNumOfA_RequiredByB;
+} RevCompareElement;
+
+//
+//	Now, define the table. This table should only be included once,
+//	in one program. If it is linked from 2 modules, there will likely
+//	be a multiply defined symbol error from the linker.
+//
+//	To fix this problem, REV_REFERENCE_ONLY can be defined. This will
+//	allow access to the revision information table without a redefinition
+//	of the tables.
+//
+extern const int			   RevCompareTableLength;
+
+extern const RevCompareElement RevCompareTable[];
+
+/********************************************************************\
+* Routine: RevCheckCompatibility(callerComp,compB,compB_BuildNumber)
+*
+*	The following routine is used to check compatibility between
+*	the calling component and a component that has some dependencies
+*	on it. If this routine returns REV_FALSE, it is expected that the caller
+*	will send an appropriate incompatibility message and stop.
+*
+*	This routine is only meant to check for compatibility in the
+*	absolute sense. If code wishes to execute a different path based
+*	on the CompB_BuildNumber, then this routine is not useful. The
+*	routine RevGetBuildNumber can be used to get the calling module's
+*	current build number for a comparison check.
+*
+*	The return value is REV_TRUE, if compatibility is possible, and REV_FALSE
+*	if the components are definitely not compatible, or there is an
+*	error when trying to figure it out. To be more specific:
+*
+*		1) REV_TRUE if component B is newer than calling component. (In this
+*		   case, the revision check done by component B with respect to
+*		   this component will give the real compatibility information.
+*		   It is the only one with the knowledge, since this component
+*		   could not look into the future.)
+*		2) REV_TRUE if calling component is more recent and table shows okay
+*		3) REV_FALSE if calling component more recent and table show not okay
+*		4) REV_FALSE if calling component is more recent and table entry to
+*		   check does not exist.
+*
+*	Note that the CompB_BuildNumber must be attained by the calling
+*	routine through some mechanism done by the caller.
+*
+* Input:
+*
+*	callerComp - Name of component making this call
+*	compB - Name of component to check compatibility with
+*	compB_BuildNumber - Build number to component B
+*
+* Output:
+*
+*	None
+*
+* Return Value:
+*
+*	REV_TRUE - Component compatibility is possible, continue as usual. compB
+*		   must give true compatibility information.
+*	REV_FALSE - Incompatible components, notify and end
+*
+\********************************************************************/
+static inline REV_BOOL RevCheckCompatibility(
+		RevComponent callerComp,
+		RevComponent compB,
+		unsigned long compB_BuildNumber)
+{
+	int i;
+	unsigned long RevForB;
+
+	//
+	//	Compatibility check is possible, so we should continue. When
+	//	compB makes this call in its own component, it will get the
+	//	true compatibility information, since only it can know.
+	//
+	if (RevGetBuildNumber() < compB_BuildNumber) return REV_TRUE;
+
+	//
+	//	Go through rev table. When the components are found in the
+	//	same table entry, return the approprate number.
+	//
+	for (i=0; i<RevCompareTableLength; i++) {
+		if (RevCompareTable[i].A == callerComp) {
+			if (RevCompareTable[i].B == compB) {
+				RevForB = RevCompareTable[i].BuildNumOfB_RequiredByA;
+				return (compB_BuildNumber >= RevForB);
+			}
+		} else if (RevCompareTable[i].B == callerComp) {
+			if (RevCompareTable[i].A == compB) {
+				RevForB = RevCompareTable[i].BuildNumOfA_RequiredByB;
+				return (compB_BuildNumber >= RevForB);
+			}
+		}
+	}
+
+	//
+	//	Uh oh! No relevant table entry was found (this should never
+	//	happen).
+	//
+	return REV_FALSE;
+}
+
+
+//
+//	Now create a structure that can be used by a FIB to check
+//	compatibility.
+//
+typedef struct _RevCheck {
+	RevComponent callingComponent;
+	FsaRevision callingRevision;
+} RevCheck;
+
+typedef struct _RevCheckResp {
+	REV_BOOL possiblyCompatible;
+	FsaRevision adapterSWRevision;
+} RevCheckResp;
+
+#endif /* bios */
+#endif /* _REVISION_H */
+
+//
+//	The following allows for inclusion of revision.h in other h
+//	files. when you include this file in another h file, simply
+//	define REV_REFERENCE_ONLY. This will be undefined later, so that
+//	the single C file inclusion in the module will be used to
+//	implement the global structures.
+//
+#ifndef REV_REFERENCE_ONLY
+#ifndef _REVISION_H_GLOBAL
+#define _REVISION_H_GLOBAL
+
+
+
+//
+//	The following array is the table of compatibility. This table
+//	can be modified in two ways:
+//
+//		1) A component which has an incompatible change done to
+//		   it, can get a new build number.
+//
+//		2) A new component can be added, requiring more entries
+//		   to be place into this table.
+//
+//
+//	In case (1), you must change the revision number in the appropriate
+//	column, based on which component absolutely requires an upgrade.
+//
+//	Example: A new FIB used by the API, in build number 105
+//		{RevApi,	RevAdapterSW,		100,  100}
+//			---> would be changed to <---
+//		{RevApi,	RevAdapterSW,		105,  100}
+//
+//	Example: A structure is changed for a FIB that only the API uses
+//		{RevApi,	RevAdapterSW,		100,  100}
+//			---> would be changed to <---
+//		{RevApi,	RevAdapterSW,		105,  105}
+//
+//
+//	In case (2), the less common case, the enumerated list of
+//	components must be changed to include the new component. Then
+//	entries need to be placed into this table.
+//
+//	Since the revisions must be communicated between the two
+//	components, it is likely that you would need to put in the
+//	current build number for both columns. That is the recommended
+//	way to start revision test.
+//
+const RevCompareElement RevCompareTable[] = {
+	// Component A		Component B			MinBForA	MinAForB
+	// -----------		-----------			--------	--------
+	{RevApplication,	RevApi,				2120,		2120	},
+	{RevDkiCli,		RevApi,				2120,		2120	},
+	{RevDkiCli,		RevFileSysDriver,	        257,		257	},
+	{RevDkiCli,		RevMiniportDriver,	        257,		257	},
+	{RevDkiCli,		RevAdapterSW,		        257,		257	},
+	{RevApi,		RevFileSysDriver,	        2120,		2120	},
+	{RevApi,		RevMiniportDriver,	        2120,		2120	},
+	{RevApi,		RevAdapterSW,		        2120,		2120	},
+	{RevApi,		RevNetService,		        2120,		2120	},
+	{RevFileSysDriver,	RevMiniportDriver,	        100,		100	},
+	{RevFileSysDriver,	RevAdapterSW,		        257,		257	},
+	{RevMiniportDriver,	RevAdapterSW,		        257,		257	},
+	{RevMiniportDriver,	RevMonitor,			100,		100	},
+	{RevApi,		RevNetService,		        2120,		2120	},
+	{RevApi,		RevRemoteApi,		        2120,		2120	},
+	{RevNetService,		RevRemoteApi,		        2120,		2120	}
+};
+
+const int RevCompareTableLength = sizeof(RevCompareTable)/sizeof(RevCompareElement);
+
+#endif /* _REVISION_H_GLOBAL */
+#endif /* REV_REFERENCE_ONLY */
+#undef REV_REFERENCE_ONLY
+
+
+
+
+
+
+
diff -BburN linux.orig/drivers/scsi/aacraid/include/rx.h linux/drivers/scsi/aacraid/include/rx.h
--- linux.orig/drivers/scsi/aacraid/include/rx.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/rx.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,80 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   rx.h
+ *
+ * Abstract: Prototypes and data structures unique to the Rx based controller board.
+ *
+ *	
+ --*/
+
+
+typedef struct _Rx_ADAPTER_EXTENSION {
+
+	//
+	// The following must be first.
+	//
+	PPCI_MINIPORT_COMMON_EXTENSION	Common;
+	struct _Rx_ADAPTER_EXTENSION	*Next;				// Next adapter miniport structure
+    USHORT							LocalMaskInterruptControl;
+	PRx_DEVICE_REGISTERS			Device;
+
+} Rx_ADAPTER_EXTENSION;
+
+    
+typedef Rx_ADAPTER_EXTENSION *PRx_ADAPTER_EXTENSION;
+
+
+
+#ifdef LINUX
+/*
+ * 
+ */
+
+#define Rx_READ_UCHAR(AEP,  CSR)			*(volatile unsigned char *)  &((AEP)->Device->CSR)
+    
+
+
+#define Rx_READ_ULONG(AEP,  CSR)			*(volatile unsigned int *)   &((AEP)->Device->CSR)
+#define Rx_WRITE_UCHAR(AEP,  CSR, Value)	*(volatile unsigned char *)  &((AEP)->Device->CSR) = (Value)
+
+
+#define Rx_WRITE_ULONG(AEP, CSR, Value)		*(volatile unsigned int *)   &((AEP)->Device->CSR) = (Value)
+
+#endif /* LINUX */
+
+
+VOID
+RxInterruptAdapter(
+	PVOID Arg1
+	);
+
+VOID
+RxNotifyAdapter(
+	PVOID Arg1,
+    IN HOST_2_ADAP_EVENT AdapterEvent
+    );
+
+VOID
+RxResetDevice(
+	PVOID Arg1
+	);
+
+
diff -BburN linux.orig/drivers/scsi/aacraid/include/rxcommon.h linux/drivers/scsi/aacraid/include/rxcommon.h
--- linux.orig/drivers/scsi/aacraid/include/rxcommon.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/rxcommon.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,105 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   rxcommon.h
+ *
+ * Abstract: Structures and defines for the i960 Rx chip.
+ *
+ *	
+ --*/
+
+#ifndef _Rx_COMMON_H_
+#define _Rx_COMMON_H_
+
+
+
+//
+// Rx Message Unit Registers
+//
+
+typedef volatile struct _StructRxMURegisters {
+										//	 Local	|   PCI*	|	Name
+										//			|		|
+	unsigned	ARSR;					//	1300h	|	00h	|	APIC Register Select Register
+	unsigned	reserved0;				//	1304h	|	04h	|	Reserved
+	unsigned	AWR;					//	1308h	|	08h	|	APIC Window Register
+	unsigned	reserved1;				//	130Ch	|	0Ch	|	Reserved
+	unsigned	IMRx[2];				//	1310h	|	10h	|	Inbound Message Registers
+	unsigned	OMRx[2];				//	1318h	|	18h	|	Outbound Message Registers
+	unsigned	IDR;					//	1320h	|	20h	|	Inbound Doorbell Register
+	unsigned	IISR;					//	1324h	|	24h	|	Inbound Interrupt Status Register
+	unsigned	IIMR;					//	1328h	|	28h	|	Inbound Interrupt Mask Register
+	unsigned	ODR;					//	132Ch	|	2Ch	|	Outbound Doorbell Register
+	unsigned	OISR;					//	1330h	|	30h	|	Outbound Interrupt Status Register
+	unsigned	OIMR;					//	1334h	|	34h	|	Outbound Interrupt Mask Register
+										// * Must access trhough ATU Inbound Translation Window
+
+}Rx_MU_CONFIG;
+typedef Rx_MU_CONFIG *PRx_MU_CONFIG;
+
+typedef volatile struct _Rx_Inbound {
+
+	unsigned	Mailbox[8];
+
+}Rx_Inbound;
+
+typedef Rx_Inbound *PRx_Inbound;
+
+#define	InboundMailbox0		IndexRegs.Mailbox[0]
+#define	InboundMailbox1		IndexRegs.Mailbox[1]
+#define	InboundMailbox2		IndexRegs.Mailbox[2]
+#define	InboundMailbox3		IndexRegs.Mailbox[3]
+#define	InboundMailbox4		IndexRegs.Mailbox[4]
+
+
+
+#define	INBOUNDDOORBELL_0	0x00000001
+#define INBOUNDDOORBELL_1	0x00000002
+#define INBOUNDDOORBELL_2	0x00000004
+#define INBOUNDDOORBELL_3	0x00000008
+#define INBOUNDDOORBELL_4	0x00000010
+#define INBOUNDDOORBELL_5	0x00000020
+#define INBOUNDDOORBELL_6	0x00000040
+
+
+#define	OUTBOUNDDOORBELL_0	0x00000001
+#define OUTBOUNDDOORBELL_1	0x00000002
+#define OUTBOUNDDOORBELL_2	0x00000004
+#define OUTBOUNDDOORBELL_3	0x00000008
+#define OUTBOUNDDOORBELL_4	0x00000010
+
+
+#define InboundDoorbellReg	MUnit.IDR
+
+#define OutboundDoorbellReg	MUnit.ODR
+
+
+typedef struct _Rx_DEVICE_REGISTERS {
+	Rx_MU_CONFIG			MUnit;			// 1300h - 1334h
+	unsigned				reserved1[6];	// 1338h - 134ch
+	Rx_Inbound				IndexRegs;
+} Rx_DEVICE_REGISTERS;
+
+typedef Rx_DEVICE_REGISTERS *PRx_DEVICE_REGISTERS;
+
+
+#endif // _Rx_COMMON_H_
+
+
diff -BburN linux.orig/drivers/scsi/aacraid/include/sap1.h linux/drivers/scsi/aacraid/include/sap1.h
--- linux.orig/drivers/scsi/aacraid/include/sap1.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/sap1.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,78 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   sap1.h
+ *
+ * Abstract: Prototypes and data structures unique to the Strong Arm based controller board.
+ *
+ *	
+ --*/
+
+#define Sa_MINIPORT_REVISION			1
+
+typedef struct _Sa_ADAPTER_EXTENSION {
+
+	//
+	// The following must be first.
+	//
+	PPCI_MINIPORT_COMMON_EXTENSION	Common;
+	struct _Sa_ADAPTER_EXTENSION	*Next;			// Next adapter miniport structure
+	USHORT							LocalMaskInterruptControl;
+	PSa_DEVICE_REGISTERS			Device;
+
+} Sa_ADAPTER_EXTENSION;
+
+typedef Sa_ADAPTER_EXTENSION *PSa_ADAPTER_EXTENSION;
+
+ 
+
+#ifdef LINUX
+/*
+ * 
+ */
+
+ 
+#define Sa_READ_USHORT(AEP, CSR)			*(volatile unsigned short *) &((AEP)->Device->CSR)
+#define Sa_READ_ULONG(AEP,  CSR)			*(volatile unsigned int *)   &((AEP)->Device->CSR)
+
+ 
+#define Sa_WRITE_USHORT(AEP, CSR, Value)	*(volatile unsigned short *) &((AEP)->Device->CSR) = (Value)
+#define Sa_WRITE_ULONG(AEP, CSR, Value)		*(volatile unsigned int *)   &((AEP)->Device->CSR) = (Value)
+
+#endif /* LINUX */
+
+ 
+VOID
+SaInterruptAdapter(
+	PVOID Arg1
+	);
+
+VOID
+SaNotifyAdapter(
+	PVOID Arg1,
+    IN HOST_2_ADAP_EVENT AdapterEvent
+    );
+
+VOID
+SaResetDevice(
+	PVOID Arg1
+	);
+
+ 
diff -BburN linux.orig/drivers/scsi/aacraid/include/sap1common.h linux/drivers/scsi/aacraid/include/sap1common.h
--- linux.orig/drivers/scsi/aacraid/include/sap1common.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/sap1common.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,110 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   sap1common.h
+ *
+ * Abstract: Structures and defines for the Drawbridge and StrongArm110 chip.
+ *	
+ --*/
+
+#ifndef _Sa_COMMON_H_
+#define _Sa_COMMON_H_
+
+
+//
+// SaP1 Message Unit Registers
+//
+
+typedef volatile struct _StructSaDrawbridge_CSR_RegisterMap {
+												//	 Offset |	Name
+	unsigned			reserved[10];			//	00h-27h |   Reserved
+	unsigned char		LUT_Offset;				//		28h	|	Looup Table Offset
+	unsigned char		reserved1[3];			// 	29h-2bh	|	Reserved
+	unsigned			LUT_Data;				//		2ch	|	Looup Table Data	
+	unsigned			reserved2[26];			//	30h-97h	|	Reserved
+	unsigned short		PRICLEARIRQ;			//		98h	|	Primary Clear Irq
+	unsigned short		SECCLEARIRQ;			//		9ah	|	Secondary Clear Irq
+	unsigned short		PRISETIRQ;				//		9ch	|	Primary Set Irq
+	unsigned short		SECSETIRQ;				//		9eh	|	Secondary Set Irq
+	unsigned short		PRICLEARIRQMASK;		//		a0h	|	Primary Clear Irq Mask
+	unsigned short		SECCLEARIRQMASK;		//		a2h	|	Secondary Clear Irq Mask
+	unsigned short		PRISETIRQMASK;			//		a4h	|	Primary Set Irq Mask
+	unsigned short		SECSETIRQMASK;			//		a6h	|	Secondary Set Irq Mask
+	unsigned			MAILBOX0;				//		a8h	|	Scratchpad 0
+	unsigned			MAILBOX1;				//		ach	|	Scratchpad 1
+	unsigned			MAILBOX2;				//		b0h	|	Scratchpad 2
+	unsigned			MAILBOX3;				//		b4h	|	Scratchpad 3
+	unsigned			MAILBOX4;				//		b8h	|	Scratchpad 4
+	unsigned			MAILBOX5;				//		bch	|	Scratchpad 5
+	unsigned			MAILBOX6;				//		c0h	|	Scratchpad 6
+	unsigned			MAILBOX7;				//		c4h	|	Scratchpad 7
+
+	unsigned			ROM_Setup_Data;			//		c8h | 	Rom Setup and Data
+	unsigned			ROM_Control_Addr;		//		cch | 	Rom Control and Address
+
+	unsigned			reserved3[12];			//	d0h-ffh	| 	reserved
+	unsigned			LUT[64];				// 100h-1ffh|	Lookup Table Entries
+
+	//
+	//  TO DO
+	//	need to add DMA, I2O, UART, etc registers form 80h to 364h
+	//
+
+}Sa_Drawbridge_CSR;
+
+typedef Sa_Drawbridge_CSR *PSa_Drawbridge_CSR;
+
+
+#define Mailbox0	SaDbCSR.MAILBOX0
+#define Mailbox1	SaDbCSR.MAILBOX1
+#define Mailbox2	SaDbCSR.MAILBOX2
+#define Mailbox3	SaDbCSR.MAILBOX3
+#define Mailbox4	SaDbCSR.MAILBOX4
+
+	
+#define Mailbox7	SaDbCSR.MAILBOX7
+	
+#define DoorbellReg_p SaDbCSR.PRISETIRQ
+#define DoorbellReg_s SaDbCSR.SECSETIRQ
+#define DoorbellClrReg_p SaDbCSR.PRICLEARIRQ
+
+
+#define	DOORBELL_0	0x00000001
+#define DOORBELL_1	0x00000002
+#define DOORBELL_2	0x00000004
+#define DOORBELL_3	0x00000008
+#define DOORBELL_4	0x00000010
+#define DOORBELL_5	0x00000020
+#define DOORBELL_6	0x00000040
+
+	
+#define PrintfReady			DOORBELL_5
+#define PrintfDone			DOORBELL_5
+	
+typedef struct _Sa_DEVICE_REGISTERS {
+	Sa_Drawbridge_CSR	SaDbCSR;			// 98h - c4h
+} Sa_DEVICE_REGISTERS;
+	
+typedef Sa_DEVICE_REGISTERS *PSa_DEVICE_REGISTERS;
+
+	
+#endif // _Sa_COMMON_H_
+
+
diff -BburN linux.orig/drivers/scsi/aacraid/include/version.h linux/drivers/scsi/aacraid/include/version.h
--- linux.orig/drivers/scsi/aacraid/include/version.h	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/include/version.h	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,35 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   version.h
+ *
+ * Abstract: Keeps track of build number for development purposes.
+ *	
+ --*/
+
+#include "build_number.h"
+
+#define REV_MAJOR 2
+#define REV_MINOR 1
+#define REV_TYPE RevType_Release
+#define REV_DASH 5
+
+#define FSA_VERSION_STRING "2.1.5.3857\0"
+
diff -BburN linux.orig/drivers/scsi/aacraid/linit.c linux/drivers/scsi/aacraid/linit.c
--- linux.orig/drivers/scsi/aacraid/linit.c	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/linit.c	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,1035 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   linit.c
+ *
+ * Abstract: Linux Driver entry module for Adaptec RAID Array Controller
+ *				
+ *	Provides the following driver entry points:
+ *		AAC_DetectHostAdapter()
+ *		AAC_ReleaseHostAdapter()
+ *		AAC_QueueCommand()
+ *		AAC_ResetCommand()
+ *		AAC_BIOSDiskParameters()
+ *		AAC_ProcDirectoryInfo()
+ *	
+ --*/
+
+/*------------------------------------------------------------------------------
+ *              D E F I N E S
+ *----------------------------------------------------------------------------*/
+#define AAC_DRIVER_VERSION				"0.1.1"
+#define AAC_DRIVER_BUILD_DATE			__DATE__
+#define MAX_DRIVER_QUEUE_DEPTH			500
+
+/*------------------------------------------------------------------------------
+ *              I N C L U D E S
+ *----------------------------------------------------------------------------*/
+#include "osheaders.h"
+
+#include "AacGenericTypes.h"
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+#include "sd.h"
+#include "linit.h"
+#include "aac_unix_defs.h"
+#include "fsatypes.h"
+#include "comstruc.h"
+#include "fsaport.h"
+#include "pcisup.h"
+#include "port.h"
+
+/*------------------------------------------------------------------------------
+ *              G L O B A L S
+ *----------------------------------------------------------------------------*/
+extern FSA_MINIPORT MiniPorts[];
+extern int CommPrinting;
+extern char DescriptionString[];
+extern char devicestr[];
+
+/*------------------------------------------------------------------------------
+ *              M O D U L E   G L O B A L S
+ *----------------------------------------------------------------------------*/
+aac_options_t g_options = { CMN_ERR_LEVEL, 0 };	// default message_level
+
+char g_DriverName[] = { "aacraid" };
+#define module_options aacraid_options
+static char * aacraid_options = NULL;
+
+/* AAC_ProcDirectoryEntry is the  /proc/scsi directory entry.*/
+proc_dir_entry_t AAC_ProcDirectoryEntry =
+	{ PROC_SCSI_SCSI, 3, "aacraid", S_IFDIR | S_IRUGO | S_IXUGO, 2,
+	0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+
+PCI_MINIPORT_COMMON_EXTENSION *g_CommonExtensionPtrArray[ MAXIMUM_NUM_ADAPTERS ];
+unsigned g_HostAdapterCount = 0;
+unsigned g_chardev_major = 0;
+
+int g_single_command_done = FALSE;
+
+/*------------------------------------------------------------------------------
+ *              F U N C T I O N   P R O T O T Y P E S
+ *----------------------------------------------------------------------------*/
+int AacHba_Ioctl(
+	PCI_MINIPORT_COMMON_EXTENSION *CommonExtension,
+	int cmd,
+	void * arg );
+
+int AacHba_ProbeContainers( 
+	PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr );
+
+int AacHba_DoScsiCmd(
+	Scsi_Cmnd *scsi_cmnd_ptr,
+	int wait );
+
+void AacHba_DetachAdapter(
+	IN PVOID AdapterArg );
+
+int AacHba_ClassDriverInit(
+	PCI_MINIPORT_COMMON_EXTENSION * CommonExtensionPtr);
+
+void AacHba_AbortScsiCommand(
+	Scsi_Cmnd *scsi_cmnd_ptr );
+
+
+/*------------------------------------------------------------------------------
+ *              L O C A L   F U N C T I O N   P R O T O T Y P E S
+ *----------------------------------------------------------------------------*/
+static int parse_keyword(
+	char ** str_ptr, 
+	char * keyword );
+
+static void AAC_ParseDriverOptions( 
+	char * cmnd_line_options_str );
+
+static void AAC_AnnounceDriver( void );
+
+int AAC_ChardevIoctl(
+	struct inode * inode_ptr, 
+	struct file * file_ptr,
+	unsigned int cmd,
+	unsigned long arg );
+
+int AAC_ChardevOpen(
+	struct inode * inode_ptr,
+	struct file * file_ptr );
+
+int AAC_ChardevRelease(
+	struct inode * inode_ptr,
+	struct file * file_ptr );
+
+struct file_operations AAC_fops = {
+	NULL,				// lseek
+	NULL,				// read
+	NULL,				// write
+	NULL,				// readdir
+	NULL,				// poll
+	AAC_ChardevIoctl,	// ioctl
+	NULL,				// mmap
+	AAC_ChardevOpen,	// open
+	NULL,				// flush
+	AAC_ChardevRelease,	// release
+	NULL,				// fsync
+	NULL,				// fasync
+	NULL,				// check media change
+	NULL,				// revalidate
+	NULL				// lock
+};
+
+/*------------------------------------------------------------------------------
+ *              F U N C T I O N S
+ *----------------------------------------------------------------------------*/
+/*------------------------------------------------------------------------------
+	AAC_AnnounceDriver()
+
+		Announce the driver name, version and date.
+ *----------------------------------------------------------------------------*/
+static void AAC_AnnounceDriver( void )
+/*----------------------------------------------------------------------------*/
+{
+	printk("<1>%s, %s\n", 
+		   "aacraid raid driver version", AAC_DRIVER_BUILD_DATE );   
+	schedule();
+}
+
+
+/*------------------------------------------------------------------------------
+	AAC_DetectHostAdapter()
+
+		Probe for AAC Host Adapters initialize, register, and report the 
+		configuration of each AAC Host Adapter found.
+
+	Preconditions:
+	Postconditions:
+		- Returns the number of adapters successfully initialized and 
+		registered.
+		- Initialize all data necessary for this particular SCSI driver.
+	Notes:
+		The detect routine must not call any of the mid level functions 
+		to queue commands because things are not guaranteed to be set 
+		up yet. The detect routine can send commands to the host adapter 
+		as long as the program control will not be passed to scsi.c in 
+		the processing of the command. Note especially that 
+		scsi_malloc/scsi_free must not be called.
+ *----------------------------------------------------------------------------*/
+int AAC_DetectHostAdapter(
+	Scsi_Host_Template *HostTemplate )
+/*----------------------------------------------------------------------------*/
+{
+	int index;
+	int ContainerId;
+	uint16_t vendor_id, device_id, sub_vendor_id, sub_system_id;
+	struct Scsi_Host *host_ptr;
+	PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr;
+	struct pci_dev *dev = NULL;
+	extern int NumMiniPorts;
+	fsadev_t *fsa_dev_ptr;
+	char *DeviceName;
+
+	struct pci_dev *devp;
+
+	int	first_index, last_index, increment;
+
+	CommPrinting = TRUE;
+
+	#ifdef MODULE
+	EXPORT_NO_SYMBOLS;
+	#endif
+
+	AAC_AnnounceDriver();
+
+	if( module_options != NULL )
+		AAC_ParseDriverOptions( module_options );
+
+
+	// NumMiniPorts & MiniPorts[] defined in aacid.c
+	if (g_options.reverse_scan == 0) {
+		first_index = 0;
+		last_index  = NumMiniPorts;
+		increment   = 1;
+	} else {
+		first_index = NumMiniPorts -1;
+		last_index  = -1;
+		increment   = -1;
+	}
+
+	for( index = first_index; index != last_index; index += increment )
+	{
+		device_id = MiniPorts[index].DeviceId;
+		vendor_id = MiniPorts[index].VendorId;
+		DeviceName = MiniPorts[index].DeviceName;
+		cmn_err(CE_DEBUG, "Checking %s %x/%x/%x/%x", 
+					DeviceName,
+					vendor_id, 
+					device_id,
+					MiniPorts[index].SubVendorId,
+					MiniPorts[index].SubSystemId);
+
+
+		// pci_find_device traverses the pci_devices linked list for devices
+		// with matching vendor and device ids.
+
+		dev = NULL;	// start from beginning of list
+		while( ( dev = pci_find_device( vendor_id, device_id, dev ) ) )
+		{
+		  if( pci_read_config_word( dev, PCI_SUBSYSTEM_VENDOR_ID, &sub_vendor_id ) ){
+			cmn_err(CE_WARN, "pci_read_config_word SUBSYS_VENDOR_ID failed");
+			break;
+		  }
+		  if( pci_read_config_word( dev, PCI_SUBSYSTEM_ID, &sub_system_id ) ){
+			cmn_err(CE_WARN, "pci_read_config_work SUBSYSTEM_ID failed");
+			break;
+		  }
+
+		  cmn_err(CE_DEBUG, "     found: %x/%x/%x/%x", vendor_id, device_id, sub_vendor_id, sub_system_id);
+		  if( ( sub_vendor_id != MiniPorts[index].SubVendorId ) || 
+			  ( sub_system_id != MiniPorts[index].SubSystemId ) ){
+			     continue;
+		  }
+			
+
+			printk("<1>%s device detected\n", DeviceName );
+			// cmn_err(CE_WARN, "%x/%x/%x/%x", vendor_id, device_id, sub_vendor_id, sub_system_id);
+
+			// Increment the host adapter count
+			g_HostAdapterCount++;
+
+			// scsi_register() allocates memory for a Scsi_Hosts structure and
+			// links it into the linked list of host adapters. This linked list
+			// contains the data for all possible <supported> scsi hosts.
+			// This is similar to the Scsi_Host_Template, except that we have
+			// one entry for each actual physical host adapter on the system,
+			// stored as a linked list. If there are two AAC boards, then we
+			// will need to make two Scsi_Host entries, but there will be only
+			// one Scsi_Host_Template entry. The second argument to scsi_register()
+			// specifies the size of the extra memory we want to hold any device 
+			// specific information.
+			host_ptr = scsi_register( HostTemplate, 
+				sizeof( PCI_MINIPORT_COMMON_EXTENSION ) );
+
+			// These three parameters can be used to allow for wide SCSI 
+			// and for host adapters that support multiple buses.
+			host_ptr->max_id = 17;
+			host_ptr->max_lun = 8;
+			host_ptr->max_channel = 1;
+
+			host_ptr->irq = dev->irq;		// Adapter IRQ number
+			host_ptr->base = ( char * )(dev->base_address[0] & ~0xff);
+
+			cmn_err( CE_DEBUG, "Device base address = 0x%lx [0x%lx]", host_ptr->base, dev->base_address[0] );
+			cmn_err( CE_DEBUG, "Device irq = 0x%lx", dev->irq );
+
+			// The unique_id field is a unique identifier that must be assigned
+			// so that we have some way of identifying each host adapter properly
+			// and uniquely. For hosts that do not support more than one card in the
+			// system, this does not need to be set. It is initialized to zero in
+			// scsi_register(). This is the value returned from OsGetDeviceInstance().
+			host_ptr->unique_id = g_HostAdapterCount - 1;
+
+			host_ptr->this_id = 16;			// SCSI Id for the adapter itself
+
+			// Set the maximum number of simultaneous commands supported by the driver.
+			host_ptr->can_queue = MAX_DRIVER_QUEUE_DEPTH;
+
+			// Define the maximum number of scatter/gather elements supported by 
+			// the driver. 
+			host_ptr->sg_tablesize = 17;
+
+			host_ptr->cmd_per_lun = 1;		// untagged queue depth
+
+			// This function is called after the device list has been built to find
+			// tagged queueing depth supported for each device.
+			host_ptr->select_queue_depths = AAC_SelectQueueDepths;
+
+			CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )host_ptr->hostdata;
+			
+			// attach a pointer back to Scsi_Host
+			CommonExtensionPtr->OsDep.scsi_host_ptr = host_ptr;	
+			CommonExtensionPtr->OsDep.MiniPortIndex =  index;
+
+			// Initialize the ordinal number of the device to -1
+			fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev );
+			for( ContainerId = 0; ContainerId < MAXIMUM_NUM_CONTAINERS; ContainerId++ )
+				fsa_dev_ptr->ContainerDevNo[ContainerId] = -1;
+
+			// Call initialization routine
+			if( ( *MiniPorts[index].InitRoutine )
+				( CommonExtensionPtr, host_ptr->unique_id, dev->bus->number, 0 ) != 0 )
+			{
+				// device initialization failed
+				cmn_err( CE_WARN, "%s:%d device initialization failed", DeviceName, host_ptr->unique_id );
+				scsi_unregister( host_ptr );
+				g_HostAdapterCount--;
+			}
+			else
+			{
+				cmn_err( CE_NOTE, "%s:%d device initialization successful", DeviceName, host_ptr->unique_id  );
+				AacHba_ClassDriverInit( CommonExtensionPtr );
+				cmn_err(CE_NOTE, "%d:%d AacHba_ClassDriverInit complete", DeviceName, host_ptr->unique_id);
+				AacHba_ProbeContainers( CommonExtensionPtr );
+				cmn_err( CE_DEBUG, "Probe containers completed" );
+				g_CommonExtensionPtrArray[ g_HostAdapterCount - 1 ] = CommonExtensionPtr;
+				// OsSleep( 1 );
+			}
+		}
+	}
+
+	if( g_HostAdapterCount )
+		if( !( g_chardev_major = register_chrdev( 0, devicestr, &AAC_fops ) ) )
+			cmn_err( CE_WARN, "%s: unable to register %s device", DeviceName, devicestr);
+
+	HostTemplate->present = g_HostAdapterCount; // # of cards of this type found
+
+	return( g_HostAdapterCount ); 
+}
+
+
+/*------------------------------------------------------------------------------
+	AAC_ReleaseHostAdapter()
+
+		Release all resources previously acquired to support a specific Host 
+		Adapter and unregister the AAC Host Adapter.
+ *----------------------------------------------------------------------------*/
+int AAC_ReleaseHostAdapter( 
+	struct Scsi_Host *host_ptr )
+/*----------------------------------------------------------------------------*/
+{
+	PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr;
+
+	cmn_err( CE_DEBUG, "AAC_ReleaseHostAdapter" );
+
+	CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )host_ptr->hostdata;
+
+	// kill any threads we started
+	kill_proc( CommonExtensionPtr->OsDep.thread_pid, SIGKILL, 0 );
+
+	// Call the comm layer to detach from this adapter
+	AacHba_DetachAdapter( CommonExtensionPtr->Adapter );
+
+	// remove interrupt binding
+	OsDetachInterrupt( CommonExtensionPtr->MiniPort );
+
+	SaDetachDevice( CommonExtensionPtr );
+
+	// unregister adapter
+	scsi_unregister( host_ptr );
+
+	if( g_chardev_major )
+	{
+		unregister_chrdev( g_chardev_major, devicestr );
+		g_chardev_major = 0;
+	}
+
+	return( 0 ); // #REVISIT# return code
+}
+
+
+/*------------------------------------------------------------------------------
+	AAC_QueueCommand()
+
+		Queues a command for execution by the associated Host Adapter.
+ *----------------------------------------------------------------------------*/
+int AAC_QueueCommand(
+	Scsi_Cmnd *scsi_cmnd_ptr,
+	void ( *CompletionRoutine )( Scsi_Cmnd * ) )
+/*----------------------------------------------------------------------------*/
+{
+	scsi_cmnd_ptr->scsi_done = CompletionRoutine;
+
+	// AacHba_DoScsiCmd() handles command processing, setting the 
+	// result code and calling completion routine. 
+	#ifdef SYNC_FIB
+	if( AacHba_DoScsiCmd( scsi_cmnd_ptr, 1 ) )	// called with wait = TRUE
+	#else
+	if( AacHba_DoScsiCmd( scsi_cmnd_ptr, 0 ) )	// called with wait = FALSE
+	#endif
+		cmn_err( CE_DEBUG, "AacHba_DoScsiCmd failed" );
+	return 0;
+} 
+
+
+/*------------------------------------------------------------------------------
+	AAC_Done()
+
+		Callback function for a non-queued command.
+
+	Postconditions
+		Sets g_single_command done to TRUE
+ *----------------------------------------------------------------------------*/
+void AAC_Done( 
+	Scsi_Cmnd * scsi_cmnd_ptr ) 
+/*----------------------------------------------------------------------------*/
+{
+	g_single_command_done = TRUE;
+}
+
+
+/*------------------------------------------------------------------------------
+	AAC_Command()
+	
+		Accepts a single command for execution by the associated Host Adapter.
+
+	Postconditions
+		Returns an int where:
+		Byte 0 = SCSI status code
+		Byte 1 = SCSI 1 byte message
+		Byte 2 = host error return
+		Byte 3 = mid level error return
+ *----------------------------------------------------------------------------*/
+int AAC_Command(
+	Scsi_Cmnd *scsi_cmnd_ptr )
+/*----------------------------------------------------------------------------*/
+{
+	scsi_cmnd_ptr->scsi_done = AAC_Done;
+
+	cmn_err( CE_DEBUG, "AAC_Command" );
+
+	// AacHba_DoScsiCmd() handles command processing, setting the 
+	// result code and calling completion routine.
+	g_single_command_done = FALSE;
+	
+	AacHba_DoScsiCmd( scsi_cmnd_ptr, 0 );
+	while( !g_single_command_done );
+	return( scsi_cmnd_ptr->result );
+} 
+
+
+/*------------------------------------------------------------------------------
+	AAC_AbortCommand()
+
+		Abort command if possible.
+ *----------------------------------------------------------------------------*/
+int AAC_AbortCommand( 
+	Scsi_Cmnd *scsi_cmnd_ptr )
+/*----------------------------------------------------------------------------*/
+{
+	int target = scsi_cmnd_ptr->target;
+	int hba = scsi_cmnd_ptr->host->unique_id;
+	int result = 0;
+	u_short interrupt_status;
+	PCI_MINIPORT_COMMON_EXTENSION *cep;
+	char   *DeviceName;
+
+	cmn_err( CE_WARN, "%s:%d ABORT", g_DriverName, hba, target );
+	AacHba_AbortScsiCommand( scsi_cmnd_ptr );
+
+	cep = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata );
+	DeviceName = MiniPorts[cep->OsDep.MiniPortIndex].DeviceName; 
+
+		/*
+		cmn_err( CE_WARN, "%s:%d Unable to abort command to target %d - "
+		  "command already completed", DeviceName, hba, target);
+		result = SCSI_ABORT_NOT_RUNNING;
+
+		cmn_err(CE_WARN, "%s:%d Unable to abort command to target %d - "
+		   "no command found\n", DeviceName, hba, target);
+		result = SCSI_ABORT_NOT_RUNNING;
+
+		cmn_err(CE_WARN, "%s:%d Unable to abort command to target %d - "
+		   "command reset\n", DeviceName, hba, target);
+		result = SCSI_ABORT_PENDING;
+
+		cmn_err(CE_WARN, "%s:%d Unable to abort command to target %d - "
+		   "abort tag not supported\n", DeviceName, hba, target);
+		result = SCSI_ABORT_SNOOZE;
+
+		cmn_err(CE_WARN, "%s:%d Aborting command to target %d - pending",
+		   DeviceName, hba, target);
+		result = SCSI_ABORT_PENDING;
+
+		cmn_err(CE_WARN, "%s:%d Unable to abort command to target %d",
+		   DeviceName, hba, target);
+		result = SCSI_ABORT_BUSY;
+
+		cmn_err(CE_WARN, "%s:%d Aborted command to target %d\n",
+		   DeviceName, hba, target);
+		result = SCSI_ABORT_SUCCESS;
+		*/
+
+	// Abort not supported yet
+	result = SCSI_ABORT_BUSY;
+	return result;
+}
+
+
+/*------------------------------------------------------------------------------
+	AAC_ResetCommand()
+
+		Reset command handling.
+ *----------------------------------------------------------------------------*/
+int AAC_ResetCommand( 
+	struct scsi_cmnd *scsi_cmnd_ptr, 
+	unsigned int reset_flags )
+/*----------------------------------------------------------------------------*/
+{
+	int target = scsi_cmnd_ptr->target;
+	int hba = scsi_cmnd_ptr->host->unique_id;
+	PCI_MINIPORT_COMMON_EXTENSION *cep;
+	char	*DeviceName;
+
+	cep = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata );
+	DeviceName = MiniPorts[cep->OsDep.MiniPortIndex].DeviceName;
+
+	cmn_err( CE_WARN, "%s:%d RESET", DeviceName, hba, target );
+
+	return SCSI_RESET_PUNT;
+}
+
+
+/*------------------------------------------------------------------------------
+	AAC_DriverInfo()
+
+		Returns the host adapter name
+ *----------------------------------------------------------------------------*/
+const char *AAC_DriverInfo( 
+	struct Scsi_Host *host_ptr )
+/*----------------------------------------------------------------------------*/
+{
+  PCI_MINIPORT_COMMON_EXTENSION *cep;
+  char	*DeviceName;
+
+  cep = ( PCI_MINIPORT_COMMON_EXTENSION * )( host_ptr->hostdata );
+  DeviceName = MiniPorts[cep->OsDep.MiniPortIndex].DeviceName;
+
+  cmn_err( CE_DEBUG, "AAC_DriverInfo" );
+  return (DeviceName);
+}
+
+
+/*------------------------------------------------------------------------------
+	AAC_BIOSDiskParameters()
+
+		Return the Heads/Sectors/Cylinders BIOS Disk Parameters for Disk.  
+		The default disk geometry is 64 heads, 32 sectors, and the appropriate 
+		number of cylinders so as not to exceed drive capacity.  In order for 
+		disks equal to or larger than 1 GB to be addressable by the BIOS
+		without exceeding the BIOS limitation of 1024 cylinders, Extended 
+		Translation should be enabled.   With Extended Translation enabled, 
+		drives between 1 GB inclusive and 2 GB exclusive are given a disk 
+		geometry of 128 heads and 32 sectors, and drives above 2 GB inclusive 
+		are given a disk geometry of 255 heads and 63 sectors.  However, if 
+		the BIOS detects that the Extended Translation setting does not match 
+		the geometry in the partition table, then the translation inferred 
+		from the partition table will be used by the BIOS, and a warning may 
+		be displayed.
+ *----------------------------------------------------------------------------*/
+int AAC_BIOSDiskParameters(
+	Scsi_Disk *scsi_disk_ptr, 
+	kdev_t device,
+	int *parameter_ptr )
+/*----------------------------------------------------------------------------*/
+{
+	AAC_BIOS_DiskParameters_T *disk_parameters = 
+		( AAC_BIOS_DiskParameters_T *)parameter_ptr;
+	struct buffer_head * buffer_head_ptr;
+
+	cmn_err( CE_DEBUG, "AAC_BIOSDiskParameters" );
+
+	// Assuming extended translation is enabled - #REVISIT#
+	if( scsi_disk_ptr->capacity >= 2 * 1024 * 1024 ) // 1 GB in 512 byte sectors
+	{
+		if( scsi_disk_ptr->capacity >= 4 * 1024 * 1024 ) // 2 GB in 512 byte sectors
+		{
+			disk_parameters->heads = 255;
+			disk_parameters->sectors = 63;
+		}
+		else
+		{
+			disk_parameters->heads = 128;
+			disk_parameters->sectors = 32;
+		}
+	}
+	else
+	{
+		disk_parameters->heads = 64;
+		disk_parameters->sectors = 32;
+	}
+
+	disk_parameters->cylinders = scsi_disk_ptr->capacity
+		/( disk_parameters->heads * disk_parameters->sectors );
+
+	// Read the first 1024 bytes from the disk device
+	buffer_head_ptr = bread( 
+						MKDEV( MAJOR( device ), 
+						MINOR( device ) & ~0x0F ), 
+						0, 1024 );
+
+	if( buffer_head_ptr == NULL )
+		return( 0 );
+	/* 
+		If the boot sector partition table is valid, search for a partition 
+		table entry whose end_head matches one of the standard geometry 
+		translations ( 64/32, 128/32, 255/63 ).
+	*/
+	if( *( unsigned short * )( buffer_head_ptr->b_data + 0x1fe ) == 0xaa55 )
+	{
+		struct partition *first_partition_entry =
+			( struct partition * )( buffer_head_ptr->b_data + 0x1be );
+		struct partition *partition_entry = first_partition_entry;
+		int saved_cylinders = disk_parameters->cylinders;
+		int partition_number;
+		unsigned char partition_entry_end_head, partition_entry_end_sector;
+
+		for( partition_number = 0; partition_number < 4; partition_number++ )
+		{
+			partition_entry_end_head   = partition_entry->end_head;
+			partition_entry_end_sector = partition_entry->end_sector & 0x3f;
+
+			if( partition_entry_end_head == ( 64 - 1 ) )
+			{
+				disk_parameters->heads = 64;
+				disk_parameters->sectors = 32;
+				break;
+			}
+			else if( partition_entry_end_head == ( 128 - 1 ) )
+			{
+				disk_parameters->heads = 128;
+				disk_parameters->sectors = 32;
+				break;
+			}
+			else if( partition_entry_end_head == ( 255 - 1 ) ) 
+			{
+				disk_parameters->heads = 255;
+				disk_parameters->sectors = 63;
+				break;
+			}
+			partition_entry++;
+		}
+
+		if( partition_number == 4 )
+		{
+			partition_entry_end_head   = first_partition_entry->end_head;
+			partition_entry_end_sector = first_partition_entry->end_sector & 0x3f;
+		}
+
+		disk_parameters->cylinders = scsi_disk_ptr->capacity
+			/( disk_parameters->heads * disk_parameters->sectors );
+
+		if( ( partition_number < 4 )  && ( partition_entry_end_sector == disk_parameters->sectors ) )
+		{
+			if( disk_parameters->cylinders != saved_cylinders )
+				cmn_err( CE_NOTE, "Adopting geometry: heads=%d, sectors=%d from partition table %d",
+					disk_parameters->heads, disk_parameters->sectors, partition_number );
+		}
+		else if( ( partition_entry_end_head > 0 ) || ( partition_entry_end_sector > 0 ) )
+		{
+			cmn_err( CE_NOTE, "Strange geometry: heads=%d, sectors=%d in partition table %d",
+				partition_entry_end_head + 1, partition_entry_end_sector, partition_number );
+			cmn_err( CE_NOTE, "Using geometry: heads=%d, sectors=%d",
+					disk_parameters->heads, disk_parameters->sectors );
+		}
+	}
+	
+	brelse( buffer_head_ptr );
+
+	return( 0 );
+}
+
+
+/*------------------------------------------------------------------------------
+	AAC_ProcDirectoryInfo()
+
+		Implement /proc/scsi/<drivername>/<n>.
+		Used to export driver statistics and other infos to the world outside 
+		the kernel using the proc file system. Also provides an interface to
+		feed the driver with information.
+
+	Postconditions
+		For reads
+			- if offset > 0 return 0
+			- if offset == 0 write data to proc_buffer and set the start_ptr to
+			beginning of proc_buffer, return the number of characters written.
+		For writes
+			- writes currently not supported, return 0
+ *----------------------------------------------------------------------------*/
+int AAC_ProcDirectoryInfo(
+	char *proc_buffer,		// read/write buffer
+	char **start_ptr,		// start of valid data in the buffer
+	off_t offset,			// offset from the beginning of the imaginary file 
+	int bytes_available,	// bytes available
+	int host_no,			// SCSI host number 
+	int write )				// direction of dataflow: TRUE for writes, FALSE for reads	
+/*----------------------------------------------------------------------------*/
+{
+	int length = 0;
+	cmn_err( CE_DEBUG, "AAC_ProcDirectoryInfo" );
+
+	if( ( write ) || ( offset > 0 ) )
+		return( 0 );
+
+	*start_ptr = proc_buffer;
+
+	return( sprintf(&proc_buffer[length], "%s  %d\n", "Raid Controller, scsi hba number", host_no ) );
+}
+
+
+
+/*------------------------------------------------------------------------------
+	AAC_SelectQueueDepths()
+
+		Selects queue depths for each target device based on the host adapter's
+		total capacity and the queue depth supported by the target device.
+		A queue depth of one automatically disables tagged queueing.
+ *----------------------------------------------------------------------------*/
+void AAC_SelectQueueDepths(
+	struct Scsi_Host * host_ptr,
+	Scsi_Device * scsi_device_ptr )
+/*----------------------------------------------------------------------------*/
+{
+	Scsi_Device * device_ptr;
+
+	cmn_err( CE_DEBUG, "AAC_SelectQueueDepths" );
+	cmn_err( CE_DEBUG, "Device #   Q Depth   Online" );
+	cmn_err( CE_DEBUG, "---------------------------" );
+	for( device_ptr = scsi_device_ptr; device_ptr != NULL; device_ptr = device_ptr->next )
+		if( device_ptr->host == host_ptr )
+		{
+			device_ptr->queue_depth = 10;		
+			cmn_err( CE_DEBUG, "  %2d         %d        %d", 
+				device_ptr->id, device_ptr->queue_depth, device_ptr->online );
+		}
+}
+
+
+/*------------------------------------------------------------------------------
+	AAC_SearchBiosSignature()
+
+		Locate adapter signature in BIOS
+ *----------------------------------------------------------------------------*/
+int AAC_SearchBiosSignature( void )
+/*----------------------------------------------------------------------------*/
+{
+	unsigned base;
+	unsigned namep;
+	int index;
+	int val;
+	char name_buf[32];
+	int result = FALSE;
+
+	for( base = 0xc8000; base < 0xdffff; base += 0x4000 )
+	{
+		val = readb( base );
+		if( val != 0x55 ) 
+			continue;
+
+		result = TRUE;
+		namep = base + 0x1e;
+		memcpy_fromio( name_buf, namep, 32 );
+		name_buf[31] = '\0';
+	}
+	return( result );
+}
+
+
+/*------------------------------------------------------------------------------
+	AAC_Ioctl()
+
+		Handle SCSI ioctls
+ *----------------------------------------------------------------------------*/
+int AAC_Ioctl(
+	Scsi_Device * scsi_dev_ptr,
+	int cmd,
+	void * arg )
+/*----------------------------------------------------------------------------*/
+{
+	PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr;
+
+	cmn_err( CE_DEBUG, "AAC_Ioctl" );
+	CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )scsi_dev_ptr->host->hostdata;
+	return( AacHba_Ioctl( CommonExtensionPtr, cmd, arg ) );
+}
+
+
+
+/*------------------------------------------------------------------------------
+	AAC_ChardevOpen()
+	
+		Handle character device open
+	
+	Preconditions:
+	Postconditions:
+		Returns 0 if successful, -ENODEV or -EINVAL otherwise
+ *----------------------------------------------------------------------------*/
+int AAC_ChardevOpen(
+	struct inode * inode_ptr,
+	struct file * file_ptr )
+/*----------------------------------------------------------------------------*/
+{
+	unsigned minor_number;
+
+	cmn_err( CE_DEBUG, "AAC_ChardevOpen" );
+
+	// check device permissions in file_ptr->f_mode ??
+
+	// extract & check the minor number
+	minor_number = MINOR( inode_ptr->i_rdev );
+	if( minor_number > ( g_HostAdapterCount - 1 ) )
+	{
+		cmn_err( CE_WARN, "AAC_ChardevOpen: Minor number %d not supported", minor_number );
+		return( -ENODEV );
+	}
+
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+
+	return( 0 );
+}
+
+
+/*------------------------------------------------------------------------------
+	AAC_ChardevRelease()
+	
+		Handle character device release.
+	
+	Preconditions:
+	Postconditions:
+		Returns 0 if successful, -ENODEV or -EINVAL otherwise
+ *----------------------------------------------------------------------------*/
+int AAC_ChardevRelease(
+	struct inode * inode_ptr,
+	struct file * file_ptr )
+/*----------------------------------------------------------------------------*/
+{
+	cmn_err( CE_DEBUG, "AAC_ChardevRelease" );
+
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+
+	return( 0 );
+}
+
+
+/*------------------------------------------------------------------------------
+	AAC_ChardevIoctl()
+	
+		Handle character device interface ioctls
+	
+	Preconditions:
+	Postconditions:
+		Returns 0 if successful, -ENODEV or -EINVAL otherwise
+ *----------------------------------------------------------------------------*/
+int AAC_ChardevIoctl(
+	struct inode * inode_ptr, 
+	struct file * file_ptr,
+	unsigned int cmd,
+	unsigned long arg )
+/*----------------------------------------------------------------------------*/
+{
+	unsigned minor_number;
+	PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr;
+
+	cmn_err( CE_DEBUG, "AAC_ChardevIoctl" );
+
+	// check device permissions in file_ptr->f_mode ??
+
+	// extract & check the minor number
+	minor_number = MINOR( inode_ptr->i_rdev );
+	if( minor_number > ( g_HostAdapterCount - 1 ) )
+	{
+		cmn_err( CE_WARN, "AAC_ChardevIoctl: Minor number %d not supported", minor_number );
+		return( -ENODEV );
+	}
+
+	// get device pointer
+	CommonExtensionPtr = g_CommonExtensionPtrArray[ minor_number ];
+
+	// dispatch ioctl - AacHba_Ioctl() returns zero on success
+	if( AacHba_Ioctl( CommonExtensionPtr, cmd, ( void * )arg ) )
+		return( -EINVAL );
+
+	return( 0 );
+}
+
+
+/*------------------------------------------------------------------------------
+	parse_keyword()
+
+		Look for the keyword in str_ptr
+
+	Preconditions:
+	Postconditions:
+		If keyword found
+			- return true and update the pointer str_ptr.
+		otherwise
+			- return false
+ *----------------------------------------------------------------------------*/
+static int parse_keyword(
+	char ** str_ptr, 
+	char * keyword )
+/*----------------------------------------------------------------------------*/
+{
+	char * ptr = *str_ptr;
+	
+	while( *keyword != '\0' )
+	{
+		char string_char = *ptr++;
+		char keyword_char = *keyword++;
+
+		if ( ( string_char >= 'A' ) && ( string_char <= 'Z' ) )
+			string_char += 'a' - 'Z';
+		if( ( keyword_char >= 'A' ) && ( keyword_char <= 'Z' ) ) 
+			keyword_char += 'a' - 'Z';
+		if( string_char != keyword_char )
+			return FALSE;
+	}
+	*str_ptr = ptr;
+	return TRUE;
+}
+
+
+/*------------------------------------------------------------------------------
+	AAC_ParseDriverOptions()
+
+	For modules the usage is:
+		insmod -f aacraid.o 'aacraid_options="<option_name:argument>"'
+ *----------------------------------------------------------------------------*/
+static void AAC_ParseDriverOptions( 
+	char * cmnd_line_options_str )
+/*----------------------------------------------------------------------------*/
+{
+	int message_level;
+	int reverse_scan;
+	char *cp;
+	char *endp;
+
+	cp = cmnd_line_options_str;
+
+	cmn_err(CE_DEBUG, "AAC_ParseDriverOptions: <%s>", cp);
+
+	while( *cp ) {
+		if( parse_keyword( &cp, "message_level:" ) ) {
+			message_level = simple_strtoul( cp, 0, 0 );
+			if( ( message_level < CE_TAIL ) && ( message_level >= 0 ) ) {
+				g_options.message_level = message_level;
+				cmn_err( CE_WARN, "%s: new message level = %d", g_DriverName, g_options.message_level );
+			}
+			else {
+				cmn_err( CE_WARN, "%s: invalid message level = %d", g_DriverName, message_level );
+			}
+		} else if (parse_keyword( &cp, "reverse_scan:" ) ) {
+			reverse_scan = simple_strtoul( cp, 0, 0 );
+			if (reverse_scan) {
+				g_options.reverse_scan = 1;
+				cmn_err( CE_WARN, "%s: reversing device discovery order", g_DriverName, g_options.message_level );
+			}
+		}
+		else {
+			cmn_err( CE_WARN, "%s: unknown command line option <%s>", g_DriverName, cp );
+		}
+
+		/*
+		 * skip to next option,  accept " ", ";", and "," as delimiters
+		 */
+		while ( *cp && (*cp != ' ')  && (*cp != ';')  && (*cp != ','))
+			cp++;
+
+		if (*cp)				 /* skip over the delimiter */
+			cp++;
+	}
+
+}
+
+
+/*------------------------------------------------------------------------------
+	Include Module support if requested.
+
+	To use the low level SCSI driver support using the linux kernel loadable 
+	module interface we should initialize the global variable driver_interface  
+	(datatype Scsi_Host_Template) and then include the file scsi_module.c.
+	This should also be wrapped in a #ifdef MODULE/#endif
+ *----------------------------------------------------------------------------*/
+#ifdef MODULE
+
+/*
+	The Loadable Kernel Module Installation Facility may pass us
+	a pointer to a driver specific options string to be parsed, 
+	we assign this to options string. 
+*/
+MODULE_PARM( module_options, "s" );
+
+Scsi_Host_Template driver_template = AAC_HOST_TEMPLATE_ENTRY;
+
+#include "scsi_module.c"
+
+#endif
diff -BburN linux.orig/drivers/scsi/aacraid/osddi.c linux/drivers/scsi/aacraid/osddi.c
--- linux.orig/drivers/scsi/aacraid/osddi.c	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/osddi.c	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,509 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   osddi.c
+ *
+ * Abstract: This file contains all the proceedures which use LINUX specific Device 
+ *		Driver Interfaces.
+ *	
+ --*/
+#include "osheaders.h"
+
+#include <linux/smp_lock.h>
+
+#ifdef fsid_t
+#undef fsid_t
+#endif
+#include "AacGenericTypes.h"
+#include "aac_unix_defs.h"
+#include "comstruc.h"
+#include "monkerapi.h"
+#include "protocol.h"
+#include "fsafs.h"
+
+#include "sap1common.h"
+#include "fsaport.h"
+#include "pcisup.h"
+#include "sap1.h"
+#include "nodetype.h"
+#include "comsup.h"
+#include "afacomm.h"
+#include "adapter.h"
+
+
+void AacSaPciIsr( 
+	int irq,
+	void * irq_data,
+	struct pt_regs *regs);
+
+void AacRxPciIsr( 
+	int irq,
+	void * irq_data,
+	struct pt_regs *regs);
+
+unsigned SaPciIsr (
+    IN PSa_ADAPTER_EXTENSION AdapterExtension );
+
+unsigned RxPciIsr (
+    IN PSa_ADAPTER_EXTENSION AdapterExtension );
+
+
+/*----------------------------------------------------------------------------*/
+VOID AfaCommInterruptHost(
+	PVOID			AdapterArg,
+	ADAPTER_EVENT	AdapterEvent )
+/*----------------------------------------------------------------------------*/
+{
+	PAFA_COMM_ADAPTER	Adapter = ( PAFA_COMM_ADAPTER ) AdapterArg;
+	PCOMM_REGION CommRegion = Adapter->CommRegion;
+
+	switch (AdapterEvent) {
+
+	  case HostNormRespQue:
+	        OsSoftInterruptTrigger( CommRegion->HostNormRespQue.ConsumerRoutine );
+	
+	// #REVIEW# - what do we do with this
+	// if (FsaCommData.HardInterruptModeration)
+	//			DisableInterrupt( Adapter, HostNormRespQue, TRUE );
+
+			break;
+
+      case AdapNormCmdNotFull:
+	        OsSoftInterruptTrigger( CommRegion->QueueNotFullDpc );
+			break;
+
+	  case HostNormCmdQue:
+	        OsSoftInterruptTrigger( CommRegion->HostNormCmdQue.ConsumerRoutine );
+			break;
+
+      case AdapNormRespNotFull:
+	        OsSoftInterruptTrigger( CommRegion->QueueNotFullDpc );
+			break;
+
+	// #REVIEW# - what do we do with these
+	  case HostHighCmdQue:
+	  case HostHighRespQue:
+	  case AdapHighCmdNotFull:
+	  case AdapHighRespNotFull:
+	  case SynchCommandComplete:
+	  case AdapInternalError:
+		  break;
+	}
+}
+
+
+// get the device name associated with this instance of the device
+/*----------------------------------------------------------------------------*/
+char *OsGetDeviceName( 
+	void *AdapterExtension )
+/*----------------------------------------------------------------------------*/
+{
+	return( ( ( Sa_ADAPTER_EXTENSION * )AdapterExtension )->Common->
+		OsDep.scsi_host_ptr->hostt->name );
+}
+
+
+/*----------------------------------------------------------------------------*/
+int OsGetDeviceInstance( 
+	void *AdapterExtension )
+/*----------------------------------------------------------------------------*/
+{
+	return( ( int )( ( Sa_ADAPTER_EXTENSION * )AdapterExtension )->Common->
+		OsDep.scsi_host_ptr->unique_id );
+}
+
+
+/*------------------------------------------------------------------------------
+	OsMapDeviceRegisters()
+
+	Postconditions:
+		Return zero on success non-zero otherwise.
+ *----------------------------------------------------------------------------*/
+int OsMapDeviceRegisters( 
+	Sa_ADAPTER_EXTENSION *AdapterExtension )
+/*----------------------------------------------------------------------------*/
+{
+	PCI_MINIPORT_COMMON_EXTENSION *CommonExtension;
+
+	CommonExtension = AdapterExtension->Common;
+
+	if( AdapterExtension->Device = ( Sa_DEVICE_REGISTERS * )
+			ioremap( ( unsigned long )CommonExtension->OsDep.scsi_host_ptr->base, 8192 ) )
+	{
+		cmn_err( CE_DEBUG, "Device mapped to virtual address 0x%x", AdapterExtension->Device ); 
+		return( 0 );
+	}
+	else
+	{	
+		cmn_err( CE_WARN, "OsMapDeviceRegisters: ioremap() failed" );
+		return( 1 );
+	}
+}
+
+
+/*------------------------------------------------------------------------------
+	OsUnMapDeviceRegisters()
+
+	Postconditions:
+ *----------------------------------------------------------------------------*/
+void OsUnMapDeviceRegisters( 
+	Sa_ADAPTER_EXTENSION *AdapterExtension )
+/*----------------------------------------------------------------------------*/
+{
+	iounmap( ( void * )AdapterExtension->Device );
+}
+
+
+/*----------------------------------------------------------------------------*/
+int OsAttachInterrupt( 
+	Sa_ADAPTER_EXTENSION *AdapterExtension ,
+	int	WhichIsr )
+/*----------------------------------------------------------------------------*/
+{
+	PCI_MINIPORT_COMMON_EXTENSION *CommonExtension;
+	void *irq_data;
+	void (*Isr)();
+
+	CommonExtension = AdapterExtension->Common;
+	irq_data = ( void * )AdapterExtension;
+
+	switch (WhichIsr) {
+		case SaISR:
+			Isr = AacSaPciIsr;
+			break;
+		case RxISR:
+			Isr = AacRxPciIsr;
+			break;
+		default:
+			cmn_err(CE_WARN, "OsAttachInterrupt: invalid ISR case: 0x%x", WhichIsr);
+			return( FAILURE );
+			break;
+	}
+
+	
+	if	( OsRegisterInterrupt (
+				CommonExtension->OsDep.scsi_host_ptr->irq,	// interrupt number
+				Isr,										// handler function
+				irq_data )
+		) 
+	{
+		cmn_err( CE_DEBUG, "OsAttachInterrupt: Failed for IRQ: 0x%x", 
+			CommonExtension->OsDep.scsi_host_ptr->irq );
+		return( FAILURE );
+	}
+
+	return ( 0 );
+}
+
+
+/*----------------------------------------------------------------------------*/
+void AacSaPciIsr( 
+	int irq,
+	void * irq_data,
+	struct pt_regs *regs)
+/*----------------------------------------------------------------------------*/
+{
+	// call the actual interrupt handler
+	SaPciIsr( ( Sa_ADAPTER_EXTENSION * )irq_data );
+}
+
+/*----------------------------------------------------------------------------*/
+void AacRxPciIsr( 
+	int irq,
+	void * irq_data,
+	struct pt_regs *regs)
+/*----------------------------------------------------------------------------*/
+{
+	// call the actual interrupt handler
+	RxPciIsr( ( Sa_ADAPTER_EXTENSION * )irq_data );
+}
+
+
+/*----------------------------------------------------------------------------*/
+void OsDetachInterrupt( 
+	Sa_ADAPTER_EXTENSION *AdapterExtension )
+/*----------------------------------------------------------------------------*/
+{
+	PCI_MINIPORT_COMMON_EXTENSION *CommonExtension;
+	void *irq_data;
+
+	CommonExtension = AdapterExtension->Common;
+	irq_data = ( void * )AdapterExtension;
+
+	OsUnregisterInterrupt (
+		CommonExtension->OsDep.scsi_host_ptr->irq,	// interrupt number
+		irq_data );
+}
+
+
+/*----------------------------------------------------------------------------*/
+int OsAttachDMA( 
+	Sa_ADAPTER_EXTENSION *AdapterExtension )
+/*----------------------------------------------------------------------------*/
+{
+	return( 0 );
+}
+
+/*----------------------------------------------------------------------------*/
+int OsAttachHBA( 
+	Sa_ADAPTER_EXTENSION *AdapterExtension )
+/*----------------------------------------------------------------------------*/
+{
+	return( 0 );
+}
+
+/*----------------------------------------------------------------------------*/
+void OsDetachDevice( 
+	Sa_ADAPTER_EXTENSION *AdapterExtension )
+/*----------------------------------------------------------------------------*/
+{
+	OsUnMapDeviceRegisters( AdapterExtension );
+	return( 0 );
+}
+
+/*----------------------------------------------------------------------------*/
+ULONG *OsAllocCommPhysMem(
+	Sa_ADAPTER_EXTENSION 	*AdapterExtension, 
+	ULONG					size,
+	ULONG					**virt_addr_pptr,
+	ULONG					*phys_addr_ptr )
+/*----------------------------------------------------------------------------*/
+{
+	if( ( *virt_addr_pptr = ( ULONG * )OsAllocMemory( size, GFP_KERNEL ) ) )
+	{
+		*phys_addr_ptr = OsVirtToPhys( ( volatile void * )*virt_addr_pptr );
+		if( !*phys_addr_ptr )
+		{
+			cmn_err( CE_WARN, "OsAllocCommPhysMem: OsVirtToPhys failed" );
+		}
+				
+		return( *virt_addr_pptr );
+	}
+	else
+		return( NULL );
+}
+
+OsAifKernelThread(
+	Sa_ADAPTER_EXTENSION    *AdapterExtension )
+{
+
+	struct fs_struct *fs;
+	int i;
+	struct task_struct *tsk;
+
+	tsk = current;
+
+
+	/*
+	 * set up the name that will appear in 'ps'
+	 * stored in  task_struct.comm[16].
+	 */
+
+	sprintf(tsk->comm, "AIFd");
+
+
+	// use_init_fs_context();  only exists in 2.2.13 onward.
+
+#ifdef __SMP__
+	lock_kernel();
+#endif
+
+	/*
+	 * we were started as a result of loading the  module.
+	 * free all of user space pages
+	 */
+
+	exit_mm(tsk);
+
+	exit_files(tsk);
+
+	exit_fs(tsk);
+
+	fs = init_task.fs;
+	tsk->fs = fs;
+
+	tsk->session = 1;
+	tsk->pgrp = 1;
+
+	if (fs)
+		atomic_inc(&fs->count);
+
+#ifdef __SMP__
+	unlock_kernel();
+#endif
+
+
+
+
+	NormCommandThread(AdapterExtension);
+	/* NOT REACHED */
+}
+
+/*----------------------------------------------------------------------------*/
+void OsStartKernelThreads(
+	Sa_ADAPTER_EXTENSION 	*AdapterExtension )
+/*----------------------------------------------------------------------------*/
+{
+	PCI_MINIPORT_COMMON_EXTENSION	*CommonExtension;
+	AFA_COMM_ADAPTER				*Adapter;
+	extern void 					NormCommandThread(void *Adapter);
+
+	CommonExtension = AdapterExtension->Common;
+	Adapter = (AFA_COMM_ADAPTER *)CommonExtension->Adapter;
+
+	// 
+	// Start thread which will handle interrupts for this adapter
+	//
+	//kthread_spawn(FsaCommIntrHandler, AdapterExtension, "fsaintr",0);
+
+	//
+	// Start thread which will handle AdapterInititatedFibs from this adapter
+	//
+	CommonExtension->OsDep.thread_pid = 
+		kernel_thread( ( int ( * )( void * ) )OsAifKernelThread, Adapter, 0 );
+//		kernel_thread( ( int ( * )( void * ) )NormCommandThread, Adapter, 0 );
+}
+
+/*----------------------------------------------------------------------------*/
+BOOLEAN AfaPortAllocateAndMapFibSpace(
+	PVOID Arg1,
+    IN PMAPFIB_CONTEXT MapFibContext )
+/*----------------------------------------------------------------------------*/
+{
+	PVOID 		BaseAddress;
+	ULONG		PhysAddress;
+
+	if( !( BaseAddress = (ULONG *)OsAllocMemory( MapFibContext->Size, GFP_KERNEL ) ) )
+	{
+		cmn_err( CE_WARN, "AfaPortAllocateAndMapFibSpace: OsAllocMemory failed" );
+		return( FALSE );
+	}
+
+	PhysAddress = OsVirtToPhys( BaseAddress );
+	
+	MapFibContext->FibVirtualAddress = BaseAddress;
+	MapFibContext->FibPhysicalAddress = (PVOID) PhysAddress;
+
+	return (TRUE);
+}
+
+/*----------------------------------------------------------------------------*/
+BOOLEAN AfaPortUnmapAndFreeFibSpace(
+	PVOID Arg1,
+    IN PMAPFIB_CONTEXT MapFibContext )
+/*----------------------------------------------------------------------------*/
+{
+	PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
+
+	OsFreeMemory( MapFibContext->FibVirtualAddress, 0 );
+
+	return (TRUE);
+}
+
+/*----------------------------------------------------------------------------*/
+BOOLEAN AfaPortFreeAdapterCommArea(
+	IN PVOID Arg1 )
+/*----------------------------------------------------------------------------*/
+{
+	PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
+
+	OsFreeMemory( CommonExtension->CommAddress, 0 );
+
+	return (TRUE);
+}
+
+
+/* ================================================================================ */
+/*
+ * Not sure if the functions below here ever get called in the current code
+ * These probably should be a different file.
+ */
+/*
+ddi_dma_attr_t AfaPortDmaAttributes = {
+	//rpbfix : we may want something different for I/O
+	DMA_ATTR_V0,
+	0,
+	0xffffffff,
+	0x0000ffff,
+	1,
+	1,
+	1,
+	0x0000ffff,
+	0x0000ffff,
+	17,
+	512,
+	0
+};
+*/
+
+AAC_STATUS
+AfaPortBuildSgMap(
+	PVOID Arg1,
+	IN PSGMAP_CONTEXT SgMapContext
+	)
+
+/*++
+
+Routine Description:
+
+	This routine build a scatter gather map using the information
+	in the SgMapContext.
+
+Arguments:
+
+	AdapterExtension - Pointer to adapter extension structure.
+    SgMapContext - Pointer to the SgMapContext for the request.
+
+
+Return Value:
+
+	AAC_STATUS	
+--*/
+{
+	printk( "<1>AfaPortBuildSgMap: unimplemented function called" );
+	return (STATUS_UNSUCCESSFUL);
+}
+
+VOID
+AfaPortFreeDmaResources(
+	PVOID Arg1,
+    IN PSGMAP_CONTEXT SgMapContext
+    )
+
+/*++
+
+Routine Description:
+
+    Given a pointer to the IRP context will free all reserved DMA resources allocated for
+    the completed IO operation.
+
+Arguments:
+
+    Fib - Pointer to the Fib the caller wishes to have transfered over to the adapter.
+    Context - Pointer to the Irp Context we use to store the dma mapping information
+        we need to do and complete the IO.
+
+Return Value:
+
+    Nothing
+
+--*/
+{
+}
diff -BburN linux.orig/drivers/scsi/aacraid/osfuncs.c linux/drivers/scsi/aacraid/osfuncs.c
--- linux.orig/drivers/scsi/aacraid/osfuncs.c	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/osfuncs.c	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,589 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  osfuncs.c
+ *
+ * Abstract: Holds all of the O/S specific interface functions.
+ *	
+ --*/
+
+#include "osheaders.h"
+
+//static LKINFO_DECL(fsa_locks, "fsa_locks",0);
+
+extern aac_options_t g_options;
+
+OS_SOFTINTR g_idle_task = { 0, 0, 0, 0 };
+struct wait_queue * g_wait_queue_ptr = NULL;
+struct wait_queue g_wait;
+
+void OsTimeoutHandler( 
+	struct semaphore * sem );
+
+int * OsIdleTask( void * data );
+
+//-----------------------------------------------------------------------------
+// Memory Allocation functions
+
+/*----------------------------------------------------------------------------*/
+void * OsAllocMemory(
+	OS_SIZE_T Size,
+	unsigned int Flags )
+/*----------------------------------------------------------------------------*/
+{
+	void *mem_ptr;
+
+	if( !( mem_ptr = kmalloc( Size, GFP_KERNEL ) ) )
+		cmn_err( CE_WARN, "OsAllocMemory: FAILED\n" );
+	return( mem_ptr );
+}
+
+
+/*----------------------------------------------------------------------------*/
+void OsFreeMemory(
+	void * Buffer,
+	OS_SIZE_T Size )
+/*----------------------------------------------------------------------------*/
+{
+	kfree( Buffer );
+}
+
+
+/*----------------------------------------------------------------------------*/
+int OsRegisterInterrupt(
+	unsigned int irq,		// interrupt number
+	void ( *handler )( int, void*, struct pt_regs * ),	// handler function
+	void *irq_data )		// argument to handler function
+/*----------------------------------------------------------------------------*/
+{
+	return( request_irq (
+		irq,										// interrupt number
+		handler,									// handler function
+		SA_INTERRUPT | SA_SHIRQ,					// fast handler
+		"aacraid",
+		irq_data ) );
+}
+
+
+/*----------------------------------------------------------------------------*/
+void OsUnregisterInterrupt(
+	unsigned int irq,		// interrupt number
+	void *irq_data)
+/*----------------------------------------------------------------------------*/
+{
+	free_irq (
+		irq,										// interrupt number
+		irq_data );
+}
+
+
+/*----------------------------------------------------------------------------*/
+unsigned long OsVirtToPhys( 
+	void * virtual_address )
+/*----------------------------------------------------------------------------*/
+{
+	return( virt_to_phys( virtual_address ) );
+}
+
+
+//-----------------------------------------------------------------------------
+// MUTEX functions
+
+/*----------------------------------------------------------------------------*/
+OS_STATUS OsMutexInit( 
+	OS_MUTEX *Mutex,
+	OS_SPINLOCK_COOKIE Cookie )
+/*----------------------------------------------------------------------------*/
+{
+	Mutex->wq_ptr = NULL;
+	Mutex->lock_var = 0;
+	return ( 0 );
+}
+
+
+/*----------------------------------------------------------------------------*/
+void OsMutexDestroy( 
+	OS_MUTEX *Mutex )
+/*----------------------------------------------------------------------------*/
+{
+}
+
+
+/*----------------------------------------------------------------------------*/
+void OsMutexAcquire( 
+	OS_MUTEX *Mutex )
+/*----------------------------------------------------------------------------*/
+{
+	struct wait_queue wait = { current, NULL };
+	unsigned long time_stamp;
+
+	time_stamp = jiffies;
+
+	if( test_and_set_bit( 0, &( Mutex->lock_var ) ) != 0 )
+	{
+		if( in_interrupt() )
+			panic( "OsMutexAcquire going to sleep at interrupt time\n" );
+		current->state = TASK_INTERRUPTIBLE;
+		add_wait_queue( &( Mutex->wq_ptr ), &wait );
+		while( test_and_set_bit( 0, &( Mutex->lock_var ) ) != 0 )
+			schedule();
+		remove_wait_queue( &( Mutex->wq_ptr ), &wait );
+	}
+
+	if( ( jiffies - 1 ) > time_stamp )
+		cmn_err( CE_WARN, "Mutex %ld locked out for %ld ticks", 
+			Mutex, jiffies - time_stamp );
+}
+
+
+/*----------------------------------------------------------------------------*/
+void OsMutexRelease( 
+	OS_MUTEX *Mutex )
+/*----------------------------------------------------------------------------*/
+{
+	if( test_and_clear_bit( 0, &( Mutex->lock_var ) ) == 0 )
+		cmn_err( CE_WARN, "OsMutexRelease: mutex not locked" );
+	wake_up_interruptible( &( Mutex->wq_ptr ) );
+}
+
+// see man hierarchy(D5)
+#define FSA_LOCK 1
+
+//-----------------------------------------------------------------------------
+// Spinlock functions
+
+/*----------------------------------------------------------------------------*/
+OS_SPINLOCK * OsSpinLockAlloc( void ) 
+/*----------------------------------------------------------------------------*/
+{
+	OS_SPINLOCK *SpinLock;
+	int i;
+
+	SpinLock = ( OS_SPINLOCK * )kmalloc( sizeof( OS_SPINLOCK ), GFP_KERNEL );
+	SpinLock->spin_lock = SPIN_LOCK_UNLOCKED;
+	for( i = 0; i < NR_CPUS; i++ )
+		SpinLock->cpu_lock_count[ i ] = 0;
+	return( SpinLock );
+}
+
+
+/*----------------------------------------------------------------------------*/
+OS_STATUS OsSpinLockInit( 
+	OS_SPINLOCK *SpinLock,
+	OS_SPINLOCK_COOKIE Cookie )
+/*----------------------------------------------------------------------------*/
+{
+	return( 0 );
+}
+
+
+/*----------------------------------------------------------------------------*/
+void OsSpinLockDestroy( 
+	OS_SPINLOCK *SpinLock )
+/*----------------------------------------------------------------------------*/
+{
+	kfree( SpinLock );
+	SpinLock = NULL;
+}
+
+
+/*----------------------------------------------------------------------------*/
+void OsSpinLockAcquire( 
+	OS_SPINLOCK *SpinLock )
+/*----------------------------------------------------------------------------*/
+{
+	unsigned cpu_id, i;
+
+	if( SpinLock )
+	{
+		/*
+		if( OsSpinLockOwned( SpinLock ) )
+		{
+			SpinLock->lockout_count++;
+			if( SpinLock->lockout_count > 200 )
+			{
+				cmn_err( CE_WARN, "spin lock #%ld: lockout_count high", SpinLock );
+				SpinLock->lockout_count = 0;
+			}
+		}
+		*/
+		cpu_id = smp_processor_id();
+		if( SpinLock->cpu_lock_count[ cpu_id ] )
+			panic( "CPU %d trying to acquire lock again: lock count = %d\n", 
+				cpu_id, SpinLock->cpu_lock_count[ cpu_id ] );
+		/*
+		for( i = 0; i < NR_CPUS; i++ )
+			if( SpinLock->cpu_lock_count[ i ] )
+				panic( "Another CPU has the lock\n" );
+		*/
+		spin_lock_irqsave( &( SpinLock->spin_lock ), SpinLock->cpu_flag );
+		SpinLock->cpu_lock_count[ cpu_id ]++;
+	}
+	else
+		cmn_err( CE_WARN, "OsSpinLockAcquire: lock does not exist" );
+}
+
+
+/*----------------------------------------------------------------------------*/
+void OsSpinLockRelease( 
+	OS_SPINLOCK *SpinLock )
+/*----------------------------------------------------------------------------*/
+{
+	if( SpinLock )
+	{
+		SpinLock->cpu_lock_count[ smp_processor_id() ]--;
+		spin_unlock_irqrestore( &( SpinLock->spin_lock ), SpinLock->cpu_flag );
+	}
+	else
+		cmn_err( CE_WARN, "OsSpinLockRelease: lock does not exist" );
+}
+
+
+/*----------------------------------------------------------------------------*/
+int OsSpinLockOwned(
+	OS_SPINLOCK *SpinLock )
+/*----------------------------------------------------------------------------*/
+{
+#ifdef __SMP__
+	if( SpinLock->spin_lock.lock != 0 )
+		return( 1 );
+	else
+#endif
+		return( 0 );
+}
+
+
+//-----------------------------------------------------------------------------
+// CvLock functions
+
+/*----------------------------------------------------------------------------*/
+OS_CVLOCK *OsCvLockAlloc( void ) 
+/*----------------------------------------------------------------------------*/
+{
+	OS_CVLOCK *cv_lock;
+
+#ifdef CVLOCK_USE_SPINLOCK
+	cv_lock = OsSpinLockAlloc(); 
+#else
+	cv_lock = ( OS_CVLOCK * )kmalloc( sizeof( OS_CVLOCK ), GFP_KERNEL );
+	cv_lock->wq_ptr = NULL;
+	cv_lock->lock_var = 0;
+#endif
+
+	return( cv_lock );
+}
+
+
+/*----------------------------------------------------------------------------*/
+OS_STATUS OsCvLockInit( 
+	OS_CVLOCK *cv_lock,
+	OS_SPINLOCK_COOKIE Cookie )
+/*----------------------------------------------------------------------------*/
+{
+	return ( 0 );
+}
+
+
+/*----------------------------------------------------------------------------*/
+void OsCvLockDestroy( 
+	OS_CVLOCK *cv_lock )
+/*----------------------------------------------------------------------------*/
+{
+	if( cv_lock )
+		kfree( cv_lock );
+	cv_lock = NULL;
+}
+
+
+/*----------------------------------------------------------------------------*/
+void OsCvLockAcquire( 
+	OS_CVLOCK *cv_lock )
+/*----------------------------------------------------------------------------*/
+{
+#ifdef CVLOCK_USE_SPINLOCK
+	OsSpinLockAcquire( cv_lock );
+#else
+	OsMutexAcquire(	cv_lock );
+#endif
+}
+
+
+/*----------------------------------------------------------------------------*/
+void OsCvLockRelease( 
+	OS_CVLOCK *cv_lock )
+/*----------------------------------------------------------------------------*/
+{
+#ifdef CVLOCK_USE_SPINLOCK
+	OsSpinLockRelease( cv_lock );
+#else
+	OsMutexRelease( cv_lock );
+#endif
+}
+
+
+/*----------------------------------------------------------------------------*/
+int OsCvLockOwned(
+	OS_CVLOCK *cv_lock )
+/*----------------------------------------------------------------------------*/
+{
+	return( 1 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Conditional variable functions
+
+/*----------------------------------------------------------------------------*/
+void OsCv_init ( 
+	OS_CV_T *cv_ptr )
+/*----------------------------------------------------------------------------*/
+{
+	cv_ptr->lock_var = 1;
+	cv_ptr->wq_ptr = NULL;
+}
+
+
+/*----------------------------------------------------------------------------*/
+void OsCv_destroy( 
+	OS_CV_T  *cv_ptr )
+/*----------------------------------------------------------------------------*/
+{
+}
+
+
+/*----------------------------------------------------------------------------*/
+void OsCv_wait( 
+	OS_CV_T *cv_ptr, 
+	OS_CVLOCK *cv_lock_ptr )
+/*----------------------------------------------------------------------------*/
+{
+	struct wait_queue wait = { current, NULL };
+	unsigned long flags;
+	
+	if( in_interrupt() )
+		panic( "OsCv_wait going to sleep at interrupt time\n" );
+
+	cv_ptr->type = TASK_UNINTERRUPTIBLE;
+	current->state = TASK_UNINTERRUPTIBLE;
+	add_wait_queue( &( cv_ptr->wq_ptr ), &wait );
+
+	OsCvLockRelease( cv_lock_ptr );
+	schedule();
+
+	while( test_and_set_bit( 0, &( cv_ptr->lock_var ) ) != 0 )
+	{
+		if( in_interrupt() )
+			panic( "OsCv_wait going to sleep at interrupt time\n" );
+		schedule();
+	}
+
+	remove_wait_queue( &( cv_ptr->wq_ptr ), &wait );
+	
+	OsCvLockAcquire( cv_lock_ptr );
+}
+
+
+/*----------------------------------------------------------------------------*/
+int OsCv_wait_sig( 
+	OS_CV_T *cv_ptr,
+	OS_CVLOCK *cv_lock_ptr ) 
+/*----------------------------------------------------------------------------*/
+{
+	struct wait_queue wait = { current, NULL };
+	unsigned long flags;
+	int signal_state = 1;
+	
+	if( in_interrupt() )
+		panic( "OsCv_wait_sig going to sleep at interrupt time\n" );
+
+	cv_ptr->type = TASK_INTERRUPTIBLE;
+	current->state = TASK_INTERRUPTIBLE;
+	add_wait_queue( &( cv_ptr->wq_ptr ), &wait );
+
+	OsCvLockRelease( cv_lock_ptr );
+	schedule();
+
+	while( ( test_and_set_bit( 0, &( cv_ptr->lock_var ) ) != 0 ) && 
+			( !signal_pending( current ) ) )
+	{
+		if( in_interrupt() )
+			panic( "OsCv_wait_sig going to sleep at interrupt time\n" );
+		schedule();
+	}
+
+	if( signal_pending( current ) )
+		signal_state = 0;
+	
+	remove_wait_queue( &( cv_ptr->wq_ptr ), &wait );
+	
+	OsCvLockAcquire( cv_lock_ptr );
+	return( signal_state );
+}
+
+
+/*----------------------------------------------------------------------------*/
+void OsCv_signal( 
+	OS_CV_T *cv_ptr )
+/*----------------------------------------------------------------------------*/
+{
+	clear_bit( 0, &( cv_ptr->lock_var ) );
+	if( cv_ptr->type == TASK_INTERRUPTIBLE )
+		wake_up_interruptible( &( cv_ptr->wq_ptr ) );
+	else
+		wake_up( &( cv_ptr->wq_ptr ) );
+}
+
+
+// return time in seconds
+/*----------------------------------------------------------------------------*/
+unsigned long OsGetSeconds( void )
+/*----------------------------------------------------------------------------*/
+{
+	return( jiffies/HZ );
+}
+
+
+//-----------------------------------------------------------------------------
+// Deferred procedure call functions
+
+// create a soft interrupt object
+/*----------------------------------------------------------------------------*/
+int OsSoftInterruptAdd( 
+	OS_SOFTINTR **ptr,
+	void * handler,
+	void * data )
+/*----------------------------------------------------------------------------*/
+{
+	OS_SOFTINTR *tmp_ptr;
+
+	if( !( tmp_ptr = ( OS_SOFTINTR * )kmalloc( sizeof( OS_SOFTINTR ), GFP_KERNEL ) ) )
+		return( -1 );
+	tmp_ptr->routine = handler;
+	tmp_ptr->data = data;
+	tmp_ptr->next = NULL;
+	tmp_ptr->sync = 0;
+
+	*ptr = tmp_ptr; 
+
+	return( 0 );
+}
+
+/*
+	Use kernel_thread( ( int ( * )( void * ) )OsIdleTask, NULL, 0 ); to start
+*/
+/*----------------------------------------------------------------------------*/
+int * OsIdleTask( void * data )
+/*----------------------------------------------------------------------------*/
+{
+	struct wait_queue wait = { current, NULL };
+
+	while( 1 )
+	{
+		//interruptible_sleep_on( &g_wait_queue_ptr );
+		current->state = TASK_INTERRUPTIBLE;
+		add_wait_queue( &g_wait_queue_ptr, &wait );
+		schedule();
+		remove_wait_queue( &g_wait_queue_ptr, &wait );
+		wait.task =  current;
+		wait.next = NULL;
+	}
+	return( NULL );
+}
+
+
+// dispatch a soft interrupt 
+/*----------------------------------------------------------------------------*/
+void OsSoftInterruptTrigger( 
+	OS_SOFTINTR *soft_intr_ptr )
+/*----------------------------------------------------------------------------*/
+{
+	// wake up a kernel thread
+	//wake_up_interruptible( &g_wait_queue_ptr );
+
+	// put in scheduler task queue
+	//queue_task( soft_intr_ptr, &tq_scheduler );
+	
+	// call the completion routine directly
+	soft_intr_ptr->routine( soft_intr_ptr->data );
+}
+
+
+// delete a soft interrupt object
+/*----------------------------------------------------------------------------*/
+void OsSoftInterruptRemove( 
+	OS_SOFTINTR *arg )
+/*----------------------------------------------------------------------------*/
+{
+	if( arg )
+		kfree( arg );
+	arg = NULL;
+}
+
+
+/*----------------------------------------------------------------------------*/
+void OsSleep( 
+	unsigned time )		// in seconds
+/*----------------------------------------------------------------------------*/
+{
+	struct semaphore sem = MUTEX_LOCKED;
+	struct timer_list timer_var;
+	
+	if( in_interrupt() )
+		panic( "OsSleep going to sleep at interrupt time\n" );
+
+	init_timer( &timer_var );
+	timer_var.function = ( void ( * )( unsigned long ) )OsTimeoutHandler;
+	timer_var.data = ( unsigned long )&sem;
+	timer_var.expires = jiffies + time * HZ;
+
+	add_timer( &timer_var );
+	down( &sem );
+
+	del_timer( &timer_var );
+}
+
+
+/*----------------------------------------------------------------------------*/
+void OsTimeoutHandler( 
+	struct semaphore * sem )
+/*----------------------------------------------------------------------------*/
+{
+	if( sem != NULL )
+		up( sem );
+}
+
+
+/*----------------------------------------------------------------------------*/
+void printk_err(
+	int flag, 
+	char *fmt, 
+	...)
+/*----------------------------------------------------------------------------*/
+{
+	char	buf[256];
+	va_list	ap;
+
+	va_start(ap, fmt);
+	(void) vsprintf(buf, fmt, ap);
+	va_end(ap);
+	
+	if( flag <= g_options.message_level )
+		printk("<1>%s\n", buf);
+}
diff -BburN linux.orig/drivers/scsi/aacraid/ossup.c linux/drivers/scsi/aacraid/ossup.c
--- linux.orig/drivers/scsi/aacraid/ossup.c	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/ossup.c	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,197 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  ossup.c
+ *
+ * 
+ *
+ --*/
+
+#include "osheaders.h"
+
+#include "aac_unix_defs.h"
+
+
+AAC_STATUS
+ExInitializeZone(
+    IN PZONE_HEADER Zone,
+    IN ULONG BlockSize,
+    IN PVOID InitialSegment,
+    IN ULONG InitialSegmentSize
+    )
+
+/*++
+
+Routine Description:
+
+    This function initializes a zone header.  Once successfully
+    initialized, blocks can be allocated and freed from the zone, and
+    the zone can be extended.
+
+Arguments:
+
+    Zone - Supplies the address of a zone header to be initialized.
+
+    BlockSize - Supplies the block size of the allocatable unit within
+                the zone.  The size must be larger that the size of the
+                initial segment, and must be 64-bit aligned.
+
+    InitialSegment - Supplies the address of a segment of storage.  The
+                     first ZONE_SEGMENT_HEADER-sized portion of the segment
+                     is used by the zone allocator.  The remainder of
+                     the segment is carved up into fixed size
+                     (BlockSize) blocks and is made available for
+                     allocation and deallocation from the zone.  The
+                     address of the segment must be aligned on a 64-bit
+                     boundary.
+
+    InitialSegmentSize - Supplies the size in bytes of the InitialSegment.
+
+Return Value:
+
+    STATUS_UNSUCCESSFUL - BlockSize or InitialSegment was not aligned on
+                          64-bit boundaries, or BlockSize was larger than
+                          the initial segment size.
+
+    STATUS_SUCCESS - The zone was successfully initialized.
+
+--*/
+
+{
+    ULONG i;
+    PCHAR p;
+
+
+    Zone->BlockSize = BlockSize;
+
+    Zone->SegmentList.Next = &((PZONE_SEGMENT_HEADER) InitialSegment)->SegmentList;
+    ((PZONE_SEGMENT_HEADER) InitialSegment)->SegmentList.Next = NULL;
+    ((PZONE_SEGMENT_HEADER) InitialSegment)->Reserved = NULL;
+
+    Zone->FreeList.Next = NULL;
+
+    p = (PCHAR)InitialSegment + sizeof(ZONE_SEGMENT_HEADER);
+
+    for (i = sizeof(ZONE_SEGMENT_HEADER);
+         i <= InitialSegmentSize - BlockSize;
+         i += BlockSize
+        ) {
+        ((PSINGLE_LIST_ENTRY)p)->Next = Zone->FreeList.Next;
+        Zone->FreeList.Next = (PSINGLE_LIST_ENTRY)p;
+        p += BlockSize;
+    }
+    Zone->TotalSegmentSize = i;
+
+#if 0
+    DbgPrint( "EX: ExInitializeZone( %lx, %lx, %lu, %lu, %lx )\n",
+              Zone, InitialSegment, InitialSegmentSize,
+              BlockSize, p
+            );
+#endif
+
+    return STATUS_SUCCESS;
+}
+
+AAC_STATUS
+ExExtendZone(
+    IN PZONE_HEADER Zone,
+    IN PVOID Segment,
+    IN ULONG SegmentSize
+    )
+
+/*++
+
+Routine Description:
+
+    This function extends a zone by adding another segment's worth of
+    blocks to the zone.
+
+Arguments:
+
+    Zone - Supplies the address of a zone header to be extended.
+
+    Segment - Supplies the address of a segment of storage.  The first
+              ZONE_SEGMENT_HEADER-sized portion of the segment is used by the
+              zone allocator.  The remainder of the segment is carved up
+              into fixed-size (BlockSize) blocks and is added to the
+              zone.  The address of the segment must be aligned on a 64-
+              bit boundary.
+
+    SegmentSize - Supplies the size in bytes of Segment.
+
+Return Value:
+
+    STATUS_UNSUCCESSFUL - BlockSize or Segment was not aligned on
+                          64-bit boundaries, or BlockSize was larger than
+                          the segment size.
+
+    STATUS_SUCCESS - The zone was successfully extended.
+
+--*/
+
+{
+    ULONG i;
+    PCHAR p;
+
+
+    ((PZONE_SEGMENT_HEADER) Segment)->SegmentList.Next = Zone->SegmentList.Next;
+    Zone->SegmentList.Next = &((PZONE_SEGMENT_HEADER) Segment)->SegmentList;
+
+    p = (PCHAR)Segment + sizeof(ZONE_SEGMENT_HEADER);
+
+    for (i = sizeof(ZONE_SEGMENT_HEADER);
+         i <= SegmentSize - Zone->BlockSize;
+         i += Zone->BlockSize
+        ) {
+
+        ((PSINGLE_LIST_ENTRY)p)->Next = Zone->FreeList.Next;
+        Zone->FreeList.Next = (PSINGLE_LIST_ENTRY)p;
+        p += Zone->BlockSize;
+    }
+    Zone->TotalSegmentSize += i;
+
+#if 0
+    DbgPrint( "EX: ExExtendZone( %lx, %lx, %lu, %lu, %lx )\n",
+              Zone, Segment, SegmentSize, Zone->BlockSize, p
+            );
+#endif
+
+    return STATUS_SUCCESS;
+}
+
+DbgPrint()
+{
+}
+
+/* Function: InqStrCopy()
+ *
+ * Arguments: [2] pointer to char
+ *
+ * Purpose: Copy a String from one location to another
+ * without copying \0
+ */
+void
+InqStrCopy(char *a, char *b)
+{
+
+	while(*a != (char)0) 
+		*b++ = *a++;
+}
+
diff -BburN linux.orig/drivers/scsi/aacraid/port.c linux/drivers/scsi/aacraid/port.c
--- linux.orig/drivers/scsi/aacraid/port.c	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/port.c	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,284 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  port.c
+ *
+ * Abstract: All support routines for FSA communication which are miniport specific.
+ *
+ --*/
+
+#include "osheaders.h"
+
+
+#include "AacGenericTypes.h"
+
+#include "aac_unix_defs.h"
+
+#include "fsatypes.h"
+#include "comstruc.h"
+#include "protocol.h"
+
+#include "fsaport.h"
+#include "fsaioctl.h"
+
+#include "pcisup.h"
+#include "port.h"
+
+int AfaPortPrinting = 1;
+
+extern AAC_STATUS AfaPort_Err_Adapter_Printf;
+extern AAC_STATUS AfaPort_Warn_Adapter_Printf;
+extern AAC_STATUS AfaPort_Info_Adapter_Printf;
+extern AAC_STATUS AfaPort_Err_FastAfa_Load_Driver;
+
+
+
+VOID
+AfaPortLogError(
+	IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension,
+	IN AAC_STATUS ErrorCode,
+	IN PUCHAR StringBuffer,
+	IN ULONG StringLength
+	)
+/*++
+
+Routine Description:
+
+	Does all of the work to log an error log entry
+Arguments:
+
+	CommonExtension - Pointer to the adapter that caused the error.
+
+	ErrorCode - Which error is being logged.
+
+	StringBuffer - Pointer to optional String for error log entry.
+
+	StringLength - Length of StringBuffer.
+
+Return Value:
+
+    Nothing
+
+--*/
+
+{
+
+}
+
+BOOLEAN
+AfaPortGetNextAdapterNumber(
+    IN  PDRIVER_OBJECT  DriverObject,
+	OUT PDEVICE_OBJECT 	*FsaDeviceObject,
+	OUT PFILE_OBJECT 	*FileObject,
+	OUT PULONG			AdapterNumber
+	)
+{
+}
+BOOLEAN
+AfaPortAllocateAdapterCommArea(
+	IN PVOID		Arg1,
+	IN OUT PVOID	*CommHeaderAddress,
+	IN ULONG		CommAreaSize,
+	IN ULONG		CommAreaAlignment
+	)
+{
+	PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
+	PVOID BaseAddress;
+	PHYSICAL_ADDRESS PhysicalBaseAddress;
+	ULONG TotalSize, BytesToAlign;
+	size_t		RealLength;
+	uint_t		Count;
+//	ULONG SizeOfFastIoComm = sizeof(FASTIO_STRUCT);
+//	ULONG AdapterFibsSize = PAGE_SIZE;
+	ULONG AdapterFibsSize = 4096;
+	ULONG PrintfBufferSize = 256;
+	PADAPTER_INIT_STRUCT InitStruct;
+	extern int MiniPortRevision;
+	ULONG	PhysAddress;
+
+//	TotalSize = AdapterFibsSize + sizeof(ADAPTER_INIT_STRUCT) + CommAreaSize + CommAreaAlignment +
+//		 SizeOfFastIoComm + PrintfBufferSize;
+	TotalSize = AdapterFibsSize + sizeof(ADAPTER_INIT_STRUCT) + CommAreaSize + CommAreaAlignment +
+		 PrintfBufferSize;
+
+
+	OsAllocCommPhysMem(CommonExtension->MiniPort, TotalSize, &BaseAddress, &PhysAddress);
+
+	CommonExtension->CommAddress  = BaseAddress;
+	CommonExtension->CommPhysAddr = PhysAddress;
+	CommonExtension->CommSize 	  = TotalSize;
+
+	PhysicalBaseAddress.HighPart = 0;
+	PhysicalBaseAddress.LowPart = PhysAddress;
+
+	CommonExtension->InitStruct = (PADAPTER_INIT_STRUCT)((PUCHAR)(BaseAddress) + AdapterFibsSize);
+	CommonExtension->PhysicalInitStruct = (PADAPTER_INIT_STRUCT)((PUCHAR)(PhysicalBaseAddress.LowPart) + AdapterFibsSize);
+
+	InitStruct = CommonExtension->InitStruct;
+
+	InitStruct->InitStructRevision = ADAPTER_INIT_STRUCT_REVISION;
+	InitStruct->MiniPortRevision = MiniPortRevision;
+	InitStruct->FilesystemRevision = CommonExtension->FilesystemRevision;
+
+	//
+	// Adapter Fibs are the first thing allocated so that they start page aligned
+	//
+	InitStruct->AdapterFibsVirtualAddress = BaseAddress;
+	InitStruct->AdapterFibsPhysicalAddress = (PVOID) PhysicalBaseAddress.LowPart;
+	InitStruct->AdapterFibsSize = AdapterFibsSize;
+	InitStruct->AdapterFibAlign = sizeof(FIB);
+
+	//
+	// Increment the base address by the amount already used
+	//
+	BaseAddress = (PVOID)((PUCHAR)(BaseAddress) + AdapterFibsSize + sizeof(ADAPTER_INIT_STRUCT));
+	PhysicalBaseAddress.LowPart = (ULONG)((PUCHAR)(PhysicalBaseAddress.LowPart) + AdapterFibsSize + sizeof(ADAPTER_INIT_STRUCT));
+
+	//
+	// Align the beginning of Headers to CommAreaAlignment
+	//
+	BytesToAlign = (CommAreaAlignment - ((ULONG)(BaseAddress) & (CommAreaAlignment - 1)));
+	BaseAddress = (PVOID)((PUCHAR)(BaseAddress) + BytesToAlign);
+	PhysicalBaseAddress.LowPart = (ULONG)((PUCHAR)(PhysicalBaseAddress.LowPart) + BytesToAlign);
+
+	//
+	// Fill in addresses of the Comm Area Headers and Queues
+	//
+	*CommHeaderAddress = BaseAddress;
+	InitStruct->CommHeaderAddress = (PVOID)PhysicalBaseAddress.LowPart;
+
+	//
+	//	Increment the base address by the size of the CommArea
+	//
+	BaseAddress = (PVOID)((PUCHAR)(BaseAddress) + CommAreaSize);
+	PhysicalBaseAddress.LowPart = (ULONG)((PUCHAR)(PhysicalBaseAddress.LowPart) + CommAreaSize);
+
+
+	//
+	// Place the Printf buffer area after the Fast I/O comm area.
+	//
+	CommonExtension->PrintfBufferAddress = (PVOID)(BaseAddress);
+	InitStruct->PrintfBufferAddress = (PVOID)PhysicalBaseAddress.LowPart;
+	InitStruct->PrintfBufferSize = PrintfBufferSize;
+
+	AfaPortPrint("FsaAllocateAdapterCommArea: allocated a common buffer of 0x%x bytes from address 0x%x to address 0x%x\n",
+			 TotalSize, InitStruct->AdapterFibsVirtualAddress,
+			 (PUCHAR)(InitStruct->AdapterFibsVirtualAddress) + TotalSize);
+
+	AfaPortPrint("Mapped on to PCI address 0x%x\n", InitStruct->AdapterFibsPhysicalAddress);
+
+	return (TRUE);
+}
+
+AAC_STATUS
+AfaPortCreate (
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp
+    )
+/*++
+
+Routine Description:
+
+	The routine will get called each time a user issues a CreateFile on the DeviceObject
+	for the adapter.
+
+	The main purpose of this routine is to set up any data structures that may be needed
+	to handle any requests made on this DeviceObject.
+
+Arguments:
+
+	DeviceObject - Pointer to device object representing adapter
+
+	Irp - Pointer to Irp that caused this open
+
+
+Return Value:
+
+	Status value returned from File system driver AdapterOpen
+
+--*/
+
+{
+}
+
+AAC_STATUS
+AfaPortClose (
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp
+    )
+/*++
+
+Routine Description:
+
+	This routine will get called each time a user issues a CloseHandle on the DeviceObject
+	for the adapter.
+
+	The main purpose of this routine is to cleanup any data structures that have been set up
+	while this FileObject has been opened.
+
+Arguments:
+
+	DeviceObject - Pointer to device object representing adapter
+
+	Irp - Pointer to Irp that caused this close
+
+Return Value:
+
+	Status value returned from File system driver AdapterClose
+
+--*/
+
+{
+
+}
+
+AAC_STATUS
+AfaPortDeviceControl (
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp
+    )
+{
+
+}
+
+ULONG
+AfaPortGetMaxPhysicalPage(
+	IN PPCI_MINIPORT_COMMON_EXTENSION	CommonExtension
+	)
+/*++
+
+Routine Description:
+
+	This routine determines the max physical page in host memory.
+
+Arguments:
+
+	AdapterExtension
+
+Return Value:
+
+	Max physical page in host memory.
+
+--*/
+{
+
+}
+
+
diff -BburN linux.orig/drivers/scsi/aacraid/rx.c linux/drivers/scsi/aacraid/rx.c
--- linux.orig/drivers/scsi/aacraid/rx.c	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/rx.c	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,894 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  rx.c
+ *
+ * Abstract: Hardware miniport for Drawbridge specific hardware functions.
+ *
+ --*/
+
+#include "osheaders.h"
+
+
+#include "AacGenericTypes.h"
+
+#include "aac_unix_defs.h"
+
+#include "fsatypes.h"
+#include "comstruc.h"
+#include "fsact.h"
+#include "protocol.h"
+
+#define DEFINE_PCI_IDS
+#include "rxcommon.h"
+#include "monkerapi.h"
+
+#include "fsaport.h"
+#include "fsaioctl.h"
+
+#include "pcisup.h"
+#include "rx.h"
+
+#include "port.h"
+
+#define BugCheckFileId                   (FSAFS_BUG_CHECK_CYCLONESUP)
+
+// #define RxBugCheck(A,B,C) { KeBugCheckEx(0x00000AFA, __LINE__, (ULONG)A, (ULONG)B,(ULONG)C ); }
+
+#define RxBugCheck(A, B, C) {	cmn_err(CE_PANIC, "aacdisk : line %s, 0x%x, 0x%x, 0x%x ", __LINE__, A, B, C);  }
+
+#define NUM_TICKS_PER_SECOND (1000 * 1000 * 10) /* time is in 100 nanoseconds */
+
+
+//
+// The list of all the Rx adapter structures
+//
+
+PRx_ADAPTER_EXTENSION	RxAdapterList;
+
+int
+RxInitDevice(
+	IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension,
+	IN ULONG AdapterNumber,
+	IN ULONG PciBus,
+	IN ULONG PciSlot
+);
+
+BOOLEAN
+RxSendSynchFib(
+	PVOID Arg1,
+	ULONG FibPhysicalAddress
+	);
+
+FSA_USER_VAR	RxUserVars[] = {
+	{ "AfaPortPrinting", (PULONG)&AfaPortPrinting, NULL },
+};
+
+
+//
+// Declare private use routines for this modual
+//
+
+u_int
+RxPciIsr (
+    IN PRx_ADAPTER_EXTENSION AdapterExtension
+    )
+
+/*++
+
+Routine Description:
+
+    The Isr routine for fsa Rx based adapter boards.
+
+Arguments:
+
+
+Return Value:
+
+	TRUE - if the interrupt was handled by this isr
+	FALSE - if the interrupt was not handled by this isr
+
+--*/
+
+{
+	ULONG	DoorbellBits;
+	UCHAR	InterruptStatus, Mask;
+	u_int OurInterrupt = INTR_UNCLAIMED;
+
+	//cmn_err(CE_WARN, "RxPciIsr entered\n");
+
+	InterruptStatus = Rx_READ_UCHAR(AdapterExtension, MUnit.OISR);
+
+	//
+	// Read mask and invert because drawbridge is reversed.
+	//
+	// This allows us to only service interrupts that have been enabled.
+	//
+
+	Mask = ~(Rx_READ_UCHAR(AdapterExtension, MUnit.OIMR));
+
+	// Check to see if this is our interrupt.  If it isn't just return FALSE.
+
+
+	if (InterruptStatus & Mask) {
+
+		DoorbellBits = Rx_READ_ULONG(AdapterExtension, OutboundDoorbellReg);
+
+		OurInterrupt = INTR_CLAIMED;
+
+		if (DoorbellBits & DoorBellPrintfReady) {
+
+
+			cmn_err(CE_CONT, "%s:%s", OsGetDeviceName(AdapterExtension), AdapterExtension->Common->PrintfBufferAddress);
+
+			Rx_WRITE_ULONG(AdapterExtension, MUnit.ODR,DoorBellPrintfReady); //clear PrintfReady
+
+			Rx_WRITE_ULONG(AdapterExtension, InboundDoorbellReg,DoorBellPrintfDone);
+
+
+		} else if (DoorbellBits & DoorBellAdapterNormCmdReady) {	// Adapter -> Host Normal Command Ready
+
+			AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, HostNormCmdQue);
+			Rx_WRITE_ULONG(AdapterExtension, MUnit.ODR, DoorBellAdapterNormCmdReady);
+
+		} else if (DoorbellBits & DoorBellAdapterNormRespReady) {	// Adapter -> Host Normal Response Ready
+
+			AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, HostNormRespQue);
+			Rx_WRITE_ULONG(AdapterExtension, MUnit.ODR,DoorBellAdapterNormRespReady);
+
+		} else if (DoorbellBits & DoorBellAdapterNormCmdNotFull) {	// Adapter -> Host Normal Command Not Full
+
+			AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, AdapNormCmdNotFull);
+			Rx_WRITE_ULONG(AdapterExtension, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
+
+		} else if (DoorbellBits & DoorBellAdapterNormRespNotFull) {	// Adapter -> Host Normal Response Not Full
+
+			AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, AdapNormRespNotFull);
+			Rx_WRITE_ULONG(AdapterExtension, MUnit.ODR, DoorBellAdapterNormRespNotFull);
+
+		}
+
+	}
+	return(OurInterrupt);
+}
+
+VOID
+RxEnableInterrupt(
+	PVOID						Arg1,
+	ADAPTER_EVENT				AdapterEvent,
+	BOOLEAN						AtDeviceIrq
+	)
+/*++
+
+Routine Description:
+
+	This routine will enable the corresponding adapter event to cause an interrupt on 
+	the host.
+
+Arguments:
+
+	AdapterExtension - Which adapter to enable.
+
+	AdapterEvent - Which adapter event.
+
+	AtDeviceIrq - Whether the system is in DEVICE irql
+
+Return Value:
+
+    Nothing.
+
+--*/
+{
+	PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
+	PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) CommonExtension->MiniPort;
+
+	//cmn_err(CE_WARN, "RxEnableInterrupt");
+	switch (AdapterEvent) {
+
+	  case HostNormCmdQue:
+
+		AdapterExtension->LocalMaskInterruptControl &= ~(OUTBOUNDDOORBELL_1);
+
+		break;
+
+	  case HostNormRespQue:
+
+		AdapterExtension->LocalMaskInterruptControl &= ~(OUTBOUNDDOORBELL_2);
+
+		break;
+
+      case AdapNormCmdNotFull:
+
+		AdapterExtension->LocalMaskInterruptControl &= ~(OUTBOUNDDOORBELL_3);
+
+		break;
+
+      case AdapNormRespNotFull:
+
+		AdapterExtension->LocalMaskInterruptControl &= ~(OUTBOUNDDOORBELL_4);
+
+		break;
+
+	}
+
+}
+
+VOID
+RxDisableInterrupt(
+	PVOID						Arg1,
+	ADAPTER_EVENT				AdapterEvent,
+	BOOLEAN						AtDeviceIrq
+	)
+/*++
+
+Routine Description:
+
+	This routine will disable the corresponding adapter event to cause an interrupt on 
+	the host.
+
+Arguments:
+
+	AdapterExtension - Which adapter to enable.
+
+	AdapterEvent - Which adapter event.
+
+	AtDeviceIrq - Whether the system is in DEVICE irql
+
+Return Value:
+
+    Nothing.
+
+--*/
+{
+	PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
+	PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) CommonExtension->MiniPort;
+
+	//cmn_err(CE_WARN, "RxEnableInterrupt");
+
+	switch (AdapterEvent) {
+
+
+	  case HostNormCmdQue:
+
+		AdapterExtension->LocalMaskInterruptControl |= (OUTBOUNDDOORBELL_1);
+
+		break;
+
+	  case HostNormRespQue:
+
+		AdapterExtension->LocalMaskInterruptControl |= (OUTBOUNDDOORBELL_2);
+
+		break;
+
+      case AdapNormCmdNotFull:
+
+		AdapterExtension->LocalMaskInterruptControl |= (OUTBOUNDDOORBELL_3);
+
+		break;
+
+
+      case AdapNormRespNotFull:
+
+		AdapterExtension->LocalMaskInterruptControl |= (OUTBOUNDDOORBELL_4);
+
+		break;
+
+	}
+
+}
+
+
+
+RxDetachDevice(
+	IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension
+	)
+{
+	PRx_ADAPTER_EXTENSION AdapterExtension = CommonExtension->MiniPort;
+
+	//
+	// Free the register mapping.
+	//
+
+	OsDetachDevice( AdapterExtension);
+
+	OsFreeMemory( AdapterExtension, sizeof(Rx_ADAPTER_EXTENSION) );
+
+}
+
+int
+RxInitDevice(
+	IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension,
+	IN ULONG AdapterNumber,
+	IN ULONG PciBus,
+	IN ULONG PciSlot
+)
+
+/*++
+
+Routine Description:
+
+	Scans the PCI bus looking for the Rx card. When found all resources for the
+	device will be allocated and the interrupt vectors and csrs will be allocated and
+	mapped.
+
+ 	The device_interface in the commregion will be allocated and linked to the comm region.
+
+Arguments:
+
+
+Return Value:
+
+    TRUE - if the device was setup with not problems
+    FALSE - if the device could not be mapped and init successfully
+
+--*/
+
+{
+	AAC_STATUS Status;
+	PRx_ADAPTER_EXTENSION AdapterExtension = NULL;
+	FSA_NEW_ADAPTER NewAdapter;
+	ULONG StartTime, EndTime, WaitTime;
+	ULONG InitStatus;
+	int instance;
+	int nIntrs;
+	char * name;
+
+    AfaPortPrint("In init device.\n");
+
+	//cmn_err(CE_WARN, "In RxInitDevice");
+
+//	AdapterExtension->Common->AdapterIndex = AdapterIndex;
+	CommonExtension->AdapterNumber = AdapterNumber;
+
+
+	CommonExtension->PciBusNumber = PciBus;
+	CommonExtension->PciSlotNumber = PciSlot;
+
+
+	AdapterExtension = OsAllocMemory( sizeof(Rx_ADAPTER_EXTENSION), OS_ALLOC_MEM_SLEEP );
+	AdapterExtension->Common = CommonExtension;
+	CommonExtension->MiniPort = AdapterExtension;
+
+	instance = OsGetDeviceInstance(AdapterExtension);
+	name     = OsGetDeviceName(AdapterExtension);
+	//
+	// Map in the registers from the adapter, register space 0 is config space,
+	// register space 1 is the memery space.
+	//
+
+	if (OsMapDeviceRegisters(AdapterExtension)) {
+
+		cmn_err(CE_CONT, "%s%d: can't map device registers\n",
+				OsGetDeviceName(AdapterExtension), instance);
+		return(FAILURE);
+	}
+
+	//
+	// Check to see if the board failed any self tests.
+	//
+
+	if (Rx_READ_ULONG( AdapterExtension, IndexRegs.Mailbox[7]) & SELF_TEST_FAILED) {
+
+		cmn_err(CE_CONT, "%s%d: adapter self-test failed\n",
+				OsGetDeviceName(AdapterExtension), instance);
+		return(FAILURE);
+
+	}
+	//cmn_err(CE_WARN, "RxInitDevice: %s%d: adapter passwd self-test\n",
+	//			OsGetDeviceName(AdapterExtension), instance);
+
+	//
+	// Check to see if the board panic'd while booting.
+	//
+
+	if (Rx_READ_ULONG( AdapterExtension, IndexRegs.Mailbox[7]) & KERNEL_PANIC) {
+
+		cmn_err(CE_CONT, "%s%d: adapter kernel panic'd\n",
+				OsGetDeviceName(AdapterExtension), instance);
+		return(FAILURE);
+
+	}
+
+	StartTime = OsGetSeconds();
+	WaitTime = 0;
+
+
+	//
+	//  Wait for the adapter to be up and running. Wait up until 3 minutes.
+	//
+
+	while (!(Rx_READ_ULONG( AdapterExtension, IndexRegs.Mailbox[7]) & KERNEL_UP_AND_RUNNING)) {
+	
+		EndTime = OsGetSeconds();
+
+		WaitTime = EndTime - StartTime;
+
+		if ( WaitTime > (3 * 10) ) {
+
+			InitStatus = Rx_READ_ULONG( AdapterExtension, IndexRegs.Mailbox[7]) >> 16;
+
+			cmn_err(CE_CONT, "%s%d: adapter kernel failed to start, init status = %d\n",
+					OsGetDeviceName(AdapterExtension), instance, InitStatus);
+			return(FAILURE);
+
+		}
+	}
+
+	if (OsAttachInterrupt(AdapterExtension,RxISR)) {
+		cmn_err(CE_WARN, "%s%d RxInitDevice: failed OsAttachIntterupt", name, instance);
+		return(FAILURE);
+	}
+
+
+	if (OsAttachDMA(AdapterExtension)) {
+		cmn_err(CE_WARN, "%s%d SaInitDevice: failed OsAttachDMA", name, instance);
+		return(FAILURE);
+	}
+
+	//
+	// Fill in the function dispatch table.
+	//
+
+	AdapterExtension->Common->AdapterFuncs.SizeOfFsaPortFuncs = sizeof(FSAPORT_FUNCS);
+	AdapterExtension->Common->AdapterFuncs.AllocateAdapterCommArea = AfaPortAllocateAdapterCommArea;
+	AdapterExtension->Common->AdapterFuncs.FreeAdapterCommArea = AfaPortFreeAdapterCommArea;
+	AdapterExtension->Common->AdapterFuncs.BuildSgMap = AfaPortBuildSgMap;
+	AdapterExtension->Common->AdapterFuncs.FreeDmaResources = AfaPortFreeDmaResources;
+	AdapterExtension->Common->AdapterFuncs.AllocateAndMapFibSpace = AfaPortAllocateAndMapFibSpace;
+	AdapterExtension->Common->AdapterFuncs.UnmapAndFreeFibSpace = AfaPortUnmapAndFreeFibSpace;
+	AdapterExtension->Common->AdapterFuncs.InterruptAdapter = RxInterruptAdapter;
+	AdapterExtension->Common->AdapterFuncs.EnableInterrupt = RxEnableInterrupt;
+	AdapterExtension->Common->AdapterFuncs.DisableInterrupt = RxDisableInterrupt;
+	AdapterExtension->Common->AdapterFuncs.NotifyAdapter = RxNotifyAdapter;
+	AdapterExtension->Common->AdapterFuncs.ResetDevice = RxResetDevice;
+	AdapterExtension->Common->AdapterFuncs.InterruptHost = NULL;
+
+	AdapterExtension->Common->AdapterFuncs.SendSynchFib = RxSendSynchFib;
+
+	NewAdapter.AdapterExtension = CommonExtension;
+	NewAdapter.AdapterFuncs = &AdapterExtension->Common->AdapterFuncs;
+	NewAdapter.AdapterInterruptsBelowDpc = FALSE;
+	NewAdapter.AdapterUserVars = RxUserVars;
+	NewAdapter.AdapterUserVarsSize = sizeof(RxUserVars) / sizeof(FSA_USER_VAR);
+
+	NewAdapter.Dip = CommonExtension->OsDep.dip;
+
+	
+	if (AfaCommInitNewAdapter( &NewAdapter ) == NULL) {
+		
+		cmn_err(CE_WARN, "AfaCommInitNewAdapter failed\n");
+		return (FAILURE);
+	}
+
+
+	AdapterExtension->Common->Adapter = NewAdapter.Adapter;
+
+	if (AdapterExtension->Common->Adapter == NULL) {
+
+		AfaPortLogError(AdapterExtension->Common, FAILURE, NULL, 0);
+		cmn_err(CE_WARN, "%s%d RxInitDevice: No Adapter pointer", name, instance);
+
+
+		return (FAILURE);
+	}
+
+
+	//
+	// Start any kernel threads needed
+	//
+	OsStartKernelThreads(AdapterExtension);
+
+	//
+	// Tell the adapter that all is configure, and it can start accepting requests
+	//
+
+	RxStartAdapter(AdapterExtension);
+
+
+#ifdef AACDISK
+#endif
+
+
+	//
+	// Put this adapter into the list of Rx adapters
+	//
+
+	AdapterExtension->Next = RxAdapterList;
+	RxAdapterList = AdapterExtension;
+
+	AdapterExtension->Common->AdapterConfigured = TRUE;
+
+
+#ifdef AACDISK
+	//
+	// Call the disk layer to initialize itself.
+	//
+
+	AfaDiskInitNewAdapter( AdapterExtension->Common->AdapterNumber, AdapterExtension->Common->Adapter );
+#endif
+
+
+init_done:
+
+	AdapterExtension->Common->AdapterPrintfsToScreen = FALSE;
+
+
+
+	OsAttachHBA(AdapterExtension);
+
+    return(0);
+}
+
+VOID
+RxStartAdapter(
+	PRx_ADAPTER_EXTENSION AdapterExtension
+	)
+{
+	ULONG ReturnStatus;
+	LARGE_INTEGER HostTime;
+	ULONG ElapsedSeconds;
+	PADAPTER_INIT_STRUCT InitStruct;
+
+	//cmn_err(CE_WARN, "RxStartAdapter");
+	//
+	// Fill in the remaining pieces of the InitStruct.
+	//
+
+	InitStruct = AdapterExtension->Common->InitStruct;
+
+	InitStruct->HostPhysMemPages = AfaPortGetMaxPhysicalPage(AdapterExtension->Common);
+
+	ElapsedSeconds = OsGetSeconds();
+
+	InitStruct->HostElapsedSeconds = ElapsedSeconds;
+
+	//
+	// Tell the adapter we are back and up and running so it will scan its command
+	// queues and enable our interrupts
+	//
+
+	AdapterExtension->LocalMaskInterruptControl =
+		(DoorBellPrintfReady | OUTBOUNDDOORBELL_1 | OUTBOUNDDOORBELL_2 | OUTBOUNDDOORBELL_3 | OUTBOUNDDOORBELL_4);
+
+	//
+	// First clear out all interrupts.  Then enable the one's that we can handle.
+	//
+
+	Rx_WRITE_UCHAR( AdapterExtension, MUnit.OIMR, 0xff);
+	Rx_WRITE_ULONG( AdapterExtension, MUnit.ODR, 0xffffffff);
+//	Rx_WRITE_UCHAR(AdapterExtension, MUnit.OIMR, ~(UCHAR)OUTBOUND_DOORBELL_INTERRUPT_MASK);
+	Rx_WRITE_UCHAR( AdapterExtension, MUnit.OIMR, 0xfb);
+
+	RxSendSynchCommand(AdapterExtension, 
+	 				 INIT_STRUCT_BASE_ADDRESS, 
+	 				 (ULONG) AdapterExtension->Common->PhysicalInitStruct,
+					 0,
+					 0,
+					 0,
+					 &ReturnStatus);
+
+}
+
+
+VOID
+RxResetDevice(
+	PVOID Arg1
+    )
+
+{
+}
+
+VOID
+RxInterruptAdapter(
+	PVOID Arg1
+	)
+/*++
+
+Routine Description:
+
+	The will cause the adapter to take a break point.
+
+Arguments:
+
+	None
+
+Return Value:
+
+    Nothing
+
+--*/
+{
+	PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
+	PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) CommonExtension->MiniPort;
+
+	ULONG ReturnStatus;
+
+	RxSendSynchCommand(AdapterExtension, 
+					   BREAKPOINT_REQUEST,
+					   0,
+					   0,
+					   0,
+					   0,
+					   &ReturnStatus);
+
+}
+
+VOID
+RxNotifyAdapter(
+	PVOID Arg1,
+    IN HOST_2_ADAP_EVENT AdapterEvent
+    )
+/*++
+
+Routine Description:
+
+    Will read the adapter CSRs to find the reason the adapter has
+    interrupted us.
+
+Arguments:
+
+    AdapterEvent - Enumerated type the returns the reason why we were interrutped.
+
+Return Value:
+
+    Nothing
+
+--*/
+{
+	PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
+	PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) CommonExtension->MiniPort;
+	ULONG ReturnStatus;
+
+	//cmn_err(CE_WARN, "RxNotifyAdapter %d", AdapterEvent);
+
+    switch (AdapterEvent) {
+        case AdapNormCmdQue:
+
+			Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_1);
+            break;
+
+        case HostNormRespNotFull:
+
+			Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_4);
+            break;
+
+        case AdapNormRespQue:
+
+			Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_2);
+            break;
+
+        case HostNormCmdNotFull:
+
+			Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_3);
+            break;
+
+        case HostShutdown:
+
+//			RxSendSynchCommand(AdapterExtension, HOST_CRASHING, 0, 0, 0, 0, &ReturnStatus);
+
+            break;
+
+		case FastIo:
+			Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_6);
+			break;
+
+		case AdapPrintfDone:
+			Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_5);
+			break;
+
+        default:
+
+			RxBugCheck(0,0,0);
+            AfaPortPrint("Notify requested with an invalid request 0x%x.\n",AdapterEvent);
+            break;
+    }
+}
+
+AAC_STATUS
+RxSendSynchCommand(
+	PVOID Arg1,
+	ULONG Command,
+	ULONG Parameter1,
+	ULONG Parameter2,
+	ULONG Parameter3,
+	ULONG Parameter4,
+	PULONG	ReturnStatus
+	)
+/*++
+
+Routine Description:
+
+	This routine will send a synchronous comamnd to the adapter and wait for its
+	completion.
+
+Arguments:
+
+	AdapterExtension - Pointer to adapter extension structure.
+	Command - Which command to send
+	Parameter1 - 4	- Parameters for command
+	ReturnStatus - return status from adapter after completion of command
+
+
+Return Value:
+
+	AAC_STATUS
+
+--*/
+{
+	PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) Arg1;
+	ULONG StartTime,EndTime,WaitTime;
+	BOOLEAN CommandSucceeded;
+
+	//cmn_err(CE_WARN, "RxSendSyncCommand");
+	//
+	// Write the Command into Mailbox 0
+	//
+
+	Rx_WRITE_ULONG( AdapterExtension, InboundMailbox0, Command);
+
+	//
+	// Write the parameters into Mailboxes 1 - 4
+	//
+
+	Rx_WRITE_ULONG( AdapterExtension, InboundMailbox1, Parameter1);
+	Rx_WRITE_ULONG( AdapterExtension, InboundMailbox2, Parameter2);
+	Rx_WRITE_ULONG( AdapterExtension, InboundMailbox3, Parameter3);
+	Rx_WRITE_ULONG( AdapterExtension, InboundMailbox4, Parameter4);
+
+	//
+	// Clear the synch command doorbell to start on a clean slate.
+	//
+		
+	Rx_WRITE_ULONG( AdapterExtension, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
+
+	//
+	// disable doorbell interrupts
+	//
+
+	Rx_WRITE_UCHAR( AdapterExtension, MUnit.OIMR, 
+					Rx_READ_UCHAR(AdapterExtension, MUnit.OIMR) | 0x04);
+
+	//
+	// force the completion of the mask register write before issuing the interrupt.
+	//
+
+	Rx_READ_UCHAR ( AdapterExtension, MUnit.OIMR);
+
+	//
+	// Signal that there is a new synch command
+	//
+
+	Rx_WRITE_ULONG( AdapterExtension, InboundDoorbellReg, INBOUNDDOORBELL_0);
+
+	CommandSucceeded = FALSE;
+
+	StartTime = OsGetSeconds();
+	WaitTime = 0;
+
+	while (WaitTime < 30) { // wait up to 30 seconds
+
+		drv_usecwait(5);				// delay 5 microseconds to let Mon960 get info.
+
+		//
+		// Mon110 will set doorbell0 bit when it has completed the command.
+		//
+
+		if (Rx_READ_ULONG(AdapterExtension, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) {
+
+			//
+			// clear the doorbell.
+			//
+
+			Rx_WRITE_ULONG(AdapterExtension, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
+
+			CommandSucceeded = TRUE;
+			break;
+		}
+
+		EndTime = OsGetSeconds();
+		WaitTime = EndTime - StartTime;
+
+	}
+
+	if (CommandSucceeded != TRUE) {
+
+		//
+		// restore interrupt mask even though we timed out
+		//
+
+		Rx_WRITE_UCHAR(AdapterExtension, MUnit.OIMR, 
+			 		   Rx_READ_ULONG(AdapterExtension, MUnit.OIMR) & 0xfb);
+
+		return (STATUS_IO_TIMEOUT);
+
+	}
+
+	//
+	// Pull the synch status from Mailbox 0.
+	//
+
+	*ReturnStatus = Rx_READ_ULONG(AdapterExtension, IndexRegs.Mailbox[0]);
+
+	//
+	// Clear the synch command doorbell.
+	//
+		
+	Rx_WRITE_ULONG(AdapterExtension, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
+
+	//
+	// restore interrupt mask
+	//
+
+	Rx_WRITE_UCHAR(AdapterExtension, MUnit.OIMR, 
+		 		   Rx_READ_ULONG(AdapterExtension, MUnit.OIMR) & 0xfb);
+
+	//
+	// Return SUCCESS
+	//
+
+	return (STATUS_SUCCESS);
+
+}
+
+BOOLEAN
+RxSendSynchFib(
+	PVOID Arg1,
+	ULONG FibPhysicalAddress
+	)
+/*++
+
+Routine Description:
+
+	This routine will send a synchronous fib to the adapter and wait for its
+	completion.
+
+Arguments:
+
+	AdapterExtension - Pointer to adapter extension structure.
+	FibPhysicalAddress - Physical address of fib to send.
+
+
+Return Value:
+
+	BOOLEAN
+
+--*/
+{
+	PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
+	PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) CommonExtension->MiniPort;
+	ULONG returnStatus;
+
+	if (RxSendSynchCommand( AdapterExtension,
+						    SEND_SYNCHRONOUS_FIB,
+						    FibPhysicalAddress,
+						    0,
+						    0,
+						    0,
+						    &returnStatus ) != STATUS_SUCCESS ) {
+
+		return (FALSE);
+		
+	}
+	
+	return (TRUE);
+										
+}
+
+
diff -BburN linux.orig/drivers/scsi/aacraid/sap1sup.c linux/drivers/scsi/aacraid/sap1sup.c
--- linux.orig/drivers/scsi/aacraid/sap1sup.c	Wed Dec 31 18:00:00 1969
+++ linux/drivers/scsi/aacraid/sap1sup.c	Fri Feb  9 15:27:46 2001
@@ -0,0 +1,862 @@
+/*++
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  sap1sup.c
+ *
+ * Abstract: Drawbridge specific support functions
+ *
+ --*/
+
+#include "osheaders.h"
+
+
+#include "AacGenericTypes.h"
+
+#include "aac_unix_defs.h"
+
+#include "fsatypes.h"
+#include "comstruc.h"
+#include "fsact.h"
+#include "protocol.h"
+
+#define DEFINE_PCI_IDS
+#include "sap1common.h"
+#include "monkerapi.h"
+
+#include "fsaport.h"
+#include "fsaioctl.h"
+
+
+#include "pcisup.h"
+#include "sap1.h"
+
+#include "port.h"
+
+#include "nodetype.h"
+#include "comsup.h"
+#include "afacomm.h"
+#include "adapter.h"
+
+#define BugCheckFileId                   (FSAFS_BUG_CHECK_CYCLONESUP)
+
+// #define SaBugCheck(A,B,C) { KeBugCheckEx(0x00000AFA, __LINE__, (ULONG)A, (ULONG)B,(ULONG)C ); }
+
+#define SaBugCheck(A, B, C) {	cmn_err(CE_PANIC, "aacdisk : line %s, 0x%x, 0x%x, 0x%x ", __LINE__, A, B, C);  }
+
+#define NUM_TICKS_PER_SECOND (1000 * 1000 * 10) /* time is in 100 nanoseconds */
+
+int MiniPortRevision = Sa_MINIPORT_REVISION;
+
+
+//
+// The list of all the Sa adapter structures
+//
+
+PSa_ADAPTER_EXTENSION	SaAdapterList;
+
+int
+SaInitDevice(
+	IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension,
+	IN ULONG AdapterNumber,
+	IN ULONG PciBus,
+	IN ULONG PciSlot
+);
+
+BOOLEAN
+SaSendSynchFib(
+	PVOID Arg1,
+	ULONG FibPhysicalAddress
+	);
+
+FSA_USER_VAR	SaUserVars[] = {
+	{ "AfaPortPrinting", (PULONG)&AfaPortPrinting, NULL },
+};
+
+
+//
+// Declare private use routines for this modual
+//
+
+u_int
+SaPciIsr (
+    IN PSa_ADAPTER_EXTENSION AdapterExtension
+    )
+
+/*++
+
+Routine Description:
+
+    The Isr routine for fsa Sa based adapter boards.
+
+Arguments:
+
+
+Return Value:
+
+	TRUE - if the interrupt was handled by this isr
+	FALSE - if the interrupt was not handled by this isr
+
+--*/
+
+{
+	USHORT InterruptStatus, Mask;
+	u_int OurInterrupt = INTR_UNCLAIMED;
+
+//	cmn_err(CE_WARN, "SaPciIsr entered\n");
+
+	InterruptStatus = Sa_READ_USHORT( AdapterExtension, DoorbellReg_p);
+
+	//
+	// Read mask and invert because drawbridge is reversed.
+	//
+	// This allows us to only service interrupts that have been enabled.
+	//
+
+	Mask = ~(Sa_READ_USHORT( AdapterExtension, SaDbCSR.PRISETIRQMASK));
+
+	// Check to see if this is our interrupt.  If it isn't just return FALSE.
+
+
+	if (InterruptStatus & Mask) {
+
+		OurInterrupt = INTR_CLAIMED;
+
+		if (InterruptStatus & PrintfReady) {
+
+
+			cmn_err(CE_WARN, "%s:%s", OsGetDeviceName(AdapterExtension), AdapterExtension->Common->PrintfBufferAddress);
+
+			Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p,PrintfReady); //clear PrintfReady
+
+			Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,PrintfDone);
+
+		} else if (InterruptStatus & DOORBELL_1) {	// Adapter -> Host Normal Command Ready
+
+			AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, HostNormCmdQue);
+			Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p, DOORBELL_1);
+
+		} else if (InterruptStatus & DOORBELL_2) {	// Adapter -> Host Normal Response Ready
+
+			AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, HostNormRespQue);
+			Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p,DOORBELL_2);
+
+		} else if (InterruptStatus & DOORBELL_3) {	// Adapter -> Host Normal Command Not Full
+
+			AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, AdapNormCmdNotFull);
+			Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p, DOORBELL_3);
+
+		} else if (InterruptStatus & DOORBELL_4) {	// Adapter -> Host Normal Response Not Full
+
+			AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, AdapNormRespNotFull);
+			Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p, DOORBELL_4);
+
+		}
+
+	}
+	return(OurInterrupt);
+}
+
+VOID
+SaEnableInterrupt(
+	PVOID						Arg1,
+	ADAPTER_EVENT				AdapterEvent,
+	BOOLEAN						AtDeviceIrq
+	)
+/*++
+
+Routine Description:
+
+	This routine will enable the corresponding adapter event to cause an interrupt on 
+	the host.
+
+Arguments:
+
+	AdapterExtension - Which adapter to enable.
+
+	AdapterEvent - Which adapter event.
+
+	AtDeviceIrq - Whether the system is in DEVICE irql
+
+Return Value:
+
+    Nothing.
+
+--*/
+{
+	PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
+	PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) CommonExtension->MiniPort;
+
+	switch (AdapterEvent) {
+
+	  case HostNormCmdQue:
+
+		Sa_WRITE_USHORT( AdapterExtension,  SaDbCSR.PRICLEARIRQMASK, DOORBELL_1 );
+
+		break;
+
+	  case HostNormRespQue:
+
+		Sa_WRITE_USHORT( AdapterExtension,  SaDbCSR.PRICLEARIRQMASK, DOORBELL_2 );
+
+		break;
+
+      case AdapNormCmdNotFull:
+
+		Sa_WRITE_USHORT( AdapterExtension,  SaDbCSR.PRICLEARIRQMASK, DOORBELL_3 );
+
+		break;
+
+      case AdapNormRespNotFull:
+
+		Sa_WRITE_USHORT( AdapterExtension,  SaDbCSR.PRICLEARIRQMASK, DOORBELL_4 );
+
+		break;
+
+	}
+
+}
+
+VOID
+SaDisableInterrupt(
+	PVOID						Arg1,
+	ADAPTER_EVENT				AdapterEvent,
+	BOOLEAN						AtDeviceIrq
+	)
+/*++
+
+Routine Description:
+
+	This routine will disable the corresponding adapter event to cause an interrupt on 
+	the host.
+
+Arguments:
+
+	AdapterExtension - Which adapter to enable.
+
+	AdapterEvent - Which adapter event.
+
+	AtDeviceIrq - Whether the system is in DEVICE irql
+
+Return Value:
+
+    Nothing.
+
+--*/
+{
+	PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
+	PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) CommonExtension->MiniPort;
+
+	switch (AdapterEvent) {
+
+
+	  case HostNormCmdQue:
+
+		Sa_WRITE_USHORT( AdapterExtension,  SaDbCSR.PRISETIRQMASK, DOORBELL_1 );
+
+		break;
+
+	  case HostNormRespQue:
+
+		Sa_WRITE_USHORT( AdapterExtension,  SaDbCSR.PRISETIRQMASK, DOORBELL_2 );
+
+		break;
+
+      case AdapNormCmdNotFull:
+
+		Sa_WRITE_USHORT( AdapterExtension,  SaDbCSR.PRISETIRQMASK, DOORBELL_3 );
+
+		break;
+
+
+      case AdapNormRespNotFull:
+
+		Sa_WRITE_USHORT( AdapterExtension,  SaDbCSR.PRISETIRQMASK, DOORBELL_4 );
+
+		break;
+
+	}
+
+}
+
+SaDetachDevice(
+	IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension
+	)
+{
+	PSa_ADAPTER_EXTENSION AdapterExtension = CommonExtension->MiniPort;
+
+	//
+	// Free the register mapping.
+	//
+
+	OsDetachDevice(AdapterExtension);
+
+	OsFreeMemory( AdapterExtension, sizeof(Sa_ADAPTER_EXTENSION) );
+
+}
+
+int
+SaInitDevice(
+	IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension,
+	IN ULONG AdapterNumber,
+	IN ULONG PciBus,
+	IN ULONG PciSlot
+)
+
+/*++
+
+Routine Description:
+
+	Scans the PCI bus looking for the Sa card. When found all resources for the
+	device will be allocated and the interrupt vectors and csrs will be allocated and
+	mapped.
+
+ 	The device_interface in the commregion will be allocated and linked to the comm region.
+
+Arguments:
+
+
+Return Value:
+
+    TRUE - if the device was setup with not problems
+    FALSE - if the device could not be mapped and init successfully
+
+--*/
+
+{
+	AAC_STATUS Status;
+	PSa_ADAPTER_EXTENSION AdapterExtension = NULL;
+	FSA_NEW_ADAPTER NewAdapter;
+	ULONG StartTime, EndTime, WaitTime;
+	ULONG InitStatus;
+	int instance;
+	char *name;
+
+    AfaPortPrint("In init device.\n");
+
+//	cmn_err(CE_NOTE, "SaInitDevice ");
+
+//	AdapterExtension->Common->AdapterIndex = AdapterIndex;
+	CommonExtension->AdapterNumber = AdapterNumber;
+
+
+	CommonExtension->PciBusNumber = PciBus;
+	CommonExtension->PciSlotNumber = PciSlot;
+
+
+	AdapterExtension = OsAllocMemory( sizeof(Sa_ADAPTER_EXTENSION), OS_ALLOC_MEM_SLEEP );
+	AdapterExtension->Common = CommonExtension;
+	CommonExtension->MiniPort = AdapterExtension;
+
+	instance = OsGetDeviceInstance(AdapterExtension);
+	name     = OsGetDeviceName(AdapterExtension);
+
+	//
+	// Map in the registers from the adapter, register space 0 is config space,
+	// register space 1 is the memery space.
+	//
+
+	if (OsMapDeviceRegisters(AdapterExtension)){
+		cmn_err(CE_WARN, "%s%d SaInitDevice: failed OsMapDeviceRegisters", name, instance);
+		return(FAILURE);
+	}
+
+
+	//
+	// Check to see if the board failed any self tests.
+	//
+
+	if (Sa_READ_ULONG( AdapterExtension, Mailbox7) & SELF_TEST_FAILED) {
+
+		cmn_err(CE_WARN, "%s%d: adapter self-test failed\n",
+				name, instance);
+		return(FAILURE);
+	}
+
+	//
+	// Check to see if the board panic'd while booting.
+	//
+
+	if (Sa_READ_ULONG( AdapterExtension, Mailbox7) & KERNEL_PANIC) {
+
+		cmn_err(CE_WARN, "%s%d: adapter kernel panic'd\n",
+				name, instance);
+		return(FAILURE);
+	}
+
+
+	StartTime = OsGetSeconds();
+	WaitTime = 0;
+
+
+	//
+	//  Wait for the adapter to be up and running. Wait up until 3 minutes.
+	//
+
+	while (!(Sa_READ_ULONG( AdapterExtension, Mailbox7) & KERNEL_UP_AND_RUNNING)) {
+	
+		EndTime = OsGetSeconds();
+
+		WaitTime = EndTime - StartTime;
+
+		if ( WaitTime > (3 * 60) ) {
+
+			InitStatus = Sa_READ_ULONG( AdapterExtension, Mailbox7) >> 16;
+
+			cmn_err(CE_WARN, "%s%d: adapter kernel failed to start, init status = %d\n",
+					name, instance, InitStatus);
+			return(FAILURE);
+
+		}
+	}
+
+	if (OsAttachInterrupt(AdapterExtension, SaISR)) {
+		cmn_err(CE_WARN, "%s%d SaInitDevice: failed OsAttachIntterupt", name, instance);
+		return(FAILURE);
+	}
+
+	if (OsAttachDMA(AdapterExtension)) {
+		cmn_err(CE_WARN, "%s%d SaInitDevice: failed OsAttachDMA", name, instance);
+		return(FAILURE);
+	}
+
+
+	//
+	// Fill in the function dispatch table.
+	//
+
+	AdapterExtension->Common->AdapterFuncs.SizeOfFsaPortFuncs = sizeof(FSAPORT_FUNCS);
+	AdapterExtension->Common->AdapterFuncs.AllocateAdapterCommArea = AfaPortAllocateAdapterCommArea;
+	AdapterExtension->Common->AdapterFuncs.FreeAdapterCommArea = AfaPortFreeAdapterCommArea;
+	AdapterExtension->Common->AdapterFuncs.BuildSgMap = AfaPortBuildSgMap;
+	AdapterExtension->Common->AdapterFuncs.FreeDmaResources = AfaPortFreeDmaResources;
+	AdapterExtension->Common->AdapterFuncs.AllocateAndMapFibSpace = AfaPortAllocateAndMapFibSpace;
+	AdapterExtension->Common->AdapterFuncs.UnmapAndFreeFibSpace = AfaPortUnmapAndFreeFibSpace;
+	AdapterExtension->Common->AdapterFuncs.InterruptAdapter = SaInterruptAdapter;
+	AdapterExtension->Common->AdapterFuncs.EnableInterrupt = SaEnableInterrupt;
+	AdapterExtension->Common->AdapterFuncs.DisableInterrupt = SaDisableInterrupt;
+	AdapterExtension->Common->AdapterFuncs.NotifyAdapter = SaNotifyAdapter;
+	AdapterExtension->Common->AdapterFuncs.ResetDevice = SaResetDevice;
+	AdapterExtension->Common->AdapterFuncs.InterruptHost = NULL;
+
+	AdapterExtension->Common->AdapterFuncs.SendSynchFib = SaSendSynchFib;
+
+	NewAdapter.AdapterExtension = CommonExtension;
+	NewAdapter.AdapterFuncs = &AdapterExtension->Common->AdapterFuncs;
+	NewAdapter.AdapterInterruptsBelowDpc = FALSE;
+	NewAdapter.AdapterUserVars = SaUserVars;
+	NewAdapter.AdapterUserVarsSize = sizeof(SaUserVars) / sizeof(FSA_USER_VAR);
+
+	NewAdapter.Dip = CommonExtension->OsDep.dip;
+
+	
+	if ( AfaCommInitNewAdapter( &NewAdapter ) == NULL) {
+			cmn_err(CE_WARN, "SaInitDevice: AfaCommInitNewAdapter failed\n");
+			return (FAILURE);
+	};
+
+
+	AdapterExtension->Common->Adapter = NewAdapter.Adapter;
+
+	if (AdapterExtension->Common->Adapter == NULL) {
+
+		AfaPortLogError(AdapterExtension->Common, FAILURE, NULL, 0);
+		cmn_err(CE_WARN, "%s%d SaInitDevice: No Adapter pointer", name, instance);
+
+		return (FAILURE); 
+	}
+
+
+    //
+	// Start any kernel threads needed
+	OsStartKernelThreads(AdapterExtension);
+	//
+	// Tell the adapter that all is configure, and it can start accepting requests
+	//
+
+	SaStartAdapter(AdapterExtension);
+
+
+
+	//
+	// Put this adapter into the list of Sa adapters
+	//
+
+	AdapterExtension->Next = SaAdapterList;
+	SaAdapterList = AdapterExtension;
+
+	AdapterExtension->Common->AdapterConfigured = TRUE;
+
+
+#ifdef AACDISK
+	//
+	// Call the disk layer to initialize itself.
+	//
+
+	AfaDiskInitNewAdapter( AdapterExtension->Common->AdapterNumber, AdapterExtension->Common->Adapter );
+#endif
+
+
+init_done:
+
+	AdapterExtension->Common->AdapterPrintfsToScreen = FALSE;
+
+	OsAttachHBA(AdapterExtension);
+
+	return (0);
+
+init_error:
+
+	return (FAILURE);
+}
+
+VOID
+SaStartAdapter(
+	PSa_ADAPTER_EXTENSION AdapterExtension
+	)
+{
+	ULONG ReturnStatus;
+	LARGE_INTEGER HostTime;
+	ULONG ElapsedSeconds;
+	PADAPTER_INIT_STRUCT InitStruct;
+
+	//
+	// Fill in the remaining pieces of the InitStruct.
+	//
+
+	InitStruct = AdapterExtension->Common->InitStruct;
+
+	InitStruct->HostPhysMemPages = AfaPortGetMaxPhysicalPage(AdapterExtension->Common);
+
+	ElapsedSeconds = OsGetSeconds();
+
+	InitStruct->HostElapsedSeconds = ElapsedSeconds;
+
+	//
+	// Tell the adapter we are back and up and running so it will scan its command
+	// queues and enable our interrupts
+	//
+
+	AdapterExtension->LocalMaskInterruptControl =
+		(PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4);
+
+
+	//
+	// First clear out all interrupts.  Then enable the one's that we can handle.
+	//
+
+	Sa_WRITE_USHORT( AdapterExtension,  SaDbCSR.PRISETIRQMASK, (USHORT) 0xffff );
+	Sa_WRITE_USHORT( AdapterExtension,  SaDbCSR.PRICLEARIRQMASK,
+					(PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4) );
+
+	SaSendSynchCommand(AdapterExtension, 
+	 				 INIT_STRUCT_BASE_ADDRESS, 
+	 				 (ULONG) AdapterExtension->Common->PhysicalInitStruct,
+					 0,
+					 0,
+					 0,
+					 &ReturnStatus);
+
+}
+
+
+VOID
+SaResetDevice(
+	PVOID Arg1
+    )
+
+{
+}
+
+VOID
+SaInterruptAdapter(
+	PVOID Arg1
+	)
+/*++
+
+Routine Description:
+
+	The will cause the adapter to take a break point.
+
+Arguments:
+
+	None
+
+Return Value:
+
+    Nothing
+
+--*/
+{
+	PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
+	PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) CommonExtension->MiniPort;
+
+	ULONG ReturnStatus;
+
+	SaSendSynchCommand(AdapterExtension, 
+					   BREAKPOINT_REQUEST,
+					   0,
+					   0,
+					   0,
+					   0,
+					   &ReturnStatus);
+
+}
+
+VOID
+SaNotifyAdapter(
+	PVOID Arg1,
+    IN HOST_2_ADAP_EVENT AdapterEvent
+    )
+/*++
+
+Routine Description:
+
+    Will read the adapter CSRs to find the reason the adapter has
+    interrupted us.
+
+Arguments:
+
+    AdapterEvent - Enumerated type the returns the reason why we were interrutped.
+
+Return Value:
+
+    Nothing
+
+--*/
+{
+	PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
+	PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) CommonExtension->MiniPort;
+	ULONG ReturnStatus;
+
+    switch (AdapterEvent) {
+        case AdapNormCmdQue:
+
+			Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_1);
+            break;
+
+        case HostNormRespNotFull:
+
+			Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_4);
+            break;
+
+        case AdapNormRespQue:
+
+			Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_2);
+            break;
+
+        case HostNormCmdNotFull:
+
+			Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_3);
+            break;
+
+        case HostShutdown:
+
+//			SaSendSynchCommand(AdapterExtension, HOST_CRASHING, 0, 0, 0, 0, &ReturnStatus);
+
+            break;
+
+		case FastIo:
+			Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_6);
+			break;
+
+		case AdapPrintfDone:
+			Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_5);
+			break;
+
+        default:
+
+			SaBugCheck(0,0,0);
+            AfaPortPrint("Notify requested with an invalid request 0x%x.\n",AdapterEvent);
+            break;
+    }
+}
+
+AAC_STATUS
+SaSendSynchCommand(
+	PVOID Arg1,
+	ULONG Command,
+	ULONG Parameter1,
+	ULONG Parameter2,
+	ULONG Parameter3,
+	ULONG Parameter4,
+	PULONG	ReturnStatus
+	)
+/*++
+
+Routine Description:
+
+	This routine will send a synchronous comamnd to the adapter and wait for its
+	completion.
+
+Arguments:
+
+	AdapterExtension - Pointer to adapter extension structure.
+	Command - Which command to send
+	Parameter1 - 4	- Parameters for command
+	ReturnStatus - return status from adapter after completion of command
+
+
+Return Value:
+
+	AAC_STATUS
+
+--*/
+{
+	PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) Arg1;
+	ULONG StartTime,EndTime,WaitTime;
+	BOOLEAN CommandSucceeded;
+
+	//
+	// Write the Command into Mailbox 0
+	//
+
+	Sa_WRITE_ULONG( AdapterExtension, Mailbox0, Command);
+
+	//
+	// Write the parameters into Mailboxes 1 - 4
+	//
+
+	Sa_WRITE_ULONG( AdapterExtension, Mailbox1, Parameter1);
+	Sa_WRITE_ULONG( AdapterExtension, Mailbox2, Parameter2);
+	Sa_WRITE_ULONG( AdapterExtension, Mailbox3, Parameter3);
+	Sa_WRITE_ULONG( AdapterExtension, Mailbox4, Parameter4);
+
+	//
+	// Clear the synch command doorbell to start on a clean slate.
+	//
+		
+	Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p, DOORBELL_0);
+
+	//
+	// Signal that there is a new synch command
+	//
+
+	Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s, DOORBELL_0);
+
+	CommandSucceeded = FALSE;
+
+	StartTime = OsGetSeconds();
+	WaitTime = 0;
+
+	while (WaitTime < 30) { // wait up to 30 seconds
+
+		drv_usecwait(5);				// delay 5 microseconds to let Mon960 get info.
+
+		//
+		// Mon110 will set doorbell0 bit when it has completed the command.
+		//
+
+		if( Sa_READ_USHORT( AdapterExtension, DoorbellReg_p) & DOORBELL_0 )  {
+
+			CommandSucceeded = TRUE;
+			break;
+		}
+
+		EndTime = OsGetSeconds();
+		WaitTime = EndTime - StartTime;
+
+	}
+
+	if (CommandSucceeded != TRUE) {
+
+		return (STATUS_IO_TIMEOUT);
+
+	}
+
+	//
+	// Clear the synch command doorbell.
+	//
+		
+	Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p, DOORBELL_0);
+
+	//
+	// Pull the synch status from Mailbox 0.
+	//
+
+	*ReturnStatus = Sa_READ_ULONG( AdapterExtension, Mailbox0);
+
+	//
+	// Return SUCCESS
+	//
+
+	return (STATUS_SUCCESS);
+
+}
+
+BOOLEAN
+SaSendSynchFib(
+	PVOID Arg1,
+	ULONG FibPhysicalAddress
+	)
+/*++
+
+Routine Description:
+
+	This routine will send a synchronous fib to the adapter and wait for its
+	completion.
+
+Arguments:
+
+	AdapterExtension - Pointer to adapter extension structure.
+	FibPhysicalAddress - Physical address of fib to send.
+
+
+Return Value:
+
+	BOOLEAN
+
+--*/
+{
+	PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
+	PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) CommonExtension->MiniPort;
+	ULONG returnStatus;
+
+	if (SaSendSynchCommand( AdapterExtension,
+						    SEND_SYNCHRONOUS_FIB,
+						    FibPhysicalAddress,
+						    0,
+						    0,
+						    0,
+						    &returnStatus ) != STATUS_SUCCESS ) {
+
+		return (FALSE);
+		
+	}
+	
+	return (TRUE);
+										
+}
+
+BOOLEAN
+WriteFlash(
+	PVOID AdapterExtension,
+	ULONG *MappedBuffer)
+{
+	return (FALSE);
+}
+
+BOOLEAN
+ReadFlash(
+	PVOID AdapterExtension,
+	ULONG *MappedBuffer)
+{
+	return (FALSE);
+}
+
