VOID
LogError(
    IN PVOID DeviceExtension,
    IN ULONG ErrorCode,
    IN ULONG UniqueId
    )
{
#if (NTDDI_VERSION > NTDDI_WIN7)
    STOR_LOG_EVENT_DETAILS logEvent;
    memset( &logEvent, 0, sizeof(logEvent) );
    logEvent.InterfaceRevision         = STOR_CURRENT_LOG_INTERFACE_REVISION;
    logEvent.Size                      = sizeof(logEvent);
    logEvent.EventAssociation          = StorEventAdapterAssociation;
    logEvent.StorportSpecificErrorCode = TRUE;
    logEvent.ErrorCode                 = ErrorCode;
    logEvent.DumpDataSize              = sizeof(UniqueId);
    logEvent.DumpData                  = &UniqueId;
    StorPortLogSystemEvent( DeviceExtension, &logEvent, NULL );
#else
    ScsiPortLogError(DeviceExtension,
                         NULL,
                         0,
                         0,
                         0,
                         ErrorCode,
                         UniqueId);
#endif
}
示例#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()
ULONG
VirtIoFindAdapter(
    IN PVOID DeviceExtension,
    IN PVOID HwContext,
    IN PVOID BusInformation,
    IN PCHAR ArgumentString,
    IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
    OUT PBOOLEAN Again
    )
{

    PACCESS_RANGE      accessRange;
    PADAPTER_EXTENSION adaptExt;
    ULONG_PTR          deviceBase;
    ULONG              allocationSize;
    ULONG              pageNum;

#ifdef MSI_SUPPORTED
    PPCI_COMMON_CONFIG pPciConf = NULL;
    UCHAR              pci_cfg_buf[256];
    ULONG              pci_cfg_len;
#endif

    UNREFERENCED_PARAMETER( HwContext );
    UNREFERENCED_PARAMETER( BusInformation );
    UNREFERENCED_PARAMETER( ArgumentString );
    UNREFERENCED_PARAMETER( Again );

    adaptExt = (PADAPTER_EXTENSION)DeviceExtension;

    adaptExt->dump_mode  = IsCrashDumpMode;

    ConfigInfo->Master                 = TRUE;
    ConfigInfo->ScatterGather          = TRUE;
    ConfigInfo->DmaWidth               = Width32Bits;
    ConfigInfo->Dma32BitAddresses      = TRUE;
    ConfigInfo->Dma64BitAddresses      = TRUE;
    ConfigInfo->WmiDataProvider        = FALSE;
#ifdef USE_STORPORT
    ConfigInfo->MapBuffers             = STOR_MAP_NON_READ_WRITE_BUFFERS;
    ConfigInfo->SynchronizationModel   = StorSynchronizeFullDuplex;
#ifdef MSI_SUPPORTED
    ConfigInfo->HwMSInterruptRoutine   = VirtIoMSInterruptRoutine;
    ConfigInfo->InterruptSynchronizationMode=InterruptSynchronizePerMessage;
#endif
#else
    ConfigInfo->MapBuffers             = TRUE;
#endif

    accessRange = &(*ConfigInfo->AccessRanges)[0];

    ASSERT (FALSE == accessRange->RangeInMemory) ;

    RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("Port  Resource [%08I64X-%08I64X]\n",
                accessRange->RangeStart.QuadPart,
                accessRange->RangeStart.QuadPart +
                accessRange->RangeLength));

    if ( accessRange->RangeLength < IO_PORT_LENGTH) {
        ScsiPortLogError(DeviceExtension,
                         NULL,
                         0,
                         0,
                         0,
                         SP_INTERNAL_ADAPTER_ERROR,
                         __LINE__);
        RhelDbgPrint(TRACE_LEVEL_FATAL, ("Wrong access range %x bytes\n", accessRange->RangeLength));
        return SP_RETURN_NOT_FOUND;
    }

    if (!ScsiPortValidateRange(DeviceExtension,
                                           ConfigInfo->AdapterInterfaceType,
                                           ConfigInfo->SystemIoBusNumber,
                                           accessRange->RangeStart,
                                           accessRange->RangeLength,
                                           (BOOLEAN)!accessRange->RangeInMemory)) {

        ScsiPortLogError(DeviceExtension,
                         NULL,
                         0,
                         0,
                         0,
                         SP_INTERNAL_ADAPTER_ERROR,
                         __LINE__);

        RhelDbgPrint(TRACE_LEVEL_FATAL, ("Range validation failed %x for %x bytes\n",
                   (*ConfigInfo->AccessRanges)[0].RangeStart.LowPart,
                   (*ConfigInfo->AccessRanges)[0].RangeLength));

        return SP_RETURN_ERROR;
    }


    ConfigInfo->NumberOfBuses               = 1;
    ConfigInfo->MaximumNumberOfTargets      = 1;
    ConfigInfo->MaximumNumberOfLogicalUnits = 1;

    deviceBase = (ULONG_PTR)ScsiPortGetDeviceBase(DeviceExtension,
                                           ConfigInfo->AdapterInterfaceType,
                                           ConfigInfo->SystemIoBusNumber,
                                           accessRange->RangeStart,
                                           accessRange->RangeLength,
                                           (BOOLEAN)!accessRange->RangeInMemory);

    if (deviceBase == (ULONG_PTR)NULL) {
        ScsiPortLogError(DeviceExtension,
                         NULL,
                         0,
                         0,
                         0,
                         SP_INTERNAL_ADAPTER_ERROR,
                         __LINE__);

        RhelDbgPrint(TRACE_LEVEL_FATAL, ("Couldn't map %x for %x bytes\n",
                   (*ConfigInfo->AccessRanges)[0].RangeStart.LowPart,
                   (*ConfigInfo->AccessRanges)[0].RangeLength));
        return SP_RETURN_ERROR;
    }

	VirtIODeviceInitialize(&adaptExt->vdev, deviceBase, sizeof(adaptExt->vdev));
	adaptExt->msix_enabled = FALSE;

#ifdef MSI_SUPPORTED
    pci_cfg_len = StorPortGetBusData (DeviceExtension,
                                           PCIConfiguration,
                                           ConfigInfo->SystemIoBusNumber,
                                           (ULONG)ConfigInfo->SlotNumber,
                                           (PVOID)pci_cfg_buf,
                                           (ULONG)256);
    if (pci_cfg_len == 256)
    {
        UCHAR CapOffset;
        PPCI_MSIX_CAPABILITY pMsixCapOffset;

        pPciConf = (PPCI_COMMON_CONFIG)pci_cfg_buf;
        if ( (pPciConf->Status & PCI_STATUS_CAPABILITIES_LIST) == 0)
        {
           RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("NO CAPABILITIES_LIST\n"));
        }
        else
        {
           if ( (pPciConf->HeaderType & (~PCI_MULTIFUNCTION)) == PCI_DEVICE_TYPE )
           {
              CapOffset = pPciConf->u.type0.CapabilitiesPtr;
              while (CapOffset != 0)
              {
                 pMsixCapOffset = (PPCI_MSIX_CAPABILITY)(pci_cfg_buf + CapOffset);
                 if ( pMsixCapOffset->Header.CapabilityID == PCI_CAPABILITY_ID_MSIX )
                 {
                    RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("MessageControl.TableSize = %d\n", pMsixCapOffset->MessageControl.TableSize));
                    RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("MessageControl.FunctionMask = %d\n", pMsixCapOffset->MessageControl.FunctionMask));
                    RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("MessageControl.MSIXEnable = %d\n", pMsixCapOffset->MessageControl.MSIXEnable));

                    RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("MessageTable = %p\n", pMsixCapOffset->MessageTable));
                    RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("PBATable = %d\n", pMsixCapOffset->PBATable));
                    adaptExt->msix_enabled = (pMsixCapOffset->MessageControl.MSIXEnable == 1);
                    break;
                 }
                 else
                 {
                    CapOffset = pMsixCapOffset->Header.Next;
                    RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("CapabilityID = %x, Next CapOffset = %x\n", pMsixCapOffset->Header.CapabilityID, CapOffset));
                 }
              }
              VirtIODeviceSetMSIXUsed(&adaptExt->vdev, adaptExt->msix_enabled);
           }
           else
           {
              RhelDbgPrint(TRACE_LEVEL_FATAL, ("NOT A PCI_DEVICE_TYPE\n"));
           }
        }
    }
    else
    {
        RhelDbgPrint(TRACE_LEVEL_FATAL, ("CANNOT READ PCI CONFIGURATION SPACE %d\n", pci_cfg_len));
    }
#endif

	VirtIODeviceReset(&adaptExt->vdev);
	WriteVirtIODeviceWord(adaptExt->vdev.addr + VIRTIO_PCI_QUEUE_SEL, (USHORT)0);
    if (adaptExt->dump_mode) {
        WriteVirtIODeviceWord(adaptExt->vdev.addr + VIRTIO_PCI_QUEUE_PFN, (USHORT)0);
    }

	adaptExt->features = ReadVirtIODeviceRegister(adaptExt->vdev.addr + VIRTIO_PCI_HOST_FEATURES);
    ConfigInfo->CachesData = CHECKBIT(adaptExt->features, VIRTIO_BLK_F_WCACHE) ? TRUE : FALSE;
    RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("VIRTIO_BLK_F_WCACHE = %d\n", ConfigInfo->CachesData));

	VirtIODeviceQueryQueueAllocation(&adaptExt->vdev, 0, &pageNum, &allocationSize);

    if(adaptExt->dump_mode) {
        ConfigInfo->NumberOfPhysicalBreaks = 8;
    } else {
        ConfigInfo->NumberOfPhysicalBreaks = MAX_PHYS_SEGMENTS + 1;
    }

    ConfigInfo->MaximumTransferLength = 0x00FFFFFF;
    adaptExt->queue_depth = pageNum / ConfigInfo->NumberOfPhysicalBreaks - 1;

#if (INDIRECT_SUPPORTED)
    if(!adaptExt->dump_mode) {
        adaptExt->indirect = CHECKBIT(adaptExt->features, VIRTIO_RING_F_INDIRECT_DESC);
    }
    if(adaptExt->indirect) {
        adaptExt->queue_depth = pageNum;
    }
#else
	adaptExt->indirect = 0;
#endif
    RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("breaks_number = %x  queue_depth = %x\n",
                ConfigInfo->NumberOfPhysicalBreaks,
                adaptExt->queue_depth));

    adaptExt->uncachedExtensionVa = ScsiPortGetUncachedExtension(DeviceExtension, ConfigInfo, allocationSize);
    if (!adaptExt->uncachedExtensionVa) {
        ScsiPortLogError(DeviceExtension,
                         NULL,
                         0,
                         0,
                         0,
                         SP_INTERNAL_ADAPTER_ERROR,
                         __LINE__);

        RhelDbgPrint(TRACE_LEVEL_FATAL, ("Couldn't get uncached extension\n"));
        return SP_RETURN_ERROR;
    }

    InitializeListHead(&adaptExt->list_head);
#ifdef USE_STORPORT
    InitializeListHead(&adaptExt->complete_list);
#endif
    return SP_RETURN_FOUND;
}
BOOLEAN
VirtIoHwInitialize(
    IN PVOID DeviceExtension
    )
{

    PADAPTER_EXTENSION adaptExt;
    BOOLEAN            ret = FALSE;
#ifdef MSI_SUPPORTED
    MESSAGE_INTERRUPT_INFORMATION msi_info;
#endif

    RhelDbgPrint(TRACE_LEVEL_VERBOSE, ("%s (%d)\n", __FUNCTION__, KeGetCurrentIrql()));

    adaptExt = (PADAPTER_EXTENSION)DeviceExtension;

#ifdef MSI_SUPPORTED
    while(StorPortGetMSIInfo(DeviceExtension, adaptExt->msix_vectors, &msi_info) == STOR_STATUS_SUCCESS) {
        RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("MessageId = %x\n", msi_info.MessageId));
        RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("MessageData = %x\n", msi_info.MessageData));
        RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("InterruptVector = %x\n", msi_info.InterruptVector));
        RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("InterruptLevel = %x\n", msi_info.InterruptLevel));
        RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("InterruptMode = %s\n", msi_info.InterruptMode == LevelSensitive ? "LevelSensitive" : "Latched"));
        RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("MessageAddress = %p\n\n", msi_info.MessageAddress));
        ++adaptExt->msix_vectors;
    }

    if(!adaptExt->dump_mode && (adaptExt->msix_vectors > 1)) {
        adaptExt->vq = FindVirtualQueue(adaptExt, 0, adaptExt->msix_vectors - 1);
    }
#endif

    if(!adaptExt->vq) {
        adaptExt->vq = FindVirtualQueue(adaptExt, 0, 0);
    }
    if (!adaptExt->vq) {
        ScsiPortLogError(DeviceExtension,
                         NULL,
                         0,
                         0,
                         0,
                         SP_INTERNAL_ADAPTER_ERROR,
                         __LINE__);

        RhelDbgPrint(TRACE_LEVEL_FATAL, ("Cannot find snd virtual queue\n"));
        return ret;
    }

    RhelGetDiskGeometry(DeviceExtension);

    memset(&adaptExt->inquiry_data, 0, sizeof(INQUIRYDATA));

    adaptExt->inquiry_data.ANSIVersion = 4;
    adaptExt->inquiry_data.ResponseDataFormat = 2;
    adaptExt->inquiry_data.CommandQueue = 1;
    adaptExt->inquiry_data.DeviceType   = DIRECT_ACCESS_DEVICE;
    adaptExt->inquiry_data.Wide32Bit    = 1;
    adaptExt->inquiry_data.AdditionalLength = 91;
    ScsiPortMoveMemory(&adaptExt->inquiry_data.VendorId, "Red Hat ", sizeof("Red Hat "));
    ScsiPortMoveMemory(&adaptExt->inquiry_data.ProductId, "VirtIO", sizeof("VirtIO"));
    ScsiPortMoveMemory(&adaptExt->inquiry_data.ProductRevisionLevel, "0001", sizeof("0001"));
    ScsiPortMoveMemory(&adaptExt->inquiry_data.VendorSpecific, "0001", sizeof("0001"));

    if(!adaptExt->dump_mode)
    {
        RhelGetSerialNumber(DeviceExtension);
    }

    ret = TRUE;

#ifdef USE_STORPORT
    if(!adaptExt->dump_mode && !adaptExt->dpc_ok)
    {
        ret = StorPortEnablePassiveInitialization(DeviceExtension, VirtIoPassiveInitializeRoutine);
    }
#endif

    if (ret)
    {
		VirtIODeviceAddStatus(&adaptExt->vdev, VIRTIO_CONFIG_S_DRIVER_OK);
    }

    return ret;
}
示例#5
0
ULONG
Wd7000ExFindAdapter(
    IN PVOID HwDeviceExtension,
    IN PVOID Context,
    IN PVOID BusInformation,
    IN PCHAR ArgumentString,
    IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
    OUT PBOOLEAN Again
    )

/*++

Routine Description:

    This function is called by the OS-specific port driver after
    the necessary storage has been allocated, to gather information
    about the adapter's configuration.

Arguments:

    HwDeviceExtension - HBA miniport driver's adapter data storage
    ConfigInfo - Configuration information structure describing HBA

Return Value:

    TRUE if adapter present in system

--*/

