class2.c
来自「ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机」· C语言 代码 · 共 2,425 行 · 第 1/5 页
C
2,425 行
srb->Function = SRB_FUNCTION_RELEASE_QUEUE;
}
//
// Build the asynchronous request to be sent to the port driver.
//
irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if(irp == NULL) {
//
// We have no better way of dealing with this at the moment
//
KeBugCheck((ULONG)0x0000002DL);
}
IoSetCompletionRoutine(irp,
(PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
context,
TRUE,
TRUE,
TRUE);
irpStack = IoGetNextIrpStackLocation(irp);
irpStack->MajorFunction = IRP_MJ_SCSI;
srb->OriginalRequest = irp;
//
// Store the SRB address in next stack for port driver.
//
irpStack->Parameters.Scsi.Srb = srb;
//
// Since this routine can cause outstanding requests to be completed, and
// calling a completion routine at < DISPATCH_LEVEL is dangerous (if they
// call IoStartNextPacket we will bugcheck) raise up to dispatch level before
// issuing the request
//
currentIrql = KeGetCurrentIrql();
if(currentIrql < DISPATCH_LEVEL) {
KeRaiseIrql(DISPATCH_LEVEL, ¤tIrql);
IoCallDriver(deviceExtension->PortDeviceObject, irp);
KeLowerIrql(currentIrql);
} else {
IoCallDriver(deviceExtension->PortDeviceObject, irp);
}
return;
} // end ScsiClassReleaseQueue()
VOID
STDCALL
StartUnit(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Send command to SCSI unit to start or power up.
Because this command is issued asynchronounsly, that is, without
waiting on it to complete, the IMMEDIATE flag is not set. This
means that the CDB will not return until the drive has powered up.
This should keep subsequent requests from being submitted to the
device before it has completely spun up.
This routine is called from the InterpretSense routine, when a
request sense returns data indicating that a drive must be
powered up.
Arguments:
DeviceObject - The device object for the logical unit with
the frozen queue.
Return Value:
None.
--*/
{
PIO_STACK_LOCATION irpStack;
PIRP irp;
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PSCSI_REQUEST_BLOCK srb;
PCOMPLETION_CONTEXT context;
PCDB cdb;
//
// Allocate Srb from nonpaged pool.
//
context = ExAllocatePool(NonPagedPoolMustSucceed,
sizeof(COMPLETION_CONTEXT));
//
// Save the device object in the context for use by the completion
// routine.
//
context->DeviceObject = DeviceObject;
srb = &context->Srb;
//
// Zero out srb.
//
RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
//
// Write length to SRB.
//
srb->Length = SCSI_REQUEST_BLOCK_SIZE;
//
// Set up SCSI bus address.
//
srb->PathId = deviceExtension->PathId;
srb->TargetId = deviceExtension->TargetId;
srb->Lun = deviceExtension->Lun;
srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
//
// Set timeout value large enough for drive to spin up.
//
srb->TimeOutValue = START_UNIT_TIMEOUT;
//
// Set the transfer length.
//
srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
//
// Build the start unit CDB.
//
srb->CdbLength = 6;
cdb = (PCDB)srb->Cdb;
cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
cdb->START_STOP.Start = 1;
cdb->START_STOP.LogicalUnitNumber = srb->Lun;
//
// Build the asynchronous request to be sent to the port driver.
// Since this routine is called from a DPC the IRP should always be
// available.
//
irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
IoSetCompletionRoutine(irp,
(PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
context,
TRUE,
TRUE,
TRUE);
irpStack = IoGetNextIrpStackLocation(irp);
irpStack->MajorFunction = IRP_MJ_SCSI;
srb->OriginalRequest = irp;
//
// Store the SRB address in next stack for port driver.
//
irpStack->Parameters.Scsi.Srb = srb;
//
// Call the port driver with the IRP.
//
IoCallDriver(deviceExtension->PortDeviceObject, irp);
return;
} // end StartUnit()
NTSTATUS
STDCALL
ScsiClassAsynchronousCompletion(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context
)
/*++
Routine Description:
This routine is called when an asynchronous I/O request
which was issused by the class driver completes. Examples of such requests
are release queue or START UNIT. This routine releases the queue if
necessary. It then frees the context and the IRP.
Arguments:
DeviceObject - The device object for the logical unit; however since this
is the top stack location the value is NULL.
Irp - Supplies a pointer to the Irp to be processed.
Context - Supplies the context to be used to process this request.
Return Value:
None.
--*/
{
PCOMPLETION_CONTEXT context = Context;
PSCSI_REQUEST_BLOCK srb;
srb = &context->Srb;
//
// If this is an execute srb, then check the return status and make sure.
// the queue is not frozen.
//
if (srb->Function == SRB_FUNCTION_EXECUTE_SCSI) {
//
// Check for a frozen queue.
//
if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
//
// Unfreeze the queue getting the device object from the context.
//
ScsiClassReleaseQueue(context->DeviceObject);
}
}
//
// Free the context and the Irp.
//
if (Irp->MdlAddress != NULL) {
MmUnlockPages(Irp->MdlAddress);
IoFreeMdl(Irp->MdlAddress);
Irp->MdlAddress = NULL;
}
ExFreePool(context);
IoFreeIrp(Irp);
//
// Indicate the I/O system should stop processing the Irp completion.
//
return STATUS_MORE_PROCESSING_REQUIRED;
} // ScsiClassAsynchronousCompletion()
VOID
STDCALL
ScsiClassSplitRequest(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN ULONG MaximumBytes
)
/*++
Routine Description:
Break request into smaller requests. Each new request will be the
maximum transfer size that the port driver can handle or if it
is the final request, it may be the residual size.
The number of IRPs required to process this request is written in the
current stack of the original IRP. Then as each new IRP completes
the count in the original IRP is decremented. When the count goes to
zero, the original IRP is completed.
Arguments:
DeviceObject - Pointer to the class device object to be addressed.
Irp - Pointer to Irp the orginal request.
Return Value:
None.
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
PVOID dataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
ULONG dataLength = MaximumBytes;
ULONG irpCount = (transferByteCount + MaximumBytes - 1) / MaximumBytes;
ULONG i;
PSCSI_REQUEST_BLOCK srb;
DebugPrint((2, "ScsiClassSplitRequest: Requires %d IRPs\n", irpCount));
DebugPrint((2, "ScsiClassSplitRequest: Original IRP %lx\n", Irp));
//
// If all partial transfers complete successfully then the status and
// bytes transferred are already set up. Failing a partial-transfer IRP
// will set status to error and bytes transferred to 0 during
// IoCompletion. Setting bytes transferred to 0 if an IRP fails allows
// asynchronous partial transfers. This is an optimization for the
// successful case.
//
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = transferByteCount;
//
// Save number of IRPs to complete count on current stack
// of original IRP.
//
nextIrpStack->Parameters.Others.Argument1 = (PVOID) irpCount;
for (i = 0; i < irpCount; i++) {
PIRP newIrp;
PIO_STACK_LOCATION newIrpStack;
//
// Allocate new IRP.
//
newIrp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (newIrp == NULL) {
DebugPrint((1,"ScsiClassSplitRequest: Can't allocate Irp\n"));
//
// If an Irp can't be allocated then the orginal request cannot
// be executed. If this is the first request then just fail the
// orginal request; otherwise just return. When the pending
// requests complete, they will complete the original request.
// In either case set the IRP status to failure.
//
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Information = 0;
if (i == 0) {
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
return;
}
DebugPrint((2, "ScsiClassSplitRequest: New IRP %lx\n", newIrp));
//
// Write MDL address to new IRP. In the port driver the SRB data
// buffer field is used as an offset into the MDL, so the same MDL
// can be used for each partial transfer. This saves having to build
// a new MDL for each partial transfer.
//
newIrp->MdlAddress = Irp->MdlAddress;
//
// At this point there is no current stack. IoSetNextIrpStackLocation
// will make the first stack location the current stack so that the
// SRB address can be written there.
//
IoSetNextIrpStackLocation(newIrp);
newIrpStack = IoGetCurrentIrpStackLocation(newIrp);
newIrpStack->MajorFunction = currentIrpStack->MajorFunction;
newIrpStack->Parameters.Read.Length = dataLength;
newIrpStack->Parameters.Read.ByteOffset = startingOffset;
newIrpStack->DeviceObject = DeviceObject;
//
// Build SRB and CDB.
//
ScsiClassBuildRequest(DeviceObject, newIrp);
//
// Adjust SRB for this partial transfer.
//
newIrpStack = IoGetNextIrpStackLocation(newIrp);
srb = newIrpStack->Parameters.Others.Argument1;
srb->DataBuffer = dataBuffer;
//
// Write original IRP address to new IRP.
//
newIrp->AssociatedIrp.MasterIrp = Irp;
//
// Set the completion routine to ScsiClassIoCompleteAssociated.
//
IoSetCompletionRoutine(newIrp,
ScsiClassIoCompleteAssociated,
srb,
TRUE,
TRUE,
TRUE);
//
// Call port driver with new request.
//
IoCallDriver(deviceExtension->PortDeviceObject, newIrp);
//
// Set up for next request.
//
dataBuffer = (PCHAR)dataBuffer + MaximumBytes;
transferByteCount -= MaximumBytes;
if (transferByteCount > MaximumBytes) {
dataLength = MaximumBytes;
} else {
dataLength = transferByteCount;
}
//
// Adjust disk byte offset.
//
startingOffset.QuadPart = startingOffset.QuadPart + MaximumBytes;
}
return;
} // end ScsiClassSplitRequest()
NTSTATUS
STDCALL
ScsiClassIoComplete(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
This routine executes when the port driver has completed a request.
It looks at the SRB status in the completing SRB and if not success
it checks for valid request sense buffer information. If valid, the
info is used to update status with more precise message of type of
error. This routine deallocates the SRB.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?