Message ID | 1414584016-25888-6-git-send-email-hare@suse.de |
---|---|
State | New |
Headers | show |
On 29/10/2014 13:00, Hannes Reinecke wrote: > The 2108 chip supports MSI and MSI-X, so update the emulation > to support both chips. Is it expected that it doesn't work with latest SeaBIOS? > Signed-off-by: Hannes Reinecke <hare@suse.de> > --- > hw/scsi/megasas.c | 218 +++++++++++++++++++++++++++++++++++++++++------ > hw/scsi/mfi.h | 7 ++ > include/hw/pci/pci_ids.h | 1 + > 3 files changed, 201 insertions(+), 25 deletions(-) > > diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c > index 10e9d7a..190a0bd 100644 > --- a/hw/scsi/megasas.c > +++ b/hw/scsi/megasas.c > @@ -30,9 +30,11 @@ > > #include "mfi.h" > > -#define MEGASAS_VERSION "1.70" > +#define MEGASAS_VERSION_GEN1 "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_GEN2_DEFAULT_FRAMES 1008 /* Windows requires this */ > #define MEGASAS_MAX_SGE 128 /* Firmware limit */ > #define MEGASAS_DEFAULT_SGE 80 > #define MEGASAS_MAX_SECTORS 0xFFFF /* No real limit */ > @@ -90,6 +92,8 @@ typedef struct MegasasState { > int intr_mask; > int doorbell; > int busy; > + int diag; > + int adp_reset; > > MegasasCmd *event_cmd; > int event_locale; > @@ -114,10 +118,26 @@ typedef struct MegasasState { > SCSIBus bus; > } MegasasState; > > -#define TYPE_MEGASAS "megasas" > +typedef struct MegasasBaseClass { > + PCIDeviceClass parent_class; > + const char *product_name; > + const char *product_version; > + int mmio_bar; > + int ioport_bar; > + int osts; > +} MegasasBaseClass; > + > +#define TYPE_MEGASAS_BASE "megasas-base" > +#define TYPE_MEGASAS_GEN1 "megasas" > +#define TYPE_MEGASAS_GEN2 "megasas-gen2" > > #define MEGASAS(obj) \ > - OBJECT_CHECK(MegasasState, (obj), TYPE_MEGASAS) > + OBJECT_CHECK(MegasasState, (obj), TYPE_MEGASAS_BASE) > + > +#define MEGASAS_DEVICE_CLASS(oc) \ > + OBJECT_CLASS_CHECK(MegasasBaseClass, (oc), TYPE_MEGASAS_BASE) > +#define MEGASAS_DEVICE_GET_CLASS(oc) \ > + OBJECT_GET_CLASS(MegasasBaseClass, (oc), TYPE_MEGASAS_BASE) > > #define MEGASAS_INTR_DISABLED_MASK 0xFFFFFFFF > > @@ -685,6 +705,8 @@ 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); > + MegasasBaseClass *base_class = MEGASAS_DEVICE_GET_CLASS(s); > struct mfi_ctrl_info info; > size_t dcmd_size = sizeof(info); > BusChild *kid; > @@ -697,10 +719,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 > @@ -727,11 +749,12 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd) > num_pd_disks++; > } > > - memcpy(info.product_name, "MegaRAID SAS 8708EM2", 20); > + memcpy(info.product_name, base_class->product_name, 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); > + snprintf(info.image_component[0].version, 10, "%s-QEMU", > + base_class->product_version); > memcpy(info.image_component[0].build_date, "Apr 1 2014", 11); > memcpy(info.image_component[0].build_time, "12:34:56", 8); > info.image_component_count = 1; > @@ -1963,6 +1986,8 @@ static uint64_t megasas_mmio_read(void *opaque, hwaddr addr, > unsigned size) > { > MegasasState *s = opaque; > + PCIDevice *pci_dev = PCI_DEVICE(s); > + MegasasBaseClass *base_class = MEGASAS_DEVICE_GET_CLASS(s); > uint32_t retval = 0; > > switch (addr) { > @@ -1971,14 +1996,14 @@ static uint64_t megasas_mmio_read(void *opaque, hwaddr addr, > break; > case MFI_OMSG0: > case MFI_OSP0: > - retval = (megasas_use_msix(s) ? MFI_FWSTATE_MSIX_SUPPORTED : 0) | > + retval = (msix_present(pci_dev) ? MFI_FWSTATE_MSIX_SUPPORTED : 0) | > (s->fw_state & MFI_FWSTATE_MASK) | > ((s->fw_sge & 0xff) << 16) | > (s->fw_cmds & 0xFFFF); > break; > case MFI_OSTS: > if (megasas_intr_enabled(s) && s->doorbell) { > - retval = MFI_1078_RM | 1; > + retval = base_class->osts; > } > break; > case MFI_OMSK: > @@ -1987,6 +2012,12 @@ static uint64_t megasas_mmio_read(void *opaque, hwaddr addr, > case MFI_ODCR0: > retval = s->doorbell; > break; > + case MFI_DIAG: > + retval = s->diag; > + break; > + case MFI_OSP1: > + retval = 15; > + break; > default: > trace_megasas_mmio_invalid_readl(addr); > break; > @@ -1995,6 +2026,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) > { > @@ -2020,6 +2053,10 @@ static void megasas_mmio_write(void *opaque, hwaddr addr, > if (val & MFI_FWINIT_MFIMODE) { > /* discard MFIs */ > } > + if (val & MFI_FWINIT_STOP_ADP) { > + /* Terminal error, stop processing */ > + s->fw_state = MFI_FWSTATE_FAULT; > + } > break; > case MFI_OMSK: > s->intr_mask = val; > @@ -2039,6 +2076,7 @@ static void megasas_mmio_write(void *opaque, hwaddr addr, > } > } else { > trace_megasas_intr_disabled(); > + megasas_soft_reset(s); > } > break; > case MFI_ODCR0: > @@ -2060,8 +2098,9 @@ static void megasas_mmio_write(void *opaque, hwaddr addr, > break; > case MFI_IQPL: > /* Received low 32 bits of a 64 bit MFI frame address */ > + /* Fallthrough */ > case MFI_IQP: > - /* Received 32 bit MFI frame address */ > + /* Received 64 bit MFI frame address */ > frame_addr = (val & ~0x1F); > /* Add possible 64 bit offset */ > frame_addr |= ((uint64_t)s->frame_hi << 32); > @@ -2069,6 +2108,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; > @@ -2153,7 +2214,7 @@ static void megasas_scsi_reset(DeviceState *dev) > megasas_soft_reset(s); > } > > -static const VMStateDescription vmstate_megasas = { > +static VMStateDescription vmstate_megasas_gen1 = { > .name = "megasas", > .version_id = 0, > .minimum_version_id = 0, > @@ -2171,6 +2232,25 @@ static const VMStateDescription vmstate_megasas = { > } > }; > > +static 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); > @@ -2198,6 +2278,7 @@ static int megasas_scsi_init(PCIDevice *dev) > { > DeviceState *d = DEVICE(dev); > MegasasState *s = MEGASAS(dev); > + MegasasBaseClass *b = MEGASAS_DEVICE_GET_CLASS(s); > uint8_t *pci_conf; > int i, bar_type; > Error *err = NULL; > @@ -2221,14 +2302,18 @@ 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, b->mmio_bar, 0x2000, > + &s->mmio_io, b->mmio_bar, 0x3800, 0x68)) { > s->flags &= ~MEGASAS_MASK_USE_MSIX; > } > + if (pci_is_express(dev)) { > + pcie_endpoint_cap_init(dev, 0xa0); > + } > > 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, b->ioport_bar, > + PCI_BASE_ADDRESS_SPACE_IO, &s->port_io); > + pci_register_bar(dev, b->mmio_bar, bar_type, &s->mmio_io); > pci_register_bar(dev, 3, bar_type, &s->queue_io); > > if (megasas_use_msix(s)) { > @@ -2291,7 +2376,7 @@ megasas_write_config(PCIDevice *pci, uint32_t addr, uint32_t val, int len) > msi_write_config(pci, addr, val, len); > } > > -static Property megasas_properties[] = { > +static Property megasas_properties_gen1[] = { > DEFINE_PROP_UINT32("max_sge", MegasasState, fw_sge, > MEGASAS_DEFAULT_SGE), > DEFINE_PROP_UINT32("max_cmds", MegasasState, fw_cmds, > @@ -2307,36 +2392,119 @@ static Property megasas_properties[] = { > DEFINE_PROP_END_OF_LIST(), > }; > > +static Property megasas_properties_gen2[] = { > + DEFINE_PROP_UINT32("max_sge", MegasasState, fw_sge, > + MEGASAS_DEFAULT_SGE), > + DEFINE_PROP_UINT32("max_cmds", MegasasState, fw_cmds, > + MEGASAS_GEN2_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(), > +}; > + > +typedef struct MegasasInfo { > + const char *name; > + const char *desc; > + const char *product_name; > + const char *product_version; > + uint16_t device_id; > + uint16_t subsystem_id; > + int ioport_bar; > + int mmio_bar; > + bool is_express; > + int osts; > + VMStateDescription *vmsd; > + Property *props; > +} MegasasInfo; > + > +static struct MegasasInfo megasas_devices[] = { > + { > + .name = TYPE_MEGASAS_GEN1, > + .desc = "LSI MegaRAID SAS 1078", > + .product_name = "LSI MegaRAID SAS 8708EM2", > + .product_version = MEGASAS_VERSION_GEN1, > + .device_id = PCI_DEVICE_ID_LSI_SAS1078, > + .subsystem_id = 0x1013, > + .ioport_bar = 2, > + .mmio_bar = 0, > + .osts = MFI_1078_RM | 1, > + .is_express = false, > + .vmsd = &vmstate_megasas_gen1, > + .props = megasas_properties_gen1, > + },{ > + .name = TYPE_MEGASAS_GEN2, > + .desc = "LSI MegaRAID SAS 2108", > + .product_name = "LSI MegaRAID SAS 9260-8i", > + .product_version = MEGASAS_VERSION_GEN2, > + .device_id = PCI_DEVICE_ID_LSI_SAS0079, > + .subsystem_id = 0x9261, > + .ioport_bar = 0, > + .mmio_bar = 1, > + .osts = MFI_GEN2_RM, > + .is_express = true, > + .vmsd = &vmstate_megasas_gen2, > + .props = megasas_properties_gen2, > + } > +}; > + > static void megasas_class_init(ObjectClass *oc, void *data) > { > DeviceClass *dc = DEVICE_CLASS(oc); > PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc); > + MegasasBaseClass *e = MEGASAS_DEVICE_CLASS(oc); > + const MegasasInfo *info = data; > > pc->init = megasas_scsi_init; > pc->exit = megasas_scsi_uninit; > pc->vendor_id = PCI_VENDOR_ID_LSI_LOGIC; > - pc->device_id = PCI_DEVICE_ID_LSI_SAS1078; > + pc->device_id = info->device_id; > pc->subsystem_vendor_id = PCI_VENDOR_ID_LSI_LOGIC; > - pc->subsystem_id = 0x1013; > + pc->subsystem_id = info->subsystem_id; > pc->class_id = PCI_CLASS_STORAGE_RAID; > - dc->props = megasas_properties; > + pc->is_express = info->is_express; > + e->mmio_bar = info->mmio_bar; > + e->ioport_bar = info->ioport_bar; > + e->osts = info->osts; > + e->product_name = info->product_name; > + e->product_version = info->product_version; > + dc->props = info->props; > dc->reset = megasas_scsi_reset; > - dc->vmsd = &vmstate_megasas; > + dc->vmsd = info->vmsd; > set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); > - dc->desc = "LSI MegaRAID SAS 1078"; > + dc->desc = info->desc; > pc->config_write = megasas_write_config; > } > > static const TypeInfo megasas_info = { > - .name = TYPE_MEGASAS, > + .name = TYPE_MEGASAS_BASE, > .parent = TYPE_PCI_DEVICE, > .instance_size = sizeof(MegasasState), > - .class_init = megasas_class_init, > + .class_size = sizeof(MegasasBaseClass), > + .abstract = true, > }; > > static void megasas_register_types(void) > { > + int i; > + > type_register_static(&megasas_info); > + for (i = 0; i < ARRAY_SIZE(megasas_devices); i++) { > + const MegasasInfo *info = &megasas_devices[i]; > + TypeInfo type_info = {}; > + > + type_info.name = info->name; > + type_info.parent = TYPE_MEGASAS_BASE; > + type_info.class_data = (void *)info; > + type_info.class_init = megasas_class_init; > + > + type_register(&type_info); > + } > } > > type_init(megasas_register_types) > diff --git a/hw/scsi/mfi.h b/hw/scsi/mfi.h > index 455c96b..29d4177 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 10/31/2014 06:08 PM, Paolo Bonzini wrote: > > > On 29/10/2014 13:00, Hannes Reinecke wrote: >> The 2108 chip supports MSI and MSI-X, so update the emulation >> to support both chips. > > Is it expected that it doesn't work with latest SeaBIOS? > Not expected, but apparently this is the case. I'll be updating SeaBIOS once the patches are in qemu. Cheers, Hannes
On 31/10/2014 18:30, Hannes Reinecke wrote: >>> The 2108 chip supports MSI and MSI-X, so update the emulation >>> to support both chips. >> >> Is it expected that it doesn't work with latest SeaBIOS? > > Not expected, but apparently this is the case. > I'll be updating SeaBIOS once the patches are in qemu. It works with RHEL6, so I went ahead and sent a pull request. Paolo
On 10/31/2014 06:31 PM, Paolo Bonzini wrote: > On 31/10/2014 18:30, Hannes Reinecke wrote: >>>> The 2108 chip supports MSI and MSI-X, so update the emulation >>>> to support both chips. >>> >>> Is it expected that it doesn't work with latest SeaBIOS? >> >> Not expected, but apparently this is the case. >> I'll be updating SeaBIOS once the patches are in qemu. > > It works with RHEL6, so I went ahead and sent a pull request. > I've seen it. Thanks. Cheers, Hannes
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index 10e9d7a..190a0bd 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -30,9 +30,11 @@ #include "mfi.h" -#define MEGASAS_VERSION "1.70" +#define MEGASAS_VERSION_GEN1 "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_GEN2_DEFAULT_FRAMES 1008 /* Windows requires this */ #define MEGASAS_MAX_SGE 128 /* Firmware limit */ #define MEGASAS_DEFAULT_SGE 80 #define MEGASAS_MAX_SECTORS 0xFFFF /* No real limit */ @@ -90,6 +92,8 @@ typedef struct MegasasState { int intr_mask; int doorbell; int busy; + int diag; + int adp_reset; MegasasCmd *event_cmd; int event_locale; @@ -114,10 +118,26 @@ typedef struct MegasasState { SCSIBus bus; } MegasasState; -#define TYPE_MEGASAS "megasas" +typedef struct MegasasBaseClass { + PCIDeviceClass parent_class; + const char *product_name; + const char *product_version; + int mmio_bar; + int ioport_bar; + int osts; +} MegasasBaseClass; + +#define TYPE_MEGASAS_BASE "megasas-base" +#define TYPE_MEGASAS_GEN1 "megasas" +#define TYPE_MEGASAS_GEN2 "megasas-gen2" #define MEGASAS(obj) \ - OBJECT_CHECK(MegasasState, (obj), TYPE_MEGASAS) + OBJECT_CHECK(MegasasState, (obj), TYPE_MEGASAS_BASE) + +#define MEGASAS_DEVICE_CLASS(oc) \ + OBJECT_CLASS_CHECK(MegasasBaseClass, (oc), TYPE_MEGASAS_BASE) +#define MEGASAS_DEVICE_GET_CLASS(oc) \ + OBJECT_GET_CLASS(MegasasBaseClass, (oc), TYPE_MEGASAS_BASE) #define MEGASAS_INTR_DISABLED_MASK 0xFFFFFFFF @@ -685,6 +705,8 @@ 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); + MegasasBaseClass *base_class = MEGASAS_DEVICE_GET_CLASS(s); struct mfi_ctrl_info info; size_t dcmd_size = sizeof(info); BusChild *kid; @@ -697,10 +719,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 @@ -727,11 +749,12 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd) num_pd_disks++; } - memcpy(info.product_name, "MegaRAID SAS 8708EM2", 20); + memcpy(info.product_name, base_class->product_name, 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); + snprintf(info.image_component[0].version, 10, "%s-QEMU", + base_class->product_version); memcpy(info.image_component[0].build_date, "Apr 1 2014", 11); memcpy(info.image_component[0].build_time, "12:34:56", 8); info.image_component_count = 1; @@ -1963,6 +1986,8 @@ static uint64_t megasas_mmio_read(void *opaque, hwaddr addr, unsigned size) { MegasasState *s = opaque; + PCIDevice *pci_dev = PCI_DEVICE(s); + MegasasBaseClass *base_class = MEGASAS_DEVICE_GET_CLASS(s); uint32_t retval = 0; switch (addr) { @@ -1971,14 +1996,14 @@ static uint64_t megasas_mmio_read(void *opaque, hwaddr addr, break; case MFI_OMSG0: case MFI_OSP0: - retval = (megasas_use_msix(s) ? MFI_FWSTATE_MSIX_SUPPORTED : 0) | + retval = (msix_present(pci_dev) ? MFI_FWSTATE_MSIX_SUPPORTED : 0) | (s->fw_state & MFI_FWSTATE_MASK) | ((s->fw_sge & 0xff) << 16) | (s->fw_cmds & 0xFFFF); break; case MFI_OSTS: if (megasas_intr_enabled(s) && s->doorbell) { - retval = MFI_1078_RM | 1; + retval = base_class->osts; } break; case MFI_OMSK: @@ -1987,6 +2012,12 @@ static uint64_t megasas_mmio_read(void *opaque, hwaddr addr, case MFI_ODCR0: retval = s->doorbell; break; + case MFI_DIAG: + retval = s->diag; + break; + case MFI_OSP1: + retval = 15; + break; default: trace_megasas_mmio_invalid_readl(addr); break; @@ -1995,6 +2026,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) { @@ -2020,6 +2053,10 @@ static void megasas_mmio_write(void *opaque, hwaddr addr, if (val & MFI_FWINIT_MFIMODE) { /* discard MFIs */ } + if (val & MFI_FWINIT_STOP_ADP) { + /* Terminal error, stop processing */ + s->fw_state = MFI_FWSTATE_FAULT; + } break; case MFI_OMSK: s->intr_mask = val; @@ -2039,6 +2076,7 @@ static void megasas_mmio_write(void *opaque, hwaddr addr, } } else { trace_megasas_intr_disabled(); + megasas_soft_reset(s); } break; case MFI_ODCR0: @@ -2060,8 +2098,9 @@ static void megasas_mmio_write(void *opaque, hwaddr addr, break; case MFI_IQPL: /* Received low 32 bits of a 64 bit MFI frame address */ + /* Fallthrough */ case MFI_IQP: - /* Received 32 bit MFI frame address */ + /* Received 64 bit MFI frame address */ frame_addr = (val & ~0x1F); /* Add possible 64 bit offset */ frame_addr |= ((uint64_t)s->frame_hi << 32); @@ -2069,6 +2108,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; @@ -2153,7 +2214,7 @@ static void megasas_scsi_reset(DeviceState *dev) megasas_soft_reset(s); } -static const VMStateDescription vmstate_megasas = { +static VMStateDescription vmstate_megasas_gen1 = { .name = "megasas", .version_id = 0, .minimum_version_id = 0, @@ -2171,6 +2232,25 @@ static const VMStateDescription vmstate_megasas = { } }; +static 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); @@ -2198,6 +2278,7 @@ static int megasas_scsi_init(PCIDevice *dev) { DeviceState *d = DEVICE(dev); MegasasState *s = MEGASAS(dev); + MegasasBaseClass *b = MEGASAS_DEVICE_GET_CLASS(s); uint8_t *pci_conf; int i, bar_type; Error *err = NULL; @@ -2221,14 +2302,18 @@ 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, b->mmio_bar, 0x2000, + &s->mmio_io, b->mmio_bar, 0x3800, 0x68)) { s->flags &= ~MEGASAS_MASK_USE_MSIX; } + if (pci_is_express(dev)) { + pcie_endpoint_cap_init(dev, 0xa0); + } 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, b->ioport_bar, + PCI_BASE_ADDRESS_SPACE_IO, &s->port_io); + pci_register_bar(dev, b->mmio_bar, bar_type, &s->mmio_io); pci_register_bar(dev, 3, bar_type, &s->queue_io); if (megasas_use_msix(s)) { @@ -2291,7 +2376,7 @@ megasas_write_config(PCIDevice *pci, uint32_t addr, uint32_t val, int len) msi_write_config(pci, addr, val, len); } -static Property megasas_properties[] = { +static Property megasas_properties_gen1[] = { DEFINE_PROP_UINT32("max_sge", MegasasState, fw_sge, MEGASAS_DEFAULT_SGE), DEFINE_PROP_UINT32("max_cmds", MegasasState, fw_cmds, @@ -2307,36 +2392,119 @@ static Property megasas_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static Property megasas_properties_gen2[] = { + DEFINE_PROP_UINT32("max_sge", MegasasState, fw_sge, + MEGASAS_DEFAULT_SGE), + DEFINE_PROP_UINT32("max_cmds", MegasasState, fw_cmds, + MEGASAS_GEN2_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(), +}; + +typedef struct MegasasInfo { + const char *name; + const char *desc; + const char *product_name; + const char *product_version; + uint16_t device_id; + uint16_t subsystem_id; + int ioport_bar; + int mmio_bar; + bool is_express; + int osts; + VMStateDescription *vmsd; + Property *props; +} MegasasInfo; + +static struct MegasasInfo megasas_devices[] = { + { + .name = TYPE_MEGASAS_GEN1, + .desc = "LSI MegaRAID SAS 1078", + .product_name = "LSI MegaRAID SAS 8708EM2", + .product_version = MEGASAS_VERSION_GEN1, + .device_id = PCI_DEVICE_ID_LSI_SAS1078, + .subsystem_id = 0x1013, + .ioport_bar = 2, + .mmio_bar = 0, + .osts = MFI_1078_RM | 1, + .is_express = false, + .vmsd = &vmstate_megasas_gen1, + .props = megasas_properties_gen1, + },{ + .name = TYPE_MEGASAS_GEN2, + .desc = "LSI MegaRAID SAS 2108", + .product_name = "LSI MegaRAID SAS 9260-8i", + .product_version = MEGASAS_VERSION_GEN2, + .device_id = PCI_DEVICE_ID_LSI_SAS0079, + .subsystem_id = 0x9261, + .ioport_bar = 0, + .mmio_bar = 1, + .osts = MFI_GEN2_RM, + .is_express = true, + .vmsd = &vmstate_megasas_gen2, + .props = megasas_properties_gen2, + } +}; + static void megasas_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc); + MegasasBaseClass *e = MEGASAS_DEVICE_CLASS(oc); + const MegasasInfo *info = data; pc->init = megasas_scsi_init; pc->exit = megasas_scsi_uninit; pc->vendor_id = PCI_VENDOR_ID_LSI_LOGIC; - pc->device_id = PCI_DEVICE_ID_LSI_SAS1078; + pc->device_id = info->device_id; pc->subsystem_vendor_id = PCI_VENDOR_ID_LSI_LOGIC; - pc->subsystem_id = 0x1013; + pc->subsystem_id = info->subsystem_id; pc->class_id = PCI_CLASS_STORAGE_RAID; - dc->props = megasas_properties; + pc->is_express = info->is_express; + e->mmio_bar = info->mmio_bar; + e->ioport_bar = info->ioport_bar; + e->osts = info->osts; + e->product_name = info->product_name; + e->product_version = info->product_version; + dc->props = info->props; dc->reset = megasas_scsi_reset; - dc->vmsd = &vmstate_megasas; + dc->vmsd = info->vmsd; set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - dc->desc = "LSI MegaRAID SAS 1078"; + dc->desc = info->desc; pc->config_write = megasas_write_config; } static const TypeInfo megasas_info = { - .name = TYPE_MEGASAS, + .name = TYPE_MEGASAS_BASE, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(MegasasState), - .class_init = megasas_class_init, + .class_size = sizeof(MegasasBaseClass), + .abstract = true, }; static void megasas_register_types(void) { + int i; + type_register_static(&megasas_info); + for (i = 0; i < ARRAY_SIZE(megasas_devices); i++) { + const MegasasInfo *info = &megasas_devices[i]; + TypeInfo type_info = {}; + + type_info.name = info->name; + type_info.parent = TYPE_MEGASAS_BASE; + type_info.class_data = (void *)info; + type_info.class_init = megasas_class_init; + + type_register(&type_info); + } } type_init(megasas_register_types) diff --git a/hw/scsi/mfi.h b/hw/scsi/mfi.h index 455c96b..29d4177 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 | 218 +++++++++++++++++++++++++++++++++++++++++------ hw/scsi/mfi.h | 7 ++ include/hw/pci/pci_ids.h | 1 + 3 files changed, 201 insertions(+), 25 deletions(-)