summaryrefslogtreecommitdiffstats
path: root/private/ntos/miniport/compaq
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/miniport/compaq/cpqarray.c3819
-rw-r--r--private/ntos/miniport/compaq/cpqarray.h412
-rw-r--r--private/ntos/miniport/compaq/cpqarray.rc13
-rw-r--r--private/ntos/miniport/compaq/cpqsczmp.h211
-rw-r--r--private/ntos/miniport/compaq/cpqsmngr.h509
-rw-r--r--private/ntos/miniport/compaq/makefile6
-rw-r--r--private/ntos/miniport/compaq/pcibios.h27
-rw-r--r--private/ntos/miniport/compaq/scsireg.h223
-rw-r--r--private/ntos/miniport/compaq/sources39
9 files changed, 5259 insertions, 0 deletions
diff --git a/private/ntos/miniport/compaq/cpqarray.c b/private/ntos/miniport/compaq/cpqarray.c
new file mode 100644
index 000000000..b5a0219d3
--- /dev/null
+++ b/private/ntos/miniport/compaq/cpqarray.c
@@ -0,0 +1,3819 @@
+/*++
+
+Copyright (c) 1993-4 Microsoft Corporation
+
+Module Name:
+
+ cpqarray.c
+
+Abstract:
+
+ This is the device driver for the Compaq Intelligent Disk Array.
+
+Authors:
+
+ Mike Glass (mglass)
+
+Environment:
+
+ kernel mode only
+
+Notes:
+
+ Compaq Information Manager (CIM) support was developed by Tom Bonola and
+ Tom Woller, courtesy of Compaq Computer Corporation.
+
+Revision History:
+
+--*/
+
+#ifndef BYTE
+#define BYTE unsigned char
+#endif
+
+#ifndef WORD
+#define WORD unsigned short
+#endif
+
+#ifndef DWORD
+#define DWORD unsigned long
+#endif
+
+#ifndef INT
+#define INT int
+#endif
+
+#ifndef STATIC
+#if DBG
+#define STATIC
+#else
+#define STATIC static
+#endif
+#endif
+
+
+
+#include "miniport.h"
+#include "scsi.h"
+#include <ntddscsi.h>
+#include <scsireg.h>
+#include <cpqsczmp.h> // Compaq SCSI M&P definitions
+#include "cpqarray.h"
+#include "pcibios.h"
+
+
+//
+// Adapter storage area
+//
+
+typedef struct _DEVICE_EXTENSION {
+
+ //
+ // Requests needing restarts
+ //
+
+ PCOMMAND_LIST RestartRequests;
+
+ //
+ // IDA BMIC registers
+ //
+
+ PIDA_CONTROLLER Bmic;
+ PULONG CPFIFO;
+ PULONG CCFIFO;
+ PULONG InterruptMask;
+ PULONG InterruptStatus;
+ PULONG InterruptPending;
+ HBA_CONFIGURATION HBAConfiguration; //Memory mapped base
+ ULONG BaseIOAddress; // I/O space accessible, not used.
+ PEISAPCI_CONTROLLER eisapci;
+ ULONG PCIoff;
+
+ //
+ // Noncached extension for identify commands
+ //
+
+ PVOID IdentifyBuffer;
+
+ //
+ // Number of logical drives
+ //
+
+ ULONG NumberOfLogicalDrives;
+ UCHAR SectorShift; //setup to 9
+ ULONG EisaId;
+ UCHAR IrqLevel;
+ IDENTIFY_CONTROLLER IdentifyData; // permanent controller info storage
+
+} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
+
+//
+// Drive storage area
+//
+
+typedef struct _LOGICAL_UNIT_EXTENSION {
+
+ //
+ // Drive indentify data.
+ //
+
+ IDENTIFY_LOGICAL_DRIVE IdentifyData;
+ SENSE_CONFIGURATION SenseData; // sense data for logical drive
+
+} LOGICAL_UNIT_EXTENSION, *PLOGICAL_UNIT_EXTENSION;
+
+#include "cpqsmngr.h"
+
+VOID
+BuildFlushDisable(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+);
+
+ULONG
+IdaProcessIoctl(
+ IN PDEVICE_EXTENSION pIdaDeviceExtension,
+ PVOID pIoctlBuffer,
+ IN PSCSI_REQUEST_BLOCK Srb
+);
+ULONG
+BuildCIMList(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+);
+VOID
+IdaMoveMemory(
+ OUT PUCHAR pDestination,
+ IN PUCHAR pSource,
+ IN ULONG ulLength
+);
+
+BOOLEAN
+IdaStrCmp(
+ IN PUCHAR p1,
+ IN PUCHAR p2
+);
+
+VOID
+IdaEnableInts(IN PDEVICE_EXTENSION);
+
+
+VOID
+IdaDisableInts(IN PDEVICE_EXTENSION);
+
+
+BOOLEAN
+SearchEisaBus(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from IdaFindAdapter 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 Compaq IDA 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 info 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 Compaq IDA board id.
+ //
+
+ if ((slotInformation->CompressedId & 0x00FFFFFF) == 0x0040110E) {
+ break;
+ }
+ }
+
+ //
+ // Check if all slots searched.
+ //
+
+ if (eisaSlotNumber == 16) {
+ return FALSE;
+ }
+
+ //
+ // Set up default port address.
+ //
+
+ accessRange->RangeStart.LowPart =
+ (eisaSlotNumber * 0x1000) + 0x0C80;
+ accessRange->RangeLength = sizeof(IDA_CONTROLLER);
+
+ accessRange++;
+
+ ConfigInfo->SlotNumber = eisaSlotNumber;
+
+ //
+ // 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 = LevelSensitive;
+ }
+
+ //
+ // 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,
+ "CPQARRAY: 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;
+
+} // end SearchEisaBus()
+
+
+BOOLEAN
+IdaInitialize(
+ 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;
+
+
+ if (deviceExtension->HBAConfiguration.bHBAModel == IDA_EISA_DAZZLER) {
+
+ {
+ ULONG tmp;
+ DebugPrint((3,"CPQARRAY: Initing DAZZLER\n"));
+ tmp = ScsiPortReadPortUlong(&deviceExtension->eisapci->CPFIFO);
+ DebugPrint((3,"IdaInitialize: Room for %x requests\n",tmp));
+ }
+
+ //
+ // Enable command completion interrupts and not channel clear
+ //
+ ScsiPortWritePortUlong(&deviceExtension->eisapci->InterruptMask,
+ IDA_PCI_FIFO_NOT_EMPTY_MASK);
+ } else {
+
+ //
+ // Enable completion interrupts.
+ //
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->InterruptControl,
+ IDA_COMPLETION_INTERRUPT_ENABLE);
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SystemDoorBellMask,
+ IDA_COMPLETION_INTERRUPT_ENABLE);
+ }
+
+ return TRUE;
+} // end IdaInitialize()
+
+
+BOOLEAN
+IdaInitializePCI(
+ 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
+
+--*/
+
+{
+ PULONG ptmp;
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+
+ DebugPrint((1,"CPQARRAY: Initing PCI DAZZLER at 0x%x\n",
+ deviceExtension->HBAConfiguration.ulBaseIOAddress));
+ //
+ // Enable command completion interrupts and not channel clear
+ //
+ ptmp = deviceExtension->InterruptMask;
+ ptmp[0] |= IDA_PCI_FIFO_NOT_EMPTY_MASK;
+
+ DebugPrint((1,"IdaInitializePCI: Room for %x requests\n",
+ *((PULONG)deviceExtension->CPFIFO)));
+
+ return TRUE;
+
+} // end IdaInitializePCI()
+
+
+
+BOOLEAN
+IdaResetBus(
+ 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
+
+--*/
+
+{
+
+#ifndef NCPQNO_TIMEOUT
+ //
+ // 10 second timeout is inappropriate for IDA-style controllers. The
+ // better approach is to never timeout any requests. Proper fix is
+ // to have a class driver for IDA and set the timeout for each type
+ // of controller (currently 3 minutes is a good timeout).
+ //
+/* ScsiPortLogError(HwDeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_REQUEST_TIMEOUT,
+ 1); */
+#else
+
+ //
+ // Complete all outstanding requests.
+ //
+
+ ScsiPortCompleteRequest(HwDeviceExtension,
+ (UCHAR)PathId,
+ 0xFF,
+ 0xFF,
+ SRB_STATUS_BUS_RESET);
+#endif
+
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ HwDeviceExtension,
+ NULL);
+
+ return TRUE;
+
+} // end IdaResetBus()
+
+
+VOID
+BuildCommandList(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine builds a command list suitable for submission to the
+ Compaq IDA controller, from an SRB.
+
+Arguments:
+
+ DeviceExtension - Address of adapter storage area.
+ Srb - System request.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCOMMAND_LIST commandList = Srb->SrbExtension;
+ PVOID dataPointer;
+ ULONG physicalAddress;
+ ULONG bytesLeft;
+ ULONG descriptor;
+ ULONG length;
+
+ //
+ // Save SRB address for interrupt routine.
+ //
+
+ commandList->SrbAddress = Srb;
+
+ //
+ // Set up Command List Header.
+ //
+
+ commandList->CommandListHeader.LogicalDriveNumber = Srb->TargetId;
+
+ commandList->CommandListHeader.RequestPriority = CL_NORMAL_PRIORITY;
+
+ commandList->CommandListHeader.Flags =
+ CL_FLAGS_NOTIFY_LIST_COMPLETE + CL_FLAGS_NOTIFY_LIST_ERROR;
+
+ //
+ // Terminate request list.
+ //
+
+ commandList->RequestHeader.NextRequestOffset = 0;
+
+ //
+ // Clear request tracking flags.
+ //
+
+ commandList->Flags = 0;
+
+ //
+ // Determine command.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+ commandList->RequestHeader.CommandByte = RH_COMMAND_READ;
+ } else {
+ commandList->RequestHeader.CommandByte = RH_COMMAND_WRITE;
+ }
+
+ //
+ // Reset error code.
+ //
+
+ commandList->RequestHeader.ErrorCode = 0;
+
+ //
+ // Clear reserved field.
+ //
+
+ commandList->RequestHeader.Reserved = 0;
+
+ //
+ // Determine number of blocks to transfer.
+ //
+
+ commandList->RequestHeader.BlockCount =
+ ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb |
+ ((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8;
+
+ //
+ // Determine number starting block.
+ //
+
+ commandList->RequestHeader.BlockNumber =
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24;
+
+ //
+ // Build scatter/gather descriptor list.
+ //
+
+ descriptor = 0;
+ dataPointer = Srb->DataBuffer;
+ bytesLeft = Srb->DataTransferLength;
+
+ do {
+
+ //
+ // Get physical address and length of contiguous
+ // physical buffer.
+ //
+
+ physicalAddress =
+ 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;
+ }
+
+ //
+ // Fill in descriptor.
+ //
+
+ commandList->SgDescriptor[descriptor].Address = physicalAddress;
+ commandList->SgDescriptor[descriptor].Length = length;
+
+ //
+ // Adjust counts.
+ //
+
+ dataPointer = (PUCHAR)dataPointer + length;
+ bytesLeft -= length;
+ descriptor++;
+
+ } while (bytesLeft);
+
+ //
+ // Calculate size of command list.
+ //
+
+ commandList->RequestHeader.ScatterGatherCount = (UCHAR) descriptor;
+ commandList->CommandListSize = sizeof(COMMAND_LIST_HEADER) +
+ sizeof(REQUEST_HEADER) +
+ sizeof(SG_DESCRIPTOR) *
+ descriptor;
+
+ return;
+
+} // end BuildCommandList()
+
+VOID
+SubmitCommandList(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PCOMMAND_LIST CommandList
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to submit a command list to the controller. If
+ the controller can't take it within a specified time interval, then the
+ request is queued to be retried after another request completes.
+
+Arguments:
+
+ DeviceExtension - Address of adapter storage area.
+ CommandList - Request to be submitted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG physicalAddress;
+ ULONG length;
+ ULONG i;
+ PULONG ptmp;
+ ULONG tmp;
+
+#ifdef DBG
+ DebugPrint((3,
+ "%x %x %x %x Cmd=%x %x Bln=%x Blc=%x SGc=%x %x SG0l=%x SG0a=%x\n",
+ CommandList->CommandListHeader.LogicalDriveNumber,
+ CommandList->CommandListHeader.RequestPriority,
+ CommandList->CommandListHeader.Flags,
+ CommandList->RequestHeader.NextRequestOffset,
+ CommandList->RequestHeader.CommandByte,
+ CommandList->RequestHeader.ErrorCode,
+ CommandList->RequestHeader.BlockNumber,
+ CommandList->RequestHeader.BlockCount,
+ CommandList->RequestHeader.ScatterGatherCount,
+ CommandList->RequestHeader.Reserved,
+ CommandList->SgDescriptor[0].Length,
+ CommandList->SgDescriptor[0].Address
+ ));
+
+ if (CommandList->RequestHeader.ScatterGatherCount > 1) {
+
+ for (i=1;i<CommandList->RequestHeader.ScatterGatherCount;i++) {
+ DebugPrint((1,
+ "%d-l=%x a=%x ",
+ i,CommandList->SgDescriptor[i].Length,
+ CommandList->SgDescriptor[i].Address
+ ));
+ }
+
+ DebugPrint((3,"\n"));
+ }
+#endif
+
+ //
+ // Check for double submission.
+ //
+
+ if (CommandList->Flags & CL_FLAGS_REQUEST_STARTED) {
+
+ DebugPrint((0,
+ "CPQARRAY: SubmitCommandList: Double submission %x\n"));
+
+ //
+ // Log this error.
+ //
+
+ ScsiPortLogError(DeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 1);
+
+ return;
+ }
+
+ //
+ // Get physical address of command list.
+ //
+
+ physicalAddress =
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ NULL,
+ CommandList,
+ &length).LowPart;
+
+ // Handle slightly different Command Header in case of SMART-2
+ // controllers. Probably should introduce union to clearify
+ // Command Header structure instead of setting .Flags to List
+ // size. Size is in dwords not bytes as was the case in SMART
+ // and previous ida controllers.
+
+ if (DeviceExtension->HBAConfiguration.bHBAModel == IDA_PCI_DAZZLER) {
+
+ DebugPrint((9,"SubmitCommandList: DAZZLER PCI card\n"));
+
+ CommandList->CommandListHeader.RequestPriority = 0;
+
+ CommandList->CommandListHeader.Flags =
+ ((CommandList->CommandListSize % 4) ? 1 : 0) +
+ (CommandList->CommandListSize >> 2);
+
+ ptmp = DeviceExtension->CPFIFO;
+
+ do {
+ tmp = ptmp[0];
+ ptmp[0] = physicalAddress;
+ } while (tmp == 0);
+
+ DebugPrint((3,
+ "SubmitCommandList: ptmp=0x%x physicalAddress=0x%x\n",
+ ptmp,physicalAddress));
+ CommandList->Flags |= CL_FLAGS_REQUEST_STARTED;
+
+ } else if ((DeviceExtension->HBAConfiguration.bHBAModel ==
+ IDA_EISA_DAZZLER) && !DeviceExtension->PCIoff ) {
+ DebugPrint((9,"SubmitCommandList: DAZZLER EISA PCI interface\n"));
+ CommandList->CommandListHeader.RequestPriority = 0;
+ CommandList->CommandListHeader.Flags =
+ ((CommandList->CommandListSize % 4) ? 1 : 0) +
+ (CommandList->CommandListSize/4);
+
+ //
+ // loop on CPFIFO until we have room to submit
+ //
+ do {
+ tmp = ScsiPortReadPortUlong(&DeviceExtension->eisapci->CPFIFO);
+ ScsiPortWritePortUlong(&DeviceExtension->eisapci->CPFIFO,
+ physicalAddress);
+ } while (tmp == 0);
+
+ CommandList->Flags |= CL_FLAGS_REQUEST_STARTED;
+ } else {
+ DebugPrint((9, "SubmitCommandList: DAZZLER EISA compatible interface\n"));
+
+ //
+ // Wait up to 100 microseconds for submission channel to clear.
+ //
+
+ for (i=0; i<100; i++) {
+
+ if (!(ScsiPortReadPortUchar(&DeviceExtension->Bmic->SystemDoorBell) &
+ SYSTEM_DOORBELL_SUBMIT_CHANNEL_CLEAR)) {
+
+ //
+ // Stall for a microsecond.
+ //
+
+ ScsiPortStallExecution(1);
+
+ } else {
+ break;
+ }
+
+ }
+
+ //
+ // Check for timeout.
+ //
+
+ if (i == 100) {
+
+ //
+ // Queue request for restart in completion routine.
+ //
+
+ DebugPrint((1,
+ "CPQARRAY: SubmitRequest: Queueing %x\n",
+ CommandList));
+
+ CommandList->Flags |= CL_FLAGS_REQUEST_QUEUED;
+ CommandList->NextEntry = DeviceExtension->RestartRequests;
+ DeviceExtension->RestartRequests = CommandList;
+
+ } else {
+
+ CommandList->Flags |= CL_FLAGS_REQUEST_STARTED;
+
+ //
+ // Reset channel clear bit to claim channel.
+ //
+
+ ScsiPortWritePortUchar(&DeviceExtension->Bmic->SystemDoorBell,
+ SYSTEM_DOORBELL_SUBMIT_CHANNEL_CLEAR);
+
+ //
+ // Write Command List physical address to BMIC mailbox.
+ //
+
+ ScsiPortWritePortUlong(&DeviceExtension->Bmic->CommandListSubmit.Address,
+ physicalAddress);
+
+ //
+ // Write Command List length to BMIC mailbox.
+ //
+
+ ScsiPortWritePortUshort(&DeviceExtension->Bmic->CommandListSubmit.Length,
+ CommandList->CommandListSize);
+
+ //
+ // Set channel busy bit to signal new Command List is available.
+ //
+
+ ScsiPortWritePortUchar(&DeviceExtension->Bmic->LocalDoorBell,
+ LOCAL_DOORBELL_COMMAND_LIST_SUBMIT);
+ }
+
+ }
+
+} // end SubmitCommandList()
+
+
+
+BOOLEAN
+IdaInterrupt(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This interrupt service routine is called by the system to process an
+ adapter interrupt. The Compaq IDA controller interrupts to signal
+ completion of a request.
+
+Arguments:
+
+ HwDeviceExtension - Address of adapter storage area.
+
+Return Value:
+
+ TRUE if adapter is interrupting.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG physicalAddress;
+ PCOMMAND_LIST commandList;
+ PCOMMAND_LIST nextCommand;
+ PSCSI_REQUEST_BLOCK srb;
+ UCHAR status;
+ PSRB_IO_CONTROL pSrb;
+ PIDA_ERROR_BITS dataPointer;
+ PUCHAR ReturnPointer;
+ PUCHAR MovePointer;
+ UCHAR CmdListStatus;
+ PULONG ptmp;
+
+ //
+ // Verify that interrupt is from one of our controllers.
+ //
+
+ if ((deviceExtension->HBAConfiguration.bHBAModel == IDA_EISA_DAZZLER) &&
+ !deviceExtension->PCIoff ) {
+ DebugPrint((3,"IdaInterrupt: DAZZLER PCI mode\n"));
+
+ //
+ // The PCI interface specification calls for us to check the
+ // InterruptPending register to verify that an interrupt has
+ // been asserted at our controller. We are instead looking
+ // at the InterruptStatus masked with 0x01 to acheive the same
+ // result. We cannot use the spec's method, because at init and
+ // during a rescan at runtime, we have disabled controller
+ // interrupts and thus InterruptPending will be set to zero.
+ //
+
+ if (!(ScsiPortReadPortUlong(&deviceExtension->eisapci->InterruptStatus)
+ & IDA_PCI_COMPLETION_STATUS_ACTIVE)) {
+
+ //
+ // Interrupt is not for this controller.
+ //
+
+ return FALSE;
+ }
+
+ //
+ // Read the physical address
+ //
+
+ physicalAddress = ScsiPortReadPortUlong(&deviceExtension->
+ eisapci->CCFIFO);
+
+ DebugPrint((1,"CCFIFO=%x\n",physicalAddress));
+
+ CmdListStatus = (UCHAR)physicalAddress &
+ IDA_PCI_COMPLETION_STATUS_MASK;
+
+ if (CmdListStatus & IDA_PCI_COMPLETION_ERROR) {
+
+ DebugPrint((1,"IdaInterrupt: DAZZLER ERROR bit 0 set\n"));
+
+ //
+ // for compatibility change the status to old style error code.
+ //
+
+ CmdListStatus = RH_BAD_COMMAND_LIST;
+ }
+
+ physicalAddress &= IDA_PCI_PHYS_ADDR_MASK;
+
+ } else if (deviceExtension->HBAConfiguration.bHBAModel
+ == IDA_BASE_CONTROLLER) {
+
+ //
+ // Check if interrupt is expected.
+ //
+
+ if (!(ScsiPortReadPortUchar(&deviceExtension->Bmic->SystemDoorBell) &
+ SYSTEM_DOORBELL_COMMAND_LIST_COMPLETE)) {
+
+ //
+ // Interrupt is spurious.
+ //
+
+ return FALSE;
+ }
+
+ //
+ // Get physical command list address from mailbox.
+ //
+
+ physicalAddress =
+ ScsiPortReadPortUlong(&deviceExtension->Bmic->
+ CommandListComplete.Address);
+
+ CmdListStatus =
+ ScsiPortReadPortUchar(&deviceExtension->Bmic->
+ CommandListComplete.Status);
+
+ //
+ // Dismiss interrupt at device by clearing command complete
+ // bit in system doorbell.
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SystemDoorBell,
+ SYSTEM_DOORBELL_COMMAND_LIST_COMPLETE);
+
+ //
+ // Free command completion channel.
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->LocalDoorBell,
+ LOCAL_DOORBELL_COMPLETE_CHANNEL_CLEAR);
+
+ } else if (deviceExtension->HBAConfiguration.bHBAModel
+ == IDA_PCI_DAZZLER) {
+
+ // Flags gets the list size and then write the phys addr out
+ // to the port
+ DebugPrint((3,"IdaInterrupt: DAZZLER PCI card\n"));
+
+ //
+ // The PCI interface specification calls for us to check the
+ // InterruptPending register to verify that an interrupt has
+ // been asserted at our controller. We are instead looking
+ // at the InterruptStatus masked with 0x01 to acheive the same
+ // result. We cannot use the spec's method, because at init and
+ // during a rescan at runtime, we have disabled controller
+ // interrupts and thus InterruptPending will be set to zero.
+ //
+
+ if (!(*((PULONG)deviceExtension->InterruptStatus) &
+ IDA_PCI_COMPLETION_STATUS_ACTIVE)) {
+
+ //
+ // Interrupt is not for this controller.
+ //
+
+ return FALSE;
+ }
+
+ //
+ // Read the physical address
+ //
+
+ ptmp = deviceExtension->CCFIFO;
+ physicalAddress = ptmp[0];
+
+ DebugPrint((9,"CCFIFO=%x\n",physicalAddress));
+
+ CmdListStatus = (UCHAR)physicalAddress & IDA_PCI_COMPLETION_STATUS_MASK;
+
+ if (CmdListStatus & IDA_PCI_COMPLETION_ERROR) {
+
+ DebugPrint((1,"IdaInterrupt: DAZZLER ERROR bit 0 set\n"));
+
+ CmdListStatus = RH_BAD_COMMAND_LIST;
+ }
+
+ physicalAddress &= IDA_PCI_PHYS_ADDR_MASK;
+
+ } else {
+
+ DebugPrint((1,"IdaInterrupt: ERROR - unknown HBA\n"));
+
+ }
+
+ //
+ // As a sanity check make sure physical address is not zero.
+ //
+
+ if (!physicalAddress) {
+
+ DebugPrint((1,
+ "IdaInterrupt: Physical address is zero\n"));
+
+ //
+ // Log this error.
+ //
+
+ ScsiPortLogError(HwDeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 2);
+
+ return TRUE;
+ }
+
+ //
+ // Get the virtual command list address.
+ //
+
+ commandList =
+ ScsiPortGetVirtualAddress(deviceExtension,
+ ScsiPortConvertUlongToPhysicalAddress(
+ physicalAddress));
+
+ DebugPrint((9, "Phys=%x %x\n",physicalAddress,commandList));
+
+ //
+ // As a sanity check make sure command list is not zero.
+ //
+
+ if (!commandList) {
+
+ DebugPrint((1, "IdaInterrupt: Command list is zero\n"));
+
+ //
+ // Log this error.
+ //
+
+ ScsiPortLogError(HwDeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 3);
+
+ return TRUE;
+ }
+
+ //
+ // Check for double completion.
+ //
+
+ if (commandList->Flags & CL_FLAGS_REQUEST_COMPLETED) {
+
+ DebugPrint((1, "IdaInterrupt: Double completion %x\n",
+ commandList));
+
+ //
+ // Log this error.
+ //
+
+ ScsiPortLogError(HwDeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 4);
+
+ return TRUE;
+
+ } else {
+
+ commandList->Flags |= CL_FLAGS_REQUEST_COMPLETED;
+ }
+
+ DebugPrint((3,"ErrorCode=%x\n", commandList->RequestHeader.ErrorCode));
+
+ if (CmdListStatus & RH_BAD_COMMAND_LIST)
+ commandList->RequestHeader.ErrorCode |= RH_BAD_COMMAND_LIST;
+
+ //
+ // Check request block error code.
+ //
+
+ DebugPrint((3,"ErrorCode=%x\n", commandList->RequestHeader.ErrorCode));
+
+ switch (commandList->RequestHeader.ErrorCode & ~RH_WARNING) {
+
+ case RH_SUCCESS:
+
+ status = SRB_STATUS_SUCCESS;
+ break;
+
+ case RH_FATAL_ERROR:
+
+ status = SRB_STATUS_ERROR;
+ break;
+
+ case RH_RECOVERABLE_ERROR:
+
+ status = SRB_STATUS_SUCCESS;
+ break;
+
+ case RH_INVALID_REQUEST:
+
+ status = SRB_STATUS_INVALID_REQUEST;
+ break;
+
+ case RH_REQUEST_ABORTED:
+
+ status = SRB_STATUS_ABORTED;
+ break;
+
+ default:
+
+ status = SRB_STATUS_ERROR;
+ break;
+ }
+
+ //
+ // Get SRB.
+ //
+
+ srb = commandList->SrbAddress;
+
+ //
+ // As a sanity check make sure SRB is not zero.
+ //
+
+ if (!srb) {
+
+ if (!commandList->Flags & CL_FLAGS_IDENTIFY_REQUEST) {
+
+ DebugPrint((1, "IdaInterrupt: SRB is zero\n"));
+
+ //
+ // Log this error.
+ //
+
+ ScsiPortLogError(HwDeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 5);
+ }
+
+ return TRUE;
+ }
+
+ if (srb->Function == SRB_FUNCTION_IO_CONTROL) {
+
+ pSrb = (PSRB_IO_CONTROL)srb->DataBuffer;
+
+ switch (pSrb->ControlCode) {
+ case CPQ_IOCTL_PASSTHROUGH:
+ {
+ dataPointer = (PIDA_ERROR_BITS)((PUCHAR)srb->DataBuffer
+ + srb->DataTransferLength
+ - sizeof(IDA_ERROR_BITS));
+
+ if (CmdListStatus & RH_BAD_COMMAND_LIST) {
+ DebugPrint((1,
+ "IdaInterrupt: BAD_COMMAND_LIST error for PASSTHRU to %x\n",
+ deviceExtension));
+
+ dataPointer->ControllerError = RH_BAD_COMMAND_LIST |
+ (ULONG)commandList->RequestHeader.ErrorCode;
+ } else {
+ dataPointer->ControllerError =
+ (ULONG)commandList->RequestHeader.ErrorCode;
+ }
+
+ break;
+ }
+
+ case CPQ_IOCTL_SCSIPASSTHROUGH:
+ {
+
+ PSCSI_BUFFER_HEADER dataPacket;
+ ULONG bufferOffset;
+
+ if (commandList->RequestHeader.BlockNumber == 1) {
+ DebugPrint((3,
+ "IdaInterrupt: SCSIPASSTHRU intermediate copy needed.\n"));
+
+ //
+ // if BlockNumber == 1 then need to copy the data at the end of the
+ // commandList into the user buffer.
+ //
+
+ ReturnPointer = (PUCHAR)srb->DataBuffer
+ + sizeof(SRB_IO_CONTROL)
+ + sizeof(MAP_PARAMETER_PACKET);
+
+ MovePointer = (PUCHAR)commandList + sizeof(SG_DESCRIPTOR)
+ + sizeof(COMMAND_LIST_HEADER)
+ + sizeof(REQUEST_HEADER)
+ + sizeof(SCSI_PASSTHRU);
+
+ IdaMoveMemory(ReturnPointer, MovePointer,
+ commandList->SgDescriptor[0].Length);
+ }
+
+ //
+ // setup the return fields in the return data area.
+ //
+
+ bufferOffset = sizeof(SRB_IO_CONTROL) + sizeof(SCSI_PASSTHRU);
+
+ dataPacket = (PSCSI_BUFFER_HEADER)((PUCHAR)srb->DataBuffer
+ + bufferOffset);
+
+ dataPacket->CmdError = (UCHAR)commandList->RequestHeader.ErrorCode;
+
+ dataPacket->device_status =
+ ((PSCSI_PASSTHRU) (&commandList->
+ SgDescriptor[
+ commandList->
+ RequestHeader.ScatterGatherCount
+ ].Length))->scsi_header.device_status;
+
+ dataPacket->machine_error =
+ ((PSCSI_PASSTHRU) (&commandList->
+ SgDescriptor[commandList->RequestHeader.
+ ScatterGatherCount
+ ].
+ Length))->scsi_header.machine_error;
+
+ if (CmdListStatus & RH_BAD_COMMAND_LIST) {
+ DebugPrint((1,
+ "IdaInterrupt: BAD_COMMAND_LIST error for SCSI PASSTHRU to %x\n",
+ deviceExtension));
+
+ dataPacket->CmdError = (UCHAR)(RH_BAD_COMMAND_LIST |
+ commandList->RequestHeader.ErrorCode);
+ }
+
+ }
+
+ default:
+ break;
+
+ } // end switch
+
+ }
+
+ srb->SrbStatus = status;
+
+ //
+ // Inform system that this request is complete.
+ //
+
+ ScsiPortNotification(RequestComplete, deviceExtension, srb);
+
+ //
+ // Check if any requests need restarting.
+ //
+
+ if (deviceExtension->RestartRequests) {
+
+ //
+ // Get pointer to head of list.
+ //
+
+ nextCommand = deviceExtension->RestartRequests;
+ deviceExtension->RestartRequests = NULL;
+
+ //
+ // Try to restart each request in the list.
+ //
+
+ while (nextCommand) {
+
+ commandList = nextCommand;
+ nextCommand = nextCommand->NextEntry;
+
+ DebugPrint((1, "IdaInterrupt: Restarting request %x\n",
+ commandList));
+
+ //
+ // Submit command list to controller.
+ //
+
+ SubmitCommandList(deviceExtension, commandList);
+ }
+
+ }
+
+ return TRUE;
+
+} // IdaInterrupt();
+
+BOOLEAN
+GetDiskIdentifyData(
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PVOID HwDeviceExtension,
+ IN PCOMMAND_LIST CommandList,
+ IN ULONG DriveNumber,
+ IN UCHAR Command
+ )
+
+/*++
+
+Routine Description:
+
+ Issue request to get identify data for this drive. This
+ routine has been modified for SMART-2 controller support.
+ Specifically, we are not accepting rescans for added logical
+ drives at run-time. Two functions have been added to
+ disable/enable controller interrupts while requesting details
+ from the firmware.
+
+Arguments:
+
+ HwDeviceExtension - Address of adapter storage area.
+ CommandList - Buffer for building request to controller.
+ DriveNumber - Identifies drive on controller.
+ Command - IDA command code.
+
+Return Value:
+
+ TRUE if successful.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG length;
+ ULONG i;
+ BOOLEAN intrtn;
+
+ //
+ // Disable controller interrupts. This action was added with support
+ // for the SMART-2 controllers and online logical drive configuration.
+ // Following the addition of one or more logical drives, a rescan will
+ // request information about the new drives. Since this routine will
+ // return requested information, we cannot simply submit the command
+ // and exit. To reduce the number of outstanding requests we find at
+ // the controller while searching for ours, interrupts are temporarily
+ // disabled at all array controllers. The impact of this should not be
+ // too significant, as we should not be rescanning often.
+ //
+
+ IdaDisableInts(deviceExtension);
+
+ //
+ // load srb for interrupt routine...
+ //
+
+ CommandList->SrbAddress = Srb;
+
+ //
+ // Set up Command List Header.
+ //
+
+ CommandList->CommandListHeader.LogicalDriveNumber = (UCHAR)DriveNumber;
+ CommandList->CommandListHeader.RequestPriority = CL_NORMAL_PRIORITY;
+
+ //
+ // Indicate no notification required.
+ //
+
+ CommandList->CommandListHeader.Flags = 0;
+
+ //
+ // Zero out unused fields.
+ //
+
+ CommandList->RequestHeader.NextRequestOffset = 0;
+ CommandList->RequestHeader.ErrorCode = RH_SUCCESS;
+ CommandList->RequestHeader.Reserved = 0;
+
+ //
+ // Determine command.
+ //
+
+ CommandList->RequestHeader.CommandByte = Command;
+
+ //
+ // Set up request control fields.
+ //
+
+ CommandList->RequestHeader.BlockCount = 1;
+ CommandList->RequestHeader.BlockNumber = 0;
+ CommandList->Flags = CL_FLAGS_IDENTIFY_REQUEST;
+
+ //
+ // Fill in scatter/gather entry.
+ //
+
+ CommandList->SgDescriptor[0].Length = 512;
+
+ CommandList->SgDescriptor[0].Address =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(HwDeviceExtension,
+ NULL,
+ deviceExtension->
+ IdentifyBuffer,
+ &length));
+
+ //
+ // Calculate size of command list.
+ //
+
+ CommandList->RequestHeader.ScatterGatherCount=1;
+ CommandList->CommandListSize = sizeof(COMMAND_LIST_HEADER) +
+ sizeof(REQUEST_HEADER) +
+ sizeof(SG_DESCRIPTOR);
+
+ //
+ // Submit command list to controller.
+ //
+
+ SubmitCommandList(deviceExtension, CommandList);
+
+ DebugPrint((1, "GetDiskIdentifyData: Command Submitted:\n"));
+
+ //
+ // Poll interrupt routine. We are planning to poll for quite
+ // some time. It appears that the initial request made to the
+ // Dazzler/P board takes sometime and if we don't wait long
+ // enough here, we will have problems at init and probably
+ // anytime a rescan is requested. Current setting is 6 minutes
+ // which is probably too long, but.....
+ //
+
+ for (i=0; i < 360000; i++) {
+
+ //
+ // Call interrupt routine directly.
+ //
+
+ IdaInterrupt(HwDeviceExtension);
+
+ DebugPrint((1, "GetDiskIdentifyData: IdaInterrupt called:\n"));
+
+ // check for my completion...
+ if (CommandList->Flags & CL_FLAGS_REQUEST_COMPLETED) {
+
+ //
+ // Check status of completed request.
+ //
+
+ if ((CommandList->RequestHeader.ErrorCode & ~RH_WARNING) ==
+ RH_SUCCESS) {
+ IdaEnableInts(deviceExtension);
+ return TRUE;
+ } else {
+ DebugPrint((1, "GetDiskIdentifyData: Command failed: %x\n",
+ CommandList->RequestHeader.ErrorCode));
+
+ //
+ // Command failed.
+ //
+
+ IdaEnableInts(deviceExtension);
+ return FALSE;
+ }
+
+ }
+
+ ScsiPortStallExecution(1000);
+
+ }
+
+ IdaEnableInts(deviceExtension);
+ return FALSE;
+
+} // end GetDiskIdentifyData()
+
+
+BOOLEAN
+IdaStartIo(
+ 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;
+ PLOGICAL_UNIT_EXTENSION luExtension;
+ ULONG i;
+ UCHAR status;
+
+ switch (Srb->Function) {
+
+ case SRB_FUNCTION_RESET_BUS:
+
+ if (!IdaResetBus(deviceExtension, Srb->PathId)) {
+ status = SRB_STATUS_ERROR;
+ } else {
+ status = SRB_STATUS_SUCCESS;
+ }
+
+ break;
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ switch (Srb->Cdb[0]) {
+
+ case SCSIOP_WRITE:
+ case SCSIOP_READ:
+
+ //
+ // Build command list from SRB.
+ //
+
+ BuildCommandList(deviceExtension,
+ Srb);
+
+ //
+ // Submit command list to controller.
+ //
+
+ SubmitCommandList(deviceExtension,
+ (PCOMMAND_LIST)Srb->SrbExtension);
+
+ status = SRB_STATUS_PENDING;
+ break;
+
+ case SCSIOP_TEST_UNIT_READY:
+
+ status = SRB_STATUS_SUCCESS;
+ break;
+
+ case SCSIOP_READ_CAPACITY:
+
+ //
+ // Get logical unit extension.
+ //
+ luExtension =
+ ScsiPortGetLogicalUnit(deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ if (luExtension) {
+ ULONG blockSize = luExtension->IdentifyData.BlockLength;
+
+ //
+ // 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,
+ &luExtension->IdentifyData.NumberOfBlocks);
+
+ DebugPrint((1, "IdaStartIo: Block size %x\n",
+ luExtension->IdentifyData.BlockLength));
+
+ DebugPrint((1, "IdaStartIo: Number of blocks %x\n",
+ luExtension->IdentifyData.NumberOfBlocks));
+
+ status = SRB_STATUS_SUCCESS;
+
+ } else {
+ status = SRB_STATUS_ERROR;
+ }
+
+ break;
+
+ case SCSIOP_INQUIRY:
+ //
+ // Only respond at logical unit 0;
+ //
+
+ if (Srb->Lun != 0) {
+ //
+ // Indicate no device found at this address.
+ //
+ status = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+ }
+
+ //
+ // Get number of logical drives.
+ //
+
+ if (GetDiskIdentifyData(Srb, HwDeviceExtension,
+ (PCOMMAND_LIST)Srb->SrbExtension,
+ 0, RH_COMMAND_IDENTIFY_CONTROLLER)) {
+ deviceExtension->NumberOfLogicalDrives = (ULONG)
+ ((PIDENTIFY_CONTROLLER)
+ deviceExtension->IdentifyBuffer)->NumberLogicalDrives;
+
+ DebugPrint((1,
+ "IdaStartIo: Number of logical drives %x\n",
+ deviceExtension->NumberOfLogicalDrives));
+
+ //
+ // save off the identify controller buffer to the
+ // extension area
+ //
+
+ ScsiPortMoveMemory(&deviceExtension->IdentifyData,
+ deviceExtension->IdentifyBuffer,
+ sizeof(IDENTIFY_CONTROLLER));
+
+ } else {
+ DebugPrint((1,
+ "IdaFindAdapters: Get controller information failed\n"));
+ status = SRB_STATUS_ERROR;
+ break;
+ }
+
+ //
+ // Check if this is for one of the reported logical drives.
+ //
+
+ if (Srb->TargetId >=
+ deviceExtension->NumberOfLogicalDrives) {
+ status = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+ }
+
+ //
+ // Issue identify command.
+ //
+
+ if (!GetDiskIdentifyData(Srb, HwDeviceExtension,
+ (PCOMMAND_LIST)Srb->SrbExtension,
+ Srb->TargetId,
+ RH_COMMAND_IDENTIFY_LOGICAL_DRIVES)) {
+ status = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+ }
+
+ //
+ // Get logical unit extension.
+ //
+
+ luExtension = ScsiPortGetLogicalUnit(deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ //
+ // Copy data from buffer to logical unit extension.
+ //
+
+ ScsiPortMoveMemory(&luExtension->IdentifyData,
+ deviceExtension->IdentifyBuffer,
+ sizeof(IDENTIFY_LOGICAL_DRIVE));
+ //
+ // Issue sense configuration command.
+ //
+
+ if (!GetDiskIdentifyData(Srb, HwDeviceExtension,
+ (PCOMMAND_LIST)Srb->SrbExtension,
+ Srb->TargetId,
+ RH_COMMAND_SENSE_CONFIGURATION)) {
+
+ status = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+ }
+
+ //
+ // Copy data from buffer to logical unit extension.
+ //
+
+ ScsiPortMoveMemory(&luExtension->SenseData,
+ deviceExtension->IdentifyBuffer,
+ sizeof(SENSE_CONFIGURATION));
+
+ //
+ // Zero INQUIRY data structure.
+ //
+
+ for (i = 0; i < Srb->DataTransferLength; i++) {
+ ((PUCHAR)Srb->DataBuffer)[i] = 0;
+ }
+
+ //
+ // Compaq IDA only supports disks.
+ //
+
+ ((PINQUIRYDATA)Srb->DataBuffer)->DeviceType = DIRECT_ACCESS_DEVICE;
+
+ //
+ // Fill in vendor identification fields.
+ //
+
+ ((PINQUIRYDATA)Srb->DataBuffer)->VendorId[0] = 'C';
+ ((PINQUIRYDATA)Srb->DataBuffer)->VendorId[1] = 'o';
+ ((PINQUIRYDATA)Srb->DataBuffer)->VendorId[2] = 'm';
+ ((PINQUIRYDATA)Srb->DataBuffer)->VendorId[3] = 'p';
+ ((PINQUIRYDATA)Srb->DataBuffer)->VendorId[4] = 'a';
+ ((PINQUIRYDATA)Srb->DataBuffer)->VendorId[5] = 'q';
+ ((PINQUIRYDATA)Srb->DataBuffer)->VendorId[6] = ' ';
+ ((PINQUIRYDATA)Srb->DataBuffer)->VendorId[7] = ' ';
+
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[0] = 'D';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[1] = 'i';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[2] = 's';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[3] = 'k';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[4] = ' ';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[5] = 'A';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[6] = 'r';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[7] = 'r';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[8] = 'a';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[9] = 'y';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[10] = ' ';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[11] = ' ';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[12] = ' ';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[13] = ' ';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[14] = ' ';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[15] = ' ';
+
+ //
+ // Move firmware revision from IDENTIFY data to
+ // product revision in INQUIRY data.
+ //
+
+ for (i = 0; i < 4; i++) {
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductRevisionLevel[i] =
+ deviceExtension->IdentifyData.FirmwareRevision[i];
+ }
+
+ status = SRB_STATUS_SUCCESS;
+ break;
+
+ case SCSIOP_VERIFY:
+
+ //
+ // Compaq array controllers hotfix bad sectors as they are
+ // encountered. A sector verify in unnecessary.
+ //
+
+ status = SRB_STATUS_SUCCESS;
+ break;
+
+ default:
+
+ status = SRB_STATUS_INVALID_REQUEST;
+ break;
+
+ } // end switch (Srb->Cdb[0])
+
+ break;
+
+ //
+ // Issue FLUSH/DISABLE if shutdown command.
+ //
+
+ case SRB_FUNCTION_SHUTDOWN:
+
+ BuildFlushDisable(deviceExtension,Srb);
+ SubmitCommandList(deviceExtension,
+ (PCOMMAND_LIST)Srb->SrbExtension);
+
+ status = SRB_STATUS_PENDING;
+
+ break;
+
+ //
+ // Do not need the flush command since all controllers have
+ // memory that is battery backed up. Just return success.
+ //
+
+ case SRB_FUNCTION_FLUSH:
+ status = SRB_STATUS_SUCCESS;
+ break;
+
+ case SRB_FUNCTION_IO_CONTROL: {
+ PCPQ_IDA_IDENTIFY pIoctlBuffer;
+
+ pIoctlBuffer = (PCPQ_IDA_IDENTIFY)Srb->DataBuffer;
+
+ //
+ // Status is returned mainly in 2 fields to the calling thread.
+ // These 2 fields determine if other status fields are valid to
+ // check. If the request is not a valid request for this driver
+ // then the Header.ReturnCode is not modified and the
+ // Srb->SrbStatus is set to SRB_STATUS_INVALID_REQUEST. If
+ // the request is valid for this driver then Srb->SrbStatus
+ // is always returned as SRB_STATUS_SUCCESS and the
+ // Header.ReturnCode contains information concerning the
+ // status of the particular request.
+ //
+
+ if (!IdaStrCmp(pIoctlBuffer->Header.Signature, IDA_SIGNATURE)) {
+
+ if (IdaProcessIoctl(deviceExtension,
+ pIoctlBuffer,
+ Srb) == CPQ_CIM_ISSUED) {
+
+ status = SRB_STATUS_PENDING;
+
+ } else {
+ status = SRB_STATUS_SUCCESS;
+ }
+
+ } else {
+ status = SRB_STATUS_INVALID_REQUEST;
+ }
+
+ 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);
+ }
+
+ //
+ // 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 IdaStartIo()
+
+ULONG
+IdaProcessIoctl(
+ IN PDEVICE_EXTENSION deviceExtension,
+ PVOID pIoctlBuffer,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+{
+ ULONG currentId;
+ ULONG numberOfLuns;
+ ULONG status;
+ PCPQ_IDA_IDENTIFY pCPQ = pIoctlBuffer;
+
+ //
+ // Build command list from SRB.
+ //
+
+ status = CPQ_CIM_COMPLETED;
+
+ DebugPrint((3,
+ "IdaProcessIoctl(): parsing request %d for PathId=%d TargetId=%d Lun=%d\n",
+ pCPQ->Header.ControlCode,Srb->PathId,Srb->TargetId,Srb->Lun));
+
+ switch(pCPQ->Header.ControlCode) {
+ case CPQ_IOCTL_IDENTIFY_DRIVER: {
+ PLOGICAL_UNIT_EXTENSION luExtension;
+
+ PMAP_HEADER header = (PMAP_HEADER)((PUCHAR)Srb->DataBuffer +
+ sizeof(SRB_IO_CONTROL));
+
+ IdaMoveMemory(header->DriverName, IDA_DRIVER_NAME,
+ sizeof(header->DriverName));
+
+ header->DriverMajorVersion = IDA_MAJOR_VERSION;
+ header->DriverMinorVersion = IDA_MINOR_VERSION;
+
+ header->ControllerCount = 1;
+
+ //
+ // We need to give back the number of LUNs not the actual
+ // number of LUNs available because LU extensions are not
+ // discarded when a drive has been removed or taken off-line.
+ //
+
+ currentId = 0;
+ numberOfLuns = 0;
+
+ luExtension = ScsiPortGetLogicalUnit(deviceExtension,
+ Srb->PathId,
+ (UCHAR)currentId,
+ Srb->Lun);
+ while (luExtension) {
+ numberOfLuns++;
+ currentId++;
+ luExtension = ScsiPortGetLogicalUnit(deviceExtension,
+ Srb->PathId,
+ (UCHAR)currentId,
+ Srb->Lun);
+ }
+
+ header->LogicalDiskCount = numberOfLuns;
+
+ header->RequiredMemory = sizeof(MAP_CONTROLLER_DATA) +
+ (sizeof(MAP_LOGICALDRIVE_DATA) * numberOfLuns);
+
+ status = CPQ_CIM_COMPLETED;
+ break;
+ }
+
+ case CPQ_IOCTL_IDENTIFY_CONTROLLERS: {
+ ULONG i;
+ PLOGICAL_UNIT_EXTENSION luExtension;
+ PMAP_LOGICALDRIVE_DATA LdriveData;
+ PMAP_CONTROLLER_DATA controllerData;
+
+ //
+ // Take care of the controller struct first
+ //
+
+ controllerData = (PMAP_CONTROLLER_DATA)
+ ((PUCHAR)Srb->DataBuffer + sizeof(SRB_IO_CONTROL));
+
+ controllerData->NextController = NULL;
+
+ //
+ // calculate offset from the beginning of the controller data area.
+ //
+
+ controllerData->LogicalDriveList =
+ (PMAP_LOGICALDRIVE_DATA)(controllerData + 1);
+ controllerData->EisaId = deviceExtension->EisaId;
+ controllerData->BmicIoAddress = (ULONG)deviceExtension->Bmic;
+ controllerData->IrqLevel = deviceExtension->IrqLevel;
+
+ IdaMoveMemory((PUCHAR)&controllerData->ControllerInfo,
+ (PUCHAR)&deviceExtension->IdentifyData,
+ sizeof(IDENTIFY_CONTROLLER));
+
+ //
+ // Now look for logical units until one is not found. In the future
+ // support non-consecutive logical units, for now, stop searching.
+ //
+
+ currentId = 0;
+ luExtension = ScsiPortGetLogicalUnit(deviceExtension,
+ Srb->PathId,
+ (UCHAR)currentId,
+ Srb->Lun);
+
+ LdriveData = controllerData->LogicalDriveList;
+
+ while (luExtension) {
+
+ //
+ // Set the DeviceLengthXX sizes to 0, removed from CIM interface.
+ //
+
+ LdriveData->NextLogicalDrive = LdriveData + 1;
+ LdriveData->Controller = controllerData;
+ LdriveData->LogicalDriveNumber = currentId;
+ LdriveData->SystemDriveNumber = 0;
+ LdriveData->DeviceLengthLo = 0;
+ LdriveData->DeviceLengthHi = 0;
+ LdriveData->SectorSize = (ULONG)(1 << deviceExtension->SectorShift);
+ IdaMoveMemory((PUCHAR)&LdriveData->Configuration,
+ (PUCHAR)&luExtension->SenseData,
+ sizeof(SENSE_CONFIGURATION));
+
+ IdaMoveMemory((PUCHAR)&LdriveData->LogicalDriveInfo,
+ (PUCHAR)&luExtension->IdentifyData,
+ sizeof(IDENTIFY_LOGICAL_DRIVE));
+
+ currentId++;
+ luExtension =
+ ScsiPortGetLogicalUnit(deviceExtension, Srb->PathId,
+ (UCHAR)currentId, Srb->Lun);
+
+ if (!luExtension) {
+ break;
+ }
+
+ LdriveData = LdriveData + 1;
+ }
+
+ LdriveData->NextLogicalDrive = NULL;
+
+ //
+ // Need to convert NextLogicalDrive fields to offsets from virtual
+ // addresses. currentId is the last ID that was found.
+ //
+
+ if (currentId) {
+ controllerData->LogicalDriveList =
+ (PMAP_LOGICALDRIVE_DATA)sizeof(MAP_CONTROLLER_DATA);
+ LdriveData = (PMAP_LOGICALDRIVE_DATA)(controllerData + 1);
+ LdriveData->NextLogicalDrive = NULL;
+
+ for (i=0;i<(currentId-1);i++,LdriveData++) {
+ LdriveData->NextLogicalDrive =
+ (PMAP_LOGICALDRIVE_DATA)(sizeof(MAP_CONTROLLER_DATA)
+ + ((i+1)*sizeof(MAP_LOGICALDRIVE_DATA)));
+ }
+
+ } else {
+ controllerData->LogicalDriveList = NULL;
+ }
+
+ status = CPQ_CIM_COMPLETED;
+ break;
+ }
+
+ case CPQ_IOCTL_PASSTHROUGH:
+ case CPQ_IOCTL_SCSIPASSTHROUGH: {
+
+ if (!(BuildCIMList(deviceExtension, Srb) == CPQ_CIM_CMDBUILT)) {
+ status = CPQ_CIM_COMPLETED;
+ } else {
+
+ //
+ // Submit command list to controller.
+ //
+
+ DebugPrint((3,
+ "IdaProcessIoctl(): Submitting PASSTHRU request to %x\n",
+ deviceExtension));
+
+ SubmitCommandList(deviceExtension,
+ (PCOMMAND_LIST)Srb->SrbExtension);
+ status = CPQ_CIM_ISSUED;
+ }
+ break;
+ }
+
+ case CPQ_IOCTL_CONFIGURATION_INFO: {
+ PIDA_CONFIGURATION pConfigData;
+
+ //
+ // Setup pointer to the Config Data area
+ //
+
+ pConfigData = (PIDA_CONFIGURATION)
+ ((PUCHAR)Srb->DataBuffer + sizeof(SRB_IO_CONTROL));
+
+ pConfigData->ulBaseMemoryAddress =
+ deviceExtension->HBAConfiguration.ulBaseIOAddress;
+ pConfigData->bIoBusType =
+ deviceExtension->HBAConfiguration.bHBAIoBusType;
+ pConfigData->ulBaseIOAddress = deviceExtension->BaseIOAddress;
+ pConfigData->ulControllerID = deviceExtension->EisaId;
+ IdaMoveMemory((PUCHAR)&pConfigData->IoBusData,
+ (PUCHAR)&deviceExtension->HBAConfiguration.HBAIoBusData,
+ sizeof(union _IO_BUS_DATA));
+ status = CPQ_CIM_COMPLETED;
+ break;
+ }
+
+ default:
+ pCPQ->Header.ReturnCode = CPQ_SCSI_ERR_BAD_CNTL_CODE;
+ status = CPQ_CIM_COMPLETED;
+ break;
+ }
+
+ return(status);
+}
+
+
+VOID
+BuildFlushDisable(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine builds a shutdown command list suitable for submission to the
+ Compaq IDA controller, from an SRB.
+
+Arguments:
+
+ DeviceExtension - Address of adapter storage area.
+ Srb - System request.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCOMMAND_LIST commandList = Srb->SrbExtension;
+ ULONG length,i;
+ PFLUSH_DISABLE pFlushDisable;
+ PSG_DESCRIPTOR sgList;
+
+ sgList = commandList->SgDescriptor;
+
+ // clear out reserved area
+
+ for (i=0;i<MAXIMUM_SG_DESCRIPTORS;i++) {
+ sgList[i].Address = 0;
+ sgList[i].Length = 0;
+ }
+
+ //
+ // Save SRB address for interrupt routine.
+ //
+
+ commandList->SrbAddress = Srb;
+
+ //
+ // Set up Command List Header.
+ //
+
+ commandList->CommandListHeader.LogicalDriveNumber = 0;
+
+ commandList->CommandListHeader.RequestPriority = CL_NORMAL_PRIORITY;
+
+ commandList->CommandListHeader.Flags =
+ CL_FLAGS_NOTIFY_LIST_COMPLETE + CL_FLAGS_NOTIFY_LIST_ERROR;
+
+ //
+ // Set up Request Header.
+ //
+ // Terminate request list.
+ //
+
+ commandList->RequestHeader.NextRequestOffset = 0;
+
+ commandList->Flags = 0;
+
+ //
+ // Reset error code.
+ //
+
+ commandList->RequestHeader.ErrorCode = 0;
+
+ //
+ // Clear reserved field.
+ //
+
+ commandList->RequestHeader.Reserved = 0;
+
+ //
+ // Check for special Compaq passthrough command.
+ //
+
+ commandList->RequestHeader.BlockCount = (USHORT)1;
+ commandList->RequestHeader.BlockNumber = (ULONG)0;
+ commandList->RequestHeader.CommandByte = RH_COMMAND_FLUSH_DISABLE_CACHE;
+
+ pFlushDisable = (PFLUSH_DISABLE)&(sgList[1].Length);
+ pFlushDisable->disable_flag = 1; //disable cache also
+
+ sgList[0].Address =
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ NULL,
+ commandList,
+ &length).LowPart;
+
+ //
+ // ScsiPortGetPhysicalAddress only accepts certain virtual addresses,
+ // so use the commandList and then increment over to the second s/g
+ // descriptor where the structure for the flush/disable command is
+ // located.
+ //
+ // Note that since it is difficult to allocate nonpaged memory at this
+ // level of the driver, and the command has 510 bytes of reserved
+ // area in the structure then memory will be retrieved by the controller
+ // that is past the end of the defined commandlist allocated memory.
+ // This will not be a problem unless the memory extends beyond the
+ // actual physical end of memory in the machine.
+ //
+ // The IDA-2 controller requires a multiple of 512 for the length so
+ // to avoid code that is controller dependent just use 512 that is
+ // accepted by all controllers. This command returns an BAD REQUEST
+ // when issued to IDA controllers since those controllers have no
+ // memory on the board.
+ //
+
+ sgList[0].Address += (sizeof(COMMAND_LIST_HEADER) +
+ sizeof(REQUEST_HEADER) +
+ sizeof(SG_DESCRIPTOR));
+
+ sgList[0].Length = 512;
+ commandList->RequestHeader.BlockNumber = 0;
+ commandList->RequestHeader.ScatterGatherCount=1;
+
+ //
+ // Build physical address translation list entry.
+ //
+
+ commandList->CommandListSize = (sizeof(COMMAND_LIST_HEADER) +
+ sizeof(REQUEST_HEADER) +
+ sizeof(SG_DESCRIPTOR));
+}
+
+
+ULONG
+IdaFindAdapter(
+ 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;
+ DebugPrint((9,"&deviceExtension=%x\n",&deviceExtension));
+ DebugPrint((9,"&deviceExtension->PCIoff=%x\n",&deviceExtension->PCIoff));
+
+ //
+ // 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);
+
+ //
+ // Complete description of controller.
+ //
+
+ ConfigInfo->MaximumTransferLength = (ULONG)-1;
+ ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SG_DESCRIPTORS;
+ ConfigInfo->NumberOfBuses = 1;
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+ ConfigInfo->Dma32BitAddresses = TRUE;
+
+ //
+ // Get noncached extension for identify requests.
+ //
+
+ deviceExtension->EisaId =
+ ScsiPortReadPortUlong(&deviceExtension->Bmic->BoardId);
+
+ if ((deviceExtension->EisaId & IDA_EISA_ID_MASKID_LOW) >=
+ (IDA_EISA_ID_DAZZLER & IDA_EISA_ID_MASKID_LOW)) {
+
+ deviceExtension->HBAConfiguration.bHBAModel = IDA_EISA_DAZZLER;
+
+ deviceExtension->eisapci =
+ (PEISAPCI_CONTROLLER)(((ULONG)deviceExtension->Bmic & 0xf000));
+
+ DebugPrint((9,"Found EISA DAZZLER: deviceExtension->eisapci=%x\n",
+ deviceExtension->eisapci));
+
+ ConfigInfo->MaximumNumberOfTargets = 32;
+ } else {
+ deviceExtension->HBAConfiguration.bHBAModel = IDA_BASE_CONTROLLER;
+ }
+
+ //
+ // Setup some vars needed for the IDENTIFY commands
+ //
+
+ deviceExtension->IrqLevel = (UCHAR)ConfigInfo->BusInterruptLevel;
+ deviceExtension->SectorShift = 9;
+
+ deviceExtension->IdentifyBuffer =
+ ScsiPortGetUncachedExtension(deviceExtension,
+ ConfigInfo,
+ 512);
+ ConfigInfo->CachesData = TRUE;
+
+ deviceExtension->HBAConfiguration.HBAIoBusData.usEisaSlot =
+ (USHORT)ConfigInfo->SlotNumber;
+
+ deviceExtension->BaseIOAddress = ConfigInfo->SlotNumber * 0x1000;
+ deviceExtension->HBAConfiguration.bHBAIoBusType = EISA_BUS;
+
+ //
+ // Tell system to look for more adapters.
+ //
+
+ *Again = TRUE;
+
+ return SP_RETURN_FOUND;
+
+} // end IdaFindAdapter()
+
+
+ULONG
+BuildCIMList(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine builds a command list suitable for submission to the
+ Compaq IDA controller, from an SRB.
+
+Arguments:
+
+ DeviceExtension - Address of adapter storage area.
+ Srb - System request.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCOMMAND_LIST commandList = Srb->SrbExtension;
+ PUCHAR dataPointer;
+ ULONG physicalAddress;
+ ULONG bytesLeft;
+ ULONG descriptor;
+ ULONG length;
+ ULONG bufferOffset;
+ ULONG status;
+ PSRB_IO_CONTROL pSrb;
+ PSCSI_PASSTHRU scsipass;
+
+ //
+ // Save SRB address for interrupt routine.
+ //
+
+ commandList->SrbAddress = Srb;
+
+ //
+ // Set up Command List Header.
+ //
+
+ commandList->CommandListHeader.LogicalDriveNumber = Srb->TargetId;
+ commandList->CommandListHeader.RequestPriority = CL_NORMAL_PRIORITY;
+
+ commandList->CommandListHeader.Flags =
+ CL_FLAGS_NOTIFY_LIST_COMPLETE + CL_FLAGS_NOTIFY_LIST_ERROR;
+
+ commandList->RequestHeader.NextRequestOffset = 0;
+ commandList->Flags = 0;
+ commandList->RequestHeader.ErrorCode = 0;
+ commandList->RequestHeader.Reserved = 0;
+ commandList->RequestHeader.BlockCount = 0;
+ commandList->RequestHeader.BlockNumber = 0;
+
+ status = CPQ_CIM_ERROR;
+ pSrb = (PSRB_IO_CONTROL)Srb->DataBuffer;
+
+ switch (pSrb->ControlCode) {
+ case CPQ_IOCTL_PASSTHROUGH:
+ {
+ PMAP_PARAMETER_PACKET pParmPkt = (PMAP_PARAMETER_PACKET)
+ (((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
+
+ commandList->CommandListHeader.LogicalDriveNumber = pParmPkt->TargetId;
+ commandList->RequestHeader.BlockCount = pParmPkt->BlockCount;
+ commandList->RequestHeader.BlockNumber = pParmPkt->BlockNumber;
+ commandList->RequestHeader.CommandByte = pParmPkt->IdaLogicalCommand;
+
+ //
+ // Build scatter/gather descriptor list.
+ //
+
+ descriptor = 0;
+ bufferOffset = sizeof(SRB_IO_CONTROL) + sizeof(MAP_PARAMETER_PACKET);
+ dataPointer = (PUCHAR)Srb->DataBuffer + bufferOffset;
+ bytesLeft = Srb->DataTransferLength - bufferOffset -
+ sizeof(IDA_ERROR_BITS);
+
+ do {
+
+ //
+ // Get physical address and length of contiguous
+ // physical buffer.
+ //
+
+ physicalAddress =
+ 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;
+ }
+
+ //
+ // Fill in descriptor.
+ //
+
+ commandList->SgDescriptor[descriptor].Address = physicalAddress;
+ commandList->SgDescriptor[descriptor].Length = length;
+
+ //
+ // Adjust counts.
+ //
+
+ dataPointer = dataPointer + length;
+ bytesLeft -= length;
+ descriptor++;
+
+ } while (bytesLeft);
+
+ //
+ // Calculate size of command list.
+ //
+
+ commandList->RequestHeader.ScatterGatherCount=(UCHAR)descriptor;
+ commandList->CommandListSize = (sizeof(COMMAND_LIST_HEADER) +
+ sizeof(REQUEST_HEADER) +
+ sizeof(SG_DESCRIPTOR) *
+ descriptor);
+
+ status = CPQ_CIM_CMDBUILT;
+ break;
+ }
+
+ case CPQ_IOCTL_SCSIPASSTHROUGH:
+
+ //
+ // Build scatter/gather descriptor list.
+ //
+
+ descriptor = 0;
+
+ bufferOffset = (sizeof(SRB_IO_CONTROL) +
+ sizeof(SCSI_PASSTHRU) +
+ sizeof(SCSI_BUFFER_HEADER));
+
+ dataPointer = (PUCHAR)Srb->DataBuffer + bufferOffset;
+ bytesLeft = Srb->DataTransferLength - bufferOffset;
+
+ //
+ // Get physical address and length of contiguous
+ // physical buffer.
+ //
+
+ physicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ dataPointer,
+ &length)
+ );
+ //
+ // get to the scsi cdb area, and then copy to the end of the cmdlist
+ // which is after the first s/g descriptor.
+ // modify to move after the last USED s/g area when more than 1 s/g
+ // functions in the controller f/w.
+ //
+
+ scsipass = (PSCSI_PASSTHRU)(((PUCHAR)Srb->DataBuffer +
+ sizeof(SRB_IO_CONTROL)));
+ IdaMoveMemory((PUCHAR)&commandList->SgDescriptor[1].Length,
+ (PUCHAR)scsipass,
+ sizeof(SCSI_PASSTHRU_HEADER) +
+ scsipass->scsi_header.cdb_length
+ );
+
+ bufferOffset = (sizeof(SG_DESCRIPTOR) +
+ sizeof(COMMAND_LIST_HEADER) +
+ sizeof(REQUEST_HEADER) +
+ sizeof(SCSI_PASSTHRU_HEADER) +
+ scsipass->scsi_header.cdb_length);
+
+ //
+ // If length of physical memory is less than needed space
+ // attempt to use nonpaged memory left in the command list
+ // else return error since allocating memory is not possible
+ // under the miniport design.
+ //
+
+ if (length < bytesLeft) {
+
+ if (( (MAXIMUM_SG_DESCRIPTORS * sizeof(SG_DESCRIPTOR)) -
+ sizeof(SG_DESCRIPTOR) -
+ sizeof(SCSI_PASSTHRU)) < bytesLeft) {
+
+ DebugPrint((3,
+ "BuildCIMList(): Returning CPQ_SCSI_ERR_NONCONTIGUOUS\n"));
+
+ pSrb->ReturnCode = CPQ_SCSI_ERR_NONCONTIGUOUS;
+ return(CPQ_CIM_NONCONTIGUOUS);
+ }
+
+ //
+ // Get the physical address of the start of the command list and then
+ // increment to the first non-used byte in the s/g descriptor list.
+ // There are limitations on what physical addresses can be obtained
+ // from the ScsiPort calls so use what we know is nonpaged memory.
+ //
+
+ physicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ commandList,
+ &length)
+ );
+
+ physicalAddress += bufferOffset;
+
+ //
+ // set BlockNumber to flag that a copy from end of commandList is needed
+ // when the request is completed.
+ //
+
+ commandList->RequestHeader.BlockNumber = 1;
+ }
+
+ commandList->RequestHeader.CommandByte = RH_COMMAND_SCSI_PASS_THRU;
+ commandList->CommandListSize = (USHORT)bufferOffset;
+ commandList->SgDescriptor[descriptor].Address = physicalAddress;
+ commandList->SgDescriptor[descriptor].Length = bytesLeft;
+ commandList->RequestHeader.ScatterGatherCount = 1;
+ commandList->CommandListHeader.LogicalDriveNumber = 0;
+
+ status = CPQ_CIM_CMDBUILT;
+ break;
+
+ default:
+
+ DebugPrint((1,
+ "BuildCIMList(): Returning CPQ_SCSI_ERR_BAD_CNTL_CODE\n"));
+ pSrb->ReturnCode = CPQ_SCSI_ERR_BAD_CNTL_CODE;
+ status = CPQ_CIM_ERROR;
+ break;
+ }
+
+ return(status);
+
+} // end BuildCIMList()
+
+VOID
+IdaMoveMemory(
+ OUT PUCHAR pDestination,
+ IN PUCHAR pSource,
+ IN ULONG ulLength
+ )
+
+{
+ while (ulLength--)
+ *pDestination++ = *pSource++;
+ return;
+}
+
+BOOLEAN
+IdaStrCmp(
+ IN PUCHAR p1,
+ IN PUCHAR p2
+ )
+{
+ ULONG count=0;
+ ULONG p1count=0;
+ ULONG p2count=0;
+
+ //
+ // Get count of number of bytes in first
+ // Get count for second
+ // Perform while loop until out of greater number of bytes.
+ //
+
+ while ((p1[count] < 0x7f) && (p1[count] > 0x1f))
+ count++;
+
+ p1count = count;
+
+ while ((p2[count] < 0x7f) && (p2[count] > 0x1f))
+ count++;
+
+ p2count = count;
+
+ if (p1count != p2count)
+ return(TRUE);
+
+ count = p2count;
+
+ while (count) {
+ if (p1[count-1] != p2[count-1])
+ return(TRUE);
+ count--;
+ }
+
+ return(FALSE);
+
+}
+
+
+// Device extension global variable. This variable is needed for the
+// pci_bios function since there is no way to pass in this value. The
+// ScsiPortGetBusData and ScsiPortSetBusDataByOffset require a pointer
+// to the device extension as an argument to the function.
+
+STATIC PVOID gpDeviceExtension = NULL;
+
+//
+// Internal module function prototypes
+//
+
+STATIC
+ULONG
+GetPciSpecifics(
+ IN OUT PVOID pDeviceExtension,
+ IN OUT PIDA_CONTEXT pIDAContext,
+ IN OUT PPORT_CONFIGURATION_INFORMATION pConfigInfo,
+ IN PPCI_SLOT_NUMBER pPciSlotNumber
+ );
+
+STATIC
+ULONG
+GetPciResources(
+ IN PVOID pDeviceExtension,
+ IN PPCI_COMMON_CONFIG pPciConfigHeader,
+ IN ULONG ulPciSlotNumber,
+ IN OUT PPORT_CONFIGURATION_INFORMATION pConfigInfo
+ );
+
+
+
+ULONG
+IDAFindPci(
+ IN OUT PVOID pDeviceExtension,
+ IN OUT PVOID pContext,
+ IN PVOID pBusInformation,
+ IN PCHAR pArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION pConfigInfo,
+ OUT PBOOLEAN pAgain
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the SCSI port driver to find SMART-2/P
+ controllers on the system's PCI buses. This routine searches only
+ the input PCI bus number in the port configuration information. If
+ a controller is found, the function fills out the controller's resource
+ requirements in the port configuration information and begins the
+ initialization process for the controller.
+
+
+Arguments:
+
+ pDeviceExtension - pointer to the miniport driver's per-controller
+ storage area
+ pContext - pointer to the context value passed to ScsiPortInitialize()
+ pBusInformation - pointer to bus type specific information
+ pArgumentString - pointer to null-terminated ASCII string
+ pConfigInfo - pointer to SCSI port configuration information
+
+
+Return Values:
+
+ pDeviceExtension - Minport driver's per-controller storage area
+ pContext - Context value passed to ScsiPortInitialize()
+ pConfigInfo - pointer to SCSI port configuration information
+ pAgain - Indicates to call function again to find more controllers.
+
+
+ Function Return Values:
+
+ SP_RETURN_FOUND - Indicates a host adapter was found and the configuration
+ information was successfully determined.
+
+ SP_RETURN_ERROR - Indicates a host adapter was found but an error occurred
+ obtaining the configuration information.
+
+ SP_RETURN_NOT_FOUND - Indicates no host adapter was found for the supplied
+ configuration information.
+
+ SP_RETURN_BAD_CONFIG - Indicates the supplied configuration information
+ was invalid.
+
+-- */
+
+{
+ BYTE bDeviceNumber;
+ BYTE bFunctionNumber;
+ BYTE bStartDeviceNumber;
+ BYTE bStartFunctionNumber;
+ PCI_SLOT_NUMBER PciSlotNumber;
+ PIDA_CONTEXT pIDAContext = pContext;
+ PCI_COMMON_CONFIG PciConfigHeader;
+ ULONG ulBytes;
+ ULONG ulInitStatus;
+ ULONG ulTmp1;
+ ULONG ulTmp2;
+
+
+ UNREFERENCED_PARAMETER(pBusInformation);
+ UNREFERENCED_PARAMETER(pArgumentString);
+
+
+ DebugPrint((4, "\nDAZZLER: Enter function IDAFindPci.\n"));
+
+ //
+ // Set the input pAgain argument to TRUE. This ensures that the function
+ // will be called for every PCI bus in the system.
+ //
+
+ *pAgain = TRUE;
+
+ // Clear the slot number.
+
+ PciSlotNumber.u.AsULONG = 0;
+
+
+ // Set the initial search starting numbers.
+
+ bStartDeviceNumber = pIDAContext->PciAddress.bDeviceNumber;
+ bStartFunctionNumber = pIDAContext->PciAddress.bFunctionNumber;
+
+ DebugPrint((4, "DAZZLER: Beginning search on system PCI bus %u.\n",
+ pConfigInfo->SystemIoBusNumber));
+
+
+ // Look at each device.
+
+ for (bDeviceNumber = bStartDeviceNumber;
+ bDeviceNumber < PCI_MAX_DEVICES;
+ bDeviceNumber++ ) {
+
+ // Set the device number in the PCI slot number.
+
+ PciSlotNumber.u.bits.DeviceNumber = bDeviceNumber;
+
+ // Look at each function of the device.
+
+ for (bFunctionNumber = bStartFunctionNumber;
+ bFunctionNumber < PCI_MAX_FUNCTION;
+ bFunctionNumber++) {
+ // Set the function number in the PCI slot number.
+
+ PciSlotNumber.u.bits.FunctionNumber = bFunctionNumber;
+
+ // Get the PCI configuration data for the slot.
+
+ DebugPrint( (4, "DAZZLER: Searching device %#x, function %x.\n",
+ bDeviceNumber, bFunctionNumber) );
+
+ ulBytes = ScsiPortGetBusData(pDeviceExtension,
+ PCIConfiguration,
+ pConfigInfo->SystemIoBusNumber,
+ PciSlotNumber.u.AsULONG,
+ &PciConfigHeader,
+ PCI_COMMON_HDR_LENGTH);
+
+ if (ulBytes == 0) {
+ // Out of PCI data for this bus.
+
+ DebugPrint((4, "DAZZLER: No more PCI devices on bus!\n"));
+
+ pIDAContext->PciAddress.bDeviceNumber = 0;
+ pIDAContext->PciAddress.bFunctionNumber = 0;
+
+ return (SP_RETURN_NOT_FOUND);
+ }
+
+ // Check for a valid vendor ID.
+
+#ifdef DBG
+ if (PciConfigHeader.VendorID != PCI_INVALID_VENDORID) {
+
+ // print out the PciConfigHeader
+
+ DebugPrint((4,
+ "PciConfigHeader: VendorId=%x DeviceId=%x Command=%x Status=%x\n"
+ ,PciConfigHeader.VendorID,
+ PciConfigHeader.DeviceID,
+ PciConfigHeader.Command) );
+
+ DebugPrint((4,
+ "RevisionID=%x ProgIf=%x SubClass=%x BaseClass=%x CacheLineSize=%x\n",
+ PciConfigHeader.RevisionID,
+ PciConfigHeader.ProgIf,
+ PciConfigHeader.SubClass,
+ PciConfigHeader.BaseClass,
+ PciConfigHeader.CacheLineSize) );
+
+ DebugPrint((4,"LatencyTimer=%x HeaderType=%x BIST=%x\n",
+ PciConfigHeader.LatencyTimer,
+ PciConfigHeader.HeaderType,
+ PciConfigHeader.BIST) );
+ }
+#endif
+
+ if (PciConfigHeader.VendorID == PCI_INVALID_VENDORID) {
+ // No PCI device or no more functions on the current device.
+ // Go to the next device.
+
+ break;
+ }
+
+
+ // PCI controller found. Next check to see if it is one of the
+ // controllers being searched for.
+
+ if ((PciConfigHeader.VendorID ==
+ pIDAContext->PciIdentifier.usVendorID) &&
+ (PciConfigHeader.DeviceID ==
+ pIDAContext->PciIdentifier.usDeviceID)) {
+ DebugPrint( (4, "DAZZLER: Found PCI controller.\n") );
+
+ // Check if the controller is enabled.
+
+ if ((PciConfigHeader.Command & PCI_ENABLE_IO_SPACE) &&
+ (PciConfigHeader.Command & PCI_ENABLE_MEMORY_SPACE)) {
+ DebugPrint( (4, "DAZZLER: Controller is enabled.\n") );
+
+ //
+ // Get PCI Id placed in offset 0x2c and place into the
+ // device extension EisaId.
+ //
+
+// ulTmp1 = ulTmp2 = PciConfigHeader.u.type0.Reserved1[1];
+ ulTmp1 = ulTmp2 = ((((ULONG) PciConfigHeader.u.type0.SubSystemID) << 16) |
+ PciConfigHeader.u.type0.SubVendorID);
+
+ // Fix it because the bytes are swapped
+
+ ulTmp1 &= 0xff00ff00;
+ ulTmp2 &= 0x00ff00ff;
+
+ ulTmp1 = ulTmp1 >> 8;
+ ulTmp2 = ulTmp2 << 8;
+
+ ((PDEVICE_EXTENSION)pDeviceExtension)->EisaId = ulTmp1 | ulTmp2;
+
+ // Set starting address for the next search.
+
+ pIDAContext->PciAddress.bDeviceNumber = bDeviceNumber;
+ pIDAContext->PciAddress.bFunctionNumber = bFunctionNumber + 1;
+
+
+ // Get the PCI resource requirements for the controller.
+
+ ulInitStatus = GetPciResources(pDeviceExtension,
+ &PciConfigHeader,
+ PciSlotNumber.u.AsULONG,
+ pConfigInfo);
+
+ if (ulInitStatus != SP_RETURN_FOUND) {
+
+ DebugPrint((0,
+ "DAZZLER: Could not get PCI resources for controller!\n"));
+
+ return (ulInitStatus);
+ }
+
+ // Get the PCI specifics for the controller.
+
+ ulInitStatus = GetPciSpecifics(pDeviceExtension,
+ pIDAContext,
+ pConfigInfo,
+ &PciSlotNumber);
+
+ if (ulInitStatus != SP_RETURN_FOUND) {
+ DebugPrint((0, "DAZZLER: Could not get PCI specifics for controller!\n") );
+ }
+
+ return (ulInitStatus);
+
+ } else {
+ DebugPrint( (4, "DAZZLER: Controller is disabled.\n") );
+ continue;
+ }
+
+ } // end if ((PciConfigHeader.VendorID == ...) &&
+
+
+ } // end for (bFunctionNumber = bStartFunctionNumber; ...)
+
+
+ // Reset the initial starting function number.
+
+ bStartFunctionNumber = 0;
+
+ } // end for (bDeviceNumber = bStartDeviceNumber; ...)
+
+
+ // A controller was not found.
+
+ DebugPrint( (4,
+ "DAZZLER: Failed to find any PCI controllers this pass.\n") );
+
+ pIDAContext->PciAddress.bDeviceNumber = 0;
+ pIDAContext->PciAddress.bFunctionNumber = 0;
+
+ return (SP_RETURN_NOT_FOUND);
+
+} // end IDAFindPci()
+
+
+
+STATIC
+ULONG
+GetPciResources(
+ IN PVOID pDeviceExtension,
+ IN PPCI_COMMON_CONFIG pPciConfigHeader,
+ IN ULONG ulPciSlotNumber,
+ IN OUT PPORT_CONFIGURATION_INFORMATION pConfigInfo
+ )
+
+
+/*++
+
+Routine Description:
+
+ This routine gets the resources required by the input PCI controller.
+
+
+Arguments:
+
+ pDeviceExtension - pointer to the miniport driver's per-controller
+ storage area
+ pPciConfigHeader - pointer to the controller's PCI configuration header
+ ulPciSlotNumber - the PCI controller's address represented as a ULONG
+ pConfigInfo - pointer to SCSI port configuration information
+
+
+Return Values:
+
+ pConfigInfo - pointer to SCSI port configuration information. The access
+ range elements of the structure are filled in with the resources
+ required by the controller.
+
+ Function Return Values:
+
+ SP_RETURN_FOUND - Used to indicate that the HBA was successfully
+ initialized.
+
+ SP_RETURN_ERROR - Used to indicate that the HBA could not be properly
+ initilaized.
+
+-- */
+
+{
+ PACCESS_RANGE pAccessRange;
+ PCI_COMMON_CONFIG PciTmpCfgHdr;
+ ULONG ulAddressSpaceMask = 0xFFFFFFFF;
+ ULONG ulAddressSpace, ulAddressLength, ulBytes;
+ USHORT i;
+
+
+ DebugPrint( (2, "\nDAZZLER: Enter function GetPciResources.\n") );
+
+
+ // Verify the number of available access ranges.
+
+ if (pConfigInfo->NumberOfAccessRanges > IDA_PCI_NUM_ACCESS_RANGES) {
+
+ DebugPrint((0,
+ "DAZZLER: # of access ranges invalid for PCI controller.\n"));
+
+ return (SP_RETURN_ERROR);
+ }
+
+
+ // Get the resources required for each PCI base address.
+
+ for (i = 0; i < IDA_PCI_NUM_ACCESS_RANGES; i++) {
+ // Get pointer to the access range element to fill out.
+
+ pAccessRange = &((*(pConfigInfo->AccessRanges))[i]);
+
+
+ // Check to see if the PCI base address is memory or I/O.
+
+ if (pPciConfigHeader->u.type0.BaseAddresses[i] & PCI_ADDRESS_IO_SPACE) {
+
+ // Address is an I/O address.
+
+ pAccessRange->RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(pPciConfigHeader->
+ u.type0.BaseAddresses[i] &
+ ~PCI_ADDRESS_IO_SPACE);
+
+ pAccessRange->RangeInMemory = FALSE;
+ } else {
+ // Address is a memory address.
+
+ ASSERT((pPciConfigHeader->u.type0.BaseAddresses[i] &
+ PCI_ADDRESS_MEMORY_TYPE_MASK) & PCI_TYPE_32BIT);
+
+ pAccessRange->RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(pPciConfigHeader->
+ u.type0.BaseAddresses[i] &
+ 0xfffffff0);
+
+ pAccessRange->RangeInMemory = TRUE;
+
+ DebugPrint((4, "pAccessRange->RangeStart.Hi/Low=%x %x ->RangeLength=%x\n",
+ pAccessRange->RangeStart.HighPart,pAccessRange->
+ RangeStart.LowPart,
+ pAccessRange->RangeLength));
+ }
+
+
+ // Get the amount of address space required. This is done by writing all
+ // 1's to the register and then reading the value back. The device will
+ // return 0's in all don't care bits. The first signficant bit set beyond
+ // those used to indicate memory or I/O determines the address space
+ // required. Finally, the register is restored with the original address.
+
+ ulBytes = ScsiPortSetBusDataByOffset(pDeviceExtension, PCIConfiguration,
+ pConfigInfo->SystemIoBusNumber,
+ ulPciSlotNumber,
+ (PVOID) &ulAddressSpaceMask,
+ FIELD_OFFSET(PCI_COMMON_CONFIG,
+ u.type0.BaseAddresses[i]),
+ sizeof(ULONG)
+ );
+
+ if (ulBytes == 0) {
+ DebugPrint((0,
+ "DAZZLER: Could not set PCI slot information for slot %u.\n",
+ ulPciSlotNumber));
+
+ return (SP_RETURN_ERROR);
+ }
+
+
+ // Read the value back.
+
+ ulBytes = ScsiPortGetBusData( pDeviceExtension,
+ PCIConfiguration,
+ pConfigInfo->SystemIoBusNumber,
+ ulPciSlotNumber,
+ &PciTmpCfgHdr,
+ PCI_COMMON_HDR_LENGTH );
+
+ if (ulBytes == 0) {
+
+ DebugPrint((0,
+ "DAZZLER: Could not get PCI information for slot %u.\n",
+ ulPciSlotNumber)
+ );
+
+ return(SP_RETURN_ERROR);
+ }
+
+
+ // Determine the space required by finding the first bit set.
+
+ ulAddressSpace = PciTmpCfgHdr.u.type0.BaseAddresses[i];
+ ulAddressLength = 1 << ((ulAddressSpace & PCI_ADDRESS_IO_SPACE) ? 2 : 4);
+
+ while (!(ulAddressSpace & ulAddressLength) && ulAddressLength) {
+ ulAddressLength <<= 1;
+ }
+
+ // Set the access range length.
+
+ pAccessRange->RangeLength = ulAddressLength;
+
+ DebugPrint((4,
+ "pAccessRange->RangeStart.Hi/Low=%x %x ->RangeLength=%x\n",
+ pAccessRange->RangeStart.HighPart,pAccessRange->
+ RangeStart.LowPart,
+ pAccessRange->RangeLength)
+ );
+
+ // Reset the base address register to its original value.
+
+ ulBytes = ScsiPortSetBusDataByOffset(pDeviceExtension,
+ PCIConfiguration,
+ pConfigInfo->SystemIoBusNumber,
+ ulPciSlotNumber,
+ (PVOID) &pPciConfigHeader->
+ u.type0.BaseAddresses[i],
+ FIELD_OFFSET(PCI_COMMON_CONFIG,
+ u.type0.BaseAddresses[i]),
+ sizeof(ULONG)
+ );
+
+ if (ulBytes == 0) {
+
+ DebugPrint((0, "DAZZLER: Could not set PCI information for slot %u.\n",
+ ulPciSlotNumber));
+
+ return(SP_RETURN_ERROR);
+ }
+
+ } // end for (i = 0;...)
+
+
+ // Set the IRQ information in the port configuration data structure.
+
+ pConfigInfo->BusInterruptLevel = pPciConfigHeader->u.type0.InterruptLine;
+ pConfigInfo->InterruptMode = LevelSensitive;
+
+ // Return success.
+
+ return(SP_RETURN_FOUND);
+
+} // end GetPciResources
+
+
+
+
+STATIC
+ULONG
+GetPciSpecifics(
+ IN OUT PVOID pDeviceExtension,
+ IN OUT PIDA_CONTEXT pIDAContext,
+ IN OUT PPORT_CONFIGURATION_INFORMATION pConfigInfo,
+ IN PPCI_SLOT_NUMBER pPciSlotNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to complete initialization of the port configuration
+ information for the input controller. This function also begins the
+ configuration of the SMGR for the controller. Finally, the function makes
+ the call to initialize the controller.
+
+
+Arguments:
+
+ pDeviceExtension - Miniport driver's per-controller storage area
+ pIDAContext - Context value passed to ScsiPortInitialize()
+ pConfigInfo - pointer to SCSI port configuration information
+
+
+Return Values:
+
+ pDeviceExtension - Minport driver's per-controller storage area
+ pIDAContext - Context value passed to ScsiPortInitialize()
+ pConfigInfo - pointer to SCSI port configuration information
+
+
+ Function Return Values:
+
+ SP_RETURN_FOUND - Used to indicate that the HBA was successfully
+ initialized.
+
+ SP_RETURN_ERROR - Used to indicate that the HBA could not be properly
+ initilaized.
+
+-- */
+
+{
+ PACCESS_RANGE pAccessRange;
+ PDEVICE_EXTENSION pIDADeviceExtension = pDeviceExtension;
+ PVOID pBaseAddress, pIoAddress = NULL, pMemoryAddress = NULL;
+ ULONG ulInitStatus, ulPhysicalMemoryAddress;
+ USHORT i;
+
+
+ DebugPrint( (6, "Enter function GetPciSpecifics.\n") );
+
+
+ // Get and verify the access ranges and its length.
+
+ for (i = 0; i < IDA_PCI_NUM_ACCESS_RANGES - 1; i++) {
+ pAccessRange = &((*(pConfigInfo->AccessRanges))[i]);
+ ASSERT(pAccessRange->RangeLength != 0);
+
+ // Get the mapped system address.
+
+ pBaseAddress = ScsiPortGetDeviceBase(pDeviceExtension,
+ pConfigInfo->AdapterInterfaceType,
+ pConfigInfo->SystemIoBusNumber,
+ pAccessRange->RangeStart,
+ pAccessRange->RangeLength,
+ (BOOLEAN)!pAccessRange->RangeInMemory
+ );
+
+ if (pBaseAddress == NULL) {
+
+ DebugPrint( (0,
+ "DAZZLER: Error getting base addr. for PCI controller.\n"));
+
+ return (SP_RETURN_ERROR);
+ }
+
+
+ // Set the appropriate pointer to the mapped address.
+
+ if (pAccessRange->RangeInMemory) {
+ pMemoryAddress = pBaseAddress;
+
+ ulPhysicalMemoryAddress =
+ ScsiPortConvertPhysicalAddressToUlong( pAccessRange->RangeStart );
+
+ } else {
+ pIoAddress = pBaseAddress;
+ }
+
+ } // end for (i = 0;...)
+
+
+ // Debug checks
+
+ ASSERT(pIoAddress);
+ ASSERT(pMemoryAddress);
+
+ DebugPrint((4,
+ "DAZZLER: PCI controller I/O base address = %0#10x\n",
+ pIoAddress)
+ );
+
+ DebugPrint((4,
+ "DAZZLER: PCI controller memory base address = %0#10x\n",
+ pMemoryAddress)
+ );
+
+ DebugPrint((4,
+ "DAZZLER: PCI controller physical memory address = %0#10x\n",
+ ulPhysicalMemoryAddress)
+ );
+
+ DebugPrint((4,
+ "DAZZLER: PCI controller bus number = %#x\n",
+ pConfigInfo->SystemIoBusNumber)
+ );
+
+ DebugPrint((4,
+ "DAZZLER: PCI controller device number = %#x\n",
+ pPciSlotNumber->u.bits.DeviceNumber)
+ );
+
+ DebugPrint((4,
+ "DAZZLER: PCI controller function number = %#x\n",
+ pPciSlotNumber->u.bits.FunctionNumber)
+ );
+
+ // Finish initalizing the port configuration information
+
+ pConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_SIZE;
+ pConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SG_DESCRIPTORS;
+ pConfigInfo->ScatterGather = TRUE;
+ pConfigInfo->Master = TRUE;
+ pConfigInfo->NumberOfBuses = 1;
+ pConfigInfo->Dma32BitAddresses = TRUE;
+ pConfigInfo->MaximumNumberOfTargets = 32;
+
+ //
+ // Setup some vars needed for the IDENTIFY commands
+ //
+
+ pConfigInfo->CachesData = TRUE;
+ pIDADeviceExtension->SectorShift = 9;
+ pIDADeviceExtension->IdentifyBuffer =
+ ScsiPortGetUncachedExtension(pDeviceExtension,
+ pConfigInfo,
+ 512);
+
+ // Fill in the HBA configuration data in the device extension.
+
+ if (pMemoryAddress) {
+
+ pIDADeviceExtension->HBAConfiguration.ulBaseIOAddress =
+ (ULONG)pMemoryAddress;
+
+ pIDADeviceExtension->CPFIFO =
+ (PULONG)((PUCHAR)pMemoryAddress+IDA_PCI_CPFIFO_OFFSET);
+
+ pIDADeviceExtension->CCFIFO =
+ (PULONG)((PUCHAR)pMemoryAddress+IDA_PCI_CCFIFO_OFFSET);
+
+ pIDADeviceExtension->InterruptMask =
+ (PULONG)((PUCHAR)pMemoryAddress+IDA_PCI_MASK_OFFSET);
+
+ pIDADeviceExtension->InterruptStatus = (PULONG)((PUCHAR)pMemoryAddress+
+ IDA_PCI_STATUS_OFFSET);
+
+ pIDADeviceExtension->InterruptPending = (PULONG)((PUCHAR)pMemoryAddress+
+ IDA_PCI_PENDING_OFFSET);
+
+ ulInitStatus = SP_RETURN_FOUND;
+ }
+
+ if (pIoAddress) {
+ pIDADeviceExtension->BaseIOAddress = (ULONG)pIoAddress;
+ }
+
+ pIDADeviceExtension->HBAConfiguration.bHBAModel = pIDAContext->bHBAModel;
+ pIDADeviceExtension->HBAConfiguration.bHBAIoBusType = PCI_BUS;
+
+ pIDADeviceExtension->HBAConfiguration.HBAIoBusData.PciAddress.
+ bPCIBusNumber = (BYTE)pConfigInfo->SystemIoBusNumber;
+
+ pIDADeviceExtension->HBAConfiguration.HBAIoBusData.PciAddress.
+ bDeviceNumber = (BYTE)pPciSlotNumber->u.bits.DeviceNumber;
+
+ pIDADeviceExtension->HBAConfiguration.HBAIoBusData.PciAddress.
+ bFunctionNumber = (BYTE)pPciSlotNumber->u.bits.FunctionNumber;
+
+ pIDADeviceExtension->HBAConfiguration.bNumScsiBuses =
+ pConfigInfo->NumberOfBuses;
+
+ DebugPrint((1,
+ "CCFIFO=0x%x CPFIFO=0x%x InterruptMask=0x%x InterruptStatus=0x%x InterruptPending=0x%x BaseIo=0x%x\n",
+ pIDADeviceExtension->CCFIFO,
+ pIDADeviceExtension->CPFIFO,
+ pIDADeviceExtension->InterruptMask,
+ pIDADeviceExtension->InterruptStatus,
+ pIDADeviceExtension->InterruptPending,
+ pIDADeviceExtension->BaseIOAddress )
+ );
+
+
+ if (ulInitStatus != SP_RETURN_FOUND) {
+
+ // Free the device base for this controller.
+
+ ScsiPortFreeDeviceBase(pDeviceExtension, pIoAddress);
+ ScsiPortFreeDeviceBase(pDeviceExtension, pMemoryAddress);
+
+ } // end if (ulInitStatus != SP_RETURN_FOUND)
+
+ return (ulInitStatus);
+
+} // end GetPciSpecifics()
+
+
+ULONG
+DriverEntry(
+ IN PVOID pDriverObject,
+ IN PVOID pArgument2
+ )
+
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point. This function initializes
+ the hardware initialization data structure and begins the process of
+ finding controllers that the driver supports.
+
+
+Arguments:
+
+ pDriverObject - Pointer to the driver's driver object.
+ pArgument2 - Pointer to driver's entry in the Registry.
+
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+-- */
+
+{
+ IDA_CONTEXT IDAContext;
+ HW_INITIALIZATION_DATA hwInitializationData;
+ ULONG i, ulStatus, ulReturnStatus=0;
+ ULONG eisaSlotNumber;
+ UCHAR deviceId[8] = {'0', '0', '4', '0', '1', '1', '0', 'E'};
+
+ DebugPrint((0,"\n\nCompaq Disk Array 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 = IdaInitialize;
+ hwInitializationData.HwResetBus = IdaResetBus;
+ hwInitializationData.HwStartIo = IdaStartIo;
+ hwInitializationData.HwInterrupt = IdaInterrupt;
+ hwInitializationData.HwFindAdapter = IdaFindAdapter;
+
+ //
+ // Indicate no buffer mapping but will need physical addresses.
+ //
+
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+
+ //
+ // Specify size of extensions.
+ //
+
+ hwInitializationData.DeviceExtensionSize =
+ sizeof(DEVICE_EXTENSION);
+ hwInitializationData.SpecificLuExtensionSize =
+ sizeof(LOGICAL_UNIT_EXTENSION);
+
+ //
+ // Specifiy the bus type.
+ //
+
+ hwInitializationData.AdapterInterfaceType = Eisa;
+ hwInitializationData.NumberOfAccessRanges = 3;
+
+ //
+ // Ask for SRB extensions for command lists.
+ //
+
+ hwInitializationData.SrbExtensionSize = sizeof(COMMAND_LIST);
+
+ //
+ // 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;
+
+ //
+ // Indicate EISA id.
+ //
+
+ hwInitializationData.DeviceId = &deviceId;
+ hwInitializationData.DeviceIdLength = 8;
+
+ //
+ // Call the system to search for this adapter.
+ //
+
+ ulReturnStatus = ScsiPortInitialize(pDriverObject, pArgument2,
+ &hwInitializationData,
+ &eisaSlotNumber
+ );
+
+ // Initialize hardware initialization data structure to zeroes.
+
+ for (i = 0; i < sizeof(HW_INITIALIZATION_DATA); i++) {
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+ }
+
+ // Fill in the hardware initialization data structure.
+
+ hwInitializationData.HwInitializationDataSize =
+ sizeof(HW_INITIALIZATION_DATA);
+
+ // Set driver entry points.
+
+ hwInitializationData.HwInitialize = IdaInitializePCI;
+ hwInitializationData.HwStartIo = IdaStartIo;
+ hwInitializationData.HwInterrupt = IdaInterrupt;
+ hwInitializationData.HwResetBus = IdaResetBus;
+ hwInitializationData.HwDmaStarted = NULL;
+ hwInitializationData.HwAdapterState = NULL;
+
+
+ // Specify size of extensions.
+
+ hwInitializationData.DeviceExtensionSize = sizeof(DEVICE_EXTENSION);
+
+ hwInitializationData.SpecificLuExtensionSize =
+ sizeof(LOGICAL_UNIT_EXTENSION);
+
+ hwInitializationData.SrbExtensionSize = sizeof(COMMAND_LIST);
+
+
+ // Initialize other data.
+
+ hwInitializationData.MapBuffers = FALSE;
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+ hwInitializationData.TaggedQueuing = TRUE;
+ hwInitializationData.AutoRequestSense = TRUE;
+ hwInitializationData.MultipleRequestPerLu = TRUE;
+ hwInitializationData.ReceiveEvent = FALSE;
+
+ //
+ // Indicate that this controller supports multiple outstanding
+ // requests to its devices.
+ //
+
+ hwInitializationData.MultipleRequestPerLu = TRUE;
+ hwInitializationData.AutoRequestSense = TRUE;
+
+ // Setup required values to find PCI Compaq 32-Bit Array controllers.
+
+ hwInitializationData.AdapterInterfaceType = PCIBus;
+ hwInitializationData.NumberOfAccessRanges = IDA_PCI_NUM_ACCESS_RANGES;
+ hwInitializationData.HwFindAdapter = IDAFindPci;
+
+ IDAContext.bHBAModel = IDA_PCI_DAZZLER;
+ IDAContext.PciAddress.bPCIBusNumber = 0;
+ IDAContext.PciAddress.bDeviceNumber = 0;
+ IDAContext.PciAddress.bFunctionNumber = 0;
+ IDAContext.PciIdentifier.usVendorID = IDA_PCI_COMPAQ_ID;
+ IDAContext.PciIdentifier.usDeviceID = IDA_PCI_DAZZLER_DEVICE_ID;
+
+
+ ulStatus = ScsiPortInitialize(pDriverObject,
+ pArgument2,
+ &hwInitializationData,
+ &IDAContext
+ );
+
+ DebugPrint((0, "DAZZLER: PCI search status = %0#10x\n", ulStatus));
+
+ ulReturnStatus = (ulReturnStatus < ulStatus) ? ulReturnStatus : ulStatus;
+
+ // Return the final status value.
+
+ DebugPrint( (4, "DAZZLER: Final status = %0#10x\n", ulReturnStatus) );
+
+ return (ulReturnStatus);
+
+} // end DriverEntry()
+
+VOID
+IdaDisableInts(
+ IN PDEVICE_EXTENSION pDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Called for SCSI inquiry processing (GetDiskIdentifyData) to eliminate
+ interupts generated at the controller. This was added to support
+ Online Blazer and the ability to recognize Logical Volumes that may
+ be added while the system is running. GetDiskIdentifyData submits
+ the inquiry packet and returns to Startio when this packet has been
+ processed by the controller. Interrupts at the adapter are temporarily
+ disabled because we must wait for completion and we want to get back
+ in a timely fashion.
+
+Arguments:
+
+ pDeviceExtension - pointer to adapter's device extension.
+
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = pDeviceExtension;
+ PULONG pIntMask;
+
+ if (deviceExtension->HBAConfiguration.bHBAModel == IDA_PCI_DAZZLER) {
+
+ //
+ // we are looking at the Dazzler/P...use memapped io
+ //
+
+ pIntMask = deviceExtension->InterruptMask;
+ *pIntMask = 0L;
+ } else
+
+ if (deviceExtension->HBAConfiguration.bHBAModel == IDA_EISA_DAZZLER
+ && !deviceExtension->PCIoff)
+
+ //
+ // we are dealing with Dazzler/E use mapped portio
+ //
+
+ ScsiPortWritePortUlong(&deviceExtension->eisapci->InterruptMask, 0L);
+ else {
+
+ //
+ // ida and prior adapter....BMIC interface
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->InterruptControl, 0);
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SystemDoorBellMask, 0);
+ }
+
+} // end IdaDisableInts
+
+VOID
+IdaEnableInts(
+ IN PDEVICE_EXTENSION pDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Called for SCSI inquiry processing (GetDiskIdentifyData) to enable
+ interupts generated at the controller. This was added to support
+ Online Blazer and the ability to recognize Logical Volumes that may
+ be added while the system is running. GetDiskIdentifyData submits
+ the inquiry packet and returns to Startio when this packet has been
+ processed by the controller. Interrupts at the adapter are temporarily
+ disabled because we must wait for completion and we want to get back
+ in a timely fashion.
+
+Arguments:
+
+ pDeviceExtension - pointer to adapter's device extension.
+
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = pDeviceExtension;
+ PULONG pIntMask;
+
+ if (deviceExtension->HBAConfiguration.bHBAModel == IDA_PCI_DAZZLER) {
+
+ //
+ // Dazzler/P...use memmapped io
+ //
+
+ pIntMask = deviceExtension->InterruptMask;
+ *pIntMask = 1L;
+ } else
+
+ if (deviceExtension->HBAConfiguration.bHBAModel == IDA_EISA_DAZZLER
+ && !deviceExtension->PCIoff)
+
+ //
+ // Dazzler/E...use 32bit port io
+ //
+
+ ScsiPortWritePortUlong(&deviceExtension->eisapci->InterruptMask, 1L);
+ else {
+
+ //
+ // ida and prior...use BMIC interface
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->InterruptControl, 1);
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SystemDoorBellMask, 1);
+ }
+
+} // end IdaEnableInts
diff --git a/private/ntos/miniport/compaq/cpqarray.h b/private/ntos/miniport/compaq/cpqarray.h
new file mode 100644
index 000000000..843f67922
--- /dev/null
+++ b/private/ntos/miniport/compaq/cpqarray.h
@@ -0,0 +1,412 @@
+/*++
+
+Copyright (c) 1991-4 Microsoft Corporation
+
+Module Name:
+
+ cpqarray.h
+
+Abstract:
+
+ This file contains definitions of structures used to
+ communicate with the Compaq Intelligent Disk Array.
+
+Author:
+
+ Mike Glass (mglass)
+ Tom Bonola (Compaq)
+
+Notes:
+
+Revision History:
+
+--*/
+
+//
+// The Command List Header contiains information that applies to all
+// the Request Blocks in the Command List.
+//
+
+typedef struct _COMMAND_LIST_HEADER {
+
+ UCHAR LogicalDriveNumber;
+ UCHAR RequestPriority;
+ USHORT Flags;
+
+} COMMAND_LIST_HEADER, *PCOMMAND_LIST_HEADER;
+
+//
+// Request Priorities
+//
+
+#define CL_NORMAL_PRIORITY 0x02
+
+//
+// Flag word bit definitions
+//
+
+#define CL_FLAGS_NOTIFY_LIST_COMPLETE 0x0000
+#define CL_FLAGS_NOTIFY_REQUEST_COMPLETE 0x0001
+#define CL_FLAGS_NOTIFY_LIST_ERROR 0x0000
+#define CL_FLAGS_NOTIFY_REQUEST_ERROR 0x0002
+#define CL_FLAGS_ABORT_ON_ERROR 0x0004
+#define CL_FLAGS_ORDERED_REQUESTS 0x0008
+
+typedef struct _REQUEST_HEADER {
+
+ USHORT NextRequestOffset;
+ UCHAR CommandByte;
+ UCHAR ErrorCode;
+ ULONG BlockNumber;
+ USHORT BlockCount;
+ UCHAR ScatterGatherCount;
+ UCHAR Reserved;
+
+} REQUEST_HEADER, *PREQUEST_HEADER;
+
+//
+// Error code definitions
+//
+
+#define RH_SUCCESS 0x00
+#define RH_INVALID_REQUEST 0x10
+#define RH_REQUEST_ABORTED 0x08
+#define RH_FATAL_ERROR 0x04
+#define RH_RECOVERABLE_ERROR 0x02
+#define RH_WARNING 0x40
+#define RH_BAD_COMMAND_LIST 0x20
+
+//
+// Scatter/Gather descriptor definition
+//
+
+#define PAGE_SIZE (ULONG)0x1000
+#define MAXIMUM_SG_DESCRIPTORS 17
+#define MAXIMUM_TRANSFER_SIZE (MAXIMUM_SG_DESCRIPTORS - 1) * PAGE_SIZE
+
+typedef struct _SG_DESCRIPTOR {
+
+ ULONG Length;
+ ULONG Address;
+
+} SG_DESCRIPTOR, *PSG_DESCRIPTOR;
+
+//
+// Command List
+//
+
+typedef struct _COMMAND_LIST {
+
+ //
+ // Compaq RLH.
+ //
+
+ COMMAND_LIST_HEADER CommandListHeader;
+ REQUEST_HEADER RequestHeader;
+ SG_DESCRIPTOR SgDescriptor[MAXIMUM_SG_DESCRIPTORS];
+
+ //
+ // Next list entry
+ //
+
+ struct _COMMAND_LIST *NextEntry;
+
+ //
+ // SRB pointer
+ //
+
+ PSCSI_REQUEST_BLOCK SrbAddress;
+
+ //
+ // Request tracking flags
+ //
+
+ ULONG Flags;
+
+ //
+ // Command list size.
+ //
+
+ USHORT CommandListSize;
+
+} COMMAND_LIST, *PCOMMAND_LIST;
+
+//
+// Commands
+//
+
+#define RH_COMMAND_IDENTIFY_LOGICAL_DRIVES 0x10
+#define RH_COMMAND_IDENTIFY_CONTROLLER 0x11
+#define RH_COMMAND_IDENTIFY_LOGICAL_DRIVE_STATUS 0x12
+#define RH_COMMAND_READ 0x20
+#define RH_COMMAND_WRITE 0x30
+#define RH_COMMAND_SENSE_CONFIGURATION 0x50
+#define RH_COMMAND_SET_CONFIGURATION 0x51
+#define RH_COMMAND_FLUSH_DISABLE_CACHE 0xc2
+#define RH_COMMAND_SCSI_PASS_THRU 0x90
+
+//
+// Flag field bit definitions
+//
+
+#define CL_FLAGS_REQUEST_QUEUED 0x0001
+#define CL_FLAGS_REQUEST_STARTED 0x0002
+#define CL_FLAGS_REQUEST_COMPLETED 0x0004
+#define CL_FLAGS_IDENTIFY_REQUEST 0x0008
+
+//
+// Fixed Disk Parameter Table
+//
+
+#pragma pack(1)
+
+typedef struct _DISK_PARAMETER_TABLE {
+
+ USHORT MaximumCylinders; // BIOS translated
+ UCHAR MaximumHeads; // BIOS translated
+ UCHAR TranslationSignature;
+ UCHAR SectorsPerTrack; // physical characteristics
+ USHORT WritePrecompCylinder;
+ UCHAR MaximumECCBurst;
+ UCHAR DriveControl;
+ USHORT NumberOfCylinders; // physical characteristics
+ UCHAR NumberOfHeads; // physical characteristics
+ USHORT LandingZone;
+ UCHAR MaximumSectorsPerTrack; // BIOS translated
+ UCHAR CheckSum;
+
+} DISK_PARAMETER_TABLE, *PDISK_PARAMETER_TABLE;
+
+#define IDENTIFY_BUFFER_SIZE 512
+
+//
+// Identify Logical Drives
+//
+
+typedef struct _IDENTIFY_LOGICAL_DRIVE {
+
+ USHORT BlockLength;
+ ULONG NumberOfBlocks;
+ DISK_PARAMETER_TABLE ParameterTable;
+ UCHAR FaultToleranceType;
+ UCHAR Reserved[5];
+
+} IDENTIFY_LOGICAL_DRIVE, *PIDENTIFY_LOGICAL_DRIVE;
+
+//
+// Identify Controller information
+//
+
+typedef struct _IDENTIFY_CONTROLLER {
+
+ UCHAR NumberLogicalDrives;
+ ULONG ConfigurationSignature;
+ UCHAR FirmwareRevision[4];
+ UCHAR Reserved[247];
+
+} IDENTIFY_CONTROLLER, *PIDENTIFY_CONTROLLER;
+
+//
+// Set/Sense Configuration information
+//
+
+typedef struct _SENSE_CONFIGURATION {
+
+ ULONG ConfigurationSignature;
+ USHORT SiConfiguration;
+ USHORT OsConfiguration;
+ USHORT NumberPhysicalDrives;
+ USHORT PDrivesInLDrives;
+ USHORT FaultToleranceType;
+ UCHAR PhysicalDrive[16];
+ UCHAR LogicalDrive[16];
+ ULONG DriveAssignmentMap;
+ UCHAR Reserved[462];
+
+} SENSE_CONFIGURATION, *PCONFIGURATION;
+
+//
+// Fault Tolerance Type
+//
+
+#define FT_DATA_GUARD 0x0002
+#define FT_MIRRORING 0x0001
+#define FT_NONE_ 0x0000
+
+//
+// Drive Failure Assignment Map
+//
+
+typedef struct _DRIVE_FAILURE_MAP {
+
+ UCHAR LogicalDriveStatus;
+ UCHAR DriveFailureAssignmentMap[4];
+ UCHAR Reserved[251];
+
+} DRIVE_FAILURE_MAP, *PDRIVE_FAILURE_MAP;
+
+#pragma pack()
+
+typedef struct _MAILBOX {
+
+ ULONG Address;
+ USHORT Length;
+ UCHAR Status;
+ UCHAR TagId;
+
+} MAILBOX, *PMAILBOX;
+
+//
+// Command List Status bit definitions
+//
+
+#define CL_STATUS_LIST_COMPLETE 0x01
+#define CL_STATUS_NONFATAL_ERROR 0x02
+#define CL_STATUS_FATAL_ERROR 0x04
+#define CL_STATUS_ABORT 0x08
+
+//
+// 32-bit IDA Controller registers
+//
+
+typedef struct _IDA_CONTROLLER {
+
+ ULONG BoardId; // xC80
+ UCHAR Undefined[4]; // xC84
+ UCHAR Configuration; // xC88
+ UCHAR InterruptControl; // xC89
+ UCHAR Undefined1[2]; // xC8A
+ UCHAR LocalDoorBellMask; // xC8C
+ UCHAR LocalDoorBell; // xC8D
+ UCHAR SystemDoorBellMask; // xC8E
+ UCHAR SystemDoorBell; // xC8F
+ MAILBOX CommandListSubmit; // xC90
+ MAILBOX CommandListComplete; // xC98`
+ UCHAR Reserved[32]; // xCA0
+ UCHAR ControllerConfiguration; // xCC0
+
+} IDA_CONTROLLER, *PIDA_CONTROLLER;
+
+//
+// Controller bHBAModel definitions
+//
+#define IDA_UNDEFINED_CONTROLLER 0
+#define IDA_BASE_CONTROLLER 1
+#define IDA_PCI_DAZZLER 2
+#define IDA_EISA_DAZZLER 3
+
+//
+// DAZZLER PCI interface definitions for EISA I/O space
+//
+
+typedef struct _EISAPCI_CONTROLLER {
+
+ ULONG Timer; // x000
+ ULONG CPFIFO; // x004
+ ULONG CCFIFO; // x008
+ ULONG InterruptMask; // x00C
+ ULONG InterruptStatus; // x010
+ ULONG InterruptPending; // x014
+
+} EISAPCI_CONTROLLER, *PEISAPCI_CONTROLLER;
+
+#define IDA_PCI_TIMER_OFFSET 0
+#define IDA_PCI_CPFIFO_OFFSET 4
+#define IDA_PCI_CCFIFO_OFFSET 8
+#define IDA_PCI_MASK_OFFSET 12
+#define IDA_PCI_STATUS_OFFSET 16
+#define IDA_PCI_PENDING_OFFSET 20
+
+#define IDA_PCI_IRQ_DISABLE_MASK 0x00000000
+#define IDA_PCI_FIFO_NOT_EMPTY_MASK 0x00000001
+#define IDA_PCI_FIFO_NOT_FULL_MASK 0x00000002
+#define IDA_PCI_COMPLETION_STATUS_ACTIVE 0x00000001
+#define IDA_PCI_ISSUE_STATUS_CLEAR 0x00000002
+
+#define IDA_PCI_PHYS_ADDR_MASK 0xfffffffc
+#define IDA_PCI_COMPLETION_STATUS_MASK 0x00000003
+#define IDA_PCI_COMPLETION_ERROR 0x00000001
+
+#define IDA_PCI_COMPAQ_ID 0x00000E11
+#define IDA_PCI_DAZZLER_DEVICE_ID 0x0000AE10
+#define IDA_EISA_ID_MASKID_LOW 0xff000000
+
+#define IDA_PCI_NUM_ACCESS_RANGES 3
+
+typedef struct _PCI_IDENTIFIER {
+ USHORT usVendorID;
+ USHORT usDeviceID;
+} PCI_IDENTIFIER, *PPCI_IDENTIFIER;
+
+typedef struct _IDA_CONTEXT {
+ UCHAR bHBAModel;
+ USHORT usEisaSlot;
+ PCI_IDENTIFIER PciIdentifier;
+ PCI_ADDRESS PciAddress;
+} IDA_CONTEXT, *PIDA_CONTEXT;
+
+
+//
+// System Doorbell Interrupt Register bit definitions
+//
+
+#define SYSTEM_DOORBELL_COMMAND_LIST_COMPLETE 0x01
+#define SYSTEM_DOORBELL_SUBMIT_CHANNEL_CLEAR 0x02
+
+//
+// Local Doorbell Interrupt Register bit definitions
+//
+
+#define LOCAL_DOORBELL_COMMAND_LIST_SUBMIT 0x01
+#define LOCAL_DOORBELL_COMPLETE_CHANNEL_CLEAR 0x02
+
+//
+// Doorbell register channel clear bit
+//
+
+#define IDA_CHANNEL_CLEAR 0x01
+
+//
+// Interrupt Control register bit definitions
+//
+
+#define IDA_INTERRUPT_PENDING 0x02
+
+//
+// System doorbell register interrupt mask
+//
+
+#define IDA_COMPLETION_INTERRUPT_ENABLE 0x01
+
+//
+// Controller Configuration Register bit definitions
+//
+
+#define STANDARD_INTERFACE_ENABLE 0x01
+#define STANDARD_INTERFACE_SECONDARY_IO_ADDRESS 0x02
+#define BUS_MASTER_DISABLE 0x04
+#define SOFTWARE_RESET 0x08
+#define BUS_MASTER_INTERRUPT_11_ENABLE 0x10
+#define BUS_MASTER_INTERRUPT_10_ENABLE 0x20
+#define BUS_MASTER_INTERRUPT_14_ENABLE 0x40
+#define BUS_MASTER_INTERRUPT_15_ENABLE 0x80
+
+//
+// Disk configuration information
+//
+
+typedef struct _DISK_CONFIGURATION {
+
+ UCHAR NumberLogicalDrives;
+ IDENTIFY_LOGICAL_DRIVE LogicalDriveInformation[2];
+
+} DISK_CONFIGURATION, *PDISK_CONFIGURATION;
+
+//
+// structure for the flush/disable cache command
+//
+typedef struct _FLUSH_DISABLE {
+ USHORT disable_flag;
+ UCHAR reserved[30];
+} FLUSH_DISABLE, *PFLUSH_DISABLE;
+
diff --git a/private/ntos/miniport/compaq/cpqarray.rc b/private/ntos/miniport/compaq/cpqarray.rc
new file mode 100644
index 000000000..b6be0f39f
--- /dev/null
+++ b/private/ntos/miniport/compaq/cpqarray.rc
@@ -0,0 +1,13 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Compaq Disk Array Driver 2,01,01,001"
+#define VER_INTERNALNAME_STR "cpqarray.sys"
+#define VER_ORIGINALFILENAME_STR "cpqarray.sys"
+
+#include "common.ver"
+
+
diff --git a/private/ntos/miniport/compaq/cpqsczmp.h b/private/ntos/miniport/compaq/cpqsczmp.h
new file mode 100644
index 000000000..7c9198dc4
--- /dev/null
+++ b/private/ntos/miniport/compaq/cpqsczmp.h
@@ -0,0 +1,211 @@
+/*++
+
+Copyright Compaq Computer Corporation 1994. All Rights Reserved.
+
+
+Module Name:
+
+ CPQSCZMP.H
+
+
+Abstract:
+
+ This file contains data structures and definitions used by SCSI miniport
+ drivers that support Compaq Monitoring & Performance.
+
+
+Author:
+
+ Michael E. McGowen
+
+
+Revision History:
+
+ 1.00 MEM 04/01/94 Initial release.
+ 1.01 MEM 07/01/94 Added additional fields to HBA configuration.
+ 1.02 MEM 08/08/94 Changed IOCTL signature.
+
+
+-- */
+
+
+
+/**************************************************************************
+ *
+ * DATA TYPE PREFIX (Hungarian notation)
+ *
+ * f : BOOL (flag)
+ * ch : CHAR (signed 8 bit)
+ * s : SHORT (signed 16 bit)
+ * l : LONG (signed 32 bit)
+ * uch : UCHAR (unsigned 8 bit)
+ * us : USHORT (unsigned 16 bit)
+ * ul : ULONG (unsigned 32 bit)
+ * b : BYTE (unsigned 8 bit)
+ * sz : CHAR[] (ASCIIZ array of char)
+ * fb : UCHAR (bitmapped byte of flags)
+ * fs : USHORT (bitmapped short of flags)
+ * fl : ULONG (bitmapped long of flags)
+ * r : REAL (real number, single precision 32bit)
+ * rd : DOUBLE (real number, double precision 64bit)
+ * pfn : pointer to function
+ * x : x coordinate
+ * y : y coordinate
+ * sel : Segment selector
+ * p : Pointer (pch, pus, psz, ...)
+ * np : near pointer...
+ * a : array (ach, aus, asz, ...)
+ * i : index to array (ich, ius, ...)
+ * c : count (cb, cus, ...)
+ * d : delta ,difference (dx, dy, ...)
+ * h : handle
+ * id : ID
+ * g : Global variable
+ *
+ *************************************************************************/
+
+#ifndef _INCL_CPQSCZMP_H_
+#define _INCL_CPQSCZMP_H_
+
+
+// Common defines
+
+#define MAX_DRIVER_DESC_SIZE 81
+#define MAX_DRIVER_NAME_SIZE 13
+
+
+// HBA I/O Bus Types
+
+#define ISA_BUS 1
+#define EISA_BUS 2
+#define PCI_BUS 3
+#define PCMCIA_BUS 4
+
+
+// IOCTL defines supporting Compaq M&P
+
+#define CPQ_SCSI_IOCTL_SIGNATURE "SCSIM&P"
+#define CPQ_SCSI_IOCTL_TIMEOUT 10
+
+
+// IOCTL control codes
+
+#define CPQ_SCSI_IOCTL_GET_DRIVER_INFO 1
+#define CPQ_SCSI_IOCTL_GET_HBA_CONFIG 2
+#define CPQ_SCSI_IOCTL_GET_SCSI_BUS_DATA 3
+#define CPQ_SCSI_IOCTL_GET_DEVICE_DATA 4
+#define CPQ_SCSI_IOCTL_GET_DEVICE_ERRORS 5
+#define CPQ_SCSI_IOCTL_GET_AND_CLEAR_DEVICE_DATA 6
+#define CPQ_SCSI_IOCTL_GET_AND_CLEAR_DEVICE_ERRORS 7
+
+
+// IOCTL return codes
+
+#define CPQ_SCSI_ERR_OK 0
+#define CPQ_SCSI_ERR_FAILED 1
+#define CPQ_SCSI_ERR_BAD_CNTL_CODE 2
+#define CPQ_SCSI_ERR_REVISION 3
+#define CPQ_SCSI_ERR_MORE_DATA 4
+#define CPQ_SCSI_ERR_INVALID_DEVICE 5
+
+
+// Macros
+
+#define INCREMENT_ULONG(ulValue) \
+ { \
+ if (ulValue < 0xFFFFFFFE) \
+ ulValue++; \
+ } \
+
+
+// Data structures
+
+typedef struct _SCSI_MINIPORT_DRIVER_INFO {
+ CHAR szDriverName[MAX_DRIVER_NAME_SIZE];
+ CHAR szDriverDescription[MAX_DRIVER_DESC_SIZE];
+ SHORT sDriverMajorRev;
+ SHORT sDriverMinorRev;
+ BOOLEAN fMandPSupported;
+} SCSI_MINIPORT_DRIVER_INFO, *PSCSI_MINIPORT_DRIVER_INFO;
+
+typedef struct _PCI_ADDRESS {
+ BYTE bPCIBusNumber;
+ BYTE bDeviceNumber;
+ BYTE bFunctionNumber;
+ BYTE bReserved;
+} PCI_ADDRESS, *PPCI_ADDRESS;
+
+typedef union _IO_BUS_DATA {
+ USHORT usEisaSlot;
+ PCI_ADDRESS PciAddress;
+} IO_BUS_DATA, *PIO_BUS_DATA;
+
+typedef struct _HBA_CONFIGURATION {
+ ULONG ulBaseIOAddress;
+ BYTE bHBAModel;
+ BYTE bHBAIoBusType;
+ IO_BUS_DATA HBAIoBusData;
+ BYTE bNumScsiBuses;
+ BYTE abInitiatorBusId[8];
+ CHAR szFWVers[5];
+ CHAR szSWVers[5];
+ CHAR szSerialNumber[16];
+ ULONG ulBoardID;
+ BYTE bBoardRevision;
+ BOOLEAN fWideSCSI;
+} HBA_CONFIGURATION, *PHBA_CONFIGURATION;
+
+typedef struct _DEVICE_DATA {
+ SCSI_ADDRESS DeviceAddress;
+ CPQ_SCSI_DEVICE DeviceData;
+} DEVICE_DATA, *PDEVICE_DATA;
+
+typedef struct _DEVICE_ERRORS {
+ ULONG ulHardReadErrs;
+ ULONG ulHardWriteErrs;
+ ULONG ulEccCorrReads;
+ ULONG ulRecvReadErrs;
+ ULONG ulRecvWriteErrs;
+ ULONG ulSeekErrs;
+ ULONG ulTimeouts;
+} DEVICE_ERRORS, *PDEVICE_ERRORS;
+
+typedef struct _DEVICE_ERROR_DATA {
+ SCSI_ADDRESS DeviceAddress;
+ DEVICE_ERRORS DeviceErrors;
+} DEVICE_ERROR_DATA, *PDEVICE_ERROR_DATA;
+
+
+// IOCTL buffer data structures
+
+typedef struct _DRIVER_INFO_BUFFER {
+ SRB_IO_CONTROL IoctlHeader;
+ SCSI_MINIPORT_DRIVER_INFO DriverInfo;
+} DRIVER_INFO_BUFFER, *PDRIVER_INFO_BUFFER;
+
+typedef struct _HBA_CONFIGURATION_BUFFER {
+ SRB_IO_CONTROL IoctlHeader;
+ HBA_CONFIGURATION HBAConfiguration;
+} HBA_CONFIGURATION_BUFFER, *PHBA_CONFIGURATION_BUFFER;
+
+typedef struct _SCSI_BUS_DATA_BUFFER {
+ SRB_IO_CONTROL IoctlHeader;
+ CPQ_SCSI_CNTLR ScsiBus;
+} SCSI_BUS_DATA_BUFFER, *PSCSI_BUS_DATA_BUFFER;
+
+typedef struct _DEVICE_DATA_BUFFER {
+ SRB_IO_CONTROL IoctlHeader;
+ DEVICE_DATA ScsiDevice;
+} DEVICE_DATA_BUFFER, *PDEVICE_DATA_BUFFER;
+
+typedef struct _DEVICE_ERROR_DATA_BUFFER {
+ SRB_IO_CONTROL IoctlHeader;
+ DEVICE_ERROR_DATA ScsiDevice;
+} DEVICE_ERROR_DATA_BUFFER, *PDEVICE_ERROR_DATA_BUFFER;
+
+typedef struct _MORE_DATA_BUFFER {
+ SRB_IO_CONTROL IoctlHeader;
+ ULONG ulExpectedSize;
+} MORE_DATA_BUFFER, *PMORE_DATA_BUFFER;
+
+#endif // _INCL_CPQSCZMP_H_
diff --git a/private/ntos/miniport/compaq/cpqsmngr.h b/private/ntos/miniport/compaq/cpqsmngr.h
new file mode 100644
index 000000000..7fa592cc6
--- /dev/null
+++ b/private/ntos/miniport/compaq/cpqsmngr.h
@@ -0,0 +1,509 @@
+/*++
+
+
+Copyright (c) 1993 Microsoft Corporation
+Copyright (c) 1993 Compaq Computer Corporation
+
+Module Name:
+
+ cpqsmngr.h
+
+Abstract:
+
+ This file contains the data structures required to support Compaq's
+ Management and Performance.
+
+Author:
+
+ Tombo - Compaq Computer Corporation
+
+Notes:
+
+Revision History:
+
+--*/
+
+#ifndef CPQSMNGR
+#define CPQSMNGR
+
+#define IDA_DRIVER_NAME "Compaq Windows NT DriveArray"
+#define IDA_MAJOR_VERSION 2
+#define IDA_MINOR_VERSION 00
+
+//
+// The following defines identify the appropriate IDA controller types.
+//
+
+#define IDA_EISA_ID_TYPEMASK 0x00ffffff // Masks off the controller type
+#define IDA_EISA_ID_ARRAY 0x0040110e // 0x0e114000 Common for all IDAs
+
+#define IDA_EISA_ID_DISCO 0x0140110e // 0x0e114001
+#define IDA_EISA_ID_CANCUN 0x0240110e // 0x0e114002
+#define IDA_EISA_ID_STANZA 0x1040110e // 0x0e114010
+#define IDA_EISA_ID_WARRIOR 0x2040110e // 0x0e114020
+#define IDA_EISA_ID_DAZZLER 0x3040110e // 0x0e114030
+
+//
+// This macro checks the Irp for a device control function.
+//
+// The parameters for this macro are...
+//
+// IN PIRP Irp // Pointer to the IO request packet.
+//
+#define MAPISPASSTHROUGH( Irp ) \
+ ((IoGetCurrentIrpStackLocation(Irp)->MajorFunction \
+ == \
+ IRP_MJ_DEVICE_CONTROL ) && \
+ (IoGetCurrentIrpStackLocation(Irp)->\
+ Parameters.DeviceIoControl.IoControlCode \
+ == \
+ MAP_IOCTL_PASSTHROUGH ))
+#ifndef NSCSIPASS
+#define MAPISSCSIPASSTHROUGH( Irp ) \
+ ((IoGetCurrentIrpStackLocation(Irp)->MajorFunction \
+ == \
+ IRP_MJ_DEVICE_CONTROL ) && \
+ (IoGetCurrentIrpStackLocation(Irp)->\
+ Parameters.DeviceIoControl.IoControlCode \
+ == \
+ MAP_IOCTL_SCSIPASSTHROUGH ))
+#endif
+
+//
+// The following macro frees up any allocated resources beginning at
+// the specified controller device.
+//
+#define MAP_FREE_RESOURCES( ControllerDevice ){ \
+ PMAP_CONTROLLER_DEVICE Controller; \
+ PMAP_CONTROLLER_DEVICE tmpController; \
+ PMAP_DISK_DEVICE Disk; \
+ PMAP_DISK_DEVICE tmpDisk; \
+ \
+ for( Controller=ControllerDevice; Controller; Controller=tmpController ){\
+ for( Disk=Controller->DiskDeviceList; Disk; Disk=tmpDisk ){ \
+ tmpDisk = Disk->Next; \
+ ExFreePool( Disk ); \
+ } \
+ tmpController = Controller->Next; \
+ ExFreePool( Controller ); \
+ } \
+}
+
+//
+// The following macro obtains a pointer to the last CONTROLLER_DEVICE
+// in the chain of MAP controller devices.
+//
+#define MAP_GET_LAST_CONTROLLER( cd ){ \
+ PMAP_CONTROLLER_DEVICE c; \
+ if( FirstController ){ \
+ for( c = FirstController; \
+ c->Next; \
+ c = c->Next ); \
+ *((PMAP_CONTROLLER_DEVICE*)(cd)) = c; \
+ }else{ \
+ *((PMAP_CONTROLLER_DEVICE*)(cd)) = FirstController; \
+ } \
+}
+
+//
+// The following macro obtains a pointer to the last DISK_DEVICE
+// in the chain of MAP disk devices on the last controller.
+//
+#define MAP_GET_LAST_DISK( dd, cd ){ \
+ PMAP_DISK_DEVICE d; \
+ *((PMAP_DISK_DEVICE*)(dd)) = (PMAP_DISK_DEVICE)0; \
+ MAP_GET_LAST_CONTROLLER( (cd) ); \
+ if( *((PMAP_CONTROLLER_DEVICE*)(cd)) ){ \
+ if((*((PMAP_CONTROLLER_DEVICE*)(cd)))->DiskDeviceList){ \
+ for( d = (*((PMAP_CONTROLLER_DEVICE*)(cd)))->DiskDeviceList; \
+ d->Next; \
+ d = d->Next ); \
+ *((PMAP_DISK_DEVICE*)(dd)) = d; \
+ } \
+ } \
+}
+
+#pragma pack( 1 ) // All structures need to be byte packed.
+
+//
+// The following data structure represents the MAP header buffer filled
+// in by the MAP_COMMAND_IDDRIVER command.
+//
+// The Entries include...
+//
+// DriverName - Pointer to an Array of NUL terminated ASCII
+// characters representing the IDA driver name.
+//
+// ControllerCount - The number of IDA controllers in the system.
+//
+// LogicalDiskCount - The aggregate number of IDA logical disks found
+// in the system.
+//
+// RequiredMemory - The memory size required for the data buffer
+// used in the IDA_MAP_COMMAND_IDCONTROLLERS command.
+//
+// DriverMajorVersion - The version number to the right hand side
+// of the decimal point.
+//
+// DriverMinorVersion - The version number to the left hand side
+// of the decimal point.
+//
+
+typedef struct _MAP_HEADER{
+
+ UCHAR DriverName[32];
+ ULONG ControllerCount;
+ ULONG LogicalDiskCount;
+ ULONG RequiredMemory;
+ UCHAR DriverMajorVersion;
+ UCHAR DriverMinorVersion;
+
+}MAP_HEADER, *PMAP_HEADER;
+
+//
+// The following data structure represents the MAP header buffer filled
+// in by the MAP_COMMAND_IDCONTROLLERS command.
+//
+// The Entries include...
+//
+// NextController - Pointer to the next controller in the chain.
+// A value of NULL indicates no more controllers follow.
+//
+// LogicalDriveList - Pointer to the list of IDA logical drive
+// information for ALL of the IDA logical drives that exist
+// on this controller.
+//
+// EisaId - The Eisa ID number read as a 32 bit value from EISA IO
+// space zC80h - zC83h. The valid values include...
+//
+// IDA_EISA_ID_DISCO 0x0140110e // 0e 11 40 01
+// IDA_EISA_ID_CANCUN 0x0240110e // 0e 11 40 02
+// IDA_EISA_ID_STANZA 0x1040110e // 0e 11 40 10
+// IDA_EISA_ID_WARRIOR 0x2040110e // 0e 11 40 20
+//
+// BmicIoAddress - The IO address where this controller resides in
+// EISA IO space. The value will be some derivative of zC80h
+// where 'z' is the physical EISA slot the controller resides
+// in.
+//
+// IrqLevel - The controller's EISA bus interrupt level.
+//
+// ControllerInfo - The controller's information as received by the
+// "IdentifyController" IDA logical command.
+// The size of this data structure will be the largest size
+// required to accomodate ALL flavors of Compaq supported IDA
+// controllers.
+//
+
+typedef struct _MAP_CONTROLLER_DATA{
+
+ struct _MAP_CONTROLLER_DATA *NextController;
+ struct _MAP_LOGICALDRIVE_DATA *LogicalDriveList;
+ ULONG EisaId;
+ ULONG BmicIoAddress;
+ UCHAR IrqLevel;
+ IDENTIFY_CONTROLLER ControllerInfo; //"IdentifyController"
+
+}MAP_CONTROLLER_DATA, *PMAP_CONTROLLER_DATA;
+
+//
+// The following data structure represents the MAP header buffer filled
+// in by the MAP_COMMAND_IDCONTROLLERS command. This is a fragment
+// data structure that defines the IDA logical drive information for each
+// IDA controller.
+//
+// The Entries include...
+//
+// NextLogicalDrive - Pointer to the next IDA logical drive on this
+// controller. A value of NULL indicates that there are no more
+// IDA logical drives on this controller.
+//
+// Controller - Pointer to the Controller data structure that this
+// IDA logical drive resides on.
+//
+// LogicalDriveNumber - The IDA logical drive number assigned by this
+// controller.
+//
+// SystemDriveNumber - The NT drive number assigned to this IDA logical
+// drive by the IDA device driver. It is the number that represents
+// "\Device\HarddiskN" where "N" is the SystemDriveNumber.
+//
+// DeviceLengthLo - The Low 32 bits of the IDA logical device's RAW
+// partition length.
+//
+// DeviceLengthHi - The High 32 bits of the IDA logical drive's RAW
+// partition length.
+//
+// SectorSize - The sector size in bytes for this IDA logical device.
+//
+// Configuration - The logical drive's configuration information as
+// received by the "SenseConfiguration" IDA logical command.
+// The size of this data structure will be the largest size
+// required to accomodate ALL flavors of Compaq supported IDA
+// controllers.
+//
+// LogicalDriveInfo - The IDA logical drive information buffer as
+// received by the "IdentifyLogicalDrive" IDA logical command.
+// The size of this data structure will be the largest size
+// required to accomodate ALL flavors of Compaq supported IDA
+// controllers.
+//
+
+typedef struct _MAP_LOGICALDRIVE_DATA{
+
+ struct _MAP_LOGICALDRIVE_DATA *NextLogicalDrive;
+ struct _MAP_CONTROLLER_DATA *Controller;
+ ULONG LogicalDriveNumber;
+ ULONG SystemDriveNumber;
+ ULONG DeviceLengthLo;
+ ULONG DeviceLengthHi;
+ ULONG SectorSize;
+ SENSE_CONFIGURATION Configuration; //"SenseConfiguration"
+ IDENTIFY_LOGICAL_DRIVE LogicalDriveInfo; //"IdentifyLogicalDrive"
+
+}MAP_LOGICALDRIVE_DATA, *PMAP_LOGICALDRIVE_DATA;
+
+//
+// The following data structure represents the parameter packet buffer
+// specified in all of the M&P device controls to the IDA device driver.
+//
+// The Entries include...
+//
+// Reserved
+//
+// IdaLogicalCommand - The IDA logical command to passthrough to the
+// IDA controller. This field is read by the IDA device driver.
+//
+// BlockNumber - The starting block number on the IDA logical drive.
+//
+// BlockSize - The size in bytes of the passthrough data transfer.
+//
+// BlockCount - The number of blocks to transfer. A block is equal
+// to a sector worth of data.
+//
+
+typedef struct _MAP_PARAMETER_PACKET{
+
+ UCHAR TargetId;
+ IN UCHAR IdaLogicalCommand;
+ IN ULONG BlockNumber;
+ IN ULONG BlockSize;
+ IN USHORT BlockCount;
+
+}MAP_PARAMETER_PACKET, *PMAP_PARAMETER_PACKET;
+
+
+//
+// The following data structure represents the data packet buffer
+// specified in all of the M&P device controls to the IDA device driver.
+//
+// The Entries include...
+//
+// ControllerError - The error bits returned by the IDA controller.
+//
+// ControllerData - The requested data returned by the controller.
+//
+
+typedef struct _MAP_DATA_PACKET{
+
+ OUT ULONG ControllerError;
+ OUT UCHAR ControllerData[];
+
+}MAP_DATA_PACKET, *PMAP_DATA_PACKET;
+
+//
+// The following data structures are used to abstract Microsoft's use
+// of controller and device data structures to fit COMPAQ's M&P data
+// structure format. This permits Microsoft's data structures to remain
+// unaltered so that my buddy, Mr. Disk himself, Mike Glass (AKA Gumby)
+// can still support general Array functionalilty without having to
+// figure out what the hell I did!
+//
+
+typedef struct _MAP_CONTROLLER_DEVICE{
+
+ // Pointer to the next controller device structure.
+ struct _MAP_CONTROLLER_DEVICE* Next;
+
+ // Pointer to the Microsoft defined device extension for this controller.
+ PDEVICE_EXTENSION ControllerExtension;
+
+ // EISA ID for this controller device.
+ ULONG EisaID;
+
+ // Pointer to a list of MAP logical device data structures.
+ struct _MAP_DISK_DEVICE* DiskDeviceList;
+
+ // Array controller configuration information data area.
+ IDENTIFY_CONTROLLER ControllerInformation;
+
+}MAP_CONTROLLER_DEVICE, *PMAP_CONTROLLER_DEVICE;
+
+
+typedef struct _MAP_DISK_DEVICE{
+
+ // Pointer to the next disk device data structure.
+ struct _MAP_DISK_DEVICE* Next;
+
+ // Pointer to Microsoft's defined disk device extension.
+ PDEVICE_EXTENSION DeviceExtension;
+
+ // Disk device configuration information data area.
+ SENSE_CONFIGURATION DeviceConfiguration;
+
+ // Disk device information data area.
+ IDENTIFY_LOGICAL_DRIVE DeviceInformation;
+
+ // The logical drive number for this disk device on this controller.
+ ULONG LogicalDriveNumber;
+
+ // The NT system drive number assigned by NT.
+ ULONG SystemDriveNumber;
+
+ // Pointer to the controller device data area for the controller this
+ // logical disk device resides on.
+ PMAP_CONTROLLER_DEVICE ControllerDevice;
+
+}MAP_DISK_DEVICE, *PMAP_DISK_DEVICE;
+#ifndef NSCSIPASS
+typedef struct {
+ CHAR CmdError;
+ CHAR device_status;
+ CHAR machine_error;
+ CHAR reserved;
+ UCHAR data[512];
+} SCSI_BUFFER,*PSCSI_BUFFER;
+
+typedef struct _SCSI_PASSTHRU_HEADER {
+ UCHAR scsi_target_id;
+ UCHAR path_id;
+ UCHAR logical_unit;
+ ULONG time_out_value;
+ ULONG flags;
+ UCHAR device_status;
+ UCHAR machine_error;
+ UCHAR cdb_length;
+ UCHAR reserved[16];
+
+} SCSI_PASSTHRU_HEADER, *PSCSI_PASSTHRU_HEADER;
+
+#define MAX_CDB_LENGTH 24
+typedef struct _SCSI_PASSTHRU_CDB {
+ UCHAR cdb[MAX_CDB_LENGTH];
+} SCSI_PASSTHRU_CDB, *PSCSI_PASSTHRU_CDB;
+
+typedef struct _SCSI_PASSTHRU {
+ SCSI_PASSTHRU_HEADER scsi_header;
+ SCSI_PASSTHRU_CDB scsi_cdb;
+} SCSI_PASSTHRU, *PSCSI_PASSTHRU;
+#endif
+#define CPQ_SCSI_ERR_OK 0
+#define CPQ_SCSI_ERR_FAILED 1
+#define CPQ_SCSI_ERR_BAD_CNTL_CODE 2
+#define CPQ_SCSI_ERR_REVISION 3
+#define CPQ_SCSI_ERR_NONCONTIGUOUS 4
+
+
+//Arbitrary return values not associated to the same routines.
+
+#define CPQ_CIM_ISSUED 1
+#define CPQ_CIM_COMPLETED 2
+#define CPQ_CIM_CMDBUILT 3
+#define CPQ_CIM_NONCONTIGUOUS 4
+#define CPQ_CIM_ERROR 5
+
+//
+// Define header for I/O control SRB.
+//
+
+#ifdef NDAZ
+typedef struct _SRB_IO_CONTROL {
+ ULONG HeaderLength;
+ UCHAR Signature[8];
+ ULONG Timeout;
+ ULONG ControlCode;
+ ULONG ReturnCode;
+ ULONG Length;
+} SRB_IO_CONTROL, *PSRB_IO_CONTROL;
+#endif
+
+
+typedef struct _IDA_ERROR_BITS {
+ ULONG ControllerError;
+} IDA_ERROR_BITS, *PIDA_ERROR_BITS;
+
+typedef struct _SCSI_BUFFER_HEADER {
+ UCHAR CmdError;
+ UCHAR device_status;
+ UCHAR machine_error;
+ UCHAR reserved;
+} SCSI_BUFFER_HEADER, *PSCSI_BUFFER_HEADER;
+
+typedef struct _IDA_SCSI_PASSTHRU {
+ SCSI_PASSTHRU scsipass;
+ SCSI_BUFFER scsibuffer;
+}IDA_SCSI_PASSTHRU, *PIDA_SCSI_PASSTHRU;
+
+typedef struct _CPQ_IDA_PASSTHRU {
+ SRB_IO_CONTROL Header;
+ MAP_PARAMETER_PACKET PassThru;
+ UCHAR ReturnData[1];
+}CPQ_IDA_PASSTHRU, *PCPQ_IDA_PASSTHRU;
+
+typedef struct _CPQ_IDA_SCSI_PASSTHRU {
+ SRB_IO_CONTROL Header;
+ IDA_SCSI_PASSTHRU ScsiPassThru;
+}CPQ_IDA_SCSI_PASSTHRU, *PCPQ_IDA_SCSI_PASSTHRU;
+
+typedef struct _CPQ_IDA_IDENTIFY {
+ SRB_IO_CONTROL Header;
+ UCHAR ReturnData[1];
+}CPQ_IDA_IDENTIFY, *PCPQ_IDA_IDENTIFY;
+
+typedef struct _IDA_CONFIGURATION {
+ ULONG ulBaseIOAddress;
+ ULONG ulBaseMemoryAddress;
+ ULONG ulControllerID;
+ BYTE bIoBusType;
+ IO_BUS_DATA IoBusData;
+} IDA_CONFIGURATION, *PIDA_CONFIGURATION;
+
+typedef struct _IDA_CONFIGURATION_BUFFER {
+ SRB_IO_CONTROL IoctlHeader;
+ IDA_CONFIGURATION IDAConfiguration;
+} IDA_CONFIGURATION_BUFFER, *PIDA_CONFIGURATION_BUFFER;
+
+#define CPQ_IOCTL_IDENTIFY_DRIVER 1
+#define CPQ_IOCTL_IDENTIFY_CONTROLLERS 2
+#define CPQ_IOCTL_PASSTHROUGH 3
+#define CPQ_IOCTL_SCSIPASSTHROUGH 4
+#define CPQ_IOCTL_CONFIGURATION_INFO 5
+
+#define IDA_SIGNATURE "IDAM&P"
+
+
+#pragma pack( )
+
+//
+// The following defines specify the possible Ioctl commands that
+// can be passed to the IDA device driver from the M&P agent.
+//
+
+#define MAP_IOCTL_IDENTIFY_DRIVER \
+ CTL_CODE(FILE_DEVICE_DISK,2048,METHOD_BUFFERED,FILE_ANY_ACCESS)
+
+#define MAP_IOCTL_IDENTIFY_CONTROLLERS \
+ CTL_CODE(FILE_DEVICE_DISK,2049,METHOD_BUFFERED,FILE_ANY_ACCESS)
+
+#define MAP_IOCTL_PASSTHROUGH \
+ CTL_CODE(FILE_DEVICE_DISK,2050,METHOD_OUT_DIRECT,FILE_ANY_ACCESS)
+
+#define MAP_IOCTL_SCSIPASSTHROUGH \
+ CTL_CODE(FILE_DEVICE_DISK,2051,METHOD_OUT_DIRECT,FILE_ANY_ACCESS)
+
+#define MAP_IOCTL_CONFIGURATION_INFO \
+ CTL_CODE(FILE_DEVICE_DISK,2052,METHOD_OUT_DIRECT,FILE_ANY_ACCESS)
+
+#endif //CPQSMNGR
+
+
diff --git a/private/ntos/miniport/compaq/makefile b/private/ntos/miniport/compaq/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/miniport/compaq/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/compaq/pcibios.h b/private/ntos/miniport/compaq/pcibios.h
new file mode 100644
index 000000000..24ad70bc5
--- /dev/null
+++ b/private/ntos/miniport/compaq/pcibios.h
@@ -0,0 +1,27 @@
+/* pci_bios command codes */
+
+#define GENERATE_SPECIAL_CYCLE (unsigned char)0x06
+#define READ_CONFIG_BYTE (unsigned char)0x08
+#define READ_CONFIG_WORD (unsigned char)0x09
+#define READ_CONFIG_DWORD (unsigned char)0x0A
+#define WRITE_CONFIG_BYTE (unsigned char)0x0B
+#define WRITE_CONFIG_WORD (unsigned char)0x0C
+#define WRITE_CONFIG_DWORD (unsigned char)0x0D
+
+#define SUCCESSFUL 0x00
+#define FUNC_NOT_SUPPORTED 0x81
+#define BAD_VENDOR_ID 0x83
+#define DEVICE_NOT_FOUND 0x86
+#define BAD_REGISTER_NUMBER 0x87
+
+/* pci_bios will be call through a pointer */
+/* pci_bios returns 0x00 for sucess and non-zero for failure. */
+/* pci_bios should return the rom int return code for failure. */
+/* pci_bios can or 0x80 with the command for 32 bit calls. */
+
+int pci_bios( unsigned char cmd, /* PCI bios command to perform */
+ unsigned char bus, /* PCI bus number 0...255 */
+ unsigned char device, /* PCI device number 0...31 */
+ unsigned char func, /* PCI function number 0...7 */
+ unsigned char reg, /* PCI register number 0...255 */
+ unsigned long *value ); /* Data value used for command */
diff --git a/private/ntos/miniport/compaq/scsireg.h b/private/ntos/miniport/compaq/scsireg.h
new file mode 100644
index 000000000..66d83f6b9
--- /dev/null
+++ b/private/ntos/miniport/compaq/scsireg.h
@@ -0,0 +1,223 @@
+// (C) Copyright COMPAQ Computer Corporation 1994, All rights reserved.
+//***************************************************************************
+//
+// Module : SCSIREG.H
+//
+// Version: 1.0
+//
+// Author : David Green
+//
+//***************************************************************************
+//
+// Change Log:
+//
+// 06/30/94 DRG - Split SCSI Registry info from CPQNTREG.H
+//
+//****************************************************************************
+
+
+#ifndef _SCSIREG_H
+#define _SCSIREG_H
+
+
+#pragma pack(1)
+
+
+// ***************************************************************************
+//
+// COMPAQ SCSI SUPPORT MIB
+//
+// ***************************************************************************
+
+/* SCSI device types */
+#ifndef CPQ_REG_OTHER
+#define CPQ_REG_OTHER 1
+#endif
+#define SCSI_DEV_TYPE_DISK 2
+#define SCSI_DEV_TYPE_TAPE 3
+#define SCSI_DEV_TYPE_PRINTER 4
+#define SCSI_DEV_TYPE_PROCESSOR 5
+#define SCSI_DEV_TYPE_WORMDRIVE 6
+#define SCSI_DEV_TYPE_CDROM 7
+#define SCSI_DEV_TYPE_SCANNER 8
+#define SCSI_DEV_TYPE_OPTICAL 9
+#define SCSI_DEV_TYPE_JUKEBOX 10
+#define SCSI_DEV_TYPE_COMMDEV 11
+
+/* SCSI data bus width for both the controller & devices */
+// CPQ_REG_OTHER 1
+#define SCSI_WIDTH_NARROW 2
+#define SCSI_WIDTH_WIDE16 3
+
+/* SCSI device locations */
+// CPQ_REG_OTHER 1
+#define SCSI_DEV_LOC_PROLIANT 2
+
+// COMPAQ\SCSI\COMPONENT\DEVICE[xx]
+
+typedef struct _CPQ_SCSI_DEVICE {
+ BYTE devCntlrIndex;
+ BYTE devBusIndex;
+ BYTE devScsiIdIndex;
+ BYTE devType;
+ BYTE devLocation;
+ CHAR devModel[17];
+ CHAR devFWRev[5];
+ CHAR devVendor[9];
+ ULONG devParityErrs;
+ ULONG devPhasErrs;
+ ULONG devSelectTimeouts;
+ ULONG devMsgRejects;
+ ULONG devNegPeriod;
+ // New fields
+ ULONG devNegSpeed;
+ ULONG devPhysWidth;
+ ULONG devNegWidth;
+ BYTE bReserved[16]; // Not in MIB
+} CPQ_SCSI_DEVICE, * pCPQ_SCSI_DEVICE;
+
+
+/* SCSI controller models */
+// CPQ_REG_OTHER 1
+#define SCSI_CNTLR_MODEL_710 2 // c710 EISA
+#define SCSI_CNTLR_MODEL_94 3 // c94 EISA
+#define SCSI_CNTLR_MODEL_810 4 // c810 PCI
+#define SCSI_CNTLR_MODEL_825e 5 // c825 EISA
+#define SCSI_CNTLR_MODEL_825p 6 // c825 PCI
+#define SCSI_CNTLR_MODEL_974p 7 // AM53c974 PCI
+
+/* SCSI controller status */
+// CPQ_REG_OTHER 1
+#define SCSI_CNTLR_STATUS_OK 2
+#define SCSI_CNTLR_STATUS_FAILED 3
+
+// COMPAQ\SCSI\COMPONENT\SCSICNTLR[XX]
+
+typedef struct _CPQ_SCSI_CNTLR {
+ BYTE cntlrIndex;
+ BYTE cntlrBusIndex;
+ BYTE cntlrModel;
+ BYTE cntlrSlot;
+ BYTE cntlrStatus;
+ BYTE cntlrCondition;
+ CHAR cntlrFWVers[5];
+ CHAR cntlrSWVers[5];
+ ULONG cntlrHardResets;
+ ULONG cntlrSoftResets;
+ ULONG cntlrTimeouts;
+ ULONG cntlrBaseIOAddr;
+ BYTE cntlrSerialNumber[16];
+ ULONG cntlrBoardId;
+ ULONG cntlrBoardRevision;
+ ULONG cntlrBoardWidth;
+ BYTE bReserved[16]; // Not in MIB
+} CPQ_SCSI_CNTLR, * pCPQ_SCSI_CNTLR;
+
+
+// This is deprecated, but some code still references it
+
+/* SCSI logical drive fault tolerance values (defined with IDA) */
+// CPQ_REG_OTHER 1
+// FAULT_TOL_NONE 2
+// FAULT_TOL_MIRRORING 3
+// FAULT_TOL_RAID4 4
+// FAULT_TOL_RAID5 5
+
+/* SCSI logical drive status values (defined with IDA) */
+// CPQ_REG_OTHER 1
+// LOG_DRV_OK 2
+// LOG_DRV_FAILED 3
+// LOG_DRV_UNCONFIGURED 4
+// LOG_DRV_RECOVERING 5
+// LOG_DRV_READY_REBUILD 6
+// LOG_DRV_REBUILDING 7
+// LOG_DRV_WRONG_DRIVE 8
+// LOG_DRV_BAD_CONNECT 9
+
+// COMPAQ\SCSI\COMPONENT\LOGDRV[XX]
+
+typedef struct _CPQ_SCSI_LOGICAL {
+ BYTE logDrvCntlrIndex;
+ BYTE logDrvBusIndex;
+ BYTE logDrvIndex;
+ BYTE logDrvFaultTol;
+ BYTE logDrvStatus;
+ BYTE logDrvCondition;
+ ULONG logDrvSize;
+ BYTE logDrvPhyDrvIDs[33];
+} CPQ_SCSI_LOGICAL, * pCPQ_SCSI_LOGICAL;
+
+
+/* SCSI physical drive status */
+// CPQ_REG_OTHER 1
+#define SCSI_PHYS_STATUS_OK 2
+#define SCSI_PHYS_STATUS_FAILED 3
+#define SCSI_PHYS_STATUS_NOT_CONFIGURED 4
+#define SCSI_PHYS_STATUS_BAD_CABLE 5
+#define SCSI_PHYS_STATUS_MISSING_WAS_OK 6
+#define SCSI_PHYS_STATUS_MISSING_WAS_FAILED 7
+
+/* SCSI physical drive statistics preservation */
+// CPQ_REG_OTHER 1
+#define SCSI_PHYS_PRES_NVRAM 2
+#define SCSI_PHYS_PRES_DISK 3
+#define SCSI_PHYS_PRES_NO_CPU 4
+#define SCSI_PHYS_PRES_NO_NVRAM 5
+#define SCSI_PHYS_PRES_NO_DRV 6
+#define SCSI_PHYS_PRES_NO_SW 7
+
+/* Physical drive placement values */
+// CPQ_REG_OTHER 1
+// PHYS_DRV_PLACE_INTERNAL 2
+// PHYS_DRV_PLACE_EXTERNAL 3
+
+/* Physical drive hot plug values */
+// CPQ_REG_OTHER 1
+// PHYS_DRV_HOT_PLUG 2
+// PHYS_DRV_NOT_HOT_PLUG 3
+
+
+// COMPAQ\SCSI\COMPONENT\PHYDRV[XX]
+
+typedef struct _CPQ_SCSI_PHYSICAL {
+ BYTE phyDrvCntlrIndex;
+ BYTE phyDrvBusIndex;
+ BYTE phyDrvIndex;
+ CHAR phyDrvModel[17];
+ CHAR phyDrvFWRev[5];
+ CHAR phyDrvVendor[9];
+ ULONG phyDrvSize;
+ BYTE phyDrvScsiId;
+ BYTE phyDrvStatus;
+ ULONG phyDrvServiceHours;
+ ULONG phyDrvReads;
+ ULONG phyDrvHReads;
+ ULONG phyDrvWrites;
+ ULONG phyDrvHWrites;
+ ULONG phyDrvHardReadErrs;
+ ULONG phyDrvHardWriteErrs;
+ ULONG phyDrvEccCorrReads;
+ ULONG phyDrvRecvReadErrs;
+ ULONG phyDrvRecvWriteErrs;
+ ULONG phyDrvSeekErrs;
+ ULONG phyDrvSpinupTime;
+ ULONG phyDrvUsedRealloc;
+ ULONG phyDrvTimeouts;
+ ULONG phyDrvPostErrs;
+ ULONG phyDrvPostCode;
+ BYTE phyDrvCondition;
+ BYTE phyDrvFuncTest1;
+ BYTE phyDrvFuncTest2;
+ BYTE phyDrvStatsPreserved;
+ CHAR phyDrvSerialNum[13];
+ BYTE phyDrvPlacement;
+ BYTE phyDrvParent;
+ ULONG phyDrvSectorSize;
+ BYTE phyDrvHotPlug;
+ BYTE phyDrvReserved[17]; // Reserved for alignment
+} CPQ_SCSI_PHYSICAL, * pCPQ_SCSI_PHYSICAL;
+
+
+#pragma pack()
+
+#endif
diff --git a/private/ntos/miniport/compaq/sources b/private/ntos/miniport/compaq/sources
new file mode 100644
index 000000000..2682269d9
--- /dev/null
+++ b/private/ntos/miniport/compaq/sources
@@ -0,0 +1,39 @@
+!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=cpqarray
+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=cpqarray.c cpqarray.rc
+