Beispiel #1
0
VOID
ScsiPortLogError(
    IN PVOID HwDeviceExtension,
    IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
    IN UCHAR PathId,
    IN UCHAR TargetId,
    IN UCHAR Lun,
    IN ULONG ErrorCode,
    IN ULONG UniqueId
)

/*++

Routine Description:

    This routine saves the error log information, and queues a DPC if necessary.

Arguments:

    HwDeviceExtension - Supplies the HBA miniport driver's adapter data storage.

    Srb - Supplies an optional pointer to srb if there is one.

    TargetId, Lun and PathId - specify device address on a SCSI bus.

    ErrorCode - Supplies an error code indicating the type of error.

    UniqueId - Supplies a unique identifier for the error.

Return Value:

    None.

--*/

{
    PADAPTER_EXTENSION deviceExtension = GET_FDO_EXTENSION(HwDeviceExtension);
    PDEVICE_OBJECT DeviceObject = deviceExtension->CommonExtension.DeviceObject;
    PSRB_DATA srbData;
    PERROR_LOG_ENTRY errorLogEntry;

    //
    // If the error log entry is already full, then dump the error.
    //

    if (deviceExtension->InterruptData.InterruptFlags & PD_LOG_ERROR) {

#if SCSIDBG_ENABLED
        DebugPrint((1,"ScsiPortLogError: Dumping scsi error log packet.\n"));
        DebugPrint((1,
                    "PathId = %2x, TargetId = %2x, Lun = %2x, ErrorCode = %x, UniqueId = %x.",
                    PathId,
                    TargetId,
                    Lun,
                    ErrorCode,
                    UniqueId
                   ));
#endif
        return;
    }

    //
    // Save the error log data in the log entry.
    //

    errorLogEntry = &deviceExtension->InterruptData.LogEntry;

    errorLogEntry->ErrorCode = ErrorCode;
    errorLogEntry->TargetId = TargetId;
    errorLogEntry->Lun = Lun;
    errorLogEntry->PathId = PathId;
    errorLogEntry->UniqueId = UniqueId;

    //
    // Get the sequence number from the SRB data.
    //

    if (Srb != NULL) {

        srbData = Srb->OriginalRequest;

        ASSERT_SRB_DATA(srbData);

        errorLogEntry->SequenceNumber = srbData->SequenceNumber;
        errorLogEntry->ErrorLogRetryCount = srbData->ErrorLogRetryCount++;
    } else {
        errorLogEntry->SequenceNumber = 0;
        errorLogEntry->ErrorLogRetryCount = 0;
    }

    //
    // Indicate that the error log entry is in use.
    //

    deviceExtension->InterruptData.InterruptFlags |= PD_LOG_ERROR;

    //
    // Request a DPC be queued after the interrupt completes.
    //

    deviceExtension->InterruptData.InterruptFlags |= PD_NOTIFICATION_REQUIRED;

    return;

} // end ScsiPortLogError()
Beispiel #2
0
VOID
ScsiPortIoMapTransfer(
    IN PVOID HwDeviceExtension,
    IN PSCSI_REQUEST_BLOCK Srb,
    IN PVOID LogicalAddress,
    IN ULONG Length
)
/*++

Routine Description:

    Saves the parameters for the call to IoMapTransfer and schedules the DPC
    if necessary.

Arguments:

    HwDeviceExtension - Supplies a the hardware device extension for the
        host bus adapter which will be doing the data transfer.

    Srb - Supplies the particular request that data transfer is for.

    LogicalAddress - Supplies the logical address where the transfer should
        begin.

    Length - Supplies the maximum length in bytes of the transfer.

Return Value:

   None.

--*/

{
    PADAPTER_EXTENSION deviceExtension = GET_FDO_EXTENSION(HwDeviceExtension);
    PSRB_DATA srbData = Srb->OriginalRequest;

    ASSERT_SRB_DATA(srbData);

    //
    // If this is a 64-bit system then this call is illegal.  Bugcheck.
    //

    if(Sp64BitPhysicalAddresses) {
        KeBugCheckEx(PORT_DRIVER_INTERNAL,
                     1,
                     STATUS_NOT_SUPPORTED,
                     (ULONG_PTR) HwDeviceExtension,
                     (ULONG_PTR) deviceExtension->DeviceObject->DriverObject);
    }

    //
    // Make sure this host bus adapter has an Dma adapter object.
    //

    if (deviceExtension->DmaAdapterObject == NULL) {

        //
        // No DMA adapter, no work.
        //

        return;
    }

    ASSERT((Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION) != SRB_FLAGS_UNSPECIFIED_DIRECTION);

    deviceExtension->InterruptData.MapTransferParameters.SrbData = srbData;

    deviceExtension->InterruptData.MapTransferParameters.LogicalAddress = LogicalAddress;
    deviceExtension->InterruptData.MapTransferParameters.Length = Length;
    deviceExtension->InterruptData.MapTransferParameters.SrbFlags = Srb->SrbFlags;

    deviceExtension->InterruptData.InterruptFlags |= PD_MAP_TRANSFER;

    //
    // Request a DPC be queued after the interrupt completes.
    //

    deviceExtension->InterruptData.InterruptFlags |= PD_NOTIFICATION_REQUIRED;

} // end ScsiPortIoMapTransfer()
Beispiel #3
0
VOID
ScsiPortNotification(
    IN SCSI_NOTIFICATION_TYPE NotificationType,
    IN PVOID HwDeviceExtension,
    ...
)

/*++

Routine Description:

Arguments:

Return Value:

--*/

{
    PADAPTER_EXTENSION deviceExtension = GET_FDO_EXTENSION(HwDeviceExtension);

    PLOGICAL_UNIT_EXTENSION logicalUnit;
    PSRB_DATA               srbData;
    PSCSI_REQUEST_BLOCK     srb;
    UCHAR                   pathId;
    UCHAR                   targetId;
    UCHAR                   lun;
    va_list                 ap;

    va_start(ap, HwDeviceExtension);

    switch (NotificationType) {

    case NextRequest:

        //
        // Start next packet on adapter's queue.
        //

        deviceExtension->InterruptData.InterruptFlags |= PD_READY_FOR_NEXT_REQUEST;
        break;

    case RequestComplete:

        srb = va_arg(ap, PSCSI_REQUEST_BLOCK);

        ASSERT(srb->SrbStatus != SRB_STATUS_PENDING);

        ASSERT(srb->SrbStatus != SRB_STATUS_SUCCESS ||
               srb->ScsiStatus == SCSISTAT_GOOD ||
               srb->Function != SRB_FUNCTION_EXECUTE_SCSI);

        //
        // If this srb has already been completed then return, otherwise
        // clear the active flag.
        //

        if (srb->SrbFlags & SRB_FLAGS_IS_ACTIVE) {
            srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE;
        } else {
            va_end(ap);
            return;
        }

        //
        // Treat abort completions as a special case.
        //

        if (srb->Function == SRB_FUNCTION_ABORT_COMMAND) {

            ASSERT(FALSE);
            logicalUnit = GetLogicalUnitExtension(deviceExtension,
                                                  srb->PathId,
                                                  srb->TargetId,
                                                  srb->Lun,
                                                  FALSE,
                                                  FALSE);

            logicalUnit->CompletedAbort =
                deviceExtension->InterruptData.CompletedAbort;

            deviceExtension->InterruptData.CompletedAbort = logicalUnit;

        } else {

            //
            // Validate the srb data.
            //

            srbData = srb->OriginalRequest;

#if DBG
            ASSERT_SRB_DATA(srbData);

            ASSERT(srbData->CurrentSrb == srb);

            ASSERT(srbData->CurrentSrb != NULL &&
                   srbData->CompletedRequests == NULL);

            if ((srb->SrbStatus == SRB_STATUS_SUCCESS) &&
                    ((srb->Cdb[0] == SCSIOP_READ) ||
                     (srb->Cdb[0] == SCSIOP_WRITE))) {
                ASSERT(srb->DataTransferLength);
            }
#endif

            if(((srb->SrbStatus == SRB_STATUS_SUCCESS) ||
                    (srb->SrbStatus == SRB_STATUS_DATA_OVERRUN)) &&
                    (TEST_FLAG(srb->SrbFlags, SRB_FLAGS_UNSPECIFIED_DIRECTION))) {
                ASSERT(srbData->OriginalDataTransferLength >=
                       srb->DataTransferLength);
            }

            srbData->CompletedRequests =
                deviceExtension->InterruptData.CompletedRequests;
            deviceExtension->InterruptData.CompletedRequests = srbData;

            //
            // Cache away the last logical unit we touched in the miniport.
            // This is cleared when we come out of the miniport
            // synchronization but provides a shortcut for finding the
            // logical unit before going into the hash table.
            //

            deviceExtension->CachedLogicalUnit = srbData->LogicalUnit;
        }

        break;

    case ResetDetected:

        //
        // Notifiy the port driver that a reset has been reported.
        //

        deviceExtension->InterruptData.InterruptFlags |=
            PD_RESET_REPORTED | PD_RESET_HOLD;
        break;

    case NextLuRequest:

        //
        // The miniport driver is ready for the next request and
        // can accept a request for this logical unit.
        //

        pathId = va_arg(ap, UCHAR);
        targetId = va_arg(ap, UCHAR);
        lun = va_arg(ap, UCHAR);

        //
        // A next request is impiled by this notification so set the
        // ready for next reqeust flag.
        //

        deviceExtension->InterruptData.InterruptFlags |= PD_READY_FOR_NEXT_REQUEST;

        logicalUnit = deviceExtension->CachedLogicalUnit;

        if((logicalUnit == NULL) ||
                (logicalUnit->TargetId != targetId) ||
                (logicalUnit->PathId != pathId) ||
                (logicalUnit->Lun != lun)) {

            logicalUnit = GetLogicalUnitExtension(deviceExtension,
                                                  pathId,
                                                  targetId,
                                                  lun,
                                                  FALSE,
                                                  FALSE);
        }

        if (logicalUnit != NULL && logicalUnit->ReadyLogicalUnit != NULL) {

            //
            // Since our ReadyLogicalUnit link field is not NULL we must
            // have already been linked onto a ReadyLogicalUnit list.
            // There is nothing to do.
            //

            break;
        }

        //
        // Don't process this as request for the next logical unit, if
        // there is a untagged request for active for this logical unit.
        // The logical unit will be started when untagged request completes.
        //

        if (logicalUnit->CurrentUntaggedRequest == NULL) {

            //
            // Add the logical unit to the chain of logical units that
            // another request maybe processed for.
            //

            logicalUnit->ReadyLogicalUnit =
                deviceExtension->InterruptData.ReadyLogicalUnit;
            deviceExtension->InterruptData.ReadyLogicalUnit = logicalUnit;
        }

        break;

    case CallDisableInterrupts:

        ASSERT(deviceExtension->InterruptData.InterruptFlags &
               PD_DISABLE_INTERRUPTS);

        //
        // The miniport wants us to call the specified routine
        // with interrupts disabled.  This is done after the current
        // HwRequestInterrutp routine completes. Indicate the call is
        // needed and save the routine to be called.
        //

        deviceExtension->Flags |= PD_DISABLE_CALL_REQUEST;

        deviceExtension->HwRequestInterrupt = va_arg(ap, PHW_INTERRUPT);

        break;

    case CallEnableInterrupts:

        //
        // The miniport wants us to call the specified routine
        // with interrupts enabled this is done from the DPC.
        // Disable calls to the interrupt routine, indicate the call is
        // needed and save the routine to be called.
        //

        deviceExtension->InterruptData.InterruptFlags |=
            PD_DISABLE_INTERRUPTS | PD_ENABLE_CALL_REQUEST;

        deviceExtension->HwRequestInterrupt = va_arg(ap, PHW_INTERRUPT);

        break;

    case RequestTimerCall:

        //
        // The driver wants to set the miniport timer.
        // Save the timer parameters.
        //

        deviceExtension->InterruptData.InterruptFlags |=
            PD_TIMER_CALL_REQUEST;
        deviceExtension->InterruptData.HwTimerRequest =
            va_arg(ap, PHW_INTERRUPT);
        deviceExtension->InterruptData.MiniportTimerValue =
            va_arg(ap, ULONG);
        break;

    case WMIEvent: {

        //
        // The miniport wishes to post a WMI event for the adapter
        // or a specified SCSI target.
        //

        PWMI_MINIPORT_REQUEST_ITEM lastMiniPortRequest;
        PWMI_MINIPORT_REQUEST_ITEM wmiMiniPortRequest;
        PWNODE_EVENT_ITEM          wnodeEventItem;
        PWNODE_EVENT_ITEM          wnodeEventItemCopy;

        wnodeEventItem     = va_arg(ap, PWNODE_EVENT_ITEM);
        pathId             = va_arg(ap, UCHAR);

        if (pathId != 0xFF) {
            targetId = va_arg(ap, UCHAR);
            lun      = va_arg(ap, UCHAR);
        }

        //
        // Validate the event first.  Then attempt to obtain a free
        // WMI_MINIPORT_REQUEST_ITEM structure so that we may store
        // this request and process it at DPC level later.  If none
        // are obtained or the event is bad, we ignore the request.
        //

        if ((wnodeEventItem == NULL) ||
                (wnodeEventItem->WnodeHeader.BufferSize >
                 WMI_MINIPORT_EVENT_ITEM_MAX_SIZE)) {

            va_end(ap);    //  size, no free WMI_MINIPORT_REQUEST_ITEMs left]
            return;
        }

        //
        // Remove the WMI_MINIPORT_REQUEST_ITEM from the free list.
        //
        wmiMiniPortRequest = SpWmiPopFreeRequestItem(deviceExtension);

        //
        // Log an error if a free request item could not be dequeued
        // (log only once in the lifetime of this adapter).
        //
        if (wmiMiniPortRequest == NULL) {

            if (!deviceExtension->WmiFreeMiniPortRequestsExhausted) {
                deviceExtension->WmiFreeMiniPortRequestsExhausted = TRUE;
                ScsiPortLogError(HwDeviceExtension,
                                 NULL,
                                 pathId,
                                 targetId,
                                 lun,
                                 SP_LOST_WMI_MINIPORT_REQUEST,
                                 0);
            }

            va_end(ap);
            return;
        }

        //
        // Save information pertaining to this WMI request for later
        // processing.
        //

        deviceExtension->InterruptData.InterruptFlags |= PD_WMI_REQUEST;

        wmiMiniPortRequest->TypeOfRequest = (UCHAR)WMIEvent;
        wmiMiniPortRequest->PathId        = pathId;
        wmiMiniPortRequest->TargetId      = targetId;
        wmiMiniPortRequest->Lun           = lun;

        RtlCopyMemory(wmiMiniPortRequest->WnodeEventItem,
                      wnodeEventItem,
                      wnodeEventItem->WnodeHeader.BufferSize);

        //
        // Queue the new WMI_MINIPORT_REQUEST_ITEM to the end of list in the
        // interrupt data structure.
        //
        wmiMiniPortRequest->NextRequest = NULL;

        lastMiniPortRequest =
            deviceExtension->InterruptData.WmiMiniPortRequests;

        if (lastMiniPortRequest) {

            while (lastMiniPortRequest->NextRequest) {
                lastMiniPortRequest = lastMiniPortRequest->NextRequest;
            }
            lastMiniPortRequest->NextRequest = wmiMiniPortRequest;

        } else {
            deviceExtension->InterruptData.WmiMiniPortRequests =
                wmiMiniPortRequest;
        }

        break;
    }

    case WMIReregister: {
        //
        // The miniport wishes to re-register the GUIDs for the adapter or
        // a specified SCSI target.
        //

        PWMI_MINIPORT_REQUEST_ITEM lastMiniPortRequest;
        PWMI_MINIPORT_REQUEST_ITEM wmiMiniPortRequest;

        pathId             = va_arg(ap, UCHAR);

        if (pathId != 0xFF) {
            targetId = va_arg(ap, UCHAR);
            lun      = va_arg(ap, UCHAR);
        }

        //
        // Attempt to obtain a free WMI_MINIPORT_REQUEST_ITEM structure
        // so that we may store this request and process it at DPC
        // level later. If none are obtained or the event is bad, we
        // ignore the request.
        //
        // Remove a WMI_MINPORT_REQUEST_ITEM from the free list.
        //
        wmiMiniPortRequest = SpWmiPopFreeRequestItem(deviceExtension);

        if (wmiMiniPortRequest == NULL) {

            //
            // Log an error if a free request item could not be dequeued
            // (log only once in the lifetime of this adapter).
            //
            if (!deviceExtension->WmiFreeMiniPortRequestsExhausted) {

                deviceExtension->WmiFreeMiniPortRequestsExhausted = TRUE;

                ScsiPortLogError(HwDeviceExtension,
                                 NULL,
                                 pathId,
                                 targetId,
                                 lun,
                                 SP_LOST_WMI_MINIPORT_REQUEST,
                                 0);
            }

            va_end(ap);
            return;
        }

        //
        // Save information pertaining to this WMI request for later
        // processing.
        //

        deviceExtension->InterruptData.InterruptFlags |= PD_WMI_REQUEST;
        wmiMiniPortRequest->TypeOfRequest = (UCHAR)WMIReregister;
        wmiMiniPortRequest->PathId        = pathId;
        wmiMiniPortRequest->TargetId      = targetId;
        wmiMiniPortRequest->Lun           = lun;

        //
        // Queue the new WMI_MINIPORT_REQUEST_ITEM to the end of list in the
        // interrupt data structure.
        //
        wmiMiniPortRequest->NextRequest = NULL;

        lastMiniPortRequest =
            deviceExtension->InterruptData.WmiMiniPortRequests;

        if (lastMiniPortRequest) {

            while (lastMiniPortRequest->NextRequest) {
                lastMiniPortRequest = lastMiniPortRequest->NextRequest;
            }
            lastMiniPortRequest->NextRequest = wmiMiniPortRequest;

        } else {
            deviceExtension->InterruptData.WmiMiniPortRequests =
                wmiMiniPortRequest;
        }

        break;
    }

    case BusChangeDetected: {

        SET_FLAG(deviceExtension->InterruptData.InterruptFlags,
                 PD_BUS_CHANGE_DETECTED);
        break;
    }

    default: {
        ASSERT(0);
        break;
    }
    }

    va_end(ap);

    //
    // Request a DPC be queued after the interrupt completes.
    //

    deviceExtension->InterruptData.InterruptFlags |= PD_NOTIFICATION_REQUIRED;

} // end ScsiPortNotification()
Beispiel #4
0
SCSI_PHYSICAL_ADDRESS
ScsiPortGetPhysicalAddress(
    IN PVOID HwDeviceExtension,
    IN PSCSI_REQUEST_BLOCK Srb,
    IN PVOID VirtualAddress,
    OUT ULONG *Length
)

