Index: /trunk/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp	(revision 45969)
+++ /trunk/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp	(revision 45970)
@@ -27,4 +27,5 @@
 #include <iprt/asm.h>
 #include <iprt/string.h>
+#include <iprt/list.h>
 #ifdef IN_RING3
 # include <iprt/memcache.h>
@@ -45,5 +46,8 @@
 *******************************************************************************/
 /** The current saved state version. */
-#define LSILOGIC_SAVED_STATE_VERSION                4
+#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. */
@@ -97,4 +101,21 @@
 /** 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;
 
 /**
@@ -170,4 +191,6 @@
     /** Flag whether the guest enabled event notification from the IOC. */
     bool                 fEventNotificationEnabled;
+    /** Flag whether the diagnostic address and RW registers are enabled. */
+    bool                 fDiagRegsEnabled;
 
     /** Queue to send tasks to R3. - R3 ptr */
@@ -308,8 +331,19 @@
     bool volatile                  fRedo;
     /** Alignment padding. */
-    bool                            afPAdding2[HC_ARCH_BITS == 32 ? 2 : 6];
+    bool                             afPadding2[HC_ARCH_BITS == 32 ? 2 : 6];
     /** List of tasks which can be redone. */
     R3PTRTYPE(volatile PLSILOGICREQ) pTasksRedoHead;
 
+    /** Current address to read from or write to in the diagnostic memory region. */
+    uint32_t                         u32DiagMemAddr;
+
+    uint32_t                         u32Padding3;
+
+    union
+    {
+        /** List of memory regions - PLSILOGICMEMREGN. */
+        RTLISTANCHOR                 ListMemRegns;
+        uint8_t                      u8Padding[2 * sizeof(RTUINTPTR)];
+    };
 } LSILOGISCSI;
 /** Pointer to the device instance data of the LsiLogic emulation. */
@@ -452,4 +486,40 @@
 }
 
+/**
+ * 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
 
@@ -481,12 +551,14 @@
 
     /* 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;
 
     lsilogicR3ConfigurationPagesFree(pThis);
@@ -555,7 +627,6 @@
     AssertRC(rc);
 
-# if 0
     /* Check for a entry in the queue. */
-    if (RT_UNLIKELY(pThis->uReplyPostQueueNextAddressRead != pThis->uReplyPostQueueNextEntryFreeWrite))
+    if (!lsilogicReplyPostQueueGetFrameCount(pThis))
     {
         /* Set error code. */
@@ -564,5 +635,4 @@
         return;
     }
-# endif
 
     /* We have a context reply. */
@@ -615,7 +685,6 @@
         AssertRC(rc);
 
-#if 0
         /* Check for a free reply frame. */
-        if (RT_UNLIKELY(pThis->uReplyFreeQueueNextAddressRead != pThis->uReplyFreeQueueNextEntryFreeWrite))
+        if (!lsilogicReplyFreeQueueGetFrameCount(pThis))
         {
             /* Set error code. */
@@ -624,5 +693,4 @@
             return;
         }
-#endif
 
         uint32_t u32ReplyFrameAddressLow = pThis->CTX_SUFF(pReplyFreeQueueBase)[pThis->uReplyFreeQueueNextAddressRead];
@@ -644,7 +712,6 @@
         AssertRC(rc);
 
-#if 0
         /* Check for a entry in the queue. */
-        if (RT_UNLIKELY(pThis->uReplyPostQueueNextAddressRead != pThis->uReplyPostQueueNextEntryFreeWrite))
+        if (!lsilogicReplyPostQueueGetFrameCount(pThis))
         {
             /* Set error code. */
@@ -653,5 +720,4 @@
             return;
         }
-#endif
 
         /* We have a address reply. Set the 31th bit to indicate that. */
@@ -677,23 +743,226 @@
 }
 
-/**
- * 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;
+#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);
+    }
+}
+
+/**
+ * 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
-        cReplyFrames = pThis->cReplyQueueEntries - pThis->uReplyFreeQueueNextAddressRead + pThis->uReplyFreeQueueNextEntryFreeWrite;
-
-    return cReplyFrames;
-}
-
-#ifdef IN_RING3
+    {
+        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;
+            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);
+            }
+            /* else: Silently fail, there is nothing we can do here and the guest might work nevertheless. */
+
+            lsilogicR3MemRegionInsert(pThis, pRegion);
+        }
+        else
+        {
+            /* 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;
+
+                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
@@ -786,5 +1055,4 @@
             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 = pThis->u32HostMFAHighAddr;
             pReply->IOCFacts.u16GlobalCredits     = pThis->cRequestQueueEntries - 1; /* One entry is always free. */
@@ -795,6 +1063,33 @@
             pReply->IOCFacts.u8MaxDevices         = pThis->cMaxDevices;
             pReply->IOCFacts.u8MaxBuses           = pThis->cMaxBuses;
-            pReply->IOCFacts.u32FwImageSize       = 0; /* No image needed. */
-            pReply->IOCFacts.u32FWVersion         = 0;
+
+            /* 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;
         }
@@ -903,4 +1198,5 @@
 
             pReply->FWDownload.u8MessageLength    = 5;
+            LogFlowFunc(("FW Download request issued\n"));
             break;
         }
@@ -917,4 +1213,5 @@
     return rc;
 }
+
 #endif /* IN_RING3 */
 
@@ -1109,4 +1406,5 @@
                 pThis->fDiagnosticEnabled = false;
                 pThis->iDiagnosticAccess  = 0;
+                pThis->fDiagRegsEnabled   = false;
             }
             else if ((u32 & 0xf) == g_lsilogicDiagnosticAccess[pThis->iDiagnosticAccess])
