class2.c
来自「一个类似windows」· C语言 代码 · 共 2,461 行 · 第 1/5 页
C
2,461 行
Srb->SenseInfoBuffer = (SENSE_DATA*)ROUND_UP((ULONG_PTR)(Srb + 1), SENSEINFO_ALIGNMENT);
Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
Srb->DataBuffer = BufferAddress;
Srb->DataTransferLength = BufferLength;
Srb->ScsiStatus = 0;
Srb->SrbStatus = 0;
Srb->NextSrb = NULL;
if (BufferAddress != NULL)
{
if (Irp->MdlAddress == NULL)
{
/* Allocate an MDL */
if (!IoAllocateMdl(BufferAddress,
BufferLength,
FALSE,
FALSE,
Irp))
{
DPRINT("Mdl-Allocation failed\n");
return(STATUS_INSUFFICIENT_RESOURCES);
}
MmBuildMdlForNonPagedPool(Irp->MdlAddress);
}
/* Set data direction */
Srb->SrbFlags = (WriteToDevice) ? SRB_FLAGS_DATA_OUT : SRB_FLAGS_DATA_IN;
}
else
{
/* Set data direction */
Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
}
/* Set the retry counter */
Stack = IoGetCurrentIrpStackLocation(Irp);
Stack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
/* Set the completion routine */
IoSetCompletionRoutine(Irp,
ScsiClassIoComplete,
Srb,
TRUE,
TRUE,
TRUE);
/* Attach Srb to the Irp */
Stack = IoGetNextIrpStackLocation(Irp);
Stack->MajorFunction = IRP_MJ_SCSI;
Stack->Parameters.Scsi.Srb = Srb;
Srb->OriginalRequest = Irp;
/* Call the port driver */
return(IoCallDriver(DeviceExtension->PortDeviceObject,
Irp));
}
/*
* @implemented
*/
NTSTATUS STDCALL
ScsiClassSendSrbSynchronous(PDEVICE_OBJECT DeviceObject,
PSCSI_REQUEST_BLOCK Srb,
PVOID BufferAddress,
ULONG BufferLength,
BOOLEAN WriteToDevice)
{
PDEVICE_EXTENSION DeviceExtension;
IO_STATUS_BLOCK IoStatusBlock;
PIO_STACK_LOCATION IrpStack;
ULONG RequestType;
BOOLEAN Retry;
ULONG RetryCount;
KEVENT Event;
PIRP Irp;
NTSTATUS Status;
LARGE_INTEGER RetryWait;
DPRINT("ScsiClassSendSrbSynchronous() called\n");
RetryCount = MAXIMUM_RETRIES;
DeviceExtension = DeviceObject->DeviceExtension;
Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
Srb->PathId = DeviceExtension->PathId;
Srb->TargetId = DeviceExtension->TargetId;
Srb->Lun = DeviceExtension->Lun;
Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
Srb->SenseInfoBuffer = ExAllocatePool(NonPagedPool,
SENSE_BUFFER_SIZE);
if (Srb->SenseInfoBuffer == NULL)
return(STATUS_INSUFFICIENT_RESOURCES);
if (BufferAddress == NULL)
{
BufferLength = 0;
RequestType = IOCTL_SCSI_EXECUTE_NONE;
Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
}
else
{
if (WriteToDevice == TRUE)
{
RequestType = IOCTL_SCSI_EXECUTE_IN; // needs _in_ to the device
Srb->SrbFlags = SRB_FLAGS_DATA_OUT; // needs _out_ from the caller
}
else
{
RequestType = IOCTL_SCSI_EXECUTE_OUT;
Srb->SrbFlags = SRB_FLAGS_DATA_IN;
}
}
Srb->DataBuffer = BufferAddress;
TryAgain:
Srb->DataTransferLength = BufferLength;
KeInitializeEvent(&Event,
NotificationEvent,
FALSE);
Irp = IoBuildDeviceIoControlRequest(RequestType,
DeviceExtension->PortDeviceObject,
NULL,
0,
BufferAddress,
BufferLength,
TRUE,
&Event,
&IoStatusBlock);
if (Irp == NULL)
{
DPRINT("IoBuildDeviceIoControlRequest() failed\n");
ExFreePool(Srb->SenseInfoBuffer);
Srb->SenseInfoBuffer = NULL;
Srb->SenseInfoBufferLength = 0;
return(STATUS_INSUFFICIENT_RESOURCES);
}
/* Attach Srb to the Irp */
IrpStack = IoGetNextIrpStackLocation(Irp);
IrpStack->Parameters.Scsi.Srb = Srb;
Srb->OriginalRequest = Irp;
/* Call the SCSI port driver */
Status = IoCallDriver(DeviceExtension->PortDeviceObject,
Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event,
Suspended,
KernelMode,
FALSE,
NULL);
}
if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS)
{
/* Release the queue if it is frozen */
if (Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN)
{
ScsiClassReleaseQueue (DeviceObject);
}
/* Get more detailed status information */
Retry = ScsiClassInterpretSenseInfo(DeviceObject,
Srb,
IRP_MJ_SCSI,
0,
MAXIMUM_RETRIES - RetryCount,
&Status);
if (Retry == TRUE)
{
DPRINT("Try again (RetryCount %lu)\n", RetryCount);
/* FIXME: Wait a little if we got a timeout error */
if (RetryCount--)
{
RetryWait.QuadPart = - RETRY_WAIT;
KeDelayExecutionThread(KernelMode, FALSE, &RetryWait);
goto TryAgain;
}
}
}
else
{
Status = STATUS_SUCCESS;
}
ExFreePool(Srb->SenseInfoBuffer);
DPRINT("ScsiClassSendSrbSynchronous() done\n");
return(Status);
}
/*
* @implemented
*/
VOID STDCALL
ScsiClassSplitRequest(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN ULONG MaximumBytes)
{
PDEVICE_EXTENSION DeviceExtension;
PIO_STACK_LOCATION CurrentStack;
PIO_STACK_LOCATION NextStack;
PIO_STACK_LOCATION NewStack;
PSCSI_REQUEST_BLOCK Srb;
LARGE_INTEGER Offset;
PIRP NewIrp;
PVOID DataBuffer;
ULONG TransferLength;
ULONG RequestCount;
ULONG DataLength;
ULONG i;
DPRINT("ScsiClassSplitRequest(DeviceObject %lx Irp %lx MaximumBytes %lu)\n",
DeviceObject, Irp, MaximumBytes);
DeviceExtension = DeviceObject->DeviceExtension;
CurrentStack = IoGetCurrentIrpStackLocation(Irp);
NextStack = IoGetNextIrpStackLocation(Irp);
DataBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
/* Initialize transfer data for first request */
Offset = CurrentStack->Parameters.Read.ByteOffset;
TransferLength = CurrentStack->Parameters.Read.Length;
/* Set the result length */
Irp->IoStatus.Information = TransferLength;
DataLength = MaximumBytes;
RequestCount = ROUND_UP(TransferLength, MaximumBytes) / MaximumBytes;
/* Save request count in the original IRP */
NextStack->Parameters.Others.Argument1 = (PVOID)RequestCount;
DPRINT("RequestCount %lu\n", RequestCount);
for (i = 0; i < RequestCount; i++)
{
/* Create a new IRP */
NewIrp = IoAllocateIrp(DeviceObject->StackSize,
FALSE);
if (NewIrp == NULL)
{
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Information = 0;
if (i == 0)
IoCompleteRequest(Irp,
IO_NO_INCREMENT);
return;
}
/* Initialize the new IRP */
NewIrp->MdlAddress = Irp->MdlAddress;
NewIrp->Tail.Overlay.Thread = PsGetCurrentThread();
IoSetNextIrpStackLocation(NewIrp);
NewStack = IoGetCurrentIrpStackLocation(NewIrp);
NewStack->MajorFunction = CurrentStack->MajorFunction;
NewStack->Parameters.Read.ByteOffset = Offset;
NewStack->Parameters.Read.Length = DataLength;
NewStack->DeviceObject = DeviceObject;
ScsiClassBuildRequest(DeviceObject,
NewIrp);
NewStack = IoGetNextIrpStackLocation(NewIrp);
Srb = NewStack->Parameters.Others.Argument1;
Srb->DataBuffer = DataBuffer;
NewIrp->AssociatedIrp.MasterIrp = Irp;
/* Initialize completion routine */
IoSetCompletionRoutine(NewIrp,
ScsiClassIoCompleteAssociated,
Srb,
TRUE,
TRUE,
TRUE);
/* Send the new IRP down to the port driver */
IoCallDriver(DeviceExtension->PortDeviceObject,
NewIrp);
/* Adjust transfer data for next request */
DataBuffer = (PCHAR)DataBuffer + MaximumBytes;
TransferLength -= MaximumBytes;
DataLength = (TransferLength > MaximumBytes) ? MaximumBytes : TransferLength;
Offset.QuadPart = Offset.QuadPart + MaximumBytes;
}
}
/* INTERNAL FUNCTIONS *******************************************************/
static NTSTATUS STDCALL
ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PDEVICE_EXTENSION DeviceExtension;
DPRINT("ScsiClassCreateClose() called\n");
DeviceExtension = DeviceObject->DeviceExtension;
if (DeviceExtension->ClassCreateClose)
return(DeviceExtension->ClassCreateClose(DeviceObject,
Irp));
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return(STATUS_SUCCESS);
}
static NTSTATUS STDCALL
ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PDEVICE_EXTENSION DeviceExtension;
PIO_STACK_LOCATION IrpStack;
ULONG MaximumTransferLength;
ULONG CurrentTransferLength;
ULONG MaximumTransferPages;
ULONG CurrentTransferPages;
NTSTATUS Status;
DPRINT("ScsiClassReadWrite() called\n");
DeviceExtension = DeviceObject->DeviceExtension;
IrpStack = IoGetCurrentIrpStackLocation(Irp);
DPRINT("Relative Offset: %I64u Length: %lu\n",
IrpStack->Parameters.Read.ByteOffset.QuadPart,
IrpStack->Parameters.Read.Length);
MaximumTransferLength = DeviceExtension->PortCapabilities->MaximumTransferLength;
MaximumTransferPages = DeviceExtension->PortCapabilities->MaximumPhysicalPages;
CurrentTransferLength = IrpStack->Parameters.Read.Length;
if ((DeviceObject->Flags & DO_VERIFY_VOLUME) &&
!(IrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME))
{
IoSetHardErrorOrVerifyDevice(Irp,
DeviceObject);
Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp,
IO_NO_INCREMENT);
return(STATUS_VERIFY_REQUIRED);
}
/* Class driver verifies the IRP */
Status = DeviceExtension->ClassReadWriteVerification(DeviceObject,
Irp);
if (!NT_SUCCESS(Status))
{
IoCompleteRequest(Irp,
IO_NO_INCREMENT);
return(Status);
}
else if (Status == STATUS_PENDING)
{
IoMarkIrpPending(Irp);
return(STATUS_PENDING);
}
/* Finish a zero-byte transfer */
if (CurrentTransferLength == 0)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp,
IO_NO_INCREMENT);
return(STATUS_SUCCESS);
}
if (DeviceExtension->ClassStartIo != NULL)
{
DPRINT("ScsiClassReadWrite() starting packet\n");
IoMarkIrpPending(Irp);
IoStartPacket(DeviceObject,
Irp,
NULL,
NULL);
return(STATUS_PENDING);
}
/* Adjust partition-relative starting offset to absolute offset */
IrpStack->Parameters.Read.ByteOffset.QuadPart +=
(DeviceExtension->StartingOffset.QuadPart + DeviceExtension->DMByteSkew);
/* Calculate number of pages in this transfer */
CurrentTransferPages =
ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
IrpStack->Parameters.Read.Length);
if (CurrentTransferLength > MaximumTransferLength ||
CurrentTransferPages > MaximumTransferPages)
{
DPRINT("Split current request: MaximumTransferLength %lu CurrentTransferLength %lu\n",
MaximumTransferLength, CurrentTransferLength);
/* Adjust the maximum transfer length */
CurrentTransferPages = DeviceExtension->PortCapabilities->MaximumPhysicalPages;
if (MaximumTransferLength > CurrentTransferPages * PAGE_SIZE)
MaximumTransferLength = CurrentTransferPages * PAGE_SIZE;
if (MaximumTransferLength == 0)
MaximumTransferLength = PAGE_SIZE;
IoMarkIrpPending(Irp);
/* Split current request */
ScsiClassSplitRequest(DeviceObject,
Irp,
MaximumTransferLength);
return(STATUS_PENDING);
}
ScsiClassBuildRequest(DeviceObject,
Irp);
DPRINT("ScsiClassReadWrite() done\n");
/* Call the port driver */
return(IoCallDriver(DeviceExtension->PortDeviceObject,
Irp));
}
static NTSTATUS STDCALL
ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PDEVICE_EXTENSION DeviceExtension;
DPRINT("ScsiClassDeviceDispatch() called\n");
DeviceExtension = DeviceObject->DeviceExtension;
if (DeviceExtension->ClassDeviceControl)
{
return(DeviceExtension->ClassDeviceControl(DeviceObject, Irp));
}
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return(STATUS_INVALID_DEVICE_REQUEST);
}
static NTSTATUS STDCALL
ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PDEVICE_EXTENSION DeviceExtension;
DPRINT("ScsiClassShutdownFlush() called\n");
DeviceExtension = DeviceObject->DeviceExtension;
if (DeviceExtension->ClassShutdownFlush)
{
return(DeviceExtension->ClassShutdownFlush(DeviceObject, Irp));
}
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?