/*++

Routine Description:

    Convert virtual address to physical address for DMA.

Arguments:

Return Value:

--*/

{
    PADAPTER_EXTENSION deviceExtension = GET_FDO_EXTENSION(HwDeviceExtension);
    ULONG             byteOffset;
    PHYSICAL_ADDRESS  address;
    ULONG             length;

    if (Srb == NULL || Srb->SenseInfoBuffer == VirtualAddress) {

        byteOffset = (ULONG)((PCCHAR) VirtualAddress - (PCCHAR)
                             deviceExtension->SrbExtensionBuffer);

        ASSERT(byteOffset < deviceExtension->CommonBufferSize);

        length = deviceExtension->CommonBufferSize - byteOffset;
        address.QuadPart = deviceExtension->PhysicalCommonBuffer.QuadPart + byteOffset;

    } else if (deviceExtension->MasterWithAdapter) {

#ifdef USE_DMA_MACROS
        PSCATTER_GATHER_ELEMENT scatterList;
#else
        PSRB_SCATTER_GATHER scatterList;
#endif
        PSRB_DATA srbData;

        //
        // A scatter/gather list has already been allocated use it to determine
        // the physical address and length.  Get the scatter/gather list.
        //

        srbData = Srb->OriginalRequest;

        ASSERT_SRB_DATA(srbData);

        scatterList =
#ifdef USE_DMA_MACROS
            (PSCATTER_GATHER_ELEMENT)
#endif // USE_DMA_MACROS
            srbData->ScatterGatherList;

        //
        // Calculate byte offset into the data buffer.
        //

        byteOffset = (ULONG)((PCHAR) VirtualAddress - (PCHAR) Srb->DataBuffer);

        //
        // Find the appropriate entry in the scatter/gatter list.
        //

        while (byteOffset >= scatterList->Length) {

            byteOffset -= scatterList->Length;
            scatterList++;
        }

        //
        // Calculate the physical address and length to be returned.
        //

        length = scatterList->Length - byteOffset;

#ifdef USE_DMA_MACROS

        address.QuadPart = scatterList->Address.QuadPart + byteOffset;
#else

        address.QuadPart = scatterList->PhysicalAddress.QuadPart + byteOffset;
#endif

    } else {
        *Length = 0;
        address.QuadPart = (LONGLONG)(SP_UNINITIALIZED_VALUE);
    }

    *Length = length;

    return address;

} // end ScsiPortGetPhysicalAddress()
Beispiel #5
0
VOID
FASTCALL
SpCompleteRequest(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN OPTIONAL PSRB_DATA SrbData,
    IN CCHAR PriorityBoost
)

