From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ntos/miniport/mylex/dac960/d960api.h | 56 + private/ntos/miniport/mylex/dac960/dac960nt.c | 4152 ++++++++++++++++++++++++ private/ntos/miniport/mylex/dac960/dac960nt.h | 428 +++ private/ntos/miniport/mylex/dac960/dac960nt.rc | 38 + private/ntos/miniport/mylex/dac960/dacioctl.c | 525 +++ private/ntos/miniport/mylex/dac960/dmc960nt.h | 87 + private/ntos/miniport/mylex/dac960/makefile | 6 + private/ntos/miniport/mylex/dac960/raidapi.h | 277 ++ private/ntos/miniport/mylex/dac960/raiddefs.h | 34 + private/ntos/miniport/mylex/dac960/sources | 13 + 10 files changed, 5616 insertions(+) create mode 100644 private/ntos/miniport/mylex/dac960/d960api.h create mode 100644 private/ntos/miniport/mylex/dac960/dac960nt.c create mode 100644 private/ntos/miniport/mylex/dac960/dac960nt.h create mode 100644 private/ntos/miniport/mylex/dac960/dac960nt.rc create mode 100644 private/ntos/miniport/mylex/dac960/dacioctl.c create mode 100644 private/ntos/miniport/mylex/dac960/dmc960nt.h create mode 100644 private/ntos/miniport/mylex/dac960/makefile create mode 100644 private/ntos/miniport/mylex/dac960/raidapi.h create mode 100644 private/ntos/miniport/mylex/dac960/raiddefs.h create mode 100644 private/ntos/miniport/mylex/dac960/sources (limited to 'private/ntos/miniport/mylex/dac960') diff --git a/private/ntos/miniport/mylex/dac960/d960api.h b/private/ntos/miniport/mylex/dac960/d960api.h new file mode 100644 index 000000000..a76fdf94b --- /dev/null +++ b/private/ntos/miniport/mylex/dac960/d960api.h @@ -0,0 +1,56 @@ +#include "ntddscsi.h" +#include "raidapi.h" + +// +// Function prototype declarations +// + +BOOLEAN +SubmitRequest( + IN PDEVICE_EXTENSION DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb +); + +BOOLEAN +SubmitCdbDirect( + IN PDEVICE_EXTENSION DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb +); + +BOOLEAN +SendIoctlDcmdRequest( + IN PDEVICE_EXTENSION DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb +); + +BOOLEAN +SendIoctlCdbDirect( + IN PDEVICE_EXTENSION DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb +); + +VOID +SetupAdapterInfo( + IN PDEVICE_EXTENSION DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb +); + +VOID +SetupDriverVersionInfo( + IN PDEVICE_EXTENSION DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb +); + +#define DRIVER_REVISION 0x0305 +#define DRIVER_BUILD_DATE 0x00052495 + +typedef struct _IOCTL_REQ_HEADER { + + SRB_IO_CONTROL SrbIoctl; + UCHAR Unused1[2]; + USHORT DriverErrorCode; + USHORT CompletionCode; + UCHAR Unused2[10]; + HBA_GENERIC_MBOX GenMailBox; + +} IOCTL_REQ_HEADER, *PIOCTL_REQ_HEADER; diff --git a/private/ntos/miniport/mylex/dac960/dac960nt.c b/private/ntos/miniport/mylex/dac960/dac960nt.c new file mode 100644 index 000000000..ce3b740ea --- /dev/null +++ b/private/ntos/miniport/mylex/dac960/dac960nt.c @@ -0,0 +1,4152 @@ +/*++ + +Copyright (c) 1994 Microsoft Corporation + +Module Name: + + Dac960Nt.c + +Abstract: + + This is the device driver for the Mylex 960 family of disk array controllers. + +Author: + + Mike Glass (mglass) + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#include "miniport.h" +#include "Dmc960Nt.h" +#include "Dac960Nt.h" +#include "D960api.h" + +// +// Function declarations +// + +BOOLEAN +Dac960EisaPciSendInitTimeRequest( + IN PDEVICE_EXTENSION DeviceExtension, + IN ULONG TimeOutValue +) + +/*++ + +Routine Description: + + Send Request to DAC960-EISA/PCI Controllers and poll for command + completion + +Assumptions: + Controller Interrupts are turned off + Supports Dac960 Type 5 Commands only + +Arguments: + + DeviceExtension - Adapter state information. + TimeoutValue - TimeOut value (0xFFFFFFFF - Polled Mode) + +Return Value: + + TRUE if commands complete successfully. + +--*/ + +{ + ULONG i; + BOOLEAN completionStatus = TRUE; + + // + // Claim submission semaphore. + // + + if (ScsiPortReadPortUchar(DeviceExtension->LocalDoorBell) & DAC960_LOCAL_DOORBELL_SUBMIT_BUSY) + { + // + // Clear any bits set in system doorbell and tell controller + // that the mailbox is free. + // + + ScsiPortWritePortUchar(DeviceExtension->SystemDoorBell, + ScsiPortReadPortUchar(DeviceExtension->SystemDoorBell)); + + ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell, + DAC960_LOCAL_DOORBELL_MAILBOX_FREE); + + // + // Check semaphore again. + // + + if (ScsiPortReadPortUchar(DeviceExtension->LocalDoorBell) & DAC960_LOCAL_DOORBELL_SUBMIT_BUSY) + { + return FALSE; + } + } + + // + // Issue Request + // + + ScsiPortWritePortUchar(&DeviceExtension->PmailBox->OperationCode, + DeviceExtension->MailBox.OperationCode); + + ScsiPortWritePortUlong(&DeviceExtension->PmailBox->PhysicalAddress, + DeviceExtension->MailBox.PhysicalAddress); + + ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell, + DAC960_LOCAL_DOORBELL_SUBMIT_BUSY); + + // + // Poll for completion. + // + + for (i = 0; i < TimeOutValue; i++) + { + if (ScsiPortReadPortUchar(DeviceExtension->SystemDoorBell) & + DAC960_SYSTEM_DOORBELL_COMMAND_COMPLETE) { + // + // Update Status field + // + + DeviceExtension->MailBox.Status = + ScsiPortReadPortUshort(&DeviceExtension->PmailBox->Status); + + break; + } else { + + ScsiPortStallExecution(50); + } + } + + // + // Check for timeout. + // + + if (i == TimeOutValue) { + DebugPrint((1, + "DAC960: Request: %x timed out\n", + DeviceExtension->MailBox.OperationCode)); + + completionStatus = FALSE; + } + + // + // Dismiss interrupt and tell host mailbox is free. + // + + ScsiPortWritePortUchar(DeviceExtension->SystemDoorBell, + ScsiPortReadPortUchar(DeviceExtension->SystemDoorBell)); + + ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell, + DAC960_LOCAL_DOORBELL_MAILBOX_FREE); + + return (completionStatus); +} + +BOOLEAN +Dac960McaSendInitTimeRequest( + IN PDEVICE_EXTENSION DeviceExtension, + IN ULONG TimeOutValue +) + +/*++ + +Routine Description: + + Send Request to DAC960-MCA Controller and poll for command completion + +Assumptions: + Controller Interrupts are turned off + Supports Dac960 Type 5 Commands only + +Arguments: + + DeviceExtension - Adapter state information. + TimeoutValue - TimeOut value (0xFFFFFFFF - Polled Mode) + +Return Value: + + TRUE if commands complete successfully. + +--*/ + +{ + ULONG i; + BOOLEAN completionStatus = TRUE; + + // + // Issue Request + // + + ScsiPortWriteRegisterUchar(&DeviceExtension->PmailBox->OperationCode, + DeviceExtension->MailBox.OperationCode); + + ScsiPortWriteRegisterUlong(&DeviceExtension->PmailBox->PhysicalAddress, + DeviceExtension->MailBox.PhysicalAddress); + + ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell, + DMC960_SUBMIT_COMMAND); + + // + // Poll for completion. + // + + for (i = 0; i < TimeOutValue; i++) { + + if (ScsiPortReadPortUchar(DeviceExtension->SystemDoorBell) & + DMC960_INTERRUPT_VALID) { + + // + // Update Status field + // + + DeviceExtension->MailBox.Status = + ScsiPortReadRegisterUshort(&DeviceExtension->PmailBox->Status); + + break; + + } else { + + ScsiPortStallExecution(50); + } + } + + // + // Check for timeout. + // + + if (i == TimeOutValue) { + DebugPrint((1, + "DAC960: Request: %x timed out\n", + DeviceExtension->MailBox.OperationCode)); + + completionStatus = FALSE; + } + + // + // Dismiss interrupt and tell host mailbox is free. + // + + ScsiPortWritePortUchar(DeviceExtension->BaseIoAddress + + DMC960_SUBSYSTEM_CONTROL_PORT, + (DMC960_DISABLE_INTERRUPT | DMC960_CLEAR_INTERRUPT_ON_READ)); + + ScsiPortReadPortUchar(DeviceExtension->SystemDoorBell); + + ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell, + DMC960_ACKNOWLEDGE_STATUS); + + ScsiPortWritePortUchar(DeviceExtension->BaseIoAddress + + DMC960_SUBSYSTEM_CONTROL_PORT, + DMC960_DISABLE_INTERRUPT); + + return (completionStatus); +} + +BOOLEAN +Dac960ScanForNonDiskDevices( + IN PDEVICE_EXTENSION DeviceExtension +) + +/*++ + +Routine Description: + + Issue SCSI_INQUIRY request to all Devices, looking for Non + Hard Disk devices and construct the NonDisk device table + +Arguments: + + DeviceExtension - Adapter state information. + +Return Value: + + TRUE if commands complete successfully. + +--*/ + +{ + ULONG i; + PINQUIRYDATA inquiryData; + PDIRECT_CDB directCdb = (PDIRECT_CDB) DeviceExtension->NoncachedExtension; + BOOLEAN status; + UCHAR channel; + UCHAR target; + + + // + // Fill in Direct CDB Table with SCSI_INQUIRY command information + // + + directCdb->CommandControl = (DAC960_CONTROL_ENABLE_DISCONNECT | + DAC960_CONTROL_TIMEOUT_10_SECS | + DAC960_CONTROL_DATA_IN); + + inquiryData = (PINQUIRYDATA) ((PUCHAR) directCdb + sizeof(DIRECT_CDB)); + + directCdb->DataBufferAddress = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress(DeviceExtension, + NULL, + ((PUCHAR) inquiryData), + &i)); + + directCdb->CdbLength = 6; + directCdb->RequestSenseLength = SENSE_BUFFER_SIZE; + + ((PCDB) directCdb->Cdb)->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY; + ((PCDB) directCdb->Cdb)->CDB6INQUIRY.Reserved1 = 0; + ((PCDB) directCdb->Cdb)->CDB6INQUIRY.LogicalUnitNumber = 0; + ((PCDB) directCdb->Cdb)->CDB6INQUIRY.PageCode = 0; + ((PCDB) directCdb->Cdb)->CDB6INQUIRY.IReserved = 0; + ((PCDB) directCdb->Cdb)->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE; + ((PCDB) directCdb->Cdb)->CDB6INQUIRY.Control = 0; + + directCdb->Status = 0; + directCdb->Reserved = 0; + + // + // Set up Mail Box registers for DIRECT_CDB command information. + // + + DeviceExtension->MailBox.OperationCode = DAC960_COMMAND_DIRECT; + + DeviceExtension->MailBox.PhysicalAddress = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress(DeviceExtension, + NULL, + directCdb, + &i)); + + + for (channel = 0; channel < DeviceExtension->NumberOfChannels; channel++) + { + for (target = 0; target < MAXIMUM_TARGETS_PER_CHANNEL; target++) + { + // + // Initialize this device state to not present/not accessible + // + + DeviceExtension->DeviceList[channel][target] = + DAC960_DEVICE_NOT_ACCESSIBLE; + +#ifdef GAM_SUPPORT + // + // GAM device will be configured on Channel 0, Target 6 + // + + if ((channel == 0) && (target == 6)) { + + DeviceExtension->DeviceList[channel][target] = DAC960_DEVICE_ACCESSIBLE; + + continue; + } +#endif + // + // Fill up DCDB Table + // + + directCdb->TargetId = target; + directCdb->Channel = channel; + + directCdb->DataTransferLength = INQUIRYDATABUFFERSIZE; + + // + // Issue Direct CDB command + // + + if (DeviceExtension->AdapterInterfaceType == MicroChannel) + status = Dac960McaSendInitTimeRequest(DeviceExtension, 0xFFFFFFFF); + else + status = Dac960EisaPciSendInitTimeRequest(DeviceExtension, 0xFFFFFFFF); + + if (status) { + if (DeviceExtension->MailBox.Status == DAC960_STATUS_GOOD) + { + if (inquiryData->DeviceType != DIRECT_ACCESS_DEVICE) + DeviceExtension->DeviceList[channel][target] = + DAC960_DEVICE_ACCESSIBLE; + } + } else { + DebugPrint((0, "DAC960: ScanForNonDisk Devices failed\n")); + return (status); + } + } + } + + return (TRUE); +} + +BOOLEAN +GetEisaPciConfiguration( + IN PDEVICE_EXTENSION DeviceExtension, + IN PPORT_CONFIGURATION_INFORMATION ConfigInfo +) + +/*++ + +Routine Description: + + Issue ENQUIRY and ENQUIRY 2 commands to DAC960 (EISA/PCI). + +Arguments: + + DeviceExtension - Adapter state information. + ConfigInfo - Port configuration information structure. + +Return Value: + + TRUE if commands complete successfully. + +--*/ + +{ + ULONG i; + ULONG physicalAddress; + USHORT status; + + // + // Maximum number of physical segments is 16. + // + + ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SGL_DESCRIPTORS - 1; + ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_LENGTH; + + // + // Indicate that this adapter is a busmaster, supports scatter/gather, + // caches data and can do DMA to/from physical addresses above 16MB. + // + + ConfigInfo->ScatterGather = TRUE; + ConfigInfo->Master = TRUE; + ConfigInfo->CachesData = TRUE; + ConfigInfo->Dma32BitAddresses = TRUE; + + // + // Get noncached extension for enquiry command. + // + + DeviceExtension->NoncachedExtension = + ScsiPortGetUncachedExtension(DeviceExtension, + ConfigInfo, + 196); + + // + // Get physical address of noncached extension. + // + + physicalAddress = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress(DeviceExtension, + NULL, + DeviceExtension->NoncachedExtension, + &i)); + + // + // Check to see if adapter is initialized and ready to accept commands. + // + + ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell, + DAC960_LOCAL_DOORBELL_MAILBOX_FREE); + + // + // Wait for controller to clear bit. + // + + for (i = 0; i < 5000; i++) { + + if (!(ScsiPortReadPortUchar(DeviceExtension->LocalDoorBell) & + DAC960_LOCAL_DOORBELL_MAILBOX_FREE)) { + break; + } + + ScsiPortStallExecution(5000); + } + + // + // Claim submission semaphore. + // + + if (ScsiPortReadPortUchar(DeviceExtension->LocalDoorBell) & DAC960_LOCAL_DOORBELL_SUBMIT_BUSY) { + + // + // Clear any bits set in system doorbell and tell controller + // that the mailbox is free. + // + + ScsiPortWritePortUchar(DeviceExtension->SystemDoorBell, + ScsiPortReadPortUchar(DeviceExtension->SystemDoorBell)); + + ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell, + DAC960_LOCAL_DOORBELL_MAILBOX_FREE); + + // + // Check semaphore again. + // + + if (ScsiPortReadPortUchar(DeviceExtension->LocalDoorBell) & DAC960_LOCAL_DOORBELL_SUBMIT_BUSY) { + return FALSE; + } + } + + // + // Set up Mail Box registers with ENQUIRY 2 command information. + // + + DeviceExtension->MailBox.OperationCode = DAC960_COMMAND_ENQUIRE2; + + DeviceExtension->MailBox.PhysicalAddress = physicalAddress; + + // + // Issue ENQUIRY 2 command + // + + if (Dac960EisaPciSendInitTimeRequest(DeviceExtension, 200)) + { + // + // Set interrupt mode. + // + + if (DeviceExtension->MailBox.Status) { + + // + // Enquire 2 failed so assume Level. + // + + ConfigInfo->InterruptMode = LevelSensitive; + + } else { + + // + // Check enquire 2 data for interrupt mode. + // + + if (((PENQUIRE2)DeviceExtension->NoncachedExtension)->InterruptMode) { + ConfigInfo->InterruptMode = LevelSensitive; + } else { + ConfigInfo->InterruptMode = Latched; + } + } + } else { + // + // ENQUIRY 2 command timed out, so assume Level. + // + + ConfigInfo->InterruptMode = LevelSensitive; + + DebugPrint((0, "DAC960: ENQUIRY2 command timed-out\n")); + } + + // + // Scan For Non Hard Disk devices + // + // + + Dac960ScanForNonDiskDevices(DeviceExtension); + + // + // Set up Mail Box registers with ENQUIRE command information. + // + + if (DeviceExtension->AdapterType == DAC960_NEW_ADAPTER) + DeviceExtension->MailBox.OperationCode = DAC960_COMMAND_ENQUIRE_3X; + else + DeviceExtension->MailBox.OperationCode = DAC960_COMMAND_ENQUIRE; + + DeviceExtension->MailBox.PhysicalAddress = physicalAddress; + + // + // Issue ENQUIRE command. + // + + if (! Dac960EisaPciSendInitTimeRequest(DeviceExtension, 100)) { + DebugPrint((0, "DAC960: ENQUIRE command timed-out\n")); + } + + // + // Ask system to scan target ids 0-15. System drives will appear + // at target ids 8-15. + // + + ConfigInfo->MaximumNumberOfTargets = 16; + + // + // Record maximum number of outstanding requests to the adapter. + // + + if (DeviceExtension->AdapterType == DAC960_NEW_ADAPTER) { + DeviceExtension->MaximumAdapterRequests = ((PDAC960_ENQUIRY_3X) + DeviceExtension->NoncachedExtension)->NumberOfConcurrentCommands; + } else { + DeviceExtension->MaximumAdapterRequests = ((PDAC960_ENQUIRY) + DeviceExtension->NoncachedExtension)->NumberOfConcurrentCommands; + } + + + // + // This shameless hack is necessary because this value is coming up + // with zero most of time. If I debug it, then it works find, the COD + // looks great. I have no idea what's going on here, but for now I will + // just account for this anomoly. + // + + if (!DeviceExtension->MaximumAdapterRequests) { + DebugPrint((0, + "Dac960FindAdapter: MaximumAdapterRequests is 0!\n")); + DeviceExtension->MaximumAdapterRequests = 0x40; + } + + // + // Say max commands is 60. This may be necessary to support asynchronous + // rebuild etc. + // + + DeviceExtension->MaximumAdapterRequests -= 4; + + // + // Indicate that each initiator is at id 7 for each bus. + // + + for (i = 0; i < ConfigInfo->NumberOfBuses; i++) { + ConfigInfo->InitiatorBusId[i] = 7; + } + + return TRUE; + +} // end GetEisaPciConfiguration() + +BOOLEAN +GetMcaConfiguration( + IN PDEVICE_EXTENSION DeviceExtension, + IN PPORT_CONFIGURATION_INFORMATION ConfigInfo +) + +/*++ + +Routine Description: + + Issue ENQUIRY and ENQUIRY 2 commands to DAC960 (MCA). + +Arguments: + + DeviceExtension - Adapter state information. + ConfigInfo - Port configuration information structure. + +Return Value: + + TRUE if commands complete successfully. + +--*/ + +{ + ULONG i; + ULONG physicalAddress; + USHORT status; + + // + // Maximum number of physical segments is 16. + // + + ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SGL_DESCRIPTORS - 1; + ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_LENGTH; + + // + // Indicate that this adapter is a busmaster, supports scatter/gather, + // caches data and can do DMA to/from physical addresses above 16MB. + // + + ConfigInfo->ScatterGather = TRUE; + ConfigInfo->Master = TRUE; + ConfigInfo->CachesData = TRUE; + ConfigInfo->Dma32BitAddresses = TRUE; + + // + // Get noncached extension for enquiry command. + // + + DeviceExtension->NoncachedExtension = + ScsiPortGetUncachedExtension(DeviceExtension, + ConfigInfo, + 128); + + // + // Get physical address of noncached extension. + // + + physicalAddress = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress(DeviceExtension, + NULL, + DeviceExtension->NoncachedExtension, + &i)); + // + // Check to see if adapter is initialized and ready to accept commands. + // + + ScsiPortWriteRegisterUchar(DeviceExtension->BaseBiosAddress + 0x188d, 2); + + ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell, + DMC960_ACKNOWLEDGE_STATUS); + + // + // Wait for controller to clear bit. + // + + for (i = 0; i < 5000; i++) { + + if (!(ScsiPortReadRegisterUchar(DeviceExtension->BaseBiosAddress + 0x188d) & 2)) { + break; + } + + ScsiPortStallExecution(5000); + } + + // + // Claim submission semaphore. + // + + if (ScsiPortReadRegisterUchar(&DeviceExtension->PmailBox->OperationCode) != 0) { + + // + // Clear any bits set in system doorbell. + // + + ScsiPortWritePortUchar(DeviceExtension->SystemDoorBell, 0); + + // + // Check for submission semaphore again. + // + + if (ScsiPortReadRegisterUchar(&DeviceExtension->PmailBox->OperationCode) != 0) { + DebugPrint((0,"Dac960nt: MCA Adapter initialization failed\n")); + return FALSE; + } + } + + + // + // Set up Mail Box registers with ENQUIRY 2 command information. + // + + DeviceExtension->MailBox.OperationCode = DAC960_COMMAND_ENQUIRE2; + + DeviceExtension->MailBox.PhysicalAddress = physicalAddress; + + // + // Issue ENQUIRY 2 command + // + + if (Dac960McaSendInitTimeRequest(DeviceExtension, 200)) { + + // + // Set Interrupt Mode + // + + if (DeviceExtension->MailBox.Status) + { + // + // Enquire 2 failed so assume Level. + // + + ConfigInfo->InterruptMode = LevelSensitive; + + } else { + + // + // Check enquire 2 data for interrupt mode. + // + + if (((PENQUIRE2)DeviceExtension->NoncachedExtension)->InterruptMode) { + ConfigInfo->InterruptMode = LevelSensitive; + } else { + ConfigInfo->InterruptMode = Latched; + } + } + } + else { + // + // Enquire 2 timed-out, so assume Level. + // + + ConfigInfo->InterruptMode = LevelSensitive; + + } + + // + // Enquiry 2 is always returning Latched Mode. Needs to be fixed + // in Firmware. Till then assume LevelSensitive. + // + + ConfigInfo->InterruptMode = LevelSensitive; + + // + // Scan For Non Disk devices. + // + + Dac960ScanForNonDiskDevices(DeviceExtension); + + // + // Set up Mail Box registers with ENQUIRE command information. + // + + DeviceExtension->MailBox.OperationCode = DAC960_COMMAND_ENQUIRE; + + DeviceExtension->MailBox.PhysicalAddress = physicalAddress; + + // + // Issue ENQUIRE command. + // + + if (! Dac960McaSendInitTimeRequest(DeviceExtension, 100)) { + DebugPrint((0, "DAC960: Enquire command timed-out\n")); + } + + // + // Ask system to scan target ids 0-15. System drives will appear + // at target ids 8-15. + // + + ConfigInfo->MaximumNumberOfTargets = 16; + + // + // Record maximum number of outstanding requests to the adapter. + // + + DeviceExtension->MaximumAdapterRequests = + DeviceExtension->NoncachedExtension->NumberOfConcurrentCommands; + + // + // This shameless hack is necessary because this value is coming up + // with zero most of time. If I debug it, then it works find, the COD + // looks great. I have no idea what's going on here, but for now I will + // just account for this anomoly. + // + + if (!DeviceExtension->MaximumAdapterRequests) { + DebugPrint((0, + "Dac960FindAdapter: MaximumAdapterRequests is 0!\n")); + DeviceExtension->MaximumAdapterRequests = 0x40; + } + + // + // Say max commands is 60. This may be necessary to support asynchronous + // rebuild etc. + // + + DeviceExtension->MaximumAdapterRequests -= 4; + + // + // Indicate that each initiator is at id 7 for each bus. + // + + for (i = 0; i < ConfigInfo->NumberOfBuses; i++) { + ConfigInfo->InitiatorBusId[i] = 7; + } + + return TRUE; + +} // end GetMcaConfiguration() + +ULONG +Dac960EisaFindAdapter( + IN PVOID HwDeviceExtension, + IN PVOID Context, + IN PVOID BusInformation, + IN PCHAR ArgumentString, + IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, + OUT PBOOLEAN Again +) + +/*++ + +Routine Description: + + This function is called by the OS-specific port driver after + the necessary storage has been allocated, to gather information + about the adapter's configuration. + +Arguments: + + HwDeviceExtension - HBA miniport driver's adapter data storage + Context - EISA slot number. + BusInformation - Not used. + ArgumentString - Not used. + ConfigInfo - Data shared between system and driver describing an adapter. + Again - Indicates that driver wishes to be called again to continue + search for adapters. + +Return Value: + + TRUE if adapter present in system + +--*/ + +{ + PDEVICE_EXTENSION deviceExtension = HwDeviceExtension; + PEISA_REGISTERS eisaRegisters; + ULONG eisaSlotNumber; + ULONG eisaId; + PUCHAR baseAddress; + UCHAR interruptLevel; + UCHAR biosAddress; + BOOLEAN found=FALSE; + + // + // Scan EISA bus for DAC960 adapters. + // + + for (eisaSlotNumber = *(PULONG)Context + 1; + eisaSlotNumber < MAXIMUM_EISA_SLOTS; + eisaSlotNumber++) { + + // + // Update the slot count to indicate this slot has been checked. + // + + (*(PULONG)Context)++; + + // + // Get the system address for this card. The card uses I/O space. + // + + baseAddress = (PUCHAR) + ScsiPortGetDeviceBase(deviceExtension, + ConfigInfo->AdapterInterfaceType, + ConfigInfo->SystemIoBusNumber, + ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber), + 0x1000, + TRUE); + + eisaRegisters = + (PEISA_REGISTERS)(baseAddress + 0xC80); + deviceExtension->BaseIoAddress = (PUCHAR)eisaRegisters; + + // + // Look at EISA id. + // + + eisaId = ScsiPortReadPortUlong(&eisaRegisters->EisaId); + + if ((eisaId & 0xF0FFFFFF) == DAC_EISA_ID) { + deviceExtension->Slot = (UCHAR) eisaSlotNumber; + found = TRUE; + break; + } + + // + // If an adapter was not found unmap address. + // + + ScsiPortFreeDeviceBase(deviceExtension, baseAddress); + + } // end for (eisaSlotNumber ... + + // + // If no more adapters were found then indicate search is complete. + // + + if (!found) { + *Again = FALSE; + return SP_RETURN_NOT_FOUND; + } + + // + // Set the address of mailbox and doorbell registers. + // + + deviceExtension->PmailBox = (PMAILBOX)&eisaRegisters->MailBox.OperationCode; + deviceExtension->LocalDoorBell = &eisaRegisters->LocalDoorBell; + deviceExtension->SystemDoorBell = &eisaRegisters->SystemDoorBell; + + // + // Fill in the access array information. + // + + (*ConfigInfo->AccessRanges)[0].RangeStart = + ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber + 0xC80); + (*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(EISA_REGISTERS); + (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE; + + // + // Determine number of SCSI channels supported by this adapter by + // looking low byte of EISA ID. + // + + switch (eisaId >> 24) { + + case 0x70: + ConfigInfo->NumberOfBuses = 5; + deviceExtension->NumberOfChannels = 5; + break; + + case 0x75: + case 0x71: + case 0x72: + deviceExtension->NumberOfChannels = 3; + ConfigInfo->NumberOfBuses = 3; + break; + + case 0x76: + case 0x73: + deviceExtension->NumberOfChannels = 2; + ConfigInfo->NumberOfBuses = 2; + break; + + case 0x77: + case 0x74: + default: + deviceExtension->NumberOfChannels = 1; + ConfigInfo->NumberOfBuses = 1; + break; + } + + // + // Read adapter interrupt level. + // + + interruptLevel = + ScsiPortReadPortUchar(&eisaRegisters->InterruptLevel) & 0x60; + + switch (interruptLevel) { + + case 0x00: + ConfigInfo->BusInterruptLevel = 15; + break; + + case 0x20: + ConfigInfo->BusInterruptLevel = 11; + break; + + case 0x40: + ConfigInfo->BusInterruptLevel = 12; + break; + + case 0x60: + ConfigInfo->BusInterruptLevel = 14; + break; + } + + // + // Read BIOS ROM address. + // + + biosAddress = ScsiPortReadPortUchar(&eisaRegisters->BiosAddress); + + // + // Check if BIOS enabled. + // + + if (biosAddress & DAC960_BIOS_ENABLED) { + + ULONG rangeStart; + + switch (biosAddress & 7) { + + case 0: + rangeStart = 0xC0000; + break; + case 1: + rangeStart = 0xC4000; + break; + case 2: + rangeStart = 0xC8000; + break; + case 3: + rangeStart = 0xCC000; + break; + case 4: + rangeStart = 0xD0000; + break; + case 5: + rangeStart = 0xD4000; + break; + case 6: + rangeStart = 0xD8000; + break; + case 7: + rangeStart = 0xDC000; + break; + } + + // + // Fill in the access array information. + // + + (*ConfigInfo->AccessRanges)[1].RangeStart = + ScsiPortConvertUlongToPhysicalAddress(rangeStart); + (*ConfigInfo->AccessRanges)[1].RangeLength = 0x4000; + (*ConfigInfo->AccessRanges)[1].RangeInMemory = TRUE; + + // + // Set BIOS Base Address in Device Extension. + // + + deviceExtension->BaseBiosAddress = (PUCHAR) rangeStart; + } + + // + // Disable DAC960 Interupts. + // + + ScsiPortWritePortUchar(&eisaRegisters->InterruptEnable, 0); + ScsiPortWritePortUchar(&eisaRegisters->SystemDoorBellEnable, 0); + + // + // Set Adapter Interface Type. + // + + deviceExtension->AdapterInterfaceType = + ConfigInfo->AdapterInterfaceType; + + // + // Set Adapter Type + // + + deviceExtension->AdapterType = DAC960_OLD_ADAPTER; + + // + // Issue ENQUIRY and ENQUIRY 2 commands to get adapter configuration. + // + + if (!GetEisaPciConfiguration(deviceExtension, + ConfigInfo)) { + return SP_INTERNAL_ADAPTER_ERROR; + } + + // + // Fill in System Resources used by Adapter, in device extension. + // + + deviceExtension->SystemIoBusNumber = + ConfigInfo->SystemIoBusNumber; + + deviceExtension->BusInterruptLevel = + ConfigInfo->BusInterruptLevel; + + deviceExtension->InterruptMode = ConfigInfo->InterruptMode; + + + // + // Enable interrupts. For the local doorbell, enable interrupts to host + // when a command has been submitted and when a completion has been + // processed. For the system doorbell, enable only an interrupt when a + // command is completed by the host. Note: I am noticing that when I get + // a completion interrupt, not only is the bit set that indicates a command + // is complete, but the bit that indicates that the submission channel is + // free is also set. If I don't clear both bits, the interrupt won't go + // away. (MGLASS) + // + + ScsiPortWritePortUchar(&eisaRegisters->InterruptEnable, 1); + ScsiPortWritePortUchar(&eisaRegisters->SystemDoorBellEnable, 1); + + DebugPrint((0, + "DAC960: Active request array address %x\n", + deviceExtension->ActiveRequests)); + + // + // Tell system to keep on searching. + // + + *Again = TRUE; + + deviceExtension->NextRequest = TRUE; + + return SP_RETURN_FOUND; + +} // end Dac960EisaFindAdapter() + +ULONG +Dac960PciFindAdapter( + IN PVOID HwDeviceExtension, + IN PVOID Context, + IN PVOID BusInformation, + IN PCHAR ArgumentString, + IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, + OUT PBOOLEAN Again +) + +/*++ + +Routine Description: + + This function is called by the OS-specific port driver after + the necessary storage has been allocated, to gather information + about the adapter's configuration. + +Arguments: + + HwDeviceExtension - HBA miniport driver's adapter data storage + Context - DAC960 PCI Adapter Type. + BusInformation - Bus Specific Information. + ArgumentString - Not used. + ConfigInfo - Data shared between system and driver describing an adapter. + Again - Indicates that driver wishes to be called again to continue + search for adapters. + +Return Value: + + TRUE if adapter present in system + +--*/ + +{ + PDEVICE_EXTENSION deviceExtension = HwDeviceExtension; + PCI_COMMON_CONFIG pciConfig; + ULONG rc, i; + ULONG address; + USHORT commandRegister; + BOOLEAN disableDac960MemorySpaceAccess = FALSE; + + // + // Patch for DAC960 PCU3 - System does not reboot after shutdown. + // + + for (i = 0; i < ConfigInfo->NumberOfAccessRanges; i++) { + if ((*ConfigInfo->AccessRanges)[i].RangeInMemory && + (*ConfigInfo->AccessRanges)[i].RangeLength != 0) { + + address = ScsiPortConvertPhysicalAddressToUlong( + (*ConfigInfo->AccessRanges)[i].RangeStart); + + if (address >= 0xFFFC0000) { + disableDac960MemorySpaceAccess = TRUE; + break; + } + } + } + + if (disableDac960MemorySpaceAccess) { + // + // Check for Bus Specific information passed in from system. + // + + if (BusInformation != (PVOID) NULL) { + // + // Get Command Register value from PCI Config Space + // + + commandRegister = ((PPCI_COMMON_CONFIG) BusInformation)->Command; + } + else { + // + // Get PCI Config Space information for DAC960 Pci Controller + // + + rc = ScsiPortGetBusData(deviceExtension, + PCIConfiguration, + ConfigInfo->SystemIoBusNumber, + (ULONG) ConfigInfo->SlotNumber, + (PVOID) &pciConfig, + sizeof(PCI_COMMON_CONFIG)); + + if (rc == 0 || rc == 2) { + DebugPrint((0, "Error: 0x%x, Getting PCI Config Space information for DAC960 Pci Controller\n")); + + *Again = FALSE; + return SP_RETURN_NOT_FOUND; + } + else { + // + // Get Command Register value from PCI config space + // + + commandRegister = pciConfig.Command; + } + } + + // + // Check if Memory Space Access Bit is enabled in Command Register + // + + if (commandRegister & PCI_ENABLE_MEMORY_SPACE) { + // + // Disable Memory Space Access for DAC960 Pci Controller + // + + commandRegister &= ~PCI_ENABLE_MEMORY_SPACE; + + // + // Set Command Register value in DAC960 Pci Config Space + // + + rc = ScsiPortSetBusDataByOffset(deviceExtension, + PCIConfiguration, + ConfigInfo->SystemIoBusNumber, + (ULONG) ConfigInfo->SlotNumber, + (PVOID) &commandRegister, + 0x04, // Command Register Offset + 2); // 2 Bytes + + if (rc != 2) { + DebugPrint((0, "Error: 0x%x, Setting Command Register Value in DAC960 Pci Config Space")); + + *Again = FALSE; + return SP_RETURN_NOT_FOUND; + } + } + } + + // + // Check for configuration information passed in from system. + // + + if ((*ConfigInfo->AccessRanges)[0].RangeLength == 0) { + + DebugPrint((1, + "Dac960nt: No configuration information\n")); + + *Again = FALSE; + return SP_RETURN_NOT_FOUND; + } + + // + // Get the system address for this card. The card uses I/O space. + // + + deviceExtension->BaseIoAddress = + ScsiPortGetDeviceBase(deviceExtension, + ConfigInfo->AdapterInterfaceType, + ConfigInfo->SystemIoBusNumber, + (*ConfigInfo->AccessRanges)[0].RangeStart, + sizeof(PCI_REGISTERS), + TRUE); + + // + // Set up register pointers. + // + + deviceExtension->PmailBox = (PMAILBOX)deviceExtension->BaseIoAddress; + deviceExtension->LocalDoorBell = deviceExtension->BaseIoAddress + 0x40; + deviceExtension->SystemDoorBell = deviceExtension->BaseIoAddress + 0x41; + + // + // Set number of channels. + // + + deviceExtension->NumberOfChannels = 3; + ConfigInfo->NumberOfBuses = 3; + + // + // Disable Interrupts from DAC960P board. + // + + ScsiPortWritePortUchar(deviceExtension->SystemDoorBell + 2, 0); + + // + // Set Adapter Interface Type. + // + + deviceExtension->AdapterInterfaceType = + ConfigInfo->AdapterInterfaceType; + + // + // Set Adapter Type + // + + deviceExtension->AdapterType = *(PULONG)Context; + + // + // Issue ENQUIRY and ENQUIRY 2 commands to get adapter configuration. + // + + if (!GetEisaPciConfiguration(deviceExtension, + ConfigInfo)) { + return SP_INTERNAL_ADAPTER_ERROR; + } + + // + // Fill in System Resources used by Adapter, in device extension. + // + + deviceExtension->SystemIoBusNumber = + ConfigInfo->SystemIoBusNumber; + + deviceExtension->BusInterruptLevel = + ConfigInfo->BusInterruptLevel; + + // + // DAC960P FW 2.0 returns Interrupt Mode as 'Latched'. + // Assume 'Level Sensitive' till it is fixed in Firmware. + // + + ConfigInfo->InterruptMode = LevelSensitive; + + deviceExtension->InterruptMode = ConfigInfo->InterruptMode; + + + deviceExtension->BaseBiosAddress = 0; + + deviceExtension->Slot = 0; + + // + // Enable completion interrupts. + // + + ScsiPortWritePortUchar(deviceExtension->SystemDoorBell + 2, 1); + + // + // Tell system to keep on searching. + // + + *Again = TRUE; + + deviceExtension->NextRequest = TRUE; + + return SP_RETURN_FOUND; + +} // end Dac960PciFindAdapter() + +ULONG +Dac960McaFindAdapter( + IN PVOID HwDeviceExtension, + IN PVOID Context, + IN PVOID BusInformation, + IN PCHAR ArgumentString, + IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, + OUT PBOOLEAN Again +) + +/*++ + +Routine Description: + + This function is called by the OS-specific port driver after + the necessary storage has been allocated, to gather information + about the adapter's configuration. + +Arguments: + + HwDeviceExtension - HBA miniport driver's adapter data storage + Context - MCA slot number. + BusInformation - Not used. + ArgumentString - Not used. + ConfigInfo - Data shared between system and driver describing an adapter. + Again - Indicates that driver wishes to be called again to continue + search for adapters. + +Return Value: + + TRUE if adapter present in system + +--*/ + +{ + PDEVICE_EXTENSION deviceExtension = HwDeviceExtension; + ULONG baseBiosAddress; + ULONG baseIoAddress; + ULONG mcaSlotNumber; + LONG i; + BOOLEAN found=FALSE; + + // + // Scan MCA bus for DMC960 adapters. + // + + + for (mcaSlotNumber = *(PULONG)Context; + mcaSlotNumber < MAXIMUM_MCA_SLOTS; + mcaSlotNumber++) { + + // + // Update the slot count to indicate this slot has been checked. + // + + (*(PULONG)Context)++; + + // + // Get POS data for this slot. + // + + i = ScsiPortGetBusData (deviceExtension, + Pos, + 0, + mcaSlotNumber, + &deviceExtension->PosData, + sizeof( POS_DATA ) + ); + + // + // If less than the requested amount of data is returned, then + // insure that this adapter is ignored. + // + + if ( i < (sizeof( POS_DATA ))) { + continue; + } + + if (deviceExtension->PosData.AdapterId == MAGPIE_ADAPTER_ID || + deviceExtension->PosData.AdapterId == HUMMINGBIRD_ADAPTER_ID || + deviceExtension->PosData.AdapterId == PASSPLAY_ADAPTER_ID) { + + deviceExtension->Slot = (UCHAR) mcaSlotNumber; + found = TRUE; + break; + } + } + + if (!found) { + *Again = FALSE; + return SP_RETURN_NOT_FOUND; + } + + // + // Set adapter base I/O address. + // + + i = (deviceExtension->PosData.OptionData4 >> 3) & 0x07; + + baseIoAddress = 0x1c00 + ((i * 2) << 12); + + // + // Set adapter base Bios address. + // + + i = (deviceExtension->PosData.OptionData1 >> 2) & 0x0f; + + baseBiosAddress = 0xc0000 + ((i * 2) << 12); + + + // + // Fill in the access array information. + // + + (*ConfigInfo->AccessRanges)[0].RangeStart = + ScsiPortConvertUlongToPhysicalAddress(baseIoAddress); + (*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(MCA_REGISTERS); + (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE; + + (*ConfigInfo->AccessRanges)[1].RangeStart = + ScsiPortConvertUlongToPhysicalAddress(baseBiosAddress); + (*ConfigInfo->AccessRanges)[1].RangeLength = 0x2000; + (*ConfigInfo->AccessRanges)[1].RangeInMemory = TRUE; + + + deviceExtension->BaseBiosAddress = + ScsiPortGetDeviceBase(deviceExtension, + ConfigInfo->AdapterInterfaceType, + ConfigInfo->SystemIoBusNumber, + ScsiPortConvertUlongToPhysicalAddress(baseBiosAddress), + 0x2000, + FALSE); + + deviceExtension->BaseIoAddress = + ScsiPortGetDeviceBase(deviceExtension, + ConfigInfo->AdapterInterfaceType, + ConfigInfo->SystemIoBusNumber, + ScsiPortConvertUlongToPhysicalAddress(baseIoAddress), + sizeof(MCA_REGISTERS), + TRUE); + + // + // Set up register pointers. + // + + deviceExtension->PmailBox = (PMAILBOX)(deviceExtension->BaseBiosAddress + + 0x1890); + + // + // DMC960 Attention Port is equivalent to EISA/PCI Local Door Bell register. + // + + deviceExtension->LocalDoorBell = deviceExtension->BaseIoAddress + + DMC960_ATTENTION_PORT; + + // + // DMC960 Command Status Busy Port is equivalent to EISA/PCI System DoorBell + // register. + // + + deviceExtension->SystemDoorBell = deviceExtension->BaseIoAddress + + DMC960_COMMAND_STATUS_BUSY_PORT; + + // + // Set configuration information + // + + switch(((deviceExtension->PosData.OptionData1 >> 6) & 0x03)) { + + case 0x00: + ConfigInfo->BusInterruptLevel = 14; + break; + + case 0x01: + ConfigInfo->BusInterruptLevel = 12; + break; + + case 0x02: + ConfigInfo->BusInterruptLevel = 11; + break; + + case 0x03: + ConfigInfo->BusInterruptLevel = 10; + break; + + } + + ConfigInfo->NumberOfBuses = 2; + + // + // Disable DMC960 Interrupts. + // + + ScsiPortWritePortUchar(deviceExtension->BaseIoAddress + + DMC960_SUBSYSTEM_CONTROL_PORT, + DMC960_DISABLE_INTERRUPT); + // + // Set Adapter Interface Type. + // + + deviceExtension->AdapterInterfaceType = ConfigInfo->AdapterInterfaceType; + deviceExtension->NumberOfChannels = ConfigInfo->NumberOfBuses; + + // + // Set Adapter Type + // + + deviceExtension->AdapterType = DAC960_OLD_ADAPTER; + + // + // Issue ENQUIRY and ENQUIRY2 commands to get adapter configuration. + // + + if(!GetMcaConfiguration(deviceExtension, + ConfigInfo)) { + return SP_INTERNAL_ADAPTER_ERROR; + } + + // + // Fill in System Resources used by Adapter, in device extension. + // + + deviceExtension->SystemIoBusNumber = ConfigInfo->SystemIoBusNumber; + + deviceExtension->BusInterruptLevel = ConfigInfo->BusInterruptLevel; + + deviceExtension->InterruptMode = ConfigInfo->InterruptMode; + + + // + // Enable DMC960 Interrupts. + // + + ScsiPortWritePortUchar(deviceExtension->BaseIoAddress + + DMC960_SUBSYSTEM_CONTROL_PORT, + DMC960_ENABLE_INTERRUPT); + + + *Again = TRUE; + + deviceExtension->NextRequest = TRUE; + + return SP_RETURN_FOUND; + +} // end Dac960McaFindAdapter() + +BOOLEAN +Dac960Initialize( + IN PVOID HwDeviceExtension + ) + +/*++ + +Routine Description: + + Inititialize adapter. + +Arguments: + + HwDeviceExtension - HBA miniport driver's adapter data storage + +Return Value: + + TRUE - if initialization successful. + FALSE - if initialization unsuccessful. + +--*/ + +{ + PDEVICE_EXTENSION deviceExtension = + HwDeviceExtension; + + return(TRUE); + +} // end Dac960Initialize() + +BOOLEAN +BuildScatterGather( + IN PDEVICE_EXTENSION DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb, + OUT PULONG PhysicalAddress, + OUT PULONG DescriptorCount +) + +/*++ + +Routine Description: + + Build scatter/gather list. + +Arguments: + + DeviceExtension - Adapter state + SRB - System request + +Return Value: + + TRUE if scatter/gather command should be used. + FALSE if no scatter/gather is necessary. + +--*/ + +{ + PSG_DESCRIPTOR sgList; + ULONG descriptorNumber; + ULONG bytesLeft; + PUCHAR dataPointer; + ULONG length; + + // + // Get data pointer, byte count and index to scatter/gather list. + // + + sgList = (PSG_DESCRIPTOR)Srb->SrbExtension; + descriptorNumber = 0; + bytesLeft = Srb->DataTransferLength; + dataPointer = Srb->DataBuffer; + + // + // Build the scatter/gather list. + // + + while (bytesLeft) { + + // + // Get physical address and length of contiguous + // physical buffer. + // + + sgList[descriptorNumber].Address = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress(DeviceExtension, + Srb, + dataPointer, + &length)); + + // + // If length of physical memory is more + // than bytes left in transfer, use bytes + // left as final length. + // + + if (length > bytesLeft) { + length = bytesLeft; + } + + // + // Complete SG descriptor. + // + + sgList[descriptorNumber].Length = length; + + // + // Update pointers and counters. + // + + bytesLeft -= length; + dataPointer += length; + descriptorNumber++; + } + + // + // Return descriptior count. + // + + *DescriptorCount = descriptorNumber; + + // + // Check if number of scatter/gather descriptors is greater than 1. + // + + if (descriptorNumber > 1) { + + // + // Calculate physical address of the scatter/gather list. + // + + *PhysicalAddress = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress(DeviceExtension, + NULL, + sgList, + &length)); + + return TRUE; + + } else { + + // + // Calculate physical address of the data buffer. + // + + *PhysicalAddress = sgList[0].Address; + return FALSE; + } + +} // BuildScatterGather() + +BOOLEAN +BuildScatterGatherExtended( + IN PDEVICE_EXTENSION DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb, + OUT PULONG PhysicalAddress, + OUT PULONG DescriptorCount +) + +/*++ + +Routine Description: + + Build scatter/gather list using extended format supported in Fw 3.x. + +Arguments: + + DeviceExtension - Adapter state + SRB - System request + +Return Value: + + TRUE if scatter/gather command should be used. + FALSE if no scatter/gather is necessary. + +--*/ + +{ + PSG_DESCRIPTOR sgList; + ULONG descriptorNumber; + ULONG bytesLeft; + PUCHAR dataPointer; + ULONG length; + ULONG i; + PSG_DESCRIPTOR sgElem; + + // + // Get data pointer, byte count and index to scatter/gather list. + // + + sgList = (PSG_DESCRIPTOR)Srb->SrbExtension; + descriptorNumber = 1; + bytesLeft = Srb->DataTransferLength; + dataPointer = Srb->DataBuffer; + + // + // Build the scatter/gather list. + // + + while (bytesLeft) { + + // + // Get physical address and length of contiguous + // physical buffer. + // + + sgList[descriptorNumber].Address = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress(DeviceExtension, + Srb, + dataPointer, + &length)); + + // + // If length of physical memory is more + // than bytes left in transfer, use bytes + // left as final length. + // + + if (length > bytesLeft) { + length = bytesLeft; + } + + // + // Complete SG descriptor. + // + + sgList[descriptorNumber].Length = length; + + // + // Update pointers and counters. + // + + bytesLeft -= length; + dataPointer += length; + descriptorNumber++; + } + + // + // Return descriptior count. + // + + *DescriptorCount = --descriptorNumber; + + // + // Check if number of scatter/gather descriptors is greater than 1. + // + + if (descriptorNumber > 1) { + + // + // Calculate physical address of the scatter/gather list. + // + + *PhysicalAddress = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress(DeviceExtension, + NULL, + sgList, + &length)); + + // + // Store count of data blocks in SG list 0th element. + // + + sgList[0].Address = (USHORT) + (((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb | + (((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8)); + + sgList[0].Length = 0; + + return TRUE; + + } else { + + // + // Calculate physical address of the data buffer. + // + + *PhysicalAddress = sgList[1].Address; + return FALSE; + } + +} // BuildScatterGatherExtended() + +BOOLEAN +IsAdapterReady( + IN PDEVICE_EXTENSION DeviceExtension +) + +/*++ + +Routine Description: + + Determine if Adapter is ready to accept new request. + +Arguments: + + DeviceExtension - Adapter state. + +Return Value: + + TRUE if adapter can accept new request. + FALSE if host adapter is busy + +--*/ +{ + ULONG i; + + // + // Claim submission semaphore. + // + + if(DeviceExtension->AdapterInterfaceType == MicroChannel) { + + for (i=0; i<100; i++) { + + if (ScsiPortReadRegisterUchar(&DeviceExtension->PmailBox->OperationCode)) { + ScsiPortStallExecution(5); + } else { + break; + } + } + } + else { + + for (i=0; i<100; i++) { + + if (ScsiPortReadPortUchar(DeviceExtension->LocalDoorBell) & DAC960_LOCAL_DOORBELL_SUBMIT_BUSY) { + ScsiPortStallExecution(5); + } else { + break; + } + } + } + + // + // Check for timeout. + // + + if (i == 100) { + + DebugPrint((1, + "DAC960: Timeout waiting for submission channel\n")); + + return FALSE; + } + + return TRUE; + +} + +VOID +SendRequest( + IN PDEVICE_EXTENSION DeviceExtension +) + +/*++ + +Routine Description: + + submit request to DAC960. + +Arguments: + + DeviceExtension - Adapter state. + +Return Value: + + None. + +--*/ + +{ + + PMAILBOX mailBox = (PMAILBOX) &DeviceExtension->MailBox; + PEXTENDED_MAILBOX extendedMailBox; + + if(DeviceExtension->AdapterInterfaceType == MicroChannel) { + + // + // Write scatter/gather descriptor count to controller. + // + + ScsiPortWriteRegisterUchar(&DeviceExtension->PmailBox->ScatterGatherCount, + mailBox->ScatterGatherCount); + // + // Write physical address to controller. + // + + ScsiPortWriteRegisterUlong(&DeviceExtension->PmailBox->PhysicalAddress, + mailBox->PhysicalAddress); + + // + // Write starting block number to controller. + // + + ScsiPortWriteRegisterUchar(&DeviceExtension->PmailBox->BlockNumber[0], + mailBox->BlockNumber[0]); + + ScsiPortWriteRegisterUchar(&DeviceExtension->PmailBox->BlockNumber[1], + mailBox->BlockNumber[1]); + + ScsiPortWriteRegisterUchar(&DeviceExtension->PmailBox->BlockNumber[2], + mailBox->BlockNumber[2]); + + // + // Write block count to controller (bits 0-13) + // and msb block number (bits 14-15). + // + + ScsiPortWriteRegisterUshort(&DeviceExtension->PmailBox->BlockCount, + mailBox->BlockCount); + + // + // Write command to controller. + // + + ScsiPortWriteRegisterUchar(&DeviceExtension->PmailBox->OperationCode, + mailBox->OperationCode); + + // + // Write request id to controller. + // + + ScsiPortWriteRegisterUchar(&DeviceExtension->PmailBox->CommandIdSubmit, + mailBox->CommandIdSubmit), + + // + // Write drive number to controller. + // + + ScsiPortWriteRegisterUchar(&DeviceExtension->PmailBox->DriveNumber, + mailBox->DriveNumber); + + // + // Ring host submission doorbell. + // + + ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell, + DMC960_SUBMIT_COMMAND); + } + else { + + // + // Write scatter/gather descriptor count to controller. + // + + ScsiPortWritePortUchar(&DeviceExtension->PmailBox->ScatterGatherCount, + mailBox->ScatterGatherCount); + + // + // Write physical address to controller. + // + + ScsiPortWritePortUlong(&DeviceExtension->PmailBox->PhysicalAddress, + mailBox->PhysicalAddress); + + // + // Write starting block number to controller. + // + + ScsiPortWritePortUchar(&DeviceExtension->PmailBox->BlockNumber[0], + mailBox->BlockNumber[0]); + + ScsiPortWritePortUchar(&DeviceExtension->PmailBox->BlockNumber[1], + mailBox->BlockNumber[1]); + + ScsiPortWritePortUchar(&DeviceExtension->PmailBox->BlockNumber[2], + mailBox->BlockNumber[2]); + + // + // Write block count to controller (bits 0-13) + // and msb block number (bits 14-15). + // + + ScsiPortWritePortUshort(&DeviceExtension->PmailBox->BlockCount, + mailBox->BlockCount); + + // + // Write command to controller. + // + + ScsiPortWritePortUchar(&DeviceExtension->PmailBox->OperationCode, + mailBox->OperationCode); + + // + // Write request id to controller. + // + + ScsiPortWritePortUchar(&DeviceExtension->PmailBox->CommandIdSubmit, + mailBox->CommandIdSubmit); + + // + // Write drive number to controller. + // + + ScsiPortWritePortUchar(&DeviceExtension->PmailBox->DriveNumber, + mailBox->DriveNumber); + + // + // Ring host submission doorbell. + // + + ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell, + DAC960_LOCAL_DOORBELL_SUBMIT_BUSY); + } +} // end SendRequest() + +BOOLEAN +SubmitRequest( + IN PDEVICE_EXTENSION DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb +) + +/*++ + +Routine Description: + + Build and submit request to DAC960. + +Arguments: + + DeviceExtension - Adapter state. + SRB - System request. + +Return Value: + + TRUE if command was started + FALSE if host adapter is busy + +--*/ + +{ + ULONG descriptorNumber; + ULONG physicalAddress; + UCHAR command; + UCHAR busyCurrentIndex; + + // + // Determine if adapter can accept new request. + // + + if(!IsAdapterReady(DeviceExtension)) + return FALSE; + + // + // Check that next slot is vacant. + // + + if (DeviceExtension->ActiveRequests[DeviceExtension->CurrentIndex]) { + + // + // Collision occurred. + // + + busyCurrentIndex = DeviceExtension->CurrentIndex++; + + do { + if (! DeviceExtension->ActiveRequests[DeviceExtension->CurrentIndex]) { + break; + } + } while (++DeviceExtension->CurrentIndex != busyCurrentIndex) ; + + if (DeviceExtension->CurrentIndex == busyCurrentIndex) { + + // + // We should never encounter this condition. + // + + DebugPrint((1, + "DAC960: SubmitRequest-Collision in active request array\n")); + return FALSE; + } + } + + // + // Determine command. + // + + if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) { + + command = DAC960_COMMAND_READ; + + } else if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) { + + command = DAC960_COMMAND_WRITE; + + } else if ((Srb->Function == SRB_FUNCTION_FLUSH) || (Srb->Function == SRB_FUNCTION_SHUTDOWN)) { + + command = DAC960_COMMAND_FLUSH; + goto commonSubmit; + + } else { + + // + // Log this as illegal request. + // + + ScsiPortLogError(DeviceExtension, + NULL, + 0, + 0, + 0, + SRB_STATUS_INVALID_REQUEST, + 1 << 8); + + return FALSE; + } + + if (DeviceExtension->AdapterType == DAC960_NEW_ADAPTER) { + + command += DAC960_COMMAND_EXTENDED; + + // + // Build scatter/gather list if memory is not physically contiguous. + // + + if (BuildScatterGatherExtended(DeviceExtension, + Srb, + &physicalAddress, + &descriptorNumber)) { + + // + // OR in scatter/gather bit. + // + + command |= DAC960_COMMAND_SG; + + // + // Write scatter/gather descriptor count in Mailbox. + // + + ((PEXTENDED_MAILBOX) &DeviceExtension->MailBox)->BlockCount = + (USHORT) descriptorNumber; + } + else { + // + // Write block count to controller + // + + ((PEXTENDED_MAILBOX) &DeviceExtension->MailBox)->BlockCount = + (USHORT) (((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb | + (((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8)); + } + + // + // Write physical address in Mailbox. + // + + ((PEXTENDED_MAILBOX) &DeviceExtension->MailBox)->PhysicalAddress = + physicalAddress; + + // + // Write starting block number in Mailbox. + // + + ((PEXTENDED_MAILBOX) &DeviceExtension->MailBox)->BlockNumber[0] = + ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3; + + ((PEXTENDED_MAILBOX) &DeviceExtension->MailBox)->BlockNumber[1] = + ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2; + + ((PEXTENDED_MAILBOX) &DeviceExtension->MailBox)->BlockNumber[2] = + ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1; + + ((PEXTENDED_MAILBOX) &DeviceExtension->MailBox)->BlockNumber[3] = + ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0; + + // + // Write drive number to controller. + // + + ((PEXTENDED_MAILBOX) &DeviceExtension->MailBox)->DriveNumber = (UCHAR) + ((Srb->TargetId & ~DAC960_SYSTEM_DRIVE) + (Srb->Lun << 3)); + } + else { + + // + // Build scatter/gather list if memory is not physically contiguous. + // + + if (BuildScatterGather(DeviceExtension, + Srb, + &physicalAddress, + &descriptorNumber)) { + + // + // OR in scatter/gather bit. + // + + command |= DAC960_COMMAND_SG; + + // + // Write scatter/gather descriptor count in Mailbox. + // + + DeviceExtension->MailBox.ScatterGatherCount = + (UCHAR)descriptorNumber; + } + + // + // Write physical address in Mailbox. + // + + DeviceExtension->MailBox.PhysicalAddress = physicalAddress; + + // + // Write starting block number in Mailbox. + // + + DeviceExtension->MailBox.BlockNumber[0] = + ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3; + + DeviceExtension->MailBox.BlockNumber[1] = + ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2; + + DeviceExtension->MailBox.BlockNumber[2] = + ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1; + + // + // Write block count to controller (bits 0-13) + // and msb block number (bits 14-15). + // + + DeviceExtension->MailBox.BlockCount = (USHORT) + (((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb | + ((((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb & 0x3F) << 8) | + ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 14); + + // + // Write drive number to controller. + // + + DeviceExtension->MailBox.DriveNumber = (UCHAR) + ((Srb->TargetId & ~DAC960_SYSTEM_DRIVE) + (Srb->Lun << 3)); + } + +commonSubmit: + + // + // Write command to controller. + // + + DeviceExtension->MailBox.OperationCode = command; + + // + // Write request id to controller. + // + + DeviceExtension->MailBox.CommandIdSubmit = + DeviceExtension->CurrentIndex; + + // + // Start writing mailbox to controller. + // + + SendRequest(DeviceExtension); + + return TRUE; + +} // SubmitRequest() + +VOID +SendCdbDirect( + IN PDEVICE_EXTENSION DeviceExtension +) + +/*++ + +Routine Description: + + Send CDB directly to device - DAC960. + +Arguments: + + DeviceExtension - Adapter state. + +Return Value: + + None. + +--*/ +{ + PMAILBOX mailBox = &DeviceExtension->MailBox; + + if(DeviceExtension->AdapterInterfaceType == MicroChannel) { + + // + // Write Scatter/Gather Count to controller. + // For Fw Ver < 3.x, scatter/gather count goes to register C + // For Fw Ver >= 3.x, scattre/gather count goes to register 2 + // + + if (DeviceExtension->AdapterType == DAC960_NEW_ADAPTER) { + ScsiPortWriteRegisterUshort(&DeviceExtension->PmailBox->BlockCount, + mailBox->BlockCount); + } + else { + ScsiPortWriteRegisterUchar(&DeviceExtension->PmailBox->ScatterGatherCount, + mailBox->ScatterGatherCount); + } + + // + // Write physical address to controller. + // + + ScsiPortWriteRegisterUlong(&DeviceExtension->PmailBox->PhysicalAddress, + mailBox->PhysicalAddress); + + // + // Write command to controller. + // + + ScsiPortWriteRegisterUchar(&DeviceExtension->PmailBox->OperationCode, + mailBox->OperationCode); + + // + // Write request id to controller. + // + + ScsiPortWriteRegisterUchar(&DeviceExtension->PmailBox->CommandIdSubmit, + mailBox->CommandIdSubmit); + + // + // Ring host submission doorbell. + // + + ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell, + DMC960_SUBMIT_COMMAND); + } + else { + + // + // Write Scatter/Gather Count to controller. + // For Fw Ver < 3.x, scatter/gather count goes to register C + // For Fw Ver >= 3.x, scattre/gather count goes to register 2 + // + + if (DeviceExtension->AdapterType == DAC960_NEW_ADAPTER) { + ScsiPortWritePortUshort(&DeviceExtension->PmailBox->BlockCount, + mailBox->BlockCount); + } + else { + ScsiPortWritePortUchar(&DeviceExtension->PmailBox->ScatterGatherCount, + mailBox->ScatterGatherCount); + } + + // + // Write physical address to controller. + // + + ScsiPortWritePortUlong(&DeviceExtension->PmailBox->PhysicalAddress, + mailBox->PhysicalAddress); + + // + // Write command to controller. + // + + ScsiPortWritePortUchar(&DeviceExtension->PmailBox->OperationCode, + mailBox->OperationCode); + + // + // Write request id to controller. + // + + ScsiPortWritePortUchar(&DeviceExtension->PmailBox->CommandIdSubmit, + mailBox->CommandIdSubmit); + + // + // Ring host submission doorbell. + // + + ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell, + DAC960_LOCAL_DOORBELL_SUBMIT_BUSY); + } + +} // SendCdbDirect() + + +BOOLEAN +SubmitCdbDirect( + IN PDEVICE_EXTENSION DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb +) + +/*++ + +Routine Description: + + Build direct CDB and send directly to device - DAC960. + +Arguments: + + DeviceExtension - Adapter state. + SRB - System request. + +Return Value: + + TRUE if command was started + FALSE if host adapter is busy + +--*/ +{ + ULONG physicalAddress; + PDIRECT_CDB directCdb; + UCHAR command; + ULONG descriptorNumber; + ULONG i; + UCHAR busyCurrentIndex; + + // + // Determine if adapter is ready to accept new request. + // + + if(!IsAdapterReady(DeviceExtension)) { + return FALSE; + } + + // + // Check that next slot is vacant. + // + + if (DeviceExtension->ActiveRequests[DeviceExtension->CurrentIndex]) { + + // + // Collision occurred. + // + + busyCurrentIndex = DeviceExtension->CurrentIndex++; + + do { + if (! DeviceExtension->ActiveRequests[DeviceExtension->CurrentIndex]) { + break; + } + } while (++DeviceExtension->CurrentIndex != busyCurrentIndex) ; + + if (DeviceExtension->CurrentIndex == busyCurrentIndex) { + + // + // We should never encounter this condition. + // + + DebugPrint((1, + "DAC960: SubmitCdbDirect-Collision in active request array\n")); + return FALSE; + } + } + + // + // Set command code. + // + + command = DAC960_COMMAND_DIRECT; + + // + // Build scatter/gather list if memory is not physically contiguous. + // + + if (DeviceExtension->AdapterType == DAC960_NEW_ADAPTER) { + + if (BuildScatterGatherExtended(DeviceExtension, + Srb, + &physicalAddress, + &descriptorNumber)) { + // + // OR in scatter/gather bit. + // + + command |= DAC960_COMMAND_SG; + + // + // Write scatter/gather descriptor count in mailbox. + // For Fw Ver >= 3.x, scatter/gather count goes to reg 2 + // + + DeviceExtension->MailBox.BlockCount = + (USHORT)descriptorNumber; + } + } + else { + if (BuildScatterGather(DeviceExtension, + Srb, + &physicalAddress, + &descriptorNumber)) { + + // + // OR in scatter/gather bit. + // + + command |= DAC960_COMMAND_SG; + + // + // Write scatter/gather descriptor count in mailbox. + // + + DeviceExtension->MailBox.ScatterGatherCount = + (UCHAR)descriptorNumber; + } + } + + // + // Get address of data buffer offset after the scatter/gather list. + // + + directCdb = + (PDIRECT_CDB)((PUCHAR)Srb->SrbExtension + + MAXIMUM_SGL_DESCRIPTORS * sizeof(SG_DESCRIPTOR)); + + // + // Set device SCSI address. + // + + directCdb->TargetId = Srb->TargetId; + directCdb->Channel = Srb->PathId; + + // + // Set Data transfer length. + // + + directCdb->DataBufferAddress = physicalAddress; + directCdb->DataTransferLength = (USHORT)Srb->DataTransferLength; + + // + // Initialize control field indicating disconnect allowed. + // + + directCdb->CommandControl = DAC960_CONTROL_ENABLE_DISCONNECT; + + // + // Set data direction bit and allow disconnects. + // + + if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) { + directCdb->CommandControl |= + DAC960_CONTROL_DATA_IN; + } else if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) { + directCdb->CommandControl |= + DAC960_CONTROL_DATA_OUT; + } + + // + // Copy CDB from SRB. + // + + for (i = 0; i < 12; i++) { + directCdb->Cdb[i] = ((PUCHAR)Srb->Cdb)[i]; + } + + // + // Set lengths of CDB and request sense buffer. + // + + directCdb->CdbLength = Srb->CdbLength; + directCdb->RequestSenseLength = Srb->SenseInfoBufferLength; + + // + // Get physical address of direct CDB packet. + // + + physicalAddress = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress(DeviceExtension, + NULL, + directCdb, + &i)); + + // + // Write physical address in mailbox. + // + + DeviceExtension->MailBox.PhysicalAddress = physicalAddress; + + // + // Write command in mailbox. + // + + DeviceExtension->MailBox.OperationCode = command; + + // + // Write request id in mailbox. + // + + DeviceExtension->MailBox.CommandIdSubmit = + DeviceExtension->CurrentIndex; + + // + // Start writing Mailbox to controller. + // + + SendCdbDirect(DeviceExtension); + + return TRUE; + +} // SubmitCdbDirect() + +BOOLEAN +Dac960ResetChannel( + IN PVOID HwDeviceExtension, + IN ULONG PathId +) + +/*++ + +Routine Description: + + Reset Non Disk device associated with Srb. + +Arguments: + + HwDeviceExtension - HBA miniport driver's adapter data storage + PathId - SCSI channel number. + +Return Value: + + TRUE if resets issued to all channels. + +--*/ + +{ + PDEVICE_EXTENSION deviceExtension = HwDeviceExtension; + + if(!IsAdapterReady(deviceExtension)) { + + DebugPrint((1, + "DAC960: Timeout waiting for submission channel %x on reset\n")); + + if(deviceExtension->AdapterInterfaceType == MicroChannel) { + // + // This is bad news. The DAC960 doesn't have a direct hard reset. + // Clear any bits set in system doorbell. + // + + ScsiPortWritePortUchar(deviceExtension->SystemDoorBell, 0); + + // + // Now check again if submission channel is free. + // + + if (ScsiPortReadRegisterUchar(&deviceExtension->PmailBox->OperationCode) != 0) { + + // + // Give up. + // + + return FALSE; + } + } + else { + // + // This is bad news. The DAC960 doesn't have a direct hard reset. + // Clear any bits set in system doorbell. + // + + ScsiPortWritePortUchar(deviceExtension->SystemDoorBell, + ScsiPortReadPortUchar(deviceExtension->SystemDoorBell)); + + // + // Now check again if submission channel is free. + // + + if (ScsiPortReadPortUchar(deviceExtension->LocalDoorBell) & DAC960_LOCAL_DOORBELL_SUBMIT_BUSY) { + + // + // Give up. + // + + return FALSE; + } + } + } + + // + // Write command in mailbox. + // + + deviceExtension->MailBox.OperationCode = + DAC960_COMMAND_RESET; + + // + // Write channel number in mailbox. + // + + deviceExtension->MailBox.BlockCount = + (UCHAR)PathId; + + + // + // Indicate Soft reset required. + // + + deviceExtension->MailBox.BlockNumber[0] = 0; + + + deviceExtension->MailBox.CommandIdSubmit = + deviceExtension->CurrentIndex; + + // + // Start writing mail box to controller. + // + + SendRequest(deviceExtension); + + return TRUE; +} + +BOOLEAN +Dac960ResetBus( + IN PVOID HwDeviceExtension, + IN ULONG PathId +) + +/*++ + +Routine Description: + + Reset Dac960 SCSI adapter and SCSI bus. + NOTE: Command ID is ignored as this command will be completed + before reset interrupt occurs and all active slots are zeroed. + +Arguments: + + HwDeviceExtension - HBA miniport driver's adapter data storage + PathId - not used. + +Return Value: + + TRUE if resets issued to all channels. + +--*/ + +{ + + // + // There is nothing that can be done by Hard/Soft Resetting SCSI channels. + // Dac960 FW does not support a mechanism to abort requests. So If we go + // ahead and indicate to ScsiPort that all requests are complete then + // ScsiPort releases all data buffers and Dac960 DMAs data to data buffers + // which have just been released and eventually system panics. + + // I have observed many instances, where Dac960 takes more than 10 seconds + // to complete requests, specially during insertion/removal of Hot Spare/ + // New/Dead drives. Everything is fine with the adapter, just that it takes + // more than 10 seconds to scan all SCSI channels. Issusing Hard Reset to + // each SCSI channel forces the adapter to re-scan the bus, which would + // worsen the situation. + // + + // I have chosen not to complete all pending requests in the reset + // routine, instead decided to complete the requests as they get completed + // by adapter. -(mouli) + // + +#ifdef ENABLE_DAC960_RESETS + + PDEVICE_EXTENSION deviceExtension = HwDeviceExtension; + ULONG channelNumber; + ULONG i; + + // + // Reset each channel on the adapter. This is because a system drive is + // potentially a composition of several disks arranged across all of the + // channels. + // + + for (channelNumber = 0; + channelNumber < deviceExtension->NumberOfChannels; + channelNumber++) { + + if(!IsAdapterReady(deviceExtension)) { + + DebugPrint((1, + "DAC960: Timeout waiting for submission channel %x on reset\n")); + + if(deviceExtension->AdapterInterfaceType == MicroChannel) { + // + // This is bad news. The DAC960 doesn't have a direct hard reset. + // Clear any bits set in system doorbell. + // + + ScsiPortWritePortUchar(deviceExtension->SystemDoorBell, 0); + + // + // Now check again if submission channel is free. + // + + if (ScsiPortReadRegisterUchar(&deviceExtension->PmailBox->OperationCode) != 0) { + + // + // Give up. + // + + break; + } + } + else { + // + // This is bad news. The DAC960 doesn't have a direct hard reset. + // Clear any bits set in system doorbell. + // + + ScsiPortWritePortUchar(deviceExtension->SystemDoorBell, + ScsiPortReadPortUchar(deviceExtension->SystemDoorBell)); + + // + // Now check again if submission channel is free. + // + + if (ScsiPortReadPortUchar(deviceExtension->LocalDoorBell) & DAC960_LOCAL_DOORBELL_SUBMIT_BUSY) { + + // + // Give up. + // + + break; + } + } + } + + // + // Write command in mailbox. + // + + deviceExtension->MailBox.OperationCode = + DAC960_COMMAND_RESET; + + // + // Write channel number in mailbox. + // + + deviceExtension->MailBox.BlockCount = + (UCHAR)channelNumber; + + // + // Indicate hard reset required. + // + + deviceExtension->MailBox.BlockNumber[0] = 1; + + // + // Start writing mail box to controller. + // + + SendRequest(deviceExtension); + } + + // + // Complete all outstanding requests. + // + + ScsiPortCompleteRequest(deviceExtension, + (UCHAR)-1, + (UCHAR)-1, + (UCHAR)-1, + SRB_STATUS_BUS_RESET); + + // + // Reset submission queue. + // + + deviceExtension->SubmissionQueueHead = NULL; + deviceExtension->SubmissionQueueTail = NULL; + + // + // Clear active request array. + // + + for (i = 0; i < 256; i++) { + deviceExtension->ActiveRequests[i] = NULL; + } + + // + // Indicate no outstanding adapter requests and reset + // active request array index. + // + + deviceExtension->CurrentAdapterRequests = 0; + +#endif + + return TRUE; + +} // end Dac960ResetBus() + +BOOLEAN +Dac960StartIo( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb +) + +/*++ + +Routine Description: + + This routine is called from the SCSI port driver synchronized + with the kernel to start a request. + +Arguments: + + HwDeviceExtension - HBA miniport driver's adapter data storage + Srb - IO request packet + +Return Value: + + TRUE + +--*/ + +{ + PDEVICE_EXTENSION deviceExtension = HwDeviceExtension; + ULONG i; + UCHAR status; + + switch (Srb->Function) { + + case SRB_FUNCTION_EXECUTE_SCSI: + + if (Srb->TargetId & DAC960_SYSTEM_DRIVE) { + + // + // Determine command from CDB operation code. + // + + switch (Srb->Cdb[0]) { + + case SCSIOP_READ: + case SCSIOP_WRITE: + + // + // Check if number of outstanding adapter requests + // equals or exceeds maximum. If not, submit SRB. + // + + if (deviceExtension->CurrentAdapterRequests < + deviceExtension->MaximumAdapterRequests) { + + // + // Send request to controller. + // + + if (SubmitRequest(deviceExtension, Srb)) { + + status = SRB_STATUS_PENDING; + + } else { + + status = SRB_STATUS_BUSY; + } + + } else { + + status = SRB_STATUS_BUSY; + } + + break; + + case SCSIOP_INQUIRY: + + // + // DAC960 only supports LUN 0. + // + + i = (Srb->TargetId & ~DAC960_SYSTEM_DRIVE) + (Srb->Lun << 3); + + if (deviceExtension->AdapterType == DAC960_NEW_ADAPTER) { + if (i >= ((PDAC960_ENQUIRY_3X)deviceExtension->NoncachedExtension)->NumberOfDrives || + Srb->PathId != 0) { + + status = SRB_STATUS_SELECTION_TIMEOUT; + break; + } + } + else { + if (i >= ((PDAC960_ENQUIRY)deviceExtension->NoncachedExtension)->NumberOfDrives || + Srb->PathId != 0) { + + status = SRB_STATUS_SELECTION_TIMEOUT; + break; + } + } + + // + // Fill in inquiry buffer. + // + + ((PUCHAR)Srb->DataBuffer)[0] = 0; + ((PUCHAR)Srb->DataBuffer)[1] = 0; + ((PUCHAR)Srb->DataBuffer)[2] = 1; + ((PUCHAR)Srb->DataBuffer)[3] = 0; + ((PUCHAR)Srb->DataBuffer)[4] = 0x20; + ((PUCHAR)Srb->DataBuffer)[5] = 0; + ((PUCHAR)Srb->DataBuffer)[6] = 0; + ((PUCHAR)Srb->DataBuffer)[7] = 0; + ((PUCHAR)Srb->DataBuffer)[8] = 'M'; + ((PUCHAR)Srb->DataBuffer)[9] = 'Y'; + ((PUCHAR)Srb->DataBuffer)[10] = 'L'; + ((PUCHAR)Srb->DataBuffer)[11] = 'E'; + ((PUCHAR)Srb->DataBuffer)[12] = 'X'; + ((PUCHAR)Srb->DataBuffer)[13] = ' '; + ((PUCHAR)Srb->DataBuffer)[14] = 'D'; + ((PUCHAR)Srb->DataBuffer)[15] = 'A'; + ((PUCHAR)Srb->DataBuffer)[16] = 'C'; + ((PUCHAR)Srb->DataBuffer)[17] = '9'; + ((PUCHAR)Srb->DataBuffer)[18] = '6'; + ((PUCHAR)Srb->DataBuffer)[19] = '0'; + + for (i = 20; i < Srb->DataTransferLength; i++) { + ((PUCHAR)Srb->DataBuffer)[i] = ' '; + } + + status = SRB_STATUS_SUCCESS; + break; + + case SCSIOP_READ_CAPACITY: + + // + // Fill in read capacity data. + // + + i = (Srb->TargetId & ~DAC960_SYSTEM_DRIVE) + (Srb->Lun << 3); + + if (deviceExtension->AdapterType == DAC960_NEW_ADAPTER) { + + REVERSE_BYTES(&((PREAD_CAPACITY_DATA)Srb->DataBuffer)->LogicalBlockAddress, + &(((PDAC960_ENQUIRY_3X)deviceExtension->NoncachedExtension)->SectorSize[i])); + } + else { + REVERSE_BYTES(&((PREAD_CAPACITY_DATA)Srb->DataBuffer)->LogicalBlockAddress, + &(((PDAC960_ENQUIRY)deviceExtension->NoncachedExtension)->SectorSize[i])); + } + + ((PUCHAR)Srb->DataBuffer)[4] = 0; + ((PUCHAR)Srb->DataBuffer)[5] = 0; + ((PUCHAR)Srb->DataBuffer)[6] = 2; + ((PUCHAR)Srb->DataBuffer)[7] = 0; + + // + // Fall through to common code. + // + + case SCSIOP_VERIFY: + + // + // Complete this request. + // + + status = SRB_STATUS_SUCCESS; + break; + + default: + + // + // Fail this request. + // + + DebugPrint((1, + "Dac960StartIo: SCSI CDB opcode %x not handled\n", + Srb->Cdb[0])); + + status = SRB_STATUS_INVALID_REQUEST; + break; + + } // end switch (Srb->Cdb[0]) + + break; + + } else { + + // + // These are passthrough requests. Only accept request to LUN 0. + // This is because the DAC960 direct CDB interface does not include + // a field for LUN. + // + + if ((Srb->Lun != 0) || + (deviceExtension->DeviceList[Srb->PathId][Srb->TargetId] != DAC960_DEVICE_ACCESSIBLE)) { + status = SRB_STATUS_SELECTION_TIMEOUT; + break; + } + +#ifdef GAM_SUPPORT + + if ((Srb->PathId == 0) && (Srb->TargetId == 6)) { + + switch (Srb->Cdb[0]) { + + case SCSIOP_INQUIRY: + + // + // Fill in inquiry buffer for the GAM device. + // + + ((PUCHAR)Srb->DataBuffer)[0] = 0x03; // Processor device + ((PUCHAR)Srb->DataBuffer)[1] = 0; + ((PUCHAR)Srb->DataBuffer)[2] = 1; + ((PUCHAR)Srb->DataBuffer)[3] = 0; + ((PUCHAR)Srb->DataBuffer)[4] = 0x20; + ((PUCHAR)Srb->DataBuffer)[5] = 0; + ((PUCHAR)Srb->DataBuffer)[6] = 0; + ((PUCHAR)Srb->DataBuffer)[7] = 0; + ((PUCHAR)Srb->DataBuffer)[8] = 'M'; + ((PUCHAR)Srb->DataBuffer)[9] = 'Y'; + ((PUCHAR)Srb->DataBuffer)[10] = 'L'; + ((PUCHAR)Srb->DataBuffer)[11] = 'E'; + ((PUCHAR)Srb->DataBuffer)[12] = 'X'; + ((PUCHAR)Srb->DataBuffer)[13] = ' '; + ((PUCHAR)Srb->DataBuffer)[14] = ' '; + ((PUCHAR)Srb->DataBuffer)[15] = ' '; + ((PUCHAR)Srb->DataBuffer)[16] = 'G'; + ((PUCHAR)Srb->DataBuffer)[17] = 'A'; + ((PUCHAR)Srb->DataBuffer)[18] = 'M'; + ((PUCHAR)Srb->DataBuffer)[19] = ' '; + ((PUCHAR)Srb->DataBuffer)[20] = 'D'; + ((PUCHAR)Srb->DataBuffer)[21] = 'E'; + ((PUCHAR)Srb->DataBuffer)[22] = 'V'; + ((PUCHAR)Srb->DataBuffer)[23] = 'I'; + ((PUCHAR)Srb->DataBuffer)[24] = 'C'; + ((PUCHAR)Srb->DataBuffer)[25] = 'E'; + + for (i = 26; i < Srb->DataTransferLength; i++) { + ((PUCHAR)Srb->DataBuffer)[i] = ' '; + } + + status = SRB_STATUS_SUCCESS; + break; + + default: + status = SRB_STATUS_SELECTION_TIMEOUT; + break; + } + + break; + } +#endif + + // + // Check if number of outstanding adapter requests + // equals or exceeds maximum. If not, submit SRB. + // + + if (deviceExtension->CurrentAdapterRequests < + deviceExtension->MaximumAdapterRequests) { + + // + // Send request to controller. + // + + if (SubmitCdbDirect(deviceExtension, Srb)) { + + status = SRB_STATUS_PENDING; + + } else { + + status = SRB_STATUS_BUSY; + } + + } else { + + status = SRB_STATUS_BUSY; + } + + break; + } + + case SRB_FUNCTION_FLUSH: + case SRB_FUNCTION_SHUTDOWN: + + // + // Issue flush command to controller. + // + + if (!SubmitRequest(deviceExtension, Srb)) { + + status = SRB_STATUS_BUSY; + + } else { + + status = SRB_STATUS_PENDING; + } + + break; + + case SRB_FUNCTION_ABORT_COMMAND: + + // + // If the request is for Non-Disk device, do soft reset. + // + + if ( !(Srb->TargetId & DAC960_SYSTEM_DRIVE)) { + + // + // Issue request to soft reset Non-Disk device. + // + + if (Dac960ResetChannel(deviceExtension, + Srb->NextSrb->PathId)) { + + // + // Set the flag to indicate that we are handling abort + // Request, so do not ask for new requests. + // + + deviceExtension->NextRequest = FALSE; + + status = SRB_STATUS_PENDING; + + } else { + + status = SRB_STATUS_ABORT_FAILED; + } + } + else { + + // + // There is nothing the miniport can do, if logical drive + // requests are timing out. Resetting the channel does not help. + // It only makes the situation worse. + // + + // + // Indicate that the abort failed. + // + + status = SRB_STATUS_ABORT_FAILED; + } + + break; + + case SRB_FUNCTION_RESET_BUS: + case SRB_FUNCTION_RESET_DEVICE: + + // + // There is nothing the miniport can do by issuing Hard Resets on + // Dac960 SCSI channels. + // + + // + // Set the flag to indicate that we are handling Reset request, + // so do not ask for new requests. + // + + deviceExtension->NextRequest = FALSE; + + status = SRB_STATUS_SUCCESS; + + break; + + case SRB_FUNCTION_IO_CONTROL: + + DebugPrint((0, "DAC960: Ioctl\n")); + + // + // Check if number of outstanding adapter requests + // equals or exceeds maximum. If not, submit SRB. + // + + if (deviceExtension->CurrentAdapterRequests < + deviceExtension->MaximumAdapterRequests) { + + PIOCTL_REQ_HEADER ioctlReqHeader = + (PIOCTL_REQ_HEADER)Srb->DataBuffer; + + // + // Send request to controller. + // + + switch (ioctlReqHeader->GenMailBox.Reg0) { + case MIOC_ADP_INFO: + + SetupAdapterInfo(deviceExtension, Srb); + + status = SRB_STATUS_SUCCESS; + break; + + case MIOC_DRIVER_VERSION: + + SetupDriverVersionInfo(deviceExtension, Srb); + + status = SRB_STATUS_SUCCESS; + break; + + case DAC960_COMMAND_DIRECT: + + if (SendIoctlCdbDirect(deviceExtension, Srb)) { + + status = SRB_STATUS_PENDING; + + } else { + ioctlReqHeader->DriverErrorCode = + DAC_IOCTL_RESOURCE_ALLOC_FAILURE; + + status = SRB_STATUS_SUCCESS; + } + + break; + + default: + + if (SendIoctlDcmdRequest(deviceExtension, Srb)) { + + status = SRB_STATUS_PENDING; + + } else { + ioctlReqHeader->DriverErrorCode = + DAC_IOCTL_RESOURCE_ALLOC_FAILURE; + + status = SRB_STATUS_SUCCESS; + } + + break; + } + + } else { + + status = SRB_STATUS_BUSY; + } + + break; + + default: + + // + // Fail this request. + // + + DebugPrint((1, + "Dac960StartIo: SRB fucntion %x not handled\n", + Srb->Function)); + + status = SRB_STATUS_INVALID_REQUEST; + break; + + } // end switch + + // + // Check if this request is complete. + // + + if (status == SRB_STATUS_PENDING) { + + // + // Record SRB in active request array. + // + + deviceExtension->ActiveRequests[deviceExtension->CurrentIndex] = Srb; + + // + // Bump the count of outstanding adapter requests. + // + + deviceExtension->CurrentAdapterRequests++; + + // + // Advance active request index array. + // + + deviceExtension->CurrentIndex++; + + } else if (status == SRB_STATUS_BUSY) { + + // + // Check that there are outstanding requests to thump + // the queue. + // + + if (deviceExtension->CurrentAdapterRequests) { + + // + // Queue SRB for resubmission. + // + + if (!deviceExtension->SubmissionQueueHead) { + deviceExtension->SubmissionQueueHead = Srb; + deviceExtension->SubmissionQueueTail = Srb; + } else { + deviceExtension->SubmissionQueueTail->NextSrb = Srb; + deviceExtension->SubmissionQueueTail = Srb; + } + + status = SRB_STATUS_PENDING; + } + + } else { + + // + // Notify system of request completion. + // + + Srb->SrbStatus = status; + ScsiPortNotification(RequestComplete, + deviceExtension, + Srb); + } + + // + // Check if this is a request to a system drive. Indicating + // ready for next logical unit request causes the system to + // send overlapped requests to this device (tag queuing). + // + // The DAC960 only supports a single outstanding direct CDB + // request per device, so indicate ready for next adapter request. + // + + if (deviceExtension->NextRequest) { + + if (Srb->TargetId & DAC960_SYSTEM_DRIVE) { + + // + // Indicate ready for next logical unit request. + // + + ScsiPortNotification(NextLuRequest, + deviceExtension, + Srb->PathId, + Srb->TargetId, + Srb->Lun); + } else { + + // + // Indicate ready for next adapter request. + // + + ScsiPortNotification(NextRequest, + deviceExtension, + Srb->PathId, + Srb->TargetId, + Srb->Lun); + } + } + + return TRUE; + +} // end Dac960StartIo() + +BOOLEAN +Dac960CheckInterrupt( + IN PDEVICE_EXTENSION DeviceExtension, + OUT PUSHORT Status, + OUT PUCHAR Index +) + +/*++ + +Routine Description: + + This routine reads interrupt register to determine if the adapter is + indeed the source of the interrupt, and if so clears interrupt and + returns command completion status and command index. + +Arguments: + + DeviceExtension - HBA miniport driver's adapter data storage + Status - DAC960 Command completion status. + Index - DAC960 Command index. + +Return Value: + + TRUE if the adapter is interrupting. + FALSE if the adapter is not the source of the interrupt. + +--*/ + +{ + + if(DeviceExtension->AdapterInterfaceType == MicroChannel) { + + if (ScsiPortReadPortUchar(DeviceExtension->SystemDoorBell) & + DMC960_INTERRUPT_VALID) { + // + // The adapter is indeed the source of the interrupt. + // Set 'Clear Interrupt Valid Bit on read' in subsystem + // control port. + // + + ScsiPortWritePortUchar(DeviceExtension->BaseIoAddress + + DMC960_SUBSYSTEM_CONTROL_PORT, + (DMC960_ENABLE_INTERRUPT | DMC960_CLEAR_INTERRUPT_ON_READ)); + + // + // Read index, status and error of completing command. + // + + *Index = ScsiPortReadRegisterUchar(&DeviceExtension->PmailBox->CommandIdComplete); + *Status = ScsiPortReadRegisterUshort(&DeviceExtension->PmailBox->Status); + + // + // Dismiss interrupt and tell host mailbox is free. + // + + ScsiPortReadPortUchar(DeviceExtension->SystemDoorBell); + + // + // status accepted acknowledgement. + // + + ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell, + DMC960_ACKNOWLEDGE_STATUS); + + // + // Set 'Not to Clear Interrupt Valid Bit on read' bits in subsystem + // control port. + // + + ScsiPortWritePortUchar(DeviceExtension->BaseIoAddress + + DMC960_SUBSYSTEM_CONTROL_PORT, + DMC960_ENABLE_INTERRUPT); + } + else { + return FALSE; + } + + } + else { + + // + // Check for command complete. + // + + if (!(ScsiPortReadPortUchar(DeviceExtension->SystemDoorBell) & + DAC960_SYSTEM_DOORBELL_COMMAND_COMPLETE)) { + return FALSE; + } + + // + // Read index, status and error of completing command. + // + + *Index = ScsiPortReadPortUchar(&DeviceExtension->PmailBox->CommandIdComplete); + *Status = ScsiPortReadPortUshort(&DeviceExtension->PmailBox->Status); + + // + // Dismiss interrupt and tell host mailbox is free. + // + + ScsiPortWritePortUchar(DeviceExtension->SystemDoorBell, + ScsiPortReadPortUchar(DeviceExtension->SystemDoorBell)); + + ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell, + DAC960_LOCAL_DOORBELL_MAILBOX_FREE); + + // + } + + return TRUE; +} + +BOOLEAN +Dac960Interrupt( + IN PVOID HwDeviceExtension +) + +/*++ + +Routine Description: + + This is the interrupt service routine for the DAC960 SCSI adapter. + It reads the interrupt register to determine if the adapter is indeed + the source of the interrupt and clears the interrupt at the device. + +Arguments: + + HwDeviceExtension - HBA miniport driver's adapter data storage + +Return Value: + + TRUE if we handled the interrupt + +--*/ + +{ + PDEVICE_EXTENSION deviceExtension = HwDeviceExtension; + PSCSI_REQUEST_BLOCK srb; + PSCSI_REQUEST_BLOCK restartList; + USHORT status; + UCHAR index; + + // + // Determine if the adapter is indeed the source of interrupt. + // + + if(! Dac960CheckInterrupt(deviceExtension, + &status, + &index)) { + return FALSE; + } + + // + // Get SRB. + // + + srb = deviceExtension->ActiveRequests[index]; + + if (!srb) { + DebugPrint((1, + "Dac960Interrupt: No active SRB for index %x\n", + index)); + return TRUE; + } + + if (status != 0) { + + // + // Map DAC960 error to SRB status. + // + + switch (status) { + + case DAC960_STATUS_CHECK_CONDITION: + + if (srb->TargetId & DAC960_SYSTEM_DRIVE) { + + // + // This request was to a system drive. + // + + srb->SrbStatus = SRB_STATUS_NO_DEVICE; + + } else { + + PDIRECT_CDB directCdb; + ULONG requestSenseLength; + ULONG i; + + // + // Get address of direct CDB packet. + // + + directCdb = + (PDIRECT_CDB)((PUCHAR)srb->SrbExtension + + MAXIMUM_SGL_DESCRIPTORS * sizeof(SG_DESCRIPTOR)); + + // + // This request was a pass-through. + // Copy request sense buffer to SRB. + // + + requestSenseLength = + srb->SenseInfoBufferLength < + directCdb->RequestSenseLength ? + srb->SenseInfoBufferLength: + directCdb->RequestSenseLength; + + for (i = 0; + i < requestSenseLength; + i++) { + + ((PUCHAR)srb->SenseInfoBuffer)[i] = + directCdb->RequestSenseData[i]; + } + + // + // Set statuses to indicate check condition and valid + // request sense information. + // + + srb->SrbStatus = SRB_STATUS_ERROR | SRB_STATUS_AUTOSENSE_VALID; + srb->ScsiStatus = SCSISTAT_CHECK_CONDITION; + } + + break; + + case DAC960_STATUS_BUSY: + srb->SrbStatus = SRB_STATUS_BUSY; + break; + + case DAC960_STATUS_SELECT_TIMEOUT: + case DAC960_STATUS_DEVICE_TIMEOUT: + srb->SrbStatus = SRB_STATUS_SELECTION_TIMEOUT; + break; + + case DAC960_STATUS_NOT_IMPLEMENTED: + case DAC960_STATUS_BOUNDS_ERROR: + srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; + break; + + case DAC960_STATUS_ERROR: + if (srb->TargetId & DAC960_SYSTEM_DRIVE) + { + if(srb->SenseInfoBufferLength) + { + ULONG i; + + for (i = 0; i < srb->SenseInfoBufferLength; i++) + ((PUCHAR)srb->SenseInfoBuffer)[i] = 0; + + ((PSENSE_DATA) srb->SenseInfoBuffer)->ErrorCode = 0x70; + ((PSENSE_DATA) srb->SenseInfoBuffer)->SenseKey = SCSI_SENSE_MEDIUM_ERROR; + + if (srb->SrbFlags & SRB_FLAGS_DATA_IN) + ((PSENSE_DATA) srb->SenseInfoBuffer)->AdditionalSenseCode = 0x11; + + srb->SrbStatus = SRB_STATUS_ERROR | SRB_STATUS_AUTOSENSE_VALID; + + DebugPrint((0, + "DAC960: System Drive %d, cmd sts = 1, sense info returned\n", + ((srb->TargetId & ~DAC960_SYSTEM_DRIVE) + (srb->Lun << 3)))); + + } + else + { + DebugPrint((0, + "DAC960: System Drive %d, cmd sts = 1, sense info length 0\n", + ((srb->TargetId & ~DAC960_SYSTEM_DRIVE) + (srb->Lun << 3)))); + + + srb->SrbStatus = SRB_STATUS_ERROR; + } + } + else { + DebugPrint((0, + "DAC960: SCSI Target Id %x, cmd sts = 1\n", + srb->TargetId)); + + srb->SrbStatus = SRB_STATUS_ERROR; + } + + break; + + default: + + DebugPrint((1, + "DAC960: Unrecognized status %x\n", + status)); + + srb->SrbStatus = SRB_STATUS_ERROR; + + break; + } + + // + // Check for IOCTL request. + // + + if (srb->Function == SRB_FUNCTION_IO_CONTROL) { + + // + // Update status in IOCTL header. + // + + ((PIOCTL_REQ_HEADER)srb->DataBuffer)->CompletionCode = status; + srb->SrbStatus = SRB_STATUS_SUCCESS; + } + + } else { + + srb->SrbStatus = SRB_STATUS_SUCCESS; + } + + // + // Determine if we were to abort this request and a SCSI Bus Reset + // occured while this request was being executed. If so, set Srb + // status field to reflect the scenerio. + // + + if (deviceExtension->NextRequest == FALSE) { + srb->SrbStatus = SRB_STATUS_BUS_RESET; + } + + // + // Complete request. + // + + ScsiPortNotification(RequestComplete, + deviceExtension, + srb); + + // + // Indicate this index is free. + // + + deviceExtension->ActiveRequests[index] = NULL; + + // + // Decrement count of outstanding adapter requests. + // + + deviceExtension->CurrentAdapterRequests--; + + // + // Check to see if we are done handling SCSI Reset. If so set the + // flag to indicate that the new requests can be processed. + // + + if (! deviceExtension->CurrentAdapterRequests) + deviceExtension->NextRequest = TRUE; + + // + // Check to see if a new request can be sent to controller. + // + + if (deviceExtension->NextRequest) { + + // + // Start requests that timed out waiting for controller to become ready. + // + + restartList = deviceExtension->SubmissionQueueHead; + deviceExtension->SubmissionQueueHead = NULL; + + while (restartList) { + + // + // Get next pending request. + // + + srb = restartList; + + // + // Check if this request exceeds maximum for this adapter. + // + + if (deviceExtension->CurrentAdapterRequests >= + deviceExtension->MaximumAdapterRequests) { + + continue; + } + + // + // Remove request from pending queue. + // + + restartList = srb->NextSrb; + srb->NextSrb = NULL; + + // + // Start request over again. + // + + Dac960StartIo(deviceExtension, + srb); + } + } + + return TRUE; + +} // end Dac960Interrupt() + +ULONG +DriverEntry ( + IN PVOID DriverObject, + IN PVOID Argument2 +) + +/*++ + +Routine Description: + + Installable driver initialization entry point for system. + It scans the EISA slots looking for DAC960 host adapters. + +Arguments: + + Driver Object + +Return Value: + + Status from ScsiPortInitialize() + +--*/ + +{ + HW_INITIALIZATION_DATA hwInitializationData; + ULONG i; + ULONG SlotNumber; + ULONG Status1, Status2; + UCHAR vendorId[4] = {'1', '0', '6', '9'}; + UCHAR deviceId[4] = {'0', '0', '0', '1'}; + + DebugPrint((1,"\nDAC960 SCSI Miniport Driver\n")); + + // Zero out structure. + + for (i=0; i= 3.x +#define DAC960_COMMAND_WRITE 0x03 // DAC960 Fw Ver < 3.x +#define DAC960_COMMAND_WRITE_EXT 0x34 // DAC960 Fw Ver >= 3.x +#define DAC960_COMMAND_DIRECT 0x04 +#define DAC960_COMMAND_ENQUIRE 0x05 // DAC960 Fw Ver < 3.x +#define DAC960_COMMAND_ENQUIRE_3X 0x53 // DAC960 Fw Ver >= 3.x +#define DAC960_COMMAND_FLUSH 0x0A +#define DAC960_COMMAND_RESET 0x1A +#define DAC960_COMMAND_ENQUIRE2 0x1C +#define DAC960_COMMAND_SG 0x80 +#define DAC960_COMMAND_EXTENDED 0x31 // DAC960 Fw Ver >= 3.x + +// +// Define BIOS enabled bit +// + +#define DAC960_BIOS_ENABLED 0x40 + +// +// Scatter Gather List +// + +typedef struct _SG_DESCRIPTOR { + ULONG Address; + ULONG Length; +} SG_DESCRIPTOR, *PSG_DESCRIPTOR; + +typedef struct _SGL { + SG_DESCRIPTOR Descriptor[1]; +} SGL, *PSGL; + +// +// Enquiry data, DAC960 Fw < 3.x +// + +typedef struct _DAC960_ENQUIRY { + UCHAR NumberOfDrives; // 00 + UCHAR Unused1[3]; // 01 + ULONG SectorSize[8]; // 04 + USHORT NumberOfFlashes; // 36 + UCHAR StatusFlags; // 38 + UCHAR FreeStateChangeCount; // 39 + UCHAR MinorFirmwareRevision; // 40 + UCHAR MajorFirmwareRevision; // 41 + UCHAR RebuildFlag; // 42 + UCHAR NumberOfConcurrentCommands; // 43 + UCHAR NumberOfOfflineDrives; // 44 + UCHAR Unused2[3]; // 45 + UCHAR NumberOfCriticalDrives; // 48 + UCHAR Unused3[3]; // 49 + UCHAR NumberOfDeadDisks; // 52 + UCHAR Unused4; // 53 + UCHAR NumberOfRebuildingDisks; // 54 + UCHAR MiscellaneousFlags; // 55 +} DAC960_ENQUIRY, *PDAC960_ENQUIRY; + +// +// Enquiry data, DAC960 Fw >= 3.x +// + +typedef struct _DAC960_ENQUIRY_3X { + UCHAR NumberOfDrives; // 00 + UCHAR Unused1[3]; // 01 + ULONG SectorSize[32]; // 04 + USHORT NumberOfFlashes; // 100 + UCHAR StatusFlags; // 102 + UCHAR FreeStateChangeCount; // 103 + UCHAR MinorFirmwareRevision; // 104 + UCHAR MajorFirmwareRevision; // 105 + UCHAR RebuildFlag; // 106 + UCHAR NumberOfConcurrentCommands; // 107 + UCHAR NumberOfOfflineDrives; // 108 + UCHAR Unused2[3]; // 109 + UCHAR NumberOfCriticalDrives; // 112 + UCHAR Unused3[3]; // 113 + UCHAR NumberOfDeadDisks; // 116 + UCHAR Unused4; // 117 + UCHAR NumberOfRebuildingDisks; // 118 + UCHAR MiscellaneousFlags; // 119 +} DAC960_ENQUIRY_3X, *PDAC960_ENQUIRY_3X; + + +// +// Pass-through command +// + +typedef struct _DIRECT_CDB { + UCHAR TargetId:4; // 00 (bits 0-3) + UCHAR Channel:4; // 00 (bits 4-7) + UCHAR CommandControl; // 01 + USHORT DataTransferLength; // 02 + ULONG DataBufferAddress; // 04 + UCHAR CdbLength; // 08 + UCHAR RequestSenseLength; // 09 + UCHAR Cdb[12]; // 10 + UCHAR RequestSenseData[64]; // 22 + UCHAR Status; // 86 + UCHAR Reserved; // 87 +} DIRECT_CDB, *PDIRECT_CDB; + +// +// Direct CDB command control bit definitions +// + +#define DAC960_CONTROL_ENABLE_DISCONNECT 0x80 +#define DAC960_CONTROL_DISABLE_REQUEST_SENSE 0x40 +#define DAC960_CONTROL_DATA_IN 0x01 +#define DAC960_CONTROL_DATA_OUT 0x02 +#define DAC960_CONTROL_TIMEOUT_10_SECS 0x10 +#define DAC960_CONTROL_TIMEOUT_60_SECS 0x20 +#define DAC960_CONTROL_TIMEOUT_20_MINUTES 0x30 + + +// +// Enquire 2 structure +// + +typedef struct _ENQUIRE2 { + ULONG Reserved1; + ULONG EisaId; + ULONG InterruptMode:1; + ULONG Unused1:31; + UCHAR ConfiguredChannels; + UCHAR ActualChannels; + UCHAR MaximumTargets; + UCHAR MaximumTags; + UCHAR MaximumSystemDrives; + UCHAR MaximumDrivesPerStripe; + UCHAR MaximumSpansPerSystemDrive; + UCHAR Reserved2[5]; + ULONG DramSize; + UCHAR DramForCache[5]; + UCHAR SizeOfFlash[3]; + ULONG SizeOfNvram; + ULONG Reserved3[5]; + USHORT PhysicalSectorSize; + USHORT LogicalSectorSize; + USHORT MaximumSectorsPerCommand; + USHORT BlockingFactor; + USHORT CacheLineSize; +} ENQUIRE2, *PENQUIRE2; + +// +// Device extension +// + +typedef struct _DEVICE_EXTENSION { + + // + // DAC960 register base address + // + + PUCHAR BaseIoAddress; + + // + // Command submission mailbox address + // + + PMAILBOX PmailBox; + + // + // Mailbox structure space + // + + MAILBOX MailBox; + + // + // System doorbell address + // + + PUCHAR SystemDoorBell; + + // + // Local doorbell address + // + + PUCHAR LocalDoorBell; + + // + // Noncached extension + // + + PDAC960_ENQUIRY NoncachedExtension; + + // + // Pending request queue + // + + PSCSI_REQUEST_BLOCK SubmissionQueueHead; + PSCSI_REQUEST_BLOCK SubmissionQueueTail; + + // + // Maximum number of outstanding requests per adapter + // + + UCHAR MaximumAdapterRequests; + + // + // Current number of outstanding requests per adapter + // + + UCHAR CurrentAdapterRequests; + + // + // Last active request index used + // + + UCHAR CurrentIndex; + + // + // HBA Slot number. + // + + UCHAR Slot; + + // + // Number of SCSI channels. (Used for resetting adapter.) + // + + ULONG NumberOfChannels; + + // + // System I/O Bus Number. + // + + ULONG SystemIoBusNumber; + + // + // Host Bus Adapter Interface Type. + // + + INTERFACE_TYPE AdapterInterfaceType; + + // + // Host Bus Adapter Interrupt Level. + // + + ULONG BusInterruptLevel; + + // + // Adapter Interrupt Mode: Level/Latched. + // + + KINTERRUPT_MODE InterruptMode; + + // + // BIOS Base Address. + // + + PUCHAR BaseBiosAddress; + + // + // Adapter Type (DAC960 PCI device id 0x0002 - new adapter, else old) + // + + ULONG AdapterType; + + // + // Active request pointers + // + + PSCSI_REQUEST_BLOCK ActiveRequests[256]; + + // + // DMC960 POS Registers. + // + + POS_DATA PosData; + + // + // Flag to indicate, if we should send a new command to controller + // and ask for new request. To handle Abort/SCSI Bus Reset Scenerio. + // + + BOOLEAN NextRequest; + + // + // Contains List Of Physical Devices that are accessible + // + + UCHAR DeviceList[MAXIMUM_CHANNELS][MAXIMUM_TARGETS_PER_CHANNEL]; + + +} DEVICE_EXTENSION, *PDEVICE_EXTENSION; + + diff --git a/private/ntos/miniport/mylex/dac960/dac960nt.rc b/private/ntos/miniport/mylex/dac960/dac960nt.rc new file mode 100644 index 000000000..14b1baf2a --- /dev/null +++ b/private/ntos/miniport/mylex/dac960/dac960nt.rc @@ -0,0 +1,38 @@ +#include + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "DAC960 SCSI Controller Driver" +#define VER_INTERNALNAME_STR "DAC960NT.sys" +#define VER_ORIGINALFILENAME_STR "DAC960NT.sys" + +#ifdef VER_COMPANYNAME_STR +#undef VER_COMPANYNAME_STR +#endif + +#define VER_COMPANYNAME_STR "Mylex Corporation" +#define VER_LEGALCOPYRIGHT_YEARS "1994-1995" +#define VER_LEGALCOPYRIGHT_STR "Copyright \251 Mylex Corp. " VER_LEGALCOPYRIGHT_YEARS + +#ifdef VER_PRODUCTNAME_STR +#undef VER_PRODUCTNAME_STR +#endif + +#define VER_PRODUCTNAME_STR "Mylex DAC960 SCSI RAID Controller" + +#ifdef VER_PRODUCTVERSION_STR +#undef VER_PRODUCTVERSION_STR +#endif + +#define VER_PRODUCTVERSION_STR "4.02" + +#ifdef VER_PRODUCTVERSION +#undef VER_PRODUCTVERSION +#endif + +#define VER_PRODUCTVERSION 4,02,00 + +#include "common.ver" + diff --git a/private/ntos/miniport/mylex/dac960/dacioctl.c b/private/ntos/miniport/mylex/dac960/dacioctl.c new file mode 100644 index 000000000..dcccc92d4 --- /dev/null +++ b/private/ntos/miniport/mylex/dac960/dacioctl.c @@ -0,0 +1,525 @@ +/*++ + +Copyright (c) 1994 Microsoft Corporation + +Module Name: + + Dacioctl.c + +Abstract: + + This module provides support for DAC960 configuration IOCTls. + +Author: + + Mouli (mouli@mylex.com) + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#include "miniport.h" +#include "Dmc960Nt.h" +#include "Dac960Nt.h" +#include "d960api.h" + +BOOLEAN +SubmitRequest( + IN PDEVICE_EXTENSION DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb +); + +BOOLEAN +SubmitCdbDirect( + IN PDEVICE_EXTENSION DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb +); + +BOOLEAN +IsAdapterReady( + IN PDEVICE_EXTENSION DeviceExtension +); + +VOID +SendRequest( + IN PDEVICE_EXTENSION DeviceExtension +); + +VOID +SendCdbDirect( + IN PDEVICE_EXTENSION DeviceExtension +); + +BOOLEAN +SendIoctlDcmdRequest( + IN PDEVICE_EXTENSION DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb +) + +/*++ + +Routine Description: + + Build and submit IOCTL Request-DAC960(Non-DCDB) command to DAC960. + +Arguments: + + DeviceExtension - Adapter state. + SRB - System request. + +Return Value: + + TRUE if command was started + FALSE if host adapter is busy + +--*/ + +{ + ULONG physicalAddress; + PIOCTL_REQ_HEADER IoctlReqHeader; + ULONG i; + UCHAR busyCurrentIndex; + + // + // Determine if adapter can accept new request. + // + + if(!IsAdapterReady(DeviceExtension)) { + return FALSE; + } + + // + // Check that next slot is vacant. + // + + if (DeviceExtension->ActiveRequests[DeviceExtension->CurrentIndex]) { + + // + // Collision occurred. + // + + busyCurrentIndex = DeviceExtension->CurrentIndex++; + + do { + if (! DeviceExtension->ActiveRequests[DeviceExtension->CurrentIndex]) { + break; + } + } while (++DeviceExtension->CurrentIndex != busyCurrentIndex) ; + + if (DeviceExtension->CurrentIndex == busyCurrentIndex) { + + // + // We should never encounter this condition. + // + + DebugPrint((0, + "DAC960: SendIoctlDcmdRequest-Collision in active request array\n")); + + return FALSE; + } + } + + IoctlReqHeader = (PIOCTL_REQ_HEADER) Srb->DataBuffer; + + physicalAddress = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress(DeviceExtension, + Srb, + ((PUCHAR)Srb->DataBuffer + + sizeof(IOCTL_REQ_HEADER)), + &i)); + + // + // The buffer passed in may not be physically contiguous. + // + + if (i < Srb->DataTransferLength - sizeof(IOCTL_REQ_HEADER)) { + DebugPrint((1, + "Dac960: DCMD IOCTL buffer is not contiguous\n")); + return FALSE; + } + + // + // Write physical address in mailbox. + // + + DeviceExtension->MailBox.PhysicalAddress = physicalAddress; + + // + // Write command in mailbox. + // + + DeviceExtension->MailBox.OperationCode = + IoctlReqHeader->GenMailBox.Reg0; + + // + // Write request in mailbox. + // + + DeviceExtension->MailBox.CommandIdSubmit = + DeviceExtension->CurrentIndex; + + // + // Write Mail Box Registers 2 and 3. + // + + DeviceExtension->MailBox.BlockCount = (USHORT) + (IoctlReqHeader->GenMailBox.Reg2 | + (IoctlReqHeader->GenMailBox.Reg3 << 8)); + + // + // Write Mail Box Registers 4, 5 and 6. + // + + DeviceExtension->MailBox.BlockNumber[0] = + IoctlReqHeader->GenMailBox.Reg4; + + DeviceExtension->MailBox.BlockNumber[1] = + IoctlReqHeader->GenMailBox.Reg5; + + DeviceExtension->MailBox.BlockNumber[2] = + IoctlReqHeader->GenMailBox.Reg6; + + // + // Write Mail Box Register 7. + // + + DeviceExtension->MailBox.DriveNumber = + IoctlReqHeader->GenMailBox.Reg7; + + // + // Write Mail Box Register C. + // + + DeviceExtension->MailBox.ScatterGatherCount = + IoctlReqHeader->GenMailBox.RegC; + + // + // Start writing mailbox to controller. + // + + SendRequest(DeviceExtension); + + return(TRUE); + +} // SendIoctlDcmdRequest() + + +BOOLEAN +SendIoctlCdbDirect( + IN PDEVICE_EXTENSION DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb +) + +/*++ + +Routine Description: + + Send IOCTL Request-CDB directly to device. + +Arguments: + + DeviceExtension - Adapter state. + SRB - System request. + +Return Value: + + TRUE if command was started + FALSE if host adapter is busy + +--*/ + +{ + ULONG physicalAddress; + PDIRECT_CDB directCdb; + PIOCTL_REQ_HEADER IoctlReqHeader; + ULONG i; + UCHAR busyCurrentIndex; + + // + // Determine if adapter can accept new request. + // + + if(!IsAdapterReady(DeviceExtension)) { + return FALSE; + } + + // + // Check that next slot is vacant. + // + + if (DeviceExtension->ActiveRequests[DeviceExtension->CurrentIndex]) { + + // + // Collision occurred. + // + + busyCurrentIndex = DeviceExtension->CurrentIndex++; + + do { + if (! DeviceExtension->ActiveRequests[DeviceExtension->CurrentIndex]) { + break; + } + } while (++DeviceExtension->CurrentIndex != busyCurrentIndex) ; + + if (DeviceExtension->CurrentIndex == busyCurrentIndex) { + + // + // We should never encounter this condition. + // + + DebugPrint((0, + "DAC960: SendIoctlCdbDirect-Collision in active request array\n")); + + return FALSE; + } + } + + IoctlReqHeader = (PIOCTL_REQ_HEADER) Srb->DataBuffer; + + directCdb = + (PDIRECT_CDB)((PUCHAR)Srb->DataBuffer + sizeof(IOCTL_REQ_HEADER)); + + // + // Get address of data buffer offset. + // + + physicalAddress = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress(DeviceExtension, + Srb, + ((PUCHAR)Srb->DataBuffer + + sizeof(IOCTL_REQ_HEADER) + + sizeof(DIRECT_CDB)), + &i)); + + // + // The buffer passed in may not be physically contiguous. + // + + if (i < Srb->DataTransferLength - + (sizeof(IOCTL_REQ_HEADER) + sizeof(DIRECT_CDB))) { + DebugPrint((1, + "Dac960: DCDB IOCTL buffer is not contiguous\n")); + return FALSE; + } + + directCdb->DataBufferAddress = physicalAddress; + + if (directCdb->DataTransferLength == 0) { + + // + // mask off data xfer in/out bits + // + + directCdb->CommandControl &= ~(DAC960_CONTROL_DATA_IN | + DAC960_CONTROL_DATA_OUT); + } + + // + // Disable Early-status on command bit + // + + directCdb->CommandControl &= 0xfb; + + // + // Get physical address of direct CDB packet. + // + + physicalAddress = + ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress(DeviceExtension, + Srb, + directCdb, + &i)); + + // + // Write physical address in mailbox. + // + + DeviceExtension->MailBox.PhysicalAddress = physicalAddress; + + // + // Write command in mailbox. + // + + DeviceExtension->MailBox.OperationCode = + IoctlReqHeader->GenMailBox.Reg0; + + // + // Write request id in mailbox. + // + + DeviceExtension->MailBox.CommandIdSubmit = + DeviceExtension->CurrentIndex; + + // + // Start writing mailbox to controller. + // + + SendCdbDirect(DeviceExtension); + + return(TRUE); + +} // SendIoctlCdbDirect() + +VOID +SetupAdapterInfo( + IN PDEVICE_EXTENSION DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb +) + +/*++ + +Routine Description: + + Copy Adapter Information to Application Buffer. + +Arguments: + + DeviceExtension - Adapter state. + SRB - System request. + +Return Value: + + None. + +--*/ + +{ + PADAPTER_INFO AdpInfo; + + AdpInfo = (PADAPTER_INFO)((PUCHAR) Srb->DataBuffer + + sizeof(IOCTL_REQ_HEADER)); + + // + // Fill in Adapter Features Information. + // + + if (DeviceExtension->AdapterInterfaceType == MicroChannel) { + + AdpInfo->AdpFeatures.Model = (UCHAR) DeviceExtension->PosData.AdapterId; + AdpInfo->AdpFeatures.SubModel = DeviceExtension->PosData.OptionData3; + } + else { + + AdpInfo->AdpFeatures.Model = 0; + AdpInfo->AdpFeatures.SubModel = 0; + } + + if (DeviceExtension->AdapterType == DAC960_NEW_ADAPTER) { + + AdpInfo->AdpFeatures.MaxSysDrv = 32; + AdpInfo->AdpFeatures.MaxTgt = 16; + } + else { + AdpInfo->AdpFeatures.MaxSysDrv = 8; + + if (AdpInfo->AdpFeatures.MaxChn == 5) { + AdpInfo->AdpFeatures.MaxTgt = 4; + } + else { + AdpInfo->AdpFeatures.MaxTgt = 7; + } + } + + AdpInfo->AdpFeatures.MaxChn = (UCHAR) DeviceExtension->NumberOfChannels; + + AdpInfo->AdpFeatures.AdapterType = (UCHAR) DeviceExtension->AdapterType; + AdpInfo->AdpFeatures.PktFormat = 0; + + + AdpInfo->AdpFeatures.Reserved1 = 0; + AdpInfo->AdpFeatures.Reserved2 = 0; + AdpInfo->AdpFeatures.CacheSize = 0; + AdpInfo->AdpFeatures.OemCode = 0; + AdpInfo->AdpFeatures.Reserved3 = 0; + + // + // Fill in the System Resources information. + // + + AdpInfo->SysResources.BusInterface = + (UCHAR) DeviceExtension->AdapterInterfaceType; + + AdpInfo->SysResources.BusNumber = + (UCHAR) DeviceExtension->SystemIoBusNumber; + + + AdpInfo->SysResources.IrqVector = + (UCHAR) DeviceExtension->BusInterruptLevel; + + AdpInfo->SysResources.IrqType = + (UCHAR) DeviceExtension->InterruptMode; + + + AdpInfo->SysResources.Slot = DeviceExtension->Slot; + AdpInfo->SysResources.Reserved2 = 0; + + AdpInfo->SysResources.IoAddress = (ULONG) DeviceExtension->BaseIoAddress; + + AdpInfo->SysResources.MemAddress = 0; + + AdpInfo->SysResources.BiosAddress = (ULONG) DeviceExtension->BaseBiosAddress; + AdpInfo->SysResources.Reserved3 = 0; + + // + // Fill in the Firmware & BIOS version information. + // + + if (DeviceExtension->AdapterType == DAC960_NEW_ADAPTER) { + + AdpInfo->VerControl.MinorFirmwareRevision = + ((PDAC960_ENQUIRY_3X)DeviceExtension->NoncachedExtension)->MinorFirmwareRevision; + } + else { + + AdpInfo->VerControl.MajorFirmwareRevision = + ((PDAC960_ENQUIRY)DeviceExtension->NoncachedExtension)->MajorFirmwareRevision; + } + + AdpInfo->VerControl.MinorBIOSRevision = 0; + AdpInfo->VerControl.MajorBIOSRevision = 0; + AdpInfo->VerControl.Reserved = 0; +} + +VOID +SetupDriverVersionInfo( + IN PDEVICE_EXTENSION DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb +) + +/*++ + +Routine Description: + + Copy Driver Version Information to Application Buffer. + +Arguments: + + DeviceExtension - Adapter state. + SRB - System request. + +Return Value: + + None. + +--*/ + +{ + PDRIVER_VERSION driverVersion; + + driverVersion = (PDRIVER_VERSION)((PUCHAR) Srb->DataBuffer + + sizeof(IOCTL_REQ_HEADER)); + + driverVersion->DriverMajorVersion = (UCHAR) (DRIVER_REVISION >> 8); + driverVersion->DriverMinorVersion = (UCHAR) DRIVER_REVISION; + driverVersion->Month = (UCHAR) (DRIVER_BUILD_DATE >> 16); + driverVersion->Date = (UCHAR) (DRIVER_BUILD_DATE >> 8); + driverVersion->Year = (UCHAR) DRIVER_BUILD_DATE; + +} diff --git a/private/ntos/miniport/mylex/dac960/dmc960nt.h b/private/ntos/miniport/mylex/dac960/dmc960nt.h new file mode 100644 index 000000000..c00f41065 --- /dev/null +++ b/private/ntos/miniport/mylex/dac960/dmc960nt.h @@ -0,0 +1,87 @@ +/*++ + +Copyright (c) 1994 Mylex Corporation + +Module Name: + + dmc960nt.h + +Abstract: + + The module defines the structures, defines for DMC960 Adapter. + +Author: + + Mouli (mouli@mylex.com) + +Environment: + + Kernel mode Only + +Revision History: + +--*/ + + +#define MAXIMUM_MCA_SLOTS 0x08 + +// +// DMC960 Adapter IDs +// + +#define MAGPIE_ADAPTER_ID 0x8f6c // Mylex Version +#define HUMMINGBIRD_ADAPTER_ID 0x8f82 // Pass Play Option +#define PASSPLAY_ADAPTER_ID 0x8fbb // Pass Play + +// +// DMC960 Control Registers definitions. +// + +#define DMC960_ATTENTION_PORT 0x04 +#define DMC960_SUBSYSTEM_CONTROL_PORT 0x05 +#define DMC960_COMMAND_STATUS_BUSY_PORT 0x07 + +// +// DMC960 Interrupt Valid bit (Bit 1 in Command Status Busy Port). +// +#define DMC960_INTERRUPT_VALID 0x02 + +// +// DMC960 Interrupt Control bit definitions (Set in Subsytem Control Port). +// + +#define DMC960_DISABLE_INTERRUPT 0x02 +#define DMC960_ENABLE_INTERRUPT 0x03 +#define DMC960_CLEAR_INTERRUPT_ON_READ 0x40 + +// +// DMC960 Command/status Handshaking register values. +// + +#define DMC960_SUBMIT_COMMAND 0xd0 +#define DMC960_ACKNOWLEDGE_STATUS 0xd1 + +// +// Define Option Select Register Structures. +// + +typedef struct _POS_DATA { + USHORT AdapterId; + UCHAR OptionData1; + UCHAR OptionData2; + UCHAR OptionData3; + UCHAR OptionData4; +} POS_DATA, *PPOS_DATA; + +// +// DAC960 MCA register definition +// + +typedef struct _MCA_REGISTERS { + UCHAR NotUsed1[4]; // IoBase + 0x00 + UCHAR AttentionPort; // IoBase + 0x04 + UCHAR SubsystemControlPort; // IoBase + 0x05 + UCHAR NotUsed2; // IoBase + 0x06 + UCHAR CommandStatusBusyPort; // IoBase + 0x07 +} MCA_REGISTERS, *PMCA_REGISTERS; + diff --git a/private/ntos/miniport/mylex/dac960/makefile b/private/ntos/miniport/mylex/dac960/makefile new file mode 100644 index 000000000..0d61f853d --- /dev/null +++ b/private/ntos/miniport/mylex/dac960/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/ntos/miniport/mylex/dac960/raidapi.h b/private/ntos/miniport/mylex/dac960/raidapi.h new file mode 100644 index 000000000..86261105b --- /dev/null +++ b/private/ntos/miniport/mylex/dac960/raidapi.h @@ -0,0 +1,277 @@ +/***************************************************************************** +* * +* COPYRIGHT (C) Mylex Corporation 1992-1994 * +* * +* This software is furnished under a license and may be used and copied * +* only in accordance with the terms and conditions of such license * +* and with inclusion of the above copyright notice. This software or nay * +* other copies thereof may not be provided or otherwise made available to * +* any other person. No title to and ownership of the software is hereby * +* transferred. * +* * +* The information in this software is subject to change without notices * +* and should not be construed as a commitment by Mylex Corporation * +*****************************************************************************/ + +/**************************************************************************** +* * +* Name: RAIDAPI.H * +* * +* Description: Structure Definitions Used by Driver and Utils * +* * +* Envrionment: * +* * +* Operating System: Netware 3.x and 4.x,OS/2 2.x,Win NT 3.5,Unixware 2.0 * +* * +* --------------- Revision History ------------------------ * +* * +* Date Author Change * +* ---- ----- ------------------------------------- * +* 11/04/94 Subra.Hegde Added few more BUS Definitions * +* 01/06/95 Subra.Hegde Reserved1 field in SYS_RESOURCES changed to * +* Slot. * +* 05/10/95 Mouli Re-defined DRV_IOCTL structure * +* Removed IO_MBOX, HBA_MBOX structure defs * +* 05/18/95 Subra Added DRIVER_VERSION structure * +****************************************************************************/ + +#ifndef _RAIDAPI_H +#define _RAIDAPI_H + + +#ifndef UCHAR +#define UCHAR unsigned char +#endif + +#ifndef USHORT +#define USHORT unsigned short +#endif + +#ifndef ULONG +#define ULONG unsigned long +#endif + +#ifndef VOID +#define VOID void +#endif + +/* + * Adapter Interface Type + */ + +#define AI_INTERNAL 0x00 +#define AI_ISA_BUS 0x01 /* ISA Bus Type */ +#define AI_EISA_BUS 0x02 /* EISA Bus Type */ +#define AI_uCHNL_BUS 0x03 /* MicroChannel Bus Type */ +#define AI_TURBO_BUS 0x04 /* Turbo Channel Bus Type */ +#define AI_PCI_BUS 0x05 /* PCI Bus Type */ +#define AI_VME_BUS 0x06 /* VME Bus Type */ +#define AI_NU_BUS 0x07 /* NuBus Type */ +#define AI_PCMCIA_BUS 0x08 /* PCMCIA Bus Type */ +#define AI_C_BUS 0x09 /* C Bus */ +#define AI_MPI_BUS 0x0A /* MPI Bus */ +#define AI_MPSA_BUS 0x0B /* MPSA Bus */ +#define AI_SCSI2SCSI_BUS 0x0C /* SCSI to SCSI Bus */ + +/* + * Interrupt Type + */ + +#define IRQ_TYPE_EDGE 0x00 /* Irq is Edge Type */ +#define IRQ_TYPE_LEVEL 0x01 /* Irq is Level Type */ + +/* + * definitions to identify new/old DAC960 adapters + */ + +#define DAC960_OLD_ADAPTER 0x00 /* DAC960 with Fw Ver < 3.x */ +#define DAC960_NEW_ADAPTER 0x01 /* DAC960 with Fw Ver >= 3.x */ + +/* + * All structure definitions are packed on 1-byte boundary. + */ + +#pragma pack(1) + +/* + * Generic Mail Box Registers Structure Format + */ + +typedef struct _HBA_GENERIC_MBOX { + + UCHAR Reg0; /* HBA Mail Box Register 0 */ + UCHAR Reg1; /* HBA Mail Box Register 1 */ + UCHAR Reg2; /* HBA Mail Box Register 2 */ + UCHAR Reg3; /* HBA Mail Box Register 3 */ + UCHAR Reg4; /* HBA Mail Box Register 4 */ + UCHAR Reg5; /* HBA Mail Box Register 5 */ + UCHAR Reg6; /* HBA Mail Box Register 6 */ + UCHAR Reg7; /* HBA Mail Box Register 7 */ + UCHAR Reg8; /* HBA Mail Box Register 8 */ + UCHAR Reg9; /* HBA Mail Box Register 9 */ + UCHAR RegA; /* HBA Mail Box Register A */ + UCHAR RegB; /* HBA Mail Box Register B */ + UCHAR RegC; /* HBA Mail Box Register C */ + UCHAR RegD; /* HBA Mail Box Register D */ + UCHAR RegE; /* HBA Mail Box Register E */ + UCHAR RegF; /* HBA Mail Box Register F */ + +} HBA_GENERIC_MBOX, *PHBA_GENERIC_MBOX; + +/* + * Host Bus Adapter Embedded Software Version Control Information + */ + +typedef struct _VERSION_CONTROL { + + UCHAR MinorFirmwareRevision; /* HBA Firmware Minor Version No */ + UCHAR MajorFirmwareRevision; /* HBA Firmware Major Version No */ + UCHAR MinorBIOSRevision; /* HBA BIOS Minor Version No */ + UCHAR MajorBIOSRevision; /* HBA BIOS Major Version No */ + ULONG Reserved; /* Reserved */ + +} VERSION_CONTROL, *PVERSION_CONTROL; + +/* + * System Resources used by Host Bus Adapter + */ + +typedef struct _SYSTEM_RESOURCES { + + UCHAR BusInterface; /* HBA System Bus Interface Type */ + UCHAR BusNumber; /* System Bus No, HBA is sitting on */ + UCHAR IrqVector; /* HBA Interrupt Vector No */ + UCHAR IrqType; /* HBA Irq Type : Edge/Level */ + UCHAR Slot; /* HBA Slot Number */ + UCHAR Reserved2; /* Reserved */ + ULONG IoAddress; /* HBA IO Base Address */ + /* EISA : 0xzC80 */ + /* PCI: Read_Config_word(Register 0x10) & 0xff80*/ + ULONG MemAddress; /* HBA Memory Base Address */ + ULONG BiosAddress; /* HBA BIOS Address (if enabled) */ + ULONG Reserved3; /* Reserved */ + +} SYSTEM_RESOURCES, *PSYSTEM_RESOURCES; + +/* + * Host Bus Adapter Features + */ + +typedef struct _ADAPTER_FEATURES { + + UCHAR Model; /* HBA Family Model */ + UCHAR SubModel; /* HBA Sub Model */ + UCHAR MaxSysDrv; /* Maximum System Drives */ + UCHAR MaxTgt; /* Maximum Targets per Channel */ + UCHAR MaxChn; /* Maximum Channels per Adapter */ + UCHAR Reserved1; /* Reserved */ + UCHAR Reserved2; /* Reserved */ + UCHAR AdapterType; /* Controller type(0,1) */ + UCHAR PktFormat; /* IOCTL packet format(0) */ + ULONG CacheSize; /* HBA Cache Size In Mega Bytes */ + ULONG OemCode; /* HBA OEM Identifier Code */ + ULONG Reserved3; /* Reserved */ + +} ADAPTER_FEATURES, *PADAPTER_FEATUTRES; + +typedef struct _ADAPTER_INFO { + + UCHAR AdapterIndex; /* Logical Adapter Index */ + ADAPTER_FEATURES AdpFeatures; + SYSTEM_RESOURCES SysResources; + VERSION_CONTROL VerControl; + UCHAR Reserved[12]; + +} ADAPTER_INFO, *PADAPTER_INFO; + +/* + * Driver IOCTL Support Stuff. + */ + +/* + * The DAC960 controller specific IOCTL commands + */ +#define DACDIO 0x44414300 /* DAC960 ioctls */ +#define DAC_DIODCDB (DACDIO|2) /* DAC960 direct cdb */ +#define DAC_DIODCMD (DACDIO|3) /* DAC960 direct cmd */ + +/* + * DAC960 driver signature + */ + +#define DRV_SIGNATURE 0x4D594C58 /* MYLX */ + +/* + * Data Direction control defs + */ + +#define DATA_XFER_NONE 0 +#define DATA_XFER_IN 1 +#define DATA_XFER_OUT 2 + +/* + * Driver IoControl Request Format + */ + +typedef struct _DRV_IOCTL { + + ULONG Signature; /* Driver would look for this */ + ULONG ControlCode; /* IOCTL Control Code */ + VOID *IoctlBuffer; /* IOCTL Specific input buffer */ + ULONG IoctlBufferLen; /* ioctl buffer length */ + VOID *DataBufferAddr; /* User Virtual Buffer Address */ + ULONG DataBufferLen; /* Data Buffer Length */ + ULONG Reserved1; /* Reserved for future use */ + ULONG Reserved2; /* Reserved for future use */ + UCHAR AdapterIndex; /* Logical Adapter Index */ + UCHAR DataDirection; /* Bytes xferred out by driver */ + UCHAR TimeOutValue; /* Time out value - not used */ + UCHAR Reserved3; /* Reserved for future use */ + USHORT DriverErrorCode; /* Driver Returned Error Code */ + USHORT CompletionCode; /* DAC960 command completion code */ + +} DRV_IOCTL, *PDRV_IOCTL; + +/* + * Driver Version Number format - all fields in hex + */ +typedef struct _DRIVER_VERSION{ + + UCHAR DriverMajorVersion; /* Major version number */ + UCHAR DriverMinorVersion; /* Minor version number */ + UCHAR Month; /* Driver Build - Month */ + UCHAR Date; /* Driver Build - Date */ + UCHAR Year; /* Driver Build - Year */ + UCHAR Reserved[3]; + +} DRIVER_VERSION,*PDRIVER_VERSION; + +#pragma pack() + +/* + * IOCTL Codes for internal driver requests + */ + +#define MIOC_ADP_INFO 0xA0 /* Get Adapter information */ +#define MIOC_DRIVER_VERSION 0xA1 /* Get Driver Version */ + +/* + * Error Codes returned by Driver + */ + +#define NOMORE_ADAPTERS 0x0001 /* wiil be made obsolete */ +#define INVALID_COMMANDCODE 0x0201 /* will be made obsolete */ +#define INVALID_ARGUMENT 0x0202 /* wiil be made obsolete */ + +/* + * Driver Error Code Values + */ + +#define DAC_IOCTL_SUCCESS 0x0000 +#define DAC_IOCTL_INVALID_ADAPTER_NUMBER 0x0001 +#define DAC_IOCTL_INVALID_ARGUMENT 0x0002 +#define DAC_IOCTL_UNSUPPORTED_REQUEST 0x0003 +#define DAC_IOCTL_RESOURCE_ALLOC_FAILURE 0x0004 +#define DAC_IOCTL_INTERNAL_XFER_ERROR 0x0005 + +#endif diff --git a/private/ntos/miniport/mylex/dac960/raiddefs.h b/private/ntos/miniport/mylex/dac960/raiddefs.h new file mode 100644 index 000000000..a370d2f08 --- /dev/null +++ b/private/ntos/miniport/mylex/dac960/raiddefs.h @@ -0,0 +1,34 @@ + +#ifndef __RAIDDEFS_H +#define __RAIDDEFS_H + +/***************************************************************************** +* * +* COPYRIGHT (C) Mylex Corporation 1992-1994 * +* * +* This software is furnished under a license and may be used and copied * +* only in accordance with the terms and conditions of such license * +* and with inclusion of the above copyright notice. This software or nay * +* other copies thereof may not be provided or otherwise made available to * +* any other person. No title to and ownership of the software is hereby * +* transferred. * +* * +* The information in this software is subject to change without notices * +* and should not be construed as a commitment by Mylex Corporation * +*****************************************************************************/ + +/* + Definitions used by Utilities and by the driver for Utility support +*/ + +/* IOCTL Codes For Driver */ + +#define MIOC_ADP_INFO 0xA0 /* Get Interface Type */ + +/* Error Codes returned by Driver */ + +#define NOMORE_ADAPTERS 0x01 +#define INVALID_COMMANDCODE 0x201 +#define INVALID_ARGUMENT 0x202 + +#endif diff --git a/private/ntos/miniport/mylex/dac960/sources b/private/ntos/miniport/mylex/dac960/sources new file mode 100644 index 000000000..ea9591b71 --- /dev/null +++ b/private/ntos/miniport/mylex/dac960/sources @@ -0,0 +1,13 @@ +TARGETNAME=dac960nt +TARGETPATH=obj +TARGETTYPE=DRIVER + +#INCLUDES=$(BASEDIR)\src\scsi\inc +INCLUDES=..\..\..\inc + +TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib + +SOURCES=dac960nt.c dac960nt.rc dacioctl.c + +C_DEFINES=-DGAM_SUPPORT + -- cgit v1.2.3