diff options
Diffstat (limited to 'src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp')
| -rw-r--r-- | src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp | 3498 |
1 files changed, 1910 insertions, 1588 deletions
diff --git a/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp b/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp index a8bce58e..6511ef7c 100644 --- a/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp +++ b/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp @@ -1,10 +1,10 @@ /* $Id: DevLsiLogicSCSI.cpp $ */ /** @file - * VBox storage devices: LsiLogic LSI53c1030 SCSI controller. + * DevLsiLogicSCSI - LsiLogic LSI53c1030 SCSI controller. */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -15,15 +15,20 @@ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ -//#define DEBUG +/******************************************************************************* +* Header Files * +*******************************************************************************/ #define LOG_GROUP LOG_GROUP_DEV_LSILOGICSCSI #include <VBox/vmm/pdmdev.h> #include <VBox/vmm/pdmqueue.h> +#include <VBox/vmm/pdmthread.h> #include <VBox/vmm/pdmcritsect.h> #include <VBox/scsi.h> +#include <VBox/sup.h> #include <iprt/assert.h> #include <iprt/asm.h> #include <iprt/string.h> +#include <iprt/list.h> #ifdef IN_RING3 # include <iprt/memcache.h> # include <iprt/mem.h> @@ -37,17 +42,54 @@ #include "VBoxDD.h" + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ /** The current saved state version. */ -#define LSILOGIC_SAVED_STATE_VERSION 3 +#define LSILOGIC_SAVED_STATE_VERSION 5 +/** The saved state version used by VirtualBox before the diagnostic + * memory access was implemented. */ +#define LSILOGIC_SAVED_STATE_VERSION_PRE_DIAG_MEM 4 +/** The saved state version used by VirtualBox before the doorbell status flag + * was changed from bool to a 32bit enum. */ +#define LSILOGIC_SAVED_STATE_VERSION_BOOL_DOORBELL 3 /** The saved state version used by VirtualBox before SAS support was added. */ -#define LSILOGIC_SAVED_STATE_VERSION_PRE_SAS 2 +#define LSILOGIC_SAVED_STATE_VERSION_PRE_SAS 2 /** The saved state version used by VirtualBox 3.0 and earlier. It does not * include the device config part. */ -#define LSILOGIC_SAVED_STATE_VERSION_VBOX_30 1 +#define LSILOGIC_SAVED_STATE_VERSION_VBOX_30 1 /** Maximum number of entries in the release log. */ #define MAX_REL_LOG_ERRORS 1024 +#define LSILOGIC_RTGCPHYS_FROM_U32(Hi, Lo) ( (RTGCPHYS)RT_MAKE_U64(Lo, Hi) ) + +/** Upper number a buffer is freed if it was too big before. */ +#define LSILOGIC_MAX_ALLOC_TOO_MUCH 20 + +/** Maximum size of the memory regions (prevents teh guest from DOSing the host by + * allocating loadds of memory). */ +#define LSILOGIC_MEMORY_REGIONS_MAX (_1M) + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ + +/** + * I/O buffer copy worker. + * + * @returns nothing. + * @param pDevIns Device instance data. + * @param GCPhysIoBuf Guest physical address of the I/O buffer. + * @param pvBuf R3 buffer pointer. + * @param cbCopy How much to copy. + */ +typedef DECLCALLBACK(void) FNLSILOGICIOBUFCOPY(PPDMDEVINS pDevIns, RTGCPHYS GCPhysIoBuf, + void *pvBuf, size_t cbCopy); +/** Pointer to a I/O buffer copy worker. */ +typedef FNLSILOGICIOBUFCOPY *PFNLSILOGICIOBUFCOPY; + /** * Reply data. */ @@ -61,7 +103,26 @@ typedef struct LSILOGICSCSIREPLY uint32_t cbReply; /** Different views to the reply depending on the request type. */ MptReplyUnion Reply; -} LSILOGICSCSIREPLY, *PLSILOGICSCSIREPLY; +} LSILOGICSCSIREPLY; +/** Pointer to reply data. */ +typedef LSILOGICSCSIREPLY *PLSILOGICSCSIREPLY; + +/** + * Memory region of the IOC. + */ +typedef struct LSILOGICMEMREGN +{ + /** List node. */ + RTLISTNODE NodeList; + /** 32bit address the region starts to describe. */ + uint32_t u32AddrStart; + /** 32bit address the region ends (inclusive). */ + uint32_t u32AddrEnd; + /** Data for this region - variable. */ + uint32_t au32Data[1]; +} LSILOGICMEMREGN; +/** Pointer to a memory region. */ +typedef LSILOGICMEMREGN *PLSILOGICMEMREGN; /** * State of a device attached to the buslogic host adapter. @@ -76,7 +137,7 @@ typedef struct LSILOGICDEVICE R3PTRTYPE(struct LSILOGICSCSI *) pLsiLogicR3; /** LUN of the device. */ - RTUINT iLUN; + uint32_t iLUN; /** Number of outstanding tasks on the port. */ volatile uint32_t cOutstandingRequests; @@ -97,14 +158,15 @@ typedef struct LSILOGICDEVICE /** The status LED state for this device. */ PDMLED Led; -} LSILOGICDEVICE, *PLSILOGICDEVICE; +} LSILOGICDEVICE; +/** Pointer to a device state. */ +typedef LSILOGICDEVICE *PLSILOGICDEVICE; /** Pointer to a task state. */ -typedef struct LSILOGICTASKSTATE *PLSILOGICTASKSTATE; +typedef struct LSILOGICREQ *PLSILOGICREQ; /** - * Device instance data for the emulated - * SCSI controller. + * Device instance data for the emulated SCSI controller. */ typedef struct LSILOGICSCSI { @@ -127,19 +189,15 @@ typedef struct LSILOGICSCSI /** Who needs to init the driver to get into operational state. */ LSILOGICWHOINIT enmWhoInit; /** Flag whether we are in doorbell function. */ - bool fDoorbellInProgress; + LSILOGICDOORBELLSTATE enmDoorbellState; /** Flag whether diagnostic access is enabled. */ bool fDiagnosticEnabled; - /** Flag whether a notification was send to R3. */ bool fNotificationSend; - /** Flag whether the guest enabled event notification from the IOC. */ bool fEventNotificationEnabled; - -#if HC_ARCH_BITS == 64 - uint32_t Alignment0; -#endif + /** Flag whether the diagnostic address and RW registers are enabled. */ + bool fDiagRegsEnabled; /** Queue to send tasks to R3. - R3 ptr */ R3PTRTYPE(PPDMQUEUE) pNotificationQueueR3; @@ -148,40 +206,30 @@ typedef struct LSILOGICSCSI /** Queue to send tasks to R3. - RC ptr */ RCPTRTYPE(PPDMQUEUE) pNotificationQueueRC; -#if HC_ARCH_BITS == 64 - uint32_t Alignment1; -#endif - /** Number of device states allocated. */ - uint32_t cDeviceStates; - -#if HC_ARCH_BITS == 64 - uint32_t Alignment2; -#endif + uint32_t cDeviceStates; /** States for attached devices. */ R3PTRTYPE(PLSILOGICDEVICE) paDeviceStates; - - /** MMIO address the device is mapped to. */ - RTGCPHYS GCPhysMMIOBase; - /** I/O port address the device is mapped to. */ - RTIOPORT IOPortBase; +#if HC_ARCH_BITS == 32 + RTR3PTR R3PtrPadding0; +#endif /** Interrupt mask. */ volatile uint32_t uInterruptMask; /** Interrupt status register. */ volatile uint32_t uInterruptStatus; - /** Buffer for messages which are passed - * through the doorbell using the + /** Buffer for messages which are passed through the doorbell using the * handshake method. */ - uint32_t aMessage[sizeof(MptConfigurationRequest)]; + uint32_t aMessage[sizeof(MptConfigurationRequest)]; /** @todo r=bird: Looks like 4 tims the required size? Please explain in comment if this correct... */ /** Actual position in the buffer. */ uint32_t iMessage; /** Size of the message which is given in the doorbell message in dwords. */ uint32_t cMessage; - /** Reply buffer. */ + /** Reply buffer. + * @note 60 bytes */ MptReplyUnion ReplyBuffer; /** Next entry to read. */ uint32_t uNextReplyEntryRead; @@ -191,6 +239,11 @@ typedef struct LSILOGICSCSI /** The fault code of the I/O controller if we are in the fault state. */ uint16_t u16IOCFaultCode; + /** I/O port address the device is mapped to. */ + RTIOPORT IOPortBase; + /** MMIO address the device is mapped to. */ + RTGCPHYS GCPhysMMIOBase; + /** Upper 32 bits of the message frame address to locate requests in guest memory. */ uint32_t u32HostMFAHighAddr; /** Upper 32 bits of the sense buffer address. */ @@ -211,7 +264,6 @@ typedef struct LSILOGICSCSI /** Number entries allocated for the outstanding request queue. */ uint32_t cRequestQueueEntries; - uint32_t Alignment3; /** Critical section protecting the reply post queue. */ PDMCRITSECT ReplyPostQueueCritSect; @@ -238,6 +290,8 @@ typedef struct LSILOGICSCSI RCPTRTYPE(volatile uint32_t *) pReplyPostQueueBaseRC; /** Pointer to the start of the request queue - RC. */ RCPTRTYPE(volatile uint32_t *) pRequestQueueBaseRC; + /** End these RC pointers on a 64-bit boundrary. */ + RTRCPTR RCPtrPadding1; /** Next free entry in the reply queue the guest can write a address to. */ volatile uint32_t uReplyFreeQueueNextEntryFreeWrite; @@ -259,18 +313,12 @@ typedef struct LSILOGICSCSI /** Handle counter */ uint16_t u16NextHandle; - uint16_t u16Alignment4; - uint32_t u32Alignment5; - /** Number of ports this controller has. */ uint8_t cPorts; -#if HC_ARCH_BITS == 64 - uint32_t Alignment6; -#endif - /** BIOS emulation. */ VBOXSCSI VBoxSCSI; + /** Cache for allocated tasks. */ R3PTRTYPE(RTMEMCACHE) hTaskCache; /** Status LUN: The base interface. */ @@ -282,54 +330,53 @@ typedef struct LSILOGICSCSI /** Pointer to the configuration page area. */ R3PTRTYPE(PMptConfigurationPagesSupported) pConfigurationPages; -#if HC_ARCH_BITS == 64 - uint32_t Alignment7; -#endif - /** Indicates that PDMDevHlpAsyncNotificationCompleted should be called when * a port is entering the idle state. */ - bool volatile fSignalIdle; + bool volatile fSignalIdle; /** Flag whether we have tasks which need to be processed again- */ - bool volatile fRedo; + bool volatile fRedo; + /** Flag whether the worker thread is sleeping. */ + volatile bool fWrkThreadSleeping; + /** Alignment padding. */ + bool afPadding2[HC_ARCH_BITS == 32 ? 1 : 5]; /** List of tasks which can be redone. */ - R3PTRTYPE(volatile PLSILOGICTASKSTATE) pTasksRedoHead; + R3PTRTYPE(volatile PLSILOGICREQ) pTasksRedoHead; -} LSILOGISCSI, *PLSILOGICSCSI; + /** Current address to read from or write to in the diagnostic memory region. */ + uint32_t u32DiagMemAddr; + /** Current size of the memory regions. */ + uint32_t cbMemRegns; + +#if HC_ARCH_BITS ==32 + uint32_t u32Padding3; +#endif -/** - * Scatter gather list entry data. - */ -typedef struct LSILOGICTASKSTATESGENTRY -{ - /** Flag whether the buffer in the list is from the guest or an - * allocated temporary buffer because the segments in the guest - * are not sector aligned. - */ - bool fGuestMemory; - /** Flag whether the buffer contains data or is the destination for the transfer. */ - bool fBufferContainsData; - /** Pointer to the start of the buffer. */ - void *pvBuf; - /** Size of the buffer. */ - uint32_t cbBuf; - /** Flag dependent data. */ union { - /** Data to handle direct mappings of guest buffers. */ - PGMPAGEMAPLOCK PageLock; - /** The segment in the guest which is not sector aligned. */ - RTGCPHYS GCPhysAddrBufferUnaligned; - } u; -} LSILOGICTASKSTATESGENTRY, *PLSILOGICTASKSTATESGENTRY; + /** List of memory regions - PLSILOGICMEMREGN. */ + RTLISTANCHOR ListMemRegns; + uint8_t u8Padding[2 * sizeof(RTUINTPTR)]; + }; + + /** The support driver session handle. */ + R3R0PTRTYPE(PSUPDRVSESSION) pSupDrvSession; + /** Worker thread. */ + R3PTRTYPE(PPDMTHREAD) pThreadWrk; + /** The event semaphore the processing thread waits on. */ + SUPSEMEVENT hEvtProcess; + +} LSILOGISCSI; +/** Pointer to the device instance data of the LsiLogic emulation. */ +typedef LSILOGICSCSI *PLSILOGICSCSI; /** * Task state object which holds all necessary data while * processing the request from the guest. */ -typedef struct LSILOGICTASKSTATE +typedef struct LSILOGICREQ { /** Next in the redo list. */ - PLSILOGICTASKSTATE pRedoNext; + PLSILOGICREQ pRedoNext; /** Target device. */ PLSILOGICDEVICE pTargetDevice; /** The message request from the guest. */ @@ -341,50 +388,43 @@ typedef struct LSILOGICTASKSTATE /** Address of the message request frame in guests memory. * Used to read the S/G entries in the second step. */ RTGCPHYS GCPhysMessageFrameAddr; - /** Number of scatter gather list entries. */ - uint32_t cSGListEntries; - /** How many entries would fit into the sg list. */ - uint32_t cSGListSize; - /** How many times the list was too big. */ - uint32_t cSGListTooBig; - /** Pointer to the first entry of the scatter gather list. */ - PRTSGSEG pSGListHead; - /** How many entries would fit into the sg info list. */ - uint32_t cSGInfoSize; - /** Number of entries for the information entries. */ - uint32_t cSGInfoEntries; - /** How many times the list was too big. */ - uint32_t cSGInfoTooBig; - /** Pointer to the first mapping information entry. */ - PLSILOGICTASKSTATESGENTRY paSGEntries; - /** Size of the temporary buffer for unaligned guest segments. */ - uint32_t cbBufferUnaligned; - /** Pointer to the temporary buffer. */ - void *pvBufferUnaligned; + /** Physical start address of the S/G list. */ + RTGCPHYS GCPhysSgStart; + /** Chain offset */ + uint32_t cChainOffset; + /** Segment describing the I/O buffer. */ + RTSGSEG SegIoBuf; + /** Additional memory allocation for this task. */ + void *pvAlloc; + /** Siize of the allocation. */ + size_t cbAlloc; + /** Number of times we had too much memory allocated for the request. */ + unsigned cAllocTooMuch; /** Pointer to the sense buffer. */ uint8_t abSenseBuffer[18]; /** Flag whether the request was issued from the BIOS. */ bool fBIOS; -} LSILOGICTASKSTATE; +} LSILOGICREQ; + #ifndef VBOX_DEVICE_STRUCT_TESTCASE +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ RT_C_DECLS_BEGIN #ifdef IN_RING3 -static void lsilogicInitializeConfigurationPages(PLSILOGICSCSI pLsiLogic); -static void lsilogicConfigurationPagesFree(PLSILOGICSCSI pThis); -static int lsilogicProcessConfigurationRequest(PLSILOGICSCSI pLsiLogic, PMptConfigurationRequest pConfigurationReq, - PMptConfigurationReply pReply); +static void lsilogicR3InitializeConfigurationPages(PLSILOGICSCSI pThis); +static void lsilogicR3ConfigurationPagesFree(PLSILOGICSCSI pThis); +static int lsilogicR3ProcessConfigurationRequest(PLSILOGICSCSI pThis, PMptConfigurationRequest pConfigurationReq, + PMptConfigurationReply pReply); #endif RT_C_DECLS_END -#define PDMIBASE_2_PLSILOGICDEVICE(pInterface) ( (PLSILOGICDEVICE)((uintptr_t)(pInterface) - RT_OFFSETOF(LSILOGICDEVICE, IBase)) ) -#define PDMISCSIPORT_2_PLSILOGICDEVICE(pInterface) ( (PLSILOGICDEVICE)((uintptr_t)(pInterface) - RT_OFFSETOF(LSILOGICDEVICE, ISCSIPort)) ) -#define PDMILEDPORTS_2_PLSILOGICDEVICE(pInterface) ( (PLSILOGICDEVICE)((uintptr_t)(pInterface) - RT_OFFSETOF(LSILOGICDEVICE, ILed)) ) -#define LSILOGIC_RTGCPHYS_FROM_U32(Hi, Lo) ( (RTGCPHYS)RT_MAKE_U64(Lo, Hi) ) -#define PDMIBASE_2_PLSILOGICSCSI(pInterface) ( (PLSILOGICSCSI)((uintptr_t)(pInterface) - RT_OFFSETOF(LSILOGICSCSI, IBase)) ) -#define PDMILEDPORTS_2_PLSILOGICSCSI(pInterface) ( (PLSILOGICSCSI)((uintptr_t)(pInterface) - RT_OFFSETOF(LSILOGICSCSI, ILeds)) ) +/******************************************************************************* +* Global Variables * +*******************************************************************************/ /** Key sequence the guest has to write to enable access * to diagnostic memory. */ static const uint8_t g_lsilogicDiagnosticAccess[] = {0x04, 0x0b, 0x02, 0x07, 0x0d}; @@ -393,7 +433,7 @@ static const uint8_t g_lsilogicDiagnosticAccess[] = {0x04, 0x0b, 0x02, 0x07, 0x0 * Updates the status of the interrupt pin of the device. * * @returns nothing. - * @param pThis Pointer to the device instance data. + * @param pThis Pointer to the LsiLogic device state. */ static void lsilogicUpdateInterrupt(PLSILOGICSCSI pThis) { @@ -423,13 +463,13 @@ static void lsilogicUpdateInterrupt(PLSILOGICSCSI pThis) * updates the interrupt status. * * @returns nothing. - * @param pLsiLogic Pointer to the device instance. - * @param uStatus The status bit to set. + * @param pThis Pointer to the LsiLogic device state. + * @param uStatus The status bit to set. */ -DECLINLINE(void) lsilogicSetInterrupt(PLSILOGICSCSI pLsiLogic, uint32_t uStatus) +DECLINLINE(void) lsilogicSetInterrupt(PLSILOGICSCSI pThis, uint32_t uStatus) { - ASMAtomicOrU32(&pLsiLogic->uInterruptStatus, uStatus); - lsilogicUpdateInterrupt(pLsiLogic); + ASMAtomicOrU32(&pThis->uInterruptStatus, uStatus); + lsilogicUpdateInterrupt(pThis); } /** @@ -437,50 +477,86 @@ DECLINLINE(void) lsilogicSetInterrupt(PLSILOGICSCSI pLsiLogic, uint32_t uStatus) * updates the interrupt status. * * @returns nothing. - * @param pLsiLogic Pointer to the device instance. - * @param uStatus The status bit to set. + * @param pThis Pointer to the LsiLogic device state. + * @param uStatus The status bit to set. */ -DECLINLINE(void) lsilogicClearInterrupt(PLSILOGICSCSI pLsiLogic, uint32_t uStatus) +DECLINLINE(void) lsilogicClearInterrupt(PLSILOGICSCSI pThis, uint32_t uStatus) { - ASMAtomicAndU32(&pLsiLogic->uInterruptStatus, ~uStatus); - lsilogicUpdateInterrupt(pLsiLogic); + ASMAtomicAndU32(&pThis->uInterruptStatus, ~uStatus); + lsilogicUpdateInterrupt(pThis); } /** * Sets the I/O controller into fault state and sets the fault code. * * @returns nothing - * @param pLsiLogic Pointer to the controller device instance. - * @param uIOCFaultCode Fault code to set. + * @param pThis Pointer to the LsiLogic device state. + * @param uIOCFaultCode Fault code to set. */ -DECLINLINE(void) lsilogicSetIOCFaultCode(PLSILOGICSCSI pLsiLogic, uint16_t uIOCFaultCode) +DECLINLINE(void) lsilogicSetIOCFaultCode(PLSILOGICSCSI pThis, uint16_t uIOCFaultCode) { - if (pLsiLogic->enmState != LSILOGICSTATE_FAULT) + if (pThis->enmState != LSILOGICSTATE_FAULT) { Log(("%s: Setting I/O controller into FAULT state: uIOCFaultCode=%u\n", __FUNCTION__, uIOCFaultCode)); - pLsiLogic->enmState = LSILOGICSTATE_FAULT; - pLsiLogic->u16IOCFaultCode = uIOCFaultCode; + pThis->enmState = LSILOGICSTATE_FAULT; + pThis->u16IOCFaultCode = uIOCFaultCode; } else - { Log(("%s: We are already in FAULT state\n")); - } +} + +/** + * Returns the number of frames in the reply free queue. + * + * @returns Number of frames in the reply free queue. + * @param pThis Pointer to the LsiLogic device state. + */ +DECLINLINE(uint32_t) lsilogicReplyFreeQueueGetFrameCount(PLSILOGICSCSI pThis) +{ + uint32_t cReplyFrames = 0; + + if (pThis->uReplyFreeQueueNextAddressRead <= pThis->uReplyFreeQueueNextEntryFreeWrite) + cReplyFrames = pThis->uReplyFreeQueueNextEntryFreeWrite - pThis->uReplyFreeQueueNextAddressRead; + else + cReplyFrames = pThis->cReplyQueueEntries - pThis->uReplyFreeQueueNextAddressRead + pThis->uReplyFreeQueueNextEntryFreeWrite; + + return cReplyFrames; +} + +/** + * Returns the number of free entries in the reply post queue. + * + * @returns Number of frames in the reply free queue. + * @param pThis Pointer to the LsiLogic device state. + */ +DECLINLINE(uint32_t) lsilogicReplyPostQueueGetFrameCount(PLSILOGICSCSI pThis) +{ + uint32_t cReplyFrames = 0; + + if (pThis->uReplyPostQueueNextAddressRead <= pThis->uReplyPostQueueNextEntryFreeWrite) + cReplyFrames = pThis->cReplyQueueEntries - pThis->uReplyPostQueueNextEntryFreeWrite + pThis->uReplyPostQueueNextAddressRead; + else + cReplyFrames = pThis->uReplyPostQueueNextEntryFreeWrite - pThis->uReplyPostQueueNextAddressRead; + + return cReplyFrames; } #ifdef IN_RING3 + /** * Performs a hard reset on the controller. * * @returns VBox status code. - * @param pThis Pointer to the device instance to initialize. + * @param pThis Pointer to the LsiLogic device state. */ -static int lsilogicHardReset(PLSILOGICSCSI pThis) +static int lsilogicR3HardReset(PLSILOGICSCSI pThis) { pThis->enmState = LSILOGICSTATE_RESET; + pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_NOT_IN_USE; /* The interrupts are masked out. */ - pThis->uInterruptMask |= LSILOGIC_REG_HOST_INTR_MASK_DOORBELL | - LSILOGIC_REG_HOST_INTR_MASK_REPLY; + pThis->uInterruptMask |= LSILOGIC_REG_HOST_INTR_MASK_DOORBELL + | LSILOGIC_REG_HOST_INTR_MASK_REPLY; /* Reset interrupt states. */ pThis->uInterruptStatus = 0; lsilogicUpdateInterrupt(pThis); @@ -494,17 +570,19 @@ static int lsilogicHardReset(PLSILOGICSCSI pThis) pThis->uRequestQueueNextAddressRead = 0; /* Disable diagnostic access. */ - pThis->iDiagnosticAccess = 0; + pThis->iDiagnosticAccess = 0; + pThis->fDiagnosticEnabled = false; + pThis->fDiagRegsEnabled = false; /* Set default values. */ - pThis->cMaxDevices = pThis->cDeviceStates; - pThis->cMaxBuses = 1; - pThis->cbReplyFrame = 128; /* @todo Figure out where it is needed. */ - pThis->u16NextHandle = 1; - /** @todo: Put stuff to reset here. */ + pThis->cMaxDevices = pThis->cDeviceStates; + pThis->cMaxBuses = 1; + pThis->cbReplyFrame = 128; /* @todo Figure out where it is needed. */ + pThis->u16NextHandle = 1; + pThis->u32DiagMemAddr = 0; - lsilogicConfigurationPagesFree(pThis); - lsilogicInitializeConfigurationPages(pThis); + lsilogicR3ConfigurationPagesFree(pThis); + lsilogicR3InitializeConfigurationPages(pThis); /* Mark that we finished performing the reset. */ pThis->enmState = LSILOGICSTATE_READY; @@ -517,7 +595,7 @@ static int lsilogicHardReset(PLSILOGICSCSI pThis) * @returns nothing. * @param pThis The LsiLogic controller instance */ -static void lsilogicConfigurationPagesFree(PLSILOGICSCSI pThis) +static void lsilogicR3ConfigurationPagesFree(PLSILOGICSCSI pThis) { if (pThis->pConfigurationPages) @@ -553,69 +631,39 @@ static void lsilogicConfigurationPagesFree(PLSILOGICSCSI pThis) * Finishes a context reply. * * @returns nothing - * @param pLsiLogic Pointer to the device instance - * @param u32MessageContext The message context ID to post. + * @param pThis Pointer to the LsiLogic device state. + * @param u32MessageContext The message context ID to post. */ -static void lsilogicFinishContextReply(PLSILOGICSCSI pLsiLogic, uint32_t u32MessageContext) +static void lsilogicR3FinishContextReply(PLSILOGICSCSI pThis, uint32_t u32MessageContext) { int rc; - LogFlowFunc(("pLsiLogic=%#p u32MessageContext=%#x\n", pLsiLogic, u32MessageContext)); + LogFlowFunc(("pThis=%#p u32MessageContext=%#x\n", pThis, u32MessageContext)); - AssertMsg(!pLsiLogic->fDoorbellInProgress, ("We are in a doorbell function\n")); + AssertMsg(pThis->enmDoorbellState == LSILOGICDOORBELLSTATE_NOT_IN_USE, ("We are in a doorbell function\n")); /* Write message context ID into reply post queue. */ - rc = PDMCritSectEnter(&pLsiLogic->ReplyPostQueueCritSect, VINF_SUCCESS); + rc = PDMCritSectEnter(&pThis->ReplyPostQueueCritSect, VINF_SUCCESS); AssertRC(rc); -#if 0 /* Check for a entry in the queue. */ - if (RT_UNLIKELY(pLsiLogic->uReplyPostQueueNextAddressRead != pLsiLogic->uReplyPostQueueNextEntryFreeWrite)) + if (!lsilogicReplyPostQueueGetFrameCount(pThis)) { /* Set error code. */ - lsilogicSetIOCFaultCode(pLsiLogic, LSILOGIC_IOCSTATUS_INSUFFICIENT_RESOURCES); - PDMCritSectLeave(&pLsiLogic->ReplyPostQueueCritSect); + lsilogicSetIOCFaultCode(pThis, LSILOGIC_IOCSTATUS_INSUFFICIENT_RESOURCES); + PDMCritSectLeave(&pThis->ReplyPostQueueCritSect); return; } -#endif /* We have a context reply. */ - ASMAtomicWriteU32(&pLsiLogic->CTX_SUFF(pReplyPostQueueBase)[pLsiLogic->uReplyPostQueueNextEntryFreeWrite], u32MessageContext); - ASMAtomicIncU32(&pLsiLogic->uReplyPostQueueNextEntryFreeWrite); - pLsiLogic->uReplyPostQueueNextEntryFreeWrite %= pLsiLogic->cReplyQueueEntries; + ASMAtomicWriteU32(&pThis->CTX_SUFF(pReplyPostQueueBase)[pThis->uReplyPostQueueNextEntryFreeWrite], u32MessageContext); + ASMAtomicIncU32(&pThis->uReplyPostQueueNextEntryFreeWrite); + pThis->uReplyPostQueueNextEntryFreeWrite %= pThis->cReplyQueueEntries; /* Set interrupt. */ - lsilogicSetInterrupt(pLsiLogic, LSILOGIC_REG_HOST_INTR_STATUS_REPLY_INTR); - - PDMCritSectLeave(&pLsiLogic->ReplyPostQueueCritSect); -} + lsilogicSetInterrupt(pThis, LSILOGIC_REG_HOST_INTR_STATUS_REPLY_INTR); -static void lsilogicTaskStateClear(PLSILOGICTASKSTATE pTaskState) -{ - RTMemFree(pTaskState->pSGListHead); - RTMemFree(pTaskState->paSGEntries); - if (pTaskState->pvBufferUnaligned) - RTMemPageFree(pTaskState->pvBufferUnaligned, pTaskState->cbBufferUnaligned); - pTaskState->cSGListSize = 0; - pTaskState->cSGInfoSize = 0; - pTaskState->cSGInfoEntries = 0; - pTaskState->cSGListTooBig = 0; - pTaskState->pSGListHead = NULL; - pTaskState->paSGEntries = NULL; - pTaskState->pvBufferUnaligned = NULL; - pTaskState->cbBufferUnaligned = 0; -} - -static int lsilogicTaskStateCtor(RTMEMCACHE hMemCache, void *pvObj, void *pvUser) -{ - memset(pvObj, 0, sizeof(LSILOGICTASKSTATE)); - return VINF_SUCCESS; -} - -static void lsilogicTaskStateDtor(RTMEMCACHE hMemCache, void *pvObj, void *pvUser) -{ - PLSILOGICTASKSTATE pTaskState = (PLSILOGICTASKSTATE)pvObj; - lsilogicTaskStateClear(pTaskState); + PDMCritSectLeave(&pThis->ReplyPostQueueCritSect); } #endif /* IN_RING3 */ @@ -624,24 +672,24 @@ static void lsilogicTaskStateDtor(RTMEMCACHE hMemCache, void *pvObj, void *pvUse * Takes necessary steps to finish a reply frame. * * @returns nothing - * @param pLsiLogic Pointer to the device instance + * @param pThis Pointer to the LsiLogic device state. * @param pReply Pointer to the reply message. * @param fForceReplyFifo Flag whether the use of the reply post fifo is forced. */ -static void lsilogicFinishAddressReply(PLSILOGICSCSI pLsiLogic, PMptReplyUnion pReply, bool fForceReplyFifo) +static void lsilogicFinishAddressReply(PLSILOGICSCSI pThis, PMptReplyUnion pReply, bool fForceReplyFifo) { /* * If we are in a doorbell function we set the reply size now and * set the system doorbell status interrupt to notify the guest that * we are ready to send the reply. */ - if (pLsiLogic->fDoorbellInProgress && !fForceReplyFifo) + if (pThis->enmDoorbellState != LSILOGICDOORBELLSTATE_NOT_IN_USE && !fForceReplyFifo) { /* Set size of the reply in 16bit words. The size in the reply is in 32bit dwords. */ - pLsiLogic->cReplySize = pReply->Header.u8MessageLength * 2; - Log(("%s: cReplySize=%u\n", __FUNCTION__, pLsiLogic->cReplySize)); - pLsiLogic->uNextReplyEntryRead = 0; - lsilogicSetInterrupt(pLsiLogic, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL); + pThis->cReplySize = pReply->Header.u8MessageLength * 2; + Log(("%s: cReplySize=%u\n", __FUNCTION__, pThis->cReplySize)); + pThis->uNextReplyEntryRead = 0; + lsilogicSetInterrupt(pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL); } else { @@ -653,65 +701,61 @@ static void lsilogicFinishAddressReply(PLSILOGICSCSI pLsiLogic, PMptReplyUnion p #ifdef IN_RING3 int rc; /* Grab a free reply message from the queue. */ - rc = PDMCritSectEnter(&pLsiLogic->ReplyFreeQueueCritSect, VINF_SUCCESS); + rc = PDMCritSectEnter(&pThis->ReplyFreeQueueCritSect, VINF_SUCCESS); AssertRC(rc); -#if 0 /* Check for a free reply frame. */ - if (RT_UNLIKELY(pLsiLogic->uReplyFreeQueueNextAddressRead != pLsiLogic->uReplyFreeQueueNextEntryFreeWrite)) + if (!lsilogicReplyFreeQueueGetFrameCount(pThis)) { /* Set error code. */ - lsilogicSetIOCFaultCode(pLsiLogic, LSILOGIC_IOCSTATUS_INSUFFICIENT_RESOURCES); - PDMCritSectLeave(&pLsiLogic->ReplyFreeQueueCritSect); + lsilogicSetIOCFaultCode(pThis, LSILOGIC_IOCSTATUS_INSUFFICIENT_RESOURCES); + PDMCritSectLeave(&pThis->ReplyFreeQueueCritSect); return; } -#endif - uint32_t u32ReplyFrameAddressLow = pLsiLogic->CTX_SUFF(pReplyFreeQueueBase)[pLsiLogic->uReplyFreeQueueNextAddressRead]; + uint32_t u32ReplyFrameAddressLow = pThis->CTX_SUFF(pReplyFreeQueueBase)[pThis->uReplyFreeQueueNextAddressRead]; - pLsiLogic->uReplyFreeQueueNextAddressRead++; - pLsiLogic->uReplyFreeQueueNextAddressRead %= pLsiLogic->cReplyQueueEntries; + pThis->uReplyFreeQueueNextAddressRead++; + pThis->uReplyFreeQueueNextAddressRead %= pThis->cReplyQueueEntries; - PDMCritSectLeave(&pLsiLogic->ReplyFreeQueueCritSect); + PDMCritSectLeave(&pThis->ReplyFreeQueueCritSect); /* Build 64bit physical address. */ - RTGCPHYS GCPhysReplyMessage = LSILOGIC_RTGCPHYS_FROM_U32(pLsiLogic->u32HostMFAHighAddr, u32ReplyFrameAddressLow); - size_t cbReplyCopied = (pLsiLogic->cbReplyFrame < sizeof(MptReplyUnion)) ? pLsiLogic->cbReplyFrame : sizeof(MptReplyUnion); + RTGCPHYS GCPhysReplyMessage = LSILOGIC_RTGCPHYS_FROM_U32(pThis->u32HostMFAHighAddr, u32ReplyFrameAddressLow); + size_t cbReplyCopied = (pThis->cbReplyFrame < sizeof(MptReplyUnion)) ? pThis->cbReplyFrame : sizeof(MptReplyUnion); /* Write reply to guest memory. */ - PDMDevHlpPhysWrite(pLsiLogic->CTX_SUFF(pDevIns), GCPhysReplyMessage, pReply, cbReplyCopied); + PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), GCPhysReplyMessage, pReply, cbReplyCopied); /* Write low 32bits of reply frame into post reply queue. */ - rc = PDMCritSectEnter(&pLsiLogic->ReplyPostQueueCritSect, VINF_SUCCESS); + rc = PDMCritSectEnter(&pThis->ReplyPostQueueCritSect, VINF_SUCCESS); AssertRC(rc); -#if 0 /* Check for a entry in the queue. */ - if (RT_UNLIKELY(pLsiLogic->uReplyPostQueueNextAddressRead != pLsiLogic->uReplyPostQueueNextEntryFreeWrite)) + if (!lsilogicReplyPostQueueGetFrameCount(pThis)) { /* Set error code. */ - lsilogicSetIOCFaultCode(pLsiLogic, LSILOGIC_IOCSTATUS_INSUFFICIENT_RESOURCES); - PDMCritSectLeave(&pLsiLogic->ReplyPostQueueCritSect); + lsilogicSetIOCFaultCode(pThis, LSILOGIC_IOCSTATUS_INSUFFICIENT_RESOURCES); + PDMCritSectLeave(&pThis->ReplyPostQueueCritSect); return; } -#endif /* We have a address reply. Set the 31th bit to indicate that. */ - ASMAtomicWriteU32(&pLsiLogic->CTX_SUFF(pReplyPostQueueBase)[pLsiLogic->uReplyPostQueueNextEntryFreeWrite], + ASMAtomicWriteU32(&pThis->CTX_SUFF(pReplyPostQueueBase)[pThis->uReplyPostQueueNextEntryFreeWrite], RT_BIT(31) | (u32ReplyFrameAddressLow >> 1)); - ASMAtomicIncU32(&pLsiLogic->uReplyPostQueueNextEntryFreeWrite); - pLsiLogic->uReplyPostQueueNextEntryFreeWrite %= pLsiLogic->cReplyQueueEntries; + ASMAtomicIncU32(&pThis->uReplyPostQueueNextEntryFreeWrite); + pThis->uReplyPostQueueNextEntryFreeWrite %= pThis->cReplyQueueEntries; if (fForceReplyFifo) { - pLsiLogic->fDoorbellInProgress = false; - lsilogicSetInterrupt(pLsiLogic, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL); + pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_NOT_IN_USE; + lsilogicSetInterrupt(pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL); } /* Set interrupt. */ - lsilogicSetInterrupt(pLsiLogic, LSILOGIC_REG_HOST_INTR_STATUS_REPLY_INTR); + lsilogicSetInterrupt(pThis, LSILOGIC_REG_HOST_INTR_STATUS_REPLY_INTR); - PDMCritSectLeave(&pLsiLogic->ReplyPostQueueCritSect); + PDMCritSectLeave(&pThis->ReplyPostQueueCritSect); #else AssertMsgFailed(("This is not allowed to happen.\n")); #endif @@ -719,25 +763,256 @@ static void lsilogicFinishAddressReply(PLSILOGICSCSI pLsiLogic, PMptReplyUnion p } #ifdef IN_RING3 + +/** + * Tries to find a memory region which covers the given address. + * + * @returns Pointer to memory region or NULL if not found. + * @param pThis Pointer to the LsiLogic device state. + * @param u32Addr The 32bit address to search for. + */ +static PLSILOGICMEMREGN lsilogicR3MemRegionFindByAddr(PLSILOGICSCSI pThis, uint32_t u32Addr) +{ + PLSILOGICMEMREGN pIt; + PLSILOGICMEMREGN pRegion = NULL; + + RTListForEach(&pThis->ListMemRegns, pIt, LSILOGICMEMREGN, NodeList) + { + if ( u32Addr >= pIt->u32AddrStart + && u32Addr <= pIt->u32AddrEnd) + { + pRegion = pIt; + break; + } + } + + return pRegion; +} + +/** + * Frees all allocated memory regions. + * + * @returns nothing. + * @param pThis Pointer to the LsiLogic device state. + */ +static void lsilogicR3MemRegionsFree(PLSILOGICSCSI pThis) +{ + PLSILOGICMEMREGN pIt; + PLSILOGICMEMREGN pItNext; + + RTListForEachSafe(&pThis->ListMemRegns, pIt, pItNext, LSILOGICMEMREGN, NodeList) + { + RTListNodeRemove(&pIt->NodeList); + RTMemFree(pIt); + } + pThis->cbMemRegns = 0; +} + +/** + * Inserts a given memory region into the list. + * + * @returns nothing. + * @param pThis Pointer to the LsiLogic device state. + * @param pRegion The region to insert. + */ +static void lsilogicR3MemRegionInsert(PLSILOGICSCSI pThis, PLSILOGICMEMREGN pRegion) +{ + PLSILOGICMEMREGN pIt; + bool fInserted = false; + + /* Insert at the right position. */ + RTListForEach(&pThis->ListMemRegns, pIt, LSILOGICMEMREGN, NodeList) + { + if (pRegion->u32AddrEnd < pIt->u32AddrStart) + { + RTListNodeInsertBefore(&pIt->NodeList, &pRegion->NodeList); + fInserted = true; + break; + } + } + if (!fInserted) + RTListAppend(&pThis->ListMemRegns, &pRegion->NodeList); +} + +/** + * Count number of memory regions. + * + * @returns Number of memory regions. + * @param pThis Pointer to the LsiLogic device state. + */ +static uint32_t lsilogicR3MemRegionsCount(PLSILOGICSCSI pThis) +{ + uint32_t cRegions = 0; + PLSILOGICMEMREGN pIt; + + RTListForEach(&pThis->ListMemRegns, pIt, LSILOGICMEMREGN, NodeList) + { + cRegions++; + } + + return cRegions; +} + +/** + * Handles a write to the diagnostic data register. + * + * @returns nothing. + * @param pThis Pointer to the LsiLogic device state. + * @param u32Data Data to write. + */ +static void lsilogicR3DiagRegDataWrite(PLSILOGICSCSI pThis, uint32_t u32Data) +{ + PLSILOGICMEMREGN pRegion = lsilogicR3MemRegionFindByAddr(pThis, pThis->u32DiagMemAddr); + + if (pRegion) + { + uint32_t offRegion = pThis->u32DiagMemAddr - pRegion->u32AddrStart; + + AssertMsg( offRegion % 4 == 0 + && pThis->u32DiagMemAddr <= pRegion->u32AddrEnd, + ("Region offset not on a word boundary or crosses memory region\n")); + + offRegion /= 4; + pRegion->au32Data[offRegion] = u32Data; + } + else + { + PLSILOGICMEMREGN pIt; + + pRegion = NULL; + + /* Create new region, first check whether we can extend another region. */ + RTListForEach(&pThis->ListMemRegns, pIt, LSILOGICMEMREGN, NodeList) + { + if (pThis->u32DiagMemAddr == pIt->u32AddrEnd + sizeof(uint32_t)) + { + pRegion = pIt; + break; + } + } + + if (pRegion) + { + /* Reallocate. */ + RTListNodeRemove(&pRegion->NodeList); + + uint32_t cRegionSizeOld = (pRegion->u32AddrEnd - pRegion->u32AddrStart) / 4 + 1; + uint32_t cRegionSizeNew = cRegionSizeOld + 512; + + if (pThis->cbMemRegns + 512 * sizeof(uint32_t) < LSILOGIC_MEMORY_REGIONS_MAX) + { + PLSILOGICMEMREGN pRegionNew = (PLSILOGICMEMREGN)RTMemRealloc(pRegion, RT_OFFSETOF(LSILOGICMEMREGN, au32Data[cRegionSizeNew])); + + if (pRegionNew) + { + pRegion = pRegionNew; + memset(&pRegion->au32Data[cRegionSizeOld], 0, 512 * sizeof(uint32_t)); + pRegion->au32Data[cRegionSizeOld] = u32Data; + pRegion->u32AddrEnd = pRegion->u32AddrStart + (cRegionSizeNew - 1) * sizeof(uint32_t); + pThis->cbMemRegns += 512 * sizeof(uint32_t); + } + /* else: Silently fail, there is nothing we can do here and the guest might work nevertheless. */ + + lsilogicR3MemRegionInsert(pThis, pRegion); + } + } + else + { + if (pThis->cbMemRegns + 512 * sizeof(uint32_t) < LSILOGIC_MEMORY_REGIONS_MAX) + { + /* Create completely new. */ + pRegion = (PLSILOGICMEMREGN)RTMemAllocZ(RT_OFFSETOF(LSILOGICMEMREGN, au32Data[512])); + if (pRegion) + { + pRegion->u32AddrStart = pThis->u32DiagMemAddr; + pRegion->u32AddrEnd = pRegion->u32AddrStart + (512 - 1) * sizeof(uint32_t); + pRegion->au32Data[0] = u32Data; + pThis->cbMemRegns += 512 * sizeof(uint32_t); + + lsilogicR3MemRegionInsert(pThis, pRegion); + } + /* else: Silently fail, there is nothing we can do here and the guest might work nevertheless. */ + } + } + + } + + /* Memory access is always 32bit big. */ + pThis->u32DiagMemAddr += sizeof(uint32_t); +} + +/** + * Handles a read from the diagnostic data register. + * + * @returns nothing. + * @param pThis Pointer to the LsiLogic device state. + * @param pu32Data Where to store the data. + */ +static void lsilogicR3DiagRegDataRead(PLSILOGICSCSI pThis, uint32_t *pu32Data) +{ + PLSILOGICMEMREGN pRegion = lsilogicR3MemRegionFindByAddr(pThis, pThis->u32DiagMemAddr); + + if (pRegion) + { + uint32_t offRegion = pThis->u32DiagMemAddr - pRegion->u32AddrStart; + + AssertMsg( offRegion % 4 == 0 + && pThis->u32DiagMemAddr <= pRegion->u32AddrEnd, + ("Region offset not on a word boundary or crosses memory region\n")); + + offRegion /= 4; + *pu32Data = pRegion->au32Data[offRegion]; + } + else /* No region, default value 0. */ + *pu32Data = 0; + + /* Memory access is always 32bit big. */ + pThis->u32DiagMemAddr += sizeof(uint32_t); +} + +/** + * Handles a write to the diagnostic memory address register. + * + * @returns nothing. + * @param pThis Pointer to the LsiLogic device state. + * @param u32Addr Address to write. + */ +static void lsilogicR3DiagRegAddressWrite(PLSILOGICSCSI pThis, uint32_t u32Addr) +{ + pThis->u32DiagMemAddr = u32Addr & ~UINT32_C(0x3); /* 32bit alignment. */ +} + +/** + * Handles a read from the diagnostic memory address register. + * + * @returns nothing. + * @param pThis Pointer to the LsiLogic device state. + * @param pu32Addr Where to store the current address. + */ +static void lsilogicR3DiagRegAddressRead(PLSILOGICSCSI pThis, uint32_t *pu32Addr) +{ + *pu32Addr = pThis->u32DiagMemAddr; +} + /** * Processes a given Request from the guest * * @returns VBox status code. - * @param pLsiLogic Pointer to the device instance. - * @param pMessageHdr Pointer to the message header of the request. - * @param pReply Pointer to the reply. + * @param pThis Pointer to the LsiLogic device state. + * @param pMessageHdr Pointer to the message header of the request. + * @param pReply Pointer to the reply. */ -static int lsilogicProcessMessageRequest(PLSILOGICSCSI pLsiLogic, PMptMessageHdr pMessageHdr, PMptReplyUnion pReply) +static int lsilogicR3ProcessMessageRequest(PLSILOGICSCSI pThis, PMptMessageHdr pMessageHdr, PMptReplyUnion pReply) { int rc = VINF_SUCCESS; bool fForceReplyPostFifo = false; -#ifdef DEBUG +# ifdef LOG_ENABLED if (pMessageHdr->u8Function < RT_ELEMENTS(g_apszMPTFunctionNames)) Log(("Message request function: %s\n", g_apszMPTFunctionNames[pMessageHdr->u8Function])); else Log(("Message request function: <unknown>\n")); -#endif +# endif memset(pReply, 0, sizeof(MptReplyUnion)); @@ -765,61 +1040,87 @@ static int lsilogicProcessMessageRequest(PLSILOGICSCSI pLsiLogic, PMptMessageHdr PMptIOCInitRequest pIOCInitReq = (PMptIOCInitRequest)pMessageHdr; /* Update configuration values. */ - pLsiLogic->enmWhoInit = (LSILOGICWHOINIT)pIOCInitReq->u8WhoInit; - pLsiLogic->cbReplyFrame = pIOCInitReq->u16ReplyFrameSize; - pLsiLogic->cMaxBuses = pIOCInitReq->u8MaxBuses; - pLsiLogic->cMaxDevices = pIOCInitReq->u8MaxDevices; - pLsiLogic->u32HostMFAHighAddr = pIOCInitReq->u32HostMfaHighAddr; - pLsiLogic->u32SenseBufferHighAddr = pIOCInitReq->u32SenseBufferHighAddr; - - if (pLsiLogic->enmState == LSILOGICSTATE_READY) + pThis->enmWhoInit = (LSILOGICWHOINIT)pIOCInitReq->u8WhoInit; + pThis->cbReplyFrame = pIOCInitReq->u16ReplyFrameSize; + pThis->cMaxBuses = pIOCInitReq->u8MaxBuses; + pThis->cMaxDevices = pIOCInitReq->u8MaxDevices; + pThis->u32HostMFAHighAddr = pIOCInitReq->u32HostMfaHighAddr; + pThis->u32SenseBufferHighAddr = pIOCInitReq->u32SenseBufferHighAddr; + + if (pThis->enmState == LSILOGICSTATE_READY) { - pLsiLogic->enmState = LSILOGICSTATE_OPERATIONAL; + pThis->enmState = LSILOGICSTATE_OPERATIONAL; } /* Return reply. */ pReply->IOCInit.u8MessageLength = 5; - pReply->IOCInit.u8WhoInit = pLsiLogic->enmWhoInit; - pReply->IOCInit.u8MaxDevices = pLsiLogic->cMaxDevices; - pReply->IOCInit.u8MaxBuses = pLsiLogic->cMaxBuses; + pReply->IOCInit.u8WhoInit = pThis->enmWhoInit; + pReply->IOCInit.u8MaxDevices = pThis->cMaxDevices; + pReply->IOCInit.u8MaxBuses = pThis->cMaxBuses; break; } case MPT_MESSAGE_HDR_FUNCTION_IOC_FACTS: { pReply->IOCFacts.u8MessageLength = 15; /* 15 32bit dwords. */ - if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI) + if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI) { pReply->IOCFacts.u16MessageVersion = 0x0102; /* Version from the specification. */ - pReply->IOCFacts.u8NumberOfPorts = pLsiLogic->cPorts; + pReply->IOCFacts.u8NumberOfPorts = pThis->cPorts; } - else if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS) + else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS) { pReply->IOCFacts.u16MessageVersion = 0x0105; /* Version from the specification. */ - pReply->IOCFacts.u8NumberOfPorts = pLsiLogic->cPorts; + pReply->IOCFacts.u8NumberOfPorts = pThis->cPorts; } else - AssertMsgFailed(("Invalid controller type %d\n", pLsiLogic->enmCtrlType)); + AssertMsgFailed(("Invalid controller type %d\n", pThis->enmCtrlType)); pReply->IOCFacts.u8IOCNumber = 0; /* PCI function number. */ pReply->IOCFacts.u16IOCExceptions = 0; pReply->IOCFacts.u8MaxChainDepth = LSILOGICSCSI_MAXIMUM_CHAIN_DEPTH; - pReply->IOCFacts.u8WhoInit = pLsiLogic->enmWhoInit; + pReply->IOCFacts.u8WhoInit = pThis->enmWhoInit; pReply->IOCFacts.u8BlockSize = 12; /* Block size in 32bit dwords. This is the largest request we can get (SCSI I/O). */ pReply->IOCFacts.u8Flags = 0; /* Bit 0 is set if the guest must upload the FW prior to using the controller. Obviously not needed here. */ - pReply->IOCFacts.u16ReplyQueueDepth = pLsiLogic->cReplyQueueEntries - 1; /* One entry is always free. */ + pReply->IOCFacts.u16ReplyQueueDepth = pThis->cReplyQueueEntries - 1; /* One entry is always free. */ pReply->IOCFacts.u16RequestFrameSize = 128; /* @todo Figure out where it is needed. */ - pReply->IOCFacts.u16ProductID = 0xcafe; /* Our own product ID :) */ - pReply->IOCFacts.u32CurrentHostMFAHighAddr = pLsiLogic->u32HostMFAHighAddr; - pReply->IOCFacts.u16GlobalCredits = pLsiLogic->cRequestQueueEntries - 1; /* One entry is always free. */ + pReply->IOCFacts.u32CurrentHostMFAHighAddr = pThis->u32HostMFAHighAddr; + pReply->IOCFacts.u16GlobalCredits = pThis->cRequestQueueEntries - 1; /* One entry is always free. */ pReply->IOCFacts.u8EventState = 0; /* Event notifications not enabled. */ - pReply->IOCFacts.u32CurrentSenseBufferHighAddr = pLsiLogic->u32SenseBufferHighAddr; - pReply->IOCFacts.u16CurReplyFrameSize = pLsiLogic->cbReplyFrame; - pReply->IOCFacts.u8MaxDevices = pLsiLogic->cMaxDevices; - pReply->IOCFacts.u8MaxBuses = pLsiLogic->cMaxBuses; - pReply->IOCFacts.u32FwImageSize = 0; /* No image needed. */ - pReply->IOCFacts.u32FWVersion = 0; + pReply->IOCFacts.u32CurrentSenseBufferHighAddr = pThis->u32SenseBufferHighAddr; + pReply->IOCFacts.u16CurReplyFrameSize = pThis->cbReplyFrame; + pReply->IOCFacts.u8MaxDevices = pThis->cMaxDevices; + pReply->IOCFacts.u8MaxBuses = pThis->cMaxBuses; + + /* Check for a valid firmware image in the IOC memory which was downlaoded by tzhe guest earlier. */ + PLSILOGICMEMREGN pRegion = lsilogicR3MemRegionFindByAddr(pThis, LSILOGIC_FWIMGHDR_LOAD_ADDRESS); + + if (pRegion) + { + uint32_t offImgHdr = (LSILOGIC_FWIMGHDR_LOAD_ADDRESS - pRegion->u32AddrStart) / 4; + PFwImageHdr pFwImgHdr = (PFwImageHdr)&pRegion->au32Data[offImgHdr]; + + /* Check for the signature. */ + /** @todo: Checksum validation. */ + if ( pFwImgHdr->u32Signature1 == LSILOGIC_FWIMGHDR_SIGNATURE1 + && pFwImgHdr->u32Signature2 == LSILOGIC_FWIMGHDR_SIGNATURE2 + && pFwImgHdr->u32Signature3 == LSILOGIC_FWIMGHDR_SIGNATURE3) + { + LogFlowFunc(("IOC Facts: Found valid firmware image header in memory, using version (%#x), size (%d) and product ID (%#x) from there\n", + pFwImgHdr->u32FwVersion, pFwImgHdr->u32ImageSize, pFwImgHdr->u16ProductId)); + + pReply->IOCFacts.u16ProductID = pFwImgHdr->u16ProductId; + pReply->IOCFacts.u32FwImageSize = pFwImgHdr->u32ImageSize; + pReply->IOCFacts.u32FWVersion = pFwImgHdr->u32FwVersion; + } + } + else + { + pReply->IOCFacts.u16ProductID = 0xcafe; /* Our own product ID :) */ + pReply->IOCFacts.u32FwImageSize = 0; /* No image needed. */ + pReply->IOCFacts.u32FWVersion = 0; + } break; } case MPT_MESSAGE_HDR_FUNCTION_PORT_FACTS: @@ -829,10 +1130,10 @@ static int lsilogicProcessMessageRequest(PLSILOGICSCSI pLsiLogic, PMptMessageHdr pReply->PortFacts.u8MessageLength = 10; pReply->PortFacts.u8PortNumber = pPortFactsReq->u8PortNumber; - if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI) + if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI) { /* This controller only supports one bus with bus number 0. */ - if (pPortFactsReq->u8PortNumber >= pLsiLogic->cPorts) + if (pPortFactsReq->u8PortNumber >= pThis->cPorts) { pReply->PortFacts.u8PortType = 0; /* Not existant. */ } @@ -847,25 +1148,25 @@ static int lsilogicProcessMessageRequest(PLSILOGICSCSI pLsiLogic, PMptMessageHdr pReply->PortFacts.u16MaxLANBuckets = 0; /* Only for the LAN controller. */ } } - else if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS) + else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS) { - if (pPortFactsReq->u8PortNumber >= pLsiLogic->cPorts) + if (pPortFactsReq->u8PortNumber >= pThis->cPorts) { pReply->PortFacts.u8PortType = 0; /* Not existant. */ } else { pReply->PortFacts.u8PortType = 0x30; /* SAS Port. */ - pReply->PortFacts.u16MaxDevices = pLsiLogic->cPorts; + pReply->PortFacts.u16MaxDevices = pThis->cPorts; pReply->PortFacts.u16ProtocolFlags = RT_BIT(3) | RT_BIT(0); /* SCSI initiator and LUN supported. */ - pReply->PortFacts.u16PortSCSIID = pLsiLogic->cPorts; + pReply->PortFacts.u16PortSCSIID = pThis->cPorts; pReply->PortFacts.u16MaxPersistentIDs = 0; pReply->PortFacts.u16MaxPostedCmdBuffers = 0; /* Only applies for target mode which we dont support. */ pReply->PortFacts.u16MaxLANBuckets = 0; /* Only for the LAN controller. */ } } else - AssertMsgFailed(("Invalid controller type %d\n", pLsiLogic->enmCtrlType)); + AssertMsgFailed(("Invalid controller type %d\n", pThis->enmCtrlType)); break; } case MPT_MESSAGE_HDR_FUNCTION_PORT_ENABLE: @@ -885,9 +1186,9 @@ static int lsilogicProcessMessageRequest(PLSILOGICSCSI pLsiLogic, PMptMessageHdr PMptEventNotificationRequest pEventNotificationReq = (PMptEventNotificationRequest)pMessageHdr; if (pEventNotificationReq->u8Switch) - pLsiLogic->fEventNotificationEnabled = true; + pThis->fEventNotificationEnabled = true; else - pLsiLogic->fEventNotificationEnabled = false; + pThis->fEventNotificationEnabled = false; pReply->EventNotification.u16EventDataLength = 1; /* 1 32bit D-Word. */ pReply->EventNotification.u8MessageLength = 8; @@ -895,7 +1196,7 @@ static int lsilogicProcessMessageRequest(PLSILOGICSCSI pLsiLogic, PMptMessageHdr pReply->EventNotification.u8AckRequired = 0; pReply->EventNotification.u32Event = MPT_EVENT_EVENT_CHANGE; pReply->EventNotification.u32EventContext = 0; - pReply->EventNotification.u32EventData = pLsiLogic->fEventNotificationEnabled ? 1 : 0; + pReply->EventNotification.u32EventData = pThis->fEventNotificationEnabled ? 1 : 0; break; } @@ -908,7 +1209,7 @@ static int lsilogicProcessMessageRequest(PLSILOGICSCSI pLsiLogic, PMptMessageHdr { PMptConfigurationRequest pConfigurationReq = (PMptConfigurationRequest)pMessageHdr; - rc = lsilogicProcessConfigurationRequest(pLsiLogic, pConfigurationReq, &pReply->Configuration); + rc = lsilogicR3ProcessConfigurationRequest(pThis, pConfigurationReq, &pReply->Configuration); AssertRC(rc); break; } @@ -926,6 +1227,7 @@ static int lsilogicProcessMessageRequest(PLSILOGICSCSI pLsiLogic, PMptMessageHdr //PMptFWDownloadRequest pFWDownloadReq = (PMptFWDownloadRequest)pMessageHdr; pReply->FWDownload.u8MessageLength = 5; + LogFlowFunc(("FW Download request issued\n")); break; } case MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST: /* Should be handled already. */ @@ -937,27 +1239,24 @@ static int lsilogicProcessMessageRequest(PLSILOGICSCSI pLsiLogic, PMptMessageHdr pReply->Header.u8Function = pMessageHdr->u8Function; pReply->Header.u32MessageContext = pMessageHdr->u32MessageContext; - lsilogicFinishAddressReply(pLsiLogic, pReply, fForceReplyPostFifo); + lsilogicFinishAddressReply(pThis, pReply, fForceReplyPostFifo); return rc; } -#endif + +#endif /* IN_RING3 */ /** * Writes a value to a register at a given offset. * * @returns VBox status code. - * @param pThis Pointer to the LsiLogic SCSI controller instance data. - * @param uOffset Offset of the register to write. - * @param pv Pointer to the value to write - * @param cb Number of bytes to write. + * @param pThis Pointer to the LsiLogic device state. + * @param offReg Offset of the register to write. + * @param u32 The value being written. */ -static int lsilogicRegisterWrite(PLSILOGICSCSI pThis, uint32_t uOffset, void const *pv, unsigned cb) +static int lsilogicRegisterWrite(PLSILOGICSCSI pThis, uint32_t offReg, uint32_t u32) { - uint32_t u32 = *(uint32_t *)pv; - - LogFlowFunc(("pThis=%#p uOffset=%#x pv=%#p{%.*Rhxs} cb=%u\n", pThis, uOffset, pv, cb, pv, cb)); - - switch (uOffset) + LogFlowFunc(("pThis=%#p offReg=%#x u32=%#x\n", pThis, offReg, u32)); + switch (offReg) { case LSILOGIC_REG_REPLY_QUEUE: { @@ -986,10 +1285,16 @@ static int lsilogicRegisterWrite(PLSILOGICSCSI pThis, uint32_t uOffset, void con /* Send notification to R3 if there is not one send already. */ if (!ASMAtomicXchgBool(&pThis->fNotificationSend, true)) { +#ifdef IN_RC PPDMQUEUEITEMCORE pNotificationItem = PDMQueueAlloc(pThis->CTX_SUFF(pNotificationQueue)); AssertPtr(pNotificationItem); PDMQueueInsert(pThis->CTX_SUFF(pNotificationQueue), pNotificationItem); +#else + LogFlowFunc(("Signal event semaphore\n")); + int rc = SUPSemEventSignal(pThis->pSupDrvSession, pThis->hEvtProcess); + AssertRC(rc); +#endif } break; } @@ -1002,14 +1307,20 @@ static int lsilogicRegisterWrite(PLSILOGICSCSI pThis, uint32_t uOffset, void con * The guest needs to wait with posting new messages here until the bit is cleared. * Because the guest is not continuing execution while we are here we can skip this. */ - if (!pThis->fDoorbellInProgress) + if (pThis->enmDoorbellState == LSILOGICDOORBELLSTATE_NOT_IN_USE) { uint32_t uFunction = LSILOGIC_REG_DOORBELL_GET_FUNCTION(u32); switch (uFunction) { + case LSILOGIC_DOORBELL_FUNCTION_IO_UNIT_RESET: case LSILOGIC_DOORBELL_FUNCTION_IOC_MSG_UNIT_RESET: { + /* + * The I/O unit reset does much more on real hardware like + * reloading the firmware, nothing we need to do here, + * so this is like the IOC message unit reset. + */ pThis->enmState = LSILOGICSTATE_RESET; /* Reset interrupt status. */ @@ -1023,12 +1334,10 @@ static int lsilogicRegisterWrite(PLSILOGICSCSI pThis, uint32_t uOffset, void con pThis->uReplyPostQueueNextAddressRead = 0; pThis->uRequestQueueNextEntryFreeWrite = 0; pThis->uRequestQueueNextAddressRead = 0; - pThis->enmState = LSILOGICSTATE_READY; - break; - } - case LSILOGIC_DOORBELL_FUNCTION_IO_UNIT_RESET: - { - AssertMsgFailed(("todo\n")); + + /* Only the IOC message unit reset transisionts to the ready state. */ + if (uFunction == LSILOGIC_DOORBELL_FUNCTION_IOC_MSG_UNIT_RESET) + pThis->enmState = LSILOGICSTATE_READY; break; } case LSILOGIC_DOORBELL_FUNCTION_HANDSHAKE: @@ -1037,21 +1346,23 @@ static int lsilogicRegisterWrite(PLSILOGICSCSI pThis, uint32_t uOffset, void con pThis->iMessage = 0; AssertMsg(pThis->cMessage <= RT_ELEMENTS(pThis->aMessage), ("Message doesn't fit into the buffer, cMessage=%u", pThis->cMessage)); - pThis->fDoorbellInProgress = true; + pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_FN_HANDSHAKE; /* Update the interrupt status to notify the guest that a doorbell function was started. */ lsilogicSetInterrupt(pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL); break; } case LSILOGIC_DOORBELL_FUNCTION_REPLY_FRAME_REMOVAL: { - AssertMsgFailed(("todo\n")); + pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_RFR_FRAME_COUNT_LOW; + /* Update the interrupt status to notify the guest that a doorbell function was started. */ + lsilogicSetInterrupt(pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL); break; } default: AssertMsgFailed(("Unknown function %u to perform\n", uFunction)); } } - else + else if (pThis->enmDoorbellState == LSILOGICDOORBELLSTATE_FN_HANDSHAKE) { /* * We are already performing a doorbell function. @@ -1070,7 +1381,7 @@ static int lsilogicRegisterWrite(PLSILOGICSCSI pThis, uint32_t uOffset, void con #ifdef IN_RING3 if (pThis->iMessage == pThis->cMessage) { - int rc = lsilogicProcessMessageRequest(pThis, (PMptMessageHdr)pThis->aMessage, &pThis->ReplyBuffer); + int rc = lsilogicR3ProcessMessageRequest(pThis, (PMptMessageHdr)pThis->aMessage, &pThis->ReplyBuffer); AssertRC(rc); } #endif @@ -1093,17 +1404,26 @@ static int lsilogicRegisterWrite(PLSILOGICSCSI pThis, uint32_t uOffset, void con * We do not use lsilogicSetInterrupt here because the interrupt status * is updated afterwards anyway. */ - if ( (pThis->fDoorbellInProgress) + if ( (pThis->enmDoorbellState == LSILOGICDOORBELLSTATE_FN_HANDSHAKE) && (pThis->cMessage == pThis->iMessage)) { if (pThis->uNextReplyEntryRead == pThis->cReplySize) { /* Reply finished. Reset doorbell in progress status. */ Log(("%s: Doorbell function finished\n", __FUNCTION__)); - pThis->fDoorbellInProgress = false; + pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_NOT_IN_USE; } ASMAtomicOrU32(&pThis->uInterruptStatus, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL); } + else if ( pThis->enmDoorbellState != LSILOGICDOORBELLSTATE_NOT_IN_USE + && pThis->enmDoorbellState != LSILOGICDOORBELLSTATE_FN_HANDSHAKE) + { + /* Reply frame removal, check whether the reply free queue is empty. */ + if ( pThis->uReplyFreeQueueNextAddressRead == pThis->uReplyFreeQueueNextEntryFreeWrite + && pThis->enmDoorbellState == LSILOGICDOORBELLSTATE_RFR_NEXT_FRAME_LOW) + pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_NOT_IN_USE; + ASMAtomicOrU32(&pThis->uInterruptStatus, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL); + } lsilogicUpdateInterrupt(pThis); break; @@ -1121,6 +1441,7 @@ static int lsilogicRegisterWrite(PLSILOGICSCSI pThis, uint32_t uOffset, void con /* Any value will cause a reset and disabling access. */ pThis->fDiagnosticEnabled = false; pThis->iDiagnosticAccess = 0; + pThis->fDiagRegsEnabled = false; } else if ((u32 & 0xf) == g_lsilogicDiagnosticAccess[pThis->iDiagnosticAccess]) { @@ -1143,15 +1464,42 @@ static int lsilogicRegisterWrite(PLSILOGICSCSI pThis, uint32_t uOffset, void con } case LSILOGIC_REG_HOST_DIAGNOSTIC: { + if (pThis->fDiagnosticEnabled) + { #ifndef IN_RING3 - return VINF_IOM_R3_IOPORT_WRITE; + return VINF_IOM_R3_MMIO_WRITE; #else - if (u32 & LSILOGIC_REG_HOST_DIAGNOSTIC_RESET_ADAPTER) + if (u32 & LSILOGIC_REG_HOST_DIAGNOSTIC_RESET_ADAPTER) + lsilogicR3HardReset(pThis); + else if (u32 & LSILOGIC_REG_HOST_DIAGNOSTIC_DIAG_RW_ENABLE) + pThis->fDiagRegsEnabled = true; +#endif + } + break; + } + case LSILOGIC_REG_DIAG_RW_DATA: + { + if (pThis->fDiagRegsEnabled) { - lsilogicHardReset(pThis); +#ifndef IN_RING3 + return VINF_IOM_R3_MMIO_WRITE; +#else + lsilogicR3DiagRegDataWrite(pThis, u32); +#endif } break; + } + case LSILOGIC_REG_DIAG_RW_ADDRESS: + { + if (pThis->fDiagRegsEnabled) + { +#ifndef IN_RING3 + return VINF_IOM_R3_MMIO_WRITE; +#else + lsilogicR3DiagRegAddressWrite(pThis, u32); #endif + } + break; } default: /* Ignore. */ { @@ -1165,28 +1513,21 @@ static int lsilogicRegisterWrite(PLSILOGICSCSI pThis, uint32_t uOffset, void con * Reads the content of a register at a given offset. * * @returns VBox status code. - * @param pThis Pointer to the LsiLogic SCSI controller instance data. - * @param uOffset Offset of the register to read. - * @param pv Where to store the content of the register. - * @param cb Number of bytes to read. + * @param pThis Pointer to the LsiLogic device state. + * @param offReg Offset of the register to read. + * @param pu32 Where to store the content of the register. */ -static int lsilogicRegisterRead(PLSILOGICSCSI pThis, uint32_t uOffset, void *pv, unsigned cb) +static int lsilogicRegisterRead(PLSILOGICSCSI pThis, uint32_t offReg, uint32_t *pu32) { int rc = VINF_SUCCESS; uint32_t u32 = 0; + Assert(!(offReg & 3)); /* Align to a 4 byte offset. */ - switch (uOffset & ~3) + switch (offReg) { case LSILOGIC_REG_REPLY_QUEUE: { - /* - * Non 4-byte access may cause real strange behavior because the data is part of a physical guest address. - * But some drivers use 1-byte access to scan for SCSI controllers. - */ - if (RT_UNLIKELY(cb != 4)) - LogFlowFunc((": cb is not 4 (%u)\n", cb)); - rc = PDMCritSectEnter(&pThis->ReplyPostQueueCritSect, VINF_IOM_R3_MMIO_READ); if (rc != VINF_SUCCESS) break; @@ -1215,23 +1556,61 @@ static int lsilogicRegisterRead(PLSILOGICSCSI pThis, uint32_t uOffset, void *pv, case LSILOGIC_REG_DOORBELL: { u32 = LSILOGIC_REG_DOORBELL_SET_STATE(pThis->enmState); - u32 |= LSILOGIC_REG_DOORBELL_SET_USED(pThis->fDoorbellInProgress); + u32 |= LSILOGIC_REG_DOORBELL_SET_USED(pThis->enmDoorbellState); u32 |= LSILOGIC_REG_DOORBELL_SET_WHOINIT(pThis->enmWhoInit); /* * If there is a doorbell function in progress we pass the return value * instead of the status code. We transfer 16bit of the reply * during one read. */ - if (pThis->fDoorbellInProgress) + switch (pThis->enmDoorbellState) { - /* Return next 16bit value. */ - u32 |= pThis->ReplyBuffer.au16Reply[pThis->uNextReplyEntryRead++]; - } - else - { - /* We return the status code of the I/O controller. */ - u32 |= pThis->u16IOCFaultCode; + case LSILOGICDOORBELLSTATE_NOT_IN_USE: + /* We return the status code of the I/O controller. */ + u32 |= pThis->u16IOCFaultCode; + break; + case LSILOGICDOORBELLSTATE_FN_HANDSHAKE: + /* Return next 16bit value. */ + u32 |= pThis->ReplyBuffer.au16Reply[pThis->uNextReplyEntryRead++]; + lsilogicSetInterrupt(pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL); + break; + case LSILOGICDOORBELLSTATE_RFR_FRAME_COUNT_LOW: + { + uint32_t cReplyFrames = lsilogicReplyFreeQueueGetFrameCount(pThis); + + u32 |= cReplyFrames & UINT32_C(0xffff); + pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_RFR_FRAME_COUNT_HIGH; + lsilogicSetInterrupt(pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL); + break; + } + case LSILOGICDOORBELLSTATE_RFR_FRAME_COUNT_HIGH: + { + uint32_t cReplyFrames = lsilogicReplyFreeQueueGetFrameCount(pThis); + + u32 |= cReplyFrames >> 16; + pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_RFR_NEXT_FRAME_LOW; + lsilogicSetInterrupt(pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL); + break; + } + case LSILOGICDOORBELLSTATE_RFR_NEXT_FRAME_LOW: + if (pThis->uReplyFreeQueueNextEntryFreeWrite != pThis->uReplyFreeQueueNextAddressRead) + { + u32 |= pThis->CTX_SUFF(pReplyFreeQueueBase)[pThis->uReplyFreeQueueNextAddressRead] & UINT32_C(0xffff); + pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_RFR_NEXT_FRAME_HIGH; + lsilogicSetInterrupt(pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL); + } + break; + case LSILOGICDOORBELLSTATE_RFR_NEXT_FRAME_HIGH: + u32 |= pThis->CTX_SUFF(pReplyFreeQueueBase)[pThis->uReplyFreeQueueNextAddressRead] >> 16; + pThis->uReplyFreeQueueNextAddressRead++; + pThis->uReplyFreeQueueNextAddressRead %= pThis->cReplyQueueEntries; + pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_RFR_NEXT_FRAME_LOW; + lsilogicSetInterrupt(pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL); + break; + default: + AssertMsgFailed(("Invalid doorbell state %d\n", pThis->enmDoorbellState)); } + break; } case LSILOGIC_REG_HOST_INTR_STATUS: @@ -1247,99 +1626,130 @@ static int lsilogicRegisterRead(PLSILOGICSCSI pThis, uint32_t uOffset, void *pv, case LSILOGIC_REG_HOST_DIAGNOSTIC: { if (pThis->fDiagnosticEnabled) - u32 = LSILOGIC_REG_HOST_DIAGNOSTIC_DRWE; - else - u32 = 0; + u32 |= LSILOGIC_REG_HOST_DIAGNOSTIC_DRWE; + if (pThis->fDiagRegsEnabled) + u32 |= LSILOGIC_REG_HOST_DIAGNOSTIC_DIAG_RW_ENABLE; break; } - case LSILOGIC_REG_TEST_BASE_ADDRESS: /* The spec doesn't say anything about these registers, so we just ignore them */ case LSILOGIC_REG_DIAG_RW_DATA: - case LSILOGIC_REG_DIAG_RW_ADDRESS: - default: /* Ignore. */ { - break; - } - } - - /* Clip data according to the read size. */ - switch (cb) - { - case 4: - { - *(uint32_t *)pv = u32; - break; + if (pThis->fDiagRegsEnabled) + { +#ifndef IN_RING3 + return VINF_IOM_R3_MMIO_READ; +#else + lsilogicR3DiagRegDataRead(pThis, &u32); +#endif + } } - case 2: + case LSILOGIC_REG_DIAG_RW_ADDRESS: { - uint8_t uBitsOff = (uOffset - (uOffset & 3))*8; - - u32 &= (0xffff << uBitsOff); - *(uint16_t *)pv = (uint16_t)(u32 >> uBitsOff); - break; + if (pThis->fDiagRegsEnabled) + { +#ifndef IN_RING3 + return VINF_IOM_R3_MMIO_READ; +#else + lsilogicR3DiagRegAddressRead(pThis, &u32); +#endif + } } - case 1: + case LSILOGIC_REG_TEST_BASE_ADDRESS: /* The spec doesn't say anything about these registers, so we just ignore them */ + default: /* Ignore. */ { - uint8_t uBitsOff = (uOffset - (uOffset & 3))*8; - - u32 &= (0xff << uBitsOff); - *(uint8_t *)pv = (uint8_t)(u32 >> uBitsOff); + /** @todo LSILOGIC_REG_DIAG_* should return all F's when accessed by MMIO. We + * return 0. Likely to apply to undefined offsets as well. */ break; } - default: - AssertMsgFailed(("Invalid access size %u\n", cb)); } - LogFlowFunc(("pThis=%#p uOffset=%#x pv=%#p{%.*Rhxs} cb=%u\n", pThis, uOffset, pv, cb, pv, cb)); - + *pu32 = u32; + LogFlowFunc(("pThis=%#p offReg=%#x u32=%#x\n", pThis, offReg, u32)); return rc; } -PDMBOTHCBDECL(int) lsilogicIOPortWrite (PPDMDEVINS pDevIns, void *pvUser, - RTIOPORT Port, uint32_t u32, unsigned cb) +/** + * @callback_method_impl{FNIOMIOPORTOUT} + */ +PDMBOTHCBDECL(int) lsilogicIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb) { - PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); - uint32_t uOffset = Port - pThis->IOPortBase; - - Assert(cb <= 4); + PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); + uint32_t offReg = Port - pThis->IOPortBase; + int rc; - int rc = lsilogicRegisterWrite(pThis, uOffset, &u32, cb); - if (rc == VINF_IOM_R3_MMIO_WRITE) - rc = VINF_IOM_R3_IOPORT_WRITE; + if (!(offReg & 3)) + { + rc = lsilogicRegisterWrite(pThis, offReg, u32); + if (rc == VINF_IOM_R3_MMIO_WRITE) + rc = VINF_IOM_R3_IOPORT_WRITE; + } + else + { + Log(("lsilogicIOPortWrite: Ignoring misaligned write - offReg=%#x u32=%#x cb=%#x\n", offReg, u32, cb)); + rc = VINF_SUCCESS; + } return rc; } -PDMBOTHCBDECL(int) lsilogicIOPortRead (PPDMDEVINS pDevIns, void *pvUser, - RTIOPORT Port, uint32_t *pu32, unsigned cb) +/** + * @callback_method_impl{FNIOMIOPORTIN} + */ +PDMBOTHCBDECL(int) lsilogicIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb) { - PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); - uint32_t uOffset = Port - pThis->IOPortBase; + PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); + uint32_t offReg = Port - pThis->IOPortBase; - Assert(cb <= 4); - - int rc = lsilogicRegisterRead(pThis, uOffset, pu32, cb); + int rc = lsilogicRegisterRead(pThis, offReg & ~(uint32_t)3, pu32); if (rc == VINF_IOM_R3_MMIO_READ) rc = VINF_IOM_R3_IOPORT_READ; return rc; } -PDMBOTHCBDECL(int) lsilogicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, - RTGCPHYS GCPhysAddr, void const *pv, unsigned cb) +/** + * @callback_method_impl{FNIOMMMIOWRITE} + */ +PDMBOTHCBDECL(int) lsilogicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb) { - PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); - uint32_t uOffset = GCPhysAddr - pThis->GCPhysMMIOBase; + PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); + uint32_t offReg = GCPhysAddr - pThis->GCPhysMMIOBase; + uint32_t u32; + int rc; + + /* See comments in lsilogicR3Map regarding size and alignment. */ + if (cb == 4) + u32 = *(uint32_t const *)pv; + else + { + if (cb > 4) + u32 = *(uint32_t const *)pv; + else if (cb >= 2) + u32 = *(uint16_t const *)pv; + else + u32 = *(uint8_t const *)pv; + Log(("lsilogicMMIOWrite: Non-DWORD write access - offReg=%#x u32=%#x cb=%#x\n", offReg, u32, cb)); + } - return lsilogicRegisterWrite(pThis, uOffset, pv, cb); + if (!(offReg & 3)) + rc = lsilogicRegisterWrite(pThis, offReg, u32); + else + { + Log(("lsilogicIOPortWrite: Ignoring misaligned write - offReg=%#x u32=%#x cb=%#x\n", offReg, u32, cb)); + rc = VINF_SUCCESS; + } + return rc; } -PDMBOTHCBDECL(int) lsilogicMMIORead(PPDMDEVINS pDevIns, void *pvUser, - RTGCPHYS GCPhysAddr, void *pv, unsigned cb) +/** + * @callback_method_impl{FNIOMMMIOREAD} + */ +PDMBOTHCBDECL(int) lsilogicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb) { - PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); - uint32_t uOffset = GCPhysAddr - pThis->GCPhysMMIOBase; + PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); + uint32_t offReg = GCPhysAddr - pThis->GCPhysMMIOBase; + Assert(!(offReg & 3)); Assert(cb == 4); - return lsilogicRegisterRead(pThis, uOffset, pv, cb); + return lsilogicRegisterRead(pThis, offReg, (uint32_t *)pv); } PDMBOTHCBDECL(int) lsilogicDiagnosticWrite(PPDMDEVINS pDevIns, void *pvUser, @@ -1364,545 +1774,320 @@ PDMBOTHCBDECL(int) lsilogicDiagnosticRead(PPDMDEVINS pDevIns, void *pvUser, #ifdef IN_RING3 +# ifdef LOG_ENABLED /** - * Copies a contiguous buffer into the scatter gather list provided by the guest. + * Dump an SG entry. * - * @returns nothing - * @param pTaskState Pointer to the task state which contains the SGL. - * @param pvBuf Pointer to the buffer to copy. - * @param cbCopy Number of bytes to copy. + * @returns nothing. + * @param pSGEntry Pointer to the SG entry to dump */ -static void lsilogicScatterGatherListCopyFromBuffer(PLSILOGICTASKSTATE pTaskState, void *pvBuf, size_t cbCopy) +static void lsilogicDumpSGEntry(PMptSGEntryUnion pSGEntry) { - unsigned cSGEntry = 0; - PRTSGSEG pSGEntry = &pTaskState->pSGListHead[cSGEntry]; - uint8_t *pu8Buf = (uint8_t *)pvBuf; - - while (cSGEntry < pTaskState->cSGListEntries) + if (LogIsEnabled()) { - size_t cbToCopy = (cbCopy < pSGEntry->cbSeg) ? cbCopy : pSGEntry->cbSeg; - - memcpy(pSGEntry->pvSeg, pu8Buf, cbToCopy); - - cbCopy -= cbToCopy; - /* We finished. */ - if (!cbCopy) - break; - - /* Advance the buffer. */ - pu8Buf += cbToCopy; + switch (pSGEntry->Simple32.u2ElementType) + { + case MPTSGENTRYTYPE_SIMPLE: + { + Log(("%s: Dumping info for SIMPLE SG entry:\n", __FUNCTION__)); + Log(("%s: u24Length=%u\n", __FUNCTION__, pSGEntry->Simple32.u24Length)); + Log(("%s: fEndOfList=%d\n", __FUNCTION__, pSGEntry->Simple32.fEndOfList)); + Log(("%s: f64BitAddress=%d\n", __FUNCTION__, pSGEntry->Simple32.f64BitAddress)); + Log(("%s: fBufferContainsData=%d\n", __FUNCTION__, pSGEntry->Simple32.fBufferContainsData)); + Log(("%s: fLocalAddress=%d\n", __FUNCTION__, pSGEntry->Simple32.fLocalAddress)); + Log(("%s: fEndOfBuffer=%d\n", __FUNCTION__, pSGEntry->Simple32.fEndOfBuffer)); + Log(("%s: fLastElement=%d\n", __FUNCTION__, pSGEntry->Simple32.fLastElement)); + Log(("%s: u32DataBufferAddressLow=%u\n", __FUNCTION__, pSGEntry->Simple32.u32DataBufferAddressLow)); + if (pSGEntry->Simple32.f64BitAddress) + { + Log(("%s: u32DataBufferAddressHigh=%u\n", __FUNCTION__, pSGEntry->Simple64.u32DataBufferAddressHigh)); + Log(("%s: GCDataBufferAddress=%RGp\n", __FUNCTION__, + ((uint64_t)pSGEntry->Simple64.u32DataBufferAddressHigh << 32) + | pSGEntry->Simple64.u32DataBufferAddressLow)); + } + else + Log(("%s: GCDataBufferAddress=%RGp\n", __FUNCTION__, pSGEntry->Simple32.u32DataBufferAddressLow)); - /* Go to the next entry in the list. */ - pSGEntry++; - cSGEntry++; + break; + } + case MPTSGENTRYTYPE_CHAIN: + { + Log(("%s: Dumping info for CHAIN SG entry:\n", __FUNCTION__)); + Log(("%s: u16Length=%u\n", __FUNCTION__, pSGEntry->Chain.u16Length)); + Log(("%s: u8NExtChainOffset=%d\n", __FUNCTION__, pSGEntry->Chain.u8NextChainOffset)); + Log(("%s: f64BitAddress=%d\n", __FUNCTION__, pSGEntry->Chain.f64BitAddress)); + Log(("%s: fLocalAddress=%d\n", __FUNCTION__, pSGEntry->Chain.fLocalAddress)); + Log(("%s: u32SegmentAddressLow=%u\n", __FUNCTION__, pSGEntry->Chain.u32SegmentAddressLow)); + Log(("%s: u32SegmentAddressHigh=%u\n", __FUNCTION__, pSGEntry->Chain.u32SegmentAddressHigh)); + if (pSGEntry->Chain.f64BitAddress) + Log(("%s: GCSegmentAddress=%RGp\n", __FUNCTION__, + ((uint64_t)pSGEntry->Chain.u32SegmentAddressHigh << 32) | pSGEntry->Chain.u32SegmentAddressLow)); + else + Log(("%s: GCSegmentAddress=%RGp\n", __FUNCTION__, pSGEntry->Chain.u32SegmentAddressLow)); + break; + } + } } } +# endif /* LOG_ENABLED */ /** - * Copy a temporary buffer into a part of the guest scatter gather list - * described by the given descriptor entry. + * Walks the guest S/G buffer calling the given copy worker for every buffer. * * @returns nothing. - * @param pDevIns Pointer to the device instance data. - * @param pSGInfo Pointer to the segment info structure which describes the guest segments - * to write to which are unaligned. + * @param pDevIns Device instance data. + * @param pLsiReq LSI request state. + * @param cbCopy How much bytes to copy. + * @param pfnIoBufCopy Copy worker to call. */ -static void lsilogicCopyFromBufferIntoSGList(PPDMDEVINS pDevIns, PLSILOGICTASKSTATESGENTRY pSGInfo) +static void lsilogicSgBufWalker(PPDMDEVINS pDevIns, PLSILOGICREQ pLsiReq, size_t cbCopy, + PFNLSILOGICIOBUFCOPY pfnIoBufCopy) { - RTGCPHYS GCPhysBuffer = pSGInfo->u.GCPhysAddrBufferUnaligned; + bool fEndOfList = false; + RTGCPHYS GCPhysSgEntryNext = pLsiReq->GCPhysSgStart; + RTGCPHYS GCPhysSegmentStart = pLsiReq->GCPhysSgStart; + uint32_t cChainOffsetNext = pLsiReq->cChainOffset; + uint8_t *pbBuf = (uint8_t *)pLsiReq->SegIoBuf.pvSeg; + + /* Go through the list until we reach the end. */ + while ( !fEndOfList + && cbCopy) + { + bool fEndOfSegment = false; - AssertMsg(!pSGInfo->fGuestMemory, ("This is not possible\n")); + while ( !fEndOfSegment + && cbCopy) + { + MptSGEntryUnion SGEntry; - /* Copy into SG entry. */ - PDMDevHlpPhysWrite(pDevIns, GCPhysBuffer, pSGInfo->pvBuf, pSGInfo->cbBuf); + Log(("%s: Reading SG entry from %RGp\n", __FUNCTION__, GCPhysSgEntryNext)); -} + /* Read the entry. */ + PDMDevHlpPhysRead(pDevIns, GCPhysSgEntryNext, &SGEntry, sizeof(MptSGEntryUnion)); -/** - * Copy a part of the guest scatter gather list into a temporary buffer. - * - * @returns nothing. - * @param pDevIns Pointer to the device instance data. - * @param pSGInfo Pointer to the segment info structure which describes the guest segments - * to read from which are unaligned. - */ -static void lsilogicCopyFromSGListIntoBuffer(PPDMDEVINS pDevIns, PLSILOGICTASKSTATESGENTRY pSGInfo) -{ - RTGCPHYS GCPhysBuffer = pSGInfo->u.GCPhysAddrBufferUnaligned; +# ifdef LOG_ENABLED + lsilogicDumpSGEntry(&SGEntry); +# endif - AssertMsg(!pSGInfo->fGuestMemory, ("This is not possible\n")); + AssertMsg(SGEntry.Simple32.u2ElementType == MPTSGENTRYTYPE_SIMPLE, ("Invalid SG entry type\n")); - /* Copy into temporary buffer. */ - PDMDevHlpPhysRead(pDevIns, GCPhysBuffer, pSGInfo->pvBuf, pSGInfo->cbBuf); -} + /* Check if this is a zero element and abort. */ + if ( !SGEntry.Simple32.u24Length + && SGEntry.Simple32.fEndOfList + && SGEntry.Simple32.fEndOfBuffer) + return; -static int lsilogicScatterGatherListAllocate(PLSILOGICTASKSTATE pTaskState, uint32_t cSGList, uint32_t cSGInfo, uint32_t cbUnaligned) -{ - if (pTaskState->cSGListSize < cSGList) - { - /* The entries are not allocated yet or the number is too small. */ - if (pTaskState->cSGListSize) - RTMemFree(pTaskState->pSGListHead); - - /* Allocate R3 scatter gather list. */ - pTaskState->pSGListHead = (PRTSGSEG)RTMemAllocZ(cSGList * sizeof(RTSGSEG)); - if (!pTaskState->pSGListHead) - return VERR_NO_MEMORY; - - /* Reset usage statistics. */ - pTaskState->cSGListSize = cSGList; - pTaskState->cSGListEntries = cSGList; - pTaskState->cSGListTooBig = 0; - } - else if (pTaskState->cSGListSize > cSGList) - { - /* - * The list is too big. Increment counter. - * So that the destroying function can free - * the list if it is too big too many times - * in a row. - */ - pTaskState->cSGListEntries = cSGList; - pTaskState->cSGListTooBig++; - } - else - { - /* - * Needed entries matches current size. - * Reset counter. - */ - pTaskState->cSGListEntries = cSGList; - pTaskState->cSGListTooBig = 0; - } + uint32_t cbCopyThis = SGEntry.Simple32.u24Length; + RTGCPHYS GCPhysAddrDataBuffer = SGEntry.Simple32.u32DataBufferAddressLow; - if (pTaskState->cSGInfoSize < cSGInfo) - { - /* The entries are not allocated yet or the number is too small. */ - if (pTaskState->cSGInfoSize) - RTMemFree(pTaskState->paSGEntries); - - pTaskState->paSGEntries = (PLSILOGICTASKSTATESGENTRY)RTMemAllocZ(cSGInfo * sizeof(LSILOGICTASKSTATESGENTRY)); - if (!pTaskState->paSGEntries) - return VERR_NO_MEMORY; - - /* Reset usage statistics. */ - pTaskState->cSGInfoSize = cSGInfo; - pTaskState->cSGInfoEntries = cSGInfo; - pTaskState->cSGInfoTooBig = 0; - } - else if (pTaskState->cSGInfoSize > cSGInfo) - { - /* - * The list is too big. Increment counter. - * So that the destroying function can free - * the list if it is too big too many times - * in a row. - */ - pTaskState->cSGInfoEntries = cSGInfo; - pTaskState->cSGInfoTooBig++; - } - else - { - /* - * Needed entries matches current size. - * Reset counter. - */ - pTaskState->cSGInfoEntries = cSGInfo; - pTaskState->cSGInfoTooBig = 0; - } + if (SGEntry.Simple32.f64BitAddress) + { + GCPhysAddrDataBuffer |= ((uint64_t)SGEntry.Simple64.u32DataBufferAddressHigh) << 32; + GCPhysSgEntryNext += sizeof(MptSGEntrySimple64); + } + else + GCPhysSgEntryNext += sizeof(MptSGEntrySimple32); - if (pTaskState->cbBufferUnaligned < cbUnaligned) - { - if (pTaskState->pvBufferUnaligned) - RTMemPageFree(pTaskState->pvBufferUnaligned, pTaskState->cbBufferUnaligned); + pfnIoBufCopy(pDevIns, GCPhysAddrDataBuffer, pbBuf, cbCopyThis); + pbBuf += cbCopyThis; + cbCopy -= cbCopyThis; - Log(("%s: Allocating buffer for unaligned segments cbUnaligned=%u\n", __FUNCTION__, cbUnaligned)); + /* Check if we reached the end of the list. */ + if (SGEntry.Simple32.fEndOfList) + { + /* We finished. */ + fEndOfSegment = true; + fEndOfList = true; + } + else if (SGEntry.Simple32.fLastElement) + fEndOfSegment = true; + } /* while (!fEndOfSegment) */ - pTaskState->pvBufferUnaligned = RTMemPageAlloc(cbUnaligned); - if (!pTaskState->pvBufferUnaligned) - return VERR_NO_MEMORY; + /* Get next chain element. */ + if (cChainOffsetNext) + { + MptSGEntryChain SGEntryChain; - pTaskState->cbBufferUnaligned = cbUnaligned; - } + PDMDevHlpPhysRead(pDevIns, GCPhysSegmentStart + cChainOffsetNext, &SGEntryChain, sizeof(MptSGEntryChain)); - /* Make debugging easier. */ -#ifdef DEBUG - memset(pTaskState->pSGListHead, 0, pTaskState->cSGListSize * sizeof(RTSGSEG)); - memset(pTaskState->paSGEntries, 0, pTaskState->cSGInfoSize * sizeof(LSILOGICTASKSTATESGENTRY)); - if (pTaskState->pvBufferUnaligned) - memset(pTaskState->pvBufferUnaligned, 0, pTaskState->cbBufferUnaligned); -#endif - return VINF_SUCCESS; + AssertMsg(SGEntryChain.u2ElementType == MPTSGENTRYTYPE_CHAIN, ("Invalid SG entry type\n")); + + /* Set the next address now. */ + GCPhysSgEntryNext = SGEntryChain.u32SegmentAddressLow; + if (SGEntryChain.f64BitAddress) + GCPhysSgEntryNext |= ((uint64_t)SGEntryChain.u32SegmentAddressHigh) << 32; + + GCPhysSegmentStart = GCPhysSgEntryNext; + cChainOffsetNext = SGEntryChain.u8NextChainOffset * sizeof(uint32_t); + } + } /* while (!fEndOfList) */ +} + +static DECLCALLBACK(void) lsilogicCopyFromGuest(PPDMDEVINS pDevIns, RTGCPHYS GCPhysIoBuf, + void *pvBuf, size_t cbCopy) +{ + PDMDevHlpPhysRead(pDevIns, GCPhysIoBuf, pvBuf, cbCopy); +} + +static DECLCALLBACK(void) lsilogicCopyToGuest(PPDMDEVINS pDevIns, RTGCPHYS GCPhysIoBuf, + void *pvBuf, size_t cbCopy) +{ + PDMDevHlpPCIPhysWrite(pDevIns, GCPhysIoBuf, pvBuf, cbCopy); } /** - * Destroy a scatter gather list. + * Copy from a guest S/G buffer to the I/O buffer. * * @returns nothing. - * @param pLsiLogic Pointer to the LsiLogic SCSI controller. - * @param pTaskState Pointer to the task state. + * @param pDevIns Device instance data. + * @param pLsiReq Request data. + * @param cbCopy How much to copy over. */ -static void lsilogicScatterGatherListDestroy(PLSILOGICSCSI pLsiLogic, PLSILOGICTASKSTATE pTaskState) +DECLINLINE(void) lsilogicCopyFromSgBuf(PPDMDEVINS pDevIns, PLSILOGICREQ pLsiReq, size_t cbCopy) { - PPDMDEVINS pDevIns = pLsiLogic->CTX_SUFF(pDevIns); - PLSILOGICTASKSTATESGENTRY pSGInfoCurr = pTaskState->paSGEntries; - - for (unsigned i = 0; i < pTaskState->cSGInfoEntries; i++) - { - if (pSGInfoCurr->fGuestMemory) - { - /* Release the lock. */ - PDMDevHlpPhysReleasePageMappingLock(pDevIns, &pSGInfoCurr->u.PageLock); - } - else if (!pSGInfoCurr->fBufferContainsData) - { - /* Copy the data into the guest segments now. */ - lsilogicCopyFromBufferIntoSGList(pLsiLogic->CTX_SUFF(pDevIns), pSGInfoCurr); - } - - pSGInfoCurr++; - } - - /* Free allocated memory if the list was too big too many times. */ - if (pTaskState->cSGListTooBig >= LSILOGIC_NR_OF_ALLOWED_BIGGER_LISTS) - lsilogicTaskStateClear(pTaskState); + lsilogicSgBufWalker(pDevIns, pLsiReq, cbCopy, lsilogicCopyFromGuest); } -#ifdef DEBUG /** - * Dump an SG entry. + * Copy from an I/O buffer to the guest S/G buffer. * * @returns nothing. - * @param pSGEntry Pointer to the SG entry to dump + * @param pDevIns Device instance data. + * @param pLsiReq Request data. + * @param cbCopy How much to copy over. */ -static void lsilogicDumpSGEntry(PMptSGEntryUnion pSGEntry) +DECLINLINE(void) lsilogicCopyToSgBuf(PPDMDEVINS pDevIns, PLSILOGICREQ pLsiReq, size_t cbCopy) { - switch (pSGEntry->Simple32.u2ElementType) - { - case MPTSGENTRYTYPE_SIMPLE: - { - Log(("%s: Dumping info for SIMPLE SG entry:\n", __FUNCTION__)); - Log(("%s: u24Length=%u\n", __FUNCTION__, pSGEntry->Simple32.u24Length)); - Log(("%s: fEndOfList=%d\n", __FUNCTION__, pSGEntry->Simple32.fEndOfList)); - Log(("%s: f64BitAddress=%d\n", __FUNCTION__, pSGEntry->Simple32.f64BitAddress)); - Log(("%s: fBufferContainsData=%d\n", __FUNCTION__, pSGEntry->Simple32.fBufferContainsData)); - Log(("%s: fLocalAddress=%d\n", __FUNCTION__, pSGEntry->Simple32.fLocalAddress)); - Log(("%s: fEndOfBuffer=%d\n", __FUNCTION__, pSGEntry->Simple32.fEndOfBuffer)); - Log(("%s: fLastElement=%d\n", __FUNCTION__, pSGEntry->Simple32.fLastElement)); - Log(("%s: u32DataBufferAddressLow=%u\n", __FUNCTION__, pSGEntry->Simple32.u32DataBufferAddressLow)); - if (pSGEntry->Simple32.f64BitAddress) - { - Log(("%s: u32DataBufferAddressHigh=%u\n", __FUNCTION__, pSGEntry->Simple64.u32DataBufferAddressHigh)); - Log(("%s: GCDataBufferAddress=%RGp\n", __FUNCTION__, - ((uint64_t)pSGEntry->Simple64.u32DataBufferAddressHigh << 32) | pSGEntry->Simple64.u32DataBufferAddressLow)); - } - else - Log(("%s: GCDataBufferAddress=%RGp\n", __FUNCTION__, pSGEntry->Simple32.u32DataBufferAddressLow)); - - break; - } - case MPTSGENTRYTYPE_CHAIN: - { - Log(("%s: Dumping info for CHAIN SG entry:\n", __FUNCTION__)); - Log(("%s: u16Length=%u\n", __FUNCTION__, pSGEntry->Chain.u16Length)); - Log(("%s: u8NExtChainOffset=%d\n", __FUNCTION__, pSGEntry->Chain.u8NextChainOffset)); - Log(("%s: f64BitAddress=%d\n", __FUNCTION__, pSGEntry->Chain.f64BitAddress)); - Log(("%s: fLocalAddress=%d\n", __FUNCTION__, pSGEntry->Chain.fLocalAddress)); - Log(("%s: u32SegmentAddressLow=%u\n", __FUNCTION__, pSGEntry->Chain.u32SegmentAddressLow)); - Log(("%s: u32SegmentAddressHigh=%u\n", __FUNCTION__, pSGEntry->Chain.u32SegmentAddressHigh)); - if (pSGEntry->Chain.f64BitAddress) - Log(("%s: GCSegmentAddress=%RGp\n", __FUNCTION__, - ((uint64_t)pSGEntry->Chain.u32SegmentAddressHigh << 32) | pSGEntry->Chain.u32SegmentAddressLow)); - else - Log(("%s: GCSegmentAddress=%RGp\n", __FUNCTION__, pSGEntry->Chain.u32SegmentAddressLow)); - break; - } - } + lsilogicSgBufWalker(pDevIns, pLsiReq, cbCopy, lsilogicCopyToGuest); } -#endif /** - * Create scatter gather list descriptors. + * Allocates memory for the given request using already allocated memory if possible. * - * @returns VBox status code. - * @param pLsiLogic Pointer to the LsiLogic SCSI controller. - * @param pTaskState Pointer to the task state. - * @param GCPhysSGLStart Guest physical address of the first SG entry. - * @param uChainOffset Offset in bytes from the beginning of the SGL segment to the chain element. - * @thread EMT + * @returns Pointer to the memory or NULL on failure + * @param pLsiReq The request to allocate memory for. + * @param cb The amount of memory to allocate. */ -static int lsilogicScatterGatherListCreate(PLSILOGICSCSI pLsiLogic, PLSILOGICTASKSTATE pTaskState, - RTGCPHYS GCPhysSGLStart, uint32_t uChainOffset) +static void *lsilogicReqMemAlloc(PLSILOGICREQ pLsiReq, size_t cb) { - int rc = VINF_SUCCESS; - PPDMDEVINS pDevIns = pLsiLogic->CTX_SUFF(pDevIns); - PVM pVM = PDMDevHlpGetVM(pDevIns); - bool fUnaligned; /* Flag whether the current buffer is unaligned. */ - uint32_t cbUnaligned; /* Size of the unaligned buffers. */ - uint32_t cSGEntriesR3 = 0; - uint32_t cSGInfo = 0; - uint32_t cbSegment = 0; - PLSILOGICTASKSTATESGENTRY pSGInfoCurr = NULL; - uint8_t *pu8BufferUnalignedPos = NULL; - uint8_t *pbBufferUnalignedSGInfoPos = NULL; - uint32_t cbUnalignedComplete = 0; - bool fDoMapping = false; - bool fEndOfList; - RTGCPHYS GCPhysSGEntryNext; - RTGCPHYS GCPhysSegmentStart; - uint32_t uChainOffsetNext; - - /* - * Two passes - one to count needed scatter gather list entries and needed unaligned - * buffers and one to actually map the SG list into R3. - */ - for (int i = 0; i < 2; i++) - { - fUnaligned = false; - cbUnaligned = 0; - fEndOfList = false; - - GCPhysSGEntryNext = GCPhysSGLStart; - uChainOffsetNext = uChainOffset; - GCPhysSegmentStart = GCPhysSGLStart; - - if (fDoMapping) - { - Log(("%s: cSGInfo=%u\n", __FUNCTION__, cSGInfo)); - - /* The number of needed SG entries in R3 is known. Allocate needed memory. */ - rc = lsilogicScatterGatherListAllocate(pTaskState, cSGInfo, cSGInfo, cbUnalignedComplete); - AssertMsgRC(rc, ("Failed to allocate scatter gather array rc=%Rrc\n", rc)); - - /* We are now able to map the pages into R3. */ - pSGInfoCurr = pTaskState->paSGEntries; - /* Initialize first segment to remove the need for additional if checks later in the code. */ - pSGInfoCurr->fGuestMemory= false; - pu8BufferUnalignedPos = (uint8_t *)pTaskState->pvBufferUnaligned; - pbBufferUnalignedSGInfoPos = pu8BufferUnalignedPos; - } - - /* Go through the list until we reach the end. */ - while (!fEndOfList) - { - bool fEndOfSegment = false; - - while (!fEndOfSegment) - { - MptSGEntryUnion SGEntry; - - Log(("%s: Reading SG entry from %RGp\n", __FUNCTION__, GCPhysSGEntryNext)); - - /* Read the entry. */ - PDMDevHlpPhysRead(pDevIns, GCPhysSGEntryNext, &SGEntry, sizeof(MptSGEntryUnion)); - -#ifdef DEBUG - lsilogicDumpSGEntry(&SGEntry); -#endif - - AssertMsg(SGEntry.Simple32.u2ElementType == MPTSGENTRYTYPE_SIMPLE, ("Invalid SG entry type\n")); - - /* Check if this is a zero element. */ - if ( !SGEntry.Simple32.u24Length - && SGEntry.Simple32.fEndOfList - && SGEntry.Simple32.fEndOfBuffer) - { - pTaskState->cSGListEntries = 0; - pTaskState->cSGInfoEntries = 0; - return VINF_SUCCESS; - } - - uint32_t cbDataToTransfer = SGEntry.Simple32.u24Length; - bool fBufferContainsData = !!SGEntry.Simple32.fBufferContainsData; - RTGCPHYS GCPhysAddrDataBuffer = SGEntry.Simple32.u32DataBufferAddressLow; - - if (SGEntry.Simple32.f64BitAddress) - { - GCPhysAddrDataBuffer |= ((uint64_t)SGEntry.Simple64.u32DataBufferAddressHigh) << 32; - GCPhysSGEntryNext += sizeof(MptSGEntrySimple64); - } - else - GCPhysSGEntryNext += sizeof(MptSGEntrySimple32); - - if (fDoMapping) - { - pSGInfoCurr->fGuestMemory = false; - pSGInfoCurr->fBufferContainsData = fBufferContainsData; - pSGInfoCurr->cbBuf = cbDataToTransfer; - pSGInfoCurr->pvBuf = pbBufferUnalignedSGInfoPos; - pbBufferUnalignedSGInfoPos += cbDataToTransfer; - pSGInfoCurr->u.GCPhysAddrBufferUnaligned = GCPhysAddrDataBuffer; - if (fBufferContainsData) - lsilogicCopyFromSGListIntoBuffer(pDevIns, pSGInfoCurr); - pSGInfoCurr++; - } - else - { - cbUnalignedComplete += cbDataToTransfer; - cSGInfo++; - } - - /* Check if we reached the end of the list. */ - if (SGEntry.Simple32.fEndOfList) - { - /* We finished. */ - fEndOfSegment = true; - fEndOfList = true; - } - else if (SGEntry.Simple32.fLastElement) - { - fEndOfSegment = true; - } - } /* while (!fEndOfSegment) */ - - /* Get next chain element. */ - if (uChainOffsetNext) - { - MptSGEntryChain SGEntryChain; - - PDMDevHlpPhysRead(pDevIns, GCPhysSegmentStart + uChainOffsetNext, &SGEntryChain, sizeof(MptSGEntryChain)); - - AssertMsg(SGEntryChain.u2ElementType == MPTSGENTRYTYPE_CHAIN, ("Invalid SG entry type\n")); - - /* Set the next address now. */ - GCPhysSGEntryNext = SGEntryChain.u32SegmentAddressLow; - if (SGEntryChain.f64BitAddress) - GCPhysSGEntryNext |= ((uint64_t)SGEntryChain.u32SegmentAddressHigh) << 32; - - GCPhysSegmentStart = GCPhysSGEntryNext; - uChainOffsetNext = SGEntryChain.u8NextChainOffset * sizeof(uint32_t); - } - - } /* while (!fEndOfList) */ - - fDoMapping = true; - if (fUnaligned) - cbUnalignedComplete += cbUnaligned; - } - - uint32_t cSGEntries; - PRTSGSEG pSGEntryCurr = pTaskState->pSGListHead; - pSGInfoCurr = pTaskState->paSGEntries; - - /* Initialize first entry. */ - pSGEntryCurr->pvSeg = pSGInfoCurr->pvBuf; - pSGEntryCurr->cbSeg = pSGInfoCurr->cbBuf; - pSGInfoCurr++; - cSGEntries = 1; - - /* Construct the scatter gather list. */ - for (unsigned i = 0; i < (pTaskState->cSGInfoEntries-1); i++) + if (pLsiReq->cbAlloc > cb) + pLsiReq->cAllocTooMuch++; + else if (pLsiReq->cbAlloc < cb) { - if (pSGEntryCurr->cbSeg % 512 != 0) - { - AssertMsg((uint8_t *)pSGEntryCurr->pvSeg + pSGEntryCurr->cbSeg == pSGInfoCurr->pvBuf, - ("Buffer ist not sector aligned but the buffer addresses are not adjacent\n")); - - pSGEntryCurr->cbSeg += pSGInfoCurr->cbBuf; - } - else - { - if (((uint8_t *)pSGEntryCurr->pvSeg + pSGEntryCurr->cbSeg) == pSGInfoCurr->pvBuf) - { - pSGEntryCurr->cbSeg += pSGInfoCurr->cbBuf; - } - else - { - pSGEntryCurr++; - cSGEntries++; - pSGEntryCurr->pvSeg = pSGInfoCurr->pvBuf; - pSGEntryCurr->cbSeg = pSGInfoCurr->cbBuf; - } - } - - pSGInfoCurr++; + if (pLsiReq->cbAlloc) + RTMemPageFree(pLsiReq->pvAlloc, pLsiReq->cbAlloc); + + pLsiReq->cbAlloc = RT_ALIGN_Z(cb, _4K); + pLsiReq->pvAlloc = RTMemPageAlloc(pLsiReq->cbAlloc); + pLsiReq->cAllocTooMuch = 0; + if (RT_UNLIKELY(!pLsiReq->pvAlloc)) + pLsiReq->cbAlloc = 0; } - pTaskState->cSGListEntries = cSGEntries; - - return rc; + return pLsiReq->pvAlloc; } -/* - * Disabled because the sense buffer provided by the LsiLogic driver for Windows XP - * crosses page boundaries. - */ -#if 0 /** - * Free the sense buffer. + * Frees memory allocated for the given request. * * @returns nothing. - * @param pTaskState Pointer to the task state. + * @param pLsiReq The request. */ -static void lsilogicFreeGCSenseBuffer(PLSILOGICSCSI pLsiLogic, PLSILOGICTASKSTATE pTaskState) +static void lsilogicReqMemFree(PLSILOGICREQ pLsiReq) { - PVM pVM = PDMDevHlpGetVM(pLsiLogic->CTX_SUFF(pDevIns)); - - PGMPhysReleasePageMappingLock(pVM, &pTaskState->PageLockSense); - pTaskState->pbSenseBuffer = NULL; + if (pLsiReq->cAllocTooMuch >= LSILOGIC_MAX_ALLOC_TOO_MUCH) + { + RTMemPageFree(pLsiReq->pvAlloc, pLsiReq->cbAlloc); + pLsiReq->cbAlloc = 0; + pLsiReq->cAllocTooMuch = 0; + } } /** - * Map the sense buffer into R3. + * Allocate I/O memory and copies the guest buffer for writes. * * @returns VBox status code. - * @param pTaskState Pointer to the task state. - * @note Current assumption is that the sense buffer is not scattered and does not cross a page boundary. + * @param pDevIns The device instance. + * @param pLsiReq The request state. + * @param cbTransfer Amount of bytes to allocate. */ -static int lsilogicMapGCSenseBufferIntoR3(PLSILOGICSCSI pLsiLogic, PLSILOGICTASKSTATE pTaskState) +static int lsilogicIoBufAllocate(PPDMDEVINS pDevIns, PLSILOGICREQ pLsiReq, + size_t cbTransfer) { - int rc = VINF_SUCCESS; - PPDMDEVINS pDevIns = pLsiLogic->CTX_SUFF(pDevIns); - RTGCPHYS GCPhysAddrSenseBuffer; + uint8_t uTxDir = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_GET(pLsiReq->GuestRequest.SCSIIO.u32Control); - GCPhysAddrSenseBuffer = pTaskState->GuestRequest.SCSIIO.u32SenseBufferLowAddress; - GCPhysAddrSenseBuffer |= ((uint64_t)pLsiLogic->u32SenseBufferHighAddr << 32); + AssertMsg( uTxDir == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE + || uTxDir == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ + || uTxDir == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_NONE, + ("Allocating I/O memory for a non I/O request is not allowed\n")); -#ifdef RT_STRICT - uint32_t cbSenseBuffer = pTaskState->GuestRequest.SCSIIO.u8SenseBufferLength; -#endif - RTGCPHYS GCPhysAddrSenseBufferBase = PAGE_ADDRESS(GCPhysAddrSenseBuffer); + pLsiReq->SegIoBuf.pvSeg = lsilogicReqMemAlloc(pLsiReq, cbTransfer); + if (!pLsiReq->SegIoBuf.pvSeg) + return VERR_NO_MEMORY; - AssertMsg(GCPhysAddrSenseBuffer >= GCPhysAddrSenseBufferBase, - ("Impossible GCPhysAddrSenseBuffer < GCPhysAddrSenseBufferBase\n")); + pLsiReq->SegIoBuf.cbSeg = cbTransfer; + if ( uTxDir == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE + || uTxDir == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_NONE) + lsilogicCopyFromSgBuf(pDevIns, pLsiReq, cbTransfer); - /* Sanity checks for the assumption. */ - AssertMsg(((GCPhysAddrSenseBuffer + cbSenseBuffer) <= (GCPhysAddrSenseBufferBase + PAGE_SIZE)), - ("Sense buffer crosses page boundary\n")); + return VINF_SUCCESS; +} - rc = PDMDevHlpPhysGCPhys2CCPtr(pDevIns, GCPhysAddrSenseBufferBase, (void **)&pTaskState->pbSenseBuffer, &pTaskState->PageLockSense); - AssertMsgRC(rc, ("Mapping sense buffer failed rc=%Rrc\n", rc)); +/** + * Frees the I/O memory of the given request and updates the guest buffer if necessary. + * + * @returns nothing. + * @param pDevIns The device instance. + * @param pLsiReq The request state. + * @param fCopyToGuest Flag whether to update the guest buffer if necessary. + * Nothing is copied if false even if the request was a read. + */ +static void lsilogicIoBufFree(PPDMDEVINS pDevIns, PLSILOGICREQ pLsiReq, + bool fCopyToGuest) +{ + uint8_t uTxDir = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_GET(pLsiReq->GuestRequest.SCSIIO.u32Control); - /* Correct start address of the sense buffer. */ - pTaskState->pbSenseBuffer += (GCPhysAddrSenseBuffer - GCPhysAddrSenseBufferBase); + AssertMsg( uTxDir == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE + || uTxDir == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ + || uTxDir == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_NONE, + ("Allocating I/O memory for a non I/O request is not allowed\n")); - return rc; + if ( ( uTxDir == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ + || uTxDir == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_NONE) + && fCopyToGuest) + lsilogicCopyToSgBuf(pDevIns, pLsiReq, pLsiReq->SegIoBuf.cbSeg); + + lsilogicReqMemFree(pLsiReq); + pLsiReq->SegIoBuf.pvSeg = NULL; + pLsiReq->SegIoBuf.cbSeg = 0; } -#endif -#ifdef DEBUG -static void lsilogicDumpSCSIIORequest(PMptSCSIIORequest pSCSIIORequest) +# ifdef LOG_ENABLED +static void lsilogicR3DumpSCSIIORequest(PMptSCSIIORequest pSCSIIORequest) { - Log(("%s: u8TargetID=%d\n", __FUNCTION__, pSCSIIORequest->u8TargetID)); - Log(("%s: u8Bus=%d\n", __FUNCTION__, pSCSIIORequest->u8Bus)); - Log(("%s: u8ChainOffset=%d\n", __FUNCTION__, pSCSIIORequest->u8ChainOffset)); - Log(("%s: u8Function=%d\n", __FUNCTION__, pSCSIIORequest->u8Function)); - Log(("%s: u8CDBLength=%d\n", __FUNCTION__, pSCSIIORequest->u8CDBLength)); - Log(("%s: u8SenseBufferLength=%d\n", __FUNCTION__, pSCSIIORequest->u8SenseBufferLength)); - Log(("%s: u8MessageFlags=%d\n", __FUNCTION__, pSCSIIORequest->u8MessageFlags)); - Log(("%s: u32MessageContext=%#x\n", __FUNCTION__, pSCSIIORequest->u32MessageContext)); - for (unsigned i = 0; i < RT_ELEMENTS(pSCSIIORequest->au8LUN); i++) - Log(("%s: u8LUN[%d]=%d\n", __FUNCTION__, i, pSCSIIORequest->au8LUN[i])); - Log(("%s: u32Control=%#x\n", __FUNCTION__, pSCSIIORequest->u32Control)); - for (unsigned i = 0; i < RT_ELEMENTS(pSCSIIORequest->au8CDB); i++) - Log(("%s: u8CDB[%d]=%d\n", __FUNCTION__, i, pSCSIIORequest->au8CDB[i])); - Log(("%s: u32DataLength=%#x\n", __FUNCTION__, pSCSIIORequest->u32DataLength)); - Log(("%s: u32SenseBufferLowAddress=%#x\n", __FUNCTION__, pSCSIIORequest->u32SenseBufferLowAddress)); + if (LogIsEnabled()) + { + Log(("%s: u8TargetID=%d\n", __FUNCTION__, pSCSIIORequest->u8TargetID)); + Log(("%s: u8Bus=%d\n", __FUNCTION__, pSCSIIORequest->u8Bus)); + Log(("%s: u8ChainOffset=%d\n", __FUNCTION__, pSCSIIORequest->u8ChainOffset)); + Log(("%s: u8Function=%d\n", __FUNCTION__, pSCSIIORequest->u8Function)); + Log(("%s: u8CDBLength=%d\n", __FUNCTION__, pSCSIIORequest->u8CDBLength)); + Log(("%s: u8SenseBufferLength=%d\n", __FUNCTION__, pSCSIIORequest->u8SenseBufferLength)); + Log(("%s: u8MessageFlags=%d\n", __FUNCTION__, pSCSIIORequest->u8MessageFlags)); + Log(("%s: u32MessageContext=%#x\n", __FUNCTION__, pSCSIIORequest->u32MessageContext)); + for (unsigned i = 0; i < RT_ELEMENTS(pSCSIIORequest->au8LUN); i++) + Log(("%s: u8LUN[%d]=%d\n", __FUNCTION__, i, pSCSIIORequest->au8LUN[i])); + Log(("%s: u32Control=%#x\n", __FUNCTION__, pSCSIIORequest->u32Control)); + for (unsigned i = 0; i < RT_ELEMENTS(pSCSIIORequest->au8CDB); i++) + Log(("%s: u8CDB[%d]=%d\n", __FUNCTION__, i, pSCSIIORequest->au8CDB[i])); + Log(("%s: u32DataLength=%#x\n", __FUNCTION__, pSCSIIORequest->u32DataLength)); + Log(("%s: u32SenseBufferLowAddress=%#x\n", __FUNCTION__, pSCSIIORequest->u32SenseBufferLowAddress)); + } } -#endif +# endif -static void lsilogicWarningDiskFull(PPDMDEVINS pDevIns) +static void lsilogicR3WarningDiskFull(PPDMDEVINS pDevIns) { int rc; LogRel(("LsiLogic#%d: Host disk full\n", pDevIns->iInstance)); @@ -1911,7 +2096,7 @@ static void lsilogicWarningDiskFull(PPDMDEVINS pDevIns) AssertRC(rc); } -static void lsilogicWarningFileTooBig(PPDMDEVINS pDevIns) +static void lsilogicR3WarningFileTooBig(PPDMDEVINS pDevIns) { int rc; LogRel(("LsiLogic#%d: File too big\n", pDevIns->iInstance)); @@ -1920,7 +2105,7 @@ static void lsilogicWarningFileTooBig(PPDMDEVINS pDevIns) AssertRC(rc); } -static void lsilogicWarningISCSI(PPDMDEVINS pDevIns) +static void lsilogicR3WarningISCSI(PPDMDEVINS pDevIns) { int rc; LogRel(("LsiLogic#%d: iSCSI target unavailable\n", pDevIns->iInstance)); @@ -1929,7 +2114,7 @@ static void lsilogicWarningISCSI(PPDMDEVINS pDevIns) AssertRC(rc); } -static void lsilogicWarningUnknown(PPDMDEVINS pDevIns, int rc) +static void lsilogicR3WarningUnknown(PPDMDEVINS pDevIns, int rc) { int rc2; LogRel(("LsiLogic#%d: Unknown but recoverable error has occurred (rc=%Rrc)\n", pDevIns->iInstance, rc)); @@ -1938,20 +2123,20 @@ static void lsilogicWarningUnknown(PPDMDEVINS pDevIns, int rc) AssertRC(rc2); } -static void lsilogicRedoSetWarning(PLSILOGICSCSI pThis, int rc) +static void lsilogicR3RedoSetWarning(PLSILOGICSCSI pThis, int rc) { if (rc == VERR_DISK_FULL) - lsilogicWarningDiskFull(pThis->CTX_SUFF(pDevIns)); + lsilogicR3WarningDiskFull(pThis->CTX_SUFF(pDevIns)); else if (rc == VERR_FILE_TOO_BIG) - lsilogicWarningFileTooBig(pThis->CTX_SUFF(pDevIns)); + lsilogicR3WarningFileTooBig(pThis->CTX_SUFF(pDevIns)); else if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED) { /* iSCSI connection abort (first error) or failure to reestablish * connection (second error). Pause VM. On resume we'll retry. */ - lsilogicWarningISCSI(pThis->CTX_SUFF(pDevIns)); + lsilogicR3WarningISCSI(pThis->CTX_SUFF(pDevIns)); } else - lsilogicWarningUnknown(pThis->CTX_SUFF(pDevIns), rc); + lsilogicR3WarningUnknown(pThis->CTX_SUFF(pDevIns), rc); } /** @@ -1962,216 +2147,223 @@ static void lsilogicRedoSetWarning(PLSILOGICSCSI pThis, int rc) * the request. * * @returns VBox status code. - * @param pLsiLogic Pointer to the device instance which sends the request. - * @param pTaskState Pointer to the task state data. + * @param pThis Pointer to the LsiLogic device state. + * @param pLsiReq Pointer to the task state data. */ -static int lsilogicProcessSCSIIORequest(PLSILOGICSCSI pLsiLogic, PLSILOGICTASKSTATE pTaskState) +static int lsilogicR3ProcessSCSIIORequest(PLSILOGICSCSI pThis, PLSILOGICREQ pLsiReq) { int rc = VINF_SUCCESS; -#ifdef DEBUG - lsilogicDumpSCSIIORequest(&pTaskState->GuestRequest.SCSIIO); -#endif +# ifdef LOG_ENABLED + lsilogicR3DumpSCSIIORequest(&pLsiReq->GuestRequest.SCSIIO); +# endif - pTaskState->fBIOS = false; + pLsiReq->fBIOS = false; + pLsiReq->GCPhysSgStart = pLsiReq->GCPhysMessageFrameAddr + sizeof(MptSCSIIORequest); + pLsiReq->cChainOffset = pLsiReq->GuestRequest.SCSIIO.u8ChainOffset; + if (pLsiReq->cChainOffset) + pLsiReq->cChainOffset = pLsiReq->cChainOffset * sizeof(uint32_t) - sizeof(MptSCSIIORequest); - if (RT_LIKELY( (pTaskState->GuestRequest.SCSIIO.u8TargetID < pLsiLogic->cDeviceStates) - && (pTaskState->GuestRequest.SCSIIO.u8Bus == 0))) + if (RT_LIKELY( (pLsiReq->GuestRequest.SCSIIO.u8TargetID < pThis->cDeviceStates) + && (pLsiReq->GuestRequest.SCSIIO.u8Bus == 0))) { PLSILOGICDEVICE pTargetDevice; - pTargetDevice = &pLsiLogic->paDeviceStates[pTaskState->GuestRequest.SCSIIO.u8TargetID]; + pTargetDevice = &pThis->paDeviceStates[pLsiReq->GuestRequest.SCSIIO.u8TargetID]; if (pTargetDevice->pDrvBase) { - uint32_t uChainOffset; - - /* Create Scatter gather list. */ - uChainOffset = pTaskState->GuestRequest.SCSIIO.u8ChainOffset; - if (uChainOffset) - uChainOffset = uChainOffset * sizeof(uint32_t) - sizeof(MptSCSIIORequest); - - rc = lsilogicScatterGatherListCreate(pLsiLogic, pTaskState, - pTaskState->GCPhysMessageFrameAddr + sizeof(MptSCSIIORequest), - uChainOffset); - AssertRC(rc); + if (pLsiReq->GuestRequest.SCSIIO.u32DataLength) + { -#if 0 - /* Map sense buffer. */ - rc = lsilogicMapGCSenseBufferIntoR3(pLsiLogic, pTaskState); - AssertRC(rc); -#endif + rc = lsilogicIoBufAllocate(pThis->CTX_SUFF(pDevIns), pLsiReq, + pLsiReq->GuestRequest.SCSIIO.u32DataLength); + AssertRC(rc); /** @todo: Insufficient resources error. */ + } /* Setup the SCSI request. */ - pTaskState->pTargetDevice = pTargetDevice; - pTaskState->PDMScsiRequest.uLogicalUnit = pTaskState->GuestRequest.SCSIIO.au8LUN[1]; + pLsiReq->pTargetDevice = pTargetDevice; + pLsiReq->PDMScsiRequest.uLogicalUnit = pLsiReq->GuestRequest.SCSIIO.au8LUN[1]; - uint8_t uDataDirection = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_GET(pTaskState->GuestRequest.SCSIIO.u32Control); + uint8_t uDataDirection = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_GET(pLsiReq->GuestRequest.SCSIIO.u32Control); if (uDataDirection == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_NONE) - pTaskState->PDMScsiRequest.uDataDirection = PDMSCSIREQUESTTXDIR_NONE; + pLsiReq->PDMScsiRequest.uDataDirection = PDMSCSIREQUESTTXDIR_NONE; else if (uDataDirection == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE) - pTaskState->PDMScsiRequest.uDataDirection = PDMSCSIREQUESTTXDIR_TO_DEVICE; + pLsiReq->PDMScsiRequest.uDataDirection = PDMSCSIREQUESTTXDIR_TO_DEVICE; else if (uDataDirection == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ) - pTaskState->PDMScsiRequest.uDataDirection = PDMSCSIREQUESTTXDIR_FROM_DEVICE; - - pTaskState->PDMScsiRequest.cbCDB = pTaskState->GuestRequest.SCSIIO.u8CDBLength; - pTaskState->PDMScsiRequest.pbCDB = pTaskState->GuestRequest.SCSIIO.au8CDB; - pTaskState->PDMScsiRequest.cbScatterGather = pTaskState->GuestRequest.SCSIIO.u32DataLength; - pTaskState->PDMScsiRequest.cScatterGatherEntries = pTaskState->cSGListEntries; - pTaskState->PDMScsiRequest.paScatterGatherHead = pTaskState->pSGListHead; - pTaskState->PDMScsiRequest.cbSenseBuffer = sizeof(pTaskState->abSenseBuffer); - memset(pTaskState->abSenseBuffer, 0, pTaskState->PDMScsiRequest.cbSenseBuffer); - pTaskState->PDMScsiRequest.pbSenseBuffer = pTaskState->abSenseBuffer; - pTaskState->PDMScsiRequest.pvUser = pTaskState; + pLsiReq->PDMScsiRequest.uDataDirection = PDMSCSIREQUESTTXDIR_FROM_DEVICE; + + pLsiReq->PDMScsiRequest.cbCDB = pLsiReq->GuestRequest.SCSIIO.u8CDBLength; + pLsiReq->PDMScsiRequest.pbCDB = pLsiReq->GuestRequest.SCSIIO.au8CDB; + pLsiReq->PDMScsiRequest.cbScatterGather = pLsiReq->GuestRequest.SCSIIO.u32DataLength; + if (pLsiReq->PDMScsiRequest.cbScatterGather) + { + pLsiReq->PDMScsiRequest.cScatterGatherEntries = 1; + pLsiReq->PDMScsiRequest.paScatterGatherHead = &pLsiReq->SegIoBuf; + } + else + { + pLsiReq->PDMScsiRequest.cScatterGatherEntries = 0; + pLsiReq->PDMScsiRequest.paScatterGatherHead = NULL; + } + pLsiReq->PDMScsiRequest.cbSenseBuffer = sizeof(pLsiReq->abSenseBuffer); + memset(pLsiReq->abSenseBuffer, 0, pLsiReq->PDMScsiRequest.cbSenseBuffer); + pLsiReq->PDMScsiRequest.pbSenseBuffer = pLsiReq->abSenseBuffer; + pLsiReq->PDMScsiRequest.pvUser = pLsiReq; ASMAtomicIncU32(&pTargetDevice->cOutstandingRequests); - rc = pTargetDevice->pDrvSCSIConnector->pfnSCSIRequestSend(pTargetDevice->pDrvSCSIConnector, &pTaskState->PDMScsiRequest); + rc = pTargetDevice->pDrvSCSIConnector->pfnSCSIRequestSend(pTargetDevice->pDrvSCSIConnector, &pLsiReq->PDMScsiRequest); AssertMsgRC(rc, ("Sending request to SCSI layer failed rc=%Rrc\n", rc)); return VINF_SUCCESS; } else { /* Device is not present report SCSI selection timeout. */ - pTaskState->IOCReply.SCSIIOError.u16IOCStatus = MPT_SCSI_IO_ERROR_IOCSTATUS_DEVICE_NOT_THERE; + pLsiReq->IOCReply.SCSIIOError.u16IOCStatus = MPT_SCSI_IO_ERROR_IOCSTATUS_DEVICE_NOT_THERE; } } else { /* Report out of bounds target ID or bus. */ - if (pTaskState->GuestRequest.SCSIIO.u8Bus != 0) - pTaskState->IOCReply.SCSIIOError.u16IOCStatus = MPT_SCSI_IO_ERROR_IOCSTATUS_INVALID_BUS; + if (pLsiReq->GuestRequest.SCSIIO.u8Bus != 0) + pLsiReq->IOCReply.SCSIIOError.u16IOCStatus = MPT_SCSI_IO_ERROR_IOCSTATUS_INVALID_BUS; else - pTaskState->IOCReply.SCSIIOError.u16IOCStatus = MPT_SCSI_IO_ERROR_IOCSTATUS_INVALID_TARGETID; + pLsiReq->IOCReply.SCSIIOError.u16IOCStatus = MPT_SCSI_IO_ERROR_IOCSTATUS_INVALID_TARGETID; } static int g_cLogged = 0; if (g_cLogged++ < MAX_REL_LOG_ERRORS) { - LogRel(("LsiLogic#%d: %d/%d (Bus/Target) doesn't exist\n", pLsiLogic->CTX_SUFF(pDevIns)->iInstance, - pTaskState->GuestRequest.SCSIIO.u8TargetID, pTaskState->GuestRequest.SCSIIO.u8Bus)); + LogRel(("LsiLogic#%d: %d/%d (Bus/Target) doesn't exist\n", pThis->CTX_SUFF(pDevIns)->iInstance, + pLsiReq->GuestRequest.SCSIIO.u8TargetID, pLsiReq->GuestRequest.SCSIIO.u8Bus)); /* Log the CDB too */ LogRel(("LsiLogic#%d: Guest issued CDB {%#x", - pLsiLogic->CTX_SUFF(pDevIns)->iInstance, pTaskState->GuestRequest.SCSIIO.au8CDB[0])); - for (unsigned i = 1; i < pTaskState->GuestRequest.SCSIIO.u8CDBLength; i++) - LogRel((", %#x", pTaskState->GuestRequest.SCSIIO.au8CDB[i])); + pThis->CTX_SUFF(pDevIns)->iInstance, pLsiReq->GuestRequest.SCSIIO.au8CDB[0])); + for (unsigned i = 1; i < pLsiReq->GuestRequest.SCSIIO.u8CDBLength; i++) + LogRel((", %#x", pLsiReq->GuestRequest.SCSIIO.au8CDB[i])); LogRel(("}\n")); } /* The rest is equal to both errors. */ - pTaskState->IOCReply.SCSIIOError.u8TargetID = pTaskState->GuestRequest.SCSIIO.u8TargetID; - pTaskState->IOCReply.SCSIIOError.u8Bus = pTaskState->GuestRequest.SCSIIO.u8Bus; - pTaskState->IOCReply.SCSIIOError.u8MessageLength = sizeof(MptSCSIIOErrorReply) / 4; - pTaskState->IOCReply.SCSIIOError.u8Function = pTaskState->GuestRequest.SCSIIO.u8Function; - pTaskState->IOCReply.SCSIIOError.u8CDBLength = pTaskState->GuestRequest.SCSIIO.u8CDBLength; - pTaskState->IOCReply.SCSIIOError.u8SenseBufferLength = pTaskState->GuestRequest.SCSIIO.u8SenseBufferLength; - pTaskState->IOCReply.SCSIIOError.u32MessageContext = pTaskState->GuestRequest.SCSIIO.u32MessageContext; - pTaskState->IOCReply.SCSIIOError.u8SCSIStatus = SCSI_STATUS_OK; - pTaskState->IOCReply.SCSIIOError.u8SCSIState = MPT_SCSI_IO_ERROR_SCSI_STATE_TERMINATED; - pTaskState->IOCReply.SCSIIOError.u32IOCLogInfo = 0; - pTaskState->IOCReply.SCSIIOError.u32TransferCount = 0; - pTaskState->IOCReply.SCSIIOError.u32SenseCount = 0; - pTaskState->IOCReply.SCSIIOError.u32ResponseInfo = 0; - - lsilogicFinishAddressReply(pLsiLogic, &pTaskState->IOCReply, false); - RTMemCacheFree(pLsiLogic->hTaskCache, pTaskState); + pLsiReq->IOCReply.SCSIIOError.u8TargetID = pLsiReq->GuestRequest.SCSIIO.u8TargetID; + pLsiReq->IOCReply.SCSIIOError.u8Bus = pLsiReq->GuestRequest.SCSIIO.u8Bus; + pLsiReq->IOCReply.SCSIIOError.u8MessageLength = sizeof(MptSCSIIOErrorReply) / 4; + pLsiReq->IOCReply.SCSIIOError.u8Function = pLsiReq->GuestRequest.SCSIIO.u8Function; + pLsiReq->IOCReply.SCSIIOError.u8CDBLength = pLsiReq->GuestRequest.SCSIIO.u8CDBLength; + pLsiReq->IOCReply.SCSIIOError.u8SenseBufferLength = pLsiReq->GuestRequest.SCSIIO.u8SenseBufferLength; + pLsiReq->IOCReply.SCSIIOError.u32MessageContext = pLsiReq->GuestRequest.SCSIIO.u32MessageContext; + pLsiReq->IOCReply.SCSIIOError.u8SCSIStatus = SCSI_STATUS_OK; + pLsiReq->IOCReply.SCSIIOError.u8SCSIState = MPT_SCSI_IO_ERROR_SCSI_STATE_TERMINATED; + pLsiReq->IOCReply.SCSIIOError.u32IOCLogInfo = 0; + pLsiReq->IOCReply.SCSIIOError.u32TransferCount = 0; + pLsiReq->IOCReply.SCSIIOError.u32SenseCount = 0; + pLsiReq->IOCReply.SCSIIOError.u32ResponseInfo = 0; + + lsilogicFinishAddressReply(pThis, &pLsiReq->IOCReply, false); + RTMemCacheFree(pThis->hTaskCache, pLsiReq); return rc; } -static DECLCALLBACK(int) lsilogicDeviceSCSIRequestCompleted(PPDMISCSIPORT pInterface, PPDMSCSIREQUEST pSCSIRequest, - int rcCompletion, bool fRedo, int rcReq) +/** + * @interface_method_impl{PDMISCSIPORT,pfnSCSIRequestCompleted} + */ +static DECLCALLBACK(int) lsilogicR3DeviceSCSIRequestCompleted(PPDMISCSIPORT pInterface, PPDMSCSIREQUEST pSCSIRequest, + int rcCompletion, bool fRedo, int rcReq) { - PLSILOGICTASKSTATE pTaskState = (PLSILOGICTASKSTATE)pSCSIRequest->pvUser; - PLSILOGICDEVICE pLsiLogicDevice = pTaskState->pTargetDevice; - PLSILOGICSCSI pLsiLogic = pLsiLogicDevice->CTX_SUFF(pLsiLogic); + PLSILOGICREQ pLsiReq = (PLSILOGICREQ)pSCSIRequest->pvUser; + PLSILOGICDEVICE pLsiLogicDevice = pLsiReq->pTargetDevice; + PLSILOGICSCSI pThis = pLsiLogicDevice->CTX_SUFF(pLsiLogic); /* If the task failed but it is possible to redo it again after a suspend * add it to the list. */ if (fRedo) { - if (!pTaskState->fBIOS) - lsilogicScatterGatherListDestroy(pLsiLogic, pTaskState); + if (!pLsiReq->fBIOS && pLsiReq->PDMScsiRequest.cbScatterGather) + lsilogicIoBufFree(pThis->CTX_SUFF(pDevIns), pLsiReq, false /* fCopyToGuest */); /* Add to the list. */ do { - pTaskState->pRedoNext = ASMAtomicReadPtrT(&pLsiLogic->pTasksRedoHead, PLSILOGICTASKSTATE); - } while (!ASMAtomicCmpXchgPtr(&pLsiLogic->pTasksRedoHead, pTaskState, pTaskState->pRedoNext)); + pLsiReq->pRedoNext = ASMAtomicReadPtrT(&pThis->pTasksRedoHead, PLSILOGICREQ); + } while (!ASMAtomicCmpXchgPtr(&pThis->pTasksRedoHead, pLsiReq, pLsiReq->pRedoNext)); /* Suspend the VM if not done already. */ - if (!ASMAtomicXchgBool(&pLsiLogic->fRedo, true)) - lsilogicRedoSetWarning(pLsiLogic, rcReq); + if (!ASMAtomicXchgBool(&pThis->fRedo, true)) + lsilogicR3RedoSetWarning(pThis, rcReq); } else { - if (RT_UNLIKELY(pTaskState->fBIOS)) + if (RT_UNLIKELY(pLsiReq->fBIOS)) { - int rc = vboxscsiRequestFinished(&pLsiLogic->VBoxSCSI, pSCSIRequest); + int rc = vboxscsiRequestFinished(&pThis->VBoxSCSI, pSCSIRequest, rcCompletion); AssertMsgRC(rc, ("Finishing BIOS SCSI request failed rc=%Rrc\n", rc)); } else { -#if 0 - lsilogicFreeGCSenseBuffer(pLsiLogic, pTaskState); -#else RTGCPHYS GCPhysAddrSenseBuffer; - GCPhysAddrSenseBuffer = pTaskState->GuestRequest.SCSIIO.u32SenseBufferLowAddress; - GCPhysAddrSenseBuffer |= ((uint64_t)pLsiLogic->u32SenseBufferHighAddr << 32); + GCPhysAddrSenseBuffer = pLsiReq->GuestRequest.SCSIIO.u32SenseBufferLowAddress; + GCPhysAddrSenseBuffer |= ((uint64_t)pThis->u32SenseBufferHighAddr << 32); /* Copy the sense buffer over. */ - PDMDevHlpPhysWrite(pLsiLogic->CTX_SUFF(pDevIns), GCPhysAddrSenseBuffer, pTaskState->abSenseBuffer, - RT_UNLIKELY(pTaskState->GuestRequest.SCSIIO.u8SenseBufferLength < pTaskState->PDMScsiRequest.cbSenseBuffer) - ? pTaskState->GuestRequest.SCSIIO.u8SenseBufferLength - : pTaskState->PDMScsiRequest.cbSenseBuffer); -#endif - lsilogicScatterGatherListDestroy(pLsiLogic, pTaskState); + PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), GCPhysAddrSenseBuffer, pLsiReq->abSenseBuffer, + RT_UNLIKELY( pLsiReq->GuestRequest.SCSIIO.u8SenseBufferLength + < pLsiReq->PDMScsiRequest.cbSenseBuffer) + ? pLsiReq->GuestRequest.SCSIIO.u8SenseBufferLength + : pLsiReq->PDMScsiRequest.cbSenseBuffer); + + if (pLsiReq->PDMScsiRequest.cbScatterGather) + lsilogicIoBufFree(pThis->CTX_SUFF(pDevIns), pLsiReq, true /* fCopyToGuest */); if (RT_LIKELY(rcCompletion == SCSI_STATUS_OK)) - lsilogicFinishContextReply(pLsiLogic, pTaskState->GuestRequest.SCSIIO.u32MessageContext); + lsilogicR3FinishContextReply(pThis, pLsiReq->GuestRequest.SCSIIO.u32MessageContext); else { /* The SCSI target encountered an error during processing post a reply. */ - memset(&pTaskState->IOCReply, 0, sizeof(MptReplyUnion)); - pTaskState->IOCReply.SCSIIOError.u8TargetID = pTaskState->GuestRequest.SCSIIO.u8TargetID; - pTaskState->IOCReply.SCSIIOError.u8Bus = pTaskState->GuestRequest.SCSIIO.u8Bus; - pTaskState->IOCReply.SCSIIOError.u8MessageLength = 8; - pTaskState->IOCReply.SCSIIOError.u8Function = pTaskState->GuestRequest.SCSIIO.u8Function; - pTaskState->IOCReply.SCSIIOError.u8CDBLength = pTaskState->GuestRequest.SCSIIO.u8CDBLength; - pTaskState->IOCReply.SCSIIOError.u8SenseBufferLength = pTaskState->GuestRequest.SCSIIO.u8SenseBufferLength; - pTaskState->IOCReply.SCSIIOError.u8MessageFlags = pTaskState->GuestRequest.SCSIIO.u8MessageFlags; - pTaskState->IOCReply.SCSIIOError.u32MessageContext = pTaskState->GuestRequest.SCSIIO.u32MessageContext; - pTaskState->IOCReply.SCSIIOError.u8SCSIStatus = rcCompletion; - pTaskState->IOCReply.SCSIIOError.u8SCSIState = MPT_SCSI_IO_ERROR_SCSI_STATE_AUTOSENSE_VALID; - pTaskState->IOCReply.SCSIIOError.u16IOCStatus = 0; - pTaskState->IOCReply.SCSIIOError.u32IOCLogInfo = 0; - pTaskState->IOCReply.SCSIIOError.u32TransferCount = 0; - pTaskState->IOCReply.SCSIIOError.u32SenseCount = sizeof(pTaskState->abSenseBuffer); - pTaskState->IOCReply.SCSIIOError.u32ResponseInfo = 0; - - lsilogicFinishAddressReply(pLsiLogic, &pTaskState->IOCReply, true); + memset(&pLsiReq->IOCReply, 0, sizeof(MptReplyUnion)); + pLsiReq->IOCReply.SCSIIOError.u8TargetID = pLsiReq->GuestRequest.SCSIIO.u8TargetID; + pLsiReq->IOCReply.SCSIIOError.u8Bus = pLsiReq->GuestRequest.SCSIIO.u8Bus; + pLsiReq->IOCReply.SCSIIOError.u8MessageLength = 8; + pLsiReq->IOCReply.SCSIIOError.u8Function = pLsiReq->GuestRequest.SCSIIO.u8Function; + pLsiReq->IOCReply.SCSIIOError.u8CDBLength = pLsiReq->GuestRequest.SCSIIO.u8CDBLength; + pLsiReq->IOCReply.SCSIIOError.u8SenseBufferLength = pLsiReq->GuestRequest.SCSIIO.u8SenseBufferLength; + pLsiReq->IOCReply.SCSIIOError.u8MessageFlags = pLsiReq->GuestRequest.SCSIIO.u8MessageFlags; + pLsiReq->IOCReply.SCSIIOError.u32MessageContext = pLsiReq->GuestRequest.SCSIIO.u32MessageContext; + pLsiReq->IOCReply.SCSIIOError.u8SCSIStatus = rcCompletion; + pLsiReq->IOCReply.SCSIIOError.u8SCSIState = MPT_SCSI_IO_ERROR_SCSI_STATE_AUTOSENSE_VALID; + pLsiReq->IOCReply.SCSIIOError.u16IOCStatus = 0; + pLsiReq->IOCReply.SCSIIOError.u32IOCLogInfo = 0; + pLsiReq->IOCReply.SCSIIOError.u32TransferCount = 0; + pLsiReq->IOCReply.SCSIIOError.u32SenseCount = sizeof(pLsiReq->abSenseBuffer); + pLsiReq->IOCReply.SCSIIOError.u32ResponseInfo = 0; + + lsilogicFinishAddressReply(pThis, &pLsiReq->IOCReply, false); } } - RTMemCacheFree(pLsiLogic->hTaskCache, pTaskState); + RTMemCacheFree(pThis->hTaskCache, pLsiReq); } ASMAtomicDecU32(&pLsiLogicDevice->cOutstandingRequests); - if (pLsiLogicDevice->cOutstandingRequests == 0 && pLsiLogic->fSignalIdle) - PDMDevHlpAsyncNotificationCompleted(pLsiLogic->pDevInsR3); + if (pLsiLogicDevice->cOutstandingRequests == 0 && pThis->fSignalIdle) + PDMDevHlpAsyncNotificationCompleted(pThis->pDevInsR3); return VINF_SUCCESS; } -static DECLCALLBACK(int) lsilogicQueryDeviceLocation(PPDMISCSIPORT pInterface, const char **ppcszController, - uint32_t *piInstance, uint32_t *piLUN) +/** + * @interface_method_impl{PDMISCSIPORT,pfnQueryDeviceLocation} + */ +static DECLCALLBACK(int) lsilogicR3QueryDeviceLocation(PPDMISCSIPORT pInterface, const char **ppcszController, + uint32_t *piInstance, uint32_t *piLUN) { - PLSILOGICDEVICE pLsiLogicDevice = PDMISCSIPORT_2_PLSILOGICDEVICE(pInterface); + PLSILOGICDEVICE pLsiLogicDevice = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, ISCSIPort); PPDMDEVINS pDevIns = pLsiLogicDevice->CTX_SUFF(pLsiLogic)->CTX_SUFF(pDevIns); AssertPtrReturn(ppcszController, VERR_INVALID_POINTER); @@ -2195,17 +2387,17 @@ static DECLCALLBACK(int) lsilogicQueryDeviceLocation(PPDMISCSIPORT pInterface, c * @param ppPageHeader Where to store the pointer to the page header. * @param ppbPageData Where to store the pointer to the page data. */ -static int lsilogicConfigurationIOUnitPageGetFromNumber(PLSILOGICSCSI pLsiLogic, - PMptConfigurationPagesSupported pPages, - uint8_t u8PageNumber, - PMptConfigurationPageHeader *ppPageHeader, - uint8_t **ppbPageData, size_t *pcbPage) +static int lsilogicR3ConfigurationIOUnitPageGetFromNumber(PLSILOGICSCSI pThis, + PMptConfigurationPagesSupported pPages, + uint8_t u8PageNumber, + PMptConfigurationPageHeader *ppPageHeader, + uint8_t **ppbPageData, size_t *pcbPage) { int rc = VINF_SUCCESS; - AssertMsg(VALID_PTR(ppPageHeader) && VALID_PTR(ppbPageData), ("Invalid parameters\n")); + AssertPtr(ppPageHeader); Assert(ppbPageData); - switch(u8PageNumber) + switch (u8PageNumber) { case 0: *ppPageHeader = &pPages->IOUnitPage0.u.fields.Header; @@ -2249,17 +2441,17 @@ static int lsilogicConfigurationIOUnitPageGetFromNumber(PLSILOGICSCSI pLsiLogic, * @param ppPageHeader Where to store the pointer to the page header. * @param ppbPageData Where to store the pointer to the page data. */ -static int lsilogicConfigurationIOCPageGetFromNumber(PLSILOGICSCSI pLsiLogic, - PMptConfigurationPagesSupported pPages, - uint8_t u8PageNumber, - PMptConfigurationPageHeader *ppPageHeader, - uint8_t **ppbPageData, size_t *pcbPage) +static int lsilogicR3ConfigurationIOCPageGetFromNumber(PLSILOGICSCSI pThis, + PMptConfigurationPagesSupported pPages, + uint8_t u8PageNumber, + PMptConfigurationPageHeader *ppPageHeader, + uint8_t **ppbPageData, size_t *pcbPage) { int rc = VINF_SUCCESS; - AssertMsg(VALID_PTR(ppPageHeader) && VALID_PTR(ppbPageData), ("Invalid parameters\n")); + AssertPtr(ppPageHeader); Assert(ppbPageData); - switch(u8PageNumber) + switch (u8PageNumber) { case 0: *ppPageHeader = &pPages->IOCPage0.u.fields.Header; @@ -2308,17 +2500,17 @@ static int lsilogicConfigurationIOCPageGetFromNumber(PLSILOGICSCSI pLsiLogic, * @param ppPageHeader Where to store the pointer to the page header. * @param ppbPageData Where to store the pointer to the page data. */ -static int lsilogicConfigurationManufacturingPageGetFromNumber(PLSILOGICSCSI pLsiLogic, - PMptConfigurationPagesSupported pPages, - uint8_t u8PageNumber, - PMptConfigurationPageHeader *ppPageHeader, - uint8_t **ppbPageData, size_t *pcbPage) +static int lsilogicR3ConfigurationManufacturingPageGetFromNumber(PLSILOGICSCSI pThis, + PMptConfigurationPagesSupported pPages, + uint8_t u8PageNumber, + PMptConfigurationPageHeader *ppPageHeader, + uint8_t **ppbPageData, size_t *pcbPage) { int rc = VINF_SUCCESS; - AssertMsg(VALID_PTR(ppPageHeader) && VALID_PTR(ppbPageData), ("Invalid parameters\n")); + AssertPtr(ppPageHeader); Assert(ppbPageData); - switch(u8PageNumber) + switch (u8PageNumber) { case 0: *ppPageHeader = &pPages->ManufacturingPage0.u.fields.Header; @@ -2356,7 +2548,7 @@ static int lsilogicConfigurationManufacturingPageGetFromNumber(PLSILOGICSCSI pLs *pcbPage = sizeof(pPages->ManufacturingPage6); break; case 7: - if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS) + if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS) { *ppPageHeader = &pPages->u.SasPages.pManufacturingPage7->u.fields.Header; *ppbPageData = pPages->u.SasPages.pManufacturingPage7->u.abPageData; @@ -2397,17 +2589,17 @@ static int lsilogicConfigurationManufacturingPageGetFromNumber(PLSILOGICSCSI pLs * @param ppPageHeader Where to store the pointer to the page header. * @param ppbPageData Where to store the pointer to the page data. */ -static int lsilogicConfigurationBiosPageGetFromNumber(PLSILOGICSCSI pLsiLogic, - PMptConfigurationPagesSupported pPages, - uint8_t u8PageNumber, - PMptConfigurationPageHeader *ppPageHeader, - uint8_t **ppbPageData, size_t *pcbPage) +static int lsilogicR3ConfigurationBiosPageGetFromNumber(PLSILOGICSCSI pThis, + PMptConfigurationPagesSupported pPages, + uint8_t u8PageNumber, + PMptConfigurationPageHeader *ppPageHeader, + uint8_t **ppbPageData, size_t *pcbPage) { int rc = VINF_SUCCESS; - AssertMsg(VALID_PTR(ppPageHeader) && VALID_PTR(ppbPageData), ("Invalid parameters\n")); + AssertPtr(ppPageHeader); Assert(ppbPageData); - switch(u8PageNumber) + switch (u8PageNumber) { case 1: *ppPageHeader = &pPages->BIOSPage1.u.fields.Header; @@ -2441,21 +2633,21 @@ static int lsilogicConfigurationBiosPageGetFromNumber(PLSILOGICSCSI pLsiLogic, * @param ppPageHeader Where to store the pointer to the page header. * @param ppbPageData Where to store the pointer to the page data. */ -static int lsilogicConfigurationSCSISPIPortPageGetFromNumber(PLSILOGICSCSI pLsiLogic, - PMptConfigurationPagesSupported pPages, - uint8_t u8Port, - uint8_t u8PageNumber, - PMptConfigurationPageHeader *ppPageHeader, - uint8_t **ppbPageData, size_t *pcbPage) +static int lsilogicR3ConfigurationSCSISPIPortPageGetFromNumber(PLSILOGICSCSI pThis, + PMptConfigurationPagesSupported pPages, + uint8_t u8Port, + uint8_t u8PageNumber, + PMptConfigurationPageHeader *ppPageHeader, + uint8_t **ppbPageData, size_t *pcbPage) { int rc = VINF_SUCCESS; + AssertPtr(ppPageHeader); Assert(ppbPageData); - AssertMsg(VALID_PTR(ppPageHeader) && VALID_PTR(ppbPageData), ("Invalid parameters\n")); if (u8Port >= RT_ELEMENTS(pPages->u.SpiPages.aPortPages)) return VERR_NOT_FOUND; - switch(u8PageNumber) + switch (u8PageNumber) { case 0: *ppPageHeader = &pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage0.u.fields.Header; @@ -2489,16 +2681,15 @@ static int lsilogicConfigurationSCSISPIPortPageGetFromNumber(PLSILOGICSCSI pLsiL * @param ppPageHeader Where to store the pointer to the page header. * @param ppbPageData Where to store the pointer to the page data. */ -static int lsilogicConfigurationSCSISPIDevicePageGetFromNumber(PLSILOGICSCSI pLsiLogic, - PMptConfigurationPagesSupported pPages, - uint8_t u8Bus, - uint8_t u8TargetID, uint8_t u8PageNumber, - PMptConfigurationPageHeader *ppPageHeader, - uint8_t **ppbPageData, size_t *pcbPage) +static int lsilogicR3ConfigurationSCSISPIDevicePageGetFromNumber(PLSILOGICSCSI pThis, + PMptConfigurationPagesSupported pPages, + uint8_t u8Bus, + uint8_t u8TargetID, uint8_t u8PageNumber, + PMptConfigurationPageHeader *ppPageHeader, + uint8_t **ppbPageData, size_t *pcbPage) { int rc = VINF_SUCCESS; - - AssertMsg(VALID_PTR(ppPageHeader) && VALID_PTR(ppbPageData), ("Invalid parameters\n")); + AssertPtr(ppPageHeader); Assert(ppbPageData); if (u8Bus >= RT_ELEMENTS(pPages->u.SpiPages.aBuses)) return VERR_NOT_FOUND; @@ -2506,7 +2697,7 @@ static int lsilogicConfigurationSCSISPIDevicePageGetFromNumber(PLSILOGICSCSI pLs if (u8TargetID >= RT_ELEMENTS(pPages->u.SpiPages.aBuses[u8Bus].aDevicePages)) return VERR_NOT_FOUND; - switch(u8PageNumber) + switch (u8PageNumber) { case 0: *ppPageHeader = &pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage0.u.fields.Header; @@ -2535,15 +2726,15 @@ static int lsilogicConfigurationSCSISPIDevicePageGetFromNumber(PLSILOGICSCSI pLs return rc; } -static int lsilogicConfigurationSASIOUnitPageGetFromNumber(PLSILOGICSCSI pLsiLogic, - PMptConfigurationPagesSupported pPages, - uint8_t u8PageNumber, - PMptExtendedConfigurationPageHeader *ppPageHeader, - uint8_t **ppbPageData, size_t *pcbPage) +static int lsilogicR3ConfigurationSASIOUnitPageGetFromNumber(PLSILOGICSCSI pThis, + PMptConfigurationPagesSupported pPages, + uint8_t u8PageNumber, + PMptExtendedConfigurationPageHeader *ppPageHeader, + uint8_t **ppbPageData, size_t *pcbPage) { int rc = VINF_SUCCESS; - switch(u8PageNumber) + switch (u8PageNumber) { case 0: *ppPageHeader = &pPages->u.SasPages.pSASIOUnitPage0->u.fields.ExtHeader; @@ -2572,12 +2763,12 @@ static int lsilogicConfigurationSASIOUnitPageGetFromNumber(PLSILOGICSCSI pLsiLog return rc; } -static int lsilogicConfigurationSASPHYPageGetFromNumber(PLSILOGICSCSI pLsiLogic, - PMptConfigurationPagesSupported pPages, - uint8_t u8PageNumber, - MptConfigurationPageAddress PageAddress, - PMptExtendedConfigurationPageHeader *ppPageHeader, - uint8_t **ppbPageData, size_t *pcbPage) +static int lsilogicR3ConfigurationSASPHYPageGetFromNumber(PLSILOGICSCSI pThis, + PMptConfigurationPagesSupported pPages, + uint8_t u8PageNumber, + MptConfigurationPageAddress PageAddress, + PMptExtendedConfigurationPageHeader *ppPageHeader, + uint8_t **ppbPageData, size_t *pcbPage) { int rc = VINF_SUCCESS; uint8_t uAddressForm = MPT_CONFIGURATION_PAGE_ADDRESS_GET_SAS_FORM(PageAddress); @@ -2613,7 +2804,7 @@ static int lsilogicConfigurationSASPHYPageGetFromNumber(PLSILOGICSCSI pLsiLogic, if (pPHYPages) { - switch(u8PageNumber) + switch (u8PageNumber) { case 0: *ppPageHeader = &pPHYPages->SASPHYPage0.u.fields.ExtHeader; @@ -2635,12 +2826,12 @@ static int lsilogicConfigurationSASPHYPageGetFromNumber(PLSILOGICSCSI pLsiLogic, return rc; } -static int lsilogicConfigurationSASDevicePageGetFromNumber(PLSILOGICSCSI pLsiLogic, - PMptConfigurationPagesSupported pPages, - uint8_t u8PageNumber, - MptConfigurationPageAddress PageAddress, - PMptExtendedConfigurationPageHeader *ppPageHeader, - uint8_t **ppbPageData, size_t *pcbPage) +static int lsilogicR3ConfigurationSASDevicePageGetFromNumber(PLSILOGICSCSI pThis, + PMptConfigurationPagesSupported pPages, + uint8_t u8PageNumber, + MptConfigurationPageAddress PageAddress, + PMptExtendedConfigurationPageHeader *ppPageHeader, + uint8_t **ppbPageData, size_t *pcbPage) { int rc = VINF_SUCCESS; uint8_t uAddressForm = MPT_CONFIGURATION_PAGE_ADDRESS_GET_SAS_FORM(PageAddress); @@ -2699,7 +2890,7 @@ static int lsilogicConfigurationSASDevicePageGetFromNumber(PLSILOGICSCSI pLsiLog if (pSASDevice) { - switch(u8PageNumber) + switch (u8PageNumber) { case 0: *ppPageHeader = &pSASDevice->SASDevicePage0.u.fields.ExtHeader; @@ -2730,15 +2921,15 @@ static int lsilogicConfigurationSASDevicePageGetFromNumber(PLSILOGICSCSI pLsiLog * Returns the extended configuration page header and data. * @returns VINF_SUCCESS if successful * VERR_NOT_FOUND if the requested page could be found. - * @param pLsiLogic The LsiLogic controller instance. + * @param pThis Pointer to the LsiLogic device state. * @param pConfigurationReq The configuration request. * @param u8PageNumber Number of the page to get. * @param ppPageHeader Where to store the pointer to the page header. * @param ppbPageData Where to store the pointer to the page data. */ -static int lsilogicConfigurationPageGetExtended(PLSILOGICSCSI pLsiLogic, PMptConfigurationRequest pConfigurationReq, - PMptExtendedConfigurationPageHeader *ppPageHeader, - uint8_t **ppbPageData, size_t *pcbPage) +static int lsilogicR3ConfigurationPageGetExtended(PLSILOGICSCSI pThis, PMptConfigurationRequest pConfigurationReq, + PMptExtendedConfigurationPageHeader *ppPageHeader, + uint8_t **ppbPageData, size_t *pcbPage) { int rc = VINF_SUCCESS; @@ -2750,16 +2941,16 @@ static int lsilogicConfigurationPageGetExtended(PLSILOGICSCSI pLsiLogic, PMptCon { case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT: { - rc = lsilogicConfigurationSASIOUnitPageGetFromNumber(pLsiLogic, - pLsiLogic->pConfigurationPages, + rc = lsilogicR3ConfigurationSASIOUnitPageGetFromNumber(pThis, + pThis->pConfigurationPages, pConfigurationReq->u8PageNumber, ppPageHeader, ppbPageData, pcbPage); break; } case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASPHYS: { - rc = lsilogicConfigurationSASPHYPageGetFromNumber(pLsiLogic, - pLsiLogic->pConfigurationPages, + rc = lsilogicR3ConfigurationSASPHYPageGetFromNumber(pThis, + pThis->pConfigurationPages, pConfigurationReq->u8PageNumber, pConfigurationReq->PageAddress, ppPageHeader, ppbPageData, pcbPage); @@ -2767,8 +2958,8 @@ static int lsilogicConfigurationPageGetExtended(PLSILOGICSCSI pLsiLogic, PMptCon } case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE: { - rc = lsilogicConfigurationSASDevicePageGetFromNumber(pLsiLogic, - pLsiLogic->pConfigurationPages, + rc = lsilogicR3ConfigurationSASDevicePageGetFromNumber(pThis, + pThis->pConfigurationPages, pConfigurationReq->u8PageNumber, pConfigurationReq->PageAddress, ppPageHeader, ppbPageData, pcbPage); @@ -2787,12 +2978,12 @@ static int lsilogicConfigurationPageGetExtended(PLSILOGICSCSI pLsiLogic, PMptCon * Processes a Configuration request. * * @returns VBox status code. - * @param pLsiLogic Pointer to the device instance which sends the request. - * @param pConfigurationReq Pointer to the request structure. - * @param pReply Pointer to the reply message frame + * @param pThis Pointer to the LsiLogic device state. + * @param pConfigurationReq Pointer to the request structure. + * @param pReply Pointer to the reply message frame */ -static int lsilogicProcessConfigurationRequest(PLSILOGICSCSI pLsiLogic, PMptConfigurationRequest pConfigurationReq, - PMptConfigurationReply pReply) +static int lsilogicR3ProcessConfigurationRequest(PLSILOGICSCSI pThis, PMptConfigurationRequest pConfigurationReq, + PMptConfigurationReply pReply) { int rc = VINF_SUCCESS; uint8_t *pbPageData = NULL; @@ -2802,7 +2993,7 @@ static int lsilogicProcessConfigurationRequest(PLSILOGICSCSI pLsiLogic, PMptConf uint8_t u8PageAttribute; size_t cbPage = 0; - LogFlowFunc(("pLsiLogic=%#p\n", pLsiLogic)); + LogFlowFunc(("pThis=%#p\n", pThis)); u8PageType = MPT_CONFIGURATION_PAGE_TYPE_GET(pConfigurationReq->u8PageType); u8PageAttribute = MPT_CONFIGURATION_PAGE_ATTRIBUTE_GET(pConfigurationReq->u8PageType); @@ -2825,8 +3016,8 @@ static int lsilogicProcessConfigurationRequest(PLSILOGICSCSI pLsiLogic, PMptConf case MPT_CONFIGURATION_PAGE_TYPE_IO_UNIT: { /* Get the page data. */ - rc = lsilogicConfigurationIOUnitPageGetFromNumber(pLsiLogic, - pLsiLogic->pConfigurationPages, + rc = lsilogicR3ConfigurationIOUnitPageGetFromNumber(pThis, + pThis->pConfigurationPages, pConfigurationReq->u8PageNumber, &pPageHeader, &pbPageData, &cbPage); break; @@ -2834,8 +3025,8 @@ static int lsilogicProcessConfigurationRequest(PLSILOGICSCSI pLsiLogic, PMptConf case MPT_CONFIGURATION_PAGE_TYPE_IOC: { /* Get the page data. */ - rc = lsilogicConfigurationIOCPageGetFromNumber(pLsiLogic, - pLsiLogic->pConfigurationPages, + rc = lsilogicR3ConfigurationIOCPageGetFromNumber(pThis, + pThis->pConfigurationPages, pConfigurationReq->u8PageNumber, &pPageHeader, &pbPageData, &cbPage); break; @@ -2843,8 +3034,8 @@ static int lsilogicProcessConfigurationRequest(PLSILOGICSCSI pLsiLogic, PMptConf case MPT_CONFIGURATION_PAGE_TYPE_MANUFACTURING: { /* Get the page data. */ - rc = lsilogicConfigurationManufacturingPageGetFromNumber(pLsiLogic, - pLsiLogic->pConfigurationPages, + rc = lsilogicR3ConfigurationManufacturingPageGetFromNumber(pThis, + pThis->pConfigurationPages, pConfigurationReq->u8PageNumber, &pPageHeader, &pbPageData, &cbPage); break; @@ -2852,8 +3043,8 @@ static int lsilogicProcessConfigurationRequest(PLSILOGICSCSI pLsiLogic, PMptConf case MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_PORT: { /* Get the page data. */ - rc = lsilogicConfigurationSCSISPIPortPageGetFromNumber(pLsiLogic, - pLsiLogic->pConfigurationPages, + rc = lsilogicR3ConfigurationSCSISPIPortPageGetFromNumber(pThis, + pThis->pConfigurationPages, pConfigurationReq->PageAddress.MPIPortNumber.u8PortNumber, pConfigurationReq->u8PageNumber, &pPageHeader, &pbPageData, &cbPage); @@ -2862,8 +3053,8 @@ static int lsilogicProcessConfigurationRequest(PLSILOGICSCSI pLsiLogic, PMptConf case MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE: { /* Get the page data. */ - rc = lsilogicConfigurationSCSISPIDevicePageGetFromNumber(pLsiLogic, - pLsiLogic->pConfigurationPages, + rc = lsilogicR3ConfigurationSCSISPIDevicePageGetFromNumber(pThis, + pThis->pConfigurationPages, pConfigurationReq->PageAddress.BusAndTargetId.u8Bus, pConfigurationReq->PageAddress.BusAndTargetId.u8TargetID, pConfigurationReq->u8PageNumber, @@ -2872,15 +3063,15 @@ static int lsilogicProcessConfigurationRequest(PLSILOGICSCSI pLsiLogic, PMptConf } case MPT_CONFIGURATION_PAGE_TYPE_BIOS: { - rc = lsilogicConfigurationBiosPageGetFromNumber(pLsiLogic, - pLsiLogic->pConfigurationPages, + rc = lsilogicR3ConfigurationBiosPageGetFromNumber(pThis, + pThis->pConfigurationPages, pConfigurationReq->u8PageNumber, &pPageHeader, &pbPageData, &cbPage); break; } case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED: { - rc = lsilogicConfigurationPageGetExtended(pLsiLogic, + rc = lsilogicR3ConfigurationPageGetExtended(pThis, pConfigurationReq, &pExtPageHeader, &pbPageData, &cbPage); break; @@ -2945,8 +3136,7 @@ static int lsilogicProcessConfigurationRequest(PLSILOGICSCSI pLsiLogic, PMptConf if (pConfigurationReq->SimpleSGElement.f64BitAddress) GCPhysAddrPageBuffer |= (uint64_t)pConfigurationReq->SimpleSGElement.u32DataBufferAddressHigh << 32; - PDMDevHlpPhysWrite(pLsiLogic->CTX_SUFF(pDevIns), GCPhysAddrPageBuffer, pbPageData, - RT_MIN(cbBuffer, cbPage)); + PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), GCPhysAddrPageBuffer, pbPageData, RT_MIN(cbBuffer, cbPage)); } break; } @@ -2962,7 +3152,7 @@ static int lsilogicProcessConfigurationRequest(PLSILOGICSCSI pLsiLogic, PMptConf LogFlow(("cbBuffer=%u cbPage=%u\n", cbBuffer, cbPage)); - PDMDevHlpPhysRead(pLsiLogic->CTX_SUFF(pDevIns), GCPhysAddrPageBuffer, pbPageData, + PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), GCPhysAddrPageBuffer, pbPageData, RT_MIN(cbBuffer, cbPage)); } break; @@ -2978,18 +3168,18 @@ static int lsilogicProcessConfigurationRequest(PLSILOGICSCSI pLsiLogic, PMptConf * Initializes the configuration pages for the SPI SCSI controller. * * @returns nothing - * @param pLsiLogic Pointer to the Lsilogic SCSI instance. + * @param pThis Pointer to the LsiLogic device state. */ -static void lsilogicInitializeConfigurationPagesSpi(PLSILOGICSCSI pLsiLogic) +static void lsilogicR3InitializeConfigurationPagesSpi(PLSILOGICSCSI pThis) { - PMptConfigurationPagesSpi pPages = &pLsiLogic->pConfigurationPages->u.SpiPages; + PMptConfigurationPagesSpi pPages = &pThis->pConfigurationPages->u.SpiPages; - AssertMsg(pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI, ("Controller is not the SPI SCSI one\n")); + AssertMsg(pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI, ("Controller is not the SPI SCSI one\n")); - LogFlowFunc(("pLsiLogic=%#p\n", pLsiLogic)); + LogFlowFunc(("pThis=%#p\n", pThis)); /* Clear everything first. */ - memset(pPages, 0, sizeof(PMptConfigurationPagesSpi)); + memset(pPages, 0, sizeof(MptConfigurationPagesSpi)); for (unsigned i = 0; i < RT_ELEMENTS(pPages->aPortPages); i++) { @@ -3069,7 +3259,7 @@ static void lsilogicInitializeConfigurationPagesSpi(PLSILOGICSCSI pLsiLogic) * Generates a handle. * * @returns the handle. - * @param pThis The LsiLogic instance. + * @param pThis Pointer to the LsiLogic device state. */ DECLINLINE(uint16_t) lsilogicGetHandle(PLSILOGICSCSI pThis) { @@ -3102,9 +3292,9 @@ void lsilogicSASAddressGenerate(PSASADDRESS pSASAddress, unsigned iId) * Initializes the configuration pages for the SAS SCSI controller. * * @returns nothing - * @param pThis Pointer to the Lsilogic SCSI instance. + * @param pThis Pointer to the LsiLogic device state. */ -static void lsilogicInitializeConfigurationPagesSas(PLSILOGICSCSI pThis) +static void lsilogicR3InitializeConfigurationPagesSas(PLSILOGICSCSI pThis) { PMptConfigurationPagesSas pPages = &pThis->pConfigurationPages->u.SasPages; @@ -3298,16 +3488,16 @@ static void lsilogicInitializeConfigurationPagesSas(PLSILOGICSCSI pThis) * Initializes the configuration pages. * * @returns nothing - * @param pLsiLogic Pointer to the Lsilogic SCSI instance. + * @param pThis Pointer to the LsiLogic device state. */ -static void lsilogicInitializeConfigurationPages(PLSILOGICSCSI pLsiLogic) +static void lsilogicR3InitializeConfigurationPages(PLSILOGICSCSI pThis) { /* Initialize the common pages. */ PMptConfigurationPagesSupported pPages = (PMptConfigurationPagesSupported)RTMemAllocZ(sizeof(MptConfigurationPagesSupported)); - pLsiLogic->pConfigurationPages = pPages; + pThis->pConfigurationPages = pPages; - LogFlowFunc(("pLsiLogic=%#p\n", pLsiLogic)); + LogFlowFunc(("pThis=%#p\n", pThis)); /* Clear everything first. */ memset(pPages, 0, sizeof(MptConfigurationPagesSupported)); @@ -3332,12 +3522,12 @@ static void lsilogicInitializeConfigurationPages(PLSILOGICSCSI pLsiLogic) MptConfigurationPageManufacturing2, 2, MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY); - if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI) + if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI) { pPages->ManufacturingPage2.u.fields.u16PCIDeviceID = LSILOGICSCSI_PCI_SPI_DEVICE_ID; pPages->ManufacturingPage2.u.fields.u8PCIRevisionID = LSILOGICSCSI_PCI_SPI_REVISION_ID; } - else if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS) + else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS) { pPages->ManufacturingPage2.u.fields.u16PCIDeviceID = LSILOGICSCSI_PCI_SAS_DEVICE_ID; pPages->ManufacturingPage2.u.fields.u8PCIRevisionID = LSILOGICSCSI_PCI_SAS_REVISION_ID; @@ -3348,12 +3538,12 @@ static void lsilogicInitializeConfigurationPages(PLSILOGICSCSI pLsiLogic) MptConfigurationPageManufacturing3, 3, MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY); - if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI) + if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI) { pPages->ManufacturingPage3.u.fields.u16PCIDeviceID = LSILOGICSCSI_PCI_SPI_DEVICE_ID; pPages->ManufacturingPage3.u.fields.u8PCIRevisionID = LSILOGICSCSI_PCI_SPI_REVISION_ID; } - else if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS) + else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS) { pPages->ManufacturingPage3.u.fields.u16PCIDeviceID = LSILOGICSCSI_PCI_SAS_DEVICE_ID; pPages->ManufacturingPage3.u.fields.u8PCIRevisionID = LSILOGICSCSI_PCI_SAS_REVISION_ID; @@ -3416,7 +3606,7 @@ static void lsilogicInitializeConfigurationPages(PLSILOGICSCSI pLsiLogic) pPages->IOUnitPage2.u.fields.aAdapterOrder[0].fAdapterEnabled = true; pPages->IOUnitPage2.u.fields.aAdapterOrder[0].fAdapterEmbedded = true; pPages->IOUnitPage2.u.fields.aAdapterOrder[0].u8PCIBusNumber = 0; - pPages->IOUnitPage2.u.fields.aAdapterOrder[0].u8PCIDevFn = pLsiLogic->PciDev.devfn; + pPages->IOUnitPage2.u.fields.aAdapterOrder[0].u8PCIDevFn = pThis->PciDev.devfn; /* I/O Unit page 3. */ MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage3, @@ -3436,7 +3626,7 @@ static void lsilogicInitializeConfigurationPages(PLSILOGICSCSI pLsiLogic) pPages->IOCPage0.u.fields.u32TotalNVStore = 0; pPages->IOCPage0.u.fields.u32FreeNVStore = 0; - if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI) + if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI) { pPages->IOCPage0.u.fields.u16VendorId = LSILOGICSCSI_PCI_VENDOR_ID; pPages->IOCPage0.u.fields.u16DeviceId = LSILOGICSCSI_PCI_SPI_DEVICE_ID; @@ -3445,7 +3635,7 @@ static void lsilogicInitializeConfigurationPages(PLSILOGICSCSI pLsiLogic) pPages->IOCPage0.u.fields.u16SubsystemVendorId = LSILOGICSCSI_PCI_SPI_SUBSYSTEM_VENDOR_ID; pPages->IOCPage0.u.fields.u16SubsystemId = LSILOGICSCSI_PCI_SPI_SUBSYSTEM_ID; } - else if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS) + else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS) { pPages->IOCPage0.u.fields.u16VendorId = LSILOGICSCSI_PCI_VENDOR_ID; pPages->IOCPage0.u.fields.u16DeviceId = LSILOGICSCSI_PCI_SAS_DEVICE_ID; @@ -3502,122 +3692,26 @@ static void lsilogicInitializeConfigurationPages(PLSILOGICSCSI pLsiLogic) MptConfigurationPageBIOS4, 4, MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE); - if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI) - lsilogicInitializeConfigurationPagesSpi(pLsiLogic); - else if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS) - lsilogicInitializeConfigurationPagesSas(pLsiLogic); + if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI) + lsilogicR3InitializeConfigurationPagesSpi(pThis); + else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS) + lsilogicR3InitializeConfigurationPagesSas(pThis); else - AssertMsgFailed(("Invalid controller type %d\n", pLsiLogic->enmCtrlType)); + AssertMsgFailed(("Invalid controller type %d\n", pThis->enmCtrlType)); } /** - * Transmit queue consumer - * Queue a new async task. - * - * @returns Success indicator. - * If false the item will not be removed and the flushing will stop. - * @param pDevIns The device instance. - * @param pItem The item to consume. Upon return this item will be freed. + * @callback_method_impl{FNPDMQUEUEDEV, Transmit queue consumer.} */ -static DECLCALLBACK(bool) lsilogicNotifyQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem) +static DECLCALLBACK(bool) lsilogicR3NotifyQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem) { - PLSILOGICSCSI pLsiLogic = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); + PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); int rc = VINF_SUCCESS; LogFlowFunc(("pDevIns=%#p pItem=%#p\n", pDevIns, pItem)); - /* Reset notification event. */ - ASMAtomicXchgBool(&pLsiLogic->fNotificationSend, false); - - /* Only process request which arrived before we received the notification. */ - uint32_t uRequestQueueNextEntryWrite = ASMAtomicReadU32(&pLsiLogic->uRequestQueueNextEntryFreeWrite); - - /* Go through the messages now and process them. */ - while ( RT_LIKELY(pLsiLogic->enmState == LSILOGICSTATE_OPERATIONAL) - && (pLsiLogic->uRequestQueueNextAddressRead != uRequestQueueNextEntryWrite)) - { - uint32_t u32RequestMessageFrameDesc = pLsiLogic->CTX_SUFF(pRequestQueueBase)[pLsiLogic->uRequestQueueNextAddressRead]; - RTGCPHYS GCPhysMessageFrameAddr = LSILOGIC_RTGCPHYS_FROM_U32(pLsiLogic->u32HostMFAHighAddr, - (u32RequestMessageFrameDesc & ~0x07)); - - PLSILOGICTASKSTATE pTaskState; - - /* Get new task state. */ - rc = RTMemCacheAllocEx(pLsiLogic->hTaskCache, (void **)&pTaskState); - AssertRC(rc); - - pTaskState->GCPhysMessageFrameAddr = GCPhysMessageFrameAddr; - - /* Read the message header from the guest first. */ - PDMDevHlpPhysRead(pDevIns, GCPhysMessageFrameAddr, &pTaskState->GuestRequest, sizeof(MptMessageHdr)); - - /* Determine the size of the request. */ - uint32_t cbRequest = 0; - - switch (pTaskState->GuestRequest.Header.u8Function) - { - case MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST: - cbRequest = sizeof(MptSCSIIORequest); - break; - case MPT_MESSAGE_HDR_FUNCTION_SCSI_TASK_MGMT: - cbRequest = sizeof(MptSCSITaskManagementRequest); - break; - case MPT_MESSAGE_HDR_FUNCTION_IOC_INIT: - cbRequest = sizeof(MptIOCInitRequest); - break; - case MPT_MESSAGE_HDR_FUNCTION_IOC_FACTS: - cbRequest = sizeof(MptIOCFactsRequest); - break; - case MPT_MESSAGE_HDR_FUNCTION_CONFIG: - cbRequest = sizeof(MptConfigurationRequest); - break; - case MPT_MESSAGE_HDR_FUNCTION_PORT_FACTS: - cbRequest = sizeof(MptPortFactsRequest); - break; - case MPT_MESSAGE_HDR_FUNCTION_PORT_ENABLE: - cbRequest = sizeof(MptPortEnableRequest); - break; - case MPT_MESSAGE_HDR_FUNCTION_EVENT_NOTIFICATION: - cbRequest = sizeof(MptEventNotificationRequest); - break; - case MPT_MESSAGE_HDR_FUNCTION_EVENT_ACK: - AssertMsgFailed(("todo\n")); - //cbRequest = sizeof(MptEventAckRequest); - break; - case MPT_MESSAGE_HDR_FUNCTION_FW_DOWNLOAD: - cbRequest = sizeof(MptFWDownloadRequest); - break; - case MPT_MESSAGE_HDR_FUNCTION_FW_UPLOAD: - cbRequest = sizeof(MptFWUploadRequest); - break; - default: - AssertMsgFailed(("Unknown function issued %u\n", pTaskState->GuestRequest.Header.u8Function)); - lsilogicSetIOCFaultCode(pLsiLogic, LSILOGIC_IOCSTATUS_INVALID_FUNCTION); - } - - if (cbRequest != 0) - { - /* Read the complete message frame from guest memory now. */ - PDMDevHlpPhysRead(pDevIns, GCPhysMessageFrameAddr, &pTaskState->GuestRequest, cbRequest); - - /* Handle SCSI I/O requests now. */ - if (pTaskState->GuestRequest.Header.u8Function == MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST) - { - rc = lsilogicProcessSCSIIORequest(pLsiLogic, pTaskState); - AssertRC(rc); - } - else - { - MptReplyUnion Reply; - rc = lsilogicProcessMessageRequest(pLsiLogic, &pTaskState->GuestRequest.Header, &Reply); - AssertRC(rc); - RTMemCacheFree(pLsiLogic->hTaskCache, pTaskState); - } - - pLsiLogic->uRequestQueueNextAddressRead++; - pLsiLogic->uRequestQueueNextAddressRead %= pLsiLogic->cRequestQueueEntries; - } - } + rc = SUPSemEventSignal(pThis->pSupDrvSession, pThis->hEvtProcess); + AssertRC(rc); return true; } @@ -3627,10 +3721,10 @@ static DECLCALLBACK(bool) lsilogicNotifyQueueConsumer(PPDMDEVINS pDevIns, PPDMQU * * @returns VBox status code. * - * @param pThis The LsiLogic devi state. - * @param pcszCtrlType The string to use. + * @param pThis Pointer to the LsiLogic device state. + * @param pcszCtrlType The string to use. */ -static int lsilogicGetCtrlTypeFromString(PLSILOGICSCSI pThis, const char *pcszCtrlType) +static int lsilogicR3GetCtrlTypeFromString(PLSILOGICSCSI pThis, const char *pcszCtrlType) { int rc = VERR_INVALID_PARAMETER; @@ -3649,28 +3743,18 @@ static int lsilogicGetCtrlTypeFromString(PLSILOGICSCSI pThis, const char *pcszCt } /** - * Port I/O Handler for IN operations - legacy port. - * - * @returns VBox status code. - * - * @param pDevIns The device instance. - * @param pvUser User argument. - * @param uPort Port number used for the IN operation. - * @param pu32 Where to store the result. - * @param cb Number of bytes read. + * @callback_method_impl{FNIOMIOPORTIN, Legacy ISA port.} */ -static int lsilogicIsaIOPortRead (PPDMDEVINS pDevIns, void *pvUser, - RTIOPORT Port, uint32_t *pu32, unsigned cb) +static DECLCALLBACK(int) lsilogicR3IsaIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb) { - int rc; PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); Assert(cb == 1); - uint8_t iRegister = pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI - ? Port - LSILOGIC_BIOS_IO_PORT - : Port - LSILOGIC_SAS_BIOS_IO_PORT; - rc = vboxscsiReadRegister(&pThis->VBoxSCSI, iRegister, pu32); + uint8_t iRegister = pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI + ? Port - LSILOGIC_BIOS_IO_PORT + : Port - LSILOGIC_SAS_BIOS_IO_PORT; + int rc = vboxscsiReadRegister(&pThis->VBoxSCSI, iRegister, pu32); Log2(("%s: pu32=%p:{%.*Rhxs} iRegister=%d rc=%Rrc\n", __FUNCTION__, pu32, 1, pu32, iRegister, rc)); @@ -3682,41 +3766,41 @@ static int lsilogicIsaIOPortRead (PPDMDEVINS pDevIns, void *pvUser, * Prepares a request from the BIOS. * * @returns VBox status code. - * @param pLsiLogic Pointer to the LsiLogic device instance. + * @param pThis Pointer to the LsiLogic device state. */ -static int lsilogicPrepareBIOSSCSIRequest(PLSILOGICSCSI pLsiLogic) +static int lsilogicR3PrepareBiosScsiRequest(PLSILOGICSCSI pThis) { int rc; - PLSILOGICTASKSTATE pTaskState; + PLSILOGICREQ pLsiReq; uint32_t uTargetDevice; - rc = RTMemCacheAllocEx(pLsiLogic->hTaskCache, (void **)&pTaskState); + rc = RTMemCacheAllocEx(pThis->hTaskCache, (void **)&pLsiReq); AssertMsgRCReturn(rc, ("Getting task from cache failed rc=%Rrc\n", rc), rc); - pTaskState->fBIOS = true; + pLsiReq->fBIOS = true; - rc = vboxscsiSetupRequest(&pLsiLogic->VBoxSCSI, &pTaskState->PDMScsiRequest, &uTargetDevice); + rc = vboxscsiSetupRequest(&pThis->VBoxSCSI, &pLsiReq->PDMScsiRequest, &uTargetDevice); AssertMsgRCReturn(rc, ("Setting up SCSI request failed rc=%Rrc\n", rc), rc); - pTaskState->PDMScsiRequest.pvUser = pTaskState; + pLsiReq->PDMScsiRequest.pvUser = pLsiReq; - if (uTargetDevice < pLsiLogic->cDeviceStates) + if (uTargetDevice < pThis->cDeviceStates) { - pTaskState->pTargetDevice = &pLsiLogic->paDeviceStates[uTargetDevice]; + pLsiReq->pTargetDevice = &pThis->paDeviceStates[uTargetDevice]; - if (pTaskState->pTargetDevice->pDrvBase) + if (pLsiReq->pTargetDevice->pDrvBase) { - ASMAtomicIncU32(&pTaskState->pTargetDevice->cOutstandingRequests); + ASMAtomicIncU32(&pLsiReq->pTargetDevice->cOutstandingRequests); - rc = pTaskState->pTargetDevice->pDrvSCSIConnector->pfnSCSIRequestSend(pTaskState->pTargetDevice->pDrvSCSIConnector, - &pTaskState->PDMScsiRequest); + rc = pLsiReq->pTargetDevice->pDrvSCSIConnector->pfnSCSIRequestSend(pLsiReq->pTargetDevice->pDrvSCSIConnector, + &pLsiReq->PDMScsiRequest); AssertMsgRCReturn(rc, ("Sending request to SCSI layer failed rc=%Rrc\n", rc), rc); return VINF_SUCCESS; } } /* Device is not present. */ - AssertMsg(pTaskState->PDMScsiRequest.pbCDB[0] == SCSI_INQUIRY, + AssertMsg(pLsiReq->PDMScsiRequest.pbCDB[0] == SCSI_INQUIRY, ("Device is not present but command is not inquiry\n")); SCSIINQUIRYDATA ScsiInquiryData; @@ -3725,44 +3809,32 @@ static int lsilogicPrepareBIOSSCSIRequest(PLSILOGICSCSI pLsiLogic) ScsiInquiryData.u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_UNKNOWN; ScsiInquiryData.u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_NOT_CONNECTED_NOT_SUPPORTED; - memcpy(pLsiLogic->VBoxSCSI.pBuf, &ScsiInquiryData, 5); + memcpy(pThis->VBoxSCSI.pbBuf, &ScsiInquiryData, 5); - rc = vboxscsiRequestFinished(&pLsiLogic->VBoxSCSI, &pTaskState->PDMScsiRequest); + rc = vboxscsiRequestFinished(&pThis->VBoxSCSI, &pLsiReq->PDMScsiRequest, SCSI_STATUS_OK); AssertMsgRCReturn(rc, ("Finishing BIOS SCSI request failed rc=%Rrc\n", rc), rc); - RTMemCacheFree(pLsiLogic->hTaskCache, pTaskState); + RTMemCacheFree(pThis->hTaskCache, pLsiReq); return rc; } /** - * Port I/O Handler for OUT operations - legacy port. - * - * @returns VBox status code. - * - * @param pDevIns The device instance. - * @param pvUser User argument. - * @param uPort Port number used for the IN operation. - * @param u32 The value to output. - * @param cb The value size in bytes. + * @callback_method_impl{FNIOMIOPORTOUT, Legacy ISA port.} */ -static int lsilogicIsaIOPortWrite (PPDMDEVINS pDevIns, void *pvUser, - RTIOPORT Port, uint32_t u32, unsigned cb) +static DECLCALLBACK(int) lsilogicR3IsaIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb) { - int rc; PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); - - Log2(("#%d %s: pvUser=%#p cb=%d u32=%#x Port=%#x\n", - pDevIns->iInstance, __FUNCTION__, pvUser, cb, u32, Port)); + Log2(("#%d %s: pvUser=%#p cb=%d u32=%#x Port=%#x\n", pDevIns->iInstance, __FUNCTION__, pvUser, cb, u32, Port)); Assert(cb == 1); - uint8_t iRegister = pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI - ? Port - LSILOGIC_BIOS_IO_PORT - : Port - LSILOGIC_SAS_BIOS_IO_PORT; - rc = vboxscsiWriteRegister(&pThis->VBoxSCSI, iRegister, (uint8_t)u32); + uint8_t iRegister = pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI + ? Port - LSILOGIC_BIOS_IO_PORT + : Port - LSILOGIC_SAS_BIOS_IO_PORT; + int rc = vboxscsiWriteRegister(&pThis->VBoxSCSI, iRegister, (uint8_t)u32); if (rc == VERR_MORE_DATA) { - rc = lsilogicPrepareBIOSSCSIRequest(pThis); + rc = lsilogicR3PrepareBiosScsiRequest(pThis); AssertRC(rc); } else if (RT_FAILURE(rc)) @@ -3772,25 +3844,22 @@ static int lsilogicIsaIOPortWrite (PPDMDEVINS pDevIns, void *pvUser, } /** - * Port I/O Handler for primary port range OUT string operations. - * @see FNIOMIOPORTOUTSTRING for details. + * @callback_method_impl{FNIOMIOPORTOUTSTRING, + * Port I/O Handler for primary port range OUT string operations.} */ -static DECLCALLBACK(int) lsilogicIsaIOPortWriteStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, PRTGCUINTREG pcTransfer, unsigned cb) +static DECLCALLBACK(int) lsilogicR3IsaIOPortWriteStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, + PRTGCPTR pGCPtrSrc, PRTGCUINTREG pcTransfer, unsigned cb) { PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); - int rc; - - Log2(("#%d %s: pvUser=%#p cb=%d Port=%#x\n", - pDevIns->iInstance, __FUNCTION__, pvUser, cb, Port)); + Log2(("#%d %s: pvUser=%#p cb=%d Port=%#x\n", pDevIns->iInstance, __FUNCTION__, pvUser, cb, Port)); - uint8_t iRegister = pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI - ? Port - LSILOGIC_BIOS_IO_PORT - : Port - LSILOGIC_SAS_BIOS_IO_PORT; - rc = vboxscsiWriteString(pDevIns, &pThis->VBoxSCSI, iRegister, - pGCPtrSrc, pcTransfer, cb); + uint8_t iRegister = pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI + ? Port - LSILOGIC_BIOS_IO_PORT + : Port - LSILOGIC_SAS_BIOS_IO_PORT; + int rc = vboxscsiWriteString(pDevIns, &pThis->VBoxSCSI, iRegister, pGCPtrSrc, pcTransfer, cb); if (rc == VERR_MORE_DATA) { - rc = lsilogicPrepareBIOSSCSIRequest(pThis); + rc = lsilogicR3PrepareBiosScsiRequest(pThis); AssertRC(rc); } else if (RT_FAILURE(rc)) @@ -3800,26 +3869,29 @@ static DECLCALLBACK(int) lsilogicIsaIOPortWriteStr(PPDMDEVINS pDevIns, void *pvU } /** - * Port I/O Handler for primary port range IN string operations. - * @see FNIOMIOPORTINSTRING for details. + * @callback_method_impl{FNIOMIOPORTINSTRING, + * Port I/O Handler for primary port range IN string operations.} */ -static DECLCALLBACK(int) lsilogicIsaIOPortReadStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst, PRTGCUINTREG pcTransfer, unsigned cb) +static DECLCALLBACK(int) lsilogicR3IsaIOPortReadStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst, + PRTGCUINTREG pcTransfer, unsigned cb) { PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); LogFlowFunc(("#%d %s: pvUser=%#p cb=%d Port=%#x\n", pDevIns->iInstance, __FUNCTION__, pvUser, cb, Port)); - uint8_t iRegister = pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI - ? Port - LSILOGIC_BIOS_IO_PORT - : Port - LSILOGIC_SAS_BIOS_IO_PORT; - return vboxscsiReadString(pDevIns, &pThis->VBoxSCSI, iRegister, - pGCPtrDst, pcTransfer, cb); + uint8_t iRegister = pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI + ? Port - LSILOGIC_BIOS_IO_PORT + : Port - LSILOGIC_SAS_BIOS_IO_PORT; + return vboxscsiReadString(pDevIns, &pThis->VBoxSCSI, iRegister, pGCPtrDst, pcTransfer, cb); } -static DECLCALLBACK(int) lsilogicMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, - RTGCPHYS GCPhysAddress, uint32_t cb, - PCIADDRESSSPACE enmType) +/** + * @callback_method_impl{FNPCIIOREGIONMAP} + */ +static DECLCALLBACK(int) lsilogicR3Map(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, + RTGCPHYS GCPhysAddress, uint32_t cb, + PCIADDRESSSPACE enmType) { PPDMDEVINS pDevIns = pPciDev->pDevIns; PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); @@ -3837,11 +3909,24 @@ static DECLCALLBACK(int) lsilogicMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegio || (enmType == PCI_ADDRESS_SPACE_IO && cb >= LSILOGIC_PCI_SPACE_IO_SIZE), ("PCI region type and size do not match\n")); - if ((enmType == PCI_ADDRESS_SPACE_MEM) && (iRegion == 1)) + if (enmType == PCI_ADDRESS_SPACE_MEM && iRegion == 1) { - /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */ + /* + * Non-4-byte read access to LSILOGIC_REG_REPLY_QUEUE may cause real strange behavior + * because the data is part of a physical guest address. But some drivers use 1-byte + * access to scan for SCSI controllers. So, we simplify our code by telling IOM to + * read DWORDs. + * + * Regarding writes, we couldn't find anything specific in the specs about what should + * happen. So far we've ignored unaligned writes and assumed the missing bytes of + * byte and word access to be zero. We suspect that IOMMMIO_FLAGS_WRITE_ONLY_DWORD + * or IOMMMIO_FLAGS_WRITE_DWORD_ZEROED would be the most appropriate here, but since we + * don't have real hw to test one, the old behavior is kept exactly like it used to be. + */ + /** @todo Check out unaligned writes and non-dword writes on real LsiLogic + * hardware. */ rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL /*pvUser*/, - IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU, + IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_PASSTHRU, lsilogicMMIOWrite, lsilogicMMIORead, pcszCtrl); if (RT_FAILURE(rc)) return rc; @@ -3921,13 +4006,9 @@ static DECLCALLBACK(int) lsilogicMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegio } /** - * LsiLogic status info callback. - * - * @param pDevIns The device instance. - * @param pHlp The output helpers. - * @param pszArgs The arguments. + * @callback_method_impl{PFNDBGFHANDLERDEV} */ -static DECLCALLBACK(void) lsilogicInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) +static DECLCALLBACK(void) lsilogicR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) { PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); bool fVerbose = false; @@ -3955,7 +4036,7 @@ static DECLCALLBACK(void) lsilogicInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, c */ pHlp->pfnPrintf(pHlp, "enmState=%u\n", pThis->enmState); pHlp->pfnPrintf(pHlp, "enmWhoInit=%u\n", pThis->enmWhoInit); - pHlp->pfnPrintf(pHlp, "fDoorbellInProgress=%RTbool\n", pThis->fDoorbellInProgress); + pHlp->pfnPrintf(pHlp, "enmDoorbellState=%d\n", pThis->enmDoorbellState); pHlp->pfnPrintf(pHlp, "fDiagnosticEnabled=%RTbool\n", pThis->fDiagnosticEnabled); pHlp->pfnPrintf(pHlp, "fNotificationSend=%RTbool\n", pThis->fNotificationSend); pHlp->pfnPrintf(pHlp, "fEventNotificationEnabled=%RTbool\n", pThis->fEventNotificationEnabled); @@ -4019,9 +4100,9 @@ static DECLCALLBACK(void) lsilogicInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, c * * @returns VBox status code. * - * @param pThis The LsiLogic device instance. + * @param pThis Pointer to the LsiLogic device state. */ -static int lsilogicQueuesAlloc(PLSILOGICSCSI pThis) +static int lsilogicR3QueuesAlloc(PLSILOGICSCSI pThis) { PVM pVM = PDMDevHlpGetVM(pThis->pDevInsR3); uint32_t cbQueues; @@ -4053,9 +4134,9 @@ static int lsilogicQueuesAlloc(PLSILOGICSCSI pThis) * * @returns nothing. * - * @param pThis The LsiLogic device instance. + * @param pThis Pointer to the LsiLogic device state. */ -static void lsilogicQueuesFree(PLSILOGICSCSI pThis) +static void lsilogicR3QueuesFree(PLSILOGICSCSI pThis) { PVM pVM = PDMDevHlpGetVM(pThis->pDevInsR3); int rc = VINF_SUCCESS; @@ -4070,14 +4151,152 @@ static void lsilogicQueuesFree(PLSILOGICSCSI pThis) pThis->pRequestQueueBaseR3 = NULL; } + +/* The worker thread. */ +static DECLCALLBACK(int) lsilogicR3Worker(PPDMDEVINS pDevIns, PPDMTHREAD pThread) +{ + PLSILOGICSCSI pThis = (PLSILOGICSCSI)pThread->pvUser; + int rc = VINF_SUCCESS; + + if (pThread->enmState == PDMTHREADSTATE_INITIALIZING) + return VINF_SUCCESS; + + while (pThread->enmState == PDMTHREADSTATE_RUNNING) + { + bool fNotificationSend; + + ASMAtomicWriteBool(&pThis->fWrkThreadSleeping, true); + fNotificationSend = ASMAtomicXchgBool(&pThis->fNotificationSend, false); + if (!fNotificationSend) + { + Assert(ASMAtomicReadBool(&pThis->fWrkThreadSleeping)); + rc = SUPSemEventWaitNoResume(pThis->pSupDrvSession, pThis->hEvtProcess, RT_INDEFINITE_WAIT); + AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc); + if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING)) + break; + LogFlowFunc(("Woken up with rc=%Rrc\n", rc)); + fNotificationSend = ASMAtomicXchgBool(&pThis->fNotificationSend, false); + } + + ASMAtomicWriteBool(&pThis->fWrkThreadSleeping, false); + + /* Only process request which arrived before we received the notification. */ + uint32_t uRequestQueueNextEntryWrite = ASMAtomicReadU32(&pThis->uRequestQueueNextEntryFreeWrite); + + /* Go through the messages now and process them. */ + while ( RT_LIKELY(pThis->enmState == LSILOGICSTATE_OPERATIONAL) + && (pThis->uRequestQueueNextAddressRead != uRequestQueueNextEntryWrite)) + { + uint32_t u32RequestMessageFrameDesc = pThis->CTX_SUFF(pRequestQueueBase)[pThis->uRequestQueueNextAddressRead]; + RTGCPHYS GCPhysMessageFrameAddr = LSILOGIC_RTGCPHYS_FROM_U32(pThis->u32HostMFAHighAddr, + (u32RequestMessageFrameDesc & ~0x07)); + + PLSILOGICREQ pLsiReq; + + /* Get new task state. */ + rc = RTMemCacheAllocEx(pThis->hTaskCache, (void **)&pLsiReq); + AssertRC(rc); + + pLsiReq->GCPhysMessageFrameAddr = GCPhysMessageFrameAddr; + + /* Read the message header from the guest first. */ + PDMDevHlpPhysRead(pDevIns, GCPhysMessageFrameAddr, &pLsiReq->GuestRequest, sizeof(MptMessageHdr)); + + /* Determine the size of the request. */ + uint32_t cbRequest = 0; + + switch (pLsiReq->GuestRequest.Header.u8Function) + { + case MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST: + cbRequest = sizeof(MptSCSIIORequest); + break; + case MPT_MESSAGE_HDR_FUNCTION_SCSI_TASK_MGMT: + cbRequest = sizeof(MptSCSITaskManagementRequest); + break; + case MPT_MESSAGE_HDR_FUNCTION_IOC_INIT: + cbRequest = sizeof(MptIOCInitRequest); + break; + case MPT_MESSAGE_HDR_FUNCTION_IOC_FACTS: + cbRequest = sizeof(MptIOCFactsRequest); + break; + case MPT_MESSAGE_HDR_FUNCTION_CONFIG: + cbRequest = sizeof(MptConfigurationRequest); + break; + case MPT_MESSAGE_HDR_FUNCTION_PORT_FACTS: + cbRequest = sizeof(MptPortFactsRequest); + break; + case MPT_MESSAGE_HDR_FUNCTION_PORT_ENABLE: + cbRequest = sizeof(MptPortEnableRequest); + break; + case MPT_MESSAGE_HDR_FUNCTION_EVENT_NOTIFICATION: + cbRequest = sizeof(MptEventNotificationRequest); + break; + case MPT_MESSAGE_HDR_FUNCTION_EVENT_ACK: + AssertMsgFailed(("todo\n")); + //cbRequest = sizeof(MptEventAckRequest); + break; + case MPT_MESSAGE_HDR_FUNCTION_FW_DOWNLOAD: + cbRequest = sizeof(MptFWDownloadRequest); + break; + case MPT_MESSAGE_HDR_FUNCTION_FW_UPLOAD: + cbRequest = sizeof(MptFWUploadRequest); + break; + default: + AssertMsgFailed(("Unknown function issued %u\n", pLsiReq->GuestRequest.Header.u8Function)); + lsilogicSetIOCFaultCode(pThis, LSILOGIC_IOCSTATUS_INVALID_FUNCTION); + } + + if (cbRequest != 0) + { + /* Read the complete message frame from guest memory now. */ + PDMDevHlpPhysRead(pDevIns, GCPhysMessageFrameAddr, &pLsiReq->GuestRequest, cbRequest); + + /* Handle SCSI I/O requests now. */ + if (pLsiReq->GuestRequest.Header.u8Function == MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST) + { + rc = lsilogicR3ProcessSCSIIORequest(pThis, pLsiReq); + AssertRC(rc); + } + else + { + MptReplyUnion Reply; + rc = lsilogicR3ProcessMessageRequest(pThis, &pLsiReq->GuestRequest.Header, &Reply); + AssertRC(rc); + RTMemCacheFree(pThis->hTaskCache, pLsiReq); + } + + pThis->uRequestQueueNextAddressRead++; + pThis->uRequestQueueNextAddressRead %= pThis->cRequestQueueEntries; + } + } /* While request frames available. */ + } /* While running */ + + return VINF_SUCCESS; +} + + +/** + * Unblock the worker thread so it can respond to a state change. + * + * @returns VBox status code. + * @param pDevIns The pcnet device instance. + * @param pThread The send thread. + */ +static DECLCALLBACK(int) lsilogicR3WorkerWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread) +{ + PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); + return SUPSemEventSignal(pThis->pSupDrvSession, pThis->hEvtProcess); +} + + /** * Kicks the controller to process pending tasks after the VM was resumed * or loaded from a saved state. * * @returns nothing. - * @param pThis The LsiLogic device instance. + * @param pThis Pointer to the LsiLogic device state. */ -static void lsilogicKick(PLSILOGICSCSI pThis) +static void lsilogicR3Kick(PLSILOGICSCSI pThis) { if (pThis->fNotificationSend) { @@ -4089,13 +4308,21 @@ static void lsilogicKick(PLSILOGICSCSI pThis) else if (pThis->VBoxSCSI.fBusy) { /* The BIOS had a request active when we got suspended. Resume it. */ - int rc = lsilogicPrepareBIOSSCSIRequest(pThis); + int rc = lsilogicR3PrepareBiosScsiRequest(pThis); AssertRC(rc); } } -static DECLCALLBACK(int) lsilogicLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass) + +/* + * Saved state. + */ + +/** + * @callback_method_impl{FNSSMDEVLIVEEXEC} + */ +static DECLCALLBACK(int) lsilogicR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass) { PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); @@ -4110,62 +4337,77 @@ static DECLCALLBACK(int) lsilogicLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, u return VINF_SSM_DONT_CALL_AGAIN; } -static DECLCALLBACK(int) lsilogicSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM) +/** + * @callback_method_impl{FNSSMDEVSAVEEXEC} + */ +static DECLCALLBACK(int) lsilogicR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM) { - PLSILOGICSCSI pLsiLogic = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); + PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); /* Every device first. */ - lsilogicLiveExec(pDevIns, pSSM, SSM_PASS_FINAL); - for (unsigned i = 0; i < pLsiLogic->cDeviceStates; i++) + lsilogicR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL); + for (unsigned i = 0; i < pThis->cDeviceStates; i++) { - PLSILOGICDEVICE pDevice = &pLsiLogic->paDeviceStates[i]; + PLSILOGICDEVICE pDevice = &pThis->paDeviceStates[i]; AssertMsg(!pDevice->cOutstandingRequests, ("There are still outstanding requests on this device\n")); SSMR3PutU32(pSSM, pDevice->cOutstandingRequests); } /* Now the main device state. */ - SSMR3PutU32 (pSSM, pLsiLogic->enmState); - SSMR3PutU32 (pSSM, pLsiLogic->enmWhoInit); - SSMR3PutBool (pSSM, pLsiLogic->fDoorbellInProgress); - SSMR3PutBool (pSSM, pLsiLogic->fDiagnosticEnabled); - SSMR3PutBool (pSSM, pLsiLogic->fNotificationSend); - SSMR3PutBool (pSSM, pLsiLogic->fEventNotificationEnabled); - SSMR3PutU32 (pSSM, pLsiLogic->uInterruptMask); - SSMR3PutU32 (pSSM, pLsiLogic->uInterruptStatus); - for (unsigned i = 0; i < RT_ELEMENTS(pLsiLogic->aMessage); i++) - SSMR3PutU32 (pSSM, pLsiLogic->aMessage[i]); - SSMR3PutU32 (pSSM, pLsiLogic->iMessage); - SSMR3PutU32 (pSSM, pLsiLogic->cMessage); - SSMR3PutMem (pSSM, &pLsiLogic->ReplyBuffer, sizeof(pLsiLogic->ReplyBuffer)); - SSMR3PutU32 (pSSM, pLsiLogic->uNextReplyEntryRead); - SSMR3PutU32 (pSSM, pLsiLogic->cReplySize); - SSMR3PutU16 (pSSM, pLsiLogic->u16IOCFaultCode); - SSMR3PutU32 (pSSM, pLsiLogic->u32HostMFAHighAddr); - SSMR3PutU32 (pSSM, pLsiLogic->u32SenseBufferHighAddr); - SSMR3PutU8 (pSSM, pLsiLogic->cMaxDevices); - SSMR3PutU8 (pSSM, pLsiLogic->cMaxBuses); - SSMR3PutU16 (pSSM, pLsiLogic->cbReplyFrame); - SSMR3PutU32 (pSSM, pLsiLogic->iDiagnosticAccess); - SSMR3PutU32 (pSSM, pLsiLogic->cReplyQueueEntries); - SSMR3PutU32 (pSSM, pLsiLogic->cRequestQueueEntries); - SSMR3PutU32 (pSSM, pLsiLogic->uReplyFreeQueueNextEntryFreeWrite); - SSMR3PutU32 (pSSM, pLsiLogic->uReplyFreeQueueNextAddressRead); - SSMR3PutU32 (pSSM, pLsiLogic->uReplyPostQueueNextEntryFreeWrite); - SSMR3PutU32 (pSSM, pLsiLogic->uReplyPostQueueNextAddressRead); - SSMR3PutU32 (pSSM, pLsiLogic->uRequestQueueNextEntryFreeWrite); - SSMR3PutU32 (pSSM, pLsiLogic->uRequestQueueNextAddressRead); - - for (unsigned i = 0; i < pLsiLogic->cReplyQueueEntries; i++) - SSMR3PutU32(pSSM, pLsiLogic->pReplyFreeQueueBaseR3[i]); - for (unsigned i = 0; i < pLsiLogic->cReplyQueueEntries; i++) - SSMR3PutU32(pSSM, pLsiLogic->pReplyPostQueueBaseR3[i]); - for (unsigned i = 0; i < pLsiLogic->cRequestQueueEntries; i++) - SSMR3PutU32(pSSM, pLsiLogic->pRequestQueueBaseR3[i]); - - SSMR3PutU16 (pSSM, pLsiLogic->u16NextHandle); - - PMptConfigurationPagesSupported pPages = pLsiLogic->pConfigurationPages; + SSMR3PutU32 (pSSM, pThis->enmState); + SSMR3PutU32 (pSSM, pThis->enmWhoInit); + SSMR3PutU32 (pSSM, pThis->enmDoorbellState); + SSMR3PutBool (pSSM, pThis->fDiagnosticEnabled); + SSMR3PutBool (pSSM, pThis->fNotificationSend); + SSMR3PutBool (pSSM, pThis->fEventNotificationEnabled); + SSMR3PutU32 (pSSM, pThis->uInterruptMask); + SSMR3PutU32 (pSSM, pThis->uInterruptStatus); + for (unsigned i = 0; i < RT_ELEMENTS(pThis->aMessage); i++) + SSMR3PutU32 (pSSM, pThis->aMessage[i]); + SSMR3PutU32 (pSSM, pThis->iMessage); + SSMR3PutU32 (pSSM, pThis->cMessage); + SSMR3PutMem (pSSM, &pThis->ReplyBuffer, sizeof(pThis->ReplyBuffer)); + SSMR3PutU32 (pSSM, pThis->uNextReplyEntryRead); + SSMR3PutU32 (pSSM, pThis->cReplySize); + SSMR3PutU16 (pSSM, pThis->u16IOCFaultCode); + SSMR3PutU32 (pSSM, pThis->u32HostMFAHighAddr); + SSMR3PutU32 (pSSM, pThis->u32SenseBufferHighAddr); + SSMR3PutU8 (pSSM, pThis->cMaxDevices); + SSMR3PutU8 (pSSM, pThis->cMaxBuses); + SSMR3PutU16 (pSSM, pThis->cbReplyFrame); + SSMR3PutU32 (pSSM, pThis->iDiagnosticAccess); + SSMR3PutU32 (pSSM, pThis->cReplyQueueEntries); + SSMR3PutU32 (pSSM, pThis->cRequestQueueEntries); + SSMR3PutU32 (pSSM, pThis->uReplyFreeQueueNextEntryFreeWrite); + SSMR3PutU32 (pSSM, pThis->uReplyFreeQueueNextAddressRead); + SSMR3PutU32 (pSSM, pThis->uReplyPostQueueNextEntryFreeWrite); + SSMR3PutU32 (pSSM, pThis->uReplyPostQueueNextAddressRead); + SSMR3PutU32 (pSSM, pThis->uRequestQueueNextEntryFreeWrite); + SSMR3PutU32 (pSSM, pThis->uRequestQueueNextAddressRead); + + for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++) + SSMR3PutU32(pSSM, pThis->pReplyFreeQueueBaseR3[i]); + for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++) + SSMR3PutU32(pSSM, pThis->pReplyPostQueueBaseR3[i]); + for (unsigned i = 0; i < pThis->cRequestQueueEntries; i++) + SSMR3PutU32(pSSM, pThis->pRequestQueueBaseR3[i]); + + SSMR3PutU16 (pSSM, pThis->u16NextHandle); + + /* Save diagnostic memory register and data regions. */ + SSMR3PutU32 (pSSM, pThis->u32DiagMemAddr); + SSMR3PutU32 (pSSM, lsilogicR3MemRegionsCount(pThis)); + + PLSILOGICMEMREGN pIt = NULL; + RTListForEach(&pThis->ListMemRegns, pIt, LSILOGICMEMREGN, NodeList) + { + SSMR3PutU32(pSSM, pIt->u32AddrStart); + SSMR3PutU32(pSSM, pIt->u32AddrEnd); + SSMR3PutMem(pSSM, &pIt->au32Data[0], (pIt->u32AddrEnd - pIt->u32AddrStart + 1) * sizeof(uint32_t)); + } + + PMptConfigurationPagesSupported pPages = pThis->pConfigurationPages; SSMR3PutMem (pSSM, &pPages->ManufacturingPage0, sizeof(MptConfigurationPageManufacturing0)); SSMR3PutMem (pSSM, &pPages->ManufacturingPage1, sizeof(MptConfigurationPageManufacturing1)); @@ -4193,7 +4435,7 @@ static DECLCALLBACK(int) lsilogicSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM) SSMR3PutMem (pSSM, &pPages->BIOSPage4, sizeof(MptConfigurationPageBIOS4)); /* Device dependent pages */ - if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI) + if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI) { PMptConfigurationPagesSpi pSpiPages = &pPages->u.SpiPages; @@ -4209,7 +4451,7 @@ static DECLCALLBACK(int) lsilogicSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM) SSMR3PutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage3, sizeof(MptConfigurationPageSCSISPIDevice3)); } } - else if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS) + else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS) { PMptConfigurationPagesSas pSasPages = &pPages->u.SasPages; @@ -4246,39 +4488,47 @@ static DECLCALLBACK(int) lsilogicSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM) } } else - AssertMsgFailed(("Invalid controller type %d\n", pLsiLogic->enmCtrlType)); + AssertMsgFailed(("Invalid controller type %d\n", pThis->enmCtrlType)); /* Now the data for the BIOS interface. */ - SSMR3PutU8 (pSSM, pLsiLogic->VBoxSCSI.regIdentify); - SSMR3PutU8 (pSSM, pLsiLogic->VBoxSCSI.uTargetDevice); - SSMR3PutU8 (pSSM, pLsiLogic->VBoxSCSI.uTxDir); - SSMR3PutU8 (pSSM, pLsiLogic->VBoxSCSI.cbCDB); - SSMR3PutMem (pSSM, pLsiLogic->VBoxSCSI.aCDB, sizeof(pLsiLogic->VBoxSCSI.aCDB)); - SSMR3PutU8 (pSSM, pLsiLogic->VBoxSCSI.iCDB); - SSMR3PutU32 (pSSM, pLsiLogic->VBoxSCSI.cbBuf); - SSMR3PutU32 (pSSM, pLsiLogic->VBoxSCSI.iBuf); - SSMR3PutBool (pSSM, pLsiLogic->VBoxSCSI.fBusy); - SSMR3PutU8 (pSSM, pLsiLogic->VBoxSCSI.enmState); - if (pLsiLogic->VBoxSCSI.cbBuf) - SSMR3PutMem(pSSM, pLsiLogic->VBoxSCSI.pBuf, pLsiLogic->VBoxSCSI.cbBuf); + SSMR3PutU8 (pSSM, pThis->VBoxSCSI.regIdentify); + SSMR3PutU8 (pSSM, pThis->VBoxSCSI.uTargetDevice); + SSMR3PutU8 (pSSM, pThis->VBoxSCSI.uTxDir); + SSMR3PutU8 (pSSM, pThis->VBoxSCSI.cbCDB); + SSMR3PutMem (pSSM, pThis->VBoxSCSI.abCDB, sizeof(pThis->VBoxSCSI.abCDB)); + SSMR3PutU8 (pSSM, pThis->VBoxSCSI.iCDB); + SSMR3PutU32 (pSSM, pThis->VBoxSCSI.cbBuf); + SSMR3PutU32 (pSSM, pThis->VBoxSCSI.iBuf); + SSMR3PutBool (pSSM, pThis->VBoxSCSI.fBusy); + SSMR3PutU8 (pSSM, pThis->VBoxSCSI.enmState); + if (pThis->VBoxSCSI.cbBuf) + SSMR3PutMem(pSSM, pThis->VBoxSCSI.pbBuf, pThis->VBoxSCSI.cbBuf); return SSMR3PutU32(pSSM, ~0); } -static DECLCALLBACK(int) lsilogicLoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM) +/** + * @callback_method_impl{FNSSMDEVLOADDONE} + */ +static DECLCALLBACK(int) lsilogicR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM) { PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); - lsilogicKick(pThis); + lsilogicR3Kick(pThis); return VINF_SUCCESS; } -static DECLCALLBACK(int) lsilogicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass) +/** + * @callback_method_impl{FNSSMDEVLOADEXEC} + */ +static DECLCALLBACK(int) lsilogicR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass) { - PLSILOGICSCSI pLsiLogic = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); + PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); int rc; if ( uVersion != LSILOGIC_SAVED_STATE_VERSION + && uVersion != LSILOGIC_SAVED_STATE_VERSION_PRE_DIAG_MEM + && uVersion != LSILOGIC_SAVED_STATE_VERSION_BOOL_DOORBELL && uVersion != LSILOGIC_SAVED_STATE_VERSION_PRE_SAS && uVersion != LSILOGIC_SAVED_STATE_VERSION_VBOX_30) return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION; @@ -4296,96 +4546,111 @@ static DECLCALLBACK(int) lsilogicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, u rc = SSMR3GetU32(pSSM, &cPorts); AssertRCReturn(rc, rc); - if (enmCtrlType != pLsiLogic->enmCtrlType) + if (enmCtrlType != pThis->enmCtrlType) return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Target config mismatch (Controller type): config=%d state=%d"), - pLsiLogic->enmCtrlType, enmCtrlType); - if (cDeviceStates != pLsiLogic->cDeviceStates) + pThis->enmCtrlType, enmCtrlType); + if (cDeviceStates != pThis->cDeviceStates) return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Target config mismatch (Device states): config=%u state=%u"), - pLsiLogic->cDeviceStates, cDeviceStates); - if (cPorts != pLsiLogic->cPorts) + pThis->cDeviceStates, cDeviceStates); + if (cPorts != pThis->cPorts) return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Target config mismatch (Ports): config=%u state=%u"), - pLsiLogic->cPorts, cPorts); + pThis->cPorts, cPorts); } if (uVersion > LSILOGIC_SAVED_STATE_VERSION_VBOX_30) { - for (unsigned i = 0; i < pLsiLogic->cDeviceStates; i++) + for (unsigned i = 0; i < pThis->cDeviceStates; i++) { bool fPresent; rc = SSMR3GetBool(pSSM, &fPresent); AssertRCReturn(rc, rc); - if (fPresent != (pLsiLogic->paDeviceStates[i].pDrvBase != NULL)) + if (fPresent != (pThis->paDeviceStates[i].pDrvBase != NULL)) return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Target %u config mismatch: config=%RTbool state=%RTbool"), - i, pLsiLogic->paDeviceStates[i].pDrvBase != NULL, fPresent); + i, pThis->paDeviceStates[i].pDrvBase != NULL, fPresent); } } if (uPass != SSM_PASS_FINAL) return VINF_SUCCESS; /* Every device first. */ - for (unsigned i = 0; i < pLsiLogic->cDeviceStates; i++) + for (unsigned i = 0; i < pThis->cDeviceStates; i++) { - PLSILOGICDEVICE pDevice = &pLsiLogic->paDeviceStates[i]; + PLSILOGICDEVICE pDevice = &pThis->paDeviceStates[i]; AssertMsg(!pDevice->cOutstandingRequests, ("There are still outstanding requests on this device\n")); SSMR3GetU32(pSSM, (uint32_t *)&pDevice->cOutstandingRequests); } /* Now the main device state. */ - SSMR3GetU32 (pSSM, (uint32_t *)&pLsiLogic->enmState); - SSMR3GetU32 (pSSM, (uint32_t *)&pLsiLogic->enmWhoInit); - SSMR3GetBool (pSSM, &pLsiLogic->fDoorbellInProgress); - SSMR3GetBool (pSSM, &pLsiLogic->fDiagnosticEnabled); - SSMR3GetBool (pSSM, &pLsiLogic->fNotificationSend); - SSMR3GetBool (pSSM, &pLsiLogic->fEventNotificationEnabled); - SSMR3GetU32 (pSSM, (uint32_t *)&pLsiLogic->uInterruptMask); - SSMR3GetU32 (pSSM, (uint32_t *)&pLsiLogic->uInterruptStatus); - for (unsigned i = 0; i < RT_ELEMENTS(pLsiLogic->aMessage); i++) - SSMR3GetU32 (pSSM, &pLsiLogic->aMessage[i]); - SSMR3GetU32 (pSSM, &pLsiLogic->iMessage); - SSMR3GetU32 (pSSM, &pLsiLogic->cMessage); - SSMR3GetMem (pSSM, &pLsiLogic->ReplyBuffer, sizeof(pLsiLogic->ReplyBuffer)); - SSMR3GetU32 (pSSM, &pLsiLogic->uNextReplyEntryRead); - SSMR3GetU32 (pSSM, &pLsiLogic->cReplySize); - SSMR3GetU16 (pSSM, &pLsiLogic->u16IOCFaultCode); - SSMR3GetU32 (pSSM, &pLsiLogic->u32HostMFAHighAddr); - SSMR3GetU32 (pSSM, &pLsiLogic->u32SenseBufferHighAddr); - SSMR3GetU8 (pSSM, &pLsiLogic->cMaxDevices); - SSMR3GetU8 (pSSM, &pLsiLogic->cMaxBuses); - SSMR3GetU16 (pSSM, &pLsiLogic->cbReplyFrame); - SSMR3GetU32 (pSSM, &pLsiLogic->iDiagnosticAccess); + SSMR3GetU32 (pSSM, (uint32_t *)&pThis->enmState); + SSMR3GetU32 (pSSM, (uint32_t *)&pThis->enmWhoInit); + if (uVersion <= LSILOGIC_SAVED_STATE_VERSION_BOOL_DOORBELL) + { + bool fDoorbellInProgress = false; + + /* + * The doorbell status flag distinguishes only between + * doorbell not in use or a Function handshake is currently in progress. + */ + SSMR3GetBool (pSSM, &fDoorbellInProgress); + if (fDoorbellInProgress) + pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_FN_HANDSHAKE; + else + pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_NOT_IN_USE; + } + else + SSMR3GetU32(pSSM, (uint32_t *)&pThis->enmDoorbellState); + SSMR3GetBool (pSSM, &pThis->fDiagnosticEnabled); + SSMR3GetBool (pSSM, &pThis->fNotificationSend); + SSMR3GetBool (pSSM, &pThis->fEventNotificationEnabled); + SSMR3GetU32 (pSSM, (uint32_t *)&pThis->uInterruptMask); + SSMR3GetU32 (pSSM, (uint32_t *)&pThis->uInterruptStatus); + for (unsigned i = 0; i < RT_ELEMENTS(pThis->aMessage); i++) + SSMR3GetU32 (pSSM, &pThis->aMessage[i]); + SSMR3GetU32 (pSSM, &pThis->iMessage); + SSMR3GetU32 (pSSM, &pThis->cMessage); + SSMR3GetMem (pSSM, &pThis->ReplyBuffer, sizeof(pThis->ReplyBuffer)); + SSMR3GetU32 (pSSM, &pThis->uNextReplyEntryRead); + SSMR3GetU32 (pSSM, &pThis->cReplySize); + SSMR3GetU16 (pSSM, &pThis->u16IOCFaultCode); + SSMR3GetU32 (pSSM, &pThis->u32HostMFAHighAddr); + SSMR3GetU32 (pSSM, &pThis->u32SenseBufferHighAddr); + SSMR3GetU8 (pSSM, &pThis->cMaxDevices); + SSMR3GetU8 (pSSM, &pThis->cMaxBuses); + SSMR3GetU16 (pSSM, &pThis->cbReplyFrame); + SSMR3GetU32 (pSSM, &pThis->iDiagnosticAccess); uint32_t cReplyQueueEntries, cRequestQueueEntries; SSMR3GetU32 (pSSM, &cReplyQueueEntries); SSMR3GetU32 (pSSM, &cRequestQueueEntries); - if ( cReplyQueueEntries != pLsiLogic->cReplyQueueEntries - || cRequestQueueEntries != pLsiLogic->cRequestQueueEntries) + if ( cReplyQueueEntries != pThis->cReplyQueueEntries + || cRequestQueueEntries != pThis->cRequestQueueEntries) { LogFlow(("Reallocating queues cReplyQueueEntries=%u cRequestQueuEntries=%u\n", cReplyQueueEntries, cRequestQueueEntries)); - lsilogicQueuesFree(pLsiLogic); - pLsiLogic->cReplyQueueEntries = cReplyQueueEntries; - pLsiLogic->cRequestQueueEntries = cRequestQueueEntries; - rc = lsilogicQueuesAlloc(pLsiLogic); + lsilogicR3QueuesFree(pThis); + pThis->cReplyQueueEntries = cReplyQueueEntries; + pThis->cRequestQueueEntries = cRequestQueueEntries; + rc = lsilogicR3QueuesAlloc(pThis); if (RT_FAILURE(rc)) return rc; } - SSMR3GetU32 (pSSM, (uint32_t *)&pLsiLogic->uReplyFreeQueueNextEntryFreeWrite); - SSMR3GetU32 (pSSM, (uint32_t *)&pLsiLogic->uReplyFreeQueueNextAddressRead); - SSMR3GetU32 (pSSM, (uint32_t *)&pLsiLogic->uReplyPostQueueNextEntryFreeWrite); - SSMR3GetU32 (pSSM, (uint32_t *)&pLsiLogic->uReplyPostQueueNextAddressRead); - SSMR3GetU32 (pSSM, (uint32_t *)&pLsiLogic->uRequestQueueNextEntryFreeWrite); - SSMR3GetU32 (pSSM, (uint32_t *)&pLsiLogic->uRequestQueueNextAddressRead); + SSMR3GetU32 (pSSM, (uint32_t *)&pThis->uReplyFreeQueueNextEntryFreeWrite); + SSMR3GetU32 (pSSM, (uint32_t *)&pThis->uReplyFreeQueueNextAddressRead); + SSMR3GetU32 (pSSM, (uint32_t *)&pThis->uReplyPostQueueNextEntryFreeWrite); + SSMR3GetU32 (pSSM, (uint32_t *)&pThis->uReplyPostQueueNextAddressRead); + SSMR3GetU32 (pSSM, (uint32_t *)&pThis->uRequestQueueNextEntryFreeWrite); + SSMR3GetU32 (pSSM, (uint32_t *)&pThis->uRequestQueueNextAddressRead); - PMptConfigurationPagesSupported pPages = pLsiLogic->pConfigurationPages; + PMptConfigurationPagesSupported pPages = pThis->pConfigurationPages; if (uVersion <= LSILOGIC_SAVED_STATE_VERSION_PRE_SAS) { PMptConfigurationPagesSpi pSpiPages = &pPages->u.SpiPages; MptConfigurationPagesSupported_SSM_V2 ConfigPagesV2; - if (pLsiLogic->enmCtrlType != LSILOGICCTRLTYPE_SCSI_SPI) + if (pThis->enmCtrlType != LSILOGICCTRLTYPE_SCSI_SPI) return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: Expected SPI SCSI controller")); SSMR3GetMem(pSSM, &ConfigPagesV2, @@ -4422,14 +4687,52 @@ static DECLCALLBACK(int) lsilogicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, u else { /* Queue content */ - for (unsigned i = 0; i < pLsiLogic->cReplyQueueEntries; i++) - SSMR3GetU32(pSSM, (uint32_t *)&pLsiLogic->pReplyFreeQueueBaseR3[i]); - for (unsigned i = 0; i < pLsiLogic->cReplyQueueEntries; i++) - SSMR3GetU32(pSSM, (uint32_t *)&pLsiLogic->pReplyPostQueueBaseR3[i]); - for (unsigned i = 0; i < pLsiLogic->cRequestQueueEntries; i++) - SSMR3GetU32(pSSM, (uint32_t *)&pLsiLogic->pRequestQueueBaseR3[i]); + for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++) + SSMR3GetU32(pSSM, (uint32_t *)&pThis->pReplyFreeQueueBaseR3[i]); + for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++) + SSMR3GetU32(pSSM, (uint32_t *)&pThis->pReplyPostQueueBaseR3[i]); + for (unsigned i = 0; i < pThis->cRequestQueueEntries; i++) + SSMR3GetU32(pSSM, (uint32_t *)&pThis->pRequestQueueBaseR3[i]); + + SSMR3GetU16(pSSM, &pThis->u16NextHandle); + + if (uVersion > LSILOGIC_SAVED_STATE_VERSION_PRE_DIAG_MEM) + { + uint32_t cMemRegions = 0; + + /* Save diagnostic memory register and data regions. */ + SSMR3GetU32 (pSSM, &pThis->u32DiagMemAddr); + SSMR3GetU32 (pSSM, &cMemRegions); + + while (cMemRegions) + { + uint32_t u32AddrStart = 0; + uint32_t u32AddrEnd = 0; + uint32_t cRegion = 0; + PLSILOGICMEMREGN pRegion = NULL; - SSMR3GetU16(pSSM, &pLsiLogic->u16NextHandle); + SSMR3GetU32(pSSM, &u32AddrStart); + SSMR3GetU32(pSSM, &u32AddrEnd); + + cRegion = u32AddrEnd - u32AddrStart + 1; + pRegion = (PLSILOGICMEMREGN)RTMemAllocZ(RT_OFFSETOF(LSILOGICMEMREGN, au32Data[cRegion])); + if (pRegion) + { + pRegion->u32AddrStart = u32AddrStart; + pRegion->u32AddrEnd = u32AddrEnd; + SSMR3GetMem(pSSM, &pRegion->au32Data[0], cRegion * sizeof(uint32_t)); + lsilogicR3MemRegionInsert(pThis, pRegion); + pThis->cbMemRegns += cRegion * sizeof(uint32_t); + } + else + { + /* Leave a log message but continue. */ + LogRel(("LsiLogic: Out of memory while restoring the state, might not work as expected\n")); + SSMR3Skip(pSSM, cRegion * sizeof(uint32_t)); + } + cMemRegions--; + } + } /* Configuration pages */ SSMR3GetMem(pSSM, &pPages->ManufacturingPage0, sizeof(MptConfigurationPageManufacturing0)); @@ -4458,7 +4761,7 @@ static DECLCALLBACK(int) lsilogicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, u SSMR3GetMem(pSSM, &pPages->BIOSPage4, sizeof(MptConfigurationPageBIOS4)); /* Device dependent pages */ - if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI) + if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI) { PMptConfigurationPagesSpi pSpiPages = &pPages->u.SpiPages; @@ -4474,7 +4777,7 @@ static DECLCALLBACK(int) lsilogicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, u SSMR3GetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage3, sizeof(MptConfigurationPageSCSISPIDevice3)); } } - else if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS) + else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS) { uint32_t cbPage0, cbPage1, cPHYs, cbManufacturingPage7; PMptConfigurationPagesSas pSasPages = &pPages->u.SasPages; @@ -4527,30 +4830,30 @@ static DECLCALLBACK(int) lsilogicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, u Assert(!pCurr); } else - AssertMsgFailed(("Invalid controller type %d\n", pLsiLogic->enmCtrlType)); + AssertMsgFailed(("Invalid controller type %d\n", pThis->enmCtrlType)); } /* Now the data for the BIOS interface. */ - SSMR3GetU8 (pSSM, &pLsiLogic->VBoxSCSI.regIdentify); - SSMR3GetU8 (pSSM, &pLsiLogic->VBoxSCSI.uTargetDevice); - SSMR3GetU8 (pSSM, &pLsiLogic->VBoxSCSI.uTxDir); - SSMR3GetU8 (pSSM, &pLsiLogic->VBoxSCSI.cbCDB); - SSMR3GetMem (pSSM, pLsiLogic->VBoxSCSI.aCDB, sizeof(pLsiLogic->VBoxSCSI.aCDB)); - SSMR3GetU8 (pSSM, &pLsiLogic->VBoxSCSI.iCDB); - SSMR3GetU32 (pSSM, &pLsiLogic->VBoxSCSI.cbBuf); - SSMR3GetU32 (pSSM, &pLsiLogic->VBoxSCSI.iBuf); - SSMR3GetBool(pSSM, (bool *)&pLsiLogic->VBoxSCSI.fBusy); - SSMR3GetU8 (pSSM, (uint8_t *)&pLsiLogic->VBoxSCSI.enmState); - if (pLsiLogic->VBoxSCSI.cbBuf) + SSMR3GetU8 (pSSM, &pThis->VBoxSCSI.regIdentify); + SSMR3GetU8 (pSSM, &pThis->VBoxSCSI.uTargetDevice); + SSMR3GetU8 (pSSM, &pThis->VBoxSCSI.uTxDir); + SSMR3GetU8 (pSSM, &pThis->VBoxSCSI.cbCDB); + SSMR3GetMem (pSSM, pThis->VBoxSCSI.abCDB, sizeof(pThis->VBoxSCSI.abCDB)); + SSMR3GetU8 (pSSM, &pThis->VBoxSCSI.iCDB); + SSMR3GetU32 (pSSM, &pThis->VBoxSCSI.cbBuf); + SSMR3GetU32 (pSSM, &pThis->VBoxSCSI.iBuf); + SSMR3GetBool(pSSM, (bool *)&pThis->VBoxSCSI.fBusy); + SSMR3GetU8 (pSSM, (uint8_t *)&pThis->VBoxSCSI.enmState); + if (pThis->VBoxSCSI.cbBuf) { - pLsiLogic->VBoxSCSI.pBuf = (uint8_t *)RTMemAllocZ(pLsiLogic->VBoxSCSI.cbBuf); - if (!pLsiLogic->VBoxSCSI.pBuf) + pThis->VBoxSCSI.pbBuf = (uint8_t *)RTMemAllocZ(pThis->VBoxSCSI.cbBuf); + if (!pThis->VBoxSCSI.pbBuf) { LogRel(("LsiLogic: Out of memory during restore.\n")); return PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY, N_("LsiLogic: Out of memory during restore\n")); } - SSMR3GetMem(pSSM, pLsiLogic->VBoxSCSI.pBuf, pLsiLogic->VBoxSCSI.cbBuf); + SSMR3GetMem(pSSM, pThis->VBoxSCSI.pbBuf, pThis->VBoxSCSI.cbBuf); } uint32_t u32; @@ -4562,18 +4865,19 @@ static DECLCALLBACK(int) lsilogicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, u return VINF_SUCCESS; } + +/* + * The device level IBASE and LED interfaces. + */ + /** - * Gets the pointer to the status LED of a device - called from the SCSi driver. + * @interface_method_impl{PDMILEDPORTS,pfnQueryInterface, For a SCSI device.} * - * @returns VBox status code. - * @param pInterface Pointer to the interface structure containing the called function pointer. - * @param iLUN The unit which status LED we desire. Always 0 here as the driver - * doesn't know about other LUN's. - * @param ppLed Where to store the LED pointer. + * @remarks Called by the scsi driver, proxying the main calls. */ -static DECLCALLBACK(int) lsilogicDeviceQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed) +static DECLCALLBACK(int) lsilogicR3DeviceQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed) { - PLSILOGICDEVICE pDevice = PDMILEDPORTS_2_PLSILOGICDEVICE(pInterface); + PLSILOGICDEVICE pDevice = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, ILed); if (iLUN == 0) { *ppLed = &pDevice->Led; @@ -4587,9 +4891,9 @@ static DECLCALLBACK(int) lsilogicDeviceQueryStatusLed(PPDMILEDPORTS pInterface, /** * @interface_method_impl{PDMIBASE,pfnQueryInterface} */ -static DECLCALLBACK(void *) lsilogicDeviceQueryInterface(PPDMIBASE pInterface, const char *pszIID) +static DECLCALLBACK(void *) lsilogicR3DeviceQueryInterface(PPDMIBASE pInterface, const char *pszIID) { - PLSILOGICDEVICE pDevice = PDMIBASE_2_PLSILOGICDEVICE(pInterface); + PLSILOGICDEVICE pDevice = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, IBase); PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDevice->IBase); PDMIBASE_RETURN_INTERFACE(pszIID, PDMISCSIPORT, &pDevice->ISCSIPort); @@ -4597,6 +4901,11 @@ static DECLCALLBACK(void *) lsilogicDeviceQueryInterface(PPDMIBASE pInterface, c return NULL; } + +/* + * The controller level IBASE and LED interfaces. + */ + /** * Gets the pointer to the status LED of a unit. * @@ -4605,12 +4914,12 @@ static DECLCALLBACK(void *) lsilogicDeviceQueryInterface(PPDMIBASE pInterface, c * @param iLUN The unit which status LED we desire. * @param ppLed Where to store the LED pointer. */ -static DECLCALLBACK(int) lsilogicStatusQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed) +static DECLCALLBACK(int) lsilogicR3StatusQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed) { - PLSILOGICSCSI pLsiLogic = PDMILEDPORTS_2_PLSILOGICSCSI(pInterface); - if (iLUN < pLsiLogic->cDeviceStates) + PLSILOGICSCSI pThis = RT_FROM_MEMBER(pInterface, LSILOGICSCSI, ILeds); + if (iLUN < pThis->cDeviceStates) { - *ppLed = &pLsiLogic->paDeviceStates[iLUN].Led; + *ppLed = &pThis->paDeviceStates[iLUN].Led; Assert((*ppLed)->u32Magic == PDMLED_MAGIC); return VINF_SUCCESS; } @@ -4620,20 +4929,23 @@ static DECLCALLBACK(int) lsilogicStatusQueryStatusLed(PPDMILEDPORTS pInterface, /** * @interface_method_impl{PDMIBASE,pfnQueryInterface} */ -static DECLCALLBACK(void *) lsilogicStatusQueryInterface(PPDMIBASE pInterface, const char *pszIID) +static DECLCALLBACK(void *) lsilogicR3StatusQueryInterface(PPDMIBASE pInterface, const char *pszIID) { - PLSILOGICSCSI pThis = PDMIBASE_2_PLSILOGICSCSI(pInterface); + PLSILOGICSCSI pThis = RT_FROM_MEMBER(pInterface, LSILOGICSCSI, IBase); PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase); PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThis->ILeds); return NULL; } -/* -=-=-=-=- Helper -=-=-=-=- */ + +/* + * The PDM device interface and some helpers. + */ /** * Checks if all asynchronous I/O is finished. * - * Used by lsilogicReset, lsilogicSuspend and lsilogicPowerOff. + * Used by lsilogicR3Reset, lsilogicR3Suspend and lsilogicR3PowerOff. * * @returns true if quiesced, false if busy. * @param pDevIns The device instance. @@ -4656,10 +4968,8 @@ static bool lsilogicR3AllAsyncIOIsFinished(PPDMDEVINS pDevIns) } /** - * Callback employed by lsilogicR3Suspend and lsilogicR3PowerOff.. - * - * @returns true if we've quiesced, false if we're still working. - * @param pDevIns The device instance. + * @callback_method_impl{FNPDMDEVASYNCNOTIFY, + * Callback employed by lsilogicR3Suspend and lsilogicR3PowerOff.} */ static DECLCALLBACK(bool) lsilogicR3IsAsyncSuspendOrPowerOffDone(PPDMDEVINS pDevIns) { @@ -4695,19 +5005,19 @@ static void lsilogicR3SuspendOrPowerOff(PPDMDEVINS pDevIns) * Guest execution is suspended at this point so there is no race between us and * lsilogicRegisterWrite. */ - PLSILOGICTASKSTATE pTaskState = pThis->pTasksRedoHead; + PLSILOGICREQ pLsiReq = pThis->pTasksRedoHead; pThis->pTasksRedoHead = NULL; - while (pTaskState) + while (pLsiReq) { - PLSILOGICTASKSTATE pFree; + PLSILOGICREQ pFree; - if (!pTaskState->fBIOS) + if (!pLsiReq->fBIOS) { /* Write only the lower 32bit part of the address. */ ASMAtomicWriteU32(&pThis->CTX_SUFF(pRequestQueueBase)[pThis->uRequestQueueNextEntryFreeWrite], - pTaskState->GCPhysMessageFrameAddr & UINT32_C(0xffffffff)); + pLsiReq->GCPhysMessageFrameAddr & UINT32_C(0xffffffff)); pThis->uRequestQueueNextEntryFreeWrite++; pThis->uRequestQueueNextEntryFreeWrite %= pThis->cRequestQueueEntries; @@ -4716,12 +5026,12 @@ static void lsilogicR3SuspendOrPowerOff(PPDMDEVINS pDevIns) } else { - AssertMsg(!pTaskState->pRedoNext, ("Only one BIOS task can be active!\n")); - vboxscsiSetRequestRedo(&pThis->VBoxSCSI, &pTaskState->PDMScsiRequest); + AssertMsg(!pLsiReq->pRedoNext, ("Only one BIOS task can be active!\n")); + vboxscsiSetRequestRedo(&pThis->VBoxSCSI, &pLsiReq->PDMScsiRequest); } - pFree = pTaskState; - pTaskState = pTaskState->pRedoNext; + pFree = pLsiReq; + pLsiReq = pLsiReq->pRedoNext; RTMemCacheFree(pThis->hTaskCache, pFree); } @@ -4731,41 +5041,33 @@ static void lsilogicR3SuspendOrPowerOff(PPDMDEVINS pDevIns) } /** - * Suspend notification. - * - * @param pDevIns The device instance data. + * @interface_method_impl{PDMDEVREG,pfnSuspend} */ -static DECLCALLBACK(void) lsilogicSuspend(PPDMDEVINS pDevIns) +static DECLCALLBACK(void) lsilogicR3Suspend(PPDMDEVINS pDevIns) { - Log(("lsilogicSuspend\n")); + Log(("lsilogicR3Suspend\n")); lsilogicR3SuspendOrPowerOff(pDevIns); } /** - * Resume notification. - * - * @param pDevIns The device instance data. + * @interface_method_impl{PDMDEVREG,pfnResume} */ -static DECLCALLBACK(void) lsilogicResume(PPDMDEVINS pDevIns) +static DECLCALLBACK(void) lsilogicR3Resume(PPDMDEVINS pDevIns) { PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); - Log(("lsilogicResume\n")); + Log(("lsilogicR3Resume\n")); - lsilogicKick(pThis); + lsilogicR3Kick(pThis); } /** - * Detach notification. + * @interface_method_impl{PDMDEVREG,pfnDetach} * * One harddisk at one port has been unplugged. * The VM is suspended at this point. - * - * @param pDevIns The device instance. - * @param iLUN The logical unit which is being detached. - * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines. */ -static DECLCALLBACK(void) lsilogicDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags) +static DECLCALLBACK(void) lsilogicR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags) { PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); PLSILOGICDEVICE pDevice = &pThis->paDeviceStates[iLUN]; @@ -4786,16 +5088,9 @@ static DECLCALLBACK(void) lsilogicDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint } /** - * Attach command. - * - * This is called when we change block driver. - * - * @returns VBox status code. - * @param pDevIns The device instance. - * @param iLUN The logical unit which is being detached. - * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines. + * @interface_method_impl{PDMDEVREG,pfnAttach} */ -static DECLCALLBACK(int) lsilogicAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags) +static DECLCALLBACK(int) lsilogicR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags) { PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); PLSILOGICDEVICE pDevice = &pThis->paDeviceStates[iLUN]; @@ -4842,20 +5137,18 @@ static DECLCALLBACK(int) lsilogicAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint */ static void lsilogicR3ResetCommon(PPDMDEVINS pDevIns) { - PLSILOGICSCSI pLsiLogic = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); + PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); int rc; - rc = lsilogicHardReset(pLsiLogic); + rc = lsilogicR3HardReset(pThis); AssertRC(rc); - vboxscsiInitialize(&pLsiLogic->VBoxSCSI); + vboxscsiInitialize(&pThis->VBoxSCSI); } /** - * Callback employed by lsilogicR3Reset. - * - * @returns true if we've quiesced, false if we're still working. - * @param pDevIns The device instance. + * @callback_method_impl{FNPDMDEVASYNCNOTIFY, + * Callback employed by lsilogicR3Reset.} */ static DECLCALLBACK(bool) lsilogicR3IsAsyncResetDone(PPDMDEVINS pDevIns) { @@ -4870,9 +5163,9 @@ static DECLCALLBACK(bool) lsilogicR3IsAsyncResetDone(PPDMDEVINS pDevIns) } /** - * @copydoc FNPDMDEVRESET + * @interface_method_impl{PDMDEVREG,pfnReset} */ -static DECLCALLBACK(void) lsilogicReset(PPDMDEVINS pDevIns) +static DECLCALLBACK(void) lsilogicR3Reset(PPDMDEVINS pDevIns) { PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); @@ -4887,9 +5180,9 @@ static DECLCALLBACK(void) lsilogicReset(PPDMDEVINS pDevIns) } /** - * @copydoc FNPDMDEVRELOCATE + * @interface_method_impl{PDMDEVREG,pfnRelocate} */ -static DECLCALLBACK(void) lsilogicRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta) +static DECLCALLBACK(void) lsilogicR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta) { PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); @@ -4903,9 +5196,18 @@ static DECLCALLBACK(void) lsilogicRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDel } /** - * @copydoc FNPDMDEVDESTRUCT + * @interface_method_impl{PDMDEVREG,pfnPowerOff} */ -static DECLCALLBACK(int) lsilogicDestruct(PPDMDEVINS pDevIns) +static DECLCALLBACK(void) lsilogicR3PowerOff(PPDMDEVINS pDevIns) +{ + Log(("lsilogicR3PowerOff\n")); + lsilogicR3SuspendOrPowerOff(pDevIns); +} + +/** + * @interface_method_impl{PDMDEVREG,pfnDestruct} + */ +static DECLCALLBACK(int) lsilogicR3Destruct(PPDMDEVINS pDevIns) { PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns); @@ -4913,43 +5215,45 @@ static DECLCALLBACK(int) lsilogicDestruct(PPDMDEVINS pDevIns) PDMR3CritSectDelete(&pThis->ReplyFreeQueueCritSect); PDMR3CritSectDelete(&pThis->ReplyPostQueueCritSect); - if (pThis->paDeviceStates) - RTMemFree(pThis->paDeviceStates); + RTMemFree(pThis->paDeviceStates); + pThis->paDeviceStates = NULL; /* Destroy task cache. */ - int rc = VINF_SUCCESS; if (pThis->hTaskCache != NIL_RTMEMCACHE) - rc = RTMemCacheDestroy(pThis->hTaskCache); + { + int rc = RTMemCacheDestroy(pThis->hTaskCache); AssertRC(rc); + pThis->hTaskCache = NIL_RTMEMCACHE; + } - lsilogicConfigurationPagesFree(pThis); + if (pThis->hEvtProcess != NIL_SUPSEMEVENT) + { + SUPSemEventClose(pThis->pSupDrvSession, pThis->hEvtProcess); + pThis->hEvtProcess = NIL_SUPSEMEVENT; + } - return rc; -} + lsilogicR3ConfigurationPagesFree(pThis); + lsilogicR3MemRegionsFree(pThis); -/** - * Poweroff notification. - * - * @param pDevIns Pointer to the device instance - */ -static DECLCALLBACK(void) lsilogicPowerOff(PPDMDEVINS pDevIns) -{ - Log(("lsilogicPowerOff\n")); - lsilogicR3SuspendOrPowerOff(pDevIns); + return VINF_SUCCESS; } /** - * @copydoc FNPDMDEVCONSTRUCT + * @interface_method_impl{PDMDEVREG,pfnConstruct} */ -static DECLCALLBACK(int) lsilogicConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg) +static DECLCALLBACK(int) lsilogicR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg) { PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI); - int rc = VINF_SUCCESS; - char *pszCtrlType = NULL; - char szDevTag[20]; - bool fBootable = true; + int rc = VINF_SUCCESS; PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); /* + * Initialize enought of the state to make the destructure not trip up. + */ + pThis->hTaskCache = NIL_RTMEMCACHE; + pThis->hEvtProcess = NIL_SUPSEMEVENT; + RTListInit(&pThis->ListMemRegns); + + /* * Validate and read configuration. */ rc = CFGMR3AreValuesValid(pCfg, "GCEnabled\0" @@ -4990,6 +5294,7 @@ static DECLCALLBACK(int) lsilogicConstruct(PPDMDEVINS pDevIns, int iInstance, PC N_("LsiLogic configuration error: failed to read RequestQueue as integer")); Log(("%s: RequestQueueDepth=%u\n", __FUNCTION__, pThis->cRequestQueueEntries)); + char *pszCtrlType; rc = CFGMR3QueryStringAllocDef(pCfg, "ControllerType", &pszCtrlType, LSILOGICSCSI_PCI_SPI_CTRLNAME); if (RT_FAILURE(rc)) @@ -4997,9 +5302,10 @@ static DECLCALLBACK(int) lsilogicConstruct(PPDMDEVINS pDevIns, int iInstance, PC N_("LsiLogic configuration error: failed to read ControllerType as string")); Log(("%s: ControllerType=%s\n", __FUNCTION__, pszCtrlType)); - rc = lsilogicGetCtrlTypeFromString(pThis, pszCtrlType); + rc = lsilogicR3GetCtrlTypeFromString(pThis, pszCtrlType); MMR3HeapFree(pszCtrlType); + char szDevTag[20]; RTStrPrintf(szDevTag, sizeof(szDevTag), "LSILOGIC%s-%u", pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI ? "SPI" : "SAS", iInstance); @@ -5024,6 +5330,7 @@ static DECLCALLBACK(int) lsilogicConstruct(PPDMDEVINS pDevIns, int iInstance, PC return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic configuration error: failed to read NumPorts as integer")); + bool fBootable; rc = CFGMR3QueryBoolDef(pCfg, "Bootable", &fBootable, true); if (RT_FAILURE(rc)) return PDMDEV_SET_ERROR(pDevIns, rc, @@ -5053,56 +5360,72 @@ static DECLCALLBACK(int) lsilogicConstruct(PPDMDEVINS pDevIns, int iInstance, PC PCIDevSetClassBase (&pThis->PciDev, 0x01); /* Mass storage */ PCIDevSetInterruptPin(&pThis->PciDev, 0x01); /* Interrupt pin A */ -#ifdef VBOX_WITH_MSI_DEVICES +# ifdef VBOX_WITH_MSI_DEVICES PCIDevSetStatus(&pThis->PciDev, VBOX_PCI_STATUS_CAP_LIST); PCIDevSetCapabilityList(&pThis->PciDev, 0x80); -#endif +# endif pThis->pDevInsR3 = pDevIns; pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns); pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); - pThis->IBase.pfnQueryInterface = lsilogicStatusQueryInterface; - pThis->ILeds.pfnQueryStatusLed = lsilogicStatusQueryStatusLed; + pThis->pSupDrvSession = PDMDevHlpGetSupDrvSession(pDevIns); + pThis->IBase.pfnQueryInterface = lsilogicR3StatusQueryInterface; + pThis->ILeds.pfnQueryStatusLed = lsilogicR3StatusQueryStatusLed; + + /* + * Create critical sections protecting the reply post and free queues. + * Note! We do our own syncronization, so NOP the default crit sect for the device. + */ + rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns)); + AssertRCReturn(rc, rc); + + rc = PDMDevHlpCritSectInit(pDevIns, &pThis->ReplyFreeQueueCritSect, RT_SRC_POS, "%sRFQ", szDevTag); + if (RT_FAILURE(rc)) + return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic: cannot create critical section for reply free queue")); + + rc = PDMDevHlpCritSectInit(pDevIns, &pThis->ReplyPostQueueCritSect, RT_SRC_POS, "%sRPQ", szDevTag); + if (RT_FAILURE(rc)) + return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic: cannot create critical section for reply post queue")); /* * Register the PCI device, it's I/O regions. */ - rc = PDMDevHlpPCIRegister (pDevIns, &pThis->PciDev); + rc = PDMDevHlpPCIRegister(pDevIns, &pThis->PciDev); if (RT_FAILURE(rc)) return rc; -#ifdef VBOX_WITH_MSI_DEVICES - PDMMSIREG aMsiReg; - RT_ZERO(aMsiReg); +# ifdef VBOX_WITH_MSI_DEVICES + PDMMSIREG MsiReg; + RT_ZERO(MsiReg); /* use this code for MSI-X support */ -#if 0 - aMsiReg.cMsixVectors = 1; - aMsiReg.iMsixCapOffset = 0x80; - aMsiReg.iMsixNextOffset = 0x0; - aMsiReg.iMsixBar = 3; -#else - aMsiReg.cMsiVectors = 1; - aMsiReg.iMsiCapOffset = 0x80; - aMsiReg.iMsiNextOffset = 0x0; -#endif - rc = PDMDevHlpPCIRegisterMsi(pDevIns, &aMsiReg); +# if 0 + MsiReg.cMsixVectors = 1; + MsiReg.iMsixCapOffset = 0x80; + MsiReg.iMsixNextOffset = 0x00; + MsiReg.iMsixBar = 3; +# else + MsiReg.cMsiVectors = 1; + MsiReg.iMsiCapOffset = 0x80; + MsiReg.iMsiNextOffset = 0x00; +# endif + rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg); if (RT_FAILURE (rc)) { LogRel(("Chipset cannot do MSI: %Rrc\n", rc)); /* That's OK, we can work without MSI */ PCIDevSetCapabilityList(&pThis->PciDev, 0x0); } -#endif +# endif - rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, LSILOGIC_PCI_SPACE_IO_SIZE, PCI_ADDRESS_SPACE_IO, lsilogicMap); + rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, LSILOGIC_PCI_SPACE_IO_SIZE, PCI_ADDRESS_SPACE_IO, lsilogicR3Map); if (RT_FAILURE(rc)) return rc; - rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, LSILOGIC_PCI_SPACE_MEM_SIZE, PCI_ADDRESS_SPACE_MEM, lsilogicMap); + rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, LSILOGIC_PCI_SPACE_MEM_SIZE, PCI_ADDRESS_SPACE_MEM, lsilogicR3Map); if (RT_FAILURE(rc)) return rc; - rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, LSILOGIC_PCI_SPACE_MEM_SIZE, PCI_ADDRESS_SPACE_MEM, lsilogicMap); + rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, LSILOGIC_PCI_SPACE_MEM_SIZE, PCI_ADDRESS_SPACE_MEM, lsilogicR3Map); if (RT_FAILURE(rc)) return rc; @@ -5110,7 +5433,7 @@ static DECLCALLBACK(int) lsilogicConstruct(PPDMDEVINS pDevIns, int iInstance, PC char szTaggedText[64]; RTStrPrintf(szTaggedText, sizeof(szTaggedText), "%s-Task", szDevTag); rc = PDMDevHlpQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 2, 0, - lsilogicNotifyQueueConsumer, true, + lsilogicR3NotifyQueueConsumer, true, szTaggedText, &pThis->pNotificationQueueR3); if (RT_FAILURE(rc)) @@ -5127,31 +5450,17 @@ static DECLCALLBACK(int) lsilogicConstruct(PPDMDEVINS pDevIns, int iInstance, PC /* * Allocate memory for the queues. */ - rc = lsilogicQueuesAlloc(pThis); + rc = lsilogicR3QueuesAlloc(pThis); if (RT_FAILURE(rc)) return rc; /* - * Create critical sections protecting the reply post and free queues. - */ - rc = PDMDevHlpCritSectInit(pDevIns, &pThis->ReplyFreeQueueCritSect, RT_SRC_POS, "%sRFQ", szDevTag); - if (RT_FAILURE(rc)) - return PDMDEV_SET_ERROR(pDevIns, rc, - N_("LsiLogic: cannot create critical section for reply free queue")); - - rc = PDMDevHlpCritSectInit(pDevIns, &pThis->ReplyPostQueueCritSect, RT_SRC_POS, "%sRPQ", szDevTag); - if (RT_FAILURE(rc)) - return PDMDEV_SET_ERROR(pDevIns, rc, - N_("LsiLogic: cannot create critical section for reply post queue")); - - /* * Allocate task cache. */ - rc = RTMemCacheCreate(&pThis->hTaskCache, sizeof(LSILOGICTASKSTATE), 0, UINT32_MAX, - lsilogicTaskStateCtor, lsilogicTaskStateDtor, NULL, 0); + rc = RTMemCacheCreate(&pThis->hTaskCache, sizeof(LSILOGICREQ), 0, UINT32_MAX, + NULL, NULL, NULL, 0); if (RT_FAILURE(rc)) - return PDMDEV_SET_ERROR(pDevIns, rc, - N_("Cannot create task cache")); + return PDMDEV_SET_ERROR(pDevIns, rc, N_("Cannot create task cache")); if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI) pThis->cDeviceStates = pThis->cPorts * LSILOGICSCSI_PCI_SPI_DEVICES_PER_BUS_MAX; @@ -5161,12 +5470,25 @@ static DECLCALLBACK(int) lsilogicConstruct(PPDMDEVINS pDevIns, int iInstance, PC AssertMsgFailed(("Invalid controller type: %d\n", pThis->enmCtrlType)); /* + * Create event semaphore and worker thread. + */ + rc = PDMDevHlpThreadCreate(pDevIns, &pThis->pThreadWrk, pThis, lsilogicR3Worker, + lsilogicR3WorkerWakeUp, 0, RTTHREADTYPE_IO, szDevTag); + if (RT_FAILURE(rc)) + return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, + N_("LsiLogic: Failed to create worker thread %s"), szDevTag); + + rc = SUPSemEventCreate(pThis->pSupDrvSession, &pThis->hEvtProcess); + if (RT_FAILURE(rc)) + return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, + N_("LsiLogic: Failed to create SUP event semaphore")); + + /* * Allocate device states. */ pThis->paDeviceStates = (PLSILOGICDEVICE)RTMemAllocZ(sizeof(LSILOGICDEVICE) * pThis->cDeviceStates); if (!pThis->paDeviceStates) - return PDMDEV_SET_ERROR(pDevIns, rc, - N_("Failed to allocate memory for device states")); + return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to allocate memory for device states")); for (unsigned i = 0; i < pThis->cDeviceStates; i++) { @@ -5177,12 +5499,12 @@ static DECLCALLBACK(int) lsilogicConstruct(PPDMDEVINS pDevIns, int iInstance, PC pDevice->iLUN = i; pDevice->pLsiLogicR3 = pThis; pDevice->Led.u32Magic = PDMLED_MAGIC; - pDevice->IBase.pfnQueryInterface = lsilogicDeviceQueryInterface; - pDevice->ISCSIPort.pfnSCSIRequestCompleted = lsilogicDeviceSCSIRequestCompleted; - pDevice->ISCSIPort.pfnQueryDeviceLocation = lsilogicQueryDeviceLocation; - pDevice->ILed.pfnQueryStatusLed = lsilogicDeviceQueryStatusLed; + pDevice->IBase.pfnQueryInterface = lsilogicR3DeviceQueryInterface; + pDevice->ISCSIPort.pfnSCSIRequestCompleted = lsilogicR3DeviceSCSIRequestCompleted; + pDevice->ISCSIPort.pfnQueryDeviceLocation = lsilogicR3QueryDeviceLocation; + pDevice->ILed.pfnQueryStatusLed = lsilogicR3DeviceQueryStatusLed; - RTStrPrintf(szName, sizeof(szName), "Device%d", i); + RTStrPrintf(szName, sizeof(szName), "Device%u", i); /* Attach SCSI driver. */ rc = PDMDevHlpDriverAttach(pDevIns, pDevice->iLUN, &pDevice->IBase, &pDevice->pDrvBase, szName); @@ -5230,13 +5552,13 @@ static DECLCALLBACK(int) lsilogicConstruct(PPDMDEVINS pDevIns, int iInstance, PC { if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI) rc = PDMDevHlpIOPortRegister(pDevIns, LSILOGIC_BIOS_IO_PORT, 4, NULL, - lsilogicIsaIOPortWrite, lsilogicIsaIOPortRead, - lsilogicIsaIOPortWriteStr, lsilogicIsaIOPortReadStr, + lsilogicR3IsaIOPortWrite, lsilogicR3IsaIOPortRead, + lsilogicR3IsaIOPortWriteStr, lsilogicR3IsaIOPortReadStr, "LsiLogic BIOS"); else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS) rc = PDMDevHlpIOPortRegister(pDevIns, LSILOGIC_SAS_BIOS_IO_PORT, 4, NULL, - lsilogicIsaIOPortWrite, lsilogicIsaIOPortRead, - lsilogicIsaIOPortWriteStr, lsilogicIsaIOPortReadStr, + lsilogicR3IsaIOPortWrite, lsilogicR3IsaIOPortRead, + lsilogicR3IsaIOPortWriteStr, lsilogicR3IsaIOPortReadStr, "LsiLogic SAS BIOS"); else AssertMsgFailed(("Invalid controller type %d\n", pThis->enmCtrlType)); @@ -5247,9 +5569,9 @@ static DECLCALLBACK(int) lsilogicConstruct(PPDMDEVINS pDevIns, int iInstance, PC /* Register save state handlers. */ rc = PDMDevHlpSSMRegisterEx(pDevIns, LSILOGIC_SAVED_STATE_VERSION, sizeof(*pThis), NULL, - NULL, lsilogicLiveExec, NULL, - NULL, lsilogicSaveExec, NULL, - NULL, lsilogicLoadExec, lsilogicLoadDone); + NULL, lsilogicR3LiveExec, NULL, + NULL, lsilogicR3SaveExec, NULL, + NULL, lsilogicR3LoadExec, lsilogicR3LoadDone); if (RT_FAILURE(rc)) return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic cannot register save state handlers")); @@ -5259,14 +5581,14 @@ static DECLCALLBACK(int) lsilogicConstruct(PPDMDEVINS pDevIns, int iInstance, PC * Register the info item. */ char szTmp[128]; - RTStrPrintf(szTmp, sizeof(szTmp), "%s%d", pDevIns->pReg->szName, pDevIns->iInstance); + RTStrPrintf(szTmp, sizeof(szTmp), "%s%u", pDevIns->pReg->szName, pDevIns->iInstance); PDMDevHlpDBGFInfoRegister(pDevIns, szTmp, pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI ? "LsiLogic SPI info." - : "LsiLogic SAS info.", lsilogicInfo); + : "LsiLogic SAS info.", lsilogicR3Info); /* Perform hard reset. */ - rc = lsilogicHardReset(pThis); + rc = lsilogicR3HardReset(pThis); AssertRC(rc); return rc; @@ -5297,31 +5619,31 @@ const PDMDEVREG g_DeviceLsiLogicSCSI = /* cbInstance */ sizeof(LSILOGICSCSI), /* pfnConstruct */ - lsilogicConstruct, + lsilogicR3Construct, /* pfnDestruct */ - lsilogicDestruct, + lsilogicR3Destruct, /* pfnRelocate */ - lsilogicRelocate, - /* pfnIOCtl */ + lsilogicR3Relocate, + /* pfnMemSetup */ NULL, /* pfnPowerOn */ NULL, /* pfnReset */ - lsilogicReset, + lsilogicR3Reset, /* pfnSuspend */ - lsilogicSuspend, + lsilogicR3Suspend, /* pfnResume */ - lsilogicResume, + lsilogicR3Resume, /* pfnAttach */ - lsilogicAttach, + lsilogicR3Attach, /* pfnDetach */ - lsilogicDetach, + lsilogicR3Detach, /* pfnQueryInterface. */ NULL, /* pfnInitComplete */ NULL, /* pfnPowerOff */ - lsilogicPowerOff, + lsilogicR3PowerOff, /* pfnSoftReset */ NULL, /* u32VersionEnd */ @@ -5354,31 +5676,31 @@ const PDMDEVREG g_DeviceLsiLogicSAS = /* cbInstance */ sizeof(LSILOGICSCSI), /* pfnConstruct */ - lsilogicConstruct, + lsilogicR3Construct, /* pfnDestruct */ - lsilogicDestruct, + lsilogicR3Destruct, /* pfnRelocate */ - lsilogicRelocate, - /* pfnIOCtl */ + lsilogicR3Relocate, + /* pfnMemSetup */ NULL, /* pfnPowerOn */ NULL, /* pfnReset */ - lsilogicReset, + lsilogicR3Reset, /* pfnSuspend */ - lsilogicSuspend, + lsilogicR3Suspend, /* pfnResume */ - lsilogicResume, + lsilogicR3Resume, /* pfnAttach */ - lsilogicAttach, + lsilogicR3Attach, /* pfnDetach */ - lsilogicDetach, + lsilogicR3Detach, /* pfnQueryInterface. */ NULL, /* pfnInitComplete */ NULL, /* pfnPowerOff */ - lsilogicPowerOff, + lsilogicR3PowerOff, /* pfnSoftReset */ NULL, /* u32VersionEnd */ |
