qemu-devel
[Top][All Lists]
Advanced

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

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


From: Michael S. Tsirkin
Subject: Re: [Qemu-devel] [PATCH] hw: Add support for new LSI Logic devices.
Date: Wed, 12 Sep 2012 02:50:21 +0300

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 <address@hidden>

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



reply via email to

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