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