SRB_FUNCTION_LOCK_QUEUE always return SRB_STATUS_PENDING

Hi,
I have a lower storage filter driver sitting right below disk driver.
In my filter driver, I build IRP to send SRB_FUNCTION_LOCK_QUEUE to lock the storage driver internal queue. However, I always get status success on IRP but SRB_STATUS_PENDING on SRB block. I look at the WDK document. It seems that if several times retry can be applyed if SRB return failed. But SRB_STATUS_PENDING is not failed status. I can’t find any info about what driver should do in that case. I even can not verify if the requirement is really success. Do I have something wrong? I put the code in here. Any help is appreciated.

NTSTATUS FilterLockQueue(IN PDEVICE_OBJECT DeviceObject, OUT PIO_STATUS_BLOCK pIoStatus)
{
PIRP irp;
PVOID senseInfoBuffer;
PSCSI_REQUEST_BLOCK srb;

PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION deviceExtension;

KEVENT WaitEvent;
NTSTATUS status;

deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;

srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE);
if (srb == NULL)
return STATUS_INSUFFICIENT_RESOURCES;

RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);

senseInfoBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);

if (senseInfoBuffer == NULL) {

ExFreePool(srb);

return STATUS_INSUFFICIENT_RESOURCES;
}

irp = IoAllocateIrp((CCHAR)(deviceExtension->TargetDeviceObject->StackSize + 1), FALSE);

if (irp == NULL) {

ExFreePool(senseInfoBuffer);
ExFreePool(srb);

return STATUS_INSUFFICIENT_RESOURCES;
}

//
// Get next stack location.
//
irpStack = IoGetNextIrpStackLocation(irp);

KeInitializeEvent(&WaitEvent, NotificationEvent, FALSE);

//
// Set up SRB for execute scsi request. Save SRB address in next stack
// for the port driver.
//

irpStack->MajorFunction = IRP_MJ_SCSI;
irpStack->Parameters.Scsi.Srb = srb;

irp->UserIosb = pIoStatus;
irp->UserEvent = &WaitEvent;

srb->Length = sizeof(SCSI_REQUEST_BLOCK);
srb->OriginalRequest = irp;
srb->SrbFlags |= SRB_FLAGS_BYPASS_LOCKED_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE;

srb->Function = SRB_FUNCTION_LOCK_QUEUE;

srb->SenseInfoBuffer = senseInfoBuffer;
srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;

srb->ScsiStatus = srb->SrbStatus = 0;
srb->NextSrb = 0;

IoSetCompletionRoutine(irp,
FilterLockQueueCompletion,
Srb,
TRUE,
TRUE,
TRUE);

status = IoCallDriver(deviceExtension->TargetDeviceObject, irp);

//
// Wait for the completion routine to be called
//
if (status == STATUS_PENDING) {

status = KeWaitForSingleObject(&WaitEvent,
Executive,
KernelMode,
FALSE,
NULL);

status = pIoStatus->Status;
}

//
// Verify that our CompleteRequest was called
//
ASSERT(KeReadStateEvent(&WaitEvent) || !NT_SUCCESS(irp->IoStatus.Status));

ASSERT(SRB_STATUS(srb->SrbStatus) != SRB_STATUS_PENDING);
ASSERT(status != STATUS_PENDING);
ASSERT(!(srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN));

//
// Free the srb
//
ExFreePool(senseInfoBuffer);
ExFreePool(srb);

return status;
}

NTSTATUS FilterLockQueueCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
{
ULONG srbStatus;
//NTSTATUS status;

PSCSI_REQUEST_BLOCK srb;
PIO_STACK_LOCATION irpStack;
PSENSE_DATA senseInfoBuffer;

UCHAR sensecode;

srb = (PSCSI_REQUEST_BLOCK)Context;

irpStack = IoGetCurrentIrpStackLocation(Irp);

/* srbStatus in here is always SRB_STATUS_PENDING */
srbStatus = SRB_STATUS(srb->SrbStatus);

senseInfoBuffer = srb->SenseInfoBuffer;

sensecode = senseInfoBuffer->SenseKey & 0xf;

*(Irp->UserIosb) = Irp->IoStatus;

KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE);

//
// Free the the IRP.
//
IoFreeIrp(Irp);

return STATUS_MORE_PROCESSING_REQUIRED;
}

Finally, I have the SRB sent to lower driver stack and get the SRB status back. But the status is SRB_STATUS_INVALID_REQUEST. How can I verify if there are some errors while my fiilter driver preparing SRB or lower port driver stack doesn’t support SRB_FUNCTION_LOCK_QUEUE ? Based on WDK document "Only the SRB Length, Function, SrbFlags, and OriginalRequest members are valid. When the queue is locked, only requests with SrbFlags ORed with SRB_FLAGS_BYPASS_LOCKED_QUEUE will be processed. SCSI miniport drivers do not process SRB_FUNCTION_LOCK_QUEUE requests. " My understanding is SRB_FUNCTION_LOCK_QUEUE is handled by port driver. But how to debug this issue when port driver return SRB_STATUS_INVALID_REQUEST?

