summaryrefslogtreecommitdiff
path: root/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp')
-rw-r--r--src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp3498
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 */