diff -burN linux-2.2.19/MAINTAINERS linux.aacraid/MAINTAINERS --- linux-2.2.19/MAINTAINERS Sun Mar 25 10:37:29 2001 +++ linux.aacraid/MAINTAINERS Fri Jun 29 14:08:45 2001 @@ -100,10 +100,13 @@ S: Maintained AACRAID ADAPTEC RAID DRIVER -P: Brian M. Boerner -M: aacraid@ntc.adaptec.com -L: To Be Announced -S: Maintained +P: Adaptec OEM RAID Solutions +M: linux-aacraid-devel@dell.com +L: linux-aacraid-devel@dell.com +L: linux-aacraid-announce@dell.com +W: http://domsch.com/linux +W: http://lists.us.dell.com/ +S: Supported AD1816 SOUND DRIVER P: Thorsten Knabe diff -burN linux-2.2.19/drivers/scsi/Config.in linux.aacraid/drivers/scsi/Config.in --- linux-2.2.19/drivers/scsi/Config.in Sun Mar 25 10:37:35 2001 +++ linux.aacraid/drivers/scsi/Config.in Fri Jun 29 13:33:59 2001 @@ -27,6 +27,7 @@ dep_tristate 'Adaptec AHA152X/2825 support' CONFIG_SCSI_AHA152X $CONFIG_SCSI dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI +dep_tristate 'Adaptec RAID Controller support' CONFIG_SCSI_AACRAID $CONFIG_SCSI dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then bool ' Enable Tagged Command Queueing (TCQ) by default' CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT diff -burN linux-2.2.19/drivers/scsi/Makefile linux.aacraid/drivers/scsi/Makefile --- linux-2.2.19/drivers/scsi/Makefile Sun Mar 25 10:37:35 2001 +++ linux.aacraid/drivers/scsi/Makefile Fri Jun 29 13:33:59 2001 @@ -367,6 +367,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 @@ -749,3 +757,5 @@ sd_mod.o: sd.o sd_ioctl.o $(LD) $(LD_RFLAG) -r -o $@ sd.o sd_ioctl.o +aacraid.o: + cd aacraid; make diff -burN linux-2.2.19/drivers/scsi/aacraid/ChangeLog linux.aacraid/drivers/scsi/aacraid/ChangeLog --- linux-2.2.19/drivers/scsi/aacraid/ChangeLog Wed Dec 31 18:00:00 1969 +++ linux.aacraid/drivers/scsi/aacraid/ChangeLog Fri Jul 20 09:53:32 2001 @@ -0,0 +1,12 @@ +2001-07-20 Matt Domsch +* Started with linux-2.2.18-aacraid-1.0.6.patch +* Applied linux-2.2.x-1.0.7-aacraid.patch +* Applied PERCID_add.patch +* Applied SMP fixup patch from Chris Pascoe (patch vs. 2.4.x backported) +* Fixed up MAINTAINERS and README +* Created ChangeLog +* Produced patch against 2.2.19. diff -burN linux-2.2.19/drivers/scsi/aacraid/Makefile linux.aacraid/drivers/scsi/aacraid/Makefile --- linux-2.2.19/drivers/scsi/aacraid/Makefile Wed Dec 31 18:00:00 1969 +++ linux.aacraid/drivers/scsi/aacraid/Makefile Fri Jun 29 13:33:59 2001 @@ -0,0 +1,171 @@ +# +# Makefile aacraid Raid Controller +# + +############################################################################### +### SOURCE FILES DEFINES +############################################################################### + +CFILES_DRIVER=\ + ./aachba.c \ + ./aacid.c \ + ./commctrl.c \ + ./comminit.c \ + ./commsup.c \ + ./dpcsup.c \ + ./linit.c \ + ./osddi.c \ + ./osfuncs.c \ + ./ossup.c \ + ./port.c \ + ./rx.c \ + ./sap1sup.c + +IFILES_DRIVER=\ + ./include/AacGenericTypes.h \ + ./include/aac_unix_defs.h \ + ./include/adapter.h \ + ./include/afacomm.h \ + ./include/aifstruc.h \ + ./include/build_number.h \ + ./include/commdata.h \ + ./include/commerr.h \ + ./include/commfibcontext.h \ + ./include/comprocs.h \ + ./include/comproto.h \ + ./include/comstruc.h \ + ./include/comsup.h \ + ./include/fsact.h \ + ./include/fsafs.h \ + ./include/fsaioctl.h \ + ./include/fsaport.h \ + ./include/fsatypes.h \ + ./include/linit.h \ + ./include/monkerapi.h \ + ./include/nodetype.h \ + ./include/nvramioctl.h \ + ./include/osheaders.h \ + ./include/ostypes.h \ + ./include/pcisup.h \ + ./include/perfpack.h \ + ./include/port.h \ + ./include/protocol.h \ + ./include/revision.h \ + ./include/rxcommon.h \ + ./include/rx.h \ + ./include/sap1common.h \ + ./include/sap1.h \ + ./include/version.h + +ALL_SOURCE=\ + ${CFILES_DRIVER} \ + ${IFILES_DRIVER} + +############################################################################### +### OBJECT FILES DEFINES +############################################################################### + + +OFILES_DRIVER=\ + linit.o \ + osfuncs.o \ + osddi.o \ + aachba.o \ + commctrl.o \ + comminit.o \ + commsup.o \ + dpcsup.o \ + ossup.o \ + port.o \ + rx.o \ + sap1sup.o + +TARGET_OFILES= ${OFILES_DRIVER} aacid.o + +############################################################################### +### GENERAL DEFINES +############################################################################### + +# Remember that we're doing a chdir one level lower, so we need an extra ../ +INCS= \ + -I./include \ + -I../../../include -I.. \ + -I/usr/src/linux/include -I/usr/src/linux/drivers/scsi + +WARNINGS= -w -Wall -Wno-unused -Wno-switch -Wno-missing-prototypes -Wno-implicit + +COMMON_FLAGS=\ + -D__KERNEL__=1 -DUNIX -DCVLOCK_USE_SPINLOCK -DLINUX \ + -Wall -Wstrict-prototypes \ + ${INCS} \ + ${WARNINGS} \ + -O2 -fomit-frame-pointer + +AACFLAGS=${CFLAGS} ${COMMON_FLAGS} ${EXTRA_FLAGS} + +############################################################################### +### DO GENERAL STUFF +############################################################################### + +.SUFFIXES: +.SUFFIXES: .c .o .h .a + +all: source ${TARGET_OFILES} aacraid.o + +source: ${ALL_SOURCE} + +clean: + rm *.o + +############################################################################### +### DRIVER LINKS +############################################################################### + +aacraid.o: source ${TARGET_OFILES} + ld -r -o $@ $(TARGET_OFILES) + cp -r aacraid.o ../ + +############################################################################### +### SIMPLE COMPILES +############################################################################### + +linit.o: ./linit.c + $(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o linit.o ./linit.c + +aachba.o: ./aachba.c + $(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o aachba.o ./aachba.c + +osddi.o: ./osddi.c + $(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o osddi.o ./osddi.c + +osfuncs.o: ./osfuncs.c + $(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o osfuncs.o ./osfuncs.c + +commctrl.o: ./commctrl.c + $(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o commctrl.o ./commctrl.c + +comminit.o: ./comminit.c + $(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o comminit.o ./comminit.c + +commsup.o: ./commsup.c + $(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o commsup.o ./commsup.c + +dpcsup.o: ./dpcsup.c + $(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o dpcsup.o ./dpcsup.c + +aacid.o: ./aacid.c + $(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o aacid.o ./aacid.c + +port.o: ./port.c + $(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o port.o ./port.c + +ossup.o: ./ossup.c + $(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o ossup.o ./ossup.c + +rx.o: ./rx.c + $(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o rx.o ./rx.c + +sap1sup.o: ./sap1sup.c + $(CC) $(COMMON_FLAGS) $(AACFLAGS) -c -o sap1sup.o ./sap1sup.c + + diff -burN linux-2.2.19/drivers/scsi/aacraid/README linux.aacraid/drivers/scsi/aacraid/README --- linux-2.2.19/drivers/scsi/aacraid/README Wed Dec 31 18:00:00 1969 +++ linux.aacraid/drivers/scsi/aacraid/README Fri Jun 29 14:02:49 2001 @@ -0,0 +1,29 @@ + AACRAID Driver for Linux + +Introduction +------------------------- +The aacraid driver adds support for Adaptec (http://www.adaptec.com) +OEM based RAID controllers. This driver is for kernel 2.2.x. A +similar driver is available for kernel 2.4.x. + +Supported Cards/Chipsets +------------------------- + Dell Computer Corporation PERC 2 Quad Channel + Dell Computer Corporation PERC 2/Si + Dell Computer Corporation PERC 3/Si + Dell Computer Corporation PERC 3/Di + HP NetRAID-4M + +Not Supported Devices +------------------------- + Any and All Adaptec branded raid controllers. + +People +------------------------- + Adaptec Unix OEM Product Group + +Mailing List +------------------------- +Please see http://lists.us.dell.com/ for information +on mailing lists. There is both a development and +an announcment list. diff -burN linux-2.2.19/drivers/scsi/aacraid/aachba.c linux.aacraid/drivers/scsi/aacraid/aachba.c --- linux-2.2.19/drivers/scsi/aacraid/aachba.c Wed Dec 31 18:00:00 1969 +++ linux.aacraid/drivers/scsi/aacraid/aachba.c Fri Jul 20 09:52:36 2001 @@ -0,0 +1,1880 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * aachba.c + * + * Abstract: driver... + * +--*/ + +static char *ident_aachba = "aacraid_ident aachba.c 1.0.6 2000/10/09 Adaptec, Inc."; + +/*------------------------------------------------------------------------------ + * I N C L U D E S + *----------------------------------------------------------------------------*/ +#include "osheaders.h" +#include "AacGenericTypes.h" +#include "aac_unix_defs.h" +#include "comstruc.h" +#include "monkerapi.h" +#include "protocol.h" +#include "fsafs.h" +#include "fsact.h" +#include "fsaioctl.h" + +#include "sap1common.h" +#include "fsaport.h" +#include "pcisup.h" +#include "sap1.h" +#include "nodetype.h" +#include "comsup.h" +#include "afacomm.h" +#include "adapter.h" + +/*------------------------------------------------------------------------------ + * D E F I N E S + *----------------------------------------------------------------------------*/ +/* SCSI Commands */ +#define SS_TEST 0x00 /* Test unit ready */ +#define SS_REZERO 0x01 /* Rezero unit */ +#define SS_REQSEN 0x03 /* Request Sense */ +#define SS_REASGN 0x07 /* Reassign blocks */ +#define SS_READ 0x08 /* Read 6 */ +#define SS_WRITE 0x0A /* Write 6 */ +#define SS_INQUIR 0x12 /* inquiry */ +#define SS_ST_SP 0x1B /* Start/Stop unit */ +#define SS_LOCK 0x1E /* prevent/allow medium removal */ +#define SS_RESERV 0x16 /* Reserve */ +#define SS_RELES 0x17 /* Release */ +#define SS_MODESEN 0x1A /* Mode Sense 6 */ +#define SS_RDCAP 0x25 /* Read Capacity */ +#define SM_READ 0x28 /* Read 10 */ +#define SM_WRITE 0x2A /* Write 10 */ +#define SS_SEEK 0x2B /* Seek */ + +/* values for inqd_pdt: Peripheral device type in plain English */ +#define INQD_PDT_DA 0x00 /* Direct-access (DISK) device */ +#define INQD_PDT_PROC 0x03 /* Processor device */ +#define INQD_PDT_CHNGR 0x08 /* Changer (jukebox, scsi2) */ +#define INQD_PDT_COMM 0x09 /* Communication device (scsi2) */ +#define INQD_PDT_NOLUN2 0x1f /* Unknown Device (scsi2) */ +#define INQD_PDT_NOLUN 0x7f /* Logical Unit Not Present */ + +#define INQD_PDT_DMASK 0x1F /* Peripheral Device Type Mask */ +#define INQD_PDT_QMASK 0xE0 /* Peripheral Device Qualifer Mask */ + +#define TARGET_LUN_TO_CONTAINER(Target, Lun) (((Lun) << 4) | Target) +#define CONTAINER_TO_TARGET(Container) ((Container) & 0xf) +#define CONTAINER_TO_LUN(Container) ((Container) >> 4) + +#define MAX_FIB_DATA (sizeof(FIB) - sizeof(FIB_HEADER)) + +#define MAX_DRIVER_SG_SEGMENT_COUNT 17 + +// ------------------------------------------------------ +// Sense keys +// +#define SENKEY_NO_SENSE 0x00 // +#define SENKEY_UNDEFINED 0x01 // +#define SENKEY_NOT_READY 0x02 // +#define SENKEY_MEDIUM_ERR 0x03 // +#define SENKEY_HW_ERR 0x04 // +#define SENKEY_ILLEGAL 0x05 // +#define SENKEY_ATTENTION 0x06 // +#define SENKEY_PROTECTED 0x07 // +#define SENKEY_BLANK 0x08 // +#define SENKEY_V_UNIQUE 0x09 // +#define SENKEY_CPY_ABORT 0x0A // +#define SENKEY_ABORT 0x0B // +#define SENKEY_EQUAL 0x0C // +#define SENKEY_VOL_OVERFLOW 0x0D // +#define SENKEY_MISCOMP 0x0E // +#define SENKEY_RESERVED 0x0F // + +// ------------------------------------------------------ +// Sense codes +// +#define SENCODE_NO_SENSE 0x00 +#define SENCODE_END_OF_DATA 0x00 +#define SENCODE_BECOMING_READY 0x04 +#define SENCODE_INIT_CMD_REQUIRED 0x04 +#define SENCODE_PARAM_LIST_LENGTH_ERROR 0x1A +#define SENCODE_INVALID_COMMAND 0x20 +#define SENCODE_LBA_OUT_OF_RANGE 0x21 +#define SENCODE_INVALID_CDB_FIELD 0x24 +#define SENCODE_LUN_NOT_SUPPORTED 0x25 +#define SENCODE_INVALID_PARAM_FIELD 0x26 +#define SENCODE_PARAM_NOT_SUPPORTED 0x26 +#define SENCODE_PARAM_VALUE_INVALID 0x26 +#define SENCODE_RESET_OCCURRED 0x29 +#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x3E +#define SENCODE_INQUIRY_DATA_CHANGED 0x3F +#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x39 +#define SENCODE_DIAGNOSTIC_FAILURE 0x40 +#define SENCODE_INTERNAL_TARGET_FAILURE 0x44 +#define SENCODE_INVALID_MESSAGE_ERROR 0x49 +#define SENCODE_LUN_FAILED_SELF_CONFIG 0x4c +#define SENCODE_OVERLAPPED_COMMAND 0x4E + +// ------------------------------------------------------ +// Additional sense codes +// +#define ASENCODE_NO_SENSE 0x00 +#define ASENCODE_END_OF_DATA 0x05 +#define ASENCODE_BECOMING_READY 0x01 +#define ASENCODE_INIT_CMD_REQUIRED 0x02 +#define ASENCODE_PARAM_LIST_LENGTH_ERROR 0x00 +#define ASENCODE_INVALID_COMMAND 0x00 +#define ASENCODE_LBA_OUT_OF_RANGE 0x00 +#define ASENCODE_INVALID_CDB_FIELD 0x00 +#define ASENCODE_LUN_NOT_SUPPORTED 0x00 +#define ASENCODE_INVALID_PARAM_FIELD 0x00 +#define ASENCODE_PARAM_NOT_SUPPORTED 0x01 +#define ASENCODE_PARAM_VALUE_INVALID 0x02 +#define ASENCODE_RESET_OCCURRED 0x00 +#define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x00 +#define ASENCODE_INQUIRY_DATA_CHANGED 0x03 +#define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x00 +#define ASENCODE_DIAGNOSTIC_FAILURE 0x80 +#define ASENCODE_INTERNAL_TARGET_FAILURE 0x00 +#define ASENCODE_INVALID_MESSAGE_ERROR 0x00 +#define ASENCODE_LUN_FAILED_SELF_CONFIG 0x00 +#define ASENCODE_OVERLAPPED_COMMAND 0x00 + +#define BYTE0( x ) ( unsigned char )( x ) +#define BYTE1( x ) ( unsigned char )( x >> 8 ) +#define BYTE2( x ) ( unsigned char )( x >> 16 ) +#define BYTE3( x ) ( unsigned char )( x >> 24 ) + +/*------------------------------------------------------------------------------ + * S T R U C T S / T Y P E D E F S + *----------------------------------------------------------------------------*/ +/* SCSI inquiry data */ +struct inquiry_data { + unchar inqd_pdt; /* Peripheral qualifier | Peripheral Device Type */ + unchar inqd_dtq; /* RMB | Device Type Qualifier */ + unchar inqd_ver; /* ISO version | ECMA version | ANSI-approved version */ + unchar inqd_rdf; /* AENC | TrmIOP | Response data format */ + unchar inqd_len; /* Additional length (n-4) */ + unchar inqd_pad1[2]; /* Reserved - must be zero */ + unchar inqd_pad2; /* RelAdr | WBus32 | WBus16 | Sync | Linked |Reserved| CmdQue | SftRe */ + unchar inqd_vid[8]; /* Vendor ID */ + unchar inqd_pid[16]; /* Product ID */ + unchar inqd_prl[4]; /* Product Revision Level */ +}; + +struct sense_data { + unchar error_code; // 70h (current errors), 71h(deferred errors) + unchar valid:1; // A valid bit of one indicates that the information + // field contains valid information as defined in the + // SCSI-2 Standard. + + unchar segment_number; // Only used for COPY, COMPARE, or COPY AND VERIFY + // commands + + unchar sense_key:4; // Sense Key + unchar reserved:1; + unchar ILI:1; // Incorrect Length Indicator + unchar EOM:1; // End Of Medium - reserved for random access devices + unchar filemark:1; // Filemark - reserved for random access devices + + unchar information[4]; // for direct-access devices, contains the unsigned + // logical block address or residue associated with + // the sense key + unchar add_sense_len; // number of additional sense bytes to follow this field + unchar cmnd_info[4]; // not used + unchar ASC; // Additional Sense Code + unchar ASCQ; // Additional Sense Code Qualifier + unchar FRUC; // Field Replaceable Unit Code - not used + + unchar bit_ptr:3; // indicates which byte of the CDB or parameter data + // was in error + unchar BPV:1; // bit pointer valid (BPV): 1- indicates that + // the bit_ptr field has valid value + unchar reserved2:2; + unchar CD:1; // command data bit: 1- illegal parameter in CDB. + // 0- illegal parameter in data. + unchar SKSV:1; + + unchar field_ptr[2]; // byte of the CDB or parameter data in error +}; + +/*------------------------------------------------------------------------------ + * G L O B A L S + *----------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------ + * M O D U L E G L O B A L S + *----------------------------------------------------------------------------*/ +static fsadev_t *g_fsa_dev_array[8]; // SCSI Device Instance Pointers +static struct sense_data g_sense_data[MAXIMUM_NUM_CONTAINERS]; + +/*------------------------------------------------------------------------------ + * F U N C T I O N P R O T O T Y P E S + *----------------------------------------------------------------------------*/ +AAC_STATUS AacHba_OpenAdapter( PVOID AdapterArg); +AAC_STATUS AacHba_CloseAdapter( PVOID AdapterArg); +BOOLEAN AacHba_HandleAif( PVOID AdapterArg, PFIB_CONTEXT FibContext); +BOOLEAN AacHba_AdapterDeviceControl ( PVOID AdapterArg, + PAFA_IOCTL_CMD IoctlCmdPtr, int * ReturnStatus); + +void AacHba_CompleteScsi( + Scsi_Cmnd *scsi_cmnd_ptr ); + +void AacHba_CompleteScsiNoLock( + Scsi_Cmnd *scsi_cmnd_ptr ); + +static void AacHba_ReadCallback( + void *Context, + PFIB_CONTEXT FibContext, + int FibStatus ); + +static void AacHba_WriteCallback( + void *Context, + PFIB_CONTEXT FibContext, + int FibStatus ); + +int AacHba_DoScsiRead( + Scsi_Cmnd *scsi_cmnd_ptr, + int ContainerId, + int wait ); + +int AacHba_DoScsiWrite( + Scsi_Cmnd *scsi_cmnd_ptr, + int ContainerId, + int wait ); + +int AacHba_QueryDisk( + PVOID AdapterArg, // CommonExtensionPtr + IN PAFA_IOCTL_CMD IoctlCmdPtr ); + +int AacHba_ForceDeleteDisk( + PVOID AdapterArg, // CommonExtensionPtr + IN PAFA_IOCTL_CMD IoctlCmdPtr ); + +int AacHba_DeleteDisk( + PVOID AdapterArg, + IN PAFA_IOCTL_CMD IoctlCmdPtr ); + +void AacHba_DetachAdapter( + IN PVOID AdapterArg ); + +BOOLEAN AacCommDetachAdapter( + IN PAFA_COMM_ADAPTER Adapter ); + +void AacHba_SetSenseData( + char * sense_buf, + unchar sense_key, + unchar sense_code, + unchar a_sense_code, + unchar incorrect_length, + unchar bit_pointer, + unsigned field_pointer, + unsigned long residue ); + +static void get_sd_devname( + long disknum, + char * buffer); + +// Keep these here for the time being - #REVIEW# +int +AfaCommAdapterDeviceControl ( + IN PVOID AdapterArg, + IN PAFA_IOCTL_CMD IoctlCmdPtr + ); + +AAC_STATUS +AfaCommRegisterNewClassDriver( + IN PAFA_COMM_ADAPTER Adapter, + IN PAFA_NEW_CLASS_DRIVER NewClassDriver, + OUT PAFA_NEW_CLASS_DRIVER_RESPONSE NewClassDriverResponse + ); + +void +SetInqDataStr (int, void *, int); +/*------------------------------------------------------------------------------ + * F U N C T I O N S + *----------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------ + AacHba_ClassDriverInit() + + Setup 'core' class driver to answer ioctl's + *----------------------------------------------------------------------------*/ +int AacHba_ClassDriverInit( + PCI_MINIPORT_COMMON_EXTENSION * CommonExtensionPtr) +/*----------------------------------------------------------------------------*/ +{ + AFA_NEW_CLASS_DRIVER NewClassDriver; + AFA_NEW_CLASS_DRIVER_RESPONSE NewClassDriverResponse; + PAFA_COMM_ADAPTER Adapter; + + Adapter = (AFA_COMM_ADAPTER *)CommonExtensionPtr->Adapter; + + RtlZeroMemory( &NewClassDriver, sizeof( AFA_NEW_CLASS_DRIVER ) ); + + // ClassDriverExtension is the first argument passed to class driver functions below + NewClassDriver.ClassDriverExtension = CommonExtensionPtr; + + NewClassDriver.OpenAdapter = AacHba_OpenAdapter; + NewClassDriver.CloseAdapter = AacHba_CloseAdapter; + NewClassDriver.DeviceControl = AacHba_AdapterDeviceControl; + NewClassDriver.HandleAif = AacHba_HandleAif; + AfaCommRegisterNewClassDriver( Adapter, &NewClassDriver, &NewClassDriverResponse ); + + return(0); +} + + +/*------------------------------------------------------------------------------ + AacHba_ProbeContainers() + + Make a list of all containers in the system. + *----------------------------------------------------------------------------*/ +int AacHba_ProbeContainers( + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr ) +/*----------------------------------------------------------------------------*/ +{ + fsadev_t *fsa_dev_ptr; + int Index, Status; + PMNTINFO DiskInfo; + PMNTINFORESPONSE DiskInfoResponse; + PFIB_CONTEXT FibContext; + AFA_COMM_ADAPTER *Adapter; + unsigned instance; + + 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] - 1; + cp = scsi_cmnd_ptr->request_buffer; + cp[0] = ( capacity >> 24 ) & 0xff; + cp[1] = ( capacity >> 16 ) & 0xff; + cp[2] = ( capacity >> 8 ) & 0xff; + cp[3] = ( capacity >> 0 ) & 0xff; + cp[4] = 0; + cp[5] = 0; + cp[6] = 2; + cp[7] = 0; + + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + + return ( 0 ); + } + + case SS_MODESEN: + { + char *mode_buf; + + cmn_err( CE_DEBUG, "MODE SENSE command" ); + mode_buf = scsi_cmnd_ptr->request_buffer; + mode_buf[0] = 0; // Mode data length (MSB) + mode_buf[1] = 6; // Mode data length (LSB) + mode_buf[2] = 0; // Medium type - default + mode_buf[3] = 0; // Device-specific param, bit 8: 0/1 = write enabled/protected + mode_buf[4] = 0; // reserved + mode_buf[5] = 0; // reserved + mode_buf[6] = 0; // Block descriptor length (MSB) + mode_buf[7] = 0; // Block descriptor length (LSB) + + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + + return ( 0 ); + } + + + // These commands are all No-Ops + case SS_TEST: + cmn_err( CE_DEBUG, "TEST UNIT READY command" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_REQSEN: + cmn_err( CE_DEBUG, "REQUEST SENSE command" ); + + memcpy( scsi_cmnd_ptr->sense_buffer, &g_sense_data[ContainerId], + sizeof( struct sense_data ) ); + bzero( &g_sense_data[ContainerId], sizeof( struct sense_data ) ); + + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_LOCK: + cmn_err(CE_DEBUG, "LOCK command"); + + if( scsi_cmnd_ptr->cmnd[4] ) + fsa_dev_ptr->ContainerLocked[ContainerId] = 1; + else + fsa_dev_ptr->ContainerLocked[ContainerId] = 0; + + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_RESERV: + cmn_err( CE_DEBUG, "RESERVE command" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_RELES: + cmn_err( CE_DEBUG, "RELEASE command" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_REZERO: + cmn_err( CE_DEBUG, "REZERO command" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_REASGN: + cmn_err( CE_DEBUG, "REASSIGN command" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_SEEK: + cmn_err( CE_DEBUG, "SEEK command" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_ST_SP: + cmn_err( CE_DEBUG, "START/STOP command" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + } + + switch ( scsi_cmnd_ptr->cmnd[0] ) + { + case SS_READ: + case SM_READ: + // Hack to keep track of ordinal number of the device that corresponds + // to a container. Needed to convert containers to /dev/sd device names + fsa_dev_ptr->ContainerDevNo[ContainerId] = + DEVICE_NR( scsi_cmnd_ptr->request.rq_dev ); + + return( AacHba_DoScsiRead( scsi_cmnd_ptr, ContainerId, wait ) ); + break; + + case SS_WRITE: + case SM_WRITE: + return( AacHba_DoScsiWrite( scsi_cmnd_ptr, ContainerId, wait ) ); + break; + } + // + // Unhandled commands + // + cmn_err( CE_WARN, "Unhandled SCSI Command: 0x%x", scsi_cmnd_ptr->cmnd[0] ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_ILLEGAL, SENCODE_INVALID_COMMAND, ASENCODE_INVALID_COMMAND, + 0, 0, 0, 0 ); + + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( -1 ); +} + + +/*------------------------------------------------------------------------------ + AacHba_DoScsiRead() + + Handles SCSI READ requests + + Preconditions: + Postconditions: + Returns 0 on success, -1 on failure + *----------------------------------------------------------------------------*/ +int AacHba_DoScsiRead( + Scsi_Cmnd *scsi_cmnd_ptr, + int ContainerId, + int wait ) +/*----------------------------------------------------------------------------*/ +{ + u_long lba; + u_long count; + u_long byte_count; + int Status; + + PBLOCKREAD BlockReadDisk; + PBLOCKREADRESPONSE BlockReadResponse; + uint16_t FibSize; + PCI_MINIPORT_COMMON_EXTENSION *CommonExtension; + AFA_COMM_ADAPTER *Adapter; + PFIB_CONTEXT cmd_fibcontext; + + CommonExtension = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata ); + Adapter = ( AFA_COMM_ADAPTER * )CommonExtension->Adapter; + + // Get block address and transfer length + if ( scsi_cmnd_ptr->cmnd[0] == SS_READ ) // 6 byte command + { + cmn_err( CE_DEBUG, "aachba: received a read(6) command on target %d", ContainerId ); + + lba = ( ( scsi_cmnd_ptr->cmnd[1] & 0x1F ) << 16 ) | + ( scsi_cmnd_ptr->cmnd[2] << 8 ) | + scsi_cmnd_ptr->cmnd[3]; + count = scsi_cmnd_ptr->cmnd[4]; + + if ( count == 0 ) + count = 256; + } + else + { + cmn_err( CE_DEBUG, "aachba: received a read(10) command on target %d", ContainerId ); + + lba = ( scsi_cmnd_ptr->cmnd[2] << 24 ) | ( scsi_cmnd_ptr->cmnd[3] << 16 ) | + ( scsi_cmnd_ptr->cmnd[4] << 8 ) | scsi_cmnd_ptr->cmnd[5]; + + count = ( scsi_cmnd_ptr->cmnd[7] << 8 ) | scsi_cmnd_ptr->cmnd[8]; + } + cmn_err( CE_DEBUG, "AacHba_DoScsiRead[cpu %d]: lba = %lu, t = %ld", smp_processor_id(), lba, jiffies ); + + //------------------------------------------------------------------------- + // Alocate and initialize a Fib + // Setup BlockRead command + if( !( cmd_fibcontext = Adapter->CommFuncs.AllocateFib( Adapter ) ) ) + { + cmn_err( CE_WARN, "AacHba_DoScsiRead: AllocateFib failed\n" ); + scsi_cmnd_ptr->result = DID_ERROR << 16; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( -1 ); + } + + Adapter->CommFuncs.InitializeFib( cmd_fibcontext ); + + BlockReadDisk = ( PBLOCKREAD )Adapter->CommFuncs.GetFibData( cmd_fibcontext ); + BlockReadDisk->Command = VM_CtBlockRead; + BlockReadDisk->ContainerId = ContainerId; + BlockReadDisk->BlockNumber = lba; + BlockReadDisk->ByteCount = count * 512; + BlockReadDisk->SgMap.SgCount = 1; + + if( BlockReadDisk->ByteCount > ( 64 * 1024 ) ) + { + cmn_err( CE_WARN, "AacHba_DoScsiRead: READ request is larger than 64K" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_ILLEGAL, SENCODE_INVALID_CDB_FIELD, ASENCODE_INVALID_CDB_FIELD, + 0, 0, 7, 0 ); + + goto err_return; + } + + //------------------------------------------------------------------------- + // Build Scatter/Gather list + // + if ( scsi_cmnd_ptr->use_sg ) // use scatter/gather list + { + struct scatterlist *scatterlist_ptr; + int segment; + + scatterlist_ptr = ( struct scatterlist * )scsi_cmnd_ptr->request_buffer; + + byte_count = 0; + for( segment = 0; segment< scsi_cmnd_ptr->use_sg; segment++ ) + { + BlockReadDisk->SgMap.SgEntry[segment].SgAddress = + ( void * )OsVirtToPhys( scatterlist_ptr[segment].address ); + BlockReadDisk->SgMap.SgEntry[segment].SgByteCount = + scatterlist_ptr[segment].length; + +#ifdef DEBUG_SGBUFFER + memset( scatterlist_ptr[segment].address, 0xa5, + scatterlist_ptr[segment].length ); +#endif + + byte_count += scatterlist_ptr[segment].length; + + if( BlockReadDisk->SgMap.SgEntry[segment].SgByteCount > ( 64 * 1024 ) ) + { + cmn_err( CE_WARN, "AacHba_DoScsiRead: Segment byte count is larger than 64K" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_ILLEGAL, SENCODE_INVALID_CDB_FIELD, ASENCODE_INVALID_CDB_FIELD, + 0, 0, 7, 0 ); + + goto err_return; + } + /* + cmn_err(CE_DEBUG, "SgEntry[%d].SgAddress = 0x%x, Byte count = 0x%x", + segment, + BlockReadDisk->SgMap.SgEntry[segment].SgAddress, + BlockReadDisk->SgMap.SgEntry[segment].SgByteCount); + */ + } + BlockReadDisk->SgMap.SgCount = scsi_cmnd_ptr->use_sg; + + if( BlockReadDisk->SgMap.SgCount > MAX_DRIVER_SG_SEGMENT_COUNT ) + { + cmn_err( CE_WARN, "AacHba_DoScsiRead: READ request with SgCount > %d", + MAX_DRIVER_SG_SEGMENT_COUNT ); + scsi_cmnd_ptr->result = DID_ERROR << 16; + goto err_return; + } + } + else // one piece of contiguous phys mem + { + BlockReadDisk->SgMap.SgEntry[0].SgAddress = + ( void * )OsVirtToPhys( scsi_cmnd_ptr->request_buffer ); + BlockReadDisk->SgMap.SgEntry[0].SgByteCount = scsi_cmnd_ptr->request_bufflen; + + byte_count = scsi_cmnd_ptr->request_bufflen; + + if( BlockReadDisk->SgMap.SgEntry[0].SgByteCount > ( 64 * 1024 ) ) + { + cmn_err( CE_WARN, "AacHba_DoScsiRead: Single segment byte count is larger than 64K" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_ILLEGAL, SENCODE_INVALID_CDB_FIELD, ASENCODE_INVALID_CDB_FIELD, + 0, 0, 7, 0 ); + + goto err_return; + } + } + + if( byte_count != BlockReadDisk->ByteCount ) + cmn_err( CE_WARN, "AacHba_DoScsiRead: byte_count != BlockReadDisk->ByteCount" ); + + //------------------------------------------------------------------------- + // Now send the Fib to the adapter + // + FibSize = sizeof( BLOCKREAD ) + ( ( BlockReadDisk->SgMap.SgCount - 1 ) * sizeof( SGENTRY ) ); + + if( wait ) + { + // This path shouldn't ever get executed with the current driver + Status = Adapter->CommFuncs.SendFib( ContainerCommand, + cmd_fibcontext, + FibSize, + FsaNormal, + TRUE, + NULL, + TRUE, + NULL, + NULL); + + BlockReadResponse = ( PBLOCKREADRESPONSE ) + Adapter->CommFuncs.GetFibData( cmd_fibcontext ); + + Adapter->CommFuncs.CompleteFib( cmd_fibcontext ); + Adapter->CommFuncs.FreeFib( cmd_fibcontext ); + + if( BlockReadResponse->Status != ST_OK ) + { + cmn_err( CE_WARN, "AacHba_DoScsiRead: BlockReadCommand failed with status: %d", + BlockReadResponse->Status ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_HW_ERR, SENCODE_INTERNAL_TARGET_FAILURE, ASENCODE_INTERNAL_TARGET_FAILURE, + 0, 0, 0, 0 ); + + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( -1 ); + } + else + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + } + else + { + Status = Adapter->CommFuncs.SendFib( ContainerCommand, + cmd_fibcontext, + FibSize, + FsaNormal, + FALSE, + NULL, + TRUE, + ( PFIB_CALLBACK )AacHba_ReadCallback, + ( void *)scsi_cmnd_ptr ); + + // Check that the command queued to the controller + if (Status != STATUS_PENDING) { + cmn_err( CE_WARN, "AacHba_DoScsiRead: SendFib failed with status: %d\n", + Status); + + // For some reason, the Fib didn't queue, return QUEUE_FULL + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | QUEUE_FULL ; + goto err_return; + } + + // don't call done func here + return ( 0 ); + } + +err_return: + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + + Adapter->CommFuncs.CompleteFib( cmd_fibcontext ); + Adapter->CommFuncs.FreeFib( cmd_fibcontext ); + + return ( -1 ); +} + + +/*------------------------------------------------------------------------------ + AacHba_DoScsiWrite() + + Handles SCSI WRITE requests + + Preconditions: + Postconditions: + Returns 0 on success, -1 on failure + *----------------------------------------------------------------------------*/ +int AacHba_DoScsiWrite( + Scsi_Cmnd *scsi_cmnd_ptr, + int ContainerId, + int wait ) +/*----------------------------------------------------------------------------*/ +{ + u_long lba; + u_long count; + u_long byte_count; + int Status; + + PBLOCKWRITE BlockWriteDisk; + PBLOCKWRITERESPONSE BlockWriteResponse; + uint16_t FibSize; + PCI_MINIPORT_COMMON_EXTENSION *CommonExtension; + AFA_COMM_ADAPTER *Adapter; + PFIB_CONTEXT cmd_fibcontext; + + CommonExtension = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata ); + Adapter = ( AFA_COMM_ADAPTER * )CommonExtension->Adapter; + + // Get block address and transfer length + if ( scsi_cmnd_ptr->cmnd[0] == SS_WRITE ) // 6 byte command + { + lba = ( ( scsi_cmnd_ptr->cmnd[1] & 0x1F ) << 16 ) | + ( scsi_cmnd_ptr->cmnd[2] << 8 ) | + scsi_cmnd_ptr->cmnd[3]; + count = scsi_cmnd_ptr->cmnd[4]; + + + if ( count == 0 ) + count = 256; + } + else + { + cmn_err( CE_DEBUG, "aachba: received a write(10) command on target %d", ContainerId ); + + lba = ( scsi_cmnd_ptr->cmnd[2] << 24 ) | ( scsi_cmnd_ptr->cmnd[3] << 16 ) | + ( scsi_cmnd_ptr->cmnd[4] << 8 ) | scsi_cmnd_ptr->cmnd[5]; + + count = ( scsi_cmnd_ptr->cmnd[7] << 8 ) | scsi_cmnd_ptr->cmnd[8]; + } + cmn_err( CE_DEBUG, "AacHba_DoScsiWrite[cpu %d]: lba = %lu, t = %ld", smp_processor_id(), lba, jiffies ); + + //------------------------------------------------------------------------- + // Alocate and initialize a Fib + // Setup BlockWrite command + if( !( cmd_fibcontext = Adapter->CommFuncs.AllocateFib( Adapter ) ) ) + { + cmn_err( CE_WARN, "AacHba_DoScsiWrite: AllocateFib failed\n" ); + scsi_cmnd_ptr->result = DID_ERROR << 16; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( -1 ); + } + + Adapter->CommFuncs.InitializeFib( cmd_fibcontext ); + + BlockWriteDisk = (PBLOCKWRITE) Adapter->CommFuncs.GetFibData( cmd_fibcontext ); + BlockWriteDisk->Command = VM_CtBlockWrite; + BlockWriteDisk->ContainerId = ContainerId; + BlockWriteDisk->BlockNumber = lba; + BlockWriteDisk->ByteCount = count * 512; + BlockWriteDisk->SgMap.SgCount = 1; + + if ( BlockWriteDisk->ByteCount > ( 64 * 1024 ) ) + { + 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 ) + { + // This path shouldn't ever get executed with the current driver + Status = Adapter->CommFuncs.SendFib( ContainerCommand, + cmd_fibcontext, + FibSize, + FsaNormal, + TRUE, + NULL, + TRUE, + NULL, + NULL ); + + BlockWriteResponse = ( PBLOCKWRITERESPONSE ) + Adapter->CommFuncs.GetFibData( cmd_fibcontext ); + + Adapter->CommFuncs.CompleteFib( cmd_fibcontext ); + Adapter->CommFuncs.FreeFib( cmd_fibcontext ); + + if( BlockWriteResponse->Status != ST_OK ) + { + cmn_err( CE_WARN, "AacHba_DoScsiWrite: BlockWriteCommand failed with status: %d\n", + BlockWriteResponse->Status ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;; + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_HW_ERR, SENCODE_INTERNAL_TARGET_FAILURE, ASENCODE_INTERNAL_TARGET_FAILURE, + 0, 0, 0, 0 ); + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( -1 ); + } + else + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + } + else + { + Status = Adapter->CommFuncs.SendFib( ContainerCommand, + cmd_fibcontext, + FibSize, + FsaNormal, + FALSE, + NULL, + TRUE, + ( PFIB_CALLBACK )AacHba_WriteCallback, + ( void * )scsi_cmnd_ptr ); + + // Check that the command queued to the controller + if (Status != STATUS_PENDING) { + cmn_err( CE_WARN, "AacHba_DoScsiWrite: SendFib failed with status: %d\n", + Status); + + // For some reason, the Fib didn't queue, return QUEUE_FULL + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | QUEUE_FULL ; + goto err_return; + } + + // don't call done func here - it should be called by the WriteCallback + return ( 0 ); + } + +err_return: + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + + Adapter->CommFuncs.CompleteFib( cmd_fibcontext ); + Adapter->CommFuncs.FreeFib( cmd_fibcontext ); + + return ( -1 ); +} + + +/*------------------------------------------------------------------------------ + AacHba_ReadCallback() + *----------------------------------------------------------------------------*/ +void AacHba_ReadCallback( + VOID *Context, + PFIB_CONTEXT FibContext, + int FibStatus ) +/*----------------------------------------------------------------------------*/ +{ + PCI_MINIPORT_COMMON_EXTENSION *CommonExtension; + AFA_COMM_ADAPTER *Adapter; + BLOCKREADRESPONSE *BlockReadResponse; + Scsi_Cmnd * scsi_cmnd_ptr; + u_long lba; + int ContainerId; + + scsi_cmnd_ptr = ( Scsi_Cmnd * )Context; + + CommonExtension = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata ); + Adapter = ( AFA_COMM_ADAPTER * )CommonExtension->Adapter; + + ContainerId = TARGET_LUN_TO_CONTAINER( scsi_cmnd_ptr->target, scsi_cmnd_ptr->lun ); + + lba = ( ( scsi_cmnd_ptr->cmnd[1] & 0x1F ) << 16 ) | + ( scsi_cmnd_ptr->cmnd[2] << 8 ) | + scsi_cmnd_ptr->cmnd[3]; + cmn_err( CE_DEBUG, "AacHba_ReadCallback[cpu %d]: lba = %ld, t = %ld", smp_processor_id(), lba, jiffies ); + + if( FibContext == 0 ) + { + cmn_err( CE_WARN, "AacHba_ReadCallback: no fib context" ); + scsi_cmnd_ptr->result = DID_ERROR << 16; + AacHba_CompleteScsi( scsi_cmnd_ptr ); + return; + } + + BlockReadResponse = ( PBLOCKREADRESPONSE )Adapter->CommFuncs.GetFibData( FibContext ); + + if ( BlockReadResponse->Status == ST_OK ) + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + else + { + cmn_err( CE_WARN, "AacHba_ReadCallback: read failed, status = %d\n", + BlockReadResponse->Status ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_HW_ERR, SENCODE_INTERNAL_TARGET_FAILURE, ASENCODE_INTERNAL_TARGET_FAILURE, + 0, 0, 0, 0 ); + } + +#ifdef DEBUG_SGBUFFER + if ( scsi_cmnd_ptr->use_sg ) // use scatter/gather list + { + struct scatterlist *scatterlist_ptr; + int i, segment, count; + char *ptr; + + scatterlist_ptr = ( struct scatterlist * )scsi_cmnd_ptr->request_buffer; + + for( segment = 0; segment < scsi_cmnd_ptr->use_sg; segment++ ) + { + count = 0; + ptr = scatterlist_ptr[segment].address; + for( i = 0; i < scatterlist_ptr[segment].length; i++ ) + { + if( *( ptr++ ) == 0xa5 ) + count++; + } + if( count == scatterlist_ptr[segment].length ) + cmn_err( CE_WARN, "AacHba_ReadCallback: segment %d not filled", segment ); + + } + } +#endif + + Adapter->CommFuncs.CompleteFib( FibContext ); + Adapter->CommFuncs.FreeFib( FibContext ); + + AacHba_CompleteScsi( scsi_cmnd_ptr ); +} + +/*------------------------------------------------------------------------------ + AacHba_WriteCallback() + *----------------------------------------------------------------------------*/ +void AacHba_WriteCallback( + VOID *Context, + PFIB_CONTEXT FibContext, + int FibStatus ) +/*----------------------------------------------------------------------------*/ +{ + PCI_MINIPORT_COMMON_EXTENSION *CommonExtension; + AFA_COMM_ADAPTER *Adapter; + BLOCKWRITERESPONSE *BlockWriteResponse; + Scsi_Cmnd *scsi_cmnd_ptr; + u_long lba; + int ContainerId; + + scsi_cmnd_ptr = ( Scsi_Cmnd * )Context; + + CommonExtension = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata ); + Adapter = ( AFA_COMM_ADAPTER * )CommonExtension->Adapter; + + ContainerId = TARGET_LUN_TO_CONTAINER( scsi_cmnd_ptr->target, scsi_cmnd_ptr->lun ); + + lba = ( ( scsi_cmnd_ptr->cmnd[1] & 0x1F ) << 16 ) | + ( scsi_cmnd_ptr->cmnd[2] << 8 ) | + scsi_cmnd_ptr->cmnd[3]; + cmn_err( CE_DEBUG, "AacHba_WriteCallback[cpu %d]: lba = %ld, t = %ld", smp_processor_id(), lba, jiffies ); + if( FibContext == 0 ) + { + cmn_err( CE_WARN, "AacHba_WriteCallback: no fib context" ); + scsi_cmnd_ptr->result = DID_ERROR << 16; + AacHba_CompleteScsi( scsi_cmnd_ptr ); + return; + } + + BlockWriteResponse = (PBLOCKWRITERESPONSE) Adapter->CommFuncs.GetFibData( FibContext ); + if (BlockWriteResponse->Status == ST_OK) + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + else + { + cmn_err( CE_WARN, "AacHba_WriteCallback: write failed, status = %d\n", + BlockWriteResponse->Status ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_HW_ERR, SENCODE_INTERNAL_TARGET_FAILURE, ASENCODE_INTERNAL_TARGET_FAILURE, + 0, 0, 0, 0 ); + } + + Adapter->CommFuncs.CompleteFib( FibContext ); + Adapter->CommFuncs.FreeFib( FibContext ); + + AacHba_CompleteScsi( scsi_cmnd_ptr ); +} + + +/*------------------------------------------------------------------------------ + AacHba_Ioctl() + + Handle IOCTL requests + + Preconditions: + Postconditions: + *----------------------------------------------------------------------------*/ +int AacHba_Ioctl( + PCI_MINIPORT_COMMON_EXTENSION *CommonExtension, + int cmd, + void * arg ) +/*----------------------------------------------------------------------------*/ +{ + Sa_ADAPTER_EXTENSION *AdapterExtension; + AFA_IOCTL_CMD IoctlCmd; + int status; + + AdapterExtension = ( Sa_ADAPTER_EXTENSION * )CommonExtension->MiniPort; + + cmn_err( CE_DEBUG, "AacHba_Ioctl, type = %d", cmd ); + switch( cmd ) + { + case FSACTL_SENDFIB: + cmn_err( CE_DEBUG, "FSACTL_SENDFIB" ); + break; + + case FSACTL_AIF_THREAD: + cmn_err( CE_DEBUG, "FSACTL_AIF_THREAD" ); + break; + + case FSACTL_NULL_IO_TEST: + cmn_err( CE_DEBUG, "FSACTL_NULL_IO_TEST" ); + break; + + case FSACTL_SIM_IO_TEST: + cmn_err( CE_DEBUG, "FSACTL_SIM_IO_TEST" ); + break; + + case FSACTL_GET_FIBTIMES: + cmn_err( CE_DEBUG, "FSACTL_GET_FIBTIMES" ); + break; + + case FSACTL_ZERO_FIBTIMES: + cmn_err( CE_DEBUG, "FSACTL_ZERO_FIBTIMES"); + break; + + case FSACTL_GET_VAR: + cmn_err( CE_DEBUG, "FSACTL_GET_VAR" ); + break; + + case FSACTL_SET_VAR: + cmn_err( CE_DEBUG, "FSACTL_SET_VAR" ); + break; + + case FSACTL_OPEN_ADAPTER_CONFIG: + cmn_err( CE_DEBUG, "FSACTL_OPEN_ADAPTER_CONFIG" ); + break; + + case FSACTL_CLOSE_ADAPTER_CONFIG: + cmn_err( CE_DEBUG, "FSACTL_CLOSE_ADAPTER_CONFIG" ); + break; + + case FSACTL_QUERY_ADAPTER_CONFIG: + cmn_err( CE_DEBUG, "FSACTL_QUERY_ADAPTER_CONFIG" ); + break; + + case FSACTL_OPEN_GET_ADAPTER_FIB: + cmn_err( CE_DEBUG, "FSACTL_OPEN_GET_ADAPTER_FIB" ); + break; + + case FSACTL_GET_NEXT_ADAPTER_FIB: + cmn_err( CE_DEBUG, "FSACTL_GET_NEXT_ADAPTER_FIB" ); + break; + + case FSACTL_CLOSE_GET_ADAPTER_FIB: + cmn_err( CE_DEBUG, "FSACTL_CLOSE_GET_ADAPTER_FIB" ); + break; + + case FSACTL_MINIPORT_REV_CHECK: + cmn_err( CE_DEBUG, "FSACTL_MINIPORT_REV_CHECK" ); + break; + + case FSACTL_OPENCLS_COMM_PERF_DATA: + cmn_err( CE_DEBUG, "FSACTL_OPENCLS_COMM_PERF_DATA" ); + break; + + case FSACTL_GET_COMM_PERF_DATA: + cmn_err( CE_DEBUG, "FSACTL_GET_COMM_PERF_DATA" ); + break; + + case FSACTL_QUERY_DISK: + cmn_err( CE_DEBUG, "FSACTL_QUERY_DISK" ); + break; + + case FSACTL_DELETE_DISK: + cmn_err( CE_DEBUG, "FSACTL_DELETE_DISK" ); + break; + + default: + cmn_err( CE_DEBUG, "Unknown ioctl: 0x%x", cmd ); + } + + IoctlCmd.cmd = cmd; + IoctlCmd.arg = ( intptr_t )arg; + IoctlCmd.flag = 0; + IoctlCmd.cred_p = 0; + IoctlCmd.rval_p = 0; + + status = AfaCommAdapterDeviceControl( CommonExtension->Adapter, &IoctlCmd ); + cmn_err( CE_DEBUG, "AAC_Ioctl, completion status = %d", status ); + return( status ); +} + + +/*------------------------------------------------------------------------------ + AacHba_AdapterDeviceControl() + + Preconditions: + Postconditions: + Returns TRUE if ioctl handled, FALSE otherwise + *ReturnStatus set to completion status + *----------------------------------------------------------------------------*/ +BOOLEAN AacHba_AdapterDeviceControl ( + PVOID AdapterArg, // CommonExtensionPtr + IN PAFA_IOCTL_CMD IoctlCmdPtr, + OUT int * ReturnStatus ) +/*----------------------------------------------------------------------------*/ +{ + BOOLEAN Handled = TRUE; // start out handling it. + int Status = EFAULT; + + switch( IoctlCmdPtr->cmd ) + { + case FSACTL_QUERY_DISK: + Status = AacHba_QueryDisk( AdapterArg, IoctlCmdPtr ); + break; + + case FSACTL_DELETE_DISK: + Status = AacHba_DeleteDisk( AdapterArg, IoctlCmdPtr ); + break; + + case FSACTL_FORCE_DELETE_DISK: + Status = AacHba_ForceDeleteDisk( AdapterArg, IoctlCmdPtr ); + break; + + case 2131: + if( AacHba_ProbeContainers( ( PCI_MINIPORT_COMMON_EXTENSION * )AdapterArg ) ) + Status = -EFAULT; + break; + + default: + Handled = FALSE; + break; + } + + *ReturnStatus = Status; + + return( Handled ); +} + + +/*------------------------------------------------------------------------------ + AacHba_QueryDisk() + + Postconditions: + Return values + 0 = OK + -EFAULT = Bad address + -EINVAL = Bad container number + *----------------------------------------------------------------------------*/ +int AacHba_QueryDisk( + PVOID AdapterArg, // CommonExtensionPtr + IN PAFA_IOCTL_CMD IoctlCmdPtr ) +/*----------------------------------------------------------------------------*/ +{ + UNIX_QUERY_DISK QueryDisk; + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr; + fsadev_t *fsa_dev_ptr; + + CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )AdapterArg; + fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev ); + + if( copyin( IoctlCmdPtr->arg, &QueryDisk, sizeof( UNIX_QUERY_DISK ) ) ) + return( -EFAULT ); + + if (QueryDisk.ContainerNumber == -1) + QueryDisk.ContainerNumber = TARGET_LUN_TO_CONTAINER( QueryDisk.Target, QueryDisk.Lun ); + else + if( ( QueryDisk.Bus == -1 ) && ( QueryDisk.Target == -1 ) && ( QueryDisk.Lun == -1 ) ) + { + if( QueryDisk.ContainerNumber > MAXIMUM_NUM_CONTAINERS ) + return( -EINVAL ); + + QueryDisk.Instance = CommonExtensionPtr->OsDep.scsi_host_ptr->host_no; + QueryDisk.Bus = 0; + QueryDisk.Target = CONTAINER_TO_TARGET( QueryDisk.ContainerNumber ); + QueryDisk.Lun = CONTAINER_TO_LUN( QueryDisk.ContainerNumber ); + } + else + return( -EINVAL ); + + QueryDisk.Valid = fsa_dev_ptr->ContainerValid[QueryDisk.ContainerNumber]; + QueryDisk.Locked = fsa_dev_ptr->ContainerLocked[QueryDisk.ContainerNumber]; + QueryDisk.Deleted = fsa_dev_ptr->ContainerDeleted[QueryDisk.ContainerNumber]; + + if( fsa_dev_ptr->ContainerDevNo[QueryDisk.ContainerNumber] == -1 ) + QueryDisk.UnMapped = TRUE; + else + QueryDisk.UnMapped = FALSE; + + get_sd_devname( fsa_dev_ptr->ContainerDevNo[QueryDisk.ContainerNumber], + QueryDisk.diskDeviceName ); + + if( copyout( &QueryDisk, IoctlCmdPtr->arg, sizeof( UNIX_QUERY_DISK ) ) ) + return( -EFAULT ); + + return( 0 ); +} + + +/*------------------------------------------------------------------------------ + get_sd_devname() + *----------------------------------------------------------------------------*/ +static void get_sd_devname( + long disknum, + char * buffer) +/*----------------------------------------------------------------------------*/ +{ + if( disknum < 0 ) + { + sprintf(buffer, "%s", ""); + return; + } + + if( disknum < 26 ) + sprintf(buffer, "sd%c", 'a' + disknum); + else { + unsigned int min1; + unsigned int min2; + /* + * For larger numbers of disks, we need to go to a new + * naming scheme. + */ + min1 = disknum / 26; + min2 = disknum % 26; + sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2); + } +} + + +/*------------------------------------------------------------------------------ + AacHba_ForceDeleteDisk() + + Postconditions: + Return values + 0 = OK + -EFAULT = Bad address + -EINVAL = Bad container number + *----------------------------------------------------------------------------*/ +int AacHba_ForceDeleteDisk( + PVOID AdapterArg, // CommonExtensionPtr + IN PAFA_IOCTL_CMD IoctlCmdPtr ) +/*----------------------------------------------------------------------------*/ +{ + DELETE_DISK DeleteDisk; + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr; + fsadev_t *fsa_dev_ptr; + + CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )AdapterArg; + fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev ); + + if ( copyin( IoctlCmdPtr->arg, &DeleteDisk, sizeof( DELETE_DISK ) ) ) + return( -EFAULT ); + + if ( DeleteDisk.ContainerNumber > MAXIMUM_NUM_CONTAINERS ) + return( -EINVAL ); + + // Mark this container as being deleted. + fsa_dev_ptr->ContainerDeleted[DeleteDisk.ContainerNumber] = TRUE; + + // Mark the container as no longer valid + fsa_dev_ptr->ContainerValid[DeleteDisk.ContainerNumber] = 0; + + return( 0 ); +} + + +/*------------------------------------------------------------------------------ + AacHba_DeleteDisk() + + Postconditions: + Return values + 0 = OK + -EFAULT = Bad address + -EINVAL = Bad container number + -EBUSY = Device locked + *----------------------------------------------------------------------------*/ +int AacHba_DeleteDisk( + PVOID AdapterArg, + IN PAFA_IOCTL_CMD IoctlCmdPtr ) +/*----------------------------------------------------------------------------*/ +{ + DELETE_DISK DeleteDisk; + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr; + fsadev_t *fsa_dev_ptr; + + CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )AdapterArg; + fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev ); + + if( copyin( IoctlCmdPtr->arg, &DeleteDisk, sizeof( DELETE_DISK ) ) ) + return( -EFAULT ); + + if( DeleteDisk.ContainerNumber > MAXIMUM_NUM_CONTAINERS ) + return( -EINVAL ); + + // If the container is locked, it can not be deleted by the API. + if( fsa_dev_ptr->ContainerLocked[DeleteDisk.ContainerNumber] ) + return( -EBUSY ); + else + { + // Mark the container as no longer being valid. + fsa_dev_ptr->ContainerValid[DeleteDisk.ContainerNumber] = 0; + fsa_dev_ptr->ContainerDevNo[DeleteDisk.ContainerNumber] = -1; + return(0); + } +} + + +/*------------------------------------------------------------------------------ + AacHba_OpenAdapter() + *----------------------------------------------------------------------------*/ +AAC_STATUS AacHba_OpenAdapter( + IN PVOID AdapterArg ) +/*----------------------------------------------------------------------------*/ +{ + return( STATUS_SUCCESS ); +} + + +/*------------------------------------------------------------------------------ + AacHba_CloseAdapter() + *----------------------------------------------------------------------------*/ +AAC_STATUS AacHba_CloseAdapter( + IN PVOID AdapterArg ) +/*----------------------------------------------------------------------------*/ +{ + return( STATUS_SUCCESS ); +} + + +/*------------------------------------------------------------------------------ + AacHba_DetachAdapter() + *----------------------------------------------------------------------------*/ +void AacHba_DetachAdapter( + IN PVOID AdapterArg ) +/*----------------------------------------------------------------------------*/ +{ + AacCommDetachAdapter( AdapterArg ); +} + + +/*------------------------------------------------------------------------------ + AacHba_AbortScsiCommand() + *----------------------------------------------------------------------------*/ +void AacHba_AbortScsiCommand( + Scsi_Cmnd *scsi_cmnd_ptr ) +/*----------------------------------------------------------------------------*/ +{ + u_short interrupt_status; + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr; + + CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata ); + interrupt_status = Sa_READ_USHORT( ( PSa_ADAPTER_EXTENSION )( CommonExtensionPtr->MiniPort ), + DoorbellReg_p ); + cmn_err( CE_WARN, "interrupt_status = %d", interrupt_status ); + + if( interrupt_status & DOORBELL_1) { // Adapter -> Host Normal Command Ready + cmn_err( CE_WARN, "DOORBELL_1: Adapter -> Host Normal Command Ready" ); + } + + if( interrupt_status & DOORBELL_2) { // Adapter -> Host Normal Response Ready + cmn_err( CE_WARN, "DOORBELL_2: Adapter -> Host Normal Response Ready" ); + } + + if ( interrupt_status & DOORBELL_3) { // Adapter -> Host Normal Command Not Full + cmn_err( CE_WARN, "DOORBELL_3: Adapter -> Host Normal Command Not Full" ); + } + + if ( interrupt_status & DOORBELL_4) { // Adapter -> Host Normal Response Not Full + cmn_err( CE_WARN, "DOORBELL_4: Adapter -> Host Normal Response Not Full" ); + } + +} + + +/*------------------------------------------------------------------------------ + AacHba_HandleAif() + *----------------------------------------------------------------------------*/ +BOOLEAN AacHba_HandleAif( + IN PVOID AdapterArg, + IN PFIB_CONTEXT FibContext ) +/*----------------------------------------------------------------------------*/ +{ + return( FALSE ); +} + + +/*------------------------------------------------------------------------------ + AacHba_SetSenseData() + Fill in the sense data. + Preconditions: + Postconditions: + *----------------------------------------------------------------------------*/ +void AacHba_SetSenseData( + char * sense_buf, + unchar sense_key, + unchar sense_code, + unchar a_sense_code, + unchar incorrect_length, + unchar bit_pointer, + unsigned field_pointer, + unsigned long residue ) +/*----------------------------------------------------------------------------*/ +{ + sense_buf[0] = 0xF0; // Sense data valid, err code 70h (current error) + sense_buf[1] = 0; // Segment number, always zero + + if( incorrect_length ) + { + sense_buf[2] = sense_key | 0x20; // Set the ILI bit | sense key + sense_buf[3] = BYTE3(residue); + sense_buf[4] = BYTE2(residue); + sense_buf[5] = BYTE1(residue); + sense_buf[6] = BYTE0(residue); + } + else + sense_buf[2] = sense_key; // Sense key + + if( sense_key == SENKEY_ILLEGAL ) + sense_buf[7] = 10; // Additional sense length + else + sense_buf[7] = 6; // Additional sense length + + sense_buf[12] = sense_code; // Additional sense code + sense_buf[13] = a_sense_code; // Additional sense code qualifier + if( sense_key == SENKEY_ILLEGAL ) + { + sense_buf[15] = 0; + + if( sense_code == SENCODE_INVALID_PARAM_FIELD ) + sense_buf[15] = 0x80; // Std sense key specific field + // Illegal parameter is in the parameter block + + if( sense_code == SENCODE_INVALID_CDB_FIELD ) + sense_buf[15] = 0xc0; // Std sense key specific field + // Illegal parameter is in the CDB block + sense_buf[15] |= bit_pointer; + sense_buf[16] = field_pointer >> 8; // MSB + sense_buf[17] = field_pointer; // LSB + } +} + diff -burN linux-2.2.19/drivers/scsi/aacraid/aacid.c linux.aacraid/drivers/scsi/aacraid/aacid.c --- linux-2.2.19/drivers/scsi/aacraid/aacid.c Wed Dec 31 18:00:00 1969 +++ linux.aacraid/drivers/scsi/aacraid/aacid.c Fri Jun 29 13:35:31 2001 @@ -0,0 +1,153 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * aac.c + * + * Abstract: Data structures for controller specific info. + * +--*/ + +static char *ident_aacid = "aacraid_ident aacid.c 1.0.6 2000/10/09 Adaptec, Inc."; + +#include "osheaders.h" + +#include "AacGenericTypes.h" + +#include "aac_unix_defs.h" + +#include "fsatypes.h" +#include "comstruc.h" +#include "fsaport.h" +#include "pcisup.h" + +#include "version.h" + + +/* Function Prototypes */ +void InqStrCopy(char *a, char *b); /* ossup.c */ + +/* Device name used to register and unregister + the device in linit.c */ +char devicestr[]="aac"; + +char *container_types[] = { + "None", + "Volume", + "Mirror", + "Stripe", + "RAID5", + "SSRW", + "SSRO", + "Morph", + "Legacy", + "RAID4", + "RAID10", + "RAID00", + "V-MIRRORS", + "PSEUDO R4", + "RAID50", + "Unknown" +}; + +/* Local Structure to set SCSI inquiry data strings */ +typedef struct _INQSTR { + char vid[8]; /* Vendor ID */ + char pid[16]; /* Product ID */ + char prl[4]; /* Product Revision Level */ +} INQSTR, *INQSTRP; + +FSA_MINIPORT MiniPorts[]; + +/* Function: SetInqDataStr + * + * Arguments: [1] pointer to void [1] int + * + * Purpose: Sets SCSI inquiry data strings for vendor, product + * and revision level. Allows strings to be set in platform dependant + * files instead of in OS dependant driver source. + */ +void +SetInqDataStr ( + int MiniPortIndex, + void *dataPtr, + int tindex) +{ + INQSTRP InqStrPtr; + char *findit; + FSA_MINIPORT *mp; + + mp = &MiniPorts[MiniPortIndex]; + + InqStrPtr = (INQSTRP)(dataPtr); /* cast dataPtr to type INQSTRP */ + + InqStrCopy (mp->Vendor, InqStrPtr->vid); + InqStrCopy (mp->Model, InqStrPtr->pid); /* last six chars reserved for vol type */ + + findit = InqStrPtr->pid; + + for ( ; *findit != ' '; findit++); /* walk till we find a space then incr by 1 */ + findit++; + + if (tindex < (sizeof(container_types)/sizeof(char *))){ + InqStrCopy (container_types[tindex], findit); + } + InqStrCopy ("0001", InqStrPtr->prl); +} + +int +SaInitDevice( + IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension, + IN ULONG AdapterNumber, + IN ULONG PciBus, + IN ULONG PciSlot +); + +int +RxInitDevice( + IN PPCI_MINIPORT_COMMON_EXTENSION CommonExtension, + IN ULONG AdapterNumber, + IN ULONG PciBus, + IN ULONG PciSlot +); + + +/* + * Because of the way Linux names scsi devices, the order in this table has + * become important. Check for on-board Raid first, add-in cards second. + */ + +FSA_MINIPORT MiniPorts[] = { + { 0x1028, 0x0001, 0x1028, 0x0001, "afa", RxInitDevice, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Si */ + { 0x1028, 0x0002, 0x1028, 0x0002, "afa", RxInitDevice, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Di */ + { 0x1028, 0x0003, 0x1028, 0x0003, "afa", RxInitDevice, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Si */ + { 0x1028, 0x0004, 0x1028, 0x00d0, "afa", RxInitDevice, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Si */ + { 0x1028, 0x0002, 0x1028, 0x00d1, "afa", RxInitDevice, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Di */ + { 0x1028, 0x0002, 0x1028, 0x00d9, "afa", RxInitDevice, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Di */ + { 0x1028, 0x000a, 0x1028, 0x0106, "afa", RxInitDevice, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Di */ + { 0x1011, 0x0046, 0x9005, 0x1364, "afa", SaInitDevice, "percraid", "DELL ", "PERCRAID " }, /* Dell PERC2 "Quad Channel */ + { 0x1011, 0x0046, 0x103c, 0x10c2, "hpn", SaInitDevice, "hpnraid", "HP ", "NetRAID-4M " } /* HP NetRAID-4M */ +}; + + +#define NUM_MINIPORTS (sizeof(MiniPorts) / sizeof(FSA_MINIPORT)) + +int NumMiniPorts = NUM_MINIPORTS; + +char DescriptionString[] = "AACxxx Raid Controller" FSA_VERSION_STRING ; diff -burN linux-2.2.19/drivers/scsi/aacraid/commctrl.c linux.aacraid/drivers/scsi/aacraid/commctrl.c --- linux-2.2.19/drivers/scsi/aacraid/commctrl.c Wed Dec 31 18:00:00 1969 +++ linux.aacraid/drivers/scsi/aacraid/commctrl.c Fri Jun 29 13:34:32 2001 @@ -0,0 +1,1098 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * commctrl.c + * + * Abstract: Contains all routines for control of the AFA comm layer + * +--*/ + +static char *ident_commctrl = "aacraid_ident commctrl.c 1.0.7 2000/10/11 Adaptec, Inc."; + +#include "comprocs.h" +#include "osheaders.h" +#include "ostypes.h" + + + + + +typedef BOOLEAN BOOL; +#define inline /* _inline */ + +#include +AAC_STATUS +FsaCtlCheckRevision( + IN PAFA_COMM_ADAPTER Adapter, + IN PAFA_IOCTL_CMD IoctlCmdPtr + ) +/*++ + +Routine Description: + + This routine validates the revision of the caller with the current revision + of the filesystem. + +Arguments: + + Adapter - Supplies which adapter is being processed. + + Irp - Supplies the Irp being processed. + + IrpContext - Supplies the IrpContext. + +Return Value: + + AAC_STATUS + +--*/ + +{ + RevCheck APIRevCheck; + RevCheckResp APIRevCheckResp; + RevComponent APICallingComponent; + ULONG APIBuildNumber; + + if (COPYIN( (caddr_t) IoctlCmdPtr->arg, (caddr_t) &APIRevCheck, sizeof(RevCheck), IoctlCmdPtr->flag )) { + return (EFAULT); + } + + APICallingComponent = APIRevCheck.callingComponent; + APIBuildNumber = APIRevCheck.callingRevision.buildNumber; + + APIRevCheckResp.possiblyCompatible = RevCheckCompatibility( RevMiniportDriver , APICallingComponent, APIBuildNumber ); + + APIRevCheckResp.adapterSWRevision.external.ul = RevGetExternalRev(); + APIRevCheckResp.adapterSWRevision.buildNumber = RevGetBuildNumber(); + + if (COPYOUT( (caddr_t) &APIRevCheckResp, (caddr_t) IoctlCmdPtr->arg, sizeof(RevCheckResp), IoctlCmdPtr->flag )) { + return (EFAULT); + } + + return (0); +} + + +int +AfaCommAdapterDeviceControl( + IN PVOID AdapterArg, + IN PAFA_IOCTL_CMD IoctlCmdPtr + ) +{ + PAFA_COMM_ADAPTER Adapter = (PAFA_COMM_ADAPTER) AdapterArg; + int Status = ENOTTY; +// PIO_STACK_LOCATION IrpSp; + PAFA_CLASS_DRIVER ClassDriver; + + // + // First loop through all of the class drivers to give them a chance to handle + // the Device control first. + // + + ClassDriver = Adapter->ClassDriverList; + + while (ClassDriver) { + + if (ClassDriver->DeviceControl) { + + if (ClassDriver->DeviceControl( ClassDriver->ClassDriverExtension, IoctlCmdPtr, &Status ) ) { + + return (Status); + + } + } + + ClassDriver = ClassDriver->Next; + } + + switch (IoctlCmdPtr->cmd) { + + + case FSACTL_SENDFIB: + + Status = AfaCommCtlSendFib( Adapter, IoctlCmdPtr ); + break; + + case FSACTL_AIF_THREAD: + + Status = AfaCommCtlAifThread( Adapter, IoctlCmdPtr ); + break; + + + case FSACTL_OPEN_GET_ADAPTER_FIB: + + Status = FsaCtlOpenGetAdapterFib( Adapter, IoctlCmdPtr ); + break; + + case FSACTL_GET_NEXT_ADAPTER_FIB: + + Status = FsaCtlGetNextAdapterFib( Adapter, IoctlCmdPtr ); + break; + + case FSACTL_CLOSE_GET_ADAPTER_FIB: + + Status = FsaCtlCloseGetAdapterFib( Adapter, IoctlCmdPtr ); + break; + + case FSACTL_MINIPORT_REV_CHECK: + + Status = FsaCtlCheckRevision( Adapter , IoctlCmdPtr ); + break; + + + default: + + Status = ENOTTY; + break; + + } + + + return (Status); +} + +AAC_STATUS +AfaCommRegisterNewClassDriver( + IN PAFA_COMM_ADAPTER Adapter, + IN PAFA_NEW_CLASS_DRIVER NewClassDriver, + OUT PAFA_NEW_CLASS_DRIVER_RESPONSE NewClassDriverResponse + ) +/*++ + +Routine Description: + + This routine registers a new class driver for the comm layer. + + It will return a pointer to the communication functions for the class driver + to use. + +Arguments: + + Adapter - Supplies which adapter is being processed. + + Irp - Supplies the Irp being processed. + +Return Value: + + STATUS_SUCCESS - Everything OK. + +--*/ +{ + AAC_STATUS Status; + PAFA_CLASS_DRIVER ClassDriver; + + + ClassDriver = (PAFA_CLASS_DRIVER) OsAllocMemory( sizeof(AFA_CLASS_DRIVER), OS_ALLOC_MEM_SLEEP ); + + if (ClassDriver == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + + return Status; + } + + // + // If the class driver has sent in user Vars, then copy them into the global + // area. + // + + if (NewClassDriver->NumUserVars) { + + PFSA_USER_VAR NewUserVars; + + NewUserVars = OsAllocMemory( (FsaCommData.NumUserVars + + NewClassDriver->NumUserVars) * sizeof(FSA_USER_VAR), OS_ALLOC_MEM_SLEEP ); + + // + // First copy the existing into the new area. + // + + RtlCopyMemory( NewUserVars, FsaCommData.UserVars, FsaCommData.NumUserVars * sizeof(FSA_USER_VAR) ); + + // + // Next copy the new vars passed in from class driver. + // + + RtlCopyMemory( (NewUserVars + FsaCommData.NumUserVars), + NewClassDriver->UserVars, + NewClassDriver->NumUserVars * sizeof(FSA_USER_VAR) ); + + // + // Free up the old user vars. + // + + OsFreeMemory( FsaCommData.UserVars, FsaCommData.NumUserVars * sizeof(FSA_USER_VAR) ); + + // + // Point the global to the new area. + // + + FsaCommData.UserVars = NewUserVars; + + // + // Update the total count. + // + + FsaCommData.NumUserVars += NewClassDriver->NumUserVars; + + } + + ClassDriver->OpenAdapter = NewClassDriver->OpenAdapter; + ClassDriver->CloseAdapter = NewClassDriver->CloseAdapter; + ClassDriver->DeviceControl = NewClassDriver->DeviceControl; + ClassDriver->HandleAif = NewClassDriver->HandleAif; + ClassDriver->ClassDriverExtension = NewClassDriver->ClassDriverExtension; + + ClassDriver->Next = Adapter->ClassDriverList; + Adapter->ClassDriverList = ClassDriver; + + // + // Now return the information needed by the class driver to communicate to us. + // + + NewClassDriverResponse->CommFuncs = &Adapter->CommFuncs; + NewClassDriverResponse->CommPortExtension = Adapter; + NewClassDriverResponse->MiniPortExtension = Adapter->AdapterExtension; + NewClassDriverResponse->SpinLockCookie = Adapter->SpinLockCookie; + NewClassDriverResponse->Dip = Adapter->Dip; + + return (STATUS_SUCCESS); + + +} + +int +AfaCommCtlSendFib( + IN PAFA_COMM_ADAPTER Adapter, + IN PAFA_IOCTL_CMD IoctlCmdPtr +) +/*++ + +Routine Description: + + This routine sends a fib to the adapter on behalf of a user level + program. + +Arguments: + + Adapter - Supplies which adapter is being processed. + + IoctlCmdPtr - Pointer to the arguments to the IOCTL call + +Return Value: + + STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer. + + STATUS_INSUFFICIENT_RESOURCES - If a memory allocation failed. + + STATUS_SUCCESS - Everything OK. + +--*/ +{ + PFIB KFib; +// PMDL DmaMdl = NULL; + PCOMM_FIB_CONTEXT FibContext; + PSGMAP_CONTEXT SgMapContext; + SGMAP_CONTEXT _SgMapContext; + QUEUE_TYPES WhichQueue; + PVOID UsersAddress; + AAC_STATUS Status; + + FibContext = AllocateFib( Adapter ); + + KFib = FibContext->Fib; + + // + // First copy in the header so that we can check the size field. + // + + if (COPYIN( (caddr_t) IoctlCmdPtr->arg, (caddr_t) KFib, sizeof(FIB_HEADER), IoctlCmdPtr->flag )) { + FreeFib( FibContext ); + Status = EFAULT; + return (Status); + } + + // + // Since we copy based on the fib header size, make sure that we + // will not overrun the buffer when we copy the memory. Return + // an error if we would. + // + + if (KFib->Header.Size > sizeof(FIB) - sizeof(FIB_HEADER)) { + FreeFib( FibContext ); + Status = EINVAL; + return Status; + + } + + if (COPYIN( (caddr_t) IoctlCmdPtr->arg, (caddr_t) KFib, KFib->Header.Size + sizeof(FIB_HEADER), IoctlCmdPtr->flag )) { + FreeFib( FibContext ); + Status = EFAULT; + return (Status); + } + + WhichQueue = AdapNormCmdQueue; + + + if (KFib->Header.Command == TakeABreakPt) { + + InterruptAdapter(Adapter); + + // + // Since we didn't really send a fib, zero out the state to allow + // cleanup code not to assert. + // + + KFib->Header.XferState = 0; + + + } else { + + if (SendFib(KFib->Header.Command, FibContext, KFib->Header.Size , FsaNormal, + TRUE, NULL, TRUE, NULL, NULL) != FSA_SUCCESS) { + FsaCommPrint("User SendFib failed!.\n"); + + + FreeFib( FibContext ); + return (ENXIO); + } + + if (CompleteFib(FibContext) != FSA_SUCCESS) { + FsaCommPrint("User Complete FIB failed.\n"); + + FreeFib( FibContext ); + return (ENXIO); + } + + + } + + + // + // Make sure that the size returned by the adapter (which includes + // the header) is less than or equal to the size of a fib, so we + // don't corrupt application data. Then copy that size to the user + // buffer. (Don't try to add the header information again, since it + // was already included by the adapter.) + // + ASSERT(KFib->Header.Size <= sizeof(FIB)); + + if (COPYOUT( (caddr_t) KFib, (caddr_t) IoctlCmdPtr->arg, KFib->Header.Size, IoctlCmdPtr->flag )) { + FreeFib( FibContext ); + Status = EFAULT; + return (Status); + } + + FreeFib( FibContext ); + + return (0); + +} + +int +AfaCommCtlAifThread( + IN PAFA_COMM_ADAPTER Adapter, + IN PAFA_IOCTL_CMD IoctlCmdPtr +) +/*++ + +Routine Description: + + This routine will act as the AIF thread for this adapter. + +Arguments: + + Adapter - Supplies which adapter is being processed. + + IoctlCmdPtr - Pointer to the arguments to the IOCTL call + +Return Value: + + STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer. + + STATUS_INSUFFICIENT_RESOURCES - If a memory allocation failed. + + STATUS_SUCCESS - Everything OK. + +--*/ +{ + return (NormCommandThread(Adapter)); +} + + + +#ifdef GATHER_FIB_TIMES +AAC_STATUS +AfaCommGetFibTimes( + IN PAFA_COMM_ADAPTER Adapter, + IN PIRP Irp + ) +/*++ + +Routine Description: + + This routine returns the gathered fibtimes to the user. + +Arguments: + + Adapter - Supplies which adapter is being processed. + + Irp - Supplies the Irp being processed. + +Return Value: + + STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer. + + STATUS_INSUFFICIENT_RESOURCES - If a memory allocation failed. + + STATUS_SUCCESS - Everything OK. + +--*/ +{ + PALL_FIB_TIMES AllFibTimes; + PLARGE_INTEGER FreqPtr; + PIO_STACK_LOCATION IrpSp; + + // + // Get a pointer to the current Irp stack location + // + + IrpSp = IoGetCurrentIrpStackLocation( Irp ); + + FreqPtr = (PLARGE_INTEGER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer; + + *FreqPtr = Adapter->FibTimesFrequency; + + AllFibTimes = (PALL_FIB_TIMES)((PUCHAR)FreqPtr + sizeof(LARGE_INTEGER)); + + RtlCopyMemory(AllFibTimes, Adapter->FibTimes, sizeof(ALL_FIB_TIMES)); + + Irp->IoStatus.Information = 0; + + return (STATUS_SUCCESS); + +} + +AAC_STATUS +AfaCommZeroFibTimes( + IN PAFA_COMM_ADAPTER Adapter, + IN PIRP Irp + ) +/*++ + +Routine Description: + + This routine zero's the FibTimes structure within the adapter structure. + +Arguments: + + Adapter - Supplies which adapter is being processed. + + Irp - Supplies the Irp being processed. + +Return Value: + + STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer. + + STATUS_INSUFFICIENT_RESOURCES - If a memory allocation failed. + + STATUS_SUCCESS - Everything OK. + +--*/ +{ + PFIB_TIMES FibTimesPtr; + int i; + PIO_STACK_LOCATION IrpSp; + + // + // Get a pointer to the current Irp stack location + // + + IrpSp = IoGetCurrentIrpStackLocation( Irp ); + + // + // Initialize the Fib timing data structures + // + RtlZeroMemory(Adapter->FibTimes, sizeof(ALL_FIB_TIMES)); + + for (i = 0; i < MAX_FSACOMMAND_NUM; i++) { + + FibTimesPtr = &Adapter->FibTimes->FileSys[i]; + + FibTimesPtr->Minimum.LowPart = 0xffffffff; + FibTimesPtr->Minimum.HighPart = 0x7fffffff; + FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff; + FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff; + } + for (i = 0; i < MAX_RW_FIB_TIMES; i++) { + + FibTimesPtr = &Adapter->FibTimes->Read[i]; + + FibTimesPtr->Minimum.LowPart = 0xffffffff; + FibTimesPtr->Minimum.HighPart = 0x7fffffff; + FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff; + FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff; + } + for (i = 0; i < MAX_RW_FIB_TIMES; i++) { + + FibTimesPtr = &Adapter->FibTimes->Write[i]; + + FibTimesPtr->Minimum.LowPart = 0xffffffff; + FibTimesPtr->Minimum.HighPart = 0x7fffffff; + FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff; + FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff; + } + + FibTimesPtr = &Adapter->FibTimes->Other; + + FibTimesPtr->Minimum.LowPart = 0xffffffff; + FibTimesPtr->Minimum.HighPart = 0x7fffffff; + FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff; + FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff; + + Irp->IoStatus.Information = 0; + + return (STATUS_SUCCESS); + +} +#endif // GATHER_FIB_TIMES + +#ifndef unix_aif +int +FsaCtlOpenGetAdapterFib( + IN PAFA_COMM_ADAPTER Adapter, + IN PAFA_IOCTL_CMD IoctlCmdPtr + ) +/*++ + +Routine Description: + + This routine will get the next Fib, if available, from the AdapterFibContext + passed in from the user. + +Arguments: + + Adapter - Supplies which adapter is being processed. + + Irp - Supplies the Irp being processed. + +Return Value: + + STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer. + + STATUS_INSUFFICIENT_RESOURCES - If a memory allocation failed. + + STATUS_SUCCESS - Everything OK. + +--*/ +{ + PGET_ADAPTER_FIB_CONTEXT AdapterFibContext; +// HANDLE Event; +// PKEVENT eventObject = (PKEVENT) NULL; + int Status; + + // + // The context must be allocated from NonPagedPool because we need to use MmIsAddressValid. + // + + AdapterFibContext = OsAllocMemory(sizeof(GET_ADAPTER_FIB_CONTEXT), OS_ALLOC_MEM_SLEEP); + + if (AdapterFibContext == NULL) { + + Status = ENOMEM; + + } else { + + AdapterFibContext->NodeTypeCode = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT; + AdapterFibContext->NodeByteSize = sizeof(GET_ADAPTER_FIB_CONTEXT); + + + // + // Initialize the conditional variable use to wait for the next AIF. + // + + OsCv_init( &AdapterFibContext->UserEvent); + + // + // Set WaitingForFib to FALSE to indicate we are not in a WaitForSingleObject + // + + AdapterFibContext->WaitingForFib = FALSE; + + // + // Initialize the FibList and set the count of fibs on the list to 0. + // + + AdapterFibContext->FibCount = 0; + InitializeListHead(&AdapterFibContext->FibList); + + // + // Overload FileObject with a time stamp. + // + AdapterFibContext->FileObject = (void *)OsGetSeconds(); + + // + // Now add this context onto the adapter's AdapterFibContext list. + // + + OsCvLockAcquire(Adapter->AdapterFibMutex); + + InsertTailList(&Adapter->AdapterFibContextList, &AdapterFibContext->NextContext); + + OsCvLockRelease(Adapter->AdapterFibMutex); + + if (COPYOUT( &AdapterFibContext, (caddr_t) IoctlCmdPtr->arg, sizeof(PGET_ADAPTER_FIB_CONTEXT), + IoctlCmdPtr->flag )) { + + Status = EFAULT; + + } else { + + Status = 0; + + } + + } + + return (Status); +} + +int +FsaCtlGetNextAdapterFib( + IN PAFA_COMM_ADAPTER Adapter, + IN PAFA_IOCTL_CMD IoctlCmdPtr + ) +/*++ + +Routine Description: + + This routine will get the next Fib, if available, from the AdapterFibContext + passed in from the user. + +Arguments: + + Adapter - Supplies which adapter is being processed. + + Irp - Supplies the Irp being processed. + +Return Value: + + STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer. + + STATUS_NO_MORE_ENTRIES - There are no more Fibs for this AdapterFibContext. + + STATUS_SUCCESS - Everything OK. + +--*/ +{ + GET_ADAPTER_FIB_IOCTL AdapterFibIoctl; + PGET_ADAPTER_FIB_CONTEXT AdapterFibContext, aifcp; + PFIB Fib; + int Status; + PLIST_ENTRY Entry; + int found; + + if (COPYIN( (caddr_t) IoctlCmdPtr->arg, (caddr_t) &AdapterFibIoctl, + sizeof(GET_ADAPTER_FIB_IOCTL), IoctlCmdPtr->flag )) { + return (EFAULT); + } + + // + // Extract the AdapterFibContext from the Input parameters. + // + + AdapterFibContext = (PGET_ADAPTER_FIB_CONTEXT) AdapterFibIoctl.AdapterFibContext; + + // + // Verify that the HANDLE passed in was a valid AdapterFibContext + // + // Search the list of AdapterFibContext addresses on the adapter to be sure + // this is a valid address + + found = 0; + Entry = Adapter->AdapterFibContextList.Flink; + + while ( Entry != &Adapter->AdapterFibContextList ) { + aifcp = CONTAINING_RECORD ( Entry, GET_ADAPTER_FIB_CONTEXT, NextContext ); + if ( AdapterFibContext == aifcp ) { // We found a winner + found = 1; + break; + } + Entry = Entry->Flink; + } + + if ( found == 0 ) { + return ( EINVAL );; + } + + if ( (AdapterFibContext->NodeTypeCode != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || + (AdapterFibContext->NodeByteSize != sizeof(GET_ADAPTER_FIB_CONTEXT)) ) { + + return ( EINVAL ); + + } + + Status = STATUS_SUCCESS; + + OsCvLockAcquire(Adapter->AdapterFibMutex); + + // + // If there are no fibs to send back, then either wait or return EAGAIN + // +return_fib: + + if (!IsListEmpty(&AdapterFibContext->FibList)) { + + PLIST_ENTRY Entry; + + // + // Pull the next fib from the FibList + // + Entry = RemoveHeadList(&AdapterFibContext->FibList); + + Fib = CONTAINING_RECORD( Entry, FIB, Header.FibLinks ); + + AdapterFibContext->FibCount--; + + if (COPYOUT( Fib, AdapterFibIoctl.AifFib, sizeof(FIB), IoctlCmdPtr->flag )) { + + OsCvLockRelease( Adapter->AdapterFibMutex ); + OsFreeMemory( Fib, sizeof(Fib) ); + return (EFAULT); + + } + + // + // Free the space occupied by this copy of the fib. + // + + OsFreeMemory(Fib, sizeof(FIB)); + + Status = 0; + + // + // Overload FileObject with a time stamp + // + AdapterFibContext->FileObject = ( void * )OsGetSeconds(); + + } else { + + if (AdapterFibIoctl.Wait) { + + if (OsCv_wait_sig( &AdapterFibContext->UserEvent, Adapter->AdapterFibMutex ) == 0) { + + Status = EINTR; + + } else { + + goto return_fib; + + } + } else { + + Status = EAGAIN; + + } + + } + OsCvLockRelease( Adapter->AdapterFibMutex ); + + return (Status); +} + +int +FsaCtlCloseGetAdapterFib( + IN PAFA_COMM_ADAPTER Adapter, + IN PAFA_IOCTL_CMD IoctlCmdPtr + ) +/*++ + +Routine Description: + + This routine will close down the AdapterFibContext passed in from the user. + +Arguments: + + Adapter - Supplies which adapter is being processed. + + Irp - Supplies the Irp being processed. + +Return Value: + + STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer. + + STATUS_SUCCESS - Everything OK. + +--*/ +{ + PGET_ADAPTER_FIB_CONTEXT AdapterFibContext, aifcp; + AAC_STATUS Status; + + PLIST_ENTRY Entry; + int found; + + // + // Extract the AdapterFibContext from the Input parameters + // + + AdapterFibContext = (PGET_ADAPTER_FIB_CONTEXT) IoctlCmdPtr->arg; + + if (AdapterFibContext == 0) { + cmn_err(CE_WARN, "FsaCtlCloseGetAdapterFib: AdapterFibContext is NULL"); + return(EINVAL); + } + + // + // Verify that the HANDLE passed in was a valid AdapterFibContext + // + // Search the list of AdapterFibContext addresses on the adapter to be sure + // this is a valid address + + found = 0; + Entry = Adapter->AdapterFibContextList.Flink; + + while ( Entry != &Adapter->AdapterFibContextList ) { + aifcp = CONTAINING_RECORD ( Entry, GET_ADAPTER_FIB_CONTEXT, NextContext ); + if ( AdapterFibContext == aifcp ) { // We found a winner + found = 1; + break; + } + Entry = Entry->Flink; + } + + if ( found == 0 ) { + return ( 0 ); // Already Gone + } + + if ( (AdapterFibContext->NodeTypeCode != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || + (AdapterFibContext->NodeByteSize != sizeof(GET_ADAPTER_FIB_CONTEXT)) ) { + + return (EINVAL); + + } + + OsCvLockAcquire(Adapter->AdapterFibMutex); + + Status = FsaCloseAdapterFibContext(Adapter, AdapterFibContext); + + OsCvLockRelease(Adapter->AdapterFibMutex); + + return (Status); +} + +int +FsaCloseAdapterFibContext( + IN PAFA_COMM_ADAPTER Adapter, + IN PGET_ADAPTER_FIB_CONTEXT AdapterFibContext + ) +{ + int Status; + PFIB Fib; + + // + // First free any FIBs that have not been consumed yet. + // + + while (!IsListEmpty(&AdapterFibContext->FibList)) { + + PLIST_ENTRY Entry; + + // + // Pull the next fib from the FibList + // + + Entry = RemoveHeadList(&AdapterFibContext->FibList); + + Fib = CONTAINING_RECORD( Entry, FIB, Header.FibLinks ); + + AdapterFibContext->FibCount--; + + // + // Free the space occupied by this copy of the fib. + // + + OsFreeMemory(Fib, sizeof(FIB)); + } + + // + // Remove the Context from the AdapterFibContext List + // + + RemoveEntryList(&AdapterFibContext->NextContext); + + OsCv_destroy( &AdapterFibContext->UserEvent ); + + // + // Invalidate context + // + + AdapterFibContext->NodeTypeCode = 0; + + // + // Free the space occupied by the Context + // + + OsFreeMemory(AdapterFibContext, sizeof(GET_ADAPTER_FIB_CONTEXT)); + + Status = STATUS_SUCCESS; + + return Status; +} +#endif + +AAC_STATUS +AfaCommOpenAdapter( + IN PVOID Arg + ) +/*++ + +Routine Description: + + The routine will get called by the miniport each time a user issues a CreateFile on the DeviceObject + for the adapter. + + The main purpose of this routine is to set up any data structures that may be needed + to handle any requests made on this DeviceObject. + +Arguments: + + Adapter - Pointer to which adapter miniport was opened. + + +Return Value: + + STATUS_SUCCESS + +--*/ + +{ + PAFA_COMM_ADAPTER Adapter = (PAFA_COMM_ADAPTER) Arg; + AAC_STATUS Status = STATUS_SUCCESS; + PAFA_CLASS_DRIVER ClassDriver; + + ClassDriver = Adapter->ClassDriverList; + + while (ClassDriver) { + + if (ClassDriver->OpenAdapter) { + + Status = ClassDriver->OpenAdapter( ClassDriver->ClassDriverExtension ); + + if (Status != STATUS_SUCCESS) + break; + } + + ClassDriver = ClassDriver->Next; + } + + return ( Status ); +} + +AAC_STATUS +AfaCommCloseAdapter( + IN PVOID Arg + ) +/*++ + +Routine Description: + + This routine will get called by the miniport each time a user issues a CloseHandle on the DeviceObject + for the adapter. + + The main purpose of this routine is to cleanup any data structures that have been set up + while this FileObject has been opened. + + This routine loops through all of the AdapterFibContext structures to determine if any need + to be deleted for this FileObject. + +Arguments: + + Adapter - Pointer to adapter miniport + + Irp - Pointer to Irp that caused this close + +Return Value: + + Status value returned from File system driver AdapterClose + +--*/ +{ + PAFA_COMM_ADAPTER Adapter = (PAFA_COMM_ADAPTER) Arg; + PLIST_ENTRY Entry, NextEntry; + PGET_ADAPTER_FIB_CONTEXT AdapterFibContext; + AAC_STATUS Status = STATUS_SUCCESS; + PAFA_CLASS_DRIVER ClassDriver; + + OsCvLockAcquire(Adapter->AdapterFibMutex); + + Entry = Adapter->AdapterFibContextList.Flink; + + // + // Loop through all of the AdapterFibContext, looking for any that + // were created with the FileObject that is being closed. + // + while (Entry != &Adapter->AdapterFibContextList) { + + // + // Extract the AdapterFibContext + // + AdapterFibContext = CONTAINING_RECORD( Entry, GET_ADAPTER_FIB_CONTEXT, NextContext ); + + // + // Save the next entry because CloseAdapterFibContext will delete the AdapterFibContext + // + NextEntry = Entry->Flink; + + Entry = NextEntry; + + } + +#ifdef unix_config_file + // + // If this FileObject had the adapter open for configuration, then release it. + // + if ( Adapter->AdapterConfigFileObject == IrpSp->FileObject ) { + + Adapter->AdapterConfigFileObject = NULL; + + } +#endif + + OsCvLockRelease(Adapter->AdapterFibMutex); + + ClassDriver = Adapter->ClassDriverList; + + while (ClassDriver) { + + if (ClassDriver->CloseAdapter) { + + Status = ClassDriver->CloseAdapter( ClassDriver->ClassDriverExtension ); + + if (Status != STATUS_SUCCESS) + break; + } + + ClassDriver = ClassDriver->Next; + } + + return ( Status ); + +} + diff -burN linux-2.2.19/drivers/scsi/aacraid/comminit.c linux.aacraid/drivers/scsi/aacraid/comminit.c --- linux-2.2.19/drivers/scsi/aacraid/comminit.c Wed Dec 31 18:00:00 1969 +++ linux.aacraid/drivers/scsi/aacraid/comminit.c Fri Jun 29 13:34:32 2001 @@ -0,0 +1,1266 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * comminit.c + * + * Abstract: This supports the initialization of the host adapter commuication interface. + * This is a platform dependent module for the pci cyclone board. + * + --*/ + +static char *ident_comminit = "aacraid_ident comminit.c 1.0.6 2000/10/09 Adaptec, Inc."; + +#include "comprocs.h" + +#define BugCheckFileId (FSAFS_BUG_CHECK_COMMINIT) + +VOID +AfaCommBugcheckHandler( + IN PVOID Buffer, + IN ULONG Length + ); + +VOID +ThrottlePeriodEndDpcRtn( + IN PKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2); + +FSA_COMM_DATA FsaCommData; + +AAC_STATUS +HardInterruptModeration1Changed( + IN PVOID AdapterContext, + IN ULONG NewValue + ) +{ + PAFA_COMM_ADAPTER Adapter = AdapterContext; + + // + // If we are using interrupt moderation, then disable the interrupt + // until we need to use it. + // + if (FsaCommData.HardInterruptModeration1) + DisableInterrupt( Adapter, AdapNormCmdNotFull, FALSE ); + else + EnableInterrupt( Adapter, AdapNormCmdNotFull, FALSE ); + + return (STATUS_SUCCESS); +} + +AAC_STATUS +FsaFibTimeoutChanged( + IN PVOID AdapterContext, + IN ULONG NewValue + ) +{ + // + // scale the new timeout from seconds to 100 nsec units + // +// FsaCommData.AdapterTimeout = RtlConvertLongToLargeInteger(-10*1000*1000*NewValue); + + return (STATUS_SUCCESS); +} + +#ifdef GATHER_FIB_TIMES +extern int GatherFibTimes; +#endif + +FSA_USER_VAR FsaCommUserVars[] = { +#ifdef FIB_CHECKSUMS + { "do_fib_checksums", (PULONG)&FsaCommData.do_fib_checksums, NULL }, +#endif +#ifdef GATHER_FIB_TIMES + { "GatherFibTimes", (PULONG)&GatherFibTimes, NULL }, +#endif + { "EnableAdapterTimeouts", (PULONG)&FsaCommData.EnableAdapterTimeouts, NULL}, + { "EnableInterruptModeration", (PULONG)&FsaCommData.EnableInterruptModeration, NULL }, + { "FsaDataFibsSent", (PULONG) &FsaCommData.FibsSent, NULL }, + { "FsaDataFibRecved", (PULONG) &FsaCommData.FibRecved, NULL }, + { "HardInterruptModeration", (PULONG)&FsaCommData.HardInterruptModeration, NULL}, + { "HardInterruptModeration1", (PULONG)&FsaCommData.HardInterruptModeration1, HardInterruptModeration1Changed}, + { "EnableFibTimeoutBreak", (PULONG)&FsaCommData.EnableFibTimeoutBreak, NULL}, + { "PeakFibsConsumed", (PULONG)&FsaCommData.PeakFibsConsumed, NULL }, + { "ZeroFibsConsumed", (PULONG)&FsaCommData.ZeroFibsConsumed, NULL }, + { "FibTimeoutSeconds", (PULONG) &FsaCommData.FibTimeoutSeconds, FsaFibTimeoutChanged }, +}; + +#define NUM_COMM_USER_VARS (sizeof(FsaCommUserVars) / sizeof(FSA_USER_VAR) ) + + +AAC_STATUS +AacCommDriverEntry( + ) + +/*++ + +Routine Description: + + This is the initialization routine for the FileArray Comm layer device driver. + +Arguments: + + DriverObject - Pointer to driver object created by the system. + +Return Value: + + AAC_STATUS - The function value is the final status from the initialization + operation. + +--*/ + +{ + AAC_STATUS Status; + PVOID BugCheckBuffer; + + RtlZeroMemory( &FsaCommData, sizeof(FSA_COMM_DATA) ); + + + // + // Load the global timeout value for the adapter timeout + // Also init the global that enables or disables adapter timeouts + // + +// FsaCommData.AdapterTimeout = RtlConvertLongToLargeInteger(-10*1000*1000*180); + + FsaCommData.FibTimeoutSeconds = 180; + + FsaCommData.EnableAdapterTimeouts = TRUE; + +// FsaCommData.QueueFreeTimeout = RtlConvertLongToLargeInteger(QUEUE_ENTRY_FREE_TIMEOUT); + +#ifdef unix_fib_timeout + FsaCommData.FibTimeoutIncrement = (180 * 1000 * 1000 * 10) / KeQueryTimeIncrement(); +#endif + + FsaCommData.EnableInterruptModeration = FALSE; + + // + // Preload UserVars with all variables from the comm layer. The class layers will + // include theirs when they register. + // + + FsaCommData.UserVars = OsAllocMemory(NUM_COMM_USER_VARS * sizeof(FSA_USER_VAR), OS_ALLOC_MEM_SLEEP ); + FsaCommData.NumUserVars = NUM_COMM_USER_VARS; + + RtlCopyMemory( FsaCommData.UserVars, &FsaCommUserVars, NUM_COMM_USER_VARS * sizeof(FSA_USER_VAR) ); + + +#ifdef AACDISK + // + // Call the disk driver to initialize itself. + // + + AacDiskDriverEntry(); + +#endif + + + + return (STATUS_SUCCESS); +} + + +VOID +DetachNTQueue( + IN PAFA_COMM_ADAPTER Adapter, + IN OUT PCOMM_QUE Queue, + IN QUEUE_TYPES WhichQueue + ) +/*++ + +Routine Description: + + This routine will release all of the resources used by a given queue. + +Arguments: + + Adapter - Which adapter the queue belongs to + Queue - Pointer to the queue itself + WhichQueue - Identifies which of the host queues this is. + +Return Value: + + NONE. + +--*/ +{ + switch (WhichQueue) { + + case HostNormCmdQueue: + + Os_remove_softintr( Queue->ConsumerRoutine ); + OsSpinLockDestroy( Queue->QueueLock ); + OsCv_destroy( &Queue->CommandReady ); + + break; + + case HostHighCmdQueue: + + Os_remove_softintr( Queue->ConsumerRoutine ); + OsSpinLockDestroy( Queue->QueueLock ); + OsCv_destroy( &Queue->CommandReady ); + + break; + + case HostNormRespQueue: + + Os_remove_softintr( Queue->ConsumerRoutine ); + OsSpinLockDestroy( Queue->QueueLock ); + break; + + case HostHighRespQueue: + + Os_remove_softintr( Queue->ConsumerRoutine ); + OsSpinLockDestroy( Queue->QueueLock ); + break; + + case AdapNormCmdQueue: + case AdapHighCmdQueue: + case AdapNormRespQueue: + case AdapHighRespQueue: + OsCv_destroy( &Queue->QueueFull ); + break; + } +} + +VOID +InitializeNTQueue( + IN PAFA_COMM_ADAPTER Adapter, + IN OUT PCOMM_QUE Queue, + IN QUEUE_TYPES WhichQueue + ) +/*++ + +Routine Description: + + Will initialize all entries in the queue that is NT specific. + +Arguments: + +Return Value: + + Nothing there is nothing to allocate so nothing should fail + +--*/ +{ + + Queue->NumOutstandingIos = 0; + + // + // Store a pointer to the adapter structure. + // + + Queue->Adapter = Adapter; + + InitializeListHead( &Queue->OutstandingIoQueue ); + + switch (WhichQueue) { + + case HostNormCmdQueue: + + OsCv_init( &Queue->CommandReady); + OsSpinLockInit( Queue->QueueLock, Adapter->SpinLockCookie); + if (ddi_add_softintr( Adapter->Dip, DDI_SOFTINT_HIGH, &Queue->ConsumerRoutine, NULL, + NULL, (PUNIX_INTR_HANDLER)HostCommandNormDpc, + (caddr_t)Queue ) != DDI_SUCCESS) { + + cmn_err(CE_CONT, "OS_addr_intr failed\n"); + } + + InitializeListHead(&Queue->CommandQueue); + + break; + + case HostHighCmdQueue: + + OsCv_init( &Queue->CommandReady); + OsSpinLockInit( Queue->QueueLock, Adapter->SpinLockCookie); + if (ddi_add_softintr( Adapter->Dip, DDI_SOFTINT_HIGH, &Queue->ConsumerRoutine, NULL, + NULL, (PUNIX_INTR_HANDLER)HostCommandHighDpc, + (caddr_t) Queue ) != DDI_SUCCESS) { + + cmn_err(CE_CONT, "OS_addr_intr failed\n"); + } + + InitializeListHead(&Queue->CommandQueue); + break; + + case HostNormRespQueue: + + OsSpinLockInit( Queue->QueueLock, Adapter->SpinLockCookie); + if (ddi_add_softintr( Adapter->Dip, DDI_SOFTINT_HIGH, &Queue->ConsumerRoutine, NULL, + NULL, (PUNIX_INTR_HANDLER)HostResponseNormalDpc, + (caddr_t) Queue ) != DDI_SUCCESS) { + + cmn_err(CE_CONT, "OS_addr_intr failed\n"); + } + break; + + case HostHighRespQueue: + + + OsSpinLockInit( Queue->QueueLock, Adapter->SpinLockCookie); + if (ddi_add_softintr( Adapter->Dip, DDI_SOFTINT_HIGH, &Queue->ConsumerRoutine, NULL, + NULL, (PUNIX_INTR_HANDLER)HostResponseHighDpc, + (caddr_t) Queue ) != DDI_SUCCESS) { + + cmn_err(CE_CONT, "OS_addr_intr failed\n"); + } + break; + + case AdapNormCmdQueue: + case AdapHighCmdQueue: + case AdapNormRespQueue: + case AdapHighRespQueue: + + OsCv_init( &Queue->QueueFull); + break; + } +} + +BOOLEAN +StartFsaCommandThreads(PAFA_COMM_ADAPTER Adapter) +/*++ + +Routine Description: + + Create and start the command receiver threads. + +Arguments: + + +Return Value: + + Nothing + +--*/ + +{ + return(TRUE); +} + +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, &