3 Copyright (C) Microsoft Corporation. All rights reserved.
11 Functions for using common scratch buffer
35 #include "scratch.tmh"
38 // Forward declarations
39 EVT_WDF_REQUEST_COMPLETION_ROUTINE ScratchBuffer_ReadWriteCompletionRoutine
;
43 #pragma alloc_text(PAGE, ScratchBuffer_Deallocate)
44 #pragma alloc_text(PAGE, ScratchBuffer_Allocate)
45 #pragma alloc_text(PAGE, ScratchBuffer_SetupSrb)
46 #pragma alloc_text(PAGE, ScratchBuffer_ExecuteCdbEx)
50 _IRQL_requires_max_(APC_LEVEL
)
52 ScratchBuffer_Deallocate(
53 _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension
59 release all resources allocated for scratch.
63 DeviceExtension - device extension
73 NT_ASSERT(DeviceExtension
->ScratchContext
.ScratchInUse
== 0);
75 if (DeviceExtension
->ScratchContext
.ScratchHistory
!= NULL
)
77 ExFreePool(DeviceExtension
->ScratchContext
.ScratchHistory
);
78 DeviceExtension
->ScratchContext
.ScratchHistory
= NULL
;
80 if (DeviceExtension
->ScratchContext
.ScratchSense
!= NULL
)
82 ExFreePool(DeviceExtension
->ScratchContext
.ScratchSense
);
83 DeviceExtension
->ScratchContext
.ScratchSense
= NULL
;
85 if (DeviceExtension
->ScratchContext
.ScratchSrb
!= NULL
)
87 ExFreePool(DeviceExtension
->ScratchContext
.ScratchSrb
);
88 DeviceExtension
->ScratchContext
.ScratchSrb
= NULL
;
90 if (DeviceExtension
->ScratchContext
.ScratchBufferSize
!= 0)
92 DeviceExtension
->ScratchContext
.ScratchBufferSize
= 0;
94 if (DeviceExtension
->ScratchContext
.ScratchBufferMdl
!= NULL
)
96 IoFreeMdl(DeviceExtension
->ScratchContext
.ScratchBufferMdl
);
97 DeviceExtension
->ScratchContext
.ScratchBufferMdl
= NULL
;
99 if (DeviceExtension
->ScratchContext
.ScratchBuffer
!= NULL
)
101 ExFreePool(DeviceExtension
->ScratchContext
.ScratchBuffer
);
102 DeviceExtension
->ScratchContext
.ScratchBuffer
= NULL
;
105 if (DeviceExtension
->ScratchContext
.PartialMdl
!= NULL
)
107 IoFreeMdl(DeviceExtension
->ScratchContext
.PartialMdl
);
108 DeviceExtension
->ScratchContext
.PartialMdl
= NULL
;
111 if (DeviceExtension
->ScratchContext
.ScratchRequest
!= NULL
)
113 PIRP irp
= WdfRequestWdmGetIrp(DeviceExtension
->ScratchContext
.ScratchRequest
);
116 irp
->MdlAddress
= NULL
;
118 WdfObjectDelete(DeviceExtension
->ScratchContext
.ScratchRequest
);
119 DeviceExtension
->ScratchContext
.ScratchRequest
= NULL
;
125 _IRQL_requires_max_(APC_LEVEL
)
127 ScratchBuffer_Allocate(
128 _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension
134 allocate resources allocated for scratch.
138 DeviceExtension - device extension
146 NTSTATUS status
= STATUS_SUCCESS
;
150 NT_ASSERT(DeviceExtension
->ScratchContext
.ScratchInUse
== 0);
152 // quick-exit if already allocated
153 if ((DeviceExtension
->ScratchContext
.ScratchBuffer
!= NULL
) &&
154 (DeviceExtension
->ScratchContext
.ScratchBufferMdl
!= NULL
) &&
155 (DeviceExtension
->ScratchContext
.ScratchBufferSize
!= 0) &&
156 (DeviceExtension
->ScratchContext
.ScratchRequest
!= NULL
) &&
157 (DeviceExtension
->ScratchContext
.ScratchSrb
!= NULL
) &&
158 (DeviceExtension
->ScratchContext
.ScratchHistory
!= NULL
) &&
159 (DeviceExtension
->ScratchContext
.PartialMdl
!= NULL
)
165 // validate max transfer already determined
166 NT_ASSERT(DeviceExtension
->DeviceAdditionalData
.MaxPageAlignedTransferBytes
!= 0);
168 // validate no partially-saved state
169 NT_ASSERT(DeviceExtension
->ScratchContext
.ScratchBuffer
== NULL
);
170 NT_ASSERT(DeviceExtension
->ScratchContext
.ScratchBufferMdl
== NULL
);
171 NT_ASSERT(DeviceExtension
->ScratchContext
.ScratchBufferSize
== 0);
172 NT_ASSERT(DeviceExtension
->ScratchContext
.ScratchRequest
== NULL
);
173 NT_ASSERT(DeviceExtension
->ScratchContext
.PartialMdl
== NULL
);
175 // limit the scratch buffer to between 4k and 64k (so data length fits into USHORT -- req'd for many commands)
176 DeviceExtension
->ScratchContext
.ScratchBufferSize
= min(DeviceExtension
->DeviceAdditionalData
.MaxPageAlignedTransferBytes
, (64*1024));
178 // allocate the buffer
179 if (NT_SUCCESS(status
))
181 DeviceExtension
->ScratchContext
.ScratchBuffer
= ExAllocatePoolWithTag(NonPagedPoolNx
,
182 DeviceExtension
->ScratchContext
.ScratchBufferSize
,
184 if (DeviceExtension
->ScratchContext
.ScratchBuffer
== NULL
)
186 status
= STATUS_INSUFFICIENT_RESOURCES
;
187 TracePrint((TRACE_LEVEL_WARNING
, TRACE_FLAG_INIT
,
188 "Failed to allocate scratch buffer of %x bytes\n",
189 DeviceExtension
->ScratchContext
.ScratchBufferSize
192 else if (BYTE_OFFSET(DeviceExtension
->ScratchContext
.ScratchBuffer
) != 0)
194 status
= STATUS_INTERNAL_ERROR
;
195 TracePrint((TRACE_LEVEL_FATAL
, TRACE_FLAG_INIT
,
196 "Allocation of %x bytes non-paged pool was not "
197 "allocated on page boundary? STATUS_INTERNAL_ERROR\n",
198 DeviceExtension
->ScratchContext
.ScratchBufferSize
204 if (NT_SUCCESS(status
))
206 DeviceExtension
->ScratchContext
.ScratchBufferMdl
= IoAllocateMdl(DeviceExtension
->ScratchContext
.ScratchBuffer
,
207 DeviceExtension
->ScratchContext
.ScratchBufferSize
,
209 if (DeviceExtension
->ScratchContext
.ScratchBufferMdl
== NULL
)
211 status
= STATUS_INSUFFICIENT_RESOURCES
;
212 TracePrint((TRACE_LEVEL_WARNING
, TRACE_FLAG_INIT
,
213 "Failed to allocate MDL for %x byte buffer\n",
214 DeviceExtension
->ScratchContext
.ScratchBufferSize
219 MmBuildMdlForNonPagedPool(DeviceExtension
->ScratchContext
.ScratchBufferMdl
);
223 // create the request
224 if (NT_SUCCESS(status
))
226 WDF_OBJECT_ATTRIBUTES attributes
;
227 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes
,
228 CDROM_REQUEST_CONTEXT
);
230 status
= WdfRequestCreate(&attributes
,
231 DeviceExtension
->IoTarget
,
232 &DeviceExtension
->ScratchContext
.ScratchRequest
);
234 if ((!NT_SUCCESS(status
)) ||
235 (DeviceExtension
->ScratchContext
.ScratchRequest
== NULL
))
237 status
= STATUS_INSUFFICIENT_RESOURCES
;
238 TracePrint((TRACE_LEVEL_WARNING
, TRACE_FLAG_INIT
,
239 "Failed to allocate scratch MDL \n"));
244 if (NT_SUCCESS(status
))
246 DeviceExtension
->ScratchContext
.ScratchSrb
= ExAllocatePoolWithTag(NonPagedPoolNx
,
247 sizeof(SCSI_REQUEST_BLOCK
),
250 if (DeviceExtension
->ScratchContext
.ScratchSrb
== NULL
)
252 status
= STATUS_INSUFFICIENT_RESOURCES
;
253 TracePrint((TRACE_LEVEL_WARNING
, TRACE_FLAG_INIT
,
254 "Failed to allocate scratch SRB\n"));
258 // allocate the sense buffer
259 if (NT_SUCCESS(status
))
261 DeviceExtension
->ScratchContext
.ScratchSense
= ExAllocatePoolWithTag(NonPagedPoolNx
,
265 if (DeviceExtension
->ScratchContext
.ScratchSense
== NULL
)
267 status
= STATUS_INSUFFICIENT_RESOURCES
;
268 TracePrint((TRACE_LEVEL_WARNING
, TRACE_FLAG_INIT
,
269 "Failed to allocate scratch sense data\n"
274 // allocate the SRB history data
275 if (NT_SUCCESS(status
))
277 size_t allocationSize
= sizeof(SRB_HISTORY
) - sizeof(SRB_HISTORY_ITEM
);
278 allocationSize
+= 20 * sizeof(SRB_HISTORY_ITEM
);
280 DeviceExtension
->ScratchContext
.ScratchHistory
= ExAllocatePoolWithTag(NonPagedPoolNx
,
283 if (DeviceExtension
->ScratchContext
.ScratchHistory
== NULL
)
285 status
= STATUS_INSUFFICIENT_RESOURCES
;
286 TracePrint((TRACE_LEVEL_WARNING
, TRACE_FLAG_INIT
,
287 "Failed to allocate scratch history buffer\n"
292 // must be initialized here...
293 RtlZeroMemory(DeviceExtension
->ScratchContext
.ScratchHistory
, allocationSize
);
294 DeviceExtension
->ScratchContext
.ScratchHistory
->TotalHistoryCount
= 20;
299 if (NT_SUCCESS(status
))
301 ULONG transferLength
= 0;
303 status
= RtlULongAdd(DeviceExtension
->DeviceAdditionalData
.MaxPageAlignedTransferBytes
, PAGE_SIZE
, &transferLength
);
304 if (NT_SUCCESS(status
))
306 DeviceExtension
->ScratchContext
.PartialMdlIsBuilt
= FALSE
;
307 DeviceExtension
->ScratchContext
.PartialMdl
= IoAllocateMdl(NULL
,
312 if (DeviceExtension
->ScratchContext
.PartialMdl
== NULL
)
314 status
= STATUS_INSUFFICIENT_RESOURCES
;
315 TracePrint((TRACE_LEVEL_WARNING
, TRACE_FLAG_INIT
,
316 "Failed to allocate MDL for %x byte buffer\n",
317 DeviceExtension
->ScratchContext
.ScratchBufferSize
322 NT_ASSERT(DeviceExtension
->ScratchContext
.PartialMdl
->Size
>=
323 (CSHORT
)(sizeof(MDL
) + BYTES_TO_PAGES(DeviceExtension
->DeviceAdditionalData
.MaxPageAlignedTransferBytes
) * sizeof(PFN_NUMBER
)));
328 status
= STATUS_INTEGER_OVERFLOW
;
332 // cleanup on failure
333 if (!NT_SUCCESS(status
))
335 ScratchBuffer_Deallocate(DeviceExtension
);
338 return NT_SUCCESS(status
);
343 ScratchBuffer_ResetItems(
344 _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension
,
345 _In_ BOOLEAN ResetRequestHistory
351 reset scratch items for reuse.
355 DeviceExtension - device extension
356 ResetRequestHistory - reset history fields or not
364 NTSTATUS status
= STATUS_SUCCESS
;
365 WDF_REQUEST_REUSE_PARAMS reuseParams
;
368 NT_ASSERT(DeviceExtension
->ScratchContext
.ScratchHistory
!= NULL
);
369 NT_ASSERT(DeviceExtension
->ScratchContext
.ScratchSense
!= NULL
);
370 NT_ASSERT(DeviceExtension
->ScratchContext
.ScratchSrb
!= NULL
);
371 NT_ASSERT(DeviceExtension
->ScratchContext
.ScratchRequest
!= NULL
);
372 NT_ASSERT(DeviceExtension
->ScratchContext
.ScratchBufferSize
!= 0);
373 NT_ASSERT(DeviceExtension
->ScratchContext
.ScratchBuffer
!= NULL
);
374 NT_ASSERT(DeviceExtension
->ScratchContext
.ScratchBufferMdl
!= NULL
);
375 NT_ASSERT(DeviceExtension
->ScratchContext
.ScratchInUse
!= 0);
377 irp
= WdfRequestWdmGetIrp(DeviceExtension
->ScratchContext
.ScratchRequest
);
379 if (ResetRequestHistory
)
381 PSRB_HISTORY history
= DeviceExtension
->ScratchContext
.ScratchHistory
;
382 RtlZeroMemory(history
->History
, sizeof(SRB_HISTORY_ITEM
) * history
->TotalHistoryCount
);
383 history
->ClassDriverUse
[0] = 0;
384 history
->ClassDriverUse
[1] = 0;
385 history
->ClassDriverUse
[2] = 0;
386 history
->ClassDriverUse
[3] = 0;
387 history
->UsedHistoryCount
= 0;
390 // re-use the KMDF request object
392 // deassign the MdlAddress, this is the value we assign explicitly.
393 // this is to prevent WdfRequestReuse to release the Mdl unexpectly.
396 irp
->MdlAddress
= NULL
;
399 WDF_REQUEST_REUSE_PARAMS_INIT(&reuseParams
, WDF_REQUEST_REUSE_NO_FLAGS
, STATUS_NOT_SUPPORTED
);
400 status
= WdfRequestReuse(DeviceExtension
->ScratchContext
.ScratchRequest
, &reuseParams
);
401 // WDF request to format the request befor sending it
402 if (NT_SUCCESS(status
))
404 // clean up completion routine.
405 WdfRequestSetCompletionRoutine(DeviceExtension
->ScratchContext
.ScratchRequest
, NULL
, NULL
);
407 status
= WdfIoTargetFormatRequestForInternalIoctlOthers(DeviceExtension
->IoTarget
,
408 DeviceExtension
->ScratchContext
.ScratchRequest
,
409 IOCTL_SCSI_EXECUTE_IN
,
413 if (!NT_SUCCESS(status
))
415 TracePrint((TRACE_LEVEL_ERROR
, TRACE_FLAG_GENERAL
,
416 "ScratchBuffer_ResetItems: WdfIoTargetFormatRequestForInternalIoctlOthers failed, %!STATUS!\n",
421 RtlZeroMemory(DeviceExtension
->ScratchContext
.ScratchSense
, sizeof(SENSE_DATA
));
422 RtlZeroMemory(DeviceExtension
->ScratchContext
.ScratchSrb
, sizeof(SCSI_REQUEST_BLOCK
));
429 ScratchBuffer_PerformNextReadWrite(
430 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
,
431 _In_ BOOLEAN FirstTry
437 This function asynchronously sends the next read/write SRB down the stack.
441 DeviceExtension - Device extension
449 PCDROM_SCRATCH_READ_WRITE_CONTEXT readWriteContext
= &DeviceExtension
->ScratchContext
.ScratchReadWriteContext
;
450 PCDROM_REQUEST_CONTEXT requestContext
= RequestGetContext(DeviceExtension
->ScratchContext
.ScratchRequest
);
451 WDFREQUEST originalRequest
= requestContext
->OriginalRequest
;
452 NTSTATUS status
= STATUS_SUCCESS
;
455 BOOLEAN usePartialMdl
;
457 transferSize
= min((readWriteContext
->EntireXferLen
- readWriteContext
->TransferedBytes
), readWriteContext
->MaxLength
);
461 DeviceExtension
->ScratchContext
.NumRetries
= 0;
464 ScratchBuffer_ResetItems(DeviceExtension
, FALSE
);
466 usePartialMdl
= (readWriteContext
->PacketsCount
> 1 || readWriteContext
->TransferedBytes
> 0);
468 ScratchBuffer_SetupReadWriteSrb(DeviceExtension
,
470 readWriteContext
->StartingOffset
,
472 readWriteContext
->DataBuffer
,
473 readWriteContext
->IsRead
,
477 WdfRequestSetCompletionRoutine(DeviceExtension
->ScratchContext
.ScratchRequest
,
478 ScratchBuffer_ReadWriteCompletionRoutine
, DeviceExtension
);
480 status
= ScratchBuffer_SendSrb(DeviceExtension
, FALSE
, (FirstTry
? &readWriteContext
->SrbHistoryItem
: NULL
));
487 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
488 ScratchBuffer_ReadWriteTimerRoutine(
490 PVOID DeferredContext
,
491 PVOID SystemArgument1
,
492 PVOID SystemArgument2
498 Timer routine for retrying read and write requests.
510 PCDROM_DEVICE_EXTENSION deviceExtension
= NULL
;
511 PCDROM_SCRATCH_READ_WRITE_CONTEXT readWriteContext
= NULL
;
512 WDFREQUEST originalRequest
= NULL
;
513 PCDROM_REQUEST_CONTEXT requestContext
= NULL
;
514 NTSTATUS status
= STATUS_SUCCESS
;
517 UNREFERENCED_PARAMETER(Dpc
);
518 UNREFERENCED_PARAMETER(SystemArgument1
);
519 UNREFERENCED_PARAMETER(SystemArgument2
);
521 if (DeferredContext
== NULL
)
523 // This is impossible, but definition of KDEFERRED_ROUTINE allows optional argument,
524 // and thus OACR will complain.
529 originalRequest
= (WDFREQUEST
) DeferredContext
;
530 requestContext
= RequestGetContext(originalRequest
);
532 KeAcquireSpinLock(&requestContext
->ReadWriteCancelSpinLock
, &oldIrql
);
534 if (!requestContext
->ReadWriteIsCompleted
)
536 // As the first step, unregister the cancellation routine
537 status
= WdfRequestUnmarkCancelable(originalRequest
);
541 status
= STATUS_CANCELLED
;
544 KeReleaseSpinLock(&requestContext
->ReadWriteCancelSpinLock
, oldIrql
);
546 if (status
!= STATUS_CANCELLED
)
548 deviceExtension
= requestContext
->DeviceExtension
;
549 readWriteContext
= &deviceExtension
->ScratchContext
.ScratchReadWriteContext
;
551 // We use timer only for retries, that's why the second parameter is always FALSE
552 status
= ScratchBuffer_PerformNextReadWrite(deviceExtension
, FALSE
);
554 if (!NT_SUCCESS(status
))
556 ScratchBuffer_EndUse(deviceExtension
);
557 RequestCompletion(deviceExtension
, originalRequest
, status
, readWriteContext
->TransferedBytes
);
562 // Drop the extra reference
564 WdfObjectDereference(originalRequest
);
568 EVT_WDF_REQUEST_CANCEL ScratchBuffer_ReadWriteEvtRequestCancel
;
571 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
572 ScratchBuffer_ReadWriteEvtRequestCancel(
573 _In_ WDFREQUEST Request
579 Cancels a request waiting for the read/write timer to expire. This function does not
580 support cancellation of requests that have already been sent down.
584 Request - WDF request
592 PCDROM_REQUEST_CONTEXT requestContext
= RequestGetContext(Request
);
593 PCDROM_DEVICE_EXTENSION deviceExtension
= requestContext
->DeviceExtension
;
594 PCDROM_SCRATCH_READ_WRITE_CONTEXT readWriteContext
= &deviceExtension
->ScratchContext
.ScratchReadWriteContext
;
597 KeAcquireSpinLock(&requestContext
->ReadWriteCancelSpinLock
, &oldIrql
);
599 if (KeCancelTimer(&requestContext
->ReadWriteTimer
))
602 // Timer is canceled, we own the request. Drop the reference we took before
603 // queueing the timer.
605 WdfObjectDereference(Request
);
610 // Timer will run and drop the reference but it won't complete the request
611 // because we set IsCompleted to TRUE
615 requestContext
->ReadWriteIsCompleted
= TRUE
;
617 KeReleaseSpinLock(&requestContext
->ReadWriteCancelSpinLock
, oldIrql
);
619 ScratchBuffer_EndUse(deviceExtension
);
621 // If WdfTimerStop returned TRUE, it means this request was scheduled for a retry
622 // and the retry has not happened yet. We just need to cancel it and release the scratch buffer.
623 RequestCompletion(deviceExtension
, Request
, STATUS_CANCELLED
, readWriteContext
->TransferedBytes
);
627 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
628 ScratchBuffer_ReadWriteCompletionRoutine(
629 _In_ WDFREQUEST Request
,
630 _In_ WDFIOTARGET Target
,
631 _In_ PWDF_REQUEST_COMPLETION_PARAMS Params
,
632 _In_ WDFCONTEXT Context
638 Read/write request completion routine.
641 Request - WDF request
642 Target - The IO target the request was completed by.
643 Params - the request completion parameters
652 PCDROM_DEVICE_EXTENSION deviceExtension
= (PCDROM_DEVICE_EXTENSION
) Context
;
653 PCDROM_SCRATCH_READ_WRITE_CONTEXT readWriteContext
= &deviceExtension
->ScratchContext
.ScratchReadWriteContext
;
654 NTSTATUS status
= STATUS_SUCCESS
;
655 PCDROM_REQUEST_CONTEXT requestContext
= RequestGetContext(deviceExtension
->ScratchContext
.ScratchRequest
);
656 WDFREQUEST originalRequest
= requestContext
->OriginalRequest
;
658 if (!NT_SUCCESS(WdfRequestGetStatus(Request
)))
660 TracePrint((TRACE_LEVEL_WARNING
, TRACE_FLAG_INIT
,
661 "WdfRequestSend: %lx\n",
662 WdfRequestGetStatus(Request
)
666 UNREFERENCED_PARAMETER(Params
);
667 UNREFERENCED_PARAMETER(Target
);
669 // We are not calling ScratchBuffer_BeginUse / ScratchBuffer_EndUse in this function, because we already own
670 // the scratch buffer if this function is being called.
672 if ((deviceExtension
->ScratchContext
.ScratchSrb
->SrbStatus
== SRB_STATUS_ABORTED
) &&
673 (deviceExtension
->ScratchContext
.ScratchSrb
->InternalStatus
== STATUS_CANCELLED
))
675 // The request has been cancelled, just need to complete it
677 else if (SRB_STATUS(deviceExtension
->ScratchContext
.ScratchSrb
->SrbStatus
) != SRB_STATUS_SUCCESS
)
679 // The SCSI command that we sent down has failed, retry it if necessary
680 BOOLEAN shouldRetry
= TRUE
;
681 LONGLONG retryIn100nsUnits
= 0;
683 shouldRetry
= RequestSenseInfoInterpretForScratchBuffer(deviceExtension
,
684 deviceExtension
->ScratchContext
.NumRetries
,
690 deviceExtension
->ScratchContext
.NumRetries
++;
692 if (retryIn100nsUnits
== 0)
694 // We take a shortcut here by calling ScratchBuffer_PerformNextReadWrite directly:
695 // this helps to avoid unnecessary context switch.
696 status
= ScratchBuffer_PerformNextReadWrite(deviceExtension
, FALSE
);
698 if (NT_SUCCESS(status
))
700 // We're not done with the request yet, no need to complete it now
706 PCDROM_REQUEST_CONTEXT originalRequestContext
= RequestGetContext(originalRequest
);
710 // Initialize the spin lock and timer local to the original request.
712 if (!originalRequestContext
->ReadWriteRetryInitialized
)
714 KeInitializeSpinLock(&originalRequestContext
->ReadWriteCancelSpinLock
);
715 KeInitializeTimer(&originalRequestContext
->ReadWriteTimer
);
716 KeInitializeDpc(&originalRequestContext
->ReadWriteDpc
, ScratchBuffer_ReadWriteTimerRoutine
, originalRequest
);
717 originalRequestContext
->ReadWriteRetryInitialized
= TRUE
;
720 KeAcquireSpinLock(&requestContext
->ReadWriteCancelSpinLock
, &oldIrql
);
722 status
= WdfRequestMarkCancelableEx(originalRequest
, ScratchBuffer_ReadWriteEvtRequestCancel
);
724 if (status
== STATUS_CANCELLED
)
726 requestContext
->ReadWriteIsCompleted
= TRUE
;
728 KeReleaseSpinLock(&requestContext
->ReadWriteCancelSpinLock
, oldIrql
);
734 t
.QuadPart
= -retryIn100nsUnits
;
736 WdfObjectReference(originalRequest
);
738 // Use negative time to indicate that we want a relative delay
739 KeSetTimer(&originalRequestContext
->ReadWriteTimer
,
741 &originalRequestContext
->ReadWriteDpc
744 KeReleaseSpinLock(&requestContext
->ReadWriteCancelSpinLock
, oldIrql
);
753 // The SCSI command has succeeded
754 readWriteContext
->DataBuffer
+= deviceExtension
->ScratchContext
.ScratchSrb
->DataTransferLength
;
755 readWriteContext
->StartingOffset
.QuadPart
+= deviceExtension
->ScratchContext
.ScratchSrb
->DataTransferLength
;
756 readWriteContext
->TransferedBytes
+= deviceExtension
->ScratchContext
.ScratchSrb
->DataTransferLength
;
757 readWriteContext
->PacketsCount
--;
759 // Update the SRB history item
760 if (readWriteContext
->SrbHistoryItem
)
764 // Query the tick count and store in the history
765 KeQueryTickCount(&readWriteContext
->SrbHistoryItem
->TickCountCompleted
);
767 // Copy the SRB Status...
768 readWriteContext
->SrbHistoryItem
->SrbStatus
= deviceExtension
->ScratchContext
.ScratchSrb
->SrbStatus
;
770 // Determine the amount of valid sense data
771 if (deviceExtension
->ScratchContext
.ScratchSrb
->SenseInfoBufferLength
>=
772 RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA
, AdditionalSenseLength
))
774 PSENSE_DATA sense
= (PSENSE_DATA
)deviceExtension
->ScratchContext
.ScratchSrb
->SenseInfoBuffer
;
775 senseSize
= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA
, AdditionalSenseLength
) +
776 sense
->AdditionalSenseLength
;
777 senseSize
= min(senseSize
, sizeof(SENSE_DATA
));
781 senseSize
= deviceExtension
->ScratchContext
.ScratchSrb
->SenseInfoBufferLength
;
784 // Normalize the sense data copy in the history
785 RtlZeroMemory(&(readWriteContext
->SrbHistoryItem
->NormalizedSenseData
), sizeof(SENSE_DATA
));
786 RtlCopyMemory(&(readWriteContext
->SrbHistoryItem
->NormalizedSenseData
),
787 deviceExtension
->ScratchContext
.ScratchSrb
->SenseInfoBuffer
, senseSize
);
790 // Check whether we need to send more SCSI commands to complete the request
791 if (readWriteContext
->PacketsCount
> 0)
793 status
= ScratchBuffer_PerformNextReadWrite(deviceExtension
, TRUE
);
795 if (NT_SUCCESS(status
))
797 // We're not done with the request yet, no need to complete it now
803 ScratchBuffer_EndUse(deviceExtension
);
806 RequestCompletion(deviceExtension
, originalRequest
, status
, readWriteContext
->TransferedBytes
);
809 _IRQL_requires_max_(APC_LEVEL
)
811 ScratchBuffer_SetupSrb(
812 _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension
,
813 _In_opt_ WDFREQUEST OriginalRequest
,
814 _In_ ULONG MaximumTransferLength
,
815 _In_ BOOLEAN GetDataFromDevice
821 setup scratch SRB for sending out.
825 DeviceExtension - device extension
826 OriginalRequest - original request delivered by WDF
827 MaximumTransferLength - transfer length
828 GetDataFromDevice - TRUE (get data from device); FALSE (send data to device)
836 WDFREQUEST request
= DeviceExtension
->ScratchContext
.ScratchRequest
;
837 PIRP irp
= WdfRequestWdmGetIrp(request
);
838 PSCSI_REQUEST_BLOCK srb
= DeviceExtension
->ScratchContext
.ScratchSrb
;
839 PIO_STACK_LOCATION irpStack
= NULL
;
840 PCDROM_REQUEST_CONTEXT requestContext
= RequestGetContext(request
);
844 requestContext
->OriginalRequest
= OriginalRequest
;
846 // set to use the full scratch buffer via the scratch SRB
847 irpStack
= IoGetNextIrpStackLocation(irp
);
848 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
849 if (MaximumTransferLength
== 0)
851 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_NONE
;
853 else if (GetDataFromDevice
)
855 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
859 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_OUT
;
861 irpStack
->Parameters
.Scsi
.Srb
= srb
;
863 if (MaximumTransferLength
> 0)
865 // the Irp must show the MDL's address for the transfer
866 irp
->MdlAddress
= DeviceExtension
->ScratchContext
.ScratchBufferMdl
;
868 srb
->DataBuffer
= DeviceExtension
->ScratchContext
.ScratchBuffer
;
871 // prepare the SRB with default values
872 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
873 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
874 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
878 srb
->OriginalRequest
= irp
;
879 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
880 srb
->SenseInfoBuffer
= DeviceExtension
->ScratchContext
.ScratchSense
;
882 srb
->CdbLength
= 16; // to cause failures if not set correctly -- CD devices limited to 12 bytes for now...
884 srb
->DataTransferLength
= min(DeviceExtension
->ScratchContext
.ScratchBufferSize
, MaximumTransferLength
);
885 srb
->TimeOutValue
= DeviceExtension
->TimeOutValue
;
886 srb
->SrbFlags
= DeviceExtension
->SrbFlags
;
887 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
888 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_QUEUE_FREEZE
);
890 if (MaximumTransferLength
== 0)
892 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
894 else if (GetDataFromDevice
)
896 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
900 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_OUT
);
906 ScratchBuffer_SendSrb(
907 _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension
,
908 _In_ BOOLEAN SynchronousSrb
,
909 _When_(SynchronousSrb
, _Pre_null_
)
910 _When_(!SynchronousSrb
, _In_opt_
)
911 PSRB_HISTORY_ITEM
*SrbHistoryItem
917 Send the command from the scratch SRB to lower driver and retry if necessary.
921 DeviceExtension - device extension
922 SynchronousSrb - indicates whether the SRB needs to be sent synchronously or nor
923 SrbHistoryItem - storage for SRB history item, if this is an asynchronous request
931 NTSTATUS status
= STATUS_SUCCESS
;
932 PSCSI_REQUEST_BLOCK srb
= DeviceExtension
->ScratchContext
.ScratchSrb
;
933 PSRB_HISTORY history
= DeviceExtension
->ScratchContext
.ScratchHistory
;
934 PSRB_HISTORY_ITEM item
= NULL
;
935 BOOLEAN requestCancelled
= FALSE
;
937 srb
->InternalStatus
= 0;
940 // allocate/update history pre-command, if it is a synchronous request or we were supplied
941 // with a storage for the history item
942 if (SynchronousSrb
|| SrbHistoryItem
!= NULL
)
944 // sending a packet implies a new history unit is to be used.
945 NT_ASSERT( history
->UsedHistoryCount
<= history
->TotalHistoryCount
);
947 // if already all used up, remove at least one history unit
948 if (history
->UsedHistoryCount
== history
->TotalHistoryCount
)
950 CompressSrbHistoryData(history
);
951 NT_ASSERT( history
->UsedHistoryCount
< history
->TotalHistoryCount
);
954 // thus, since we are about to increment the count, it must now be less...
955 NT_ASSERT( history
->UsedHistoryCount
< history
->TotalHistoryCount
);
957 // increment the number of history units in use
958 history
->UsedHistoryCount
++;
960 // determine index to use
961 item
= &( history
->History
[ history
->UsedHistoryCount
-1 ] );
963 if (SrbHistoryItem
!= NULL
)
965 *SrbHistoryItem
= item
;
968 // zero out the history item
969 RtlZeroMemory(item
, sizeof(SRB_HISTORY_ITEM
));
971 // Query the tick count and store in the history
972 KeQueryTickCount(&item
->TickCountSent
);
975 // get cancellation status;
977 PCDROM_REQUEST_CONTEXT requestContext
= RequestGetContext(DeviceExtension
->ScratchContext
.ScratchRequest
);
979 if (requestContext
->OriginalRequest
!= NULL
)
981 requestCancelled
= WdfRequestIsCanceled(requestContext
->OriginalRequest
);
985 if (!requestCancelled
)
987 status
= RequestSend(DeviceExtension
,
988 DeviceExtension
->ScratchContext
.ScratchRequest
,
989 DeviceExtension
->IoTarget
,
990 SynchronousSrb
? WDF_REQUEST_SEND_OPTION_SYNCHRONOUS
: 0,
993 // If this is a synchronous request, update the history item immediately, including "normalized" sense data
998 // Query the tick count and store in the history
999 KeQueryTickCount(&item
->TickCountCompleted
);
1001 // Copy the SRB Status
1002 item
->SrbStatus
= srb
->SrbStatus
;
1004 // Determine the amount of valid sense data
1005 if (srb
->SenseInfoBufferLength
>= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA
, AdditionalSenseLength
))
1007 PSENSE_DATA sense
= (PSENSE_DATA
)srb
->SenseInfoBuffer
;
1008 senseSize
= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA
, AdditionalSenseLength
) +
1009 sense
->AdditionalSenseLength
;
1010 senseSize
= min(senseSize
, sizeof(SENSE_DATA
));
1014 senseSize
= srb
->SenseInfoBufferLength
;
1017 // Normalize the sense data copy in the history
1018 RtlZeroMemory(&(item
->NormalizedSenseData
), sizeof(SENSE_DATA
));
1019 RtlCopyMemory(&(item
->NormalizedSenseData
), srb
->SenseInfoBuffer
, senseSize
);
1024 DeviceExtension
->ScratchContext
.ScratchSrb
->SrbStatus
= SRB_STATUS_ABORTED
;
1025 DeviceExtension
->ScratchContext
.ScratchSrb
->InternalStatus
= (ULONG
)STATUS_CANCELLED
;
1026 status
= STATUS_CANCELLED
;
1033 CompressSrbHistoryData(
1034 _Inout_ PSRB_HISTORY RequestHistory
1038 Routine Description:
1040 compress the SRB history data.
1044 RequestHistory - SRB history data
1048 RequestHistory - compressed history data
1053 NT_ASSERT( RequestHistory
->UsedHistoryCount
== RequestHistory
->TotalHistoryCount
);
1054 ValidateSrbHistoryDataPresumptions(RequestHistory
);
1056 for (i
=0; i
< RequestHistory
->UsedHistoryCount
; i
++)
1059 PSRB_HISTORY_ITEM toMatch
= &( RequestHistory
->History
[i
] );
1060 // hint: read const qualifiers backwards. i.e. srbstatus is a const UCHAR
1061 // so, "UCHAR const * const x" is read "x is a const pointer to a const UCHAR"
1062 // unfortunately, "const UCHAR" is equivalent to "UCHAR const", which causes
1063 // people no end of confusion due to its widespread use.
1064 UCHAR
const srbStatus
= toMatch
->SrbStatus
;
1065 UCHAR
const sense
= toMatch
->NormalizedSenseData
.SenseKey
;
1066 UCHAR
const asc
= toMatch
->NormalizedSenseData
.AdditionalSenseCode
;
1067 UCHAR
const ascq
= toMatch
->NormalizedSenseData
.AdditionalSenseCodeQualifier
;
1070 // see if there are any at higher indices with identical Sense/ASC/ASCQ
1071 for (j
= i
+1; (toMatch
->ClassDriverUse
!= 0xFF) && (j
< RequestHistory
->UsedHistoryCount
); j
++)
1073 PSRB_HISTORY_ITEM found
= &( RequestHistory
->History
[j
] );
1074 // close enough match?
1075 if ((srbStatus
== found
->SrbStatus
) &&
1076 (sense
== found
->NormalizedSenseData
.SenseKey
) &&
1077 (asc
== found
->NormalizedSenseData
.AdditionalSenseCode
) &&
1078 (ascq
== found
->NormalizedSenseData
.AdditionalSenseCodeQualifier
)) {
1080 // add the fields to keep reasonable track of delay times.
1081 if (toMatch
->MillisecondsDelayOnRetry
+ found
->MillisecondsDelayOnRetry
< toMatch
->MillisecondsDelayOnRetry
) {
1082 toMatch
->MillisecondsDelayOnRetry
= MAXULONG
;
1084 toMatch
->MillisecondsDelayOnRetry
+= found
->MillisecondsDelayOnRetry
;
1087 // this found item cannot contain any compressed entries because
1088 // the first entry with a given set of sense/asc/ascq will always
1089 // either be full (0xFF) or be the only partially-full entry with
1090 // that sense/asc/ascq.
1091 NT_ASSERT(found
->ClassDriverUse
== 0);
1092 // add the counts so we still know how many retries total
1093 toMatch
->ClassDriverUse
++;
1096 // if not the last entry, need to move later entries earlier in the array
1097 if (j
!= RequestHistory
->UsedHistoryCount
-1) {
1098 // how many entries remain?
1099 SIZE_T remainingBytes
= RequestHistory
->UsedHistoryCount
- 1 - j
;
1100 remainingBytes
*= sizeof(SRB_HISTORY_ITEM
);
1102 // note that MOVE is required due to overlapping entries
1103 RtlMoveMemory(found
, found
+1, remainingBytes
);
1105 // Finally, decrement the number of used history count and
1106 // decrement j to rescan the current location again
1107 --RequestHistory
->UsedHistoryCount
;
1109 } // end moving of array elements around
1110 } // end of close enough match
1114 // unable to compress duplicate sense/asc/ascq, so just lose the most recent data
1115 if (RequestHistory
->UsedHistoryCount
== RequestHistory
->TotalHistoryCount
)
1117 PSRB_HISTORY_ITEM item
= &( RequestHistory
->History
[ RequestHistory
->TotalHistoryCount
-1 ] );
1118 RequestHistory
->ClassDriverUse
[0] += item
->ClassDriverUse
; // how many did we "lose"?
1119 RequestHistory
->UsedHistoryCount
--;
1122 // finally, zero any that are no longer in use
1123 NT_ASSERT( RequestHistory
->UsedHistoryCount
!= RequestHistory
->TotalHistoryCount
);
1125 SIZE_T bytesToZero
= RequestHistory
->TotalHistoryCount
- RequestHistory
->UsedHistoryCount
;
1126 bytesToZero
*= sizeof(SRB_HISTORY_ITEM
);
1127 RtlZeroMemory(&(RequestHistory
->History
[RequestHistory
->UsedHistoryCount
]), bytesToZero
);
1130 ValidateSrbHistoryDataPresumptions(RequestHistory
);
1135 ValidateSrbHistoryDataPresumptions(
1136 _In_ SRB_HISTORY
const * RequestHistory
1140 // validate that all fully-compressed items are before any non-fully-compressed items of any particular sense/asc/ascq
1141 // validate that there is at most one partially-compressed item of any particular sense/asc/ascq
1142 // validate that all items of any particular sense/asc/ascq that are uncompressed are at the end
1143 // THUS: A(255) A(255) A( 40) A( 0) A( 0) is legal for all types with A as sense/asc/ascq
1144 // A(0) B(255) A( 0) B( 17) B( 0) is also legal because A/B are different types of error
1147 for (i
= 0; i
< RequestHistory
->UsedHistoryCount
; i
++)
1149 SRB_HISTORY_ITEM
const * toMatch
= &( RequestHistory
->History
[i
] );
1150 UCHAR
const srbStatus
= toMatch
->SrbStatus
;
1151 UCHAR
const sense
= toMatch
->NormalizedSenseData
.SenseKey
;
1152 UCHAR
const asc
= toMatch
->NormalizedSenseData
.AdditionalSenseCode
;
1153 UCHAR
const ascq
= toMatch
->NormalizedSenseData
.AdditionalSenseCodeQualifier
;
1156 BOOLEAN foundPartiallyCompressedItem
=
1157 (toMatch
->ClassDriverUse
!= 0) &&
1158 (toMatch
->ClassDriverUse
!= 0xFF) ;
1159 BOOLEAN foundUncompressedItem
=
1160 (toMatch
->ClassDriverUse
== 0) ;
1162 for (j
= i
+1; j
< RequestHistory
->UsedHistoryCount
; j
++)
1164 SRB_HISTORY_ITEM
const * found
= &( RequestHistory
->History
[j
] );
1165 if ((srbStatus
== found
->SrbStatus
) &&
1166 (sense
== found
->NormalizedSenseData
.SenseKey
) &&
1167 (asc
== found
->NormalizedSenseData
.AdditionalSenseCode
) &&
1168 (ascq
== found
->NormalizedSenseData
.AdditionalSenseCodeQualifier
)
1171 // found a matching type, so validate ordering rules
1172 if (foundUncompressedItem
&& (found
->ClassDriverUse
!= 0))
1174 DbgPrintEx(DPFLTR_CDROM_ID
, DPFLTR_ERROR_LEVEL
,
1175 "History data has compressed history following uncompressed history "
1176 "for srbstatus/sense/asc/ascq of %02x/%02x/%02x/%02x at indices %d (%08x) and %d (%08x)\n",
1177 srbStatus
, sense
, asc
, ascq
,
1182 else if (foundPartiallyCompressedItem
&& (found
->ClassDriverUse
== 0xFF))
1184 DbgPrintEx(DPFLTR_CDROM_ID
, DPFLTR_ERROR_LEVEL
,
1185 "History data has fully compressed history following partially compressed history "
1186 "for srbstatus/sense/asc/ascq of %02x/%02x/%02x/%02x at indices %d (%08x) and %d (%08x)\n",
1187 srbStatus
, sense
, asc
, ascq
,
1193 // update if we have now found partially compressed and/or uncompressed items
1194 if (found
->ClassDriverUse
== 0)
1196 foundUncompressedItem
= TRUE
;
1198 else if (found
->ClassDriverUse
!= 0xFF)
1200 foundPartiallyCompressedItem
= TRUE
;
1202 } // end match of (toMatch,found)
1206 UNREFERENCED_PARAMETER(RequestHistory
);
1212 ScratchBuffer_SetupReadWriteSrb(
1213 _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension
,
1214 _In_ WDFREQUEST OriginalRequest
,
1215 _In_ LARGE_INTEGER StartingOffset
,
1216 _In_ ULONG RequiredLength
,
1217 _Inout_updates_bytes_(RequiredLength
) UCHAR
* DataBuffer
,
1218 _In_ BOOLEAN IsReadRequest
,
1219 _In_ BOOLEAN UsePartialMdl
1223 Routine Description:
1225 setup SRB for read/write request.
1229 DeviceExtension - device extension
1230 OriginalRequest - read/write request
1231 StartingOffset - read/write starting offset
1232 DataBuffer - buffer for read/write
1233 IsReadRequest - TRUE (read); FALSE (write)
1241 //NOTE: R/W request not use the ScratchBuffer, instead, it uses the buffer associated with IRP.
1243 PSCSI_REQUEST_BLOCK srb
= DeviceExtension
->ScratchContext
.ScratchSrb
;
1244 PCDB cdb
= (PCDB
)srb
->Cdb
;
1245 LARGE_INTEGER logicalBlockAddr
;
1246 ULONG numTransferBlocks
;
1248 PIRP originalIrp
= WdfRequestWdmGetIrp(OriginalRequest
);
1250 PIRP irp
= WdfRequestWdmGetIrp(DeviceExtension
->ScratchContext
.ScratchRequest
);
1251 PIO_STACK_LOCATION irpStack
= NULL
;
1253 PCDROM_REQUEST_CONTEXT requestContext
= RequestGetContext(DeviceExtension
->ScratchContext
.ScratchRequest
);
1255 requestContext
->OriginalRequest
= OriginalRequest
;
1258 logicalBlockAddr
.QuadPart
= Int64ShrlMod32(StartingOffset
.QuadPart
, DeviceExtension
->SectorShift
);
1259 numTransferBlocks
= RequiredLength
>> DeviceExtension
->SectorShift
;
1261 // set to use the full scratch buffer via the scratch SRB
1262 irpStack
= IoGetNextIrpStackLocation(irp
);
1263 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
1266 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
1270 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_OUT
;
1272 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1274 // prepare the SRB with default values
1275 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1276 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1277 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
1279 srb
->ScsiStatus
= 0;
1280 srb
->NextSrb
= NULL
;
1281 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1282 srb
->SenseInfoBuffer
= DeviceExtension
->ScratchContext
.ScratchSense
;
1284 srb
->DataBuffer
= DataBuffer
;
1285 srb
->DataTransferLength
= RequiredLength
;
1287 srb
->QueueSortKey
= logicalBlockAddr
.LowPart
;
1288 if (logicalBlockAddr
.QuadPart
> 0xFFFFFFFF)
1291 // If the requested LBA is more than max ULONG set the
1292 // QueueSortKey to the maximum value, so that these
1293 // requests can be added towards the end of the queue.
1295 srb
->QueueSortKey
= 0xFFFFFFFF;
1298 srb
->OriginalRequest
= irp
;
1299 srb
->TimeOutValue
= DeviceExtension
->TimeOutValue
;
1301 if (RequestIsRealtimeStreaming(OriginalRequest
, IsReadRequest
) &&
1302 !TEST_FLAG(DeviceExtension
->PrivateFdoData
->HackFlags
, FDO_HACK_NO_STREAMING
))
1306 RtlZeroMemory(&cdb
->READ12
, sizeof(cdb
->READ12
));
1307 REVERSE_BYTES(&cdb
->READ12
.LogicalBlock
, &logicalBlockAddr
.LowPart
);
1308 REVERSE_BYTES(&cdb
->READ12
.TransferLength
, &numTransferBlocks
);
1309 cdb
->READ12
.Streaming
= 1;
1310 cdb
->READ12
.OperationCode
= SCSIOP_READ12
;
1311 srb
->CdbLength
= sizeof(cdb
->READ12
);
1315 RtlZeroMemory(&cdb
->WRITE12
, sizeof(cdb
->WRITE12
));
1316 REVERSE_BYTES(&cdb
->WRITE12
.LogicalBlock
, &logicalBlockAddr
.LowPart
);
1317 REVERSE_BYTES(&cdb
->WRITE12
.TransferLength
, &numTransferBlocks
);
1318 cdb
->WRITE12
.Streaming
= 1;
1319 cdb
->WRITE12
.OperationCode
= SCSIOP_WRITE12
;
1320 srb
->CdbLength
= sizeof(cdb
->WRITE12
);
1325 RtlZeroMemory(&cdb
->CDB10
, sizeof(cdb
->CDB10
));
1326 cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)&logicalBlockAddr
.LowPart
)->Byte3
;
1327 cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)&logicalBlockAddr
.LowPart
)->Byte2
;
1328 cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)&logicalBlockAddr
.LowPart
)->Byte1
;
1329 cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)&logicalBlockAddr
.LowPart
)->Byte0
;
1330 cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)&numTransferBlocks
)->Byte1
;
1331 cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)&numTransferBlocks
)->Byte0
;
1332 cdb
->CDB10
.OperationCode
= (IsReadRequest
) ? SCSIOP_READ
: SCSIOP_WRITE
;
1333 srb
->CdbLength
= sizeof(cdb
->CDB10
);
1336 // Set SRB and IRP flags
1337 srb
->SrbFlags
= DeviceExtension
->SrbFlags
;
1338 if (TEST_FLAG(originalIrp
->Flags
, IRP_PAGING_IO
) ||
1339 TEST_FLAG(originalIrp
->Flags
, IRP_SYNCHRONOUS_PAGING_IO
))
1341 SET_FLAG(srb
->SrbFlags
, SRB_CLASS_FLAGS_PAGING
);
1344 SET_FLAG(srb
->SrbFlags
, (IsReadRequest
) ? SRB_FLAGS_DATA_IN
: SRB_FLAGS_DATA_OUT
);
1345 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_ADAPTER_CACHE_ENABLE
);
1348 // If the request is not split, we can use the original IRP MDL. If the
1349 // request needs to be split, we need to use a partial MDL. The partial MDL
1350 // is needed because more than one driver might be mapping the same MDL
1351 // and this causes problems.
1353 if (UsePartialMdl
== FALSE
)
1355 irp
->MdlAddress
= originalIrp
->MdlAddress
;
1359 if (DeviceExtension
->ScratchContext
.PartialMdlIsBuilt
!= FALSE
)
1361 MmPrepareMdlForReuse(DeviceExtension
->ScratchContext
.PartialMdl
);
1364 IoBuildPartialMdl(originalIrp
->MdlAddress
, DeviceExtension
->ScratchContext
.PartialMdl
, srb
->DataBuffer
, srb
->DataTransferLength
);
1365 DeviceExtension
->ScratchContext
.PartialMdlIsBuilt
= TRUE
;
1366 irp
->MdlAddress
= DeviceExtension
->ScratchContext
.PartialMdl
;
1369 //DBGLOGSENDPACKET(Pkt);
1370 //HISTORYLOGSENDPACKET(Pkt);
1373 // Set the original irp here for SFIO.
1375 srb
->SrbExtension
= (PVOID
)(originalIrp
);
1380 _IRQL_requires_max_(APC_LEVEL
)
1382 ScratchBuffer_ExecuteCdbEx(
1383 _Inout_ PCDROM_DEVICE_EXTENSION DeviceExtension
,
1384 _In_opt_ WDFREQUEST OriginalRequest
,
1385 _In_ ULONG TransferSize
,
1386 _In_ BOOLEAN GetDataFromDevice
,
1388 _In_ UCHAR OprationLength
,
1389 _In_ ULONG TimeoutValue
1393 Routine Description:
1395 Use Scratch buffer to send the Cdb, check error and retry if necessary.
1399 DeviceExtension - device context
1400 OriginalRequest - original request that requires this CDB operation
1401 TransferSize - Data transfer size required
1402 GetFromDevice - TRUE if getting data from device.
1404 OprationLength - SCSI command length: 6, 10 or 12
1405 TimeoutValue - if > 0, use it as timeout value for command
1406 if 0, use the default device timeout value
1414 NTSTATUS status
= STATUS_SUCCESS
;
1415 PSCSI_REQUEST_BLOCK srb
= DeviceExtension
->ScratchContext
.ScratchSrb
;
1416 PCDB cdb
= (PCDB
)(srb
->Cdb
);
1418 BOOLEAN shouldRetry
= TRUE
;
1419 ULONG timesAlreadyRetried
= 0;
1420 LONGLONG retryIn100nsUnits
= 0;
1426 ScratchBuffer_SetupSrb(DeviceExtension
, OriginalRequest
, TransferSize
, GetDataFromDevice
);
1428 // Set up the SRB/CDB
1429 RtlCopyMemory(cdb
, Cdb
, sizeof(CDB
));
1431 srb
->CdbLength
= OprationLength
;
1433 if (TimeoutValue
> 0)
1435 srb
->TimeOutValue
= TimeoutValue
;
1438 ScratchBuffer_SendSrb(DeviceExtension
, TRUE
, NULL
);
1440 if ((DeviceExtension
->ScratchContext
.ScratchSrb
->SrbStatus
== SRB_STATUS_ABORTED
) &&
1441 (DeviceExtension
->ScratchContext
.ScratchSrb
->InternalStatus
== STATUS_CANCELLED
))
1443 shouldRetry
= FALSE
;
1444 status
= STATUS_CANCELLED
;
1448 shouldRetry
= RequestSenseInfoInterpretForScratchBuffer(DeviceExtension
,
1449 timesAlreadyRetried
,
1451 &retryIn100nsUnits
);
1455 t
.QuadPart
= -retryIn100nsUnits
;
1456 timesAlreadyRetried
++;
1457 KeDelayExecutionThread(KernelMode
, FALSE
, &t
);
1459 ScratchBuffer_ResetItems(DeviceExtension
, FALSE
);