WDF Disk Lower Filter Driver, catching SRB READs

As an experiment I’ve been working on learning the KMDF programming model, as such please forgive my ignorance.

What I’ve got is a lower filter on Disk class that has been setup to “catch” EvtIoInternalDeviceControl or IRP_MJ_INTERNAL_DEVICE_CONTROL irps.

Essentially in my “Read” function I identify SCSI CDB 0x08 (READ6) and 0x28 (READ10) SCSI commands and send them to my Completion Routine, all others I forward and forget.

Now when it comes to the Completion routine, how do I get access to the buffer/length? I had tried the following:

wdmReadIrp = WdfRequestWdmGetIrp(Request);

wdmSCSILoc = IoGetCurrentIrpStackLocation(wdmReadIrp);

Length = wdmSCSILoc->Parameters.Scsi.Srb->DataTransferLength; // Appears to be accurate

Buffer = wdmSCSILoc->Parameters.Scsi.Srb->DataBuffer; //Problems if I access this…

My first thought was to use WdfRequestRetrieveOutputBuffer, but I found it to be unsuccessful and then located this posting…

let me clarify how/when WdfRequestRetrieveInput/OutputBuffer will work. It

will work when the current stack location describes the length of the
buffer(s). So that means the following major codes always work

IRP_MJ_READ
IRP_MJ_WRITE
IRP_MJ_DEVICE_CONTROL

IRP_MN_INTERNAL_DEVICE_CONTROL is problematic since many different types
of buffers come in with this IRP and not very many of them have an
associated length that is stored in
Parameters.DeviceIoControl.OutputBufferLength/InputBufferLength. In these
cases, you just have to get the request parameters and use the pointer

I imagine I’m pretty close to having this knocked, but can’t seem to figure out where to go next.

How do I go from “Parameters.Scsi.Srb->DataBuffer” and actually get a data buffer I can work with?

Thanks!

M

> I imagine I’m pretty close to having this knocked, but can’t seem to

figure out where to go next.

How do I go from “Parameters.Scsi.Srb->DataBuffer” and actually get a data
buffer I can work with?

The problem with Srb->DataBuffer is that it might be a user mode virtual
address, it’s really not useful at this level other than being a cookie
value for the DMA abstraction.

However the IRPs submitted will also have an MDL associated with them, so
you can call MmGetSystemAddressForMdlSafe on Irp->MdlAddress and get a
non-pageable system address that you can use.

Also, in case you weren’t already aware the disk class driver source code is
available in the WDK, so you can see how the SCSI requests are built (grep
SetupReadWriteTransferPacket). This also allows you to build your own
version of the driver and step through if necessary.

-scott


Scott Noone
Consulting Associate
OSR Open Systems Resources, Inc.
http://www.osronline.com

wrote in message news:xxxxx@ntdev…
> As an experiment I’ve been working on learning the KMDF programming model,
> as such please forgive my ignorance.
>
> What I’ve got is a lower filter on Disk class that has been setup to
> “catch” EvtIoInternalDeviceControl or IRP_MJ_INTERNAL_DEVICE_CONTROL irps.
>
> Essentially in my “Read” function I identify SCSI CDB 0x08 (READ6) and
> 0x28 (READ10) SCSI commands and send them to my Completion Routine, all
> others I forward and forget.
>
> Now when it comes to the Completion routine, how do I get access to the
> buffer/length? I had tried the following:
>
> wdmReadIrp = WdfRequestWdmGetIrp(Request);
>
> wdmSCSILoc = IoGetCurrentIrpStackLocation(wdmReadIrp);
>
> Length = wdmSCSILoc->Parameters.Scsi.Srb->DataTransferLength; //
> Appears to be accurate
>
> Buffer = wdmSCSILoc->Parameters.Scsi.Srb->DataBuffer; //Problems if I
> access this…
>
> My first thought was to use WdfRequestRetrieveOutputBuffer, but I found it
> to be unsuccessful and then located this posting…
>
> let me clarify how/when WdfRequestRetrieveInput/OutputBuffer will work. It
>> will work when the current stack location describes the length of the
>> buffer(s). So that means the following major codes always work
>>
>> IRP_MJ_READ
>> IRP_MJ_WRITE
>> IRP_MJ_DEVICE_CONTROL
>>
>> IRP_MN_INTERNAL_DEVICE_CONTROL is problematic since many different types
>> of buffers come in with this IRP and not very many of them have an
>> associated length that is stored in
>> Parameters.DeviceIoControl.OutputBufferLength/InputBufferLength. In these
>> cases, you just have to get the request parameters and use the pointer
>
> I imagine I’m pretty close to having this knocked, but can’t seem to
> figure out where to go next.
>
> How do I go from “Parameters.Scsi.Srb->DataBuffer” and actually get a data
> buffer I can work with?
>
> Thanks!
>
> M
>
>
>

You could compare address of the DataBuffer in EvtIoInternalDeviceControl and Completion routine. Just in case to be sure you work with the same address.
You also could get Srb in KMDF by using another way

WDF_REQUEST_PARAMETERS_INIT(&params);
WdfRequestGetParameters( Request, &params );
Srb = (PSCSI_REQUEST_BLOCK)params.Parameters.Others.Arg1;

Igor Sharovar

> You could compare address of the DataBuffer in EvtIoInternalDeviceControl

and Completion routine. Just in case to be sure you >work with the same
address.

From a lower disk filter Srb->DataBuffer is the result of
MmGetMdlVirtualAddress (see class.c), so he shouldn’t be using this. He
needs to grab the MDL and get a system address for it.

-scott


Scott Noone
Consulting Associate
OSR Open Systems Resources, Inc.
http://www.osronline.com

wrote in message news:xxxxx@ntdev…
> You could compare address of the DataBuffer in EvtIoInternalDeviceControl
> and Completion routine. Just in case to be sure you work with the same
> address.
> You also could get Srb in KMDF by using another way
>
> WDF_REQUEST_PARAMETERS_INIT(&params);
> WdfRequestGetParameters( Request, &params );
> Srb = (PSCSI_REQUEST_BLOCK)params.Parameters.Others.Arg1;
>
>
> Igor Sharovar
>