summaryrefslogtreecommitdiff
path: root/storage/class/cdrom/src/scratch.c
diff options
context:
space:
mode:
Diffstat (limited to 'storage/class/cdrom/src/scratch.c')
-rw-r--r--storage/class/cdrom/src/scratch.c1463
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;
-}
-
-