SCSI Filter Driver

Hi All,

I’m looking at developing a simple SCSI filter driver for analysing the usage of certain inquiry commands sent to SCSI devices. Ultimately I’ll be aiming to output a count of the number of commands with certain CDB’s that the driver sees. I’ve written a simple filter driver (upper class filter sitting on the SCSIAdapter stack) that just prints debug messages when it sees certain IRP’s, but I’ve got the problem of not being able to recieve IRP_MJ_SCSI. From what I’ve read already on this forum, it looks like I need to incorporate some sort of virtual device to get the filter to see all the SCSI traffic. I’ve also run OSR’s DeviceTree program which tells me that for BusHound, under the “\Driver\bhound6” there is a “\Device\BusHound” device.

What I would like to know is: (1) Whether or not I’m going down the right route with this? Is making a virtual device the best way to achieve this? And (2) If I am; how to I go about making a simple device (like \Device\BusHound)?

Any help would be greatly appreciated.

Thanks,

Ben

SRBs (IRP_MJ_SCSI) are directed at the PDOs enumerated by the adapter
device, not at the adapter device FDO that you are filtering. You either
need a bus filter driver for the adapter device or a lower FDO filter driver
for each of the various classes of enumerated devices (disk, tape, cdrom
etc.) that you are interested in. Also be aware that some software on the
CDROM side insists on misbehaving and not respecting devnode stacks at all
and will defeat standard pnp filter drivers of any sort.

On Mon, Aug 4, 2008 at 12:06 PM, <ben.simpson> wrote:

> Hi All,
>
> I’m looking at developing a simple SCSI filter driver for analysing the
> usage of certain inquiry commands sent to SCSI devices. Ultimately I’ll be
> aiming to output a count of the number of commands with certain CDB’s that
> the driver sees. I’ve written a simple filter driver (upper class filter
> sitting on the SCSIAdapter stack) that just prints debug messages when it
> sees certain IRP’s, but I’ve got the problem of not being able to recieve
> IRP_MJ_SCSI. From what I’ve read already on this forum, it looks like I need
> to incorporate some sort of virtual device to get the filter to see all the
> SCSI traffic. I’ve also run OSR’s DeviceTree program which tells me that for
> BusHound, under the “\Driver\bhound6” there is a “\Device\BusHound” device.
>
> What I would like to know is: (1) Whether or not I’m going down the right
> route with this? Is making a virtual device the best way to achieve this?
> And (2) If I am; how to I go about making a simple device (like
> \Device\BusHound)?
>
> Any help would be greatly appreciated.
>
> Thanks,
>
> Ben
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>


Mark Roddy</ben.simpson>

To see all SCSI traffic you need to implement hook-based driver. Layered
immediately on the top of SCSIPORT or monolithic storage port drivers.
Not blessed way by Microsoft but the only one confirmed working. Classic
approach will let you see only “friendly” applications I/O.

Regards,
Anton Kolomyeytsev

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of ben.simpson@hp.com
Sent: Monday, August 04, 2008 7:07 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] SCSI Filter Driver

Hi All,

I’m looking at developing a simple SCSI filter driver for analysing the
usage of certain inquiry commands sent to SCSI devices. Ultimately I’ll be
aiming to output a count of the number of commands with certain CDB’s that
the driver sees. I’ve written a simple filter driver (upper class filter
sitting on the SCSIAdapter stack) that just prints debug messages when it
sees certain IRP’s, but I’ve got the problem of not being able to recieve
IRP_MJ_SCSI. From what I’ve read already on this forum, it looks like I need
to incorporate some sort of virtual device to get the filter to see all the
SCSI traffic. I’ve also run OSR’s DeviceTree program which tells me that for
BusHound, under the “\Driver\bhound6” there is a “\Device\BusHound” device.

What I would like to know is: (1) Whether or not I’m going down the right
route with this? Is making a virtual device the best way to achieve this?
And (2) If I am; how to I go about making a simple device (like
\Device\BusHound)?

Any help would be greatly appreciated.

Thanks,

Ben


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Thanks for the responses. What exactly do you mean by ‘hook-based driver’? I’ve done some searching around for info on this, but I’ve not been able to find anything helpful. If anyone has some relative documentation or example code I could look at that’d be great.

Many thanks,

Ben

Quoting ben.simpson@hp.com:

Thanks for the responses. What exactly do you mean by ‘hook-based driver’?
I’ve done some searching around for info on this, but I’ve not been able to
find anything helpful. If anyone has some relative documentation or example
code I could look at that’d be great.

Many thanks,

Ben

Hooking is bad practice so you are not likely to find much information on it.

If you have any PDO on the port driver you can easily hook.

old = pdo->DriverObject->MajorFunction[IRP_MJ_SCSI];
pdo->DriverObject->MajorFunction[IRP_MJ_SCSI] = MyFilter;

in MyFilter call old(DeviceObject, Irp)

All the caveats of hooking apply. Prefast will hate it.
Very bad practice, not allowed in my company.


Visit Pipex Business: The homepage for UK Small Businesses

Go to http://www.pipex.co.uk/business-services

> Thanks for the responses. What exactly do you mean by ‘hook-based driver’?

Some CD burning tools do not use IoCallDriver to deliver the request to the
storage port, instead using direct calls to the dispatch entries of the storage
port’s driver object.

To monitor such tools, hooking of these dispatch entries is the only chance.


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

> old = pdo->DriverObject->MajorFunction[IRP_MJ_SCSI];

pdo->DriverObject->MajorFunction[IRP_MJ_SCSI] = MyFilter;

I would use InterlockedExchangePointer for this :slight_smile:


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

Actually prefast is agnostic to what you are doing as long as your code is
not brain dead and verifier doesn’t test for it. The checked version of
scsiport will assert. Probably storport has the same guard in it as well.

Unless the OP really cares about capturing CDROM SRBs for all third party
CD/DVD stuff he does not need to hook anything. If, for example, he is
actually focusing on disk IO, bus or class filters will be fine.

On Tue, Aug 5, 2008 at 6:54 AM, wrote:

> Quoting ben.simpson@hp.com:
>
> > Thanks for the responses. What exactly do you mean by ‘hook-based
> driver’?
> > I’ve done some searching around for info on this, but I’ve not been able
> to
> > find anything helpful. If anyone has some relative documentation or
> example
> > code I could look at that’d be great.
> >
> > Many thanks,
> >
> > Ben
> >
> Hooking is bad practice so you are not likely to find much information on
> it.
>
> If you have any PDO on the port driver you can easily hook.
>
> old = pdo->DriverObject->MajorFunction[IRP_MJ_SCSI];
> pdo->DriverObject->MajorFunction[IRP_MJ_SCSI] = MyFilter;
>
> in MyFilter call old(DeviceObject, Irp)
>
> All the caveats of hooking apply. Prefast will hate it.
> Very bad practice, not allowed in my company.
>
>
>
>
> -------------------------------------------------
> Visit Pipex Business: The homepage for UK Small Businesses
>
> Go to http://www.pipex.co.uk/business-services
>
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>


Mark Roddy

Thanks again. Just to clarify, I’m not looking to do anything with CDROM SRB’s, I’m only looking at sequential access devices. The code I’m trying to use is:

DriverObject->MajorFunction[IRP_MJ_SCSI] = Scsifilter;

NTSTATUS Scsifilter(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);

DebugPrint(“Scsifilter: IRP_MJ_SCSI\n”);

if ((currentIrpStack->Parameters.Scsi.Srb->Cdb[0] == SCSIOP_WRITE) || (currentIrpStack->Parameters.Scsi.Srb->Cdb[0] == SCSIOP_READ))
{
//Just say we had a read or write command
DebugPrint(“Scsifilter: READ OR WRITE COMMAND\n”));
}

I guess because I’m not hooking anything (as discussed already here), I’m not seeing any IRP_MJ_SCSI’s. If I use Ian’s method of hooking, will that enable me to catch the IRP_MJ_SCSI’s in this way?

Thanks,

Ben

Quoting ben.simpson@hp.com:

I guess because I’m not hooking anything (as discussed already here), I’m not
seeing any IRP_MJ_SCSI’s. If I use Ian’s method of hooking, will that enable
me to catch the IRP_MJ_SCSI’s in this way?

