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; }
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()