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