Hannes Reinecke 336646
From: Shivasharan S <shivasharan.srikanteshwara@broadcom.com>
Hannes Reinecke 336646
Date: Tue, 29 Jan 2019 01:38:14 -0800
Hannes Reinecke 336646
Subject: [PATCH] scsi: megaraid_sas: Add support for DEVICE_LIST DCMD in
Hannes Reinecke 336646
 driver
Hannes Reinecke 336646
References: bsc#1136271
Hannes Reinecke 336646
Git-commit: f6fe57310811780d55d79e30da51db98677f1a90
Hannes Reinecke 336646
Patch-mainline: v5.1-rc1
Hannes Reinecke 336646
Hannes Reinecke 336646
This patch adds support for the new DEVICE_LIST DCMD.
Hannes Reinecke 336646
Hannes Reinecke 336646
Driver currently sends two separate DCMDs for getting the list of PDs and
Hannes Reinecke 336646
LDs that are exposed to host.  The new DCMD provides a single interface to
Hannes Reinecke 336646
get a list of both PDs and LDs that are exposed to the host.  Based on the
Hannes Reinecke 336646
list of target IDs that are returned by this DCMD, driver will add the
Hannes Reinecke 336646
devices (PD/LD) to SML.  Driver will check for FW support for this new DCMD
Hannes Reinecke 336646
and based on the support will either send the new DCMD or will fall back to
Hannes Reinecke 336646
the earlier method of sending two separate DCMDs for PD and LD list.
Hannes Reinecke 336646
Hannes Reinecke 336646
Signed-off-by: Kashyap Desai <kashyap.desai@broadcom.com>
Hannes Reinecke 336646
Signed-off-by: Shivasharan S <shivasharan.srikanteshwara@broadcom.com>
Hannes Reinecke 336646
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Hannes Reinecke 336646
Signed-off-by: Hannes Reinecke <hare@suse.de>
Hannes Reinecke 336646
---
Hannes Reinecke 336646
 drivers/scsi/megaraid/megaraid_sas.h        |  49 +++++-
Hannes Reinecke 336646
 drivers/scsi/megaraid/megaraid_sas_base.c   | 222 +++++++++++++++++++++++++---
Hannes Reinecke 336646
 drivers/scsi/megaraid/megaraid_sas_fusion.c |   1 +
Hannes Reinecke 336646
 drivers/scsi/megaraid/megaraid_sas_fusion.h |   1 +
Hannes Reinecke 336646
 4 files changed, 250 insertions(+), 23 deletions(-)
Hannes Reinecke 336646
Hannes Reinecke 336646
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
Hannes Reinecke 336646
index 16536c41f0c5..fe1173f02c54 100644
Hannes Reinecke 336646
--- a/drivers/scsi/megaraid/megaraid_sas.h
Hannes Reinecke 336646
+++ b/drivers/scsi/megaraid/megaraid_sas.h
Hannes Reinecke 336646
@@ -790,6 +790,37 @@ struct MR_LD_TARGETID_LIST {
Hannes Reinecke 336646
 	u8	targetId[MAX_LOGICAL_DRIVES_EXT];
Hannes Reinecke 336646
 };
Hannes Reinecke 336646
 
Hannes Reinecke 336646
+struct MR_HOST_DEVICE_LIST_ENTRY {
Hannes Reinecke 336646
+	struct {
Hannes Reinecke 336646
+		union {
Hannes Reinecke 336646
+			struct {
Hannes Reinecke 336646
+#if defined(__BIG_ENDIAN_BITFIELD)
Hannes Reinecke 336646
+				u8 reserved:7;
Hannes Reinecke 336646
+				u8 is_sys_pd:1;
Hannes Reinecke 336646
+#else
Hannes Reinecke 336646
+				u8 is_sys_pd:1;
Hannes Reinecke 336646
+				u8 reserved:7;
Hannes Reinecke 336646
+#endif
Hannes Reinecke 336646
+			} bits;
Hannes Reinecke 336646
+			u8 byte;
Hannes Reinecke 336646
+		} u;
Hannes Reinecke 336646
+	} flags;
Hannes Reinecke 336646
+	u8 scsi_type;
Hannes Reinecke 336646
+	__le16 target_id;
Hannes Reinecke 336646
+	u8 reserved[2];
Hannes Reinecke 336646
+	__le64 sas_addr[2];
Hannes Reinecke 336646
+} __packed;
Hannes Reinecke 336646
+
Hannes Reinecke 336646
+struct MR_HOST_DEVICE_LIST {
Hannes Reinecke 336646
+	__le32			size;
Hannes Reinecke 336646
+	__le32			count;
Hannes Reinecke 336646
+	struct MR_HOST_DEVICE_LIST_ENTRY	host_device_list[1];
Hannes Reinecke 336646
+} __packed;
Hannes Reinecke 336646
+
Hannes Reinecke 336646
+#define HOST_DEVICE_LIST_SZ (sizeof(struct MR_HOST_DEVICE_LIST) +	       \
Hannes Reinecke 336646
+			      (sizeof(struct MR_HOST_DEVICE_LIST_ENTRY) *      \
Hannes Reinecke 336646
+			      (MEGASAS_MAX_PD + MAX_LOGICAL_DRIVES_EXT - 1)))
Hannes Reinecke 336646
+
Hannes Reinecke 336646
 
Hannes Reinecke 336646
 /*
Hannes Reinecke 336646
  * SAS controller properties
Hannes Reinecke 336646
@@ -870,13 +901,17 @@ struct megasas_ctrl_prop {
Hannes Reinecke 336646
 		u8 viewSpace;
Hannes Reinecke 336646
 		struct {
Hannes Reinecke 336646
 #if   defined(__BIG_ENDIAN_BITFIELD)
Hannes Reinecke 336646
-			u16 reserved2:11;
Hannes Reinecke 336646
+			u16 reserved3:9;
Hannes Reinecke 336646
+			u16 enable_fw_dev_list:1;
Hannes Reinecke 336646
+			u16 reserved2:1;
Hannes Reinecke 336646
 			u16 enable_snap_dump:1;
Hannes Reinecke 336646
 			u16 reserved1:4;
Hannes Reinecke 336646
 #else
Hannes Reinecke 336646
 			u16 reserved1:4;
Hannes Reinecke 336646
 			u16 enable_snap_dump:1;
Hannes Reinecke 336646
-			u16 reserved2:11;
Hannes Reinecke 336646
+			u16 reserved2:1;
Hannes Reinecke 336646
+			u16 enable_fw_dev_list:1;
Hannes Reinecke 336646
+			u16 reserved3:9;
Hannes Reinecke 336646
 #endif
Hannes Reinecke 336646
 		} on_off_properties2;
Hannes Reinecke 336646
 	};
Hannes Reinecke 336646
@@ -1685,7 +1720,8 @@ union megasas_sgl_frame {
Hannes Reinecke 336646
 typedef union _MFI_CAPABILITIES {
Hannes Reinecke 336646
 	struct {
Hannes Reinecke 336646
 #if   defined(__BIG_ENDIAN_BITFIELD)
Hannes Reinecke 336646
-	u32     reserved:17;
Hannes Reinecke 336646
+	u32     reserved:16;
Hannes Reinecke 336646
+	u32	support_fw_exposed_dev_list:1;
Hannes Reinecke 336646
 	u32	support_nvme_passthru:1;
Hannes Reinecke 336646
 	u32     support_64bit_mode:1;
Hannes Reinecke 336646
 	u32 support_pd_map_target_id:1;
Hannes Reinecke 336646
@@ -1717,7 +1753,8 @@ typedef union _MFI_CAPABILITIES {
Hannes Reinecke 336646
 	u32	support_pd_map_target_id:1;
Hannes Reinecke 336646
 	u32     support_64bit_mode:1;
Hannes Reinecke 336646
 	u32	support_nvme_passthru:1;
Hannes Reinecke 336646
-	u32     reserved:17;
Hannes Reinecke 336646
+	u32	support_fw_exposed_dev_list:1;
Hannes Reinecke 336646
+	u32     reserved:16;
Hannes Reinecke 336646
 #endif
Hannes Reinecke 336646
 	} mfi_capabilities;
Hannes Reinecke 336646
 	__le32		reg;
Hannes Reinecke 336646
@@ -2202,6 +2239,9 @@ struct megasas_instance {
Hannes Reinecke 336646
 	struct MR_LD_TARGETID_LIST *ld_targetid_list_buf;
Hannes Reinecke 336646
 	dma_addr_t ld_targetid_list_buf_h;
Hannes Reinecke 336646
 
Hannes Reinecke 336646
+	struct MR_HOST_DEVICE_LIST *host_device_list_buf;
Hannes Reinecke 336646
+	dma_addr_t host_device_list_buf_h;
Hannes Reinecke 336646
+
Hannes Reinecke 336646
 	struct MR_SNAPDUMP_PROPERTIES *snapdump_prop;
Hannes Reinecke 336646
 	dma_addr_t snapdump_prop_h;
Hannes Reinecke 336646
 
Hannes Reinecke 336646
@@ -2337,6 +2377,7 @@ struct megasas_instance {
Hannes Reinecke 336646
 	u8 task_abort_tmo;
Hannes Reinecke 336646
 	u8 max_reset_tmo;
Hannes Reinecke 336646
 	u8 snapdump_wait_time;
Hannes Reinecke 336646
+	u8 enable_fw_dev_list;
Hannes Reinecke 336646
 };
Hannes Reinecke 336646
 struct MR_LD_VF_MAP {
Hannes Reinecke 336646
 	u32 size;
Hannes Reinecke 336646
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
Hannes Reinecke 336646
index e6dd1aab9931..37e811d9c4c4 100644
Hannes Reinecke 336646
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
Hannes Reinecke 336646
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
Hannes Reinecke 336646
@@ -4640,6 +4640,123 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type)
Hannes Reinecke 336646
 	return ret;
Hannes Reinecke 336646
 }
Hannes Reinecke 336646
 
Hannes Reinecke 336646
+/**
Hannes Reinecke 336646
+ * dcmd.opcode            - MR_DCMD_CTRL_DEVICE_LIST_GET
Hannes Reinecke 336646
+ * dcmd.mbox              - reserved
Hannes Reinecke 336646
+ * dcmd.sge IN            - ptr to return MR_HOST_DEVICE_LIST structure
Hannes Reinecke 336646
+ * Desc:    This DCMD will return the combined device list
Hannes Reinecke 336646
+ * Status:  MFI_STAT_OK - List returned successfully
Hannes Reinecke 336646
+ *          MFI_STAT_INVALID_CMD - Firmware support for the feature has been
Hannes Reinecke 336646
+ *                                 disabled
Hannes Reinecke 336646
+ * @instance:			Adapter soft state
Hannes Reinecke 336646
+ * @is_probe:			Driver probe check
Hannes Reinecke 336646
+ * Return:			0 if DCMD succeeded
Hannes Reinecke 336646
+ *				 non-zero if failed
Hannes Reinecke 336646
+ */
Hannes Reinecke 336646
+int
Hannes Reinecke 336646
+megasas_host_device_list_query(struct megasas_instance *instance,
Hannes Reinecke 336646
+			       bool is_probe)
Hannes Reinecke 336646
+{
Hannes Reinecke 336646
+	int ret, i, target_id;
Hannes Reinecke 336646
+	struct megasas_cmd *cmd;
Hannes Reinecke 336646
+	struct megasas_dcmd_frame *dcmd;
Hannes Reinecke 336646
+	struct MR_HOST_DEVICE_LIST *ci;
Hannes Reinecke 336646
+	u32 count;
Hannes Reinecke 336646
+	dma_addr_t ci_h;
Hannes Reinecke 336646
+
Hannes Reinecke 336646
+	ci = instance->host_device_list_buf;
Hannes Reinecke 336646
+	ci_h = instance->host_device_list_buf_h;
Hannes Reinecke 336646
+
Hannes Reinecke 336646
+	cmd = megasas_get_cmd(instance);
Hannes Reinecke 336646
+
Hannes Reinecke 336646
+	if (!cmd) {
Hannes Reinecke 336646
+		dev_warn(&instance->pdev->dev,
Hannes Reinecke 336646
+			 "%s: failed to get cmd\n",
Hannes Reinecke 336646
+			 __func__);
Hannes Reinecke 336646
+		return -ENOMEM;
Hannes Reinecke 336646
+	}
Hannes Reinecke 336646
+
Hannes Reinecke 336646
+	dcmd = &cmd->frame->dcmd;
Hannes Reinecke 336646
+
Hannes Reinecke 336646
+	memset(ci, 0, sizeof(*ci));
Hannes Reinecke 336646
+	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
Hannes Reinecke 336646
+
Hannes Reinecke 336646
+	dcmd->mbox.b[0] = is_probe ? 0 : 1;
Hannes Reinecke 336646
+	dcmd->cmd = MFI_CMD_DCMD;
Hannes Reinecke 336646
+	dcmd->cmd_status = MFI_STAT_INVALID_STATUS;
Hannes Reinecke 336646
+	dcmd->sge_count = 1;
Hannes Reinecke 336646
+	dcmd->flags = MFI_FRAME_DIR_READ;
Hannes Reinecke 336646
+	dcmd->timeout = 0;
Hannes Reinecke 336646
+	dcmd->pad_0 = 0;
Hannes Reinecke 336646
+	dcmd->data_xfer_len = cpu_to_le32(HOST_DEVICE_LIST_SZ);
Hannes Reinecke 336646
+	dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_DEVICE_LIST_GET);
Hannes Reinecke 336646
+
Hannes Reinecke 336646
+	megasas_set_dma_settings(instance, dcmd, ci_h, HOST_DEVICE_LIST_SZ);
Hannes Reinecke 336646
+
Hannes Reinecke 336646
+	if (!instance->mask_interrupts) {
Hannes Reinecke 336646
+		ret = megasas_issue_blocked_cmd(instance, cmd,
Hannes Reinecke 336646
+						MFI_IO_TIMEOUT_SECS);
Hannes Reinecke 336646
+	} else {
Hannes Reinecke 336646
+		ret = megasas_issue_polled(instance, cmd);
Hannes Reinecke 336646
+		cmd->flags |= DRV_DCMD_SKIP_REFIRE;
Hannes Reinecke 336646
+	}
Hannes Reinecke 336646
+
Hannes Reinecke 336646
+	switch (ret) {
Hannes Reinecke 336646
+	case DCMD_SUCCESS:
Hannes Reinecke 336646
+		/* Fill the internal pd_list and ld_ids array based on
Hannes Reinecke 336646
+		 * targetIds returned by FW
Hannes Reinecke 336646
+		 */
Hannes Reinecke 336646
+		count = le32_to_cpu(ci->count);
Hannes Reinecke 336646
+
Hannes Reinecke 336646
+		memset(instance->local_pd_list, 0,
Hannes Reinecke 336646
+		       MEGASAS_MAX_PD * sizeof(struct megasas_pd_list));
Hannes Reinecke 336646
+		memset(instance->ld_ids, 0xff, MAX_LOGICAL_DRIVES_EXT);
Hannes Reinecke 336646
+		for (i = 0; i < count; i++) {
Hannes Reinecke 336646
+			target_id = le16_to_cpu(ci->host_device_list[i].target_id);
Hannes Reinecke 336646
+			if (ci->host_device_list[i].flags.u.bits.is_sys_pd) {
Hannes Reinecke 336646
+				instance->local_pd_list[target_id].tid = target_id;
Hannes Reinecke 336646
+				instance->local_pd_list[target_id].driveType =
Hannes Reinecke 336646
+						ci->host_device_list[i].scsi_type;
Hannes Reinecke 336646
+				instance->local_pd_list[target_id].driveState =
Hannes Reinecke 336646
+						MR_PD_STATE_SYSTEM;
Hannes Reinecke 336646
+			} else {
Hannes Reinecke 336646
+				instance->ld_ids[target_id] = target_id;
Hannes Reinecke 336646
+			}
Hannes Reinecke 336646
+		}
Hannes Reinecke 336646
+
Hannes Reinecke 336646
+		memcpy(instance->pd_list, instance->local_pd_list,
Hannes Reinecke 336646
+		       sizeof(instance->pd_list));
Hannes Reinecke 336646
+		break;
Hannes Reinecke 336646
+
Hannes Reinecke 336646
+	case DCMD_TIMEOUT:
Hannes Reinecke 336646
+		switch (dcmd_timeout_ocr_possible(instance)) {
Hannes Reinecke 336646
+		case INITIATE_OCR:
Hannes Reinecke 336646
+			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
Hannes Reinecke 336646
+			megasas_reset_fusion(instance->host,
Hannes Reinecke 336646
+				MFI_IO_TIMEOUT_OCR);
Hannes Reinecke 336646
+			break;
Hannes Reinecke 336646
+		case KILL_ADAPTER:
Hannes Reinecke 336646
+			megaraid_sas_kill_hba(instance);
Hannes Reinecke 336646
+			break;
Hannes Reinecke 336646
+		case IGNORE_TIMEOUT:
Hannes Reinecke 336646
+			dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
Hannes Reinecke 336646
+				 __func__, __LINE__);
Hannes Reinecke 336646
+			break;
Hannes Reinecke 336646
+		}
Hannes Reinecke 336646
+		break;
Hannes Reinecke 336646
+	case DCMD_FAILED:
Hannes Reinecke 336646
+		dev_err(&instance->pdev->dev,
Hannes Reinecke 336646
+			"%s: MR_DCMD_CTRL_DEVICE_LIST_GET failed\n",
Hannes Reinecke 336646
+			__func__);
Hannes Reinecke 336646
+		break;
Hannes Reinecke 336646
+	}
Hannes Reinecke 336646
+
Hannes Reinecke 336646
+	if (ret != DCMD_TIMEOUT)
Hannes Reinecke 336646
+		megasas_return_cmd(instance, cmd);
Hannes Reinecke 336646
+
Hannes Reinecke 336646
+	return ret;
Hannes Reinecke 336646
+}
Hannes Reinecke 336646
+
Hannes Reinecke 336646
 /*
Hannes Reinecke 336646
  * megasas_update_ext_vd_details : Update details w.r.t Extended VD
Hannes Reinecke 336646
  * instance			 : Controller's instance
Hannes Reinecke 336646
@@ -4867,6 +4984,9 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
Hannes Reinecke 336646
 			(ci->properties.on_off_properties2.enable_snap_dump ?
Hannes Reinecke 336646
 			 MEGASAS_DEFAULT_SNAP_DUMP_WAIT_TIME : 0);
Hannes Reinecke 336646
 
Hannes Reinecke 336646
+		instance->enable_fw_dev_list =
Hannes Reinecke 336646
+			ci->properties.on_off_properties2.enable_fw_dev_list;
Hannes Reinecke 336646
+
Hannes Reinecke 336646
 		dev_info(&instance->pdev->dev,
Hannes Reinecke 336646
 			"controller type\t: %s(%dMB)\n",
Hannes Reinecke 336646
 			instance->is_imr ? "iMR" : "MR",
Hannes Reinecke 336646
@@ -5331,6 +5451,8 @@ static void megasas_setup_reply_map(struct megasas_instance *instance)
Hannes Reinecke 336646
  * @return:			Success or failure
Hannes Reinecke 336646
  *
Hannes Reinecke 336646
  * Issue DCMDs to Firmware to get the PD and LD list.
Hannes Reinecke 336646
+ * Based on the FW support, driver sends the HOST_DEVICE_LIST or combination
Hannes Reinecke 336646
+ * of PD_LIST/LD_LIST_QUERY DCMDs to get the device list.
Hannes Reinecke 336646
  */
Hannes Reinecke 336646
 static
Hannes Reinecke 336646
 int megasas_get_device_list(struct megasas_instance *instance)
Hannes Reinecke 336646
@@ -5339,15 +5461,20 @@ int megasas_get_device_list(struct megasas_instance *instance)
Hannes Reinecke 336646
 	       (MEGASAS_MAX_PD * sizeof(struct megasas_pd_list)));
Hannes Reinecke 336646
 	memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
Hannes Reinecke 336646
 
Hannes Reinecke 336646
-	if (megasas_get_pd_list(instance) < 0) {
Hannes Reinecke 336646
-		dev_err(&instance->pdev->dev, "failed to get PD list\n");
Hannes Reinecke 336646
-		return FAILED;
Hannes Reinecke 336646
-	}
Hannes Reinecke 336646
+	if (instance->enable_fw_dev_list) {
Hannes Reinecke 336646
+		if (megasas_host_device_list_query(instance, true))
Hannes Reinecke 336646
+			return FAILED;
Hannes Reinecke 336646
+	} else {
Hannes Reinecke 336646
+		if (megasas_get_pd_list(instance) < 0) {
Hannes Reinecke 336646
+			dev_err(&instance->pdev->dev, "failed to get PD list\n");
Hannes Reinecke 336646
+			return FAILED;
Hannes Reinecke 336646
+		}
Hannes Reinecke 336646
 
Hannes Reinecke 336646
-	if (megasas_ld_list_query(instance,
Hannes Reinecke 336646
-				  MR_LD_QUERY_TYPE_EXPOSED_TO_HOST)) {
Hannes Reinecke 336646
-		dev_err(&instance->pdev->dev, "failed to get LD list\n");
Hannes Reinecke 336646
-		return FAILED;
Hannes Reinecke 336646
+		if (megasas_ld_list_query(instance,
Hannes Reinecke 336646
+					  MR_LD_QUERY_TYPE_EXPOSED_TO_HOST)) {
Hannes Reinecke 336646
+			dev_err(&instance->pdev->dev, "failed to get LD list\n");
Hannes Reinecke 336646
+			return FAILED;
Hannes Reinecke 336646
+		}
Hannes Reinecke 336646
 	}
Hannes Reinecke 336646
 
Hannes Reinecke 336646
 	return SUCCESS;
Hannes Reinecke 336646
@@ -6449,6 +6576,18 @@ int megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance)
Hannes Reinecke 336646
 		if (!instance->snapdump_prop)
