@@ -688,8 +688,7 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
struct mfi_ctrl_info info;
size_t dcmd_size = sizeof(info);
BusChild *kid;
- int num_ld_disks = 0;
- uint16_t sdev_id;
+ int num_pd_disks = 0;
memset(&info, 0x0, cmd->iov_size);
if (cmd->iov_size < dcmd_size) {
@@ -718,13 +717,14 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
info.device.port_count = 8;
QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
+ uint16_t pd_id;
- if (num_ld_disks < 8) {
- sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF);
- info.device.port_addr[num_ld_disks] =
- cpu_to_le64(megasas_get_sata_addr(sdev_id));
+ if (num_pd_disks < 8) {
+ pd_id = ((sdev->id & 0xFF) << 8) | (sdev->lun & 0xFF);
+ info.device.port_addr[num_pd_disks] =
+ cpu_to_le64(megasas_get_sata_addr(pd_id));
}
- num_ld_disks++;
+ num_pd_disks++;
}
memcpy(info.product_name, "MegaRAID SAS 8708EM2", 20);
@@ -750,13 +750,14 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
info.max_arms = 32;
info.max_spans = 8;
info.max_arrays = MEGASAS_MAX_ARRAYS;
- info.max_lds = s->fw_luns;
+ info.max_lds = MFI_MAX_LD;
info.max_cmds = cpu_to_le16(s->fw_cmds);
info.max_sg_elements = cpu_to_le16(s->fw_sge);
info.max_request_size = cpu_to_le32(MEGASAS_MAX_SECTORS);
- info.lds_present = cpu_to_le16(num_ld_disks);
- info.pd_present = cpu_to_le16(num_ld_disks);
- info.pd_disks_present = cpu_to_le16(num_ld_disks);
+ if (!megasas_is_jbod(s))
+ info.lds_present = cpu_to_le16(num_pd_disks);
+ info.pd_present = cpu_to_le16(num_pd_disks);
+ info.pd_disks_present = cpu_to_le16(num_pd_disks);
info.hw_present = cpu_to_le32(MFI_INFO_HW_NVRAM |
MFI_INFO_HW_MEM |
MFI_INFO_HW_FLASH);
@@ -915,7 +916,6 @@ static int megasas_dcmd_pd_get_list(MegasasState *s, MegasasCmd *cmd)
size_t dcmd_size = sizeof(info);
BusChild *kid;
uint32_t offset, dcmd_limit, num_pd_disks = 0, max_pd_disks;
- uint16_t sdev_id;
memset(&info, 0, dcmd_size);
offset = 8;
@@ -927,22 +927,25 @@ static int megasas_dcmd_pd_get_list(MegasasState *s, MegasasCmd *cmd)
}
max_pd_disks = (cmd->iov_size - offset) / sizeof(struct mfi_pd_address);
- if (max_pd_disks > s->fw_luns) {
- max_pd_disks = s->fw_luns;
+ if (max_pd_disks > MFI_MAX_SYS_PDS) {
+ max_pd_disks = MFI_MAX_SYS_PDS;
}
-
QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
+ uint16_t pd_id;
+
+ if (num_pd_disks >= max_pd_disks)
+ break;
- sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF);
- info.addr[num_pd_disks].device_id = cpu_to_le16(sdev_id);
+ pd_id = ((sdev->id & 0xFF) << 8) | (sdev->lun & 0xFF);
+ info.addr[num_pd_disks].device_id = cpu_to_le16(pd_id);
info.addr[num_pd_disks].encl_device_id = 0xFFFF;
info.addr[num_pd_disks].encl_index = 0;
- info.addr[num_pd_disks].slot_number = (sdev->id & 0xFF);
+ info.addr[num_pd_disks].slot_number = sdev->id & 0xFF;
info.addr[num_pd_disks].scsi_dev_type = sdev->type;
info.addr[num_pd_disks].connect_port_bitmap = 0x1;
info.addr[num_pd_disks].sas_addr[0] =
- cpu_to_le64(megasas_get_sata_addr(sdev_id));
+ cpu_to_le64(megasas_get_sata_addr(pd_id));
num_pd_disks++;
offset += sizeof(struct mfi_pd_address);
}
@@ -977,7 +980,7 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, MegasasCmd *cmd)
size_t dcmd_size = sizeof(struct mfi_pd_info);
BlockConf *conf = &sdev->conf;
uint64_t pd_size;
- uint16_t sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF);
+ uint16_t pd_id = ((sdev->id & 0xFF) << 8) | (sdev->lun & 0xFF);
uint8_t cmdbuf[6];
SCSIRequest *req;
size_t len, resid;
@@ -1035,7 +1038,7 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, MegasasCmd *cmd)
info->fw_state = cpu_to_le16(MFI_PD_STATE_OFFLINE);
}
- info->ref.v.device_id = cpu_to_le16(sdev_id);
+ info->ref.v.device_id = cpu_to_le16(pd_id);
info->state.ddf.pd_type = cpu_to_le16(MFI_PD_DDF_TYPE_IN_VD|
MFI_PD_DDF_TYPE_INTF_SAS);
bdrv_get_geometry(conf->bs, &pd_size);
@@ -1046,7 +1049,7 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, MegasasCmd *cmd)
info->slot_number = (sdev->id & 0xFF);
info->path_info.count = 1;
info->path_info.sas_addr[0] =
- cpu_to_le64(megasas_get_sata_addr(sdev_id));
+ cpu_to_le64(megasas_get_sata_addr(pd_id));
info->connected_port_bitmap = 0x1;
info->device_speed = 1;
info->link_speed = 1;
@@ -1061,6 +1064,7 @@ static int megasas_dcmd_pd_get_info(MegasasState *s, MegasasCmd *cmd)
{
size_t dcmd_size = sizeof(struct mfi_pd_info);
uint16_t pd_id;
+ uint8_t target_id, lun_id;
SCSIDevice *sdev = NULL;
int retval = MFI_STAT_DEVICE_NOT_FOUND;
@@ -1070,7 +1074,9 @@ static int megasas_dcmd_pd_get_info(MegasasState *s, MegasasCmd *cmd)
/* mbox0 has the ID */
pd_id = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
- sdev = scsi_device_find(&s->bus, 0, pd_id, 0);
+ target_id = (pd_id >> 8) & 0xFF;
+ lun_id = pd_id & 0xFF;
+ sdev = scsi_device_find(&s->bus, 0, target_id, lun_id);
trace_megasas_dcmd_pd_get_info(cmd->index, pd_id);
if (sdev) {
@@ -1085,7 +1091,7 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd)
{
struct mfi_ld_list info;
size_t dcmd_size = sizeof(info), resid;
- uint32_t num_ld_disks = 0, max_ld_disks = s->fw_luns;
+ uint32_t num_ld_disks = 0, max_ld_disks;
uint64_t ld_size;
BusChild *kid;
@@ -1096,9 +1102,13 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd)
return MFI_STAT_INVALID_PARAMETER;
}
+ max_ld_disks = (cmd->iov_size - 8) / 16;
if (megasas_is_jbod(s)) {
max_ld_disks = 0;
}
+ if (max_ld_disks > MFI_MAX_LD) {
+ max_ld_disks = MFI_MAX_LD;
+ }
QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
BlockConf *conf = &sdev->conf;
@@ -1109,7 +1119,6 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd)
/* Logical device size is in blocks */
bdrv_get_geometry(conf->bs, &ld_size);
info.ld_list[num_ld_disks].ld.v.target_id = sdev->id;
- info.ld_list[num_ld_disks].ld.v.lun_id = sdev->lun;
info.ld_list[num_ld_disks].state = MFI_LD_STATE_OPTIMAL;
info.ld_list[num_ld_disks].size = cpu_to_le64(ld_size);
num_ld_disks++;
@@ -1145,10 +1154,13 @@ static int megasas_dcmd_ld_list_query(MegasasState *s, MegasasCmd *cmd)
return MFI_STAT_INVALID_PARAMETER;
}
dcmd_size = sizeof(uint32_t) * 2 + 3;
-
+ max_ld_disks = cmd->iov_size - dcmd_size;
if (megasas_is_jbod(s)) {
max_ld_disks = 0;
}
+ if (max_ld_disks > MFI_MAX_LD) {
+ max_ld_disks = MFI_MAX_LD;
+ }
QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
@@ -1176,7 +1188,7 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, MegasasCmd *cmd)
SCSIRequest *req;
ssize_t len, resid;
BlockConf *conf = &sdev->conf;
- uint16_t sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF);
+ uint16_t sdev_id = ((sdev->id & 0xFF) << 8) | (sdev->lun & 0xFF);
uint64_t ld_size;
if (!cmd->iov_buf) {
@@ -1294,7 +1306,7 @@ static int megasas_dcmd_cfg_read(MegasasState *s, MegasasCmd *cmd)
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);
+ uint16_t sdev_id = ((sdev->id & 0xFF) << 8) | (sdev->lun & 0xFF);
struct mfi_array *array;
struct mfi_ld_config *ld;
uint64_t pd_size;
@@ -1320,7 +1332,7 @@ static int megasas_dcmd_cfg_read(MegasasState *s, MegasasCmd *cmd)
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.ld.v.target_id = sdev->id;
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 |
@@ -1606,10 +1618,18 @@ static int megasas_handle_scsi(MegasasState *s, MegasasCmd *cmd,
cdb = cmd->frame->pass.cdb;
- if (cmd->frame->header.target_id < s->fw_luns) {
- sdev = scsi_device_find(&s->bus, 0, cmd->frame->header.target_id,
- cmd->frame->header.lun_id);
+ if (is_logical) {
+ if (cmd->frame->header.target_id >= MFI_MAX_LD ||
+ cmd->frame->header.lun_id != 0) {
+ trace_megasas_scsi_target_not_present(
+ mfi_frame_desc[cmd->frame->header.frame_cmd], is_logical,
+ cmd->frame->header.target_id, cmd->frame->header.lun_id);
+ return MFI_STAT_DEVICE_NOT_FOUND;
+ }
}
+ sdev = scsi_device_find(&s->bus, 0, cmd->frame->header.target_id,
+ cmd->frame->header.lun_id);
+
cmd->iov_size = le32_to_cpu(cmd->frame->header.data_len);
trace_megasas_handle_scsi(mfi_frame_desc[cmd->frame->header.frame_cmd],
is_logical, cmd->frame->header.target_id,
@@ -1679,7 +1699,8 @@ static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd)
lba_start_hi = le32_to_cpu(cmd->frame->io.lba_hi);
lba_start = ((uint64_t)lba_start_hi << 32) | lba_start_lo;
- if (cmd->frame->header.target_id < s->fw_luns) {
+ if (cmd->frame->header.target_id < MFI_MAX_LD &&
+ cmd->frame->header.lun_id == 0) {
sdev = scsi_device_find(&s->bus, 0, cmd->frame->header.target_id,
cmd->frame->header.lun_id);
}
@@ -2234,8 +2255,12 @@ static int megasas_scsi_init(PCIDevice *dev)
}
trace_megasas_init(s->fw_sge, s->fw_cmds,
megasas_is_jbod(s) ? "jbod" : "raid");
- s->fw_luns = (MFI_MAX_LD > MAX_SCSI_DEVS) ?
- MAX_SCSI_DEVS : MFI_MAX_LD;
+
+ if (megasas_is_jbod(s)) {
+ s->fw_luns = MFI_MAX_SYS_PDS;
+ } else {
+ s->fw_luns = MFI_MAX_LD;
+ }
s->producer_pa = 0;
s->consumer_pa = 0;
for (i = 0; i < s->fw_cmds; i++) {
@@ -1094,7 +1094,7 @@ struct mfi_pd_list {
union mfi_ld_ref {
struct {
uint8_t target_id;
- uint8_t lun_id;
+ uint8_t reserved;
uint16_t seq;
} v;
uint32_t ref;
Logical drives can only be addressed with the 'target_id' number; LUN numbers cannot be selected. Physical drives can be selected with both, target and LUN id. So we should disallow LUN numbers not equal to 0 when in RAID mode. Signed-off-by: Hannes Reinecke <hare@suse.de> --- hw/scsi/megasas.c | 95 +++++++++++++++++++++++++++++++++++-------------------- hw/scsi/mfi.h | 2 +- 2 files changed, 61 insertions(+), 36 deletions(-)