-/* $Id: atapi.c,v 1.9 2002/03/04 22:31:06 ekohl Exp $
+/*
+ * ReactOS kernel
+ * Copyright (C) 2001, 2002, 2003, 2004, 2005 ReactOS Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/* $Id$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS ATAPI miniport driver
- * FILE: services/storage/atapi/atapi.c
+ * FILE: drivers/storage/atapi/atapi.c
* PURPOSE: ATAPI miniport driver
* PROGRAMMERS: Eric Kohl (ekohl@rz-online.de)
+ * Hartmut Birr
* REVISIONS:
* 09-09-2001 Created
*/
* - handle removable atapi non-cdrom drives
*/
-// -------------------------------------------------------------------------
+#define ENABLE_PCI
+#define ENABLE_NATIVE_PCI
+#define ENABLE_ISA
+#define ENABLE_DMA
-#include <ddk/ntddk.h>
+// -------------------------------------------------------------------------
-#include "../include/srb.h"
-#include "../include/scsi.h"
-#include "../include/ntddscsi.h"
+#include <ntddk.h>
+#include <srb.h>
+#include <scsi.h>
+#include <ntddscsi.h>
+#include <ntdddisk.h>
+#include <ntddstor.h>
#include "atapi.h"
#define NDEBUG
#include <debug.h>
-#define VERSION "V0.0.1"
+#define VERSION "0.0.1"
+
+NTSTATUS NTAPI
+DriverEntry(IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath);
// ------------------------------------------------------- File Static Data
+#ifdef ENABLE_DMA
+typedef struct _PRD
+{
+ ULONG PhysAddress;
+ ULONG Length;
+} PRD, *PPRD;
+#endif
+
// ATAPI_MINIPORT_EXTENSION
//
// DESCRIPTION:
typedef struct _ATAPI_MINIPORT_EXTENSION
{
IDE_DRIVE_IDENTIFY DeviceParams[2];
- BOOLEAN DevicePresent[2];
- BOOLEAN DeviceAtapi[2];
+ ULONG DeviceFlags[2];
+ ULONG TransferSize[2];
ULONG CommandPortBase;
ULONG ControlPortBase;
+ ULONG BusMasterRegisterBase;
- BOOLEAN ExpectingInterrupt;
PSCSI_REQUEST_BLOCK CurrentSrb;
- PUSHORT DataBuffer;
+ PUCHAR DataBuffer;
+ ULONG DataTransferLength;
+
+ BOOLEAN (FASTCALL *Handler)(IN struct _ATAPI_MINIPORT_EXTENSION* DevExt);
+#ifdef ENABLE_DMA
+ BOOLEAN UseDma;
+ ULONG PRDCount;
+ ULONG PRDMaxCount;
+ PPRD PRDTable;
+ SCSI_PHYSICAL_ADDRESS PRDTablePhysicalAddress;
+#endif
} ATAPI_MINIPORT_EXTENSION, *PATAPI_MINIPORT_EXTENSION;
+/* DeviceFlags */
+#define DEVICE_PRESENT 0x00000001
+#define DEVICE_ATAPI 0x00000002
+#define DEVICE_MULTI_SECTOR_CMD 0x00000004
+#define DEVICE_DWORD_IO 0x00000008
+#define DEVICE_48BIT_ADDRESS 0x00000010
+#define DEVICE_MEDIA_STATUS 0x00000020
+#define DEVICE_DMA_CMD 0x00000040
+#define DEVICE_NO_FLUSH 0x00000080
+
typedef struct _UNIT_EXTENSION
{
ULONG Dummy;
} UNIT_EXTENSION, *PUNIT_EXTENSION;
+PCI_SLOT_NUMBER LastSlotNumber;
+
+#ifdef ENABLE_NATIVE_PCI
+typedef struct _PCI_NATIVE_CONTROLLER
+{
+ USHORT VendorID;
+ USHORT DeviceID;
+}
+PCI_NATIVE_CONTROLLER, *PPCI_NATIVE_CONTROLLER;
+
+PCI_NATIVE_CONTROLLER const PciNativeController[] =
+{
+ {
+ 0x105A, // Promise
+ 0x4D68, // PDC20268, Ultra100TX2
+ },
+ {
+ 0x105A, // Promise
+ 0x4D30, // PDC20267, Ultra100
+ }
+};
+#endif
+
// ----------------------------------------------- Discardable Declarations
#ifdef ALLOC_PRAGMA
-// make the initialization routines discardable, so that they
+// make the initialization routines discardable, so that they
// don't waste space
#pragma alloc_text(init, DriverEntry)
-#pragma alloc_text(init, IDECreateController)
-#pragma alloc_text(init, IDEPolledRead)
// make the PASSIVE_LEVEL routines pageable, so that they don't
// waste nonpaged memory
-#pragma alloc_text(page, IDEShutdown)
-#pragma alloc_text(page, IDEDispatchOpenClose)
-#pragma alloc_text(page, IDEDispatchRead)
-#pragma alloc_text(page, IDEDispatchWrite)
-
#endif /* ALLOC_PRAGMA */
// ---------------------------------------------------- Forward Declarations
+#ifdef ENABLE_DMA
+static BOOLEAN
+AtapiInitDma(PATAPI_MINIPORT_EXTENSION DevExt,
+ PSCSI_REQUEST_BLOCK Srb,
+ UCHAR cmd);
+#endif
+
static ULONG STDCALL
AtapiFindCompatiblePciController(PVOID DeviceExtension,
PVOID HwContext,
AtapiStartIo(IN PVOID DeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb);
+static VOID
+AtapiExecuteCommand(PATAPI_MINIPORT_EXTENSION DevExt,
+ UCHAR command,
+ BOOLEAN (FASTCALL *Handler)(PATAPI_MINIPORT_EXTENSION));
+
static BOOLEAN STDCALL
AtapiInterrupt(IN PVOID DeviceExtension);
+static BOOLEAN FASTCALL
+AtapiNoDataInterrupt(PATAPI_MINIPORT_EXTENSION DevExt);
+
+static BOOLEAN FASTCALL
+AtapiPacketInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt);
+
+static BOOLEAN FASTCALL
+AtapiSmartInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt);
+
+static BOOLEAN FASTCALL
+AtapiReadInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt);
+
+#ifdef ENABLE_DMA
+static BOOLEAN FASTCALL
+AtapiDmaPacketInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt);
+
+static BOOLEAN FASTCALL
+AtapiDmaInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt);
+#endif
+
+static BOOLEAN FASTCALL
+AtapiWriteInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt);
+
static BOOLEAN
AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
PPORT_CONFIGURATION_INFORMATION ConfigInfo);
OUT PIDE_DRIVE_IDENTIFY DrvParms);
static BOOLEAN
-IDEResetController(IN WORD CommandPort,
- IN WORD ControlPort);
-
-static int
-AtapiPolledRead(IN WORD CommandPort,
- IN WORD ControlPort,
- IN BYTE PreComp,
- IN BYTE SectorCnt,
- IN BYTE SectorNum,
- IN BYTE CylinderLow,
- IN BYTE CylinderHigh,
- IN BYTE DrvHead,
- IN BYTE Command,
- OUT BYTE *Buffer);
-
-
+AtapiPolledRead(IN ULONG CommandPort,
+ IN ULONG ControlPort,
+ IN UCHAR PreComp,
+ IN UCHAR SectorCnt,
+ IN UCHAR SectorNum,
+ IN UCHAR CylinderLow,
+ IN UCHAR CylinderHigh,
+ IN UCHAR DrvHead,
+ IN UCHAR Command,
+ OUT PUCHAR Buffer);
static ULONG
AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb);
+static ULONG
+AtapiSendSmartCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb);
+
static ULONG
AtapiInquiry(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb);
AtapiReadWrite(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb);
+static ULONG
+AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension,
+ PSCSI_REQUEST_BLOCK Srb);
+
+static ULONG
+AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension,
+ PSCSI_REQUEST_BLOCK Srb);
+
+static UCHAR
+AtapiErrorToScsi(PVOID DeviceExtension,
+ PSCSI_REQUEST_BLOCK Srb);
+
+static VOID
+AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb);
+
// ---------------------------------------------------------------- Inlines
void
-IDESwapBytePairs(char *Buf,
+IDESwapBytePairs(UCHAR *Buf,
int Cnt)
{
- char t;
+ UCHAR t;
int i;
for (i = 0; i < Cnt; i += 2)
}
-static BOOLEAN
-IdeFindDrive(int Address,
- int DriveIdx)
-{
- ULONG Cyl;
-
- DPRINT1("IdeFindDrive(Address %lx DriveIdx %lu) called!\n", Address, DriveIdx);
-
- IDEWriteDriveHead(Address, IDE_DH_FIXED | (DriveIdx ? IDE_DH_DRV1 : 0));
- IDEWriteCylinderLow(Address, 0x30);
-
- Cyl = IDEReadCylinderLow(Address);
- DPRINT1("Cylinder %lx\n", Cyl);
-
-
- DPRINT1("IdeFindDrive() done!\n");
-// for(;;);
- return(Cyl == 0x30);
-}
-
-
// ------------------------------------------------------- Public Interface
// DriverEntry
//
// DESCRIPTION:
-// This function initializes the driver, locates and claims
+// This function initializes the driver, locates and claims
// hardware resources, and creates various NT objects needed
// to process I/O requests.
//
// ARGUMENTS:
// IN PDRIVER_OBJECT DriverObject System allocated Driver Object
// for this driver
-// IN PUNICODE_STRING RegistryPath Name of registry driver service
+// IN PUNICODE_STRING RegistryPath Name of registry driver service
// key
//
// RETURNS:
// NTSTATUS
-STDCALL NTSTATUS
+NTSTATUS NTAPI
DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
HW_INITIALIZATION_DATA InitData;
NTSTATUS Status;
- DbgPrint("ATAPI Driver %s\n", VERSION);
+ DPRINT("ATAPI Driver %s\n", VERSION);
+ DPRINT("RegistryPath: '%wZ'\n", RegistryPath);
/* Initialize data structure */
RtlZeroMemory(&InitData,
InitData.MapBuffers = TRUE;
/* Search the PCI bus for compatibility mode ide controllers */
+#ifdef ENABLE_PCI
+ InitData.NeedPhysicalAddresses = TRUE;
+
InitData.HwFindAdapter = AtapiFindCompatiblePciController;
- InitData.NumberOfAccessRanges = 2;
+ InitData.NumberOfAccessRanges = 3;
InitData.AdapterInterfaceType = PCIBus;
InitData.VendorId = NULL;
NULL);
// if (newStatus < statusToReturn)
// statusToReturn = newStatus;
+#endif
- /* Search the ISA bus for ide controllers */
-#if 0
- InitData.HwFindAdapter = AtapiFindIsaBusController;
- InitData.NumberOfAccessRanges = 2;
- InitData.AdapterInterfaceType = Isa;
+ /* Search the PCI bus for all ide controllers */
+#ifdef ENABLE_NATIVE_PCI
+ InitData.NeedPhysicalAddresses = TRUE;
- InitData.VendorId = NULL;
+ InitData.HwFindAdapter = AtapiFindNativePciController;
+ InitData.NumberOfAccessRanges = 3;
+ InitData.AdapterInterfaceType = PCIBus;
+
+ InitData.VendorId = 0;
InitData.VendorIdLength = 0;
- InitData.DeviceId = NULL;
+ InitData.DeviceId = 0;
InitData.DeviceIdLength = 0;
+ LastSlotNumber.u.AsULONG = 0xFFFFFFFF;
+
Status = ScsiPortInitialize(DriverObject,
RegistryPath,
&InitData,
NULL);
-// if (newStatus < statusToReturn)
-// statusToReturn = newStatus;
+// if (newStatus < statusToReturn)
+// statusToReturn = newStatus;
#endif
- /* Search the PCI bus for native mode ide controllers */
-#if 0
- InitData.HwFindAdapter = AtapiFindNativePciController;
+ /* Search the ISA bus for ide controllers */
+#ifdef ENABLE_ISA
+ InitData.HwFindAdapter = AtapiFindIsaBusController;
InitData.NumberOfAccessRanges = 2;
- InitData.AdapterInterfaceType = PCIBus;
+ InitData.AdapterInterfaceType = Isa;
InitData.VendorId = NULL;
InitData.VendorIdLength = 0;
Status = ScsiPortInitialize(DriverObject,
RegistryPath,
&InitData,
- (PVOID)i);
-// if (newStatus < statusToReturn)
-// statusToReturn = newStatus;
+ NULL);
+// if (newStatus < statusToReturn)
+// statusToReturn = newStatus;
#endif
- DPRINT1( "Returning from DriverEntry\n" );
+ DPRINT("Returning from DriverEntry\n");
return(Status);
}
+BOOLEAN
+AtapiClaimHwResources(PATAPI_MINIPORT_EXTENSION DevExt,
+ PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ INTERFACE_TYPE InterfaceType,
+ ULONG CommandPortBase,
+ ULONG ControlPortBase,
+ ULONG BusMasterPortBase,
+ ULONG InterruptVector)
+{
+ SCSI_PHYSICAL_ADDRESS IoAddress;
+ PVOID IoBase;
+#ifdef ENABLE_DMA
+ ULONG Length;
+#endif
+ IoAddress = ScsiPortConvertUlongToPhysicalAddress(CommandPortBase);
+ IoBase = ScsiPortGetDeviceBase((PVOID)DevExt,
+ InterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ IoAddress,
+ 8,
+ TRUE);
+ if (IoBase == NULL)
+ {
+ return FALSE;
+ }
+ DevExt->Handler = NULL;
+ DevExt->CommandPortBase = (ULONG)IoBase;
+ (*ConfigInfo->AccessRanges)[0].RangeStart = IoAddress;
+ (*ConfigInfo->AccessRanges)[0].RangeLength = 8;
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+ if (ControlPortBase)
+ {
+ IoAddress = ScsiPortConvertUlongToPhysicalAddress(ControlPortBase + 2);
+ IoBase = ScsiPortGetDeviceBase((PVOID)DevExt,
+ InterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ IoAddress,
+ 1,
+ TRUE);
+ if (IoBase == NULL)
+ {
+ ScsiPortFreeDeviceBase((PVOID)DevExt,
+ (PVOID)DevExt->CommandPortBase);
+ return FALSE;
+ }
+ DevExt->ControlPortBase = (ULONG)IoBase;
+ (*ConfigInfo->AccessRanges)[1].RangeStart = IoAddress;
+ (*ConfigInfo->AccessRanges)[1].RangeLength = 1;
+ (*ConfigInfo->AccessRanges)[1].RangeInMemory = FALSE;
+ }
+ if (BusMasterPortBase)
+ {
+ IoAddress = ScsiPortConvertUlongToPhysicalAddress(BusMasterPortBase);
+ IoBase = ScsiPortGetDeviceBase((PVOID)DevExt,
+ InterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ IoAddress,
+ 8,
+ TRUE);
+ if (IoBase == NULL)
+ {
+ ScsiPortFreeDeviceBase((PVOID)DevExt, (PVOID)DevExt->CommandPortBase);
+ ScsiPortFreeDeviceBase((PVOID)DevExt, (PVOID)DevExt->ControlPortBase);
+ return FALSE;
+ }
+ DevExt->BusMasterRegisterBase = (ULONG)IoBase;
+ (*ConfigInfo->AccessRanges)[2].RangeStart = IoAddress;
+ (*ConfigInfo->AccessRanges)[2].RangeLength = 8;
+ (*ConfigInfo->AccessRanges)[2].RangeInMemory = FALSE;
+#ifdef ENABLE_DMA
+// ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE;
+// ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE;
+ ConfigInfo->DmaWidth = Width32Bits;
+// ConfigInfo->DmaSpeed = Compatible;
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+ ConfigInfo->NumberOfPhysicalBreaks = 0x10000 / PAGE_SIZE + 1;
+ ConfigInfo->Dma32BitAddresses = TRUE;
+ ConfigInfo->NeedPhysicalAddresses = TRUE;
+ ConfigInfo->MapBuffers = TRUE;
+
+ DevExt->PRDMaxCount = PAGE_SIZE / sizeof(PRD);
+ DevExt->PRDTable = ScsiPortGetUncachedExtension(DevExt, ConfigInfo, sizeof(PRD) * DevExt->PRDMaxCount);
+ if (DevExt->PRDTable != NULL)
+ {
+ DevExt->PRDTablePhysicalAddress = ScsiPortGetPhysicalAddress(DevExt, NULL, DevExt->PRDTable, &Length);
+ }
+ if (DevExt->PRDTable == NULL ||
+ DevExt->PRDTablePhysicalAddress.QuadPart == 0LL ||
+ Length < sizeof(PRD) * DevExt->PRDMaxCount)
+ {
+ ScsiPortFreeDeviceBase((PVOID)DevExt, (PVOID)DevExt->CommandPortBase);
+ ScsiPortFreeDeviceBase((PVOID)DevExt, (PVOID)DevExt->ControlPortBase);
+ ScsiPortFreeDeviceBase((PVOID)DevExt, (PVOID)DevExt->BusMasterRegisterBase);
+ return FALSE;
+ }
+#endif
+ }
+ ConfigInfo->BusInterruptLevel = InterruptVector;
+ ConfigInfo->BusInterruptVector = InterruptVector;
+ ConfigInfo->InterruptMode = (InterfaceType == Isa) ? Latched : LevelSensitive;
+
+ if ((CommandPortBase == 0x1F0 || ControlPortBase == 0x3F4) && !ConfigInfo->AtdiskPrimaryClaimed)
+ {
+ ConfigInfo->AtdiskPrimaryClaimed = TRUE;
+ }
+ if ((CommandPortBase == 0x170 || ControlPortBase == 0x374) && !ConfigInfo->AtdiskSecondaryClaimed)
+ {
+ ConfigInfo->AtdiskSecondaryClaimed = TRUE;
+ }
+ return TRUE;
+}
+
+
+#ifdef ENABLE_PCI
static ULONG STDCALL
AtapiFindCompatiblePciController(PVOID DeviceExtension,
PVOID HwContext,
PCI_SLOT_NUMBER SlotNumber;
PCI_COMMON_CONFIG PciConfig;
ULONG DataSize;
+ ULONG StartDeviceNumber;
+ ULONG DeviceNumber;
+ ULONG StartFunctionNumber;
ULONG FunctionNumber;
BOOLEAN ChannelFound;
BOOLEAN DeviceFound;
+ ULONG BusMasterBasePort = 0;
DPRINT("AtapiFindCompatiblePciController() Bus: %lu Slot: %lu\n",
ConfigInfo->SystemIoBusNumber,
ConfigInfo->AtdiskSecondaryClaimed == TRUE)
return(SP_RETURN_NOT_FOUND);
-
- SlotNumber.u.AsULONG = 0;
- for (FunctionNumber = 0 /*ConfigInfo->SlotNumber*/; FunctionNumber < 256; FunctionNumber++)
- {
-// SlotNumber.u.bits.FunctionNumber = FunctionNumber;
-// SlotNumber.u.AsULONG = (FunctionNumber & 0x07);
- SlotNumber.u.AsULONG = FunctionNumber;
-
- ChannelFound = FALSE;
- DeviceFound = FALSE;
-
- DataSize = ScsiPortGetBusData(DeviceExtension,
- PCIConfiguration,
- 0,
- SlotNumber.u.AsULONG,
- &PciConfig,
- sizeof(PCI_COMMON_CONFIG));
-// if (DataSize != sizeof(PCI_COMMON_CONFIG) ||
-// PciConfig.VendorID == PCI_INVALID_VENDORID)
- if (DataSize == 0)
+ SlotNumber.u.AsULONG = ConfigInfo->SlotNumber;
+ StartDeviceNumber = SlotNumber.u.bits.DeviceNumber;
+ StartFunctionNumber = SlotNumber.u.bits.FunctionNumber;
+ for (DeviceNumber = StartDeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
+ {
+ SlotNumber.u.bits.DeviceNumber = DeviceNumber;
+ for (FunctionNumber = StartFunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
+ {
+ SlotNumber.u.bits.FunctionNumber = FunctionNumber;
+ ChannelFound = FALSE;
+ DeviceFound = FALSE;
+
+ DataSize = ScsiPortGetBusData(DeviceExtension,
+ PCIConfiguration,
+ ConfigInfo->SystemIoBusNumber,
+ SlotNumber.u.AsULONG,
+ &PciConfig,
+ PCI_COMMON_HDR_LENGTH);
+ if (DataSize != PCI_COMMON_HDR_LENGTH)
{
-// if ((SlotNumber.u.AsULONG & 0x07) == 0)
-// return(SP_RETURN_ERROR); /* No bus found */
-
- continue;
-// return(SP_RETURN_ERROR);
+ if (FunctionNumber == 0)
+ {
+ break;
+ }
+ else
+ {
+ continue;
+ }
}
- if (PciConfig.BaseClass == 0x01 &&
- PciConfig.SubClass == 0x01) // &&
-// (PciConfig.ProgIf & 0x05) == 0)
+ DPRINT("%x %x\n", PciConfig.BaseClass, PciConfig.SubClass);
+ if (PciConfig.BaseClass == 0x01 &&
+ PciConfig.SubClass == 0x01) // &&
+// (PciConfig.ProgIf & 0x05) == 0)
{
- /* both channels are in compatibility mode */
- DPRINT1("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
- ConfigInfo->SystemIoBusNumber,
-// SlotNumber.u.AsULONG >> 3,
-// SlotNumber.u.AsULONG & 0x07,
- SlotNumber.u.bits.DeviceNumber,
- SlotNumber.u.bits.FunctionNumber,
- PciConfig.VendorID,
- PciConfig.DeviceID);
- DPRINT("ProgIF 0x%02hx\n", PciConfig.ProgIf);
-
- DPRINT1("Found IDE controller in compatibility mode!\n");
-
- ConfigInfo->NumberOfBuses = 1;
- ConfigInfo->MaximumNumberOfTargets = 2;
- ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
-
- if (ConfigInfo->AtdiskPrimaryClaimed == FALSE)
- {
+ /* both channels are in compatibility mode */
+ DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
+ ConfigInfo->SystemIoBusNumber,
+ SlotNumber.u.bits.DeviceNumber,
+ SlotNumber.u.bits.FunctionNumber,
+ PciConfig.VendorID,
+ PciConfig.DeviceID);
+ DPRINT("ProgIF 0x%02hx\n", PciConfig.ProgIf);
+
+ DPRINT("Found IDE controller in compatibility mode!\n");
+
+ ConfigInfo->NumberOfBuses = 1;
+ ConfigInfo->MaximumNumberOfTargets = 2;
+ ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
+
+ if (PciConfig.ProgIf & 0x80)
+ {
+ DPRINT("Found IDE Bus Master controller!\n");
+ if (PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_SPACE)
+ {
+ BusMasterBasePort = PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_ADDRESS_MASK;
+ DPRINT(" IDE Bus Master Registers at IO %lx\n", BusMasterBasePort);
+ }
+ }
+ if (ConfigInfo->AtdiskPrimaryClaimed == FALSE)
+ {
/* Both channels unclaimed: Claim primary channel */
- DPRINT1("Primary channel!\n");
-
- DevExt->CommandPortBase = 0x01F0;
- DevExt->ControlPortBase = 0x03F6;
-
- ConfigInfo->BusInterruptLevel = 14;
- ConfigInfo->BusInterruptVector = 14;
- ConfigInfo->InterruptMode = LevelSensitive;
-
- ConfigInfo->AccessRanges[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x01F0);
- ConfigInfo->AccessRanges[0].RangeLength = 8;
- ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
-
- ConfigInfo->AccessRanges[1].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x03F6);
- ConfigInfo->AccessRanges[1].RangeLength = 1;
- ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
-
- ConfigInfo->AtdiskPrimaryClaimed = TRUE;
- ChannelFound = TRUE;
- *Again = TRUE;
- }
- else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
- {
+ DPRINT("Primary channel!\n");
+ ChannelFound = AtapiClaimHwResources(DevExt,
+ ConfigInfo,
+ PCIBus,
+ 0x1F0,
+ 0x3F4,
+ BusMasterBasePort,
+ 14);
+ *Again = TRUE;
+ }
+ else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
+ {
/* Primary channel already claimed: claim secondary channel */
- DPRINT1("Secondary channel!\n");
-
- DevExt->CommandPortBase = 0x0170;
- DevExt->ControlPortBase = 0x0376;
-
- ConfigInfo->BusInterruptLevel = 15;
- ConfigInfo->BusInterruptVector = 15;
- ConfigInfo->InterruptMode = LevelSensitive;
-
- ConfigInfo->AccessRanges[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x0170);
- ConfigInfo->AccessRanges[0].RangeLength = 8;
- ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
-
- ConfigInfo->AccessRanges[1].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x0376);
- ConfigInfo->AccessRanges[1].RangeLength = 1;
- ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
-
- ConfigInfo->AtdiskSecondaryClaimed = TRUE;
- ChannelFound = TRUE;
+ DPRINT("Secondary channel!\n");
+
+ ChannelFound = AtapiClaimHwResources(DevExt,
+ ConfigInfo,
+ PCIBus,
+ 0x170,
+ 0x374,
+ BusMasterBasePort ? BusMasterBasePort + 8 : 0,
+ 15);
*Again = FALSE;
- }
-
- /* Find attached devices */
- if (ChannelFound == TRUE)
- {
- DeviceFound = AtapiFindDevices(DevExt,
- ConfigInfo);
- }
- DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
- return(SP_RETURN_FOUND);
- }
- }
-
+ }
+ /* Find attached devices */
+ if (ChannelFound)
+ {
+ DeviceFound = AtapiFindDevices(DevExt, ConfigInfo);
+ ConfigInfo->SlotNumber = SlotNumber.u.AsULONG;
+ DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
+ return(SP_RETURN_FOUND);
+ }
+ }
+ if (FunctionNumber == 0 && !(PciConfig.HeaderType & PCI_MULTIFUNCTION))
+ {
+ break;
+ }
+ }
+ StartFunctionNumber = 0;
+ }
DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_NOT_FOUND\n");
return(SP_RETURN_NOT_FOUND);
}
+#endif
+#ifdef ENABLE_ISA
static ULONG STDCALL
AtapiFindIsaBusController(PVOID DeviceExtension,
PVOID HwContext,
PBOOLEAN Again)
{
PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
+ BOOLEAN ChannelFound = FALSE;
+ BOOLEAN DeviceFound = FALSE;
DPRINT("AtapiFindIsaBusController() called!\n");
*Again = FALSE;
- if (ConfigInfo->AtdiskPrimaryClaimed == TRUE)
- {
- DPRINT("Primary IDE controller already claimed!\n");
+ ConfigInfo->NumberOfBuses = 1;
+ ConfigInfo->MaximumNumberOfTargets = 2;
+ ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
+ if (ConfigInfo->AtdiskPrimaryClaimed == FALSE)
+ {
+ /* Both channels unclaimed: Claim primary channel */
+ DPRINT("Primary channel!\n");
+
+ ChannelFound = AtapiClaimHwResources(DevExt,
+ ConfigInfo,
+ Isa,
+ 0x1F0,
+ 0x3F4,
+ 0,
+ 14);
+ *Again = TRUE;
}
-
- if (ConfigInfo->AtdiskSecondaryClaimed == TRUE)
+ else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
{
- DPRINT("Secondary IDE controller already claimed!\n");
-
+ /* Primary channel already claimed: claim secondary channel */
+ DPRINT("Secondary channel!\n");
+
+ ChannelFound = AtapiClaimHwResources(DevExt,
+ ConfigInfo,
+ Isa,
+ 0x170,
+ 0x374,
+ 0,
+ 15);
+ *Again = FALSE;
+ }
+ else
+ {
+ DPRINT("AtapiFindIsaBusController() both channels claimed. Returns: SP_RETURN_NOT_FOUND\n");
+ *Again = FALSE;
+ return(SP_RETURN_NOT_FOUND);
}
- DPRINT("AtapiFindIsaBusController() done!\n");
-
- return(SP_RETURN_NOT_FOUND);
+ /* Find attached devices */
+ if (ChannelFound)
+ {
+ DeviceFound = AtapiFindDevices(DevExt,
+ ConfigInfo);
+ DPRINT("AtapiFindIsaBusController() returns: SP_RETURN_FOUND\n");
+ return(SP_RETURN_FOUND);
+ }
+ *Again = FALSE;
+ return SP_RETURN_NOT_FOUND;
}
+#endif
+#ifdef ENABLE_NATIVE_PCI
static ULONG STDCALL
AtapiFindNativePciController(PVOID DeviceExtension,
PVOID HwContext,
PBOOLEAN Again)
{
PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
+ PCI_COMMON_CONFIG PciConfig;
+ PCI_SLOT_NUMBER SlotNumber;
+ ULONG DataSize;
+ ULONG DeviceNumber;
+ ULONG StartDeviceNumber;
+ ULONG FunctionNumber;
+ ULONG StartFunctionNumber;
+ ULONG BusMasterBasePort;
+ ULONG Count;
+ BOOLEAN ChannelFound;
DPRINT("AtapiFindNativePciController() called!\n");
+ SlotNumber.u.AsULONG = ConfigInfo->SlotNumber;
+ StartDeviceNumber = SlotNumber.u.bits.DeviceNumber;
+ StartFunctionNumber = SlotNumber.u.bits.FunctionNumber;
+ for (DeviceNumber = StartDeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
+ {
+ SlotNumber.u.bits.DeviceNumber = DeviceNumber;
+ for (FunctionNumber = StartFunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
+ {
+ SlotNumber.u.bits.FunctionNumber = FunctionNumber;
+ DataSize = ScsiPortGetBusData(DeviceExtension,
+ PCIConfiguration,
+ ConfigInfo->SystemIoBusNumber,
+ SlotNumber.u.AsULONG,
+ &PciConfig,
+ PCI_COMMON_HDR_LENGTH);
+ if (DataSize != PCI_COMMON_HDR_LENGTH)
+ {
+ break;
+ }
+ for (Count = 0; Count < sizeof(PciNativeController)/sizeof(PCI_NATIVE_CONTROLLER); Count++)
+ {
+ if (PciConfig.VendorID == PciNativeController[Count].VendorID &&
+ PciConfig.DeviceID == PciNativeController[Count].DeviceID)
+ {
+ break;
+ }
+ }
+ if (Count < sizeof(PciNativeController)/sizeof(PCI_NATIVE_CONTROLLER))
+ {
+ /* We have found a known native pci ide controller */
+ if ((PciConfig.ProgIf & 0x80) && (PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_SPACE))
+ {
+ DPRINT("Found IDE Bus Master controller!\n");
+ BusMasterBasePort = PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_ADDRESS_MASK;
+ DPRINT(" IDE Bus Master Registers at IO %lx\n", BusMasterBasePort);
+ }
+ else
+ {
+ BusMasterBasePort = 0;
+ }
+
+ DPRINT("VendorID: %04x, DeviceID: %04x\n", PciConfig.VendorID, PciConfig.DeviceID);
+ ConfigInfo->NumberOfBuses = 1;
+ ConfigInfo->MaximumNumberOfTargets = 2;
+ ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
+
+ /* FIXME:
+ We must not store and use the last tested slot number. If there is a recall
+ to the some device and we will claim the primary channel again than the call
+ to ScsiPortGetDeviceBase in AtapiClaimHwResource will fail and we can try to
+ claim the secondary channel.
+ */
+ ChannelFound = FALSE;
+ if (LastSlotNumber.u.AsULONG != SlotNumber.u.AsULONG)
+ {
+ /* try to claim primary channel */
+ if ((PciConfig.u.type0.BaseAddresses[0] & PCI_ADDRESS_IO_SPACE) &&
+ (PciConfig.u.type0.BaseAddresses[1] & PCI_ADDRESS_IO_SPACE))
+ {
+ /* primary channel is enabled */
+ ChannelFound = AtapiClaimHwResources(DevExt,
+ ConfigInfo,
+ PCIBus,
+ PciConfig.u.type0.BaseAddresses[0] & PCI_ADDRESS_IO_ADDRESS_MASK,
+ PciConfig.u.type0.BaseAddresses[1] & PCI_ADDRESS_IO_ADDRESS_MASK,
+ BusMasterBasePort,
+ PciConfig.u.type0.InterruptLine);
+ if (ChannelFound)
+ {
+ AtapiFindDevices(DevExt, ConfigInfo);
+ *Again = TRUE;
+ ConfigInfo->SlotNumber = LastSlotNumber.u.AsULONG = SlotNumber.u.AsULONG;
+ return SP_RETURN_FOUND;
+ }
+ }
+ }
+ if (!ChannelFound)
+ {
+ /* try to claim secondary channel */
+ if ((PciConfig.u.type0.BaseAddresses[2] & PCI_ADDRESS_IO_SPACE) &&
+ (PciConfig.u.type0.BaseAddresses[3] & PCI_ADDRESS_IO_SPACE))
+ {
+ /* secondary channel is enabled */
+ ChannelFound = AtapiClaimHwResources(DevExt,
+ ConfigInfo,
+ PCIBus,
+ PciConfig.u.type0.BaseAddresses[2] & PCI_ADDRESS_IO_ADDRESS_MASK,
+ PciConfig.u.type0.BaseAddresses[3] & PCI_ADDRESS_IO_ADDRESS_MASK,
+ BusMasterBasePort ? BusMasterBasePort + 8 : 0,
+ PciConfig.u.type0.InterruptLine);
+ if (ChannelFound)
+ {
+ AtapiFindDevices(DevExt, ConfigInfo);
+ *Again = FALSE;
+ LastSlotNumber.u.AsULONG = 0xFFFFFFFF;
+ return SP_RETURN_FOUND;
+ }
+ }
+ }
+ }
+ }
+ StartFunctionNumber = 0;
+ }
*Again = FALSE;
-
+ LastSlotNumber.u.AsULONG = 0xFFFFFFFF;
DPRINT("AtapiFindNativePciController() done!\n");
return(SP_RETURN_NOT_FOUND);
}
+#endif
static BOOLEAN STDCALL
PATAPI_MINIPORT_EXTENSION DevExt;
ULONG Result;
- DPRINT1("AtapiStartIo() called\n");
+ DPRINT("AtapiStartIo() called\n");
DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
{
case SRB_FUNCTION_EXECUTE_SCSI:
DevExt->CurrentSrb = Srb;
- if (DevExt->DeviceAtapi[Srb->TargetId] == TRUE)
+ if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI)
{
Result = AtapiSendAtapiCommand(DevExt,
Srb);
}
break;
+ case SRB_FUNCTION_ABORT_COMMAND:
+ if (DevExt->CurrentSrb != NULL)
+ {
+ Result = SRB_STATUS_ABORT_FAILED;
+ }
+ else
+ {
+ Result = SRB_STATUS_SUCCESS;
+ }
+ break;
+
+ case SRB_FUNCTION_IO_CONTROL:
+ {
+ PSRB_IO_CONTROL SrbIoControl = (PSRB_IO_CONTROL)Srb->DataBuffer;
+ if (Srb->DataTransferLength < sizeof(SRB_IO_CONTROL) ||
+ Srb->DataTransferLength < SrbIoControl->Length + sizeof(SRB_IO_CONTROL))
+ {
+ Result = SRB_STATUS_INVALID_REQUEST;
+ }
+ else
+ {
+ if (!_strnicmp((char*)SrbIoControl->Signature, "ScsiDisk", 8))
+ {
+ switch (SrbIoControl->ControlCode)
+ {
+ default:
+ Result = SRB_STATUS_INVALID_REQUEST;
+ break;
+
+ case IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE:
+ case IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES:
+ case IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS:
+ case IOCTL_SCSI_MINIPORT_ENABLE_SMART:
+ case IOCTL_SCSI_MINIPORT_DISABLE_SMART:
+ case IOCTL_SCSI_MINIPORT_RETURN_STATUS:
+ case IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS:
+ case IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS:
+ case IOCTL_SCSI_MINIPORT_READ_SMART_LOG:
+#if 0
+ case IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG:
+#endif
+ Result = AtapiSendSmartCommand(DevExt, Srb);
+ break;
+
+ case IOCTL_SCSI_MINIPORT_SMART_VERSION:
+ {
+ GETVERSIONINPARAMS Version;
+ ULONG i;
+
+ DPRINT("IOCTL_SCSI_MINIPORT_SMART_VERSION\n");
+
+ RtlZeroMemory(&Version, sizeof(GETVERSIONINPARAMS));
+ Version.bVersion = 1;
+ Version.bRevision = 1;
+ for (i = 0; i < 2; i++)
+ {
+ switch (DevExt->DeviceFlags[i] & (DEVICE_PRESENT|DEVICE_ATAPI))
+ {
+ case DEVICE_PRESENT:
+ Version.bIDEDeviceMap |= 0x01 << i;
+ break;
+/*
+ case DEVICE_PRESENT|DEVICE_ATAPI:
+ Version.bIDEDeviceMap |= 0x11 << i;
+ break;
+*/
+ }
+ }
+ Version.fCapabilities = CAP_ATA_ID_CMD/*|CAP_ATAPI_ID_CMD|CAP_SMART_CMD*/;
+ SrbIoControl->Length = min(sizeof(GETVERSIONINPARAMS), Srb->DataTransferLength - sizeof(SRB_IO_CONTROL));
+ memcpy(SrbIoControl + 1, &Version, SrbIoControl->Length);
+ Result = SRB_STATUS_SUCCESS;
+ break;
+ }
+
+ case IOCTL_SCSI_MINIPORT_IDENTIFY:
+ {
+ SENDCMDOUTPARAMS OutParams;
+ SENDCMDINPARAMS InParams = *(PSENDCMDINPARAMS)(SrbIoControl + 1);
+
+ DPRINT("IOCTL_SCSI_MINIPORT_IDENTIFY\n");
+
+ if (Srb->DataTransferLength < sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1)
+ {
+ Result = SRB_STATUS_INVALID_REQUEST;
+ break;
+ }
+
+ RtlZeroMemory(&OutParams, sizeof(SENDCMDOUTPARAMS));
+
+ if (InParams.irDriveRegs.bCommandReg != IDE_CMD_IDENT_ATA_DRV)
+ {
+ DPRINT("bCommandReg: %x\n", InParams.irDriveRegs.bCommandReg);
+ OutParams.DriverStatus.bIDEError = 1;
+ Result = SRB_STATUS_INVALID_REQUEST;
+ }
+ else if (InParams.bDriveNumber > 1 ||
+ (DevExt->DeviceFlags[InParams.bDriveNumber] & (DEVICE_PRESENT|DEVICE_ATAPI)) != DEVICE_PRESENT)
+ {
+ OutParams.DriverStatus.bIDEError = 1;
+ Result = SRB_STATUS_NO_DEVICE;
+ }
+ else
+ {
+ Result = SRB_STATUS_SUCCESS;
+ }
+ if (Result == SRB_STATUS_SUCCESS)
+ {
+ SrbIoControl->Length = min(sizeof(SENDCMDOUTPARAMS) - 1 + IDENTIFY_BUFFER_SIZE, Srb->DataTransferLength - sizeof(SRB_IO_CONTROL));
+ }
+ else
+ {
+ SrbIoControl->Length = min(sizeof(SENDCMDOUTPARAMS) - 1, Srb->DataTransferLength - sizeof(SRB_IO_CONTROL));
+ }
+
+ if (SrbIoControl->Length >= sizeof(SENDCMDOUTPARAMS) - 1)
+ {
+ OutParams.cBufferSize = min(SrbIoControl->Length, IDENTIFY_BUFFER_SIZE);
+ }
+
+ memcpy(SrbIoControl + 1, &OutParams, min (SrbIoControl->Length, sizeof(SENDCMDOUTPARAMS) - 1));
+
+ if (SrbIoControl->Length > sizeof(SENDCMDOUTPARAMS) - 1)
+ {
+ RtlCopyMemory((PVOID)((ULONG_PTR)(SrbIoControl + 1) + sizeof(SENDCMDOUTPARAMS) - 1), &DevExt->DeviceParams[InParams.bDriveNumber], OutParams.cBufferSize);
+ }
+ break;
+ }
+ }
+ }
+ else
+ {
+ Result = SRB_STATUS_INVALID_REQUEST;
+ SrbIoControl->Length = 0;
+ }
+ }
+ break;
+ }
+
+ default:
+ Result = SRB_STATUS_INVALID_REQUEST;
+ break;
}
Srb->SrbStatus = Result;
if (Result != SRB_STATUS_PENDING)
{
DevExt->CurrentSrb = NULL;
- Srb->SrbStatus = (UCHAR)Result;
ScsiPortNotification(RequestComplete,
DeviceExtension,
}
else
{
- DPRINT1("SrbStatus = SRB_STATUS_PENDING\n");
+ DPRINT("SrbStatus = SRB_STATUS_PENDING\n");
}
- DPRINT1("AtapiStartIo() done\n");
+ DPRINT("AtapiStartIo() done\n");
return(TRUE);
}
-
static BOOLEAN STDCALL
AtapiInterrupt(IN PVOID DeviceExtension)
{
PATAPI_MINIPORT_EXTENSION DevExt;
- PSCSI_REQUEST_BLOCK Srb;
- ULONG CommandPortBase;
- ULONG ControlPortBase;
-
- UCHAR DeviceStatus;
- BOOLEAN IsLastBlock, AnErrorOccured, RequestIsComplete;
- ULONG Retries;
- NTSTATUS ErrorStatus;
- ULONG ErrorInformation;
- PUCHAR TargetAddress;
-
-
-
- DPRINT("AtapiInterrupt() called!\n");
-
+ UCHAR Status;
DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
- if (DevExt->ExpectingInterrupt == FALSE)
+
+ if (DevExt->Handler == NULL)
{
- return(FALSE);
+ Status = IDEReadAltStatus(DevExt->ControlPortBase);
+ if ((Status & (IDE_SR_DRDY|IDE_SR_BUSY|IDE_SR_ERR|IDE_SR_DRQ)) != IDE_SR_DRDY)
+ {
+ static ULONG Count = 0;
+ Count++;
+ DPRINT1("Unexpected Interrupt, CommandPort=%04x, Status=%02x, Count=%ld\n",
+ DevExt->CommandPortBase, Status, Count);
+ }
+ return FALSE;
}
-
- Srb = DevExt->CurrentSrb;
-
- DPRINT("Srb: %p\n", Srb);
-
- CommandPortBase = DevExt->CommandPortBase;
- ControlPortBase = DevExt->ControlPortBase;
-
- DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", CommandPortBase, ControlPortBase);
-
-
- IsLastBlock = FALSE;
- AnErrorOccured = FALSE;
- RequestIsComplete = FALSE;
- ErrorStatus = STATUS_SUCCESS;
- ErrorInformation = 0;
-
- DeviceStatus = IDEReadStatus(CommandPortBase);
-
- /* Handle error condition if it exists */
- if (DeviceStatus & IDE_SR_ERR)
+#ifdef ENABLE_DMA
+ if (DevExt->UseDma)
{
- BYTE ErrorReg, SectorCount, SectorNum, CylinderLow, CylinderHigh;
- BYTE DriveHead;
-
- /* Log the error */
- ErrorReg = IDEReadError(CommandPortBase);
- CylinderLow = IDEReadCylinderLow(CommandPortBase);
- CylinderHigh = IDEReadCylinderHigh(CommandPortBase);
- DriveHead = IDEReadDriveHead(CommandPortBase);
- SectorCount = IDEReadSectorCount(CommandPortBase);
- SectorNum = IDEReadSectorNum(CommandPortBase);
-
- /* FIXME: should use the NT error logging facility */
- DbgPrint("ATAPT Error: OP:%02x STAT:%02x ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
- 0, //DeviceExtension->Operation,
- DeviceStatus,
- ErrorReg,
- CylinderLow,
- CylinderHigh,
- SectorCount,
- SectorNum);
-
- /* FIXME: should retry the command and perhaps recalibrate the drive */
-
- // Set error status information
- AnErrorOccured = TRUE;
- ErrorStatus = STATUS_DISK_OPERATION_FAILED;
-#if 0
- ErrorInformation =
- (((((((CylinderHigh << 8) + CylinderLow) *
- DeviceExtension->LogicalHeads) +
- (DriveHead % DeviceExtension->LogicalHeads)) *
- DeviceExtension->SectorsPerLogTrk) + SectorNum - 1) -
- DeviceExtension->StartingSector) * DeviceExtension->BytesPerSector;
-#endif
+ Status = IDEReadDMAStatus(DevExt->BusMasterRegisterBase);
+ if (!(Status & 0x04))
+ {
+ return FALSE;
+ }
}
else
- {
- switch (Srb->Cdb[0])
- {
- case SCSIOP_READ:
- DPRINT("SCSIOP_READ\n");
-
- /* Update controller/device state variables */
- TargetAddress = Srb->DataBuffer;
- Srb->DataBuffer += DevExt->DeviceParams[Srb->TargetId].BytesPerSector;
- Srb->DataTransferLength -= DevExt->DeviceParams[Srb->TargetId].BytesPerSector;
-// DevExt->SectorsTransferred++;
-
- /* Remember whether DRQ should be low at end (last block read) */
- IsLastBlock = (Srb->DataTransferLength == 0);
- DPRINT("IsLastBlock == %s\n", (IsLastBlock)?"TRUE":"FALSE");
-
- /* Wait for DRQ assertion */
- for (Retries = 0; Retries < IDE_MAX_DRQ_RETRIES &&
- !(IDEReadStatus(CommandPortBase) & IDE_SR_DRQ);
- Retries++)
- {
- KeStallExecutionProcessor(10);
- }
-
- /* Copy the block of data */
- IDEReadBlock(CommandPortBase,
- TargetAddress,
- IDE_SECTOR_BUF_SZ);
-
- /* check DRQ */
- if (IsLastBlock)
- {
- for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
- (IDEReadStatus(CommandPortBase) & IDE_SR_BUSY);
- Retries++)
- {
- KeStallExecutionProcessor(10);
- }
-
- /* Check for data overrun */
- if (IDEReadStatus(CommandPortBase) & IDE_SR_DRQ)
- {
- AnErrorOccured = TRUE;
- ErrorStatus = STATUS_DATA_OVERRUN;
- ErrorInformation = 0;
- }
- else
- {
-
-#if 0
- // Setup next transfer or set RequestIsComplete
- if (DeviceExtension->BytesRequested >
- DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER)
- {
- DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
- DeviceExtension->SectorsTransferred = 0;
- DeviceExtension->BytesToTransfer =
- DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER;
- DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
- }
- else if (DeviceExtension->BytesRequested > 0)
- {
- DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
- DeviceExtension->SectorsTransferred = 0;
- DeviceExtension->BytesToTransfer = DeviceExtension->BytesRequested;
- DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
- }
- else
- {
- RequestIsComplete = TRUE;
- }
#endif
- RequestIsComplete = TRUE;
- }
- }
- break;
-
- case SCSIOP_WRITE:
- DPRINT1("AtapiInterrupt(): SCSIOP_WRITE not implemented yet!\n");
- RequestIsComplete = TRUE;
- IsLastBlock = TRUE;
- break;
- }
+ {
+ Status = IDEReadAltStatus(DevExt->ControlPortBase);
+ if (Status & IDE_SR_BUSY)
+ {
+ return FALSE;
+ }
}
+ return DevExt->Handler(DevExt);
+}
+
+// ---------------------------------------------------- Discardable statics
+#ifdef ENABLE_DMA
+static BOOLEAN
+AtapiConfigDma(PATAPI_MINIPORT_EXTENSION DeviceExtension, ULONG UnitNumber)
+{
+ BOOLEAN Result = FALSE;
+ UCHAR Status;
- /* If there was an error or the request is done, complete the packet */
- if (AnErrorOccured || RequestIsComplete)
+ if (UnitNumber < 2)
{
+ if (DeviceExtension->PRDTable)
+ {
+ if (DeviceExtension->DeviceParams[UnitNumber].Capabilities & IDE_DRID_DMA_SUPPORTED)
+ {
+ if ((DeviceExtension->DeviceParams[UnitNumber].TMFieldsValid & 0x0004) &&
+ (DeviceExtension->DeviceParams[UnitNumber].UltraDmaModes & 0x7F00))
+ {
+ Result = TRUE;
+ }
+ else if (DeviceExtension->DeviceParams[UnitNumber].TMFieldsValid & 0x0002)
+ {
+ if ((DeviceExtension->DeviceParams[UnitNumber].MultiDmaModes & 0x0404) == 0x0404)
+ {
+ Result = TRUE;
+ }
#if 0
- /* Set the return status and info values */
- Irp = ControllerExtension->CurrentIrp;
- Irp->IoStatus.Status = ErrorStatus;
- Irp->IoStatus.Information = ErrorInformation;
-
- /* Clear out controller fields */
- ControllerExtension->OperationInProgress = FALSE;
- ControllerExtension->DeviceStatus = 0;
-
- /* Queue the Dpc to finish up */
- IoRequestDpc(DeviceExtension->DeviceObject,
- Irp,
- ControllerExtension);
+ /* FIXME:
+ * should we support single mode dma ?
+ */
+ else if ((DeviceExtension->DeviceParams[UnitNumber].DmaModes & 0x0404) == 0x0404)
+ {
+ Result = TRUE;
+ }
#endif
+ }
+ Status = IDEReadDMAStatus(DeviceExtension->BusMasterRegisterBase);
+ if (Result)
+ {
+ IDEWriteDMAStatus(DeviceExtension->BusMasterRegisterBase, Status | (UnitNumber ? 0x40 : 0x20));
+ }
+ else
+ {
+ IDEWriteDMAStatus(DeviceExtension->BusMasterRegisterBase, Status & (UnitNumber ? ~0x40 : ~0x20));
+ }
+ }
+ }
}
- else if (IsLastBlock)
- {
-#if 0
- /* Else more data is needed, setup next device I/O */
- IDEStartController((PVOID)DeviceExtension);
+ return Result;
+}
#endif
- }
-
- if (IsLastBlock)
- {
- DevExt->ExpectingInterrupt = FALSE;
-
- ScsiPortNotification(RequestComplete,
- DeviceExtension,
- Srb);
-
- ScsiPortNotification(NextRequest,
- DeviceExtension,
- NULL);
- }
-}
-
- DPRINT("AtapiInterrupt() done!\n");
-
- return(TRUE);
-}
-
-
-
-
-
-
-// ---------------------------------------------------- Discardable statics
+/**********************************************************************
+ * NAME INTERNAL
+ * AtapiFindDevices
+ *
+ * DESCRIPTION
+ * Searches for devices on the given port.
+ *
+ * RUN LEVEL
+ * PASSIVE_LEVEL
+ *
+ * ARGUMENTS
+ * DeviceExtension
+ * Port device specific information.
+ *
+ * ConfigInfo
+ * Port configuration information.
+ *
+ * RETURN VALUE
+ * TRUE: At least one device is attached to the port.
+ * FALSE: No device is attached to the port.
+ */
static BOOLEAN
AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
ULONG ControlPortBase;
ULONG UnitNumber;
ULONG Retries;
- BYTE High, Low;
+ UCHAR High;
+ UCHAR Low;
DPRINT("AtapiFindDevices() called\n");
-// CommandPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart);
- CommandPortBase = ScsiPortConvertPhysicalAddressToUlong(ConfigInfo->AccessRanges[0].RangeStart);
+ CommandPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart);
DPRINT(" CommandPortBase: %x\n", CommandPortBase);
-// ControlPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[1].RangeStart);
- ControlPortBase = ScsiPortConvertPhysicalAddressToUlong(ConfigInfo->AccessRanges[1].RangeStart);
+ ControlPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[1].RangeStart);
DPRINT(" ControlPortBase: %x\n", ControlPortBase);
for (UnitNumber = 0; UnitNumber < 2; UnitNumber++)
{
- /* disable interrupts */
- IDEWriteDriveControl(ControlPortBase,
- IDE_DC_nIEN);
-
- /* select drive */
+ /* Select drive */
IDEWriteDriveHead(CommandPortBase,
IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
ScsiPortStallExecution(500);
+
+ /* Disable interrupts */
+ IDEWriteDriveControl(ControlPortBase,
+ IDE_DC_nIEN);
+ ScsiPortStallExecution(500);
+
+ /* Check if a device is attached to the interface */
+ IDEWriteCylinderHigh(CommandPortBase, 0xaa);
+ IDEWriteCylinderLow(CommandPortBase, 0x55);
+
+ High = IDEReadCylinderHigh(CommandPortBase);
+ Low = IDEReadCylinderLow(CommandPortBase);
+
IDEWriteCylinderHigh(CommandPortBase, 0);
IDEWriteCylinderLow(CommandPortBase, 0);
- IDEWriteCommand(CommandPortBase, 0x08); /* IDE_COMMAND_ATAPI_RESET */
-// ScsiPortStallExecution(1000*1000);
-// IDEWriteDriveHead(CommandPortBase,
-// IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
-// IDE_DH_FIXED);
+
+ if (Low != 0x55 || High != 0xaa)
+ {
+ DPRINT("No Drive found. UnitNumber %d CommandPortBase %x\n", UnitNumber, CommandPortBase);
+ continue;
+ }
+
+ AtapiExecuteCommand(DeviceExtension, IDE_CMD_RESET, NULL);
for (Retries = 0; Retries < 20000; Retries++)
{
}
ScsiPortStallExecution(150);
}
- if (Retries >= IDE_RESET_BUSY_TIMEOUT * 1000)
+ if (Retries >= 20000)
{
- DbgPrint("Timeout on drive %lu\n", UnitNumber);
- return(DeviceFound);
+ DPRINT("Timeout on drive %lu\n", UnitNumber);
+ DeviceExtension->DeviceFlags[UnitNumber] &= ~DEVICE_PRESENT;
+ continue;
}
High = IDEReadCylinderHigh(CommandPortBase);
&DeviceExtension->DeviceParams[UnitNumber]))
{
DPRINT(" ATAPI drive found!\n");
- DeviceExtension->DevicePresent[UnitNumber] = TRUE;
- DeviceExtension->DeviceAtapi[UnitNumber] = TRUE;
+ DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_PRESENT;
+ DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_ATAPI;
+ DeviceExtension->TransferSize[UnitNumber] =
+ DeviceExtension->DeviceParams[UnitNumber].BytesPerSector;
+#ifdef ENABLE_DMA
+ if (AtapiConfigDma(DeviceExtension, UnitNumber))
+ {
+ DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_DMA_CMD;
+ }
+#endif
+ if (!(DeviceExtension->DeviceParams[UnitNumber].SupportedFeatures83 & 0x1000) ||
+ !(DeviceExtension->DeviceParams[UnitNumber].EnabledFeatures86 & 0x1000))
+ {
+ DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_NO_FLUSH;
+ }
+
+ /* Don't flush CD/DVD drives */
+ if (((DeviceExtension->DeviceParams[UnitNumber].ConfigBits >> 8) & 0x1F) == READ_ONLY_DIRECT_ACCESS_DEVICE)
+ {
+ DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_NO_FLUSH;
+ }
DeviceFound = TRUE;
}
else
&DeviceExtension->DeviceParams[UnitNumber]))
{
DPRINT(" IDE drive found!\n");
- DeviceExtension->DevicePresent[UnitNumber] = TRUE;
- DeviceExtension->DeviceAtapi[UnitNumber] = FALSE;
+ DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_PRESENT;
+ DeviceExtension->TransferSize[UnitNumber] = DeviceExtension->DeviceParams[UnitNumber].BytesPerSector;
+ if ((DeviceExtension->DeviceParams[UnitNumber].RWMultImplemented & 0x8000) &&
+ (DeviceExtension->DeviceParams[UnitNumber].RWMultImplemented & 0xff) &&
+ (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0x100) &&
+ (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0xff))
+ {
+ DeviceExtension->TransferSize[UnitNumber] *= (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0xff);
+ DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_MULTI_SECTOR_CMD;
+ }
+ if (DeviceExtension->DeviceParams[UnitNumber].SupportedFeatures83 & 0x0400 &&
+ DeviceExtension->DeviceParams[UnitNumber].EnabledFeatures86 & 0x0400)
+ {
+ DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_48BIT_ADDRESS;
+ }
+ if (DeviceExtension->DeviceParams[UnitNumber].DWordIo)
+ {
+ DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_DWORD_IO;
+ }
+#ifdef ENABLE_DMA
+ if (AtapiConfigDma(DeviceExtension, UnitNumber))
+ {
+ DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_DMA_CMD;
+ }
+#endif
+ if (DeviceExtension->DeviceFlags[UnitNumber] & DEVICE_48BIT_ADDRESS)
+ {
+ if (!(DeviceExtension->DeviceParams[UnitNumber].SupportedFeatures83 & 0x2000) ||
+ !(DeviceExtension->DeviceParams[UnitNumber].EnabledFeatures86 & 0x2000))
+ {
+ DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_NO_FLUSH;
+ }
+ }
+ else
+ {
+ if (!(DeviceExtension->DeviceParams[UnitNumber].SupportedFeatures83 & 0x1000) ||
+ !(DeviceExtension->DeviceParams[UnitNumber].EnabledFeatures86 & 0x1000))
+ {
+ DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_NO_FLUSH;
+ }
+ }
DeviceFound = TRUE;
}
else
}
}
- DPRINT("AtapiFindDrives() done\n");
+ /* Reset pending interrupts */
+ IDEReadStatus(CommandPortBase);
+ /* Reenable interrupts */
+ IDEWriteDriveControl(ControlPortBase, 0);
+ ScsiPortStallExecution(500);
+ /* Return with drive 0 selected */
+ IDEWriteDriveHead(CommandPortBase, IDE_DH_FIXED);
+ ScsiPortStallExecution(500);
+
+ DPRINT("AtapiFindDrives() done (DeviceFound %s)\n", (DeviceFound) ? "TRUE" : "FALSE");
return(DeviceFound);
}
-// AtapiResetController
-//
-// DESCRIPTION:
-// Reset the controller and report completion status
-//
-// RUN LEVEL:
-// PASSIVE_LEVEL
-//
-// ARGUMENTS:
-// IN WORD CommandPort The address of the command port
-// IN WORD ControlPort The address of the control port
-//
-// RETURNS:
-//
-
-static BOOLEAN
-AtapiResetController(IN WORD CommandPort,
- IN WORD ControlPort)
-{
- int Retries;
-
- /* Assert drive reset line */
- IDEWriteDriveControl(ControlPort, IDE_DC_SRST);
-
- /* Wait for min. 25 microseconds */
- ScsiPortStallExecution(IDE_RESET_PULSE_LENGTH);
-
- /* Negate drive reset line */
- IDEWriteDriveControl(ControlPort, 0);
-
- /* Wait for BUSY negation */
- for (Retries = 0; Retries < IDE_RESET_BUSY_TIMEOUT * 1000; Retries++)
- {
- if (!(IDEReadStatus(CommandPort) & IDE_SR_BUSY))
- {
- break;
- }
- ScsiPortStallExecution(10);
- }
-
- CHECKPOINT;
- if (Retries >= IDE_RESET_BUSY_TIMEOUT * 1000)
- {
- return(FALSE);
- }
-
- CHECKPOINT;
-
- // return TRUE if controller came back to life. and
- // the registers are initialized correctly
- return(IDEReadError(CommandPort) == 1);
-}
-
/*
* AtapiIdentifyDevice
*
IN BOOLEAN Atapi,
OUT PIDE_DRIVE_IDENTIFY DrvParms)
{
+ LONG i;
+ ULONG mode;
+ char SerialNumber[20];
+ char FirmwareRev[8];
+ char ModelNumber[40];
+
/* Get the Drive Identify block from drive or die */
- if (AtapiPolledRead((WORD)CommandPort,
- (WORD)ControlPort,
+ if (AtapiPolledRead(CommandPort,
+ ControlPort,
0,
1,
0,
0,
(DriveNum ? IDE_DH_DRV1 : 0),
(Atapi ? IDE_CMD_IDENT_ATAPI_DRV : IDE_CMD_IDENT_ATA_DRV),
- (BYTE *)DrvParms) != 0) /* atapi_identify */
+ (PUCHAR)DrvParms) == FALSE)
{
- DPRINT1("IDEPolledRead() failed\n");
+ DPRINT("AtapiPolledRead() failed\n");
return FALSE;
}
/* Report on drive parameters if debug mode */
- IDESwapBytePairs(DrvParms->SerialNumber, 20);
- IDESwapBytePairs(DrvParms->FirmwareRev, 8);
- IDESwapBytePairs(DrvParms->ModelNumber, 40);
- DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
- DrvParms->ConfigBits,
- DrvParms->LogicalCyls,
- DrvParms->LogicalHeads,
- DrvParms->SectorsPerTrack,
- DrvParms->InterSectorGap,
+ memcpy(SerialNumber, DrvParms->SerialNumber, 20);
+ memcpy(FirmwareRev, DrvParms->FirmwareRev, 8);
+ memcpy(ModelNumber, DrvParms->ModelNumber, 40);
+ IDESwapBytePairs((PUCHAR)SerialNumber, 20);
+ IDESwapBytePairs((PUCHAR)FirmwareRev, 8);
+ IDESwapBytePairs((PUCHAR)ModelNumber, 40);
+ DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
+ DrvParms->ConfigBits,
+ DrvParms->LogicalCyls,
+ DrvParms->LogicalHeads,
+ DrvParms->SectorsPerTrack,
+ DrvParms->InterSectorGap,
DrvParms->InterSectorGapSize);
- DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
- DrvParms->BytesInPLO,
- DrvParms->VendorUniqueCnt,
- DrvParms->SerialNumber);
- DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
- DrvParms->ControllerType,
- DrvParms->BufferSize * IDE_SECTOR_BUF_SZ,
- DrvParms->ECCByteCnt,
- DrvParms->FirmwareRev);
- DPRINT("Model:[%.40s]\n", DrvParms->ModelNumber);
- DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
- (DrvParms->RWMultImplemented) & 0xff,
+ DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
+ DrvParms->BytesInPLO,
+ DrvParms->VendorUniqueCnt,
+ SerialNumber);
+ DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
+ DrvParms->ControllerType,
+ DrvParms->BufferSize * IDE_SECTOR_BUF_SZ,
+ DrvParms->ECCByteCnt,
+ FirmwareRev);
+ DPRINT("Model:[%.40s]\n", ModelNumber);
+ DPRINT("RWMultMax?:%04x RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
+ (DrvParms->RWMultImplemented),
+ (DrvParms->RWMultCurrent) & 0xff,
(DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0,
- (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0,
+ (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0,
DrvParms->MinPIOTransTime,
DrvParms->MinDMATransTime);
DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
- DrvParms->TMCylinders,
- DrvParms->TMHeads,
+ DrvParms->TMCylinders,
+ DrvParms->TMHeads,
DrvParms->TMSectorsPerTrk,
(ULONG)(DrvParms->TMCapacityLo + (DrvParms->TMCapacityHi << 16)));
DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
DrvParms->TMSectorCountHi,
DrvParms->TMSectorCountLo,
(ULONG)((DrvParms->TMSectorCountHi << 16) + DrvParms->TMSectorCountLo));
+ DPRINT("SupportedFeatures83: %x, EnabledFeatures86 %x\n", DrvParms->SupportedFeatures83, DrvParms->EnabledFeatures86);
+ DPRINT("Max48BitAddress: %I64d\n", *(PULONGLONG)DrvParms->Max48BitAddress);
+ if (DrvParms->TMFieldsValid & 0x0004)
+ {
+ if ((DrvParms->UltraDmaModes >> 8) && (DrvParms->UltraDmaModes & 0xff))
+ {
+ mode = 7;
+ while (!(DrvParms->UltraDmaModes & (0x0100 << mode)))
+ {
+ mode--;
+ }
+ DPRINT("Ultra DMA mode %d is selected\n", mode);
+ }
+ else if ((DrvParms->MultiDmaModes >> 8) & (DrvParms->MultiDmaModes & 0x07))
+ {
+ mode = 2;
+ while(!(DrvParms->MultiDmaModes & (0x01 << mode)))
+ {
+ mode--;
+ }
+ DPRINT("Multi DMA mode %d is selected\n", mode);
+ }
+ }
+ if (! Atapi && 0 != (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED))
+ {
+ /* LBA ATA drives always have a sector size of 512 */
+ DrvParms->BytesPerSector = 512;
+ }
+ else
+ {
+ DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
+ if (DrvParms->BytesPerSector == 0)
+ {
+ DrvParms->BytesPerSector = 512;
+ }
+ else
+ {
+ for (i = 15; i >= 0; i--)
+ {
+ if (DrvParms->BytesPerSector & (1 << i))
+ {
+ DrvParms->BytesPerSector = 1 << i;
+ break;
+ }
+ }
+ }
+ }
DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
- if (DrvParms->BytesPerSector == 0)
- DrvParms->BytesPerSector = 512;
+
return TRUE;
}
// PASSIVE_LEVEL
//
// ARGUMENTS:
-// IN WORD Address Address of command port for drive
-// IN BYTE PreComp Value to write to precomp register
-// IN BYTE SectorCnt Value to write to sectorCnt register
-// IN BYTE SectorNum Value to write to sectorNum register
-// IN BYTE CylinderLow Value to write to CylinderLow register
-// IN BYTE CylinderHigh Value to write to CylinderHigh register
-// IN BYTE DrvHead Value to write to Drive/Head register
-// IN BYTE Command Value to write to Command register
-// OUT BYTE *Buffer Buffer for output data
+// IN ULONG CommandPort Address of command port for drive
+// IN ULONG ControlPort Address of control port for drive
+// IN UCHAR PreComp Value to write to precomp register
+// IN UCHAR SectorCnt Value to write to sectorCnt register
+// IN UCHAR SectorNum Value to write to sectorNum register
+// IN UCHAR CylinderLow Value to write to CylinderLow register
+// IN UCHAR CylinderHigh Value to write to CylinderHigh register
+// IN UCHAR DrvHead Value to write to Drive/Head register
+// IN UCHAR Command Value to write to Command register
+// OUT PUCHAR Buffer Buffer for output data
//
// RETURNS:
-// int 0 is success, non 0 is an error code
+// BOOLEAN: TRUE success, FALSE error
//
-static int
-AtapiPolledRead(IN WORD Address,
- IN WORD ControlPort,
- IN BYTE PreComp,
- IN BYTE SectorCnt,
- IN BYTE SectorNum,
- IN BYTE CylinderLow,
- IN BYTE CylinderHigh,
- IN BYTE DrvHead,
- IN BYTE Command,
- OUT BYTE *Buffer)
+static BOOLEAN
+AtapiPolledRead(IN ULONG CommandPort,
+ IN ULONG ControlPort,
+ IN UCHAR PreComp,
+ IN UCHAR SectorCnt,
+ IN UCHAR SectorNum,
+ IN UCHAR CylinderLow,
+ IN UCHAR CylinderHigh,
+ IN UCHAR DrvHead,
+ IN UCHAR Command,
+ OUT PUCHAR Buffer)
{
ULONG SectorCount = 0;
ULONG RetryCount;
BOOLEAN Junk = FALSE;
UCHAR Status;
- UCHAR Control;
- /* Disable interrupts */
- Control = IDEReadAltStatus(ControlPort);
- IDEWriteDriveControl(ControlPort, Control | IDE_DC_nIEN);
-
- /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
+ /* Wait for BUSY to clear */
for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
{
- Status = IDEReadStatus(Address);
- if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
- {
- break;
- }
+ Status = IDEReadStatus(CommandPort);
+ if (!(Status & IDE_SR_BUSY))
+ {
+ break;
+ }
ScsiPortStallExecution(10);
}
- if (RetryCount == IDE_MAX_BUSY_RETRIES)
+ DPRINT("status=%02x\n", Status);
+ DPRINT("waited %ld usecs for busy to clear\n", RetryCount * 10);
+ if (RetryCount >= IDE_MAX_BUSY_RETRIES)
{
- return(IDE_ER_ABRT);
+ DPRINT("Drive is BUSY for too long\n");
+ return FALSE;
}
/* Write Drive/Head to select drive */
- IDEWriteDriveHead(Address, IDE_DH_FIXED | DrvHead);
+ IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
+ ScsiPortStallExecution(500);
+
+ /* Disable interrupts */
+ IDEWriteDriveControl(ControlPort, IDE_DC_nIEN);
+ ScsiPortStallExecution(500);
+#if 0
/* Wait for STATUS.BUSY and STATUS.DRQ to clear */
for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
{
- Status = IDEReadStatus(Address);
+ Status = IDEReadStatus(CommandPort);
if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
{
break;
}
if (RetryCount >= IDE_MAX_BUSY_RETRIES)
{
- return IDE_ER_ABRT;
+ return FALSE;
}
+#endif
/* Issue command to drive */
if (DrvHead & IDE_DH_LBA)
}
/* Setup command parameters */
- IDEWritePrecomp(Address, PreComp);
- IDEWriteSectorCount(Address, SectorCnt);
- IDEWriteSectorNum(Address, SectorNum);
- IDEWriteCylinderHigh(Address, CylinderHigh);
- IDEWriteCylinderLow(Address, CylinderLow);
- IDEWriteDriveHead(Address, IDE_DH_FIXED | DrvHead);
+ IDEWritePrecomp(CommandPort, PreComp);
+ IDEWriteSectorCount(CommandPort, SectorCnt);
+ IDEWriteSectorNum(CommandPort, SectorNum);
+ IDEWriteCylinderHigh(CommandPort, CylinderHigh);
+ IDEWriteCylinderLow(CommandPort, CylinderLow);
+ IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
/* Issue the command */
- IDEWriteCommand(Address, Command);
+ IDEWriteCommand(CommandPort, Command);
ScsiPortStallExecution(50);
/* wait for DRQ or error */
for (RetryCount = 0; RetryCount < IDE_MAX_POLL_RETRIES; RetryCount++)
{
- Status = IDEReadStatus(Address);
+ Status = IDEReadStatus(CommandPort);
if (!(Status & IDE_SR_BUSY))
{
if (Status & IDE_SR_ERR)
{
- IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
- return(IDE_ER_ABRT);
+ IDEWriteDriveControl(ControlPort, 0);
+ ScsiPortStallExecution(50);
+ IDEReadStatus(CommandPort);
+
+ return FALSE;
}
+
if (Status & IDE_SR_DRQ)
{
break;
}
else
{
- IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
- return(IDE_ER_ABRT);
+ IDEWriteDriveControl(ControlPort, 0);
+ ScsiPortStallExecution(50);
+ IDEReadStatus(CommandPort);
+
+ return FALSE;
}
}
ScsiPortStallExecution(10);
/* timed out */
if (RetryCount >= IDE_MAX_POLL_RETRIES)
{
- IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
- return(IDE_ER_ABRT);
+ IDEWriteDriveControl(ControlPort, 0);
+ ScsiPortStallExecution(50);
+ IDEReadStatus(CommandPort);
+
+ return FALSE;
}
while (1)
/* Read data into buffer */
if (Junk == FALSE)
{
- IDEReadBlock(Address, Buffer, IDE_SECTOR_BUF_SZ);
+ IDEReadBlock(CommandPort, Buffer, IDE_SECTOR_BUF_SZ);
Buffer += IDE_SECTOR_BUF_SZ;
}
else
{
UCHAR JunkBuffer[IDE_SECTOR_BUF_SZ];
- IDEReadBlock(Address, JunkBuffer, IDE_SECTOR_BUF_SZ);
+ IDEReadBlock(CommandPort, JunkBuffer, IDE_SECTOR_BUF_SZ);
}
SectorCount++;
/* Check for error or more sectors to read */
for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
{
- Status = IDEReadStatus(Address);
+ Status = IDEReadStatus(CommandPort);
if (!(Status & IDE_SR_BUSY))
{
if (Status & IDE_SR_ERR)
{
- IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
- return(IDE_ER_ABRT);
+ IDEWriteDriveControl(ControlPort, 0);
+ ScsiPortStallExecution(50);
+ IDEReadStatus(CommandPort);
+
+ return FALSE;
}
if (Status & IDE_SR_DRQ)
{
DPRINT("Read %lu sectors of junk!\n",
SectorCount - SectorCnt);
}
- IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
- return(0);
+ IDEWriteDriveControl(ControlPort, 0);
+ ScsiPortStallExecution(50);
+ IDEReadStatus(CommandPort);
+
+ return TRUE;
}
}
}
// ------------------------------------------- Nondiscardable statics
static ULONG
-AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
+AtapiSendSmartCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb)
{
- DPRINT1("AtapiSendAtapiComamnd() called!\n");
- DPRINT1("Not implemented yet!\n");
- return(SRB_STATUS_SELECTION_TIMEOUT);
-}
+ PSRB_IO_CONTROL SrbIoControl = (PSRB_IO_CONTROL)Srb->DataBuffer;
+ SENDCMDINPARAMS InParams;
+ PSENDCMDOUTPARAMS OutParams = (PSENDCMDOUTPARAMS)(SrbIoControl + 1);
+ ULONG Retries;
+ UCHAR Status;
+ if (Srb->DataTransferLength < sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDOUTPARAMS) - 1 ||
+ SrbIoControl->Length < sizeof(SENDCMDOUTPARAMS) - 1)
+ {
+ return SRB_STATUS_INVALID_REQUEST;
+ }
+ InParams = *(PSENDCMDINPARAMS)(SrbIoControl + 1);
+
+ DPRINT("%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ InParams.irDriveRegs.bFeaturesReg,
+ InParams.irDriveRegs.bSectorCountReg,
+ InParams.irDriveRegs.bSectorNumberReg,
+ InParams.irDriveRegs.bCylLowReg,
+ InParams.irDriveRegs.bCylHighReg,
+ InParams.irDriveRegs.bDriveHeadReg,
+ InParams.irDriveRegs.bCommandReg,
+ InParams.irDriveRegs.bReserved);
+
+ if (InParams.bDriveNumber > 1 ||
+ (DeviceExtension->DeviceFlags[InParams.bDriveNumber] & (DEVICE_PRESENT|DEVICE_ATAPI)) != DEVICE_PRESENT)
+ {
+ RtlZeroMemory(&OutParams, sizeof(SENDCMDOUTPARAMS));
+ OutParams->DriverStatus.bIDEError = 1;
+ return SRB_STATUS_NO_DEVICE;
+ }
-static ULONG
-AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
- IN PSCSI_REQUEST_BLOCK Srb)
-{
- ULONG SrbStatus = SRB_STATUS_SUCCESS;
+ DeviceExtension->DataTransferLength = 0;
- DPRINT1("AtapiSendIdeCommand() called!\n");
+ switch (SrbIoControl->ControlCode)
+ {
+ case IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS:
+ DPRINT("IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS\n");
+
+ if (Srb->DataTransferLength < sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDOUTPARAMS) - 1 + READ_ATTRIBUTE_BUFFER_SIZE ||
+ SrbIoControl->Length < sizeof(SENDCMDOUTPARAMS) - 1 + READ_ATTRIBUTE_BUFFER_SIZE ||
+ InParams.irDriveRegs.bFeaturesReg != READ_ATTRIBUTES ||
+ InParams.irDriveRegs.bCylLowReg != SMART_CYL_LOW ||
+ InParams.irDriveRegs.bCylHighReg != SMART_CYL_HI ||
+ InParams.irDriveRegs.bCommandReg != SMART_CMD)
+ {
+ return SRB_STATUS_INVALID_REQUEST;
+ }
+ InParams.irDriveRegs.bSectorCountReg = 0;
+ InParams.irDriveRegs.bSectorNumberReg = 0;
+ DeviceExtension->DataTransferLength = READ_ATTRIBUTE_BUFFER_SIZE;
+ break;
+
+ case IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS:
+ DPRINT("IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS\n");
+
+ if (Srb->DataTransferLength < sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDOUTPARAMS) - 1 + READ_THRESHOLD_BUFFER_SIZE ||
+ SrbIoControl->Length < sizeof(SENDCMDOUTPARAMS) - 1 + READ_THRESHOLD_BUFFER_SIZE ||
+ InParams.irDriveRegs.bFeaturesReg != READ_THRESHOLDS ||
+ InParams.irDriveRegs.bCylLowReg != SMART_CYL_LOW ||
+ InParams.irDriveRegs.bCylHighReg != SMART_CYL_HI ||
+ InParams.irDriveRegs.bCommandReg != SMART_CMD)
+ {
+ return SRB_STATUS_INVALID_REQUEST;
+ }
+ InParams.irDriveRegs.bSectorCountReg = 0;
+ InParams.irDriveRegs.bSectorNumberReg = 0;
+ DeviceExtension->DataTransferLength = READ_THRESHOLD_BUFFER_SIZE;
+ break;
+
+ case IOCTL_SCSI_MINIPORT_READ_SMART_LOG:
+ DPRINT("IOCTL_SCSI_MINIPORT_READ_SMART_LOG\n");
+
+ if (Srb->DataTransferLength < sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDOUTPARAMS) - 1 + max(1, InParams.irDriveRegs.bSectorCountReg) * SMART_LOG_SECTOR_SIZE ||
+ SrbIoControl->Length < sizeof(SENDCMDOUTPARAMS) - 1 + max(1, InParams.irDriveRegs.bSectorCountReg) * SMART_LOG_SECTOR_SIZE ||
+ InParams.irDriveRegs.bFeaturesReg != SMART_READ_LOG ||
+ InParams.irDriveRegs.bCylLowReg != SMART_CYL_LOW ||
+ InParams.irDriveRegs.bCylHighReg != SMART_CYL_HI ||
+ InParams.irDriveRegs.bCommandReg != SMART_CMD)
+ {
+ return SRB_STATUS_INVALID_REQUEST;
+ }
+ DeviceExtension->DataTransferLength = max(1, InParams.irDriveRegs.bSectorCountReg) * SMART_LOG_SECTOR_SIZE;
+ break;
+
+ case IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE:
+ DPRINT("IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE\n");
+
+ if (InParams.irDriveRegs.bFeaturesReg != ENABLE_DISABLE_AUTOSAVE ||
+ (InParams.irDriveRegs.bSectorCountReg != 0 && InParams.irDriveRegs.bSectorCountReg != 1) ||
+ InParams.irDriveRegs.bCylLowReg != SMART_CYL_LOW ||
+ InParams.irDriveRegs.bCylHighReg != SMART_CYL_HI ||
+ InParams.irDriveRegs.bCommandReg != SMART_CMD)
+ {
+ return SRB_STATUS_INVALID_REQUEST;
+ }
+ InParams.irDriveRegs.bSectorNumberReg = 0;
+ break;
+
+ case IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES:
+ DPRINT("IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES\n");
+
+ if (InParams.irDriveRegs.bFeaturesReg != SAVE_ATTRIBUTE_VALUES ||
+ (InParams.irDriveRegs.bSectorCountReg != 0 && InParams.irDriveRegs.bSectorCountReg != 0xf1) ||
+ InParams.irDriveRegs.bCylLowReg != SMART_CYL_LOW ||
+ InParams.irDriveRegs.bCylHighReg != SMART_CYL_HI ||
+ InParams.irDriveRegs.bCommandReg != SMART_CMD)
+ {
+ return SRB_STATUS_INVALID_REQUEST;
+ }
+ InParams.irDriveRegs.bSectorNumberReg = 0;
+ break;
+
+ case IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS:
+ DPRINT("IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS\n");
+
+ if (InParams.irDriveRegs.bFeaturesReg != EXECUTE_OFFLINE_DIAGS ||
+ InParams.irDriveRegs.bCylLowReg != SMART_CYL_LOW ||
+ InParams.irDriveRegs.bCylHighReg != SMART_CYL_HI ||
+ InParams.irDriveRegs.bCommandReg != SMART_CMD)
+ {
+ return SRB_STATUS_INVALID_REQUEST;
+ }
+ InParams.irDriveRegs.bSectorCountReg = 0;
+ break;
+
+ case IOCTL_SCSI_MINIPORT_ENABLE_SMART:
+ DPRINT("IOCTL_SCSI_MINIPORT_ENABLE_SMART\n");
+
+ if (InParams.irDriveRegs.bFeaturesReg != ENABLE_SMART ||
+ InParams.irDriveRegs.bCylLowReg != SMART_CYL_LOW ||
+ InParams.irDriveRegs.bCylHighReg != SMART_CYL_HI ||
+ InParams.irDriveRegs.bCommandReg != SMART_CMD)
+ {
+ return SRB_STATUS_INVALID_REQUEST;
+ }
+ InParams.irDriveRegs.bSectorCountReg = 0;
+ InParams.irDriveRegs.bSectorNumberReg = 0;
+ break;
+
+ case IOCTL_SCSI_MINIPORT_DISABLE_SMART:
+ DPRINT("IOCTL_SCSI_MINIPORT_DISABLE_SMART\n");
+
+ if (InParams.irDriveRegs.bFeaturesReg != DISABLE_SMART ||
+ InParams.irDriveRegs.bCylLowReg != SMART_CYL_LOW ||
+ InParams.irDriveRegs.bCylHighReg != SMART_CYL_HI ||
+ InParams.irDriveRegs.bCommandReg != SMART_CMD)
+ {
+ return SRB_STATUS_INVALID_REQUEST;
+ }
+ InParams.irDriveRegs.bSectorCountReg = 0;
+ InParams.irDriveRegs.bSectorNumberReg = 0;
+ break;
+
+ case IOCTL_SCSI_MINIPORT_RETURN_STATUS:
+ DPRINT("IOCTL_SCSI_MINIPORT_RETURN_STATUS\n");
+
+ if (InParams.irDriveRegs.bFeaturesReg != RETURN_SMART_STATUS ||
+ InParams.irDriveRegs.bCylLowReg != SMART_CYL_LOW ||
+ InParams.irDriveRegs.bCylHighReg != SMART_CYL_HI ||
+ InParams.irDriveRegs.bCommandReg != SMART_CMD)
+ {
+ return SRB_STATUS_INVALID_REQUEST;
+ }
+ InParams.irDriveRegs.bSectorCountReg = 0;
+ InParams.irDriveRegs.bSectorNumberReg = 0;
+ break;
+ }
- DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
- Srb->PathId,
- Srb->TargetId,
- Srb->Lun);
+ Srb->TargetId = InParams.bDriveNumber;
+
+ /* Set pointer to data buffer. */
+ DeviceExtension->DataBuffer = (PUCHAR)OutParams->bBuffer;
- switch (Srb->Cdb[0])
- {
- case SCSIOP_INQUIRY:
- SrbStatus = AtapiInquiry(DeviceExtension,
- Srb);
- break;
+ DeviceExtension->CurrentSrb = Srb;
- case SCSIOP_READ_CAPACITY:
- SrbStatus = AtapiReadCapacity(DeviceExtension,
- Srb);
- break;
+ /* wait for BUSY to clear */
+ for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
+ {
+ Status = IDEReadStatus(DeviceExtension->CommandPortBase);
+ if (!(Status & IDE_SR_BUSY))
+ {
+ break;
+ }
+ ScsiPortStallExecution(10);
+ }
+ if (Retries >= IDE_MAX_BUSY_RETRIES)
+ {
+ DPRINT ("Drive is BUSY for too long\n");
+ return(SRB_STATUS_BUSY);
+ }
- case SCSIOP_READ:
- case SCSIOP_WRITE:
- SrbStatus = AtapiReadWrite(DeviceExtension,
- Srb);
- break;
+ /* Select the desired drive */
+ InParams.irDriveRegs.bDriveHeadReg = (InParams.bDriveNumber ? IDE_DH_DRV1 : IDE_DH_DRV0) | IDE_DH_FIXED;
+ IDEWriteDriveHead(DeviceExtension->CommandPortBase, InParams.irDriveRegs.bDriveHeadReg);
+ ScsiPortStallExecution(2);
- case SCSIOP_MODE_SENSE:
- case SCSIOP_TEST_UNIT_READY:
- case SCSIOP_VERIFY:
- case SCSIOP_START_STOP_UNIT:
- case SCSIOP_REQUEST_SENSE:
- break;
+ IDEWritePrecomp(DeviceExtension->CommandPortBase, InParams.irDriveRegs.bFeaturesReg);
+ IDEWriteSectorCount(DeviceExtension->CommandPortBase, InParams.irDriveRegs.bSectorCountReg);
+ IDEWriteSectorNum(DeviceExtension->CommandPortBase, InParams.irDriveRegs.bSectorNumberReg);
+ IDEWriteCylinderLow(DeviceExtension->CommandPortBase, InParams.irDriveRegs.bCylLowReg);
+ IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, InParams.irDriveRegs.bCylHighReg);
- default:
- DPRINT1("AtapiSendIdeCommand():unknown command %x\n",
- Srb->Cdb[0]);
- SrbStatus = SRB_STATUS_INVALID_REQUEST;
- break;
- }
+ AtapiExecuteCommand(DeviceExtension, InParams.irDriveRegs.bCommandReg, AtapiSmartInterrupt);
- DPRINT1("AtapiSendIdeCommand() done!\n");
+ /* Wait for interrupt. */
+ return SRB_STATUS_PENDING;
- return(SrbStatus);
}
-
static ULONG
-AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension,
- PSCSI_REQUEST_BLOCK Srb)
+AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb)
{
- PIDE_DRIVE_IDENTIFY DeviceParams;
- PINQUIRYDATA InquiryData;
- ULONG i;
-
- DPRINT1("SCSIOP_INQUIRY: TargetId: %lu\n", Srb->TargetId);
-
- if ((Srb->PathId != 0) ||
- (Srb->TargetId > 1) ||
- (Srb->Lun != 0) ||
- (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE))
- {
- return(SRB_STATUS_SELECTION_TIMEOUT);
- }
-
- InquiryData = Srb->DataBuffer;
- DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
+ UCHAR ByteCountHigh;
+ UCHAR ByteCountLow;
+ ULONG Retries;
+ ULONG CdbSize;
+ UCHAR Status;
- /* clear buffer */
- for (i = 0; i < Srb->DataTransferLength; i++)
- {
- ((PUCHAR)Srb->DataBuffer)[i] = 0;
- }
+ DPRINT("AtapiSendAtapiCommand() called!\n");
- /* set device class */
- if (DeviceExtension->DeviceAtapi[Srb->TargetId] == FALSE)
- {
- /* hard-disk */
- InquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
- }
- else
+ if (Srb->PathId != 0)
{
- /* FIXME: this is incorrect use SCSI-INQUIRY command!! */
- /* cdrom drive */
- InquiryData->DeviceType = READ_ONLY_DIRECT_ACCESS_DEVICE;
+ Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
+ return(SRB_STATUS_INVALID_PATH_ID);
}
- DPRINT("ConfigBits: 0x%x\n", DeviceParams->ConfigBits);
- if (DeviceParams->ConfigBits & 0x80)
+ if (Srb->TargetId > 1)
{
- DPRINT1("Removable media!\n");
- InquiryData->RemovableMedia = 1;
+ Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
+ return(SRB_STATUS_INVALID_TARGET_ID);
}
- for (i = 0; i < 20; i += 2)
+ if (Srb->Lun != 0)
{
- InquiryData->VendorId[i] =
- ((PUCHAR)DeviceParams->ModelNumber)[i];
- InquiryData->VendorId[i+1] =
- ((PUCHAR)DeviceParams->ModelNumber)[i+1];
+ Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
+ return(SRB_STATUS_INVALID_LUN);
}
- for (i = 0; i < 4; i++)
+ if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_PRESENT))
{
- InquiryData->ProductId[12+i] = ' ';
+ Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+ return(SRB_STATUS_NO_DEVICE);
}
- for (i = 0; i < 4; i += 2)
+ if (Srb->Cdb[0] == SCSIOP_MODE_SENSE)
{
- InquiryData->ProductRevisionLevel[i] =
- ((PUCHAR)DeviceParams->FirmwareRev)[i];
- InquiryData->ProductRevisionLevel[i+1] =
- ((PUCHAR)DeviceParams->FirmwareRev)[i+1];
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ return (SRB_STATUS_INVALID_REQUEST);
}
- return(SRB_STATUS_SUCCESS);
-}
+ DPRINT("AtapiSendAtapiCommand(): TargetId: %lu\n",
+ Srb->TargetId);
+ if (Srb->Cdb[0] == SCSIOP_INQUIRY)
+ return(AtapiInquiry(DeviceExtension,
+ Srb));
-static ULONG
-AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension,
- PSCSI_REQUEST_BLOCK Srb)
-{
- PREAD_CAPACITY_DATA CapacityData;
- PIDE_DRIVE_IDENTIFY DeviceParams;
- ULONG LastSector;
+ /* Set pointer to data buffer. */
+ DeviceExtension->DataBuffer = (PUCHAR)Srb->DataBuffer;
+ DeviceExtension->DataTransferLength = Srb->DataTransferLength;
+ DeviceExtension->CurrentSrb = Srb;
- DPRINT1("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb->TargetId);
+ DPRINT("BufferAddress %x, BufferLength %d\n", Srb->DataBuffer, Srb->DataTransferLength);
- if ((Srb->PathId != 0) ||
- (Srb->TargetId > 1) ||
- (Srb->Lun != 0) ||
- (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE))
+ /* Wait for BUSY to clear */
+ for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
+ {
+ Status = IDEReadStatus(DeviceExtension->CommandPortBase);
+ if (!(Status & IDE_SR_BUSY))
+ {
+ break;
+ }
+ ScsiPortStallExecution(10);
+ }
+ DPRINT("status=%02x\n", Status);
+ DPRINT("waited %ld usecs for busy to clear\n", Retries * 10);
+ if (Retries >= IDE_MAX_BUSY_RETRIES)
{
- return(SRB_STATUS_SELECTION_TIMEOUT);
+ DPRINT("Drive is BUSY for too long\n");
+ return(SRB_STATUS_BUSY);
}
+ /* Select the desired drive */
+ IDEWriteDriveHead(DeviceExtension->CommandPortBase,
+ IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
+ /* Wait a little while */
+ ScsiPortStallExecution(50);
+
+#if 0
+ /* Wait for BUSY to clear and DRDY to assert */
+ for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
+ {
+ Status = IDEReadStatus(DeviceExtension->CommandPortBase);
+ if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
+ {
+ break;
+ }
+ ScsiPortStallExecution(10);
+ }
+ DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
+ if (Retries >= IDE_MAX_BUSY_RETRIES)
+ {
+ DPRINT("Drive is BUSY for too long after drive select\n");
+ return(SRB_STATUS_BUSY);
+ }
+#endif
+
+#ifdef ENABLE_DMA
+ if ((DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_DMA_CMD) &&
+ (Srb->Cdb[0] == SCSIOP_READ || Srb->Cdb[0] == SCSIOP_WRITE))
+ {
+ DeviceExtension->UseDma = AtapiInitDma(DeviceExtension, Srb, Srb->SrbFlags & SRB_FLAGS_DATA_IN ? 1 << 3 : 0);
+ }
+ else
+ {
+ DeviceExtension->UseDma = FALSE;
+ }
+#endif
+
+ if (DeviceExtension->DataTransferLength < 0x10000)
+ {
+ ByteCountLow = (UCHAR)(DeviceExtension->DataTransferLength & 0xFF);
+ ByteCountHigh = (UCHAR)(DeviceExtension->DataTransferLength >> 8);
+ }
+ else
+ {
+ ByteCountLow = 0xFF;
+ ByteCountHigh = 0xFF;
+ }
+
+ /* Set feature register */
+#ifdef ENABLE_DMA
+ IDEWritePrecomp(DeviceExtension->CommandPortBase, DeviceExtension->UseDma ? 1 : 0);
+#else
+ IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
+#endif
+
+ /* Set command packet length */
+ IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, ByteCountHigh);
+ IDEWriteCylinderLow(DeviceExtension->CommandPortBase, ByteCountLow);
+
+ /* Issue command to drive */
+#ifdef ENABLE_DMA
+ if (DeviceExtension->UseDma)
+ {
+ AtapiExecuteCommand(DeviceExtension, IDE_CMD_PACKET, AtapiDmaPacketInterrupt);
+ }
+ else
+#endif
+ {
+ AtapiExecuteCommand(DeviceExtension, IDE_CMD_PACKET, AtapiPacketInterrupt);
+ }
+
+ /* Wait for DRQ to assert */
+ for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
+ {
+ Status = IDEReadStatus(DeviceExtension->CommandPortBase);
+ if ((Status & IDE_SR_DRQ))
+ {
+ break;
+ }
+ ScsiPortStallExecution(10);
+ }
+
+ /* Convert special SCSI SRBs to ATAPI format */
+ switch (Srb->Cdb[0])
+ {
+ case SCSIOP_FORMAT_UNIT:
+ case SCSIOP_MODE_SELECT:
+ AtapiScsiSrbToAtapi (Srb);
+ break;
+ }
+
+ CdbSize = ((DeviceExtension->DeviceParams[Srb->TargetId].ConfigBits & 0x3) == 1) ? 16 : 12;
+ DPRINT("CdbSize: %lu\n", CdbSize);
+
+ /* Write command packet */
+ IDEWriteBlock(DeviceExtension->CommandPortBase,
+ (PUSHORT)Srb->Cdb,
+ CdbSize);
+
+#ifdef ENABLE_DMA
+ if (DeviceExtension->UseDma)
+ {
+ UCHAR DmaCommand;
+ /* start DMA */
+ DmaCommand = IDEReadDMACommand(DeviceExtension->BusMasterRegisterBase);
+ IDEWriteDMACommand(DeviceExtension->BusMasterRegisterBase, DmaCommand|0x01);
+ }
+#endif
+ DPRINT("AtapiSendAtapiCommand() done\n");
+
+ return(SRB_STATUS_PENDING);
+}
+
+
+static ULONG
+AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb)
+{
+ ULONG SrbStatus = SRB_STATUS_SUCCESS;
+
+ DPRINT("AtapiSendIdeCommand() called!\n");
+
+ DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ if (Srb->PathId != 0)
+ {
+ Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
+ return(SRB_STATUS_INVALID_PATH_ID);
+ }
+
+ if (Srb->TargetId > 1)
+ {
+ Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
+ return(SRB_STATUS_INVALID_TARGET_ID);
+ }
+
+ if (Srb->Lun != 0)
+ {
+ Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
+ return(SRB_STATUS_INVALID_LUN);
+ }
+
+ if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_PRESENT))
+ {
+ Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+ return(SRB_STATUS_NO_DEVICE);
+ }
+
+ switch (Srb->Cdb[0])
+ {
+ case SCSIOP_INQUIRY:
+ SrbStatus = AtapiInquiry(DeviceExtension,
+ Srb);
+ break;
+
+ case SCSIOP_READ_CAPACITY:
+ SrbStatus = AtapiReadCapacity(DeviceExtension,
+ Srb);
+ break;
+
+ case SCSIOP_READ:
+ case SCSIOP_WRITE:
+ SrbStatus = AtapiReadWrite(DeviceExtension,
+ Srb);
+ break;
+
+ case SCSIOP_SYNCHRONIZE_CACHE:
+ SrbStatus = AtapiFlushCache(DeviceExtension,
+ Srb);
+ break;
+
+ case SCSIOP_TEST_UNIT_READY:
+ SrbStatus = AtapiTestUnitReady(DeviceExtension,
+ Srb);
+ break;
+
+ case SCSIOP_MODE_SENSE:
+
+ case SCSIOP_VERIFY:
+ case SCSIOP_START_STOP_UNIT:
+ case SCSIOP_REQUEST_SENSE:
+ break;
+
+ default:
+ DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
+ Srb->Cdb[0]);
+ SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ break;
+ }
+
+ DPRINT("AtapiSendIdeCommand() done!\n");
+
+ return(SrbStatus);
+}
+
+
+static ULONG
+AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension,
+ PSCSI_REQUEST_BLOCK Srb)
+{
+ PIDE_DRIVE_IDENTIFY DeviceParams;
+ PINQUIRYDATA InquiryData;
+
+ DPRINT("SCSIOP_INQUIRY: DeviceExtension %p TargetId: %lu\n",
+ DeviceExtension, Srb->TargetId);
+
+ InquiryData = Srb->DataBuffer;
+ DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
+
+ /* clear buffer */
+ memset(Srb->DataBuffer, 0, Srb->DataTransferLength);
+
+ /* set device class */
+ if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI)
+ {
+ /* get it from the ATAPI configuration word */
+ InquiryData->DeviceType = (DeviceParams->ConfigBits >> 8) & 0x1F;
+ DPRINT("Device class: %u\n", InquiryData->DeviceType);
+ }
+ else
+ {
+ /* hard-disk */
+ InquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
+ }
+
+ DPRINT("ConfigBits: 0x%x\n", DeviceParams->ConfigBits);
+ if (DeviceParams->ConfigBits & 0x80)
+ {
+ DPRINT("Removable media!\n");
+ InquiryData->RemovableMedia = 1;
+ }
+
+ memcpy(InquiryData->VendorId, DeviceParams->ModelNumber, 20);
+ IDESwapBytePairs(InquiryData->VendorId, 20);
+
+ memcpy(&InquiryData->ProductId[12], " ", 4);
+
+ memcpy(InquiryData->ProductRevisionLevel, DeviceParams->FirmwareRev, 4);
+ IDESwapBytePairs(InquiryData->ProductRevisionLevel, 4);
+
+ InquiryData->AdditionalLength = 31;
+
+ DPRINT("VendorId: '%.20s'\n", InquiryData->VendorId);
+
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ return(SRB_STATUS_SUCCESS);
+}
+
+
+static ULONG
+AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension,
+ PSCSI_REQUEST_BLOCK Srb)
+{
+ PREAD_CAPACITY_DATA CapacityData;
+ PIDE_DRIVE_IDENTIFY DeviceParams;
+ LARGE_INTEGER LastSector;
+
+ DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb->TargetId);
CapacityData = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
/* Calculate last sector (big-endian). */
if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
{
- LastSector = (ULONG)((DeviceParams->TMSectorCountHi << 16) +
- DeviceParams->TMSectorCountLo) - 1;
+ if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
+ {
+ ((PUSHORT)&LastSector)[0] = DeviceParams->Max48BitAddress[0];
+ ((PUSHORT)&LastSector)[1] = DeviceParams->Max48BitAddress[1];
+ ((PUSHORT)&LastSector)[2] = DeviceParams->Max48BitAddress[2];
+ ((PUSHORT)&LastSector)[3] = DeviceParams->Max48BitAddress[3];
+ LastSector.QuadPart -= 1;
+
+ }
+ else
+ {
+ LastSector.u.HighPart = 0;
+ LastSector.u.LowPart = (ULONG)((DeviceParams->TMSectorCountHi << 16) +
+ DeviceParams->TMSectorCountLo)-1;
+ }
}
else
{
- LastSector = (ULONG)(DeviceParams->LogicalCyls *
- DeviceParams->LogicalHeads *
- DeviceParams->SectorsPerTrack)-1;
+ LastSector.u.HighPart = 0;
+ LastSector.u.LowPart = (ULONG)(DeviceParams->LogicalCyls *
+ DeviceParams->LogicalHeads *
+ DeviceParams->SectorsPerTrack)-1;
+ }
+ if (LastSector.u.HighPart)
+ {
+ DPRINT1("Disk is too large for our implementation (%I64d sectors\n", LastSector.QuadPart);
+ KEBUGCHECK(0);
}
CapacityData->LogicalBlockAddress = (((PUCHAR)&LastSector)[0] << 24) |
LastSector,
CapacityData->LogicalBlockAddress);
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
return(SRB_STATUS_SUCCESS);
}
PSCSI_REQUEST_BLOCK Srb)
{
PIDE_DRIVE_IDENTIFY DeviceParams;
-
- ULONG StartingSector,i;
+ ULONG StartingSector;
ULONG SectorCount;
- UCHAR CylinderHigh;
- UCHAR CylinderLow;
+ UCHAR CylinderHigh[2];
+ UCHAR CylinderLow[2];
UCHAR DrvHead;
- UCHAR SectorNumber;
+ UCHAR SectorNumber[2];
UCHAR Command;
ULONG Retries;
UCHAR Status;
+ BOOLEAN (FASTCALL *Handler)(PATAPI_MINIPORT_EXTENSION DevExt);
-
- DPRINT1("AtapiReadWrite() called!\n");
-
- if ((Srb->PathId != 0) ||
- (Srb->TargetId > 1) ||
- (Srb->Lun != 0) ||
- (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE))
- {
- return(SRB_STATUS_SELECTION_TIMEOUT);
- }
-
+ DPRINT("AtapiReadWrite() called!\n");
DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
Srb->TargetId);
Srb->DataTransferLength,
SectorCount);
- if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
- {
- SectorNumber = StartingSector & 0xff;
- CylinderLow = (StartingSector >> 8) & 0xff;
- CylinderHigh = (StartingSector >> 16) & 0xff;
- DrvHead = ((StartingSector >> 24) & 0x0f) |
- (Srb->TargetId ? IDE_DH_DRV1 : 0) |
- IDE_DH_LBA;
- }
- else
- {
- SectorNumber = (StartingSector % DeviceParams->SectorsPerTrack) + 1;
- StartingSector /= DeviceParams->SectorsPerTrack;
- DrvHead = (StartingSector % DeviceParams->LogicalHeads) |
- (Srb->TargetId ? IDE_DH_DRV1 : 0);
- StartingSector /= DeviceParams->LogicalHeads;
- CylinderLow = StartingSector & 0xff;
- CylinderHigh = StartingSector >> 8;
- }
-
-
- if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
+ if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
{
- Command = IDE_CMD_READ;
- }
- else
- {
- Command = IDE_CMD_WRITE;
+ SectorNumber[0] = StartingSector & 0xff;
+ CylinderLow[0] = (StartingSector >> 8) & 0xff;
+ CylinderHigh[0] = (StartingSector >> 16) & 0xff;
+ SectorNumber[1] = (StartingSector >> 24) & 0xff;
+ CylinderLow[1] = 0;
+ CylinderHigh[1] = 0;
+ DrvHead = (Srb->TargetId ? IDE_DH_DRV1 : 0) | IDE_DH_LBA;
+#if 0
+ DPRINT("%s:BUS=%04x:DRV=%d:LBA48=1:BLK=%08d:SC=%02x:CM=%02x\n",
+ (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
+ DeviceExtension->CommandPortBase,
+ DrvHead & IDE_DH_DRV1 ? 1 : 0,
+ (SectorNumber[1] << 24) +
+ (CylinderHigh[0] << 16) + (CylinderLow[0] << 8) + DectorNumberLow[0],
+ SectorCount,
+ Command);
+#endif
}
-
- if (DrvHead & IDE_DH_LBA)
+ else if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
{
- DPRINT1("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
+ SectorNumber[0] = StartingSector & 0xff;
+ CylinderLow[0] = (StartingSector >> 8) & 0xff;
+ CylinderHigh[0] = (StartingSector >> 16) & 0xff;
+ SectorNumber[1] = 0;
+ CylinderLow[1] = 0;
+ CylinderHigh[1] = 0;
+ DrvHead = ((StartingSector >> 24) & 0x0f) |
+ (Srb->TargetId ? IDE_DH_DRV1 : 0) |
+ IDE_DH_LBA;
+
+ DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
(Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
DeviceExtension->CommandPortBase,
DrvHead & IDE_DH_DRV1 ? 1 : 0,
((DrvHead & 0x0f) << 24) +
- (CylinderHigh << 16) + (CylinderLow << 8) + SectorNumber,
+ (CylinderHigh[0] << 16) + (CylinderLow[0] << 8) + SectorNumber[0],
SectorCount,
Command);
}
else
{
- DPRINT1("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
+ SectorNumber[0] = (StartingSector % DeviceParams->SectorsPerTrack) + 1;
+ StartingSector /= DeviceParams->SectorsPerTrack;
+ DrvHead = (StartingSector % DeviceParams->LogicalHeads) |
+ (Srb->TargetId ? IDE_DH_DRV1 : 0);
+ StartingSector /= DeviceParams->LogicalHeads;
+ CylinderLow[0] = StartingSector & 0xff;
+ CylinderHigh[0] = StartingSector >> 8;
+ SectorNumber[1] = 0;
+ CylinderLow[1] = 0;
+ CylinderHigh[1] = 0;
+
+ DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
(Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
DeviceExtension->CommandPortBase,
- DrvHead & IDE_DH_DRV1 ? 1 : 0,
- CylinderHigh,
- CylinderLow,
+ DrvHead & IDE_DH_DRV1 ? 1 : 0,
+ CylinderHigh[0],
+ CylinderLow[0],
DrvHead & 0x0f,
- SectorNumber,
+ SectorNumber[0],
SectorCount,
Command);
}
/* Set pointer to data buffer. */
- DeviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer;
+ DeviceExtension->DataBuffer = (PUCHAR)Srb->DataBuffer;
+ DeviceExtension->DataTransferLength = Srb->DataTransferLength;
DeviceExtension->CurrentSrb = Srb;
- DeviceExtension->ExpectingInterrupt = TRUE;
-
-
/* wait for BUSY to clear */
for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
}
ScsiPortStallExecution(10);
}
- DPRINT ("status=%02x\n", Status);
- DPRINT ("waited %ld usecs for busy to clear\n", Retries * 10);
+ DPRINT("status=%02x\n", Status);
+ DPRINT("waited %ld usecs for busy to clear\n", Retries * 10);
if (Retries >= IDE_MAX_BUSY_RETRIES)
{
DPRINT ("Drive is BUSY for too long\n");
return(SRB_STATUS_BUSY);
-#if 0
- if (++ControllerExtension->Retries > IDE_MAX_CMD_RETRIES)
- {
- DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
- Irp = ControllerExtension->CurrentIrp;
- Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
- Irp->IoStatus.Information = 0;
-
- return FALSE;
- }
- else
- {
- DPRINT ("Beginning drive reset sequence\n");
- IDEBeginControllerReset(ControllerExtension);
-
- return TRUE;
- }
-#endif
}
/* Select the desired drive */
IDEWriteDriveHead(DeviceExtension->CommandPortBase,
IDE_DH_FIXED | DrvHead);
+ ScsiPortStallExecution(10);
+#if 0
/* wait for BUSY to clear and DRDY to assert */
for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
{
}
ScsiPortStallExecution(10);
}
- DPRINT ("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
+ DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
if (Retries >= IDE_MAX_BUSY_RETRIES)
{
- DPRINT ("Drive is BUSY for too long after drive select\n");
+ DPRINT("Drive is BUSY for too long after drive select\n");
return(SRB_STATUS_BUSY);
-#if 0
- if (ControllerExtension->Retries++ > IDE_MAX_CMD_RETRIES)
- {
- DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
- Irp = ControllerExtension->CurrentIrp;
- Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
- Irp->IoStatus.Information = 0;
-
- return FALSE;
- }
- else
- {
- DPRINT ("Beginning drive reset sequence\n");
- IDEBeginControllerReset(ControllerExtension);
-
- return TRUE;
- }
-#endif
}
+#endif
- if (Command == IDE_CMD_WRITE)
+ /* Setup command parameters */
+ if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
{
- DPRINT1("Write not implemented yet!\n");
- return(SRB_STATUS_SUCCESS);
+ IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
+ IDEWriteSectorCount(DeviceExtension->CommandPortBase, SectorCount >> 8);
+ IDEWriteSectorNum(DeviceExtension->CommandPortBase, SectorNumber[1]);
+ IDEWriteCylinderLow(DeviceExtension->CommandPortBase, CylinderLow[1]);
+ IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, CylinderHigh[1]);
}
- /* Indicate expecting an interrupt. */
- DeviceExtension->ExpectingInterrupt = TRUE;
-
- /* Setup command parameters */
IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
- IDEWriteSectorCount(DeviceExtension->CommandPortBase, SectorCount);
- IDEWriteSectorNum(DeviceExtension->CommandPortBase, SectorNumber);
- IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, CylinderHigh);
- IDEWriteCylinderLow(DeviceExtension->CommandPortBase, CylinderLow);
- IDEWriteDriveHead(DeviceExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
-
- /* Issue command to drive */
- IDEWriteCommand(DeviceExtension->CommandPortBase, Command);
-// ControllerExtension->TimerState = IDETimerCmdWait;
-// ControllerExtension->TimerCount = IDE_CMD_TIMEOUT;
-
-
- /* FIXME: Write data here! */
-
-
- DPRINT1("AtapiReadWrite() done!\n");
-
- /* Wait for interrupt. */
- return(SRB_STATUS_PENDING);
-}
+ IDEWriteSectorCount(DeviceExtension->CommandPortBase, SectorCount & 0xff);
+ IDEWriteSectorNum(DeviceExtension->CommandPortBase, SectorNumber[0]);
+ IDEWriteCylinderLow(DeviceExtension->CommandPortBase, CylinderLow[0]);
+ IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, CylinderHigh[0]);
+
+#ifdef ENABLE_DMA
+ if (DeviceExtension->PRDTable &&
+ DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_DMA_CMD)
+ {
+ DeviceExtension->UseDma = AtapiInitDma(DeviceExtension, Srb, Srb->SrbFlags & SRB_FLAGS_DATA_IN ? 1 << 3 : 0);
+ }
+ if (DeviceExtension->UseDma)
+ {
+ Handler = AtapiDmaInterrupt;
+ if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
+ {
+ Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_DMA_EXT : IDE_CMD_WRITE_DMA_EXT;
+ }
+ else
+ {
+ Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_DMA : IDE_CMD_WRITE_DMA;
+ }
+ }
+ else
+#endif
+ {
+ Handler = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? AtapiReadInterrupt : AtapiWriteInterrupt;
+ if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_MULTI_SECTOR_CMD)
+ {
+ if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
+ {
+ Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_MULTIPLE_EXT : IDE_CMD_WRITE_MULTIPLE_EXT;
+ }
+ else
+ {
+ Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_MULTIPLE : IDE_CMD_WRITE_MULTIPLE;
+ }
+ }
+ else
+ {
+ if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
+ {
+ Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_EXT : IDE_CMD_WRITE_EXT;
+ }
+ else
+ {
+ Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ : IDE_CMD_WRITE;
+ }
+ }
+ }
+
+ AtapiExecuteCommand(DeviceExtension, Command, Handler);
+
+#ifdef ENABLE_DMA
+ if (DeviceExtension->UseDma)
+ {
+ UCHAR DmaCommand;
+ /* start DMA */
+ DmaCommand = IDEReadDMACommand(DeviceExtension->BusMasterRegisterBase);
+ IDEWriteDMACommand(DeviceExtension->BusMasterRegisterBase, DmaCommand|0x01);
+ }
+ else
+#endif
+ {
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT)
+ {
+ /* Write data block */
+ PUCHAR TargetAddress;
+ ULONG TransferSize;
+
+ /* Wait for controller ready */
+ for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
+ {
+ UCHAR Status = IDEReadStatus(DeviceExtension->CommandPortBase);
+ if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
+ {
+ break;
+ }
+ ScsiPortStallExecution(10);
+ }
+ if (Retries >= IDE_MAX_WRITE_RETRIES)
+ {
+ DPRINT1("Drive is BUSY for too long after sending write command\n");
+ return(SRB_STATUS_BUSY);
+ }
+
+ /* Update DeviceExtension data */
+ TransferSize = DeviceExtension->TransferSize[Srb->TargetId];
+ if (DeviceExtension->DataTransferLength < TransferSize)
+ {
+ TransferSize = DeviceExtension->DataTransferLength;
+ }
+
+ TargetAddress = DeviceExtension->DataBuffer;
+ DeviceExtension->DataBuffer += TransferSize;
+ DeviceExtension->DataTransferLength -= TransferSize;
+
+ /* Write data block */
+ if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_DWORD_IO)
+ {
+ IDEWriteBlock32(DeviceExtension->CommandPortBase,
+ TargetAddress,
+ TransferSize);
+ }
+ else
+ {
+ IDEWriteBlock(DeviceExtension->CommandPortBase,
+ TargetAddress,
+ TransferSize);
+ }
+ }
+ }
+
+ DPRINT("AtapiReadWrite() done!\n");
+
+ /* Wait for interrupt. */
+ return(SRB_STATUS_PENDING);
+}
+
+
+static ULONG
+AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension,
+ PSCSI_REQUEST_BLOCK Srb)
+{
+ ULONG Retries;
+ UCHAR Status;
+
+ DPRINT("AtapiFlushCache() called!\n");
+ DPRINT("SCSIOP_SYNCRONIZE_CACHE: TargetId: %lu\n",
+ Srb->TargetId);
+
+ if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_NO_FLUSH)
+ {
+ /*
+ * NOTE: Don't flush the cache for CD/DVD drives. Although
+ * the ATAPI-6 standard allows that, it has been experimentally
+ * proved that it can damage some broken LG drives. Afterall
+ * it doesn't make sense to flush cache on devices we don't
+ * write to.
+ */
+
+ /* The device states it doesn't support the command or it is disabled */
+ DPRINT("The drive doesn't support FLUSH_CACHE\n");
+ return SRB_STATUS_INVALID_REQUEST;
+ }
+
+ /* Wait for BUSY to clear */
+ for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
+ {
+ Status = IDEReadStatus(DeviceExtension->CommandPortBase);
+ if (!(Status & IDE_SR_BUSY))
+ {
+ break;
+ }
+ ScsiPortStallExecution(10);
+ }
+ DPRINT("Status=%02x\n", Status);
+ DPRINT("Waited %ld usecs for busy to clear\n", Retries * 10);
+ if (Retries >= IDE_MAX_BUSY_RETRIES)
+ {
+ DPRINT1("Drive is BUSY for too long\n");
+ return(SRB_STATUS_BUSY);
+ }
+
+ /* Select the desired drive */
+ IDEWriteDriveHead(DeviceExtension->CommandPortBase,
+ IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
+ ScsiPortStallExecution(10);
+
+ /* Issue command to drive */
+ AtapiExecuteCommand(DeviceExtension,
+ DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS ? IDE_CMD_FLUSH_CACHE_EXT : IDE_CMD_FLUSH_CACHE,
+ AtapiNoDataInterrupt);
+
+
+ DPRINT("AtapiFlushCache() done!\n");
+
+ /* Wait for interrupt. */
+ return(SRB_STATUS_PENDING);
+}
+
+
+static ULONG
+AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension,
+ PSCSI_REQUEST_BLOCK Srb)
+{
+ ULONG Retries;
+ UCHAR Status;
+ UCHAR Error;
+
+ DPRINT1("AtapiTestUnitReady() called!\n");
+
+ DPRINT1("SCSIOP_TEST_UNIT_READY: TargetId: %lu\n",
+ Srb->TargetId);
+
+ /* Return success if media status is not supported */
+ if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_MEDIA_STATUS))
+ {
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ return(SRB_STATUS_SUCCESS);
+ }
+
+ /* Wait for BUSY to clear */
+ for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
+ {
+ Status = IDEReadStatus(DeviceExtension->CommandPortBase);
+ if (!(Status & IDE_SR_BUSY))
+ {
+ break;
+ }
+ ScsiPortStallExecution(10);
+ }
+ DPRINT1("Status=%02x\n", Status);
+ DPRINT1("Waited %ld usecs for busy to clear\n", Retries * 10);
+ if (Retries >= IDE_MAX_BUSY_RETRIES)
+ {
+ DPRINT1("Drive is BUSY for too long\n");
+ return(SRB_STATUS_BUSY);
+ }
+
+ /* Select the desired drive */
+ IDEWriteDriveHead(DeviceExtension->CommandPortBase,
+ IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
+ ScsiPortStallExecution(10);
+
+ /* Issue command to drive */
+ AtapiExecuteCommand(DeviceExtension, IDE_CMD_GET_MEDIA_STATUS, AtapiNoDataInterrupt);
+
+ /* Wait for controller ready */
+ for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
+ {
+ Status = IDEReadStatus(DeviceExtension->CommandPortBase);
+ if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
+ {
+ break;
+ }
+ ScsiPortStallExecution(10);
+ }
+ if (Retries >= IDE_MAX_WRITE_RETRIES)
+ {
+ DPRINT1("Drive is BUSY for too long after sending write command\n");
+ DeviceExtension->Handler = NULL;
+ return(SRB_STATUS_BUSY);
+ }
+
+ if (Status & IDE_SR_ERR)
+ {
+ Error = IDEReadError(DeviceExtension->CommandPortBase);
+ if (Error == IDE_ER_UNC)
+ {
+CHECKPOINT1;
+ /* Handle write protection 'error' */
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ DeviceExtension->Handler = NULL;
+ return(SRB_STATUS_SUCCESS);
+ }
+ else
+ {
+CHECKPOINT1;
+ /* Indicate expecting an interrupt. */
+ return(SRB_STATUS_PENDING);
+ }
+ }
+
+ DeviceExtension->Handler = NULL;
+
+ DPRINT1("AtapiTestUnitReady() done!\n");
+
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ return(SRB_STATUS_SUCCESS);
+}
+
+
+static UCHAR
+AtapiErrorToScsi(PVOID DeviceExtension,
+ PSCSI_REQUEST_BLOCK Srb)
+{
+ PATAPI_MINIPORT_EXTENSION DevExt;
+ ULONG CommandPortBase;
+ ULONG ControlPortBase;
+ UCHAR ErrorReg;
+ UCHAR ScsiStatus;
+ UCHAR SrbStatus;
+
+ DPRINT("AtapiErrorToScsi() called\n");
+
+ DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
+
+ CommandPortBase = DevExt->CommandPortBase;
+ ControlPortBase = DevExt->ControlPortBase;
+
+ ErrorReg = IDEReadError(CommandPortBase);
+
+ if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI)
+ {
+ switch (ErrorReg >> 4)
+ {
+ case SCSI_SENSE_NO_SENSE:
+ DPRINT("ATAPI error: SCSI_SENSE_NO_SENSE\n");
+ ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ SrbStatus = SRB_STATUS_ERROR;
+ break;
+
+ case SCSI_SENSE_RECOVERED_ERROR:
+ DPRINT("ATAPI error: SCSI_SENSE_RECOVERED_SENSE\n");
+ ScsiStatus = 0;
+ SrbStatus = SRB_STATUS_SUCCESS;
+ break;
+
+ case SCSI_SENSE_NOT_READY:
+ DPRINT("ATAPI error: SCSI_SENSE_NOT_READY\n");
+ ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ SrbStatus = SRB_STATUS_ERROR;
+ break;
+
+ case SCSI_SENSE_MEDIUM_ERROR:
+ DPRINT("ATAPI error: SCSI_SENSE_MEDIUM_ERROR\n");
+ ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ SrbStatus = SRB_STATUS_ERROR;
+ break;
+
+ case SCSI_SENSE_HARDWARE_ERROR:
+ DPRINT("ATAPI error: SCSI_SENSE_HARDWARE_ERROR\n");
+ ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ SrbStatus = SRB_STATUS_ERROR;
+ break;
+
+ case SCSI_SENSE_ILLEGAL_REQUEST:
+ DPRINT("ATAPI error: SCSI_SENSE_ILLEGAL_REQUEST\n");
+ ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ SrbStatus = SRB_STATUS_ERROR;
+ break;
+
+ case SCSI_SENSE_UNIT_ATTENTION:
+ DPRINT("ATAPI error: SCSI_SENSE_UNIT_ATTENTION\n");
+ ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ SrbStatus = SRB_STATUS_ERROR;
+ break;
+
+ case SCSI_SENSE_DATA_PROTECT:
+ DPRINT("ATAPI error: SCSI_SENSE_DATA_PROTECT\n");
+ ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ SrbStatus = SRB_STATUS_ERROR;
+ break;
+
+ case SCSI_SENSE_BLANK_CHECK:
+ DPRINT("ATAPI error: SCSI_SENSE_BLANK_CHECK\n");
+ ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ SrbStatus = SRB_STATUS_ERROR;
+ break;
+
+ case SCSI_SENSE_ABORTED_COMMAND:
+ DPRINT("ATAPI error: SCSI_SENSE_ABORTED_COMMAND\n");
+ ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ SrbStatus = SRB_STATUS_ERROR;
+ break;
+
+ default:
+ DPRINT("ATAPI error: Invalid sense key\n");
+ ScsiStatus = 0;
+ SrbStatus = SRB_STATUS_ERROR;
+ break;
+ }
+ }
+ else
+ {
+ DPRINT1("IDE error: %02x\n", ErrorReg);
+
+ ScsiStatus = 0;
+ SrbStatus = SRB_STATUS_ERROR;
+
+#if 0
+ UCHAR SectorCount, SectorNum, CylinderLow, CylinderHigh;
+ UCHAR DriveHead;
+
+ CylinderLow = IDEReadCylinderLow(CommandPortBase);
+ CylinderHigh = IDEReadCylinderHigh(CommandPortBase);
+ DriveHead = IDEReadDriveHead(CommandPortBase);
+ SectorCount = IDEReadSectorCount(CommandPortBase);
+ SectorNum = IDEReadSectorNum(CommandPortBase);
+
+ DPRINT1("IDE Error: ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
+ ErrorReg,
+ CylinderLow,
+ CylinderHigh,
+ SectorCount,
+ SectorNum);
+#endif
+ }
+
+
+
+ Srb->ScsiStatus = ScsiStatus;
+
+ DPRINT("AtapiErrorToScsi() done\n");
+
+ return(SrbStatus);
+}
+
+
+static VOID
+AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb)
+{
+ DPRINT("AtapiConvertScsiToAtapi() called\n");
+
+ Srb->CdbLength = 12;
+
+ switch (Srb->Cdb[0])
+ {
+ case SCSIOP_FORMAT_UNIT:
+ Srb->Cdb[0] = ATAPI_FORMAT_UNIT;
+ break;
+
+ case SCSIOP_MODE_SELECT:
+ {
+ PATAPI_MODE_SELECT12 AtapiModeSelect;
+ UCHAR Length;
+
+ AtapiModeSelect = (PATAPI_MODE_SELECT12)Srb->Cdb;
+ Length = ((PCDB)Srb->Cdb)->MODE_SELECT.ParameterListLength;
+
+ RtlZeroMemory (Srb->Cdb,
+ MAXIMUM_CDB_SIZE);
+ AtapiModeSelect->OperationCode = ATAPI_MODE_SELECT;
+ AtapiModeSelect->PFBit = 1;
+ AtapiModeSelect->ParameterListLengthMsb = 0;
+ AtapiModeSelect->ParameterListLengthLsb = Length;
+ }
+ break;
+ }
+}
+
+static VOID FASTCALL
+AtapiCompleteRequest(PATAPI_MINIPORT_EXTENSION DevExt,
+ UCHAR SrbStatus)
+{
+ PSCSI_REQUEST_BLOCK Srb;
+ Srb = DevExt->CurrentSrb;
+
+ DPRINT("AtapiCompleteRequest(DevExt %x, SrbStatus %x)\n", DevExt, SrbStatus);
+
+ Srb->SrbStatus = SrbStatus;
+ if (SrbStatus == SRB_STATUS_ERROR)
+ {
+ Srb->SrbStatus = AtapiErrorToScsi((PVOID)DevExt, Srb);
+ }
+ else if (SrbStatus == SRB_STATUS_DATA_OVERRUN)
+ {
+ Srb->DataTransferLength -= DevExt->DataTransferLength;
+ }
+
+ DevExt->Handler = NULL;
+ ScsiPortNotification(RequestComplete, (PVOID)DevExt, Srb);
+ ScsiPortNotification(NextRequest, (PVOID)DevExt, NULL);
+}
+
+#ifdef ENABLE_DMA
+static BOOLEAN FASTCALL
+AtapiDmaPacketInterrupt(PATAPI_MINIPORT_EXTENSION DevExt)
+{
+ UCHAR SrbStatus;
+ UCHAR DmaCommand;
+ UCHAR DmaStatus;
+ UCHAR Status;
+ UCHAR Error;
+ UCHAR SensKey;
+
+ DPRINT("AtapiPacketDmaInterrupt\n");
+
+ DevExt->UseDma = FALSE;
+
+ /* stop DMA */
+ DmaCommand = IDEReadDMACommand(DevExt->BusMasterRegisterBase);
+ IDEWriteDMACommand(DevExt->BusMasterRegisterBase, DmaCommand & 0xfe);
+ /* get DMA status */
+ DmaStatus = IDEReadDMAStatus(DevExt->BusMasterRegisterBase);
+ /* clear the INTR & ERROR bits */
+ IDEWriteDMAStatus(DevExt->BusMasterRegisterBase, DmaStatus | 0x06);
+
+ Status = IDEReadStatus(DevExt->CommandPortBase);
+ DPRINT("DriveStatus: %x\n", Status);
+
+ if (Status & (IDE_SR_BUSY|IDE_SR_ERR))
+ {
+ if (Status & IDE_SR_ERR)
+ {
+ Error = IDEReadError(DevExt->CommandPortBase);
+ SensKey = Error >> 4;
+ DPRINT("DriveError: %x, SenseKey: %x\n", Error, SensKey);
+ }
+ SrbStatus = SRB_STATUS_ERROR;
+ }
+ else
+ {
+ if ((DmaStatus & 0x07) != 0x04)
+ {
+ DPRINT("DmaStatus: %02x\n", DmaStatus);
+ SrbStatus = SRB_STATUS_ERROR;
+ }
+ else
+ {
+ SrbStatus = STATUS_SUCCESS;
+ }
+ }
+ AtapiCompleteRequest(DevExt, SrbStatus);
+ DPRINT("AtapiDmaPacketInterrupt() done\n");
+ return TRUE;
+}
+#endif
+
+static BOOLEAN FASTCALL
+AtapiPacketInterrupt(PATAPI_MINIPORT_EXTENSION DevExt)
+{
+ PSCSI_REQUEST_BLOCK Srb;
+ UCHAR Status;
+ UCHAR IntReason;
+ ULONG TransferSize;
+ ULONG JunkSize = 0;
+ BOOLEAN IsLastBlock;
+ PUCHAR TargetAddress;
+ ULONG Retries;
+ UCHAR SrbStatus;
+ UCHAR Error;
+ UCHAR SensKey;
+
+ DPRINT("AtapiPacketInterrupt()\n");
+
+ Srb = DevExt->CurrentSrb;
+
+ Status = IDEReadStatus(DevExt->CommandPortBase);
+ DPRINT("DriveStatus: %x\n", Status);
+
+ if (Status & (IDE_SR_BUSY|IDE_SR_ERR))
+ {
+ if (Status & IDE_SR_ERR)
+ {
+ Error = IDEReadError(DevExt->CommandPortBase);
+ SensKey = Error >> 4;
+ DPRINT("DriveError: %x, SenseKey: %x\n", Error, SensKey);
+ }
+
+ AtapiCompleteRequest(DevExt, SRB_STATUS_ERROR);
+ DPRINT("AtapiPacketInterrupt() done\n");
+ return TRUE;
+ }
+
+ IntReason = IDEReadSectorCount(DevExt->CommandPortBase);
+ TransferSize = IDEReadCylinderLow(DevExt->CommandPortBase);
+ TransferSize += IDEReadCylinderHigh(DevExt->CommandPortBase) << 8;
+
+ if (!(Status & IDE_SR_DRQ))
+ {
+ if (DevExt->DataTransferLength > 0)
+ {
+ DPRINT1("AtapiPacketInterrupt: data underrun (%d bytes), command was %02x\n",
+ DevExt->DataTransferLength, Srb->Cdb[0]);
+ SrbStatus = SRB_STATUS_DATA_OVERRUN;
+ }
+ else
+ {
+ SrbStatus = SRB_STATUS_SUCCESS;
+ }
+ AtapiCompleteRequest(DevExt, SrbStatus);
+ DPRINT("AtapiPacketInterrupt() done\n");
+ return TRUE;
+ }
+
+ TargetAddress = DevExt->DataBuffer;
+
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
+ {
+ DPRINT("read data\n");
+ if (DevExt->DataTransferLength <= TransferSize)
+ {
+ JunkSize = TransferSize - DevExt->DataTransferLength;
+ TransferSize = DevExt->DataTransferLength;
+
+ DevExt->DataTransferLength = 0;
+ IsLastBlock = TRUE;
+ }
+ else
+ {
+ DevExt->DataTransferLength -= TransferSize;
+ IsLastBlock = FALSE;
+ }
+
+ DPRINT("TargetAddress %x, TransferSize %d\n", TargetAddress, TransferSize);
+
+ DevExt->DataBuffer += TransferSize;
+
+ IDEReadBlock(DevExt->CommandPortBase, TargetAddress, TransferSize);
+
+ /* check DRQ */
+ if (IsLastBlock)
+ {
+ /* Read remaining junk from device */
+ while (JunkSize > 0)
+ {
+ IDEReadWord(DevExt->CommandPortBase);
+ JunkSize -= 2;
+ }
+
+ for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES && (IDEReadStatus(DevExt->CommandPortBase) & IDE_SR_BUSY); Retries++)
+ {
+ ScsiPortStallExecution(10);
+ }
+
+ /* Check for data overrun */
+ while (IDEReadStatus(DevExt->CommandPortBase) & IDE_SR_DRQ)
+ {
+ DPRINT1("AtapiInterrupt(): reading overrun data!\n");
+ IDEReadWord(DevExt->CommandPortBase);
+ }
+ }
+
+ SrbStatus = SRB_STATUS_SUCCESS;
+ }
+ else if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT)
+ {
+ DPRINT("write data\n");
+ if (DevExt->DataTransferLength < TransferSize)
+ {
+ TransferSize = DevExt->DataTransferLength;
+ }
+
+ TargetAddress = DevExt->DataBuffer;
+
+ DPRINT("TargetAddress %x, TransferSize %x\n", TargetAddress, TransferSize);
+
+ DevExt->DataBuffer += TransferSize;
+ DevExt->DataTransferLength -= TransferSize;
+
+ /* Write the sector */
+ IDEWriteBlock(DevExt->CommandPortBase, TargetAddress, TransferSize);
+ SrbStatus = SRB_STATUS_SUCCESS;
+ IsLastBlock = FALSE;
+ }
+ else
+ {
+ DPRINT("Unspecified transfer direction!\n");
+ SrbStatus = SRB_STATUS_SUCCESS;
+ IsLastBlock = TRUE;
+ }
+ if (IsLastBlock)
+ {
+ AtapiCompleteRequest(DevExt, SrbStatus);
+ }
+ DPRINT("AtapiPacketInterrupt() done\n");
+ return TRUE;
+}
+
+static BOOLEAN FASTCALL
+AtapiNoDataInterrupt(PATAPI_MINIPORT_EXTENSION DevExt)
+{
+ UCHAR Status;
+
+ DPRINT("AtapiNoDataInterrupt()\n");
+
+ Status = IDEReadStatus(DevExt->CommandPortBase);
+ AtapiCompleteRequest(DevExt,
+ (Status & (IDE_SR_DRDY|IDE_SR_BUSY|IDE_SR_ERR|IDE_SR_DRQ)) == IDE_SR_DRDY ? SRB_STATUS_SUCCESS : SRB_STATUS_ERROR);
+
+ DPRINT("AtapiNoDatanterrupt() done!\n");
+ return TRUE;
+}
+
+#ifdef ENABLE_DMA
+static BOOLEAN FASTCALL
+AtapiDmaInterrupt(PATAPI_MINIPORT_EXTENSION DevExt)
+{
+ UCHAR DmaCommand;
+ UCHAR DmaStatus;
+ UCHAR Status;
+
+ DPRINT("AtapiDmaInterrupt()\n");
+
+ DevExt->UseDma = FALSE;
+ /* stop DMA */
+ DmaCommand = IDEReadDMACommand(DevExt->BusMasterRegisterBase);
+ IDEWriteDMACommand(DevExt->BusMasterRegisterBase, DmaCommand & 0xfe);
+ /* get DMA status */
+ DmaStatus = IDEReadDMAStatus(DevExt->BusMasterRegisterBase);
+ /* clear the INTR & ERROR bits */
+ IDEWriteDMAStatus(DevExt->BusMasterRegisterBase, DmaStatus | 0x06);
+
+ /* read the drive status */
+ Status = IDEReadStatus(DevExt->CommandPortBase);
+ if ((Status & (IDE_SR_DRDY|IDE_SR_BUSY|IDE_SR_ERR|IDE_SR_WERR|IDE_SR_DRQ)) == IDE_SR_DRDY &&
+ (DmaStatus & 0x07) == 4)
+ {
+ AtapiCompleteRequest(DevExt, SRB_STATUS_SUCCESS);
+ DPRINT("AtapiDmaInterrupt() done\n");
+ return TRUE;
+ }
+ DPRINT1("Status %x\n", Status);
+ DPRINT1("%x\n", DmaStatus);
+ AtapiCompleteRequest(DevExt, SRB_STATUS_ERROR);
+ DPRINT1("AtapiDmaReadInterrupt() done\n");
+ return TRUE;
+}
+#endif
+
+static BOOLEAN FASTCALL
+AtapiSmartInterrupt(PATAPI_MINIPORT_EXTENSION DevExt)
+{
+ PSCSI_REQUEST_BLOCK Srb;
+ UCHAR DeviceStatus;
+ PSRB_IO_CONTROL SrbIoControl;
+ PSENDCMDOUTPARAMS OutParams;
+ PIDEREGS IdeRegs;
+
+ DPRINT("AtapiSmartInterrupt() called!\n");
+
+ Srb = DevExt->CurrentSrb;
+
+
+ DeviceStatus = IDEReadStatus(DevExt->CommandPortBase);
+ if ((DeviceStatus & (IDE_SR_DRQ|IDE_SR_BUSY|IDE_SR_ERR)) != (DevExt->DataTransferLength ? IDE_SR_DRQ : 0))
+ {
+ if (DeviceStatus & (IDE_SR_ERR|IDE_SR_DRQ))
+ {
+ AtapiCompleteRequest(DevExt, SRB_STATUS_ERROR);
+ DPRINT("AtapiSmartInterrupt() done!\n");
+ return TRUE;
+ }
+ DPRINT("AtapiSmartInterrupt() done!\n");
+ return FALSE;
+ }
+
+ DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", DevExt->CommandPortBase, DevExt->ControlPortBase);
+
+ if (DevExt->DataTransferLength)
+ {
+ IDEReadBlock(DevExt->CommandPortBase, DevExt->DataBuffer, 512);
+ DevExt->DataTransferLength -= 512;
+ DevExt->DataBuffer += 512;
+ }
+
+ if (DevExt->DataTransferLength == 0)
+ {
+ SrbIoControl = (PSRB_IO_CONTROL)Srb->DataBuffer;
+ OutParams = (PSENDCMDOUTPARAMS)(SrbIoControl + 1);
+
+ OutParams->DriverStatus.bDriverError = 0;
+ OutParams->DriverStatus.bIDEError = 0;
+
+ if (SrbIoControl->ControlCode == IOCTL_SCSI_MINIPORT_RETURN_STATUS)
+ {
+ IdeRegs = (PIDEREGS)OutParams->bBuffer;
+
+ IdeRegs->bFeaturesReg = RETURN_SMART_STATUS;
+ IdeRegs->bSectorCountReg = IDEReadSectorCount(DevExt->CommandPortBase);
+ IdeRegs->bSectorNumberReg = IDEReadSectorNum(DevExt->CommandPortBase);
+ IdeRegs->bCylLowReg = IDEReadCylinderLow(DevExt->CommandPortBase);
+ IdeRegs->bCylHighReg = IDEReadCylinderHigh(DevExt->CommandPortBase);
+ IdeRegs->bDriveHeadReg = IDEReadDriveHead(DevExt->CommandPortBase);
+ IdeRegs->bCommandReg = SMART_CMD;
+ IdeRegs->bReserved = 0;
+
+ OutParams->cBufferSize = 8;
+ }
+ else
+ {
+ OutParams->cBufferSize = DevExt->DataBuffer - OutParams->bBuffer;
+ }
+
+ AtapiCompleteRequest(DevExt, SRB_STATUS_SUCCESS);
+ }
+
+ DPRINT("AtapiSmartInterrupt() done!\n");
+
+ return(TRUE);
+}
+
+
+static BOOLEAN FASTCALL
+AtapiReadInterrupt(PATAPI_MINIPORT_EXTENSION DevExt)
+{
+ PSCSI_REQUEST_BLOCK Srb;
+ UCHAR DeviceStatus;
+ BOOLEAN IsLastBlock;
+ PUCHAR TargetAddress;
+ ULONG TransferSize;
+
+ DPRINT("AtapiReadInterrupt() called!\n");
+
+ Srb = DevExt->CurrentSrb;
+
+ DeviceStatus = IDEReadStatus(DevExt->CommandPortBase);
+ if ((DeviceStatus & (IDE_SR_DRQ|IDE_SR_BUSY|IDE_SR_ERR)) != IDE_SR_DRQ)
+ {
+ if (DeviceStatus & (IDE_SR_ERR|IDE_SR_DRQ))
+ {
+ AtapiCompleteRequest(DevExt, SRB_STATUS_ERROR);
+ DPRINT("AtapiReadInterrupt() done!\n");
+ return TRUE;
+ }
+ DPRINT("AtapiReadInterrupt() done!\n");
+ return FALSE;
+ }
+
+ DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", DevExt->CommandPortBase, DevExt->ControlPortBase);
+
+ /* Update controller/device state variables */
+ TargetAddress = DevExt->DataBuffer;
+ TransferSize = DevExt->TransferSize[Srb->TargetId];
+
+ DPRINT("TransferLength: %lu\n", Srb->DataTransferLength);
+ DPRINT("TransferSize: %lu\n", TransferSize);
+
+ if (DevExt->DataTransferLength <= TransferSize)
+ {
+ TransferSize = DevExt->DataTransferLength;
+ DevExt->DataTransferLength = 0;
+ IsLastBlock = TRUE;
+ }
+ else
+ {
+ DevExt->DataTransferLength -= TransferSize;
+ IsLastBlock = FALSE;
+ }
+ DevExt->DataBuffer += TransferSize;
+ DPRINT("IsLastBlock == %s\n", (IsLastBlock) ? "TRUE" : "FALSE");
+
+ /* Copy the block of data */
+ if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_DWORD_IO)
+ {
+ IDEReadBlock32(DevExt->CommandPortBase, TargetAddress, TransferSize);
+ }
+ else
+ {
+ IDEReadBlock(DevExt->CommandPortBase, TargetAddress, TransferSize);
+ }
+
+ if (IsLastBlock)
+ {
+ AtapiCompleteRequest(DevExt, SRB_STATUS_SUCCESS);
+ }
+
+ DPRINT("AtapiReadInterrupt() done!\n");
+
+ return(TRUE);
+}
+
+static BOOLEAN FASTCALL
+AtapiWriteInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt)
+{
+ PSCSI_REQUEST_BLOCK Srb;
+ UCHAR DeviceStatus;
+ BOOLEAN IsLastBlock;
+ PUCHAR TargetAddress;
+ ULONG TransferSize;
+
+ DPRINT("AtapiWriteInterrupt() called!\n");
+
+ DeviceStatus = IDEReadStatus(DevExt->CommandPortBase);
+ if ((DeviceStatus & (IDE_SR_DRDY|IDE_SR_BUSY|IDE_SR_ERR|IDE_SR_WERR)) != IDE_SR_DRDY)
+ {
+ if (DeviceStatus & (IDE_SR_DRDY|IDE_SR_ERR|IDE_SR_WERR))
+ {
+ AtapiCompleteRequest(DevExt, SRB_STATUS_ERROR);
+ DPRINT("AtapiWriteInterrupt() done!\n");
+ return TRUE;
+ }
+ DPRINT("AtapiWriteInterrupt() done!\n");
+ return FALSE;
+ }
+ else
+ {
+ Srb = DevExt->CurrentSrb;
+ TransferSize = DevExt->TransferSize[Srb->TargetId];
+ if (DevExt->DataTransferLength < TransferSize)
+ {
+ TransferSize = DevExt->DataTransferLength;
+ }
+ if (TransferSize > 0 && (DeviceStatus & IDE_SR_DRQ))
+ {
+ IsLastBlock = FALSE;
+ TargetAddress = DevExt->DataBuffer;
+ DevExt->DataBuffer += TransferSize;
+ DevExt->DataTransferLength -= TransferSize;
+
+ DPRINT("TransferLength: %lu\n", Srb->DataTransferLength);
+ DPRINT("TransferSize: %lu\n", TransferSize);
+ /* Write the sector */
+ if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_DWORD_IO)
+ {
+ IDEWriteBlock32(DevExt->CommandPortBase, TargetAddress, TransferSize);
+ }
+ else
+ {
+ IDEWriteBlock(DevExt->CommandPortBase, TargetAddress, TransferSize);
+ }
+ }
+ else if (DeviceStatus & IDE_SR_DRQ)
+ {
+ DPRINT("AtapiWriteInterrupt(): data overrun error!\n");
+ IsLastBlock = TRUE;
+ }
+ else if (TransferSize > 0 && !(DeviceStatus & IDE_SR_DRQ))
+ {
+ DPRINT1("%d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", TransferSize);
+ IsLastBlock = TRUE;
+ }
+ else
+ {
+ IsLastBlock = TRUE;
+ }
+ if (IsLastBlock)
+ {
+ AtapiCompleteRequest(DevExt, SRB_STATUS_SUCCESS);
+ }
+ DPRINT("AtapiWriteInterrupt() done!\n");
+ return TRUE;
+ }
+}
+
+static VOID
+AtapiExecuteCommand(PATAPI_MINIPORT_EXTENSION DevExt,
+ UCHAR command,
+ BOOLEAN (FASTCALL *Handler)(PATAPI_MINIPORT_EXTENSION))
+{
+ if (DevExt->Handler != NULL)
+ {
+ DPRINT1("DevExt->Handler is already set!!\n");
+ }
+ DevExt->Handler = Handler;
+ IDEWriteCommand(DevExt->CommandPortBase, command);
+ ScsiPortStallExecution(1);
+}
+
+#ifdef ENABLE_DMA
+static BOOLEAN
+AtapiInitDma(PATAPI_MINIPORT_EXTENSION DevExt,
+ PSCSI_REQUEST_BLOCK Srb,
+ UCHAR cmd)
+{
+ PVOID StartAddress;
+ PVOID EndAddress;
+ PPRD PRDEntry = DevExt->PRDTable;
+ SCSI_PHYSICAL_ADDRESS PhysicalAddress;
+ ULONG Length;
+ ULONG tmpLength;
+ UCHAR Status;
+
+ DPRINT("AtapiInitDma()\n");
+
+ StartAddress = Srb->DataBuffer;
+ EndAddress = (PVOID)((ULONG_PTR)StartAddress + Srb->DataTransferLength);
+ DevExt->PRDCount = 0;
+
+ while (StartAddress < EndAddress)
+ {
+ PhysicalAddress = ScsiPortGetPhysicalAddress(DevExt, Srb, StartAddress, &Length);
+ if (PhysicalAddress.QuadPart == 0LL || Length == 0)
+ {
+ return FALSE;
+ }
+
+ while (Length)
+ {
+ /* calculate the length up to the next 64k boundary */
+ tmpLength = 0x10000 - (PhysicalAddress.u.LowPart & 0xffff);
+ if (tmpLength > Length)
+ {
+ tmpLength = Length;
+ }
+ DevExt->PRDCount++;
+ if (DevExt->PRDCount > DevExt->PRDMaxCount)
+ {
+ return FALSE;
+ }
+ if (tmpLength == 0x10000)
+ {
+ /* Some dirty controllers cannot handle 64k transfers. We split a 64k transfer in two 32k. */
+ tmpLength = 0x8000;
+ DPRINT("PRD Nr. %d VirtualAddress %08x PhysicalAddress %08x, Length %04x\n",
+ DevExt->PRDCount - 1, StartAddress, PhysicalAddress.u.LowPart, tmpLength);
+ PRDEntry->PhysAddress = PhysicalAddress.u.LowPart;
+ PRDEntry->Length = tmpLength;
+ PRDEntry++;
+ DevExt->PRDCount++;
+ if (DevExt->PRDCount > DevExt->PRDMaxCount)
+ {
+ return FALSE;
+ }
+ PhysicalAddress.u.LowPart += tmpLength;
+ StartAddress = (PVOID)((ULONG_PTR)StartAddress + tmpLength);
+ Length -= tmpLength;
+ PRDEntry->PhysAddress = PhysicalAddress.u.LowPart;
+ }
+ DPRINT("PRD Nr. %d VirtualAddress %08x PhysicalAddress %08x, Length %04x\n",
+ DevExt->PRDCount - 1, StartAddress, PhysicalAddress.u.LowPart, tmpLength);
+ PRDEntry->PhysAddress = PhysicalAddress.u.LowPart;
+ PRDEntry->Length = tmpLength;
+ PRDEntry++;
+ StartAddress = (PVOID)((ULONG_PTR)StartAddress + tmpLength);
+ PhysicalAddress.u.LowPart += tmpLength;
+ Length -= tmpLength;
+ }
+ }
+ /* set the end marker in the last PRD */
+ PRDEntry--;
+ PRDEntry->Length |= 0x80000000;
+ /* set the PDR table */
+ IDEWritePRDTable(DevExt->BusMasterRegisterBase, DevExt->PRDTablePhysicalAddress.u.LowPart);
+ /* write the DMA command */
+ IDEWriteDMACommand(DevExt->BusMasterRegisterBase, cmd);
+ /* reset the status and interrupt bit */
+ Status = IDEReadDMAStatus(DevExt->BusMasterRegisterBase);
+ IDEWriteDMAStatus(DevExt->BusMasterRegisterBase, Status | 0x06);
+ return TRUE;
+}
+#endif
/* EOF */