Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1274 lines
30 KiB

/*++
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