Index: linux-2.4.1/Makefile
diff -u linux-2.4.1/Makefile:1.1.1.1 linux-2.4.1/Makefile:1.3
--- linux-2.4.1/Makefile:1.1.1.1	Sun Feb 11 19:15:33 2001
+++ linux-2.4.1/Makefile	Mon Feb 12 16:58:33 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 1
-EXTRAVERSION =
+EXTRAVERSION =aac
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
Index: linux-2.4.1/arch/i386/defconfig
diff -u linux-2.4.1/arch/i386/defconfig:1.1.1.1 linux-2.4.1/arch/i386/defconfig:1.2
--- linux-2.4.1/arch/i386/defconfig:1.1.1.1	Sun Feb 11 19:15:46 2001
+++ linux-2.4.1/arch/i386/defconfig	Sun Feb 11 19:20:59 2001
@@ -274,6 +274,7 @@
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
Index: linux-2.4.1/drivers/scsi/Config.in
diff -u linux-2.4.1/drivers/scsi/Config.in:1.1.1.1 linux-2.4.1/drivers/scsi/Config.in:1.3
--- linux-2.4.1/drivers/scsi/Config.in:1.1.1.1	Sun Feb 11 19:15:41 2001
+++ linux-2.4.1/drivers/scsi/Config.in	Sun Feb 11 20:17:42 2001
@@ -50,6 +50,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 AACRAID 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
Index: linux-2.4.1/drivers/scsi/Makefile
diff -u linux-2.4.1/drivers/scsi/Makefile:1.1.1.1 linux-2.4.1/drivers/scsi/Makefile:1.2
--- linux-2.4.1/drivers/scsi/Makefile:1.1.1.1	Sun Feb 11 19:15:41 2001
+++ linux-2.4.1/drivers/scsi/Makefile	Sun Feb 11 19:21:05 2001
@@ -63,6 +63,7 @@
 obj-$(CONFIG_SCSI_AHA152X)	+= aha152x.o
 obj-$(CONFIG_SCSI_AHA1542)	+= aha1542.o
 obj-$(CONFIG_SCSI_AHA1740)	+= aha1740.o
+obj-$(CONFIG_SCSI_AACRAID)	+= aacraid.o
 obj-$(CONFIG_SCSI_AIC7XXX)	+= aic7xxx.o
 obj-$(CONFIG_SCSI_IPS)		+= ips.o
 obj-$(CONFIG_SCSI_FD_MCS)	+= fd_mcs.o
@@ -179,3 +180,7 @@
 sim710_u.h: sim710_d.h
 
 sim710.o : sim710_d.h
