You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4926 lines
142 KiB
4926 lines
142 KiB
|
|
/*++
|
|
|
|
Copyright (C) 1993-99 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
devpdo.c
|
|
|
|
Abstract:
|
|
|
|
--*/
|
|
|
|
#include "ideport.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
|
|
#pragma alloc_text(PAGE, IdeSendIdePassThrough)
|
|
#pragma alloc_text(PAGE, DeviceInitIdStrings)
|
|
#pragma alloc_text(PAGE, DeviceInitDeviceType)
|
|
#pragma alloc_text(PAGE, DeviceQueryDeviceRelations)
|
|
#pragma alloc_text(PAGE, DeviceUsageNotification)
|
|
#pragma alloc_text(PAGE, DeviceBuildStorageDeviceDescriptor)
|
|
#pragma alloc_text(PAGE, DeviceQueryPnPDeviceState)
|
|
#pragma alloc_text(PAGE, DeviceQueryCapabilities)
|
|
#pragma alloc_text(PAGE, DeviceBuildBusId)
|
|
#pragma alloc_text(PAGE, DeviceBuildCompatibleId)
|
|
#pragma alloc_text(PAGE, DeviceBuildHardwareId)
|
|
#pragma alloc_text(PAGE, DeviceBuildInstanceId)
|
|
#pragma alloc_text(PAGE, DeviceQueryId)
|
|
#pragma alloc_text(PAGE, DeviceQueryText)
|
|
#pragma alloc_text(PAGE, DeviceIdeTestUnitReady)
|
|
#pragma alloc_text(PAGE, DeviceQueryInitData)
|
|
#pragma alloc_text(PAGE, DeviceQueryStopRemoveDevice)
|
|
#pragma alloc_text(PAGE, DeviceStopDevice)
|
|
#pragma alloc_text(PAGE, DeviceScsiGetAddress)
|
|
#pragma alloc_text(PAGE, DeviceStorageQueryProperty)
|
|
#pragma alloc_text(PAGE, CopyField)
|
|
|
|
#pragma alloc_text(NONPAGE, DeviceIdeModeSelect)
|
|
#pragma alloc_text(NONPAGE, DeviceInitDeviceState)
|
|
#pragma alloc_text(NONPAGE, DeviceStartDeviceQueue)
|
|
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
PDEVICE_OBJECT
|
|
DeviceCreatePhysicalDeviceObject (
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PFDO_EXTENSION FdoExtension,
|
|
IN PUNICODE_STRING DeviceObjectName
|
|
)
|
|
{
|
|
PDEVICE_OBJECT physicalDeviceObject;
|
|
PPDO_EXTENSION pdoExtension;
|
|
NTSTATUS status;
|
|
|
|
physicalDeviceObject = NULL;
|
|
|
|
status = IoCreateDevice(
|
|
DriverObject, // our driver object
|
|
sizeof(PDO_EXTENSION), // size of our extension
|
|
DeviceObjectName, // our name
|
|
FILE_DEVICE_MASS_STORAGE, // device type
|
|
FILE_DEVICE_SECURE_OPEN, // device characteristics
|
|
FALSE, // not exclusive
|
|
&physicalDeviceObject // store new device object here
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// spinning up could take a lot of current;
|
|
//
|
|
physicalDeviceObject->Flags |= DO_POWER_INRUSH | DO_DIRECT_IO;
|
|
|
|
//
|
|
// fix up alignment requirement
|
|
//
|
|
physicalDeviceObject->AlignmentRequirement = FdoExtension->DeviceObject->AlignmentRequirement;
|
|
if (physicalDeviceObject->AlignmentRequirement < 1) {
|
|
physicalDeviceObject->AlignmentRequirement = 1;
|
|
}
|
|
|
|
pdoExtension = physicalDeviceObject->DeviceExtension;
|
|
RtlZeroMemory (pdoExtension, sizeof(PDO_EXTENSION));
|
|
|
|
//
|
|
// Keeping track of those device objects
|
|
//
|
|
pdoExtension->DriverObject = DriverObject;
|
|
pdoExtension->DeviceObject = physicalDeviceObject;
|
|
|
|
//
|
|
// keep track of our parent
|
|
//
|
|
pdoExtension->ParentDeviceExtension = FdoExtension;
|
|
|
|
//
|
|
// Dispatch Table
|
|
//
|
|
pdoExtension->DefaultDispatch = IdePortNoSupportIrp;
|
|
pdoExtension->PnPDispatchTable = PdoPnpDispatchTable;
|
|
pdoExtension->PowerDispatchTable = PdoPowerDispatchTable;
|
|
pdoExtension->WmiDispatchTable = PdoWmiDispatchTable;
|
|
|
|
//
|
|
// We have to be in this D0 state before we can be enumurated
|
|
//
|
|
pdoExtension->SystemPowerState = PowerSystemWorking;
|
|
pdoExtension->DevicePowerState = PowerDeviceD0;
|
|
}
|
|
|
|
return physicalDeviceObject;
|
|
}
|
|
|
|
NTSTATUS
|
|
DeviceStartDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PPDO_EXTENSION pdoExtension;
|
|
KEVENT event;
|
|
|
|
pdoExtension = RefPdoWithTag(
|
|
DeviceObject,
|
|
TRUE,
|
|
DeviceStartDevice
|
|
);
|
|
|
|
if (pdoExtension) {
|
|
|
|
KIRQL currentIrql;
|
|
|
|
// ISSUE: if we are not lun0, we really should wait for lun0 to start first
|
|
|
|
|
|
#if defined (IDEPORT_WMI_SUPPORT)
|
|
//
|
|
// register with WMI
|
|
//
|
|
if (!(pdoExtension->PdoState & PDOS_STARTED)) {
|
|
IdePortWmiRegister ((PDEVICE_EXTENSION_HEADER)pdoExtension);
|
|
}
|
|
else {
|
|
DebugPrint((1, "ATAPI: PDOe %x Didn't register for WMI\n", pdoExtension));
|
|
}
|
|
#endif // IDEPORT_WMI_SUPPORT
|
|
|
|
KeAcquireSpinLock(&pdoExtension->PdoSpinLock, ¤tIrql);
|
|
|
|
SETMASK (pdoExtension->PdoState, PDOS_STARTED);
|
|
CLRMASK (pdoExtension->PdoState, PDOS_STOPPED | PDOS_REMOVED | PDOS_SURPRISE_REMOVED | PDOS_DISABLED_BY_USER);
|
|
|
|
KeReleaseSpinLock(&pdoExtension->PdoSpinLock, currentIrql);
|
|
|
|
//
|
|
// need to init device with acpi GTF before processing
|
|
// the first request
|
|
//
|
|
// the assert could fire if the device is not powered up
|
|
// ignore the assert for the time being. Everything should
|
|
// work fine as the first request would power up the device
|
|
//
|
|
//ASSERT(pdoExtension->InitDeviceWithAcpiGtf == 0);
|
|
InterlockedIncrement (&pdoExtension->InitDeviceWithAcpiGtf);
|
|
|
|
//
|
|
// keep the device queue block until we can go through some
|
|
// init code
|
|
//
|
|
DeviceStopDeviceQueueSafe (pdoExtension, PDOS_QUEUE_FROZEN_BY_START, FALSE);
|
|
|
|
//
|
|
// clear the stop_device block
|
|
//
|
|
status = DeviceStartDeviceQueue (pdoExtension, PDOS_QUEUE_FROZEN_BY_STOP_DEVICE);
|
|
|
|
//
|
|
// init pdo with acpi bios _GTF data
|
|
//
|
|
KeInitializeEvent(&event,
|
|
NotificationEvent,
|
|
FALSE);
|
|
|
|
DeviceQueryInitData(
|
|
pdoExtension
|
|
);
|
|
|
|
//
|
|
// can't really tell if it is enabled or not
|
|
// assume it is.
|
|
//
|
|
pdoExtension->WriteCacheEnable = TRUE;
|
|
|
|
status = DeviceInitDeviceState(
|
|
pdoExtension,
|
|
DeviceInitCompletionRoutine,
|
|
&event
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
ASSERT(NT_SUCCESS(status));
|
|
DeviceInitCompletionRoutine (
|
|
&event,
|
|
status
|
|
);
|
|
|
|
} else {
|
|
|
|
KeWaitForSingleObject(&event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
|
|
//
|
|
// open the queue
|
|
//
|
|
DeviceStartDeviceQueue (pdoExtension, PDOS_QUEUE_FROZEN_BY_START);
|
|
|
|
|
|
UnrefPdoWithTag(
|
|
pdoExtension,
|
|
DeviceStartDevice
|
|
);
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
status = STATUS_DEVICE_DOES_NOT_EXIST;
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
DeviceStartDeviceQueue (
|
|
IN PPDO_EXTENSION PdoExtension,
|
|
IN ULONG StopFlagToClear
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
KIRQL currentIrql;
|
|
BOOLEAN restartQueue;
|
|
ULONG oldPdoState;
|
|
|
|
restartQueue = FALSE;
|
|
|
|
KeAcquireSpinLock(&PdoExtension->PdoSpinLock, ¤tIrql);
|
|
|
|
oldPdoState = PdoExtension->PdoState;
|
|
|
|
CLRMASK (PdoExtension->PdoState, StopFlagToClear);
|
|
|
|
if (PdoExtension->PdoState & PDOS_DEADMEAT) {
|
|
|
|
restartQueue = FALSE;
|
|
|
|
} else if ((oldPdoState & PDOS_MUST_QUEUE) !=
|
|
(PdoExtension->PdoState & PDOS_MUST_QUEUE)) {
|
|
|
|
//
|
|
// make sure we have actually cleared some
|
|
// PDOS_MUST_QUEUE bits.
|
|
//
|
|
if (!(PdoExtension->PdoState & PDOS_MUST_QUEUE)) {
|
|
|
|
restartQueue = TRUE;
|
|
}
|
|
}
|
|
|
|
KeReleaseSpinLock(&PdoExtension->PdoSpinLock, currentIrql);
|
|
|
|
//
|
|
// Restart queue
|
|
//
|
|
if (restartQueue) {
|
|
|
|
KeAcquireSpinLock(&PdoExtension->ParentDeviceExtension->SpinLock, ¤tIrql);
|
|
|
|
GetNextLuPendingRequest(PdoExtension->ParentDeviceExtension, PdoExtension);
|
|
|
|
KeLowerIrql(currentIrql);
|
|
|
|
DebugPrint ((DBG_PNP, "IdePort: pdo 0x%x is pnp started with 0x%x items queued\n", PdoExtension->DeviceObject, PdoExtension->NumberOfIrpQueued));
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DeviceStopDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PPDO_EXTENSION pdoExtension;
|
|
|
|
PAGED_CODE();
|
|
|
|
pdoExtension = RefPdoWithTag(
|
|
DeviceObject,
|
|
TRUE,
|
|
DeviceStopDevice
|
|
);
|
|
|
|
if (pdoExtension) {
|
|
|
|
DebugPrint ((
|
|
DBG_PNP,
|
|
"pdoe 0x%x 0x%x (%d, %d, %d) got a STOP device\n",
|
|
pdoExtension,
|
|
pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress,
|
|
pdoExtension->PathId,
|
|
pdoExtension->TargetId,
|
|
pdoExtension->Lun
|
|
));
|
|
|
|
status = DeviceStopDeviceQueueSafe (pdoExtension, PDOS_QUEUE_FROZEN_BY_STOP_DEVICE, FALSE);
|
|
UnrefPdoWithTag (
|
|
pdoExtension,
|
|
DeviceStopDevice
|
|
);
|
|
|
|
} else {
|
|
|
|
status = STATUS_DEVICE_DOES_NOT_EXIST;
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
DeviceStopDeviceQueueSafe (
|
|
IN PPDO_EXTENSION PdoExtension,
|
|
IN ULONG QueueStopFlag,
|
|
IN BOOLEAN LowMem
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PPDO_STOP_QUEUE_CONTEXT context;
|
|
KIRQL currentIrql;
|
|
BOOLEAN queueAlreadyBlocked = FALSE;
|
|
PENUMERATION_STRUCT enumStruct;
|
|
ULONG retryCount = 1;
|
|
ULONG locked;
|
|
|
|
ASSERT (PDOS_MUST_QUEUE & QueueStopFlag);
|
|
|
|
//
|
|
// make sure the queue is not already blocked for the same reason
|
|
//
|
|
ASSERT (!(PdoExtension->PdoState & QueueStopFlag));
|
|
|
|
if (LowMem) {
|
|
|
|
//
|
|
//Lock
|
|
//
|
|
ASSERT(InterlockedCompareExchange(&(PdoExtension->ParentDeviceExtension->EnumStructLock),
|
|
1, 0) == 0);
|
|
|
|
enumStruct=PdoExtension->ParentDeviceExtension->PreAllocEnumStruct;
|
|
if (enumStruct) {
|
|
context=enumStruct->StopQContext;
|
|
retryCount=5;
|
|
} else {
|
|
ASSERT(enumStruct);
|
|
LowMem=FALSE;
|
|
retryCount=1;
|
|
}
|
|
}
|
|
|
|
if (!LowMem) {
|
|
context = ExAllocatePool (NonPagedPool, sizeof(*context));
|
|
}
|
|
|
|
if (context) {
|
|
|
|
//
|
|
// check to see if queue is already blocked
|
|
//
|
|
KeAcquireSpinLock(&PdoExtension->PdoSpinLock, ¤tIrql);
|
|
if (PdoExtension->PdoState & (PDOS_MUST_QUEUE | PDOS_DEADMEAT)) {
|
|
|
|
SETMASK (PdoExtension->PdoState, QueueStopFlag);
|
|
queueAlreadyBlocked = TRUE;
|
|
}
|
|
KeReleaseSpinLock(&PdoExtension->PdoSpinLock, currentIrql);
|
|
|
|
RtlZeroMemory (context, sizeof (*context));
|
|
KeInitializeEvent(&context->Event,
|
|
NotificationEvent,
|
|
FALSE);
|
|
|
|
context->PdoExtension = PdoExtension;
|
|
context->QueueStopFlag = QueueStopFlag;
|
|
context->AtaPassThroughData.IdeReg.bReserved = ATA_PTFLAGS_NO_OP;
|
|
|
|
if (queueAlreadyBlocked) {
|
|
|
|
IdeStopQueueCompletionRoutine (
|
|
PdoExtension->DeviceObject,
|
|
context,
|
|
STATUS_SUCCESS
|
|
);
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
//
|
|
// send a no-op request to block the queue
|
|
//
|
|
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
//
|
|
// if lowMem=0, this loop will execute only once
|
|
//
|
|
while (status == STATUS_INSUFFICIENT_RESOURCES && retryCount--) {
|
|
status = IssueAsyncAtaPassThroughSafe (
|
|
PdoExtension->ParentDeviceExtension,
|
|
PdoExtension,
|
|
&context->AtaPassThroughData,
|
|
FALSE,
|
|
IdeStopQueueCompletionRoutine,
|
|
context,
|
|
TRUE, // TRUE really means complete this irp before starting a new one
|
|
DEFAULT_ATA_PASS_THROUGH_TIMEOUT,
|
|
LowMem
|
|
);
|
|
ASSERT (NT_SUCCESS(status));
|
|
|
|
if (status == STATUS_PENDING) {
|
|
|
|
KeWaitForSingleObject(&context->Event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
|
|
status = context->Status;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Don't free the context if it was Pre-alloced.
|
|
//
|
|
if (!LowMem) {
|
|
ExFreePool (context);
|
|
} else {
|
|
|
|
// Unlock
|
|
ASSERT(InterlockedCompareExchange(&(PdoExtension->ParentDeviceExtension->EnumStructLock),
|
|
0, 1) == 1);
|
|
}
|
|
|
|
} else {
|
|
|
|
status = STATUS_NO_MEMORY;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
IdeStopQueueCompletionRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PPDO_STOP_QUEUE_CONTEXT Context,
|
|
IN NTSTATUS Status
|
|
)
|
|
{
|
|
PPDO_EXTENSION pdoExtension;
|
|
KIRQL currentIrql;
|
|
|
|
pdoExtension = Context->PdoExtension;
|
|
Context->Status = Status;
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
KeAcquireSpinLock(&pdoExtension->PdoSpinLock, ¤tIrql);
|
|
|
|
if (Context->QueueStopFlag == PDOS_QUEUE_FROZEN_BY_STOP_DEVICE) {
|
|
|
|
SETMASK (pdoExtension->PdoState, PDOS_STOPPED);
|
|
}
|
|
|
|
SETMASK (pdoExtension->PdoState, Context->QueueStopFlag);
|
|
|
|
DebugPrint ((DBG_PNP, "IdePort: pdo 0x%x is pnp stopped with 0x%x items queued\n", DeviceObject, pdoExtension->NumberOfIrpQueued));
|
|
|
|
KeReleaseSpinLock(&pdoExtension->PdoSpinLock, currentIrql);
|
|
|
|
} else {
|
|
|
|
DebugPrint ((0, "IdePort: unable to stop pdo 0x%x\n", pdoExtension));
|
|
}
|
|
|
|
KeSetEvent (&Context->Event, 0, FALSE);
|
|
|
|
return;
|
|
}
|
|
|
|
NTSTATUS
|
|
DeviceRemoveDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PPDO_EXTENSION pdoExtension;
|
|
KIRQL currentIrql;
|
|
PDEVICE_OBJECT parentAttacheePdo;
|
|
BOOLEAN freePdo;
|
|
BOOLEAN callIoDeleteDevice;
|
|
BOOLEAN deregWmi = FALSE;
|
|
|
|
pdoExtension = RefPdoWithTag(
|
|
DeviceObject,
|
|
TRUE,
|
|
DeviceRemoveDevice
|
|
);
|
|
|
|
if (pdoExtension) {
|
|
|
|
PIO_STACK_LOCATION thisIrpSp;
|
|
|
|
thisIrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
|
|
if (thisIrpSp->MinorFunction == IRP_MN_SURPRISE_REMOVAL) {
|
|
|
|
//
|
|
// freeze the queue if it is a surprise remove. This is
|
|
// necessary since a surprise remove on the fdo would
|
|
// clear the interrupt object. Any request that gets
|
|
// sent down after the surprise remove will cause an access
|
|
// violation if it makes into startio.
|
|
//
|
|
DeviceStopDeviceQueueSafe(pdoExtension,
|
|
PDOS_QUEUE_FROZEN_BY_STOP_DEVICE,
|
|
TRUE
|
|
);
|
|
}
|
|
|
|
KeAcquireSpinLock(&pdoExtension->PdoSpinLock, ¤tIrql);
|
|
|
|
if (pdoExtension->PdoState & PDOS_NEED_RESCAN) {
|
|
|
|
CLRMASK (pdoExtension->PdoState, PDOS_NEED_RESCAN);
|
|
|
|
//
|
|
// get ready for IoInvalidateDeviceRelations
|
|
//
|
|
parentAttacheePdo = pdoExtension->ParentDeviceExtension->AttacheePdo;
|
|
|
|
} else {
|
|
|
|
parentAttacheePdo = NULL;
|
|
}
|
|
|
|
if (thisIrpSp->MinorFunction == IRP_MN_REMOVE_DEVICE) {
|
|
|
|
DebugPrint ((
|
|
DBG_PNP,
|
|
"pdoe 0x%x 0x%x (%d, %d, %d) got a REMOVE device\n",
|
|
pdoExtension,
|
|
pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress,
|
|
pdoExtension->PathId,
|
|
pdoExtension->TargetId,
|
|
pdoExtension->Lun
|
|
));
|
|
|
|
if (pdoExtension->PdoState & (PDOS_DEADMEAT | PDOS_SURPRISE_REMOVED)) {
|
|
|
|
SETMASK (pdoExtension->PdoState, PDOS_REMOVED);
|
|
|
|
if (pdoExtension->PdoState & PDOS_REPORTED_TO_PNP) {
|
|
|
|
freePdo = FALSE;
|
|
|
|
} else {
|
|
|
|
freePdo = TRUE;
|
|
}
|
|
|
|
} else {
|
|
|
|
SETMASK (pdoExtension->PdoState, PDOS_DISABLED_BY_USER);
|
|
freePdo = FALSE;
|
|
}
|
|
|
|
if ((pdoExtension->PdoState & PDOS_STARTED) &&
|
|
!(pdoExtension->PdoState & PDOS_SURPRISE_REMOVED)) {
|
|
deregWmi = TRUE;
|
|
}
|
|
CLRMASK (pdoExtension->PdoState, PDOS_STARTED);
|
|
|
|
//
|
|
// not claimed anymore
|
|
//
|
|
CLRMASK (pdoExtension->PdoState, PDOS_DEVICE_CLIAMED);
|
|
|
|
callIoDeleteDevice = TRUE;
|
|
|
|
} else {
|
|
|
|
DebugPrint ((
|
|
DBG_PNP,
|
|
"pdoe 0x%x 0x%x (%d, %d, %d) got a SURPRISE_REMOVE device\n",
|
|
pdoExtension,
|
|
pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress,
|
|
pdoExtension->PathId,
|
|
pdoExtension->TargetId,
|
|
pdoExtension->Lun
|
|
));
|
|
|
|
SETMASK (pdoExtension->PdoState, PDOS_SURPRISE_REMOVED | PDOS_DEADMEAT);
|
|
|
|
if (pdoExtension->PdoState & PDOS_STARTED) {
|
|
deregWmi = TRUE;
|
|
}
|
|
|
|
freePdo = TRUE;
|
|
freePdo = FALSE;
|
|
callIoDeleteDevice = FALSE;
|
|
}
|
|
|
|
KeReleaseSpinLock(&pdoExtension->PdoSpinLock, currentIrql);
|
|
|
|
#if defined (IDEPORT_WMI_SUPPORT)
|
|
//
|
|
// deregister with WMI
|
|
//
|
|
if (deregWmi) {
|
|
|
|
IdePortWmiDeregister ((PDEVICE_EXTENSION_HEADER)pdoExtension);
|
|
}
|
|
#endif // IDEPORT_WMI_SUPPORT
|
|
|
|
if (freePdo) {
|
|
|
|
status = FreePdoWithTag(
|
|
pdoExtension,
|
|
TRUE,
|
|
callIoDeleteDevice,
|
|
DeviceRemoveDevice
|
|
);
|
|
|
|
} else {
|
|
|
|
//
|
|
// release the pdo
|
|
//
|
|
UnrefPdoWithTag (
|
|
pdoExtension,
|
|
DeviceRemoveDevice
|
|
);
|
|
}
|
|
|
|
if (parentAttacheePdo) {
|
|
|
|
IoInvalidateDeviceRelations (
|
|
parentAttacheePdo,
|
|
BusRelations
|
|
);
|
|
}
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|
return STATUS_SUCCESS;
|
|
|
|
} // DeviceRemoveDevice
|
|
|
|
NTSTATUS
|
|
DeviceUsageNotification (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PPDO_EXTENSION pdoExtension;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
pdoExtension = RefPdoWithTag(
|
|
DeviceObject,
|
|
FALSE,
|
|
DeviceUsageNotification
|
|
);
|
|
status = Irp->IoStatus.Status;
|
|
|
|
if (pdoExtension) {
|
|
|
|
PIO_STACK_LOCATION irpSp;
|
|
PDEVICE_OBJECT targetDeviceObject;
|
|
IO_STATUS_BLOCK ioStatus;
|
|
PULONG deviceUsageCount;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypePaging) {
|
|
|
|
//
|
|
// Adjust the paging path count for this device.
|
|
//
|
|
deviceUsageCount = &pdoExtension->PagingPathCount;
|
|
|
|
//
|
|
// changing device state
|
|
//
|
|
IoInvalidateDeviceState(pdoExtension->DeviceObject);
|
|
|
|
} else if (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypeHibernation) {
|
|
|
|
//
|
|
// Adjust the paging path count for this device.
|
|
//
|
|
deviceUsageCount = &pdoExtension->HiberPathCount;
|
|
|
|
} else if (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypeDumpFile) {
|
|
|
|
//
|
|
// Adjust the paging path count for this device.
|
|
//
|
|
deviceUsageCount = &pdoExtension->CrashDumpPathCount;
|
|
|
|
} else {
|
|
|
|
deviceUsageCount = NULL;
|
|
DebugPrint ((DBG_ALWAYS,
|
|
"ATAPI: Unknown IRP_MN_DEVICE_USAGE_NOTIFICATION type: 0x%x\n",
|
|
irpSp->Parameters.UsageNotification.Type));
|
|
}
|
|
|
|
//
|
|
// get the top of parent's device stack
|
|
//
|
|
targetDeviceObject = IoGetAttachedDeviceReference(
|
|
pdoExtension->
|
|
ParentDeviceExtension->
|
|
DeviceObject);
|
|
|
|
|
|
ioStatus.Status = STATUS_NOT_SUPPORTED;
|
|
status = IdePortSyncSendIrp (targetDeviceObject, irpSp, &ioStatus);
|
|
|
|
ObDereferenceObject (targetDeviceObject);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
POWER_STATE powerState;
|
|
|
|
if (deviceUsageCount) {
|
|
|
|
IoAdjustPagingPathCount (
|
|
deviceUsageCount,
|
|
irpSp->Parameters.UsageNotification.InPath
|
|
);
|
|
}
|
|
|
|
if (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypeDumpFile) {
|
|
|
|
//
|
|
// reset the idle timeout to "forever"
|
|
//
|
|
DeviceRegisterIdleDetection (
|
|
pdoExtension,
|
|
DEVICE_VERY_LONG_IDLE_TIMEOUT,
|
|
DEVICE_VERY_LONG_IDLE_TIMEOUT
|
|
);
|
|
|
|
if (pdoExtension->IdleCounter) {
|
|
|
|
PoSetDeviceBusy (pdoExtension->IdleCounter);
|
|
}
|
|
|
|
//
|
|
// spin up the crash dump drive
|
|
//
|
|
powerState.DeviceState = PowerDeviceD0;
|
|
PoRequestPowerIrp (
|
|
pdoExtension->DeviceObject,
|
|
IRP_MN_SET_POWER,
|
|
powerState,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// release the pdo
|
|
//
|
|
UnrefPdoWithTag (
|
|
pdoExtension,
|
|
DeviceUsageNotification
|
|
);
|
|
|
|
} else {
|
|
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|
return status;
|
|
|
|
} // DeviceUsageNotification
|
|
|
|
NTSTATUS
|
|
DeviceQueryStopRemoveDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PPDO_EXTENSION pdoExtension;
|
|
PIO_STACK_LOCATION thisIrpSp;
|
|
|
|
PAGED_CODE();
|
|
|
|
thisIrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
pdoExtension = RefPdoWithTag(
|
|
DeviceObject,
|
|
TRUE,
|
|
DeviceQueryStopRemoveDevice
|
|
);
|
|
|
|
if (pdoExtension) {
|
|
|
|
if ((pdoExtension->PdoState & PDOS_LEGACY_ATTACHER) &&
|
|
(thisIrpSp->MinorFunction == IRP_MN_QUERY_REMOVE_DEVICE)) {
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
|
|
} else if (pdoExtension->PagingPathCount ||
|
|
pdoExtension->CrashDumpPathCount) {
|
|
|
|
//
|
|
// Check the paging path count for this device.
|
|
//
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
|
|
} else {
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
UnrefPdoWithTag (
|
|
pdoExtension,
|
|
DeviceQueryStopRemoveDevice
|
|
);
|
|
|
|
|
|
} else {
|
|
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
DebugPrint((1, "Query remove failed\n"));
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|
return status;
|
|
|
|
} // DeviceQueryStopRemoveDevice
|
|
|
|
NTSTATUS
|
|
DeviceQueryId (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION thisIrpSp;
|
|
PPDO_EXTENSION pdoExtension;
|
|
NTSTATUS status;
|
|
PWSTR idString;
|
|
|
|
PAGED_CODE();
|
|
|
|
thisIrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
|
|
idString = NULL;
|
|
status = STATUS_DEVICE_DOES_NOT_EXIST;
|
|
|
|
pdoExtension = RefPdoWithTag (
|
|
DeviceObject,
|
|
TRUE,
|
|
DeviceQueryId
|
|
);
|
|
if (pdoExtension) {
|
|
|
|
switch (thisIrpSp->Parameters.QueryId.IdType) {
|
|
|
|
case BusQueryDeviceID:
|
|
|
|
//
|
|
// Caller wants the bus ID of this device.
|
|
//
|
|
|
|
idString = DeviceBuildBusId(pdoExtension);
|
|
break;
|
|
|
|
case BusQueryInstanceID:
|
|
|
|
//
|
|
// Caller wants the unique id of the device
|
|
//
|
|
|
|
idString = DeviceBuildInstanceId(pdoExtension);
|
|
break;
|
|
|
|
case BusQueryCompatibleIDs:
|
|
|
|
//
|
|
// Caller wants the compatible id of the device
|
|
//
|
|
|
|
idString = DeviceBuildCompatibleId(pdoExtension);
|
|
break;
|
|
|
|
case BusQueryHardwareIDs:
|
|
|
|
//
|
|
// Caller wants the hardware id of the device
|
|
//
|
|
|
|
idString = DeviceBuildHardwareId(pdoExtension);
|
|
break;
|
|
|
|
default:
|
|
DebugPrint ((1, "ideport: QueryID type %d not supported\n", thisIrpSp->Parameters.QueryId.IdType));
|
|
status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
UnrefPdoWithTag(
|
|
pdoExtension,
|
|
DeviceQueryId
|
|
);
|
|
}
|
|
|
|
if( idString != NULL ){
|
|
Irp->IoStatus.Information = (ULONG_PTR) idString;
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|
return status;
|
|
|
|
} // DeviceQueryId
|
|
|
|
|
|
PWSTR
|
|
DeviceBuildBusId(
|
|
IN PPDO_EXTENSION pdoExtension
|
|
)
|
|
{
|
|
#define IDE_BUS_ID_PREFIX "IDE\\"
|
|
|
|
PUCHAR deviceTypeIdString;
|
|
ULONG deviceTypeIdLen;
|
|
UCHAR compatibleId[10];
|
|
|
|
|
|
USHORT idStringBufLen;
|
|
|
|
PUCHAR idString;
|
|
ANSI_STRING ansiBusIdString;
|
|
PWCHAR idWString;
|
|
UNICODE_STRING unicodeIdString;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// get the device type
|
|
//
|
|
deviceTypeIdString = (PUCHAR)IdePortGetDeviceTypeString (
|
|
pdoExtension->ScsiDeviceType
|
|
);
|
|
|
|
if (deviceTypeIdString == NULL) {
|
|
|
|
sprintf (compatibleId,
|
|
"Type%d",
|
|
pdoExtension->ScsiDeviceType);
|
|
|
|
deviceTypeIdString = compatibleId;
|
|
}
|
|
deviceTypeIdLen = strlen(deviceTypeIdString);
|
|
|
|
idStringBufLen = (USHORT)(strlen( IDE_BUS_ID_PREFIX ) +
|
|
deviceTypeIdLen +
|
|
sizeof (pdoExtension->FullVendorProductId) +
|
|
sizeof (pdoExtension->FullProductRevisionId) +
|
|
sizeof (pdoExtension->FullSerialNumber) +
|
|
1);
|
|
|
|
//
|
|
// get the string buffers
|
|
//
|
|
idWString = ExAllocatePool( PagedPool, idStringBufLen * sizeof(WCHAR));
|
|
idString = ExAllocatePool( PagedPool, idStringBufLen);
|
|
|
|
if (idString && idWString) {
|
|
|
|
//
|
|
// build the ansi string
|
|
//
|
|
sprintf(idString, IDE_BUS_ID_PREFIX);
|
|
|
|
CopyField(idString + strlen(idString),
|
|
deviceTypeIdString,
|
|
deviceTypeIdLen,
|
|
'_');
|
|
|
|
CopyField(idString + strlen(idString),
|
|
pdoExtension->FullVendorProductId,
|
|
sizeof (pdoExtension->FullVendorProductId) - sizeof(CHAR),
|
|
'_');
|
|
CopyField(idString + strlen(idString),
|
|
pdoExtension->FullProductRevisionId,
|
|
sizeof (pdoExtension->FullProductRevisionId) - sizeof(CHAR),
|
|
'_');
|
|
|
|
RtlInitAnsiString (
|
|
&ansiBusIdString,
|
|
idString
|
|
);
|
|
|
|
//
|
|
// build the unicode string
|
|
//
|
|
unicodeIdString.Length = 0;
|
|
unicodeIdString.MaximumLength = idStringBufLen * sizeof(WCHAR);
|
|
unicodeIdString.Buffer = (PWSTR) idWString;
|
|
|
|
RtlAnsiStringToUnicodeString(
|
|
&unicodeIdString,
|
|
&ansiBusIdString,
|
|
FALSE
|
|
);
|
|
|
|
unicodeIdString.Buffer[unicodeIdString.Length/sizeof(WCHAR)] = L'\0';
|
|
|
|
} else {
|
|
|
|
if (idWString) {
|
|
ExFreePool (idWString);
|
|
}
|
|
}
|
|
|
|
if (idString) {
|
|
ExFreePool (idString);
|
|
}
|
|
return idWString;
|
|
}
|
|
|
|
PWSTR
|
|
DeviceBuildInstanceId(
|
|
IN PPDO_EXTENSION pdoExtension
|
|
)
|
|
{
|
|
PWSTR idString;
|
|
USHORT idStringBufLen;
|
|
NTSTATUS status;
|
|
WCHAR ideNonUniqueIdFormat[] = L"%x.%x.%x";
|
|
|
|
PAGED_CODE();
|
|
|
|
idStringBufLen = (sizeof(pdoExtension->FullSerialNumber) + 1) * sizeof(WCHAR);
|
|
idString = ExAllocatePool (PagedPool, idStringBufLen);
|
|
if( idString == NULL ){
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Form the string and return it.
|
|
//
|
|
if (pdoExtension->FullSerialNumber[0]) {
|
|
|
|
ANSI_STRING ansiCompatibleIdString;
|
|
UNICODE_STRING unicodeIdString;
|
|
|
|
//
|
|
// unique id
|
|
//
|
|
RtlInitAnsiString (
|
|
&ansiCompatibleIdString,
|
|
pdoExtension->FullSerialNumber
|
|
);
|
|
|
|
unicodeIdString.Length = 0;
|
|
unicodeIdString.MaximumLength = idStringBufLen;
|
|
unicodeIdString.Buffer = idString;
|
|
|
|
RtlAnsiStringToUnicodeString(
|
|
&unicodeIdString,
|
|
&ansiCompatibleIdString,
|
|
FALSE
|
|
);
|
|
|
|
idString[unicodeIdString.Length / 2] = L'\0';
|
|
|
|
} else {
|
|
|
|
//
|
|
// non-unique id
|
|
//
|
|
swprintf( idString,
|
|
ideNonUniqueIdFormat,
|
|
pdoExtension->PathId,
|
|
pdoExtension->TargetId,
|
|
pdoExtension->Lun);
|
|
}
|
|
|
|
return idString;
|
|
}
|
|
|
|
PWSTR
|
|
DeviceBuildCompatibleId(
|
|
IN PPDO_EXTENSION pdoExtension
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PCSTR compatibleIdString;
|
|
|
|
ANSI_STRING ansiCompatibleIdString;
|
|
UNICODE_STRING unicodeIdString;
|
|
|
|
PWCHAR compIdStrings;
|
|
ULONG totalBufferLen;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (pdoExtension->ParentDeviceExtension->HwDeviceExtension->
|
|
DeviceFlags[pdoExtension->TargetId] & DFLAGS_LS120_FORMAT) {
|
|
|
|
//
|
|
// ls-120 drive detected
|
|
// return the special ls-120 compatible ID
|
|
//
|
|
compatibleIdString = SuperFloppyCompatibleIdString;
|
|
|
|
} else {
|
|
|
|
compatibleIdString = IdePortGetCompatibleIdString (pdoExtension->ScsiDeviceType);
|
|
|
|
}
|
|
|
|
|
|
RtlInitAnsiString (
|
|
&ansiCompatibleIdString,
|
|
compatibleIdString
|
|
);
|
|
|
|
totalBufferLen = RtlAnsiStringToUnicodeSize (
|
|
&ansiCompatibleIdString
|
|
);
|
|
|
|
unicodeIdString.Length = 0;
|
|
unicodeIdString.MaximumLength = (USHORT) totalBufferLen;
|
|
|
|
//
|
|
// null terminator
|
|
//
|
|
totalBufferLen += sizeof(WCHAR);
|
|
|
|
//
|
|
// multi-string null terminator
|
|
//
|
|
totalBufferLen += sizeof(WCHAR);
|
|
|
|
compIdStrings = ExAllocatePool (PagedPool, totalBufferLen);
|
|
|
|
if (compIdStrings) {
|
|
|
|
unicodeIdString.Buffer = compIdStrings;
|
|
} else {
|
|
|
|
unicodeIdString.Buffer = NULL;
|
|
}
|
|
|
|
if (unicodeIdString.Buffer) {
|
|
|
|
RtlAnsiStringToUnicodeString(
|
|
&unicodeIdString,
|
|
&ansiCompatibleIdString,
|
|
FALSE
|
|
);
|
|
|
|
unicodeIdString.Buffer[unicodeIdString.Length/2 + 0] = L'\0';
|
|
unicodeIdString.Buffer[unicodeIdString.Length/2 + 1] = L'\0';
|
|
}
|
|
|
|
return compIdStrings;
|
|
}
|
|
|
|
PWSTR
|
|
DeviceBuildHardwareId(
|
|
IN PPDO_EXTENSION pdoExtension
|
|
)
|
|
{
|
|
#define NUMBER_HARDWARE_STRINGS 5
|
|
|
|
ULONG i;
|
|
PWSTR idMultiString;
|
|
PWSTR idString;
|
|
UCHAR scratch[64];
|
|
ULONG idStringLen;
|
|
NTSTATUS status;
|
|
ANSI_STRING ansiCompatibleIdString;
|
|
UNICODE_STRING unicodeIdString;
|
|
|
|
PCSTR deviceTypeCompIdString;
|
|
UCHAR deviceTypeCompId[20];
|
|
PCSTR deviceTypeIdString;
|
|
UCHAR deviceTypeId[20];
|
|
|
|
UCHAR ScsiDeviceType;
|
|
|
|
PAGED_CODE();
|
|
|
|
ScsiDeviceType = pdoExtension->ScsiDeviceType;
|
|
|
|
idStringLen = (64 * NUMBER_HARDWARE_STRINGS + sizeof (UCHAR)) * sizeof (WCHAR);
|
|
idMultiString = ExAllocatePool (PagedPool, idStringLen);
|
|
if (idMultiString == NULL) {
|
|
|
|
return NULL;
|
|
}
|
|
|
|
deviceTypeIdString = IdePortGetDeviceTypeString(ScsiDeviceType);
|
|
if (deviceTypeIdString == NULL) {
|
|
|
|
sprintf (deviceTypeId,
|
|
"Type%d",
|
|
ScsiDeviceType);
|
|
|
|
deviceTypeIdString = deviceTypeId;
|
|
}
|
|
|
|
if (pdoExtension->ParentDeviceExtension->HwDeviceExtension->
|
|
DeviceFlags[pdoExtension->TargetId] & DFLAGS_LS120_FORMAT) {
|
|
|
|
//
|
|
// ls-120 drive detected
|
|
// return the special ls-120 compatible ID
|
|
//
|
|
deviceTypeCompIdString = SuperFloppyCompatibleIdString;
|
|
|
|
} else {
|
|
|
|
deviceTypeCompIdString = IdePortGetCompatibleIdString (ScsiDeviceType);
|
|
if (deviceTypeCompIdString == NULL) {
|
|
|
|
sprintf (deviceTypeCompId,
|
|
"GenType%d",
|
|
ScsiDeviceType);
|
|
|
|
deviceTypeCompIdString = deviceTypeCompId;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Zero out the string buffer
|
|
//
|
|
|
|
RtlZeroMemory(idMultiString, idStringLen);
|
|
idString = idMultiString;
|
|
|
|
for(i = 0; i < NUMBER_HARDWARE_STRINGS; i++) {
|
|
|
|
//
|
|
// Build each of the hardware id's
|
|
//
|
|
|
|
switch(i) {
|
|
|
|
//
|
|
// Bus + Dev Type + Vendor + Product + Revision
|
|
//
|
|
|
|
case 0: {
|
|
|
|
sprintf(scratch, "IDE\\%s", deviceTypeIdString);
|
|
|
|
CopyField(scratch + strlen(scratch),
|
|
pdoExtension->FullVendorProductId,
|
|
sizeof (pdoExtension->FullVendorProductId) - sizeof(CHAR),
|
|
'_');
|
|
CopyField(scratch + strlen(scratch),
|
|
pdoExtension->FullProductRevisionId,
|
|
sizeof (pdoExtension->FullProductRevisionId) - sizeof(CHAR),
|
|
'_');
|
|
break;
|
|
}
|
|
|
|
//
|
|
// bus + vendor + product + revision[0]
|
|
case 1: {
|
|
|
|
sprintf(scratch, "IDE\\");
|
|
|
|
CopyField(scratch + strlen(scratch),
|
|
pdoExtension->FullVendorProductId,
|
|
sizeof (pdoExtension->FullVendorProductId) - sizeof(CHAR),
|
|
'_');
|
|
CopyField(scratch + strlen(scratch),
|
|
pdoExtension->FullProductRevisionId,
|
|
sizeof (pdoExtension->FullProductRevisionId) - sizeof(CHAR),
|
|
'_');
|
|
break;
|
|
}
|
|
|
|
//
|
|
// bus + device + vendor + product
|
|
case 2: {
|
|
|
|
sprintf(scratch, "IDE\\%s", deviceTypeIdString);
|
|
|
|
CopyField(scratch + strlen(scratch),
|
|
pdoExtension->FullVendorProductId,
|
|
sizeof (pdoExtension->FullVendorProductId) - sizeof(CHAR),
|
|
'_');
|
|
break;
|
|
}
|
|
|
|
//
|
|
// vendor + product + revision[0] (win9x)
|
|
case 3: {
|
|
|
|
CopyField(scratch,
|
|
pdoExtension->FullVendorProductId,
|
|
sizeof (pdoExtension->FullVendorProductId) - sizeof(CHAR),
|
|
'_');
|
|
CopyField(scratch + strlen(scratch),
|
|
pdoExtension->FullProductRevisionId,
|
|
sizeof (pdoExtension->FullProductRevisionId) - sizeof(CHAR),
|
|
'_');
|
|
|
|
break;
|
|
}
|
|
|
|
case 4: {
|
|
|
|
strcpy(scratch, deviceTypeCompIdString);
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
RtlInitAnsiString (
|
|
&ansiCompatibleIdString,
|
|
scratch
|
|
);
|
|
|
|
unicodeIdString.Length = 0;
|
|
unicodeIdString.MaximumLength = (USHORT) RtlAnsiStringToUnicodeSize(
|
|
&ansiCompatibleIdString
|
|
);
|
|
unicodeIdString.Buffer = idString;
|
|
|
|
RtlAnsiStringToUnicodeString(
|
|
&unicodeIdString,
|
|
&ansiCompatibleIdString,
|
|
FALSE
|
|
);
|
|
|
|
idString[unicodeIdString.Length / 2] = L'\0';
|
|
idString += unicodeIdString.Length / 2+ 1;
|
|
}
|
|
idString[0] = L'\0';
|
|
|
|
return idMultiString;
|
|
|
|
#undef NUMBER_HARDWARE_STRINGS
|
|
}
|
|
|
|
|
|
VOID
|
|
CopyField(
|
|
IN PUCHAR Destination,
|
|
IN PUCHAR Source,
|
|
IN ULONG Count,
|
|
IN UCHAR Change
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will copy Count string bytes from Source to Destination. If
|
|
it finds a nul byte in the Source it will translate that and any subsequent
|
|
bytes into Change. It will also replace non-printable characters with the
|
|
specified character.
|
|
|
|
Arguments:
|
|
|
|
Destination - the location to copy bytes
|
|
|
|
Source - the location to copy bytes from
|
|
|
|
Count - the number of bytes to be copied
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i = 0;
|
|
BOOLEAN pastEnd = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
for(i = 0; i < Count; i++) {
|
|
|
|
if(!pastEnd) {
|
|
|
|
if(Source[i] == 0) {
|
|
|
|
pastEnd = TRUE;
|
|
|
|
Destination[i] = Change;
|
|
|
|
} else if ((Source[i] <= L' ') ||
|
|
(Source[i] > ((WCHAR)0x7f)) ||
|
|
(Source[i] == L',')) {
|
|
|
|
Destination[i] = Change;
|
|
|
|
} else {
|
|
|
|
Destination[i] = Source[i];
|
|
|
|
}
|
|
} else {
|
|
Destination[i] = Change;
|
|
}
|
|
}
|
|
|
|
Destination[i] = L'\0';
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
DeviceDeviceIoControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION thisIrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
PPDO_EXTENSION pdoExtension;
|
|
BOOLEAN passItToFdo;
|
|
PDEVICE_OBJECT parentDeviceObject;
|
|
NTSTATUS status;
|
|
ULONG controlCode;
|
|
|
|
|
|
controlCode = thisIrpSp->Parameters.DeviceIoControl.IoControlCode;
|
|
|
|
if ((DEVICE_TYPE_FROM_CTL_CODE(controlCode) != IOCTL_STORAGE_BASE) &&
|
|
(DEVICE_TYPE_FROM_CTL_CODE(controlCode) != IOCTL_SCSI_BASE)) {
|
|
|
|
status = Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// RefPdo makes sure that the pdo is not removed.
|
|
//
|
|
pdoExtension = RefPdoWithTag(
|
|
DeviceObject,
|
|
FALSE,
|
|
Irp
|
|
);
|
|
|
|
if (pdoExtension) {
|
|
|
|
passItToFdo = TRUE;
|
|
parentDeviceObject = pdoExtension->ParentDeviceExtension->DeviceObject;
|
|
|
|
switch (controlCode) {
|
|
|
|
case IOCTL_SCSI_PASS_THROUGH_DIRECT:
|
|
case IOCTL_SCSI_PASS_THROUGH:
|
|
|
|
status = PortSetPassThroughAddress(Irp,
|
|
pdoExtension->PathId,
|
|
pdoExtension->TargetId,
|
|
pdoExtension->Lun
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// pass it to fdo
|
|
//
|
|
passItToFdo = TRUE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Error - complete it
|
|
//
|
|
passItToFdo = FALSE;
|
|
Irp->IoStatus.Status = status;
|
|
}
|
|
|
|
break;
|
|
|
|
case IOCTL_ATA_PASS_THROUGH:
|
|
|
|
status = IdeAtaPassThroughSetPortAddress(Irp,
|
|
pdoExtension->PathId,
|
|
pdoExtension->TargetId,
|
|
pdoExtension->Lun
|
|
);
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// This was originally designed to handle the request
|
|
// at the FDO. It was later decided to restrict this
|
|
// to the PDO. The routine should be slightly re-designed
|
|
// for this case by removing set and get address and passing
|
|
// in the PDO to it. This will be done later
|
|
//
|
|
status = IdeHandleAtaPassThroughIoctl(
|
|
pdoExtension->ParentDeviceExtension,
|
|
Irp,
|
|
FALSE
|
|
);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Error - complete it
|
|
//
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
|
|
//
|
|
// don't pass it to the fdo.
|
|
//
|
|
passItToFdo = FALSE;
|
|
break;
|
|
|
|
case IOCTL_ATA_PASS_THROUGH_DIRECT:
|
|
|
|
status = IdeAtaPassThroughSetPortAddress(Irp,
|
|
pdoExtension->PathId,
|
|
pdoExtension->TargetId,
|
|
pdoExtension->Lun
|
|
);
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
status = IdeHandleAtaPassThroughIoctl(
|
|
pdoExtension->ParentDeviceExtension,
|
|
Irp,
|
|
TRUE
|
|
);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Error - complete it
|
|
//
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
|
|
//
|
|
// don't pass it to the fdo.
|
|
//
|
|
passItToFdo = FALSE;
|
|
break;
|
|
|
|
case IOCTL_IDE_PASS_THROUGH:
|
|
|
|
//
|
|
// Do not support this ioclt
|
|
//
|
|
|
|
//Irp->IoStatus.Status = IdeSendIdePassThrough(pdoExtension, Irp);
|
|
passItToFdo = FALSE;
|
|
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
break;
|
|
|
|
case IOCTL_SCSI_GET_ADDRESS:
|
|
|
|
passItToFdo = FALSE;
|
|
Irp->IoStatus.Status = DeviceScsiGetAddress(pdoExtension, Irp);
|
|
|
|
break;
|
|
|
|
case IOCTL_SCSI_GET_DUMP_POINTERS:
|
|
|
|
passItToFdo = FALSE;
|
|
Irp->IoStatus.Status = DeviceGetDumpPointers(pdoExtension, Irp);
|
|
|
|
break;
|
|
|
|
|
|
case IOCTL_STORAGE_QUERY_PROPERTY:
|
|
|
|
status = DeviceStorageQueryProperty(pdoExtension, Irp);
|
|
|
|
if (status == STATUS_NOT_SUPPORTED) {
|
|
|
|
//
|
|
// not supported - pass it to fdo
|
|
//
|
|
passItToFdo = TRUE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// handled here. complete it
|
|
//
|
|
passItToFdo = FALSE;
|
|
Irp->IoStatus.Status = status;
|
|
}
|
|
|
|
break;
|
|
|
|
case IOCTL_SCSI_MINIPORT:
|
|
case IOCTL_SCSI_GET_INQUIRY_DATA:
|
|
case IOCTL_SCSI_GET_CAPABILITIES:
|
|
|
|
//
|
|
// these need to be handled by the fdo
|
|
//
|
|
passItToFdo = TRUE;
|
|
break;
|
|
|
|
case IOCTL_SCSI_RESCAN_BUS:
|
|
default:
|
|
|
|
|
|
//
|
|
// do not pass down unknown ioctls to the fdo
|
|
// these ioctls should be sent directly to the fdo
|
|
//
|
|
passItToFdo = FALSE;
|
|
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
UnrefPdoWithTag( pdoExtension, Irp );
|
|
|
|
} else {
|
|
|
|
passItToFdo = FALSE;
|
|
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
|
|
}
|
|
|
|
if (passItToFdo) {
|
|
|
|
return IdePortDeviceControl (parentDeviceObject, Irp);
|
|
|
|
} else {
|
|
|
|
status = Irp->IoStatus.Status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
DeviceScsiGetAddress (
|
|
PPDO_EXTENSION PdoExtension,
|
|
PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION thisIrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
if(thisIrpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(SCSI_ADDRESS)) {
|
|
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
|
|
} else {
|
|
|
|
PSCSI_ADDRESS scsiAddress = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
scsiAddress->Length = sizeof(SCSI_ADDRESS);
|
|
scsiAddress->PortNumber = (UCHAR) PdoExtension->
|
|
ParentDeviceExtension->ScsiPortNumber;
|
|
scsiAddress->PathId = PdoExtension->PathId;
|
|
scsiAddress->TargetId = PdoExtension->TargetId;
|
|
scsiAddress->Lun = PdoExtension->Lun;
|
|
|
|
Irp->IoStatus.Information = sizeof(SCSI_ADDRESS);
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
DeviceGetDumpPointers(
|
|
PPDO_EXTENSION PdoExtension,
|
|
PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION thisIrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
NTSTATUS status;
|
|
|
|
//
|
|
// Get parameters for crash dump driver.
|
|
//
|
|
if (Irp->RequestorMode != KernelMode) {
|
|
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
} else if (thisIrpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(DUMP_POINTERS)) {
|
|
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
|
|
} else {
|
|
|
|
PCRASHDUMP_INIT_DATA dumpInitData;
|
|
|
|
//
|
|
// caller needs to free this
|
|
//
|
|
// ISSUE: make sure we tell the parent to power up
|
|
//
|
|
dumpInitData = ExAllocatePool (NonPagedPool,
|
|
sizeof (CRASHDUMP_INIT_DATA)
|
|
);
|
|
|
|
if (dumpInitData) {
|
|
|
|
PDUMP_POINTERS dumpPointers;
|
|
dumpPointers = (PDUMP_POINTERS)Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
RtlZeroMemory (dumpInitData, sizeof (CRASHDUMP_INIT_DATA));
|
|
dumpInitData->PathId = PdoExtension->PathId;
|
|
dumpInitData->TargetId = PdoExtension->TargetId;
|
|
dumpInitData->Lun = PdoExtension->Lun;
|
|
|
|
dumpInitData->LiveHwDeviceExtension =
|
|
PdoExtension->ParentDeviceExtension->HwDeviceExtension;
|
|
|
|
dumpPointers->AdapterObject = NULL;
|
|
dumpPointers->MappedRegisterBase = NULL;
|
|
dumpPointers->DumpData = dumpInitData;
|
|
dumpPointers->CommonBufferVa = NULL;
|
|
dumpPointers->CommonBufferPa.QuadPart = 0;
|
|
dumpPointers->CommonBufferSize = 0;
|
|
dumpPointers->DeviceObject = PdoExtension->DeviceObject;
|
|
dumpPointers->AllocateCommonBuffers = FALSE;
|
|
|
|
Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
IdeLogNoMemoryError(PdoExtension->ParentDeviceExtension,
|
|
PdoExtension->TargetId,
|
|
NonPagedPool,
|
|
sizeof(CRASHDUMP_INIT_DATA),
|
|
IDEPORT_TAG_DUMP_POINTER
|
|
);
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
DeviceStorageQueryProperty (
|
|
PPDO_EXTENSION PdoExtension,
|
|
PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION thisIrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
PSTORAGE_PROPERTY_QUERY storageQuery;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
storageQuery = Irp->AssociatedIrp.SystemBuffer;
|
|
status = STATUS_NOT_SUPPORTED;
|
|
|
|
if (thisIrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(STORAGE_PROPERTY_QUERY)) {
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
} else {
|
|
|
|
if (storageQuery->PropertyId == StorageDeviceProperty) { // device property
|
|
|
|
ULONG bufferSize;
|
|
|
|
switch (storageQuery->QueryType) {
|
|
case PropertyStandardQuery:
|
|
DebugPrint ((2,
|
|
"IdePortPdoDispatch: IOCTL_STORAGE_QUERY_PROPERTY PropertyStandardQuery\n"
|
|
));
|
|
|
|
bufferSize = thisIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
status = DeviceBuildStorageDeviceDescriptor(
|
|
PdoExtension,
|
|
(PSTORAGE_DEVICE_DESCRIPTOR) Irp->AssociatedIrp.SystemBuffer,
|
|
&bufferSize
|
|
);
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
Irp->IoStatus.Information = bufferSize;
|
|
}
|
|
|
|
break;
|
|
|
|
case PropertyExistsQuery:
|
|
DebugPrint ((2, "IdePortPdoDispatch: IOCTL_STORAGE_QUERY_PROPERTY PropertyExistsQuery\n"));
|
|
// ISSUE: Will be implemented when required
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case PropertyMaskQuery:
|
|
DebugPrint ((2, "IdePortPdoDispatch: IOCTL_STORAGE_QUERY_PROPERTY PropertyMaskQuery\n"));
|
|
//ISSUE: Will implement when required
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
default:
|
|
DebugPrint ((2, "IdePortPdoDispatch: IOCTL_STORAGE_QUERY_PROPERTY unknown type\n"));
|
|
// ISSUE: Will implement when required
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
DeviceBuildStorageDeviceDescriptor(
|
|
PPDO_EXTENSION pdoExtension,
|
|
IN OUT PSTORAGE_DEVICE_DESCRIPTOR StorageDeviceDescriptor,
|
|
IN OUT PULONG BufferSize
|
|
)
|
|
{
|
|
|
|
STORAGE_DEVICE_DESCRIPTOR localStorageDeviceDescriptor;
|
|
ULONG productIdLength;
|
|
ULONG revisionIdLength;
|
|
ULONG serialNumberLength;
|
|
PUCHAR bytebuffer;
|
|
ULONG byteLeft;
|
|
ULONG byteToCopy;
|
|
|
|
INQUIRYDATA InquiryData;
|
|
NTSTATUS status;
|
|
|
|
ASSERT (pdoExtension);
|
|
ASSERT (StorageDeviceDescriptor);
|
|
|
|
productIdLength = strlen(pdoExtension->FullVendorProductId) + sizeof(UCHAR);
|
|
revisionIdLength = strlen(pdoExtension->FullProductRevisionId) + sizeof(UCHAR);
|
|
serialNumberLength = strlen(pdoExtension->FullSerialNumber) + sizeof(UCHAR);
|
|
|
|
RtlZeroMemory (&localStorageDeviceDescriptor, sizeof (STORAGE_DEVICE_DESCRIPTOR));
|
|
localStorageDeviceDescriptor.Version = sizeof (STORAGE_DEVICE_DESCRIPTOR);
|
|
localStorageDeviceDescriptor.Size = sizeof (STORAGE_DEVICE_DESCRIPTOR) +
|
|
INQUIRYDATABUFFERSIZE +
|
|
productIdLength +
|
|
revisionIdLength +
|
|
serialNumberLength;
|
|
|
|
localStorageDeviceDescriptor.DeviceType = pdoExtension->ScsiDeviceType;
|
|
|
|
if (pdoExtension->
|
|
ParentDeviceExtension->
|
|
HwDeviceExtension->
|
|
DeviceFlags[pdoExtension->TargetId] &
|
|
DFLAGS_REMOVABLE_DRIVE) {
|
|
|
|
localStorageDeviceDescriptor.RemovableMedia = TRUE;
|
|
}
|
|
|
|
if (pdoExtension->
|
|
ParentDeviceExtension->
|
|
HwDeviceExtension->
|
|
DeviceFlags[pdoExtension->TargetId] &
|
|
DFLAGS_ATAPI_DEVICE) {
|
|
|
|
localStorageDeviceDescriptor.BusType = BusTypeAtapi;
|
|
} else {
|
|
|
|
localStorageDeviceDescriptor.BusType = BusTypeAta;
|
|
}
|
|
|
|
bytebuffer = (PUCHAR) StorageDeviceDescriptor;
|
|
byteLeft = *BufferSize;
|
|
|
|
//
|
|
// copy the basic STORAGE_DEVICE_DESCRIPTOR
|
|
//
|
|
if (byteLeft) {
|
|
|
|
byteToCopy = min(sizeof (STORAGE_DEVICE_DESCRIPTOR), byteLeft);
|
|
|
|
RtlCopyMemory (StorageDeviceDescriptor,
|
|
&localStorageDeviceDescriptor,
|
|
byteToCopy);
|
|
|
|
bytebuffer += byteToCopy;
|
|
byteLeft -= byteToCopy;
|
|
}
|
|
|
|
//
|
|
// copy raw device properties (Inquiry Data)
|
|
//
|
|
if (byteLeft) {
|
|
|
|
status = IssueInquirySafe(
|
|
pdoExtension->ParentDeviceExtension,
|
|
pdoExtension,
|
|
&InquiryData,
|
|
FALSE
|
|
);
|
|
|
|
if (NT_SUCCESS(status) || (status == STATUS_DATA_OVERRUN)) {
|
|
|
|
byteToCopy = min(INQUIRYDATABUFFERSIZE, byteLeft);
|
|
|
|
RtlCopyMemory (bytebuffer,
|
|
&InquiryData,
|
|
byteToCopy);
|
|
|
|
StorageDeviceDescriptor->RawPropertiesLength = byteToCopy;
|
|
|
|
bytebuffer += byteToCopy;
|
|
byteLeft -= byteToCopy;
|
|
}
|
|
}
|
|
|
|
//
|
|
// copy product ID
|
|
//
|
|
if (byteLeft) {
|
|
|
|
byteToCopy = min(productIdLength, byteLeft);
|
|
|
|
RtlCopyMemory (bytebuffer,
|
|
pdoExtension->FullVendorProductId,
|
|
byteToCopy);
|
|
bytebuffer[byteToCopy - 1] = '\0';
|
|
|
|
StorageDeviceDescriptor->ProductIdOffset = *BufferSize - byteLeft;
|
|
|
|
bytebuffer += byteToCopy;
|
|
byteLeft -= byteToCopy;
|
|
}
|
|
|
|
//
|
|
// copy revision ID
|
|
//
|
|
if (byteLeft) {
|
|
|
|
byteToCopy = min(productIdLength, byteLeft);
|
|
|
|
RtlCopyMemory (bytebuffer,
|
|
pdoExtension->FullProductRevisionId,
|
|
byteToCopy);
|
|
bytebuffer[byteToCopy - 1] = '\0';
|
|
|
|
StorageDeviceDescriptor->ProductRevisionOffset = *BufferSize - byteLeft;
|
|
|
|
bytebuffer += byteToCopy;
|
|
byteLeft -= byteToCopy;
|
|
}
|
|
|
|
//
|
|
// copy serial #
|
|
//
|
|
if (byteLeft) {
|
|
|
|
byteToCopy = min(serialNumberLength, byteLeft);
|
|
|
|
RtlCopyMemory (bytebuffer,
|
|
pdoExtension->FullSerialNumber,
|
|
byteToCopy);
|
|
bytebuffer[byteToCopy - 1] = '\0';
|
|
|
|
StorageDeviceDescriptor->SerialNumberOffset = *BufferSize - byteLeft;
|
|
|
|
bytebuffer += byteToCopy;
|
|
byteLeft -= byteToCopy;
|
|
}
|
|
|
|
*BufferSize -= byteLeft;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // DeviceBuildStorageDeviceDescriptor
|
|
|
|
|
|
NTSTATUS
|
|
DeviceQueryCapabilities (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION thisIrpSp;
|
|
PPDO_EXTENSION pdoExtension;
|
|
PDEVICE_CAPABILITIES capabilities;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
thisIrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
capabilities = thisIrpSp->Parameters.DeviceCapabilities.Capabilities;
|
|
|
|
pdoExtension = RefPdoWithTag (
|
|
DeviceObject,
|
|
TRUE,
|
|
DeviceQueryCapabilities
|
|
);
|
|
|
|
if (pdoExtension == NULL) {
|
|
|
|
status = STATUS_DEVICE_DOES_NOT_EXIST;
|
|
|
|
} else {
|
|
|
|
DEVICE_CAPABILITIES parentDeviceCapabilities;
|
|
|
|
status = IdeGetDeviceCapabilities(
|
|
pdoExtension->ParentDeviceExtension->AttacheePdo,
|
|
&parentDeviceCapabilities);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
RtlMoveMemory (
|
|
capabilities,
|
|
&parentDeviceCapabilities,
|
|
sizeof(DEVICE_CAPABILITIES));
|
|
|
|
if (pdoExtension->FullSerialNumber[0]) {
|
|
|
|
capabilities->UniqueID = TRUE;
|
|
} else {
|
|
|
|
capabilities->UniqueID = FALSE;
|
|
}
|
|
|
|
//
|
|
// never!
|
|
//
|
|
capabilities->Removable = FALSE;
|
|
capabilities->SurpriseRemovalOK = FALSE;
|
|
|
|
capabilities->Address = PNP_ADDRESS(pdoExtension->TargetId, pdoExtension->Lun);
|
|
capabilities->UINumber = pdoExtension->TargetId;
|
|
|
|
capabilities->D1Latency = 31 * (1000 * 10); // 31s
|
|
capabilities->D2Latency = 31 * (1000 * 10); // 31s
|
|
capabilities->D3Latency = 31 * (1000 * 10); // 31s
|
|
}
|
|
|
|
UnrefPdoWithTag (
|
|
pdoExtension,
|
|
DeviceQueryCapabilities
|
|
);
|
|
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
} // DeviceQueryCapabitilies
|
|
|
|
NTSTATUS
|
|
IdePortInsertByKeyDeviceQueue (
|
|
IN PPDO_EXTENSION PdoExtension,
|
|
IN PIRP Irp,
|
|
IN ULONG SortKey,
|
|
OUT PBOOLEAN Inserted
|
|
)
|
|
{
|
|
KIRQL currentIrql;
|
|
NTSTATUS status;
|
|
POWER_STATE powerState;
|
|
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb;
|
|
BOOLEAN urgentSrb;
|
|
|
|
status = STATUS_SUCCESS;
|
|
*Inserted = FALSE;
|
|
|
|
KeRaiseIrql(DISPATCH_LEVEL, ¤tIrql);
|
|
|
|
if (PdoExtension->LuFlags & PD_QUEUE_FROZEN) {
|
|
|
|
DebugPrint((1,"IdePortDispatch: Request put in frozen queue!\n"));
|
|
}
|
|
|
|
*Inserted = KeInsertByKeyDeviceQueue(
|
|
&PdoExtension->DeviceObject->DeviceQueue,
|
|
&Irp->Tail.Overlay.DeviceQueueEntry,
|
|
SortKey);
|
|
|
|
if (*Inserted == FALSE) {
|
|
|
|
//
|
|
// we need this check here because in the remove irp codepath
|
|
// setting the PDOS_REMOVED flag and flushing the queue are not
|
|
// atomic. If the queue is already flushed and there are no active
|
|
// requests, no one will pick this one up. If there is one active the
|
|
// flush would have cleared the queue busy and we could end up with
|
|
// two active requests simultaneously. If the PDOS_REMOVED flag is
|
|
// set then flush the queue to clear up any requests that got queued
|
|
// due to busy being set by this request. Note that if the flush in the
|
|
// remove happens after this it will just be an extra flush. No harm there
|
|
//
|
|
if (PdoExtension->PdoState & PDOS_REMOVED) {
|
|
|
|
//
|
|
// lower the irql
|
|
//
|
|
KeLowerIrql(currentIrql);
|
|
|
|
//
|
|
// The pdo has been removed. We have to flush any requests in
|
|
// the queue since the remove irp could be done with the flush
|
|
// already. Note that this will also clear the queue busy.
|
|
//
|
|
IdePortFlushLogicalUnit(PdoExtension->ParentDeviceExtension,
|
|
PdoExtension,
|
|
TRUE
|
|
);
|
|
|
|
//
|
|
// complete the request in hand
|
|
//
|
|
srb->SrbStatus = SRB_STATUS_REQUEST_FLUSHED;
|
|
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
|
|
|
|
|
|
UnrefLogicalUnitExtensionWithTag(
|
|
PdoExtension->ParentDeviceExtension,
|
|
PdoExtension,
|
|
Irp
|
|
);
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
//
|
|
// return true so that the dispatch routine doesn't attempt
|
|
// to send it down
|
|
//
|
|
*Inserted = TRUE;
|
|
|
|
return status;
|
|
}
|
|
|
|
if (PdoExtension->PdoState & PDOS_QUEUE_BLOCKED) {
|
|
|
|
ASSERT (PdoExtension->PendingRequest == NULL);
|
|
PdoExtension->PendingRequest = Irp;
|
|
*Inserted = TRUE;
|
|
|
|
if (!(PdoExtension->PdoState & PDOS_MUST_QUEUE)) {
|
|
|
|
|
|
|
|
//
|
|
// device is powered down
|
|
// use a large time in case it spins up slowly
|
|
//
|
|
if (srb->TimeOutValue < DEFAULT_SPINUP_TIME) {
|
|
|
|
srb->TimeOutValue = DEFAULT_SPINUP_TIME;
|
|
}
|
|
|
|
//
|
|
// We are not powered up.
|
|
// issue an power up
|
|
//
|
|
powerState.DeviceState = PowerDeviceD0;
|
|
status = PoRequestPowerIrp (
|
|
PdoExtension->DeviceObject,
|
|
IRP_MN_SET_POWER,
|
|
powerState,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
ASSERT (NT_SUCCESS(status));
|
|
|
|
DebugPrint ((2, "IdePort GetNextLuRequest: 0x%x 0x%x need to spin up device, requeue irp 0x%x\n",
|
|
PdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress,
|
|
PdoExtension->TargetId,
|
|
Irp));
|
|
}
|
|
|
|
} else if (srb->Function != SRB_FUNCTION_ATA_POWER_PASS_THROUGH) {
|
|
|
|
//
|
|
// If this irp is not for changing power state, we may have
|
|
// to queue it
|
|
//
|
|
if (PdoExtension->DevicePowerState != PowerDeviceD0) {
|
|
|
|
if (PdoExtension->DevicePowerState != PowerDeviceD3) {
|
|
|
|
//
|
|
// we are in D1 or D2.
|
|
// We can never be sure that we are in D0 when
|
|
// we tell the device to go from D1/D2 to D0.
|
|
// Some device lies and won't spin up until it sees
|
|
// a media access command. This causes longer time
|
|
// to execute the command
|
|
//
|
|
// to prevent the next command from timing out, we
|
|
// will increment its timeout
|
|
//
|
|
|
|
if (srb->TimeOutValue < 30) {
|
|
|
|
srb->TimeOutValue = 30;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We are not powered up.
|
|
// issue an power up
|
|
//
|
|
powerState.DeviceState = PowerDeviceD0;
|
|
status = PoRequestPowerIrp (
|
|
PdoExtension->DeviceObject,
|
|
IRP_MN_SET_POWER,
|
|
powerState,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
ASSERT (NT_SUCCESS(status));
|
|
status = STATUS_SUCCESS;
|
|
|
|
ASSERT (PdoExtension->PendingRequest == NULL);
|
|
PdoExtension->PendingRequest = Irp;
|
|
|
|
DebugPrint ((1, "IdePort IdePortInsertByKeyDeviceQueue: 0x%x 0x%x need to spin up device, requeue irp 0x%x\n",
|
|
PdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress,
|
|
PdoExtension->TargetId,
|
|
Irp));
|
|
|
|
*Inserted = TRUE;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
#if DBG
|
|
InterlockedIncrement (
|
|
&PdoExtension->NumberOfIrpQueued
|
|
);
|
|
#endif // DBG
|
|
|
|
}
|
|
|
|
KeLowerIrql(currentIrql);
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
DeviceInitCompletionRoutine (
|
|
PVOID Context,
|
|
NTSTATUS Status
|
|
)
|
|
{
|
|
PKEVENT event = Context;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
//ASSERT (!"DeviceInitDeviceState Failed\n");
|
|
DebugPrint((DBG_ALWAYS, "ATAPI: ERROR: DeviceInitDeviceStateFailed with Status %x\n",
|
|
Status));
|
|
}
|
|
|
|
KeSetEvent (event, 0, FALSE);
|
|
}
|
|
|
|
NTSTATUS
|
|
DeviceQueryText (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION thisIrpSp;
|
|
PPDO_EXTENSION pdoExtension;
|
|
PWCHAR returnString;
|
|
LONG i;
|
|
UNICODE_STRING unicodeString;
|
|
ANSI_STRING ansiString;
|
|
ULONG stringLen;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
thisIrpSp = IoGetCurrentIrpStackLocation (Irp);
|
|
|
|
returnString = NULL;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
pdoExtension = RefPdoWithTag (
|
|
DeviceObject,
|
|
TRUE,
|
|
DeviceQueryText
|
|
);
|
|
|
|
if (pdoExtension == NULL) {
|
|
|
|
status = STATUS_DEVICE_DOES_NOT_EXIST;
|
|
|
|
} else {
|
|
|
|
status = STATUS_NO_MEMORY;
|
|
|
|
if (thisIrpSp->Parameters.QueryDeviceText.DeviceTextType == DeviceTextDescription) {
|
|
|
|
stringLen = sizeof (pdoExtension->FullVendorProductId);
|
|
stringLen *= sizeof(WCHAR);
|
|
returnString = ExAllocatePool (
|
|
PagedPool,
|
|
stringLen
|
|
);
|
|
if (returnString) {
|
|
|
|
unicodeString.Length = 0;
|
|
unicodeString.MaximumLength = (USHORT) stringLen;
|
|
unicodeString.Buffer = returnString;
|
|
|
|
//
|
|
// vendor ID
|
|
//
|
|
RtlInitAnsiString (
|
|
&ansiString,
|
|
pdoExtension->FullVendorProductId
|
|
);
|
|
|
|
RtlAnsiStringToUnicodeString(
|
|
&unicodeString,
|
|
&ansiString,
|
|
FALSE
|
|
);
|
|
|
|
ASSERT(unicodeString.Length < unicodeString.MaximumLength);
|
|
//
|
|
// get rid of trailing spaces and nulls
|
|
//
|
|
for (i=(unicodeString.Length/2)-1; i >= 0; i--) {
|
|
|
|
if ((returnString[i] == ' ') || (returnString[i] == 0)) {
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// null terminate it
|
|
//
|
|
returnString[i + 1] = 0;
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
} else if (thisIrpSp->Parameters.QueryDeviceText.DeviceTextType == DeviceTextLocationInformation) {
|
|
|
|
stringLen = 100;
|
|
|
|
returnString = ExAllocatePool (
|
|
PagedPool,
|
|
stringLen
|
|
);
|
|
|
|
if (returnString) {
|
|
|
|
wcscpy(returnString,
|
|
(((pdoExtension->TargetId & 0x1) == 0) ? L"0" :
|
|
L"1"));
|
|
|
|
RtlInitUnicodeString(&unicodeString, returnString);
|
|
|
|
//
|
|
// null terminate it
|
|
//
|
|
unicodeString.Buffer[unicodeString.Length/sizeof(WCHAR) + 0] = L'\0';
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
} else {
|
|
|
|
status = STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
UnrefPdoWithTag (
|
|
pdoExtension,
|
|
DeviceQueryText
|
|
);
|
|
}
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR) returnString;
|
|
Irp->IoStatus.Status = status;
|
|
|
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|
return status;
|
|
} // DeviceQueryText
|
|
|
|
NTSTATUS
|
|
IdeSendIdePassThrough (
|
|
IN PPDO_EXTENSION PdoExtension,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sends a user specified IDE task registers
|
|
It creates an srb which is processed normally by the port driver.
|
|
This call is synchornous.
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension - Supplies a pointer the SCSI adapter device extension.
|
|
|
|
RequestIrp - Supplies a pointe to the Irp which made the original request.
|
|
|
|
Return Value:
|
|
|
|
Returns a status indicating the success or failure of the operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
PIO_STACK_LOCATION irpStack;
|
|
PATA_PASS_THROUGH ataPassThroughData;
|
|
ULONG dataBufferSize;
|
|
BOOLEAN dataIn;
|
|
NTSTATUS status;
|
|
ULONG outputBufferSize;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugPrint((3,"IdePortSendPassThrough: Enter routine\n"));
|
|
|
|
//
|
|
// validate target device
|
|
//
|
|
if (PdoExtension->Lun != 0) {
|
|
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
//
|
|
// Get a pointer to the control block.
|
|
//
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
ataPassThroughData = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
//
|
|
// Validiate the user buffer.
|
|
//
|
|
if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
|
|
FIELD_OFFSET(ATA_PASS_THROUGH, DataBuffer)) {
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
|
|
FIELD_OFFSET(ATA_PASS_THROUGH, DataBuffer)) {
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
ASSERT(ataPassThroughData != NULL);
|
|
|
|
dataBufferSize = ataPassThroughData->DataBufferSize;
|
|
|
|
outputBufferSize = FIELD_OFFSET(ATA_PASS_THROUGH, DataBuffer) + dataBufferSize;
|
|
|
|
if (outputBufferSize < dataBufferSize) {
|
|
|
|
//
|
|
// outputBufferSize overflows a ULONG
|
|
//
|
|
outputBufferSize = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
|
|
}
|
|
|
|
//
|
|
// SECURITY: This should be fixed. If the output buffer size is larger
|
|
// than the output buffer length, we could potentially bugcheck.
|
|
//
|
|
if ((irpStack->Parameters.DeviceIoControl.OutputBufferLength) >=
|
|
outputBufferSize) {
|
|
|
|
dataIn = TRUE;
|
|
|
|
} else {
|
|
|
|
dataIn = FALSE;
|
|
}
|
|
|
|
status = IssueSyncAtaPassThroughSafe (
|
|
PdoExtension->ParentDeviceExtension,
|
|
PdoExtension,
|
|
ataPassThroughData,
|
|
dataIn,
|
|
FALSE,
|
|
DEFAULT_ATA_PASS_THROUGH_TIMEOUT,
|
|
FALSE
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// SECURITY: verify that we always copy outpubuffersize
|
|
// data in the SUCCESS case
|
|
//
|
|
Irp->IoStatus.Information = outputBufferSize;
|
|
|
|
} else {
|
|
|
|
//
|
|
// ignore all errors
|
|
// let the caller figure out the error
|
|
// from the task file registers
|
|
//
|
|
status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = FIELD_OFFSET(ATA_PASS_THROUGH, DataBuffer);
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
return status;
|
|
|
|
} // IdeSendIdePassThrough
|
|
|
|
VOID
|
|
DeviceRegisterIdleDetection (
|
|
IN PPDO_EXTENSION PdoExtension,
|
|
IN ULONG ConservationIdleTime,
|
|
IN ULONG PerformanceIdleTime
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
ATA_PASS_THROUGH ataPassThroughData;
|
|
|
|
//
|
|
// Many ATAPI device (Acer and Panasonice Changer) doesn't like ATA
|
|
// power down command. Since they auto-spin-down anyway, we are not
|
|
// go to power manage it
|
|
//
|
|
if (!(PdoExtension->PdoState & PDOS_NO_POWER_DOWN)) {
|
|
|
|
if (!PdoExtension->CrashDumpPathCount) {
|
|
|
|
RtlZeroMemory (&ataPassThroughData, sizeof(ataPassThroughData));
|
|
ataPassThroughData.IdeReg.bCommandReg = IDE_COMMAND_IDLE_IMMEDIATE;
|
|
ataPassThroughData.IdeReg.bReserved = ATA_PTFLAGS_STATUS_DRDY_REQUIRED;
|
|
|
|
status = IssueSyncAtaPassThroughSafe (
|
|
PdoExtension->ParentDeviceExtension,
|
|
PdoExtension,
|
|
&ataPassThroughData,
|
|
FALSE,
|
|
FALSE,
|
|
DEFAULT_ATA_PASS_THROUGH_TIMEOUT,
|
|
FALSE
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
DEVICE_POWER_STATE devicePowerState;
|
|
|
|
//
|
|
// ISSUE
|
|
// should check the registry/device property whether
|
|
// idle detection has been disabled for this device
|
|
//
|
|
devicePowerState = PowerDeviceD3;
|
|
PdoExtension->IdleCounter = PoRegisterDeviceForIdleDetection (
|
|
PdoExtension->DeviceObject,
|
|
ConservationIdleTime, // seconds
|
|
PerformanceIdleTime, // seconds
|
|
devicePowerState
|
|
);
|
|
|
|
DebugPrint ((1, "IdePort: pdoExtension 0x%x support power managerment command\n", PdoExtension));
|
|
|
|
} else {
|
|
|
|
KIRQL currentIrql;
|
|
|
|
KeAcquireSpinLock(&PdoExtension->PdoSpinLock, ¤tIrql);
|
|
|
|
SETMASK (PdoExtension->PdoState, PDOS_NO_POWER_DOWN);
|
|
|
|
KeReleaseSpinLock(&PdoExtension->PdoSpinLock, currentIrql);
|
|
|
|
DebugPrint ((1, "IdePort: pdoExtension 0x%x DOES NOT support power managerment command\n", PdoExtension));
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
DeviceUnregisterIdleDetection (
|
|
IN PPDO_EXTENSION PdoExtension
|
|
)
|
|
{
|
|
DEVICE_POWER_STATE devicePowerState;
|
|
devicePowerState = PowerDeviceD3;
|
|
|
|
if (PdoExtension->IdleCounter) {
|
|
|
|
PoRegisterDeviceForIdleDetection (
|
|
PdoExtension->DeviceObject,
|
|
0,
|
|
0,
|
|
devicePowerState
|
|
);
|
|
|
|
PdoExtension->IdleCounter = NULL;
|
|
}
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
DeviceInitIdStrings (
|
|
IN PPDO_EXTENSION PdoExtension,
|
|
IN IDE_DEVICETYPE DeviceType,
|
|
IN PINQUIRYDATA InquiryData,
|
|
IN PIDENTIFY_DATA IdentifyData
|
|
)
|
|
{
|
|
LONG i;
|
|
UCHAR c;
|
|
|
|
SPECIAL_ACTION_FLAG specialFlags;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT (PdoExtension);
|
|
ASSERT (IdentifyData);
|
|
|
|
if (DeviceType == DeviceIsAta) {
|
|
|
|
CopyField(
|
|
PdoExtension->FullVendorProductId,
|
|
IdentifyData->ModelNumber,
|
|
sizeof(PdoExtension->FullVendorProductId)-1,
|
|
' '
|
|
);
|
|
|
|
CopyField(
|
|
PdoExtension->FullProductRevisionId,
|
|
IdentifyData->FirmwareRevision,
|
|
sizeof(PdoExtension->FullProductRevisionId)-1,
|
|
' '
|
|
);
|
|
|
|
//
|
|
// byte swap
|
|
//
|
|
for (i=0; i<sizeof(PdoExtension->FullVendorProductId)-1; i+=2) {
|
|
c = PdoExtension->FullVendorProductId[i];
|
|
PdoExtension->FullVendorProductId[i] = PdoExtension->FullVendorProductId[i + 1];
|
|
PdoExtension->FullVendorProductId[i + 1] = c;
|
|
}
|
|
for (i=0; i<sizeof(PdoExtension->FullProductRevisionId)-1; i+=2) {
|
|
c = PdoExtension->FullProductRevisionId[i];
|
|
PdoExtension->FullProductRevisionId[i] = PdoExtension->FullProductRevisionId[i + 1];
|
|
PdoExtension->FullProductRevisionId[i + 1] = c;
|
|
}
|
|
|
|
} else if (DeviceType == DeviceIsAtapi) {
|
|
|
|
PUCHAR fullVendorProductId;
|
|
|
|
fullVendorProductId = PdoExtension->FullVendorProductId;
|
|
|
|
CopyField(
|
|
fullVendorProductId,
|
|
InquiryData->VendorId,
|
|
8,
|
|
' '
|
|
);
|
|
|
|
for (i=7; i >= 0; i--) {
|
|
|
|
if (fullVendorProductId[i] != ' ') {
|
|
|
|
fullVendorProductId[i + 1] = ' ';
|
|
fullVendorProductId += i + 2;
|
|
break;
|
|
}
|
|
}
|
|
|
|
CopyField(
|
|
fullVendorProductId,
|
|
InquiryData->ProductId,
|
|
16,
|
|
' '
|
|
);
|
|
|
|
fullVendorProductId += 16;
|
|
|
|
for (i=0; fullVendorProductId+i < PdoExtension->FullVendorProductId+40; i++) {
|
|
fullVendorProductId[i] = ' ';
|
|
}
|
|
|
|
CopyField(
|
|
PdoExtension->FullProductRevisionId,
|
|
InquiryData->ProductRevisionLevel,
|
|
4,
|
|
' '
|
|
);
|
|
|
|
for (i=4; i<8; i++) {
|
|
PdoExtension->FullProductRevisionId[i] = ' ';
|
|
}
|
|
|
|
} else {
|
|
|
|
ASSERT (FALSE);
|
|
}
|
|
|
|
//
|
|
// take out trailing spaces
|
|
//
|
|
for (i=sizeof(PdoExtension->FullVendorProductId)-2; i >= 0; i--) {
|
|
|
|
if (PdoExtension->FullVendorProductId[i] != ' ') {
|
|
|
|
PdoExtension->FullVendorProductId[i+1] = '\0';
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i=sizeof(PdoExtension->FullProductRevisionId)-2; i >= 0; i--) {
|
|
|
|
if (PdoExtension->FullProductRevisionId[i] != ' ') {
|
|
|
|
PdoExtension->FullProductRevisionId[i+1] = '\0';
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check the vendor & product id to see if we should disable the serial
|
|
// number for this device.
|
|
//
|
|
|
|
specialFlags = IdeFindSpecialDevice(PdoExtension->FullVendorProductId,
|
|
PdoExtension->FullProductRevisionId);
|
|
|
|
//
|
|
// look for serial number
|
|
//
|
|
// some device returns non-printable characters as part of its
|
|
// serial number. to get around this, we will turn all raw numbers
|
|
// into a string.
|
|
//
|
|
if ((specialFlags != disableSerialNumber) &&
|
|
(IdentifyData->SerialNumber[0] != ' ') &&
|
|
(IdentifyData->SerialNumber[0] != '\0')) {
|
|
|
|
for (i=0; i<sizeof(IdentifyData->SerialNumber); i++) {
|
|
|
|
sprintf (PdoExtension->FullSerialNumber+i*2, "%2x", IdentifyData->SerialNumber[i]);
|
|
}
|
|
|
|
PdoExtension->FullSerialNumber[sizeof(PdoExtension->FullSerialNumber) - 1] = '\0';
|
|
|
|
} else {
|
|
|
|
PdoExtension->FullSerialNumber[0] = '\0';
|
|
}
|
|
|
|
DebugPrint ((
|
|
DBG_BUSSCAN,
|
|
"PDOE 0x%x: Full IDs \n\t%s\n\t%s\n\t%s\n",
|
|
PdoExtension,
|
|
PdoExtension->FullVendorProductId,
|
|
PdoExtension->FullProductRevisionId,
|
|
PdoExtension->FullSerialNumber
|
|
));
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
DeviceInitDeviceType (
|
|
IN PPDO_EXTENSION PdoExtension,
|
|
IN PINQUIRYDATA InquiryData
|
|
)
|
|
{
|
|
PdoExtension->ScsiDeviceType = InquiryData->DeviceType;
|
|
|
|
if(InquiryData->RemovableMedia) {
|
|
|
|
SETMASK (PdoExtension->DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
NTSTATUS
|
|
DeviceQueryDeviceRelations (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION thisIrpSp;
|
|
PDEVICE_RELATIONS deviceRelations;
|
|
NTSTATUS status;
|
|
|
|
IDE_PATH_ID pathId;
|
|
PPDO_EXTENSION pdoExtension;
|
|
PPDO_EXTENSION otherPdoExtension;
|
|
ULONG numPdos;
|
|
|
|
thisIrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
|
|
switch (thisIrpSp->Parameters.QueryDeviceRelations.Type) {
|
|
|
|
case TargetDeviceRelation:
|
|
|
|
deviceRelations = ExAllocatePool (
|
|
NonPagedPool,
|
|
sizeof(*deviceRelations) +
|
|
sizeof(deviceRelations->Objects[0]) * 1
|
|
);
|
|
|
|
if (deviceRelations != NULL) {
|
|
|
|
deviceRelations->Count = 1;
|
|
deviceRelations->Objects[0] = DeviceObject;
|
|
|
|
ObReferenceObjectByPointer(DeviceObject,
|
|
0,
|
|
0,
|
|
KernelMode);
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
|
|
} else {
|
|
|
|
Irp->IoStatus.Status = STATUS_NO_MEMORY;
|
|
Irp->IoStatus.Information = 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
status = Irp->IoStatus.Status;
|
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|
return status;
|
|
} // DeviceQueryDeviceRelations
|
|
|
|
NTSTATUS
|
|
DeviceQueryInitData (
|
|
IN PPDO_EXTENSION PdoExtension
|
|
)
|
|
{
|
|
PDEVICE_SETTINGS deviceSettings;
|
|
PDEVICE_SETTINGS tempDeviceSettings;
|
|
NTSTATUS status;
|
|
ATA_PASS_THROUGH ataPassThroughData;
|
|
|
|
PPDO_EXTENSION lun0PdoExtension;
|
|
ULONG totalDeviceSettingEntries;
|
|
ULONG firstNewEntryOffset;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugPrint ((
|
|
DBG_PNP,
|
|
"DeviceQueryInitData: Init. pdoe 0x%x (%d,%d,%d)\n",
|
|
PdoExtension,
|
|
PdoExtension->PathId,
|
|
PdoExtension->TargetId,
|
|
PdoExtension->Lun
|
|
));
|
|
|
|
deviceSettings = PdoExtension->AcpiDeviceSettings;
|
|
if (deviceSettings == NULL) {
|
|
|
|
//
|
|
// ISSUE: we can't be sure acpi is always attached on lun0
|
|
//
|
|
// get the lun0 pdo
|
|
//
|
|
lun0PdoExtension = RefLogicalUnitExtensionWithTag(
|
|
PdoExtension->ParentDeviceExtension,
|
|
PdoExtension->PathId,
|
|
PdoExtension->TargetId,
|
|
0,
|
|
TRUE,
|
|
DeviceQueryInitData
|
|
);
|
|
|
|
if (lun0PdoExtension) {
|
|
|
|
ASSERT (lun0PdoExtension->TargetId == PdoExtension->TargetId);
|
|
|
|
status = DeviceQueryFirmwareBootSettings (
|
|
lun0PdoExtension,
|
|
&deviceSettings
|
|
);
|
|
|
|
//
|
|
// let go Lun0
|
|
//
|
|
UnrefPdoWithTag(
|
|
lun0PdoExtension,
|
|
DeviceQueryInitData
|
|
);
|
|
}
|
|
|
|
if (deviceSettings) {
|
|
|
|
ULONG i;
|
|
ULONG j;
|
|
|
|
for (i=0; i<deviceSettings->NumEntries; i++) {
|
|
|
|
//
|
|
// Ignore SET_DRIVE_PARAMETERS, SET_MULTIPLE and set transfermode commands
|
|
// in GTF
|
|
//
|
|
if (((deviceSettings->FirmwareSettings[i].bCommandReg == IDE_COMMAND_SET_FEATURE) &&
|
|
(deviceSettings->FirmwareSettings[i].bFeaturesReg == IDE_SET_FEATURE_SET_TRANSFER_MODE)) ||
|
|
(deviceSettings->FirmwareSettings[i].bCommandReg == IDE_COMMAND_SET_DRIVE_PARAMETERS) ||
|
|
(deviceSettings->FirmwareSettings[i].bCommandReg == IDE_COMMAND_SET_MULTIPLE)) {
|
|
|
|
DebugPrint((DBG_ACPI,
|
|
"Ignoring Command %xin GTF\n",
|
|
deviceSettings->FirmwareSettings[i].bCommandReg
|
|
));
|
|
|
|
deviceSettings->NumEntries--;
|
|
|
|
//
|
|
// remove this command by shifting the rest up one entry
|
|
//
|
|
for (j=i; j<deviceSettings->NumEntries; j++) {
|
|
|
|
deviceSettings->FirmwareSettings[j] = deviceSettings->FirmwareSettings[j+1];
|
|
}
|
|
|
|
//
|
|
// we move something new into the current i entry
|
|
// better adjust i so that we will check this entry
|
|
// again
|
|
//
|
|
if (i < deviceSettings->NumEntries) {
|
|
i--;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// we need to add a new setting
|
|
//
|
|
if (PdoExtension->ScsiDeviceType == DIRECT_ACCESS_DEVICE) {
|
|
totalDeviceSettingEntries = 2;
|
|
} else {
|
|
totalDeviceSettingEntries = 1;
|
|
}
|
|
|
|
if (deviceSettings) {
|
|
totalDeviceSettingEntries += deviceSettings->NumEntries;
|
|
firstNewEntryOffset = deviceSettings->NumEntries;
|
|
} else {
|
|
firstNewEntryOffset = 0;
|
|
}
|
|
|
|
tempDeviceSettings = ExAllocatePool (
|
|
NonPagedPool,
|
|
sizeof(DEVICE_SETTINGS) +
|
|
(totalDeviceSettingEntries) * sizeof(IDEREGS)
|
|
);
|
|
|
|
if (tempDeviceSettings) {
|
|
|
|
tempDeviceSettings->NumEntries = totalDeviceSettingEntries;
|
|
|
|
//
|
|
// copy the settings from acpi query
|
|
//
|
|
if (deviceSettings) {
|
|
RtlCopyMemory (&tempDeviceSettings->FirmwareSettings,
|
|
&deviceSettings->FirmwareSettings,
|
|
sizeof(IDEREGS) * deviceSettings->NumEntries);
|
|
|
|
//
|
|
// don't need the old structure anymore
|
|
//
|
|
ExFreePool (deviceSettings);
|
|
deviceSettings = NULL;
|
|
}
|
|
|
|
//
|
|
// add the new settings
|
|
//
|
|
RtlZeroMemory (
|
|
&tempDeviceSettings->FirmwareSettings[firstNewEntryOffset],
|
|
sizeof (IDEREGS));
|
|
tempDeviceSettings->FirmwareSettings[firstNewEntryOffset].bFeaturesReg =
|
|
IDE_SET_FEATURE_DISABLE_REVERT_TO_POWER_ON;
|
|
tempDeviceSettings->FirmwareSettings[firstNewEntryOffset].bCommandReg =
|
|
IDE_COMMAND_SET_FEATURE;
|
|
tempDeviceSettings->FirmwareSettings[firstNewEntryOffset].bReserved =
|
|
ATA_PTFLAGS_STATUS_DRDY_REQUIRED | ATA_PTFLAGS_OK_TO_FAIL;
|
|
|
|
if (PdoExtension->ScsiDeviceType == DIRECT_ACCESS_DEVICE) {
|
|
|
|
RtlZeroMemory (
|
|
&tempDeviceSettings->FirmwareSettings[firstNewEntryOffset + 1],
|
|
sizeof (IDEREGS));
|
|
tempDeviceSettings->FirmwareSettings[firstNewEntryOffset + 1].bFeaturesReg =
|
|
IDE_SET_FEATURE_ENABLE_WRITE_CACHE;
|
|
tempDeviceSettings->FirmwareSettings[firstNewEntryOffset + 1].bCommandReg =
|
|
IDE_COMMAND_SET_FEATURE;
|
|
tempDeviceSettings->FirmwareSettings[firstNewEntryOffset + 1].bReserved =
|
|
ATA_PTFLAGS_STATUS_DRDY_REQUIRED | ATA_PTFLAGS_OK_TO_FAIL;
|
|
}
|
|
|
|
//
|
|
// throw away the old and keep the new
|
|
//
|
|
deviceSettings = tempDeviceSettings;
|
|
|
|
} else {
|
|
|
|
//
|
|
// someone took all the memory.
|
|
// we can't build a new device setting structure
|
|
// will have to use the old one
|
|
//
|
|
}
|
|
|
|
//
|
|
// keep it around
|
|
//
|
|
PdoExtension->AcpiDeviceSettings = deviceSettings;
|
|
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
DeviceInitDeviceState (
|
|
IN PPDO_EXTENSION PdoExtension,
|
|
DEVICE_INIT_COMPLETION DeviceInitCompletionRoutine,
|
|
PVOID DeviceInitCompletionContext
|
|
)
|
|
{
|
|
PDEVICE_SETTINGS deviceSettings;
|
|
NTSTATUS status;
|
|
PDEVICE_INIT_DEVICE_STATE_CONTEXT deviceStateContext;
|
|
ULONG deviceStateContextSize;
|
|
ULONG numState;
|
|
ULONG numRequestSent;
|
|
DEVICE_INIT_STATE deviceInitState[deviceInitState_done];
|
|
|
|
if (!InterlockedExchange (&PdoExtension->InitDeviceWithAcpiGtf, 0)) {
|
|
|
|
//
|
|
// make sure we only do this once per start
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
if (!(PdoExtension->PdoState & PDOS_STARTED)) {
|
|
|
|
DebugPrint ((DBG_PNP, "DeviceInitDeviceState: device not started...skipping acpi init\n"));
|
|
|
|
(DeviceInitCompletionRoutine) (
|
|
DeviceInitCompletionContext,
|
|
STATUS_SUCCESS
|
|
);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
deviceStateContextSize = sizeof (DEVICE_INIT_DEVICE_STATE_CONTEXT);
|
|
|
|
deviceStateContext = ExAllocatePool (NonPagedPool, deviceStateContextSize);
|
|
if (deviceStateContext == NULL) {
|
|
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
if (!RefPdoWithTag(PdoExtension->DeviceObject, FALSE, DeviceInitDeviceState)) {
|
|
ExFreePool (deviceStateContext);
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
RtlZeroMemory(
|
|
deviceStateContext,
|
|
deviceStateContextSize
|
|
);
|
|
|
|
deviceSettings = PdoExtension->AcpiDeviceSettings;
|
|
|
|
//
|
|
// compute the total number of inti state we are going to have
|
|
//
|
|
numState = 0;
|
|
if (deviceSettings) {
|
|
|
|
deviceStateContext->DeviceInitState[numState] = deviceInitState_acpi;
|
|
numState++;
|
|
}
|
|
deviceStateContext->DeviceInitState[numState] = deviceInitState_done;
|
|
numState++;
|
|
|
|
ASSERT(numState <= deviceInitState_max);
|
|
|
|
deviceStateContext->PdoExtension = PdoExtension;
|
|
deviceStateContext->NumInitState = numState;
|
|
deviceStateContext->DeviceInitCompletionRoutine = DeviceInitCompletionRoutine;
|
|
deviceStateContext->DeviceInitCompletionContext = DeviceInitCompletionContext;
|
|
|
|
DeviceInitDeviceStateCompletionRoutine (
|
|
PdoExtension->DeviceObject,
|
|
deviceStateContext,
|
|
STATUS_SUCCESS
|
|
);
|
|
|
|
return STATUS_PENDING;
|
|
} // DeviceInitDeviceState
|
|
|
|
VOID
|
|
DeviceInitDeviceStateCompletionRoutine (
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PVOID Context,
|
|
NTSTATUS Status
|
|
)
|
|
{
|
|
ULONG numRequestCompleted;
|
|
PDEVICE_INIT_DEVICE_STATE_CONTEXT deviceStateContext = Context;
|
|
PDEVICE_SETTINGS deviceSettings;
|
|
PPDO_EXTENSION PdoExtension;
|
|
NTSTATUS status;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
InterlockedIncrement (&deviceStateContext->NumRequestFailed);
|
|
DebugPrint ((DBG_ALWAYS, "DeviceInitDeviceStateCompletionRoutine: Last init. command failed with status %x\n",
|
|
Status));
|
|
}
|
|
|
|
PdoExtension = deviceStateContext->PdoExtension;
|
|
switch (deviceStateContext->DeviceInitState[deviceStateContext->CurrentState]) {
|
|
|
|
case deviceInitState_acpi:
|
|
|
|
deviceSettings = PdoExtension->AcpiDeviceSettings;
|
|
ASSERT (deviceSettings);
|
|
|
|
RtlZeroMemory (
|
|
&deviceStateContext->AtaPassThroughData,
|
|
sizeof(deviceStateContext->AtaPassThroughData)
|
|
);
|
|
|
|
deviceStateContext->AtaPassThroughData.IdeReg =
|
|
deviceSettings->FirmwareSettings[deviceStateContext->NumAcpiRequestSent];
|
|
|
|
deviceStateContext->AtaPassThroughData.IdeReg.bReserved |=
|
|
ATA_PTFLAGS_STATUS_DRDY_REQUIRED | ATA_PTFLAGS_URGENT;
|
|
|
|
deviceStateContext->NumAcpiRequestSent++;
|
|
if (deviceStateContext->NumAcpiRequestSent >= deviceSettings->NumEntries) {
|
|
//
|
|
// sent all acpi init state. go to the next state
|
|
//
|
|
deviceStateContext->CurrentState++;
|
|
}
|
|
|
|
if ((deviceStateContext->AtaPassThroughData.IdeReg.bFeaturesReg ==
|
|
IDE_SET_FEATURE_ENABLE_WRITE_CACHE) &&
|
|
(deviceStateContext->AtaPassThroughData.IdeReg.bCommandReg ==
|
|
IDE_COMMAND_SET_FEATURE)) {
|
|
|
|
//
|
|
// only ata harddisk should have this entry
|
|
//
|
|
ASSERT (PdoExtension->ScsiDeviceType == DIRECT_ACCESS_DEVICE);
|
|
|
|
if (PdoExtension->WriteCacheEnable == FALSE) {
|
|
|
|
deviceStateContext->AtaPassThroughData.IdeReg.bFeaturesReg =
|
|
IDE_SET_FEATURE_DISABLE_WRITE_CACHE;
|
|
}
|
|
}
|
|
|
|
|
|
DebugPrint ((
|
|
DBG_PNP,
|
|
"IdePort: restore firmware settings from ACPI BIOS. ide command = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
|
|
deviceStateContext->AtaPassThroughData.IdeReg.bFeaturesReg,
|
|
deviceStateContext->AtaPassThroughData.IdeReg.bSectorCountReg,
|
|
deviceStateContext->AtaPassThroughData.IdeReg.bSectorNumberReg,
|
|
deviceStateContext->AtaPassThroughData.IdeReg.bCylLowReg,
|
|
deviceStateContext->AtaPassThroughData.IdeReg.bCylHighReg,
|
|
deviceStateContext->AtaPassThroughData.IdeReg.bDriveHeadReg,
|
|
deviceStateContext->AtaPassThroughData.IdeReg.bCommandReg
|
|
));
|
|
|
|
status = IssueAsyncAtaPassThroughSafe (
|
|
PdoExtension->ParentDeviceExtension,
|
|
PdoExtension,
|
|
&deviceStateContext->AtaPassThroughData,
|
|
TRUE,
|
|
DeviceInitDeviceStateCompletionRoutine,
|
|
deviceStateContext,
|
|
FALSE,
|
|
DEFAULT_ATA_PASS_THROUGH_TIMEOUT,
|
|
FALSE
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// can't send the request
|
|
// notify the completion routine that we fail
|
|
//
|
|
DeviceInitDeviceStateCompletionRoutine (
|
|
PdoExtension->DeviceObject,
|
|
deviceStateContext,
|
|
status
|
|
);
|
|
}
|
|
break;
|
|
|
|
case deviceInitState_done:
|
|
|
|
//
|
|
// notify the original caller w/ error if any
|
|
//
|
|
(*deviceStateContext->DeviceInitCompletionRoutine) (
|
|
deviceStateContext->DeviceInitCompletionContext,
|
|
deviceStateContext->NumRequestFailed ?
|
|
STATUS_UNSUCCESSFUL :
|
|
STATUS_SUCCESS
|
|
);
|
|
|
|
UnrefPdoWithTag(
|
|
deviceStateContext->PdoExtension,
|
|
DeviceInitDeviceState
|
|
);
|
|
|
|
ExFreePool (deviceStateContext);
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
NTSTATUS
|
|
DeviceIdeReadCapacity (
|
|
IN PPDO_EXTENSION PdoExtension,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PIDE_READ_CAPACITY_CONTEXT context;
|
|
PATA_PASS_THROUGH ataPassThroughData;
|
|
ULONG dataSize;
|
|
PUCHAR dataOffset;
|
|
PHW_DEVICE_EXTENSION hwDeviceExtension=PdoExtension->ParentDeviceExtension->HwDeviceExtension;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb;
|
|
|
|
//
|
|
// Check for device present flag
|
|
//
|
|
if (!(hwDeviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_DEVICE_PRESENT)) {
|
|
|
|
srb->SrbStatus = SRB_STATUS_NO_DEVICE;
|
|
|
|
UnrefLogicalUnitExtensionWithTag(
|
|
PdoExtension->ParentDeviceExtension,
|
|
PdoExtension,
|
|
Irp
|
|
);
|
|
|
|
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
context = ExAllocatePool (
|
|
NonPagedPool,
|
|
sizeof(IDE_READ_CAPACITY_CONTEXT)
|
|
);
|
|
if ((context == NULL) || (Irp->MdlAddress == NULL)) {
|
|
|
|
if (context) {
|
|
ExFreePool(context);
|
|
}
|
|
|
|
UnrefLogicalUnitExtensionWithTag(
|
|
PdoExtension->ParentDeviceExtension,
|
|
PdoExtension,
|
|
Irp
|
|
);
|
|
|
|
srb->SrbStatus = SRB_STATUS_INTERNAL_ERROR;
|
|
srb->InternalStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
IdeLogNoMemoryError(PdoExtension->ParentDeviceExtension,
|
|
PdoExtension->TargetId,
|
|
NonPagedPool,
|
|
sizeof(IDE_READ_CAPACITY_CONTEXT),
|
|
IDEPORT_TAG_READCAP_CONTEXT
|
|
);
|
|
|
|
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// save the old data buffer for restoring later
|
|
//
|
|
context->OldDataBuffer = srb->DataBuffer;
|
|
context->GeometryIoctl=FALSE;
|
|
|
|
//
|
|
// map the buffer in
|
|
//
|
|
dataOffset = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority);
|
|
srb->DataBuffer = dataOffset +
|
|
(ULONG)((PUCHAR)srb->DataBuffer -
|
|
(PCCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress));
|
|
|
|
context->PdoExtension = PdoExtension;
|
|
context->OriginalIrp = Irp;
|
|
|
|
// MdlSafe failed
|
|
|
|
if (dataOffset == NULL) {
|
|
|
|
IdeLogNoMemoryError(PdoExtension->ParentDeviceExtension,
|
|
PdoExtension->TargetId,
|
|
NonPagedPool,
|
|
sizeof(MDL),
|
|
IDEPORT_TAG_READCAP_MDL
|
|
);
|
|
|
|
DeviceIdeReadCapacityCompletionRoutine (
|
|
PdoExtension->DeviceObject,
|
|
context,
|
|
STATUS_INSUFFICIENT_RESOURCES
|
|
);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
ataPassThroughData = &context->AtaPassThroughData;
|
|
|
|
RtlZeroMemory (
|
|
ataPassThroughData,
|
|
sizeof (*ataPassThroughData)
|
|
);
|
|
|
|
ataPassThroughData->DataBufferSize = sizeof(IDENTIFY_DATA);
|
|
|
|
ataPassThroughData->IdeReg.bCommandReg = IDE_COMMAND_IDENTIFY;
|
|
ataPassThroughData->IdeReg.bReserved = ATA_PTFLAGS_STATUS_DRDY_REQUIRED;
|
|
|
|
status = IssueAsyncAtaPassThroughSafe (
|
|
PdoExtension->ParentDeviceExtension,
|
|
PdoExtension,
|
|
ataPassThroughData,
|
|
TRUE,
|
|
DeviceIdeReadCapacityCompletionRoutine,
|
|
context,
|
|
FALSE,
|
|
DEFAULT_ATA_PASS_THROUGH_TIMEOUT,
|
|
FALSE
|
|
);
|
|
|
|
if (status != STATUS_PENDING) {
|
|
|
|
DeviceIdeReadCapacityCompletionRoutine (
|
|
PdoExtension->DeviceObject,
|
|
context,
|
|
status
|
|
);
|
|
}
|
|
|
|
//
|
|
// the irp was marked pending. return status_pending
|
|
//
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
VOID
|
|
DeviceIdeReadCapacityCompletionRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
PVOID Context,
|
|
NTSTATUS Status
|
|
)
|
|
{
|
|
PIDE_READ_CAPACITY_CONTEXT context = Context;
|
|
PIRP irp = context->OriginalIrp;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(irp);
|
|
PSCSI_REQUEST_BLOCK srb;
|
|
KIRQL currentIrql;
|
|
PKSPIN_LOCK spinLock;
|
|
ULONG numberOfCylinders;
|
|
ULONG numberOfHeads;
|
|
ULONG sectorsPerTrack;
|
|
PHW_DEVICE_EXTENSION hwDeviceExtension;
|
|
ULONG i;
|
|
ULONG totalCHSSize;
|
|
ULONG targetId;
|
|
PIDENTIFY_DATA identifyData;
|
|
|
|
srb = irpStack->Parameters.Scsi.Srb;
|
|
targetId=srb->TargetId;
|
|
hwDeviceExtension = context->PdoExtension->ParentDeviceExtension->HwDeviceExtension;
|
|
spinLock = &context->PdoExtension->ParentDeviceExtension->SpinLock;
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
identifyData = (PIDENTIFY_DATA) context->AtaPassThroughData.DataBuffer;
|
|
|
|
IdePortFudgeAtaIdentifyData(
|
|
identifyData
|
|
);
|
|
|
|
if ( ((identifyData->MajorRevision == 0) ||
|
|
((identifyData->NumberOfCurrentCylinders == 0) ||
|
|
(identifyData->NumberOfCurrentHeads == 0) ||
|
|
(identifyData->CurrentSectorsPerTrack == 0))) ) {
|
|
|
|
numberOfCylinders = identifyData->NumCylinders;
|
|
numberOfHeads = identifyData->NumHeads;
|
|
sectorsPerTrack = identifyData->NumSectorsPerTrack;
|
|
|
|
} else {
|
|
|
|
numberOfCylinders = identifyData->NumberOfCurrentCylinders;
|
|
numberOfHeads = identifyData->NumberOfCurrentHeads;
|
|
sectorsPerTrack = identifyData->CurrentSectorsPerTrack;
|
|
|
|
if (identifyData->UserAddressableSectors >
|
|
(numberOfCylinders * numberOfHeads * sectorsPerTrack)) {
|
|
|
|
//
|
|
// some ide driver has a 2G jumer to get around bios
|
|
// problem. make sure we are not tricked the samw way.
|
|
//
|
|
if ((numberOfCylinders <= 0xfff) &&
|
|
(numberOfHeads == 0x10) &&
|
|
(sectorsPerTrack == 0x3f)) {
|
|
|
|
numberOfCylinders = identifyData->UserAddressableSectors / (0x10 * 0x3f);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Workaround for devices that return 0 in the geometry fields.
|
|
//
|
|
if ((numberOfCylinders == 0) ||
|
|
(numberOfHeads == 0) ||
|
|
(sectorsPerTrack == 0)) {
|
|
|
|
//
|
|
// round up chs to 1
|
|
//
|
|
numberOfCylinders = 1;
|
|
numberOfHeads = 1;
|
|
sectorsPerTrack =1;
|
|
totalCHSSize = 0;
|
|
|
|
} else {
|
|
|
|
totalCHSSize = (numberOfHeads * numberOfCylinders * sectorsPerTrack);
|
|
|
|
}
|
|
|
|
//
|
|
// update the HW Device Extension Data
|
|
//
|
|
KeAcquireSpinLock(spinLock, ¤tIrql);
|
|
|
|
InitDeviceGeometry(
|
|
hwDeviceExtension,
|
|
targetId,
|
|
numberOfCylinders,
|
|
numberOfHeads,
|
|
sectorsPerTrack
|
|
);
|
|
|
|
if (hwDeviceExtension->DeviceFlags[targetId] & DFLAGS_IDENTIFY_INVALID) {
|
|
|
|
RtlMoveMemory (
|
|
hwDeviceExtension->IdentifyData + targetId,
|
|
identifyData,
|
|
sizeof (IDENTIFY_DATA)
|
|
);
|
|
|
|
ASSERT(!(hwDeviceExtension->DeviceFlags[targetId] & DFLAGS_REMOVABLE_DRIVE));
|
|
|
|
SETMASK(hwDeviceExtension->DeviceFlags[targetId], DFLAGS_IDENTIFY_VALID);
|
|
CLRMASK(hwDeviceExtension->DeviceFlags[targetId], DFLAGS_IDENTIFY_INVALID);
|
|
}
|
|
|
|
if (srb) {
|
|
//
|
|
// Claim 512 byte blocks (big-endian).
|
|
//
|
|
((READ_CAPACITY_DATA UNALIGNED *)srb->DataBuffer)->BytesPerBlock = 0x20000;
|
|
|
|
//
|
|
// Calculate last sector.
|
|
//
|
|
if (context->PdoExtension->ParentDeviceExtension->
|
|
HwDeviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_LBA) {
|
|
// LBA device
|
|
i = identifyData->UserAddressableSectors - 1;
|
|
|
|
//
|
|
// LBAs can only be 28 bits wide
|
|
//
|
|
if (i >= MAX_28BIT_LBA) {
|
|
i = MAX_28BIT_LBA - 1;
|
|
}
|
|
|
|
#ifdef ENABLE_48BIT_LBA
|
|
if (context->PdoExtension->ParentDeviceExtension->
|
|
HwDeviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_48BIT_LBA) {
|
|
|
|
i = identifyData->Max48BitLBA[0] - 1;
|
|
|
|
//
|
|
// currently we support only upto 32 bits.
|
|
//
|
|
ASSERT(identifyData->Max48BitLBA[1] == 0);
|
|
}
|
|
#endif
|
|
DebugPrint((1,
|
|
"IDE LBA disk %x - total # of sectors = 0x%x\n",
|
|
srb->TargetId,
|
|
identifyData->UserAddressableSectors));
|
|
|
|
} else {
|
|
|
|
// CHS device
|
|
//i = (numberOfHeads * numberOfCylinders * sectorsPerTrack) - 1;
|
|
i=totalCHSSize - 1;
|
|
|
|
DebugPrint((1,
|
|
"IDE CHS disk %x - #sectors %x, #heads %x, #cylinders %x\n",
|
|
srb->TargetId,
|
|
sectorsPerTrack,
|
|
numberOfHeads,
|
|
numberOfCylinders));
|
|
DebugPrint((1,
|
|
"IDE CHS disk Identify data%x - #sectors %x, #heads %x, #cylinders %x\n",
|
|
srb->TargetId,
|
|
identifyData->NumSectorsPerTrack,
|
|
identifyData->NumHeads,
|
|
identifyData->NumCylinders));
|
|
DebugPrint((1,
|
|
"IDE CHS disk Identify currentdata%x - #sectors %x, #heads %x, #cylinders %x\n",
|
|
srb->TargetId,
|
|
identifyData->CurrentSectorsPerTrack,
|
|
identifyData->NumberOfCurrentHeads,
|
|
identifyData->NumberOfCurrentCylinders));
|
|
}
|
|
|
|
((READ_CAPACITY_DATA UNALIGNED *)srb->DataBuffer)->LogicalBlockAddress =
|
|
(((PUCHAR)&i)[0] << 24) | (((PUCHAR)&i)[1] << 16) |
|
|
(((PUCHAR)&i)[2] << 8) | ((PUCHAR)&i)[3];
|
|
|
|
srb->SrbStatus = SRB_STATUS_SUCCESS;
|
|
|
|
irp->IoStatus.Information = sizeof(READ_CAPACITY_DATA);
|
|
|
|
}
|
|
|
|
KeReleaseSpinLock(spinLock, currentIrql);
|
|
|
|
} else {
|
|
|
|
if (srb) {
|
|
if (Status==STATUS_INSUFFICIENT_RESOURCES) {
|
|
srb->SrbStatus=SRB_STATUS_INTERNAL_ERROR;
|
|
srb->InternalStatus=STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
else {
|
|
srb->SrbStatus = SRB_STATUS_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (srb) {
|
|
|
|
//
|
|
// restoring DataBuffer
|
|
//
|
|
srb->DataBuffer = context->OldDataBuffer;
|
|
}
|
|
|
|
UnrefLogicalUnitExtensionWithTag(
|
|
context->PdoExtension->ParentDeviceExtension,
|
|
context->PdoExtension,
|
|
irp
|
|
);
|
|
|
|
IDEPORT_PUT_LUNEXT_IN_IRP (irpStack, NULL);
|
|
|
|
ExFreePool (context);
|
|
|
|
irp->IoStatus.Status = Status;
|
|
IoCompleteRequest(irp, IO_NO_INCREMENT);
|
|
return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DeviceIdeModeSense (
|
|
IN PPDO_EXTENSION PdoExtension,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irpStack;
|
|
PSCSI_REQUEST_BLOCK srb;
|
|
PCDB cdb;
|
|
ULONG modeDataBufferSize;
|
|
ULONG dataBufferSize;
|
|
ULONG dataBufferByteLeft;
|
|
PMODE_PARAMETER_HEADER modePageHeader;
|
|
PUCHAR pageData;
|
|
PHW_DEVICE_EXTENSION hwDeviceExtension;
|
|
|
|
PAGED_CODE();
|
|
|
|
hwDeviceExtension = PdoExtension->ParentDeviceExtension->HwDeviceExtension;
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
srb = irpStack->Parameters.Scsi.Srb;
|
|
cdb = (PCDB) srb->Cdb;
|
|
|
|
//
|
|
// Check for device present flag
|
|
//
|
|
if (!(hwDeviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_DEVICE_PRESENT)) {
|
|
|
|
srb->SrbStatus = SRB_STATUS_NO_DEVICE;
|
|
|
|
UnrefLogicalUnitExtensionWithTag(
|
|
PdoExtension->ParentDeviceExtension,
|
|
PdoExtension,
|
|
Irp
|
|
);
|
|
|
|
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
ASSERT(cdb->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE);
|
|
|
|
//
|
|
// make sure this is for the right lun
|
|
//
|
|
if (cdb->MODE_SENSE.LogicalUnitNumber != PdoExtension->Lun) {
|
|
|
|
srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
goto getout;
|
|
}
|
|
|
|
//
|
|
// only support page control for current values
|
|
//
|
|
if (cdb->MODE_SENSE.Pc != 0) {
|
|
|
|
srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
goto getout;
|
|
}
|
|
|
|
//
|
|
// save the data buffer size for later use
|
|
//
|
|
modeDataBufferSize = srb->DataTransferLength;
|
|
|
|
//
|
|
// make sure the output buffer is at least the size of the header
|
|
//
|
|
if (modeDataBufferSize < sizeof(MODE_PARAMETER_HEADER)) {
|
|
|
|
srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
goto getout;
|
|
}
|
|
|
|
//
|
|
// some basic init.
|
|
//
|
|
modePageHeader = srb->DataBuffer;
|
|
pageData = (PUCHAR) (modePageHeader + 1);
|
|
RtlZeroMemory (modePageHeader, modeDataBufferSize);
|
|
ASSERT (modeDataBufferSize);
|
|
ASSERT (modePageHeader);
|
|
|
|
modePageHeader->ModeDataLength = sizeof(MODE_PARAMETER_HEADER) -
|
|
FIELD_OFFSET(MODE_PARAMETER_HEADER, MediumType);
|
|
|
|
//
|
|
// get write protect bit from smart data
|
|
//
|
|
if (hwDeviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED) {
|
|
|
|
ATA_PASS_THROUGH ataPassThroughData;
|
|
NTSTATUS localStatus;
|
|
|
|
RtlZeroMemory (
|
|
&ataPassThroughData,
|
|
sizeof (ataPassThroughData)
|
|
);
|
|
|
|
ataPassThroughData.IdeReg.bCommandReg = IDE_COMMAND_GET_MEDIA_STATUS;
|
|
ataPassThroughData.IdeReg.bReserved = ATA_PTFLAGS_STATUS_DRDY_REQUIRED;
|
|
|
|
localStatus = IssueSyncAtaPassThroughSafe (
|
|
PdoExtension->ParentDeviceExtension,
|
|
PdoExtension,
|
|
&ataPassThroughData,
|
|
FALSE,
|
|
FALSE,
|
|
DEFAULT_ATA_PASS_THROUGH_TIMEOUT,
|
|
FALSE);
|
|
|
|
if (ataPassThroughData.IdeReg.bCommandReg & IDE_STATUS_ERROR) {
|
|
|
|
if (ataPassThroughData.IdeReg.bFeaturesReg & IDE_ERROR_DATA_ERROR){
|
|
|
|
modePageHeader->DeviceSpecificParameter |= MODE_DSP_WRITE_PROTECT;
|
|
}
|
|
}
|
|
}
|
|
|
|
dataBufferByteLeft = modeDataBufferSize - sizeof(MODE_PARAMETER_HEADER);
|
|
|
|
if ((cdb->MODE_SENSE.PageCode == MODE_SENSE_RETURN_ALL) ||
|
|
(cdb->MODE_SENSE.PageCode == MODE_PAGE_CACHING)) {
|
|
|
|
if (dataBufferByteLeft >= sizeof(MODE_CACHING_PAGE)) {
|
|
|
|
//
|
|
// cache settings page
|
|
//
|
|
|
|
PMODE_CACHING_PAGE cachePage;
|
|
|
|
cachePage = (PMODE_CACHING_PAGE) pageData;
|
|
|
|
cachePage->PageCode = MODE_PAGE_CACHING;
|
|
cachePage->PageSavable = 0;
|
|
cachePage->PageLength = 0xa;
|
|
cachePage->ReadDisableCache = 0;
|
|
cachePage->WriteCacheEnable = PdoExtension->WriteCacheEnable;
|
|
|
|
//
|
|
// update out data buffer pointer
|
|
//
|
|
pageData += sizeof (MODE_CACHING_PAGE);
|
|
dataBufferByteLeft -= sizeof (MODE_CACHING_PAGE);
|
|
modePageHeader->ModeDataLength += sizeof (MODE_CACHING_PAGE);
|
|
|
|
} else {
|
|
|
|
srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
|
|
srb->DataTransferLength -= dataBufferByteLeft;
|
|
Irp->IoStatus.Information = srb->DataTransferLength;
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
goto getout;
|
|
}
|
|
}
|
|
|
|
//
|
|
// update the number of bytes we are returning
|
|
//
|
|
srb->DataTransferLength -= dataBufferByteLeft;
|
|
Irp->IoStatus.Information = srb->DataTransferLength;
|
|
status = STATUS_SUCCESS;
|
|
srb->SrbStatus = SRB_STATUS_SUCCESS;
|
|
|
|
getout:
|
|
|
|
UnrefPdoWithTag(
|
|
PdoExtension,
|
|
Irp
|
|
);
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
DeviceIdeModeSelect (
|
|
IN PPDO_EXTENSION PdoExtension,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irpStack;
|
|
PSCSI_REQUEST_BLOCK srb;
|
|
PCDB cdb;
|
|
|
|
ULONG modeDataBufferSize;
|
|
PMODE_PARAMETER_HEADER modePageHeader;
|
|
PUCHAR modePage;
|
|
ULONG pageOffset;
|
|
PMODE_CACHING_PAGE cachePage;
|
|
PHW_DEVICE_EXTENSION hwDeviceExtension;
|
|
|
|
PAGED_CODE();
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
srb = irpStack->Parameters.Scsi.Srb;
|
|
cdb = (PCDB) srb->Cdb;
|
|
|
|
hwDeviceExtension = PdoExtension->ParentDeviceExtension->HwDeviceExtension;
|
|
|
|
//
|
|
// Check for device present flag
|
|
//
|
|
if (!(hwDeviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_DEVICE_PRESENT)) {
|
|
|
|
srb->SrbStatus = SRB_STATUS_NO_DEVICE;
|
|
|
|
UnrefLogicalUnitExtensionWithTag(
|
|
PdoExtension->ParentDeviceExtension,
|
|
PdoExtension,
|
|
Irp
|
|
);
|
|
|
|
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
ASSERT(cdb->MODE_SELECT.OperationCode == SCSIOP_MODE_SELECT);
|
|
|
|
//
|
|
// make sure this is for the right lun
|
|
//
|
|
if (cdb->MODE_SELECT.LogicalUnitNumber != PdoExtension->Lun) {
|
|
|
|
srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
goto getout;
|
|
}
|
|
|
|
//
|
|
// only support scsi-2 mode select format
|
|
//
|
|
if (cdb->MODE_SELECT.PFBit != 1) {
|
|
|
|
srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
goto getout;
|
|
}
|
|
|
|
modeDataBufferSize = cdb->MODE_SELECT.ParameterListLength;
|
|
modePageHeader = srb->DataBuffer;
|
|
|
|
if (modeDataBufferSize < sizeof(MODE_PARAMETER_HEADER)) {
|
|
srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
goto getout;
|
|
}
|
|
|
|
pageOffset = sizeof(MODE_PARAMETER_HEADER) + modePageHeader->BlockDescriptorLength;
|
|
|
|
while (modeDataBufferSize > pageOffset) {
|
|
|
|
modePage = ((PUCHAR) modePageHeader) + pageOffset;
|
|
cachePage = (PMODE_CACHING_PAGE) modePage;
|
|
|
|
if ((cachePage->PageCode == MODE_PAGE_CACHING) &&
|
|
((modePageHeader->ModeDataLength - pageOffset) >= sizeof(MODE_CACHING_PAGE)) &&
|
|
(cachePage->PageLength == 0xa)) {
|
|
|
|
if (cachePage->WriteCacheEnable != PdoExtension->WriteCacheEnable) {
|
|
|
|
ATA_PASS_THROUGH ataPassThroughData;
|
|
NTSTATUS localStatus;
|
|
|
|
RtlZeroMemory (
|
|
&ataPassThroughData,
|
|
sizeof (ataPassThroughData)
|
|
);
|
|
|
|
if (cachePage->WriteCacheEnable) {
|
|
ataPassThroughData.IdeReg.bFeaturesReg = IDE_SET_FEATURE_ENABLE_WRITE_CACHE;
|
|
} else {
|
|
ataPassThroughData.IdeReg.bFeaturesReg = IDE_SET_FEATURE_DISABLE_WRITE_CACHE;
|
|
}
|
|
ataPassThroughData.IdeReg.bCommandReg = IDE_COMMAND_SET_FEATURE;
|
|
ataPassThroughData.IdeReg.bReserved = ATA_PTFLAGS_STATUS_DRDY_REQUIRED;
|
|
|
|
localStatus = IssueSyncAtaPassThroughSafe (
|
|
PdoExtension->ParentDeviceExtension,
|
|
PdoExtension,
|
|
&ataPassThroughData,
|
|
FALSE,
|
|
FALSE,
|
|
DEFAULT_ATA_PASS_THROUGH_TIMEOUT,
|
|
FALSE);
|
|
|
|
if (NT_SUCCESS(localStatus) &&
|
|
!(ataPassThroughData.IdeReg.bCommandReg & IDE_STATUS_ERROR)) {
|
|
|
|
PdoExtension->WriteCacheEnable = cachePage->WriteCacheEnable;
|
|
} else {
|
|
status = STATUS_IO_DEVICE_ERROR;
|
|
srb->SrbStatus = SRB_STATUS_ERROR;
|
|
goto getout;
|
|
}
|
|
|
|
}
|
|
|
|
pageOffset += sizeof(MODE_CACHING_PAGE);
|
|
|
|
} else {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
srb->SrbStatus = SRB_STATUS_ERROR;
|
|
goto getout;
|
|
}
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
srb->SrbStatus = SRB_STATUS_SUCCESS;
|
|
|
|
getout:
|
|
|
|
UnrefPdoWithTag(
|
|
PdoExtension,
|
|
Irp
|
|
);
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DeviceQueryPnPDeviceState (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PPDO_EXTENSION pdoExtension;
|
|
|
|
pdoExtension = RefPdoWithTag(
|
|
DeviceObject,
|
|
TRUE,
|
|
DeviceQueryPnPDeviceState
|
|
);
|
|
|
|
if (pdoExtension) {
|
|
|
|
PPNP_DEVICE_STATE deviceState;
|
|
|
|
DebugPrint((DBG_PNP, "QUERY_DEVICE_STATE for PDOE 0x%x\n", pdoExtension));
|
|
|
|
if(pdoExtension->PagingPathCount != 0) {
|
|
deviceState = (PPNP_DEVICE_STATE) &(Irp->IoStatus.Information);
|
|
SETMASK((*deviceState), PNP_DEVICE_NOT_DISABLEABLE);
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
UnrefPdoWithTag(
|
|
pdoExtension,
|
|
DeviceQueryPnPDeviceState
|
|
);
|
|
|
|
} else {
|
|
|
|
status = STATUS_DEVICE_DOES_NOT_EXIST;
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
DeviceAtapiModeCommandCompletion (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Description
|
|
|
|
Completes the original irp after copying the data from the current srb
|
|
|
|
Arguments:
|
|
|
|
DeviceObject Not used
|
|
Irp The irp - Not used
|
|
Context Srb
|
|
|
|
Return value:
|
|
|
|
STATUS_MORE_PROCESSING_REQUIRED
|
|
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION irpStack;
|
|
PIDE_MODE_COMMAND_CONTEXT context = Context;
|
|
PSCSI_REQUEST_BLOCK srb = context->Srb;
|
|
PSCSI_REQUEST_BLOCK originalSrb;
|
|
PIRP originalIrp;
|
|
UCHAR bytesAdjust = sizeof(MODE_PARAMETER_HEADER_10) -
|
|
sizeof(MODE_PARAMETER_HEADER);
|
|
ULONG transferLength;
|
|
|
|
//
|
|
// retrieve the original srb and the irp
|
|
//
|
|
originalSrb = *((PVOID *) (srb+1));
|
|
ASSERT(originalSrb);
|
|
|
|
originalIrp = originalSrb->OriginalRequest;
|
|
ASSERT(originalIrp);
|
|
|
|
transferLength = srb->DataTransferLength;
|
|
|
|
if (srb->Cdb[0] == ATAPI_MODE_SENSE) {
|
|
|
|
PMODE_PARAMETER_HEADER_10 header_10 = (PMODE_PARAMETER_HEADER_10)(srb->DataBuffer);
|
|
PMODE_PARAMETER_HEADER header = (PMODE_PARAMETER_HEADER)(originalSrb->DataBuffer);
|
|
|
|
header->ModeDataLength = header_10->ModeDataLengthLsb;
|
|
header->MediumType = header_10->MediumType;
|
|
|
|
//
|
|
// ATAPI Mode Parameter Header doesn't have these fields.
|
|
//
|
|
|
|
header->DeviceSpecificParameter = header_10->Reserved[0];
|
|
|
|
//
|
|
// ISSUE:
|
|
//
|
|
header->BlockDescriptorLength = header_10->Reserved[4];
|
|
|
|
//
|
|
// copy the rest of the data
|
|
//
|
|
|
|
if (transferLength > sizeof(MODE_PARAMETER_HEADER_10)) {
|
|
|
|
RtlMoveMemory((PUCHAR)originalSrb->DataBuffer+sizeof(MODE_PARAMETER_HEADER),
|
|
(PUCHAR)srb->DataBuffer+sizeof(MODE_PARAMETER_HEADER_10),
|
|
transferLength - sizeof(MODE_PARAMETER_HEADER_10));
|
|
}
|
|
|
|
DebugPrint((1,
|
|
"Mode Sense completed - status 0x%x, length 0x%x\n",
|
|
srb->SrbStatus,
|
|
srb->DataTransferLength
|
|
));
|
|
|
|
|
|
} else if (srb->Cdb[0] == ATAPI_MODE_SELECT) {
|
|
|
|
DebugPrint((1,
|
|
"Mode Select completed - status 0x%x, length 0x%x\n",
|
|
srb->SrbStatus,
|
|
srb->DataTransferLength
|
|
));
|
|
} else {
|
|
|
|
ASSERT (FALSE);
|
|
}
|
|
|
|
//
|
|
// update the original srb
|
|
//
|
|
originalSrb->DataBuffer = context->OriginalDataBuffer;
|
|
originalSrb->SrbStatus = srb->SrbStatus;
|
|
originalSrb->ScsiStatus = srb->ScsiStatus;
|
|
|
|
if (transferLength > bytesAdjust) {
|
|
originalSrb->DataTransferLength = transferLength - bytesAdjust;
|
|
} else {
|
|
|
|
//
|
|
// error. transfer length should be zero.
|
|
// if it is less than the header, we will just pass it up.
|
|
//
|
|
originalSrb->DataTransferLength = transferLength;
|
|
}
|
|
|
|
//
|
|
// Decrement the logUnitExtension reference count
|
|
//
|
|
irpStack = IoGetCurrentIrpStackLocation(originalIrp);
|
|
|
|
UnrefLogicalUnitExtensionWithTag(
|
|
IDEPORT_GET_LUNEXT_IN_IRP(irpStack)->ParentDeviceExtension,
|
|
IDEPORT_GET_LUNEXT_IN_IRP(irpStack),
|
|
originalIrp
|
|
);
|
|
|
|
//
|
|
// we will follow the same logic as we did for srb data transfer length.
|
|
//
|
|
if (Irp->IoStatus.Information > bytesAdjust) {
|
|
originalIrp->IoStatus.Information = Irp->IoStatus.Information - bytesAdjust;
|
|
} else {
|
|
originalIrp->IoStatus.Information = Irp->IoStatus.Information;
|
|
}
|
|
originalIrp->IoStatus.Status = Irp->IoStatus.Status;
|
|
|
|
DebugPrint((1,
|
|
"Original Mode command completed - status 0x%x, length 0x%x, irpstatus 0x%x\n",
|
|
originalSrb->SrbStatus,
|
|
originalSrb->DataTransferLength,
|
|
originalIrp->IoStatus.Status
|
|
));
|
|
|
|
IoCompleteRequest(originalIrp, IO_NO_INCREMENT);
|
|
|
|
//
|
|
// Free the srb, buffer and the irp
|
|
//
|
|
ASSERT(srb->DataBuffer);
|
|
ExFreePool(srb->DataBuffer);
|
|
|
|
ExFreePool(srb);
|
|
|
|
ExFreePool(context);
|
|
|
|
IdeFreeIrpAndMdl(Irp);
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
NTSTATUS
|
|
DeviceAtapiModeSense (
|
|
IN PPDO_EXTENSION PdoExtension,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
PSCSI_REQUEST_BLOCK originalSrb = irpStack->Parameters.Scsi.Srb;
|
|
PSCSI_REQUEST_BLOCK srb = NULL;
|
|
NTSTATUS status;
|
|
PVOID *pointer;
|
|
PCDB cdb;
|
|
PVOID modeSenseBuffer;
|
|
PUCHAR dataOffset;
|
|
PIDE_MODE_COMMAND_CONTEXT context;
|
|
PMODE_PARAMETER_HEADER_10 header_10;
|
|
PMODE_PARAMETER_HEADER header;
|
|
UCHAR bytesAdjust = sizeof(MODE_PARAMETER_HEADER_10) -
|
|
sizeof(MODE_PARAMETER_HEADER);
|
|
USHORT allocationLength;
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
context = NULL;
|
|
srb = NULL;
|
|
|
|
//
|
|
// databuffer should be as big as the header
|
|
//
|
|
if (originalSrb->DataTransferLength < sizeof(MODE_PARAMETER_HEADER)) {
|
|
|
|
originalSrb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
goto GetOut;
|
|
}
|
|
|
|
//
|
|
// allocate the context
|
|
//
|
|
context = ExAllocatePool (
|
|
NonPagedPool,
|
|
sizeof(IDE_MODE_COMMAND_CONTEXT)
|
|
);
|
|
|
|
if (context == NULL) {
|
|
|
|
IdeLogNoMemoryError(PdoExtension->ParentDeviceExtension,
|
|
PdoExtension->TargetId,
|
|
NonPagedPool,
|
|
sizeof(IDE_MODE_COMMAND_CONTEXT),
|
|
IDEPORT_TAG_ATAPI_MODE_SENSE
|
|
);
|
|
|
|
originalSrb->SrbStatus = SRB_STATUS_INTERNAL_ERROR;
|
|
originalSrb->InternalStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto GetOut;
|
|
}
|
|
|
|
ASSERT(context);
|
|
|
|
context->OriginalDataBuffer = originalSrb->DataBuffer;
|
|
|
|
if (Irp->MdlAddress == NULL) {
|
|
|
|
originalSrb->SrbStatus = SRB_STATUS_INTERNAL_ERROR;
|
|
originalSrb->InternalStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto GetOut;
|
|
}
|
|
|
|
//
|
|
// map the buffer in
|
|
//
|
|
dataOffset = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority);
|
|
originalSrb->DataBuffer = dataOffset +
|
|
(ULONG)((PUCHAR)originalSrb->DataBuffer -
|
|
(PCCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress));
|
|
//
|
|
// allocate a new srb
|
|
//
|
|
srb = ExAllocatePool (NonPagedPool,
|
|
sizeof (SCSI_REQUEST_BLOCK)+ sizeof(PVOID));
|
|
|
|
if (srb == NULL) {
|
|
|
|
IdeLogNoMemoryError(PdoExtension->ParentDeviceExtension,
|
|
PdoExtension->TargetId,
|
|
NonPagedPool,
|
|
sizeof(SCSI_REQUEST_BLOCK),
|
|
IDEPORT_TAG_ATAPI_MODE_SENSE
|
|
);
|
|
|
|
originalSrb->SrbStatus = SRB_STATUS_INTERNAL_ERROR;
|
|
originalSrb->InternalStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto GetOut;
|
|
}
|
|
|
|
//
|
|
// Save the original SRB after the Srb.
|
|
//
|
|
pointer = (PVOID *) (srb+1);
|
|
*pointer = originalSrb;
|
|
|
|
//
|
|
// Fill in SRB fields.
|
|
//
|
|
RtlCopyMemory(srb, originalSrb, sizeof(SCSI_REQUEST_BLOCK));
|
|
|
|
//
|
|
// Allocate a new buffer
|
|
//
|
|
modeSenseBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
|
|
originalSrb->DataTransferLength + bytesAdjust
|
|
);
|
|
|
|
RtlZeroMemory(modeSenseBuffer,originalSrb->DataTransferLength+bytesAdjust);
|
|
header_10 = (PMODE_PARAMETER_HEADER_10)modeSenseBuffer;
|
|
header = (PMODE_PARAMETER_HEADER)(originalSrb->DataBuffer);
|
|
|
|
header_10->ModeDataLengthLsb = header->ModeDataLength;
|
|
header_10->MediumType = header->MediumType;
|
|
|
|
header_10->Reserved[4] = header->BlockDescriptorLength;
|
|
|
|
srb->DataBuffer = modeSenseBuffer;
|
|
srb->DataTransferLength = originalSrb->DataTransferLength + bytesAdjust;
|
|
|
|
srb->CdbLength = 12;
|
|
|
|
allocationLength = ((PCDB)originalSrb->Cdb)->MODE_SENSE.AllocationLength;
|
|
allocationLength += bytesAdjust;
|
|
|
|
cdb = (PCDB) srb->Cdb;
|
|
|
|
RtlZeroMemory(cdb, sizeof(CDB));
|
|
|
|
cdb->MODE_SENSE10.OperationCode = ATAPI_MODE_SENSE;
|
|
cdb->MODE_SENSE10.LogicalUnitNumber = ((PCDB)originalSrb->Cdb)->MODE_SENSE.LogicalUnitNumber;
|
|
cdb->MODE_SENSE10.PageCode = ((PCDB)originalSrb->Cdb)->MODE_SENSE.PageCode;
|
|
cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR) (allocationLength >> 8);
|
|
cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR) (allocationLength & 0xFF);
|
|
|
|
context->Srb = srb;
|
|
|
|
//
|
|
// send the srb
|
|
//
|
|
status = IdeBuildAndSendIrp (PdoExtension,
|
|
srb,
|
|
DeviceAtapiModeCommandCompletion,
|
|
context
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
ASSERT(status == STATUS_PENDING);
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
GetOut:
|
|
|
|
if (srb) {
|
|
ExFreePool(srb);
|
|
}
|
|
|
|
if (context) {
|
|
|
|
originalSrb->DataBuffer = context->OriginalDataBuffer;
|
|
ExFreePool(context);
|
|
}
|
|
|
|
UnrefLogicalUnitExtensionWithTag(
|
|
PdoExtension->ParentDeviceExtension,
|
|
PdoExtension,
|
|
Irp
|
|
);
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
NTSTATUS
|
|
DeviceAtapiModeSelect (
|
|
IN PPDO_EXTENSION PdoExtension,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
PSCSI_REQUEST_BLOCK originalSrb = irpStack->Parameters.Scsi.Srb;
|
|
PSCSI_REQUEST_BLOCK srb = NULL;
|
|
NTSTATUS status;
|
|
PVOID *pointer;
|
|
PCDB cdb;
|
|
PVOID modeSelectBuffer;
|
|
PUCHAR dataOffset;
|
|
PIDE_MODE_COMMAND_CONTEXT context;
|
|
PMODE_PARAMETER_HEADER_10 header_10;
|
|
PMODE_PARAMETER_HEADER header;
|
|
UCHAR bytesToSkip;
|
|
UCHAR bytesAdjust = sizeof(MODE_PARAMETER_HEADER_10) -
|
|
sizeof(MODE_PARAMETER_HEADER);
|
|
USHORT paramListLength;
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
context = NULL;
|
|
srb = NULL;
|
|
|
|
//
|
|
// the databuffer should be big enough to hold the header
|
|
//
|
|
if (originalSrb->DataTransferLength < sizeof(MODE_PARAMETER_HEADER)) {
|
|
|
|
originalSrb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
goto GetOut;
|
|
}
|
|
|
|
header = (PMODE_PARAMETER_HEADER)(originalSrb->DataBuffer);
|
|
|
|
//
|
|
// do not copy the block descriptor. Atapi devices don't use
|
|
// the block descriptor.
|
|
//
|
|
bytesToSkip = sizeof(MODE_PARAMETER_HEADER) +
|
|
header->BlockDescriptorLength;
|
|
|
|
//
|
|
// the databuffer should be big enough to hold the header
|
|
// and the block descriptor (specified in the header)
|
|
//
|
|
if (originalSrb->DataTransferLength < bytesToSkip) {
|
|
|
|
originalSrb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
goto GetOut;
|
|
}
|
|
|
|
//
|
|
// allocate the context
|
|
//
|
|
context = ExAllocatePool (
|
|
NonPagedPool,
|
|
sizeof(IDE_MODE_COMMAND_CONTEXT)
|
|
);
|
|
|
|
if (context == NULL) {
|
|
|
|
IdeLogNoMemoryError(PdoExtension->ParentDeviceExtension,
|
|
PdoExtension->TargetId,
|
|
NonPagedPool,
|
|
sizeof(IDE_MODE_COMMAND_CONTEXT),
|
|
IDEPORT_TAG_ATAPI_MODE_SENSE
|
|
);
|
|
|
|
originalSrb->SrbStatus = SRB_STATUS_INTERNAL_ERROR;
|
|
originalSrb->InternalStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto GetOut;
|
|
}
|
|
|
|
ASSERT(context);
|
|
|
|
context->OriginalDataBuffer = originalSrb->DataBuffer;
|
|
|
|
if (Irp->MdlAddress == NULL) {
|
|
|
|
originalSrb->SrbStatus = SRB_STATUS_INTERNAL_ERROR;
|
|
originalSrb->InternalStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto GetOut;
|
|
}
|
|
|
|
//
|
|
// map the buffer in
|
|
//
|
|
dataOffset = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority);
|
|
originalSrb->DataBuffer = dataOffset +
|
|
(ULONG)((PUCHAR)originalSrb->DataBuffer -
|
|
(PCCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress));
|
|
|
|
//
|
|
// allocate a new srb
|
|
//
|
|
srb = ExAllocatePool (NonPagedPool,
|
|
sizeof (SCSI_REQUEST_BLOCK)+ sizeof(PVOID));
|
|
|
|
if (srb == NULL) {
|
|
|
|
IdeLogNoMemoryError(PdoExtension->ParentDeviceExtension,
|
|
PdoExtension->TargetId,
|
|
NonPagedPool,
|
|
sizeof(SCSI_REQUEST_BLOCK),
|
|
IDEPORT_TAG_ATAPI_MODE_SENSE
|
|
);
|
|
|
|
originalSrb->SrbStatus = SRB_STATUS_INTERNAL_ERROR;
|
|
originalSrb->InternalStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto GetOut;
|
|
}
|
|
|
|
//
|
|
// Save the original SRB after the Srb.
|
|
//
|
|
pointer = (PVOID *) (srb+1);
|
|
*pointer = originalSrb;
|
|
|
|
//
|
|
// Fill in SRB fields.
|
|
//
|
|
RtlCopyMemory(srb, originalSrb, sizeof(SCSI_REQUEST_BLOCK));
|
|
|
|
//
|
|
// Allocate a new buffer (we should subtract the block descriptor length
|
|
// leave it like this for the time being)
|
|
//
|
|
modeSelectBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
|
|
originalSrb->DataTransferLength + bytesAdjust
|
|
);
|
|
|
|
RtlZeroMemory(modeSelectBuffer, sizeof(MODE_PARAMETER_HEADER_10));
|
|
header_10 = (PMODE_PARAMETER_HEADER_10)modeSelectBuffer;
|
|
|
|
header_10->ModeDataLengthLsb = header->ModeDataLength;
|
|
header_10->MediumType = header->MediumType;
|
|
|
|
//
|
|
// block descriptor length in header_10 should be 0 for ATAPI devices
|
|
//
|
|
//header_10->Reserved[4] = header->BlockDescriptorLength;
|
|
|
|
//
|
|
// copy the rest of the buffer, if any
|
|
//
|
|
if (originalSrb->DataTransferLength > bytesToSkip) {
|
|
|
|
RtlCopyMemory(((PUCHAR)modeSelectBuffer+sizeof(MODE_PARAMETER_HEADER_10)),
|
|
((PUCHAR)originalSrb->DataBuffer + bytesToSkip),
|
|
(originalSrb->DataTransferLength - bytesToSkip)
|
|
);
|
|
}
|
|
|
|
/*
|
|
RtlCopyMemory(((PUCHAR)modeSelectBuffer+sizeof(MODE_PARAMETER_HEADER_10)),
|
|
((PUCHAR)originalSrb->DataBuffer + sizeof(MODE_PARAMETER_HEADER)),
|
|
(originalSrb->DataTransferLength - sizeof(MODE_PARAMETER_HEADER))
|
|
);
|
|
*/
|
|
|
|
srb->DataBuffer = modeSelectBuffer;
|
|
srb->DataTransferLength = originalSrb->DataTransferLength +
|
|
sizeof(MODE_PARAMETER_HEADER_10) -
|
|
bytesToSkip;
|
|
|
|
srb->CdbLength = 12;
|
|
|
|
paramListLength = ((PCDB)originalSrb->Cdb)->MODE_SELECT.ParameterListLength;
|
|
paramListLength += sizeof(MODE_PARAMETER_HEADER_10);
|
|
paramListLength -= bytesToSkip;
|
|
|
|
//
|
|
// fill in the cdb
|
|
//
|
|
cdb = (PCDB) srb->Cdb;
|
|
|
|
RtlZeroMemory(cdb, sizeof(CDB));
|
|
|
|
cdb->MODE_SELECT10.OperationCode = ATAPI_MODE_SELECT;
|
|
cdb->MODE_SELECT10.LogicalUnitNumber = ((PCDB)originalSrb->Cdb)->MODE_SELECT.LogicalUnitNumber;
|
|
cdb->MODE_SELECT10.SPBit = ((PCDB)originalSrb->Cdb)->MODE_SELECT.SPBit;
|
|
cdb->MODE_SELECT10.PFBit = 1;
|
|
cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR) (paramListLength >> 8);
|
|
cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR) (paramListLength & 0xFF);
|
|
|
|
context->Srb = srb;
|
|
|
|
//
|
|
// send the srb
|
|
//
|
|
status = IdeBuildAndSendIrp (PdoExtension,
|
|
srb,
|
|
DeviceAtapiModeCommandCompletion,
|
|
context
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
ASSERT(status == STATUS_PENDING);
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
GetOut:
|
|
|
|
if (srb) {
|
|
ExFreePool(srb);
|
|
}
|
|
|
|
if (context) {
|
|
|
|
originalSrb->DataBuffer = context->OriginalDataBuffer;
|
|
|
|
ExFreePool(context);
|
|
}
|
|
|
|
UnrefLogicalUnitExtensionWithTag(
|
|
PdoExtension->ParentDeviceExtension,
|
|
PdoExtension,
|
|
Irp
|
|
);
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_PENDING;
|
|
|
|
}
|
|
|
|
#if 0
|
|
NTSTATUS
|
|
DeviceIdeTestUnitReady (
|
|
IN PPDO_EXTENSION PdoExtension,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irpStack;
|
|
PSCSI_REQUEST_BLOCK srb;
|
|
PHW_DEVICE_EXTENSION hwDeviceExtension;
|
|
|
|
PAGED_CODE();
|
|
|
|
hwDeviceExtension = PdoExtension->ParentDeviceExtension->HwDeviceExtension;
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
srb = irpStack->Parameters.Scsi.Srb;
|
|
|
|
//
|
|
// get write protect bit from smart data
|
|
//
|
|
if (hwDeviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED) {
|
|
|
|
ATA_PASS_THROUGH ataPassThroughData;
|
|
NTSTATUS localStatus;
|
|
|
|
RtlZeroMemory (
|
|
&ataPassThroughData,
|
|
sizeof (ataPassThroughData)
|
|
);
|
|
|
|
ataPassThroughData.IdeReg.bCommandReg = IDE_COMMAND_GET_MEDIA_STATUS;
|
|
ataPassThroughData.IdeReg.bReserved = ATA_PTFLAGS_STATUS_DRDY_REQUIRED;
|
|
|
|
localStatus = IssueSyncAtaPassThroughSafe (
|
|
PdoExtension->ParentDeviceExtension,
|
|
PdoExtension,
|
|
&ataPassThroughData,
|
|
FALSE,
|
|
FALSE,
|
|
DEFAULT_ATA_PASS_THROUGH_TIMEOUT,
|
|
FALSE);
|
|
|
|
if (NT_SUCCESS(localStatus)) {
|
|
|
|
if (ataPassThroughData.IdeReg.bCommandReg & IDE_STATUS_ERROR){
|
|
if (ataPassThroughData.IdeReg.bFeaturesReg & IDE_ERROR_DATA_ERROR){
|
|
//
|
|
// Special case: If current media is write-protected,
|
|
// the 0xDA command will always fail since the write-protect bit
|
|
// is sticky,so we can ignore this error
|
|
//
|
|
status = SRB_STATUS_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
dataBufferByteLeft = modeDataBufferSize - sizeof(MODE_PARAMETER_HEADER);
|
|
|
|
if (IsNEC_98) {
|
|
|
|
HANDLE pageHandle;
|
|
ULONG numberOfCylinders;
|
|
ULONG numberOfHeads;
|
|
ULONG sectorsPerTrack;
|
|
KIRQL currentIrql;
|
|
PKSPIN_LOCK spinLock;
|
|
|
|
//
|
|
// take a snap shot of the CHS values
|
|
//
|
|
spinLock = &PdoExtension->ParentDeviceExtension->SpinLock;
|
|
|
|
//
|
|
// lock the code before grabbing a lock
|
|
//
|
|
pageHandle = MmLockPagableCodeSection(DeviceIdeModeSense);
|
|
KeAcquireSpinLock(spinLock, ¤tIrql);
|
|
|
|
numberOfCylinders = hwDeviceExtension->NumberOfCylinders[srb->TargetId];
|
|
numberOfHeads = hwDeviceExtension->NumberOfHeads[srb->TargetId];
|
|
sectorsPerTrack = hwDeviceExtension->SectorsPerTrack[srb->TargetId];
|
|
|
|
KeReleaseSpinLock(spinLock, currentIrql);
|
|
MmUnlockPagableImageSection(pageHandle);
|
|
|
|
//
|
|
// Set pages which are formated as nec-scsi.
|
|
//
|
|
if ((cdb->MODE_SENSE.PageCode == MODE_SENSE_RETURN_ALL) ||
|
|
(cdb->MODE_SENSE.PageCode == MODE_PAGE_ERROR_RECOVERY)) {
|
|
|
|
//
|
|
// error recovery page
|
|
//
|
|
|
|
if (dataBufferByteLeft >= 0x6 + 2) {
|
|
|
|
PMODE_DISCONNECT_PAGE recoveryPage;
|
|
|
|
recoveryPage = (PMODE_DISCONNECT_PAGE) pageData;
|
|
|
|
recoveryPage->PageCode = MODE_PAGE_ERROR_RECOVERY;
|
|
recoveryPage->PageLength = 0x6;
|
|
|
|
//
|
|
// update out data buffer pointer
|
|
//
|
|
pageData += recoveryPage->PageLength + 2;
|
|
dataBufferByteLeft -= (recoveryPage->PageLength + 2);
|
|
modePageHeader->ModeDataLength += recoveryPage->PageLength + 2;
|
|
|
|
} else {
|
|
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
goto getout;
|
|
}
|
|
}
|
|
|
|
if ((cdb->MODE_SENSE.PageCode == MODE_SENSE_RETURN_ALL) ||
|
|
(cdb->MODE_SENSE.PageCode == MODE_PAGE_FORMAT_DEVICE)) {
|
|
|
|
//
|
|
// format device page
|
|
//
|
|
|
|
if (dataBufferByteLeft >= 0x16 + 2) {
|
|
|
|
PMODE_FORMAT_PAGE formatPage;
|
|
|
|
formatPage = (PMODE_FORMAT_PAGE) pageData;
|
|
|
|
formatPage->PageCode = MODE_PAGE_FORMAT_DEVICE;
|
|
formatPage->PageLength = 0x16;
|
|
|
|
//
|
|
// SectorsPerTrack
|
|
//
|
|
((PFOUR_BYTE)&formatPage->SectorsPerTrack[0])->Byte1 =
|
|
((PFOUR_BYTE)§orsPerTrack)->Byte0;
|
|
|
|
((PFOUR_BYTE)&formatPage->SectorsPerTrack[0])->Byte0 =
|
|
((PFOUR_BYTE)§orsPerTrack)->Byte1;
|
|
|
|
//
|
|
// update out data buffer pointer
|
|
//
|
|
pageData += formatPage->PageLength + 2;
|
|
dataBufferByteLeft -= (formatPage->PageLength + 2);
|
|
modePageHeader->ModeDataLength += formatPage->PageLength + 2;
|
|
|
|
} else {
|
|
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
goto getout;
|
|
}
|
|
}
|
|
|
|
if ((cdb->MODE_SENSE.PageCode == MODE_SENSE_RETURN_ALL) ||
|
|
(cdb->MODE_SENSE.PageCode == MODE_PAGE_RIGID_GEOMETRY)) {
|
|
|
|
//
|
|
// rigid geometry page
|
|
//
|
|
|
|
if (dataBufferByteLeft >= 0x12 + 2) {
|
|
|
|
PMODE_RIGID_GEOMETRY_PAGE geometryPage;
|
|
|
|
geometryPage = (PMODE_RIGID_GEOMETRY_PAGE) pageData;
|
|
|
|
geometryPage->PageCode = MODE_PAGE_RIGID_GEOMETRY;
|
|
geometryPage->PageLength = 0x12;
|
|
|
|
//
|
|
// NumberOfHeads
|
|
//
|
|
geometryPage->NumberOfHeads = (UCHAR) numberOfHeads;
|
|
|
|
//
|
|
// NumberOfCylinders
|
|
//
|
|
((PFOUR_BYTE)&geometryPage->NumberOfCylinders)->Byte2
|
|
= ((PFOUR_BYTE)&numberOfCylinders)->Byte0;
|
|
((PFOUR_BYTE)&geometryPage->NumberOfCylinders)->Byte1
|
|
= ((PFOUR_BYTE)&numberOfCylinders)->Byte1;
|
|
((PFOUR_BYTE)&geometryPage->NumberOfCylinders)->Byte0
|
|
= 0;
|
|
|
|
//
|
|
// update out data buffer pointer
|
|
//
|
|
pageData += geometryPage->PageLength + 2;
|
|
dataBufferByteLeft -= (geometryPage->PageLength + 2);
|
|
modePageHeader->ModeDataLength += geometryPage->PageLength + 2;
|
|
|
|
} else {
|
|
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
goto getout;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((cdb->MODE_SENSE.PageCode == MODE_SENSE_RETURN_ALL) ||
|
|
(cdb->MODE_SENSE.PageCode == MODE_PAGE_CACHING)) {
|
|
|
|
if (dataBufferByteLeft >= sizeof(MODE_CACHING_PAGE)) {
|
|
|
|
//
|
|
// cache settings page
|
|
//
|
|
|
|
PMODE_CACHING_PAGE cachePage;
|
|
|
|
cachePage = (PMODE_CACHING_PAGE) pageData;
|
|
|
|
cachePage->PageCode = MODE_PAGE_CACHING;
|
|
cachePage->PageSavable = 0;
|
|
cachePage->PageLength = 0xa;
|
|
cachePage->ReadDisableCache = 0;
|
|
cachePage->WriteCacheEnable = PdoExtension->WriteCacheEnable;
|
|
|
|
//
|
|
// update out data buffer pointer
|
|
//
|
|
pageData += sizeof (MODE_CACHING_PAGE);
|
|
dataBufferByteLeft -= sizeof (MODE_CACHING_PAGE);
|
|
modePageHeader->ModeDataLength += sizeof (MODE_CACHING_PAGE);
|
|
|
|
} else {
|
|
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
goto getout;
|
|
}
|
|
}
|
|
|
|
//
|
|
// update the number of bytes we are returning
|
|
//
|
|
srb->DataTransferLength -= dataBufferByteLeft;
|
|
Irp->IoStatus.Information = srb->DataTransferLength;
|
|
status = STATUS_SUCCESS;
|
|
srb->SrbStatus = SRB_STATUS_SUCCESS;
|
|
|
|
getout:
|
|
|
|
UnrefPdoWithTag(
|
|
PdoExtension,
|
|
Irp
|
|
);
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
#endif
|