[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 05/13] megasas: add MegaRAID SAS 2108 emulation
From: |
Paolo Bonzini |
Subject: |
Re: [Qemu-devel] [PATCH 05/13] megasas: add MegaRAID SAS 2108 emulation |
Date: |
Fri, 31 Oct 2014 18:08:54 +0100 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.2.0 |
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 <address@hidden>
> ---
> 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
>
- [Qemu-devel] [PATCHv2 00/13] megasas: gen2 emulation and MSI-X fixes, Hannes Reinecke, 2014/10/29
- [Qemu-devel] [PATCH 03/13] megasas: simplify trace event messages, Hannes Reinecke, 2014/10/29
- [Qemu-devel] [PATCH 01/13] scsi: Rename scsi_cdb_length() to scsi_xfer_length(), Hannes Reinecke, 2014/10/29
- [Qemu-devel] [PATCH 06/13] megasas: Fix typo in megasas_dcmd_ld_get_list(), Hannes Reinecke, 2014/10/29
- [Qemu-devel] [PATCH 04/13] megasas: fixup device mapping, Hannes Reinecke, 2014/10/29
- [Qemu-devel] [PATCH 05/13] megasas: add MegaRAID SAS 2108 emulation, Hannes Reinecke, 2014/10/29
- Re: [Qemu-devel] [PATCH 05/13] megasas: add MegaRAID SAS 2108 emulation,
Paolo Bonzini <=
[Qemu-devel] [PATCH 07/13] megasas: Decode register names, Hannes Reinecke, 2014/10/29
[Qemu-devel] [PATCH 09/13] megasas: Ignore duplicate init_firmware commands, Hannes Reinecke, 2014/10/29
[Qemu-devel] [PATCH 08/13] megasas: Clear unit attention on initial reset, Hannes Reinecke, 2014/10/29
[Qemu-devel] [PATCH 02/13] megasas: fixup MFI_DCMD_LD_LIST_QUERY, Hannes Reinecke, 2014/10/29
[Qemu-devel] [PATCH 12/13] megasas: Rework frame queueing algorithm, Hannes Reinecke, 2014/10/29
[Qemu-devel] [PATCH 13/13] megasas: Fixup MSI-X handling, Hannes Reinecke, 2014/10/29
[Qemu-devel] [PATCH 10/13] megasas: Implement DCMD_CLUSTER_RESET_LD, Hannes Reinecke, 2014/10/29