Re: [PATCH 3/3] megasas: LSI Megaraid SAS emulation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 01.07.2011, at 09:42, Hannes Reinecke wrote:

> This patch adds an emulation for the LSI Megaraid SAS 8708EM2 HBA.
> 
> Signed-off-by: Hannes Reinecke <hare@xxxxxxx>
> ---
> Makefile.objs           |    1 +
> default-configs/pci.mak |    1 +
> hw/megasas.c            | 1923 +++++++++++++++++++++++++++++++++++++++++++++++
> hw/mfi.h                | 1197 +++++++++++++++++++++++++++++
> hw/pci_ids.h            |    3 +-
> 5 files changed, 3124 insertions(+), 1 deletions(-)
> create mode 100644 hw/megasas.c
> create mode 100644 hw/mfi.h
> 
> diff --git a/Makefile.objs b/Makefile.objs
> index cea15e4..6f5d113 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -258,6 +258,7 @@ hw-obj-$(CONFIG_AHCI) += ide/ich.o
> 
> # SCSI layer
> hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o
> +hw-obj-$(CONFIG_MEGASAS_SCSI_PCI) += megasas.o
> hw-obj-$(CONFIG_ESP) += esp.o
> 
> hw-obj-y += dma-helpers.o sysbus.o isa-bus.o
> diff --git a/default-configs/pci.mak b/default-configs/pci.mak
> index 22bd350..fabb56c 100644
> --- a/default-configs/pci.mak
> +++ b/default-configs/pci.mak
> @@ -9,6 +9,7 @@ CONFIG_EEPRO100_PCI=y
> CONFIG_PCNET_PCI=y
> CONFIG_PCNET_COMMON=y
> CONFIG_LSI_SCSI_PCI=y
> +CONFIG_MEGASAS_SCSI_PCI=y
> CONFIG_RTL8139_PCI=y
> CONFIG_E1000_PCI=y
> CONFIG_IDE_CORE=y
> diff --git a/hw/megasas.c b/hw/megasas.c
> new file mode 100644
> index 0000000..75f9be3
> --- /dev/null
> +++ b/hw/megasas.c
> @@ -0,0 +1,1923 @@
> +/*
> + * QEMU MegaRAID SAS 8708EM2 Host Bus Adapter emulation
> + *
> + * Copyright (c) 2009-2011 Hannes Reinecke, SUSE Labs
> + *
> + * This code is licenced under the LGPL.

Please take a look at the license header of other LGPL code and just copy it :).

> + */
> +
> +#include <time.h>
> +#include <assert.h>

Are you sure you need to manually include those?

> +
> +#include "hw.h"
> +#include "pci.h"
> +#include "dma.h"
> +#include "iov.h"
> +#include "scsi.h"
> +#include "scsi-defs.h"
> +#include "block_int.h"
> +#ifdef __linux__
> +# include <scsi/sg.h>

Is this really necessary? Device code shouldn't be host dependent IMHO. I also haven't found any user of this in the actual code, so it might be as easy as merely removing the include :).

