📄 tape.c
字号:
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 device object
Irp - Pointer to Irp
Return Value:
None.
--*/
{
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
ULONG irpCount;
ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
PSCSI_REQUEST_BLOCK srb;
LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
ULONG dataLength = MaximumBytes;
PVOID dataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
LONG remainingIrps;
BOOLEAN completeOriginalIrp = FALSE;
NTSTATUS status;
ULONG i;
PAGED_CODE();
//
// Caluculate number of requests to break this IRP into.
//
irpCount = (transferByteCount + MaximumBytes - 1) / MaximumBytes;
DebugPrint((2,
"SplitTapeRequest: Requires %d IRPs\n", irpCount));
DebugPrint((2,
"SplitTapeRequest: Original IRP %p\n", Irp));
//
// If all partial transfers complete successfully then
// the status is already set up.
// Failing partial transfer IRP will set status to
// error and bytes transferred to 0 during IoCompletion.
//
Irp->IoStatus.Status = STATUS_SUCCESS;
//CEP Irp->IoStatus.Information = transferByteCount;
Irp->IoStatus.Information = 0;
//
// Save number of IRPs to complete count on current stack
// of original IRP.
//
nextIrpStack->Parameters.Others.Argument1 = ULongToPtr( irpCount );
for (i = 0; i < irpCount; i++) {
PIRP newIrp;
PIO_STACK_LOCATION newIrpStack;
//
// Allocate new IRP.
//
newIrp = IoAllocateIrp(Fdo->StackSize, FALSE);
if (newIrp == NULL) {
DebugPrint((1,
"SplitTapeRequest: Can't allocate Irp\n"));
//
// Decrement count of outstanding partial requests.
//
remainingIrps = InterlockedDecrement((PLONG)&nextIrpStack->Parameters.Others.Argument1);
//
// Check if any outstanding IRPs.
//
if (remainingIrps == 0) {
completeOriginalIrp = TRUE;
}
//
// Update original IRP with failing status.
//
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Information = 0;
//
// Keep going with this request as outstanding partials
// may be in progress.
//
goto KeepGoing;
}
DebugPrint((2,
"SplitTapeRequest: New IRP %p\n", newIrp));
//
// Write MDL address to new IRP.
// In the port driver the SRB data length
// 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 = Fdo;
//
// Build SRB and CDB.
//
TapeReadWrite(Fdo, 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 TapeIoCompleteAssociated.
//
IoSetCompletionRoutine(newIrp,
TapeIoCompleteAssociated,
srb,
TRUE,
TRUE,
TRUE);
//
// Call port driver with new request.
//
status = IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, newIrp);
if (!NT_SUCCESS(status)) {
DebugPrint((1,
"SplitTapeRequest: IoCallDriver returned error\n"));
//
// Decrement count of outstanding partial requests.
//
remainingIrps = InterlockedDecrement((PLONG)&nextIrpStack->Parameters.Others.Argument1);
//
// Check if any outstanding IRPs.
//
if (remainingIrps == 0) {
completeOriginalIrp = TRUE;
}
//
// Update original IRP with failing status.
//
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
//
// Deallocate this partial IRP.
//
IoFreeIrp(newIrp);
}
KeepGoing:
//
// 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 += MaximumBytes;
}
//
// Check if original IRP should be completed.
//
if (completeOriginalIrp) {
ClassReleaseRemoveLock(Fdo, Irp);
ClassCompleteRequest(Fdo, Irp, 0);
}
return;
} // end SplitTapeRequest()
VOID
TapeReadWrite(
IN PDEVICE_OBJECT Fdo,
IN PIRP Irp
)
/*++
Routine Description:
This routine builds up the given irp for a read or write request.
Arguments:
DeviceObject - Supplies the device object.
Irp - Supplies the I/O request packet.
Return Value:
None.
--*/
{
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
PTAPE_DATA tapeData = (PTAPE_DATA)(fdoExtension->CommonExtension.DriverData);
PTAPE_INIT_DATA_EX tapeInitData = &tapeData->TapeInitData;
PVOID minitapeExtension = (tapeData + 1);
PIO_STACK_LOCATION irpSp, nextSp;
PSCSI_REQUEST_BLOCK srb;
PCDB cdb;
ULONG transferBlocks;
PAGED_CODE();
//
// Allocate an Srb.
//
srb = ExAllocateFromNPagedLookasideList(&(fdoExtension->CommonExtension.SrbLookasideList));
srb->SrbFlags = 0;
irpSp = IoGetCurrentIrpStackLocation(Irp);
if (irpSp->MajorFunction == IRP_MJ_READ) {
srb->SrbFlags |= SRB_FLAGS_DATA_IN;
} else {
srb->SrbFlags |= SRB_FLAGS_DATA_OUT;
}
srb->Length = SCSI_REQUEST_BLOCK_SIZE;
srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
srb->SrbStatus = 0;
srb->ScsiStatus = 0;
srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
srb->SrbFlags |= fdoExtension->SrbFlags;
srb->DataTransferLength = irpSp->Parameters.Read.Length;
srb->TimeOutValue = fdoExtension->TimeOutValue;
srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
srb->SenseInfoBuffer = fdoExtension->SenseData;
srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
srb->NextSrb = NULL;
srb->OriginalRequest = Irp;
srb->SrbExtension = NULL;
srb->QueueSortKey = 0;
//
// Indicate that 6-byte CDB's will be used.
//
srb->CdbLength = CDB6GENERIC_LENGTH;
//
// Fill in CDB fields.
//
cdb = (PCDB)srb->Cdb;
//
// Zero CDB in SRB.
//
RtlZeroMemory(cdb, MAXIMUM_CDB_SIZE);
if (fdoExtension->DiskGeometry.BytesPerSector) {
//
// Since we are writing fixed block mode, normalize transfer count
// to number of blocks.
//
transferBlocks = irpSp->Parameters.Read.Length / fdoExtension->DiskGeometry.BytesPerSector;
//
// Tell the device that we are in fixed block mode.
//
cdb->CDB6READWRITETAPE.VendorSpecific = 1;
} else {
//
// Variable block mode transfer.
//
transferBlocks = irpSp->Parameters.Read.Length;
cdb->CDB6READWRITETAPE.VendorSpecific = 0;
}
//
// Set up transfer length
//
cdb->CDB6READWRITETAPE.TransferLenMSB = (UCHAR)((transferBlocks >> 16) & 0xff);
cdb->CDB6READWRITETAPE.TransferLen = (UCHAR)((transferBlocks >> 8) & 0xff);
cdb->CDB6READWRITETAPE.TransferLenLSB = (UCHAR)(transferBlocks & 0xff);
//
// Set transfer direction.
//
if (srb->SrbFlags & SRB_FLAGS_DATA_IN) {
DebugPrint((3,
"TapeReadWrite: Read Command\n"));
cdb->CDB6READWRITETAPE.OperationCode = SCSIOP_READ6;
} else {
DebugPrint((3,
"TapeReadWrite: Write Command\n"));
cdb->CDB6READWRITETAPE.OperationCode = SCSIOP_WRITE6;
}
nextSp = IoGetNextIrpStackLocation(Irp);
nextSp->MajorFunction = IRP_MJ_SCSI;
nextSp->Parameters.Scsi.Srb = srb;
irpSp->Parameters.Others.Argument4 = (PVOID) MAXIMUM_RETRIES;
IoSetCompletionRoutine(Irp,
ClassIoComplete,
srb,
TRUE,
TRUE,
FALSE);
if (tapeInitData->PreProcessReadWrite) {
//
// If the routine exists, call it. The miniclass driver will
// do whatever it needs to.
//
tapeInitData->PreProcessReadWrite(minitapeExtension,
NULL,
NULL,
srb,
0,
0,
NULL);
}
}
NTSTATUS
TapeIoCompleteAssociated(
IN PDEVICE_OBJECT Fdo,
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. This routine is used for
requests which were build by split request. After it has processed
the request it decrements the Irp count in the master Irp. If the
count goes to zero then the master Irp is completed.
Arguments:
DeviceObject - Supplies the device object which represents the logical
unit.
Irp - Supplies the Irp which has completed.
Context - Supplies a pointer to the SRB.
Return Value:
NT status
--*/
{
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
PSCSI_REQUEST_BLOCK srb = Context;
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
PTAPE_DATA tapeData = (PTAPE_DATA)(fdoExtension->CommonExtension.DriverData);
LONG irpCount;
PIRP originalIrp = Irp->AssociatedIrp.MasterIrp;
NTSTATUS status;
//
// Check SRB status for success of completing request.
//
if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
DebugPrint((2,
"TapeIoCompleteAssociated: IRP %p, SRB %p", Irp, srb));
//
// Release the queue if it is frozen.
//
if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
ClassReleaseQueue(Fdo);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -