megasas: fixup device mapping

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>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Hannes Reinecke 2014-10-29 13:00:07 +01:00 committed by Paolo Bonzini
parent 7bd908491c
commit 3f2cd4dd47
2 changed files with 61 additions and 36 deletions

View file

@ -689,8 +689,7 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
struct mfi_ctrl_info info; struct mfi_ctrl_info info;
size_t dcmd_size = sizeof(info); size_t dcmd_size = sizeof(info);
BusChild *kid; BusChild *kid;
int num_ld_disks = 0; int num_pd_disks = 0;
uint16_t sdev_id;
memset(&info, 0x0, cmd->iov_size); memset(&info, 0x0, cmd->iov_size);
if (cmd->iov_size < dcmd_size) { if (cmd->iov_size < dcmd_size) {
@ -719,13 +718,14 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
info.device.port_count = 8; info.device.port_count = 8;
QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child); SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
uint16_t pd_id;
if (num_ld_disks < 8) { if (num_pd_disks < 8) {
sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF); pd_id = ((sdev->id & 0xFF) << 8) | (sdev->lun & 0xFF);
info.device.port_addr[num_ld_disks] = info.device.port_addr[num_pd_disks] =
cpu_to_le64(megasas_get_sata_addr(sdev_id)); cpu_to_le64(megasas_get_sata_addr(pd_id));
} }
num_ld_disks++; num_pd_disks++;
} }
memcpy(info.product_name, "MegaRAID SAS 8708EM2", 20); memcpy(info.product_name, "MegaRAID SAS 8708EM2", 20);
@ -751,13 +751,14 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
info.max_arms = 32; info.max_arms = 32;
info.max_spans = 8; info.max_spans = 8;
info.max_arrays = MEGASAS_MAX_ARRAYS; 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_cmds = cpu_to_le16(s->fw_cmds);
info.max_sg_elements = cpu_to_le16(s->fw_sge); info.max_sg_elements = cpu_to_le16(s->fw_sge);
info.max_request_size = cpu_to_le32(MEGASAS_MAX_SECTORS); info.max_request_size = cpu_to_le32(MEGASAS_MAX_SECTORS);
info.lds_present = cpu_to_le16(num_ld_disks); if (!megasas_is_jbod(s))
info.pd_present = cpu_to_le16(num_ld_disks); info.lds_present = cpu_to_le16(num_pd_disks);
info.pd_disks_present = cpu_to_le16(num_ld_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 | info.hw_present = cpu_to_le32(MFI_INFO_HW_NVRAM |
MFI_INFO_HW_MEM | MFI_INFO_HW_MEM |
MFI_INFO_HW_FLASH); MFI_INFO_HW_FLASH);
@ -916,7 +917,6 @@ static int megasas_dcmd_pd_get_list(MegasasState *s, MegasasCmd *cmd)
size_t dcmd_size = sizeof(info); size_t dcmd_size = sizeof(info);
BusChild *kid; BusChild *kid;
uint32_t offset, dcmd_limit, num_pd_disks = 0, max_pd_disks; uint32_t offset, dcmd_limit, num_pd_disks = 0, max_pd_disks;
uint16_t sdev_id;
memset(&info, 0, dcmd_size); memset(&info, 0, dcmd_size);
offset = 8; offset = 8;
@ -928,22 +928,25 @@ static int megasas_dcmd_pd_get_list(MegasasState *s, MegasasCmd *cmd)
} }
max_pd_disks = (cmd->iov_size - offset) / sizeof(struct mfi_pd_address); max_pd_disks = (cmd->iov_size - offset) / sizeof(struct mfi_pd_address);
if (max_pd_disks > s->fw_luns) { if (max_pd_disks > MFI_MAX_SYS_PDS) {
max_pd_disks = s->fw_luns; max_pd_disks = MFI_MAX_SYS_PDS;
} }
QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child); SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
uint16_t pd_id;
sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF); if (num_pd_disks >= max_pd_disks)
info.addr[num_pd_disks].device_id = cpu_to_le16(sdev_id); break;
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_device_id = 0xFFFF;
info.addr[num_pd_disks].encl_index = 0; 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].scsi_dev_type = sdev->type;
info.addr[num_pd_disks].connect_port_bitmap = 0x1; info.addr[num_pd_disks].connect_port_bitmap = 0x1;
info.addr[num_pd_disks].sas_addr[0] = 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++; num_pd_disks++;
offset += sizeof(struct mfi_pd_address); offset += sizeof(struct mfi_pd_address);
} }
@ -978,7 +981,7 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
struct mfi_pd_info *info = cmd->iov_buf; struct mfi_pd_info *info = cmd->iov_buf;
size_t dcmd_size = sizeof(struct mfi_pd_info); size_t dcmd_size = sizeof(struct mfi_pd_info);
uint64_t pd_size; uint64_t pd_size;
uint16_t sdev_id = ((sdev->id & 0xFF) >> 8) | (lun & 0xFF); uint16_t pd_id = ((sdev->id & 0xFF) << 8) | (lun & 0xFF);
uint8_t cmdbuf[6]; uint8_t cmdbuf[6];
SCSIRequest *req; SCSIRequest *req;
size_t len, resid; size_t len, resid;
@ -1034,7 +1037,7 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
info->fw_state = cpu_to_le16(MFI_PD_STATE_OFFLINE); 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| info->state.ddf.pd_type = cpu_to_le16(MFI_PD_DDF_TYPE_IN_VD|
MFI_PD_DDF_TYPE_INTF_SAS); MFI_PD_DDF_TYPE_INTF_SAS);
blk_get_geometry(sdev->conf.blk, &pd_size); blk_get_geometry(sdev->conf.blk, &pd_size);
@ -1045,7 +1048,7 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
info->slot_number = (sdev->id & 0xFF); info->slot_number = (sdev->id & 0xFF);
info->path_info.count = 1; info->path_info.count = 1;
info->path_info.sas_addr[0] = 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->connected_port_bitmap = 0x1;
info->device_speed = 1; info->device_speed = 1;
info->link_speed = 1; info->link_speed = 1;
@ -1060,6 +1063,7 @@ static int megasas_dcmd_pd_get_info(MegasasState *s, MegasasCmd *cmd)
{ {
size_t dcmd_size = sizeof(struct mfi_pd_info); size_t dcmd_size = sizeof(struct mfi_pd_info);
uint16_t pd_id; uint16_t pd_id;
uint8_t target_id, lun_id;
SCSIDevice *sdev = NULL; SCSIDevice *sdev = NULL;
int retval = MFI_STAT_DEVICE_NOT_FOUND; int retval = MFI_STAT_DEVICE_NOT_FOUND;
@ -1069,7 +1073,9 @@ static int megasas_dcmd_pd_get_info(MegasasState *s, MegasasCmd *cmd)
/* mbox0 has the ID */ /* mbox0 has the ID */
pd_id = le16_to_cpu(cmd->frame->dcmd.mbox[0]); 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); trace_megasas_dcmd_pd_get_info(cmd->index, pd_id);
if (sdev) { if (sdev) {
@ -1084,7 +1090,7 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd)
{ {
struct mfi_ld_list info; struct mfi_ld_list info;
size_t dcmd_size = sizeof(info), resid; 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; uint64_t ld_size;
BusChild *kid; BusChild *kid;
@ -1095,9 +1101,13 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd)
return MFI_STAT_INVALID_PARAMETER; return MFI_STAT_INVALID_PARAMETER;
} }
max_ld_disks = (cmd->iov_size - 8) / 16;
if (megasas_is_jbod(s)) { if (megasas_is_jbod(s)) {
max_ld_disks = 0; 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) { QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child); SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
@ -1107,7 +1117,6 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd)
/* Logical device size is in blocks */ /* Logical device size is in blocks */
blk_get_geometry(sdev->conf.blk, &ld_size); blk_get_geometry(sdev->conf.blk, &ld_size);
info.ld_list[num_ld_disks].ld.v.target_id = sdev->id; 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].state = MFI_LD_STATE_OPTIMAL;
info.ld_list[num_ld_disks].size = cpu_to_le64(ld_size); info.ld_list[num_ld_disks].size = cpu_to_le64(ld_size);
num_ld_disks++; num_ld_disks++;
@ -1143,10 +1152,13 @@ static int megasas_dcmd_ld_list_query(MegasasState *s, MegasasCmd *cmd)
return MFI_STAT_INVALID_PARAMETER; return MFI_STAT_INVALID_PARAMETER;
} }
dcmd_size = sizeof(uint32_t) * 2 + 3; dcmd_size = sizeof(uint32_t) * 2 + 3;
max_ld_disks = cmd->iov_size - dcmd_size;
if (megasas_is_jbod(s)) { if (megasas_is_jbod(s)) {
max_ld_disks = 0; 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) { QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child); SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
@ -1174,7 +1186,7 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
uint8_t cdb[6]; uint8_t cdb[6];
SCSIRequest *req; SCSIRequest *req;
ssize_t len, resid; ssize_t len, resid;
uint16_t sdev_id = ((sdev->id & 0xFF) >> 8) | (lun & 0xFF); uint16_t sdev_id = ((sdev->id & 0xFF) << 8) | (lun & 0xFF);
uint64_t ld_size; uint64_t ld_size;
if (!cmd->iov_buf) { if (!cmd->iov_buf) {
@ -1290,7 +1302,7 @@ static int megasas_dcmd_cfg_read(MegasasState *s, MegasasCmd *cmd)
QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child); SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
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_array *array;
struct mfi_ld_config *ld; struct mfi_ld_config *ld;
uint64_t pd_size; uint64_t pd_size;
@ -1316,7 +1328,7 @@ static int megasas_dcmd_cfg_read(MegasasState *s, MegasasCmd *cmd)
array_offset += sizeof(struct mfi_array); array_offset += sizeof(struct mfi_array);
ld = (struct mfi_ld_config *)(data + ld_offset); ld = (struct mfi_ld_config *)(data + ld_offset);
memset(ld, 0, sizeof(struct mfi_ld_config)); 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 | ld->properties.default_cache_policy = MR_LD_CACHE_READ_AHEAD |
MR_LD_CACHE_READ_ADAPTIVE; MR_LD_CACHE_READ_ADAPTIVE;
ld->properties.current_cache_policy = MR_LD_CACHE_READ_AHEAD | ld->properties.current_cache_policy = MR_LD_CACHE_READ_AHEAD |
@ -1603,10 +1615,18 @@ static int megasas_handle_scsi(MegasasState *s, MegasasCmd *cmd,
cdb = cmd->frame->pass.cdb; cdb = cmd->frame->pass.cdb;
if (cmd->frame->header.target_id < s->fw_luns) { if (is_logical) {
sdev = scsi_device_find(&s->bus, 0, cmd->frame->header.target_id, if (cmd->frame->header.target_id >= MFI_MAX_LD ||
cmd->frame->header.lun_id); 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); cmd->iov_size = le32_to_cpu(cmd->frame->header.data_len);
trace_megasas_handle_scsi(mfi_frame_desc[cmd->frame->header.frame_cmd], trace_megasas_handle_scsi(mfi_frame_desc[cmd->frame->header.frame_cmd],
is_logical, cmd->frame->header.target_id, is_logical, cmd->frame->header.target_id,
@ -1677,7 +1697,8 @@ static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd)
lba_start_hi = le32_to_cpu(cmd->frame->io.lba_hi); lba_start_hi = le32_to_cpu(cmd->frame->io.lba_hi);
lba_start = ((uint64_t)lba_start_hi << 32) | lba_start_lo; 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, sdev = scsi_device_find(&s->bus, 0, cmd->frame->header.target_id,
cmd->frame->header.lun_id); cmd->frame->header.lun_id);
} }
@ -2233,8 +2254,12 @@ static int megasas_scsi_init(PCIDevice *dev)
} }
trace_megasas_init(s->fw_sge, s->fw_cmds, trace_megasas_init(s->fw_sge, s->fw_cmds,
megasas_is_jbod(s) ? "jbod" : "raid"); 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->producer_pa = 0;
s->consumer_pa = 0; s->consumer_pa = 0;
for (i = 0; i < s->fw_cmds; i++) { for (i = 0; i < s->fw_cmds; i++) {

View file

@ -1094,7 +1094,7 @@ struct mfi_pd_list {
union mfi_ld_ref { union mfi_ld_ref {
struct { struct {
uint8_t target_id; uint8_t target_id;
uint8_t lun_id; uint8_t reserved;
uint16_t seq; uint16_t seq;
} v; } v;
uint32_t ref; uint32_t ref;