> +#endif
> +
> +#include "mfi.h"
> +
> +#define DEBUG_MEGASAS
> +#undef DEBUG_MEGASAS_REG
> +#undef DEBUG_MEGASAS_QUEUE
> +#undef DEBUG_MEGASAS_MFI
> +#undef DEBUG_MEGASAS_IO
> +#undef DEBUG_MEGASAS_DCMD
> +
> +#ifdef DEBUG_MEGASAS
> +#define DPRINTF(fmt, ...) \
> +do { printf("megasas: " fmt , ## __VA_ARGS__); } while (0)
> +#define BADF(fmt, ...) \
> +do { fprintf(stderr, "megasas: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
> +#ifdef DEBUG_MEGASAS_REG
> +#define DPRINTF_REG DPRINTF
> +#else
> +#define DPRINTF_REG(fmt, ...) do {} while(0)
> +#endif
> +#ifdef DEBUG_MEGASAS_QUEUE
> +#define DPRINTF_QUEUE DPRINTF
> +#else
> +#define DPRINTF_QUEUE(fmt, ...) do {} while(0)
> +#endif
> +#ifdef DEBUG_MEGASAS_MFI
> +#define DPRINTF_MFI DPRINTF
> +#else
> +#define DPRINTF_MFI(fmt, ...) do {} while(0)
> +#endif
> +#ifdef DEBUG_MEGASAS_IO
> +#define DPRINTF_IO DPRINTF
> +#else
> +#define DPRINTF_IO(fmt, ...) do {} while(0)
> +#endif
> +#ifdef DEBUG_MEGASAS_DCMD
> +#define DPRINTF_DCMD DPRINTF
> +#else
> +#define DPRINTF_DCMD(fmt, ...) do {} while(0)
> +#endif
> +#else
> +#define DPRINTF(fmt, ...) do {} while(0)
> +#define DPRINTF_REG DPRINTF
> +#define DPRINTF_QUEUE DPRINTF
> +#define DPRINTF_MFI DPRINTF
> +#define DPRINTF_IO DPRINTF
> +#define DPRINTF_DCMD DPRINTF
> +#define BADF(fmt, ...) \
> +do { fprintf(stderr, "megasas: error: " fmt , ## __VA_ARGS__);} while (0)
> +#endif
> +
> +/* Static definitions */
> +#define MEGASAS_VERSION "1.20"
> +#define MEGASAS_MAX_FRAMES 2048         /* Firmware limit at 65535 */
> +#define MEGASAS_DEFAULT_FRAMES 1000     /* Windows requires this */
> +#define MEGASAS_MAX_SGE 256             /* Firmware limit */
> +#define MEGASAS_DEFAULT_SGE 80
> +#define MEGASAS_MAX_SECTORS 0xFFFF      /* No real limit */
> +#define MEGASAS_MAX_ARRAYS 128
> +
> +const char *mfi_frame_desc[] = {
> +    "MFI init", "LD Read", "LD Write", "LD SCSI", "PD SCSI",
> +    "MFI Doorbell", "MFI Abort", "MFI SMP", "MFI Stop"};
> +
> +struct megasas_cmd_t {
> +    int index;
> +    int context;
> +    int count;
> +
> +    target_phys_addr_t pa;
> +    target_phys_addr_t pa_size;
> +    union mfi_frame *frame;
> +    SCSIRequest *req;
> +    struct iovec *iov;
> +    void *iov_buf;
> +    long iov_cnt;
> +    long iov_size;
> +    long iov_offset;

Why would anything be a long? It's either target_ulong or uintXX_t for device code usually :).

> +    SCSIDevice *sdev;
> +    struct megasas_state_t *state;
> +};
> +
> +typedef struct megasas_state_t {
> +    PCIDevice dev;
> +    int mmio_io_addr;
> +    int io_addr;
> +    int queue_addr;
> +    uint32_t frame_hi;
> +
> +    int fw_state;
> +    uint32_t fw_sge;
> +    uint32_t fw_cmds;
> +    int fw_luns;
> +    int intr_mask;
> +    int doorbell;
> +    int busy;
> +    char *raid_mode_str;
> +    int is_jbod;
> +
> +    int event_count;
> +    int shutdown_event;
> +    int boot_event;
> +
> +    uint64_t reply_queue_pa;
> +    void *reply_queue;
> +    int reply_queue_len;
> +    int reply_queue_index;
> +    uint64_t consumer_pa;
> +    uint64_t producer_pa;
> +
> +    struct megasas_cmd_t frames[MEGASAS_MAX_FRAMES];
> +
> +    SCSIBus bus;
> +} MPTState;
> +
> +#define MEGASAS_INTR_DISABLED_MASK 0xFFFFFFFF
> +
> +#define MEGASAS_INTR_ENABLED(s) (((s)->intr_mask & MEGASAS_INTR_DISABLED_MASK ) != MEGASAS_INTR_DISABLED_MASK)
> +
> +#define megasas_frame_set_cmd_status(f,v)                               \
> +    stb_phys((f) + offsetof(struct mfi_frame_header, cmd_status), v);
> +
> +#define megasas_frame_set_scsi_status(f,v)                              \
> +    stb_phys((f) + offsetof(struct mfi_frame_header, scsi_status), v);
> +
> +#define megasas_frame_get_cmd(f)                                        \
> +    ldub_phys((f) + offsetof(struct mfi_frame_header, frame_cmd))
> +
> +#define megasas_frame_get_context(f)                                    \
> +    ldl_phys(frame_addr + offsetof(struct mfi_frame_header, context));
> +
> +static void megasas_soft_reset(MPTState *s);
> +
> +static int megasas_map_sgl(struct megasas_cmd_t *cmd, int pa_offset)
> +{
> +    int i;
> +    uint16_t flags = le16_to_cpu(cmd->frame->header.flags);
> +    int is_sgl64 = (flags & MFI_FRAME_SGL64) ? 1 : 0;
> +    int is_write = (flags & MFI_FRAME_DIR_WRITE) ? 1 : 0;
> +    int sgl_addr_size = is_sgl64 ? sizeof(uint64_t) : sizeof(uint32_t);
> +    size_t iov_count = 0;
> +
> +    cmd->iov = qemu_malloc(sizeof(struct iovec) * (cmd->frame->header.sge_count + 1));
> +    for (i = 0; i < cmd->frame->header.sge_count; i++) {
> +        target_phys_addr_t pa, iov_pa, iov_size;
> +
> +        pa = cmd->pa + pa_offset;
> +        if (is_sgl64)
> +            iov_pa = ldq_phys(pa);

Could you please send your patch through scripts/checkpatch.pl, so that coding style issues don't hold up the commit process?

[...]

> +
> +static void megasas_xfer_complete(SCSIRequest *req, uint32_t len)
> +{
> +    struct megasas_cmd_t *cmd;
> +    uint8_t *buf;
> +
> +    cmd = req->hba_private;
> +    if (!cmd) {


Is this still necessary with the new pointer infrastructure?

> +        /*
> +	 * Bad. A command has been completed but we couldn't find it.
> +	 * Only safe way out of here is to terminate everything and
> +	 * hope the HBA recovers.
> +	 */
> +        DPRINTF("SCSI request %p not found", req);
> +        return;
> +    }
> +
> +    DPRINTF_IO("%s req %p cmd %p lun %p xfer completed, len %u\n",
> +               mfi_frame_desc[cmd->frame->header.frame_cmd], req, cmd,
> +               cmd->sdev, len);
> +
> +    if (len) {
> +        uint16_t flags = le16_to_cpu(cmd->frame->header.flags);
> +        int is_write = (flags & MFI_FRAME_DIR_WRITE) ? 1 : 0;
> +        size_t bytes;
> +
> +        buf = scsi_req_get_buf(req);
> +        if (is_write) {
> +            DPRINTF_IO("%s req %p cmd %p lun %p write finished, left %u\n",
> +                       mfi_frame_desc[cmd->frame->header.frame_cmd], req,
> +                       cmd, cmd->sdev, len);
> +            bytes = iov_to_buf(cmd->iov, cmd->iov_cnt, buf,
> +                               cmd->iov_offset, len);
> +            if (bytes != len) {
> +                len = bytes;
> +            }
> +            cmd->iov_offset += bytes;
> +        } else {
> +            DPRINTF_IO("%s req %p cmd %p lun %p read finished, len %u\n",
> +                       mfi_frame_desc[cmd->frame->header.frame_cmd], req,
> +                       cmd, cmd->sdev, len);
> +            bytes = iov_from_buf(cmd->iov, cmd->iov_cnt, buf,
> +                                 cmd->iov_offset, len);
> +            if (bytes != len) {
> +                len = bytes;
> +            }
> +            cmd->iov_offset += bytes;
> +        }
> +    }
> +    cmd->iov_size -= len;
> +    scsi_req_continue(req);
> +}
> +
> +static void megasas_command_complete(SCSIRequest *req, uint32_t status)
> +{
> +    struct megasas_cmd_t *cmd;
> +    uint8_t cmd_status = MFI_STAT_OK;
> +
> +    cmd = req->hba_private;
> +    if (!cmd) {

same here

[...]

> diff --git a/hw/pci_ids.h b/hw/pci_ids.h
> index d94578c..796aaf1 100644
> --- a/hw/pci_ids.h
> +++ b/hw/pci_ids.h
> @@ -12,9 +12,9 @@
> 
> #define PCI_BASE_CLASS_STORAGE           0x01
> #define PCI_BASE_CLASS_NETWORK           0x02
> -

I don't think this is intentional, no?

> #define PCI_CLASS_STORAGE_SCSI           0x0100
> #define PCI_CLASS_STORAGE_IDE            0x0101
> +#define PCI_CLASS_STORAGE_RAID           0x0104
> #define PCI_CLASS_STORAGE_SATA           0x0106
> #define PCI_CLASS_STORAGE_OTHER          0x0180
> 
> @@ -47,6 +47,7 @@
> 
> #define PCI_VENDOR_ID_LSI_LOGIC          0x1000
> #define PCI_DEVICE_ID_LSI_53C895A        0x0012
> +#define PCI_DEVICE_ID_LSI_SAS1078        0x0060

Michael, these go to your table :)


Alex

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux