Question about storage stack, particularly IASTOR.sys

Folks,

I was trying to cook-up a really ad-hoc test how ( and when - if there is a
state machine) this SCSIOP_READ_CAPACITY works. In one particular HW raid
configuration we see classpnp get stuck ( if you know the code path of this
in classpnp) because the PktCompetion routine never gets called, so the
dispatch is blocked forever.

So what I did is to take ( fairly wholesale) that part of the code, and got
rid off the overlying PACKET structure,

Here is the main body of the code ( with lots of junk, pls ignore those )

/*

* SubmitTransferPacket

*

* Set up the IRP for the TRANSFER_PACKET submission and send it down.

*/

NTSTATUS SubmitTransferIrp(PDEVICE_OBJECT Fdo, PIRP Irp, PKEVENT event,

PSCSI_REQUEST_BLOCK Srb)

{

//PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;

// PDEVICE_OBJECT nextDevObj = commonExtension->LowerDeviceObject;

// PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;

// PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;

// BOOLEAN idleRequest = FALSE;

PIO_STACK_LOCATION nextSp;

/*

* Attach the SRB to the IRP.

* The reused IRP’s stack location has to be rewritten for each retry

* call because IoCompleteRequest clears the stack locations.

*/

///IoReuseIrp(Pkt->Irp, STATUS_NOT_SUPPORTED);

nextSp = IoGetNextIrpStackLocation(Irp);

nextSp->MajorFunction = IRP_MJ_SCSI;

nextSp->Parameters.Scsi.Srb = Srb;

Srb->ScsiStatus = 0;

//ps sense data buffer needed ???

// Srb->SenseInfoBufferLength = 0; // sizeof(SENSE_DATA);

//

IoSetCompletionRoutine(Irp, IrpCompletion , event, TRUE, TRUE, TRUE);

return IoCallDriver(Fdo, Irp);

}

/*

* SetupDriveCapacityTransferPacket

*

* Set up a transferPacket for a synchronous Drive Capacity transfer.

*/

VOID SetupDriveCapacityTransferPacket(PIRP Irp,

PVOID ReadCapacityBuffer,

ULONG ReadCapacityBufferLen,

PSCSI_REQUEST_BLOCK Srb,

BOOLEAN Use16ByteCdb)

{

//PFUNCTIONAL_DEVICE_EXTENSION fdoExt =Fdo->DeviceExtension;

PCDB pCdb;

if (!Srb ) KdBreakPoint();

RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));

Srb->Length = sizeof(SCSI_REQUEST_BLOCK);

Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;

Srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;

Srb->OriginalRequest = Irp;

Srb->SenseInfoBuffer = MemAllocateBuffer(sizeof(SENSE_DATA));
///&Pkt->SrbErrorSenseData;

Srb->SenseInfoBufferLength = sizeof(SENSE_DATA);

Srb->TimeOutValue = SCSI_DISK_TIMEOUT * 4; //fdoExt->TimeOutValue;

Srb->DataBuffer = ReadCapacityBuffer;

Srb->DataTransferLength = ReadCapacityBufferLen;

/// srb.SrbFlags = fdoExt->SrbFlags;

SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_IN);

SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);

SET_FLAG(Srb->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);

pCdb = (PCDB)Srb->Cdb;

if (Use16ByteCdb == TRUE) {

ASSERT(ReadCapacityBufferLen >= sizeof(READ_CAPACITY_DATA_EX));

Srb->CdbLength = 16;

pCdb->CDB16.OperationCode = SCSIOP_READ_CAPACITY16;

REVERSE_BYTES(&pCdb->CDB16.TransferLength, &ReadCapacityBufferLen);

pCdb->AsByte[1] = 0x10; // Service Action

} else {

Srb->CdbLength = 10;

pCdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;

}

}

NTSTATUS ClassReadDriveCapacity(__in PDEVICE_OBJECT Fdo)

