summaryrefslogtreecommitdiffstats
path: root/private/ntos/miniport/dell
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/miniport/dell
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/miniport/dell')
-rw-r--r--private/ntos/miniport/dell/delldsa.c1767
-rw-r--r--private/ntos/miniport/dell/delldsa.h210
-rw-r--r--private/ntos/miniport/dell/delldsa.rc12
-rw-r--r--private/ntos/miniport/dell/makefile6
-rw-r--r--private/ntos/miniport/dell/sources40
5 files changed, 2035 insertions, 0 deletions
diff --git a/private/ntos/miniport/dell/delldsa.c b/private/ntos/miniport/dell/delldsa.c
new file mode 100644
index 000000000..e2c7b203c
--- /dev/null
+++ b/private/ntos/miniport/dell/delldsa.c
@@ -0,0 +1,1767 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ DellDsa.c
+
+Abstract:
+
+ This is the device driver for the DELL Drive Arrays.
+
+Authors:
+
+ Mike Glass (mglass)
+
+Environment:
+
+ kernel mode only
+
+Revision History:
+
+--*/
+
+#include "miniport.h"
+#include "scsi.h"
+#include "delldsa.h"
+
+//
+// Disk Device Extension
+//
+
+typedef struct _DEVICE_EXTENSION {
+
+ //
+ // BMIC registers
+ //
+
+ PDDA_REGISTERS Bmic;
+
+ //
+ // Buffer for IDENTIFY command.
+ //
+
+ PVOID IdentifyBuffer;
+
+ //
+ // The rest of the fields are for the controller itself.
+ //
+ // Firmware major version
+ // 1 : DDA
+ // 2 : DSA
+ //
+
+ USHORT MajorVersion;
+ USHORT MinorVersion;
+
+ UCHAR NumberOfLogicalDrives;
+ UCHAR EmulationMode;
+ UCHAR MaximumQueueDepth;
+ UCHAR MaximumNumberOfSgDescriptors;
+
+ //
+ // Keep track of state of verify.
+ //
+
+ ULONG CurrentSector;
+ ULONG RemainingSectors;
+
+ //
+ // Array of outstanding requests
+ //
+
+ PSCSI_REQUEST_BLOCK Srb[256];
+
+} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
+
+BOOLEAN
+ExtendedCommand(
+ PDEVICE_EXTENSION DeviceExtension,
+ IN UCHAR LogicalDrive,
+ IN UCHAR Command
+ )
+
+/*++
+
+Routine Description:
+
+ Ring local doorbell and wait for completion bit in local doorbell to be set.
+ This function is only called during initialization.
+
+Arguments:
+
+ DeviceExtension - Controller data.
+ LogicalDrive - Logical drive defined on this controller.
+ Command - Command byte to be sent.
+
+Return Value:
+
+ TRUE - if completion bit set in local doorbell.
+ FALSE - if timeout occurred waiting for bit to be set.
+
+--*/
+
+{
+ ULONG i;
+
+ //
+ // Claim submission semaphore.
+ //
+
+ for (i=0; i<1000; i++) {
+
+ if (ScsiPortReadPortUchar(&DeviceExtension->Bmic->SubmissionSemaphore)) {
+ ScsiPortStallExecution(1);
+ } else {
+ break;
+ }
+ }
+
+ //
+ // Check for timeout.
+ //
+
+ if (i == 1000) {
+ return FALSE;
+ }
+
+ //
+ // Claim submission semaphore
+ //
+
+ ScsiPortWritePortUchar(&DeviceExtension->Bmic->SubmissionSemaphore, 1);
+
+ //
+ // Write command byte to controller.
+ //
+
+ ScsiPortWritePortUchar(&DeviceExtension->Bmic->Command, Command);
+
+ //
+ // Write logical drive number to controller. Some extended commands
+ // do not require a logical drive number, but setting it doesn't hurt
+ // anything and makes this routine more flexible.
+ //
+
+ ScsiPortWritePortUchar(&DeviceExtension->Bmic->DriveNumber, LogicalDrive);
+
+ //
+ // Ring submission doorbell.
+ //
+
+ ScsiPortWritePortUchar(&DeviceExtension->Bmic->SubmissionDoorBell,
+ DDA_DOORBELL_EXTENDED_COMMAND);
+
+ //
+ // Spin for completion.
+ //
+
+ for (i=0; i<10000; i++) {
+
+ if (ScsiPortReadPortUchar(&DeviceExtension->Bmic->CompletionDoorBell) &
+ DDA_DOORBELL_EXTENDED_COMMAND) {
+ break;
+ } else {
+ ScsiPortStallExecution(10);
+ }
+ }
+
+ //
+ // Check for timeout.
+ //
+
+ if (i == 10000) {
+ return FALSE;
+ }
+
+ //
+ // Clear completion status
+ //
+
+ ScsiPortWritePortUchar(&DeviceExtension->Bmic->CompletionDoorBell, 0xff);
+
+ return TRUE;
+
+} // end ExtendedCommand
+
+
+VOID
+BuildRequest(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Translates a system SRB to a DDA request.
+
+ A DDA request has the following restrictions:
+
+ (1) Its scatter/gather list size is specified in
+ DeviceExtension->MaximumSGSize and is usually 16.
+ (2) Scatter/gather requests use sector counts rather than byte counts.
+ A scather/gather boundry cannot exist in the middle of a sector.
+ (3) The maximum size of a single DDA I/O is limited to 128 sectors.
+ This is because some early disk devices have bugs causing data
+ corruption in larger transfers.
+
+ DSA controllers do not have restriction (2), but some DSA firmware
+ have bugs such that byte SG hangs the controller.
+
+Arguments:
+
+ DeviceExtension - Represents the target disk.
+ SRB - System request.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDDA_REQUEST_BLOCK ddaRequest = Srb->SrbExtension;
+ PUCHAR dataPointer;
+ ULONG descriptorNumber;
+ ULONG bytesLeft;
+ PSG_DESCRIPTOR sgList;
+ ULONG length;
+
+ //
+ // Set drive number if request packet.
+ //
+
+ ddaRequest->DriveNumber = Srb->TargetId;
+
+ //
+ // Use SRB tag as request id.
+ //
+
+ ddaRequest->RequestId = Srb->QueueTag;
+ DeviceExtension->Srb[Srb->QueueTag] = Srb;
+
+ //
+ // Determine starting block number.
+ //
+
+ ddaRequest->StartingSector =
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24;
+
+ //
+ // Get data pointer, byte count and index to scatter/gather list.
+ //
+
+ sgList = ddaRequest->SgList.Descriptor;
+ 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].Count = length;
+
+ //
+ // Update pointers and counters.
+ //
+
+ bytesLeft -= length;
+ dataPointer += length;
+ descriptorNumber++;
+ }
+
+ //
+ // Convert to non-scatter/gather if possible. This improves
+ // command overhead by eliminating the SG list read across the bus.
+ //
+
+ if (descriptorNumber == 1) {
+
+ //
+ // Change data pointer and count.
+ //
+
+ ddaRequest->Size = (UCHAR)(sgList[0].Count / 512);
+ ddaRequest->PhysicalAddress = sgList[0].Address;
+
+ //
+ // Determine new command code.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+ ddaRequest->Command = DDA_COMMAND_READ;
+ } else {
+ ddaRequest->Command = DDA_COMMAND_WRITE;
+ }
+
+ } else {
+
+ ddaRequest->Size = (UCHAR)descriptorNumber;
+
+ //
+ // Calculate physical address of the scatter/gather list.
+ //
+
+ ddaRequest->PhysicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ NULL,
+ sgList,
+ &length));
+
+ //
+ // Check firmware to determine whether scatter/gather
+ // descriptors must be converted to sector descripters or
+ // whether byte-level scatter/gather can be used.
+ //
+
+ if (DeviceExtension->MajorVersion == 1) {
+
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+ ddaRequest->Command = DDA_COMMAND_SG_READ;
+ } else {
+ ddaRequest->Command = DDA_COMMAND_SG_WRITE;
+ }
+
+ //
+ // Convert byte counts to sector counts.
+ //
+
+ for (descriptorNumber=0;
+ descriptorNumber < ddaRequest->Size; descriptorNumber++) {
+ sgList[descriptorNumber].Count /= 512;
+ }
+
+ } else {
+
+ //
+ // Use byte-level scatter/gather.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+ ddaRequest->Command = DDA_COMMAND_SG_READB;
+ } else {
+ ddaRequest->Command = DDA_COMMAND_SG_WRITEB;
+ }
+ }
+ }
+
+ return;
+
+} // end BuildRequest()
+
+
+VOID
+BuildVerifyRequest(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ DeviceExtension - Represents the target disk.
+ SRB - System request.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDDA_REQUEST_BLOCK ddaRequest = Srb->SrbExtension;
+ PUCHAR dataPointer;
+ ULONG descriptorNumber;
+ ULONG bytesLeft;
+ PSG_DESCRIPTOR sgList;
+ ULONG length;
+ USHORT sectorCount;
+
+ //
+ // Set drive number if request packet.
+ //
+
+ ddaRequest->DriveNumber = Srb->TargetId;
+
+ //
+ // Use SRB tag as request id.
+ //
+
+ ddaRequest->RequestId = Srb->QueueTag;
+ DeviceExtension->Srb[Srb->QueueTag] = Srb;
+
+ //
+ // Determine starting block number.
+ //
+
+ ddaRequest->StartingSector =
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24;
+
+ //
+ // Get data pointer, byte count and index to scatter/gather list.
+ //
+
+ sectorCount = ((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8 | ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb;
+ DeviceExtension->CurrentSector = ddaRequest->StartingSector;
+
+ if (sectorCount > 0x80) {
+ DeviceExtension->RemainingSectors = sectorCount - 0x80;
+ sectorCount = 0x80;
+ } else {
+ DeviceExtension->RemainingSectors = 0;
+ }
+
+ ddaRequest->Size = (UCHAR)sectorCount;
+ ddaRequest->Command = DDA_COMMAND_VERIFY;
+ ddaRequest->PhysicalAddress = 0;
+
+ return;
+
+} // end BuildVerifyRequest()
+
+BOOLEAN
+SubmitRequest(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PDDA_REQUEST_BLOCK DdaRequest
+ )
+
+/*++
+
+Routine Description:
+
+ Submit DDA/DSA request to controller.
+
+Arguments:
+
+ DeviceExtension - Address of adapter storage area.
+ DdaRequest - Request to be submitted.
+
+Return Value:
+
+ TRUE - if request submitted.
+ FALSE - if timeout occurred waiting for submission semaphore.
+
+--*/
+
+{
+ PDDA_REGISTERS bmic = DeviceExtension->Bmic;
+ ULONG i;
+
+ //
+ // Claim submission semaphore.
+ //
+
+ for (i=0; i<100; i++) {
+
+ if (ScsiPortReadPortUchar(&bmic->SubmissionSemaphore)) {
+ ScsiPortStallExecution(20);
+ } else {
+ break;
+ }
+ }
+
+ //
+ // Check for timeout.
+ //
+
+ if (i == 100) {
+
+ DebugPrint((1,
+ "DELLDSA: SubmitRequest: Timeout waiting for submission channel %x\n",
+ DdaRequest));
+
+ return FALSE;
+ }
+
+ //
+ // Submit request.
+ //
+
+ ScsiPortWritePortUchar(&bmic->SubmissionSemaphore, 1);
+ ScsiPortWritePortUchar(&bmic->Command, DdaRequest->Command);
+ ScsiPortWritePortUchar(&bmic->DriveNumber, DdaRequest->DriveNumber);
+ ScsiPortWritePortUchar(&bmic->TransferCount, DdaRequest->Size);
+ ScsiPortWritePortUchar(&bmic->RequestIdOut, DdaRequest->RequestId);
+ ScsiPortWritePortUlong(&bmic->StartingSector, DdaRequest->StartingSector);
+ ScsiPortWritePortUlong(&bmic->DataAddress, DdaRequest->PhysicalAddress);
+ ScsiPortWritePortUchar(&bmic->SubmissionDoorBell,
+ DDA_DOORBELL_LOGICAL_COMMAND);
+
+ return TRUE;
+
+} // SubmitRequest()
+
+
+BOOLEAN
+DsaResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine resets the controller and completes outstanding requests.
+
+Arguments:
+
+ HwDeviceExtension - Address of adapter storage area.
+ PathId - Indicates adapter to reset.
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG i;
+
+ //
+ // Reset controller.
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SubmissionSemaphore, 1);
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SubmissionDoorBell,
+ DDA_DOORBELL_SOFT_RESET);
+
+ //
+ // Spin for reset completion.
+ //
+
+ for (i=0; i<1000000; i++) {
+
+ if (!(ScsiPortReadPortUchar(&deviceExtension->Bmic->SubmissionSemaphore) & 1)) {
+ break;
+ }
+
+ ScsiPortStallExecution(5);
+ }
+
+ //
+ // Check for timeout.
+ //
+
+ if (i == 1000000) {
+ return FALSE;
+ }
+
+ //
+ // Complete all outstanding requests.
+ //
+
+ ScsiPortCompleteRequest(HwDeviceExtension,
+ (UCHAR)PathId,
+ 0xFF,
+ 0xFF,
+ SRB_STATUS_BUS_RESET);
+
+ //
+ // Clear all SRB entries in device extension.
+ //
+
+ for (i=0; i<256; i++) {
+ deviceExtension->Srb[i] = NULL;
+ }
+
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ HwDeviceExtension,
+ NULL);
+
+ return TRUE;
+
+} // end DsaResetBus()
+
+
+BOOLEAN
+DsaInterrupt(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt handler for the DELL DDA/DSA controller.
+
+Arguments:
+
+ DeviceExtension - Represents the target controller.
+
+Return Value:
+
+ Return TRUE if controller is interrupting.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PDDA_REGISTERS bmic = deviceExtension->Bmic;
+ PDDA_REQUEST_BLOCK ddaRequest;
+ PSCSI_REQUEST_BLOCK srb;
+ UCHAR status;
+ UCHAR tag;
+
+ //
+ // Check if interrupt expected and clear it.
+ //
+
+ status = ScsiPortReadPortUchar(&deviceExtension->Bmic->CompletionDoorBell);
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->CompletionDoorBell, status);
+
+ if (!(status & DDA_INTERRUPTS)) {
+
+ //
+ // Interrupt is spurious.
+ //
+
+ return FALSE;
+ }
+
+ if (status & DDA_DOORBELL_EXTENDED_COMMAND) {
+ return TRUE;
+ }
+
+ status = ScsiPortReadPortUchar(&bmic->Status);
+ tag = ScsiPortReadPortUchar(&bmic->RequestIdIn);
+
+ //
+ // Release completion semaphore.
+ //
+
+ ScsiPortWritePortUchar(&bmic->CompletionSemaphore, 0);
+
+ //
+ // Get SRB address.
+ //
+
+ srb = deviceExtension->Srb[tag];
+ deviceExtension->Srb[tag] = NULL;
+
+ if (!srb) {
+ return TRUE;
+ }
+
+ if (srb->Cdb[0] == SCSIOP_VERIFY) {
+
+ if (status == DDA_STATUS_NO_ERROR) {
+
+ //
+ // See if the verify isn't yet complete.
+ //
+
+ if (deviceExtension->RemainingSectors != 0) {
+
+ ULONG i;
+ USHORT sectorCount;
+
+ ddaRequest = srb->SrbExtension;
+ sectorCount = ddaRequest->Size;
+
+ //
+ // Determine the new starting block number.
+ //
+
+ ddaRequest->StartingSector += sectorCount;
+
+ sectorCount = (USHORT)deviceExtension->RemainingSectors;
+
+ if (sectorCount > 0x80) {
+ deviceExtension->RemainingSectors = sectorCount - 0x80;
+ sectorCount = 0x80;
+ } else {
+ deviceExtension->RemainingSectors = 0;
+ }
+
+
+ ddaRequest->Size = (UCHAR)sectorCount;
+ ddaRequest->Command = DDA_COMMAND_VERIFY;
+ ddaRequest->PhysicalAddress = 0;
+
+ ddaRequest->RequestId = srb->QueueTag;
+ deviceExtension->Srb[srb->QueueTag] = srb;
+
+ //
+ // Claim submission semaphore.
+ //
+
+ for (i=0; i<100; i++) {
+
+ if (ScsiPortReadPortUchar(&bmic->SubmissionSemaphore)) {
+ ScsiPortStallExecution(20);
+ } else {
+ break;
+ }
+ }
+
+ //
+ // Check for timeout.
+ //
+
+ if (i == 100) {
+
+ DebugPrint((1,
+ "DELLDSA: SubmitRequest: Timeout waiting for submission channel %x\n",
+ ddaRequest));
+
+ status = DDA_STATUS_TIMEOUT;
+
+ } else {
+
+ //
+ // Submit request.
+ //
+
+ ScsiPortWritePortUchar(&bmic->SubmissionSemaphore, 1);
+ ScsiPortWritePortUchar(&bmic->Command, ddaRequest->Command);
+ ScsiPortWritePortUchar(&bmic->DriveNumber, ddaRequest->DriveNumber);
+ ScsiPortWritePortUchar(&bmic->TransferCount, ddaRequest->Size);
+ ScsiPortWritePortUchar(&bmic->RequestIdOut, ddaRequest->RequestId);
+ ScsiPortWritePortUlong(&bmic->StartingSector, ddaRequest->StartingSector);
+ ScsiPortWritePortUlong(&bmic->DataAddress, ddaRequest->PhysicalAddress);
+ ScsiPortWritePortUchar(&bmic->SubmissionDoorBell,
+ DDA_DOORBELL_LOGICAL_COMMAND);
+
+ return TRUE;
+ }
+ } else {
+
+ //
+ // Ask for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+
+ }
+ }
+ }
+
+ //
+ // Map DDA/DSA status to SRB status.
+ //
+
+ switch (status) {
+
+ case DDA_STATUS_NO_ERROR:
+
+ srb->SrbStatus = SRB_STATUS_SUCCESS;
+ break;
+
+ case DDA_STATUS_TIMEOUT:
+
+ srb->SrbStatus = SRB_STATUS_TIMEOUT;
+ break;
+
+ case DDA_STATUS_TRACK0_NOT_FOUND:
+ case DDA_STATUS_ABORTED:
+ case DDA_STATUS_UNCORRECTABLE_ERROR:
+
+ srb->SrbStatus = SRB_STATUS_ERROR;
+ break;
+
+ case DDA_STATUS_CORRECTABLE_ERROR:
+
+ srb->SrbStatus = SRB_STATUS_ERROR_RECOVERY;
+ break;
+
+ case DDA_STATUS_SECTOR_ID_NOT_FOUND:
+
+ srb->SrbStatus = SRB_STATUS_ERROR;
+ break;
+
+ case DDA_STATUS_BAD_BLOCK_FOUND:
+ case DDA_STATUS_WRITE_ERROR:
+
+ srb->SrbStatus = SRB_STATUS_ERROR;
+ break;
+ }
+
+ //
+ // Inform system that this request is complete.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ srb);
+
+ return TRUE;
+
+} // end DsaInterrupt()
+
+
+BOOLEAN
+DsaStartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This is routine is called by the system to start a request on the adapter.
+
+Arguments:
+
+ HwDeviceExtension - Address of adapter storage area.
+ Srb - Address of the request to be started.
+
+Return Value:
+
+ TRUE - The request has been started.
+ FALSE - The controller was busy.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ UCHAR status;
+ ULONG i;
+
+ switch (Srb->Function) {
+
+ case SRB_FUNCTION_RESET_BUS:
+
+ if (!DsaResetBus(deviceExtension,
+ Srb->PathId)) {
+
+ status = SRB_STATUS_ERROR;
+
+ } else {
+
+ status = SRB_STATUS_SUCCESS;
+ }
+
+ break;
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ switch (Srb->Cdb[0]) {
+
+ case SCSIOP_VERIFY:
+
+
+ BuildVerifyRequest(deviceExtension,Srb);
+
+ if (SubmitRequest(deviceExtension,
+ (PDDA_REQUEST_BLOCK)Srb->SrbExtension)) {
+
+ status = SRB_STATUS_PENDING;
+
+ //
+ // return, upon completion the verify path will ask for the next request.
+ //
+
+ return TRUE;
+
+ } else {
+
+ //
+ // Timed out waiting for submission channel to clear.
+ //
+
+ status = SRB_STATUS_BUSY;
+ }
+
+ break;
+
+
+ case SCSIOP_WRITE:
+ case SCSIOP_READ:
+
+ //
+ // Build command list from SRB.
+ //
+
+ BuildRequest(deviceExtension,
+ Srb);
+
+ //
+ // Submit request to controller.
+ //
+
+ if (SubmitRequest(deviceExtension,
+ (PDDA_REQUEST_BLOCK)Srb->SrbExtension)) {
+
+ status = SRB_STATUS_PENDING;
+
+ } else {
+
+ //
+ // Timed out waiting for submission channel to clear.
+ //
+
+ status = SRB_STATUS_BUSY;
+ }
+
+ break;
+
+ case SCSIOP_TEST_UNIT_READY:
+
+ status = SRB_STATUS_SUCCESS;
+
+ break;
+
+ case SCSIOP_READ_CAPACITY:
+
+ //
+ // Issue extended command to get disk geometry.
+ //
+
+ if (!ExtendedCommand(deviceExtension,
+ Srb->TargetId,
+ DDA_GET_LOGICAL_GEOMETRY)) {
+
+ DebugPrint((1,"DsaStartIo: Couldn't get logical drive geometry\n"));
+ status = SRB_STATUS_ERROR;
+
+ } else {
+
+ ULONG blockSize = 512;
+ UCHAR sectorsPerTrack =
+ ScsiPortReadPortUchar(&((PDDA_GET_GEOMETRY)deviceExtension->Bmic)->SectorsPerTrack);
+ UCHAR numberOfHeads =
+ ScsiPortReadPortUchar(&((PDDA_GET_GEOMETRY)deviceExtension->Bmic)->NumberOfHeads);
+ USHORT numberOfCylinders =
+ ScsiPortReadPortUshort(&((PDDA_GET_GEOMETRY)deviceExtension->Bmic)->NumberOfCylinders);
+ ULONG numberOfBlocks;
+
+ //
+ // Release semaphore.
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SubmissionSemaphore, 0);
+
+ DebugPrint((1,
+ "DsaStartIo: Block size %x\n",
+ blockSize));
+
+ DebugPrint((1,
+ "DsaStartIo: Sectors per track %x\n",
+ sectorsPerTrack));
+
+ DebugPrint((1,
+ "DsaStartIo: Number of heads %x\n",
+ numberOfHeads));
+
+ DebugPrint((1,
+ "DsaStartIo: Number of cylinders %x\n",
+ numberOfCylinders));
+
+ //
+ // Calculate number of sectors on this disk.
+ //
+
+ numberOfBlocks =
+ sectorsPerTrack *
+ numberOfHeads *
+ numberOfCylinders;
+
+ //
+ // Get blocksize and number of blocks from identify
+ // data.
+ //
+
+ REVERSE_BYTES(&((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock,
+ &blockSize);
+
+ REVERSE_BYTES(&((PREAD_CAPACITY_DATA)Srb->DataBuffer)->LogicalBlockAddress,
+ &numberOfBlocks);
+
+ status = SRB_STATUS_SUCCESS;
+ }
+
+ break;
+
+ case SCSIOP_INQUIRY:
+
+ //
+ // Only respond at logical unit 0;
+ //
+
+ if (Srb->Lun != 0 ||
+ Srb->TargetId >=
+ deviceExtension->NumberOfLogicalDrives) {
+
+ //
+ // Indicate no device found at this address.
+ //
+
+ status = SRB_STATUS_SELECTION_TIMEOUT;
+
+ } else {
+
+ PINQUIRYDATA inquiryData = Srb->DataBuffer;
+
+ //
+ // Zero INQUIRY data structure.
+ //
+
+ for (i = 0; i < Srb->DataTransferLength; i++) {
+ ((PUCHAR)Srb->DataBuffer)[i] = 0;
+ }
+
+ //
+ // Dell DDA/DSA only supports disks.
+ //
+
+ inquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
+
+ //
+ // Fill in vendor identification fields.
+ //
+
+ inquiryData->VendorId[0] = 'D';
+ inquiryData->VendorId[1] = 'e';
+ inquiryData->VendorId[2] = 'l';
+ inquiryData->VendorId[3] = 'l';
+ inquiryData->VendorId[4] = ' ';
+ inquiryData->VendorId[5] = ' ';
+ inquiryData->VendorId[6] = ' ';
+ inquiryData->VendorId[7] = 'D';
+ inquiryData->VendorId[8] = 'i';
+ inquiryData->VendorId[9] = 's';
+ inquiryData->VendorId[10] = 'k';
+ inquiryData->VendorId[11] = ' ';
+ inquiryData->VendorId[12] = 'A';
+ inquiryData->VendorId[13] = 'r';
+ inquiryData->VendorId[14] = 'r';
+ inquiryData->VendorId[15] = 'a';
+ inquiryData->VendorId[16] = 'y';
+ inquiryData->VendorId[17] = ' ';
+ inquiryData->VendorId[18] = ' ';
+ inquiryData->VendorId[19] = ' ';
+ inquiryData->VendorId[20] = ' ';
+
+ //
+ // Initialize unused portion of product id.
+ //
+
+ for (i = 0; i < 4; i++) {
+ inquiryData->ProductId[12+i] = ' ';
+ }
+
+ //
+ // Move firmware revision from IDENTIFY data to
+ // product revision in INQUIRY data.
+ //
+
+ for (i = 0; i < 4; i += 2) {
+ inquiryData->ProductRevisionLevel[i] = ' ';
+ inquiryData->ProductRevisionLevel[i+1] = ' ';
+ }
+
+ status = SRB_STATUS_SUCCESS;
+ }
+
+ break;
+
+ default:
+
+ status = SRB_STATUS_INVALID_REQUEST;
+
+ break;
+
+ } // end switch (Srb->Cdb[0])
+
+ break;
+
+ default:
+
+ status = SRB_STATUS_INVALID_REQUEST;
+
+ } // end switch
+
+ //
+ // Check if SRB should be completed.
+ //
+
+ if (status != SRB_STATUS_PENDING) {
+
+ //
+ // Set status in SRB.
+ //
+
+ Srb->SrbStatus = status;
+
+ //
+ // Inform system that this request is complete.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+ } else {
+
+ //
+ // Indicate to system that the controller can take another request
+ // for this device.
+ //
+
+ ScsiPortNotification(NextLuRequest,
+ deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+ }
+
+
+ return TRUE;
+
+} // end DsaStartIo()
+
+
+BOOLEAN
+SearchEisaBus(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from DsaFindAdapter if the system fails to
+ pass in predetermined configuration data. It searches the EISA bus
+ data looking for information about controllers that this driver
+ supports.
+
+Arguments:
+
+ HwDeviceExtension - Address of adapter storage area.
+ Context - Used to track how many EISA slots have been searched.
+ ConfigInfo - System template for configuration information.
+
+Return Value:
+
+ TRUE - If Dell DDA/DSA controller found.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG length;
+ ULONG eisaSlotNumber;
+ PACCESS_RANGE accessRange;
+ PCM_EISA_SLOT_INFORMATION slotInformation;
+ PCM_EISA_FUNCTION_INFORMATION functionInformation;
+ ULONG numberOfFunctions;
+
+ //
+ // Get pointer to first configuration information structure access range.
+ //
+
+ accessRange = &((*(ConfigInfo->AccessRanges))[0]);
+
+ for (eisaSlotNumber=*((PULONG)Context);
+ eisaSlotNumber<16;
+ eisaSlotNumber++) {
+
+ //
+ // Get pointer to bus data for this EISA slot.
+ //
+
+ length = ScsiPortGetBusData(HwDeviceExtension,
+ EisaConfiguration,
+ ConfigInfo->SystemIoBusNumber,
+ eisaSlotNumber,
+ &slotInformation,
+ 0);
+
+ if (!length) {
+ continue;
+ }
+
+ //
+ // Check for Dell board id.
+ //
+
+ if ((slotInformation->CompressedId & 0xf0ffffff) != DDA_ID) {
+ continue;
+ }
+
+ //
+ // Set up default port address.
+ //
+
+ accessRange->RangeStart.LowPart =
+ (eisaSlotNumber * 0x1000) + 0x0C80;
+ accessRange->RangeLength = sizeof(DDA_REGISTERS);
+
+ accessRange++;
+
+ //
+ // Get the number of EISA configuration functions returned in bus data.
+ //
+
+ numberOfFunctions = slotInformation->NumberFunctions;
+
+ //
+ // Get first configuration record.
+ //
+
+ functionInformation =
+ (PCM_EISA_FUNCTION_INFORMATION)(slotInformation + 1);
+
+ //
+ // Walk configuration records to find EISA IRQ.
+ //
+
+ for (; 0 < numberOfFunctions; numberOfFunctions--, functionInformation++) {
+
+ //
+ // Check for IRQ.
+ //
+
+ if (functionInformation->FunctionFlags & EISA_HAS_IRQ_ENTRY) {
+
+ ConfigInfo->BusInterruptLevel =
+ functionInformation->EisaIrq->ConfigurationByte.Interrupt;
+ ConfigInfo->InterruptMode = Latched;
+ }
+
+ //
+ // Check for IO ranges.
+ //
+
+ if (functionInformation->FunctionFlags & EISA_HAS_PORT_RANGE) {
+
+ PEISA_PORT_CONFIGURATION eisaPort =
+ functionInformation->EisaPort;
+
+ //
+ // Search for emulation ranges.
+ //
+
+ while (eisaPort->PortAddress) {
+
+ //
+ // Check range to determine length.
+ //
+
+ switch (eisaPort->PortAddress) {
+
+ case 0x000001f0:
+ case 0x00000170:
+
+ accessRange->RangeStart.LowPart = eisaPort->PortAddress;
+ accessRange->RangeLength = 0x0000000F;
+ break;
+
+ case 0x000003f6:
+ case 0x00000176:
+
+ accessRange->RangeStart.LowPart = eisaPort->PortAddress;
+ accessRange->RangeLength = 0x00000001;
+ break;
+ }
+
+ DebugPrint((1,
+ "DELLDSA: SearchEisaBus: IO base %x\n",
+ eisaPort->PortAddress));
+
+ //
+ // Advance pointers to next IO range.
+ //
+
+ accessRange++;
+ eisaPort++;
+ }
+ }
+ }
+
+ //
+ // Indicate from which EISA slot to continue search.
+ //
+
+ *((PULONG)Context) = eisaSlotNumber + 1;
+
+ return TRUE;
+ }
+
+ return FALSE;
+
+} // end SearchEisaBus()
+
+
+BOOLEAN
+DsaInitialize(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by the system during initialization to
+ prepare the controller to receive requests.
+
+Arguments:
+
+ HwDeviceExtension - Address of adapter storage area.
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG i;
+
+ //
+ // Check if controller needs a reset.
+ //
+
+ if (ScsiPortReadPortUchar(&deviceExtension->Bmic->SubmissionSemaphore)) {
+
+ //
+ // Issue a soft reset.
+ //
+
+ DebugPrint((1,
+ "DellDsa: Submission channnel stuck; Resetting controller\n"));
+
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SubmissionSemaphore, 1);
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SubmissionDoorBell,
+ DDA_DOORBELL_SOFT_RESET);
+
+ //
+ // Spin for reset completion.
+ //
+
+ for (i=0; i<1000000; i++) {
+
+ if (!(ScsiPortReadPortUchar((PUCHAR)&deviceExtension->Bmic->SubmissionSemaphore) & 1)) {
+ break;
+ }
+
+ ScsiPortStallExecution(5);
+ }
+
+ //
+ // Check for timeout.
+ //
+
+ if (i == 1000000) {
+
+ return FALSE;
+ }
+ }
+
+ //
+ // Enable completion interrupts.
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->InterruptControl, 1);
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->CompletionInterruptMask,
+ DDA_DOORBELL_LOGICAL_COMMAND);
+
+ //
+ // Clear all SRB entries in device extension.
+ //
+
+ for (i=0; i<256; i++) {
+ deviceExtension->Srb[i] = NULL;
+ }
+
+ return TRUE;
+
+} // end DsaInitialize()
+
+
+ULONG
+DsaFindAdapter(
+ 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 fills in the configuration information structure
+
+Arguments:
+
+ HwDeviceExtension - Supplies a pointer to the device extension.
+ Context - Supplies adapter initialization structure.
+ BusInformation - Unused.
+ ArgumentString - Unused.
+ ConfigInfo - Pointer to the configuration information structure.
+ Again - Indicates that system should continue search for adapters.
+
+Return Value:
+
+ SP_RETURN_FOUND - Indicates adapter found.
+ SP_RETURN_NOT_FOUND - Indicates adapter not found.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PACCESS_RANGE accessRange;
+
+ //
+ // Get access range.
+ //
+
+ accessRange = &((*(ConfigInfo->AccessRanges))[0]);
+
+ if (accessRange->RangeLength == 0) {
+
+ if (!SearchEisaBus(HwDeviceExtension,
+ Context,
+ ConfigInfo)) {
+
+
+ //
+ // Tell system nothing was found and not to call again.
+ //
+
+ *Again = FALSE;
+ return SP_RETURN_NOT_FOUND;
+ }
+ }
+
+ //
+ // Get system-mapped controller address.
+ //
+
+ deviceExtension->Bmic =
+ ScsiPortGetDeviceBase(HwDeviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ accessRange->RangeStart,
+ accessRange->RangeLength,
+ (BOOLEAN)!accessRange->RangeInMemory);
+
+
+ ConfigInfo->NumberOfBuses = 1;
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+ ConfigInfo->Dma32BitAddresses = TRUE;
+
+
+ //
+ // Initialize controller.
+ //
+
+ DsaInitialize(deviceExtension);
+
+ //
+ // Get firmware version.
+ //
+
+ if (!ExtendedCommand(deviceExtension,
+ 0,
+ DDA_GET_FIRMWARE_VERSION)) {
+
+ DebugPrint((1,"DsaFindAdapter: Couldn't get firmware version\n"));
+ return SRB_STATUS_ERROR;
+ }
+
+ deviceExtension->MajorVersion =
+ ScsiPortReadPortUshort((PUSHORT)&deviceExtension->Bmic->Command);
+
+ deviceExtension->MinorVersion =
+ ScsiPortReadPortUshort((PUSHORT)&deviceExtension->Bmic->TransferCount);
+
+ //
+ // Release semaphore.
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SubmissionSemaphore, 0);
+
+ //
+ // Beta versions of DDA do not have scatter/gather. Versions prior
+ // to 1.23 have a starvation bug that makes command queueing risky.
+ // We simply won't run on these dinosaurs.
+ //
+
+ if (deviceExtension->MajorVersion == 1 &&
+ deviceExtension->MinorVersion <= 22) {
+
+ //
+ // Log error and return.
+ //
+
+ ScsiPortLogError(HwDeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_BAD_FW_ERROR,
+ 5 << 8);
+
+ return SRB_STATUS_ERROR;
+ }
+
+ //
+ // DDA adapters support scatter/gather with the caveat that the descriptors
+ // must be sector aligned and can't handle large transfers.
+ //
+
+ if (deviceExtension->MajorVersion == 1) {
+ ConfigInfo->AlignmentMask = 511;
+ ConfigInfo->MaximumTransferLength = 0x8000;
+ ConfigInfo->NumberOfPhysicalBreaks = 8;
+ } else {
+ ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SG_DESCRIPTORS;
+ }
+
+ //
+ // Get noncached extension for identify requests.
+ //
+
+ deviceExtension->IdentifyBuffer =
+ ScsiPortGetUncachedExtension(deviceExtension,
+ ConfigInfo,
+ 512);
+
+ //
+ // Get hardware configuration.
+ //
+
+ if (!ExtendedCommand(deviceExtension,
+ 0,
+ DDA_GET_HARDWARE_CONFIGURATION)) {
+
+ DebugPrint((1,"DsaFindAdapter: Couldn't get hw configuration\n"));
+ return SRB_STATUS_ERROR;
+ }
+
+ //
+ // Record interrupt level.
+ //
+
+ ConfigInfo->BusInterruptLevel = ScsiPortReadPortUchar(&deviceExtension->Bmic->Command);
+
+ //
+ // Release semaphore.
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SubmissionSemaphore, 0);
+
+ //
+ // Read Number of drives and emulation mode.
+ //
+
+ if (!ExtendedCommand(deviceExtension,
+ 0,
+ DDA_GET_NUMBER_LOGICAL_DRIVES)) {
+
+ DebugPrint((1,"DsaFindAdapter: Couldn't get number of drives\n"));
+
+ return SRB_STATUS_ERROR;
+ }
+
+ deviceExtension->NumberOfLogicalDrives =
+ ScsiPortReadPortUchar(&deviceExtension->Bmic->Command);
+ deviceExtension->EmulationMode =
+ ScsiPortReadPortUchar(&deviceExtension->Bmic->DriveNumber);
+
+ //
+ // Release semaphore.
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SubmissionSemaphore, 0);
+
+ //
+ // Check if any logical drives reported.
+ //
+
+ DebugPrint((1,
+ "DsaFindAdapter: numDrives %d emulation %d\n",
+ deviceExtension->NumberOfLogicalDrives,
+ deviceExtension->EmulationMode));
+
+ if (!deviceExtension->NumberOfLogicalDrives) {
+
+ DebugPrint((1,"DsaFindAdapter: No logical drives defined\n"));
+ return SP_RETURN_NOT_FOUND;
+ }
+
+ //
+ // Tell system to look for more adapters.
+ //
+
+ *Again = TRUE;
+
+ return SP_RETURN_FOUND;
+
+} // end DsaFindAdapter()
+
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+ This is the initial entry point for system initialization.
+
+Arguments:
+
+ DriverObject - System's representation of this driver.
+ Argument2 - Not used.
+
+Return Value:
+
+ BOOLEAN
+
+--*/
+
+{
+ HW_INITIALIZATION_DATA hwInitializationData;
+ ULONG eisaSlotNumber;
+ ULONG i;
+
+ DebugPrint((1,"\n\nDELL DSA/DDA 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 = DsaInitialize;
+ hwInitializationData.HwResetBus = DsaResetBus;
+ hwInitializationData.HwStartIo = DsaStartIo;
+ hwInitializationData.HwInterrupt = DsaInterrupt;
+ hwInitializationData.HwFindAdapter = DsaFindAdapter;
+
+ //
+ // Indicate no buffer mapping but will need physical addresses.
+ //
+
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+
+ //
+ // Specify size of extensions.
+ //
+
+ hwInitializationData.DeviceExtensionSize =
+ sizeof(DEVICE_EXTENSION);
+
+ //
+ // Specifiy the bus type.
+ //
+
+ hwInitializationData.AdapterInterfaceType = Eisa;
+ hwInitializationData.NumberOfAccessRanges = 3;
+
+ //
+ // Ask for SRB extensions for command lists.
+ //
+
+ hwInitializationData.SrbExtensionSize = sizeof(DDA_REQUEST_BLOCK);
+
+ //
+ // Indicate that this controller supports multiple outstand
+ // requests to its devices.
+ //
+
+ hwInitializationData.MultipleRequestPerLu = TRUE;
+ hwInitializationData.AutoRequestSense = TRUE;
+
+ //
+ // Set the context parameter to indicate that the search for controllers
+ // should start at the first EISA slot. This is only for a manual search
+ // by the miniport driver, if the system does not pass in predetermined
+ // configuration.
+ //
+
+ eisaSlotNumber = 0;
+
+ //
+ // Call the system to search for this adapter.
+ //
+
+ return
+ ScsiPortInitialize(DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &eisaSlotNumber);
+
+} // end DriverEntry()
+
diff --git a/private/ntos/miniport/dell/delldsa.h b/private/ntos/miniport/dell/delldsa.h
new file mode 100644
index 000000000..b26ebaab2
--- /dev/null
+++ b/private/ntos/miniport/dell/delldsa.h
@@ -0,0 +1,210 @@
+
+#pragma pack(1)
+
+#define DELLDSA_MAJOR_VERSION 1
+#define DELLDSA_MINOR_VERSION 0
+
+#define MAXIMUM_SG_DESCRIPTORS 16
+#define MAXIMUM_DDA_SG_DESCRIPTORS 8
+#define MAXIMUM_XFER_SIZE 0x8000
+
+#define DDA_ID 0x0040ac10 // Least significant nibble will be masked.
+
+//
+// Logical Identify Command
+//
+
+typedef struct _DDA_INDENTIFY {
+ ULONG TotalSectors;
+ USHORT LogicalNumberOfHeads;
+ USHORT LogicalSectorsPerTrack;
+ USHORT TotalLogicalCylinders;
+ USHORT PhysicalNumberOfHeads;
+ USHORT PhysicalSectorsPerTrack;
+ USHORT TotalPhysicalCylinders;
+ USHORT ReservedCylinders;
+ UCHAR MaximumTransfer;
+ UCHAR Multiple;
+ USHORT DataDriveBitMap;
+ USHORT ParityDriveBitMap;
+ UCHAR ConfiguredType;
+ UCHAR Type;
+ UCHAR Status;
+ UCHAR Reserved;
+ ULONG PatchAddress;
+ ULONG ErrorLogAddress;
+ ULONG NumberErrorEventsLogged;
+ ULONG NumberRemappedStripes;
+ ULONG ErrorsPerDrive[10];
+ ULONG FirmWareRevision;
+ UCHAR EmulationMode;
+ UCHAR MaximumReadAhead;
+ UCHAR PostWritesEnabled;
+ UCHAR CacheEnabled;
+ ULONG BmicBurstSize;
+ UCHAR SourceRevision[32];
+} DDA_IDENTIFY, *PDDA_IDENTIFY;
+
+//
+// DDA BMIC Registers
+//
+
+typedef struct _DDA_REGISTERS {
+ ULONG BoardId; // ?C80
+ UCHAR Reserved1[5]; // ?C84
+ UCHAR InterruptControl; // ?C89
+ UCHAR SubmissionSemaphore; // ?C8A
+ UCHAR CompletionSemaphore; // ?C8B
+ UCHAR Reserved2; // ?C8C
+ UCHAR SubmissionDoorBell; // ?C8D
+ UCHAR CompletionInterruptMask; // ?C8E
+ UCHAR CompletionDoorBell; // ?C8F
+ UCHAR Command; // ?C90
+ UCHAR DriveNumber; // ?C91
+ UCHAR TransferCount; // ?C92
+ UCHAR RequestIdOut; // ?C93
+ ULONG StartingSector; // ?C94
+ ULONG DataAddress; // ?C98
+ UCHAR Status; // ?C9C
+ UCHAR SectorsRemaining; // ?C9D
+ UCHAR RequestIdIn; // ?C9E
+} DDA_REGISTERS, *PDDA_REGISTERS;
+
+//
+// Logical command definitions
+//
+
+#define DDA_COMMAND_RECALIBRATE 0x00
+#define DDA_COMMAND_READ 0x01
+#define DDA_COMMAND_WRITE 0x02
+#define DDA_COMMAND_VERIFY 0x03
+#define DDA_COMMAND_SEEK 0x04
+#define DDA_COMMAND_GUARDED 0x05
+#define DDA_COMMAND_IDENTIFY 0x0A
+#define DDA_COMMAND_READLOG 0x0D
+#define DDA_COMMAND_SG_READ 0x0E
+#define DDA_COMMAND_SG_WRITE 0x0F
+#define DDA_COMMAND_INITLOG 0x10
+#define DDA_COMMAND_REMAP_BLOCK 0x12
+#define DDA_COMMAND_SG_READB 0x18
+#define DDA_COMMAND_SG_WRITEB 0x19
+#define DDA_COMMAND_READPUNLOG 0x1E
+#define DDA_COMMAND_INITPUNLOG 0x1F
+#define DDA_COMMAND_READCTLRLOG 0x20
+#define DDA_COMMAND_INITCTLRLOG 0x21
+#define DDA_COMMAND_CONVERTPDEV 0x22
+#define DDA_COMMAND_QUIESCEPUN 0x23
+#define DDA_COMMAND_SCANDEVICES 0x24
+#define DDA_COMMAND_RESERVED1 0x25
+
+//
+// Extended command definitiions
+//
+
+#define DDA_GET_FIRMWARE_VERSION 0x02
+#define DDA_GET_MAXIMUM_COMMANDS 0x03
+#define DDA_GET_NUMBER_LOGICAL_DRIVES 0x06
+#define DDA_GET_LOGICAL_GEOMETRY 0x07
+#define DDA_GET_HARDWARE_CONFIGURATION 0x0F
+
+//
+// Status register definitions
+//
+
+#define DDA_STATUS_NO_ERROR 0x00
+#define DDA_STATUS_TIMEOUT 0x01
+#define DDA_STATUS_TRACK0_NOT_FOUND 0x02
+#define DDA_STATUS_ABORTED 0x04
+#define DDA_STATUS_CORRECTABLE_ERROR 0x08
+#define DDA_STATUS_SECTOR_ID_NOT_FOUND 0x10
+#define DDA_STATUS_WRITE_ERROR 0x20
+#define DDA_STATUS_UNCORRECTABLE_ERROR 0x40
+#define DDA_STATUS_BAD_BLOCK_FOUND 0x80
+
+#define DDA_PUP_DEAD 0 // controller died
+#define DDA_PUP_OK 1 // normal
+#define DDA_PUP_NOTCONFIG 2 // no configuration (virgin)
+#define DDA_PUP_BADCONFIG 3 // bad drive configuration
+#define DDA_PUP_RECOVER 4 // new drive - recovery possible
+#define DDA_PUP_DF_CORR 5 // drive failed - correctable
+#define DDA_PUP_DF_UNCORR 6 // drive failed - uncorrectable
+#define DDA_PUP_NODRIVES 7 // no drives attached
+#define DDA_PUP_DRIVESADDED 8 // more drives than expected
+#define DDA_PUP_MAINTAIN 9 // maintain mode
+#define DDA_PUP_MANFMODE 10 // manufacturing mode
+#define DDA_PUP_NEW 11 // new - needs remap generated
+#define DDA_PUP_NONE 14 // no drive configuration
+
+//
+// DDA Scatter/Gather Descriptor definitions
+//
+
+typedef struct _SG_DESCRIPTOR {
+ ULONG Address;
+ ULONG Count;
+} SG_DESCRIPTOR, *PSG_DESCRIPTOR;
+
+typedef struct _SG_LIST {
+ SG_DESCRIPTOR Descriptor[MAXIMUM_SG_DESCRIPTORS];
+} SG_LIST, *PSG_LIST;
+
+#define DDA_REQUEST_IRP 0
+#define DDA_REQUEST_IOCTL 1
+
+typedef struct _DDA_REQUEST_BLOCK {
+ SG_LIST SgList;
+ struct _DDA_REQUEST_BLOCK *Next;
+ ULONG StartingSector;
+ ULONG PhysicalAddress;
+ UCHAR Command;
+ UCHAR DriveNumber;
+ UCHAR Size;
+ UCHAR RequestId;
+} DDA_REQUEST_BLOCK, *PDDA_REQUEST_BLOCK;
+
+//
+// Emulation mode definitions
+//
+
+#define DDA_EMULATION_NONE 0x00
+#define DDA_EMULATION_ADAPTEC 0x01
+
+//
+// Get Geometry registers
+//
+
+typedef struct _DDA_GET_GEOMETRY {
+ ULONG Reserved[4];
+ ULONG TotalCapacity;
+ UCHAR NumberOfHeads;
+ UCHAR SectorsPerTrack;
+ USHORT NumberOfCylinders;
+ USHORT PhysicalSpt;
+ UCHAR PhysicalHeads;
+ UCHAR CurrentStatus;
+} DDA_GET_GEOMETRY, *PDDA_GET_GEOMETRY;
+
+#pragma pack()
+
+//
+// Doorbell definitions
+//
+
+#define DDA_DOORBELL_SOFT_RESET 0x08
+#define DDA_DOORBELL_LOGICAL_COMMAND 0x10
+#define DDA_DOORBELL_PHYSICAL_COMMAND 0x20
+#define DDA_DOORBELL_EXTENDED_COMMAND 0x40
+#define DDA_DOORBELL_HARD_RESET 0x80
+
+#define DDA_INTERRUPTS (DDA_DOORBELL_LOGICAL_COMMAND|DDA_DOORBELL_EXTENDED_COMMAND)
+
+//
+// Interface mode values
+//
+
+#define IMODE_RUN 0
+#define IMODE_RESET 1
+#define IMODE_SUBMIT 2
+#define IMODE_EXTENDED 3
+#define IMODE_EXTDONE 4
+
diff --git a/private/ntos/miniport/dell/delldsa.rc b/private/ntos/miniport/dell/delldsa.rc
new file mode 100644
index 000000000..4281469e1
--- /dev/null
+++ b/private/ntos/miniport/dell/delldsa.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Dell Disk Array Driver"
+#define VER_INTERNALNAME_STR "delldsa.sys"
+#define VER_ORIGINALFILENAME_STR "delldsa.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/dell/makefile b/private/ntos/miniport/dell/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/miniport/dell/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 OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/dell/sources b/private/ntos/miniport/dell/sources
new file mode 100644
index 000000000..80ff399f7
--- /dev/null
+++ b/private/ntos/miniport/dell/sources
@@ -0,0 +1,40 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=delldsa
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=MINIPORT
+
+INCLUDES=..\..\inc
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+!IF $(ALPHA)
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib $(BASEDIR)\public\sdk\lib\*\libcntpr.lib
+!ENDIF
+SOURCES=delldsa.c delldsa.rc
+
+