summaryrefslogtreecommitdiffstats
path: root/private/ntos/miniport/mylex/dac960
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/miniport/mylex/dac960')
-rw-r--r--private/ntos/miniport/mylex/dac960/d960api.h56
-rw-r--r--private/ntos/miniport/mylex/dac960/dac960nt.c4152
-rw-r--r--private/ntos/miniport/mylex/dac960/dac960nt.h428
-rw-r--r--private/ntos/miniport/mylex/dac960/dac960nt.rc38
-rw-r--r--private/ntos/miniport/mylex/dac960/dacioctl.c525
-rw-r--r--private/ntos/miniport/mylex/dac960/dmc960nt.h87
-rw-r--r--private/ntos/miniport/mylex/dac960/makefile6
-rw-r--r--private/ntos/miniport/mylex/dac960/raidapi.h277
-rw-r--r--private/ntos/miniport/mylex/dac960/raiddefs.h34
-rw-r--r--private/ntos/miniport/mylex/dac960/sources13
10 files changed, 5616 insertions, 0 deletions
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<sizeof(HW_INITIALIZATION_DATA); i++)
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+
+ // Set size of hwInitializationData.
+
+ hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
+
+ // Set entry points.
+
+ hwInitializationData.HwInitialize = Dac960Initialize;
+ hwInitializationData.HwStartIo = Dac960StartIo;
+ hwInitializationData.HwInterrupt = Dac960Interrupt;
+ hwInitializationData.HwResetBus = Dac960ResetBus;
+
+ //
+ // Show two access ranges - adapter registers and BIOS.
+ //
+
+ hwInitializationData.NumberOfAccessRanges = 2;
+
+ //
+ // Indicate will need physical addresses.
+ //
+
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+
+ //
+ // Indicate auto request sense is supported.
+ //
+
+ hwInitializationData.AutoRequestSense = TRUE;
+ hwInitializationData.MultipleRequestPerLu = TRUE;
+
+ //
+ // Specify size of extensions.
+ //
+
+ hwInitializationData.DeviceExtensionSize = sizeof(DEVICE_EXTENSION);
+ hwInitializationData.SrbExtensionSize =
+ sizeof(SG_DESCRIPTOR) * MAXIMUM_SGL_DESCRIPTORS + sizeof(DIRECT_CDB);
+
+#ifndef DAC960_EISA_SUPPORT_ONLY
+
+ //
+ // Set PCI ids.
+ //
+
+ hwInitializationData.DeviceId = &deviceId;
+ hwInitializationData.DeviceIdLength = 4;
+ hwInitializationData.VendorId = &vendorId;
+ hwInitializationData.VendorIdLength = 4;
+
+ //
+ // Attempt PCI initialization for old DAC960 PCI (Device Id - 0001)
+ // Controllers.
+ //
+
+ hwInitializationData.AdapterInterfaceType = PCIBus;
+ hwInitializationData.HwFindAdapter = Dac960PciFindAdapter;
+ SlotNumber = DAC960_OLD_ADAPTER;
+
+ Status1 = ScsiPortInitialize(DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &SlotNumber);
+ //
+ // Attempt PCI initialization for new DAC960 PCI (Device Id - 0002)
+ // Controllers.
+ //
+
+ deviceId[3] = '2';
+ SlotNumber = DAC960_NEW_ADAPTER;
+
+ Status2 = ScsiPortInitialize(DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &SlotNumber);
+
+ Status1 = Status2 < Status1 ? Status2 : Status1;
+
+#endif // DAC960_EISA_SUPPORT_ONLY
+
+ //
+ // Attempt EISA initialization.
+ //
+
+
+ SlotNumber = 0;
+ hwInitializationData.AdapterInterfaceType = Eisa;
+ hwInitializationData.HwFindAdapter = Dac960EisaFindAdapter;
+
+ Status2 = ScsiPortInitialize(DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &SlotNumber);
+
+#ifndef DAC960_EISA_SUPPORT_ONLY
+
+ Status1 = Status2 < Status1 ? Status2 : Status1;
+
+ //
+ // Attempt MCA initialization.
+ //
+
+
+ SlotNumber = 0;
+ hwInitializationData.AdapterInterfaceType = MicroChannel;
+ hwInitializationData.HwFindAdapter = Dac960McaFindAdapter;
+
+ Status2 = ScsiPortInitialize(DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &SlotNumber);
+
+ //
+ // Return the smaller status.
+ //
+
+ return (Status2 < Status1 ? Status2 : Status1);
+
+#else
+
+ return (Status2);
+
+#endif // DAC960_EISA_SUPPORT_ONLY
+
+} // end DriverEntry()
diff --git a/private/ntos/miniport/mylex/dac960/dac960nt.h b/private/ntos/miniport/mylex/dac960/dac960nt.h
new file mode 100644
index 000000000..32a078785
--- /dev/null
+++ b/private/ntos/miniport/mylex/dac960/dac960nt.h
@@ -0,0 +1,428 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ Dac960Nt.h
+
+Abstract:
+
+ This is header file for the driver for the Mylex 960 family.
+
+Author:
+
+ Mike Glass (mglass)
+
+Environment:
+
+ kernel mode only
+
+Revision History:
+
+--*/
+
+#include "scsi.h"
+
+//
+// SG list size is 17, one additional entry to support Fw 3.x format
+//
+
+#define MAXIMUM_SGL_DESCRIPTORS 0x12
+
+#define MAXIMUM_TRANSFER_LENGTH 0xF000
+#define MAXIMUM_EISA_SLOTS 0x10
+#define MAXIMUM_CHANNELS 0x05
+#define MAXIMUM_TARGETS_PER_CHANNEL 0x07
+
+#define DAC_EISA_ID 0x70009835
+
+#define DAC960_SYSTEM_DRIVE 0x08
+#define DAC960_DEVICE_NOT_ACCESSIBLE 0x00
+#define DAC960_DEVICE_ACCESSIBLE 0x01
+
+//
+// DAC960 mailbox register definition
+//
+
+typedef struct _MAILBOX {
+ UCHAR OperationCode; // zC90
+ UCHAR CommandIdSubmit; // zC91
+ USHORT BlockCount; // zC92
+ UCHAR BlockNumber[3]; // zC94
+ UCHAR DriveNumber; // zC97
+ ULONG PhysicalAddress; // zC98
+ UCHAR ScatterGatherCount; // zC9C
+ UCHAR CommandIdComplete; // zC9D
+ USHORT Status; // zC9E
+} MAILBOX, *PMAILBOX;
+
+//
+// DAC960 mailbox register definition for DAC960 Extended Commands
+//
+
+typedef struct _EXTENDED_MAILBOX {
+ UCHAR OperationCode; // zC90
+ UCHAR CommandIdSubmit; // zC91
+ USHORT BlockCount; // zC92
+ UCHAR BlockNumber[4]; // zC94
+ ULONG PhysicalAddress; // zC98
+ UCHAR DriveNumber; // zC9C
+ UCHAR CommandIdComplete; // zC9D
+ USHORT Status; // zC9E
+} EXTENDED_MAILBOX, *PEXTENDED_MAILBOX;
+
+//
+// DAC960 EISA register definition
+//
+
+typedef struct _EISA_REGISTERS {
+ ULONG EisaId; // zC80
+ UCHAR NotUsed1[4]; // zC84
+ UCHAR GlobalConfiguration; // zC88
+ UCHAR InterruptEnable; // zC89
+ UCHAR NotUsed2[2]; // zC9A
+ UCHAR LocalDoorBellEnable; // zC8C
+ UCHAR LocalDoorBell; // zC8D
+ UCHAR SystemDoorBellEnable; // zC8E
+ UCHAR SystemDoorBell; // zC8F
+ MAILBOX MailBox; // zC90
+ UCHAR Unused4[33]; // zCA0
+ UCHAR BiosAddress; // zCC1
+ UCHAR Unused5; // zCC2
+ UCHAR InterruptLevel; // zCC3
+} EISA_REGISTERS, *PEISA_REGISTERS;
+
+//
+// DAC960 PCI register definition
+//
+
+typedef struct _PCI_REGISTERS {
+ MAILBOX MailBox; // 0x00
+ UCHAR NotUsed1[48]; // 0x10
+ UCHAR LocalDoorBell; // 0x40
+ UCHAR SystemDoorBell; // 0x41
+ UCHAR NotUsed2[1]; // 0x42
+ UCHAR InterruptEnable; // 0x43
+} PCI_REGISTERS, *PPCI_REGISTERS;
+
+
+//
+// Local doorbell definition
+//
+
+#define DAC960_LOCAL_DOORBELL_SUBMIT_BUSY 0x01
+#define DAC960_LOCAL_DOORBELL_MAILBOX_FREE 0x02
+
+//
+// System doorbell definition
+//
+
+#define DAC960_SYSTEM_DOORBELL_COMMAND_COMPLETE 0x01
+#define DAC960_SYSTEM_DOORBELL_SUBMISSION_COMPLETE 0x02
+
+//
+// Command complete status
+//
+
+#define DAC960_STATUS_GOOD 0x0000
+#define DAC960_STATUS_ERROR 0x0001
+#define DAC960_STATUS_NO_DRIVE 0x0002 // system drives
+#define DAC960_STATUS_CHECK_CONDITION 0x0002 // pass-through
+#define DAC960_STATUS_BUSY 0x0008
+#define DAC960_STATUS_SELECT_TIMEOUT 0x000F
+#define DAC960_STATUS_DEVICE_TIMEOUT 0x000E
+#define DAC960_STATUS_NOT_IMPLEMENTED 0x0104
+#define DAC960_STATUS_BOUNDS_ERROR 0x0105
+
+//
+// Command codes
+//
+
+#define DAC960_COMMAND_READ 0x02 // DAC960 Fw Ver < 3.x
+#define DAC960_COMMAND_READ_EXT 0x33 // DAC960 Fw Ver >= 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 <windows.h>
+
+#include <ntverp.h>
+
+#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
+