*********************************************************************
Hi,
I have a lower storage filter driver sitting right below disk driver.
In my filter driver, I build IRP to send SRB_FUNCTION_LOCK_QUEUE to lock the
storage driver internal queue. However, I always get status success on IRP but
SRB_STATUS_PENDING on SRB block. I look at the WDK document. It seems that if
several times retry can be applyed if SRB return failed. But SRB_STATUS_PENDING
is not failed status. I can’t find any info about what driver should do in that
case. I even can not verify if the requirement is really success. Do I have
something wrong? I put the code in here. Any help is appreciated.

NTSTATUS FilterLockQueue(IN PDEVICE_OBJECT DeviceObject, OUT PIO_STATUS_BLOCK
pIoStatus)
{
PIRP irp;
PVOID senseInfoBuffer;
PSCSI_REQUEST_BLOCK srb;

PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION deviceExtension;

KEVENT WaitEvent;
NTSTATUS status;

deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;

srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE);
if (srb == NULL)
return STATUS_INSUFFICIENT_RESOURCES;

RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);

senseInfoBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
SENSE_BUFFER_SIZE);

if (senseInfoBuffer == NULL) {

ExFreePool(srb);

return STATUS_INSUFFICIENT_RESOURCES;
}

irp = IoAllocateIrp((CCHAR)(deviceExtension->TargetDeviceObject->StackSize +
1), FALSE);

if (irp == NULL) {

ExFreePool(senseInfoBuffer);
ExFreePool(srb);

return STATUS_INSUFFICIENT_RESOURCES;
}

//
// Get next stack location.
//
irpStack = IoGetNextIrpStackLocation(irp);

KeInitializeEvent(&WaitEvent, NotificationEvent, FALSE);

//
// Set up SRB for execute scsi request. Save SRB address in next stack
// for the port driver.
//

irpStack->MajorFunction = IRP_MJ_SCSI;
irpStack->Parameters.Scsi.Srb = srb;

irp->UserIosb = pIoStatus;
irp->UserEvent = &WaitEvent;

srb->Length = sizeof(SCSI_REQUEST_BLOCK);
srb->OriginalRequest = irp;
srb->SrbFlags |= SRB_FLAGS_BYPASS_LOCKED_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE;

srb->Function = SRB_FUNCTION_LOCK_QUEUE;

srb->SenseInfoBuffer = senseInfoBuffer;
srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;

srb->ScsiStatus = srb->SrbStatus = 0;
srb->NextSrb = 0;

IoSetCompletionRoutine(irp,
FilterLockQueueCompletion,
Srb,
TRUE,
TRUE,
TRUE);

status = IoCallDriver(deviceExtension->TargetDeviceObject, irp);

//
// Wait for the completion routine to be called
//
if (status == STATUS_PENDING) {

status = KeWaitForSingleObject(&WaitEvent,
Executive,
KernelMode,
FALSE,
NULL);

status = pIoStatus->Status;
}

//
// Verify that our CompleteRequest was called
//
ASSERT(KeReadStateEvent(&WaitEvent) || !NT_SUCCESS(irp->IoStatus.Status));

ASSERT(SRB_STATUS(srb->SrbStatus) != SRB_STATUS_PENDING);
ASSERT(status != STATUS_PENDING);
ASSERT(!(srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN));

//
// Free the srb
//
ExFreePool(senseInfoBuffer);
ExFreePool(srb);

return status;
}

NTSTATUS FilterLockQueueCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp,
IN PVOID Context)
{
ULONG srbStatus;
//NTSTATUS status;

PSCSI_REQUEST_BLOCK srb;
PIO_STACK_LOCATION irpStack;
PSENSE_DATA senseInfoBuffer;

UCHAR sensecode;

srb = (PSCSI_REQUEST_BLOCK)Context;

irpStack = IoGetCurrentIrpStackLocation(Irp);

/* srbStatus in here is always SRB_STATUS_PENDING */
srbStatus = SRB_STATUS(srb->SrbStatus);

senseInfoBuffer = srb->SenseInfoBuffer;

sensecode = senseInfoBuffer->SenseKey & 0xf;

*(Irp->UserIosb) = Irp->IoStatus;

KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE);

//
// Free the the IRP.
//
IoFreeIrp(Irp);

return STATUS_MORE_PROCESSING_REQUIRED;
}