ReactOS 0.4.17-dev-1133-gc25e4fd
srb.c File Reference
#include "precomp.h"
#include "inline.h"
#include <debug/driverdbg.h>
#include <debug.h>
Include dependency graph for srb.c:

Go to the source code of this file.

Macros

#define NDEBUG
 

Functions

static VOID StorpSrbInitRequestReference (_In_ PQUEUED_REQUEST_REFERENCE RequestReference, _In_ PSCSI_REQUEST_BLOCK Srb, _In_ PIRP Irp, _In_ PPDO_DEVICE_EXTENSION PdoExtension)
 Initializes a request reference and sets the SRB => ReqRef link.
 
static PQUEUED_REQUEST_REFERENCE StorpSrbAllocateRequestReference (_In_ PSCSI_REQUEST_BLOCK Srb, _In_ PIRP Irp, _In_ PPDO_DEVICE_EXTENSION PdoExtension)
 Allocates QUEUED_REQUEST_REFERENCE for an SRB that is going to be processed.
 
static PQUEUED_REQUEST_REFERENCE StorpSrbAcquireReservedRequestReference (_In_ PSCSI_REQUEST_BLOCK Srb, _In_ PIRP Irp, _In_ PPDO_DEVICE_EXTENSION PdoExtension)
 Takes the adapter reserve, if it is there and nobody else holds it.
 
VOID StorpSrbFreeRequestReference (_In_ PSCSI_REQUEST_BLOCK Srb)
 Frees an SRB's Request Reference and restore Srb->OriginalRequest field to IRP. This function does not check if Srb->OriginalRequest is actually an request reference, and you must determine it by other means.
 
FORCEINLINE BOOLEAN StorpAssignTagToSrb (_In_ PPDO_DEVICE_EXTENSION PdoExtension, _In_ PSCSI_REQUEST_BLOCK Srb)
 Assigns a queue tag to a request if it stated it supports one.
 
VOID NTAPI PortPdoAfterBuildingScatterGatherList (_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ PSCATTER_GATHER_LIST ScatterGatherList, _In_ PVOID Context)
 
static NTSTATUS PortPdoStarveRequest (_In_ PFDO_DEVICE_EXTENSION FdoExtension, _In_ PSCSI_REQUEST_BLOCK Srb, _In_ PIRP Irp)
 Parks a request that is out of memory, or fails it if there is no reserve to wait for. Either way the IRP is no longer ours, hence STATUS_PENDING.
 
NTSTATUS PortPdoSrbAllocatePrivateContexts (_In_ PSCSI_REQUEST_BLOCK Srb, _In_ PPDO_DEVICE_EXTENSION PdoExtension, _In_ PFDO_DEVICE_EXTENSION FdoExtension)
 
NTSTATUS PortPdoIssueRequest (_In_ PPDO_DEVICE_EXTENSION PdoExtension, _In_ PQUEUED_REQUEST_REFERENCE RequestReference)
 
VOID PortPdoScheduleRequestNoFlowControl (_In_ PFDO_DEVICE_EXTENSION FdoExtension, _In_ PQUEUED_REQUEST_REFERENCE RequestReference)
 
BOOLEAN PortPdoScheduleRequestFlowControlled (_In_ PPDO_DEVICE_EXTENSION PdoExtension, _In_ PFDO_DEVICE_EXTENSION FdoExtension, _In_ PQUEUED_REQUEST_REFERENCE RequestReference)
 Schedules an outstanding request and return a boolean value to indicate if the request can be immediately issued.
 
NTSTATUS NTAPI PortPdoScsi (_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp)
 
static VOID PortScheduleComingRequestsOnCompletion (_In_ PPDO_DEVICE_EXTENSION PdoExtension, _In_ PFDO_DEVICE_EXTENSION FdoExtension)
 
static VOID PortCompleteRequest (_In_ PQUEUED_REQUEST_REFERENCE RequestReference)
 
VOID NTAPI PortCompletionDpc (_In_ PKDPC Dpc, _In_ PVOID Context, _In_ PVOID SystemArgument1, _In_ PVOID SystemArgument2)
 

Macro Definition Documentation

◆ NDEBUG

#define NDEBUG

Definition at line 13 of file srb.c.

Function Documentation

◆ PortCompleteRequest()

static VOID PortCompleteRequest ( _In_ PQUEUED_REQUEST_REFERENCE  RequestReference)
static

Definition at line 740 of file srb.c.

