📄 xferpkt.c
字号:
pkt->OriginalIrp->IoStatus.Status = Irp->IoStatus.Status;
/*
* If the original I/O originated in user space (i.e. it is thread-queued),
* and the error is user-correctable (e.g. media is missing, for removable media),
* alert the user.
* Since this is only one of possibly several packets completing for the original IRP,
* we may do this more than once for a single request. That's ok; this allows
* us to test each returned status with IoIsErrorUserInduced().
*/
if (IoIsErrorUserInduced(Irp->IoStatus.Status) &&
pkt->CompleteOriginalIrpWhenLastPacketCompletes &&
pkt->OriginalIrp->Tail.Overlay.Thread){
IoSetHardErrorOrVerifyDevice(pkt->OriginalIrp, Fdo);
}
}
/*
* We use a field in the original IRP to count
* down the transfer pieces as they complete.
*/
numPacketsRemaining = InterlockedDecrement(
(PLONG)&pkt->OriginalIrp->Tail.Overlay.DriverContext[0]);
if (numPacketsRemaining > 0){
/*
* More transfer pieces remain for the original request.
* Wait for them to complete before completing the original irp.
*/
}
else {
/*
* All the transfer pieces are done.
* Complete the original irp if appropriate.
*/
ASSERT(numPacketsRemaining == 0);
if (pkt->CompleteOriginalIrpWhenLastPacketCompletes){
IO_PAGING_PRIORITY priority = (TEST_FLAG(pkt->OriginalIrp->Flags, IRP_PAGING_IO)) ? IoGetPagingIoPriority(pkt->OriginalIrp) : IoPagingPriorityInvalid;
KIRQL oldIrql;
if (NT_SUCCESS(pkt->OriginalIrp->IoStatus.Status)){
ASSERT((ULONG)pkt->OriginalIrp->IoStatus.Information == origCurrentSp->Parameters.Read.Length);
ClasspPerfIncrementSuccessfulIo(fdoExt);
}
ClassReleaseRemoveLock(Fdo, pkt->OriginalIrp);
/*
* We submitted all the downward irps, including this last one, on the thread
* that the OriginalIrp came in on. So the OriginalIrp is completing on a
* different thread iff this last downward irp is completing on a different thread.
* If BlkCache is loaded, for example, it will often complete
* requests out of the cache on the same thread, therefore not marking the downward
* irp pending and not requiring us to do so here. If the downward request is completing
* on the same thread, then by not marking the OriginalIrp pending we can save an APC
* and get extra perf benefit out of BlkCache.
* Note that if the packet ever cycled due to retry or LowMemRetry,
* we set the pending bit in those codepaths.
*/
if (pkt->Irp->PendingReturned){
IoMarkIrpPending(pkt->OriginalIrp);
}
ClassCompleteRequest(Fdo, pkt->OriginalIrp, IO_DISK_INCREMENT);
//
// Drop the count only after completing the request, to give
// Mm some amount of time to issue its next critical request
//
if (priority == IoPagingPriorityHigh)
{
KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
if (fdoData->MaxInterleavedNormalIo < ClassMaxInterleavePerCriticalIo)
{
fdoData->MaxInterleavedNormalIo = 0;
}
else
{
fdoData->MaxInterleavedNormalIo -= ClassMaxInterleavePerCriticalIo;
}
fdoData->NumHighPriorityPagingIo--;
if (fdoData->NumHighPriorityPagingIo == 0)
{
LARGE_INTEGER period;
//
// Exiting throttle mode
//
KeQuerySystemTime(&fdoData->ThrottleStopTime);
period.QuadPart = fdoData->ThrottleStopTime.QuadPart - fdoData->ThrottleStartTime.QuadPart;
fdoData->LongestThrottlePeriod.QuadPart = max(fdoData->LongestThrottlePeriod.QuadPart, period.QuadPart);
}
KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
}
/*
* We may have been called by one of the class drivers (e.g. cdrom)
* via the legacy API ClassSplitRequest.
* This is the only case for which the packet engine is called for an FDO
* with a StartIo routine; in that case, we have to call IoStartNextPacket
* now that the original irp has been completed.
*/
if (fdoExt->CommonExtension.DriverExtension->InitData.ClassStartIo) {
if (TEST_FLAG(pkt->Srb.SrbFlags, SRB_FLAGS_DONT_START_NEXT_PACKET)){
DBGTRAP(("SRB_FLAGS_DONT_START_NEXT_PACKET should never be set here (??)"));
}
else {
KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
IoStartNextPacket(Fdo, FALSE);
KeLowerIrql(oldIrql);
}
}
}
}
/*
* If the packet was synchronous, write the final result back to the issuer's status buffer
* and signal his event.
*/
if (pkt->SyncEventPtr){
KeSetEvent(pkt->SyncEventPtr, 0, FALSE);
pkt->SyncEventPtr = NULL;
}
/*
* Free the completed packet.
*/
pkt->UsePartialMdl = FALSE;
pkt->OriginalIrp = NULL;
pkt->InLowMemRetry = FALSE;
EnqueueFreeTransferPacket(Fdo, pkt);
/*
* Now that we have freed some resources,
* try again to send one of the previously deferred irps.
*/
deferredIrp = DequeueDeferredClientIrp(fdoData);
if (deferredIrp){
ServiceTransferRequest(Fdo, deferredIrp);
}
ClassReleaseRemoveLock(Fdo, (PIRP)&uniqueAddr);
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
/*
* SetupEjectionTransferPacket
*
* Set up a transferPacket for a synchronous Ejection Control transfer.
*/
VOID SetupEjectionTransferPacket( TRANSFER_PACKET *Pkt,
BOOLEAN PreventMediaRemoval,
PKEVENT SyncEventPtr,
PIRP OriginalIrp)
{
PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
PCDB pCdb;
PAGED_CODE();
RtlZeroMemory(&Pkt->Srb, sizeof(SCSI_REQUEST_BLOCK));
Pkt->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
Pkt->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
Pkt->Srb.QueueAction = SRB_SIMPLE_TAG_REQUEST;
Pkt->Srb.CdbLength = 6;
Pkt->Srb.OriginalRequest = Pkt->Irp;
Pkt->Srb.SenseInfoBuffer = &Pkt->SrbErrorSenseData;
Pkt->Srb.SenseInfoBufferLength = sizeof(SENSE_DATA);
Pkt->Srb.TimeOutValue = fdoExt->TimeOutValue;
Pkt->Srb.SrbFlags = fdoExt->SrbFlags;
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
pCdb = (PCDB)Pkt->Srb.Cdb;
pCdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
pCdb->MEDIA_REMOVAL.Prevent = PreventMediaRemoval;
Pkt->BufPtrCopy = NULL;
Pkt->BufLenCopy = 0;
Pkt->OriginalIrp = OriginalIrp;
Pkt->NumRetries = NUM_LOCKMEDIAREMOVAL_RETRIES;
Pkt->SyncEventPtr = SyncEventPtr;
Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE;
}
/*
* SetupModeSenseTransferPacket
*
* Set up a transferPacket for a synchronous Mode Sense transfer.
*/
VOID SetupModeSenseTransferPacket( TRANSFER_PACKET *Pkt,
PKEVENT SyncEventPtr,
PVOID ModeSenseBuffer,
UCHAR ModeSenseBufferLen,
UCHAR PageMode,
PIRP OriginalIrp)
{
PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
PCDB pCdb;
PAGED_CODE();
RtlZeroMemory(&Pkt->Srb, sizeof(SCSI_REQUEST_BLOCK));
Pkt->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
Pkt->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
Pkt->Srb.QueueAction = SRB_SIMPLE_TAG_REQUEST;
Pkt->Srb.CdbLength = 6;
Pkt->Srb.OriginalRequest = Pkt->Irp;
Pkt->Srb.SenseInfoBuffer = &Pkt->SrbErrorSenseData;
Pkt->Srb.SenseInfoBufferLength = sizeof(SENSE_DATA);
Pkt->Srb.TimeOutValue = fdoExt->TimeOutValue;
Pkt->Srb.DataBuffer = ModeSenseBuffer;
Pkt->Srb.DataTransferLength = ModeSenseBufferLen;
Pkt->Srb.SrbFlags = fdoExt->SrbFlags;
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DATA_IN);
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
pCdb = (PCDB)Pkt->Srb.Cdb;
pCdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
pCdb->MODE_SENSE.PageCode = PageMode;
pCdb->MODE_SENSE.AllocationLength = (UCHAR)ModeSenseBufferLen;
Pkt->BufPtrCopy = ModeSenseBuffer;
Pkt->BufLenCopy = ModeSenseBufferLen;
Pkt->OriginalIrp = OriginalIrp;
Pkt->NumRetries = NUM_MODESENSE_RETRIES;
Pkt->SyncEventPtr = SyncEventPtr;
Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE;
}
/*
* SetupDriveCapacityTransferPacket
*
* Set up a transferPacket for a synchronous Drive Capacity transfer.
*/
VOID SetupDriveCapacityTransferPacket( TRANSFER_PACKET *Pkt,
PVOID ReadCapacityBuffer,
ULONG ReadCapacityBufferLen,
PKEVENT SyncEventPtr,
PIRP OriginalIrp,
BOOLEAN Use16ByteCdb)
{
PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
PCDB pCdb;
RtlZeroMemory(&Pkt->Srb, sizeof(SCSI_REQUEST_BLOCK));
Pkt->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
Pkt->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
Pkt->Srb.QueueAction = SRB_SIMPLE_TAG_REQUEST;
Pkt->Srb.OriginalRequest = Pkt->Irp;
Pkt->Srb.SenseInfoBuffer = &Pkt->SrbErrorSenseData;
Pkt->Srb.SenseInfoBufferLength = sizeof(SENSE_DATA);
Pkt->Srb.TimeOutValue = fdoExt->TimeOutValue;
Pkt->Srb.DataBuffer = ReadCapacityBuffer;
Pkt->Srb.DataTransferLength = ReadCapacityBufferLen;
Pkt->Srb.SrbFlags = fdoExt->SrbFlags;
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DATA_IN);
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
pCdb = (PCDB)Pkt->Srb.Cdb;
if (Use16ByteCdb == TRUE) {
ASSERT(ReadCapacityBufferLen >= sizeof(READ_CAPACITY_DATA_EX));
Pkt->Srb.CdbLength = 16;
pCdb->CDB16.OperationCode = SCSIOP_READ_CAPACITY16;
REVERSE_BYTES(&pCdb->CDB16.TransferLength, &ReadCapacityBufferLen);
pCdb->AsByte[1] = 0x10; // Service Action
} else {
Pkt->Srb.CdbLength = 10;
pCdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
}
Pkt->BufPtrCopy = ReadCapacityBuffer;
Pkt->BufLenCopy = ReadCapacityBufferLen;
Pkt->OriginalIrp = OriginalIrp;
Pkt->NumRetries = NUM_DRIVECAPACITY_RETRIES;
Pkt->SyncEventPtr = SyncEventPtr;
Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE;
}
#if 0
/*
* SetupSendStartUnitTransferPacket
*
* Set up a transferPacket for a synchronous Send Start Unit transfer.
*/
VOID SetupSendStartUnitTransferPacket( TRANSFER_PACKET *Pkt,
PIRP OriginalIrp)
{
PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
PCDB pCdb;
PAGED_CODE();
RtlZeroMemory(&Pkt->Srb, sizeof(SCSI_REQUEST_BLOCK));
/*
* Initialize the SRB.
* Use a very long timeout value to give the drive time to spin up.
*/
Pkt->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
Pkt->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
Pkt->Srb.TimeOutValue = START_UNIT_TIMEOUT;
Pkt->Srb.CdbLength = 6;
Pkt->Srb.OriginalRequest = Pkt->Irp;
Pkt->Srb.SenseInfoBuffer = &Pkt->SrbErrorSenseData;
Pkt->Srb.SenseInfoBufferLength = sizeof(SENSE_DATA);
Pkt->Srb.Lun = 0;
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DISABLE_AUTOSENSE);
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
pCdb = (PCDB)Pkt->Srb.Cdb;
pCdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
pCdb->START_STOP.Start = 1;
pCdb->START_STOP.Immediate = 0;
pCdb->START_STOP.LogicalUnitNumber = 0;
Pkt->OriginalIrp = OriginalIrp;
Pkt->NumRetries = 0;
Pkt->SyncEventPtr = NULL;
Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -