diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/miniport/compaq/cpqarray.c | 3819 | ||||
-rw-r--r-- | private/ntos/miniport/compaq/cpqarray.h | 412 | ||||
-rw-r--r-- | private/ntos/miniport/compaq/cpqarray.rc | 13 | ||||
-rw-r--r-- | private/ntos/miniport/compaq/cpqsczmp.h | 211 | ||||
-rw-r--r-- | private/ntos/miniport/compaq/cpqsmngr.h | 509 | ||||
-rw-r--r-- | private/ntos/miniport/compaq/makefile | 6 | ||||
-rw-r--r-- | private/ntos/miniport/compaq/pcibios.h | 27 | ||||
-rw-r--r-- | private/ntos/miniport/compaq/scsireg.h | 223 | ||||
-rw-r--r-- | private/ntos/miniport/compaq/sources | 39 |
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 + |