Exemple #1
0
/*
 *  RetryTransferPacket
 *
 *      Retry sending a TRANSFER_PACKET.
 *
 *      Return TRUE iff the packet is complete.
 *          (if so the status in pkt->irp is the final status).
 */
BOOLEAN RetryTransferPacket(PTRANSFER_PACKET Pkt)
{
    BOOLEAN packetDone;

    TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "retrying failed transfer (pkt=%ph, op=%s)", Pkt, DBGGETSCSIOPSTR(Pkt->Srb)));

    NT_ASSERT(Pkt->NumRetries > 0 || Pkt->RetryHistory);
    Pkt->NumRetries--;

    //
    // If this is the last retry, then turn off disconnect, sync transfer,
    // and tagged queuing.  On all other retries, leave the original settings.
    //

    if ( 0 == Pkt->NumRetries ) {
        /*
         *  Tone down performance on the retry.
         *  This increases the chance for success on the retry.
         *  We've seen instances of drives that fail consistently but then start working
         *  once this scale-down is applied.
         */
        SrbSetSrbFlags(Pkt->Srb, SRB_FLAGS_DISABLE_DISCONNECT);
        SrbSetSrbFlags(Pkt->Srb, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
        SrbClearSrbFlags(Pkt->Srb, SRB_FLAGS_QUEUE_ACTION_ENABLE);
        SrbSetRequestTag(Pkt->Srb, SP_UNTAGGED);
    }

    if (Pkt->Irp->IoStatus.Status == STATUS_INSUFFICIENT_RESOURCES) {

        PCDB pCdb = SrbGetCdb(Pkt->Srb);
        UCHAR cdbOpcode = 0;
        BOOLEAN isReadWrite = FALSE;

        PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Pkt->Fdo->DeviceExtension;
        PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;

        if (pCdb) {
            cdbOpcode = pCdb->CDB10.OperationCode;
            isReadWrite = IS_SCSIOP_READWRITE(cdbOpcode);
        }

        if ((Pkt->DriverUsesStartIO) &&
            ( (cdbOpcode == SCSIOP_WRITE6 ) ||
              (cdbOpcode == SCSIOP_WRITE  ) ||
              (cdbOpcode == SCSIOP_WRITE12) ||
              (cdbOpcode == SCSIOP_WRITE16) )) {

            /* don't retry writes in super-low-memory conditions if the
             * driver must serialize against StartIO.  This is because
             * some write methods used in such drivers cannot accept
             * random-sized writes. (i.e CD-RW in packet writing mode)
             * Reads, however, are always safe to split up.
             */
            SET_FLAG(fdoData->TrackingFlags, TRACKING_FORWARD_PROGRESS_PATH1);
            packetDone = TRUE;
        }
        else if (Pkt->InLowMemRetry || !isReadWrite){
            /*
             *  This should never happen under normal circumstances.
             *  The memory manager guarantees that at least four pages will
             *  be available to allow forward progress in the port driver.
             *  So a one-page transfer should never fail with insufficient resources.
             *
             *  However, it is possible to get in here with virtual storage
             *  or thin provisioned storage for example.
             *  A single sector write can trigger an allocation request and
             *  presently a forward progress guarantee is not provided.
             *  VHD also may have some limitations in forward progress guarantee.
             *  And USB too might also fall into this category.
             */
            SET_FLAG(fdoData->TrackingFlags, TRACKING_FORWARD_PROGRESS_PATH2);
            packetDone = TRUE;
        }
        else {
            /*
             *  We are in low-memory stress.
             *  Start the low-memory retry state machine, which tries to
             *  resend the packet in little one-page chunks.
             */
            SET_FLAG(fdoData->TrackingFlags, TRACKING_FORWARD_PROGRESS_PATH3);
            InitLowMemRetry(Pkt,
                            Pkt->BufPtrCopy,
                            Pkt->BufLenCopy,
                            Pkt->TargetLocationCopy);
            StepLowMemRetry(Pkt);
            packetDone = FALSE;
        }
    }
    else {
        /*
         *  Retry the packet by simply resending it after a delay.
         *  Put the packet back in the pending queue and
         *  schedule a timer to retry the transfer.
         *
         *  Do not call SetupReadWriteTransferPacket again because:
         *  (1)  The minidriver may have set some bits
         *       in the SRB that it needs again and
         *  (2)  doing so would reset numRetries.
         *
         *  BECAUSE we do not call SetupReadWriteTransferPacket again,
         *  we have to reset a couple fields in the SRB that
         *  some miniports overwrite when they fail an SRB.
         */

        SrbSetDataBuffer(Pkt->Srb, Pkt->BufPtrCopy);
        SrbSetDataTransferLength(Pkt->Srb, Pkt->BufLenCopy);

        TransferPacketQueueRetryDpc(Pkt);

        packetDone = FALSE;
    }

    return packetDone;
}
Exemple #2
0
/*
 *  ISSUE: REMOVE this old function implementation as soon as the
 *                  boottime pagefile problems with the new one (below)
 *                  are resolved.
 */
NTSTATUS
ClasspEjectionControl(
    IN PDEVICE_OBJECT Fdo,
    IN PIRP Irp,
    IN MEDIA_LOCK_TYPE LockType,
    IN BOOLEAN Lock
    )
{
    PFUNCTIONAL_DEVICE_EXTENSION FdoExtension = Fdo->DeviceExtension;
    PCOMMON_DEVICE_EXTENSION commonExtension =
        (PCOMMON_DEVICE_EXTENSION) FdoExtension;

    PFILE_OBJECT_EXTENSION fsContext = NULL;
    NTSTATUS status;
    PSCSI_REQUEST_BLOCK srb = NULL;
    BOOLEAN countChanged = FALSE;

    PAGED_CODE();

    /*
     *  Ensure that the user thread is not suspended while we are holding EjectSynchronizationEvent.
     */
    KeEnterCriticalRegion();

    status = KeWaitForSingleObject(
                &(FdoExtension->EjectSynchronizationEvent),
                UserRequest,
                KernelMode,
                FALSE,
                NULL);

    NT_ASSERT(status == STATUS_SUCCESS);

    TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
                "ClasspEjectionControl: "
                "Received request for %s lock type\n",
                LockTypeStrings[LockType]
                ));

    try {
        PCDB cdb = NULL;

        //
        // Determine if this is a "secured" request.
        //

        if (LockType == SecureMediaLock) {

            PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
            PFILE_OBJECT fileObject = irpStack->FileObject;

            //
            // Make sure that the file object we are supplied has a
            // proper FsContext before we try doing a secured lock.
            //

            if (fileObject != NULL) {
                fsContext = ClassGetFsContext(commonExtension, fileObject);
            }

            if (fsContext == NULL) {

                //
                // This handle isn't setup correctly.  We can't let the
                // operation go.
                //

                status = STATUS_INVALID_PARAMETER;
                leave;
            }
        }

        if (Lock) {

            //
            // This is a lock command.  Reissue the command in case bus or
            // device was reset and the lock was cleared.
            // note: may need to decrement count if actual lock operation
            //       failed....
            //

            switch (LockType) {

                case SimpleMediaLock: {
                    FdoExtension->LockCount++;
                    countChanged = TRUE;
                    break;
                }

                case SecureMediaLock: {
                    fsContext->LockCount++;
                    FdoExtension->ProtectedLockCount++;
                    countChanged = TRUE;
                    break;
                }

                case InternalMediaLock: {
                    FdoExtension->InternalLockCount++;
                    countChanged = TRUE;
                    break;
                }
            }

        } else {

            //
            // This is an unlock command.  If it's a secured one then make sure
            // the caller has a lock outstanding or return an error.
            // note: may need to re-increment the count if actual unlock
            //       operation fails....
            //

            switch (LockType) {

                case SimpleMediaLock: {
                    if(FdoExtension->LockCount != 0) {
                        FdoExtension->LockCount--;
                        countChanged = TRUE;
                    }
                    break;
                }

                case SecureMediaLock: {
                    if(fsContext->LockCount == 0) {
                        status = STATUS_INVALID_DEVICE_STATE;
                        leave;
                    }
                    fsContext->LockCount--;
                    FdoExtension->ProtectedLockCount--;
                    countChanged = TRUE;
                    break;
                }

                case InternalMediaLock: {
                    NT_ASSERT(FdoExtension->InternalLockCount != 0);
                    FdoExtension->InternalLockCount--;
                    countChanged = TRUE;
                    break;
                }
            }

            //
            // We only send an unlock command to the drive if both the
            // secured and unsecured lock counts have dropped to zero.
            //

            if ((FdoExtension->ProtectedLockCount != 0) ||
                (FdoExtension->InternalLockCount != 0) ||
                (FdoExtension->LockCount != 0)) {

                status = STATUS_SUCCESS;
                leave;
            }
        }

        status = STATUS_SUCCESS;
        if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {

            srb = (PSCSI_REQUEST_BLOCK)ClasspAllocateSrb(FdoExtension);

            if (srb == NULL) {
                status = STATUS_INSUFFICIENT_RESOURCES;
                leave;
            }

            if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {

                //
                // NOTE - this is based on size used in ClasspAllocateSrb
                //

                status = InitializeStorageRequestBlock((PSTORAGE_REQUEST_BLOCK)srb,
                                                       STORAGE_ADDRESS_TYPE_BTL8,
                                                       CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE,
                                                       1,
                                                       SrbExDataTypeScsiCdb16);
                if (!NT_SUCCESS(status)) {
                    NT_ASSERT(FALSE);
                    leave;
                }

            } else {
                RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
            }

            SrbSetCdbLength(srb, 6);
            cdb = SrbGetCdb(srb);
            NT_ASSERT(cdb != NULL);

            cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;

            //
            // TRUE - prevent media removal.
            // FALSE - allow media removal.
            //

            cdb->MEDIA_REMOVAL.Prevent = Lock;

            //
            // Set timeout value.
            //

            SrbSetTimeOutValue(srb, FdoExtension->TimeOutValue);

            //
            // The actual lock operation on the device isn't so important
            // as the internal lock counts.  Ignore failures.
            //

            status = ClassSendSrbSynchronous(FdoExtension->DeviceObject,
                                             srb,
                                             NULL,
                                             0,
                                             FALSE);
        }

    } finally {

        if (!NT_SUCCESS(status)) {
            TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
                        "ClasspEjectionControl: FAILED status %x -- "
                        "reverting lock counts\n", status));

            if (countChanged) {

                //
                // have to revert to previous counts if the
                // lock/unlock operation actually failed.
                //

                if (Lock) {

                    switch (LockType) {

                        case SimpleMediaLock: {
                            FdoExtension->LockCount--;
                            break;
                        }

                        case SecureMediaLock: {
                            fsContext->LockCount--;
                            FdoExtension->ProtectedLockCount--;
                            break;
                        }

                        case InternalMediaLock: {
                            FdoExtension->InternalLockCount--;
                            break;
                        }
                    }

                } else {

                    switch (LockType) {

                        case SimpleMediaLock: {
                            FdoExtension->LockCount++;
                            break;
                        }

                        case SecureMediaLock: {
                            fsContext->LockCount++;
                            FdoExtension->ProtectedLockCount++;
                            break;
                        }

                        case InternalMediaLock: {
                            FdoExtension->InternalLockCount++;
                            break;
                        }
                    }
                }

            }

        } else {

            TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
                        "ClasspEjectionControl: Succeeded\n"));

        }

        TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
                    "ClasspEjectionControl: "
                    "Current Counts: Internal: %x  Secure: %x  Simple: %x\n",
                    FdoExtension->InternalLockCount,
                    FdoExtension->ProtectedLockCount,
                    FdoExtension->LockCount
                    ));

        KeSetEvent(&(FdoExtension->EjectSynchronizationEvent),
                   IO_NO_INCREMENT,
                   FALSE);
        KeLeaveCriticalRegion();

        if (srb) {
            ClassFreeOrReuseSrb(FdoExtension, srb);
        }

    }
    return status;
}
Exemple #3
0
VOID
ReleaseSlottedCommand(
    _In_ PAHCI_CHANNEL_EXTENSION ChannelExtension,
    _In_ UCHAR SlotNumber,
    _In_ BOOLEAN AtDIRQL
    )
