[Top][All Lists]
[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
Re: [Qemu-devel] [PATCH] hw: Add support for new LSI Logic devices., Gerhard Wiesinger, 2012/09/12
Re: [Qemu-devel] [PATCH] hw: Add support for new LSI Logic devices., Avi Kivity, 2012/09/12