{
    PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
    PEISA_CONTROLLER eisaController;
    PULONG adapterCount = Context;
    PNONCACHED_EXTENSION ncExtension;
    ULONG eisaSlotNumber;
    PICB icb;
    PADAPTER_INQUIRY adapterInquiry;
    ULONG physicalIcb;
    ULONG i;
    ULONG length;
    UCHAR status;

    //
    // Check to see if adapter present in system.
    //
    if (!AdapterPresent(deviceExtension, ConfigInfo, Context)) {
        DebugPrint((1,"Wd7000EX: SCSI adapter not present\n"));
        *Again = FALSE;
        return SP_RETURN_NOT_FOUND;
    }

    //
    // There is still more to look at.
    //

    *Again = FALSE;

    //
    // Fill in the access array information only if there are no
    // default parameters already there.
    //
    if (ScsiPortConvertPhysicalAddressToUlong(
            (*ConfigInfo->AccessRanges)[0].RangeStart) == 0) {

        *Again = TRUE;
        (*ConfigInfo->AccessRanges)[0].RangeStart =
            ScsiPortConvertUlongToPhysicalAddress(0x1000 * (*((PULONG) Context)) + EISA_ADDRESS_BASE);
        (*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(EISA_CONTROLLER);
        (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;

        //
        // Indicate maximum transfer length in bytes.
        //
        ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_SIZE;

        //
        // Maximum number of physical segments is 32.
        //
        ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SDL_SIZE;

        //
        // Set the configuration parameters for this card.
        //
    
        ConfigInfo->NumberOfBuses = 1;
        deviceExtension->NumberOfBuses = 1;
        ConfigInfo->ScatterGather = TRUE;
        ConfigInfo->Master = TRUE;
    
        //
        // Get a noncached extension for an adapter inquiry command.
        //
    
        ncExtension = ScsiPortGetUncachedExtension(
                                    deviceExtension,
                                    ConfigInfo,
                                    sizeof(NONCACHED_EXTENSION));
    
        if (ncExtension == NULL) {
    
            //
            // Log error.
            //
    
            ScsiPortLogError(
                deviceExtension,
                NULL,
                0,
                0,
                0,
                SP_INTERNAL_ADAPTER_ERROR,
                6 << 16
                );
    
            return SP_RETURN_ERROR;
        }
    
        length = sizeof(NONCACHED_EXTENSION);
    
        //
        // Convert virtual to physical address.
        //
    
        physicalIcb = ScsiPortConvertPhysicalAddressToUlong(
            ScsiPortGetPhysicalAddress(deviceExtension,
                                     NULL,
                                     ncExtension,
                                     &length));
    
        //
        // Initialize the pointers.
        //
    
        icb = &ncExtension->Icb;
        adapterInquiry = &ncExtension->AdapterInquiry;
    
        //
        // Create ICB for Adapter Inquiry Command.
        //
    
        icb->IcbFlags = 0;
        icb->CompletionStatus = 0;
        icb->Reserved = 0;
        icb->DataBufferAddress = ScsiPortConvertPhysicalAddressToUlong(
            ScsiPortGetPhysicalAddress(
                deviceExtension,
                NULL,
                adapterInquiry,
                &length));
    
        icb->TransferCount = sizeof(ADAPTER_INQUIRY);
    
        icb->OpCode = ADAPTER_INQUIRY_COMMAND;
    
        //
        // Get ICB physical address.
        //
    
        physicalIcb = ScsiPortConvertPhysicalAddressToUlong(
            ScsiPortGetPhysicalAddress(
                deviceExtension,
                NULL,
                icb,
                &length));
    
        //
        // Disable system interrupts.
        //
    
        ScsiPortWritePortUchar(&deviceExtension->EisaController->SystemInterruptEnable,
            SYSTEM_INTERRUPTS_DISABLE);
    
        //
        // Write ICB physical address and command to mailbox.
        //
    
        SendCommand(PROCESS_ICB,
                physicalIcb,
                deviceExtension);
    
        //
        // Poll for ICB completion.
        //
    
        i = 0;
        while ((status =
            ScsiPortReadPortUchar(
            &deviceExtension->EisaController->ResponseRegister)) == 0) {
    
            i++;
    
            if (i > 100000) {
    
                break;
            }
    
            ScsiPortStallExecution(10);
        }
    
        if (status == 0) {
    
            //
            // The request timed out. Log an error and return.
            //
    
            ScsiPortLogError(
                deviceExtension,
                NULL,
                0,
                0,
                0,
                SP_INTERNAL_ADAPTER_ERROR,
                7 << 16
                );
            return SP_RETURN_ERROR;
        }
    
        DebugPrint((1, "Wd7000ExFindAdapter: Get configuration request time = %d.\n", i * 10));
    
        //
        // Acknowledge interrupt.
        //
    
        ScsiPortWritePortUchar(&deviceExtension->EisaController->ResponseRegister, 0xFF);
    
        //
        // Enable system interrupts.
        //
    
        ScsiPortWritePortUchar(&deviceExtension->EisaController->SystemInterruptEnable,
            SYSTEM_INTERRUPTS_ENABLE);
    
        //
        // Check returned status for success.
        //
    
        if (status != COMPLETE_SUCCESS) {
    
            //
            // Give up.
            //
    
            DebugPrint((1,"Wd7000Ex: Response register %x\n", status));
            DebugPrint((1,"Wd7000Ex: Adapter inquiry failed\n"));
    
            //
            // Log error.
            //
    
            ScsiPortLogError(
                deviceExtension,
                NULL,
                0,
                0,
                0,
                SP_INTERNAL_ADAPTER_ERROR,
                8 << 16
                );
    
            return SP_RETURN_ERROR;
        }
    
        //
        // NOTE: Delay here. I don't understand this latency between
        //          when the device interrupts and the status of the ICB
        //          is success and when the data is actually available in
        //          the buffer.
        //
    
        ScsiPortStallExecution(300);
    
        if (adapterInquiry->AdapterInformation & DUAL_CHANNEL) {
    
            //
            // There are two buses on the adapter.
            //
    
            ConfigInfo->InitiatorBusId[1] =
                (adapterInquiry->ChannelInformation >> 4) & BUS_ID_MASK;
            ConfigInfo->NumberOfBuses = 2;
            deviceExtension->NumberOfBuses = 2;
        }