742{
744 PIRP Irp;
749 BOOLEAN FromReserve;
750
751 /* Take out our information */
752 Srb = RequestReference->Srb;
753 Irp = RequestReference->Irp;
754 PdoExtension = RequestReference->PdoExtension;
755 FdoExtension = PdoExtension->FdoExtension;
756
757 /* The reference is released further down, so remember this while it is still valid */
758 FromReserve = RequestReference->FromReserve;
759
760 /* FIXME: DELETE AFTER DEBUG */
761 // if (RequestReference->DumpSpecialRequest)
762 // {
763 // StorpDumpRequestResponse(RequestReference);
764 // }
765
766 DPRINT("Completing request: (%d:%d:%d) ReqRef %p Srb %p Irp %p Tag %x\n",
767 Srb->PathId, Srb->TargetId, Srb->Lun, RequestReference, Srb, RequestReference->Irp, Srb->QueueTag);
768
769 /* Return SG list resources back to system */
770 if (RequestReference->ScatterGatherList)
771 {
772 FdoExtension->DmaAdapter->DmaOperations->
773 PutScatterGatherList(FdoExtension->DmaAdapter,
774 (PSCATTER_GATHER_LIST)RequestReference->ScatterGatherList,
775 RequestReference->WriteToDevice);
776 RequestReference->ScatterGatherList = NULL;
777
778 // /* Release pages we locked for DMA, if we actually have locked it */
779 // if (RequestReference->MappedSystemVa != NULL)
780 // {
781 // MmUnmapLockedPages(RequestReference->MappedSystemVa, RequestReference->Irp->MdlAddress);
782 // }
783 /* Unlock the pages locked for DMA */
784 if (RequestReference->MappedSystemVa)
785 {
786 MmUnlockPages(RequestReference->Irp->MdlAddress);
787 }
788 }
789
790 /* Check if we need to interact with flow control. */
791 if (RequestReference->IsOutstanding)
792 {
793 /* Take the request out of FDO and PDO structures, and update flow control data */
796
797 FdoExtension->FlowControl.OutstandingRequestCount--;
798 if (FdoExtension->FlowControl.RemainingBusyRequests)
799 {
800 --FdoExtension->FlowControl.RemainingBusyRequests;
801
802 /* Clear busy state as needed */
803 if (FdoExtension->FlowControl.OutstandingRequestCount == 0 ||
804 FdoExtension->FlowControl.RemainingBusyRequests == 0)
805 {
806 FdoExtension->FlowControl.IsBusy = FALSE;
807 }
808 }
809
810 RemoveEntryList(&RequestReference->PdoEntry);
811 --PdoExtension->FlowControl.OutstandingRequestCount;
812 if (PdoExtension->FlowControl.RemainingBusyRequests)
813 {
814 --PdoExtension->FlowControl.RemainingBusyRequests;
815
816 /* Clear busy state as needed */
817 if (PdoExtension->FlowControl.OutstandingRequestCount == 0 ||
818 PdoExtension->FlowControl.RemainingBusyRequests == 0)
819 {
820 PdoExtension->FlowControl.IsBusy = FALSE;
821 }
822 }
823
824 /* Decrement strong ordered request count if needed */
825 if (RequestReference->StrongOrdered)
826 {
827 --PdoExtension->FlowControl.StrongOrderedCount;
828 }
829
830 /* Free the private data structure. No one should use it anymore */
832 RequestReference = NULL;
833
834 /* Schedule next IO before we release flow control lock */
836
837 /* We're done, release flow control lock */
840
841 }
842
843 /*
844 * Free SRB extension as this request will never go back to miniport again. Must free it before
845 * IoCompleteRequest because class driver's completion routine may issue another request. If we
846 * free it after IoCompleteRequest we may zero out the newly-issued SRB's extension, since one
847 * single SRB can be reused between requests, and the SRB issued in completion routine could be
848 * the same one we operating here.
849 */
850 if (Srb->SrbExtension)
851 {
852 /* The reserved one is handed back along with its packet, not freed */
853 if (!FromReserve)
854 {
856 }
858 }
859
860 /*
861 * After done with internal accountings, we can finally complete this IO.
862 *
863 * We must not complete the IO before scheduling next IO, because at that point the flow control
864 * lock is still held, and class driver's completion routine may issue another request. This
865 * will cause a recursive lock acquisition in PDO SCSI handler and lead to bugcheck.
866 */
867 switch (SRB_STATUS(Srb->SrbStatus))
868 {
871 break;
872
873 case SRB_STATUS_BUSY:
875 break;
876
877 default:
878 IoStatus = STATUS_UNSUCCESSFUL; // FIXME:
879 break;
880 }
881 Irp->IoStatus.Status = IoStatus;
882 Irp->IoStatus.Information = Srb->DataTransferLength; /* FIXME: hopefully this is correct */
883
884 /* We just gave memory back, so let one request that ran out of it through */
886
887 DPRINT("Calling IoCompleteRequest\n");
889}
unsigned char BOOLEAN
Definition: actypes.h:127
LONG NTSTATUS
Definition: precomp.h:26
_In_ PSCSI_REQUEST_BLOCK Srb
Definition: cdrom.h:989
_In_ PIRP Irp
Definition: csq.h:116
#define NULL
Definition: types.h:112
#define FALSE
Definition: types.h:117
#define SRB_STATUS(Status)
Definition: srb.h:389
#define SRB_STATUS_BUSY
Definition: srb.h:345
#define SRB_STATUS_SUCCESS
Definition: srb.h:341
#define TAG_SRB_EXTENSION
Definition: precomp.h:41
@ PdoExtension
Definition: precomp.h:61
@ FdoExtension
Definition: precomp.h:60
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
VOID FASTCALL KeAcquireInStackQueuedSpinLock(IN PKSPIN_LOCK SpinLock, IN PKLOCK_QUEUE_HANDLE LockHandle)
Definition: spinlock.c:130
VOID FASTCALL KeReleaseInStackQueuedSpinLock(IN PKLOCK_QUEUE_HANDLE LockHandle)
Definition: spinlock.c:166
#define StorpCheckFlowControl(...)
Definition: inline.h:252
VOID NTAPI MmUnlockPages(IN PMDL Mdl)
Definition: mdlsup.c:1435
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
__in UCHAR __in POWER_STATE __in_opt PVOID __in PIO_STATUS_BLOCK IoStatus
Definition: mxum.h:159
#define IoCompleteRequest
Definition: irp.c:1272
#define STATUS_SUCCESS
Definition: shellext.h:65
#define DPRINT
Definition: sndvol32.h:73
VOID StorpSrbFreeRequestReference(_In_ PSCSI_REQUEST_BLOCK Srb)
Frees an SRB's Request Reference and restore Srb->OriginalRequest field to IRP. This function does no...
Definition: srb.c:106
static VOID PortScheduleComingRequestsOnCompletion(_In_ PPDO_DEVICE_EXTENSION PdoExtension, _In_ PFDO_DEVICE_EXTENSION FdoExtension)
Definition: srb.c:670
VOID PortRetryStarvedRequest(_In_ PFDO_DEVICE_EXTENSION FdoExtension)
Retries one queued request, so each completion lets exactly one through.
Definition: fdo.c:135
UCHAR QueueTag
Definition: srb.h:256
UCHAR TargetId
Definition: srb.h:254
UCHAR PathId
Definition: srb.h:253
ULONG DataTransferLength
Definition: srb.h:261
PVOID SrbExtension
Definition: srb.h:267
UCHAR SrbStatus
Definition: srb.h:251
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define STATUS_DEVICE_BUSY
Definition: udferr_usr.h:129
struct _SCATTER_GATHER_LIST * PSCATTER_GATHER_LIST
Definition: iotypes.h:2206
#define IO_DISK_INCREMENT
Definition: iotypes.h:600
*LockHandle LockHandle _Out_ PKLOCK_QUEUE_HANDLE LockHandle
Definition: kefuncs.h:717

