Пример #1
0
/*++////////////////////////////////////////////////////////////////////////////

ClassIoCompleteAssociated()

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:

    Fdo - Supplies the functional device object which represents the target.

    Irp - Supplies the Irp which has completed.

    Context - Supplies a pointer to the SRB.

Return Value:

    NT status

--*/
NTSTATUS
NTAPI
ClassIoCompleteAssociated(
    IN PDEVICE_OBJECT Fdo,
    IN PIRP Irp,
    IN PVOID Context
    )
{
    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;

    PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
    PSCSI_REQUEST_BLOCK srb = Context;

    PIRP originalIrp = Irp->AssociatedIrp.MasterIrp;
    LONG irpCount;

    NTSTATUS status;
    BOOLEAN retry;

    DBGWARN(("ClassIoCompleteAssociated is OBSOLETE !"));

    //
    // Check SRB status for success of completing request.
    //

    if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {

        ULONG retryInterval;

        DebugPrint((2,"ClassIoCompleteAssociated: IRP %p, SRB %p", Irp, srb));

        //
        // Release the queue if it is frozen.
        //

        if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
            ClassReleaseQueue(Fdo);
        }

        retry = ClassInterpretSenseInfo(
                    Fdo,
                    srb,
                    irpStack->MajorFunction,
                    irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ?
                        irpStack->Parameters.DeviceIoControl.IoControlCode :
                        0,
                    MAXIMUM_RETRIES -
                        ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4),
                    &status,
                    &retryInterval);

        //
        // If the status is verified required and the this request
        // should bypass verify required then retry the request.
        //

        if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
            status == STATUS_VERIFY_REQUIRED) {

            status = STATUS_IO_DEVICE_ERROR;
            retry = TRUE;
        }

        if (retry && ((*(PCHAR*)&irpStack->Parameters.Others.Argument4)--)) {

            //
            // Retry request. If the class driver has supplied a StartIo,
            // call it directly for retries.
            //

            DebugPrint((1, "Retry request %p\n", Irp));

            if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) {
                FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb);
            }

            RetryRequest(Fdo, Irp, srb, TRUE, retryInterval);

            return STATUS_MORE_PROCESSING_REQUIRED;
        }

    } else {

        //
        // Set status for successful request.
        //

        status = STATUS_SUCCESS;

    } // end if (SRB_STATUS(srb->SrbStatus) ...

    //
    // Return SRB to list.
    //

    if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) {
        FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb);
    }

    ClassFreeOrReuseSrb(fdoExtension, srb);

    //
    // Set status in completing IRP.
    //

    Irp->IoStatus.Status = status;

    DebugPrint((2, "ClassIoCompleteAssociated: Partial xfer IRP %p\n", Irp));

    //
    // Get next stack location. This original request is unused
    // except to keep track of the completing partial IRPs so the
    // stack location is valid.
    //

    irpStack = IoGetNextIrpStackLocation(originalIrp);

    //
    // Update status only if error so that if any partial transfer
    // completes with error, then the original IRP will return with
    // error. If any of the asynchronous partial transfer IRPs fail,
    // with an error then the original IRP will return 0 bytes transfered.
    // This is an optimization for successful transfers.
    //

    if (!NT_SUCCESS(status)) {

        originalIrp->IoStatus.Status = status;
        originalIrp->IoStatus.Information = 0;

        //
        // Set the hard error if necessary.
        //

        if (IoIsErrorUserInduced(status)) {

            //
            // Store DeviceObject for filesystem.
            //

            IoSetHardErrorOrVerifyDevice(originalIrp, Fdo);
        }
    }

    //
    // Decrement and get the count of remaining IRPs.
    //

    irpCount = InterlockedDecrement(
                    (PLONG)&irpStack->Parameters.Others.Argument1);

    DebugPrint((2, "ClassIoCompleteAssociated: Partial IRPs left %d\n",
                irpCount));

    //
    // Ensure that the irpCount doesn't go negative.  This was happening once
    // because classpnp would get confused if it ran out of resources when
    // splitting the request.
    //

    ASSERT(irpCount >= 0);

    if (irpCount == 0) {

        //
        // All partial IRPs have completed.
        //

        DebugPrint((2,
                 "ClassIoCompleteAssociated: All partial IRPs complete %p\n",
                 originalIrp));

        if (fdoExtension->CommonExtension.DriverExtension->InitData.ClassStartIo) {

            //
            // Acquire a separate copy of the remove lock so the debugging code
            // works okay and we don't have to hold up the completion of this
            // irp until after we start the next packet(s).
            //

            KIRQL oldIrql;
            UCHAR uniqueAddress;
            ClassAcquireRemoveLock(Fdo, (PIRP)&uniqueAddress);
            ClassReleaseRemoveLock(Fdo, originalIrp);
            ClassCompleteRequest(Fdo, originalIrp, IO_DISK_INCREMENT);

            KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
            IoStartNextPacket(Fdo, FALSE);
            KeLowerIrql(oldIrql);

            ClassReleaseRemoveLock(Fdo, (PIRP)&uniqueAddress);

        } else {

            //
            // just complete this request
            //

            ClassReleaseRemoveLock(Fdo, originalIrp);
            ClassCompleteRequest(Fdo, originalIrp, IO_DISK_INCREMENT);

        }

    }

    //
    // Deallocate IRP and indicate the I/O system should not attempt any more
    // processing.
    //

    IoFreeIrp(Irp);
    return STATUS_MORE_PROCESSING_REQUIRED;

} // end ClassIoCompleteAssociated()
Пример #2
0
/*
 *  InterpretTransferPacketError
 *
 *      Interpret the SRB error into a meaningful IRP status.
 *      ClassInterpretSenseInfo also may modify the SRB for the retry.
 *
 *      Return TRUE iff packet should be retried.
 */
BOOLEAN InterpretTransferPacketError(PTRANSFER_PACKET Pkt)
{
    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Pkt->Fdo->DeviceExtension;
    PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
    ULONG timesAlreadyRetried;
    BOOLEAN shouldRetry = FALSE;
    PCDB pCdb = ClasspTransferPacketGetCdb(Pkt);

    /*
     *  Interpret the error using the returned sense info first.
     */
    Pkt->RetryIn100nsUnits = 0;

    /*
     *  Pre-calculate the number of times the IO has already been
     *  retried, so that all InterpretSenseInfo routines get the right value.
     */
    if (pCdb->MEDIA_REMOVAL.OperationCode == SCSIOP_MEDIUM_REMOVAL)
    {
        timesAlreadyRetried = NUM_LOCKMEDIAREMOVAL_RETRIES - Pkt->NumRetries;
    }
    else if ((pCdb->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE) ||
             (pCdb->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE10))
    {
        timesAlreadyRetried = NUM_MODESENSE_RETRIES - Pkt->NumRetries;
    }
    else if ((pCdb->CDB10.OperationCode == SCSIOP_READ_CAPACITY) ||
             (pCdb->CDB16.OperationCode == SCSIOP_READ_CAPACITY16))
    {
        timesAlreadyRetried = NUM_DRIVECAPACITY_RETRIES - Pkt->NumRetries;
    }
    else if (IS_SCSIOP_READWRITE(pCdb->CDB10.OperationCode))
    {
        timesAlreadyRetried = NUM_IO_RETRIES - Pkt->NumRetries;
    }
    else if (pCdb->TOKEN_OPERATION.OperationCode == SCSIOP_POPULATE_TOKEN &&
             pCdb->TOKEN_OPERATION.ServiceAction == SERVICE_ACTION_POPULATE_TOKEN)
    {
        timesAlreadyRetried = NUM_POPULATE_TOKEN_RETRIES - Pkt->NumRetries;
    }
    else if (pCdb->TOKEN_OPERATION.OperationCode == SCSIOP_WRITE_USING_TOKEN &&
             pCdb->TOKEN_OPERATION.ServiceAction == SERVICE_ACTION_WRITE_USING_TOKEN)
    {
        timesAlreadyRetried = NUM_WRITE_USING_TOKEN_RETRIES - Pkt->NumRetries;
    }
    else if (ClasspIsReceiveTokenInformation(pCdb))
    {
        timesAlreadyRetried = NUM_RECEIVE_TOKEN_INFORMATION_RETRIES - Pkt->NumRetries;
    }
    else
    {
        TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "Unhandled SRB Function %xh in error path for packet %p (did miniport change Srb.Cdb.OperationCode ?)", (ULONG)pCdb->CDB10.OperationCode, Pkt));
        timesAlreadyRetried = 0;
    }


    if (fdoData->InterpretSenseInfo != NULL) {

        SCSI_REQUEST_BLOCK tempSrb = {0};
        PSCSI_REQUEST_BLOCK srbPtr = (PSCSI_REQUEST_BLOCK)Pkt->Srb;

        // SAL annotation and ClassInitializeEx() both validate this
        NT_ASSERT(fdoData->InterpretSenseInfo->Interpret != NULL);

        //
        // If class driver does not support extended SRB and this is
        // an extended SRB, convert to legacy SRB and pass to class
        // driver.
        //
        if ((Pkt->Srb->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) &&
            ((fdoExtension->CommonExtension.DriverExtension->SrbSupport &
              CLASS_SRB_STORAGE_REQUEST_BLOCK) == 0)) {
            ClasspConvertToScsiRequestBlock(&tempSrb, (PSTORAGE_REQUEST_BLOCK)Pkt->Srb);
            srbPtr = &tempSrb;
        }

        shouldRetry = fdoData->InterpretSenseInfo->Interpret(Pkt->Fdo,
                                                             Pkt->OriginalIrp,
                                                             srbPtr,
                                                             IRP_MJ_SCSI,
                                                             0,
                                                             timesAlreadyRetried,
                                                             Pkt->RetryHistory,
                                                             &Pkt->Irp->IoStatus.Status,
                                                             &Pkt->RetryIn100nsUnits);

    }
    else if (pCdb->MEDIA_REMOVAL.OperationCode == SCSIOP_MEDIUM_REMOVAL){

        ULONG retryIntervalSeconds = 0;
        /*
         *  This is an Ejection Control SRB.  Interpret its sense info specially.
         */
        shouldRetry = ClassInterpretSenseInfo(
                            Pkt->Fdo,
                            (PSCSI_REQUEST_BLOCK)Pkt->Srb,
                            IRP_MJ_SCSI,
                            0,
                            timesAlreadyRetried,
                            &Pkt->Irp->IoStatus.Status,
                            &retryIntervalSeconds);

        if (shouldRetry){
            /*
             *  If the device is not ready, wait at least 2 seconds before retrying.
             */
            PVOID senseInfoBuffer = ClasspTransferPacketGetSenseInfoBuffer(Pkt);

            UCHAR senseInfoBufferLength = ClasspTransferPacketGetSenseInfoBufferLength(Pkt);
            BOOLEAN validSense = FALSE;
            UCHAR additionalSenseCode = 0;
            BOOLEAN setRetryIntervalSeconds = FALSE;

            validSense = ScsiGetSenseKeyAndCodes(senseInfoBuffer,
                                                 senseInfoBufferLength,
                                                 SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED,
                                                 NULL,
                                                 &additionalSenseCode,
                                                 NULL);

            if (validSense) {

                if ((Pkt->Irp->IoStatus.Status == STATUS_DEVICE_NOT_READY) &&
                    (additionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)) {
                    setRetryIntervalSeconds = TRUE;
                }
            }

            if (!setRetryIntervalSeconds && (SRB_STATUS(Pkt->Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT)) {
                setRetryIntervalSeconds = TRUE;
            }

            if (setRetryIntervalSeconds) {
                retryIntervalSeconds = MAX(retryIntervalSeconds, 2);
            }
        }

        if (shouldRetry)
        {
            Pkt->RetryIn100nsUnits = retryIntervalSeconds;
            Pkt->RetryIn100nsUnits *= 1000 * 1000 * 10;
        }

    }
    else if ((pCdb->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE) ||
            (pCdb->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE10)){

        ULONG retryIntervalSeconds = 0;
        /*
         *  This is an Mode Sense SRB.  Interpret its sense info specially.
         */
        shouldRetry = ClassInterpretSenseInfo(
                            Pkt->Fdo,
                            (PSCSI_REQUEST_BLOCK)Pkt->Srb,
                            IRP_MJ_SCSI,
                            0,
                            timesAlreadyRetried,
                            &Pkt->Irp->IoStatus.Status,
                            &retryIntervalSeconds);
        if (shouldRetry){
            /*
             *  If the device is not ready, wait at least 2 seconds before retrying.
             */
            PVOID senseInfoBuffer = ClasspTransferPacketGetSenseInfoBuffer(Pkt);
            UCHAR senseInfoBufferLength = ClasspTransferPacketGetSenseInfoBufferLength(Pkt);
            BOOLEAN validSense = FALSE;
            UCHAR additionalSenseCode = 0;
            BOOLEAN setRetryIntervalSeconds = FALSE;

            NT_ASSERT(senseInfoBuffer);

            validSense = ScsiGetSenseKeyAndCodes(senseInfoBuffer,
                                                 senseInfoBufferLength,
                                                 SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED,
                                                 NULL,
                                                 &additionalSenseCode,
                                                 NULL);

            if (validSense) {
                if ((Pkt->Irp->IoStatus.Status == STATUS_DEVICE_NOT_READY) &&
                    (additionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)) {
                    setRetryIntervalSeconds = TRUE;
                }
            }

            if (!setRetryIntervalSeconds && (SRB_STATUS(Pkt->Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT)) {
                setRetryIntervalSeconds = TRUE;
            }

            if (setRetryIntervalSeconds) {
                retryIntervalSeconds = MAX(retryIntervalSeconds, 2);
            }
        }

        /*
         *  Some special cases for mode sense.
         */
        if (Pkt->Irp->IoStatus.Status == STATUS_VERIFY_REQUIRED){
            shouldRetry = TRUE;
        }
        else if (SRB_STATUS(Pkt->Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN){
            /*
             *  This is a HACK.
             *  Atapi returns SRB_STATUS_DATA_OVERRUN when it really means
             *  underrun (i.e. success, and the buffer is longer than needed).
             *  So treat this as a success.
             *  When the caller of this function sees that the status was changed to success,
             *  it will add the transferred length to the original irp.
             */
            Pkt->Irp->IoStatus.Status = STATUS_SUCCESS;
            shouldRetry = FALSE;
        }

        if (shouldRetry)
        {
            Pkt->RetryIn100nsUnits = retryIntervalSeconds;
            Pkt->RetryIn100nsUnits *= 1000 * 1000 * 10;
        }

    }
    else if ((pCdb->CDB10.OperationCode == SCSIOP_READ_CAPACITY) ||
             (pCdb->CDB16.OperationCode == SCSIOP_READ_CAPACITY16)) {

        ULONG retryIntervalSeconds = 0;

        /*
         *  This is a Drive Capacity SRB.  Interpret its sense info specially.
         */
        shouldRetry = ClassInterpretSenseInfo(
                            Pkt->Fdo,
                            (PSCSI_REQUEST_BLOCK)Pkt->Srb,
                            IRP_MJ_SCSI,
                            0,
                            timesAlreadyRetried,
                            &Pkt->Irp->IoStatus.Status,
                            &retryIntervalSeconds);
        if (Pkt->Irp->IoStatus.Status == STATUS_VERIFY_REQUIRED){
            shouldRetry = TRUE;
        }

        if (shouldRetry)
        {
            Pkt->RetryIn100nsUnits = retryIntervalSeconds;
            Pkt->RetryIn100nsUnits *= 1000 * 1000 * 10;
        }

    }
    else if (IS_SCSIOP_READWRITE(pCdb->CDB10.OperationCode)) {

        ULONG retryIntervalSeconds = 0;
        /*
         *  This is a Read/Write Data packet.
         */
        PIO_STACK_LOCATION origCurrentSp = IoGetCurrentIrpStackLocation(Pkt->OriginalIrp);

        shouldRetry = ClassInterpretSenseInfo(
                            Pkt->Fdo,
                            (PSCSI_REQUEST_BLOCK)Pkt->Srb,
                            origCurrentSp->MajorFunction,
                            0,
                            timesAlreadyRetried,
                            &Pkt->Irp->IoStatus.Status,
                            &retryIntervalSeconds);
        /*
         *  Deal with some special cases.
         */
        if (Pkt->Irp->IoStatus.Status == STATUS_INSUFFICIENT_RESOURCES){
            /*
             *  We are in extreme low-memory stress.
             *  We will retry in smaller chunks.
             */
            shouldRetry = TRUE;
        }
        else if (TEST_FLAG(origCurrentSp->Flags, SL_OVERRIDE_VERIFY_VOLUME) &&
                (Pkt->Irp->IoStatus.Status == STATUS_VERIFY_REQUIRED)){
            /*
             *  We are still verifying a (possibly) reloaded disk/cdrom.
             *  So retry the request.
             */
            Pkt->Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
            shouldRetry = TRUE;
        }

        if (shouldRetry)
        {
            Pkt->RetryIn100nsUnits = retryIntervalSeconds;
            Pkt->RetryIn100nsUnits *= 1000 * 1000 * 10;
        }

    } else if (ClasspIsOffloadDataTransferCommand(pCdb)) {

        ULONG retryIntervalSeconds = 0;

        Pkt->TransferCount = 0;

        shouldRetry = ClassInterpretSenseInfo(
                            Pkt->Fdo,
                            (PSCSI_REQUEST_BLOCK)Pkt->Srb,
                            IRP_MJ_SCSI,
                            0,
                            timesAlreadyRetried,
                            &Pkt->Irp->IoStatus.Status,
                            &retryIntervalSeconds);

        if (shouldRetry) {

            Pkt->RetryIn100nsUnits = retryIntervalSeconds;
            Pkt->RetryIn100nsUnits *= 1000 * 1000 * 10;

        } else {

            if (ClasspIsTokenOperation(pCdb)) {

                PVOID senseInfoBuffer = ClasspTransferPacketGetSenseInfoBuffer(Pkt);
                UCHAR senseInfoBufferLength = ClasspTransferPacketGetSenseInfoBufferLength(Pkt);
                BOOLEAN validSense = FALSE;
                UCHAR senseKey = 0;
                UCHAR additionalSenseCode = 0;
                UCHAR additionalSenseQual = 0;
                BOOLEAN isInformationValid = FALSE;
                ULONGLONG information = 0;

                NT_ASSERT(senseInfoBuffer);

                validSense = ScsiGetSenseKeyAndCodes(senseInfoBuffer,
                                                     senseInfoBufferLength,
                                                     SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED,
                                                     &senseKey,
                                                     &additionalSenseCode,
                                                     &additionalSenseQual);

                if (validSense) {

                    //
                    // If this is a data underrun condition (i.e. target truncated the offload data transfer),
                    // the SenseData's Information field may have the TransferCount.
                    //
                    if ((senseKey == SCSI_SENSE_COPY_ABORTED || senseKey == SCSI_SENSE_ABORTED_COMMAND) &&
                        (additionalSenseCode == SCSI_ADSENSE_COPY_TARGET_DEVICE_ERROR && additionalSenseQual == SCSI_SENSEQ_DATA_UNDERRUN)) {

                            //
                            // Sense data in Descriptor format
                            //
                            if (IsDescriptorSenseDataFormat(senseInfoBuffer)) {

                                PVOID startBuffer = NULL;
                                UCHAR startBufferLength = 0;


                                if (ScsiGetSenseDescriptor(senseInfoBuffer,
                                                           SrbGetSenseInfoBufferLength(Pkt->Srb),
                                                           &startBuffer,
                                                           &startBufferLength)) {
                                    UCHAR outType;
                                    PVOID outBuffer = NULL;
                                    UCHAR outBufferLength = 0;

                                    UCHAR typeList[1] = {SCSI_SENSE_DESCRIPTOR_TYPE_INFORMATION};

                                    if (ScsiGetNextSenseDescriptorByType(startBuffer,
                                                                         startBufferLength,
                                                                         typeList,
                                                                         ARRAYSIZE(typeList),
                                                                         &outType,
                                                                         &outBuffer,
                                                                         &outBufferLength)) {

                                        if (outType == SCSI_SENSE_DESCRIPTOR_TYPE_INFORMATION) {

                                            if (ScsiValidateInformationSenseDescriptor(outBuffer, outBufferLength)) {
                                                REVERSE_BYTES_QUAD(&information, &(((PSCSI_SENSE_DESCRIPTOR_INFORMATION)outBuffer)->Information));
                                                isInformationValid = TRUE;
                                            }

                                        } else {

                                            //
                                            // ScsiGetNextDescriptorByType should only return a type that is specified by us.
                                            //
                                            NT_ASSERT(FALSE);
                                        }
                                    }
                                }
                            } else {

                                //
                                // Sense data in Fixed format
                                //
                                REVERSE_BYTES(&information, &(((PFIXED_SENSE_DATA)senseInfoBuffer)->Information));
                                isInformationValid = TRUE;
                            }

                        if (isInformationValid) {
                            Pkt->TransferCount = information;
                        }
                    }
                }
            }
        }

    }
    else {
        TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "Unhandled SRB Function %xh in error path for packet %p (did miniport change Srb.Cdb.OperationCode ?)", (ULONG)pCdb->CDB10.OperationCode, Pkt));
    }

    return shouldRetry;
}
Пример #3
0
/*++////////////////////////////////////////////////////////////////////////////

ClasspPowerDownCompletion()

Routine Description:

    This routine is used for intermediate completion of a power up request.
    PowerUp requires four requests to be sent to the lower driver in sequence.

        * The queue is "power locked" to ensure that the class driver power-up
          work can be done before request processing resumes.

        * The power irp is sent down the stack for any filter drivers and the
          port driver to return power and resume command processing for the
          device.  Since the queue is locked, no queued irps will be sent
          immediately.

        * A start unit command is issued to the device with appropriate flags
          to override the "power locked" queue.

        * The queue is "power unlocked" to start processing requests again.

    This routine uses the function in the srb which just completed to determine
    which state it is in.

Arguments:

    DeviceObject - the device object being powered up

    Irp - the IO_REQUEST_PACKET containing the power request

    Srb - the SRB used to perform port/class operations.

Return Value:

    STATUS_MORE_PROCESSING_REQUIRED or
    STATUS_SUCCESS

--*/
NTSTATUS
NTAPI
ClasspPowerDownCompletion(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN PVOID CompletionContext
    )
{
    PCLASS_POWER_CONTEXT context = CompletionContext;
    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
    PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;

    PIO_STACK_LOCATION currentStack = IoGetCurrentIrpStackLocation(Irp);
    PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp);

    NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED;

    DebugPrint((1, "ClasspPowerDownCompletion: Device Object %p, "
                   "Irp %p, Context %p\n",
                DeviceObject, Irp, context));

    ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
    ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE));
    ASSERT(context->Options.PowerDown == TRUE);
    ASSERT(context->Options.HandleSpinDown);

    if(Irp->PendingReturned) {
        IoMarkIrpPending(Irp);
    }

    context->PowerChangeState.PowerDown2++;

    switch(context->PowerChangeState.PowerDown2) {

        case PowerDownDeviceLocked2: {

            PCDB cdb;

            DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp));

            if((context->Options.LockQueue == TRUE) &&
               (!NT_SUCCESS(Irp->IoStatus.Status))) {

                DebugPrint((1, "(%p)\tIrp status was %lx\n",
                            Irp,
                            Irp->IoStatus.Status));
                DebugPrint((1, "(%p)\tSrb status was %lx\n",
                            Irp,
                            context->Srb.SrbStatus));

                Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;

                //
                // Lock was not successful - throw down the power IRP
                // by itself and don't try to spin down the drive or unlock
                // the queue.
                //

                context->InUse = FALSE;
                context = NULL;

                //
                // Set the new power state
                //

                fdoExtension->DevicePowerState =
                    currentStack->Parameters.Power.State.DeviceState;

                //
                // Indicate to Po that we've been successfully powered down
                // so it can do it's notification stuff.
                //

                IoCopyCurrentIrpStackLocationToNext(Irp);
                IoSetCompletionRoutine(Irp,
                                       ClasspStartNextPowerIrpCompletion,
                                       NULL,
                                       TRUE,
                                       TRUE,
                                       TRUE);

                PoSetPowerState(DeviceObject,
                                currentStack->Parameters.Power.Type,
                                currentStack->Parameters.Power.State);

                fdoExtension->PowerDownInProgress = FALSE;

                PoCallDriver(commonExtension->LowerDeviceObject, Irp);

                ClassReleaseRemoveLock(commonExtension->DeviceObject,
                                       Irp);

                return STATUS_MORE_PROCESSING_REQUIRED;

            } else {
                context->QueueLocked = (UCHAR) context->Options.LockQueue;
            }

            if (!TEST_FLAG(fdoExtension->PrivateFdoData->HackFlags,
                           FDO_HACK_NO_SYNC_CACHE)) {

                //
                // send SCSIOP_SYNCHRONIZE_CACHE
                //

                context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
                context->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;

                context->Srb.TimeOutValue = fdoExtension->TimeOutValue;

                context->Srb.SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER |
                                        SRB_FLAGS_DISABLE_AUTOSENSE |
                                        SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
                                        SRB_FLAGS_NO_QUEUE_FREEZE |
                                        SRB_FLAGS_BYPASS_LOCKED_QUEUE;

                context->Srb.SrbStatus = context->Srb.ScsiStatus = 0;
                context->Srb.DataTransferLength = 0;

                context->Srb.CdbLength = 10;

                cdb = (PCDB) context->Srb.Cdb;

                RtlZeroMemory(cdb, sizeof(CDB));
                cdb->SYNCHRONIZE_CACHE10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE;

                IoSetCompletionRoutine(Irp,
                                       ClasspPowerDownCompletion,
                                       context,
                                       TRUE,
                                       TRUE,
                                       TRUE);

                nextStack->Parameters.Scsi.Srb = &(context->Srb);
                nextStack->MajorFunction = IRP_MJ_SCSI;

                status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);

                DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp, status));
                break;

            } else {

                DebugPrint((1, "(%p)\tPower Down: not sending SYNCH_CACHE\n",
                            DeviceObject));
                context->PowerChangeState.PowerDown2++;
                context->Srb.SrbStatus = SRB_STATUS_SUCCESS;
                // and fall through....
            }
            // no break in case the device doesn't like synch_cache commands

        }
         
        case PowerDownDeviceFlushed2: {

            PCDB cdb;

            DebugPrint((1, "(%p)\tPreviously send SCSIOP_SYNCHRONIZE_CACHE\n",
                        Irp));

            //
            // SCSIOP_SYNCHRONIZE_CACHE was sent
            //

            if(SRB_STATUS(context->Srb.SrbStatus) != SRB_STATUS_SUCCESS) {

                BOOLEAN retry;

                DebugPrint((1, "(%p)\tError occured when issuing "
                            "SYNCHRONIZE_CACHE command to device. "
                            "Srb %p, Status %lx\n",
                            Irp,
                            &context->Srb,
                            context->Srb.SrbStatus));

                ASSERT(!(TEST_FLAG(context->Srb.SrbStatus,
                                   SRB_STATUS_QUEUE_FROZEN)));
                ASSERT(context->Srb.Function == SRB_FUNCTION_EXECUTE_SCSI);

                context->RetryInterval = 0;
                retry = ClassInterpretSenseInfo(
                            commonExtension->DeviceObject,
                            &context->Srb,
                            IRP_MJ_SCSI,
                            IRP_MJ_POWER,
                            MAXIMUM_RETRIES - context->RetryCount,
                            &status,
                            &context->RetryInterval);

                if((retry == TRUE) && (context->RetryCount-- != 0)) {

                        DebugPrint((1, "(%p)\tRetrying failed request\n", Irp));

                        //
                        // decrement the state so we come back through here
                        // the next time.
                        //

                        context->PowerChangeState.PowerDown2--;
                        RetryPowerRequest(commonExtension->DeviceObject,
                                          Irp,
                                          context);
                        break;
                }

                DebugPrint((1, "(%p)\tSYNCHRONIZE_CACHE not retried\n", Irp));
                context->RetryCount = MAXIMUM_RETRIES;

            } // end !SRB_STATUS_SUCCESS

            //
            // note: we are purposefully ignoring any errors.  if the drive
            //       doesn't support a synch_cache, then we're up a creek
            //       anyways.
            //

            DebugPrint((1, "(%p)\tSending stop unit to device\n", Irp));

            //
            // Issue the start unit command to the device.
            //

            context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
            context->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;

            context->Srb.TimeOutValue = START_UNIT_TIMEOUT;

            context->Srb.SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER |
                                    SRB_FLAGS_DISABLE_AUTOSENSE |
                                    SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
                                    SRB_FLAGS_NO_QUEUE_FREEZE |
                                    SRB_FLAGS_BYPASS_LOCKED_QUEUE;

            context->Srb.SrbStatus = context->Srb.ScsiStatus = 0;
            context->Srb.DataTransferLength = 0;

            context->Srb.CdbLength = 6;

            cdb = (PCDB) context->Srb.Cdb;
            RtlZeroMemory(cdb, sizeof(CDB));

            cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
            cdb->START_STOP.Start = 0;
            cdb->START_STOP.Immediate = 1;

            IoSetCompletionRoutine(Irp,
                                   ClasspPowerDownCompletion,
                                   context,
                                   TRUE,
                                   TRUE,
                                   TRUE);

            nextStack->Parameters.Scsi.Srb = &(context->Srb);
            nextStack->MajorFunction = IRP_MJ_SCSI;

            status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);

            DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp, status));
            break;

        }

        case PowerDownDeviceStopped2: {

            BOOLEAN ignoreError = TRUE;

            //
            // stop was sent
            //

            if(SRB_STATUS(context->Srb.SrbStatus) != SRB_STATUS_SUCCESS) {

                BOOLEAN retry;

                DebugPrint((1, "(%p)\tError occured when issueing STOP_UNIT "
                            "command to device. Srb %p, Status %lx\n",
                            Irp,
                            &context->Srb,
                            context->Srb.SrbStatus));

                ASSERT(!(TEST_FLAG(context->Srb.SrbStatus,
                                   SRB_STATUS_QUEUE_FROZEN)));
                ASSERT(context->Srb.Function == SRB_FUNCTION_EXECUTE_SCSI);

                context->RetryInterval = 0;
                retry = ClassInterpretSenseInfo(
                            commonExtension->DeviceObject,
                            &context->Srb,
                            IRP_MJ_SCSI,
                            IRP_MJ_POWER,
                            MAXIMUM_RETRIES - context->RetryCount,
                            &status,
                            &context->RetryInterval);

                if((retry == TRUE) && (context->RetryCount-- != 0)) {

                        DebugPrint((1, "(%p)\tRetrying failed request\n", Irp));

                        //
                        // decrement the state so we come back through here
                        // the next time.
                        //

                        context->PowerChangeState.PowerDown2--;
                        RetryPowerRequest(commonExtension->DeviceObject,
                                          Irp,
                                          context);
                        break;
                }

                DebugPrint((1, "(%p)\tSTOP_UNIT not retried\n", Irp));
                context->RetryCount = MAXIMUM_RETRIES;

            } // end !SRB_STATUS_SUCCESS


            DebugPrint((1, "(%p)\tPreviously sent stop unit\n", Irp));

            //
            // some operations, such as a physical format in progress,
            // should not be ignored and should fail the power operation.
            //

            if (!NT_SUCCESS(status)) {

                PSENSE_DATA senseBuffer = context->Srb.SenseInfoBuffer;

                if (TEST_FLAG(context->Srb.SrbStatus,
                              SRB_STATUS_AUTOSENSE_VALID) &&
                    ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_NOT_READY) &&
                    (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) &&
                    (senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_FORMAT_IN_PROGRESS)
                    ) {
                    ignoreError = FALSE;
                    context->FinalStatus = STATUS_DEVICE_BUSY;
                    status = context->FinalStatus;
                }

            }

            if (NT_SUCCESS(status) || ignoreError) {

                //
                // Issue the actual power request to the lower driver.
                //

                Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;

                IoCopyCurrentIrpStackLocationToNext(Irp);

                IoSetCompletionRoutine(Irp,
                                       ClasspPowerDownCompletion,
                                       context,
                                       TRUE,
                                       TRUE,
                                       TRUE);

                status = PoCallDriver(commonExtension->LowerDeviceObject, Irp);

                DebugPrint((1, "(%p)\tPoCallDriver returned %lx\n", Irp, status));
                break;
            }
            
            // else fall through w/o sending the power irp, since the device
            // is reporting an error that would be "really bad" to power down
            // during.

        }

        case PowerDownDeviceOff2: {

            //
            // SpinDown request completed ... whether it succeeded or not is
            // another matter entirely.
            //

            DebugPrint((1, "(%p)\tPreviously sent power irp\n", Irp));

            if (context->QueueLocked) {

                DebugPrint((1, "(%p)\tUnlocking queue\n", Irp));

                context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);

                context->Srb.SrbStatus = context->Srb.ScsiStatus = 0;
                context->Srb.DataTransferLength = 0;

                context->Srb.Function = SRB_FUNCTION_UNLOCK_QUEUE;
                context->Srb.SrbFlags = SRB_FLAGS_BYPASS_LOCKED_QUEUE;
                nextStack->Parameters.Scsi.Srb = &(context->Srb);
                nextStack->MajorFunction = IRP_MJ_SCSI;

                IoSetCompletionRoutine(Irp,
                                       ClasspPowerDownCompletion,
                                       context,
                                       TRUE,
                                       TRUE,
                                       TRUE);

                status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
                DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n",
                            Irp,
                            status));
                break;
            }

        }

        case PowerDownDeviceUnlocked2: {

            //
            // This is the end of the dance.  Free the srb and complete the
            // request finally.  We're ignoring possible intermediate
            // error conditions ....
            //

            if (context->QueueLocked == FALSE) {
                DebugPrint((1, "(%p)\tFall through (queue not locked)\n", Irp));
            } else {
                DebugPrint((1, "(%p)\tPreviously unlocked queue\n", Irp));
                ASSERT(NT_SUCCESS(Irp->IoStatus.Status));
                ASSERT(context->Srb.SrbStatus == SRB_STATUS_SUCCESS);
            }

            DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp));
            context->InUse = FALSE;
            status = context->FinalStatus; // allow failure to propogate
            context = NULL;

            if(Irp->PendingReturned) {
                IoMarkIrpPending(Irp);
            }

            Irp->IoStatus.Status = status;
            Irp->IoStatus.Information = 0;

            if (NT_SUCCESS(status)) {
                
                //
                // Set the new power state
                //

                fdoExtension->DevicePowerState =
                    currentStack->Parameters.Power.State.DeviceState;

            }


            DebugPrint((1, "(%p)\tStarting next power irp\n", Irp));

            ClassReleaseRemoveLock(DeviceObject, Irp);
            PoStartNextPowerIrp(Irp);
            fdoExtension->PowerDownInProgress = FALSE;

            return status;
        }

        case PowerDownDeviceInitial2: {
            NT_ASSERT(context->PowerChangeState.PowerDown2 != PowerDownDeviceInitial2);
            break;
        }
    }

    return STATUS_MORE_PROCESSING_REQUIRED;
} // end ClasspPowerDownCompletion()
Пример #4
0
/*++////////////////////////////////////////////////////////////////////////////

ClasspPowerUpCompletion()

Routine Description:

    This routine is used for intermediate completion of a power up request.
    PowerUp requires four requests to be sent to the lower driver in sequence.

        * The queue is "power locked" to ensure that the class driver power-up
          work can be done before request processing resumes.

        * The power irp is sent down the stack for any filter drivers and the
          port driver to return power and resume command processing for the
          device.  Since the queue is locked, no queued irps will be sent
          immediately.

        * A start unit command is issued to the device with appropriate flags
          to override the "power locked" queue.

        * The queue is "power unlocked" to start processing requests again.

    This routine uses the function in the srb which just completed to determine
    which state it is in.

Arguments:

    DeviceObject - the device object being powered up

    Irp - the IO_REQUEST_PACKET containing the power request

    Srb - the SRB used to perform port/class operations.

Return Value:

    STATUS_MORE_PROCESSING_REQUIRED or
    STATUS_SUCCESS
    
--*/
NTSTATUS
NTAPI
ClasspPowerUpCompletion(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN PVOID CompletionContext
    )
{
    PCLASS_POWER_CONTEXT context = CompletionContext;
    PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;

    PIO_STACK_LOCATION currentStack = IoGetCurrentIrpStackLocation(Irp);
    PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp);


    NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED;

    DebugPrint((1, "ClasspPowerUpCompletion: Device Object %p, Irp %p, "
                   "Context %p\n",
                DeviceObject, Irp, context));

    ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
    ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE));
    ASSERT(context->Options.PowerDown == FALSE);
    ASSERT(context->Options.HandleSpinUp);

    if(Irp->PendingReturned) {
        IoMarkIrpPending(Irp);
    }

    context->PowerChangeState.PowerUp++;

    switch(context->PowerChangeState.PowerUp) {

        case PowerUpDeviceLocked: {

            DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp));

            //
            // Issue the actual power request to the lower driver.
            //

            IoCopyCurrentIrpStackLocationToNext(Irp);

            //
            // If the lock wasn't successful then just bail out on the power
            // request unless we can ignore failed locks
            //

            if((context->Options.LockQueue == TRUE) &&
               (!NT_SUCCESS(Irp->IoStatus.Status))) {

                DebugPrint((1, "(%p)\tIrp status was %lx\n",
                            Irp, Irp->IoStatus.Status));
                DebugPrint((1, "(%p)\tSrb status was %lx\n",
                            Irp, context->Srb.SrbStatus));

                //
                // Lock was not successful - throw down the power IRP
                // by itself and don't try to spin up the drive or unlock
                // the queue.
                //

                context->InUse = FALSE;
                context = NULL;

                //
                // Set the new power state
                //

                fdoExtension->DevicePowerState =
                    currentStack->Parameters.Power.State.DeviceState;

                Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;

                IoCopyCurrentIrpStackLocationToNext(Irp);

                IoSetCompletionRoutine(Irp,
                                       ClasspStartNextPowerIrpCompletion,
                                       NULL,
                                       TRUE,
                                       TRUE,
                                       TRUE);

                //
                // Indicate to Po that we've been successfully powered up so
                // it can do it's notification stuff.
                //

                PoSetPowerState(DeviceObject,
                                currentStack->Parameters.Power.Type,
                                currentStack->Parameters.Power.State);

                PoCallDriver(commonExtension->LowerDeviceObject, Irp);

                ClassReleaseRemoveLock(commonExtension->DeviceObject,
                                       Irp);

                return STATUS_MORE_PROCESSING_REQUIRED;

            } else {
                context->QueueLocked = (UCHAR) context->Options.LockQueue;
            }

            Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;

            context->PowerChangeState.PowerUp = PowerUpDeviceLocked;

            IoSetCompletionRoutine(Irp,
                                   ClasspPowerUpCompletion,
                                   context,
                                   TRUE,
                                   TRUE,
                                   TRUE);

            status = PoCallDriver(commonExtension->LowerDeviceObject, Irp);

            DebugPrint((2, "(%p)\tPoCallDriver returned %lx\n", Irp, status));
            break;
        }

        case PowerUpDeviceOn: {

            PCDB cdb;

            if(NT_SUCCESS(Irp->IoStatus.Status)) {

                DebugPrint((1, "(%p)\tSending start unit to device\n", Irp));

                //
                // Issue the start unit command to the device.
                //

                context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
                context->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;

                context->Srb.SrbStatus = context->Srb.ScsiStatus = 0;
                context->Srb.DataTransferLength = 0;

                context->Srb.TimeOutValue = START_UNIT_TIMEOUT;

                context->Srb.SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER |
                                        SRB_FLAGS_DISABLE_AUTOSENSE |
                                        SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
                                        SRB_FLAGS_NO_QUEUE_FREEZE;

                if(context->Options.LockQueue) {
                    SET_FLAG(context->Srb.SrbFlags, SRB_FLAGS_BYPASS_LOCKED_QUEUE);
                }

                context->Srb.CdbLength = 6;

                cdb = (PCDB) (context->Srb.Cdb);
                RtlZeroMemory(cdb, sizeof(CDB));


                cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
                cdb->START_STOP.Start = 1;

                context->PowerChangeState.PowerUp = PowerUpDeviceOn;

                IoSetCompletionRoutine(Irp,
                                       ClasspPowerUpCompletion,
                                       context,
                                       TRUE,
                                       TRUE,
                                       TRUE);

                nextStack->Parameters.Scsi.Srb = &(context->Srb);
                nextStack->MajorFunction = IRP_MJ_SCSI;

                status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);

                DebugPrint((2, "(%p)\tIoCallDriver returned %lx\n", Irp, status));

            } else {

                //
                // we're done.
                //

                context->FinalStatus = Irp->IoStatus.Status;
                goto ClasspPowerUpCompletionFailure;
            }

            break;
        }

        case PowerUpDeviceStarted: { // 3

            //
            // First deal with an error if one occurred.
            //

            if(SRB_STATUS(context->Srb.SrbStatus) != SRB_STATUS_SUCCESS) {

                BOOLEAN retry;

                DebugPrint((1, "%p\tError occured when issuing START_UNIT "
                            "command to device. Srb %p, Status %x\n",
                            Irp,
                            &context->Srb,
                            context->Srb.SrbStatus));

                ASSERT(!(TEST_FLAG(context->Srb.SrbStatus,
                                   SRB_STATUS_QUEUE_FROZEN)));
                ASSERT(context->Srb.Function == SRB_FUNCTION_EXECUTE_SCSI);

                context->RetryInterval = 0;

                retry = ClassInterpretSenseInfo(
                            commonExtension->DeviceObject,
                            &context->Srb,
                            IRP_MJ_SCSI,
                            IRP_MJ_POWER,
                            MAXIMUM_RETRIES - context->RetryCount,
                            &status,
                            &context->RetryInterval);

                if((retry == TRUE) && (context->RetryCount-- != 0)) {

                    DebugPrint((1, "(%p)\tRetrying failed request\n", Irp));

                    //
                    // Decrement the state so we come back through here the
                    // next time.
                    //

                    context->PowerChangeState.PowerUp--;

                    RetryPowerRequest(commonExtension->DeviceObject,
                                      Irp,
                                      context);

                    break;

                }

                // reset retries
                context->RetryCount = MAXIMUM_RETRIES;

            }

ClasspPowerUpCompletionFailure:

            DebugPrint((1, "(%p)\tPreviously spun device up\n", Irp));

            if (context->QueueLocked) {
                DebugPrint((1, "(%p)\tUnlocking queue\n", Irp));

                context->Srb.Function = SRB_FUNCTION_UNLOCK_QUEUE;
                context->Srb.SrbFlags = SRB_FLAGS_BYPASS_LOCKED_QUEUE;
                context->Srb.SrbStatus = context->Srb.ScsiStatus = 0;
                context->Srb.DataTransferLength = 0;

                nextStack->Parameters.Scsi.Srb = &(context->Srb);
                nextStack->MajorFunction = IRP_MJ_SCSI;

                context->PowerChangeState.PowerUp = PowerUpDeviceStarted;

                IoSetCompletionRoutine(Irp,
                                       ClasspPowerUpCompletion,
                                       context,
                                       TRUE,
                                       TRUE,
                                       TRUE);

                status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
                DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n",
                            Irp, status));
                break;
            }

            // Fall-through to next case...

        }

        case PowerUpDeviceUnlocked: {

            //
            // This is the end of the dance.  Free the srb and complete the
            // request finally.  We're ignoring possible intermediate
            // error conditions ....
            //

            if (context->QueueLocked) {
                DebugPrint((1, "(%p)\tPreviously unlocked queue\n", Irp));
                ASSERT(NT_SUCCESS(Irp->IoStatus.Status));
                ASSERT(context->Srb.SrbStatus == SRB_STATUS_SUCCESS);
            } else {
                DebugPrint((1, "(%p)\tFall-through (queue not locked)\n", Irp));
            }

            DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp));
            context->InUse = FALSE;

            status = context->FinalStatus;
            Irp->IoStatus.Status = status;

            context = NULL;

            //
            // Set the new power state
            //

            if(NT_SUCCESS(status)) {
                fdoExtension->DevicePowerState =
                    currentStack->Parameters.Power.State.DeviceState;
            }

            //
            // Indicate to Po that we've been successfully powered up so
            // it can do it's notification stuff.
            //
            
            PoSetPowerState(DeviceObject,
                            currentStack->Parameters.Power.Type,
                            currentStack->Parameters.Power.State);

            DebugPrint((1, "(%p)\tStarting next power irp\n", Irp));
            ClassReleaseRemoveLock(DeviceObject, Irp);
            PoStartNextPowerIrp(Irp);

            return status;
        }

        case PowerUpDeviceInitial: {
            NT_ASSERT(context->PowerChangeState.PowerUp != PowerUpDeviceInitial);
            break;
        }
    }

    return STATUS_MORE_PROCESSING_REQUIRED;
} // end ClasspPowerUpCompletion()
Пример #5
0
NTSTATUS
NTAPI
CdRomUpdateMmcDriveCapabilitiesCompletion(
    IN PDEVICE_OBJECT Unused,
    IN PIRP Irp,
    IN PDEVICE_OBJECT Fdo
    )
{
    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
    //PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
    PCDROM_DATA cdData = fdoExtension->CommonExtension.DriverData;
    PCDROM_MMC_EXTENSION mmcData = &(cdData->Mmc);
    PSCSI_REQUEST_BLOCK srb = &(mmcData->CapabilitiesSrb);
    PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    //PIRP delayedIrp;
    ULONG retryCount;
    LARGE_INTEGER delay;

    
    // completion routine should retry as necessary.
    // when success, clear the flag to allow startio to proceed.
    // else fail original request when retries are exhausted.

    ASSERT(mmcData->CapabilitiesIrp == Irp);

    // for now, if succeeded, just print the new pages.

    if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
        
        //
        // ISSUE-2000/4/20-henrygab - should we try to reallocate if size
        //                            available became larger than what we
        //                            originally allocated?  otherwise, it
        //                            is possible (not probable) that we
        //                            would miss the feature.  can check
        //                            that by finding out what the last
        //                            feature is in the current group.
        //

        BOOLEAN retry;
        ULONG retryInterval;
        
        //
        // Release the queue if it is frozen.
        //

        if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
            ClassReleaseQueue(Fdo);
        }

        retry = ClassInterpretSenseInfo(
                    Fdo,
                    srb,
                    irpStack->MajorFunction,
                    0,
                    MAXIMUM_RETRIES - ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4),
                    &status,
                    &retryInterval);

        //
        // DATA_OVERRUN is not an error in this case....
        //

        if (status == STATUS_DATA_OVERRUN) {
            status = STATUS_SUCCESS;
        }

        //
        // override verify_volume based on original irp's settings
        //

        if (TEST_FLAG(irpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME) &&
            status == STATUS_VERIFY_REQUIRED) {
            status = STATUS_IO_DEVICE_ERROR;
            retry = TRUE;
        }

        //
        // get current retry count
        //
        retryCount = PtrToUlong(irpStack->Parameters.Others.Argument1);

        if (retry && retryCount) {

            //
            // update retry count
            //
            irpStack->Parameters.Others.Argument1 = UlongToPtr(retryCount-1);


            delay.QuadPart = retryInterval;
            delay.QuadPart *= (LONGLONG)1000 * 1000 * 10;
            
            //
            // retry the request
            //

            KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
                       "Not using ClassRetryRequest Yet\n"));
            KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
                       "Retry update capabilities %p\n", Irp));
            CdRomPrepareUpdateCapabilitiesIrp(Fdo);
            
            CdRomRetryRequest(fdoExtension, Irp, retryInterval, TRUE);

            //
            // ClassRetryRequest(Fdo, Irp, delay);
            //
            
            return STATUS_MORE_PROCESSING_REQUIRED;
        
        }

    } else {
        
        status = STATUS_SUCCESS;

    }

    Irp->IoStatus.Status = status;

    KeSetEvent(&mmcData->CapabilitiesEvent, IO_CD_ROM_INCREMENT, FALSE);


    return STATUS_MORE_PROCESSING_REQUIRED;
}
Пример #6
0
/*
 *  InterpretTransferPacketError
 *
 *      Interpret the SRB error into a meaningful IRP status.
 *      ClassInterpretSenseInfo also may modify the SRB for the retry.
 *
 *      Return TRUE iff packet should be retried.
 */
