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