Referenced by PortCompletionDpc().

◆ PortCompletionDpc()

VOID NTAPI PortCompletionDpc ( _In_ PKDPC  Dpc,
_In_ PVOID  Context,
_In_ PVOID  SystemArgument1,
_In_ PVOID  SystemArgument2 
)

Definition at line 894 of file srb.c.

899{
900 PQUEUED_REQUEST_REFERENCE RequestReference;
904 ULONG Count = 0;
905
906 DPRINT("PortCompletionDpc(%p %p %p %p)\n", Dpc, Context, SystemArgument1, SystemArgument2);
907
908 /* Take context pointer as FDO extension */
910
911 /* Flush all entries in the list and complete all requests */
912 Entry = InterlockedFlushSList(&FdoExtension->CompletionList);
913 while (Entry)
914 {
915 /* Prepare Next pointer first (Completion routine will free the memory that contains it) */
916 Next = Entry->Next;
917
918 /* Get original request */
919 RequestReference = CONTAINING_RECORD(Entry, QUEUED_REQUEST_REFERENCE, CompletionEntry);
920
921 /* Call real completion routine */
922 PortCompleteRequest(RequestReference);
923
924 /* Move on to next one */
925 Entry = Next;
926 ++Count;
927 }
928
929 DPRINT("Completed %d requests\n", Count);
930}
struct _FDO_DEVICE_EXTENSION * PFDO_DEVICE_EXTENSION
int Count
Definition: noreturn.cpp:7
Entry
Definition: section.c:5216
STDMETHOD() Next(THIS_ ULONG celt, IAssociationElement *pElement, ULONG *pceltFetched) PURE
static VOID PortCompleteRequest(_In_ PQUEUED_REQUEST_REFERENCE RequestReference)
Definition: srb.c:740
_In_ PVOID Context
Definition: storport.h:2325
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
_Must_inspect_result_ _In_ PWDF_DPC_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFDPC * Dpc
Definition: wdfdpc.h:112
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:756
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:757
#define InterlockedFlushSList(SListHead)
Definition: rtlfuncs.h:3419
#define PSLIST_ENTRY
Definition: rtltypes.h:134

Referenced by PortAddDevice().

◆ PortPdoAfterBuildingScatterGatherList()

VOID NTAPI PortPdoAfterBuildingScatterGatherList ( _In_ PDEVICE_OBJECT  DeviceObject,
_In_ PIRP  Irp,
_In_ PSCATTER_GATHER_LIST  ScatterGatherList,
_In_ PVOID  Context 
)

Definition at line 168 of file srb.c.

173{
175 PVOID MiniportExtension;
176 PHW_INITIALIZATION_DATA HwInitData;
177 PQUEUED_REQUEST_REFERENCE RequestReference;
178 BOOLEAN CanStartIo = TRUE;
180
181 RequestReference = (PQUEUED_REQUEST_REFERENCE)Context;
183 MiniportExtension = &FdoExtension->Miniport.MiniportExtension->HwDeviceExtension;
184 HwInitData = FdoExtension->HwInitData;
185
186 /* Save our SG List */
187 RequestReference->ScatterGatherList = (PSTOR_SCATTER_GATHER_LIST)ScatterGatherList;
188
189 /* BuildIo and StartIo are called on DISPATCH_LEVEL */
191
192 do {
193 /* Call BuildIo, if one is provided */
194 if (HwInitData->HwBuildIo)
195 {
196 CanStartIo = HwInitData->HwBuildIo(MiniportExtension, RequestReference->Srb);
197 }
198
199 /* If BuildIo says the request processing shall stop here, no more processing is needed */
200 if (!CanStartIo)
201 {
202 break;
203 }
204
205 HwInitData->HwStartIo(MiniportExtension, RequestReference->Srb);
206 }
207 while (0);
208
209 /* Restore IRQL */
211}
#define TRUE
Definition: types.h:120
struct _QUEUED_REQUEST_REFERENCE * PQUEUED_REQUEST_REFERENCE
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
KIRQL FASTCALL KfRaiseIrql(IN KIRQL NewIrql)
Definition: pic.c:187
PHW_STARTIO HwStartIo
Definition: srb.h:568
PHW_BUILDIO HwBuildIo
Definition: storport.h:2423
PSCSI_REQUEST_BLOCK Srb
Definition: precomp.h:343
PSTOR_SCATTER_GATHER_LIST ScatterGatherList
Definition: precomp.h:345
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2061
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778

Referenced by PortPdoIssueRequest().

◆ PortPdoIssueRequest()

NTSTATUS PortPdoIssueRequest ( _In_ PPDO_DEVICE_EXTENSION  PdoExtension,
_In_ PQUEUED_REQUEST_REFERENCE  RequestReference 
)

Definition at line 290 of file srb.c.

293{
294 PIRP Irp;
297 PHW_INITIALIZATION_DATA HwInitData;
299
300 Irp = RequestReference->Irp;
301 FdoExtension = PdoExtension->FdoExtension;
302 HwInitData = FdoExtension->Miniport.InitData;
303
304 NT_ASSERT(HwInitData);
305
306 /* Fill in SCSI address data */
307 /* FIXME: Not sure if this is the best place for it. */
308 RequestReference->Srb->PathId = PdoExtension->Bus;
309 RequestReference->Srb->TargetId = PdoExtension->Target;
310 RequestReference->Srb->Lun = PdoExtension->Lun;
311
312 /* FIXME: Delete after debug */
313 // PSCSI_REQUEST_BLOCK Srb = RequestReference->Srb;
314 // if (Srb->Function == SRB_FUNCTION_EXECUTE_SCSI &&
315 // (Srb->Cdb[0] == SCSIOP_GET_EVENT_STATUS || Srb->Cdb[0] == SCSIOP_TEST_UNIT_READY))
316 // {
317 // RequestReference->DumpSpecialRequest = TRUE;
318 // StorpDumpRequest(RequestReference);
319 // }
320
321 /* Start an DMA if IO subsystem allocated an MDL for us */
322 /* FIXME: Does this strategy work? */
323 if (RequestReference->Irp->MdlAddress)
324 {
325 /*
326 * Lock the buffer so that it stays in physical memory.
327 * In the two cases avoided here the memory has already been locked
328 */
329 if (!TEST_FLAG(Irp->MdlAddress->MdlFlags, MDL_SOURCE_IS_NONPAGED_POOL) &&
330 !TEST_FLAG(Irp->MdlAddress->MdlFlags, MDL_MAPPED_TO_SYSTEM_VA) &&
331 !TEST_FLAG(Irp->MdlAddress->MdlFlags, MDL_PAGES_LOCKED) &&
332 !TEST_FLAG(Irp->MdlAddress->MdlFlags, MDL_PARTIAL))
333 {
334 RequestReference->MappedSystemVa = (PVOID)1; /* FIXME: CHANGE ITS NAME */
336 }
337
338 /* Following call requires DISPATCH_LEVEL. */
340
341 /* Make up the scatter gather list */
342 /* FIXME: I don't know if we actually hit it */
343 NT_ASSERT((RequestReference->Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION) !=
345 RequestReference->WriteToDevice =
346 TEST_FLAG(RequestReference->Srb->SrbFlags, SRB_FLAGS_DATA_OUT);
347
348 FdoExtension->DmaAdapter->DmaOperations->
349 GetScatterGatherList(FdoExtension->DmaAdapter,
350 FdoExtension->Device,
351 RequestReference->Irp->MdlAddress,
352 MmGetMdlVirtualAddress(RequestReference->Irp->MdlAddress),
353 RequestReference->Srb->DataTransferLength,
355 (PVOID)RequestReference,
356 RequestReference->WriteToDevice);
357
358 /* Restore IRQL */
360 } else {
361 /* Otherwise just start the IO with a NULL scatter gather list */
363 RequestReference->Irp,
364 NULL,
365 RequestReference);
366 }
367
368 /* FIXME: Is this correct? */
370
371 return Status;
372}
#define TEST_FLAG(Flags, Bit)
Definition: cdrom.h:1495
#define SRB_FLAGS_DATA_OUT
Definition: srb.h:401
#define SRB_FLAGS_UNSPECIFIED_DIRECTION
Definition: srb.h:403
Status
Definition: gdiplustypes.h:24
VOID NTAPI MmProbeAndLockPages(IN PMDL Mdl, IN KPROCESSOR_MODE AccessMode, IN LOCK_OPERATION Operation)
Definition: mdlsup.c:931
#define KernelMode
Definition: asm.h:38
VOID NTAPI PortPdoAfterBuildingScatterGatherList(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ PSCATTER_GATHER_LIST ScatterGatherList, _In_ PVOID Context)
Definition: srb.c:168
#define STATUS_PENDING
Definition: telnetd.h:14
void * PVOID
Definition: typedefs.h:50
@ IoModifyAccess
Definition: ketypes.h:933
#define MmGetMdlVirtualAddress(_Mdl)
#define MDL_PAGES_LOCKED
Definition: mmtypes.h:19
#define MDL_PARTIAL
Definition: mmtypes.h:22
#define MDL_SOURCE_IS_NONPAGED_POOL
Definition: mmtypes.h:20
#define MDL_MAPPED_TO_SYSTEM_VA
Definition: mmtypes.h:18
#define NT_ASSERT
Definition: rtlfuncs.h:3334

Referenced by PortPdoScsi(), and PortScheduleComingRequestsOnCompletion().

◆ PortPdoScheduleRequestFlowControlled()

BOOLEAN PortPdoScheduleRequestFlowControlled ( _In_ PPDO_DEVICE_EXTENSION  PdoExtension,
_In_ PFDO_DEVICE_EXTENSION  FdoExtension,
_In_ PQUEUED_REQUEST_REFERENCE  RequestReference 
)

Schedules an outstanding request and return a boolean value to indicate if the request can be immediately issued.

Parameters
PdoExtensionPDO device extension.
FdoExtensionFDO device extension.
RequestReferenceRequestReference must be allocated beforehand.
Returns
BOOLEAN When TRUE, you can call PortPdoIssueRequest to issue request right away; When FALSE, the request is already queued in flow control structures and you can safely go on without further processing, it will be issued upon completions.

Definition at line 397 of file srb.c.

401{
402 PPDO_IO_FLOW_CONTROL FlowControl = &PdoExtension->FlowControl;
404 PSCSI_REQUEST_BLOCK Srb = RequestReference->Srb;
405 BOOLEAN StrongOrderedRequest = FALSE;
406 BOOLEAN IssueRequest = TRUE;
407
408 /* Set outstanding flag */
409 RequestReference->IsOutstanding = TRUE;
410
411 /* Check if we can issue this request. */
412 /* Acquire the HBA global flow control lock first */
415
416 do
417 {
418 /* Check PDO flow control conditions */
419
420 /* Sanity check */
421 NT_ASSERT(FlowControl->OutstandingRequestCount <= PdoExtension->OutstandingRequestMax);
422
423 /* If PDO is not suitable to receive a request, make it wait */
424 if (FlowControl->IsBusy || FlowControl->IsPaused ||
427 FlowControl->StrongOrderedCount ||
428 FlowControl->OutstandingRequestCount == PdoExtension->OutstandingRequestMax ||
429 (!IsListEmpty(&FlowControl->AwaitingRequestsListHead)))
430 {
432 &RequestReference->PdoEntry);
433 IssueRequest = FALSE;
434 break;
435 }
436
437 /* Check if this request is strong-ordered */
440 {
441 RequestReference->StrongOrdered = TRUE;
442 StrongOrderedRequest = TRUE;
443 ++FlowControl->StrongOrderedCount;
444 }
445
446 /*
447 * If this request is strong ordered and the LUN's active/approved list is not
448 * drained, the request must wait.
449 */
450 if (StrongOrderedRequest && !IsListEmpty(&FlowControl->ActiveRequestsListHead))
451 {
453 &RequestReference->PdoEntry);
454 IssueRequest = FALSE;
455 break;
456 }
457
458 /*
459 * If any break's triggered before this point, the request is in PDO waiting queue.
460 * Going past this point meant PDO approves this request. Put it into active list.
461 */
463 {
465 &RequestReference->PdoEntry);
466 } else {
468 &RequestReference->PdoEntry);
469 }
470
471 /* A new outstanding request is added to this LUN */
472 ++FlowControl->OutstandingRequestCount;
473
474 /* Check FDO flow control status. */
475
476 /* If the FDO can't handle more requests, then the request should be queued. */
477 if (FlowControl->IsBusy || FlowControl->IsPaused ||
478 FlowControl->OutstandingRequestCount == FdoExtension->OutstandingRequestMax)
479 {
480 /* Put into FDO queue */
481 InsertHeadList(&FdoExtension->FlowControl.FdoBlockedRequestsListHead,
482 &RequestReference->FdoEntry);
483
484 /*
485 * Now the request is in PDO active list, in FDO awaiting queue, not issued.
486 * Let it wait until another completion event schedules it.
487 */
488 break;
489 }
490
491 /* Seems good, increment FDO request count */
492 ++FdoExtension->FlowControl.OutstandingRequestCount;
493
494 /*
495 * Now the request is counted in FDO & PDO, and is put into PDO active list,
496 * next step we're going to issue it.
497 */
498 } while (0);
499
500 // FIXME: The port driver indicates that an LU-specific queue has been frozen by
501 // returning a request with SRB_STATUS_QUEUE_FROZEN in the SrbStatus member. New
502 // requests from the class driver can be inserted into the queue, but only autosense
503 // requests are sent to the logical unit as long as its queue is frozen.
504 // https://learn.microsoft.com/en-us/windows-hardware/drivers/storage/storage-class-driver-s-releasequeue-routine
505
506 /* We've determined where the request goes. Release the flow control lock */
509
510 return IssueRequest;
511}
#define SRB_FLAGS_BYPASS_FROZEN_QUEUE
Definition: srb.h:398
#define SRB_ORDERED_QUEUE_TAG_REQUEST
Definition: srb.h:425
#define SRB_FLAGS_QUEUE_ACTION_ENABLE
Definition: srb.h:395
#define SRB_HEAD_OF_QUEUE_TAG_REQUEST
Definition: srb.h:424
#define SRB_FLAGS_BYPASS_LOCKED_QUEUE
Definition: srb.h:410
#define InsertTailList(ListHead, Entry)
#define InsertHeadList(ListHead, Entry)
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
LIST_ENTRY ActiveRequestsListHead
Definition: precomp.h:180
ULONG OutstandingRequestCount
Definition: precomp.h:171
ULONG StrongOrderedCount
Definition: precomp.h:168
LIST_ENTRY AwaitingRequestsListHead
Definition: precomp.h:186
UCHAR QueueAction
Definition: srb.h:257
ULONG SrbFlags
Definition: srb.h:260

Referenced by PortPdoScsi().

◆ PortPdoScheduleRequestNoFlowControl()

VOID PortPdoScheduleRequestNoFlowControl ( _In_ PFDO_DEVICE_EXTENSION  FdoExtension,
_In_ PQUEUED_REQUEST_REFERENCE  RequestReference 
)

Definition at line 376 of file srb.c.

379{
380 /* Ensure outstanding flag is unset */
381 RequestReference->IsOutstanding = FALSE;
382}

Referenced by PortPdoScsi().

◆ PortPdoScsi()

NTSTATUS NTAPI PortPdoScsi ( _In_ PDEVICE_OBJECT  DeviceObject,
_In_ PIRP  Irp 
)

Definition at line 516 of file srb.c.

