This is an excellent question that is essentially asking for help with
asynchronous operations as a whole. Allow me to try to explain what I
understand you are doing, and then provide a solution (which others will
undoubtably update ;)):
Tape Device Stack:
TAPE.SYS
YourFilter.SYS
PortDriver.SYS
Discussing now YourFilter only:
- When receive READ6, set completion routine Read6Complete().
When Read6Complete() occurs:
2.1) This is where you are asking about how to not use KeWait()
2.2) Prepare the irp for the decryption routine.
2.3) Setup a structure with:
2.3.1) your device object(*)
2.3.2) the original READ6 irp pointer
2.3.3) any context you need for the new decryption irp
2.4) Set completion routine context to this structure.
2.5) Set completion routine for decryption irp to
DecryptRead6Complete().
2.6) Set STATUS_PENDING and such appropriately if required – IMPORTANT.
2.7) Send irp to decryption routine and return STATUS_PENDING
unconditionally.
When DecryptRead6Complete() occurs:
3.1) Extract your device object and original irp pointer
3.3) Copy any data as required.
3.3) Cleanup irp you sent to decryption driver
3.3.1) Free the decryption irp or store for later use.
3.3.2) Free any resources related to decryption irp or store for later
use.
3.4) Call IoCompleteRequest() on the original irp
3.5) Return STATUS_PENDING, since you don’t want decryption irp
completed.
Note that you return STATUS_PENDING in both completion routines. That’s
OK, as you end up calling IoCompleteRequest() again in 3.4, which gets
the original irp to complete. While this method of asynchronous
operations is somewhat more complex that a synchronous IO model, it
allows you significantly more flexibility in how you process IO.
Hth,
.
(*) If you allocate the irp, your completion routine won’t be given a
valid device object. It’s weird, but it’s because the completion
routine’s device object comes from the *previous* irpstack (or, to look
at it another way, the completion routine is set in the *next*
irpstack). So, because you don’t have an irpstack, your devobj is set
to NULL in the completion routine. Fun, eh?
(**) I only get the digest version of this list once a day, so expect my
responses to be somewhat delayed.
-----Original Message-----
From: Michael [mailto:xxxxx@yahoo.ca]
Sent: Thursday, September 04, 2003 8:42 PM
Subject: Completion Routine at DISPATCH_LEVEL
Hi, everyone, I have a question about my SCSI filter driver. My filter
is
a lower filter of tape drive. In this filter I intercept the
SCSIOP_READ6
and SCSIOP_WRITE6 operations for encryption/decryption. In my current
IRP’s completion routine I need to build a new IRP and send it to
another
driver for decryption. I also set a completion routine for this new IRP.
That driver for decryption uses some asynchronous operation. So the
IoCallDriver() routine simply returns STATUS_PENDING. The problem
happened
when the current IRP completion routine is running at DISPATCH_LEVEL.
Since it is at DISPATCH_LEVEL, so I couldn’t use KeWaitForSingleObject()
to wait for the new IRP’s completion routine to be finished. In that way
my filter driver don’t know when this new IRP will be completed. In
other
words I don’t know at what time my data will be decrypted. What can I
do?
How can I handle the current IRP once the new IRP returns
STATUS_PENDING?
Simple return STATUS_MORE_PROCESSING_REQUIRED?
Any help or idea will be appreciated. Thanks
Michael