Esempio n. 1
0
BOOLEAN
SpWmiRemoveFreeMiniPortRequestItems(
    IN PADAPTER_EXTENSION   fdoExtension
    )
/*++

Routine Description:

   This function removes WMI_MINIPORT_REQUEST_ITEM structures from the "free"
   queue of the adapter extension.

   It removed all the free cells.

Arguments:

    fdoExtension    - The device_extension

Return Value:

   TRUE always.

--*/

{
    PWMI_MINIPORT_REQUEST_ITEM   tmpRequestItem;
    PWMI_MINIPORT_REQUEST_ITEM   wmiRequestItem;

    //
    // Set the watermark to 0
    // No need to grab a lock we're just setting it
    fdoExtension->WmiFreeMiniPortRequestWatermark = 0;

    DebugPrint((1, "SpWmiRemoveFreeMiniPortRequestItems: Removing %p", fdoExtension));


    //
    // Walk the queue of items and de-allocate as many as we need to.
    //
    for (;;) {
        // Pop
        wmiRequestItem = SpWmiPopFreeRequestItem(fdoExtension);
        if (wmiRequestItem == NULL) {
            break;
        } else {
            ExFreePool(wmiRequestItem);
        }
    }

    // BUGBUG
    // Later we should add a check and make sure that the count of
    // cells is 0

    return TRUE;
}
Esempio n. 2
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()