519{
525 PMINIPORT Miniport;
526 PHW_INITIALIZATION_DATA HwInitData;
527
528 DPRINT("PortPdoScsi(%p %p)\n", DeviceObject, Irp);
529
531 Srb = Stack->Parameters.Scsi.Srb;
532
533 if (Srb == NULL) {
534 DPRINT1("Srb is NULL!");
537
538 Irp->IoStatus.Information = 0;
539 Irp->IoStatus.Status = Status;
540
542 return Status;
543 }
544
547 FdoExtension = PdoExtension->FdoExtension;
549 Miniport = &FdoExtension->Miniport;
550 HwInitData = Miniport->InitData;
551
552 switch (Srb->Function) {
553 /* Both of these should be sent to device and let themselves process this */
556 {
557 PQUEUED_REQUEST_REFERENCE RequestReference;
558 BOOLEAN IssueRequest;
559
560 /* Mark IRP as pending */
562
563 /* Allocate private contexts */
565 if (Status != STATUS_SUCCESS)
566 {
567 break;
568 }
569 RequestReference = (PQUEUED_REQUEST_REFERENCE)Srb->OriginalRequest;
570
571 /* Assign a tag to the SRB if it supports tagging */
573
574 DPRINT("New request (%d:%d:%d) ReqRef %p Srb %p Irp %p Tag %x SrbExt %p(%d)\n",
576 RequestReference, Srb, Irp, Srb->QueueTag,
577 Srb->SrbExtension, HwInitData->SrbExtensionSize);
578
579 /*
580 * Do the scheduling. If returns TRUE, we should issue this request to the hardware.
581 * Otherwise it will keep waiting until next completion schedules it, or be cancelled on
582 * an error, etc.
583 */
586 RequestReference);
587
588 /* This request is viable to be issued. */
589 if (IssueRequest)
590 {
591 Status = PortPdoIssueRequest(PdoExtension, RequestReference);
592 } else {
594 }
595
596 break;
597 }
598
599 /*
600 * These requests are actually sent to adapters and are not outstanding requests for devices
601 * so we simply pass them down to miniport
602 */
605 {
606 PQUEUED_REQUEST_REFERENCE RequestReference;
607
608 /* Mark IRP as pending */
610
611 /* Allocate private contexts */
613 if (Status != STATUS_SUCCESS)
614 {
615 break;
616 }
617 RequestReference = (PQUEUED_REQUEST_REFERENCE)Srb->OriginalRequest;
618
619 /*
620 * Call the non-flow-controlled scheduling function (it does nothing but the model is
621 * preserved for consistency)
622 */
624
625 /* Fire up the request immediately */
626 PortPdoIssueRequest(PdoExtension, RequestReference);
627
628 break;
629 }
630
632 {
633 if (InterlockedCompareExchange(&PdoExtension->IsClaimed, 1, 0))
634 {
637 break;
638 }
639
640 /* The claimed device object is handed back to the class driver here */
641 Srb->DataBuffer = PdoExtension->Device;
644 break;
645 }
646
648 {
649 InterlockedExchange(&PdoExtension->IsClaimed, 0);
650
653 break;
654 }
655
656 default:
657 DPRINT1("Unsupported Srb Function %02X!", Srb->Function);
658 // DbgBreakPoint();
661 break;
662 }
663
664 return Status;
665}
static PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(PIRP Irp)
#define InterlockedExchange
Definition: armddk.h:54
#define DPRINT1
Definition: precomp.h:8
#define STATUS_NOT_IMPLEMENTED
Definition: d3dkmdt.h:42
struct _PDO_DEVICE_EXTENSION * PPDO_DEVICE_EXTENSION
#define SRB_FUNCTION_RELEASE_DEVICE
Definition: srb.h:321
#define SRB_FUNCTION_CLAIM_DEVICE
Definition: srb.h:316
#define SRB_FUNCTION_IO_CONTROL
Definition: srb.h:317
#define SRB_FUNCTION_EXECUTE_SCSI
Definition: srb.h:315
#define SRB_FUNCTION_FLUSH
Definition: srb.h:323
#define SRB_FUNCTION_SHUTDOWN
Definition: srb.h:322
#define SRB_STATUS_INVALID_REQUEST
Definition: srb.h:346
FORCEINLINE VOID StorpCompleteRequest(_In_ PIRP Irp, _In_ UCHAR SrbStatus, _In_ NTSTATUS IrpStatus)
Completes a request with specified SRB status and IRP status.
Definition: inline.h:19
#define InterlockedCompareExchange
Definition: interlocked.h:119
IoMarkIrpPending(Irp)
FORCEINLINE BOOLEAN StorpAssignTagToSrb(_In_ PPDO_DEVICE_EXTENSION PdoExtension, _In_ PSCSI_REQUEST_BLOCK Srb)
Assigns a queue tag to a request if it stated it supports one.
Definition: srb.c:136
BOOLEAN PortPdoScheduleRequestFlowControlled(_In_ PPDO_DEVICE_EXTENSION PdoExtension, _In_ PFDO_DEVICE_EXTENSION FdoExtension, _In_ PQUEUED_REQUEST_REFERENCE RequestReference)
Schedules an outstanding request and return a boolean value to indicate if the request can be immedia...
Definition: srb.c:397
VOID PortPdoScheduleRequestNoFlowControl(_In_ PFDO_DEVICE_EXTENSION FdoExtension, _In_ PQUEUED_REQUEST_REFERENCE RequestReference)
Definition: srb.c:376
NTSTATUS PortPdoSrbAllocatePrivateContexts(_In_ PSCSI_REQUEST_BLOCK Srb, _In_ PPDO_DEVICE_EXTENSION PdoExtension, _In_ PFDO_DEVICE_EXTENSION FdoExtension)
Definition: srb.c:240
NTSTATUS PortPdoIssueRequest(_In_ PPDO_DEVICE_EXTENSION PdoExtension, _In_ PQUEUED_REQUEST_REFERENCE RequestReference)
Definition: srb.c:290
ULONG SrbExtensionSize
Definition: srb.h:576
PHW_INITIALIZATION_DATA InitData
Definition: precomp.h:91
PVOID OriginalRequest
Definition: srb.h:266
PVOID DataBuffer
Definition: srb.h:263
UCHAR Function
Definition: srb.h:250
_In_ WDFREQUEST _In_ PIO_STACK_LOCATION Stack
Definition: wdfrequest.h:639
NTSYSAPI void WINAPI DbgBreakPoint(void)
#define IO_NO_INCREMENT
Definition: iotypes.h:598

Referenced by PortDispatchScsi(), and PortRetryStarvedRequest().

◆ PortPdoSrbAllocatePrivateContexts()

NTSTATUS PortPdoSrbAllocatePrivateContexts ( _In_ PSCSI_REQUEST_BLOCK  Srb,
_In_ PPDO_DEVICE_EXTENSION  PdoExtension,
_In_ PFDO_DEVICE_EXTENSION  FdoExtension 
)

Definition at line 240 of file srb.c.

