qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH] hw: Add support for new LSI Logic devices.


From: Gerhard Wiesinger
Subject: Re: [Qemu-devel] [PATCH] hw: Add support for new LSI Logic devices.
Date: Thu, 08 Nov 2012 20:03:07 +0100
User-agent: Mozilla/5.0 (Windows NT 6.0; WOW64; rv:16.0) Gecko/20121026 Thunderbird/16.0.2

Tested Don's latest patch and also with his non submitted seabios patch.

XP, Linux: Tested-by: Gerhard Wiesinger <address@hidden>

Please integrate it. I think we should get more speed here.

Ciao,
Gerhard

On 11.09.2012 19:00, Don Slutz wrote:
Add LSI53C1030, SAS1068, SAS1068e.  Based on code from "VirtualBox Open Source 
Edition".
Based on QEMU MegaRAID SAS 8708EM2.

This is a common VMware disk controller.

SEABIOS change for booting is in the works.

Tested with Fedora 16, 17.  CentoOS 6. Windows 2003R2 and 2008R2.

Signed-off-by: Don Slutz <address@hidden>
---
  default-configs/pci.mak |    1 +
  hw/Makefile.objs        |    1 +
  hw/lsilogic.c           | 2743 ++++++++++++++++++++++++++++++++++++++
  hw/lsilogic.h           | 3365 +++++++++++++++++++++++++++++++++++++++++++++++
  hw/pci_ids.h            |    4 +
  trace-events            |   26 +
  6 files changed, 6140 insertions(+), 0 deletions(-)
  create mode 100644 hw/lsilogic.c
  create mode 100644 hw/lsilogic.h

diff --git a/default-configs/pci.mak b/default-configs/pci.mak
index 69e18f1..ae4873d 100644
--- a/default-configs/pci.mak
+++ b/default-configs/pci.mak
@@ -11,6 +11,7 @@ CONFIG_PCNET_PCI=y
  CONFIG_PCNET_COMMON=y
  CONFIG_LSI_SCSI_PCI=y
  CONFIG_MEGASAS_SCSI_PCI=y
+CONFIG_LSILOGIC_SCSI_PCI=y
  CONFIG_RTL8139_PCI=y
  CONFIG_E1000_PCI=y
  CONFIG_IDE_CORE=y
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 6dfebd2..e5f939c 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -115,6 +115,7 @@ hw-obj-$(CONFIG_OPENCORES_ETH) += opencores_eth.o
  # SCSI layer
  hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o
  hw-obj-$(CONFIG_MEGASAS_SCSI_PCI) += megasas.o
+hw-obj-$(CONFIG_LSILOGIC_SCSI_PCI) += lsilogic.o
  hw-obj-$(CONFIG_ESP) += esp.o
  hw-obj-$(CONFIG_ESP_PCI) += esp-pci.o
diff --git a/hw/lsilogic.c b/hw/lsilogic.c
new file mode 100644
index 0000000..1c0a54f
--- /dev/null
+++ b/hw/lsilogic.c
@@ -0,0 +1,2743 @@
+/*
+ * QEMU LSILOGIC LSI53C1030 SCSI and SAS1068 Host Bus Adapter emulation
+ * Based on the QEMU Megaraid emulator and the VirtualBox LsiLogic
+ * LSI53c1030 SCSI controller
+ *
+ * Copyright (c) 2009-2012 Hannes Reinecke, SUSE Labs
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Id: DevLsiLogicSCSI.cpp 40642 2012-03-26 13:14:08Z vboxsync $ */
+/** @file
+ * VBox storage devices: LsiLogic LSI53c1030 SCSI controller.
+ */
+
+/*
+ * Copyright (C) 2006-2009 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+#include "hw.h"
+#include "pci.h"
+#include "dma.h"
+#include "msix.h"
+#include "iov.h"
+#include "scsi.h"
+#include "scsi-defs.h"
+#include "block_int.h"
+#include "trace.h"
+
+#include "lsilogic.h"
+
+#define RT_ELEMENTS(aArray)        (sizeof(aArray) / sizeof((aArray)[0]))
+
+#define LSILOGIC_MAX_FRAMES 2048     /* Firmware limit at 65535 */
+
+#define NAA_LOCALLY_ASSIGNED_ID 0x3ULL
+#define IEEE_COMPANY_LOCALLY_ASSIGNED 0x525400
+
+#define LSILOGIC_FLAG_USE_MSIX      0
+#define LSILOGIC_MASK_USE_MSIX      (1 << LSILOGIC_FLAG_USE_MSIX)
+#define LSILOGIC_FLAG_USE_QUEUE64   1
+#define LSILOGIC_MASK_USE_QUEUE64   (1 << LSILOGIC_FLAG_USE_QUEUE64)
+#define LSILOGIC_CMD_BUSY   (1 << 0)
+
+typedef struct LsilogicCmd {
+    uint32_t index;
+    uint16_t flags;
+    uint16_t count;
+    uint64_t context;
+
+    target_phys_addr_t host_msg_frame_pa;
+    MptRequestUnion request;
+    MptReplyUnion reply;
+    SCSIRequest *req;
+    QEMUSGList qsg;
+    uint32_t sge_cnt;
+    void *iov_buf;
+    size_t iov_size;
+    size_t iov_offset;
+    struct LsilogicState *state;
+} LsilogicCmd;
+
+typedef struct Lsilogic_device {
+    struct LsilogicState *pLsiLogic;
+
+    uint32_t iLUN;
+    uint32_t cOutstandingRequests;
+    uint32_t *pDrvBase;
+} Lsilogic_device;
+
+typedef struct LsilogicState {
+    PCIDevice dev;
+    MemoryRegion mmio_io;
+    MemoryRegion port_io;
+    MemoryRegion diag_io;
+
+    MptConfigurationPagesSupported *config_pages;
+
+    LSILOGICCTRLTYPE ctrl_type;
+    LSILOGICSTATE state;
+    LSILOGICWHOINIT who_init;
+    uint16_t next_handle;
+    uint32_t ports;
+    uint32_t flags;
+    uint32_t intr_mask;
+    uint32_t intr_status;
+    uint32_t doorbell;
+    uint32_t busy;
+    bool     event_notification_enabled;
+    bool     diagnostic_enabled;
+    uint32   diagnostic_access_idx;
+    /** Maximum number of devices the driver reported he can handle. */
+    uint16_t max_devices;
+    /** Maximum number of buses the driver reported he can handle. */
+    uint16_t max_buses;
+
+    uint64_t sas_addr;
+
+     /* Buffer for messages which are passed through the doorbell
+      * using the handshake method.
+      */
+    uint32_t drbl_message[(sizeof(MptRequestUnion)+sizeof(uint32_t)-1)/
+                                sizeof(uint32_t)];
+    uint16_t drbl_message_index;
+    uint16_t drbl_message_size; /** Size of the message in dwords. */
+
+    MptReplyUnion reply_buffer;
+    uint16_t next_reply_entry_read;
+    uint16_t reply_size;        /* in 16bit words. */
+
+    uint16_t IOC_fault_code;    /* if we are in the fault state. */
+    /** Current size of reply message frames in the guest. */
+    uint16_t reply_frame_size;
+    /** Upper 32 bits of the message frame address to
+        locate requests in guest memory. */
+    uint32_t host_mfa_high_addr;
+    /** Upper 32 bits of the sense buffer address. */
+    uint32_t sense_buffer_high_addr;
+
+    uint32_t reply_queue_entries;
+    uint32_t request_queue_entries;
+
+    uint32_t *reply_post_queue;
+    uint32_t *reply_free_queue;
+    uint32_t *request_queue;
+    uint32_t reply_free_queue_next_entry_free_write;
+    uint32_t reply_free_queue_next_address_read;
+
+    uint32_t reply_post_queue_next_entry_free_write;
+    uint32_t reply_post_queue_next_address_read;
+
+    uint32_t request_queue_next_entry_free_write;
+    uint32_t request_queue_next_address_read;
+
+    uint32_t next_frame;
+    LsilogicCmd * frames[LSILOGIC_MAX_FRAMES];
+
+    SCSIBus bus;
+} LsilogicState;
+
+#define LSILOGIC_INTR_DISABLED_MASK 0xFFFFFFFF
+
+static bool lsilogic_use_msix(LsilogicState *s)
+{
+    return s->flags & LSILOGIC_MASK_USE_MSIX;
+}
+
+static bool lsilogic_is_sas(LsilogicState *s)
+{
+    return true;
+}
+
+static uint16_t lsilogicGetHandle(LsilogicState *s)
+{
+    uint16_t u16Handle = s->next_handle++;
+    return u16Handle;
+}
+
+static void lsilogic_soft_reset(LsilogicState *s);
+
+static void lsilogic_update_interrupt(LsilogicState *s)
+{
+    uint32_t uIntSts;
+
+    uIntSts = (s->intr_status & ~LSILOGIC_REG_HOST_INTR_STATUS_DOORBELL_STS);
+    uIntSts &= ~(s->intr_mask & ~LSILOGIC_REG_HOST_INTR_MASK_IRQ_ROUTING);
+
+    if (uIntSts) {
+        if (msix_enabled(&s->dev)) {
+            trace_lsilogic_msix_raise(0);
+            msix_notify(&s->dev, 0);
+        } else {
+            trace_lsilogic_irq_raise();
+            qemu_irq_raise(s->dev.irq[0]);
+        }
+    } else if (!msix_enabled(&s->dev)) {
+        trace_lsilogic_irq_lower();
+        qemu_irq_lower(s->dev.irq[0]);
+    }
+}
+
+static void lsilogic_finish_address_reply(LsilogicState *s,
+        MptReplyUnion *reply, 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 (s->doorbell && !fForceReplyFifo) {
+        /* Set size of the reply in 16bit words.
+           The size in the reply is in 32bit dwords. */
+        s->reply_size = reply->Header.u8MessageLength * 2;
+        s->next_reply_entry_read = 0;
+        s->intr_status |= LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL;
+        lsilogic_update_interrupt(s);
+    } else {
+        /* Grab a free reply message from the queue. */
+
+        /* Check for a free reply frame and room on the post queue. */
+        if ((s->reply_free_queue_next_address_read ==
+                s->reply_free_queue_next_entry_free_write)) {
+            s->IOC_fault_code = LSILOGIC_IOCSTATUS_INSUFFICIENT_RESOURCES;
+            s->state = LSILOGICSTATE_FAULT;
+            return;
+        }
+        uint32_t reply_frame_address_low =
+                s->reply_free_queue[s->reply_free_queue_next_address_read];
+
+        uint32_t next_addr = (s->reply_free_queue_next_address_read + 1) %
+                s->reply_queue_entries;
+        if (next_addr != s->reply_free_queue_next_entry_free_write) {
+            s->reply_free_queue_next_address_read = next_addr;
+        }
+
+        uint64_t reply_message_pa = ((uint64_t)s->host_mfa_high_addr << 32) |
+                reply_frame_address_low;
+        int reply_copied = (s->reply_frame_size < sizeof(MptReplyUnion)) ?
+                s->reply_frame_size : sizeof(MptReplyUnion);
+
+        cpu_physical_memory_write((target_phys_addr_t)reply_message_pa,
+                (uint8_t *)reply, reply_copied);
+
+        /* Write low 32bits of reply frame into post reply queue. */
+
+        /* We have a address reply. Set the 31th bit to indicate that. */
+        s->reply_post_queue[s->reply_post_queue_next_entry_free_write++] =
+                (1<<31) | (reply_frame_address_low >> 1);
+        s->reply_post_queue_next_entry_free_write %= s->reply_queue_entries;
+
+        if (fForceReplyFifo) {
+            s->doorbell = false;
+            s->intr_status |= LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL;
+        }
+
+        /* Set interrupt. */
+        s->intr_status |= LSILOGIC_REG_HOST_INTR_STATUS_REPLY_INTR;
+        lsilogic_update_interrupt(s);
+    }
+}
+
+static void lsilogic_abort_command(LsilogicCmd *cmd)
+{
+    if (cmd->req) {
+        scsi_req_cancel(cmd->req);
+        cmd->req = NULL;
+    }
+}
+
+
+static QEMUSGList *lsilogic_get_sg_list(SCSIRequest *req)
+{
+    LsilogicCmd *cmd = req->hba_private;
+
+    if (cmd->sge_cnt == 0) {
+        return NULL;
+    } else {
+        return &cmd->qsg;
+    }
+}
+
+static void lsilogic_xfer_complete(SCSIRequest *req, uint32_t len)
+{
+    LsilogicCmd *cmd = req->hba_private;
+
+    trace_lsilogic_io_complete(cmd->index, len);
+    if (cmd->sge_cnt != 0) {
+        scsi_req_continue(req);
+        return;
+    }
+}
+
+static void lsilogic_finish_context_reply(LsilogicState *s,
+        uint32_t u32MessageContext)
+{
+    assert(!s->doorbell);
+
+    /* Write message context ID into reply post queue. */
+    s->reply_post_queue[s->reply_post_queue_next_entry_free_write++] =
+        u32MessageContext;
+    s->reply_post_queue_next_entry_free_write %= s->reply_queue_entries;
+
+    s->intr_status |= LSILOGIC_REG_HOST_INTR_STATUS_REPLY_INTR;
+    lsilogic_update_interrupt(s);
+}
+
+static void lsilogic_command_complete(SCSIRequest *req,
+        uint32_t status, size_t resid)
+{
+    LsilogicCmd *cmd = req->hba_private;
+    uint8_t sense_buf[SCSI_SENSE_BUF_SIZE];
+    uint8_t sense_len;
+
+    target_phys_addr_t sense_buffer_pa =
+        cmd->request.SCSIIO.u32SenseBufferLowAddress |
+            ((uint64_t)cmd->state->sense_buffer_high_addr << 32);
+
+    trace_lsilogic_command_complete(cmd->index, status, resid);
+
+    if (cmd->sge_cnt) {
+        qemu_sglist_destroy(&cmd->qsg);
+    }
+
+    sense_len = scsi_req_get_sense(cmd->req, sense_buf,
+        SCSI_SENSE_BUF_SIZE);
+    req->status = status;
+    trace_lsilogic_scsi_complete(cmd->index, req->status,
+        cmd->iov_size, req->cmd.xfer);
+
+    if (sense_len > 0) {
+        cpu_physical_memory_write(sense_buffer_pa, sense_buf,
+                MIN(cmd->request.SCSIIO.u8SenseBufferLength, sense_len));
+    }
+
+    if (req->status != GOOD) {
+        /* The SCSI target encountered an error during processing.
+                Post a reply. */
+        memset(&cmd->reply, 0, sizeof(MptReplyUnion));
+        cmd->reply.SCSIIOError.u8TargetID          =
+                cmd->request.SCSIIO.u8TargetID;
+        cmd->reply.SCSIIOError.u8Bus               =
+                cmd->request.SCSIIO.u8Bus;
+        cmd->reply.SCSIIOError.u8MessageLength     = 8;
+        cmd->reply.SCSIIOError.u8Function          =
+                cmd->request.SCSIIO.u8Function;
+        cmd->reply.SCSIIOError.u8CDBLength         =
+                cmd->request.SCSIIO.u8CDBLength;
+        cmd->reply.SCSIIOError.u8SenseBufferLength =
+                cmd->request.SCSIIO.u8SenseBufferLength;
+        cmd->reply.SCSIIOError.u8MessageFlags      =
+                cmd->request.SCSIIO.u8MessageFlags;
+        cmd->reply.SCSIIOError.u32MessageContext   =
+                cmd->request.SCSIIO.u32MessageContext;
+        cmd->reply.SCSIIOError.u8SCSIStatus        = req->status;
+        cmd->reply.SCSIIOError.u8SCSIState         =
+                MPT_SCSI_IO_ERROR_SCSI_STATE_AUTOSENSE_VALID;
+        cmd->reply.SCSIIOError.u16IOCStatus        = 0;
+        cmd->reply.SCSIIOError.u32IOCLogInfo       = 0;
+        cmd->reply.SCSIIOError.u32TransferCount    = 0;
+        cmd->reply.SCSIIOError.u32SenseCount       = sense_len;
+        cmd->reply.SCSIIOError.u32ResponseInfo     = 0;
+
+        lsilogic_finish_address_reply(cmd->state, &cmd->reply, true);
+    } else {
+        lsilogic_finish_context_reply(cmd->state,
+                cmd->request.SCSIIO.u32MessageContext);
+    }
+
+    scsi_req_unref(cmd->req);
+    cmd->req = NULL;
+    g_free(cmd);
+}
+
+static void lsilogic_command_cancel(SCSIRequest *req)
+{
+    LsilogicCmd *cmd = req->hba_private;
+
+    if (cmd) {
+        lsilogic_abort_command(cmd);
+    } else {
+        scsi_req_unref(req);
+    }
+}
+
+static void lsilogic_map_sgl(LsilogicState *s, LsilogicCmd *cmd,
+        target_phys_addr_t sgl_pa, uint32_t chain_offset)
+{
+    uint32_t iov_count = 0;
+    bool do_mapping = false;
+    uint32_t pass;
+
+    for (pass = 0; pass < 2; pass++) {
+        bool end_of_list = false;
+        target_phys_addr_t next_sge_pa = sgl_pa;
+        target_phys_addr_t seg_start_pa = sgl_pa;
+        uint32_t next_chain_offset = chain_offset;
+
+        if (do_mapping) {
+            cmd->sge_cnt = iov_count;
+            qemu_sglist_init(&cmd->qsg, iov_count, pci_dma_context(&s->dev));
+        }
+        while (end_of_list == false) {
+            bool end_of_seg = false;
+
+            while (end_of_seg == false) {
+                MptSGEntryUnion sge;
+                cpu_physical_memory_read(next_sge_pa, &sge,
+                        sizeof(MptSGEntryUnion));
+                assert(sge.Simple32.u2ElementType == MPTSGENTRYTYPE_SIMPLE);
+                if (sge.Simple32.u24Length == 0 && sge.Simple32.fEndOfList &&
+                                sge.Simple32.fEndOfBuffer) {
+                    cmd->sge_cnt = 0;
+                    return;
+                }
+                if (sge.Simple32.f64BitAddress) {
+                    next_sge_pa += sizeof(MptSGEntrySimple64);
+                } else {
+                    next_sge_pa += sizeof(MptSGEntrySimple32);
+                }
+                if (do_mapping) {
+                    dma_addr_t iov_pa = sge.Simple32.u32DataBufferAddressLow;
+                    dma_addr_t iov_size = sge.Simple32.u24Length;
+
+                    if (sge.Simple32.f64BitAddress) {
+                        iov_pa |= ((uint64_t)sge.Simple64.
+                                u32DataBufferAddressHigh) << 32;
+                    }
+
+                    qemu_sglist_add(&cmd->qsg, iov_pa, iov_size);
+                }
+                iov_count++;
+                if (sge.Simple32.fEndOfList) {
+                    end_of_seg = true;
+                    end_of_list = true;
+                } else if (sge.Simple32.fLastElement) {
+                    end_of_seg = true;
+                }
+            }
+            if (next_chain_offset) {
+                MptSGEntryChain sgec;
+                cpu_physical_memory_read(seg_start_pa + next_chain_offset,
+                        &sgec, sizeof(MptSGEntryChain));
+                assert(sgec.u2ElementType == MPTSGENTRYTYPE_CHAIN);
+                next_sge_pa = sgec.u32SegmentAddressLow;
+                if (sgec.f64BitAddress) {
+                    next_sge_pa |=
+                        ((uint64_t)sgec.u32SegmentAddressHigh) << 32;
+                }
+                seg_start_pa = next_sge_pa;
+                next_chain_offset = sgec.u8NextChainOffset * sizeof(uint32_t);
+            }
+        }
+        do_mapping = true;
+    }
+}
+
+static int lsilogic_process_SCSIIO_Request(LsilogicState *s, LsilogicCmd *cmd)
+{
+    struct SCSIDevice *sdev = NULL;
+
+    if (cmd->request.SCSIIO.u8TargetID < s->max_devices &&
+                cmd->request.SCSIIO.u8Bus == 0) {
+        sdev = scsi_device_find(&s->bus, 0, cmd->request.SCSIIO.u8TargetID,
+                                cmd->request.SCSIIO.au8LUN[1]);
+        cmd->iov_size = le32_to_cpu(cmd->request.SCSIIO.u32DataLength);
+        trace_lsilogic_handle_scsi("SCSI IO", 0,
+                cmd->request.SCSIIO.u8TargetID,
+                cmd->request.SCSIIO.au8LUN[1], sdev, cmd->iov_size);
+        if (sdev) {
+            uint32_t chain_offset = cmd->request.SCSIIO.u8ChainOffset;
+            int32_t len;
+            bool is_write;
+
+            if (chain_offset) {
+                chain_offset = chain_offset * sizeof(uint32_t) -
+                        sizeof(MptSCSIIORequest);
+            }
+
+            lsilogic_map_sgl(s, cmd, cmd->host_msg_frame_pa +
+                        sizeof(MptSCSIIORequest), chain_offset);
+            is_write = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_GET(
+                        cmd->request.SCSIIO.u32Control) ==
+                                MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE ?
+                        true : false;
+            cmd->state = s;
+            cmd->req = scsi_req_new(sdev, cmd->index++,
+                            cmd->request.SCSIIO.au8LUN[1],
+                                cmd->request.SCSIIO.au8CDB, cmd);
+            len = scsi_req_enqueue(cmd->req);
+            if (len < 0) {
+                len = -len;
+            }
+            if (len > 0) {
+                if (len > cmd->iov_size) {
+                    if (is_write) {
+                        trace_lsilogic_iov_write_overflow(cmd->index, len,
+                                cmd->iov_size);
+                    } else {
+                        trace_lsilogic_iov_read_overflow(cmd->index, len,
+                                cmd->iov_size);
+                    }
+                }
+                if (len < cmd->iov_size) {
+                    if (is_write) {
+                        trace_lsilogic_iov_write_underflow(cmd->index, len,
+                                cmd->iov_size);
+                    } else {
+                        trace_lsilogic_iov_read_underflow(cmd->index, len,
+                                cmd->iov_size);
+                    }
+                    cmd->iov_size = len;
+                }
+                scsi_req_continue(cmd->req);
+            }
+            if (len > 0) {
+                if (is_write) {
+                    trace_lsilogic_scsi_write_start(cmd->index, len);
+                } else {
+                    trace_lsilogic_scsi_read_start(cmd->index, len);
+                }
+            } else {
+                trace_lsilogic_scsi_nodata(cmd->index);
+            }
+            return 0;
+        } else {
+            cmd->reply.SCSIIOError.u16IOCStatus =
+                MPT_SCSI_IO_ERROR_IOCSTATUS_DEVICE_NOT_THERE;
+        }
+    } else {
+        if (cmd->request.SCSIIO.u8Bus != 0) {
+            cmd->reply.SCSIIOError.u16IOCStatus =
+                MPT_SCSI_IO_ERROR_IOCSTATUS_INVALID_BUS;
+        } else {
+            cmd->reply.SCSIIOError.u16IOCStatus =
+                MPT_SCSI_IO_ERROR_IOCSTATUS_INVALID_TARGETID;
+        }
+    }
+    cmd->reply.SCSIIOError.u8TargetID          =
+        cmd->request.SCSIIO.u8TargetID;
+    cmd->reply.SCSIIOError.u8Bus               =
+        cmd->request.SCSIIO.u8Bus;
+    cmd->reply.SCSIIOError.u8MessageLength     =
+        sizeof(MptSCSIIOErrorReply) / 4;
+    cmd->reply.SCSIIOError.u8Function          =
+        cmd->request.SCSIIO.u8Function;
+    cmd->reply.SCSIIOError.u8CDBLength         =
+        cmd->request.SCSIIO.u8CDBLength;
+    cmd->reply.SCSIIOError.u8SenseBufferLength =
+        cmd->request.SCSIIO.u8SenseBufferLength;
+    cmd->reply.SCSIIOError.u32MessageContext   =
+        cmd->request.SCSIIO.u32MessageContext;
+    cmd->reply.SCSIIOError.u8SCSIStatus        = GOOD;
+    cmd->reply.SCSIIOError.u8SCSIState         =
+        MPT_SCSI_IO_ERROR_SCSI_STATE_TERMINATED;
+    cmd->reply.SCSIIOError.u32IOCLogInfo       = 0;
+    cmd->reply.SCSIIOError.u32TransferCount    = 0;
+    cmd->reply.SCSIIOError.u32SenseCount       = 0;
+    cmd->reply.SCSIIOError.u32ResponseInfo     = 0;
+
+    lsilogic_finish_address_reply(s, &cmd->reply, false);
+    g_free(cmd);
+
+    return 0;
+}
+
+static void lsilogic_process_message(LsilogicState *s, MptMessageHdr *msg,
+        MptReplyUnion *reply);
+
+static bool lsilogic_queue_consumer(LsilogicState *s)
+{
+    /* Only process request which arrived before we
+        received the notification. */
+    uint32_t uRequestQueueNextEntryWrite =
+        s->request_queue_next_entry_free_write;
+
+    /* Go through the messages now and process them. */
+    while ((s->state == LSILOGICSTATE_OPERATIONAL)
+           && (s->request_queue_next_address_read !=
+                uRequestQueueNextEntryWrite)) {
+        uint32_t u32RequestMessageFrameDesc =
+                s->request_queue[s->request_queue_next_address_read];
+        MptRequestUnion request;
+        target_phys_addr_t host_msg_frame_pa;
+
+
+        host_msg_frame_pa = ((uint64_t)s->host_mfa_high_addr) << 32 |
+                (u32RequestMessageFrameDesc & ~0x03);
+
+        /* Read the message header from the guest first. */
+        cpu_physical_memory_read(host_msg_frame_pa, &request.Header,
+                sizeof(MptMessageHdr));
+
+        /* Determine the size of the request. */
+        uint32_t cbRequest = 0;
+
+        switch (request.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_FW_DOWNLOAD:
+            cbRequest = sizeof(MptFWDownloadRequest);
+            break;
+        case MPT_MESSAGE_HDR_FUNCTION_FW_UPLOAD:
+            cbRequest = sizeof(MptFWUploadRequest);
+            break;
+        case MPT_MESSAGE_HDR_FUNCTION_EVENT_ACK:
+        default:
+            if (s->state != LSILOGICSTATE_FAULT) {
+                s->IOC_fault_code = LSILOGIC_IOCSTATUS_INVALID_FUNCTION;
+                s->state = LSILOGICSTATE_FAULT;
+            }
+        }
+
+        if (cbRequest != 0) {
+            /* Handle SCSI I/O requests seperately. */
+            if (request.Header.u8Function ==
+                        MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST) {
+                LsilogicCmd *cmd = g_malloc0(sizeof(LsilogicCmd));
+                cpu_physical_memory_read(host_msg_frame_pa,
+                        &cmd->request.Header, cbRequest);
+                cmd->host_msg_frame_pa = host_msg_frame_pa;
+                lsilogic_process_SCSIIO_Request(s, cmd);
+            } else {
+                MptReplyUnion Reply;
+                cpu_physical_memory_read(host_msg_frame_pa, &request.Header,
+                        cbRequest);
+                lsilogic_process_message(s, &request.Header, &Reply);
+            }
+
+        }
+        s->request_queue_next_address_read++;
+        s->request_queue_next_address_read %= s->request_queue_entries;
+    }
+
+    return true;
+}
+
+
+static int lsilogic_hard_reset(LsilogicState *s);
+
+static int lsilogic_config_unit_page(LsilogicState *pLsiLogic,
+                            PMptConfigurationPagesSupported pPages,
+                            uint8_t u8PageNumber,
+                            PMptConfigurationPageHeader *ppPageHeader,
+                            uint8_t **ppbPageData, size_t *pcbPage)
+{
+    int rc = 0;
+
+    switch (u8PageNumber) {
+    case 0:
+        *ppPageHeader = &pPages->IOUnitPage0.u.fields.Header;
+        *ppbPageData  =  pPages->IOUnitPage0.u.abPageData;
+        *pcbPage      = sizeof(pPages->IOUnitPage0);
+        break;
+    case 1:
+        *ppPageHeader = &pPages->IOUnitPage1.u.fields.Header;
+        *ppbPageData  =  pPages->IOUnitPage1.u.abPageData;
+        *pcbPage      = sizeof(pPages->IOUnitPage1);
+        break;
+    case 2:
+        *ppPageHeader = &pPages->IOUnitPage2.u.fields.Header;
+        *ppbPageData  =  pPages->IOUnitPage2.u.abPageData;
+        *pcbPage      = sizeof(pPages->IOUnitPage2);
+        break;
+    case 3:
+        *ppPageHeader = &pPages->IOUnitPage3.u.fields.Header;
+        *ppbPageData  =  pPages->IOUnitPage3.u.abPageData;
+        *pcbPage      = sizeof(pPages->IOUnitPage3);
+        break;
+    case 4:
+        *ppPageHeader = &pPages->IOUnitPage4.u.fields.Header;
+        *ppbPageData  =  pPages->IOUnitPage4.u.abPageData;
+        *pcbPage      = sizeof(pPages->IOUnitPage4);
+        break;
+    default:
+        rc = -1;
+    }
+
+    return rc;
+}
+
+static int lsilogic_config_ioc_page(LsilogicState *pLsiLogic,
+                         PMptConfigurationPagesSupported pPages,
+                         uint8_t u8PageNumber,
+                         PMptConfigurationPageHeader *ppPageHeader,
+                         uint8_t **ppbPageData, size_t *pcbPage)
+{
+    int rc = 0;
+
+    switch (u8PageNumber) {
+    case 0:
+        *ppPageHeader = &pPages->IOCPage0.u.fields.Header;
+        *ppbPageData  =  pPages->IOCPage0.u.abPageData;
+        *pcbPage      = sizeof(pPages->IOCPage0);
+        break;
+    case 1:
+        *ppPageHeader = &pPages->IOCPage1.u.fields.Header;
+        *ppbPageData  =  pPages->IOCPage1.u.abPageData;
+        *pcbPage      = sizeof(pPages->IOCPage1);
+        break;
+    case 2:
+        *ppPageHeader = &pPages->IOCPage2.u.fields.Header;
+        *ppbPageData  =  pPages->IOCPage2.u.abPageData;
+        *pcbPage      = sizeof(pPages->IOCPage2);
+        break;
+    case 3:
+        *ppPageHeader = &pPages->IOCPage3.u.fields.Header;
+        *ppbPageData  =  pPages->IOCPage3.u.abPageData;
+        *pcbPage      = sizeof(pPages->IOCPage3);
+        break;
+    case 4:
+        *ppPageHeader = &pPages->IOCPage4.u.fields.Header;
+        *ppbPageData  =  pPages->IOCPage4.u.abPageData;
+        *pcbPage      = sizeof(pPages->IOCPage4);
+        break;
+    case 6:
+        *ppPageHeader = &pPages->IOCPage6.u.fields.Header;
+        *ppbPageData  =  pPages->IOCPage6.u.abPageData;
+        *pcbPage      = sizeof(pPages->IOCPage6);
+        break;
+    default:
+        rc = -1;
+    }
+
+    return rc;
+}
+
+static int lsilogic_config_manufacturing_page(LsilogicState *pLsiLogic,
+                               PMptConfigurationPagesSupported pPages,
+                               uint8_t u8PageNumber,
+                               PMptConfigurationPageHeader *ppPageHeader,
+                               uint8_t **ppbPageData, size_t *pcbPage)
+{
+    int rc = 0;
+
+    switch (u8PageNumber) {
+    case 0:
+        *ppPageHeader = &pPages->ManufacturingPage0.u.fields.Header;
+        *ppbPageData  =  pPages->ManufacturingPage0.u.abPageData;
+        *pcbPage      = sizeof(pPages->ManufacturingPage0);
+        break;
+    case 1:
+        *ppPageHeader = &pPages->ManufacturingPage1.u.fields.Header;
+        *ppbPageData  =  pPages->ManufacturingPage1.u.abPageData;
+        *pcbPage      = sizeof(pPages->ManufacturingPage1);
+        break;
+    case 2:
+        *ppPageHeader = &pPages->ManufacturingPage2.u.fields.Header;
+        *ppbPageData  =  pPages->ManufacturingPage2.u.abPageData;
+        *pcbPage      = sizeof(pPages->ManufacturingPage2);
+        break;
+    case 3:
+        *ppPageHeader = &pPages->ManufacturingPage3.u.fields.Header;
+        *ppbPageData  =  pPages->ManufacturingPage3.u.abPageData;
+        *pcbPage      = sizeof(pPages->ManufacturingPage3);
+        break;
+    case 4:
+        *ppPageHeader = &pPages->ManufacturingPage4.u.fields.Header;
+        *ppbPageData  =  pPages->ManufacturingPage4.u.abPageData;
+        *pcbPage      = sizeof(pPages->ManufacturingPage4);
+        break;
+    case 5:
+        *ppPageHeader = &pPages->ManufacturingPage5.u.fields.Header;
+        *ppbPageData  =  pPages->ManufacturingPage5.u.abPageData;
+        *pcbPage      = sizeof(pPages->ManufacturingPage5);
+        break;
+    case 6:
+        *ppPageHeader = &pPages->ManufacturingPage6.u.fields.Header;
+        *ppbPageData  =  pPages->ManufacturingPage6.u.abPageData;
+        *pcbPage      = sizeof(pPages->ManufacturingPage6);
+        break;
+    case 7:
+        if (pLsiLogic->ctrl_type == LSILOGICCTRLTYPE_SCSI_SAS) {
+            *ppPageHeader = &pPages->u.SasPages.pManufacturingPage7->
+                u.fields.Header;
+            *ppbPageData  =  pPages->u.SasPages.pManufacturingPage7->
+                u.abPageData;
+            *pcbPage      = pPages->u.SasPages.cbManufacturingPage7;
+        } else {
+            rc = -1;
+        }
+        break;
+    case 8:
+        *ppPageHeader = &pPages->ManufacturingPage8.u.fields.Header;
+        *ppbPageData  =  pPages->ManufacturingPage8.u.abPageData;
+        *pcbPage      = sizeof(pPages->ManufacturingPage8);
+        break;
+    case 9:
+        *ppPageHeader = &pPages->ManufacturingPage9.u.fields.Header;
+        *ppbPageData  =  pPages->ManufacturingPage9.u.abPageData;
+        *pcbPage      = sizeof(pPages->ManufacturingPage9);
+        break;
+    case 10:
+        *ppPageHeader = &pPages->ManufacturingPage10.u.fields.Header;
+        *ppbPageData  =  pPages->ManufacturingPage10.u.abPageData;
+        *pcbPage      = sizeof(pPages->ManufacturingPage10);
+        break;
+    default:
+        rc = -1;
+    }
+
+    return rc;
+}
+
+static int lsilogic_config_bios_page(LsilogicState *pLsiLogic,
+                              PMptConfigurationPagesSupported pPages,
+                              uint8_t u8PageNumber,
+                              PMptConfigurationPageHeader *ppPageHeader,
+                              uint8_t **ppbPageData, size_t *pcbPage)
+{
+    int rc = 0;
+
+    switch (u8PageNumber) {
+    case 1:
+        *ppPageHeader = &pPages->BIOSPage1.u.fields.Header;
+        *ppbPageData  =  pPages->BIOSPage1.u.abPageData;
+        *pcbPage      = sizeof(pPages->BIOSPage1);
+        break;
+    case 2:
+        *ppPageHeader = &pPages->BIOSPage2.u.fields.Header;
+        *ppbPageData  =  pPages->BIOSPage2.u.abPageData;
+        *pcbPage      = sizeof(pPages->BIOSPage2);
+        break;
+    case 4:
+        *ppPageHeader = &pPages->BIOSPage4.u.fields.Header;
+        *ppbPageData  =  pPages->BIOSPage4.u.abPageData;
+        *pcbPage      = sizeof(pPages->BIOSPage4);
+        break;
+    default:
+        rc = -1;
+    }
+
+    return rc;
+}
+
+static int lsilogic_config_scsi_spi_port_page(LsilogicState *pLsiLogic,
+                             PMptConfigurationPagesSupported pPages,
+                             uint8_t u8Port,
+                             uint8_t u8PageNumber,
+                             PMptConfigurationPageHeader *ppPageHeader,
+                             uint8_t **ppbPageData, size_t *pcbPage)
+{
+    int rc = 0;
+
+    if (u8Port >= RT_ELEMENTS(pPages->u.SpiPages.aPortPages)) {
+        return -1;
+    }
+
+    switch (u8PageNumber) {
+    case 0:
+        *ppPageHeader = &pPages->u.SpiPages.aPortPages[u8Port].
+            SCSISPIPortPage0.u.fields.Header;
+        *ppbPageData  =  pPages->u.SpiPages.aPortPages[u8Port].
+            SCSISPIPortPage0.u.abPageData;
+        *pcbPage      = sizeof(pPages->u.SpiPages.aPortPages[u8Port].
+            SCSISPIPortPage0);
+        break;
+    case 1:
+        *ppPageHeader = &pPages->u.SpiPages.aPortPages[u8Port].
+            SCSISPIPortPage1.u.fields.Header;
+        *ppbPageData  =  pPages->u.SpiPages.aPortPages[u8Port].
+            SCSISPIPortPage1.u.abPageData;
+        *pcbPage      = sizeof(pPages->u.SpiPages.aPortPages[u8Port].
+            SCSISPIPortPage1);
+        break;
+    case 2:
+        *ppPageHeader = &pPages->u.SpiPages.aPortPages[u8Port].
+            SCSISPIPortPage2.u.fields.Header;
+        *ppbPageData  =  pPages->u.SpiPages.aPortPages[u8Port].
+            SCSISPIPortPage2.u.abPageData;
+        *pcbPage      = sizeof(pPages->u.SpiPages.aPortPages[u8Port]
+            .SCSISPIPortPage2);
+        break;
+    default:
+        rc = -1;
+    }
+
+    return rc;
+}
+
+static int lsilogic_config_scsi_spi_device_page(LsilogicState *pLsiLogic,
+                           PMptConfigurationPagesSupported pPages,
+                           uint8_t u8Bus,
+                           uint8_t u8TargetID, uint8_t u8PageNumber,
+                           PMptConfigurationPageHeader *ppPageHeader,
+                           uint8_t **ppbPageData, size_t *pcbPage)
+{
+    int rc = 0;
+
+    if (u8Bus >= RT_ELEMENTS(pPages->u.SpiPages.aBuses)) {
+        return -1;
+    }
+
+    if (u8TargetID >=
+        RT_ELEMENTS(pPages->u.SpiPages.aBuses[u8Bus].aDevicePages)) {
+        return -1;
+    }
+
+    switch (u8PageNumber) {
+    case 0:
+        *ppPageHeader = &pPages->u.SpiPages.aBuses[u8Bus].
+                aDevicePages[u8TargetID].SCSISPIDevicePage0.u.fields.Header;
+        *ppbPageData  =  pPages->u.SpiPages.aBuses[u8Bus].
+                aDevicePages[u8TargetID].SCSISPIDevicePage0.u.abPageData;
+        *pcbPage      = sizeof(pPages->u.SpiPages.aBuses[u8Bus].
+                aDevicePages[u8TargetID].SCSISPIDevicePage0);
+        break;
+    case 1:
+        *ppPageHeader = &pPages->u.SpiPages.aBuses[u8Bus].
+                aDevicePages[u8TargetID].SCSISPIDevicePage1.u.fields.Header;
+        *ppbPageData  =  pPages->u.SpiPages.aBuses[u8Bus].
+                aDevicePages[u8TargetID].SCSISPIDevicePage1.u.abPageData;
+        *pcbPage      = sizeof(pPages->u.SpiPages.aBuses[u8Bus].
+                aDevicePages[u8TargetID].SCSISPIDevicePage1);
+        break;
+    case 2:
+        *ppPageHeader = &pPages->u.SpiPages.aBuses[u8Bus].
+                aDevicePages[u8TargetID].SCSISPIDevicePage2.u.fields.Header;
+        *ppbPageData  =  pPages->u.SpiPages.aBuses[u8Bus].
+                aDevicePages[u8TargetID].SCSISPIDevicePage2.u.abPageData;
+        *pcbPage      = sizeof(pPages->u.SpiPages.aBuses[u8Bus].
+                aDevicePages[u8TargetID].SCSISPIDevicePage2);
+        break;
+    case 3:
+        *ppPageHeader = &pPages->u.SpiPages.aBuses[u8Bus].
+                aDevicePages[u8TargetID].SCSISPIDevicePage3.u.fields.Header;
+        *ppbPageData  =  pPages->u.SpiPages.aBuses[u8Bus].
+                aDevicePages[u8TargetID].SCSISPIDevicePage3.u.abPageData;
+        *pcbPage      = sizeof(pPages->u.SpiPages.aBuses[u8Bus].
+                aDevicePages[u8TargetID].SCSISPIDevicePage3);
+        break;
+    default:
+        rc = -1;
+    }
+
+    return rc;
+}
+
+static int lsilogic_config_sas_unit(LsilogicState *pLsiLogic,
+                       PMptConfigurationPagesSupported pPages,
+                       uint8_t u8PageNumber,
+                       PMptExtendedConfigurationPageHeader *ppPageHeader,
+                       uint8_t **ppbPageData, size_t *pcbPage)
+{
+    int rc = 0;
+
+    switch (u8PageNumber) {
+    case 0:
+        *ppPageHeader = &pPages->u.SasPages.pSASIOUnitPage0->u.fields.
+                ExtHeader;
+        *ppbPageData  = pPages->u.SasPages.pSASIOUnitPage0->u.abPageData;
+        *pcbPage      = pPages->u.SasPages.cbSASIOUnitPage0;
+        break;
+    case 1:
+        *ppPageHeader = &pPages->u.SasPages.pSASIOUnitPage1->u.fields.
+                ExtHeader;
+        *ppbPageData  = pPages->u.SasPages.pSASIOUnitPage1->u.abPageData;
+        *pcbPage      = pPages->u.SasPages.cbSASIOUnitPage1;
+        break;
+    case 2:
+        *ppPageHeader = &pPages->u.SasPages.SASIOUnitPage2.u.fields.ExtHeader;
+        *ppbPageData  =  pPages->u.SasPages.SASIOUnitPage2.u.abPageData;
+        *pcbPage      = sizeof(pPages->u.SasPages.SASIOUnitPage2);
+        break;
+    case 3:
+        *ppPageHeader = &pPages->u.SasPages.SASIOUnitPage3.u.fields.ExtHeader;
+        *ppbPageData  =  pPages->u.SasPages.SASIOUnitPage3.u.abPageData;
+        *pcbPage      = sizeof(pPages->u.SasPages.SASIOUnitPage3);
+        break;
+    default:
+        rc = -1;
+    }
+
+    return rc;
+}
+
+static int lsilogic_config_sas_phy(LsilogicState *pLsiLogic,
+                PMptConfigurationPagesSupported pPages,
+                uint8_t u8PageNumber,
+                MptConfigurationPageAddress PageAddress,
+                PMptExtendedConfigurationPageHeader *ppPageHeader,
+                uint8_t **ppbPageData, size_t *pcbPage)
+{
+    int rc = 0;
+    uint8_t uAddressForm =
+        MPT_CONFIGURATION_PAGE_ADDRESS_GET_SAS_FORM(PageAddress);
+    PMptConfigurationPagesSas pPagesSas = &pPages->u.SasPages;
+    PMptPHY pPHYPages = NULL;
+
+
+    if (uAddressForm == 0) { /* PHY number */
+        uint8_t u8PhyNumber = PageAddress.SASPHY.Form0.u8PhyNumber;
+
+        if (u8PhyNumber >= pPagesSas->cPHYs) {
+            return -1;
+        }
+
+        pPHYPages = &pPagesSas->paPHYs[u8PhyNumber];
+    } else if (uAddressForm == 1) { /* Index form */
+        uint16_t u16Index = PageAddress.SASPHY.Form1.u16Index;
+
+        if (u16Index >= pPagesSas->cPHYs) {
+            return -1;
+        }
+
+        pPHYPages = &pPagesSas->paPHYs[u16Index];
+    } else {
+        rc = -1; /* Correct? */
+    }
+
+    if (pPHYPages) {
+        switch (u8PageNumber) {
+        case 0:
+            *ppPageHeader = &pPHYPages->SASPHYPage0.u.fields.ExtHeader;
+            *ppbPageData  = pPHYPages->SASPHYPage0.u.abPageData;
+            *pcbPage      = sizeof(pPHYPages->SASPHYPage0);
+            break;
+        case 1:
+            *ppPageHeader = &pPHYPages->SASPHYPage1.u.fields.ExtHeader;
+            *ppbPageData  =  pPHYPages->SASPHYPage1.u.abPageData;
+            *pcbPage      = sizeof(pPHYPages->SASPHYPage1);
+            break;
+        default:
+            rc = -1;
+        }
+    } else {
+        rc = -1;
+    }
+
+    return rc;
+}
+
+static int lsilogic_config_sas_device(LsilogicState *pLsiLogic,
+                   PMptConfigurationPagesSupported pPages,
+                   uint8_t u8PageNumber,
+                   MptConfigurationPageAddress PageAddress,
+                   PMptExtendedConfigurationPageHeader *ppPageHeader,
+                   uint8_t **ppbPageData, size_t *pcbPage)
+{
+    int rc = 0;
+    uint8_t uAddressForm =
+        MPT_CONFIGURATION_PAGE_ADDRESS_GET_SAS_FORM(PageAddress);
+    PMptConfigurationPagesSas pPagesSas = &pPages->u.SasPages;
+    PMptSASDevice pSASDevice = NULL;
+
+    if (uAddressForm == 0) {
+        uint16_t u16Handle = PageAddress.SASDevice.Form0And2.u16Handle;
+
+        pSASDevice = pPagesSas->pSASDeviceHead;
+
+        /* Get the first device? */
+        if (u16Handle != 0xffff) {
+            /* No, search for the right one. */
+
+            while (pSASDevice
+                   && pSASDevice->SASDevicePage0.u.fields.u16DevHandle !=
+                        u16Handle)
+                pSASDevice = pSASDevice->pNext;
+
+            if (pSASDevice) {
+                pSASDevice = pSASDevice->pNext;
+            }
+        }
+    } else if (uAddressForm == 1) {
+        uint8_t u8TargetID = PageAddress.SASDevice.Form1.u8TargetID;
+        uint8_t u8Bus      = PageAddress.SASDevice.Form1.u8Bus;
+
+        pSASDevice = pPagesSas->pSASDeviceHead;
+
+        while (pSASDevice
+               && (pSASDevice->SASDevicePage0.u.fields.u8TargetID !=
+                        u8TargetID
+                   || pSASDevice->SASDevicePage0.u.fields.u8Bus != u8Bus))
+            pSASDevice = pSASDevice->pNext;
+    } else if (uAddressForm == 2) {
+        uint16_t u16Handle = PageAddress.SASDevice.Form0And2.u16Handle;
+
+        pSASDevice = pPagesSas->pSASDeviceHead;
+
+        while (pSASDevice
+               && pSASDevice->SASDevicePage0.u.fields.u16DevHandle !=
+                u16Handle) {
+            pSASDevice = pSASDevice->pNext;
+        }
+    }
+
+    if (pSASDevice) {
+        switch (u8PageNumber) {
+        case 0:
+            *ppPageHeader = &pSASDevice->SASDevicePage0.u.fields.ExtHeader;
+            *ppbPageData  =  pSASDevice->SASDevicePage0.u.abPageData;
+            *pcbPage      = sizeof(pSASDevice->SASDevicePage0);
+            break;
+        case 1:
+            *ppPageHeader = &pSASDevice->SASDevicePage1.u.fields.ExtHeader;
+            *ppbPageData  =  pSASDevice->SASDevicePage1.u.abPageData;
+            *pcbPage      = sizeof(pSASDevice->SASDevicePage1);
+            break;
+        case 2:
+            *ppPageHeader = &pSASDevice->SASDevicePage2.u.fields.ExtHeader;
+            *ppbPageData  =  pSASDevice->SASDevicePage2.u.abPageData;
+            *pcbPage      = sizeof(pSASDevice->SASDevicePage2);
+            break;
+        default:
+            rc = -1;
+        }
+    } else {
+        rc = -1;
+    }
+
+    return rc;
+}
+
+static int lsilogic_config_page_get_extended(LsilogicState *pLsiLogic,
+                PMptConfigurationRequest pConfigurationReq,
+                PMptExtendedConfigurationPageHeader *ppPageHeader,
+                uint8_t **ppbPageData, size_t *pcbPage)
+{
+    int rc = 0;
+
+    switch (pConfigurationReq->u8ExtPageType) {
+    case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT:
+    {
+        rc = lsilogic_config_sas_unit(pLsiLogic,
+                                     pLsiLogic->config_pages,
+                                     pConfigurationReq->u8PageNumber,
+                                     ppPageHeader, ppbPageData, pcbPage);
+        break;
+    }
+    case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASPHYS:
+    {
+        rc = lsilogic_config_sas_phy(pLsiLogic,
+                                      pLsiLogic->config_pages,
+                                      pConfigurationReq->u8PageNumber,
+                                      pConfigurationReq->PageAddress,
+                                      ppPageHeader, ppbPageData, pcbPage);
+        break;
+    }
+    case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE:
+    {
+        rc = lsilogic_config_sas_device(pLsiLogic,
+                                     pLsiLogic->config_pages,
+                                     pConfigurationReq->u8PageNumber,
+                                     pConfigurationReq->PageAddress,
+                                     ppPageHeader, ppbPageData, pcbPage);
+        break;
+    }
+    case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASEXPANDER:
+        /* No expanders supported */
+    case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_ENCLOSURE:
+        /* No enclosures supported */
+    default:
+        rc = -1;
+    }
+
+    return rc;
+}
+
+
+static int lsilogic_process_config_req(LsilogicState *s,
+        MptConfigurationRequest *config_req, MptConfigurationReply *reply)
+{
+    int rc = 0;
+    uint8_t                            *pbPageData     = NULL;
+    PMptConfigurationPageHeader         pPageHeader    = NULL;
+    PMptExtendedConfigurationPageHeader pExtPageHeader = NULL;
+    size_t                              cbPage = 0;
+
+
+    /* Copy common bits from the request into the reply. */
+    reply->u8MessageLength   = 6; /* 6 32bit D-Words. */
+    reply->u8Action          = config_req->u8Action;
+    reply->u8Function        = config_req->u8Function;
+    reply->u32MessageContext = config_req->u32MessageContext;
+
+    switch (MPT_CONFIGURATION_PAGE_TYPE_GET(config_req->u8PageType)) {
+    case MPT_CONFIGURATION_PAGE_TYPE_IO_UNIT:
+    {
+        rc = lsilogic_config_unit_page(s, s->config_pages,
+                  config_req->u8PageNumber,
+                  &pPageHeader, &pbPageData, &cbPage);
+        break;
+    }
+    case MPT_CONFIGURATION_PAGE_TYPE_IOC:
+    {
+        /* Get the page data. */
+        rc = lsilogic_config_ioc_page(s, s->config_pages,
+                  config_req->u8PageNumber,
+                  &pPageHeader, &pbPageData, &cbPage);
+        break;
+    }
+    case MPT_CONFIGURATION_PAGE_TYPE_MANUFACTURING:
+    {
+        rc = lsilogic_config_manufacturing_page(s, s->config_pages,
+                 config_req->u8PageNumber,
+                 &pPageHeader, &pbPageData, &cbPage);
+        break;
+    }
+    case MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_PORT:
+    {
+        rc = lsilogic_config_scsi_spi_port_page(s, s->config_pages,
+                 config_req->PageAddress.MPIPortNumber.u8PortNumber,
+                 config_req->u8PageNumber,
+                 &pPageHeader, &pbPageData, &cbPage);
+        break;
+    }
+    case MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE:
+    {
+        rc = lsilogic_config_scsi_spi_device_page(s, s->config_pages,
+                 config_req->PageAddress.BusAndTargetId.u8Bus,
+                 config_req->PageAddress.BusAndTargetId.u8TargetID,
+                 config_req->u8PageNumber,
+                 &pPageHeader, &pbPageData, &cbPage);
+        break;
+    }
+    case MPT_CONFIGURATION_PAGE_TYPE_BIOS:
+    {
+        rc = lsilogic_config_bios_page(s, s->config_pages,
+                            config_req->u8PageNumber,
+                            &pPageHeader, &pbPageData, &cbPage);
+        break;
+    }
+    case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED:
+    {
+        rc = lsilogic_config_page_get_extended(s, config_req,
+            &pExtPageHeader, &pbPageData, &cbPage);
+        break;
+    }
+    default:
+        rc = -1;
+    }
+
+    if (rc == -1) {
+        reply->u8PageType    = config_req->u8PageType;
+        reply->u8PageNumber  = config_req->u8PageNumber;
+        reply->u8PageLength  = config_req->u8PageLength;
+        reply->u8PageVersion = config_req->u8PageVersion;
+        reply->u16IOCStatus  = MPT_IOCSTATUS_CONFIG_INVALID_PAGE;
+        return 0;
+    }
+
+    if (MPT_CONFIGURATION_PAGE_TYPE_GET(config_req->u8PageType) ==
+                MPT_CONFIGURATION_PAGE_TYPE_EXTENDED) {
+        reply->u8PageType       = pExtPageHeader->u8PageType;
+        reply->u8PageNumber     = pExtPageHeader->u8PageNumber;
+        reply->u8PageVersion    = pExtPageHeader->u8PageVersion;
+        reply->u8ExtPageType    = pExtPageHeader->u8ExtPageType;
+        reply->u16ExtPageLength = pExtPageHeader->u16ExtPageLength;
+    } else {
+        reply->u8PageType    = pPageHeader->u8PageType;
+        reply->u8PageNumber  = pPageHeader->u8PageNumber;
+        reply->u8PageLength  = pPageHeader->u8PageLength;
+        reply->u8PageVersion = pPageHeader->u8PageVersion;
+    }
+
+    /*
+     * Don't use the scatter gather handling code as the configuration
+     * request always have only one simple element.
+     */
+    switch (config_req->u8Action) {
+    case MPT_CONFIGURATION_REQUEST_ACTION_DEFAULT:
+        /* Nothing to do. We are always using the defaults. */
+    case MPT_CONFIGURATION_REQUEST_ACTION_HEADER:
+    {
+        /* Already copied above nothing to do. */
+        break;
+    }
+    case MPT_CONFIGURATION_REQUEST_ACTION_READ_NVRAM:
+    case MPT_CONFIGURATION_REQUEST_ACTION_READ_CURRENT:
+    case MPT_CONFIGURATION_REQUEST_ACTION_READ_DEFAULT:
+    {
+        uint32_t cbBuffer = config_req->SimpleSGElement.u24Length;
+        if (cbBuffer != 0) {
+            uint64_t page_buffer_pa = config_req->SimpleSGElement.
+                u32DataBufferAddressLow;
+            if (config_req->SimpleSGElement.f64BitAddress) {
+                page_buffer_pa |= (uint64_t)config_req->SimpleSGElement.
+                        u32DataBufferAddressHigh << 32;
+            }
+
+            cpu_physical_memory_write(page_buffer_pa, pbPageData, MIN(cbBuffer,
+                cbPage));
+        }
+        break;
+    }
+    case MPT_CONFIGURATION_REQUEST_ACTION_WRITE_CURRENT:
+    case MPT_CONFIGURATION_REQUEST_ACTION_WRITE_NVRAM:
+    {
+        uint32_t cbBuffer = config_req->SimpleSGElement.u24Length;
+        if (cbBuffer != 0) {
+            uint64_t page_buffer_pa = config_req->SimpleSGElement.
+                u32DataBufferAddressLow;
+            if (config_req->SimpleSGElement.f64BitAddress) {
+                page_buffer_pa |= (uint64_t)config_req->SimpleSGElement.
+                        u32DataBufferAddressHigh << 32;
+            }
+            cpu_physical_memory_read(page_buffer_pa, pbPageData, MIN(cbBuffer,
+                cbPage));
+        }
+        break;
+    }
+    default:
+        break;
+    }
+
+    return 0;
+}
+
+static const char *lsilogic_msg_desc[] = {
+        "SCSI_IO_REQUEST",
+        "SCSI_TASK_MGMT",
+        "IOC_INIT",
+        "IOC_FACTS",
+        "CONFIG",
+        "PORT_FACTS",
+        "PORT_ENABLE",
+        "EVENT_NOTIFICATION",
+        "EVENT_ACK",
+        "FW_DOWNLOAD",
+        "TARGET_CMD_BUFFER_POST",
+        "TARGET_ASSIST",
+        "TARGET_STATUS_SEND",
+        "TARGET_MODE_ABORT",
+        "UNDEFINED",
+        "UNDEFINED",
+        "UNDEFINED",
+        "UNDEFINED",
+        "FW_UPLOAD"
+};
+
+static void lsilogic_process_message(LsilogicState *s, MptMessageHdr *msg,
+        MptReplyUnion *reply)
+{
+    bool fForceReplyPostFifo = false;
+
+    memset(reply, 0, sizeof(MptReplyUnion));
+
+    trace_lsilogic_process_message(lsilogic_msg_desc[msg->u8Function]);
+    switch (msg->u8Function) {
+    case MPT_MESSAGE_HDR_FUNCTION_SCSI_TASK_MGMT:
+    {
+        PMptSCSITaskManagementRequest pTaskMgmtReq =
+            (PMptSCSITaskManagementRequest)msg;
+
+        reply->SCSITaskManagement.u8MessageLength     = 6;
+        reply->SCSITaskManagement.u8TaskType          =
+            pTaskMgmtReq->u8TaskType;
+        reply->SCSITaskManagement.u32TerminationCount = 0;
+        fForceReplyPostFifo = true;
+        break;
+    }
+
+    case MPT_MESSAGE_HDR_FUNCTION_IOC_INIT:
+    {
+        /* This request sets the I/O contr to the operational state. */
+        PMptIOCInitRequest pIOCInitReq = (PMptIOCInitRequest)msg;
+
+        /* Update configuration values. */
+        s->who_init             = (LSILOGICWHOINIT)pIOCInitReq->u8WhoInit;
+        s->reply_frame_size     = pIOCInitReq->u16ReplyFrameSize;
+        s->max_buses            = pIOCInitReq->u8MaxBuses;
+        s->max_devices          = pIOCInitReq->u8MaxDevices;
+        s->host_mfa_high_addr   = pIOCInitReq->u32HostMfaHighAddr;
+        s->sense_buffer_high_addr = pIOCInitReq->u32SenseBufferHighAddr;
+
+        if (s->state == LSILOGICSTATE_READY) {
+            s->state = LSILOGICSTATE_OPERATIONAL;
+        }
+
+        /* Return reply. */
+        reply->IOCInit.u8MessageLength = 5;
+        reply->IOCInit.u8WhoInit       = s->who_init;
+        reply->IOCInit.u8MaxDevices    = s->max_devices;
+        reply->IOCInit.u8MaxBuses      = s->max_buses;
+        break;
+    }
+    case MPT_MESSAGE_HDR_FUNCTION_IOC_FACTS:
+    {
+        reply->IOCFacts.u8MessageLength      = 15; /* 15 32bit dwords. */
+
+        if (s->ctrl_type == LSILOGICCTRLTYPE_SCSI_SPI) {
+            /* Version from the specification. */
+            reply->IOCFacts.u16MessageVersion    = 0x0102;
+         } else if (s->ctrl_type == LSILOGICCTRLTYPE_SCSI_SAS) {
+            /* Version from the specification. */
+            reply->IOCFacts.u16MessageVersion    = 0x0105;
+         }
+
+        reply->IOCFacts.u8NumberOfPorts      = s->ports;
+        /* PCI function number. */
+        reply->IOCFacts.u8IOCNumber          = 0;
+        reply->IOCFacts.u16IOCExceptions     = 0;
+        reply->IOCFacts.u8MaxChainDepth = LSILOGICSCSI_MAXIMUM_CHAIN_DEPTH;
+        reply->IOCFacts.u8WhoInit            = s->who_init;
+        /* Block size in 32bit dwords. This is the largest request
+           we can get (SCSI I/O). */
+        reply->IOCFacts.u8BlockSize          = 12;
+        /* Bit 0 is set if the guest must upload the FW prior to using
+            the controller. Obviously not needed here. */
+        reply->IOCFacts.u8Flags              = 0;
+        /* One entry is always free. */
+        reply->IOCFacts.u16ReplyQueueDepth   = s->reply_queue_entries - 1;
+        reply->IOCFacts.u16RequestFrameSize  = 128;
+        /* Our own product ID :) */
+        reply->IOCFacts.u16ProductID         = 0x2704;
+        reply->IOCFacts.u32CurrentHostMFAHighAddr = s->host_mfa_high_addr;
+        /* One entry is always free. */
+        reply->IOCFacts.u16GlobalCredits = s->request_queue_entries - 1;
+
+            /* Event notifications not enabled. */
+        reply->IOCFacts.u8EventState         = 0;
+        reply->IOCFacts.u32CurrentSenseBufferHighAddr =
+            s->sense_buffer_high_addr;
+        reply->IOCFacts.u16CurReplyFrameSize = s->reply_frame_size;
+        reply->IOCFacts.u8MaxDevices         = s->max_devices;
+        reply->IOCFacts.u8MaxBuses           = s->max_buses;
+        reply->IOCFacts.u32FwImageSize       = 0;
+        reply->IOCFacts.u32FWVersion         = 0x1329200;
+        break;
+    }
+    case MPT_MESSAGE_HDR_FUNCTION_PORT_FACTS:
+    {
+        PMptPortFactsRequest pPortFactsReq = (PMptPortFactsRequest)msg;
+
+        reply->PortFacts.u8MessageLength = 10;
+        reply->PortFacts.u8PortNumber    = pPortFactsReq->u8PortNumber;
+
+        if (s->ctrl_type == LSILOGICCTRLTYPE_SCSI_SPI) {
+            /* This controller only supports one bus with bus number 0. */
+            if (pPortFactsReq->u8PortNumber >= s->ports) {
+                reply->PortFacts.u8PortType = 0; /* Not existant. */
+            } else {
+                reply->PortFacts.u8PortType = 0x01; /* SCSI Port. */
+                reply->PortFacts.u16MaxDevices          =
+                    LSILOGICSCSI_PCI_SPI_DEVICES_PER_BUS_MAX;
+                /* SCSI initiator and LUN supported. */
+                reply->PortFacts.u16ProtocolFlags = (1 << 3) | (1 << 0);
+                reply->PortFacts.u16PortSCSIID          = 7; /* Default */
+                reply->PortFacts.u16MaxPersistentIDs    = 0;
+                /* Only applies for target mode which we dont support. */
+                reply->PortFacts.u16MaxPostedCmdBuffers = 0;
+                /* Only for the LAN controller. */
+                reply->PortFacts.u16MaxLANBuckets       = 0;
+            }
+        } else if (s->ctrl_type == LSILOGICCTRLTYPE_SCSI_SAS) {
+            if (pPortFactsReq->u8PortNumber >= s->ports) {
+                reply->PortFacts.u8PortType = 0; /* Not existant. */
+            } else {
+                reply->PortFacts.u8PortType = 0x30; /* SAS Port. */
+                reply->PortFacts.u16MaxDevices          = s->ports;
+                /* SCSI initiator and LUN supported. */
+                reply->PortFacts.u16ProtocolFlags = (1 << 3) | (1 << 0);
+                reply->PortFacts.u16PortSCSIID          = s->ports;
+                reply->PortFacts.u16MaxPersistentIDs    = 0;
+                /* Only applies for target mode which we dont support. */
+                reply->PortFacts.u16MaxPostedCmdBuffers = 0;
+                /* Only for the LAN controller. */
+                reply->PortFacts.u16MaxLANBuckets       = 0;
+            }
+        }
+        break;
+    }
+    case MPT_MESSAGE_HDR_FUNCTION_PORT_ENABLE:
+    {
+        /*
+         * The port enable request notifies the IOC to make the port
+         * available and perform appropriate discovery on the associated
+         * link.
+         */
+        PMptPortEnableRequest pPortEnableReq = (PMptPortEnableRequest)msg;
+
+        reply->PortEnable.u8MessageLength = 5;
+        reply->PortEnable.u8PortNumber    = pPortEnableReq->u8PortNumber;
+        break;
+    }
+    case MPT_MESSAGE_HDR_FUNCTION_EVENT_NOTIFICATION:
+    {
+        PMptEventNotificationRequest pEventNotificationReq =
+            (PMptEventNotificationRequest)msg;
+
+        if (pEventNotificationReq->u8Switch) {
+            s->event_notification_enabled = true;
+        } else {
+            s->event_notification_enabled = false;
+        }
+
+        reply->EventNotification.u16EventDataLength = 1; /* 32bit Word. */
+        reply->EventNotification.u8MessageLength    = 8;
+        reply->EventNotification.u8MessageFlags     = (1 << 7);
+        reply->EventNotification.u8AckRequired      = 0;
+        reply->EventNotification.u32Event = MPT_EVENT_EVENT_CHANGE;
+        reply->EventNotification.u32EventContext    = 0;
+        reply->EventNotification.u32EventData       =
+            s->event_notification_enabled ? 1 : 0;
+
+        break;
+    }
+    case MPT_MESSAGE_HDR_FUNCTION_EVENT_ACK:
+    {
+        break;
+    }
+    case MPT_MESSAGE_HDR_FUNCTION_CONFIG:
+    {
+        PMptConfigurationRequest config_req =
+            (PMptConfigurationRequest)msg;
+
+        lsilogic_process_config_req(s, config_req, &reply->Configuration);
+        break;
+    }
+    case MPT_MESSAGE_HDR_FUNCTION_FW_UPLOAD:
+    {
+        PMptFWUploadRequest pFWUploadReq = (PMptFWUploadRequest)msg;
+        target_phys_addr_t iov_pa = pFWUploadReq->sge.u32DataBufferAddressLow;
+        void *ptr;
+
+        reply->FWUpload.u8ImageType        = pFWUploadReq->u8ImageType;
+        reply->FWUpload.u8MessageLength    = 6;
+        assert(pFWUploadReq->u8ImageType == MPI_FW_UPLOAD_ITYPE_BIOS_FLASH);
+        assert(pFWUploadReq->sge.u2ElementType == MPTSGENTRYTYPE_SIMPLE);
+        assert(pFWUploadReq->sge.f64BitAddress == 0);
+        assert(pFWUploadReq->sge.fEndOfList);
+        assert(pFWUploadReq->sge.fLastElement);
+        reply->FWUpload.u32ActualImageSize = memory_region_size(&s->dev.rom);
+        assert(reply->FWUpload.u32ActualImageSize >=
+            pFWUploadReq->TCSge.ImageOffset + pFWUploadReq->sge.u24Length);
+        ptr = memory_region_get_ram_ptr(&s->dev.rom);
+        cpu_physical_memory_write(iov_pa, (uint8_t *)ptr +
+            pFWUploadReq->TCSge.ImageOffset, pFWUploadReq->sge.u24Length);
+        qemu_put_ram_ptr(ptr);
+        reply->FWUpload.u32ActualImageSize = memory_region_size(&s->dev.rom);
+        break;
+    }
+    case MPT_MESSAGE_HDR_FUNCTION_FW_DOWNLOAD:
+    {
+
+        reply->FWDownload.u8MessageLength    = 5;
+        break;
+    }
+    case MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST:
+        /* Should be handled already. */
+    default:
+        trace_lsilogic_unhandled_cmd(msg->u8Function, 0);
+    }
+
+    /* Copy common bits from request message frame to reply. */
+    reply->Header.u8Function        = msg->u8Function;
+    reply->Header.u32MessageContext = msg->u32MessageContext;
+
+    lsilogic_finish_address_reply(s, reply, fForceReplyPostFifo);
+}
+
+static uint64_t lsilogic_mmio_read(void *opaque, target_phys_addr_t addr,
+                                  unsigned size)
+{
+    LsilogicState *s = opaque;
+    uint32_t retval = 0;
+
+    switch (addr & ~3) {
+    case LSILOGIC_REG_DOORBELL:
+        retval = LSILOGIC_REG_DOORBELL_SET_STATE(s->state) |
+                 LSILOGIC_REG_DOORBELL_SET_USED(s->doorbell) |
+                 LSILOGIC_REG_DOORBELL_SET_WHOINIT(s->who_init);
+        /*
+         * If there is a doorbell function in progress we pass the
+         * return value instead of the status code. We transfer 16bits
+         * of the reply during one read.
+         */
+        if (s->doorbell) {
+            retval |= s->reply_buffer.au16Reply[s->next_reply_entry_read++];
+        } else {
+            retval |= s->IOC_fault_code;
+        }
+        break;
+
+    case LSILOGIC_REG_REPLY_QUEUE:
+        if (s->reply_post_queue_next_entry_free_write !=
+                s->reply_post_queue_next_address_read) {
+            retval = s->reply_post_queue[
+                s->reply_post_queue_next_address_read++];
+            s->reply_post_queue_next_address_read %=
+                s->reply_queue_entries;
+        } else {
+            /* The reply post queue is empty. Reset interrupt. */
+            retval = 0xffffffff;
+            s->intr_status &= ~LSILOGIC_REG_HOST_INTR_STATUS_REPLY_INTR;
+            lsilogic_update_interrupt(s);
+        }
+        break;
+
+    case LSILOGIC_REG_HOST_INTR_STATUS:
+        retval = s->intr_status;
+        break;
+
+    case LSILOGIC_REG_HOST_INTR_MASK:
+        retval = s->intr_mask;
+        break;
+
+    case LSILOGIC_REG_HOST_DIAGNOSTIC:
+        if (s->diagnostic_enabled) {
+            retval = LSILOGIC_REG_HOST_DIAGNOSTIC_DRWE;
+        } else {
+            retval = 0;
+        }
+        break;
+
+    case LSILOGIC_REG_TEST_BASE_ADDRESS:
+    case LSILOGIC_REG_DIAG_RW_DATA:
+    case LSILOGIC_REG_DIAG_RW_ADDRESS:
+    default:
+        trace_lsilogic_mmio_invalid_readl(addr);
+        break;
+    }
+    trace_lsilogic_mmio_readl(addr, retval);
+    return retval;
+}
+
+static void lsilogic_mmio_write(void *opaque, target_phys_addr_t addr,
+                               uint64_t val, unsigned size)
+{
+    static const uint8_t DiagnosticAccess[] = {0x04, 0x0b, 0x02, 0x07, 0x0d};
+
+    LsilogicState *s = opaque;
+
+    trace_lsilogic_mmio_writel(addr, val);
+    switch (addr) {
+    case LSILOGIC_REG_REPLY_QUEUE:
+        s->reply_free_queue[s->reply_free_queue_next_entry_free_write++] = val;
+        s->reply_free_queue_next_entry_free_write %= s->reply_queue_entries;
+        break;
+
+    case LSILOGIC_REG_REQUEST_QUEUE:
+        s->request_queue[s->request_queue_next_entry_free_write++] = val;
+        s->request_queue_next_entry_free_write %= s->request_queue_entries;
+        lsilogic_queue_consumer(s);
+        break;
+
+    case LSILOGIC_REG_DOORBELL:
+        if (!s->doorbell) {
+            uint32_t uFunction = LSILOGIC_REG_DOORBELL_GET_FUNCTION(val);
+
+            switch (uFunction) {
+            case LSILOGIC_DOORBELL_FUNCTION_IOC_MSG_UNIT_RESET:
+                lsilogic_soft_reset(s);
+                break;
+            case LSILOGIC_DOORBELL_FUNCTION_IO_UNIT_RESET:
+                break;
+            case LSILOGIC_DOORBELL_FUNCTION_HANDSHAKE:
+            {
+                s->drbl_message_size = LSILOGIC_REG_DOORBELL_GET_SIZE(val);
+                s->drbl_message_index = 0;
+                s->doorbell = true;
+                /* Update the interrupt status to notify the guest that
+                   a doorbell function was started. */
+                s->intr_status |=
+                    LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL;
+                lsilogic_update_interrupt(s);
+            }
+                break;
+            case LSILOGIC_DOORBELL_FUNCTION_REPLY_FRAME_REMOVAL:
+            default:
+                trace_lsilogic_mmio_invalid_writel(addr, val);
+                break;
+            }
+        } else {
+            /*
+            * We are already performing a doorbell function.
+            * Get the remaining parameters.
+            */
+            s->drbl_message[s->drbl_message_index++] = val;
+            if (s->drbl_message_index == s->drbl_message_size) {
+                lsilogic_process_message(s, (MptMessageHdr *)s->drbl_message,
+                        &s->reply_buffer);
+            }
+        }
+        break;
+
+    case LSILOGIC_REG_HOST_INTR_STATUS:
+        s->intr_status &= ~LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL;
+        if (s->doorbell && s->drbl_message_size == s->drbl_message_index) {
+            if (s->next_reply_entry_read == s->reply_size) {
+                s->doorbell = false;
+            }
+            s->intr_status |= LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL;
+        }
+        lsilogic_update_interrupt(s);
+        break;
+
+    case LSILOGIC_REG_HOST_INTR_MASK:
+        s->intr_mask = val & LSILOGIC_REG_HOST_INTR_MASK_W_MASK;
+        lsilogic_update_interrupt(s);
+        break;
+
+    case LSILOGIC_REG_WRITE_SEQUENCE:
+        /* Any value will cause a reset and disabling access. */
+        if (s->diagnostic_enabled) {
+            s->diagnostic_enabled = false;
+            s->diagnostic_access_idx = 0;
+        } else if ((val & 0xf) == DiagnosticAccess[s->diagnostic_access_idx]) {
+            s->diagnostic_access_idx++;
+            if (s->diagnostic_access_idx == sizeof(DiagnosticAccess)) {
+                /*
+                * Key sequence successfully written. Enable access to
+                * diagnostic memory and register.
+                */
+                s->diagnostic_enabled = true;
+            }
+        } else { /* Wrong value written - reset to beginning. */
+            s->diagnostic_access_idx = 0;
+        }
+        break;
+
+        break;
+
+    case LSILOGIC_REG_HOST_DIAGNOSTIC:
+        if (val & LSILOGIC_REG_HOST_DIAGNOSTIC_RESET_ADAPTER) {
+            lsilogic_hard_reset(s);
+        }
+        break;
+    default:
+        trace_lsilogic_mmio_invalid_writel(addr, val);
+        break;
+    }
+}
+
+static const MemoryRegionOps lsilogic_mmio_ops = {
+    .read = lsilogic_mmio_read,
+    .write = lsilogic_mmio_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 8,
+        .max_access_size = 8,
+    }
+};
+
+static uint64_t lsilogic_port_read(void *opaque, target_phys_addr_t addr,
+                                  unsigned size)
+{
+    return lsilogic_mmio_read(opaque, addr & 0xff, size);
+}
+
+static void lsilogic_port_write(void *opaque, target_phys_addr_t addr,
+                               uint64_t val, unsigned size)
+{
+    lsilogic_mmio_write(opaque, addr & 0xff, val, size);
+}
+
+static const MemoryRegionOps lsilogic_port_ops = {
+    .read = lsilogic_port_read,
+    .write = lsilogic_port_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    }
+};
+
+static uint64_t lsilogic_diag_read(void *opaque, target_phys_addr_t addr,
+                                   unsigned size)
+{
+    trace_lsilogic_diag_readl(addr, 0);
+    return 0;
+}
+
+static void lsilogic_diag_write(void *opaque, target_phys_addr_t addr,
+                               uint64_t val, unsigned size)
+{
+    trace_lsilogic_diag_writel(addr, val);
+}
+
+static const MemoryRegionOps lsilogic_diag_ops = {
+    .read = lsilogic_diag_read,
+    .write = lsilogic_diag_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 8,
+        .max_access_size = 8,
+    }
+};
+
+static void lsilogic_soft_reset(LsilogicState *s)
+{
+    int i;
+    trace_lsilogic_reset();
+    s->state = LSILOGICSTATE_RESET;
+
+    s->intr_status = 0;
+    lsilogic_update_interrupt(s);
+
+    /* Reset the queues. */
+    s->reply_free_queue_next_entry_free_write = 0;
+    s->reply_free_queue_next_address_read = 0;
+    s->reply_post_queue_next_entry_free_write = 0;
+    s->reply_post_queue_next_address_read = 0;
+    s->request_queue_next_entry_free_write = 0;
+    s->request_queue_next_address_read = 0;
+    for (i = 0; i < LSILOGIC_MAX_FRAMES; i++) {
+        LsilogicCmd *cmd = s->frames[i];
+        if (cmd) {
+            lsilogic_abort_command(cmd);
+            cmd->flags = 0;
+        }
+    }
+    s->next_frame = 0;
+    s->state = LSILOGICSTATE_READY;
+}
+
+static void lsilogic_config_pages_free(LsilogicState *s)
+{
+
+    if (s->config_pages) {
+        /* Destroy device list if we emulate a SAS controller. */
+        if (s->ctrl_type == LSILOGICCTRLTYPE_SCSI_SAS) {
+            PMptConfigurationPagesSas pSasPages = &s->config_pages->u.SasPages;
+            PMptSASDevice pSASDeviceCurr = pSasPages->pSASDeviceHead;
+
+            while (pSASDeviceCurr) {
+                PMptSASDevice pFree = pSASDeviceCurr;
+
+                pSASDeviceCurr = pSASDeviceCurr->pNext;
+                g_free(pFree);
+            }
+            if (pSasPages->paPHYs) {
+                g_free(pSasPages->paPHYs);
+            }
+            if (pSasPages->pManufacturingPage7) {
+                g_free(pSasPages->pManufacturingPage7);
+            }
+            if (pSasPages->pSASIOUnitPage0) {
+                g_free(pSasPages->pSASIOUnitPage0);
+            }
+            if (pSasPages->pSASIOUnitPage1) {
+                g_free(pSasPages->pSASIOUnitPage1);
+            }
+        }
+
+        g_free(s->config_pages);
+    }
+}
+
+static void lsilogic_init_config_pages_spi(LsilogicState *s)
+{
+    unsigned i;
+    PMptConfigurationPagesSpi pPages = &s->config_pages->u.SpiPages;
+
+    /* Clear everything first. */
+    memset(pPages, 0, sizeof(PMptConfigurationPagesSpi));
+
+    for (i = 0; i < RT_ELEMENTS(pPages->aPortPages); i++) {
+        /* SCSI-SPI port page 0. */
+        pPages->aPortPages[i].SCSISPIPortPage0.u.fields.Header.u8PageType   =
+                MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
+                  | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_PORT;
+        pPages->aPortPages[i].SCSISPIPortPage0.u.fields.Header.u8PageNumber =
+                0;
+        pPages->aPortPages[i].SCSISPIPortPage0.u.fields.Header.u8PageLength =
+                sizeof(MptConfigurationPageSCSISPIPort0) / 4;
+        pPages->aPortPages[i].SCSISPIPortPage0.u.fields.
+                fInformationUnitTransfersCapable = true;
+        pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fDTCapable  = true;
+        pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fQASCapable = true;
+        pPages->aPortPages[i].SCSISPIPortPage0.u.fields.
+                u8MinimumSynchronousTransferPeriod =  0;
+        pPages->aPortPages[i].SCSISPIPortPage0.u.fields.
+                u8MaximumSynchronousOffset         = 0xff;
+        pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fWide = true;
+        pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fAIPCapable = true;
+        pPages->aPortPages[i].SCSISPIPortPage0.u.fields.u2SignalingType =
+                0x3; /* Single Ended. */
+
+        /* SCSI-SPI port page 1. */
+        pPages->aPortPages[i].SCSISPIPortPage1.u.fields.Header.u8PageType   =
+                MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
+                  | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_PORT;
+        pPages->aPortPages[i].SCSISPIPortPage1.u.fields.Header.u8PageNumber = 
1;
+        pPages->aPortPages[i].SCSISPIPortPage1.u.fields.Header.u8PageLength =
+                sizeof(MptConfigurationPageSCSISPIPort1) / 4;
+        pPages->aPortPages[i].SCSISPIPortPage1.u.fields.u8SCSIID = 7;
+        pPages->aPortPages[i].SCSISPIPortPage1.u.fields.
+                u16PortResponseIDsBitmask = (1 << 7);
+        pPages->aPortPages[i].SCSISPIPortPage1.u.fields.u32OnBusTimerValue = 0;
+
+        /* SCSI-SPI port page 2. */
+        pPages->aPortPages[i].SCSISPIPortPage2.u.fields.Header.u8PageType   =
+                MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
+                  | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_PORT;
+        pPages->aPortPages[i].SCSISPIPortPage2.u.fields.
+                Header.u8PageNumber = 2;
+        pPages->aPortPages[i].SCSISPIPortPage2.u.fields.Header.
+                u8PageLength = sizeof(MptConfigurationPageSCSISPIPort2) / 4;
+        pPages->aPortPages[i].SCSISPIPortPage2.u.fields.
+                u4HostSCSIID           = 7;
+        pPages->aPortPages[i].SCSISPIPortPage2.u.fields.
+                u2InitializeHBA        = 0x3;
+        pPages->aPortPages[i].SCSISPIPortPage2.u.fields.
+                fTerminationDisabled   = true;
+        unsigned iDevice;
+
+        for (iDevice = 0; iDevice < RT_ELEMENTS(pPages->aPortPages[i].
+                SCSISPIPortPage2.u.fields.aDeviceSettings); iDevice++) {
+            pPages->aPortPages[i].SCSISPIPortPage2.u.fields.
+                aDeviceSettings[iDevice].fBootChoice   = true;
+        }
+        /* Everything else 0 for now. */
+    }
+
+    unsigned uBusCurr;
+    for (uBusCurr = 0; uBusCurr < RT_ELEMENTS(pPages->aBuses); uBusCurr++) {
+        unsigned uDeviceCurr;
+        for (uDeviceCurr = 0; uDeviceCurr <
+                RT_ELEMENTS(pPages->aBuses[uBusCurr].aDevicePages);
+                        uDeviceCurr++) {
+            /* SCSI-SPI device page 0. */
+            pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].
+                SCSISPIDevicePage0.u.fields.Header.u8PageType   =
+                        MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
+                         | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE;
+            pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].
+                SCSISPIDevicePage0.u.fields.Header.u8PageNumber = 0;
+            pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].
+                SCSISPIDevicePage0.u.fields.Header.u8PageLength =
+                        sizeof(MptConfigurationPageSCSISPIDevice0) / 4;
+            /* Everything else 0 for now. */
+
+            /* SCSI-SPI device page 1. */
+            pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].
+                SCSISPIDevicePage1.u.fields.Header.u8PageType   =
+                        MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
+                         | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE;
+            pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].
+                SCSISPIDevicePage1.u.fields.Header.u8PageNumber = 1;
+            pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].
+                SCSISPIDevicePage1.u.fields.Header.u8PageLength =
+                        sizeof(MptConfigurationPageSCSISPIDevice1) / 4;
+            /* Everything else 0 for now. */
+
+            /* SCSI-SPI device page 2. */
+            pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].
+                SCSISPIDevicePage2.u.fields.Header.u8PageType   =
+                        MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
+                         | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE;
+            pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].
+                SCSISPIDevicePage2.u.fields.Header.u8PageNumber = 2;
+            pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].
+                SCSISPIDevicePage2.u.fields.Header.u8PageLength =
+                        sizeof(MptConfigurationPageSCSISPIDevice2) / 4;
+            /* Everything else 0 for now. */
+
+            pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].
+                SCSISPIDevicePage3.u.fields.Header.u8PageType   =
+                        MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
+                         | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE;
+            pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].
+                SCSISPIDevicePage3.u.fields.Header.u8PageNumber = 3;
+            pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].
+                SCSISPIDevicePage3.u.fields.Header.u8PageLength =
+                        sizeof(MptConfigurationPageSCSISPIDevice3) / 4;
+            /* Everything else 0 for now. */
+        }
+    }
+}
+
+static void lsilogic_init_config_pages_sas(LsilogicState *s)
+{
+    PMptConfigurationPagesSas pPages = &s->config_pages->u.SasPages;
+
+    /* Manufacturing Page 7 - Connector settings. */
+    pPages->cbManufacturingPage7 =
+        LSILOGICSCSI_MANUFACTURING7_GET_SIZE(s->ports);
+    PMptConfigurationPageManufacturing7 pManufacturingPage7 =
+        (PMptConfigurationPageManufacturing7)g_malloc0(
+            pPages->cbManufacturingPage7);
+    MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(pManufacturingPage7, 0, 7,
+                      MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
+    /* Set size manually. */
+    if (pPages->cbManufacturingPage7 / 4 > 255) {
+        pManufacturingPage7->u.fields.Header.u8PageLength = 255;
+    } else {
+        pManufacturingPage7->u.fields.Header.u8PageLength =
+                pPages->cbManufacturingPage7 / 4;
+    }
+    pManufacturingPage7->u.fields.u8NumPhys = s->ports;
+    pPages->pManufacturingPage7 = pManufacturingPage7;
+
+    /* SAS I/O unit page 0 - Port specific information. */
+    pPages->cbSASIOUnitPage0 = LSILOGICSCSI_SASIOUNIT0_GET_SIZE(s->ports);
+    PMptConfigurationPageSASIOUnit0 pSASPage0 =
+        (PMptConfigurationPageSASIOUnit0)g_malloc0(pPages->cbSASIOUnitPage0);
+
+    MPT_CONFIG_EXTENDED_PAGE_HEADER_INIT(pSASPage0, pPages->cbSASIOUnitPage0,
+                             0, MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY,
+                             MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT);
+    pSASPage0->u.fields.u8NumPhys = s->ports;
+    pPages->pSASIOUnitPage0 = pSASPage0;
+
+    /* SAS I/O unit page 1 - Port specific settings. */
+    pPages->cbSASIOUnitPage1 = LSILOGICSCSI_SASIOUNIT1_GET_SIZE(s->ports);
+    PMptConfigurationPageSASIOUnit1 pSASPage1 =
+        (PMptConfigurationPageSASIOUnit1)g_malloc0(pPages->cbSASIOUnitPage1);
+
+    MPT_CONFIG_EXTENDED_PAGE_HEADER_INIT(pSASPage1, pPages->cbSASIOUnitPage1,
+                             1, MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE,
+                             MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT);
+    pSASPage1->u.fields.u8NumPhys = pSASPage0->u.fields.u8NumPhys;
+    pSASPage1->u.fields.u16ControlFlags = 0;
+    pSASPage1->u.fields.u16AdditionalControlFlags = 0;
+    pPages->pSASIOUnitPage1 = pSASPage1;
+
+    /* SAS I/O unit page 2 - Port specific information. */
+    pPages->SASIOUnitPage2.u.fields.ExtHeader.u8PageType       =
+        MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
+         | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
+    pPages->SASIOUnitPage2.u.fields.ExtHeader.u8PageNumber     = 2;
+    pPages->SASIOUnitPage2.u.fields.ExtHeader.u8ExtPageType    =
+        MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT;
+    pPages->SASIOUnitPage2.u.fields.ExtHeader.u16ExtPageLength =
+        sizeof(MptConfigurationPageSASIOUnit2) / 4;
+
+    /* SAS I/O unit page 3 - Port specific information. */
+    pPages->SASIOUnitPage3.u.fields.ExtHeader.u8PageType       =
+        MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
+         | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
+    pPages->SASIOUnitPage3.u.fields.ExtHeader.u8PageNumber     = 3;
+    pPages->SASIOUnitPage3.u.fields.ExtHeader.u8ExtPageType    =
+        MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT;
+    pPages->SASIOUnitPage3.u.fields.ExtHeader.u16ExtPageLength =
+        sizeof(MptConfigurationPageSASIOUnit3) / 4;
+
+    pPages->cPHYs  = s->ports;
+    pPages->paPHYs = (PMptPHY)g_malloc0(pPages->cPHYs * sizeof(MptPHY));
+
+    /* Initialize the PHY configuration */
+    unsigned i;
+    for (i = 0; i < s->ports; i++) {
+        PMptPHY pPHYPages = &pPages->paPHYs[i];
+        uint16_t u16ControllerHandle = lsilogicGetHandle(s);
+
+        pManufacturingPage7->u.fields.aPHY[i].u8Location =
+                LSILOGICSCSI_MANUFACTURING7_LOCATION_AUTO;
+
+        pSASPage0->u.fields.aPHY[i].u8Port      = i;
+        pSASPage0->u.fields.aPHY[i].u8PortFlags = 0;
+        pSASPage0->u.fields.aPHY[i].u8PhyFlags  = 0;
+        pSASPage0->u.fields.aPHY[i].u8NegotiatedLinkRate =
+                LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_FAILED;
+        pSASPage0->u.fields.aPHY[i].u32ControllerPhyDeviceInfo =
+                LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(
+                    LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_NO);
+        pSASPage0->u.fields.aPHY[i].u16ControllerDevHandle =
+                u16ControllerHandle;
+        pSASPage0->u.fields.aPHY[i].u16AttachedDevHandle = 0;
+        pSASPage0->u.fields.aPHY[i].u32DiscoveryStatus = 0;
+
+        pSASPage1->u.fields.aPHY[i].u8Port           = i;
+        pSASPage1->u.fields.aPHY[i].u8PortFlags      = 0;
+        pSASPage1->u.fields.aPHY[i].u8PhyFlags       = 0;
+        pSASPage1->u.fields.aPHY[i].u8MaxMinLinkRate =
+                LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MIN_SET(
+                    LSILOGICSCSI_SASIOUNIT1_LINK_RATE_15GB)
+                   | LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MAX_SET(
+                    LSILOGICSCSI_SASIOUNIT1_LINK_RATE_30GB);
+        pSASPage1->u.fields.aPHY[i].u32ControllerPhyDeviceInfo =
+                LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(
+                    LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_NO);
+
+        /* SAS PHY page 0. */
+        pPHYPages->SASPHYPage0.u.fields.ExtHeader.u8PageType       =
+                MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
+                  | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
+        pPHYPages->SASPHYPage0.u.fields.ExtHeader.u8PageNumber     = 0;
+        pPHYPages->SASPHYPage0.u.fields.ExtHeader.u8ExtPageType    =
+                MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASPHYS;
+        pPHYPages->SASPHYPage0.u.fields.ExtHeader.u16ExtPageLength =
+                sizeof(MptConfigurationPageSASPHY0) / 4;
+        pPHYPages->SASPHYPage0.u.fields.u8AttachedPhyIdentifier    = i;
+        pPHYPages->SASPHYPage0.u.fields.u32AttachedDeviceInfo      =
+                LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_SET(
+                    LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_NO);
+        pPHYPages->SASPHYPage0.u.fields.u8ProgrammedLinkRate       =
+                LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MIN_SET(
+                    LSILOGICSCSI_SASIOUNIT1_LINK_RATE_15GB)
+                 | LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MAX_SET(
+                    LSILOGICSCSI_SASIOUNIT1_LINK_RATE_30GB);
+        pPHYPages->SASPHYPage0.u.fields.u8HwLinkRate               =
+                LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MIN_SET(
+                    LSILOGICSCSI_SASIOUNIT1_LINK_RATE_15GB)
+                 | LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MAX_SET(
+                    LSILOGICSCSI_SASIOUNIT1_LINK_RATE_30GB);
+
+        /* SAS PHY page 1. */
+        pPHYPages->SASPHYPage1.u.fields.ExtHeader.u8PageType       =
+                MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
+                 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
+        pPHYPages->SASPHYPage1.u.fields.ExtHeader.u8PageNumber     = 1;
+        pPHYPages->SASPHYPage1.u.fields.ExtHeader.u8ExtPageType    =
+                MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASPHYS;
+        pPHYPages->SASPHYPage1.u.fields.ExtHeader.u16ExtPageLength =
+                sizeof(MptConfigurationPageSASPHY1) / 4;
+
+        /* Settings for present devices. */
+        if (scsi_device_find(&s->bus, 0, i, 0)) {
+            uint16_t u16DeviceHandle = lsilogicGetHandle(s);
+            SASADDRESS SASAddress;
+            PMptSASDevice pSASDevice =
+                (PMptSASDevice)g_malloc0(sizeof(MptSASDevice));
+
+            memset(&SASAddress, 0, sizeof(SASADDRESS));
+            SASAddress.u64Address = s->sas_addr;
+
+            pSASPage0->u.fields.aPHY[i].u8NegotiatedLinkRate       =
+                LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_SET(
+                    LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_30GB);
+            pSASPage0->u.fields.aPHY[i].u32ControllerPhyDeviceInfo =
+                LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(
+                    LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_END)
+                 | LSILOGICSCSI_SASIOUNIT0_DEVICE_SSP_TARGET;
+            pSASPage0->u.fields.aPHY[i].u16AttachedDevHandle       =
+                u16DeviceHandle;
+            pSASPage1->u.fields.aPHY[i].u32ControllerPhyDeviceInfo =
+                LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(
+                    LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_END)
+                 | LSILOGICSCSI_SASIOUNIT0_DEVICE_SSP_TARGET;
+            pSASPage0->u.fields.aPHY[i].u16ControllerDevHandle     =
+                u16DeviceHandle;
+
+            pPHYPages->SASPHYPage0.u.fields.u32AttachedDeviceInfo  =
+                LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_SET(
+                    LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_END);
+            pPHYPages->SASPHYPage0.u.fields.SASAddress             =
+                SASAddress;
+            pPHYPages->SASPHYPage0.u.fields.u16OwnerDevHandle      =
+                u16DeviceHandle;
+            pPHYPages->SASPHYPage0.u.fields.u16AttachedDevHandle   =
+                u16DeviceHandle;
+
+            /* SAS device page 0. */
+            pSASDevice->SASDevicePage0.u.fields.ExtHeader.u8PageType       =
+                MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
+                 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
+            pSASDevice->SASDevicePage0.u.fields.ExtHeader.u8PageNumber     = 0;
+            pSASDevice->SASDevicePage0.u.fields.ExtHeader.u8ExtPageType    =
+                MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE;
+            pSASDevice->SASDevicePage0.u.fields.ExtHeader.u16ExtPageLength =
+                sizeof(MptConfigurationPageSASDevice0) / 4;
+            pSASDevice->SASDevicePage0.u.fields.SASAddress                 =
+                SASAddress;
+            pSASDevice->SASDevicePage0.u.fields.u16ParentDevHandle         =
+                u16ControllerHandle;
+            pSASDevice->SASDevicePage0.u.fields.u8PhyNum                   = i;
+            pSASDevice->SASDevicePage0.u.fields.u8AccessStatus =
+                LSILOGICSCSI_SASDEVICE0_STATUS_NO_ERRORS;
+            pSASDevice->SASDevicePage0.u.fields.u16DevHandle = u16DeviceHandle;
+            pSASDevice->SASDevicePage0.u.fields.u8TargetID                 = i;
+            pSASDevice->SASDevicePage0.u.fields.u8Bus                      = 0;
+            pSASDevice->SASDevicePage0.u.fields.u32DeviceInfo              =
+                LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_SET(
+                    LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_END)
+                     | LSILOGICSCSI_SASIOUNIT0_DEVICE_SSP_TARGET;
+            pSASDevice->SASDevicePage0.u.fields.u16Flags                   =
+             LSILOGICSCSI_SASDEVICE0_FLAGS_DEVICE_PRESENT
+             | LSILOGICSCSI_SASDEVICE0_FLAGS_DEVICE_MAPPED_TO_BUS_AND_TARGET_ID
+             | LSILOGICSCSI_SASDEVICE0_FLAGS_DEVICE_MAPPING_PERSISTENT;
+            pSASDevice->SASDevicePage0.u.fields.u8PhysicalPort             = i;
+
+            /* SAS device page 1. */
+            pSASDevice->SASDevicePage1.u.fields.ExtHeader.u8PageType       =
+                MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
+                     | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
+            pSASDevice->SASDevicePage1.u.fields.ExtHeader.u8PageNumber     = 1;
+            pSASDevice->SASDevicePage1.u.fields.ExtHeader.u8ExtPageType    =
+                MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE;
+            pSASDevice->SASDevicePage1.u.fields.ExtHeader.u16ExtPageLength =
+                sizeof(MptConfigurationPageSASDevice1) / 4;
+            pSASDevice->SASDevicePage1.u.fields.SASAddress = SASAddress;
+            pSASDevice->SASDevicePage1.u.fields.u16DevHandle = u16DeviceHandle;
+            pSASDevice->SASDevicePage1.u.fields.u8TargetID                 = i;
+            pSASDevice->SASDevicePage1.u.fields.u8Bus                      = 0;
+
+            /* SAS device page 2. */
+            pSASDevice->SASDevicePage2.u.fields.ExtHeader.u8PageType       =
+                        MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
+                          | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
+            pSASDevice->SASDevicePage2.u.fields.ExtHeader.u8PageNumber     = 2;
+            pSASDevice->SASDevicePage2.u.fields.ExtHeader.u8ExtPageType    =
+                        MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE;
+            pSASDevice->SASDevicePage2.u.fields.ExtHeader.u16ExtPageLength =
+                        sizeof(MptConfigurationPageSASDevice2) / 4;
+            pSASDevice->SASDevicePage2.u.fields.SASAddress                 =
+                        SASAddress;
+
+            /* Link into device list. */
+            if (!pPages->cDevices) {
+                pPages->pSASDeviceHead = pSASDevice;
+                pPages->pSASDeviceTail = pSASDevice;
+                pPages->cDevices = 1;
+            } else {
+                pSASDevice->pPrev = pPages->pSASDeviceTail;
+                pPages->pSASDeviceTail->pNext = pSASDevice;
+                pPages->pSASDeviceTail = pSASDevice;
+                pPages->cDevices++;
+            }
+        }
+    }
+}
+
+static void lsilogic_init_config_pages(LsilogicState *s)
+{
+    /* Initialize the common pages. */
+    PMptConfigurationPagesSupported pPages =
+        (PMptConfigurationPagesSupported)g_malloc0(
+                sizeof(MptConfigurationPagesSupported));
+
+    s->config_pages = pPages;
+
+    /* Clear everything first. */
+    memset(pPages, 0, sizeof(MptConfigurationPagesSupported));
+
+    /* Manufacturing Page 0. */
+    MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage0,
+                      MptConfigurationPageManufacturing0, 0,
+                      MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
+    strncpy((char *)pPages->ManufacturingPage0.u.fields.abChipName,
+                                                    "QEMU MPT Fusion", 16);
+    strncpy((char *)pPages->ManufacturingPage0.u.fields.abChipRevision,
+                                                    "1.0", 8);
+    strncpy((char *)pPages->ManufacturingPage0.u.fields.abBoardName,
+                                                    "QEMU MPT Fusion", 16);
+    strncpy((char *)pPages->ManufacturingPage0.u.fields.abBoardAssembly,
+                                                    "Verizon", 8);
+    strncpy((char *)pPages->ManufacturingPage0.u.fields.abBoardTracerNumber,
+                                                    "DEADBEEFDEADBEEF", 16);
+
+    /* Manufacturing Page 1 - Leave it 0 for now. */
+    MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage1,
+                      MptConfigurationPageManufacturing1, 1,
+                      MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
+
+    /* Manufacturing Page 2. */
+    MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage2,
+                      MptConfigurationPageManufacturing2, 2,
+                      MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
+
+    if (s->ctrl_type == 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 (s->ctrl_type == LSILOGICCTRLTYPE_SCSI_SAS) {
+        pPages->ManufacturingPage2.u.fields.u16PCIDeviceID =
+                LSILOGICSCSI_PCI_SAS_DEVICE_ID;
+        pPages->ManufacturingPage2.u.fields.u8PCIRevisionID =
+                LSILOGICSCSI_PCI_SAS_REVISION_ID;
+    }
+
+    /* Manufacturing Page 3. */
+    MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage3,
+                      MptConfigurationPageManufacturing3, 3,
+                      MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
+
+    if (s->ctrl_type == 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 (s->ctrl_type == LSILOGICCTRLTYPE_SCSI_SAS) {
+        pPages->ManufacturingPage3.u.fields.u16PCIDeviceID =
+                LSILOGICSCSI_PCI_SAS_DEVICE_ID;
+        pPages->ManufacturingPage3.u.fields.u8PCIRevisionID =
+                LSILOGICSCSI_PCI_SAS_REVISION_ID;
+    }
+
+    /* Manufacturing Page 4 - Leave it 0 for now. */
+    MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage4,
+                      MptConfigurationPageManufacturing4, 4,
+                      MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
+
+    /* Manufacturing Page 5 - WWID settings. */
+    MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage5,
+                      MptConfigurationPageManufacturing5, 5,
+                      MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
+
+    /* Manufacturing Page 6 - Product specific settings. */
+    MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage6,
+                                  MptConfigurationPageManufacturing6, 6,
+                                  MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
+
+    /* Manufacturing Page 8 -  Product specific settings. */
+    MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage8,
+                                  MptConfigurationPageManufacturing8, 8,
+                                  MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
+
+    /* Manufacturing Page 9 -  Product specific settings. */
+    MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage9,
+                                  MptConfigurationPageManufacturing9, 9,
+                                  MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
+
+    /* Manufacturing Page 10 -  Product specific settings. */
+    MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage10,
+                                  MptConfigurationPageManufacturing10, 10,
+                                  MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
+
+    /* I/O Unit page 0. */
+    MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage0,
+                                MptConfigurationPageIOUnit0, 0,
+                                MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
+    pPages->IOUnitPage0.u.fields.u64UniqueIdentifier = 0xcafe;
+
+    /* I/O Unit page 1. */
+    MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage1,
+                                MptConfigurationPageIOUnit1, 1,
+                                MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
+    pPages->IOUnitPage1.u.fields.fSingleFunction         = true;
+    pPages->IOUnitPage1.u.fields.fAllPathsMapped         = false;
+    pPages->IOUnitPage1.u.fields.fIntegratedRAIDDisabled = true;
+    pPages->IOUnitPage1.u.fields.f32BitAccessForced      = false;
+
+    /* I/O Unit page 2. */
+    MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage2,
+                                MptConfigurationPageIOUnit2, 2,
+                                MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT);
+    pPages->IOUnitPage2.u.fields.fPauseOnError       = false;
+    pPages->IOUnitPage2.u.fields.fVerboseModeEnabled = false;
+    pPages->IOUnitPage2.u.fields.fDisableColorVideo  = false;
+    pPages->IOUnitPage2.u.fields.fNotHookInt40h      = false;
+    pPages->IOUnitPage2.u.fields.u32BIOSVersion      = 0xdeadbeef;
+    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 = s->dev.devfn;
+
+    /* I/O Unit page 3. */
+    MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage3,
+                                MptConfigurationPageIOUnit3, 3,
+                                MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
+    pPages->IOUnitPage3.u.fields.u8GPIOCount = 0;
+
+    /* I/O Unit page 4. */
+    MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage4,
+                                MptConfigurationPageIOUnit4, 4,
+                                MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
+
+    /* IOC page 0. */
+    MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage0,
+                                MptConfigurationPageIOC0, 0,
+                                MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
+    pPages->IOCPage0.u.fields.u32TotalNVStore      = 0;
+    pPages->IOCPage0.u.fields.u32FreeNVStore       = 0;
+
+    if (s->ctrl_type == LSILOGICCTRLTYPE_SCSI_SPI) {
+        pPages->IOCPage0.u.fields.u16VendorId          =
+                LSILOGICSCSI_PCI_VENDOR_ID;
+        pPages->IOCPage0.u.fields.u16DeviceId          =
+                LSILOGICSCSI_PCI_SPI_DEVICE_ID;
+        pPages->IOCPage0.u.fields.u8RevisionId         =
+                LSILOGICSCSI_PCI_SPI_REVISION_ID;
+        pPages->IOCPage0.u.fields.u32ClassCode         =
+                LSILOGICSCSI_PCI_SPI_CLASS_CODE;
+        pPages->IOCPage0.u.fields.u16SubsystemVendorId =
+                LSILOGICSCSI_PCI_SPI_SUBSYSTEM_VENDOR_ID;
+        pPages->IOCPage0.u.fields.u16SubsystemId       =
+                LSILOGICSCSI_PCI_SPI_SUBSYSTEM_ID;
+    } else if (s->ctrl_type == LSILOGICCTRLTYPE_SCSI_SAS) {
+        pPages->IOCPage0.u.fields.u16VendorId          =
+                LSILOGICSCSI_PCI_VENDOR_ID;
+        pPages->IOCPage0.u.fields.u16DeviceId          =
+                LSILOGICSCSI_PCI_SAS_DEVICE_ID;
+        pPages->IOCPage0.u.fields.u8RevisionId         =
+                LSILOGICSCSI_PCI_SAS_REVISION_ID;
+        pPages->IOCPage0.u.fields.u32ClassCode         =
+                LSILOGICSCSI_PCI_SAS_CLASS_CODE;
+        pPages->IOCPage0.u.fields.u16SubsystemVendorId =
+                LSILOGICSCSI_PCI_SAS_SUBSYSTEM_VENDOR_ID;
+        pPages->IOCPage0.u.fields.u16SubsystemId       =
+                LSILOGICSCSI_PCI_SAS_SUBSYSTEM_ID;
+    }
+
+    /* IOC page 1. */
+    MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage1,
+                            MptConfigurationPageIOC1, 1,
+                            MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
+    pPages->IOCPage1.u.fields.fReplyCoalescingEnabled = false;
+    pPages->IOCPage1.u.fields.u32CoalescingTimeout    = 0;
+    pPages->IOCPage1.u.fields.u8CoalescingDepth       = 0;
+
+    /* IOC page 2. */
+    MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage2,
+                                MptConfigurationPageIOC2, 2,
+                                MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
+    /* Everything else here is 0. */
+
+    /* IOC page 3. */
+    MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage3,
+                                MptConfigurationPageIOC3, 3,
+                                MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
+    /* Everything else here is 0. */
+
+    /* IOC page 4. */
+    MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage4,
+                                MptConfigurationPageIOC4, 4,
+                                MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
+    /* Everything else here is 0. */
+
+    /* IOC page 6. */
+    MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage6,
+                                MptConfigurationPageIOC6, 6,
+                                MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
+    /* Everything else here is 0. */
+
+    /* BIOS page 1. */
+    MPT_CONFIG_PAGE_HEADER_INIT_BIOS(&pPages->BIOSPage1,
+                                 MptConfigurationPageBIOS1, 1,
+                                 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
+
+    /* BIOS page 2. */
+    MPT_CONFIG_PAGE_HEADER_INIT_BIOS(&pPages->BIOSPage2,
+                                 MptConfigurationPageBIOS2, 2,
+                                 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
+
+    /* BIOS page 4. */
+    MPT_CONFIG_PAGE_HEADER_INIT_BIOS(&pPages->BIOSPage4,
+                                 MptConfigurationPageBIOS4, 4,
+                                 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
+
+    if (s->ctrl_type == LSILOGICCTRLTYPE_SCSI_SPI) {
+        lsilogic_init_config_pages_spi(s);
+    } else if (s->ctrl_type == LSILOGICCTRLTYPE_SCSI_SAS) {
+        lsilogic_init_config_pages_sas(s);
+    }
+}
+
+
+static int lsilogic_hard_reset(LsilogicState *s)
+{
+
+    s->intr_mask |= LSILOGIC_REG_HOST_INTR_MASK_DOORBELL |
+                             LSILOGIC_REG_HOST_INTR_MASK_REPLY;
+    lsilogic_soft_reset(s);
+
+    /* Set default values. */
+    if (s->ctrl_type == LSILOGICCTRLTYPE_SCSI_SPI) {
+        s->max_devices = LSILOGICSCSI_PCI_SPI_PORTS_MAX *
+                         LSILOGICSCSI_PCI_SPI_DEVICES_PER_BUS_MAX;
+    } else if (s->ctrl_type == LSILOGICCTRLTYPE_SCSI_SAS) {
+        s->max_devices = LSILOGICSCSI_PCI_SAS_PORTS_MAX *
+                         LSILOGICSCSI_PCI_SAS_DEVICES_PER_PORT_MAX;
+    }
+    s->max_buses     = 1;
+    s->reply_frame_size  = 128; /* @todo Figure out where it is needed. */
+    s->next_handle = 1;
+
+    lsilogic_config_pages_free(s);
+    lsilogic_init_config_pages(s);
+
+    /* Mark that we finished performing the reset. */
+    s->state = LSILOGICSTATE_READY;
+    return 0;
+}
+
+static void lsilogic_scsi_reset(DeviceState *dev)
+{
+    LsilogicState *s = DO_UPCAST(LsilogicState, dev.qdev, dev);
+
+    lsilogic_hard_reset(s);
+}
+
+static const VMStateDescription vmstate_lsilogic = {
+    .name = "lsilogic",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, LsilogicState),
+
+        VMSTATE_UINT32(intr_mask, LsilogicState),
+        VMSTATE_UINT32(doorbell, LsilogicState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void lsilogic_queues_free(LsilogicState *s)
+{
+    assert(s->reply_free_queue);
+
+    g_free(s->reply_free_queue);
+
+    s->reply_free_queue = NULL;
+    s->reply_post_queue = NULL;
+    s->request_queue = NULL;
+}
+
+static void lsilogic_scsi_uninit(PCIDevice *d)
+{
+    LsilogicState *s = DO_UPCAST(LsilogicState, dev, d);
+
+    lsilogic_queues_free(s);
+#ifdef USE_MSIX
+    msix_uninit(&s->dev, &s->mmio_io);
+#endif
+    memory_region_destroy(&s->mmio_io);
+    memory_region_destroy(&s->port_io);
+    memory_region_destroy(&s->diag_io);
+}
+
+static const struct SCSIBusInfo lsilogic_scsi_info = {
+    .tcq = true,
+    .max_target = LSILOGICSCSI_PCI_SAS_PORTS_MAX,
+    .max_lun = 1,
+
+    .transfer_data = lsilogic_xfer_complete,
+    .get_sg_list = lsilogic_get_sg_list,
+    .complete = lsilogic_command_complete,
+    .cancel = lsilogic_command_cancel,
+};
+
+static int lsilogic_queues_alloc(LsilogicState *s)
+{
+    uint32_t cbQueues;
+
+    assert(!s->reply_free_queue);
+
+    cbQueues  = 2*s->reply_queue_entries * sizeof(uint32_t);
+    cbQueues += s->request_queue_entries * sizeof(uint32_t);
+
+    s->reply_free_queue = g_malloc0(cbQueues);
+
+    s->reply_post_queue = s->reply_free_queue + s->reply_queue_entries;
+
+    s->request_queue   = s->reply_post_queue + s->reply_queue_entries;
+
+    return 0;
+}
+
+static int lsilogic_scsi_init(PCIDevice *dev, LSILOGICCTRLTYPE ctrl_type)
+{
+    LsilogicState *s = DO_UPCAST(LsilogicState, dev, dev);
+    uint8_t *pci_conf;
+
+    s->ctrl_type = ctrl_type;
+
+    pci_conf = s->dev.config;
+
+    /* PCI latency timer = 0 */
+    pci_conf[PCI_LATENCY_TIMER] = 0;
+    /* Interrupt pin 1 */
+    pci_conf[PCI_INTERRUPT_PIN] = 0x01;
+
+    if (s->ctrl_type == LSILOGICCTRLTYPE_SCSI_SPI) {
+        memory_region_init_io(&s->mmio_io, &lsilogic_mmio_ops, s,
+                              "lsilogic-mmio", 0x4000);
+        memory_region_init_io(&s->port_io, &lsilogic_port_ops, s,
+                              "lsilogic-io", 256);
+        memory_region_init_io(&s->diag_io, &lsilogic_diag_ops, s,
+                              "lsilogic-diag", 0x10000);
+    } else if (s->ctrl_type == LSILOGICCTRLTYPE_SCSI_SAS) {
+        memory_region_init_io(&s->mmio_io, &lsilogic_mmio_ops, s,
+                              "lsilogic-mmio", 0x4000);
+        memory_region_init_io(&s->port_io, &lsilogic_port_ops, s,
+                              "lsilogic-io", 256);
+        memory_region_init_io(&s->diag_io, &lsilogic_diag_ops, s,
+                              "lsilogic-diag", 0x10000);
+    }
+
+#ifdef USE_MSIX
+    /* MSI-X support is currently broken */
+    if (lsilogic_use_msix(s) &&
+        msix_init(&s->dev, 15, &s->mmio_io, 0, 0x2000)) {
+        s->flags &= ~LSILOGIC_MASK_USE_MSIX;
+    }
+#else
+    s->flags &= ~LSILOGIC_MASK_USE_MSIX;
+#endif
+
+    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->port_io);
+    pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY |
+                                 PCI_BASE_ADDRESS_MEM_TYPE_32, &s->mmio_io);
+    pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY |
+                                 PCI_BASE_ADDRESS_MEM_TYPE_32, &s->diag_io);
+
+    if (lsilogic_use_msix(s)) {
+        msix_vector_use(&s->dev, 0);
+    }
+
+    if (!s->sas_addr) {
+        s->sas_addr = ((NAA_LOCALLY_ASSIGNED_ID << 24) |
+                       IEEE_COMPANY_LOCALLY_ASSIGNED) << 36;
+        s->sas_addr |= (pci_bus_num(dev->bus) << 16);
+        s->sas_addr |= (PCI_SLOT(dev->devfn) << 8);
+        s->sas_addr |= PCI_FUNC(dev->devfn);
+    }
+    s->reply_queue_entries = LSILOGICSCSI_REPLY_QUEUE_DEPTH_DEFAULT + 1;
+    s->request_queue_entries = LSILOGICSCSI_REQUEST_QUEUE_DEPTH_DEFAULT + 1;
+    lsilogic_queues_alloc(s);
+
+    trace_lsilogic_init(0, 0,
+                       lsilogic_use_msix(s) ? "MSI-X" : "INTx",
+                       lsilogic_is_sas(s) ? "sas" : "scsi");
+
+    if (s->ctrl_type == LSILOGICCTRLTYPE_SCSI_SPI) {
+        s->ports = LSILOGICSCSI_PCI_SPI_PORTS_MAX;
+        s->max_devices = s->ports * LSILOGICSCSI_PCI_SPI_DEVICES_PER_BUS_MAX;
+    } else if (s->ctrl_type == LSILOGICCTRLTYPE_SCSI_SAS) {
+        s->max_devices = s->ports * LSILOGICSCSI_PCI_SAS_DEVICES_PER_PORT_MAX;
+    }
+
+    scsi_bus_new(&s->bus, &dev->qdev, &lsilogic_scsi_info);
+    scsi_bus_legacy_handle_cmdline(&s->bus);
+    return 0;
+}
+
+static int lsilogic_scsi_spi_init(PCIDevice *dev)
+{
+    return lsilogic_scsi_init(dev, LSILOGICCTRLTYPE_SCSI_SPI);
+}
+
+static int lsilogic_scsi_sas_init(PCIDevice *dev)
+{
+    return lsilogic_scsi_init(dev, LSILOGICCTRLTYPE_SCSI_SAS);
+}
+
+static Property lsilogicscsi_properties[] = {
+#ifdef USE_MSIX
+    DEFINE_PROP_BIT("use_msix", LsilogicState, flags,
+                    LSILOGIC_FLAG_USE_MSIX, false),
+#endif
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static Property lsilogicsas_properties[] = {
+    DEFINE_PROP_UINT32("ports", LsilogicState, ports,
+                       LSILOGICSCSI_PCI_SAS_PORTS_DEFAULT),
+    DEFINE_PROP_HEX64("sas_address", LsilogicState, sas_addr, 0),
+#ifdef USE_MSIX
+    DEFINE_PROP_BIT("use_msix", LsilogicState, flags,
+                    LSILOGIC_FLAG_USE_MSIX, false),
+#endif
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void lsilogicscsi_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
+
+    pc->init = lsilogic_scsi_spi_init;
+    pc->exit = lsilogic_scsi_uninit;
+    pc->vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
+    pc->device_id = PCI_DEVICE_ID_LSI_53C1030;
+    pc->subsystem_vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
+    pc->subsystem_id = 0x8000;
+    pc->class_id = PCI_CLASS_STORAGE_SCSI;
+    dc->props = lsilogicscsi_properties;
+    dc->reset = lsilogic_scsi_reset;
+    dc->vmsd = &vmstate_lsilogic;
+    dc->desc = "LSI SCSI 53C1030";
+}
+
+static void lsilogicsas_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
+
+    pc->init = lsilogic_scsi_sas_init;
+    pc->exit = lsilogic_scsi_uninit;
+    pc->romfile = 0;
+    pc->vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
+    pc->device_id = PCI_DEVICE_ID_LSI_SAS1068;
+    pc->subsystem_vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
+    pc->subsystem_id = 0x8000;
+    pc->class_id = PCI_CLASS_STORAGE_SCSI;
+    dc->props = lsilogicsas_properties;
+    dc->reset = lsilogic_scsi_reset;
+    dc->vmsd = &vmstate_lsilogic;
+    dc->desc = "LSI SAS 1068";
+}
+
+static void lsilogicsase_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
+
+    pc->init = lsilogic_scsi_sas_init;
+    pc->exit = lsilogic_scsi_uninit;
+    pc->romfile = 0;
+    pc->vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
+    pc->device_id = PCI_DEVICE_ID_LSI_SAS1068E;
+    pc->subsystem_vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
+    pc->subsystem_id = 0x8000;
+    pc->is_express = 1;
+    pc->class_id = PCI_CLASS_STORAGE_SCSI;
+    dc->props = lsilogicsas_properties;
+    dc->reset = lsilogic_scsi_reset;
+    dc->vmsd = &vmstate_lsilogic;
+    dc->desc = "LSI SAS 1068E";
+}
+
+static const TypeInfo lsilogic_info[] = {
+    {
+        .name  = "lsi53c1030",
+        .parent = TYPE_PCI_DEVICE,
+        .instance_size = sizeof(LsilogicState),
+        .class_init = lsilogicscsi_class_init,
+    }, {
+        .name  = "sas1068",
+        .parent = TYPE_PCI_DEVICE,
+        .instance_size = sizeof(LsilogicState),
+        .class_init = lsilogicsas_class_init,
+    }, {
+        .name  = "sas1068e",
+        .parent = TYPE_PCI_DEVICE,
+        .instance_size = sizeof(LsilogicState),
+        .class_init = lsilogicsase_class_init,
+    }
+};
+
+static void lsilogic_register_types(void)
+{
+    unsigned i;
+    for (i = 0; i < ARRAY_SIZE(lsilogic_info); i++) {
+        type_register(&lsilogic_info[i]);
+    }
+}
+
+type_init(lsilogic_register_types)
diff --git a/hw/lsilogic.h b/hw/lsilogic.h
new file mode 100644
index 0000000..ed2f791
--- /dev/null
+++ b/hw/lsilogic.h
@@ -0,0 +1,3365 @@
+/* Id: DevLsiLogicSCSI.h 40640 2012-03-26 12:55:17Z vboxsync $ */
+/** @file
+ * VBox storage devices: LsiLogic LSI53c1030 SCSI controller - Defines and 
structures.
+ */
+
+/*
+ * Copyright (C) 2006-2009 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+#ifndef __DEVLSILOGICSCSI_H__
+#define __DEVLSILOGICSCSI_H__
+
+
+#define LSILOGICSCSI_REQUEST_QUEUE_DEPTH_DEFAULT 128
+#define LSILOGICSCSI_REPLY_QUEUE_DEPTH_DEFAULT   128
+
+#define LSILOGICSCSI_MAXIMUM_CHAIN_DEPTH 0x22
+
+#define LSILOGIC_NR_OF_ALLOWED_BIGGER_LISTS 100
+
+/** Equal for all devices */
+#define LSILOGICSCSI_PCI_VENDOR_ID            (0x1000)
+
+/** SPI SCSI controller (LSI53C1030) */
+#define LSILOGICSCSI_PCI_SPI_CTRLNAME             "LSI53C1030"
+#define LSILOGICSCSI_PCI_SPI_DEVICE_ID            (0x0030)
+#define LSILOGICSCSI_PCI_SPI_REVISION_ID          (0x00)
+#define LSILOGICSCSI_PCI_SPI_CLASS_CODE           (0x01)
+#define LSILOGICSCSI_PCI_SPI_SUBSYSTEM_VENDOR_ID  (0x1000)
+#define LSILOGICSCSI_PCI_SPI_SUBSYSTEM_ID         (0x8000)
+#define LSILOGICSCSI_PCI_SPI_PORTS_MAX            1
+#define LSILOGICSCSI_PCI_SPI_BUSES_MAX            1
+#define LSILOGICSCSI_PCI_SPI_DEVICES_PER_BUS_MAX  16
+#define LSILOGICSCSI_PCI_SPI_DEVICES_MAX \
+    (LSILOGICSCSI_PCI_SPI_BUSES_MAX*LSILOGICSCSI_PCI_SPI_DEVICES_PER_BUS_MAX)
+
+/** SAS SCSI controller (SAS1068 PCI-X Fusion-MPT SAS) */
+#define LSILOGICSCSI_PCI_SAS_CTRLNAME             "SAS1068"
+#define LSILOGICSCSI_PCI_SAS_DEVICE_ID            (0x0054)
+#define LSILOGICSCSI_PCI_SAS_REVISION_ID          (0x00)
+#define LSILOGICSCSI_PCI_SAS_CLASS_CODE           (0x00)
+#define LSILOGICSCSI_PCI_SAS_SUBSYSTEM_VENDOR_ID  (0x1000)
+#define LSILOGICSCSI_PCI_SAS_SUBSYSTEM_ID         (0x8000)
+#define LSILOGICSCSI_PCI_SAS_PORTS_MAX             256
+#define LSILOGICSCSI_PCI_SAS_PORTS_DEFAULT           8
+#define LSILOGICSCSI_PCI_SAS_DEVICES_PER_PORT_MAX    1
+#define LSILOGICSCSI_PCI_SAS_DEVICES_MAX \
+    (LSILOGICSCSI_PCI_SAS_PORTS_MAX*LSILOGICSCSI_PCI_SAS_DEVICES_PER_PORT_MAX)
+
+/**
+ * A SAS address.
+ */
+#pragma pack(1)
+typedef union SASADDRESS {
+    /** 64bit view. */
+    uint64_t    u64Address;
+    /** 32bit view. */
+    uint32_t    u32Address[2];
+    /** 16bit view. */
+    uint16_t    u16Address[4];
+    /** Byte view. */
+    uint8_t     u8Address[8];
+} SASADDRESS, *PSASADDRESS;
+#pragma pack()
+
+/**
+ * Possible device types we support.
+ */
+typedef enum LSILOGICCTRLTYPE {
+    /** SPI SCSI controller (PCI dev id 0x0030) */
+    LSILOGICCTRLTYPE_SCSI_SPI = 0,
+    /** SAS SCSI controller (PCI dev id 0x0054) */
+    LSILOGICCTRLTYPE_SCSI_SAS = 1,
+    /** 32bit hack */
+    LSILOGICCTRLTYPE_32BIT_HACK = 0x7fffffff
+} LSILOGICCTRLTYPE, *PLSILOGICCTRLTYPE;
+
+/**
+ * A simple SG element for a 64bit address.
+ */
+#pragma pack(1)
+typedef struct MptSGEntrySimple64 {
+    /** Length of the buffer this entry describes. */
+    unsigned u24Length:24;
+    /** Flag whether this element is the end of the list. */
+    unsigned fEndOfList:1;
+    /** Flag whether the address is 32bit or 64bits wide. */
+    unsigned f64BitAddress:1;
+    /** Flag whether this buffer contains data to be transferred or
+        is the destination. */
+    unsigned fBufferContainsData:1;
+    /** Flag whether this is a local address or a system address. */
+    unsigned fLocalAddress:1;
+    /** Element type. */
+    unsigned u2ElementType:2;
+    /** Flag whether this is the last element of the buffer. */
+    unsigned fEndOfBuffer:1;
+    /** Flag whether this is the last element of the current segment. */
+    unsigned fLastElement:1;
+    /** Lower 32bits of the address of the data buffer. */
+    unsigned u32DataBufferAddressLow:32;
+    /** Upper 32bits of the address of the data buffer. */
+    unsigned u32DataBufferAddressHigh:32;
+} MptSGEntrySimple64, *PMptSGEntrySimple64;
+#pragma pack()
+
+/**
+ * A simple SG element for a 32bit address.
+ */
+#pragma pack(1)
+typedef struct MptSGEntrySimple32 {
+    /** Length of the buffer this entry describes. */
+    unsigned u24Length:24;
+    /** Flag whether this element is the end of the list. */
+    unsigned fEndOfList:1;
+    /** Flag whether the address is 32bit or 64bits wide. */
+    unsigned f64BitAddress:1;
+    /** Flag whether this buffer contains data to be transferred
+        or is the destination. */
+    unsigned fBufferContainsData:1;
+    /** Flag whether this is a local address or a system address. */
+    unsigned fLocalAddress:1;
+    /** Element type. */
+    unsigned u2ElementType:2;
+    /** Flag whether this is the last element of the buffer. */
+    unsigned fEndOfBuffer:1;
+    /** Flag whether this is the last element of the current segment. */
+    unsigned fLastElement:1;
+    /** Lower 32bits of the address of the data buffer. */
+    unsigned u32DataBufferAddressLow:32;
+} MptSGEntrySimple32, *PMptSGEntrySimple32;
+#pragma pack()
+
+/**
+ * A chain SG element.
+ */
+#pragma pack(1)
+typedef struct MptSGEntryChain {
+    /** Size of the segment. */
+    unsigned u16Length:16;
+    /** Offset in 32bit words of the next chain element in the segment
+     *  identified by this element. */
+    unsigned u8NextChainOffset:8;
+    /** Reserved. */
+    unsigned fReserved0:1;
+    /** Flag whether the address is 32bit or 64bits wide. */
+    unsigned f64BitAddress:1;
+    /** Reserved. */
+    unsigned fReserved1:1;
+    /** Flag whether this is a local address or a system address. */
+    unsigned fLocalAddress:1;
+    /** Element type. */
+    unsigned u2ElementType:2;
+    /** Flag whether this is the last element of the buffer. */
+    unsigned u2Reserved2:2;
+    /** Lower 32bits of the address of the data buffer. */
+    unsigned u32SegmentAddressLow:32;
+    /** Upper 32bits of the address of the data buffer. */
+    unsigned u32SegmentAddressHigh:32;
+} MptSGEntryChain, *PMptSGEntryChain;
+#pragma pack()
+
+typedef union MptSGEntryUnion {
+    MptSGEntrySimple64 Simple64;
+    MptSGEntrySimple32 Simple32;
+    MptSGEntryChain    Chain;
+} MptSGEntryUnion, *PMptSGEntryUnion;
+
+/**
+ * MPT Fusion message header - Common for all message frames.
+ * This is filled in by the guest.
+ */
+#pragma pack(1)
+typedef struct MptMessageHdr {
+    /** Function dependent data. */
+    uint16_t    u16FunctionDependent;
+    /** Chain offset. */
+    uint8_t     u8ChainOffset;
+    /** The function code. */
+    uint8_t     u8Function;
+    /** Function dependent data. */
+    uint8_t     au8FunctionDependent[3];
+    /** Message flags. */
+    uint8_t     u8MessageFlags;
+    /** Message context - Unique ID from the guest unmodified by the device. */
+    uint32_t    u32MessageContext;
+} MptMessageHdr, *PMptMessageHdr;
+#pragma pack()
+
+/** Defined function codes found in the message header. */
+#define MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST        (0x00)
+#define MPT_MESSAGE_HDR_FUNCTION_SCSI_TASK_MGMT         (0x01)
+#define MPT_MESSAGE_HDR_FUNCTION_IOC_INIT               (0x02)
+#define MPT_MESSAGE_HDR_FUNCTION_IOC_FACTS              (0x03)
+#define MPT_MESSAGE_HDR_FUNCTION_CONFIG                 (0x04)
+#define MPT_MESSAGE_HDR_FUNCTION_PORT_FACTS             (0x05)
+#define MPT_MESSAGE_HDR_FUNCTION_PORT_ENABLE            (0x06)
+#define MPT_MESSAGE_HDR_FUNCTION_EVENT_NOTIFICATION     (0x07)
+#define MPT_MESSAGE_HDR_FUNCTION_EVENT_ACK              (0x08)
+#define MPT_MESSAGE_HDR_FUNCTION_FW_DOWNLOAD            (0x09)
+#define MPT_MESSAGE_HDR_FUNCTION_TARGET_CMD_BUFFER_POST (0x0A)
+#define MPT_MESSAGE_HDR_FUNCTION_TARGET_ASSIST          (0x0B)
+#define MPT_MESSAGE_HDR_FUNCTION_TARGET_STATUS_SEND     (0x0C)
+#define MPT_MESSAGE_HDR_FUNCTION_TARGET_MODE_ABORT      (0x0D)
+#define MPT_MESSAGE_HDR_FUNCTION_FW_UPLOAD              (0x12)
+
+#ifdef DEBUG
+/**
+ * Function names
+ */
+static const char * const g_apszMPTFunctionNames[] = {
+    "SCSI I/O Request",
+    "SCSI Task Management",
+    "IOC Init",
+    "IOC Facts",
+    "Config",
+    "Port Facts",
+    "Port Enable",
+    "Event Notification",
+    "Event Ack",
+    "Firmware Download"
+};
+#endif
+
+/**
+ * Default reply message.
+ * Send from the device to the guest upon completion of a request.
+ */
+ #pragma pack(1)
+typedef struct MptDefaultReplyMessage {
+    /** Function dependent data. */
+    uint16_t    u16FunctionDependent;
+    /** Length of the message in 32bit DWords. */
+    uint8_t     u8MessageLength;
+    /** Function which completed. */
+    uint8_t     u8Function;
+    /** Function dependent. */
+    uint8_t     au8FunctionDependent[3];
+    /** Message flags. */
+    uint8_t     u8MessageFlags;
+    /** Message context given in the request. */
+    uint32_t    u32MessageContext;
+    /** Function dependent status code. */
+    uint16_t    u16FunctionDependentStatus;
+    /** Status of the IOC. */
+    uint16_t    u16IOCStatus;
+    /** Additional log info. */
+    uint32_t    u32IOCLogInfo;
+} MptDefaultReplyMessage, *PMptDefaultReplyMessage;
+#pragma pack()
+
+/**
+ * IO controller init request.
+ */
+#pragma pack(1)
+typedef struct MptIOCInitRequest {
+    /** Which system send this init request. */
+    uint8_t     u8WhoInit;
+    /** Reserved */
+    uint8_t     u8Reserved;
+    /** Chain offset in the SG list. */
+    uint8_t     u8ChainOffset;
+    /** Function to execute. */
+    uint8_t     u8Function;
+    /** Flags */
+    uint8_t     u8Flags;
+    /** Maximum number of devices the driver can handle. */
+    uint8_t     u8MaxDevices;
+    /** Maximum number of buses the driver can handle. */
+    uint8_t     u8MaxBuses;
+    /** Message flags. */
+    uint8_t     u8MessageFlags;
+    /** Message context ID. */
+    uint32_t    u32MessageContext;
+    /** Reply frame size. */
+    uint16_t    u16ReplyFrameSize;
+    /** Reserved */
+    uint16_t    u16Reserved;
+    /** Upper 32bit part of the 64bit address the message frames are in.
+     *  That means all frames must be in the same 4GB segment. */
+    uint32_t    u32HostMfaHighAddr;
+    /** Upper 32bit of the sense buffer. */
+    uint32_t    u32SenseBufferHighAddr;
+} MptIOCInitRequest, *PMptIOCInitRequest;
+#pragma pack()
+
+/**
+ * IO controller init reply.
+ */
+#pragma pack(1)
+typedef struct MptIOCInitReply {
+    /** Which subsystem send this init request. */
+    uint8_t     u8WhoInit;
+    /** Reserved */
+    uint8_t     u8Reserved;
+    /** Message length */
+    uint8_t     u8MessageLength;
+    /** Function. */
+    uint8_t     u8Function;
+    /** Flags */
+    uint8_t     u8Flags;
+    /** Maximum number of devices the driver can handle. */
+    uint8_t     u8MaxDevices;
+    /** Maximum number of busses the driver can handle. */
+    uint8_t     u8MaxBuses;
+    /** Message flags. */
+    uint8_t     u8MessageFlags;
+    /** Message context ID */
+    uint32_t    u32MessageContext;
+    /** Reserved */
+    uint16_t    u16Reserved;
+    /** IO controller status. */
+    uint16_t    u16IOCStatus;
+    /** IO controller log information. */
+    uint32_t    u32IOCLogInfo;
+} MptIOCInitReply, *PMptIOCInitReply;
+#pragma pack()
+
+/**
+ * IO controller facts request.
+ */
+#pragma pack(1)
+typedef struct MptIOCFactsRequest {
+    /** Reserved. */
+    uint16_t    u16Reserved;
+    /** Chain offset in SG list. */
+    uint8_t     u8ChainOffset;
+    /** Function number. */
+    uint8_t     u8Function;
+    /** Reserved */
+    uint8_t     u8Reserved[3];
+    /** Message flags. */
+    uint8_t     u8MessageFlags;
+    /** Message context ID. */
+    uint32_t    u32MessageContext;
+} MptIOCFactsRequest, *PMptIOCFactsRequest;
+#pragma pack()
+
+/**
+ * IO controller facts reply.
+ */
+#pragma pack(1)
+typedef struct MptIOCFactsReply {
+    /** Message version. */
+    uint16_t    u16MessageVersion;
+    /** Message length. */
+    uint8_t     u8MessageLength;
+    /** Function number. */
+    uint8_t     u8Function;
+    /** Reserved */
+    uint16_t    u16Reserved1;
+    /** IO controller number */
+    uint8_t     u8IOCNumber;
+    /** Message flags. */
+    uint8_t     u8MessageFlags;
+    /** Message context ID. */
+    uint32_t    u32MessageContext;
+    /** IO controller exceptions */
+    uint16_t    u16IOCExceptions;
+    /** IO controller status. */
+    uint16_t    u16IOCStatus;
+    /** IO controller log information. */
+    uint32_t    u32IOCLogInfo;
+    /** Maximum chain depth. */
+    uint8_t     u8MaxChainDepth;
+    /** The current value of the WhoInit field. */
+    uint8_t     u8WhoInit;
+    /** Block size. */
+    uint8_t     u8BlockSize;
+    /** Flags. */
+    uint8_t     u8Flags;
+    /** Depth of the reply queue. */
+    uint16_t    u16ReplyQueueDepth;
+    /** Size of a request frame. */
+    uint16_t    u16RequestFrameSize;
+    /** Reserved */
+    uint16_t    u16Reserved2;
+    /** Product ID. */
+    uint16_t    u16ProductID;
+    /** Current value of the high 32bit MFA address. */
+    uint32_t    u32CurrentHostMFAHighAddr;
+    /** Global credits - Number of entries allocated to queues */
+    uint16_t    u16GlobalCredits;
+    /** Number of ports on the IO controller */
+    uint8_t     u8NumberOfPorts;
+    /** Event state. */
+    uint8_t     u8EventState;
+    /** Current value of the high 32bit sense buffer address. */
+    uint32_t    u32CurrentSenseBufferHighAddr;
+    /** Current reply frame size. */
+    uint16_t    u16CurReplyFrameSize;
+    /** Maximum number of devices. */
+    uint8_t     u8MaxDevices;
+    /** Maximum number of buses. */
+    uint8_t     u8MaxBuses;
+    /** Size of the firmware image. */
+    uint32_t    u32FwImageSize;
+    /** Reserved. */
+    uint32_t    u32Reserved;
+    /** Firmware version */
+    uint32_t    u32FWVersion;
+} MptIOCFactsReply, *PMptIOCFactsReply;
+#pragma pack()
+
+/**
+ * Port facts request
+ */
+#pragma pack(1)
+typedef struct MptPortFactsRequest {
+    /** Reserved */
+    uint16_t    u16Reserved1;
+    /** Message length. */
+    uint8_t     u8MessageLength;
+    /** Function number. */
+    uint8_t     u8Function;
+    /** Reserved */
+    uint16_t    u16Reserved2;
+    /** Port number to get facts for. */
+    uint8_t     u8PortNumber;
+    /** Message flags. */
+    uint8_t     u8MessageFlags;
+    /** Message context ID. */
+    uint32_t    u32MessageContext;
+} MptPortFactsRequest, *PMptPortFactsRequest;
+#pragma pack()
+
+/**
+ * Port facts reply.
+ */
+#pragma pack(1)
+typedef struct MptPortFactsReply {
+    /** Reserved. */
+    uint16_t    u16Reserved1;
+    /** Message length. */
+    uint8_t     u8MessageLength;
+    /** Function number. */
+    uint8_t     u8Function;
+    /** Reserved */
+    uint16_t    u16Reserved2;
+    /** Port number the facts are for. */
+    uint8_t     u8PortNumber;
+    /** Message flags. */
+    uint8_t     u8MessageFlags;
+    /** Message context ID. */
+    uint32_t    u32MessageContext;
+    /** Reserved. */
+    uint16_t    u16Reserved3;
+    /** IO controller status. */
+    uint16_t    u16IOCStatus;
+    /** IO controller log information. */
+    uint32_t    u32IOCLogInfo;
+    /** Reserved */
+    uint8_t     u8Reserved;
+    /** Port type */
+    uint8_t     u8PortType;
+    /** Maximum number of devices on this port. */
+    uint16_t    u16MaxDevices;
+    /** SCSI ID of this port on the attached bus. */
+    uint16_t    u16PortSCSIID;
+    /** Protocol flags. */
+    uint16_t    u16ProtocolFlags;
+    /** Maximum number of target command buffers which can be
+        posted to this port at a time. */
+    uint16_t    u16MaxPostedCmdBuffers;
+    /** Maximum number of target IDs that remain persistent
+        between power/reset cycles. */
+    uint16_t    u16MaxPersistentIDs;
+    /** Maximum number of LAN buckets. */
+    uint16_t    u16MaxLANBuckets;
+    /** Reserved. */
+    uint16_t    u16Reserved4;
+    /** Reserved. */
+    uint32_t    u32Reserved;
+} MptPortFactsReply, *PMptPortFactsReply;
+#pragma pack()
+
+/**
+ * Port Enable request.
+ */
+#pragma pack(1)
+typedef struct MptPortEnableRequest {
+    /** Reserved. */
+    uint16_t    u16Reserved1;
+    /** Message length. */
+    uint8_t     u8MessageLength;
+    /** Function number. */
+    uint8_t     u8Function;
+    /** Reserved. */
+    uint16_t    u16Reserved2;
+    /** Port number to enable. */
+    uint8_t     u8PortNumber;
+    /** Message flags. */
+    uint8_t     u8MessageFlags;
+    /** Message context ID. */
+    uint32_t    u32MessageContext;
+} MptPortEnableRequest, *PMptPortEnableRequest;
+#pragma pack()
+
+/**
+ * Port enable reply.
+ */
+#pragma pack(1)
+typedef struct MptPortEnableReply {
+    /** Reserved. */
+    uint16_t    u16Reserved1;
+    /** Message length. */
+    uint8_t     u8MessageLength;
+    /** Function number. */
+    uint8_t     u8Function;
+    /** Reserved */
+    uint16_t    u16Reserved2;
+    /** Port number which was enabled. */
+    uint8_t     u8PortNumber;
+    /** Message flags. */
+    uint8_t     u8MessageFlags;
+    /** Message context ID. */
+    uint32_t    u32MessageContext;
+    /** Reserved. */
+    uint16_t    u16Reserved3;
+    /** IO controller status */
+    uint16_t    u16IOCStatus;
+    /** IO controller log information. */
+    uint32_t    u32IOCLogInfo;
+} MptPortEnableReply, *PMptPortEnableReply;
+#pragma pack()
+
+/**
+ * Event notification request.
+ */
+#pragma pack(1)
+typedef struct MptEventNotificationRequest {
+    /** Switch - Turns event notification on and off. */
+    uint8_t     u8Switch;
+    /** Reserved. */
+    uint8_t     u8Reserved1;
+    /** Chain offset. */
+    uint8_t     u8ChainOffset;
+    /** Function number. */
+    uint8_t     u8Function;
+    /** Reserved. */
+    uint8_t     u8reserved2[3];
+    /** Message flags. */
+    uint8_t     u8MessageFlags;
+    /** Message context ID. */
+    uint32_t    u32MessageContext;
+} MptEventNotificationRequest, *PMptEventNotificationRequest;
+#pragma pack()
+
+/**
+ * Event notification reply.
+ */
+#pragma pack(1)
+typedef struct MptEventNotificationReply {
+    /** Event data length. */
+    uint16_t    u16EventDataLength;
+    /** Message length. */
+    uint8_t     u8MessageLength;
+    /** Function number. */
+    uint8_t     u8Function;
+    /** Reserved. */
+    uint16_t    u16Reserved1;
+    /** Ack required. */
+    uint8_t     u8AckRequired;
+    /** Message flags. */
+    uint8_t     u8MessageFlags;
+    /** Message context ID. */
+    uint32_t    u32MessageContext;
+    /** Reserved. */
+    uint16_t    u16Reserved2;
+    /** IO controller status. */
+    uint16_t    u16IOCStatus;
+    /** IO controller log information. */
+    uint32_t    u32IOCLogInfo;
+    /** Notification event. */
+    uint32_t    u32Event;
+    /** Event context. */
+    uint32_t    u32EventContext;
+    /** Event data. */
+    uint32_t    u32EventData;
+} MptEventNotificationReply, *PMptEventNotificationReply;
+#pragma pack()
+
+#define MPT_EVENT_EVENT_CHANGE (0x0000000a)
+
+/**
+ * FW download request.
+ */
+#pragma pack(1)
+typedef struct MptFWDownloadRequest {
+    /** Switch - Turns event notification on and off. */
+    uint8_t     u8ImageType;
+    /** Reserved. */
+    uint8_t     u8Reserved1;
+    /** Chain offset. */
+    uint8_t     u8ChainOffset;
+    /** Function number. */
+    uint8_t     u8Function;
+    /** Reserved. */
+    uint8_t     u8Reserved2[3];
+    /** Message flags. */
+    uint8_t     u8MessageFlags;
+    /** Message context ID. */
+    uint32_t    u32MessageContext;
+} MptFWDownloadRequest, *PMptFWDownloadRequest;
+#pragma pack()
+
+#define MPT_FW_DOWNLOAD_REQUEST_IMAGE_TYPE_RESERVED 0
+#define MPT_FW_DOWNLOAD_REQUEST_IMAGE_TYPE_FIRMWARE 1
+#define MPT_FW_DOWNLOAD_REQUEST_IMAGE_TYPE_MPI_BIOS 2
+#define MPT_FW_DOWNLOAD_REQUEST_IMAGE_TYPE_NVDATA   3
+
+/**
+ * FW download reply.
+ */
+#pragma pack(1)
+typedef struct MptFWDownloadReply {
+    /** Reserved. */
+    uint16_t    u16Reserved1;
+    /** Message length. */
+    uint8_t     u8MessageLength;
+    /** Function number. */
+    uint8_t     u8Function;
+    /** Reserved. */
+    uint8_t     u8Reserved2[3];
+    /** Message flags. */
+    uint8_t     u8MessageFlags;
+    /** Message context ID. */
+    uint32_t    u32MessageContext;
+    /** Reserved. */
+    uint16_t    u16Reserved2;
+    /** IO controller status. */
+    uint16_t    u16IOCStatus;
+    /** IO controller log information. */
+    uint32_t    u32IOCLogInfo;
+} MptFWDownloadReply, *PMptFWDownloadReply;
+#pragma pack()
+
+typedef struct MptFwHeader {
+    uint32_t    ArmBranchInstruction0;      /* 00h */
+    uint32_t    Signature0;                 /* 04h */
+    uint32_t    Signature1;                 /* 08h */
+    uint32_t    Signature2;                 /* 0Ch */
+    uint32_t    ArmBranchInstruction1;      /* 10h */
+    uint32_t    ArmBranchInstruction2;      /* 14h */
+    uint32_t    Reserved;                   /* 18h */
+    uint32_t    Checksum;                   /* 1Ch */
+    uint16_t    VendorId;                   /* 20h */
+    uint16_t    ProductId;                  /* 22h */
+    uint32_t    FWVersion;                  /* 24h */
+    uint32_t    SeqCodeVersion;             /* 28h */
+    uint32_t    ImageSize;                  /* 2Ch */
+    uint32_t    NextImageHeaderOffset;      /* 30h */
+    uint32_t    LoadStartAddress;           /* 34h */
+    uint32_t    IopResetVectorValue;        /* 38h */
+    uint32_t    IopResetRegAddr;            /* 3Ch */
+    uint32_t    VersionNameWhat;            /* 40h */
+    uint8_t     VersionName[32];            /* 44h */
+    uint32_t    VendorNameWhat;             /* 64h */
+    uint8_t     VendorName[32];             /* 68h */
+} MptFwHeader_t, *pMptFwHeader_t;
+
+typedef struct MptFWUploadTCSGE {
+    uint8_t      Reserved;                   /* 00h */
+    uint8_t      ContextSize;                /* 01h */
+    uint8_t      DetailsLength;              /* 02h */
+    uint8_t      Flags;                      /* 03h */
+    uint32_t     Reserved1;                  /* 04h */
+    uint32_t     ImageOffset;                /* 08h */
+    uint32_t     ImageSize;                  /* 0Ch */
+} MptFWUploadTCSGE_t, *pMptFWUploadTCSGE_t;
+
+#define MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM          (0x00)
+#define MPI_FW_UPLOAD_ITYPE_FW_FLASH            (0x01)
+#define MPI_FW_UPLOAD_ITYPE_BIOS_FLASH          (0x02)
+#define MPI_FW_UPLOAD_ITYPE_NVDATA              (0x03)
+#define MPI_FW_UPLOAD_ITYPE_BOOTLOADER          (0x04)
+#define MPI_FW_UPLOAD_ITYPE_FW_BACKUP           (0x05)
+#define MPI_FW_UPLOAD_ITYPE_MANUFACTURING       (0x06)
+#define MPI_FW_UPLOAD_ITYPE_CONFIG_1            (0x07)
+#define MPI_FW_UPLOAD_ITYPE_CONFIG_2            (0x08)
+#define MPI_FW_UPLOAD_ITYPE_MEGARAID            (0x09)
+#define MPI_FW_UPLOAD_ITYPE_COMPLETE            (0x0A)
+#define MPI_FW_UPLOAD_ITYPE_COMMON_BOOT_BLOCK   (0x0B)
+
+/**
+ * FW upload request.
+ */
+#pragma pack(1)
+typedef struct MptFWUploadRequest {
+    /** Requested image type. */
+    uint8_t     u8ImageType;
+    /** Reserved. */
+    uint8_t     u8Reserved1;
+    /** Chain offset. */
+    uint8_t     u8ChainOffset;
+    /** Function number. */
+    uint8_t     u8Function;
+    /** Reserved. */
+    uint8_t     u8Reserved2[3];
+    /** Message flags. */
+    uint8_t     u8MessageFlags;
+    /** Message context ID. */
+    uint32_t    u32MessageContext;
+    MptFWUploadTCSGE_t TCSge;
+    MptSGEntrySimple32 sge;
+} MptFWUploadRequest, *PMptFWUploadRequest;
+#pragma pack()
+
+/**
+ * FW upload reply.
+ */
+#pragma pack(1)
+typedef struct MptFWUploadReply {
+    /** Image type. */
+    uint8_t     u8ImageType;
+    /** Reserved. */
+    uint8_t     u8Reserved1;
+    /** Message length. */
+    uint8_t     u8MessageLength;
+    /** Function number. */
+    uint8_t     u8Function;
+    /** Reserved. */
+    uint8_t     u8Reserved2[3];
+    /** Message flags. */
+    uint8_t     u8MessageFlags;
+    /** Message context ID. */
+    uint32_t    u32MessageContext;
+    /** Reserved. */
+    uint16_t    u16Reserved2;
+    /** IO controller status. */
+    uint16_t    u16IOCStatus;
+    /** IO controller log information. */
+    uint32_t    u32IOCLogInfo;
+    /** Uploaded image size. */
+    uint32_t    u32ActualImageSize;
+} MptFWUploadReply, *PMptFWUploadReply;
+#pragma pack()
+
+/**
+ * SCSI IO Request
+ */
+#pragma pack(1)
+typedef struct MptSCSIIORequest {
+    /** Target ID */
+    uint8_t     u8TargetID;
+    /** Bus number */
+    uint8_t     u8Bus;
+    /** Chain offset */
+    uint8_t     u8ChainOffset;
+    /** Function number. */
+    uint8_t     u8Function;
+    /** CDB length. */
+    uint8_t     u8CDBLength;
+    /** Sense buffer length. */
+    uint8_t     u8SenseBufferLength;
+    /** Reserved */
+    uint8_t     u8Reserved;
+    /** Message flags. */
+    uint8_t     u8MessageFlags;
+    /** Message context ID. */
+    uint32_t    u32MessageContext;
+    /** LUN */
+    uint8_t     au8LUN[8];
+    /** Control values. */
+    uint32_t    u32Control;
+    /** The CDB. */
+    uint8_t     au8CDB[16];
+    /** Data length. */
+    uint32_t    u32DataLength;
+    /** Sense buffer low 32bit address. */
+    uint32_t    u32SenseBufferLowAddress;
+} MptSCSIIORequest, *PMptSCSIIORequest;
+#pragma pack()
+
+#define MPT_SCSIIO_REQUEST_CONTROL_TXDIR_GET(x) (((x) & 0x3000000) >> 24)
+#define MPT_SCSIIO_REQUEST_CONTROL_TXDIR_NONE  (0x0)
+#define MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE (0x1)
+#define MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ  (0x2)
+
+/**
+ * SCSI IO error reply.
+ */
+#pragma pack(1)
+typedef struct MptSCSIIOErrorReply {
+    /** Target ID */
+    uint8_t     u8TargetID;
+    /** Bus number */
+    uint8_t     u8Bus;
+    /** Message length. */
+    uint8_t     u8MessageLength;
+    /** Function number. */
+    uint8_t     u8Function;
+    /** CDB length */
+    uint8_t     u8CDBLength;
+    /** Sense buffer length */
+    uint8_t     u8SenseBufferLength;
+    /** Reserved */
+    uint8_t     u8Reserved;
+    /** Message flags */
+    uint8_t     u8MessageFlags;
+    /** Message context ID */
+    uint32_t    u32MessageContext;
+    /** SCSI status. */
+    uint8_t     u8SCSIStatus;
+    /** SCSI state */
+    uint8_t     u8SCSIState;
+    /** IO controller status */
+    uint16_t    u16IOCStatus;
+    /** IO controller log information */
+    uint32_t    u32IOCLogInfo;
+    /** Transfer count */
+    uint32_t    u32TransferCount;
+    /** Sense count */
+    uint32_t    u32SenseCount;
+    /** Response information */
+    uint32_t    u32ResponseInfo;
+} MptSCSIIOErrorReply, *PMptSCSIIOErrorReply;
+#pragma pack()
+
+#define MPT_SCSI_IO_ERROR_SCSI_STATE_AUTOSENSE_VALID (0x01)
+#define MPT_SCSI_IO_ERROR_SCSI_STATE_TERMINATED      (0x08)
+
+/**
+ * IOC status codes specific to the SCSI I/O error reply.
+ */
+#define MPT_SCSI_IO_ERROR_IOCSTATUS_INVALID_BUS      (0x0041)
+#define MPT_SCSI_IO_ERROR_IOCSTATUS_INVALID_TARGETID (0x0042)
+#define MPT_SCSI_IO_ERROR_IOCSTATUS_DEVICE_NOT_THERE (0x0043)
+
+/**
+ * SCSI task management request.
+ */
+#pragma pack(1)
+typedef struct MptSCSITaskManagementRequest {
+    /** Target ID */
+    uint8_t     u8TargetID;
+    /** Bus number */
+    uint8_t     u8Bus;
+    /** Chain offset */
+    uint8_t     u8ChainOffset;
+    /** Function number */
+    uint8_t     u8Function;
+    /** Reserved */
+    uint8_t     u8Reserved1;
+    /** Task type */
+    uint8_t     u8TaskType;
+    /** Reserved */
+    uint8_t     u8Reserved2;
+    /** Message flags */
+    uint8_t     u8MessageFlags;
+    /** Message context ID */
+    uint32_t    u32MessageContext;
+    /** LUN */
+    uint8_t     au8LUN[8];
+    /** Reserved */
+    uint8_t     auReserved[28];
+    /** Task message context ID. */
+    uint32_t    u32TaskMessageContext;
+} MptSCSITaskManagementRequest, *PMptSCSITaskManagementRequest;
+#pragma pack()
+
+/**
+ * SCSI task management reply.
+ */
+#pragma pack(1)
+typedef struct MptSCSITaskManagementReply {
+    /** Target ID */
+    uint8_t     u8TargetID;
+    /** Bus number */
+    uint8_t     u8Bus;
+    /** Message length */
+    uint8_t     u8MessageLength;
+    /** Function number */
+    uint8_t     u8Function;
+    /** Reserved */
+    uint8_t     u8Reserved1;
+    /** Task type */
+    uint8_t     u8TaskType;
+    /** Reserved */
+    uint8_t     u8Reserved2;
+    /** Message flags */
+    uint8_t     u8MessageFlags;
+    /** Message context ID */
+    uint32_t    u32MessageContext;
+    /** Reserved */
+    uint16_t    u16Reserved;
+    /** IO controller status */
+    uint16_t    u16IOCStatus;
+    /** IO controller log information */
+    uint32_t    u32IOCLogInfo;
+    /** Termination count */
+    uint32_t    u32TerminationCount;
+} MptSCSITaskManagementReply, *PMptSCSITaskManagementReply;
+#pragma pack()
+
+/**
+ * Page address for SAS expander page types.
+ */
+#pragma pack(1)
+typedef union MptConfigurationPageAddressSASExpander {
+    struct {
+        uint16_t    u16Handle;
+        uint16_t    u16Reserved;
+    } Form0And2;
+    struct {
+        uint16_t    u16Handle;
+        uint8_t     u8PhyNum;
+        uint8_t     u8Reserved;
+    } Form1;
+} MptConfigurationPageAddressSASExpander,
+ *PMptConfigurationPageAddressSASExpander;
+#pragma pack()
+
+/**
+ * Page address for SAS device page types.
+ */
+#pragma pack(1)
+typedef union MptConfigurationPageAddressSASDevice {
+    struct {
+        uint16_t    u16Handle;
+        uint16_t    u16Reserved;
+    } Form0And2;
+    struct {
+        uint8_t     u8TargetID;
+        uint8_t     u8Bus;
+        uint8_t     u8Reserved;
+    } Form1;
+} MptConfigurationPageAddressSASDevice, *PMptConfigurationPageAddressSASDevice;
+#pragma pack()
+
+/**
+ * Page address for SAS PHY page types.
+ */
+#pragma pack(1)
+typedef union MptConfigurationPageAddressSASPHY {
+    struct {
+        uint8_t     u8PhyNumber;
+        uint8_t     u8Reserved[3];
+    } Form0;
+    struct {
+        uint16_t    u16Index;
+        uint16_t    u16Reserved;
+    } Form1;
+} MptConfigurationPageAddressSASPHY, *PMptConfigurationPageAddressSASPHY;
+#pragma pack()
+
+/**
+ * Page address for SAS Enclosure page types.
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageAddressSASEnclosure {
+    uint16_t    u16Handle;
+    uint16_t    u16Reserved;
+} MptConfigurationPageAddressSASEnclosure,
+ *PMptConfigurationPageAddressSASEnclosure;
+#pragma pack()
+
+/**
+ * Union of all possible address types.
+ */
+#pragma pack(1)
+typedef union MptConfigurationPageAddress {
+    /** 32bit view. */
+    uint32_t u32PageAddress;
+    struct {
+        /** Port number to get the configuration page for. */
+        uint8_t u8PortNumber;
+        /** Reserved. */
+        uint8_t u8Reserved[3];
+    } MPIPortNumber;
+    struct {
+        /** Target ID to get the configuration page for. */
+        uint8_t u8TargetID;
+        /** Bus number to get the configuration page for. */
+        uint8_t u8Bus;
+        /** Reserved. */
+        uint8_t u8Reserved[2];
+    } BusAndTargetId;
+    MptConfigurationPageAddressSASExpander  SASExpander;
+    MptConfigurationPageAddressSASDevice    SASDevice;
+    MptConfigurationPageAddressSASPHY       SASPHY;
+    MptConfigurationPageAddressSASEnclosure SASEnclosure;
+} MptConfigurationPageAddress, *PMptConfigurationPageAddress;
+#pragma pack()
+
+#define MPT_CONFIGURATION_PAGE_ADDRESS_GET_SAS_FORM(x) \
+ (((x).u32PageAddress >> 28) & 0x0f)
+
+/**
+ * Configuration request
+ */
+#pragma pack(1)
+typedef struct MptConfigurationRequest {
+    /** Action code. */
+    uint8_t    u8Action;
+    /** Reserved. */
+    uint8_t    u8Reserved1;
+    /** Chain offset. */
+    uint8_t    u8ChainOffset;
+    /** Function number. */
+    uint8_t    u8Function;
+    /** Extended page length. */
+    uint16_t   u16ExtPageLength;
+    /** Extended page type */
+    uint8_t    u8ExtPageType;
+    /** Message flags. */
+    uint8_t    u8MessageFlags;
+    /** Message context ID. */
+    uint32_t   u32MessageContext;
+    /** Reserved. */
+    uint8_t    u8Reserved2[8];
+    /** Version number of the page. */
+    uint8_t    u8PageVersion;
+    /** Length of the page in 32bit Dwords. */
+    uint8_t    u8PageLength;
+    /** Page number to access. */
+    uint8_t    u8PageNumber;
+    /** Type of the page being accessed. */
+    uint8_t    u8PageType;
+    /** Page type dependent address. */
+    MptConfigurationPageAddress PageAddress;
+    /** Simple SG element describing the buffer. */
+    MptSGEntrySimple64          SimpleSGElement;
+    uint32_t    reserved[4];
+} MptConfigurationRequest, *PMptConfigurationRequest;
+#pragma pack()
+
+/** Possible action codes. */
+#define MPT_CONFIGURATION_REQUEST_ACTION_HEADER        (0x00)
+#define MPT_CONFIGURATION_REQUEST_ACTION_READ_CURRENT  (0x01)
+#define MPT_CONFIGURATION_REQUEST_ACTION_WRITE_CURRENT (0x02)
+#define MPT_CONFIGURATION_REQUEST_ACTION_DEFAULT       (0x03)
+#define MPT_CONFIGURATION_REQUEST_ACTION_WRITE_NVRAM   (0x04)
+#define MPT_CONFIGURATION_REQUEST_ACTION_READ_DEFAULT  (0x05)
+#define MPT_CONFIGURATION_REQUEST_ACTION_READ_NVRAM    (0x06)
+
+/** Page type codes. */
+#define MPT_CONFIGURATION_REQUEST_PAGE_TYPE_IO_UNIT    (0x00)
+#define MPT_CONFIGURATION_REQUEST_PAGE_TYPE_IOC        (0x01)
+#define MPT_CONFIGURATION_REQUEST_PAGE_TYPE_BIOS       (0x02)
+#define MPT_CONFIGURATION_REQUEST_PAGE_TYPE_SCSI_PORT  (0x03)
+#define MPT_CONFIGURATION_REQUEST_PAGE_TYPE_EXTENDED   (0x0F)
+
+/**
+ * Configuration reply.
+ */
+#pragma pack(1)
+typedef struct MptConfigurationReply {
+    /** Action code. */
+    uint8_t    u8Action;
+    /** Reserved. */
+    uint8_t    u8Reserved;
+    /** Message length. */
+    uint8_t    u8MessageLength;
+    /** Function number. */
+    uint8_t    u8Function;
+    /** Extended page length. */
+    uint16_t   u16ExtPageLength;
+    /** Extended page type */
+    uint8_t    u8ExtPageType;
+    /** Message flags. */
+    uint8_t    u8MessageFlags;
+    /** Message context ID. */
+    uint32_t   u32MessageContext;
+    /** Reserved. */
+    uint16_t   u16Reserved;
+    /** I/O controller status. */
+    uint16_t   u16IOCStatus;
+    /** I/O controller log information. */
+    uint32_t   u32IOCLogInfo;
+    /** Version number of the page. */
+    uint8_t    u8PageVersion;
+    /** Length of the page in 32bit Dwords. */
+    uint8_t    u8PageLength;
+    /** Page number to access. */
+    uint8_t    u8PageNumber;
+    /** Type of the page being accessed. */
+    uint8_t    u8PageType;
+} MptConfigurationReply, *PMptConfigurationReply;
+#pragma pack()
+
+/** Additional I/O controller status codes for the configuration reply. */
+#define MPT_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020)
+#define MPT_IOCSTATUS_CONFIG_INVALID_TYPE   (0x0021)
+#define MPT_IOCSTATUS_CONFIG_INVALID_PAGE   (0x0022)
+#define MPT_IOCSTATUS_CONFIG_INVALID_DATA   (0x0023)
+#define MPT_IOCSTATUS_CONFIG_NO_DEFAULTS    (0x0024)
+#define MPT_IOCSTATUS_CONFIG_CANT_COMMIT    (0x0025)
+
+/**
+ * Union of all possible request messages.
+ */
+typedef union MptRequestUnion {
+    MptMessageHdr                Header;
+    MptIOCInitRequest            IOCInit;
+    MptIOCFactsRequest           IOCFacts;
+    MptPortFactsRequest          PortFacts;
+    MptPortEnableRequest         PortEnable;
+    MptEventNotificationRequest  EventNotification;
+    MptSCSIIORequest             SCSIIO;
+    MptSCSITaskManagementRequest SCSITaskManagement;
+    MptConfigurationRequest      Configuration;
+    MptFWDownloadRequest         FWDownload;
+    MptFWUploadRequest           FWUpload;
+} MptRequestUnion, *PMptRequestUnion;
+
+/**
+ * Union of all possible reply messages.
+ */
+typedef union MptReplyUnion {
+    /** 16bit view. */
+    uint16_t                   au16Reply[30];
+    MptDefaultReplyMessage     Header;
+    MptIOCInitReply            IOCInit;
+    MptIOCFactsReply           IOCFacts;
+    MptPortFactsReply          PortFacts;
+    MptPortEnableReply         PortEnable;
+    MptEventNotificationReply  EventNotification;
+    MptSCSIIOErrorReply        SCSIIOError;
+    MptSCSITaskManagementReply SCSITaskManagement;
+    MptConfigurationReply      Configuration;
+    MptFWDownloadReply         FWDownload;
+    MptFWUploadReply           FWUpload;
+} MptReplyUnion, *PMptReplyUnion;
+
+
+/**
+ * Configuration Page attributes.
+ */
+#define MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY            (0x00)
+#define MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE          (0x10)
+#define MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT          (0x20)
+#define MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY (0x30)
+
+#define MPT_CONFIGURATION_PAGE_ATTRIBUTE_GET(u8PageType) ((u8PageType) & 0xf0)
+
+/**
+ * Configuration Page types.
+ */
+#define MPT_CONFIGURATION_PAGE_TYPE_IO_UNIT                  (0x00)
+#define MPT_CONFIGURATION_PAGE_TYPE_IOC                      (0x01)
+#define MPT_CONFIGURATION_PAGE_TYPE_BIOS                     (0x02)
+#define MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_PORT            (0x03)
+#define MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE          (0x04)
+#define MPT_CONFIGURATION_PAGE_TYPE_MANUFACTURING            (0x09)
+#define MPT_CONFIGURATION_PAGE_TYPE_EXTENDED                 (0x0F)
+
+#define MPT_CONFIGURATION_PAGE_TYPE_GET(u8PageType) ((u8PageType) & 0x0f)
+
+/**
+ * Extented page types.
+ */
+#define MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT       (0x10)
+#define MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASEXPANDER     (0x11)
+#define MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE       (0x12)
+#define MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASPHYS         (0x13)
+#define MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_LOG             (0x14)
+#define MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_ENCLOSURE       (0x15)
+
+/**
+ * Configuration Page header - Common to all pages.
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageHeader {
+    /** Version of the page. */
+    uint8_t     u8PageVersion;
+    /** The length of the page in 32bit D-Words. */
+    uint8_t     u8PageLength;
+    /** Number of the page. */
+    uint8_t     u8PageNumber;
+    /** Type of the page. */
+    uint8_t     u8PageType;
+} MptConfigurationPageHeader, *PMptConfigurationPageHeader;
+#pragma pack()
+
+/**
+ * Extended configuration page header - Common to all extended pages.
+ */
+#pragma pack(1)
+typedef struct MptExtendedConfigurationPageHeader {
+    /** Version of the page. */
+    uint8_t     u8PageVersion;
+    /** Reserved. */
+    uint8_t     u8Reserved1;
+    /** Number of the page. */
+    uint8_t     u8PageNumber;
+    /** Type of the page. */
+    uint8_t     u8PageType;
+    /** Extended page length. */
+    uint16_t    u16ExtPageLength;
+    /** Extended page type. */
+    uint8_t     u8ExtPageType;
+    /** Reserved */
+    uint8_t     u8Reserved2;
+} MptExtendedConfigurationPageHeader, *PMptExtendedConfigurationPageHeader;
+#pragma pack()
+
+/**
+ * Manufacturing page 0. - Readonly.
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageManufacturing0 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[76];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Name of the chip. */
+            uint8_t               abChipName[16];
+            /** Chip revision. */
+            uint8_t               abChipRevision[8];
+            /** Board name. */
+            uint8_t               abBoardName[16];
+            /** Board assembly. */
+            uint8_t               abBoardAssembly[16];
+            /** Board tracer number. */
+            uint8_t               abBoardTracerNumber[16];
+        } fields;
+    } u;
+} MptConfigurationPageManufacturing0, *PMptConfigurationPageManufacturing0;
+#pragma pack()
+
+/**
+ * Manufacturing page 1. - Readonly Persistent.
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageManufacturing1 {
+    /** Union */
+    union {
+        /** Byte view */
+        uint8_t                           abPageData[260];
+        /** Field view */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** VPD info - don't know what belongs here so all zero. */
+            uint8_t                       abVPDInfo[256];
+        } fields;
+    } u;
+} MptConfigurationPageManufacturing1, *PMptConfigurationPageManufacturing1;
+#pragma pack()
+
+/**
+ * Manufacturing page 2. - Readonly.
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageManufacturing2 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                        abPageData[8];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader Header;
+            /** PCI Device ID. */
+            uint16_t                   u16PCIDeviceID;
+            /** PCI Revision ID. */
+            uint8_t                    u8PCIRevisionID;
+            /** Reserved. */
+            uint8_t                    u8Reserved;
+            /** Hardware specific settings... */
+        } fields;
+    } u;
+} MptConfigurationPageManufacturing2, *PMptConfigurationPageManufacturing2;
+#pragma pack()
+
+/**
+ * Manufacturing page 3. - Readonly.
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageManufacturing3 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[8];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** PCI Device ID. */
+            uint16_t              u16PCIDeviceID;
+            /** PCI Revision ID. */
+            uint8_t               u8PCIRevisionID;
+            /** Reserved. */
+            uint8_t               u8Reserved;
+            /** Chip specific settings... */
+        } fields;
+    } u;
+} MptConfigurationPageManufacturing3, *PMptConfigurationPageManufacturing3;
+#pragma pack()
+
+/**
+ * Manufacturing page 4. - Readonly.
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageManufacturing4 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[84];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Reserved. */
+            uint32_t              u32Reserved;
+            /** InfoOffset0. */
+            uint8_t               u8InfoOffset0;
+            /** Info size. */
+            uint8_t               u8InfoSize0;
+            /** InfoOffset1. */
+            uint8_t               u8InfoOffset1;
+            /** Info size. */
+            uint8_t               u8InfoSize1;
+            /** Size of the inquiry data. */
+            uint8_t               u8InquirySize;
+            /** Reserved. */
+            uint8_t               abReserved[3];
+            /** Inquiry data. */
+            uint8_t               abInquiryData[56];
+            /** IS volume settings. */
+            uint32_t              u32ISVolumeSettings;
+            /** IME volume settings. */
+            uint32_t              u32IMEVolumeSettings;
+            /** IM volume settings. */
+            uint32_t              u32IMVolumeSettings;
+        } fields;
+    } u;
+} MptConfigurationPageManufacturing4, *PMptConfigurationPageManufacturing4;
+#pragma pack()
+
+/**
+ * Manufacturing page 5 - Readonly.
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageManufacturing5 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                           abPageData[88];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Base WWID. */
+            uint64_t                      u64BaseWWID;
+            /** Flags */
+            uint8_t                       u8Flags;
+            /** Number of ForceWWID fields in this page. */
+            uint8_t                       u8NumForceWWID;
+            /** Reserved */
+            uint16_t                      u16Reserved;
+            /** Reserved */
+            uint32_t                      au32Reserved[2];
+            /** ForceWWID entries  Maximum of 8 because the SAS
+               controller doesn't has more */
+            uint64_t                      au64ForceWWID[8];
+        } fields;
+    } u;
+} MptConfigurationPageManufacturing5, *PMptConfigurationPageManufacturing5;
+#pragma pack()
+
+/**
+ * Manufacturing page 6 - Readonly.
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageManufacturing6 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                           abPageData[4];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Product specific data - 0 for now */
+        } fields;
+    } u;
+} MptConfigurationPageManufacturing6, *PMptConfigurationPageManufacturing6;
+#pragma pack()
+
+/**
+ * Manufacutring page 7 - PHY element.
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageManufacturing7PHY {
+    /** Pinout */
+    uint32_t                  u32Pinout;
+    /** Connector name */
+    uint8_t                   szConnector[16];
+    /** Location */
+    uint8_t                   u8Location;
+    /** reserved */
+    uint8_t                   u8Reserved;
+    /** Slot */
+    uint16_t                  u16Slot;
+} MptConfigurationPageManufacturing7PHY,
+ *PMptConfigurationPageManufacturing7PHY;
+#pragma pack()
+
+/**
+ * Manufacturing page 7 - Readonly.
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageManufacturing7 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                           abPageData[1];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Reserved */
+            uint32_t                      au32Reserved[2];
+            /** Flags */
+            uint32_t                      u32Flags;
+            /** Enclosure name */
+            uint8_t                       szEnclosureName[16];
+            /** Number of PHYs */
+            uint8_t                       u8NumPhys;
+            /** Reserved */
+            uint8_t                       au8Reserved[3];
+            /** PHY list for the SAS controller -
+                variable depending on the number of ports */
+            MptConfigurationPageManufacturing7PHY aPHY[1];
+        } fields;
+    } u;
+} MptConfigurationPageManufacturing7, *PMptConfigurationPageManufacturing7;
+#pragma pack()
+
+#define LSILOGICSCSI_MANUFACTURING7_GET_SIZE(ports) \
+ (sizeof(MptConfigurationPageManufacturing7) + ((ports) - 1) * \
+  sizeof(MptConfigurationPageManufacturing7PHY))
+
+/** Flags for the flags field */
+#define LSILOGICSCSI_MANUFACTURING7_FLAGS_USE_PROVIDED_INFORMATION (1<<0)
+
+/** Flags for the pinout field */
+#define LSILOGICSCSI_MANUFACTURING7_PINOUT_UNKNOWN                 (1<<0)
+#define LSILOGICSCSI_MANUFACTURING7_PINOUT_SFF8482                 (1<<1)
+#define LSILOGICSCSI_MANUFACTURING7_PINOUT_SFF8470_LANE1           (1<<8)
+#define LSILOGICSCSI_MANUFACTURING7_PINOUT_SFF8470_LANE2           (1<<9)
+#define LSILOGICSCSI_MANUFACTURING7_PINOUT_SFF8470_LANE3           (1<<10)
+#define LSILOGICSCSI_MANUFACTURING7_PINOUT_SFF8470_LANE4           (1<<11)
+#define LSILOGICSCSI_MANUFACTURING7_PINOUT_SFF8484_LANE1           (1<<16)
+#define LSILOGICSCSI_MANUFACTURING7_PINOUT_SFF8484_LANE2           (1<<17)
+#define LSILOGICSCSI_MANUFACTURING7_PINOUT_SFF8484_LANE3           (1<<18)
+#define LSILOGICSCSI_MANUFACTURING7_PINOUT_SFF8484_LANE4           (1<<19)
+
+/** Flags for the location field */
+#define LSILOGICSCSI_MANUFACTURING7_LOCATION_UNKNOWN               0x01
+#define LSILOGICSCSI_MANUFACTURING7_LOCATION_INTERNAL              0x02
+#define LSILOGICSCSI_MANUFACTURING7_LOCATION_EXTERNAL              0x04
+#define LSILOGICSCSI_MANUFACTURING7_LOCATION_SWITCHABLE            0x08
+#define LSILOGICSCSI_MANUFACTURING7_LOCATION_AUTO                  0x10
+#define LSILOGICSCSI_MANUFACTURING7_LOCATION_NOT_PRESENT           0x20
+#define LSILOGICSCSI_MANUFACTURING7_LOCATION_NOT_CONNECTED         0x80
+
+/**
+ * Manufacturing page 8 - Readonly.
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageManufacturing8 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                           abPageData[4];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Product specific information */
+        } fields;
+    } u;
+} MptConfigurationPageManufacturing8, *PMptConfigurationPageManufacturing8;
+#pragma pack()
+
+/**
+ * Manufacturing page 9 - Readonly.
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageManufacturing9 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                           abPageData[4];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Product specific information */
+        } fields;
+    } u;
+} MptConfigurationPageManufacturing9, *PMptConfigurationPageManufacturing9;
+#pragma pack()
+
+/**
+ * Manufacturing page 10 - Readonly.
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageManufacturing10 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                           abPageData[4];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Product specific information */
+        } fields;
+    } u;
+} MptConfigurationPageManufacturing10, *PMptConfigurationPageManufacturing10;
+#pragma pack()
+
+/**
+ * IO Unit page 0. - Readonly.
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageIOUnit0 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[12];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** A unique identifier. */
+            uint64_t              u64UniqueIdentifier;
+        } fields;
+    } u;
+} MptConfigurationPageIOUnit0, *PMptConfigurationPageIOUnit0;
+#pragma pack()
+
+/**
+ * IO Unit page 1. - Read/Write.
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageIOUnit1 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[8];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Flag whether this is a single function PCI device. */
+            unsigned              fSingleFunction:1;
+            /** Flag whether all possible paths to a device are mapped. */
+            unsigned              fAllPathsMapped:1;
+            /** Reserved. */
+            unsigned              u4Reserved:4;
+            /** Flag whether all RAID functionality is disabled. */
+            unsigned              fIntegratedRAIDDisabled:1;
+            /** Flag whether 32bit PCI accesses are forced. */
+            unsigned              f32BitAccessForced:1;
+            /** Reserved. */
+            unsigned              abReserved:24;
+        } fields;
+    } u;
+} MptConfigurationPageIOUnit1, *PMptConfigurationPageIOUnit1;
+#pragma pack()
+
+/**
+ * Adapter Ordering.
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageIOUnit2AdapterOrdering {
+    /** PCI bus number. */
+    unsigned    u8PCIBusNumber:8;
+    /** PCI device and function number. */
+    unsigned    u8PCIDevFn:8;
+    /** Flag whether the adapter is embedded. */
+    unsigned    fAdapterEmbedded:1;
+    /** Flag whether the adapter is enabled. */
+    unsigned    fAdapterEnabled:1;
+    /** Reserved. */
+    unsigned    u6Reserved:6;
+    /** Reserved. */
+    unsigned    u8Reserved:8;
+} MptConfigurationPageIOUnit2AdapterOrdering,
+ *PMptConfigurationPageIOUnit2AdapterOrdering;
+#pragma pack()
+
+/**
+ * IO Unit page 2. - Read/Write.
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageIOUnit2 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[28];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Reserved. */
+            unsigned              fReserved:1;
+            /** Flag whether Pause on error is enabled. */
+            unsigned              fPauseOnError:1;
+            /** Flag whether verbose mode is enabled. */
+            unsigned              fVerboseModeEnabled:1;
+            /** Set to disable color video. */
+            unsigned              fDisableColorVideo:1;
+            /** Flag whether int 40h is hooked. */
+            unsigned              fNotHookInt40h:1;
+            /** Reserved. */
+            unsigned              u3Reserved:3;
+            /** Reserved. */
+            unsigned              abReserved:24;
+            /** BIOS version. */
+            uint32_t              u32BIOSVersion;
+            /** Adapter ordering. */
+            MptConfigurationPageIOUnit2AdapterOrdering aAdapterOrder[4];
+        } fields;
+    } u;
+} MptConfigurationPageIOUnit2, *PMptConfigurationPageIOUnit2;
+#pragma pack()
+
+/*
+ * IO Unit page 3. - Read/Write.
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageIOUnit3 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[8];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Number of GPIO values. */
+            uint8_t               u8GPIOCount;
+            /** Reserved. */
+            uint8_t               abReserved[3];
+        } fields;
+    } u;
+} MptConfigurationPageIOUnit3, *PMptConfigurationPageIOUnit3;
+#pragma pack()
+
+/*
+ * IO Unit page 4. - Readonly for everyone except the BIOS.
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageIOUnit4 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[20];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Reserved */
+            uint32_t                      u32Reserved;
+            /** SG entry describing the Firmware location. */
+            MptSGEntrySimple64            FWImageSGE;
+        } fields;
+    } u;
+} MptConfigurationPageIOUnit4, *PMptConfigurationPageIOUnit4;
+#pragma pack()
+
+/**
+ * IOC page 0. - Readonly
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageIOC0 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[28];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Total amount of NV memory in bytes. */
+            uint32_t              u32TotalNVStore;
+            /** Number of free bytes in the NV store. */
+            uint32_t              u32FreeNVStore;
+            /** PCI vendor ID. */
+            uint16_t              u16VendorId;
+            /** PCI device ID. */
+            uint16_t              u16DeviceId;
+            /** PCI revision ID. */
+            uint8_t               u8RevisionId;
+            /** Reserved. */
+            uint8_t               abReserved[3];
+            /** PCI class code. */
+            uint32_t              u32ClassCode;
+            /** Subsystem vendor Id. */
+            uint16_t              u16SubsystemVendorId;
+            /** Subsystem Id. */
+            uint16_t              u16SubsystemId;
+        } fields;
+    } u;
+} MptConfigurationPageIOC0, *PMptConfigurationPageIOC0;
+#pragma pack()
+
+/**
+ * IOC page 1. - Read/Write
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageIOC1 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[16];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Flag whether reply coalescing is enabled. */
+            unsigned              fReplyCoalescingEnabled:1;
+            /** Reserved. */
+            unsigned              u31Reserved:31;
+            /** Coalescing Timeout in microseconds. */
+            unsigned              u32CoalescingTimeout:32;
+            /** Coalescing depth. */
+            unsigned              u8CoalescingDepth:8;
+            /** Reserved. */
+            unsigned              u8Reserved0:8;
+            unsigned              u8Reserved1:8;
+            unsigned              u8Reserved2:8;
+        } fields;
+    } u;
+} MptConfigurationPageIOC1, *PMptConfigurationPageIOC1;
+#pragma pack()
+
+/**
+ * IOC page 2. - Readonly
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageIOC2 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[12];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Flag whether striping is supported. */
+            unsigned              fStripingSupported:1;
+            /** Flag whether enhanced mirroring is supported. */
+            unsigned              fEnhancedMirroringSupported:1;
+            /** Flag whether mirroring is supported. */
+            unsigned              fMirroringSupported:1;
+            /** Reserved. */
+            unsigned              u26Reserved:26;
+            /** Flag whether SES is supported. */
+            unsigned              fSESSupported:1;
+            /** Flag whether SAF-TE is supported. */
+            unsigned              fSAFTESupported:1;
+            /** Flag whether cross channel volumes are supported. */
+            unsigned              fCrossChannelVolumesSupported:1;
+            /** Number of active integrated RAID volumes. */
+            unsigned              u8NumActiveVolumes:8;
+            /** Maximum number of integrated RAID volumes supported. */
+            unsigned              u8MaxVolumes:8;
+            /** Number of active integrated RAID physical disks. */
+            unsigned              u8NumActivePhysDisks:8;
+            /** Maximum number of integrated RAID physical disks supported. */
+            unsigned              u8MaxPhysDisks:8;
+            /** RAID volumes... - not supported. */
+        } fields;
+    } u;
+} MptConfigurationPageIOC2, *PMptConfigurationPageIOC2;
+#pragma pack()
+
+/**
+ * IOC page 3. - Readonly
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageIOC3 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[8];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Number of active integrated RAID physical disks. */
+            uint8_t               u8NumPhysDisks;
+            /** Reserved. */
+            uint8_t               abReserved[3];
+        } fields;
+    } u;
+} MptConfigurationPageIOC3, *PMptConfigurationPageIOC3;
+#pragma pack()
+
+/**
+ * IOC page 4. - Read/Write
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageIOC4 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[8];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Number of SEP entries in this page. */
+            uint8_t               u8ActiveSEP;
+            /** Maximum number of SEp entries supported. */
+            uint8_t               u8MaxSEP;
+            /** Reserved. */
+            uint16_t              u16Reserved;
+            /** SEP entries... - not supported. */
+        } fields;
+    } u;
+} MptConfigurationPageIOC4, *PMptConfigurationPageIOC4;
+#pragma pack()
+
+/**
+ * IOC page 6. - Read/Write
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageIOC6 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[60];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            uint32_t                      u32CapabilitiesFlags;
+            uint8_t                       u8MaxDrivesIS;
+            uint8_t                       u8MaxDrivesIM;
+            uint8_t                       u8MaxDrivesIME;
+            uint8_t                       u8Reserved1;
+            uint8_t                       u8MinDrivesIS;
+            uint8_t                       u8MinDrivesIM;
+            uint8_t                       u8MinDrivesIME;
+            uint8_t                       u8Reserved2;
+            uint8_t                       u8MaxGlobalHotSpares;
+            uint8_t                       u8Reserved3;
+            uint16_t                      u16Reserved4;
+            uint32_t                      u32Reserved5;
+            uint32_t                      u32SupportedStripeSizeMapIS;
+            uint32_t                      u32SupportedStripeSizeMapIME;
+            uint32_t                      u32Reserved6;
+            uint8_t                       u8MetadataSize;
+            uint8_t                       u8Reserved7;
+            uint16_t                      u16Reserved8;
+            uint16_t                      u16MaxBadBlockTableEntries;
+            uint16_t                      u16Reserved9;
+            uint16_t                      u16IRNvsramUsage;
+            uint16_t                      u16Reserved10;
+            uint32_t                      u32IRNvsramVersion;
+            uint32_t                      u32Reserved11;
+        } fields;
+    } u;
+} MptConfigurationPageIOC6, *PMptConfigurationPageIOC6;
+#pragma pack()
+
+/**
+ * BIOS page 1 - Read/write.
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageBIOS1 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[48];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** BIOS options */
+            uint32_t                      u32BiosOptions;
+            /** IOC settings */
+            uint32_t                      u32IOCSettings;
+            /** Reserved */
+            uint32_t                      u32Reserved;
+            /** Device settings */
+            uint32_t                      u32DeviceSettings;
+            /** Number of devices */
+            uint16_t                      u16NumberOfDevices;
+            /** Expander spinup */
+            uint8_t                       u8ExpanderSpinup;
+            /** Reserved */
+            uint8_t                       u8Reserved;
+            /** I/O timeout of block devices without removable media */
+            uint16_t                      u16IOTimeoutBlockDevicesNonRM;
+            /** I/O timeout sequential */
+            uint16_t                      u16IOTimeoutSequential;
+            /** I/O timeout other */
+            uint16_t                      u16IOTimeoutOther;
+            /** I/O timeout of block devices with removable media */
+            uint16_t                      u16IOTimeoutBlockDevicesRM;
+        } fields;
+    } u;
+} MptConfigurationPageBIOS1, *PMptConfigurationPageBIOS1;
+#pragma pack()
+
+#define LSILOGICSCSI_BIOS1_BIOSOPTIONS_BIOS_DISABLE              (1<<0)
+#define LSILOGICSCSI_BIOS1_BIOSOPTIONS_SCAN_FROM_HIGH_TO_LOW     (1<<1)
+#define LSILOGICSCSI_BIOS1_BIOSOPTIONS_BIOS_EXTENDED_SAS_SUPPORT (1<<8)
+#define LSILOGICSCSI_BIOS1_BIOSOPTIONS_BIOS_EXTENDED_FC_SUPPORT  (1<<9)
+#define LSILOGICSCSI_BIOS1_BIOSOPTIONS_BIOS_EXTENDED_SPI_SUPPORT (1<<10)
+
+#define LSILOGICSCSI_BIOS1_IOCSETTINGS_ALTERNATE_CHS             (1<<3)
+
+#define LSILOGICSCSI_BIOS1_IOCSETTINGS_ADAPTER_SUPPORT_SET(x)    ((x) << 4)
+#define LSILOGICSCSI_BIOS1_IOCSETTINGS_ADAPTER_SUPPORT_DISABLED  0x00
+#define LSILOGICSCSI_BIOS1_IOCSETTINGS_ADAPTER_SUPPORT_BIOS_ONLY 0x01
+#define LSILOGICSCSI_BIOS1_IOCSETTINGS_ADAPTER_SUPPORT_OS_ONLY   0x02
+#define LSILOGICSCSI_BIOS1_IOCSETTINGS_ADAPTER_SUPPORT_BOT       0x03
+
+#define LSILOGICSCSI_BIOS1_IOCSETTINGS_REMOVABLE_MEDIA_SET(x)    ((x) << 6)
+#define LSILOGICSCSI_BIOS1_IOCSETTINGS_REMOVABLE_MEDIA_NO_INT13H 0x00
+#define LSILOGICSCSI_BIOS1_IOCSETTINGS_REMOVABLE_BOOT_MEDIA_INT13H 0x01
+#define LSILOGICSCSI_BIOS1_IOCSETTINGS_REMOVABLE_MEDIA_INT13H      0x02
+
+#define LSILOGICSCSI_BIOS1_IOCSETTINGS_SPINUP_DELAY_SET(x) \
+ ((x & 0xF) << 8)
+#define LSILOGICSCSI_BIOS1_IOCSETTINGS_SPINUP_DELAY_GET(x) \
+ ((x >> 8) & 0x0F)
+#define LSILOGICSCSI_BIOS1_IOCSETTINGS_MAX_TARGET_SPINUP_SET(x) \
+ ((x & 0xF) << 12)
+#define LSILOGICSCSI_BIOS1_IOCSETTINGS_MAX_TARGET_SPINUP_GET(x) \
+ ((x >> 12) & 0x0F)
+
+#define LSILOGICSCSI_BIOS1_IOCSETTINGS_BOOT_PREFERENCE_SET(x) \
+ (((x) & 0x3) << 16)
+#define LSILOGICSCSI_BIOS1_IOCSETTINGS_BOOT_PREFERENCE_ENCLOSURE   0x0
+#define LSILOGICSCSI_BIOS1_IOCSETTINGS_BOOT_PREFERENCE_SAS_ADDRESS 0x1
+
+#define LSILOGICSCSI_BIOS1_IOCSETTINGS_DIRECT_ATTACH_SPINUP_MODE_ALL (1<<18)
+#define LSILOGICSCSI_BIOS1_IOCSETTINGS_AUTO_PORT_ENABLE              (1<<19)
+
+#define LSILOGICSCSI_BIOS1_IOCSETTINGS_PORT_ENABLE_REPLY_DELAY_SET(x) \
+ (((x) & 0xF) << 20)
+#define LSILOGICSCSI_BIOS1_IOCSETTINGS_PORT_ENABLE_REPLY_DELAY_GET(x) \
+ ((x >> 20) & 0x0F)
+
+#define LSILOGICSCSI_BIOS1_IOCSETTINGS_PORT_ENABLE_SPINUP_DELAY_SET(x) \
+ (((x) & 0xF) << 24)
+#define LSILOGICSCSI_BIOS1_IOCSETTINGS_PORT_ENABLE_SPINUP_DELAY_GET(x) \
+ ((x >> 24) & 0x0F)
+
+#define LSILOGICSCSI_BIOS1_DEVSETTINGS_DISABLE_LUN_SCANS      (1<<0)
+#define LSILOGICSCSI_BIOS1_DEVSETTINGS_DISABLE_LUN_SCANS_NON_REMOVABLE_DEVS \
+ (1<<1)
+#define LSILOGICSCSI_BIOS1_DEVSETTINGS_DISABLE_LUN_SCANS_REMOVABLE_DEVS (1<<2)
+#define LSILOGICSCSI_BIOS1_DEVSETTINGS_DISABLE_LUN_SCANS2     (1<<3)
+#define LSILOGICSCSI_BIOS1_DEVSETTINGS_DISABLE_SMART_POLLING  (1<<4)
+
+#define LSILOGICSCSI_BIOS1_EXPANDERSPINUP_SPINUP_DELAY_SET(x) ((x) & 0x0F)
+#define LSILOGICSCSI_BIOS1_EXPANDERSPINUP_SPINUP_DELAY_GET(x) ((x) & 0x0F)
+#define LSILOGICSCSI_BIOS1_EXPANDERSPINUP_MAX_SPINUP_DELAY_SET(x) \
+ (((x) & 0x0F) << 4)
+#define LSILOGICSCSI_BIOS1_EXPANDERSPINUP_MAX_SPINUP_DELAY_GET(x) \
+ ((x >> 4) & 0x0F)
+
+/**
+ * BIOS page 2 - Read/write.
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageBIOS2 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[384];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Reserved */
+            uint32_t                      au32Reserved[6];
+            /** Format of the boot device field. */
+            uint8_t                       u8BootDeviceForm;
+            /** Previous format of the boot device field. */
+            uint8_t                       u8PrevBootDeviceForm;
+            /** Reserved */
+            uint16_t                      u16Reserved;
+            /** Boot device fields - dependent on the format */
+            union {
+                /** Device for AdapterNumber:Bus:Target:LUN */
+                struct {
+                    /** Target ID */
+                    uint8_t               u8TargetID;
+                    /** Bus */
+                    uint8_t               u8Bus;
+                    /** Adapter Number */
+                    uint8_t               u8AdapterNumber;
+                    /** Reserved */
+                    uint8_t               u8Reserved;
+                    /** Reserved */
+                    uint32_t              au32Reserved[3];
+                    /** LUN */
+                    uint32_t              aLUN[5];
+                    /** Reserved */
+                    uint32_t              au32Reserved2[56];
+                } AdapterNumberBusTargetLUN;
+                /** Device for PCIAddress:Bus:Target:LUN */
+                struct {
+                    /** Target ID */
+                    uint8_t               u8TargetID;
+                    /** Bus */
+                    uint8_t               u8Bus;
+                    /** Adapter Number */
+                    uint16_t              u16PCIAddress;
+                    /** Reserved */
+                    uint32_t              au32Reserved[3];
+                    /** LUN */
+                    uint32_t              aLUN[5];
+                    /** Reserved */
+                    uint32_t              au32Reserved2[56];
+                } PCIAddressBusTargetLUN;
+                /** Device for PCISlotNo:Bus:Target:LUN */
+                struct {
+                    /** Target ID */
+                    uint8_t               u8TargetID;
+                    /** Bus */
+                    uint8_t               u8Bus;
+                    /** PCI Slot Number */
+                    uint8_t              u16PCISlotNo;
+                    /** Reserved */
+                    uint32_t              au32Reserved[3];
+                    /** LUN */
+                    uint32_t              aLUN[5];
+                    /** Reserved */
+                    uint32_t              au32Reserved2[56];
+                } PCIAddressBusSlotLUN;
+                /** Device for FC channel world wide name */
+                struct {
+                    /** World wide port name low */
+                    uint32_t              u32WorldWidePortNameLow;
+                    /** World wide port name high */
+                    uint32_t              u32WorldWidePortNameHigh;
+                    /** Reserved */
+                    uint32_t              au32Reserved[3];
+                    /** LUN */
+                    uint32_t              aLUN[5];
+                    /** Reserved */
+                    uint32_t              au32Reserved2[56];
+                } FCWorldWideName;
+                /** Device for FC channel world wide name */
+                struct {
+                    /** SAS address */
+                    SASADDRESS            SASAddress;
+                    /** Reserved */
+                    uint32_t              au32Reserved[3];
+                    /** LUN */
+                    uint32_t              aLUN[5];
+                    /** Reserved */
+                    uint32_t              au32Reserved2[56];
+                } SASWorldWideName;
+                /** Device for Enclosure/Slot */
+                struct {
+                    /** Enclosure logical ID */
+                    uint64_t              u64EnclosureLogicalID;
+                    /** Reserved */
+                    uint32_t              au32Reserved[3];
+                    /** LUN */
+                    uint32_t              aLUN[5];
+                    /** Reserved */
+                    uint32_t              au32Reserved2[56];
+                } EnclosureSlot;
+            } BootDevice;
+        } fields;
+    } u;
+} MptConfigurationPageBIOS2, *PMptConfigurationPageBIOS2;
+#pragma pack()
+
+#define LSILOGICSCSI_BIOS2_BOOT_DEVICE_FORM_SET(x)                 ((x) & 0x0F)
+#define LSILOGICSCSI_BIOS2_BOOT_DEVICE_FORM_FIRST                  0x0
+#define LSILOGICSCSI_BIOS2_BOOT_DEVICE_FORM_ADAPTER_BUS_TARGET_LUN 0x1
+#define LSILOGICSCSI_BIOS2_BOOT_DEVICE_FORM_PCIADDR_BUS_TARGET_LUN 0x2
+#define LSILOGICSCSI_BIOS2_BOOT_DEVICE_FORM_PCISLOT_BUS_TARGET_LUN 0x3
+#define LSILOGICSCSI_BIOS2_BOOT_DEVICE_FORM_FC_WWN                 0x4
+#define LSILOGICSCSI_BIOS2_BOOT_DEVICE_FORM_SAS_WWN                0x5
+#define LSILOGICSCSI_BIOS2_BOOT_DEVICE_FORM_ENCLOSURE_SLOT         0x6
+
+/**
+ * BIOS page 4 - Read/Write (Where is 3? - not defined in the spec)
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageBIOS4 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[12];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Reassignment Base WWID */
+            uint64_t                      u64ReassignmentBaseWWID;
+        } fields;
+    } u;
+} MptConfigurationPageBIOS4, *PMptConfigurationPageBIOS4;
+#pragma pack()
+
+/**
+ * SCSI-SPI port page 0. - Readonly
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageSCSISPIPort0 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[12];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /* Flag whether this port is information unit transfers capable. */
+            unsigned              fInformationUnitTransfersCapable:1;
+            /* Flag whether the port is DT (Dual Transfer) capable. */
+            unsigned              fDTCapable:1;
+            /* Flag whether the port is QAS  capable. */
+            unsigned              fQASCapable:1;
+            /* Reserved. */
+            unsigned              u5Reserved1:5;
+            /* Minimum Synchronous transfer period. */
+            unsigned              u8MinimumSynchronousTransferPeriod:8;
+            /* Maximum synchronous offset. */
+            unsigned              u8MaximumSynchronousOffset:8;
+            /** Reserved. */
+            unsigned              u5Reserved2:5;
+            /* Flag whether indicating the width of the bus -
+                0 narrow and 1 for wide. */
+            unsigned              fWide:1;
+            /* Reserved */
+            unsigned              fReserved:1;
+            /* Flag whether the port is AIP capable. */
+            unsigned              fAIPCapable:1;
+            /* Signaling Type. */
+            unsigned              u2SignalingType:2;
+            /* Reserved. */
+            unsigned              u30Reserved:30;
+        } fields;
+    } u;
+} MptConfigurationPageSCSISPIPort0, *PMptConfigurationPageSCSISPIPort0;
+#pragma pack()
+
+/**
+ * SCSI-SPI port page 1. - Read/Write
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageSCSISPIPort1 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[12];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** The SCSI ID of the port. */
+            uint8_t               u8SCSIID;
+            /** Reserved. */
+            uint8_t               u8Reserved;
+            /** Port response IDs Bit mask field. */
+            uint16_t              u16PortResponseIDsBitmask;
+            /** Value for the on BUS timer. */
+            uint32_t              u32OnBusTimerValue;
+        } fields;
+    } u;
+} MptConfigurationPageSCSISPIPort1, *PMptConfigurationPageSCSISPIPort1;
+#pragma pack()
+
+/**
+ * Device settings for one device.
+ */
+#pragma pack(1)
+typedef struct MptDeviceSettings {
+    /** Timeout for I/O in seconds. */
+    unsigned    u8Timeout:8;
+    /** Minimum synchronous factor. */
+    unsigned    u8SyncFactor:8;
+    /** Flag whether disconnect is enabled. */
+    unsigned    fDisconnectEnable:1;
+    /** Flag whether Scan ID is enabled. */
+    unsigned    fScanIDEnable:1;
+    /** Flag whether Scan LUNs is enabled. */
+    unsigned    fScanLUNEnable:1;
+    /** Flag whether tagged queuing is enabled. */
+    unsigned    fTaggedQueuingEnabled:1;
+    /** Flag whether wide is enabled. */
+    unsigned    fWideDisable:1;
+    /** Flag whether this device is bootable. */
+    unsigned    fBootChoice:1;
+    /** Reserved. */
+    unsigned    u10Reserved:10;
+} MptDeviceSettings, *PMptDeviceSettings;
+#pragma pack()
+
+/**
+ * SCSI-SPI port page 2. - Read/Write for the BIOS
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageSCSISPIPort2 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[76];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Flag indicating the bus scan order. */
+            unsigned              fBusScanOrderHighToLow:1;
+            /** Reserved. */
+            unsigned              fReserved:1;
+            /** Flag whether SCSI Bus resets are avoided. */
+            unsigned              fAvoidSCSIBusResets:1;
+            /** Flag whether alternate CHS is used. */
+            unsigned              fAlternateCHS:1;
+            /** Flag whether termination is disabled. */
+            unsigned              fTerminationDisabled:1;
+            /** Reserved. */
+            unsigned              u27Reserved:27;
+            /** Host SCSI ID. */
+            unsigned              u4HostSCSIID:4;
+            /** Initialize HBA. */
+            unsigned              u2InitializeHBA:2;
+            /** Removeable media setting. */
+            unsigned              u2RemovableMediaSetting:2;
+            /** Spinup delay. */
+            unsigned              u4SpinupDelay:4;
+            /** Negotiating settings. */
+            unsigned              u2NegotitatingSettings:2;
+            /** Reserved. */
+            unsigned              u18Reserved:18;
+            /** Device Settings. */
+            MptDeviceSettings     aDeviceSettings[16];
+        } fields;
+    } u;
+} MptConfigurationPageSCSISPIPort2, *PMptConfigurationPageSCSISPIPort2;
+#pragma pack()
+
+/**
+ * SCSI-SPI device page 0. - Readonly
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageSCSISPIDevice0 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[12];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Negotiated Parameters. */
+            /** Information Units enabled. */
+            unsigned              fInformationUnitsEnabled:1;
+            /** Dual Transfers Enabled. */
+            unsigned              fDTEnabled:1;
+            /** QAS enabled. */
+            unsigned              fQASEnabled:1;
+            /** Reserved. */
+            unsigned              u5Reserved1:5;
+            /** Synchronous Transfer period. */
+            unsigned              u8NegotiatedSynchronousTransferPeriod:8;
+            /** Synchronous offset. */
+            unsigned              u8NegotiatedSynchronousOffset:8;
+            /** Reserved. */
+            unsigned              u5Reserved2:5;
+            /** Width - 0 for narrow and 1 for wide. */
+            unsigned              fWide:1;
+            /** Reserved. */
+            unsigned              fReserved:1;
+            /** AIP enabled. */
+            unsigned              fAIPEnabled:1;
+            /** Flag whether negotiation occurred. */
+            unsigned              fNegotationOccured:1;
+            /** Flag whether a SDTR message was rejected. */
+            unsigned              fSDTRRejected:1;
+            /** Flag whether a WDTR message was rejected. */
+            unsigned              fWDTRRejected:1;
+            /** Flag whether a PPR message was rejected. */
+            unsigned              fPPRRejected:1;
+            /** Reserved. */
+            unsigned              u28Reserved:28;
+        } fields;
+    } u;
+} MptConfigurationPageSCSISPIDevice0, *PMptConfigurationPageSCSISPIDevice0;
+#pragma pack()
+
+/**
+ * SCSI-SPI device page 1. - Read/Write
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageSCSISPIDevice1 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[16];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Requested Parameters. */
+            /** Information Units enable. */
+            bool                  fInformationUnitsEnable:1;
+            /** Dual Transfers Enable. */
+            bool                  fDTEnable:1;
+            /** QAS enable. */
+            bool                  fQASEnable:1;
+            /** Reserved. */
+            unsigned              u5Reserved1:5;
+            /** Synchronous Transfer period. */
+            unsigned              u8NegotiatedSynchronousTransferPeriod:8;
+            /** Synchronous offset. */
+            unsigned              u8NegotiatedSynchronousOffset:8;
+            /** Reserved. */
+            unsigned              u5Reserved2:5;
+            /** Width - 0 for narrow and 1 for wide. */
+            bool                  fWide:1;
+            /** Reserved. */
+            bool                  fReserved1:1;
+            /** AIP enable. */
+            bool                  fAIPEnable:1;
+            /** Reserved. */
+            bool                  fReserved2:1;
+            /** WDTR disallowed. */
+            bool                  fWDTRDisallowed:1;
+            /** SDTR disallowed. */
+            bool                  fSDTRDisallowed:1;
+            /** Reserved. */
+            unsigned              u29Reserved:29;
+        } fields;
+    } u;
+} MptConfigurationPageSCSISPIDevice1, *PMptConfigurationPageSCSISPIDevice1;
+#pragma pack()
+
+/**
+ * SCSI-SPI device page 2. - Read/Write
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageSCSISPIDevice2 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[16];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Reserved. */
+            unsigned              u4Reserved:4;
+            /** ISI enable. */
+            unsigned              fISIEnable:1;
+            /** Secondary driver enable. */
+            unsigned              fSecondaryDriverEnable:1;
+            /** Reserved. */
+            unsigned              fReserved:1;
+            /** Slew create controller. */
+            unsigned              u3SlewRateControler:3;
+            /** Primary drive strength controller. */
+            unsigned              u3PrimaryDriveStrengthControl:3;
+            /** Secondary drive strength controller. */
+            unsigned              u3SecondaryDriveStrengthControl:3;
+            /** Reserved. */
+            unsigned              u12Reserved:12;
+            /** XCLKH_ST. */
+            unsigned              fXCLKH_ST:1;
+            /** XCLKS_ST. */
+            unsigned              fXCLKS_ST:1;
+            /** XCLKH_DT. */
+            unsigned              fXCLKH_DT:1;
+            /** XCLKS_DT. */
+            unsigned              fXCLKS_DT:1;
+            /** Parity pipe select. */
+            unsigned              u2ParityPipeSelect:2;
+            /** Reserved. */
+            unsigned              u30Reserved:30;
+            /** Data bit pipeline select. */
+            unsigned              u32DataPipelineSelect:32;
+        } fields;
+    } u;
+} MptConfigurationPageSCSISPIDevice2, *PMptConfigurationPageSCSISPIDevice2;
+#pragma pack()
+
+/**
+ * SCSI-SPI device page 3 (Revision G). - Readonly
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageSCSISPIDevice3 {
+    /** Union. */
+    union {
+        /** Byte view. */
+        uint8_t                   abPageData[1];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptConfigurationPageHeader    Header;
+            /** Number of times the IOC rejected a message because
+                it doesn't support the operation. */
+            uint16_t                      u16MsgRejectCount;
+            /** Number of times the SCSI bus entered an invalid
+                operation state. */
+            uint16_t                      u16PhaseErrorCount;
+            /** Number of parity errors. */
+            uint16_t                      u16ParityCount;
+            /** Reserved. */
+            uint16_t                      u16Reserved;
+        } fields;
+    } u;
+} MptConfigurationPageSCSISPIDevice3, *PMptConfigurationPageSCSISPIDevice3;
+#pragma pack()
+
+/**
+ * PHY entry for the SAS I/O unit page 0
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageSASIOUnit0PHY {
+    /** Port number */
+    uint8_t                           u8Port;
+    /** Port flags */
+    uint8_t                           u8PortFlags;
+    /** Phy flags */
+    uint8_t                           u8PhyFlags;
+    /** negotiated link rate */
+    uint8_t                           u8NegotiatedLinkRate;
+    /** Controller phy device info */
+    uint32_t                          u32ControllerPhyDeviceInfo;
+    /** Attached device handle */
+    uint16_t                          u16AttachedDevHandle;
+    /** Controller device handle */
+    uint16_t                          u16ControllerDevHandle;
+    /** Discovery status */
+    uint32_t                          u32DiscoveryStatus;
+} MptConfigurationPageSASIOUnit0PHY, *PMptConfigurationPageSASIOUnit0PHY;
+#pragma pack()
+
+/**
+ * SAS I/O  Unit page 0 - Readonly
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageSASIOUnit0 {
+    /** Union. */
+    union {
+        /** Byte view - variable. */
+        uint8_t                                   abPageData[1];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptExtendedConfigurationPageHeader    ExtHeader;
+            /** Nvdata version default */
+            uint16_t                              u16NvdataVersionDefault;
+            /** Nvdata version persistent */
+            uint16_t                              u16NvdataVersionPersistent;
+            /** Number of physical ports */
+            uint8_t                               u8NumPhys;
+            /** Reserved */
+            uint8_t                               au8Reserved[3];
+            /** Content for each physical port -
+                variable depending on the amount of ports. */
+            MptConfigurationPageSASIOUnit0PHY     aPHY[1];
+        } fields;
+    } u;
+} MptConfigurationPageSASIOUnit0, *PMptConfigurationPageSASIOUnit0;
+#pragma pack()
+
+#define LSILOGICSCSI_SASIOUNIT0_GET_SIZE(ports) \
+ (sizeof(MptConfigurationPageSASIOUnit0) + ((ports) - 1) * \
+  sizeof(MptConfigurationPageSASIOUnit0PHY))
+
+#define LSILOGICSCSI_SASIOUNIT0_PORT_CONFIGURATION_AUTO  (1<<0)
+#define LSILOGICSCSI_SASIOUNIT0_PORT_TARGET_IOC          (1<<2)
+#define LSILOGICSCSI_SASIOUNIT0_PORT_DISCOVERY_IN_STATUS (1<<3)
+
+#define LSILOGICSCSI_SASIOUNIT0_PHY_RX_INVERTED          (1<<0)
+#define LSILOGICSCSI_SASIOUNIT0_PHY_TX_INVERTED          (1<<1)
+#define LSILOGICSCSI_SASIOUNIT0_PHY_DISABLED             (1<<2)
+
+#define LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_SET(x)   ((x) & 0x0F)
+#define LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_GET(x)   ((x) & 0x0F)
+#define LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_UNKNOWN  0x00
+#define LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_DISABLED 0x01
+#define LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_FAILED   0x02
+#define LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_SATA_OOB 0x03
+#define LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_15GB     0x08
+#define LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_30GB     0x09
+
+#define LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(x)          ((x) & 0x3)
+#define LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_NO              0x0
+#define LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_END             0x1
+#define LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_EDGE_EXPANDER   0x2
+#define LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_FANOUT_EXPANDER 0x3
+
+#define LSILOGICSCSI_SASIOUNIT0_DEVICE_SATA_HOST            (1<<3)
+#define LSILOGICSCSI_SASIOUNIT0_DEVICE_SMP_INITIATOR        (1<<4)
+#define LSILOGICSCSI_SASIOUNIT0_DEVICE_STP_INITIATOR        (1<<5)
+#define LSILOGICSCSI_SASIOUNIT0_DEVICE_SSP_INITIATOR        (1<<6)
+#define LSILOGICSCSI_SASIOUNIT0_DEVICE_SATA                 (1<<7)
+#define LSILOGICSCSI_SASIOUNIT0_DEVICE_SMP_TARGET           (1<<8)
+#define LSILOGICSCSI_SASIOUNIT0_DEVICE_STP_TARGET           (1<<9)
+#define LSILOGICSCSI_SASIOUNIT0_DEVICE_SSP_TARGET           (1<<10)
+#define LSILOGICSCSI_SASIOUNIT0_DEVICE_DIRECT_ATTACHED      (1<<11)
+#define LSILOGICSCSI_SASIOUNIT0_DEVICE_LSI                  (1<<12)
+#define LSILOGICSCSI_SASIOUNIT0_DEVICE_ATAPI_DEVICE         (1<<13)
+#define LSILOGICSCSI_SASIOUNIT0_DEVICE_SEP_DEVICE           (1<<14)
+
+#define LSILOGICSCSI_SASIOUNIT0_DISCOVERY_STATUS_LOOP            (1<<0)
+#define LSILOGICSCSI_SASIOUNIT0_DISCOVERY_STATUS_UNADDRESSABLE   (1<<1)
+#define LSILOGICSCSI_SASIOUNIT0_DISCOVERY_STATUS_SAME_SAS_ADDR   (1<<2)
+#define LSILOGICSCSI_SASIOUNIT0_DISCOVERY_STATUS_EXPANDER_ERROR  (1<<3)
+#define LSILOGICSCSI_SASIOUNIT0_DISCOVERY_STATUS_SMP_TIMEOUT     (1<<4)
+#define LSILOGICSCSI_SASIOUNIT0_DISCOVERY_STATUS_EXP_ROUTE_OOE   (1<<5)
+#define LSILOGICSCSI_SASIOUNIT0_DISCOVERY_STATUS_EXP_ROUTE_IDX   (1<<6)
+#define LSILOGICSCSI_SASIOUNIT0_DISCOVERY_STATUS_SMP_FUNC_FAILED (1<<7)
+#define LSILOGICSCSI_SASIOUNIT0_DISCOVERY_STATUS_SMP_CRC_ERROR   (1<<8)
+#define LSILOGICSCSI_SASIOUNIT0_DISCOVERY_STATUS_SUBTRSCTIVE_LNK (1<<9)
+#define LSILOGICSCSI_SASIOUNIT0_DISCOVERY_STATUS_TBL_LNK         (1<<10)
+#define LSILOGICSCSI_SASIOUNIT0_DISCOVERY_STATUS_UNSUPPORTED_DEV (1<<11)
+#define LSILOGICSCSI_SASIOUNIT0_DISCOVERY_STATUS_MAX_SATA_TGTS   (1<<12)
+#define LSILOGICSCSI_SASIOUNIT0_DISCOVERY_STATUS_MULT_CTRLS      (1<<13)
+
+/**
+ * PHY entry for the SAS I/O unit page 1
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageSASIOUnit1PHY {
+    /** Port number */
+    uint8_t                           u8Port;
+    /** Port flags */
+    uint8_t                           u8PortFlags;
+    /** Phy flags */
+    uint8_t                           u8PhyFlags;
+    /** Max link rate */
+    uint8_t                           u8MaxMinLinkRate;
+    /** Controller phy device info */
+    uint32_t                          u32ControllerPhyDeviceInfo;
+    /** Maximum target port connect time */
+    uint16_t                          u16MaxTargetPortConnectTime;
+    /** Reserved */
+    uint16_t                          u16Reserved;
+} MptConfigurationPageSASIOUnit1PHY, *PMptConfigurationPageSASIOUnit1PHY;
+#pragma pack()
+
+/**
+ * SAS I/O  Unit page 1 - Read/Write
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageSASIOUnit1 {
+    /** Union. */
+    union {
+        /** Byte view - variable. */
+        uint8_t                                   abPageData[1];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptExtendedConfigurationPageHeader    ExtHeader;
+            /** Control flags */
+            uint16_t                              u16ControlFlags;
+            /** maximum number of SATA targets */
+            uint16_t                              u16MaxNumSATATargets;
+            /** additional control flags */
+            uint16_t                              u16AdditionalControlFlags;
+            /** Reserved */
+            uint16_t                              u16Reserved;
+            /** Number of PHYs */
+            uint8_t                               u8NumPhys;
+            /** maximum SATA queue depth */
+            uint8_t                               u8SATAMaxQDepth;
+            /** Delay for reporting missing devices. */
+            uint8_t                               u8ReportDeviceMissingDelay;
+            /** I/O device missing delay */
+            uint8_t                               u8IODeviceMissingDelay;
+            /** Content for each physical port -
+                variable depending on the number of ports */
+            MptConfigurationPageSASIOUnit1PHY     aPHY[1];
+        } fields;
+    } u;
+} MptConfigurationPageSASIOUnit1, *PMptConfigurationPageSASIOUnit1;
+#pragma pack()
+
+#define LSILOGICSCSI_SASIOUNIT1_GET_SIZE(ports) \
+ (sizeof(MptConfigurationPageSASIOUnit1) + ((ports) - 1) * \
+  sizeof(MptConfigurationPageSASIOUnit1PHY))
+
+#define LSILOGICSCSI_SASIOUNIT1_CONTROL_CLEAR_SATA_AFFILIATION     (1<<0)
+#define LSILOGICSCSI_SASIOUNIT1_CONTROL_FIRST_LEVEL_DISCOVERY_ONLY (1<<1)
+#define LSILOGICSCSI_SASIOUNIT1_CONTROL_SUBTRACTIVE_LNK_ILLEGAL    (1<<2)
+#define LSILOGICSCSI_SASIOUNIT1_CONTROL_IOC_ENABLE_HIGH_PHY        (1<<3)
+#define LSILOGICSCSI_SASIOUNIT1_CONTROL_SATA_FUA_REQUIRED          (1<<4)
+#define LSILOGICSCSI_SASIOUNIT1_CONTROL_SATA_NCQ_REQUIRED          (1<<5)
+#define LSILOGICSCSI_SASIOUNIT1_CONTROL_SATA_SMART_REQUIRED        (1<<6)
+#define LSILOGICSCSI_SASIOUNIT1_CONTROL_SATA_LBA48_REQUIRED        (1<<7)
+#define LSILOGICSCSI_SASIOUNIT1_CONTROL_SATA_INIT_POSTPONED        (1<<8)
+
+#define LSILOGICSCSI_SASIOUNIT1_CONTROL_DEVICE_SUPPORT_SET(x) \
+ (((x) & 0x3) << 9)
+#define LSILOGICSCSI_SASIOUNIT1_CONTROL_DEVICE_SUPPORT_GET(x) \
+ (((x) >> 9) & 0x3)
+#define LSILOGICSCSI_SASIOUNIT1_CONTROL_DEVICE_SUPPORT_SAS_AND_SATA 0x00
+#define LSILOGICSCSI_SASIOUNIT1_CONTROL_DEVICE_SUPPORT_SAS          0x01
+#define LSILOGICSCSI_SASIOUNIT1_CONTROL_DEVICE_SUPPORT_SATA         0x02
+
+#define LSILOGICSCSI_SASIOUNIT1_CONTROL_SATA_EXP_ADDR                  (1<<11)
+#define LSILOGICSCSI_SASIOUNIT1_CONTROL_SATA_SETTINGS_PRESERV_REQUIRED (1<<12)
+#define LSILOGICSCSI_SASIOUNIT1_CONTROL_SATA_LIMIT_RATE_15GB           (1<<13)
+#define LSILOGICSCSI_SASIOUNIT1_CONTROL_SATA_LIMIT_RATE_30GB           (1<<14)
+#define LSILOGICSCSI_SASIOUNIT1_CONTROL_SAS_SELF_TEST_ENABLED          (1<<15)
+
+#define LSILOGICSCSI_SASIOUNIT1_ADDITIONAL_CONTROL_TBL_LNKS_ALLOW        (1<<0)
+#define LSILOGICSCSI_SASIOUNIT1_ADDITIONAL_CONTROL_SATA_RST_NO_AFFIL     (1<<1)
+#define LSILOGICSCSI_SASIOUNIT1_ADDITIONAL_CONTROL_SATA_RST_SELF_AFFIL   (1<<2)
+#define LSILOGICSCSI_SASIOUNIT1_ADDITIONAL_CONTROL_SATA_RST_OTHER_AFFIL  (1<<3)
+#define LSILOGICSCSI_SASIOUNIT1_ADDITIONAL_CONTROL_SATA_RST_PORT_EN_ONLY (1<<4)
+#define LSILOGICSCSI_SASIOUNIT1_ADDITIONAL_CONTROL_HIDE_NON_ZERO_PHYS    (1<<5)
+#define LSILOGICSCSI_SASIOUNIT1_ADDITIONAL_CONTROL_SATA_ASYNC_NOTIF      (1<<6)
+#define LSILOGICSCSI_SASIOUNIT1_ADDITIONAL_CONTROL_MULT_PORTS_ILL_SAME_DOMAIN \
+ (1<<7)
+
+#define LSILOGICSCSI_SASIOUNIT1_MISSING_DEVICE_DELAY_UNITS_16_SEC     (1<<7)
+#define LSILOGICSCSI_SASIOUNIT1_MISSING_DEVICE_DELAY_SET(x)   ((x) & 0x7F)
+#define LSILOGICSCSI_SASIOUNIT1_MISSING_DEVICE_DELAY_GET(x)   ((x) & 0x7F)
+
+#define LSILOGICSCSI_SASIOUNIT1_PORT_CONFIGURATION_AUTO       (1<<0)
+#define LSILOGICSCSI_SASIOUNIT1_PORT_CONFIGURATION_IOC1       (1<<2)
+
+#define LSILOGICSCSI_SASIOUNIT1_PHY_RX_INVERT                 (1<<0)
+#define LSILOGICSCSI_SASIOUNIT1_PHY_TX_INVERT                 (1<<1)
+#define LSILOGICSCSI_SASIOUNIT1_PHY_DISABLE                   (1<<2)
+
+#define LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MIN_SET(x)          ((x) & 0xF)
+#define LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MIN_GET(x)          ((x) & 0xF)
+#define LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MAX_SET(x)          (((x) & 0xF)<<4)
+#define LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MAX_GET(x)          ((x >> 4) & 0xF)
+#define LSILOGICSCSI_SASIOUNIT1_LINK_RATE_15GB                0x8
+#define LSILOGICSCSI_SASIOUNIT1_LINK_RATE_30GB                0x9
+
+#define LSILOGICSCSI_SASIOUNIT1_CTL_PHY_DEVICE_TYPE_SET(x)    ((x) & 0x3)
+#define LSILOGICSCSI_SASIOUNIT1_CTL_PHY_DEVICE_TYPE_GET(x)    ((x) & 0x3)
+#define LSILOGICSCSI_SASIOUNIT1_CTL_PHY_DEVICE_TYPE_NO                0x0
+#define LSILOGICSCSI_SASIOUNIT1_CTL_PHY_DEVICE_TYPE_END               0x1
+#define LSILOGICSCSI_SASIOUNIT1_CTL_PHY_DEVICE_TYPE_EDGE_EXPANDER     0x2
+#define LSILOGICSCSI_SASIOUNIT1_CTL_PHY_DEVICE_TYPE_FANOUT_EXPANDER   0x3
+#define LSILOGICSCSI_SASIOUNIT1_CTL_PHY_DEVICE_SMP_INITIATOR  (1<<4)
+#define LSILOGICSCSI_SASIOUNIT1_CTL_PHY_DEVICE_STP_INITIATOR  (1<<5)
+#define LSILOGICSCSI_SASIOUNIT1_CTL_PHY_DEVICE_SSP_INITIATOR  (1<<6)
+#define LSILOGICSCSI_SASIOUNIT1_CTL_PHY_DEVICE_SMP_TARGET     (1<<8)
+#define LSILOGICSCSI_SASIOUNIT1_CTL_PHY_DEVICE_STP_TARGET     (1<<9)
+#define LSILOGICSCSI_SASIOUNIT1_CTL_PHY_DEVICE_SSP_TARGET     (1<<10)
+#define LSILOGICSCSI_SASIOUNIT1_CTL_PHY_DEVICE_DIRECT_ATTACHED    (1<<11)
+#define LSILOGICSCSI_SASIOUNIT1_CTL_PHY_DEVICE_LSI            (1<<12)
+#define LSILOGICSCSI_SASIOUNIT1_CTL_PHY_DEVICE_ATAPI          (1<<13)
+#define LSILOGICSCSI_SASIOUNIT1_CTL_PHY_DEVICE_SEP            (1<<14)
+
+/**
+ * SAS I/O unit page 2 - Read/Write
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageSASIOUnit2 {
+    /** Union. */
+    union {
+        /** Byte view - variable. */
+        uint8_t                                   abPageData[1];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptExtendedConfigurationPageHeader    ExtHeader;
+            /** Device numbers per enclosure */
+            uint8_t                               u8NumDevsPerEnclosure;
+            /** Boot device wait time */
+            uint8_t                               u8BootDeviceWaitTime;
+            /** Reserved */
+            uint16_t                              u16Reserved;
+            /** Maximum number of persistent Bus and target ID mappings */
+            uint16_t                              u16MaxPersistentIDs;
+            /** Number of persistent IDs used */
+            uint16_t                              u16NumPersistentIDsUsed;
+            /** Status */
+            uint8_t                               u8Status;
+            /** Flags */
+            uint8_t                               u8Flags;
+            /** Maximum number of physical mapped IDs */
+            uint16_t                              u16MaxNumPhysicalMappedIDs;
+        } fields;
+    } u;
+} MptConfigurationPageSASIOUnit2, *PMptConfigurationPageSASIOUnit2;
+#pragma pack()
+
+#define LSILOGICSCSI_SASIOUNIT2_STATUS_PERSISTENT_MAP_TBL_FULL       (1<<0)
+#define LSILOGICSCSI_SASIOUNIT2_STATUS_PERSISTENT_MAP_DISABLED       (1<<1)
+#define LSILOGICSCSI_SASIOUNIT2_STATUS_PERSISTENT_ENC_DEV_UNMAPPED   (1<<2)
+#define LSILOGICSCSI_SASIOUNIT2_STATUS_PERSISTENT_DEV_LIMIT_EXCEEDED (1<<3)
+
+#define LSILOGICSCSI_SASIOUNIT2_FLAGS_PERSISTENT_MAP_DISABLE          (1<<0)
+#define LSILOGICSCSI_SASIOUNIT2_FLAGS_PERSISTENT_PHYS_MAP_MODE_SET(x) \
+ ((x & 0x7) << 1)
+#define LSILOGICSCSI_SASIOUNIT2_FLAGS_PERSISTENT_PHYS_MAP_MODE_GET(x) \
+ ((x >> 1) & 0x7)
+#define LSILOGICSCSI_SASIOUNIT2_FLAGS_PERSISTENT_PHYS_MAP_MODE_NO     0x0
+#define LSILOGICSCSI_SASIOUNIT2_FLAGS_PERSISTENT_PHYS_MAP_MODE_DIRECT_ATTACHED\
+ 0x1
+#define LSILOGICSCSI_SASIOUNIT2_FLAGS_PERSISTENT_PHYS_MAP_MODE_ENC    0x2
+#define LSILOGICSCSI_SASIOUNIT2_FLAGS_PERSISTENT_PHYS_MAP_MODE_HOST   0x7
+#define LSILOGICSCSI_SASIOUNIT2_FLAGS_RESERVE_TARGET_ID_ZERO          (1<<4)
+#define LSILOGICSCSI_SASIOUNIT2_FLAGS_START_SLOT_NUMBER_ONE           (1<<5)
+
+/**
+ * SAS I/O unit page 3 - Read/Write
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageSASIOUnit3 {
+    /** Union. */
+    union {
+        /** Byte view - variable. */
+        uint8_t                                   abPageData[1];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptExtendedConfigurationPageHeader    ExtHeader;
+            /** Reserved */
+            uint32_t                          u32Reserved;
+            uint32_t                          u32MaxInvalidDwordCount;
+            uint32_t                          u32InvalidDwordCountTime;
+            uint32_t                          u32MaxRunningDisparityErrorCount;
+            uint32_t                          u32RunningDisparityErrorTime;
+            uint32_t                          u32MaxLossDwordSynchCount;
+            uint32_t                          u32LossDwordSynchCountTime;
+            uint32_t                          u32MaxPhysResetProblemCount;
+            uint32_t                          u32PhyResetProblemTime;
+        } fields;
+    } u;
+} MptConfigurationPageSASIOUnit3, *PMptConfigurationPageSASIOUnit3;
+#pragma pack()
+
+/**
+ * SAS PHY page 0 - Readonly
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageSASPHY0 {
+    /** Union. */
+    union {
+        /** Byte view - variable. */
+        uint8_t                                   abPageData[1];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptExtendedConfigurationPageHeader    ExtHeader;
+            /** Owner dev handle. */
+            uint16_t                              u16OwnerDevHandle;
+            /** Reserved */
+            uint16_t                              u16Reserved0;
+            /** SAS address */
+            SASADDRESS                            SASAddress;
+            /** Attached device handle */
+            uint16_t                              u16AttachedDevHandle;
+            /** Attached phy identifier */
+            uint8_t                               u8AttachedPhyIdentifier;
+            /** Reserved */
+            uint8_t                               u8Reserved1;
+            /** Attached device information */
+            uint32_t                              u32AttachedDeviceInfo;
+            /** Programmed link rate */
+            uint8_t                               u8ProgrammedLinkRate;
+            /** Hardware link rate */
+            uint8_t                               u8HwLinkRate;
+            /** Change count */
+            uint8_t                               u8ChangeCount;
+            /** Flags */
+            uint8_t                               u8Flags;
+            /** Phy information */
+            uint32_t                              u32PhyInfo;
+        } fields;
+    } u;
+} MptConfigurationPageSASPHY0, *PMptConfigurationPageSASPHY0;
+#pragma pack()
+
+#define LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_SET(x)          ((x) & 0x3)
+#define LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_GET(x)          ((x) & 0x3)
+#define LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_NO              0x0
+#define LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_END             0x1
+#define LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_EDGE_EXPANDER   0x2
+#define LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_FANOUT_EXPANDER 0x3
+#define LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_SMP_INITIATOR        (1<<4)
+#define LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_STP_INITIATOR        (1<<5)
+#define LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_SSP_INITIATOR        (1<<6)
+#define LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_SMP_TARGET           (1<<8)
+#define LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_STP_TARGET           (1<<9)
+#define LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_SSP_TARGET           (1<<10)
+#define LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_DIRECT_ATTACHED      (1<<11)
+#define LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_LSI                  (1<<12)
+#define LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_ATAPI                (1<<13)
+#define LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_SEP                  (1<<14)
+
+/**
+ * SAS PHY page 1 - Readonly
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageSASPHY1 {
+    /** Union. */
+    union {
+        /** Byte view - variable. */
+        uint8_t                                   abPageData[1];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptExtendedConfigurationPageHeader    ExtHeader;
+            /** Reserved */
+            uint32_t                              u32Reserved0;
+            uint32_t                              u32InvalidDwordCound;
+            uint32_t                              
u32RunningDisparityErrorCount;
+            uint32_t                              u32LossDwordSynchCount;
+            uint32_t                              u32PhyResetProblemCount;
+        } fields;
+    } u;
+} MptConfigurationPageSASPHY1, *PMptConfigurationPageSASPHY1;
+#pragma pack()
+
+/**
+ * SAS Device page 0 - Readonly
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageSASDevice0 {
+    /** Union. */
+    union {
+        /** Byte view - variable. */
+        uint8_t                                   abPageData[1];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptExtendedConfigurationPageHeader    ExtHeader;
+            /** Slot number */
+            uint16_t                              u16Slot;
+            /** Enclosure handle. */
+            uint16_t                              u16EnclosureHandle;
+            /** SAS address */
+            SASADDRESS                            SASAddress;
+            /** Parent device handle */
+            uint16_t                              u16ParentDevHandle;
+            /** Phy number */
+            uint8_t                               u8PhyNum;
+            /** Access status */
+            uint8_t                               u8AccessStatus;
+            /** Device handle */
+            uint16_t                              u16DevHandle;
+            /** Target ID */
+            uint8_t                               u8TargetID;
+            /** Bus */
+            uint8_t                               u8Bus;
+            /** Device info */
+            uint32_t                              u32DeviceInfo;
+            /** Flags */
+            uint16_t                              u16Flags;
+            /** Physical port */
+            uint8_t                               u8PhysicalPort;
+            /** Reserved */
+            uint8_t                               u8Reserved0;
+        } fields;
+    } u;
+} MptConfigurationPageSASDevice0, *PMptConfigurationPageSASDevice0;
+#pragma pack()
+
+#define LSILOGICSCSI_SASDEVICE0_STATUS_NO_ERRORS                 (0x00)
+
+#define LSILOGICSCSI_SASDEVICE0_DEV_INFO_DEVICE_TYPE_SET(x)      ((x) & 0x3)
+#define LSILOGICSCSI_SASDEVICE0_DEV_INFO_DEVICE_TYPE_GET(x)      ((x) & 0x3)
+#define LSILOGICSCSI_SASDEVICE0_DEV_INFO_DEVICE_TYPE_NO              0x0
+#define LSILOGICSCSI_SASDEVICE0_DEV_INFO_DEVICE_TYPE_END             0x1
+#define LSILOGICSCSI_SASDEVICE0_DEV_INFO_DEVICE_TYPE_EDGE_EXPANDER   0x2
+#define LSILOGICSCSI_SASDEVICE0_DEV_INFO_DEVICE_TYPE_FANOUT_EXPANDER 0x3
+#define LSILOGICSCSI_SASDEVICE0_DEV_INFO_DEVICE_SMP_INITIATOR        (1<<4)
+#define LSILOGICSCSI_SASDEVICE0_DEV_INFO_DEVICE_STP_INITIATOR        (1<<5)
+#define LSILOGICSCSI_SASDEVICE0_DEV_INFO_DEVICE_SSP_INITIATOR        (1<<6)
+#define LSILOGICSCSI_SASDEVICE0_DEV_INFO_DEVICE_SMP_TARGET           (1<<8)
+#define LSILOGICSCSI_SASDEVICE0_DEV_INFO_DEVICE_STP_TARGET           (1<<9)
+#define LSILOGICSCSI_SASDEVICE0_DEV_INFO_DEVICE_SSP_TARGET           (1<<10)
+#define LSILOGICSCSI_SASDEVICE0_DEV_INFO_DEVICE_DIRECT_ATTACHED      (1<<11)
+#define LSILOGICSCSI_SASDEVICE0_DEV_INFO_DEVICE_LSI                  (1<<12)
+#define LSILOGICSCSI_SASDEVICE0_DEV_INFO_DEVICE_ATAPI                (1<<13)
+#define LSILOGICSCSI_SASDEVICE0_DEV_INFO_DEVICE_SEP                  (1<<14)
+
+#define LSILOGICSCSI_SASDEVICE0_FLAGS_DEVICE_PRESENT                 (1<<0)
+#define LSILOGICSCSI_SASDEVICE0_FLAGS_DEVICE_MAPPED_TO_BUS_AND_TARGET_ID \
+ (1<<(1))
+#define LSILOGICSCSI_SASDEVICE0_FLAGS_DEVICE_MAPPING_PERSISTENT \
+ (1<<(2))
+
+/**
+ * SAS Device page 1 - Readonly
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageSASDevice1 {
+    /** Union. */
+    union {
+        /** Byte view - variable. */
+        uint8_t                                   abPageData[1];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptExtendedConfigurationPageHeader    ExtHeader;
+            /** Reserved */
+            uint32_t                              u32Reserved0;
+            /** SAS address */
+            SASADDRESS                            SASAddress;
+            /** Reserved */
+            uint32_t                              u32Reserved;
+            /** Device handle */
+            uint16_t                              u16DevHandle;
+            /** Target ID */
+            uint8_t                               u8TargetID;
+            /** Bus */
+            uint8_t                               u8Bus;
+            /** Initial REgister device FIS */
+            uint32_t                              au32InitialRegDeviceFIS[5];
+        } fields;
+    } u;
+} MptConfigurationPageSASDevice1, *PMptConfigurationPageSASDevice1;
+#pragma pack()
+
+/**
+ * SAS Device page 2 - Read/Write persistent
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageSASDevice2 {
+    /** Union. */
+    union {
+        /** Byte view - variable. */
+        uint8_t                                   abPageData[1];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptExtendedConfigurationPageHeader    ExtHeader;
+            /** Physical identifier */
+            SASADDRESS                            SASAddress;
+            /** Enclosure mapping */
+            uint32_t                              u32EnclosureMapping;
+        } fields;
+    } u;
+} MptConfigurationPageSASDevice2, *PMptConfigurationPageSASDevice2;
+#pragma pack()
+
+/**
+ * A device entitiy containing all pages.
+ */
+typedef struct MptSASDevice {
+    /** Pointer to the next device if any. */
+    struct MptSASDevice            *pNext;
+    /** Pointer to the previous device if any. */
+    struct MptSASDevice            *pPrev;
+
+    MptConfigurationPageSASDevice0  SASDevicePage0;
+    MptConfigurationPageSASDevice1  SASDevicePage1;
+    MptConfigurationPageSASDevice2  SASDevicePage2;
+} MptSASDevice, *PMptSASDevice;
+
+/**
+ * SAS Expander page 0 - Readonly
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageSASExpander0 {
+    /** Union. */
+    union {
+        /** Byte view - variable. */
+        uint8_t                                   abPageData[1];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptExtendedConfigurationPageHeader    ExtHeader;
+            /** Physical port */
+            uint8_t                               u8PhysicalPort;
+            /** Reserved */
+            uint8_t                               u8Reserved0;
+            /** Enclosure handle */
+            uint16_t                              u16EnclosureHandle;
+            /** SAS address */
+            SASADDRESS                            SASAddress;
+            /** Discovery status */
+            uint32_t                              u32DiscoveryStatus;
+            /** Device handle. */
+            uint16_t                              u16DevHandle;
+            /** Parent device handle */
+            uint16_t                              u16ParentDevHandle;
+            /** Expander change count */
+            uint16_t                              u16ExpanderChangeCount;
+            /** Expander route indexes */
+            uint16_t                              u16ExpanderRouteIndexes;
+            /** Number of PHys in this expander */
+            uint8_t                               u8NumPhys;
+            /** SAS level */
+            uint8_t                               u8SASLevel;
+            /** Flags */
+            uint8_t                               u8Flags;
+            /** Reserved */
+            uint8_t                               u8Reserved1;
+        } fields;
+    } u;
+} MptConfigurationPageSASExpander0, *PMptConfigurationPageSASExpander0;
+#pragma pack()
+
+/**
+ * SAS Expander page 1 - Readonly
+ */
+#pragma pack(1)
+typedef struct MptConfigurationPageSASExpander1 {
+    /** Union. */
+    union {
+        /** Byte view - variable. */
+        uint8_t                                   abPageData[1];
+        /** Field view. */
+        struct {
+            /** The omnipresent header. */
+            MptExtendedConfigurationPageHeader    ExtHeader;
+            /** Physical port */
+            uint8_t                               u8PhysicalPort;
+            /** Reserved */
+            uint8_t                               u8Reserved0[3];
+            /** Number of PHYs */
+            uint8_t                               u8NumPhys;
+            /** Number of the Phy the information in this page is for. */
+            uint8_t                               u8Phy;
+            /** Number of routing table entries */
+            uint16_t                              u16NumTableEntriesProgrammed;
+            /** Programmed link rate */
+            uint8_t                               u8ProgrammedLinkRate;
+            /** Hardware link rate */
+            uint8_t                               u8HwLinkRate;
+            /** Attached device handle */
+            uint16_t                              u16AttachedDevHandle;
+            /** Phy information */
+            uint32_t                              u32PhyInfo;
+            /** Attached device information */
+            uint32_t                              u32AttachedDeviceInfo;
+            /** Owner device handle. */
+            uint16_t                              u16OwnerDevHandle;
+            /** Change count */
+            uint8_t                               u8ChangeCount;
+            /** Negotiated link rate */
+            uint8_t                               u8NegotiatedLinkRate;
+            /** Phy identifier */
+            uint8_t                               u8PhyIdentifier;
+            /** Attached phy identifier */
+            uint8_t                               u8AttachedPhyIdentifier;
+            /** Reserved */
+            uint8_t                               u8Reserved1;
+            /** Discovery information */
+            uint8_t                               u8DiscoveryInfo;
+            /** Reserved */
+            uint32_t                              u32Reserved;
+        } fields;
+    } u;
+} MptConfigurationPageSASExpander1, *PMptConfigurationPageSASExpander1;
+#pragma pack()
+
+/**
+ * Structure of all supported pages for the SCSI SPI controller.
+ * Used to load the device state from older versions.
+ */
+typedef struct MptConfigurationPagesSupported_SSM_V2 {
+    MptConfigurationPageManufacturing0 ManufacturingPage0;
+    MptConfigurationPageManufacturing1 ManufacturingPage1;
+    MptConfigurationPageManufacturing2 ManufacturingPage2;
+    MptConfigurationPageManufacturing3 ManufacturingPage3;
+    MptConfigurationPageManufacturing4 ManufacturingPage4;
+    MptConfigurationPageIOUnit0        IOUnitPage0;
+    MptConfigurationPageIOUnit1        IOUnitPage1;
+    MptConfigurationPageIOUnit2        IOUnitPage2;
+    MptConfigurationPageIOUnit3        IOUnitPage3;
+    MptConfigurationPageIOC0           IOCPage0;
+    MptConfigurationPageIOC1           IOCPage1;
+    MptConfigurationPageIOC2           IOCPage2;
+    MptConfigurationPageIOC3           IOCPage3;
+    MptConfigurationPageIOC4           IOCPage4;
+    MptConfigurationPageIOC6           IOCPage6;
+    struct {
+        MptConfigurationPageSCSISPIPort0   SCSISPIPortPage0;
+        MptConfigurationPageSCSISPIPort1   SCSISPIPortPage1;
+        MptConfigurationPageSCSISPIPort2   SCSISPIPortPage2;
+    } aPortPages[1]; /* Currently only one port supported. */
+    struct {
+        struct {
+            MptConfigurationPageSCSISPIDevice0 SCSISPIDevicePage0;
+            MptConfigurationPageSCSISPIDevice1 SCSISPIDevicePage1;
+            MptConfigurationPageSCSISPIDevice2 SCSISPIDevicePage2;
+            MptConfigurationPageSCSISPIDevice3 SCSISPIDevicePage3;
+        } aDevicePages[LSILOGICSCSI_PCI_SPI_DEVICES_MAX];
+    } aBuses[1]; /* Only one bus at the moment. */
+} MptConfigurationPagesSupported_SSM_V2,
+ *PMptConfigurationPagesSupported_SSM_V2;
+
+typedef struct MptConfigurationPagesSpi {
+    struct {
+        MptConfigurationPageSCSISPIPort0   SCSISPIPortPage0;
+        MptConfigurationPageSCSISPIPort1   SCSISPIPortPage1;
+        MptConfigurationPageSCSISPIPort2   SCSISPIPortPage2;
+    } aPortPages[1]; /* Currently only one port supported. */
+    struct {
+        struct {
+            MptConfigurationPageSCSISPIDevice0 SCSISPIDevicePage0;
+            MptConfigurationPageSCSISPIDevice1 SCSISPIDevicePage1;
+            MptConfigurationPageSCSISPIDevice2 SCSISPIDevicePage2;
+            MptConfigurationPageSCSISPIDevice3 SCSISPIDevicePage3;
+        } aDevicePages[LSILOGICSCSI_PCI_SPI_DEVICES_MAX];
+    } aBuses[1]; /* Only one bus at the moment. */
+} MptConfigurationPagesSpi, *PMptConfigurationPagesSpi;
+
+typedef struct MptPHY {
+    MptConfigurationPageSASPHY0     SASPHYPage0;
+    MptConfigurationPageSASPHY1     SASPHYPage1;
+} MptPHY, *PMptPHY;
+
+#pragma pack(1)
+typedef struct MptConfigurationPagesSas {
+    /** Size of the manufacturing page 7 */
+    uint32_t                            cbManufacturingPage7;
+    /** Pointer to the manufacturing page 7 */
+    PMptConfigurationPageManufacturing7 pManufacturingPage7;
+    /** Size of the I/O unit page 0 */
+    uint32_t                            cbSASIOUnitPage0;
+    /** Pointer to the I/O unit page 0 */
+    PMptConfigurationPageSASIOUnit0     pSASIOUnitPage0;
+    /** Size of the I/O unit page 1 */
+    uint32_t                            cbSASIOUnitPage1;
+    /** Pointer to the I/O unit page 1 */
+    PMptConfigurationPageSASIOUnit1     pSASIOUnitPage1;
+    /** I/O unit page 2 */
+    MptConfigurationPageSASIOUnit2      SASIOUnitPage2;
+    /** I/O unit page 3 */
+    MptConfigurationPageSASIOUnit3      SASIOUnitPage3;
+
+    /** Number of PHYs in the array. */
+    uint32_t                            cPHYs;
+    /** Pointer to an array of per PHYS pages. */
+    PMptPHY                             paPHYs;
+
+    /** Number of devices detected. */
+    uint32_t                            cDevices;
+    /** Pointer to the first SAS device. */
+    PMptSASDevice                       pSASDeviceHead;
+    /** Pointer to the last SAS device. */
+    PMptSASDevice                       pSASDeviceTail;
+} MptConfigurationPagesSas, *PMptConfigurationPagesSas;
+#pragma pack()
+
+/**
+ * Structure of all supported pages for both controllers.
+ */
+typedef struct MptConfigurationPagesSupported {
+    MptConfigurationPageManufacturing0  ManufacturingPage0;
+    MptConfigurationPageManufacturing1  ManufacturingPage1;
+    MptConfigurationPageManufacturing2  ManufacturingPage2;
+    MptConfigurationPageManufacturing3  ManufacturingPage3;
+    MptConfigurationPageManufacturing4  ManufacturingPage4;
+    MptConfigurationPageManufacturing5  ManufacturingPage5;
+    MptConfigurationPageManufacturing6  ManufacturingPage6;
+    MptConfigurationPageManufacturing8  ManufacturingPage8;
+    MptConfigurationPageManufacturing9  ManufacturingPage9;
+    MptConfigurationPageManufacturing10 ManufacturingPage10;
+    MptConfigurationPageIOUnit0         IOUnitPage0;
+    MptConfigurationPageIOUnit1         IOUnitPage1;
+    MptConfigurationPageIOUnit2         IOUnitPage2;
+    MptConfigurationPageIOUnit3         IOUnitPage3;
+    MptConfigurationPageIOUnit4         IOUnitPage4;
+    MptConfigurationPageIOC0            IOCPage0;
+    MptConfigurationPageIOC1            IOCPage1;
+    MptConfigurationPageIOC2            IOCPage2;
+    MptConfigurationPageIOC3            IOCPage3;
+    MptConfigurationPageIOC4            IOCPage4;
+    MptConfigurationPageIOC6            IOCPage6;
+    /* BIOS page 0 is not described */
+    MptConfigurationPageBIOS1           BIOSPage1;
+    MptConfigurationPageBIOS2           BIOSPage2;
+    /* BIOS page 3 is not described */
+    MptConfigurationPageBIOS4           BIOSPage4;
+
+    /** Controller dependent data. */
+    union {
+        MptConfigurationPagesSpi        SpiPages;
+        MptConfigurationPagesSas        SasPages;
+    } u;
+} MptConfigurationPagesSupported, *PMptConfigurationPagesSupported;
+
+/**
+ * Initializes a page header.
+ */
+#define MPT_CONFIG_PAGE_HEADER_INIT(pg, type, nr, flags) \
+    (pg)->u.fields.Header.u8PageType   = flags; \
+    (pg)->u.fields.Header.u8PageNumber = nr; \
+    (pg)->u.fields.Header.u8PageLength = sizeof(type) / 4
+
+#define MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(pg, type, nr, flags) \
+    MPT_CONFIG_PAGE_HEADER_INIT(pg, type, nr, flags | \
+        MPT_CONFIGURATION_PAGE_TYPE_MANUFACTURING)
+
+#define MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(pg, type, nr, flags) \
+    MPT_CONFIG_PAGE_HEADER_INIT(pg, type, nr, flags | \
+        MPT_CONFIGURATION_PAGE_TYPE_IO_UNIT)
+
+#define MPT_CONFIG_PAGE_HEADER_INIT_IOC(pg, type, nr, flags) \
+    MPT_CONFIG_PAGE_HEADER_INIT(pg, type, nr, flags | \
+        MPT_CONFIGURATION_PAGE_TYPE_IOC)
+
+#define MPT_CONFIG_PAGE_HEADER_INIT_BIOS(pg, type, nr, flags) \
+    MPT_CONFIG_PAGE_HEADER_INIT(pg, type, nr, flags | \
+        MPT_CONFIGURATION_PAGE_TYPE_BIOS)
+
+/**
+ * Initializes a extended page header.
+ */
+#define MPT_CONFIG_EXTENDED_PAGE_HEADER_INIT(pg, cb, nr, flags, exttype) \
+    (pg)->u.fields.ExtHeader.u8PageType   = flags | \
+        MPT_CONFIGURATION_PAGE_TYPE_EXTENDED; \
+    (pg)->u.fields.ExtHeader.u8PageNumber = nr; \
+    (pg)->u.fields.ExtHeader.u8ExtPageType = exttype; \
+    (pg)->u.fields.ExtHeader.u16ExtPageLength = cb / 4
+
+/**
+ * Possible SG element types.
+ */
+enum MPTSGENTRYTYPE {
+    MPTSGENTRYTYPE_TRANSACTION_CONTEXT = 0x00,
+    MPTSGENTRYTYPE_SIMPLE              = 0x01,
+    MPTSGENTRYTYPE_CHAIN               = 0x03
+};
+
+/**
+ * Register interface.
+ */
+
+/**
+ * Defined states that the SCSI controller can have.
+ */
+typedef enum LSILOGICSTATE {
+    /** Reset state. */
+    LSILOGICSTATE_RESET       = 0x00,
+    /** Ready state. */
+    LSILOGICSTATE_READY       = 0x01,
+    /** Operational state. */
+    LSILOGICSTATE_OPERATIONAL = 0x02,
+    /** Fault state. */
+    LSILOGICSTATE_FAULT       = 0x04,
+    /** 32bit size hack */
+    LSILOGICSTATE_32BIT_HACK  = 0x7fffffff
+} LSILOGICSTATE;
+
+/**
+ * Which entity needs to initialize the controller
+ * to get into the operational state.
+ */
+typedef enum LSILOGICWHOINIT {
+    /** Not initialized. */
+    LSILOGICWHOINIT_NOT_INITIALIZED = 0x00,
+    /** System BIOS. */
+    LSILOGICWHOINIT_SYSTEM_BIOS     = 0x01,
+    /** ROM Bios. */
+    LSILOGICWHOINIT_ROM_BIOS        = 0x02,
+    /** PCI Peer. */
+    LSILOGICWHOINIT_PCI_PEER        = 0x03,
+    /** Host driver. */
+    LSILOGICWHOINIT_HOST_DRIVER     = 0x04,
+    /** Manufacturing. */
+    LSILOGICWHOINIT_MANUFACTURING   = 0x05,
+    /** 32bit size hack. */
+    LSILOGICWHOINIT_32BIT_HACK      = 0x7fffffff
+} LSILOGICWHOINIT;
+
+
+/**
+ * IOC status codes.
+ */
+#define LSILOGIC_IOCSTATUS_SUCCESS                0x0000
+#define LSILOGIC_IOCSTATUS_INVALID_FUNCTION       0x0001
+#define LSILOGIC_IOCSTATUS_BUSY                   0x0002
+#define LSILOGIC_IOCSTATUS_INVALID_SGL            0x0003
+#define LSILOGIC_IOCSTATUS_INTERNAL_ERROR         0x0004
+#define LSILOGIC_IOCSTATUS_RESERVED               0x0005
+#define LSILOGIC_IOCSTATUS_INSUFFICIENT_RESOURCES 0x0006
+#define LSILOGIC_IOCSTATUS_INVALID_FIELD          0x0007
+#define LSILOGIC_IOCSTATUS_INVALID_STATE          0x0008
+#define LSILOGIC_IOCSTATUS_OP_STATE_NOT_SUPPOTED  0x0009
+
+/**
+ * Size of the I/O and MMIO space.
+ */
+#define LSILOGIC_PCI_SPACE_IO_SIZE  256
+#define LSILOGIC_PCI_SPACE_MEM_SIZE (16 * 1024)
+
+/**
+ * Doorbell register - Used to get the status of the controller and
+ * initialise it.
+ */
+#define LSILOGIC_REG_DOORBELL 0x00
+#define LSILOGIC_REG_DOORBELL_SET_STATE(State) (((State) & 0x0f) << 28)
+#define LSILOGIC_REG_DOORBELL_SET_USED(fUsed) (((fUsed) ? 1 : 0) << 27)
+#define LSILOGIC_REG_DOORBELL_SET_WHOINIT(Who)(((Who) & 0x07) << 24)
+#define LSILOGIC_REG_DOORBELL_SET_FAULT_CODE(Code) (Code)
+#define LSILOGIC_REG_DOORBELL_GET_FUNCTION(x) (((x) & 0xff000000) >> 24)
+#define LSILOGIC_REG_DOORBELL_GET_SIZE(x)     (((x) & 0x00ff0000) >> 16)
+
+/**
+ * Functions which can be passed through the system doorbell.
+ */
+#define LSILOGIC_DOORBELL_FUNCTION_IOC_MSG_UNIT_RESET  0x40
+#define LSILOGIC_DOORBELL_FUNCTION_IO_UNIT_RESET       0x41
+#define LSILOGIC_DOORBELL_FUNCTION_HANDSHAKE           0x42
+#define LSILOGIC_DOORBELL_FUNCTION_REPLY_FRAME_REMOVAL 0x43
+
+/**
+ * Write sequence register for the diagnostic register.
+ */
+#define LSILOGIC_REG_WRITE_SEQUENCE    0x04
+
+/**
+ * Diagnostic register - used to reset the controller.
+ */
+#define LSILOGIC_REG_HOST_DIAGNOSTIC   0x08
+#define LSILOGIC_REG_HOST_DIAGNOSTIC_DIAG_MEM_ENABLE     (1<<(0))
+#define LSILOGIC_REG_HOST_DIAGNOSTIC_DISABLE_ARM         (1<<(1))
+#define LSILOGIC_REG_HOST_DIAGNOSTIC_RESET_ADAPTER       (1<<(2))
+#define LSILOGIC_REG_HOST_DIAGNOSTIC_DIAG_RW_ENABLE      (1<<(4))
+#define LSILOGIC_REG_HOST_DIAGNOSTIC_RESET_HISTORY       (1<<(5))
+#define LSILOGIC_REG_HOST_DIAGNOSTIC_FLASH_BAD_SIG       (1<<(6))
+#define LSILOGIC_REG_HOST_DIAGNOSTIC_DRWE                (1<<(7))
+#define LSILOGIC_REG_HOST_DIAGNOSTIC_PREVENT_IOC_BOOT    (1<<(9))
+#define LSILOGIC_REG_HOST_DIAGNOSTIC_CLEAR_FLASH_BAD_SIG (1<<(10))
+
+#define LSILOGIC_REG_TEST_BASE_ADDRESS 0x0c
+#define LSILOGIC_REG_DIAG_RW_DATA      0x10
+#define LSILOGIC_REG_DIAG_RW_ADDRESS   0x14
+
+/**
+ * Interrupt status register.
+ */
+#define LSILOGIC_REG_HOST_INTR_STATUS  0x30
+#define LSILOGIC_REG_HOST_INTR_STATUS_W_MASK (1<<(3))
+#define LSILOGIC_REG_HOST_INTR_STATUS_DOORBELL_STS    (1<<(31))
+#define LSILOGIC_REG_HOST_INTR_STATUS_REPLY_INTR      (1<<(3))
+#define LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL (1<<(0))
+
+/**
+ * Interrupt mask register.
+ */
+#define LSILOGIC_REG_HOST_INTR_MASK    0x34
+#define LSILOGIC_REG_HOST_INTR_MASK_W_MASK (1<<(0) | 1<<(3) | 1<<(8) | 1<<(9))
+#define LSILOGIC_REG_HOST_INTR_MASK_IRQ_ROUTING (1<<(8) | 1<<(9))
+#define LSILOGIC_REG_HOST_INTR_MASK_DOORBELL (1<<(0))
+#define LSILOGIC_REG_HOST_INTR_MASK_REPLY    (1<<(3))
+
+/**
+ * Queue registers.
+ */
+#define LSILOGIC_REG_REQUEST_QUEUE     0x40
+#define LSILOGIC_REG_REPLY_QUEUE       0x44
+
+#endif /* __DEVLSILOGICSCSI_H__ */
diff --git a/hw/pci_ids.h b/hw/pci_ids.h
index 301bf1c..f83c804 100644
--- a/hw/pci_ids.h
+++ b/hw/pci_ids.h
@@ -48,6 +48,10 @@
#define PCI_VENDOR_ID_LSI_LOGIC 0x1000
  #define PCI_DEVICE_ID_LSI_53C895A        0x0012
+#define PCI_DEVICE_ID_LSI_53C1030        0x0030
+#define PCI_DEVICE_ID_LSI_SAS1064        0x0050
+#define PCI_DEVICE_ID_LSI_SAS1068        0x0054
+#define PCI_DEVICE_ID_LSI_SAS1068E       0x0058
  #define PCI_DEVICE_ID_LSI_SAS1078        0x0060
#define PCI_VENDOR_ID_DEC 0x1011
diff --git a/trace-events b/trace-events
index 8fcbc50..0eb2024 100644
--- a/trace-events
+++ b/trace-events
@@ -534,6 +534,32 @@ lm32_uart_irq_state(int level) "irq state %d"
  # hw/lm32_sys.c
  lm32_sys_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 
0x%08x"
+# hw/lsilogic.c
+lsilogic_command_complete(int cmd, uint32_t status, uint32_t resid) "scmd %d: 
command completed, status %x, residual %d"
+lsilogic_diag_readl(unsigned long addr, uint32_t val) "addr 0x%lx: 0x%x"
+lsilogic_diag_writel(uint32_t addr, uint32_t val) "addr 0x%x: 0x%x"
+lsilogic_handle_scsi(const char *frame, int bus, int dev, int lun, void *sdev, unsigned 
long size) "%s dev %x/%x/%x sdev %p xfer %lu"
+lsilogic_init(int sges, int cmds, const char *intr, const char *mode) "Using %d 
sges, %d cmds, %s, %s mode"
+lsilogic_io_complete(int cmd, uint32_t len) "scmd %d: %d bytes completed"
+lsilogic_iov_read_overflow(int cmd, int bytes, int len) "scmd %d: %d/%d bytes"
+lsilogic_iov_read_underflow(int cmd, int bytes, int len) "scmd %d: %d/%d bytes"
+lsilogic_iov_write_overflow(int cmd, int bytes, int len) "scmd %d: %d/%d bytes"
+lsilogic_iov_write_underflow(int cmd, int bytes, int len) "scmd %d: %d/%d 
bytes"
+lsilogic_irq_lower(void) "INTx"
+lsilogic_irq_raise(void) "INTx"
+lsilogic_mmio_invalid_readl(unsigned long addr) "addr 0x%lx"
+lsilogic_mmio_invalid_writel(uint32_t addr, uint32_t val) "addr 0x%x: 0x%x"
+lsilogic_mmio_readl(unsigned long addr, uint32_t val) "addr 0x%lx: 0x%x"
+lsilogic_mmio_writel(uint32_t addr, uint32_t val) "addr 0x%x: 0x%x"
+lsilogic_msix_raise(int vector) "vector %d"
+lsilogic_process_message(const char *msg) "MPT cmd %s\n"
+lsilogic_reset(void) "Reset"
+lsilogic_scsi_complete(int cmd, uint32_t status, int len, int xfer) "scmd %d: 
finished with status %x, len %u/%u"
+lsilogic_scsi_nodata(int cmd) "scmd %d: no data to be transferred"
+lsilogic_scsi_read_start(int cmd, int len) "scmd %d: transfer %d bytes of data"
+lsilogic_scsi_write_start(int cmd, int len) "scmd %d: transfer %d bytes of 
data"
+lsilogic_unhandled_cmd(int cmd, uint8_t msg_cmd) "scmd %d: Unhandled cmd %x"
+
  # hw/megasas.c
  megasas_init_firmware(uint64_t pa) "pa %" PRIx64 " "
  megasas_init_queue(uint64_t queue_pa, int queue_len, uint64_t head, uint64_t tail, uint32_t flags) "queue at 
%" PRIx64 " len %d head %" PRIx64 " tail %" PRIx64 " flags %x"




reply via email to

[Prev in Thread] Current Thread [Next in Thread]