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;
}