[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 1/3] megasas: add MegaRAID SAS 2108 emulation
From: |
Hannes Reinecke |
Subject: |
[Qemu-devel] [PATCH 1/3] megasas: add MegaRAID SAS 2108 emulation |
Date: |
Mon, 28 Apr 2014 15:01:43 +0200 |
The 2108 chip supports MSI and MSI-X, so update the emulation
to support both chips.
Signed-off-by: Hannes Reinecke <address@hidden>
---
hw/scsi/megasas.c | 138 ++++++++++++++++++++++++++++++++++++++++++-----
hw/scsi/mfi.h | 7 +++
include/hw/pci/pci_ids.h | 1 +
3 files changed, 134 insertions(+), 12 deletions(-)
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index baee46f..519e3bc 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -31,6 +31,7 @@
#include "mfi.h"
#define MEGASAS_VERSION "1.70"
+#define MEGASAS_VERSION_GEN2 "1.80"
#define MEGASAS_MAX_FRAMES 2048 /* Firmware limit at 65535 */
#define MEGASAS_DEFAULT_FRAMES 1000 /* Windows requires this */
#define MEGASAS_MAX_SGE 128 /* Firmware limit */
@@ -90,6 +91,8 @@ typedef struct MegasasState {
int intr_mask;
int doorbell;
int busy;
+ int diag;
+ int adp_reset;
MegasasCmd *event_cmd;
int event_locale;
@@ -115,12 +118,18 @@ typedef struct MegasasState {
} MegasasState;
#define TYPE_MEGASAS "megasas"
+#define TYPE_MEGASAS_GEN2 "megasas-gen2"
#define MEGASAS(obj) \
OBJECT_CHECK(MegasasState, (obj), TYPE_MEGASAS)
#define MEGASAS_INTR_DISABLED_MASK 0xFFFFFFFF
+static bool megasas_is_gen2(PCIDeviceClass *dc)
+{
+ return dc->device_id == PCI_DEVICE_ID_LSI_SAS0079;
+}
+
static bool megasas_intr_enabled(MegasasState *s)
{
if ((s->intr_mask & MEGASAS_INTR_DISABLED_MASK) !=
@@ -681,6 +690,7 @@ static void megasas_finish_dcmd(MegasasCmd *cmd, uint32_t
iov_size)
static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
{
PCIDevice *pci_dev = PCI_DEVICE(s);
+ PCIDeviceClass *pci_class = PCI_DEVICE_GET_CLASS(pci_dev);
struct mfi_ctrl_info info;
size_t dcmd_size = sizeof(info);
BusChild *kid;
@@ -694,10 +704,10 @@ static int megasas_ctrl_get_info(MegasasState *s,
MegasasCmd *cmd)
return MFI_STAT_INVALID_PARAMETER;
}
- info.pci.vendor = cpu_to_le16(PCI_VENDOR_ID_LSI_LOGIC);
- info.pci.device = cpu_to_le16(PCI_DEVICE_ID_LSI_SAS1078);
- info.pci.subvendor = cpu_to_le16(PCI_VENDOR_ID_LSI_LOGIC);
- info.pci.subdevice = cpu_to_le16(0x1013);
+ info.pci.vendor = cpu_to_le16(pci_class->vendor_id);
+ info.pci.device = cpu_to_le16(pci_class->device_id);
+ info.pci.subvendor = cpu_to_le16(pci_class->subsystem_vendor_id);
+ info.pci.subdevice = cpu_to_le16(pci_class->subsystem_id);
/*
* For some reason the firmware supports
@@ -723,11 +733,21 @@ static int megasas_ctrl_get_info(MegasasState *s,
MegasasCmd *cmd)
num_ld_disks++;
}
- memcpy(info.product_name, "MegaRAID SAS 8708EM2", 20);
+ if (megasas_is_gen2(pci_class)) {
+ memcpy(info.product_name, "LSI MegaRAID SAS 9260-8i", 24);
+ } else {
+ memcpy(info.product_name, "LSI MegaRAID SAS 8708EM2", 24);
+ }
snprintf(info.serial_number, 32, "%s", s->hba_serial);
snprintf(info.package_version, 0x60, "%s-QEMU", QEMU_VERSION);
memcpy(info.image_component[0].name, "APP", 3);
- memcpy(info.image_component[0].version, MEGASAS_VERSION "-QEMU", 9);
+ if (megasas_is_gen2(pci_class)) {
+ memcpy(info.image_component[0].version,
+ MEGASAS_VERSION_GEN2 "-QEMU", 9);
+ } else {
+ memcpy(info.image_component[0].version,
+ MEGASAS_VERSION "-QEMU", 9);
+ }
memcpy(info.image_component[0].build_date, __DATE__, 11);
memcpy(info.image_component[0].build_time, __TIME__, 8);
info.image_component_count = 1;
@@ -1907,6 +1927,7 @@ static uint64_t megasas_mmio_read(void *opaque, hwaddr
addr,
unsigned size)
{
MegasasState *s = opaque;
+ PCIDeviceClass *pci_class = PCI_DEVICE_GET_CLASS(s);
uint32_t retval = 0;
switch (addr) {
@@ -1922,7 +1943,11 @@ static uint64_t megasas_mmio_read(void *opaque, hwaddr
addr,
break;
case MFI_OSTS:
if (megasas_intr_enabled(s) && s->doorbell) {
- retval = MFI_1078_RM | 1;
+ if (megasas_is_gen2(pci_class)) {
+ retval = MFI_GEN2_RM;
+ } else {
+ retval = MFI_1078_RM | 1;
+ }
}
break;
case MFI_OMSK:
@@ -1931,6 +1956,9 @@ static uint64_t megasas_mmio_read(void *opaque, hwaddr
addr,
case MFI_ODCR0:
retval = s->doorbell;
break;
+ case MFI_DIAG:
+ retval = s->diag;
+ break;
default:
trace_megasas_mmio_invalid_readl(addr);
break;
@@ -1939,6 +1967,8 @@ static uint64_t megasas_mmio_read(void *opaque, hwaddr
addr,
return retval;
}
+static int adp_reset_seq[] = {0x00, 0x04, 0x0b, 0x02, 0x07, 0x0d};
+
static void megasas_mmio_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
@@ -2013,6 +2043,28 @@ static void megasas_mmio_write(void *opaque, hwaddr addr,
frame_count = (val >> 1) & 0xF;
megasas_handle_frame(s, frame_addr, frame_count);
break;
+ case MFI_SEQ:
+ /* Magic sequence to start ADP reset */
+ if (adp_reset_seq[s->adp_reset] == val) {
+ s->adp_reset++;
+ } else {
+ s->adp_reset = 0;
+ s->diag = 0;
+ }
+ if (s->adp_reset == 6) {
+ s->diag = MFI_DIAG_WRITE_ENABLE;
+ }
+ break;
+ case MFI_DIAG:
+ /* ADP reset */
+ if ((s->diag & MFI_DIAG_WRITE_ENABLE) &&
+ (val & MFI_DIAG_RESET_ADP)) {
+ s->diag |= MFI_DIAG_RESET_ADP;
+ megasas_soft_reset(s);
+ s->adp_reset = 0;
+ s->diag = 0;
+ }
+ break;
default:
trace_megasas_mmio_invalid_writel(addr, val);
break;
@@ -2116,6 +2168,25 @@ static const VMStateDescription vmstate_megasas = {
}
};
+static const VMStateDescription vmstate_megasas_gen2 = {
+ .name = "megasas-gen2",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCIE_DEVICE(parent_obj, MegasasState),
+ VMSTATE_MSIX(parent_obj, MegasasState),
+
+ VMSTATE_INT32(fw_state, MegasasState),
+ VMSTATE_INT32(intr_mask, MegasasState),
+ VMSTATE_INT32(doorbell, MegasasState),
+ VMSTATE_UINT64(reply_queue_pa, MegasasState),
+ VMSTATE_UINT64(consumer_pa, MegasasState),
+ VMSTATE_UINT64(producer_pa, MegasasState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void megasas_scsi_uninit(PCIDevice *d)
{
MegasasState *s = MEGASAS(d);
@@ -2146,10 +2217,18 @@ static int megasas_scsi_init(PCIDevice *dev)
{
DeviceState *d = DEVICE(dev);
MegasasState *s = MEGASAS(dev);
+ PCIDeviceClass *c = PCI_DEVICE_GET_CLASS(dev);
uint8_t *pci_conf;
- int i, bar_type;
+ int i, bar_type, mmio_bar, ioport_bar;
Error *err = NULL;
+ if (megasas_is_gen2(c)) {
+ mmio_bar = 1;
+ ioport_bar = 0;
+ } else {
+ mmio_bar = 0;
+ ioport_bar = 2;
+ }
pci_conf = dev->config;
/* PCI latency timer = 0 */
@@ -2169,14 +2248,14 @@ static int megasas_scsi_init(PCIDevice *dev)
s->flags &= ~MEGASAS_MASK_USE_MSI;
}
if (megasas_use_msix(s) &&
- msix_init(dev, 15, &s->mmio_io, 0, 0x2000,
- &s->mmio_io, 0, 0x3800, 0x68)) {
+ msix_init(dev, 15, &s->mmio_io, mmio_bar, 0x2000,
+ &s->mmio_io, mmio_bar, 0x3800, 0x68)) {
s->flags &= ~MEGASAS_MASK_USE_MSIX;
}
bar_type = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64;
- pci_register_bar(dev, 0, bar_type, &s->mmio_io);
- pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_IO, &s->port_io);
+ pci_register_bar(dev, ioport_bar, PCI_BASE_ADDRESS_SPACE_IO, &s->port_io);
+ pci_register_bar(dev, mmio_bar, bar_type, &s->mmio_io);
pci_register_bar(dev, 3, bar_type, &s->queue_io);
if (megasas_use_msix(s)) {
@@ -2278,9 +2357,44 @@ static const TypeInfo megasas_info = {
.class_init = megasas_class_init,
};
+static Property megasas_gen2_properties[] = {
+ DEFINE_PROP_UINT32("max_sge", MegasasState, fw_sge,
+ MEGASAS_DEFAULT_SGE),
+ DEFINE_PROP_UINT32("max_cmds", MegasasState, fw_cmds,
+ MEGASAS_DEFAULT_FRAMES),
+ DEFINE_PROP_STRING("hba_serial", MegasasState, hba_serial),
+ DEFINE_PROP_UINT64("sas_address", MegasasState, sas_addr, 0),
+ DEFINE_PROP_BIT("use_msi", MegasasState, flags,
+ MEGASAS_FLAG_USE_MSI, true),
+ DEFINE_PROP_BIT("use_msix", MegasasState, flags,
+ MEGASAS_FLAG_USE_MSIX, true),
+ DEFINE_PROP_BIT("use_jbod", MegasasState, flags,
+ MEGASAS_FLAG_USE_JBOD, false),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void megasas_gen2_class_init(ObjectClass *oc, void *data)
+{
+ PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ pc->device_id = PCI_DEVICE_ID_LSI_SAS0079;
+ pc->subsystem_id = 0x9261;
+ dc->props = megasas_gen2_properties;
+ dc->desc = "LSI MegaRAID SAS 2108";
+ dc->vmsd = &vmstate_megasas_gen2;
+}
+
+static TypeInfo megasas_gen2_info = {
+ .name = TYPE_MEGASAS_GEN2,
+ .parent = TYPE_MEGASAS,
+ .class_init = megasas_gen2_class_init,
+};
+
static void megasas_register_types(void)
{
type_register_static(&megasas_info);
+ type_register_static(&megasas_gen2_info);
}
type_init(megasas_register_types)
diff --git a/hw/scsi/mfi.h b/hw/scsi/mfi.h
index a3034f6..b344e4a 100644
--- a/hw/scsi/mfi.h
+++ b/hw/scsi/mfi.h
@@ -60,6 +60,7 @@
#define MFI_ODR0 0x9c /* outbound doorbell register0 */
#define MFI_ODCR0 0xa0 /* outbound doorbell clear register0
*/
#define MFI_OSP0 0xb0 /* outbound scratch pad0 */
+#define MFI_OSP1 0xb4 /* outbound scratch pad1 */
#define MFI_IQPL 0xc0 /* Inbound queue port (low bytes) */
#define MFI_IQPH 0xc4 /* Inbound queue port (high bytes) */
#define MFI_DIAG 0xf8 /* Host diag */
@@ -116,6 +117,12 @@
#define MFI_FWINIT_STOP_ADP 0x00000020 /* Move to operational, stop */
#define MFI_FWINIT_ADP_RESET 0x00000040 /* Reset ADP */
+/*
+ * Control bits for the DIAG register
+ */
+#define MFI_DIAG_WRITE_ENABLE 0x00000080
+#define MFI_DIAG_RESET_ADP 0x00000004
+
/* MFI Commands */
typedef enum {
MFI_CMD_INIT = 0x00,
diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h
index e597070..321d622 100644
--- a/include/hw/pci/pci_ids.h
+++ b/include/hw/pci/pci_ids.h
@@ -56,6 +56,7 @@
#define PCI_DEVICE_ID_LSI_53C810 0x0001
#define PCI_DEVICE_ID_LSI_53C895A 0x0012
#define PCI_DEVICE_ID_LSI_SAS1078 0x0060
+#define PCI_DEVICE_ID_LSI_SAS0079 0x0079
#define PCI_VENDOR_ID_DEC 0x1011
#define PCI_DEVICE_ID_DEC_21154 0x0026
--
1.7.12.4