📄 tape.c
字号:
//
// Not all bytes were transfered. Update information field with
// number of bytes transfered from sense buffer.
//
if (senseBuffer->Valid) {
REVERSE_BYTES((FOUR_BYTE UNALIGNED *)&residualBlocks,
(FOUR_BYTE UNALIGNED *)(senseBuffer->Information));
} else {
residualBlocks = 0;
}
length = ((PCDB) Srb->Cdb)->CDB6READWRITETAPE.TransferLenLSB;
length |= ((PCDB) Srb->Cdb)->CDB6READWRITETAPE.TransferLen << 8;
length |= ((PCDB) Srb->Cdb)->CDB6READWRITETAPE.TransferLenMSB << 16;
actualLength = length;
length -= residualBlocks;
if (length < 0) {
length = 0;
*Status = STATUS_IO_DEVICE_ERROR;
}
if (fdoExtension->DiskGeometry.BytesPerSector) {
actualLength *= fdoExtension->DiskGeometry.BytesPerSector;
length *= fdoExtension->DiskGeometry.BytesPerSector;
}
if (length > actualLength) {
length = actualLength;
}
irp->IoStatus.Information = length;
DebugPrint((1,"ScsiTapeError: Transfer Count: %lx\n", Srb->DataTransferLength));
DebugPrint((1," Residual Blocks: %lx\n", residualBlocks));
DebugPrint((1," Irp IoStatus Information = %lx\n", irp->IoStatus.Information));
}
} else {
DebugPrint((1, "SRB Status : %x, SCSI Status : %x\n",
SRB_STATUS(Srb->SrbStatus),
(Srb->ScsiStatus)));
}
//
// Call tape device specific error handler.
//
if (tapeInitData->TapeError &&
ScsiTapeNtStatusToTapeStatus(*Status, &tapeStatus)) {
oldTapeStatus = tapeStatus;
tapeInitData->TapeError(minitapeExtension, Srb, &tapeStatus);
if (tapeStatus != oldTapeStatus) {
ScsiTapeTapeStatusToNtStatus(tapeStatus, Status);
}
}
//
// Notify the system that this tape drive requires cleaning
//
if ((*Status) == STATUS_DEVICE_REQUIRES_CLEANING) {
LARGE_INTEGER currentTime;
LARGE_INTEGER driveCleanInterval;
KeQuerySystemTime(¤tTime);
driveCleanInterval.QuadPart = ONE_SECOND;
driveCleanInterval.QuadPart *= TAPE_DRIVE_CLEAN_NOTIFICATION_INTERVAL;
if ((currentTime.QuadPart) >
((tapeData->LastDriveCleanRequestTime.QuadPart) +
(driveCleanInterval.QuadPart))) {
NotificationStructure[0].Event = GUID_IO_DRIVE_REQUIRES_CLEANING;
NotificationStructure[0].Version = 1;
NotificationStructure[0].Size = sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION) +
sizeof(ULONG) - sizeof(UCHAR);
NotificationStructure[0].FileObject = NULL;
NotificationStructure[0].NameBufferOffset = -1;
//
// Increasing Index for this event
//
*((PULONG) (&(NotificationStructure[0].CustomDataBuffer[0]))) = 0;
IoReportTargetDeviceChangeAsynchronous(fdoExtension->LowerPdo,
&NotificationStructure[0],
NULL,
NULL);
tapeData->LastDriveCleanRequestTime.QuadPart = currentTime.QuadPart;
}
}
return;
} // end ScsiTapeError()
NTSTATUS
TapeReadWriteVerification(
IN PDEVICE_OBJECT DeviceObject,
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.
--*/
{
PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = commonExtension->PartitionZeroExtension;
PSTORAGE_ADAPTER_DESCRIPTOR adapterDescriptor = fdoExtension->CommonExtension.PartitionZeroExtension->AdapterDescriptor;
PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
ULONG transferPages;
ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
ULONG maximumTransferLength = adapterDescriptor->MaximumTransferLength;
ULONG bytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
PAGED_CODE();
//
// Since most tape devices don't support 10-byte read/write, the entire request must be dealt with here.
// STATUS_PENDING will be returned to the classpnp driver, so that it does nothing.
//
//
// Ensure that the request is for something valid - ie. not 0.
//
if (currentIrpStack->Parameters.Read.Length == 0) {
//
// Class code will handle this.
//
return STATUS_SUCCESS;
}
//
// Check that blocksize has been established.
//
if (bytesPerSector == UNDEFINED_BLOCK_SIZE) {
DebugPrint((1,
"TapeReadWriteVerification: Invalid block size - UNDEFINED\n"));
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
//
// ClassPnp will handle completing the request.
//
return STATUS_INVALID_PARAMETER;
}
if (bytesPerSector) {
if (transferByteCount % bytesPerSector) {
DebugPrint((1,
"TapeReadWriteVerification: Invalid block size\n"));
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
//
// ClassPnp will handle completing the request.
//
return STATUS_INVALID_PARAMETER;
}
}
//
// Calculate number of pages in this transfer.
//
transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
currentIrpStack->Parameters.Read.Length);
//
// Check if request length is greater than the maximum number of
// bytes that the hardware can transfer.
//
//
// Calculate number of pages in this transfer.
//
if (currentIrpStack->Parameters.Read.Length > maximumTransferLength ||
transferPages > adapterDescriptor->MaximumPhysicalPages) {
DebugPrint((2,
"TapeReadWriteVerification: Request greater than maximum\n"));
DebugPrint((2,
"TapeReadWriteVerification: Maximum is %lx\n",
maximumTransferLength));
DebugPrint((2,
"TapeReadWriteVerification: Byte count is %lx\n",
currentIrpStack->Parameters.Read.Length));
transferPages = adapterDescriptor->MaximumPhysicalPages - 1;
if (maximumTransferLength > transferPages << PAGE_SHIFT ) {
maximumTransferLength = transferPages << PAGE_SHIFT;
}
//
// Check that maximum transfer size is not zero.
//
if (maximumTransferLength == 0) {
maximumTransferLength = PAGE_SIZE;
}
//
// Ensure that this is reasonable, according to the current block size.
//
if (bytesPerSector) {
if (maximumTransferLength % bytesPerSector) {
ULONG tmpLength;
tmpLength = maximumTransferLength % bytesPerSector;
maximumTransferLength = maximumTransferLength - tmpLength;
}
}
//
// Mark IRP with status pending.
//
IoMarkIrpPending(Irp);
//
// Request greater than port driver maximum.
// Break up into smaller routines.
//
SplitTapeRequest(DeviceObject, Irp, maximumTransferLength);
return STATUS_PENDING;
}
//
// Build SRB and CDB for this IRP.
//
TapeReadWrite(DeviceObject, Irp);
IoMarkIrpPending(Irp);
IoCallDriver(commonExtension->LowerDeviceObject, Irp);
return STATUS_PENDING;
}
VOID
SplitTapeRequest(
IN PDEVICE_OBJECT Fdo,
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 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.
//
IoSetCompl
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -