From patchwork Tue Sep 11 17:00:13 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Don Slutz X-Patchwork-Id: 183156 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 15D3D2C0089 for ; Wed, 12 Sep 2012 03:01:27 +1000 (EST) Received: from localhost ([::1]:41578 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TBTq1-0000NU-0i for incoming@patchwork.ozlabs.org; Tue, 11 Sep 2012 13:01:25 -0400 Received: from eggs.gnu.org ([208.118.235.92]:42513) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TBTpL-0000IM-Qz for qemu-devel@nongnu.org; Tue, 11 Sep 2012 13:01:04 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TBTp2-0006TC-GX for qemu-devel@nongnu.org; Tue, 11 Sep 2012 13:00:43 -0400 Received: from hub021-nj-8.exch021.serverdata.net ([206.225.164.233]:9800) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TBTp1-0006Qs-Vz for qemu-devel@nongnu.org; Tue, 11 Sep 2012 13:00:24 -0400 Received: from localhost.localdomain (131.239.15.22) by east.exch021.serverdata.net (10.240.4.118) with Microsoft SMTP Server (TLS) id 14.2.309.2; Tue, 11 Sep 2012 10:00:21 -0700 From: Don Slutz To: , , , Date: Tue, 11 Sep 2012 13:00:13 -0400 Message-ID: <1347382813-5662-1-git-send-email-Don@CloudSwitch.com> X-Mailer: git-send-email 1.7.1 MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Windows XP/2000 (RFC1323+, w+, tstamp-) X-Received-From: 206.225.164.233 Cc: Don Slutz Subject: [Qemu-devel] [PATCH] hw: Add support for new LSI Logic devices. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- 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 . + */ + +/* 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"