{

//PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;

//PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;

//PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;

READ_CAPACITY_DATA_EX readCapacityData = {0};

READ_CAPACITY_DATA_EX * preadCapacityData;

ULONG readCapacityDataSize;

SCSI_REQUEST_BLOCK srb;

SCSI_REQUEST_BLOCK *psrb;

NTSTATUS status;

PMDL driveCapMdl = NULL;

KEVENT event;

PIRP irp;

//IRP pseudoIrp = {0};

//BOOLEAN use16ByteCdb;

// BOOLEAN match = TRUE;

psrb = MemAllocateBuffer( sizeof (SCSI_REQUEST_BLOCK) );

readCapacityDataSize = sizeof(READ_CAPACITY_DATA);

preadCapacityData = MemAllocateBuffer( readCapacityDataSize);
//basically from NP paged pool

//ps NewTransperIrp does this now

// Allocate the MDL based on the Read Capacity command.

//

driveCapMdl = BuildDeviceInputMdl(&readCapacityData,
readCapacityDataSize);

if (driveCapMdl == NULL) {

status = STATUS_INSUFFICIENT_RESOURCES;

goto SafeExit;

}

irp = NewTransferIrp(Fdo, readCapacityDataSize );

if (irp == NULL) {

status = STATUS_INSUFFICIENT_RESOURCES;

KdBreakPoint();

goto SafeExit;

}

//

// Set this up as a SYNCHRONOUS transfer, submit it,

// and wait for the packet to complete. The result

// status will be written to the original irp.

//

KeInitializeEvent(&event, SynchronizationEvent, FALSE);

SetupDriveCapacityTransferPacket(irp, ///Fdo,

preadCapacityData, //
&readCapacityData,

readCapacityDataSize,

psrb, //&srb, //following code from
disk.c

FALSE /*use16ByteCdb*/);

status = SubmitTransferIrp(Fdo, irp, &event, psrb /*&srb */);

if (STATUS_PENDING == status) {

(VOID)KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
NULL);

}

if (NT_SUCCESS(irp->IoStatus.Status)) {

//

}else {

//

// The request failed.

//

KdBreakPoint();

}

SafeExit:

if (irp && irp->MdlAddress){

//MmUnlockPages(irp->MdlAddress);

IoFreeMdl(irp->MdlAddress);

}

if (irp){

IoFreeIrp(irp);

}

return status;

}

What I observed is that when the IoCallDriver calls down path, iastore
changes the DataBuffer pointer. __But this buffer happens to be in user
space, so later on when it tries to access ( we are not accessing anything
here, once done, we just chk for status.), at irql 2, it Bug checks.

The status is 259.

So for example, when the calls - SubmitTransferIrp(Fdo, irp, &event, psrb
/*&srb */); returns I check to see the srb structure, and see that
iastor.sys changed it. (By setting access break points). If I replace it
back, then another access to it by iastor don’t bugcheck.

What is 259, it is not from ntstatus.h, right?

The request goes to the target HDD, at startDevice time.

Any thoughts?

-pro

Here is the dig, but still looking for why it would do this, absolutely no
clue yet…

Local var @ 0x8078658c Type _SCSI_REQUEST_BLOCK*

0x88ed42b8

+0x000 Length : 0x40

+0x002 Function : 0 ‘’

+0x003 SrbStatus : 0 ‘’

+0x004 ScsiStatus : 0 ‘’

+0x005 PathId : 0 ‘’

+0x006 TargetId : 0 ‘’

+0x007 Lun : 0 ‘’

+0x008 QueueTag : 0 ‘’

+0x009 QueueAction : 0x20 ’ ’

+0x00a CdbLength : 0xa ‘’

+0x00b SenseInfoBufferLength : 0x12 ‘’

+0x00c SrbFlags : 0x148

+0x010 DataTransferLength : 8

+0x014 TimeOutValue : 0x28

+0x018 DataBuffer : 0x87775838 Void

+0x01c SenseInfoBuffer : 0x88ed31a0 Void

+0x020 NextSrb : (null)

+0x024 OriginalRequest : 0x873511c0 Void

+0x028 SrbExtension : 0x8784f728 Void

+0x02c InternalStatus : 0

+0x02c QueueSortKey : 0

+0x02c LinkTimeoutValue : 0

+0x030 Cdb : [16] “%”

1: kd> ? 0x88ed42b8+0x18

Evaluate expression: -1997716784 = 88ed42d0

These are the access breaks ( no other access break in this session )

5 e 88ed42d0 w 4 0001 (0001)

6 e 88ed42d4 w 4 0001 (0001)

/// iastor module range

8c601000 8c702000 iaStor (no symbols) - This is the range

1: kd> r @eax

eax=1bd95838

1: kd> r @ebx

ebx=87775838 <<<<- this is the

edi=88ed42b8

8c631136 7405 je iaStor+0x3013d (8c63113d)

8c631138 03c3 add eax,ebx <- No idea, why it is adding

8c63113a 894718 mov dword ptr [edi+18h],eax <- This is where it
gets replaced, we broke in here due to bp Number 5

8c63113d 33c0 xor eax,eax

8c63113f 5f pop edi

8c631140 5e pop esi

8c631141 5b pop ebx

8c631142 5d pop ebp

8c631143 c20800 ret 8

8c631146 cc int 3

8c631147 cc int 3

8c631148 cc int 3

////

1: kd> dt preadCapacityData

Local var @ 0x80786584 Type _READ_CAPACITY_DATA_EX* <— 6fd0 >= 6584

=4000

0x87775838 <– this is what this Ptr valiable holds

+0x000 LogicalBlockAddress : _LARGE_INTEGER 0x0

+0x008 BytesPerBlock : 0x4050002

1: kd> dd 0x80786584

80786584 87775838 88ed54e0 88ed42b8 807865c0 <<- 87775838 Okay

80786594 8cb545b4 8784fb10 00000030 87351a70

807865a4 00000001 00000000 00000001 01000000

807865b4 00000000 88ed8000 88ed44c8 807865d4

807865c4 8cb71444 88ed4410 00000000 88ed44c8

807865d4 807865fc 8cb715b9 88ed4410 87351978

807865e4 00010000 8416ad00 00000000 8416ad00

807865f4 87351a54 88ed44c8 8078660c 8cb87552

///

1: kd> dd 0x8078658c - this is the stack address where psrb is defined.

8078658c 88ed42b8 807865c0 8cb545b4 8784fb10 <<<- 88ed42b8 the value psrb
holds

8078659c 00000030 87351a70 00000001 00000000

807865ac 00000001 01000000 00000000 88ed8000

807865bc 88ed44c8 807865d4 8cb71444 88ed4410

807865cc 00000000 88ed44c8 807865fc 8cb715b9

807865dc 88ed4410 87351978 00010000 8416ad00

807865ec 00000000 8416ad00 87351a54 88ed44c8

807865fc 8078660c 8cb87552 88ed4410 87351978

/// stack within limits???

///

Win32 Start Address nt!Phase1Initialization (0x841c8487)

Stack Init 80786fd0 Current 80786408 Base 80787000 Limit 80784000 Call 0

Priority 31 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2
PagePriority 5

ChildEBP RetAddr Args to Child

80786590 8cb545b4 8784fb10 00000030 87351a70
diskfltr!ClassReadDriveCapacity+0xba (FPO: [Non-Fpo]) (CONV: stdcall)

///

Stack Init 80786fd0 Limit 80784000 ( toss out first four nibble, they are
noise )

location of psrb -> 0x8078658c

After toss out 6fd0 >= 658c >=4000 . Of course we knew it, but just checked
again.

When our driver gets control -

1: kd> dt psrb

Local var @ 0x8078658c Type _SCSI_REQUEST_BLOCK*

0x88ed42b8

+0x000 Length : 0x40

+0x002 Function : 0 ‘’

+0x003 SrbStatus : 0 ‘’

+0x004 ScsiStatus : 0 ‘’

+0x005 PathId : 0 ‘’

+0x006 TargetId : 0 ‘’

+0x007 Lun : 0 ‘’

+0x008 QueueTag : 0 ‘’

+0x009 QueueAction : 0x20 ’ ’

+0x00a CdbLength : 0xa ‘’

+0x00b SenseInfoBufferLength : 0x12 ‘’

+0x00c SrbFlags : 0x148

+0x010 DataTransferLength : 8

+0x014 TimeOutValue : 0x28

+0x018 DataBuffer : 0x1bd95838 Void <<<------ This is what
iastor.sys plugged in, later when it completes, try to access at irql== 2

+0x01c SenseInfoBuffer : 0x88ed31a0 Void

+0x020 NextSrb : (null)

+0x024 OriginalRequest : 0x873511c0 Void

+0x028 SrbExtension : 0x8784f728 Void

+0x02c InternalStatus : 0

+0x02c QueueSortKey : 0

+0x02c LinkTimeoutValue : 0

+0x030 Cdb : [16] “%”

At this stage if I just plugged back the original address, well of course it
had to be status pending returned here… it does not bug check.