/*++

Routine Description:

    This routine is a wrapper around IoCompleteRequest.  It is used primarily
    for debugging purposes.  The routine will assert if the Irp being completed
    is still holding the release lock.

Arguments:


Return Value:

    none

--*/

{

    PADAPTER_EXTENSION adapterExtension = DeviceObject->DeviceExtension;
#if DBG
    PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
    PREMOVE_TRACKING_BLOCK *listEntry =
        &((PREMOVE_TRACKING_BLOCK) commonExtension->RemoveTrackingList);

    KIRQL oldIrql;

    KeAcquireSpinLock(&commonExtension->RemoveTrackingSpinlock,
                      &oldIrql);

    while(*listEntry != NULL) {

        if((*listEntry)->Tag == Irp) {
            break;
        }

        listEntry = &((*listEntry)->NextBlock);
    }

    if(*listEntry != NULL) {

        DebugPrint((0, ">>>>SpCompleteRequest: Irp %#p completed while "
                    "still holding the remove lock\n",
                    Irp));
        DebugPrint((0, ">>>>SpReleaseRemoveLock: Lock acquired in file "
                    "%s on line %d\n", (*listEntry)->File, (*listEntry)->Line));
        ASSERT(FALSE);
    }

    KeReleaseSpinLock(&commonExtension->RemoveTrackingSpinlock, oldIrql);

    if(ARGUMENT_PRESENT(SrbData)) {
        PLOGICAL_UNIT_EXTENSION logicalUnit;

        ASSERT_SRB_DATA(SrbData);
        ASSERT(SrbData->ScatterGatherList == NULL);

        ASSERT_SRB_DATA(SrbData);
        ASSERT(SrbData->CurrentIrp == Irp);

        logicalUnit = SrbData->LogicalUnit;

        ASSERT(logicalUnit != NULL);
        ASSERT(logicalUnit->CurrentUntaggedRequest != SrbData);
        ASSERT_PDO(logicalUnit->CommonExtension.DeviceObject);

        ASSERT(SrbData->RemappedMdl == NULL);
    }

#endif

    //
    // If the caller specified an SRB_DATA structure for the completion then
    // we will free it to the lookaside list, fix the OriginalIrp value in the
    // srb and release the queue-tag value assigned to the device.
    //

    if(ARGUMENT_PRESENT(SrbData)) {
        PLOGICAL_UNIT_EXTENSION logicalUnit;

        logicalUnit = SrbData->LogicalUnit;

        if((SrbData->CurrentSrb->Function == SRB_FUNCTION_LOCK_QUEUE) ||
                (SrbData->CurrentSrb->Function == SRB_FUNCTION_UNLOCK_QUEUE)) {
            ASSERT(SrbData->CurrentSrb == logicalUnit->LockRequest);
            logicalUnit->LockRequest = NULL;
        }

        SrbData->CurrentSrb->OriginalRequest = SrbData->CurrentIrp;
        SrbData->CurrentIrp = NULL;
        SrbData->CurrentSrb = NULL;

        ASSERT(SrbData->FreeRoutine != NULL);
        ASSERT((SrbData->FreeRoutine == SpFreeSrbData) ||
               (SrbData->FreeRoutine == SpFreeBypassSrbData));

        SrbData->FreeRoutine(logicalUnit->AdapterExtension, SrbData);
        SpReleaseRemoveLock(logicalUnit->CommonExtension.DeviceObject, Irp);
    }

    IoCompleteRequest(Irp, PriorityBoost);
    return;
}