diff mbox

[1/3] megasas: add MegaRAID SAS 2108 emulation

Message ID 1398690105-13949-2-git-send-email-hare@suse.de
State New
Headers show

Commit Message

Hannes Reinecke April 28, 2014, 1:01 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        | 138 ++++++++++++++++++++++++++++++++++++++++++-----
 hw/scsi/mfi.h            |   7 +++
 include/hw/pci/pci_ids.h |   1 +
 3 files changed, 134 insertions(+), 12 deletions(-)

Comments

Paolo Bonzini April 28, 2014, 2:44 p.m. UTC | #1
Il 28/04/2014 15:01, Hannes Reinecke ha scritto:
> The 2108 chip supports MSI and MSI-X, so update the emulation
> to support both chips.

Should the 2108 PCIDeviceClass set the is_express member to true? 
Otherwise you get no QEMU_PCI_CAP_EXPRESS capability.

Paolo

> Signed-off-by: Hannes Reinecke <hare@suse.de>
> ---
>  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
>
Hannes Reinecke April 28, 2014, 2:48 p.m. UTC | #2
On 04/28/2014 04:44 PM, Paolo Bonzini wrote:
> Il 28/04/2014 15:01, Hannes Reinecke ha scritto:
>> The 2108 chip supports MSI and MSI-X, so update the emulation
>> to support both chips.
>
> Should the 2108 PCIDeviceClass set the is_express member to true?
> Otherwise you get no QEMU_PCI_CAP_EXPRESS capability.
>
Ah. Yes, of course.
Can you fix it up?

Cheers,

Hannes
Paolo Bonzini April 28, 2014, 2:54 p.m. UTC | #3
Il 28/04/2014 16:48, Hannes Reinecke ha scritto:
> On 04/28/2014 04:44 PM, Paolo Bonzini wrote:
>> Il 28/04/2014 15:01, Hannes Reinecke ha scritto:
>>> The 2108 chip supports MSI and MSI-X, so update the emulation
>>> to support both chips.
>>
>> Should the 2108 PCIDeviceClass set the is_express member to true?
>> Otherwise you get no QEMU_PCI_CAP_EXPRESS capability.
>>
> Ah. Yes, of course.
> Can you fix it up?

Ok, just wanted to check.

Paolo
Andreas Färber April 28, 2014, 3:20 p.m. UTC | #4
Am 28.04.2014 15:01, schrieb Hannes Reinecke:
> 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        | 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
[...]
> @@ -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);
[...]
> @@ -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 = {

static const

> +    .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)

I note that there is still no qtest in this series. We need to draw a
line somewhere.

Have you tested this device at all? I would expect it to fail horribly
due to the "use_jbod" property being defined on derived and parent type!

Further, deriving the new model from the original one conflicts with my
series for QOM'ifying ->vmsd similar to ->props. Please use an abstract
base type with dc->vmsd == NULL if we need to keep the VMSDs separate.

Regards,
Andreas
Hannes Reinecke April 29, 2014, 6:07 a.m. UTC | #5
On 04/28/2014 05:20 PM, Andreas Färber wrote:
> Am 28.04.2014 15:01, schrieb Hannes Reinecke:
>> 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        | 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
> [...]
>> @@ -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);
> [...]
>> @@ -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 = {
>
> static const
>
>> +    .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)
>
> I note that there is still no qtest in this series. We need to draw a
> line somewhere.
>
> Have you tested this device at all? I would expect it to fail horribly
> due to the "use_jbod" property being defined on derived and parent type!
>
Ah. No, it doesn't fail. System works happily.

> Further, deriving the new model from the original one conflicts with my
> series for QOM'ifying ->vmsd similar to ->props. Please use an abstract
> base type with dc->vmsd == NULL if we need to keep the VMSDs separate.
>
<sigh>Of course. Would've been too easy.</sigh>

For those who do not follow qemu-devel on a daily basis, can you 
elaborate somewhat on how this should be done?
IE would it be sufficient to have one base class and two derived 
classes, so that the current 'megasas' would move to a derived class?
But in doing so, how do I prevent the base class from showing
up in the list of possible drivers?
Is there some example in the code where this is already done?

Cheers,

Hannes
diff mbox

Patch

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