ULONG VioScsiAcquireSpinLock( IN PVOID DeviceExtension, IN ULONG MessageID, IN PSTOR_LOCK_HANDLE LockHandle ) { PADAPTER_EXTENSION adaptExt; ULONG status = STOR_STATUS_SUCCESS; ENTER_FN(); adaptExt = (PADAPTER_EXTENSION)DeviceExtension; if (adaptExt->num_queues > 1) { ULONG oldIrql = 0; status = StorPortAcquireMSISpinLock(DeviceExtension, MessageID, &oldIrql); LockHandle->Context.OldIrql = (KIRQL)oldIrql; if (status != STOR_STATUS_SUCCESS) { RhelDbgPrint(TRACE_LEVEL_ERROR, ("%s StorPortAcquireMSISpinLock returned status 0x%x\n", __FUNCTION__, status)); } } else { StorPortAcquireSpinLock(DeviceExtension, InterruptLock, NULL, LockHandle); } return status; EXIT_FN(); }
VOID ShutDown( IN PVOID DeviceExtension ) { PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension; ENTER_FN(); VirtIODeviceReset(&adaptExt->vdev); StorPortWritePortUshort(DeviceExtension, (PUSHORT)(adaptExt->device_base + VIRTIO_PCI_GUEST_FEATURES), 0); if (adaptExt->vq[0]) { adaptExt->vq[0]->vq_ops->shutdown(adaptExt->vq[0]); VirtIODeviceDeleteQueue(adaptExt->vq[0], NULL); adaptExt->vq[0] = NULL; } if (adaptExt->vq[1]) { adaptExt->vq[1]->vq_ops->shutdown(adaptExt->vq[1]); VirtIODeviceDeleteQueue(adaptExt->vq[1], NULL); adaptExt->vq[1] = NULL; } if (adaptExt->vq[2]) { adaptExt->vq[2]->vq_ops->shutdown(adaptExt->vq[2]); VirtIODeviceDeleteQueue(adaptExt->vq[2], NULL); adaptExt->vq[2] = NULL; } EXIT_FN(); }
VOID GetScsiConfig( IN PVOID DeviceExtension ) { PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension; ENTER_FN(); adaptExt->features = StorPortReadPortUlong(DeviceExtension, (PULONG)(adaptExt->device_base + VIRTIO_PCI_HOST_FEATURES)); VirtIODeviceGet( &adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, seg_max), &adaptExt->scsi_config.seg_max, sizeof(adaptExt->scsi_config.seg_max)); VirtIODeviceGet( &adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, num_queues), &adaptExt->scsi_config.num_queues, sizeof(adaptExt->scsi_config.num_queues)); VirtIODeviceGet( &adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, max_sectors), &adaptExt->scsi_config.max_sectors, sizeof(adaptExt->scsi_config.max_sectors)); VirtIODeviceGet( &adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, cmd_per_lun), &adaptExt->scsi_config.cmd_per_lun, sizeof(adaptExt->scsi_config.cmd_per_lun)); VirtIODeviceGet( &adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, event_info_size), &adaptExt->scsi_config.event_info_size, sizeof(adaptExt->scsi_config.event_info_size)); VirtIODeviceGet( &adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, sense_size), &adaptExt->scsi_config.sense_size, sizeof(adaptExt->scsi_config.sense_size)); VirtIODeviceGet( &adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, cdb_size), &adaptExt->scsi_config.cdb_size, sizeof(adaptExt->scsi_config.cdb_size)); VirtIODeviceGet( &adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, max_channel), &adaptExt->scsi_config.max_channel, sizeof(adaptExt->scsi_config.max_channel)); VirtIODeviceGet( &adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, max_target), &adaptExt->scsi_config.max_target, sizeof(adaptExt->scsi_config.max_target)); VirtIODeviceGet( &adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, max_lun), &adaptExt->scsi_config.max_lun, sizeof(adaptExt->scsi_config.max_lun)); EXIT_FN(); }
VOID PostProcessRequest( IN PVOID DeviceExtension, IN PSCSI_REQUEST_BLOCK Srb ) { PCDB cdb; PADAPTER_EXTENSION adaptExt; PSRB_EXTENSION srbExt; ENTER_FN(); cdb = (PCDB)&Srb->Cdb[0]; srbExt = (PSRB_EXTENSION)Srb->SrbExtension; adaptExt = (PADAPTER_EXTENSION)DeviceExtension; switch (cdb->CDB6GENERIC.OperationCode) { case SCSIOP_READ_CAPACITY: case SCSIOP_READ_CAPACITY16: StorPortSetDeviceQueueDepth( DeviceExtension, Srb->PathId, Srb->TargetId, Srb->Lun, adaptExt->queue_depth); break; default: break; } EXIT_FN(); }
BOOLEAN SendTMF( IN PVOID DeviceExtension, IN PSCSI_REQUEST_BLOCK Srb ) { ENTER_FN(); return StorPortSynchronizeAccess(DeviceExtension, SynchronizedTMFRoutine, (PVOID)Srb); EXIT_FN(); }
BOOLEAN SendSRB( IN PVOID DeviceExtension, IN PSRB_TYPE Srb ) { PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension; PSRB_EXTENSION srbExt = SRB_EXTENSION(Srb); PVOID va = NULL; ULONGLONG pa = 0; ULONG QueueNumber = 0; ULONG OldIrql = 0; ULONG MessageId = 0; BOOLEAN kick = FALSE; STOR_LOCK_HANDLE LockHandle = { 0 }; ULONG status = STOR_STATUS_SUCCESS; ENTER_FN(); SET_VA_PA(); if (adaptExt->num_queues > 1) { QueueNumber = adaptExt->cpu_to_vq_map[srbExt->cpu] + VIRTIO_SCSI_REQUEST_QUEUE_0; MessageId = QueueNumber + 1; } else { QueueNumber = VIRTIO_SCSI_REQUEST_QUEUE_0; } VioScsiAcquireSpinLock(DeviceExtension, MessageId, &LockHandle); if (virtqueue_add_buf(adaptExt->vq[QueueNumber], &srbExt->sg[0], srbExt->out, srbExt->in, &srbExt->cmd, va, pa) >= 0){ kick = TRUE; } else { RhelDbgPrint(TRACE_LEVEL_ERROR, ("%s Can not add packet to queue.\n", __FUNCTION__)); //FIXME } VioScsiReleaseSpinLock(DeviceExtension, MessageId, &LockHandle); if (kick == TRUE) { virtqueue_kick(adaptExt->vq[QueueNumber]); } if (adaptExt->num_queues > 1) { if (CHECKFLAG(adaptExt->perfFlags, STOR_PERF_OPTIMIZE_FOR_COMPLETION_DURING_STARTIO)) { // ProcessQueue(DeviceExtension, MessageId, FALSE); } } EXIT_FN(); return kick; }
BOOLEAN InitHW( IN PVOID DeviceExtension, IN PPORT_CONFIGURATION_INFORMATION ConfigInfo ) { PACCESS_RANGE accessRange; PADAPTER_EXTENSION adaptExt; ENTER_FN(); adaptExt = (PADAPTER_EXTENSION)DeviceExtension; 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 FALSE; } adaptExt->device_base = (ULONG_PTR)StorPortGetDeviceBase(DeviceExtension, ConfigInfo->AdapterInterfaceType, ConfigInfo->SystemIoBusNumber, accessRange->RangeStart, accessRange->RangeLength, (BOOLEAN)!accessRange->RangeInMemory); if (adaptExt->device_base == (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 FALSE; } adaptExt->pvdev = &adaptExt->vdev; VirtIODeviceInitialize(adaptExt->pvdev, adaptExt->device_base, sizeof(VirtIODevice)); EXIT_FN(); return TRUE; }
VOID CompleteRequest( IN PVOID DeviceExtension, IN PSCSI_REQUEST_BLOCK Srb ) { ENTER_FN(); PostProcessRequest(DeviceExtension, Srb); StorPortNotification(RequestComplete, DeviceExtension, Srb); EXIT_FN(); }
BOOLEAN KickEvent( IN PVOID DeviceExtension, IN PVirtIOSCSIEventNode EventNode ) { PADAPTER_EXTENSION adaptExt; ULONG fragLen; ENTER_FN(); adaptExt = (PADAPTER_EXTENSION)DeviceExtension; RtlZeroMemory((PVOID)EventNode, sizeof(VirtIOSCSIEventNode)); EventNode->sg.physAddr = StorPortGetPhysicalAddress(DeviceExtension, NULL, &EventNode->event, &fragLen); EventNode->sg.length = sizeof(VirtIOSCSIEvent); return SynchronizedKickEventRoutine(DeviceExtension, (PVOID)EventNode); EXIT_FN(); }
VOID ShutDown( IN PVOID DeviceExtension ) { ULONG index; PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension; ENTER_FN(); VirtIODeviceReset(adaptExt->pvdev); StorPortWritePortUshort(DeviceExtension, (PUSHORT)(adaptExt->device_base + VIRTIO_PCI_GUEST_FEATURES), 0); for (index = VIRTIO_SCSI_CONTROL_QUEUE; index < adaptExt->num_queues + VIRTIO_SCSI_REQUEST_QUEUE_0; ++index) { if (adaptExt->vq[index]) { virtqueue_shutdown(adaptExt->vq[index]); VirtIODeviceDeleteQueue(adaptExt->vq[index], NULL); adaptExt->vq[index] = NULL; } } EXIT_FN(); }
BOOLEAN VioScsiStartIo( IN PVOID DeviceExtension, IN PSCSI_REQUEST_BLOCK Srb ) { ENTER_FN(); if (PreProcessRequest(DeviceExtension, Srb) || !SendSRB(DeviceExtension, Srb)) { if(Srb->SrbStatus == SRB_STATUS_PENDING) { Srb->SrbStatus = SRB_STATUS_ERROR; } CompleteRequest(DeviceExtension, Srb); } EXIT_FN(); return TRUE; }
BOOLEAN FORCEINLINE PreProcessRequest( IN PVOID DeviceExtension, IN PSCSI_REQUEST_BLOCK Srb ) { PADAPTER_EXTENSION adaptExt; ENTER_FN(); adaptExt = (PADAPTER_EXTENSION)DeviceExtension; switch (Srb->Function) { case SRB_FUNCTION_PNP: case SRB_FUNCTION_POWER: case SRB_FUNCTION_RESET_DEVICE: case SRB_FUNCTION_RESET_LOGICAL_UNIT: { Srb->SrbStatus = SRB_STATUS_SUCCESS; return TRUE; } } EXIT_FN(); return FALSE; }
BOOLEAN SendSRB( IN PVOID DeviceExtension, IN PSCSI_REQUEST_BLOCK Srb ) { PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension; PSRB_EXTENSION srbExt = (PSRB_EXTENSION)Srb->SrbExtension; PVOID va = NULL; ULONGLONG pa = 0; ULONG QueueNumber = 0; ULONG OldIrql = 0; ULONG MessageId = 0; BOOLEAN kick = FALSE; STOR_LOCK_HANDLE LockHandle = { 0 }; ULONG status = STOR_STATUS_SUCCESS; ENTER_FN(); SET_VA_PA(); RhelDbgPrint(TRACE_LEVEL_INFORMATION, ("Srb %p issued on %d::%d QueueNumber %d\n", Srb, srbExt->procNum.Group, srbExt->procNum.Number, QueueNumber)); if (adaptExt->num_queues > 1) { QueueNumber = adaptExt->cpu_to_vq_map[srbExt->procNum.Number]; MessageId = QueueNumber + 1; if (CHECKFLAG(adaptExt->perfFlags, STOR_PERF_OPTIMIZE_FOR_COMPLETION_DURING_STARTIO)) { ProcessQueue(DeviceExtension, MessageId, FALSE); } // status = StorPortAcquireMSISpinLock(DeviceExtension, MessageId, &OldIrql); if (status != STOR_STATUS_SUCCESS) { RhelDbgPrint(TRACE_LEVEL_ERROR, ("%s StorPortAcquireMSISpinLock returned status 0x%x\n", __FUNCTION__, status)); } } else { QueueNumber = VIRTIO_SCSI_REQUEST_QUEUE_0; StorPortAcquireSpinLock(DeviceExtension, InterruptLock, NULL, &LockHandle); } if (virtqueue_add_buf(adaptExt->vq[QueueNumber], &srbExt->sg[0], srbExt->out, srbExt->in, &srbExt->cmd, va, pa) >= 0){ kick = TRUE; } else { RhelDbgPrint(TRACE_LEVEL_WARNING, ("%s Cant add packet to queue.\n", __FUNCTION__)); //FIXME } if (adaptExt->num_queues > 1) { // status = StorPortReleaseMSISpinLock(DeviceExtension, MessageId, OldIrql); if (status != STOR_STATUS_SUCCESS) { RhelDbgPrint(TRACE_LEVEL_ERROR, ("%s StorPortReleaseMSISpinLock returned status 0x%x\n", __FUNCTION__, status)); } } else { StorPortReleaseSpinLock(DeviceExtension, &LockHandle); } if (kick == TRUE) { virtqueue_kick(adaptExt->vq[QueueNumber]); } return kick; EXIT_FN(); }
BOOLEAN VioScsiBuildIo( IN PVOID DeviceExtension, IN PSCSI_REQUEST_BLOCK Srb ) { PCDB cdb; ULONG i; ULONG fragLen; ULONG sgElement; ULONG sgMaxElements; PADAPTER_EXTENSION adaptExt; PSRB_EXTENSION srbExt; PSTOR_SCATTER_GATHER_LIST sgList; VirtIOSCSICmd *cmd; ENTER_FN(); cdb = (PCDB)&Srb->Cdb[0]; srbExt = (PSRB_EXTENSION)Srb->SrbExtension; adaptExt = (PADAPTER_EXTENSION)DeviceExtension; if( (Srb->PathId > 0) || (Srb->TargetId >= adaptExt->scsi_config.max_target) || (Srb->Lun >= adaptExt->scsi_config.max_lun) ) { Srb->SrbStatus = SRB_STATUS_NO_DEVICE; StorPortNotification(RequestComplete, DeviceExtension, Srb); return FALSE; } RhelDbgPrint(TRACE_LEVEL_VERBOSE, ("<-->%s (%d::%d::%d)\n", DbgGetScsiOpStr(Srb), Srb->PathId, Srb->TargetId, Srb->Lun)); memset(srbExt, 0, sizeof(*srbExt)); cmd = &srbExt->cmd; cmd->sc = Srb; cmd->req.cmd.lun[0] = 1; cmd->req.cmd.lun[1] = Srb->TargetId; cmd->req.cmd.lun[2] = 0; cmd->req.cmd.lun[3] = Srb->Lun; cmd->req.cmd.tag = (unsigned long)Srb; cmd->req.cmd.task_attr = VIRTIO_SCSI_S_SIMPLE; cmd->req.cmd.prio = 0; cmd->req.cmd.crn = 0; memcpy(cmd->req.cmd.cdb, cdb, min(VIRTIO_SCSI_CDB_SIZE, Srb->CdbLength)); sgElement = 0; srbExt->sg[sgElement].physAddr = StorPortGetPhysicalAddress(DeviceExtension, NULL, &cmd->req.cmd, &fragLen); srbExt->sg[sgElement].ulSize = sizeof(cmd->req.cmd); sgElement++; sgList = StorPortGetScatterGatherList(DeviceExtension, Srb); if (sgList) { sgMaxElements = sgList->NumberOfElements; if((Srb->SrbFlags & SRB_FLAGS_DATA_OUT) == SRB_FLAGS_DATA_OUT) { for (i = 0; i < sgMaxElements; i++, sgElement++) { srbExt->sg[sgElement].physAddr = sgList->List[i].PhysicalAddress; srbExt->sg[sgElement].ulSize = sgList->List[i].Length; srbExt->Xfer += sgList->List[i].Length; } } } srbExt->out = sgElement; srbExt->sg[sgElement].physAddr = StorPortGetPhysicalAddress(DeviceExtension, NULL, &cmd->resp.cmd, &fragLen); srbExt->sg[sgElement].ulSize = sizeof(cmd->resp.cmd); sgElement++; if (sgList) { sgMaxElements = sgList->NumberOfElements; if((Srb->SrbFlags & SRB_FLAGS_DATA_OUT) != SRB_FLAGS_DATA_OUT) { for (i = 0; i < sgMaxElements; i++, sgElement++) { srbExt->sg[sgElement].physAddr = sgList->List[i].PhysicalAddress; srbExt->sg[sgElement].ulSize = sgList->List[i].Length; srbExt->Xfer += sgList->List[i].Length; } } } srbExt->in = sgElement - srbExt->out; EXIT_FN(); return TRUE; }
SCSI_ADAPTER_CONTROL_STATUS VioScsiAdapterControl( IN PVOID DeviceExtension, IN SCSI_ADAPTER_CONTROL_TYPE ControlType, IN PVOID Parameters ) { PSCSI_SUPPORTED_CONTROL_TYPE_LIST ControlTypeList; ULONG AdjustedMaxControlType; ULONG Index; PADAPTER_EXTENSION adaptExt; SCSI_ADAPTER_CONTROL_STATUS status = ScsiAdapterControlUnsuccessful; BOOLEAN SupportedConrolTypes[5] = {TRUE, TRUE, TRUE, FALSE, FALSE}; adaptExt = (PADAPTER_EXTENSION)DeviceExtension; ENTER_FN(); RhelDbgPrint(TRACE_LEVEL_VERBOSE, ("%s %d\n", __FUNCTION__, ControlType)); switch (ControlType) { case ScsiQuerySupportedControlTypes: { RhelDbgPrint(TRACE_LEVEL_VERBOSE, ("ScsiQuerySupportedControlTypes\n")); ControlTypeList = (PSCSI_SUPPORTED_CONTROL_TYPE_LIST)Parameters; AdjustedMaxControlType = (ControlTypeList->MaxControlType < 5) ? ControlTypeList->MaxControlType : 5; for (Index = 0; Index < AdjustedMaxControlType; Index++) { ControlTypeList->SupportedTypeList[Index] = SupportedConrolTypes[Index]; } status = ScsiAdapterControlSuccess; break; } case ScsiStopAdapter: { RhelDbgPrint(TRACE_LEVEL_VERBOSE, ("ScsiStopAdapter\n")); ShutDown(DeviceExtension); status = ScsiAdapterControlSuccess; break; } case ScsiRestartAdapter: { RhelDbgPrint(TRACE_LEVEL_VERBOSE, ("ScsiRestartAdapter\n")); VirtIODeviceReset(&adaptExt->vdev); StorPortWritePortUshort(DeviceExtension, (PUSHORT)(adaptExt->device_base + VIRTIO_PCI_QUEUE_SEL), (USHORT)0); StorPortWritePortUshort(DeviceExtension, (PUSHORT)(adaptExt->device_base + VIRTIO_PCI_QUEUE_PFN),(USHORT)0); StorPortWritePortUshort(DeviceExtension, (PUSHORT)(adaptExt->device_base + VIRTIO_PCI_QUEUE_SEL), (USHORT)1); StorPortWritePortUshort(DeviceExtension, (PUSHORT)(adaptExt->device_base + VIRTIO_PCI_QUEUE_PFN),(USHORT)0); StorPortWritePortUshort(DeviceExtension, (PUSHORT)(adaptExt->device_base + VIRTIO_PCI_QUEUE_SEL), (USHORT)2); StorPortWritePortUshort(DeviceExtension, (PUSHORT)(adaptExt->device_base + VIRTIO_PCI_QUEUE_PFN),(USHORT)0); adaptExt->vq[0] = NULL; adaptExt->vq[1] = NULL; adaptExt->vq[2] = NULL; if (!VioScsiHwInitialize(DeviceExtension)) { RhelDbgPrint(TRACE_LEVEL_FATAL, ("Cannot Initialize HW\n")); break; } status = ScsiAdapterControlSuccess; break; } default: break; } EXIT_FN(); return status; }
BOOLEAN VioScsiHwInitialize( IN PVOID DeviceExtension ) { PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension; PVOID ptr = adaptExt->uncachedExtensionVa; ULONG i; #if (MSI_SUPPORTED == 1) MESSAGE_INTERRUPT_INFORMATION msi_info; #endif ENTER_FN(); adaptExt->msix_vectors = 0; #if (MSI_SUPPORTED == 1) 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[0] = FindVirtualQueue(adaptExt, 0, 1); } if(!adaptExt->dump_mode && (adaptExt->msix_vectors > 2)) { adaptExt->vq[1] = FindVirtualQueue(adaptExt, 1, 2); } if(!adaptExt->dump_mode && (adaptExt->msix_vectors > 3)) { adaptExt->vq[2] = FindVirtualQueue(adaptExt, 2, 3); } #endif if (!adaptExt->vq[0]) { adaptExt->vq[0] = FindVirtualQueue(adaptExt, 0, 0); } if (!adaptExt->vq[0]) { RhelDbgPrint(TRACE_LEVEL_FATAL, ("Cannot find virtual queue 0\n")); return FALSE; } if (!adaptExt->vq[1]) { adaptExt->vq[1] = FindVirtualQueue(adaptExt, 1, 0); } if (!adaptExt->vq[1]) { RhelDbgPrint(TRACE_LEVEL_FATAL, ("Cannot find virtual queue 1\n")); return FALSE; } if (!adaptExt->vq[2]) { adaptExt->vq[2] = FindVirtualQueue(adaptExt, 2, 0); } if (!adaptExt->vq[2]) { RhelDbgPrint(TRACE_LEVEL_FATAL, ("Cannot find virtual queue 2\n")); return FALSE; } adaptExt->tmf_cmd.SrbExtension = (PSRB_EXTENSION)((ULONG_PTR)adaptExt->uncachedExtensionVa + adaptExt->offset[3]); adaptExt->events = (PVirtIOSCSIEventNode)((ULONG_PTR)adaptExt->uncachedExtensionVa + adaptExt->offset[4]); if (!adaptExt->dump_mode && CHECKBIT(adaptExt->features, VIRTIO_SCSI_F_HOTPLUG)) { PVirtIOSCSIEventNode events = adaptExt->events; for (i = 0; i < 8; i++) { if (!KickEvent(DeviceExtension, (PVOID)(&events[i]))) { RhelDbgPrint(TRACE_LEVEL_FATAL, ("Can't add event %d\n", i)); } } } StorPortWritePortUshort(DeviceExtension, (PUSHORT)(adaptExt->device_base + VIRTIO_PCI_GUEST_FEATURES), (USHORT)((1 << VIRTIO_SCSI_F_HOTPLUG) | (1 << VIRTIO_SCSI_F_CHANGE))); StorPortWritePortUchar(DeviceExtension, (PUCHAR)(adaptExt->device_base + VIRTIO_PCI_STATUS), (UCHAR)VIRTIO_CONFIG_S_DRIVER_OK); EXIT_FN(); return TRUE; }