diff options
Diffstat (limited to 'storage/class/cdrom/src/scratch.c')
| -rw-r--r-- | storage/class/cdrom/src/scratch.c | 1463 |
1 files changed, 0 insertions, 1463 deletions
diff --git a/storage/class/cdrom/src/scratch.c b/storage/class/cdrom/src/scratch.c deleted file mode 100644 index fe82049a..00000000 --- a/storage/class/cdrom/src/scratch.c +++ /dev/null @@ -1,1463 +0,0 @@ -/*-- - -Copyright (C) Microsoft Corporation. All rights reserved. - -Module Name: - - scratch.c - -Abstract: - - Functions for using common scratch buffer - -Environment: - - kernel mode only - -Notes: - - -Revision History: - ---*/ - -#include "stddef.h" -#include "string.h" - -#include "ntddk.h" -#include "ntddstor.h" -#include "cdrom.h" -#include "ioctl.h" -#include "scratch.h" -#include "mmc.h" - -#ifdef DEBUG_USE_WPP -#include "scratch.tmh" -#endif - -// Forward declarations -EVT_WDF_REQUEST_COMPLETION_ROUTINE ScratchBuffer_ReadWriteCompletionRoutine; - -#ifdef ALLOC_PRAGMA - -#pragma alloc_text(PAGE, ScratchBuffer_Deallocate) -#pragma alloc_text(PAGE, ScratchBuffer_Allocate) -#pragma alloc_text(PAGE, ScratchBuffer_SetupSrb) -#pragma alloc_text(PAGE, ScratchBuffer_ExecuteCdbEx) - -#endif - -_IRQL_requires_max_(APC_LEVEL) -VOID -ScratchBuffer_Deallocate( - _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension - ) -/*++ - -Routine Description: - - release all resources allocated for scratch. - -Arguments: - - DeviceExtension - device extension - -Return Value: - - none - ---*/ -{ - PAGED_CODE (); - - NT_ASSERT(DeviceExtension->ScratchContext.ScratchInUse == 0); - - if (DeviceExtension->ScratchContext.ScratchHistory != NULL) - { - ExFreePool(DeviceExtension->ScratchContext.ScratchHistory); - DeviceExtension->ScratchContext.ScratchHistory = NULL; - } - if (DeviceExtension->ScratchContext.ScratchSense != NULL) - { - ExFreePool(DeviceExtension->ScratchContext.ScratchSense); - DeviceExtension->ScratchContext.ScratchSense = NULL; - } - if (DeviceExtension->ScratchContext.ScratchSrb != NULL) - { - ExFreePool(DeviceExtension->ScratchContext.ScratchSrb); - DeviceExtension->ScratchContext.ScratchSrb = NULL; - } - if (DeviceExtension->ScratchContext.ScratchBufferSize != 0) - { - DeviceExtension->ScratchContext.ScratchBufferSize = 0; - } - if (DeviceExtension->ScratchContext.ScratchBufferMdl != NULL) - { - IoFreeMdl(DeviceExtension->ScratchContext.ScratchBufferMdl); - DeviceExtension->ScratchContext.ScratchBufferMdl = NULL; - } - if (DeviceExtension->ScratchContext.ScratchBuffer != NULL) - { - ExFreePool(DeviceExtension->ScratchContext.ScratchBuffer); - DeviceExtension->ScratchContext.ScratchBuffer = NULL; - } - - if (DeviceExtension->ScratchContext.PartialMdl != NULL) - { - IoFreeMdl(DeviceExtension->ScratchContext.PartialMdl); - DeviceExtension->ScratchContext.PartialMdl = NULL; - } - - if (DeviceExtension->ScratchContext.ScratchRequest != NULL) - { - PIRP irp = WdfRequestWdmGetIrp(DeviceExtension->ScratchContext.ScratchRequest); - if (irp->MdlAddress) - { - irp->MdlAddress = NULL; - } - WdfObjectDelete(DeviceExtension->ScratchContext.ScratchRequest); - DeviceExtension->ScratchContext.ScratchRequest = NULL; - } - - return; -} - -_IRQL_requires_max_(APC_LEVEL) -BOOLEAN -ScratchBuffer_Allocate( - _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension - ) -/*++ - -Routine Description: - - allocate resources allocated for scratch. - -Arguments: - - DeviceExtension - device extension - -Return Value: - - none - ---*/ -{ - NTSTATUS status = STATUS_SUCCESS; - - PAGED_CODE (); - - NT_ASSERT(DeviceExtension->ScratchContext.ScratchInUse == 0); - - // quick-exit if already allocated - if ((DeviceExtension->ScratchContext.ScratchBuffer != NULL) && - (DeviceExtension->ScratchContext.ScratchBufferMdl != NULL) && - (DeviceExtension->ScratchContext.ScratchBufferSize != 0) && - (DeviceExtension->ScratchContext.ScratchRequest != NULL) && - (DeviceExtension->ScratchContext.ScratchSrb != NULL) && - (DeviceExtension->ScratchContext.ScratchHistory != NULL) && - (DeviceExtension->ScratchContext.PartialMdl != NULL) - ) - { - return TRUE; - } - - // validate max transfer already determined - NT_ASSERT(DeviceExtension->DeviceAdditionalData.MaxPageAlignedTransferBytes != 0); - - // validate no partially-saved state - NT_ASSERT(DeviceExtension->ScratchContext.ScratchBuffer == NULL); - NT_ASSERT(DeviceExtension->ScratchContext.ScratchBufferMdl == NULL); - NT_ASSERT(DeviceExtension->ScratchContext.ScratchBufferSize == 0); - NT_ASSERT(DeviceExtension->ScratchContext.ScratchRequest == NULL); - NT_ASSERT(DeviceExtension->ScratchContext.PartialMdl == NULL); - - // limit the scratch buffer to between 4k and 64k (so data length fits into USHORT -- req'd for many commands) - DeviceExtension->ScratchContext.ScratchBufferSize = min(DeviceExtension->DeviceAdditionalData.MaxPageAlignedTransferBytes, (64*1024)); - - // allocate the buffer - if (NT_SUCCESS(status)) - { - DeviceExtension->ScratchContext.ScratchBuffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, - DeviceExtension->ScratchContext.ScratchBufferSize, - CDROM_TAG_SCRATCH); - if (DeviceExtension->ScratchContext.ScratchBuffer == NULL) - { - status = STATUS_INSUFFICIENT_RESOURCES; - TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, - "Failed to allocate scratch buffer of %x bytes\n", - DeviceExtension->ScratchContext.ScratchBufferSize - )); - } - else if (BYTE_OFFSET(DeviceExtension->ScratchContext.ScratchBuffer) != 0) - { - status = STATUS_INTERNAL_ERROR; - TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_INIT, - "Allocation of %x bytes non-paged pool was not " - "allocated on page boundary? STATUS_INTERNAL_ERROR\n", - DeviceExtension->ScratchContext.ScratchBufferSize - )); - } - } - - // allocate the MDL - if (NT_SUCCESS(status)) - { - DeviceExtension->ScratchContext.ScratchBufferMdl = IoAllocateMdl(DeviceExtension->ScratchContext.ScratchBuffer, - DeviceExtension->ScratchContext.ScratchBufferSize, - FALSE, FALSE, NULL); - if (DeviceExtension->ScratchContext.ScratchBufferMdl == NULL) - { - status = STATUS_INSUFFICIENT_RESOURCES; - TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, - "Failed to allocate MDL for %x byte buffer\n", - DeviceExtension->ScratchContext.ScratchBufferSize - )); - } - else - { - MmBuildMdlForNonPagedPool(DeviceExtension->ScratchContext.ScratchBufferMdl); - } - } - - // create the request - if (NT_SUCCESS(status)) - { - WDF_OBJECT_ATTRIBUTES attributes; - WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, - CDROM_REQUEST_CONTEXT); - - status = WdfRequestCreate(&attributes, - DeviceExtension->IoTarget, - &DeviceExtension->ScratchContext.ScratchRequest); - - if ((!NT_SUCCESS(status)) || - (DeviceExtension->ScratchContext.ScratchRequest == NULL)) - { - status = STATUS_INSUFFICIENT_RESOURCES; - TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, - "Failed to allocate scratch MDL \n")); - } - } - - // allocate the srb - if (NT_SUCCESS(status)) - { - DeviceExtension->ScratchContext.ScratchSrb = ExAllocatePool2(POOL_FLAG_NON_PAGED, - sizeof(SCSI_REQUEST_BLOCK), - CDROM_TAG_SCRATCH); - - if (DeviceExtension->ScratchContext.ScratchSrb == NULL) - { - status = STATUS_INSUFFICIENT_RESOURCES; - TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, - "Failed to allocate scratch SRB\n")); - } - } - - // allocate the sense buffer - if (NT_SUCCESS(status)) - { - DeviceExtension->ScratchContext.ScratchSense = ExAllocatePool2(POOL_FLAG_NON_PAGED, - sizeof(SENSE_DATA), - CDROM_TAG_SCRATCH); - - if (DeviceExtension->ScratchContext.ScratchSense == NULL) - { - status = STATUS_INSUFFICIENT_RESOURCES; - TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, - "Failed to allocate scratch sense data\n" - )); - } - } - - // allocate the SRB history data - if (NT_SUCCESS(status)) - { - size_t allocationSize = sizeof(SRB_HISTORY) - sizeof(SRB_HISTORY_ITEM); - allocationSize += 20 * sizeof(SRB_HISTORY_ITEM); - - DeviceExtension->ScratchContext.ScratchHistory = ExAllocatePool2(POOL_FLAG_NON_PAGED, - allocationSize, - CDROM_TAG_SCRATCH); - if (DeviceExtension->ScratchContext.ScratchHistory == NULL) - { - status = STATUS_INSUFFICIENT_RESOURCES; - TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, - "Failed to allocate scratch history buffer\n" - )); - } - else - { - // must be initialized here... - DeviceExtension->ScratchContext.ScratchHistory->TotalHistoryCount = 20; - } - } - - // allocate the MDL - if (NT_SUCCESS(status)) - { - ULONG transferLength = 0; - - status = RtlULongAdd(DeviceExtension->DeviceAdditionalData.MaxPageAlignedTransferBytes, PAGE_SIZE, &transferLength); - if (NT_SUCCESS(status)) - { - DeviceExtension->ScratchContext.PartialMdlIsBuilt = FALSE; - DeviceExtension->ScratchContext.PartialMdl = IoAllocateMdl(NULL, - transferLength, - FALSE, - FALSE, - NULL); - if (DeviceExtension->ScratchContext.PartialMdl == NULL) - { - status = STATUS_INSUFFICIENT_RESOURCES; - TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, - "Failed to allocate MDL for %x byte buffer\n", - DeviceExtension->ScratchContext.ScratchBufferSize - )); - } - else - { - NT_ASSERT(DeviceExtension->ScratchContext.PartialMdl->Size >= - (CSHORT)(sizeof(MDL) + BYTES_TO_PAGES(DeviceExtension->DeviceAdditionalData.MaxPageAlignedTransferBytes) * sizeof(PFN_NUMBER))); - } - } - else - { - status = STATUS_INTEGER_OVERFLOW; - } - } - - // cleanup on failure - if (!NT_SUCCESS(status)) - { - ScratchBuffer_Deallocate(DeviceExtension); - } - - return NT_SUCCESS(status); -} - - -VOID -ScratchBuffer_ResetItems( - _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension, - _In_ BOOLEAN ResetRequestHistory - ) -/*++ - -Routine Description: - - reset scratch items for reuse. - -Arguments: - - DeviceExtension - device extension - ResetRequestHistory - reset history fields or not - -Return Value: - - none - ---*/ -{ - NTSTATUS status = STATUS_SUCCESS; - WDF_REQUEST_REUSE_PARAMS reuseParams; - PIRP irp = NULL; - - NT_ASSERT(DeviceExtension->ScratchContext.ScratchHistory != NULL); - NT_ASSERT(DeviceExtension->ScratchContext.ScratchSense != NULL); - NT_ASSERT(DeviceExtension->ScratchContext.ScratchSrb != NULL); - NT_ASSERT(DeviceExtension->ScratchContext.ScratchRequest != NULL); - NT_ASSERT(DeviceExtension->ScratchContext.ScratchBufferSize != 0); - NT_ASSERT(DeviceExtension->ScratchContext.ScratchBuffer != NULL); - NT_ASSERT(DeviceExtension->ScratchContext.ScratchBufferMdl != NULL); - NT_ASSERT(DeviceExtension->ScratchContext.ScratchInUse != 0); - - irp = WdfRequestWdmGetIrp(DeviceExtension->ScratchContext.ScratchRequest); - - if (ResetRequestHistory) - { - PSRB_HISTORY history = DeviceExtension->ScratchContext.ScratchHistory; - RtlZeroMemory(history->History, sizeof(SRB_HISTORY_ITEM) * history->TotalHistoryCount); - history->ClassDriverUse[0] = 0; - history->ClassDriverUse[1] = 0; - history->ClassDriverUse[2] = 0; - history->ClassDriverUse[3] = 0; - history->UsedHistoryCount = 0; - } - - // re-use the KMDF request object - - // deassign the MdlAddress, this is the value we assign explicitly. - // this is to prevent WdfRequestReuse to release the Mdl unexpectly. - if (irp->MdlAddress) - { - irp->MdlAddress = NULL; - } - - WDF_REQUEST_REUSE_PARAMS_INIT(&reuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED); - status = WdfRequestReuse(DeviceExtension->ScratchContext.ScratchRequest, &reuseParams); - // WDF request to format the request befor sending it - if (NT_SUCCESS(status)) - { - // clean up completion routine. - WdfRequestSetCompletionRoutine(DeviceExtension->ScratchContext.ScratchRequest, NULL, NULL); - - status = WdfIoTargetFormatRequestForInternalIoctlOthers(DeviceExtension->IoTarget, - DeviceExtension->ScratchContext.ScratchRequest, - IOCTL_SCSI_EXECUTE_IN, - NULL, NULL, - NULL, NULL, - NULL, NULL); - if (!NT_SUCCESS(status)) - { - TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, - "ScratchBuffer_ResetItems: WdfIoTargetFormatRequestForInternalIoctlOthers failed, %!STATUS!\n", - status)); - } - } - - RtlZeroMemory(DeviceExtension->ScratchContext.ScratchSense, sizeof(SENSE_DATA)); - RtlZeroMemory(DeviceExtension->ScratchContext.ScratchSrb, sizeof(SCSI_REQUEST_BLOCK)); - - return; -} - - -NTSTATUS -ScratchBuffer_PerformNextReadWrite( - _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, - _In_ BOOLEAN FirstTry - ) -/*++ - -Routine Description: - - This function asynchronously sends the next read/write SRB down the stack. - -Arguments: - - DeviceExtension - Device extension - -Return Value: - - none - ---*/ -{ - PCDROM_SCRATCH_READ_WRITE_CONTEXT readWriteContext = &DeviceExtension->ScratchContext.ScratchReadWriteContext; - PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(DeviceExtension->ScratchContext.ScratchRequest); - WDFREQUEST originalRequest = requestContext->OriginalRequest; - NTSTATUS status = STATUS_SUCCESS; - - ULONG transferSize; - BOOLEAN usePartialMdl; - - transferSize = min((readWriteContext->EntireXferLen - readWriteContext->TransferedBytes), readWriteContext->MaxLength); - - if (FirstTry) - { - DeviceExtension->ScratchContext.NumRetries = 0; - } - - ScratchBuffer_ResetItems(DeviceExtension, FALSE); - - usePartialMdl = (readWriteContext->PacketsCount > 1 || readWriteContext->TransferedBytes > 0); - - ScratchBuffer_SetupReadWriteSrb(DeviceExtension, - originalRequest, - readWriteContext->StartingOffset, - transferSize, - readWriteContext->DataBuffer, - readWriteContext->IsRead, - usePartialMdl - ); - - WdfRequestSetCompletionRoutine(DeviceExtension->ScratchContext.ScratchRequest, - ScratchBuffer_ReadWriteCompletionRoutine, DeviceExtension); - - status = ScratchBuffer_SendSrb(DeviceExtension, FALSE, (FirstTry ? &readWriteContext->SrbHistoryItem : NULL)); - - return status; -} - - -VOID -ScratchBuffer_ReadWriteTimerRoutine( - struct _KDPC *Dpc, - PVOID DeferredContext, - PVOID SystemArgument1, - PVOID SystemArgument2 - ) -/*++ - -Routine Description: - - Timer routine for retrying read and write requests. - -Arguments: - - Timer - WDF timer - -Return Value: - - none - ---*/ -{ - PCDROM_DEVICE_EXTENSION deviceExtension = NULL; - PCDROM_SCRATCH_READ_WRITE_CONTEXT readWriteContext = NULL; - WDFREQUEST originalRequest = NULL; - PCDROM_REQUEST_CONTEXT requestContext = NULL; - NTSTATUS status = STATUS_SUCCESS; - KIRQL oldIrql; - - UNREFERENCED_PARAMETER(Dpc); - UNREFERENCED_PARAMETER(SystemArgument1); - UNREFERENCED_PARAMETER(SystemArgument2); - - if (DeferredContext == NULL) - { - // This is impossible, but definition of KDEFERRED_ROUTINE allows optional argument, - // and thus OACR will complain. - - return; - } - - originalRequest = (WDFREQUEST) DeferredContext; - requestContext = RequestGetContext(originalRequest); - - KeAcquireSpinLock(&requestContext->ReadWriteCancelSpinLock, &oldIrql); - - if (!requestContext->ReadWriteIsCompleted) - { - // As the first step, unregister the cancellation routine - status = WdfRequestUnmarkCancelable(originalRequest); - } - else - { - status = STATUS_CANCELLED; - } - - KeReleaseSpinLock(&requestContext->ReadWriteCancelSpinLock, oldIrql); - - if (status != STATUS_CANCELLED) - { - deviceExtension = requestContext->DeviceExtension; - readWriteContext = &deviceExtension->ScratchContext.ScratchReadWriteContext; - - // We use timer only for retries, that's why the second parameter is always FALSE - status = ScratchBuffer_PerformNextReadWrite(deviceExtension, FALSE); - - if (!NT_SUCCESS(status)) - { - ScratchBuffer_EndUse(deviceExtension); - RequestCompletion(deviceExtension, originalRequest, status, readWriteContext->TransferedBytes); - } - } - - // - // Drop the extra reference - // - WdfObjectDereference(originalRequest); -} - - -EVT_WDF_REQUEST_CANCEL ScratchBuffer_ReadWriteEvtRequestCancel; - -VOID -ScratchBuffer_ReadWriteEvtRequestCancel( - _In_ WDFREQUEST Request - ) -/*++ - -Routine Description: - - Cancels a request waiting for the read/write timer to expire. This function does not - support cancellation of requests that have already been sent down. - -Arguments: - - Request - WDF request - -Return Value: - - none - ---*/ -{ - PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); - PCDROM_DEVICE_EXTENSION deviceExtension = requestContext->DeviceExtension; - PCDROM_SCRATCH_READ_WRITE_CONTEXT readWriteContext = &deviceExtension->ScratchContext.ScratchReadWriteContext; - KIRQL oldIrql; - - KeAcquireSpinLock(&requestContext->ReadWriteCancelSpinLock, &oldIrql); - - if (KeCancelTimer(&requestContext->ReadWriteTimer)) - { - // - // Timer is canceled, we own the request. Drop the reference we took before - // queueing the timer. - // - WdfObjectDereference(Request); - } - else - { - // - // Timer will run and drop the reference but it won't complete the request - // because we set IsCompleted to TRUE - // - } - - requestContext->ReadWriteIsCompleted = TRUE; - - KeReleaseSpinLock(&requestContext->ReadWriteCancelSpinLock, oldIrql); - - ScratchBuffer_EndUse(deviceExtension); - - // If WdfTimerStop returned TRUE, it means this request was scheduled for a retry - // and the retry has not happened yet. We just need to cancel it and release the scratch buffer. - RequestCompletion(deviceExtension, Request, STATUS_CANCELLED, readWriteContext->TransferedBytes); -} - -VOID -ScratchBuffer_ReadWriteCompletionRoutine( - _In_ WDFREQUEST Request, - _In_ WDFIOTARGET Target, - _In_ PWDF_REQUEST_COMPLETION_PARAMS Params, - _In_ WDFCONTEXT Context - ) -/*++ - -Routine Description: - - Read/write request completion routine. - -Arguments: - Request - WDF request - Target - The IO target the request was completed by. - Params - the request completion parameters - Context - context - -Return Value: - - none - ---*/ -{ - PCDROM_DEVICE_EXTENSION deviceExtension = (PCDROM_DEVICE_EXTENSION) Context; - PCDROM_SCRATCH_READ_WRITE_CONTEXT readWriteContext = &deviceExtension->ScratchContext.ScratchReadWriteContext; - NTSTATUS status = STATUS_SUCCESS; - PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(deviceExtension->ScratchContext.ScratchRequest); - WDFREQUEST originalRequest = requestContext->OriginalRequest; - - if (!NT_SUCCESS(WdfRequestGetStatus(Request))) - { - TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, - "WdfRequestSend: %lx\n", - WdfRequestGetStatus(Request) - )); - } - - UNREFERENCED_PARAMETER(Params); - UNREFERENCED_PARAMETER(Target); - - // We are not calling ScratchBuffer_BeginUse / ScratchBuffer_EndUse in this function, because we already own - // the scratch buffer if this function is being called. - - if ((deviceExtension->ScratchContext.ScratchSrb->SrbStatus == SRB_STATUS_ABORTED) && - (deviceExtension->ScratchContext.ScratchSrb->InternalStatus == STATUS_CANCELLED)) - { - // The request has been cancelled, just need to complete it - } - else if (SRB_STATUS(deviceExtension->ScratchContext.ScratchSrb->SrbStatus) != SRB_STATUS_SUCCESS) - { - // The SCSI command that we sent down has failed, retry it if necessary - BOOLEAN shouldRetry = TRUE; - LONGLONG retryIn100nsUnits = 0; - - shouldRetry = RequestSenseInfoInterpretForScratchBuffer(deviceExtension, - deviceExtension->ScratchContext.NumRetries, - &status, - &retryIn100nsUnits); - - if (shouldRetry) - { - deviceExtension->ScratchContext.NumRetries++; - - if (retryIn100nsUnits == 0) - { - // We take a shortcut here by calling ScratchBuffer_PerformNextReadWrite directly: - // this helps to avoid unnecessary context switch. - status = ScratchBuffer_PerformNextReadWrite(deviceExtension, FALSE); - - if (NT_SUCCESS(status)) - { - // We're not done with the request yet, no need to complete it now - return; - } - } - else - { - PCDROM_REQUEST_CONTEXT originalRequestContext = RequestGetContext(originalRequest); - KIRQL oldIrql; - - // - // Initialize the spin lock and timer local to the original request. - // - if (!originalRequestContext->ReadWriteRetryInitialized) - { - KeInitializeSpinLock(&originalRequestContext->ReadWriteCancelSpinLock); - KeInitializeTimer(&originalRequestContext->ReadWriteTimer); - KeInitializeDpc(&originalRequestContext->ReadWriteDpc, ScratchBuffer_ReadWriteTimerRoutine, originalRequest); - originalRequestContext->ReadWriteRetryInitialized = TRUE; - } - - KeAcquireSpinLock(&requestContext->ReadWriteCancelSpinLock, &oldIrql); - - status = WdfRequestMarkCancelableEx(originalRequest, ScratchBuffer_ReadWriteEvtRequestCancel); - - if (status == STATUS_CANCELLED) - { - requestContext->ReadWriteIsCompleted = TRUE; - - KeReleaseSpinLock(&requestContext->ReadWriteCancelSpinLock, oldIrql); - } - else - { - LARGE_INTEGER t; - - t.QuadPart = -retryIn100nsUnits; - - WdfObjectReference(originalRequest); - - // Use negative time to indicate that we want a relative delay - KeSetTimer(&originalRequestContext->ReadWriteTimer, - t, - &originalRequestContext->ReadWriteDpc - ); - - KeReleaseSpinLock(&requestContext->ReadWriteCancelSpinLock, oldIrql); - - return; - } - } - } - } - else - { - // The SCSI command has succeeded - readWriteContext->DataBuffer += deviceExtension->ScratchContext.ScratchSrb->DataTransferLength; - readWriteContext->StartingOffset.QuadPart += deviceExtension->ScratchContext.ScratchSrb->DataTransferLength; - readWriteContext->TransferedBytes += deviceExtension->ScratchContext.ScratchSrb->DataTransferLength; - readWriteContext->PacketsCount--; - - // Update the SRB history item - if (readWriteContext->SrbHistoryItem) - { - ULONG senseSize; - - // Query the tick count and store in the history - KeQueryTickCount(&readWriteContext->SrbHistoryItem->TickCountCompleted); - - // Copy the SRB Status... - readWriteContext->SrbHistoryItem->SrbStatus = deviceExtension->ScratchContext.ScratchSrb->SrbStatus; - - // Determine the amount of valid sense data - if (deviceExtension->ScratchContext.ScratchSrb->SenseInfoBufferLength >= - RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength)) - { - PSENSE_DATA sense = (PSENSE_DATA)deviceExtension->ScratchContext.ScratchSrb->SenseInfoBuffer; - senseSize = RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength) + - sense->AdditionalSenseLength; - senseSize = min(senseSize, sizeof(SENSE_DATA)); - } - else - { - senseSize = deviceExtension->ScratchContext.ScratchSrb->SenseInfoBufferLength; - } - - // Normalize the sense data copy in the history - RtlZeroMemory(&(readWriteContext->SrbHistoryItem->NormalizedSenseData), sizeof(SENSE_DATA)); - RtlCopyMemory(&(readWriteContext->SrbHistoryItem->NormalizedSenseData), - deviceExtension->ScratchContext.ScratchSrb->SenseInfoBuffer, senseSize); - } - - // Check whether we need to send more SCSI commands to complete the request - if (readWriteContext->PacketsCount > 0) - { - status = ScratchBuffer_PerformNextReadWrite(deviceExtension, TRUE); - - if (NT_SUCCESS(status)) - { - // We're not done with the request yet, no need to complete it now - return; - } - } - } - - ScratchBuffer_EndUse(deviceExtension); - - - RequestCompletion(deviceExtension, originalRequest, status, readWriteContext->TransferedBytes); -} - -_IRQL_requires_max_(APC_LEVEL) -VOID -ScratchBuffer_SetupSrb( - _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension, - _In_opt_ WDFREQUEST OriginalRequest, - _In_ ULONG MaximumTransferLength, - _In_ BOOLEAN GetDataFromDevice - ) -/*++ - -Routine Description: - - setup scratch SRB for sending out. - -Arguments: - - DeviceExtension - device extension - OriginalRequest - original request delivered by WDF - MaximumTransferLength - transfer length - GetDataFromDevice - TRUE (get data from device); FALSE (send data to device) - -Return Value: - - none - ---*/ -{ - WDFREQUEST request = DeviceExtension->ScratchContext.ScratchRequest; - PIRP irp = WdfRequestWdmGetIrp(request); - PSCSI_REQUEST_BLOCK srb = DeviceExtension->ScratchContext.ScratchSrb; - PIO_STACK_LOCATION irpStack = NULL; - PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(request); - - PAGED_CODE (); - - requestContext->OriginalRequest = OriginalRequest; - - // set to use the full scratch buffer via the scratch SRB - irpStack = IoGetNextIrpStackLocation(irp); - irpStack->MajorFunction = IRP_MJ_SCSI; - if (MaximumTransferLength == 0) - { - irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_NONE; - } - else if (GetDataFromDevice) - { - irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN; - } - else - { - irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_OUT; - } - irpStack->Parameters.Scsi.Srb = srb; - - if (MaximumTransferLength > 0) - { - // the Irp must show the MDL's address for the transfer - irp->MdlAddress = DeviceExtension->ScratchContext.ScratchBufferMdl; - - srb->DataBuffer = DeviceExtension->ScratchContext.ScratchBuffer; - } - - // prepare the SRB with default values - srb->Length = SCSI_REQUEST_BLOCK_SIZE; - srb->Function = SRB_FUNCTION_EXECUTE_SCSI; - srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; - srb->SrbStatus = 0; - srb->ScsiStatus = 0; - srb->NextSrb = NULL; - srb->OriginalRequest = irp; - srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; - srb->SenseInfoBuffer = DeviceExtension->ScratchContext.ScratchSense; - - srb->CdbLength = 16; // to cause failures if not set correctly -- CD devices limited to 12 bytes for now... - - srb->DataTransferLength = min(DeviceExtension->ScratchContext.ScratchBufferSize, MaximumTransferLength); - srb->TimeOutValue = DeviceExtension->TimeOutValue; - srb->SrbFlags = DeviceExtension->SrbFlags; - SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER); - SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE); - - if (MaximumTransferLength == 0) - { - SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER); - } - else if (GetDataFromDevice) - { - SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN); - } - else - { - SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_OUT); - } -} - - -NTSTATUS -ScratchBuffer_SendSrb( - _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension, - _In_ BOOLEAN SynchronousSrb, - _When_(SynchronousSrb, _Pre_null_) - _When_(!SynchronousSrb, _In_opt_) - PSRB_HISTORY_ITEM *SrbHistoryItem - ) -/*++ - -Routine Description: - - Send the command from the scratch SRB to lower driver and retry if necessary. - -Arguments: - - DeviceExtension - device extension - SynchronousSrb - indicates whether the SRB needs to be sent synchronously or nor - SrbHistoryItem - storage for SRB history item, if this is an asynchronous request - -Return Value: - - none - ---*/ -{ - NTSTATUS status = STATUS_SUCCESS; - PSCSI_REQUEST_BLOCK srb = DeviceExtension->ScratchContext.ScratchSrb; - PSRB_HISTORY history = DeviceExtension->ScratchContext.ScratchHistory; - PSRB_HISTORY_ITEM item = NULL; - BOOLEAN requestCancelled = FALSE; - - srb->InternalStatus = 0; - srb->SrbStatus = 0; - - // allocate/update history pre-command, if it is a synchronous request or we were supplied - // with a storage for the history item - if (SynchronousSrb || SrbHistoryItem != NULL) - { - // sending a packet implies a new history unit is to be used. - NT_ASSERT( history->UsedHistoryCount <= history->TotalHistoryCount ); - - // if already all used up, remove at least one history unit - if (history->UsedHistoryCount == history->TotalHistoryCount ) - { - CompressSrbHistoryData(history); - NT_ASSERT( history->UsedHistoryCount < history->TotalHistoryCount ); - } - - // thus, since we are about to increment the count, it must now be less... - NT_ASSERT( history->UsedHistoryCount < history->TotalHistoryCount ); - - // increment the number of history units in use - history->UsedHistoryCount++; - - // determine index to use - item = &( history->History[ history->UsedHistoryCount-1 ] ); - - if (SrbHistoryItem != NULL) - { - *SrbHistoryItem = item; - } - - // zero out the history item - RtlZeroMemory(item, sizeof(SRB_HISTORY_ITEM)); - - // Query the tick count and store in the history - KeQueryTickCount(&item->TickCountSent); - } - - // get cancellation status; - { - PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(DeviceExtension->ScratchContext.ScratchRequest); - - if (requestContext->OriginalRequest != NULL) - { - requestCancelled = WdfRequestIsCanceled(requestContext->OriginalRequest); - } - } - - if (!requestCancelled) - { - status = RequestSend(DeviceExtension, - DeviceExtension->ScratchContext.ScratchRequest, - DeviceExtension->IoTarget, - SynchronousSrb ? WDF_REQUEST_SEND_OPTION_SYNCHRONOUS : 0, - NULL); - - // If this is a synchronous request, update the history item immediately, including "normalized" sense data - if (SynchronousSrb) - { - ULONG senseSize; - - // Query the tick count and store in the history - KeQueryTickCount(&item->TickCountCompleted); - - // Copy the SRB Status - item->SrbStatus = srb->SrbStatus; - - // Determine the amount of valid sense data - if (srb->SenseInfoBufferLength >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength)) - { - PSENSE_DATA sense = (PSENSE_DATA)srb->SenseInfoBuffer; - senseSize = RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength) + - sense->AdditionalSenseLength; - senseSize = min(senseSize, sizeof(SENSE_DATA)); - } - else - { - senseSize = srb->SenseInfoBufferLength; - } - - // Normalize the sense data copy in the history - RtlZeroMemory(&(item->NormalizedSenseData), sizeof(SENSE_DATA)); - RtlCopyMemory(&(item->NormalizedSenseData), srb->SenseInfoBuffer, senseSize); - } - } - else - { - DeviceExtension->ScratchContext.ScratchSrb->SrbStatus = SRB_STATUS_ABORTED; - DeviceExtension->ScratchContext.ScratchSrb->InternalStatus = (ULONG)STATUS_CANCELLED; - status = STATUS_CANCELLED; - } - - return status; -} - -VOID -CompressSrbHistoryData( - _Inout_ PSRB_HISTORY RequestHistory - ) -/*++ - -Routine Description: - - compress the SRB history data. - -Arguments: - - RequestHistory - SRB history data - -Return Value: - - RequestHistory - compressed history data - ---*/ -{ - ULONG i; - NT_ASSERT( RequestHistory->UsedHistoryCount == RequestHistory->TotalHistoryCount ); - ValidateSrbHistoryDataPresumptions(RequestHistory); - - for (i=0; i < RequestHistory->UsedHistoryCount; i++) - { - // for each item... - PSRB_HISTORY_ITEM toMatch = &( RequestHistory->History[i] ); - // hint: read const qualifiers backwards. i.e. srbstatus is a const UCHAR - // so, "UCHAR const * const x" is read "x is a const pointer to a const UCHAR" - // unfortunately, "const UCHAR" is equivalent to "UCHAR const", which causes - // people no end of confusion due to its widespread use. - UCHAR const srbStatus = toMatch->SrbStatus; - UCHAR const sense = toMatch->NormalizedSenseData.SenseKey; - UCHAR const asc = toMatch->NormalizedSenseData.AdditionalSenseCode; - UCHAR const ascq = toMatch->NormalizedSenseData.AdditionalSenseCodeQualifier; - ULONG j; - - // see if there are any at higher indices with identical Sense/ASC/ASCQ - for (j = i+1; (toMatch->ClassDriverUse != 0xFF) && (j < RequestHistory->UsedHistoryCount); j++) - { - PSRB_HISTORY_ITEM found = &( RequestHistory->History[j] ); - // close enough match? - if ((srbStatus == found->SrbStatus) && - (sense == found->NormalizedSenseData.SenseKey) && - (asc == found->NormalizedSenseData.AdditionalSenseCode) && - (ascq == found->NormalizedSenseData.AdditionalSenseCodeQualifier)) { - - // add the fields to keep reasonable track of delay times. - if (toMatch->MillisecondsDelayOnRetry + found->MillisecondsDelayOnRetry < toMatch->MillisecondsDelayOnRetry) { - toMatch->MillisecondsDelayOnRetry = MAXULONG; - } else { - toMatch->MillisecondsDelayOnRetry += found->MillisecondsDelayOnRetry; - } - - // this found item cannot contain any compressed entries because - // the first entry with a given set of sense/asc/ascq will always - // either be full (0xFF) or be the only partially-full entry with - // that sense/asc/ascq. - NT_ASSERT(found->ClassDriverUse == 0); - // add the counts so we still know how many retries total - toMatch->ClassDriverUse++; - - - // if not the last entry, need to move later entries earlier in the array - if (j != RequestHistory->UsedHistoryCount-1) { - // how many entries remain? - SIZE_T remainingBytes = RequestHistory->UsedHistoryCount - 1 - j; - remainingBytes *= sizeof(SRB_HISTORY_ITEM); - - // note that MOVE is required due to overlapping entries - RtlMoveMemory(found, found+1, remainingBytes); - - // Finally, decrement the number of used history count and - // decrement j to rescan the current location again - --RequestHistory->UsedHistoryCount; - --j; - } // end moving of array elements around - } // end of close enough match - } // end j loop - } // end i loop - - // unable to compress duplicate sense/asc/ascq, so just lose the most recent data - if (RequestHistory->UsedHistoryCount == RequestHistory->TotalHistoryCount) - { - PSRB_HISTORY_ITEM item = &( RequestHistory->History[ RequestHistory->TotalHistoryCount-1 ] ); - RequestHistory->ClassDriverUse[0] += item->ClassDriverUse; // how many did we "lose"? - RequestHistory->UsedHistoryCount--; - } - - // finally, zero any that are no longer in use - NT_ASSERT( RequestHistory->UsedHistoryCount != RequestHistory->TotalHistoryCount); - { - SIZE_T bytesToZero = RequestHistory->TotalHistoryCount - RequestHistory->UsedHistoryCount; - bytesToZero *= sizeof(SRB_HISTORY_ITEM); - RtlZeroMemory(&(RequestHistory->History[RequestHistory->UsedHistoryCount]), bytesToZero); - } - - ValidateSrbHistoryDataPresumptions(RequestHistory); - return; -} - -VOID -ValidateSrbHistoryDataPresumptions( - _In_ SRB_HISTORY const * RequestHistory - ) -{ -#if DBG - // validate that all fully-compressed items are before any non-fully-compressed items of any particular sense/asc/ascq - // validate that there is at most one partially-compressed item of any particular sense/asc/ascq - // validate that all items of any particular sense/asc/ascq that are uncompressed are at the end - // THUS: A(255) A(255) A( 40) A( 0) A( 0) is legal for all types with A as sense/asc/ascq - // A(0) B(255) A( 0) B( 17) B( 0) is also legal because A/B are different types of error - - ULONG i; - for (i = 0; i < RequestHistory->UsedHistoryCount; i++) - { - SRB_HISTORY_ITEM const * toMatch = &( RequestHistory->History[i] ); - UCHAR const srbStatus = toMatch->SrbStatus; - UCHAR const sense = toMatch->NormalizedSenseData.SenseKey; - UCHAR const asc = toMatch->NormalizedSenseData.AdditionalSenseCode; - UCHAR const ascq = toMatch->NormalizedSenseData.AdditionalSenseCodeQualifier; - ULONG j; - - BOOLEAN foundPartiallyCompressedItem = - (toMatch->ClassDriverUse != 0) && - (toMatch->ClassDriverUse != 0xFF) ; - BOOLEAN foundUncompressedItem = - (toMatch->ClassDriverUse == 0) ; - - for (j = i+1; j < RequestHistory->UsedHistoryCount; j++) - { - SRB_HISTORY_ITEM const * found = &( RequestHistory->History[j] ); - if ((srbStatus == found->SrbStatus) && - (sense == found->NormalizedSenseData.SenseKey) && - (asc == found->NormalizedSenseData.AdditionalSenseCode) && - (ascq == found->NormalizedSenseData.AdditionalSenseCodeQualifier) - ) - { - // found a matching type, so validate ordering rules - if (foundUncompressedItem && (found->ClassDriverUse != 0)) - { - DbgPrintEx(DPFLTR_CDROM_ID, DPFLTR_ERROR_LEVEL, - "History data has compressed history following uncompressed history " - "for srbstatus/sense/asc/ascq of %02x/%02x/%02x/%02x at indices %d (%08x) and %d (%08x)\n", - srbStatus, sense, asc, ascq, - i,i, j,j - ); - NT_ASSERT(FALSE); - } - else if (foundPartiallyCompressedItem && (found->ClassDriverUse == 0xFF)) - { - DbgPrintEx(DPFLTR_CDROM_ID, DPFLTR_ERROR_LEVEL, - "History data has fully compressed history following partially compressed history " - "for srbstatus/sense/asc/ascq of %02x/%02x/%02x/%02x at indices %d (%08x) and %d (%08x)\n", - srbStatus, sense, asc, ascq, - i,i, j,j - ); - NT_ASSERT(FALSE); - } - - // update if we have now found partially compressed and/or uncompressed items - if (found->ClassDriverUse == 0) - { - foundUncompressedItem = TRUE; - } - else if (found->ClassDriverUse != 0xFF) - { - foundPartiallyCompressedItem = TRUE; - } - } // end match of (toMatch,found) - } // end loop j - } // end loop i -#else - UNREFERENCED_PARAMETER(RequestHistory); -#endif - return; -} - -VOID -ScratchBuffer_SetupReadWriteSrb( - _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension, - _In_ WDFREQUEST OriginalRequest, - _In_ LARGE_INTEGER StartingOffset, - _In_ ULONG RequiredLength, - _Inout_updates_bytes_(RequiredLength) UCHAR* DataBuffer, - _In_ BOOLEAN IsReadRequest, - _In_ BOOLEAN UsePartialMdl - ) -/*++ - -Routine Description: - - setup SRB for read/write request. - -Arguments: - - DeviceExtension - device extension - OriginalRequest - read/write request - StartingOffset - read/write starting offset - DataBuffer - buffer for read/write - IsReadRequest - TRUE (read); FALSE (write) - -Return Value: - - none - ---*/ -{ - //NOTE: R/W request not use the ScratchBuffer, instead, it uses the buffer associated with IRP. - - PSCSI_REQUEST_BLOCK srb = DeviceExtension->ScratchContext.ScratchSrb; - PCDB cdb = (PCDB)srb->Cdb; - LARGE_INTEGER logicalBlockAddr; - ULONG numTransferBlocks; - - PIRP originalIrp = WdfRequestWdmGetIrp(OriginalRequest); - - PIRP irp = WdfRequestWdmGetIrp(DeviceExtension->ScratchContext.ScratchRequest); - PIO_STACK_LOCATION irpStack = NULL; - - PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(DeviceExtension->ScratchContext.ScratchRequest); - - requestContext->OriginalRequest = OriginalRequest; - - - logicalBlockAddr.QuadPart = Int64ShrlMod32(StartingOffset.QuadPart, DeviceExtension->SectorShift); - numTransferBlocks = RequiredLength >> DeviceExtension->SectorShift; - - // set to use the full scratch buffer via the scratch SRB - irpStack = IoGetNextIrpStackLocation(irp); - irpStack->MajorFunction = IRP_MJ_SCSI; - if (IsReadRequest) - { - irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN; - } - else - { - irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_OUT; - } - irpStack->Parameters.Scsi.Srb = srb; - - // prepare the SRB with default values - srb->Length = SCSI_REQUEST_BLOCK_SIZE; - srb->Function = SRB_FUNCTION_EXECUTE_SCSI; - srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; - srb->SrbStatus = 0; - srb->ScsiStatus = 0; - srb->NextSrb = NULL; - srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; - srb->SenseInfoBuffer = DeviceExtension->ScratchContext.ScratchSense; - - srb->DataBuffer = DataBuffer; - srb->DataTransferLength = RequiredLength; - - srb->QueueSortKey = logicalBlockAddr.LowPart; - if (logicalBlockAddr.QuadPart > 0xFFFFFFFF) - { - // - // If the requested LBA is more than max ULONG set the - // QueueSortKey to the maximum value, so that these - // requests can be added towards the end of the queue. - // - srb->QueueSortKey = 0xFFFFFFFF; - } - - srb->OriginalRequest = irp; - srb->TimeOutValue = DeviceExtension->TimeOutValue; - - if (RequestIsRealtimeStreaming(OriginalRequest, IsReadRequest) && - !TEST_FLAG(DeviceExtension->PrivateFdoData->HackFlags, FDO_HACK_NO_STREAMING)) - { - if (IsReadRequest) - { - RtlZeroMemory(&cdb->READ12, sizeof(cdb->READ12)); - REVERSE_BYTES(&cdb->READ12.LogicalBlock, &logicalBlockAddr.LowPart); - REVERSE_BYTES(&cdb->READ12.TransferLength, &numTransferBlocks); - cdb->READ12.Streaming = 1; - cdb->READ12.OperationCode = SCSIOP_READ12; - srb->CdbLength = sizeof(cdb->READ12); - } - else - { - RtlZeroMemory(&cdb->WRITE12, sizeof(cdb->WRITE12)); - REVERSE_BYTES(&cdb->WRITE12.LogicalBlock, &logicalBlockAddr.LowPart); - REVERSE_BYTES(&cdb->WRITE12.TransferLength, &numTransferBlocks); - cdb->WRITE12.Streaming = 1; - cdb->WRITE12.OperationCode = SCSIOP_WRITE12; - srb->CdbLength = sizeof(cdb->WRITE12); - } - } - else - { - RtlZeroMemory(&cdb->CDB10, sizeof(cdb->CDB10)); - cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte3; - cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte2; - cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte1; - cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte0; - cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&numTransferBlocks)->Byte1; - cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&numTransferBlocks)->Byte0; - cdb->CDB10.OperationCode = (IsReadRequest) ? SCSIOP_READ : SCSIOP_WRITE; - srb->CdbLength = sizeof(cdb->CDB10); - } - - // Set SRB and IRP flags - srb->SrbFlags = DeviceExtension->SrbFlags; - if (TEST_FLAG(originalIrp->Flags, IRP_PAGING_IO) || - TEST_FLAG(originalIrp->Flags, IRP_SYNCHRONOUS_PAGING_IO)) - { - SET_FLAG(srb->SrbFlags, SRB_CLASS_FLAGS_PAGING); - } - - SET_FLAG(srb->SrbFlags, (IsReadRequest) ? SRB_FLAGS_DATA_IN : SRB_FLAGS_DATA_OUT); - SET_FLAG(srb->SrbFlags, SRB_FLAGS_ADAPTER_CACHE_ENABLE); - - // - // If the request is not split, we can use the original IRP MDL. If the - // request needs to be split, we need to use a partial MDL. The partial MDL - // is needed because more than one driver might be mapping the same MDL - // and this causes problems. - // - if (UsePartialMdl == FALSE) - { - irp->MdlAddress = originalIrp->MdlAddress; - } - else - { - if (DeviceExtension->ScratchContext.PartialMdlIsBuilt != FALSE) - { - MmPrepareMdlForReuse(DeviceExtension->ScratchContext.PartialMdl); - } - - IoBuildPartialMdl(originalIrp->MdlAddress, DeviceExtension->ScratchContext.PartialMdl, srb->DataBuffer, srb->DataTransferLength); - DeviceExtension->ScratchContext.PartialMdlIsBuilt = TRUE; - irp->MdlAddress = DeviceExtension->ScratchContext.PartialMdl; - } - - //DBGLOGSENDPACKET(Pkt); - //HISTORYLOGSENDPACKET(Pkt); - - // - // Set the original irp here for SFIO. - // - srb->SrbExtension = (PVOID)(originalIrp); - - return; -} - -_IRQL_requires_max_(APC_LEVEL) -NTSTATUS -ScratchBuffer_ExecuteCdbEx( - _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension, - _In_opt_ WDFREQUEST OriginalRequest, - _In_ ULONG TransferSize, - _In_ BOOLEAN GetDataFromDevice, - _In_ PCDB Cdb, - _In_ UCHAR OprationLength, - _In_ ULONG TimeoutValue - ) -/*++ - -Routine Description: - - Use Scratch buffer to send the Cdb, check error and retry if necessary. - -Arguments: - - DeviceExtension - device context - OriginalRequest - original request that requires this CDB operation - TransferSize - Data transfer size required - GetFromDevice - TRUE if getting data from device. - Cdb - SCSI command - OprationLength - SCSI command length: 6, 10 or 12 - TimeoutValue - if > 0, use it as timeout value for command - if 0, use the default device timeout value - -Return Value: - - NTSTATUS - ---*/ -{ - NTSTATUS status = STATUS_SUCCESS; - PSCSI_REQUEST_BLOCK srb = DeviceExtension->ScratchContext.ScratchSrb; - PCDB cdb = (PCDB)(srb->Cdb); - - BOOLEAN shouldRetry = TRUE; - ULONG timesAlreadyRetried = 0; - LONGLONG retryIn100nsUnits = 0; - - PAGED_CODE (); - - while (shouldRetry) - { - ScratchBuffer_SetupSrb(DeviceExtension, OriginalRequest, TransferSize, GetDataFromDevice); - - // Set up the SRB/CDB - RtlCopyMemory(cdb, Cdb, sizeof(CDB)); - - srb->CdbLength = OprationLength; - - if (TimeoutValue > 0) - { - srb->TimeOutValue = TimeoutValue; - } - - ScratchBuffer_SendSrb(DeviceExtension, TRUE, NULL); - - if ((DeviceExtension->ScratchContext.ScratchSrb->SrbStatus == SRB_STATUS_ABORTED) && - (DeviceExtension->ScratchContext.ScratchSrb->InternalStatus == STATUS_CANCELLED)) - { - shouldRetry = FALSE; - status = STATUS_CANCELLED; - } - else - { - shouldRetry = RequestSenseInfoInterpretForScratchBuffer(DeviceExtension, - timesAlreadyRetried, - &status, - &retryIn100nsUnits); - if (shouldRetry) - { - LARGE_INTEGER t; - t.QuadPart = -retryIn100nsUnits; - timesAlreadyRetried++; - KeDelayExecutionThread(KernelMode, FALSE, &t); - // keep items clean - ScratchBuffer_ResetItems(DeviceExtension, FALSE); - } - } - } - - return status; -} - - |