Hannes Reinecke 336646
 			dev_err(&pdev->dev,
Hannes Reinecke 336646
 				"Failed to allocate snapdump properties buffer\n");
Hannes Reinecke 336646
+
Hannes Reinecke 336646
+		instance->host_device_list_buf = dma_alloc_coherent(&pdev->dev,
Hannes Reinecke 336646
+							HOST_DEVICE_LIST_SZ,
Hannes Reinecke 336646
+							&instance->host_device_list_buf_h,
Hannes Reinecke 336646
+							GFP_KERNEL);
Hannes Reinecke 336646
+
Hannes Reinecke 336646
+		if (!instance->host_device_list_buf) {
Hannes Reinecke 336646
+			dev_err(&pdev->dev,
Hannes Reinecke 336646
+				"Failed to allocate targetid list buffer\n");
Hannes Reinecke 336646
+			return -ENOMEM;
Hannes Reinecke 336646
+		}
Hannes Reinecke 336646
+
Hannes Reinecke 336646
 	}
Hannes Reinecke 336646
 
Hannes Reinecke 336646
 	instance->pd_list_buf =
Hannes Reinecke 336646
@@ -6598,6 +6737,13 @@ void megasas_free_ctrl_dma_buffers(struct megasas_instance *instance)
Hannes Reinecke 336646
 				  sizeof(struct MR_SNAPDUMP_PROPERTIES),
