📄 tape.c
字号:
case SCSI_SENSEQ_SETMARK_DETECTED :
DebugPrint((1,
"InterpretSenseInfo: Setmark detected\n"));
*Status = STATUS_SETMARK_DETECTED;
break ;
case SCSI_SENSEQ_FILEMARK_DETECTED :
default:
DebugPrint((1,
"InterpretSenseInfo: Filemark detected\n"));
*Status = STATUS_FILEMARK_DETECTED;
break ;
}
} else if ( senseBuffer->EndOfMedia ) {
switch( senseBuffer->AdditionalSenseCodeQualifier ) {
case SCSI_SENSEQ_BEGINNING_OF_MEDIA_DETECTED :
DebugPrint((1,
"InterpretSenseInfo: Beginning of media detected\n"));
*Status = STATUS_BEGINNING_OF_MEDIA;
break ;
case SCSI_SENSEQ_END_OF_MEDIA_DETECTED :
default:
DebugPrint((1,
"InterpretSenseInfo: End of media detected\n"));
*Status = STATUS_END_OF_MEDIA;
break ;
}
}
break;
case SCSI_SENSE_NO_SENSE:
//
// Check other indicators
//
if (senseBuffer->FileMark) {
switch( senseBuffer->AdditionalSenseCodeQualifier ) {
case SCSI_SENSEQ_SETMARK_DETECTED :
DebugPrint((1,
"InterpretSenseInfo: Setmark detected\n"));
*Status = STATUS_SETMARK_DETECTED;
break ;
case SCSI_SENSEQ_FILEMARK_DETECTED :
default:
DebugPrint((1,
"InterpretSenseInfo: Filemark detected\n"));
*Status = STATUS_FILEMARK_DETECTED;
break ;
}
} else if (senseBuffer->EndOfMedia) {
switch(senseBuffer->AdditionalSenseCodeQualifier) {
case SCSI_SENSEQ_BEGINNING_OF_MEDIA_DETECTED :
DebugPrint((1,
"InterpretSenseInfo: Beginning of media detected\n"));
*Status = STATUS_BEGINNING_OF_MEDIA;
break ;
case SCSI_SENSEQ_END_OF_MEDIA_DETECTED :
default:
DebugPrint((1,
"InterpretSenseInfo: End of media detected\n"));
*Status = STATUS_END_OF_MEDIA;
break;
}
} else if (senseBuffer->IncorrectLength) {
//
// If we're in variable block mode then ignore
// incorrect length.
//
if (fdoExtension->DiskGeometry.BytesPerSector == 0 &&
Srb->Cdb[0] == SCSIOP_READ6) {
REVERSE_BYTES((FOUR_BYTE UNALIGNED *)&residualBlocks,
(FOUR_BYTE UNALIGNED *)(senseBuffer->Information));
if (residualBlocks >= 0) {
DebugPrint((1,"InterpretSenseInfo: In variable block mode :We read less than specified\n"));
*Status = STATUS_SUCCESS;
} else {
DebugPrint((1,"InterpretSenseInfo: In variable block mode :Data left in block\n"));
*Status = STATUS_BUFFER_OVERFLOW;
}
}
}
break;
case SCSI_SENSE_BLANK_CHECK:
DebugPrint((1,
"InterpretSenseInfo: Media blank check\n"));
*Status = STATUS_NO_DATA_DETECTED;
break;
case SCSI_SENSE_VOL_OVERFLOW:
DebugPrint((1,
"InterpretSenseInfo: End of Media Overflow\n"));
*Status = STATUS_EOM_OVERFLOW;
break;
case SCSI_SENSE_NOT_READY:
switch (senseBuffer->AdditionalSenseCode) {
case SCSI_ADSENSE_LUN_NOT_READY:
switch (senseBuffer->AdditionalSenseCodeQualifier) {
case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED:
*Status = STATUS_NO_MEDIA;
break;
case SCSI_SENSEQ_FORMAT_IN_PROGRESS:
break;
case SCSI_SENSEQ_INIT_COMMAND_REQUIRED:
default:
//
// Allow retries, if the drive isn't ready.
//
*Retry = TRUE;
break;
}
break;
case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE:
DebugPrint((1,
"InterpretSenseInfo:"
" No Media in device.\n"));
*Status = STATUS_NO_MEDIA;
break;
}
break;
} // end switch
//
// Check if a filemark or setmark was encountered,
// or an end-of-media or no-data condition exists.
//
if ((NT_WARNING(*Status) || NT_SUCCESS( *Status)) &&
(Srb->Cdb[0] == SCSIOP_WRITE6 || Srb->Cdb[0] == SCSIOP_READ6)) {
LONG actualLength;
//
// 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -