diff mbox

hw: Add support for new LSI Logic devices.

Message ID 1347382813-5662-1-git-send-email-Don@CloudSwitch.com
State New
Headers show

Commit Message

Don Slutz Sept. 11, 2012, 5 p.m. UTC
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 <Don@CloudSwitch.com>
---
 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

Comments

Michael S. Tsirkin Sept. 11, 2012, 11:50 p.m. UTC | #1
On Tue, Sep 11, 2012 at 01:00:13PM -0400, 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.

I think you mean VMware emulates this controller too,
pls say it explicitly in the commit log.

> SEABIOS change for booting is in the works.
> 
> Tested with Fedora 16, 17.  CentoOS 6. Windows 2003R2 and 2008R2.
> 
> Signed-off-by: Don Slutz <Don@CloudSwitch.com>

Minor comments below.

Coding style does not adhere to qemu standards,
I guess you know that :)

Otherwise, from pci side of things this looks OK.
I did not look at the scsi side of things.

> ---
>  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.
> + */
> +
> +

I suspect you need to rewrite above: probably add
all copyrights in 1st header and make it v2 only.

> +#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]))

Pls replace with ARRAY_SIZE.

> +
> +#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);
> +    }

Find 10 differences between if and else branches above :)

> +
> +#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";

I think it should be more verbose
"LSI Logic PCI-X Fusion-MPT SAS Host Bus Adapter"
or something?


> +}
> +
> +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.
> + */

Can you combine this header into .c file please?
And if possible, drop all kind of unused types
and dead code from it.

> +
> +/*
> + * 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)

pci ids are in their standard names, pls use from there.

> +#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

Interesting. I see:
1000  LSI Logic / Symbios Logic
        0054  SAS1068 PCI-X Fusion-MPT SAS
        0050  SAS1064 PCI-X Fusion-MPT SAS
	0030  53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI

so in reality these are PCI-X devices?

I don't mind that pci-x in qemu is incomplete
but maybe add a comment about this in code.


> +#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"
> -- 
> 1.7.1
Paolo Bonzini Sept. 12, 2012, 6:01 a.m. UTC | #2
Il 12/09/2012 01:50, Michael S. Tsirkin ha scritto:
> +static void lsilogic_abort_command(LsilogicCmd *cmd)
> +{
> +    if (cmd->req) {
> +        scsi_req_cancel(cmd->req);
> +        cmd->req = NULL;
> +    }
> +}

This only needs to be cmd->req = NULL.

> 
> +    if (cmd) {
> +        lsilogic_abort_command(cmd);
> +    } else {
> +        scsi_req_unref(req);
> +    }

This should be

    if (cmd && cmd->req) {
        scsi_req_unref(req);
        cmd->req = NULL;
    }

>> +                                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);
>> +            }

I think the second if needs to go before scsi_req_continue, otherwise
the trace will be a bit confused.

The SCSI parts otherwise look good.  I don't think there's much value in
keeping the coding standards for code that comes from elsewhere (I mean
mostly the struct definitions).

For the obvious bikeshedding, please call this lsisas1068.[ch].

Paolo
Gerhard Wiesinger Sept. 12, 2012, 6:58 a.m. UTC | #3
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 <Don@CloudSwitch.com>
>

Hello Don,

Looks great! Will give it a try.

BTW: Anyone working on a Buslogic SCSI implementation. Then the list for 
VMWare is IHMO complete.

Ciao,
Gerhard
Kevin Wolf Sept. 12, 2012, 12:36 p.m. UTC | #4
Am 12.09.2012 01:50, schrieb Michael S. Tsirkin:
> On Tue, Sep 11, 2012 at 01:00:13PM -0400, 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.
> 
> I think you mean VMware emulates this controller too,
> pls say it explicitly in the commit log.
> 
>> SEABIOS change for booting is in the works.
>>
>> Tested with Fedora 16, 17.  CentoOS 6. Windows 2003R2 and 2008R2.
>>
>> Signed-off-by: Don Slutz <Don@CloudSwitch.com>
> 
> Minor comments below.
> 
> Coding style does not adhere to qemu standards,
> I guess you know that :)
> 
> Otherwise, from pci side of things this looks OK.
> I did not look at the scsi side of things.
> 
>> ---
>>  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.
>> + */
>> +
>> +
> 
> I suspect you need to rewrite above: probably add
> all copyrights in 1st header and make it v2 only.

Do we even accept new GPLv2-only code?

Kevin
Anthony Liguori Sept. 12, 2012, 1:58 p.m. UTC | #5
Kevin Wolf <kwolf@redhat.com> writes:

> Am 12.09.2012 01:50, schrieb Michael S. Tsirkin:
>> On Tue, Sep 11, 2012 at 01:00:13PM -0400, 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.
>> 
>> I think you mean VMware emulates this controller too,
>> pls say it explicitly in the commit log.
>> 
>>> SEABIOS change for booting is in the works.
>>>
>>> Tested with Fedora 16, 17.  CentoOS 6. Windows 2003R2 and 2008R2.
>>>
>>> Signed-off-by: Don Slutz <Don@CloudSwitch.com>
>> 
>> Minor comments below.
>> 
>> Coding style does not adhere to qemu standards,
>> I guess you know that :)
>> 
>> Otherwise, from pci side of things this looks OK.
>> I did not look at the scsi side of things.
>> 
>>> ---
>>>  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.
>>> + */
>>> +
>>> +
>> 
>> I suspect you need to rewrite above: probably add
>> all copyrights in 1st header and make it v2 only.
>
> Do we even accept new GPLv2-only code?

Yes.

I've got some concern about the maintainability of this though.  This is
code copied from another project and then heavily modified.

Are we prepared to independently fork this device?  How are we going to test it
regularly?

We seem to be growing SCSI controllers like weeds.  Why would someone
use this verses megasas vs. LSI vs virtio-scsi?

Regards,

Anthony Liguori

>
> Kevin
Avi Kivity Sept. 12, 2012, 3:38 p.m. UTC | #6
On 09/11/2012 08:00 PM, 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.
> 

Is the spec for these devices freely available?  Please provide a link
in the source.
Paolo Bonzini Sept. 13, 2012, 6:24 a.m. UTC | #7
Il 12/09/2012 15:58, Anthony Liguori ha scritto:
> Why would someone use this verses megasas vs. LSI vs virtio-scsi?

LSI is dead.  Compare it to IDE.

virtio-scsi has the highest performance, but it is not supported on all
guests.  Compare it to virtio-blk.

This vs. megasas is a good question; both can be compared to AHCI, they
have good performance and have the advantage of compatibility with real
hardware.  If this had gone in first, I would probably have rejected
megasas, but this has the advantage of being used in VMware and
VirtualBox.  Plus, unlike megasas Don said he'd work on SeaBIOS support,
so it has further merit.

Paolo
Don Slutz Sept. 13, 2012, 12:43 p.m. UTC | #8
On 09/12/12 09:58, Anthony Liguori wrote:
> Kevin Wolf <kwolf@redhat.com> writes:
>
>> Am 12.09.2012 01:50, schrieb Michael S. Tsirkin:
>>> On Tue, Sep 11, 2012 at 01:00:13PM -0400, 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.
>>> I think you mean VMware emulates this controller too,
>>> pls say it explicitly in the commit log.
Will do in V2.
>>>
>>>> SEABIOS change for booting is in the works.
>>>>
>>>> Tested with Fedora 16, 17.  CentoOS 6. Windows 2003R2 and 2008R2.
>>>>
>>>> Signed-off-by: Don Slutz <Don@CloudSwitch.com>
>>> Minor comments below.
>>>
>>> Coding style does not adhere to qemu standards,
>>> I guess you know that :)
Yes, But I did get checkpatch.pl to not complain.
>>>
>>> Otherwise, from pci side of things this looks OK.
>>> I did not look at the scsi side of things.
>>>
>>>> ---
>>>>   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.
>>>> + */
>>>> +
>>>> +
>>> I suspect you need to rewrite above: probably add
>>> all copyrights in 1st header and make it v2 only.
Working on the rewrite.
>> Do we even accept new GPLv2-only code?
> Yes.
>
> I've got some concern about the maintainability of this though.  This is
> code copied from another project and then heavily modified.
>
> Are we prepared to independently fork this device?  How are we going to test it
> regularly?
I have no issue with adding myself to MAINTAINERS (hw/lsilogic*) for 
this patch.  In the near term I will be doing a lot of testing with it.  
I am just starting at looking into some sort of automatic test for this.
> We seem to be growing SCSI controllers like weeds.  Why would someone
> use this verses megasas vs. LSI vs virtio-scsi?
If you are attempting to use a disk that was built under Virtual Box, 
VMware, etc. as a guest for QEMU, it is likely that this is the scsi 
controller (if it was built using one) that was used.
>
> Regards,
>
> Anthony Liguori
>
>> Kevin
Don Slutz Sept. 13, 2012, 12:46 p.m. UTC | #9
On 09/12/12 11:38, Avi Kivity wrote:
> On 09/11/2012 08:00 PM, 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.
>>
> Is the spec for these devices freely available?  Please provide a link
> in the source.
>
>
Still looking for freely available spec.
    -Don
Anthony Liguori Sept. 13, 2012, 1:14 p.m. UTC | #10
Paolo Bonzini <pbonzini@redhat.com> writes:

> Il 12/09/2012 15:58, Anthony Liguori ha scritto:
>> Why would someone use this verses megasas vs. LSI vs virtio-scsi?
>
> LSI is dead.  Compare it to IDE.
>
> virtio-scsi has the highest performance, but it is not supported on all
> guests.  Compare it to virtio-blk.
>
> This vs. megasas is a good question; both can be compared to AHCI, they
> have good performance and have the advantage of compatibility with real
> hardware.  If this had gone in first, I would probably have rejected
> megasas, but this has the advantage of being used in VMware and
> VirtualBox.  Plus, unlike megasas Don said he'd work on SeaBIOS support,
> so it has further merit.

Okay.  Thanks.

Regards,

Anthony Liguori

>
> Paolo
Michael S. Tsirkin Sept. 13, 2012, 1:54 p.m. UTC | #11
On Tue, Sep 11, 2012 at 01:00:13PM -0400, Don Slutz wrote:
> +            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);

BTW all this logic seems wrong on big endian.
Maybe we don't care short term but we do long term.
I think you need to fix it up using le_to_cpu or something.
And in particular this likely means bitfields can not be used cleanly,
so you will not be able to resync lsilogic.h from virtualbox.
The implication I guess is that we should just fix up the style
to match qemu.
Don Slutz Sept. 13, 2012, 5:10 p.m. UTC | #12
On 09/12/12 02:58, Gerhard Wiesinger wrote:
> 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 <Don@CloudSwitch.com>
>>
>
> Hello Don,
>
> Looks great! Will give it a try.
>
> BTW: Anyone working on a Buslogic SCSI implementation. Then the list 
> for VMWare is IHMO complete.
I am thinking about doing it.  Seems to not be popular.
>
> Ciao,
> Gerhard
>
    -Don
Anthony Liguori Sept. 13, 2012, 8:57 p.m. UTC | #13
"Michael S. Tsirkin" <mst@redhat.com> writes:

> On Tue, Sep 11, 2012 at 01:00:13PM -0400, Don Slutz wrote:
>> +            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);
>
> BTW all this logic seems wrong on big endian.
> Maybe we don't care short term but we do long term.

I think we care short term.  It's easy enough to copy and past but i'm
not inclined to believe this will be maintained longer term if someone
makes the investment to de-uglify things.

I can tolerate a lot, but I'm not going to pull something with variable
names of 'u8NextChainOffset' :-)  Changing this in tree is just
unnecessary churn.

Regards,

Anthony Liguori

> I think you need to fix it up using le_to_cpu or something.
> And in particular this likely means bitfields can not be used cleanly,
> so you will not be able to resync lsilogic.h from virtualbox.
> The implication I guess is that we should just fix up the style
> to match qemu.
>
> -- 
> MST
Don Slutz Sept. 29, 2012, 2:35 p.m. UTC | #14
On 09/13/12 16:57, Anthony Liguori wrote:
> "Michael S. Tsirkin" <mst@redhat.com> writes:
>
>> On Tue, Sep 11, 2012 at 01:00:13PM -0400, Don Slutz wrote:
>>> +            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);
>> BTW all this logic seems wrong on big endian.
>> Maybe we don't care short term but we do long term.
> I think we care short term.  It's easy enough to copy and past but i'm
> not inclined to believe this will be maintained longer term if someone
> makes the investment to de-uglify things.
How important is the big endian support?

lsi53c895a.c says:

/* ??? Need to check if the {read,write}[wl] routines work properly on
    big-endian targets.  */

I could do the same, I.E. code it up and submit it un-tested on big 
endian soon.  Or since I currently do not have access to any real big 
endian hardware;  do all testing on QEMU on QEMU.

> I can tolerate a lot, but I'm not going to pull something with variable
> names of 'u8NextChainOffset' :-)  Changing this in tree is just
> unnecessary churn.

I have re-worked the variable names.  For example:

             if (next_chain_offset) {
                 MptSGEntryChain sgec;
                 cpu_physical_memory_read(seg_start_pa + next_chain_offset,
                                          &sgec, sizeof(MptSGEntryChain));
                 assert(sgec.element_type == MPTSGENTRYTYPE_CHAIN);
                 next_sge_pa = sgec.segment_address_low;
                 if (sgec.bit_address) {
                     next_sge_pa |=
                         ((uint64_t)sgec.segment_address_high) << 32;
                 }
                 seg_start_pa = next_sge_pa;
                 next_chain_offset = sgec.next_chain_offset * 
sizeof(uint32_t);

Does this look better?

> Regards,
>
> Anthony Liguori
>
>> I think you need to fix it up using le_to_cpu or something.
>> And in particular this likely means bitfields can not be used cleanly,
>> so you will not be able to resync lsilogic.h from virtualbox.
>> The implication I guess is that we should just fix up the style
>> to match qemu.
>>
>> -- 
>> MST
   -Don Slutz
Paolo Bonzini Oct. 1, 2012, 2:25 p.m. UTC | #15
Il 29/09/2012 16:35, Don Slutz ha scritto:
>>
> How important is the big endian support?
> 
> lsi53c895a.c says:
> 
> /* ??? Need to check if the {read,write}[wl] routines work properly on
>    big-endian targets.  */
> 
> I could do the same, I.E. code it up and submit it un-tested on big
> endian soon.  Or since I currently do not have access to any real big
> endian hardware;  do all testing on QEMU on QEMU.

Yes, that's a start.

The best example of big endian hardware that QEMU supports is pSeries.
Usually the pSeries people are quite helpful with endianness bugs.

Paolo
Hannes Reinecke Oct. 4, 2012, 1:45 p.m. UTC | #16
On 09/13/2012 08:24 AM, Paolo Bonzini wrote:
> Il 12/09/2012 15:58, Anthony Liguori ha scritto:
>> Why would someone use this verses megasas vs. LSI vs virtio-scsi?
>
> LSI is dead.  Compare it to IDE.
>
> virtio-scsi has the highest performance, but it is not supported on all
> guests.  Compare it to virtio-blk.
>
> This vs. megasas is a good question; both can be compared to AHCI, they
> have good performance and have the advantage of compatibility with real
> hardware.  If this had gone in first, I would probably have rejected
> megasas, but this has the advantage of being used in VMware and
> VirtualBox.  Plus, unlike megasas Don said he'd work on SeaBIOS support,
> so it has further merit.
>
Ah.

Well, I'll be working on SeaBIOS support then, too :-)
I just haven't seen the need yet as it boots happily with an 
external ROM ...

However:
The main difference here is that the proposed 'lsilogic' controller 
emulates a SCSI or SAS controller, whereas the megasas emulates a 
RAID controller.
So for the former you have to implement _lot_ of code to make the 
emulation happy; most of which will be static (just look at the 
various config pages it'll has to implement) and just adds to the 
general size of the code without any functional benefit.

For megasas the controller itself does an emulation, which maps 
pretty well to qemu. And you don't have to implement all these 
transport-specific details.

Cheers,

Hannes
Gerhard Wiesinger Nov. 8, 2012, 7:03 p.m. UTC | #17
Tested Don's latest patch and also with his non submitted seabios patch.

XP, Linux: Tested-by: Gerhard Wiesinger <lists@wiesinger.com>

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 <Don@CloudSwitch.com>
> ---
>   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"
diff mbox

Patch

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"