diff mbox

[4/7] megasas: add MegaRAID SAS 2108 emulation

Message ID 1397659459-10069-5-git-send-email-hare@suse.de
State New
Headers show

Commit Message

Hannes Reinecke April 16, 2014, 2:44 p.m. UTC
The 2108 chip supports MSI and MSI-X, so update the emulation
to support both chips.

Signed-off-by: Hannes Reinecke <hare@suse.de>
---
 hw/scsi/megasas.c        | 118 ++++++++++++++++++++++++++++++++++++++++++-----
 hw/scsi/mfi.h            |   7 +++
 include/hw/pci/pci_ids.h |   1 +
 3 files changed, 114 insertions(+), 12 deletions(-)
diff mbox

Patch

diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index a12cd92..a5bfeba 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;
@@ -2146,10 +2198,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 +2229,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 +2338,43 @@  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";
+}
+
+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