Thanks,

Ben

Do not hook. The trick with filter drivers is where you install them. If you install your filter as a lower class
or device filter you will see the SCSIOPs. An upper filter for the Scsi/Storport just filters the scsi control
device which is not what you want.


Visit Pipex Business: The homepage for UK Small Businesses

Go to http://www.pipex.co.uk/business-services

No - you do not need to hook. As usual we have gone off on a tangent
here. You need to either make your filter a lower filter for the class
FDOs (disk for example), which is fully documented and supported, or
make your current hba fdo filter a bus filter driver (not documented but
sort of supported.) I’d go with the lower disk device class FDO filter.
See the disk perf sample driver.

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
ben.simpson@hp.com
Sent: Tuesday, August 05, 2008 10:03 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] SCSI Filter Driver

Thanks again. Just to clarify, I’m not looking to do anything with CDROM
SRB’s, I’m only looking at sequential access devices. The code I’m
trying to use is:

DriverObject->MajorFunction[IRP_MJ_SCSI] = Scsifilter;

NTSTATUS Scsifilter(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PDEVICE_EXTENSION deviceExtension =
DeviceObject->DeviceExtension;
PIO_STACK_LOCATION currentIrpStack =
IoGetCurrentIrpStackLocation(Irp);

DebugPrint(“Scsifilter: IRP_MJ_SCSI\n”);

if ((currentIrpStack->Parameters.Scsi.Srb->Cdb[0] ==
SCSIOP_WRITE) || (currentIrpStack->Parameters.Scsi.Srb->Cdb[0] ==
SCSIOP_READ))
{
//Just say we had a read or write command
DebugPrint(“Scsifilter: READ OR WRITE COMMAND\n”));
}

I guess because I’m not hooking anything (as discussed already here),
I’m not seeing any IRP_MJ_SCSI’s. If I use Ian’s method of hooking, will
that enable me to catch the IRP_MJ_SCSI’s in this way?

Thanks,

Ben


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Thanks for the help. I’ve got the filter sitting in the right place now, and I’m successfully capturing IRP_MJ_SCSI’s, however I’ve now got the problem that if I try to look at the CDB’s within the SRB’s, I get the BSOD.

The code I’m using is similar to what I posted already, just tweaked a bit:

NTSTATUS Scsifilter(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);

if (currentIrpStack->Parameters.Scsi.Srb->Cdb[0] == SCSIOP_TEST_UNIT_READY)
{
DebugPrint((69, “Scsifilter: SCSI TEST UNIT READY\n”));
} else {
DebugPrint((69, “Scsifilter: SCSI\n”));
}

AFAIK, this is the right way to look at the CDB’s, but as I say it’s just giving me a BSOD. Any ideas anyone?

Thanks,

Ben

Quoting ben.simpson@hp.com:

Thanks for the help. I’ve got the filter sitting in the right place now, and
I’m successfully capturing IRP_MJ_SCSI’s, however I’ve now got the problem
that if I try to look at the CDB’s within the SRB’s, I get the BSOD.

The code I’m using is similar to what I posted already, just tweaked a bit:

NTSTATUS Scsifilter(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION currentIrpStack =
IoGetCurrentIrpStackLocation(Irp);

if (currentIrpStack->Parameters.Scsi.Srb->Cdb[0] == SCSIOP_TEST_UNIT_READY)
{
DebugPrint((69, “Scsifilter: SCSI TEST UNIT READY\n”));
} else {
DebugPrint((69, “Scsifilter: SCSI\n”));
}

I can not see why that would happen. You may need to lock data buffers to look at them but the cdb should not need
locking.

The only other thing I can see is you should be checking Srb->Function == SRB_FUNCTION_EXECUTE_SCSI before you
consider the Cdb to valid. Again I can not see why that would fault it is still there, just meaningless for the
other functions. I have never seen short Srbs.

I assume you are passing the Irp down in the usual way.


Visit Pipex Business: The homepage for UK Small Businesses

Go to http://www.pipex.co.uk/business-services

Yea, I’m passing the SRB down as usual. The line you suggested adding seems to work, I can see SCSIOP_TEST_UNIT_READY’s being issued every second by the Windows RSM service, but when I print out the CDB value using the following code, I get an odd number come out…

if(currentIrpStack->Parameters.Scsi.Srb->Function == SRB_FUNCTION_EXECUTE_SCSI)
{
if (currentIrpStack->Parameters.Scsi.Srb->Cdb[0] == SCSIOP_TEST_UNIT_READY)
{
DebugPrint((69, “Scsifilter: SCSI TEST UNIT READY (%d)\n”,currentIrpStack->Parameters.Scsi.Srb->Cdb[0]));
}
}

That prints out the debug message: “Scsifilter: SCSI TEST UNIT READY (-2141942708)”. This should surely be printing out “SCSI TEST UNIT READY (0)” or something similar?

Ben

Maybe, It is issue in the DebugPrint function,
You can fix it to the follow:
if(currentIrpStack->Parameters.Scsi.Srb->Function == SRB_FUNCTION_EXECUTE_SCSI)
{
UCHAR Cdb;

Cdb = currentIrpStack->Parameters.Scsi.Srb->Cdb[0];
if (Cdb == SCSIOP_TEST_UNIT_READY)
{
DebugPrint((69, “Scsifilter: SCSI TEST UNIT READY
(%d)\n”,Cdb));
}
}
I sure it should be correct,

Yea, sorry I found a bug in my DebugPrint func :slight_smile: It’s all working really well now, I’m making good progress with it. I’ve got the filter sitting as a lower class filter on the TapeDrive class, and I’m able to see most traffic, but I’m not able to see SCSI passthrough commands. Is this just a matter of sitting my driver elsewhere in the stack?

Thanks,

Ben

Quoting ben.simpson@hp.com:

but I’m not able to see SCSI passthrough commands. Is this just a matter of
sitting my driver elsewhere in the stack?

No. You are in the right location.

SCSI_PASS_THROUGH (SPT)comes down the IRP_MJ_DEVICE_CONTROL path. So you will not
see it when you look at IRP_MJ_INTERNAL_DEVICE_CONTROL (IRP_MJ_SCSI).

When you process SPT there are 64bit issues you get a slightly different structure
from 32 bit clients.


Visit Pipex Business: The homepage for UK Small Businesses

Go to http://www.pipex.co.uk/business-services

SPT can also be sent to the adapter FDO, which you wouldn’t see from a lower
disk/tape filter (which I think is where the OP is now sitting).

-scott


Scott Noone
Software Engineer
OSR Open Systems Resources, Inc.
http://www.osronline.com

wrote in message news:xxxxx@ntdev…
> Quoting ben.simpson@hp.com:
>
>
>> but I’m not able to see SCSI passthrough commands. Is this just a matter
>> of
>> sitting my driver elsewhere in the stack?
>>
>
> No. You are in the right location.
>
> SCSI_PASS_THROUGH (SPT)comes down the IRP_MJ_DEVICE_CONTROL path. So you
> will not
> see it when you look at IRP_MJ_INTERNAL_DEVICE_CONTROL (IRP_MJ_SCSI).
>
> When you process SPT there are 64bit issues you get a slightly different
> structure
> from 32 bit clients.
>
>
> -------------------------------------------------
> Visit Pipex Business: The homepage for UK Small Businesses
>
> Go to http://www.pipex.co.uk/business-services
>
>

Quoting Scott Noone :

> SPT can also be sent to the adapter FDO, which you wouldn’t see from a lower
>
> disk/tape filter (which I think is where the OP is now sitting).
>
> -scott

Agreed. He needs to be both Lower Tape Class and Upper Port (where I think he started).

-------------------------------------------------
Visit Pipex Business: The homepage for UK Small Businesses

Go to http://www.pipex.co.uk/business-services

Yea, I can see the SCSI passthrough’s now, thanks :slight_smile: I notice there’s no SCSI_PASS_THROUGH within the PIO_STACK_LOCATION->Parameters, is there another function I need to call for getting the SCSI_PASS_THROUGH from the IRP?

Ben