@@ -1131,13 +1429,40 @@
         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)
             {
-                lsilogicR3HardReset(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. */
@@ -1266,12 +1591,32 @@
         {
             if (pThis->fDiagnosticEnabled)
-                u32 = LSILOGIC_REG_HOST_DIAGNOSTIC_DRWE;
-            else
-                u32 = 0;
-            break;
+                u32 |= LSILOGIC_REG_HOST_DIAGNOSTIC_DRWE;
+            if (pThis->fDiagRegsEnabled)
+                u32 |= LSILOGIC_REG_HOST_DIAGNOSTIC_DIAG_RW_ENABLE;
+            break;
+        }
+        case LSILOGIC_REG_DIAG_RW_DATA:
+        {
+            if (pThis->fDiagRegsEnabled)
+            {
+#ifndef IN_RING3
+                return VINF_IOM_R3_MMIO_READ;
+#else
+                lsilogicR3DiagRegDataRead(pThis, &u32);
+#endif
+            }
+        }
+        case LSILOGIC_REG_DIAG_RW_ADDRESS:
+        {
+            if (pThis->fDiagRegsEnabled)
+            {
+#ifndef IN_RING3
+                return VINF_IOM_R3_MMIO_READ;
+#else
+                lsilogicR3DiagRegAddressRead(pThis, &u32);
+#endif
+            }
         }
         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. */
         {
@@ -1351,9 +1696,5 @@
 
     if (!(offReg & 3))
-    {
         rc = lsilogicRegisterWrite(pThis, offReg, u32);
-        if (rc == VINF_IOM_R3_MMIO_WRITE)
-            rc = VINF_IOM_R3_IOPORT_WRITE;
-    }
     else
     {
@@ -1455,4 +1796,13 @@
 # endif /* LOG_ENABLED */
 
+/**
+ * Walks the guest S/G buffer calling the given copy worker for every buffer.
+ *
+ * @returns nothing.
+ * @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 lsilogicSgBufWalker(PPDMDEVINS pDevIns, PLSILOGICREQ pLsiReq, size_t cbCopy,
                                 PFNLSILOGICIOBUFCOPY pfnIoBufCopy)
@@ -1505,6 +1855,6 @@
 
             pfnIoBufCopy(pDevIns, GCPhysAddrDataBuffer, pbBuf, cbCopyThis);
-            pbBuf      += cbCopyThis;
-            cbCopyThis -= cbCopyThis;
+            pbBuf  += cbCopyThis;
+            cbCopy -= cbCopyThis;
 
             /* Check if we reached the end of the list. */
@@ -1633,5 +1983,6 @@
 
     AssertMsg(   uTxDir == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE
-              || uTxDir == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ,
+              || 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"));
 
@@ -1641,5 +1992,6 @@
 
     pLsiReq->SegIoBuf.cbSeg = cbTransfer;
-    if (uTxDir == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE)
+    if (   uTxDir == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE
+        || uTxDir == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_NONE)
         lsilogicCopyFromSgBuf(pDevIns, pLsiReq, cbTransfer);
 
@@ -1662,8 +2014,10 @@
 
     AssertMsg(   uTxDir == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE
-              || uTxDir == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ,
+              || 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"));
 
-    if (   uTxDir == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ
+    if (   (   uTxDir == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ
+            || uTxDir == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_NONE)
         && fCopyToGuest)
         lsilogicCopyToSgBuf(pDevIns, pLsiReq, pLsiReq->SegIoBuf.cbSeg);
@@ -1953,5 +2307,5 @@
                 pLsiReq->IOCReply.SCSIIOError.u32ResponseInfo     = 0;
 
-                lsilogicFinishAddressReply(pThis, &pLsiReq->IOCReply, true);
+                lsilogicFinishAddressReply(pThis, &pLsiReq->IOCReply, false);
             }
         }
@@ -3958,4 +4312,16 @@
     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;
 
@@ -4078,4 +4444,6 @@
 
     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)
@@ -4244,4 +4612,41 @@
 
         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;
+
+                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);
+                }
+                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 */
@@ -4737,4 +5142,5 @@
 
     lsilogicR3ConfigurationPagesFree(pThis);
+    lsilogicR3MemRegionsFree(pThis);
 
     return VINF_SUCCESS;
@@ -4754,4 +5160,5 @@
      */
     pThis->hTaskCache = NIL_RTMEMCACHE;
+    RTListInit(&pThis->ListMemRegns);
 
     /*
Index: /trunk/src/VBox/Devices/Storage/DevLsiLogicSCSI.h
===================================================================
--- /trunk/src/VBox/Devices/Storage/DevLsiLogicSCSI.h	(revision 45969)
+++ /trunk/src/VBox/Devices/Storage/DevLsiLogicSCSI.h	(revision 45970)
@@ -1153,4 +1153,67 @@
 AssertCompileSize(MptReplyUnion, 60);
 
+/**
+ * Firmware image header.
+ */
+#pragma pack(1)
+typedef struct FwImageHdr
+{
+    /** ARM branch instruction. */
+    uint32_t    u32ArmBrInsn;
+    /** Signature part 1. */
+    uint32_t    u32Signature1;
+    /** Signature part 2. */
+    uint32_t    u32Signature2;
+    /** Signature part 3. */
+    uint32_t    u32Signature3;
+    /** Another ARM branch instruction. */
+    uint32_t    u32ArmBrInsn2;
+    /** Yet another ARM branch instruction. */
+    uint32_t    u32ArmBrInsn3;
+    /** Reserved. */
+    uint32_t    u32Reserved;
+    /** Checksum of the image. */
+    uint32_t    u32Checksum;
+    /** Vendor ID. */
+    uint16_t    u16VendorId;
+    /** Product ID. */
+    uint16_t    u16ProductId;
+    /** Firmware version. */
+    uint32_t    u32FwVersion;
+    /** Firmware sequencer Code version. */
+    uint32_t    u32SeqCodeVersion;
+    /** Image size in bytes including the header. */
+    uint32_t    u32ImageSize;
+    /** Offset of the first extended image header. */
+    uint32_t    u32NextImageHeaderOffset;
+    /** Start address of the image in IOC memory. */
+    uint32_t    u32LoadStartAddress;
+    /** Absolute start address of the Iop ARM. */
+    uint32_t    u32IopResetVectorValue;
+    /** Address of the IopResetVector register. */
+    uint32_t    u32IopResetVectorRegAddr;
+    /** Marker value for what utility. */
+    uint32_t    u32VersionNameWhat;
+    /** ASCII string of version. */
+    uint8_t     aszVersionName[256];
+    /** Marker value for what utility. */
+    uint32_t    u32VendorNameWhat;
+    /** ASCII string of vendor name. */
+    uint8_t     aszVendorName[256];
+} FwImageHdr, *PFwImageHdr;
+#pragma pack()
+AssertCompileSize(FwImageHdr, 584);
+
+/** First part of the signature. */
+#define LSILOGIC_FWIMGHDR_SIGNATURE1 UINT32_C(0x5aeaa55a)
+/** Second part of the signature. */
+#define LSILOGIC_FWIMGHDR_SIGNATURE2 UINT32_C(0xa55aeaa5)
+/** Third part of the signature. */
+#define LSILOGIC_FWIMGHDR_SIGNATURE3 UINT32_C(0x5aa55aea)
+/** Load address of the firmware image to watch for,
+ * seen used by Solaris 9. When this value is written to the
+ * diagnostic address register we know a firmware image is downloaded.
+ */
+#define LSILOGIC_FWIMGHDR_LOAD_ADDRESS UINT32_C(0x21ff5e00)
 
 /**
Index: /trunk/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
===================================================================
--- /trunk/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp	(revision 45969)
+++ /trunk/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp	(revision 45970)
@@ -1563,4 +1563,5 @@
     GEN_CHECK_OFF(LSILOGICSCSI, fNotificationSend);
     GEN_CHECK_OFF(LSILOGICSCSI, fEventNotificationEnabled);
+    GEN_CHECK_OFF(LSILOGICSCSI, fDiagRegsEnabled);
     GEN_CHECK_OFF(LSILOGICSCSI, pNotificationQueueR3);
     GEN_CHECK_OFF(LSILOGICSCSI, pNotificationQueueR0);
@@ -1616,4 +1617,6 @@
     GEN_CHECK_OFF(LSILOGICSCSI, fRedo);
     GEN_CHECK_OFF(LSILOGICSCSI, pTasksRedoHead);
+    GEN_CHECK_OFF(LSILOGICSCSI, u32DiagMemAddr);
+    GEN_CHECK_OFF(LSILOGICSCSI, ListMemRegns);
 #endif /* VBOX_WITH_LSILOGIC */
 