+
+aacraid.o:
+	cd aacraid; make
+
Index: linux-2.4.1/drivers/scsi/aacraid/Makefile
diff -u /dev/null linux-2.4.1/drivers/scsi/aacraid/Makefile:1.2
--- /dev/null	Tue Feb 13 10:55:24 2001
+++ linux-2.4.1/drivers/scsi/aacraid/Makefile	Mon Feb 12 16:58:42 2001
@@ -0,0 +1,169 @@
+#
+# 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..
+
+WARNINGS= -w -Wall -Wno-unused -Wno-switch -Wno-missing-prototypes -Wno-implicit
+
+
+COMMON_FLAGS=\
+	-D__KERNEL__=1 -DUNIX -DCVLOCK_USE_SPINLOCK -DLINUX \
+	${INCS} \
+	${WARNINGS}
+
+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
+
+
Index: linux-2.4.1/drivers/scsi/aacraid/README
diff -u /dev/null linux-2.4.1/drivers/scsi/aacraid/README:1.2
--- /dev/null	Tue Feb 13 10:55:24 2001
+++ linux-2.4.1/drivers/scsi/aacraid/README	Sun Feb 11 20:28:25 2001
@@ -0,0 +1,46 @@
+				AACRAID Driver for Linux
+
+Introduction
+-------------------------
+The aacraid driver adds support for Adaptec (http://www.adaptec.com)
+OEM based RAID controllers.
+
+It is important to note the amount of test time the 2.4.x driver
+received. Though not a great deal has changed between 2.2 and 2.4
+for this version, it has not recevied a great deal of test time.
+
+A new driver version is in the works and that version will be
+submitted to the standard distribution kernel. The previous
+2.2 version was submitted but rejected due to the large
+amount of code reduncdancy and NTisms. This driver was
+initially ported from NT to Solaris and then to Linux.
+
+The new version is being written on Unix for Unix and
+should be much easier to read and a great deal cleaner.
+
+Supported Cards/Chipsets
+-------------------------
+	Dell Computer Corporation PERC 2 Quad Channel
+	Dell Computer Corporation PERC 2/Si
+	Dell Computer Corporation PERC 3/Si
+	Dell Computer Corporation PERC 3/Di
+	HP NetRAID-4M
+
+Not Supported Devices
+-------------------------
+	Any and All Adaptec branded raid controllers.
+
+People
+-------------------------
+	Adaptec Unix OEM Product Group
+
+Mailing List
+-------------------------
+please see http://domsch.com/linux for information
+on mailing lists. There is both a development and
+an announcment list. Due to the overwhelming amount
+of mail I receive about this driver, I can not
+answer questions individually and requests should
+be directed to the list server. Thanks.
+
+Modified by Brian Boerner February 2001
Index: linux-2.4.1/drivers/scsi/aacraid/aachba.c
diff -u /dev/null linux-2.4.1/drivers/scsi/aacraid/aachba.c:1.2
--- /dev/null	Tue Feb 13 10:55:24 2001
+++ linux-2.4.1/drivers/scsi/aacraid/aachba.c	Sun Feb 11 22:15:44 2001
@@ -0,0 +1,1874 @@
+/*++
+ * 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...
+ *
+--*/
+
+static char *ident_aachba = "aacraid_ident aachba.c 1.0.6 2000/10/09 Adaptec, Inc.";
+
+/*------------------------------------------------------------------------------
+ *              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;
+	char                            *bufp;
+	int                             size;
+
+
+	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 )
+		{	
+
+			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" );
+			cmn_err( CE_WARN, "AacHba_DoScsiRead: ByteCount: %d", BlockReadDisk->ByteCount);
+			cmn_err( CE_WARN, "AacHba_DoScsiRead: SG ELEMENTS: %d", scsi_cmnd_ptr->use_sg);
+			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 ) )
+	  {
+		  struct scatterlist *scatterlist_ptr;
+		  int segment;
+		  scatterlist_ptr = (struct scatterlist *)scsi_cmnd_ptr->request_buffer;
+
+		  cmn_err( CE_WARN, "\n");
+		  cmn_err( CE_WARN, "AacHba_`DoScsiWrite: WRITE request is larger than 64K");
+		  cmn_err( CE_WARN, "AacHba_DoScsiWrite: ByteCount: %d", BlockWriteDisk->ByteCount);
+/*  		  cmn_err( CE_WARN, "AacHba_DoScsiWrite: SG ELEMENTS: %d", scsi_cmnd_ptr->use_sg); */
+/*  		  cmn_err( CE_WARN, "Dump SG Element Size..."); */
+/*  		  for( segment = 0; segment < scsi_cmnd_ptr->use_sg; segment++ )  */
+/*  		  { */
+/*  			  cmn_err (CE_WARN, "SG Segment %d: %d", segment, scatterlist_ptr[segment].length); */
+/*  		  } */
+/*  		  cmn_err (CE_WARN, "\n"); */
+
+		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
+	}
+}
+
Index: linux-2.4.1/drivers/scsi/aacraid/aacid.c
diff -u /dev/null linux-2.4.1/drivers/scsi/aacraid/aacid.c:1.1
--- /dev/null	Tue Feb 13 10:55:24 2001
+++ linux-2.4.1/drivers/scsi/aacraid/aacid.c	Sun Feb 11 19:21:09 2001
@@ -0,0 +1,153 @@
+/*++
+ * 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.
+ *
+--*/
+
+static char *ident_aacid = "aacraid_ident aacid.c 1.0.6 2000/10/09 Adaptec, Inc.";
+
+#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, 0x0002, 0x1028, 0x00d1, "afa", RxInitDevice, "percraid", "DELL    ", "PERCRAID        " }, /* PERC 3/Di */
+	{ 0x1028, 0x0002, 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 ;
Index: linux-2.4.1/drivers/scsi/aacraid/commctrl.c
diff -u /dev/null linux-2.4.1/drivers/scsi/aacraid/commctrl.c:1.1
--- /dev/null	Tue Feb 13 10:55:24 2001
+++ linux-2.4.1/drivers/scsi/aacraid/commctrl.c	Sun Feb 11 19:21:09 2001
@@ -0,0 +1,1098 @@
+/*++
+ * 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
+ *
+--*/
+
+static char *ident_commctrl = "aacraid_ident commctrl.c 1.0.7 2000/10/11 Adaptec, Inc.";
+
+#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);
+
+		//
+		// Overload FileObject with a time stamp.
+		//
+		AdapterFibContext->FileObject = (void *)OsGetSeconds();
+
+		//
+		// 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, aifcp;
+	PFIB Fib;
+	int Status;
+	PLIST_ENTRY Entry;
+	int found;
+
+	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
+	//
+	// Search the list of AdapterFibContext addresses on the adapter to be sure
+	// this is a valid address
+
+	found = 0;
+	Entry = Adapter->AdapterFibContextList.Flink;
+
+	while ( Entry != &Adapter->AdapterFibContextList ) {
+			aifcp = CONTAINING_RECORD ( Entry, GET_ADAPTER_FIB_CONTEXT, NextContext );
+			if ( AdapterFibContext == aifcp ) {   // We found a winner
+					found = 1;
+					break;
+			}
+			Entry = Entry->Flink;
+	}
+
+	if ( found == 0 ) {
+			return ( EINVAL );;
+	}
+
+	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;
+
+		//
+		// Overload FileObject with a time stamp
+		// 
+		AdapterFibContext->FileObject = ( void * )OsGetSeconds();
+
+	} 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, aifcp;
+	AAC_STATUS Status;
+
+	PLIST_ENTRY Entry;
+	int found;
+
+	//
+	// 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
+	//
+	// Search the list of AdapterFibContext addresses on the adapter to be sure
+	// this is a valid address
+
+	found = 0;
+	Entry = Adapter->AdapterFibContextList.Flink;
+
+	while ( Entry != &Adapter->AdapterFibContextList ) {
+			aifcp = CONTAINING_RECORD ( Entry, GET_ADAPTER_FIB_CONTEXT, NextContext );
+			if ( AdapterFibContext == aifcp ) {   // We found a winner
+					found = 1;
+					break;
+			}
+			Entry = Entry->Flink;
+	}
+
+	if ( found == 0 ) {
+		return ( 0 ); // Already Gone
+	}
+
+	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 );
+
+}
+
Index: linux-2.4.1/drivers/scsi/aacraid/comminit.c
diff -u /dev/null linux-2.4.1/drivers/scsi/aacraid/comminit.c:1.1
--- /dev/null	Tue Feb 13 10:55:24 2001
+++ linux-2.4.1/drivers/scsi/aacraid/comminit.c	Sun Feb 11 19:21:09 2001
@@ -0,0 +1,986 @@
+/*++
+ * 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.
+ *
+ --*/
+
+static char *ident_comminit = "aacraid_ident comminit.c 1.0.6 2000/10/09 Adaptec, Inc.";
+
+#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);
+}
+
+
+
+/*++
+
+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.
+--*/
+BOOLEAN
+AacCommDetachAdapter (IN PAFA_COMM_ADAPTER	Adapter)
+{
+	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) 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);
+	}
+
+
+	//
+	// 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;
+
+	//
+	// 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);
+}
+
+
+    
+/*++
+
+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.
+--*/
+BOOLEAN
+CommInit(PAFA_COMM_ADAPTER Adapter)
+{
+    
+    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);
+
+	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 );				 
+}
+
+
Index: linux-2.4.1/drivers/scsi/aacraid/commsup.c
diff -u /dev/null linux-2.4.1/drivers/scsi/aacraid/commsup.c:1.1
--- /dev/null	Tue Feb 13 10:55:24 2001
+++ linux-2.4.1/drivers/scsi/aacraid/commsup.c	Sun Feb 11 19:21:09 2001
@@ -0,0 +1,2180 @@
+/*++
+ * 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.
+ *
+ *
+ --*/
+
+static char *ident_commsup = "aacraid_ident commsup.c 1.0.7 2000/10/11 Adaptec, Inc.";
+
+#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
+    );
+
+
+/*++
+
+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.
+
+--*/
+BOOLEAN
+FsaFreeFibContextSegment (PAFA_COMM_ADAPTER Adapter,
+						  PFIB_CONTEXT_ZONE_SEGMENT	ZoneSegment)
+{
+	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 