Hannes Reinecke 336646
 				  instance->snapdump_prop,
Hannes Reinecke 336646
 				  instance->snapdump_prop_h);
Hannes Reinecke 336646
+
Hannes Reinecke 336646
+	if (instance->host_device_list_buf)
Hannes Reinecke 336646
+		dma_free_coherent(&pdev->dev,
Hannes Reinecke 336646
+				  HOST_DEVICE_LIST_SZ,
Hannes Reinecke 336646
+				  instance->host_device_list_buf,
Hannes Reinecke 336646
+				  instance->host_device_list_buf_h);
Hannes Reinecke 336646
+
Hannes Reinecke 336646
 }
Hannes Reinecke 336646
 
Hannes Reinecke 336646
 /*
Hannes Reinecke 336646
@@ -6771,7 +6917,9 @@ static int megasas_probe_one(struct pci_dev *pdev,
Hannes Reinecke 336646
 	/*
Hannes Reinecke 336646
 	 * Trigger SCSI to scan our drives
Hannes Reinecke 336646
 	 */
Hannes Reinecke 336646
-	scsi_scan_host(host);
Hannes Reinecke 336646
+	if (!instance->enable_fw_dev_list ||
Hannes Reinecke 336646
+	    (instance->host_device_list_buf->count > 0))
Hannes Reinecke 336646
+		scsi_scan_host(host);
Hannes Reinecke 336646
 
