I’m working on a project that needs to send some bespoke manufacture commands
directly to certain hard disk. I can achieve my goal with a application using
DeviceIoControl(); without a issue but the project calls for mapping it into a
driver. I can send IOCTL_DISK_GET_DRIVE_GEOMETRY via WdfIoTargetSendIoctlSynchronously
and works flawlessly. but IOCTL_ATA_PASS_THROUGH returns STATUS_INVALID_PARAMETER.
I use same BufferDescriptors for GEOMETRY as for PASS_THROUGH, but preload information
into the buffer out with the PASS_THROUGH; Can anyone suggest best way to debug/diagnose
what the potential issue is?
//---------CODE---------------
#ifdef ALLOC_PRAGMA
#pragma alloc_text (PAGE, ATA_OpenHDD)
#pragma alloc_text (PAGE, ATA_Read)
#pragma alloc_text (PAGE, ATA_ReadCompletion)
#pragma alloc_text (PAGE, ATA_FormatPTERead)
#endif
NTSTATUS
ATA_OpenHDD(
In WDFQUEUE Queue,
PUNICODE_STRING SymbolicLink,
WDFIOTARGET *Target
)
{
NTSTATUS status = STATUS_SUCCESS;
PTARGET_DEVICE_INFO targetDeviceInfo = NULL;
WDF_IO_TARGET_OPEN_PARAMS openParams;
WDFIOTARGET ioTarget;
WDF_OBJECT_ATTRIBUTES attributes;
PDEVICE_CONTEXT deviceContext =
QueueGetContext(Queue)->pDeviceContext;
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, TARGET_DEVICE_INFO);
status = WdfIoTargetCreate(deviceContext->WdfDevice, &attributes, &ioTarget);
if (!NT_SUCCESS(status)) {
KdPrint((“ATA_OpenHDD >> WdfIoTargetCreate failed 0x%x\n”, status));
return status;
}
targetDeviceInfo = GetTargetDeviceInfo(ioTarget);
targetDeviceInfo->DeviceContext = deviceContext;
if (targetDeviceInfo->Opened) {
*Target = ioTarget;
return status;
}
WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME( &openParams, SymbolicLink,
STANDARD_RIGHTS_ALL);
openParams.ShareAccess = FILE_SHARE_WRITE | FILE_SHARE_READ;
openParams.FileAttributes = 0x20000000; //Required at User-Mode might be
required here.
status = WdfIoTargetOpen(ioTarget, &openParams);
if (!NT_SUCCESS(status)) {
KdPrint((“ATA_OpenHDD >> WdfIoTargetOpen failed with status 0x%x\n”, status));
WdfObjectDelete(ioTarget);
return status;
}
KdPrint((“ATA_OpenHDD >> Target Device 0x%p, PDO 0x%p, Fileobject 0x%p,
Filehandle 0x%p\n”,
WdfIoTargetWdmGetTargetDeviceObject(ioTarget),
WdfIoTargetWdmGetTargetPhysicalDevice(ioTarget),
WdfIoTargetWdmGetTargetFileObject(ioTarget),
WdfIoTargetWdmGetTargetFileHandle(ioTarget)));
//
// Create two requests - one for read and one for write.
//
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
attributes.ParentObject = ioTarget;
status = WdfRequestCreate(&attributes, ioTarget,
&targetDeviceInfo->ReadRequest);
if (!NT_SUCCESS(status)) {
WdfObjectDelete(ioTarget);
return status;
}
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
attributes.ParentObject = ioTarget;
status = WdfRequestCreate(&attributes, ioTarget,
&targetDeviceInfo->WriteRequest);
if (!NT_SUCCESS(status)) {
WdfObjectDelete(ioTarget);
return status;
}
targetDeviceInfo->Opened = TRUE;
*Target = ioTarget;
return status;
}
NTSTATUS
ATA_Read(
In WDFQUEUE Queue,
In PUNICODE_STRING SymbolicLink
)
{
PDEVICE_CONTEXT deviceContext =
QueueGetContext(Queue)->pDeviceContext;
NTSTATUS status = STATUS_SUCCESS;
PTARGET_DEVICE_INFO targetInfo;
WDFIOTARGET ioTarget;
WDFREQUEST request;
ULONG_PTR BytesRead;
if (!deviceContext->FirstReadDone) {
deviceContext->FirstReadDone = TRUE;
KdPrint((“ATA_Read >> SymbolicLink = %wZ\n”, SymbolicLink));
status = ATA_OpenHDD(Queue, SymbolicLink, &ioTarget);
if (!NT_SUCCESS(status)) {
KdPrint((“ATA_Read >> ATA_OpenHDD failed 0x%x\n”, status));
return status;
}
KdPrint((“ATA_Read >> ioTarget = 0x%x\n”, ioTarget));
KdPrint((“ATA_Read >> &ioTarget = 0x%x\n”, &ioTarget));
targetInfo = GetTargetDeviceInfo(ioTarget);
request = targetInfo->ReadRequest;
//START OF READ LOOP=====================================================
KdPrint((“ATA_Read >> Assigning PTE values to (PVOID)SEND.\n”));
ATA_FormatPTERead(0x90, targetInfo);
KdPrint((“ATA_Read >> PTE values assigned.\n”));
status = WdfIoTargetSendIoctlSynchronously(
ioTarget,
request,
IOCTL_ATA_PASS_THROUGH,
&targetInfo->DiskReadBufferDescriptor,
&targetInfo->DiskWriteBufferDescriptor,
NULL,
&BytesRead);
if (!NT_SUCCESS(status)) {
KdPrint((“ATA_Read >> WdfIoTargetSendInternalIoctlSynchronously Failed
(status: 0x%x)\n”, status));
} else {
KdPrint((“ATA_Read >> WdfIoTargetSendInternalIoctlSynchronously Success
(status: 0x%x : Bytesread: %d)\n”, status, BytesRead));
}
//END OF LOOP=========================================================
if ((ioTarget != NULL) & (targetInfo->Opened)) {
targetInfo->Opened = FALSE;
WdfIoTargetClose(ioTarget);
KdPrint((“ATA_Read >> ioTarget Closed\n”));
}
}
return status;
}
VOID
ATA_FormatPTERead(
In int Address,
PTARGET_DEVICE_INFO targetDeviceInfo
)
{
NTSTATUS status;
WDF_OBJECT_ATTRIBUTES MemAttributes;
USHORT cmdBufferSize = 512 * 0x10;
UNREFERENCED_PARAMETER(Address);
if (targetDeviceInfo != NULL) {
//READ BUFFER FOR IOCTL DATA OUT
WDF_OBJECT_ATTRIBUTES_INIT(&MemAttributes);
MemAttributes.ParentObject = targetDeviceInfo->ReadRequest;
status = WdfMemoryCreate(&MemAttributes, NonPagedPool, RAMDISK_TAG_READ,
sizeof(ATA_PASS_THROUGH_EX)+cmdBufferSize, &targetDeviceInfo->DiskReadBuffer,
(PVOID*)&targetDeviceInfo->SEND);
if (!NT_SUCCESS(status)) {
KdPrint((“ATA_FormatPTERead >> WdfMemoryCreate Read failed 0x%x\n”,
status));
}
WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&(targetDeviceInfo->DiskReadBufferDescriptor)
, (PVOID)&targetDeviceInfo->SEND, sizeof(ATA_PASS_THROUGH_EX)+cmdBufferSize);
//WRITE BUFFER FOR IOCTL DATA IN
WDF_OBJECT_ATTRIBUTES_INIT(&MemAttributes);
MemAttributes.ParentObject = targetDeviceInfo->ReadRequest;
status = WdfMemoryCreate(&MemAttributes, NonPagedPool, RAMDISK_TAG_WRITE,
sizeof(ATA_PASS_THROUGH_EX)+cmdBufferSize, &targetDeviceInfo->DiskWriteBuffer,
(PVOID*)&targetDeviceInfo->RECV);
if (!NT_SUCCESS(status)) {
KdPrint((“ATA_FormatPTERead >> WdfMemoryCreate Write failed 0x%x\n”,
status));
}
WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&(targetDeviceInfo->DiskWriteBufferDescriptor
), (PVOID)&targetDeviceInfo->RECV, sizeof(ATA_PASS_THROUGH_EX)+cmdBufferSize);
KdPrint((“ATA_FormatPTERead >> Casting Send to ATA_PASS Struct;\n”));
ATA_PASS_THROUGH_EX * PTE_SEND = (ATA_PASS_THROUGH_EX
*)(targetDeviceInfo->SEND);
PTE_SEND->Length = (USHORT)(sizeof(ATA_PASS_THROUGH_EX) + cmdBufferSize);
PTE_SEND->TimeOutValue = 10;
PTE_SEND->DataTransferLength = cmdBufferSize;
PTE_SEND->DataBufferOffset = sizeof(ATA_PASS_THROUGH_EX);
PTE_SEND->AtaFlags = ATA_FLAGS_DATA_IN | ATA_FLAGS_DRDY_REQUIRED |
ATA_FLAGS_48BIT_COMMAND;
PTE_SEND->ReservedAsUchar = 0;
KdPrint((“ATA_FormatPTERead >> Setting LBA Values;\n”));
IDEREGS * ir = (IDEREGS *)&(PTE_SEND->CurrentTaskFile);
IDEREGS * pir = (IDEREGS *)&(PTE_SEND->PreviousTaskFile);
// COMMANDS AND VALUES REMOVED : ir->bCommandReg etc…
KdPrint((“ATA_FormatPTERead >> ATA_PASS Struct Complete;\n”));
}
}
NTSTATUS
ATA_Write(
In WDFQUEUE Queue,
In PUNICODE_STRING SymbolicLink
)
{
PDEVICE_CONTEXT deviceContext =
QueueGetContext(Queue)->pDeviceContext;
NTSTATUS status = STATUS_SUCCESS;
PTARGET_DEVICE_INFO targetInfo;
WDFIOTARGET ioTarget;
WDFREQUEST request;
ULONG_PTR BytesRead;
//USHORT cmdBufferSize = 512 * 0x10;
KdPrint((“ATA_Write >> SymbolicLink = %wZ\n”, SymbolicLink));
status = ATA_OpenHDD(Queue, SymbolicLink, &ioTarget);
if (!NT_SUCCESS(status)) {
KdPrint((“ATA_Write >> ATA_OpenHDD failed 0x%x\n”, status));
return status;
}
KdPrint((“ATA_Write >> ioTarget = 0x%x\n”, ioTarget));
KdPrint((“ATA_Write >> &ioTarget = 0x%x\n”, &ioTarget));
targetInfo = GetTargetDeviceInfo(ioTarget);
request = targetInfo->ReadRequest;
//START OF WRITE LOOP=====================================================
KdPrint((“ATA_Write >> Assigning PTE values to (PVOID)SEND.\n”));
ATA_FormatPTEWrite(0x90, deviceContext->DiskImage, 0, targetInfo);
KdPrint((“ATA_Write >> PTE values assigned.\n”));
status = WdfIoTargetSendIoctlSynchronously(
ioTarget,
request,
IOCTL_ATA_PASS_THROUGH,
&targetInfo->DiskReadBufferDescriptor,
&targetInfo->DiskWriteBufferDescriptor,
NULL,
&BytesRead);
if (!NT_SUCCESS(status)) {
KdPrint((“ATA_Write >> WdfIoTargetSendInternalIoctlSynchronously Failed
(status: 0x%x)\n”, status));
return status;
}
else {
KdPrint((“ATA_Write >> WdfIoTargetSendInternalIoctlSynchronously Success
(status: 0x%x : Bytesread: %d)\n”, status, BytesRead));
}
//END OF LOOP=========================================================
if ((ioTarget != NULL) & (targetInfo->Opened)) {
targetInfo->Opened = FALSE;
WdfIoTargetClose(ioTarget);
KdPrint((“ATA_Write >> ioTarget Closed\n”));
}
return status;
}
VOID
ATA_FormatPTEWrite(
In int Address,
In PUCHAR Data,
In ULONG DataOffset,
PTARGET_DEVICE_INFO targetDeviceInfo
)
{
NTSTATUS status;
WDF_OBJECT_ATTRIBUTES MemAttributes;
USHORT cmdBufferSize = 512 * 0x10;
if (targetDeviceInfo != NULL) {
//READ BUFFER FOR IOCTL DATA OUT
WDF_OBJECT_ATTRIBUTES_INIT(&MemAttributes);
MemAttributes.ParentObject = targetDeviceInfo->ReadRequest;
status = WdfMemoryCreate(&MemAttributes, NonPagedPool, RAMDISK_TAG_READ,
sizeof(ATA_PASS_THROUGH_EX)+cmdBufferSize, &targetDeviceInfo->DiskReadBuffer,
(PVOID*)&targetDeviceInfo->SEND);
if (!NT_SUCCESS(status)) {
KdPrint((“ATA_FormatPTEWrite >> WdfMemoryCreate Read failed 0x%x\n”,
status));
}
WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&(targetDeviceInfo->DiskReadBufferDescriptor)
, (PVOID)&targetDeviceInfo->SEND, sizeof(ATA_PASS_THROUGH_EX)+cmdBufferSize);
//WRITE BUFFER FOR IOCTL DATA IN
WDF_OBJECT_ATTRIBUTES_INIT(&MemAttributes);
MemAttributes.ParentObject = targetDeviceInfo->ReadRequest;
status = WdfMemoryCreate(&MemAttributes, NonPagedPool, RAMDISK_TAG_WRITE,
sizeof(ATA_PASS_THROUGH_EX)+cmdBufferSize, &targetDeviceInfo->DiskWriteBuffer,
(PVOID*)&targetDeviceInfo->RECV);
if (!NT_SUCCESS(status)) {
KdPrint((“ATA_FormatPTEWrite >> WdfMemoryCreate Write failed 0x%x\n”,
status));
}
WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&(targetDeviceInfo->DiskWriteBufferDescriptor
), (PVOID)&targetDeviceInfo->RECV, sizeof(ATA_PASS_THROUGH_EX)+cmdBufferSize);
status = WdfMemoryCopyFromBuffer(targetDeviceInfo->DiskReadBuffer, //
Destination
sizeof(ATA_PASS_THROUGH_EX), // Offset into the destination
Data + DataOffset, // Pointer Into Source
cmdBufferSize); // Length To from Source
if (!NT_SUCCESS(status)) {
KdPrint((“ATA_FormatPTEWrite >> WdfMemoryCopyFromBuffer failed 0x%x\n”,
status));
}
KdPrint((“ATA_FormatPTEWrite >> Casting Send to ATA_PASS Struct;\n”));
ATA_PASS_THROUGH_EX * PTE_SEND = (ATA_PASS_THROUGH_EX
*)(targetDeviceInfo->SEND);
PTE_SEND->Length = (USHORT)(sizeof(ATA_PASS_THROUGH_EX)+cmdBufferSize);
PTE_SEND->TimeOutValue = 10;
PTE_SEND->DataTransferLength = cmdBufferSize;
PTE_SEND->DataBufferOffset = sizeof(ATA_PASS_THROUGH_EX);
PTE_SEND->AtaFlags = ATA_FLAGS_DATA_IN | ATA_FLAGS_DRDY_REQUIRED |
ATA_FLAGS_48BIT_COMMAND;
PTE_SEND->ReservedAsUchar = 0;
KdPrint((“ATA_FormatPTEWrite >> Setting LBA Values;\n”));
IDEREGS * ir = (IDEREGS *)&(PTE_SEND->CurrentTaskFile);
IDEREGS * pir = (IDEREGS *)&(PTE_SEND->PreviousTaskFile);
//COMMANDS REMOVED
KdPrint((“ATA_FormatPTERead >> ATA_PASS Struct Complete;\n”));
}
}
//---------------------------------------------