BOOLEAN NTAPI InterpretTransferPacketError(PTRANSFER_PACKET Pkt)
{
    BOOLEAN shouldRetry = FALSE;
    PCDB pCdb = (PCDB)Pkt->Srb.Cdb;
    
    /*
     *  Interpret the error using the returned sense info first.
     */
    Pkt->RetryIntervalSec = 0;
    if (pCdb->MEDIA_REMOVAL.OperationCode == SCSIOP_MEDIUM_REMOVAL){
        /*
         *  This is an Ejection Control SRB.  Interpret its sense info specially.
         */
        shouldRetry = ClassInterpretSenseInfo(
                            Pkt->Fdo,
                            &Pkt->Srb,
                            IRP_MJ_SCSI,
                            0,
                            MAXIMUM_RETRIES - Pkt->NumRetries,
                            &Pkt->Irp->IoStatus.Status,
                            &Pkt->RetryIntervalSec);
        if (shouldRetry){
            /*
             *  If the device is not ready, wait at least 2 seconds before retrying.
             */
            PSENSE_DATA senseInfoBuffer = Pkt->Srb.SenseInfoBuffer; 
            ASSERT(senseInfoBuffer);
            if (((Pkt->Irp->IoStatus.Status == STATUS_DEVICE_NOT_READY) &&
                (senseInfoBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)) ||
                    (SRB_STATUS(Pkt->Srb.SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT)){
                    
                Pkt->RetryIntervalSec = MAX(Pkt->RetryIntervalSec, 2); 
            }
        }
    }
    else if ((pCdb->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE) ||
            (pCdb->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE10)){
        /*
         *  This is an Mode Sense SRB.  Interpret its sense info specially.
         */
        shouldRetry = ClassInterpretSenseInfo(
                            Pkt->Fdo,
                            &Pkt->Srb,
                            IRP_MJ_SCSI,
                            0,
                            MAXIMUM_RETRIES - Pkt->NumRetries,
                            &Pkt->Irp->IoStatus.Status,
                            &Pkt->RetryIntervalSec);
        if (shouldRetry){
            /*
             *  If the device is not ready, wait at least 2 seconds before retrying.
             */
            PSENSE_DATA senseInfoBuffer = Pkt->Srb.SenseInfoBuffer; 
            ASSERT(senseInfoBuffer);
            if (((Pkt->Irp->IoStatus.Status == STATUS_DEVICE_NOT_READY) &&
                (senseInfoBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)) ||
                    (SRB_STATUS(Pkt->Srb.SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT)){
                    
                Pkt->RetryIntervalSec = MAX(Pkt->RetryIntervalSec, 2); 
            }
        }
        
        /*
         *  Some special cases for mode sense.
         */
        if (Pkt->Irp->IoStatus.Status == STATUS_VERIFY_REQUIRED){
            shouldRetry = TRUE;
        }
        else if (SRB_STATUS(Pkt->Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN){
            /*
             *  This is a HACK.
             *  Atapi returns SRB_STATUS_DATA_OVERRUN when it really means 
             *  underrun (i.e. success, and the buffer is longer than needed).
             *  So treat this as a success.
             */
            Pkt->Irp->IoStatus.Status = STATUS_SUCCESS;
            InterlockedExchangeAdd((PLONG)&Pkt->OriginalIrp->IoStatus.Information, (LONG)Pkt->Srb.DataTransferLength);            
            shouldRetry = FALSE;
        }
    }            
    else if (pCdb->CDB10.OperationCode == SCSIOP_READ_CAPACITY){
        /*
         *  This is a Drive Capacity SRB.  Interpret its sense info specially.
         */
        shouldRetry = ClassInterpretSenseInfo(
                            Pkt->Fdo,
                            &Pkt->Srb,
                            IRP_MJ_SCSI,
                            0,
                            MAXIMUM_RETRIES - Pkt->NumRetries,
                            &Pkt->Irp->IoStatus.Status,
                            &Pkt->RetryIntervalSec);
        if (Pkt->Irp->IoStatus.Status == STATUS_VERIFY_REQUIRED){
            shouldRetry = TRUE;            
        }
    }
    else if ((pCdb->CDB10.OperationCode == SCSIOP_READ) ||
            (pCdb->CDB10.OperationCode == SCSIOP_WRITE)){
        /*
         *  This is a Read/Write Data packet.
         */
        PIO_STACK_LOCATION origCurrentSp = IoGetCurrentIrpStackLocation(Pkt->OriginalIrp);
        
        shouldRetry = ClassInterpretSenseInfo(
                            Pkt->Fdo,
                            &Pkt->Srb,
                            origCurrentSp->MajorFunction,
                            0,
                            MAXIMUM_RETRIES - Pkt->NumRetries,
                            &Pkt->Irp->IoStatus.Status,
                            &Pkt->RetryIntervalSec);
        /*
         *  Deal with some special cases.
         */
        if (Pkt->Irp->IoStatus.Status == STATUS_INSUFFICIENT_RESOURCES){
            /*
             *  We are in extreme low-memory stress.  
             *  We will retry in smaller chunks.
             */
            shouldRetry = TRUE;
        }
        else if (TEST_FLAG(origCurrentSp->Flags, SL_OVERRIDE_VERIFY_VOLUME) &&
                (Pkt->Irp->IoStatus.Status == STATUS_VERIFY_REQUIRED)){
            /*
             *  We are still verifying a (possibly) reloaded disk/cdrom.
             *  So retry the request.
             */
            Pkt->Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR; 
            shouldRetry = TRUE;
        }
    }
    else {
        DBGERR(("Unhandled SRB Function %xh in error path for packet %p (did miniport change Srb.Cdb.OperationCode ?)", (ULONG)pCdb->CDB10.OperationCode, Pkt));
    }

    return shouldRetry;
}