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.
857 lines
22 KiB
857 lines
22 KiB
/*++
|
|
|
|
Copyright (c) 1995-1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ezwrite.c
|
|
|
|
Abstract:
|
|
|
|
Arbitration Support routines for clusdisk.c
|
|
|
|
Authors:
|
|
|
|
Gor Nishanov 11-June-1998
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "clusdskp.h"
|
|
#include "clusvmsg.h"
|
|
#include "diskarbp.h"
|
|
#include <strsafe.h> // Should be included last.
|
|
|
|
#if !defined(WMI_TRACING)
|
|
|
|
#define CDLOG0(Dummy)
|
|
#define CDLOG(Dummy1,Dummy2)
|
|
#define CDLOGFLG(Dummy0,Dummy1,Dummy2)
|
|
#define LOGENABLED(Dummy) FALSE
|
|
|
|
#else
|
|
|
|
#include "ezwrite.tmh"
|
|
|
|
#endif // !defined(WMI_TRACING)
|
|
|
|
#define ARBITRATION_BUFFER_SIZE PAGE_SIZE
|
|
|
|
PARBITRATION_ID gArbitrationBuffer = 0;
|
|
|
|
NTSTATUS
|
|
ArbitrationInitialize(
|
|
VOID
|
|
)
|
|
{
|
|
gArbitrationBuffer = ExAllocatePool(NonPagedPool, ARBITRATION_BUFFER_SIZE);
|
|
if( gArbitrationBuffer == NULL ) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(gArbitrationBuffer, ARBITRATION_BUFFER_SIZE);
|
|
KeQuerySystemTime( &gArbitrationBuffer->SystemTime );
|
|
gArbitrationBuffer->SeqNo.QuadPart = 2; // UserMode arbitration uses 0 and 1 //
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
ArbitrationDone(
|
|
VOID
|
|
)
|
|
{
|
|
if(gArbitrationBuffer != 0) {
|
|
ExFreePool(gArbitrationBuffer);
|
|
gArbitrationBuffer = 0;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ArbitrationTick(
|
|
VOID
|
|
)
|
|
{
|
|
// InterlockedIncrement(&gArbitrationBuffer->SeqNo.LowPart);
|
|
++gArbitrationBuffer->SeqNo.QuadPart;
|
|
}
|
|
|
|
BOOLEAN
|
|
ValidSectorSize(
|
|
IN ULONG SectorSize)
|
|
{
|
|
// too big //
|
|
if (SectorSize > ARBITRATION_BUFFER_SIZE) {
|
|
return FALSE;
|
|
}
|
|
|
|
// too small //
|
|
if (SectorSize < sizeof(ARBITRATION_ID)) {
|
|
return FALSE;
|
|
}
|
|
|
|
// not a power of two //
|
|
if (SectorSize & (SectorSize - 1) ) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
NTSTATUS
|
|
VerifyArbitrationArgumentsIfAny(
|
|
IN PULONG InputData,
|
|
IN LONG InputSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process Parameters Passed to IOCTL_DISK_CLUSTER_START_RESERVE.
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension - The target device extension
|
|
InputData - InputData array from Irp
|
|
InputSize - its size
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
PSTART_RESERVE_DATA params = (PSTART_RESERVE_DATA)InputData;
|
|
|
|
// Old style StartReserve //
|
|
if( InputSize == sizeof(ULONG) ) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// We have less arguments than we need //
|
|
if( InputSize < sizeof(START_RESERVE_DATA) ) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
// Wrong Version //
|
|
if(params->Version != START_RESERVE_DATA_V1_SIG) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
// Signature size is invalid //
|
|
if (params->NodeSignatureSize > sizeof(params->NodeSignature)) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if( !ValidSectorSize(params->SectorSize) ) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
ProcessArbitrationArgumentsIfAny(
|
|
IN PCLUS_DEVICE_EXTENSION DeviceExtension,
|
|
IN PULONG InputData,
|
|
IN LONG InputSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process Parameters Passed to IOCTL_DISK_CLUSTER_START_RESERVE.
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension - The target device extension
|
|
InputData - InputData array from Irp
|
|
InputSize - its size
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
Notes:
|
|
|
|
Assumes that parameters are valid.
|
|
Use VerifyArbitrationArgumentsIfAny to verify parameters
|
|
|
|
--*/
|
|
{
|
|
PSTART_RESERVE_DATA params = (PSTART_RESERVE_DATA)InputData;
|
|
|
|
DeviceExtension->SectorSize = 0; // Invalidate Sector Size //
|
|
|
|
// old style StartReserve //
|
|
if( InputSize == sizeof(ULONG) ) {
|
|
return;
|
|
}
|
|
|
|
RtlCopyMemory(gArbitrationBuffer->NodeSignature,
|
|
params->NodeSignature, params->NodeSignatureSize);
|
|
|
|
DeviceExtension->ArbitrationSector = params->ArbitrationSector;
|
|
DeviceExtension->SectorSize = params->SectorSize;
|
|
}
|
|
|
|
NTSTATUS
|
|
DoUncheckedReadWrite(
|
|
IN PCLUS_DEVICE_EXTENSION DeviceExtension,
|
|
IN PARBITRATION_READ_WRITE_PARAMS params
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prepares read/write IRP and executes it synchronously
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension - The target device extension
|
|
params - Describes offset, operation, buffer, etc
|
|
This structure is defined in cluster\inc\diskarbp.h
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PIRP irp;
|
|
NTSTATUS status;
|
|
PKEVENT event;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
LARGE_INTEGER offset;
|
|
ULONG function = (params->Operation == AE_READ)?IRP_MJ_READ:IRP_MJ_WRITE;
|
|
ULONG retryCount = 1;
|
|
|
|
event = ExAllocatePool( NonPagedPool,
|
|
sizeof(KEVENT) );
|
|
if ( !event ) {
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
retry:
|
|
|
|
KeInitializeEvent(event,
|
|
NotificationEvent,
|
|
FALSE);
|
|
|
|
offset.QuadPart = (ULONGLONG) (params->SectorSize * params->SectorNo);
|
|
|
|
irp = IoBuildSynchronousFsdRequest(function,
|
|
DeviceExtension->TargetDeviceObject,
|
|
params->Buffer,
|
|
params->SectorSize,
|
|
&offset,
|
|
event,
|
|
&ioStatusBlock);
|
|
|
|
if ( irp == NULL ) {
|
|
ExFreePool( event );
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
status = IoCallDriver(DeviceExtension->TargetDeviceObject,
|
|
irp);
|
|
|
|
if (status == STATUS_PENDING) {
|
|
KeWaitForSingleObject(event,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
status = ioStatusBlock.Status;
|
|
}
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
if ( retryCount-- &&
|
|
(status == STATUS_IO_DEVICE_ERROR) ) {
|
|
goto retry;
|
|
}
|
|
ClusDiskPrint((
|
|
1,
|
|
"[ClusDisk] Failed read/write for Signature %08X, status %lx.\n",
|
|
DeviceExtension->Signature,
|
|
status
|
|
));
|
|
}
|
|
|
|
ExFreePool(event);
|
|
|
|
return(status);
|
|
|
|
} // DoUncheckedReadWrite //
|
|
|
|
|
|
NTSTATUS
|
|
WriteToArbitrationSector(
|
|
IN PCLUS_DEVICE_EXTENSION DeviceExtension,
|
|
IN PARB_RESERVE_COMPLETION Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Writes to an Arbitration Sector asynchronously.
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension - The device extension for the physical device to reserve.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
LARGE_INTEGER offset;
|
|
|
|
PIRP irp = NULL;
|
|
PIO_STACK_LOCATION irpStack;
|
|
PARB_RESERVE_COMPLETION arbContext;
|
|
|
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|
|
|
if (0 == gArbitrationBuffer || 0 == DeviceExtension->SectorSize) {
|
|
status = STATUS_SUCCESS;
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Acquire remove lock for this device. If the IRP is sent, it will be
|
|
// released in the completion routine.
|
|
//
|
|
|
|
status = AcquireRemoveLock( &DeviceExtension->RemoveLock, WriteToArbitrationSector );
|
|
if ( !NT_SUCCESS(status) ) {
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// If context is non-null, then we are retrying this I/O. If null,
|
|
// we need to allocate a context structure for the write.
|
|
//
|
|
|
|
if ( Context ) {
|
|
arbContext = Context;
|
|
arbContext->IoEndTime.QuadPart = (ULONGLONG) 0;
|
|
|
|
} else {
|
|
|
|
arbContext = ExAllocatePool( NonPagedPool, sizeof(ARB_RESERVE_COMPLETION) );
|
|
|
|
if ( !arbContext ) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
ReleaseRemoveLock( &DeviceExtension->RemoveLock, WriteToArbitrationSector );
|
|
goto FnExit;
|
|
}
|
|
|
|
RtlZeroMemory( arbContext, sizeof(ARB_RESERVE_COMPLETION) );
|
|
|
|
//
|
|
// Fill in context structure. Note we do not specify the optional
|
|
// routines as the write failure is not critical.
|
|
//
|
|
|
|
arbContext->RetriesLeft = 1;
|
|
arbContext->LockTag = WriteToArbitrationSector;
|
|
arbContext->DeviceObject = DeviceExtension->DeviceObject;
|
|
arbContext->DeviceExtension = DeviceExtension;
|
|
arbContext->Type = ArbIoWrite;
|
|
}
|
|
|
|
KeQuerySystemTime( &arbContext->IoStartTime );
|
|
|
|
offset.QuadPart = (ULONGLONG) (DeviceExtension->SectorSize * DeviceExtension->ArbitrationSector);
|
|
|
|
irp = IoBuildAsynchronousFsdRequest( IRP_MJ_WRITE,
|
|
DeviceExtension->TargetDeviceObject,
|
|
gArbitrationBuffer,
|
|
DeviceExtension->SectorSize,
|
|
&offset,
|
|
NULL );
|
|
|
|
if ( NULL == irp ) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
ExFreePool( arbContext );
|
|
ReleaseRemoveLock( &DeviceExtension->RemoveLock, WriteToArbitrationSector );
|
|
goto FnExit;
|
|
}
|
|
|
|
InterlockedIncrement( &DeviceExtension->ArbWriteCount );
|
|
|
|
IoSetCompletionRoutine( irp,
|
|
ArbReserveCompletion,
|
|
arbContext,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE );
|
|
|
|
ClusDiskPrint(( 4,
|
|
"[ClusDisk] ArbWrite IRP %p for DO %p DiskNo %u Sig %08X \n",
|
|
irp,
|
|
DeviceExtension->DeviceObject,
|
|
DeviceExtension->DiskNumber,
|
|
DeviceExtension->Signature ));
|
|
|
|
status = IoCallDriver( DeviceExtension->TargetDeviceObject,
|
|
irp );
|
|
|
|
FnExit:
|
|
|
|
return status;
|
|
|
|
} // WriteToArbitrationSector
|
|
|
|
|
|
NTSTATUS
|
|
ArbReserveCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completion routine for the asynchronous arbitration write.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject
|
|
|
|
Irp - Asynchoronous arbitration write.
|
|
|
|
Context - Pointer to ARB_RESERVE_COMPLETION structure.
|
|
|
|
Return Value:
|
|
|
|
STATUS_MORE_PROCESSING_REQUIRED - must be returned or system will fail!
|
|
|
|
--*/
|
|
{
|
|
PARB_RESERVE_COMPLETION arbContext = Context;
|
|
PCLUS_DEVICE_EXTENSION deviceExtension;
|
|
PIO_WORKITEM workItem = NULL;
|
|
|
|
PVOID lockTag;
|
|
|
|
if ( NULL == DeviceObject ) {
|
|
DeviceObject = arbContext->DeviceObject;
|
|
}
|
|
|
|
deviceExtension = arbContext->DeviceExtension;
|
|
|
|
arbContext->FinalStatus = Irp->IoStatus.Status;
|
|
|
|
//
|
|
// Save lock tag here because the context may be freed by the time
|
|
// we need to release remove lock.
|
|
//
|
|
|
|
lockTag = arbContext->LockTag;
|
|
|
|
KeQuerySystemTime( &arbContext->IoEndTime );
|
|
|
|
//
|
|
// Decrement the correct counter based on this I/O type.
|
|
//
|
|
|
|
if ( ArbIoReserve == arbContext->Type ) {
|
|
InterlockedDecrement( &deviceExtension->ReserveCount );
|
|
} else if ( ArbIoWrite == arbContext->Type ) {
|
|
InterlockedDecrement( &deviceExtension->ArbWriteCount );
|
|
}
|
|
|
|
ClusDiskPrint(( 4,
|
|
"[ClusDisk] %s IRP %p for DO %p DiskNo %u Sig %08X status %08X \n",
|
|
ArbIoReserve == arbContext->Type ? "Reserve " : "ArbWrite",
|
|
Irp,
|
|
deviceExtension->DeviceObject,
|
|
deviceExtension->DiskNumber,
|
|
deviceExtension->Signature,
|
|
arbContext->FinalStatus ));
|
|
|
|
//
|
|
// Retry this request (at least once) for specific failures.
|
|
//
|
|
|
|
if ( arbContext->RetriesLeft-- &&
|
|
STATUS_IO_DEVICE_ERROR == arbContext->FinalStatus &&
|
|
arbContext->RetryRoutine ) {
|
|
|
|
ClusDiskPrint(( 1,
|
|
"[ClusDisk] Retrying %s for DO %p DiskNo %u Sig %08X \n",
|
|
ArbIoReserve == arbContext->Type ? "Reserve " : "ArbWrite",
|
|
deviceExtension->DeviceObject,
|
|
deviceExtension->DiskNumber,
|
|
deviceExtension->Signature ));
|
|
|
|
//
|
|
// Since we are running in an I/O completion routine, this routine
|
|
// could be running at any IRQL up to DISPATCH_LEVEL. It would be
|
|
// bad to call back into the driver stack at this level, so queue
|
|
// a work item to retry the I/O.
|
|
//
|
|
// Queue the workitem. IoQueueWorkItem will insure that the device object
|
|
// referenced while the work-item progresses.
|
|
//
|
|
|
|
workItem = IoAllocateWorkItem( DeviceObject );
|
|
|
|
if ( workItem ) {
|
|
|
|
arbContext->WorkItem = workItem;
|
|
|
|
IoQueueWorkItem( workItem,
|
|
RequeueArbReserveIo,
|
|
DelayedWorkQueue,
|
|
Context );
|
|
}
|
|
|
|
} else if ( !NT_SUCCESS(arbContext->FinalStatus) ) {
|
|
|
|
//
|
|
// If not successful, call the optional failure routine.
|
|
//
|
|
|
|
if ( arbContext->FailureRoutine ) {
|
|
|
|
(arbContext->FailureRoutine)( arbContext->DeviceExtension,
|
|
arbContext );
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// On success, call the optional post completion routine.
|
|
//
|
|
|
|
if ( arbContext->PostCompletionRoutine ) {
|
|
|
|
(arbContext->PostCompletionRoutine)( arbContext->DeviceExtension,
|
|
arbContext );
|
|
}
|
|
}
|
|
|
|
ReleaseRemoveLock( &deviceExtension->RemoveLock, lockTag );
|
|
|
|
//
|
|
// If we did not allocate a work item, the I/O was not retried and we
|
|
// have to free the context.
|
|
//
|
|
|
|
if ( !workItem ) {
|
|
|
|
ExFreePool( Context );
|
|
}
|
|
|
|
//
|
|
// Unlock and free the MDL. Then free the IRP.
|
|
//
|
|
|
|
if (Irp->MdlAddress != NULL) {
|
|
|
|
MmUnlockPages( Irp->MdlAddress );
|
|
IoFreeMdl( Irp->MdlAddress );
|
|
Irp->MdlAddress = NULL;
|
|
}
|
|
|
|
IoFreeIrp( Irp );
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
|
|
} // ArbReserveCompletion
|
|
|
|
|
|
RequeueArbReserveIo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine runs in a system worker thread. It will call
|
|
the specified retry routine to requeue a new I/O.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject
|
|
|
|
Context - Pointer to ARB_RESERVE_COMPLETION structure.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PARB_RESERVE_COMPLETION arbContext = Context;
|
|
|
|
BOOLEAN freeArbContext = FALSE;
|
|
|
|
//
|
|
// Call the real routines to rebuild and re-issue the I/O request.
|
|
//
|
|
|
|
if ( arbContext->RetryRoutine ) {
|
|
(arbContext->RetryRoutine)( DeviceObject->DeviceExtension,
|
|
Context );
|
|
} else {
|
|
freeArbContext = TRUE;
|
|
}
|
|
|
|
IoFreeWorkItem( arbContext->WorkItem );
|
|
|
|
if ( freeArbContext ) {
|
|
ExFreePool( Context );
|
|
}
|
|
|
|
} // RequeueArbReserveIo
|
|
|
|
|
|
|
|
VOID
|
|
ArbitrationWrite(
|
|
IN PCLUS_DEVICE_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
status = WriteToArbitrationSector( DeviceExtension, NULL );
|
|
if ( !NT_SUCCESS(status) ) {
|
|
|
|
CDLOGF(RESERVE,"ArbitrationWrite(%p) => %!status!",
|
|
DeviceExtension->DeviceObject,
|
|
status );
|
|
|
|
ClusDiskPrint((
|
|
1,
|
|
"[ClusDisk] Failed to write to arb sector on DiskNo %d Sig %08X status %08X \n",
|
|
DeviceExtension->DiskNumber,
|
|
DeviceExtension->Signature,
|
|
status ));
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
SimpleDeviceIoControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN ULONG Ioctl,
|
|
IN PVOID InBuffer,
|
|
IN ULONG InBufferSize,
|
|
IN PVOID OutBuffer,
|
|
IN ULONG OutBufferSize)
|
|
{
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
|
|
PKEVENT event = 0;
|
|
PIRP irp = 0;
|
|
|
|
CDLOG( "SimpleDeviceIoControl(%p): Entry Ioctl %x", DeviceObject, Ioctl );
|
|
|
|
event = ExAllocatePool( NonPagedPool, sizeof(KEVENT) );
|
|
if ( event == NULL ) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
ClusDiskPrint((
|
|
1,
|
|
"[ClusDisk] SimpleDeviceIoControl: Failed to allocate event\n" ));
|
|
goto exit_gracefully;
|
|
}
|
|
|
|
irp = IoBuildDeviceIoControlRequest(
|
|
Ioctl,
|
|
DeviceObject,
|
|
InBuffer, InBufferSize,
|
|
OutBuffer, OutBufferSize,
|
|
FALSE,
|
|
event,
|
|
&ioStatusBlock);
|
|
if ( !irp ) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
ClusDiskPrint((
|
|
1,
|
|
"[ClusDisk] SimpleDeviceIoControl. Failed to build IRP %x.\n",
|
|
Ioctl
|
|
));
|
|
goto exit_gracefully;
|
|
}
|
|
|
|
//
|
|
// Set the event object to the unsignaled state.
|
|
// It will be used to signal request completion.
|
|
//
|
|
|
|
KeInitializeEvent(event, NotificationEvent, FALSE);
|
|
|
|
status = IoCallDriver(DeviceObject, irp);
|
|
|
|
if (status == STATUS_PENDING) {
|
|
|
|
KeWaitForSingleObject(event,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
status = ioStatusBlock.Status;
|
|
}
|
|
|
|
exit_gracefully:
|
|
|
|
if ( event ) {
|
|
ExFreePool( event );
|
|
}
|
|
|
|
CDLOG( "SimpleDeviceIoControl(%p): Exit Ioctl %x => %x",
|
|
DeviceObject, Ioctl, status );
|
|
|
|
return status;
|
|
|
|
} // SimpleDeviceIoControl
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arbitration support routine. Currently provides ability to read/write
|
|
physical sectors on the disk while the device is offline
|
|
|
|
Arguments:
|
|
|
|
SectorSize: requred sector size
|
|
(Assumes that the SectorSize is a power of two)
|
|
|
|
Return Value:
|
|
|
|
STATUS_INVALID_PARAMETER
|
|
STATUS_SUCCESS
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
NTSTATUS
|
|
ProcessArbitrationEscape(
|
|
IN PCLUS_DEVICE_EXTENSION DeviceExtension,
|
|
IN PULONG InputData,
|
|
IN LONG InputSize,
|
|
IN PULONG OutputSize
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_INVALID_PARAMETER;
|
|
PARBITRATION_READ_WRITE_PARAMS params;
|
|
|
|
if( InputData[0] != AE_SECTORSIZE ) {
|
|
*OutputSize = 0;
|
|
}
|
|
|
|
switch(InputData[0]) {
|
|
|
|
// Users can query whether ARBITRATION_ESCAPE is present by calling //
|
|
// AE_TEST subfunction //
|
|
|
|
case AE_TEST:
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case AE_WRITE:
|
|
case AE_READ:
|
|
if(InputSize < ARBITRATION_READ_WRITE_PARAMS_SIZE) {
|
|
break;
|
|
}
|
|
params = (PARBITRATION_READ_WRITE_PARAMS)InputData;
|
|
if ( !ValidSectorSize(params->SectorSize) ) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// This IOCTL is method buffered and the user data buffer is a pointer within
|
|
// this buffered structure. The user buffer is checked now for read/write
|
|
// access, and will be probed and locked in IoBuildSynchronousFsdRequest.
|
|
//
|
|
|
|
try {
|
|
ProbeForWrite( params->Buffer, params->SectorSize, sizeof( UCHAR ) );
|
|
ProbeForRead ( params->Buffer, params->SectorSize, sizeof( UCHAR ) );
|
|
status = DoUncheckedReadWrite(DeviceExtension, params);
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
return GetExceptionCode();
|
|
}
|
|
break;
|
|
|
|
case AE_POKE:
|
|
{
|
|
PARTITION_INFORMATION partInfo;
|
|
|
|
status = SimpleDeviceIoControl(
|
|
DeviceExtension->TargetDeviceObject,
|
|
IOCTL_DISK_GET_PARTITION_INFO,
|
|
NULL, 0,
|
|
&partInfo, sizeof(PARTITION_INFORMATION) );
|
|
break;
|
|
}
|
|
case AE_RESET:
|
|
{
|
|
ClusDiskLogError( DeviceExtension->DriverObject, // OK - DevObj is cluster DevObj
|
|
DeviceExtension->DeviceObject,
|
|
DeviceExtension->ScsiAddress.PathId, // Sequence number
|
|
IRP_MJ_DEVICE_CONTROL, // Major function code
|
|
0, // Retry count
|
|
ID_CLUSTER_ARB_RESET, // Unique error
|
|
STATUS_SUCCESS,
|
|
CLUSDISK_RESET_BUS_REQUESTED,
|
|
0,
|
|
NULL );
|
|
|
|
status = ResetScsiDevice( NULL, &DeviceExtension->ScsiAddress );
|
|
break;
|
|
}
|
|
case AE_RESERVE:
|
|
{
|
|
status = SimpleDeviceIoControl(
|
|
DeviceExtension->TargetDeviceObject,
|
|
IOCTL_STORAGE_RESERVE,
|
|
NULL, 0, NULL, 0 );
|
|
break;
|
|
}
|
|
case AE_RELEASE:
|
|
{
|
|
status = SimpleDeviceIoControl(
|
|
DeviceExtension->TargetDeviceObject,
|
|
IOCTL_STORAGE_RELEASE,
|
|
NULL, 0, NULL, 0 );
|
|
break;
|
|
}
|
|
case AE_SECTORSIZE:
|
|
{
|
|
DISK_GEOMETRY diskGeometry;
|
|
if (*OutputSize < sizeof(ULONG)) {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
*OutputSize = 0;
|
|
break;
|
|
}
|
|
status = SimpleDeviceIoControl(
|
|
DeviceExtension->TargetDeviceObject,
|
|
IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
|
NULL, 0,
|
|
&diskGeometry, sizeof(diskGeometry) );
|
|
|
|
if ( NT_SUCCESS(status) ) {
|
|
*InputData = diskGeometry.BytesPerSector;
|
|
*OutputSize = sizeof(ULONG);
|
|
} else {
|
|
*OutputSize = 0;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(status);
|
|
} // ProcessArbitrationEscape //
|
|
|