qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] [PATCH] megasas: Update to version 1.01


From: Blue Swirl
Subject: Re: [Qemu-devel] [PATCH] megasas: Update to version 1.01
Date: Thu, 10 Jun 2010 17:13:43 +0000

On Tue, Jun 8, 2010 at 2:15 PM, Hannes Reinecke <address@hidden> wrote:
>
> This patch updates the megasas HBA emulation to version 1.01.
> It fixes the following issues:
>
> - Remove hand-crafted inquiry command
> - Remove bounce-buffer for direct commands
> - Implements qdev properties to set 'max_sge', 'max_cmds'.
> - Implement JBOD mode
> - Improve direct command handling
> - Minor cleanups
>
> Signed-off-by: Hannes Reinecke <address@hidden>
>
> diff --git a/hw/megasas.c b/hw/megasas.c
> index 250c3fb..19569a8 100644
> --- a/hw/megasas.c
> +++ b/hw/megasas.c
> @@ -40,38 +40,17 @@ do { fprintf(stderr, "megasas: error: " fmt , ## 
> __VA_ARGS__);} while (0)
>  #endif
>
>  /* Static definitions */
> -#define MEGASAS_MAX_FRAMES 1000
> -#define MEGASAS_MAX_SGE 8
> -#define MEGASAS_MAX_LUNS 128
> -
> -/* Frame definitions */
> -#define MEGASAS_FRAME_CMD_OFFSET               0x00
> -#define MEGASAS_FRAME_SENSE_LEN_OFFSET         0x01
> -#define MEGASAS_FRAME_CMD_STATUS_OFFSET        0x02
> -#define MEGASAS_FRAME_SCSI_STATUS_OFFSET       0x03
> -#define MEGASAS_FRAME_TARGET_ID_OFFSET         0x04
> -#define MEGASAS_FRAME_LUN_ID_OFFSET            0x05
> -#define MEGASAS_FRAME_CDB_LEN_OFFSET           0x06
> -#define MEGASAS_FRAME_SGE_COUNT_OFFSET         0x07
> -#define MEGASAS_FRAME_CONTEXT_OFFSET           0x08
> -#define MEGASAS_FRAME_FLAGS_OFFSET             0x10
> -#define MEGASAS_FRAME_XFER_LEN_OFFSET          0x14
> -
> -#define MEGASAS_DCMD_SGL_OFFSET                        0x28
> -
> -#define MEGASAS_PTHRU_SGL_OFFSET               0x30
> -
> -#define MEGASAS_IO_SGL_OFFSET                  0x28
> +#define MEGASAS_VERSION "1.01"
> +#define MEGASAS_MAX_FRAMES 2048                /* Firmware limit at 65535 */
> +#define MEGASAS_DEFAULT_FRAMES 1000    /* Windows requires this */
> +#define MEGASAS_MAX_SGE 255            /* Firmware limit */
> +#define MEGASAS_DEFAULT_SGE 80
> +#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_lun_t {
> -    SCSIDevice *sdev;
> -    BlockDriverAIOCB *aiocb;
> -};
> -
>  struct megasas_cmd_t {
>     int index;
>
> @@ -81,8 +60,8 @@ struct megasas_cmd_t {
>     QEMUSGList sg;
>     void *iov_buf;
>     long iov_size;
> +    SCSIDevice *sdev;
>     struct megasas_state_t *state;
> -    struct megasas_lun_t *lun;
>  };
>
>  typedef struct megasas_state_t {
> @@ -93,12 +72,14 @@ typedef struct megasas_state_t {
>     uint32_t frame_hi;
>
>     int fw_state;
> -    int fw_sge;
> -    int fw_cmds;
> +    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;
> @@ -113,8 +94,6 @@ typedef struct megasas_state_t {
>
>     struct megasas_cmd_t frames[MEGASAS_MAX_FRAMES];
>
> -    struct megasas_lun_t luns[MEGASAS_MAX_LUNS];
> -
>     SCSIBus bus;
>  } MPTState;
>
> @@ -123,13 +102,19 @@ typedef struct megasas_state_t {
>  #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) + MEGASAS_FRAME_CMD_STATUS_OFFSET, v);
> +    stb_phys((f) + offsetof(struct mfi_frame_header, cmd_status), v);
>
>  #define megasas_frame_set_sense_len(f,v)               \
> -    stb_phys((f) + MEGASAS_FRAME_SENSE_LEN_OFFSET, v);
> +    stb_phys((f) + offsetof(struct mfi_frame_header, sense_len), v);
>
>  #define megasas_frame_set_scsi_status(f,v)             \
> -    stb_phys((f) + MEGASAS_FRAME_SCSI_STATUS_OFFSET, 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);
>
> @@ -181,37 +166,20 @@ static void megasas_build_sense(struct megasas_cmd_t 
> *cmd, SCSISense sense)
>     qemu_free(sense_ptr);
>  }
>
> -static int megasas_get_inq(SCSIDevice *sdev, int pg, uint8_t *buf, int 
> buflen)
> -{
> -    SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, sdev->qdev.parent_bus);
> -
> -    memset(buf, 0, buflen);
> -    if (pg == 0) {
> -       memcpy(&buf[16], "QEMU HARDDISK  ", 16);
> -       memcpy(&buf[8], "QEMU   ", 8);
> -       memcpy(&buf[32], QEMU_VERSION, 4);
> -       /* Identify device as SCSI-3 rev 1 */
> -       buf[2] = 3;
> -       buf[3] = 2; /* Format 2 */
> -       buf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */
> -       /* Sync data transfer and TCQ.  */
> -       buf[7] = 0x10 | (bus->tcq ? 0x02 : 0);
> -    } else if (pg == 0x83) {
> -       int id_len = strlen(bdrv_get_device_name(sdev->conf.dinfo->bdrv));
> -
> -       buflen = 0;
> -       buf[buflen++] = 0;
> -       buf[buflen++] = pg;
> -       buf[buflen++] = 0x00;
> -       buf[buflen++] = 3 + id_len;
> -       buf[buflen++] = 0x2; // ASCII
> -       buf[buflen++] = 0;   // not officially assigned
> -       buf[buflen++] = 0;   // reserved
> -       buf[buflen++] = id_len; // length of data following
> -       memcpy(buf + buflen, bdrv_get_device_name(sdev->conf.dinfo->bdrv), 
> id_len);
> -       buflen += id_len;
> +static int megasas_setup_inquiry(SCSIRequest *req, int pg,
> +                                uint8_t *buf, int len)
> +{
> +    uint8_t cdb[6] = { INQUIRY, 0, 0, 0, 0, 0};
> +
> +    if (pg > 0) {
> +       cdb[1] = 0x1;
> +       cdb[2] = pg;
>     }
> -    return buflen;
> +    cdb[3] = (len >> 8) & 0xff;
> +    cdb[4] = (len & 0xff);
> +    scsi_req_parse(req, cdb);
> +    scsi_req_buf(req, buf);
> +    return len;
>  }
>
>  /*
> @@ -234,6 +202,16 @@ static uint64_t megasas_fw_time(void)
>     return bcd_time;
>  }
>
> +static uint64_t megasas_gen_sas_addr(unsigned long id)
> +{
> +    uint64_t addr;
> +
> +    addr = ((uint64_t)0x5001a4a << 36);

With 0x5001a4aULL the cast could be avoided.

> +    addr |= ((uint64_t)id & 0xfffffffff);

This cast could be avoided by making id uint64_t.

> +
> +    return addr;
> +}
> +
>  /*
>  * Frame handling
>  */
> @@ -254,7 +232,7 @@ static inline struct megasas_cmd_t 
> *megasas_lookup_frame(MPTState *s,
>
>     index = s->reply_queue_index;
>
> -    while (num < MEGASAS_MAX_FRAMES) {
> +    while (num < s->fw_cmds) {
>        if (s->frames[index].pa && s->frames[index].pa == frame) {
>            cmd = &s->frames[index];
>            break;
> @@ -282,7 +260,7 @@ static inline struct megasas_cmd_t 
> *megasas_next_frame(MPTState *s,
>     }
>     index = s->reply_queue_index;
>     num = 0;
> -    while (num < MEGASAS_MAX_FRAMES) {
> +    while (num < s->fw_cmds) {
>        if (!s->frames[index].pa) {
>            cmd = &s->frames[index];
>            break;
> @@ -377,7 +355,7 @@ static void megasas_dump_frame(struct megasas_cmd_t *cmd)
>
>  static int megasas_finish_command(MPTState *s, struct megasas_cmd_t *cmd)
>  {
> -    int context;
> +    int context = -1;
>
>     if (!cmd) {
>  #ifdef DEBUG_MEGASAS_QUEUE
> @@ -386,8 +364,8 @@ static int megasas_finish_command(MPTState *s, struct 
> megasas_cmd_t *cmd)
>        s->event_count++;
>        return -1;
>     }
> -    context = cmd->frame->header.context;
> -    cmd->lun = NULL;
> +    if (cmd->frame)
> +       context = cmd->frame->header.context;
>
>     return context;
>  }
> @@ -483,14 +461,14 @@ static int megasas_finish_dcmd(struct megasas_cmd_t 
> *cmd, uint32_t size)
>     }
>     cpu_physical_memory_unmap(cmd->iov_buf, cmd->iov_size, 1, size);
>     if (cmd->iov_size > size)
> -       stl_phys(cmd->pa + MEGASAS_DCMD_SGL_OFFSET + sgl_addr_size, size);
> +       stl_phys(cmd->pa + offsetof(struct mfi_dcmd_frame,sgl) + 
> sgl_addr_size, size);
>
>     return size;
>  }
>
>  static int megasas_ctrl_get_info(MPTState *s, struct megasas_cmd_t *cmd)
>  {
> -    struct mfi_ctrl_info info;
> +    struct mfi_ctrl_info *info = cmd->iov_buf;
>     int n, num_ld_disks = 0;
>
>     for (n = 0; n < s->fw_luns; n++) {
> @@ -498,134 +476,189 @@ static int megasas_ctrl_get_info(MPTState *s, struct 
> megasas_cmd_t *cmd)
>            num_ld_disks++;
>     }
>
> -    memset(&info, 0x0, sizeof(info));
> -    info.pci.vendor = PCI_VENDOR_ID_LSI_LOGIC;
> -    info.pci.device = PCI_DEVICE_ID_LSI_SAS1078;
> -    info.pci.subvendor = PCI_VENDOR_ID_LSI_LOGIC;
> -    info.pci.subdevice = 0x1013;
> -
> -    info.host.type = MFI_INFO_HOST_PCIX;
> -    info.device.type = MFI_INFO_DEV_SAS3G;
> -    info.device.port_count = 2;
> -
> -    memcpy(info.product_name,"MegaRAID SAS 8708EM2", 20);
> -    sprintf(info.package_version,"%s-QEMU", QEMU_VERSION);
> -    info.current_fw_time = megasas_fw_time();
> -    info.max_arms = 32;
> -    info.max_spans = 8;
> -    info.max_arrays = MEGASAS_MAX_LUNS;
> -    info.max_lds = s->fw_luns;
> -    info.max_cmds = s->fw_cmds;
> -    info.max_sg_elements = s->fw_sge;
> -    info.max_request_size = 8192;
> -    info.lds_present = num_ld_disks;
> -    info.pd_present = num_ld_disks + 1;
> -    info.pd_disks_present = num_ld_disks;
> -    info.memory_size = 512;
> -    info.nvram_size = 32;
> -    info.flash_size = 16;
> -    info.raid_levels = MFI_INFO_RAID_0;
> -    info.adapter_ops = MFI_INFO_AOPS_RBLD_RATE |
> +    memset(cmd->iov_buf, 0x0, cmd->iov_size);
> +    if (cmd->iov_size != sizeof(struct mfi_ctrl_info)) {
> +#ifdef DEBUG_MEGASAS_DCMD
> +       DPRINTF("Ctrl Get Info: invalid xfer_len %ld\n", cmd->iov_size);
> +#endif

Please avoid the #ifdef/#endif with a new macro DPRINTF_DCMD() if necessary.

> +       return MFI_STAT_INVALID_PARAMETER;
> +    }
> +
> +#ifdef DEBUG_MEGASAS_DCMD
> +    DPRINTF("MFI DCMD get controller info\n");
> +#endif
> +    info->pci.vendor = PCI_VENDOR_ID_LSI_LOGIC;
> +    info->pci.device = PCI_DEVICE_ID_LSI_SAS1078;
> +    info->pci.subvendor = PCI_VENDOR_ID_LSI_LOGIC;
> +    info->pci.subdevice = 0x1013;
> +
> +    info->host.type = MFI_INFO_HOST_PCIX;
> +    info->device.type = MFI_INFO_DEV_SAS3G;
> +    info->device.port_count = 2;
> +    info->device.port_addr[0] = megasas_gen_sas_addr((unsigned long)s);
> +
> +    memcpy(info->product_name,"MegaRAID SAS 8708EM2", 20);
> +    sprintf(info->serial_number,"QEMU%08lx",(unsigned long)s & 0xFFFFFFFF);

Please use snprintf(), OpenBSD linker issues warnings for all uses of sprintf().

> +    sprintf(info->package_version,"%s-QEMU", QEMU_VERSION);
> +    strcpy(info->image_component[0].name, "APP");

Same problem with strcpy(), please use pstrcpy(), snprintf() or memcpy().

> +    strcpy(info->image_component[0].version, MEGASAS_VERSION "-QEMU");
> +    strcpy(info->image_component[0].build_date, __DATE__);
> +    strcpy(info->image_component[0].build_time, __TIME__);
> +    info->image_component_count = 1;
> +    info->current_fw_time = megasas_fw_time();
> +    info->max_arms = 32;
> +    info->max_spans = 8;
> +    info->max_arrays = MEGASAS_MAX_ARRAYS;
> +    info->max_lds = s->fw_luns;
> +    info->max_cmds = s->fw_cmds;
> +    info->max_sg_elements = s->fw_sge;
> +    info->max_request_size = 8192;
> +    info->lds_present = num_ld_disks;
> +    info->pd_present = num_ld_disks + 1;
> +    info->pd_disks_present = num_ld_disks;
> +    info->hw_present = MFI_INFO_HW_NVRAM | MFI_INFO_HW_MEM | 
> MFI_INFO_HW_FLASH;
> +    info->memory_size = 512;
> +    info->nvram_size = 32;
> +    info->flash_size = 16;
> +    info->raid_levels = MFI_INFO_RAID_0;
> +    info->adapter_ops = MFI_INFO_AOPS_RBLD_RATE |
>         MFI_INFO_AOPS_SELF_DIAGNOSTIC |
>         MFI_INFO_AOPS_MIXED_ARRAY;
> -    info.ld_ops = MFI_INFO_LDOPS_DISK_CACHE_POLICY |
> +    info->ld_ops = MFI_INFO_LDOPS_DISK_CACHE_POLICY |
>         MFI_INFO_LDOPS_ACCESS_POLICY |
>         MFI_INFO_LDOPS_IO_POLICY |
>         MFI_INFO_LDOPS_WRITE_POLICY |
>         MFI_INFO_LDOPS_READ_POLICY;
> -    info.stripe_sz_ops.min = 4;
> -    info.stripe_sz_ops.max = 0xf;
> -    info.properties.pred_fail_poll_interval = 300;
> -    info.properties.intr_throttle_cnt = 16;
> -    info.pd_ops = 0x3;
> -    info.pd_mix_support = MFI_INFO_PDMIX_SAS | MFI_INFO_PDMIX_LD;
> -    memcpy(cmd->iov_buf, (uint8_t *)&info, sizeof(info));
> +    info->max_strips_per_io = 42;
> +    info->stripe_sz_ops.min = 4;
> +    info->stripe_sz_ops.max = 0xf;
> +    info->properties.pred_fail_poll_interval = 300;
> +    info->properties.intr_throttle_cnt = 16;
> +    info->properties.intr_throttle_timeout = 50;
> +    info->properties.rebuild_rate = 30;
> +    info->properties.patrol_read_rate = 30;
> +    info->properties.bgi_rate = 30;
> +    info->properties.cc_rate = 30;
> +    info->properties.recon_rate = 30;
> +    info->properties.cache_flush_interval = 4;
> +    info->properties.spinup_drv_cnt = 2;
> +    info->properties.spinup_delay = 6;
> +    info->properties.ecc_bucket_size = 15;
> +    info->properties.ecc_bucket_leak_rate = 1440;
> +    info->properties.expose_encl_devices = 1;
> +    info->pd_ops = MFI_INFO_PDOPS_FORCE_ONLINE | 
> MFI_INFO_PDOPS_FORCE_OFFLINE;
> +    info->pd_mix_support = MFI_INFO_PDMIX_SAS | MFI_INFO_PDMIX_SATA | 
> MFI_INFO_PDMIX_LD;
>
> -    return sizeof(info);
> +    return MFI_STAT_OK;
>  }
>
>  static int megasas_mfc_get_defaults(MPTState *s, struct megasas_cmd_t *cmd)
>  {
> -    struct mfi_defaults info;
> +    struct mfi_defaults *info = cmd->iov_buf;
>
> -    memset(&info, 0x0, sizeof(info));
> +    memset(cmd->iov_buf, 0x0, cmd->iov_size);
> +    if (cmd->iov_size != sizeof(struct mfi_defaults)) {
> +#ifdef DEBUG_MEGASAS_DCMD
> +       DPRINTF("MFC Get defaults: invalid xfer_len %ld\n", cmd->iov_size);
> +#endif
> +       return MFI_STAT_INVALID_PARAMETER;
> +    }
>
> -    info.stripe_size = 8;
> -    info.flush_time = 4;
> -    info.background_rate = 30;
> -    info.allow_mix_in_enclosure = 1;
> -    info.allow_mix_in_ld = 1;
> -    info.direct_pd_mapping = 1;
> -    info.bios_enumerate_lds = 1;
> -    info.disable_ctrl_r = 1;
> -    memcpy(cmd->iov_buf, (uint8_t *)&info, sizeof(info));
> +    info->stripe_size = 8;
> +    info->flush_time = 4;
> +    info->background_rate = 30;
> +    info->allow_mix_in_enclosure = 1;
> +    info->allow_mix_in_ld = 1;
> +    info->direct_pd_mapping = 1;
> +    info->bios_enumerate_lds = 1;
> +    info->disable_ctrl_r = 1;
> +    info->expose_enclosure_devices = 1;
> +    info->disable_preboot_cli = 1;
> +    info->cluster_disable = 1;
>
> -    return sizeof(info);
> +    return MFI_STAT_OK;
>  }
>
> -static int megasas_dcmd_get_bios_info(MPTState *d, struct megasas_cmd_t *cmd)
> +static int megasas_dcmd_get_bios_info(MPTState *s, struct megasas_cmd_t *cmd)
>  {
> -    struct mfi_bios_data info;
> +    struct mfi_bios_data *info = cmd->iov_buf;
>
> -    memset(&info, 0x0, sizeof(info));
> -    info.continue_on_error = 1;
> -    memcpy(cmd->iov_buf, (uint8_t *)&info, sizeof(info));
> +    memset(cmd->iov_buf, 0x0, cmd->iov_size);
> +    if (cmd->iov_size != sizeof(struct mfi_bios_data)) {
> +#ifdef DEBUG_MEGASAS_DCMD
> +       DPRINTF("Get BIOS info: invalid xfer_len %ld\n", cmd->iov_size);
> +#endif
> +       return MFI_STAT_INVALID_PARAMETER;
> +    }
> +    info->continue_on_error = 1;
>
> -return sizeof(info);
> +    return MFI_STAT_OK;
>  }
>
> -static int megasas_dcmd_get_fw_time(MPTState *d, struct megasas_cmd_t *cmd)
> +static int megasas_dcmd_get_fw_time(MPTState *s, struct megasas_cmd_t *cmd)
>  {
>     uint64_t fw_time;
>
>     fw_time = megasas_fw_time();
> -    memcpy(cmd->iov_buf, (uint8_t *)&fw_time, sizeof(fw_time));
>
> -    return sizeof(fw_time);
> +    memcpy(cmd->iov_buf, &fw_time, sizeof(fw_time));
> +    return MFI_STAT_OK;
>  }
>
> -static int megasas_dcmd_set_fw_time(MPTState *d, struct megasas_cmd_t *cmd)
> +static int megasas_dcmd_set_fw_time(MPTState *s, struct megasas_cmd_t *cmd)
>  {
>     uint64_t fw_time;
>
> +    memset(cmd->iov_buf, 0x0, cmd->iov_size);
>     memcpy(&fw_time, cmd->frame->dcmd.mbox, sizeof(fw_time));
>     DPRINTF("set fw time %lx\n", fw_time);
>     fw_time = megasas_fw_time();
> -    memcpy(cmd->iov_buf, (uint8_t *)&fw_time, sizeof(fw_time));
> -
> -    return sizeof(fw_time);
> +    memcpy(cmd->iov_buf, &fw_time, sizeof(fw_time));
> +    return MFI_STAT_OK;
>  }
>
> -
>  static int megasas_event_info(MPTState *s, struct megasas_cmd_t *cmd)
>  {
> -    struct mfi_evt_log_state info;
> +    struct mfi_evt_log_state *info = cmd->iov_buf;
>
> -    memset(&info, 0, sizeof(info));
> -    info.newest_seq_num = s->event_count;
> -    info.shutdown_seq_num = s->shutdown_event;
> -    info.boot_seq_num = s->boot_event;
> +    memset(info, 0, cmd->iov_size);
> +    info->newest_seq_num = s->event_count;
> +    info->shutdown_seq_num = s->shutdown_event;
> +    info->boot_seq_num = s->boot_event;
>
> -    memcpy(cmd->iov_buf, (uint8_t *)&info, sizeof(info));
> -
> -    return sizeof(info);
> +    return MFI_STAT_OK;
>  }
>
>  static int megasas_dcmd_pd_get_list(MPTState *s, struct megasas_cmd_t *cmd)
>  {
> -    struct mfi_pd_list info;
> -    uint32_t offset, num_pd_disks = 0;
> +    struct mfi_pd_list *info = cmd->iov_buf;
> +    uint32_t offset, num_pd_disks = 0, max_luns;
>     uint16_t dev_id;
>
> -    memset(&info, 0x0, sizeof(info));
> +    memset(cmd->iov_buf, 0, cmd->iov_size);
>     offset = 8;
> -    for (dev_id = 0; dev_id < s->fw_luns; dev_id++) {
> +    if (cmd->iov_size < (offset + sizeof(struct mfi_pd_address))) {
> +#ifdef DEBUG_MEGASAS_DCMD
> +       DPRINTF("PD get list: invalid xfer_len %ld\n", cmd->iov_size);
> +#endif
> +       return MFI_STAT_INVALID_PARAMETER;
> +    }
> +
> +    max_luns = (cmd->iov_size - offset) / sizeof(struct mfi_pd_address);
> +    if (max_luns > s->fw_luns)
> +       max_luns = s->fw_luns;
> +#ifdef DEBUG_MEGASAS_DCMD
> +    DPRINTF("PD get list: returning info for %d PDs\n", max_luns);
> +#endif
> +
> +    for (dev_id = 0; dev_id < max_luns; dev_id++) {
>        SCSIDevice *sdev;
>
>        sdev = s->bus.devs[dev_id];
>        if (sdev) {
> -           info.addr[num_pd_disks].device_id = dev_id;
> -           info.addr[num_pd_disks].encl_device_id = dev_id;
> +           info->addr[num_pd_disks].device_id = dev_id;
> +           info->addr[num_pd_disks].encl_device_id = dev_id;
> +           info->addr[num_pd_disks].sas_addr[0] = 
> megasas_gen_sas_addr((unsigned long)sdev);
>            num_pd_disks ++;
>            offset += sizeof(struct mfi_pd_address);
>        }
> @@ -634,19 +667,87 @@ static int megasas_dcmd_pd_get_list(MPTState *s, struct 
> megasas_cmd_t *cmd)
>     DPRINTF("PD get list: %d PDs, size %d\n", num_pd_disks, offset);
>  #endif
>
> -    info.size = offset;
> -    info.count = num_pd_disks;
> -    memcpy(cmd->iov_buf, (uint8_t *)&info, offset);
> +    info->size = offset;
> +    info->count = num_pd_disks;
>
> -    return offset;
> +    return MFI_STAT_OK;
> +}
> +
> +static int megasas_dcmd_pd_list_query(MPTState *s, struct megasas_cmd_t *cmd)
> +{
> +    uint16_t flags;
> +
> +    /* mbox0 contains flags */
> +    flags = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
> +
> +#ifdef DEBUG_MEGASAS_DCMD
> +    DPRINTF("PD query list: flags %x\n", flags);
> +#endif
> +
> +    if (flags == MR_PD_QUERY_TYPE_ALL || s->is_jbod)
> +       return megasas_dcmd_pd_get_list(s, cmd);
> +
> +    return MFI_STAT_OK;
> +}
> +
> +static int megasas_pd_get_info_submit(SCSIDevice * sdev, int lun,
> +                                     struct megasas_cmd_t *cmd)
> +{
> +    struct mfi_pd_info * info = cmd->iov_buf;
> +    SCSIRequest *req;
> +
> +    if (info->inquiry_data[4] == 0) {
> +       /* Additional length is zero, resubmit */
> +       req = scsi_req_get(sdev, (uint32_t) -1, lun);
> +       if (!req)
> +           return MFI_STAT_FLASH_ALLOC_FAIL;
> +#ifdef DEBUG_MEGASAS_DCMD
> +       DPRINTF("PD get info submit std inquiry to dev %d\n", lun);
> +#endif
> +       req->hba_private = cmd;
> +       megasas_setup_inquiry(req, 0, info->inquiry_data,
> +                             sizeof(info->inquiry_data));
> +       return MFI_STAT_INVALID_STATUS;
> +    } else if (info->vpd_page83[3] == 0) {
> +       /* Additional length is zero, resubmit */
> +       req = scsi_req_get(sdev, (uint32_t) -1, lun);
> +       if (!req)
> +           return MFI_STAT_FLASH_ALLOC_FAIL;
> +#ifdef DEBUG_MEGASAS_DCMD
> +       DPRINTF("PD get info submit vpd inquiry to dev %d\n", lun);
> +#endif
> +       req->hba_private = cmd;
> +       megasas_setup_inquiry(req, 0x83,(uint8_t *)info->vpd_page83,
> +                             sizeof(info->vpd_page83));
> +       return MFI_STAT_INVALID_STATUS;
> +    }
> +
> +    /* Finished, set FW state */
> +    if (cmd->state->is_jbod)
> +       info->fw_state = MFI_PD_STATE_SYSTEM;
> +    else
> +       info->fw_state = MFI_PD_STATE_ONLINE;
> +#ifdef DEBUG_MEGASAS_DCMD
> +    DPRINTF("PD get info set state for dev %d to %x\n", lun, info->fw_state);
> +#endif
> +    return MFI_STAT_OK;
>  }
>
>  static int megasas_dcmd_pd_get_info(MPTState *s, struct megasas_cmd_t *cmd)
>  {
> -    struct mfi_pd_info info;
> +    struct mfi_pd_info *info = cmd->iov_buf;
>     uint64_t pd_size;
>     uint16_t pd_id;
>     SCSIDevice *sdev = NULL;
> +    int retval = MFI_STAT_OK;
> +
> +    memset(cmd->iov_buf, 0, cmd->iov_size);
> +    if (cmd->iov_size != sizeof(struct mfi_pd_info)) {
> +#ifdef DEBUG_MEGASAS_DCMD
> +       DPRINTF("PD get info: invalid xfer_len %ld\n", cmd->iov_size);
> +#endif
> +       return MFI_STAT_INVALID_PARAMETER;
> +    }
>
>     /* mbox0 has the ID */
>     pd_id = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
> @@ -655,64 +756,106 @@ static int megasas_dcmd_pd_get_info(MPTState *s, 
> struct megasas_cmd_t *cmd)
>     DPRINTF("PD get info for dev %d\n", pd_id);
>  #endif
>     sdev = s->bus.devs[pd_id];
> -    memset((uint8_t *)&info, 0x0, sizeof(info));
> -    info.ref.v.device_id = pd_id;
> +    info->ref.v.device_id = pd_id;
>
>     if (sdev) {
> -       /* Submit inquiry */
> -       megasas_get_inq(sdev, 0, (uint8_t *)&info.inquiry_data,
> -                       sizeof(info.inquiry_data));
> -       megasas_get_inq(sdev, 0x83, (uint8_t *)&info.vpd_page83,
> -                       sizeof(info.vpd_page83));
> -       info.fw_state = 0;
> -       info.state.ddf.v.pd_type.in_vd = 1;
> -       info.state.ddf.v.pd_type.intf = 0x2;
> +       info->state.ddf.v.pd_type.in_vd = 1;
> +       info->state.ddf.v.pd_type.intf = 0x2;
>        bdrv_get_geometry(sdev->conf.dinfo->bdrv, &pd_size);
> -       info.raw_size = pd_size;
> -       info.non_coerced_size = pd_size;
> -       info.coerced_size = pd_size;
> +       info->raw_size = pd_size;
> +       info->non_coerced_size = pd_size;
> +       info->coerced_size = pd_size;
> +       info->fw_state = MFI_PD_STATE_OFFLINE;
> +       info->path_info.count = 1;
> +       info->path_info.sas_addr[0] = megasas_gen_sas_addr((unsigned 
> long)sdev);
> +       /* Submit inquiry */
> +       retval = megasas_pd_get_info_submit(cmd->sdev, pd_id, cmd);
>     }
> -    memcpy(cmd->iov_buf, (uint8_t *)&info, sizeof(info));
>
> -    return sizeof(info);
> +    return retval;
>  }
>
>  static int megasas_dcmd_ld_get_list(MPTState *s, struct megasas_cmd_t *cmd)
>  {
> -    struct mfi_ld_list info;
> -    uint32_t num_ld_disks = 0;
> +    struct mfi_ld_list *info = cmd->iov_buf;
> +    uint32_t num_ld_disks = 0, max_ld_disks = s->fw_luns;
>     uint64_t ld_size;
>     uint8_t n;
>     int offset;
>
> -    memset(&info, 0x0, sizeof(info));
> -    offset = 8;
> -    for (n = 0; n < s->fw_luns; n++) {
> +    memset(cmd->iov_buf, 0, cmd->iov_size);
> +    if (cmd->iov_size != sizeof(struct mfi_ld_list)) {
> +#ifdef DEBUG_MEGASAS_DCMD
> +       DPRINTF("LD get list: invalid xfer_len %ld\n", cmd->iov_size);
> +#endif
> +       return MFI_STAT_INVALID_PARAMETER;
> +    }
> +
> +    if (s->is_jbod)
> +       max_ld_disks = 0;
> +
> +#ifdef DEBUG_MEGASAS_DCMD
> +    DPRINTF("LD get list: returning info for %d LDs\n", max_ld_disks);
> +#endif
> +    for (n = 0; n < max_ld_disks; n++) {
>        SCSIDevice *sdev;
>
>        sdev = s->bus.devs[n];
>        if (sdev) {
>            bdrv_get_geometry(sdev->conf.dinfo->bdrv, &ld_size);
>            ld_size *= 512;
> -           info.ld_list[num_ld_disks].ld.v.target_id = n;
> -           info.ld_list[num_ld_disks].state = MFI_LD_STATE_OPTIMAL;
> -           info.ld_list[num_ld_disks].size = ld_size;
> +           info->ld_list[num_ld_disks].ld.v.target_id = n;
> +           info->ld_list[num_ld_disks].state = MFI_LD_STATE_OPTIMAL;
> +           info->ld_list[num_ld_disks].size = ld_size;
>            num_ld_disks ++;
>            offset += 18;
>        }
>     }
> -    info.ld_count = num_ld_disks;
> -    memcpy(cmd->iov_buf, (uint8_t *)&info, offset);
> +    info->ld_count = num_ld_disks;
> +#ifdef DEBUG_MEGASAS_DCMD
> +    DPRINTF("LD get list: found %d LDs\n", num_ld_disks);
> +#endif
> +
> +    return MFI_STAT_OK;
> +}
> +
> +static int megasas_ld_get_info_submit(SCSIDevice * sdev, int lun,
> +                                     struct megasas_cmd_t *cmd)
> +{
> +    struct mfi_ld_info * info = cmd->iov_buf;
> +    SCSIRequest *req;
>
> -    return offset;
> +    if (info->vpd_page83[3] == 0) {
> +       req = scsi_req_get(sdev, (uint32_t) -1, lun);
> +       if (!req)

This would be against CODING_STYLE but nobody seems to care.

> +           return MFI_STAT_FLASH_ALLOC_FAIL;
> +#ifdef DEBUG_MEGASAS_DCMD
> +       DPRINTF("LD get info submit vpd inquiry to dev %d\n", lun);
> +#endif
> +       req->hba_private = cmd;
> +       megasas_setup_inquiry(req, 0x83,(uint8_t *)info->vpd_page83,
> +                             sizeof(info->vpd_page83));
> +       return MFI_STAT_INVALID_STATUS;
> +    }
> +    info->ld_config.params.state = MFI_LD_STATE_OPTIMAL;
> +    return MFI_STAT_OK;
>  }
>
>  static int megasas_dcmd_ld_get_info(MPTState *s, struct megasas_cmd_t *cmd)
>  {
> -    struct mfi_ld_info info;
> +    struct mfi_ld_info *info = cmd->iov_buf;
>     uint64_t ld_size;
>     uint16_t ld_id;
>     SCSIDevice *sdev = NULL;
> +    int retval = MFI_STAT_OK;
> +
> +    memset(cmd->iov_buf, 0, cmd->iov_size);
> +    if (cmd->iov_size != sizeof(struct mfi_ld_info)) {
> +#ifdef DEBUG_MEGASAS_DCMD
> +       DPRINTF("LD get info: invalid xfer_len %ld\n", cmd->iov_size);
> +#endif
> +       return MFI_STAT_INVALID_PARAMETER;
> +    }
>
>     /* mbox0 has the ID */
>     ld_id = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
> @@ -721,51 +864,71 @@ static int megasas_dcmd_ld_get_info(MPTState *s, struct 
> megasas_cmd_t *cmd)
>     DPRINTF("LD get info for dev %d\n", ld_id);
>  #endif
>     sdev = s->bus.devs[ld_id];
> -    memset((void *)&info, 0x0, sizeof(info));
> -    info.ld_config.properties.ld.v.target_id = ld_id;
> +    info->ld_config.properties.ld.v.target_id = ld_id;
>
>     if (sdev) {
> -       memcpy(&info.ld_config.properties.name, "QEMU HARDDISK  ", 16);
> -       info.ld_config.params.stripe_size = 64;
> -       info.ld_config.params.num_drives = 1;
> -       info.ld_config.params.state = MFI_LD_STATE_OPTIMAL;
> -       info.ld_config.params.is_consistent = 1;
> +       info->ld_config.params.stripe_size = 64;
> +       info->ld_config.params.num_drives = 1;
> +       info->ld_config.params.state = MFI_LD_STATE_OFFLINE;
> +       info->ld_config.params.is_consistent = 1;
>        bdrv_get_geometry(sdev->conf.dinfo->bdrv, &ld_size);
> -       info.size = ld_size;
> -       megasas_get_inq(sdev, 0x83, (uint8_t *)&info.vpd_page83,
> -            sizeof(info.vpd_page83));
> +       info->size = ld_size;
> +       retval = megasas_ld_get_info_submit(cmd->sdev, ld_id, cmd);
>     }
> -    memcpy(cmd->iov_buf, (uint8_t *)&info, sizeof(info));
>
> -    return sizeof(info);
> +    return retval;
>  }
>
>  static int megasas_dcmd_get_properties(MPTState *s, struct megasas_cmd_t 
> *cmd)
>  {
> -    struct mfi_ctrl_props info;
> +    struct mfi_ctrl_props *info = cmd->iov_buf;
>
> -#ifdef DEBUG_MEGASAS_MFI
> +    if (cmd->iov_size != sizeof(struct mfi_ctrl_props)) {
> +#ifdef DEBUG_MEGASAS_DCMD
> +       DPRINTF("DCMD get properties: invalid xfer_len %ld\n", cmd->iov_size);
> +#endif
> +       memset(cmd->iov_buf, 0, cmd->iov_size);
> +       return MFI_STAT_INVALID_PARAMETER;
> +    }
> +
> +#ifdef DEBUG_MEGASAS_DCMD
>     DPRINTF("DCMD get properties: xfer_len %d sge_count %d\n",
>            cmd->frame->header.data_len, cmd->frame->header.sge_count);
>  #endif
> -    info.pred_fail_poll_interval = 300;
> -    info.intr_throttle_cnt = 16;
> -    info.intr_throttle_timeout = 50;
> -    info.rebuild_rate = 30;
> -    info.patrol_read_rate = 30;
> -    info.bgi_rate = 30;
> -    info.cc_rate = 30;
> -    info.recon_rate = 30;
> -    info.cache_flush_interval = 4;
> -    info.spinup_drv_cnt = 2;
> -    info.spinup_delay = 6;
> -    info.ecc_bucket_size = 15;
> -    info.ecc_bucket_leak_rate = 1440;
> -    info.expose_encl_devices = 1;
> -
> -    memcpy(cmd->iov_buf, (uint8_t *)&info, sizeof(info));
> -
> -    return sizeof(info);
> +    info->pred_fail_poll_interval = 300;
> +    info->intr_throttle_cnt = 16;
> +    info->intr_throttle_timeout = 50;
> +    info->rebuild_rate = 30;
> +    info->patrol_read_rate = 30;
> +    info->bgi_rate = 30;
> +    info->cc_rate = 30;
> +    info->recon_rate = 30;
> +    info->cache_flush_interval = 4;
> +    info->spinup_drv_cnt = 2;
> +    info->spinup_delay = 6;
> +    info->ecc_bucket_size = 15;
> +    info->ecc_bucket_leak_rate = 1440;
> +    info->expose_encl_devices = 1;
> +
> +    return MFI_STAT_OK;
> +}
> +
> +static int megasas_cache_flush(MPTState *s, struct megasas_cmd_t *cmd)
> +{
> +#ifdef DEBUG_MEGASAS_DCMD
> +    DPRINTF("MFI DCMD Cache flush\n");
> +#endif
> +    qemu_aio_flush();
> +    return MFI_STAT_OK;
> +}
> +
> +static int megasas_ctrl_shutdown(MPTState *s, struct megasas_cmd_t *cmd)
> +{
> +#ifdef DEBUG_MEGASAS_DCMD
> +    DPRINTF("MFI DCMD Controller shutdown\n");
> +#endif
> +    s->fw_state = MFI_FWSTATE_READY;
> +    return MFI_STAT_OK;
>  }
>
>  static int megasas_dcmd_set_properties(MPTState *s, struct megasas_cmd_t 
> *cmd)
> @@ -814,7 +977,7 @@ static int megasas_dcmd_set_properties(MPTState *s, 
> struct megasas_cmd_t *cmd)
>     DPRINTF("%02x %02x %02x %0x2 %02x %02x %02x %02x\n",
>            dummy[0x38], dummy[0x39], dummy[0x3a], dummy[0x3b],
>            dummy[0x3c], dummy[0x3d], dummy[0x3e], dummy[0x3f]);
> -    return cmd->frame->header.data_len;
> +    return MFI_STAT_OK;
>  }
>
>  static int megasas_dcmd_dummy(MPTState *s, struct megasas_cmd_t *cmd)
> @@ -825,13 +988,67 @@ static int megasas_dcmd_dummy(MPTState *s, struct 
> megasas_cmd_t *cmd)
>  #endif
>     memset(cmd->iov_buf, 0, cmd->frame->header.data_len);
>
> -    return cmd->frame->header.data_len;
> +    return MFI_STAT_OK;
>  }
>
> +
> +struct dcmd_cmd_tbl_t {

static const?

> +    int opcode;
> +    int (*func)(MPTState *s, struct megasas_cmd_t *cmd);
> +} dcmd_cmd_tbl[] = {
> +    {MFI_DCMD_CTRL_MFI_HOST_MEM_ALLOC, megasas_dcmd_dummy},
> +    {MFI_DCMD_CTRL_GET_INFO, megasas_ctrl_get_info},
> +    {MFI_DCMD_CTRL_GET_PROPERTIES, megasas_dcmd_get_properties},
> +    {MFI_DCMD_CTRL_SET_PROPERTIES, megasas_dcmd_set_properties},
> +    {MFI_DCMD_SPEAKER_GET, megasas_dcmd_dummy},
> +    {MFI_DCMD_SPEAKER_ENABLE, megasas_dcmd_dummy},
> +    {MFI_DCMD_SPEAKER_DISABLE, megasas_dcmd_dummy},
> +    {MFI_DCMD_SPEAKER_SILENCE, megasas_dcmd_dummy},
> +    {MFI_DCMD_SPEAKER_TEST, megasas_dcmd_dummy},
> +    {MFI_DCMD_CTRL_EVENT_GETINFO, megasas_event_info},
> +    {MFI_DCMD_CTRL_EVENT_GET, megasas_dcmd_dummy},
> +    {MFI_DCMD_CTRL_EVENT_WAIT, megasas_dcmd_dummy},
> +    {MFI_DCMD_CTRL_SHUTDOWN, megasas_ctrl_shutdown},
> +    {MFI_DCMD_HIBERNATE_SHUTDOWN, megasas_dcmd_dummy},
> +    {MFI_DCMD_CTRL_GET_TIME, megasas_dcmd_get_fw_time},
> +    {MFI_DCMD_CTRL_SET_TIME, megasas_dcmd_set_fw_time},
> +    {MFI_DCMD_CTRL_GET_BIOS_INFO, megasas_dcmd_get_bios_info},
> +    {MFI_DCMD_CTRL_FACTORY_DEFAULTS, megasas_dcmd_dummy},
> +    {MFI_DCMD_CTRL_MFC_DEFAULTS_GET, megasas_mfc_get_defaults},
> +    {MFI_DCMD_CTRL_MFC_DEFAULTS_SET, megasas_dcmd_dummy},
> +    {MFI_DCMD_CTRL_CACHE_FLUSH, megasas_cache_flush},
> +    {MFI_DCMD_PD_GET_LIST, megasas_dcmd_pd_get_list},
> +    {MFI_DCMD_PD_LIST_QUERY, megasas_dcmd_pd_list_query},
> +    {MFI_DCMD_PD_GET_INFO, megasas_dcmd_pd_get_info},
> +    {MFI_DCMD_PD_STATE_SET, megasas_dcmd_dummy},
> +    {MFI_DCMD_PD_REBUILD, megasas_dcmd_dummy},
> +    {MFI_DCMD_PD_BLINK, megasas_dcmd_dummy},
> +    {MFI_DCMD_PD_UNBLINK, megasas_dcmd_dummy},
> +    {MFI_DCMD_LD_GET_LIST, megasas_dcmd_ld_get_list},
> +    {MFI_DCMD_LD_GET_INFO, megasas_dcmd_ld_get_info},
> +    {MFI_DCMD_LD_GET_PROP, megasas_dcmd_dummy},
> +    {MFI_DCMD_LD_SET_PROP, megasas_dcmd_dummy},
> +    {MFI_DCMD_LD_DELETE, megasas_dcmd_dummy},
> +    {MFI_DCMD_CFG_READ, megasas_dcmd_dummy},
> +    {MFI_DCMD_CFG_ADD, megasas_dcmd_dummy},
> +    {MFI_DCMD_CFG_CLEAR, megasas_dcmd_dummy},
> +    {MFI_DCMD_CFG_FOREIGN_READ, megasas_dcmd_dummy},
> +    {MFI_DCMD_CFG_FOREIGN_IMPORT, megasas_dcmd_dummy},
> +    {MFI_DCMD_BBU_STATUS, megasas_dcmd_dummy},
> +    {MFI_DCMD_BBU_CAPACITY_INFO, megasas_dcmd_dummy},
> +    {MFI_DCMD_BBU_DESIGN_INFO, megasas_dcmd_dummy},
> +    {MFI_DCMD_BBU_PROP_GET, megasas_dcmd_dummy},
> +    {MFI_DCMD_CLUSTER, megasas_dcmd_dummy},
> +    {MFI_DCMD_CLUSTER_RESET_ALL, megasas_dcmd_dummy},
> +    {MFI_DCMD_CLUSTER_RESET_LD, megasas_dcmd_dummy},
> +    {-1, NULL}
> +};
> +
>  static int megasas_handle_dcmd(MPTState *s, struct megasas_cmd_t *cmd)
>  {
>     int opcode, size = 0, len;
>     int retval = 0;
> +    struct dcmd_cmd_tbl_t *cmdptr = dcmd_cmd_tbl;
>
>     opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
>  #ifdef DEBUG_MEGASAS_DCMD
> @@ -841,158 +1058,83 @@ static int megasas_handle_dcmd(MPTState *s, struct 
> megasas_cmd_t *cmd)
>     if (len < 0) {
>        return MFI_STAT_MEMORY_NOT_AVAILABLE;
>     }
> -    switch (opcode) {
> -       case MFI_DCMD_CTRL_MFC_DEFAULTS_GET:
> -#ifdef DEBUG_MEGASAS_DCMD
> -           DPRINTF("MFI DCMD get MFC defaults\n");
> -#endif
> -           size = megasas_mfc_get_defaults(s, cmd);
> -           retval = MFI_STAT_OK;
> -           break;
> -       case MFI_DCMD_CTRL_GET_INFO:
> -#ifdef DEBUG_MEGASAS_DCMD
> -           DPRINTF("MFI DCMD get controller info\n");
> -#endif
> -           size = megasas_ctrl_get_info(s, cmd);
> -           retval = MFI_STAT_OK;
> -           break;
> -       case MFI_DCMD_CTRL_CACHE_FLUSH:
> -#ifdef DEBUG_MEGASAS_DCMD
> -           DPRINTF("MFI DCMD Cache flush\n");
> -#endif
> -           qemu_aio_flush();
> -           retval = MFI_STAT_OK;
> -           break;
> -       case MFI_DCMD_CTRL_SHUTDOWN:
> -#ifdef DEBUG_MEGASAS_DCMD
> -           DPRINTF("MFI DCMD Controller shutdown\n");
> -#endif
> -           s->fw_state = MFI_FWSTATE_READY;
> -           retval = MFI_STAT_OK;
> -           break;
> -       case MFI_DCMD_PD_LIST_QUERY:
> +    while (cmdptr->opcode != -1 && cmdptr->opcode != opcode)
> +       cmdptr++;
> +    if (cmdptr->opcode == -1) {
> +       DPRINTF("MFI DCMD %x unhandled (len %d)\n", opcode, len);
> +       retval = megasas_dcmd_dummy(s, cmd);
> +    } else {
> +       retval = cmdptr->func(s, cmd);
> +    }
> +    if (retval != MFI_STAT_INVALID_STATUS) {
> +       size = megasas_finish_dcmd(cmd, cmd->iov_size);
>  #ifdef DEBUG_MEGASAS_DCMD
> -           DPRINTF("MFI DCMD query physical devices\n");
> +       DPRINTF("MFI DCMD wrote %d bytes\n", size);
>  #endif
> -           retval = MFI_STAT_INVALID_DCMD;
> -           break;
> -       case MFI_DCMD_PD_GET_LIST:
> +    }
> +    return retval;
> +}
> +
> +static int megasas_finish_internal_dcmd(struct megasas_cmd_t *cmd,
> +                                       SCSIRequest *req)
> +{
> +    int opcode;
> +    int retval = MFI_STAT_OK;
> +    int lun = req->lun;
> +
> +    opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
> +    scsi_req_put(req);
>  #ifdef DEBUG_MEGASAS_DCMD
> -           DPRINTF("MFI DCMD PD get list\n");
> +    DPRINTF("DCMD finish internal cmd %x lun %d\n", opcode, lun);
>  #endif
> -           size = megasas_dcmd_pd_get_list(s, cmd);
> -           retval = MFI_STAT_OK;
> -           break;
> +    switch (opcode) {
>        case MFI_DCMD_PD_GET_INFO:
>  #ifdef DEBUG_MEGASAS_DCMD
> -           DPRINTF("MFI DCMD PD get info\n");
> -#endif
> -           size = megasas_dcmd_pd_get_info(s, cmd);
> -           retval = MFI_STAT_OK;
> -           break;
> -       case MFI_DCMD_LD_GET_LIST:
> -#ifdef DEBUG_MEGASAS_DCMD
> -           DPRINTF("MFI DCMD LD get list\n");
> +           DPRINTF("Internal DCMD PD get info\n");
>  #endif
> -           size = megasas_dcmd_ld_get_list(s, cmd);
> -           retval = MFI_STAT_OK;
> +           retval = megasas_pd_get_info_submit(cmd->sdev, lun, cmd);
>            break;
>        case MFI_DCMD_LD_GET_INFO:
>  #ifdef DEBUG_MEGASAS_DCMD
> -           DPRINTF("MFI DCMD LD get info\n");
> +           DPRINTF("Internal DCMD LD get info\n");
>  #endif
> -           size = megasas_dcmd_ld_get_info(s, cmd);
> -           retval = MFI_STAT_OK;
> +           retval = megasas_ld_get_info_submit(cmd->sdev, lun, cmd);
>            break;
> -       case MFI_DCMD_CTRL_GET_PROPERTIES:
> -#ifdef DEBUG_MEGASAS_DCMD
> -           DPRINTF("MFI DCMD Get Properties\n");
> -#endif
> -           size = megasas_dcmd_get_properties(s, cmd);
> -           retval = MFI_STAT_OK;
> -           break;
> -       case MFI_DCMD_CTRL_SET_PROPERTIES:
> -#ifdef DEBUG_MEGASAS_DCMD
> -           DPRINTF("MFI DCMD Set Properties\n");
> -#endif
> -           size = megasas_dcmd_set_properties(s, cmd);
> -           retval = MFI_STAT_OK;
> -           break;
> -       case MFI_DCMD_CTRL_EVENT_GETINFO:
> -           size = megasas_event_info(s, cmd);
> -           retval = MFI_STAT_OK;
> -           break;
> -       case MFI_DCMD_CFG_READ:
> -       case MFI_DCMD_CFG_FOREIGN_READ:
> -           size = megasas_dcmd_dummy(s, cmd);
> -           retval = MFI_STAT_OK;
> -           break;
> -       case MFI_DCMD_CTRL_EVENT_WAIT:
> +       default:
>  #ifdef DEBUG_MEGASAS_DCMD
> -           DPRINTF("MFI DCMD controller event wait\n");
> +           DPRINTF("Invalid internal DCMD\n");
>  #endif
>            retval = MFI_STAT_INVALID_DCMD;
>            break;
> -    case MFI_DCMD_CLUSTER_RESET_ALL:
> -    case MFI_DCMD_CLUSTER_RESET_LD:
> -        /* Cluster reset commands have a size of 0 */
> -        size = 0;
> -        retval = MFI_STAT_OK;
> -        break;
> -       case MFI_DCMD_CTRL_GET_BIOS_INFO:
> -           size = megasas_dcmd_get_bios_info(s, cmd);
> -           retval = MFI_STAT_OK;
> -           break;
> -       case MFI_DCMD_CTRL_GET_TIME:
> -           size = megasas_dcmd_get_fw_time(s, cmd);
> -           retval = MFI_STAT_OK;
> -           break;
> -    case MFI_DCMD_CTRL_SET_TIME:
> -        size = megasas_dcmd_set_fw_time(s, cmd);
> -        retval = MFI_STAT_OK;
> -        break;
> -       case 0x010e0301:
> -       case 0x010e0302:
> -       case 0x010e8481:
> -           DPRINTF("MFI DCMD %x dummy return %d bytes\n", opcode, len);
> -           size = megasas_dcmd_dummy(s, cmd);
> -           retval = MFI_STAT_OK;
> -           break;
> -       default:
> -           DPRINTF("MFI DCMD %x unhandled (len %d)\n", opcode, len);
> -           retval = MFI_STAT_INVALID_DCMD;
> -           break;
>     }
> -    size = megasas_finish_dcmd(cmd, size);
> -#ifdef DEBUG_MEGASAS_DCMD
> -    DPRINTF("MFI DCMD wrote %d bytes\n", size);
> -#endif
> +    if (retval != MFI_STAT_INVALID_STATUS)
> +       megasas_finish_dcmd(cmd, cmd->iov_size);
>     return retval;
>  }
>
> -static int megasas_handle_scsi(MPTState *s, struct megasas_cmd_t *cmd)
> +static int megasas_handle_scsi(MPTState *s, struct megasas_cmd_t *cmd, int 
> is_logical)
>  {
>     uint8_t *cdb;
>
>     cdb = cmd->frame->pass.cdb;
>
>     if (cmd->frame->header.target_id < s->fw_luns)
> -       cmd->lun = &s->luns[cmd->frame->header.target_id];
> -
> -    if (cmd->lun)
> -       cmd->lun->sdev = s->bus.devs[cmd->frame->header.target_id];
> +       cmd->sdev = s->bus.devs[cmd->frame->header.target_id];
>
>  #ifdef DEBUG_MEGASAS_IO
> -    DPRINTF("%s dev %x lun %x sdev %p xfer %d\n",
> +    DPRINTF("%s %s dev %x lun %x sdev %p xfer %d\n",
>            mfi_frame_desc[cmd->frame->header.frame_cmd],
> +           is_logical?"logical":"physical",
>            cmd->frame->header.target_id, cmd->frame->header.lun_id,
> -           cmd->lun?cmd->lun->sdev:NULL, cmd->frame->header.data_len);
> +           cmd->sdev, cmd->frame->header.data_len);
>  #endif
>
> -    if (!cmd->lun || !cmd->lun->sdev) {
> +    if (!cmd->sdev || (s->is_jbod && is_logical)) {
>  #ifdef DEBUG_MEGASAS_IO
> -       DPRINTF("%s dev %x/%x target not present\n",
> -               mfi_frame_desc[cmd->frame->header.frame_cmd], 
> cmd->frame->header.target_id,
> +       DPRINTF("%s %s dev %x/%x target not present\n",
> +               mfi_frame_desc[cmd->frame->header.frame_cmd],
> +               is_logical?"logical":"physical",
> +               cmd->frame->header.target_id,
>                cmd->frame->header.lun_id);
>  #endif
>        return MFI_STAT_DEVICE_NOT_FOUND;
> @@ -1009,7 +1151,7 @@ static int megasas_handle_scsi(MPTState *s, struct 
> megasas_cmd_t *cmd)
>        return MFI_STAT_SCSI_DONE_WITH_ERROR;
>     }
>
> -    cmd->req = scsi_req_get(cmd->lun->sdev, cmd->frame->header.context, 
> cmd->frame->header.lun_id);
> +    cmd->req = scsi_req_get(cmd->sdev, cmd->frame->header.context, 
> cmd->frame->header.lun_id);
>     cmd->req->hba_private = cmd;
>     scsi_req_parse(cmd->req, cdb);
>     if (cmd->frame->header.data_len != cmd->req->cmd.xfer) {
> @@ -1019,7 +1161,7 @@ static int megasas_handle_scsi(MPTState *s, struct 
> megasas_cmd_t *cmd)
>        s->event_count++;
>     }
>
> -    megasas_map_sgl(cmd, MEGASAS_PTHRU_SGL_OFFSET);
> +    megasas_map_sgl(cmd, offsetof(struct mfi_pass_frame, sgl));
>     scsi_req_sgl(cmd->req, &cmd->sg);
>
>     return MFI_STAT_INVALID_STATUS;
> @@ -1037,10 +1179,7 @@ static int megasas_handle_io(MPTState *s, struct 
> megasas_cmd_t *cmd)
>     lba_start = ((uint64_t)lba_start_hi << 32) | lba_start_lo;
>
>     if (cmd->frame->header.target_id < s->fw_luns)
> -       cmd->lun = &s->luns[cmd->frame->header.target_id];
> -
> -    if (cmd->lun)
> -       cmd->lun->sdev = s->bus.devs[cmd->frame->header.target_id];
> +       cmd->sdev = s->bus.devs[cmd->frame->header.target_id];
>
>  #ifdef DEBUG_MEGASAS_IO
>     DPRINTF("%s dev %x lun %x lba %lx count %lx\n",
> @@ -1048,7 +1187,7 @@ static int megasas_handle_io(MPTState *s, struct 
> megasas_cmd_t *cmd)
>            cmd->frame->header.target_id, cmd->frame->header.lun_id,
>            (unsigned long)lba_start, (unsigned long)lba_count);
>  #endif
> -    if (!cmd->lun || !cmd->lun->sdev) {
> +    if (!cmd->sdev) {
>  #ifdef DEBUG_MEGSAS_IO
>        DPRINTF("%s dev %x/%x LUN not present\n",
>                mfi_frame_desc[cmd->frame->header.frame_cmd],
> @@ -1068,9 +1207,9 @@ static int megasas_handle_io(MPTState *s, struct 
> megasas_cmd_t *cmd)
>        return MFI_STAT_SCSI_DONE_WITH_ERROR;
>     }
>
> -    cmd->req = scsi_req_get(cmd->lun->sdev, cmd->frame->header.context, 
> cmd->frame->header.lun_id);
> +    cmd->req = scsi_req_get(cmd->sdev, cmd->frame->header.context, 
> cmd->frame->header.lun_id);
>     cmd->req->hba_private = cmd;
> -    megasas_map_sgl(cmd, MEGASAS_IO_SGL_OFFSET);
> +    megasas_map_sgl(cmd, offsetof(struct mfi_io_frame, sgl));
>
>     scsi_req_setup(cmd->req, write, lba_start, lba_count);
>     scsi_req_sgl(cmd->req, &cmd->sg);
> @@ -1078,6 +1217,21 @@ static int megasas_handle_io(MPTState *s, struct 
> megasas_cmd_t *cmd)
>     return MFI_STAT_INVALID_STATUS;
>  }
>
> +static int megasas_finish_internal_command(struct megasas_cmd_t *cmd,
> +                                          SCSIRequest *req)
> +{
> +    int retval = MFI_STAT_INVALID_CMD;
> +
> +    switch (cmd->frame->header.frame_cmd) {
> +       case MFI_CMD_DCMD:
> +           retval = megasas_finish_internal_dcmd(cmd, req);
> +           break;
> +       default:
> +           break;
> +    }
> +    return retval;
> +}
> +
>  static void megasas_command_complete(SCSIRequest *req)
>  {
>     struct megasas_cmd_t *cmd;
> @@ -1095,24 +1249,38 @@ static void megasas_command_complete(SCSIRequest *req)
>        return;
>     }
>
> +    if (cmd->req != req) {
> +       /*
> +        * Internal command complete
> +        */
> +       cmd_status = megasas_finish_internal_command(cmd, req);
> +       if (cmd_status == MFI_STAT_INVALID_STATUS)
> +           return;
> +    } else {
> +
>  #ifdef DEBUG_MEGASAS_IO
> -    DPRINTF("%s req %p cmd %p lun %p finished with status %x len %u\n",
> -           mfi_frame_desc[cmd->frame->header.frame_cmd], req, cmd, 
> cmd->lun->sdev,
> -           req->status, (unsigned)req->xferlen);
> -#endif
> -    if (req->status == CHECK_CONDITION) {
> -       megasas_build_sense(cmd, cmd->lun->sdev->sense);
> -       cmd_status = MFI_STAT_SCSI_DONE_WITH_ERROR;
> -       scsi_dev_clear_sense(cmd->lun->sdev);
> -    }
> +       DPRINTF("%s req %p cmd %p lun %p finished with status %x len %u\n",
> +               mfi_frame_desc[cmd->frame->header.frame_cmd], req, cmd, 
> cmd->sdev,
> +               req->status, (unsigned)req->xferlen);
> +#endif
> +       if (req->status == CHECK_CONDITION) {
> +           megasas_build_sense(cmd, cmd->sdev->sense);
> +           cmd_status = MFI_STAT_SCSI_DONE_WITH_ERROR;
> +           scsi_dev_clear_sense(cmd->sdev);
> +       }
>
> -    megasas_unmap_sgl(cmd);
> -    megasas_frame_set_scsi_status(cmd->pa, cmd->req->status);
> -    scsi_req_put(cmd->req);
> -    cmd->req = NULL;
> +       megasas_unmap_sgl(cmd);
> +       megasas_frame_set_scsi_status(cmd->pa, cmd->req->status);
> +       scsi_req_put(cmd->req);
> +       cmd->req = NULL;
> +    }
>     context = megasas_finish_command(cmd->state, cmd);
> -    megasas_frame_set_cmd_status(cmd->pa, cmd_status);
> -    megasas_dequeue_frame(cmd->state, context);
> +    if (context == -1) {
> +       DPRINTF("Invalid context for cmd %p\n", cmd);
> +    } else {
> +       megasas_frame_set_cmd_status(cmd->pa, cmd_status);
> +       megasas_dequeue_frame(cmd->state, context);
> +    }
>  }
>
>  static int megasas_handle_abort(MPTState *s, struct megasas_cmd_t *cmd)
> @@ -1152,8 +1320,8 @@ static void megasas_handle_frame(MPTState *s, 
> target_phys_addr_t frame_addr,
>     uint32_t frame_context = 0;
>     struct megasas_cmd_t *cmd;
>
> -    frame_cmd = ldub_phys(frame_addr + MEGASAS_FRAME_CMD_OFFSET);
> -    frame_context = ldl_phys(frame_addr + MEGASAS_FRAME_CONTEXT_OFFSET);
> +    frame_cmd = megasas_frame_get_cmd(frame_addr);
> +    frame_context = megasas_frame_get_context(frame_addr);
>
>  #ifdef DEBUG_MEGASAS_MFI
>     DPRINTF("MFI cmd %x context %x count %d\n",
> @@ -1180,8 +1348,10 @@ static void megasas_handle_frame(MPTState *s, 
> target_phys_addr_t frame_addr,
>            frame_status = megasas_handle_abort(s, cmd);
>            break;
>        case MFI_CMD_PD_SCSI_IO:
> +           frame_status = megasas_handle_scsi(s, cmd, 0);
> +           break;
>        case MFI_CMD_LD_SCSI_IO:
> -           frame_status = megasas_handle_scsi(s, cmd);
> +           frame_status = megasas_handle_scsi(s, cmd, 1);
>            break;
>        case MFI_CMD_LD_READ:
>        case MFI_CMD_LD_WRITE:
> @@ -1445,7 +1615,9 @@ static void megasas_mmio_mapfunc(PCIDevice *pci_dev, 
> int region_num,
>  {
>     MPTState *s = DO_UPCAST(MPTState, dev, pci_dev);
>
> +#ifdef DEBUG_MEGASAS_REG
>     DPRINTF("Mapping MMIO region %d at %08lx\n", region_num, (unsigned 
> long)addr);
> +#endif
>     cpu_register_physical_memory(addr, size, s->mmio_io_addr);
>     s->event_count++;
>  }
> @@ -1455,8 +1627,9 @@ static void megasas_io_mapfunc(PCIDevice *pci_dev, int 
> region_num,
>  {
>     MPTState *s = DO_UPCAST(MPTState, dev, pci_dev);
>
> +#ifdef DEBUG_MEGASAS_REG
>     DPRINTF("Mapping IO region %d at %08lx\n", region_num, (unsigned 
> long)addr);
> -
> +#endif
>     register_ioport_write(addr, size, 1, megasas_io_writeb, s);
>     register_ioport_write(addr, size, 2, megasas_io_writew, s);
>     register_ioport_write(addr, size, 4, megasas_io_writel, s);
> @@ -1471,7 +1644,9 @@ static void megasas_queue_mapfunc(PCIDevice *pci_dev, 
> int region_num,
>  {
>     MPTState *s = DO_UPCAST(MPTState, dev, pci_dev);
>
> +#ifdef DEBUG_MEGASAS_REG
>     DPRINTF("Mapping QUEUE region %d at %08lx\n", region_num, (unsigned 
> long)addr);
> +#endif
>     cpu_register_physical_memory(addr, size, s->queue_addr);
>     s->event_count++;
>  }
> @@ -1555,10 +1730,20 @@ static int megasas_scsi_init(PCIDevice *dev)
>                            PCI_BASE_ADDRESS_SPACE_IO, megasas_io_mapfunc);
>     pci_register_bar((struct PCIDevice *)s, 3, 0x40000,
>                            PCI_BASE_ADDRESS_SPACE_MEMORY, 
> megasas_queue_mapfunc);
> -    s->fw_sge = MEGASAS_MAX_SGE;
> -    s->fw_cmds = MEGASAS_MAX_FRAMES;
> -    s->fw_luns = (MEGASAS_MAX_LUNS > MAX_SCSI_DEVS) ?
> -       MAX_SCSI_DEVS : MEGASAS_MAX_LUNS;
> +    if (s->fw_sge > MEGASAS_MAX_SGE)
> +       s->fw_sge = MEGASAS_MAX_SGE;
> +    if (s->fw_cmds > MEGASAS_MAX_FRAMES)
> +       s->fw_cmds = MEGASAS_MAX_FRAMES;
> +    if (s->raid_mode_str) {
> +       if (!strcmp(s->raid_mode_str, "jbod"))
> +           s->is_jbod = 1;
> +       else
> +           s->is_jbod = 0;
> +    }
> +    DPRINTF("Using %d sges, %d cmds, %s mode\n",
> +           s->fw_sge, s->fw_cmds, s->is_jbod?"jbod":"raid");

Please add spaces around '?' and ':'.

> +    s->fw_luns = (MFI_MAX_LD > MAX_SCSI_DEVS) ?
> +       MAX_SCSI_DEVS : MFI_MAX_LD;
>     s->producer_pa = 0;
>     s->consumer_pa = 0;
>     for (i = 0; i < s->fw_cmds; i++) {
> @@ -1581,6 +1766,12 @@ static PCIDeviceInfo megasas_info = {
>     .qdev.size  = sizeof(MPTState),
>     .init       = megasas_scsi_init,
>     .exit       = megasas_scsi_uninit,
> +    .qdev.props = (Property[]) {
> +       DEFINE_PROP_UINT32("max_sge", MPTState, fw_sge, MEGASAS_DEFAULT_SGE),
> +       DEFINE_PROP_UINT32("max_cmds", MPTState, fw_cmds, 
> MEGASAS_DEFAULT_FRAMES),
> +       DEFINE_PROP_STRING("mode", MPTState, raid_mode_str),
> +       DEFINE_PROP_END_OF_LIST(),
> +    },
>  };
>
>  static void megaraid1078_register_devices(void)
> diff --git a/hw/mfi.h b/hw/mfi.h
> index e7a5fde..90334b1 100644
> --- a/hw/mfi.h
> +++ b/hw/mfi.h
> @@ -167,7 +167,7 @@ typedef enum {
>        MFI_DCMD_CTRL_SHUTDOWN =                0x01050000,
>        MFI_DCMD_HIBERNATE_SHUTDOWN =           0x01060000,
>        MFI_DCMD_CTRL_GET_TIME =                0x01080101,
> -    MFI_DCMD_CTRL_SET_TIME =        0x01080102,
> +       MFI_DCMD_CTRL_SET_TIME =                0x01080102,
>        MFI_DCMD_CTRL_GET_BIOS_INFO =           0x010c0100,
>        MFI_DCMD_CTRL_FACTORY_DEFAULTS =        0x010d0000,
>        MFI_DCMD_CTRL_MFC_DEFAULTS_GET =        0x010e0201,
> @@ -644,7 +644,16 @@ struct mfi_defaults {
>        uint8_t         restored_hot_spare_on_insertion;
>        uint8_t         expose_enclosure_devices;
>        uint8_t         maintain_pd_fail_history;
> -       uint8_t         resv[28];
> +       uint8_t         disable_puncture;
> +       uint8_t         zero_based_enumeration;
> +       uint8_t         disable_preboot_cli;
> +       uint8_t         show_drive_led_on_activity;
> +       uint8_t         cluster_disable;
> +       uint8_t         sas_disable;
> +       uint8_t         auto_detect_backplane;
> +       uint8_t         fde_only;
> +       uint8_t         delay_during_post;
> +       uint8_t         resv[19];
>  } __attribute__ ((packed));
>
>  /* Controller default settings */
> @@ -685,6 +694,8 @@ struct mfi_ctrl_info {
>  #define MFI_INFO_HW_ALARM      0x02
>  #define MFI_INFO_HW_NVRAM      0x04
>  #define MFI_INFO_HW_UART       0x08
> +#define MFI_INFO_HW_MEM                0x10
> +#define MFI_INFO_HW_FLASH      0x20
>        uint32_t                current_fw_time;
>        uint16_t                max_cmds;
>        uint16_t                max_sg_elements;
>
>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]