static int megasas_dcmd_cfg_read(MegasasState *s, MegasasCmd *cmd)

{

    uint8_t data[4096];

    struct mfi_config_data *info;

    int num_pd_disks = 0, array_offset, ld_offset;

    BusChild *kid;



    if (cmd->iov_size > 4096) {

        return MFI_STAT_INVALID_PARAMETER;

    }



    QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {

        num_pd_disks++;

    }

    info = (struct mfi_config_data *)&data;

    /*

     * Array mapping:

     * - One array per SCSI device

     * - One logical drive per SCSI device

     *   spanning the entire device

     */

    info->array_count = num_pd_disks;

    info->array_size = sizeof(struct mfi_array) * num_pd_disks;

    info->log_drv_count = num_pd_disks;

    info->log_drv_size = sizeof(struct mfi_ld_config) * num_pd_disks;

    info->spares_count = 0;

    info->spares_size = sizeof(struct mfi_spare);

    info->size = sizeof(struct mfi_config_data) + info->array_size +

        info->log_drv_size;

    if (info->size > 4096) {

        return MFI_STAT_INVALID_PARAMETER;

    }



    array_offset = sizeof(struct mfi_config_data);

    ld_offset = array_offset + sizeof(struct mfi_array) * num_pd_disks;



    QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {

        SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);

        BlockConf *conf = &sdev->conf;

        uint16_t sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF);

        struct mfi_array *array;

        struct mfi_ld_config *ld;

        uint64_t pd_size;

        int i;



        array = (struct mfi_array *)(data + array_offset);

        bdrv_get_geometry(conf->bs, &pd_size);

        array->size = cpu_to_le64(pd_size);

        array->num_drives = 1;

        array->array_ref = cpu_to_le16(sdev_id);

        array->pd[0].ref.v.device_id = cpu_to_le16(sdev_id);

        array->pd[0].ref.v.seq_num = 0;

        array->pd[0].fw_state = MFI_PD_STATE_ONLINE;

        array->pd[0].encl.pd = 0xFF;

        array->pd[0].encl.slot = (sdev->id & 0xFF);

        for (i = 1; i < MFI_MAX_ROW_SIZE; i++) {

            array->pd[i].ref.v.device_id = 0xFFFF;

            array->pd[i].ref.v.seq_num = 0;

            array->pd[i].fw_state = MFI_PD_STATE_UNCONFIGURED_GOOD;

            array->pd[i].encl.pd = 0xFF;

            array->pd[i].encl.slot = 0xFF;

        }

        array_offset += sizeof(struct mfi_array);

        ld = (struct mfi_ld_config *)(data + ld_offset);

        memset(ld, 0, sizeof(struct mfi_ld_config));

        ld->properties.ld.v.target_id = (sdev->id & 0xFF);

        ld->properties.default_cache_policy = MR_LD_CACHE_READ_AHEAD |

            MR_LD_CACHE_READ_ADAPTIVE;

        ld->properties.current_cache_policy = MR_LD_CACHE_READ_AHEAD |

            MR_LD_CACHE_READ_ADAPTIVE;

        ld->params.state = MFI_LD_STATE_OPTIMAL;

        ld->params.stripe_size = 3;

        ld->params.num_drives = 1;

        ld->params.span_depth = 1;

        ld->params.is_consistent = 1;

        ld->span[0].start_block = 0;

        ld->span[0].num_blocks = cpu_to_le64(pd_size);

        ld->span[0].array_ref = cpu_to_le16(sdev_id);

        ld_offset += sizeof(struct mfi_ld_config);

    }



    cmd->iov_size -= dma_buf_read((uint8_t *)data, info->size, &cmd->qsg);

    return MFI_STAT_OK;

}
