NTSTATUS
ReadWriteDisk(
PDEVICE_OBJECT DeviceObject,
ULONG SectorOffset,
ULONG IsReadOperation, // = 0 means is a write operation otherwise is read
PVOID Buffer,
ULONG SectorCount,
PIO_STATUS_BLOCK IoStatusBlock
)
{
SENSE_DATA SenseData; // error info - -
SCSI_REQUEST_BLOCK ScsiRequestBlock;
PCDB CommandDescriptorBlock;
PIRP Irp;
PIO_STACK_LOCATION IrpSp;
PMDL Mdl;
KEVENT Event;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
if (SectorCount > 0xFFFF)
{
return STATUS_INVALID_PARAMETER;
}
RtlZeroMemory(&SenseData, sizeof(SENSE_DATA));
RtlZeroMemory(&ScsiRequestBlock, sizeof(SCSI_REQUEST_BLOCK));
ScsiRequestBlock.Length = sizeof(SCSI_REQUEST_BLOCK);
ScsiRequestBlock.Function = SRB_FUNCTION_EXECUTE_SCSI;
ScsiRequestBlock.DataBuffer = Buffer;
ScsiRequestBlock.SenseInfoBuffer = &SenseData;
ScsiRequestBlock.SenseInfoBufferLength = sizeof(SENSE_DATA);
ScsiRequestBlock.DataTransferLength = SectorCount * BytesPerSector;
ScsiRequestBlock.QueueAction = SRB_FLAGS_DISABLE_AUTOSENSE; // Indicates that request-sense information should not be returned ???
ScsiRequestBlock.SrbFlags = IsReadOperation ? SRB_FLAGS_DATA_IN : SRB_FLAGS_DATA_OUT;
ScsiRequestBlock.SrbFlags |= IsReadOperation ? SRB_FLAGS_ADAPTER_CACHE_ENABLE : 0;
ScsiRequestBlock.SrbFlags |= SRB_FLAGS_DISABLE_AUTOSENSE;
ScsiRequestBlock.TimeOutValue = -1; //////////////////////// second
ScsiRequestBlock.QueueSortKey = SectorOffset; // Specifies the offset from the start of the media or zero, depending on the type of the target device.
ScsiRequestBlock.CdbLength = 10; // sizeof(CDB.CDB10);
CommandDescriptorBlock = (PCDB)ScsiRequestBlock.Cdb;
CommandDescriptorBlock->CDB10.OperationCode = IsReadOperation ? SCSIOP_READ : SCSIOP_WRITE;
CommandDescriptorBlock->CDB10.LogicalUnitNumber = 0; // ??????????? what's this?
CommandDescriptorBlock->CDB10.Reserved1 = 0; // in fact, not needed.
// ForceUnitAccess, RelativeAddress, DisablePageOut remains still - in fact, remains 0.
CommandDescriptorBlock->CDB10.LogicalBlockByte0 = (UCHAR)(SectorOffset >> 0x18);
CommandDescriptorBlock->CDB10.LogicalBlockByte1 = (UCHAR)(SectorOffset >> 0x10);
CommandDescriptorBlock->CDB10.LogicalBlockByte2 = (UCHAR)(SectorOffset >> 0x8);
CommandDescriptorBlock->CDB10.LogicalBlockByte3 = (UCHAR)(SectorOffset);
CommandDescriptorBlock->CDB10.Reserved2 = 0;
CommandDescriptorBlock->CDB10.TransferBlocksMsb = (UCHAR)(SectorCount >> 0x8);
CommandDescriptorBlock->CDB10.TransferBlocksLsb = (UCHAR)(SectorCount);
CommandDescriptorBlock->CDB10.Control = 0; // how to initialize this?
KeInitializeEvent(&Event, NotificationEvent, FALSE);
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (!Irp)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
Mdl = IoAllocateMdl(Buffer, SectorCount * BytesPerSector, FALSE, FALSE, Irp);
if (!Mdl)
{
IoFreeIrp(Irp);
return STATUS_INSUFFICIENT_RESOURCES;
}
MmProbeAndLockPages(Mdl, KernelMode, IsReadOperation ? IoReadAccess : IoWriteAccess);
ScsiRequestBlock.OriginalRequest = Irp;
Irp->UserIosb = IoStatusBlock;
Irp->UserEvent = &Event;
RtlZeroMemory(&Irp->IoStatus, sizeof(IO_STATUS_BLOCK));
Irp->MdlAddress = Mdl;
Irp->AssociatedIrp.SystemBuffer = NULL;
Irp->Cancel = FALSE;
Irp->CancelRoutine = NULL;
Irp->Flags = IRP_NOCACHE | IRP_SYNCHRONOUS_API;
Irp->RequestorMode = KernelMode;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
IrpSp = IoGetNextIrpStackLocation(Irp);
IrpSp->DeviceObject = DeviceObject;
IrpSp->MajorFunction = IRP_MJ_SCSI;
IrpSp->Parameters.Scsi.Srb = &ScsiRequestBlock;
IoSetCompletionRoutine(Irp, IoCompletionRoutine, &ScsiRequestBlock, TRUE, TRUE, TRUE);
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
(VOID)KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = STATUS_SUCCESS;
}
if ((ScsiRequestBlock.SenseInfoBuffer != &SenseData) && (ScsiRequestBlock.SenseInfoBuffer))
{
ExFreePool(ScsiRequestBlock.SenseInfoBuffer); // should we do this?
DbgPrint(" Information: Freed ScsiRequestBlock.SenseInfoBuffer.\n");
}
if (NT_SUCCESS(Status) && ((ScsiRequestBlock.SrbStatus == SRB_STATUS_SUCCESS) || (ScsiRequestBlock.SrbStatus == SRB_STATUS_PENDING)) && (ScsiRequestBlock.ScsiStatus == SCSISTAT_GOOD) )
{
//DbgPrint(" Information: ReadWriteDisk operation succeeded.\n");
Status = STATUS_SUCCESS;
}
else
{
DbgPrint("Error: ReadWriteDisk fails with NT status 0x%X, Scsi status 0x%X and Srb status 0x%X.\n", Status, ScsiRequestBlock.ScsiStatus, ScsiRequestBlock.SrbStatus);
Status = STATUS_UNSUCCESSFUL;
}
return Status;
}
以上代码是读取磁盘扇区代码(来源:
https://www.cnblogs.com/fanzi2009/archive/2009/05/07/1451201.html
),正常情况下没问题,但是读取2T的移动硬盘时,会不执行回调
IoCompletionRoutine (回调中会调用KeSetEvent),一直等待在 KeWaitForSingleObjec中,这种现象暂时只出现在对2T的移动硬盘读取时,想了想没发现问题所在,请大家指点迷津,多谢!!!