244{
245 PQUEUED_REQUEST_REFERENCE RequestReference;
246 ULONG SrbExtensionSize = FdoExtension->HwInitData->SrbExtensionSize;
247 PIRP Irp;
248
250
251 /* Allocate our private data area, falling back on the reserve when pool is exhausted */
253 if (RequestReference == NULL)
254 {
256 if (RequestReference == NULL)
257 {
259 }
260 }
261
262 /* Allocate SRB extension */
263 if (SrbExtensionSize == 0)
264 {
266 return STATUS_SUCCESS;
267 }
268
269 if (RequestReference->FromReserve)
270 {
271 Srb->SrbExtension = FdoExtension->ReservedSrbExtension;
272 RtlZeroMemory(Srb->SrbExtension, SrbExtensionSize);
273 return STATUS_SUCCESS;
274 }
275
277 SrbExtensionSize,
279 if (Srb->SrbExtension == NULL)
280 {
283 }
284
285 return STATUS_SUCCESS;
286}
struct _IRP * PIRP
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define NonPagedPool
Definition: env_spec_w32.h:307
static NTSTATUS PortPdoStarveRequest(_In_ PFDO_DEVICE_EXTENSION FdoExtension, _In_ PSCSI_REQUEST_BLOCK Srb, _In_ PIRP Irp)
Parks a request that is out of memory, or fails it if there is no reserve to wait for....
Definition: srb.c:220
static PQUEUED_REQUEST_REFERENCE StorpSrbAcquireReservedRequestReference(_In_ PSCSI_REQUEST_BLOCK Srb, _In_ PIRP Irp, _In_ PPDO_DEVICE_EXTENSION PdoExtension)
Takes the adapter reserve, if it is there and nobody else holds it.
Definition: srb.c:77
static PQUEUED_REQUEST_REFERENCE StorpSrbAllocateRequestReference(_In_ PSCSI_REQUEST_BLOCK Srb, _In_ PIRP Irp, _In_ PPDO_DEVICE_EXTENSION PdoExtension)
Allocates QUEUED_REQUEST_REFERENCE for an SRB that is going to be processed.
Definition: srb.c:51
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262

Referenced by PortPdoScsi().

◆ PortPdoStarveRequest()

static NTSTATUS PortPdoStarveRequest ( _In_ PFDO_DEVICE_EXTENSION  FdoExtension,
_In_ PSCSI_REQUEST_BLOCK  Srb,
_In_ PIRP  Irp 
)
static

Parks a request that is out of memory, or fails it if there is no reserve to wait for. Either way the IRP is no longer ours, hence STATUS_PENDING.

Definition at line 220 of file srb.c.

224{
225 /* Without a reserve nothing guarantees a completion that would retry the request */
226 if (FdoExtension->ReservedRequestReference == NULL)
227 {
230 }
231 else
232 {
234 }
235
236 return STATUS_PENDING;
237}
#define SRB_STATUS_INTERNAL_ERROR
Definition: srb.h:373
VOID PortQueueStarvedRequest(_In_ PFDO_DEVICE_EXTENSION FdoExtension, _In_ PIRP Irp)
Queues a request that could not allocate its private contexts.
Definition: fdo.c:124
ULONG InternalStatus
Definition: srb.h:269
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158

Referenced by PortPdoSrbAllocatePrivateContexts().

◆ PortScheduleComingRequestsOnCompletion()

static VOID PortScheduleComingRequestsOnCompletion ( _In_ PPDO_DEVICE_EXTENSION  PdoExtension,
_In_ PFDO_DEVICE_EXTENSION  FdoExtension 
)
static

Definition at line 670 of file srb.c.

673{
675 PQUEUED_REQUEST_REFERENCE RequestReference;
676
677 /* Sanity check again whether FDO has resource to handle the request */
678 NT_ASSERT(FdoExtension->FlowControl.OutstandingRequestCount <
679 FdoExtension->OutstandingRequestMax);
680
681 /* If FDO has waiting requests, issue one. */
682 if (!IsListEmpty(&FdoExtension->FlowControl.FdoBlockedRequestsListHead))
683 {
684 /* Sanity check */
685 NT_ASSERT(FdoExtension->FlowControl.OutstandingRequestCount <
686 FdoExtension->OutstandingRequestMax);
687
688 /* Take it out of FDO list */
689 Entry = RemoveTailList(&FdoExtension->FlowControl.FdoBlockedRequestsListHead);
690 RequestReference = CONTAINING_RECORD(Entry, QUEUED_REQUEST_REFERENCE, FdoEntry);
691
692 /* Increment FDO request counter */
693 ++FdoExtension->FlowControl.OutstandingRequestCount;
694 NT_ASSERT(FdoExtension->FlowControl.OutstandingRequestCount <=
695 FdoExtension->OutstandingRequestMax);
696
697 /* Call the start routine */
698 PortPdoIssueRequest(PdoExtension, RequestReference);
699
700 /* Our task is done */
701 return;
702 }
703
704 /* FDO's got no request, check the PDO of the just-finished request for awaiting requests */
705 if (!IsListEmpty(&PdoExtension->FlowControl.AwaitingRequestsListHead))
706 {
707 /* Sanity check */
708 NT_ASSERT(PdoExtension->FlowControl.OutstandingRequestCount <
709 PdoExtension->OutstandingRequestMax);
710
711 /* Take one request */
712 Entry = RemoveTailList(&PdoExtension->FlowControl.AwaitingRequestsListHead);
713 RequestReference = CONTAINING_RECORD(Entry, QUEUED_REQUEST_REFERENCE, PdoEntry);
714
715 /* This one goes to active list */
716 InsertHeadList(&PdoExtension->FlowControl.ActiveRequestsListHead, Entry);
717
718 /* Increment PDO request counter */
719 ++PdoExtension->FlowControl.OutstandingRequestCount;
720 NT_ASSERT(PdoExtension->FlowControl.OutstandingRequestCount <=
721 PdoExtension->OutstandingRequestMax);
722
723 /* FIXME: should be false. Allocate resource if it is determined required */
724 if (RequestReference->Srb->SrbExtension == NULL)
725 {
726 __debugbreak();
727 }
728
729 /* Call the start routine */
730 PortPdoIssueRequest(PdoExtension, RequestReference);
731
732 /* Our task is done */
733 return;
734 }
735}
#define RemoveTailList(ListHead)
Definition: env_spec_w32.h:975
void __cdecl __debugbreak(void)
Definition: intrin_ppc.h:698
Definition: typedefs.h:120

Referenced by PortCompleteRequest().

◆ StorpAssignTagToSrb()

FORCEINLINE BOOLEAN StorpAssignTagToSrb ( _In_ PPDO_DEVICE_EXTENSION  PdoExtension,
_In_ PSCSI_REQUEST_BLOCK  Srb 
)

Assigns a queue tag to a request if it stated it supports one.

Parameters
PdoExtensionPDO Device extension
SrbSRB that represents this request
Returns
BOOLEAN Whether the request was assigned a tag at last.

