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; ConfigInfo->AlignmentMask = 0x3; #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) { LogError(DeviceExtension, SP_INTERNAL_ADAPTER_ERROR, __LINE__); RhelDbgPrint(TRACE_LEVEL_FATAL, ("Wrong access range %x bytes\n", accessRange->RangeLength)); return SP_RETURN_NOT_FOUND; } #ifndef USE_STORPORT if (!ScsiPortValidateRange(DeviceExtension, ConfigInfo->AdapterInterfaceType, ConfigInfo->SystemIoBusNumber, accessRange->RangeStart, accessRange->RangeLength, (BOOLEAN)!accessRange->RangeInMemory)) { LogError(DeviceExtension, 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; } #endif 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) { LogError(DeviceExtension, 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)); VirtIODeviceAddStatus(&adaptExt->vdev, VIRTIO_CONFIG_S_DRIVER); 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); VirtIODeviceAddStatus(&adaptExt->vdev, VIRTIO_CONFIG_S_ACKNOWLEDGE); 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; if (ConfigInfo->CachesData) { u32 GuestFeatures = 0; VirtIOFeatureEnable(GuestFeatures, VIRTIO_BLK_F_WCACHE); VirtIODeviceWriteGuestFeatures(&adaptExt->vdev, GuestFeatures); } 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) { LogError(DeviceExtension, 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; }
ULONG FindAdapter (IN PVOID HAObject, IN PVOID PContext, IN PVOID BusInfo, IN PCHAR ArgString, IN OUT PPORT_CONFIGURATION_INFORMATION Config, OUT PBOOLEAN PAgain) { ADAPTER_PTR HA = HAObject; TRACE(3, ("FindAdapter(): Adapter ptr = %x, Config ptr = %x, Len = 0x%x\n", HA, Config, sizeof(struct _PORT_CONFIGURATION_INFORMATION))); /* Hunt down and register the adapters in the system: */ HA->IOBaseAddr = (U16)ScsiPortConvertPhysicalAddressToUlong( (*Config->AccessRanges)[0].RangeStart); if (Adapter_Init(HA, (unsigned *)PContext)) { // Set Again TRUE, only if we're being called with a non-sepcific access range *PAgain = ScsiPortConvertPhysicalAddressToUlong( (*Config->AccessRanges)[0].RangeStart) == 0; Config->BusInterruptLevel = HA->IRQNumber; Config->ScatterGather = HA->Supports.ScatterGather; Config->MaximumTransferLength = 0x400000; Config->NumberOfPhysicalBreaks = 0x400; // Config->NumberOfPhysicalBreaks = HA->MaxSGListLength; (*Config->AccessRanges)[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(HA->IOBaseAddr); (*Config->AccessRanges)[0].RangeLength = HA->IOAddrLen; (*Config->AccessRanges)[0].RangeInMemory = FALSE; Config->NumberOfBuses = 1; Config->InitiatorBusId[0] = HA->SCSI_ID; Config->Master = (HA->Physical.Xfermode == XM_MASTER) || (HA->Physical.Xfermode == XM_MASTER24); Config->Dma32BitAddresses = (HA->Physical.Xfermode == XM_MASTER); Config->DemandMode = (HA->Physical.Xfermode == XM_DMAD); Config->NeedPhysicalAddresses = XM_PHYSICAL(HA->Physical.Xfermode); Config->MapBuffers = TRUE; Config->CachesData = HA->Supports.Caching; Config->AlignmentMask = 0x3; Config->TaggedQueuing = FALSE; #if defined(AUTOSENSE) Config->AutoRequestSense = TRUE; #else Config->AutoRequestSense = FALSE; #endif Config->MultipleRequestPerLu = Config->AutoRequestSense; Config->ReceiveEvent = FALSE; HA->Ext = ScsiPortGetUncachedExtension(HA, Config, sizeof(AdapterExtension)); return SP_RETURN_FOUND; } else { *PAgain = FALSE; return SP_RETURN_NOT_FOUND; } }
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; }