Hannes Reinecke 336646
 	/*
Hannes Reinecke 336646
 	 * Initiate AEN (Asynchronous Event Notification)
Hannes Reinecke 336646
@@ -7900,6 +8048,8 @@ static inline void megasas_remove_scsi_device(struct scsi_device *sdev)
Hannes Reinecke 336646
  * @return:			Success or failure
Hannes Reinecke 336646
  *
Hannes Reinecke 336646
  * Issue DCMDs to Firmware to update the internal device list in driver.
Hannes Reinecke 336646
+ * Based on the FW support, driver sends the HOST_DEVICE_LIST or combination
Hannes Reinecke 336646
+ * of PD_LIST/LD_LIST_QUERY DCMDs to get the device list.
Hannes Reinecke 336646
  */
Hannes Reinecke 336646
 static
Hannes Reinecke 336646
 int megasas_update_device_list(struct megasas_instance *instance,
Hannes Reinecke 336646
@@ -7907,22 +8057,28 @@ int megasas_update_device_list(struct megasas_instance *instance,
Hannes Reinecke 336646
 {
Hannes Reinecke 336646
 	int dcmd_ret = DCMD_SUCCESS;
Hannes Reinecke 336646
 
Hannes Reinecke 336646
-	if (event_type & SCAN_PD_CHANNEL) {
Hannes Reinecke 336646
-		dcmd_ret = megasas_get_pd_list(instance);
Hannes Reinecke 336646
-
Hannes Reinecke 336646
+	if (instance->enable_fw_dev_list) {
Hannes Reinecke 336646
+		dcmd_ret = megasas_host_device_list_query(instance, false);
Hannes Reinecke 336646
 		if (dcmd_ret != DCMD_SUCCESS)
Hannes Reinecke 336646
 			goto out;
Hannes Reinecke 336646
-	}
Hannes Reinecke 336646
+	} else {
Hannes Reinecke 336646
+		if (event_type & SCAN_PD_CHANNEL) {
Hannes Reinecke 336646
+			dcmd_ret = megasas_get_pd_list(instance);
Hannes Reinecke 336646
 
Hannes Reinecke 336646
-	if (event_type & SCAN_VD_CHANNEL) {
Hannes Reinecke 336646
-		if (!instance->requestorId ||
Hannes Reinecke 336646
-		    (instance->requestorId &&
Hannes Reinecke 336646
-		     megasas_get_ld_vf_affiliation(instance, 0))) {
Hannes Reinecke 336646
-			dcmd_ret = megasas_ld_list_query(instance,
Hannes Reinecke 336646
-					MR_LD_QUERY_TYPE_EXPOSED_TO_HOST);
Hannes Reinecke 336646
 			if (dcmd_ret != DCMD_SUCCESS)
Hannes Reinecke 336646
 				goto out;
Hannes Reinecke 336646
 		}
Hannes Reinecke 336646
+
Hannes Reinecke 336646
+		if (event_type & SCAN_VD_CHANNEL) {
Hannes Reinecke 336646
+			if (!instance->requestorId ||
Hannes Reinecke 336646
+			    (instance->requestorId &&
Hannes Reinecke 336646
+			     megasas_get_ld_vf_affiliation(instance, 0))) {
Hannes Reinecke 336646
+				dcmd_ret = megasas_ld_list_query(instance,
Hannes Reinecke 336646
+						MR_LD_QUERY_TYPE_EXPOSED_TO_HOST);
Hannes Reinecke 336646
+				if (dcmd_ret != DCMD_SUCCESS)
Hannes Reinecke 336646
+					goto out;
Hannes Reinecke 336646
+			}
Hannes Reinecke 336646
+		}
Hannes Reinecke 336646
 	}
Hannes Reinecke 336646
 
Hannes Reinecke 336646
 out:
Hannes Reinecke 336646
@@ -7943,11 +8099,39 @@ void megasas_add_remove_devices(struct megasas_instance *instance,
Hannes Reinecke 336646
 	int i, j;
Hannes Reinecke 336646
 	u16 pd_index = 0;
Hannes Reinecke 336646
 	u16 ld_index = 0;
Hannes Reinecke 336646
+	u16 channel = 0, id = 0;
Hannes Reinecke 336646
 	struct Scsi_Host *host;
Hannes Reinecke 336646
 	struct scsi_device *sdev1;
Hannes Reinecke 336646
+	struct MR_HOST_DEVICE_LIST *targetid_list = NULL;
Hannes Reinecke 336646
+	struct MR_HOST_DEVICE_LIST_ENTRY *targetid_entry = NULL;
Hannes Reinecke 336646
 
Hannes Reinecke 336646
 	host = instance->host;
Hannes Reinecke 336646
 
Hannes Reinecke 336646
+	if (instance->enable_fw_dev_list) {
Hannes Reinecke 336646
+		targetid_list = instance->host_device_list_buf;
Hannes Reinecke 336646
+		for (i = 0; i < targetid_list->count; i++) {
Hannes Reinecke 336646
+			targetid_entry = &targetid_list->host_device_list[i];
Hannes Reinecke 336646
+			if (targetid_entry->flags.u.bits.is_sys_pd) {
Hannes Reinecke 336646
+				channel = le16_to_cpu(targetid_entry->target_id) /
Hannes Reinecke 336646
+						MEGASAS_MAX_DEV_PER_CHANNEL;
Hannes Reinecke 336646
+				id = le16_to_cpu(targetid_entry->target_id) %
Hannes Reinecke 336646
+						MEGASAS_MAX_DEV_PER_CHANNEL;
Hannes Reinecke 336646
+			} else {
Hannes Reinecke 336646
+				channel = MEGASAS_MAX_PD_CHANNELS +
Hannes Reinecke 336646
+					  (le16_to_cpu(targetid_entry->target_id) /
Hannes Reinecke 336646
+					   MEGASAS_MAX_DEV_PER_CHANNEL);
Hannes Reinecke 336646
+				id = le16_to_cpu(targetid_entry->target_id) %
Hannes Reinecke 336646
+						MEGASAS_MAX_DEV_PER_CHANNEL;
Hannes Reinecke 336646
+			}
Hannes Reinecke 336646
+			sdev1 = scsi_device_lookup(host, channel, id, 0);
Hannes Reinecke 336646
+			if (!sdev1) {
Hannes Reinecke 336646
+				scsi_add_device(host, channel, id, 0);
Hannes Reinecke 336646
+			} else {
Hannes Reinecke 336646
+				scsi_device_put(sdev1);
Hannes Reinecke 336646
+			}
Hannes Reinecke 336646
+		}
Hannes Reinecke 336646
+	}
Hannes Reinecke 336646
+
Hannes Reinecke 336646
 	if (scan_type & SCAN_PD_CHANNEL) {
Hannes Reinecke 336646
 		for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
Hannes Reinecke 336646
 			for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
Hannes Reinecke 336646
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
Hannes Reinecke 336646
index 3cecee38b192..4e912e01bb89 100644
Hannes Reinecke 336646
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
Hannes Reinecke 336646
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
Hannes Reinecke 336646
@@ -1074,6 +1074,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
Hannes Reinecke 336646
 	drv_ops->mfi_capabilities.support_qd_throttling = 1;
Hannes Reinecke 336646
 	drv_ops->mfi_capabilities.support_pd_map_target_id = 1;
Hannes Reinecke 336646
 	drv_ops->mfi_capabilities.support_nvme_passthru = 1;
Hannes Reinecke 336646
+	drv_ops->mfi_capabilities.support_fw_exposed_dev_list = 1;
Hannes Reinecke 336646
 
Hannes Reinecke 336646
 	if (instance->consistent_mask_64bit)
Hannes Reinecke 336646
 		drv_ops->mfi_capabilities.support_64bit_mode = 1;
Hannes Reinecke 336646
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
Hannes Reinecke 336646
index ca73c50fe723..1481bf029490 100644
Hannes Reinecke 336646
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
Hannes Reinecke 336646
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
Hannes Reinecke 336646
@@ -724,6 +724,7 @@ struct MPI2_IOC_INIT_REQUEST {
Hannes Reinecke 336646
 #define MR_DCMD_LD_VF_MAP_GET_ALL_LDS_111   0x03200200
Hannes Reinecke 336646
 #define MR_DCMD_LD_VF_MAP_GET_ALL_LDS       0x03150200
Hannes Reinecke 336646
 #define MR_DCMD_CTRL_SNAPDUMP_GET_PROPERTIES	0x01200100
Hannes Reinecke 336646
+#define MR_DCMD_CTRL_DEVICE_LIST_GET		0x01190600
Hannes Reinecke 336646
 
Hannes Reinecke 336646
 struct MR_DEV_HANDLE_INFO {
Hannes Reinecke 336646
 	__le16	curDevHdl;
Hannes Reinecke 336646
-- 
Hannes Reinecke 336646
2.16.4
Hannes Reinecke 336646