/*++
    Performs Completion Data marshalling back into the SRB
It assumes:
    SRB STATUS has already been filled out
    ATA status from the AHCI registers is valid for this command
    SlotNumber points to a fully filled out Slot entry
Called by:
    AhciHwStartIo
    AhciNonQueuedErrorRecovery
    AhciCompleteIssuedSRBs

It performs:
    (overview)
    1 Intialize
    2 Marshal completion data
    3 Complete the Command
    (details)
    1.1 Keep track of the completion for our debugging records
    2.1 Handle Request Sense marshalling
    2.2.1 Handle everything else's marshalling
    2.2.2 If this was marked as needing return data, fill in the return Task File
    3.1 Make the slot available again
    3.2 Perform the Slot's last request, if there was one
    3.3.1 IO is completing, that IO may have paused the queue so unpause the queue
    3.3.2  Complete the command
Affected Variables/Registers:
    SRB
--*/
{
    PSLOT_CONTENT           slotContent;
    PAHCI_SRB_EXTENSION     srbExtension;
    PSTORAGE_REQUEST_BLOCK  srbToRelease;
    PATA_TASK_FILE          returnTaskFile;
    BOOLEAN                 isSenseSrb;
    BOOLEAN                 retrySrb = FALSE;

    slotContent = &ChannelExtension->Slot[SlotNumber];
    if (slotContent->Srb == NULL) {
        return;
    }

    srbExtension = GetSrbExtension(slotContent->Srb);
    isSenseSrb = IsRequestSenseSrb(srbExtension->AtaFunction);

    if (LogExecuteFullDetail(ChannelExtension->AdapterExtension->LogFlags)) {
        RecordExecutionHistory(ChannelExtension, 0x10000053);//ReleaseSlottedCommand
    }

  //2/2 Log command completion part for our debugging records
    if (LogCommand(ChannelExtension->AdapterExtension->LogFlags)) {
        PCOMMAND_HISTORY         cmdHistory;
        slotContent->CommandHistoryIndex %= 64; // should not be 64 or bigger. do it anyway to make sure we are safe

        cmdHistory = &ChannelExtension->CommandHistory[slotContent->CommandHistoryIndex];
        StorPortCopyMemory((PVOID)&cmdHistory->CompletionFIS, (PVOID)&ChannelExtension->ReceivedFIS->D2hRegisterFis, sizeof(AHCI_D2H_REGISTER_FIS));
        StorPortCopyMemory((PVOID)&cmdHistory->CompletionPx, (PVOID)ChannelExtension->Px, 0x40);
        cmdHistory->SrbStatus = slotContent->Srb->SrbStatus;

    }

  //2. Then complete the command
    if (isSenseSrb) {
      //2.1 Handle Request Sense marshalling
        srbToRelease = (PSTORAGE_REQUEST_BLOCK)SrbGetOriginalRequest(slotContent->Srb);

        //that original SRB must have SRB_STATUS_AUTOSENSE_VALID set appropriately
        if (slotContent->Srb->SrbStatus == SRB_STATUS_SUCCESS) {
            srbToRelease->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
            SrbSetScsiStatus(srbToRelease, SCSISTAT_CHECK_CONDITION);
        } else {
            srbToRelease->SrbStatus &= ~SRB_STATUS_AUTOSENSE_VALID;
        }

        //finish use of Sense.Srb
        srbExtension->AtaFunction = 0;
    } else {
      //2.2.1 Handle everything else's marshalling
        srbToRelease = slotContent->Srb;

        //Record error and status
        srbExtension->AtaStatus = ChannelExtension->TaskFileData.STS.AsUchar;
        srbExtension->AtaError = ChannelExtension->TaskFileData.ERR;

        //2.2.2 If this was marked as needing return data, fill in the return Task File.
        if( IsReturnResults(srbExtension->Flags) ) {
            PCDB cdb = SrbGetCdb(srbToRelease);

            if ((cdb != NULL) && (cdb->CDB10.OperationCode == SCSIOP_ATA_PASSTHROUGH16)) {
                // for ATA PASS THROUGH 16 command, return Descriptor Format Sense Data, including ATA Status Return info.
                if (srbExtension->ResultBufferLength >= sizeof(DESCRIPTOR_SENSE_DATA)) {
                    PDESCRIPTOR_SENSE_DATA descriptorSenseData = (PDESCRIPTOR_SENSE_DATA)srbExtension->ResultBuffer;
                    PSCSI_SENSE_DESCRIPTOR_ATA_STATUS_RETURN ataStatus = (PSCSI_SENSE_DESCRIPTOR_ATA_STATUS_RETURN)((PUCHAR)descriptorSenseData + FIELD_OFFSET(DESCRIPTOR_SENSE_DATA, DescriptorBuffer));

                    AhciZeroMemory((PCHAR)srbExtension->ResultBuffer, srbExtension->ResultBufferLength);

                    // fill sense data header, leave SenseKey, ASC, ASCQ as zero.
                    descriptorSenseData->ErrorCode = SCSI_SENSE_ERRORCODE_DESCRIPTOR_CURRENT;
                    descriptorSenseData->AdditionalSenseLength = sizeof(SCSI_SENSE_DESCRIPTOR_ATA_STATUS_RETURN);

                    // fill ATA Status Return Info.
                    ataStatus->Header.DescriptorType = SCSI_SENSE_DESCRIPTOR_TYPE_ATA_STATUS_RETURN;
                    ataStatus->Header.AdditionalLength = 0x0C;
                    ataStatus->Extend = Is48BitCommand(srbExtension->Flags) ? 1 : 0;

                    ataStatus->Error = ChannelExtension->ReceivedFIS->D2hRegisterFis.Error;
                    ataStatus->SectorCount7_0 = ChannelExtension->ReceivedFIS->D2hRegisterFis.SectorCount;
                    ataStatus->LbaLow7_0 = ChannelExtension->ReceivedFIS->D2hRegisterFis.SectorNumber;
                    ataStatus->LbaMid7_0 = ChannelExtension->ReceivedFIS->D2hRegisterFis.CylLow;
                    ataStatus->LbaHigh7_0 = ChannelExtension->ReceivedFIS->D2hRegisterFis.CylHigh;
                    ataStatus->Device = ChannelExtension->ReceivedFIS->D2hRegisterFis.Dev_Head;
                    ataStatus->Status = ChannelExtension->ReceivedFIS->D2hRegisterFis.Status;

                    if (Is48BitCommand(srbExtension->Flags)) {
                        ataStatus->SectorCount15_8 = ChannelExtension->ReceivedFIS->D2hRegisterFis.SectorCount_Exp;
                        ataStatus->LbaLow15_8 = ChannelExtension->ReceivedFIS->D2hRegisterFis.SectorNum_Exp;
                        ataStatus->LbaMid15_8 = ChannelExtension->ReceivedFIS->D2hRegisterFis.CylLow_Exp;
                        ataStatus->LbaHigh15_8 = ChannelExtension->ReceivedFIS->D2hRegisterFis.CylHigh_Exp;
                    }

                } else {
                    NT_ASSERT(FALSE);
                }
            } else {
                returnTaskFile = (PATA_TASK_FILE)srbExtension->ResultBuffer;

                returnTaskFile->Current.bCommandReg = ChannelExtension->ReceivedFIS->D2hRegisterFis.Status;
                returnTaskFile->Current.bFeaturesReg = ChannelExtension->ReceivedFIS->D2hRegisterFis.Error;
                returnTaskFile->Current.bCylHighReg = ChannelExtension->ReceivedFIS->D2hRegisterFis.CylHigh;
                returnTaskFile->Current.bCylLowReg = ChannelExtension->ReceivedFIS->D2hRegisterFis.CylLow;
                returnTaskFile->Current.bDriveHeadReg = ChannelExtension->ReceivedFIS->D2hRegisterFis.Dev_Head;
                returnTaskFile->Current.bSectorCountReg = ChannelExtension->ReceivedFIS->D2hRegisterFis.SectorCount;
                returnTaskFile->Current.bSectorNumberReg = ChannelExtension->ReceivedFIS->D2hRegisterFis.SectorNumber;
                //if 48bit, get all of it
                if(Is48BitCommand(srbExtension->Flags) && (srbExtension->ResultBufferLength >= sizeof(ATA_TASK_FILE))) {
                    returnTaskFile->Previous.bCommandReg = ChannelExtension->ReceivedFIS->D2hRegisterFis.Status;
                    returnTaskFile->Previous.bFeaturesReg = ChannelExtension->ReceivedFIS->D2hRegisterFis.Error;
                    returnTaskFile->Previous.bCylHighReg = ChannelExtension->ReceivedFIS->D2hRegisterFis.CylHigh_Exp;
                    returnTaskFile->Previous.bCylLowReg = ChannelExtension->ReceivedFIS->D2hRegisterFis.CylLow_Exp;
                    returnTaskFile->Previous.bDriveHeadReg = ChannelExtension->ReceivedFIS->D2hRegisterFis.Dev_Head;
                    returnTaskFile->Previous.bSectorCountReg = ChannelExtension->ReceivedFIS->D2hRegisterFis.SectorCount_Exp;
                    returnTaskFile->Previous.bSectorNumberReg = ChannelExtension->ReceivedFIS->D2hRegisterFis.SectorNum_Exp;
                }
            }
            // set flag SRB_STATUS_AUTOSENSE_VALID so that Storport will copy it back to original Sense Buffer
            srbToRelease->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;

        }

        // interpret ATA error to be SCSI error and fill SenseBuffer
        // also log IO Record
        if (IsAtaCommand(srbExtension->AtaFunction) ||
            IsAtaCfisPayload(srbExtension->AtaFunction)) {
            // IO Record for ATA device is logged in AtaMapError()
            AtaMapError(ChannelExtension, srbToRelease, slotContent->StateFlags.FUA);
        } else {
            if (SRB_STATUS(srbToRelease->SrbStatus) == SRB_STATUS_SUCCESS) {
                ChannelExtension->DeviceExtension[0].IoRecord.SuccessCount++;
            } else {
                ChannelExtension->DeviceExtension[0].IoRecord.OtherErrorCount++;
            }
        }
    }


  //3.1 Make the slot available again
    slotContent->CmdHeader = NULL;
    slotContent->CommandHistoryIndex = 0;
    slotContent->Srb = NULL;
    slotContent->StateFlags.FUA = FALSE;

    //Clear the CommandsToComplete bit
    ChannelExtension->SlotManager.CommandsToComplete &= ~(1 << SlotNumber);
    ChannelExtension->SlotManager.HighPriorityAttribute &= ~(1 << SlotNumber);

  //3.3.1 IO is completing, that IO may have paused the queue so unpause the queue
    ChannelExtension->StateFlags.QueuePaused = FALSE;

  //3.3.2 Complete the command
    if ( (srbToRelease->SrbStatus != SRB_STATUS_SUCCESS) && !isSenseSrb && (srbExtension->RetryCount == 0) ) {
        if ( (ChannelExtension->StateFlags.HybridInfoEnabledOnHiberFile == 1) && 
             IsNCQWriteCommand(srbExtension) ) {
            // NCQ WRITE with Hybrid Information failed, retry once without Hybrid Information.
            ChannelExtension->StateFlags.HybridInfoEnabledOnHiberFile = 0;
            retrySrb = TRUE;
        } else if (srbToRelease->SrbStatus == SRB_STATUS_PARITY_ERROR) {
            // if a command encounters CRC error, retry once
            retrySrb = TRUE;
        }
    }

    if (retrySrb) {
        srbToRelease->SrbStatus = SRB_STATUS_PENDING;
        srbExtension->RetryCount++;
        AhciProcessIo(ChannelExtension, srbToRelease, AtDIRQL);
    } else {
        // otherwise, complete it.
        AhciCompleteRequest(ChannelExtension, srbToRelease, AtDIRQL);
    }
}
Exemple #4
0
VOID
ClasspCleanupProtectedLocks(
    IN PFILE_OBJECT_EXTENSION FsContext
    )
{
    PCOMMON_DEVICE_EXTENSION commonExtension =
        FsContext->DeviceObject->DeviceExtension;

    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension =
        commonExtension->PartitionZeroExtension;

    ULONG newDeviceLockCount = 1;

    PAGED_CODE();

    TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
                "ClasspCleanupProtectedLocks called for %p\n",
                FsContext->DeviceObject));
    TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
                "ClasspCleanupProtectedLocks - FsContext %p is locked "
                "%d times\n", FsContext, FsContext->LockCount));

    NT_ASSERT(BreakOnClose == FALSE);

    //
    // Synchronize with ejection and ejection control requests.
    //

    KeEnterCriticalRegion();
    (VOID)KeWaitForSingleObject(&(fdoExtension->EjectSynchronizationEvent),
                                UserRequest,
                                KernelMode,
                                FALSE,
                          NULL);

    //
    // For each secure lock on this handle decrement the secured lock count
    // for the FDO.  Keep track of the new value.
    //

    if (FsContext->LockCount != 0) {

        do {

            InterlockedDecrement((volatile LONG *)&FsContext->LockCount);

            newDeviceLockCount =
                InterlockedDecrement(&fdoExtension->ProtectedLockCount);

        } while (FsContext->LockCount > 0);

        //
        // If the new lock count has been dropped to zero then issue a lock
        // command to the device.
        //

        TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
                    "ClasspCleanupProtectedLocks: FDO secured lock count = %d "
                    "lock count = %d\n",
                    fdoExtension->ProtectedLockCount,
                    fdoExtension->LockCount));

        if ((newDeviceLockCount == 0) && (fdoExtension->LockCount == 0)) {

            SCSI_REQUEST_BLOCK srb = {0};
            UCHAR srbExBuffer[CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE] = {0};
            PSTORAGE_REQUEST_BLOCK srbEx = (PSTORAGE_REQUEST_BLOCK)srbExBuffer;
            PCDB cdb = NULL;
            NTSTATUS status;
            PSCSI_REQUEST_BLOCK srbPtr;

            TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
                        "ClasspCleanupProtectedLocks: FDO lock count dropped "
                        "to zero\n"));

            if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
                #pragma prefast(suppress:26015, "InitializeStorageRequestBlock ensures buffer access is bounded")
                status = InitializeStorageRequestBlock(srbEx,
                                                       STORAGE_ADDRESS_TYPE_BTL8,
                                                       sizeof(srbExBuffer),
                                                       1,
                                                       SrbExDataTypeScsiCdb16);
                if (NT_SUCCESS(status)) {
                    srbEx->TimeOutValue = fdoExtension->TimeOutValue;
                    SrbSetCdbLength(srbEx, 6);
                    cdb = SrbGetCdb(srbEx);
                    srbPtr = (PSCSI_REQUEST_BLOCK)srbEx;
                } else {
                    //
                    // Should not happen. Revert to legacy SRB.
                    //
                    NT_ASSERT(FALSE);
                    srb.TimeOutValue = fdoExtension->TimeOutValue;
                    srb.CdbLength = 6;
                    cdb = (PCDB) &(srb.Cdb);
                    srbPtr = &srb;
                }

            } else {

                srb.TimeOutValue = fdoExtension->TimeOutValue;
                srb.CdbLength = 6;
                cdb = (PCDB) &(srb.Cdb);
                srbPtr = &srb;

            }

            cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;

            //
            // TRUE - prevent media removal.
            // FALSE - allow media removal.
            //

            cdb->MEDIA_REMOVAL.Prevent = FALSE;

            status = ClassSendSrbSynchronous(fdoExtension->DeviceObject,
                                             srbPtr,
                                             NULL,
                                             0,
                                             FALSE);

            TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
                        "ClasspCleanupProtectedLocks: unlock request to drive "
                        "returned status %lx\n", status));
        }
    }

    KeSetEvent(&fdoExtension->EjectSynchronizationEvent,
               IO_NO_INCREMENT,
               FALSE);
    KeLeaveCriticalRegion();
    return;
}