#include <ntddk.h>
#include <string.h>
#include <srb.h>
#include <scsi.h>
PDEVICE_OBJECT GetLastDiskDeviceObject(PDRIVER_OBJECT pDrvObj);
PDEVICE_OBJECT GetATADr0DeviceObject();
NTSTATUS
MyIoCallDriver(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
);
NTSTATUS ScsiReadWriteDiskCompletion(PDEVICE_OBJECT pDevObj, PIRP pIrp, PVOID Context);
NTSTATUS ScsiReadWriteDisk(PDEVICE_OBJECT pDevObj, BOOLEAN bIsRead, ULONG ulSectorPos, PUCHAR lpDataBuff, ULONG ulSecCount);
//
// 全局变量
//
ULONG g_ulBytesPerSector = 0x200;
/**********************************************************************
* NAME
* GetLastDiskDeviceObject
*
* DESCRIPTION
* 获取\DRIVER\DISK下最后一个设备
*
* ARGUMENTS
* PDRIVER_OBJECT pDrvObj \DRIVER\DISK的驱动对象(DRIVER_OBJECT)
* RETURN VALUE
* PDEVICE_OBJECT 成功返回 \DRIVER\DISK下最后一个设备(DR0), 失败返回 NULL
*
* @implemented
*/
PDEVICE_OBJECT GetLastDiskDeviceObject(PDRIVER_OBJECT pDrvObj)
{
PDEVICE_OBJECT pCurDevObj = NULL;
PDEVICE_OBJECT pLastDevObj = NULL;
pCurDevObj = pDrvObj->DeviceObject;
while(pCurDevObj)
{
if (pCurDevObj->DeviceType == FILE_DEVICE_DISK)
{
pLastDevObj = pCurDevObj;
}
pCurDevObj = pCurDevObj->NextDevice;
}
return pLastDevObj;
}
/**********************************************************************
* NAME
* GetATADr0DeviceObject
*
* DESCRIPTION
* 获取ATA磁盘的DRO设备
*
* ARGUMENTS
* N/A
* RETURN VALUE
* PDEVICE_OBJECT 成功返回 \DRIVER\DISK的DR0设备, 失败返回 NULL
*
* @implemented
*/
PDEVICE_OBJECT GetATADr0DeviceObject()
{
UNICODE_STRING usDiskName;
NTSTATUS ntStatus = STATUS_SUCCESS;
PDRIVER_OBJECT pDiskDrvObj = NULL;
RtlInitUnicodeString(&usDiskName, DISK_DRIVER_NAME);
ntStatus = ObReferenceObjectByName(&usDiskName, 0x40, 0, 0, *IoDriverObjectType, KernelMode, NULL, (PVOID*)&pDiskDrvObj);
if (!NT_SUCCESS(ntStatus))
{
return NULL;
}
PDEVICE_OBJECT pDr0DevObj = GetLastDiskDeviceObject(pDiskDrvObj);
ObDereferenceObject(pDiskDrvObj);
return pDr0DevObj;
}
NTSTATUS
FORCEINLINE
MyIoCallDriver(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
)
{
PIO_STACK_LOCATION irpSp;
PDRIVER_OBJECT driverObject;
NTSTATUS status;
//
// Ensure that this is really an I/O Request Packet.
//
ASSERT( Irp->Type == IO_TYPE_IRP );
//
// Update the IRP stack to point to the next location.
// 修改当前堆栈索引使之成为下个IO_STACK_LOCATION的索引
// 如果索引值小于或者等于0时则说明出错
//
Irp->CurrentLocation--;
if (Irp->CurrentLocation <= 0) {
KeBugCheck( NO_MORE_IRP_STACK_LOCATIONS);
}
//
// 设置IRP当前堆栈指针指向下一个IO_STACK_LOCATION
//
irpSp = IoGetNextIrpStackLocation( Irp );
Irp->Tail.Overlay.CurrentStackLocation = irpSp;
//
// Save a pointer to the device object for this request so that it can
// be used later in completion.
//
irpSp->DeviceObject = DeviceObject;
//
// Invoke the driver at its dispatch routine entry point.
//
driverObject = DeviceObject->DriverObject;
//
// Prevent the driver from unloading.
//
status = driverObject->MajorFunction[irpSp->MajorFunction]( DeviceObject,
Irp );
return status;
}
NTSTATUS ScsiReadWriteDiskCompletion(PDEVICE_OBJECT pDevObj, PIRP pIrp, PVOID Context)
{
pIrp->UserIosb->Information = pIrp->IoStatus.Information;
pIrp->UserIosb->Status = pIrp->IoStatus.Status;
if (Context != NULL && pIrp->MdlAddress != NULL)
{
MmUnlockPages(pIrp->MdlAddress);
IoFreeMdl(pIrp->MdlAddress);
}
KeSetEvent(pIrp->UserEvent, 0, FALSE);
IoFreeIrp(pIrp);
return STATUS_MORE_PROCESSING_REQUIRED; //交回我们的例程处理
}
/**********************************************************************
* NAME
* ScsiReadWriteDisk
*
* DESCRIPTION
* 通过向DISK的DRO发送SRB(SCSI_REQUEST_BLOCK)的方式读写磁盘扇区
*
* ARGUMENTS
* BOOLEAN bIsRead TRUE表示读 FALSE 表示写
* ULONG ulSectorPos 要读写的扇区号LBN
* ULONG ulSectorCount 要读写的扇区个数
* RETURN VALUE
* PDEVICE_OBJECT 成功返回 \DRIVER\DISK的DR0设备, 失败返回 NULL
*
* @implemented
*/
NTSTATUS ScsiReadWriteDisk(PDEVICE_OBJECT pDevObj, BOOLEAN bIsRead, ULONG ulSectorPos, PUCHAR lpDataBuff, ULONG ulSecCount)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PSCSI_REQUEST_BLOCK pSrb = NULL;
PSENSE_DATA pSenseData = NULL;
PCDB pCdb10 = NULL;
KEVENT Event;
PIRP pIrp = NULL;
PMDL pMdl = NULL;
IO_STATUS_BLOCK IoSB;
pSrb = (PSCSI_REQUEST_BLOCK)ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK),0x12345678);
if (pSrb == NULL)
goto __end;
pSenseData = (PSENSE_DATA)ExAllocatePoolWithTag(NonPagedPool, sizeof(SENSE_DATA),0x12345678);
if (pSenseData == NULL)
goto __end;
RtlZeroMemory(pSrb, sizeof(SCSI_REQUEST_BLOCK));
RtlZeroMemory(pSenseData, sizeof(SENSE_DATA));
pSrb->Length = sizeof (SCSI_REQUEST_BLOCK);
pSrb->Function = SRB_FUNCTION_EXECUTE_SCSI;
//
// 我们要读写的是IDE设备 所以不需要PATHID TARGETID LUN
//
pSrb->PathId = 0;
pSrb->TargetId = 0;
pSrb->Lun = 0;
pSrb->NextSrb = NULL;
pSrb->LinkTimeoutValue = -1;
pSrb->SrbStatus = SRB_STATUS_PENDING;
pSrb->ScsiStatus = SRB_STATUS_PENDING;
pSrb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
pSrb->SenseInfoBuffer = pSenseData;
pSrb->SenseInfoBufferLength = sizeof(SENSE_DATA);
pSrb->DataBuffer = (PVOID)lpDataBuff;
pSrb->DataTransferLength = ulSecCount;
pSrb->QueueSortKey = ulSectorPos;
if (bIsRead)
{
//
// READ
//
pSrb->SrbFlags |= SRB_FLAGS_DATA_IN;
pSrb->SrbFlags |= SRB_FLAGS_ADAPTER_CACHE_ENABLE; //这里是啥意思?适配器开启缓存?
}
else
{
//
// WRITE
//
pSrb->SrbFlags |= SRB_FLAGS_DATA_OUT;
}
pSrb->SrbFlags |= SRB_FLAGS_DISABLE_AUTOSENSE;
//
// 填写CDB
//
pSrb->CdbLength = 0x0A; //CDB10
pCdb10 = (PCDB)pSrb->Cdb;
if (bIsRead)
{
pCdb10->CDB10.OperationCode = SCSIOP_READ;
}
else
{
pCdb10->CDB10.OperationCode = SCSIOP_WRITE;
}
pCdb10->CDB10.LogicalBlockByte0 = (UCHAR)(ulSectorPos >> 0x18);
pCdb10->CDB10.LogicalBlockByte1 = (UCHAR)(ulSectorPos >> 0x10);
pCdb10->CDB10.LogicalBlockByte2 = (UCHAR)(ulSectorPos >> 0x8);
pCdb10->CDB10.LogicalBlockByte3 = (UCHAR)(ulSectorPos);
pCdb10->CDB10.TransferBlocksLsb = (UCHAR)(ulSecCount >> 0x8);
pCdb10->CDB10.TransferBlocksMsb = (UCHAR)(ulSecCount);
//
// 构造IRP来SRB请求
//
KeInitializeEvent(&Event, NotificationEvent, FALSE);
pIrp = IoAllocateIrp(pDevObj->StackSize, FALSE);
if (pIrp == NULL)
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto __end;
}
pMdl = IoAllocateMdl((PVOID)lpDataBuff, ulSecCount * g_ulBytesPerSector, FALSE, FALSE, pIrp);
if (pMdl == NULL)
{
IoFreeIrp(pIrp);
pIrp = NULL;
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto __end;
}
MmProbeAndLockPages(pMdl, KernelMode, bIsRead ? IoReadAccess : IoWriteAccess);
pIrp->UserIosb = &IoSB;
RtlZeroMemory(&pIrp->IoStatus, sizeof(IO_STATUS_BLOCK));
pIrp->UserEvent = &Event;
pIrp->Cancel = FALSE;
pIrp->CancelRoutine = NULL;
pIrp->MdlAddress = pMdl;
pIrp->AssociatedIrp.SystemBuffer = NULL;
pIrp->Flags = IRP_NOCACHE | IRP_SYNCHRONOUS_API;
pIrp->RequestorMode = KernelMode;
pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
pSrb->OriginalRequest = pIrp;
//
// 填写IO_STACK_LOCATION
//
PIO_STACK_LOCATION pIrpSp = IoGetNextIrpStackLocation(pIrp);
pIrpSp->DeviceObject = pDevObj;
pIrpSp->MajorFunction = IRP_MJ_SCSI;
pIrpSp->Parameters.Scsi.Srb = pSrb;
IoSetCompletionRoutine(pIrp, ScsiReadWriteDiskCompletion, pSrb, TRUE, TRUE, TRUE);
ntStatus = MyIoCallDriver(pDevObj, pIrp);
if (ntStatus == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
ntStatus = STATUS_SUCCESS;
}
if (NT_SUCCESS(ntStatus) && pSrb->SrbStatus == SRB_STATUS_SUCCESS && pSrb->ScsiStatus == SCSISTAT_GOOD)
{
ntStatus = STATUS_SUCCESS;
}
else
{
ntStatus = STATUS_UNSUCCESSFUL;
}
__end:
if (pSrb->SenseInfoBuffer && pSrb->SenseInfoBuffer != pSenseData)
{
ExFreePool(pSrb->SenseInfoBuffer);
}
if (pSrb != NULL)
{
ExFreePool(pSrb);
}
if (pSenseData != NULL)
{
ExFreePool(pSenseData);
}
return ntStatus;
}