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

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

 



On Fri, Jul 01, 2011 at 11:16:03AM +0200, Alexander Graf wrote:
> 
> 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
> > -
> 

Yes this separates base class (1 byte) from class
word codes.

> 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