User-Mode IOCTLs to Storport Miniport driver

Hello all,

I am in the process of developing a Storport Miniport driver to interface with custom hardware and a usermode application. I need to call custom IOCTLs in the driver from my usermode application. I’m running Win7x64.
Before I had any hardware ready, I created a virtual storport miniport to get usermode communication working the way I wanted to. I am pretty much just locking usermode pages into memory in kernel-mode.
In my virtual storport miniport’s DriverEntry, I was able to define hwInitData.HwProcessServiceRequest =ProcessServiceRequest; which looked something like this in the driver:
ULONG ProcessServiceRequest( __in PVOID PDevExt, __in PVOID PIrp)
{
PIRP pIrp = (PIRP) PIrp;
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(pIrp);
if(irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL)
{
//Struct that has at minimum an IoControlCode defined as first member
PCOMMAND_IN command = (PCOMMAND_IN) pIrp->AssociatedIrp.SystemBuffer;
IoControlCode which kicks off IOCTL-specific logic>
}

}

and from Usermode I would set up a structure conforming to COMMAND_IN above and call this through:
DeviceIoControl(SPDriverHandle,IOCTL_MINIPORT_PROCESS_SERVICE_IRP, &toPass,sizeof(TESTSTRUCT),&toPass,sizeof(TESTSTRUCT),&bytesReturned,NULL);

This would enter right in to the HwProcessServiceRequest function in the driver and execute whatever code I had defined there. It was beautiful, worked flawlessly, and life was good.

You might already know what is coming, for in my naivete I expected to be able to port this fairly easily to a Storport Miniport that talks to actual hardware. Alas, I am not an experienced driver developer, and I didn’t realize that HwProcessServiceRequest doesn’t exist for a physical-device Storport Miniport. A rework was in order.

It seemed that the best way to communicate through IOCTL to my driver from usermode applications was through using a STORAGE_REQUEST_BLOCK instance with the .DataBuffer member as a pointer to the SrbIOCTL I want to send, with the function field defined as SRB_FUNCTION_IO_CONTROL and appropriate lengths, etc.
Then I will supposedly pass it to the driver with:
DeviceIoControl(SPDriverHandle, IOCTL_SCSI_MINIPORT, &StorReqBlockToSend……);
And I expected it to come out one of these functions I defined in the driver:
hwInitData.HwStartIo = StartIo;
hwInitData.HwBuildIo = BuildIo;

Neither of these functions are entered. Stranger yet is that the DeviceIoControl function returns 0 (Success, supposedly).

Here is my usermode application code. In the comments and unnecessary code are a few other failed attempts that yielded identical results. I used http://msdn.microsoft.com/en-us/library/windows/hardware/hh451474(v=vs.85).aspx (specifically the part regarding SRB_FUNCTION_IO_CONTROL) and other articles (now lost) as references

#define TEST_STORPORT_DRIVER 0xE000
#define IOCTL_TEST CTL_CODE(TEST_STORPORT_DRIVER, 0x8FF, METHOD_NEITHER, FILE_ANY_ACCESS)
//#define IOCTL_TEST CTL_CODE(FILE_DEVICE_MASS_STORAGE, 0x8FF, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)

int _tmain(int argc, _TCHAR* argv)
{
HANDLE SPDriverHandle;

SPDriverHandle = CreateFile(L"\\.\Scsi2:", // Name of the NT device to open
GENERIC_READ|GENERIC_WRITE, // Access rights requested
0, // Share access - NONE
0, // Security attributes - not used!
OPEN_EXISTING, // Device must exist to open it.
FILE_FLAG_OVERLAPPED, // Open for overlapped I/O
0); // extended attributes - not used!

if(SPDriverHandle == INVALID_HANDLE_VALUE)
{
DWORD error = GetLastError();
printf(“error:%d.\n”,error);
}
else
{
STORAGE_REQUEST_BLOCK toSend;
SRB_IO_CONTROL Srbioctl;
DWORD bytesReturned = 0;
long retCode = 0;
DWORD error = GetLastError();

printf(“Did that just work? Code: %i\n”, error);

toSend.SrbFunction = 0x02; //Equal to SRB_FUNCTION_IO_CONTROL;
toSend.DataBuffer = &Srbioctl;
toSend.DataTransferLength = sizeof(SRB_IO_CONTROL);
toSend.SrbFlags = 0;
toSend.TimeOutValue = 10;
toSend.Function = 0x02; //Equal to SRB_FUNCTION_IO_CONTROL;

Srbioctl.ControlCode = IOCTL_TEST;

Srbioctl.Length = 0;
Srbioctl.HeaderLength = sizeof(SRB_IO_CONTROL);
Srbioctl.ReturnCode = 0;
Srbioctl.Timeout = 10;

//retCode = DeviceIoControl(SPDriverHandle,IOCTL_SCSI_PASS_THROUGH,
retCode = DeviceIoControl(SPDriverHandle,IOCTL_SCSI_MINIPORT,
&toSend,sizeof(STORAGE_REQUEST_BLOCK),&toSend,sizeof(STORAGE_REQUEST_BLOCK),&bytesReturned,NULL);
printf(“DeviceIoCtl done: Code = %i \n”,retCode);
}

getchar();
return 0;
}

As long as my handle is valid (and I’ve tried the SCSI device handle, the HW ID handle, and even one I built into the driver to reference it by name), both return codes printed to the console are both “0”. No runtime errors or anything is returned to the user to indicate a failure. No bugchecks, debug output (mine), or anything else out of the kernel debugger to indicate that anything happened at all in kernelmode. No driver functions are entered and no errors are encountered. The driver IS loaded at the handles I am trying when I am trying them. Every attempt to make the driver even react to something usermode does in this way has been met with unspectacular failure. I’m not sure what I’m doing wrong, or if I’m hunting down the wrong rabbit-hole entirely.

TL:DR- I thought I had IOCTL Usermode-Driver communication working in a virtual storport miniport, but porting to a physical storport miniport won’t allow me to call IOCTLs in the same way. Above are my failed attempts at using what I think is the “right” method. How do I call IOCTLs inside a Storport Miniport from Usermode?

I appreciate any wisdom or expertise you may be able to bestow upon me! Many thanks!

I Think you used the wrong device name;
Try to use the device name like
this:PCI#VEN_1000&DEV_0054&SUBSYS_197615AD&REV_01#4&dfc46&0&00B0#{2accfe60-c130-11d2-b082-00a0c91efb8b}
You can use QueryDosDevice API to get your device name.

On Sat, Jun 2, 2012 at 6:28 AM, wrote:

> Hello all,
>
> I am in the process of developing a Storport Miniport driver to interface
> with custom hardware and a usermode application. I need to call custom
> IOCTLs in the driver from my usermode application. I’m running Win7x64.
> Before I had any hardware ready, I created a virtual storport miniport to
> get usermode communication working the way I wanted to. I am pretty much
> just locking usermode pages into memory in kernel-mode.
> In my virtual storport miniport’s DriverEntry, I was able to define
> hwInitData.HwProcessServiceRequest =ProcessServiceRequest; which looked
> something like this in the driver:
> ULONG ProcessServiceRequest( in PVOID PDevExt, in PVOID PIrp)
> {
> PIRP pIrp = (PIRP) PIrp;
> PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(pIrp);
> if(irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL)
> {
> //Struct that has at minimum an IoControlCode defined as first
> member
> PCOMMAND_IN command = (PCOMMAND_IN)
> pIrp->AssociatedIrp.SystemBuffer;
> IoControlCode which kicks off
> IOCTL-specific logic>
> }
>
> }
>
> and from Usermode I would set up a structure conforming to COMMAND_IN
> above and call this through:
> DeviceIoControl(SPDriverHandle,IOCTL_MINIPORT_PROCESS_SERVICE_IRP,
> &toPass,sizeof(TESTSTRUCT),&toPass,sizeof(TESTSTRUCT),&bytesReturned,NULL);
>
> This would enter right in to the HwProcessServiceRequest function in the
> driver and execute whatever code I had defined there. It was beautiful,
> worked flawlessly, and life was good.
>
> You might already know what is coming, for in my naivete I expected to be
> able to port this fairly easily to a Storport Miniport that talks to actual
> hardware. Alas, I am not an experienced driver developer, and I didn’t
> realize that HwProcessServiceRequest doesn’t exist for a physical-device
> Storport Miniport. A rework was in order.
>
> It seemed that the best way to communicate through IOCTL to my driver from
> usermode applications was through using a STORAGE_REQUEST_BLOCK instance
> with the .DataBuffer member as a pointer to the SrbIOCTL I want to send,
> with the function field defined as SRB_FUNCTION_IO_CONTROL and appropriate
> lengths, etc.
> Then I will supposedly pass it to the driver with:
> DeviceIoControl(SPDriverHandle, IOCTL_SCSI_MINIPORT,
> &StorReqBlockToSend……);
> And I expected it to come out one of these functions I defined in the
> driver:
> hwInitData.HwStartIo = StartIo;
> hwInitData.HwBuildIo = BuildIo;
>
> Neither of these functions are entered. Stranger yet is that the
> DeviceIoControl function returns 0 (Success, supposedly).
>
> Here is my usermode application code. In the comments and unnecessary code
> are a few other failed attempts that yielded identical results. I used
> http://msdn.microsoft.com/en-us/library/windows/hardware/hh451474(v=vs.85).aspx(specifically the part regarding SRB_FUNCTION_IO_CONTROL) and other
> articles (now lost) as references
>
> #define TEST_STORPORT_DRIVER 0xE000
> #define IOCTL_TEST CTL_CODE(TEST_STORPORT_DRIVER,
> 0x8FF, METHOD_NEITHER, FILE_ANY_ACCESS)
> //#define IOCTL_TEST
> CTL_CODE(FILE_DEVICE_MASS_STORAGE, 0x8FF, METHOD_BUFFERED, FILE_READ_DATA |
> FILE_WRITE_DATA)
>
> int _tmain(int argc, _TCHAR* argv)
> {
> HANDLE SPDriverHandle;
>
> SPDriverHandle = CreateFile(L"\\.\Scsi2:", // Name of the NT
> device to open
>
> GENERIC_READ|GENERIC_WRITE, // Access rights requested
> 0,
> // Share access - NONE
> 0,
> // Security attributes - not used!
> OPEN_EXISTING,
> // Device must exist to open it.
>
> FILE_FLAG_OVERLAPPED, // Open for overlapped I/O
> 0);
> // extended attributes - not used!
>
> if(SPDriverHandle == INVALID_HANDLE_VALUE)
> {
> DWORD error = GetLastError();
> printf(“error:%d.\n”,error);
> }
> else
> {
> STORAGE_REQUEST_BLOCK toSend;
> SRB_IO_CONTROL Srbioctl;
> DWORD bytesReturned = 0;
> long retCode = 0;
> DWORD error = GetLastError();
>
> printf(“Did that just work? Code: %i\n”, error);
>
> toSend.SrbFunction = 0x02; //Equal to
> SRB_FUNCTION_IO_CONTROL;
> toSend.DataBuffer = &Srbioctl;
> toSend.DataTransferLength = sizeof(SRB_IO_CONTROL);
> toSend.SrbFlags = 0;
> toSend.TimeOutValue = 10;
> toSend.Function = 0x02; //Equal to SRB_FUNCTION_IO_CONTROL;
>
> Srbioctl.ControlCode = IOCTL_TEST;
>
> Srbioctl.Length = 0;
> Srbioctl.HeaderLength = sizeof(SRB_IO_CONTROL);
> Srbioctl.ReturnCode = 0;
> Srbioctl.Timeout = 10;
>
> //retCode =
> DeviceIoControl(SPDriverHandle,IOCTL_SCSI_PASS_THROUGH,
> retCode =
> DeviceIoControl(SPDriverHandle,IOCTL_SCSI_MINIPORT,
>
> &toSend,sizeof(STORAGE_REQUEST_BLOCK),&toSend,sizeof(STORAGE_REQUEST_BLOCK),&bytesReturned,NULL);
> printf(“DeviceIoCtl done: Code = %i \n”,retCode);
> }
>
> getchar();
> return 0;
> }
>
>
> As long as my handle is valid (and I’ve tried the SCSI device handle, the
> HW ID handle, and even one I built into the driver to reference it by
> name), both return codes printed to the console are both “0”. No runtime
> errors or anything is returned to the user to indicate a failure. No
> bugchecks, debug output (mine), or anything else out of the kernel debugger
> to indicate that anything happened at all in kernelmode. No driver
> functions are entered and no errors are encountered. The driver IS loaded
> at the handles I am trying when I am trying them. Every attempt to make the
> driver even react to something usermode does in this way has been met with
> unspectacular failure. I’m not sure what I’m doing wrong, or if I’m hunting
> down the wrong rabbit-hole entirely.
>
>
> TL:DR- I thought I had IOCTL Usermode-Driver communication working in a
> virtual storport miniport, but porting to a physical storport miniport
> won’t allow me to call IOCTLs in the same way. Above are my failed attempts
> at using what I think is the “right” method. How do I call IOCTLs inside a
> Storport Miniport from Usermode?
>
>
> I appreciate any wisdom or expertise you may be able to bestow upon me!
> Many thanks!
>
> —
> 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
>



Best regards,
曾晓华

You can use the legacy symlinks “\.\scsiX” to access the adapter
device, it resolves to the same thing.

Mark Roddy

On Mon, Jun 4, 2012 at 3:12 AM, zeng xiaohua wrote:
> I Think you used the wrong device name;
> Try to use the device name like
> this:PCI#VEN_1000&DEV_0054&SUBSYS_197615AD&REV_01#4&dfc46&0&00B0#{2accfe60-c130-11d2-b082-00a0c91efb8b}
> You can use QueryDosDevice API to get your device name.
>
>
> On Sat, Jun 2, 2012 at 6:28 AM, wrote:
>>
>> Hello all,
>>
>> I am in the process of developing a Storport Miniport driver to interface
>> with custom hardware and a usermode application. I need to call custom
>> IOCTLs in the driver from my usermode application. I’m running Win7x64.
>> Before I had any hardware ready, I created a virtual storport miniport to
>> get usermode communication working the way I wanted to. I am pretty much
>> just locking usermode pages into memory in kernel-mode.
>> In my virtual storport miniport’s DriverEntry, I was able to define
>> hwInitData.HwProcessServiceRequest =ProcessServiceRequest; which looked
>> something like this in the driver:
>> ULONG ProcessServiceRequest( in PVOID PDevExt, in PVOID PIrp)
>> {
>> PIRP pIrp = (PIRP) PIrp;
>> PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(pIrp);
>> if(irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL)
>> {
>> //Struct that has at minimum an IoControlCode defined as first
>> member
>> PCOMMAND_IN command = (PCOMMAND_IN)
>> pIrp->AssociatedIrp.SystemBuffer;
>> IoControlCode which kicks off
>> IOCTL-specific logic>
>> }
>>
>> }
>>
>> and from Usermode I would set up a structure conforming to COMMAND_IN
>> above and call this through:
>> DeviceIoControl(SPDriverHandle,IOCTL_MINIPORT_PROCESS_SERVICE_IRP,
>> &toPass,sizeof(TESTSTRUCT),&toPass,sizeof(TESTSTRUCT),&bytesReturned,NULL);
>>
>> This would enter right in to the HwProcessServiceRequest function in the
>> driver and execute whatever code I had defined there. It was beautiful,
>> worked flawlessly, and life was good.
>>
>> You might already know what is coming, for in my naivete I expected to be
>> able to port this fairly easily to a Storport Miniport that talks to actual
>> hardware. Alas, I am not an experienced driver developer, and I didn’t
>> realize that HwProcessServiceRequest doesn’t exist for a physical-device
>> Storport Miniport. A rework was in order.
>>
>> It seemed that the best way to communicate through IOCTL to my driver from
>> usermode applications was through using a STORAGE_REQUEST_BLOCK instance
>> with the .DataBuffer member as a pointer to the SrbIOCTL I want to send,
>> with the function field defined as SRB_FUNCTION_IO_CONTROL and appropriate
>> lengths, etc.
>> Then I will supposedly pass it to the driver with:
>> DeviceIoControl(SPDriverHandle, IOCTL_SCSI_MINIPORT,
>> &StorReqBlockToSend……);
>> And I expected it to come out one of these functions I defined in the
>> driver:
>> hwInitData.HwStartIo = StartIo;
>> hwInitData.HwBuildIo = BuildIo;
>>
>> Neither of these functions are entered. Stranger yet is that the
>> DeviceIoControl function returns 0 (Success, supposedly).
>>
>> Here is my usermode application code. In the comments and unnecessary code
>> are a few other failed attempts that yielded identical results. I used
>> http://msdn.microsoft.com/en-us/library/windows/hardware/hh451474(v=vs.85).aspx
>> (specifically the part regarding SRB_FUNCTION_IO_CONTROL) and other articles
>> (now lost) as references
>>
>> #define TEST_STORPORT_DRIVER 0xE000
>> #define IOCTL_TEST CTL_CODE(TEST_STORPORT_DRIVER,
>> 0x8FF, METHOD_NEITHER, FILE_ANY_ACCESS)
>> //#define IOCTL_TEST
>> CTL_CODE(FILE_DEVICE_MASS_STORAGE, 0x8FF, METHOD_BUFFERED, FILE_READ_DATA |
>> FILE_WRITE_DATA)
>>
>> int _tmain(int argc, _TCHAR* argv)
>> {
>> HANDLE SPDriverHandle;
>>
>> SPDriverHandle = CreateFile(L"\\.\Scsi2:", // Name of the NT
>> device to open
>>
>> GENERIC_READ|GENERIC_WRITE, // Access rights requested
>> 0,
>> // Share access - NONE
>> 0,
>> // Security attributes - not used!
>> OPEN_EXISTING,
>> // Device must exist to open it.
>>
>> FILE_FLAG_OVERLAPPED, // Open for overlapped I/O
>> 0);
>> // extended attributes - not used!
>>
>> if(SPDriverHandle == INVALID_HANDLE_VALUE)
>> {
>> DWORD error = GetLastError();
>> printf(“error:%d.\n”,error);
>> }
>> else
>> {
>> STORAGE_REQUEST_BLOCK toSend;
>> SRB_IO_CONTROL Srbioctl;
>> DWORD bytesReturned = 0;
>> long retCode = 0;
>> DWORD error = GetLastError();
>>
>> printf(“Did that just work? Code: %i\n”, error);
>>
>> toSend.SrbFunction = 0x02; //Equal to
>> SRB_FUNCTION_IO_CONTROL;
>> toSend.DataBuffer = &Srbioctl;
>> toSend.DataTransferLength = sizeof(SRB_IO_CONTROL);
>> toSend.SrbFlags = 0;
>> toSend.TimeOutValue = 10;
>> toSend.Function = 0x02; //Equal to SRB_FUNCTION_IO_CONTROL;
>>
>> Srbioctl.ControlCode = IOCTL_TEST;
>>
>> Srbioctl.Length = 0;
>> Srbioctl.HeaderLength = sizeof(SRB_IO_CONTROL);
>> Srbioctl.ReturnCode = 0;
>> Srbioctl.Timeout = 10;
>>
>> //retCode =
>> DeviceIoControl(SPDriverHandle,IOCTL_SCSI_PASS_THROUGH,
>> retCode =
>> DeviceIoControl(SPDriverHandle,IOCTL_SCSI_MINIPORT,
>>
>> &toSend,sizeof(STORAGE_REQUEST_BLOCK),&toSend,sizeof(STORAGE_REQUEST_BLOCK),&bytesReturned,NULL);
>> printf(“DeviceIoCtl done: Code = %i \n”,retCode);
>> }
>>
>> getchar();
>> return 0;
>> }
>>
>>
>> As long as my handle is valid (and I’ve tried the SCSI device handle, the
>> HW ID handle, and even one I built into the driver to reference it by name),
>> both return codes printed to the console are both “0”. No runtime errors or
>> anything is returned to the user to indicate a failure. No bugchecks, debug
>> output (mine), or anything else out of the kernel debugger to indicate that
>> anything happened at all in kernelmode. No driver functions are entered and
>> no errors are encountered. The driver IS loaded at the handles I am trying
>> when I am trying them. Every attempt to make the driver even react to
>> something usermode does in this way has been met with unspectacular failure.
>> I’m not sure what I’m doing wrong, or if I’m hunting down the wrong
>> rabbit-hole entirely.
>>
>>
>> TL:DR- I thought I had IOCTL Usermode-Driver communication working in a
>> virtual storport miniport, but porting to a physical storport miniport won’t
>> allow me to call IOCTLs in the same way. Above are my failed attempts at
>> using what I think is the “right” method. How do I call IOCTLs inside a
>> Storport Miniport from Usermode?
>>
>>
>> I appreciate any wisdom or expertise you may be able to bestow upon me!
>> Many thanks!
>>
>> —
>> 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
>
>
>
>
> –
>
> Best regards,
> 曾晓华
>
> — 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

Thank you David and Mark for your replies. I’m pretty sure the names I am using are correct. The CreateFile call with the OPEN_EXISTING flag does not throw any errors, so I can only assume it is working. It does seem to be able to open both “\.\scsiX”, “PCI#VEN_FFFF&DEV_FFFF&SUBSYS…” names. I also registered the driver to a new device name through an IoCreateDevice call in the DriverEntry section. This name I could open in the same way from Usermode, and it produced the same unspectacular results as using the standard name. When I screw up the device name, it will error out (error 2), so I am led to believe the names are correct.
I’m thinking I must be screwing something up in my usermode application. The functions I expect to be called in the driver are never even entered (I’m checking through the windbg kernel debugger), but I can’t figure out what.

chowe, what if you start debugging in user mode and step into DeviceIoControl and then to kernel to see which driver gets control when you issue the call?

Your use of IOCTL_SCSI_MINIPORT isn’t quite right. The way I have done this in the past is

typedef _driver_cmd
{
SRB_IO_CONTROL header;
payload
}driver_cmd;

driver_cmd cmd;

Then use DeviceIoControl to deliver driver_cmd structures to the driver. You can forget about needing to deliver an SRB as your payload. The space after the SRB_IO_CONTROL structure is used to communicate with the driver.

I’ll add a couple more things.

  1. You want to make sure to set the Signature in the SRB_IO_CONTROL. At least in my experience the storage stack sends IOCTL’s down the stack when your device appears. You don’t want to mess wtih an IOCTL with a Signature that doesn’t match because it’s not from your app.

  2. If you don’t like the way IOCTL_SCSI_MINIPORT works, you can also use IOCTL_SCSI_PASS_THROUGH or IOCTL_SCSI_PASS_THROUGH direct with a vendor specific CDB operation code.

An easy way to send an IOCTL to a vsm is to use IOCTL_MINIPORT_PROCESS_SERVICE_IRP which the vsm receives at a special callback. From an application standpoint, this ioctl works normally like other IOCTLs versus the screwball IOCTL_SCSI_MINIPORT which is riddled with issues you can read about in the archives.

Thank you all very much for the replies. Jeff, I used your suggestions to successfully send a combined structure to my IOCTL handler as you described! Your suggestions about signature were very helpful also.

As a follow-up, my driver would like to modify the structure passed in, so that I may have 2-way communication through the passed structure. In the Virtual Storport Miniport, I used the following:
Usermode: DeviceIoControl(DriverHandle, IOCTL_MINIPORT_PROCESS_SERVICE_IRP, &Structure, Sizeof(Structure), &Structure, Sizeof(Structure), &Bytesreturned, NULL)
This passes the Structure in and expects the same back. Bytesreturned was set in Kernelmode by:
Kernelmode: pIrp->IoStatus.Information = sizeof(TESTSTRUCT);

After which I completed the IRP:
Kernelmode: pIrp->IoStatus.Status = STATUS_SUCCESS;
Kernelmode: StorPortCompleteServiceIrp(PDevExt, pIrp);

From there, Usermode would get an updated value in Bytesreturned that cooresponded to the size of the entire structure. I was able to modify a member of Structure in Kernelmode and use it in Usermode.

Now on my physical miniport, I am handling and completing IOCTLs in my HwBuildIO( PVOID AdapterExtension, PSCSI_REQUEST_BLOCK Srb) function. I can see everything I passed into the Structure. When I modify one member of the structure, and return, the Usermode structure is unaltered. The Bytesreturned value is 0. I am not updating the returned data length at all.

I have not been able to find a way through StorPortNotification or similar functions to update whatever cooresponds to Bytesreturned in the same way I used to be able to use pIrp->IoStatus.Information. There doesn’t seem to be a way to access an IRP or anything similar that I have found. Does anyone know how I might overcome this?

I’m wondering if driver modification and passing of the structure given by usermode is even possible in this way. Perhaps one of the other methods that Jeff or Eriksson mentioned would be more condusive to what I’m trying to do?

Again, many thanks to all of you!

I found my issue!

I needed to set at least one of these on SRB completion:
pSrb->ScsiStatus = SCSISTAT_GOOD;
pSrb->SrbStatus = SRB_STATUS_SUCCESS;

Otherwise Storport didn’t do anything as far as return data to Usermode goes.

And as a correction to an inaccuracy above, a DeviceIoControl return code of 0 is actually a failure.
I used GetLastError and it returned 1117. After my fix, DeviceIoControl now returns 1, which indicates a success.
Thanks again for everyone’s help!