--- linux/drivers/scsi/Config.in.aacraid Wed May 3 20:16:44 2000 +++ linux/drivers/scsi/Config.in Tue Jun 13 12:52:42 2000 @@ -26,6 +26,7 @@ dep_tristate 'Adaptec AHA152X/2825 support' CONFIG_SCSI_AHA152X $CONFIG_SCSI dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI +dep_tristate 'Adaptec RAID Controller support' CONFIG_SCSI_AACRAID $CONFIG_SCSI dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then bool ' Enable Tagged Command Queueing (TCQ) by default' CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT --- linux/drivers/scsi/Makefile.aacraid Wed May 3 20:16:44 2000 +++ linux/drivers/scsi/Makefile Tue Jun 13 12:52:42 2000 @@ -346,6 +346,14 @@ endif endif +ifeq ($(CONFIG_SCSI_AACRAID),y) +L_OBJS += aacraid.o +else + ifeq ($(CONFIG_SCSI_AACRAID),m) + M_OBJS += aacraid.o + endif +endif + ifeq ($(CONFIG_SCSI_AIC7XXX),y) L_OBJS += aic7xxx.o else @@ -705,3 +713,6 @@ sd_mod.o: sd.o sd_ioctl.o $(LD) $(LD_RFLAG) -r -o $@ sd.o sd_ioctl.o + +aacraid.o: + cd aacraid; make --- linux/drivers/scsi/aacraid/Makefile.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/Makefile Tue Jun 13 12:52:42 2000 @@ -0,0 +1,170 @@ +# +# 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/usr/src/linux/include -I/usr/src/linux/drivers/scsi + +WARNINGS= -w -Wall -Wno-unused -Wno-switch -Wno-missing-prototypes -Wno-implicit + +COMMON_FLAGS=\ + -D__KERNEL__=1 -DUNIX -DCVLOCK_USE_SPINLOCK -DLINUX \ + -Wall -Wstrict-prototypes \ + ${INCS} \ + ${WARNINGS} \ + -O2 -fomit-frame-pointer + +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) $(CFLAGS) -c -o linit.o ./linit.c + +aachba.o: ./aachba.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o aachba.o ./aachba.c + +osddi.o: ./osddi.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o osddi.o ./osddi.c + +osfuncs.o: ./osfuncs.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o osfuncs.o ./osfuncs.c + +commctrl.o: ./commctrl.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o commctrl.o ./commctrl.c + +comminit.o: ./comminit.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o comminit.o ./comminit.c + +commsup.o: ./commsup.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o commsup.o ./commsup.c + +dpcsup.o: ./dpcsup.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o dpcsup.o ./dpcsup.c + +aacid.o: ./aacid.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o aacid.o ./aacid.c + +port.o: ./port.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o port.o ./port.c + +ossup.o: ./ossup.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o ossup.o ./ossup.c + +rx.o: ./rx.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o rx.o ./rx.c + +sap1sup.o: ./sap1sup.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o sap1sup.o ./sap1sup.c + + --- linux/drivers/scsi/aacraid/aachba.c.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/aachba.c Tue Jun 13 12:52:42 2000 @@ -0,0 +1,1855 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * aachba.c + * + * Abstract: driver... + * +--*/ +/*------------------------------------------------------------------------------ + * I N C L U D E S + *----------------------------------------------------------------------------*/ +#include "osheaders.h" +#include "AacGenericTypes.h" +#include "aac_unix_defs.h" +#include "comstruc.h" +#include "monkerapi.h" +#include "protocol.h" +#include "fsafs.h" +#include "fsact.h" +#include "fsaioctl.h" + +#include "sap1common.h" +#include "fsaport.h" +#include "pcisup.h" +#include "sap1.h" +#include "nodetype.h" +#include "comsup.h" +#include "afacomm.h" +#include "adapter.h" + +/*------------------------------------------------------------------------------ + * D E F I N E S + *----------------------------------------------------------------------------*/ +/* SCSI Commands */ +#define SS_TEST 0x00 /* Test unit ready */ +#define SS_REZERO 0x01 /* Rezero unit */ +#define SS_REQSEN 0x03 /* Request Sense */ +#define SS_REASGN 0x07 /* Reassign blocks */ +#define SS_READ 0x08 /* Read 6 */ +#define SS_WRITE 0x0A /* Write 6 */ +#define SS_INQUIR 0x12 /* inquiry */ +#define SS_ST_SP 0x1B /* Start/Stop unit */ +#define SS_LOCK 0x1E /* prevent/allow medium removal */ +#define SS_RESERV 0x16 /* Reserve */ +#define SS_RELES 0x17 /* Release */ +#define SS_MODESEN 0x1A /* Mode Sense 6 */ +#define SS_RDCAP 0x25 /* Read Capacity */ +#define SM_READ 0x28 /* Read 10 */ +#define SM_WRITE 0x2A /* Write 10 */ +#define SS_SEEK 0x2B /* Seek */ + +/* values for inqd_pdt: Peripheral device type in plain English */ +#define INQD_PDT_DA 0x00 /* Direct-access (DISK) device */ +#define INQD_PDT_PROC 0x03 /* Processor device */ +#define INQD_PDT_CHNGR 0x08 /* Changer (jukebox, scsi2) */ +#define INQD_PDT_COMM 0x09 /* Communication device (scsi2) */ +#define INQD_PDT_NOLUN2 0x1f /* Unknown Device (scsi2) */ +#define INQD_PDT_NOLUN 0x7f /* Logical Unit Not Present */ + +#define INQD_PDT_DMASK 0x1F /* Peripheral Device Type Mask */ +#define INQD_PDT_QMASK 0xE0 /* Peripheral Device Qualifer Mask */ + +#define TARGET_LUN_TO_CONTAINER(Target, Lun) (((Lun) << 4) | Target) +#define CONTAINER_TO_TARGET(Container) ((Container) & 0xf) +#define CONTAINER_TO_LUN(Container) ((Container) >> 4) + +#define MAX_FIB_DATA (sizeof(FIB) - sizeof(FIB_HEADER)) + +#define MAX_DRIVER_SG_SEGMENT_COUNT 17 + +// ------------------------------------------------------ +// Sense keys +// +#define SENKEY_NO_SENSE 0x00 // +#define SENKEY_UNDEFINED 0x01 // +#define SENKEY_NOT_READY 0x02 // +#define SENKEY_MEDIUM_ERR 0x03 // +#define SENKEY_HW_ERR 0x04 // +#define SENKEY_ILLEGAL 0x05 // +#define SENKEY_ATTENTION 0x06 // +#define SENKEY_PROTECTED 0x07 // +#define SENKEY_BLANK 0x08 // +#define SENKEY_V_UNIQUE 0x09 // +#define SENKEY_CPY_ABORT 0x0A // +#define SENKEY_ABORT 0x0B // +#define SENKEY_EQUAL 0x0C // +#define SENKEY_VOL_OVERFLOW 0x0D // +#define SENKEY_MISCOMP 0x0E // +#define SENKEY_RESERVED 0x0F // + +// ------------------------------------------------------ +// Sense codes +// +#define SENCODE_NO_SENSE 0x00 +#define SENCODE_END_OF_DATA 0x00 +#define SENCODE_BECOMING_READY 0x04 +#define SENCODE_INIT_CMD_REQUIRED 0x04 +#define SENCODE_PARAM_LIST_LENGTH_ERROR 0x1A +#define SENCODE_INVALID_COMMAND 0x20 +#define SENCODE_LBA_OUT_OF_RANGE 0x21 +#define SENCODE_INVALID_CDB_FIELD 0x24 +#define SENCODE_LUN_NOT_SUPPORTED 0x25 +#define SENCODE_INVALID_PARAM_FIELD 0x26 +#define SENCODE_PARAM_NOT_SUPPORTED 0x26 +#define SENCODE_PARAM_VALUE_INVALID 0x26 +#define SENCODE_RESET_OCCURRED 0x29 +#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x3E +#define SENCODE_INQUIRY_DATA_CHANGED 0x3F +#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x39 +#define SENCODE_DIAGNOSTIC_FAILURE 0x40 +#define SENCODE_INTERNAL_TARGET_FAILURE 0x44 +#define SENCODE_INVALID_MESSAGE_ERROR 0x49 +#define SENCODE_LUN_FAILED_SELF_CONFIG 0x4c +#define SENCODE_OVERLAPPED_COMMAND 0x4E + +// ------------------------------------------------------ +// Additional sense codes +// +#define ASENCODE_NO_SENSE 0x00 +#define ASENCODE_END_OF_DATA 0x05 +#define ASENCODE_BECOMING_READY 0x01 +#define ASENCODE_INIT_CMD_REQUIRED 0x02 +#define ASENCODE_PARAM_LIST_LENGTH_ERROR 0x00 +#define ASENCODE_INVALID_COMMAND 0x00 +#define ASENCODE_LBA_OUT_OF_RANGE 0x00 +#define ASENCODE_INVALID_CDB_FIELD 0x00 +#define ASENCODE_LUN_NOT_SUPPORTED 0x00 +#define ASENCODE_INVALID_PARAM_FIELD 0x00 +#define ASENCODE_PARAM_NOT_SUPPORTED 0x01 +#define ASENCODE_PARAM_VALUE_INVALID 0x02 +#define ASENCODE_RESET_OCCURRED 0x00 +#define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x00 +#define ASENCODE_INQUIRY_DATA_CHANGED 0x03 +#define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x00 +#define ASENCODE_DIAGNOSTIC_FAILURE 0x80 +#define ASENCODE_INTERNAL_TARGET_FAILURE 0x00 +#define ASENCODE_INVALID_MESSAGE_ERROR 0x00 +#define ASENCODE_LUN_FAILED_SELF_CONFIG 0x00 +#define ASENCODE_OVERLAPPED_COMMAND 0x00 + +#define BYTE0( x ) ( unsigned char )( x ) +#define BYTE1( x ) ( unsigned char )( x >> 8 ) +#define BYTE2( x ) ( unsigned char )( x >> 16 ) +#define BYTE3( x ) ( unsigned char )( x >> 24 ) + +/*------------------------------------------------------------------------------ + * S T R U C T S / T Y P E D E F S + *----------------------------------------------------------------------------*/ +/* SCSI inquiry data */ +struct inquiry_data { + unchar inqd_pdt; /* Peripheral qualifier | Peripheral Device Type */ + unchar inqd_dtq; /* RMB | Device Type Qualifier */ + unchar inqd_ver; /* ISO version | ECMA version | ANSI-approved version */ + unchar inqd_rdf; /* AENC | TrmIOP | Response data format */ + unchar inqd_len; /* Additional length (n-4) */ + unchar inqd_pad1[2]; /* Reserved - must be zero */ + unchar inqd_pad2; /* RelAdr | WBus32 | WBus16 | Sync | Linked |Reserved| CmdQue | SftRe */ + unchar inqd_vid[8]; /* Vendor ID */ + unchar inqd_pid[16]; /* Product ID */ + unchar inqd_prl[4]; /* Product Revision Level */ +}; + +struct sense_data { + unchar error_code; // 70h (current errors), 71h(deferred errors) + unchar valid:1; // A valid bit of one indicates that the information + // field contains valid information as defined in the + // SCSI-2 Standard. + + unchar segment_number; // Only used for COPY, COMPARE, or COPY AND VERIFY + // commands + + unchar sense_key:4; // Sense Key + unchar reserved:1; + unchar ILI:1; // Incorrect Length Indicator + unchar EOM:1; // End Of Medium - reserved for random access devices + unchar filemark:1; // Filemark - reserved for random access devices + + unchar information[4]; // for direct-access devices, contains the unsigned + // logical block address or residue associated with + // the sense key + unchar add_sense_len; // number of additional sense bytes to follow this field + unchar cmnd_info[4]; // not used + unchar ASC; // Additional Sense Code + unchar ASCQ; // Additional Sense Code Qualifier + unchar FRUC; // Field Replaceable Unit Code - not used + + unchar bit_ptr:3; // indicates which byte of the CDB or parameter data + // was in error + unchar BPV:1; // bit pointer valid (BPV): 1- indicates that + // the bit_ptr field has valid value + unchar reserved2:2; + unchar CD:1; // command data bit: 1- illegal parameter in CDB. + // 0- illegal parameter in data. + unchar SKSV:1; + + unchar field_ptr[2]; // byte of the CDB or parameter data in error +}; + +/*------------------------------------------------------------------------------ + * G L O B A L S + *----------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------ + * M O D U L E G L O B A L S + *----------------------------------------------------------------------------*/ +static fsadev_t *g_fsa_dev_array[8]; // SCSI Device Instance Pointers +static struct sense_data g_sense_data[MAXIMUM_NUM_CONTAINERS]; + +/*------------------------------------------------------------------------------ + * F U N C T I O N P R O T O T Y P E S + *----------------------------------------------------------------------------*/ +AAC_STATUS AacHba_OpenAdapter( PVOID AdapterArg); +AAC_STATUS AacHba_CloseAdapter( PVOID AdapterArg); +BOOLEAN AacHba_HandleAif( PVOID AdapterArg, PFIB_CONTEXT FibContext); +BOOLEAN AacHba_AdapterDeviceControl ( PVOID AdapterArg, + PAFA_IOCTL_CMD IoctlCmdPtr, int * ReturnStatus); + +void AacHba_CompleteScsi( + Scsi_Cmnd *scsi_cmnd_ptr ); + +void AacHba_CompleteScsiNoLock( + Scsi_Cmnd *scsi_cmnd_ptr ); + +static void AacHba_ReadCallback( + void *Context, + PFIB_CONTEXT FibContext, + int FibStatus ); + +static void AacHba_WriteCallback( + void *Context, + PFIB_CONTEXT FibContext, + int FibStatus ); + +int AacHba_DoScsiRead( + Scsi_Cmnd *scsi_cmnd_ptr, + int ContainerId, + int wait ); + +int AacHba_DoScsiWrite( + Scsi_Cmnd *scsi_cmnd_ptr, + int ContainerId, + int wait ); + +int AacHba_QueryDisk( + PVOID AdapterArg, // CommonExtensionPtr + IN PAFA_IOCTL_CMD IoctlCmdPtr ); + +int AacHba_ForceDeleteDisk( + PVOID AdapterArg, // CommonExtensionPtr + IN PAFA_IOCTL_CMD IoctlCmdPtr ); + +int AacHba_DeleteDisk( + PVOID AdapterArg, + IN PAFA_IOCTL_CMD IoctlCmdPtr ); + +void AacHba_DetachAdapter( + IN PVOID AdapterArg ); + +BOOLEAN AacCommDetachAdapter( + IN PAFA_COMM_ADAPTER Adapter ); + +void AacHba_SetSenseData( + char * sense_buf, + unchar sense_key, + unchar sense_code, + unchar a_sense_code, + unchar incorrect_length, + unchar bit_pointer, + unsigned field_pointer, + unsigned long residue ); + +static void get_sd_devname( + long disknum, + char * buffer); + +// Keep these here for the time being - #REVIEW# +int +AfaCommAdapterDeviceControl ( + IN PVOID AdapterArg, + IN PAFA_IOCTL_CMD IoctlCmdPtr + ); + +AAC_STATUS +AfaCommRegisterNewClassDriver( + IN PAFA_COMM_ADAPTER Adapter, + IN PAFA_NEW_CLASS_DRIVER NewClassDriver, + OUT PAFA_NEW_CLASS_DRIVER_RESPONSE NewClassDriverResponse + ); + +void +SetInqDataStr (int, void *, int); +/*------------------------------------------------------------------------------ + * F U N C T I O N S + *----------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------ + AacHba_ClassDriverInit() + + Setup 'core' class driver to answer ioctl's + *----------------------------------------------------------------------------*/ +int AacHba_ClassDriverInit( + PCI_MINIPORT_COMMON_EXTENSION * CommonExtensionPtr) +/*----------------------------------------------------------------------------*/ +{ + AFA_NEW_CLASS_DRIVER NewClassDriver; + AFA_NEW_CLASS_DRIVER_RESPONSE NewClassDriverResponse; + PAFA_COMM_ADAPTER Adapter; + + Adapter = (AFA_COMM_ADAPTER *)CommonExtensionPtr->Adapter; + + RtlZeroMemory( &NewClassDriver, sizeof( AFA_NEW_CLASS_DRIVER ) ); + + // ClassDriverExtension is the first argument passed to class driver functions below + NewClassDriver.ClassDriverExtension = CommonExtensionPtr; + + NewClassDriver.OpenAdapter = AacHba_OpenAdapter; + NewClassDriver.CloseAdapter = AacHba_CloseAdapter; + NewClassDriver.DeviceControl = AacHba_AdapterDeviceControl; + NewClassDriver.HandleAif = AacHba_HandleAif; + AfaCommRegisterNewClassDriver( Adapter, &NewClassDriver, &NewClassDriverResponse ); + + return(0); +} + + +/*------------------------------------------------------------------------------ + AacHba_ProbeContainers() + + Make a list of all containers in the system. + *----------------------------------------------------------------------------*/ +int AacHba_ProbeContainers( + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr ) +/*----------------------------------------------------------------------------*/ +{ + fsadev_t *fsa_dev_ptr; + int Index, Status; + PMNTINFO DiskInfo; + PMNTINFORESPONSE DiskInfoResponse; + PFIB_CONTEXT FibContext; + AFA_COMM_ADAPTER *Adapter; + unsigned instance; + + Adapter = ( AFA_COMM_ADAPTER * )CommonExtensionPtr->Adapter; + fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev ); + instance = CommonExtensionPtr->OsDep.scsi_host_ptr->unique_id; + + if( !( FibContext = Adapter->CommFuncs.AllocateFib( Adapter ) ) ) + { + cmn_err( CE_WARN, "AacHba_ProbeContainers: AllocateFib failed" ); + return( STATUS_UNSUCCESSFUL ); + } + + for ( Index = 0; Index < MAXIMUM_NUM_CONTAINERS; Index++ ) + { + Adapter->CommFuncs.InitializeFib( FibContext ); + + DiskInfo = ( PMNTINFO )Adapter->CommFuncs.GetFibData( FibContext ); + + DiskInfo->Command = VM_NameServe; + DiskInfo->MntCount = Index; + DiskInfo->MntType = FT_FILESYS; + + Status = Adapter->CommFuncs.SendFib( ContainerCommand, + FibContext, + sizeof(MNTINFO), + FsaNormal, + TRUE, + NULL, + TRUE, + NULL, + NULL ); + if ( Status ) + { + cmn_err( CE_WARN, "ProbeContainers: SendFIb Failed" ); + break; + } + + DiskInfoResponse = ( PMNTINFORESPONSE )Adapter->CommFuncs.GetFibData( FibContext ); + + + if ( ( DiskInfoResponse->Status == ST_OK ) && + ( DiskInfoResponse->MntTable[0].VolType != CT_NONE ) ) + { + + + fsa_dev_ptr->ContainerValid[Index] = TRUE; + fsa_dev_ptr->ContainerType[Index] = DiskInfoResponse->MntTable[0].VolType; + fsa_dev_ptr->ContainerSize[Index] = DiskInfoResponse->MntTable[0].Capacity; + + if (DiskInfoResponse->MntTable[0].ContentState & FSCS_READONLY) + fsa_dev_ptr->ContainerReadOnly[Index] = TRUE; + } + + Adapter->CommFuncs.CompleteFib( FibContext ); + + // If there are no more containers, then stop asking. + if ((Index + 1) >= DiskInfoResponse->MntRespCount) + break; + } // end for() + + Adapter->CommFuncs.FreeFib( FibContext ); + + g_fsa_dev_array[instance] = fsa_dev_ptr; + + return( Status ); +} + + +/*------------------------------------------------------------------------------ + AacHba_ProbeContainer() + + Probe a single container. + *----------------------------------------------------------------------------*/ +int AacHba_ProbeContainer( + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr, + int ContainerId ) +/*----------------------------------------------------------------------------*/ +{ + fsadev_t *fsa_dev_ptr; + int Status; + PMNTINFO DiskInfo; + PMNTINFORESPONSE DiskInfoResponse; + PFIB_CONTEXT FibContext; + AFA_COMM_ADAPTER *Adapter; + unsigned instance; + + Adapter = ( AFA_COMM_ADAPTER * )CommonExtensionPtr->Adapter; + fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev ); + instance = CommonExtensionPtr->OsDep.scsi_host_ptr->unique_id; + + if( !( FibContext = Adapter->CommFuncs.AllocateFib( Adapter ) ) ) + { + cmn_err( CE_WARN, "AacHba_ProbeContainers: AllocateFib failed" ); + return( STATUS_UNSUCCESSFUL ); + } + + Adapter->CommFuncs.InitializeFib( FibContext ); + + DiskInfo = ( PMNTINFO )Adapter->CommFuncs.GetFibData( FibContext ); + + DiskInfo->Command = VM_NameServe; + DiskInfo->MntCount = ContainerId; + DiskInfo->MntType = FT_FILESYS; + + Status = Adapter->CommFuncs.SendFib( ContainerCommand, + FibContext, + sizeof(MNTINFO), + FsaNormal, + TRUE, + NULL, + TRUE, + NULL, + NULL ); + if ( Status ) + { + cmn_err( CE_WARN, "ProbeContainers: SendFIb Failed" ); + Adapter->CommFuncs.CompleteFib( FibContext ); + Adapter->CommFuncs.FreeFib( FibContext ); + return( Status ); + } + + DiskInfoResponse = ( PMNTINFORESPONSE )Adapter->CommFuncs.GetFibData( FibContext ); + + + if ( ( DiskInfoResponse->Status == ST_OK ) && + ( DiskInfoResponse->MntTable[0].VolType != CT_NONE ) ) + { + + fsa_dev_ptr->ContainerValid[ContainerId] = TRUE; + fsa_dev_ptr->ContainerType[ContainerId] = DiskInfoResponse->MntTable[0].VolType; + fsa_dev_ptr->ContainerSize[ContainerId] = DiskInfoResponse->MntTable[0].Capacity; + if (DiskInfoResponse->MntTable[0].ContentState & FSCS_READONLY) + fsa_dev_ptr->ContainerReadOnly[ContainerId] = TRUE; + } + + Adapter->CommFuncs.CompleteFib( FibContext ); + Adapter->CommFuncs.FreeFib( FibContext ); + + return( Status ); +} + + +/*------------------------------------------------------------------------------ + AacHba_CompleteScsi() + + Call SCSI completion routine after acquiring io_request_lock + + Preconditions: + Postconditions: + *----------------------------------------------------------------------------*/ +void AacHba_CompleteScsi( + Scsi_Cmnd *scsi_cmnd_ptr ) +{ + unsigned long cpu_flags; + + spin_lock_irqsave( &io_request_lock, cpu_flags ); + scsi_cmnd_ptr->scsi_done( scsi_cmnd_ptr ); + spin_unlock_irqrestore( &io_request_lock, cpu_flags ); +} + + +/*------------------------------------------------------------------------------ + AacHba_CompleteScsiNoLock() + + Call SCSI completion routine + + Preconditions: + Postconditions: + *----------------------------------------------------------------------------*/ +void AacHba_CompleteScsiNoLock( + Scsi_Cmnd *scsi_cmnd_ptr ) +{ + scsi_cmnd_ptr->scsi_done( scsi_cmnd_ptr ); +} + +/*------------------------------------------------------------------------------ + AacHba_DoScsiCmd() + + Process SCSI command + + Preconditions: + Postconditions: + Returns 0 on success, -1 on failure + *----------------------------------------------------------------------------*/ +int AacHba_DoScsiCmd( + Scsi_Cmnd *scsi_cmnd_ptr, + int wait ) +/*----------------------------------------------------------------------------*/ +{ + int ContainerId = 0; + fsadev_t *fsa_dev_ptr; + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr; + int MiniPortIndex; + + CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata ); + MiniPortIndex = CommonExtensionPtr->OsDep.MiniPortIndex; + + fsa_dev_ptr = g_fsa_dev_array[ scsi_cmnd_ptr->host->unique_id ]; + + // If the bus, target or lun is out of range, return fail + // Test does not apply to ID 16, the pseudo id for the controller itself. + if ( scsi_cmnd_ptr->target != scsi_cmnd_ptr->host->this_id ) + { + if( ( scsi_cmnd_ptr->channel > 0 ) || + ( scsi_cmnd_ptr->target > 15 ) || + ( scsi_cmnd_ptr->lun > 7 ) ) + { + cmn_err( CE_DEBUG, "The bus, target or lun is out of range = %d, %d, %d", + scsi_cmnd_ptr->channel, + scsi_cmnd_ptr->target, + scsi_cmnd_ptr->lun ); + scsi_cmnd_ptr->result = DID_BAD_TARGET << 16; + + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + + return ( -1 ); + } + + ContainerId = TARGET_LUN_TO_CONTAINER( scsi_cmnd_ptr->target, scsi_cmnd_ptr->lun ); + + + // If the target container doesn't exist, it may have been newly created + if( fsa_dev_ptr->ContainerValid[ContainerId] == 0 ) + { + switch( scsi_cmnd_ptr->cmnd[0] ) + { + case SS_INQUIR: + case SS_RDCAP: + case SS_TEST: + spin_unlock_irq( &io_request_lock ); + AacHba_ProbeContainer( CommonExtensionPtr, ContainerId ); + spin_lock_irq( &io_request_lock ); + default: + break; + } + } + + // If the target container still doesn't exist, return failure + if( fsa_dev_ptr->ContainerValid[ContainerId] == 0 ) + { + cmn_err( CE_DEBUG, "Target container %d doesn't exist", ContainerId ); + scsi_cmnd_ptr->result = DID_BAD_TARGET << 16; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + + return ( -1 ); + } + } + else // the command is for the controller itself + if( ( scsi_cmnd_ptr->cmnd[0] != SS_INQUIR ) && // only INQUIRY & TUR cmnd supported for controller + ( scsi_cmnd_ptr->cmnd[0] != SS_TEST ) ) + { + cmn_err( CE_WARN, "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x", + scsi_cmnd_ptr->cmnd[0] ); + + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + + AacHba_SetSenseData( (char *)&g_sense_data[ ContainerId ], + SENKEY_ILLEGAL, SENCODE_INVALID_COMMAND, ASENCODE_INVALID_COMMAND, + 0, 0, 0, 0 ); + + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + + return ( -1 ); + } + + // Handle commands here that don't really require going out to the adapter + switch ( scsi_cmnd_ptr->cmnd[0] ) + { + case SS_INQUIR: + { + struct inquiry_data *inq_data_ptr; + + cmn_err( CE_DEBUG, "INQUIRY command, ID: %d", scsi_cmnd_ptr->target ); + inq_data_ptr = ( struct inquiry_data * )scsi_cmnd_ptr->request_buffer; + bzero( inq_data_ptr, sizeof( struct inquiry_data ) ); + + inq_data_ptr->inqd_ver = 2; // claim compliance to SCSI-2 + + inq_data_ptr->inqd_dtq = 0x80; // set RMB bit to one indicating + // that the medium is removable + inq_data_ptr->inqd_rdf = 2; // A response data format value of + // two indicates that the data shall + // be in the format specified in SCSI-2 + inq_data_ptr->inqd_len = 31; + + // Set the Vendor, Product, and Revision Level see: .c i.e. aac.c + SetInqDataStr( MiniPortIndex, + (void *)(inq_data_ptr->inqd_vid), + fsa_dev_ptr->ContainerType[ContainerId]); + + if ( scsi_cmnd_ptr->target == scsi_cmnd_ptr->host->this_id ) + inq_data_ptr->inqd_pdt = INQD_PDT_PROC; // Processor device + else + inq_data_ptr->inqd_pdt = INQD_PDT_DA; // Direct/random access device + + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + + return ( 0 ); + } + + case SS_RDCAP: + { + int capacity; + char *cp; + + cmn_err( CE_DEBUG, "READ CAPACITY command" ); + capacity = fsa_dev_ptr->ContainerSize[ContainerId]; + cp = scsi_cmnd_ptr->request_buffer; + cp[0] = ( capacity >> 24 ) & 0xff; + cp[1] = ( capacity >> 16 ) & 0xff; + cp[2] = ( capacity >> 8 ) & 0xff; + cp[3] = ( capacity >> 0 ) & 0xff; + cp[4] = 0; + cp[5] = 0; + cp[6] = 2; + cp[7] = 0; + + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + + return ( 0 ); + } + + case SS_MODESEN: + { + char *mode_buf; + + cmn_err( CE_DEBUG, "MODE SENSE command" ); + mode_buf = scsi_cmnd_ptr->request_buffer; + mode_buf[0] = 0; // Mode data length (MSB) + mode_buf[1] = 6; // Mode data length (LSB) + mode_buf[2] = 0; // Medium type - default + mode_buf[3] = 0; // Device-specific param, bit 8: 0/1 = write enabled/protected + mode_buf[4] = 0; // reserved + mode_buf[5] = 0; // reserved + mode_buf[6] = 0; // Block descriptor length (MSB) + mode_buf[7] = 0; // Block descriptor length (LSB) + + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + + return ( 0 ); + } + + + // These commands are all No-Ops + case SS_TEST: + cmn_err( CE_DEBUG, "TEST UNIT READY command" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_REQSEN: + cmn_err( CE_DEBUG, "REQUEST SENSE command" ); + + memcpy( scsi_cmnd_ptr->sense_buffer, &g_sense_data[ContainerId], + sizeof( struct sense_data ) ); + bzero( &g_sense_data[ContainerId], sizeof( struct sense_data ) ); + + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_LOCK: + cmn_err(CE_DEBUG, "LOCK command"); + + if( scsi_cmnd_ptr->cmnd[4] ) + fsa_dev_ptr->ContainerLocked[ContainerId] = 1; + else + fsa_dev_ptr->ContainerLocked[ContainerId] = 0; + + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_RESERV: + cmn_err( CE_DEBUG, "RESERVE command" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_RELES: + cmn_err( CE_DEBUG, "RELEASE command" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_REZERO: + cmn_err( CE_DEBUG, "REZERO command" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_REASGN: + cmn_err( CE_DEBUG, "REASSIGN command" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_SEEK: + cmn_err( CE_DEBUG, "SEEK command" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_ST_SP: + cmn_err( CE_DEBUG, "START/STOP command" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + } + + switch ( scsi_cmnd_ptr->cmnd[0] ) + { + case SS_READ: + case SM_READ: + // Hack to keep track of ordinal number of the device that corresponds + // to a container. Needed to convert containers to /dev/sd device names + fsa_dev_ptr->ContainerDevNo[ContainerId] = + DEVICE_NR( scsi_cmnd_ptr->request.rq_dev ); + + return( AacHba_DoScsiRead( scsi_cmnd_ptr, ContainerId, wait ) ); + break; + + case SS_WRITE: + case SM_WRITE: + return( AacHba_DoScsiWrite( scsi_cmnd_ptr, ContainerId, wait ) ); + break; + } + // + // Unhandled commands + // + cmn_err( CE_WARN, "Unhandled SCSI Command: 0x%x", scsi_cmnd_ptr->cmnd[0] ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_ILLEGAL, SENCODE_INVALID_COMMAND, ASENCODE_INVALID_COMMAND, + 0, 0, 0, 0 ); + + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( -1 ); +} + + +/*------------------------------------------------------------------------------ + AacHba_DoScsiRead() + + Handles SCSI READ requests + + Preconditions: + Postconditions: + Returns 0 on success, -1 on failure + *----------------------------------------------------------------------------*/ +int AacHba_DoScsiRead( + Scsi_Cmnd *scsi_cmnd_ptr, + int ContainerId, + int wait ) +/*----------------------------------------------------------------------------*/ +{ + u_long lba; + u_long count; + u_long byte_count; + int Status; + + PBLOCKREAD BlockReadDisk; + PBLOCKREADRESPONSE BlockReadResponse; + uint16_t FibSize; + PCI_MINIPORT_COMMON_EXTENSION *CommonExtension; + AFA_COMM_ADAPTER *Adapter; + PFIB_CONTEXT cmd_fibcontext; + + CommonExtension = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata ); + Adapter = ( AFA_COMM_ADAPTER * )CommonExtension->Adapter; + + // Get block address and transfer length + if ( scsi_cmnd_ptr->cmnd[0] == SS_READ ) // 6 byte command + { + cmn_err( CE_DEBUG, "aachba: received a read(6) command on target %d", ContainerId ); + + lba = ( ( scsi_cmnd_ptr->cmnd[1] & 0x1F ) << 16 ) | + ( scsi_cmnd_ptr->cmnd[2] << 8 ) | + scsi_cmnd_ptr->cmnd[3]; + count = scsi_cmnd_ptr->cmnd[4]; + + if ( count == 0 ) + count = 256; + } + else + { + cmn_err( CE_DEBUG, "aachba: received a read(10) command on target %d", ContainerId ); + + lba = ( scsi_cmnd_ptr->cmnd[2] << 24 ) | ( scsi_cmnd_ptr->cmnd[3] << 16 ) | + ( scsi_cmnd_ptr->cmnd[4] << 8 ) | scsi_cmnd_ptr->cmnd[5]; + + count = ( scsi_cmnd_ptr->cmnd[7] << 8 ) | scsi_cmnd_ptr->cmnd[8]; + } + cmn_err( CE_DEBUG, "AacHba_DoScsiRead[cpu %d]: lba = %lu, t = %ld", smp_processor_id(), lba, jiffies ); + + //------------------------------------------------------------------------- + // Alocate and initialize a Fib + // Setup BlockRead command + if( !( cmd_fibcontext = Adapter->CommFuncs.AllocateFib( Adapter ) ) ) + { + cmn_err( CE_WARN, "AacHba_DoScsiRead: AllocateFib failed\n" ); + scsi_cmnd_ptr->result = DID_ERROR << 16; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( -1 ); + } + + Adapter->CommFuncs.InitializeFib( cmd_fibcontext ); + + BlockReadDisk = ( PBLOCKREAD )Adapter->CommFuncs.GetFibData( cmd_fibcontext ); + BlockReadDisk->Command = VM_CtBlockRead; + BlockReadDisk->ContainerId = ContainerId; + BlockReadDisk->BlockNumber = lba; + BlockReadDisk->ByteCount = count * 512; + BlockReadDisk->SgMap.SgCount = 1; + + if( BlockReadDisk->ByteCount > ( 64 * 1024 ) ) + { + cmn_err( CE_WARN, "AacHba_DoScsiRead: READ request is larger than 64K" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_ILLEGAL, SENCODE_INVALID_CDB_FIELD, ASENCODE_INVALID_CDB_FIELD, + 0, 0, 7, 0 ); + + goto err_return; + } + + //------------------------------------------------------------------------- + // Build Scatter/Gather list + // + if ( scsi_cmnd_ptr->use_sg ) // use scatter/gather list + { + struct scatterlist *scatterlist_ptr; + int segment; + + scatterlist_ptr = ( struct scatterlist * )scsi_cmnd_ptr->request_buffer; + + byte_count = 0; + for( segment = 0; segment< scsi_cmnd_ptr->use_sg; segment++ ) + { + BlockReadDisk->SgMap.SgEntry[segment].SgAddress = + ( void * )OsVirtToPhys( scatterlist_ptr[segment].address ); + BlockReadDisk->SgMap.SgEntry[segment].SgByteCount = + scatterlist_ptr[segment].length; + +#ifdef DEBUG_SGBUFFER + memset( scatterlist_ptr[segment].address, 0xa5, + scatterlist_ptr[segment].length ); +#endif + + byte_count += scatterlist_ptr[segment].length; + + if( BlockReadDisk->SgMap.SgEntry[segment].SgByteCount > ( 64 * 1024 ) ) + { + cmn_err( CE_WARN, "AacHba_DoScsiRead: Segment byte count is larger than 64K" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_ILLEGAL, SENCODE_INVALID_CDB_FIELD, ASENCODE_INVALID_CDB_FIELD, + 0, 0, 7, 0 ); + + goto err_return; + } + /* + cmn_err(CE_DEBUG, "SgEntry[%d].SgAddress = 0x%x, Byte count = 0x%x", + segment, + BlockReadDisk->SgMap.SgEntry[segment].SgAddress, + BlockReadDisk->SgMap.SgEntry[segment].SgByteCount); + */ + } + BlockReadDisk->SgMap.SgCount = scsi_cmnd_ptr->use_sg; + + if( BlockReadDisk->SgMap.SgCount > MAX_DRIVER_SG_SEGMENT_COUNT ) + { + cmn_err( CE_WARN, "AacHba_DoScsiRead: READ request with SgCount > %d", + MAX_DRIVER_SG_SEGMENT_COUNT ); + scsi_cmnd_ptr->result = DID_ERROR << 16; + goto err_return; + } + } + else // one piece of contiguous phys mem + { + BlockReadDisk->SgMap.SgEntry[0].SgAddress = + ( void * )OsVirtToPhys( scsi_cmnd_ptr->request_buffer ); + BlockReadDisk->SgMap.SgEntry[0].SgByteCount = scsi_cmnd_ptr->request_bufflen; + + byte_count = scsi_cmnd_ptr->request_bufflen; + + if( BlockReadDisk->SgMap.SgEntry[0].SgByteCount > ( 64 * 1024 ) ) + { + cmn_err( CE_WARN, "AacHba_DoScsiRead: Single segment byte count is larger than 64K" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_ILLEGAL, SENCODE_INVALID_CDB_FIELD, ASENCODE_INVALID_CDB_FIELD, + 0, 0, 7, 0 ); + + goto err_return; + } + } + + if( byte_count != BlockReadDisk->ByteCount ) + cmn_err( CE_WARN, "AacHba_DoScsiRead: byte_count != BlockReadDisk->ByteCount" ); + + //------------------------------------------------------------------------- + // Now send the Fib to the adapter + // + FibSize = sizeof( BLOCKREAD ) + ( ( BlockReadDisk->SgMap.SgCount - 1 ) * sizeof( SGENTRY ) ); + + if( wait ) + { + Status = Adapter->CommFuncs.SendFib( ContainerCommand, + cmd_fibcontext, + FibSize, + FsaNormal, + TRUE, + NULL, + TRUE, + NULL, + NULL); + + BlockReadResponse = ( PBLOCKREADRESPONSE ) + Adapter->CommFuncs.GetFibData( cmd_fibcontext ); + + Adapter->CommFuncs.CompleteFib( cmd_fibcontext ); + Adapter->CommFuncs.FreeFib( cmd_fibcontext ); + + if( BlockReadResponse->Status != ST_OK ) + { + cmn_err( CE_WARN, "AacHba_DoScsiRead: BlockReadCommand failed with status: %d", + BlockReadResponse->Status ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_HW_ERR, SENCODE_INTERNAL_TARGET_FAILURE, ASENCODE_INTERNAL_TARGET_FAILURE, + 0, 0, 0, 0 ); + + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( -1 ); + } + else + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + } + else + { + Status = Adapter->CommFuncs.SendFib( ContainerCommand, + cmd_fibcontext, + FibSize, + FsaNormal, + FALSE, + NULL, + TRUE, + ( PFIB_CALLBACK )AacHba_ReadCallback, + ( void *)scsi_cmnd_ptr ); + // don't call done func here + return ( 0 ); + } + +err_return: + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + + Adapter->CommFuncs.CompleteFib( cmd_fibcontext ); + Adapter->CommFuncs.FreeFib( cmd_fibcontext ); + + return ( -1 ); +} + + +/*------------------------------------------------------------------------------ + AacHba_DoScsiWrite() + + Handles SCSI WRITE requests + + Preconditions: + Postconditions: + Returns 0 on success, -1 on failure + *----------------------------------------------------------------------------*/ +int AacHba_DoScsiWrite( + Scsi_Cmnd *scsi_cmnd_ptr, + int ContainerId, + int wait ) +/*----------------------------------------------------------------------------*/ +{ + u_long lba; + u_long count; + u_long byte_count; + int Status; + + PBLOCKWRITE BlockWriteDisk; + PBLOCKWRITERESPONSE BlockWriteResponse; + uint16_t FibSize; + PCI_MINIPORT_COMMON_EXTENSION *CommonExtension; + AFA_COMM_ADAPTER *Adapter; + PFIB_CONTEXT cmd_fibcontext; + + CommonExtension = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata ); + Adapter = ( AFA_COMM_ADAPTER * )CommonExtension->Adapter; + + // Get block address and transfer length + if ( scsi_cmnd_ptr->cmnd[0] == SS_WRITE ) // 6 byte command + { + lba = ( ( scsi_cmnd_ptr->cmnd[1] & 0x1F ) << 16 ) | + ( scsi_cmnd_ptr->cmnd[2] << 8 ) | + scsi_cmnd_ptr->cmnd[3]; + count = scsi_cmnd_ptr->cmnd[4]; + + + if ( count == 0 ) + count = 256; + } + else + { + cmn_err( CE_DEBUG, "aachba: received a write(10) command on target %d", ContainerId ); + + lba = ( scsi_cmnd_ptr->cmnd[2] << 24 ) | ( scsi_cmnd_ptr->cmnd[3] << 16 ) | + ( scsi_cmnd_ptr->cmnd[4] << 8 ) | scsi_cmnd_ptr->cmnd[5]; + + count = ( scsi_cmnd_ptr->cmnd[7] << 8 ) | scsi_cmnd_ptr->cmnd[8]; + } + cmn_err( CE_DEBUG, "AacHba_DoScsiWrite[cpu %d]: lba = %lu, t = %ld", smp_processor_id(), lba, jiffies ); + + //------------------------------------------------------------------------- + // Alocate and initialize a Fib + // Setup BlockWrite command + if( !( cmd_fibcontext = Adapter->CommFuncs.AllocateFib( Adapter ) ) ) + { + cmn_err( CE_WARN, "AacHba_DoScsiWrite: AllocateFib failed\n" ); + scsi_cmnd_ptr->result = DID_ERROR << 16; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( -1 ); + } + + Adapter->CommFuncs.InitializeFib( cmd_fibcontext ); + + BlockWriteDisk = (PBLOCKWRITE) Adapter->CommFuncs.GetFibData( cmd_fibcontext ); + BlockWriteDisk->Command = VM_CtBlockWrite; + BlockWriteDisk->ContainerId = ContainerId; + BlockWriteDisk->BlockNumber = lba; + BlockWriteDisk->ByteCount = count * 512; + BlockWriteDisk->SgMap.SgCount = 1; + + if ( BlockWriteDisk->ByteCount > ( 64 * 1024 ) ) + { + cmn_err( CE_WARN, "AacHba_DoScsiWrite: WRITE request is larger than 64K" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_ILLEGAL, SENCODE_INVALID_CDB_FIELD, ASENCODE_INVALID_CDB_FIELD, + 0, 0, 7, 0 ); + + goto err_return; + } + + //------------------------------------------------------------------------- + // Build Scatter/Gather list + // + if ( scsi_cmnd_ptr->use_sg ) // use scatter/gather list + { + struct scatterlist *scatterlist_ptr; + int segment; + + scatterlist_ptr = ( struct scatterlist * )scsi_cmnd_ptr->request_buffer; + + byte_count = 0; + for( segment = 0; segment< scsi_cmnd_ptr->use_sg; segment++ ) + { + BlockWriteDisk->SgMap.SgEntry[segment].SgAddress = + ( HOSTADDRESS )OsVirtToPhys( scatterlist_ptr[segment].address ); + BlockWriteDisk->SgMap.SgEntry[segment].SgByteCount = + scatterlist_ptr[segment].length; + + byte_count += scatterlist_ptr[segment].length; + + if ( BlockWriteDisk->SgMap.SgEntry[segment].SgByteCount > ( 64 * 1024 ) ) + { + cmn_err( CE_WARN, "AacHba_DoScsiWrite: Segment byte count is larger than 64K" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_ILLEGAL, SENCODE_INVALID_CDB_FIELD, ASENCODE_INVALID_CDB_FIELD, + 0, 0, 7, 0 ); + + goto err_return; + } + + /* + cmn_err(CE_DEBUG, "SgEntry[%d].SgAddress = 0x%x, Byte count = 0x%x", + segment, + BlockWriteDisk->SgMap.SgEntry[segment].SgAddress, + BlockWriteDisk->SgMap.SgEntry[segment].SgByteCount); + */ + } + BlockWriteDisk->SgMap.SgCount = scsi_cmnd_ptr->use_sg; + + if( BlockWriteDisk->SgMap.SgCount > MAX_DRIVER_SG_SEGMENT_COUNT ) + { + cmn_err( CE_WARN, "AacHba_DoScsiWrite: WRITE request with SgCount > %d", + MAX_DRIVER_SG_SEGMENT_COUNT ); + scsi_cmnd_ptr->result = DID_ERROR << 16; + goto err_return; + } + } + else // one piece of contiguous phys mem + { + BlockWriteDisk->SgMap.SgEntry[0].SgAddress = + ( HOSTADDRESS )OsVirtToPhys( scsi_cmnd_ptr->request_buffer ); + BlockWriteDisk->SgMap.SgEntry[0].SgByteCount = scsi_cmnd_ptr->request_bufflen; + + byte_count = scsi_cmnd_ptr->request_bufflen; + + if ( BlockWriteDisk->SgMap.SgEntry[0].SgByteCount > ( 64 * 1024 ) ) + { + cmn_err( CE_WARN, "AacHba_DoScsiWrite: Single segment byte count is larger than 64K" ); + + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_ILLEGAL, SENCODE_INVALID_CDB_FIELD, ASENCODE_INVALID_CDB_FIELD, + 0, 0, 7, 0 ); + + goto err_return; + } + } + + if( byte_count != BlockWriteDisk->ByteCount ) + cmn_err( CE_WARN, "AacHba_DoScsiWrite: byte_count != BlockReadDisk->ByteCount" ); + + //------------------------------------------------------------------------- + // Now send the Fib to the adapter + // + FibSize = sizeof( BLOCKWRITE ) + ( ( BlockWriteDisk->SgMap.SgCount - 1 ) * sizeof( SGENTRY ) ); + + if( wait ) + { + Status = Adapter->CommFuncs.SendFib( ContainerCommand, + cmd_fibcontext, + FibSize, + FsaNormal, + TRUE, + NULL, + TRUE, + NULL, + NULL ); + + BlockWriteResponse = ( PBLOCKWRITERESPONSE ) + Adapter->CommFuncs.GetFibData( cmd_fibcontext ); + + Adapter->CommFuncs.CompleteFib( cmd_fibcontext ); + Adapter->CommFuncs.FreeFib( cmd_fibcontext ); + + if( BlockWriteResponse->Status != ST_OK ) + { + cmn_err( CE_WARN, "AacHba_DoScsiWrite: BlockWriteCommand failed with status: %d\n", + BlockWriteResponse->Status ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;; + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_HW_ERR, SENCODE_INTERNAL_TARGET_FAILURE, ASENCODE_INTERNAL_TARGET_FAILURE, + 0, 0, 0, 0 ); + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( -1 ); + } + else + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + } + else + { + Status = Adapter->CommFuncs.SendFib( ContainerCommand, + cmd_fibcontext, + FibSize, + FsaNormal, + FALSE, + NULL, + TRUE, + ( PFIB_CALLBACK )AacHba_WriteCallback, + ( void * )scsi_cmnd_ptr ); + + // don't call done func here - it should be called by the WriteCallback + return ( 0 ); + } + +err_return: + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + + Adapter->CommFuncs.CompleteFib( cmd_fibcontext ); + Adapter->CommFuncs.FreeFib( cmd_fibcontext ); + + return ( -1 ); +} + + +/*------------------------------------------------------------------------------ + AacHba_ReadCallback() + *----------------------------------------------------------------------------*/ +void AacHba_ReadCallback( + VOID *Context, + PFIB_CONTEXT FibContext, + int FibStatus ) +/*----------------------------------------------------------------------------*/ +{ + PCI_MINIPORT_COMMON_EXTENSION *CommonExtension; + AFA_COMM_ADAPTER *Adapter; + BLOCKREADRESPONSE *BlockReadResponse; + Scsi_Cmnd * scsi_cmnd_ptr; + u_long lba; + int ContainerId; + + scsi_cmnd_ptr = ( Scsi_Cmnd * )Context; + + CommonExtension = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata ); + Adapter = ( AFA_COMM_ADAPTER * )CommonExtension->Adapter; + + ContainerId = TARGET_LUN_TO_CONTAINER( scsi_cmnd_ptr->target, scsi_cmnd_ptr->lun ); + + lba = ( ( scsi_cmnd_ptr->cmnd[1] & 0x1F ) << 16 ) | + ( scsi_cmnd_ptr->cmnd[2] << 8 ) | + scsi_cmnd_ptr->cmnd[3]; + cmn_err( CE_DEBUG, "AacHba_ReadCallback[cpu %d]: lba = %ld, t = %ld", smp_processor_id(), lba, jiffies ); + + if( FibContext == 0 ) + { + cmn_err( CE_WARN, "AacHba_ReadCallback: no fib context" ); + scsi_cmnd_ptr->result = DID_ERROR << 16; + AacHba_CompleteScsi( scsi_cmnd_ptr ); + return; + } + + BlockReadResponse = ( PBLOCKREADRESPONSE )Adapter->CommFuncs.GetFibData( FibContext ); + + if ( BlockReadResponse->Status == ST_OK ) + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + else + { + cmn_err( CE_WARN, "AacHba_ReadCallback: read failed, status = %d\n", + BlockReadResponse->Status ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_HW_ERR, SENCODE_INTERNAL_TARGET_FAILURE, ASENCODE_INTERNAL_TARGET_FAILURE, + 0, 0, 0, 0 ); + } + +#ifdef DEBUG_SGBUFFER + if ( scsi_cmnd_ptr->use_sg ) // use scatter/gather list + { + struct scatterlist *scatterlist_ptr; + int i, segment, count; + char *ptr; + + scatterlist_ptr = ( struct scatterlist * )scsi_cmnd_ptr->request_buffer; + + for( segment = 0; segment < scsi_cmnd_ptr->use_sg; segment++ ) + { + count = 0; + ptr = scatterlist_ptr[segment].address; + for( i = 0; i < scatterlist_ptr[segment].length; i++ ) + { + if( *( ptr++ ) == 0xa5 ) + count++; + } + if( count == scatterlist_ptr[segment].length ) + cmn_err( CE_WARN, "AacHba_ReadCallback: segment %d not filled", segment ); + + } + } +#endif + + Adapter->CommFuncs.CompleteFib( FibContext ); + Adapter->CommFuncs.FreeFib( FibContext ); + + AacHba_CompleteScsi( scsi_cmnd_ptr ); +} + +/*------------------------------------------------------------------------------ + AacHba_WriteCallback() + *----------------------------------------------------------------------------*/ +void AacHba_WriteCallback( + VOID *Context, + PFIB_CONTEXT FibContext, + int FibStatus ) +/*----------------------------------------------------------------------------*/ +{ + PCI_MINIPORT_COMMON_EXTENSION *CommonExtension; + AFA_COMM_ADAPTER *Adapter; + BLOCKWRITERESPONSE *BlockWriteResponse; + Scsi_Cmnd *scsi_cmnd_ptr; + u_long lba; + int ContainerId; + + scsi_cmnd_ptr = ( Scsi_Cmnd * )Context; + + CommonExtension = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata ); + Adapter = ( AFA_COMM_ADAPTER * )CommonExtension->Adapter; + + ContainerId = TARGET_LUN_TO_CONTAINER( scsi_cmnd_ptr->target, scsi_cmnd_ptr->lun ); + + lba = ( ( scsi_cmnd_ptr->cmnd[1] & 0x1F ) << 16 ) | + ( scsi_cmnd_ptr->cmnd[2] << 8 ) | + scsi_cmnd_ptr->cmnd[3]; + cmn_err( CE_DEBUG, "AacHba_WriteCallback[cpu %d]: lba = %ld, t = %ld", smp_processor_id(), lba, jiffies ); + if( FibContext == 0 ) + { + cmn_err( CE_WARN, "AacHba_WriteCallback: no fib context" ); + scsi_cmnd_ptr->result = DID_ERROR << 16; + AacHba_CompleteScsi( scsi_cmnd_ptr ); + return; + } + + BlockWriteResponse = (PBLOCKWRITERESPONSE) Adapter->CommFuncs.GetFibData( FibContext ); + if (BlockWriteResponse->Status == ST_OK) + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + else + { + cmn_err( CE_WARN, "AacHba_WriteCallback: write failed, status = %d\n", + BlockWriteResponse->Status ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_HW_ERR, SENCODE_INTERNAL_TARGET_FAILURE, ASENCODE_INTERNAL_TARGET_FAILURE, + 0, 0, 0, 0 ); + } + + Adapter->CommFuncs.CompleteFib( FibContext ); + Adapter->CommFuncs.FreeFib( FibContext ); + + AacHba_CompleteScsi( scsi_cmnd_ptr ); +} + + +/*------------------------------------------------------------------------------ + AacHba_Ioctl() + + Handle IOCTL requests + + Preconditions: + Postconditions: + *----------------------------------------------------------------------------*/ +int AacHba_Ioctl( + PCI_MINIPORT_COMMON_EXTENSION *CommonExtension, + int cmd, + void * arg ) +/*----------------------------------------------------------------------------*/ +{ + Sa_ADAPTER_EXTENSION *AdapterExtension; + AFA_IOCTL_CMD IoctlCmd; + int status; + + AdapterExtension = ( Sa_ADAPTER_EXTENSION * )CommonExtension->MiniPort; + + cmn_err( CE_DEBUG, "AacHba_Ioctl, type = %d", cmd ); + switch( cmd ) + { + case FSACTL_SENDFIB: + cmn_err( CE_DEBUG, "FSACTL_SENDFIB" ); + break; + + case FSACTL_AIF_THREAD: + cmn_err( CE_DEBUG, "FSACTL_AIF_THREAD" ); + break; + + case FSACTL_NULL_IO_TEST: + cmn_err( CE_DEBUG, "FSACTL_NULL_IO_TEST" ); + break; + + case FSACTL_SIM_IO_TEST: + cmn_err( CE_DEBUG, "FSACTL_SIM_IO_TEST" ); + break; + + case FSACTL_GET_FIBTIMES: + cmn_err( CE_DEBUG, "FSACTL_GET_FIBTIMES" ); + break; + + case FSACTL_ZERO_FIBTIMES: + cmn_err( CE_DEBUG, "FSACTL_ZERO_FIBTIMES"); + break; + + case FSACTL_GET_VAR: + cmn_err( CE_DEBUG, "FSACTL_GET_VAR" ); + break; + + case FSACTL_SET_VAR: + cmn_err( CE_DEBUG, "FSACTL_SET_VAR" ); + break; + + case FSACTL_OPEN_ADAPTER_CONFIG: + cmn_err( CE_DEBUG, "FSACTL_OPEN_ADAPTER_CONFIG" ); + break; + + case FSACTL_CLOSE_ADAPTER_CONFIG: + cmn_err( CE_DEBUG, "FSACTL_CLOSE_ADAPTER_CONFIG" ); + break; + + case FSACTL_QUERY_ADAPTER_CONFIG: + cmn_err( CE_DEBUG, "FSACTL_QUERY_ADAPTER_CONFIG" ); + break; + + case FSACTL_OPEN_GET_ADAPTER_FIB: + cmn_err( CE_DEBUG, "FSACTL_OPEN_GET_ADAPTER_FIB" ); + break; + + case FSACTL_GET_NEXT_ADAPTER_FIB: + cmn_err( CE_DEBUG, "FSACTL_GET_NEXT_ADAPTER_FIB" ); + break; + + case FSACTL_CLOSE_GET_ADAPTER_FIB: + cmn_err( CE_DEBUG, "FSACTL_CLOSE_GET_ADAPTER_FIB" ); + break; + + case FSACTL_MINIPORT_REV_CHECK: + cmn_err( CE_DEBUG, "FSACTL_MINIPORT_REV_CHECK" ); + break; + + case FSACTL_OPENCLS_COMM_PERF_DATA: + cmn_err( CE_DEBUG, "FSACTL_OPENCLS_COMM_PERF_DATA" ); + break; + + case FSACTL_GET_COMM_PERF_DATA: + cmn_err( CE_DEBUG, "FSACTL_GET_COMM_PERF_DATA" ); + break; + + case FSACTL_QUERY_DISK: + cmn_err( CE_DEBUG, "FSACTL_QUERY_DISK" ); + break; + + case FSACTL_DELETE_DISK: + cmn_err( CE_DEBUG, "FSACTL_DELETE_DISK" ); + break; + + default: + cmn_err( CE_DEBUG, "Unknown ioctl: 0x%x", cmd ); + } + + IoctlCmd.cmd = cmd; + IoctlCmd.arg = ( intptr_t )arg; + IoctlCmd.flag = 0; + IoctlCmd.cred_p = 0; + IoctlCmd.rval_p = 0; + + status = AfaCommAdapterDeviceControl( CommonExtension->Adapter, &IoctlCmd ); + cmn_err( CE_DEBUG, "AAC_Ioctl, completion status = %d", status ); + return( status ); +} + + +/*------------------------------------------------------------------------------ + AacHba_AdapterDeviceControl() + + Preconditions: + Postconditions: + Returns TRUE if ioctl handled, FALSE otherwise + *ReturnStatus set to completion status + *----------------------------------------------------------------------------*/ +BOOLEAN AacHba_AdapterDeviceControl ( + PVOID AdapterArg, // CommonExtensionPtr + IN PAFA_IOCTL_CMD IoctlCmdPtr, + OUT int * ReturnStatus ) +/*----------------------------------------------------------------------------*/ +{ + BOOLEAN Handled = TRUE; // start out handling it. + int Status = EFAULT; + + switch( IoctlCmdPtr->cmd ) + { + case FSACTL_QUERY_DISK: + Status = AacHba_QueryDisk( AdapterArg, IoctlCmdPtr ); + break; + + case FSACTL_DELETE_DISK: + Status = AacHba_DeleteDisk( AdapterArg, IoctlCmdPtr ); + break; + + case FSACTL_FORCE_DELETE_DISK: + Status = AacHba_ForceDeleteDisk( AdapterArg, IoctlCmdPtr ); + break; + + case 2131: + if( AacHba_ProbeContainers( ( PCI_MINIPORT_COMMON_EXTENSION * )AdapterArg ) ) + Status = -EFAULT; + break; + + default: + Handled = FALSE; + break; + } + + *ReturnStatus = Status; + + return( Handled ); +} + + +/*------------------------------------------------------------------------------ + AacHba_QueryDisk() + + Postconditions: + Return values + 0 = OK + -EFAULT = Bad address + -EINVAL = Bad container number + *----------------------------------------------------------------------------*/ +int AacHba_QueryDisk( + PVOID AdapterArg, // CommonExtensionPtr + IN PAFA_IOCTL_CMD IoctlCmdPtr ) +/*----------------------------------------------------------------------------*/ +{ + UNIX_QUERY_DISK QueryDisk; + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr; + fsadev_t *fsa_dev_ptr; + + CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )AdapterArg; + fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev ); + + if( copyin( IoctlCmdPtr->arg, &QueryDisk, sizeof( UNIX_QUERY_DISK ) ) ) + return( -EFAULT ); + + if (QueryDisk.ContainerNumber == -1) + QueryDisk.ContainerNumber = TARGET_LUN_TO_CONTAINER( QueryDisk.Target, QueryDisk.Lun ); + else + if( ( QueryDisk.Bus == -1 ) && ( QueryDisk.Target == -1 ) && ( QueryDisk.Lun == -1 ) ) + { + if( QueryDisk.ContainerNumber > MAXIMUM_NUM_CONTAINERS ) + return( -EINVAL ); + + QueryDisk.Instance = CommonExtensionPtr->OsDep.scsi_host_ptr->host_no; + QueryDisk.Bus = 0; + QueryDisk.Target = CONTAINER_TO_TARGET( QueryDisk.ContainerNumber ); + QueryDisk.Lun = CONTAINER_TO_LUN( QueryDisk.ContainerNumber ); + } + else + return( -EINVAL ); + + QueryDisk.Valid = fsa_dev_ptr->ContainerValid[QueryDisk.ContainerNumber]; + QueryDisk.Locked = fsa_dev_ptr->ContainerLocked[QueryDisk.ContainerNumber]; + QueryDisk.Deleted = fsa_dev_ptr->ContainerDeleted[QueryDisk.ContainerNumber]; + + if( fsa_dev_ptr->ContainerDevNo[QueryDisk.ContainerNumber] == -1 ) + QueryDisk.UnMapped = TRUE; + else + QueryDisk.UnMapped = FALSE; + + get_sd_devname( fsa_dev_ptr->ContainerDevNo[QueryDisk.ContainerNumber], + QueryDisk.diskDeviceName ); + + if( copyout( &QueryDisk, IoctlCmdPtr->arg, sizeof( UNIX_QUERY_DISK ) ) ) + return( -EFAULT ); + + return( 0 ); +} + + +/*------------------------------------------------------------------------------ + get_sd_devname() + *----------------------------------------------------------------------------*/ +static void get_sd_devname( + long disknum, + char * buffer) +/*----------------------------------------------------------------------------*/ +{ + if( disknum < 0 ) + { + sprintf(buffer, "%s", ""); + return; + } + + if( disknum < 26 ) + sprintf(buffer, "sd%c", 'a' + disknum); + else { + unsigned int min1; + unsigned int min2; + /* + * For larger numbers of disks, we need to go to a new + * naming scheme. + */ + min1 = disknum / 26; + min2 = disknum % 26; + sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2); + } +} + + +/*------------------------------------------------------------------------------ + AacHba_ForceDeleteDisk() + + Postconditions: + Return values + 0 = OK + -EFAULT = Bad address + -EINVAL = Bad container number + *----------------------------------------------------------------------------*/ +int AacHba_ForceDeleteDisk( + PVOID AdapterArg, // CommonExtensionPtr + IN PAFA_IOCTL_CMD IoctlCmdPtr ) +/*----------------------------------------------------------------------------*/ +{ + DELETE_DISK DeleteDisk; + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr; + fsadev_t *fsa_dev_ptr; + + CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )AdapterArg; + fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev ); + + if ( copyin( IoctlCmdPtr->arg, &DeleteDisk, sizeof( DELETE_DISK ) ) ) + return( -EFAULT ); + + if ( DeleteDisk.ContainerNumber > MAXIMUM_NUM_CONTAINERS ) + return( -EINVAL ); + + // Mark this container as being deleted. + fsa_dev_ptr->ContainerDeleted[DeleteDisk.ContainerNumber] = TRUE; + + return( 0 ); +} + +/* + * #REVIEW# + * 1- Why ContainerValid = 0 down below and ContainerDeleted = TRUE above ??? + */ + +/*------------------------------------------------------------------------------ + 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 + } +} + --- linux/drivers/scsi/aacraid/aacid.c.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/aacid.c Tue Jun 13 12:52:42 2000 @@ -0,0 +1,146 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * aac.c + * + * Abstract: Data structures for controller specific info. + * +--*/ + +#include "osheaders.h" + +#include "AacGenericTypes.h" + +#include "aac_unix_defs.h" + +#include "fsatypes.h" +#include "comstruc.h" +#include "fsaport.h" +#include "pcisup.h" + +#include "version.h" + + +/* Function Prototypes */ +void InqStrCopy(char *a, char *b); /* ossup.c */ + +/* Device name used to register and unregister + the device in linit.c */ +char devicestr[]="aac"; + +char *container_types[] = { + "None", + "Volume", + "Mirror", + "Stripe", + "RAID5", + "SSRW", + "SSRO", + "Morph", + "Legacy", + "RAID4", + "RAID10", + "RAID00", + "V-MIRRORS", + "PSEUDO R4", + "Unknown" +}; + +/* Local Structure to set SCSI inquiry data strings */ +typedef struct _INQSTR { + char vid[8]; /* Vendor ID */ + char pid[16]; /* Product ID */ + char prl[4]; /* Product Revision Level */ +} INQSTR, *INQSTRP; + +FSA_MINIPORT MiniPorts[]; + +/* Function: SetInqDataStr + * + * Arguments: [1] pointer to void [1] int + * + * Purpose: Sets SCSI inquiry data strings for vendor, product + * and revision level. Allows strings to be set in platform dependant + * files instead of in OS dependant driver source. + */ +void +SetInqDataStr ( + int MiniPortIndex, + void *dataPtr, + int tindex) +{ + INQSTRP InqStrPtr; + char *findit; + FSA_MINIPORT *mp; + + mp = &MiniPorts[MiniPortIndex]; + + InqStrPtr = (INQSTRP)(dataPtr); /* cast dataPtr to type INQSTRP */ + + InqStrCopy (mp->Vendor, InqStrPtr->vid); + InqStrCopy (mp->Model, InqStrPtr->pid); /* last six chars reserved for vol type */ + + findit = InqStrPtr->pid; + + for ( ; *findit != ' '; findit++); /* walk till we find a space then incr by 1 */ + findit++; + + if (tindex < (sizeof(container_types)/sizeof(char *))){ + InqStrCopy (container_types[tindex], findit); + } + InqStrCopy ("0001", InqStrPtr->prl); +} + +int +SaInitDevice( + IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension, + IN ULONG AdapterNumber, + IN ULONG PciBus, + IN ULONG PciSlot +); + +int +RxInitDevice( + IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension, + IN ULONG AdapterNumber, + IN ULONG PciBus, + IN ULONG PciSlot +); + + +/* + * Because of the way Linux names scsi devices, the order in this table has + * become important. Check for on-board Raid first, add-in cards second. + */ + +FSA_MINIPORT MiniPorts[] = { + { 0x1028, 0x0001, 0x1028, 0x0001, "afa", RxInitDevice, "percraid", "DELL ", "PERCRAID " }, // PowerEdge 2400 + { 0x1028, 0x0002, 0x1028, 0x0002, "afa", RxInitDevice, "percraid", "DELL ", "PERCRAID " }, // PowerEdge 4400 + { 0x1028, 0x0003, 0x1028, 0x0003, "afa", RxInitDevice, "percraid", "DELL ", "PERCRAID " }, // PowerEdge 2450 + { 0x1011, 0x0046, 0x9005, 0x1364, "afa", SaInitDevice, "percraid", "DELL ", "PERCRAID " }, // Dell PERC2 "Quad Channel" + { 0x1011, 0x0046, 0x103c, 0x10c2, "hpn", SaInitDevice, "hpnraid", "HP ", "NetRAID-4M " } // HP NetRAID-4M +}; + + +#define NUM_MINIPORTS (sizeof(MiniPorts) / sizeof(FSA_MINIPORT)) + +int NumMiniPorts = NUM_MINIPORTS; + +char DescriptionString[] = "AACxxx Raid Controller" FSA_VERSION_STRING ; --- linux/drivers/scsi/aacraid/commctrl.c.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/commctrl.c Tue Jun 13 12:52:42 2000 @@ -0,0 +1,1049 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * commctrl.c + * + * Abstract: Contains all routines for control of the AFA comm layer + * +--*/ + +#include "comprocs.h" +#include "osheaders.h" +#include "ostypes.h" + + + + + +typedef BOOLEAN BOOL; +#define inline /* _inline */ + +#include +AAC_STATUS +FsaCtlCheckRevision( + IN PAFA_COMM_ADAPTER Adapter, + IN PAFA_IOCTL_CMD IoctlCmdPtr + ) +/*++ + +Routine Description: + + This routine validates the revision of the caller with the current revision + of the filesystem. + +Arguments: + + Adapter - Supplies which adapter is being processed. + + Irp - Supplies the Irp being processed. + + IrpContext - Supplies the IrpContext. + +Return Value: + + AAC_STATUS + +--*/ + +{ + RevCheck APIRevCheck; + RevCheckResp APIRevCheckResp; + RevComponent APICallingComponent; + ULONG APIBuildNumber; + + if (COPYIN( (caddr_t) IoctlCmdPtr->arg, (caddr_t) &APIRevCheck, sizeof(RevCheck), IoctlCmdPtr->flag )) { + return (EFAULT); + } + + APICallingComponent = APIRevCheck.callingComponent; + APIBuildNumber = APIRevCheck.callingRevision.buildNumber; + + APIRevCheckResp.possiblyCompatible = RevCheckCompatibility( RevMiniportDriver , APICallingComponent, APIBuildNumber ); + + APIRevCheckResp.adapterSWRevision.external.ul = RevGetExternalRev(); + APIRevCheckResp.adapterSWRevision.buildNumber = RevGetBuildNumber(); + + if (COPYOUT( (caddr_t) &APIRevCheckResp, (caddr_t) IoctlCmdPtr->arg, sizeof(RevCheckResp), IoctlCmdPtr->flag )) { + return (EFAULT); + } + + return (0); +} + + +int +AfaCommAdapterDeviceControl( + IN PVOID AdapterArg, + IN PAFA_IOCTL_CMD IoctlCmdPtr + ) +{ + PAFA_COMM_ADAPTER Adapter = (PAFA_COMM_ADAPTER) AdapterArg; + int Status = ENOTTY; +// PIO_STACK_LOCATION IrpSp; + PAFA_CLASS_DRIVER ClassDriver; + + // + // First loop through all of the class drivers to give them a chance to handle + // the Device control first. + // + + ClassDriver = Adapter->ClassDriverList; + + while (ClassDriver) { + + if (ClassDriver->DeviceControl) { + + if (ClassDriver->DeviceControl( ClassDriver->ClassDriverExtension, IoctlCmdPtr, &Status ) ) { + + return (Status); + + } + } + + ClassDriver = ClassDriver->Next; + } + + switch (IoctlCmdPtr->cmd) { + + + case FSACTL_SENDFIB: + + Status = AfaCommCtlSendFib( Adapter, IoctlCmdPtr ); + break; + + case FSACTL_AIF_THREAD: + + Status = AfaCommCtlAifThread( Adapter, IoctlCmdPtr ); + break; + + + case FSACTL_OPEN_GET_ADAPTER_FIB: + + Status = FsaCtlOpenGetAdapterFib( Adapter, IoctlCmdPtr ); + break; + + case FSACTL_GET_NEXT_ADAPTER_FIB: + + Status = FsaCtlGetNextAdapterFib( Adapter, IoctlCmdPtr ); + break; + + case FSACTL_CLOSE_GET_ADAPTER_FIB: + + Status = FsaCtlCloseGetAdapterFib( Adapter, IoctlCmdPtr ); + break; + + case FSACTL_MINIPORT_REV_CHECK: + + Status = FsaCtlCheckRevision( Adapter , IoctlCmdPtr ); + break; + + + default: + + Status = ENOTTY; + break; + + } + + + return (Status); +} + +AAC_STATUS +AfaCommRegisterNewClassDriver( + IN PAFA_COMM_ADAPTER Adapter, + IN PAFA_NEW_CLASS_DRIVER NewClassDriver, + OUT PAFA_NEW_CLASS_DRIVER_RESPONSE NewClassDriverResponse + ) +/*++ + +Routine Description: + + This routine registers a new class driver for the comm layer. + + It will return a pointer to the communication functions for the class driver + to use. + +Arguments: + + Adapter - Supplies which adapter is being processed. + + Irp - Supplies the Irp being processed. + +Return Value: + + STATUS_SUCCESS - Everything OK. + +--*/ +{ + AAC_STATUS Status; + PAFA_CLASS_DRIVER ClassDriver; + + + ClassDriver = (PAFA_CLASS_DRIVER) OsAllocMemory( sizeof(AFA_CLASS_DRIVER), OS_ALLOC_MEM_SLEEP ); + + if (ClassDriver == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + + return Status; + } + + // + // If the class driver has sent in user Vars, then copy them into the global + // area. + // + + if (NewClassDriver->NumUserVars) { + + PFSA_USER_VAR NewUserVars; + + NewUserVars = OsAllocMemory( (FsaCommData.NumUserVars + + NewClassDriver->NumUserVars) * sizeof(FSA_USER_VAR), OS_ALLOC_MEM_SLEEP ); + + // + // First copy the existing into the new area. + // + + RtlCopyMemory( NewUserVars, FsaCommData.UserVars, FsaCommData.NumUserVars * sizeof(FSA_USER_VAR) ); + + // + // Next copy the new vars passed in from class driver. + // + + RtlCopyMemory( (NewUserVars + FsaCommData.NumUserVars), + NewClassDriver->UserVars, + NewClassDriver->NumUserVars * sizeof(FSA_USER_VAR) ); + + // + // Free up the old user vars. + // + + OsFreeMemory( FsaCommData.UserVars, FsaCommData.NumUserVars * sizeof(FSA_USER_VAR) ); + + // + // Point the global to the new area. + // + + FsaCommData.UserVars = NewUserVars; + + // + // Update the total count. + // + + FsaCommData.NumUserVars += NewClassDriver->NumUserVars; + + } + + ClassDriver->OpenAdapter = NewClassDriver->OpenAdapter; + ClassDriver->CloseAdapter = NewClassDriver->CloseAdapter; + ClassDriver->DeviceControl = NewClassDriver->DeviceControl; + ClassDriver->HandleAif = NewClassDriver->HandleAif; + ClassDriver->ClassDriverExtension = NewClassDriver->ClassDriverExtension; + + ClassDriver->Next = Adapter->ClassDriverList; + Adapter->ClassDriverList = ClassDriver; + + // + // Now return the information needed by the class driver to communicate to us. + // + + NewClassDriverResponse->CommFuncs = &Adapter->CommFuncs; + NewClassDriverResponse->CommPortExtension = Adapter; + NewClassDriverResponse->MiniPortExtension = Adapter->AdapterExtension; + NewClassDriverResponse->SpinLockCookie = Adapter->SpinLockCookie; + NewClassDriverResponse->Dip = Adapter->Dip; + + return (STATUS_SUCCESS); + + +} + +int +AfaCommCtlSendFib( + IN PAFA_COMM_ADAPTER Adapter, + IN PAFA_IOCTL_CMD IoctlCmdPtr +) +/*++ + +Routine Description: + + This routine sends a fib to the adapter on behalf of a user level + program. + +Arguments: + + Adapter - Supplies which adapter is being processed. + + IoctlCmdPtr - Pointer to the arguments to the IOCTL call + +Return Value: + + STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer. + + STATUS_INSUFFICIENT_RESOURCES - If a memory allocation failed. + + STATUS_SUCCESS - Everything OK. + +--*/ +{ + PFIB KFib; +// PMDL DmaMdl = NULL; + PCOMM_FIB_CONTEXT FibContext; + PSGMAP_CONTEXT SgMapContext; + SGMAP_CONTEXT _SgMapContext; + QUEUE_TYPES WhichQueue; + PVOID UsersAddress; + AAC_STATUS Status; + + FibContext = AllocateFib( Adapter ); + + KFib = FibContext->Fib; + + // + // First copy in the header so that we can check the size field. + // + + if (COPYIN( (caddr_t) IoctlCmdPtr->arg, (caddr_t) KFib, sizeof(FIB_HEADER), IoctlCmdPtr->flag )) { + FreeFib( FibContext ); + Status = EFAULT; + return (Status); + } + + // + // Since we copy based on the fib header size, make sure that we + // will not overrun the buffer when we copy the memory. Return + // an error if we would. + // + + if (KFib->Header.Size > sizeof(FIB) - sizeof(FIB_HEADER)) { + FreeFib( FibContext ); + Status = EINVAL; + return Status; + + } + + if (COPYIN( (caddr_t) IoctlCmdPtr->arg, (caddr_t) KFib, KFib->Header.Size + sizeof(FIB_HEADER), IoctlCmdPtr->flag )) { + FreeFib( FibContext ); + Status = EFAULT; + return (Status); + } + + WhichQueue = AdapNormCmdQueue; + + + if (KFib->Header.Command == TakeABreakPt) { + + InterruptAdapter(Adapter); + + // + // Since we didn't really send a fib, zero out the state to allow + // cleanup code not to assert. + // + + KFib->Header.XferState = 0; + + + } else { + + if (SendFib(KFib->Header.Command, FibContext, KFib->Header.Size , FsaNormal, + TRUE, NULL, TRUE, NULL, NULL) != FSA_SUCCESS) { + FsaCommPrint("User SendFib failed!.\n"); + + + FreeFib( FibContext ); + return (ENXIO); + } + + if (CompleteFib(FibContext) != FSA_SUCCESS) { + FsaCommPrint("User Complete FIB failed.\n"); + + FreeFib( FibContext ); + return (ENXIO); + } + + + } + + + // + // Make sure that the size returned by the adapter (which includes + // the header) is less than or equal to the size of a fib, so we + // don't corrupt application data. Then copy that size to the user + // buffer. (Don't try to add the header information again, since it + // was already included by the adapter.) + // + ASSERT(KFib->Header.Size <= sizeof(FIB)); + + if (COPYOUT( (caddr_t) KFib, (caddr_t) IoctlCmdPtr->arg, KFib->Header.Size, IoctlCmdPtr->flag )) { + FreeFib( FibContext ); + Status = EFAULT; + return (Status); + } + + FreeFib( FibContext ); + + return (0); + +} + +int +AfaCommCtlAifThread( + IN PAFA_COMM_ADAPTER Adapter, + IN PAFA_IOCTL_CMD IoctlCmdPtr +) +/*++ + +Routine Description: + + This routine will act as the AIF thread for this adapter. + +Arguments: + + Adapter - Supplies which adapter is being processed. + + IoctlCmdPtr - Pointer to the arguments to the IOCTL call + +Return Value: + + STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer. + + STATUS_INSUFFICIENT_RESOURCES - If a memory allocation failed. + + STATUS_SUCCESS - Everything OK. + +--*/ +{ + return (NormCommandThread(Adapter)); +} + + + +#ifdef GATHER_FIB_TIMES +AAC_STATUS +AfaCommGetFibTimes( + IN PAFA_COMM_ADAPTER Adapter, + IN PIRP Irp + ) +/*++ + +Routine Description: + + This routine returns the gathered fibtimes to the user. + +Arguments: + + Adapter - Supplies which adapter is being processed. + + Irp - Supplies the Irp being processed. + +Return Value: + + STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer. + + STATUS_INSUFFICIENT_RESOURCES - If a memory allocation failed. + + STATUS_SUCCESS - Everything OK. + +--*/ +{ + PALL_FIB_TIMES AllFibTimes; + PLARGE_INTEGER FreqPtr; + PIO_STACK_LOCATION IrpSp; + + // + // Get a pointer to the current Irp stack location + // + + IrpSp = IoGetCurrentIrpStackLocation( Irp ); + + FreqPtr = (PLARGE_INTEGER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer; + + *FreqPtr = Adapter->FibTimesFrequency; + + AllFibTimes = (PALL_FIB_TIMES)((PUCHAR)FreqPtr + sizeof(LARGE_INTEGER)); + + RtlCopyMemory(AllFibTimes, Adapter->FibTimes, sizeof(ALL_FIB_TIMES)); + + Irp->IoStatus.Information = 0; + + return (STATUS_SUCCESS); + +} + +AAC_STATUS +AfaCommZeroFibTimes( + IN PAFA_COMM_ADAPTER Adapter, + IN PIRP Irp + ) +/*++ + +Routine Description: + + This routine zero's the FibTimes structure within the adapter structure. + +Arguments: + + Adapter - Supplies which adapter is being processed. + + Irp - Supplies the Irp being processed. + +Return Value: + + STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer. + + STATUS_INSUFFICIENT_RESOURCES - If a memory allocation failed. + + STATUS_SUCCESS - Everything OK. + +--*/ +{ + PFIB_TIMES FibTimesPtr; + int i; + PIO_STACK_LOCATION IrpSp; + + // + // Get a pointer to the current Irp stack location + // + + IrpSp = IoGetCurrentIrpStackLocation( Irp ); + + // + // Initialize the Fib timing data structures + // + RtlZeroMemory(Adapter->FibTimes, sizeof(ALL_FIB_TIMES)); + + for (i = 0; i < MAX_FSACOMMAND_NUM; i++) { + + FibTimesPtr = &Adapter->FibTimes->FileSys[i]; + + FibTimesPtr->Minimum.LowPart = 0xffffffff; + FibTimesPtr->Minimum.HighPart = 0x7fffffff; + FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff; + FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff; + } + for (i = 0; i < MAX_RW_FIB_TIMES; i++) { + + FibTimesPtr = &Adapter->FibTimes->Read[i]; + + FibTimesPtr->Minimum.LowPart = 0xffffffff; + FibTimesPtr->Minimum.HighPart = 0x7fffffff; + FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff; + FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff; + } + for (i = 0; i < MAX_RW_FIB_TIMES; i++) { + + FibTimesPtr = &Adapter->FibTimes->Write[i]; + + FibTimesPtr->Minimum.LowPart = 0xffffffff; + FibTimesPtr->Minimum.HighPart = 0x7fffffff; + FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff; + FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff; + } + + FibTimesPtr = &Adapter->FibTimes->Other; + + FibTimesPtr->Minimum.LowPart = 0xffffffff; + FibTimesPtr->Minimum.HighPart = 0x7fffffff; + FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff; + FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff; + + Irp->IoStatus.Information = 0; + + return (STATUS_SUCCESS); + +} +#endif // GATHER_FIB_TIMES + +#ifndef unix_aif +int +FsaCtlOpenGetAdapterFib( + IN PAFA_COMM_ADAPTER Adapter, + IN PAFA_IOCTL_CMD IoctlCmdPtr + ) +/*++ + +Routine Description: + + This routine will get the next Fib, if available, from the AdapterFibContext + passed in from the user. + +Arguments: + + Adapter - Supplies which adapter is being processed. + + Irp - Supplies the Irp being processed. + +Return Value: + + STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer. + + STATUS_INSUFFICIENT_RESOURCES - If a memory allocation failed. + + STATUS_SUCCESS - Everything OK. + +--*/ +{ + PGET_ADAPTER_FIB_CONTEXT AdapterFibContext; +// HANDLE Event; +// PKEVENT eventObject = (PKEVENT) NULL; + int Status; + + // + // The context must be allocated from NonPagedPool because we need to use MmIsAddressValid. + // + + AdapterFibContext = OsAllocMemory(sizeof(GET_ADAPTER_FIB_CONTEXT), OS_ALLOC_MEM_SLEEP); + + if (AdapterFibContext == NULL) { + + Status = ENOMEM; + + } else { + + AdapterFibContext->NodeTypeCode = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT; + AdapterFibContext->NodeByteSize = sizeof(GET_ADAPTER_FIB_CONTEXT); + + + // + // Initialize the conditional variable use to wait for the next AIF. + // + + OsCv_init( &AdapterFibContext->UserEvent); + + // + // Set WaitingForFib to FALSE to indicate we are not in a WaitForSingleObject + // + + AdapterFibContext->WaitingForFib = FALSE; + + // + // Initialize the FibList and set the count of fibs on the list to 0. + // + + AdapterFibContext->FibCount = 0; + InitializeListHead(&AdapterFibContext->FibList); + + // + // Now add this context onto the adapter's AdapterFibContext list. + // + + OsCvLockAcquire(Adapter->AdapterFibMutex); + + InsertTailList(&Adapter->AdapterFibContextList, &AdapterFibContext->NextContext); + + OsCvLockRelease(Adapter->AdapterFibMutex); + + if (COPYOUT( &AdapterFibContext, (caddr_t) IoctlCmdPtr->arg, sizeof(PGET_ADAPTER_FIB_CONTEXT), + IoctlCmdPtr->flag )) { + + Status = EFAULT; + + } else { + + Status = 0; + + } + + } + + return (Status); +} + +int +FsaCtlGetNextAdapterFib( + IN PAFA_COMM_ADAPTER Adapter, + IN PAFA_IOCTL_CMD IoctlCmdPtr + ) +/*++ + +Routine Description: + + This routine will get the next Fib, if available, from the AdapterFibContext + passed in from the user. + +Arguments: + + Adapter - Supplies which adapter is being processed. + + Irp - Supplies the Irp being processed. + +Return Value: + + STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer. + + STATUS_NO_MORE_ENTRIES - There are no more Fibs for this AdapterFibContext. + + STATUS_SUCCESS - Everything OK. + +--*/ +{ + GET_ADAPTER_FIB_IOCTL AdapterFibIoctl; + PGET_ADAPTER_FIB_CONTEXT AdapterFibContext; + PFIB Fib; + int Status; + + if (COPYIN( (caddr_t) IoctlCmdPtr->arg, (caddr_t) &AdapterFibIoctl, + sizeof(GET_ADAPTER_FIB_IOCTL), IoctlCmdPtr->flag )) { + return (EFAULT); + } + + // + // Extract the AdapterFibContext from the Input parameters. + // + + AdapterFibContext = (PGET_ADAPTER_FIB_CONTEXT) AdapterFibIoctl.AdapterFibContext; + + // + // Verify that the HANDLE passed in was a valid AdapterFibContext + // + // rpbfix : determine if there is a way to validate the AdapterFibContext address. + // + + if ( (AdapterFibContext->NodeTypeCode != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || + (AdapterFibContext->NodeByteSize != sizeof(GET_ADAPTER_FIB_CONTEXT)) ) { + + return ( EINVAL ); + + } + + Status = STATUS_SUCCESS; + + OsCvLockAcquire(Adapter->AdapterFibMutex); + + // + // If there are no fibs to send back, then either wait or return EAGAIN + // +return_fib: + + if (!IsListEmpty(&AdapterFibContext->FibList)) { + + PLIST_ENTRY Entry; + + // + // Pull the next fib from the FibList + // + Entry = RemoveHeadList(&AdapterFibContext->FibList); + + Fib = CONTAINING_RECORD( Entry, FIB, Header.FibLinks ); + + AdapterFibContext->FibCount--; + + if (COPYOUT( Fib, AdapterFibIoctl.AifFib, sizeof(FIB), IoctlCmdPtr->flag )) { + + OsCvLockRelease( Adapter->AdapterFibMutex ); + OsFreeMemory( Fib, sizeof(Fib) ); + return (EFAULT); + + } + + // + // Free the space occupied by this copy of the fib. + // + + OsFreeMemory(Fib, sizeof(FIB)); + + Status = 0; + + } else { + + if (AdapterFibIoctl.Wait) { + + if (OsCv_wait_sig( &AdapterFibContext->UserEvent, Adapter->AdapterFibMutex ) == 0) { + + Status = EINTR; + + } else { + + goto return_fib; + + } + } else { + + Status = EAGAIN; + + } + + } + OsCvLockRelease( Adapter->AdapterFibMutex ); + + return (Status); +} + +int +FsaCtlCloseGetAdapterFib( + IN PAFA_COMM_ADAPTER Adapter, + IN PAFA_IOCTL_CMD IoctlCmdPtr + ) +/*++ + +Routine Description: + + This routine will close down the AdapterFibContext passed in from the user. + +Arguments: + + Adapter - Supplies which adapter is being processed. + + Irp - Supplies the Irp being processed. + +Return Value: + + STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer. + + STATUS_SUCCESS - Everything OK. + +--*/ +{ + PGET_ADAPTER_FIB_CONTEXT AdapterFibContext; + AAC_STATUS Status; + + // + // Extract the AdapterFibContext from the Input parameters + // + + AdapterFibContext = (PGET_ADAPTER_FIB_CONTEXT) IoctlCmdPtr->arg; + + if (AdapterFibContext == 0) { + cmn_err(CE_WARN, "FsaCtlCloseGetAdapterFib: AdapterFibContext is NULL"); + return(EINVAL); + } + + // + // Verify that the HANDLE passed in was a valid AdapterFibContext + // + // rpbfix : verify pointer sent in from user. + // + + if ( (AdapterFibContext->NodeTypeCode != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || + (AdapterFibContext->NodeByteSize != sizeof(GET_ADAPTER_FIB_CONTEXT)) ) { + + return (EINVAL); + + } + + OsCvLockAcquire(Adapter->AdapterFibMutex); + + Status = FsaCloseAdapterFibContext(Adapter, AdapterFibContext); + + OsCvLockRelease(Adapter->AdapterFibMutex); + + return (Status); +} + +int +FsaCloseAdapterFibContext( + IN PAFA_COMM_ADAPTER Adapter, + IN PGET_ADAPTER_FIB_CONTEXT AdapterFibContext + ) +{ + int Status; + PFIB Fib; + + // + // First free any FIBs that have not been consumed yet. + // + + while (!IsListEmpty(&AdapterFibContext->FibList)) { + + PLIST_ENTRY Entry; + + // + // Pull the next fib from the FibList + // + + Entry = RemoveHeadList(&AdapterFibContext->FibList); + + Fib = CONTAINING_RECORD( Entry, FIB, Header.FibLinks ); + + AdapterFibContext->FibCount--; + + // + // Free the space occupied by this copy of the fib. + // + + OsFreeMemory(Fib, sizeof(FIB)); + } + + // + // Remove the Context from the AdapterFibContext List + // + + RemoveEntryList(&AdapterFibContext->NextContext); + + OsCv_destroy( &AdapterFibContext->UserEvent ); + + // + // Invalidate context + // + + AdapterFibContext->NodeTypeCode = 0; + + // + // Free the space occupied by the Context + // + + OsFreeMemory(AdapterFibContext, sizeof(GET_ADAPTER_FIB_CONTEXT)); + + Status = STATUS_SUCCESS; + + return Status; +} +#endif + +AAC_STATUS +AfaCommOpenAdapter( + IN PVOID Arg + ) +/*++ + +Routine Description: + + The routine will get called by the miniport each time a user issues a CreateFile on the DeviceObject + for the adapter. + + The main purpose of this routine is to set up any data structures that may be needed + to handle any requests made on this DeviceObject. + +Arguments: + + Adapter - Pointer to which adapter miniport was opened. + + +Return Value: + + STATUS_SUCCESS + +--*/ + +{ + PAFA_COMM_ADAPTER Adapter = (PAFA_COMM_ADAPTER) Arg; + AAC_STATUS Status = STATUS_SUCCESS; + PAFA_CLASS_DRIVER ClassDriver; + + ClassDriver = Adapter->ClassDriverList; + + while (ClassDriver) { + + if (ClassDriver->OpenAdapter) { + + Status = ClassDriver->OpenAdapter( ClassDriver->ClassDriverExtension ); + + if (Status != STATUS_SUCCESS) + break; + } + + ClassDriver = ClassDriver->Next; + } + + return ( Status ); +} + +AAC_STATUS +AfaCommCloseAdapter( + IN PVOID Arg + ) +/*++ + +Routine Description: + + This routine will get called by the miniport each time a user issues a CloseHandle on the DeviceObject + for the adapter. + + The main purpose of this routine is to cleanup any data structures that have been set up + while this FileObject has been opened. + + This routine loops through all of the AdapterFibContext structures to determine if any need + to be deleted for this FileObject. + +Arguments: + + Adapter - Pointer to adapter miniport + + Irp - Pointer to Irp that caused this close + +Return Value: + + Status value returned from File system driver AdapterClose + +--*/ +{ + PAFA_COMM_ADAPTER Adapter = (PAFA_COMM_ADAPTER) Arg; + PLIST_ENTRY Entry, NextEntry; + PGET_ADAPTER_FIB_CONTEXT AdapterFibContext; + AAC_STATUS Status = STATUS_SUCCESS; + PAFA_CLASS_DRIVER ClassDriver; + + OsCvLockAcquire(Adapter->AdapterFibMutex); + + Entry = Adapter->AdapterFibContextList.Flink; + + // + // Loop through all of the AdapterFibContext, looking for any that + // were created with the FileObject that is being closed. + // + while (Entry != &Adapter->AdapterFibContextList) { + + // + // Extract the AdapterFibContext + // + AdapterFibContext = CONTAINING_RECORD( Entry, GET_ADAPTER_FIB_CONTEXT, NextContext ); + + // + // Save the next entry because CloseAdapterFibContext will delete the AdapterFibContext + // + NextEntry = Entry->Flink; + + Entry = NextEntry; + + } + +#ifdef unix_config_file + // + // If this FileObject had the adapter open for configuration, then release it. + // + if ( Adapter->AdapterConfigFileObject == IrpSp->FileObject ) { + + Adapter->AdapterConfigFileObject = NULL; + + } +#endif + + OsCvLockRelease(Adapter->AdapterFibMutex); + + ClassDriver = Adapter->ClassDriverList; + + while (ClassDriver) { + + if (ClassDriver->CloseAdapter) { + + Status = ClassDriver->CloseAdapter( ClassDriver->ClassDriverExtension ); + + if (Status != STATUS_SUCCESS) + break; + } + + ClassDriver = ClassDriver->Next; + } + + return ( Status ); + +} + --- linux/drivers/scsi/aacraid/comminit.c.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/comminit.c Tue Jun 13 12:52:42 2000 @@ -0,0 +1,1263 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * comminit.c + * + * Abstract: This supports the initialization of the host adapter commuication interface. + * This is a platform dependent module for the pci cyclone board. + * + --*/ +#include "comprocs.h" + +#define BugCheckFileId (FSAFS_BUG_CHECK_COMMINIT) + +VOID +AfaCommBugcheckHandler( + IN PVOID Buffer, + IN ULONG Length + ); + +VOID +ThrottlePeriodEndDpcRtn( + IN PKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2); + +FSA_COMM_DATA FsaCommData; + +AAC_STATUS +HardInterruptModeration1Changed( + IN PVOID AdapterContext, + IN ULONG NewValue + ) +{ + PAFA_COMM_ADAPTER Adapter = AdapterContext; + + // + // If we are using interrupt moderation, then disable the interrupt + // until we need to use it. + // + if (FsaCommData.HardInterruptModeration1) + DisableInterrupt( Adapter, AdapNormCmdNotFull, FALSE ); + else + EnableInterrupt( Adapter, AdapNormCmdNotFull, FALSE ); + + return (STATUS_SUCCESS); +} + +AAC_STATUS +FsaFibTimeoutChanged( + IN PVOID AdapterContext, + IN ULONG NewValue + ) +{ + // + // scale the new timeout from seconds to 100 nsec units + // +// FsaCommData.AdapterTimeout = RtlConvertLongToLargeInteger(-10*1000*1000*NewValue); + + return (STATUS_SUCCESS); +} + +#ifdef GATHER_FIB_TIMES +extern int GatherFibTimes; +#endif + +FSA_USER_VAR FsaCommUserVars[] = { +#ifdef FIB_CHECKSUMS + { "do_fib_checksums", (PULONG)&FsaCommData.do_fib_checksums, NULL }, +#endif +#ifdef GATHER_FIB_TIMES + { "GatherFibTimes", (PULONG)&GatherFibTimes, NULL }, +#endif + { "EnableAdapterTimeouts", (PULONG)&FsaCommData.EnableAdapterTimeouts, NULL}, + { "EnableInterruptModeration", (PULONG)&FsaCommData.EnableInterruptModeration, NULL }, + { "FsaDataFibsSent", (PULONG) &FsaCommData.FibsSent, NULL }, + { "FsaDataFibRecved", (PULONG) &FsaCommData.FibRecved, NULL }, + { "HardInterruptModeration", (PULONG)&FsaCommData.HardInterruptModeration, NULL}, + { "HardInterruptModeration1", (PULONG)&FsaCommData.HardInterruptModeration1, HardInterruptModeration1Changed}, + { "EnableFibTimeoutBreak", (PULONG)&FsaCommData.EnableFibTimeoutBreak, NULL}, + { "PeakFibsConsumed", (PULONG)&FsaCommData.PeakFibsConsumed, NULL }, + { "ZeroFibsConsumed", (PULONG)&FsaCommData.ZeroFibsConsumed, NULL }, + { "FibTimeoutSeconds", (PULONG) &FsaCommData.FibTimeoutSeconds, FsaFibTimeoutChanged }, +}; + +#define NUM_COMM_USER_VARS (sizeof(FsaCommUserVars) / sizeof(FSA_USER_VAR) ) + + +AAC_STATUS +AacCommDriverEntry( + ) + +/*++ + +Routine Description: + + This is the initialization routine for the FileArray Comm layer device driver. + +Arguments: + + DriverObject - Pointer to driver object created by the system. + +Return Value: + + AAC_STATUS - The function value is the final status from the initialization + operation. + +--*/ + +{ + AAC_STATUS Status; + PVOID BugCheckBuffer; + + RtlZeroMemory( &FsaCommData, sizeof(FSA_COMM_DATA) ); + + + // + // Load the global timeout value for the adapter timeout + // Also init the global that enables or disables adapter timeouts + // + +// FsaCommData.AdapterTimeout = RtlConvertLongToLargeInteger(-10*1000*1000*180); + + FsaCommData.FibTimeoutSeconds = 180; + + FsaCommData.EnableAdapterTimeouts = TRUE; + +// FsaCommData.QueueFreeTimeout = RtlConvertLongToLargeInteger(QUEUE_ENTRY_FREE_TIMEOUT); + +#ifdef unix_fib_timeout + FsaCommData.FibTimeoutIncrement = (180 * 1000 * 1000 * 10) / KeQueryTimeIncrement(); +#endif + + FsaCommData.EnableInterruptModeration = FALSE; + + // + // Preload UserVars with all variables from the comm layer. The class layers will + // include theirs when they register. + // + + FsaCommData.UserVars = OsAllocMemory(NUM_COMM_USER_VARS * sizeof(FSA_USER_VAR), OS_ALLOC_MEM_SLEEP ); + FsaCommData.NumUserVars = NUM_COMM_USER_VARS; + + RtlCopyMemory( FsaCommData.UserVars, &FsaCommUserVars, NUM_COMM_USER_VARS * sizeof(FSA_USER_VAR) ); + + +#ifdef AACDISK + // + // Call the disk driver to initialize itself. + // + + AacDiskDriverEntry(); + +#endif + + + + return (STATUS_SUCCESS); +} + + +VOID +DetachNTQueue( + IN PAFA_COMM_ADAPTER Adapter, + IN OUT PCOMM_QUE Queue, + IN QUEUE_TYPES WhichQueue + ) +/*++ + +Routine Description: + + This routine will release all of the resources used by a given queue. + +Arguments: + + Adapter - Which adapter the queue belongs to + Queue - Pointer to the queue itself + WhichQueue - Identifies which of the host queues this is. + +Return Value: + + NONE. + +--*/ +{ + switch (WhichQueue) { + + case HostNormCmdQueue: + + Os_remove_softintr( Queue->ConsumerRoutine ); + OsSpinLockDestroy( Queue->QueueLock ); + OsCv_destroy( &Queue->CommandReady ); + + break; + + case HostHighCmdQueue: + + Os_remove_softintr( Queue->ConsumerRoutine ); + OsSpinLockDestroy( Queue->QueueLock ); + OsCv_destroy( &Queue->CommandReady ); + + break; + + case HostNormRespQueue: + + Os_remove_softintr( Queue->ConsumerRoutine ); + OsSpinLockDestroy( Queue->QueueLock ); + break; + + case HostHighRespQueue: + + Os_remove_softintr( Queue->ConsumerRoutine ); + OsSpinLockDestroy( Queue->QueueLock ); + break; + + case AdapNormCmdQueue: + case AdapHighCmdQueue: + case AdapNormRespQueue: + case AdapHighRespQueue: + OsCv_destroy( &Queue->QueueFull ); + break; + } +} + +VOID +InitializeNTQueue( + IN PAFA_COMM_ADAPTER Adapter, + IN OUT PCOMM_QUE Queue, + IN QUEUE_TYPES WhichQueue + ) +/*++ + +Routine Description: + + Will initialize all entries in the queue that is NT specific. + +Arguments: + +Return Value: + + Nothing there is nothing to allocate so nothing should fail + +--*/ +{ + + Queue->NumOutstandingIos = 0; + + // + // Store a pointer to the adapter structure. + // + + Queue->Adapter = Adapter; + + InitializeListHead( &Queue->OutstandingIoQueue ); + + switch (WhichQueue) { + + case HostNormCmdQueue: + + OsCv_init( &Queue->CommandReady); + OsSpinLockInit( Queue->QueueLock, Adapter->SpinLockCookie); + if (ddi_add_softintr( Adapter->Dip, DDI_SOFTINT_HIGH, &Queue->ConsumerRoutine, NULL, + NULL, (PUNIX_INTR_HANDLER)HostCommandNormDpc, + (caddr_t)Queue ) != DDI_SUCCESS) { + + cmn_err(CE_CONT, "OS_addr_intr failed\n"); + } + + InitializeListHead(&Queue->CommandQueue); + + break; + + case HostHighCmdQueue: + + OsCv_init( &Queue->CommandReady); + OsSpinLockInit( Queue->QueueLock, Adapter->SpinLockCookie); + if (ddi_add_softintr( Adapter->Dip, DDI_SOFTINT_HIGH, &Queue->ConsumerRoutine, NULL, + NULL, (PUNIX_INTR_HANDLER)HostCommandHighDpc, + (caddr_t) Queue ) != DDI_SUCCESS) { + + cmn_err(CE_CONT, "OS_addr_intr failed\n"); + } + + InitializeListHead(&Queue->CommandQueue); + break; + + case HostNormRespQueue: + + OsSpinLockInit( Queue->QueueLock, Adapter->SpinLockCookie); + if (ddi_add_softintr( Adapter->Dip, DDI_SOFTINT_HIGH, &Queue->ConsumerRoutine, NULL, + NULL, (PUNIX_INTR_HANDLER)HostResponseNormalDpc, + (caddr_t) Queue ) != DDI_SUCCESS) { + + cmn_err(CE_CONT, "OS_addr_intr failed\n"); + } + break; + + case HostHighRespQueue: + + + OsSpinLockInit( Queue->QueueLock, Adapter->SpinLockCookie); + if (ddi_add_softintr( Adapter->Dip, DDI_SOFTINT_HIGH, &Queue->ConsumerRoutine, NULL, + NULL, (PUNIX_INTR_HANDLER)HostResponseHighDpc, + (caddr_t) Queue ) != DDI_SUCCESS) { + + cmn_err(CE_CONT, "OS_addr_intr failed\n"); + } + break; + + case AdapNormCmdQueue: + case AdapHighCmdQueue: + case AdapNormRespQueue: + case AdapHighRespQueue: + + OsCv_init( &Queue->QueueFull); + break; + } +} + +BOOLEAN +StartFsaCommandThreads(PAFA_COMM_ADAPTER Adapter) +/*++ + +Routine Description: + + Create and start the command receiver threads. + +Arguments: + + +Return Value: + + Nothing + +--*/ + +{ + return(TRUE); +} + +VOID +AfaCommTimeoutFib( + PAFA_COMM_ADAPTER Adapter, + PCOMM_FIB_CONTEXT FibContext + ) +/*++ + +Routine Description: + + This routine will do all of the work necessary to timeout the given fib. + +Arguments: + + Adapter - Pointer to an adapter structure. + + FibContext - Pointer to the context to time out. + +Return Value: + + Nothing. + +--*/ +{ + PFIB Fib = FibContext->Fib; + + +#ifdef unix_fib_timeout + if (Fib->Header.XferState & Async) { + + FibContext->FibCallback(FibContext->FibCallbackContext, FibContext, STATUS_IO_TIMEOUT); + + } else { + + KeSetEvent(&FibContext->FsaEvent, 0, FALSE); + + } +#endif +} + +VOID +AfaCommTimeoutRoutine( + PKDPC Dpc, + PVOID NullArgument, + PVOID Argument1, + PVOID Argument2 + ) +/*++ + +Routine Description: + + This DPC routine is executed by the expiration of a periodic timer. The purpose of this routine + is to check for fib's that should be timed out. + +Arguments: + + Dpc - Pointer to this routine. + + +Return Value: + + Nothing. + +--*/ +{ +#ifdef unix_fib_timeout + PCOMM_QUE OurQueue; + PLIST_ENTRY Entry, NextEntry; + LIST_ENTRY TimeoutQueue; + PCOMM_FIB_CONTEXT FibContext; + LARGE_INTEGER TickCount; + PAFA_COMM_ADAPTER Adapter; + + Adapter = FsaCommData.AdapterList; + + while (Adapter) { + + InitializeListHead( &TimeoutQueue ); + + OurQueue = &Adapter->CommRegion->AdapNormCmdQue; + + // DbgPrint("AfaCommTimeoutRoutine called, outstanding fibs = %d\n", OurQueue->NumOutstandingIos); + +// KeAcquireSpinLockAtDpcLevel( OurQueue->QueueLock ); + OsSpinLockAcquire( OurQueue->QueueLock ); + + KeQueryTickCount(&TickCount); + + Entry = OurQueue->OutstandingIoQueue.Flink; + + while (Entry != &OurQueue->OutstandingIoQueue) { + + FibContext = CONTAINING_RECORD( Entry, COMM_FIB_CONTEXT, QueueEntry ); + + // + // If the current tick count if less than the first fib on the queue, then + // none of the fib's have timed out. + // + + if (TickCount.QuadPart <= FibContext->TimeoutValue.QuadPart) { + + break; + + } + + // + // First, grab the next entry, then put this entry onto the queue to be timed out. + // + + NextEntry = Entry->Flink; + + // + // Mark the FibContext as timed out while we have the SpinLock. + // + + FibContext = CONTAINING_RECORD( Entry, COMM_FIB_CONTEXT, QueueEntry ); + + FibContext->Flags |= FIB_CONTEXT_FLAG_TIMED_OUT; + FibContext->Fib->Header.XferState |= TimedOut; + + RemoveEntryList( Entry ); + OurQueue->NumOutstandingIos--; + + InsertTailList( &TimeoutQueue, Entry ); + + + Entry = NextEntry; + + } + +// KeReleaseSpinLockFromDpcLevel( OurQueue->QueueLock ); + OsSpinLockRelease( OurQueue->QueueLock ); + + // + // Now walk through all fibs that need to be timed out. + // + + while (!IsListEmpty( &TimeoutQueue )) { + + Entry = RemoveHeadList( &TimeoutQueue ); + + FibContext = CONTAINING_RECORD( Entry, COMM_FIB_CONTEXT, QueueEntry ); + + AfaCommTimeoutFib( Adapter, FibContext ); + + } + + Adapter = Adapter->NextAdapter; + } +#endif +} + +BOOLEAN +AacCommDetachAdapter( + IN PAFA_COMM_ADAPTER Adapter + ) +/*++ + +Routine Description: + + This routine gets called to detach all resources that have been allocated for + this adapter. + +Arguments: + + Adapter - Pointer to the adapter structure to detach. + +Return Value: + + TRUE - All resources have been properly released. + FALSE - An error occured while trying to release resources. +--*/ +{ + PAFA_CLASS_DRIVER ClassDriver; + // + // First remove this adapter from the list of adapters. + // + + if (FsaCommData.AdapterList == Adapter) { + + FsaCommData.AdapterList = Adapter->NextAdapter; + + } else { + + PAFA_COMM_ADAPTER CurrentAdapter, NextAdapter; + + CurrentAdapter = FsaCommData.AdapterList; + NextAdapter = CurrentAdapter->NextAdapter; + + while (NextAdapter) { + + if (NextAdapter == Adapter) { + + CurrentAdapter->NextAdapter = NextAdapter->NextAdapter; + break; + + } + + CurrentAdapter = NextAdapter; + NextAdapter = CurrentAdapter->NextAdapter; + } + } + + // + // First send a shutdown to the adapter. + // + + AfaCommShutdown( Adapter ); + + // + // Destroy the FibContextZone for this adapter. This will free up all + // of the fib space used by this adapter. + // + + FsaFreeFibContextZone( Adapter ); + + // + // Destroy the mutex used for synch'ing adapter fibs. + // + + OsCvLockDestroy( Adapter->AdapterFibMutex ); + + // + // Detach all of the host queues. + // + + DetachNTQueue( Adapter, &Adapter->CommRegion->AdapHighRespQue, AdapHighRespQueue ); + DetachNTQueue( Adapter, &Adapter->CommRegion->AdapNormRespQue, AdapNormRespQueue ); + DetachNTQueue( Adapter, &Adapter->CommRegion->HostHighRespQue, HostHighRespQueue ); + DetachNTQueue( Adapter, &Adapter->CommRegion->HostNormRespQue, HostNormRespQueue ); + DetachNTQueue( Adapter, &Adapter->CommRegion->AdapHighCmdQue, AdapHighCmdQueue ); + DetachNTQueue( Adapter, &Adapter->CommRegion->AdapNormCmdQue, AdapNormCmdQueue ); + DetachNTQueue( Adapter, &Adapter->CommRegion->HostHighCmdQue, HostHighCmdQueue ); + DetachNTQueue( Adapter, &Adapter->CommRegion->HostNormCmdQue, HostNormCmdQueue ); + + // + // Destroy the mutex used to protect the FibContextZone + // + + OsSpinLockDestroy( Adapter->FibContextZoneSpinLock ); + + // + // Call the miniport to free the space allocated for the shared comm queues + // between the host and the adapter. + // + + FsaFreeAdapterCommArea( Adapter ); + + // + // Free the memory used by the comm region for this adapter + // + + OsFreeMemory( Adapter->CommRegion, sizeof(COMM_REGION) ); + + // + // Free the memory used by the adapter structure. + // + ClassDriver = Adapter->ClassDriverList; + Adapter->ClassDriverList = Adapter->ClassDriverList->Next; + OsFreeMemory( ClassDriver, sizeof(AFA_CLASS_DRIVER) ); + + OsFreeMemory( Adapter, sizeof(AFA_COMM_ADAPTER) ); + + return (TRUE); +} + +PVOID +AfaCommInitNewAdapter( + IN PFSA_NEW_ADAPTER NewAdapter + ) +{ + PVOID BugCheckBuffer; + PAFA_COMM_ADAPTER Adapter; + MAPFIB_CONTEXT MapFibContext; + LARGE_INTEGER Time; + char ErrorBuffer[60]; + +// Adapter = (PAFA_COMM_ADAPTER)ExAllocatePool(NonPagedPoolMustSucceed, sizeof(AFA_COMM_ADAPTER)); + Adapter = (PAFA_COMM_ADAPTER) OsAllocMemory( sizeof(AFA_COMM_ADAPTER) , OS_ALLOC_MEM_SLEEP ); + + if (Adapter == NULL) + return (NULL); + + RtlZeroMemory(Adapter, sizeof(AFA_COMM_ADAPTER)); + + + // + // Save the current adapter number and increment the total number. + // + + Adapter->AdapterNumber = FsaCommData.TotalAdapters++; + + + // + // Fill in the pointer back to the device specific structures. + // The device specific driver has also passed a pointer for us to + // fill in with the Adapter object that we have created. + // + + Adapter->AdapterExtension = NewAdapter->AdapterExtension; + Adapter->AdapterFuncs = NewAdapter->AdapterFuncs; + Adapter->InterruptsBelowDpc = NewAdapter->AdapterInterruptsBelowDpc; + Adapter->AdapterUserVars = NewAdapter->AdapterUserVars; + Adapter->AdapterUserVarsSize = NewAdapter->AdapterUserVarsSize; + + Adapter->Dip = NewAdapter->Dip; + + // + // Fill in Our address into the function dispatch table + // + + NewAdapter->AdapterFuncs->InterruptHost = AfaCommInterruptHost; + NewAdapter->AdapterFuncs->OpenAdapter = AfaCommOpenAdapter; + NewAdapter->AdapterFuncs->CloseAdapter = AfaCommCloseAdapter; + NewAdapter->AdapterFuncs->DeviceControl = AfaCommAdapterDeviceControl; + + // + // Ok now init the communication subsystem + // + + Adapter->CommRegion = (PCOMM_REGION) OsAllocMemory(sizeof(COMM_REGION), OS_ALLOC_MEM_SLEEP); + if (Adapter->CommRegion == NULL) { + cmn_err(CE_WARN, "Error could not allocate comm region.\n"); + return (NULL); + } + RtlZeroMemory(Adapter->CommRegion, sizeof(COMM_REGION)); + + // + // Get a pointer to the iblock_cookie + // + + ddi_get_soft_iblock_cookie( Adapter->Dip, DDI_SOFTINT_HIGH, &Adapter->SpinLockCookie ); + + if (!CommInit(Adapter)) { + FsaCommPrint("Failed to init the commuication subsystem.\n"); + return(NULL); + } + + +#ifdef unix_fib_timeout + // + // If this is the first adapter, then start the timeout routine timer. + // + + if (Adapter->AdapterNumber == 0) { + + // + // Initialize the DPC used to check for Fib timeouts. + // + + KeInitializeDpc( &FsaCommData.TimeoutDPC, AfaCommTimeoutRoutine, NULL ); + + // + // Initialize the Timer used to check for Fib Timeouts. + // + + KeInitializeTimer( &FsaCommData.TimeoutTimer ); + + // + // Set the timer to go off every 15 seconds. + // + + Time.QuadPart = - (15 * 10 * 1000 * 1000); + + KeSetTimerEx( &FsaCommData.TimeoutTimer, Time, (15 * 1000), &FsaCommData.TimeoutDPC ); + + } +#endif + + + // + // Initialize the list of AdapterFibContext's. + // + + InitializeListHead(&Adapter->AdapterFibContextList); + + // + // Initialize the fast mutex used for synchronization of the adapter fibs + // + + Adapter->AdapterFibMutex = OsCvLockAlloc(); + OsCvLockInit(Adapter->AdapterFibMutex, NULL); + + // + // Allocate and start the FSA command threads. These threads will handle + // command requests from the adapter. They will wait on an event then pull + // all CDBs off the thread's queue. Each CDB will be given to a worker thread + // upto a defined limit. When that limit is reached wait a event will be waited + // on till a worker thread is finished. + // + + if (!StartFsaCommandThreads(Adapter)) { + FsaCommPrint("Fsainit could not initilize the command receiver threads.\n"); + return (NULL); + } + +#ifdef unix_crash_dump + // + // Allocate and map a fib for use by the synch path, which is used for crash + // dumps. + // + // Allocate an entire page so that alignment is correct. + // + + Adapter->SyncFib = OsAllocMemory( PAGE_SIZE, OS_ALLOC_MEM_SLEEP ); + MapFibContext.Fib = Adapter->SyncFib; + MapFibContext.Size = sizeof(FIB); + MapFib( Adapter, &MapFibContext ); + Adapter->SyncFibPhysicalAddress = MapFibContext.LogicalFibAddress.LowPart; +#endif + + Adapter->CommFuncs.SizeOfAfaCommFuncs = sizeof(AFACOMM_FUNCS); + + Adapter->CommFuncs.AllocateFib = AllocateFib; + + Adapter->CommFuncs.FreeFib = FreeFib; + Adapter->CommFuncs.FreeFibFromDpc = FreeFibFromDpc; + Adapter->CommFuncs.DeallocateFib = DeallocateFib; + + Adapter->CommFuncs.InitializeFib = InitializeFib; + Adapter->CommFuncs.GetFibData = FsaGetFibData; + Adapter->CommFuncs.SendFib = SendFib; + Adapter->CommFuncs.CompleteFib = CompleteFib; + Adapter->CommFuncs.CompleteAdapterFib = CompleteAdapterFib; + + Adapter->CommFuncs.SendSynchFib = SendSynchFib; + + Adapter->CommFuncs.FreeDmaResources = Adapter->AdapterFuncs->FreeDmaResources; + Adapter->CommFuncs.BuildSgMap = Adapter->AdapterFuncs->BuildSgMap; + +#ifdef GATHER_FIB_TIMES + // + // Initialize the Fib timing data structures + // + { + PFIB_TIMES FibTimesPtr; + int i; + + KeQueryPerformanceCounter(&Adapter->FibTimesFrequency); + + Adapter->FibTimesFrequency.QuadPart >>= 7; + + Adapter->FibTimes = (PALL_FIB_TIMES)ExAllocatePool(NonPagedPool, sizeof(ALL_FIB_TIMES)); + RtlZeroMemory(Adapter->FibTimes, sizeof(ALL_FIB_TIMES)); + + for (i = 0; i < MAX_FSACOMMAND_NUM; i++) { + + FibTimesPtr = &Adapter->FibTimes->FileSys[i]; + + FibTimesPtr->Minimum.LowPart = 0xffffffff; + FibTimesPtr->Minimum.HighPart = 0x7fffffff; + FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff; + FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff; + } + for (i = 0; i < MAX_RW_FIB_TIMES; i++) { + + FibTimesPtr = &Adapter->FibTimes->Read[i]; + + FibTimesPtr->Minimum.LowPart = 0xffffffff; + FibTimesPtr->Minimum.HighPart = 0x7fffffff; + FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff; + FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff; + } + for (i = 0; i < MAX_RW_FIB_TIMES; i++) { + + FibTimesPtr = &Adapter->FibTimes->Write[i]; + + FibTimesPtr->Minimum.LowPart = 0xffffffff; + FibTimesPtr->Minimum.HighPart = 0x7fffffff; + FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff; + FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff; + } + + FibTimesPtr = &Adapter->FibTimes->Other; + + FibTimesPtr->Minimum.LowPart = 0xffffffff; + FibTimesPtr->Minimum.HighPart = 0x7fffffff; + FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff; + FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff; + } +#endif + + // + // Add this adapter in to our Adapter List. + // + + Adapter->NextAdapter = FsaCommData.AdapterList; + FsaCommData.AdapterList = Adapter; + + NewAdapter->Adapter = Adapter; + +// AfaDiskInitNewAdapter( Adapter->AdapterNumber, Adapter ); + + return (Adapter); +} + +AAC_STATUS +CommInitialize( + PAFA_COMM_ADAPTER Adapter + ) +{ + // + // Now allocate and initialize the zone structures used as our pool + // of FIB context records. The size of the zone is based on the + // system memory size. We also initialize the mutex used to protect + // the zone. + // + Adapter->FibContextZoneSpinLock= OsSpinLockAlloc(); + OsSpinLockInit( Adapter->FibContextZoneSpinLock, Adapter->SpinLockCookie ); + + Adapter->FibContextZoneExtendSize = 64; + + return (STATUS_SUCCESS); +} + + + +BOOLEAN +CommInit(PAFA_COMM_ADAPTER Adapter) +/*++ + +Routine Description: + + Initializes the data structures that are required for the FSA commuication + interface to operate. + +Arguments: + + None - all global or allocated data. + +Return Value: + + TRUE - if we were able to init the commuication interface. + FALSE - If there were errors initing. This is a fatal error. +--*/ +{ + + ULONG SizeOfHeaders = (sizeof(QUEUE_INDEX) * NUMBER_OF_COMM_QUEUES) * 2; + ULONG SizeOfQueues = sizeof(QUEUE_ENTRY) * TOTAL_QUEUE_ENTRIES; + PQUEUE_INDEX Headers; + PQUEUE_ENTRY Queues; + ULONG TotalSize; + PCOMM_REGION CommRegion = Adapter->CommRegion; + + CommInitialize( Adapter ); + + FsaCommPrint("CommInit: Queue entry size is 0x%x, Queue index size is 0x%x, Number of total entries is 0x%x, # queues = 0x%x.\n", + sizeof(QUEUE_ENTRY), sizeof(QUEUE_INDEX), TOTAL_QUEUE_ENTRIES, NUMBER_OF_COMM_QUEUES); + // + // + // Allocate the physically contigous space for the commuication queue + // headers. + // + + TotalSize = SizeOfHeaders + SizeOfQueues; + + if (!FsaAllocateAdapterCommArea(Adapter, (PVOID *)&Headers, TotalSize, QUEUE_ALIGNMENT)) + return (FALSE); + +#ifdef API_THROTTLE + // + // Initialize the throttle semaphore. + // Its a counted semaphore so we can allow a + // number of threads to be signalled by it at once. + // + + CommRegion->ThrottleLimit = THROTTLE_MAX_DATA_FIBS; + CommRegion->ThrottleTimeout = RtlConvertLongToLargeInteger(THROTTLE_PERIOD_DURATION); + CommRegion->ThrottleWaitTimeout = RtlConvertLongToLargeInteger(THROTTLE_WAIT_DURATION); + CommRegion->ThrottleActive = FALSE; // Is there a current throttle active period ? + CommRegion->ThrottleTimerFires = 0; // No fires of throttle timer yet. + CommRegion->ThrottleTimerSets = 0; + + CommRegion->ThrottledFibs = 0; + CommRegion->ThrottleTimedoutFibs = 0; + CommRegion->ApiFibs = 0; + CommRegion->NonPassiveFibs = 0; + CommRegion->TotalFibs = 0; + CommRegion->FSInfoFibs = 0; + CommRegion->ThrottleTimedoutFibs = 0; + + // + // Initialize the semaphore controlling I/Os to the adapter. + // We set it not signalled with a maximum signalled count + // representing the maximum number of I/Os we'll allow at + // once at the adapter. + // + KeInitializeSemaphore(&CommRegion->ThrottleReleaseSema, + CommRegion->ThrottleLimit, + CommRegion->ThrottleLimit); + // + // Initialize the Timer and Dpc for the Throttle timeout routine. + // + KeInitializeTimer(&CommRegion->ThrottleTimer); + KeInitializeDpc(&CommRegion->ThrottleDpc, + (PKDEFERRED_ROUTINE) &ThrottlePeriodEndDpcRtn, + (PVOID) Adapter); + +#endif // #ifdef API_THROTTLE + + Queues = (PQUEUE_ENTRY)((PUCHAR)Headers + SizeOfHeaders); + + + + if (ddi_add_softintr( Adapter->Dip, DDI_SOFTINT_HIGH, &CommRegion->QueueNotFullDpc, NULL, + NULL, (PUNIX_INTR_HANDLER)CommonNotFullDpc, + (caddr_t)CommRegion ) != DDI_SUCCESS) { + + cmn_err(CE_CONT, "Os_addr_intr failed\n"); + } + + + // Adapter to Host normal priority Command queue + + + CommRegion->HostNormCmdQue.Headers.ProducerIndex = Headers++; + CommRegion->HostNormCmdQue.Headers.ConsumerIndex = Headers++; + *CommRegion->HostNormCmdQue.Headers.ProducerIndex = HOST_NORM_CMD_ENTRIES; + *CommRegion->HostNormCmdQue.Headers.ConsumerIndex = HOST_NORM_CMD_ENTRIES; + + CommRegion->HostNormCmdQue.SavedIrql = 0; + CommRegion->HostNormCmdQue.BaseAddress = Queues; + CommRegion->HostNormCmdQue.QueueEntries = HOST_NORM_CMD_ENTRIES; + + CommRegion->HostNormCmdQue.QueueLock = OsSpinLockAlloc(); + if (CommRegion->HostNormCmdQue.QueueLock == NULL) { + return (FALSE); + } + InitializeNTQueue(Adapter, &CommRegion->HostNormCmdQue, HostNormCmdQueue); + + + Queues += HOST_NORM_CMD_ENTRIES; + + // Adapter to Host high priority command queue + + CommRegion->HostHighCmdQue.Headers.ProducerIndex = Headers++; + CommRegion->HostHighCmdQue.Headers.ConsumerIndex = Headers++; + *CommRegion->HostHighCmdQue.Headers.ProducerIndex = HOST_HIGH_CMD_ENTRIES; + *CommRegion->HostHighCmdQue.Headers.ConsumerIndex = HOST_HIGH_CMD_ENTRIES; + + CommRegion->HostHighCmdQue.SavedIrql = 0; + CommRegion->HostHighCmdQue.BaseAddress = Queues; + CommRegion->HostHighCmdQue.QueueEntries = HOST_HIGH_CMD_ENTRIES; +// CommRegion->HostHighCmdQue.QueueLock = (PKSPIN_LOCK) ExAllocatePool(NonPagedPool, sizeof(KSPIN_LOCK)); + CommRegion->HostHighCmdQue.QueueLock = OsSpinLockAlloc(); + if (CommRegion->HostHighCmdQue.QueueLock == NULL) { + return (FALSE); + } + InitializeNTQueue(Adapter, &CommRegion->HostHighCmdQue, HostHighCmdQueue); + + Queues += HOST_HIGH_CMD_ENTRIES; + + // Host to adapter normal priority command queue + + CommRegion->AdapNormCmdQue.Headers.ProducerIndex = Headers++; + CommRegion->AdapNormCmdQue.Headers.ConsumerIndex = Headers++; + *CommRegion->AdapNormCmdQue.Headers.ProducerIndex = ADAP_NORM_CMD_ENTRIES; + *CommRegion->AdapNormCmdQue.Headers.ConsumerIndex = ADAP_NORM_CMD_ENTRIES; + + CommRegion->AdapNormCmdQue.SavedIrql = 0; + CommRegion->AdapNormCmdQue.BaseAddress = Queues; + CommRegion->AdapNormCmdQue.QueueEntries = ADAP_NORM_CMD_ENTRIES; + InitializeNTQueue(Adapter, &CommRegion->AdapNormCmdQue, AdapNormCmdQueue); + + Queues += ADAP_NORM_CMD_ENTRIES; + + // host to adapter high priority command queue + + CommRegion->AdapHighCmdQue.Headers.ProducerIndex = Headers++; + CommRegion->AdapHighCmdQue.Headers.ConsumerIndex = Headers++; + *CommRegion->AdapHighCmdQue.Headers.ProducerIndex = ADAP_HIGH_CMD_ENTRIES; + *CommRegion->AdapHighCmdQue.Headers.ConsumerIndex = ADAP_HIGH_CMD_ENTRIES; + + CommRegion->AdapHighCmdQue.SavedIrql = 0; + CommRegion->AdapHighCmdQue.BaseAddress = Queues; + CommRegion->AdapHighCmdQue.QueueEntries = ADAP_HIGH_CMD_ENTRIES; + InitializeNTQueue(Adapter, &CommRegion->AdapHighCmdQue, AdapHighCmdQueue); + + Queues += ADAP_HIGH_CMD_ENTRIES; + + // adapter to host normal priority response queue + + CommRegion->HostNormRespQue.Headers.ProducerIndex = Headers++; + CommRegion->HostNormRespQue.Headers.ConsumerIndex = Headers++; + *CommRegion->HostNormRespQue.Headers.ProducerIndex = HOST_NORM_RESP_ENTRIES; + *CommRegion->HostNormRespQue.Headers.ConsumerIndex = HOST_NORM_RESP_ENTRIES; + + CommRegion->HostNormRespQue.SavedIrql = 0; + CommRegion->HostNormRespQue.BaseAddress = Queues; + CommRegion->HostNormRespQue.QueueEntries = HOST_NORM_RESP_ENTRIES; +// CommRegion->HostNormRespQue.QueueLock = (PKSPIN_LOCK) ExAllocatePool(NonPagedPool, sizeof(KSPIN_LOCK)); + CommRegion->HostNormRespQue.QueueLock = OsSpinLockAlloc(); + if (CommRegion->HostNormRespQue.QueueLock == NULL) { + return (FALSE); + } + InitializeNTQueue(Adapter, &CommRegion->HostNormRespQue, HostNormRespQueue); + + Queues += HOST_NORM_RESP_ENTRIES; + + // adapter to host high priority response queue + + CommRegion->HostHighRespQue.Headers.ProducerIndex = Headers++; + CommRegion->HostHighRespQue.Headers.ConsumerIndex = Headers++; + *CommRegion->HostHighRespQue.Headers.ProducerIndex = HOST_HIGH_RESP_ENTRIES; + *CommRegion->HostHighRespQue.Headers.ConsumerIndex = HOST_HIGH_RESP_ENTRIES; + + CommRegion->HostHighRespQue.SavedIrql = 0; + CommRegion->HostHighRespQue.BaseAddress = Queues; + CommRegion->HostHighRespQue.QueueEntries = HOST_HIGH_RESP_ENTRIES; +// CommRegion->HostHighRespQue.QueueLock = (PKSPIN_LOCK) ExAllocatePool(NonPagedPool, sizeof(KSPIN_LOCK)); + CommRegion->HostHighRespQue.QueueLock = OsSpinLockAlloc(); + if (CommRegion->HostHighRespQue.QueueLock == NULL) { + return (FALSE); + } + InitializeNTQueue(Adapter, &CommRegion->HostHighRespQue, HostHighRespQueue); + + Queues += HOST_HIGH_RESP_ENTRIES; + + // host to adapter normal priority response queue + + CommRegion->AdapNormRespQue.Headers.ProducerIndex = Headers++; + CommRegion->AdapNormRespQue.Headers.ConsumerIndex = Headers++; + *CommRegion->AdapNormRespQue.Headers.ProducerIndex = ADAP_NORM_RESP_ENTRIES; + *CommRegion->AdapNormRespQue.Headers.ConsumerIndex = ADAP_NORM_RESP_ENTRIES; + + CommRegion->AdapNormRespQue.SavedIrql = 0; + CommRegion->AdapNormRespQue.BaseAddress = Queues; + CommRegion->AdapNormRespQue.QueueEntries = ADAP_NORM_RESP_ENTRIES; + InitializeNTQueue(Adapter, &CommRegion->AdapNormRespQue, AdapNormRespQueue); + + Queues += ADAP_NORM_RESP_ENTRIES; + + // host to adapter high priority response queue + + CommRegion->AdapHighRespQue.Headers.ProducerIndex = Headers++; + CommRegion->AdapHighRespQue.Headers.ConsumerIndex = Headers++; + *CommRegion->AdapHighRespQue.Headers.ProducerIndex = ADAP_HIGH_RESP_ENTRIES; + *CommRegion->AdapHighRespQue.Headers.ConsumerIndex = ADAP_HIGH_RESP_ENTRIES; + + CommRegion->AdapHighRespQue.SavedIrql = 0; + CommRegion->AdapHighRespQue.BaseAddress = Queues; + CommRegion->AdapHighRespQue.QueueEntries = ADAP_HIGH_RESP_ENTRIES; + InitializeNTQueue(Adapter, &CommRegion->AdapHighRespQue, AdapHighRespQueue); + + CommRegion->AdapNormCmdQue.QueueLock = CommRegion->HostNormRespQue.QueueLock; + CommRegion->AdapHighCmdQue.QueueLock = CommRegion->HostHighRespQue.QueueLock; + CommRegion->AdapNormRespQue.QueueLock = CommRegion->HostNormCmdQue.QueueLock; + CommRegion->AdapHighRespQue.QueueLock = CommRegion->HostHighCmdQue.QueueLock; + + return(TRUE); +} + +AAC_STATUS +AfaCommShutdown( + PAFA_COMM_ADAPTER Adapter + ) +/*++ + +Routine Description: + + This routine will send a shutdown request to each adapter. + +Arguments: + + Adapter - which adapter to send the shutdown to. + +Return Value: + + NT Status success. + +--*/ + +{ + PFIB_CONTEXT FibContext; + PCLOSECOMMAND CloseCommand; + AAC_STATUS Status; + + FibContext = AllocateFib( Adapter ); + + InitializeFib( FibContext ); + + CloseCommand = (PCLOSECOMMAND) FsaGetFibData( FibContext ); + + CloseCommand->Command = VM_CloseAll; + CloseCommand->ContainerId = 0xffffffff; + + Status = SendFib( ContainerCommand, FibContext, sizeof(CLOSECOMMAND), FsaNormal, TRUE, NULL, TRUE, NULL, NULL ); + + if (Status != STATUS_SUCCESS) { + + FreeFib( FibContext ); + + goto ret; + + } + + CompleteFib( FibContext ); + + FreeFib( FibContext ); + + + Status = STATUS_SUCCESS; + +ret: + + return (Status); + +} + +VOID +AfaCommBugcheckHandler( + IN PVOID Buffer, + IN ULONG Length + ) +/*++ + +Routine Description: + + This routine will shutdown the adapter if there is a bugcheck and + copy the shutdown data from the adapter response into the buffer + so it will show up in the host dump file. +p +Arguments: + + Buffer - This buffer will be written to the host dump by nt for us. + + Length - The size of the buffer. + +Return Value: + + N/A + +--*/ +{ + PAFA_COMM_ADAPTER Adapter = FsaCommData.AdapterList; + + while (Adapter) { + + NotifyAdapter(Adapter, HostShutdown); + + Adapter = Adapter->NextAdapter; + + } + +} + +VOID +FsaCommLogEvent( + PFIB_CONTEXT FibContext, + PDEVICE_OBJECT DeviceObject, + AAC_STATUS FsaStatus, + AAC_STATUS AacStatus, + ULONG LocationCode, + USHORT Category, + PUCHAR String, + BOOLEAN DumpFib +) +{ +} + +AfaCommProbeDisks( + PAFA_COMM_ADAPTER Adapter + ) +{ + PMNTINFO DiskInfo; + PMNTINFORESPONSE DiskInfoResponse; + AAC_STATUS Status; + PCOMM_FIB_CONTEXT FibContext; + + FibContext = AllocateFib( Adapter ); + + InitializeFib( FibContext ); + + DiskInfo = (PMNTINFO) FibContext->Fib->data; + DiskInfo->Command = VM_NameServe; + DiskInfo->MntCount = 0; + DiskInfo->MntType = FT_FILESYS; + + Status = SendFib(ContainerCommand, + FibContext, + sizeof(MNTINFO), + FsaNormal, + TRUE, + NULL, + TRUE, + NULL, + NULL); + + DiskInfoResponse = (PMNTINFORESPONSE) FibContext->Fib->data; + + if (DiskInfoResponse->MntRespCount) { + + cmn_err(CE_CONT, "container found on adapter, size = 0x%x blocks\n", + DiskInfoResponse->MntTable[0].Capacity); + + } else { + + cmn_err(CE_CONT, "no containers found on adapter\n"); + + } + + CompleteFib( FibContext ); + + FreeFib( FibContext ); +} + + --- linux/drivers/scsi/aacraid/commsup.c.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/commsup.c Tue Jun 13 12:52:42 2000 @@ -0,0 +1,2294 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * commsup.c + * + * Abstract: Contain all routines that are required for FSA host/adapter + * commuication. + * + * + --*/ +#include "comprocs.h" + +#define BugCheckFileId (FSAFS_BUG_CHECK_COMMSUP) + +int CommPrinting; + +void +ThrottleExceptionHandler( + IN PCOMM_REGION CommRegion, + AAC_STATUS Status + ); + +void ThrottlePeriodEndDpcRtn( + IN PKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2 + ); + +BOOLEAN +FsaFreeFibContextSegment( + PAFA_COMM_ADAPTER Adapter, + PFIB_CONTEXT_ZONE_SEGMENT ZoneSegment + ) +/*++ + +Routine Description: + + This routine will free all resources used by a given FibContextSegment. + +Arguments: + + Adapter - The adapter that this COMM_FIB_CONTEXT will communicate with. + ZoneSegment - The segment to release resources from. + +Return Value: + + TRUE - All resources were properly freed. + FALSE - An Error occured while freeing resources. + +--*/ + +{ + PCOMM_FIB_CONTEXT FibContext; + int i; + + // Account for the ZONE_SEGMENT_HEADER before the first actual FibContext. + + for (i = 0, FibContext = (PCOMM_FIB_CONTEXT)((PUCHAR)ZoneSegment->FibContextSegment + sizeof(ZONE_SEGMENT_HEADER)); + i < ZoneSegment->ExtendSize; i++, FibContext++) { + + OsCvLockDestroy( FibContext->FsaEventMutex ); + OsCv_destroy( &FibContext->FsaEvent ); + + } + + UnmapAndFreeFibSpace( Adapter, &ZoneSegment->MapFibContext ); + + OsFreeMemory( ZoneSegment->FibContextSegment, ZoneSegment->FibContextSegmentSize ); + + OsFreeMemory( ZoneSegment, sizeof( FIB_CONTEXT_ZONE_SEGMENT ) ); + + return (TRUE); +} + +BOOLEAN +FsaFreeFibContextZone( + PAFA_COMM_ADAPTER Adapter + ) +/*++ + +Routine Description: + + This routine will walk through the FibContextSegmentList and free up all + resources used by the FibContextZone. + +Arguments: + + Adapter - The adapter that this COMM_FIB_CONTEXT will communicate with. + +Return Value: + + TRUE - All resources were properly freed. + FALSE - An Error occured while freeing resources. + +--*/ + +{ + PFIB_CONTEXT_ZONE_SEGMENT ZoneSegment, NextZoneSegment; + + ZoneSegment = Adapter->FibContextSegmentList; + + while (ZoneSegment) { + + NextZoneSegment = ZoneSegment->Next; + + FsaFreeFibContextSegment( Adapter, ZoneSegment ); + + ZoneSegment = NextZoneSegment; + } + + return (TRUE); +} + + + +BOOLEAN +FsaExtendFibContextZone( + IN PAFA_COMM_ADAPTER Adapter + ) +{ + int ExtendSize; + KIRQL SavedIrql; + ULONG ZoneSegmentAllocSize, FibAllocSize; + PVOID FibContextSegment; + PCOMM_FIB_CONTEXT FibContext; + PFIB Fib; + PVOID FibPhysicalAddress; + int i; + PFIB_CONTEXT_ZONE_SEGMENT ZoneSegment; + + // + // Allocate space to describe this zone segment. + // + + ZoneSegment = OsAllocMemory( sizeof( FIB_CONTEXT_ZONE_SEGMENT ), OS_ALLOC_MEM_SLEEP ); + + ExtendSize = Adapter->FibContextZoneExtendSize; + ZoneSegmentAllocSize = (ExtendSize * sizeof(COMM_FIB_CONTEXT)) + sizeof(ZONE_SEGMENT_HEADER); + + FibContextSegment = OsAllocMemory( ZoneSegmentAllocSize, OS_ALLOC_MEM_SLEEP ); + + if (FibContextSegment == NULL) { + return (FALSE); + } + + RtlZeroMemory( FibContextSegment, ZoneSegmentAllocSize ); + + ZoneSegment->FibContextSegment = FibContextSegment; + ZoneSegment->FibContextSegmentSize = ZoneSegmentAllocSize; + ZoneSegment->ExtendSize = ExtendSize; + + FibAllocSize = ExtendSize * sizeof(FIB); + + + ZoneSegment->MapFibContext.Size = FibAllocSize; + + AllocateAndMapFibSpace( Adapter, &ZoneSegment->MapFibContext ); + + Fib = ZoneSegment->MapFibContext.FibVirtualAddress; + FibPhysicalAddress = ZoneSegment->MapFibContext.FibPhysicalAddress; + + RtlZeroMemory( Fib, FibAllocSize ); + + // Account for the ZONE_SEGMENT_HEADER before the first actual FibContext. + + for (i = 0, FibContext = (PCOMM_FIB_CONTEXT)((PUCHAR)FibContextSegment + sizeof(ZONE_SEGMENT_HEADER)); + i < ExtendSize; i++, FibContext++) { + + FibContext->Adapter = Adapter; + + FibContext->Fib = Fib; + FibContext->FibData = (PVOID) FibContext->Fib->data; + + OsCv_init( &FibContext->FsaEvent); + FibContext->FsaEventMutex = OsCvLockAlloc(); + OsCvLockInit( FibContext->FsaEventMutex, Adapter->SpinLockCookie ); + + Fib->Header.XferState = 0xffffffff; + Fib->Header.SenderSize = sizeof(FIB); + + FibContext->LogicalFibAddress.LowPart = (ULONG) FibPhysicalAddress; + + Fib = (PFIB)((PUCHAR)Fib + sizeof(FIB)); + FibPhysicalAddress = (PVOID)((PUCHAR)FibPhysicalAddress + sizeof(FIB)); + } + + // + // If FibContextZone.TotalSegmentSize is non-zero, then a zone has already been + // initialized, we just need to extend it. + // + + if (Adapter->FibContextZone.TotalSegmentSize) { + + OsSpinLockAcquire( Adapter->FibContextZoneSpinLock ); + + ExExtendZone( &Adapter->FibContextZone, + FibContextSegment, + ZoneSegmentAllocSize ); + + OsSpinLockRelease( Adapter->FibContextZoneSpinLock ); + + } else { + + if (ExInitializeZone( &Adapter->FibContextZone, + sizeof(COMM_FIB_CONTEXT), + FibContextSegment, + ZoneSegmentAllocSize ) != STATUS_SUCCESS) + FsaBugCheck(0,0,0); + + } + + // + // Add this segment to the adapter's list of segments + // + + ZoneSegment->Next = Adapter->FibContextSegmentList; + Adapter->FibContextSegmentList = ZoneSegment; + + return (TRUE); +} + + + +PFIB_CONTEXT +AllocateFib ( + IN PVOID AdapterArg + ) + +/*++ + +Routine Description: + + This routine creates a new COMM_FIB_CONTEXT record + +Arguments: + + Adapter - The adapter that this COMM_FIB_CONTEXT will communicate with. + +Return Value: + + PCOMM_FIB_CONTEXT - returns a pointer to the newly allocate COMM_FIB_CONTEXT Record + +--*/ + +{ + PAFA_COMM_ADAPTER Adapter = (PAFA_COMM_ADAPTER) AdapterArg; + KIRQL SavedIrql; + PCOMM_FIB_CONTEXT FibContext; + int FullZoneLoopCounter = 0; + + // + // Acquire the zone spin lock, and check to see if the zone is full. + // If it is, then release the spin lock and allocate more fibs for the + // zone. The ExtendFibZone routine will re-acquire the spin lock to add + // the new fibs onto the zone. + // + + OsSpinLockAcquire( Adapter->FibContextZoneSpinLock ); + + while (ExIsFullZone( &Adapter->FibContextZone )) { + + if (++FullZoneLoopCounter > 10) + FsaBugCheck(0,0,0); + + OsSpinLockRelease( Adapter->FibContextZoneSpinLock ); + + if (FsaExtendFibContextZone(Adapter) == FALSE) { + return (NULL); + } + + OsSpinLockAcquire( Adapter->FibContextZoneSpinLock ); + + } + + // + // At this point we now know that the zone has at least one more + // IRP context record available. So allocate from the zone and + // then release the mutex. + // + + FibContext = (PCOMM_FIB_CONTEXT) ExAllocateFromZone( &Adapter->FibContextZone ); + + OsSpinLockRelease( Adapter->FibContextZoneSpinLock ); + + // + // Set the proper node type code and node byte size + // + + FibContext->NodeTypeCode = FSAFS_NTC_FIB_CONTEXT; + FibContext->NodeByteSize = sizeof( COMM_FIB_CONTEXT ); + + // + // Null out fields that depend on being zero at the start of each I/O + // + + FibContext->Fib->Header.XferState = 0; + FibContext->FibCallback = NULL; + FibContext->FibCallbackContext = NULL; + + + // + // return and tell the caller + // + + return ((PFIB_CONTEXT) FibContext); +} + + +VOID +FreeFib ( + IN PFIB_CONTEXT Context + ) + +/*++ + +Routine Description: + + This routine deallocates and removes the specified COMM_FIB_CONTEXT record + from the Fsafs in memory data structures. It should only be called + by FsaCompleteRequest. + +Arguments: + + FibContext - Supplies the COMM_FIB_CONTEXT to remove + +Return Value: + + None + +--*/ + +{ + KIRQL SavedIrql; + PCOMM_FIB_CONTEXT FibContext = Context; + + ASSERT(FibContext->NodeTypeCode == FSAFS_NTC_FIB_CONTEXT); + + OsSpinLockAcquire( FibContext->Adapter->FibContextZoneSpinLock ); + + if (FibContext->Flags & FIB_CONTEXT_FLAG_TIMED_OUT) { + + FsaCommData.TimedOutFibs++; + + FibContext->Next = FibContext->Adapter->FibContextTimedOutList; + FibContext->Adapter->FibContextTimedOutList = FibContext; + + } else { + + ASSERT(FibContext->Fib->Header.XferState == 0); + + if (FibContext->Fib->Header.XferState != 0) { + cmn_err(CE_WARN, "FreeFib, XferState != 0, FibContext = 0x%x, XferState = 0x%x\n", + FibContext, FibContext->Fib->Header.XferState); + } + + ExFreeToZone( &FibContext->Adapter->FibContextZone, FibContext ); + + } + + OsSpinLockRelease( FibContext->Adapter->FibContextZoneSpinLock ); + + // + // return and tell the caller + // + + return; +} + + +VOID +FreeFibFromDpc( + IN PFIB_CONTEXT Context + ) + +/*++ + +Routine Description: + + This routine deallocates and removes the specified COMM_FIB_CONTEXT record + from the Fsafs in memory data structures. It should only be called + from the dpc routines to from dpc to free an FibContext from an async or + no response io + +Arguments: + + FibContext - Supplies the COMM_FIB_CONTEXT to remove + +Return Value: + + None + +--*/ + +{ + PCOMM_FIB_CONTEXT FibContext = (PCOMM_FIB_CONTEXT) Context; + + ASSERT(FibContext->NodeTypeCode == FSAFS_NTC_FIB_CONTEXT); + + OsSpinLockAcquire(FibContext->Adapter->FibContextZoneSpinLock); + + if (FibContext->Flags & FIB_CONTEXT_FLAG_TIMED_OUT) { + + FsaCommData.TimedOutFibs++; + + FibContext->Next = FibContext->Adapter->FibContextTimedOutList; + FibContext->Adapter->FibContextTimedOutList = FibContext; + + } else { + + ASSERT(FibContext->Fib->Header.XferState == 0); + + if (FibContext->Fib->Header.XferState != 0) { + cmn_err(CE_WARN, "FreeFibFromDpc, XferState != 0, FibContext = 0x%x, XferState = 0x%x\n", + FibContext, FibContext->Fib->Header.XferState); + } + + + ExFreeToZone( &FibContext->Adapter->FibContextZone, FibContext ); + + } + + OsSpinLockRelease(FibContext->Adapter->FibContextZoneSpinLock); + + // + // return and tell the caller + // + + return; +} + + + +AAC_STATUS +InitializeFib( + IN PFIB_CONTEXT Context + ) +/*++ + +Routine Description: + + Will initialize a FIB of the requested size. + +Arguments: + + Fib is a pointer to a location which will receive the address of the allocated + FIB. + + Size is the size of the Fib to allocate. + +Return Value: + + NT_SUCCESS if a Fib was returned to the caller. + NT_ERROR if event was an invalid event. + +--*/ +{ + PCOMM_FIB_CONTEXT FibContext = (PCOMM_FIB_CONTEXT) Context; + PFIB Fib = FibContext->Fib; + + Fib->Header.StructType = TFib; + Fib->Header.Size = sizeof(FIB); +// if (Fib->Header.XferState & AllocatedFromPool) +// Fib->Header.XferState = HostOwned | FibInitialized | FibEmpty | AllocatedFromPool; +// else + Fib->Header.XferState = HostOwned | FibInitialized | FibEmpty | FastResponseCapable; + Fib->Header.SenderFibAddress = 0; + Fib->Header.ReceiverFibAddress = 0; + Fib->Header.SenderSize = sizeof(FIB); + + return(STATUS_SUCCESS); +} + +AAC_STATUS +AllocatePoolFib( + OUT PFIB *Fib, + IN USHORT Size + ) +/*++ + +Routine Description: + + Will allocate and initialize a FIB of the requested size and return a + pointer to the structure. The size allocated may be larger than the size + requested due to allocation performace optimizations. + +Arguments: + + Fib is a pointer to a location which will receive the address of the allocated + FIB. + + Size is the size of the Fib to allocate. + + JustInitialize is a boolean which indicates a Fib has been allocated most likly in an + imbedded structure the FS always allocates. So just initiaize it and return. + +Return Value: + + NT_SUCCESS if a Fib was returned to the caller. + NT_ERROR if event was an invalid event. + +--*/ +{ + +} + +AAC_STATUS +DeallocateFib( + PFIB_CONTEXT Context + ) +/*++ + +Routine Description: + + Will deallocate and return to the free pool the FIB pointed to by the + caller. Upon return accessing locations pointed to by the FIB parameter + could cause system access faults. + +Arguments: + + Fib is a pointer to the FIB that caller wishes to deallocate. + +Return Value: + + NT_SUCCESS if a Fib was returned to the caller. + NT_ERROR if event was an invalid event. + +--*/ +{ + PCOMM_FIB_CONTEXT FibContext = (PCOMM_FIB_CONTEXT) Context; + PFIB Fib = FibContext->Fib; + + if ( Fib->Header.StructType != TFib ) { + FsaCommPrint("Error CompleteFib called with a non Fib structure.\n"); + return(STATUS_UNSUCCESSFUL); + } + + + Fib->Header.XferState = 0; + + return(STATUS_SUCCESS); + +} + + +AAC_STATUS +GetResponse( + IN PCOMM_QUE ResponseQueue, + OUT PFIB Fib + ) +/*++ + +Routine Description: + + Gets a QE off the requested response queue and gets the response FIB into + host memory. The FIB may already be in host memory depending on the bus + interface, or may require the host to DMA it over from the adapter. The routine + will return the FIB to the caller. + +Arguments: + + ResponseQueue - Is the queue the caller wishes to have the response gotten from. + Fib - Is the Fib which was the response from the adapter + +Return Value: + + NT_SUCCESS if a Fib was returned to the caller. + NT_ERROR if there was no Fib to return to the caller. + bkpfix - add in all the other possible errors ect + +--*/ +{ +return(STATUS_UNSUCCESSFUL); +} + +// +// Commuication primitives define and support the queuing method we use to +// support host to adapter commuication. All queue accesses happen through +// these routines and are the only routines which have a knowledge of the +// how these queues are implemented. +// + +BOOLEAN +GetEntry( + IN PAFA_COMM_ADAPTER Adapter, + IN QUEUE_TYPES WhichQueue, + OUT PQUEUE_ENTRY *Entry, + OUT PQUEUE_INDEX Index, + OUT ULONG *DontInterrupt + ) +/*++ + +Routine Description: + + With a priority the routine returns a queue entry if the queue has free entries. If the queue + is full(no free entries) than no entry is returned and the function returns FALSE otherwise TRUE is + returned. + +Arguments: + + Priority is an enumerated type which determines which priority level + command queue the QE is going to be queued on. + + Entry is a pointer to the address of where to return the address of + the queue entry from the requested command queue. + + Index is a pointer to the address of where to store the index of the new + queue entry returned. + + DontInterrupt - We set this true if the queue state is such that we don't + need to interrupt the adapter for this queue entry. + +Return Value: + + TRUE - If a queue entry is returned + FALSE - If there are no free queue entries on the requested command queue. + +--*/ +{ + ULONG QueueOffset; + BOOLEAN status; + PCOMM_REGION CommRegion; + + CommRegion = Adapter->CommRegion; + + // + // All of the queues wrap when they reach the end, so we check to see if they + // have reached the end and if they have we just set the index back to zero. + // This is a wrap. You could or off the high bits in all updates but this is + // a bit faster I think. + // + + if (WhichQueue == AdapHighCmdQueue) { + *Index = *(CommRegion->AdapHighCmdQue.Headers.ProducerIndex); + + if (*Index - 2 == *(CommRegion->AdapHighCmdQue.Headers.ConsumerIndex)) + *DontInterrupt = TRUE; + + if (*Index >= ADAP_HIGH_CMD_ENTRIES) + *Index = 0; + + if (*Index + 1 == *(CommRegion->AdapHighCmdQue.Headers.ConsumerIndex)) { // Queue is full + status = FALSE; + cmn_err(CE_WARN, "Adapter High Command Queue full, %d outstanding", + CommRegion->AdapHighCmdQue.NumOutstandingIos); + } else { + QueueOffset = sizeof(QUEUE_ENTRY) * (*Index); + *Entry = QueueOffset + CommRegion->AdapHighCmdQue.BaseAddress; + + status = TRUE; + } + } else if (WhichQueue == AdapNormCmdQueue) { + + *Index = *(CommRegion->AdapNormCmdQue.Headers.ProducerIndex); + + if (*Index - 2 == *(CommRegion->AdapNormCmdQue.Headers.ConsumerIndex)) + *DontInterrupt = TRUE; + + // + // If we are at the end of the QUEUE then wrap back to + // the beginning. + // + + if (*Index >= ADAP_NORM_CMD_ENTRIES) + *Index = 0; // Wrap to front of the Producer Queue. + + // + // The IEEE spec says that it the producer is one behind the consumer then + // the queue is full. + // + + ASSERT(*(CommRegion->AdapNormCmdQue.Headers.ConsumerIndex) != 0); + + if (*Index + 1 == *(CommRegion->AdapNormCmdQue.Headers.ConsumerIndex)) { // Queue is full + cmn_err(CE_WARN, "Adapter Norm Command Queue full, %d outstanding", + CommRegion->AdapNormCmdQue.NumOutstandingIos); + status = FALSE; + } else { + // + // The success case just falls through and returns the a valid queue entry. + // + +#ifdef commdebug + FsaCommPrint("queue entry = %x.\n",CommRegion->AdapNormCmdQue.BaseAddress + *Index); + FsaCommPrint("GetEntry: Index = %d, QueueOffset = %x, Entry = %x, *Entry = %x.\n", + *Index, QueueOffset, Entry, *Entry); +#endif + *Entry = CommRegion->AdapNormCmdQue.BaseAddress + *Index; + + status = TRUE; + } + } else if (WhichQueue == AdapHighRespQueue) { + + *Index = *(CommRegion->AdapHighRespQue.Headers.ProducerIndex); + + if (*Index - 2 == *(CommRegion->AdapHighRespQue.Headers.ConsumerIndex)) + *DontInterrupt = TRUE; + + if (*Index >= ADAP_HIGH_RESP_ENTRIES) + *Index = 0; + + if (*Index + 1 == *(CommRegion->AdapHighRespQue.Headers.ConsumerIndex)) { // Queue is full + status = FALSE; + cmn_err(CE_WARN, "Adapter High Resp Queue full, %d outstanding", + CommRegion->AdapHighRespQue.NumOutstandingIos); + } else { + *Entry = CommRegion->AdapHighRespQue.BaseAddress + *Index; + status = TRUE; + } + } else if (WhichQueue == AdapNormRespQueue) { + + *Index = *(CommRegion->AdapNormRespQue.Headers.ProducerIndex); + + if (*Index - 2 == *(CommRegion->AdapNormRespQue.Headers.ConsumerIndex)) + *DontInterrupt = TRUE; + + // + // If we are at the end of the QUEUE then wrap back to + // the beginning. + // + + if (*Index >= ADAP_NORM_RESP_ENTRIES) + *Index = 0; // Wrap to front of the Producer Queue. + + // + // The IEEE spec says that it the producer is one behind the consumer then + // the queue is full. + // + + if (*Index + 1 == *(CommRegion->AdapNormRespQue.Headers.ConsumerIndex)) { // Queue is full + status = FALSE; + cmn_err(CE_WARN, "Adapter Norm Resp Queue full, %d outstanding", + CommRegion->AdapNormRespQue.NumOutstandingIos); + } else { + // + // The success case just falls through and returns the a valid queue entry. + // + + *Entry = CommRegion->AdapNormRespQue.BaseAddress + *Index; + +#ifdef commdebug + FsaCommPrint("queue entry = %x.\n",CommRegion->AdapNormRespQue.BaseAddress + *Index); + FsaCommPrint("GetEntry: Index = %d, Entry = %x, *Entry = %x.\n",*Index, Entry, *Entry); +#endif + status = TRUE; + } + } else { + cmn_err(CE_PANIC, "GetEntry: invalid queue %d", WhichQueue); + } + + + return (status); +} + + + +#ifdef API_THROTTLE + +void ThrottleCheck( + IN PAFA_COMM_ADAPTER Adapter, + IN PFIB Fib + ) +/*++ + +Routine Description: + + This routine implements data I/O throttling. Throttling occurs when + a CLI FIB is detected. To ensure the CLI responds quickly (the user + is waiting for the response), this mechanism restricts the queue + depth of data IOs at the adapter for a period of time (called the + Throttle Period, default 5 seconds). + + The mechanism uses a counted semaphore to place threads into a wait + state should there be too many data I/Os outstanding. + + At the start of a throttle period (indicated by the first CLI FIB) + a timer is started. When the timer expires, new requests can go to + the adapter freely. Throttled requests gradually drain to the + adapter as each outstanding throttle I/O completes. + + To avoid hurting regular I/O performance, we use a flag in the FIB + header to mark FIBs involved in throttling. This means we only need + take the extra spinlock in the response DPC routine for FIBs who + were subject to throttling. If no throttling is occurring, the cost + to the regular code paths is a handful of instructions. + +Arguments: + + Adapter - Pointer to per-adapter context. This is used to locate the + throttle information for this adapter. + + Fib - Pointer to the header for the fib being sent. + +Return Value: + + None. + +--*/ +{ + PCOMM_REGION CommRegion = Adapter->CommRegion; + AAC_STATUS Status; + + // + // This routine is called under protection of the queue spinlock. + // As such we are allowed to check and change the counts for the + // throttle. + // Check the FIB. If its not a data operation, send it on without + // throttle check. If it is a data operation, check for throttle. + // + + CommRegion->TotalFibs++; // Keep statistics + + if ((Fib->Header.XferState & ApiFib) != 0) { + + CommRegion->ApiFibs++; // Keep statistics + + // + // Its an API fib. If the throttle is not already active, + // make it so. This will prevent new data Fibs being sent + // if they exceed the throttle check. + // + + if (!CommRegion->ThrottleActive) { + BOOLEAN InQue; + + CommRegion->ThrottleActive = TRUE; // This causes new data I/Os to be throttled + + // + // Schedule a timer for the throttle active period. When + // it expires, we'll be called back at routine ThrottleDpcRoutine + // above. This will signify the throttle active period ended + // and any waiting threads will be signalled to restart. + // + + FsaCommPrint("Throttle Period Start - CommRegion: %x\n", CommRegion); + CommRegion->ThrottleTimerSets++; + InQue = KeSetTimer( &CommRegion->ThrottleTimer, + CommRegion->ThrottleTimeout, + &CommRegion->ThrottleDpc); + ASSERT(InQue == FALSE); + } + + return; + } + + // + // Its a non-API fib, so subject to throttle checks. + // The following are exempt from throttling: + // o FIBs marked as "throttle exempt" by upper layers. + // o I/Os issued from a raised IRQL. We can't suspend + // a thread when at raised IRQL so throttling is exempt. + // + + if (CommRegion->AdapNormCmdQue.SavedIrql != PASSIVE_LEVEL) { + + CommRegion->NonPassiveFibs++; + FsaCommPrint("ThrottleCheck: Non-Passive level FIB bypasses throttle: %x\n", Fib); + return; + + } + + if (CommRegion->ThrottleActive) { + + // + // Throttle is active. + // Check if the FIB is a read or write. If so, and its to the + // file system information area, let it through without throttling. + // + + if (Fib->Header.Command == ContainerCommand) { + PBLOCKREAD BlockDisk = (PBLOCKREAD) &Fib->data; + + // + // *** Note *** We are using read and write command formats + // interchangably here. This is ok for this purpose as the + // command is in the same place for both. Read and write command + // formats are different at higher offsets though. + // + + if ( ((BlockDisk->Command == VM_CtBlockRead) || + (BlockDisk->Command == VM_CtBlockWrite)) && + (BlockDisk->BlockNumber <= FILESYSTEM_INFO_MAX_BLKNO)) { + + CommRegion->FSInfoFibs++; // Keep statistics + return; + + } + + } + + // + // Throttle the FIB. + // Mark it as throttle active so that it can signal a waiter + // when it completes. + + CommRegion->ThrottledFibs++; + Fib->Header.Flags |= ThrottledFib; + + // + // Release the spinlock so we can wait the thread if necessary. + // Since we specify a timeout, check the caller is at passive level. + // + + OsSpinLockRelease((CommRegion->AdapNormCmdQue.QueueLock), CommRegion->AdapNormCmdQue.SavedIrql); + + FsaCommPrint("ThrottleCheck - Thread Suspension - FIB: %x\n", Fib); + + Status = KeWaitForSingleObject(&CommRegion->ThrottleReleaseSema, + Executive, // Don't allow user APCs to wake us + KernelMode, // Wait in kernel mode + FALSE, // Not alertable + &CommRegion->ThrottleWaitTimeout); // Timeout after this time + + // + // Check the signal status. If we've timed out, clear the throttle + // flag on the FIB to avoid us signalling the semaphore on completion. + // We never acquired the semaphore. + // + if (Status == STATUS_TIMEOUT) { + + CommRegion->ThrottleTimedoutFibs++; + FsaCommPrint("ThrottledFib Timed Out - FIB: %x\n", Fib); + Fib->Header.Flags &= ~ThrottledFib; // Clear the throttledfib flag + + } else { + + ASSERT(Status == STATUS_SUCCESS); // No other return is possible + + } + + // + // We've been woken up and can now send the FIB to the adapter. + // Acquire the spinlock again so we can get a queue entry. This + // returns to GetQueueEntry. + // + + FsaCommPrint("ThrottleCheck - Thread Resume - FIB: %x\n", Fib); + KeAcquireSpinLock((CommRegion->AdapNormCmdQue.QueueLock), &(CommRegion->AdapNormCmdQue.SavedIrql)); + CommRegion->ThrottleOutstandingFibs++; // There's another throttle controlled FIB going. + return; + + } +} + +#endif //#ifdef API_THROTTLE + +int GetQueueEntryTimeouts = 0; + +AAC_STATUS +GetQueueEntry( + IN PAFA_COMM_ADAPTER Adapter, + OUT PQUEUE_INDEX Index, + IN QUEUE_TYPES WhichQueue, + IN PFIB Fib, + IN BOOLEAN Wait, + IN PCOMM_FIB_CONTEXT FibContext, + OUT ULONG *DontInterrupt + ) +/*++ + +Routine Description: + + Gets the next free QE off the requested priorty adapter command queue and + associates the Fib with the QE. The QE represented by index is ready to + insert on the queue when this routine returns success. + +Arguments: + + Index is the returned value which represents the QE which is ready to + insert on the adapter's command queue. + + Priority is an enumerated type which determines which priority level + command queue the QE is going to be queued on. + + Fib is a pointer to the FIB the caller wishes to have associated with the + QE. + + Wait is a boolean which determines if the routine will wait if there are + no free QEs on the requested priority command queue. + + FibContext is where the driver stores all system resources required to execute the + command requested from the calling thread. This includes mapping resources for + the FIB and the 'users' buffer. + + DontInterrupt - We set this true if the queue state is such that we don't + need to interrupt the adapter for this queue entry. + +Return Value: + + NT_SUCCESS if a Fib was returned to the caller. + NT_ERROR if event was an invalid event. + +--*/ +{ + PQUEUE_ENTRY QueueEntry = NULL; + BOOLEAN MapAddress = FALSE; + int timeouts = 0; + AAC_STATUS Status; + PCOMM_REGION CommRegion; + + CommRegion = Adapter->CommRegion; + + // + // Get the spinlock for the queue we are putting a command on + // + + if (WhichQueue == AdapHighCmdQueue) + OsSpinLockAcquire(CommRegion->AdapHighCmdQue.QueueLock); + else if (WhichQueue == AdapNormCmdQueue) + OsSpinLockAcquire(CommRegion->AdapNormCmdQue.QueueLock); + else if (WhichQueue == AdapHighRespQueue) + OsSpinLockAcquire(CommRegion->AdapHighRespQue.QueueLock); + else if (WhichQueue == AdapNormRespQueue) + OsSpinLockAcquire(CommRegion->AdapNormRespQue.QueueLock); + else { + FsaCommPrint("Invalid queue priority passed to GetQueueEntry.\n"); + return(FSA_INVALID_QUEUE); + } + + // + // Get the pointers to a queue entry on the queue the caller wishes to queue + // a command request on. If there are no entries then wait if that is what the + // caller requested. + // + + if (WhichQueue == AdapHighCmdQueue) { + + while ( !GetEntry(Adapter, AdapHighCmdQueue, &QueueEntry, Index, DontInterrupt) ) { // if no entries wait for some if caller wants to + cmn_err(CE_PANIC, "GetEntries failed (1)\n"); + } + + // + // Setup queue entry with a command, status and Fib mapped + // + + QueueEntry->Size = Fib->Header.Size; + MapAddress = TRUE; + + } else if (WhichQueue == AdapNormCmdQueue) { + +#ifdef API_THROTTLE + // + // Check if this is a data I/O that may be throttled. Throttling + // occurs if FAST is trying to issue FIBs to the adapter for management + // commands. If a FAST FIB is detected by ThrottleCheck it is allowed + // to go to the adapter (barring no queue entries being available). If + // the FAST fib is the first FAST fib to be detected, a data I/O throttle + // period is started. New incoming data I/Os are restricted so that only + // a few can be outstanding to the adapter at once. This prevents the + // FAST FIBs being starved out from the disks. Once the period has ended, + // normal service is resumed. + // New data FIBs (i.e. non-FAST FIB) can be initiated so long as they + // don't exceed the throttle maximum of outstanding FIBs. If the new FIB + // *would* exceed the maximum, the thread is put to sleep, waiting on the + // data I/O throttle synchronization semaphore. When the first data FIB completes + // that takes the outstanding count to below the threshold, the throttle + // synchronization semaphore is signalled once. It is signaled for each completing + // FIB until the throttle period ends and all throttled FIBs have completed. + // + ThrottleCheck(Adapter, Fib); // Thread may be suspended here with spinlock released ! +#endif // #ifdef API_THROTTLE + +#ifdef commdebug + FsaCommPrint("Requesting a qe address in address %x.\n", &QueueEntry); +#endif + while ( !GetEntry(Adapter, AdapNormCmdQueue, &QueueEntry, Index, DontInterrupt) ) { // if no entries wait for some if caller wants to + + cmn_err(CE_PANIC, "GetEntries failed (2)\n"); + } + + // + // Setup queue entry with command, status and Fib mapped + // + +#ifdef commdebug + FsaCommPrint("We got a QE from the normal command queue address of %x, Index returned = %d\n", + *QueueEntry, *Index); +#endif + QueueEntry->Size = Fib->Header.Size; + MapAddress = TRUE; + + } else if (WhichQueue == AdapHighRespQueue) { + + while ( !GetEntry(Adapter, AdapHighRespQueue, &QueueEntry, Index, DontInterrupt) ) { // if no entries wait for some if caller wants to + } + + // + // Setup queue entry with command, status and Fib mapped + // + + QueueEntry->Size = Fib->Header.Size; + QueueEntry->FibAddress = Fib->Header.SenderFibAddress; // Restore adapters pointer to the FIB + Fib->Header.ReceiverFibAddress = Fib->Header.SenderFibAddress; // Let the adapter now where to find its data + MapAddress = FALSE; + + } else if (WhichQueue == AdapNormRespQueue) { + while ( !GetEntry(Adapter, AdapNormRespQueue, &QueueEntry, Index, DontInterrupt) ) { // if no entries wait for some if caller wants to + } + + // + // Setup queue entry with command, status, adapter's pointer to the Fib it sent + // + + QueueEntry->Size = Fib->Header.Size; + QueueEntry->FibAddress = Fib->Header.SenderFibAddress; // Restore adapters pointer to the FIB + Fib->Header.ReceiverFibAddress = Fib->Header.SenderFibAddress; // Let the adapter now where to find its data + MapAddress = FALSE; + } + + // + // If MapFib is true than we need to map the Fib and put pointers in the queue entry. + // + + if (MapAddress) { + QueueEntry->FibAddress = (ULONG)(FibContext->LogicalFibAddress.LowPart); + } + + // + // Return + // +#ifdef commdebug + FsaCommPrint("Queue Entry contents:.\n"); + FsaCommPrint(" Command = %d.\n", QueueEntry->Command); + FsaCommPrint(" Status = %x.\n", QueueEntry->Status); + FsaCommPrint(" Rec Fib address low = %x.\n", QueueEntry->FibAddressLow); + FsaCommPrint(" Fib size in bytes = %d.\n", QueueEntry->Size); +#endif + + return(FSA_SUCCESS); +} + +AAC_STATUS +InsertQueueEntry( + IN PAFA_COMM_ADAPTER Adapter, + IN QUEUE_INDEX Index, + IN QUEUE_TYPES WhichQueue, + IN ULONG DontInterrupt + ) +/*++ + +Routine Description: + + Gets the next free QE off the requested priorty adapter command queue and + associates the Fib with the QE. The QE represented by index is ready to + insert on the queue when this routine returns success. + +Arguments: + + Index is the returned value which represents the QE which is ready to + insert on the adapter's command queue. + + WhichQueue tells us which queue the caller wishes to have the entry put. + +Return Value: + + NT_SUCCESS if a Fib was returned to the caller. + NT_ERROR if event was an invalid event. + +--*/ +{ + PCOMM_REGION CommRegion; + + CommRegion = Adapter->CommRegion; + + // + // We have already verified the queue in getentry, but we still have to make + // sure we don't wrap here too. + // + + if (WhichQueue == AdapHighCmdQueue) { + + *(CommRegion->AdapHighCmdQue.Headers.ProducerIndex) = Index + 1; + + OsSpinLockRelease(CommRegion->AdapHighCmdQue.QueueLock); + + if (!DontInterrupt) + NotifyAdapter(Adapter, AdapHighCmdQue); + + } else if (WhichQueue == AdapNormCmdQueue) { + +#ifdef commdebug + FsaCommPrint("InsertQueueEntry: Inerting with an index of %d.\n",Index); +#endif + *(CommRegion->AdapNormCmdQue.Headers.ProducerIndex) = Index + 1; + + OsSpinLockRelease(CommRegion->AdapNormCmdQue.QueueLock); + + if (!DontInterrupt) + NotifyAdapter(Adapter, AdapNormCmdQue); + + } else if (WhichQueue == AdapHighRespQueue) { + + *(CommRegion->AdapHighRespQue.Headers.ProducerIndex) = Index + 1; + + OsSpinLockRelease(CommRegion->AdapHighRespQue.QueueLock); + + if (!DontInterrupt) + NotifyAdapter(Adapter, AdapHighRespQue); + + } else if (WhichQueue == AdapNormRespQueue) { + + *(CommRegion->AdapNormRespQue.Headers.ProducerIndex) = Index + 1; + + OsSpinLockRelease(CommRegion->AdapNormRespQue.QueueLock); + + if (!DontInterrupt) + NotifyAdapter(Adapter, AdapNormRespQue); + + } else { + FsaCommPrint("Invalid queue priority passed to InsertQueueEntry.\n"); + return(FSA_INVALID_QUEUE_PRIORITY); + } + + return(FSA_SUCCESS); +} + +extern int GatherFibTimes; + +BOOLEAN +SendSynchFib( + PVOID Arg, + FIB_COMMAND Command, + PVOID Data, + USHORT Size, + PVOID Response, + USHORT *ResponseSize + ) +/*++ + +Routine Description: + + This routine will send a synchronous FIB to the adapter and wait for its + completion. + +Arguments: + + DeviceExtension - Pointer to adapter extension structure. + + +Return Value: + + BOOLEAN + +--*/ +{ + PAFA_COMM_ADAPTER Adapter = Arg; + FIB *Fib; + ULONG returnStatus; + + Fib = Adapter->SyncFib; + + Fib->Header.StructType = TFib; + Fib->Header.Size = sizeof(FIB); + Fib->Header.XferState = HostOwned | FibInitialized | FibEmpty; + Fib->Header.ReceiverFibAddress = 0; + Fib->Header.SenderSize = sizeof(FIB); + Fib->Header.SenderFibAddress = (ULONG)Fib; + Fib->Header.Command = Command; + + // + // Copy the Data portion into the Fib. + // + + RtlCopyMemory( Fib->data, Data, Size ); + + + Fib->Header.XferState |= (SentFromHost | NormalPriority); + + // + // Set the size of the Fib we want to send to the adapter + // + + Fib->Header.Size = sizeof(FIB_HEADER) + Size; + + if (!Adapter->AdapterFuncs->SendSynchFib( Adapter->AdapterExtension, + Adapter->SyncFibPhysicalAddress )) { + + return (FALSE); + + } + + // + // Copy the response back to the caller's buffer. + // + + RtlCopyMemory( Response, Fib->data, Fib->Header.Size - sizeof(FIB_HEADER) ); + + *ResponseSize = Fib->Header.Size - sizeof(FIB_HEADER); + + // + // Indicate success + // + + return (TRUE); +} + +// +// Define the highest level of host to adapter communication routines. These +// routines will support host to adapter FS commuication. These routines have +// no knowledge of the commuication method used. This level sends and receives +// FIBs. This level has no knowledge of how these FIBs get passed back and forth. +// + +AAC_STATUS +SendFib( + IN FIB_COMMAND Command, + IN PFIB_CONTEXT Context, + IN ULONG Size, + IN COMM_PRIORITIES Priority, + IN BOOLEAN Wait, + IN PVOID WaitOn, + IN BOOLEAN ResponseExpected, + IN PFIB_CALLBACK FibCallback, + IN PVOID FibCallbackContext + ) +/*++ + +Routine Description: + + Sends the requested FIB to the adapter and optionally will wait for a + response FIB. If the caller does not wish to wait for a response than + an event to wait on must be supplied. This event will be set when a + response FIB is received from the adapter. + +Arguments: + + Fib is a pointer to the FIB the caller wishes to send to the adapter. + + Size - Size of the data portion of the Fib. + + Priority is an enumerated type which determines which priority level + the caller wishes to send this command at. + + Wait is a boolean which determines if the routine will wait for the + completion Fib to be returned(TRUE), or return when the Fib has been + successfully received by the adapter(FALSE). + + WaitOn is only vaild when Wait is FALSE. The Event will be set when the response + FIB has been returned by the adapter. + + ReturnFib is an optional pointer to a FIB that if present the response FIB will + copied to. + +Return Value: + + NT_SUCCESS if a Fib was returned to the caller. + NT_ERROR if event was an invalid event. + +--*/ +{ + PCOMM_FIB_CONTEXT FibContext = (PCOMM_FIB_CONTEXT) Context; + QUEUE_INDEX Index; + QUEUE_TYPES WhichQueue; + LARGE_INTEGER Timeout; + AAC_STATUS Status; + PAFA_COMM_ADAPTER Adapter = FibContext->Adapter; + ULONG DontInterrupt = FALSE; + PFIB Fib = FibContext->Fib; + IN PCOMM_QUE OurQueue; + +// cmn_err( CE_NOTE, "^SendFib entered\n"); + + Timeout = FsaCommData.AdapterTimeout; + + if (!(Fib->Header.XferState & HostOwned)) { + FsaCommPrint("SendFib was called with a xfer state not set to HostOwned!\n"); + FsaCommLogEvent(FibContext, + FsaCommData.DeviceObject, + FSAFS_FIB_INVALID, + STATUS_UNSUCCESSFUL, + BugCheckFileId | __LINE__, + FACILITY_FSAFS_ERROR_CODE, + NULL, + TRUE); + + return(STATUS_UNSUCCESSFUL); + + } + + // + // There are 5 cases with the wait and reponse requested flags. The only invalid cases + // are if the caller requests to wait and does not request a response and if the + // caller does not want a response and the Fib is not allocated from pool. If a response + // is not requesed the Fib will just be deallocaed by the DPC routine when the response + // comes back from the adapter. No further processing will be done besides deleting the + // Fib. We will have a debug mode where the adapter can notify the host it had a problem + // and the host can log that fact. + + if (Wait && !ResponseExpected) { + + FsaCommLogEvent(FibContext, + FsaCommData.DeviceObject, + FSAFS_FIB_INVALID, + STATUS_UNSUCCESSFUL, + BugCheckFileId | __LINE__, + FACILITY_FSAFS_ERROR_CODE, + NULL, + TRUE); + + return(STATUS_UNSUCCESSFUL); + + } else if (!Wait && ResponseExpected) { + Fib->Header.XferState |= (Async | ResponseExpected); + FIB_COUNTER_INCREMENT(FsaCommData.AsyncSent); + } else if (!Wait && !ResponseExpected) { + Fib->Header.XferState |= NoResponseExpected; + FIB_COUNTER_INCREMENT(FsaCommData.NoResponseSent); + } else if (Wait && ResponseExpected) { +// OsCv_init(&FibContext->FsaEvent, NULL, CV_DRIVER, NULL); + Fib->Header.XferState |= ResponseExpected; + FIB_COUNTER_INCREMENT(FsaCommData.NormalSent); + } + + Fib->Header.SenderData = (ULONG)FibContext; // so we can complete the io in the dpc routine + + // + // Set FIB state to indicate where it came from and if we want a response from the + // adapter. Also load the command from the caller. + // + + Fib->Header.SenderFibAddress = (ULONG)Fib; + Fib->Header.Command = Command; + Fib->Header.XferState |= SentFromHost; + FibContext->Fib->Header.Flags = 0; // Zero the flags field - its internal only... + + // + // Set the size of the Fib we want to send to the adapter + // + + Fib->Header.Size = sizeof(FIB_HEADER) + Size; + if (Fib->Header.Size > Fib->Header.SenderSize) { + return(STATUS_BUFFER_OVERFLOW); + } + + // + // Get a queue entry connect the FIB to it and send an notify the adapter a command is ready. + // + + if (Priority == FsaHigh) { + Fib->Header.XferState |= HighPriority; + WhichQueue = AdapHighCmdQueue; + OurQueue = &Adapter->CommRegion->AdapHighCmdQue; + } else { + Fib->Header.XferState |= NormalPriority; + WhichQueue = AdapNormCmdQueue; + OurQueue = &Adapter->CommRegion->AdapNormCmdQue; + } + +#ifdef GATHER_FIB_TIMES + if (GatherFibTimes) { + + if (Command == NuFileSystem) { + + FSACOMMAND FsaCommand; + PREAD ReadCommand; + PWRITE WriteCommand; + int Index; + + FsaCommand = (FSACOMMAND)Fib->data[0]; + + switch (FsaCommand) { + + case Read: + + ReadCommand = (PREAD)Fib->data; + + Index = ReadCommand->ByteCount >> 9; // divide by 512 + + FibContext->FibTimesPtr = &Adapter->FibTimes->Read[Index]; + + break; + + case Write: + + WriteCommand = (PWRITE)Fib->data; + + Index = WriteCommand->ByteCount >> 9; // divide by 512 + + FibContext->FibTimesPtr = &Adapter->FibTimes->Write[Index]; + + break; + + default: + + FibContext->FibTimesPtr = &Adapter->FibTimes->FileSys[FsaCommand]; + + break; + } + } else { + + FibContext->FibTimesPtr = &Adapter->FibTimes->Other; + + } + } +#endif + +#ifdef FIB_CHECKSUMS + if (FsaCommData.do_fib_checksums) { + int i; + unsigned char *pFib; + ULONG CheckSum = 0; + + Fib->Header.FibCheckSum = 0; // Zero out checksum before computing + + pFib = (unsigned char *)Fib; + for (i = 0; i < Fib->Header.Size; i++) { + CheckSum += *pFib++; + } + Fib->Header.FibCheckSum = CheckSum; + } +#endif + + + if ( GetQueueEntry( Adapter, &Index, WhichQueue, Fib, TRUE, FibContext, &DontInterrupt) != FSA_SUCCESS ) { + + + return(STATUS_UNSUCCESSFUL); + //FsaBugCheck(IrpContext, Index, WhichQueue); + } + +#ifdef commdebug + FsaCommPrint("SendFib: inserting a queue entry at index %d.\n",Index); + FsaCommPrint("Fib contents:.\n"); + FsaCommPrint(" Command = %d.\n", Fib->Header.Command); + FsaCommPrint(" XferState = %x.\n", Fib->Header.XferState ); + FsaCommPrint(" Send Fib low address = %x.\n", Fib->Header.SenderFibAddressLow); + FsaCommPrint(" Send Fib high address = %x.\n", Fib->Header.SenderFibAddressHigh); + FsaCommPrint(" Sender data low = %x.\n", Fib->Header.SenderDataLow); + FsaCommPrint(" Sender data High = %x.\n", Fib->Header.SenderDataHigh); + FsaCommPrint(" Rec Fib address low = %x.\n", Fib->Header.ReceiverFibAddressLow); +#endif + + // + // Fill in the Callback and CallbackContext if we are not going to wait. + // + + if (!Wait) { + + FibContext->FibCallback = FibCallback; + FibContext->FibCallbackContext = FibCallbackContext; + + } + +#ifdef GATHER_FIB_TIMES + if (GatherFibTimes) { + FibContext->FibTimeStamp.QuadPart = KeQueryPerformanceCounter(NULL).QuadPart >> 7; + } +#endif // GATHER_FIB_TIMES + + FIB_COUNTER_INCREMENT(FsaCommData.FibsSent); + +#ifdef unix_fib_timeout + // + // Put this fib onto the Outstanding I/O queue and increment the number of outstanding fibs. + // + + KeQueryTickCount( &FibContext->TimeoutValue ); + FibContext->TimeoutValue.QuadPart += FsaCommData.FibTimeoutIncrement; +#endif + + InsertTailList( &OurQueue->OutstandingIoQueue, &FibContext->QueueEntry ); + OurQueue->NumOutstandingIos++; + + FibContext->FibComplete = 0; + + if ( InsertQueueEntry( Adapter, Index, WhichQueue, (DontInterrupt & FsaCommData.EnableInterruptModeration)) != FSA_SUCCESS ) { + + return(STATUS_UNSUCCESSFUL); + //FsaBugCheck(IrpContext, Index, WhichQueue); + } + + // + // If the caller wanted us to wait for response wait now. + // If Timeouts are enabled than set the timeout otherwise wait forever. + // + + FSA_DO_PERF_INC(FibsSent) + + if (Wait) { + + OsCvLockAcquire( FibContext->FsaEventMutex ); + + while (FibContext->FibComplete == 0) { + + OsCv_wait( &FibContext->FsaEvent, FibContext->FsaEventMutex ); + + } + + OsCvLockRelease( FibContext->FsaEventMutex ); + + if ( (FibContext->Flags & FIB_CONTEXT_FLAG_TIMED_OUT) ) { + + return(STATUS_IO_TIMEOUT); + + } else { + + return(STATUS_SUCCESS); + } + } + + // + // If the user does not want a response than return success otherwise return pending + // + + ASSERT( FibCallback ); + + if (ResponseExpected) + return(STATUS_PENDING); + else + return(STATUS_SUCCESS); +} + +BOOLEAN +GetConsumerEntry( + IN PAFA_COMM_ADAPTER Adapter, + PCOMM_QUE OurQueue, + OUT PQUEUE_ENTRY *Entry + ) +/*++ + +Routine Description: + + Will return a pointer to the entry on the top of the queue requested that we are a consumer + of, and return the address of the queue entry. It does not change the state of the queue. + +Arguments: + + OurQueue - is the queue the queue entry should be removed from. + + Entry - is a pointer where the address of the queue entry should be returned. + +Return Value: + + TRUE if there was a queue entry on the response queue for the host to consume. + FALSE if there were no queue entries to consume. + +--*/ + +{ + QUEUE_INDEX Index; + BOOLEAN status; + + if (*OurQueue->Headers.ProducerIndex == *OurQueue->Headers.ConsumerIndex) { + status = FALSE; + } else { + + // + // The consumer index must be wrapped if we have reached the end of + // the queue. + // Else we just use the entry pointed to by the header index + // + + if (*OurQueue->Headers.ConsumerIndex >= OurQueue->QueueEntries) + Index = 0; + else + Index = *OurQueue->Headers.ConsumerIndex; + + *Entry = OurQueue->BaseAddress + Index; + +#ifdef commdebug + FsaCommPrint("Got a QE at Index %d, QE Addrss of %x.\n",Index,*Entry); +#endif + status = TRUE; + } + + return(status); +} + +BOOLEAN +ConsumerEntryAvailable( + IN PAFA_COMM_ADAPTER Adapter, + PCOMM_QUE OurQueue + ) +{ + return (*OurQueue->Headers.ProducerIndex != *OurQueue->Headers.ConsumerIndex); +} + +VOID +FreeConsumerEntry( + IN PAFA_COMM_ADAPTER Adapter, + PCOMM_QUE OurQueue, + QUEUE_TYPES WhichQueue + ) +/*++ + +Routine Description: + + Frees up the current top of the queue we are a consumer of. If the queue was full + notify the producer that the queue is no longer full. + +Arguments: + + OurQueue - is the queue we will free the current consumer entry on. + +Return Value: + + TRUE if there was a queue entry on the response queue for the host to consume. + FALSE if there were no queue entries to consume. + +--*/ + +{ + BOOLEAN WasFull = FALSE; + HOST_2_ADAP_EVENT Notify; + + if (*OurQueue->Headers.ProducerIndex+1 == *OurQueue->Headers.ConsumerIndex) + WasFull = TRUE; + + if (*OurQueue->Headers.ConsumerIndex >= OurQueue->QueueEntries) + *OurQueue->Headers.ConsumerIndex = 1; + else + *OurQueue->Headers.ConsumerIndex += 1; + + if (WasFull) { + switch (WhichQueue) { + + case HostNormCmdQueue: + Notify = HostNormCmdNotFull; + break; + case HostHighCmdQueue: + Notify = HostHighCmdNotFull; + break; + + case HostNormRespQueue: + Notify = HostNormRespNotFull; + break; + + case HostHighRespQueue: + Notify = HostHighRespNotFull; + break; + + } + NotifyAdapter(Adapter, Notify); + } + +} + +AAC_STATUS +CompleteAdapterFib( + IN PFIB_CONTEXT Context, + IN USHORT Size + ) +/*++ + +Routine Description: + + Will do all necessary work to complete a FIB that was sent from the adapter. + +Arguments: + + Fib is a pointer to the FIB that caller wishes to complete processing on. + + Size - Size of the completion Packet(Opitional). If not present than the current + largest size in the Fib will be used + + Adapter - Pointer to which adapter sent this FIB + +Return Value: + + NT_SUCCESS if a Fib was returned to the caller. + NT_ERROR if event was an invalid event. + +--*/ +{ + PCOMM_FIB_CONTEXT FibContext = Context; + PFIB Fib = FibContext->Fib; + PAFA_COMM_ADAPTER Adapter = FibContext->Adapter; + ULONG DontInterrupt = FALSE; + + if (Fib->Header.XferState == 0) + return(STATUS_SUCCESS); + + // + // If we plan to do anything check the structure type first. + // + + if ( Fib->Header.StructType != TFib ) { + FsaCommPrint("Error CompleteFib called with a non Fib structure.\n"); + return(STATUS_UNSUCCESSFUL); + } + + // + // This block handles the case where the adapter had sent us a command and we + // have finished processing the command. We call completeFib when we are done + // processing the command and want to send a response back to the adapter. This + // will send the completed cdb to the adapter. + // + + if (Fib->Header.XferState & SentFromAdapter) { + Fib->Header.XferState |= HostProcessed; + if (Fib->Header.XferState & HighPriority) { + QUEUE_INDEX Index; + + if (Size) { + Size += sizeof(FIB_HEADER); + if (Size > Fib->Header.SenderSize) + return(STATUS_BUFFER_OVERFLOW); + Fib->Header.Size = Size; + } + + if (GetQueueEntry(Adapter, &Index, AdapHighRespQueue, Fib, TRUE, NULL, &DontInterrupt) != STATUS_SUCCESS) { + FsaCommPrint("CompleteFib got an error geting a queue entry for a response.\n"); + return(FSA_FATAL); + } + if (InsertQueueEntry(Adapter, + Index, + AdapHighRespQueue, + (DontInterrupt & (BOOLEAN)FsaCommData.EnableInterruptModeration)) != STATUS_SUCCESS) { + FsaCommPrint("CompleteFib failed while inserting entry on the queue.\n"); + } + } else if (Fib->Header.XferState & NormalPriority) { + QUEUE_INDEX Index; + + if (Size) { + Size += sizeof(FIB_HEADER); + if (Size > Fib->Header.SenderSize) + return(STATUS_BUFFER_OVERFLOW); + Fib->Header.Size = Size; + } + + if (GetQueueEntry(Adapter, &Index, AdapNormRespQueue, Fib, TRUE, NULL, &DontInterrupt) != STATUS_SUCCESS) { + FsaCommPrint("CompleteFib got an error geting a queue entry for a response.\n"); + return(FSA_FATAL); + } + if (InsertQueueEntry(Adapter, + Index, + AdapNormRespQueue, + (DontInterrupt & (BOOLEAN)FsaCommData.EnableInterruptModeration)) != STATUS_SUCCESS) { + FsaCommPrint("CompleteFib failed while inserting entry on the queue.\n"); + } + } + } else { + cmn_err(CE_WARN, "CompleteFib: Unknown xferstate detected.\n"); + FsaBugCheck(0,0,0); + } + return(STATUS_SUCCESS); +} + +AAC_STATUS +CompleteFib( + IN PFIB_CONTEXT Context + ) +/*++ + +Routine Description: + + Will do all necessary work to complete a FIB. If the caller wishes to + reuse the FIB after post processing has been completed Reinitialize + should be called set to TRUE, otherwise the FIB will be returned to the + free FIB pool. If Reinitialize is set to TRUE then the FIB header is + reinitialzied and is ready for reuse on return from this routine. + +Arguments: + + Fib is a pointer to the FIB that caller wishes to complete processing on. + + Size - Size of the completion Packet(Opitional). If not present than the current + largest size in the Fib will be used + + Reinitialize is a boolean which determines if the routine will ready the + completed FIB for reuse(TRUE) or not(FALSE). + +Return Value: + + NT_SUCCESS if a Fib was returned to the caller. + NT_ERROR if event was an invalid event. + +--*/ +{ + PCOMM_FIB_CONTEXT FibContext = (PCOMM_FIB_CONTEXT) Context; + PAFA_COMM_ADAPTER Adapter = FibContext->Adapter; + PFIB Fib = FibContext->Fib; + + // + // Check for a fib which has already been completed + // + +// ASSERT(Fib->Header.XferState & AdapterProcessed); + if (Fib->Header.XferState == 0) + return(STATUS_SUCCESS); + + // + // If we plan to do anything check the structure type first. + // + + if ( Fib->Header.StructType != TFib ) { + FsaCommPrint("Error CompleteFib called with a non Fib structure.\n"); + return(STATUS_UNSUCCESSFUL); + } + +#if 0 +//#if FSA_ADAPTER_METER + // + // Meter the completion + // + fsaMeterEnd( // meter the end of an operation + &(Adapter->FibMeter), // .. the meter + IrpContext->FibMeterType, // .. type of operation + &(IrpContext->FibStartTime), // .. ptr to operation start timestamp + FibGetMeterSize(Fib, // .. number of bytes in operation + IrpContext->FibMeterType, + IrpContext->FibSubCommand)); +#endif // FSA_ADAPTER_METER + + // + // This block completes a cdb which orginated on the host and we just need + // to deallocate the cdb or reinit it. At this point the command is complete + // that we had sent to the adapter and this cdb could be reused. + // + + if ( (Fib->Header.XferState & SentFromHost) && + (Fib->Header.XferState & AdapterProcessed)) { + + ASSERT(FibContext->LogicalFibAddress.LowPart != 0); + + return( DeallocateFib(FibContext) ); + + // + // This handles the case when the host has aborted the I/O to the + // adapter because the adapter is not responding + // + + } else if (Fib->Header.XferState & SentFromHost) { + + ASSERT(FibContext->LogicalFibAddress.LowPart != 0); + + + return( DeallocateFib(FibContext) ); + + } else if (Fib->Header.XferState & HostOwned) { + + return(DeallocateFib(FibContext)); + + } else { + cmn_err(CE_WARN, "CompleteFib: Unknown xferstate detected.\n"); + FsaBugCheck(0,0,0); + } + return(STATUS_SUCCESS); +} + +VOID +HandleDriverAif( + IN PAFA_COMM_ADAPTER Adapter, + IN PCOMM_FIB_CONTEXT FibContext + ) +/*++ + +Routine Description: + + This routine handles a driver notify fib from the adapter and dispatches it to + the appropriate routine for handling. + +Arguments: + + Adapter - Which adapter this fib is from + FibContext - Pointer to FibContext from adapter. + +Return Value: + + Nothing. + +--*/ +{ + PFIB Fib = FibContext->Fib; + PAFA_CLASS_DRIVER ClassDriver; + BOOLEAN Handled = FALSE; + + + // + // First loop through all of the class drivers to give them a chance to handle + // the Fib. + // + + ClassDriver = Adapter->ClassDriverList; + + while (ClassDriver) { + + if (ClassDriver->HandleAif) { + + if (ClassDriver->HandleAif( ClassDriver->ClassDriverExtension, FibContext ) ) { + + Handled = TRUE; + break; + + } + } + + ClassDriver = ClassDriver->Next; + } + + if (!Handled) { + + // + // Set the status of this FIB to be Invalid parameter. + // + +// *(FSASTATUS *)Fib->data = ST_INVAL; + *(FSASTATUS *)Fib->data = ST_OK; + + + CompleteAdapterFib(FibContext, sizeof(FSASTATUS)); + + } +} + +int +NormCommandThread( + IN PAFA_COMM_ADAPTER Adapter + ) +/*++ + +Routine Description: + + Waits on the commandready event in it's queue. When the event gets set it will + pull FIBs off it's queue. It will continue to pull FIBs off till the queue is empty. + When the queue is empty it will wait for more FIBs. + +Arguments: + + Context is used. All data os global + +Return Value: + Nothing. + +--*/ +{ + PFIB Fib, NewFib; + COMM_FIB_CONTEXT FibContext; // for error logging + KIRQL SavedIrql; + PCOMM_REGION CommRegion = Adapter->CommRegion; + PLIST_ENTRY Entry; + PGET_ADAPTER_FIB_CONTEXT AdapterFibContext; + + // + // We can only have one thread per adapter for AIF's. + // + + if (Adapter->AifThreadStarted) { + return (EINVAL); + } + +// cmn_err(CE_NOTE, "AIF thread started"); + + // + // Let the DPC know it has a place to send the AIF's to. + // + + Adapter->AifThreadStarted = TRUE; + + RtlZeroMemory(&FibContext, sizeof(COMM_FIB_CONTEXT)); + + OsSpinLockAcquire(CommRegion->HostNormCmdQue.QueueLock); + + while (TRUE) { + + // + // NOTE : the QueueLock is held at the top of each loop. + // + + ASSERT(OsSpinLockOwned(CommRegion->HostNormCmdQue.QueueLock)); + + while (!IsListEmpty(&(CommRegion->HostNormCmdQue.CommandQueue))) { + PLIST_ENTRY Entry; + PAIFCOMMANDTOHOST AifCommandToHost; + + Entry = RemoveHeadList(&(CommRegion->HostNormCmdQue.CommandQueue)); + + OsSpinLockRelease(CommRegion->HostNormCmdQue.QueueLock); + + Fib = CONTAINING_RECORD( Entry, FIB, Header.FibLinks ); + + // + // We will process the FIB here or pass it to a worker thread that is TBD. We Really + // can't do anything at this point since we don't have anything defined for this thread to + // do. + // + + // cmn_err(CE_NOTE, "Got Fib from the adapter with a NORMAL priority, command 0x%x.\n", Fib->Header.Command); + + RtlZeroMemory( &FibContext, sizeof(COMM_FIB_CONTEXT) ); + + + FibContext.NodeTypeCode = FSAFS_NTC_FIB_CONTEXT; + FibContext.NodeByteSize = sizeof( COMM_FIB_CONTEXT ); + FibContext.Fib = Fib; + FibContext.FibData = Fib->data; + FibContext.Adapter = Adapter; + + + // + // We only handle AifRequest fibs from the adapter. + // + + ASSERT(Fib->Header.Command == AifRequest); + + + AifCommandToHost = (PAIFCOMMANDTOHOST) Fib->data; + + if (AifCommandToHost->command == AifCmdDriverNotify) { + + + + HandleDriverAif( Adapter, &FibContext ); + + } else { + + + OsCvLockAcquire(Adapter->AdapterFibMutex); + + Entry = Adapter->AdapterFibContextList.Flink; + + // + // For each Context that is on the AdapterFibContextList, make a copy of the + // fib, and then set the event to wake up the thread that is waiting for it. + // + + while (Entry != &Adapter->AdapterFibContextList) { + + // + // Extract the AdapterFibContext + // + + AdapterFibContext = CONTAINING_RECORD( Entry, GET_ADAPTER_FIB_CONTEXT, NextContext ); + +// Warning: sleep possible while holding spinlock + NewFib = OsAllocMemory(sizeof(FIB), OS_ALLOC_MEM_SLEEP); + + if (NewFib) { + + // + // Make the copy of the FIB + // + + RtlCopyMemory(NewFib, Fib, sizeof(FIB)); + + // + // Put the FIB onto the AdapterFibContext's FibList + // + + InsertTailList(&AdapterFibContext->FibList, &NewFib->Header.FibLinks); + AdapterFibContext->FibCount++; + + // + // Set the event to wake up the thread that will waiting. + // + + OsCv_signal(&AdapterFibContext->UserEvent); + + } else { + + + } + + Entry = Entry->Flink; + } + + // + // Set the status of this FIB + // + + *(FSASTATUS *)Fib->data = ST_OK; + + CompleteAdapterFib( &FibContext, sizeof(FSASTATUS) ); + + OsCvLockRelease(Adapter->AdapterFibMutex); + + } + + OsSpinLockAcquire(CommRegion->HostNormCmdQue.QueueLock); + + } + + // + // There are no more AIF's, call cv_wait_sig to wait for more + // to process. + // + + // cmn_err(CE_NOTE, "no more AIF's going to sleep\n"); + + if (OsCv_wait_sig( &(CommRegion->HostNormCmdQue.CommandReady), + CommRegion->HostNormCmdQue.QueueLock ) == 0) { + + OsSpinLockRelease(CommRegion->HostNormCmdQue.QueueLock); + + Adapter->AifThreadStarted = FALSE; + + // cmn_err(CE_NOTE, "AifThread awoken by a signal\n"); + + return (EINTR); + + } + + // cmn_err(CE_NOTE, "^Aif thread awake, going to look for more AIF's\n"); + + } +} + + +PVOID +FsaGetFibData( + IN PFIB_CONTEXT Context + ) +{ + PCOMM_FIB_CONTEXT FibContext = (PCOMM_FIB_CONTEXT) Context; + + return ((PVOID)FibContext->Fib->data); +} + + +#ifdef API_THROTTLE + +void ThrottlePeriodEndDpcRtn( + IN PKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2 + ) +/*++ + +Routine Description: + + This routine is called as a DPC when a throttle period expires. It + restarts all threads suspended due to the throttling flow control. + + The throttling counted semaphore is signalled for all waiting threads + and the indicator of throttling active is cleared. + +Arguments: + + Dpc - Pointer to Dpc structure. Not used. + DefferedContext - Pointer to per-adapter context. This is used to locate the + throttle information for this adapter. + SystemArgument1 - Not used + SystemArgument2 - Not used + +Return Value: + + None. + +--*/ +{ + PCOMM_REGION CommRegion; + PAFA_COMM_ADAPTER Adapter = (PAFA_COMM_ADAPTER) DeferredContext; + + CommRegion = Adapter->CommRegion; + + // + // Acquire the spinlock protecting the throttle status. + // + OsSpinLockAcquire(CommRegion->AdapNormCmdQue.QueueLock); + + FsaCommPrint("ThrottlePeriodEndDpc\n"); + + // + // Check that the timer has fired as many times as it was set ! + // + + CommRegion->ThrottleTimerFires++; + ASSERT(CommRegion->ThrottleTimerFires == CommRegion->ThrottleTimerSets); + + // + // The throttle period is now over. Restart all threads waiting + // on the throttle being released. + // Clear the throttle active indicator. This will allow new FIBs + // to be sent to the adapter once we release the spinlock on exiting + // the DPC. This means all restarted threads will be runnable + // threads by then. + // + + ASSERT(CommRegion->ThrottleActive == TRUE); // The throttle had better be on ! + CommRegion->ThrottleActive = FALSE; // This allows new data FIBs to go to the adapter on dpc exit + + OsSpinLockRelease(CommRegion->AdapNormCmdQue.QueueLock); +} + +#endif // #ifdef API_THROTTLE + --- linux/drivers/scsi/aacraid/dpcsup.c.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/dpcsup.c Tue Jun 13 12:52:42 2000 @@ -0,0 +1,553 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * dpcsup.c + * + * Abstract: All DPC processing routines for the cyclone board occur here. + * + * + --*/ +#include "comprocs.h" + + +// +// The Bug check file id for this module +// + +#define BugCheckFileId (FSAFS_BUG_CHECK_DPCSUP) + +#define Dbg (DEBUG_TRACE_DPCSUP) + +u_int +CommonNotFullDpc( + IN PCOMM_REGION CommRegion + ) +/*++ + +Routine Description: + + This DPC routine will be queued when the adapter interrupts us to let us know the queue is + no longer full. The Isr will pass the queue that we will set the not full event. + +Arguments: + + Dpc - Pointer to this routine. + + Dummy - is a pointer to the comm region which is global so we don't need it anyway + + Queue is a pointer to the queue structure we will operate on. + + MoreData2 are DPC parameters we don't need for this function. Maybe we can add some accounting + stuff in here. + +Return Value: + Nothing. + +--*/ +{ + +#ifdef unix_queue_full + KeSetEvent(&Queue->QueueFull, 0, FALSE); +#endif + +} + +int GatherFibTimes = 0; + +// XXX - hack this in until I figure out which header file should contain it. +extern ULONG +FibGetMeterSize( + PFIB pFib, + ULONG MeterType, + char SubCommand + ); + +u_int +HostResponseNormalDpc( + IN PCOMM_QUE OurQueue + ) +/*++ + +Routine Description: + + This DPC routine will be queued when the adapter interrupts us to let us know there + is a response on our normal priority queue. We will pull off all QE there are and wake + up all the waiters before exiting. We will take a spinlock out on the queue before operating + on it. + +Arguments: + + Dpc - Pointer to this routine. + + OurQueue is a pointer to the queue structure we will operate on. + + MoreData1&2 are DPC parameters we don't need for this function. Maybe we can add some accounting + stuff in here. + +Return Value: + Nothing. + +--*/ +{ + PAFA_COMM_ADAPTER Adapter = OurQueue->Adapter; + PQUEUE_ENTRY QueueEntry; + PFIB Fib; + PCOMM_FIB_CONTEXT FibContext; + int Consumed = 0; + KIRQL OldIrql; + + LARGE_INTEGER ResponseAllocSize; + +#ifdef commdebug + FsaCommPrint("entering the host normal reponse dpc routine.\n"); +#endif + +// cmn_err( CE_CONT, "^HostNormalResponseDpc entered\n"); + + OsSpinLockAcquire( OurQueue->QueueLock ); + + // + // Keep pulling response QEs off the response queue and waking + // up the waiters until there are no more QEs. We then return + // back to the system. If no response was requesed we just + // deallocate the Fib here and continue. + // + + loop: + while ( GetConsumerEntry( Adapter, OurQueue, &QueueEntry) ) { + + int IsFastResponse; + + IsFastResponse = (int) (QueueEntry->FibAddress & 0x01); + Fib = (PFIB) (QueueEntry->FibAddress & ~0x01); + + FreeConsumerEntry(Adapter, OurQueue, HostNormRespQueue); + +#ifdef API_THROTTLE + // + // Throttling support to improve CLI responsiveness under load. + // Check if this FIB was participating in throttle I/O. + // If so, take the spinlock to protect the throttle values + // and count the completion. Then signal the next waiting + // thread. + // + + if ((Fib->Header.Flags & ThrottledFib) != 0) { + PCOMM_REGION CommRegion = Adapter->CommRegion; + + FsaCommPrint("NormResponseDpc Throttled FIB Completion - FIB: %x, ThrottledFibs: %d\n", + Fib, CommRegion->ThrottleOutstandingFibs); + + // + // Account for the completion. + // + + ASSERT(CommRegion->ThrottleOutstandingFibs > 0); + CommRegion->ThrottleOutstandingFibs--; // One less FIB outstanding + + KeReleaseSemaphore(&CommRegion->ThrottleReleaseSema, + 0, + 1, // Release a waiting thread. + FALSE); + + + } // End of throttle code +#endif // #ifdef API_THROTTLE + + FibContext = (PCOMM_FIB_CONTEXT)Fib->Header.SenderData; + + ASSERT(FibContext->Fib == Fib); + + // + // Remove this FibContext from the Outstanding I/O queue. + // But only if it has not already been timed out. + // + // If the fib has been timed out already, then just continue. + // The caller has already been notified that the fib timed out. + // + + if (!(FibContext->Flags & FIB_CONTEXT_FLAG_TIMED_OUT)) { + + RemoveEntryList( &FibContext->QueueEntry ); + Adapter->CommRegion->AdapNormCmdQue.NumOutstandingIos--; + + } else { + + FsaCommLogEvent(FibContext, + FsaCommData.DeviceObject, + FSAFS_TIMED_OUT_FIB_COMPLETED, + STATUS_UNSUCCESSFUL, + BugCheckFileId | __LINE__, + FACILITY_FSAFS_ERROR_CODE, + NULL, + TRUE); + + continue; + + } + + OsSpinLockRelease( OurQueue->QueueLock ); + + if (IsFastResponse) { + + // + // doctor the fib + // + + *(FSASTATUS *)Fib->data = ST_OK; + + Fib->Header.XferState |= AdapterProcessed; + + } + +#ifdef GATHER_FIB_TIMES + if (GatherFibTimes) { + + LARGE_INTEGER FibTime, FibTimeDelta; + LARGE_INTEGER AdapterFibTimeDelta; + PFIB_TIMES FibTimesPtr; + ULONG Index; + ULONG LowAdapterFibTimeDelta; + + FibTimesPtr = FibContext->FibTimesPtr; + + FibTime.QuadPart = KeQueryPerformanceCounter(NULL).QuadPart >> 7; + + FibTimeDelta = RtlLargeIntegerSubtract(FibTime, FibContext->FibTimeStamp); + + if (RtlLargeIntegerLessThan(FibTimeDelta, FibTimesPtr->Minimum)) { + FibTimesPtr->Minimum = FibTimeDelta; + } + if (RtlLargeIntegerGreaterThan(FibTimeDelta, FibTimesPtr->Maximum)) { + FibTimesPtr->Maximum = FibTimeDelta; + } + + FibTimesPtr->TotalTime = RtlLargeIntegerAdd(FibTimesPtr->TotalTime, FibTimeDelta); + FibTimesPtr->TotalFibs = RtlLargeIntegerAdd(FibTimesPtr->TotalFibs, RtlConvertLongToLargeInteger(1)); + + if (Fib->Header.ReceiverTimeDone > Fib->Header.ReceiverTimeStart) { + AdapterFibTimeDelta = RtlConvertLongToLargeInteger(Fib->Header.ReceiverTimeDone - Fib->Header.ReceiverTimeStart); + } else { + AdapterFibTimeDelta = RtlConvertLongToLargeInteger(Fib->Header.ReceiverTimeDone + + ((ULONG)(0xffffffff) - Fib->Header.ReceiverTimeStart)); + } + + if (RtlLargeIntegerLessThan(AdapterFibTimeDelta, FibTimesPtr->AdapterMinimum)) { + FibTimesPtr->AdapterMinimum = AdapterFibTimeDelta; + } + if (RtlLargeIntegerGreaterThan(AdapterFibTimeDelta, FibTimesPtr->AdapterMaximum)) { + FibTimesPtr->AdapterMaximum = AdapterFibTimeDelta; + } + + FibTimesPtr->AdapterTotalTime = RtlLargeIntegerAdd(FibTimesPtr->AdapterTotalTime, AdapterFibTimeDelta); + + if (GatherFibTimes == 1) { + LowAdapterFibTimeDelta = AdapterFibTimeDelta.LowPart; + } else { + LowAdapterFibTimeDelta = FibTimeDelta.LowPart; + } + + if ((LowAdapterFibTimeDelta & 0xffffff00) == 0) { + + Index = (LowAdapterFibTimeDelta & 0xf0) >> 4; + + } else if ((LowAdapterFibTimeDelta & 0xfffff000) == 0) { + + Index = 16 + ((LowAdapterFibTimeDelta & 0xf00) >> 8); + + } else if ((LowAdapterFibTimeDelta & 0xffff0000) == 0) { + + Index = 32 + ((LowAdapterFibTimeDelta & 0xf000) >> 12); + + } else if ((LowAdapterFibTimeDelta & 0xfff00000) == 0) { + + Index = 48 + ((LowAdapterFibTimeDelta & 0xf0000) >> 16); + + } else { + Index = 64; + } + + FibTimesPtr->AdapterBuckets[Index]++; + + } +#endif + + ASSERT((Fib->Header.XferState & (AdapterProcessed | HostOwned | SentFromHost)) == (AdapterProcessed | HostOwned | SentFromHost)); + + FIB_COUNTER_INCREMENT(FsaCommData.FibRecved); + + ASSERT(FsaCommData.FibsSent >= FsaCommData.FibRecved); + + + if (Fib->Header.Command == NuFileSystem) { + + FSASTATUS *pStatus = (FSASTATUS *)Fib->data; + + if (*pStatus & 0xffff0000) { + + ULONG Hint = *pStatus; + + *pStatus = ST_OK; + +/* + DbgPrint("Replacing hint in fid (drive = %d, f1 = 0x%x, f2 = 0x%x, hint = 0x%x, new_hint = 0x%x)\n", + IrpContext->NonPaged->FileId.fid_driveno, + IrpContext->NonPaged->FileId.fid_f1, + IrpContext->NonPaged->FileId.fid_f2, + IrpContext->NonPaged->FileId.fid_hint, + Hint); +*/ + + } + + } + + if (Fib->Header.XferState & (NoResponseExpected | Async) ) { + + ASSERT(FibContext->FibCallback); + + if (Fib->Header.XferState & NoResponseExpected) + FIB_COUNTER_INCREMENT(FsaCommData.NoResponseRecved); + else + FIB_COUNTER_INCREMENT(FsaCommData.AsyncRecved); + + // + // NOTE: we can not touch the FibContext after this call, because it may have been + // deallocated. + // + + FibContext->FibCallback(FibContext->FibCallbackContext, FibContext, STATUS_SUCCESS); + + } else { + + OsCvLockAcquire( FibContext->FsaEventMutex); + + FibContext->FibComplete = 1; + + OsCv_signal( &FibContext->FsaEvent ); + + OsCvLockRelease( FibContext->FsaEventMutex ); + + FIB_COUNTER_INCREMENT(FsaCommData.NormalRecved); + + } + + + Consumed++; + + OsSpinLockAcquire( OurQueue->QueueLock ); + + } + + if (Consumed > FsaCommData.PeakFibsConsumed) + FsaCommData.PeakFibsConsumed = Consumed; + + if (Consumed == 0) + FsaCommData.ZeroFibsConsumed++; + + if (FsaCommData.HardInterruptModeration) { + + // + // Re-Enable the interrupt from the adapter, then recheck to see if anything has + // been put on the queue. This removes the race condition that exists between the + // last time we checked the queue, and when we re-enabled the interrupt. + // + // If there is something on the queue, then go handle it. + // + + EnableInterrupt( Adapter, HostNormRespQue, FALSE ); + + if (ConsumerEntryAvailable( Adapter, OurQueue ) ) { + + DisableInterrupt( Adapter, HostNormRespQue, FALSE ); + + goto loop; + + } + } + +#ifdef commdebug + FsaCommPrint("Exiting host normal reponse dpc routine after consuming %d QE(s).\n",Consumed); +#endif + + OsSpinLockRelease( OurQueue->QueueLock ); + +} + +u_int +HostResponseHighDpc( + IN PCOMM_QUE OurQueue + ) +/*++ + +Routine Description: + + This DPC routine wiol be queued when the adapter interrupts us to let us know there + is a response on our high priority queue. We will pull off all QE there are and wake + up all the waiters before exiting. We will take a spinlock out on the queue before operating + on it. + +Arguments: + + Dpc - Pointer to this routine. + + OurQueue is a pointer to the queue structure we will operate on. + + MoreData1&2 are DPC parameters we don't need for this function. Maybe we can add some accounting + stuff in here. + +Return Value: + Nothing. + +--*/ +{ +} + +u_int +HostCommandHighDpc( + IN PCOMM_QUE OurQueue + ) +/*++ + +Routine Description: + + This DPC routine will be queued when the adapter interrupts us to let us know there + is a command on our high priority queue. We will pull off all QE there are and wake + up all the waiters before exiting. We will take a spinlock out on the queue before operating + on it. + +Arguments: + + Dpc - Pointer to this routine. + + OurQueue is a pointer to the queue structure we will operate on. + + MoreData1&2 are DPC parameters we don't need for this function. Maybe we can add some accounting + stuff in here. + +Return Value: + Nothing. + +--*/ +{ +} + + +u_int +HostCommandNormDpc( + IN PCOMM_QUE OurQueue + ) +/*++ + +Routine Description: + + This DPC routine will be queued when the adapter interrupts us to let us know there + is a command on our normal priority queue. We will pull off all QE there are and wake + up all the waiters before exiting. We will take a spinlock out on the queue before operating + on it. + +Arguments: + + Dpc - Pointer to this routine. + + OurQueue is a pointer to the queue structure we will operate on. + + MoreData1&2 are DPC parameters we don't need for this function. Maybe we can add some accounting + stuff in here. + +Return Value: + Nothing. + +--*/ +{ + PAFA_COMM_ADAPTER Adapter = OurQueue->Adapter; + PQUEUE_ENTRY QueueEntry; + + OsSpinLockAcquire( OurQueue->QueueLock ); + + // + // Keep pulling response QEs off the response queue and waking + // up the waiters until there are no more QEs. We then return + // back to the system. + // + + while ( GetConsumerEntry( Adapter, OurQueue, &QueueEntry) ) { + + PFIB Fib; + + Fib = (PFIB)QueueEntry->FibAddress; + + + if (Adapter->AifThreadStarted) { + + +// cmn_err(CE_CONT, "^Received AIF, putting onto command queue\n"); + + + InsertTailList(&OurQueue->CommandQueue, &Fib->Header.FibLinks); + FreeConsumerEntry(Adapter, OurQueue, HostNormCmdQueue); + OsCv_signal(&OurQueue->CommandReady); + + + + } else { + + + + COMM_FIB_CONTEXT FibContext; + + + + FreeConsumerEntry(Adapter, OurQueue, HostNormCmdQueue); + + + + OsSpinLockRelease( OurQueue->QueueLock ); + + + +// cmn_err(CE_CONT, "^Received AIF, thread not started\n"); + + + RtlZeroMemory( &FibContext, sizeof(COMM_FIB_CONTEXT) ); + + FibContext.NodeTypeCode = FSAFS_NTC_FIB_CONTEXT; + FibContext.NodeByteSize = sizeof( COMM_FIB_CONTEXT ); + FibContext.Fib = Fib; + FibContext.FibData = Fib->data; + FibContext.Adapter = Adapter; + + // + // Set the status of this FIB + // + + *(FSASTATUS *)Fib->data = ST_OK; + + CompleteAdapterFib( &FibContext, sizeof(FSASTATUS) ); + + + + OsSpinLockAcquire( OurQueue->QueueLock ); + } + } + + OsSpinLockRelease( OurQueue->QueueLock ); + +} --- linux/drivers/scsi/aacraid/include/AacGenericTypes.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/AacGenericTypes.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,54 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * + * AacGenericTypes.h + * + * Abstract: + * + * The module defines the generic data types that all of the other header files + * depend upon. + --*/ +#ifndef _AAC_GENERIC_TYPES +#define _AAC_GENERIC_TYPES + +typedef char AAC_INT8, *PAAC_INT8; +typedef short AAC_INT16, *PAAC_INT16; +typedef int AAC_INT32, *PAAC_INT32; +typedef long long AAC_INT64, *PAAC_INT64; + +typedef unsigned char AAC_UINT8, *PAAC_UINT8; +typedef unsigned short AAC_UINT16, *PAAC_UINT16; +typedef unsigned int AAC_UINT32, *PAAC_UINT32; +typedef unsigned long long AAC_UINT64, *PAAC_UINT64; + +typedef void AAC_VOID, *PAAC_VOID; + +// +// this compiler uses 32 bit enum data types +// + +#define AAC_32BIT_ENUMS 1 +#define FAILURE 1 +#define INTR_UNCLAIMED 1 +#define INTR_CLAIMED 0 + +#endif // _AAC_GENERIC_TYPES + --- linux/drivers/scsi/aacraid/include/aac_unix_defs.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/aac_unix_defs.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,298 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * + * aac_unix_defs.h + * + * Abstract: + * + * Macro definition and typedefs + * + --*/ + +#ifndef _AAC_UNIX_DEFS +#define _AAC_UNIX_DEFS + +#define AAC_MAX_ADAPTERS 64 + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#define PAGE_SIZE 4096 + +typedef void VOID; +typedef VOID *PVOID; + +typedef char CHAR, *PCHAR; +typedef unsigned char UCHAR, *PUCHAR; +typedef short SHORT, *PSHORT; +typedef short CSHORT, *PCSHORT; +typedef unsigned short USHORT, *PUSHORT; +typedef unsigned long ULONG, *PULONG; +typedef long LONG, *PLONG; + +typedef unsigned long BOOLEAN; + +typedef unsigned long AAC_STATUS, *PNT_STATUS; + +typedef struct { + unsigned long LowPart; + unsigned long HighPart; +} LARGE_INTEGER; + +typedef LARGE_INTEGER PHYSICAL_ADDRESS; + + +typedef struct _AFA_IOCTL_CMD { + int cmd; + intptr_t arg; + int flag; + cred_t *cred_p; + int *rval_p; +} AFA_IOCTL_CMD, *PAFA_IOCTL_CMD; + + +// +// Singly linked list structure. Can be used as either a list head, or +// as link words. +// + +typedef struct _SINGLE_LIST_ENTRY { + struct _SINGLE_LIST_ENTRY *Next; +} SINGLE_LIST_ENTRY, *PSINGLE_LIST_ENTRY; + + +// +// Calculate the address of the base of the structure given its type, and an +// address of a field within the structure. +// + +#define CONTAINING_RECORD(address, type, field) ((type *)( \ + (PCHAR)(address) - \ + (PCHAR)(&((type *)0)->field))) + +typedef PVOID PMDL; +typedef PVOID PDEVICE_OBJECT; +typedef PVOID PADAPTER_OBJECT; +typedef ULONG KIRQL; +typedef PVOID HANDLE; +typedef PVOID KDPC, *PKDPC; +typedef PVOID PFILE_OBJECT; +typedef PVOID PIRP; +typedef PVOID PDRIVER_OBJECT; +typedef ULONG KTIMER; + + +#define STATUS_SUCCESS 0x00000000 +#define STATUS_PENDING 0x40000001 +#define STATUS_IO_TIMEOUT 0xc0000001 +#define STATUS_UNSUCCESSFUL 0xc0000002 +#define STATUS_INSUFFICIENT_RESOURCES 0xc0000005 +#define STATUS_BUFFER_OVERFLOW 0xc0000003 + + +#define OUT + + + +typedef u_int +(*PUNIX_INTR_HANDLER)(caddr_t Arg); + +// +// Zone Allocation +// + +typedef struct _ZONE_SEGMENT_HEADER { + SINGLE_LIST_ENTRY SegmentList; + PVOID Reserved; +} ZONE_SEGMENT_HEADER, *PZONE_SEGMENT_HEADER; + +typedef struct _ZONE_HEADER { + SINGLE_LIST_ENTRY FreeList; + SINGLE_LIST_ENTRY SegmentList; + ULONG BlockSize; + ULONG TotalSegmentSize; +} ZONE_HEADER, *PZONE_HEADER; + + +//++ +// +// PVOID +// ExAllocateFromZone( +// IN PZONE_HEADER Zone +// ) +// +// Routine Description: +// +// This routine removes an entry from the zone and returns a pointer to it. +// +// Arguments: +// +// Zone - Pointer to the zone header controlling the storage from which the +// entry is to be allocated. +// +// Return Value: +// +// The function value is a pointer to the storage allocated from the zone. +// +//-- + +#define ExAllocateFromZone(Zone) \ + (PVOID)((Zone)->FreeList.Next); \ + if ( (Zone)->FreeList.Next ) (Zone)->FreeList.Next = (Zone)->FreeList.Next->Next + +//++ +// +// PVOID +// ExFreeToZone( +// IN PZONE_HEADER Zone, +// IN PVOID Block +// ) +// +// Routine Description: +// +// This routine places the specified block of storage back onto the free +// list in the specified zone. +// +// Arguments: +// +// Zone - Pointer to the zone header controlling the storage to which the +// entry is to be inserted. +// +// Block - Pointer to the block of storage to be freed back to the zone. +// +// Return Value: +// +// Pointer to previous block of storage that was at the head of the free +// list. NULL implies the zone went from no available free blocks to +// at least one free block. +// +//-- + +#define ExFreeToZone(Zone,Block) \ + ( ((PSINGLE_LIST_ENTRY)(Block))->Next = (Zone)->FreeList.Next, \ + (Zone)->FreeList.Next = ((PSINGLE_LIST_ENTRY)(Block)), \ + ((PSINGLE_LIST_ENTRY)(Block))->Next \ + ) + +//++ +// +// BOOLEAN +// ExIsFullZone( +// IN PZONE_HEADER Zone +// ) +// +// Routine Description: +// +// This routine determines if the specified zone is full or not. A zone +// is considered full if the free list is empty. +// +// Arguments: +// +// Zone - Pointer to the zone header to be tested. +// +// Return Value: +// +// TRUE if the zone is full and FALSE otherwise. +// +//-- + +#define ExIsFullZone(Zone) \ + ( (Zone)->FreeList.Next == (PSINGLE_LIST_ENTRY)NULL ) + + +#define RtlCopyMemory( Destination, Source, Size ) bcopy( (Source), (Destination), (Size) ) +#define RtlZeroMemory( Destination, Size ) bzero( (Destination), (Size) ) + +// +// Doubly-linked list manipulation routines. Implemented as macros +// but logically these are procedures. +// + +// +// VOID +// InitializeListHead( +// PLIST_ENTRY ListHead +// ); +// + +#define InitializeListHead(ListHead) (\ + (ListHead)->Flink = (ListHead)->Blink = (ListHead)) + +// +// BOOLEAN +// IsListEmpty( +// PLIST_ENTRY ListHead +// ); +// + +#define IsListEmpty(ListHead) \ + ((ListHead)->Flink == (ListHead)) + +// +// PLIST_ENTRY +// RemoveHeadList( +// PLIST_ENTRY ListHead +// ); +// + +#define RemoveHeadList(ListHead) \ + (ListHead)->Flink;\ + {RemoveEntryList((ListHead)->Flink)} + + +// +// VOID +// RemoveEntryList( +// PLIST_ENTRY Entry +// ); +// + +#define RemoveEntryList(Entry) {\ + PLIST_ENTRY _EX_Blink;\ + PLIST_ENTRY _EX_Flink;\ + _EX_Flink = (Entry)->Flink;\ + _EX_Blink = (Entry)->Blink;\ + _EX_Blink->Flink = _EX_Flink;\ + _EX_Flink->Blink = _EX_Blink;\ + } + +// +// VOID +// InsertTailList( +// PLIST_ENTRY ListHead, +// PLIST_ENTRY Entry +// ); +// + +#define InsertTailList(ListHead,Entry) {\ + PLIST_ENTRY _EX_Blink;\ + PLIST_ENTRY _EX_ListHead;\ + _EX_ListHead = (ListHead);\ + _EX_Blink = _EX_ListHead->Blink;\ + (Entry)->Flink = _EX_ListHead;\ + (Entry)->Blink = _EX_Blink;\ + _EX_Blink->Flink = (Entry);\ + _EX_ListHead->Blink = (Entry);\ + } + +#endif /* AAC_UNIX_DEFS */ --- linux/drivers/scsi/aacraid/include/adapter.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/adapter.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,175 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * + * Adapter.h + * + * Abstract: + * The module contains the definitions for a comm layer view of the adapter. + * + * + * + --*/ + +#ifndef _ADAPTER_ +#define _ADAPTER_ + + +typedef struct _GET_ADAPTER_FIB_CONTEXT { + + NODE_TYPE_CODE NodeTypeCode; // used for verification of structure + NODE_BYTE_SIZE NodeByteSize; + PFILE_OBJECT FileObject; // used for cleanup + LIST_ENTRY NextContext; // used to link context's into a linked list + OS_CV_T UserEvent; // this is used to wait for the next fib to arrive. + BOOLEAN WaitingForFib; // Set to true when thread is in WaitForSingleObject + ULONG FibCount; // total number of FIBs on FibList + LIST_ENTRY FibList; +} GET_ADAPTER_FIB_CONTEXT; +typedef GET_ADAPTER_FIB_CONTEXT *PGET_ADAPTER_FIB_CONTEXT; + + +typedef struct _FIB_CONTEXT_ZONE_SEGMENT { + + struct _FIB_CONTEXT_ZONE_SEGMENT *Next; + ULONG FibContextSegmentSize; + PVOID FibContextSegment; + ULONG ExtendSize; + MAPFIB_CONTEXT MapFibContext; + +} FIB_CONTEXT_ZONE_SEGMENT; +typedef FIB_CONTEXT_ZONE_SEGMENT *PFIB_CONTEXT_ZONE_SEGMENT; + +typedef struct _AFA_COMM_ADAPTER { + + struct _AFA_COMM_ADAPTER *NextAdapter; + + // + // The following fields are used to allocate FIB context structures + // using the zone allocator, and other fixed sized structures from a + // small cache. The mutex protects access to the zone/lists + // + + ZONE_HEADER FibContextZone; + OS_SPINLOCK *FibContextZoneSpinLock; + int FibContextZoneExtendSize; + + PFIB_CONTEXT_ZONE_SEGMENT FibContextSegmentList; + + PVOID FibContextTimedOutList; + + PFIB SyncFib; + ULONG SyncFibPhysicalAddress; + + PCOMM_REGION CommRegion; + + OS_SPINLOCK_COOKIE SpinLockCookie; + +// UNICODE_STRING TimeoutString; + +#ifdef GATHER_FIB_TIMES + // + // The following contains detailed timings of round trip to the adapter + // depending on which Fib type + // + + PALL_FIB_TIMES FibTimes; + LARGE_INTEGER FibTimesFrequency; +#endif + + // + // The user API will use an IOCTL to register itself to receive FIBs + // from the adapter. The following list is used to keep track of all + // the threads that have requested these FIBs. The mutex is used to + // synchronize access to all data associated with the adapter fibs. + // + LIST_ENTRY AdapterFibContextList; + OS_CVLOCK *AdapterFibMutex; + + // + // The following holds which FileObject is allow to send configuration + // commands to the adapter that would modify the configuration. + // + // This is controlled by the FSACTL_OPEN_ADAPTER_CONFIG and FSACTL_CLOSE_ADAPTER_CONFIG + // ioctls. + // + PFILE_OBJECT AdapterConfigFileObject; + + // + // The following is really here because of the simulator + // + BOOLEAN InterruptsBelowDpc; + + // + // The following is the device specific extension. + // + PVOID AdapterExtension; + PFSAPORT_FUNCS AdapterFuncs; + void *Dip; + + // + // The following are user variables that are specific to the mini port. + // + PFSA_USER_VAR AdapterUserVars; + ULONG AdapterUserVarsSize; + + // + // The following is the number of the individual adapter..i.e. \Device\Afa0 + // + LONG AdapterNumber; + + AFACOMM_FUNCS CommFuncs; + + PAFA_CLASS_DRIVER ClassDriverList; + + BOOLEAN AifThreadStarted; + +} AFA_COMM_ADAPTER; + +typedef AFA_COMM_ADAPTER *PAFA_COMM_ADAPTER; + + +#define FsaAllocateAdapterCommArea(Adapter, BaseAddress, Size, Alignment) \ + Adapter->AdapterFuncs->AllocateAdapterCommArea(Adapter->AdapterExtension, BaseAddress, Size, Alignment) + +#define FsaFreeAdapterCommArea(Adapter) \ + Adapter->AdapterFuncs->FreeAdapterCommArea(Adapter->AdapterExtension) + + +#define AllocateAndMapFibSpace(Adapter, MapFibContext) \ + Adapter->AdapterFuncs->AllocateAndMapFibSpace(Adapter->AdapterExtension, MapFibContext) + +#define UnmapAndFreeFibSpace(Adapter, MapFibContext) \ + Adapter->AdapterFuncs->UnmapAndFreeFibSpace(Adapter->AdapterExtension, MapFibContext) + +#define InterruptAdapter(Adapter) \ + Adapter->AdapterFuncs->InterruptAdapter(Adapter->AdapterExtension) + +#define NotifyAdapter(Adapter, AdapterEvent) \ + Adapter->AdapterFuncs->NotifyAdapter(Adapter->AdapterExtension, AdapterEvent) + +#define EnableInterrupt(Adapter, AdapterEvent, AtDeviceIrq) \ + Adapter->AdapterFuncs->EnableInterrupt(Adapter->AdapterExtension, AdapterEvent, AtDeviceIrq) + +#define DisableInterrupt(Adapter, AdapterEvent, AtDeviceIrq) \ + Adapter->AdapterFuncs->DisableInterrupt(Adapter->AdapterExtension, AdapterEvent, AtDeviceIrq) + + +#endif // _ADAPTER_ --- linux/drivers/scsi/aacraid/include/afacomm.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/afacomm.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,189 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * AfaComm.h + * + * Abstract: + * This module defines all of the external interfaces to the AFA comm layer. + * + * + * + --*/ +#ifndef _AFACOMM_ +#define _AFACOMM_ + +#include "fsaport.h" + +typedef void *PFIB_CONTEXT; + +typedef VOID +(*PFIB_CALLBACK)( + PVOID FibCallbackContext, + PFIB_CONTEXT FibContext, + AAC_STATUS Status + ); + + +typedef PFIB_CONTEXT +(*PAFA_COMM_ALLOCATE_FIB) ( + IN PVOID AdapterExtension + ); + +typedef VOID +(*PAFA_COMM_FREE_FIB) ( + IN PFIB_CONTEXT FibContext + ); + + +typedef AAC_STATUS +(*PAFA_COMM_DEALLOCATE_FIB) ( + IN PFIB_CONTEXT FibContext + ); + + +typedef VOID +(*PAFA_COMM_FREE_FIB_FROM_DPC) ( + IN PFIB_CONTEXT FibContext + ); + +typedef AAC_STATUS +(*PAFA_COMM_INITIALIZE_FIB) ( + IN PFIB_CONTEXT FibContext + ); + +typedef PVOID +(*PAFA_COMM_GET_FIB_DATA) ( + IN PFIB_CONTEXT FibContext + ); + +typedef AAC_STATUS +(*PAFA_COMM_SEND_FIB) ( + IN FIB_COMMAND Command, + IN PFIB_CONTEXT FibContext, + IN ULONG Size, + IN COMM_PRIORITIES Priority, + IN BOOLEAN Wait, + IN PVOID WaitOn, + IN BOOLEAN ResponseExpected, + IN PFIB_CALLBACK FibCallback, + IN PVOID FibCallbackContext + ); + +typedef AAC_STATUS +(*PAFA_COMM_COMPLETE_FIB) ( + IN PFIB_CONTEXT FibContext + ); + +typedef AAC_STATUS +(*PAFA_COMM_COMPLETE_ADAPTER_FIB) ( + IN PFIB_CONTEXT FibContext, + IN USHORT Size + ); + +typedef BOOLEAN +(*PAFA_COMM_SEND_SYNCH_FIB) ( + PVOID AdapterExtension, + FIB_COMMAND Command, + PVOID Data, + USHORT Size, + PVOID Response, + USHORT *ResponseSize + ); + + +typedef struct _AFACOMM_FUNCS { + ULONG SizeOfAfaCommFuncs; + PAFA_COMM_ALLOCATE_FIB AllocateFib; + PAFA_COMM_FREE_FIB FreeFib; + PAFA_COMM_FREE_FIB_FROM_DPC FreeFibFromDpc; + PAFA_COMM_DEALLOCATE_FIB DeallocateFib; + PAFA_COMM_INITIALIZE_FIB InitializeFib; + PAFA_COMM_GET_FIB_DATA GetFibData; + PAFA_COMM_SEND_FIB SendFib; + PAFA_COMM_COMPLETE_FIB CompleteFib; + PAFA_COMM_COMPLETE_ADAPTER_FIB CompleteAdapterFib; + PAFA_COMM_SEND_SYNCH_FIB SendSynchFib; + PFSA_FREE_DMA_RESOURCES FreeDmaResources; + PFSA_BUILD_SGMAP BuildSgMap; + PFSA_ADAPTER_ADDR_TO_SYSTEM_ADDR AdapterAddressToSystemAddress; +} AFACOMM_FUNCS; +typedef AFACOMM_FUNCS *PAFACOMM_FUNCS; + + +typedef AAC_STATUS +(*PAFA_CLASS_OPEN_ADAPTER) ( + IN PVOID Adapter + ); + + +typedef AAC_STATUS +(*PAFA_CLASS_CLOSE_ADAPTER) ( + IN PVOID Adapter + ); + + +typedef BOOLEAN +(*PAFA_CLASS_DEV_CONTROL) ( + IN PVOID Adapter, + IN PAFA_IOCTL_CMD IoctlCmdPtr, + OUT int * Status + ); + +typedef BOOLEAN +(*PAFA_CLASS_HANDLE_AIF) ( + IN PVOID Adapter, + IN PFIB_CONTEXT FibContext + ); + + +typedef struct _AFA_NEW_CLASS_DRIVER { + PVOID ClassDriverExtension; + PAFA_CLASS_OPEN_ADAPTER OpenAdapter; + PAFA_CLASS_CLOSE_ADAPTER CloseAdapter; + PAFA_CLASS_DEV_CONTROL DeviceControl; + PAFA_CLASS_HANDLE_AIF HandleAif; + PFSA_USER_VAR UserVars; + ULONG NumUserVars; +} AFA_NEW_CLASS_DRIVER; +typedef AFA_NEW_CLASS_DRIVER *PAFA_NEW_CLASS_DRIVER; + + +typedef struct _AFA_NEW_CLASS_DRIVER_RESPONSE { + PAFACOMM_FUNCS CommFuncs; + PVOID CommPortExtension; + PVOID MiniPortExtension; + OS_SPINLOCK_COOKIE SpinLockCookie; + void *Dip; +} AFA_NEW_CLASS_DRIVER_RESPONSE; +typedef AFA_NEW_CLASS_DRIVER_RESPONSE *PAFA_NEW_CLASS_DRIVER_RESPONSE; + + +typedef struct _AFA_CLASS_DRIVER { + struct _AFA_CLASS_DRIVER *Next; + PVOID ClassDriverExtension; + PAFA_CLASS_OPEN_ADAPTER OpenAdapter; + PAFA_CLASS_CLOSE_ADAPTER CloseAdapter; + PAFA_CLASS_DEV_CONTROL DeviceControl; + PAFA_CLASS_HANDLE_AIF HandleAif; +} AFA_CLASS_DRIVER; +typedef AFA_CLASS_DRIVER *PAFA_CLASS_DRIVER; + + +#endif // _AFACOMM_ --- linux/drivers/scsi/aacraid/include/aifstruc.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/aifstruc.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,317 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * Aifstruc.h + * + * Abstract: + * Define all shared data types relating to + * the set of features utilizing Adapter + * Initiated Fibs. + * + * + * + --*/ +#ifndef _AIFSTRUC_H +#define _AIFSTRUC_H + +#include + +// +// 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 + + + --- linux/drivers/scsi/aacraid/include/build_number.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/build_number.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,38 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * build_number.h + * + * Abstract: + * DThis module contains the single location where the build number + * is kept. + * + * + * + --*/ +#ifndef _BUILD_NUMBER_H +#define _BUILD_NUMBER_H + + +#define REV_BUILD_NUMBER 3911 + + +#endif // _BUILD_NUMBER_H + --- linux/drivers/scsi/aacraid/include/commdata.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/commdata.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,110 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * commdata.h + * + * Abstract: Define the communication layer of the adapter + * + * + * + --*/ +#ifndef _COMMDATA_ +#define _COMMDATA_ + +typedef struct _FSA_COMM_DATA { + + // + // A pointer to the Driver and Device object we were initialized with + // + + PDRIVER_OBJECT DriverObject; + PDEVICE_OBJECT DeviceObject; + + // + // A list of all adapters we have configured. + // + + PAFA_COMM_ADAPTER AdapterList; + ULONG TotalAdapters; + + // + // Adapter timeout support. This is the default timeout to wait for the + // adapter to respond(setup in initfs.c), and a boolean to indicate if + // we should timeout requests to the adapter or not. + // + + LARGE_INTEGER QueueFreeTimeout; + LARGE_INTEGER AdapterTimeout; + BOOLEAN EnableAdapterTimeouts; + + ULONG FibTimeoutIncrement; + + ULONG FibsSent; + ULONG FibRecved; + ULONG NoResponseSent; + ULONG NoResponseRecved; + ULONG AsyncSent; + ULONG AsyncRecved; + ULONG NormalSent; + ULONG NormalRecved; + + ULONG TimedOutFibs; + + KDPC TimeoutDPC; + KTIMER TimeoutTimer; + + // + // If this value is set to 1 then interrupt moderation will occur + // in the base commuication support. + // + + ULONG EnableInterruptModeration; + + int HardInterruptModeration; + int HardInterruptModeration1; + int PeakFibsConsumed; + int ZeroFibsConsumed; + int EnableFibTimeoutBreak; + ULONG FibTimeoutSeconds; + + // + // The following holds all of the available user settable variables. + // This includes all for the comm layer as well as any from the class + // drivers as well. + // + + FSA_USER_VAR *UserVars; + ULONG NumUserVars; + + + ULONG MeterFlag; + +#ifdef FIB_CHECKSUMS + int do_fib_checksums; +#endif + +} FSA_COMM_DATA; +typedef FSA_COMM_DATA *PFSA_COMM_DATA; + +extern FSA_COMM_DATA FsaCommData; + + +#endif // _COMMDATA_ + --- linux/drivers/scsi/aacraid/include/commerr.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/commerr.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,122 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * commerr.h + * + * Abstract: This file defines all errors that are unique to the Adaptec Fsa Filesystem + * + * + * + --*/ + +#ifndef _FSAERR_ +#define _FSAERR_ +// +// Note: comments in the .mc file must use both ";" and "//". +// +// Status values are 32 bit values layed out as follows: +// +// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 +// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +---+-+-------------------------+-------------------------------+ +// |Sev|C| Facility | Code | +// +---+-+-------------------------+-------------------------------+ +// +// where +// +// Sev - is the severity code +// +// 00 - Success +// 01 - Informational +// 10 - Warning +// 11 - Error +// +// C - is the Customer code flag +// +// Facility - is the facility code +// +// Code - is the facility's status code +// + + +// +// %1 is reserved by the IO Manager. If IoAllocateErrorLogEntry is +// called with a device, the name of the device will be inserted into +// the message at %1. Otherwise, the place of %1 will be left empty. +// In either case, the insertion strings from the driver's error log +// entry starts at %2. In other words, the first insertion string goes +// to %2, the second to %3 and so on. +// + +// +// Values are 32 bit values layed out as follows: +// +// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 +// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +---+-+-+-----------------------+-------------------------------+ +// |Sev|C|R| Facility | Code | +// +---+-+-+-----------------------+-------------------------------+ +// +// where +// +// Sev - is the severity code +// +// 00 - Success +// 01 - Informational +// 10 - Warning +// 11 - Error +// +// C - is the Customer code flag +// +// R - is a reserved bit +// +// Facility - is the facility code +// +// Code - is the facility's status code +// +// +// Define the facility codes +// + + +#define FACILITY_FSAFS_ERROR_CODE 0x7 + + + +// +// MessageId: FSAFS_FIB_INVALID +// +// MessageText: +// +// A communication packet was detected to be formatted poorly. Please Contact Adaptec support. +// +#define FSAFS_FIB_INVALID ((AAC_STATUS)0xE0070009L) + + +// +// MessageId: FSAFS_TIMED_OUT_FIB_COMPLETED +// +// MessageText: +// +// A Fib previously timed out by host has been completed by the adapter. (\\.\Afa%2) +// +#define FSAFS_TIMED_OUT_FIB_COMPLETED ((AAC_STATUS)0xA007000EL) + +#endif _FSAERR_ --- linux/drivers/scsi/aacraid/include/commfibcontext.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/commfibcontext.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,96 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * commfibcontext.h + * + * Abstract: defines the _COMM_FIB_CONTEXT strcuture + * + * + * + --*/ +#ifndef _COMM_FIB_CONTEXT_ +#define _COMM_FIB_CONTEXT_ + +typedef struct _COMM_FIB_CONTEXT { + + PVOID Next; // this is used by the zone allocation + + // + // Type and size of this record (must be FSA_NTC_FIB_CONTEXT) + // + // NOTE: THIS STRUCTURE MUST REMAIN 64-bit ALIGNED IN SIZE, SINCE + // IT IS ZONE ALLOCATED, AND REPINNED_BCBS_ARRAY_SIZE AFFECTS + // ITS SIZE. + // + + NODE_TYPE_CODE NodeTypeCode; + NODE_BYTE_SIZE NodeByteSize; + + // + // The Adapter that this I/O is destined for. + // + + PAFA_COMM_ADAPTER Adapter; + + PHYSICAL_ADDRESS LogicalFibAddress; + + // + // This is the event the sendfib routine will wait on if the + // caller did not pass one and this is synch io. + // + + OS_CV_T FsaEvent; + OS_CVLOCK *FsaEventMutex; + + ULONG FibComplete; // gets set to 1 when fib is complete + + PFIB_CALLBACK FibCallback; + PVOID FibCallbackContext; + + ULONG Flags; + + +#ifdef GATHER_FIB_TIMES + LARGE_INTEGER FibTimeStamp; + PFIB_TIMES FibTimesPtr; +#endif + + // + // The following is used to put this fib context onto the Outstanding I/O queue. + // + + LIST_ENTRY QueueEntry; + + // + // The following is used to timeout a fib to the adapter. + // + + LARGE_INTEGER TimeoutValue; + + PVOID FibData; + + PFIB Fib; + +} COMM_FIB_CONTEXT; +typedef COMM_FIB_CONTEXT *PCOMM_FIB_CONTEXT; + +#define FIB_CONTEXT_FLAG_TIMED_OUT (0x00000001) + +#endif /* _COMM_FIB_CONTEXT_ */ --- linux/drivers/scsi/aacraid/include/comprocs.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/comprocs.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,91 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * comprocs.h + * + * Abstract: This module defines all of the globally used procedures in the Afa comm layer + * + * + * + --*/ +#ifndef _COMPROCS_ +#define _COMPROCS_ + +#include "osheaders.h" + +#include "AacGenericTypes.h" + +#include "aac_unix_defs.h" + +#include "nodetype.h" + +// #define GATHER_FIB_TIMES + +#include "fsatypes.h" + +#include "perfpack.h" + +#include "comstruc.h" + +//#include "unix_protocol.h" + +#include "fsact.h" + +#include "protocol.h" + +#include "fsaioctl.h" + +#undef GATHER_FIB_TIMES + +#include "aifstruc.h" + +#include "fsaport.h" +#include "comsup.h" +#include "afacomm.h" +#include "adapter.h" + +#include "commfibcontext.h" +#include "comproto.h" +#include "commdata.h" +#include "commerr.h" + + + + +// +// The following macro is used when sending and receiving FIBs. It is only used for +// debugging. + +#if DBG +#define FIB_COUNTER_INCREMENT(Counter) InterlockedIncrement(&(Counter)) +#else +#define FIB_COUNTER_INCREMENT(Counter) +#endif + + + +int +AfaCommAdapterDeviceControl ( + IN PVOID AdapterArg, + IN PAFA_IOCTL_CMD IoctlCmdPtr + ); + + +#endif // _COMPROCS_ --- linux/drivers/scsi/aacraid/include/comproto.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/comproto.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,168 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * comproto.h + * + * Abstract: Global routines for the commuication interface that are device + * independant. + * + * + * + --*/ +#ifndef _COMM_PROTO +#define _COMM_PROTO + +// +// define the routines we need so we can commuicate with the +// fsa adapter +// + +// +// The following 4 dpc routines will support commuication from the adapter to the +// host. There is one DPC routine to deal with each type of queue that supports +// commuication from the adapter. (adapter to host resposes, adapter to host commands) +// These routines will simply pull off the QE and set an event. In the case of a +// adapter to host command they will also put the FIB on a queue to be processed by +// a FS thread running at passive level. +// + +// Handle queue not full notification to the file system thread waiting for a queue entry + +u_int +CommonNotFullDpc( + IN PCOMM_REGION CommRegion + ); + +// Adapter to host normal priority responses + +u_int +HostResponseNormalDpc( + IN PCOMM_QUE OurQueue + ); + +// Adapter to host high priority responses +u_int +HostResponseHighDpc( + IN PCOMM_QUE OurQueue + ); + +// Adapter to host high priority commands +u_int +HostCommandHighDpc( + IN PCOMM_QUE OurQueue + ); + + +// Adapter to host normal priority commands +u_int +HostCommandNormDpc( + IN PCOMM_QUE OurQueue + ); + + + +BOOLEAN +SendSynchFib( + PVOID Arg, + FIB_COMMAND Command, + PVOID Data, + USHORT Size, + PVOID Response, + USHORT *ResponseSize + ); + +PFIB_CONTEXT +AllocateFib ( + IN PVOID Adapter + ); + +VOID +FreeFib ( + IN PFIB_CONTEXT FibContext + ); + +VOID +FreeFibFromDpc( + IN PFIB_CONTEXT FibContext + ); + +AAC_STATUS +DeallocateFib( + IN PFIB_CONTEXT FibContext + ); + + + +AAC_STATUS +SendFib( + IN FIB_COMMAND Command, + IN PFIB_CONTEXT FibContext, + IN ULONG Size, + IN COMM_PRIORITIES Priority, + IN BOOLEAN Wait, + IN PVOID WaitOn, + IN BOOLEAN ResponseExpected, + IN PFIB_CALLBACK FibCallback, + IN PVOID FibCallbackContext + ); + +AAC_STATUS +CompleteFib( + IN PFIB_CONTEXT FibContext + ); + +AAC_STATUS +CompleteAdapterFib( + IN PFIB_CONTEXT FibContext, + IN USHORT Size + ); + +AAC_STATUS +InitializeFib( + IN PFIB_CONTEXT FibContext + ); + + +PVOID +FsaGetFibData( + IN PFIB_CONTEXT FibContext + ); + + + +AAC_STATUS +AfaCommOpenAdapter ( + IN PVOID AdapterArg + ); + +AAC_STATUS +AfaCommCloseAdapter ( + IN PVOID AdapterArg + ); + + +VOID +AfaCommInterruptHost( + PVOID Adapter, + ADAPTER_EVENT AdapterEvent + ); + + +#endif // _COMM_PROTO --- linux/drivers/scsi/aacraid/include/comstruc.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/comstruc.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,412 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * comstruc.h + * + * Abstract: This module defines the data structures that make up the communication + * region for the FSA filesystem. This region is how the host based code + * communicates both control and data to the adapter based code. + * + * + * + --*/ +#ifndef _COMM_STRUCT +#define _COMM_STRUCT + +// +// Define all the constants needed for the communication interface +// + +// Define how many queue entries each queue will have and the total number of +// entries for the entire communication interface. Also define how many queues +// we support. + +#define NUMBER_OF_COMM_QUEUES 8 // 4 command; 4 response + +#define HOST_HIGH_CMD_ENTRIES 4 +#define HOST_NORM_CMD_ENTRIES 8 +#define ADAP_HIGH_CMD_ENTRIES 4 +#define ADAP_NORM_CMD_ENTRIES 512 +#define HOST_HIGH_RESP_ENTRIES 4 +#define HOST_NORM_RESP_ENTRIES 512 +#define ADAP_HIGH_RESP_ENTRIES 4 +#define ADAP_NORM_RESP_ENTRIES 8 + +#define TOTAL_QUEUE_ENTRIES \ + (HOST_NORM_CMD_ENTRIES + HOST_HIGH_CMD_ENTRIES + ADAP_NORM_CMD_ENTRIES + ADAP_HIGH_CMD_ENTRIES + \ + HOST_NORM_RESP_ENTRIES + HOST_HIGH_RESP_ENTRIES + ADAP_NORM_RESP_ENTRIES + ADAP_HIGH_RESP_ENTRIES) + + + + +// Set the queues on a 16 byte alignment +#define QUEUE_ALIGNMENT 16 + + +// +// The queue headers define the Communication Region queues. These +// are physically contiguous and accessible by both the adapter and the +// host. Even though all queue headers are in the same contiguous block they will be +// represented as individual units in the data structures. +// + +typedef AAC_UINT32 QUEUE_INDEX; + +typedef QUEUE_INDEX *PQUEUE_INDEX; + +typedef struct _QUEUE_ENTRY { + + AAC_UINT32 Size; // Size in bytes of the Fib which this QE points to + AAC_UINT32 FibAddress; // Receiver addressable address of the FIB (low 32 address bits) + +} QUEUE_ENTRY; + +typedef QUEUE_ENTRY *PQUEUE_ENTRY; + + + +// The adapter assumes the ProducerIndex and ConsumerIndex are grouped +// adjacently and in that order. +// +typedef struct _QUEUE_HEADERS { + + PHYSICAL_ADDRESS LogicalHeaderAddress; // Address to hand the adapter to access to this queue head + PQUEUE_INDEX ProducerIndex; // The producer index for this queue (host address) + PQUEUE_INDEX ConsumerIndex; // The consumer index for this queue (host address) + +} QUEUE_HEADERS; +typedef QUEUE_HEADERS *PQUEUE_HEADERS; + +// +// Define all the events which the adapter would like to notify +// the host of. +// +typedef enum _ADAPTER_EVENT { + HostNormCmdQue = 1, // Change in host normal priority command queue + HostHighCmdQue, // Change in host high priority command queue + HostNormRespQue, // Change in host normal priority response queue + HostHighRespQue, // Change in host high priority response queue + AdapNormRespNotFull, + AdapHighRespNotFull, + AdapNormCmdNotFull, + AdapHighCmdNotFull, + SynchCommandComplete, + AdapInternalError = 0xfe // The adapter detected an internal error shutting down + +} _E_ADAPTER_EVENT; + +#ifdef AAC_32BIT_ENUMS +typedef _E_ADAPTER_EVENT ADAPTER_EVENT; +#else +typedef AAC_UINT32 ADAPTER_EVENT; +#endif + +// +// Define all the events the host wishes to notify the +// adapter of. +// +typedef enum _HOST_2_ADAP_EVENT { + AdapNormCmdQue = 1, + AdapHighCmdQue, + AdapNormRespQue, + AdapHighRespQue, + HostShutdown, + HostPowerFail, + FatalCommError, + HostNormRespNotFull, + HostHighRespNotFull, + HostNormCmdNotFull, + HostHighCmdNotFull, + FastIo, + AdapPrintfDone +} _E_HOST_2_ADAP_EVENT; + +#ifdef AAC_32BIT_ENUMS +typedef _E_HOST_2_ADAP_EVENT HOST_2_ADAP_EVENT; +#else +typedef AAC_UINT32 HOST_2_ADAP_EVENT; +#endif + +// +// Define all the queues that the adapter and host use to communicate +// + +typedef enum _QUEUE_TYPES { + HostNormCmdQueue = 1, // Adapter to host normal priority command traffic + HostHighCmdQueue, // Adapter to host high priority command traffic + AdapNormRespQueue, // Host to adapter normal priority response traffic + AdapHighRespQueue, // Host to adapter high priority response traffic + AdapNormCmdQueue, // Host to adapter normal priority command traffic + AdapHighCmdQueue, // Host to adapter high priority command traffic + HostNormRespQueue, // Adapter to host normal priority response traffic + HostHighRespQueue // Adapter to host high priority response traffic +} _E_QUEUE_TYPES; + +#ifdef AAC_32BIT_ENUMS +typedef _E_QUEUE_TYPES QUEUE_TYPES; +#else +typedef AAC_UINT32 QUEUE_TYPES; +#endif + + +// +// Assign type values to the FSA communication data structures +// + +typedef enum _STRUCT_TYPES { + TFib = 1, + TQe, + TCtPerf +} _E_STRUCT_TYPES; + +#ifdef AAC_32BIT_ENUMS +typedef _E_STRUCT_TYPES STRUCT_TYPES; +#else +typedef AAC_UINT32 STRUCT_TYPES; +#endif + +// +// Define the priority levels the FSA communication routines support. +// + +typedef enum _COMM_PRIORITIES { + FsaNormal = 1, + FsaHigh +} _E_COMM_PRIORITIES; + +#ifdef AAC_32BIT_ENUMS +typedef _E_COMM_PRIORITIES COMM_PRIORITIES; +#else +typedef AAC_UINT32 COMM_PRIORITIES; +#endif + + + +// +// Define the LIST_ENTRY structure. This structure is used on the NT side to link +// the FIBs together in a linked list. Since this structure gets compiled on the adapter +// as well, we need to define this structure for the adapter's use. If '_NT_DEF_' +// is defined, then this header is being included from the NT side, and therefore LIST_ENTRY +// is already defined. +#if !defined(_NTDEF_) && !defined(_WINNT_) +typedef struct _LIST_ENTRY { + struct _LIST_ENTRY *Flink; + struct _LIST_ENTRY *Blink; +} LIST_ENTRY; +typedef LIST_ENTRY *PLIST_ENTRY; +#endif + + +// +// Define the FIB. The FIB is the where all the requested data and +// command information are put to the application on the FSA adapter. +// + +typedef struct _FIB_HEADER { + AAC_UINT32 XferState; // Current transfer state for this CCB + AAC_UINT16 Command; // Routing information for the destination + AAC_UINT8 StructType; // Type FIB + AAC_UINT8 Flags; // Flags for FIB + AAC_UINT16 Size; // Size of this FIB in bytes + AAC_UINT16 SenderSize; // Size of the FIB in the sender (for response sizing) + AAC_UINT32 SenderFibAddress; // Host defined data in the FIB + AAC_UINT32 ReceiverFibAddress; // Logical address of this FIB for the adapter + AAC_UINT32 SenderData; // Place holder for the sender to store data +#ifndef __midl + union { + struct { + AAC_UINT32 _ReceiverTimeStart; // Timestamp for receipt of fib + AAC_UINT32 _ReceiverTimeDone; // Timestamp for completion of fib + } _s; + LIST_ENTRY _FibLinks; // Used to link Adapter Initiated Fibs on the host + } _u; +#else // The MIDL compiler does not support unions without a discriminant. + struct { // Since nothing during the midl compile actually looks into this + struct { // structure, this shoudl be ok. + AAC_UINT32 _ReceiverTimeStart; // Timestamp for receipt of fib + AAC_UINT32 _ReceiverTimeDone; // Timestamp for completion of fib + } _s; + } _u; +#endif +} FIB_HEADER; + + +#define FibLinks _u._FibLinks + + +#define FIB_DATA_SIZE_IN_BYTES (512 - sizeof(FIB_HEADER)) + + +typedef struct _FIB { + +#ifdef BRIDGE //rma + DLQUE link; +#endif + FIB_HEADER Header; + + AAC_UINT8 data[FIB_DATA_SIZE_IN_BYTES]; // Command specific data + +} FIB; +typedef FIB *PFIB; + + + +// +// FIB commands +// + +typedef enum _FIB_COMMANDS { + TestCommandResponse = 1, + TestAdapterCommand = 2, + + // Lowlevel and comm commands + + LastTestCommand = 100, + ReinitHostNormCommandQueue = 101, + ReinitHostHighCommandQueue = 102, + ReinitHostHighRespQueue = 103, + ReinitHostNormRespQueue = 104, + ReinitAdapNormCommandQueue = 105, + ReinitAdapHighCommandQueue = 107, + ReinitAdapHighRespQueue = 108, + ReinitAdapNormRespQueue = 109, + InterfaceShutdown = 110, + DmaCommandFib = 120, + StartProfile = 121, + TermProfile = 122, + SpeedTest = 123, + TakeABreakPt = 124, + RequestPerfData = 125, + SetInterruptDefTimer= 126, + SetInterruptDefCount= 127, + GetInterruptDefStatus= 128, + LastCommCommand = 129, + + // Filesystem commands + + NuFileSystem = 300, + UFS = 301, + HostFileSystem = 302, + LastFileSystemCommand = 303, + + // Container Commands + + ContainerCommand = 500, + ContainerCommand64 = 501, + + // Cluster Commands + + ClusterCommand = 550, + + // Scsi Port commands (scsi passthrough) + + ScsiPortCommand = 600, + + // misc house keeping and generic adapter initiated commands + + AifRequest = 700, + CheckRevision = 701, + FsaHostShutdown = 702, + RequestAdapterInfo = 703, + IsAdapterPaused = 704, + SendHostTime = 705, + LastMiscCommand = 706 + +} _E_FIB_COMMANDS; + + + +typedef AAC_UINT16 FIB_COMMAND; + +// +// Commands that will target the failover level on the FSA adapter +// + +typedef enum _FIB_XFER_STATE { + HostOwned = (1<<0), + AdapterOwned = (1<<1), + FibInitialized = (1<<2), + FibEmpty = (1<<3), + AllocatedFromPool = (1<<4), + SentFromHost = (1<<5), + SentFromAdapter = (1<<6), + ResponseExpected = (1<<7), + NoResponseExpected = (1<<8), + AdapterProcessed = (1<<9), + HostProcessed = (1<<10), + HighPriority = (1<<11), + NormalPriority = (1<<12), + Async = (1<<13), + AsyncIo = (1<<13), // rpbfix: remove with new regime + PageFileIo = (1<<14), // rpbfix: remove with new regime + ShutdownRequest = (1<<15), + LazyWrite = (1<<16), // rpbfix: remove with new regime + AdapterMicroFib = (1<<17), + BIOSFibPath = (1<<18), + FastResponseCapable = (1<<19), + ApiFib = (1<<20) // Its an API Fib. + +} _E_FIB_XFER_STATE; + + +typedef enum _FSA_ERRORS { + FSA_NORMAL = 0, + FSA_SUCCESS = 0, + FSA_PENDING = 0x01, + FSA_FATAL = 0x02, + FSA_INVALID_QUEUE = 0x03, + FSA_NOENTRIES = 0x04, + FSA_SENDFAILED = 0x05, + FSA_INVALID_QUEUE_PRIORITY = 0x06, + FSA_FIB_ALLOCATION_FAILED = 0x07, + FSA_FIB_DEALLOCATION_FAILED = 0x08 + +} _E_FSA_ERRORS; + + +// +// The following defines needs to be updated any time there is an incompatible change made +// to the ADAPTER_INIT_STRUCT structure. +// +#define ADAPTER_INIT_STRUCT_REVISION 3 + +typedef struct _ADAPTER_INIT_STRUCT { + AAC_UINT32 InitStructRevision; + AAC_UINT32 MiniPortRevision; + AAC_UINT32 FilesystemRevision; + PAAC_VOID CommHeaderAddress; + PAAC_VOID FastIoCommAreaAddress; + PAAC_VOID AdapterFibsPhysicalAddress; + PAAC_VOID AdapterFibsVirtualAddress; + AAC_UINT32 AdapterFibsSize; + AAC_UINT32 AdapterFibAlign; + PAAC_VOID PrintfBufferAddress; + AAC_UINT32 PrintfBufferSize; + AAC_UINT32 HostPhysMemPages; // number of 4k pages of host physical memory + AAC_UINT32 HostElapsedSeconds; // number of seconds since 1970. +} ADAPTER_INIT_STRUCT; +typedef ADAPTER_INIT_STRUCT *PADAPTER_INIT_STRUCT; + + + + +#endif //_COMM_STRUCT + + --- linux/drivers/scsi/aacraid/include/comsup.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/comsup.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,131 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * comsup.h + * + * Abstract: This module defines the data structures that make up the + * commuication region for the FSA filesystem. This region is + * how the host based code commuicates both control and data + * to the adapter based code. + * + * + * + --*/ +#ifndef _COMM_SUP_DEF +#define _COMM_SUP_DEF + + +// +// The adapter interface specs all queues to be located in the same physically +// contigous block. The host structure that defines the commuication queues will +// assume they are each a seperate physically contigous memory region that will +// support them all being one big contigous block. +// There is a command and response queue for each level and direction of +// commuication. These regions are accessed by both the host and adapter. +// +typedef struct _COMM_QUE { + + PHYSICAL_ADDRESS LogicalAddress; // This is the address we give the adapter + + PQUEUE_ENTRY BaseAddress; // This is the system virtual address + QUEUE_HEADERS Headers; // A pointer to the producer and consumer queue headers for this queue + ULONG QueueEntries; // Number of queue entries on this queue + OS_CV_T QueueFull; // Event to wait on if the queue is full + OS_CV_T CommandReady; // Indicates there is a Command ready from the adapter on this queue. + // This is only valid for adapter to host command queues. + OS_SPINLOCK *QueueLock; // Spinlock for this queue must take this lock before accessing the lock + KIRQL SavedIrql; // Previous IRQL when the spin lock is taken + ddi_softintr_t ConsumerRoutine; // The DPC routine which will consume entries off this queue + // Only queues which the host will be the consumer will this field be valid + LIST_ENTRY CommandQueue; // A queue of FIBs which need to be prcessed by the FS thread. This is + // only valid for command queues which receive entries from the adapter. + LIST_ENTRY OutstandingIoQueue; // A queue of outstanding fib's to the adapter. + ULONG NumOutstandingIos; // Number of entries on outstanding queue. + + PVOID Adapter; // Back pointer to adapter structure + +} COMM_QUE; +typedef COMM_QUE *PCOMM_QUE; + + +typedef struct _COMM_REGION { + + COMM_QUE HostNormCmdQue; // Command queue for normal priority commands from the host + COMM_QUE HostNormRespQue; // A response for normal priority adapter responses + + COMM_QUE HostHighCmdQue; // Command queue for high priority commands from the host + COMM_QUE HostHighRespQue; // A response for normal priority adapter responses + + COMM_QUE AdapNormCmdQue; // Command queue for normal priority command from the adapter + COMM_QUE AdapNormRespQue; // A response for normal priority host responses + + COMM_QUE AdapHighCmdQue; // Command queue for high priority command from the adapter + COMM_QUE AdapHighRespQue; // A response for high priority host responses + + // + // The 2 threads below are the threads which handle command traffic from the + // the adapter. There is one for normal priority and one for high priority queues. + // These threads will wait on the commandready event for it's queue. + // + + HANDLE NormCommandThread; + HANDLE HighCommandThread; + + // + // This dpc routine will handle the setting the of not full event when the adapter + // lets us know the queue is not longer full via interrupt + // + + KDPC QueueNotFullDpc; + +#ifdef API_THROTTLE + // + // Support for data I/O throttling to improve CLI performance + // while the system is under load. + // This is the throttling mechanism built into the COMM layer. + // Look in commsup.c, dpcsup.c and comminit.c for use. + // + + int ThrottleLimit; // Max queue depth of data ops allowed during throttle + int ThrottleOutstandingFibs; // Number of data FIBs outstanding to adapter + LARGE_INTEGER ThrottleTimeout; // Duration of a a throttle period + LARGE_INTEGER ThrottleWaitTimeout; // Timeout for a suspended threads to wait + BOOLEAN ThrottleActive; // Is there a current throttle active period ? + KTIMER ThrottleTimer; // Throttle timer to end a throttle period. + KDPC ThrottleDpc; // Throttle timer timeout DPC routine. + KSEMAPHORE ThrottleReleaseSema; // Semaphore callers of SendFib wait on during a throttle. + + unsigned int ThrottleExceptionsCount; // Number of times throttle exception handler executed (0!) + unsigned int ThrottleTimerFires; // Debug info - #times throttle timer Dpc has fired + unsigned int ThrottleTimerSets; // Debug info - #times throttle timer was set + + unsigned int ThrottledFibs; + unsigned int ThrottleTimedoutFibs; + unsigned int ApiFibs; + unsigned int NonPassiveFibs; + unsigned int TotalFibs; + unsigned int FSInfoFibs; + +#endif // #ifdef API_THROTTLE + +} COMM_REGION; +typedef COMM_REGION *PCOMM_REGION; + +#endif // _COMM_SUP --- linux/drivers/scsi/aacraid/include/fsact.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/fsact.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,163 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * fsact.h + * + * Abstract: Common container structures that are required to be + * known on both the host and adapter. + * + * + --*/ +#ifndef _FSACT_H_ +#define _FSACT_H_ + +//#include +//#include +#include // 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_ */ + + --- linux/drivers/scsi/aacraid/include/fsafs.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/fsafs.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,77 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * fsafs.h + * + * Abstract: Common file system structures that are required to be + * known on both the host and adapter + * + * + * + --*/ + +#ifndef _FSAFS_H_ +#define _FSAFS_H_ 1 + + +#include // 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_ */ + --- linux/drivers/scsi/aacraid/include/fsaioctl.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/fsaioctl.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,157 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * fsaioctl.h + * + * Abstract: Defines the interface structures between user mode applications + * and the fsa driver. This structures are used in + * DeviceIoControl() calls. + * + * + * + --*/ +#ifndef _FSAIOCTL_H_ +#define _FSAIOCTL_H_ + +#ifndef IOTRACEUSER + +#ifndef CTL_CODE + + +#define FILE_DEVICE_CONTROLLER 0x00000004 + +// +// Macro definition for defining IOCTL and FSCTL function control codes. Note +// that function codes 0-2047 are reserved for Microsoft Corporation, and +// 2048-4095 are reserved for customers. +// + +#define CTL_CODE( DeviceType, Function, Method, Access ) ( \ + ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ +) + +// +// Define the method codes for how buffers are passed for I/O and FS controls +// + +#define METHOD_BUFFERED 0 + + +#define METHOD_NEITHER 3 + +// +// Define the access check value for any access +// +// +// The FILE_READ_ACCESS and FILE_WRITE_ACCESS constants are also defined in +// ntioapi.h as FILE_READ_DATA and FILE_WRITE_DATA. The values for these +// constants *MUST* always be in sync. +// +#define FILE_ANY_ACCESS 0 + + + +#endif + + + +typedef struct _UNIX_QUERY_DISK { + AAC_INT32 ContainerNumber; + AAC_INT32 Bus; + AAC_INT32 Target; + AAC_INT32 Lun; + AAC_BOOLEAN Valid; + AAC_BOOLEAN Locked; + AAC_BOOLEAN Deleted; + AAC_INT32 Instance; + AAC_INT8 diskDeviceName[10]; + AAC_BOOLEAN UnMapped; +} UNIX_QUERY_DISK; +typedef UNIX_QUERY_DISK *PUNIX_QUERY_DISK; + + +typedef struct _DELETE_DISK { + AAC_UINT32 NtDiskNumber; + AAC_UINT32 ContainerNumber; +} DELETE_DISK; +typedef DELETE_DISK *PDELETE_DISK; + + +#endif /*IOTRACEUSER*/ + +#define FSACTL_NULL_IO_TEST 0x43 // CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2048, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSACTL_SIM_IO_TEST 0x53 // CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2049, METHOD_NEITHER, FILE_ANY_ACCESS) + + +#define FSACTL_SENDFIB CTL_CODE(FILE_DEVICE_CONTROLLER, 2050, METHOD_BUFFERED, FILE_ANY_ACCESS) + + +#define FSACTL_GET_VAR 0x93 +#define FSACTL_SET_VAR 0xa3 +#define FSACTL_GET_FIBTIMES 0xb3 +#define FSACTL_ZERO_FIBTIMES 0xc3 + + +#define FSACTL_DELETE_DISK 0x163 +#define FSACTL_QUERY_DISK 0x173 + + +// AfaComm perfmon ioctls +#define FSACTL_GET_COMM_PERF_DATA CTL_CODE(FILE_DEVICE_CONTROLLER, 2084, METHOD_BUFFERED, FILE_ANY_ACCESS) + + +#define FSACTL_OPENCLS_COMM_PERF_DATA CTL_CODE(FILE_DEVICE_CONTROLLER, 2085, METHOD_BUFFERED, FILE_ANY_ACCESS) + + +typedef struct _GET_ADAPTER_FIB_IOCTL { + char *AdapterFibContext; + int Wait; + char *AifFib; +} GET_ADAPTER_FIB_IOCTL, *PGET_ADAPTER_FIB_IOCTL; + +// +// filesystem ioctls +// +#define FSACTL_OPEN_GET_ADAPTER_FIB CTL_CODE(FILE_DEVICE_CONTROLLER, 2100, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define FSACTL_GET_NEXT_ADAPTER_FIB CTL_CODE(FILE_DEVICE_CONTROLLER, 2101, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define FSACTL_CLOSE_GET_ADAPTER_FIB CTL_CODE(FILE_DEVICE_CONTROLLER, 2102, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define FSACTL_OPEN_ADAPTER_CONFIG CTL_CODE(FILE_DEVICE_CONTROLLER, 2103, METHOD_NEITHER, FILE_ANY_ACCESS) + +#define FSACTL_CLOSE_ADAPTER_CONFIG CTL_CODE(FILE_DEVICE_CONTROLLER, 2104, METHOD_NEITHER, FILE_ANY_ACCESS) + + +#define FSACTL_MINIPORT_REV_CHECK CTL_CODE(FILE_DEVICE_CONTROLLER, 2107, METHOD_BUFFERED, FILE_ANY_ACCESS) + + +#define FSACTL_QUERY_ADAPTER_CONFIG CTL_CODE(FILE_DEVICE_CONTROLLER, 2113, METHOD_BUFFERED, FILE_ANY_ACCESS) + + +#define FSACTL_FORCE_DELETE_DISK CTL_CODE(FILE_DEVICE_CONTROLLER, 2120, METHOD_NEITHER, FILE_ANY_ACCESS) + + +#define FSACTL_AIF_THREAD CTL_CODE(FILE_DEVICE_CONTROLLER, 2127, METHOD_NEITHER, FILE_ANY_ACCESS) + + +#endif // _FSAIOCTL_H_ + + --- linux/drivers/scsi/aacraid/include/fsaport.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/fsaport.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,221 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * fsaport.h + * + * Abstract: This module defines all of the globally used procedures in the FSA + * file system. + * + * + * + --*/ +#ifndef _FSAPORT_ +#define _FSAPORT_ + +// +// The scatter/gather map context is the information we +// we need to keep the map and transfer data to and from the +// adapter. +// + +typedef struct _SGMAP_CONTEXT { + + caddr_t BaseAddress; + PVOID MapRegBase; + ULONG NumberMapRegs; + PSGMAP SgMapPtr; + ULONG ByteCount; // Used to check the Mdl length. + BOOLEAN WriteToDevice; + + struct buf *bp; + + +} SGMAP_CONTEXT; +typedef SGMAP_CONTEXT *PSGMAP_CONTEXT; + +typedef struct _MAPFIB_CONTEXT { + PMDL Mdl; + PVOID MapRegBase; + ULONG NumberMapRegs; + PVOID FibVirtualAddress; + ULONG Size; + PVOID FibPhysicalAddress; + + +} MAPFIB_CONTEXT; +typedef MAPFIB_CONTEXT *PMAPFIB_CONTEXT; + +typedef BOOLEAN +(*PFSA_ALLOCATE_ADAPTER_COMM_AREA)( + PVOID AdapterExtension, + IN OUT PVOID *BaseAddress, + IN ULONG Size, + IN ULONG Alignment + ); + +typedef BOOLEAN +(*PFSA_FREE_ADAPTER_COMM_AREA)( + PVOID AdapterExtension + ); + +typedef VOID +(*PFSA_FREE_DMA_RESOURCES)( + IN PVOID AdapterExtension, + IN PSGMAP_CONTEXT SgMapContext + ); + +typedef BOOLEAN +(*PFSA_ALLOCATE_AND_MAP_FIB_SPACE)( + IN PVOID AdapterExtension, + IN PMAPFIB_CONTEXT MapFibContext + ); + +typedef BOOLEAN +(*PFSA_UNMAP_AND_FREE_FIB_SPACE)( + IN PVOID AdapterExtension, + IN PMAPFIB_CONTEXT MapFibContext + ); + +typedef VOID +(*PFSA_INTERRUPT_ADAPTER)( + IN PVOID AdapterExtension + ); + +typedef VOID +(*PFSA_NOTIFY_ADAPTER)( + IN PVOID AdapterExtension, + IN HOST_2_ADAP_EVENT AdapterEvent + ); + +typedef VOID +(*PFSA_RESET_DEVICE)( + PVOID AdapterExtension + ); + +typedef AAC_STATUS +(*PFSA_BUILD_SGMAP)( + IN PVOID AdapterExtension, + IN PSGMAP_CONTEXT SgMapContext + ); + +typedef PVOID +(*PFSA_ADAPTER_ADDR_TO_SYSTEM_ADDR)( + IN PVOID AdapterExtension, + IN PVOID AdapterAddress + ); + +typedef VOID +(*PFSA_INTERRUPT_HOST)( + PVOID Adapter, + ADAPTER_EVENT AdapterEvent + ); + +typedef VOID +(*PFSA_ENABLE_INTERRUPT)( + PVOID Adapter, + ADAPTER_EVENT AdapterEvent, + BOOLEAN AtDeviceIrq + ); + + +typedef VOID +(*PFSA_DISABLE_INTERRUPT)( + PVOID Adapter, + ADAPTER_EVENT AdapterEvent, + BOOLEAN AtDeviceIrq + ); + +typedef AAC_STATUS +(*PFSA_OPEN_ADAPTER) ( + IN PVOID Adapter + ); + +typedef int +(*PFSA_DEVICE_CONTROL) ( + IN PVOID Adapter, + IN PAFA_IOCTL_CMD IoctlCmdPtr + ); + +typedef AAC_STATUS +(*PFSA_CLOSE_ADAPTER) ( + IN PVOID Adapter + ); + +typedef BOOLEAN +(*PFSA_SEND_SYNCH_FIB) ( + IN PVOID Adapter, + IN ULONG FibPhysicalAddress + ); + +typedef struct _FSAPORT_FUNCS { + ULONG SizeOfFsaPortFuncs; + + PFSA_ALLOCATE_ADAPTER_COMM_AREA AllocateAdapterCommArea; + PFSA_FREE_ADAPTER_COMM_AREA FreeAdapterCommArea; + PFSA_FREE_DMA_RESOURCES FreeDmaResources; + PFSA_ALLOCATE_AND_MAP_FIB_SPACE AllocateAndMapFibSpace; + PFSA_UNMAP_AND_FREE_FIB_SPACE UnmapAndFreeFibSpace; + PFSA_INTERRUPT_ADAPTER InterruptAdapter; + PFSA_NOTIFY_ADAPTER NotifyAdapter; + PFSA_ENABLE_INTERRUPT EnableInterrupt; + PFSA_DISABLE_INTERRUPT DisableInterrupt; + PFSA_RESET_DEVICE ResetDevice; + PFSA_BUILD_SGMAP BuildSgMap; + PFSA_ADAPTER_ADDR_TO_SYSTEM_ADDR AdapterAddressToSystemAddress; + + PFSA_INTERRUPT_HOST InterruptHost; + PFSA_OPEN_ADAPTER OpenAdapter; + PFSA_DEVICE_CONTROL DeviceControl; + PFSA_CLOSE_ADAPTER CloseAdapter; + + PFSA_SEND_SYNCH_FIB SendSynchFib; + +} FSAPORT_FUNCS; +typedef FSAPORT_FUNCS *PFSAPORT_FUNCS; + +typedef AAC_STATUS +(*PFSA_SETVAR_CALLBACK) ( + IN PVOID Adapter, + IN ULONG NewValue + ); + +typedef struct _FSA_USER_VAR { + char Name[32]; + ULONG *Address; + PFSA_SETVAR_CALLBACK SetVarCallback; +} FSA_USER_VAR; + +typedef FSA_USER_VAR *PFSA_USER_VAR; + +typedef struct _FSA_NEW_ADAPTER { + PVOID AdapterExtension; + PFSAPORT_FUNCS AdapterFuncs; + PVOID Adapter; + BOOLEAN AdapterInterruptsBelowDpc; + PFSA_USER_VAR AdapterUserVars; + ULONG AdapterUserVarsSize; + void *Dip; +} FSA_NEW_ADAPTER; +typedef FSA_NEW_ADAPTER *PFSA_NEW_ADAPTER; + +#define FSAFS_GET_NEXT_ADAPTER CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2048, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSAFS_INIT_NEW_ADAPTER CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2049, METHOD_NEITHER, FILE_ANY_ACCESS) + +#endif --- linux/drivers/scsi/aacraid/include/fsatypes.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/fsatypes.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,214 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * fsatypes.h + * + * Abstract: Define all shared data types here, ie, those + * types shared among several components, such + * as host (driver + apps), adapter, and BIOS. + * + * + --*/ +#ifndef _FSATYPES_H +#define _FSATYPES_H + + + +typedef AAC_UINT32 AAC_BOOLEAN; + +// +// Define a 64-bit address structure for use on +// a 32-bit processor architecture. +// +typedef struct { + AAC_UINT32 lo32; + AAC_UINT32 hi32; +} AAC_UINT64S, *PAAC_UINT64S; + + + +// +// Container Types +// +typedef struct { + AAC_UINT32 data[2]; // RMA FIX, make this a real serial number when we + // know what it looks like. Note, BIOS sees this + // definition and it must be coded in such a way + // that it appears to be 64 bits. ints are 16 bits + // in BIOS land; fortunately, longs are 32 bits. +} SerialNumberT; + + + +// +// *********************** +// DON'T CHANGE THE ORDER, ctdevsw use this order to map the drivers +// *********************** +// drivers for CT_NONE to CT_PASSTHRU +// +typedef enum _FSAVOLTYPE { + CT_NONE = 0, + CT_VOLUME, + CT_MIRROR, + CT_STRIPE, + CT_RAID5, + CT_SSRW, + CT_SSRO, + CT_MORPH, + CT_PASSTHRU, + CT_RAID4, + CT_RAID10, // stripe of mirror + CT_RAID00, // stripe of stripe + CT_VOLUME_OF_MIRRORS, // volume of mirror + CT_PSEUDO_RAID3, // really raid4 + + CT_LAST_VOLUME_TYPE + +} _E_FSAVOLTYPE; + +#ifdef AAC_32BIT_ENUMS +typedef _E_FSAVOLTYPE FSAVOLTYPE; +#else +typedef AAC_UINT32 FSAVOLTYPE; +#endif + + +// +// Types of objects addressable in some fashion by the client. +// This is a superset of those objects handled just by the filesystem +// and includes "raw" objects that an administrator would use to +// configure containers and filesystems. +// +typedef enum _FTYPE { + FT_REG = 1, // regular file + FT_DIR, // directory + FT_BLK, // "block" device - reserved + FT_CHR, // "character special" device - reserved + FT_LNK, // symbolic link + FT_SOCK, // socket + FT_FIFO, // fifo + FT_FILESYS, // ADAPTEC's "FSA"(tm) filesystem + FT_DRIVE, // physical disk - addressable in scsi by bus/target/lun + FT_SLICE, // virtual disk - raw volume - slice + FT_PARTITION, // FSA partition - carved out of a slice - building block for containers + FT_VOLUME, // Container - Volume Set + FT_STRIPE, // Container - Stripe Set + FT_MIRROR, // Container - Mirror Set + FT_RAID5, // Container - Raid 5 Set + FT_DATABASE // Storage object with "foreign" content manager +} _E_FTYPE; + +#ifdef AAC_32BIT_ENUMS +typedef _E_FTYPE FTYPE; +#else +typedef AAC_UINT32 FTYPE; +#endif + + + +// +// Host side memory scatter gather list +// Used by the adapter for read, write, and readdirplus operations +// +typedef PAAC_UINT8 HOSTADDRESS; + +typedef struct _SGENTRY { + HOSTADDRESS SgAddress; /* 32-bit Base address. */ + AAC_UINT32 SgByteCount; /* Length. */ +} SGENTRY; +typedef SGENTRY *PSGENTRY; + + + +// +// SGMAP +// +// This is the SGMAP structure for all commands that use +// 32-bit addressing. +// +// Note that the upper 16 bits of SgCount are used as flags. +// Only the lower 16 bits of SgCount are actually used as the +// SG element count. +// +typedef struct _SGMAP { + AAC_UINT32 SgCount; + SGENTRY SgEntry[1]; +} SGMAP; +typedef SGMAP *PSGMAP; + + + +// +// SGMAP64 +// +// This is the SGMAP structure for 64-bit container commands. +// +typedef struct _SGMAP64 { + AAC_UINT8 SgCount; + AAC_UINT8 SgSectorsPerPage; + AAC_UINT16 SgByteOffset; // For the first page + AAC_UINT64S SgEntry[1]; // Must be last entry +} SGMAP64; +typedef SGMAP64 *PSGMAP64; + + + + +// +// attempt at common time structure across host and adapter +// +typedef struct __TIME_T { + + AAC_UINT32 tv_sec; /* seconds (maybe, depends upon host) */ + AAC_UINT32 tv_usec; /* and nanoseconds (maybe, depends upon host)*/ + +} TIME_T; +typedef TIME_T *PTIME_T; + +#ifndef _TIME_T +#define timespec __TIME_T +#define ts_sec tv_sec +#define ts_nsec tv_usec +#endif + + + + +typedef struct _ContainerCreationInfo +{ + + AAC_UINT8 ViaBuildNumber; // e.g., 588 + AAC_UINT8 MicroSecond; // e.g., 588 + AAC_UINT8 Via; // e.g., 1 = FSU, + // 2 = API, + AAC_UINT8 YearsSince1900; // e.g., 1997 = 97 + AAC_UINT32 Date; // + // unsigned Month :4; // 1 - 12 + // unsigned Day :6; // 1 - 32 + // unsigned Hour :6; // 0 - 23 + // unsigned Minute :6; // 0 - 60 + // unsigned Second :6; // 0 - 60 + SerialNumberT ViaAdapterSerialNumber; // e.g., 0x1DEADB0BFAFAF001 +} ContainerCreationInfo; + + +#endif // _FSATYPES_H + + --- linux/drivers/scsi/aacraid/include/linit.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/linit.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,112 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * linit.h + * + * Abstract: Header file for Linux Driver for Adaptec RAID Array Controller + * + --*/ +/*------------------------------------------------------------------------------ + * I N C L U D E S + *----------------------------------------------------------------------------*/ + +#ifndef _LINIT_H_ +#define _LINIT_H_ + +#include + +/*------------------------------------------------------------------------------ + * D E F I N E S + *----------------------------------------------------------------------------*/ +/* Define the AAC SCSI Host Template structure. */ +#define AAC_HOST_TEMPLATE_ENTRY \ + { proc_dir: &AAC_ProcDirectoryEntry, /* ProcFS Directory Entry */ \ + proc_info: AAC_ProcDirectoryInfo, /* ProcFS Info Function */ \ + name: "AAC", /* Driver Name */ \ + detect: AAC_DetectHostAdapter, /* Detect Host Adapter */ \ + release: AAC_ReleaseHostAdapter, /* Release Host Adapter */ \ + info: AAC_DriverInfo, /* Driver Info Function */ \ + ioctl: AAC_Ioctl, /* ioctl Interface */ \ + command: AAC_Command, /* unqueued command */ \ + queuecommand: AAC_QueueCommand, /* Queue Command Function */ \ + abort: AAC_AbortCommand, /* Abort Command Function */ \ + reset: AAC_ResetCommand, /* Reset Command Function */ \ + bios_param: AAC_BIOSDiskParameters, /* BIOS Disk Parameters */ \ + can_queue: 1, /* Default initial value */ \ + this_id: 0, /* Default initial value */ \ + sg_tablesize: 0, /* Default initial value */ \ + cmd_per_lun: 0, /* Default initial value */ \ + present: 0, /* Default initial value */ \ + unchecked_isa_dma: 0, /* Default Initial Value */ \ + use_new_eh_code: 0, /* Default initial value */ \ + eh_abort_handler: AAC_AbortCommand, /* New Abort Command func */ \ + eh_strategy_handler: NULL, /* New Strategy Error Handler */ \ + eh_device_reset_handler: NULL, /* New Device Reset Handler */ \ + eh_bus_reset_handler: NULL, /* New Bus Reset Handler */ \ + eh_host_reset_handler: NULL, /* New Host reset Handler */ \ + use_clustering: ENABLE_CLUSTERING /* Disable Clustering */ \ + } + + +/*------------------------------------------------------------------------------ + * T Y P E D E F S / S T R U C T S + *----------------------------------------------------------------------------*/ +typedef struct proc_dir_entry proc_dir_entry_t; + + + +typedef struct AAC_BIOS_DiskParameters +{ + int heads; + int sectors; + int cylinders; +} AAC_BIOS_DiskParameters_T; + + +/*------------------------------------------------------------------------------ + * P R O G R A M G L O B A L S + *----------------------------------------------------------------------------*/ + +const char *AAC_DriverInfo( struct Scsi_Host * ); + +extern proc_dir_entry_t AAC_ProcDirectoryEntry; + + + +/*------------------------------------------------------------------------------ + * F U N C T I O N P R O T O T Y P E S + *----------------------------------------------------------------------------*/ +/* Define prototypes for the AAC Driver Interface Functions. */ +int AAC_DetectHostAdapter( Scsi_Host_Template * ); +int AAC_ReleaseHostAdapter( struct Scsi_Host * ); +int AAC_QueueCommand( Scsi_Cmnd *, void ( *CompletionRoutine )( Scsi_Cmnd * ) ); +int AAC_Command( Scsi_Cmnd * ); +int AAC_ResetCommand( Scsi_Cmnd *, unsigned int ); +int AAC_BIOSDiskParameters( Disk *, kdev_t, int * ); +int AAC_ProcDirectoryInfo( char *, char **, off_t, int, int, int ); +int AAC_Ioctl( Scsi_Device *, int, void * ); + + +void AAC_SelectQueueDepths( struct Scsi_Host *, Scsi_Device * ); + + +int AAC_AbortCommand( Scsi_Cmnd *scsi_cmnd_ptr ); + +#endif /* _LINIT_H_ */ --- linux/drivers/scsi/aacraid/include/monkerapi.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/monkerapi.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,97 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * monkerapi.h + * + * Abstract: This module contains the definitions used by the Host Adapter + * Communications interface. + * This is the interface used for by host programs and the Adapter + * to communicate via synchronous commands via a shared set of registers + * on a platform (typically doorbells and mailboxes). + * + --*/ +//********************************************************************** +// +// Monitor / Kernel API +// +// 03/24/1998 Bob Peret Initial creation +// +//********************************************************************** + +#ifndef MONKER_H +#define MONKER_H + + +#define BREAKPOINT_REQUEST 0x00000004 +#define INIT_STRUCT_BASE_ADDRESS 0x00000005 + + +#define SEND_SYNCHRONOUS_FIB 0x0000000c + + + +// +// Adapter Status Register +// +// Phase Staus mailbox is 32bits: +// <31:16> = Phase Status +// <15:0> = Phase +// +// The adapter reports is present state through the phase. Only +// a single phase should be ever be set. Each phase can have multiple +// phase status bits to provide more detailed information about the +// state of the board. Care should be taken to ensure that any phase status +// bits that are set when changing the phase are also valid for the new phase +// or be cleared out. Adapter software (monitor, iflash, kernel) is responsible +// for properly maintining the phase status mailbox when it is running. + +// +// MONKER_API Phases +// +// Phases are bit oriented. It is NOT valid +// to have multiple bits set +// + + +#define SELF_TEST_FAILED 0x00000004 + + +#define KERNEL_UP_AND_RUNNING 0x00000080 +#define KERNEL_PANIC 0x00000100 + + + +// +// Doorbell bit defines +// + + +#define DoorBellPrintfDone (1<<5) // Host -> Adapter + + +#define DoorBellAdapterNormCmdReady (1<<1) // Adapter -> Host +#define DoorBellAdapterNormRespReady (1<<2) // Adapter -> Host +#define DoorBellAdapterNormCmdNotFull (1<<3) // Adapter -> Host +#define DoorBellAdapterNormRespNotFull (1<<4) // Adapter -> Host +#define DoorBellPrintfReady (1<<5) // Adapter -> Host + + +#endif // MONKER_H + --- linux/drivers/scsi/aacraid/include/nodetype.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/nodetype.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,64 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * nodetype.h + * + * Abstract: This module defines all of the node type codes used in this development + * shell. Every major data structure in the file system is assigned a node + * type code that is. This code is the first CSHORT in the structure and is + * followed by a CSHORT containing the size, in bytes, of the structure. + * + --*/ +#ifndef _NODETYPE_ +#define _NODETYPE_ + +typedef CSHORT NODE_TYPE_CODE; + + +#define FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT ((NODE_TYPE_CODE)0x030b) +#define FSAFS_NTC_FIB_CONTEXT ((NODE_TYPE_CODE)0x030c) + + +typedef CSHORT NODE_BYTE_SIZE; + + +// +// The following definitions are used to generate meaningful blue bugcheck +// screens. On a bugcheck the file system can output 4 ulongs of useful +// information. The first ulong will have encoded in it a source file id +// (in the high word) and the line number of the bugcheck (in the low word). +// The other values can be whatever the caller of the bugcheck routine deems +// necessary. +// +// Each individual file that calls bugcheck needs to have defined at the +// start of the file a constant called BugCheckFileId with one of the +// FSAFS_BUG_CHECK_ values defined below and then use FsaBugCheck to bugcheck +// the system. +// + + +#define FSAFS_BUG_CHECK_COMMSUP (0X001e0000) +#define FSAFS_BUG_CHECK_DPCSUP (0X001f0000) + + +#define FsaBugCheck(A,B,C) { cmn_err( CE_PANIC, "aacdisk: module %x, line %x, 0x%x, 0x%x, 0x%x ", BugCheckFileId, __LINE__, A, B, C); } + + +#endif // _NODETYPE_ --- linux/drivers/scsi/aacraid/include/nvramioctl.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/nvramioctl.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,112 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * nvramioctl.h + * + * Abstract: This file defines the data structures related to querying + * and controlling the FSA NVRAM/WriteCache subsystem via the NVRAMIOCTL FIB. + * + --*/ +#ifndef _NVRAMIOCTL_H_ +#define _NVRAMIOCTL_H_ 1 + + + +/* + * NVRAM/Write Cache subsystem states + */ +typedef enum _NVSTATUS { + NVSTATUS_DISABLED = 0, // present, clean, not being used + NVSTATUS_ENABLED, // present, possibly dirty, ready for use + NVSTATUS_ERROR, // present, dirty, contains dirty data + // for bad/missing device + NVSTATUS_BATTERY, // present, bad or low battery, may contain dirty data + // for bad/missing device + NVSTATUS_UNKNOWN // present????? +} _E_NVSTATUS; + +#ifdef AAC_32BIT_ENUMS +typedef _E_NVSTATUS NVSTATUS; +#else +typedef AAC_UINT32 NVSTATUS; +#endif + +/* + * NVRAM/Write Cache subsystem battery component states + * + */ +//NB: this enum should be identical to battery_status in nvram.h +// or else collapsed into one enum someday +typedef enum _NVBATTSTATUS { + NVBATTSTATUS_NONE = 0, // battery has no power or is not present + NVBATTSTATUS_LOW, // battery is low on power + NVBATTSTATUS_OK, // battery is okay - normal operation possible only in this state + NVBATTSTATUS_RECONDITIONING // no battery present - reconditioning in process +} _E_NVBATTSTATUS; + +#ifdef AAC_32BIT_ENUMS +typedef _E_NVBATTSTATUS NVBATTSTATUS; +#else +typedef AAC_UINT32 NVBATTSTATUS; +#endif + +/* + * battery transition type + */ +typedef enum _NVBATT_TRANSITION { + NVBATT_TRANSITION_NONE = 0, // battery now has no power or is not present + NVBATT_TRANSITION_LOW, // battery is now low on power + NVBATT_TRANSITION_OK // battery is now okay - normal operation possible only in this state +} _E_NVBATT_TRANSITION; + +#ifdef AAC_32BIT_ENUMS +typedef _E_NVBATT_TRANSITION NVBATT_TRANSITION; +#else +typedef AAC_UINT32 NVBATT_TRANSITION; +#endif + +/* + * NVRAM Info structure returned for NVRAM_GetInfo call + */ +typedef struct _NVRAMDEVINFO { + AAC_UINT32 NV_Enabled; /* write caching enabled */ + AAC_UINT32 NV_Error; /* device in error state */ + AAC_UINT32 NV_NDirty; /* count of dirty NVRAM buffers */ + AAC_UINT32 NV_NActive; /* count of NVRAM buffers being written */ +} NVRAMDEVINFO, *PNVRAMDEVINFO; + +typedef struct _NVRAMINFO { + NVSTATUS NV_Status; /* nvram subsystem status */ + NVBATTSTATUS NV_BattStatus; /* battery status */ + AAC_UINT32 NV_Size; /* size of WriteCache NVRAM in bytes */ + AAC_UINT32 NV_BufSize; /* size of NVRAM buffers in bytes */ + AAC_UINT32 NV_NBufs; /* number of NVRAM buffers */ + AAC_UINT32 NV_NDirty; /* count of dirty NVRAM buffers */ + AAC_UINT32 NV_NClean; /* count of clean NVRAM buffers */ + AAC_UINT32 NV_NActive; /* count of NVRAM buffers being written */ + AAC_UINT32 NV_NBrokered; /* count of brokered NVRAM buffers */ + NVRAMDEVINFO NV_DevInfo[NFILESYS]; /* per device info */ + AAC_UINT32 NV_BattNeedsReconditioning; /* boolean */ + AAC_UINT32 NV_TotalSize; /* total size of all non-volatile memories in bytes */ +} NVRAMINFO, *PNVRAMINFO; + +#endif /* !_NVRAMIOCTL_H_ */ + + --- linux/drivers/scsi/aacraid/include/osheaders.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/osheaders.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,137 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * osheaders.h + * + * Abstract: Holds all of the header file includes for a particular O/S flavor. + * + --*/ +#ifndef _OSHEADERS_H_ +#define _OSHEADERS_H_ + +#include // retrieve the kernel configuration info +#if defined( CONFIG_MODVERSIONS ) && !defined( MODVERSIONS ) +#define MODVERSIONS // force it on +#endif + +#include + +#if defined( MODVERSIONS ) && defined( MODULE ) +#if DRIVER_KERNEL_CODE >= KERNEL_VERSION(2,2,12) +#ifdef __SMP__ +#include +#elif defined( BOOT_DRIVER ) +#include +#else +#include +#endif // ifdef __SMP__ +#else +#include +#endif +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" + +#ifndef intptr_t +#define intptr_t void * +#endif + +#ifndef cred_t +#define cred_t void +#endif + +#ifndef paddr32_t +#define paddr32_t unsigned +#endif + +#ifndef bzero +#define bzero(b,len) memset(b,0,len) +#endif + +#ifndef bcopy +#define bcopy(src,dst,len) memcpy(dst,src,len ) +#endif + +#ifndef DEVICE_NR +#define DEVICE_NR(device) ( ( ( MAJOR( device ) & 7 ) << 4 ) + ( MINOR( device ) >> 4 ) ) +#endif + +typedef unsigned uint_t; + +typedef enum +{ + CE_PANIC = 0, + CE_WARN, + CE_NOTE, + CE_CONT, + CE_DEBUG, + CE_DEBUG2, + CE_TAIL +} CE_ENUM_T; + +#define CMN_ERR_LEVEL CE_WARN + +#ifndef IN +#define IN +#endif + +// usage of READ & WRITE as a typedefs in protocol.h +// conflicts with 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_ + --- linux/drivers/scsi/aacraid/include/ostypes.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/ostypes.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,145 @@ +/*++ + * 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_ + +#define MAXIMUM_NUM_CONTAINERS 64 // 4 Luns * 16 Targets +#define MAXIMUM_NUM_ADAPTERS 8 + +#define OS_ALLOC_MEM_SLEEP GFP_KERNEL + +#define Os_remove_softintr OsSoftInterruptRemove +#define OsPrintf printk +#define FsaCommPrint OsPrintf + +// the return values for copy_from_user & copy_to_user is the +// number of bytes not transferred. Thus if an internal error +// occurs, the return value is greater than zero. +#define COPYIN(SRC,DST,COUNT,FLAGS) copy_from_user(DST,SRC,COUNT) +#define COPYOUT(SRC,DST,COUNT,FLAGS) copy_to_user(DST,SRC,COUNT) + +#define copyin(SRC,DST,COUNT) copy_from_user(DST,SRC,COUNT) +#define copyout(SRC,DST,COUNT) copy_to_user(DST,SRC,COUNT) + +/*------------------------------------------------------------------------------ + * S T R U C T S / T Y P E D E F S + *----------------------------------------------------------------------------*/ +typedef struct OS_MUTEX +{ + unsigned long lock_var; + struct wait_queue * wq_ptr; + unsigned owner; +} OS_MUTEX; + +typedef struct OS_SPINLOCK +{ + spinlock_t spin_lock; + unsigned cpu_lock_count[8]; + long cpu_flag; + long lockout_count; +} OS_SPINLOCK; + +#ifdef CVLOCK_USE_SPINLOCK + typedef OS_SPINLOCK OS_CVLOCK; +#else + typedef OS_MUTEX OS_CVLOCK; +#endif + +typedef size_t OS_SIZE_T; + +typedef struct OS_CV_T +{ + unsigned long lock_var; + unsigned long type; + struct wait_queue *wq_ptr; +} OS_CV_T; + +struct fsa_scsi_hba { + void *CommonExtension; + unsigned long ContainerSize[MAXIMUM_NUM_CONTAINERS]; + unsigned long ContainerType[MAXIMUM_NUM_CONTAINERS]; + unsigned char ContainerValid[MAXIMUM_NUM_CONTAINERS]; + unsigned char ContainerReadOnly[MAXIMUM_NUM_CONTAINERS]; + unsigned char ContainerLocked[MAXIMUM_NUM_CONTAINERS]; + unsigned char ContainerDeleted[MAXIMUM_NUM_CONTAINERS]; + long ContainerDevNo[MAXIMUM_NUM_CONTAINERS]; +}; + +typedef struct fsa_scsi_hba fsadev_t; + +typedef struct OsKI +{ + struct Scsi_Host *scsi_host_ptr; + void * dip; // #REVISIT# + fsadev_t fsa_dev; + int thread_pid; + int MiniPortIndex; +} OsKI_t; + +#define dev_info_t fsadev_t + +typedef int OS_SPINLOCK_COOKIE; + +typedef unsigned int OS_STATUS; + +typedef struct tq_struct OS_SOFTINTR; + +typedef OS_SOFTINTR *ddi_softintr_t; + + + +//----------------------------------------------------------------------------- +// Conditional variable functions + +void OsCv_init ( + OS_CV_T *cv_ptr ); + + +//----------------------------------------------------------------------------- +// Printing functions +void printk_err(int flag, char *fmt, ...); + +#define cmn_err printk_err + + +// +// just ignore these solaris ddi functions in the code +// +#define DDI_SUCCESS 0 + +#define ddi_add_softintr(A,B,C,D,E,F,G) OsSoftInterruptAdd(C,F,G) + +//#REVIEW# +#define ddi_remove_softintr(A) 0 +#define ddi_get_soft_iblock_cookie(A, B, C) 0 + +#define ASSERT(expr) ((void) 0) +#define drv_usecwait udelay + +#endif // _OSTYPES_H_ --- linux/drivers/scsi/aacraid/include/pcisup.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/pcisup.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,102 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * pcisup.h + * + * Abstract: This module defines functions that are defined in PciSup.c + * + --*/ +#ifndef _PCISUP_ +#define _PCISUP_ + + + + +/* + * define which interrupt handler needs to be installed + */ + +#define SaISR 1 +#define RxISR 2 + +typedef struct _PCI_MINIPORT_COMMON_EXTENSION { + ULONG AdapterNumber; // Which FSA# this miniport is + + ULONG PciBusNumber; // Which PCI bus we are located on + ULONG PciSlotNumber; // Whiat PCI slot we are in + + PVOID Adapter; // Back pointer to Fsa adapter object + ULONG AdapterIndex; // Index into PlxAdapterTypes array + PDEVICE_OBJECT DeviceObject; // Pointer to our device object + + FSAPORT_FUNCS AdapterFuncs; + ULONG FilesystemRevision; // Main driver's revision number + +// KIRQL IsrIrql; // irql our isr runs at +// PKINTERRUPT IsrObject; // Our Interrupt object +// ULONG NumMapRegs; // Max amount map regs per dma allowed by the system +// PADAPTER_OBJECT NtAdapter; // The adapter object for the cyclone board + + PADAPTER_INIT_STRUCT InitStruct; // Holds initialization info to communicate with adapter + PVOID PhysicalInitStruct; // Holds physical address of the init struct + +// PFASTIO_STRUCT FastIoCommArea; // pointer to common buffer used for FastIo communication (Host view) + + PVOID PrintfBufferAddress; // pointer to buffer used for printf's from the adapter + + BOOLEAN AdapterPrintfsToScreen; + BOOLEAN AdapterConfigured; // set to true when we know adapter can take FIBs + + void * MiniPort; + + caddr_t CommAddress; // Base address of Comm area + paddr32_t CommPhysAddr; // Physical Address of Comm area + size_t CommSize; + + OsKI_t OsDep; // OS dependent kernel interfaces + + +} PCI_MINIPORT_COMMON_EXTENSION; + +typedef PCI_MINIPORT_COMMON_EXTENSION *PPCI_MINIPORT_COMMON_EXTENSION; + +typedef int +(*PFSA_MINIPORT_INIT) ( + IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension, + IN ULONG AdapterNumber, + IN ULONG PciBus, + IN ULONG PciSlot + ); + +typedef struct _FSA_MINIPORT { + USHORT VendorId; + USHORT DeviceId; + USHORT SubVendorId; + USHORT SubSystemId; + PCHAR DevicePrefix; + PFSA_MINIPORT_INIT InitRoutine; + PCHAR DeviceName; + PCHAR Vendor; + PCHAR Model; +} FSA_MINIPORT; +typedef FSA_MINIPORT *PFSA_MINIPORT; + + +#endif // _PCISUP_ --- linux/drivers/scsi/aacraid/include/perfpack.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/perfpack.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,109 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * perfpack.h + * + * Abstract: This file defines the layout of the performance data that is passed + * back from the FSA filesystem driver. + * + * + --*/ + +#ifndef _FSA_PERFPACK_H_ +#define _FSA_PERFPACK_H_ 1 + + +//#define FSA_DO_PERF 1 /* enable the engineering counters */ + +#ifdef FSA_DO_PERF +// +// engineering counters +// +typedef struct _FSA_PERF_DATA { + ULONG FibsSent; + ULONG ReadDirs; + ULONG GetAttrs; + ULONG SetAttrs; + ULONG Lookups; + ULONG ReadFibs; + ULONG WriteFibs; + ULONG CreateFibs; + ULONG MakeDirs; + ULONG RemoveFibs; + ULONG RemoveDirs; + ULONG RenameFibs; + ULONG ReadDirPlus; + ULONG FsStat; + ULONG WriteBytes; + ULONG ReadBytes; +// NT FSA entry points + ULONG FsaFsdCreateCount; + ULONG FsaFsdCloseCount; + ULONG FsaFsdReadCount; + ULONG FsaFsdWriteCount; + ULONG FsaFsdQueryInformationCount; + + struct _FsaFsdSetInfomation{ + ULONG FsaSetAllocationInfoCount; + ULONG FsaSetBasicInfoCount; + ULONG FsaSetDispositionInfoCount; + ULONG FsaSetEndOfFileInfoCount; + ULONG FsaSetPositionInfoCount; + ULONG FsaSetRenameInfoCount; + ULONG FsaClearArchiveBitCount; + }; + + ULONG FsaFsdFlushBuffersCount; + ULONG FsaFsdQueryVolumeInfoCount; + ULONG FsaFsdSetVolumeInfoCount; + ULONG FsaFsdCleanupCount; + ULONG FsaFsdDirectoryControlCount; + ULONG FsaFsdFileSystemControlCount; + ULONG FsaFsdLockControlCount; + ULONG FsaFsdDeviceControlCount; + ULONG FsaFsdShutdownCount; + ULONG FsaFsdQuerySecurityInfo; + ULONG FsaFsdSetSecurityInfo; + ULONG FastIoCheckIfPossibleCount; + ULONG FastIoReadCount; + ULONG FastIoWriteCount; + ULONG FastIoQueryBasicInfoCount; + ULONG FastIoQueryStandardInfoCount; + ULONG FastIoLockCount; + ULONG FastIoUnlockSingleCount; + ULONG FastIoUnlockAllCount; + ULONG FastIoUnlockAllByKeyCount; + ULONG FastIoDeviceControlCount; + } FSA_PERF_DATA; + +typedef FSA_PERF_DATA *PFSA_PERF_DATA; + + +#else /* FSA_DO_PERF */ + +// +// engineering performance counters are disabled +// +#define FSA_DO_PERF_INC(Counter) /* */ +#define FSA_DO_FSP_PERF_INC(Counter) /* */ + +#endif /* FSA_DO_PERF */ + +#endif // _FSA_PERFPACK_H_ --- linux/drivers/scsi/aacraid/include/port.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/port.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,86 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * port.h + * + * Abstract: This module defines functions and structures that are in common among all miniports + * + * + --*/ + +#ifndef _PORT_ +#define _PORT_ + + +#ifdef DBG +#define AfaPortPrint if (AfaPortPrinting) DbgPrint +extern int AfaPortPrinting; +#else +#define AfaPortPrint +#endif DBG + +extern int AfaPortPrinting; + + +BOOLEAN +AfaPortAllocateAdapterCommArea( + IN PVOID Arg1, + IN OUT PVOID *CommHeaderAddress, + IN ULONG CommAreaSize, + IN ULONG CommAreaAlignment + ); + + +BOOLEAN +AfaPortFreeAdapterCommArea( + IN PVOID Arg1 + ); + + +AAC_STATUS +AfaPortBuildSgMap( + PVOID Arg1, + IN PSGMAP_CONTEXT SgMapContext + ); + + +VOID +AfaPortFreeDmaResources( + PVOID Arg1, + IN PSGMAP_CONTEXT SgMapContext + ); + + +BOOLEAN +AfaPortAllocateAndMapFibSpace( + PVOID Arg1, + IN PMAPFIB_CONTEXT MapFibContext + ); + + +BOOLEAN +AfaPortUnmapAndFreeFibSpace( + PVOID Arg1, + IN PMAPFIB_CONTEXT MapFibContext + ); + + +#endif // _PORT_ + --- linux/drivers/scsi/aacraid/include/protocol.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/protocol.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,248 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * protocol.h + * + * Abstract: Defines the commands and command data which enables the nt + * filesystem driver to be the client of the fsa adapter + * filesystem. This protocol is largely modeled after the NFS + * V3 protocol with modifications allowed due to the unique + * client/server model FSA works under. + * + * + * + --*/ + +#ifndef _PROTOCOL_H_ +#define _PROTOCOL_H_ + + +#include // definition of FSAFID; includes fsatypes.h +#include // 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_ + --- linux/drivers/scsi/aacraid/include/revision.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/revision.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,349 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * revision.h + * + * Abstract: This module contains all of the revision information for + * the FSA product, as well as the support routines for + * checking module compatibility. + * + * Before editing anything in this module, make sure that + * you read the comments. Some lines are changed automatically + * as part of the build, and should never be changed by hand. + * + * Routines (all inlines): + * + * RevGetBuildNumber - Retrieve current build number + * RevGetExternalRev - Retrieve revision for external use + * RevGetFullRevision - Retrieve full revision structure + * + * RevCheckCompatibility - Checks compatibility base on internal table + * + * RevCheckCompatibilityFullInfo - Check for static component + * RevGetCompInfoTableSize - Get size for static component table + * RevGetCompInfoTable - Get actual table to place on static component + * RevGetBuildNumberFromInfo - Get build number for static component. + * + * + * + --*/ + +#ifndef _REVISION_H +#define _REVISION_H + + +#include "version.h" // revision numbers kept separate so they can be used by resource compiler as well + +typedef int REV_BOOL; + +#define REV_TRUE 1 +#define REV_FALSE 0 + +// +// Define Revision Levels for this product +// +// IMPORTANT: Do NOT modify BUILD_NUMBER define, this is modified +// automatically by the build. +// +// Version is VMAJOR.MINOR-DASH TYPE (Build BUILD_NUMBER) +// +// IMPORTANT: Don't access these revisions directly. They can be +// accessed via, the RevGetXxxxx rouines. +// + + +#define REV_AS_LONGWORD \ + ((REV_MAJOR << 24) | (REV_MINOR << 16) | (REV_TYPE << 8) | (REV_DASH)) + + + +#ifndef BIOS + +// +// Enumerate the types of product levels we can have +// +enum { + RevType_Devo=1, // Development mode, testing all of latest + RevType_Alpha, // Alpha - Internal field test + RevType_Beta, // Beta - External field test + RevType_Release // Release - Retail version +}; + +// +// Define the basic structure for all revision information. Note +// that the ordering of the components is such that they should +// always increase. dash will be updated the most, then the version +// type, then minor and major. +// +typedef struct { + union { + struct { + unsigned char dash; // Dash version number + unsigned char type; // Type, 1=Devo, 2=Alpha, 3=Beta, 4=Release + unsigned char minor;// Minor version minor + unsigned char major;// Major version number + } comp; // Components to external viewed rev number + unsigned long ul; // External revision as single 32-bit value + } external; // External revision number (union) + unsigned long buildNumber; // Automatically generated build number +} FsaRevision; + + +// +// Define simple routines to get basic revision information. The +// definitions should never be accessed directly. These routines +// are meant to be used to access all relevant information no matter +// how simple. +// +static inline unsigned long RevGetBuildNumber() {return REV_BUILD_NUMBER;} + +static inline unsigned long RevGetExternalRev() {return REV_AS_LONGWORD;} + + +// +// Enumerate different components that may have to check +// compatibility. This list of components can be changed +// at any time. +// +// IMPORTANT: ONLY add to the END of this enum structure. Otherwise, +// incompatibilities between component rev checking will +// cause wrong checking results. +// +typedef enum { + RevApplication = 1, // Any user End application + RevDkiCli, // ADAPTEC proprietary interface (knows FIBs) + RevNetService, // Network Service Revision (under API) + RevApi, // ADAPTEC User mode API + RevFileSysDriver, // FSA File System Driver + RevMiniportDriver, // FSA File System Miniport Driver + RevAdapterSW, // Adapter Software (or NT Simulator) + RevMonitor, // Monitor for adapter hardware (MON960 for now) + RevRemoteApi // The remote API. + // ALWAYS ADD NEW COMPONENTS HERE - AT END +} RevComponent; + +// +// Define a structure so that we can create a compatibility table. +// +typedef struct { + RevComponent A,B; + unsigned long BuildNumOfB_RequiredByA; + unsigned long BuildNumOfA_RequiredByB; +} RevCompareElement; + +// +// Now, define the table. This table should only be included once, +// in one program. If it is linked from 2 modules, there will likely +// be a multiply defined symbol error from the linker. +// +// To fix this problem, REV_REFERENCE_ONLY can be defined. This will +// allow access to the revision information table without a redefinition +// of the tables. +// +extern const int RevCompareTableLength; + +extern const RevCompareElement RevCompareTable[]; + +/********************************************************************\ +* Routine: RevCheckCompatibility(callerComp,compB,compB_BuildNumber) +* +* The following routine is used to check compatibility between +* the calling component and a component that has some dependencies +* on it. If this routine returns REV_FALSE, it is expected that the caller +* will send an appropriate incompatibility message and stop. +* +* This routine is only meant to check for compatibility in the +* absolute sense. If code wishes to execute a different path based +* on the CompB_BuildNumber, then this routine is not useful. The +* routine RevGetBuildNumber can be used to get the calling module's +* current build number for a comparison check. +* +* The return value is REV_TRUE, if compatibility is possible, and REV_FALSE +* if the components are definitely not compatible, or there is an +* error when trying to figure it out. To be more specific: +* +* 1) REV_TRUE if component B is newer than calling component. (In this +* case, the revision check done by component B with respect to +* this component will give the real compatibility information. +* It is the only one with the knowledge, since this component +* could not look into the future.) +* 2) REV_TRUE if calling component is more recent and table shows okay +* 3) REV_FALSE if calling component more recent and table show not okay +* 4) REV_FALSE if calling component is more recent and table entry to +* check does not exist. +* +* Note that the CompB_BuildNumber must be attained by the calling +* routine through some mechanism done by the caller. +* +* Input: +* +* callerComp - Name of component making this call +* compB - Name of component to check compatibility with +* compB_BuildNumber - Build number to component B +* +* Output: +* +* None +* +* Return Value: +* +* REV_TRUE - Component compatibility is possible, continue as usual. compB +* must give true compatibility information. +* REV_FALSE - Incompatible components, notify and end +* +\********************************************************************/ +static inline REV_BOOL RevCheckCompatibility( + RevComponent callerComp, + RevComponent compB, + unsigned long compB_BuildNumber) +{ + int i; + unsigned long RevForB; + + // + // Compatibility check is possible, so we should continue. When + // compB makes this call in its own component, it will get the + // true compatibility information, since only it can know. + // + if (RevGetBuildNumber() < compB_BuildNumber) return REV_TRUE; + + // + // Go through rev table. When the components are found in the + // same table entry, return the approprate number. + // + for (i=0; i= 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 + + + + + + + --- linux/drivers/scsi/aacraid/include/rx.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/rx.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,80 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * rx.h + * + * Abstract: Prototypes and data structures unique to the Rx based controller board. + * + * + --*/ + + +typedef struct _Rx_ADAPTER_EXTENSION { + + // + // The following must be first. + // + PPCI_MINIPORT_COMMON_EXTENSION Common; + struct _Rx_ADAPTER_EXTENSION *Next; // Next adapter miniport structure + USHORT LocalMaskInterruptControl; + PRx_DEVICE_REGISTERS Device; + +} Rx_ADAPTER_EXTENSION; + + +typedef Rx_ADAPTER_EXTENSION *PRx_ADAPTER_EXTENSION; + + + +#ifdef LINUX +/* + * + */ + +#define Rx_READ_UCHAR(AEP, CSR) *(volatile unsigned char *) &((AEP)->Device->CSR) + + + +#define Rx_READ_ULONG(AEP, CSR) *(volatile unsigned int *) &((AEP)->Device->CSR) +#define Rx_WRITE_UCHAR(AEP, CSR, Value) *(volatile unsigned char *) &((AEP)->Device->CSR) = (Value) + + +#define Rx_WRITE_ULONG(AEP, CSR, Value) *(volatile unsigned int *) &((AEP)->Device->CSR) = (Value) + +#endif /* LINUX */ + + +VOID +RxInterruptAdapter( + PVOID Arg1 + ); + +VOID +RxNotifyAdapter( + PVOID Arg1, + IN HOST_2_ADAP_EVENT AdapterEvent + ); + +VOID +RxResetDevice( + PVOID Arg1 + ); + + --- linux/drivers/scsi/aacraid/include/rxcommon.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/rxcommon.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,105 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * rxcommon.h + * + * Abstract: Structures and defines for the i960 Rx chip. + * + * + --*/ + +#ifndef _Rx_COMMON_H_ +#define _Rx_COMMON_H_ + + + +// +// Rx Message Unit Registers +// + +typedef volatile struct _StructRxMURegisters { + // Local | PCI* | Name + // | | + unsigned ARSR; // 1300h | 00h | APIC Register Select Register + unsigned reserved0; // 1304h | 04h | Reserved + unsigned AWR; // 1308h | 08h | APIC Window Register + unsigned reserved1; // 130Ch | 0Ch | Reserved + unsigned IMRx[2]; // 1310h | 10h | Inbound Message Registers + unsigned OMRx[2]; // 1318h | 18h | Outbound Message Registers + unsigned IDR; // 1320h | 20h | Inbound Doorbell Register + unsigned IISR; // 1324h | 24h | Inbound Interrupt Status Register + unsigned IIMR; // 1328h | 28h | Inbound Interrupt Mask Register + unsigned ODR; // 132Ch | 2Ch | Outbound Doorbell Register + unsigned OISR; // 1330h | 30h | Outbound Interrupt Status Register + unsigned OIMR; // 1334h | 34h | Outbound Interrupt Mask Register + // * Must access trhough ATU Inbound Translation Window + +}Rx_MU_CONFIG; +typedef Rx_MU_CONFIG *PRx_MU_CONFIG; + +typedef volatile struct _Rx_Inbound { + + unsigned Mailbox[8]; + +}Rx_Inbound; + +typedef Rx_Inbound *PRx_Inbound; + +#define InboundMailbox0 IndexRegs.Mailbox[0] +#define InboundMailbox1 IndexRegs.Mailbox[1] +#define InboundMailbox2 IndexRegs.Mailbox[2] +#define InboundMailbox3 IndexRegs.Mailbox[3] +#define InboundMailbox4 IndexRegs.Mailbox[4] + + + +#define INBOUNDDOORBELL_0 0x00000001 +#define INBOUNDDOORBELL_1 0x00000002 +#define INBOUNDDOORBELL_2 0x00000004 +#define INBOUNDDOORBELL_3 0x00000008 +#define INBOUNDDOORBELL_4 0x00000010 +#define INBOUNDDOORBELL_5 0x00000020 +#define INBOUNDDOORBELL_6 0x00000040 + + +#define OUTBOUNDDOORBELL_0 0x00000001 +#define OUTBOUNDDOORBELL_1 0x00000002 +#define OUTBOUNDDOORBELL_2 0x00000004 +#define OUTBOUNDDOORBELL_3 0x00000008 +#define OUTBOUNDDOORBELL_4 0x00000010 + + +#define InboundDoorbellReg MUnit.IDR + +#define OutboundDoorbellReg MUnit.ODR + + +typedef struct _Rx_DEVICE_REGISTERS { + Rx_MU_CONFIG MUnit; // 1300h - 1334h + unsigned reserved1[6]; // 1338h - 134ch + Rx_Inbound IndexRegs; +} Rx_DEVICE_REGISTERS; + +typedef Rx_DEVICE_REGISTERS *PRx_DEVICE_REGISTERS; + + +#endif // _Rx_COMMON_H_ + + --- linux/drivers/scsi/aacraid/include/sap1.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/sap1.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,78 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * sap1.h + * + * Abstract: Prototypes and data structures unique to the Strong Arm based controller board. + * + * + --*/ + +#define Sa_MINIPORT_REVISION 1 + +typedef struct _Sa_ADAPTER_EXTENSION { + + // + // The following must be first. + // + PPCI_MINIPORT_COMMON_EXTENSION Common; + struct _Sa_ADAPTER_EXTENSION *Next; // Next adapter miniport structure + USHORT LocalMaskInterruptControl; + PSa_DEVICE_REGISTERS Device; + +} Sa_ADAPTER_EXTENSION; + +typedef Sa_ADAPTER_EXTENSION *PSa_ADAPTER_EXTENSION; + + + +#ifdef LINUX +/* + * + */ + + +#define Sa_READ_USHORT(AEP, CSR) *(volatile unsigned short *) &((AEP)->Device->CSR) +#define Sa_READ_ULONG(AEP, CSR) *(volatile unsigned int *) &((AEP)->Device->CSR) + + +#define Sa_WRITE_USHORT(AEP, CSR, Value) *(volatile unsigned short *) &((AEP)->Device->CSR) = (Value) +#define Sa_WRITE_ULONG(AEP, CSR, Value) *(volatile unsigned int *) &((AEP)->Device->CSR) = (Value) + +#endif /* LINUX */ + + +VOID +SaInterruptAdapter( + PVOID Arg1 + ); + +VOID +SaNotifyAdapter( + PVOID Arg1, + IN HOST_2_ADAP_EVENT AdapterEvent + ); + +VOID +SaResetDevice( + PVOID Arg1 + ); + + --- linux/drivers/scsi/aacraid/include/sap1common.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/sap1common.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,110 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * sap1common.h + * + * Abstract: Structures and defines for the Drawbridge and StrongArm110 chip. + * + --*/ + +#ifndef _Sa_COMMON_H_ +#define _Sa_COMMON_H_ + + +// +// SaP1 Message Unit Registers +// + +typedef volatile struct _StructSaDrawbridge_CSR_RegisterMap { + // Offset | Name + unsigned reserved[10]; // 00h-27h | Reserved + unsigned char LUT_Offset; // 28h | Looup Table Offset + unsigned char reserved1[3]; // 29h-2bh | Reserved + unsigned LUT_Data; // 2ch | Looup Table Data + unsigned reserved2[26]; // 30h-97h | Reserved + unsigned short PRICLEARIRQ; // 98h | Primary Clear Irq + unsigned short SECCLEARIRQ; // 9ah | Secondary Clear Irq + unsigned short PRISETIRQ; // 9ch | Primary Set Irq + unsigned short SECSETIRQ; // 9eh | Secondary Set Irq + unsigned short PRICLEARIRQMASK; // a0h | Primary Clear Irq Mask + unsigned short SECCLEARIRQMASK; // a2h | Secondary Clear Irq Mask + unsigned short PRISETIRQMASK; // a4h | Primary Set Irq Mask + unsigned short SECSETIRQMASK; // a6h | Secondary Set Irq Mask + unsigned MAILBOX0; // a8h | Scratchpad 0 + unsigned MAILBOX1; // ach | Scratchpad 1 + unsigned MAILBOX2; // b0h | Scratchpad 2 + unsigned MAILBOX3; // b4h | Scratchpad 3 + unsigned MAILBOX4; // b8h | Scratchpad 4 + unsigned MAILBOX5; // bch | Scratchpad 5 + unsigned MAILBOX6; // c0h | Scratchpad 6 + unsigned MAILBOX7; // c4h | Scratchpad 7 + + unsigned ROM_Setup_Data; // c8h | Rom Setup and Data + unsigned ROM_Control_Addr; // cch | Rom Control and Address + + unsigned reserved3[12]; // d0h-ffh | reserved + unsigned LUT[64]; // 100h-1ffh| Lookup Table Entries + + // + // TO DO + // need to add DMA, I2O, UART, etc registers form 80h to 364h + // + +}Sa_Drawbridge_CSR; + +typedef Sa_Drawbridge_CSR *PSa_Drawbridge_CSR; + + +#define Mailbox0 SaDbCSR.MAILBOX0 +#define Mailbox1 SaDbCSR.MAILBOX1 +#define Mailbox2 SaDbCSR.MAILBOX2 +#define Mailbox3 SaDbCSR.MAILBOX3 +#define Mailbox4 SaDbCSR.MAILBOX4 + + +#define Mailbox7 SaDbCSR.MAILBOX7 + +#define DoorbellReg_p SaDbCSR.PRISETIRQ +#define DoorbellReg_s SaDbCSR.SECSETIRQ +#define DoorbellClrReg_p SaDbCSR.PRICLEARIRQ + + +#define DOORBELL_0 0x00000001 +#define DOORBELL_1 0x00000002 +#define DOORBELL_2 0x00000004 +#define DOORBELL_3 0x00000008 +#define DOORBELL_4 0x00000010 +#define DOORBELL_5 0x00000020 +#define DOORBELL_6 0x00000040 + + +#define PrintfReady DOORBELL_5 +#define PrintfDone DOORBELL_5 + +typedef struct _Sa_DEVICE_REGISTERS { + Sa_Drawbridge_CSR SaDbCSR; // 98h - c4h +} Sa_DEVICE_REGISTERS; + +typedef Sa_DEVICE_REGISTERS *PSa_DEVICE_REGISTERS; + + +#endif // _Sa_COMMON_H_ + + --- linux/drivers/scsi/aacraid/include/version.h.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/include/version.h Tue Jun 13 12:52:42 2000 @@ -0,0 +1,35 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * version.h + * + * Abstract: Keeps track of build number for development purposes. + * + --*/ + +#include "build_number.h" + +#define REV_MAJOR 2 +#define REV_MINOR 1 +#define REV_TYPE RevType_Release +#define REV_DASH 5 + +#define FSA_VERSION_STRING "2.1.5.3857\0" + --- linux/drivers/scsi/aacraid/linit.c.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/linit.c Tue Jun 13 12:52:42 2000 @@ -0,0 +1,1035 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * linit.c + * + * Abstract: Linux Driver entry module for Adaptec RAID Array Controller + * + * Provides the following driver entry points: + * AAC_DetectHostAdapter() + * AAC_ReleaseHostAdapter() + * AAC_QueueCommand() + * AAC_ResetCommand() + * AAC_BIOSDiskParameters() + * AAC_ProcDirectoryInfo() + * + --*/ + +/*------------------------------------------------------------------------------ + * D E F I N E S + *----------------------------------------------------------------------------*/ +#define AAC_DRIVER_VERSION "0.1.1" +#define AAC_DRIVER_BUILD_DATE __DATE__ +#define MAX_DRIVER_QUEUE_DEPTH 500 + +/*------------------------------------------------------------------------------ + * I N C L U D E S + *----------------------------------------------------------------------------*/ +#include "osheaders.h" + +#include "AacGenericTypes.h" + +#ifdef MODULE +#include +#endif +#include "sd.h" +#include "linit.h" +#include "aac_unix_defs.h" +#include "fsatypes.h" +#include "comstruc.h" +#include "fsaport.h" +#include "pcisup.h" +#include "port.h" + +/*------------------------------------------------------------------------------ + * G L O B A L S + *----------------------------------------------------------------------------*/ +extern FSA_MINIPORT MiniPorts[]; +extern int CommPrinting; +extern char DescriptionString[]; +extern char devicestr[]; + +/*------------------------------------------------------------------------------ + * M O D U L E G L O B A L S + *----------------------------------------------------------------------------*/ +aac_options_t g_options = { CMN_ERR_LEVEL, 0 }; // default message_level + +char g_DriverName[] = { "aacraid" }; +#define module_options aacraid_options +static char * aacraid_options = NULL; + +/* AAC_ProcDirectoryEntry is the /proc/scsi directory entry.*/ +proc_dir_entry_t AAC_ProcDirectoryEntry = + { PROC_SCSI_SCSI, 3, "aacraid", S_IFDIR | S_IRUGO | S_IXUGO, 2, + 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +PCI_MINIPORT_COMMON_EXTENSION *g_CommonExtensionPtrArray[ MAXIMUM_NUM_ADAPTERS ]; +unsigned g_HostAdapterCount = 0; +unsigned g_chardev_major = 0; + +int g_single_command_done = FALSE; + +/*------------------------------------------------------------------------------ + * F U N C T I O N P R O T O T Y P E S + *----------------------------------------------------------------------------*/ +int AacHba_Ioctl( + PCI_MINIPORT_COMMON_EXTENSION *CommonExtension, + int cmd, + void * arg ); + +int AacHba_ProbeContainers( + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr ); + +int AacHba_DoScsiCmd( + Scsi_Cmnd *scsi_cmnd_ptr, + int wait ); + +void AacHba_DetachAdapter( + IN PVOID AdapterArg ); + +int AacHba_ClassDriverInit( + PCI_MINIPORT_COMMON_EXTENSION * CommonExtensionPtr); + +void AacHba_AbortScsiCommand( + Scsi_Cmnd *scsi_cmnd_ptr ); + + +/*------------------------------------------------------------------------------ + * L O C A L F U N C T I O N P R O T O T Y P E S + *----------------------------------------------------------------------------*/ +static int parse_keyword( + char ** str_ptr, + char * keyword ); + +static void AAC_ParseDriverOptions( + char * cmnd_line_options_str ); + +static void AAC_AnnounceDriver( void ); + +int AAC_ChardevIoctl( + struct inode * inode_ptr, + struct file * file_ptr, + unsigned int cmd, + unsigned long arg ); + +int AAC_ChardevOpen( + struct inode * inode_ptr, + struct file * file_ptr ); + +int AAC_ChardevRelease( + struct inode * inode_ptr, + struct file * file_ptr ); + +struct file_operations AAC_fops = { + NULL, // lseek + NULL, // read + NULL, // write + NULL, // readdir + NULL, // poll + AAC_ChardevIoctl, // ioctl + NULL, // mmap + AAC_ChardevOpen, // open + NULL, // flush + AAC_ChardevRelease, // release + NULL, // fsync + NULL, // fasync + NULL, // check media change + NULL, // revalidate + NULL // lock +}; + +/*------------------------------------------------------------------------------ + * F U N C T I O N S + *----------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------ + AAC_AnnounceDriver() + + Announce the driver name, version and date. + *----------------------------------------------------------------------------*/ +static void AAC_AnnounceDriver( void ) +/*----------------------------------------------------------------------------*/ +{ + printk("<1>%s, %s\n", + "aacraid raid driver version", AAC_DRIVER_BUILD_DATE ); + schedule(); +} + + +/*------------------------------------------------------------------------------ + AAC_DetectHostAdapter() + + Probe for AAC Host Adapters initialize, register, and report the + configuration of each AAC Host Adapter found. + + Preconditions: + Postconditions: + - Returns the number of adapters successfully initialized and + registered. + - Initialize all data necessary for this particular SCSI driver. + Notes: + The detect routine must not call any of the mid level functions + to queue commands because things are not guaranteed to be set + up yet. The detect routine can send commands to the host adapter + as long as the program control will not be passed to scsi.c in + the processing of the command. Note especially that + scsi_malloc/scsi_free must not be called. + *----------------------------------------------------------------------------*/ +int AAC_DetectHostAdapter( + Scsi_Host_Template *HostTemplate ) +/*----------------------------------------------------------------------------*/ +{ + int index; + int ContainerId; + uint16_t vendor_id, device_id, sub_vendor_id, sub_system_id; + struct Scsi_Host *host_ptr; + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr; + struct pci_dev *dev = NULL; + extern int NumMiniPorts; + fsadev_t *fsa_dev_ptr; + char *DeviceName; + + struct pci_dev *devp; + + int first_index, last_index, increment; + + CommPrinting = TRUE; + + #ifdef MODULE + EXPORT_NO_SYMBOLS; + #endif + + AAC_AnnounceDriver(); + + if( module_options != NULL ) + AAC_ParseDriverOptions( module_options ); + + + // NumMiniPorts & MiniPorts[] defined in aacid.c + if (g_options.reverse_scan == 0) { + first_index = 0; + last_index = NumMiniPorts; + increment = 1; + } else { + first_index = NumMiniPorts -1; + last_index = -1; + increment = -1; + } + + for( index = first_index; index != last_index; index += increment ) + { + device_id = MiniPorts[index].DeviceId; + vendor_id = MiniPorts[index].VendorId; + DeviceName = MiniPorts[index].DeviceName; + cmn_err(CE_DEBUG, "Checking %s %x/%x/%x/%x", + DeviceName, + vendor_id, + device_id, + MiniPorts[index].SubVendorId, + MiniPorts[index].SubSystemId); + + + // pci_find_device traverses the pci_devices linked list for devices + // with matching vendor and device ids. + + dev = NULL; // start from beginning of list + while( ( dev = pci_find_device( vendor_id, device_id, dev ) ) ) + { + if( pci_read_config_word( dev, PCI_SUBSYSTEM_VENDOR_ID, &sub_vendor_id ) ){ + cmn_err(CE_WARN, "pci_read_config_word SUBSYS_VENDOR_ID failed"); + break; + } + if( pci_read_config_word( dev, PCI_SUBSYSTEM_ID, &sub_system_id ) ){ + cmn_err(CE_WARN, "pci_read_config_work SUBSYSTEM_ID failed"); + break; + } + + cmn_err(CE_DEBUG, " found: %x/%x/%x/%x", vendor_id, device_id, sub_vendor_id, sub_system_id); + if( ( sub_vendor_id != MiniPorts[index].SubVendorId ) || + ( sub_system_id != MiniPorts[index].SubSystemId ) ){ + continue; + } + + + printk("<1>%s device detected\n", DeviceName ); + // cmn_err(CE_WARN, "%x/%x/%x/%x", vendor_id, device_id, sub_vendor_id, sub_system_id); + + // Increment the host adapter count + g_HostAdapterCount++; + + // scsi_register() allocates memory for a Scsi_Hosts structure and + // links it into the linked list of host adapters. This linked list + // contains the data for all possible scsi hosts. + // This is similar to the Scsi_Host_Template, except that we have + // one entry for each actual physical host adapter on the system, + // stored as a linked list. If there are two AAC boards, then we + // will need to make two Scsi_Host entries, but there will be only + // one Scsi_Host_Template entry. The second argument to scsi_register() + // specifies the size of the extra memory we want to hold any device + // specific information. + host_ptr = scsi_register( HostTemplate, + sizeof( PCI_MINIPORT_COMMON_EXTENSION ) ); + + // These three parameters can be used to allow for wide SCSI + // and for host adapters that support multiple buses. + host_ptr->max_id = 17; + host_ptr->max_lun = 8; + host_ptr->max_channel = 1; + + host_ptr->irq = dev->irq; // Adapter IRQ number + host_ptr->base = ( char * )(dev->base_address[0] & ~0xff); + + cmn_err( CE_DEBUG, "Device base address = 0x%lx [0x%lx]", host_ptr->base, dev->base_address[0] ); + cmn_err( CE_DEBUG, "Device irq = 0x%lx", dev->irq ); + + // The unique_id field is a unique identifier that must be assigned + // so that we have some way of identifying each host adapter properly + // and uniquely. For hosts that do not support more than one card in the + // system, this does not need to be set. It is initialized to zero in + // scsi_register(). This is the value returned from OsGetDeviceInstance(). + host_ptr->unique_id = g_HostAdapterCount - 1; + + host_ptr->this_id = 16; // SCSI Id for the adapter itself + + // Set the maximum number of simultaneous commands supported by the driver. + host_ptr->can_queue = MAX_DRIVER_QUEUE_DEPTH; + + // Define the maximum number of scatter/gather elements supported by + // the driver. + host_ptr->sg_tablesize = 17; + + host_ptr->cmd_per_lun = 1; // untagged queue depth + + // This function is called after the device list has been built to find + // tagged queueing depth supported for each device. + host_ptr->select_queue_depths = AAC_SelectQueueDepths; + + CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )host_ptr->hostdata; + + // attach a pointer back to Scsi_Host + CommonExtensionPtr->OsDep.scsi_host_ptr = host_ptr; + CommonExtensionPtr->OsDep.MiniPortIndex = index; + + // Initialize the ordinal number of the device to -1 + fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev ); + for( ContainerId = 0; ContainerId < MAXIMUM_NUM_CONTAINERS; ContainerId++ ) + fsa_dev_ptr->ContainerDevNo[ContainerId] = -1; + + // Call initialization routine + if( ( *MiniPorts[index].InitRoutine ) + ( CommonExtensionPtr, host_ptr->unique_id, dev->bus->number, 0 ) != 0 ) + { + // device initialization failed + cmn_err( CE_WARN, "%s:%d device initialization failed", DeviceName, host_ptr->unique_id ); + scsi_unregister( host_ptr ); + g_HostAdapterCount--; + } + else + { + cmn_err( CE_NOTE, "%s:%d device initialization successful", DeviceName, host_ptr->unique_id ); + AacHba_ClassDriverInit( CommonExtensionPtr ); + cmn_err(CE_NOTE, "%d:%d AacHba_ClassDriverInit complete", DeviceName, host_ptr->unique_id); + AacHba_ProbeContainers( CommonExtensionPtr ); + cmn_err( CE_DEBUG, "Probe containers completed" ); + g_CommonExtensionPtrArray[ g_HostAdapterCount - 1 ] = CommonExtensionPtr; + // OsSleep( 1 ); + } + } + } + + if( g_HostAdapterCount ) + if( !( g_chardev_major = register_chrdev( 0, devicestr, &AAC_fops ) ) ) + cmn_err( CE_WARN, "%s: unable to register %s device", DeviceName, devicestr); + + HostTemplate->present = g_HostAdapterCount; // # of cards of this type found + + return( g_HostAdapterCount ); +} + + +/*------------------------------------------------------------------------------ + AAC_ReleaseHostAdapter() + + Release all resources previously acquired to support a specific Host + Adapter and unregister the AAC Host Adapter. + *----------------------------------------------------------------------------*/ +int AAC_ReleaseHostAdapter( + struct Scsi_Host *host_ptr ) +/*----------------------------------------------------------------------------*/ +{ + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr; + + cmn_err( CE_DEBUG, "AAC_ReleaseHostAdapter" ); + + CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )host_ptr->hostdata; + + // kill any threads we started + kill_proc( CommonExtensionPtr->OsDep.thread_pid, SIGKILL, 0 ); + + // Call the comm layer to detach from this adapter + AacHba_DetachAdapter( CommonExtensionPtr->Adapter ); + + // remove interrupt binding + OsDetachInterrupt( CommonExtensionPtr->MiniPort ); + + SaDetachDevice( CommonExtensionPtr ); + + // unregister adapter + scsi_unregister( host_ptr ); + + if( g_chardev_major ) + { + unregister_chrdev( g_chardev_major, devicestr ); + g_chardev_major = 0; + } + + return( 0 ); // #REVISIT# return code +} + + +/*------------------------------------------------------------------------------ + AAC_QueueCommand() + + Queues a command for execution by the associated Host Adapter. + *----------------------------------------------------------------------------*/ +int AAC_QueueCommand( + Scsi_Cmnd *scsi_cmnd_ptr, + void ( *CompletionRoutine )( Scsi_Cmnd * ) ) +/*----------------------------------------------------------------------------*/ +{ + scsi_cmnd_ptr->scsi_done = CompletionRoutine; + + // AacHba_DoScsiCmd() handles command processing, setting the + // result code and calling completion routine. + #ifdef SYNC_FIB + if( AacHba_DoScsiCmd( scsi_cmnd_ptr, 1 ) ) // called with wait = TRUE + #else + if( AacHba_DoScsiCmd( scsi_cmnd_ptr, 0 ) ) // called with wait = FALSE + #endif + cmn_err( CE_DEBUG, "AacHba_DoScsiCmd failed" ); + return 0; +} + + +/*------------------------------------------------------------------------------ + AAC_Done() + + Callback function for a non-queued command. + + Postconditions + Sets g_single_command done to TRUE + *----------------------------------------------------------------------------*/ +void AAC_Done( + Scsi_Cmnd * scsi_cmnd_ptr ) +/*----------------------------------------------------------------------------*/ +{ + g_single_command_done = TRUE; +} + + +/*------------------------------------------------------------------------------ + AAC_Command() + + Accepts a single command for execution by the associated Host Adapter. + + Postconditions + Returns an int where: + Byte 0 = SCSI status code + Byte 1 = SCSI 1 byte message + Byte 2 = host error return + Byte 3 = mid level error return + *----------------------------------------------------------------------------*/ +int AAC_Command( + Scsi_Cmnd *scsi_cmnd_ptr ) +/*----------------------------------------------------------------------------*/ +{ + scsi_cmnd_ptr->scsi_done = AAC_Done; + + cmn_err( CE_DEBUG, "AAC_Command" ); + + // AacHba_DoScsiCmd() handles command processing, setting the + // result code and calling completion routine. + g_single_command_done = FALSE; + + AacHba_DoScsiCmd( scsi_cmnd_ptr, 0 ); + while( !g_single_command_done ); + return( scsi_cmnd_ptr->result ); +} + + +/*------------------------------------------------------------------------------ + AAC_AbortCommand() + + Abort command if possible. + *----------------------------------------------------------------------------*/ +int AAC_AbortCommand( + Scsi_Cmnd *scsi_cmnd_ptr ) +/*----------------------------------------------------------------------------*/ +{ + int target = scsi_cmnd_ptr->target; + int hba = scsi_cmnd_ptr->host->unique_id; + int result = 0; + u_short interrupt_status; + PCI_MINIPORT_COMMON_EXTENSION *cep; + char *DeviceName; + + cmn_err( CE_WARN, "%s:%d ABORT", g_DriverName, hba, target ); + AacHba_AbortScsiCommand( scsi_cmnd_ptr ); + + cep = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata ); + DeviceName = MiniPorts[cep->OsDep.MiniPortIndex].DeviceName; + + /* + cmn_err( CE_WARN, "%s:%d Unable to abort command to target %d - " + "command already completed", DeviceName, hba, target); + result = SCSI_ABORT_NOT_RUNNING; + + cmn_err(CE_WARN, "%s:%d Unable to abort command to target %d - " + "no command found\n", DeviceName, hba, target); + result = SCSI_ABORT_NOT_RUNNING; + + cmn_err(CE_WARN, "%s:%d Unable to abort command to target %d - " + "command reset\n", DeviceName, hba, target); + result = SCSI_ABORT_PENDING; + + cmn_err(CE_WARN, "%s:%d Unable to abort command to target %d - " + "abort tag not supported\n", DeviceName, hba, target); + result = SCSI_ABORT_SNOOZE; + + cmn_err(CE_WARN, "%s:%d Aborting command to target %d - pending", + DeviceName, hba, target); + result = SCSI_ABORT_PENDING; + + cmn_err(CE_WARN, "%s:%d Unable to abort command to target %d", + DeviceName, hba, target); + result = SCSI_ABORT_BUSY; + + cmn_err(CE_WARN, "%s:%d Aborted command to target %d\n", + DeviceName, hba, target); + result = SCSI_ABORT_SUCCESS; + */ + + // Abort not supported yet + result = SCSI_ABORT_BUSY; + return result; +} + + +/*------------------------------------------------------------------------------ + AAC_ResetCommand() + + Reset command handling. + *----------------------------------------------------------------------------*/ +int AAC_ResetCommand( + struct scsi_cmnd *scsi_cmnd_ptr, + unsigned int reset_flags ) +/*----------------------------------------------------------------------------*/ +{ + int target = scsi_cmnd_ptr->target; + int hba = scsi_cmnd_ptr->host->unique_id; + PCI_MINIPORT_COMMON_EXTENSION *cep; + char *DeviceName; + + cep = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata ); + DeviceName = MiniPorts[cep->OsDep.MiniPortIndex].DeviceName; + + cmn_err( CE_WARN, "%s:%d RESET", DeviceName, hba, target ); + + return SCSI_RESET_PUNT; +} + + +/*------------------------------------------------------------------------------ + AAC_DriverInfo() + + Returns the host adapter name + *----------------------------------------------------------------------------*/ +const char *AAC_DriverInfo( + struct Scsi_Host *host_ptr ) +/*----------------------------------------------------------------------------*/ +{ + PCI_MINIPORT_COMMON_EXTENSION *cep; + char *DeviceName; + + cep = ( PCI_MINIPORT_COMMON_EXTENSION * )( host_ptr->hostdata ); + DeviceName = MiniPorts[cep->OsDep.MiniPortIndex].DeviceName; + + cmn_err( CE_DEBUG, "AAC_DriverInfo" ); + return (DeviceName); +} + + +/*------------------------------------------------------------------------------ + AAC_BIOSDiskParameters() + + Return the Heads/Sectors/Cylinders BIOS Disk Parameters for Disk. + The default disk geometry is 64 heads, 32 sectors, and the appropriate + number of cylinders so as not to exceed drive capacity. In order for + disks equal to or larger than 1 GB to be addressable by the BIOS + without exceeding the BIOS limitation of 1024 cylinders, Extended + Translation should be enabled. With Extended Translation enabled, + drives between 1 GB inclusive and 2 GB exclusive are given a disk + geometry of 128 heads and 32 sectors, and drives above 2 GB inclusive + are given a disk geometry of 255 heads and 63 sectors. However, if + the BIOS detects that the Extended Translation setting does not match + the geometry in the partition table, then the translation inferred + from the partition table will be used by the BIOS, and a warning may + be displayed. + *----------------------------------------------------------------------------*/ +int AAC_BIOSDiskParameters( + Scsi_Disk *scsi_disk_ptr, + kdev_t device, + int *parameter_ptr ) +/*----------------------------------------------------------------------------*/ +{ + AAC_BIOS_DiskParameters_T *disk_parameters = + ( AAC_BIOS_DiskParameters_T *)parameter_ptr; + struct buffer_head * buffer_head_ptr; + + cmn_err( CE_DEBUG, "AAC_BIOSDiskParameters" ); + + // Assuming extended translation is enabled - #REVISIT# + if( scsi_disk_ptr->capacity >= 2 * 1024 * 1024 ) // 1 GB in 512 byte sectors + { + if( scsi_disk_ptr->capacity >= 4 * 1024 * 1024 ) // 2 GB in 512 byte sectors + { + disk_parameters->heads = 255; + disk_parameters->sectors = 63; + } + else + { + disk_parameters->heads = 128; + disk_parameters->sectors = 32; + } + } + else + { + disk_parameters->heads = 64; + disk_parameters->sectors = 32; + } + + disk_parameters->cylinders = scsi_disk_ptr->capacity + /( disk_parameters->heads * disk_parameters->sectors ); + + // Read the first 1024 bytes from the disk device + buffer_head_ptr = bread( + MKDEV( MAJOR( device ), + MINOR( device ) & ~0x0F ), + 0, 1024 ); + + if( buffer_head_ptr == NULL ) + return( 0 ); + /* + If the boot sector partition table is valid, search for a partition + table entry whose end_head matches one of the standard geometry + translations ( 64/32, 128/32, 255/63 ). + */ + if( *( unsigned short * )( buffer_head_ptr->b_data + 0x1fe ) == 0xaa55 ) + { + struct partition *first_partition_entry = + ( struct partition * )( buffer_head_ptr->b_data + 0x1be ); + struct partition *partition_entry = first_partition_entry; + int saved_cylinders = disk_parameters->cylinders; + int partition_number; + unsigned char partition_entry_end_head, partition_entry_end_sector; + + for( partition_number = 0; partition_number < 4; partition_number++ ) + { + partition_entry_end_head = partition_entry->end_head; + partition_entry_end_sector = partition_entry->end_sector & 0x3f; + + if( partition_entry_end_head == ( 64 - 1 ) ) + { + disk_parameters->heads = 64; + disk_parameters->sectors = 32; + break; + } + else if( partition_entry_end_head == ( 128 - 1 ) ) + { + disk_parameters->heads = 128; + disk_parameters->sectors = 32; + break; + } + else if( partition_entry_end_head == ( 255 - 1 ) ) + { + disk_parameters->heads = 255; + disk_parameters->sectors = 63; + break; + } + partition_entry++; + } + + if( partition_number == 4 ) + { + partition_entry_end_head = first_partition_entry->end_head; + partition_entry_end_sector = first_partition_entry->end_sector & 0x3f; + } + + disk_parameters->cylinders = scsi_disk_ptr->capacity + /( disk_parameters->heads * disk_parameters->sectors ); + + if( ( partition_number < 4 ) && ( partition_entry_end_sector == disk_parameters->sectors ) ) + { + if( disk_parameters->cylinders != saved_cylinders ) + cmn_err( CE_NOTE, "Adopting geometry: heads=%d, sectors=%d from partition table %d", + disk_parameters->heads, disk_parameters->sectors, partition_number ); + } + else if( ( partition_entry_end_head > 0 ) || ( partition_entry_end_sector > 0 ) ) + { + cmn_err( CE_NOTE, "Strange geometry: heads=%d, sectors=%d in partition table %d", + partition_entry_end_head + 1, partition_entry_end_sector, partition_number ); + cmn_err( CE_NOTE, "Using geometry: heads=%d, sectors=%d", + disk_parameters->heads, disk_parameters->sectors ); + } + } + + brelse( buffer_head_ptr ); + + return( 0 ); +} + + +/*------------------------------------------------------------------------------ + AAC_ProcDirectoryInfo() + + Implement /proc/scsi//. + Used to export driver statistics and other infos to the world outside + the kernel using the proc file system. Also provides an interface to + feed the driver with information. + + Postconditions + For reads + - if offset > 0 return 0 + - if offset == 0 write data to proc_buffer and set the start_ptr to + beginning of proc_buffer, return the number of characters written. + For writes + - writes currently not supported, return 0 + *----------------------------------------------------------------------------*/ +int AAC_ProcDirectoryInfo( + char *proc_buffer, // read/write buffer + char **start_ptr, // start of valid data in the buffer + off_t offset, // offset from the beginning of the imaginary file + int bytes_available, // bytes available + int host_no, // SCSI host number + int write ) // direction of dataflow: TRUE for writes, FALSE for reads +/*----------------------------------------------------------------------------*/ +{ + int length = 0; + cmn_err( CE_DEBUG, "AAC_ProcDirectoryInfo" ); + + if( ( write ) || ( offset > 0 ) ) + return( 0 ); + + *start_ptr = proc_buffer; + + return( sprintf(&proc_buffer[length], "%s %d\n", "Raid Controller, scsi hba number", host_no ) ); +} + + + +/*------------------------------------------------------------------------------ + AAC_SelectQueueDepths() + + Selects queue depths for each target device based on the host adapter's + total capacity and the queue depth supported by the target device. + A queue depth of one automatically disables tagged queueing. + *----------------------------------------------------------------------------*/ +void AAC_SelectQueueDepths( + struct Scsi_Host * host_ptr, + Scsi_Device * scsi_device_ptr ) +/*----------------------------------------------------------------------------*/ +{ + Scsi_Device * device_ptr; + + cmn_err( CE_DEBUG, "AAC_SelectQueueDepths" ); + cmn_err( CE_DEBUG, "Device # Q Depth Online" ); + cmn_err( CE_DEBUG, "---------------------------" ); + for( device_ptr = scsi_device_ptr; device_ptr != NULL; device_ptr = device_ptr->next ) + if( device_ptr->host == host_ptr ) + { + device_ptr->queue_depth = 10; + cmn_err( CE_DEBUG, " %2d %d %d", + device_ptr->id, device_ptr->queue_depth, device_ptr->online ); + } +} + + +/*------------------------------------------------------------------------------ + AAC_SearchBiosSignature() + + Locate adapter signature in BIOS + *----------------------------------------------------------------------------*/ +int AAC_SearchBiosSignature( void ) +/*----------------------------------------------------------------------------*/ +{ + unsigned base; + unsigned namep; + int index; + int val; + char name_buf[32]; + int result = FALSE; + + for( base = 0xc8000; base < 0xdffff; base += 0x4000 ) + { + val = readb( base ); + if( val != 0x55 ) + continue; + + result = TRUE; + namep = base + 0x1e; + memcpy_fromio( name_buf, namep, 32 ); + name_buf[31] = '\0'; + } + return( result ); +} + + +/*------------------------------------------------------------------------------ + AAC_Ioctl() + + Handle SCSI ioctls + *----------------------------------------------------------------------------*/ +int AAC_Ioctl( + Scsi_Device * scsi_dev_ptr, + int cmd, + void * arg ) +/*----------------------------------------------------------------------------*/ +{ + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr; + + cmn_err( CE_DEBUG, "AAC_Ioctl" ); + CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )scsi_dev_ptr->host->hostdata; + return( AacHba_Ioctl( CommonExtensionPtr, cmd, arg ) ); +} + + + +/*------------------------------------------------------------------------------ + AAC_ChardevOpen() + + Handle character device open + + Preconditions: + Postconditions: + Returns 0 if successful, -ENODEV or -EINVAL otherwise + *----------------------------------------------------------------------------*/ +int AAC_ChardevOpen( + struct inode * inode_ptr, + struct file * file_ptr ) +/*----------------------------------------------------------------------------*/ +{ + unsigned minor_number; + + cmn_err( CE_DEBUG, "AAC_ChardevOpen" ); + + // check device permissions in file_ptr->f_mode ?? + + // extract & check the minor number + minor_number = MINOR( inode_ptr->i_rdev ); + if( minor_number > ( g_HostAdapterCount - 1 ) ) + { + cmn_err( CE_WARN, "AAC_ChardevOpen: Minor number %d not supported", minor_number ); + return( -ENODEV ); + } + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + + return( 0 ); +} + + +/*------------------------------------------------------------------------------ + AAC_ChardevRelease() + + Handle character device release. + + Preconditions: + Postconditions: + Returns 0 if successful, -ENODEV or -EINVAL otherwise + *----------------------------------------------------------------------------*/ +int AAC_ChardevRelease( + struct inode * inode_ptr, + struct file * file_ptr ) +/*----------------------------------------------------------------------------*/ +{ + cmn_err( CE_DEBUG, "AAC_ChardevRelease" ); + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + + return( 0 ); +} + + +/*------------------------------------------------------------------------------ + AAC_ChardevIoctl() + + Handle character device interface ioctls + + Preconditions: + Postconditions: + Returns 0 if successful, -ENODEV or -EINVAL otherwise + *----------------------------------------------------------------------------*/ +int AAC_ChardevIoctl( + struct inode * inode_ptr, + struct file * file_ptr, + unsigned int cmd, + unsigned long arg ) +/*----------------------------------------------------------------------------*/ +{ + unsigned minor_number; + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr; + + cmn_err( CE_DEBUG, "AAC_ChardevIoctl" ); + + // check device permissions in file_ptr->f_mode ?? + + // extract & check the minor number + minor_number = MINOR( inode_ptr->i_rdev ); + if( minor_number > ( g_HostAdapterCount - 1 ) ) + { + cmn_err( CE_WARN, "AAC_ChardevIoctl: Minor number %d not supported", minor_number ); + return( -ENODEV ); + } + + // get device pointer + CommonExtensionPtr = g_CommonExtensionPtrArray[ minor_number ]; + + // dispatch ioctl - AacHba_Ioctl() returns zero on success + if( AacHba_Ioctl( CommonExtensionPtr, cmd, ( void * )arg ) ) + return( -EINVAL ); + + return( 0 ); +} + + +/*------------------------------------------------------------------------------ + parse_keyword() + + Look for the keyword in str_ptr + + Preconditions: + Postconditions: + If keyword found + - return true and update the pointer str_ptr. + otherwise + - return false + *----------------------------------------------------------------------------*/ +static int parse_keyword( + char ** str_ptr, + char * keyword ) +/*----------------------------------------------------------------------------*/ +{ + char * ptr = *str_ptr; + + while( *keyword != '\0' ) + { + char string_char = *ptr++; + char keyword_char = *keyword++; + + if ( ( string_char >= 'A' ) && ( string_char <= 'Z' ) ) + string_char += 'a' - 'Z'; + if( ( keyword_char >= 'A' ) && ( keyword_char <= 'Z' ) ) + keyword_char += 'a' - 'Z'; + if( string_char != keyword_char ) + return FALSE; + } + *str_ptr = ptr; + return TRUE; +} + + +/*------------------------------------------------------------------------------ + AAC_ParseDriverOptions() + + For modules the usage is: + insmod -f aacraid.o 'aacraid_options=""' + *----------------------------------------------------------------------------*/ +static void AAC_ParseDriverOptions( + char * cmnd_line_options_str ) +/*----------------------------------------------------------------------------*/ +{ + int message_level; + int reverse_scan; + char *cp; + char *endp; + + cp = cmnd_line_options_str; + + cmn_err(CE_DEBUG, "AAC_ParseDriverOptions: <%s>", cp); + + while( *cp ) { + if( parse_keyword( &cp, "message_level:" ) ) { + message_level = simple_strtoul( cp, 0, 0 ); + if( ( message_level < CE_TAIL ) && ( message_level >= 0 ) ) { + g_options.message_level = message_level; + cmn_err( CE_WARN, "%s: new message level = %d", g_DriverName, g_options.message_level ); + } + else { + cmn_err( CE_WARN, "%s: invalid message level = %d", g_DriverName, message_level ); + } + } else if (parse_keyword( &cp, "reverse_scan:" ) ) { + reverse_scan = simple_strtoul( cp, 0, 0 ); + if (reverse_scan) { + g_options.reverse_scan = 1; + cmn_err( CE_WARN, "%s: reversing device discovery order", g_DriverName, g_options.message_level ); + } + } + else { + cmn_err( CE_WARN, "%s: unknown command line option <%s>", g_DriverName, cp ); + } + + /* + * skip to next option, accept " ", ";", and "," as delimiters + */ + while ( *cp && (*cp != ' ') && (*cp != ';') && (*cp != ',')) + cp++; + + if (*cp) /* skip over the delimiter */ + cp++; + } + +} + + +/*------------------------------------------------------------------------------ + Include Module support if requested. + + To use the low level SCSI driver support using the linux kernel loadable + module interface we should initialize the global variable driver_interface + (datatype Scsi_Host_Template) and then include the file scsi_module.c. + This should also be wrapped in a #ifdef MODULE/#endif + *----------------------------------------------------------------------------*/ +#ifdef MODULE + +/* + The Loadable Kernel Module Installation Facility may pass us + a pointer to a driver specific options string to be parsed, + we assign this to options string. +*/ +MODULE_PARM( module_options, "s" ); + +Scsi_Host_Template driver_template = AAC_HOST_TEMPLATE_ENTRY; + +#include "scsi_module.c" + +#endif --- linux/drivers/scsi/aacraid/osddi.c.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/osddi.c Tue Jun 13 12:52:42 2000 @@ -0,0 +1,509 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * osddi.c + * + * Abstract: This file contains all the proceedures which use LINUX specific Device + * Driver Interfaces. + * + --*/ +#include "osheaders.h" + +#include + +#ifdef fsid_t +#undef fsid_t +#endif +#include "AacGenericTypes.h" +#include "aac_unix_defs.h" +#include "comstruc.h" +#include "monkerapi.h" +#include "protocol.h" +#include "fsafs.h" + +#include "sap1common.h" +#include "fsaport.h" +#include "pcisup.h" +#include "sap1.h" +#include "nodetype.h" +#include "comsup.h" +#include "afacomm.h" +#include "adapter.h" + + +void AacSaPciIsr( + int irq, + void * irq_data, + struct pt_regs *regs); + +void AacRxPciIsr( + int irq, + void * irq_data, + struct pt_regs *regs); + +unsigned SaPciIsr ( + IN PSa_ADAPTER_EXTENSION AdapterExtension ); + +unsigned RxPciIsr ( + IN PSa_ADAPTER_EXTENSION AdapterExtension ); + + +/*----------------------------------------------------------------------------*/ +VOID AfaCommInterruptHost( + PVOID AdapterArg, + ADAPTER_EVENT AdapterEvent ) +/*----------------------------------------------------------------------------*/ +{ + PAFA_COMM_ADAPTER Adapter = ( PAFA_COMM_ADAPTER ) AdapterArg; + PCOMM_REGION CommRegion = Adapter->CommRegion; + + switch (AdapterEvent) { + + case HostNormRespQue: + OsSoftInterruptTrigger( CommRegion->HostNormRespQue.ConsumerRoutine ); + + // #REVIEW# - what do we do with this + // if (FsaCommData.HardInterruptModeration) + // DisableInterrupt( Adapter, HostNormRespQue, TRUE ); + + break; + + case AdapNormCmdNotFull: + OsSoftInterruptTrigger( CommRegion->QueueNotFullDpc ); + break; + + case HostNormCmdQue: + OsSoftInterruptTrigger( CommRegion->HostNormCmdQue.ConsumerRoutine ); + break; + + case AdapNormRespNotFull: + OsSoftInterruptTrigger( CommRegion->QueueNotFullDpc ); + break; + + // #REVIEW# - what do we do with these + case HostHighCmdQue: + case HostHighRespQue: + case AdapHighCmdNotFull: + case AdapHighRespNotFull: + case SynchCommandComplete: + case AdapInternalError: + break; + } +} + + +// get the device name associated with this instance of the device +/*----------------------------------------------------------------------------*/ +char *OsGetDeviceName( + void *AdapterExtension ) +/*----------------------------------------------------------------------------*/ +{ + return( ( ( Sa_ADAPTER_EXTENSION * )AdapterExtension )->Common-> + OsDep.scsi_host_ptr->hostt->name ); +} + + +/*----------------------------------------------------------------------------*/ +int OsGetDeviceInstance( + void *AdapterExtension ) +/*----------------------------------------------------------------------------*/ +{ + return( ( int )( ( Sa_ADAPTER_EXTENSION * )AdapterExtension )->Common-> + OsDep.scsi_host_ptr->unique_id ); +} + + +/*------------------------------------------------------------------------------ + OsMapDeviceRegisters() + + Postconditions: + Return zero on success non-zero otherwise. + *----------------------------------------------------------------------------*/ +int OsMapDeviceRegisters( + Sa_ADAPTER_EXTENSION *AdapterExtension ) +/*----------------------------------------------------------------------------*/ +{ + PCI_MINIPORT_COMMON_EXTENSION *CommonExtension; + + CommonExtension = AdapterExtension->Common; + + if( AdapterExtension->Device = ( Sa_DEVICE_REGISTERS * ) + ioremap( ( unsigned long )CommonExtension->OsDep.scsi_host_ptr->base, 8192 ) ) + { + cmn_err( CE_DEBUG, "Device mapped to virtual address 0x%x", AdapterExtension->Device ); + return( 0 ); + } + else + { + cmn_err( CE_WARN, "OsMapDeviceRegisters: ioremap() failed" ); + return( 1 ); + } +} + + +/*------------------------------------------------------------------------------ + OsUnMapDeviceRegisters() + + Postconditions: + *----------------------------------------------------------------------------*/ +void OsUnMapDeviceRegisters( + Sa_ADAPTER_EXTENSION *AdapterExtension ) +/*----------------------------------------------------------------------------*/ +{ + iounmap( ( void * )AdapterExtension->Device ); +} + + +/*----------------------------------------------------------------------------*/ +int OsAttachInterrupt( + Sa_ADAPTER_EXTENSION *AdapterExtension , + int WhichIsr ) +/*----------------------------------------------------------------------------*/ +{ + PCI_MINIPORT_COMMON_EXTENSION *CommonExtension; + void *irq_data; + void (*Isr)(); + + CommonExtension = AdapterExtension->Common; + irq_data = ( void * )AdapterExtension; + + switch (WhichIsr) { + case SaISR: + Isr = AacSaPciIsr; + break; + case RxISR: + Isr = AacRxPciIsr; + break; + default: + cmn_err(CE_WARN, "OsAttachInterrupt: invalid ISR case: 0x%x", WhichIsr); + return( FAILURE ); + break; + } + + + if ( OsRegisterInterrupt ( + CommonExtension->OsDep.scsi_host_ptr->irq, // interrupt number + Isr, // handler function + irq_data ) + ) + { + cmn_err( CE_DEBUG, "OsAttachInterrupt: Failed for IRQ: 0x%x", + CommonExtension->OsDep.scsi_host_ptr->irq ); + return( FAILURE ); + } + + return ( 0 ); +} + + +/*----------------------------------------------------------------------------*/ +void AacSaPciIsr( + int irq, + void * irq_data, + struct pt_regs *regs) +/*----------------------------------------------------------------------------*/ +{ + // call the actual interrupt handler + SaPciIsr( ( Sa_ADAPTER_EXTENSION * )irq_data ); +} + +/*----------------------------------------------------------------------------*/ +void AacRxPciIsr( + int irq, + void * irq_data, + struct pt_regs *regs) +/*----------------------------------------------------------------------------*/ +{ + // call the actual interrupt handler + RxPciIsr( ( Sa_ADAPTER_EXTENSION * )irq_data ); +} + + +/*----------------------------------------------------------------------------*/ +void OsDetachInterrupt( + Sa_ADAPTER_EXTENSION *AdapterExtension ) +/*----------------------------------------------------------------------------*/ +{ + PCI_MINIPORT_COMMON_EXTENSION *CommonExtension; + void *irq_data; + + CommonExtension = AdapterExtension->Common; + irq_data = ( void * )AdapterExtension; + + OsUnregisterInterrupt ( + CommonExtension->OsDep.scsi_host_ptr->irq, // interrupt number + irq_data ); +} + + +/*----------------------------------------------------------------------------*/ +int OsAttachDMA( + Sa_ADAPTER_EXTENSION *AdapterExtension ) +/*----------------------------------------------------------------------------*/ +{ + return( 0 ); +} + +/*----------------------------------------------------------------------------*/ +int OsAttachHBA( + Sa_ADAPTER_EXTENSION *AdapterExtension ) +/*----------------------------------------------------------------------------*/ +{ + return( 0 ); +} + +/*----------------------------------------------------------------------------*/ +void OsDetachDevice( + Sa_ADAPTER_EXTENSION *AdapterExtension ) +/*----------------------------------------------------------------------------*/ +{ + OsUnMapDeviceRegisters( AdapterExtension ); + return( 0 ); +} + +/*----------------------------------------------------------------------------*/ +ULONG *OsAllocCommPhysMem( + Sa_ADAPTER_EXTENSION *AdapterExtension, + ULONG size, + ULONG **virt_addr_pptr, + ULONG *phys_addr_ptr ) +/*----------------------------------------------------------------------------*/ +{ + if( ( *virt_addr_pptr = ( ULONG * )OsAllocMemory( size, GFP_KERNEL ) ) ) + { + *phys_addr_ptr = OsVirtToPhys( ( volatile void * )*virt_addr_pptr ); + if( !*phys_addr_ptr ) + { + cmn_err( CE_WARN, "OsAllocCommPhysMem: OsVirtToPhys failed" ); + } + + return( *virt_addr_pptr ); + } + else + return( NULL ); +} + +OsAifKernelThread( + Sa_ADAPTER_EXTENSION *AdapterExtension ) +{ + + struct fs_struct *fs; + int i; + struct task_struct *tsk; + + tsk = current; + + + /* + * set up the name that will appear in 'ps' + * stored in task_struct.comm[16]. + */ + + sprintf(tsk->comm, "AIFd"); + + + // use_init_fs_context(); only exists in 2.2.13 onward. + +#ifdef __SMP__ + lock_kernel(); +#endif + + /* + * we were started as a result of loading the module. + * free all of user space pages + */ + + exit_mm(tsk); + + exit_files(tsk); + + exit_fs(tsk); + + fs = init_task.fs; + tsk->fs = fs; + + tsk->session = 1; + tsk->pgrp = 1; + + if (fs) + atomic_inc(&fs->count); + +#ifdef __SMP__ + unlock_kernel(); +#endif + + + + + NormCommandThread(AdapterExtension); + /* NOT REACHED */ +} + +/*----------------------------------------------------------------------------*/ +void OsStartKernelThreads( + Sa_ADAPTER_EXTENSION *AdapterExtension ) +/*----------------------------------------------------------------------------*/ +{ + PCI_MINIPORT_COMMON_EXTENSION *CommonExtension; + AFA_COMM_ADAPTER *Adapter; + extern void NormCommandThread(void *Adapter); + + CommonExtension = AdapterExtension->Common; + Adapter = (AFA_COMM_ADAPTER *)CommonExtension->Adapter; + + // + // Start thread which will handle interrupts for this adapter + // + //kthread_spawn(FsaCommIntrHandler, AdapterExtension, "fsaintr",0); + + // + // Start thread which will handle AdapterInititatedFibs from this adapter + // + CommonExtension->OsDep.thread_pid = + kernel_thread( ( int ( * )( void * ) )OsAifKernelThread, Adapter, 0 ); +// kernel_thread( ( int ( * )( void * ) )NormCommandThread, Adapter, 0 ); +} + +/*----------------------------------------------------------------------------*/ +BOOLEAN AfaPortAllocateAndMapFibSpace( + PVOID Arg1, + IN PMAPFIB_CONTEXT MapFibContext ) +/*----------------------------------------------------------------------------*/ +{ + PVOID BaseAddress; + ULONG PhysAddress; + + if( !( BaseAddress = (ULONG *)OsAllocMemory( MapFibContext->Size, GFP_KERNEL ) ) ) + { + cmn_err( CE_WARN, "AfaPortAllocateAndMapFibSpace: OsAllocMemory failed" ); + return( FALSE ); + } + + PhysAddress = OsVirtToPhys( BaseAddress ); + + MapFibContext->FibVirtualAddress = BaseAddress; + MapFibContext->FibPhysicalAddress = (PVOID) PhysAddress; + + return (TRUE); +} + +/*----------------------------------------------------------------------------*/ +BOOLEAN AfaPortUnmapAndFreeFibSpace( + PVOID Arg1, + IN PMAPFIB_CONTEXT MapFibContext ) +/*----------------------------------------------------------------------------*/ +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + + OsFreeMemory( MapFibContext->FibVirtualAddress, 0 ); + + return (TRUE); +} + +/*----------------------------------------------------------------------------*/ +BOOLEAN AfaPortFreeAdapterCommArea( + IN PVOID Arg1 ) +/*----------------------------------------------------------------------------*/ +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + + OsFreeMemory( CommonExtension->CommAddress, 0 ); + + return (TRUE); +} + + +/* ================================================================================ */ +/* + * Not sure if the functions below here ever get called in the current code + * These probably should be a different file. + */ +/* +ddi_dma_attr_t AfaPortDmaAttributes = { + //rpbfix : we may want something different for I/O + DMA_ATTR_V0, + 0, + 0xffffffff, + 0x0000ffff, + 1, + 1, + 1, + 0x0000ffff, + 0x0000ffff, + 17, + 512, + 0 +}; +*/ + +AAC_STATUS +AfaPortBuildSgMap( + PVOID Arg1, + IN PSGMAP_CONTEXT SgMapContext + ) + +/*++ + +Routine Description: + + This routine build a scatter gather map using the information + in the SgMapContext. + +Arguments: + + AdapterExtension - Pointer to adapter extension structure. + SgMapContext - Pointer to the SgMapContext for the request. + + +Return Value: + + AAC_STATUS +--*/ +{ + printk( "<1>AfaPortBuildSgMap: unimplemented function called" ); + return (STATUS_UNSUCCESSFUL); +} + +VOID +AfaPortFreeDmaResources( + PVOID Arg1, + IN PSGMAP_CONTEXT SgMapContext + ) + +/*++ + +Routine Description: + + Given a pointer to the IRP context will free all reserved DMA resources allocated for + the completed IO operation. + +Arguments: + + Fib - Pointer to the Fib the caller wishes to have transfered over to the adapter. + Context - Pointer to the Irp Context we use to store the dma mapping information + we need to do and complete the IO. + +Return Value: + + Nothing + +--*/ +{ +} --- linux/drivers/scsi/aacraid/osfuncs.c.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/osfuncs.c Tue Jun 13 12:52:42 2000 @@ -0,0 +1,589 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * osfuncs.c + * + * Abstract: Holds all of the O/S specific interface functions. + * + --*/ + +#include "osheaders.h" + +//static LKINFO_DECL(fsa_locks, "fsa_locks",0); + +extern aac_options_t g_options; + +OS_SOFTINTR g_idle_task = { 0, 0, 0, 0 }; +struct wait_queue * g_wait_queue_ptr = NULL; +struct wait_queue g_wait; + +void OsTimeoutHandler( + struct semaphore * sem ); + +int * OsIdleTask( void * data ); + +//----------------------------------------------------------------------------- +// Memory Allocation functions + +/*----------------------------------------------------------------------------*/ +void * OsAllocMemory( + OS_SIZE_T Size, + unsigned int Flags ) +/*----------------------------------------------------------------------------*/ +{ + void *mem_ptr; + + if( !( mem_ptr = kmalloc( Size, GFP_KERNEL ) ) ) + cmn_err( CE_WARN, "OsAllocMemory: FAILED\n" ); + return( mem_ptr ); +} + + +/*----------------------------------------------------------------------------*/ +void OsFreeMemory( + void * Buffer, + OS_SIZE_T Size ) +/*----------------------------------------------------------------------------*/ +{ + kfree( Buffer ); +} + + +/*----------------------------------------------------------------------------*/ +int OsRegisterInterrupt( + unsigned int irq, // interrupt number + void ( *handler )( int, void*, struct pt_regs * ), // handler function + void *irq_data ) // argument to handler function +/*----------------------------------------------------------------------------*/ +{ + return( request_irq ( + irq, // interrupt number + handler, // handler function + SA_INTERRUPT | SA_SHIRQ, // fast handler + "aacraid", + irq_data ) ); +} + + +/*----------------------------------------------------------------------------*/ +void OsUnregisterInterrupt( + unsigned int irq, // interrupt number + void *irq_data) +/*----------------------------------------------------------------------------*/ +{ + free_irq ( + irq, // interrupt number + irq_data ); +} + + +/*----------------------------------------------------------------------------*/ +unsigned long OsVirtToPhys( + void * virtual_address ) +/*----------------------------------------------------------------------------*/ +{ + return( virt_to_phys( virtual_address ) ); +} + + +//----------------------------------------------------------------------------- +// MUTEX functions + +/*----------------------------------------------------------------------------*/ +OS_STATUS OsMutexInit( + OS_MUTEX *Mutex, + OS_SPINLOCK_COOKIE Cookie ) +/*----------------------------------------------------------------------------*/ +{ + Mutex->wq_ptr = NULL; + Mutex->lock_var = 0; + return ( 0 ); +} + + +/*----------------------------------------------------------------------------*/ +void OsMutexDestroy( + OS_MUTEX *Mutex ) +/*----------------------------------------------------------------------------*/ +{ +} + + +/*----------------------------------------------------------------------------*/ +void OsMutexAcquire( + OS_MUTEX *Mutex ) +/*----------------------------------------------------------------------------*/ +{ + struct wait_queue wait = { current, NULL }; + unsigned long time_stamp; + + time_stamp = jiffies; + + if( test_and_set_bit( 0, &( Mutex->lock_var ) ) != 0 ) + { + if( in_interrupt() ) + panic( "OsMutexAcquire going to sleep at interrupt time\n" ); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue( &( Mutex->wq_ptr ), &wait ); + while( test_and_set_bit( 0, &( Mutex->lock_var ) ) != 0 ) + schedule(); + remove_wait_queue( &( Mutex->wq_ptr ), &wait ); + } + + if( ( jiffies - 1 ) > time_stamp ) + cmn_err( CE_WARN, "Mutex %ld locked out for %ld ticks", + Mutex, jiffies - time_stamp ); +} + + +/*----------------------------------------------------------------------------*/ +void OsMutexRelease( + OS_MUTEX *Mutex ) +/*----------------------------------------------------------------------------*/ +{ + if( test_and_clear_bit( 0, &( Mutex->lock_var ) ) == 0 ) + cmn_err( CE_WARN, "OsMutexRelease: mutex not locked" ); + wake_up_interruptible( &( Mutex->wq_ptr ) ); +} + +// see man hierarchy(D5) +#define FSA_LOCK 1 + +//----------------------------------------------------------------------------- +// Spinlock functions + +/*----------------------------------------------------------------------------*/ +OS_SPINLOCK * OsSpinLockAlloc( void ) +/*----------------------------------------------------------------------------*/ +{ + OS_SPINLOCK *SpinLock; + int i; + + SpinLock = ( OS_SPINLOCK * )kmalloc( sizeof( OS_SPINLOCK ), GFP_KERNEL ); + SpinLock->spin_lock = SPIN_LOCK_UNLOCKED; + for( i = 0; i < 8; i++ ) + SpinLock->cpu_lock_count[ i ] = 0; + return( SpinLock ); +} + + +/*----------------------------------------------------------------------------*/ +OS_STATUS OsSpinLockInit( + OS_SPINLOCK *SpinLock, + OS_SPINLOCK_COOKIE Cookie ) +/*----------------------------------------------------------------------------*/ +{ + return( 0 ); +} + + +/*----------------------------------------------------------------------------*/ +void OsSpinLockDestroy( + OS_SPINLOCK *SpinLock ) +/*----------------------------------------------------------------------------*/ +{ + kfree( SpinLock ); + SpinLock = NULL; +} + + +/*----------------------------------------------------------------------------*/ +void OsSpinLockAcquire( + OS_SPINLOCK *SpinLock ) +/*----------------------------------------------------------------------------*/ +{ + unsigned cpu_id, i; + + if( SpinLock ) + { + /* + if( OsSpinLockOwned( SpinLock ) ) + { + SpinLock->lockout_count++; + if( SpinLock->lockout_count > 200 ) + { + cmn_err( CE_WARN, "spin lock #%ld: lockout_count high", SpinLock ); + SpinLock->lockout_count = 0; + } + } + */ + cpu_id = smp_processor_id(); + if( SpinLock->cpu_lock_count[ cpu_id ] ) + panic( "CPU %d trying to acquire lock again: lock count = %d\n", + cpu_id, SpinLock->cpu_lock_count[ cpu_id ] ); + /* + for( i = 0; i < 8; i++ ) + if( SpinLock->cpu_lock_count[ i ] ) + panic( "Another CPU has the lock\n" ); + */ + spin_lock_irqsave( &( SpinLock->spin_lock ), SpinLock->cpu_flag ); + SpinLock->cpu_lock_count[ cpu_id ]++; + } + else + cmn_err( CE_WARN, "OsSpinLockAcquire: lock does not exist" ); +} + + +/*----------------------------------------------------------------------------*/ +void OsSpinLockRelease( + OS_SPINLOCK *SpinLock ) +/*----------------------------------------------------------------------------*/ +{ + if( SpinLock ) + { + SpinLock->cpu_lock_count[ smp_processor_id() ]--; + spin_unlock_irqrestore( &( SpinLock->spin_lock ), SpinLock->cpu_flag ); + } + else + cmn_err( CE_WARN, "OsSpinLockRelease: lock does not exist" ); +} + + +/*----------------------------------------------------------------------------*/ +int OsSpinLockOwned( + OS_SPINLOCK *SpinLock ) +/*----------------------------------------------------------------------------*/ +{ +#ifdef __SMP__ + if( SpinLock->spin_lock.lock != 0 ) + return( 1 ); + else +#endif + return( 0 ); +} + + +//----------------------------------------------------------------------------- +// CvLock functions + +/*----------------------------------------------------------------------------*/ +OS_CVLOCK *OsCvLockAlloc( void ) +/*----------------------------------------------------------------------------*/ +{ + OS_CVLOCK *cv_lock; + +#ifdef CVLOCK_USE_SPINLOCK + cv_lock = OsSpinLockAlloc(); +#else + cv_lock = ( OS_CVLOCK * )kmalloc( sizeof( OS_CVLOCK ), GFP_KERNEL ); + cv_lock->wq_ptr = NULL; + cv_lock->lock_var = 0; +#endif + + return( cv_lock ); +} + + +/*----------------------------------------------------------------------------*/ +OS_STATUS OsCvLockInit( + OS_CVLOCK *cv_lock, + OS_SPINLOCK_COOKIE Cookie ) +/*----------------------------------------------------------------------------*/ +{ + return ( 0 ); +} + + +/*----------------------------------------------------------------------------*/ +void OsCvLockDestroy( + OS_CVLOCK *cv_lock ) +/*----------------------------------------------------------------------------*/ +{ + if( cv_lock ) + kfree( cv_lock ); + cv_lock = NULL; +} + + +/*----------------------------------------------------------------------------*/ +void OsCvLockAcquire( + OS_CVLOCK *cv_lock ) +/*----------------------------------------------------------------------------*/ +{ +#ifdef CVLOCK_USE_SPINLOCK + OsSpinLockAcquire( cv_lock ); +#else + OsMutexAcquire( cv_lock ); +#endif +} + + +/*----------------------------------------------------------------------------*/ +void OsCvLockRelease( + OS_CVLOCK *cv_lock ) +/*----------------------------------------------------------------------------*/ +{ +#ifdef CVLOCK_USE_SPINLOCK + OsSpinLockRelease( cv_lock ); +#else + OsMutexRelease( cv_lock ); +#endif +} + + +/*----------------------------------------------------------------------------*/ +int OsCvLockOwned( + OS_CVLOCK *cv_lock ) +/*----------------------------------------------------------------------------*/ +{ + return( 1 ); +} + + +//----------------------------------------------------------------------------- +// Conditional variable functions + +/*----------------------------------------------------------------------------*/ +void OsCv_init ( + OS_CV_T *cv_ptr ) +/*----------------------------------------------------------------------------*/ +{ + cv_ptr->lock_var = 1; + cv_ptr->wq_ptr = NULL; +} + + +/*----------------------------------------------------------------------------*/ +void OsCv_destroy( + OS_CV_T *cv_ptr ) +/*----------------------------------------------------------------------------*/ +{ +} + + +/*----------------------------------------------------------------------------*/ +void OsCv_wait( + OS_CV_T *cv_ptr, + OS_CVLOCK *cv_lock_ptr ) +/*----------------------------------------------------------------------------*/ +{ + struct wait_queue wait = { current, NULL }; + unsigned long flags; + + if( in_interrupt() ) + panic( "OsCv_wait going to sleep at interrupt time\n" ); + + cv_ptr->type = TASK_UNINTERRUPTIBLE; + current->state = TASK_UNINTERRUPTIBLE; + add_wait_queue( &( cv_ptr->wq_ptr ), &wait ); + + OsCvLockRelease( cv_lock_ptr ); + schedule(); + + while( test_and_set_bit( 0, &( cv_ptr->lock_var ) ) != 0 ) + { + if( in_interrupt() ) + panic( "OsCv_wait going to sleep at interrupt time\n" ); + schedule(); + } + + remove_wait_queue( &( cv_ptr->wq_ptr ), &wait ); + + OsCvLockAcquire( cv_lock_ptr ); +} + + +/*----------------------------------------------------------------------------*/ +int OsCv_wait_sig( + OS_CV_T *cv_ptr, + OS_CVLOCK *cv_lock_ptr ) +/*----------------------------------------------------------------------------*/ +{ + struct wait_queue wait = { current, NULL }; + unsigned long flags; + int signal_state = 1; + + if( in_interrupt() ) + panic( "OsCv_wait_sig going to sleep at interrupt time\n" ); + + cv_ptr->type = TASK_INTERRUPTIBLE; + current->state = TASK_INTERRUPTIBLE; + add_wait_queue( &( cv_ptr->wq_ptr ), &wait ); + + OsCvLockRelease( cv_lock_ptr ); + schedule(); + + while( ( test_and_set_bit( 0, &( cv_ptr->lock_var ) ) != 0 ) && + ( !signal_pending( current ) ) ) + { + if( in_interrupt() ) + panic( "OsCv_wait_sig going to sleep at interrupt time\n" ); + schedule(); + } + + if( signal_pending( current ) ) + signal_state = 0; + + remove_wait_queue( &( cv_ptr->wq_ptr ), &wait ); + + OsCvLockAcquire( cv_lock_ptr ); + return( signal_state ); +} + + +/*----------------------------------------------------------------------------*/ +void OsCv_signal( + OS_CV_T *cv_ptr ) +/*----------------------------------------------------------------------------*/ +{ + clear_bit( 0, &( cv_ptr->lock_var ) ); + if( cv_ptr->type == TASK_INTERRUPTIBLE ) + wake_up_interruptible( &( cv_ptr->wq_ptr ) ); + else + wake_up( &( cv_ptr->wq_ptr ) ); +} + + +// return time in seconds +/*----------------------------------------------------------------------------*/ +unsigned long OsGetSeconds( void ) +/*----------------------------------------------------------------------------*/ +{ + return( jiffies/HZ ); +} + + +//----------------------------------------------------------------------------- +// Deferred procedure call functions + +// create a soft interrupt object +/*----------------------------------------------------------------------------*/ +int OsSoftInterruptAdd( + OS_SOFTINTR **ptr, + void * handler, + void * data ) +/*----------------------------------------------------------------------------*/ +{ + OS_SOFTINTR *tmp_ptr; + + if( !( tmp_ptr = ( OS_SOFTINTR * )kmalloc( sizeof( OS_SOFTINTR ), GFP_KERNEL ) ) ) + return( -1 ); + tmp_ptr->routine = handler; + tmp_ptr->data = data; + tmp_ptr->next = NULL; + tmp_ptr->sync = 0; + + *ptr = tmp_ptr; + + return( 0 ); +} + +/* + Use kernel_thread( ( int ( * )( void * ) )OsIdleTask, NULL, 0 ); to start +*/ +/*----------------------------------------------------------------------------*/ +int * OsIdleTask( void * data ) +/*----------------------------------------------------------------------------*/ +{ + struct wait_queue wait = { current, NULL }; + + while( 1 ) + { + //interruptible_sleep_on( &g_wait_queue_ptr ); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue( &g_wait_queue_ptr, &wait ); + schedule(); + remove_wait_queue( &g_wait_queue_ptr, &wait ); + wait.task = current; + wait.next = NULL; + } + return( NULL ); +} + + +// dispatch a soft interrupt +/*----------------------------------------------------------------------------*/ +void OsSoftInterruptTrigger( + OS_SOFTINTR *soft_intr_ptr ) +/*----------------------------------------------------------------------------*/ +{ + // wake up a kernel thread + //wake_up_interruptible( &g_wait_queue_ptr ); + + // put in scheduler task queue + //queue_task( soft_intr_ptr, &tq_scheduler ); + + // call the completion routine directly + soft_intr_ptr->routine( soft_intr_ptr->data ); +} + + +// delete a soft interrupt object +/*----------------------------------------------------------------------------*/ +void OsSoftInterruptRemove( + OS_SOFTINTR *arg ) +/*----------------------------------------------------------------------------*/ +{ + if( arg ) + kfree( arg ); + arg = NULL; +} + + +/*----------------------------------------------------------------------------*/ +void OsSleep( + unsigned time ) // in seconds +/*----------------------------------------------------------------------------*/ +{ + struct semaphore sem = MUTEX_LOCKED; + struct timer_list timer_var; + + if( in_interrupt() ) + panic( "OsSleep going to sleep at interrupt time\n" ); + + init_timer( &timer_var ); + timer_var.function = ( void ( * )( unsigned long ) )OsTimeoutHandler; + timer_var.data = ( unsigned long )&sem; + timer_var.expires = jiffies + time * HZ; + + add_timer( &timer_var ); + down( &sem ); + + del_timer( &timer_var ); +} + + +/*----------------------------------------------------------------------------*/ +void OsTimeoutHandler( + struct semaphore * sem ) +/*----------------------------------------------------------------------------*/ +{ + if( sem != NULL ) + up( sem ); +} + + +/*----------------------------------------------------------------------------*/ +void printk_err( + int flag, + char *fmt, + ...) +/*----------------------------------------------------------------------------*/ +{ + char buf[256]; + va_list ap; + + va_start(ap, fmt); + (void) vsprintf(buf, fmt, ap); + va_end(ap); + + if( flag <= g_options.message_level ) + printk("<1>%s\n", buf); +} --- linux/drivers/scsi/aacraid/ossup.c.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/ossup.c Tue Jun 13 12:52:42 2000 @@ -0,0 +1,197 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * ossup.c + * + * + * + --*/ + +#include "osheaders.h" + +#include "aac_unix_defs.h" + + +AAC_STATUS +ExInitializeZone( + IN PZONE_HEADER Zone, + IN ULONG BlockSize, + IN PVOID InitialSegment, + IN ULONG InitialSegmentSize + ) + +/*++ + +Routine Description: + + This function initializes a zone header. Once successfully + initialized, blocks can be allocated and freed from the zone, and + the zone can be extended. + +Arguments: + + Zone - Supplies the address of a zone header to be initialized. + + BlockSize - Supplies the block size of the allocatable unit within + the zone. The size must be larger that the size of the + initial segment, and must be 64-bit aligned. + + InitialSegment - Supplies the address of a segment of storage. The + first ZONE_SEGMENT_HEADER-sized portion of the segment + is used by the zone allocator. The remainder of + the segment is carved up into fixed size + (BlockSize) blocks and is made available for + allocation and deallocation from the zone. The + address of the segment must be aligned on a 64-bit + boundary. + + InitialSegmentSize - Supplies the size in bytes of the InitialSegment. + +Return Value: + + STATUS_UNSUCCESSFUL - BlockSize or InitialSegment was not aligned on + 64-bit boundaries, or BlockSize was larger than + the initial segment size. + + STATUS_SUCCESS - The zone was successfully initialized. + +--*/ + +{ + ULONG i; + PCHAR p; + + + Zone->BlockSize = BlockSize; + + Zone->SegmentList.Next = &((PZONE_SEGMENT_HEADER) InitialSegment)->SegmentList; + ((PZONE_SEGMENT_HEADER) InitialSegment)->SegmentList.Next = NULL; + ((PZONE_SEGMENT_HEADER) InitialSegment)->Reserved = NULL; + + Zone->FreeList.Next = NULL; + + p = (PCHAR)InitialSegment + sizeof(ZONE_SEGMENT_HEADER); + + for (i = sizeof(ZONE_SEGMENT_HEADER); + i <= InitialSegmentSize - BlockSize; + i += BlockSize + ) { + ((PSINGLE_LIST_ENTRY)p)->Next = Zone->FreeList.Next; + Zone->FreeList.Next = (PSINGLE_LIST_ENTRY)p; + p += BlockSize; + } + Zone->TotalSegmentSize = i; + +#if 0 + DbgPrint( "EX: ExInitializeZone( %lx, %lx, %lu, %lu, %lx )\n", + Zone, InitialSegment, InitialSegmentSize, + BlockSize, p + ); +#endif + + return STATUS_SUCCESS; +} + +AAC_STATUS +ExExtendZone( + IN PZONE_HEADER Zone, + IN PVOID Segment, + IN ULONG SegmentSize + ) + +/*++ + +Routine Description: + + This function extends a zone by adding another segment's worth of + blocks to the zone. + +Arguments: + + Zone - Supplies the address of a zone header to be extended. + + Segment - Supplies the address of a segment of storage. The first + ZONE_SEGMENT_HEADER-sized portion of the segment is used by the + zone allocator. The remainder of the segment is carved up + into fixed-size (BlockSize) blocks and is added to the + zone. The address of the segment must be aligned on a 64- + bit boundary. + + SegmentSize - Supplies the size in bytes of Segment. + +Return Value: + + STATUS_UNSUCCESSFUL - BlockSize or Segment was not aligned on + 64-bit boundaries, or BlockSize was larger than + the segment size. + + STATUS_SUCCESS - The zone was successfully extended. + +--*/ + +{ + ULONG i; + PCHAR p; + + + ((PZONE_SEGMENT_HEADER) Segment)->SegmentList.Next = Zone->SegmentList.Next; + Zone->SegmentList.Next = &((PZONE_SEGMENT_HEADER) Segment)->SegmentList; + + p = (PCHAR)Segment + sizeof(ZONE_SEGMENT_HEADER); + + for (i = sizeof(ZONE_SEGMENT_HEADER); + i <= SegmentSize - Zone->BlockSize; + i += Zone->BlockSize + ) { + + ((PSINGLE_LIST_ENTRY)p)->Next = Zone->FreeList.Next; + Zone->FreeList.Next = (PSINGLE_LIST_ENTRY)p; + p += Zone->BlockSize; + } + Zone->TotalSegmentSize += i; + +#if 0 + DbgPrint( "EX: ExExtendZone( %lx, %lx, %lu, %lu, %lx )\n", + Zone, Segment, SegmentSize, Zone->BlockSize, p + ); +#endif + + return STATUS_SUCCESS; +} + +DbgPrint() +{ +} + +/* Function: InqStrCopy() + * + * Arguments: [2] pointer to char + * + * Purpose: Copy a String from one location to another + * without copying \0 + */ +void +InqStrCopy(char *a, char *b) +{ + + while(*a != (char)0) + *b++ = *a++; +} + --- linux/drivers/scsi/aacraid/port.c.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/port.c Tue Jun 13 12:52:42 2000 @@ -0,0 +1,284 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * port.c + * + * Abstract: All support routines for FSA communication which are miniport specific. + * + --*/ + +#include "osheaders.h" + + +#include "AacGenericTypes.h" + +#include "aac_unix_defs.h" + +#include "fsatypes.h" +#include "comstruc.h" +#include "protocol.h" + +#include "fsaport.h" +#include "fsaioctl.h" + +#include "pcisup.h" +#include "port.h" + +int AfaPortPrinting = 1; + +extern AAC_STATUS AfaPort_Err_Adapter_Printf; +extern AAC_STATUS AfaPort_Warn_Adapter_Printf; +extern AAC_STATUS AfaPort_Info_Adapter_Printf; +extern AAC_STATUS AfaPort_Err_FastAfa_Load_Driver; + + + +VOID +AfaPortLogError( + IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension, + IN AAC_STATUS ErrorCode, + IN PUCHAR StringBuffer, + IN ULONG StringLength + ) +/*++ + +Routine Description: + + Does all of the work to log an error log entry +Arguments: + + CommonExtension - Pointer to the adapter that caused the error. + + ErrorCode - Which error is being logged. + + StringBuffer - Pointer to optional String for error log entry. + + StringLength - Length of StringBuffer. + +Return Value: + + Nothing + +--*/ + +{ + +} + +BOOLEAN +AfaPortGetNextAdapterNumber( + IN PDRIVER_OBJECT DriverObject, + OUT PDEVICE_OBJECT *FsaDeviceObject, + OUT PFILE_OBJECT *FileObject, + OUT PULONG AdapterNumber + ) +{ +} +BOOLEAN +AfaPortAllocateAdapterCommArea( + IN PVOID Arg1, + IN OUT PVOID *CommHeaderAddress, + IN ULONG CommAreaSize, + IN ULONG CommAreaAlignment + ) +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + PVOID BaseAddress; + PHYSICAL_ADDRESS PhysicalBaseAddress; + ULONG TotalSize, BytesToAlign; + size_t RealLength; + uint_t Count; +// ULONG SizeOfFastIoComm = sizeof(FASTIO_STRUCT); +// ULONG AdapterFibsSize = PAGE_SIZE; + ULONG AdapterFibsSize = 4096; + ULONG PrintfBufferSize = 256; + PADAPTER_INIT_STRUCT InitStruct; + extern int MiniPortRevision; + ULONG PhysAddress; + +// TotalSize = AdapterFibsSize + sizeof(ADAPTER_INIT_STRUCT) + CommAreaSize + CommAreaAlignment + +// SizeOfFastIoComm + PrintfBufferSize; + TotalSize = AdapterFibsSize + sizeof(ADAPTER_INIT_STRUCT) + CommAreaSize + CommAreaAlignment + + PrintfBufferSize; + + + OsAllocCommPhysMem(CommonExtension->MiniPort, TotalSize, &BaseAddress, &PhysAddress); + + CommonExtension->CommAddress = BaseAddress; + CommonExtension->CommPhysAddr = PhysAddress; + CommonExtension->CommSize = TotalSize; + + PhysicalBaseAddress.HighPart = 0; + PhysicalBaseAddress.LowPart = PhysAddress; + + CommonExtension->InitStruct = (PADAPTER_INIT_STRUCT)((PUCHAR)(BaseAddress) + AdapterFibsSize); + CommonExtension->PhysicalInitStruct = (PADAPTER_INIT_STRUCT)((PUCHAR)(PhysicalBaseAddress.LowPart) + AdapterFibsSize); + + InitStruct = CommonExtension->InitStruct; + + InitStruct->InitStructRevision = ADAPTER_INIT_STRUCT_REVISION; + InitStruct->MiniPortRevision = MiniPortRevision; + InitStruct->FilesystemRevision = CommonExtension->FilesystemRevision; + + // + // Adapter Fibs are the first thing allocated so that they start page aligned + // + InitStruct->AdapterFibsVirtualAddress = BaseAddress; + InitStruct->AdapterFibsPhysicalAddress = (PVOID) PhysicalBaseAddress.LowPart; + InitStruct->AdapterFibsSize = AdapterFibsSize; + InitStruct->AdapterFibAlign = sizeof(FIB); + + // + // Increment the base address by the amount already used + // + BaseAddress = (PVOID)((PUCHAR)(BaseAddress) + AdapterFibsSize + sizeof(ADAPTER_INIT_STRUCT)); + PhysicalBaseAddress.LowPart = (ULONG)((PUCHAR)(PhysicalBaseAddress.LowPart) + AdapterFibsSize + sizeof(ADAPTER_INIT_STRUCT)); + + // + // Align the beginning of Headers to CommAreaAlignment + // + BytesToAlign = (CommAreaAlignment - ((ULONG)(BaseAddress) & (CommAreaAlignment - 1))); + BaseAddress = (PVOID)((PUCHAR)(BaseAddress) + BytesToAlign); + PhysicalBaseAddress.LowPart = (ULONG)((PUCHAR)(PhysicalBaseAddress.LowPart) + BytesToAlign); + + // + // Fill in addresses of the Comm Area Headers and Queues + // + *CommHeaderAddress = BaseAddress; + InitStruct->CommHeaderAddress = (PVOID)PhysicalBaseAddress.LowPart; + + // + // Increment the base address by the size of the CommArea + // + BaseAddress = (PVOID)((PUCHAR)(BaseAddress) + CommAreaSize); + PhysicalBaseAddress.LowPart = (ULONG)((PUCHAR)(PhysicalBaseAddress.LowPart) + CommAreaSize); + + + // + // Place the Printf buffer area after the Fast I/O comm area. + // + CommonExtension->PrintfBufferAddress = (PVOID)(BaseAddress); + InitStruct->PrintfBufferAddress = (PVOID)PhysicalBaseAddress.LowPart; + InitStruct->PrintfBufferSize = PrintfBufferSize; + + AfaPortPrint("FsaAllocateAdapterCommArea: allocated a common buffer of 0x%x bytes from address 0x%x to address 0x%x\n", + TotalSize, InitStruct->AdapterFibsVirtualAddress, + (PUCHAR)(InitStruct->AdapterFibsVirtualAddress) + TotalSize); + + AfaPortPrint("Mapped on to PCI address 0x%x\n", InitStruct->AdapterFibsPhysicalAddress); + + return (TRUE); +} + +AAC_STATUS +AfaPortCreate ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) +/*++ + +Routine Description: + + The routine will get called each time a user issues a CreateFile on the DeviceObject + for the adapter. + + The main purpose of this routine is to set up any data structures that may be needed + to handle any requests made on this DeviceObject. + +Arguments: + + DeviceObject - Pointer to device object representing adapter + + Irp - Pointer to Irp that caused this open + + +Return Value: + + Status value returned from File system driver AdapterOpen + +--*/ + +{ +} + +AAC_STATUS +AfaPortClose ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) +/*++ + +Routine Description: + + This routine will get called each time a user issues a CloseHandle on the DeviceObject + for the adapter. + + The main purpose of this routine is to cleanup any data structures that have been set up + while this FileObject has been opened. + +Arguments: + + DeviceObject - Pointer to device object representing adapter + + Irp - Pointer to Irp that caused this close + +Return Value: + + Status value returned from File system driver AdapterClose + +--*/ + +{ + +} + +AAC_STATUS +AfaPortDeviceControl ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) +{ + +} + +ULONG +AfaPortGetMaxPhysicalPage( + IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension + ) +/*++ + +Routine Description: + + This routine determines the max physical page in host memory. + +Arguments: + + AdapterExtension + +Return Value: + + Max physical page in host memory. + +--*/ +{ + +} + + --- linux/drivers/scsi/aacraid/rx.c.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/rx.c Tue Jun 13 12:52:42 2000 @@ -0,0 +1,894 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * rx.c + * + * Abstract: Hardware miniport for Drawbridge specific hardware functions. + * + --*/ + +#include "osheaders.h" + + +#include "AacGenericTypes.h" + +#include "aac_unix_defs.h" + +#include "fsatypes.h" +#include "comstruc.h" +#include "fsact.h" +#include "protocol.h" + +#define DEFINE_PCI_IDS +#include "rxcommon.h" +#include "monkerapi.h" + +#include "fsaport.h" +#include "fsaioctl.h" + +#include "pcisup.h" +#include "rx.h" + +#include "port.h" + +#define BugCheckFileId (FSAFS_BUG_CHECK_CYCLONESUP) + +// #define RxBugCheck(A,B,C) { KeBugCheckEx(0x00000AFA, __LINE__, (ULONG)A, (ULONG)B,(ULONG)C ); } + +#define RxBugCheck(A, B, C) { cmn_err(CE_PANIC, "aacdisk : line %s, 0x%x, 0x%x, 0x%x ", __LINE__, A, B, C); } + +#define NUM_TICKS_PER_SECOND (1000 * 1000 * 10) /* time is in 100 nanoseconds */ + + +// +// The list of all the Rx adapter structures +// + +PRx_ADAPTER_EXTENSION RxAdapterList; + +int +RxInitDevice( + IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension, + IN ULONG AdapterNumber, + IN ULONG PciBus, + IN ULONG PciSlot +); + +BOOLEAN +RxSendSynchFib( + PVOID Arg1, + ULONG FibPhysicalAddress + ); + +FSA_USER_VAR RxUserVars[] = { + { "AfaPortPrinting", (PULONG)&AfaPortPrinting, NULL }, +}; + + +// +// Declare private use routines for this modual +// + +u_int +RxPciIsr ( + IN PRx_ADAPTER_EXTENSION AdapterExtension + ) + +/*++ + +Routine Description: + + The Isr routine for fsa Rx based adapter boards. + +Arguments: + + +Return Value: + + TRUE - if the interrupt was handled by this isr + FALSE - if the interrupt was not handled by this isr + +--*/ + +{ + ULONG DoorbellBits; + UCHAR InterruptStatus, Mask; + u_int OurInterrupt = INTR_UNCLAIMED; + + //cmn_err(CE_WARN, "RxPciIsr entered\n"); + + InterruptStatus = Rx_READ_UCHAR(AdapterExtension, MUnit.OISR); + + // + // Read mask and invert because drawbridge is reversed. + // + // This allows us to only service interrupts that have been enabled. + // + + Mask = ~(Rx_READ_UCHAR(AdapterExtension, MUnit.OIMR)); + + // Check to see if this is our interrupt. If it isn't just return FALSE. + + + if (InterruptStatus & Mask) { + + DoorbellBits = Rx_READ_ULONG(AdapterExtension, OutboundDoorbellReg); + + OurInterrupt = INTR_CLAIMED; + + if (DoorbellBits & DoorBellPrintfReady) { + + + cmn_err(CE_CONT, "%s:%s", OsGetDeviceName(AdapterExtension), AdapterExtension->Common->PrintfBufferAddress); + + Rx_WRITE_ULONG(AdapterExtension, MUnit.ODR,DoorBellPrintfReady); //clear PrintfReady + + Rx_WRITE_ULONG(AdapterExtension, InboundDoorbellReg,DoorBellPrintfDone); + + + } else if (DoorbellBits & DoorBellAdapterNormCmdReady) { // Adapter -> Host Normal Command Ready + + AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, HostNormCmdQue); + Rx_WRITE_ULONG(AdapterExtension, MUnit.ODR, DoorBellAdapterNormCmdReady); + + } else if (DoorbellBits & DoorBellAdapterNormRespReady) { // Adapter -> Host Normal Response Ready + + AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, HostNormRespQue); + Rx_WRITE_ULONG(AdapterExtension, MUnit.ODR,DoorBellAdapterNormRespReady); + + } else if (DoorbellBits & DoorBellAdapterNormCmdNotFull) { // Adapter -> Host Normal Command Not Full + + AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, AdapNormCmdNotFull); + Rx_WRITE_ULONG(AdapterExtension, MUnit.ODR, DoorBellAdapterNormCmdNotFull); + + } else if (DoorbellBits & DoorBellAdapterNormRespNotFull) { // Adapter -> Host Normal Response Not Full + + AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, AdapNormRespNotFull); + Rx_WRITE_ULONG(AdapterExtension, MUnit.ODR, DoorBellAdapterNormRespNotFull); + + } + + } + return(OurInterrupt); +} + +VOID +RxEnableInterrupt( + PVOID Arg1, + ADAPTER_EVENT AdapterEvent, + BOOLEAN AtDeviceIrq + ) +/*++ + +Routine Description: + + This routine will enable the corresponding adapter event to cause an interrupt on + the host. + +Arguments: + + AdapterExtension - Which adapter to enable. + + AdapterEvent - Which adapter event. + + AtDeviceIrq - Whether the system is in DEVICE irql + +Return Value: + + Nothing. + +--*/ +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) CommonExtension->MiniPort; + + //cmn_err(CE_WARN, "RxEnableInterrupt"); + switch (AdapterEvent) { + + case HostNormCmdQue: + + AdapterExtension->LocalMaskInterruptControl &= ~(OUTBOUNDDOORBELL_1); + + break; + + case HostNormRespQue: + + AdapterExtension->LocalMaskInterruptControl &= ~(OUTBOUNDDOORBELL_2); + + break; + + case AdapNormCmdNotFull: + + AdapterExtension->LocalMaskInterruptControl &= ~(OUTBOUNDDOORBELL_3); + + break; + + case AdapNormRespNotFull: + + AdapterExtension->LocalMaskInterruptControl &= ~(OUTBOUNDDOORBELL_4); + + break; + + } + +} + +VOID +RxDisableInterrupt( + PVOID Arg1, + ADAPTER_EVENT AdapterEvent, + BOOLEAN AtDeviceIrq + ) +/*++ + +Routine Description: + + This routine will disable the corresponding adapter event to cause an interrupt on + the host. + +Arguments: + + AdapterExtension - Which adapter to enable. + + AdapterEvent - Which adapter event. + + AtDeviceIrq - Whether the system is in DEVICE irql + +Return Value: + + Nothing. + +--*/ +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) CommonExtension->MiniPort; + + //cmn_err(CE_WARN, "RxEnableInterrupt"); + + switch (AdapterEvent) { + + + case HostNormCmdQue: + + AdapterExtension->LocalMaskInterruptControl |= (OUTBOUNDDOORBELL_1); + + break; + + case HostNormRespQue: + + AdapterExtension->LocalMaskInterruptControl |= (OUTBOUNDDOORBELL_2); + + break; + + case AdapNormCmdNotFull: + + AdapterExtension->LocalMaskInterruptControl |= (OUTBOUNDDOORBELL_3); + + break; + + + case AdapNormRespNotFull: + + AdapterExtension->LocalMaskInterruptControl |= (OUTBOUNDDOORBELL_4); + + break; + + } + +} + + + +RxDetachDevice( + IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension + ) +{ + PRx_ADAPTER_EXTENSION AdapterExtension = CommonExtension->MiniPort; + + // + // Free the register mapping. + // + + OsDetachDevice( AdapterExtension); + + OsFreeMemory( AdapterExtension, sizeof(Rx_ADAPTER_EXTENSION) ); + +} + +int +RxInitDevice( + IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension, + IN ULONG AdapterNumber, + IN ULONG PciBus, + IN ULONG PciSlot +) + +/*++ + +Routine Description: + + Scans the PCI bus looking for the Rx card. When found all resources for the + device will be allocated and the interrupt vectors and csrs will be allocated and + mapped. + + The device_interface in the commregion will be allocated and linked to the comm region. + +Arguments: + + +Return Value: + + TRUE - if the device was setup with not problems + FALSE - if the device could not be mapped and init successfully + +--*/ + +{ + AAC_STATUS Status; + PRx_ADAPTER_EXTENSION AdapterExtension = NULL; + FSA_NEW_ADAPTER NewAdapter; + ULONG StartTime, EndTime, WaitTime; + ULONG InitStatus; + int instance; + int nIntrs; + char * name; + + AfaPortPrint("In init device.\n"); + + //cmn_err(CE_WARN, "In RxInitDevice"); + +// AdapterExtension->Common->AdapterIndex = AdapterIndex; + CommonExtension->AdapterNumber = AdapterNumber; + + + CommonExtension->PciBusNumber = PciBus; + CommonExtension->PciSlotNumber = PciSlot; + + + AdapterExtension = OsAllocMemory( sizeof(Rx_ADAPTER_EXTENSION), OS_ALLOC_MEM_SLEEP ); + AdapterExtension->Common = CommonExtension; + CommonExtension->MiniPort = AdapterExtension; + + instance = OsGetDeviceInstance(AdapterExtension); + name = OsGetDeviceName(AdapterExtension); + // + // Map in the registers from the adapter, register space 0 is config space, + // register space 1 is the memery space. + // + + if (OsMapDeviceRegisters(AdapterExtension)) { + + cmn_err(CE_CONT, "%s%d: can't map device registers\n", + OsGetDeviceName(AdapterExtension), instance); + return(FAILURE); + } + + // + // Check to see if the board failed any self tests. + // + + if (Rx_READ_ULONG( AdapterExtension, IndexRegs.Mailbox[7]) & SELF_TEST_FAILED) { + + cmn_err(CE_CONT, "%s%d: adapter self-test failed\n", + OsGetDeviceName(AdapterExtension), instance); + return(FAILURE); + + } + //cmn_err(CE_WARN, "RxInitDevice: %s%d: adapter passwd self-test\n", + // OsGetDeviceName(AdapterExtension), instance); + + // + // Check to see if the board panic'd while booting. + // + + if (Rx_READ_ULONG( AdapterExtension, IndexRegs.Mailbox[7]) & KERNEL_PANIC) { + + cmn_err(CE_CONT, "%s%d: adapter kernel panic'd\n", + OsGetDeviceName(AdapterExtension), instance); + return(FAILURE); + + } + + StartTime = OsGetSeconds(); + WaitTime = 0; + + + // + // Wait for the adapter to be up and running. Wait up until 3 minutes. + // + + while (!(Rx_READ_ULONG( AdapterExtension, IndexRegs.Mailbox[7]) & KERNEL_UP_AND_RUNNING)) { + + EndTime = OsGetSeconds(); + + WaitTime = EndTime - StartTime; + + if ( WaitTime > (3 * 10) ) { + + InitStatus = Rx_READ_ULONG( AdapterExtension, IndexRegs.Mailbox[7]) >> 16; + + cmn_err(CE_CONT, "%s%d: adapter kernel failed to start, init status = %d\n", + OsGetDeviceName(AdapterExtension), instance, InitStatus); + return(FAILURE); + + } + } + + if (OsAttachInterrupt(AdapterExtension,RxISR)) { + cmn_err(CE_WARN, "%s%d RxInitDevice: failed OsAttachIntterupt", name, instance); + return(FAILURE); + } + + + if (OsAttachDMA(AdapterExtension)) { + cmn_err(CE_WARN, "%s%d SaInitDevice: failed OsAttachDMA", name, instance); + return(FAILURE); + } + + // + // Fill in the function dispatch table. + // + + AdapterExtension->Common->AdapterFuncs.SizeOfFsaPortFuncs = sizeof(FSAPORT_FUNCS); + AdapterExtension->Common->AdapterFuncs.AllocateAdapterCommArea = AfaPortAllocateAdapterCommArea; + AdapterExtension->Common->AdapterFuncs.FreeAdapterCommArea = AfaPortFreeAdapterCommArea; + AdapterExtension->Common->AdapterFuncs.BuildSgMap = AfaPortBuildSgMap; + AdapterExtension->Common->AdapterFuncs.FreeDmaResources = AfaPortFreeDmaResources; + AdapterExtension->Common->AdapterFuncs.AllocateAndMapFibSpace = AfaPortAllocateAndMapFibSpace; + AdapterExtension->Common->AdapterFuncs.UnmapAndFreeFibSpace = AfaPortUnmapAndFreeFibSpace; + AdapterExtension->Common->AdapterFuncs.InterruptAdapter = RxInterruptAdapter; + AdapterExtension->Common->AdapterFuncs.EnableInterrupt = RxEnableInterrupt; + AdapterExtension->Common->AdapterFuncs.DisableInterrupt = RxDisableInterrupt; + AdapterExtension->Common->AdapterFuncs.NotifyAdapter = RxNotifyAdapter; + AdapterExtension->Common->AdapterFuncs.ResetDevice = RxResetDevice; + AdapterExtension->Common->AdapterFuncs.InterruptHost = NULL; + + AdapterExtension->Common->AdapterFuncs.SendSynchFib = RxSendSynchFib; + + NewAdapter.AdapterExtension = CommonExtension; + NewAdapter.AdapterFuncs = &AdapterExtension->Common->AdapterFuncs; + NewAdapter.AdapterInterruptsBelowDpc = FALSE; + NewAdapter.AdapterUserVars = RxUserVars; + NewAdapter.AdapterUserVarsSize = sizeof(RxUserVars) / sizeof(FSA_USER_VAR); + + NewAdapter.Dip = CommonExtension->OsDep.dip; + + + if (AfaCommInitNewAdapter( &NewAdapter ) == NULL) { + + cmn_err(CE_WARN, "AfaCommInitNewAdapter failed\n"); + return (FAILURE); + } + + + AdapterExtension->Common->Adapter = NewAdapter.Adapter; + + if (AdapterExtension->Common->Adapter == NULL) { + + AfaPortLogError(AdapterExtension->Common, FAILURE, NULL, 0); + cmn_err(CE_WARN, "%s%d RxInitDevice: No Adapter pointer", name, instance); + + + return (FAILURE); + } + + + // + // Start any kernel threads needed + // + OsStartKernelThreads(AdapterExtension); + + // + // Tell the adapter that all is configure, and it can start accepting requests + // + + RxStartAdapter(AdapterExtension); + + +#ifdef AACDISK +#endif + + + // + // Put this adapter into the list of Rx adapters + // + + AdapterExtension->Next = RxAdapterList; + RxAdapterList = AdapterExtension; + + AdapterExtension->Common->AdapterConfigured = TRUE; + + +#ifdef AACDISK + // + // Call the disk layer to initialize itself. + // + + AfaDiskInitNewAdapter( AdapterExtension->Common->AdapterNumber, AdapterExtension->Common->Adapter ); +#endif + + +init_done: + + AdapterExtension->Common->AdapterPrintfsToScreen = FALSE; + + + + OsAttachHBA(AdapterExtension); + + return(0); +} + +VOID +RxStartAdapter( + PRx_ADAPTER_EXTENSION AdapterExtension + ) +{ + ULONG ReturnStatus; + LARGE_INTEGER HostTime; + ULONG ElapsedSeconds; + PADAPTER_INIT_STRUCT InitStruct; + + //cmn_err(CE_WARN, "RxStartAdapter"); + // + // Fill in the remaining pieces of the InitStruct. + // + + InitStruct = AdapterExtension->Common->InitStruct; + + InitStruct->HostPhysMemPages = AfaPortGetMaxPhysicalPage(AdapterExtension->Common); + + ElapsedSeconds = OsGetSeconds(); + + InitStruct->HostElapsedSeconds = ElapsedSeconds; + + // + // Tell the adapter we are back and up and running so it will scan its command + // queues and enable our interrupts + // + + AdapterExtension->LocalMaskInterruptControl = + (DoorBellPrintfReady | OUTBOUNDDOORBELL_1 | OUTBOUNDDOORBELL_2 | OUTBOUNDDOORBELL_3 | OUTBOUNDDOORBELL_4); + + // + // First clear out all interrupts. Then enable the one's that we can handle. + // + + Rx_WRITE_UCHAR( AdapterExtension, MUnit.OIMR, 0xff); + Rx_WRITE_ULONG( AdapterExtension, MUnit.ODR, 0xffffffff); +// Rx_WRITE_UCHAR(AdapterExtension, MUnit.OIMR, ~(UCHAR)OUTBOUND_DOORBELL_INTERRUPT_MASK); + Rx_WRITE_UCHAR( AdapterExtension, MUnit.OIMR, 0xfb); + + RxSendSynchCommand(AdapterExtension, + INIT_STRUCT_BASE_ADDRESS, + (ULONG) AdapterExtension->Common->PhysicalInitStruct, + 0, + 0, + 0, + &ReturnStatus); + +} + + +VOID +RxResetDevice( + PVOID Arg1 + ) + +{ +} + +VOID +RxInterruptAdapter( + PVOID Arg1 + ) +/*++ + +Routine Description: + + The will cause the adapter to take a break point. + +Arguments: + + None + +Return Value: + + Nothing + +--*/ +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) CommonExtension->MiniPort; + + ULONG ReturnStatus; + + RxSendSynchCommand(AdapterExtension, + BREAKPOINT_REQUEST, + 0, + 0, + 0, + 0, + &ReturnStatus); + +} + +VOID +RxNotifyAdapter( + PVOID Arg1, + IN HOST_2_ADAP_EVENT AdapterEvent + ) +/*++ + +Routine Description: + + Will read the adapter CSRs to find the reason the adapter has + interrupted us. + +Arguments: + + AdapterEvent - Enumerated type the returns the reason why we were interrutped. + +Return Value: + + Nothing + +--*/ +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) CommonExtension->MiniPort; + ULONG ReturnStatus; + + //cmn_err(CE_WARN, "RxNotifyAdapter %d", AdapterEvent); + + switch (AdapterEvent) { + case AdapNormCmdQue: + + Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_1); + break; + + case HostNormRespNotFull: + + Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_4); + break; + + case AdapNormRespQue: + + Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_2); + break; + + case HostNormCmdNotFull: + + Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_3); + break; + + case HostShutdown: + +// RxSendSynchCommand(AdapterExtension, HOST_CRASHING, 0, 0, 0, 0, &ReturnStatus); + + break; + + case FastIo: + Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_6); + break; + + case AdapPrintfDone: + Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_5); + break; + + default: + + RxBugCheck(0,0,0); + AfaPortPrint("Notify requested with an invalid request 0x%x.\n",AdapterEvent); + break; + } +} + +AAC_STATUS +RxSendSynchCommand( + PVOID Arg1, + ULONG Command, + ULONG Parameter1, + ULONG Parameter2, + ULONG Parameter3, + ULONG Parameter4, + PULONG ReturnStatus + ) +/*++ + +Routine Description: + + This routine will send a synchronous comamnd to the adapter and wait for its + completion. + +Arguments: + + AdapterExtension - Pointer to adapter extension structure. + Command - Which command to send + Parameter1 - 4 - Parameters for command + ReturnStatus - return status from adapter after completion of command + + +Return Value: + + AAC_STATUS + +--*/ +{ + PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) Arg1; + ULONG StartTime,EndTime,WaitTime; + BOOLEAN CommandSucceeded; + + //cmn_err(CE_WARN, "RxSendSyncCommand"); + // + // Write the Command into Mailbox 0 + // + + Rx_WRITE_ULONG( AdapterExtension, InboundMailbox0, Command); + + // + // Write the parameters into Mailboxes 1 - 4 + // + + Rx_WRITE_ULONG( AdapterExtension, InboundMailbox1, Parameter1); + Rx_WRITE_ULONG( AdapterExtension, InboundMailbox2, Parameter2); + Rx_WRITE_ULONG( AdapterExtension, InboundMailbox3, Parameter3); + Rx_WRITE_ULONG( AdapterExtension, InboundMailbox4, Parameter4); + + // + // Clear the synch command doorbell to start on a clean slate. + // + + Rx_WRITE_ULONG( AdapterExtension, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); + + // + // disable doorbell interrupts + // + + Rx_WRITE_UCHAR( AdapterExtension, MUnit.OIMR, + Rx_READ_UCHAR(AdapterExtension, MUnit.OIMR) | 0x04); + + // + // force the completion of the mask register write before issuing the interrupt. + // + + Rx_READ_UCHAR ( AdapterExtension, MUnit.OIMR); + + // + // Signal that there is a new synch command + // + + Rx_WRITE_ULONG( AdapterExtension, InboundDoorbellReg, INBOUNDDOORBELL_0); + + CommandSucceeded = FALSE; + + StartTime = OsGetSeconds(); + WaitTime = 0; + + while (WaitTime < 30) { // wait up to 30 seconds + + drv_usecwait(5); // delay 5 microseconds to let Mon960 get info. + + // + // Mon110 will set doorbell0 bit when it has completed the command. + // + + if (Rx_READ_ULONG(AdapterExtension, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) { + + // + // clear the doorbell. + // + + Rx_WRITE_ULONG(AdapterExtension, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); + + CommandSucceeded = TRUE; + break; + } + + EndTime = OsGetSeconds(); + WaitTime = EndTime - StartTime; + + } + + if (CommandSucceeded != TRUE) { + + // + // restore interrupt mask even though we timed out + // + + Rx_WRITE_UCHAR(AdapterExtension, MUnit.OIMR, + Rx_READ_ULONG(AdapterExtension, MUnit.OIMR) & 0xfb); + + return (STATUS_IO_TIMEOUT); + + } + + // + // Pull the synch status from Mailbox 0. + // + + *ReturnStatus = Rx_READ_ULONG(AdapterExtension, IndexRegs.Mailbox[0]); + + // + // Clear the synch command doorbell. + // + + Rx_WRITE_ULONG(AdapterExtension, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); + + // + // restore interrupt mask + // + + Rx_WRITE_UCHAR(AdapterExtension, MUnit.OIMR, + Rx_READ_ULONG(AdapterExtension, MUnit.OIMR) & 0xfb); + + // + // Return SUCCESS + // + + return (STATUS_SUCCESS); + +} + +BOOLEAN +RxSendSynchFib( + PVOID Arg1, + ULONG FibPhysicalAddress + ) +/*++ + +Routine Description: + + This routine will send a synchronous fib to the adapter and wait for its + completion. + +Arguments: + + AdapterExtension - Pointer to adapter extension structure. + FibPhysicalAddress - Physical address of fib to send. + + +Return Value: + + BOOLEAN + +--*/ +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) CommonExtension->MiniPort; + ULONG returnStatus; + + if (RxSendSynchCommand( AdapterExtension, + SEND_SYNCHRONOUS_FIB, + FibPhysicalAddress, + 0, + 0, + 0, + &returnStatus ) != STATUS_SUCCESS ) { + + return (FALSE); + + } + + return (TRUE); + +} + + --- linux/drivers/scsi/aacraid/sap1sup.c.aacraid Tue Jun 13 12:52:42 2000 +++ linux/drivers/scsi/aacraid/sap1sup.c Tue Jun 13 12:52:42 2000 @@ -0,0 +1,862 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * sap1sup.c + * + * Abstract: Drawbridge specific support functions + * + --*/ + +#include "osheaders.h" + + +#include "AacGenericTypes.h" + +#include "aac_unix_defs.h" + +#include "fsatypes.h" +#include "comstruc.h" +#include "fsact.h" +#include "protocol.h" + +#define DEFINE_PCI_IDS +#include "sap1common.h" +#include "monkerapi.h" + +#include "fsaport.h" +#include "fsaioctl.h" + + +#include "pcisup.h" +#include "sap1.h" + +#include "port.h" + +#include "nodetype.h" +#include "comsup.h" +#include "afacomm.h" +#include "adapter.h" + +#define BugCheckFileId (FSAFS_BUG_CHECK_CYCLONESUP) + +// #define SaBugCheck(A,B,C) { KeBugCheckEx(0x00000AFA, __LINE__, (ULONG)A, (ULONG)B,(ULONG)C ); } + +#define SaBugCheck(A, B, C) { cmn_err(CE_PANIC, "aacdisk : line %s, 0x%x, 0x%x, 0x%x ", __LINE__, A, B, C); } + +#define NUM_TICKS_PER_SECOND (1000 * 1000 * 10) /* time is in 100 nanoseconds */ + +int MiniPortRevision = Sa_MINIPORT_REVISION; + + +// +// The list of all the Sa adapter structures +// + +PSa_ADAPTER_EXTENSION SaAdapterList; + +int +SaInitDevice( + IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension, + IN ULONG AdapterNumber, + IN ULONG PciBus, + IN ULONG PciSlot +); + +BOOLEAN +SaSendSynchFib( + PVOID Arg1, + ULONG FibPhysicalAddress + ); + +FSA_USER_VAR SaUserVars[] = { + { "AfaPortPrinting", (PULONG)&AfaPortPrinting, NULL }, +}; + + +// +// Declare private use routines for this modual +// + +u_int +SaPciIsr ( + IN PSa_ADAPTER_EXTENSION AdapterExtension + ) + +/*++ + +Routine Description: + + The Isr routine for fsa Sa based adapter boards. + +Arguments: + + +Return Value: + + TRUE - if the interrupt was handled by this isr + FALSE - if the interrupt was not handled by this isr + +--*/ + +{ + USHORT InterruptStatus, Mask; + u_int OurInterrupt = INTR_UNCLAIMED; + +// cmn_err(CE_WARN, "SaPciIsr entered\n"); + + InterruptStatus = Sa_READ_USHORT( AdapterExtension, DoorbellReg_p); + + // + // Read mask and invert because drawbridge is reversed. + // + // This allows us to only service interrupts that have been enabled. + // + + Mask = ~(Sa_READ_USHORT( AdapterExtension, SaDbCSR.PRISETIRQMASK)); + + // Check to see if this is our interrupt. If it isn't just return FALSE. + + + if (InterruptStatus & Mask) { + + OurInterrupt = INTR_CLAIMED; + + if (InterruptStatus & PrintfReady) { + + + cmn_err(CE_WARN, "%s:%s", OsGetDeviceName(AdapterExtension), AdapterExtension->Common->PrintfBufferAddress); + + Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p,PrintfReady); //clear PrintfReady + + Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,PrintfDone); + + } else if (InterruptStatus & DOORBELL_1) { // Adapter -> Host Normal Command Ready + + AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, HostNormCmdQue); + Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p, DOORBELL_1); + + } else if (InterruptStatus & DOORBELL_2) { // Adapter -> Host Normal Response Ready + + AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, HostNormRespQue); + Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p,DOORBELL_2); + + } else if (InterruptStatus & DOORBELL_3) { // Adapter -> Host Normal Command Not Full + + AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, AdapNormCmdNotFull); + Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p, DOORBELL_3); + + } else if (InterruptStatus & DOORBELL_4) { // Adapter -> Host Normal Response Not Full + + AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, AdapNormRespNotFull); + Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p, DOORBELL_4); + + } + + } + return(OurInterrupt); +} + +VOID +SaEnableInterrupt( + PVOID Arg1, + ADAPTER_EVENT AdapterEvent, + BOOLEAN AtDeviceIrq + ) +/*++ + +Routine Description: + + This routine will enable the corresponding adapter event to cause an interrupt on + the host. + +Arguments: + + AdapterExtension - Which adapter to enable. + + AdapterEvent - Which adapter event. + + AtDeviceIrq - Whether the system is in DEVICE irql + +Return Value: + + Nothing. + +--*/ +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) CommonExtension->MiniPort; + + switch (AdapterEvent) { + + case HostNormCmdQue: + + Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRICLEARIRQMASK, DOORBELL_1 ); + + break; + + case HostNormRespQue: + + Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRICLEARIRQMASK, DOORBELL_2 ); + + break; + + case AdapNormCmdNotFull: + + Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRICLEARIRQMASK, DOORBELL_3 ); + + break; + + case AdapNormRespNotFull: + + Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRICLEARIRQMASK, DOORBELL_4 ); + + break; + + } + +} + +VOID +SaDisableInterrupt( + PVOID Arg1, + ADAPTER_EVENT AdapterEvent, + BOOLEAN AtDeviceIrq + ) +/*++ + +Routine Description: + + This routine will disable the corresponding adapter event to cause an interrupt on + the host. + +Arguments: + + AdapterExtension - Which adapter to enable. + + AdapterEvent - Which adapter event. + + AtDeviceIrq - Whether the system is in DEVICE irql + +Return Value: + + Nothing. + +--*/ +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) CommonExtension->MiniPort; + + switch (AdapterEvent) { + + + case HostNormCmdQue: + + Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRISETIRQMASK, DOORBELL_1 ); + + break; + + case HostNormRespQue: + + Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRISETIRQMASK, DOORBELL_2 ); + + break; + + case AdapNormCmdNotFull: + + Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRISETIRQMASK, DOORBELL_3 ); + + break; + + + case AdapNormRespNotFull: + + Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRISETIRQMASK, DOORBELL_4 ); + + break; + + } + +} + +SaDetachDevice( + IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension + ) +{ + PSa_ADAPTER_EXTENSION AdapterExtension = CommonExtension->MiniPort; + + // + // Free the register mapping. + // + + OsDetachDevice(AdapterExtension); + + OsFreeMemory( AdapterExtension, sizeof(Sa_ADAPTER_EXTENSION) ); + +} + +int +SaInitDevice( + IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension, + IN ULONG AdapterNumber, + IN ULONG PciBus, + IN ULONG PciSlot +) + +/*++ + +Routine Description: + + Scans the PCI bus looking for the Sa card. When found all resources for the + device will be allocated and the interrupt vectors and csrs will be allocated and + mapped. + + The device_interface in the commregion will be allocated and linked to the comm region. + +Arguments: + + +Return Value: + + TRUE - if the device was setup with not problems + FALSE - if the device could not be mapped and init successfully + +--*/ + +{ + AAC_STATUS Status; + PSa_ADAPTER_EXTENSION AdapterExtension = NULL; + FSA_NEW_ADAPTER NewAdapter; + ULONG StartTime, EndTime, WaitTime; + ULONG InitStatus; + int instance; + char *name; + + AfaPortPrint("In init device.\n"); + +// cmn_err(CE_NOTE, "SaInitDevice "); + +// AdapterExtension->Common->AdapterIndex = AdapterIndex; + CommonExtension->AdapterNumber = AdapterNumber; + + + CommonExtension->PciBusNumber = PciBus; + CommonExtension->PciSlotNumber = PciSlot; + + + AdapterExtension = OsAllocMemory( sizeof(Sa_ADAPTER_EXTENSION), OS_ALLOC_MEM_SLEEP ); + AdapterExtension->Common = CommonExtension; + CommonExtension->MiniPort = AdapterExtension; + + instance = OsGetDeviceInstance(AdapterExtension); + name = OsGetDeviceName(AdapterExtension); + + // + // Map in the registers from the adapter, register space 0 is config space, + // register space 1 is the memery space. + // + + if (OsMapDeviceRegisters(AdapterExtension)){ + cmn_err(CE_WARN, "%s%d SaInitDevice: failed OsMapDeviceRegisters", name, instance); + return(FAILURE); + } + + + // + // Check to see if the board failed any self tests. + // + + if (Sa_READ_ULONG( AdapterExtension, Mailbox7) & SELF_TEST_FAILED) { + + cmn_err(CE_WARN, "%s%d: adapter self-test failed\n", + name, instance); + return(FAILURE); + } + + // + // Check to see if the board panic'd while booting. + // + + if (Sa_READ_ULONG( AdapterExtension, Mailbox7) & KERNEL_PANIC) { + + cmn_err(CE_WARN, "%s%d: adapter kernel panic'd\n", + name, instance); + return(FAILURE); + } + + + StartTime = OsGetSeconds(); + WaitTime = 0; + + + // + // Wait for the adapter to be up and running. Wait up until 3 minutes. + // + + while (!(Sa_READ_ULONG( AdapterExtension, Mailbox7) & KERNEL_UP_AND_RUNNING)) { + + EndTime = OsGetSeconds(); + + WaitTime = EndTime - StartTime; + + if ( WaitTime > (3 * 60) ) { + + InitStatus = Sa_READ_ULONG( AdapterExtension, Mailbox7) >> 16; + + cmn_err(CE_WARN, "%s%d: adapter kernel failed to start, init status = %d\n", + name, instance, InitStatus); + return(FAILURE); + + } + } + + if (OsAttachInterrupt(AdapterExtension, SaISR)) { + cmn_err(CE_WARN, "%s%d SaInitDevice: failed OsAttachIntterupt", name, instance); + return(FAILURE); + } + + if (OsAttachDMA(AdapterExtension)) { + cmn_err(CE_WARN, "%s%d SaInitDevice: failed OsAttachDMA", name, instance); + return(FAILURE); + } + + + // + // Fill in the function dispatch table. + // + + AdapterExtension->Common->AdapterFuncs.SizeOfFsaPortFuncs = sizeof(FSAPORT_FUNCS); + AdapterExtension->Common->AdapterFuncs.AllocateAdapterCommArea = AfaPortAllocateAdapterCommArea; + AdapterExtension->Common->AdapterFuncs.FreeAdapterCommArea = AfaPortFreeAdapterCommArea; + AdapterExtension->Common->AdapterFuncs.BuildSgMap = AfaPortBuildSgMap; + AdapterExtension->Common->AdapterFuncs.FreeDmaResources = AfaPortFreeDmaResources; + AdapterExtension->Common->AdapterFuncs.AllocateAndMapFibSpace = AfaPortAllocateAndMapFibSpace; + AdapterExtension->Common->AdapterFuncs.UnmapAndFreeFibSpace = AfaPortUnmapAndFreeFibSpace; + AdapterExtension->Common->AdapterFuncs.InterruptAdapter = SaInterruptAdapter; + AdapterExtension->Common->AdapterFuncs.EnableInterrupt = SaEnableInterrupt; + AdapterExtension->Common->AdapterFuncs.DisableInterrupt = SaDisableInterrupt; + AdapterExtension->Common->AdapterFuncs.NotifyAdapter = SaNotifyAdapter; + AdapterExtension->Common->AdapterFuncs.ResetDevice = SaResetDevice; + AdapterExtension->Common->AdapterFuncs.InterruptHost = NULL; + + AdapterExtension->Common->AdapterFuncs.SendSynchFib = SaSendSynchFib; + + NewAdapter.AdapterExtension = CommonExtension; + NewAdapter.AdapterFuncs = &AdapterExtension->Common->AdapterFuncs; + NewAdapter.AdapterInterruptsBelowDpc = FALSE; + NewAdapter.AdapterUserVars = SaUserVars; + NewAdapter.AdapterUserVarsSize = sizeof(SaUserVars) / sizeof(FSA_USER_VAR); + + NewAdapter.Dip = CommonExtension->OsDep.dip; + + + if ( AfaCommInitNewAdapter( &NewAdapter ) == NULL) { + cmn_err(CE_WARN, "SaInitDevice: AfaCommInitNewAdapter failed\n"); + return (FAILURE); + }; + + + AdapterExtension->Common->Adapter = NewAdapter.Adapter; + + if (AdapterExtension->Common->Adapter == NULL) { + + AfaPortLogError(AdapterExtension->Common, FAILURE, NULL, 0); + cmn_err(CE_WARN, "%s%d SaInitDevice: No Adapter pointer", name, instance); + + return (FAILURE); + } + + + // + // Start any kernel threads needed + OsStartKernelThreads(AdapterExtension); + // + // Tell the adapter that all is configure, and it can start accepting requests + // + + SaStartAdapter(AdapterExtension); + + + + // + // Put this adapter into the list of Sa adapters + // + + AdapterExtension->Next = SaAdapterList; + SaAdapterList = AdapterExtension; + + AdapterExtension->Common->AdapterConfigured = TRUE; + + +#ifdef AACDISK + // + // Call the disk layer to initialize itself. + // + + AfaDiskInitNewAdapter( AdapterExtension->Common->AdapterNumber, AdapterExtension->Common->Adapter ); +#endif + + +init_done: + + AdapterExtension->Common->AdapterPrintfsToScreen = FALSE; + + OsAttachHBA(AdapterExtension); + + return (0); + +init_error: + + return (FAILURE); +} + +VOID +SaStartAdapter( + PSa_ADAPTER_EXTENSION AdapterExtension + ) +{ + ULONG ReturnStatus; + LARGE_INTEGER HostTime; + ULONG ElapsedSeconds; + PADAPTER_INIT_STRUCT InitStruct; + + // + // Fill in the remaining pieces of the InitStruct. + // + + InitStruct = AdapterExtension->Common->InitStruct; + + InitStruct->HostPhysMemPages = AfaPortGetMaxPhysicalPage(AdapterExtension->Common); + + ElapsedSeconds = OsGetSeconds(); + + InitStruct->HostElapsedSeconds = ElapsedSeconds; + + // + // Tell the adapter we are back and up and running so it will scan its command + // queues and enable our interrupts + // + + AdapterExtension->LocalMaskInterruptControl = + (PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4); + + + // + // First clear out all interrupts. Then enable the one's that we can handle. + // + + Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRISETIRQMASK, (USHORT) 0xffff ); + Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRICLEARIRQMASK, + (PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4) ); + + SaSendSynchCommand(AdapterExtension, + INIT_STRUCT_BASE_ADDRESS, + (ULONG) AdapterExtension->Common->PhysicalInitStruct, + 0, + 0, + 0, + &ReturnStatus); + +} + + +VOID +SaResetDevice( + PVOID Arg1 + ) + +{ +} + +VOID +SaInterruptAdapter( + PVOID Arg1 + ) +/*++ + +Routine Description: + + The will cause the adapter to take a break point. + +Arguments: + + None + +Return Value: + + Nothing + +--*/ +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) CommonExtension->MiniPort; + + ULONG ReturnStatus; + + SaSendSynchCommand(AdapterExtension, + BREAKPOINT_REQUEST, + 0, + 0, + 0, + 0, + &ReturnStatus); + +} + +VOID +SaNotifyAdapter( + PVOID Arg1, + IN HOST_2_ADAP_EVENT AdapterEvent + ) +/*++ + +Routine Description: + + Will read the adapter CSRs to find the reason the adapter has + interrupted us. + +Arguments: + + AdapterEvent - Enumerated type the returns the reason why we were interrutped. + +Return Value: + + Nothing + +--*/ +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) CommonExtension->MiniPort; + ULONG ReturnStatus; + + switch (AdapterEvent) { + case AdapNormCmdQue: + + Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_1); + break; + + case HostNormRespNotFull: + + Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_4); + break; + + case AdapNormRespQue: + + Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_2); + break; + + case HostNormCmdNotFull: + + Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_3); + break; + + case HostShutdown: + +// SaSendSynchCommand(AdapterExtension, HOST_CRASHING, 0, 0, 0, 0, &ReturnStatus); + + break; + + case FastIo: + Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_6); + break; + + case AdapPrintfDone: + Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_5); + break; + + default: + + SaBugCheck(0,0,0); + AfaPortPrint("Notify requested with an invalid request 0x%x.\n",AdapterEvent); + break; + } +} + +AAC_STATUS +SaSendSynchCommand( + PVOID Arg1, + ULONG Command, + ULONG Parameter1, + ULONG Parameter2, + ULONG Parameter3, + ULONG Parameter4, + PULONG ReturnStatus + ) +/*++ + +Routine Description: + + This routine will send a synchronous comamnd to the adapter and wait for its + completion. + +Arguments: + + AdapterExtension - Pointer to adapter extension structure. + Command - Which command to send + Parameter1 - 4 - Parameters for command + ReturnStatus - return status from adapter after completion of command + + +Return Value: + + AAC_STATUS + +--*/ +{ + PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) Arg1; + ULONG StartTime,EndTime,WaitTime; + BOOLEAN CommandSucceeded; + + // + // Write the Command into Mailbox 0 + // + + Sa_WRITE_ULONG( AdapterExtension, Mailbox0, Command); + + // + // Write the parameters into Mailboxes 1 - 4 + // + + Sa_WRITE_ULONG( AdapterExtension, Mailbox1, Parameter1); + Sa_WRITE_ULONG( AdapterExtension, Mailbox2, Parameter2); + Sa_WRITE_ULONG( AdapterExtension, Mailbox3, Parameter3); + Sa_WRITE_ULONG( AdapterExtension, Mailbox4, Parameter4); + + // + // Clear the synch command doorbell to start on a clean slate. + // + + Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p, DOORBELL_0); + + // + // Signal that there is a new synch command + // + + Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s, DOORBELL_0); + + CommandSucceeded = FALSE; + + StartTime = OsGetSeconds(); + WaitTime = 0; + + while (WaitTime < 30) { // wait up to 30 seconds + + drv_usecwait(5); // delay 5 microseconds to let Mon960 get info. + + // + // Mon110 will set doorbell0 bit when it has completed the command. + // + + if( Sa_READ_USHORT( AdapterExtension, DoorbellReg_p) & DOORBELL_0 ) { + + CommandSucceeded = TRUE; + break; + } + + EndTime = OsGetSeconds(); + WaitTime = EndTime - StartTime; + + } + + if (CommandSucceeded != TRUE) { + + return (STATUS_IO_TIMEOUT); + + } + + // + // Clear the synch command doorbell. + // + + Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p, DOORBELL_0); + + // + // Pull the synch status from Mailbox 0. + // + + *ReturnStatus = Sa_READ_ULONG( AdapterExtension, Mailbox0); + + // + // Return SUCCESS + // + + return (STATUS_SUCCESS); + +} + +BOOLEAN +SaSendSynchFib( + PVOID Arg1, + ULONG FibPhysicalAddress + ) +/*++ + +Routine Description: + + This routine will send a synchronous fib to the adapter and wait for its + completion. + +Arguments: + + AdapterExtension - Pointer to adapter extension structure. + FibPhysicalAddress - Physical address of fib to send. + + +Return Value: + + BOOLEAN + +--*/ +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) CommonExtension->MiniPort; + ULONG returnStatus; + + if (SaSendSynchCommand( AdapterExtension, + SEND_SYNCHRONOUS_FIB, + FibPhysicalAddress, + 0, + 0, + 0, + &returnStatus ) != STATUS_SUCCESS ) { + + return (FALSE); + + } + + return (TRUE); + +} + +BOOLEAN +WriteFlash( + PVOID AdapterExtension, + ULONG *MappedBuffer) +{ + return (FALSE); +} + +BOOLEAN +ReadFlash( + PVOID AdapterExtension, + ULONG *MappedBuffer) +{ + return (FALSE); +} + --- linux/drivers/scsi/hosts.c.aacraid Tue Jun 13 12:52:08 2000 +++ linux/drivers/scsi/hosts.c Tue Jun 13 12:52:42 2000 @@ -131,6 +131,10 @@ #include "aha1740.h" #endif +#ifdef CONFIG_SCSI_AACRAID +#include "aacraid/include/linit.h" +#endif + #ifdef CONFIG_SCSI_AIC7XXX #include "aic7xxx.h" #endif @@ -483,6 +487,9 @@ #endif #ifdef CONFIG_SCSI_AHA1740 AHA1740, +#endif +#ifdef CONFIG_SCSI_AACRAID + AAC_HOST_TEMPLATE_ENTRY, #endif #ifdef CONFIG_SCSI_AIC7XXX AIC7XXX, --- linux/drivers/scsi/scsi.c.aacraid Tue Jun 13 12:52:09 2000 +++ linux/drivers/scsi/scsi.c Tue Jun 13 12:52:42 2000 @@ -307,6 +307,8 @@ {"MATSHITA","PD-1","*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"iomega","jaz 1GB","J.86", BLIST_NOTQ | BLIST_NOLUN}, {"TOSHIBA","CDROM","*", BLIST_ISROM}, +{"DELL", "PERCRAID", "*", BLIST_FORCELUN}, +{"HP", "NetRAID-4M", "*", BLIST_FORCELUN}, {"MegaRAID", "LD", "*", BLIST_FORCELUN}, /* Multiple luns always safe (logical raid vols) */ {"DGC", "RAID", "*", BLIST_SPARSELUN}, /* Dell PV 650F (tgt @ LUN 0) */ {"DGC", "DISK", "*", BLIST_SPARSELUN}, /* Dell PV 650F (no tgt @ LUN 0) */ --- linux/arch/i386/defconfig.aacraid Tue Jun 13 12:52:09 2000 +++ linux/arch/i386/defconfig Tue Jun 13 12:52:42 2000 @@ -174,6 +174,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_IPS is not set # CONFIG_SCSI_ADVANSYS is not set --- linux/MAINTAINERS.aacraid Wed Jun 7 17:26:42 2000 +++ linux/MAINTAINERS Tue Jun 13 12:52:42 2000 @@ -93,6 +93,12 @@ L: linux-net@vger.rutgers.edu S: Maintained +AACRAID ADAPTEC RAID DRIVER +P: Brian M. Boerner +M: aacraid@ntc.adaptec.com +L: To Be Announced +S: Maintained + AD1816 SOUND DRIVER P: Thorsten Knabe M: Thorsten Knabe