Something went wrong. Try again.
Reactos
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468/*--
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 declarationsEVT_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)VOIDScratchBuffer_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)BOOLEANScratchBuffer_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 = ExAllocatePoolWithTag(NonPagedPoolNx, 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 = ExAllocatePoolWithTag(NonPagedPoolNx, 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 = ExAllocatePoolWithTag(NonPagedPoolNx, 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 = ExAllocatePoolWithTag(NonPagedPoolNx, 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... RtlZeroMemory(DeviceExtension->ScratchContext.ScratchHistory, allocationSize); 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);}
VOIDScratchBuffer_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;}
NTSTATUSScratchBuffer_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;}
VOIDNTAPI /* ReactOS Change: GCC Does not support STDCALL by default */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;
VOIDNTAPI /* ReactOS Change: GCC Does not support STDCALL by default */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);}
VOIDNTAPI /* ReactOS Change: GCC Does not support STDCALL by default */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)VOIDScratchBuffer_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); }}
NTSTATUSScratchBuffer_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;}
VOIDCompressSrbHistoryData( _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;}
VOIDValidateSrbHistoryDataPresumptions( _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;}
VOIDScratchBuffer_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)NTSTATUSScratchBuffer_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;}