|
|
/*++
Copyright (C) Microsoft Corporation, 2002
Module Name:
passthru.c
Abstract:
This file contains routines to handle IOCTL_ATA_PASS_THROUGH
Authors:
Krishnan Varadarajan (krishvar)
Environment:
kernel mode only
Notes:
This module implements ATA passthru.
Revision History:
--*/
#include "ideport.h"
#define DataIn(ataPassThrough) \
(ataPassThrough->AtaFlags & ATA_FLAGS_DATA_IN)
#define DataOut(ataPassThrough) \
(ataPassThrough->AtaFlags & ATA_FLAGS_DATA_OUT)
NTSTATUS IdeAtaPassThroughValidateInput ( IN PDEVICE_OBJECT Pdo, IN PIRP Irp, IN BOOLEAN Direct );
NTSTATUS IdeAtaPassThroughSyncCompletion ( PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context );
VOID IdeAtaPassThroughMarshalResults( IN PSCSI_REQUEST_BLOCK Srb, IN PATA_PASS_THROUGH_EX AtaPassThrough, IN BOOLEAN Direct, OUT PIO_STATUS_BLOCK IoStatus );
#if defined (_WIN64)
VOID IdeTranslateAtaPassThrough32To64( IN PATA_PASS_THROUGH_EX32 AtaPassThrough32, IN OUT PATA_PASS_THROUGH_EX AtaPassThrough64 );
VOID IdeTranslateAtaPassThrough64To32( IN PATA_PASS_THROUGH_EX AtaPassThrough64, IN OUT PATA_PASS_THROUGH_EX32 AtaPassThrough32 ); #endif
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, IdeHandleAtaPassThroughIoctl)
#pragma alloc_text(PAGE, IdeAtaPassThroughSetPortAddress)
#pragma alloc_text(PAGE, IdeAtaPassThroughGetPortAddress)
#pragma alloc_text(PAGE, IdeAtaPassThroughValidateInput)
#pragma alloc_text(PAGE, IdeAtaPassThroughSendSynchronous)
#pragma alloc_text(PAGE, IdeAtaPassThroughMarshalResults)
#if defined (_WIN64)
#pragma alloc_text(PAGE, IdeTranslateAtaPassThrough32To64)
#pragma alloc_text(PAGE, IdeTranslateAtaPassThrough64To32)
#endif
#endif
NTSTATUS IdeAtaPassThroughSetPortAddress ( PIRP Irp, UCHAR PathId, UCHAR TargetId, UCHAR Lun ) /*++
Routine Description:
Sets the address fields in the ataPassThrough structure embedded in the irp. Arguments:
Irp : The ata passthrough irp PathId : PathId of the pdo. TargetId : Pdo's targetId. Lun : Lun represented by the pdo.
Return Valud:
STATUS_SUCCESS if the operation succeeded. STATUS_INVALID_PARAMETER otherwise.
--*/ { PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status; ULONG requiredSize; ULONG inputLength;
PAGED_CODE();
inputLength = irpStack->Parameters.DeviceIoControl.InputBufferLength; requiredSize = sizeof(ATA_PASS_THROUGH_EX);
#if defined (_WIN64)
if (IoIs32bitProcess(Irp)) { requiredSize = sizeof(ATA_PASS_THROUGH_EX32); } #endif
if (inputLength < requiredSize) {
status = STATUS_INVALID_PARAMETER;
} else {
PATA_PASS_THROUGH_EX ataPassThrough;
ataPassThrough = Irp->AssociatedIrp.SystemBuffer; ataPassThrough->PathId = PathId; ataPassThrough->TargetId = TargetId; ataPassThrough->Lun = Lun;
status = STATUS_SUCCESS; }
return status; }
NTSTATUS IdeAtaPassThroughGetAddress( IN PIRP Irp, OUT PUCHAR PathId, OUT PUCHAR TargetId, OUT PUCHAR Lun ) /*++
Routine Description:
This routine retrieves the address of the device to witch the passthrough request is to be sent.
Arguments:
Irp - Supplies a pointer to the IRP that contains the SCSI_PASS_THROUGH structure.
PathId - Pointer to the PathId of the addressed device.
TargetId - Pointer to the TargetId of the addressed device.
Lun - Pointer to the logical unit number of the addressed device.
Return Value:
Returns a status indicating the success or failure of the operation.
--*/ { PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status; ULONG requiredSize; ULONG inputLength;
PAGED_CODE();
inputLength = irpStack->Parameters.DeviceIoControl.InputBufferLength; requiredSize = sizeof(ATA_PASS_THROUGH_EX);
#if defined (_WIN64)
if (IoIs32bitProcess(Irp)) { requiredSize = sizeof(ATA_PASS_THROUGH_EX32); } #endif
if (inputLength < requiredSize) {
status = STATUS_INVALID_PARAMETER;
} else {
PATA_PASS_THROUGH_EX ataPassThrough;
ataPassThrough = Irp->AssociatedIrp.SystemBuffer;
*PathId = ataPassThrough->PathId; *TargetId = ataPassThrough->TargetId; *Lun = ataPassThrough->Lun; status = STATUS_SUCCESS; }
return status; }
NTSTATUS IdeHandleAtaPassThroughIoctl ( PFDO_EXTENSION FdoExtension, PIRP RequestIrp, BOOLEAN Direct ) /*++
Routine Description:
This routine handles IOCTL_ATA_PASS_THROUGH and its DIRECT version. Arguments:
FdoExtension : RequestIrp : The pass through ioctl request Direct : Indicates whether it is direct or not. Return Value:
Status of the operation.
--*/ { BOOLEAN dataIn; NTSTATUS status; PATA_PASS_THROUGH_EX ataPassThrough; PUCHAR passThroughBuffer; PIO_STACK_LOCATION irpStack; PPDO_EXTENSION pdoExtension; UCHAR pathId, targetId, lun; PSCSI_REQUEST_BLOCK srb; PUCHAR buffer; ULONG bufferOffset; ULONG length; ULONG pages; PIRP irp;
#if defined (_WIN64)
ATA_PASS_THROUGH_EX ataPassThrough64; #endif
PAGED_CODE();
irp = NULL; srb = NULL; pdoExtension = NULL;
//
// get the device address
//
status = IdeAtaPassThroughGetAddress (RequestIrp, &pathId, &targetId, &lun );
if (!NT_SUCCESS(status)) {
goto GetOut; }
//
// Get a reference to the pdo
//
pdoExtension = RefLogicalUnitExtensionWithTag( FdoExtension, pathId, targetId, lun, FALSE, RequestIrp );
if (pdoExtension == NULL) {
status = STATUS_INVALID_PARAMETER; goto GetOut; }
//
// validate the system buffer in the request irp. This comes
// from user mode. So every parameter needs to be validated.
//
status = IdeAtaPassThroughValidateInput (pdoExtension->DeviceObject, RequestIrp, Direct );
if (!NT_SUCCESS(status)) {
goto GetOut; }
//
// the system buffer has been validated. Get a pointer to it
//
ataPassThrough = RequestIrp->AssociatedIrp.SystemBuffer;
//
// we need to keep the pointer to the system buffer since
// ataPassThrough could be modified to point to a structure
// allocated on the stack (in WIN64 case)
//
passThroughBuffer = (PUCHAR) ataPassThrough;
//
// If the irp is from a 32-bit app running on a 64 bit system
// then we need to take into account the size difference in the
// structure. Create a new 64 bit structure and copy over the
// fields.
//
#if defined (_WIN64)
if (IoIs32bitProcess(RequestIrp)) {
PATA_PASS_THROUGH_EX32 ataPassThrough32;
ataPassThrough32 = RequestIrp->AssociatedIrp.SystemBuffer;
IdeTranslateAtaPassThrough32To64( ataPassThrough32, &ataPassThrough64 );
ataPassThrough = &ataPassThrough64; } #endif
//
// determine the transfer length and the data buffer
//
if (ataPassThrough->DataTransferLength == 0) {
length = 0; buffer = NULL; bufferOffset = 0;
} else if (Direct == TRUE) {
length = (ULONG) ataPassThrough->DataTransferLength; buffer = (PUCHAR) ataPassThrough->DataBufferOffset; bufferOffset = 0;
} else {
length = (ULONG) ataPassThrough->DataBufferOffset + ataPassThrough->DataTransferLength; buffer = (PUCHAR) passThroughBuffer; bufferOffset = (ULONG)ataPassThrough->DataBufferOffset; }
//
// Check if the request is too big for the adapter.
//
pages = ADDRESS_AND_SIZE_TO_SPAN_PAGES( buffer + bufferOffset, ataPassThrough->DataTransferLength);
if ((ataPassThrough->DataTransferLength != 0) && ((pages > FdoExtension->Capabilities.MaximumPhysicalPages) || (ataPassThrough->DataTransferLength > FdoExtension->Capabilities.MaximumTransferLength))) { status = STATUS_INVALID_PARAMETER; goto GetOut; }
//
// setup the irp for ata pass through. The ioctl is method_buffered,
// but the data buffer could be a user mode one if it is the direct ioctl.
// determine the access mode accordingly
//
irp = IdeAtaPassThroughSetupIrp( pdoExtension->DeviceObject, buffer, length, (Direct ? UserMode : KernelMode), DataIn(ataPassThrough) ? TRUE : FALSE );
if (irp == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES; goto GetOut; }
//
// setup the srb. Use the right data offset for the databuffer.
// Note that the mdl is for the whole buffer (including the header)
//
srb = IdeAtaPassThroughSetupSrb (pdoExtension, (buffer+bufferOffset), ataPassThrough->DataTransferLength, ataPassThrough->TimeOutValue, ataPassThrough->AtaFlags, ataPassThrough->CurrentTaskFile, ataPassThrough->PreviousTaskFile );
if (srb == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES; goto GetOut; }
//
// initialize irpstack
//
irpStack = IoGetNextIrpStackLocation(irp); irpStack->MajorFunction = IRP_MJ_SCSI; irpStack->Parameters.Scsi.Srb = srb;
srb->OriginalRequest = irp;
//
// send it to our pdo synchronously
//
status = IdeAtaPassThroughSendSynchronous (pdoExtension->DeviceObject, irp);
//
// set the status
//
RequestIrp->IoStatus.Status = status;
//
// marshal the results
//
IdeAtaPassThroughMarshalResults (srb, ataPassThrough, Direct, &(RequestIrp->IoStatus) );
//
// copy back the results to the original 32 bit
// structure if necessary
//
#if defined (_WIN64)
if (IoIs32bitProcess(RequestIrp)) {
PATA_PASS_THROUGH_EX32 ataPassThrough32;
ataPassThrough32 = RequestIrp->AssociatedIrp.SystemBuffer;
IdeTranslateAtaPassThrough64To32 ( ataPassThrough, ataPassThrough32 ); } #endif
//
// return the status of the operation
//
status = RequestIrp->IoStatus.Status;
GetOut:
if (irp) {
IdeAtaPassThroughFreeIrp(irp); irp = NULL; }
if (srb) {
IdeAtaPassThroughFreeSrb(srb); srb = NULL; }
if (pdoExtension) {
UnrefLogicalUnitExtensionWithTag( FdoExtension, pdoExtension, RequestIrp ); pdoExtension = NULL; }
return status; }
NTSTATUS IdeAtaPassThroughValidateInput ( IN PDEVICE_OBJECT Pdo, IN PIRP Irp, IN BOOLEAN Direct ) /*++
Routine Description:
This routine validates the caller-supplied data and initializes the PORT_PASSTHROUGH_INFO structure.
Arguments:
PassThroughInfo - Supplies a pointer to a SCSI_PASSTHROUGH_INFO structure. Irp - Supplies a pointer to the IRP.
Direct - Supplies a boolean that indicates whether this is a SCSI_PASS_THROUGH_DIRECT request.
Return Value:
Returns a status indicating the success or failure of the operation.
--*/ { NTSTATUS status; ULONG outputLength; ULONG inputLength; PIO_STACK_LOCATION irpStack; PATA_PASS_THROUGH_EX ataPassThroughEx;
#if defined (_WIN64)
ATA_PASS_THROUGH_EX ataPassThrough64; #endif
PAGED_CODE();
irpStack = IoGetCurrentIrpStackLocation(Irp); outputLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength; inputLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
//
// For WIN64, a passthrough request from a 32-bit application requires
// us to perform a translation on the supplied SCSI_PASS_THROUGH structure.
// This is required because the layout of the 32-bit structure does not
// match that of a 64-bit structure. In this case, we translate the
// supplied 32-bit structure into a stack-allocated 64-bit structure which
// will be used to process the pass through request.
//
#if defined (_WIN64)
if (IoIs32bitProcess(Irp)) {
PATA_PASS_THROUGH_EX32 ataPassThrough32;
//
// the struct should atleast be as big as ATA_PASS_THROUGH_EX32
//
if (inputLength < sizeof(ATA_PASS_THROUGH_EX32)){ return STATUS_INVALID_PARAMETER; }
ataPassThrough32 = Irp->AssociatedIrp.SystemBuffer;
//
// The length field should match the size
// of the structure
//
if (Direct == FALSE) {
if (ataPassThrough32->Length != sizeof(ATA_PASS_THROUGH_EX32)) { return STATUS_REVISION_MISMATCH; }
} else {
if (ataPassThrough32->Length != sizeof(ATA_PASS_THROUGH_DIRECT32)) { return STATUS_REVISION_MISMATCH; } }
//
// translate the structure to the 64 bit version
//
IdeTranslateAtaPassThrough32To64( ataPassThrough32, &ataPassThrough64 );
ataPassThroughEx = &ataPassThrough64;
} else { #endif
//
// the struct should atleast be as big as ATA_PASS_THROUGH_EX32
//
if (inputLength < sizeof(ATA_PASS_THROUGH_EX)){ return(STATUS_INVALID_PARAMETER); }
ataPassThroughEx = Irp->AssociatedIrp.SystemBuffer;
//
// The length field should match the size
// of the structure
//
if (Direct == FALSE) {
if (ataPassThroughEx->Length != sizeof(ATA_PASS_THROUGH_EX)) { return STATUS_REVISION_MISMATCH; }
} else {
if (ataPassThroughEx->Length != sizeof(ATA_PASS_THROUGH_DIRECT)) { return STATUS_REVISION_MISMATCH; } } #if defined (_WIN64)
} #endif
if (!Direct) {
//
// Data buffer offset should be greater than the size of the pass
// through structure.
//
if (ataPassThroughEx->Length > ataPassThroughEx->DataBufferOffset && ataPassThroughEx->DataTransferLength != 0) { return STATUS_INVALID_PARAMETER; }
//
// If this command is sending data to the device. Make sure the data
// buffer lies entirely within the supplied input buffer.
//
if (DataOut(ataPassThroughEx)) {
if ((ataPassThroughEx->DataBufferOffset > inputLength) || ((ataPassThroughEx->DataBufferOffset + ataPassThroughEx->DataTransferLength) > inputLength)) { return STATUS_INVALID_PARAMETER; } }
//
// If this command is retrieving data from the device, make sure the
// data buffer lies entirely within the supplied output buffer.
//
if (DataIn(ataPassThroughEx)) {
if ((ataPassThroughEx->DataBufferOffset > outputLength) || ((ataPassThroughEx->DataBufferOffset + ataPassThroughEx->DataTransferLength) > outputLength)) { return STATUS_INVALID_PARAMETER; } }
} else {
//
// Make sure the databuffer is properly aligned.
//
if (ataPassThroughEx->DataBufferOffset & Pdo->AlignmentRequirement) { return STATUS_INVALID_PARAMETER; } } //
// Validate the specified timeout value.
//
if (ataPassThroughEx->TimeOutValue == 0 || ataPassThroughEx->TimeOutValue > 30 * 60 * 60) { return STATUS_INVALID_PARAMETER; }
return STATUS_SUCCESS; }
PSCSI_REQUEST_BLOCK IdeAtaPassThroughSetupSrb ( PPDO_EXTENSION PdoExtension, PVOID DataBuffer, ULONG DataBufferLength, ULONG TimeOutValue, ULONG AtaFlags, PUCHAR CurrentTaskFile, PUCHAR PreviousTaskFile ) /*++
Routine Description:
Builds an SRB for ATA PASS THROUGH. Arguments:
PdoExtension : The pdo which the request is destined for DataBuffer : Pointer to the data buffer. DataBufferLength : The size of the data buffer TimeOutValue: The request timeout value AtaFlags : Specifies the flags for the request CurrentTaskFile : the current ata registers PreviousTaskFile: previous values for 48 bit LBA feature set
Return Value:
Pointer to an SRB if one was allocated successfully, NULL otherwise. --*/ { PSCSI_REQUEST_BLOCK srb = NULL; PIDEREGS pIdeReg;
//
// allocate the srb
//
srb = ExAllocatePool (NonPagedPool, sizeof (SCSI_REQUEST_BLOCK));
if (srb == NULL) {
return NULL; }
//
// Fill in the srb.
//
RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
srb->Length = SCSI_REQUEST_BLOCK_SIZE; srb->Function = SRB_FUNCTION_ATA_PASS_THROUGH_EX; srb->SrbStatus = SRB_STATUS_PENDING; srb->PathId = PdoExtension->PathId; srb->TargetId = PdoExtension->TargetId; srb->Lun = PdoExtension->Lun; srb->SenseInfoBufferLength = 0; srb->TimeOutValue = TimeOutValue;
if (DataBufferLength != 0) {
if (AtaFlags & ATA_FLAGS_DATA_IN) { srb->SrbFlags |= SRB_FLAGS_DATA_IN; }
if (AtaFlags & ATA_FLAGS_DATA_OUT) { srb->SrbFlags |= SRB_FLAGS_DATA_OUT; } }
srb->SrbFlags |= SRB_FLAGS_DISABLE_AUTOSENSE; srb->SrbFlags |= SRB_FLAGS_NO_QUEUE_FREEZE; srb->DataTransferLength = DataBufferLength; srb->DataBuffer = DataBuffer; srb->SenseInfoBuffer = NULL;
MARK_SRB_AS_PIO_CANDIDATE(srb);
RtlCopyMemory(srb->Cdb, CurrentTaskFile, 8 );
RtlCopyMemory((PUCHAR) (&srb->Cdb[8]), PreviousTaskFile, 8 );
pIdeReg = (PIDEREGS) (srb->Cdb);
if (AtaFlags & ATA_FLAGS_DRDY_REQUIRED) {
pIdeReg->bReserved |= ATA_PTFLAGS_STATUS_DRDY_REQUIRED; }
return srb; }
PIRP IdeAtaPassThroughSetupIrp ( PDEVICE_OBJECT DeviceObject, PVOID DataBuffer, ULONG DataBufferLength, KPROCESSOR_MODE AccessMode, BOOLEAN DataIn ) /*++
Routine Description:
Builds an Irp to handle ata pass through. Arguments:
DeviceObject : The Pdo. DataBuffer : Pointer to the data buffer. DataBufferLength: its size Access Mode: KernelMode or UserMode DataIn: indicates the direction of transfer Return Value:
PIRP if one was allocated successfully, NULL otherwise.
--*/ { PIRP irp = NULL; NTSTATUS status = STATUS_SUCCESS;
//
// allocate the irp
//
irp = IoAllocateIrp ( (CCHAR) (DeviceObject->StackSize), FALSE );
if (irp == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES; goto GetOut; }
//
// allocate the mdl if needed
//
if (DataBufferLength != 0) {
ASSERT(irp);
irp->MdlAddress = IoAllocateMdl( DataBuffer, DataBufferLength, FALSE, FALSE, (PIRP) NULL );
if (irp->MdlAddress == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES; goto GetOut; }
//
// lock the pages
//
try {
MmProbeAndLockPages( irp->MdlAddress, AccessMode, (LOCK_OPERATION) (DataIn ? IoWriteAccess : IoReadAccess) );
} except(EXCEPTION_EXECUTE_HANDLER) {
if (irp->MdlAddress != NULL) {
IoFreeMdl( irp->MdlAddress ); irp->MdlAddress = NULL; } }
if (irp->MdlAddress == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES; goto GetOut;
} else {
//
// Flush the data buffer for output. This will insure that
// the data is written back to memory.
//
KeFlushIoBuffers(irp->MdlAddress, FALSE, TRUE); } }
status = STATUS_SUCCESS;
GetOut:
if (!NT_SUCCESS(status)) {
if (irp) {
if (irp->MdlAddress) {
//
// if mdladdress is set then the probeandlock
// succeeded. So unlock it now.
//
MmUnlockPages(irp->MdlAddress);
IoFreeMdl( irp->MdlAddress ); irp->MdlAddress = NULL; }
IoFreeIrp(irp); irp = NULL; } }
return irp; }
VOID IdeAtaPassThroughFreeIrp ( PIRP Irp ) /*++
Routine Description:
Free the irp and mdl allocated by IdeAtaPassThroughSetupIrp Arguments:
Irp: Irp to be freed.
Return Value:
None. --*/ { ASSERT(Irp);
if (Irp->MdlAddress) { MmUnlockPages(Irp->MdlAddress); IoFreeMdl(Irp->MdlAddress); }
IoFreeIrp(Irp);
return; }
VOID IdeAtaPassThroughFreeSrb ( PSCSI_REQUEST_BLOCK Srb ) /*++
Routine Description:
Free the srb allocated by IdeAtaPassThroughSetupSrb Arguments:
Srb: The srb to be freed. Return Value:
None --*/ { ASSERT(Srb);
ExFreePool(Srb);
return; }
NTSTATUS IdeAtaPassThroughSyncCompletion ( PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context ) /*++
Routine Description:
The completion routine for IdeAtaPassThroughSendSynchronous. It just signals the event. Arguments: DeviceObject : Not used. Irp : Not Used Context : Event to be signalled Return Value:
STATUS_MORE_PROCESSING_REQUIRED always. --*/ { PKEVENT event = Context;
KeSetEvent (event, 0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED; }
NTSTATUS IdeAtaPassThroughSendSynchronous ( PDEVICE_OBJECT DeviceObject, PIRP Irp ) /*++
Routine Description:
Sends the irp synchronously to the PDO
Arguments:
DeviceObject : The pdo Return Value:
The irp's status --*/ { KEVENT event;
KeInitializeEvent(&event, NotificationEvent, FALSE);
IoSetCompletionRoutine (Irp, IdeAtaPassThroughSyncCompletion, &event, TRUE, TRUE, TRUE );
IoCallDriver(DeviceObject, Irp);
KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, NULL );
return Irp->IoStatus.Status; }
VOID IdeAtaPassThroughMarshalResults( IN PSCSI_REQUEST_BLOCK Srb, IN PATA_PASS_THROUGH_EX AtaPassThroughEx, IN BOOLEAN Direct, OUT PIO_STATUS_BLOCK IoStatus ) /*++
Routine Description:
Fills in the IoStatus block with the appropriate status and information length. It also updates certain fields in the atapassthroughEx structure. Arguments:
Srb: The pass through srb. AtaPassThroughEx : the pass through structure. Direct : True if it is a direct ioctl. IoStatus : The Io status block that needs to be filled in.
Return Value:
None --*/ {
PAGED_CODE();
//
// copy over the task file registers
//
RtlCopyMemory(AtaPassThroughEx->CurrentTaskFile, Srb->Cdb, 8 );
RtlCopyMemory(AtaPassThroughEx->PreviousTaskFile, (PUCHAR) (&Srb->Cdb[8]), 8 );
//
// zero out the reserved register as it is used by the
// port driver
//
AtaPassThroughEx->CurrentTaskFile[7] = 0; AtaPassThroughEx->PreviousTaskFile[7] = 0;
//
// If the srb status is buffer underrun then set the status to success.
// This insures that the data will be returned to the caller.
//
if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) { IoStatus->Status = STATUS_SUCCESS; }
//
// Set the information length
//
AtaPassThroughEx->DataTransferLength = Srb->DataTransferLength;
if (Direct == TRUE) {
//
// the data is transferred directly to the supplied data buffer
//
IoStatus->Information = AtaPassThroughEx->Length;
} else {
//
// actual data is returned
//
if (DataIn(AtaPassThroughEx) && AtaPassThroughEx->DataBufferOffset != 0) {
IoStatus->Information = AtaPassThroughEx->DataBufferOffset + AtaPassThroughEx->DataTransferLength;
} else {
IoStatus->Information = AtaPassThroughEx->Length; } }
ASSERT((Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) == 0);
return; }
#if defined (_WIN64)
VOID IdeTranslateAtaPassThrough32To64( IN PATA_PASS_THROUGH_EX32 AtaPassThrough32, IN OUT PATA_PASS_THROUGH_EX AtaPassThrough64 ) /*++
Routine Description:
This function performs that marshaling.
Arguments:
ataPassThrough32 - Supplies a pointer to a 32-bit ATA_PASS_THROUGH struct.
ataPassThrough64 - Supplies a pointer to a 64-bit ATA_PASS_THROUGH structure, into which we'll copy the marshaled 32-bit data.
Return Value:
None.
--*/ { PAGED_CODE();
//
// Copy the first set of fields out of the 32-bit structure. These
// fields all line up between the 32 & 64 bit versions.
//
// Note that we do NOT adjust the length in the srbControl. This is to
// allow the calling routine to compare the length of the actual
// control area against the offsets embedded within.
//
RtlCopyMemory(AtaPassThrough64, AtaPassThrough32, FIELD_OFFSET(ATA_PASS_THROUGH_EX, DataBufferOffset) );
//
// Copy over the Taskfile.
//
RtlCopyMemory(AtaPassThrough64->CurrentTaskFile, AtaPassThrough32->CurrentTaskFile, 8 * sizeof(UCHAR) );
RtlCopyMemory(AtaPassThrough64->PreviousTaskFile, AtaPassThrough32->PreviousTaskFile, 8 * sizeof(UCHAR) );
//
// Copy the fields that follow the ULONG_PTR.
//
AtaPassThrough64->DataBufferOffset = (ULONG_PTR)AtaPassThrough32->DataBufferOffset;
return; }
VOID IdeTranslateAtaPassThrough64To32( IN PATA_PASS_THROUGH_EX AtaPassThrough64, IN OUT PATA_PASS_THROUGH_EX32 AtaPassThrough32 ) /*++
Routine Description:
This function marshals a 64-bit version of the structure back into a 32-bit version.
Arguments:
atapassthrough64 - Supplies a pointer to a 64-bit ATA_PASS_THROUGH struct.
ataPassThrough32 - Supplies the address of a pointer to a 32-bit ATA_PASS_THROUGH structure, into which we'll copy the marshaled 64-bit data.
Return Value:
None.
--*/ { PAGED_CODE();
//
// Copy back the fields through the data offsets.
//
RtlCopyMemory(AtaPassThrough32, AtaPassThrough64, FIELD_OFFSET(ATA_PASS_THROUGH_EX, DataBufferOffset));
//
// copy over the task file
//
RtlCopyMemory(AtaPassThrough32->CurrentTaskFile, AtaPassThrough64->CurrentTaskFile, 8 * sizeof(UCHAR) );
RtlCopyMemory(AtaPassThrough32->PreviousTaskFile, AtaPassThrough64->PreviousTaskFile, 8 * sizeof(UCHAR) );
return; } #endif
|