Message ID | 1398690105-13949-2-git-send-email-hare@suse.de |
---|---|
State | New |
Headers | show |
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 >
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
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
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
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 --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
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(-)