diff mbox

[08/17] megasas: fixup device mapping

Message ID 1414569232-21357-9-git-send-email-hare@suse.de
State New
Headers show

Commit Message

Hannes Reinecke Oct. 29, 2014, 7:53 a.m. UTC
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(-)
diff mbox

Patch

diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index 41194b9..1041e3d 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -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++) {
diff --git a/hw/scsi/mfi.h b/hw/scsi/mfi.h
index 5050ce4..455c96b 100644
--- a/hw/scsi/mfi.h
+++ b/hw/scsi/mfi.h
@@ -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;