--- /dev/null
+diff -burN linux-2.4.9/MAINTAINERS linux/MAINTAINERS
+--- linux-2.4.9/MAINTAINERS Thu Aug 16 13:40:30 2001
++++ linux/MAINTAINERS Thu Aug 16 13:41:30 2001
+@@ -126,6 +126,14 @@
+ W: http://www.uni-karlsruhe.de/~Robert.Siemer/Private/
+ S: Maintained
+
++AACRAID SCSI RAID DRIVER
++P: Adaptec OEM Raid Solutions
++M: linux-aacraid-devel@dell.com
++L: linux-aacraid-devel@dell.com
++L: linux-aacraid-announce@dell.com
++W: http://domsch.com/linux
++S: Supported
++
+ ACPI
+ P: Andy Grover
+ M: andrew.grover@intel.com
+diff -burN linux-2.4.9/arch/i386/defconfig linux/arch/i386/defconfig
+--- linux-2.4.9/arch/i386/defconfig Thu Aug 16 13:40:30 2001
++++ linux/arch/i386/defconfig Thu Aug 16 13:41:30 2001
+@@ -286,6 +286,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_AIC7XXX_OLD is not set
+ # CONFIG_SCSI_ADVANSYS is not set
+diff -burN linux-2.4.9/drivers/scsi/Config.in linux/drivers/scsi/Config.in
+--- linux-2.4.9/drivers/scsi/Config.in Thu Aug 16 13:40:11 2001
++++ linux/drivers/scsi/Config.in Thu Aug 16 13:41:30 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
+ source drivers/scsi/aic7xxx/Config.in
+ if [ "$CONFIG_SCSI_AIC7XXX" != "y" ]; then
+ dep_tristate 'Old Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX_OLD $CONFIG_SCSI
+diff -burN linux-2.4.9/drivers/scsi/Makefile linux/drivers/scsi/Makefile
+--- linux-2.4.9/drivers/scsi/Makefile Thu Aug 16 13:40:11 2001
++++ linux/drivers/scsi/Makefile Thu Aug 16 13:41:30 2001
+@@ -70,6 +70,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
+ ifeq ($(CONFIG_SCSI_AIC7XXX),y)
+ obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx/aic7xxx_drv.o
+ endif
+@@ -193,6 +194,10 @@
+ sim710_u.h: sim710_d.h
+
+ sim710.o : sim710_d.h
++
++aacraid.o:
++ cd aacraid; make
++
+
+ 53c700_d.h: 53c700.scr script_asm.pl
+ $(PERL) -s script_asm.pl -ncr7x0_family < 53c700.scr
+diff -burN linux-2.4.9/drivers/scsi/aacraid/ChangeLog linux/drivers/scsi/aacraid/ChangeLog
+--- linux-2.4.9/drivers/scsi/aacraid/ChangeLog Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/ChangeLog Thu Aug 16 18:18:10 2001
+@@ -0,0 +1,30 @@
++2001-08-16 Matt Domsch <Matt_Domsch@dell.com>
++* renamed aacraid_pciid to perc_pciid for future Dell controllers
++* added rx_pciid and sa_pciid options for future Adaptec controllers
++* applied changes from Adaptec (new PCI ID, some cleanups)
++* released patch against 2.4.8
++* released patch against 2.4.9
++
++2001-08-11 Matt Domsch <Matt_Domsch@dell.com>
++* applied pciid patch to allow passing a new PCI ID to the module at insmod
++* removed all #ifdef CONFIG_SMP and #ifdef MODULE stuff
++* released patch against 2.4.7
++* released patch against 2.4.8
++
++2001-07-21 Matt Domsch <Matt_Domsch@dell.com>
++* changed __SMP__ to CONFIG_SMP everywhere (really this time)
++* Applied read capacity patch
++* released patch against 2.4.6
++* released patch against 2.4.7
++
++2001-07-04 Matt Domsch <Matt_Domsch@dell.com>
++* Started with linux-2.4.5-aacraid-043001.patch
++* Applied Chris Pascoe's SMP fix patch
++* Released patch against 2.4.6
++
++
++2001-04-30 Matt Domsch <Matt_Domsch@dell.com>
++* Started with linux-2.4.3-aacraid-030101.patch
++* Applied against 2.4.4.
++* Added scsi_set_pci_device() call in linit.c
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/Makefile linux/drivers/scsi/aacraid/Makefile
+--- linux-2.4.9/drivers/scsi/aacraid/Makefile Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/Makefile Thu Aug 16 13:41:30 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
++
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/README linux/drivers/scsi/aacraid/README
+--- linux-2.4.9/drivers/scsi/aacraid/README Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/README Thu Aug 16 13:41:30 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
+diff -burN linux-2.4.9/drivers/scsi/aacraid/aachba.c linux/drivers/scsi/aacraid/aachba.c
+--- linux-2.4.9/drivers/scsi/aacraid/aachba.c Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/aachba.c Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,1897 @@
++/*++
++ * 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] - 1;
++ 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 )
++ {
++ // This path shouldn't ever get executed with the current driver
++ 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 );
++
++ // Check that the command queued to the controller
++ if (Status != STATUS_PENDING) {
++ cmn_err( CE_WARN, "AacHba_DoScsiRead: SendFib failed with status: %d\n",
++ Status);
++
++ // For some reason, the Fib didn't queue, return QUEUE_FULL
++ scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | QUEUE_FULL ;
++ goto err_return;
++ }
++
++ // 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 )
++ {
++ // This path shouldn't ever get executed with the current driver
++ 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 );
++
++ // Check that the command queued to the controller
++ if (Status != STATUS_PENDING) {
++ cmn_err( CE_WARN, "AacHba_DoScsiWrite: SendFib failed with status: %d\n",
++ Status);
++
++ // For some reason, the Fib didn't queue, return QUEUE_FULL
++ scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | QUEUE_FULL ;
++ goto err_return;
++ }
++
++ // don't call done func here - it should be called by the WriteCallback
++ return ( 0 );
++ }
++
++err_return:
++ AacHba_CompleteScsiNoLock( scsi_cmnd_ptr );
++
++ Adapter->CommFuncs.CompleteFib( cmd_fibcontext );
++ Adapter->CommFuncs.FreeFib( cmd_fibcontext );
++
++ return ( -1 );
++}
++
++
++/*------------------------------------------------------------------------------
++ AacHba_ReadCallback()
++ *----------------------------------------------------------------------------*/
++void AacHba_ReadCallback(
++ VOID *Context,
++ PFIB_CONTEXT FibContext,
++ int FibStatus )
++/*----------------------------------------------------------------------------*/
++{
++ PCI_MINIPORT_COMMON_EXTENSION *CommonExtension;
++ AFA_COMM_ADAPTER *Adapter;
++ BLOCKREADRESPONSE *BlockReadResponse;
++ Scsi_Cmnd * scsi_cmnd_ptr;
++ u_long lba;
++ int ContainerId;
++
++ scsi_cmnd_ptr = ( Scsi_Cmnd * )Context;
++
++ CommonExtension = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata );
++ Adapter = ( AFA_COMM_ADAPTER * )CommonExtension->Adapter;
++
++ ContainerId = TARGET_LUN_TO_CONTAINER( scsi_cmnd_ptr->target, scsi_cmnd_ptr->lun );
++
++ lba = ( ( scsi_cmnd_ptr->cmnd[1] & 0x1F ) << 16 ) |
++ ( scsi_cmnd_ptr->cmnd[2] << 8 ) |
++ scsi_cmnd_ptr->cmnd[3];
++ cmn_err( CE_DEBUG, "AacHba_ReadCallback[cpu %d]: lba = %ld, t = %ld", smp_processor_id(), lba, jiffies );
++
++ if( FibContext == 0 )
++ {
++ cmn_err( CE_WARN, "AacHba_ReadCallback: no fib context" );
++ scsi_cmnd_ptr->result = DID_ERROR << 16;
++ AacHba_CompleteScsi( scsi_cmnd_ptr );
++ return;
++ }
++
++ BlockReadResponse = ( PBLOCKREADRESPONSE )Adapter->CommFuncs.GetFibData( FibContext );
++
++ if ( BlockReadResponse->Status == ST_OK )
++ scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
++ else
++ {
++ cmn_err( CE_WARN, "AacHba_ReadCallback: read failed, status = %d\n",
++ BlockReadResponse->Status );
++ scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
++ AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ],
++ SENKEY_HW_ERR, SENCODE_INTERNAL_TARGET_FAILURE, ASENCODE_INTERNAL_TARGET_FAILURE,
++ 0, 0, 0, 0 );
++ }
++
++#ifdef DEBUG_SGBUFFER
++ if ( scsi_cmnd_ptr->use_sg ) // use scatter/gather list
++ {
++ struct scatterlist *scatterlist_ptr;
++ int i, segment, count;
++ char *ptr;
++
++ scatterlist_ptr = ( struct scatterlist * )scsi_cmnd_ptr->request_buffer;
++
++ for( segment = 0; segment < scsi_cmnd_ptr->use_sg; segment++ )
++ {
++ count = 0;
++ ptr = scatterlist_ptr[segment].address;
++ for( i = 0; i < scatterlist_ptr[segment].length; i++ )
++ {
++ if( *( ptr++ ) == 0xa5 )
++ count++;
++ }
++ if( count == scatterlist_ptr[segment].length )
++ cmn_err( CE_WARN, "AacHba_ReadCallback: segment %d not filled", segment );
++
++ }
++ }
++#endif
++
++ Adapter->CommFuncs.CompleteFib( FibContext );
++ Adapter->CommFuncs.FreeFib( FibContext );
++
++ AacHba_CompleteScsi( scsi_cmnd_ptr );
++}
++
++/*------------------------------------------------------------------------------
++ AacHba_WriteCallback()
++ *----------------------------------------------------------------------------*/
++void AacHba_WriteCallback(
++ VOID *Context,
++ PFIB_CONTEXT FibContext,
++ int FibStatus )
++/*----------------------------------------------------------------------------*/
++{
++ PCI_MINIPORT_COMMON_EXTENSION *CommonExtension;
++ AFA_COMM_ADAPTER *Adapter;
++ BLOCKWRITERESPONSE *BlockWriteResponse;
++ Scsi_Cmnd *scsi_cmnd_ptr;
++ u_long lba;
++ int ContainerId;
++
++ scsi_cmnd_ptr = ( Scsi_Cmnd * )Context;
++
++ CommonExtension = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata );
++ Adapter = ( AFA_COMM_ADAPTER * )CommonExtension->Adapter;
++
++ ContainerId = TARGET_LUN_TO_CONTAINER( scsi_cmnd_ptr->target, scsi_cmnd_ptr->lun );
++
++ lba = ( ( scsi_cmnd_ptr->cmnd[1] & 0x1F ) << 16 ) |
++ ( scsi_cmnd_ptr->cmnd[2] << 8 ) |
++ scsi_cmnd_ptr->cmnd[3];
++ cmn_err( CE_DEBUG, "AacHba_WriteCallback[cpu %d]: lba = %ld, t = %ld", smp_processor_id(), lba, jiffies );
++ if( FibContext == 0 )
++ {
++ cmn_err( CE_WARN, "AacHba_WriteCallback: no fib context" );
++ scsi_cmnd_ptr->result = DID_ERROR << 16;
++ AacHba_CompleteScsi( scsi_cmnd_ptr );
++ return;
++ }
++
++ BlockWriteResponse = (PBLOCKWRITERESPONSE) Adapter->CommFuncs.GetFibData( FibContext );
++ if (BlockWriteResponse->Status == ST_OK)
++ scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
++ else
++ {
++ cmn_err( CE_WARN, "AacHba_WriteCallback: write failed, status = %d\n",
++ BlockWriteResponse->Status );
++ scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;
++ AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ],
++ SENKEY_HW_ERR, SENCODE_INTERNAL_TARGET_FAILURE, ASENCODE_INTERNAL_TARGET_FAILURE,
++ 0, 0, 0, 0 );
++ }
++
++ Adapter->CommFuncs.CompleteFib( FibContext );
++ Adapter->CommFuncs.FreeFib( FibContext );
++
++ AacHba_CompleteScsi( scsi_cmnd_ptr );
++}
++
++
++/*------------------------------------------------------------------------------
++ AacHba_Ioctl()
++
++ Handle IOCTL requests
++
++ Preconditions:
++ Postconditions:
++ *----------------------------------------------------------------------------*/
++int AacHba_Ioctl(
++ PCI_MINIPORT_COMMON_EXTENSION *CommonExtension,
++ int cmd,
++ void * arg )
++/*----------------------------------------------------------------------------*/
++{
++ Sa_ADAPTER_EXTENSION *AdapterExtension;
++ AFA_IOCTL_CMD IoctlCmd;
++ int status;
++
++ AdapterExtension = ( Sa_ADAPTER_EXTENSION * )CommonExtension->MiniPort;
++
++ cmn_err( CE_DEBUG, "AacHba_Ioctl, type = %d", cmd );
++ switch( cmd )
++ {
++ case FSACTL_SENDFIB:
++ cmn_err( CE_DEBUG, "FSACTL_SENDFIB" );
++ break;
++
++ case FSACTL_AIF_THREAD:
++ cmn_err( CE_DEBUG, "FSACTL_AIF_THREAD" );
++ break;
++
++ case FSACTL_NULL_IO_TEST:
++ cmn_err( CE_DEBUG, "FSACTL_NULL_IO_TEST" );
++ break;
++
++ case FSACTL_SIM_IO_TEST:
++ cmn_err( CE_DEBUG, "FSACTL_SIM_IO_TEST" );
++ break;
++
++ case FSACTL_GET_FIBTIMES:
++ cmn_err( CE_DEBUG, "FSACTL_GET_FIBTIMES" );
++ break;
++
++ case FSACTL_ZERO_FIBTIMES:
++ cmn_err( CE_DEBUG, "FSACTL_ZERO_FIBTIMES");
++ break;
++
++ case FSACTL_GET_VAR:
++ cmn_err( CE_DEBUG, "FSACTL_GET_VAR" );
++ break;
++
++ case FSACTL_SET_VAR:
++ cmn_err( CE_DEBUG, "FSACTL_SET_VAR" );
++ break;
++
++ case FSACTL_OPEN_ADAPTER_CONFIG:
++ cmn_err( CE_DEBUG, "FSACTL_OPEN_ADAPTER_CONFIG" );
++ break;
++
++ case FSACTL_CLOSE_ADAPTER_CONFIG:
++ cmn_err( CE_DEBUG, "FSACTL_CLOSE_ADAPTER_CONFIG" );
++ break;
++
++ case FSACTL_QUERY_ADAPTER_CONFIG:
++ cmn_err( CE_DEBUG, "FSACTL_QUERY_ADAPTER_CONFIG" );
++ break;
++
++ case FSACTL_OPEN_GET_ADAPTER_FIB:
++ cmn_err( CE_DEBUG, "FSACTL_OPEN_GET_ADAPTER_FIB" );
++ break;
++
++ case FSACTL_GET_NEXT_ADAPTER_FIB:
++ cmn_err( CE_DEBUG, "FSACTL_GET_NEXT_ADAPTER_FIB" );
++ break;
++
++ case FSACTL_CLOSE_GET_ADAPTER_FIB:
++ cmn_err( CE_DEBUG, "FSACTL_CLOSE_GET_ADAPTER_FIB" );
++ break;
++
++ case FSACTL_MINIPORT_REV_CHECK:
++ cmn_err( CE_DEBUG, "FSACTL_MINIPORT_REV_CHECK" );
++ break;
++
++ case FSACTL_OPENCLS_COMM_PERF_DATA:
++ cmn_err( CE_DEBUG, "FSACTL_OPENCLS_COMM_PERF_DATA" );
++ break;
++
++ case FSACTL_GET_COMM_PERF_DATA:
++ cmn_err( CE_DEBUG, "FSACTL_GET_COMM_PERF_DATA" );
++ break;
++
++ case FSACTL_QUERY_DISK:
++ cmn_err( CE_DEBUG, "FSACTL_QUERY_DISK" );
++ break;
++
++ case FSACTL_DELETE_DISK:
++ cmn_err( CE_DEBUG, "FSACTL_DELETE_DISK" );
++ break;
++
++ default:
++ cmn_err( CE_DEBUG, "Unknown ioctl: 0x%x", cmd );
++ }
++
++ IoctlCmd.cmd = cmd;
++ IoctlCmd.arg = ( intptr_t )arg;
++ IoctlCmd.flag = 0;
++ IoctlCmd.cred_p = 0;
++ IoctlCmd.rval_p = 0;
++
++ status = AfaCommAdapterDeviceControl( CommonExtension->Adapter, &IoctlCmd );
++ cmn_err( CE_DEBUG, "AAC_Ioctl, completion status = %d", status );
++ return( status );
++}
++
++
++/*------------------------------------------------------------------------------
++ AacHba_AdapterDeviceControl()
++
++ Preconditions:
++ Postconditions:
++ Returns TRUE if ioctl handled, FALSE otherwise
++ *ReturnStatus set to completion status
++ *----------------------------------------------------------------------------*/
++BOOLEAN AacHba_AdapterDeviceControl (
++ PVOID AdapterArg, // CommonExtensionPtr
++ IN PAFA_IOCTL_CMD IoctlCmdPtr,
++ OUT int * ReturnStatus )
++/*----------------------------------------------------------------------------*/
++{
++ BOOLEAN Handled = TRUE; // start out handling it.
++ int Status = EFAULT;
++
++ switch( IoctlCmdPtr->cmd )
++ {
++ case FSACTL_QUERY_DISK:
++ Status = AacHba_QueryDisk( AdapterArg, IoctlCmdPtr );
++ break;
++
++ case FSACTL_DELETE_DISK:
++ Status = AacHba_DeleteDisk( AdapterArg, IoctlCmdPtr );
++ break;
++
++ case FSACTL_FORCE_DELETE_DISK:
++ Status = AacHba_ForceDeleteDisk( AdapterArg, IoctlCmdPtr );
++ break;
++
++ case 2131:
++ if( AacHba_ProbeContainers( ( PCI_MINIPORT_COMMON_EXTENSION * )AdapterArg ) )
++ Status = -EFAULT;
++ break;
++
++ default:
++ Handled = FALSE;
++ break;
++ }
++
++ *ReturnStatus = Status;
++
++ return( Handled );
++}
++
++
++/*------------------------------------------------------------------------------
++ AacHba_QueryDisk()
++
++ Postconditions:
++ Return values
++ 0 = OK
++ -EFAULT = Bad address
++ -EINVAL = Bad container number
++ *----------------------------------------------------------------------------*/
++int AacHba_QueryDisk(
++ PVOID AdapterArg, // CommonExtensionPtr
++ IN PAFA_IOCTL_CMD IoctlCmdPtr )
++/*----------------------------------------------------------------------------*/
++{
++ UNIX_QUERY_DISK QueryDisk;
++ PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr;
++ fsadev_t *fsa_dev_ptr;
++
++ CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )AdapterArg;
++ fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev );
++
++ if( copyin( IoctlCmdPtr->arg, &QueryDisk, sizeof( UNIX_QUERY_DISK ) ) )
++ return( -EFAULT );
++
++ if (QueryDisk.ContainerNumber == -1)
++ QueryDisk.ContainerNumber = TARGET_LUN_TO_CONTAINER( QueryDisk.Target, QueryDisk.Lun );
++ else
++ if( ( QueryDisk.Bus == -1 ) && ( QueryDisk.Target == -1 ) && ( QueryDisk.Lun == -1 ) )
++ {
++ if( QueryDisk.ContainerNumber > MAXIMUM_NUM_CONTAINERS )
++ return( -EINVAL );
++
++ QueryDisk.Instance = CommonExtensionPtr->OsDep.scsi_host_ptr->host_no;
++ QueryDisk.Bus = 0;
++ QueryDisk.Target = CONTAINER_TO_TARGET( QueryDisk.ContainerNumber );
++ QueryDisk.Lun = CONTAINER_TO_LUN( QueryDisk.ContainerNumber );
++ }
++ else
++ return( -EINVAL );
++
++ QueryDisk.Valid = fsa_dev_ptr->ContainerValid[QueryDisk.ContainerNumber];
++ QueryDisk.Locked = fsa_dev_ptr->ContainerLocked[QueryDisk.ContainerNumber];
++ QueryDisk.Deleted = fsa_dev_ptr->ContainerDeleted[QueryDisk.ContainerNumber];
++
++ if( fsa_dev_ptr->ContainerDevNo[QueryDisk.ContainerNumber] == -1 )
++ QueryDisk.UnMapped = TRUE;
++ else
++ QueryDisk.UnMapped = FALSE;
++
++ get_sd_devname( fsa_dev_ptr->ContainerDevNo[QueryDisk.ContainerNumber],
++ QueryDisk.diskDeviceName );
++
++ if( copyout( &QueryDisk, IoctlCmdPtr->arg, sizeof( UNIX_QUERY_DISK ) ) )
++ return( -EFAULT );
++
++ return( 0 );
++}
++
++
++/*------------------------------------------------------------------------------
++ get_sd_devname()
++ *----------------------------------------------------------------------------*/
++static void get_sd_devname(
++ long disknum,
++ char * buffer)
++/*----------------------------------------------------------------------------*/
++{
++ if( disknum < 0 )
++ {
++ sprintf(buffer, "%s", "");
++ return;
++ }
++
++ if( disknum < 26 )
++ sprintf(buffer, "sd%c", 'a' + disknum);
++ else {
++ unsigned int min1;
++ unsigned int min2;
++ /*
++ * For larger numbers of disks, we need to go to a new
++ * naming scheme.
++ */
++ min1 = disknum / 26;
++ min2 = disknum % 26;
++ sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2);
++ }
++}
++
++
++/*------------------------------------------------------------------------------
++ AacHba_ForceDeleteDisk()
++
++ Postconditions:
++ Return values
++ 0 = OK
++ -EFAULT = Bad address
++ -EINVAL = Bad container number
++ *----------------------------------------------------------------------------*/
++int AacHba_ForceDeleteDisk(
++ PVOID AdapterArg, // CommonExtensionPtr
++ IN PAFA_IOCTL_CMD IoctlCmdPtr )
++/*----------------------------------------------------------------------------*/
++{
++ DELETE_DISK DeleteDisk;
++ PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr;
++ fsadev_t *fsa_dev_ptr;
++
++ CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )AdapterArg;
++ fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev );
++
++ if ( copyin( IoctlCmdPtr->arg, &DeleteDisk, sizeof( DELETE_DISK ) ) )
++ return( -EFAULT );
++
++ if ( DeleteDisk.ContainerNumber > MAXIMUM_NUM_CONTAINERS )
++ return( -EINVAL );
++
++ // Mark this container as being deleted.
++ fsa_dev_ptr->ContainerDeleted[DeleteDisk.ContainerNumber] = TRUE;
++
++ // Mark the container as no longer valid
++ fsa_dev_ptr->ContainerValid[DeleteDisk.ContainerNumber] = 0;
++
++ return( 0 );
++}
++
++
++/*------------------------------------------------------------------------------
++ AacHba_DeleteDisk()
++
++ Postconditions:
++ Return values
++ 0 = OK
++ -EFAULT = Bad address
++ -EINVAL = Bad container number
++ -EBUSY = Device locked
++ *----------------------------------------------------------------------------*/
++int AacHba_DeleteDisk(
++ PVOID AdapterArg,
++ IN PAFA_IOCTL_CMD IoctlCmdPtr )
++/*----------------------------------------------------------------------------*/
++{
++ DELETE_DISK DeleteDisk;
++ PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr;
++ fsadev_t *fsa_dev_ptr;
++
++ CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )AdapterArg;
++ fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev );
++
++ if( copyin( IoctlCmdPtr->arg, &DeleteDisk, sizeof( DELETE_DISK ) ) )
++ return( -EFAULT );
++
++ if( DeleteDisk.ContainerNumber > MAXIMUM_NUM_CONTAINERS )
++ return( -EINVAL );
++
++ // If the container is locked, it can not be deleted by the API.
++ if( fsa_dev_ptr->ContainerLocked[DeleteDisk.ContainerNumber] )
++ return( -EBUSY );
++ else
++ {
++ // Mark the container as no longer being valid.
++ fsa_dev_ptr->ContainerValid[DeleteDisk.ContainerNumber] = 0;
++ fsa_dev_ptr->ContainerDevNo[DeleteDisk.ContainerNumber] = -1;
++ return(0);
++ }
++}
++
++
++/*------------------------------------------------------------------------------
++ AacHba_OpenAdapter()
++ *----------------------------------------------------------------------------*/
++AAC_STATUS AacHba_OpenAdapter(
++ IN PVOID AdapterArg )
++/*----------------------------------------------------------------------------*/
++{
++ return( STATUS_SUCCESS );
++}
++
++
++/*------------------------------------------------------------------------------
++ AacHba_CloseAdapter()
++ *----------------------------------------------------------------------------*/
++AAC_STATUS AacHba_CloseAdapter(
++ IN PVOID AdapterArg )
++/*----------------------------------------------------------------------------*/
++{
++ return( STATUS_SUCCESS );
++}
++
++
++/*------------------------------------------------------------------------------
++ AacHba_DetachAdapter()
++ *----------------------------------------------------------------------------*/
++void AacHba_DetachAdapter(
++ IN PVOID AdapterArg )
++/*----------------------------------------------------------------------------*/
++{
++ AacCommDetachAdapter( AdapterArg );
++}
++
++
++/*------------------------------------------------------------------------------
++ AacHba_AbortScsiCommand()
++ *----------------------------------------------------------------------------*/
++void AacHba_AbortScsiCommand(
++ Scsi_Cmnd *scsi_cmnd_ptr )
++/*----------------------------------------------------------------------------*/
++{
++ u_short interrupt_status;
++ PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr;
++
++ CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata );
++ interrupt_status = Sa_READ_USHORT( ( PSa_ADAPTER_EXTENSION )( CommonExtensionPtr->MiniPort ),
++ DoorbellReg_p );
++ cmn_err( CE_WARN, "interrupt_status = %d", interrupt_status );
++
++ if( interrupt_status & DOORBELL_1) { // Adapter -> Host Normal Command Ready
++ cmn_err( CE_WARN, "DOORBELL_1: Adapter -> Host Normal Command Ready" );
++ }
++
++ if( interrupt_status & DOORBELL_2) { // Adapter -> Host Normal Response Ready
++ cmn_err( CE_WARN, "DOORBELL_2: Adapter -> Host Normal Response Ready" );
++ }
++
++ if ( interrupt_status & DOORBELL_3) { // Adapter -> Host Normal Command Not Full
++ cmn_err( CE_WARN, "DOORBELL_3: Adapter -> Host Normal Command Not Full" );
++ }
++
++ if ( interrupt_status & DOORBELL_4) { // Adapter -> Host Normal Response Not Full
++ cmn_err( CE_WARN, "DOORBELL_4: Adapter -> Host Normal Response Not Full" );
++ }
++
++}
++
++
++/*------------------------------------------------------------------------------
++ AacHba_HandleAif()
++ *----------------------------------------------------------------------------*/
++BOOLEAN AacHba_HandleAif(
++ IN PVOID AdapterArg,
++ IN PFIB_CONTEXT FibContext )
++/*----------------------------------------------------------------------------*/
++{
++ return( FALSE );
++}
++
++
++/*------------------------------------------------------------------------------
++ AacHba_SetSenseData()
++ Fill in the sense data.
++ Preconditions:
++ Postconditions:
++ *----------------------------------------------------------------------------*/
++void AacHba_SetSenseData(
++ char * sense_buf,
++ unchar sense_key,
++ unchar sense_code,
++ unchar a_sense_code,
++ unchar incorrect_length,
++ unchar bit_pointer,
++ unsigned field_pointer,
++ unsigned long residue )
++/*----------------------------------------------------------------------------*/
++{
++ sense_buf[0] = 0xF0; // Sense data valid, err code 70h (current error)
++ sense_buf[1] = 0; // Segment number, always zero
++
++ if( incorrect_length )
++ {
++ sense_buf[2] = sense_key | 0x20; // Set the ILI bit | sense key
++ sense_buf[3] = BYTE3(residue);
++ sense_buf[4] = BYTE2(residue);
++ sense_buf[5] = BYTE1(residue);
++ sense_buf[6] = BYTE0(residue);
++ }
++ else
++ sense_buf[2] = sense_key; // Sense key
++
++ if( sense_key == SENKEY_ILLEGAL )
++ sense_buf[7] = 10; // Additional sense length
++ else
++ sense_buf[7] = 6; // Additional sense length
++
++ sense_buf[12] = sense_code; // Additional sense code
++ sense_buf[13] = a_sense_code; // Additional sense code qualifier
++ if( sense_key == SENKEY_ILLEGAL )
++ {
++ sense_buf[15] = 0;
++
++ if( sense_code == SENCODE_INVALID_PARAM_FIELD )
++ sense_buf[15] = 0x80; // Std sense key specific field
++ // Illegal parameter is in the parameter block
++
++ if( sense_code == SENCODE_INVALID_CDB_FIELD )
++ sense_buf[15] = 0xc0; // Std sense key specific field
++ // Illegal parameter is in the CDB block
++ sense_buf[15] |= bit_pointer;
++ sense_buf[16] = field_pointer >> 8; // MSB
++ sense_buf[17] = field_pointer; // LSB
++ }
++}
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/aacid.c linux/drivers/scsi/aacraid/aacid.c
+--- linux-2.4.9/drivers/scsi/aacraid/aacid.c Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/aacid.c Thu Aug 16 18:10:23 2001
+@@ -0,0 +1,157 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * 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[] = {
++ { 0x0000, 0x0000, 0x0000, 0x0000, "afa", RxInitDevice, "percraid", "DELL ", "PERCRAID " }, /* Dell unknown - uses perc_pciid */
++ { 0x0000, 0x0000, 0x0000, 0x0000, "aac", RxInitDevice, "aacraid", "ADAPTEC ", "AACRAID " }, /* unknown - uses rx_pciid */
++ { 0x0000, 0x0000, 0x0000, 0x0000, "aac", SaInitDevice, "aacraid", "ADAPTEC ", "AACRAID " }, /* unknown - uses sa_pciid */
++ { 0x1028, 0x0001, 0x1028, 0x0001, "afa", RxInitDevice, "percraid", "DELL ", "PERCRAID " }, /* PERC 2/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, 0x000a, 0x1028, 0x0106, "afa", RxInitDevice, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Di */
++ { 0x1011, 0x0046, 0x9005, 0x1364, "afa", SaInitDevice, "percraid", "DELL ", "PERCRAID " }, /* Dell PERC2 "Quad Channel" */
++ { 0x1011, 0x0046, 0x9005, 0x0365, "aac", SaInitDevice, "aacraid", "ADAPTEC ", "Adaptec 5400S " }, /* Adaptec 5400S */
++ { 0x1011, 0x0046, 0x103c, 0x10c2, "hpn", SaInitDevice, "hpnraid", "HP ", "NetRAID-4M " } /* HP NetRAID-4M */
++};
++
++
++#define NUM_MINIPORTS (sizeof(MiniPorts) / sizeof(FSA_MINIPORT))
++
++int NumMiniPorts = NUM_MINIPORTS;
++
++char DescriptionString[] = "AACxxx Raid Controller" FSA_VERSION_STRING ;
+diff -burN linux-2.4.9/drivers/scsi/aacraid/commctrl.c linux/drivers/scsi/aacraid/commctrl.c
+--- linux-2.4.9/drivers/scsi/aacraid/commctrl.c Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/commctrl.c Thu Aug 16 13:41:30 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 );
++
++}
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/comminit.c linux/drivers/scsi/aacraid/comminit.c
+--- linux-2.4.9/drivers/scsi/aacraid/comminit.c Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/comminit.c Thu Aug 16 13:41:30 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) )
++
++\f
++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 );
++}
++
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/commsup.c linux/drivers/scsi/aacraid/commsup.c
+--- linux-2.4.9/drivers/scsi/aacraid/commsup.c Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/commsup.c Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,2185 @@
++/*++
++ * 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 - The adapter that this COMM_FIB_CONTEXT will communicate with.
++
++Return Value:
++
++ TRUE - All resources were properly freed.
++ FALSE - An Error occured while freeing resources.
++
++--*/
++
++{
++ PFIB_CONTEXT_ZONE_SEGMENT ZoneSegment, NextZoneSegment;
++
++ ZoneSegment = Adapter->FibContextSegmentList;
++
++ while (ZoneSegment) {
++
++ NextZoneSegment = ZoneSegment->Next;
++
++ FsaFreeFibContextSegment( Adapter, ZoneSegment );
++
++ ZoneSegment = NextZoneSegment;
++ }
++
++ return (TRUE);
++}
++
++
++
++BOOLEAN
++FsaExtendFibContextZone (IN PAFA_COMM_ADAPTER Adapter)
++{
++ int ExtendSize;
++ KIRQL SavedIrql;
++ ULONG ZoneSegmentAllocSize, FibAllocSize;
++ PVOID FibContextSegment;
++ PCOMM_FIB_CONTEXT FibContext;
++ PFIB Fib;
++ PVOID FibPhysicalAddress;
++ int i;
++ PFIB_CONTEXT_ZONE_SEGMENT ZoneSegment;
++
++ //
++ // Allocate space to describe this zone segment.
++ //
++
++ cmn_err (CE_DEBUG, "Entered FsaExtendFibContextZone");
++ ZoneSegment = OsAllocMemory( sizeof( FIB_CONTEXT_ZONE_SEGMENT ), OS_ALLOC_MEM_SLEEP );
++ if (ZoneSegment == NULL) {
++ return (FALSE);
++ }
++
++ ExtendSize = Adapter->FibContextZoneExtendSize;
++ ZoneSegmentAllocSize = (ExtendSize * sizeof(COMM_FIB_CONTEXT)) + sizeof(ZONE_SEGMENT_HEADER);
++
++ FibContextSegment = OsAllocMemory( ZoneSegmentAllocSize, OS_ALLOC_MEM_SLEEP );
++
++ if (FibContextSegment == NULL) {
++ OsFreeMemory(ZoneSegment);
++ return (FALSE);
++ }
++
++ RtlZeroMemory( FibContextSegment, ZoneSegmentAllocSize );
++
++ ZoneSegment->FibContextSegment = FibContextSegment;
++ ZoneSegment->FibContextSegmentSize = ZoneSegmentAllocSize;
++ ZoneSegment->ExtendSize = ExtendSize;
++
++ FibAllocSize = ExtendSize * sizeof(FIB);
++
++
++ ZoneSegment->MapFibContext.Size = FibAllocSize;
++
++ AllocateAndMapFibSpace( Adapter, &ZoneSegment->MapFibContext );
++
++ Fib = ZoneSegment->MapFibContext.FibVirtualAddress;
++ FibPhysicalAddress = ZoneSegment->MapFibContext.FibPhysicalAddress;
++
++ RtlZeroMemory( Fib, FibAllocSize );
++
++ // Account for the ZONE_SEGMENT_HEADER before the first actual FibContext.
++
++ for (i = 0, FibContext = (PCOMM_FIB_CONTEXT)((PUCHAR)FibContextSegment + sizeof(ZONE_SEGMENT_HEADER));
++ i < ExtendSize; i++, FibContext++) {
++
++ FibContext->Adapter = Adapter;
++
++ FibContext->Fib = Fib;
++ FibContext->FibData = (PVOID) FibContext->Fib->data;
++
++ OsCv_init( &FibContext->FsaEvent);
++ FibContext->FsaEventMutex = OsCvLockAlloc();
++ OsCvLockInit( FibContext->FsaEventMutex, Adapter->SpinLockCookie );
++
++ Fib->Header.XferState = 0xffffffff;
++ Fib->Header.SenderSize = sizeof(FIB);
++
++ FibContext->LogicalFibAddress.LowPart = (ULONG) FibPhysicalAddress;
++
++ Fib = (PFIB)((PUCHAR)Fib + sizeof(FIB));
++ FibPhysicalAddress = (PVOID)((PUCHAR)FibPhysicalAddress + sizeof(FIB));
++ }
++
++ //
++ // If FibContextZone.TotalSegmentSize is non-zero, then a zone has already been
++ // initialized, we just need to extend it.
++ //
++
++ if (Adapter->FibContextZone.TotalSegmentSize) {
++
++ OsSpinLockAcquire( Adapter->FibContextZoneSpinLock );
++
++ ExExtendZone( &Adapter->FibContextZone,
++ FibContextSegment,
++ ZoneSegmentAllocSize );
++
++ OsSpinLockRelease( Adapter->FibContextZoneSpinLock );
++
++ } else {
++
++ if (ExInitializeZone( &Adapter->FibContextZone,
++ sizeof(COMM_FIB_CONTEXT),
++ FibContextSegment,
++ ZoneSegmentAllocSize ) != STATUS_SUCCESS)
++ FsaBugCheck(0,0,0);
++
++ }
++
++ //
++ // Add this segment to the adapter's list of segments
++ //
++
++ ZoneSegment->Next = Adapter->FibContextSegmentList;
++ Adapter->FibContextSegmentList = ZoneSegment;
++
++ return (TRUE);
++}
++
++
++
++/*++
++
++Routine Description:
++
++ This routine creates a new COMM_FIB_CONTEXT record
++
++Arguments:
++
++ Adapter - The adapter that this COMM_FIB_CONTEXT will communicate with.
++
++Return Value:
++
++ PCOMM_FIB_CONTEXT - returns a pointer to the newly allocate COMM_FIB_CONTEXT Record
++
++--*/
++PFIB_CONTEXT
++AllocateFib (IN PVOID AdapterArg)
++{
++ PAFA_COMM_ADAPTER Adapter = (PAFA_COMM_ADAPTER) AdapterArg;
++ KIRQL SavedIrql;
++ PCOMM_FIB_CONTEXT FibContext;
++ int FullZoneLoopCounter = 0;
++
++
++ //
++ // Acquire the zone spin lock, and check to see if the zone is full.
++ // If it is, then release the spin lock and allocate more fibs for the
++ // zone. The ExtendFibZone routine will re-acquire the spin lock to add
++ // the new fibs onto the zone.
++ //
++
++ OsSpinLockAcquire( Adapter->FibContextZoneSpinLock );
++
++ while (ExIsFullZone( &Adapter->FibContextZone )) {
++
++ if (++FullZoneLoopCounter > 10)
++ FsaBugCheck(0,0,0);
++
++ OsSpinLockRelease( Adapter->FibContextZoneSpinLock );
++
++ // bmb debug
++ cmn_err (CE_DEBUG, "Extending FibContextZone");
++ if (FsaExtendFibContextZone(Adapter) == FALSE) {
++ return (NULL);
++ }
++
++ OsSpinLockAcquire( Adapter->FibContextZoneSpinLock );
++
++ }
++
++ //
++ // At this point we now know that the zone has at least one more
++ // IRP context record available. So allocate from the zone and
++ // then release the mutex.
++ //
++
++ FibContext = (PCOMM_FIB_CONTEXT) ExAllocateFromZone( &Adapter->FibContextZone );
++
++ OsSpinLockRelease( Adapter->FibContextZoneSpinLock );
++
++ //
++ // Set the proper node type code and node byte size
++ //
++
++ FibContext->NodeTypeCode = FSAFS_NTC_FIB_CONTEXT;
++ FibContext->NodeByteSize = sizeof( COMM_FIB_CONTEXT );
++
++ //
++ // Null out fields that depend on being zero at the start of each I/O
++ //
++
++ FibContext->Fib->Header.XferState = 0;
++ FibContext->FibCallback = NULL;
++ FibContext->FibCallbackContext = NULL;
++
++
++ //
++ // return and tell the caller
++ //
++
++ return ((PFIB_CONTEXT) FibContext);
++}
++
++
++/*++
++
++Routine Description:
++
++ This routine deallocates and removes the specified COMM_FIB_CONTEXT record
++ from the Fsafs in memory data structures. It should only be called
++ by FsaCompleteRequest.
++
++Arguments:
++
++ FibContext - Supplies the COMM_FIB_CONTEXT to remove
++
++Return Value:
++
++ None
++
++--*/
++VOID
++FreeFib (IN PFIB_CONTEXT Context)
++{
++ KIRQL SavedIrql;
++ PCOMM_FIB_CONTEXT FibContext = Context;
++
++ ASSERT(FibContext->NodeTypeCode == FSAFS_NTC_FIB_CONTEXT);
++
++ OsSpinLockAcquire( FibContext->Adapter->FibContextZoneSpinLock );
++
++ if (FibContext->Flags & FIB_CONTEXT_FLAG_TIMED_OUT) {
++
++ FsaCommData.TimedOutFibs++;
++
++ FibContext->Next = FibContext->Adapter->FibContextTimedOutList;
++ FibContext->Adapter->FibContextTimedOutList = FibContext;
++
++ } else {
++
++ ASSERT(FibContext->Fib->Header.XferState == 0);
++
++ if (FibContext->Fib->Header.XferState != 0) {
++ cmn_err(CE_WARN, "FreeFib, XferState != 0, FibContext = 0x%x, XferState = 0x%x\n",
++ FibContext, FibContext->Fib->Header.XferState);
++ }
++
++ ExFreeToZone( &FibContext->Adapter->FibContextZone, FibContext );
++
++ }
++
++ OsSpinLockRelease( FibContext->Adapter->FibContextZoneSpinLock );
++
++ //
++ // return and tell the caller
++ //
++
++ return;
++}
++
++
++/*++
++
++Routine Description:
++
++ This routine deallocates and removes the specified COMM_FIB_CONTEXT record
++ from the Fsafs in memory data structures. It should only be called
++ from the dpc routines to from dpc to free an FibContext from an async or
++ no response io
++
++Arguments:
++
++ FibContext - Supplies the COMM_FIB_CONTEXT to remove
++
++Return Value:
++
++ None
++
++--*/
++VOID
++FreeFibFromDpc (IN PFIB_CONTEXT Context)
++{
++ PCOMM_FIB_CONTEXT FibContext = (PCOMM_FIB_CONTEXT) Context;
++
++ ASSERT(FibContext->NodeTypeCode == FSAFS_NTC_FIB_CONTEXT);
++
++ OsSpinLockAcquire(FibContext->Adapter->FibContextZoneSpinLock);
++
++ if (FibContext->Flags & FIB_CONTEXT_FLAG_TIMED_OUT) {
++
++ FsaCommData.TimedOutFibs++;
++
++ FibContext->Next = FibContext->Adapter->FibContextTimedOutList;
++ FibContext->Adapter->FibContextTimedOutList = FibContext;
++
++ } else {
++
++ ASSERT(FibContext->Fib->Header.XferState == 0);
++
++ if (FibContext->Fib->Header.XferState != 0) {
++ cmn_err(CE_WARN, "FreeFibFromDpc, XferState != 0, FibContext = 0x%x, XferState = 0x%x\n",
++ FibContext, FibContext->Fib->Header.XferState);
++ }
++
++
++ ExFreeToZone( &FibContext->Adapter->FibContextZone, FibContext );
++
++ }
++
++ OsSpinLockRelease(FibContext->Adapter->FibContextZoneSpinLock);
++
++ //
++ // return and tell the caller
++ //
++
++ return;
++}
++
++
++/*++
++
++Routine Description:
++
++ Will initialize a FIB of the requested size.
++
++Arguments:
++
++ Fib is a pointer to a location which will receive the address of the allocated
++ FIB.
++
++ Size is the size of the Fib to allocate.
++
++Return Value:
++
++ NT_SUCCESS if a Fib was returned to the caller.
++ NT_ERROR if event was an invalid event.
++
++--*/
++AAC_STATUS
++InitializeFib (IN PFIB_CONTEXT Context)
++{
++ PCOMM_FIB_CONTEXT FibContext = (PCOMM_FIB_CONTEXT) Context;
++ PFIB Fib = FibContext->Fib;
++
++ Fib->Header.StructType = TFib;
++ Fib->Header.Size = sizeof(FIB);
++// if (Fib->Header.XferState & AllocatedFromPool)
++// Fib->Header.XferState = HostOwned | FibInitialized | FibEmpty | AllocatedFromPool;
++// else
++ Fib->Header.XferState = HostOwned | FibInitialized | FibEmpty | FastResponseCapable;
++ Fib->Header.SenderFibAddress = 0;
++ Fib->Header.ReceiverFibAddress = 0;
++ Fib->Header.SenderSize = sizeof(FIB);
++
++ return(STATUS_SUCCESS);
++}
++
++
++/*++
++
++Routine Description:
++
++ Will allocate and initialize a FIB of the requested size and return a
++ pointer to the structure. The size allocated may be larger than the size
++ requested due to allocation performace optimizations.
++
++Arguments:
++
++ Fib is a pointer to a location which will receive the address of the allocated
++ FIB.
++
++ Size is the size of the Fib to allocate.
++
++ JustInitialize is a boolean which indicates a Fib has been allocated most likly in an
++ imbedded structure the FS always allocates. So just initiaize it and return.
++
++Return Value:
++
++ NT_SUCCESS if a Fib was returned to the caller.
++ NT_ERROR if event was an invalid event.
++
++--*/
++AAC_STATUS
++AllocatePoolFib (OUT PFIB *Fib, IN USHORT Size)
++{}
++
++
++/*++
++
++Routine Description:
++
++ Will deallocate and return to the free pool the FIB pointed to by the
++ caller. Upon return accessing locations pointed to by the FIB parameter
++ could cause system access faults.
++
++Arguments:
++
++ Fib is a pointer to the FIB that caller wishes to deallocate.
++
++Return Value:
++
++ NT_SUCCESS if a Fib was returned to the caller.
++ NT_ERROR if event was an invalid event.
++
++--*/
++AAC_STATUS
++DeallocateFib (PFIB_CONTEXT Context)
++{
++ PCOMM_FIB_CONTEXT FibContext = (PCOMM_FIB_CONTEXT) Context;
++ PFIB Fib = FibContext->Fib;
++
++ if ( Fib->Header.StructType != TFib ) {
++ FsaCommPrint("Error CompleteFib called with a non Fib structure.\n");
++ return(STATUS_UNSUCCESSFUL);
++ }
++
++
++ Fib->Header.XferState = 0;
++
++ return(STATUS_SUCCESS);
++
++}
++
++
++AAC_STATUS
++GetResponse(
++ IN PCOMM_QUE ResponseQueue,
++ OUT PFIB Fib
++ )
++/*++
++
++Routine Description:
++
++ Gets a QE off the requested response queue and gets the response FIB into
++ host memory. The FIB may already be in host memory depending on the bus
++ interface, or may require the host to DMA it over from the adapter. The routine
++ will return the FIB to the caller.
++
++Arguments:
++
++ ResponseQueue - Is the queue the caller wishes to have the response gotten from.
++ Fib - Is the Fib which was the response from the adapter
++
++Return Value:
++
++ NT_SUCCESS if a Fib was returned to the caller.
++ NT_ERROR if there was no Fib to return to the caller.
++ bkpfix - add in all the other possible errors ect
++
++--*/
++{
++return(STATUS_UNSUCCESSFUL);
++}
++
++//
++// Commuication primitives define and support the queuing method we use to
++// support host to adapter commuication. All queue accesses happen through
++// these routines and are the only routines which have a knowledge of the
++// how these queues are implemented.
++//
++
++
++/*++
++
++Routine Description:
++
++ With a priority the routine returns a queue entry if the queue has free entries. If the queue
++ is full(no free entries) than no entry is returned and the function returns FALSE otherwise TRUE is
++ returned.
++
++Arguments:
++
++ Priority is an enumerated type which determines which priority level
++ command queue the QE is going to be queued on.
++
++ Entry is a pointer to the address of where to return the address of
++ the queue entry from the requested command queue.
++
++ Index is a pointer to the address of where to store the index of the new
++ queue entry returned.
++
++ DontInterrupt - We set this true if the queue state is such that we don't
++ need to interrupt the adapter for this queue entry.
++
++Return Value:
++
++ TRUE - If a queue entry is returned
++ FALSE - If there are no free queue entries on the requested command queue.
++
++--*/
++BOOLEAN
++GetEntry (IN PAFA_COMM_ADAPTER Adapter, IN QUEUE_TYPES WhichQueue,
++ OUT PQUEUE_ENTRY *Entry, OUT PQUEUE_INDEX Index,
++ OUT ULONG *DontInterrupt)
++{
++ ULONG QueueOffset;
++ BOOLEAN status;
++ PCOMM_REGION CommRegion;
++
++ CommRegion = Adapter->CommRegion;
++
++ //
++ // All of the queues wrap when they reach the end, so we check to see if they
++ // have reached the end and if they have we just set the index back to zero.
++ // This is a wrap. You could or off the high bits in all updates but this is
++ // a bit faster I think.
++ //
++
++ if (WhichQueue == AdapHighCmdQueue) {
++ *Index = *(CommRegion->AdapHighCmdQue.Headers.ProducerIndex);
++
++ if (*Index - 2 == *(CommRegion->AdapHighCmdQue.Headers.ConsumerIndex))
++ *DontInterrupt = TRUE;
++
++ if (*Index >= ADAP_HIGH_CMD_ENTRIES)
++ *Index = 0;
++
++ if (*Index + 1 == *(CommRegion->AdapHighCmdQue.Headers.ConsumerIndex)) { // Queue is full
++ status = FALSE;
++ cmn_err(CE_WARN, "Adapter High Command Queue full, %d outstanding",
++ CommRegion->AdapHighCmdQue.NumOutstandingIos);
++ } else {
++ QueueOffset = sizeof(QUEUE_ENTRY) * (*Index);
++ *Entry = QueueOffset + CommRegion->AdapHighCmdQue.BaseAddress;
++
++ status = TRUE;
++ }
++ } else if (WhichQueue == AdapNormCmdQueue) {
++
++ *Index = *(CommRegion->AdapNormCmdQue.Headers.ProducerIndex);
++
++ if (*Index - 2 == *(CommRegion->AdapNormCmdQue.Headers.ConsumerIndex))
++ *DontInterrupt = TRUE;
++
++ //
++ // If we are at the end of the QUEUE then wrap back to
++ // the beginning.
++ //
++
++ if (*Index >= ADAP_NORM_CMD_ENTRIES)
++ *Index = 0; // Wrap to front of the Producer Queue.
++
++ //
++ // The IEEE spec says that it the producer is one behind the consumer then
++ // the queue is full.
++ //
++
++ ASSERT(*(CommRegion->AdapNormCmdQue.Headers.ConsumerIndex) != 0);
++
++ if (*Index + 1 == *(CommRegion->AdapNormCmdQue.Headers.ConsumerIndex)) { // Queue is full
++ cmn_err(CE_WARN, "Adapter Norm Command Queue full, %d outstanding",
++ CommRegion->AdapNormCmdQue.NumOutstandingIos);
++ status = FALSE;
++ } else {
++ //
++ // The success case just falls through and returns the a valid queue entry.
++ //
++
++#ifdef commdebug
++ FsaCommPrint("queue entry = %x.\n",CommRegion->AdapNormCmdQue.BaseAddress + *Index);
++ FsaCommPrint("GetEntry: Index = %d, QueueOffset = %x, Entry = %x, *Entry = %x.\n",
++ *Index, QueueOffset, Entry, *Entry);
++#endif
++ *Entry = CommRegion->AdapNormCmdQue.BaseAddress + *Index;
++
++ status = TRUE;
++ }
++ } else if (WhichQueue == AdapHighRespQueue) {
++
++ *Index = *(CommRegion->AdapHighRespQue.Headers.ProducerIndex);
++
++ if (*Index - 2 == *(CommRegion->AdapHighRespQue.Headers.ConsumerIndex))
++ *DontInterrupt = TRUE;
++
++ if (*Index >= ADAP_HIGH_RESP_ENTRIES)
++ *Index = 0;
++
++ if (*Index + 1 == *(CommRegion->AdapHighRespQue.Headers.ConsumerIndex)) { // Queue is full
++ status = FALSE;
++ cmn_err(CE_WARN, "Adapter High Resp Queue full, %d outstanding",
++ CommRegion->AdapHighRespQue.NumOutstandingIos);
++ } else {
++ *Entry = CommRegion->AdapHighRespQue.BaseAddress + *Index;
++ status = TRUE;
++ }
++ } else if (WhichQueue == AdapNormRespQueue) {
++
++ *Index = *(CommRegion->AdapNormRespQue.Headers.ProducerIndex);
++
++ if (*Index - 2 == *(CommRegion->AdapNormRespQue.Headers.ConsumerIndex))
++ *DontInterrupt = TRUE;
++
++ //
++ // If we are at the end of the QUEUE then wrap back to
++ // the beginning.
++ //
++
++ if (*Index >= ADAP_NORM_RESP_ENTRIES)
++ *Index = 0; // Wrap to front of the Producer Queue.
++
++ //
++ // The IEEE spec says that it the producer is one behind the consumer then
++ // the queue is full.
++ //
++
++ if (*Index + 1 == *(CommRegion->AdapNormRespQue.Headers.ConsumerIndex)) { // Queue is full
++ status = FALSE;
++ cmn_err(CE_WARN, "Adapter Norm Resp Queue full, %d outstanding",
++ CommRegion->AdapNormRespQue.NumOutstandingIos);
++ } else {
++ //
++ // The success case just falls through and returns the a valid queue entry.
++ //
++
++ *Entry = CommRegion->AdapNormRespQue.BaseAddress + *Index;
++
++#ifdef commdebug
++ FsaCommPrint("queue entry = %x.\n",CommRegion->AdapNormRespQue.BaseAddress + *Index);
++ FsaCommPrint("GetEntry: Index = %d, Entry = %x, *Entry = %x.\n",*Index, Entry, *Entry);
++#endif
++ status = TRUE;
++ }
++ } else {
++ cmn_err(CE_PANIC, "GetEntry: invalid queue %d", WhichQueue);
++ }
++
++
++ return (status);
++}
++
++
++
++#ifdef API_THROTTLE
++
++void ThrottleCheck(
++ IN PAFA_COMM_ADAPTER Adapter,
++ IN PFIB Fib
++ )
++/*++
++
++Routine Description:
++
++ This routine implements data I/O throttling. Throttling occurs when
++ a CLI FIB is detected. To ensure the CLI responds quickly (the user
++ is waiting for the response), this mechanism restricts the queue
++ depth of data IOs at the adapter for a period of time (called the
++ Throttle Period, default 5 seconds).
++
++ The mechanism uses a counted semaphore to place threads into a wait
++ state should there be too many data I/Os outstanding.
++
++ At the start of a throttle period (indicated by the first CLI FIB)
++ a timer is started. When the timer expires, new requests can go to
++ the adapter freely. Throttled requests gradually drain to the
++ adapter as each outstanding throttle I/O completes.
++
++ To avoid hurting regular I/O performance, we use a flag in the FIB
++ header to mark FIBs involved in throttling. This means we only need
++ take the extra spinlock in the response DPC routine for FIBs who
++ were subject to throttling. If no throttling is occurring, the cost
++ to the regular code paths is a handful of instructions.
++
++Arguments:
++
++ Adapter - Pointer to per-adapter context. This is used to locate the
++ throttle information for this adapter.
++
++ Fib - Pointer to the header for the fib being sent.
++
++Return Value:
++
++ None.
++
++--*/
++{
++ PCOMM_REGION CommRegion = Adapter->CommRegion;
++ AAC_STATUS Status;
++
++ //
++ // This routine is called under protection of the queue spinlock.
++ // As such we are allowed to check and change the counts for the
++ // throttle.
++ // Check the FIB. If its not a data operation, send it on without
++ // throttle check. If it is a data operation, check for throttle.
++ //
++
++ CommRegion->TotalFibs++; // Keep statistics
++
++ if ((Fib->Header.XferState & ApiFib) != 0) {
++
++ CommRegion->ApiFibs++; // Keep statistics
++
++ //
++ // Its an API fib. If the throttle is not already active,
++ // make it so. This will prevent new data Fibs being sent
++ // if they exceed the throttle check.
++ //
++
++ if (!CommRegion->ThrottleActive) {
++ BOOLEAN InQue;
++
++ CommRegion->ThrottleActive = TRUE; // This causes new data I/Os to be throttled
++
++ //
++ // Schedule a timer for the throttle active period. When
++ // it expires, we'll be called back at routine ThrottleDpcRoutine
++ // above. This will signify the throttle active period ended
++ // and any waiting threads will be signalled to restart.
++ //
++
++ FsaCommPrint("Throttle Period Start - CommRegion: %x\n", CommRegion);
++ CommRegion->ThrottleTimerSets++;
++ InQue = KeSetTimer( &CommRegion->ThrottleTimer,
++ CommRegion->ThrottleTimeout,
++ &CommRegion->ThrottleDpc);
++ ASSERT(InQue == FALSE);
++ }
++
++ return;
++ }
++
++ //
++ // Its a non-API fib, so subject to throttle checks.
++ // The following are exempt from throttling:
++ // o FIBs marked as "throttle exempt" by upper layers.
++ // o I/Os issued from a raised IRQL. We can't suspend
++ // a thread when at raised IRQL so throttling is exempt.
++ //
++
++ if (CommRegion->AdapNormCmdQue.SavedIrql != PASSIVE_LEVEL) {
++
++ CommRegion->NonPassiveFibs++;
++ FsaCommPrint("ThrottleCheck: Non-Passive level FIB bypasses throttle: %x\n", Fib);
++ return;
++
++ }
++
++ if (CommRegion->ThrottleActive) {
++
++ //
++ // Throttle is active.
++ // Check if the FIB is a read or write. If so, and its to the
++ // file system information area, let it through without throttling.
++ //
++
++ if (Fib->Header.Command == ContainerCommand) {
++ PBLOCKREAD BlockDisk = (PBLOCKREAD) &Fib->data;
++
++ //
++ // *** Note *** We are using read and write command formats
++ // interchangably here. This is ok for this purpose as the
++ // command is in the same place for both. Read and write command
++ // formats are different at higher offsets though.
++ //
++
++ if ( ((BlockDisk->Command == VM_CtBlockRead) ||
++ (BlockDisk->Command == VM_CtBlockWrite)) &&
++ (BlockDisk->BlockNumber <= FILESYSTEM_INFO_MAX_BLKNO)) {
++
++ CommRegion->FSInfoFibs++; // Keep statistics
++ return;
++
++ }
++
++ }
++
++ //
++ // Throttle the FIB.
++ // Mark it as throttle active so that it can signal a waiter
++ // when it completes.
++
++ CommRegion->ThrottledFibs++;
++ Fib->Header.Flags |= ThrottledFib;
++
++ //
++ // Release the spinlock so we can wait the thread if necessary.
++ // Since we specify a timeout, check the caller is at passive level.
++ //
++
++ OsSpinLockRelease((CommRegion->AdapNormCmdQue.QueueLock), CommRegion->AdapNormCmdQue.SavedIrql);
++
++ FsaCommPrint("ThrottleCheck - Thread Suspension - FIB: %x\n", Fib);
++
++ Status = KeWaitForSingleObject(&CommRegion->ThrottleReleaseSema,
++ Executive, // Don't allow user APCs to wake us
++ KernelMode, // Wait in kernel mode
++ FALSE, // Not alertable
++ &CommRegion->ThrottleWaitTimeout); // Timeout after this time
++
++ //
++ // Check the signal status. If we've timed out, clear the throttle
++ // flag on the FIB to avoid us signalling the semaphore on completion.
++ // We never acquired the semaphore.
++ //
++ if (Status == STATUS_TIMEOUT) {
++
++ CommRegion->ThrottleTimedoutFibs++;
++ FsaCommPrint("ThrottledFib Timed Out - FIB: %x\n", Fib);
++ Fib->Header.Flags &= ~ThrottledFib; // Clear the throttledfib flag
++
++ } else {
++
++ ASSERT(Status == STATUS_SUCCESS); // No other return is possible
++
++ }
++
++ //
++ // We've been woken up and can now send the FIB to the adapter.
++ // Acquire the spinlock again so we can get a queue entry. This
++ // returns to GetQueueEntry.
++ //
++
++ FsaCommPrint("ThrottleCheck - Thread Resume - FIB: %x\n", Fib);
++ KeAcquireSpinLock((CommRegion->AdapNormCmdQue.QueueLock), &(CommRegion->AdapNormCmdQue.SavedIrql));
++ CommRegion->ThrottleOutstandingFibs++; // There's another throttle controlled FIB going.
++ return;
++
++ }
++}
++
++#endif //#ifdef API_THROTTLE
++
++int GetQueueEntryTimeouts = 0;
++
++
++/*++
++
++Routine Description:
++
++ Gets the next free QE off the requested priorty adapter command queue and
++ associates the Fib with the QE. The QE represented by index is ready to
++ insert on the queue when this routine returns success.
++
++Arguments:
++
++ Index is the returned value which represents the QE which is ready to
++ insert on the adapter's command queue.
++
++ Priority is an enumerated type which determines which priority level
++ command queue the QE is going to be queued on.
++
++ Fib is a pointer to the FIB the caller wishes to have associated with the
++ QE.
++
++ Wait is a boolean which determines if the routine will wait if there are
++ no free QEs on the requested priority command queue.
++
++ FibContext is where the driver stores all system resources required to execute the
++ command requested from the calling thread. This includes mapping resources for
++ the FIB and the 'users' buffer.
++
++ DontInterrupt - We set this true if the queue state is such that we don't
++ need to interrupt the adapter for this queue entry.
++
++Return Value:
++
++ NT_SUCCESS if a Fib was returned to the caller.
++ NT_ERROR if event was an invalid event.
++
++--*/
++AAC_STATUS
++GetQueueEntry (IN PAFA_COMM_ADAPTER Adapter, OUT PQUEUE_INDEX Index,
++ IN QUEUE_TYPES WhichQueue, IN PFIB Fib, IN BOOLEAN Wait,
++ IN PCOMM_FIB_CONTEXT FibContext, OUT ULONG *DontInterrupt)
++{
++ PQUEUE_ENTRY QueueEntry = NULL;
++ BOOLEAN MapAddress = FALSE;
++ int timeouts = 0;
++ AAC_STATUS Status;
++ PCOMM_REGION CommRegion;
++
++ CommRegion = Adapter->CommRegion;
++
++ //
++ // Get the spinlock for the queue we are putting a command on
++ //
++
++ if (WhichQueue == AdapHighCmdQueue)
++ OsSpinLockAcquire(CommRegion->AdapHighCmdQue.QueueLock);
++ else if (WhichQueue == AdapNormCmdQueue)
++ OsSpinLockAcquire(CommRegion->AdapNormCmdQue.QueueLock);
++ else if (WhichQueue == AdapHighRespQueue)
++ OsSpinLockAcquire(CommRegion->AdapHighRespQue.QueueLock);
++ else if (WhichQueue == AdapNormRespQueue)
++ OsSpinLockAcquire(CommRegion->AdapNormRespQue.QueueLock);
++ else {
++ FsaCommPrint("Invalid queue priority passed to GetQueueEntry.\n");
++ return(FSA_INVALID_QUEUE);
++ }
++
++ //
++ // Get the pointers to a queue entry on the queue the caller wishes to queue
++ // a command request on. If there are no entries then wait if that is what the
++ // caller requested.
++ //
++
++ if (WhichQueue == AdapHighCmdQueue) {
++ // if no entries wait for some if caller wants to
++ while ( !GetEntry(Adapter, AdapHighCmdQueue, &QueueEntry, Index, DontInterrupt) ) {
++ cmn_err(CE_PANIC, "GetEntries failed (1)\n");
++ }
++
++ //
++ // Setup queue entry with a command, status and Fib mapped
++ //
++
++ QueueEntry->Size = Fib->Header.Size;
++ MapAddress = TRUE;
++
++ } else if (WhichQueue == AdapNormCmdQueue) {
++ // if no entries wait for some if caller wants to
++ while ( !GetEntry(Adapter, AdapNormCmdQueue, &QueueEntry, Index, DontInterrupt) ) {
++ cmn_err(CE_PANIC, "GetEntries failed (2)\n");
++ }
++
++ //
++ // Setup queue entry with command, status and Fib mapped
++ //
++
++ QueueEntry->Size = Fib->Header.Size;
++ MapAddress = TRUE;
++
++ } else if (WhichQueue == AdapHighRespQueue) {
++
++ while ( !GetEntry(Adapter, AdapHighRespQueue, &QueueEntry, Index, DontInterrupt) ) { // if no entries wait for some if caller wants to
++ }
++
++ //
++ // Setup queue entry with command, status and Fib mapped
++ //
++
++ QueueEntry->Size = Fib->Header.Size;
++ QueueEntry->FibAddress = Fib->Header.SenderFibAddress; // Restore adapters pointer to the FIB
++ Fib->Header.ReceiverFibAddress = Fib->Header.SenderFibAddress; // Let the adapter now where to find its data
++ MapAddress = FALSE;
++
++ } else if (WhichQueue == AdapNormRespQueue) {
++ while ( !GetEntry(Adapter, AdapNormRespQueue, &QueueEntry, Index, DontInterrupt) ) { // if no entries wait for some if caller wants to
++ }
++
++ //
++ // Setup queue entry with command, status, adapter's pointer to the Fib it sent
++ //
++
++ QueueEntry->Size = Fib->Header.Size;
++ QueueEntry->FibAddress = Fib->Header.SenderFibAddress; // Restore adapters pointer to the FIB
++ Fib->Header.ReceiverFibAddress = Fib->Header.SenderFibAddress; // Let the adapter now where to find its data
++ MapAddress = FALSE;
++ }
++
++ //
++ // If MapFib is true than we need to map the Fib and put pointers in the queue entry.
++ //
++
++ if (MapAddress) {
++ QueueEntry->FibAddress = (ULONG)(FibContext->LogicalFibAddress.LowPart);
++ }
++
++ //
++ // Return
++ //
++#ifdef commdebug
++ FsaCommPrint("Queue Entry contents:.\n");
++ FsaCommPrint(" Command = %d.\n", QueueEntry->Command);
++ FsaCommPrint(" Status = %x.\n", QueueEntry->Status);
++ FsaCommPrint(" Rec Fib address low = %x.\n", QueueEntry->FibAddressLow);
++ FsaCommPrint(" Fib size in bytes = %d.\n", QueueEntry->Size);
++#endif
++
++ return(FSA_SUCCESS);
++}
++
++
++/*++
++
++Routine Description:
++
++ Gets the next free QE off the requested priorty adapter command queue and
++ associates the Fib with the QE. The QE represented by index is ready to
++ insert on the queue when this routine returns success.
++
++Arguments:
++
++ Index is the returned value which represents the QE which is ready to
++ insert on the adapter's command queue.
++
++ WhichQueue tells us which queue the caller wishes to have the entry put.
++
++Return Value:
++
++ NT_SUCCESS if a Fib was returned to the caller.
++ NT_ERROR if event was an invalid event.
++
++--*/
++AAC_STATUS
++InsertQueueEntry(
++ IN PAFA_COMM_ADAPTER Adapter,
++ IN QUEUE_INDEX Index,
++ IN QUEUE_TYPES WhichQueue,
++ IN ULONG DontInterrupt
++ )
++{
++ PCOMM_REGION CommRegion;
++
++ CommRegion = Adapter->CommRegion;
++
++ //
++ // We have already verified the queue in getentry, but we still have to make
++ // sure we don't wrap here too.
++ //
++
++ if (WhichQueue == AdapHighCmdQueue) {
++
++ *(CommRegion->AdapHighCmdQue.Headers.ProducerIndex) = Index + 1;
++
++ OsSpinLockRelease(CommRegion->AdapHighCmdQue.QueueLock);
++
++ if (!DontInterrupt)
++ NotifyAdapter(Adapter, AdapHighCmdQue);
++
++ } else if (WhichQueue == AdapNormCmdQueue) {
++
++#ifdef commdebug
++ FsaCommPrint("InsertQueueEntry: Inerting with an index of %d.\n",Index);
++#endif
++ *(CommRegion->AdapNormCmdQue.Headers.ProducerIndex) = Index + 1;
++
++ OsSpinLockRelease(CommRegion->AdapNormCmdQue.QueueLock);
++
++ if (!DontInterrupt)
++ NotifyAdapter(Adapter, AdapNormCmdQue);
++
++ } else if (WhichQueue == AdapHighRespQueue) {
++
++ *(CommRegion->AdapHighRespQue.Headers.ProducerIndex) = Index + 1;
++
++ OsSpinLockRelease(CommRegion->AdapHighRespQue.QueueLock);
++
++ if (!DontInterrupt)
++ NotifyAdapter(Adapter, AdapHighRespQue);
++
++ } else if (WhichQueue == AdapNormRespQueue) {
++
++ *(CommRegion->AdapNormRespQue.Headers.ProducerIndex) = Index + 1;
++
++ OsSpinLockRelease(CommRegion->AdapNormRespQue.QueueLock);
++
++ if (!DontInterrupt)
++ NotifyAdapter(Adapter, AdapNormRespQue);
++
++ } else {
++ FsaCommPrint("Invalid queue priority passed to InsertQueueEntry.\n");
++ return(FSA_INVALID_QUEUE_PRIORITY);
++ }
++
++ return(FSA_SUCCESS);
++}
++
++extern int GatherFibTimes;
++
++BOOLEAN
++SendSynchFib(
++ PVOID Arg,
++ FIB_COMMAND Command,
++ PVOID Data,
++ USHORT Size,
++ PVOID Response,
++ USHORT *ResponseSize
++ )
++/*++
++
++Routine Description:
++
++ This routine will send a synchronous FIB to the adapter and wait for its
++ completion.
++
++Arguments:
++
++ DeviceExtension - Pointer to adapter extension structure.
++
++
++Return Value:
++
++ BOOLEAN
++
++--*/
++{
++ PAFA_COMM_ADAPTER Adapter = Arg;
++ FIB *Fib;
++ ULONG returnStatus;
++
++ Fib = Adapter->SyncFib;
++
++ Fib->Header.StructType = TFib;
++ Fib->Header.Size = sizeof(FIB);
++ Fib->Header.XferState = HostOwned | FibInitialized | FibEmpty;
++ Fib->Header.ReceiverFibAddress = 0;
++ Fib->Header.SenderSize = sizeof(FIB);
++ Fib->Header.SenderFibAddress = (ULONG)Fib;
++ Fib->Header.Command = Command;
++
++ //
++ // Copy the Data portion into the Fib.
++ //
++
++ RtlCopyMemory( Fib->data, Data, Size );
++
++
++ Fib->Header.XferState |= (SentFromHost | NormalPriority);
++
++ //
++ // Set the size of the Fib we want to send to the adapter
++ //
++
++ Fib->Header.Size = sizeof(FIB_HEADER) + Size;
++
++ if (!Adapter->AdapterFuncs->SendSynchFib( Adapter->AdapterExtension,
++ Adapter->SyncFibPhysicalAddress )) {
++
++ return (FALSE);
++
++ }
++
++ //
++ // Copy the response back to the caller's buffer.
++ //
++
++ RtlCopyMemory( Response, Fib->data, Fib->Header.Size - sizeof(FIB_HEADER) );
++
++ *ResponseSize = Fib->Header.Size - sizeof(FIB_HEADER);
++
++ //
++ // Indicate success
++ //
++
++ return (TRUE);
++}
++
++//
++// Define the highest level of host to adapter communication routines. These
++// routines will support host to adapter FS commuication. These routines have
++// no knowledge of the commuication method used. This level sends and receives
++// FIBs. This level has no knowledge of how these FIBs get passed back and forth.
++//
++
++
++
++/*++
++
++Routine Description:
++
++ Sends the requested FIB to the adapter and optionally will wait for a
++ response FIB. If the caller does not wish to wait for a response than
++ an event to wait on must be supplied. This event will be set when a
++ response FIB is received from the adapter.
++
++Arguments:
++
++ Fib is a pointer to the FIB the caller wishes to send to the adapter.
++
++ Size - Size of the data portion of the Fib.
++
++ Priority is an enumerated type which determines which priority level
++ the caller wishes to send this command at.
++
++ Wait is a boolean which determines if the routine will wait for the
++ completion Fib to be returned(TRUE), or return when the Fib has been
++ successfully received by the adapter(FALSE).
++
++ WaitOn is only vaild when Wait is FALSE. The Event will be set when the response
++ FIB has been returned by the adapter.
++
++ ReturnFib is an optional pointer to a FIB that if present the response FIB will
++ copied to.
++
++Return Value:
++
++ NT_SUCCESS if a Fib was returned to the caller.
++ NT_ERROR if event was an invalid event.
++
++ --*/
++AAC_STATUS
++SendFib (IN FIB_COMMAND Command,
++ IN PFIB_CONTEXT Context,
++ IN ULONG Size,
++ IN COMM_PRIORITIES Priority,
++ IN BOOLEAN Wait,
++ IN PVOID WaitOn,
++ IN BOOLEAN ResponseExpected,
++ IN PFIB_CALLBACK FibCallback,
++ IN PVOID FibCallbackContext)
++{
++ PCOMM_FIB_CONTEXT FibContext = (PCOMM_FIB_CONTEXT) Context;
++ QUEUE_INDEX Index;
++ QUEUE_TYPES WhichQueue;
++ LARGE_INTEGER Timeout;
++ AAC_STATUS Status;
++ PAFA_COMM_ADAPTER Adapter = FibContext->Adapter;
++ ULONG DontInterrupt = FALSE;
++ PFIB Fib = FibContext->Fib;
++ IN PCOMM_QUE OurQueue;
++
++ Timeout = FsaCommData.AdapterTimeout;
++
++ if (!(Fib->Header.XferState & HostOwned)) {
++ FsaCommPrint("SendFib was called with a xfer state not set to HostOwned!\n");
++ FsaCommLogEvent(FibContext,
++ FsaCommData.DeviceObject,
++ FSAFS_FIB_INVALID,
++ STATUS_UNSUCCESSFUL,
++ BugCheckFileId | __LINE__,
++ FACILITY_FSAFS_ERROR_CODE,
++ NULL,
++ TRUE);
++
++ return(STATUS_UNSUCCESSFUL);
++
++ }
++
++ //
++ // There are 5 cases with the wait and reponse requested flags. The only invalid cases
++ // are if the caller requests to wait and does not request a response and if the
++ // caller does not want a response and the Fib is not allocated from pool. If a response
++ // is not requesed the Fib will just be deallocaed by the DPC routine when the response
++ // comes back from the adapter. No further processing will be done besides deleting the
++ // Fib. We will have a debug mode where the adapter can notify the host it had a problem
++ // and the host can log that fact.
++
++ if (Wait && !ResponseExpected) {
++
++ FsaCommLogEvent(FibContext,
++ FsaCommData.DeviceObject,
++ FSAFS_FIB_INVALID,
++ STATUS_UNSUCCESSFUL,
++ BugCheckFileId | __LINE__,
++ FACILITY_FSAFS_ERROR_CODE,
++ NULL,
++ TRUE);
++
++ return(STATUS_UNSUCCESSFUL);
++
++ } else if (!Wait && ResponseExpected) {
++ Fib->Header.XferState |= (Async | ResponseExpected);
++ FIB_COUNTER_INCREMENT(FsaCommData.AsyncSent);
++ } else if (!Wait && !ResponseExpected) {
++ Fib->Header.XferState |= NoResponseExpected;
++ FIB_COUNTER_INCREMENT(FsaCommData.NoResponseSent);
++ } else if (Wait && ResponseExpected) {
++ Fib->Header.XferState |= ResponseExpected;
++ FIB_COUNTER_INCREMENT(FsaCommData.NormalSent);
++ }
++
++ Fib->Header.SenderData = (ULONG)FibContext; // so we can complete the io in the dpc routine
++
++ //
++ // Set FIB state to indicate where it came from and if we want a response from the
++ // adapter. Also load the command from the caller.
++ //
++
++ Fib->Header.SenderFibAddress = (ULONG)Fib;
++ Fib->Header.Command = Command;
++ Fib->Header.XferState |= SentFromHost;
++ FibContext->Fib->Header.Flags = 0; // Zero the flags field - its internal only...
++
++ //
++ // Set the size of the Fib we want to send to the adapter
++ //
++
++ Fib->Header.Size = sizeof(FIB_HEADER) + Size;
++ if (Fib->Header.Size > Fib->Header.SenderSize) {
++ return(STATUS_BUFFER_OVERFLOW);
++ }
++
++ //
++ // Get a queue entry connect the FIB to it and send an notify the adapter a command is ready.
++ //
++
++ if (Priority == FsaHigh) {
++ Fib->Header.XferState |= HighPriority;
++ WhichQueue = AdapHighCmdQueue;
++ OurQueue = &Adapter->CommRegion->AdapHighCmdQue;
++ } else {
++ Fib->Header.XferState |= NormalPriority;
++ WhichQueue = AdapNormCmdQueue;
++ OurQueue = &Adapter->CommRegion->AdapNormCmdQue;
++ }
++
++ if (Wait) {
++ OsCvLockAcquire( FibContext->FsaEventMutex );
++ }
++
++ if ( GetQueueEntry( Adapter, &Index, WhichQueue, Fib, TRUE, FibContext, &DontInterrupt) != FSA_SUCCESS )
++ return(STATUS_UNSUCCESSFUL);
++
++ // bmb debug
++
++ cmn_err (CE_DEBUG,"SendFib: inserting a queue entry at index %d.\n",Index);
++ cmn_err (CE_DEBUG,"Fib contents:.\n");
++ cmn_err (CE_DEBUG," Command = %d.\n", Fib->Header.Command);
++ cmn_err (CE_DEBUG," XferState = %x.\n", Fib->Header.XferState );
++
++ //
++ // Fill in the Callback and CallbackContext if we are not going to wait.
++ //
++
++ if (!Wait) {
++
++ FibContext->FibCallback = FibCallback;
++ FibContext->FibCallbackContext = FibCallbackContext;
++
++ }
++
++ FIB_COUNTER_INCREMENT(FsaCommData.FibsSent);
++
++ InsertTailList( &OurQueue->OutstandingIoQueue, &FibContext->QueueEntry );
++ OurQueue->NumOutstandingIos++;
++
++ FibContext->FibComplete = 0;
++
++
++
++ if ( InsertQueueEntry( Adapter, Index, WhichQueue, (DontInterrupt & FsaCommData.EnableInterruptModeration)) != FSA_SUCCESS )
++ return(STATUS_UNSUCCESSFUL);
++
++ //
++ // If the caller wanted us to wait for response wait now.
++ // If Timeouts are enabled than set the timeout otherwise wait forever.
++ //
++
++ if (Wait) {
++ while (FibContext->FibComplete == 0) {
++ OsCv_wait( &FibContext->FsaEvent, FibContext->FsaEventMutex );
++ }
++
++ OsCvLockRelease( FibContext->FsaEventMutex );
++
++ if ( (FibContext->Flags & FIB_CONTEXT_FLAG_TIMED_OUT) ) {
++ return(STATUS_IO_TIMEOUT);
++ } else {
++ return(STATUS_SUCCESS);
++ }
++ }
++
++ //
++ // If the user does not want a response than return success otherwise return pending
++ //
++
++ ASSERT( FibCallback );
++
++ if (ResponseExpected)
++ return(STATUS_PENDING);
++ else
++ return(STATUS_SUCCESS);
++}
++
++BOOLEAN
++GetConsumerEntry(
++ IN PAFA_COMM_ADAPTER Adapter,
++ PCOMM_QUE OurQueue,
++ OUT PQUEUE_ENTRY *Entry
++ )
++/*++
++
++Routine Description:
++
++ Will return a pointer to the entry on the top of the queue requested that we are a consumer
++ of, and return the address of the queue entry. It does not change the state of the queue.
++
++Arguments:
++
++ OurQueue - is the queue the queue entry should be removed from.
++
++ Entry - is a pointer where the address of the queue entry should be returned.
++
++Return Value:
++
++ TRUE if there was a queue entry on the response queue for the host to consume.
++ FALSE if there were no queue entries to consume.
++
++--*/
++
++{
++ QUEUE_INDEX Index;
++ BOOLEAN status;
++
++ if (*OurQueue->Headers.ProducerIndex == *OurQueue->Headers.ConsumerIndex) {
++ status = FALSE;
++ } else {
++
++ //
++ // The consumer index must be wrapped if we have reached the end of
++ // the queue.
++ // Else we just use the entry pointed to by the header index
++ //
++
++ if (*OurQueue->Headers.ConsumerIndex >= OurQueue->QueueEntries)
++ Index = 0;
++ else
++ Index = *OurQueue->Headers.ConsumerIndex;
++
++ *Entry = OurQueue->BaseAddress + Index;
++
++#ifdef commdebug
++ FsaCommPrint("Got a QE at Index %d, QE Addrss of %x.\n",Index,*Entry);
++#endif
++ status = TRUE;
++ }
++
++ return(status);
++}
++
++BOOLEAN
++ConsumerEntryAvailable(
++ IN PAFA_COMM_ADAPTER Adapter,
++ PCOMM_QUE OurQueue
++ )
++{
++ return (*OurQueue->Headers.ProducerIndex != *OurQueue->Headers.ConsumerIndex);
++}
++
++VOID
++FreeConsumerEntry(
++ IN PAFA_COMM_ADAPTER Adapter,
++ PCOMM_QUE OurQueue,
++ QUEUE_TYPES WhichQueue
++ )
++/*++
++
++Routine Description:
++
++ Frees up the current top of the queue we are a consumer of. If the queue was full
++ notify the producer that the queue is no longer full.
++
++Arguments:
++
++ OurQueue - is the queue we will free the current consumer entry on.
++
++Return Value:
++
++ TRUE if there was a queue entry on the response queue for the host to consume.
++ FALSE if there were no queue entries to consume.
++
++--*/
++
++{
++ BOOLEAN WasFull = FALSE;
++ HOST_2_ADAP_EVENT Notify;
++
++ if (*OurQueue->Headers.ProducerIndex+1 == *OurQueue->Headers.ConsumerIndex)
++ WasFull = TRUE;
++
++ if (*OurQueue->Headers.ConsumerIndex >= OurQueue->QueueEntries)
++ *OurQueue->Headers.ConsumerIndex = 1;
++ else
++ *OurQueue->Headers.ConsumerIndex += 1;
++
++ if (WasFull) {
++ switch (WhichQueue) {
++
++ case HostNormCmdQueue:
++ Notify = HostNormCmdNotFull;
++ break;
++ case HostHighCmdQueue:
++ Notify = HostHighCmdNotFull;
++ break;
++
++ case HostNormRespQueue:
++ Notify = HostNormRespNotFull;
++ break;
++
++ case HostHighRespQueue:
++ Notify = HostHighRespNotFull;
++ break;
++
++ }
++ NotifyAdapter(Adapter, Notify);
++ }
++
++}
++
++AAC_STATUS
++CompleteAdapterFib(
++ IN PFIB_CONTEXT Context,
++ IN USHORT Size
++ )
++/*++
++
++Routine Description:
++
++ Will do all necessary work to complete a FIB that was sent from the adapter.
++
++Arguments:
++
++ Fib is a pointer to the FIB that caller wishes to complete processing on.
++
++ Size - Size of the completion Packet(Opitional). If not present than the current
++ largest size in the Fib will be used
++
++ Adapter - Pointer to which adapter sent this FIB
++
++Return Value:
++
++ NT_SUCCESS if a Fib was returned to the caller.
++ NT_ERROR if event was an invalid event.
++
++--*/
++{
++ PCOMM_FIB_CONTEXT FibContext = Context;
++ PFIB Fib = FibContext->Fib;
++ PAFA_COMM_ADAPTER Adapter = FibContext->Adapter;
++ ULONG DontInterrupt = FALSE;
++
++ if (Fib->Header.XferState == 0)
++ return(STATUS_SUCCESS);
++
++ //
++ // If we plan to do anything check the structure type first.
++ //
++
++ if ( Fib->Header.StructType != TFib ) {
++ FsaCommPrint("Error CompleteFib called with a non Fib structure.\n");
++ return(STATUS_UNSUCCESSFUL);
++ }
++
++ //
++ // This block handles the case where the adapter had sent us a command and we
++ // have finished processing the command. We call completeFib when we are done
++ // processing the command and want to send a response back to the adapter. This
++ // will send the completed cdb to the adapter.
++ //
++
++ if (Fib->Header.XferState & SentFromAdapter) {
++ Fib->Header.XferState |= HostProcessed;
++ if (Fib->Header.XferState & HighPriority) {
++ QUEUE_INDEX Index;
++
++ if (Size) {
++ Size += sizeof(FIB_HEADER);
++ if (Size > Fib->Header.SenderSize)
++ return(STATUS_BUFFER_OVERFLOW);
++ Fib->Header.Size = Size;
++ }
++
++ if (GetQueueEntry(Adapter, &Index, AdapHighRespQueue, Fib, TRUE, NULL, &DontInterrupt) != STATUS_SUCCESS) {
++ FsaCommPrint("CompleteFib got an error geting a queue entry for a response.\n");
++ return(FSA_FATAL);
++ }
++ if (InsertQueueEntry(Adapter,
++ Index,
++ AdapHighRespQueue,
++ (DontInterrupt & (BOOLEAN)FsaCommData.EnableInterruptModeration)) != STATUS_SUCCESS) {
++ FsaCommPrint("CompleteFib failed while inserting entry on the queue.\n");
++ }
++ } else if (Fib->Header.XferState & NormalPriority) {
++ QUEUE_INDEX Index;
++
++ if (Size) {
++ Size += sizeof(FIB_HEADER);
++ if (Size > Fib->Header.SenderSize)
++ return(STATUS_BUFFER_OVERFLOW);
++ Fib->Header.Size = Size;
++ }
++
++ if (GetQueueEntry(Adapter, &Index, AdapNormRespQueue, Fib, TRUE, NULL, &DontInterrupt) != STATUS_SUCCESS) {
++ FsaCommPrint("CompleteFib got an error geting a queue entry for a response.\n");
++ return(FSA_FATAL);
++ }
++ if (InsertQueueEntry(Adapter,
++ Index,
++ AdapNormRespQueue,
++ (DontInterrupt & (BOOLEAN)FsaCommData.EnableInterruptModeration)) != STATUS_SUCCESS) {
++ FsaCommPrint("CompleteFib failed while inserting entry on the queue.\n");
++ }
++ }
++ } else {
++ cmn_err(CE_WARN, "CompleteFib: Unknown xferstate detected.\n");
++ FsaBugCheck(0,0,0);
++ }
++ return(STATUS_SUCCESS);
++}
++
++AAC_STATUS
++CompleteFib(
++ IN PFIB_CONTEXT Context
++ )
++/*++
++
++Routine Description:
++
++ Will do all necessary work to complete a FIB. If the caller wishes to
++ reuse the FIB after post processing has been completed Reinitialize
++ should be called set to TRUE, otherwise the FIB will be returned to the
++ free FIB pool. If Reinitialize is set to TRUE then the FIB header is
++ reinitialzied and is ready for reuse on return from this routine.
++
++Arguments:
++
++ Fib is a pointer to the FIB that caller wishes to complete processing on.
++
++ Size - Size of the completion Packet(Opitional). If not present than the current
++ largest size in the Fib will be used
++
++ Reinitialize is a boolean which determines if the routine will ready the
++ completed FIB for reuse(TRUE) or not(FALSE).
++
++Return Value:
++
++ NT_SUCCESS if a Fib was returned to the caller.
++ NT_ERROR if event was an invalid event.
++
++--*/
++{
++ PCOMM_FIB_CONTEXT FibContext = (PCOMM_FIB_CONTEXT) Context;
++ PAFA_COMM_ADAPTER Adapter = FibContext->Adapter;
++ PFIB Fib = FibContext->Fib;
++
++ //
++ // Check for a fib which has already been completed
++ //
++
++// ASSERT(Fib->Header.XferState & AdapterProcessed);
++ if (Fib->Header.XferState == 0)
++ return(STATUS_SUCCESS);
++
++ //
++ // If we plan to do anything check the structure type first.
++ //
++
++ if ( Fib->Header.StructType != TFib ) {
++ FsaCommPrint("Error CompleteFib called with a non Fib structure.\n");
++ return(STATUS_UNSUCCESSFUL);
++ }
++
++#if 0
++//#if FSA_ADAPTER_METER
++ //
++ // Meter the completion
++ //
++ fsaMeterEnd( // meter the end of an operation
++ &(Adapter->FibMeter), // .. the meter
++ IrpContext->FibMeterType, // .. type of operation
++ &(IrpContext->FibStartTime), // .. ptr to operation start timestamp
++ FibGetMeterSize(Fib, // .. number of bytes in operation
++ IrpContext->FibMeterType,
++ IrpContext->FibSubCommand));
++#endif // FSA_ADAPTER_METER
++
++ //
++ // This block completes a cdb which orginated on the host and we just need
++ // to deallocate the cdb or reinit it. At this point the command is complete
++ // that we had sent to the adapter and this cdb could be reused.
++ //
++
++ if ( (Fib->Header.XferState & SentFromHost) &&
++ (Fib->Header.XferState & AdapterProcessed)) {
++
++ ASSERT(FibContext->LogicalFibAddress.LowPart != 0);
++
++ return( DeallocateFib(FibContext) );
++
++ //
++ // This handles the case when the host has aborted the I/O to the
++ // adapter because the adapter is not responding
++ //
++
++ } else if (Fib->Header.XferState & SentFromHost) {
++
++ ASSERT(FibContext->LogicalFibAddress.LowPart != 0);
++
++
++ return( DeallocateFib(FibContext) );
++
++ } else if (Fib->Header.XferState & HostOwned) {
++
++ return(DeallocateFib(FibContext));
++
++ } else {
++ cmn_err(CE_WARN, "CompleteFib: Unknown xferstate detected.\n");
++ FsaBugCheck(0,0,0);
++ }
++ return(STATUS_SUCCESS);
++}
++
++VOID
++HandleDriverAif(
++ IN PAFA_COMM_ADAPTER Adapter,
++ IN PCOMM_FIB_CONTEXT FibContext
++ )
++/*++
++
++Routine Description:
++
++ This routine handles a driver notify fib from the adapter and dispatches it to
++ the appropriate routine for handling.
++
++Arguments:
++
++ Adapter - Which adapter this fib is from
++ FibContext - Pointer to FibContext from adapter.
++
++Return Value:
++
++ Nothing.
++
++--*/
++{
++ PFIB Fib = FibContext->Fib;
++ PAFA_CLASS_DRIVER ClassDriver;
++ BOOLEAN Handled = FALSE;
++
++
++ //
++ // First loop through all of the class drivers to give them a chance to handle
++ // the Fib.
++ //
++
++ ClassDriver = Adapter->ClassDriverList;
++
++ while (ClassDriver) {
++
++ if (ClassDriver->HandleAif) {
++
++ if (ClassDriver->HandleAif( ClassDriver->ClassDriverExtension, FibContext ) ) {
++
++ Handled = TRUE;
++ break;
++
++ }
++ }
++
++ ClassDriver = ClassDriver->Next;
++ }
++
++ if (!Handled) {
++
++ //
++ // Set the status of this FIB to be Invalid parameter.
++ //
++
++// *(FSASTATUS *)Fib->data = ST_INVAL;
++ *(FSASTATUS *)Fib->data = ST_OK;
++
++
++ CompleteAdapterFib(FibContext, sizeof(FSASTATUS));
++
++ }
++}
++
++int
++NormCommandThread(
++ IN PAFA_COMM_ADAPTER Adapter
++ )
++/*++
++
++Routine Description:
++
++ Waits on the commandready event in it's queue. When the event gets set it will
++ pull FIBs off it's queue. It will continue to pull FIBs off till the queue is empty.
++ When the queue is empty it will wait for more FIBs.
++
++Arguments:
++
++ Context is used. All data os global
++
++Return Value:
++ Nothing.
++
++--*/
++{
++ PFIB Fib, NewFib;
++ COMM_FIB_CONTEXT FibContext; // for error logging
++ KIRQL SavedIrql;
++ PCOMM_REGION CommRegion = Adapter->CommRegion;
++ PLIST_ENTRY Entry;
++ PGET_ADAPTER_FIB_CONTEXT AdapterFibContext;
++
++ //
++ // We can only have one thread per adapter for AIF's.
++ //
++
++ if (Adapter->AifThreadStarted) {
++ return (EINVAL);
++ }
++
++// cmn_err(CE_DEBUG, "AIF thread started");
++
++ //
++ // Let the DPC know it has a place to send the AIF's to.
++ //
++
++ Adapter->AifThreadStarted = TRUE;
++
++ RtlZeroMemory(&FibContext, sizeof(COMM_FIB_CONTEXT));
++
++ OsSpinLockAcquire(CommRegion->HostNormCmdQue.QueueLock);
++
++ while (TRUE) {
++
++ //
++ // NOTE : the QueueLock is held at the top of each loop.
++ //
++
++ ASSERT(OsSpinLockOwned(CommRegion->HostNormCmdQue.QueueLock));
++
++ while (!IsListEmpty(&(CommRegion->HostNormCmdQue.CommandQueue))) {
++ PLIST_ENTRY Entry;
++ PAIFCOMMANDTOHOST AifCommandToHost;
++
++ Entry = RemoveHeadList(&(CommRegion->HostNormCmdQue.CommandQueue));
++
++ OsSpinLockRelease(CommRegion->HostNormCmdQue.QueueLock);
++
++ Fib = CONTAINING_RECORD( Entry, FIB, Header.FibLinks );
++
++ //
++ // We will process the FIB here or pass it to a worker thread that is TBD. We Really
++ // can't do anything at this point since we don't have anything defined for this thread to
++ // do.
++ //
++
++ // cmn_err(CE_DEBUG, "Got Fib from the adapter with a NORMAL priority, command 0x%x.\n", Fib->Header.Command);
++
++ RtlZeroMemory( &FibContext, sizeof(COMM_FIB_CONTEXT) );
++
++
++ FibContext.NodeTypeCode = FSAFS_NTC_FIB_CONTEXT;
++ FibContext.NodeByteSize = sizeof( COMM_FIB_CONTEXT );
++ FibContext.Fib = Fib;
++ FibContext.FibData = Fib->data;
++ FibContext.Adapter = Adapter;
++
++
++ //
++ // We only handle AifRequest fibs from the adapter.
++ //
++
++ ASSERT(Fib->Header.Command == AifRequest);
++
++
++ AifCommandToHost = (PAIFCOMMANDTOHOST) Fib->data;
++
++ if (AifCommandToHost->command == AifCmdDriverNotify) {
++
++
++
++ HandleDriverAif( Adapter, &FibContext );
++
++ } else {
++ AAC_UINT32 time_now, time_last;
++ time_now = (AAC_UINT32)OsGetSeconds();
++
++
++ OsCvLockAcquire(Adapter->AdapterFibMutex);
++
++ Entry = Adapter->AdapterFibContextList.Flink;
++
++ //
++ // For each Context that is on the AdapterFibContextList, make a copy of the
++ // fib, and then set the event to wake up the thread that is waiting for it.
++ //
++
++ while (Entry != &Adapter->AdapterFibContextList) {
++
++ //
++ // Extract the AdapterFibContext
++ //
++
++ AdapterFibContext = CONTAINING_RECORD( Entry, GET_ADAPTER_FIB_CONTEXT, NextContext );
++
++ //
++ // Check if the queue is getting backlogged
++ //
++ if ( AdapterFibContext->FibCount > 20 ) {
++ time_last = (AAC_UINT32)(AdapterFibContext->FileObject);
++
++ //
++ // has it been > 2 minutes since the last read off the queue?
++ //
++ if ((time_now - time_last) > 120) {
++ Entry = Entry->Flink;
++ // cmn_err (CE_WARN, "aifd: Flushing orphaned AdapterFibContext: idle %d seconds, %d fibs",
++ // time_now - time_last,
++ // AdapterFibContext->FibCount);
++ FsaCloseAdapterFibContext ( Adapter, AdapterFibContext );
++ continue;
++ }
++ }
++
++// Warning: sleep possible while holding spinlock
++ NewFib = OsAllocMemory(sizeof(FIB), OS_ALLOC_MEM_SLEEP);
++
++ if (NewFib) {
++
++ //
++ // Make the copy of the FIB
++ //
++
++ RtlCopyMemory(NewFib, Fib, sizeof(FIB));
++
++ //
++ // Put the FIB onto the AdapterFibContext's FibList
++ //
++
++ InsertTailList(&AdapterFibContext->FibList, &NewFib->Header.FibLinks);
++ AdapterFibContext->FibCount++;
++
++ //
++ // Set the event to wake up the thread that will waiting.
++ //
++
++ OsCv_signal(&AdapterFibContext->UserEvent);
++
++ } else {
++
++ cmn_err (CE_WARN, "aifd: didn't allocate NewFib");
++
++ }
++
++ Entry = Entry->Flink;
++ }
++
++ //
++ // Set the status of this FIB
++ //
++
++ *(FSASTATUS *)Fib->data = ST_OK;
++
++ CompleteAdapterFib( &FibContext, sizeof(FSASTATUS) );
++
++ OsCvLockRelease(Adapter->AdapterFibMutex);
++
++ }
++
++ OsSpinLockAcquire(CommRegion->HostNormCmdQue.QueueLock);
++
++ }
++
++ //
++ // There are no more AIF's, call cv_wait_sig to wait for more
++ // to process.
++ //
++
++ // cmn_err(CE_DEBUG, "no more AIF's going to sleep\n");
++
++ if (OsCv_wait_sig( &(CommRegion->HostNormCmdQue.CommandReady),
++ CommRegion->HostNormCmdQue.QueueLock ) == 0) {
++
++ OsSpinLockRelease(CommRegion->HostNormCmdQue.QueueLock);
++
++ Adapter->AifThreadStarted = FALSE;
++
++ // cmn_err(CE_DEBUG, "AifThread awoken by a signal\n");
++
++ return (EINTR);
++
++ }
++
++ // cmn_err(CE_DEBUG, "Aif thread awake, going to look for more AIF's\n");
++
++ }
++}
++
++
++PVOID
++FsaGetFibData(
++ IN PFIB_CONTEXT Context
++ )
++{
++ PCOMM_FIB_CONTEXT FibContext = (PCOMM_FIB_CONTEXT) Context;
++
++ return ((PVOID)FibContext->Fib->data);
++}
++
++
++#ifdef API_THROTTLE
++
++void ThrottlePeriodEndDpcRtn(
++ IN PKDPC Dpc,
++ IN PVOID DeferredContext,
++ IN PVOID SystemArgument1,
++ IN PVOID SystemArgument2
++ )
++/*++
++
++Routine Description:
++
++ This routine is called as a DPC when a throttle period expires. It
++ restarts all threads suspended due to the throttling flow control.
++
++ The throttling counted semaphore is signalled for all waiting threads
++ and the indicator of throttling active is cleared.
++
++Arguments:
++
++ Dpc - Pointer to Dpc structure. Not used.
++ DefferedContext - Pointer to per-adapter context. This is used to locate the
++ throttle information for this adapter.
++ SystemArgument1 - Not used
++ SystemArgument2 - Not used
++
++Return Value:
++
++ None.
++
++--*/
++{
++ PCOMM_REGION CommRegion;
++ PAFA_COMM_ADAPTER Adapter = (PAFA_COMM_ADAPTER) DeferredContext;
++
++ CommRegion = Adapter->CommRegion;
++
++ //
++ // Acquire the spinlock protecting the throttle status.
++ //
++ OsSpinLockAcquire(CommRegion->AdapNormCmdQue.QueueLock);
++
++ FsaCommPrint("ThrottlePeriodEndDpc\n");
++
++ //
++ // Check that the timer has fired as many times as it was set !
++ //
++
++ CommRegion->ThrottleTimerFires++;
++ ASSERT(CommRegion->ThrottleTimerFires == CommRegion->ThrottleTimerSets);
++
++ //
++ // The throttle period is now over. Restart all threads waiting
++ // on the throttle being released.
++ // Clear the throttle active indicator. This will allow new FIBs
++ // to be sent to the adapter once we release the spinlock on exiting
++ // the DPC. This means all restarted threads will be runnable
++ // threads by then.
++ //
++
++ ASSERT(CommRegion->ThrottleActive == TRUE); // The throttle had better be on !
++ CommRegion->ThrottleActive = FALSE; // This allows new data FIBs to go to the adapter on dpc exit
++
++ OsSpinLockRelease(CommRegion->AdapNormCmdQue.QueueLock);
++}
++
++#endif // #ifdef API_THROTTLE
++
++/*
++ * Overrides for Emacs so that we almost follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-indent-level: 4
++ * c-brace-imaginary-offset: 0
++ * c-brace-offset: -4
++ * c-argdecl-indent: 4
++ * c-label-offset: -4
++ * c-continued-statement-offset: 4
++ * c-continued-brace-offset: 0
++ * indent-tabs-mode: nil
++ * tab-width: 8
++ * End:
++ */
+diff -burN linux-2.4.9/drivers/scsi/aacraid/dpcsup.c linux/drivers/scsi/aacraid/dpcsup.c
+--- linux-2.4.9/drivers/scsi/aacraid/dpcsup.c Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/dpcsup.c Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,443 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * dpcsup.c
++ *
++ * Abstract: All DPC processing routines for the cyclone board occur here.
++ *
++ *
++ --*/
++
++static char *ident_dpcsup = "aacraid_ident dpcsup.c 1.0.6 2000/10/09 Adaptec, Inc.";
++
++#include "comprocs.h"
++
++
++//
++// The Bug check file id for this module
++//
++
++#define BugCheckFileId (FSAFS_BUG_CHECK_DPCSUP)
++
++#define Dbg (DEBUG_TRACE_DPCSUP)
++
++u_int
++CommonNotFullDpc(
++ IN PCOMM_REGION CommRegion
++ )
++/*++
++
++Routine Description:
++
++ This DPC routine will be queued when the adapter interrupts us to let us know the queue is
++ no longer full. The Isr will pass the queue that we will set the not full event.
++
++Arguments:
++
++ Dpc - Pointer to this routine.
++
++ Dummy - is a pointer to the comm region which is global so we don't need it anyway
++
++ Queue is a pointer to the queue structure we will operate on.
++
++ MoreData2 are DPC parameters we don't need for this function. Maybe we can add some accounting
++ stuff in here.
++
++Return Value:
++ Nothing.
++
++--*/
++{
++
++#ifdef unix_queue_full
++ KeSetEvent(&Queue->QueueFull, 0, FALSE);
++#endif
++
++}
++
++int GatherFibTimes = 0;
++
++// XXX - hack this in until I figure out which header file should contain it. <smb>
++extern ULONG
++FibGetMeterSize(
++ PFIB pFib,
++ ULONG MeterType,
++ char SubCommand
++ );
++
++
++/*++
++
++Routine Description:
++
++ This DPC routine will be queued when the adapter interrupts us to let us know there
++ is a response on our normal priority queue. We will pull off all QE there are and wake
++ up all the waiters before exiting. We will take a spinlock out on the queue before operating
++ on it.
++
++Arguments:
++
++ Dpc - Pointer to this routine.
++
++ OurQueue is a pointer to the queue structure we will operate on.
++
++ MoreData1&2 are DPC parameters we don't need for this function. Maybe we can add some accounting
++ stuff in here.
++
++Return Value:
++ Nothing.
++
++--*/
++u_int
++HostResponseNormalDpc (IN PCOMM_QUE OurQueue)
++{
++ PAFA_COMM_ADAPTER Adapter = OurQueue->Adapter;
++ PQUEUE_ENTRY QueueEntry;
++ PFIB Fib;
++ PCOMM_FIB_CONTEXT FibContext;
++ int Consumed = 0;
++ KIRQL OldIrql;
++
++ LARGE_INTEGER ResponseAllocSize;
++
++#ifdef commdebug
++ FsaCommPrint("entering the host normal reponse dpc routine.\n");
++#endif
++
++ OsSpinLockAcquire( OurQueue->QueueLock );
++
++ //
++ // Keep pulling response QEs off the response queue and waking
++ // up the waiters until there are no more QEs. We then return
++ // back to the system. If no response was requesed we just
++ // deallocate the Fib here and continue.
++ //
++
++ loop:
++ while ( GetConsumerEntry( Adapter, OurQueue, &QueueEntry) ) {
++
++ int IsFastResponse;
++
++ IsFastResponse = (int) (QueueEntry->FibAddress & 0x01);
++ Fib = (PFIB) (QueueEntry->FibAddress & ~0x01);
++
++ FreeConsumerEntry(Adapter, OurQueue, HostNormRespQueue);
++
++ FibContext = (PCOMM_FIB_CONTEXT)Fib->Header.SenderData;
++
++ ASSERT(FibContext->Fib == Fib);
++
++ //
++ // Remove this FibContext from the Outstanding I/O queue.
++ // But only if it has not already been timed out.
++ //
++ // If the fib has been timed out already, then just continue.
++ // The caller has already been notified that the fib timed out.
++ //
++
++ if (!(FibContext->Flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
++
++ RemoveEntryList( &FibContext->QueueEntry );
++ Adapter->CommRegion->AdapNormCmdQue.NumOutstandingIos--;
++
++ } else {
++
++ FsaCommLogEvent(FibContext,
++ FsaCommData.DeviceObject,
++ FSAFS_TIMED_OUT_FIB_COMPLETED,
++ STATUS_UNSUCCESSFUL,
++ BugCheckFileId | __LINE__,
++ FACILITY_FSAFS_ERROR_CODE,
++ NULL,
++ TRUE);
++
++ continue;
++
++ }
++
++ OsSpinLockRelease( OurQueue->QueueLock );
++
++ if (IsFastResponse) {
++
++ //
++ // doctor the fib
++ //
++
++ *(FSASTATUS *)Fib->data = ST_OK;
++
++ Fib->Header.XferState |= AdapterProcessed;
++
++ }
++
++ ASSERT((Fib->Header.XferState & (AdapterProcessed | HostOwned | SentFromHost)) == (AdapterProcessed | HostOwned | SentFromHost));
++
++ FIB_COUNTER_INCREMENT(FsaCommData.FibRecved);
++
++ ASSERT(FsaCommData.FibsSent >= FsaCommData.FibRecved);
++
++
++ if (Fib->Header.Command == NuFileSystem) {
++
++ FSASTATUS *pStatus = (FSASTATUS *)Fib->data;
++
++ if (*pStatus & 0xffff0000) {
++
++ ULONG Hint = *pStatus;
++
++ *pStatus = ST_OK;
++
++/*
++ DbgPrint("Replacing hint in fid (drive = %d, f1 = 0x%x, f2 = 0x%x, hint = 0x%x, new_hint = 0x%x)\n",
++ IrpContext->NonPaged->FileId.fid_driveno,
++ IrpContext->NonPaged->FileId.fid_f1,
++ IrpContext->NonPaged->FileId.fid_f2,
++ IrpContext->NonPaged->FileId.fid_hint,
++ Hint);
++*/
++
++ }
++
++ }
++
++ if (Fib->Header.XferState & (NoResponseExpected | Async) ) {
++
++ ASSERT(FibContext->FibCallback);
++
++ if (Fib->Header.XferState & NoResponseExpected)
++ FIB_COUNTER_INCREMENT(FsaCommData.NoResponseRecved);
++ else
++ FIB_COUNTER_INCREMENT(FsaCommData.AsyncRecved);
++
++ //
++ // NOTE: we can not touch the FibContext after this call, because it may have been
++ // deallocated.
++ //
++
++ FibContext->FibCallback(FibContext->FibCallbackContext, FibContext, STATUS_SUCCESS);
++
++ } else {
++
++ OsCvLockAcquire( FibContext->FsaEventMutex);
++
++ FibContext->FibComplete = 1;
++
++ OsCv_signal( &FibContext->FsaEvent );
++
++ OsCvLockRelease( FibContext->FsaEventMutex );
++
++ FIB_COUNTER_INCREMENT(FsaCommData.NormalRecved);
++
++ }
++
++
++ Consumed++;
++
++ OsSpinLockAcquire( OurQueue->QueueLock );
++
++ }
++
++ if (Consumed > FsaCommData.PeakFibsConsumed)
++ FsaCommData.PeakFibsConsumed = Consumed;
++
++ if (Consumed == 0)
++ FsaCommData.ZeroFibsConsumed++;
++
++ if (FsaCommData.HardInterruptModeration) {
++
++ //
++ // Re-Enable the interrupt from the adapter, then recheck to see if anything has
++ // been put on the queue. This removes the race condition that exists between the
++ // last time we checked the queue, and when we re-enabled the interrupt.
++ //
++ // If there is something on the queue, then go handle it.
++ //
++
++ EnableInterrupt( Adapter, HostNormRespQue, FALSE );
++
++ if (ConsumerEntryAvailable( Adapter, OurQueue ) ) {
++
++ DisableInterrupt( Adapter, HostNormRespQue, FALSE );
++
++ goto loop;
++
++ }
++ }
++
++#ifdef commdebug
++ FsaCommPrint("Exiting host normal reponse dpc routine after consuming %d QE(s).\n",Consumed);
++#endif
++
++ OsSpinLockRelease( OurQueue->QueueLock );
++
++}
++
++/*++
++
++Routine Description:
++
++ This DPC routine wiol be queued when the adapter interrupts us to let us know there
++ is a response on our high priority queue. We will pull off all QE there are and wake
++ up all the waiters before exiting. We will take a spinlock out on the queue before operating
++ on it.
++
++Arguments:
++
++ Dpc - Pointer to this routine.
++
++ OurQueue is a pointer to the queue structure we will operate on.
++
++ MoreData1&2 are DPC parameters we don't need for this function. Maybe we can add some accounting
++ stuff in here.
++
++Return Value:
++ Nothing.
++
++--*/
++u_int
++HostResponseHighDpc (IN PCOMM_QUE OurQueue)
++{}
++
++
++/*++
++
++Routine Description:
++
++ This DPC routine will be queued when the adapter interrupts us to let us know there
++ is a command on our high priority queue. We will pull off all QE there are and wake
++ up all the waiters before exiting. We will take a spinlock out on the queue before operating
++ on it.
++
++Arguments:
++
++ Dpc - Pointer to this routine.
++
++ OurQueue is a pointer to the queue structure we will operate on.
++
++ MoreData1&2 are DPC parameters we don't need for this function. Maybe we can add some accounting
++ stuff in here.
++
++Return Value:
++ Nothing.
++
++--*/
++u_int
++HostCommandHighDpc (IN PCOMM_QUE OurQueue)
++{}
++
++
++/*++
++
++Routine Description:
++
++ This DPC routine will be queued when the adapter interrupts us to let us know there
++ is a command on our normal priority queue. We will pull off all QE there are and wake
++ up all the waiters before exiting. We will take a spinlock out on the queue before operating
++ on it.
++
++Arguments:
++
++ Dpc - Pointer to this routine.
++
++ OurQueue is a pointer to the queue structure we will operate on.
++
++ MoreData1&2 are DPC parameters we don't need for this function. Maybe we can add some accounting
++ stuff in here.
++
++Return Value:
++ Nothing.
++
++--*/
++u_int
++HostCommandNormDpc (IN PCOMM_QUE OurQueue)
++{
++ PAFA_COMM_ADAPTER Adapter = OurQueue->Adapter;
++ PQUEUE_ENTRY QueueEntry;
++
++ OsSpinLockAcquire( OurQueue->QueueLock );
++
++ //
++ // Keep pulling response QEs off the response queue and waking
++ // up the waiters until there are no more QEs. We then return
++ // back to the system.
++ //
++
++ while ( GetConsumerEntry( Adapter, OurQueue, &QueueEntry) ) {
++
++ PFIB Fib;
++
++ Fib = (PFIB)QueueEntry->FibAddress;
++
++
++ if (Adapter->AifThreadStarted) {
++
++
++// cmn_err(CE_CONT, "^Received AIF, putting onto command queue\n");
++
++
++ InsertTailList(&OurQueue->CommandQueue, &Fib->Header.FibLinks);
++ FreeConsumerEntry(Adapter, OurQueue, HostNormCmdQueue);
++ OsCv_signal(&OurQueue->CommandReady);
++
++
++
++ } else {
++
++
++
++ COMM_FIB_CONTEXT FibContext;
++
++
++
++ FreeConsumerEntry(Adapter, OurQueue, HostNormCmdQueue);
++
++
++
++ OsSpinLockRelease( OurQueue->QueueLock );
++
++
++
++// cmn_err(CE_CONT, "^Received AIF, thread not started\n");
++
++
++ RtlZeroMemory( &FibContext, sizeof(COMM_FIB_CONTEXT) );
++
++ FibContext.NodeTypeCode = FSAFS_NTC_FIB_CONTEXT;
++ FibContext.NodeByteSize = sizeof( COMM_FIB_CONTEXT );
++ FibContext.Fib = Fib;
++ FibContext.FibData = Fib->data;
++ FibContext.Adapter = Adapter;
++
++ //
++ // Set the status of this FIB
++ //
++
++ *(FSASTATUS *)Fib->data = ST_OK;
++
++ CompleteAdapterFib( &FibContext, sizeof(FSASTATUS) );
++
++
++
++ OsSpinLockAcquire( OurQueue->QueueLock );
++ }
++ }
++
++ OsSpinLockRelease( OurQueue->QueueLock );
++
++}
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/AacGenericTypes.h linux/drivers/scsi/aacraid/include/AacGenericTypes.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/AacGenericTypes.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/AacGenericTypes.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,57 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ *
++ * AacGenericTypes.h
++ *
++ * Abstract:
++ *
++ * The module defines the generic data types that all of the other header files
++ * depend upon.
++ --*/
++
++#ifndef _AAC_GENERIC_TYPES
++#define _AAC_GENERIC_TYPES
++
++static char *ident_AacGeneric = "aacraid_ident AacGenericTypes.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++typedef char AAC_INT8, *PAAC_INT8;
++typedef short AAC_INT16, *PAAC_INT16;
++typedef int AAC_INT32, *PAAC_INT32;
++typedef long long AAC_INT64, *PAAC_INT64;
++
++typedef unsigned char AAC_UINT8, *PAAC_UINT8;
++typedef unsigned short AAC_UINT16, *PAAC_UINT16;
++typedef unsigned int AAC_UINT32, *PAAC_UINT32;
++typedef unsigned long long AAC_UINT64, *PAAC_UINT64;
++
++typedef void AAC_VOID, *PAAC_VOID;
++
++//
++// this compiler uses 32 bit enum data types
++//
++
++#define AAC_32BIT_ENUMS 1
++#define FAILURE 1
++#define INTR_UNCLAIMED 1
++#define INTR_CLAIMED 0
++
++#endif // _AAC_GENERIC_TYPES
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/aac_unix_defs.h linux/drivers/scsi/aacraid/include/aac_unix_defs.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/aac_unix_defs.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/aac_unix_defs.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,300 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ *
++ * aac_unix_defs.h
++ *
++ * Abstract:
++ *
++ * Macro definition and typedefs
++ *
++ --*/
++
++#ifndef _AAC_UNIX_DEFS
++#define _AAC_UNIX_DEFS
++
++static char *ident_aac_unix = "aacraid_ident aac_unix_defs.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++#define AAC_MAX_ADAPTERS 64
++
++#ifndef TRUE
++#define TRUE 1
++#define FALSE 0
++#endif
++
++#define PAGE_SIZE 4096
++
++typedef void VOID;
++typedef VOID *PVOID;
++
++typedef char CHAR, *PCHAR;
++typedef unsigned char UCHAR, *PUCHAR;
++typedef short SHORT, *PSHORT;
++typedef short CSHORT, *PCSHORT;
++typedef unsigned short USHORT, *PUSHORT;
++typedef unsigned long ULONG, *PULONG;
++typedef long LONG, *PLONG;
++
++typedef unsigned long BOOLEAN;
++
++typedef unsigned long AAC_STATUS, *PNT_STATUS;
++
++typedef struct {
++ unsigned long LowPart;
++ unsigned long HighPart;
++} LARGE_INTEGER;
++
++typedef LARGE_INTEGER PHYSICAL_ADDRESS;
++
++
++typedef struct _AFA_IOCTL_CMD {
++ int cmd;
++ intptr_t arg;
++ int flag;
++ cred_t *cred_p;
++ int *rval_p;
++} AFA_IOCTL_CMD, *PAFA_IOCTL_CMD;
++
++
++//
++// Singly linked list structure. Can be used as either a list head, or
++// as link words.
++//
++
++typedef struct _SINGLE_LIST_ENTRY {
++ struct _SINGLE_LIST_ENTRY *Next;
++} SINGLE_LIST_ENTRY, *PSINGLE_LIST_ENTRY;
++
++
++//
++// Calculate the address of the base of the structure given its type, and an
++// address of a field within the structure.
++//
++
++#define CONTAINING_RECORD(address, type, field) ((type *)( \
++ (PCHAR)(address) - \
++ (PCHAR)(&((type *)0)->field)))
++
++typedef PVOID PMDL;
++typedef PVOID PDEVICE_OBJECT;
++typedef PVOID PADAPTER_OBJECT;
++typedef ULONG KIRQL;
++typedef PVOID HANDLE;
++typedef PVOID KDPC, *PKDPC;
++typedef PVOID PFILE_OBJECT;
++typedef PVOID PIRP;
++typedef PVOID PDRIVER_OBJECT;
++typedef ULONG KTIMER;
++
++
++#define STATUS_SUCCESS 0x00000000
++#define STATUS_PENDING 0x40000001
++#define STATUS_IO_TIMEOUT 0xc0000001
++#define STATUS_UNSUCCESSFUL 0xc0000002
++#define STATUS_INSUFFICIENT_RESOURCES 0xc0000005
++#define STATUS_BUFFER_OVERFLOW 0xc0000003
++
++
++#define OUT
++
++
++
++typedef u_int
++(*PUNIX_INTR_HANDLER)(caddr_t Arg);
++
++//
++// Zone Allocation
++//
++
++typedef struct _ZONE_SEGMENT_HEADER {
++ SINGLE_LIST_ENTRY SegmentList;
++ PVOID Reserved;
++} ZONE_SEGMENT_HEADER, *PZONE_SEGMENT_HEADER;
++
++typedef struct _ZONE_HEADER {
++ SINGLE_LIST_ENTRY FreeList;
++ SINGLE_LIST_ENTRY SegmentList;
++ ULONG BlockSize;
++ ULONG TotalSegmentSize;
++} ZONE_HEADER, *PZONE_HEADER;
++
++
++//++
++//
++// PVOID
++// ExAllocateFromZone(
++// IN PZONE_HEADER Zone
++// )
++//
++// Routine Description:
++//
++// This routine removes an entry from the zone and returns a pointer to it.
++//
++// Arguments:
++//
++// Zone - Pointer to the zone header controlling the storage from which the
++// entry is to be allocated.
++//
++// Return Value:
++//
++// The function value is a pointer to the storage allocated from the zone.
++//
++//--
++
++#define ExAllocateFromZone(Zone) \
++ (PVOID)((Zone)->FreeList.Next); \
++ if ( (Zone)->FreeList.Next ) (Zone)->FreeList.Next = (Zone)->FreeList.Next->Next
++
++//++
++//
++// PVOID
++// ExFreeToZone(
++// IN PZONE_HEADER Zone,
++// IN PVOID Block
++// )
++//
++// Routine Description:
++//
++// This routine places the specified block of storage back onto the free
++// list in the specified zone.
++//
++// Arguments:
++//
++// Zone - Pointer to the zone header controlling the storage to which the
++// entry is to be inserted.
++//
++// Block - Pointer to the block of storage to be freed back to the zone.
++//
++// Return Value:
++//
++// Pointer to previous block of storage that was at the head of the free
++// list. NULL implies the zone went from no available free blocks to
++// at least one free block.
++//
++//--
++
++#define ExFreeToZone(Zone,Block) \
++ ( ((PSINGLE_LIST_ENTRY)(Block))->Next = (Zone)->FreeList.Next, \
++ (Zone)->FreeList.Next = ((PSINGLE_LIST_ENTRY)(Block)), \
++ ((PSINGLE_LIST_ENTRY)(Block))->Next \
++ )
++
++//++
++//
++// BOOLEAN
++// ExIsFullZone(
++// IN PZONE_HEADER Zone
++// )
++//
++// Routine Description:
++//
++// This routine determines if the specified zone is full or not. A zone
++// is considered full if the free list is empty.
++//
++// Arguments:
++//
++// Zone - Pointer to the zone header to be tested.
++//
++// Return Value:
++//
++// TRUE if the zone is full and FALSE otherwise.
++//
++//--
++
++#define ExIsFullZone(Zone) \
++ ( (Zone)->FreeList.Next == (PSINGLE_LIST_ENTRY)NULL )
++
++
++#define RtlCopyMemory( Destination, Source, Size ) bcopy( (Source), (Destination), (Size) )
++#define RtlZeroMemory( Destination, Size ) bzero( (Destination), (Size) )
++
++//
++// Doubly-linked list manipulation routines. Implemented as macros
++// but logically these are procedures.
++//
++
++//
++// VOID
++// InitializeListHead(
++// PLIST_ENTRY ListHead
++// );
++//
++
++#define InitializeListHead(ListHead) (\
++ (ListHead)->Flink = (ListHead)->Blink = (ListHead))
++
++//
++// BOOLEAN
++// IsListEmpty(
++// PLIST_ENTRY ListHead
++// );
++//
++
++#define IsListEmpty(ListHead) \
++ ((ListHead)->Flink == (ListHead))
++
++//
++// PLIST_ENTRY
++// RemoveHeadList(
++// PLIST_ENTRY ListHead
++// );
++//
++
++#define RemoveHeadList(ListHead) \
++ (ListHead)->Flink;\
++ {RemoveEntryList((ListHead)->Flink)}
++
++
++//
++// VOID
++// RemoveEntryList(
++// PLIST_ENTRY Entry
++// );
++//
++
++#define RemoveEntryList(Entry) {\
++ PLIST_ENTRY _EX_Blink;\
++ PLIST_ENTRY _EX_Flink;\
++ _EX_Flink = (Entry)->Flink;\
++ _EX_Blink = (Entry)->Blink;\
++ _EX_Blink->Flink = _EX_Flink;\
++ _EX_Flink->Blink = _EX_Blink;\
++ }
++
++//
++// VOID
++// InsertTailList(
++// PLIST_ENTRY ListHead,
++// PLIST_ENTRY Entry
++// );
++//
++
++#define InsertTailList(ListHead,Entry) {\
++ PLIST_ENTRY _EX_Blink;\
++ PLIST_ENTRY _EX_ListHead;\
++ _EX_ListHead = (ListHead);\
++ _EX_Blink = _EX_ListHead->Blink;\
++ (Entry)->Flink = _EX_ListHead;\
++ (Entry)->Blink = _EX_Blink;\
++ _EX_Blink->Flink = (Entry);\
++ _EX_ListHead->Blink = (Entry);\
++ }
++
++#endif /* AAC_UNIX_DEFS */
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/adapter.h linux/drivers/scsi/aacraid/include/adapter.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/adapter.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/adapter.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,164 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ *
++ * Adapter.h
++ *
++ * Abstract:
++ * The module contains the definitions for a comm layer view of the adapter.
++ *
++ *
++ *
++ --*/
++
++#ifndef _ADAPTER_
++#define _ADAPTER_
++
++static char *ident_adapter = "aacraid_ident adapter.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++typedef struct _GET_ADAPTER_FIB_CONTEXT {
++
++ NODE_TYPE_CODE NodeTypeCode; // used for verification of structure
++ NODE_BYTE_SIZE NodeByteSize;
++ PFILE_OBJECT FileObject; // used for cleanup
++ LIST_ENTRY NextContext; // used to link context's into a linked list
++ OS_CV_T UserEvent; // this is used to wait for the next fib to arrive.
++ BOOLEAN WaitingForFib; // Set to true when thread is in WaitForSingleObject
++ ULONG FibCount; // total number of FIBs on FibList
++ LIST_ENTRY FibList;
++} GET_ADAPTER_FIB_CONTEXT;
++typedef GET_ADAPTER_FIB_CONTEXT *PGET_ADAPTER_FIB_CONTEXT;
++
++
++typedef struct _FIB_CONTEXT_ZONE_SEGMENT {
++
++ struct _FIB_CONTEXT_ZONE_SEGMENT *Next;
++ ULONG FibContextSegmentSize;
++ PVOID FibContextSegment;
++ ULONG ExtendSize;
++ MAPFIB_CONTEXT MapFibContext;
++
++} FIB_CONTEXT_ZONE_SEGMENT;
++typedef FIB_CONTEXT_ZONE_SEGMENT *PFIB_CONTEXT_ZONE_SEGMENT;
++
++typedef struct _AFA_COMM_ADAPTER {
++
++ struct _AFA_COMM_ADAPTER *NextAdapter;
++
++ //
++ // The following fields are used to allocate FIB context structures
++ // using the zone allocator, and other fixed sized structures from a
++ // small cache. The mutex protects access to the zone/lists
++ //
++
++ ZONE_HEADER FibContextZone;
++ OS_SPINLOCK *FibContextZoneSpinLock;
++ int FibContextZoneExtendSize;
++
++ PFIB_CONTEXT_ZONE_SEGMENT FibContextSegmentList;
++
++ PVOID FibContextTimedOutList;
++
++ PFIB SyncFib;
++ ULONG SyncFibPhysicalAddress;
++
++ PCOMM_REGION CommRegion;
++
++ OS_SPINLOCK_COOKIE SpinLockCookie;
++
++ //
++ // The user API will use an IOCTL to register itself to receive FIBs
++ // from the adapter. The following list is used to keep track of all
++ // the threads that have requested these FIBs. The mutex is used to
++ // synchronize access to all data associated with the adapter fibs.
++ //
++ LIST_ENTRY AdapterFibContextList;
++ OS_CVLOCK *AdapterFibMutex;
++
++ //
++ // The following holds which FileObject is allow to send configuration
++ // commands to the adapter that would modify the configuration.
++ //
++ // This is controlled by the FSACTL_OPEN_ADAPTER_CONFIG and FSACTL_CLOSE_ADAPTER_CONFIG
++ // ioctls.
++ //
++ PFILE_OBJECT AdapterConfigFileObject;
++
++ //
++ // The following is really here because of the simulator
++ //
++ BOOLEAN InterruptsBelowDpc;
++
++ //
++ // The following is the device specific extension.
++ //
++ PVOID AdapterExtension;
++ PFSAPORT_FUNCS AdapterFuncs;
++ void *Dip;
++
++ //
++ // The following are user variables that are specific to the mini port.
++ //
++ PFSA_USER_VAR AdapterUserVars;
++ ULONG AdapterUserVarsSize;
++
++ //
++ // The following is the number of the individual adapter..i.e. \Device\Afa0
++ //
++ LONG AdapterNumber;
++
++ AFACOMM_FUNCS CommFuncs;
++
++ PAFA_CLASS_DRIVER ClassDriverList;
++
++ BOOLEAN AifThreadStarted;
++
++} AFA_COMM_ADAPTER;
++
++typedef AFA_COMM_ADAPTER *PAFA_COMM_ADAPTER;
++
++
++#define FsaAllocateAdapterCommArea(Adapter, BaseAddress, Size, Alignment) \
++ Adapter->AdapterFuncs->AllocateAdapterCommArea(Adapter->AdapterExtension, BaseAddress, Size, Alignment)
++
++#define FsaFreeAdapterCommArea(Adapter) \
++ Adapter->AdapterFuncs->FreeAdapterCommArea(Adapter->AdapterExtension)
++
++
++#define AllocateAndMapFibSpace(Adapter, MapFibContext) \
++ Adapter->AdapterFuncs->AllocateAndMapFibSpace(Adapter->AdapterExtension, MapFibContext)
++
++#define UnmapAndFreeFibSpace(Adapter, MapFibContext) \
++ Adapter->AdapterFuncs->UnmapAndFreeFibSpace(Adapter->AdapterExtension, MapFibContext)
++
++#define InterruptAdapter(Adapter) \
++ Adapter->AdapterFuncs->InterruptAdapter(Adapter->AdapterExtension)
++
++#define NotifyAdapter(Adapter, AdapterEvent) \
++ Adapter->AdapterFuncs->NotifyAdapter(Adapter->AdapterExtension, AdapterEvent)
++
++#define EnableInterrupt(Adapter, AdapterEvent, AtDeviceIrq) \
++ Adapter->AdapterFuncs->EnableInterrupt(Adapter->AdapterExtension, AdapterEvent, AtDeviceIrq)
++
++#define DisableInterrupt(Adapter, AdapterEvent, AtDeviceIrq) \
++ Adapter->AdapterFuncs->DisableInterrupt(Adapter->AdapterExtension, AdapterEvent, AtDeviceIrq)
++
++
++#endif // _ADAPTER_
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/afacomm.h linux/drivers/scsi/aacraid/include/afacomm.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/afacomm.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/afacomm.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,191 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * AfaComm.h
++ *
++ * Abstract:
++ * This module defines all of the external interfaces to the AFA comm layer.
++ *
++ *
++ *
++ --*/
++#ifndef _AFACOMM_
++#define _AFACOMM_
++
++static char *ident_afacomm = "aacraid_ident afacomm.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++#include "fsaport.h"
++
++typedef void *PFIB_CONTEXT;
++
++typedef VOID
++(*PFIB_CALLBACK)(
++ PVOID FibCallbackContext,
++ PFIB_CONTEXT FibContext,
++ AAC_STATUS Status
++ );
++
++
++typedef PFIB_CONTEXT
++(*PAFA_COMM_ALLOCATE_FIB) (
++ IN PVOID AdapterExtension
++ );
++
++typedef VOID
++(*PAFA_COMM_FREE_FIB) (
++ IN PFIB_CONTEXT FibContext
++ );
++
++
++typedef AAC_STATUS
++(*PAFA_COMM_DEALLOCATE_FIB) (
++ IN PFIB_CONTEXT FibContext
++ );
++
++
++typedef VOID
++(*PAFA_COMM_FREE_FIB_FROM_DPC) (
++ IN PFIB_CONTEXT FibContext
++ );
++
++typedef AAC_STATUS
++(*PAFA_COMM_INITIALIZE_FIB) (
++ IN PFIB_CONTEXT FibContext
++ );
++
++typedef PVOID
++(*PAFA_COMM_GET_FIB_DATA) (
++ IN PFIB_CONTEXT FibContext
++ );
++
++typedef AAC_STATUS
++(*PAFA_COMM_SEND_FIB) (
++ IN FIB_COMMAND Command,
++ IN PFIB_CONTEXT FibContext,
++ IN ULONG Size,
++ IN COMM_PRIORITIES Priority,
++ IN BOOLEAN Wait,
++ IN PVOID WaitOn,
++ IN BOOLEAN ResponseExpected,
++ IN PFIB_CALLBACK FibCallback,
++ IN PVOID FibCallbackContext
++ );
++
++typedef AAC_STATUS
++(*PAFA_COMM_COMPLETE_FIB) (
++ IN PFIB_CONTEXT FibContext
++ );
++
++typedef AAC_STATUS
++(*PAFA_COMM_COMPLETE_ADAPTER_FIB) (
++ IN PFIB_CONTEXT FibContext,
++ IN USHORT Size
++ );
++
++typedef BOOLEAN
++(*PAFA_COMM_SEND_SYNCH_FIB) (
++ PVOID AdapterExtension,
++ FIB_COMMAND Command,
++ PVOID Data,
++ USHORT Size,
++ PVOID Response,
++ USHORT *ResponseSize
++ );
++
++
++typedef struct _AFACOMM_FUNCS {
++ ULONG SizeOfAfaCommFuncs;
++ PAFA_COMM_ALLOCATE_FIB AllocateFib;
++ PAFA_COMM_FREE_FIB FreeFib;
++ PAFA_COMM_FREE_FIB_FROM_DPC FreeFibFromDpc;
++ PAFA_COMM_DEALLOCATE_FIB DeallocateFib;
++ PAFA_COMM_INITIALIZE_FIB InitializeFib;
++ PAFA_COMM_GET_FIB_DATA GetFibData;
++ PAFA_COMM_SEND_FIB SendFib;
++ PAFA_COMM_COMPLETE_FIB CompleteFib;
++ PAFA_COMM_COMPLETE_ADAPTER_FIB CompleteAdapterFib;
++ PAFA_COMM_SEND_SYNCH_FIB SendSynchFib;
++ PFSA_FREE_DMA_RESOURCES FreeDmaResources;
++ PFSA_BUILD_SGMAP BuildSgMap;
++ PFSA_ADAPTER_ADDR_TO_SYSTEM_ADDR AdapterAddressToSystemAddress;
++} AFACOMM_FUNCS;
++typedef AFACOMM_FUNCS *PAFACOMM_FUNCS;
++
++
++typedef AAC_STATUS
++(*PAFA_CLASS_OPEN_ADAPTER) (
++ IN PVOID Adapter
++ );
++
++
++typedef AAC_STATUS
++(*PAFA_CLASS_CLOSE_ADAPTER) (
++ IN PVOID Adapter
++ );
++
++
++typedef BOOLEAN
++(*PAFA_CLASS_DEV_CONTROL) (
++ IN PVOID Adapter,
++ IN PAFA_IOCTL_CMD IoctlCmdPtr,
++ OUT int * Status
++ );
++
++typedef BOOLEAN
++(*PAFA_CLASS_HANDLE_AIF) (
++ IN PVOID Adapter,
++ IN PFIB_CONTEXT FibContext
++ );
++
++
++typedef struct _AFA_NEW_CLASS_DRIVER {
++ PVOID ClassDriverExtension;
++ PAFA_CLASS_OPEN_ADAPTER OpenAdapter;
++ PAFA_CLASS_CLOSE_ADAPTER CloseAdapter;
++ PAFA_CLASS_DEV_CONTROL DeviceControl;
++ PAFA_CLASS_HANDLE_AIF HandleAif;
++ PFSA_USER_VAR UserVars;
++ ULONG NumUserVars;
++} AFA_NEW_CLASS_DRIVER;
++typedef AFA_NEW_CLASS_DRIVER *PAFA_NEW_CLASS_DRIVER;
++
++
++typedef struct _AFA_NEW_CLASS_DRIVER_RESPONSE {
++ PAFACOMM_FUNCS CommFuncs;
++ PVOID CommPortExtension;
++ PVOID MiniPortExtension;
++ OS_SPINLOCK_COOKIE SpinLockCookie;
++ void *Dip;
++} AFA_NEW_CLASS_DRIVER_RESPONSE;
++typedef AFA_NEW_CLASS_DRIVER_RESPONSE *PAFA_NEW_CLASS_DRIVER_RESPONSE;
++
++
++typedef struct _AFA_CLASS_DRIVER {
++ struct _AFA_CLASS_DRIVER *Next;
++ PVOID ClassDriverExtension;
++ PAFA_CLASS_OPEN_ADAPTER OpenAdapter;
++ PAFA_CLASS_CLOSE_ADAPTER CloseAdapter;
++ PAFA_CLASS_DEV_CONTROL DeviceControl;
++ PAFA_CLASS_HANDLE_AIF HandleAif;
++} AFA_CLASS_DRIVER;
++typedef AFA_CLASS_DRIVER *PAFA_CLASS_DRIVER;
++
++
++#endif // _AFACOMM_
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/aifstruc.h linux/drivers/scsi/aacraid/include/aifstruc.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/aifstruc.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/aifstruc.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,319 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * Aifstruc.h
++ *
++ * Abstract:
++ * Define all shared data types relating to
++ * the set of features utilizing Adapter
++ * Initiated Fibs.
++ *
++ *
++ *
++ --*/
++#ifndef _AIFSTRUC_H
++#define _AIFSTRUC_H
++
++static char *ident_aifstruc = "aacraid_ident aifstruc.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++#include <protocol.h>
++
++//
++// Progress report structure definitions
++//
++typedef enum {
++ AifJobStsSuccess = 1,
++ AifJobStsFinished,
++ AifJobStsAborted,
++ AifJobStsFailed,
++ AifJobStsLastReportMarker = 100, // All before mean last report
++ AifJobStsSuspended,
++ AifJobStsRunning
++} _E_AifJobStatus;
++
++#ifdef AAC_32BIT_ENUMS
++typedef _E_AifJobStatus AifJobStatus;
++#else
++typedef AAC_UINT32 AifJobStatus;
++#endif
++
++
++typedef enum {
++ AifJobScsiMin = 1, // Minimum value for Scsi operation
++ AifJobScsiZero, // SCSI device clear operation
++ AifJobScsiVerify, // SCSI device Verify operation NO REPAIR
++ AifJobScsiExercise, // SCSI device Exercise operation
++ AifJobScsiVerifyRepair, // SCSI device Verify operation WITH repair
++ // Add new SCSI task types above this line
++ AifJobScsiMax = 99, // Max Scsi value
++ AifJobCtrMin, // Min Ctr op value
++ AifJobCtrZero, // Container clear operation
++ AifJobCtrCopy, // Container copy operation
++ AifJobCtrCreateMirror, // Container Create Mirror operation
++ AifJobCtrMergeMirror, // Container Merge Mirror operation
++ AifJobCtrScrubMirror, // Container Scrub Mirror operation
++ AifJobCtrRebuildRaid5, // Container Rebuild Raid5 operation
++ AifJobCtrScrubRaid5, // Container Scrub Raid5 operation
++ AifJobCtrMorph, // Container morph operation
++ AifJobCtrPartCopy, // Container Partition copy operation
++ AifJobCtrRebuildMirror, // Container Rebuild Mirror operation
++ AifJobCtrCrazyCache, // crazy cache
++ // Add new container task types above this line
++ AifJobCtrMax = 199, // Max Ctr type operation
++ AifJobFsMin, // Min Fs type operation
++ AifJobFsCreate, // File System Create operation
++ AifJobFsVerify, // File System Verify operation
++ AifJobFsExtend, // File System Extend operation
++ // Add new file system task types above this line
++ AifJobFsMax = 299, // Max Fs type operation
++ // Add new API task types here
++ AifJobApiFormatNTFS, // Format a drive to NTFS
++ AifJobApiFormatFAT, // Format a drive to FAT
++ AifJobApiUpdateSnapshot, // update the read/write half of a snapshot
++ AifJobApiFormatFAT32, // Format a drive to FAT32
++ AifJobApiMax = 399, // Max API type operation
++ AifJobCtlContinuousCtrVerify, // Controller operation
++ AifJobCtlMax = 499 // Max Controller type operation
++
++} _E_AifJobType;
++
++#ifdef AAC_32BIT_ENUMS
++typedef _E_AifJobType AifJobType;
++#else
++typedef AAC_UINT32 AifJobType;
++#endif
++
++union SrcContainer {
++ AAC_UINT32 from;
++ AAC_UINT32 master;
++ AAC_UINT32 container;
++};
++
++union DstContainer {
++ AAC_UINT32 to;
++ AAC_UINT32 slave;
++ AAC_UINT32 container;
++};
++
++
++struct AifContainers {
++ union SrcContainer src;
++ union DstContainer dst;
++};
++
++union AifJobClient {
++
++ struct AifContainers container; // For Container nd file system progress ops;
++ AAC_INT32 scsi_dh; // For SCSI progress ops
++};
++
++struct AifJobDesc {
++ AAC_UINT32 jobID; // DO NOT FILL IN! Will be filled in by AIF
++ AifJobType type; // Operation that is being performed
++ union AifJobClient client; // Details
++};
++
++struct AifJobProgressReport {
++ struct AifJobDesc jd;
++ AifJobStatus status;
++ AAC_UINT32 finalTick;
++ AAC_UINT32 currentTick;
++ AAC_UINT32 jobSpecificData1;
++ AAC_UINT32 jobSpecificData2;
++};
++
++//
++// Notification of events structure definition starts here
++//
++typedef enum {
++ // General application notifies start here
++ AifEnGeneric = 1, // Generic notification
++ AifEnTaskComplete, // Task has completed
++ AifEnConfigChange, // Adapter configuration change occurred
++ AifEnContainerChange, // Adapter specific container configuration change
++ AifEnDeviceFailure, // SCSI device failed
++ AifEnMirrorFailover, // Mirror failover started
++ AifEnContainerEvent, // Significant container event
++ AifEnFileSystemChange, // File system changed
++ AifEnConfigPause, // Container pause event
++ AifEnConfigResume, // Container resume event
++ AifEnFailoverChange, // Failover space assignment changed
++ AifEnRAID5RebuildDone, // RAID5 rebuild finished
++ AifEnEnclosureManagement, // Enclosure management event
++ AifEnBatteryEvent, // Significant NV battery event
++ AifEnAddContainer, // A new container was created.
++ AifEnDeleteContainer, // A container was deleted.
++ AifEnSMARTEvent, // SMART Event
++ AifEnBatteryNeedsRecond, // The battery needs reconditioning
++ AifEnClusterEvent, // Some cluster event
++ AifEnDiskSetEvent, // A disk set event occured.
++ // Add general application notifies above this comment
++ AifDriverNotifyStart=199, // Notifies for host driver go here
++ // Host driver notifications start here
++ AifDenMorphComplete, // A morph operation completed
++ AifDenVolumeExtendComplete // A volume expand operation completed
++ // Add host driver notifications above this comment
++} _E_AifEventNotifyType;
++
++#ifdef AAC_32BIT_ENUMS
++typedef _E_AifEventNotifyType AifEventNotifyType;
++#else
++typedef AAC_UINT32 AifEventNotifyType;
++#endif
++
++struct AifEnsGeneric {
++ AAC_INT8 text[132]; // Generic text
++};
++
++struct AifEnsDeviceFailure {
++ AAC_INT32 deviceHandle; // SCSI device handle
++};
++
++struct AifEnsMirrorFailover {
++ AAC_UINT32 container; // Container with failed element
++ AAC_UINT32 failedSlice; // Old slice which failed
++ AAC_UINT32 creatingSlice; // New slice used for auto-create
++};
++
++struct AifEnsContainerChange {
++ AAC_UINT32 container[2]; // container that changed, -1 if no container
++};
++
++struct AifEnsContainerEvent {
++ AAC_UINT32 container; // container number
++ AAC_UINT32 eventType; // event type
++};
++
++struct AifEnsEnclosureEvent {
++ AAC_UINT32 empID; // enclosure management processor number
++ AAC_UINT32 unitID; // unitId, fan id, power supply id, slot id, tempsensor id.
++ AAC_UINT32 eventType; // event type
++};
++
++
++struct AifEnsBatteryEvent {
++ NVBATT_TRANSITION transition_type; // e.g. from low to ok
++ NVBATTSTATUS current_state; // current battery state
++ NVBATTSTATUS prior_state; // previous battery state
++};
++
++struct AifEnsDiskSetEvent {
++ AAC_UINT32 eventType;
++ AAC_UINT32 DsNum[2];
++ AAC_UINT32 CreatorId[2];
++};
++
++
++
++typedef enum _CLUSTER_AIF_EVENT {
++ CLUSTER_NULL_EVENT = 0,
++ CLUSTER_PARTNER_NAME_EVENT, // change in partner hostname or adaptername from NULL to non-NULL
++ // (partner's agent may be up)
++ CLUSTER_PARTNER_NULL_NAME_EVENT // change in partner hostname or adaptername from non-null to NULL
++ // (partner has rebooted)
++} _E_CLUSTER_AIF_EVENT;
++
++#ifdef AAC_32BIT_ENUMS
++typedef _E_CLUSTER_AIF_EVENT CLUSTER_AIF_EVENT;
++#else
++typedef AAC_UINT32 CLUSTER_AIF_EVENT;
++#endif
++
++struct AifEnsClusterEvent {
++ CLUSTER_AIF_EVENT eventType;
++};
++
++struct AifEventNotify {
++ AifEventNotifyType type;
++ union {
++ struct AifEnsGeneric EG;
++ struct AifEnsDeviceFailure EDF;
++ struct AifEnsMirrorFailover EMF;
++ struct AifEnsContainerChange ECC;
++ struct AifEnsContainerEvent ECE;
++ struct AifEnsEnclosureEvent EEE;
++ struct AifEnsBatteryEvent EBE;
++ struct AifEnsDiskSetEvent EDS;
++#ifdef BRIDGE
++ struct AifEnsSMARTEvent ES;
++#endif
++ struct AifEnsClusterEvent ECLE;
++ } data;
++};
++
++//
++// Generic API structure
++//
++#define AIF_API_REPORT_MAX_SIZE 64
++typedef AAC_INT8 AifApiReport[AIF_API_REPORT_MAX_SIZE];
++
++
++
++//
++// For FIB communication, we need all of the following things
++// to send back to the user.
++//
++typedef enum {
++ AifCmdEventNotify = 1, // Notify of event
++ AifCmdJobProgress, // Progress report
++ AifCmdAPIReport, // Report from other user of API
++ AifCmdDriverNotify, // Notify host driver of event
++ AifReqJobList = 100, // Gets back complete job list
++ AifReqJobsForCtr, // Gets back jobs for specific container
++ AifReqJobsForScsi, // Gets back jobs for specific SCSI device
++ AifReqJobReport, // Gets back a specific job report or list of them
++ AifReqTerminateJob, // Terminates job
++ AifReqSuspendJob, // Suspends a job
++ AifReqResumeJob, // Resumes a job
++ AifReqSendAPIReport, // API generic report requests
++ AifReqAPIJobStart, // Start a job from the API
++ AifReqAPIJobUpdate, // Update a job report from the API
++ AifReqAPIJobFinish // Finish a job from the API
++} _E_AIFCOMMAND;
++
++#ifdef AAC_32BIT_ENUMS
++typedef _E_AIFCOMMAND AIFCOMMAND;
++#else
++typedef AAC_UINT32 AIFCOMMAND;
++#endif
++
++
++
++//
++// Adapter Initiated FIB command structures. Start with the adapter
++// initiated FIBs that really come from the adapter, and get responded
++// to by the host.
++//
++typedef struct _AIFCOMMANDTOHOST {
++ AIFCOMMAND command; // Tell host what type of notify this is
++ AAC_UINT32 seqNumber; // To allow ordering of reports (if necessary)
++ union {
++ // First define data going to the adapter
++ struct AifEventNotify EN; // Event notify structure
++ struct AifJobProgressReport PR[1]; // Progress report
++ AifApiReport AR;
++ } data;
++} AIFCOMMANDTOHOST, *PAIFCOMMANDTOHOST;
++
++
++#endif // _AIFSTRUC_H
++
++
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/build_number.h linux/drivers/scsi/aacraid/include/build_number.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/build_number.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/build_number.h Thu Aug 16 18:16:55 2001
+@@ -0,0 +1,39 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * build_number.h
++ *
++ * Abstract:
++ * DThis module contains the single location where the build number
++ * is kept.
++ *
++ *
++ *
++ --*/
++#ifndef _BUILD_NUMBER_H
++#define _BUILD_NUMBER_H
++
++static char *ident_build_num = "aacraid_ident build_number.h 1.0.7 2001/08/10 Adaptec, Inc.";
++
++#define REV_BUILD_NUMBER 5125
++
++
++#endif // _BUILD_NUMBER_H
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/commdata.h linux/drivers/scsi/aacraid/include/commdata.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/commdata.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/commdata.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,112 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * commdata.h
++ *
++ * Abstract: Define the communication layer of the adapter
++ *
++ *
++ *
++ --*/
++#ifndef _COMMDATA_
++#define _COMMDATA_
++
++static char *ident_commdata = "aacraid_ident commdata.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++typedef struct _FSA_COMM_DATA {
++
++ //
++ // A pointer to the Driver and Device object we were initialized with
++ //
++
++ PDRIVER_OBJECT DriverObject;
++ PDEVICE_OBJECT DeviceObject;
++
++ //
++ // A list of all adapters we have configured.
++ //
++
++ PAFA_COMM_ADAPTER AdapterList;
++ ULONG TotalAdapters;
++
++ //
++ // Adapter timeout support. This is the default timeout to wait for the
++ // adapter to respond(setup in initfs.c), and a boolean to indicate if
++ // we should timeout requests to the adapter or not.
++ //
++
++ LARGE_INTEGER QueueFreeTimeout;
++ LARGE_INTEGER AdapterTimeout;
++ BOOLEAN EnableAdapterTimeouts;
++
++ ULONG FibTimeoutIncrement;
++
++ ULONG FibsSent;
++ ULONG FibRecved;
++ ULONG NoResponseSent;
++ ULONG NoResponseRecved;
++ ULONG AsyncSent;
++ ULONG AsyncRecved;
++ ULONG NormalSent;
++ ULONG NormalRecved;
++
++ ULONG TimedOutFibs;
++
++ KDPC TimeoutDPC;
++ KTIMER TimeoutTimer;
++
++ //
++ // If this value is set to 1 then interrupt moderation will occur
++ // in the base commuication support.
++ //
++
++ ULONG EnableInterruptModeration;
++
++ int HardInterruptModeration;
++ int HardInterruptModeration1;
++ int PeakFibsConsumed;
++ int ZeroFibsConsumed;
++ int EnableFibTimeoutBreak;
++ ULONG FibTimeoutSeconds;
++
++ //
++ // The following holds all of the available user settable variables.
++ // This includes all for the comm layer as well as any from the class
++ // drivers as well.
++ //
++
++ FSA_USER_VAR *UserVars;
++ ULONG NumUserVars;
++
++
++ ULONG MeterFlag;
++
++#ifdef FIB_CHECKSUMS
++ int do_fib_checksums;
++#endif
++
++} FSA_COMM_DATA;
++typedef FSA_COMM_DATA *PFSA_COMM_DATA;
++
++extern FSA_COMM_DATA FsaCommData;
++
++
++#endif // _COMMDATA_
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/commerr.h linux/drivers/scsi/aacraid/include/commerr.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/commerr.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/commerr.h Thu Aug 16 18:16:55 2001
+@@ -0,0 +1,125 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * commerr.h
++ *
++ * Abstract: This file defines all errors that are unique to the Adaptec Fsa Filesystem
++ *
++ *
++ *
++ --*/
++
++#ifndef _FSAERR_
++#define _FSAERR_
++
++static char *ident_commerr = "aacraid_ident commerr.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++//
++// Note: comments in the .mc file must use both ";" and "//".
++//
++// Status values are 32 bit values layed out as follows:
++//
++// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
++// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
++// +---+-+-------------------------+-------------------------------+
++// |Sev|C| Facility | Code |
++// +---+-+-------------------------+-------------------------------+
++//
++// where
++//
++// Sev - is the severity code
++//
++// 00 - Success
++// 01 - Informational
++// 10 - Warning
++// 11 - Error
++//
++// C - is the Customer code flag
++//
++// Facility - is the facility code
++//
++// Code - is the facility's status code
++//
++
++
++//
++// %1 is reserved by the IO Manager. If IoAllocateErrorLogEntry is
++// called with a device, the name of the device will be inserted into
++// the message at %1. Otherwise, the place of %1 will be left empty.
++// In either case, the insertion strings from the driver's error log
++// entry starts at %2. In other words, the first insertion string goes
++// to %2, the second to %3 and so on.
++//
++
++//
++// Values are 32 bit values layed out as follows:
++//
++// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
++// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
++// +---+-+-+-----------------------+-------------------------------+
++// |Sev|C|R| Facility | Code |
++// +---+-+-+-----------------------+-------------------------------+
++//
++// where
++//
++// Sev - is the severity code
++//
++// 00 - Success
++// 01 - Informational
++// 10 - Warning
++// 11 - Error
++//
++// C - is the Customer code flag
++//
++// R - is a reserved bit
++//
++// Facility - is the facility code
++//
++// Code - is the facility's status code
++//
++//
++// Define the facility codes
++//
++
++
++#define FACILITY_FSAFS_ERROR_CODE 0x7
++
++
++
++//
++// MessageId: FSAFS_FIB_INVALID
++//
++// MessageText:
++//
++// A communication packet was detected to be formatted poorly. Please Contact Adaptec support.
++//
++#define FSAFS_FIB_INVALID ((AAC_STATUS)0xE0070009L)
++
++
++//
++// MessageId: FSAFS_TIMED_OUT_FIB_COMPLETED
++//
++// MessageText:
++//
++// A Fib previously timed out by host has been completed by the adapter. (\\.\Afa%2)
++//
++#define FSAFS_TIMED_OUT_FIB_COMPLETED ((AAC_STATUS)0xA007000EL)
++
++#endif /* _FSAERR_ */
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/commfibcontext.h linux/drivers/scsi/aacraid/include/commfibcontext.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/commfibcontext.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/commfibcontext.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,98 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * commfibcontext.h
++ *
++ * Abstract: defines the _COMM_FIB_CONTEXT strcuture
++ *
++ *
++ *
++ --*/
++#ifndef _COMM_FIB_CONTEXT_
++#define _COMM_FIB_CONTEXT_
++
++static char *ident_commfib = "aacraid_ident commfibcontext.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++typedef struct _COMM_FIB_CONTEXT {
++
++ PVOID Next; // this is used by the zone allocation
++
++ //
++ // Type and size of this record (must be FSA_NTC_FIB_CONTEXT)
++ //
++ // NOTE: THIS STRUCTURE MUST REMAIN 64-bit ALIGNED IN SIZE, SINCE
++ // IT IS ZONE ALLOCATED, AND REPINNED_BCBS_ARRAY_SIZE AFFECTS
++ // ITS SIZE.
++ //
++
++ NODE_TYPE_CODE NodeTypeCode;
++ NODE_BYTE_SIZE NodeByteSize;
++
++ //
++ // The Adapter that this I/O is destined for.
++ //
++
++ PAFA_COMM_ADAPTER Adapter;
++
++ PHYSICAL_ADDRESS LogicalFibAddress;
++
++ //
++ // This is the event the sendfib routine will wait on if the
++ // caller did not pass one and this is synch io.
++ //
++
++ OS_CV_T FsaEvent;
++ OS_CVLOCK *FsaEventMutex;
++
++ ULONG FibComplete; // gets set to 1 when fib is complete
++
++ PFIB_CALLBACK FibCallback;
++ PVOID FibCallbackContext;
++
++ ULONG Flags;
++
++
++#ifdef GATHER_FIB_TIMES
++ LARGE_INTEGER FibTimeStamp;
++ PFIB_TIMES FibTimesPtr;
++#endif
++
++ //
++ // The following is used to put this fib context onto the Outstanding I/O queue.
++ //
++
++ LIST_ENTRY QueueEntry;
++
++ //
++ // The following is used to timeout a fib to the adapter.
++ //
++
++ LARGE_INTEGER TimeoutValue;
++
++ PVOID FibData;
++
++ PFIB Fib;
++
++} COMM_FIB_CONTEXT;
++typedef COMM_FIB_CONTEXT *PCOMM_FIB_CONTEXT;
++
++#define FIB_CONTEXT_FLAG_TIMED_OUT (0x00000001)
++
++#endif /* _COMM_FIB_CONTEXT_ */
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/comprocs.h linux/drivers/scsi/aacraid/include/comprocs.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/comprocs.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/comprocs.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,93 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * comprocs.h
++ *
++ * Abstract: This module defines all of the globally used procedures in the Afa comm layer
++ *
++ *
++ *
++ --*/
++#ifndef _COMPROCS_
++#define _COMPROCS_
++
++static char *ident_comproc = "aacraid_ident comprocs.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++#include "osheaders.h"
++
++#include "AacGenericTypes.h"
++
++#include "aac_unix_defs.h"
++
++#include "nodetype.h"
++
++// #define GATHER_FIB_TIMES
++
++#include "fsatypes.h"
++
++#include "perfpack.h"
++
++#include "comstruc.h"
++
++//#include "unix_protocol.h"
++
++#include "fsact.h"
++
++#include "protocol.h"
++
++#include "fsaioctl.h"
++
++#undef GATHER_FIB_TIMES
++
++#include "aifstruc.h"
++
++#include "fsaport.h"
++#include "comsup.h"
++#include "afacomm.h"
++#include "adapter.h"
++
++#include "commfibcontext.h"
++#include "comproto.h"
++#include "commdata.h"
++#include "commerr.h"
++
++
++
++
++//
++// The following macro is used when sending and receiving FIBs. It is only used for
++// debugging.
++
++#if DBG
++#define FIB_COUNTER_INCREMENT(Counter) InterlockedIncrement(&(Counter))
++#else
++#define FIB_COUNTER_INCREMENT(Counter)
++#endif
++
++
++
++int
++AfaCommAdapterDeviceControl (
++ IN PVOID AdapterArg,
++ IN PAFA_IOCTL_CMD IoctlCmdPtr
++ );
++
++
++#endif // _COMPROCS_
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/comproto.h linux/drivers/scsi/aacraid/include/comproto.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/comproto.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/comproto.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,170 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * comproto.h
++ *
++ * Abstract: Global routines for the commuication interface that are device
++ * independant.
++ *
++ *
++ *
++ --*/
++#ifndef _COMM_PROTO
++#define _COMM_PROTO
++
++static char *ident_comproto = "aacraid_ident comproto.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++//
++// define the routines we need so we can commuicate with the
++// fsa adapter
++//
++
++//
++// The following 4 dpc routines will support commuication from the adapter to the
++// host. There is one DPC routine to deal with each type of queue that supports
++// commuication from the adapter. (adapter to host resposes, adapter to host commands)
++// These routines will simply pull off the QE and set an event. In the case of a
++// adapter to host command they will also put the FIB on a queue to be processed by
++// a FS thread running at passive level.
++//
++
++// Handle queue not full notification to the file system thread waiting for a queue entry
++
++u_int
++CommonNotFullDpc(
++ IN PCOMM_REGION CommRegion
++ );
++
++// Adapter to host normal priority responses
++
++u_int
++HostResponseNormalDpc(
++ IN PCOMM_QUE OurQueue
++ );
++
++// Adapter to host high priority responses
++u_int
++HostResponseHighDpc(
++ IN PCOMM_QUE OurQueue
++ );
++
++// Adapter to host high priority commands
++u_int
++HostCommandHighDpc(
++ IN PCOMM_QUE OurQueue
++ );
++
++
++// Adapter to host normal priority commands
++u_int
++HostCommandNormDpc(
++ IN PCOMM_QUE OurQueue
++ );
++
++
++
++BOOLEAN
++SendSynchFib(
++ PVOID Arg,
++ FIB_COMMAND Command,
++ PVOID Data,
++ USHORT Size,
++ PVOID Response,
++ USHORT *ResponseSize
++ );
++
++PFIB_CONTEXT
++AllocateFib (
++ IN PVOID Adapter
++ );
++
++VOID
++FreeFib (
++ IN PFIB_CONTEXT FibContext
++ );
++
++VOID
++FreeFibFromDpc(
++ IN PFIB_CONTEXT FibContext
++ );
++
++AAC_STATUS
++DeallocateFib(
++ IN PFIB_CONTEXT FibContext
++ );
++
++
++
++AAC_STATUS
++SendFib(
++ IN FIB_COMMAND Command,
++ IN PFIB_CONTEXT FibContext,
++ IN ULONG Size,
++ IN COMM_PRIORITIES Priority,
++ IN BOOLEAN Wait,
++ IN PVOID WaitOn,
++ IN BOOLEAN ResponseExpected,
++ IN PFIB_CALLBACK FibCallback,
++ IN PVOID FibCallbackContext
++ );
++
++AAC_STATUS
++CompleteFib(
++ IN PFIB_CONTEXT FibContext
++ );
++
++AAC_STATUS
++CompleteAdapterFib(
++ IN PFIB_CONTEXT FibContext,
++ IN USHORT Size
++ );
++
++AAC_STATUS
++InitializeFib(
++ IN PFIB_CONTEXT FibContext
++ );
++
++
++PVOID
++FsaGetFibData(
++ IN PFIB_CONTEXT FibContext
++ );
++
++
++
++AAC_STATUS
++AfaCommOpenAdapter (
++ IN PVOID AdapterArg
++ );
++
++AAC_STATUS
++AfaCommCloseAdapter (
++ IN PVOID AdapterArg
++ );
++
++
++VOID
++AfaCommInterruptHost(
++ PVOID Adapter,
++ ADAPTER_EVENT AdapterEvent
++ );
++
++
++#endif // _COMM_PROTO
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/comstruc.h linux/drivers/scsi/aacraid/include/comstruc.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/comstruc.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/comstruc.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,435 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * comstruc.h
++ *
++ * Abstract: This module defines the data structures that make up the communication
++ * region for the FSA filesystem. This region is how the host based code
++ * communicates both control and data to the adapter based code.
++ *
++ *
++ *
++ --*/
++#ifndef _COMM_STRUCT
++#define _COMM_STRUCT
++
++static char *ident_comstruc = "aacraid_ident comstruc.h 1.0.7 2000/10/11 Adaptec, Inc.";
++
++//
++// Define all the constants needed for the communication interface
++//
++
++// Define how many queue entries each queue will have and the total number of
++// entries for the entire communication interface. Also define how many queues
++// we support.
++
++#define NUMBER_OF_COMM_QUEUES 8 // 4 command; 4 response
++#define HOST_HIGH_CMD_ENTRIES 4
++#define HOST_NORM_CMD_ENTRIES 8
++#define ADAP_HIGH_CMD_ENTRIES 4
++#define ADAP_NORM_CMD_ENTRIES 512
++#define HOST_HIGH_RESP_ENTRIES 4
++#define HOST_NORM_RESP_ENTRIES 512
++#define ADAP_HIGH_RESP_ENTRIES 4
++#define ADAP_NORM_RESP_ENTRIES 8
++
++#define TOTAL_QUEUE_ENTRIES \
++ (HOST_NORM_CMD_ENTRIES + HOST_HIGH_CMD_ENTRIES + ADAP_NORM_CMD_ENTRIES + ADAP_HIGH_CMD_ENTRIES + \
++ HOST_NORM_RESP_ENTRIES + HOST_HIGH_RESP_ENTRIES + ADAP_NORM_RESP_ENTRIES + ADAP_HIGH_RESP_ENTRIES)
++
++
++
++
++// Set the queues on a 16 byte alignment
++#define QUEUE_ALIGNMENT 16
++
++
++//
++// The queue headers define the Communication Region queues. These
++// are physically contiguous and accessible by both the adapter and the
++// host. Even though all queue headers are in the same contiguous block they will be
++// represented as individual units in the data structures.
++//
++
++typedef AAC_UINT32 QUEUE_INDEX;
++
++typedef QUEUE_INDEX *PQUEUE_INDEX;
++
++typedef struct _QUEUE_ENTRY {
++
++ AAC_UINT32 Size; // Size in bytes of the Fib which this QE points to
++ AAC_UINT32 FibAddress; // Receiver addressable address of the FIB (low 32 address bits)
++
++} QUEUE_ENTRY;
++
++typedef QUEUE_ENTRY *PQUEUE_ENTRY;
++
++
++
++// The adapter assumes the ProducerIndex and ConsumerIndex are grouped
++// adjacently and in that order.
++//
++typedef struct _QUEUE_HEADERS {
++
++ PHYSICAL_ADDRESS LogicalHeaderAddress; // Address to hand the adapter to access to this queue head
++ PQUEUE_INDEX ProducerIndex; // The producer index for this queue (host address)
++ PQUEUE_INDEX ConsumerIndex; // The consumer index for this queue (host address)
++
++} QUEUE_HEADERS;
++typedef QUEUE_HEADERS *PQUEUE_HEADERS;
++
++//
++// Define all the events which the adapter would like to notify
++// the host of.
++//
++typedef enum _ADAPTER_EVENT {
++ HostNormCmdQue = 1, // Change in host normal priority command queue
++ HostHighCmdQue, // Change in host high priority command queue
++ HostNormRespQue, // Change in host normal priority response queue
++ HostHighRespQue, // Change in host high priority response queue
++ AdapNormRespNotFull,
++ AdapHighRespNotFull,
++ AdapNormCmdNotFull,
++ AdapHighCmdNotFull,
++ SynchCommandComplete,
++ AdapInternalError = 0xfe // The adapter detected an internal error shutting down
++
++} _E_ADAPTER_EVENT;
++
++#ifdef AAC_32BIT_ENUMS
++typedef _E_ADAPTER_EVENT ADAPTER_EVENT;
++#else
++typedef AAC_UINT32 ADAPTER_EVENT;
++#endif
++
++//
++// Define all the events the host wishes to notify the
++// adapter of.
++//
++typedef enum _HOST_2_ADAP_EVENT {
++ AdapNormCmdQue = 1,
++ AdapHighCmdQue,
++ AdapNormRespQue,
++ AdapHighRespQue,
++ HostShutdown,
++ HostPowerFail,
++ FatalCommError,
++ HostNormRespNotFull,
++ HostHighRespNotFull,
++ HostNormCmdNotFull,
++ HostHighCmdNotFull,
++ FastIo,
++ AdapPrintfDone
++} _E_HOST_2_ADAP_EVENT;
++
++#ifdef AAC_32BIT_ENUMS
++typedef _E_HOST_2_ADAP_EVENT HOST_2_ADAP_EVENT;
++#else
++typedef AAC_UINT32 HOST_2_ADAP_EVENT;
++#endif
++
++//
++// Define all the queues that the adapter and host use to communicate
++//
++
++typedef enum _QUEUE_TYPES {
++ HostNormCmdQueue = 1, // Adapter to host normal priority command traffic
++ HostHighCmdQueue, // Adapter to host high priority command traffic
++ AdapNormRespQueue, // Host to adapter normal priority response traffic
++ AdapHighRespQueue, // Host to adapter high priority response traffic
++ AdapNormCmdQueue, // Host to adapter normal priority command traffic
++ AdapHighCmdQueue, // Host to adapter high priority command traffic
++ HostNormRespQueue, // Adapter to host normal priority response traffic
++ HostHighRespQueue // Adapter to host high priority response traffic
++} _E_QUEUE_TYPES;
++
++#ifdef AAC_32BIT_ENUMS
++typedef _E_QUEUE_TYPES QUEUE_TYPES;
++#else
++typedef AAC_UINT32 QUEUE_TYPES;
++#endif
++
++
++//
++// Assign type values to the FSA communication data structures
++//
++
++typedef enum _STRUCT_TYPES {
++ TFib = 1,
++ TQe,
++ TCtPerf
++} _E_STRUCT_TYPES;
++
++#ifdef AAC_32BIT_ENUMS
++typedef _E_STRUCT_TYPES STRUCT_TYPES;
++#else
++typedef AAC_UINT32 STRUCT_TYPES;
++#endif
++
++//
++// Define the priority levels the FSA communication routines support.
++//
++
++typedef enum _COMM_PRIORITIES {
++ FsaNormal = 1,
++ FsaHigh
++} _E_COMM_PRIORITIES;
++
++#ifdef AAC_32BIT_ENUMS
++typedef _E_COMM_PRIORITIES COMM_PRIORITIES;
++#else
++typedef AAC_UINT32 COMM_PRIORITIES;
++#endif
++
++
++
++//
++// Define the LIST_ENTRY structure. This structure is used on the NT side to link
++// the FIBs together in a linked list. Since this structure gets compiled on the adapter
++// as well, we need to define this structure for the adapter's use. If '_NT_DEF_'
++// is defined, then this header is being included from the NT side, and therefore LIST_ENTRY
++// is already defined.
++#if !defined(_NTDEF_) && !defined(_WINNT_)
++typedef struct _LIST_ENTRY {
++ struct _LIST_ENTRY *Flink;
++ struct _LIST_ENTRY *Blink;
++} LIST_ENTRY;
++typedef LIST_ENTRY *PLIST_ENTRY;
++#endif
++
++
++//
++// Define the FIB. The FIB is the where all the requested data and
++// command information are put to the application on the FSA adapter.
++//
++
++typedef struct _FIB_HEADER {
++ AAC_UINT32 XferState; // Current transfer state for this CCB
++ AAC_UINT16 Command; // Routing information for the destination
++ AAC_UINT8 StructType; // Type FIB
++ AAC_UINT8 Flags; // Flags for FIB
++ AAC_UINT16 Size; // Size of this FIB in bytes
++ AAC_UINT16 SenderSize; // Size of the FIB in the sender (for response sizing)
++ AAC_UINT32 SenderFibAddress; // Host defined data in the FIB
++ AAC_UINT32 ReceiverFibAddress; // Logical address of this FIB for the adapter
++ AAC_UINT32 SenderData; // Place holder for the sender to store data
++#ifndef __midl
++ union {
++ struct {
++ AAC_UINT32 _ReceiverTimeStart; // Timestamp for receipt of fib
++ AAC_UINT32 _ReceiverTimeDone; // Timestamp for completion of fib
++ } _s;
++ LIST_ENTRY _FibLinks; // Used to link Adapter Initiated Fibs on the host
++ } _u;
++#else // The MIDL compiler does not support unions without a discriminant.
++ struct { // Since nothing during the midl compile actually looks into this
++ struct { // structure, this shoudl be ok.
++ AAC_UINT32 _ReceiverTimeStart; // Timestamp for receipt of fib
++ AAC_UINT32 _ReceiverTimeDone; // Timestamp for completion of fib
++ } _s;
++ } _u;
++#endif
++} FIB_HEADER;
++
++
++#define FibLinks _u._FibLinks
++
++
++#define FIB_DATA_SIZE_IN_BYTES (512 - sizeof(FIB_HEADER))
++
++
++typedef struct _FIB {
++
++#ifdef BRIDGE //rma
++ DLQUE link;
++#endif
++ FIB_HEADER Header;
++
++ AAC_UINT8 data[FIB_DATA_SIZE_IN_BYTES]; // Command specific data
++
++} FIB;
++typedef FIB *PFIB;
++
++
++
++//
++// FIB commands
++//
++
++typedef enum _FIB_COMMANDS {
++ TestCommandResponse = 1,
++ TestAdapterCommand = 2,
++
++ // Lowlevel and comm commands
++
++ LastTestCommand = 100,
++ ReinitHostNormCommandQueue = 101,
++ ReinitHostHighCommandQueue = 102,
++ ReinitHostHighRespQueue = 103,
++ ReinitHostNormRespQueue = 104,
++ ReinitAdapNormCommandQueue = 105,
++ ReinitAdapHighCommandQueue = 107,
++ ReinitAdapHighRespQueue = 108,
++ ReinitAdapNormRespQueue = 109,
++ InterfaceShutdown = 110,
++ DmaCommandFib = 120,
++ StartProfile = 121,
++ TermProfile = 122,
++ SpeedTest = 123,
++ TakeABreakPt = 124,
++ RequestPerfData = 125,
++ SetInterruptDefTimer= 126,
++ SetInterruptDefCount= 127,
++ GetInterruptDefStatus= 128,
++ LastCommCommand = 129,
++
++ // Filesystem commands
++
++ NuFileSystem = 300,
++ UFS = 301,
++ HostFileSystem = 302,
++ LastFileSystemCommand = 303,
++
++ // Container Commands
++
++ ContainerCommand = 500,
++ ContainerCommand64 = 501,
++
++ // Cluster Commands
++
++ ClusterCommand = 550,
++
++ // Scsi Port commands (scsi passthrough)
++
++ ScsiPortCommand = 600,
++
++ // misc house keeping and generic adapter initiated commands
++
++ AifRequest = 700,
++ CheckRevision = 701,
++ FsaHostShutdown = 702,
++ RequestAdapterInfo = 703,
++ IsAdapterPaused = 704,
++ SendHostTime = 705,
++ LastMiscCommand = 706
++
++} _E_FIB_COMMANDS;
++
++
++
++typedef AAC_UINT16 FIB_COMMAND;
++
++//
++// Commands that will target the failover level on the FSA adapter
++//
++
++typedef enum _FIB_XFER_STATE {
++ HostOwned = (1<<0),
++ AdapterOwned = (1<<1),
++ FibInitialized = (1<<2),
++ FibEmpty = (1<<3),
++ AllocatedFromPool = (1<<4),
++ SentFromHost = (1<<5),
++ SentFromAdapter = (1<<6),
++ ResponseExpected = (1<<7),
++ NoResponseExpected = (1<<8),
++ AdapterProcessed = (1<<9),
++ HostProcessed = (1<<10),
++ HighPriority = (1<<11),
++ NormalPriority = (1<<12),
++ Async = (1<<13),
++ AsyncIo = (1<<13), // rpbfix: remove with new regime
++ PageFileIo = (1<<14), // rpbfix: remove with new regime
++ ShutdownRequest = (1<<15),
++ LazyWrite = (1<<16), // rpbfix: remove with new regime
++ AdapterMicroFib = (1<<17),
++ BIOSFibPath = (1<<18),
++ FastResponseCapable = (1<<19),
++ ApiFib = (1<<20) // Its an API Fib.
++
++} _E_FIB_XFER_STATE;
++
++
++typedef enum _FSA_ERRORS {
++ FSA_NORMAL = 0,
++ FSA_SUCCESS = 0,
++ FSA_PENDING = 0x01,
++ FSA_FATAL = 0x02,
++ FSA_INVALID_QUEUE = 0x03,
++ FSA_NOENTRIES = 0x04,
++ FSA_SENDFAILED = 0x05,
++ FSA_INVALID_QUEUE_PRIORITY = 0x06,
++ FSA_FIB_ALLOCATION_FAILED = 0x07,
++ FSA_FIB_DEALLOCATION_FAILED = 0x08
++
++} _E_FSA_ERRORS;
++
++
++//
++// The following defines needs to be updated any time there is an incompatible change made
++// to the ADAPTER_INIT_STRUCT structure.
++//
++#define ADAPTER_INIT_STRUCT_REVISION 3
++
++typedef struct _ADAPTER_INIT_STRUCT {
++ AAC_UINT32 InitStructRevision;
++ AAC_UINT32 MiniPortRevision;
++ AAC_UINT32 FilesystemRevision;
++ PAAC_VOID CommHeaderAddress;
++ PAAC_VOID FastIoCommAreaAddress;
++ PAAC_VOID AdapterFibsPhysicalAddress;
++ PAAC_VOID AdapterFibsVirtualAddress;
++ AAC_UINT32 AdapterFibsSize;
++ AAC_UINT32 AdapterFibAlign;
++ PAAC_VOID PrintfBufferAddress;
++ AAC_UINT32 PrintfBufferSize;
++ AAC_UINT32 HostPhysMemPages; // number of 4k pages of host physical memory
++ AAC_UINT32 HostElapsedSeconds; // number of seconds since 1970.
++} ADAPTER_INIT_STRUCT;
++typedef ADAPTER_INIT_STRUCT *PADAPTER_INIT_STRUCT;
++
++#ifdef AAC_32BIT_ENUMS
++typedef _E_FSA_ERRORS FSA_ERRORS;
++#else
++typedef AAC_UINT32 FSA_ERRORS;
++#endif
++
++typedef enum _LOG_LEVEL {
++ LOG_INIT = 10,
++ LOG_INFORMATIONAL = 20,
++ LOG_WARNING = 30,
++ LOG_LOW_ERROR = 40,
++ LOG_MEDIUM_ERROR = 50,
++ LOG_HIGH_ERROR = 60,
++ LOG_PANIC = 70,
++ LOG_DEBUG = 80,
++ LOG_WINDBG_PRINT = 90
++} _E_LOG_LEVEL;
++
++#ifdef AAC_32BIT_ENUMS
++typedef _E_LOG_LEVEL LOG_LEVEL;
++#else
++typedef AAC_UINT32 LOG_LEVEL;
++#endif
++
++
++#endif //_COMM_STRUCT
++
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/comsup.h linux/drivers/scsi/aacraid/include/comsup.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/comsup.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/comsup.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,132 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * comsup.h
++ *
++ * Abstract: This module defines the data structures that make up the
++ * commuication region for the FSA filesystem. This region is
++ * how the host based code commuicates both control and data
++ * to the adapter based code.
++ *
++ *
++ *
++ --*/
++#ifndef _COMM_SUP_DEF
++#define _COMM_SUP_DEF
++
++static char *ident_comsup = "aacraid_ident comsup.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++//
++// The adapter interface specs all queues to be located in the same physically
++// contigous block. The host structure that defines the commuication queues will
++// assume they are each a seperate physically contigous memory region that will
++// support them all being one big contigous block.
++// There is a command and response queue for each level and direction of
++// commuication. These regions are accessed by both the host and adapter.
++//
++typedef struct _COMM_QUE {
++
++ PHYSICAL_ADDRESS LogicalAddress; // This is the address we give the adapter
++
++ PQUEUE_ENTRY BaseAddress; // This is the system virtual address
++ QUEUE_HEADERS Headers; // A pointer to the producer and consumer queue headers for this queue
++ ULONG QueueEntries; // Number of queue entries on this queue
++ OS_CV_T QueueFull; // Event to wait on if the queue is full
++ OS_CV_T CommandReady; // Indicates there is a Command ready from the adapter on this queue.
++ // This is only valid for adapter to host command queues.
++ OS_SPINLOCK *QueueLock; // Spinlock for this queue must take this lock before accessing the lock
++ KIRQL SavedIrql; // Previous IRQL when the spin lock is taken
++ ddi_softintr_t ConsumerRoutine; // The DPC routine which will consume entries off this queue
++ // Only queues which the host will be the consumer will this field be valid
++ LIST_ENTRY CommandQueue; // A queue of FIBs which need to be prcessed by the FS thread. This is
++ // only valid for command queues which receive entries from the adapter.
++ LIST_ENTRY OutstandingIoQueue; // A queue of outstanding fib's to the adapter.
++ ULONG NumOutstandingIos; // Number of entries on outstanding queue.
++
++ PVOID Adapter; // Back pointer to adapter structure
++
++} COMM_QUE;
++typedef COMM_QUE *PCOMM_QUE;
++
++
++typedef struct _COMM_REGION {
++
++ COMM_QUE HostNormCmdQue; // Command queue for normal priority commands from the host
++ COMM_QUE HostNormRespQue; // A response for normal priority adapter responses
++
++ COMM_QUE HostHighCmdQue; // Command queue for high priority commands from the host
++ COMM_QUE HostHighRespQue; // A response for normal priority adapter responses
++
++ COMM_QUE AdapNormCmdQue; // Command queue for normal priority command from the adapter
++ COMM_QUE AdapNormRespQue; // A response for normal priority host responses
++
++ COMM_QUE AdapHighCmdQue; // Command queue for high priority command from the adapter
++ COMM_QUE AdapHighRespQue; // A response for high priority host responses
++
++ //
++ // The 2 threads below are the threads which handle command traffic from the
++ // the adapter. There is one for normal priority and one for high priority queues.
++ // These threads will wait on the commandready event for it's queue.
++ //
++
++ HANDLE NormCommandThread;
++ HANDLE HighCommandThread;
++
++ //
++ // This dpc routine will handle the setting the of not full event when the adapter
++ // lets us know the queue is not longer full via interrupt
++ //
++
++ KDPC QueueNotFullDpc;
++
++#ifdef API_THROTTLE
++ //
++ // Support for data I/O throttling to improve CLI performance
++ // while the system is under load.
++ // This is the throttling mechanism built into the COMM layer.
++ // Look in commsup.c, dpcsup.c and comminit.c for use.
++ //
++
++ int ThrottleLimit; // Max queue depth of data ops allowed during throttle
++ int ThrottleOutstandingFibs; // Number of data FIBs outstanding to adapter
++ LARGE_INTEGER ThrottleTimeout; // Duration of a a throttle period
++ LARGE_INTEGER ThrottleWaitTimeout; // Timeout for a suspended threads to wait
++ BOOLEAN ThrottleActive; // Is there a current throttle active period ?
++ KTIMER ThrottleTimer; // Throttle timer to end a throttle period.
++ KDPC ThrottleDpc; // Throttle timer timeout DPC routine.
++ KSEMAPHORE ThrottleReleaseSema; // Semaphore callers of SendFib wait on during a throttle.
++
++ unsigned int ThrottleExceptionsCount; // Number of times throttle exception handler executed (0!)
++ unsigned int ThrottleTimerFires; // Debug info - #times throttle timer Dpc has fired
++ unsigned int ThrottleTimerSets; // Debug info - #times throttle timer was set
++
++ unsigned int ThrottledFibs;
++ unsigned int ThrottleTimedoutFibs;
++ unsigned int ApiFibs;
++ unsigned int NonPassiveFibs;
++ unsigned int TotalFibs;
++ unsigned int FSInfoFibs;
++
++#endif // #ifdef API_THROTTLE
++
++} COMM_REGION;
++typedef COMM_REGION *PCOMM_REGION;
++
++#endif // _COMM_SUP
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/fsact.h linux/drivers/scsi/aacraid/include/fsact.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/fsact.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/fsact.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,165 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * fsact.h
++ *
++ * Abstract: Common container structures that are required to be
++ * known on both the host and adapter.
++ *
++ *
++ --*/
++#ifndef _FSACT_H_
++#define _FSACT_H_
++
++static char *ident_fsact = "aacraid_ident fsact.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++//#include <comstruc.h>
++//#include <fsatypes.h>
++#include <protocol.h> // definitions for FSASTATUS
++
++
++/*
++ * Object-Server / Volume-Manager Dispatch Classes
++ */
++typedef enum _VM_COMMANDS {
++ VM_Null = 0,
++ VM_NameServe,
++ VM_ContainerConfig,
++ VM_Ioctl,
++ VM_FilesystemIoctl,
++ VM_CloseAll,
++ VM_CtBlockRead, // see protocol.h for BlockRead command layout
++ VM_CtBlockWrite, // see protocol.h for BlockWrite command layout
++ VM_SliceBlockRead, // raw access to configured "storage objects"
++ VM_SliceBlockWrite,
++ VM_DriveBlockRead, // raw access to physical devices
++ VM_DriveBlockWrite,
++ VM_EnclosureMgt, // enclosure management
++ VM_Unused, // used to be diskset management
++ VM_CtBlockVerify, // see protocol.h for BlockVerify command layout
++ VM_CtPerf, // performance test
++ VM_CtBlockRead64, // see protocol.h for BlockRead64 command layout
++ VM_CtBlockWrite64, // see protocol.h for BlockWrite64 command layout
++ VM_CtBlockVerify64, // see protocol.h for BlockVerify64 command layout
++ MAX_VMCOMMAND_NUM // used for sizing stats array - leave last
++} _E_VMCOMMAND;
++
++#ifdef AAC_32BIT_ENUMS
++typedef _E_VMCOMMAND VMCOMMAND;
++#else
++typedef AAC_UINT32 VMCOMMAND;
++#endif
++
++
++
++//
++// Descriptive information (eg, vital stats)
++// that a content manager might report. The
++// FileArray filesystem component is one example
++// of a content manager. Raw mode might be
++// another.
++//
++
++struct FileSysInfo {
++/*
++ a) DOS usage - THINK ABOUT WHERE THIS MIGHT GO -- THXXX
++ b) FSA usage (implemented by ObjType and ContentState fields)
++ c) Block size
++ d) Frag size
++ e) Max file system extension size - (fsMaxExtendSize * fsSpaceUnits)
++ f) I-node density - (computed from other fields)
++*/
++ AAC_UINT32 fsTotalSize; // consumed by fs, incl. metadata
++ AAC_UINT32 fsBlockSize;
++ AAC_UINT32 fsFragSize;
++ AAC_UINT32 fsMaxExtendSize;
++ AAC_UINT32 fsSpaceUnits;
++ AAC_UINT32 fsMaxNumFiles;
++ AAC_UINT32 fsNumFreeFiles;
++ AAC_UINT32 fsInodeDensity;
++}; // valid iff ObjType == FT_FILESYS && !(ContentState & FSCS_NOTCLEAN)
++
++union ContentManagerInfo {
++ struct FileSysInfo FileSys; // valid iff ObjType == FT_FILESYS && !(ContentState & FSCS_NOTCLEAN)
++};
++
++//
++// Query for "mountable" objects, ie, objects that are typically
++// associated with a drive letter on the client (host) side.
++//
++
++typedef struct _MNTOBJ {
++
++ AAC_UINT32 ObjectId;
++ FSASTRING FileSystemName; // if applicable
++ ContainerCreationInfo CreateInfo; // if applicable
++ AAC_UINT32 Capacity;
++ FSAVOLTYPE VolType; // substrate structure
++ FTYPE ObjType; // FT_FILESYS, FT_DATABASE, etc.
++ AAC_UINT32 ContentState; // unready for mounting, readonly, etc.
++
++ union ContentManagerInfo
++ ObjExtension; // Info specific to content manager (eg, filesystem)
++
++ AAC_UINT32 AlterEgoId; // != ObjectId <==> snapshot or broken mirror exists
++
++} MNTOBJ;
++
++
++#define FSCS_READONLY 0x0002 // possible result of broken mirror
++
++
++
++typedef struct _MNTINFO {
++
++ VMCOMMAND Command;
++ FTYPE MntType;
++ AAC_UINT32 MntCount;
++
++} MNTINFO;
++typedef MNTINFO *PMNTINFO;
++
++typedef struct _MNTINFORESPONSE {
++
++ FSASTATUS Status;
++ FTYPE MntType; // should be same as that requested
++ AAC_UINT32 MntRespCount;
++ MNTOBJ MntTable[1];
++
++} MNTINFORESPONSE;
++typedef MNTINFORESPONSE *PMNTINFORESPONSE;
++
++
++//
++// The following command is sent to shut down each container.
++//
++
++typedef struct _CLOSECOMMAND {
++
++ VMCOMMAND Command;
++ AAC_UINT32 ContainerId;
++
++} CLOSECOMMAND;
++typedef CLOSECOMMAND *PCLOSECOMMAND;
++
++
++#endif /* _FSACT_H_ */
++
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/fsafs.h linux/drivers/scsi/aacraid/include/fsafs.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/fsafs.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/fsafs.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,78 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * fsafs.h
++ *
++ * Abstract: Common file system structures that are required to be
++ * known on both the host and adapter
++ *
++ *
++ *
++ --*/
++
++#ifndef _FSAFS_H_
++#define _FSAFS_H_ 1
++
++static char *ident_fsafs = "aacraid_ident fsafs.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++#include <fsatypes.h> // core types, shared by client and server, eg, u_long
++
++/*
++ * Maximum number of filesystems.
++ */
++#define NFILESYS 24
++
++/*
++ * File identifier.
++ * These are unique and self validating within a filesystem
++ * on a single machine and can persist across reboots.
++ * The hint field may be volatile and is not guaranteed to persist
++ * across reboots but is used to speed up the FID to file object translation
++ * if possible. The opaque f1 and f2 fields are guaranteed to uniquely identify
++ * the file object (assuming a filesystem context, i.e. driveno).
++ */
++typedef struct {
++ AAC_UINT32 hint; // last used hint for fast reclaim
++ AAC_UINT32 f1; // opaque
++ AAC_UINT32 f2; // opaque
++ } fileid_t; /* intra-filesystem file ID type */
++
++
++/*
++ * Generic file handle
++ */
++struct fhandle {
++ fsid_t fh_fsid; /* File system id of mount point */
++ fileid_t fh_fid; /* File sys specific file id */
++};
++typedef struct fhandle fhandle_t;
++
++#define FIDSIZE sizeof(fhandle_t)
++
++typedef struct {
++ union {
++ AAC_INT8 fid_data[FIDSIZE];
++ struct fhandle fsafid;
++ } fidu;
++} FSAFID; /* FSA File ID type */
++
++
++#endif /* _FSAFS_H_ */
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/fsaioctl.h linux/drivers/scsi/aacraid/include/fsaioctl.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/fsaioctl.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/fsaioctl.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,159 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * fsaioctl.h
++ *
++ * Abstract: Defines the interface structures between user mode applications
++ * and the fsa driver. This structures are used in
++ * DeviceIoControl() calls.
++ *
++ *
++ *
++ --*/
++#ifndef _FSAIOCTL_H_
++#define _FSAIOCTL_H_
++
++static char *ident_fsaioctl = "aacraid_ident fsaioctl.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++#ifndef IOTRACEUSER
++
++#ifndef CTL_CODE
++
++
++#define FILE_DEVICE_CONTROLLER 0x00000004
++
++//
++// Macro definition for defining IOCTL and FSCTL function control codes. Note
++// that function codes 0-2047 are reserved for Microsoft Corporation, and
++// 2048-4095 are reserved for customers.
++//
++
++#define CTL_CODE( DeviceType, Function, Method, Access ) ( \
++ ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
++)
++
++//
++// Define the method codes for how buffers are passed for I/O and FS controls
++//
++
++#define METHOD_BUFFERED 0
++
++
++#define METHOD_NEITHER 3
++
++//
++// Define the access check value for any access
++//
++//
++// The FILE_READ_ACCESS and FILE_WRITE_ACCESS constants are also defined in
++// ntioapi.h as FILE_READ_DATA and FILE_WRITE_DATA. The values for these
++// constants *MUST* always be in sync.
++//
++#define FILE_ANY_ACCESS 0
++
++
++
++#endif
++
++
++
++typedef struct _UNIX_QUERY_DISK {
++ AAC_INT32 ContainerNumber;
++ AAC_INT32 Bus;
++ AAC_INT32 Target;
++ AAC_INT32 Lun;
++ AAC_BOOLEAN Valid;
++ AAC_BOOLEAN Locked;
++ AAC_BOOLEAN Deleted;
++ AAC_INT32 Instance;
++ AAC_INT8 diskDeviceName[10];
++ AAC_BOOLEAN UnMapped;
++} UNIX_QUERY_DISK;
++typedef UNIX_QUERY_DISK *PUNIX_QUERY_DISK;
++
++
++typedef struct _DELETE_DISK {
++ AAC_UINT32 NtDiskNumber;
++ AAC_UINT32 ContainerNumber;
++} DELETE_DISK;
++typedef DELETE_DISK *PDELETE_DISK;
++
++
++#endif /*IOTRACEUSER*/
++
++#define FSACTL_NULL_IO_TEST 0x43 // CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2048, METHOD_NEITHER, FILE_ANY_ACCESS)
++#define FSACTL_SIM_IO_TEST 0x53 // CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2049, METHOD_NEITHER, FILE_ANY_ACCESS)
++
++
++#define FSACTL_SENDFIB CTL_CODE(FILE_DEVICE_CONTROLLER, 2050, METHOD_BUFFERED, FILE_ANY_ACCESS)
++
++
++#define FSACTL_GET_VAR 0x93
++#define FSACTL_SET_VAR 0xa3
++#define FSACTL_GET_FIBTIMES 0xb3
++#define FSACTL_ZERO_FIBTIMES 0xc3
++
++
++#define FSACTL_DELETE_DISK 0x163
++#define FSACTL_QUERY_DISK 0x173
++
++
++// AfaComm perfmon ioctls
++#define FSACTL_GET_COMM_PERF_DATA CTL_CODE(FILE_DEVICE_CONTROLLER, 2084, METHOD_BUFFERED, FILE_ANY_ACCESS)
++
++
++#define FSACTL_OPENCLS_COMM_PERF_DATA CTL_CODE(FILE_DEVICE_CONTROLLER, 2085, METHOD_BUFFERED, FILE_ANY_ACCESS)
++
++
++typedef struct _GET_ADAPTER_FIB_IOCTL {
++ char *AdapterFibContext;
++ int Wait;
++ char *AifFib;
++} GET_ADAPTER_FIB_IOCTL, *PGET_ADAPTER_FIB_IOCTL;
++
++//
++// filesystem ioctls
++//
++#define FSACTL_OPEN_GET_ADAPTER_FIB CTL_CODE(FILE_DEVICE_CONTROLLER, 2100, METHOD_BUFFERED, FILE_ANY_ACCESS)
++
++#define FSACTL_GET_NEXT_ADAPTER_FIB CTL_CODE(FILE_DEVICE_CONTROLLER, 2101, METHOD_BUFFERED, FILE_ANY_ACCESS)
++
++#define FSACTL_CLOSE_GET_ADAPTER_FIB CTL_CODE(FILE_DEVICE_CONTROLLER, 2102, METHOD_BUFFERED, FILE_ANY_ACCESS)
++
++#define FSACTL_OPEN_ADAPTER_CONFIG CTL_CODE(FILE_DEVICE_CONTROLLER, 2103, METHOD_NEITHER, FILE_ANY_ACCESS)
++
++#define FSACTL_CLOSE_ADAPTER_CONFIG CTL_CODE(FILE_DEVICE_CONTROLLER, 2104, METHOD_NEITHER, FILE_ANY_ACCESS)
++
++
++#define FSACTL_MINIPORT_REV_CHECK CTL_CODE(FILE_DEVICE_CONTROLLER, 2107, METHOD_BUFFERED, FILE_ANY_ACCESS)
++
++
++#define FSACTL_QUERY_ADAPTER_CONFIG CTL_CODE(FILE_DEVICE_CONTROLLER, 2113, METHOD_BUFFERED, FILE_ANY_ACCESS)
++
++
++#define FSACTL_FORCE_DELETE_DISK CTL_CODE(FILE_DEVICE_CONTROLLER, 2120, METHOD_NEITHER, FILE_ANY_ACCESS)
++
++
++#define FSACTL_AIF_THREAD CTL_CODE(FILE_DEVICE_CONTROLLER, 2127, METHOD_NEITHER, FILE_ANY_ACCESS)
++
++
++#endif // _FSAIOCTL_H_
++
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/fsaport.h linux/drivers/scsi/aacraid/include/fsaport.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/fsaport.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/fsaport.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,223 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * fsaport.h
++ *
++ * Abstract: This module defines all of the globally used procedures in the FSA
++ * file system.
++ *
++ *
++ *
++ --*/
++#ifndef _FSAPORT_
++#define _FSAPORT_
++
++static char *ident_fsaport = "aacraid_ident fsaport.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++//
++// The scatter/gather map context is the information we
++// we need to keep the map and transfer data to and from the
++// adapter.
++//
++
++typedef struct _SGMAP_CONTEXT {
++
++ caddr_t BaseAddress;
++ PVOID MapRegBase;
++ ULONG NumberMapRegs;
++ PSGMAP SgMapPtr;
++ ULONG ByteCount; // Used to check the Mdl length.
++ BOOLEAN WriteToDevice;
++
++ struct buf *bp;
++
++
++} SGMAP_CONTEXT;
++typedef SGMAP_CONTEXT *PSGMAP_CONTEXT;
++
++typedef struct _MAPFIB_CONTEXT {
++ PMDL Mdl;
++ PVOID MapRegBase;
++ ULONG NumberMapRegs;
++ PVOID FibVirtualAddress;
++ ULONG Size;
++ PVOID FibPhysicalAddress;
++
++
++} MAPFIB_CONTEXT;
++typedef MAPFIB_CONTEXT *PMAPFIB_CONTEXT;
++
++typedef BOOLEAN
++(*PFSA_ALLOCATE_ADAPTER_COMM_AREA)(
++ PVOID AdapterExtension,
++ IN OUT PVOID *BaseAddress,
++ IN ULONG Size,
++ IN ULONG Alignment
++ );
++
++typedef BOOLEAN
++(*PFSA_FREE_ADAPTER_COMM_AREA)(
++ PVOID AdapterExtension
++ );
++
++typedef VOID
++(*PFSA_FREE_DMA_RESOURCES)(
++ IN PVOID AdapterExtension,
++ IN PSGMAP_CONTEXT SgMapContext
++ );
++
++typedef BOOLEAN
++(*PFSA_ALLOCATE_AND_MAP_FIB_SPACE)(
++ IN PVOID AdapterExtension,
++ IN PMAPFIB_CONTEXT MapFibContext
++ );
++
++typedef BOOLEAN
++(*PFSA_UNMAP_AND_FREE_FIB_SPACE)(
++ IN PVOID AdapterExtension,
++ IN PMAPFIB_CONTEXT MapFibContext
++ );
++
++typedef VOID
++(*PFSA_INTERRUPT_ADAPTER)(
++ IN PVOID AdapterExtension
++ );
++
++typedef VOID
++(*PFSA_NOTIFY_ADAPTER)(
++ IN PVOID AdapterExtension,
++ IN HOST_2_ADAP_EVENT AdapterEvent
++ );
++
++typedef VOID
++(*PFSA_RESET_DEVICE)(
++ PVOID AdapterExtension
++ );
++
++typedef AAC_STATUS
++(*PFSA_BUILD_SGMAP)(
++ IN PVOID AdapterExtension,
++ IN PSGMAP_CONTEXT SgMapContext
++ );
++
++typedef PVOID
++(*PFSA_ADAPTER_ADDR_TO_SYSTEM_ADDR)(
++ IN PVOID AdapterExtension,
++ IN PVOID AdapterAddress
++ );
++
++typedef VOID
++(*PFSA_INTERRUPT_HOST)(
++ PVOID Adapter,
++ ADAPTER_EVENT AdapterEvent
++ );
++
++typedef VOID
++(*PFSA_ENABLE_INTERRUPT)(
++ PVOID Adapter,
++ ADAPTER_EVENT AdapterEvent,
++ BOOLEAN AtDeviceIrq
++ );
++
++
++typedef VOID
++(*PFSA_DISABLE_INTERRUPT)(
++ PVOID Adapter,
++ ADAPTER_EVENT AdapterEvent,
++ BOOLEAN AtDeviceIrq
++ );
++
++typedef AAC_STATUS
++(*PFSA_OPEN_ADAPTER) (
++ IN PVOID Adapter
++ );
++
++typedef int
++(*PFSA_DEVICE_CONTROL) (
++ IN PVOID Adapter,
++ IN PAFA_IOCTL_CMD IoctlCmdPtr
++ );
++
++typedef AAC_STATUS
++(*PFSA_CLOSE_ADAPTER) (
++ IN PVOID Adapter
++ );
++
++typedef BOOLEAN
++(*PFSA_SEND_SYNCH_FIB) (
++ IN PVOID Adapter,
++ IN ULONG FibPhysicalAddress
++ );
++
++typedef struct _FSAPORT_FUNCS {
++ ULONG SizeOfFsaPortFuncs;
++
++ PFSA_ALLOCATE_ADAPTER_COMM_AREA AllocateAdapterCommArea;
++ PFSA_FREE_ADAPTER_COMM_AREA FreeAdapterCommArea;
++ PFSA_FREE_DMA_RESOURCES FreeDmaResources;
++ PFSA_ALLOCATE_AND_MAP_FIB_SPACE AllocateAndMapFibSpace;
++ PFSA_UNMAP_AND_FREE_FIB_SPACE UnmapAndFreeFibSpace;
++ PFSA_INTERRUPT_ADAPTER InterruptAdapter;
++ PFSA_NOTIFY_ADAPTER NotifyAdapter;
++ PFSA_ENABLE_INTERRUPT EnableInterrupt;
++ PFSA_DISABLE_INTERRUPT DisableInterrupt;
++ PFSA_RESET_DEVICE ResetDevice;
++ PFSA_BUILD_SGMAP BuildSgMap;
++ PFSA_ADAPTER_ADDR_TO_SYSTEM_ADDR AdapterAddressToSystemAddress;
++
++ PFSA_INTERRUPT_HOST InterruptHost;
++ PFSA_OPEN_ADAPTER OpenAdapter;
++ PFSA_DEVICE_CONTROL DeviceControl;
++ PFSA_CLOSE_ADAPTER CloseAdapter;
++
++ PFSA_SEND_SYNCH_FIB SendSynchFib;
++
++} FSAPORT_FUNCS;
++typedef FSAPORT_FUNCS *PFSAPORT_FUNCS;
++
++typedef AAC_STATUS
++(*PFSA_SETVAR_CALLBACK) (
++ IN PVOID Adapter,
++ IN ULONG NewValue
++ );
++
++typedef struct _FSA_USER_VAR {
++ char Name[32];
++ ULONG *Address;
++ PFSA_SETVAR_CALLBACK SetVarCallback;
++} FSA_USER_VAR;
++
++typedef FSA_USER_VAR *PFSA_USER_VAR;
++
++typedef struct _FSA_NEW_ADAPTER {
++ PVOID AdapterExtension;
++ PFSAPORT_FUNCS AdapterFuncs;
++ PVOID Adapter;
++ BOOLEAN AdapterInterruptsBelowDpc;
++ PFSA_USER_VAR AdapterUserVars;
++ ULONG AdapterUserVarsSize;
++ void *Dip;
++} FSA_NEW_ADAPTER;
++typedef FSA_NEW_ADAPTER *PFSA_NEW_ADAPTER;
++
++#define FSAFS_GET_NEXT_ADAPTER CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2048, METHOD_NEITHER, FILE_ANY_ACCESS)
++#define FSAFS_INIT_NEW_ADAPTER CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2049, METHOD_NEITHER, FILE_ANY_ACCESS)
++
++#endif
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/fsatypes.h linux/drivers/scsi/aacraid/include/fsatypes.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/fsatypes.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/fsatypes.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,214 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * fsatypes.h
++ *
++ * Abstract: Define all shared data types here, ie, those
++ * types shared among several components, such
++ * as host (driver + apps), adapter, and BIOS.
++ *
++ *
++ --*/
++#ifndef _FSATYPES_H
++#define _FSATYPES_H
++
++static char *ident_fsatype = "aacraid_ident fsatypes.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++typedef AAC_UINT32 AAC_BOOLEAN;
++
++//
++// Define a 64-bit address structure for use on
++// a 32-bit processor architecture.
++//
++typedef struct {
++ AAC_UINT32 lo32;
++ AAC_UINT32 hi32;
++} AAC_UINT64S, *PAAC_UINT64S;
++
++
++
++//
++// Container Types
++//
++typedef struct {
++ AAC_UINT32 data[2]; // RMA FIX, make this a real serial number when we
++ // know what it looks like. Note, BIOS sees this
++ // definition and it must be coded in such a way
++ // that it appears to be 64 bits. ints are 16 bits
++ // in BIOS land; fortunately, longs are 32 bits.
++} SerialNumberT;
++
++
++
++//
++// ***********************
++// DON'T CHANGE THE ORDER, ctdevsw use this order to map the drivers
++// ***********************
++// drivers for CT_NONE to CT_PASSTHRU
++//
++typedef enum _FSAVOLTYPE {
++ CT_NONE = 0,
++ CT_VOLUME,
++ CT_MIRROR,
++ CT_STRIPE,
++ CT_RAID5,
++ CT_SSRW,
++ CT_SSRO,
++ CT_MORPH,
++ CT_PASSTHRU,
++ CT_RAID4,
++ CT_RAID10, // stripe of mirror
++ CT_RAID00, // stripe of stripe
++ CT_VOLUME_OF_MIRRORS, // volume of mirror
++ CT_PSEUDO_RAID3, // really raid4
++
++ CT_LAST_VOLUME_TYPE
++
++} _E_FSAVOLTYPE;
++
++#ifdef AAC_32BIT_ENUMS
++typedef _E_FSAVOLTYPE FSAVOLTYPE;
++#else
++typedef AAC_UINT32 FSAVOLTYPE;
++#endif
++
++
++//
++// Types of objects addressable in some fashion by the client.
++// This is a superset of those objects handled just by the filesystem
++// and includes "raw" objects that an administrator would use to
++// configure containers and filesystems.
++//
++typedef enum _FTYPE {
++ FT_REG = 1, // regular file
++ FT_DIR, // directory
++ FT_BLK, // "block" device - reserved
++ FT_CHR, // "character special" device - reserved
++ FT_LNK, // symbolic link
++ FT_SOCK, // socket
++ FT_FIFO, // fifo
++ FT_FILESYS, // ADAPTEC's "FSA"(tm) filesystem
++ FT_DRIVE, // physical disk - addressable in scsi by bus/target/lun
++ FT_SLICE, // virtual disk - raw volume - slice
++ FT_PARTITION, // FSA partition - carved out of a slice - building block for containers
++ FT_VOLUME, // Container - Volume Set
++ FT_STRIPE, // Container - Stripe Set
++ FT_MIRROR, // Container - Mirror Set
++ FT_RAID5, // Container - Raid 5 Set
++ FT_DATABASE // Storage object with "foreign" content manager
++} _E_FTYPE;
++
++#ifdef AAC_32BIT_ENUMS
++typedef _E_FTYPE FTYPE;
++#else
++typedef AAC_UINT32 FTYPE;
++#endif
++
++
++
++//
++// Host side memory scatter gather list
++// Used by the adapter for read, write, and readdirplus operations
++//
++typedef PAAC_UINT8 HOSTADDRESS;
++
++typedef struct _SGENTRY {
++ HOSTADDRESS SgAddress; /* 32-bit Base address. */
++ AAC_UINT32 SgByteCount; /* Length. */
++} SGENTRY;
++typedef SGENTRY *PSGENTRY;
++
++
++
++//
++// SGMAP
++//
++// This is the SGMAP structure for all commands that use
++// 32-bit addressing.
++//
++// Note that the upper 16 bits of SgCount are used as flags.
++// Only the lower 16 bits of SgCount are actually used as the
++// SG element count.
++//
++typedef struct _SGMAP {
++ AAC_UINT32 SgCount;
++ SGENTRY SgEntry[1];
++} SGMAP;
++typedef SGMAP *PSGMAP;
++
++
++
++//
++// SGMAP64
++//
++// This is the SGMAP structure for 64-bit container commands.
++//
++typedef struct _SGMAP64 {
++ AAC_UINT8 SgCount;
++ AAC_UINT8 SgSectorsPerPage;
++ AAC_UINT16 SgByteOffset; // For the first page
++ AAC_UINT64S SgEntry[1]; // Must be last entry
++} SGMAP64;
++typedef SGMAP64 *PSGMAP64;
++
++
++
++
++//
++// attempt at common time structure across host and adapter
++//
++typedef struct __TIME_T {
++
++ AAC_UINT32 tv_sec; /* seconds (maybe, depends upon host) */
++ AAC_UINT32 tv_usec; /* and nanoseconds (maybe, depends upon host)*/
++
++} TIME_T;
++typedef TIME_T *PTIME_T;
++
++#ifndef _TIME_T
++#define timespec __TIME_T
++#define ts_sec tv_sec
++#define ts_nsec tv_usec
++#endif
++
++
++
++
++typedef struct _ContainerCreationInfo
++{
++
++ AAC_UINT8 ViaBuildNumber; // e.g., 588
++ AAC_UINT8 MicroSecond; // e.g., 588
++ AAC_UINT8 Via; // e.g., 1 = FSU,
++ // 2 = API,
++ AAC_UINT8 YearsSince1900; // e.g., 1997 = 97
++ AAC_UINT32 Date; //
++ // unsigned Month :4; // 1 - 12
++ // unsigned Day :6; // 1 - 32
++ // unsigned Hour :6; // 0 - 23
++ // unsigned Minute :6; // 0 - 60
++ // unsigned Second :6; // 0 - 60
++ SerialNumberT ViaAdapterSerialNumber; // e.g., 0x1DEADB0BFAFAF001
++} ContainerCreationInfo;
++
++
++#endif // _FSATYPES_H
++
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/linit.h linux/drivers/scsi/aacraid/include/linit.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/linit.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/linit.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,107 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * linit.h
++ *
++ * Abstract: Header file for Linux Driver for Adaptec RAID Array Controller
++ *
++ --*/
++/*------------------------------------------------------------------------------
++ * I N C L U D E S
++ *----------------------------------------------------------------------------*/
++
++#ifndef _LINIT_H_
++#define _LINIT_H_
++
++static char *ident_linith = "aacraid_ident linit.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++#include <linux/config.h>
++
++/*------------------------------------------------------------------------------
++ * D E F I N E S
++ *----------------------------------------------------------------------------*/
++/* Define the AAC SCSI Host Template structure. */
++#define AAC_HOST_TEMPLATE_ENTRY \
++ { name: "AAC", /* Driver Name */ \
++ proc_info: AAC_ProcDirectoryInfo, /* ProcFS Info Func */ \
++ detect: AAC_DetectHostAdapter, /* Detect Host Adapter */ \
++ release: AAC_ReleaseHostAdapter, /* Release Host Adapter */ \
++ info: AAC_DriverInfo, /* Driver Info Function */ \
++ ioctl: AAC_Ioctl, /* ioctl Interface */ \
++ command: AAC_Command, /* unqueued command */ \
++ queuecommand: AAC_QueueCommand, /* Queue Command Function */ \
++ abort: AAC_AbortCommand, /* Abort Command Function */ \
++ reset: AAC_ResetCommand, /* Reset Command Function */ \
++ bios_param: AAC_BIOSDiskParameters, /* BIOS Disk Parameters */ \
++ can_queue: 1, /* Default initial value */ \
++ this_id: 0, /* Default initial value */ \
++ sg_tablesize: 0, /* Default initial value */ \
++ max_sectors: 128, /* max xfer size of 64k */ \
++ cmd_per_lun: 0, /* Default initial value */ \
++ present: 0, /* Default initial value */ \
++ unchecked_isa_dma: 0, /* Default Initial Value */ \
++ use_new_eh_code: 0, /* Default initial value */ \
++ eh_abort_handler: AAC_AbortCommand, /* New Abort Command func */ \
++ eh_strategy_handler: NULL, /* New Strategy Error Handler */ \
++ eh_device_reset_handler: NULL, /* New Device Reset Handler */ \
++ eh_bus_reset_handler: NULL, /* New Bus Reset Handler */ \
++ eh_host_reset_handler: NULL, /* New Host reset Handler */ \
++ use_clustering: ENABLE_CLUSTERING /* Disable Clustering */ \
++ }
++
++
++/*------------------------------------------------------------------------------
++ * T Y P E D E F S / S T R U C T S
++ *----------------------------------------------------------------------------*/
++typedef struct AAC_BIOS_DiskParameters
++{
++ int heads;
++ int sectors;
++ int cylinders;
++} AAC_BIOS_DiskParameters_T;
++
++
++/*------------------------------------------------------------------------------
++ * P R O G R A M G L O B A L S
++ *----------------------------------------------------------------------------*/
++
++const char *AAC_DriverInfo( struct Scsi_Host * );
++
++
++/*------------------------------------------------------------------------------
++ * F U N C T I O N P R O T O T Y P E S
++ *----------------------------------------------------------------------------*/
++/* Define prototypes for the AAC Driver Interface Functions. */
++int AAC_DetectHostAdapter( Scsi_Host_Template * );
++int AAC_ReleaseHostAdapter( struct Scsi_Host * );
++int AAC_QueueCommand( Scsi_Cmnd *, void ( *CompletionRoutine )( Scsi_Cmnd * ) );
++int AAC_Command( Scsi_Cmnd * );
++int AAC_ResetCommand( Scsi_Cmnd *, unsigned int );
++int AAC_BIOSDiskParameters( Disk *, kdev_t, int * );
++int AAC_ProcDirectoryInfo( char *, char **, off_t, int, int, int );
++int AAC_Ioctl( Scsi_Device *, int, void * );
++
++
++void AAC_SelectQueueDepths( struct Scsi_Host *, Scsi_Device * );
++
++
++int AAC_AbortCommand( Scsi_Cmnd *scsi_cmnd_ptr );
++
++#endif /* _LINIT_H_ */
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/monkerapi.h linux/drivers/scsi/aacraid/include/monkerapi.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/monkerapi.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/monkerapi.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,98 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * monkerapi.h
++ *
++ * Abstract: This module contains the definitions used by the Host Adapter
++ * Communications interface.
++ * This is the interface used for by host programs and the Adapter
++ * to communicate via synchronous commands via a shared set of registers
++ * on a platform (typically doorbells and mailboxes).
++ *
++ --*/
++//**********************************************************************
++//
++// Monitor / Kernel API
++//
++// 03/24/1998 Bob Peret Initial creation
++//
++//**********************************************************************
++
++#ifndef MONKER_H
++#define MONKER_H
++
++static char *ident_monk = "aacraid_ident monkerapi.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++#define BREAKPOINT_REQUEST 0x00000004
++#define INIT_STRUCT_BASE_ADDRESS 0x00000005
++
++
++#define SEND_SYNCHRONOUS_FIB 0x0000000c
++
++
++
++//
++// Adapter Status Register
++//
++// Phase Staus mailbox is 32bits:
++// <31:16> = Phase Status
++// <15:0> = Phase
++//
++// The adapter reports is present state through the phase. Only
++// a single phase should be ever be set. Each phase can have multiple
++// phase status bits to provide more detailed information about the
++// state of the board. Care should be taken to ensure that any phase status
++// bits that are set when changing the phase are also valid for the new phase
++// or be cleared out. Adapter software (monitor, iflash, kernel) is responsible
++// for properly maintining the phase status mailbox when it is running.
++
++//
++// MONKER_API Phases
++//
++// Phases are bit oriented. It is NOT valid
++// to have multiple bits set
++//
++
++
++#define SELF_TEST_FAILED 0x00000004
++
++
++#define KERNEL_UP_AND_RUNNING 0x00000080
++#define KERNEL_PANIC 0x00000100
++
++
++
++//
++// Doorbell bit defines
++//
++
++
++#define DoorBellPrintfDone (1<<5) // Host -> Adapter
++
++
++#define DoorBellAdapterNormCmdReady (1<<1) // Adapter -> Host
++#define DoorBellAdapterNormRespReady (1<<2) // Adapter -> Host
++#define DoorBellAdapterNormCmdNotFull (1<<3) // Adapter -> Host
++#define DoorBellAdapterNormRespNotFull (1<<4) // Adapter -> Host
++#define DoorBellPrintfReady (1<<5) // Adapter -> Host
++
++
++#endif // MONKER_H
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/nodetype.h linux/drivers/scsi/aacraid/include/nodetype.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/nodetype.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/nodetype.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,67 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * nodetype.h
++ *
++ * Abstract: This module defines all of the node type codes used in this development
++ * shell. Every major data structure in the file system is assigned a node
++ * type code that is. This code is the first CSHORT in the structure and is
++ * followed by a CSHORT containing the size, in bytes, of the structure.
++ *
++ --*/
++#ifndef _NODETYPE_
++#define _NODETYPE_
++
++static char *ident_node = "aacraid_ident nodetype.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++typedef CSHORT NODE_TYPE_CODE;
++
++
++#define FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT ((NODE_TYPE_CODE)0x030b)
++#define FSAFS_NTC_FIB_CONTEXT ((NODE_TYPE_CODE)0x030c)
++
++
++typedef CSHORT NODE_BYTE_SIZE;
++
++
++//
++// The following definitions are used to generate meaningful blue bugcheck
++// screens. On a bugcheck the file system can output 4 ulongs of useful
++// information. The first ulong will have encoded in it a source file id
++// (in the high word) and the line number of the bugcheck (in the low word).
++// The other values can be whatever the caller of the bugcheck routine deems
++// necessary.
++//
++// Each individual file that calls bugcheck needs to have defined at the
++// start of the file a constant called BugCheckFileId with one of the
++// FSAFS_BUG_CHECK_ values defined below and then use FsaBugCheck to bugcheck
++// the system.
++//
++
++
++#define FSAFS_BUG_CHECK_COMMSUP (0X001e0000)
++#define FSAFS_BUG_CHECK_DPCSUP (0X001f0000)
++
++
++#define FsaBugCheck(A,B,C) { cmn_err( CE_PANIC, "aacdisk: module %x, line %x, 0x%x, 0x%x, 0x%x ", BugCheckFileId, __LINE__, A, B, C); }
++
++
++#endif // _NODETYPE_
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/nvramioctl.h linux/drivers/scsi/aacraid/include/nvramioctl.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/nvramioctl.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/nvramioctl.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,112 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * nvramioctl.h
++ *
++ * Abstract: This file defines the data structures related to querying
++ * and controlling the FSA NVRAM/WriteCache subsystem via the NVRAMIOCTL FIB.
++ *
++ --*/
++#ifndef _NVRAMIOCTL_H_
++#define _NVRAMIOCTL_H_ 1
++
++static char *ident_nvram = "aacraid_ident nvramioctl.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++/*
++ * NVRAM/Write Cache subsystem states
++ */
++typedef enum _NVSTATUS {
++ NVSTATUS_DISABLED = 0, // present, clean, not being used
++ NVSTATUS_ENABLED, // present, possibly dirty, ready for use
++ NVSTATUS_ERROR, // present, dirty, contains dirty data
++ // for bad/missing device
++ NVSTATUS_BATTERY, // present, bad or low battery, may contain dirty data
++ // for bad/missing device
++ NVSTATUS_UNKNOWN // present?????
++} _E_NVSTATUS;
++
++#ifdef AAC_32BIT_ENUMS
++typedef _E_NVSTATUS NVSTATUS;
++#else
++typedef AAC_UINT32 NVSTATUS;
++#endif
++
++/*
++ * NVRAM/Write Cache subsystem battery component states
++ *
++ */
++//NB: this enum should be identical to battery_status in nvram.h
++// or else collapsed into one enum someday
++typedef enum _NVBATTSTATUS {
++ NVBATTSTATUS_NONE = 0, // battery has no power or is not present
++ NVBATTSTATUS_LOW, // battery is low on power
++ NVBATTSTATUS_OK, // battery is okay - normal operation possible only in this state
++ NVBATTSTATUS_RECONDITIONING // no battery present - reconditioning in process
++} _E_NVBATTSTATUS;
++
++#ifdef AAC_32BIT_ENUMS
++typedef _E_NVBATTSTATUS NVBATTSTATUS;
++#else
++typedef AAC_UINT32 NVBATTSTATUS;
++#endif
++
++/*
++ * battery transition type
++ */
++typedef enum _NVBATT_TRANSITION {
++ NVBATT_TRANSITION_NONE = 0, // battery now has no power or is not present
++ NVBATT_TRANSITION_LOW, // battery is now low on power
++ NVBATT_TRANSITION_OK // battery is now okay - normal operation possible only in this state
++} _E_NVBATT_TRANSITION;
++
++#ifdef AAC_32BIT_ENUMS
++typedef _E_NVBATT_TRANSITION NVBATT_TRANSITION;
++#else
++typedef AAC_UINT32 NVBATT_TRANSITION;
++#endif
++
++/*
++ * NVRAM Info structure returned for NVRAM_GetInfo call
++ */
++typedef struct _NVRAMDEVINFO {
++ AAC_UINT32 NV_Enabled; /* write caching enabled */
++ AAC_UINT32 NV_Error; /* device in error state */
++ AAC_UINT32 NV_NDirty; /* count of dirty NVRAM buffers */
++ AAC_UINT32 NV_NActive; /* count of NVRAM buffers being written */
++} NVRAMDEVINFO, *PNVRAMDEVINFO;
++
++typedef struct _NVRAMINFO {
++ NVSTATUS NV_Status; /* nvram subsystem status */
++ NVBATTSTATUS NV_BattStatus; /* battery status */
++ AAC_UINT32 NV_Size; /* size of WriteCache NVRAM in bytes */
++ AAC_UINT32 NV_BufSize; /* size of NVRAM buffers in bytes */
++ AAC_UINT32 NV_NBufs; /* number of NVRAM buffers */
++ AAC_UINT32 NV_NDirty; /* count of dirty NVRAM buffers */
++ AAC_UINT32 NV_NClean; /* count of clean NVRAM buffers */
++ AAC_UINT32 NV_NActive; /* count of NVRAM buffers being written */
++ AAC_UINT32 NV_NBrokered; /* count of brokered NVRAM buffers */
++ NVRAMDEVINFO NV_DevInfo[NFILESYS]; /* per device info */
++ AAC_UINT32 NV_BattNeedsReconditioning; /* boolean */
++ AAC_UINT32 NV_TotalSize; /* total size of all non-volatile memories in bytes */
++} NVRAMINFO, *PNVRAMINFO;
++
++#endif /* !_NVRAMIOCTL_H_ */
++
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/osheaders.h linux/drivers/scsi/aacraid/include/osheaders.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/osheaders.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/osheaders.h Thu Aug 16 18:12:22 2001
+@@ -0,0 +1,127 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * osheaders.h
++ *
++ * Abstract: Holds all of the header file includes for a particular O/S flavor.
++ *
++ --*/
++#ifndef _OSHEADERS_H_
++#define _OSHEADERS_H_
++
++static char *ident_oshead = "aacraid_ident osheaders.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/blk.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/ioport.h>
++#include <linux/mm.h>
++#include <linux/sched.h>
++#include <linux/stat.h>
++#include <linux/pci.h>
++#include <linux/interrupt.h>
++#include <asm/dma.h>
++#include <asm/io.h>
++#include <linux/spinlock.h>
++#include <asm/system.h>
++#include <asm/bitops.h>
++#include <asm/uaccess.h>
++#include <linux/wait.h>
++#include <linux/slab.h>
++#include <linux/tqueue.h>
++#include "ostypes.h"
++#include "scsi.h"
++#include "hosts.h"
++
++#ifndef intptr_t
++#define intptr_t void *
++#endif
++
++#ifndef cred_t
++#define cred_t void
++#endif
++
++#ifndef paddr32_t
++#define paddr32_t unsigned
++#endif
++
++#ifndef bzero
++#define bzero(b,len) memset(b,0,len)
++#endif
++
++#ifndef bcopy
++#define bcopy(src,dst,len) memcpy(dst,src,len )
++#endif
++
++#ifndef DEVICE_NR
++#define DEVICE_NR(device) ( ( ( MAJOR( device ) & 7 ) << 4 ) + ( MINOR( device ) >> 4 ) )
++#endif
++
++typedef unsigned uint_t;
++
++typedef enum
++{
++ CE_PANIC = 0,
++ CE_WARN,
++ CE_NOTE,
++ CE_CONT,
++ CE_DEBUG,
++ CE_DEBUG2,
++ CE_TAIL
++} CE_ENUM_T;
++
++#define CMN_ERR_LEVEL CE_NOTE
++
++#ifndef IN
++#define IN
++#endif
++
++// usage of READ & WRITE as a typedefs in protocol.h
++// conflicts with <linux/fs.h> definition.
++#ifdef READ
++#undef READ
++#endif
++
++#ifdef WRITE
++#undef WRITE
++#endif
++
++typedef struct aac_options
++{
++ int message_level;
++ int reverse_scan;
++} aac_options_t;
++
++#endif // _OSHEADERS_H_
++
++
++
++
++
++
++
++
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/ostypes.h linux/drivers/scsi/aacraid/include/ostypes.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/ostypes.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/ostypes.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,149 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * ostypes.h
++ *
++ * Abstract: Holds all of the O/S specific types.
++ *
++ --*/
++/*------------------------------------------------------------------------------
++ * D E F I N E S
++ *----------------------------------------------------------------------------*/
++#ifndef _OSTYPES_H_
++#define _OSTYPES_H_
++
++static char *ident_ostypes = "aacraid_ident ostypes.h 1.0.7 2000/10/11 Adaptec, Inc.";
++
++#include <linux/types.h>
++
++#define MAXIMUM_NUM_CONTAINERS 64 // 4 Luns * 16 Targets
++#define MAXIMUM_NUM_ADAPTERS 8
++
++#define OS_ALLOC_MEM_SLEEP GFP_KERNEL
++
++#define Os_remove_softintr OsSoftInterruptRemove
++#define OsPrintf printk
++#define FsaCommPrint
++
++// the return values for copy_from_user & copy_to_user is the
++// number of bytes not transferred. Thus if an internal error
++// occurs, the return value is greater than zero.
++#define COPYIN(SRC,DST,COUNT,FLAGS) copy_from_user(DST,SRC,COUNT)
++#define COPYOUT(SRC,DST,COUNT,FLAGS) copy_to_user(DST,SRC,COUNT)
++
++#define copyin(SRC,DST,COUNT) copy_from_user(DST,SRC,COUNT)
++#define copyout(SRC,DST,COUNT) copy_to_user(DST,SRC,COUNT)
++
++/*------------------------------------------------------------------------------
++ * S T R U C T S / T Y P E D E F S
++ *----------------------------------------------------------------------------*/
++typedef struct OS_MUTEX
++{
++ unsigned long lock_var;
++ wait_queue_head_t wq;
++ unsigned owner;
++} OS_MUTEX;
++
++typedef struct OS_SPINLOCK
++{
++ spinlock_t spin_lock;
++ unsigned cpu_lock_count[NR_CPUS];
++ unsigned long cpu_flags[NR_CPUS];
++ long lockout_count;
++} OS_SPINLOCK;
++
++#ifdef CVLOCK_USE_SPINLOCK
++ typedef OS_SPINLOCK OS_CVLOCK;
++#else
++ typedef OS_MUTEX OS_CVLOCK;
++#endif
++
++typedef size_t OS_SIZE_T;
++
++typedef struct OS_CV_T
++{
++ unsigned long lock_var;
++ unsigned long type;
++ wait_queue_head_t wq;
++} OS_CV_T;
++
++struct fsa_scsi_hba {
++ void *CommonExtension;
++ unsigned long ContainerSize[MAXIMUM_NUM_CONTAINERS];
++ unsigned long ContainerType[MAXIMUM_NUM_CONTAINERS];
++ unsigned char ContainerValid[MAXIMUM_NUM_CONTAINERS];
++ unsigned char ContainerReadOnly[MAXIMUM_NUM_CONTAINERS];
++ unsigned char ContainerLocked[MAXIMUM_NUM_CONTAINERS];
++ unsigned char ContainerDeleted[MAXIMUM_NUM_CONTAINERS];
++ long ContainerDevNo[MAXIMUM_NUM_CONTAINERS];
++};
++
++typedef struct fsa_scsi_hba fsadev_t;
++
++typedef struct OsKI
++{
++ struct Scsi_Host *scsi_host_ptr;
++ void * dip; // #REVISIT#
++ fsadev_t fsa_dev;
++ int thread_pid;
++ int MiniPortIndex;
++} OsKI_t;
++
++#define dev_info_t fsadev_t
++
++typedef int OS_SPINLOCK_COOKIE;
++
++typedef unsigned int OS_STATUS;
++
++typedef struct tq_struct OS_SOFTINTR;
++
++typedef OS_SOFTINTR *ddi_softintr_t;
++
++
++
++//-----------------------------------------------------------------------------
++// Conditional variable functions
++
++void OsCv_init (
++ OS_CV_T *cv_ptr );
++
++
++//-----------------------------------------------------------------------------
++// Printing functions
++void printk_err(int flag, char *fmt, ...);
++
++#define cmn_err printk_err
++
++
++//
++// just ignore these solaris ddi functions in the code
++//
++#define DDI_SUCCESS 0
++
++#define ddi_add_softintr(A,B,C,D,E,F,G) OsSoftInterruptAdd(C,F,G)
++
++//#REVIEW#
++#define ddi_remove_softintr(A) 0
++#define ddi_get_soft_iblock_cookie(A, B, C) 0
++
++#define ASSERT(expr) ((void) 0)
++#define drv_usecwait udelay
++
++#endif // _OSTYPES_H_
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/pcisup.h linux/drivers/scsi/aacraid/include/pcisup.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/pcisup.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/pcisup.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,97 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * pcisup.h
++ *
++ * Abstract: This module defines functions that are defined in PciSup.c
++ *
++ --*/
++#ifndef _PCISUP_
++#define _PCISUP_
++
++static char *ident_pcisup = "aacraid_ident pcisup.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++
++/*
++ * define which interrupt handler needs to be installed
++ */
++
++#define SaISR 1
++#define RxISR 2
++
++typedef struct _PCI_MINIPORT_COMMON_EXTENSION {
++ ULONG AdapterNumber; // Which FSA# this miniport is
++
++ ULONG PciBusNumber; // Which PCI bus we are located on
++ ULONG PciSlotNumber; // Whiat PCI slot we are in
++
++ PVOID Adapter; // Back pointer to Fsa adapter object
++ ULONG AdapterIndex; // Index into PlxAdapterTypes array
++ PDEVICE_OBJECT DeviceObject; // Pointer to our device object
++
++ FSAPORT_FUNCS AdapterFuncs;
++ ULONG FilesystemRevision; // Main driver's revision number
++
++
++ PADAPTER_INIT_STRUCT InitStruct; // Holds initialization info to communicate with adapter
++ PVOID PhysicalInitStruct; // Holds physical address of the init struct
++
++
++ PVOID PrintfBufferAddress; // pointer to buffer used for printf's from the adapter
++
++ BOOLEAN AdapterPrintfsToScreen;
++ BOOLEAN AdapterConfigured; // set to true when we know adapter can take FIBs
++
++ void * MiniPort;
++
++ caddr_t CommAddress; // Base address of Comm area
++ paddr32_t CommPhysAddr; // Physical Address of Comm area
++ size_t CommSize;
++
++ OsKI_t OsDep; // OS dependent kernel interfaces
++
++
++} PCI_MINIPORT_COMMON_EXTENSION;
++
++typedef PCI_MINIPORT_COMMON_EXTENSION *PPCI_MINIPORT_COMMON_EXTENSION;
++
++typedef int
++(*PFSA_MINIPORT_INIT) (
++ IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension,
++ IN ULONG AdapterNumber,
++ IN ULONG PciBus,
++ IN ULONG PciSlot
++ );
++
++typedef struct _FSA_MINIPORT {
++ USHORT VendorId;
++ USHORT DeviceId;
++ USHORT SubVendorId;
++ USHORT SubSystemId;
++ PCHAR DevicePrefix;
++ PFSA_MINIPORT_INIT InitRoutine;
++ PCHAR DeviceName;
++ PCHAR Vendor;
++ PCHAR Model;
++} FSA_MINIPORT;
++typedef FSA_MINIPORT *PFSA_MINIPORT;
++
++
++#endif // _PCISUP_
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/perfpack.h linux/drivers/scsi/aacraid/include/perfpack.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/perfpack.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/perfpack.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,110 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * perfpack.h
++ *
++ * Abstract: This file defines the layout of the performance data that is passed
++ * back from the FSA filesystem driver.
++ *
++ *
++ --*/
++
++#ifndef _FSA_PERFPACK_H_
++#define _FSA_PERFPACK_H_ 1
++
++static char *ident_perf = "aacraid_ident perfpack.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++//#define FSA_DO_PERF 1 /* enable the engineering counters */
++
++#ifdef FSA_DO_PERF
++//
++// engineering counters
++//
++typedef struct _FSA_PERF_DATA {
++ ULONG FibsSent;
++ ULONG ReadDirs;
++ ULONG GetAttrs;
++ ULONG SetAttrs;
++ ULONG Lookups;
++ ULONG ReadFibs;
++ ULONG WriteFibs;
++ ULONG CreateFibs;
++ ULONG MakeDirs;
++ ULONG RemoveFibs;
++ ULONG RemoveDirs;
++ ULONG RenameFibs;
++ ULONG ReadDirPlus;
++ ULONG FsStat;
++ ULONG WriteBytes;
++ ULONG ReadBytes;
++// NT FSA entry points
++ ULONG FsaFsdCreateCount;
++ ULONG FsaFsdCloseCount;
++ ULONG FsaFsdReadCount;
++ ULONG FsaFsdWriteCount;
++ ULONG FsaFsdQueryInformationCount;
++
++ struct _FsaFsdSetInfomation{
++ ULONG FsaSetAllocationInfoCount;
++ ULONG FsaSetBasicInfoCount;
++ ULONG FsaSetDispositionInfoCount;
++ ULONG FsaSetEndOfFileInfoCount;
++ ULONG FsaSetPositionInfoCount;
++ ULONG FsaSetRenameInfoCount;
++ ULONG FsaClearArchiveBitCount;
++ };
++
++ ULONG FsaFsdFlushBuffersCount;
++ ULONG FsaFsdQueryVolumeInfoCount;
++ ULONG FsaFsdSetVolumeInfoCount;
++ ULONG FsaFsdCleanupCount;
++ ULONG FsaFsdDirectoryControlCount;
++ ULONG FsaFsdFileSystemControlCount;
++ ULONG FsaFsdLockControlCount;
++ ULONG FsaFsdDeviceControlCount;
++ ULONG FsaFsdShutdownCount;
++ ULONG FsaFsdQuerySecurityInfo;
++ ULONG FsaFsdSetSecurityInfo;
++ ULONG FastIoCheckIfPossibleCount;
++ ULONG FastIoReadCount;
++ ULONG FastIoWriteCount;
++ ULONG FastIoQueryBasicInfoCount;
++ ULONG FastIoQueryStandardInfoCount;
++ ULONG FastIoLockCount;
++ ULONG FastIoUnlockSingleCount;
++ ULONG FastIoUnlockAllCount;
++ ULONG FastIoUnlockAllByKeyCount;
++ ULONG FastIoDeviceControlCount;
++ } FSA_PERF_DATA;
++
++typedef FSA_PERF_DATA *PFSA_PERF_DATA;
++
++
++#else /* FSA_DO_PERF */
++
++//
++// engineering performance counters are disabled
++//
++#define FSA_DO_PERF_INC(Counter) /* */
++#define FSA_DO_FSP_PERF_INC(Counter) /* */
++
++#endif /* FSA_DO_PERF */
++
++#endif // _FSA_PERFPACK_H_
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/port.h linux/drivers/scsi/aacraid/include/port.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/port.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/port.h Thu Aug 16 18:16:55 2001
+@@ -0,0 +1,87 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * port.h
++ *
++ * Abstract: This module defines functions and structures that are in common among all miniports
++ *
++ *
++ --*/
++
++#ifndef _PORT_
++#define _PORT_
++
++static char *ident_porth = "aacraid_ident port.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++#ifdef DBG
++#define AfaPortPrint if (AfaPortPrinting) DbgPrint
++extern int AfaPortPrinting;
++#else
++#define AfaPortPrint
++#endif /* DBG */
++
++extern int AfaPortPrinting;
++
++
++BOOLEAN
++AfaPortAllocateAdapterCommArea(
++ IN PVOID Arg1,
++ IN OUT PVOID *CommHeaderAddress,
++ IN ULONG CommAreaSize,
++ IN ULONG CommAreaAlignment
++ );
++
++
++BOOLEAN
++AfaPortFreeAdapterCommArea(
++ IN PVOID Arg1
++ );
++
++
++AAC_STATUS
++AfaPortBuildSgMap(
++ PVOID Arg1,
++ IN PSGMAP_CONTEXT SgMapContext
++ );
++
++
++VOID
++AfaPortFreeDmaResources(
++ PVOID Arg1,
++ IN PSGMAP_CONTEXT SgMapContext
++ );
++
++
++BOOLEAN
++AfaPortAllocateAndMapFibSpace(
++ PVOID Arg1,
++ IN PMAPFIB_CONTEXT MapFibContext
++ );
++
++
++BOOLEAN
++AfaPortUnmapAndFreeFibSpace(
++ PVOID Arg1,
++ IN PMAPFIB_CONTEXT MapFibContext
++ );
++
++
++#endif // _PORT_
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/protocol.h linux/drivers/scsi/aacraid/include/protocol.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/protocol.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/protocol.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,249 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * protocol.h
++ *
++ * Abstract: Defines the commands and command data which enables the nt
++ * filesystem driver to be the client of the fsa adapter
++ * filesystem. This protocol is largely modeled after the NFS
++ * V3 protocol with modifications allowed due to the unique
++ * client/server model FSA works under.
++ *
++ *
++ *
++ --*/
++
++#ifndef _PROTOCOL_H_
++#define _PROTOCOL_H_
++
++static char *ident_protocol = "aacraid_ident protocol.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++#include <fsafs.h> // definition of FSAFID; includes fsatypes.h
++#include <nvramioctl.h> // for NVRAMINFO definition
++
++// #define MDL_READ_WRITE
++
++//
++// Define the command values
++//
++typedef enum _FSA_COMMANDS {
++ Null = 0,
++ GetAttributes,
++ SetAttributes,
++ Lookup,
++ ReadLink,
++ Read,
++ Write,
++ Create,
++ MakeDirectory,
++ SymbolicLink,
++ MakeNode,
++ Removex,
++ RemoveDirectoryx, // bkpfix added x to this because already defined in nt
++ Rename,
++ Link,
++ ReadDirectory,
++ ReadDirectoryPlus,
++ FileSystemStatus,
++ FileSystemInfo,
++ PathConfigure,
++ Commit,
++ Mount,
++ UnMount,
++ Newfs,
++ FsCheck,
++ FsSync,
++ SimReadWrite,
++ SetFileSystemStatus,
++ BlockRead,
++ BlockWrite,
++ NvramIoctl,
++ FsSyncWait,
++ ClearArchiveBit,
++#ifdef MDL_READ_WRITE
++ MdlReadComplete,
++ MdlWriteComplete,
++ MdlRead, // these are used solely for stats, Mdl really controlled by
++ MdlWrite, // flags field in Fib.
++#endif
++ SetAcl,
++ GetAcl,
++ AssignAcl,
++ FaultInsertion, // Fault Insertion Command
++ CrazyCache, // crazycache
++ MAX_FSACOMMAND_NUM //CJ: used for sizing stats array - leave last
++} _E_FSACOMMAND;
++
++#ifdef AAC_32BIT_ENUMS
++typedef _E_FSACOMMAND FSACOMMAND;
++#else
++typedef AAC_UINT32 FSACOMMAND;
++#endif
++
++
++
++//
++// Define the status returns
++//
++// See include\comm\errno.h for adapter kernel errno's
++typedef enum _FSASTATUS {
++ ST_OK = 0,
++ ST_PERM = 1,
++ ST_NOENT = 2,
++ ST_IO = 5,
++ ST_NXIO = 6,
++ ST_E2BIG = 7,
++ ST_ACCES = 13,
++ ST_EXIST = 17,
++ ST_XDEV = 18,
++ ST_NODEV = 19,
++ ST_NOTDIR = 20,
++ ST_ISDIR = 21,
++ ST_INVAL = 22,
++ ST_FBIG = 27,
++ ST_NOSPC = 28,
++ ST_ROFS = 30,
++ ST_MLINK = 31,
++ ST_WOULDBLOCK = 35,
++ ST_NAMETOOLONG = 63,
++ ST_NOTEMPTY = 66,
++ ST_DQUOT = 69,
++ ST_STALE = 70,
++ ST_REMOTE = 71,
++ ST_BADHANDLE = 10001,
++ ST_NOT_SYNC = 10002,
++ ST_BAD_COOKIE = 10003,
++ ST_NOTSUPP = 10004,
++ ST_TOOSMALL = 10005,
++ ST_SERVERFAULT = 10006,
++ ST_BADTYPE = 10007,
++ ST_JUKEBOX = 10008,
++ ST_NOTMOUNTED = 10009,
++ ST_MAINTMODE = 10010,
++ ST_STALEACL = 10011
++} _E_FSASTATUS;
++
++#ifdef AAC_32BIT_ENUMS
++typedef _E_FSASTATUS FSASTATUS;
++#else
++typedef AAC_UINT32 FSASTATUS;
++#endif
++
++//
++// On writes how does the client want the data written.
++//
++
++typedef enum _CACHELEVEL {
++ CSTABLE = 1,
++ CUNSTABLE
++} _E_CACHELEVEL;
++
++#ifdef AAC_32BIT_ENUMS
++typedef _E_CACHELEVEL CACHELEVEL;
++#else
++typedef AAC_UINT32 CACHELEVEL;
++#endif
++
++//
++// Lets the client know at which level the data was commited on a write request
++//
++
++typedef enum _COMMITLEVEL {
++ CMFILE_SYNCH_NVRAM = 1,
++ CMDATA_SYNCH_NVRAM,
++ CMFILE_SYNCH,
++ CMDATA_SYNCH,
++ CMUNSTABLE
++} _E_COMMITLEVEL;
++
++#ifdef AAC_32BIT_ENUMS
++typedef _E_COMMITLEVEL COMMITLEVEL;
++#else
++typedef AAC_UINT32 COMMITLEVEL;
++#endif
++
++
++
++//
++// The following are all the different commands or FIBs which can be sent to the
++// FSA filesystem. We will define a required subset which cannot return STATUS_NOT_IMPLEMENTED,
++// but others outside that subset are allowed to return not implemented. The client is then
++// responsible for dealing with the fact it is not implemented.
++//
++typedef AAC_INT8 FSASTRING[16];
++
++
++typedef AAC_UINT32 BYTECOUNT; // only 32 bit-ism
++
++
++
++//
++// BlockRead
++//
++
++typedef struct _BLOCKREAD { // variable size struct
++
++ FSACOMMAND Command;
++ AAC_UINT32 ContainerId;
++ BYTECOUNT BlockNumber;
++ BYTECOUNT ByteCount;
++ SGMAP SgMap; // Must be last in struct because it is variable
++
++} BLOCKREAD;
++typedef BLOCKREAD *PBLOCKREAD;
++
++typedef struct _BLOCKREADRESPONSE {
++
++ FSASTATUS Status;
++ BYTECOUNT ByteCount;
++
++} BLOCKREADRESPONSE;
++typedef BLOCKREADRESPONSE *PBLOCKREADRESPONSE;
++
++//
++// BlockWrite
++//
++
++typedef struct _BLOCKWRITE { // variable size struct
++
++ FSACOMMAND Command;
++ AAC_UINT32 ContainerId;
++ BYTECOUNT BlockNumber;
++ BYTECOUNT ByteCount;
++ CACHELEVEL Stable;
++ SGMAP SgMap; // Must be last in struct because it is variable
++
++} BLOCKWRITE;
++typedef BLOCKWRITE *PBLOCKWRITE;
++
++
++typedef struct _BLOCKWRITERESPONSE {
++
++ FSASTATUS Status;
++ BYTECOUNT ByteCount;
++ COMMITLEVEL Committed;
++
++} BLOCKWRITERESPONSE;
++typedef BLOCKWRITERESPONSE *PBLOCKWRITERESPONSE;
++
++
++
++#endif // _PROTOCOL_H_
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/revision.h linux/drivers/scsi/aacraid/include/revision.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/revision.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/revision.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,350 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * revision.h
++ *
++ * Abstract: This module contains all of the revision information for
++ * the FSA product, as well as the support routines for
++ * checking module compatibility.
++ *
++ * Before editing anything in this module, make sure that
++ * you read the comments. Some lines are changed automatically
++ * as part of the build, and should never be changed by hand.
++ *
++ * Routines (all inlines):
++ *
++ * RevGetBuildNumber - Retrieve current build number
++ * RevGetExternalRev - Retrieve revision for external use
++ * RevGetFullRevision - Retrieve full revision structure
++ *
++ * RevCheckCompatibility - Checks compatibility base on internal table
++ *
++ * RevCheckCompatibilityFullInfo - Check for static component
++ * RevGetCompInfoTableSize - Get size for static component table
++ * RevGetCompInfoTable - Get actual table to place on static component
++ * RevGetBuildNumberFromInfo - Get build number for static component.
++ *
++ *
++ *
++ --*/
++
++#ifndef _REVISION_H
++#define _REVISION_H
++
++static char *ident_revision = "aacraid_ident revision.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++#include "version.h" // revision numbers kept separate so they can be used by resource compiler as well
++
++typedef int REV_BOOL;
++
++#define REV_TRUE 1
++#define REV_FALSE 0
++
++//
++// Define Revision Levels for this product
++//
++// IMPORTANT: Do NOT modify BUILD_NUMBER define, this is modified
++// automatically by the build.
++//
++// Version is VMAJOR.MINOR-DASH TYPE (Build BUILD_NUMBER)
++//
++// IMPORTANT: Don't access these revisions directly. They can be
++// accessed via, the RevGetXxxxx rouines.
++//
++
++
++#define REV_AS_LONGWORD \
++ ((REV_MAJOR << 24) | (REV_MINOR << 16) | (REV_TYPE << 8) | (REV_DASH))
++
++
++
++#ifndef BIOS
++
++//
++// Enumerate the types of product levels we can have
++//
++enum {
++ RevType_Devo=1, // Development mode, testing all of latest
++ RevType_Alpha, // Alpha - Internal field test
++ RevType_Beta, // Beta - External field test
++ RevType_Release // Release - Retail version
++};
++
++//
++// Define the basic structure for all revision information. Note
++// that the ordering of the components is such that they should
++// always increase. dash will be updated the most, then the version
++// type, then minor and major.
++//
++typedef struct {
++ union {
++ struct {
++ unsigned char dash; // Dash version number
++ unsigned char type; // Type, 1=Devo, 2=Alpha, 3=Beta, 4=Release
++ unsigned char minor;// Minor version minor
++ unsigned char major;// Major version number
++ } comp; // Components to external viewed rev number
++ unsigned long ul; // External revision as single 32-bit value
++ } external; // External revision number (union)
++ unsigned long buildNumber; // Automatically generated build number
++} FsaRevision;
++
++
++//
++// Define simple routines to get basic revision information. The
++// definitions should never be accessed directly. These routines
++// are meant to be used to access all relevant information no matter
++// how simple.
++//
++static inline unsigned long RevGetBuildNumber() {return REV_BUILD_NUMBER;}
++
++static inline unsigned long RevGetExternalRev() {return REV_AS_LONGWORD;}
++
++
++//
++// Enumerate different components that may have to check
++// compatibility. This list of components can be changed
++// at any time.
++//
++// IMPORTANT: ONLY add to the END of this enum structure. Otherwise,
++// incompatibilities between component rev checking will
++// cause wrong checking results.
++//
++typedef enum {
++ RevApplication = 1, // Any user End application
++ RevDkiCli, // ADAPTEC proprietary interface (knows FIBs)
++ RevNetService, // Network Service Revision (under API)
++ RevApi, // ADAPTEC User mode API
++ RevFileSysDriver, // FSA File System Driver
++ RevMiniportDriver, // FSA File System Miniport Driver
++ RevAdapterSW, // Adapter Software (or NT Simulator)
++ RevMonitor, // Monitor for adapter hardware (MON960 for now)
++ RevRemoteApi // The remote API.
++ // ALWAYS ADD NEW COMPONENTS HERE - AT END
++} RevComponent;
++
++//
++// Define a structure so that we can create a compatibility table.
++//
++typedef struct {
++ RevComponent A,B;
++ unsigned long BuildNumOfB_RequiredByA;
++ unsigned long BuildNumOfA_RequiredByB;
++} RevCompareElement;
++
++//
++// Now, define the table. This table should only be included once,
++// in one program. If it is linked from 2 modules, there will likely
++// be a multiply defined symbol error from the linker.
++//
++// To fix this problem, REV_REFERENCE_ONLY can be defined. This will
++// allow access to the revision information table without a redefinition
++// of the tables.
++//
++extern const int RevCompareTableLength;
++
++extern const RevCompareElement RevCompareTable[];
++
++/********************************************************************\
++* Routine: RevCheckCompatibility(callerComp,compB,compB_BuildNumber)
++*
++* The following routine is used to check compatibility between
++* the calling component and a component that has some dependencies
++* on it. If this routine returns REV_FALSE, it is expected that the caller
++* will send an appropriate incompatibility message and stop.
++*
++* This routine is only meant to check for compatibility in the
++* absolute sense. If code wishes to execute a different path based
++* on the CompB_BuildNumber, then this routine is not useful. The
++* routine RevGetBuildNumber can be used to get the calling module's
++* current build number for a comparison check.
++*
++* The return value is REV_TRUE, if compatibility is possible, and REV_FALSE
++* if the components are definitely not compatible, or there is an
++* error when trying to figure it out. To be more specific:
++*
++* 1) REV_TRUE if component B is newer than calling component. (In this
++* case, the revision check done by component B with respect to
++* this component will give the real compatibility information.
++* It is the only one with the knowledge, since this component
++* could not look into the future.)
++* 2) REV_TRUE if calling component is more recent and table shows okay
++* 3) REV_FALSE if calling component more recent and table show not okay
++* 4) REV_FALSE if calling component is more recent and table entry to
++* check does not exist.
++*
++* Note that the CompB_BuildNumber must be attained by the calling
++* routine through some mechanism done by the caller.
++*
++* Input:
++*
++* callerComp - Name of component making this call
++* compB - Name of component to check compatibility with
++* compB_BuildNumber - Build number to component B
++*
++* Output:
++*
++* None
++*
++* Return Value:
++*
++* REV_TRUE - Component compatibility is possible, continue as usual. compB
++* must give true compatibility information.
++* REV_FALSE - Incompatible components, notify and end
++*
++\********************************************************************/
++static inline REV_BOOL RevCheckCompatibility(
++ RevComponent callerComp,
++ RevComponent compB,
++ unsigned long compB_BuildNumber)
++{
++ int i;
++ unsigned long RevForB;
++
++ //
++ // Compatibility check is possible, so we should continue. When
++ // compB makes this call in its own component, it will get the
++ // true compatibility information, since only it can know.
++ //
++ if (RevGetBuildNumber() < compB_BuildNumber) return REV_TRUE;
++
++ //
++ // Go through rev table. When the components are found in the
++ // same table entry, return the approprate number.
++ //
++ for (i=0; i<RevCompareTableLength; i++) {
++ if (RevCompareTable[i].A == callerComp) {
++ if (RevCompareTable[i].B == compB) {
++ RevForB = RevCompareTable[i].BuildNumOfB_RequiredByA;
++ return (compB_BuildNumber >= RevForB);
++ }
++ } else if (RevCompareTable[i].B == callerComp) {
++ if (RevCompareTable[i].A == compB) {
++ RevForB = RevCompareTable[i].BuildNumOfA_RequiredByB;
++ return (compB_BuildNumber >= RevForB);
++ }
++ }
++ }
++
++ //
++ // Uh oh! No relevant table entry was found (this should never
++ // happen).
++ //
++ return REV_FALSE;
++}
++
++
++//
++// Now create a structure that can be used by a FIB to check
++// compatibility.
++//
++typedef struct _RevCheck {
++ RevComponent callingComponent;
++ FsaRevision callingRevision;
++} RevCheck;
++
++typedef struct _RevCheckResp {
++ REV_BOOL possiblyCompatible;
++ FsaRevision adapterSWRevision;
++} RevCheckResp;
++
++#endif /* bios */
++#endif /* _REVISION_H */
++
++//
++// The following allows for inclusion of revision.h in other h
++// files. when you include this file in another h file, simply
++// define REV_REFERENCE_ONLY. This will be undefined later, so that
++// the single C file inclusion in the module will be used to
++// implement the global structures.
++//
++#ifndef REV_REFERENCE_ONLY
++#ifndef _REVISION_H_GLOBAL
++#define _REVISION_H_GLOBAL
++
++
++
++//
++// The following array is the table of compatibility. This table
++// can be modified in two ways:
++//
++// 1) A component which has an incompatible change done to
++// it, can get a new build number.
++//
++// 2) A new component can be added, requiring more entries
++// to be place into this table.
++//
++//
++// In case (1), you must change the revision number in the appropriate
++// column, based on which component absolutely requires an upgrade.
++//
++// Example: A new FIB used by the API, in build number 105
++// {RevApi, RevAdapterSW, 100, 100}
++// ---> would be changed to <---
++// {RevApi, RevAdapterSW, 105, 100}
++//
++// Example: A structure is changed for a FIB that only the API uses
++// {RevApi, RevAdapterSW, 100, 100}
++// ---> would be changed to <---
++// {RevApi, RevAdapterSW, 105, 105}
++//
++//
++// In case (2), the less common case, the enumerated list of
++// components must be changed to include the new component. Then
++// entries need to be placed into this table.
++//
++// Since the revisions must be communicated between the two
++// components, it is likely that you would need to put in the
++// current build number for both columns. That is the recommended
++// way to start revision test.
++//
++const RevCompareElement RevCompareTable[] = {
++ // Component A Component B MinBForA MinAForB
++ // ----------- ----------- -------- --------
++ {RevApplication, RevApi, 2120, 2120 },
++ {RevDkiCli, RevApi, 2120, 2120 },
++ {RevDkiCli, RevFileSysDriver, 257, 257 },
++ {RevDkiCli, RevMiniportDriver, 257, 257 },
++ {RevDkiCli, RevAdapterSW, 257, 257 },
++ {RevApi, RevFileSysDriver, 2120, 2120 },
++ {RevApi, RevMiniportDriver, 2120, 2120 },
++ {RevApi, RevAdapterSW, 2120, 2120 },
++ {RevApi, RevNetService, 2120, 2120 },
++ {RevFileSysDriver, RevMiniportDriver, 100, 100 },
++ {RevFileSysDriver, RevAdapterSW, 257, 257 },
++ {RevMiniportDriver, RevAdapterSW, 257, 257 },
++ {RevMiniportDriver, RevMonitor, 100, 100 },
++ {RevApi, RevNetService, 2120, 2120 },
++ {RevApi, RevRemoteApi, 2120, 2120 },
++ {RevNetService, RevRemoteApi, 2120, 2120 }
++};
++
++const int RevCompareTableLength = sizeof(RevCompareTable)/sizeof(RevCompareElement);
++
++#endif /* _REVISION_H_GLOBAL */
++#endif /* REV_REFERENCE_ONLY */
++#undef REV_REFERENCE_ONLY
++
++
++
++
++
++
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/rx.h linux/drivers/scsi/aacraid/include/rx.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/rx.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/rx.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,81 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * rx.h
++ *
++ * Abstract: Prototypes and data structures unique to the Rx based controller board.
++ *
++ *
++ --*/
++
++static char *ident_rxh = "aacraid_ident rx.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++typedef struct _Rx_ADAPTER_EXTENSION {
++
++ //
++ // The following must be first.
++ //
++ PPCI_MINIPORT_COMMON_EXTENSION Common;
++ struct _Rx_ADAPTER_EXTENSION *Next; // Next adapter miniport structure
++ USHORT LocalMaskInterruptControl;
++ PRx_DEVICE_REGISTERS Device;
++
++} Rx_ADAPTER_EXTENSION;
++
++
++typedef Rx_ADAPTER_EXTENSION *PRx_ADAPTER_EXTENSION;
++
++
++
++#ifdef LINUX
++/*
++ *
++ */
++
++#define Rx_READ_UCHAR(AEP, CSR) *(volatile unsigned char *) &((AEP)->Device->CSR)
++
++
++
++#define Rx_READ_ULONG(AEP, CSR) *(volatile unsigned int *) &((AEP)->Device->CSR)
++#define Rx_WRITE_UCHAR(AEP, CSR, Value) *(volatile unsigned char *) &((AEP)->Device->CSR) = (Value)
++
++
++#define Rx_WRITE_ULONG(AEP, CSR, Value) *(volatile unsigned int *) &((AEP)->Device->CSR) = (Value)
++
++#endif /* LINUX */
++
++
++VOID
++RxInterruptAdapter(
++ PVOID Arg1
++ );
++
++VOID
++RxNotifyAdapter(
++ PVOID Arg1,
++ IN HOST_2_ADAP_EVENT AdapterEvent
++ );
++
++VOID
++RxResetDevice(
++ PVOID Arg1
++ );
++
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/rxcommon.h linux/drivers/scsi/aacraid/include/rxcommon.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/rxcommon.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/rxcommon.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,105 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * rxcommon.h
++ *
++ * Abstract: Structures and defines for the i960 Rx chip.
++ *
++ *
++ --*/
++
++#ifndef _Rx_COMMON_H_
++#define _Rx_COMMON_H_
++
++static char *ident_rxcommon = "aacraid_ident rxcommon.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++//
++// Rx Message Unit Registers
++//
++
++typedef volatile struct _StructRxMURegisters {
++ // Local | PCI* | Name
++ // | |
++ unsigned ARSR; // 1300h | 00h | APIC Register Select Register
++ unsigned reserved0; // 1304h | 04h | Reserved
++ unsigned AWR; // 1308h | 08h | APIC Window Register
++ unsigned reserved1; // 130Ch | 0Ch | Reserved
++ unsigned IMRx[2]; // 1310h | 10h | Inbound Message Registers
++ unsigned OMRx[2]; // 1318h | 18h | Outbound Message Registers
++ unsigned IDR; // 1320h | 20h | Inbound Doorbell Register
++ unsigned IISR; // 1324h | 24h | Inbound Interrupt Status Register
++ unsigned IIMR; // 1328h | 28h | Inbound Interrupt Mask Register
++ unsigned ODR; // 132Ch | 2Ch | Outbound Doorbell Register
++ unsigned OISR; // 1330h | 30h | Outbound Interrupt Status Register
++ unsigned OIMR; // 1334h | 34h | Outbound Interrupt Mask Register
++ // * Must access trhough ATU Inbound Translation Window
++
++}Rx_MU_CONFIG;
++typedef Rx_MU_CONFIG *PRx_MU_CONFIG;
++
++typedef volatile struct _Rx_Inbound {
++
++ unsigned Mailbox[8];
++
++}Rx_Inbound;
++
++typedef Rx_Inbound *PRx_Inbound;
++
++#define InboundMailbox0 IndexRegs.Mailbox[0]
++#define InboundMailbox1 IndexRegs.Mailbox[1]
++#define InboundMailbox2 IndexRegs.Mailbox[2]
++#define InboundMailbox3 IndexRegs.Mailbox[3]
++#define InboundMailbox4 IndexRegs.Mailbox[4]
++
++
++
++#define INBOUNDDOORBELL_0 0x00000001
++#define INBOUNDDOORBELL_1 0x00000002
++#define INBOUNDDOORBELL_2 0x00000004
++#define INBOUNDDOORBELL_3 0x00000008
++#define INBOUNDDOORBELL_4 0x00000010
++#define INBOUNDDOORBELL_5 0x00000020
++#define INBOUNDDOORBELL_6 0x00000040
++
++
++#define OUTBOUNDDOORBELL_0 0x00000001
++#define OUTBOUNDDOORBELL_1 0x00000002
++#define OUTBOUNDDOORBELL_2 0x00000004
++#define OUTBOUNDDOORBELL_3 0x00000008
++#define OUTBOUNDDOORBELL_4 0x00000010
++
++
++#define InboundDoorbellReg MUnit.IDR
++
++#define OutboundDoorbellReg MUnit.ODR
++
++
++typedef struct _Rx_DEVICE_REGISTERS {
++ Rx_MU_CONFIG MUnit; // 1300h - 1334h
++ unsigned reserved1[6]; // 1338h - 134ch
++ Rx_Inbound IndexRegs;
++} Rx_DEVICE_REGISTERS;
++
++typedef Rx_DEVICE_REGISTERS *PRx_DEVICE_REGISTERS;
++
++
++#endif // _Rx_COMMON_H_
++
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/sap1.h linux/drivers/scsi/aacraid/include/sap1.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/sap1.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/sap1.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,85 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * sap1.h
++ *
++ * Abstract: Prototypes and data structures unique to the Strong Arm based controller board.
++ *
++ *
++ --*/
++#ifndef _SAP1_H_
++#define _SAP1_H_
++
++static char *ident_sap1h = "aacraid_ident sap1.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++#define Sa_MINIPORT_REVISION 1
++
++typedef struct _Sa_ADAPTER_EXTENSION {
++
++ //
++ // The following must be first.
++ //
++ PPCI_MINIPORT_COMMON_EXTENSION Common;
++ struct _Sa_ADAPTER_EXTENSION *Next; // Next adapter miniport structure
++ USHORT LocalMaskInterruptControl;
++ PSa_DEVICE_REGISTERS Device;
++
++} Sa_ADAPTER_EXTENSION;
++
++typedef Sa_ADAPTER_EXTENSION *PSa_ADAPTER_EXTENSION;
++
++
++
++#ifdef LINUX
++/*
++ *
++ */
++
++
++#define Sa_READ_USHORT(AEP, CSR) *(volatile unsigned short *) &((AEP)->Device->CSR)
++#define Sa_READ_ULONG(AEP, CSR) *(volatile unsigned int *) &((AEP)->Device->CSR)
++
++
++#define Sa_WRITE_USHORT(AEP, CSR, Value) *(volatile unsigned short *) &((AEP)->Device->CSR) = (Value)
++#define Sa_WRITE_ULONG(AEP, CSR, Value) *(volatile unsigned int *) &((AEP)->Device->CSR) = (Value)
++
++#endif /* LINUX */
++
++
++VOID
++SaInterruptAdapter(
++ PVOID Arg1
++ );
++
++VOID
++SaNotifyAdapter(
++ PVOID Arg1,
++ IN HOST_2_ADAP_EVENT AdapterEvent
++ );
++
++VOID
++SaResetDevice(
++ PVOID Arg1
++ );
++
++
++#endif /* _SAP1_H_ */
++
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/sap1common.h linux/drivers/scsi/aacraid/include/sap1common.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/sap1common.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/sap1common.h Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,111 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * sap1common.h
++ *
++ * Abstract: Structures and defines for the Drawbridge and StrongArm110 chip.
++ *
++ --*/
++
++#ifndef _Sa_COMMON_H_
++#define _Sa_COMMON_H_
++
++static char *ident_sap1common = "aacraid_ident sap1common.h 1.0.6 2000/10/09 Adaptec, Inc.";
++
++//
++// SaP1 Message Unit Registers
++//
++
++typedef volatile struct _StructSaDrawbridge_CSR_RegisterMap {
++ // Offset | Name
++ unsigned reserved[10]; // 00h-27h | Reserved
++ unsigned char LUT_Offset; // 28h | Looup Table Offset
++ unsigned char reserved1[3]; // 29h-2bh | Reserved
++ unsigned LUT_Data; // 2ch | Looup Table Data
++ unsigned reserved2[26]; // 30h-97h | Reserved
++ unsigned short PRICLEARIRQ; // 98h | Primary Clear Irq
++ unsigned short SECCLEARIRQ; // 9ah | Secondary Clear Irq
++ unsigned short PRISETIRQ; // 9ch | Primary Set Irq
++ unsigned short SECSETIRQ; // 9eh | Secondary Set Irq
++ unsigned short PRICLEARIRQMASK; // a0h | Primary Clear Irq Mask
++ unsigned short SECCLEARIRQMASK; // a2h | Secondary Clear Irq Mask
++ unsigned short PRISETIRQMASK; // a4h | Primary Set Irq Mask
++ unsigned short SECSETIRQMASK; // a6h | Secondary Set Irq Mask
++ unsigned MAILBOX0; // a8h | Scratchpad 0
++ unsigned MAILBOX1; // ach | Scratchpad 1
++ unsigned MAILBOX2; // b0h | Scratchpad 2
++ unsigned MAILBOX3; // b4h | Scratchpad 3
++ unsigned MAILBOX4; // b8h | Scratchpad 4
++ unsigned MAILBOX5; // bch | Scratchpad 5
++ unsigned MAILBOX6; // c0h | Scratchpad 6
++ unsigned MAILBOX7; // c4h | Scratchpad 7
++
++ unsigned ROM_Setup_Data; // c8h | Rom Setup and Data
++ unsigned ROM_Control_Addr; // cch | Rom Control and Address
++
++ unsigned reserved3[12]; // d0h-ffh | reserved
++ unsigned LUT[64]; // 100h-1ffh| Lookup Table Entries
++
++ //
++ // TO DO
++ // need to add DMA, I2O, UART, etc registers form 80h to 364h
++ //
++
++}Sa_Drawbridge_CSR;
++
++typedef Sa_Drawbridge_CSR *PSa_Drawbridge_CSR;
++
++
++#define Mailbox0 SaDbCSR.MAILBOX0
++#define Mailbox1 SaDbCSR.MAILBOX1
++#define Mailbox2 SaDbCSR.MAILBOX2
++#define Mailbox3 SaDbCSR.MAILBOX3
++#define Mailbox4 SaDbCSR.MAILBOX4
++
++
++#define Mailbox7 SaDbCSR.MAILBOX7
++
++#define DoorbellReg_p SaDbCSR.PRISETIRQ
++#define DoorbellReg_s SaDbCSR.SECSETIRQ
++#define DoorbellClrReg_p SaDbCSR.PRICLEARIRQ
++
++
++#define DOORBELL_0 0x00000001
++#define DOORBELL_1 0x00000002
++#define DOORBELL_2 0x00000004
++#define DOORBELL_3 0x00000008
++#define DOORBELL_4 0x00000010
++#define DOORBELL_5 0x00000020
++#define DOORBELL_6 0x00000040
++
++
++#define PrintfReady DOORBELL_5
++#define PrintfDone DOORBELL_5
++
++typedef struct _Sa_DEVICE_REGISTERS {
++ Sa_Drawbridge_CSR SaDbCSR; // 98h - c4h
++} Sa_DEVICE_REGISTERS;
++
++typedef Sa_DEVICE_REGISTERS *PSa_DEVICE_REGISTERS;
++
++
++#endif // _Sa_COMMON_H_
++
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/include/version.h linux/drivers/scsi/aacraid/include/version.h
+--- linux-2.4.9/drivers/scsi/aacraid/include/version.h Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/include/version.h Thu Aug 16 18:16:55 2001
+@@ -0,0 +1,40 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * version.h
++ *
++ * Abstract: Keeps track of build number for development purposes.
++ *
++ --*/
++#ifndef _VERSION_H_
++#define _VERSION_H_
++
++static char *ident_version = "aacraid_ident version.h 1.0.7 2000/8/10 Adaptec, Inc.";
++
++#include "build_number.h"
++
++#define REV_MAJOR 3
++#define REV_MINOR 0
++#define REV_TYPE RevType_Release
++#define REV_DASH 0
++
++#define FSA_VERSION_STRING "3.0.0.5125\0"
++
++#endif /* _VERSION_H_ */
+diff -burN linux-2.4.9/drivers/scsi/aacraid/linit.c linux/drivers/scsi/aacraid/linit.c
+--- linux-2.4.9/drivers/scsi/aacraid/linit.c Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/linit.c Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,1086 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * linit.c
++ *
++ * Abstract: Linux Driver entry module for Adaptec RAID Array Controller
++ *
++ * Provides the following driver entry points:
++ * AAC_DetectHostAdapter()
++ * AAC_ReleaseHostAdapter()
++ * AAC_QueueCommand()
++ * AAC_ResetCommand()
++ * AAC_BIOSDiskParameters()
++ *
++ --*/
++
++static char *ident_linit = "aacraid_ident linit.c 1.0.6 2000/10/09 Adaptec, Inc.";
++
++/*------------------------------------------------------------------------------
++ * D E F I N E S
++ *----------------------------------------------------------------------------*/
++#define AAC_DRIVER_VERSION "0.1.1"
++#define AAC_DRIVER_BUILD_DATE __DATE__
++#define MAX_DRIVER_QUEUE_DEPTH 500
++
++/*------------------------------------------------------------------------------
++ * I N C L U D E S
++ *----------------------------------------------------------------------------*/
++#include "osheaders.h"
++
++#include "AacGenericTypes.h"
++
++#include <linux/module.h>
++#include "sd.h"
++#include "linit.h"
++#include "aac_unix_defs.h"
++#include "fsatypes.h"
++#include "comstruc.h"
++#include "fsaport.h"
++#include "pcisup.h"
++#include "port.h"
++#include "afacomm.h"
++#include "nodetype.h"
++#include "comsup.h"
++#include "adapter.h"
++
++/*------------------------------------------------------------------------------
++ * G L O B A L S
++ *----------------------------------------------------------------------------*/
++extern FSA_MINIPORT MiniPorts[];
++extern int CommPrinting;
++extern char DescriptionString[];
++extern char devicestr[];
++
++/*------------------------------------------------------------------------------
++ * M O D U L E G L O B A L S
++ *----------------------------------------------------------------------------*/
++aac_options_t g_options = { CMN_ERR_LEVEL, 0 }; // default message_level
++
++char g_DriverName[] = { "aacraid" };
++
++/*
++ The Loadable Kernel Module Installation Facility may pass us
++ a pointer to a driver specific options string to be parsed,
++ we assign this to options string.
++*/
++
++static char * aacraid_options = NULL;
++MODULE_PARM ( aacraid_options, "s" );
++MODULE_PARM_DESC ( aacraid_options, "message_level:(int) reverse_scan:1 (default 0)");
++
++
++static unsigned short perc_pciid[4] = { 0, 0, 0, 0 };
++MODULE_PARM ( perc_pciid, "4h");
++MODULE_PARM_DESC ( perc_pciid, "PCI vendor,device,subsystem vendor,subsystem device, for non-auto-recognized Dell PERC controllers.");
++
++static unsigned short rx_pciid[4] = { 0, 0, 0, 0 };
++MODULE_PARM ( rx_pciid, "4h");
++MODULE_PARM_DESC ( rx_pciid, "PCI vendor,device,subsystem vendor,subsystem device, for non-auto-recognized Adaptec Rx controllers.");
++
++static unsigned short sa_pciid[4] = { 0, 0, 0, 0 };
++MODULE_PARM ( sa_pciid, "4h");
++MODULE_PARM_DESC ( sa_pciid, "PCI vendor,device,subsystem vendor,subsystem device, for non-auto-recognized Adaptec Sa controllers.");
++
++MODULE_AUTHOR ("Adaptec OEM RAID Solutions");
++
++
++
++PCI_MINIPORT_COMMON_EXTENSION *g_CommonExtensionPtrArray[ MAXIMUM_NUM_ADAPTERS ];
++unsigned g_HostAdapterCount = 0;
++unsigned g_chardev_major = 0;
++
++int g_single_command_done = FALSE;
++
++/*------------------------------------------------------------------------------
++ * F U N C T I O N P R O T O T Y P E S
++ *----------------------------------------------------------------------------*/
++int AacHba_Ioctl(
++ PCI_MINIPORT_COMMON_EXTENSION *CommonExtension,
++ int cmd,
++ void * arg );
++
++int AacHba_ProbeContainers(
++ PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr );
++
++int AacHba_DoScsiCmd(
++ Scsi_Cmnd *scsi_cmnd_ptr,
++ int wait );
++
++void AacHba_DetachAdapter(
++ IN PVOID AdapterArg );
++
++int AacHba_ClassDriverInit(
++ PCI_MINIPORT_COMMON_EXTENSION * CommonExtensionPtr);
++
++void AacHba_AbortScsiCommand(
++ Scsi_Cmnd *scsi_cmnd_ptr );
++
++
++/*------------------------------------------------------------------------------
++ * L O C A L F U N C T I O N P R O T O T Y P E S
++ *----------------------------------------------------------------------------*/
++static int parse_keyword(
++ char ** str_ptr,
++ char * keyword );
++
++static void AAC_ParseDriverOptions(
++ char * cmnd_line_options_str );
++
++static void AAC_AnnounceDriver( void );
++
++int AAC_ChardevIoctl(
++ struct inode * inode_ptr,
++ struct file * file_ptr,
++ unsigned int cmd,
++ unsigned long arg );
++
++int AAC_ChardevOpen(
++ struct inode * inode_ptr,
++ struct file * file_ptr );
++
++int AAC_ChardevRelease(
++ struct inode * inode_ptr,
++ struct file * file_ptr );
++
++struct file_operations AAC_fops = {
++ NULL, // module name
++ NULL, // lseek
++ NULL, // read
++ NULL, // write
++ NULL, // readdir
++ NULL, // poll
++ AAC_ChardevIoctl, // ioctl
++ NULL, // mmap
++ AAC_ChardevOpen, // open
++ NULL, // flush
++ AAC_ChardevRelease, // release
++ NULL, // fsync
++ NULL, // fasync
++ NULL, // check media change
++ NULL, // revalidate
++ NULL // lock
++};
++
++/*------------------------------------------------------------------------------
++ * F U N C T I O N S
++ *----------------------------------------------------------------------------*/
++/*------------------------------------------------------------------------------
++ AAC_AnnounceDriver()
++
++ Announce the driver name, version and date.
++ *----------------------------------------------------------------------------*/
++static void AAC_AnnounceDriver( void ){
++ printk(KERN_ALERT "%s, %s\n",
++ "aacraid raid driver version", AAC_DRIVER_BUILD_DATE );
++ schedule();
++}
++
++
++/*------------------------------------------------------------------------------
++ AAC_DetectHostAdapter()
++
++ Probe for AAC Host Adapters initialize, register, and report the
++ configuration of each AAC Host Adapter found.
++
++ Preconditions:
++ Postconditions:
++ - Returns the number of adapters successfully initialized and
++ registered.
++ - Initialize all data necessary for this particular SCSI driver.
++ Notes:
++ The detect routine must not call any of the mid level functions
++ to queue commands because things are not guaranteed to be set
++ up yet. The detect routine can send commands to the host adapter
++ as long as the program control will not be passed to scsi.c in
++ the processing of the command. Note especially that
++ scsi_malloc/scsi_free must not be called.
++ *----------------------------------------------------------------------------*/
++int AAC_DetectHostAdapter (Scsi_Host_Template *HostTemplate)
++{
++ int index;
++ int ContainerId;
++ uint16_t vendor_id, device_id, sub_vendor_id, sub_system_id;
++ struct Scsi_Host *host_ptr;
++ PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr;
++ struct pci_dev *dev = NULL;
++ extern int NumMiniPorts;
++ fsadev_t *fsa_dev_ptr;
++ char *DeviceName;
++
++ struct pci_dev *devp;
++
++ int first_index, last_index, increment;
++
++ CommPrinting = TRUE;
++
++ EXPORT_NO_SYMBOLS;
++
++ AAC_AnnounceDriver();
++
++ /* setting up the proc directory structure */
++ HostTemplate->proc_name = "aacraid";
++
++ if( aacraid_options != NULL ) AAC_ParseDriverOptions( aacraid_options );
++
++ /* If we were passed a PCI device ID, handle that first. */
++ if ( perc_pciid[0] != 0 ) {
++ MiniPorts[0].VendorId = perc_pciid[0];
++ MiniPorts[0].DeviceId = perc_pciid[1];
++ MiniPorts[0].SubVendorId = perc_pciid[2];
++ MiniPorts[0].SubSystemId = perc_pciid[3];
++ }
++ if ( rx_pciid[0] != 0 ) {
++ MiniPorts[1].VendorId = rx_pciid[0];
++ MiniPorts[1].DeviceId = rx_pciid[1];
++ MiniPorts[1].SubVendorId = rx_pciid[2];
++ MiniPorts[1].SubSystemId = rx_pciid[3];
++ }
++ if ( sa_pciid[0] != 0 ) {
++ MiniPorts[2].VendorId = sa_pciid[0];
++ MiniPorts[2].DeviceId = sa_pciid[1];
++ MiniPorts[2].SubVendorId = sa_pciid[2];
++ MiniPorts[2].SubSystemId = sa_pciid[3];
++ }
++
++ // NumMiniPorts & MiniPorts[] defined in aacid.c
++ if (g_options.reverse_scan == 0) {
++ first_index = 0;
++ last_index = NumMiniPorts;
++ increment = 1;
++ } else {
++ first_index = NumMiniPorts -1;
++ last_index = -1;
++ increment = -1;
++ }
++
++ for( index = first_index; index != last_index; index += increment )
++ {
++ device_id = MiniPorts[index].DeviceId;
++ vendor_id = MiniPorts[index].VendorId;
++ DeviceName = MiniPorts[index].DeviceName;
++ cmn_err(CE_DEBUG, "Checking %s %x/%x/%x/%x",
++ DeviceName, vendor_id, device_id,
++ MiniPorts[index].SubVendorId,
++ MiniPorts[index].SubSystemId);
++
++ /* If vendor and device ID are 0, this is an unused entry, so skip! */
++ if ( vendor_id == 0 && device_id == 0 ) continue;
++
++ // pci_find_device traverses the pci_devices linked list for devices
++ // with matching vendor and device ids.
++
++ dev = NULL; // start from beginning of list
++ while( ( dev = pci_find_device( vendor_id, device_id, dev ) ) )
++ {
++ if (pci_enable_device(dev)) continue;
++
++ if( pci_read_config_word( dev, PCI_SUBSYSTEM_VENDOR_ID, &sub_vendor_id ) ){
++ cmn_err(CE_WARN, "pci_read_config_word SUBSYS_VENDOR_ID failed");
++ break;
++ }
++ if( pci_read_config_word( dev, PCI_SUBSYSTEM_ID, &sub_system_id ) ){
++ cmn_err(CE_WARN, "pci_read_config_work SUBSYSTEM_ID failed");
++ break;
++ }
++
++ cmn_err(CE_DEBUG, " found: %x/%x/%x/%x", vendor_id, device_id, sub_vendor_id, sub_system_id);
++ if( ( sub_vendor_id != MiniPorts[index].SubVendorId ) ||
++ ( sub_system_id != MiniPorts[index].SubSystemId ) ){
++ continue;
++ }
++
++
++ printk(KERN_ALERT "%s device detected\n", DeviceName );
++ cmn_err(CE_DEBUG, "%x/%x/%x/%x", vendor_id, device_id, sub_vendor_id, sub_system_id);
++
++ // Increment the host adapter count
++ g_HostAdapterCount++;
++
++ // scsi_register() allocates memory for a Scsi_Hosts structure and
++ // links it into the linked list of host adapters. This linked list
++ // contains the data for all possible <supported> scsi hosts.
++ // This is similar to the Scsi_Host_Template, except that we have
++ // one entry for each actual physical host adapter on the system,
++ // stored as a linked list. If there are two AAC boards, then we
++ // will need to make two Scsi_Host entries, but there will be only
++ // one Scsi_Host_Template entry. The second argument to scsi_register()
++ // specifies the size of the extra memory we want to hold any device
++ // specific information.
++ host_ptr = scsi_register( HostTemplate, sizeof( PCI_MINIPORT_COMMON_EXTENSION ) );
++
++ // These three parameters can be used to allow for wide SCSI
++ // and for host adapters that support multiple buses.
++ host_ptr->max_id = 17;
++ host_ptr->max_lun = 8;
++ host_ptr->max_channel = 1;
++
++
++ host_ptr->irq = dev->irq; // Adapter IRQ number
++ /* host_ptr->base = ( char * )(dev->resource[0].start & ~0xff); */
++ host_ptr->base = ( char * )(dev->resource[0].start);
++ scsi_set_pci_device(host_ptr, dev);
++
++ cmn_err( CE_DEBUG, "Device base address = 0x%lx [0x%lx]", host_ptr->base, dev->resource[0].start );
++ cmn_err( CE_DEBUG, "Device irq = 0x%lx", dev->irq );
++
++ // The unique_id field is a unique identifier that must be assigned
++ // so that we have some way of identifying each host adapter properly
++ // and uniquely. For hosts that do not support more than one card in the
++ // system, this does not need to be set. It is initialized to zero in
++ // scsi_register(). This is the value returned from OsGetDeviceInstance().
++
++ host_ptr->unique_id = g_HostAdapterCount - 1;
++ host_ptr->this_id = 16; // SCSI Id for the adapter itself
++
++ // Set the maximum number of simultaneous commands supported by the driver.
++ host_ptr->can_queue = MAX_DRIVER_QUEUE_DEPTH;
++
++ // Define the maximum number of scatter/gather elements supported by
++ // the driver.
++
++ host_ptr->sg_tablesize = 16;
++ host_ptr->max_sectors = 128;
++ host_ptr->cmd_per_lun = 1; // untagged queue depth
++
++ // This function is called after the device list has been built to find
++ // tagged queueing depth supported for each device.
++
++ host_ptr->select_queue_depths = AAC_SelectQueueDepths;
++ CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )host_ptr->hostdata;
++
++ // attach a pointer back to Scsi_Host
++ CommonExtensionPtr->OsDep.scsi_host_ptr = host_ptr;
++ CommonExtensionPtr->OsDep.MiniPortIndex = index;
++
++ // Initialize the ordinal number of the device to -1
++ fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev );
++ for( ContainerId = 0; ContainerId < MAXIMUM_NUM_CONTAINERS; ContainerId++ )
++ fsa_dev_ptr->ContainerDevNo[ContainerId] = -1;
++
++ // Call initialization routine
++ cmn_err (CE_DEBUG, "Initializing Hardware...\n");
++ if( ( *MiniPorts[index].InitRoutine )
++ ( CommonExtensionPtr, host_ptr->unique_id, dev->bus->number, 0 ) != 0 )
++ {
++ // device initialization failed
++ cmn_err( CE_WARN, "%s:%d device initialization failed", DeviceName, host_ptr->unique_id );
++ scsi_unregister( host_ptr );
++ g_HostAdapterCount--;
++ } /* end if */
++ else
++ {
++ cmn_err( CE_NOTE, "%s:%d device initialization successful", DeviceName, host_ptr->unique_id );
++ AacHba_ClassDriverInit( CommonExtensionPtr );
++ cmn_err(CE_NOTE, "%s:%d AacHba_ClassDriverInit complete", DeviceName, host_ptr->unique_id);
++ AacHba_ProbeContainers( CommonExtensionPtr );
++ g_CommonExtensionPtrArray[ g_HostAdapterCount - 1 ] = CommonExtensionPtr;
++
++ } /* end else */
++
++ } /* end while */
++
++ } /* end for */
++
++ if( g_HostAdapterCount ){
++ if( !( g_chardev_major = register_chrdev( 0, devicestr, &AAC_fops ) ) )
++ cmn_err( CE_WARN, "%s: unable to register %s device", DeviceName, devicestr);
++ }
++
++ HostTemplate->present = g_HostAdapterCount; // # of cards of this type found
++
++ return( g_HostAdapterCount );
++}
++
++
++/*------------------------------------------------------------------------------
++ AAC_ReleaseHostAdapter()
++
++ Release all resources previously acquired to support a specific Host
++ Adapter and unregister the AAC Host Adapter.
++ *----------------------------------------------------------------------------*/
++int AAC_ReleaseHostAdapter(
++ struct Scsi_Host *host_ptr )
++/*----------------------------------------------------------------------------*/
++{
++ PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr;
++
++ cmn_err( CE_DEBUG, "AAC_ReleaseHostAdapter" );
++
++ CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )host_ptr->hostdata;
++
++ // kill any threads we started
++ kill_proc( CommonExtensionPtr->OsDep.thread_pid, SIGKILL, 0 );
++
++ // Call the comm layer to detach from this adapter
++ AacHba_DetachAdapter( CommonExtensionPtr->Adapter );
++
++ // remove interrupt binding
++ OsDetachInterrupt( CommonExtensionPtr->MiniPort );
++
++ SaDetachDevice( CommonExtensionPtr );
++
++ // unregister adapter
++ scsi_unregister( host_ptr );
++
++ if( g_chardev_major )
++ {
++ unregister_chrdev( g_chardev_major, devicestr );
++ g_chardev_major = 0;
++ }
++
++ return( 0 ); // #REVISIT# return code
++}
++
++
++/*------------------------------------------------------------------------------
++ AAC_QueueCommand()
++
++ Queues a command for execution by the associated Host Adapter.
++ *----------------------------------------------------------------------------*/
++int AAC_QueueCommand(
++ Scsi_Cmnd *scsi_cmnd_ptr,
++ void ( *CompletionRoutine )( Scsi_Cmnd * ) )
++/*----------------------------------------------------------------------------*/
++{
++ int ret;
++ scsi_cmnd_ptr->scsi_done = CompletionRoutine;
++
++ // AacHba_DoScsiCmd() handles command processing, setting the
++ // result code and calling completion routine.
++ #ifdef SYNC_FIB
++ if( (ret = AacHba_DoScsiCmd( scsi_cmnd_ptr, 1 )) != 0 ) // call with wait = TRUE
++ #else
++ if( (ret = AacHba_DoScsiCmd( scsi_cmnd_ptr, 0 )) != 0 ) // call with wait = FALSE
++ #endif
++ cmn_err( CE_DEBUG, "AacHba_DoScsiCmd failed" );
++ return ret;
++}
++
++
++/*------------------------------------------------------------------------------
++ AAC_Done()
++
++ Callback function for a non-queued command.
++
++ Postconditions
++ Sets g_single_command done to TRUE
++ *----------------------------------------------------------------------------*/
++void AAC_Done(
++ Scsi_Cmnd * scsi_cmnd_ptr )
++/*----------------------------------------------------------------------------*/
++{
++ g_single_command_done = TRUE;
++}
++
++
++/*------------------------------------------------------------------------------
++ AAC_Command()
++
++ Accepts a single command for execution by the associated Host Adapter.
++
++ Postconditions
++ Returns an int where:
++ Byte 0 = SCSI status code
++ Byte 1 = SCSI 1 byte message
++ Byte 2 = host error return
++ Byte 3 = mid level error return
++ *----------------------------------------------------------------------------*/
++int AAC_Command(
++ Scsi_Cmnd *scsi_cmnd_ptr )
++/*----------------------------------------------------------------------------*/
++{
++ scsi_cmnd_ptr->scsi_done = AAC_Done;
++
++ cmn_err( CE_DEBUG, "AAC_Command" );
++
++ // AacHba_DoScsiCmd() handles command processing, setting the
++ // result code and calling completion routine.
++ g_single_command_done = FALSE;
++
++ AacHba_DoScsiCmd( scsi_cmnd_ptr, 0 );
++ while( !g_single_command_done );
++ return( scsi_cmnd_ptr->result );
++}
++
++
++/*------------------------------------------------------------------------------
++ AAC_AbortCommand()
++
++ Abort command if possible.
++ *----------------------------------------------------------------------------*/
++int AAC_AbortCommand(
++ Scsi_Cmnd *scsi_cmnd_ptr )
++/*----------------------------------------------------------------------------*/
++{
++ int target = scsi_cmnd_ptr->target;
++ int hba = scsi_cmnd_ptr->host->unique_id;
++ int result = 0;
++ u_short interrupt_status;
++ PCI_MINIPORT_COMMON_EXTENSION *cep;
++ char *DeviceName;
++
++ cmn_err( CE_WARN, "%s:%d ABORT", g_DriverName, hba, target );
++ AacHba_AbortScsiCommand( scsi_cmnd_ptr );
++
++ cep = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata );
++ DeviceName = MiniPorts[cep->OsDep.MiniPortIndex].DeviceName;
++
++ /*
++ cmn_err( CE_WARN, "%s:%d Unable to abort command to target %d - "
++ "command already completed", DeviceName, hba, target);
++ result = SCSI_ABORT_NOT_RUNNING;
++
++ cmn_err(CE_WARN, "%s:%d Unable to abort command to target %d - "
++ "no command found\n", DeviceName, hba, target);
++ result = SCSI_ABORT_NOT_RUNNING;
++
++ cmn_err(CE_WARN, "%s:%d Unable to abort command to target %d - "
++ "command reset\n", DeviceName, hba, target);
++ result = SCSI_ABORT_PENDING;
++
++ cmn_err(CE_WARN, "%s:%d Unable to abort command to target %d - "
++ "abort tag not supported\n", DeviceName, hba, target);
++ result = SCSI_ABORT_SNOOZE;
++
++ cmn_err(CE_WARN, "%s:%d Aborting command to target %d - pending",
++ DeviceName, hba, target);
++ result = SCSI_ABORT_PENDING;
++
++ cmn_err(CE_WARN, "%s:%d Unable to abort command to target %d",
++ DeviceName, hba, target);
++ result = SCSI_ABORT_BUSY;
++
++ cmn_err(CE_WARN, "%s:%d Aborted command to target %d\n",
++ DeviceName, hba, target);
++ result = SCSI_ABORT_SUCCESS;
++ */
++
++ // Abort not supported yet
++ result = SCSI_ABORT_BUSY;
++ return result;
++}
++
++
++/*------------------------------------------------------------------------------
++ AAC_ResetCommand()
++
++ Reset command handling.
++ *----------------------------------------------------------------------------*/
++int AAC_ResetCommand(
++ struct scsi_cmnd *scsi_cmnd_ptr,
++ unsigned int reset_flags )
++/*----------------------------------------------------------------------------*/
++{
++ int target = scsi_cmnd_ptr->target;
++ int hba = scsi_cmnd_ptr->host->unique_id;
++ PCI_MINIPORT_COMMON_EXTENSION *cep;
++ char *DeviceName;
++
++ cep = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata );
++ DeviceName = MiniPorts[cep->OsDep.MiniPortIndex].DeviceName;
++
++ cmn_err( CE_WARN, "%s:%d RESET", DeviceName, hba, target );
++
++ return SCSI_RESET_PUNT;
++}
++
++
++/*------------------------------------------------------------------------------
++ AAC_DriverInfo()
++
++ Returns the host adapter name
++ *----------------------------------------------------------------------------*/
++const char *AAC_DriverInfo(
++ struct Scsi_Host *host_ptr )
++/*----------------------------------------------------------------------------*/
++{
++ PCI_MINIPORT_COMMON_EXTENSION *cep;
++ char *DeviceName;
++
++ cep = ( PCI_MINIPORT_COMMON_EXTENSION * )( host_ptr->hostdata );
++ DeviceName = MiniPorts[cep->OsDep.MiniPortIndex].DeviceName;
++
++ cmn_err( CE_DEBUG, "AAC_DriverInfo" );
++ return (DeviceName);
++}
++
++
++/*------------------------------------------------------------------------------
++ AAC_BIOSDiskParameters()
++
++ Return the Heads/Sectors/Cylinders BIOS Disk Parameters for Disk.
++ The default disk geometry is 64 heads, 32 sectors, and the appropriate
++ number of cylinders so as not to exceed drive capacity. In order for
++ disks equal to or larger than 1 GB to be addressable by the BIOS
++ without exceeding the BIOS limitation of 1024 cylinders, Extended
++ Translation should be enabled. With Extended Translation enabled,
++ drives between 1 GB inclusive and 2 GB exclusive are given a disk
++ geometry of 128 heads and 32 sectors, and drives above 2 GB inclusive
++ are given a disk geometry of 255 heads and 63 sectors. However, if
++ the BIOS detects that the Extended Translation setting does not match
++ the geometry in the partition table, then the translation inferred
++ from the partition table will be used by the BIOS, and a warning may
++ be displayed.
++ *----------------------------------------------------------------------------*/
++int AAC_BIOSDiskParameters(
++ Scsi_Disk *scsi_disk_ptr,
++ kdev_t device,
++ int *parameter_ptr )
++/*----------------------------------------------------------------------------*/
++{
++ AAC_BIOS_DiskParameters_T *disk_parameters =
++ ( AAC_BIOS_DiskParameters_T *)parameter_ptr;
++ struct buffer_head * buffer_head_ptr;
++
++ cmn_err( CE_DEBUG, "AAC_BIOSDiskParameters" );
++
++ // Assuming extended translation is enabled - #REVISIT#
++ if( scsi_disk_ptr->capacity >= 2 * 1024 * 1024 ) // 1 GB in 512 byte sectors
++ {
++ if( scsi_disk_ptr->capacity >= 4 * 1024 * 1024 ) // 2 GB in 512 byte sectors
++ {
++ disk_parameters->heads = 255;
++ disk_parameters->sectors = 63;
++ }
++ else
++ {
++ disk_parameters->heads = 128;
++ disk_parameters->sectors = 32;
++ }
++ }
++ else
++ {
++ disk_parameters->heads = 64;
++ disk_parameters->sectors = 32;
++ }
++
++ disk_parameters->cylinders = scsi_disk_ptr->capacity
++ /( disk_parameters->heads * disk_parameters->sectors );
++
++ // Read the first 1024 bytes from the disk device
++ buffer_head_ptr = bread(
++ MKDEV( MAJOR( device ),
++ MINOR( device ) & ~0x0F ),
++ 0, 1024 );
++
++ if( buffer_head_ptr == NULL )
++ return( 0 );
++ /*
++ If the boot sector partition table is valid, search for a partition
++ table entry whose end_head matches one of the standard geometry
++ translations ( 64/32, 128/32, 255/63 ).
++ */
++ if( *( unsigned short * )( buffer_head_ptr->b_data + 0x1fe ) == 0xaa55 )
++ {
++ struct partition *first_partition_entry =
++ ( struct partition * )( buffer_head_ptr->b_data + 0x1be );
++ struct partition *partition_entry = first_partition_entry;
++ int saved_cylinders = disk_parameters->cylinders;
++ int partition_number;
++ unsigned char partition_entry_end_head, partition_entry_end_sector;
++
++ for( partition_number = 0; partition_number < 4; partition_number++ )
++ {
++ partition_entry_end_head = partition_entry->end_head;
++ partition_entry_end_sector = partition_entry->end_sector & 0x3f;
++
++ if( partition_entry_end_head == ( 64 - 1 ) )
++ {
++ disk_parameters->heads = 64;
++ disk_parameters->sectors = 32;
++ break;
++ }
++ else if( partition_entry_end_head == ( 128 - 1 ) )
++ {
++ disk_parameters->heads = 128;
++ disk_parameters->sectors = 32;
++ break;
++ }
++ else if( partition_entry_end_head == ( 255 - 1 ) )
++ {
++ disk_parameters->heads = 255;
++ disk_parameters->sectors = 63;
++ break;
++ }
++ partition_entry++;
++ }
++
++ if( partition_number == 4 )
++ {
++ partition_entry_end_head = first_partition_entry->end_head;
++ partition_entry_end_sector = first_partition_entry->end_sector & 0x3f;
++ }
++
++ disk_parameters->cylinders = scsi_disk_ptr->capacity
++ /( disk_parameters->heads * disk_parameters->sectors );
++
++ if( ( partition_number < 4 ) && ( partition_entry_end_sector == disk_parameters->sectors ) )
++ {
++ if( disk_parameters->cylinders != saved_cylinders )
++ cmn_err( CE_DEBUG, "Adopting geometry: heads=%d, sectors=%d from partition table %d",
++ disk_parameters->heads, disk_parameters->sectors, partition_number );
++ }
++ else if( ( partition_entry_end_head > 0 ) || ( partition_entry_end_sector > 0 ) )
++ {
++ cmn_err( CE_DEBUG, "Strange geometry: heads=%d, sectors=%d in partition table %d",
++ partition_entry_end_head + 1, partition_entry_end_sector, partition_number );
++ cmn_err( CE_DEBUG, "Using geometry: heads=%d, sectors=%d",
++ disk_parameters->heads, disk_parameters->sectors );
++ }
++ }
++
++ brelse( buffer_head_ptr );
++
++ return( 0 );
++}
++
++
++/*------------------------------------------------------------------------------
++ AAC_SelectQueueDepths()
++
++ Selects queue depths for each target device based on the host adapter's
++ total capacity and the queue depth supported by the target device.
++ A queue depth of one automatically disables tagged queueing.
++ *----------------------------------------------------------------------------*/
++void AAC_SelectQueueDepths(
++ struct Scsi_Host * host_ptr,
++ Scsi_Device * scsi_device_ptr )
++/*----------------------------------------------------------------------------*/
++{
++ Scsi_Device * device_ptr;
++
++ cmn_err( CE_DEBUG, "AAC_SelectQueueDepths" );
++ cmn_err( CE_DEBUG, "Device # Q Depth Online" );
++ cmn_err( CE_DEBUG, "---------------------------" );
++ for( device_ptr = scsi_device_ptr; device_ptr != NULL; device_ptr = device_ptr->next )
++ if( device_ptr->host == host_ptr )
++ {
++ device_ptr->queue_depth = 10;
++ cmn_err( CE_DEBUG, " %2d %d %d",
++ device_ptr->id, device_ptr->queue_depth, device_ptr->online );
++ }
++}
++
++
++/*------------------------------------------------------------------------------
++ AAC_SearchBiosSignature()
++
++ Locate adapter signature in BIOS
++ *----------------------------------------------------------------------------*/
++int AAC_SearchBiosSignature( void )
++/*----------------------------------------------------------------------------*/
++{
++ unsigned base;
++ unsigned namep;
++ int index;
++ int val;
++ char name_buf[32];
++ int result = FALSE;
++
++ for( base = 0xc8000; base < 0xdffff; base += 0x4000 )
++ {
++ val = readb( base );
++ if( val != 0x55 )
++ continue;
++
++ result = TRUE;
++ namep = base + 0x1e;
++ memcpy_fromio( name_buf, namep, 32 );
++ name_buf[31] = '\0';
++ }
++ return( result );
++}
++
++
++/*------------------------------------------------------------------------------
++ AAC_Ioctl()
++
++ Handle SCSI ioctls
++ *----------------------------------------------------------------------------*/
++int AAC_Ioctl(
++ Scsi_Device * scsi_dev_ptr,
++ int cmd,
++ void * arg )
++/*----------------------------------------------------------------------------*/
++{
++ PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr;
++
++ cmn_err( CE_DEBUG, "AAC_Ioctl" );
++ CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )scsi_dev_ptr->host->hostdata;
++ return( AacHba_Ioctl( CommonExtensionPtr, cmd, arg ) );
++}
++
++
++
++/*------------------------------------------------------------------------------
++ AAC_ChardevOpen()
++
++ Handle character device open
++
++ Preconditions:
++ Postconditions:
++ Returns 0 if successful, -ENODEV or -EINVAL otherwise
++ *----------------------------------------------------------------------------*/
++int AAC_ChardevOpen(
++ struct inode * inode_ptr,
++ struct file * file_ptr )
++/*----------------------------------------------------------------------------*/
++{
++ unsigned minor_number;
++
++ cmn_err( CE_DEBUG, "AAC_ChardevOpen" );
++
++ // check device permissions in file_ptr->f_mode ??
++
++ // extract & check the minor number
++ minor_number = MINOR( inode_ptr->i_rdev );
++ if( minor_number > ( g_HostAdapterCount - 1 ) )
++ {
++ cmn_err( CE_WARN, "AAC_ChardevOpen: Minor number %d not supported", minor_number );
++ return( -ENODEV );
++ }
++
++ MOD_INC_USE_COUNT;
++
++ return( 0 );
++}
++
++
++/*------------------------------------------------------------------------------
++ AAC_ChardevRelease()
++
++ Handle character device release.
++
++ Preconditions:
++ Postconditions:
++ Returns 0 if successful, -ENODEV or -EINVAL otherwise
++ *----------------------------------------------------------------------------*/
++int AAC_ChardevRelease(
++ struct inode * inode_ptr,
++ struct file * file_ptr )
++/*----------------------------------------------------------------------------*/
++{
++ cmn_err( CE_DEBUG, "AAC_ChardevRelease" );
++
++ MOD_DEC_USE_COUNT;
++
++ return( 0 );
++}
++
++
++/*------------------------------------------------------------------------------
++ AAC_ChardevIoctl()
++
++ Handle character device interface ioctls
++
++ Preconditions:
++ Postconditions:
++ Returns 0 if successful, -ENODEV or -EINVAL otherwise
++ *----------------------------------------------------------------------------*/
++int AAC_ChardevIoctl(
++ struct inode * inode_ptr,
++ struct file * file_ptr,
++ unsigned int cmd,
++ unsigned long arg )
++{
++ unsigned minor_number;
++ PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr;
++
++ cmn_err( CE_DEBUG, "AAC_ChardevIoctl" );
++
++ // check device permissions in file_ptr->f_mode ??
++
++ // extract & check the minor number
++ minor_number = MINOR( inode_ptr->i_rdev );
++ if( minor_number > ( g_HostAdapterCount - 1 ) )
++ {
++ cmn_err( CE_WARN, "AAC_ChardevIoctl: Minor number %d not supported", minor_number );
++ return( -ENODEV );
++ }
++
++ // get device pointer
++ CommonExtensionPtr = g_CommonExtensionPtrArray[ minor_number ];
++
++ // dispatch ioctl - AacHba_Ioctl() returns zero on success
++ if( AacHba_Ioctl( CommonExtensionPtr, cmd, ( void * )arg ) )
++ return( -EINVAL );
++
++ return( 0 );
++}
++
++
++/*------------------------------------------------------------------------------
++ parse_keyword()
++
++ Look for the keyword in str_ptr
++
++ Preconditions:
++ Postconditions:
++ If keyword found
++ - return true and update the pointer str_ptr.
++ otherwise
++ - return false
++ *----------------------------------------------------------------------------*/
++static int parse_keyword(
++ char ** str_ptr,
++ char * keyword )
++/*----------------------------------------------------------------------------*/
++{
++ char * ptr = *str_ptr;
++
++ while( *keyword != '\0' )
++ {
++ char string_char = *ptr++;
++ char keyword_char = *keyword++;
++
++ if ( ( string_char >= 'A' ) && ( string_char <= 'Z' ) )
++ string_char += 'a' - 'Z';
++ if( ( keyword_char >= 'A' ) && ( keyword_char <= 'Z' ) )
++ keyword_char += 'a' - 'Z';
++ if( string_char != keyword_char )
++ return FALSE;
++ }
++ *str_ptr = ptr;
++ return TRUE;
++}
++
++
++/*------------------------------------------------------------------------------
++ AAC_ParseDriverOptions()
++
++ For modules the usage is:
++ insmod -f aacraid.o 'aacraid_options="<option_name:argument>"'
++ *----------------------------------------------------------------------------*/
++static void AAC_ParseDriverOptions(
++ char * cmnd_line_options_str )
++/*----------------------------------------------------------------------------*/
++{
++ int message_level;
++ int reverse_scan;
++ char *cp;
++ char *endp;
++
++ cp = cmnd_line_options_str;
++
++ cmn_err(CE_DEBUG, "AAC_ParseDriverOptions: <%s>", cp);
++
++ while( *cp ) {
++ if( parse_keyword( &cp, "message_level:" ) ) {
++ message_level = simple_strtoul( cp, 0, 0 );
++ if( ( message_level < CE_TAIL ) && ( message_level >= 0 ) ) {
++ g_options.message_level = message_level;
++ cmn_err( CE_WARN, "%s: new message level = %d", g_DriverName, g_options.message_level );
++ }
++ else {
++ cmn_err( CE_WARN, "%s: invalid message level = %d", g_DriverName, message_level );
++ }
++ } else if (parse_keyword( &cp, "reverse_scan:" ) ) {
++ reverse_scan = simple_strtoul( cp, 0, 0 );
++ if (reverse_scan) {
++ g_options.reverse_scan = 1;
++ cmn_err( CE_WARN, "%s: reversing device discovery order", g_DriverName, g_options.message_level );
++ }
++ }
++ else {
++ cmn_err( CE_WARN, "%s: unknown command line option <%s>", g_DriverName, cp );
++ }
++
++ /*
++ * skip to next option, accept " ", ";", and "," as delimiters
++ */
++ while ( *cp && (*cp != ' ') && (*cp != ';') && (*cp != ','))
++ cp++;
++
++ if (*cp) /* skip over the delimiter */
++ cp++;
++ }
++
++}
++
++
++/*------------------------------------------------------------------------------
++ To use the low level SCSI driver support using the linux kernel loadable
++ module interface we should initialize the global variable driver_interface
++ (datatype Scsi_Host_Template) and then include the file scsi_module.c.
++ *----------------------------------------------------------------------------*/
++
++Scsi_Host_Template driver_template = AAC_HOST_TEMPLATE_ENTRY;
++
++#include "scsi_module.c"
++
++
++/*********************************************************************
++ AAC_ProcDirectoryInfo()
++
++ Implement /proc/scsi/<drivername>/<n>.
++ Used to export driver statistics and other infos to the world outside
++ the kernel using the proc file system. Also provides an interface to
++ feed the driver with information.
++
++ Postconditions
++ For reads
++ - if offset > 0 return 0
++ - if offset == 0 write data to proc_buffer and set the start_ptr to
++ beginning of proc_buffer, return the number of characters written.
++ For writes
++ - writes currently not supported, return 0
++************************************************************/
++int AAC_ProcDirectoryInfo(
++ char *proc_buffer, // read/write buffer
++ char **start_ptr, // start of valid data in the buffer
++ off_t offset, // offset from the beginning of the imaginary file
++ int bytes_available, // bytes available
++ int host_no, // SCSI host number
++ int write ) // direction of dataflow: TRUE for writes, FALSE for reads
++{
++ int length = 0;
++ cmn_err( CE_WARN, "AAC_ProcDirectoryInfo" );
++
++ if( ( write ) || ( offset > 0 ) )
++ return( 0 );
++
++ *start_ptr = proc_buffer;
++
++ return( sprintf(&proc_buffer[length], "%s %d\n", "Raid Controller, scsi hba number", host_no ) );
++}
++
++void aac_allocate_SyncFibs (PCI_MINIPORT_COMMON_EXTENSION *CommonExtension)
++{
++ void *BaseAddress;
++ ULONG PhysAddress;
++ int size;
++ int npages;
++ int i;
++
++ AFA_COMM_ADAPTER *Adapter;
++ Adapter = CommonExtension->Adapter;
++
++
++ // Allocate 1 fib for synch fibs
++ // Allocate 1 page.
++ BaseAddress = OsAllocMemory ( PAGE_SIZE, OS_ALLOC_MEM_SLEEP);
++ bzero(BaseAddress, PAGE_SIZE);
++ PhysAddress = virt_to_phys (BaseAddress);
++ Adapter->SyncFib = BaseAddress;
++ Adapter->SyncFibPhysicalAddress = PhysAddress;
++ cmn_err(CE_DEBUG,"aac_allocate_SyncFibs: syncFib: vaddr: 0x%x paddr: 0x%x ", BaseAddress, PhysAddress);
++
++}
+diff -burN linux-2.4.9/drivers/scsi/aacraid/osddi.c linux/drivers/scsi/aacraid/osddi.c
+--- linux-2.4.9/drivers/scsi/aacraid/osddi.c Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/osddi.c Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,508 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * osddi.c
++ *
++ * Abstract: This file contains all the proceedures which use LINUX specific Device
++ * Driver Interfaces.
++ *
++ --*/
++
++static char *ident_osddi = "aacraid_ident osddi.c 1.0.6 2000/10/09 Adaptec, Inc.";
++
++#include "osheaders.h"
++
++#include <linux/smp_lock.h>
++
++#ifdef fsid_t
++#undef fsid_t
++#endif
++#include "AacGenericTypes.h"
++#include "aac_unix_defs.h"
++#include "comstruc.h"
++#include "monkerapi.h"
++#include "protocol.h"
++#include "fsafs.h"
++
++#include "sap1common.h"
++#include "fsaport.h"
++#include "pcisup.h"
++#include "sap1.h"
++#include "nodetype.h"
++#include "comsup.h"
++#include "afacomm.h"
++#include "adapter.h"
++
++
++void AacSaPciIsr(
++ int irq,
++ void * irq_data,
++ struct pt_regs *regs);
++
++void AacRxPciIsr(
++ int irq,
++ void * irq_data,
++ struct pt_regs *regs);
++
++unsigned SaPciIsr (
++ IN PSa_ADAPTER_EXTENSION AdapterExtension );
++
++unsigned RxPciIsr (
++ IN PSa_ADAPTER_EXTENSION AdapterExtension );
++
++
++/*----------------------------------------------------------------------------*/
++VOID AfaCommInterruptHost(
++ PVOID AdapterArg,
++ ADAPTER_EVENT AdapterEvent )
++/*----------------------------------------------------------------------------*/
++{
++ PAFA_COMM_ADAPTER Adapter = ( PAFA_COMM_ADAPTER ) AdapterArg;
++ PCOMM_REGION CommRegion = Adapter->CommRegion;
++
++ switch (AdapterEvent) {
++
++ case HostNormRespQue:
++ OsSoftInterruptTrigger( CommRegion->HostNormRespQue.ConsumerRoutine );
++
++ // #REVIEW# - what do we do with this
++ // if (FsaCommData.HardInterruptModeration)
++ // DisableInterrupt( Adapter, HostNormRespQue, TRUE );
++
++ break;
++
++ case AdapNormCmdNotFull:
++ OsSoftInterruptTrigger( CommRegion->QueueNotFullDpc );
++ break;
++
++ case HostNormCmdQue:
++ OsSoftInterruptTrigger( CommRegion->HostNormCmdQue.ConsumerRoutine );
++ break;
++
++ case AdapNormRespNotFull:
++ OsSoftInterruptTrigger( CommRegion->QueueNotFullDpc );
++ break;
++
++ // #REVIEW# - what do we do with these
++ case HostHighCmdQue:
++ case HostHighRespQue:
++ case AdapHighCmdNotFull:
++ case AdapHighRespNotFull:
++ case SynchCommandComplete:
++ case AdapInternalError:
++ break;
++ }
++}
++
++
++// get the device name associated with this instance of the device
++/*----------------------------------------------------------------------------*/
++char *OsGetDeviceName(
++ void *AdapterExtension )
++/*----------------------------------------------------------------------------*/
++{
++ return( ( ( Sa_ADAPTER_EXTENSION * )AdapterExtension )->Common->
++ OsDep.scsi_host_ptr->hostt->name );
++}
++
++
++/*----------------------------------------------------------------------------*/
++int OsGetDeviceInstance(
++ void *AdapterExtension )
++/*----------------------------------------------------------------------------*/
++{
++ return( ( int )( ( Sa_ADAPTER_EXTENSION * )AdapterExtension )->Common->
++ OsDep.scsi_host_ptr->unique_id );
++}
++
++
++/*------------------------------------------------------------------------------
++ OsMapDeviceRegisters()
++
++ Postconditions:
++ Return zero on success non-zero otherwise.
++ *----------------------------------------------------------------------------*/
++int OsMapDeviceRegisters(
++ Sa_ADAPTER_EXTENSION *AdapterExtension )
++/*----------------------------------------------------------------------------*/
++{
++ PCI_MINIPORT_COMMON_EXTENSION *CommonExtension;
++
++ CommonExtension = AdapterExtension->Common;
++
++ if( AdapterExtension->Device = ( Sa_DEVICE_REGISTERS * )
++ ioremap( ( unsigned long )CommonExtension->OsDep.scsi_host_ptr->base, 8192 ) )
++ {
++ cmn_err( CE_WARN, "Device mapped to virtual address 0x%x", AdapterExtension->Device );
++ return( 0 );
++ }
++ else
++ {
++ cmn_err( CE_WARN, "OsMapDeviceRegisters: ioremap() failed" );
++ return( 1 );
++ }
++}
++
++
++/*------------------------------------------------------------------------------
++ OsUnMapDeviceRegisters()
++
++ Postconditions:
++ *----------------------------------------------------------------------------*/
++void OsUnMapDeviceRegisters(
++ Sa_ADAPTER_EXTENSION *AdapterExtension )
++/*----------------------------------------------------------------------------*/
++{
++ iounmap( ( void * )AdapterExtension->Device );
++}
++
++
++/*----------------------------------------------------------------------------*/
++int OsAttachInterrupt(
++ Sa_ADAPTER_EXTENSION *AdapterExtension ,
++ int WhichIsr )
++/*----------------------------------------------------------------------------*/
++{
++ PCI_MINIPORT_COMMON_EXTENSION *CommonExtension;
++ void *irq_data;
++ void (*Isr)();
++
++ CommonExtension = AdapterExtension->Common;
++ irq_data = ( void * )AdapterExtension;
++
++ switch (WhichIsr) {
++ case SaISR:
++ Isr = AacSaPciIsr;
++ break;
++ case RxISR:
++ Isr = AacRxPciIsr;
++ break;
++ default:
++ cmn_err(CE_WARN, "OsAttachInterrupt: invalid ISR case: 0x%x", WhichIsr);
++ return( FAILURE );
++ break;
++ }
++
++
++ if ( OsRegisterInterrupt (
++ CommonExtension->OsDep.scsi_host_ptr->irq, // interrupt number
++ Isr, // handler function
++ irq_data )
++ )
++ {
++ cmn_err( CE_WARN, "OsAttachInterrupt: Failed for IRQ: 0x%x",
++ CommonExtension->OsDep.scsi_host_ptr->irq );
++ return( FAILURE );
++ }
++
++ return ( 0 );
++}
++
++
++/*----------------------------------------------------------------------------*/
++void AacSaPciIsr(
++ int irq,
++ void * irq_data,
++ struct pt_regs *regs)
++/*----------------------------------------------------------------------------*/
++{
++ // call the actual interrupt handler
++ SaPciIsr( ( Sa_ADAPTER_EXTENSION * )irq_data );
++}
++
++/*----------------------------------------------------------------------------*/
++void AacRxPciIsr(
++ int irq,
++ void * irq_data,
++ struct pt_regs *regs)
++/*----------------------------------------------------------------------------*/
++{
++ // call the actual interrupt handler
++ RxPciIsr( ( Sa_ADAPTER_EXTENSION * )irq_data );
++}
++
++
++/*----------------------------------------------------------------------------*/
++void OsDetachInterrupt(
++ Sa_ADAPTER_EXTENSION *AdapterExtension )
++/*----------------------------------------------------------------------------*/
++{
++ PCI_MINIPORT_COMMON_EXTENSION *CommonExtension;
++ void *irq_data;
++
++ CommonExtension = AdapterExtension->Common;
++ irq_data = ( void * )AdapterExtension;
++
++ OsUnregisterInterrupt (
++ CommonExtension->OsDep.scsi_host_ptr->irq, // interrupt number
++ irq_data );
++}
++
++
++/*----------------------------------------------------------------------------*/
++int OsAttachDMA(
++ Sa_ADAPTER_EXTENSION *AdapterExtension )
++/*----------------------------------------------------------------------------*/
++{
++ return( 0 );
++}
++
++/*----------------------------------------------------------------------------*/
++int OsAttachHBA(
++ Sa_ADAPTER_EXTENSION *AdapterExtension )
++/*----------------------------------------------------------------------------*/
++{
++ return( 0 );
++}
++
++/*----------------------------------------------------------------------------*/
++void OsDetachDevice(
++ Sa_ADAPTER_EXTENSION *AdapterExtension )
++/*----------------------------------------------------------------------------*/
++{
++ OsUnMapDeviceRegisters( AdapterExtension );
++ return( 0 );
++}
++
++/*----------------------------------------------------------------------------*/
++ULONG *OsAllocCommPhysMem(
++ Sa_ADAPTER_EXTENSION *AdapterExtension,
++ ULONG size,
++ ULONG **virt_addr_pptr,
++ ULONG *phys_addr_ptr )
++/*----------------------------------------------------------------------------*/
++{
++ if( ( *virt_addr_pptr = ( ULONG * )OsAllocMemory( size, GFP_KERNEL ) ) )
++ {
++ *phys_addr_ptr = OsVirtToPhys( ( volatile void * )*virt_addr_pptr );
++ if( !*phys_addr_ptr )
++ {
++ cmn_err( CE_WARN, "OsAllocCommPhysMem: OsVirtToPhys failed" );
++ }
++
++ return( *virt_addr_pptr );
++ }
++ else
++ return( NULL );
++}
++
++OsAifKernelThread(
++ Sa_ADAPTER_EXTENSION *AdapterExtension )
++{
++
++ struct fs_struct *fs;
++ int i;
++ struct task_struct *tsk;
++
++ tsk = current;
++
++
++ /*
++ * set up the name that will appear in 'ps'
++ * stored in task_struct.comm[16].
++ */
++
++ sprintf(tsk->comm, "AIFd");
++
++
++ // use_init_fs_context(); only exists in 2.2.13 onward.
++
++ lock_kernel();
++
++ /*
++ * we were started as a result of loading the module.
++ * free all of user space pages
++ */
++
++ exit_mm(tsk);
++
++ exit_files(tsk);
++
++ exit_fs(tsk);
++
++ fs = init_task.fs;
++ tsk->fs = fs;
++
++ tsk->session = 1;
++ tsk->pgrp = 1;
++
++ if (fs)
++ atomic_inc(&fs->count);
++
++ unlock_kernel();
++
++
++
++
++ NormCommandThread(AdapterExtension);
++ /* NOT REACHED */
++}
++
++/*----------------------------------------------------------------------------*/
++void OsStartKernelThreads(
++ Sa_ADAPTER_EXTENSION *AdapterExtension )
++/*----------------------------------------------------------------------------*/
++{
++ PCI_MINIPORT_COMMON_EXTENSION *CommonExtension;
++ AFA_COMM_ADAPTER *Adapter;
++ extern void NormCommandThread(void *Adapter);
++
++ CommonExtension = AdapterExtension->Common;
++ Adapter = (AFA_COMM_ADAPTER *)CommonExtension->Adapter;
++
++ //
++ // Start thread which will handle interrupts for this adapter
++ //
++ //kthread_spawn(FsaCommIntrHandler, AdapterExtension, "fsaintr",0);
++
++ //
++ // Start thread which will handle AdapterInititatedFibs from this adapter
++ //
++ CommonExtension->OsDep.thread_pid =
++ kernel_thread( ( int ( * )( void * ) )OsAifKernelThread, Adapter, 0 );
++// kernel_thread( ( int ( * )( void * ) )NormCommandThread, Adapter, 0 );
++}
++
++/*----------------------------------------------------------------------------*/
++BOOLEAN AfaPortAllocateAndMapFibSpace(
++ PVOID Arg1,
++ IN PMAPFIB_CONTEXT MapFibContext )
++/*----------------------------------------------------------------------------*/
++{
++ PVOID BaseAddress;
++ ULONG PhysAddress;
++
++ if( !( BaseAddress = (ULONG *)OsAllocMemory( MapFibContext->Size, GFP_KERNEL ) ) )
++ {
++ cmn_err( CE_WARN, "AfaPortAllocateAndMapFibSpace: OsAllocMemory failed" );
++ return( FALSE );
++ }
++
++ PhysAddress = OsVirtToPhys( BaseAddress );
++
++ MapFibContext->FibVirtualAddress = BaseAddress;
++ MapFibContext->FibPhysicalAddress = (PVOID) PhysAddress;
++
++ return (TRUE);
++}
++
++/*----------------------------------------------------------------------------*/
++BOOLEAN AfaPortUnmapAndFreeFibSpace(
++ PVOID Arg1,
++ IN PMAPFIB_CONTEXT MapFibContext )
++/*----------------------------------------------------------------------------*/
++{
++ PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
++
++ OsFreeMemory( MapFibContext->FibVirtualAddress, 0 );
++
++ return (TRUE);
++}
++
++/*----------------------------------------------------------------------------*/
++BOOLEAN AfaPortFreeAdapterCommArea(
++ IN PVOID Arg1 )
++/*----------------------------------------------------------------------------*/
++{
++ PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
++
++ OsFreeMemory( CommonExtension->CommAddress, 0 );
++
++ return (TRUE);
++}
++
++
++/* ================================================================================ */
++/*
++ * Not sure if the functions below here ever get called in the current code
++ * These probably should be a different file.
++ */
++/*
++ddi_dma_attr_t AfaPortDmaAttributes = {
++ //rpbfix : we may want something different for I/O
++ DMA_ATTR_V0,
++ 0,
++ 0xffffffff,
++ 0x0000ffff,
++ 1,
++ 1,
++ 1,
++ 0x0000ffff,
++ 0x0000ffff,
++ 17,
++ 512,
++ 0
++};
++*/
++
++AAC_STATUS
++AfaPortBuildSgMap(
++ PVOID Arg1,
++ IN PSGMAP_CONTEXT SgMapContext
++ )
++
++/*++
++
++Routine Description:
++
++ This routine build a scatter gather map using the information
++ in the SgMapContext.
++
++Arguments:
++
++ AdapterExtension - Pointer to adapter extension structure.
++ SgMapContext - Pointer to the SgMapContext for the request.
++
++
++Return Value:
++
++ AAC_STATUS
++--*/
++{
++ printk( KERN_ALERT "AfaPortBuildSgMap: unimplemented function called" );
++ return (STATUS_UNSUCCESSFUL);
++}
++
++VOID
++AfaPortFreeDmaResources(
++ PVOID Arg1,
++ IN PSGMAP_CONTEXT SgMapContext
++ )
++
++/*++
++
++Routine Description:
++
++ Given a pointer to the IRP context will free all reserved DMA resources allocated for
++ the completed IO operation.
++
++Arguments:
++
++ Fib - Pointer to the Fib the caller wishes to have transfered over to the adapter.
++ Context - Pointer to the Irp Context we use to store the dma mapping information
++ we need to do and complete the IO.
++
++Return Value:
++
++ Nothing
++
++--*/
++{
++}
+diff -burN linux-2.4.9/drivers/scsi/aacraid/osfuncs.c linux/drivers/scsi/aacraid/osfuncs.c
+--- linux-2.4.9/drivers/scsi/aacraid/osfuncs.c Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/osfuncs.c Thu Aug 16 18:15:01 2001
+@@ -0,0 +1,594 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * osfuncs.c
++ *
++ * Abstract: Holds all of the O/S specific interface functions.
++ *
++ --*/
++
++static char *ident_osfuncs = "aacraid_ident osfuncs.c 1.0.6 2000/10/09 Adaptec, Inc.";
++
++#include "osheaders.h"
++
++//static LKINFO_DECL(fsa_locks, "fsa_locks",0);
++
++extern aac_options_t g_options;
++
++OS_SOFTINTR g_idle_task = { 0, 0, 0, 0 };
++wait_queue_t * g_wait_queue_ptr = NULL;
++wait_queue_t g_wait;
++
++void OsTimeoutHandler(
++ struct semaphore * sem );
++
++int * OsIdleTask( void * data );
++
++//-----------------------------------------------------------------------------
++// Memory Allocation functions
++
++/*----------------------------------------------------------------------------*/
++void * OsAllocMemory(
++ OS_SIZE_T Size,
++ unsigned int Flags )
++/*----------------------------------------------------------------------------*/
++{
++ void *mem_ptr;
++
++ if( !( mem_ptr = kmalloc( Size, GFP_KERNEL ) ) )
++ cmn_err( CE_WARN, "OsAllocMemory: FAILED\n" );
++ return( mem_ptr );
++}
++
++
++/*----------------------------------------------------------------------------*/
++void OsFreeMemory(
++ void * Buffer,
++ OS_SIZE_T Size )
++/*----------------------------------------------------------------------------*/
++{
++ kfree( Buffer );
++}
++
++
++/*----------------------------------------------------------------------------*/
++int OsRegisterInterrupt(
++ unsigned int irq, // interrupt number
++ void ( *handler )( int, void*, struct pt_regs * ), // handler function
++ void *irq_data ) // argument to handler function
++/*----------------------------------------------------------------------------*/
++{
++ return( request_irq (irq, handler, SA_INTERRUPT | SA_SHIRQ, "aacraid", irq_data ) );
++}
++
++
++/*----------------------------------------------------------------------------*/
++void OsUnregisterInterrupt(
++ unsigned int irq, // interrupt number
++ void *irq_data)
++/*----------------------------------------------------------------------------*/
++{
++ free_irq (
++ irq, // interrupt number
++ irq_data );
++}
++
++
++/*----------------------------------------------------------------------------*/
++unsigned long OsVirtToPhys(
++ void * virtual_address )
++/*----------------------------------------------------------------------------*/
++{
++ return( virt_to_phys( virtual_address ) );
++}
++
++
++//-----------------------------------------------------------------------------
++// MUTEX functions
++
++/*----------------------------------------------------------------------------*/
++OS_STATUS OsMutexInit(
++ OS_MUTEX *Mutex,
++ OS_SPINLOCK_COOKIE Cookie )
++/*----------------------------------------------------------------------------*/
++{
++ Mutex->lock_var = 0;
++ // bzero (&Mutex->wq, sizeof (Mutex->wq));
++ init_waitqueue_head (&Mutex->wq);
++ return ( 0 );
++}
++
++
++/*----------------------------------------------------------------------------*/
++void OsMutexDestroy(
++ OS_MUTEX *Mutex )
++/*----------------------------------------------------------------------------*/
++{
++}
++
++
++/*----------------------------------------------------------------------------*/
++void OsMutexAcquire(
++ OS_MUTEX *Mutex )
++/*----------------------------------------------------------------------------*/
++{
++ // wait_queue_t wait = { current, NULL };
++ unsigned long time_stamp;
++
++ DECLARE_WAITQUEUE (wait, current);
++
++ time_stamp = jiffies;
++
++ if( test_and_set_bit( 0, &( Mutex->lock_var ) ) != 0 )
++ {
++ if( in_interrupt() )
++ panic( "OsMutexAcquire going to sleep at interrupt time\n" );
++ current->state = TASK_INTERRUPTIBLE;
++ add_wait_queue( &( Mutex->wq ), &wait );
++ while( test_and_set_bit( 0, &( Mutex->lock_var ) ) != 0 )
++ schedule();
++ remove_wait_queue( &( Mutex->wq ), &wait );
++ }
++
++ if( ( jiffies - 1 ) > time_stamp )
++ cmn_err( CE_WARN, "Mutex %ld locked out for %ld ticks",
++ Mutex, jiffies - time_stamp );
++}
++
++
++/*----------------------------------------------------------------------------*/
++void OsMutexRelease(
++ OS_MUTEX *Mutex )
++/*----------------------------------------------------------------------------*/
++{
++ if( test_and_clear_bit( 0, &( Mutex->lock_var ) ) == 0 )
++ cmn_err( CE_WARN, "OsMutexRelease: mutex not locked" );
++ wake_up_interruptible( &( Mutex->wq ) );
++}
++
++// see man hierarchy(D5)
++#define FSA_LOCK 1
++
++//-----------------------------------------------------------------------------
++// Spinlock functions
++
++/*----------------------------------------------------------------------------*/
++OS_SPINLOCK * OsSpinLockAlloc( void )
++/*----------------------------------------------------------------------------*/
++{
++ OS_SPINLOCK *SpinLock;
++ int i;
++
++
++ SpinLock = ( OS_SPINLOCK * )kmalloc( sizeof( OS_SPINLOCK ), GFP_KERNEL );
++
++ if (SpinLock == NULL)
++ cmn_err (CE_WARN, "WARNING: OsSpinLockAlloc Failed!!!");
++
++ SpinLock->spin_lock = SPIN_LOCK_UNLOCKED;
++ for( i = 0; i < NR_CPUS; i++ )
++ SpinLock->cpu_lock_count[ i ] = 0;
++ return( SpinLock );
++}
++
++
++/*----------------------------------------------------------------------------*/
++OS_STATUS OsSpinLockInit(
++ OS_SPINLOCK *SpinLock,
++ OS_SPINLOCK_COOKIE Cookie )
++/*----------------------------------------------------------------------------*/
++{
++ return( 0 );
++}
++
++
++/*----------------------------------------------------------------------------*/
++void OsSpinLockDestroy(
++ OS_SPINLOCK *SpinLock )
++/*----------------------------------------------------------------------------*/
++{
++ kfree( SpinLock );
++ SpinLock = NULL;
++}
++
++
++/*----------------------------------------------------------------------------*/
++void OsSpinLockAcquire(
++ OS_SPINLOCK *SpinLock )
++/*----------------------------------------------------------------------------*/
++{
++ unsigned cpu_id;
++
++ if( SpinLock )
++ {
++ cpu_id = smp_processor_id();
++ if( SpinLock->cpu_lock_count[ cpu_id ] ){
++ cmn_err (CE_PANIC, "CPU %d trying to acquire lock again: lock count = %d\n",
++ cpu_id, SpinLock->cpu_lock_count[ cpu_id ]);
++ }
++
++ spin_lock_irqsave( &( SpinLock->spin_lock ), SpinLock->cpu_flags[ cpu_id ] );
++ SpinLock->cpu_lock_count[ cpu_id ]++;
++
++ } else {
++ cmn_err( CE_WARN, "OsSpinLockAcquire: lock does not exist" );
++ }
++}
++
++
++/*----------------------------------------------------------------------------*/
++void OsSpinLockRelease(
++ OS_SPINLOCK *SpinLock )
++/*----------------------------------------------------------------------------*/
++{
++ unsigned cpu_id;
++
++ if( SpinLock )
++ {
++ cpu_id = smp_processor_id();
++ SpinLock->cpu_lock_count[ cpu_id ]--;
++ spin_unlock_irqrestore( &( SpinLock->spin_lock ), SpinLock->cpu_flags[ cpu_id ] );
++ }
++ else
++ cmn_err( CE_WARN, "OsSpinLockRelease: lock does not exist" );
++}
++
++
++/*----------------------------------------------------------------------------*/
++inline int OsSpinLockOwned(
++ OS_SPINLOCK *SpinLock )
++/*----------------------------------------------------------------------------*/
++{
++ return spin_is_locked (&SpinLock->spin_lock);
++}
++
++
++//-----------------------------------------------------------------------------
++// CvLock functions
++
++/*----------------------------------------------------------------------------*/
++OS_CVLOCK *OsCvLockAlloc( void )
++{
++ OS_CVLOCK *cv_lock;
++
++
++#ifdef CVLOCK_USE_SPINLOCK
++ cv_lock = OsSpinLockAlloc();
++#else
++ cv_lock = ( OS_CVLOCK * )kmalloc( sizeof( OS_CVLOCK ), GFP_KERNEL );
++ cv_lock->wq = NULL;
++ cv_lock->lock_var = 0;
++#endif
++
++ return( cv_lock );
++}
++
++
++/*----------------------------------------------------------------------------*/
++OS_STATUS OsCvLockInit(
++ OS_CVLOCK *cv_lock,
++ OS_SPINLOCK_COOKIE Cookie )
++/*----------------------------------------------------------------------------*/
++{
++ return ( 0 );
++}
++
++
++/*----------------------------------------------------------------------------*/
++void OsCvLockDestroy(
++ OS_CVLOCK *cv_lock )
++/*----------------------------------------------------------------------------*/
++{
++ if( cv_lock )
++ kfree( cv_lock );
++ cv_lock = NULL;
++}
++
++
++/*----------------------------------------------------------------------------*/
++void OsCvLockAcquire (OS_CVLOCK *cv_lock)
++{
++#ifdef CVLOCK_USE_SPINLOCK
++ OsSpinLockAcquire( cv_lock );
++#else
++ OsMutexAcquire( cv_lock );
++#endif
++}
++
++
++/*----------------------------------------------------------------------------*/
++void OsCvLockRelease(
++ OS_CVLOCK *cv_lock )
++/*----------------------------------------------------------------------------*/
++{
++#ifdef CVLOCK_USE_SPINLOCK
++ OsSpinLockRelease( cv_lock );
++#else
++ OsMutexRelease( cv_lock );
++#endif
++}
++
++
++/*----------------------------------------------------------------------------*/
++int OsCvLockOwned(
++ OS_CVLOCK *cv_lock )
++/*----------------------------------------------------------------------------*/
++{
++ return( 1 );
++}
++
++
++//-----------------------------------------------------------------------------
++// Conditional variable functions
++
++/*----------------------------------------------------------------------------*/
++void OsCv_init (
++ OS_CV_T *cv_ptr )
++/*----------------------------------------------------------------------------*/
++{
++ cv_ptr->lock_var = 1;
++ init_waitqueue_head (&cv_ptr->wq);
++}
++
++
++/*----------------------------------------------------------------------------*/
++void OsCv_destroy(
++ OS_CV_T *cv_ptr )
++/*----------------------------------------------------------------------------*/
++{
++}
++
++
++/*______________________________________________________________________________
++ -
++ -
++ -----------------------------------------------------------------------------*/
++OsCv_wait (OS_CV_T *cv_ptr, OS_CVLOCK *cv_lock_ptr)
++{
++ unsigned long flags;
++
++ DECLARE_WAITQUEUE (wait, current);
++
++ if( in_interrupt() )
++ panic( "OsCv_wait going to sleep at interrupt time\n" );
++
++ cv_ptr->type = TASK_UNINTERRUPTIBLE;
++ current->state = TASK_UNINTERRUPTIBLE;
++
++ add_wait_queue( &cv_ptr->wq, &wait );
++
++ OsCvLockRelease( cv_lock_ptr );
++ schedule();
++
++ while( test_and_set_bit( 0, &( cv_ptr->lock_var ) ) != 0 )
++ {
++ if( in_interrupt() )
++ panic( "OsCv_wait going to sleep at interrupt time\n" );
++ schedule();
++ }
++
++ remove_wait_queue( &( cv_ptr->wq ), &wait );
++
++ OsCvLockAcquire( cv_lock_ptr );
++}
++
++
++/*----------------------------------------------------------------------------*/
++int OsCv_wait_sig(
++ OS_CV_T *cv_ptr,
++ OS_CVLOCK *cv_lock_ptr )
++/*----------------------------------------------------------------------------*/
++{
++ unsigned long flags;
++ int signal_state = 1;
++
++ DECLARE_WAITQUEUE (wait, current);
++
++ if( in_interrupt() )
++ panic( "OsCv_wait_sig going to sleep at interrupt time\n" );
++
++ cv_ptr->type = TASK_INTERRUPTIBLE;
++ current->state = TASK_INTERRUPTIBLE;
++
++ add_wait_queue( &( cv_ptr->wq ), &wait );
++
++ OsCvLockRelease( cv_lock_ptr );
++ schedule();
++
++ while( ( test_and_set_bit( 0, &( cv_ptr->lock_var ) ) != 0 ) &&
++ ( !signal_pending( current ) ) )
++ {
++ if( in_interrupt() )
++ panic( "OsCv_wait_sig going to sleep at interrupt time\n" );
++ schedule();
++ }
++
++ if( signal_pending( current ) )
++ signal_state = 0;
++
++ remove_wait_queue( &( cv_ptr->wq ), &wait );
++
++ OsCvLockAcquire( cv_lock_ptr );
++ return( signal_state );
++}
++
++
++/*----------------------------------------------------------------------------*/
++void OsCv_signal(
++ OS_CV_T *cv_ptr )
++/*----------------------------------------------------------------------------*/
++{
++
++ clear_bit( 0, &( cv_ptr->lock_var ) );
++ if( cv_ptr->type == TASK_INTERRUPTIBLE )
++ wake_up_interruptible( &( cv_ptr->wq ) );
++ else{
++ wake_up( &( cv_ptr->wq ) );
++ }
++}
++
++
++// return time in seconds
++/*----------------------------------------------------------------------------*/
++unsigned long OsGetSeconds( void )
++/*----------------------------------------------------------------------------*/
++{
++ return( jiffies/HZ );
++}
++
++
++//-----------------------------------------------------------------------------
++// Deferred procedure call functions
++
++// create a soft interrupt object
++/*----------------------------------------------------------------------------*/
++int OsSoftInterruptAdd(
++ OS_SOFTINTR **ptr,
++ void * handler,
++ void * data )
++/*----------------------------------------------------------------------------*/
++{
++ OS_SOFTINTR *tmp_ptr;
++
++ if( !( tmp_ptr = ( OS_SOFTINTR * )kmalloc( sizeof( OS_SOFTINTR ), GFP_KERNEL ) ) )
++ return( -1 );
++ tmp_ptr->routine = handler;
++ tmp_ptr->data = data;
++ tmp_ptr->sync = 0;
++ INIT_LIST_HEAD(&tmp_ptr->list);
++
++ *ptr = tmp_ptr;
++
++ return( 0 );
++}
++
++/*
++ Use kernel_thread( ( int ( * )( void * ) )OsIdleTask, NULL, 0 ); to start
++*/
++/*----------------------------------------------------------------------------*/
++int * OsIdleTask( void * data )
++/*----------------------------------------------------------------------------*/
++{
++ DECLARE_WAITQUEUE (wait, current);
++
++ while( 1 )
++ {
++ current->state = TASK_INTERRUPTIBLE;
++ add_wait_queue( &g_wait_queue_ptr, &wait );
++ schedule();
++ remove_wait_queue( &g_wait_queue_ptr, &wait );
++ wait.task = current;
++ wait.task_list.next = NULL;
++ }
++ return( NULL );
++}
++
++
++// dispatch a soft interrupt
++/*----------------------------------------------------------------------------*/
++void OsSoftInterruptTrigger(
++ OS_SOFTINTR *soft_intr_ptr )
++/*----------------------------------------------------------------------------*/
++{
++ // call the completion routine directly
++ soft_intr_ptr->routine( soft_intr_ptr->data );
++}
++
++
++// delete a soft interrupt object
++/*----------------------------------------------------------------------------*/
++void OsSoftInterruptRemove(
++ OS_SOFTINTR *arg )
++/*----------------------------------------------------------------------------*/
++{
++ if( arg )
++ kfree( arg );
++ arg = NULL;
++}
++
++
++/*----------------------------------------------------------------------------*/
++void OsSleep(
++ unsigned time ) // in seconds
++/*----------------------------------------------------------------------------*/
++{
++ struct semaphore sem;
++ struct timer_list timer_var;
++
++ init_MUTEX_LOCKED (&sem);
++
++ // if( in_interrupt() )
++ // panic( "OsSleep going to sleep at interrupt time\n" );
++
++ init_timer( &timer_var );
++ timer_var.function = ( void ( * )( unsigned long ) )OsTimeoutHandler;
++ timer_var.data = ( unsigned long )&sem;
++ timer_var.expires = jiffies + time * HZ;
++
++ add_timer( &timer_var );
++ down( &sem );
++
++ del_timer( &timer_var );
++}
++
++
++/*----------------------------------------------------------------------------*/
++void OsTimeoutHandler(
++ struct semaphore * sem )
++/*----------------------------------------------------------------------------*/
++{
++ if( sem != NULL )
++ up( sem );
++}
++
++
++/*----------------------------------------------------------------------------*/
++void printk_err(
++ int flag,
++ char *fmt,
++ ...)
++/*----------------------------------------------------------------------------*/
++{
++ char buf[256];
++ va_list ap;
++
++ va_start(ap, fmt);
++ (void) vsprintf(buf, fmt, ap);
++ va_end(ap);
++
++ if( flag <= g_options.message_level )
++ printk(KERN_ALERT "%s\n", buf);
++}
++
++/* void aac_show_tasks (struct list_head *our_tasks){ */
++
++/* cmn_err (CE_DEBUG, "Entering aac_show_tasks"); */
++
++/* if (our_tasks->next == NULL || our_tasks->next == 0) */
++/* cmn_err (CE_DEBUG, "list_head->next is NULL or 0"); */
++/* else */
++/* cmn_err (CE_DEBUG, "list_head->next: 0x%x", our_tasks->next); */
++
++/* if (our_tasks->prev == NULL || our_tasks->prev == 0) */
++/* cmn_err (CE_DEBUG, "list_head->prev is NULL or 0"); */
++/* else */
++/* cmn_err (CE_DEBUG, "list_head->prev: 0x%x", our_tasks->prev); */
++
++/* } */
+diff -burN linux-2.4.9/drivers/scsi/aacraid/ossup.c linux/drivers/scsi/aacraid/ossup.c
+--- linux-2.4.9/drivers/scsi/aacraid/ossup.c Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/ossup.c Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,199 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * ossup.c
++ *
++ *
++ *
++ --*/
++
++static char *ident_ossup = "aacraid_ident ossup.c 1.0.6 2000/10/09 Adaptec, Inc.";
++
++#include "osheaders.h"
++
++#include "aac_unix_defs.h"
++
++
++AAC_STATUS
++ExInitializeZone(
++ IN PZONE_HEADER Zone,
++ IN ULONG BlockSize,
++ IN PVOID InitialSegment,
++ IN ULONG InitialSegmentSize
++ )
++
++/*++
++
++Routine Description:
++
++ This function initializes a zone header. Once successfully
++ initialized, blocks can be allocated and freed from the zone, and
++ the zone can be extended.
++
++Arguments:
++
++ Zone - Supplies the address of a zone header to be initialized.
++
++ BlockSize - Supplies the block size of the allocatable unit within
++ the zone. The size must be larger that the size of the
++ initial segment, and must be 64-bit aligned.
++
++ InitialSegment - Supplies the address of a segment of storage. The
++ first ZONE_SEGMENT_HEADER-sized portion of the segment
++ is used by the zone allocator. The remainder of
++ the segment is carved up into fixed size
++ (BlockSize) blocks and is made available for
++ allocation and deallocation from the zone. The
++ address of the segment must be aligned on a 64-bit
++ boundary.
++
++ InitialSegmentSize - Supplies the size in bytes of the InitialSegment.
++
++Return Value:
++
++ STATUS_UNSUCCESSFUL - BlockSize or InitialSegment was not aligned on
++ 64-bit boundaries, or BlockSize was larger than
++ the initial segment size.
++
++ STATUS_SUCCESS - The zone was successfully initialized.
++
++--*/
++
++{
++ ULONG i;
++ PCHAR p;
++
++
++ Zone->BlockSize = BlockSize;
++
++ Zone->SegmentList.Next = &((PZONE_SEGMENT_HEADER) InitialSegment)->SegmentList;
++ ((PZONE_SEGMENT_HEADER) InitialSegment)->SegmentList.Next = NULL;
++ ((PZONE_SEGMENT_HEADER) InitialSegment)->Reserved = NULL;
++
++ Zone->FreeList.Next = NULL;
++
++ p = (PCHAR)InitialSegment + sizeof(ZONE_SEGMENT_HEADER);
++
++ for (i = sizeof(ZONE_SEGMENT_HEADER);
++ i <= InitialSegmentSize - BlockSize;
++ i += BlockSize
++ ) {
++ ((PSINGLE_LIST_ENTRY)p)->Next = Zone->FreeList.Next;
++ Zone->FreeList.Next = (PSINGLE_LIST_ENTRY)p;
++ p += BlockSize;
++ }
++ Zone->TotalSegmentSize = i;
++
++#if 0
++ DbgPrint( "EX: ExInitializeZone( %lx, %lx, %lu, %lu, %lx )\n",
++ Zone, InitialSegment, InitialSegmentSize,
++ BlockSize, p
++ );
++#endif
++
++ return STATUS_SUCCESS;
++}
++
++AAC_STATUS
++ExExtendZone(
++ IN PZONE_HEADER Zone,
++ IN PVOID Segment,
++ IN ULONG SegmentSize
++ )
++
++/*++
++
++Routine Description:
++
++ This function extends a zone by adding another segment's worth of
++ blocks to the zone.
++
++Arguments:
++
++ Zone - Supplies the address of a zone header to be extended.
++
++ Segment - Supplies the address of a segment of storage. The first
++ ZONE_SEGMENT_HEADER-sized portion of the segment is used by the
++ zone allocator. The remainder of the segment is carved up
++ into fixed-size (BlockSize) blocks and is added to the
++ zone. The address of the segment must be aligned on a 64-
++ bit boundary.
++
++ SegmentSize - Supplies the size in bytes of Segment.
++
++Return Value:
++
++ STATUS_UNSUCCESSFUL - BlockSize or Segment was not aligned on
++ 64-bit boundaries, or BlockSize was larger than
++ the segment size.
++
++ STATUS_SUCCESS - The zone was successfully extended.
++
++--*/
++
++{
++ ULONG i;
++ PCHAR p;
++
++
++ ((PZONE_SEGMENT_HEADER) Segment)->SegmentList.Next = Zone->SegmentList.Next;
++ Zone->SegmentList.Next = &((PZONE_SEGMENT_HEADER) Segment)->SegmentList;
++
++ p = (PCHAR)Segment + sizeof(ZONE_SEGMENT_HEADER);
++
++ for (i = sizeof(ZONE_SEGMENT_HEADER);
++ i <= SegmentSize - Zone->BlockSize;
++ i += Zone->BlockSize
++ ) {
++
++ ((PSINGLE_LIST_ENTRY)p)->Next = Zone->FreeList.Next;
++ Zone->FreeList.Next = (PSINGLE_LIST_ENTRY)p;
++ p += Zone->BlockSize;
++ }
++ Zone->TotalSegmentSize += i;
++
++#if 0
++ DbgPrint( "EX: ExExtendZone( %lx, %lx, %lu, %lu, %lx )\n",
++ Zone, Segment, SegmentSize, Zone->BlockSize, p
++ );
++#endif
++
++ return STATUS_SUCCESS;
++}
++
++DbgPrint()
++{
++}
++
++/* Function: InqStrCopy()
++ *
++ * Arguments: [2] pointer to char
++ *
++ * Purpose: Copy a String from one location to another
++ * without copying \0
++ */
++void
++InqStrCopy(char *a, char *b)
++{
++
++ while(*a != (char)0)
++ *b++ = *a++;
++}
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/port.c linux/drivers/scsi/aacraid/port.c
+--- linux-2.4.9/drivers/scsi/aacraid/port.c Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/port.c Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,287 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * port.c
++ *
++ * Abstract: All support routines for FSA communication which are miniport specific.
++ *
++ --*/
++
++static char *ident_port = "aacraid_ident port.c 1.0.7 2000/10/11 Adaptec, Inc.";
++
++#include "osheaders.h"
++
++
++#include "AacGenericTypes.h"
++
++#include "aac_unix_defs.h"
++
++#include "fsatypes.h"
++#include "comstruc.h"
++#include "protocol.h"
++
++#include "fsaport.h"
++#include "fsaioctl.h"
++
++#include "pcisup.h"
++#include "port.h"
++
++int AfaPortPrinting = 1;
++
++extern AAC_STATUS AfaPort_Err_Adapter_Printf;
++extern AAC_STATUS AfaPort_Warn_Adapter_Printf;
++extern AAC_STATUS AfaPort_Info_Adapter_Printf;
++extern AAC_STATUS AfaPort_Err_FastAfa_Load_Driver;
++
++
++
++VOID
++AfaPortLogError(
++ IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension,
++ IN AAC_STATUS ErrorCode,
++ IN PUCHAR StringBuffer,
++ IN ULONG StringLength
++ )
++/*++
++
++Routine Description:
++
++ Does all of the work to log an error log entry
++Arguments:
++
++ CommonExtension - Pointer to the adapter that caused the error.
++
++ ErrorCode - Which error is being logged.
++
++ StringBuffer - Pointer to optional String for error log entry.
++
++ StringLength - Length of StringBuffer.
++
++Return Value:
++
++ Nothing
++
++--*/
++
++{
++
++}
++
++BOOLEAN
++AfaPortGetNextAdapterNumber(
++ IN PDRIVER_OBJECT DriverObject,
++ OUT PDEVICE_OBJECT *FsaDeviceObject,
++ OUT PFILE_OBJECT *FileObject,
++ OUT PULONG AdapterNumber
++ )
++{
++}
++BOOLEAN
++AfaPortAllocateAdapterCommArea(
++ IN PVOID Arg1,
++ IN OUT PVOID *CommHeaderAddress,
++ IN ULONG CommAreaSize,
++ IN ULONG CommAreaAlignment
++ )
++{
++ PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
++ PVOID BaseAddress;
++ PHYSICAL_ADDRESS PhysicalBaseAddress;
++ ULONG TotalSize, BytesToAlign;
++ size_t RealLength;
++ uint_t Count;
++// ULONG SizeOfFastIoComm = sizeof(FASTIO_STRUCT);
++// ULONG AdapterFibsSize = PAGE_SIZE;
++ ULONG AdapterFibsSize = 4096;
++ ULONG PrintfBufferSize = 256;
++ PADAPTER_INIT_STRUCT InitStruct;
++ extern int MiniPortRevision;
++ ULONG PhysAddress;
++
++// TotalSize = AdapterFibsSize + sizeof(ADAPTER_INIT_STRUCT) + CommAreaSize + CommAreaAlignment +
++// SizeOfFastIoComm + PrintfBufferSize;
++ TotalSize = AdapterFibsSize + sizeof(ADAPTER_INIT_STRUCT) + CommAreaSize + CommAreaAlignment +
++ PrintfBufferSize;
++
++
++ OsAllocCommPhysMem(CommonExtension->MiniPort, TotalSize, &BaseAddress, &PhysAddress);
++
++ CommonExtension->CommAddress = BaseAddress;
++ CommonExtension->CommPhysAddr = PhysAddress;
++ CommonExtension->CommSize = TotalSize;
++
++ PhysicalBaseAddress.HighPart = 0;
++ PhysicalBaseAddress.LowPart = PhysAddress;
++
++ CommonExtension->InitStruct = (PADAPTER_INIT_STRUCT)((PUCHAR)(BaseAddress) + AdapterFibsSize);
++ CommonExtension->PhysicalInitStruct = (PADAPTER_INIT_STRUCT)((PUCHAR)(PhysicalBaseAddress.LowPart) + AdapterFibsSize);
++
++ InitStruct = CommonExtension->InitStruct;
++
++ InitStruct->InitStructRevision = ADAPTER_INIT_STRUCT_REVISION;
++ InitStruct->MiniPortRevision = MiniPortRevision;
++ InitStruct->FilesystemRevision = CommonExtension->FilesystemRevision;
++
++ //
++ // Adapter Fibs are the first thing allocated so that they start page aligned
++ //
++ InitStruct->AdapterFibsVirtualAddress = BaseAddress;
++ InitStruct->AdapterFibsPhysicalAddress = (PVOID) PhysicalBaseAddress.LowPart;
++ InitStruct->AdapterFibsSize = AdapterFibsSize;
++ InitStruct->AdapterFibAlign = sizeof(FIB);
++
++ //
++ // Increment the base address by the amount already used
++ //
++ BaseAddress = (PVOID)((PUCHAR)(BaseAddress) + AdapterFibsSize + sizeof(ADAPTER_INIT_STRUCT));
++ PhysicalBaseAddress.LowPart = (ULONG)((PUCHAR)(PhysicalBaseAddress.LowPart) + AdapterFibsSize + sizeof(ADAPTER_INIT_STRUCT));
++
++ //
++ // Align the beginning of Headers to CommAreaAlignment
++ //
++ BytesToAlign = (CommAreaAlignment - ((ULONG)(BaseAddress) & (CommAreaAlignment - 1)));
++ BaseAddress = (PVOID)((PUCHAR)(BaseAddress) + BytesToAlign);
++ PhysicalBaseAddress.LowPart = (ULONG)((PUCHAR)(PhysicalBaseAddress.LowPart) + BytesToAlign);
++
++ //
++ // Fill in addresses of the Comm Area Headers and Queues
++ //
++ *CommHeaderAddress = BaseAddress;
++ InitStruct->CommHeaderAddress = (PVOID)PhysicalBaseAddress.LowPart;
++
++ //
++ // Increment the base address by the size of the CommArea
++ //
++ BaseAddress = (PVOID)((PUCHAR)(BaseAddress) + CommAreaSize);
++ PhysicalBaseAddress.LowPart = (ULONG)((PUCHAR)(PhysicalBaseAddress.LowPart) + CommAreaSize);
++
++
++ //
++ // Place the Printf buffer area after the Fast I/O comm area.
++ //
++ CommonExtension->PrintfBufferAddress = (PVOID)(BaseAddress);
++ InitStruct->PrintfBufferAddress = (PVOID)PhysicalBaseAddress.LowPart;
++ InitStruct->PrintfBufferSize = PrintfBufferSize;
++ bzero (BaseAddress, PrintfBufferSize);
++
++ AfaPortPrint("FsaAllocateAdapterCommArea: allocated a common buffer of 0x%x bytes from address 0x%x to address 0x%x\n",
++ TotalSize, InitStruct->AdapterFibsVirtualAddress,
++ (PUCHAR)(InitStruct->AdapterFibsVirtualAddress) + TotalSize);
++
++ AfaPortPrint("Mapped on to PCI address 0x%x\n", InitStruct->AdapterFibsPhysicalAddress);
++
++ return (TRUE);
++}
++
++AAC_STATUS
++AfaPortCreate (
++ IN PDEVICE_OBJECT DeviceObject,
++ IN PIRP Irp
++ )
++/*++
++
++Routine Description:
++
++ The routine will get called each time a user issues a CreateFile on the DeviceObject
++ for the adapter.
++
++ The main purpose of this routine is to set up any data structures that may be needed
++ to handle any requests made on this DeviceObject.
++
++Arguments:
++
++ DeviceObject - Pointer to device object representing adapter
++
++ Irp - Pointer to Irp that caused this open
++
++
++Return Value:
++
++ Status value returned from File system driver AdapterOpen
++
++--*/
++
++{
++}
++
++AAC_STATUS
++AfaPortClose (
++ IN PDEVICE_OBJECT DeviceObject,
++ IN PIRP Irp
++ )
++/*++
++
++Routine Description:
++
++ This routine will get called each time a user issues a CloseHandle on the DeviceObject
++ for the adapter.
++
++ The main purpose of this routine is to cleanup any data structures that have been set up
++ while this FileObject has been opened.
++
++Arguments:
++
++ DeviceObject - Pointer to device object representing adapter
++
++ Irp - Pointer to Irp that caused this close
++
++Return Value:
++
++ Status value returned from File system driver AdapterClose
++
++--*/
++
++{
++
++}
++
++AAC_STATUS
++AfaPortDeviceControl (
++ IN PDEVICE_OBJECT DeviceObject,
++ IN PIRP Irp
++ )
++{
++
++}
++
++ULONG
++AfaPortGetMaxPhysicalPage(
++ IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension
++ )
++/*++
++
++Routine Description:
++
++ This routine determines the max physical page in host memory.
++
++Arguments:
++
++ AdapterExtension
++
++Return Value:
++
++ Max physical page in host memory.
++
++--*/
++{
++
++}
++
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/rx.c linux/drivers/scsi/aacraid/rx.c
+--- linux-2.4.9/drivers/scsi/aacraid/rx.c Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/rx.c Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,917 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * rx.c
++ *
++ * Abstract: Hardware miniport for Drawbridge specific hardware functions.
++ *
++ --*/
++
++static char *ident_rx = "aacraid_ident rx.c 1.0.7 2000/10/11 Adaptec, Inc.";
++
++#include "osheaders.h"
++
++
++#include "AacGenericTypes.h"
++
++#include "aac_unix_defs.h"
++
++#include "fsatypes.h"
++#include "comstruc.h"
++#include "fsact.h"
++#include "protocol.h"
++
++#define DEFINE_PCI_IDS
++#include "rxcommon.h"
++#include "monkerapi.h"
++
++#include "fsaport.h"
++#include "fsaioctl.h"
++
++#include "pcisup.h"
++#include "rx.h"
++
++#include "port.h"
++
++#define BugCheckFileId (FSAFS_BUG_CHECK_CYCLONESUP)
++
++// #define RxBugCheck(A,B,C) { KeBugCheckEx(0x00000AFA, __LINE__, (ULONG)A, (ULONG)B,(ULONG)C ); }
++
++#define RxBugCheck(A, B, C) { cmn_err(CE_PANIC, "aacdisk : line %s, 0x%x, 0x%x, 0x%x ", __LINE__, A, B, C); }
++
++#define NUM_TICKS_PER_SECOND (1000 * 1000 * 10) /* time is in 100 nanoseconds */
++
++
++//
++// The list of all the Rx adapter structures
++//
++
++PRx_ADAPTER_EXTENSION RxAdapterList;
++
++int
++RxInitDevice(
++ IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension,
++ IN ULONG AdapterNumber,
++ IN ULONG PciBus,
++ IN ULONG PciSlot
++);
++
++BOOLEAN
++RxSendSynchFib(
++ PVOID Arg1,
++ ULONG FibPhysicalAddress
++ );
++
++FSA_USER_VAR RxUserVars[] = {
++ { "AfaPortPrinting", (PULONG)&AfaPortPrinting, NULL },
++};
++
++
++//
++// Declare private use routines for this modual
++//
++
++u_int
++RxPciIsr (
++ IN PRx_ADAPTER_EXTENSION AdapterExtension
++ )
++
++/*++
++
++Routine Description:
++
++ The Isr routine for fsa Rx based adapter boards.
++
++Arguments:
++
++
++Return Value:
++
++ TRUE - if the interrupt was handled by this isr
++ FALSE - if the interrupt was not handled by this isr
++
++--*/
++
++{
++ ULONG DoorbellBits;
++ UCHAR InterruptStatus, Mask;
++ u_int OurInterrupt = INTR_UNCLAIMED;
++
++ //cmn_err(CE_WARN, "RxPciIsr entered\n");
++
++ InterruptStatus = Rx_READ_UCHAR(AdapterExtension, MUnit.OISR);
++
++ //
++ // Read mask and invert because drawbridge is reversed.
++ //
++ // This allows us to only service interrupts that have been enabled.
++ //
++
++ Mask = ~(Rx_READ_UCHAR(AdapterExtension, MUnit.OIMR));
++
++ // Check to see if this is our interrupt. If it isn't just return FALSE.
++
++
++ if (InterruptStatus & Mask) {
++
++ DoorbellBits = Rx_READ_ULONG(AdapterExtension, OutboundDoorbellReg);
++
++ OurInterrupt = INTR_CLAIMED;
++
++ if (DoorbellBits & DoorBellPrintfReady) {
++
++ ULONG Length, Level;
++ unsigned char *cp;
++
++ cp = AdapterExtension->Common->PrintfBufferAddress;
++
++ //
++ // The size of the Printfbuffer is set in port.c
++ // There is no variable or define for it
++ //
++ if (Length > 255)
++ Length = 255;
++
++ if (cp[Length] != 0) {
++ // cmn_err (CE_NOTE, "byte %d is 0x%x, should be 0", Length, cp[Length]);
++ cp[Length] = 0;
++ }
++
++ if (Level == LOG_HIGH_ERROR)
++ cmn_err (CE_WARN, "%s:%s", OsGetDeviceName(AdapterExtension), AdapterExtension->Common->PrintfBufferAddress);
++ else
++ cmn_err (CE_NOTE, "%s:%s", OsGetDeviceName(AdapterExtension), AdapterExtension->Common->PrintfBufferAddress);
++
++ bzero (AdapterExtension->Common->PrintfBufferAddress, 256);
++
++ Rx_WRITE_ULONG(AdapterExtension, MUnit.ODR,DoorBellPrintfReady); //clear PrintfReady
++
++ Rx_WRITE_ULONG(AdapterExtension, InboundDoorbellReg,DoorBellPrintfDone);
++
++
++ } else if (DoorbellBits & DoorBellAdapterNormCmdReady) { // Adapter -> Host Normal Command Ready
++
++ AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, HostNormCmdQue);
++ Rx_WRITE_ULONG(AdapterExtension, MUnit.ODR, DoorBellAdapterNormCmdReady);
++
++ } else if (DoorbellBits & DoorBellAdapterNormRespReady) { // Adapter -> Host Normal Response Ready
++
++ AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, HostNormRespQue);
++ Rx_WRITE_ULONG(AdapterExtension, MUnit.ODR,DoorBellAdapterNormRespReady);
++
++ } else if (DoorbellBits & DoorBellAdapterNormCmdNotFull) { // Adapter -> Host Normal Command Not Full
++
++ AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, AdapNormCmdNotFull);
++ Rx_WRITE_ULONG(AdapterExtension, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
++
++ } else if (DoorbellBits & DoorBellAdapterNormRespNotFull) { // Adapter -> Host Normal Response Not Full
++
++ AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, AdapNormRespNotFull);
++ Rx_WRITE_ULONG(AdapterExtension, MUnit.ODR, DoorBellAdapterNormRespNotFull);
++
++ }
++
++ }
++ return(OurInterrupt);
++}
++
++VOID
++RxEnableInterrupt(
++ PVOID Arg1,
++ ADAPTER_EVENT AdapterEvent,
++ BOOLEAN AtDeviceIrq
++ )
++/*++
++
++Routine Description:
++
++ This routine will enable the corresponding adapter event to cause an interrupt on
++ the host.
++
++Arguments:
++
++ AdapterExtension - Which adapter to enable.
++
++ AdapterEvent - Which adapter event.
++
++ AtDeviceIrq - Whether the system is in DEVICE irql
++
++Return Value:
++
++ Nothing.
++
++--*/
++{
++ PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
++ PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) CommonExtension->MiniPort;
++
++ //cmn_err(CE_WARN, "RxEnableInterrupt");
++ switch (AdapterEvent) {
++
++ case HostNormCmdQue:
++
++ AdapterExtension->LocalMaskInterruptControl &= ~(OUTBOUNDDOORBELL_1);
++
++ break;
++
++ case HostNormRespQue:
++
++ AdapterExtension->LocalMaskInterruptControl &= ~(OUTBOUNDDOORBELL_2);
++
++ break;
++
++ case AdapNormCmdNotFull:
++
++ AdapterExtension->LocalMaskInterruptControl &= ~(OUTBOUNDDOORBELL_3);
++
++ break;
++
++ case AdapNormRespNotFull:
++
++ AdapterExtension->LocalMaskInterruptControl &= ~(OUTBOUNDDOORBELL_4);
++
++ break;
++
++ }
++
++}
++
++VOID
++RxDisableInterrupt(
++ PVOID Arg1,
++ ADAPTER_EVENT AdapterEvent,
++ BOOLEAN AtDeviceIrq
++ )
++/*++
++
++Routine Description:
++
++ This routine will disable the corresponding adapter event to cause an interrupt on
++ the host.
++
++Arguments:
++
++ AdapterExtension - Which adapter to enable.
++
++ AdapterEvent - Which adapter event.
++
++ AtDeviceIrq - Whether the system is in DEVICE irql
++
++Return Value:
++
++ Nothing.
++
++--*/
++{
++ PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
++ PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) CommonExtension->MiniPort;
++
++ //cmn_err(CE_WARN, "RxEnableInterrupt");
++
++ switch (AdapterEvent) {
++
++
++ case HostNormCmdQue:
++
++ AdapterExtension->LocalMaskInterruptControl |= (OUTBOUNDDOORBELL_1);
++
++ break;
++
++ case HostNormRespQue:
++
++ AdapterExtension->LocalMaskInterruptControl |= (OUTBOUNDDOORBELL_2);
++
++ break;
++
++ case AdapNormCmdNotFull:
++
++ AdapterExtension->LocalMaskInterruptControl |= (OUTBOUNDDOORBELL_3);
++
++ break;
++
++
++ case AdapNormRespNotFull:
++
++ AdapterExtension->LocalMaskInterruptControl |= (OUTBOUNDDOORBELL_4);
++
++ break;
++
++ }
++
++}
++
++
++
++RxDetachDevice(
++ IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension
++ )
++{
++ PRx_ADAPTER_EXTENSION AdapterExtension = CommonExtension->MiniPort;
++
++ //
++ // Free the register mapping.
++ //
++
++ OsDetachDevice( AdapterExtension);
++
++ OsFreeMemory( AdapterExtension, sizeof(Rx_ADAPTER_EXTENSION) );
++
++}
++
++int
++RxInitDevice(
++ IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension,
++ IN ULONG AdapterNumber,
++ IN ULONG PciBus,
++ IN ULONG PciSlot
++)
++
++/*++
++
++Routine Description:
++
++ Scans the PCI bus looking for the Rx card. When found all resources for the
++ device will be allocated and the interrupt vectors and csrs will be allocated and
++ mapped.
++
++ The device_interface in the commregion will be allocated and linked to the comm region.
++
++Arguments:
++
++
++Return Value:
++
++ TRUE - if the device was setup with not problems
++ FALSE - if the device could not be mapped and init successfully
++
++--*/
++
++{
++ AAC_STATUS Status;
++ PRx_ADAPTER_EXTENSION AdapterExtension = NULL;
++ FSA_NEW_ADAPTER NewAdapter;
++ ULONG StartTime, EndTime, WaitTime;
++ ULONG InitStatus;
++ int instance;
++ int nIntrs;
++ char * name;
++
++ AfaPortPrint("In init device.\n");
++
++ //cmn_err(CE_WARN, "In RxInitDevice");
++
++// AdapterExtension->Common->AdapterIndex = AdapterIndex;
++ CommonExtension->AdapterNumber = AdapterNumber;
++
++
++ CommonExtension->PciBusNumber = PciBus;
++ CommonExtension->PciSlotNumber = PciSlot;
++
++
++ AdapterExtension = OsAllocMemory( sizeof(Rx_ADAPTER_EXTENSION), OS_ALLOC_MEM_SLEEP );
++ AdapterExtension->Common = CommonExtension;
++ CommonExtension->MiniPort = AdapterExtension;
++
++ instance = OsGetDeviceInstance(AdapterExtension);
++ name = OsGetDeviceName(AdapterExtension);
++ //
++ // Map in the registers from the adapter, register space 0 is config space,
++ // register space 1 is the memery space.
++ //
++
++ if (OsMapDeviceRegisters(AdapterExtension)) {
++
++ cmn_err(CE_CONT, "%s%d: can't map device registers\n",
++ OsGetDeviceName(AdapterExtension), instance);
++ return(FAILURE);
++ }
++
++ //
++ // Check to see if the board failed any self tests.
++ //
++
++ if (Rx_READ_ULONG( AdapterExtension, IndexRegs.Mailbox[7]) & SELF_TEST_FAILED) {
++
++ cmn_err(CE_CONT, "%s%d: adapter self-test failed\n",
++ OsGetDeviceName(AdapterExtension), instance);
++ return(FAILURE);
++
++ }
++ //cmn_err(CE_WARN, "RxInitDevice: %s%d: adapter passwd self-test\n",
++ // OsGetDeviceName(AdapterExtension), instance);
++
++ //
++ // Check to see if the board panic'd while booting.
++ //
++
++ if (Rx_READ_ULONG( AdapterExtension, IndexRegs.Mailbox[7]) & KERNEL_PANIC) {
++
++ cmn_err(CE_CONT, "%s%d: adapter kernel panic'd\n",
++ OsGetDeviceName(AdapterExtension), instance);
++ return(FAILURE);
++
++ }
++
++ StartTime = OsGetSeconds();
++ WaitTime = 0;
++
++
++ //
++ // Wait for the adapter to be up and running. Wait up until 3 minutes.
++ //
++
++ while (!(Rx_READ_ULONG( AdapterExtension, IndexRegs.Mailbox[7]) & KERNEL_UP_AND_RUNNING)) {
++
++ EndTime = OsGetSeconds();
++
++ WaitTime = EndTime - StartTime;
++
++ if ( WaitTime > (3 * 10) ) {
++
++ InitStatus = Rx_READ_ULONG( AdapterExtension, IndexRegs.Mailbox[7]) >> 16;
++
++ cmn_err(CE_CONT, "%s%d: adapter kernel failed to start, init status = %d\n",
++ OsGetDeviceName(AdapterExtension), instance, InitStatus);
++ return(FAILURE);
++
++ }
++ }
++
++ if (OsAttachInterrupt(AdapterExtension,RxISR)) {
++ cmn_err(CE_WARN, "%s%d RxInitDevice: failed OsAttachIntterupt", name, instance);
++ return(FAILURE);
++ }
++
++
++ if (OsAttachDMA(AdapterExtension)) {
++ cmn_err(CE_WARN, "%s%d SaInitDevice: failed OsAttachDMA", name, instance);
++ return(FAILURE);
++ }
++
++ //
++ // Fill in the function dispatch table.
++ //
++
++ AdapterExtension->Common->AdapterFuncs.SizeOfFsaPortFuncs = sizeof(FSAPORT_FUNCS);
++ AdapterExtension->Common->AdapterFuncs.AllocateAdapterCommArea = AfaPortAllocateAdapterCommArea;
++ AdapterExtension->Common->AdapterFuncs.FreeAdapterCommArea = AfaPortFreeAdapterCommArea;
++ AdapterExtension->Common->AdapterFuncs.BuildSgMap = AfaPortBuildSgMap;
++ AdapterExtension->Common->AdapterFuncs.FreeDmaResources = AfaPortFreeDmaResources;
++ AdapterExtension->Common->AdapterFuncs.AllocateAndMapFibSpace = AfaPortAllocateAndMapFibSpace;
++ AdapterExtension->Common->AdapterFuncs.UnmapAndFreeFibSpace = AfaPortUnmapAndFreeFibSpace;
++ AdapterExtension->Common->AdapterFuncs.InterruptAdapter = RxInterruptAdapter;
++ AdapterExtension->Common->AdapterFuncs.EnableInterrupt = RxEnableInterrupt;
++ AdapterExtension->Common->AdapterFuncs.DisableInterrupt = RxDisableInterrupt;
++ AdapterExtension->Common->AdapterFuncs.NotifyAdapter = RxNotifyAdapter;
++ AdapterExtension->Common->AdapterFuncs.ResetDevice = RxResetDevice;
++ AdapterExtension->Common->AdapterFuncs.InterruptHost = NULL;
++
++ AdapterExtension->Common->AdapterFuncs.SendSynchFib = RxSendSynchFib;
++
++ NewAdapter.AdapterExtension = CommonExtension;
++ NewAdapter.AdapterFuncs = &AdapterExtension->Common->AdapterFuncs;
++ NewAdapter.AdapterInterruptsBelowDpc = FALSE;
++ NewAdapter.AdapterUserVars = RxUserVars;
++ NewAdapter.AdapterUserVarsSize = sizeof(RxUserVars) / sizeof(FSA_USER_VAR);
++
++ NewAdapter.Dip = CommonExtension->OsDep.dip;
++
++
++ if (AfaCommInitNewAdapter( &NewAdapter ) == NULL) {
++
++ cmn_err(CE_WARN, "AfaCommInitNewAdapter failed\n");
++ return (FAILURE);
++ }
++
++
++ AdapterExtension->Common->Adapter = NewAdapter.Adapter;
++
++ if (AdapterExtension->Common->Adapter == NULL) {
++
++ AfaPortLogError(AdapterExtension->Common, FAILURE, NULL, 0);
++ cmn_err(CE_WARN, "%s%d RxInitDevice: No Adapter pointer", name, instance);
++
++
++ return (FAILURE);
++ }
++
++
++ //
++ // Start any kernel threads needed
++ //
++ OsStartKernelThreads(AdapterExtension);
++
++ //
++ // Tell the adapter that all is configure, and it can start accepting requests
++ //
++
++ RxStartAdapter(AdapterExtension);
++
++
++#ifdef AACDISK
++#endif
++
++
++ //
++ // Put this adapter into the list of Rx adapters
++ //
++
++ AdapterExtension->Next = RxAdapterList;
++ RxAdapterList = AdapterExtension;
++
++ AdapterExtension->Common->AdapterConfigured = TRUE;
++
++
++#ifdef AACDISK
++ //
++ // Call the disk layer to initialize itself.
++ //
++
++ AfaDiskInitNewAdapter( AdapterExtension->Common->AdapterNumber, AdapterExtension->Common->Adapter );
++#endif
++
++
++init_done:
++
++ AdapterExtension->Common->AdapterPrintfsToScreen = FALSE;
++
++
++
++ OsAttachHBA(AdapterExtension);
++
++ return(0);
++}
++
++VOID
++RxStartAdapter(
++ PRx_ADAPTER_EXTENSION AdapterExtension
++ )
++{
++ ULONG ReturnStatus;
++ LARGE_INTEGER HostTime;
++ ULONG ElapsedSeconds;
++ PADAPTER_INIT_STRUCT InitStruct;
++
++ //cmn_err(CE_WARN, "RxStartAdapter");
++ //
++ // Fill in the remaining pieces of the InitStruct.
++ //
++
++ InitStruct = AdapterExtension->Common->InitStruct;
++
++ InitStruct->HostPhysMemPages = AfaPortGetMaxPhysicalPage(AdapterExtension->Common);
++
++ ElapsedSeconds = OsGetSeconds();
++
++ InitStruct->HostElapsedSeconds = ElapsedSeconds;
++
++ //
++ // Tell the adapter we are back and up and running so it will scan its command
++ // queues and enable our interrupts
++ //
++
++ AdapterExtension->LocalMaskInterruptControl =
++ (DoorBellPrintfReady | OUTBOUNDDOORBELL_1 | OUTBOUNDDOORBELL_2 | OUTBOUNDDOORBELL_3 | OUTBOUNDDOORBELL_4);
++
++ //
++ // First clear out all interrupts. Then enable the one's that we can handle.
++ //
++
++ Rx_WRITE_UCHAR( AdapterExtension, MUnit.OIMR, 0xff);
++ Rx_WRITE_ULONG( AdapterExtension, MUnit.ODR, 0xffffffff);
++// Rx_WRITE_UCHAR(AdapterExtension, MUnit.OIMR, ~(UCHAR)OUTBOUND_DOORBELL_INTERRUPT_MASK);
++ Rx_WRITE_UCHAR( AdapterExtension, MUnit.OIMR, 0xfb);
++
++ RxSendSynchCommand(AdapterExtension,
++ INIT_STRUCT_BASE_ADDRESS,
++ (ULONG) AdapterExtension->Common->PhysicalInitStruct,
++ 0,
++ 0,
++ 0,
++ &ReturnStatus);
++
++}
++
++
++VOID
++RxResetDevice(
++ PVOID Arg1
++ )
++
++{
++}
++
++VOID
++RxInterruptAdapter(
++ PVOID Arg1
++ )
++/*++
++
++Routine Description:
++
++ The will cause the adapter to take a break point.
++
++Arguments:
++
++ None
++
++Return Value:
++
++ Nothing
++
++--*/
++{
++ PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
++ PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) CommonExtension->MiniPort;
++
++ ULONG ReturnStatus;
++
++ RxSendSynchCommand(AdapterExtension,
++ BREAKPOINT_REQUEST,
++ 0,
++ 0,
++ 0,
++ 0,
++ &ReturnStatus);
++
++}
++
++VOID
++RxNotifyAdapter(
++ PVOID Arg1,
++ IN HOST_2_ADAP_EVENT AdapterEvent
++ )
++/*++
++
++Routine Description:
++
++ Will read the adapter CSRs to find the reason the adapter has
++ interrupted us.
++
++Arguments:
++
++ AdapterEvent - Enumerated type the returns the reason why we were interrutped.
++
++Return Value:
++
++ Nothing
++
++--*/
++{
++ PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
++ PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) CommonExtension->MiniPort;
++ ULONG ReturnStatus;
++
++ //cmn_err(CE_WARN, "RxNotifyAdapter %d", AdapterEvent);
++
++ switch (AdapterEvent) {
++ case AdapNormCmdQue:
++
++ Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_1);
++ break;
++
++ case HostNormRespNotFull:
++
++ Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_4);
++ break;
++
++ case AdapNormRespQue:
++
++ Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_2);
++ break;
++
++ case HostNormCmdNotFull:
++
++ Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_3);
++ break;
++
++ case HostShutdown:
++
++// RxSendSynchCommand(AdapterExtension, HOST_CRASHING, 0, 0, 0, 0, &ReturnStatus);
++
++ break;
++
++ case FastIo:
++ Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_6);
++ break;
++
++ case AdapPrintfDone:
++ Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_5);
++ break;
++
++ default:
++
++ RxBugCheck(0,0,0);
++ AfaPortPrint("Notify requested with an invalid request 0x%x.\n",AdapterEvent);
++ break;
++ }
++}
++
++AAC_STATUS
++RxSendSynchCommand(
++ PVOID Arg1,
++ ULONG Command,
++ ULONG Parameter1,
++ ULONG Parameter2,
++ ULONG Parameter3,
++ ULONG Parameter4,
++ PULONG ReturnStatus
++ )
++/*++
++
++Routine Description:
++
++ This routine will send a synchronous comamnd to the adapter and wait for its
++ completion.
++
++Arguments:
++
++ AdapterExtension - Pointer to adapter extension structure.
++ Command - Which command to send
++ Parameter1 - 4 - Parameters for command
++ ReturnStatus - return status from adapter after completion of command
++
++
++Return Value:
++
++ AAC_STATUS
++
++--*/
++{
++ PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) Arg1;
++ ULONG StartTime,EndTime,WaitTime;
++ BOOLEAN CommandSucceeded;
++
++ //cmn_err(CE_WARN, "RxSendSyncCommand");
++ //
++ // Write the Command into Mailbox 0
++ //
++
++ Rx_WRITE_ULONG( AdapterExtension, InboundMailbox0, Command);
++
++ //
++ // Write the parameters into Mailboxes 1 - 4
++ //
++
++ Rx_WRITE_ULONG( AdapterExtension, InboundMailbox1, Parameter1);
++ Rx_WRITE_ULONG( AdapterExtension, InboundMailbox2, Parameter2);
++ Rx_WRITE_ULONG( AdapterExtension, InboundMailbox3, Parameter3);
++ Rx_WRITE_ULONG( AdapterExtension, InboundMailbox4, Parameter4);
++
++ //
++ // Clear the synch command doorbell to start on a clean slate.
++ //
++
++ Rx_WRITE_ULONG( AdapterExtension, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
++
++ //
++ // disable doorbell interrupts
++ //
++
++ Rx_WRITE_UCHAR( AdapterExtension, MUnit.OIMR,
++ Rx_READ_UCHAR(AdapterExtension, MUnit.OIMR) | 0x04);
++
++ //
++ // force the completion of the mask register write before issuing the interrupt.
++ //
++
++ Rx_READ_UCHAR ( AdapterExtension, MUnit.OIMR);
++
++ //
++ // Signal that there is a new synch command
++ //
++
++ Rx_WRITE_ULONG( AdapterExtension, InboundDoorbellReg, INBOUNDDOORBELL_0);
++
++ CommandSucceeded = FALSE;
++
++ StartTime = OsGetSeconds();
++ WaitTime = 0;
++
++ while (WaitTime < 30) { // wait up to 30 seconds
++
++ drv_usecwait(5); // delay 5 microseconds to let Mon960 get info.
++
++ //
++ // Mon110 will set doorbell0 bit when it has completed the command.
++ //
++
++ if (Rx_READ_ULONG(AdapterExtension, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) {
++
++ //
++ // clear the doorbell.
++ //
++
++ Rx_WRITE_ULONG(AdapterExtension, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
++
++ CommandSucceeded = TRUE;
++ break;
++ }
++
++ EndTime = OsGetSeconds();
++ WaitTime = EndTime - StartTime;
++
++ }
++
++ if (CommandSucceeded != TRUE) {
++
++ //
++ // restore interrupt mask even though we timed out
++ //
++
++ Rx_WRITE_UCHAR(AdapterExtension, MUnit.OIMR,
++ Rx_READ_ULONG(AdapterExtension, MUnit.OIMR) & 0xfb);
++
++ return (STATUS_IO_TIMEOUT);
++
++ }
++
++ //
++ // Pull the synch status from Mailbox 0.
++ //
++
++ *ReturnStatus = Rx_READ_ULONG(AdapterExtension, IndexRegs.Mailbox[0]);
++
++ //
++ // Clear the synch command doorbell.
++ //
++
++ Rx_WRITE_ULONG(AdapterExtension, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
++
++ //
++ // restore interrupt mask
++ //
++
++ Rx_WRITE_UCHAR(AdapterExtension, MUnit.OIMR,
++ Rx_READ_ULONG(AdapterExtension, MUnit.OIMR) & 0xfb);
++
++ //
++ // Return SUCCESS
++ //
++
++ return (STATUS_SUCCESS);
++
++}
++
++BOOLEAN
++RxSendSynchFib(
++ PVOID Arg1,
++ ULONG FibPhysicalAddress
++ )
++/*++
++
++Routine Description:
++
++ This routine will send a synchronous fib to the adapter and wait for its
++ completion.
++
++Arguments:
++
++ AdapterExtension - Pointer to adapter extension structure.
++ FibPhysicalAddress - Physical address of fib to send.
++
++
++Return Value:
++
++ BOOLEAN
++
++--*/
++{
++ PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
++ PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) CommonExtension->MiniPort;
++ ULONG returnStatus;
++
++ if (RxSendSynchCommand( AdapterExtension,
++ SEND_SYNCHRONOUS_FIB,
++ FibPhysicalAddress,
++ 0,
++ 0,
++ 0,
++ &returnStatus ) != STATUS_SUCCESS ) {
++
++ return (FALSE);
++
++ }
++
++ return (TRUE);
++
++}
++
++
+diff -burN linux-2.4.9/drivers/scsi/aacraid/sap1sup.c linux/drivers/scsi/aacraid/sap1sup.c
+--- linux-2.4.9/drivers/scsi/aacraid/sap1sup.c Wed Dec 31 18:00:00 1969
++++ linux/drivers/scsi/aacraid/sap1sup.c Thu Aug 16 13:41:30 2001
+@@ -0,0 +1,859 @@
++/*++
++ * Adaptec aacraid device driver for Linux.
++ *
++ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING. If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Module Name:
++ * sap1sup.c
++ *
++ * Abstract: Drawbridge specific support functions
++ *
++ --*/
++
++static char *ident_sap1 = "aacraid_ident sap1sup.c 1.0.7 2000/10/11 Adaptec, Inc.";
++
++#include "osheaders.h"
++
++
++#include "AacGenericTypes.h"
++
++#include "aac_unix_defs.h"
++
++#include "fsatypes.h"
++#include "comstruc.h"
++#include "fsact.h"
++#include "protocol.h"
++
++#define DEFINE_PCI_IDS
++#include "sap1common.h"
++#include "monkerapi.h"
++
++#include "fsaport.h"
++#include "fsaioctl.h"
++
++
++#include "pcisup.h"
++#include "sap1.h"
++
++#include "port.h"
++
++#include "nodetype.h"
++#include "comsup.h"
++#include "afacomm.h"
++#include "adapter.h"
++
++#define BugCheckFileId (FSAFS_BUG_CHECK_CYCLONESUP)
++
++// #define SaBugCheck(A,B,C) { KeBugCheckEx(0x00000AFA, __LINE__, (ULONG)A, (ULONG)B,(ULONG)C ); }
++
++#define SaBugCheck(A, B, C) { cmn_err(CE_PANIC, "aacdisk : line %s, 0x%x, 0x%x, 0x%x ", __LINE__, A, B, C); }
++
++#define NUM_TICKS_PER_SECOND (1000 * 1000 * 10) /* time is in 100 nanoseconds */
++
++int MiniPortRevision = Sa_MINIPORT_REVISION;
++
++
++//
++// The list of all the Sa adapter structures
++//
++
++PSa_ADAPTER_EXTENSION SaAdapterList;
++
++int
++SaInitDevice(
++ IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension,
++ IN ULONG AdapterNumber,
++ IN ULONG PciBus,
++ IN ULONG PciSlot
++);
++
++BOOLEAN
++SaSendSynchFib(
++ PVOID Arg1,
++ ULONG FibPhysicalAddress
++ );
++
++FSA_USER_VAR SaUserVars[] = {
++ { "AfaPortPrinting", (PULONG)&AfaPortPrinting, NULL },
++};
++
++
++//
++// Declare private use routines for this modual
++//
++
++
++/*++
++
++Routine Description:
++
++ The Isr routine for fsa Sa based adapter boards.
++
++Arguments:
++
++
++Return Value:
++
++ TRUE - if the interrupt was handled by this isr
++ FALSE - if the interrupt was not handled by this isr
++
++--*/
++u_int
++SaPciIsr (IN PSa_ADAPTER_EXTENSION AdapterExtension)
++{
++ USHORT InterruptStatus, Mask;
++ u_int OurInterrupt = INTR_UNCLAIMED;
++
++ InterruptStatus = Sa_READ_USHORT( AdapterExtension, DoorbellReg_p);
++
++ //
++ // Read mask and invert because drawbridge is reversed.
++ //
++ // This allows us to only service interrupts that have been enabled.
++ //
++
++ Mask = ~(Sa_READ_USHORT( AdapterExtension, SaDbCSR.PRISETIRQMASK));
++
++ // Check to see if this is our interrupt. If it isn't just return FALSE.
++
++
++ if (InterruptStatus & Mask) {
++
++ OurInterrupt = INTR_CLAIMED;
++
++ if (InterruptStatus & PrintfReady) {
++
++ ULONG Length, Level;
++ unsigned char *cp;
++
++ cp = AdapterExtension->Common->PrintfBufferAddress;
++
++ //
++ // The size of the Printbuffer is set in port.c
++ // There is no variable or define for it
++ //
++ if (Length > 255)
++ Length = 255;
++
++ if (cp[Length] != 0) {
++ // cmn_err (CE_NOTE, "byte %d is 0x%x, should be 0", Length, cp[Length]);
++ cp[Length] = 0;
++ }
++
++ if (Level == LOG_HIGH_ERROR)
++ cmn_err (CE_WARN, "%s:%s", OsGetDeviceName(AdapterExtension), AdapterExtension->Common->PrintfBufferAddress);
++ else
++ cmn_err (CE_NOTE, "%s:%s", OsGetDeviceName(AdapterExtension), AdapterExtension->Common->PrintfBufferAddress);
++
++ bzero (AdapterExtension->Common->PrintfBufferAddress, 256);
++
++ Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p,PrintfReady); //clear PrintfReady
++
++ Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,PrintfDone);
++
++ } else if (InterruptStatus & DOORBELL_1) { // Adapter -> Host Normal Command Ready
++
++ AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, HostNormCmdQue);
++ Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p, DOORBELL_1);
++
++ } else if (InterruptStatus & DOORBELL_2) { // Adapter -> Host Normal Response Ready
++
++ AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, HostNormRespQue);
++ Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p,DOORBELL_2);
++
++ } else if (InterruptStatus & DOORBELL_3) { // Adapter -> Host Normal Command Not Full
++
++ AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, AdapNormCmdNotFull);
++ Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p, DOORBELL_3);
++
++ } else if (InterruptStatus & DOORBELL_4) { // Adapter -> Host Normal Response Not Full
++
++ AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, AdapNormRespNotFull);
++ Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p, DOORBELL_4);
++
++ }
++
++ }
++ return(OurInterrupt);
++}
++
++
++/*++
++
++Routine Description:
++
++ This routine will enable the corresponding adapter event to cause an interrupt on
++ the host.
++
++Arguments:
++
++ AdapterExtension - Which adapter to enable.
++
++ AdapterEvent - Which adapter event.
++
++ AtDeviceIrq - Whether the system is in DEVICE irql
++
++Return Value:
++
++ Nothing.
++
++--*/
++VOID
++SaEnableInterrupt (PVOID Arg1, ADAPTER_EVENT AdapterEvent, BOOLEAN AtDeviceIrq)
++{
++ PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
++ PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) CommonExtension->MiniPort;
++
++ switch (AdapterEvent) {
++
++ case HostNormCmdQue:
++
++ Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRICLEARIRQMASK, DOORBELL_1 );
++
++ break;
++
++ case HostNormRespQue:
++
++ Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRICLEARIRQMASK, DOORBELL_2 );
++
++ break;
++
++ case AdapNormCmdNotFull:
++
++ Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRICLEARIRQMASK, DOORBELL_3 );
++
++ break;
++
++ case AdapNormRespNotFull:
++
++ Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRICLEARIRQMASK, DOORBELL_4 );
++
++ break;
++
++ }
++
++}
++
++
++
++/*++
++
++Routine Description:
++
++ This routine will disable the corresponding adapter event to cause an interrupt on
++ the host.
++
++Arguments:
++
++ AdapterExtension - Which adapter to enable.
++
++ AdapterEvent - Which adapter event.
++
++ AtDeviceIrq - Whether the system is in DEVICE irql
++
++Return Value:
++
++ Nothing.
++
++--*/
++VOID
++SaDisableInterrupt (PVOID Arg1, ADAPTER_EVENT AdapterEvent, BOOLEAN AtDeviceIrq)
++{
++ PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
++ PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) CommonExtension->MiniPort;
++
++ switch (AdapterEvent) {
++
++
++ case HostNormCmdQue:
++
++ Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRISETIRQMASK, DOORBELL_1 );
++
++ break;
++
++ case HostNormRespQue:
++
++ Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRISETIRQMASK, DOORBELL_2 );
++
++ break;
++
++ case AdapNormCmdNotFull:
++
++ Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRISETIRQMASK, DOORBELL_3 );
++
++ break;
++
++
++ case AdapNormRespNotFull:
++
++ Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRISETIRQMASK, DOORBELL_4 );
++
++ break;
++
++ }
++
++}
++
++
++SaDetachDevice (IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension)
++{
++ PSa_ADAPTER_EXTENSION AdapterExtension = CommonExtension->MiniPort;
++
++ //
++ // Free the register mapping.
++ //
++
++ OsDetachDevice(AdapterExtension);
++
++ OsFreeMemory( AdapterExtension, sizeof(Sa_ADAPTER_EXTENSION) );
++
++}
++
++
++/*++
++
++Routine Description:
++
++ Scans the PCI bus looking for the Sa card. When found all resources for the
++ device will be allocated and the interrupt vectors and csrs will be allocated and
++ mapped.
++
++ The device_interface in the commregion will be allocated and linked to the comm region.
++
++Arguments:
++
++
++Return Value:
++
++ TRUE - if the device was setup with not problems
++ FALSE - if the device could not be mapped and init successfully
++
++--*/
++int
++SaInitDevice (IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension,
++ IN ULONG AdapterNumber, IN ULONG PciBus,
++ IN ULONG PciSlot)
++{
++ AAC_STATUS Status;
++ PSa_ADAPTER_EXTENSION AdapterExtension = NULL;
++ FSA_NEW_ADAPTER NewAdapter;
++ ULONG StartTime, EndTime, WaitTime;
++ ULONG InitStatus;
++ int instance;
++ char *name;
++
++ AfaPortPrint("In init device.\n");
++
++ CommonExtension->AdapterNumber = AdapterNumber;
++
++ CommonExtension->PciBusNumber = PciBus;
++ CommonExtension->PciSlotNumber = PciSlot;
++
++ AdapterExtension = OsAllocMemory( sizeof(Sa_ADAPTER_EXTENSION), OS_ALLOC_MEM_SLEEP );
++ AdapterExtension->Common = CommonExtension;
++ CommonExtension->MiniPort = AdapterExtension;
++
++ instance = OsGetDeviceInstance(AdapterExtension);
++ name = OsGetDeviceName(AdapterExtension);
++
++ //
++ // Map in the registers from the adapter, register space 0 is config space,
++ // register space 1 is the memery space.
++ //
++
++ if (OsMapDeviceRegisters(AdapterExtension)){
++ cmn_err(CE_WARN, "%s%d SaInitDevice: failed OsMapDeviceRegisters", name, instance);
++ return(FAILURE);
++ }
++
++
++ //
++ // Check to see if the board failed any self tests.
++ //
++
++ if (Sa_READ_ULONG( AdapterExtension, Mailbox7) & SELF_TEST_FAILED) {
++
++ cmn_err(CE_WARN, "%s%d: adapter self-test failed\n",
++ name, instance);
++ return(FAILURE);
++ }
++
++ //
++ // Check to see if the board panic'd while booting.
++ //
++
++ if (Sa_READ_ULONG( AdapterExtension, Mailbox7) & KERNEL_PANIC) {
++
++ cmn_err(CE_WARN, "%s%d: adapter kernel panic'd\n",
++ name, instance);
++ return(FAILURE);
++ }
++
++
++ StartTime = OsGetSeconds();
++ WaitTime = 0;
++
++
++ //
++ // Wait for the adapter to be up and running. Wait up until 3 minutes.
++ //
++
++ while (!(Sa_READ_ULONG( AdapterExtension, Mailbox7) & KERNEL_UP_AND_RUNNING)) {
++
++ EndTime = OsGetSeconds();
++
++ WaitTime = EndTime - StartTime;
++
++ if ( WaitTime > (3 * 60) ) {
++
++ InitStatus = Sa_READ_ULONG( AdapterExtension, Mailbox7) >> 16;
++
++ cmn_err(CE_WARN, "%s%d: adapter kernel failed to start, init status = %d\n",
++ name, instance, InitStatus);
++ return(FAILURE);
++
++ }
++ }
++
++ if (OsAttachInterrupt(AdapterExtension, SaISR)) {
++ cmn_err(CE_WARN, "%s%d SaInitDevice: failed OsAttachIntterupt", name, instance);
++ return(FAILURE);
++ }
++
++ if (OsAttachDMA(AdapterExtension)) {
++ cmn_err(CE_WARN, "%s%d SaInitDevice: failed OsAttachDMA", name, instance);
++ return(FAILURE);
++ }
++
++
++ //
++ // Fill in the function dispatch table.
++ //
++
++ AdapterExtension->Common->AdapterFuncs.SizeOfFsaPortFuncs = sizeof(FSAPORT_FUNCS);
++ AdapterExtension->Common->AdapterFuncs.AllocateAdapterCommArea = AfaPortAllocateAdapterCommArea;
++ AdapterExtension->Common->AdapterFuncs.FreeAdapterCommArea = AfaPortFreeAdapterCommArea;
++ AdapterExtension->Common->AdapterFuncs.BuildSgMap = AfaPortBuildSgMap;
++ AdapterExtension->Common->AdapterFuncs.FreeDmaResources = AfaPortFreeDmaResources;
++ AdapterExtension->Common->AdapterFuncs.AllocateAndMapFibSpace = AfaPortAllocateAndMapFibSpace;
++ AdapterExtension->Common->AdapterFuncs.UnmapAndFreeFibSpace = AfaPortUnmapAndFreeFibSpace;
++ AdapterExtension->Common->AdapterFuncs.InterruptAdapter = SaInterruptAdapter;
++ AdapterExtension->Common->AdapterFuncs.EnableInterrupt = SaEnableInterrupt;
++ AdapterExtension->Common->AdapterFuncs.DisableInterrupt = SaDisableInterrupt;
++ AdapterExtension->Common->AdapterFuncs.NotifyAdapter = SaNotifyAdapter;
++ AdapterExtension->Common->AdapterFuncs.ResetDevice = SaResetDevice;
++ AdapterExtension->Common->AdapterFuncs.InterruptHost = NULL;
++
++ AdapterExtension->Common->AdapterFuncs.SendSynchFib = SaSendSynchFib;
++
++ NewAdapter.AdapterExtension = CommonExtension;
++ NewAdapter.AdapterFuncs = &AdapterExtension->Common->AdapterFuncs;
++ NewAdapter.AdapterInterruptsBelowDpc = FALSE;
++ NewAdapter.AdapterUserVars = SaUserVars;
++ NewAdapter.AdapterUserVarsSize = sizeof(SaUserVars) / sizeof(FSA_USER_VAR);
++
++ NewAdapter.Dip = CommonExtension->OsDep.dip;
++
++
++ if ( AfaCommInitNewAdapter( &NewAdapter ) == NULL) {
++ cmn_err(CE_WARN, "SaInitDevice: AfaCommInitNewAdapter failed\n");
++ return (FAILURE);
++ };
++
++
++ AdapterExtension->Common->Adapter = NewAdapter.Adapter;
++
++ if (AdapterExtension->Common->Adapter == NULL) {
++
++ AfaPortLogError(AdapterExtension->Common, FAILURE, NULL, 0);
++ cmn_err(CE_WARN, "%s%d SaInitDevice: No Adapter pointer", name, instance);
++
++ return (FAILURE);
++ }
++
++
++ //
++ // Start any kernel threads needed
++ OsStartKernelThreads(AdapterExtension);
++
++ //
++ // Tell the adapter that all is configure, and it can start accepting requests
++ //
++
++ SaStartAdapter(AdapterExtension);
++
++
++
++ //
++ // Put this adapter into the list of Sa adapters
++ //
++
++ AdapterExtension->Next = SaAdapterList;
++ SaAdapterList = AdapterExtension;
++
++ AdapterExtension->Common->AdapterConfigured = TRUE;
++
++
++#ifdef AACDISK
++ //
++ // Call the disk layer to initialize itself.
++ //
++
++ AfaDiskInitNewAdapter( AdapterExtension->Common->AdapterNumber, AdapterExtension->Common->Adapter );
++#endif
++
++
++init_done:
++
++ AdapterExtension->Common->AdapterPrintfsToScreen = FALSE;
++
++ OsAttachHBA(AdapterExtension);
++
++ return (0);
++
++init_error:
++
++ return (FAILURE);
++}
++
++
++
++VOID
++SaStartAdapter (PSa_ADAPTER_EXTENSION AdapterExtension)
++{
++ ULONG ReturnStatus;
++ LARGE_INTEGER HostTime;
++ ULONG ElapsedSeconds;
++ PADAPTER_INIT_STRUCT InitStruct;
++
++ //
++ // Fill in the remaining pieces of the InitStruct.
++ //
++
++ InitStruct = AdapterExtension->Common->InitStruct;
++
++ InitStruct->HostPhysMemPages = AfaPortGetMaxPhysicalPage(AdapterExtension->Common);
++
++ ElapsedSeconds = OsGetSeconds();
++
++ InitStruct->HostElapsedSeconds = ElapsedSeconds;
++
++ //
++ // Tell the adapter we are back and up and running so it will scan its command
++ // queues and enable our interrupts
++ //
++
++ AdapterExtension->LocalMaskInterruptControl =
++ (PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4);
++
++
++ //
++ // First clear out all interrupts. Then enable the one's that we can handle.
++ //
++
++ Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRISETIRQMASK, (USHORT) 0xffff );
++ Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRICLEARIRQMASK,
++ (PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4) );
++
++ SaSendSynchCommand(AdapterExtension,
++ INIT_STRUCT_BASE_ADDRESS,
++ (ULONG) AdapterExtension->Common->PhysicalInitStruct,
++ 0,
++ 0,
++ 0,
++ &ReturnStatus);
++
++}
++
++
++VOID
++SaResetDevice (PVOID Arg1){
++
++}
++
++
++/*++
++
++Routine Description:
++
++ The will cause the adapter to take a break point.
++
++Arguments:
++
++ None
++
++Return Value:
++
++ Nothing
++
++--*/
++VOID
++SaInterruptAdapter (PVOID Arg1)
++{
++ PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
++ PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) CommonExtension->MiniPort;
++
++ ULONG ReturnStatus;
++
++ SaSendSynchCommand(AdapterExtension,
++ BREAKPOINT_REQUEST,
++ 0,
++ 0,
++ 0,
++ 0,
++ &ReturnStatus);
++
++}
++
++
++/*++
++
++Routine Description:
++
++ Will read the adapter CSRs to find the reason the adapter has
++ interrupted us.
++
++Arguments:
++
++ AdapterEvent - Enumerated type the returns the reason why we were interrutped.
++
++Return Value:
++
++ Nothing
++
++--*/
++VOID
++SaNotifyAdapter (PVOID Arg1, IN HOST_2_ADAP_EVENT AdapterEvent)
++{
++ PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
++ PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) CommonExtension->MiniPort;
++ ULONG ReturnStatus;
++
++ switch (AdapterEvent) {
++ case AdapNormCmdQue:
++
++ Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_1);
++ break;
++
++ case HostNormRespNotFull:
++
++ Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_4);
++ break;
++
++ case AdapNormRespQue:
++
++ Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_2);
++ break;
++
++ case HostNormCmdNotFull:
++
++ Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_3);
++ break;
++
++ case HostShutdown:
++
++// SaSendSynchCommand(AdapterExtension, HOST_CRASHING, 0, 0, 0, 0, &ReturnStatus);
++
++ break;
++
++ case FastIo:
++ Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_6);
++ break;
++
++ case AdapPrintfDone:
++ Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_5);
++ break;
++
++ default:
++
++ SaBugCheck(0,0,0);
++ AfaPortPrint("Notify requested with an invalid request 0x%x.\n",AdapterEvent);
++ break;
++ }
++}
++
++
++/*++
++
++Routine Description:
++
++ This routine will send a synchronous comamnd to the adapter and wait for its
++ completion.
++
++Arguments:
++
++ AdapterExtension - Pointer to adapter extension structure.
++ Command - Which command to send
++ Parameter1 - 4 - Parameters for command
++ ReturnStatus - return status from adapter after completion of command
++
++
++Return Value:
++
++ AAC_STATUS
++
++--*/
++AAC_STATUS
++SaSendSynchCommand(
++ PVOID Arg1,
++ ULONG Command,
++ ULONG Parameter1,
++ ULONG Parameter2,
++ ULONG Parameter3,
++ ULONG Parameter4,
++ PULONG ReturnStatus
++ )
++{
++ PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) Arg1;
++ ULONG StartTime,EndTime,WaitTime;
++ BOOLEAN CommandSucceeded;
++
++ //
++ // Write the Command into Mailbox 0
++ //
++
++ Sa_WRITE_ULONG( AdapterExtension, Mailbox0, Command);
++
++ //
++ // Write the parameters into Mailboxes 1 - 4
++ //
++
++ Sa_WRITE_ULONG( AdapterExtension, Mailbox1, Parameter1);
++ Sa_WRITE_ULONG( AdapterExtension, Mailbox2, Parameter2);
++ Sa_WRITE_ULONG( AdapterExtension, Mailbox3, Parameter3);
++ Sa_WRITE_ULONG( AdapterExtension, Mailbox4, Parameter4);
++
++ //
++ // Clear the synch command doorbell to start on a clean slate.
++ //
++
++ Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p, DOORBELL_0);
++
++ //
++ // Signal that there is a new synch command
++ //
++
++ Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s, DOORBELL_0);
++
++ CommandSucceeded = FALSE;
++
++ StartTime = OsGetSeconds();
++ WaitTime = 0;
++
++ while (WaitTime < 30) { // wait up to 30 seconds
++
++ drv_usecwait(5); // delay 5 microseconds to let Mon960 get info.
++
++ //
++ // Mon110 will set doorbell0 bit when it has completed the command.
++ //
++
++ if( Sa_READ_USHORT( AdapterExtension, DoorbellReg_p) & DOORBELL_0 ) {
++
++ CommandSucceeded = TRUE;
++ break;
++ }
++
++ EndTime = OsGetSeconds();
++ WaitTime = EndTime - StartTime;
++
++ }
++
++ if (CommandSucceeded != TRUE) {
++
++ return (STATUS_IO_TIMEOUT);
++
++ }
++
++ //
++ // Clear the synch command doorbell.
++ //
++
++ Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p, DOORBELL_0);
++
++ //
++ // Pull the synch status from Mailbox 0.
++ //
++
++ *ReturnStatus = Sa_READ_ULONG( AdapterExtension, Mailbox0);
++
++ //
++ // Return SUCCESS
++ //
++
++ return (STATUS_SUCCESS);
++
++}
++
++
++/*++
++
++Routine Description:
++
++ This routine will send a synchronous fib to the adapter and wait for its
++ completion.
++
++Arguments:
++
++ AdapterExtension - Pointer to adapter extension structure.
++ FibPhysicalAddress - Physical address of fib to send.
++
++
++Return Value:
++
++ BOOLEAN
++
++--*/
++BOOLEAN
++SaSendSynchFib (PVOID Arg1, ULONG FibPhysicalAddress)
++{
++ PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1;
++ PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) CommonExtension->MiniPort;
++ ULONG returnStatus;
++
++ if (SaSendSynchCommand( AdapterExtension,
++ SEND_SYNCHRONOUS_FIB,
++ FibPhysicalAddress,
++ 0,
++ 0,
++ 0,
++ &returnStatus ) != STATUS_SUCCESS ) {
++
++ return (FALSE);
++
++ }
++
++ return (TRUE);
++
++}
++
++BOOLEAN
++WriteFlash(
++ PVOID AdapterExtension,
++ ULONG *MappedBuffer)
++{
++ return (FALSE);
++}
++
++BOOLEAN
++ReadFlash(
++ PVOID AdapterExtension,
++ ULONG *MappedBuffer)
++{
++ return (FALSE);
++}
++
+diff -burN linux-2.4.9/drivers/scsi/scsi_scan.c linux/drivers/scsi/scsi_scan.c
+--- linux-2.4.9/drivers/scsi/scsi_scan.c Thu Aug 16 13:40:31 2001
++++ linux/drivers/scsi/scsi_scan.c Thu Aug 16 18:10:10 2001
+@@ -160,6 +160,8 @@
+ {"SONY", "TSL", "*", BLIST_FORCELUN}, // DDS3 & DDS4 autoloaders
+ {"DELL", "PERCRAID", "*", BLIST_FORCELUN},
+ {"HP", "NetRAID-4M", "*", BLIST_FORCELUN},
++ {"ADAPTEC", "AACRAID", "*", BLIST_FORCELUN},
++ {"ADAPTEC", "Adaptec 5400S", "*", BLIST_FORCELUN},
+
+ /*
+ * Must be at end of list...