Contradiction in descriptions of WdfRequestChangeTarget

The WDK documentation for WdfRequestChangeTarget says

“Your driver should call the WdfRequestChangeTarget method before it calls WdfRequestSend, if the driver sends a single I/O request to multiple I/O targets.”

Whereas the section “Sending Requests Asynchronously” says (I’ve capitalised the contradictory phrase).


“Some drivers might send a single I/O request to multiple devices, and thus to multiple I/O targets, by calling WdfRequestSend more than once for each request. These drivers must call WdfRequestChangeTarget before each call to WdfRequestSend AFTER THE FIRST ONE to verify that the request can be sent to the next I/O target.”

The first extract says before before each call, the second says before each call after the first. Which is right?

My guess would be I have to call it before each call if I intend to send a single request to multiple devices: I can’t see how the framework would handle things sensibly if I followed the advice in the second extract. For instance, if I use WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET, the first request might have been completed before I get round to sending it to a second device.

Which leads me to another question. Is the usage I’ve just mentioned supported? I.e. can I send a request to several devices using the SEND_AND_FORGET option? The discussion in Forwarding I/O requests implies that it is.


"Sometimes, a driver must send the same request to several I/O targets, typically because the driver must send a single command to all of its devices. Before sending a request to an I/O target, the driver can call WdfRequestChangeTarget to verify that the I/O target is accessible.

The driver must eventually complete every request that it forwards to an I/O target, unless it sets the WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET flag when calling WdfRequestSend."

Don

First off, you cannot have the same request pending in multiple targets, a request can only be active in one target at a time and you cannot resend it until it completes back to you. By this logic, you should not be using send and forget for this pattern. Send and forget is typically for a scenario where you receive a request and just want to fwd it down a stack. Additionally, you will have to WdfRequestReuse + reformat the request every time you resend it to another target (or the same one for that matter).

WdfRequestChangeTarget() is an API geared towards forward progress and initialization up front. Every request has an underlying PIRP. Each PIRP has a fixed number of stack locations. Each i/o target specifies a minimum number of stack locatoins it requires (DeviceObject->StackSize). To be able to send a PIRP to the target, the PIRP must have at least the number of stack locations as specifed by the I/O target. For WDFREQUESTs you create (vs ones presented by an i/o queue), KMDF will try to reallocate the PIRP if it is not big enough. It will do this reallocation as a part of WdfRequestChangeTarget, WdfIoTargetSendXxxSynchronously, or WdfIoTargetFormatForXxx calls. This means that if you are just sending the same request to multiple targets in order, you can just format the request passing the intended target and then send (and then repeat) without having to call WdfRequestChangeTarget.

d

> First off, you cannot have the same request pending in

multiple targets, a request can only be active in one target
at a time and you cannot resend it until it completes back to
you. By this logic, you should not be using send and forget
for this pattern. Send and forget is typically for a
scenario where you receive a request and just want to fwd it
down a stack. Additionally, you will have to WdfRequestReuse

  • reformat the request every time you resend it to another
    target (or the same one for that matter).

Thanks for this clarification. I did wonder exactly how the framework
would implement what I was proposing.

I still think the section I quoted in “Forwarding I/O requests” in my
previous post could mislead people into thinking that multiple requests
with send_and_forget was supported. So I would suggest that your (much more
specific) advice be included somewhere in that section.

Regards

Don