Definition at line 136 of file srb.c.

140{
141 ULONG NewTag;
142
143 /* Bail out if the request is untagged */
145 {
146 return FALSE;
147 }
148
149 /* FIXME: What if the counter overflows? */
150 NewTag = InterlockedIncrement(&PdoExtension->TagCounter);
151
152 /*
153 * We use ULONG for tag counter, and here seems to do a stupid truncation by casting to UCHAR;
154 * But since Storport has a default maximum 254 requests/LUN limitation, this is actually OK for
155 * our use case. If a miniport needs to support more than 254 tags it must use
156 * STORAGE_REQUEST_BLOCK which we don't support yet :D
157 */
158 Srb->QueueTag = (UCHAR)(NewTag % PdoExtension->OutstandingRequestMax);
159
160 DPRINT("StorpAssignTagToSrb: Assigned Tag %x, TagCounter was %x\n", Srb->QueueTag, NewTag);
161
162 return TRUE;
163}
#define InterlockedIncrement
Definition: armddk.h:53
unsigned char UCHAR
Definition: typedefs.h:53

Referenced by PortPdoScsi().

◆ StorpSrbAcquireReservedRequestReference()

static PQUEUED_REQUEST_REFERENCE StorpSrbAcquireReservedRequestReference ( _In_ PSCSI_REQUEST_BLOCK  Srb,
_In_ PIRP  Irp,
_In_ PPDO_DEVICE_EXTENSION  PdoExtension 
)
static

Takes the adapter reserve, if it is there and nobody else holds it.

Returns
PQUEUED_REQUEST_REFERENCE The reserved reference, or NULL if unavailable.

Definition at line 77 of file srb.c.

81{
83 PQUEUED_REQUEST_REFERENCE RequestReference;
84
85 if (FdoExtension->ReservedRequestReference == NULL ||
86 InterlockedCompareExchange(&FdoExtension->ReserveInUse, 1, 0) != 0)
87 {
88 return NULL;
89 }
90
91 RequestReference = FdoExtension->ReservedRequestReference;
93 RequestReference->FromReserve = TRUE;
94
95 return RequestReference;
96}
static VOID StorpSrbInitRequestReference(_In_ PQUEUED_REQUEST_REFERENCE RequestReference, _In_ PSCSI_REQUEST_BLOCK Srb, _In_ PIRP Irp, _In_ PPDO_DEVICE_EXTENSION PdoExtension)
Initializes a request reference and sets the SRB => ReqRef link.
Definition: srb.c:25

Referenced by PortPdoSrbAllocatePrivateContexts().

◆ StorpSrbAllocateRequestReference()

static PQUEUED_REQUEST_REFERENCE StorpSrbAllocateRequestReference ( _In_ PSCSI_REQUEST_BLOCK  Srb,
_In_ PIRP  Irp,
_In_ PPDO_DEVICE_EXTENSION  PdoExtension 
)
static

Allocates QUEUED_REQUEST_REFERENCE for an SRB that is going to be processed.

Parameters
Srb
Irp
Returns
PQUEUED_REQUEST_REFERENCE RequestReference structure allocated, or NULL on failure.

Definition at line 51 of file srb.c.

55{
56 PQUEUED_REQUEST_REFERENCE RequestReference;
57
58 RequestReference =
59 ExAllocateFromNPagedLookasideList(&PdoExtension->FdoExtension->RequestReferenceLookaside);
60 if (RequestReference == NULL)
61 {
62 return NULL;
63 }
64
66
67 return RequestReference;
68}

Referenced by PortPdoSrbAllocatePrivateContexts().

◆ StorpSrbFreeRequestReference()

VOID StorpSrbFreeRequestReference ( _In_ PSCSI_REQUEST_BLOCK  Srb)

Frees an SRB's Request Reference and restore Srb->OriginalRequest field to IRP. This function does not check if Srb->OriginalRequest is actually an request reference, and you must determine it by other means.

Parameters
Srb

Definition at line 106 of file srb.c.

108{
109 PQUEUED_REQUEST_REFERENCE RequestReference;
111
112 RequestReference = (PQUEUED_REQUEST_REFERENCE)Srb->OriginalRequest;
113 Srb->OriginalRequest = RequestReference->Irp;
114 FdoExtension = RequestReference->PdoExtension->FdoExtension;
115
116 if (RequestReference->FromReserve)
117 {
118 InterlockedExchange(&FdoExtension->ReserveInUse, 0);
119 }
120 else
121 {
122 ExFreeToNPagedLookasideList(&FdoExtension->RequestReferenceLookaside, RequestReference);
123 }
124}
if(dx< 0)
Definition: linetemp.h:194
PFDO_DEVICE_EXTENSION FdoExtension
Definition: precomp.h:303
PPDO_DEVICE_EXTENSION PdoExtension
Definition: precomp.h:342

Referenced by PortCompleteRequest(), and PortPdoSrbAllocatePrivateContexts().

◆ StorpSrbInitRequestReference()

static VOID StorpSrbInitRequestReference ( _In_ PQUEUED_REQUEST_REFERENCE  RequestReference,
_In_ PSCSI_REQUEST_BLOCK  Srb,
_In_ PIRP  Irp,
_In_ PPDO_DEVICE_EXTENSION  PdoExtension 
)
static

Initializes a request reference and sets the SRB => ReqRef link.

Definition at line 25 of file srb.c.

30{
31 /* Both the lookaside entries and the reserve are recycled, so they need zeroing */
32 RtlZeroMemory(RequestReference, sizeof(*RequestReference));
33
34 Srb->OriginalRequest = (PVOID)RequestReference;
35 RequestReference->Irp = Irp;
36 RequestReference->Srb = Srb;
37 RequestReference->TimeoutCounter = Srb->TimeOutValue;
38
39 RequestReference->PdoExtension = PdoExtension;
40}
ULONG TimeOutValue
Definition: srb.h:262

Referenced by StorpSrbAcquireReservedRequestReference(), and StorpSrbAllocateRequestReference().