All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/15] megaraid_sas: Updates for scsi-next
@ 2015-12-18 13:26 Sumit Saxena
  2015-12-18 13:26 ` [PATCH 01/15] megaraid_sas: Do not allow PCI access during OCR Sumit Saxena
                   ` (14 more replies)
  0 siblings, 15 replies; 50+ messages in thread
From: Sumit Saxena @ 2015-12-18 13:26 UTC (permalink / raw)
  To: jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai, sumit.saxena

Sumit Saxena (15):
  megaraid_sas: Do not allow PCI access during OCR
  megaraid_sas: MFI IO timeout handling
  megaraid_sas: Syncing request flags macro names with firmware
  megaraid_sas: Task management support
  megaraid_sas: Update device Queue depth based on interface type
  megaraid_sas: Fastpath region lock bypass
  megaraid_sas: Reply Descriptor Post Queue(RDPQ) support
  megaraid_sas: Code optimization build_and_issue_cmd return-type
  megaraid_sas: Dual Queue depth support
  megaraid_sas: IO throttling support
  megaraid_sas: Make adprecovery variable atomic
  megaraid_sas: MFI adapter's OCR changes
  megaraid_sas: Introduce module parameter for SCSI command-timeout
  megaraid_sas: SPERC OCR changes
  megaraid_sas: SPERC boot driver reorder

 drivers/scsi/megaraid/megaraid_sas.h        |  366 +++++++-
 drivers/scsi/megaraid/megaraid_sas_base.c   | 1373 +++++++++++++++++++--------
 drivers/scsi/megaraid/megaraid_sas_fp.c     |    2 +
 drivers/scsi/megaraid/megaraid_sas_fusion.c | 1260 ++++++++++++++++++-------
 drivers/scsi/megaraid/megaraid_sas_fusion.h |  136 +++-
 5 files changed, 2404 insertions(+), 733 deletions(-)


^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 01/15] megaraid_sas: Do not allow PCI access during OCR
  2015-12-18 13:26 [PATCH 00/15] megaraid_sas: Updates for scsi-next Sumit Saxena
@ 2015-12-18 13:26 ` Sumit Saxena
  2016-01-11 17:02   ` Tomas Henzl
  2015-12-18 13:26 ` [PATCH 02/15] megaraid_sas: MFI IO timeout handling Sumit Saxena
                   ` (13 subsequent siblings)
  14 siblings, 1 reply; 50+ messages in thread
From: Sumit Saxena @ 2015-12-18 13:26 UTC (permalink / raw)
  To: jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai, sumit.saxena

This patch will do synhronization between OCR function and AEN function using "reset_mutex" lock.
reset_mutex will be acquire only in first half of the AEN function which issue DCMD. Second half
of the function calls SCSI API (scsi_add_device/scsi_remove_device) should be out of reset_mutex
to avoid deadlock between scsi_eh thread and Driver.

During chip reset(inside OCR function), there should not be any PCI access and AEN function
(which is called in delayed context) may be firirng DCMDs(doing PCI writes) when chip reset is
happening in parallel which will cause FW fault. This patch will solve the problem by making
AEN thread and OCR thread mutually exclusive.

Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
---
 drivers/scsi/megaraid/megaraid_sas.h      |    2 +
 drivers/scsi/megaraid/megaraid_sas_base.c |  254 +++++++++--------------------
 2 files changed, 82 insertions(+), 174 deletions(-)

diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index c0f7c8c..ef4ff03 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -1083,6 +1083,8 @@ struct megasas_ctrl_info {
 
 #define VD_EXT_DEBUG 0
 
+#define SCAN_PD_CHANNEL	0x1
+#define SCAN_VD_CHANNEL	0x2
 
 enum MR_SCSI_CMD_TYPE {
 	READ_WRITE_LDIO = 0,
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index 97a1c1c..9650487 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -5476,7 +5476,6 @@ static int megasas_probe_one(struct pci_dev *pdev,
 	spin_lock_init(&instance->hba_lock);
 	spin_lock_init(&instance->completion_lock);
 
-	mutex_init(&instance->aen_mutex);
 	mutex_init(&instance->reset_mutex);
 
 	/*
@@ -6442,10 +6441,10 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
 	}
 	spin_unlock_irqrestore(&instance->hba_lock, flags);
 
-	mutex_lock(&instance->aen_mutex);
+	mutex_lock(&instance->reset_mutex);
 	error = megasas_register_aen(instance, aen.seq_num,
 				     aen.class_locale_word);
-	mutex_unlock(&instance->aen_mutex);
+	mutex_unlock(&instance->reset_mutex);
 	return error;
 }
 
@@ -6647,6 +6646,7 @@ megasas_aen_polling(struct work_struct *work)
 	int     i, j, doscan = 0;
 	u32 seq_num, wait_time = MEGASAS_RESET_WAIT_TIME;
 	int error;
+	u8  dcmd_ret = 0;
 
 	if (!instance) {
 		printk(KERN_ERR "invalid instance!\n");
@@ -6659,16 +6659,7 @@ megasas_aen_polling(struct work_struct *work)
 		wait_time = MEGASAS_ROUTINE_WAIT_TIME_VF;
 
 	/* Don't run the event workqueue thread if OCR is running */
-	for (i = 0; i < wait_time; i++) {
-		if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL)
-			break;
-		if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
-			dev_notice(&instance->pdev->dev, "%s waiting for "
-			       "controller reset to finish for scsi%d\n",
-			       __func__, instance->host->host_no);
-		}
-		msleep(1000);
-	}
+	mutex_lock(&instance->reset_mutex);
 
 	instance->ev = NULL;
 	host = instance->host;
@@ -6676,212 +6667,127 @@ megasas_aen_polling(struct work_struct *work)
 		megasas_decode_evt(instance);
 
 		switch (le32_to_cpu(instance->evt_detail->code)) {
-		case MR_EVT_PD_INSERTED:
-			if (megasas_get_pd_list(instance) == 0) {
-			for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
-				for (j = 0;
-				j < MEGASAS_MAX_DEV_PER_CHANNEL;
-				j++) {
-
-				pd_index =
-				(i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
-				sdev1 = scsi_device_lookup(host, i, j, 0);
-
-				if (instance->pd_list[pd_index].driveState
-						== MR_PD_STATE_SYSTEM) {
-					if (!sdev1)
-						scsi_add_device(host, i, j, 0);
-
-					if (sdev1)
-						scsi_device_put(sdev1);
-					}
-				}
-			}
-			}
-			doscan = 0;
-			break;
 
+		case MR_EVT_PD_INSERTED:
 		case MR_EVT_PD_REMOVED:
-			if (megasas_get_pd_list(instance) == 0) {
-			for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
-				for (j = 0;
-				j < MEGASAS_MAX_DEV_PER_CHANNEL;
-				j++) {
-
-				pd_index =
-				(i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
-				sdev1 = scsi_device_lookup(host, i, j, 0);
-
-				if (instance->pd_list[pd_index].driveState
-					== MR_PD_STATE_SYSTEM) {
-					if (sdev1)
-						scsi_device_put(sdev1);
-				} else {
-					if (sdev1) {
-						scsi_remove_device(sdev1);
-						scsi_device_put(sdev1);
-					}
-				}
-				}
-			}
-			}
-			doscan = 0;
+			dcmd_ret = megasas_get_pd_list(instance);
+			if (dcmd_ret == 0)
+				doscan = SCAN_PD_CHANNEL;
 			break;
 
 		case MR_EVT_LD_OFFLINE:
 		case MR_EVT_CFG_CLEARED:
 		case MR_EVT_LD_DELETED:
-			if (!instance->requestorId ||
-			    megasas_get_ld_vf_affiliation(instance, 0)) {
-				if (megasas_ld_list_query(instance,
-							  MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
-					megasas_get_ld_list(instance);
-				for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
-					for (j = 0;
-					     j < MEGASAS_MAX_DEV_PER_CHANNEL;
-					     j++) {
-
-						ld_index =
-							(i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
-						sdev1 = scsi_device_lookup(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
-
-						if (instance->ld_ids[ld_index]
-						    != 0xff) {
-							if (sdev1)
-								scsi_device_put(sdev1);
-						} else {
-							if (sdev1) {
-								scsi_remove_device(sdev1);
-								scsi_device_put(sdev1);
-							}
-						}
-					}
-				}
-				doscan = 0;
-			}
-			break;
 		case MR_EVT_LD_CREATED:
 			if (!instance->requestorId ||
-			    megasas_get_ld_vf_affiliation(instance, 0)) {
-				if (megasas_ld_list_query(instance,
-							  MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
-					megasas_get_ld_list(instance);
-				for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
-					for (j = 0;
-					     j < MEGASAS_MAX_DEV_PER_CHANNEL;
-					     j++) {
-						ld_index =
-							(i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
-						sdev1 = scsi_device_lookup(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
-
-						if (instance->ld_ids[ld_index]
-						    != 0xff) {
-							if (!sdev1)
-								scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
-						}
-						if (sdev1)
-							scsi_device_put(sdev1);
-					}
-				}
-				doscan = 0;
-			}
+				(instance->requestorId && megasas_get_ld_vf_affiliation(instance, 0)))
+				dcmd_ret = megasas_ld_list_query(instance, MR_LD_QUERY_TYPE_EXPOSED_TO_HOST);
+
+			if (dcmd_ret == 0)
+				doscan = SCAN_VD_CHANNEL;
+
 			break;
+
 		case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
 		case MR_EVT_FOREIGN_CFG_IMPORTED:
 		case MR_EVT_LD_STATE_CHANGE:
-			doscan = 1;
+			dcmd_ret = megasas_get_pd_list(instance);
+
+			if (dcmd_ret != 0)
+				break;
+
+			if (!instance->requestorId ||
+				(instance->requestorId && megasas_get_ld_vf_affiliation(instance, 0)))
+				dcmd_ret = megasas_ld_list_query(instance, MR_LD_QUERY_TYPE_EXPOSED_TO_HOST);
+
+			if (dcmd_ret != 0)
+				break;
+
+			doscan = SCAN_VD_CHANNEL | SCAN_PD_CHANNEL;
+			dev_info(&instance->pdev->dev, "scanning for scsi%d...\n",
+				instance->host->host_no);
 			break;
+
 		case MR_EVT_CTRL_PROP_CHANGED:
-			megasas_get_ctrl_info(instance);
-			break;
+				dcmd_ret = megasas_get_ctrl_info(instance);
+				break;
 		default:
 			doscan = 0;
 			break;
 		}
 	} else {
 		dev_err(&instance->pdev->dev, "invalid evt_detail!\n");
+		mutex_unlock(&instance->reset_mutex);
 		kfree(ev);
 		return;
 	}
 
-	if (doscan) {
-		dev_info(&instance->pdev->dev, "scanning for scsi%d...\n",
-		       instance->host->host_no);
-		if (megasas_get_pd_list(instance) == 0) {
-			for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
-				for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
-					pd_index = i*MEGASAS_MAX_DEV_PER_CHANNEL + j;
-					sdev1 = scsi_device_lookup(host, i, j, 0);
-					if (instance->pd_list[pd_index].driveState ==
-					    MR_PD_STATE_SYSTEM) {
-						if (!sdev1) {
-							scsi_add_device(host, i, j, 0);
-						}
-						if (sdev1)
-							scsi_device_put(sdev1);
-					} else {
-						if (sdev1) {
-							scsi_remove_device(sdev1);
-							scsi_device_put(sdev1);
-						}
+	mutex_unlock(&instance->reset_mutex);
+
+	if (doscan & SCAN_PD_CHANNEL) {
+		for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
+			for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
+				pd_index = i*MEGASAS_MAX_DEV_PER_CHANNEL + j;
+				sdev1 = scsi_device_lookup(host, i, j, 0);
+				if (instance->pd_list[pd_index].driveState ==
+							MR_PD_STATE_SYSTEM) {
+					if (!sdev1)
+						scsi_add_device(host, i, j, 0);
+					else
+						scsi_device_put(sdev1);
+				} else {
+					if (sdev1) {
+						scsi_remove_device(sdev1);
+						scsi_device_put(sdev1);
 					}
 				}
 			}
 		}
+	}
 
-		if (!instance->requestorId ||
-		    megasas_get_ld_vf_affiliation(instance, 0)) {
-			if (megasas_ld_list_query(instance,
-						  MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
-				megasas_get_ld_list(instance);
-			for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
-				for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL;
-				     j++) {
-					ld_index =
-						(i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
-					sdev1 = scsi_device_lookup(host,
-								   MEGASAS_MAX_PD_CHANNELS + i, j, 0);
-					if (instance->ld_ids[ld_index]
-					    != 0xff) {
-						if (!sdev1)
-							scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
-						else
-							scsi_device_put(sdev1);
-					} else {
-						if (sdev1) {
-							scsi_remove_device(sdev1);
-							scsi_device_put(sdev1);
-						}
+	if (doscan & SCAN_VD_CHANNEL) {
+		for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
+			for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
+				ld_index = (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+				sdev1 = scsi_device_lookup(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+				if (instance->ld_ids[ld_index] != 0xff) {
+					if (!sdev1)
+						scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+					else
+						scsi_device_put(sdev1);
+				} else {
+					if (sdev1) {
+						scsi_remove_device(sdev1);
+						scsi_device_put(sdev1);
 					}
 				}
 			}
 		}
 	}
 
-	if (instance->aen_cmd != NULL) {
-		kfree(ev);
-		return ;
-	}
-
-	seq_num = le32_to_cpu(instance->evt_detail->seq_num) + 1;
+	if (dcmd_ret == 0)
+		seq_num = le32_to_cpu(instance->evt_detail->seq_num) + 1;
+	else
+		seq_num = instance->last_seq_num;
 
 	/* Register AEN with FW for latest sequence number plus 1 */
 	class_locale.members.reserved = 0;
 	class_locale.members.locale = MR_EVT_LOCALE_ALL;
 	class_locale.members.class = MR_EVT_CLASS_DEBUG;
-	mutex_lock(&instance->aen_mutex);
+
+	if (instance->aen_cmd != NULL) {
+		kfree(ev);
+		return;
+	}
+
+	mutex_lock(&instance->reset_mutex);
 	error = megasas_register_aen(instance, seq_num,
 					class_locale.word);
-	mutex_unlock(&instance->aen_mutex);
-
 	if (error)
-		dev_err(&instance->pdev->dev, "register aen failed error %x\n", error);
+		dev_err(&instance->pdev->dev,
+			"register aen failed error %x\n", error);
 
+	mutex_unlock(&instance->reset_mutex);
 	kfree(ev);
 }
 
-- 
1.7.1


^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 02/15] megaraid_sas: MFI IO timeout handling
  2015-12-18 13:26 [PATCH 00/15] megaraid_sas: Updates for scsi-next Sumit Saxena
  2015-12-18 13:26 ` [PATCH 01/15] megaraid_sas: Do not allow PCI access during OCR Sumit Saxena
@ 2015-12-18 13:26 ` Sumit Saxena
  2016-01-11 17:02   ` Tomas Henzl
  2015-12-18 13:26 ` [PATCH 03/15] megaraid_sas: Syncing request flags macro names with firmware Sumit Saxena
                   ` (12 subsequent siblings)
  14 siblings, 1 reply; 50+ messages in thread
From: Sumit Saxena @ 2015-12-18 13:26 UTC (permalink / raw)
  To: jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai, sumit.saxena

This patch will do proper error handling for DCMD timeout and failed cases for fusion adapters.
Below are few key design points-
1. For MFI adapters, in case of DCMD timeout(DCMD which must return SUCCESS) driver will call kill adapter. 
2. What action needs to be taken in case of DCMD timeout is decided by function dcmd_timeout_ocr_possible().
DCMD timeout causing OCR is applicable to below DCMDs-

MR_DCMD_PD_LIST_QUERY
MR_DCMD_LD_GET_LIST
MR_DCMD_LD_LIST_QUERY
MR_DCMD_CTRL_SET_CRASH_DUMP_PARAMS
MR_DCMD_SYSTEM_PD_MAP_GET_INFO(for non pended DCMD)
MR_DCMD_LD_MAP_GET_INFO(for non pended DCMD)

3. If DCMD fails from Driver init path, there are certain DCMD which is must to be return SUCCESS. If those DCMD fails,
driver bail out load. For optional DCMD like pd_info etc, driver continue without executing certain functionality.

Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
---
 drivers/scsi/megaraid/megaraid_sas.h        |   22 ++-
 drivers/scsi/megaraid/megaraid_sas_base.c   |  372 ++++++++++++++++++++-------
 drivers/scsi/megaraid/megaraid_sas_fusion.c |   54 +++--
 3 files changed, 338 insertions(+), 110 deletions(-)

diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index ef4ff03..dcc6ff8 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -170,6 +170,7 @@
 
 /* Driver internal */
 #define DRV_DCMD_POLLED_MODE		0x1
+#define DRV_DCMD_SKIP_REFIRE		0x2
 
 /*
  * Definition for cmd_status
@@ -1093,6 +1094,11 @@ enum MR_SCSI_CMD_TYPE {
 	NON_READ_WRITE_SYSPDIO = 3,
 };
 
+enum DCMD_TIMEOUT_ACTION {
+	INITIATE_OCR = 0,
+	KILL_ADAPTER = 1,
+	IGNORE_TIMEOUT = 2,
+};
 /* Frame Type */
 #define IO_FRAME				0
 #define PTHRU_FRAME				1
@@ -1139,6 +1145,7 @@ enum MR_SCSI_CMD_TYPE {
 
 #define MFI_OB_INTR_STATUS_MASK			0x00000002
 #define MFI_POLL_TIMEOUT_SECS			60
+#define MFI_IO_TIMEOUT_SECS			180
 #define MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF	(5 * HZ)
 #define MEGASAS_OCR_SETTLE_TIME_VF		(1000 * 30)
 #define MEGASAS_ROUTINE_WAIT_TIME_VF		300
@@ -1918,7 +1925,7 @@ struct megasas_instance_template {
 	u32 (*init_adapter)(struct megasas_instance *);
 	u32 (*build_and_issue_cmd) (struct megasas_instance *,
 				    struct scsi_cmnd *);
-	void (*issue_dcmd) (struct megasas_instance *instance,
+	int (*issue_dcmd)(struct megasas_instance *instance,
 			    struct megasas_cmd *cmd);
 };
 
@@ -2016,6 +2023,19 @@ struct megasas_mgmt_info {
 	int max_index;
 };
 
+enum MEGASAS_OCR_CAUSE {
+	FW_FAULT_OCR			= 0,
+	SCSIIO_TIMEOUT_OCR		= 1,
+	MFI_IO_TIMEOUT_OCR		= 2,
+};
+
+enum DCMD_RETURN_STATUS {
+	DCMD_SUCCESS		= 0,
+	DCMD_TIMEOUT		= 1,
+	DCMD_FAILED		= 2,
+	DCMD_NOT_FIRED		= 3,
+};
+
 u8
 MR_BuildRaidContext(struct megasas_instance *instance,
 		    struct IO_REQUEST_INFO *io_info,
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index 9650487..380c627 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -196,11 +196,12 @@ static int megasas_get_ld_vf_affiliation(struct megasas_instance *instance,
 int megasas_check_mpio_paths(struct megasas_instance *instance,
 			     struct scsi_cmnd *scmd);
 
-void
+int
 megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
 {
 	instance->instancet->fire_cmd(instance,
 		cmd->frame_phys_addr, 0, instance->reg_set);
+	return 0;
 }
 
 /**
@@ -983,25 +984,20 @@ extern struct megasas_instance_template megasas_instance_template_fusion;
 int
 megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
 {
-	int seconds;
 	struct megasas_header *frame_hdr = &cmd->frame->hdr;
 
-	frame_hdr->cmd_status = MFI_CMD_STATUS_POLL_MODE;
+	frame_hdr->cmd_status = MFI_STAT_INVALID_STATUS;
 	frame_hdr->flags |= cpu_to_le16(MFI_FRAME_DONT_POST_IN_REPLY_QUEUE);
 
-	/*
-	 * Issue the frame using inbound queue port
-	 */
-	instance->instancet->issue_dcmd(instance, cmd);
+	if ((instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) ||
+		(instance->instancet->issue_dcmd(instance, cmd))) {
+		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
+			__func__, __LINE__);
+		return DCMD_NOT_FIRED;
+	}
 
-	/*
-	 * Wait for cmd_status to change
-	 */
-	if (instance->requestorId)
-		seconds = MEGASAS_ROUTINE_WAIT_TIME_VF;
-	else
-		seconds = MFI_POLL_TIMEOUT_SECS;
-	return wait_and_poll(instance, cmd, seconds);
+	return wait_and_poll(instance, cmd, instance->requestorId ?
+			MEGASAS_ROUTINE_WAIT_TIME_VF : MFI_IO_TIMEOUT_SECS);
 }
 
 /**
@@ -1019,21 +1015,29 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
 			  struct megasas_cmd *cmd, int timeout)
 {
 	int ret = 0;
-
 	cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
 
-	instance->instancet->issue_dcmd(instance, cmd);
+	if ((instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) ||
+		(instance->instancet->issue_dcmd(instance, cmd))) {
+		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
+			__func__, __LINE__);
+		return DCMD_NOT_FIRED;
+	}
+
 	if (timeout) {
 		ret = wait_event_timeout(instance->int_cmd_wait_q,
 				cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS, timeout * HZ);
-		if (!ret)
-			return 1;
+		if (!ret) {
+			dev_err(&instance->pdev->dev, "Failed from %s %d DCMD Timed out\n",
+				__func__, __LINE__);
+			return DCMD_TIMEOUT;
+		}
 	} else
 		wait_event(instance->int_cmd_wait_q,
 				cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS);
 
 	return (cmd->cmd_status_drv == MFI_STAT_OK) ?
-		0 : 1;
+		DCMD_SUCCESS : DCMD_FAILED;
 }
 
 /**
@@ -1077,15 +1081,20 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
 	cmd->sync_cmd = 1;
 	cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
 
-	instance->instancet->issue_dcmd(instance, cmd);
+	if ((instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) ||
+		(instance->instancet->issue_dcmd(instance, cmd))) {
+		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
+			__func__, __LINE__);
+		return DCMD_NOT_FIRED;
+	}
 
 	if (timeout) {
 		ret = wait_event_timeout(instance->abort_cmd_wait_q,
 				cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS, timeout * HZ);
 		if (!ret) {
-			dev_err(&instance->pdev->dev, "Command timedout"
-				"from %s\n", __func__);
-			return 1;
+			dev_err(&instance->pdev->dev, "Failed from %s %d Abort Timed out\n",
+				__func__, __LINE__);
+			return DCMD_TIMEOUT;
 		}
 	} else
 		wait_event(instance->abort_cmd_wait_q,
@@ -1094,7 +1103,8 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
 	cmd->sync_cmd = 0;
 
 	megasas_return_cmd(instance, cmd);
-	return 0;
+	return (cmd->cmd_status_drv == MFI_STAT_OK) ?
+		DCMD_SUCCESS : DCMD_FAILED;
 }
 
 /**
@@ -2054,9 +2064,7 @@ static int megasas_get_ld_vf_affiliation_111(struct megasas_instance *instance,
 	dev_warn(&instance->pdev->dev, "SR-IOV: Getting LD/VF affiliation for "
 	       "scsi%d\n", instance->host->host_no);
 
-	megasas_issue_blocked_cmd(instance, cmd, 0);
-
-	if (dcmd->cmd_status) {
+	if (megasas_issue_blocked_cmd(instance, cmd, 0) != DCMD_SUCCESS) {
 		dev_warn(&instance->pdev->dev, "SR-IOV: LD/VF affiliation DCMD"
 		       " failed with status 0x%x for scsi%d\n",
 		       dcmd->cmd_status, instance->host->host_no);
@@ -2166,9 +2174,8 @@ static int megasas_get_ld_vf_affiliation_12(struct megasas_instance *instance,
 	dev_warn(&instance->pdev->dev, "SR-IOV: Getting LD/VF affiliation for "
 	       "scsi%d\n", instance->host->host_no);
 
-	megasas_issue_blocked_cmd(instance, cmd, 0);
 
-	if (dcmd->cmd_status) {
+	if (megasas_issue_blocked_cmd(instance, cmd, 0) != DCMD_SUCCESS) {
 		dev_warn(&instance->pdev->dev, "SR-IOV: LD/VF affiliation DCMD"
 		       " failed with status 0x%x for scsi%d\n",
 		       dcmd->cmd_status, instance->host->host_no);
@@ -3852,6 +3859,25 @@ int megasas_alloc_cmds(struct megasas_instance *instance)
 }
 
 /*
+ * dcmd_timeout_ocr_possible -	Check if OCR is possible based on Driver/FW state.
+ * @instance:				Adapter soft state
+ *
+ * Return 0 for only Fusion adapter, if driver load/unload is not in progress
+ * or FW is not under OCR.
+ */
+inline int
+dcmd_timeout_ocr_possible(struct megasas_instance *instance) {
+
+	if (!instance->ctrl_context)
+		return KILL_ADAPTER;
+	else if (instance->unload ||
+			test_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags))
+		return IGNORE_TIMEOUT;
+	else
+		return INITIATE_OCR;
+}
+
+/*
  * megasas_get_pd_list_info -	Returns FW's pd_list structure
  * @instance:				Adapter soft state
  * @pd_list:				pd_list structure
@@ -3906,42 +3932,72 @@ megasas_get_pd_list(struct megasas_instance *instance)
 
 	if (instance->ctrl_context && !instance->mask_interrupts)
 		ret = megasas_issue_blocked_cmd(instance, cmd,
-			MEGASAS_BLOCKED_CMD_TIMEOUT);
+			MFI_IO_TIMEOUT_SECS);
 	else
 		ret = megasas_issue_polled(instance, cmd);
 
-	/*
-	 * the following function will get the instance PD LIST.
-	 */
+	switch (ret) {
+	case DCMD_FAILED:
+		megaraid_sas_kill_hba(instance);
+		break;
+	case DCMD_TIMEOUT:
 
-	pd_addr = ci->addr;
+		switch (dcmd_timeout_ocr_possible(instance)) {
+		case INITIATE_OCR:
+			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+			/*
+			 * DCMD failed from AEN path.
+			 * AEN path already hold reset_mutex to avoid PCI access
+			 * while OCR is in progress.
+			 */
+			mutex_unlock(&instance->reset_mutex);
+			megasas_reset_fusion(instance->host,
+						MFI_IO_TIMEOUT_OCR);
+			mutex_lock(&instance->reset_mutex);
+			break;
+		case KILL_ADAPTER:
+			megaraid_sas_kill_hba(instance);
+			break;
+		case IGNORE_TIMEOUT:
+			dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d \n",
+				__func__, __LINE__);
+			break;
+		}
 
-	if (ret == 0 &&
-	     (le32_to_cpu(ci->count) <
-		  (MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL))) {
+		break;
+
+	case DCMD_SUCCESS:
+		pd_addr = ci->addr;
+
+		if ((le32_to_cpu(ci->count) >
+			(MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL)))
+			break;
 
 		memset(instance->local_pd_list, 0,
-			MEGASAS_MAX_PD * sizeof(struct megasas_pd_list));
+				MEGASAS_MAX_PD * sizeof(struct megasas_pd_list));
 
 		for (pd_index = 0; pd_index < le32_to_cpu(ci->count); pd_index++) {
-
 			instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].tid	=
-				le16_to_cpu(pd_addr->deviceId);
+					le16_to_cpu(pd_addr->deviceId);
 			instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].driveType	=
-							pd_addr->scsiDevType;
+					pd_addr->scsiDevType;
 			instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].driveState	=
-							MR_PD_STATE_SYSTEM;
+					MR_PD_STATE_SYSTEM;
 			pd_addr++;
 		}
+
 		memcpy(instance->pd_list, instance->local_pd_list,
 			sizeof(instance->pd_list));
+		break;
+
 	}
 
 	pci_free_consistent(instance->pdev,
 				MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST),
 				ci, ci_h);
 
-	megasas_return_cmd(instance, cmd);
+	if (ret != DCMD_TIMEOUT)
+		megasas_return_cmd(instance, cmd);
 
 	return ret;
 }
@@ -4002,33 +4058,63 @@ megasas_get_ld_list(struct megasas_instance *instance)
 
 	if (instance->ctrl_context && !instance->mask_interrupts)
 		ret = megasas_issue_blocked_cmd(instance, cmd,
-			MEGASAS_BLOCKED_CMD_TIMEOUT);
+			MFI_IO_TIMEOUT_SECS);
 	else
 		ret = megasas_issue_polled(instance, cmd);
 
-
 	ld_count = le32_to_cpu(ci->ldCount);
 
-	/* the following function will get the instance PD LIST */
+	switch (ret) {
+	case DCMD_FAILED:
+		megaraid_sas_kill_hba(instance);
+		break;
+	case DCMD_TIMEOUT:
+
+		switch (dcmd_timeout_ocr_possible(instance)) {
+		case INITIATE_OCR:
+			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+			/*
+			 * DCMD failed from AEN path.
+			 * AEN path already hold reset_mutex to avoid PCI access
+			 * while OCR is in progress.
+			 */
+			mutex_unlock(&instance->reset_mutex);
+			megasas_reset_fusion(instance->host,
+						MFI_IO_TIMEOUT_OCR);
+			mutex_lock(&instance->reset_mutex);
+			break;
+		case KILL_ADAPTER:
+			megaraid_sas_kill_hba(instance);
+			break;
+		case IGNORE_TIMEOUT:
+			dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
+				__func__, __LINE__);
+			break;
+		}
+
+		break;
+
+	case DCMD_SUCCESS:
+		if (ld_count > instance->fw_supported_vd_count)
+			break;
 
-	if ((ret == 0) && (ld_count <= instance->fw_supported_vd_count)) {
 		memset(instance->ld_ids, 0xff, MAX_LOGICAL_DRIVES_EXT);
 
 		for (ld_index = 0; ld_index < ld_count; ld_index++) {
 			if (ci->ldList[ld_index].state != 0) {
 				ids = ci->ldList[ld_index].ref.targetId;
-				instance->ld_ids[ids] =
-					ci->ldList[ld_index].ref.targetId;
+				instance->ld_ids[ids] = ci->ldList[ld_index].ref.targetId;
 			}
 		}
+
+		break;
 	}
 
-	pci_free_consistent(instance->pdev,
-				sizeof(struct MR_LD_LIST),
-				ci,
-				ci_h);
+	pci_free_consistent(instance->pdev, sizeof(struct MR_LD_LIST), ci, ci_h);
+
+	if (ret != DCMD_TIMEOUT)
+		megasas_return_cmd(instance, cmd);
 
-	megasas_return_cmd(instance, cmd);
 	return ret;
 }
 
@@ -4090,26 +4176,61 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type)
 	dcmd->pad_0  = 0;
 
 	if (instance->ctrl_context && !instance->mask_interrupts)
-		ret = megasas_issue_blocked_cmd(instance, cmd,
-			MEGASAS_BLOCKED_CMD_TIMEOUT);
+		ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
 	else
 		ret = megasas_issue_polled(instance, cmd);
 
-	tgtid_count = le32_to_cpu(ci->count);
+	switch (ret) {
+	case DCMD_FAILED:
+		dev_info(&instance->pdev->dev,
+			"DCMD not supported by firmware - %s %d\n",
+				__func__, __LINE__);
+		ret = megasas_get_ld_list(instance);
+		break;
+	case DCMD_TIMEOUT:
+		switch (dcmd_timeout_ocr_possible(instance)) {
+		case INITIATE_OCR:
+			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+			/*
+			 * DCMD failed from AEN path.
+			 * AEN path already hold reset_mutex to avoid PCI access
+			 * while OCR is in progress.
+			 */
+			mutex_unlock(&instance->reset_mutex);
+			megasas_reset_fusion(instance->host,
+						MFI_IO_TIMEOUT_OCR);
+			mutex_lock(&instance->reset_mutex);
+			break;
+		case KILL_ADAPTER:
+			megaraid_sas_kill_hba(instance);
+			break;
+		case IGNORE_TIMEOUT:
+			dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
+				__func__, __LINE__);
+			break;
+		}
+
+		break;
+	case DCMD_SUCCESS:
+		tgtid_count = le32_to_cpu(ci->count);
+
+		if ((tgtid_count > (instance->fw_supported_vd_count)))
+			break;
 
-	if ((ret == 0) && (tgtid_count <= (instance->fw_supported_vd_count))) {
 		memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
 		for (ld_index = 0; ld_index < tgtid_count; ld_index++) {
 			ids = ci->targetId[ld_index];
 			instance->ld_ids[ids] = ci->targetId[ld_index];
 		}
 
+		break;
 	}
 
 	pci_free_consistent(instance->pdev, sizeof(struct MR_LD_TARGETID_LIST),
-			    ci, ci_h);
+		    ci, ci_h);
 
-	megasas_return_cmd(instance, cmd);
+	if (ret != DCMD_TIMEOUT)
+		megasas_return_cmd(instance, cmd);
 
 	return ret;
 }
@@ -4223,38 +4344,73 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
 	dcmd->mbox.b[0] = 1;
 
 	if (instance->ctrl_context && !instance->mask_interrupts)
-		ret = megasas_issue_blocked_cmd(instance, cmd,
-			MEGASAS_BLOCKED_CMD_TIMEOUT);
+		ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
 	else
 		ret = megasas_issue_polled(instance, cmd);
 
-	if (!ret) {
+	switch (ret) {
+	case DCMD_SUCCESS:
 		memcpy(ctrl_info, ci, sizeof(struct megasas_ctrl_info));
+		/* Save required controller information in
+		 * CPU endianness format.
+		 */
 		le32_to_cpus((u32 *)&ctrl_info->properties.OnOffProperties);
 		le32_to_cpus((u32 *)&ctrl_info->adapterOperations2);
 		le32_to_cpus((u32 *)&ctrl_info->adapterOperations3);
+
+		/* Update the latest Ext VD info.
+		 * From Init path, store current firmware details.
+		 * From OCR path, detect any firmware properties changes.
+		 * in case of Firmware upgrade without system reboot.
+		 */
 		megasas_update_ext_vd_details(instance);
 		instance->use_seqnum_jbod_fp =
 			ctrl_info->adapterOperations3.useSeqNumJbodFP;
+
+		/*Check whether controller is iMR or MR */
 		instance->is_imr = (ctrl_info->memory_size ? 0 : 1);
 		dev_info(&instance->pdev->dev,
-				"controller type\t: %s(%dMB)\n",
-				instance->is_imr ? "iMR" : "MR",
-				le16_to_cpu(ctrl_info->memory_size));
+			"controller type\t: %s(%dMB)\n",
+			instance->is_imr ? "iMR" : "MR",
+			le16_to_cpu(ctrl_info->memory_size));
+
 		instance->disableOnlineCtrlReset =
 			ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset;
-		dev_info(&instance->pdev->dev, "Online Controller Reset(OCR)\t: %s\n",
-			instance->disableOnlineCtrlReset ? "Disabled" : "Enabled");
 		instance->secure_jbod_support =
 			ctrl_info->adapterOperations3.supportSecurityonJBOD;
+		dev_info(&instance->pdev->dev, "Online Controller Reset(OCR)\t: %s\n",
+			instance->disableOnlineCtrlReset ? "Disabled" : "Enabled");
 		dev_info(&instance->pdev->dev, "Secure JBOD support\t: %s\n",
 			instance->secure_jbod_support ? "Yes" : "No");
+		break;
+
+	case DCMD_TIMEOUT:
+		switch (dcmd_timeout_ocr_possible(instance)) {
+		case INITIATE_OCR:
+			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+			megasas_reset_fusion(instance->host,
+				MFI_IO_TIMEOUT_OCR);
+			break;
+		case KILL_ADAPTER:
+			megaraid_sas_kill_hba(instance);
+			break;
+		case IGNORE_TIMEOUT:
+			dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
+				__func__, __LINE__);
+			break;
+		}
+	case DCMD_FAILED:
+		megaraid_sas_kill_hba(instance);
+		break;
+
 	}
 
 	pci_free_consistent(instance->pdev, sizeof(struct megasas_ctrl_info),
 			    ci, ci_h);
 
 	megasas_return_cmd(instance, cmd);
+
+
 	return ret;
 }
 
@@ -4304,12 +4460,28 @@ int megasas_set_crash_dump_params(struct megasas_instance *instance,
 	dcmd->sgl.sge32[0].length = cpu_to_le32(CRASH_DMA_BUF_SIZE);
 
 	if (instance->ctrl_context && !instance->mask_interrupts)
-		ret = megasas_issue_blocked_cmd(instance, cmd,
-			MEGASAS_BLOCKED_CMD_TIMEOUT);
+		ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
 	else
 		ret = megasas_issue_polled(instance, cmd);
 
-	megasas_return_cmd(instance, cmd);
+	if (ret == DCMD_TIMEOUT) {
+		switch (dcmd_timeout_ocr_possible(instance)) {
+		case INITIATE_OCR:
+			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+			megasas_reset_fusion(instance->host,
+					MFI_IO_TIMEOUT_OCR);
+			break;
+		case KILL_ADAPTER:
+			megaraid_sas_kill_hba(instance);
+			break;
+		case IGNORE_TIMEOUT:
+			dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
+				__func__, __LINE__);
+			break;
+		}
+	} else
+		megasas_return_cmd(instance, cmd);
+
 	return ret;
 }
 
@@ -5035,10 +5207,8 @@ megasas_get_seq_num(struct megasas_instance *instance,
 	dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(el_info_h);
 	dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct megasas_evt_log_info));
 
-	if (megasas_issue_blocked_cmd(instance, cmd, 30))
-		dev_err(&instance->pdev->dev, "Command timedout"
-			"from %s\n", __func__);
-	else {
+	if (megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS) ==
+		DCMD_SUCCESS) {
 		/*
 		 * Copy the data back into callers buffer
 		 */
@@ -5047,7 +5217,9 @@ megasas_get_seq_num(struct megasas_instance *instance,
 		eli->clear_seq_num = el_info->clear_seq_num;
 		eli->shutdown_seq_num = el_info->shutdown_seq_num;
 		eli->boot_seq_num = el_info->boot_seq_num;
-	}
+	} else
+		dev_err(&instance->pdev->dev, "DCMD failed "
+			"from %s\n", __func__);
 
 	pci_free_consistent(instance->pdev, sizeof(struct megasas_evt_log_info),
 			    el_info, el_info_h);
@@ -5637,9 +5809,12 @@ static void megasas_flush_cache(struct megasas_instance *instance)
 	dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_CACHE_FLUSH);
 	dcmd->mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
 
-	if (megasas_issue_blocked_cmd(instance, cmd, 30))
-		dev_err(&instance->pdev->dev, "Command timedout"
-			" from %s\n", __func__);
+	if (megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS)
+			!= DCMD_SUCCESS) {
+		dev_err(&instance->pdev->dev,
+			"return from %s %d\n", __func__, __LINE__);
+		return;
+	}
 
 	megasas_return_cmd(instance, cmd);
 }
@@ -5665,13 +5840,13 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
 
 	if (instance->aen_cmd)
 		megasas_issue_blocked_abort_cmd(instance,
-			instance->aen_cmd, MEGASAS_BLOCKED_CMD_TIMEOUT);
+			instance->aen_cmd, MFI_IO_TIMEOUT_SECS);
 	if (instance->map_update_cmd)
 		megasas_issue_blocked_abort_cmd(instance,
-			instance->map_update_cmd, MEGASAS_BLOCKED_CMD_TIMEOUT);
+			instance->map_update_cmd, MFI_IO_TIMEOUT_SECS);
 	if (instance->jbod_seq_cmd)
 		megasas_issue_blocked_abort_cmd(instance,
-			instance->jbod_seq_cmd, MEGASAS_BLOCKED_CMD_TIMEOUT);
+			instance->jbod_seq_cmd, MFI_IO_TIMEOUT_SECS);
 
 	dcmd = &cmd->frame->dcmd;
 
@@ -5686,9 +5861,12 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
 	dcmd->data_xfer_len = 0;
 	dcmd->opcode = cpu_to_le32(opcode);
 
-	if (megasas_issue_blocked_cmd(instance, cmd, 30))
-		dev_err(&instance->pdev->dev, "Command timedout"
-			"from %s\n", __func__);
+	if (megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS)
+			!= DCMD_SUCCESS) {
+		dev_err(&instance->pdev->dev,
+			"return from %s %d\n", __func__, __LINE__);
+		return;
+	}
 
 	megasas_return_cmd(instance, cmd);
 }
@@ -6226,7 +6404,15 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
 	 * cmd to the SCSI mid-layer
 	 */
 	cmd->sync_cmd = 1;
-	megasas_issue_blocked_cmd(instance, cmd, 0);
+	if (megasas_issue_blocked_cmd(instance, cmd, 0) == DCMD_NOT_FIRED) {
+		cmd->sync_cmd = 0;
+		dev_err(&instance->pdev->dev,
+			"return -EBUSY from %s %d opcode 0x%x cmd->cmd_status_drv 0x%x\n",
+			__func__, __LINE__, cmd->frame->dcmd.opcode,
+			cmd->cmd_status_drv);
+		return -EBUSY;
+	}
+
 	cmd->sync_cmd = 0;
 
 	if (instance->unload == 1) {
@@ -6646,7 +6832,7 @@ megasas_aen_polling(struct work_struct *work)
 	int     i, j, doscan = 0;
 	u32 seq_num, wait_time = MEGASAS_RESET_WAIT_TIME;
 	int error;
-	u8  dcmd_ret = 0;
+	u8  dcmd_ret = DCMD_SUCCESS;
 
 	if (!instance) {
 		printk(KERN_ERR "invalid instance!\n");
@@ -6671,7 +6857,7 @@ megasas_aen_polling(struct work_struct *work)
 		case MR_EVT_PD_INSERTED:
 		case MR_EVT_PD_REMOVED:
 			dcmd_ret = megasas_get_pd_list(instance);
-			if (dcmd_ret == 0)
+			if (dcmd_ret == DCMD_SUCCESS)
 				doscan = SCAN_PD_CHANNEL;
 			break;
 
@@ -6683,7 +6869,7 @@ megasas_aen_polling(struct work_struct *work)
 				(instance->requestorId && megasas_get_ld_vf_affiliation(instance, 0)))
 				dcmd_ret = megasas_ld_list_query(instance, MR_LD_QUERY_TYPE_EXPOSED_TO_HOST);
 
-			if (dcmd_ret == 0)
+			if (dcmd_ret == DCMD_SUCCESS)
 				doscan = SCAN_VD_CHANNEL;
 
 			break;
@@ -6693,14 +6879,14 @@ megasas_aen_polling(struct work_struct *work)
 		case MR_EVT_LD_STATE_CHANGE:
 			dcmd_ret = megasas_get_pd_list(instance);
 
-			if (dcmd_ret != 0)
+			if (dcmd_ret != DCMD_SUCCESS)
 				break;
 
 			if (!instance->requestorId ||
 				(instance->requestorId && megasas_get_ld_vf_affiliation(instance, 0)))
 				dcmd_ret = megasas_ld_list_query(instance, MR_LD_QUERY_TYPE_EXPOSED_TO_HOST);
 
-			if (dcmd_ret != 0)
+			if (dcmd_ret != DCMD_SUCCESS)
 				break;
 
 			doscan = SCAN_VD_CHANNEL | SCAN_PD_CHANNEL;
@@ -6765,7 +6951,7 @@ megasas_aen_polling(struct work_struct *work)
 		}
 	}
 
-	if (dcmd_ret == 0)
+	if (dcmd_ret == DCMD_SUCCESS)
 		seq_num = le32_to_cpu(instance->evt_detail->seq_num) + 1;
 	else
 		seq_num = instance->last_seq_num;
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index 8d630a5..6e48707 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -576,11 +576,12 @@ wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
 		msleep(20);
 	}
 
-	if (frame_hdr->cmd_status == 0xff)
-		return -ETIME;
-
-	return (frame_hdr->cmd_status == MFI_STAT_OK) ?
-		0 : 1;
+	if (frame_hdr->cmd_status == MFI_STAT_INVALID_STATUS)
+		return DCMD_TIMEOUT;
+	else if (frame_hdr->cmd_status == MFI_STAT_OK)
+		return DCMD_SUCCESS;
+	else
+		return DCMD_FAILED;
 }
 
 /**
@@ -784,7 +785,8 @@ megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) {
 
 	/* Below code is only for non pended DCMD */
 	if (instance->ctrl_context && !instance->mask_interrupts)
-		ret = megasas_issue_blocked_cmd(instance, cmd, 60);
+		ret = megasas_issue_blocked_cmd(instance, cmd,
+			MFI_IO_TIMEOUT_SECS);
 	else
 		ret = megasas_issue_polled(instance, cmd);
 
@@ -795,7 +797,10 @@ megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) {
 		ret = -EINVAL;
 	}
 
-	if (!ret)
+	if (ret == DCMD_TIMEOUT && instance->ctrl_context)
+		megaraid_sas_kill_hba(instance);
+
+	if (ret == DCMD_SUCCESS)
 		instance->pd_seq_map_id++;
 
 	megasas_return_cmd(instance, cmd);
@@ -875,10 +880,13 @@ megasas_get_ld_map_info(struct megasas_instance *instance)
 
 	if (instance->ctrl_context && !instance->mask_interrupts)
 		ret = megasas_issue_blocked_cmd(instance, cmd,
-			MEGASAS_BLOCKED_CMD_TIMEOUT);
+			MFI_IO_TIMEOUT_SECS);
 	else
 		ret = megasas_issue_polled(instance, cmd);
 
+	if (ret == DCMD_TIMEOUT && instance->ctrl_context)
+		megaraid_sas_kill_hba(instance);
+
 	megasas_return_cmd(instance, cmd);
 
 	return ret;
@@ -2411,7 +2419,7 @@ build_mpt_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
  * @cmd:			mfi cmd pointer
  *
  */
-void
+int
 megasas_issue_dcmd_fusion(struct megasas_instance *instance,
 			  struct megasas_cmd *cmd)
 {
@@ -2419,10 +2427,13 @@ megasas_issue_dcmd_fusion(struct megasas_instance *instance,
 
 	req_desc = build_mpt_cmd(instance, cmd);
 	if (!req_desc) {
-		dev_err(&instance->pdev->dev, "Couldn't issue MFI pass thru cmd\n");
-		return;
+		dev_info(&instance->pdev->dev, "Failed from %s %d\n",
+					__func__, __LINE__);
+		return DCMD_NOT_FIRED;
 	}
+
 	megasas_fire_cmd_fusion(instance, req_desc);
+	return DCMD_SUCCESS;
 }
 
 /**
@@ -2583,7 +2594,7 @@ megasas_check_reset_fusion(struct megasas_instance *instance,
 
 /* This function waits for outstanding commands on fusion to complete */
 int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
-					int iotimeout, int *convert)
+					int reason, int *convert)
 {
 	int i, outstanding, retval = 0, hb_seconds_missed = 0;
 	u32 fw_state;
@@ -2599,14 +2610,22 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
 			retval = 1;
 			goto out;
 		}
+
+		if (reason == MFI_IO_TIMEOUT_OCR) {
+			dev_info(&instance->pdev->dev,
+				"MFI IO is timed out, initiating OCR\n");
+			retval = 1;
+			goto out;
+		}
+
 		/* If SR-IOV VF mode & heartbeat timeout, don't wait */
-		if (instance->requestorId && !iotimeout) {
+		if (instance->requestorId && !reason) {
 			retval = 1;
 			goto out;
 		}
 
 		/* If SR-IOV VF mode & I/O timeout, check for HB timeout */
-		if (instance->requestorId && iotimeout) {
+		if (instance->requestorId && reason) {
 			if (instance->hb_host_mem->HB.fwCounter !=
 			    instance->hb_host_mem->HB.driverCounter) {
 				instance->hb_host_mem->HB.driverCounter =
@@ -2680,6 +2699,7 @@ void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
 	struct megasas_cmd *cmd_mfi;
 	union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
 	u16 smid;
+	bool refire_cmd = 0;
 
 	fusion = instance->ctrl_context;
 
@@ -2695,10 +2715,12 @@ void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
 			continue;
 		req_desc = megasas_get_request_descriptor
 					(instance, smid - 1);
-		if (req_desc && ((cmd_mfi->frame->dcmd.opcode !=
+		refire_cmd = req_desc && ((cmd_mfi->frame->dcmd.opcode !=
 				cpu_to_le32(MR_DCMD_LD_MAP_GET_INFO)) &&
 				 (cmd_mfi->frame->dcmd.opcode !=
-				cpu_to_le32(MR_DCMD_SYSTEM_PD_MAP_GET_INFO))))
+				cpu_to_le32(MR_DCMD_SYSTEM_PD_MAP_GET_INFO)))
+				&& !(cmd_mfi->flags & DRV_DCMD_SKIP_REFIRE);
+		if (refire_cmd)
 			megasas_fire_cmd_fusion(instance, req_desc);
 		else
 			megasas_return_cmd(instance, cmd_mfi);
-- 
1.7.1


^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 03/15] megaraid_sas: Syncing request flags macro names with firmware
  2015-12-18 13:26 [PATCH 00/15] megaraid_sas: Updates for scsi-next Sumit Saxena
  2015-12-18 13:26 ` [PATCH 01/15] megaraid_sas: Do not allow PCI access during OCR Sumit Saxena
  2015-12-18 13:26 ` [PATCH 02/15] megaraid_sas: MFI IO timeout handling Sumit Saxena
@ 2015-12-18 13:26 ` Sumit Saxena
  2016-01-11 17:03   ` Tomas Henzl
  2015-12-18 13:26 ` [PATCH 04/15] megaraid_sas: Task management support Sumit Saxena
                   ` (11 subsequent siblings)
  14 siblings, 1 reply; 50+ messages in thread
From: Sumit Saxena @ 2015-12-18 13:26 UTC (permalink / raw)
  To: jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai, sumit.saxena

Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
---
 drivers/scsi/megaraid/megaraid_sas_fusion.c |    6 +++---
 drivers/scsi/megaraid/megaraid_sas_fusion.h |    3 ++-
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index 6e48707..1dc4537 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -1666,7 +1666,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
 				   local_map_ptr, start_lba_lo);
 		io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
 		cmd->request_desc->SCSIIO.RequestFlags =
-			(MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY
+			(MPI2_REQ_DESCRIPT_FLAGS_FP_IO
 			 << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
 		if (fusion->adapter_type == INVADER_SERIES) {
 			if (io_request->RaidContext.regLockFlags ==
@@ -1799,7 +1799,7 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance,
 
 		/* build request descriptor */
 		cmd->request_desc->SCSIIO.RequestFlags =
-			(MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
+			(MPI2_REQ_DESCRIPT_FLAGS_FP_IO <<
 			MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
 		cmd->request_desc->SCSIIO.DevHandle = devHandle;
 
@@ -1905,7 +1905,7 @@ megasas_build_syspd_fusion(struct megasas_instance *instance,
 				cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
 		}
 		cmd->request_desc->SCSIIO.RequestFlags =
-			(MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
+			(MPI2_REQ_DESCRIPT_FLAGS_FP_IO <<
 				MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
 	}
 }
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
index 473005c..a9e10c4 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
@@ -176,7 +176,8 @@ enum REGION_TYPE {
 #define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD           (0x0100)
 #define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP             (0x0004)
 #define MPI2_FUNCTION_SCSI_IO_REQUEST               (0x00) /* SCSI IO */
-#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY           (0x06)
+#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY       (0x03)
+#define MPI2_REQ_DESCRIPT_FLAGS_FP_IO               (0x06)
 #define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO                 (0x00)
 #define MPI2_SGE_FLAGS_64_BIT_ADDRESSING        (0x02)
 #define MPI2_SCSIIO_CONTROL_WRITE               (0x01000000)
-- 
1.7.1


^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 04/15] megaraid_sas: Task management support
  2015-12-18 13:26 [PATCH 00/15] megaraid_sas: Updates for scsi-next Sumit Saxena
                   ` (2 preceding siblings ...)
  2015-12-18 13:26 ` [PATCH 03/15] megaraid_sas: Syncing request flags macro names with firmware Sumit Saxena
@ 2015-12-18 13:26 ` Sumit Saxena
  2016-01-11 17:03   ` Tomas Henzl
  2015-12-18 13:26 ` [PATCH 05/15] megaraid_sas: Update device Queue depth based on interface type Sumit Saxena
                   ` (10 subsequent siblings)
  14 siblings, 1 reply; 50+ messages in thread
From: Sumit Saxena @ 2015-12-18 13:26 UTC (permalink / raw)
  To: jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai, sumit.saxena

This patch will add task management(TM) support for SCSI commands in megaraid_sas driver.
Added TM functions are below-
1)Task abort
2)Target reset

Below are few key points-

1. Currently, megaraid_sas driver performs Controller reset when any IO times out.
With these TM support added in driver, in case of IO timeout task abort and target
reset will be tried to recover timed out IO. If both fails to recover IO, then
Controller reset will be called. If the TM request times out, fail the TM and escalate
to the next level(Controller reset).

2. mr_device_priv_data will be allocated for all generation of controller, but is_tm_capable
flag will never be set for older controllers (prior to Invader series) as firmware support is not
available for T.M functionality.

3. whichever firmware is capable for TM will set is_tm_capable flag in firmware API, which will be used
by Driver to pass TM frame to firmware or return back to OS as Failure to escalate next level of Error handling.

Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
---
 drivers/scsi/megaraid/megaraid_sas.h        |   13 +
 drivers/scsi/megaraid/megaraid_sas_base.c   |   63 +++-
 drivers/scsi/megaraid/megaraid_sas_fusion.c |  479 ++++++++++++++++++++++++++-
 drivers/scsi/megaraid/megaraid_sas_fusion.h |  117 +++++++-
 4 files changed, 653 insertions(+), 19 deletions(-)

diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index dcc6ff8..0fcb156 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -1520,6 +1520,15 @@ union megasas_frame {
 	u8 raw_bytes[64];
 };
 
+/**
+ * struct MR_PRIV_DEVICE - sdev private hostdata
+ * @is_tm_capable: firmware managed tm_capable flag
+ * @tm_busy: TM request is in progress
+ */
+struct MR_PRIV_DEVICE {
+	bool is_tm_capable;
+	bool tm_busy;
+};
 struct megasas_cmd;
 
 union megasas_evt_class_locale {
@@ -2073,4 +2082,8 @@ void megasas_return_mfi_mpt_pthr(struct megasas_instance *instance,
 int megasas_cmd_type(struct scsi_cmnd *cmd);
 void megasas_setup_jbod_map(struct megasas_instance *instance);
 
+void megasas_update_sdev_properties(struct scsi_device *sdev);
+int megasas_reset_fusion(struct Scsi_Host *shost, int reason);
+int megasas_task_abort_fusion(struct scsi_cmnd *scmd);
+int megasas_reset_target_fusion(struct scsi_cmnd *scmd);
 #endif				/*LSI_MEGARAID_SAS_H */
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index 380c627..c1dc23c 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -189,7 +189,6 @@ int
 wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
 	int seconds);
 void megasas_reset_reply_desc(struct megasas_instance *instance);
-int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout);
 void megasas_fusion_ocr_wq(struct work_struct *work);
 static int megasas_get_ld_vf_affiliation(struct megasas_instance *instance,
 					 int initial);
@@ -1645,6 +1644,7 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
 {
 	struct megasas_instance *instance;
 	unsigned long flags;
+	struct MR_PRIV_DEVICE *mr_device_priv_data;
 
 	instance = (struct megasas_instance *)
 	    scmd->device->host->hostdata;
@@ -1681,11 +1681,24 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
 		return 0;
 	}
 
+	mr_device_priv_data = scmd->device->hostdata;
+	if (!mr_device_priv_data) {
+		spin_unlock_irqrestore(&instance->hba_lock, flags);
+		scmd->result = DID_NO_CONNECT << 16;
+		scmd->scsi_done(scmd);
+		return 0;
+	}
+
 	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
 		spin_unlock_irqrestore(&instance->hba_lock, flags);
 		return SCSI_MLQUEUE_HOST_BUSY;
 	}
 
+	if (mr_device_priv_data->tm_busy) {
+		spin_unlock_irqrestore(&instance->hba_lock, flags);
+		return SCSI_MLQUEUE_DEVICE_BUSY;
+	}
+
 	spin_unlock_irqrestore(&instance->hba_lock, flags);
 
 	scmd->result = 0;
@@ -1736,27 +1749,39 @@ static struct megasas_instance *megasas_lookup_instance(u16 host_no)
 }
 
 /*
-* megasas_set_dma_alignment - Set DMA alignment for PI enabled VD
+* megasas_update_sdev_properties - Update sdev structure based on controller's FW capabilities
 *
 * @sdev: OS provided scsi device
 *
 * Returns void
 */
-static void megasas_set_dma_alignment(struct scsi_device *sdev)
+void megasas_update_sdev_properties(struct scsi_device *sdev)
 {
+	u16 pd_index = 0;
 	u32 device_id, ld;
 	struct megasas_instance *instance;
 	struct fusion_context *fusion;
+	struct MR_PRIV_DEVICE *mr_device_priv_data;
+	struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync;
 	struct MR_LD_RAID *raid;
 	struct MR_DRV_RAID_MAP_ALL *local_map_ptr;
 
 	instance = megasas_lookup_instance(sdev->host->host_no);
 	fusion = instance->ctrl_context;
+	mr_device_priv_data = sdev->hostdata;
 
-	if (!fusion)
+	if (!fusion || !mr_device_priv_data)
 		return;
 
-	if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS) {
+	if (sdev->channel < MEGASAS_MAX_PD_CHANNELS &&
+		instance->use_seqnum_jbod_fp) {
+		pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
+			sdev->id;
+		pd_sync = (void *)fusion->pd_seq_sync
+				[(instance->pd_seq_map_id - 1) & 1];
+		mr_device_priv_data->is_tm_capable =
+			pd_sync->seq[pd_index].capability.tmCapable;
+	} else {
 		device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL)
 					+ sdev->id;
 		local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
@@ -1764,10 +1789,14 @@ static void megasas_set_dma_alignment(struct scsi_device *sdev)
 		raid = MR_LdRaidGet(ld, local_map_ptr);
 
 		if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER)
-			blk_queue_update_dma_alignment(sdev->request_queue, 0x7);
+		blk_queue_update_dma_alignment(sdev->request_queue, 0x7);
+
+		mr_device_priv_data->is_tm_capable =
+			raid->capability.tmCapable;
 	}
 }
 
+
 static int megasas_slave_configure(struct scsi_device *sdev)
 {
 	u16 pd_index = 0;
@@ -1784,7 +1813,8 @@ static int megasas_slave_configure(struct scsi_device *sdev)
 				return -ENXIO;
 		}
 	}
-	megasas_set_dma_alignment(sdev);
+	megasas_update_sdev_properties(sdev);
+
 	/*
 	 * The RAID firmware may require extended timeouts.
 	 */
@@ -1798,6 +1828,7 @@ static int megasas_slave_alloc(struct scsi_device *sdev)
 {
 	u16 pd_index = 0;
 	struct megasas_instance *instance ;
+	struct MR_PRIV_DEVICE *mr_device_priv_data;
 
 	instance = megasas_lookup_instance(sdev->host->host_no);
 	if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
@@ -1809,13 +1840,26 @@ static int megasas_slave_alloc(struct scsi_device *sdev)
 			sdev->id;
 		if ((instance->allow_fw_scan || instance->pd_list[pd_index].driveState ==
 			MR_PD_STATE_SYSTEM)) {
-			return 0;
+			goto scan_target;
 		}
 		return -ENXIO;
 	}
+
+scan_target:
+	mr_device_priv_data = kzalloc(sizeof(*mr_device_priv_data),
+					GFP_KERNEL);
+	if (!mr_device_priv_data)
+		return -ENOMEM;
+	sdev->hostdata = mr_device_priv_data;
 	return 0;
 }
 
+static void megasas_slave_destroy(struct scsi_device *sdev)
+{
+	kfree(sdev->hostdata);
+	sdev->hostdata = NULL;
+}
+
 /*
 * megasas_complete_outstanding_ioctls - Complete outstanding ioctls after a
 *                                       kill adapter
@@ -2885,6 +2929,7 @@ static struct scsi_host_template megasas_template = {
 	.proc_name = "megaraid_sas",
 	.slave_configure = megasas_slave_configure,
 	.slave_alloc = megasas_slave_alloc,
+	.slave_destroy = megasas_slave_destroy,
 	.queuecommand = megasas_queue_command,
 	.eh_device_reset_handler = megasas_reset_device,
 	.eh_bus_reset_handler = megasas_reset_bus_host,
@@ -5434,6 +5479,8 @@ static int megasas_io_attach(struct megasas_instance *instance)
 	if (instance->ctrl_context) {
 		host->hostt->eh_device_reset_handler = NULL;
 		host->hostt->eh_bus_reset_handler = NULL;
+		host->hostt->eh_target_reset_handler = megasas_reset_target_fusion;
+		host->hostt->eh_abort_handler = megasas_task_abort_fusion;
 	}
 
 	/*
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index 1dc4537..0b31f5a 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -2100,6 +2100,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
 	struct LD_LOAD_BALANCE_INFO *lbinfo;
 	int threshold_reply_count = 0;
 	struct scsi_cmnd *scmd_local = NULL;
+	struct MR_TASK_MANAGE_REQUEST *mr_tm_req;
+	struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_tm_req;
 
 	fusion = instance->ctrl_context;
 
@@ -2141,6 +2143,16 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
 		extStatus = scsi_io_req->RaidContext.exStatus;
 
 		switch (scsi_io_req->Function) {
+		case MPI2_FUNCTION_SCSI_TASK_MGMT:
+			mr_tm_req = (struct MR_TASK_MANAGE_REQUEST *)
+						cmd_fusion->io_request;
+			mpi_tm_req = (struct MPI2_SCSI_TASK_MANAGE_REQUEST *)
+						&mr_tm_req->TmRequest;
+			dev_dbg(&instance->pdev->dev, "TM completion:"
+				"type: 0x%x TaskMID: 0x%x\n",
+				mpi_tm_req->TaskType, mpi_tm_req->TaskMID);
+			complete(&cmd_fusion->done);
+			break;
 		case MPI2_FUNCTION_SCSI_IO_REQUEST:  /*Fast Path IO.*/
 			/* Update load balancing info */
 			device_id = MEGASAS_DEV_INDEX(scmd_local);
@@ -2727,6 +2739,457 @@ void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
 	}
 }
 
+/*
+ * megasas_track_scsiio : Track SCSI IOs outstanding to a SCSI device
+ * @instance: per adapter struct
+ * @channel: the channel assigned by the OS
+ * @id: the id assigned by the OS
+ *
+ * Returns SUCCESS if no IOs pending to SCSI device, else return FAILED
+ */
+
+static int megasas_track_scsiio(struct megasas_instance *instance,
+		int id, int channel)
+{
+	int i, found = 0;
+	struct megasas_cmd_fusion *cmd_fusion;
+	struct fusion_context *fusion;
+	fusion = instance->ctrl_context;
+
+	for (i = 0 ; i < instance->max_scsi_cmds; i++) {
+		cmd_fusion = fusion->cmd_list[i];
+		if (cmd_fusion->scmd &&
+			(cmd_fusion->scmd->device->id == id &&
+			cmd_fusion->scmd->device->channel == channel)) {
+			dev_info(&instance->pdev->dev,
+				"SCSI commands pending to target"
+				"channel %d id %d \tSMID: 0x%x\n",
+				channel, id, cmd_fusion->index);
+			scsi_print_command(cmd_fusion->scmd);
+			found = 1;
+			break;
+		}
+	}
+
+	return found ? FAILED : SUCCESS;
+}
+
+/**
+ * megasas_tm_response_code - translation of device response code
+ * @ioc: per adapter object
+ * @mpi_reply: MPI reply returned by firmware
+ *
+ * Return nothing.
+ */
+static void
+megasas_tm_response_code(struct megasas_instance *instance,
+		struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply)
+{
+	char *desc;
+
+	switch (mpi_reply->ResponseCode) {
+	case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE:
+		desc = "task management request completed";
+		break;
+	case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME:
+		desc = "invalid frame";
+		break;
+	case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
+		desc = "task management request not supported";
+		break;
+	case MPI2_SCSITASKMGMT_RSP_TM_FAILED:
+		desc = "task management request failed";
+		break;
+	case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED:
+		desc = "task management request succeeded";
+		break;
+	case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN:
+		desc = "invalid lun";
+		break;
+	case 0xA:
+		desc = "overlapped tag attempted";
+		break;
+	case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
+		desc = "task queued, however not sent to target";
+		break;
+	default:
+		desc = "unknown";
+		break;
+	}
+	dev_dbg(&instance->pdev->dev, "response_code(%01x): %s\n",
+		mpi_reply->ResponseCode, desc);
+	dev_dbg(&instance->pdev->dev,
+		"TerminationCount/DevHandle/Function/TaskType/IOCStat/IOCLoginfo"
+		" 0x%x/0x%x/0x%x/0x%x/0x%x/0x%x\n",
+		mpi_reply->TerminationCount, mpi_reply->DevHandle,
+		mpi_reply->Function, mpi_reply->TaskType,
+		mpi_reply->IOCStatus, mpi_reply->IOCLogInfo);
+}
+
+/**
+ * megasas_issue_tm - main routine for sending tm requests
+ * @instance: per adapter struct
+ * @device_handle: device handle
+ * @channel: the channel assigned by the OS
+ * @id: the id assigned by the OS
+ * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in megaraid_sas_fusion.c)
+ * @smid_task: smid assigned to the task
+ * @m_type: TM_MUTEX_ON or TM_MUTEX_OFF
+ * Context: user
+ *
+ * MegaRaid use MPT interface for Task Magement request.
+ * A generic API for sending task management requests to firmware.
+ *
+ * Return SUCCESS or FAILED.
+ */
+static int
+megasas_issue_tm(struct megasas_instance *instance, u16 device_handle,
+	uint channel, uint id, u16 smid_task, u8 type)
+{
+	struct MR_TASK_MANAGE_REQUEST *mr_request;
+	struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_request;
+	unsigned long timeleft;
+	struct megasas_cmd_fusion *cmd_fusion;
+	struct megasas_cmd *cmd_mfi;
+	union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+	struct fusion_context *fusion;
+	struct megasas_cmd_fusion *scsi_lookup;
+	int rc;
+	struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply;
+
+	fusion = instance->ctrl_context;
+
+	cmd_mfi = megasas_get_cmd(instance);
+
+	if (!cmd_mfi) {
+		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
+			__func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	cmd_fusion = megasas_get_cmd_fusion(instance,
+			instance->max_scsi_cmds + cmd_mfi->index);
+
+	/*  Save the smid. To be used for returning the cmd */
+	cmd_mfi->context.smid = cmd_fusion->index;
+
+	req_desc = megasas_get_request_descriptor(instance,
+			(cmd_fusion->index - 1));
+	if (!req_desc) {
+		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
+			__func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	cmd_fusion->request_desc = req_desc;
+	req_desc->Words = 0;
+
+	scsi_lookup = fusion->cmd_list[smid_task - 1];
+
+	mr_request = (struct MR_TASK_MANAGE_REQUEST *) cmd_fusion->io_request;
+	memset(mr_request, 0, sizeof(struct MR_TASK_MANAGE_REQUEST));
+	mpi_request = (struct MPI2_SCSI_TASK_MANAGE_REQUEST *) &mr_request->TmRequest;
+	mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
+	mpi_request->DevHandle = cpu_to_le16(device_handle);
+	mpi_request->TaskType = type;
+	mpi_request->TaskMID = cpu_to_le16(smid_task);
+	mpi_request->LUN[1] = 0;
+
+
+	req_desc = cmd_fusion->request_desc;
+	req_desc->HighPriority.SMID = cpu_to_le16(cmd_fusion->index);
+	req_desc->HighPriority.RequestFlags =
+		(MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
+		MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+	req_desc->HighPriority.MSIxIndex =  0;
+	req_desc->HighPriority.LMID = 0;
+	req_desc->HighPriority.Reserved1 = 0;
+
+	if (channel < MEGASAS_MAX_PD_CHANNELS)
+		mr_request->tmReqFlags.isTMForPD = 1;
+	else
+		mr_request->tmReqFlags.isTMForLD = 1;
+
+	init_completion(&cmd_fusion->done);
+	megasas_fire_cmd_fusion(instance, req_desc);
+
+	timeleft = wait_for_completion_timeout(&cmd_fusion->done, 50 * HZ);
+
+	if (!timeleft) {
+		dev_err(&instance->pdev->dev,
+			"task mgmt type 0x%x timed out\n", type);
+		mutex_unlock(&instance->reset_mutex);
+		rc = megasas_reset_fusion(instance->host, MFI_IO_TIMEOUT_OCR);
+		mutex_lock(&instance->reset_mutex);
+		return rc;
+	}
+
+	mpi_reply = (struct MPI2_SCSI_TASK_MANAGE_REPLY *) &mr_request->TMReply;
+	megasas_tm_response_code(instance, mpi_reply);
+
+	megasas_return_cmd(instance, cmd_mfi);
+	rc = SUCCESS;
+	switch (type) {
+	case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
+		if (scsi_lookup->scmd == NULL)
+			break;
+		else {
+			instance->instancet->disable_intr(instance);
+			msleep(1000);
+			megasas_complete_cmd_dpc_fusion
+					((unsigned long)instance);
+			instance->instancet->enable_intr(instance);
+			if (scsi_lookup->scmd == NULL)
+				break;
+		}
+		rc = FAILED;
+		break;
+
+	case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
+		if ((channel == 0xFFFFFFFF) && (id == 0xFFFFFFFF))
+			break;
+		instance->instancet->disable_intr(instance);
+		msleep(1000);
+		megasas_complete_cmd_dpc_fusion
+				((unsigned long)instance);
+		rc = megasas_track_scsiio(instance, id, channel);
+		instance->instancet->enable_intr(instance);
+
+		break;
+	case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:
+	case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK:
+		break;
+	default:
+		rc = FAILED;
+		break;
+	}
+
+	return rc;
+
+}
+
+/*
+ * megasas_fusion_smid_lookup : Look for fusion command correpspodning to SCSI
+ * @instance: per adapter struct
+ *
+ * Return Non Zero index, if SMID found in outstanding commands
+ */
+static u16 megasas_fusion_smid_lookup(struct scsi_cmnd *scmd)
+{
+	int i, ret = 0;
+	struct megasas_instance *instance;
+	struct megasas_cmd_fusion *cmd_fusion;
+	struct fusion_context *fusion;
+
+	instance = (struct megasas_instance *)scmd->device->host->hostdata;
+
+	fusion = instance->ctrl_context;
+
+	for (i = 0; i < instance->max_scsi_cmds; i++) {
+		cmd_fusion = fusion->cmd_list[i];
+		if (cmd_fusion->scmd && (cmd_fusion->scmd == scmd)) {
+			scmd_printk(KERN_NOTICE, scmd, "Abort request is for"
+				" SMID: %d\n", cmd_fusion->index);
+			ret = cmd_fusion->index;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/*
+* megasas_get_tm_devhandle - Get devhandle for TM request
+* @sdev-		     OS provided scsi device
+*
+* Returns-		     devhandle/targetID of SCSI device
+*/
+static u16 megasas_get_tm_devhandle(struct scsi_device *sdev)
+{
+	u16 pd_index = 0;
+	u32 device_id;
+	struct megasas_instance *instance;
+	struct fusion_context *fusion;
+	struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync;
+	u16 devhandle = (u16)ULONG_MAX;
+
+	instance = (struct megasas_instance *)sdev->host->hostdata;
+	fusion = instance->ctrl_context;
+
+	if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
+		if (instance->use_seqnum_jbod_fp) {
+				pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
+						sdev->id;
+				pd_sync = (void *)fusion->pd_seq_sync
+						[(instance->pd_seq_map_id - 1) & 1];
+				devhandle = pd_sync->seq[pd_index].devHandle;
+		} else
+			sdev_printk(KERN_ERR, sdev, "Firmware expose tmCapable"
+				" without JBOD MAP support from %s %d\n", __func__, __LINE__);
+	} else {
+		device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL)
+				+ sdev->id;
+		devhandle = device_id;
+	}
+
+	return devhandle;
+}
+
+/*
+ * megasas_task_abort_fusion : SCSI task abort function for fusion adapters
+ * @scmd : pointer to scsi command object
+ *
+ * Return SUCCESS, if command aborted else FAILED
+ */
+
+int megasas_task_abort_fusion(struct scsi_cmnd *scmd)
+{
+	struct megasas_instance *instance;
+	u16 smid, devhandle;
+	struct fusion_context *fusion;
+	int ret;
+	struct MR_PRIV_DEVICE *mr_device_priv_data;
+	mr_device_priv_data = scmd->device->hostdata;
+
+
+	instance = (struct megasas_instance *)scmd->device->host->hostdata;
+	fusion = instance->ctrl_context;
+
+	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+		dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL,"
+		"SCSI host:%d\n", instance->host->host_no);
+		ret = FAILED;
+		return ret;
+	}
+
+	if (!mr_device_priv_data) {
+		sdev_printk(KERN_INFO, scmd->device, "device been deleted! "
+			"scmd(%p)\n", scmd);
+		scmd->result = DID_NO_CONNECT << 16;
+		scmd->scsi_done(scmd);
+		ret = SUCCESS;
+		goto out;
+	}
+
+
+	if (!mr_device_priv_data->is_tm_capable) {
+		scmd->result = DID_RESET << 16;
+		ret = FAILED;
+		goto out;
+	}
+
+	mutex_lock(&instance->reset_mutex);
+
+	smid = megasas_fusion_smid_lookup(scmd);
+
+	if (!smid) {
+		scmd->result = DID_RESET << 16;
+		ret = SUCCESS;
+		scmd_printk(KERN_NOTICE, scmd, "Command for which abort is"
+			" issued is not found in oustanding commands\n");
+		mutex_unlock(&instance->reset_mutex);
+		goto out;
+	}
+
+	devhandle = megasas_get_tm_devhandle(scmd->device);
+
+	if (devhandle == (u16)ULONG_MAX) {
+		scmd->result = DID_RESET << 16;
+		ret = SUCCESS;
+		sdev_printk(KERN_INFO, scmd->device,
+			"task abort issued for invalid devhandle\n");
+		mutex_unlock(&instance->reset_mutex);
+		goto out;
+	}
+	sdev_printk(KERN_INFO, scmd->device,
+		"attempting task abort! scmd(%p) tm_dev_handle 0x%x\n",
+		scmd, devhandle);
+
+	mr_device_priv_data->tm_busy = 1;
+	ret = megasas_issue_tm(instance, devhandle,
+			scmd->device->channel, scmd->device->id, smid,
+			MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
+	mr_device_priv_data->tm_busy = 0;
+
+	mutex_unlock(&instance->reset_mutex);
+out:
+	sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n",
+			((ret == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+
+	return ret;
+}
+
+/*
+ * megasas_reset_target_fusion : target reset function for fusion adapters
+ * scmd: SCSI command pointer
+ *
+ * Returns SUCCESS if all commands associated with target aborted else FAILED
+ */
+
+int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
+{
+
+	struct megasas_instance *instance;
+	int ret = FAILED;
+	u16 devhandle;
+	struct fusion_context *fusion;
+	struct MR_PRIV_DEVICE *mr_device_priv_data;
+	mr_device_priv_data = scmd->device->hostdata;
+
+	instance = (struct megasas_instance *)scmd->device->host->hostdata;
+	fusion = instance->ctrl_context;
+
+	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+		dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL,"
+		"SCSI host:%d\n", instance->host->host_no);
+		ret = FAILED;
+		return ret;
+	}
+
+	if (!mr_device_priv_data) {
+		sdev_printk(KERN_INFO, scmd->device, "device been deleted! "
+			"scmd(%p)\n", scmd);
+		scmd->result = DID_NO_CONNECT << 16;
+		scmd->scsi_done(scmd);
+		ret = SUCCESS;
+		goto out;
+	}
+
+
+	if (!mr_device_priv_data->is_tm_capable) {
+		scmd->result = DID_RESET << 16;
+		ret = FAILED;
+		goto out;
+	}
+
+	mutex_lock(&instance->reset_mutex);
+	devhandle = megasas_get_tm_devhandle(scmd->device);
+
+	if (devhandle == (u16)ULONG_MAX) {
+		scmd->result = DID_RESET << 16;
+		ret = SUCCESS;
+		sdev_printk(KERN_INFO, scmd->device,
+			"target reset issued for invalid devhandle\n");
+		mutex_unlock(&instance->reset_mutex);
+		goto out;
+	}
+
+	sdev_printk(KERN_INFO, scmd->device,
+		"attempting target reset! scmd(%p) tm_dev_handle 0x%x\n",
+		scmd, devhandle);
+	mr_device_priv_data->tm_busy = 1;
+	ret = megasas_issue_tm(instance, devhandle,
+			scmd->device->channel, scmd->device->id, 0,
+			MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET);
+	mr_device_priv_data->tm_busy = 0;
+	mutex_unlock(&instance->reset_mutex);
+out:
+	scmd_printk(KERN_NOTICE, scmd, "megasas: target reset %s!!\n",
+		(ret == SUCCESS) ? "SUCCESS" : "FAILED");
+
+	return ret;
+}
+
 /* Check for a second path that is currently UP */
 int megasas_check_mpio_paths(struct megasas_instance *instance,
 	struct scsi_cmnd *scmd)
@@ -2752,7 +3215,7 @@ out:
 }
 
 /* Core fusion reset function */
-int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
+int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
 {
 	int retval = SUCCESS, i, convert = 0;
 	struct megasas_instance *instance;
@@ -2761,6 +3224,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
 	u32 abs_state, status_reg, reset_adapter;
 	u32 io_timeout_in_crash_mode = 0;
 	struct scsi_cmnd *scmd_local = NULL;
+	struct scsi_device *sdev;
 
 	instance = (struct megasas_instance *)shost->hostdata;
 	fusion = instance->ctrl_context;
@@ -2779,8 +3243,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
 
 	/* IO timeout detected, forcibly put FW in FAULT state */
 	if (abs_state != MFI_STATE_FAULT && instance->crash_dump_buf &&
-		instance->crash_dump_app_support && iotimeout) {
-		dev_info(&instance->pdev->dev, "IO timeout is detected, "
+		instance->crash_dump_app_support && reason) {
+		dev_info(&instance->pdev->dev, "IO/DCMD timeout is detected, "
 			"forcibly FAULT Firmware\n");
 		instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
 		status_reg = readl(&instance->reg_set->doorbell);
@@ -2819,13 +3283,13 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
 	msleep(1000);
 
 	/* First try waiting for commands to complete */
-	if (megasas_wait_for_outstanding_fusion(instance, iotimeout,
+	if (megasas_wait_for_outstanding_fusion(instance, reason,
 						&convert)) {
 		instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
 		dev_warn(&instance->pdev->dev, "resetting fusion "
 		       "adapter scsi%d.\n", instance->host->host_no);
 		if (convert)
-			iotimeout = 0;
+			reason = 0;
 
 		/* Now return commands back to the OS */
 		for (i = 0 ; i < instance->max_scsi_cmds; i++) {
@@ -2859,7 +3323,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
 		}
 
 		/* Let SR-IOV VF & PF sync up if there was a HB failure */
-		if (instance->requestorId && !iotimeout) {
+		if (instance->requestorId && !reason) {
 			msleep(MEGASAS_OCR_SETTLE_TIME_VF);
 			/* Look for a late HB update after VF settle time */
 			if (abs_state == MFI_STATE_OPERATIONAL &&
@@ -2954,6 +3418,9 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
 
 			megasas_setup_jbod_map(instance);
 
+			shost_for_each_device(sdev, shost)
+				megasas_update_sdev_properties(sdev);
+
 			clear_bit(MEGASAS_FUSION_IN_RESET,
 				  &instance->reset_flags);
 			instance->instancet->enable_intr(instance);
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
index a9e10c4..a1f1c0b 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
@@ -176,6 +176,7 @@ enum REGION_TYPE {
 #define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD           (0x0100)
 #define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP             (0x0004)
 #define MPI2_FUNCTION_SCSI_IO_REQUEST               (0x00) /* SCSI IO */
+#define MPI2_FUNCTION_SCSI_TASK_MGMT                (0x01)
 #define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY       (0x03)
 #define MPI2_REQ_DESCRIPT_FLAGS_FP_IO               (0x06)
 #define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO                 (0x00)
@@ -278,6 +279,100 @@ union MPI2_SCSI_IO_CDB_UNION {
 	struct MPI2_SGE_SIMPLE_UNION SGE;
 };
 
+/****************************************************************************
+*  SCSI Task Management messages
+****************************************************************************/
+
+/*SCSI Task Management Request Message */
+struct MPI2_SCSI_TASK_MANAGE_REQUEST {
+	u16 DevHandle;		/*0x00 */
+	u8 ChainOffset;		/*0x02 */
+	u8 Function;		/*0x03 */
+	u8 Reserved1;		/*0x04 */
+	u8 TaskType;		/*0x05 */
+	u8 Reserved2;		/*0x06 */
+	u8 MsgFlags;		/*0x07 */
+	u8 VP_ID;		/*0x08 */
+	u8 VF_ID;		/*0x09 */
+	u16 Reserved3;		/*0x0A */
+	u8 LUN[8];		/*0x0C */
+	u32 Reserved4[7];	/*0x14 */
+	u16 TaskMID;		/*0x30 */
+	u16 Reserved5;		/*0x32 */
+};
+
+
+/*SCSI Task Management Reply Message */
+struct MPI2_SCSI_TASK_MANAGE_REPLY {
+	u16 DevHandle;		/*0x00 */
+	u8 MsgLength;		/*0x02 */
+	u8 Function;		/*0x03 */
+	u8 ResponseCode;	/*0x04 */
+	u8 TaskType;		/*0x05 */
+	u8 Reserved1;		/*0x06 */
+	u8 MsgFlags;		/*0x07 */
+	u8 VP_ID;		/*0x08 */
+	u8 VF_ID;		/*0x09 */
+	u16 Reserved2;		/*0x0A */
+	u16 Reserved3;		/*0x0C */
+	u16 IOCStatus;		/*0x0E */
+	u32 IOCLogInfo;		/*0x10 */
+	u32 TerminationCount;	/*0x14 */
+	u32 ResponseInfo;	/*0x18 */
+};
+
+struct MR_TM_REQUEST {
+	char request[128];
+};
+
+struct MR_TM_REPLY {
+	char reply[128];
+};
+
+/* SCSI Task Management Request Message */
+struct MR_TASK_MANAGE_REQUEST {
+	/*To be type casted to struct MPI2_SCSI_TASK_MANAGE_REQUEST */
+	struct MR_TM_REQUEST         TmRequest;
+	union {
+		struct {
+#if   defined(__BIG_ENDIAN_BITFIELD)
+			u32 reserved1:30;
+			u32 isTMForPD:1;
+			u32 isTMForLD:1;
+#else
+			u32 isTMForLD:1;
+			u32 isTMForPD:1;
+			u32 reserved1:30;
+#endif
+			u32 reserved2;
+		} tmReqFlags;
+		struct MR_TM_REPLY   TMReply;
+	};
+};
+
+/* TaskType values */
+
+#define MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK           (0x01)
+#define MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET        (0x02)
+#define MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET         (0x03)
+#define MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET   (0x05)
+#define MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET       (0x06)
+#define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK           (0x07)
+#define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA              (0x08)
+#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET         (0x09)
+#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT      (0x0A)
+
+/* ResponseCode values */
+
+#define MPI2_SCSITASKMGMT_RSP_TM_COMPLETE               (0x00)
+#define MPI2_SCSITASKMGMT_RSP_INVALID_FRAME             (0x02)
+#define MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED          (0x04)
+#define MPI2_SCSITASKMGMT_RSP_TM_FAILED                 (0x05)
+#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED              (0x08)
+#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN            (0x09)
+#define MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG         (0x0A)
+#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC          (0x80)
+
 /*
  * RAID SCSI IO Request Message
  * Total SGE count will be one less than  _MPI2_SCSI_IO_REQUEST
@@ -548,7 +643,8 @@ struct MR_SPAN_BLOCK_INFO {
 struct MR_LD_RAID {
 	struct {
 #if   defined(__BIG_ENDIAN_BITFIELD)
-		u32     reserved4:7;
+		u32     reserved4:6;
+		u32     tmCapable:1;
 		u32	fpNonRWCapable:1;
 		u32     fpReadAcrossStripe:1;
 		u32     fpWriteAcrossStripe:1;
@@ -570,7 +666,8 @@ struct MR_LD_RAID {
 		u32     fpWriteAcrossStripe:1;
 		u32     fpReadAcrossStripe:1;
 		u32	fpNonRWCapable:1;
-		u32     reserved4:7;
+		u32     tmCapable:1;
+		u32     reserved4:6;
 #endif
 	} capability;
 	__le32     reserved6;
@@ -695,6 +792,7 @@ struct megasas_cmd_fusion {
 	u32 sync_cmd_idx;
 	u32 index;
 	u8 pd_r1_lb;
+	struct completion done;
 };
 
 struct LD_LOAD_BALANCE_INFO {
@@ -808,9 +906,18 @@ struct MR_FW_RAID_MAP_EXT {
  *  * define MR_PD_CFG_SEQ structure for system PDs
  *   */
 struct MR_PD_CFG_SEQ {
-	__le16 seqNum;
-	__le16 devHandle;
-	u8  reserved[4];
+	u16 seqNum;
+	u16 devHandle;
+	struct {
+#if   defined(__BIG_ENDIAN_BITFIELD)
+		u8     reserved:7;
+		u8     tmCapable:1;
+#else
+		u8     tmCapable:1;
+		u8     reserved:7;
+#endif
+	} capability;
+	u8  reserved[3];
 } __packed;
 
 struct MR_PD_CFG_SEQ_NUM_SYNC {
-- 
1.7.1


^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 05/15] megaraid_sas: Update device Queue depth based on interface type
  2015-12-18 13:26 [PATCH 00/15] megaraid_sas: Updates for scsi-next Sumit Saxena
                   ` (3 preceding siblings ...)
  2015-12-18 13:26 ` [PATCH 04/15] megaraid_sas: Task management support Sumit Saxena
@ 2015-12-18 13:26 ` Sumit Saxena
  2016-01-12 14:16   ` Tomas Henzl
  2015-12-18 13:26 ` [PATCH 06/15] megaraid_sas: Fastpath region lock bypass Sumit Saxena
                   ` (9 subsequent siblings)
  14 siblings, 1 reply; 50+ messages in thread
From: Sumit Saxena @ 2015-12-18 13:26 UTC (permalink / raw)
  To: jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai, sumit.saxena

This patch will update device Queue depth based on interface type(SAS, SATA..) for sysPDs.
For Virtual disks(VDs), there will be no change in queue depth(will remain 256).
To fetch interface type(SAS or SATA or FC..) of syspD, driver will send DCMD MR_DCMD_PD_GET_INFO per sysPD.

Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>

---
 drivers/scsi/megaraid/megaraid_sas.h      |  270 ++++++++++++++++++++++++++++-
 drivers/scsi/megaraid/megaraid_sas_base.c |  127 ++++++++++++++
 2 files changed, 396 insertions(+), 1 deletions(-)

diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 0fcb156..773fc54 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -215,6 +215,7 @@
 
 #define MR_DCMD_CTRL_SET_CRASH_DUMP_PARAMS	0x01190100
 #define MR_DRIVER_SET_APP_CRASHDUMP_MODE	(0xF0010000 | 0x0600)
+#define MR_DCMD_PD_GET_INFO			0x02020000
 
 /*
  * Global functions
@@ -435,6 +436,257 @@ enum MR_PD_STATE {
 	MR_PD_STATE_SYSTEM              = 0x40,
  };
 
+union MR_PD_REF {
+	struct {
+		u16	 deviceId;
+		u16	 seqNum;
+	} mrPdRef;
+	u32	 ref;
+};
+
+/*
+ * define the DDF Type bit structure
+ */
+union MR_PD_DDF_TYPE {
+	 struct {
+		union {
+			struct {
+#ifndef __BIG_ENDIAN_BITFIELD
+				 u16	 forcedPDGUID:1;
+				 u16	 inVD:1;
+				 u16	 isGlobalSpare:1;
+				 u16	 isSpare:1;
+				 u16	 isForeign:1;
+				 u16	 reserved:7;
+				 u16	 intf:4;
+#else
+				 u16	 intf:4;
+				 u16	 reserved:7;
+				 u16	 isForeign:1;
+				 u16	 isSpare:1;
+				 u16	 isGlobalSpare:1;
+				 u16	 inVD:1;
+				 u16	 forcedPDGUID:1;
+#endif
+			 } pdType;
+			 u16	 type;
+		 };
+		 u16	 reserved;
+	 } ddf;
+	 struct {
+		 u32	reserved;
+	 } nonDisk;
+	 u32	 type;
+} __packed;
+
+/*
+ * defines the progress structure
+ */
+union MR_PROGRESS {
+	struct  {
+		u16 progress;
+		union {
+			u16 elapsedSecs;
+			u16 elapsedSecsForLastPercent;
+		};
+	} mrProgress;
+	u32 w;
+} __packed;
+
+/*
+ * defines the physical drive progress structure
+ */
+struct MR_PD_PROGRESS {
+	struct {
+#ifndef MFI_BIG_ENDIAN
+		u32     rbld:1;
+		u32     patrol:1;
+		u32     clear:1;
+		u32     copyBack:1;
+		u32     erase:1;
+		u32     locate:1;
+		u32     reserved:26;
+#else
+		u32     reserved:26;
+		u32     locate:1;
+		u32     erase:1;
+		u32     copyBack:1;
+		u32     clear:1;
+		u32     patrol:1;
+		u32     rbld:1;
+#endif
+	} active;
+	union MR_PROGRESS     rbld;
+	union MR_PROGRESS     patrol;
+	union {
+		union MR_PROGRESS     clear;
+		union MR_PROGRESS     erase;
+	};
+
+	struct {
+#ifndef MFI_BIG_ENDIAN
+		u32     rbld:1;
+		u32     patrol:1;
+		u32     clear:1;
+		u32     copyBack:1;
+		u32     erase:1;
+		u32     reserved:27;
+#else
+		u32     reserved:27;
+		u32     erase:1;
+		u32     copyBack:1;
+		u32     clear:1;
+		u32     patrol:1;
+		u32     rbld:1;
+#endif
+	} pause;
+
+	union MR_PROGRESS     reserved[3];
+} __packed;
+
+struct  MR_PD_INFO {
+	union MR_PD_REF	ref;
+	u8 inquiryData[96];
+	u8 vpdPage83[64];
+	u8 notSupported;
+	u8 scsiDevType;
+
+	union {
+		u8 connectedPortBitmap;
+		u8 connectedPortNumbers;
+	};
+
+	u8 deviceSpeed;
+	u32 mediaErrCount;
+	u32 otherErrCount;
+	u32 predFailCount;
+	u32 lastPredFailEventSeqNum;
+
+	u16 fwState;
+	u8 disabledForRemoval;
+	u8 linkSpeed;
+	union MR_PD_DDF_TYPE state;
+
+	struct {
+		u8 count;
+#ifndef __BIG_ENDIAN_BITFIELD
+		u8 isPathBroken:4;
+		u8 reserved3:3;
+		u8 widePortCapable:1;
+#else
+		u8 widePortCapable:1;
+		u8 reserved3:3;
+		u8 isPathBroken:4;
+#endif
+
+		u8 connectorIndex[2];
+		u8 reserved[4];
+		u64 sasAddr[2];
+		u8 reserved2[16];
+	} pathInfo;
+
+	u64 rawSize;
+	u64 nonCoercedSize;
+	u64 coercedSize;
+	u16 enclDeviceId;
+	u8 enclIndex;
+
+	union {
+		u8 slotNumber;
+		u8 enclConnectorIndex;
+	};
+
+	struct MR_PD_PROGRESS progInfo;
+	u8 badBlockTableFull;
+	u8 unusableInCurrentConfig;
+	u8 vpdPage83Ext[64];
+	u8 powerState;
+	u8 enclPosition;
+	u32 allowedOps;
+	u16 copyBackPartnerId;
+	u16 enclPartnerDeviceId;
+	struct {
+#ifndef __BIG_ENDIAN_BITFIELD
+		u16 fdeCapable:1;
+		u16 fdeEnabled:1;
+		u16 secured:1;
+		u16 locked:1;
+		u16 foreign:1;
+		u16 needsEKM:1;
+		u16 reserved:10;
+#else
+		u16 reserved:10;
+		u16 needsEKM:1;
+		u16 foreign:1;
+		u16 locked:1;
+		u16 secured:1;
+		u16 fdeEnabled:1;
+		u16 fdeCapable:1;
+#endif
+	} security;
+	u8 mediaType;
+	u8 notCertified;
+	u8 bridgeVendor[8];
+	u8 bridgeProductIdentification[16];
+	u8 bridgeProductRevisionLevel[4];
+	u8 satBridgeExists;
+
+	u8 interfaceType;
+	u8 temperature;
+	u8 emulatedBlockSize;
+	u16 userDataBlockSize;
+	u16 reserved2;
+
+	struct {
+#ifndef __BIG_ENDIAN_BITFIELD
+		u32 piType:3;
+		u32 piFormatted:1;
+		u32 piEligible:1;
+		u32 NCQ:1;
+		u32 WCE:1;
+		u32 commissionedSpare:1;
+		u32 emergencySpare:1;
+		u32 ineligibleForSSCD:1;
+		u32 ineligibleForLd:1;
+		u32 useSSEraseType:1;
+		u32 wceUnchanged:1;
+		u32 supportScsiUnmap:1;
+		u32 reserved:18;
+#else
+		u32 reserved:18;
+		u32 supportScsiUnmap:1;
+		u32 wceUnchanged:1;
+		u32 useSSEraseType:1;
+		u32 ineligibleForLd:1;
+		u32 ineligibleForSSCD:1;
+		u32 emergencySpare:1;
+		u32 commissionedSpare:1;
+		u32 WCE:1;
+		u32 NCQ:1;
+		u32 piEligible:1;
+		u32 piFormatted:1;
+		u32 piType:3;
+#endif
+	} properties;
+
+	u64 shieldDiagCompletionTime;
+	u8 shieldCounter;
+
+	u8 linkSpeedOther;
+	u8 reserved4[2];
+
+	struct {
+#ifndef __BIG_ENDIAN_BITFIELD
+		u32 bbmErrCountSupported:1;
+		u32 bbmErrCount:31;
+#else
+		u32 bbmErrCount:31;
+		u32 bbmErrCountSupported:1;
+#endif
+	} bbmErr;
+
+	u8 reserved1[512-428];
+} __packed;
 
  /*
  * defines the physical drive address structure
@@ -474,6 +726,7 @@ struct megasas_pd_list {
 	u16             tid;
 	u8             driveType;
 	u8             driveState;
+	u8             interface;
 } __packed;
 
  /*
@@ -1718,6 +1971,19 @@ struct MR_DRV_SYSTEM_INFO {
 	u8	reserved[1980];
 };
 
+enum MR_PD_TYPE {
+		 UNKNOWN_DRIVE = 0,
+		 PARALLEL_SCSI = 1,
+		 SAS_PD = 2,
+		 SATA_PD = 3,
+		 FC_PD = 4,
+};
+
+/* JBOD Queue depth definitions */
+#define MEGASAS_SATA_QD	32
+#define MEGASAS_SAS_QD	64
+#define MEGASAS_DEFAULT_PD_QD	64
+
 struct megasas_instance {
 
 	__le32 *producer;
@@ -1732,6 +1998,8 @@ struct megasas_instance {
 	dma_addr_t vf_affiliation_111_h;
 	struct MR_CTRL_HB_HOST_MEM *hb_host_mem;
 	dma_addr_t hb_host_mem_h;
+	struct MR_PD_INFO *pd_info;
+	dma_addr_t pd_info_h;
 
 	__le32 *reply_queue;
 	dma_addr_t reply_queue_h;
@@ -1780,7 +2048,7 @@ struct megasas_instance {
 	struct megasas_evt_detail *evt_detail;
 	dma_addr_t evt_detail_h;
 	struct megasas_cmd *aen_cmd;
-	struct mutex aen_mutex;
+	struct mutex hba_mutex;
 	struct semaphore ioctl_sem;
 
 	struct Scsi_Host *host;
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index c1dc23c..df93fa1 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -104,6 +104,8 @@ static int megasas_ld_list_query(struct megasas_instance *instance,
 static int megasas_issue_init_mfi(struct megasas_instance *instance);
 static int megasas_register_aen(struct megasas_instance *instance,
 				u32 seq_num, u32 class_locale_word);
+static int
+megasas_get_pd_info(struct megasas_instance *instance, u16 device_id);
 /*
  * PCI ID table for all supported controllers
  */
@@ -1796,6 +1798,44 @@ void megasas_update_sdev_properties(struct scsi_device *sdev)
 	}
 }
 
+static void megasas_set_device_queue_depth(struct scsi_device *sdev)
+{
+	u16				pd_index = 0;
+	int		ret = DCMD_FAILED;
+	struct megasas_instance *instance;
+
+	instance = megasas_lookup_instance(sdev->host->host_no);
+
+	if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
+		pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id;
+
+		if (instance->pd_info) {
+			mutex_lock(&instance->hba_mutex);
+			ret = megasas_get_pd_info(instance, pd_index);
+			mutex_unlock(&instance->hba_mutex);
+		}
+
+		if (ret != DCMD_SUCCESS)
+			return;
+
+		if (instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) {
+
+			switch (instance->pd_list[pd_index].interface) {
+			case SAS_PD:
+				scsi_change_queue_depth(sdev, MEGASAS_SAS_QD);
+				break;
+
+			case SATA_PD:
+				scsi_change_queue_depth(sdev, MEGASAS_SATA_QD);
+				break;
+
+			default:
+				scsi_change_queue_depth(sdev, MEGASAS_DEFAULT_PD_QD);
+			}
+		}
+	}
+}
+
 
 static int megasas_slave_configure(struct scsi_device *sdev)
 {
@@ -1813,6 +1853,7 @@ static int megasas_slave_configure(struct scsi_device *sdev)
 				return -ENXIO;
 		}
 	}
+	megasas_set_device_queue_depth(sdev);
 	megasas_update_sdev_properties(sdev);
 
 	/*
@@ -3922,6 +3963,73 @@ dcmd_timeout_ocr_possible(struct megasas_instance *instance) {
 		return INITIATE_OCR;
 }
 
+static int
+megasas_get_pd_info(struct megasas_instance *instance, u16 device_id)
+{
+	int ret;
+	struct megasas_cmd *cmd;
+	struct megasas_dcmd_frame *dcmd;
+
+	cmd = megasas_get_cmd(instance);
+
+	if (!cmd) {
+		dev_err(&instance->pdev->dev, "Failed to get cmd %s\n", __func__);
+		return -ENOMEM;
+	}
+
+	dcmd = &cmd->frame->dcmd;
+
+	memset(instance->pd_info, 0, sizeof(*instance->pd_info));
+	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+	dcmd->mbox.s[0] = cpu_to_le16(device_id);
+	dcmd->cmd = MFI_CMD_DCMD;
+	dcmd->cmd_status = 0xFF;
+	dcmd->sge_count = 1;
+	dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ);
+	dcmd->timeout = 0;
+	dcmd->pad_0 = 0;
+	dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_PD_INFO));
+	dcmd->opcode = cpu_to_le32(MR_DCMD_PD_GET_INFO);
+	dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(instance->pd_info_h);
+	dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct MR_PD_INFO));
+
+	if (instance->ctrl_context && !instance->mask_interrupts)
+		ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
+	else
+		ret = megasas_issue_polled(instance, cmd);
+
+	switch (ret) {
+	case DCMD_SUCCESS:
+		instance->pd_list[device_id].interface =
+				instance->pd_info->state.ddf.pdType.intf;
+		break;
+
+	case DCMD_TIMEOUT:
+
+		switch (dcmd_timeout_ocr_possible(instance)) {
+		case INITIATE_OCR:
+			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+			megasas_reset_fusion(instance->host,
+				MFI_IO_TIMEOUT_OCR);
+			break;
+		case KILL_ADAPTER:
+			megaraid_sas_kill_hba(instance);
+			break;
+		case IGNORE_TIMEOUT:
+			dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
+				__func__, __LINE__);
+			break;
+		}
+
+		break;
+	}
+
+	if (ret != DCMD_TIMEOUT)
+		megasas_return_cmd(instance, cmd);
+
+	return ret;
+}
 /*
  * megasas_get_pd_list_info -	Returns FW's pd_list structure
  * @instance:				Adapter soft state
@@ -5680,6 +5788,12 @@ static int megasas_probe_one(struct pci_dev *pdev,
 		goto fail_alloc_dma_buf;
 	}
 
+	instance->pd_info = pci_alloc_consistent(pdev,
+		sizeof(struct MR_PD_INFO), &instance->pd_info_h);
+
+	if (!instance->pd_info)
+		dev_err(&instance->pdev->dev, "Failed to alloc mem for pd_info\n");
+
 	/*
 	 * Initialize locks and queues
 	 */
@@ -5696,6 +5810,7 @@ static int megasas_probe_one(struct pci_dev *pdev,
 	spin_lock_init(&instance->completion_lock);
 
 	mutex_init(&instance->reset_mutex);
+	mutex_init(&instance->hba_mutex);
 
 	/*
 	 * Initialize PCI related and misc parameters
@@ -5810,6 +5925,10 @@ fail_alloc_dma_buf:
 				    instance->evt_detail,
 				    instance->evt_detail_h);
 
+	if (instance->pd_info)
+		pci_free_consistent(pdev, sizeof(struct MR_PD_INFO),
+					instance->pd_info,
+					instance->pd_info_h);
 	if (instance->producer)
 		pci_free_consistent(pdev, sizeof(u32), instance->producer,
 				    instance->producer_h);
@@ -6071,6 +6190,10 @@ fail_init_mfi:
 				instance->evt_detail,
 				instance->evt_detail_h);
 
+	if (instance->pd_info)
+		pci_free_consistent(pdev, sizeof(struct MR_PD_INFO),
+					instance->pd_info,
+					instance->pd_info_h);
 	if (instance->producer)
 		pci_free_consistent(pdev, sizeof(u32), instance->producer,
 				instance->producer_h);
@@ -6189,6 +6312,10 @@ static void megasas_detach_one(struct pci_dev *pdev)
 		pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
 				instance->evt_detail, instance->evt_detail_h);
 
+	if (instance->pd_info)
+		pci_free_consistent(pdev, sizeof(struct MR_PD_INFO),
+					instance->pd_info,
+					instance->pd_info_h);
 	if (instance->vf_affiliation)
 		pci_free_consistent(pdev, (MAX_LOGICAL_DRIVES + 1) *
 				    sizeof(struct MR_LD_VF_AFFILIATION),
-- 
1.7.1


^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 06/15] megaraid_sas: Fastpath region lock bypass
  2015-12-18 13:26 [PATCH 00/15] megaraid_sas: Updates for scsi-next Sumit Saxena
                   ` (4 preceding siblings ...)
  2015-12-18 13:26 ` [PATCH 05/15] megaraid_sas: Update device Queue depth based on interface type Sumit Saxena
@ 2015-12-18 13:26 ` Sumit Saxena
  2016-01-12 14:44   ` Tomas Henzl
  2015-12-18 13:27 ` [PATCH 07/15] megaraid_sas: Reply Descriptor Post Queue(RDPQ) support Sumit Saxena
                   ` (8 subsequent siblings)
  14 siblings, 1 reply; 50+ messages in thread
From: Sumit Saxena @ 2015-12-18 13:26 UTC (permalink / raw)
  To: jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai, sumit.saxena

Firmware will fill per LD data to tell driver that particular LD supports Region lock bypass or not. If yes, then 
Driver will send non FP LDIO to region lock bypass FIFO. With this change in driver, firmware will optimize certain
code to improve performance.

Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
---
 drivers/scsi/megaraid/megaraid_sas.h        |    8 ++++++--
 drivers/scsi/megaraid/megaraid_sas_fp.c     |    2 ++
 drivers/scsi/megaraid/megaraid_sas_fusion.c |    6 ++++--
 drivers/scsi/megaraid/megaraid_sas_fusion.h |    8 +++++---
 4 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 773fc54..01135be 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -1528,7 +1528,9 @@ union megasas_sgl_frame {
 typedef union _MFI_CAPABILITIES {
 	struct {
 #if   defined(__BIG_ENDIAN_BITFIELD)
-		u32     reserved:23;
+		u32     reserved:21;
+		u32     support_fp_rlbypass:1;
+		u32     support_vfid_in_ioframe:1;
 		u32     support_ext_io_size:1;
 		u32	support_ext_queue_depth:1;
 		u32     security_protocol_cmds_fw:1;
@@ -1548,7 +1550,9 @@ typedef union _MFI_CAPABILITIES {
 		u32     security_protocol_cmds_fw:1;
 		u32	support_ext_queue_depth:1;
 		u32     support_ext_io_size:1;
-		u32     reserved:23;
+		u32     support_vfid_in_ioframe:1;
+		u32     support_fp_rlbypass:1;
+		u32     reserved:21;
 #endif
 	} mfi_capabilities;
 	__le32		reg;
diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c
index 741509b..e413113 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fp.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fp.c
@@ -1020,6 +1020,8 @@ MR_BuildRaidContext(struct megasas_instance *instance,
 	/* assume this IO needs the full row - we'll adjust if not true */
 	regSize             = stripSize;
 
+	io_info->do_fp_rlbypass = raid->capability.fpBypassRegionLock;
+
 	/* Check if we can send this I/O via FastPath */
 	if (raid->capability.fpCapable) {
 		if (isRead)
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index 0b31f5a..e8730ef 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -666,6 +666,8 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
 	if (instance->max_chain_frame_sz > MEGASAS_CHAIN_FRAME_SZ_MIN)
 		drv_ops->mfi_capabilities.support_ext_io_size = 1;
 
+	drv_ops->mfi_capabilities.support_fp_rlbypass = 1;
+
 	/* Convert capability to LE32 */
 	cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities);
 
@@ -1710,8 +1712,8 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
 			(MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO
 			 << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
 		if (fusion->adapter_type == INVADER_SERIES) {
-			if (io_request->RaidContext.regLockFlags ==
-			    REGION_TYPE_UNUSED)
+			if (io_info.do_fp_rlbypass ||
+				(io_request->RaidContext.regLockFlags == REGION_TYPE_UNUSED))
 				cmd->request_desc->SCSIIO.RequestFlags =
 					(MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK <<
 					MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
index a1f1c0b..db0978d 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
@@ -643,7 +643,8 @@ struct MR_SPAN_BLOCK_INFO {
 struct MR_LD_RAID {
 	struct {
 #if   defined(__BIG_ENDIAN_BITFIELD)
-		u32     reserved4:6;
+		u32     reserved4:5;
+		u32     fpBypassRegionLock:1;
 		u32     tmCapable:1;
 		u32	fpNonRWCapable:1;
 		u32     fpReadAcrossStripe:1;
@@ -667,7 +668,8 @@ struct MR_LD_RAID {
 		u32     fpReadAcrossStripe:1;
 		u32	fpNonRWCapable:1;
 		u32     tmCapable:1;
-		u32     reserved4:6;
+		u32     fpBypassRegionLock:1;
+		u32     reserved4:5;
 #endif
 	} capability;
 	__le32     reserved6;
@@ -737,7 +739,7 @@ struct IO_REQUEST_INFO {
 	u8 fpOkForIo;
 	u8 IoforUnevenSpan;
 	u8 start_span;
-	u8 reserved;
+	u8 do_fp_rlbypass;
 	u64 start_row;
 	u8  span_arm;	/* span[7:5], arm[4:0] */
 	u8  pd_after_lb;
-- 
1.7.1


^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 07/15] megaraid_sas: Reply Descriptor Post Queue(RDPQ) support
  2015-12-18 13:26 [PATCH 00/15] megaraid_sas: Updates for scsi-next Sumit Saxena
                   ` (5 preceding siblings ...)
  2015-12-18 13:26 ` [PATCH 06/15] megaraid_sas: Fastpath region lock bypass Sumit Saxena
@ 2015-12-18 13:27 ` Sumit Saxena
  2015-12-18 14:49   ` [PATCH] megaraid_sas: fix kzalloc-simple.cocci warnings kbuild test robot
                     ` (2 more replies)
  2015-12-18 13:27 ` [PATCH 08/15] megaraid_sas: Code optimization build_and_issue_cmd return-type Sumit Saxena
                   ` (7 subsequent siblings)
  14 siblings, 3 replies; 50+ messages in thread
From: Sumit Saxena @ 2015-12-18 13:27 UTC (permalink / raw)
  To: jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai, sumit.saxena

This patch will create reply queue pool for each MSI-x index and will provide array of all reply queue base address
instead of single base address of legacy mode. Using this new interface Driver can support higher Queue depth allocating
more reply queue as scattered DMA pool. 

If array mode is not supported driver will fall back to legacy method of allocation reply pool. 
This method fall back controller queue depth to 1K max. To enable more than 1K QD, driver expect FW to support Array mode 
and scratch_pad3 should provide new queue depth value.

Using this method, Firmware should not allow downgrade (OFU) if latest driver and latest FW report 4K QD and Array mode reply queue.
This type of FW upgrade may cause firmware fault and it should not be supported. Upgrade of FW will work, 
but queue depth of the controller will be unchanged until reboot/driver reload.

Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
---
 drivers/scsi/megaraid/megaraid_sas.h        |    6 +-
 drivers/scsi/megaraid/megaraid_sas_base.c   |    9 +
 drivers/scsi/megaraid/megaraid_sas_fusion.c |  543 +++++++++++++++------------
 drivers/scsi/megaraid/megaraid_sas_fusion.h |   12 +-
 4 files changed, 330 insertions(+), 240 deletions(-)

diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 01135be..c539516 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -152,6 +152,7 @@
 #define MFI_RESET_FLAGS				MFI_INIT_READY| \
 						MFI_INIT_MFIMODE| \
 						MFI_INIT_ABORT
+#define MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE    (0x01)
 
 /*
  * MFI frame flags
@@ -1416,6 +1417,7 @@ enum DCMD_TIMEOUT_ACTION {
 #define MR_MAX_REPLY_QUEUES_EXT_OFFSET          0X003FC000
 #define MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT    14
 #define MR_MAX_MSIX_REG_ARRAY                   16
+#define MR_RDPQ_MODE_OFFSET			0X00800000
 /*
 * register set for both 1068 and 1078 controllers
 * structure extended for 1078 registers
@@ -1455,8 +1457,9 @@ struct megasas_register_set {
 
 	u32 	outbound_scratch_pad ;		/*00B0h*/
 	u32	outbound_scratch_pad_2;         /*00B4h*/
+	u32	outbound_scratch_pad_3;         /*00B8h*/
 
-	u32	reserved_4[2];			/*00B8h*/
+	u32	reserved_4;			/*00BCh*/
 
 	u32 	inbound_low_queue_port ;	/*00C0h*/
 
@@ -2117,6 +2120,7 @@ struct megasas_instance {
 	u8 mask_interrupts;
 	u16 max_chain_frame_sz;
 	u8 is_imr;
+	u8 is_rdpq;
 	bool dev_handle;
 };
 struct MR_LD_VF_MAP {
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index df93fa1..a3b63fa 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -92,6 +92,10 @@ int smp_affinity_enable = 1;
 module_param(smp_affinity_enable, int, S_IRUGO);
 MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disbale Default: enable(1)");
 
+int rdpq_enable = 1;
+module_param(rdpq_enable, int, S_IRUGO);
+MODULE_PARM_DESC(rdpq_enable, " Allocate reply queue in chunks for large queue depth enable/disbale Default: disable(0)");
+
 MODULE_LICENSE("GPL");
 MODULE_VERSION(MEGASAS_VERSION);
 MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com");
@@ -5081,6 +5085,9 @@ static int megasas_init_fw(struct megasas_instance *instance)
 				instance->msix_vectors = ((scratch_pad_2
 					& MR_MAX_REPLY_QUEUES_EXT_OFFSET)
 					>> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1;
+				if (rdpq_enable)
+					instance->is_rdpq = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ?
+								1 : 0;
 				fw_msix_count = instance->msix_vectors;
 				/* Save 1-15 reply post index address to local memory
 				 * Index 0 is already saved from reg offset
@@ -5117,6 +5124,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
 	dev_info(&instance->pdev->dev,
 		"current msix/online cpus\t: (%d/%d)\n",
 		instance->msix_vectors, (unsigned int)num_online_cpus());
+	dev_info(&instance->pdev->dev,
+		"firmware supports rdpq mode\t: (%d)\n", instance->is_rdpq);
 
 	tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
 		(unsigned long)instance);
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index e8730ef..aca0cd3 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -92,6 +92,8 @@ void megasas_start_timer(struct megasas_instance *instance,
 			 void *fn, unsigned long interval);
 extern struct megasas_mgmt_info megasas_mgmt_info;
 extern int resetwaittime;
+static void megasas_free_rdpq_fusion(struct megasas_instance *instance);
+static void megasas_free_reply_fusion(struct megasas_instance *instance);
 
 
 
@@ -205,112 +207,71 @@ megasas_fire_cmd_fusion(struct megasas_instance *instance,
 #endif
 }
 
-
 /**
- * megasas_teardown_frame_pool_fusion -	Destroy the cmd frame DMA pool
- * @instance:				Adapter soft state
+ * megasas_free_cmds_fusion -	Free all the cmds in the free cmd pool
+ * @instance:		Adapter soft state
  */
-static void megasas_teardown_frame_pool_fusion(
-	struct megasas_instance *instance)
+void
+megasas_free_cmds_fusion(struct megasas_instance *instance)
 {
 	int i;
 	struct fusion_context *fusion = instance->ctrl_context;
-
-	u16 max_cmd = instance->max_fw_cmds;
-
 	struct megasas_cmd_fusion *cmd;
 
-	if (!fusion->sg_dma_pool || !fusion->sense_dma_pool) {
-		dev_err(&instance->pdev->dev, "dma pool is null. SG Pool %p, "
-		       "sense pool : %p\n", fusion->sg_dma_pool,
-		       fusion->sense_dma_pool);
-		return;
-	}
-
-	/*
-	 * Return all frames to pool
-	 */
-	for (i = 0; i < max_cmd; i++) {
-
+	/* SG, Sense */
+	for (i = 0; i < instance->max_fw_cmds; i++) {
 		cmd = fusion->cmd_list[i];
-
 		if (cmd->sg_frame)
 			pci_pool_free(fusion->sg_dma_pool, cmd->sg_frame,
-				      cmd->sg_frame_phys_addr);
-
+			      cmd->sg_frame_phys_addr);
 		if (cmd->sense)
 			pci_pool_free(fusion->sense_dma_pool, cmd->sense,
-				      cmd->sense_phys_addr);
+			      cmd->sense_phys_addr);
 	}
 
-	/*
-	 * Now destroy the pool itself
-	 */
-	pci_pool_destroy(fusion->sg_dma_pool);
-	pci_pool_destroy(fusion->sense_dma_pool);
-
-	fusion->sg_dma_pool = NULL;
-	fusion->sense_dma_pool = NULL;
-}
-
-/**
- * megasas_free_cmds_fusion -	Free all the cmds in the free cmd pool
- * @instance:		Adapter soft state
- */
-void
-megasas_free_cmds_fusion(struct megasas_instance *instance)
-{
-	int i;
-	struct fusion_context *fusion = instance->ctrl_context;
-
-	u32 max_cmds, req_sz, reply_sz, io_frames_sz;
-
+	if (fusion->sg_dma_pool) {
+		pci_pool_destroy(fusion->sg_dma_pool);
+		fusion->sg_dma_pool = NULL;
+	}
+	if (fusion->sense_dma_pool) {
+		pci_pool_destroy(fusion->sense_dma_pool);
+		fusion->sense_dma_pool = NULL;
+	}
 
-	req_sz = fusion->request_alloc_sz;
-	reply_sz = fusion->reply_alloc_sz;
-	io_frames_sz = fusion->io_frames_alloc_sz;
 
-	max_cmds = instance->max_fw_cmds;
+	/* Reply Frame, Desc*/
+	if (instance->is_rdpq)
+		megasas_free_rdpq_fusion(instance);
+	else
+		megasas_free_reply_fusion(instance);
 
-	/* Free descriptors and request Frames memory */
+	/* Request Frame, Desc*/
 	if (fusion->req_frames_desc)
-		dma_free_coherent(&instance->pdev->dev, req_sz,
-				  fusion->req_frames_desc,
-				  fusion->req_frames_desc_phys);
-
-	if (fusion->reply_frames_desc) {
-		pci_pool_free(fusion->reply_frames_desc_pool,
-			      fusion->reply_frames_desc,
-			      fusion->reply_frames_desc_phys);
-		pci_pool_destroy(fusion->reply_frames_desc_pool);
-	}
-
-	if (fusion->io_request_frames) {
+		dma_free_coherent(&instance->pdev->dev,
+			fusion->request_alloc_sz, fusion->req_frames_desc,
+			fusion->req_frames_desc_phys);
+	if (fusion->io_request_frames)
 		pci_pool_free(fusion->io_request_frames_pool,
-			      fusion->io_request_frames,
-			      fusion->io_request_frames_phys);
+			fusion->io_request_frames,
+			fusion->io_request_frames_phys);
+	if (fusion->io_request_frames_pool)
 		pci_pool_destroy(fusion->io_request_frames_pool);
-	}
 
-	/* Free the Fusion frame pool */
-	megasas_teardown_frame_pool_fusion(instance);
 
-	/* Free all the commands in the cmd_list */
-	for (i = 0; i < max_cmds; i++)
+	/* cmd_list */
+	for (i = 0; i < instance->max_fw_cmds; i++)
 		kfree(fusion->cmd_list[i]);
 
-	/* Free the cmd_list buffer itself */
 	kfree(fusion->cmd_list);
 	fusion->cmd_list = NULL;
-
 }
 
 /**
- * megasas_create_frame_pool_fusion -	Creates DMA pool for cmd frames
+ * megasas_create_sg_sense_fusion -	Creates DMA pool for cmd frames
  * @instance:			Adapter soft state
  *
  */
-static int megasas_create_frame_pool_fusion(struct megasas_instance *instance)
+static int megasas_create_sg_sense_fusion(struct megasas_instance *instance)
 {
 	int i;
 	u32 max_cmd;
@@ -321,186 +282,299 @@ static int megasas_create_frame_pool_fusion(struct megasas_instance *instance)
 	max_cmd = instance->max_fw_cmds;
 
 
-	/*
-	 * Use DMA pool facility provided by PCI layer
-	 */
-
-	fusion->sg_dma_pool = pci_pool_create("sg_pool_fusion", instance->pdev,
-						instance->max_chain_frame_sz,
-						4, 0);
-	if (!fusion->sg_dma_pool) {
-		dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup request pool fusion\n");
-		return -ENOMEM;
-	}
-	fusion->sense_dma_pool = pci_pool_create("sense pool fusion",
-						 instance->pdev,
-						 SCSI_SENSE_BUFFERSIZE, 64, 0);
+	fusion->sg_dma_pool =
+			pci_pool_create("mr_sg", instance->pdev,
+				instance->max_chain_frame_sz, 4, 0);
+	/* SCSI_SENSE_BUFFERSIZE  = 96 bytes */
+	fusion->sense_dma_pool =
+			pci_pool_create("mr_sense", instance->pdev,
+				SCSI_SENSE_BUFFERSIZE, 64, 0);
 
-	if (!fusion->sense_dma_pool) {
-		dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup sense pool fusion\n");
-		pci_pool_destroy(fusion->sg_dma_pool);
-		fusion->sg_dma_pool = NULL;
-		return -ENOMEM;
-	}
+	if (!fusion->sense_dma_pool || !fusion->sg_dma_pool)
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
 
 	/*
 	 * Allocate and attach a frame to each of the commands in cmd_list
 	 */
 	for (i = 0; i < max_cmd; i++) {
-
 		cmd = fusion->cmd_list[i];
-
 		cmd->sg_frame = pci_pool_alloc(fusion->sg_dma_pool,
-					       GFP_KERNEL,
-					       &cmd->sg_frame_phys_addr);
+					GFP_KERNEL, &cmd->sg_frame_phys_addr);
 
 		cmd->sense = pci_pool_alloc(fusion->sense_dma_pool,
-					    GFP_KERNEL, &cmd->sense_phys_addr);
-		/*
-		 * megasas_teardown_frame_pool_fusion() takes care of freeing
-		 * whatever has been allocated
-		 */
+					GFP_KERNEL, &cmd->sense_phys_addr);
 		if (!cmd->sg_frame || !cmd->sense) {
-			dev_printk(KERN_DEBUG, &instance->pdev->dev, "pci_pool_alloc failed\n");
-			megasas_teardown_frame_pool_fusion(instance);
+			dev_err(&instance->pdev->dev,
+				"Failed from %s %d\n",  __func__, __LINE__);
 			return -ENOMEM;
 		}
 	}
 	return 0;
 }
 
-/**
- * megasas_alloc_cmds_fusion -	Allocates the command packets
- * @instance:		Adapter soft state
- *
- *
- * Each frame has a 32-bit field called context. This context is used to get
- * back the megasas_cmd_fusion from the frame when a frame gets completed
- * In this driver, the 32 bit values are the indices into an array cmd_list.
- * This array is used only to look up the megasas_cmd_fusion given the context.
- * The free commands themselves are maintained in a linked list called cmd_pool.
- *
- * cmds are formed in the io_request and sg_frame members of the
- * megasas_cmd_fusion. The context field is used to get a request descriptor
- * and is used as SMID of the cmd.
- * SMID value range is from 1 to max_fw_cmds.
- */
 int
-megasas_alloc_cmds_fusion(struct megasas_instance *instance)
+megasas_alloc_cmdlist_fusion(struct megasas_instance *instance)
 {
-	int i, j, count;
-	u32 max_cmd, io_frames_sz;
+	u32 max_cmd, i;
 	struct fusion_context *fusion;
-	struct megasas_cmd_fusion *cmd;
-	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
-	u32 offset;
-	dma_addr_t io_req_base_phys;
-	u8 *io_req_base;
 
 	fusion = instance->ctrl_context;
 
 	max_cmd = instance->max_fw_cmds;
 
+	/*
+	 * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers.
+	 * Allocate the dynamic array first and then allocate individual
+	 * commands.
+	 */
+	fusion->cmd_list = kmalloc(sizeof(struct megasas_cmd_fusion *) * max_cmd,
+						GFP_KERNEL);
+	if (!fusion->cmd_list) {
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
+	}
+	memset(fusion->cmd_list, 0,
+		sizeof(struct megasas_cmd_fusion *) * max_cmd);
+
+	for (i = 0; i < max_cmd; i++) {
+		fusion->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd_fusion),
+					      GFP_KERNEL);
+		if (!fusion->cmd_list[i]) {
+			dev_err(&instance->pdev->dev,
+				"Failed from %s %d\n",  __func__, __LINE__);
+			return -ENOMEM;
+		}
+		memset(fusion->cmd_list[i], 0, sizeof(struct megasas_cmd_fusion));
+	}
+	return 0;
+}
+int
+megasas_alloc_request_fusion(struct megasas_instance *instance)
+{
+	struct fusion_context *fusion;
+
+	fusion = instance->ctrl_context;
+
 	fusion->req_frames_desc =
 		dma_alloc_coherent(&instance->pdev->dev,
-				   fusion->request_alloc_sz,
-				   &fusion->req_frames_desc_phys, GFP_KERNEL);
-
+			fusion->request_alloc_sz,
+			&fusion->req_frames_desc_phys, GFP_KERNEL);
 	if (!fusion->req_frames_desc) {
-		dev_err(&instance->pdev->dev, "Could not allocate memory for "
-		       "request_frames\n");
-		goto fail_req_desc;
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	fusion->io_request_frames_pool =
+			pci_pool_create("mr_ioreq", instance->pdev,
+				fusion->io_frames_alloc_sz, 16, 0);
+
+	if (!fusion->io_request_frames_pool) {
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	fusion->io_request_frames =
+			pci_pool_alloc(fusion->io_request_frames_pool,
+				GFP_KERNEL, &fusion->io_request_frames_phys);
+	if (!fusion->io_request_frames) {
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
 	}
+	return 0;
+}
+
+int
+megasas_alloc_reply_fusion(struct megasas_instance *instance)
+{
+	int i, count;
+	struct fusion_context *fusion;
+	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
+	fusion = instance->ctrl_context;
 
 	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
 	fusion->reply_frames_desc_pool =
-		pci_pool_create("reply_frames pool", instance->pdev,
+			pci_pool_create("mr_reply", instance->pdev,
 				fusion->reply_alloc_sz * count, 16, 0);
 
 	if (!fusion->reply_frames_desc_pool) {
-		dev_err(&instance->pdev->dev, "Could not allocate memory for "
-		       "reply_frame pool\n");
-		goto fail_reply_desc;
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
 	}
 
-	fusion->reply_frames_desc =
-		pci_pool_alloc(fusion->reply_frames_desc_pool, GFP_KERNEL,
-			       &fusion->reply_frames_desc_phys);
-	if (!fusion->reply_frames_desc) {
-		dev_err(&instance->pdev->dev, "Could not allocate memory for "
-		       "reply_frame pool\n");
-		pci_pool_destroy(fusion->reply_frames_desc_pool);
-		goto fail_reply_desc;
+	fusion->reply_frames_desc[0] =
+		pci_pool_alloc(fusion->reply_frames_desc_pool,
+			GFP_KERNEL, &fusion->reply_frames_desc_phys[0]);
+	if (!fusion->reply_frames_desc[0]) {
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
 	}
-
-	reply_desc = fusion->reply_frames_desc;
+	reply_desc = fusion->reply_frames_desc[0];
 	for (i = 0; i < fusion->reply_q_depth * count; i++, reply_desc++)
-		reply_desc->Words = cpu_to_le64(ULLONG_MAX);
+		reply_desc->Words = ULLONG_MAX;
 
-	io_frames_sz = fusion->io_frames_alloc_sz;
+	/* This is not a rdpq mode, but driver still populate
+	 * reply_frame_desc array to use same msix index in ISR path.
+	 */
+	for (i = 0; i < (count - 1); i++)
+		fusion->reply_frames_desc[i + 1] =
+			fusion->reply_frames_desc[i] +
+			(fusion->reply_alloc_sz)/sizeof(union MPI2_REPLY_DESCRIPTORS_UNION);
 
-	fusion->io_request_frames_pool =
-		pci_pool_create("io_request_frames pool", instance->pdev,
-				fusion->io_frames_alloc_sz, 16, 0);
+	return 0;
+}
 
-	if (!fusion->io_request_frames_pool) {
-		dev_err(&instance->pdev->dev, "Could not allocate memory for "
-		       "io_request_frame pool\n");
-		goto fail_io_frames;
+int
+megasas_alloc_rdpq_fusion(struct megasas_instance *instance)
+{
+	int i, j, count;
+	struct fusion_context *fusion;
+	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
+
+	fusion = instance->ctrl_context;
+
+	fusion->rdpq_virt = pci_alloc_consistent(instance->pdev,
+				sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION,
+				&fusion->rdpq_phys);
+	if (!fusion->rdpq_virt) {
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
 	}
 
-	fusion->io_request_frames =
-		pci_pool_alloc(fusion->io_request_frames_pool, GFP_KERNEL,
-			       &fusion->io_request_frames_phys);
-	if (!fusion->io_request_frames) {
-		dev_err(&instance->pdev->dev, "Could not allocate memory for "
-		       "io_request_frames frames\n");
-		pci_pool_destroy(fusion->io_request_frames_pool);
-		goto fail_io_frames;
+	memset(fusion->rdpq_virt, 0,
+			sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION);
+	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+	fusion->reply_frames_desc_pool = pci_pool_create("mr_rdpq",
+							 instance->pdev, fusion->reply_alloc_sz, 16, 0);
+
+	if (!fusion->reply_frames_desc_pool) {
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
 	}
 
-	/*
-	 * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers.
-	 * Allocate the dynamic array first and then allocate individual
-	 * commands.
-	 */
-	fusion->cmd_list = kzalloc(sizeof(struct megasas_cmd_fusion *)
-				   * max_cmd, GFP_KERNEL);
+	for (i = 0; i < count; i++) {
+		fusion->reply_frames_desc[i] =
+				pci_pool_alloc(fusion->reply_frames_desc_pool,
+					GFP_KERNEL, &fusion->reply_frames_desc_phys[i]);
+		if (!fusion->reply_frames_desc[i]) {
+			dev_err(&instance->pdev->dev,
+				"Failed from %s %d\n",  __func__, __LINE__);
+			return -ENOMEM;
+		}
 
-	if (!fusion->cmd_list) {
-		dev_printk(KERN_DEBUG, &instance->pdev->dev, "out of memory. Could not alloc "
-		       "memory for cmd_list_fusion\n");
-		goto fail_cmd_list;
+		fusion->rdpq_virt[i].RDPQBaseAddress =
+			fusion->reply_frames_desc_phys[i];
+
+		reply_desc = fusion->reply_frames_desc[i];
+		for (j = 0; j < fusion->reply_q_depth; j++, reply_desc++)
+			reply_desc->Words = ULLONG_MAX;
 	}
+	return 0;
+}
 
-	max_cmd = instance->max_fw_cmds;
-	for (i = 0; i < max_cmd; i++) {
-		fusion->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd_fusion),
-					      GFP_KERNEL);
-		if (!fusion->cmd_list[i]) {
-			dev_err(&instance->pdev->dev, "Could not alloc cmd list fusion\n");
+static void
+megasas_free_rdpq_fusion(struct megasas_instance *instance) {
 
-			for (j = 0; j < i; j++)
-				kfree(fusion->cmd_list[j]);
+	int i;
+	struct fusion_context *fusion;
 
-			kfree(fusion->cmd_list);
-			fusion->cmd_list = NULL;
-			goto fail_cmd_list;
-		}
+	fusion = instance->ctrl_context;
+
+	for (i = 0; i < MAX_MSIX_QUEUES_FUSION; i++) {
+		if (fusion->reply_frames_desc[i])
+			pci_pool_free(fusion->reply_frames_desc_pool,
+				fusion->reply_frames_desc[i],
+				fusion->reply_frames_desc_phys[i]);
 	}
 
-	/* The first 256 bytes (SMID 0) is not used. Don't add to cmd list */
-	io_req_base = fusion->io_request_frames +
-		MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
-	io_req_base_phys = fusion->io_request_frames_phys +
-		MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
+	if (fusion->reply_frames_desc_pool)
+		pci_pool_destroy(fusion->reply_frames_desc_pool);
+
+	if (fusion->rdpq_virt)
+		pci_free_consistent(instance->pdev,
+			sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION,
+			fusion->rdpq_virt, fusion->rdpq_phys);
+}
+
+static void
+megasas_free_reply_fusion(struct megasas_instance *instance) {
+
+	struct fusion_context *fusion;
+
+	fusion = instance->ctrl_context;
+
+	if (fusion->reply_frames_desc[0])
+		pci_pool_free(fusion->reply_frames_desc_pool,
+			fusion->reply_frames_desc[0],
+			fusion->reply_frames_desc_phys[0]);
+
+	if (fusion->reply_frames_desc_pool)
+		pci_pool_destroy(fusion->reply_frames_desc_pool);
+
+}
+
+
+/**
+ * megasas_alloc_cmds_fusion -	Allocates the command packets
+ * @instance:		Adapter soft state
+ *
+ *
+ * Each frame has a 32-bit field called context. This context is used to get
+ * back the megasas_cmd_fusion from the frame when a frame gets completed
+ * In this driver, the 32 bit values are the indices into an array cmd_list.
+ * This array is used only to look up the megasas_cmd_fusion given the context.
+ * The free commands themselves are maintained in a linked list called cmd_pool.
+ *
+ * cmds are formed in the io_request and sg_frame members of the
+ * megasas_cmd_fusion. The context field is used to get a request descriptor
+ * and is used as SMID of the cmd.
+ * SMID value range is from 1 to max_fw_cmds.
+ */
+int
+megasas_alloc_cmds_fusion(struct megasas_instance *instance)
+{
+	int i;
+	struct fusion_context *fusion;
+	struct megasas_cmd_fusion *cmd;
+	u32 offset;
+	dma_addr_t io_req_base_phys;
+	u8 *io_req_base;
+
+
+	fusion = instance->ctrl_context;
+
+	if (megasas_alloc_cmdlist_fusion(instance))
+		return -ENOMEM;
+
+	if (megasas_alloc_request_fusion(instance))
+		goto fail_exit;
+
+	if (instance->is_rdpq) {
+		if (megasas_alloc_rdpq_fusion(instance))
+			goto fail_exit;
+	} else
+		if (megasas_alloc_reply_fusion(instance))
+			goto fail_exit;
+
+
+	/* The first 256 bytes (SMID 0) is not used. Don't add to the cmd list */
+	io_req_base = fusion->io_request_frames + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
+	io_req_base_phys = fusion->io_request_frames_phys + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
 
 	/*
 	 * Add all the commands to command pool (fusion->cmd_pool)
 	 */
 
 	/* SMID 0 is reserved. Set SMID/index from 1 */
-	for (i = 0; i < max_cmd; i++) {
+	for (i = 0; i < instance->max_fw_cmds; i++) {
 		cmd = fusion->cmd_list[i];
 		offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i;
 		memset(cmd, 0, sizeof(struct megasas_cmd_fusion));
@@ -518,35 +592,13 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance)
 		cmd->io_request_phys_addr = io_req_base_phys + offset;
 	}
 
-	/*
-	 * Create a frame pool and assign one frame to each cmd
-	 */
-	if (megasas_create_frame_pool_fusion(instance)) {
-		dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error creating frame DMA pool\n");
-		megasas_free_cmds_fusion(instance);
-		goto fail_req_desc;
-	}
+	if (megasas_create_sg_sense_fusion(instance))
+		goto fail_exit;
 
 	return 0;
 
-fail_cmd_list:
-	pci_pool_free(fusion->io_request_frames_pool, fusion->io_request_frames,
-		      fusion->io_request_frames_phys);
-	pci_pool_destroy(fusion->io_request_frames_pool);
-fail_io_frames:
-	dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
-			  fusion->reply_frames_desc,
-			  fusion->reply_frames_desc_phys);
-	pci_pool_free(fusion->reply_frames_desc_pool,
-		      fusion->reply_frames_desc,
-		      fusion->reply_frames_desc_phys);
-	pci_pool_destroy(fusion->reply_frames_desc_pool);
-
-fail_reply_desc:
-	dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
-			  fusion->req_frames_desc,
-			  fusion->req_frames_desc_phys);
-fail_req_desc:
+fail_exit:
+	megasas_free_cmds_fusion(instance);
 	return -ENOMEM;
 }
 
@@ -594,16 +646,17 @@ int
 megasas_ioc_init_fusion(struct megasas_instance *instance)
 {
 	struct megasas_init_frame *init_frame;
-	struct MPI2_IOC_INIT_REQUEST *IOCInitMessage;
+	struct MPI2_IOC_INIT_REQUEST *IOCInitMessage = NULL;
 	dma_addr_t	ioc_init_handle;
 	struct megasas_cmd *cmd;
-	u8 ret;
+	u8 ret, cur_rdpq_mode;
 	struct fusion_context *fusion;
 	union MEGASAS_REQUEST_DESCRIPTOR_UNION req_desc;
 	int i;
 	struct megasas_header *frame_hdr;
 	const char *sys_info;
 	MFI_CAPABILITIES *drv_ops;
+	u32 scratch_pad_2;
 
 	fusion = instance->ctrl_context;
 
@@ -615,6 +668,18 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
 		goto fail_get_cmd;
 	}
 
+	scratch_pad_2 = readl
+		(&instance->reg_set->outbound_scratch_pad_2);
+
+	cur_rdpq_mode = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ? 1 : 0;
+
+	if (instance->is_rdpq && !cur_rdpq_mode) {
+		dev_err(&instance->pdev->dev, "Firmware downgrade *NOT SUPPORTED*"
+			" from RDPQ mode to non RDPQ mode\n");
+		ret = 1;
+		goto fail_fw_init;
+	}
+
 	IOCInitMessage =
 	  dma_alloc_coherent(&instance->pdev->dev,
 			     sizeof(struct MPI2_IOC_INIT_REQUEST),
@@ -636,7 +701,11 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
 	IOCInitMessage->SystemRequestFrameSize = cpu_to_le16(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4);
 
 	IOCInitMessage->ReplyDescriptorPostQueueDepth = cpu_to_le16(fusion->reply_q_depth);
-	IOCInitMessage->ReplyDescriptorPostQueueAddress	= cpu_to_le64(fusion->reply_frames_desc_phys);
+	IOCInitMessage->ReplyDescriptorPostQueueAddress = instance->is_rdpq ?
+			cpu_to_le64(fusion->rdpq_phys) :
+			cpu_to_le64(fusion->reply_frames_desc_phys[0]);
+	IOCInitMessage->MsgFlags = instance->is_rdpq ?
+			MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE : 0;
 	IOCInitMessage->SystemRequestFrameBaseAddress = cpu_to_le64(fusion->io_request_frames_phys);
 	IOCInitMessage->HostMSIxVectors = instance->msix_vectors;
 	init_frame = (struct megasas_init_frame *)cmd->frame;
@@ -1087,7 +1156,10 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
 	 */
 	instance->max_fw_cmds =
 		instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
-	instance->max_fw_cmds = min(instance->max_fw_cmds, (u16)1008);
+	dev_info(&instance->pdev->dev,
+		"firmware support max fw cmd\t: (%d)\n", instance->max_fw_cmds);
+	if (!instance->is_rdpq)
+		instance->max_fw_cmds = min_t(u16, instance->max_fw_cmds, 1024);
 
 	/*
 	 * Reduce the max supported cmds by 1. This is to ensure that the
@@ -2110,10 +2182,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
 	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
 		return IRQ_HANDLED;
 
-	desc = fusion->reply_frames_desc;
-	desc += ((MSIxIndex * fusion->reply_alloc_sz)/
-		 sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)) +
-		fusion->last_reply_idx[MSIxIndex];
+	desc = fusion->reply_frames_desc[MSIxIndex] +
+				fusion->last_reply_idx[MSIxIndex];
 
 	reply_desc = (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc;
 
@@ -2208,9 +2278,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
 
 		/* Get the next reply descriptor */
 		if (!fusion->last_reply_idx[MSIxIndex])
-			desc = fusion->reply_frames_desc +
-				((MSIxIndex * fusion->reply_alloc_sz)/
-				 sizeof(union MPI2_REPLY_DESCRIPTORS_UNION));
+			desc = fusion->reply_frames_desc[MSIxIndex];
 		else
 			desc++;
 
@@ -2688,17 +2756,18 @@ out:
 
 void  megasas_reset_reply_desc(struct megasas_instance *instance)
 {
-	int i, count;
+	int i, j, count;
 	struct fusion_context *fusion;
 	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
 
 	fusion = instance->ctrl_context;
 	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
-	for (i = 0 ; i < count ; i++)
+	for (i = 0 ; i < count ; i++) {
 		fusion->last_reply_idx[i] = 0;
-	reply_desc = fusion->reply_frames_desc;
-	for (i = 0 ; i < fusion->reply_q_depth * count; i++, reply_desc++)
-		reply_desc->Words = cpu_to_le64(ULLONG_MAX);
+		reply_desc = fusion->reply_frames_desc[i];
+		for (j = 0 ; j < fusion->reply_q_depth; j++, reply_desc++)
+			reply_desc->Words = cpu_to_le64(ULLONG_MAX);
+	}
 }
 
 /*
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
index db0978d..80eaee2 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
@@ -928,6 +928,12 @@ struct MR_PD_CFG_SEQ_NUM_SYNC {
 	struct MR_PD_CFG_SEQ seq[1];
 } __packed;
 
+struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY {
+	u64 RDPQBaseAddress;
+	u32 Reserved1;
+	u32 Reserved2;
+};
+
 struct fusion_context {
 	struct megasas_cmd_fusion **cmd_list;
 	dma_addr_t req_frames_desc_phys;
@@ -940,8 +946,8 @@ struct fusion_context {
 	struct dma_pool *sg_dma_pool;
 	struct dma_pool *sense_dma_pool;
 
-	dma_addr_t reply_frames_desc_phys;
-	union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc;
+	dma_addr_t reply_frames_desc_phys[MAX_MSIX_QUEUES_FUSION];
+	union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc[MAX_MSIX_QUEUES_FUSION];
 	struct dma_pool *reply_frames_desc_pool;
 
 	u16 last_reply_idx[MAX_MSIX_QUEUES_FUSION];
@@ -951,6 +957,8 @@ struct fusion_context {
 	u32 reply_alloc_sz;
 	u32 io_frames_alloc_sz;
 
+	struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY *rdpq_virt;
+	dma_addr_t rdpq_phys;
 	u16	max_sge_in_main_msg;
 	u16	max_sge_in_chain;
 
-- 
1.7.1


^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 08/15] megaraid_sas: Code optimization build_and_issue_cmd return-type
  2015-12-18 13:26 [PATCH 00/15] megaraid_sas: Updates for scsi-next Sumit Saxena
                   ` (6 preceding siblings ...)
  2015-12-18 13:27 ` [PATCH 07/15] megaraid_sas: Reply Descriptor Post Queue(RDPQ) support Sumit Saxena
@ 2015-12-18 13:27 ` Sumit Saxena
  2016-01-14 18:05   ` Tomas Henzl
  2015-12-18 13:27 ` [PATCH 09/15] megaraid_sas: Dual Queue depth support Sumit Saxena
                   ` (6 subsequent siblings)
  14 siblings, 1 reply; 50+ messages in thread
From: Sumit Saxena @ 2015-12-18 13:27 UTC (permalink / raw)
  To: jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai, sumit.saxena

build_and_issue_cmd should return SCSI_MLQUEUE_HOST_BUSY for few error case instead of returning 1.

Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
---
 drivers/scsi/megaraid/megaraid_sas_base.c   |    9 ++-------
 drivers/scsi/megaraid/megaraid_sas_fusion.c |    4 ++--
 2 files changed, 4 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index a3b63fa..3454c5e 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -1636,7 +1636,7 @@ megasas_build_and_issue_cmd(struct megasas_instance *instance,
 	return 0;
 out_return_cmd:
 	megasas_return_cmd(instance, cmd);
-	return 1;
+	return SCSI_MLQUEUE_HOST_BUSY;
 }
 
 
@@ -1728,12 +1728,7 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
 		break;
 	}
 
-	if (instance->instancet->build_and_issue_cmd(instance, scmd)) {
-		dev_err(&instance->pdev->dev, "Err returned from build_and_issue_cmd\n");
-		return SCSI_MLQUEUE_HOST_BUSY;
-	}
-
-	return 0;
+	return instance->instancet->build_and_issue_cmd(instance, scmd);
 
  out_done:
 	scmd->scsi_done(scmd);
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index aca0cd3..9ad779d 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -2123,7 +2123,7 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
 
 	req_desc = megasas_get_request_descriptor(instance, index-1);
 	if (!req_desc)
-		return 1;
+		return SCSI_MLQUEUE_HOST_BUSY;
 
 	req_desc->Words = 0;
 	cmd->request_desc = req_desc;
@@ -2132,7 +2132,7 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
 		megasas_return_cmd_fusion(instance, cmd);
 		dev_err(&instance->pdev->dev, "Error building command\n");
 		cmd->request_desc = NULL;
-		return 1;
+		return SCSI_MLQUEUE_HOST_BUSY;
 	}
 
 	req_desc = cmd->request_desc;
-- 
1.7.1


^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 09/15] megaraid_sas: Dual Queue depth support
  2015-12-18 13:26 [PATCH 00/15] megaraid_sas: Updates for scsi-next Sumit Saxena
                   ` (7 preceding siblings ...)
  2015-12-18 13:27 ` [PATCH 08/15] megaraid_sas: Code optimization build_and_issue_cmd return-type Sumit Saxena
@ 2015-12-18 13:27 ` Sumit Saxena
  2016-01-19 13:34   ` Tomas Henzl
  2015-12-18 13:27 ` [PATCH 10/15] megaraid_sas: IO throttling support Sumit Saxena
                   ` (5 subsequent siblings)
  14 siblings, 1 reply; 50+ messages in thread
From: Sumit Saxena @ 2015-12-18 13:27 UTC (permalink / raw)
  To: jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai, sumit.saxena

This patch will add support for Dual Queue depth reported by firmware.

Below are key points-

1. For iMR controllers, firmware will report two queue depths- 1. Controller wide Queue depth 2. LDIO Queue depth(240).
Ofcourse, Controller wide Queue depth will be greater among two. Using this new method, iMR can provide larger Queue depth(QD)
for JBOD and limited QD for Virtual Disk(VD). This feature gives benefit for iMR product which will be used for deployment
with large number of JBOD and limited number of VD on setup. 
2. megaraid_sas driver will throttle Read write LDIOs based when RW LDIOs reaches "LDIO Queue Depth".
3. This feature of dual queue depth can enabled/disabled via module parameter. Default behavior is: Dual Queue depth is enabled.
4. Added sysfs parameter "ldio_outstanding" for user to read LDIO outstanding at run time.


Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
---
 drivers/scsi/megaraid/megaraid_sas.h        |    9 +++
 drivers/scsi/megaraid/megaraid_sas_base.c   |   20 ++++++-
 drivers/scsi/megaraid/megaraid_sas_fusion.c |   89 ++++++++++++++++++++++++---
 3 files changed, 108 insertions(+), 10 deletions(-)

diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index c539516..4595ef4 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -1353,6 +1353,12 @@ enum DCMD_TIMEOUT_ACTION {
 	KILL_ADAPTER = 1,
 	IGNORE_TIMEOUT = 2,
 };
+
+enum FW_BOOT_CONTEXT {
+	PROBE_CONTEXT = 0,
+	OCR_CONTEXT = 1,
+};
+
 /* Frame Type */
 #define IO_FRAME				0
 #define PTHRU_FRAME				1
@@ -2038,6 +2044,8 @@ struct megasas_instance {
 	u16 max_fw_cmds;
 	u16 max_mfi_cmds;
 	u16 max_scsi_cmds;
+	u16 ldio_threshold;
+	u16 cur_can_queue;
 	u32 max_sectors_per_req;
 	struct megasas_aen_event *ev;
 
@@ -2068,6 +2076,7 @@ struct megasas_instance {
 	u32 fw_support_ieee;
 
 	atomic_t fw_outstanding;
+	atomic_t ldio_outstanding;
 	atomic_t fw_reset_no_pci_access;
 
 	struct megasas_instance_template *instancet;
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index 3454c5e..edc26fb 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -96,6 +96,10 @@ int rdpq_enable = 1;
 module_param(rdpq_enable, int, S_IRUGO);
 MODULE_PARM_DESC(rdpq_enable, " Allocate reply queue in chunks for large queue depth enable/disbale Default: disable(0)");
 
+unsigned int dual_qdepth_disable;
+module_param(dual_qdepth_disable, int, S_IRUGO);
+MODULE_PARM_DESC(dual_qdepth_disable, "Disable dual queue depth feature. Default: 0");
+
 MODULE_LICENSE("GPL");
 MODULE_VERSION(MEGASAS_VERSION);
 MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com");
@@ -1977,7 +1981,7 @@ megasas_check_and_restore_queue_depth(struct megasas_instance *instance)
 		spin_lock_irqsave(instance->host->host_lock, flags);
 		instance->flag &= ~MEGASAS_FW_BUSY;
 
-		instance->host->can_queue = instance->max_scsi_cmds;
+		instance->host->can_queue = instance->cur_can_queue;
 		spin_unlock_irqrestore(instance->host->host_lock, flags);
 	}
 }
@@ -2942,6 +2946,16 @@ megasas_page_size_show(struct device *cdev,
 	return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long)PAGE_SIZE - 1);
 }
 
+static ssize_t
+megasas_ldio_outstanding_show(struct device *cdev, struct device_attribute *attr,
+	char *buf)
+{
+	struct Scsi_Host *shost = class_to_shost(cdev);
+	struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&instance->ldio_outstanding));
+}
+
 static DEVICE_ATTR(fw_crash_buffer, S_IRUGO | S_IWUSR,
 	megasas_fw_crash_buffer_show, megasas_fw_crash_buffer_store);
 static DEVICE_ATTR(fw_crash_buffer_size, S_IRUGO,
@@ -2950,12 +2964,15 @@ static DEVICE_ATTR(fw_crash_state, S_IRUGO | S_IWUSR,
 	megasas_fw_crash_state_show, megasas_fw_crash_state_store);
 static DEVICE_ATTR(page_size, S_IRUGO,
 	megasas_page_size_show, NULL);
+static DEVICE_ATTR(ldio_outstanding, S_IRUGO,
+	megasas_ldio_outstanding_show, NULL);
 
 struct device_attribute *megaraid_host_attrs[] = {
 	&dev_attr_fw_crash_buffer_size,
 	&dev_attr_fw_crash_buffer,
 	&dev_attr_fw_crash_state,
 	&dev_attr_page_size,
+	&dev_attr_ldio_outstanding,
 	NULL,
 };
 
@@ -4750,6 +4767,7 @@ megasas_init_adapter_mfi(struct megasas_instance *instance)
 		sema_init(&instance->ioctl_sem, (MEGASAS_MFI_IOCTL_CMDS));
 	}
 
+	instance->cur_can_queue = instance->max_scsi_cmds;
 	/*
 	 * Create a pool of commands
 	 */
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index 9ad779d..7cc7806 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -92,6 +92,7 @@ void megasas_start_timer(struct megasas_instance *instance,
 			 void *fn, unsigned long interval);
 extern struct megasas_mgmt_info megasas_mgmt_info;
 extern int resetwaittime;
+extern unsigned int dual_qdepth_disable;
 static void megasas_free_rdpq_fusion(struct megasas_instance *instance);
 static void megasas_free_reply_fusion(struct megasas_instance *instance);
 
@@ -208,6 +209,67 @@ megasas_fire_cmd_fusion(struct megasas_instance *instance,
 }
 
 /**
+ * megasas_fusion_update_can_queue -	Do all Adapter Queue depth related calculations here
+ * @instance:							Adapter soft state
+ * fw_boot_context:						Whether this function called during probe or after OCR
+ *
+ * This function is only for fusion controllers.
+ * Update host can queue, if firmware downgrade max supported firmware commands.
+ * Firmware upgrade case will be skiped because underlying firmware has
+ * more resource than exposed to the OS.
+ *
+ */
+static void
+megasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_context)
+{
+	u16 cur_max_fw_cmds = 0;
+	u16 ldio_threshold = 0;
+	struct megasas_register_set __iomem *reg_set;
+
+	reg_set = instance->reg_set;
+
+	cur_max_fw_cmds = readl(&instance->reg_set->outbound_scratch_pad_3) & 0x00FFFF;
+
+	if (dual_qdepth_disable || !cur_max_fw_cmds)
+		cur_max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
+	else
+		ldio_threshold =
+			(instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF) - MEGASAS_FUSION_IOCTL_CMDS;
+
+	dev_info(&instance->pdev->dev,
+			"Current firmware maximum commands: %d\t LDIO thershold: %d\n",
+			cur_max_fw_cmds, ldio_threshold);
+
+	if (fw_boot_context == OCR_CONTEXT) {
+		cur_max_fw_cmds = cur_max_fw_cmds - 1;
+		if (cur_max_fw_cmds <= instance->max_fw_cmds) {
+			instance->cur_can_queue =
+				cur_max_fw_cmds - (MEGASAS_FUSION_INTERNAL_CMDS +
+						MEGASAS_FUSION_IOCTL_CMDS);
+			instance->host->can_queue = instance->cur_can_queue;
+			instance->ldio_threshold = ldio_threshold;
+		}
+	} else {
+		instance->max_fw_cmds = cur_max_fw_cmds;
+		instance->ldio_threshold = ldio_threshold;
+
+		if (!instance->is_rdpq)
+			instance->max_fw_cmds = min_t(u16, instance->max_fw_cmds, 1024);
+
+		/*
+		* Reduce the max supported cmds by 1. This is to ensure that the
+		* reply_q_sz (1 more than the max cmd that driver may send)
+		* does not exceed max cmds that the FW can support
+		*/
+		instance->max_fw_cmds = instance->max_fw_cmds-1;
+
+		instance->max_scsi_cmds = instance->max_fw_cmds -
+				(MEGASAS_FUSION_INTERNAL_CMDS +
+				MEGASAS_FUSION_IOCTL_CMDS);
+		instance->cur_can_queue = instance->max_scsi_cmds;
+	}
+}
+/**
  * megasas_free_cmds_fusion -	Free all the cmds in the free cmd pool
  * @instance:		Adapter soft state
  */
@@ -736,6 +798,8 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
 		drv_ops->mfi_capabilities.support_ext_io_size = 1;
 
 	drv_ops->mfi_capabilities.support_fp_rlbypass = 1;
+	if (!dual_qdepth_disable)
+		drv_ops->mfi_capabilities.support_ext_queue_depth = 1;
 
 	/* Convert capability to LE32 */
 	cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities);
@@ -1151,15 +1215,7 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
 
 	reg_set = instance->reg_set;
 
-	/*
-	 * Get various operational parameters from status register
-	 */
-	instance->max_fw_cmds =
-		instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
-	dev_info(&instance->pdev->dev,
-		"firmware support max fw cmd\t: (%d)\n", instance->max_fw_cmds);
-	if (!instance->is_rdpq)
-		instance->max_fw_cmds = min_t(u16, instance->max_fw_cmds, 1024);
+	megasas_fusion_update_can_queue(instance, PROBE_CONTEXT);
 
 	/*
 	 * Reduce the max supported cmds by 1. This is to ensure that the
@@ -2117,6 +2173,15 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
 
 	fusion = instance->ctrl_context;
 
+	if (megasas_cmd_type(scmd) == READ_WRITE_LDIO) {
+		if (instance->ldio_threshold &&
+			(atomic_read(&instance->ldio_outstanding) >=
+			instance->ldio_threshold))
+			return SCSI_MLQUEUE_DEVICE_BUSY;
+		else
+			atomic_inc(&instance->ldio_outstanding);
+	}
+
 	cmd = megasas_get_cmd_fusion(instance, scmd->request->tag);
 
 	index = cmd->index;
@@ -2247,6 +2312,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
 			map_cmd_status(cmd_fusion, status, extStatus);
 			scsi_io_req->RaidContext.status = 0;
 			scsi_io_req->RaidContext.exStatus = 0;
+			if (megasas_cmd_type(scmd_local) == READ_WRITE_LDIO)
+				atomic_dec(&instance->ldio_outstanding);
 			megasas_return_cmd_fusion(instance, cmd_fusion);
 			scsi_dma_unmap(scmd_local);
 			scmd_local->scsi_done(scmd_local);
@@ -3370,6 +3437,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
 				scmd_local->result =
 					megasas_check_mpio_paths(instance,
 							scmd_local);
+				if (megasas_cmd_type(scmd_local) == READ_WRITE_LDIO)
+					atomic_dec(&instance->ldio_outstanding);
 				megasas_return_cmd_fusion(instance, cmd_fusion);
 				scsi_dma_unmap(scmd_local);
 				scmd_local->scsi_done(scmd_local);
@@ -3462,6 +3531,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
 			}
 
 			megasas_reset_reply_desc(instance);
+			megasas_fusion_update_can_queue(instance, OCR_CONTEXT);
+
 			if (megasas_ioc_init_fusion(instance)) {
 				dev_warn(&instance->pdev->dev,
 				       "megasas_ioc_init_fusion() failed!"
-- 
1.7.1


^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 10/15] megaraid_sas: IO throttling support
  2015-12-18 13:26 [PATCH 00/15] megaraid_sas: Updates for scsi-next Sumit Saxena
                   ` (8 preceding siblings ...)
  2015-12-18 13:27 ` [PATCH 09/15] megaraid_sas: Dual Queue depth support Sumit Saxena
@ 2015-12-18 13:27 ` Sumit Saxena
  2016-01-19 13:38   ` Tomas Henzl
  2015-12-18 13:27 ` [PATCH 11/15] megaraid_sas: Make adprecovery variable atomic Sumit Saxena
                   ` (4 subsequent siblings)
  14 siblings, 1 reply; 50+ messages in thread
From: Sumit Saxena @ 2015-12-18 13:27 UTC (permalink / raw)
  To: jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai, sumit.saxena

This patch will add capability in driver to tell firmware that it can throttle IOs in case Controller's Queue depth is downgraded post OFU
(Online firmware upgrade). This feature will ensure firmware can be downgraded from higher queue depth to lower queue depth without needing system reboot.
Added throttling code in IO path of driver, in case OS tries to send more IOs than post OFU firmware's queue depth.

Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
---
 drivers/scsi/megaraid/megaraid_sas.h        |    6 ++++--
 drivers/scsi/megaraid/megaraid_sas_fusion.c |    7 +++++++
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 4595ef4..9d2b3da 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -1537,7 +1537,8 @@ union megasas_sgl_frame {
 typedef union _MFI_CAPABILITIES {
 	struct {
 #if   defined(__BIG_ENDIAN_BITFIELD)
-		u32     reserved:21;
+		u32     reserved:20;
+		u32     support_qd_throttling:1;
 		u32     support_fp_rlbypass:1;
 		u32     support_vfid_in_ioframe:1;
 		u32     support_ext_io_size:1;
@@ -1561,7 +1562,8 @@ typedef union _MFI_CAPABILITIES {
 		u32     support_ext_io_size:1;
 		u32     support_vfid_in_ioframe:1;
 		u32     support_fp_rlbypass:1;
-		u32     reserved:21;
+		u32     support_qd_throttling:1;
+		u32     reserved:20;
 #endif
 	} mfi_capabilities;
 	__le32		reg;
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index 7cc7806..1248c7a 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -801,6 +801,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
 	if (!dual_qdepth_disable)
 		drv_ops->mfi_capabilities.support_ext_queue_depth = 1;
 
+	drv_ops->mfi_capabilities.support_qd_throttling = 1;
 	/* Convert capability to LE32 */
 	cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities);
 
@@ -2182,6 +2183,12 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
 			atomic_inc(&instance->ldio_outstanding);
 	}
 
+	if (atomic_read(&instance->fw_outstanding) >=
+			instance->host->can_queue) {
+		dev_err(&instance->pdev->dev, "Throttle IOs beyond Controller queue depth\n");
+		return SCSI_MLQUEUE_HOST_BUSY;
+	}
+
 	cmd = megasas_get_cmd_fusion(instance, scmd->request->tag);
 
 	index = cmd->index;
-- 
1.7.1


^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 11/15] megaraid_sas: Make adprecovery variable atomic
  2015-12-18 13:26 [PATCH 00/15] megaraid_sas: Updates for scsi-next Sumit Saxena
                   ` (9 preceding siblings ...)
  2015-12-18 13:27 ` [PATCH 10/15] megaraid_sas: IO throttling support Sumit Saxena
@ 2015-12-18 13:27 ` Sumit Saxena
  2016-01-19 13:52   ` Tomas Henzl
  2015-12-18 13:27 ` [PATCH 12/15] megaraid_sas: MFI adapter's OCR changes Sumit Saxena
                   ` (3 subsequent siblings)
  14 siblings, 1 reply; 50+ messages in thread
From: Sumit Saxena @ 2015-12-18 13:27 UTC (permalink / raw)
  To: jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai, sumit.saxena

Make instance->adprecovery variable atomic and removes hba_lock spinlock while accessing instance->adprecovery.

Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
---
 drivers/scsi/megaraid/megaraid_sas.h        |    2 +-
 drivers/scsi/megaraid/megaraid_sas_base.c   |   95 ++++++++++-----------------
 drivers/scsi/megaraid/megaraid_sas_fusion.c |   27 ++++----
 3 files changed, 50 insertions(+), 74 deletions(-)

diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 9d2b3da..ac19d53 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -2101,7 +2101,7 @@ struct megasas_instance {
 	u16 drv_supported_vd_count;
 	u16 drv_supported_pd_count;
 
-	u8 adprecovery;
+	atomic_t adprecovery;
 	unsigned long last_time;
 	u32 mfiStatus;
 	u32 last_seq_num;
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index edc26fb..5eaf6fd 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -483,7 +483,7 @@ static int
 megasas_check_reset_xscale(struct megasas_instance *instance,
 		struct megasas_register_set __iomem *regs)
 {
-	if ((instance->adprecovery != MEGASAS_HBA_OPERATIONAL) &&
+	if ((atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) &&
 	    (le32_to_cpu(*instance->consumer) ==
 		MEGASAS_ADPRESET_INPROG_SIGN))
 		return 1;
@@ -619,7 +619,7 @@ static int
 megasas_check_reset_ppc(struct megasas_instance *instance,
 			struct megasas_register_set __iomem *regs)
 {
-	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL)
+	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
 		return 1;
 
 	return 0;
@@ -756,7 +756,7 @@ static int
 megasas_check_reset_skinny(struct megasas_instance *instance,
 				struct megasas_register_set __iomem *regs)
 {
-	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL)
+	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
 		return 1;
 
 	return 0;
@@ -950,9 +950,8 @@ static int
 megasas_check_reset_gen2(struct megasas_instance *instance,
 		struct megasas_register_set __iomem *regs)
 {
-	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
 		return 1;
-	}
 
 	return 0;
 }
@@ -998,7 +997,7 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
 	frame_hdr->cmd_status = MFI_STAT_INVALID_STATUS;
 	frame_hdr->flags |= cpu_to_le16(MFI_FRAME_DONT_POST_IN_REPLY_QUEUE);
 
-	if ((instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) ||
+	if ((atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) ||
 		(instance->instancet->issue_dcmd(instance, cmd))) {
 		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
 			__func__, __LINE__);
@@ -1026,7 +1025,7 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
 	int ret = 0;
 	cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
 
-	if ((instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) ||
+	if ((atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) ||
 		(instance->instancet->issue_dcmd(instance, cmd))) {
 		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
 			__func__, __LINE__);
@@ -1090,7 +1089,7 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
 	cmd->sync_cmd = 1;
 	cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
 
-	if ((instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) ||
+	if ((atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) ||
 		(instance->instancet->issue_dcmd(instance, cmd))) {
 		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
 			__func__, __LINE__);
@@ -1653,7 +1652,6 @@ static int
 megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
 {
 	struct megasas_instance *instance;
-	unsigned long flags;
 	struct MR_PRIV_DEVICE *mr_device_priv_data;
 
 	instance = (struct megasas_instance *)
@@ -1668,24 +1666,20 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
 	if (instance->issuepend_done == 0)
 		return SCSI_MLQUEUE_HOST_BUSY;
 
-	spin_lock_irqsave(&instance->hba_lock, flags);
 
 	/* Check for an mpio path and adjust behavior */
-	if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) {
+	if (atomic_read(&instance->adprecovery) == MEGASAS_ADPRESET_SM_INFAULT) {
 		if (megasas_check_mpio_paths(instance, scmd) ==
 		    (DID_RESET << 16)) {
-			spin_unlock_irqrestore(&instance->hba_lock, flags);
 			return SCSI_MLQUEUE_HOST_BUSY;
 		} else {
-			spin_unlock_irqrestore(&instance->hba_lock, flags);
 			scmd->result = DID_NO_CONNECT << 16;
 			scmd->scsi_done(scmd);
 			return 0;
 		}
 	}
 
-	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
-		spin_unlock_irqrestore(&instance->hba_lock, flags);
+	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
 		scmd->result = DID_NO_CONNECT << 16;
 		scmd->scsi_done(scmd);
 		return 0;
@@ -1693,23 +1687,17 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
 
 	mr_device_priv_data = scmd->device->hostdata;
 	if (!mr_device_priv_data) {
-		spin_unlock_irqrestore(&instance->hba_lock, flags);
 		scmd->result = DID_NO_CONNECT << 16;
 		scmd->scsi_done(scmd);
 		return 0;
 	}
 
-	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
-		spin_unlock_irqrestore(&instance->hba_lock, flags);
+	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
 		return SCSI_MLQUEUE_HOST_BUSY;
-	}
 
-	if (mr_device_priv_data->tm_busy) {
-		spin_unlock_irqrestore(&instance->hba_lock, flags);
+	if (mr_device_priv_data->tm_busy)
 		return SCSI_MLQUEUE_DEVICE_BUSY;
-	}
 
-	spin_unlock_irqrestore(&instance->hba_lock, flags);
 
 	scmd->result = 0;
 
@@ -1943,7 +1931,7 @@ static void megasas_complete_outstanding_ioctls(struct megasas_instance *instanc
 void megaraid_sas_kill_hba(struct megasas_instance *instance)
 {
 	/* Set critical error to block I/O & ioctls in case caller didn't */
-	instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
+	atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
 	/* Wait 1 second to ensure IO or ioctls in build have posted */
 	msleep(1000);
 	if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
@@ -2003,7 +1991,7 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
 	unsigned long flags;
 
 	/* If we have already declared adapter dead, donot complete cmds */
-	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
 		return;
 
 	spin_lock_irqsave(&instance->completion_lock, flags);
@@ -2072,7 +2060,7 @@ void megasas_do_ocr(struct megasas_instance *instance)
 		*instance->consumer = cpu_to_le32(MEGASAS_ADPRESET_INPROG_SIGN);
 	}
 	instance->instancet->disable_intr(instance);
-	instance->adprecovery   = MEGASAS_ADPRESET_SM_INFAULT;
+	atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
 	instance->issuepend_done = 0;
 
 	atomic_set(&instance->fw_outstanding, 0);
@@ -2471,18 +2459,14 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
 	int i;
 	u32 reset_index;
 	u32 wait_time = MEGASAS_RESET_WAIT_TIME;
-	u8 adprecovery;
 	unsigned long flags;
 	struct list_head clist_local;
 	struct megasas_cmd *reset_cmd;
 	u32 fw_state;
 	u8 kill_adapter_flag;
 
-	spin_lock_irqsave(&instance->hba_lock, flags);
-	adprecovery = instance->adprecovery;
-	spin_unlock_irqrestore(&instance->hba_lock, flags);
 
-	if (adprecovery != MEGASAS_HBA_OPERATIONAL) {
+	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
 
 		INIT_LIST_HEAD(&clist_local);
 		spin_lock_irqsave(&instance->hba_lock, flags);
@@ -2493,18 +2477,13 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
 		dev_notice(&instance->pdev->dev, "HBA reset wait ...\n");
 		for (i = 0; i < wait_time; i++) {
 			msleep(1000);
-			spin_lock_irqsave(&instance->hba_lock, flags);
-			adprecovery = instance->adprecovery;
-			spin_unlock_irqrestore(&instance->hba_lock, flags);
-			if (adprecovery == MEGASAS_HBA_OPERATIONAL)
+			if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL)
 				break;
 		}
 
-		if (adprecovery != MEGASAS_HBA_OPERATIONAL) {
+		if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
 			dev_notice(&instance->pdev->dev, "reset: Stopping HBA.\n");
-			spin_lock_irqsave(&instance->hba_lock, flags);
-			instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
-			spin_unlock_irqrestore(&instance->hba_lock, flags);
+			atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
 			return FAILED;
 		}
 
@@ -2613,9 +2592,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
 				&instance->reg_set->inbound_doorbell);
 		}
 		megasas_dump_pending_frames(instance);
-		spin_lock_irqsave(&instance->hba_lock, flags);
-		instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
-		spin_unlock_irqrestore(&instance->hba_lock, flags);
+		atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
 		return FAILED;
 	}
 
@@ -2642,7 +2619,7 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd)
 	scmd_printk(KERN_NOTICE, scmd, "megasas: RESET cmd=%x retries=%x\n",
 		 scmd->cmnd[0], scmd->retries);
 
-	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
 		dev_err(&instance->pdev->dev, "cannot recover from previous reset failures\n");
 		return FAILED;
 	}
@@ -3386,13 +3363,13 @@ process_fw_state_change_wq(struct work_struct *work)
 	u32 wait;
 	unsigned long flags;
 
-	if (instance->adprecovery != MEGASAS_ADPRESET_SM_INFAULT) {
+    if (atomic_read(&instance->adprecovery) != MEGASAS_ADPRESET_SM_INFAULT) {
 		dev_notice(&instance->pdev->dev, "error, recovery st %x\n",
-				instance->adprecovery);
+				atomic_read(&instance->adprecovery));
 		return ;
 	}
 
-	if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) {
+	if (atomic_read(&instance->adprecovery) == MEGASAS_ADPRESET_SM_INFAULT) {
 		dev_notice(&instance->pdev->dev, "FW detected to be in fault"
 					"state, restarting it...\n");
 
@@ -3435,7 +3412,7 @@ process_fw_state_change_wq(struct work_struct *work)
 		megasas_issue_init_mfi(instance);
 
 		spin_lock_irqsave(&instance->hba_lock, flags);
-		instance->adprecovery	= MEGASAS_HBA_OPERATIONAL;
+		atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
 		spin_unlock_irqrestore(&instance->hba_lock, flags);
 		instance->instancet->enable_intr(instance);
 
@@ -3500,14 +3477,14 @@ megasas_deplete_reply_queue(struct megasas_instance *instance,
 
 
 			instance->instancet->disable_intr(instance);
-			instance->adprecovery	= MEGASAS_ADPRESET_SM_INFAULT;
+			atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
 			instance->issuepend_done = 0;
 
 			atomic_set(&instance->fw_outstanding, 0);
 			megasas_internal_reset_defer_cmds(instance);
 
 			dev_notice(&instance->pdev->dev, "fwState=%x, stage:%d\n",
-					fw_state, instance->adprecovery);
+					fw_state, atomic_read(&instance->adprecovery));
 
 			schedule_work(&instance->work_init);
 			return IRQ_HANDLED;
@@ -5796,7 +5773,7 @@ static int megasas_probe_one(struct pci_dev *pdev,
 	instance->flag_ieee = 0;
 	instance->ev = NULL;
 	instance->issuepend_done = 1;
-	instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+	atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
 	instance->is_imr = 0;
 
 	instance->evt_detail = pci_alloc_consistent(pdev,
@@ -5975,7 +5952,7 @@ static void megasas_flush_cache(struct megasas_instance *instance)
 	struct megasas_cmd *cmd;
 	struct megasas_dcmd_frame *dcmd;
 
-	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
 		return;
 
 	cmd = megasas_get_cmd(instance);
@@ -6018,7 +5995,7 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
 	struct megasas_cmd *cmd;
 	struct megasas_dcmd_frame *dcmd;
 
-	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
 		return;
 
 	cmd = megasas_get_cmd(instance);
@@ -6463,7 +6440,7 @@ static int megasas_set_crash_dump_params_ioctl(struct megasas_cmd *cmd)
 	for (i = 0; i < megasas_mgmt_info.max_index; i++) {
 		local_instance = megasas_mgmt_info.instance[i];
 		if (local_instance && local_instance->crash_dump_drv_support) {
-			if ((local_instance->adprecovery ==
+			if ((atomic_read(&local_instance->adprecovery) ==
 				MEGASAS_HBA_OPERATIONAL) &&
 				!megasas_set_crash_dump_params(local_instance,
 					crash_support)) {
@@ -6711,7 +6688,7 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
 		goto out_kfree_ioc;
 	}
 
-	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
 		dev_err(&instance->pdev->dev, "Controller in crit error\n");
 		error = -ENODEV;
 		goto out_kfree_ioc;
@@ -6730,7 +6707,7 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
 	for (i = 0; i < wait_time; i++) {
 
 		spin_lock_irqsave(&instance->hba_lock, flags);
-		if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
+		if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL) {
 			spin_unlock_irqrestore(&instance->hba_lock, flags);
 			break;
 		}
@@ -6745,7 +6722,7 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
 	}
 
 	spin_lock_irqsave(&instance->hba_lock, flags);
-	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
 		spin_unlock_irqrestore(&instance->hba_lock, flags);
 
 		dev_err(&instance->pdev->dev, "timed out while"
@@ -6787,7 +6764,7 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
 	if (!instance)
 		return -ENODEV;
 
-	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
 		return -ENODEV;
 	}
 
@@ -6798,7 +6775,7 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
 	for (i = 0; i < wait_time; i++) {
 
 		spin_lock_irqsave(&instance->hba_lock, flags);
-		if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
+		if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL) {
 			spin_unlock_irqrestore(&instance->hba_lock,
 						flags);
 			break;
@@ -6815,7 +6792,7 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
 	}
 
 	spin_lock_irqsave(&instance->hba_lock, flags);
-	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
 		spin_unlock_irqrestore(&instance->hba_lock, flags);
 		dev_err(&instance->pdev->dev, "timed out while waiting"
 				"for HBA to recover\n");
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index 1248c7a..96e8d80 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -2251,7 +2251,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
 
 	fusion = instance->ctrl_context;
 
-	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
 		return IRQ_HANDLED;
 
 	desc = fusion->reply_frames_desc[MSIxIndex] +
@@ -2418,7 +2418,7 @@ megasas_complete_cmd_dpc_fusion(unsigned long instance_addr)
 
 	/* If we have already declared adapter dead, donot complete cmds */
 	spin_lock_irqsave(&instance->hba_lock, flags);
-	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
 		spin_unlock_irqrestore(&instance->hba_lock, flags);
 		return;
 	}
@@ -3200,7 +3200,7 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd)
 	instance = (struct megasas_instance *)scmd->device->host->hostdata;
 	fusion = instance->ctrl_context;
 
-	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
 		dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL,"
 		"SCSI host:%d\n", instance->host->host_no);
 		ret = FAILED;
@@ -3284,7 +3284,7 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
 	instance = (struct megasas_instance *)scmd->device->host->hostdata;
 	fusion = instance->ctrl_context;
 
-	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
 		dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL,"
 		"SCSI host:%d\n", instance->host->host_no);
 		ret = FAILED;
@@ -3376,7 +3376,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
 
 	mutex_lock(&instance->reset_mutex);
 
-	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
 		dev_warn(&instance->pdev->dev, "Hardware critical error, "
 		       "returning FAILED for scsi%d.\n",
 			instance->host->host_no);
@@ -3391,7 +3391,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
 		instance->crash_dump_app_support && reason) {
 		dev_info(&instance->pdev->dev, "IO/DCMD timeout is detected, "
 			"forcibly FAULT Firmware\n");
-		instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
+		atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
 		status_reg = readl(&instance->reg_set->doorbell);
 		writel(status_reg | MFI_STATE_FORCE_OCR,
 			&instance->reg_set->doorbell);
@@ -3403,10 +3403,10 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
 			dev_dbg(&instance->pdev->dev, "waiting for [%d] "
 				"seconds for crash dump collection and OCR "
 				"to be done\n", (io_timeout_in_crash_mode * 3));
-		} while ((instance->adprecovery != MEGASAS_HBA_OPERATIONAL) &&
+		} while ((atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) &&
 			(io_timeout_in_crash_mode < 80));
 
-		if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
+		if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL) {
 			dev_info(&instance->pdev->dev, "OCR done for IO "
 				"timeout case\n");
 			retval = SUCCESS;
@@ -3423,14 +3423,14 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
 	if (instance->requestorId && !instance->skip_heartbeat_timer_del)
 		del_timer_sync(&instance->sriov_heartbeat_timer);
 	set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
-	instance->adprecovery = MEGASAS_ADPRESET_SM_POLLING;
+	atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_POLLING);
 	instance->instancet->disable_intr(instance);
 	msleep(1000);
 
 	/* First try waiting for commands to complete */
 	if (megasas_wait_for_outstanding_fusion(instance, reason,
 						&convert)) {
-		instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
+		atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
 		dev_warn(&instance->pdev->dev, "resetting fusion "
 		       "adapter scsi%d.\n", instance->host->host_no);
 		if (convert)
@@ -3513,8 +3513,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
 					       status_reg);
 					megaraid_sas_kill_hba(instance);
 					instance->skip_heartbeat_timer_del = 1;
-					instance->adprecovery =
-						MEGASAS_HW_CRITICAL_ERROR;
+					atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
 					retval = FAILED;
 					goto out;
 				}
@@ -3573,7 +3572,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
 			clear_bit(MEGASAS_FUSION_IN_RESET,
 				  &instance->reset_flags);
 			instance->instancet->enable_intr(instance);
-			instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+			atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
 
 			/* Restart SR-IOV heartbeat */
 			if (instance->requestorId) {
@@ -3618,7 +3617,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
 		}
 		clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
 		instance->instancet->enable_intr(instance);
-		instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+		atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
 	}
 out:
 	clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
-- 
1.7.1


^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 12/15] megaraid_sas: MFI adapter's OCR changes
  2015-12-18 13:26 [PATCH 00/15] megaraid_sas: Updates for scsi-next Sumit Saxena
                   ` (10 preceding siblings ...)
  2015-12-18 13:27 ` [PATCH 11/15] megaraid_sas: Make adprecovery variable atomic Sumit Saxena
@ 2015-12-18 13:27 ` Sumit Saxena
  2016-01-19 14:22   ` Tomas Henzl
  2015-12-18 13:27 ` [PATCH 13/15] megaraid_sas: Introduce module parameter for SCSI command-timeout Sumit Saxena
                   ` (2 subsequent siblings)
  14 siblings, 1 reply; 50+ messages in thread
From: Sumit Saxena @ 2015-12-18 13:27 UTC (permalink / raw)
  To: jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai, sumit.saxena

Optimized MFI adapters' OCR path, particularly megasas_wait_for_outstanding() function.

Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
---
 drivers/scsi/megaraid/megaraid_sas_base.c |  104 +++++++++++++++--------------
 1 files changed, 54 insertions(+), 50 deletions(-)

diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index 5eaf6fd..cc843d6 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -2456,15 +2456,19 @@ void megasas_sriov_heartbeat_handler(unsigned long instance_addr)
  */
 static int megasas_wait_for_outstanding(struct megasas_instance *instance)
 {
-	int i;
+	int i, sl, outstanding;
 	u32 reset_index;
 	u32 wait_time = MEGASAS_RESET_WAIT_TIME;
 	unsigned long flags;
 	struct list_head clist_local;
 	struct megasas_cmd *reset_cmd;
 	u32 fw_state;
-	u8 kill_adapter_flag;
 
+	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
+		dev_info(&instance->pdev->dev, "%s:%d HBA is killed.\n",
+		__func__, __LINE__);
+		return FAILED;
+	}
 
 	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
 
@@ -2521,7 +2525,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
 	}
 
 	for (i = 0; i < resetwaittime; i++) {
-		int outstanding = atomic_read(&instance->fw_outstanding);
+		outstanding = atomic_read(&instance->fw_outstanding);
 
 		if (!outstanding)
 			break;
@@ -2540,65 +2544,65 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
 	}
 
 	i = 0;
-	kill_adapter_flag = 0;
+	outstanding = atomic_read(&instance->fw_outstanding);
+	fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
+
+	if ((!outstanding && (fw_state == MFI_STATE_OPERATIONAL)))
+		goto no_outstanding;
+
+	if (instance->disableOnlineCtrlReset)
+		goto kill_hba_and_failed;
 	do {
-		fw_state = instance->instancet->read_fw_status_reg(
-					instance->reg_set) & MFI_STATE_MASK;
-		if ((fw_state == MFI_STATE_FAULT) &&
-			(instance->disableOnlineCtrlReset == 0)) {
-			if (i == 3) {
-				kill_adapter_flag = 2;
-				break;
-			}
+		if ((fw_state == MFI_STATE_FAULT) || atomic_read(&instance->fw_outstanding)) {
+			dev_info(&instance->pdev->dev,
+				"%s:%d waiting_for_outstanding: before issue OCR. FW state = 0x%x, oustanding 0x%x\n",
+				__func__, __LINE__, fw_state, atomic_read(&instance->fw_outstanding));
+			if (i == 3)
+				goto kill_hba_and_failed;
 			megasas_do_ocr(instance);
-			kill_adapter_flag = 1;
 
-			/* wait for 1 secs to let FW finish the pending cmds */
-			msleep(1000);
+			if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
+				dev_info(&instance->pdev->dev, "%s:%d OCR failed and HBA is killed.\n",
+				__func__, __LINE__);
+				return FAILED;
+			}
+			dev_info(&instance->pdev->dev, "%s:%d waiting_for_outstanding: after issue OCR.\n",
+				__func__, __LINE__);
+
+			for (sl = 0; sl < 10; sl++)
+				msleep(500);
+
+			outstanding = atomic_read(&instance->fw_outstanding);
+
+			fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
+			if ((!outstanding && (fw_state == MFI_STATE_OPERATIONAL)))
+				goto no_outstanding;
 		}
 		i++;
 	} while (i <= 3);
 
-	if (atomic_read(&instance->fw_outstanding) && !kill_adapter_flag) {
-		if (instance->disableOnlineCtrlReset == 0) {
-			megasas_do_ocr(instance);
+no_outstanding:
 
-			/* wait for 5 secs to let FW finish the pending cmds */
-			for (i = 0; i < wait_time; i++) {
-				int outstanding =
-					atomic_read(&instance->fw_outstanding);
-				if (!outstanding)
-					return SUCCESS;
-				msleep(1000);
-			}
-		}
-	}
+	dev_info(&instance->pdev->dev, "%s:%d no more pending commands remain after reset handling.\n",
+		__func__, __LINE__);
+	return SUCCESS;
 
-	if (atomic_read(&instance->fw_outstanding) ||
-					(kill_adapter_flag == 2)) {
-		dev_notice(&instance->pdev->dev, "pending cmds after reset\n");
-		/*
-		 * Send signal to FW to stop processing any pending cmds.
-		 * The controller will be taken offline by the OS now.
-		 */
-		if ((instance->pdev->device ==
-			PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
-			(instance->pdev->device ==
-			PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
-			writel(MFI_STOP_ADP,
-				&instance->reg_set->doorbell);
-		} else {
-			writel(MFI_STOP_ADP,
-				&instance->reg_set->inbound_doorbell);
-		}
+kill_hba_and_failed:
+
+	fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
+	if (instance->disableOnlineCtrlReset ||
+		atomic_read(&instance->fw_outstanding) ||
+		(fw_state == MFI_STATE_FAULT)) {
+		/* Reset not supported, kill adapter */
+		dev_info(&instance->pdev->dev, "%s:%d killing adapter scsi%d"
+			" disableOnlineCtrlReset %d fw_outstanding %d \n",
+			__func__, __LINE__, instance->host->host_no, instance->disableOnlineCtrlReset,
+			atomic_read(&instance->fw_outstanding));
 		megasas_dump_pending_frames(instance);
-		atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
-		return FAILED;
+		megaraid_sas_kill_hba(instance);
 	}
 
-	dev_notice(&instance->pdev->dev, "no pending cmds after reset\n");
-
-	return SUCCESS;
+	return FAILED;
 }
 
 /**
-- 
1.7.1


^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 13/15] megaraid_sas: Introduce module parameter for SCSI command-timeout
  2015-12-18 13:26 [PATCH 00/15] megaraid_sas: Updates for scsi-next Sumit Saxena
                   ` (11 preceding siblings ...)
  2015-12-18 13:27 ` [PATCH 12/15] megaraid_sas: MFI adapter's OCR changes Sumit Saxena
@ 2015-12-18 13:27 ` Sumit Saxena
  2016-01-19 14:57   ` Tomas Henzl
  2015-12-18 13:27 ` [PATCH 14/15] megaraid_sas: SPERC OCR changes Sumit Saxena
  2015-12-18 13:27 ` [PATCH 15/15] megaraid_sas: SPERC boot driver reorder Sumit Saxena
  14 siblings, 1 reply; 50+ messages in thread
From: Sumit Saxena @ 2015-12-18 13:27 UTC (permalink / raw)
  To: jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai, sumit.saxena

This patch will introduce module-parameter for SCSI command timeout value and fix setting of resetwaitime beyond a value.

Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
---
 drivers/scsi/megaraid/megaraid_sas_base.c   |   15 ++++++++++++---
 drivers/scsi/megaraid/megaraid_sas_fusion.c |    2 +-
 2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index cc843d6..316d5a0 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -83,7 +83,7 @@ module_param(throttlequeuedepth, int, S_IRUGO);
 MODULE_PARM_DESC(throttlequeuedepth,
 	"Adapter queue depth when throttled due to I/O timeout. Default: 16");
 
-int resetwaittime = MEGASAS_RESET_WAIT_TIME;
+unsigned int resetwaittime = MEGASAS_RESET_WAIT_TIME;
 module_param(resetwaittime, int, S_IRUGO);
 MODULE_PARM_DESC(resetwaittime, "Wait time in seconds after I/O timeout "
 		 "before resetting adapter. Default: 180");
@@ -100,6 +100,10 @@ unsigned int dual_qdepth_disable;
 module_param(dual_qdepth_disable, int, S_IRUGO);
 MODULE_PARM_DESC(dual_qdepth_disable, "Disable dual queue depth feature. Default: 0");
 
+unsigned int scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT;
+module_param(scmd_timeout, int, S_IRUGO);
+MODULE_PARM_DESC(scmd_timeout, "scsi command timeout (10-90s), default 90s. See megasas_reset_timer.");
+
 MODULE_LICENSE("GPL");
 MODULE_VERSION(MEGASAS_VERSION);
 MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com");
@@ -1851,7 +1855,7 @@ static int megasas_slave_configure(struct scsi_device *sdev)
 	 * The RAID firmware may require extended timeouts.
 	 */
 	blk_queue_rq_timeout(sdev->request_queue,
-		MEGASAS_DEFAULT_CMD_TIMEOUT * HZ);
+		scmd_timeout * HZ);
 
 	return 0;
 }
@@ -2651,7 +2655,7 @@ blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
 	unsigned long flags;
 
 	if (time_after(jiffies, scmd->jiffies_at_alloc +
-				(MEGASAS_DEFAULT_CMD_TIMEOUT * 2) * HZ)) {
+				(scmd_timeout * 2) * HZ)) {
 		return BLK_EH_NOT_HANDLED;
 	}
 
@@ -5260,6 +5264,11 @@ static int megasas_init_fw(struct megasas_instance *instance)
 		instance->throttlequeuedepth =
 				MEGASAS_THROTTLE_QUEUE_DEPTH;
 
+	if (resetwaittime > MEGASAS_RESET_WAIT_TIME)
+		resetwaittime = MEGASAS_RESET_WAIT_TIME;
+
+	if ((scmd_timeout < 10) || (scmd_timeout > MEGASAS_DEFAULT_CMD_TIMEOUT))
+		scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT;
 
 	/* Launch SR-IOV heartbeat timer */
 	if (instance->requestorId) {
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index 96e8d80..a973587 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -91,7 +91,7 @@ void megasas_start_timer(struct megasas_instance *instance,
 			struct timer_list *timer,
 			 void *fn, unsigned long interval);
 extern struct megasas_mgmt_info megasas_mgmt_info;
-extern int resetwaittime;
+extern unsigned int resetwaittime;
 extern unsigned int dual_qdepth_disable;
 static void megasas_free_rdpq_fusion(struct megasas_instance *instance);
 static void megasas_free_reply_fusion(struct megasas_instance *instance);
-- 
1.7.1


^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 14/15] megaraid_sas: SPERC OCR changes
  2015-12-18 13:26 [PATCH 00/15] megaraid_sas: Updates for scsi-next Sumit Saxena
                   ` (12 preceding siblings ...)
  2015-12-18 13:27 ` [PATCH 13/15] megaraid_sas: Introduce module parameter for SCSI command-timeout Sumit Saxena
@ 2015-12-18 13:27 ` Sumit Saxena
  2016-01-19 15:14   ` Tomas Henzl
  2015-12-18 13:27 ` [PATCH 15/15] megaraid_sas: SPERC boot driver reorder Sumit Saxena
  14 siblings, 1 reply; 50+ messages in thread
From: Sumit Saxena @ 2015-12-18 13:27 UTC (permalink / raw)
  To: jbottomley, hch, martin.petersen
  Cc: linux-scsi, kashyap.desai, sumit.saxena, Uday Lingala

This patch will do some fixes in OCR path of SRIOV enabled series of Avago controllers.

1)Removing late detection HB. 
2)Change in the behavior if the FW found in READY/OPERAETIONAL state.

Signed-off-by: Uday Lingala <uday.lingala@avagotech.com>
Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
---
 drivers/scsi/megaraid/megaraid_sas_fusion.c |   73 ++++++---------------------
 1 files changed, 16 insertions(+), 57 deletions(-)

diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index a973587..90217a2 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -3472,52 +3472,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
 		/* Let SR-IOV VF & PF sync up if there was a HB failure */
 		if (instance->requestorId && !reason) {
 			msleep(MEGASAS_OCR_SETTLE_TIME_VF);
-			/* Look for a late HB update after VF settle time */
-			if (abs_state == MFI_STATE_OPERATIONAL &&
-			    (instance->hb_host_mem->HB.fwCounter !=
-			     instance->hb_host_mem->HB.driverCounter)) {
-					instance->hb_host_mem->HB.driverCounter =
-						instance->hb_host_mem->HB.fwCounter;
-					dev_warn(&instance->pdev->dev, "SR-IOV:"
-					       "Late FW heartbeat update for "
-					       "scsi%d.\n",
-					       instance->host->host_no);
-			} else {
-				/* In VF mode, first poll for FW ready */
-				for (i = 0;
-				     i < (MEGASAS_RESET_WAIT_TIME * 1000);
-				     i += 20) {
-					status_reg =
-						instance->instancet->
-						read_fw_status_reg(
-							instance->reg_set);
-					abs_state = status_reg &
-						MFI_STATE_MASK;
-					if (abs_state == MFI_STATE_READY) {
-						dev_warn(&instance->pdev->dev,
-						       "SR-IOV: FW was found"
-						       "to be in ready state "
-						       "for scsi%d.\n",
-						       instance->host->host_no);
-						break;
-					}
-					msleep(20);
-				}
-				if (abs_state != MFI_STATE_READY) {
-					dev_warn(&instance->pdev->dev, "SR-IOV: "
-					       "FW not in ready state after %d"
-					       " seconds for scsi%d, status_reg = "
-					       "0x%x.\n",
-					       MEGASAS_RESET_WAIT_TIME,
-					       instance->host->host_no,
-					       status_reg);
-					megaraid_sas_kill_hba(instance);
-					instance->skip_heartbeat_timer_del = 1;
-					atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
-					retval = FAILED;
-					goto out;
-				}
-			}
+			goto transition_to_ready;
 		}
 
 		/* Now try to reset the chip */
@@ -3526,25 +3481,28 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
 			if (instance->instancet->adp_reset
 				(instance, instance->reg_set))
 				continue;
-
+transition_to_ready:
 			/* Wait for FW to become ready */
 			if (megasas_transition_to_ready(instance, 1)) {
-				dev_warn(&instance->pdev->dev, "Failed to "
-				       "transition controller to ready "
-				       "for scsi%d.\n",
-				       instance->host->host_no);
-				continue;
+				dev_warn(&instance->pdev->dev,
+					"Failed to transition controller to ready for "
+					"scsi%d.\n", instance->host->host_no);
+				if (instance->requestorId && !reason)
+					goto fail_kill_adapter;
+				else
+					continue;
 			}
-
 			megasas_reset_reply_desc(instance);
 			megasas_fusion_update_can_queue(instance, OCR_CONTEXT);
 
 			if (megasas_ioc_init_fusion(instance)) {
 				dev_warn(&instance->pdev->dev,
-				       "megasas_ioc_init_fusion() failed!"
-				       " for scsi%d\n",
-				       instance->host->host_no);
-				continue;
+				       "megasas_ioc_init_fusion() failed! for "
+				       "scsi%d\n", instance->host->host_no);
+				if (instance->requestorId && !reason)
+					goto fail_kill_adapter;
+				else
+					continue;
 			}
 
 			megasas_refire_mgmt_cmd(instance);
@@ -3601,6 +3559,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
 			retval = SUCCESS;
 			goto out;
 		}
+fail_kill_adapter:
 		/* Reset failed, kill the adapter */
 		dev_warn(&instance->pdev->dev, "Reset failed, killing "
 		       "adapter scsi%d.\n", instance->host->host_no);
-- 
1.7.1


^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 15/15] megaraid_sas: SPERC boot driver reorder
  2015-12-18 13:26 [PATCH 00/15] megaraid_sas: Updates for scsi-next Sumit Saxena
                   ` (13 preceding siblings ...)
  2015-12-18 13:27 ` [PATCH 14/15] megaraid_sas: SPERC OCR changes Sumit Saxena
@ 2015-12-18 13:27 ` Sumit Saxena
  2015-12-18 14:05   ` Christoph Hellwig
  14 siblings, 1 reply; 50+ messages in thread
From: Sumit Saxena @ 2015-12-18 13:27 UTC (permalink / raw)
  To: jbottomley, hch, martin.petersen
  Cc: linux-scsi, kashyap.desai, sumit.saxena, Uday Lingala

This patch will add support for drive ordering for a particular set of device ID (0x005D, 0x005F) & subsystem vendor ID(0x1028). 

The driver sends down MR_DCMD_CTRL_BIOS_DATA_GET to obtain information about the boot drive and calculates the target ID & Channel ID.
Instead of invoking scsi_scan_host() kernel API to let the SCSI layer scan sequentially, the driver calls scsi_add_device() to add the
targets one by one based on the following algorithms-

* If boot device is not present, driver exposes the LDs first in increasing order of target ID number followed by system PDs in slot order.
* If boot device is present and it is an LD, driver exposes the boot device first, then exposes the LDs in increasing order of target ID number
followed by system PDs in slot order.
* If boot device is present and it is an PD driver exposes the boot device first, then exposes the system PDs in slot order followed by LDs 
in increasing order of target ID.

Signed-off-by: Uday Lingala <uday.lingala@avagotech.com>
Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
---
 drivers/scsi/megaraid/megaraid_sas.h      |   32 +++
 drivers/scsi/megaraid/megaraid_sas_base.c |  333 ++++++++++++++++++++++++++++-
 2 files changed, 360 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index ac19d53..fcf2b86 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -217,6 +217,7 @@
 #define MR_DCMD_CTRL_SET_CRASH_DUMP_PARAMS	0x01190100
 #define MR_DRIVER_SET_APP_CRASHDUMP_MODE	(0xF0010000 | 0x0600)
 #define MR_DCMD_PD_GET_INFO			0x02020000
+#define MR_DCMD_CTRL_BIOS_DATA_GET              0x010c0100
 
 /*
  * Global functions
@@ -763,6 +764,21 @@ struct MR_LD_TARGETID_LIST {
 	u8	targetId[MAX_LOGICAL_DRIVES_EXT];
 };
 
+struct MR_BIOS_DATA {
+	u16     bootTargetId;
+	u8      doNotExpose;
+	u8      continueOnError;
+	u8      verbose;
+	u8      geometry;
+	u8      exposeAllDrives;
+	u8      disableCTO;
+	u8      bootDeviceIsPD;
+	u8      EKMStatus;
+	u8      autoSelectBootLd;
+	u8      reserved[52];
+	u8      checkSum;
+};
+
 
 /*
  * SAS controller properties
@@ -1341,6 +1357,8 @@ struct megasas_ctrl_info {
 #define SCAN_PD_CHANNEL	0x1
 #define SCAN_VD_CHANNEL	0x2
 
+#define MEGASAS_INVALID_TARGET_ID               0xFFFF
+
 enum MR_SCSI_CMD_TYPE {
 	READ_WRITE_LDIO = 0,
 	NON_READ_WRITE_LDIO = 1,
@@ -1994,6 +2012,17 @@ enum MR_PD_TYPE {
 		 FC_PD = 4,
 };
 
+/*
+ *  define the structure specific to drive order feature
+ */
+struct megasas_drive_order {
+	u8 needs_ordering;         /* Drive ordering feature is enabled/disabled */
+	u8 boot_drive_is_pd;       /* Set if boot device is PD */
+	u16 boot_fw_tgt_id;        /* FW Target ID */
+	u8 boot_drive_channel_id;  /* OS Channel ID */
+	u16 boot_drive_tgt_id;     /* OS Target ID */
+};
+
 /* JBOD Queue depth definitions */
 #define MEGASAS_SATA_QD	32
 #define MEGASAS_SAS_QD	64
@@ -2133,7 +2162,9 @@ struct megasas_instance {
 	u8 is_imr;
 	u8 is_rdpq;
 	bool dev_handle;
+	struct megasas_drive_order drive_order;
 };
+
 struct MR_LD_VF_MAP {
 	u32 size;
 	union MR_LD_REF ref;
@@ -2319,6 +2350,7 @@ struct megasas_mgmt_info {
 	int max_index;
 };
 
+
 enum MEGASAS_OCR_CAUSE {
 	FW_FAULT_OCR			= 0,
 	SCSIIO_TIMEOUT_OCR		= 1,
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index 316d5a0..b946ecb 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -4445,6 +4445,139 @@ static void megasas_update_ext_vd_details(struct megasas_instance *instance)
 }
 
 /**
+ * megasas_get_bios_data  -	Returns FW's mr_bios_data structure
+ * @instance:			Adapter structure
+ *
+ * Issues an internal command (DCMD) to get the FW's controller BIOS
+ * data structure.  This information is mainly used to find the
+ * boot drive and its target id.
+ */
+
+static int
+megasas_get_bios_data(struct megasas_instance *instance)
+{
+	int ret = 0;
+	struct megasas_cmd *cmd;
+	struct megasas_dcmd_frame *dcmd;
+	struct MR_BIOS_DATA *ci;
+	struct megasas_drive_order *drv_odr;
+	dma_addr_t ci_h = 0;
+
+	drv_odr = &instance->drive_order;
+	cmd = megasas_get_cmd(instance);
+
+	if (!cmd) {
+		dev_info(&instance->pdev->dev, "%s : "
+		    "Failed to get cmd\n", __func__);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	dcmd = &cmd->frame->dcmd;
+
+	ci = pci_alloc_consistent(instance->pdev,
+	    sizeof(struct MR_BIOS_DATA), &ci_h);
+
+	if (!ci) {
+		dev_info(&instance->pdev->dev, "%s : "
+		    "Failed to alloc mem for get_bios_data\n", __func__);
+		ret = -ENOMEM;
+		goto cmd_free;
+	}
+
+	memset(ci, 0, sizeof(struct MR_BIOS_DATA));
+	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+	dcmd->cmd = MFI_CMD_DCMD;
+	dcmd->cmd_status = 0xFF;
+	dcmd->sge_count = 1;
+	dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ);
+	dcmd->timeout = 0;
+	dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_BIOS_DATA));
+	dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_BIOS_DATA_GET);
+	dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(ci_h);
+	dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct MR_BIOS_DATA));
+	dcmd->pad_0  = 0;
+
+	if (instance->ctrl_context && !instance->mask_interrupts)
+		ret = megasas_issue_blocked_cmd(instance, cmd, 60);
+	else
+		ret = megasas_issue_polled(instance, cmd);
+
+	switch (ret) {
+
+	case DCMD_SUCCESS:
+		/* check if boot drive is there */
+		if (le16_to_cpu(ci->bootTargetId) != MEGASAS_INVALID_TARGET_ID) {
+			drv_odr->boot_fw_tgt_id = le16_to_cpu(ci->bootTargetId);
+			drv_odr->boot_drive_is_pd = ci->bootDeviceIsPD;
+
+			if (drv_odr->boot_drive_is_pd) {
+				/* System PD Channel id set to 0 or 1 */
+				drv_odr->boot_drive_channel_id =
+					drv_odr->boot_fw_tgt_id/
+					MEGASAS_MAX_DEV_PER_CHANNEL;
+
+				/* System PD Target id set to 0 - 127 */
+				drv_odr->boot_drive_tgt_id =
+					drv_odr->boot_fw_tgt_id -
+					(drv_odr->boot_drive_channel_id *
+					MEGASAS_MAX_DEV_PER_CHANNEL);
+			} else {
+				/* LD Channel id set to 2 or 3 */
+				drv_odr->boot_drive_channel_id =
+					MEGASAS_MAX_PD_CHANNELS +
+					(drv_odr->boot_fw_tgt_id/
+					MEGASAS_MAX_DEV_PER_CHANNEL);
+
+				/* LD Target id set to 0 - 127 */
+				drv_odr->boot_drive_tgt_id =
+					drv_odr->boot_fw_tgt_id -
+					((drv_odr->boot_drive_channel_id -
+					MEGASAS_MAX_PD_CHANNELS) *
+					MEGASAS_MAX_DEV_PER_CHANNEL);
+			}
+		}
+		break;
+	case DCMD_TIMEOUT:
+		switch (dcmd_timeout_ocr_possible(instance)) {
+		case INITIATE_OCR:
+			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+			/*
+			 * DCMD failed from AEN path.
+			 * AEN path already hold reset_mutex to avoid PCI access
+			 * while OCR is in progress.
+			 */
+			megasas_reset_fusion(instance->host,
+			MFI_IO_TIMEOUT_OCR);
+			break;
+		case KILL_ADAPTER:
+			megaraid_sas_kill_hba(instance);
+			break;
+		case IGNORE_TIMEOUT:
+			dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d \n",
+						__func__, __LINE__);
+			break;
+
+		}
+		break;
+	case DCMD_FAILED:
+		dev_info(&instance->pdev->dev, "%s : "
+		    "Failed with return(%d)\n", __func__, ret);
+		break;
+	}
+
+	pci_free_consistent(instance->pdev, sizeof(struct MR_BIOS_DATA),
+	    ci, ci_h);
+
+cmd_free:
+	if (ret != DCMD_TIMEOUT)
+		megasas_return_cmd(instance, cmd);
+out:
+	return ret;
+}
+
+/**
  * megasas_get_controller_info -	Returns FW's controller structure
  * @instance:				Adapter soft state
  *
@@ -5653,6 +5786,194 @@ fail_set_dma_mask:
 }
 
 /**
+ * megasas_need_for_drive_ordering - Identify if the card needs drive ordering
+ * @instance:		Adapter structure
+ *
+ * This function looks at the Device ID & SubSystem Vendor ID and decides
+ * whether the drive ordering needs to be performed or not
+ *
+ * returns: 1 - Needs Ordering
+ *          0 - Does Not Need Ordering
+ */
+
+static u8
+megasas_need_for_drive_ordering(struct megasas_instance *instance)
+{
+	u8 ret;
+
+	if (((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
+	    (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) &&
+	    (instance->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL))
+		ret = 1; /* Needs ordering */
+	else
+		ret = 0; /* Does NOT need ordering */
+
+	return ret;
+}
+
+/**
+ * megasas_expose_drives_to_os - expose drive to OS by scanning or adding
+ * @instance:		Adapter structure
+ *
+ * This function either invokes scsi_scan_host() to add drives for
+ * cards which doesn't need drive ordering or invokes scsi_add_device()
+ * which needs drive ordering.
+ */
+
+static void
+megasas_expose_drives_to_os(struct megasas_instance *instance)
+{
+	int i, j, ret = 0;
+	struct Scsi_Host *host;
+	struct megasas_drive_order *drv_odr;
+	u16 pd_index = 0;
+	u16 ld_index = 0;
+
+	host = instance->host;
+	drv_odr = &instance->drive_order;
+
+	drv_odr->needs_ordering =
+	    megasas_need_for_drive_ordering(instance);
+
+	/*
+	 * Check if drive ordering is needed, if not
+	 * invoke SCSI layer to scan.
+	 */
+	if (!drv_odr->needs_ordering) {
+		/* Trigger SCSI to scan our drives */
+		scsi_scan_host(host);
+		return;
+	}
+
+	/* Drive ordering is needed, obtain details on boot drive */
+	ret = megasas_get_bios_data(instance);
+	if (ret) {
+		dev_info(&instance->pdev->dev, "%s : Failure in updating "
+			"boot disk data-structure disk_order\n", __func__);
+	}
+
+	/* Check if boot drive is behind this controller, if so
+	 * add that first */
+	if (drv_odr->boot_fw_tgt_id != MEGASAS_INVALID_TARGET_ID) {
+		ret = scsi_add_device(host, drv_odr->boot_drive_channel_id,
+		    drv_odr->boot_drive_tgt_id, 0);
+		if (ret) {
+			dev_info(&instance->pdev->dev, "%s : Failure in "
+			    "scsi_add_device() for boot drive (%d)\n",
+			    __func__, ret);
+		}
+	}
+
+	/* Case 1: Boot drive is not there
+	 * Case 2: Boot drive is there & it is LD
+	 * (which is already exposed above) */
+	if ((drv_odr->boot_fw_tgt_id == MEGASAS_INVALID_TARGET_ID) ||
+	    ((drv_odr->boot_fw_tgt_id != MEGASAS_INVALID_TARGET_ID) &&
+	    (!drv_odr->boot_drive_is_pd))) {
+
+		/* Expose LDs */
+		for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
+			for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
+				ld_index = (i * MEGASAS_MAX_DEV_PER_CHANNEL)
+				    + j;
+
+				/* Check if LD is present and it is not
+				 * the already added boot drive */
+				if ((instance->ld_ids[ld_index] != 0xff) &&
+				    (ld_index != drv_odr->boot_fw_tgt_id)) {
+					ret = scsi_add_device(host,
+					    MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+					if (ret) {
+						dev_info(&instance->pdev->dev,
+						    "%s : Failure (%d) in "
+						    "scsi_add_device() for LD "
+						    "Channel:%d, Target:%d\n",
+						    __func__, ret,
+						    (MEGASAS_MAX_PD_CHANNELS
+						    + i), j);
+					}
+				}
+			}
+		}
+
+		/* Expose System PDs */
+		for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
+			for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
+				pd_index = (i * MEGASAS_MAX_DEV_PER_CHANNEL)
+				    + j;
+				if (instance->pd_list[pd_index].driveState ==
+				    MR_PD_STATE_SYSTEM) {
+					ret = scsi_add_device(host, i, j, 0);
+					if (ret) {
+						dev_info(&instance->pdev->dev,
+						    "%s : Failure (%d) in "
+						    "scsi_add_device() for "
+						    "System PD Channel: %d, "
+						    "Target: %d\n",
+						    __func__, ret, i, j);
+					}
+				}
+			}
+		}
+		return;
+	}
+
+	/* Case 3: Boot drive is there & it is System PD
+	 * (which is already exposed above) */
+	if ((drv_odr->boot_fw_tgt_id != MEGASAS_INVALID_TARGET_ID) &&
+	    (drv_odr->boot_drive_is_pd)) {
+
+		/* Expose System PDs */
+		for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
+			for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
+				pd_index = (i * MEGASAS_MAX_DEV_PER_CHANNEL)
+				    + j;
+
+				/* Check if System PD is present and
+				 * it is not the already added boot drive */
+				if ((instance->pd_list[pd_index].driveState ==
+				    MR_PD_STATE_SYSTEM) &&
+				    (pd_index != drv_odr->boot_fw_tgt_id)) {
+					ret = scsi_add_device(host, i, j, 0);
+					if (ret) {
+						dev_info(&instance->pdev->dev,
+						    "%s : Failure (%d) in "
+						    "scsi_add_device() for "
+						    "System PD Channel: %d, "
+						    "Target: %d\n",
+						    __func__, ret, i, j);
+					}
+				}
+			}
+		}
+
+		/* Expose LDs */
+		for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
+			for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
+				ld_index = (i * MEGASAS_MAX_DEV_PER_CHANNEL)
+				    + j;
+
+				/* Check if LD is present */
+				if (instance->ld_ids[ld_index] != 0xff) {
+					ret = scsi_add_device(host,
+					    MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+					if (ret) {
+						dev_info(&instance->pdev->dev,
+						    "%s : Failure (%d) in "
+						    "scsi_add_device() for LD "
+						    "Channel:%d, Target:%d\n",
+						    __func__, ret,
+						    (MEGASAS_MAX_PD_CHANNELS
+						    + i), j);
+					}
+				}
+			}
+		}
+		return;
+	}
+}
+
+/**
  * megasas_probe_one -	PCI hotplug entry point
  * @pdev:		PCI device structure
  * @id:			PCI ids of supported hotplugged adapter
@@ -5788,6 +6109,8 @@ static int megasas_probe_one(struct pci_dev *pdev,
 	instance->issuepend_done = 1;
 	atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
 	instance->is_imr = 0;
+	 /* Setting boot_fw_tgt_id to none */
+	instance->drive_order.boot_fw_tgt_id = MEGASAS_INVALID_TARGET_ID;
 
 	instance->evt_detail = pci_alloc_consistent(pdev,
 						    sizeof(struct
@@ -5895,11 +6218,6 @@ static int megasas_probe_one(struct pci_dev *pdev,
 	if (megasas_io_attach(instance))
 		goto fail_io_attach;
 
-	instance->unload = 0;
-	/*
-	 * Trigger SCSI to scan our drives
-	 */
-	scsi_scan_host(host);
 
 	/*
 	 * Initiate AEN (Asynchronous Event Notification)
@@ -5909,6 +6227,11 @@ static int megasas_probe_one(struct pci_dev *pdev,
 		goto fail_start_aen;
 	}
 
+	instance->unload = 0;
+
+	/* Expose the System PD/LD to Operating System */
+	megasas_expose_drives_to_os(instance);
+
 	/* Get current SR-IOV LD/VF affiliation */
 	if (instance->requestorId)
 		megasas_get_ld_vf_affiliation(instance, 1);
-- 
1.7.1


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 15/15] megaraid_sas: SPERC boot driver reorder
  2015-12-18 13:27 ` [PATCH 15/15] megaraid_sas: SPERC boot driver reorder Sumit Saxena
@ 2015-12-18 14:05   ` Christoph Hellwig
  2016-01-08  7:07     ` Sumit Saxena
  2016-01-12  5:26     ` Sumit Saxena
  0 siblings, 2 replies; 50+ messages in thread
From: Christoph Hellwig @ 2015-12-18 14:05 UTC (permalink / raw)
  To: Sumit Saxena
  Cc: jbottomley, hch, martin.petersen, linux-scsi, kashyap.desai,
	Uday Lingala

On Fri, Dec 18, 2015 at 06:57:08PM +0530, Sumit Saxena wrote:
> This patch will add support for drive ordering for a particular set of device ID (0x005D, 0x005F) & subsystem vendor ID(0x1028). 

This really has no business in Linux.  Everyone should be using uuid
based disk addressing if they care.  Tell Dell they should stop coming
up with this crap, as they keep leaking this weird ordering things in
again and again.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH] megaraid_sas: fix kzalloc-simple.cocci warnings
  2015-12-18 13:27 ` [PATCH 07/15] megaraid_sas: Reply Descriptor Post Queue(RDPQ) support Sumit Saxena
@ 2015-12-18 14:49   ` kbuild test robot
  2015-12-18 14:49   ` [PATCH 07/15] megaraid_sas: Reply Descriptor Post Queue(RDPQ) support kbuild test robot
  2016-01-14 17:38   ` Tomas Henzl
  2 siblings, 0 replies; 50+ messages in thread
From: kbuild test robot @ 2015-12-18 14:49 UTC (permalink / raw)
  Cc: kbuild-all, jbottomley, hch, martin.petersen, linux-scsi,
	kashyap.desai, sumit.saxena

drivers/scsi/megaraid/megaraid_sas_fusion.c:331:20-27: WARNING: kzalloc should be used for fusion -> cmd_list, instead of kmalloc/memset
drivers/scsi/megaraid/megaraid_sas_fusion.c:342:24-31: WARNING: kzalloc should be used for fusion -> cmd_list [ i ], instead of kmalloc/memset


 Use kzalloc rather than kmalloc followed by memset with 0

 This considers some simple cases that are common and easy to validate
 Note in particular that there are no ...s in the rule, so all of the
 matched code has to be contiguous

Generated by: scripts/coccinelle/api/alloc/kzalloc-simple.cocci

CC: Sumit Saxena <sumit.saxena@avagotech.com>
Signed-off-by: Fengguang Wu <fengguang.wu@intel.com>
---

 megaraid_sas_fusion.c |    9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -328,25 +328,22 @@ megasas_alloc_cmdlist_fusion(struct mega
 	 * Allocate the dynamic array first and then allocate individual
 	 * commands.
 	 */
-	fusion->cmd_list = kmalloc(sizeof(struct megasas_cmd_fusion *) * max_cmd,
-						GFP_KERNEL);
+	fusion->cmd_list = kzalloc(sizeof(struct megasas_cmd_fusion *) * max_cmd,
+				   GFP_KERNEL);
 	if (!fusion->cmd_list) {
 		dev_err(&instance->pdev->dev,
 			"Failed from %s %d\n",  __func__, __LINE__);
 		return -ENOMEM;
 	}
-	memset(fusion->cmd_list, 0,
-		sizeof(struct megasas_cmd_fusion *) * max_cmd);
 
 	for (i = 0; i < max_cmd; i++) {
-		fusion->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd_fusion),
+		fusion->cmd_list[i] = kzalloc(sizeof(struct megasas_cmd_fusion),
 					      GFP_KERNEL);
 		if (!fusion->cmd_list[i]) {
 			dev_err(&instance->pdev->dev,
 				"Failed from %s %d\n",  __func__, __LINE__);
 			return -ENOMEM;
 		}
-		memset(fusion->cmd_list[i], 0, sizeof(struct megasas_cmd_fusion));
 	}
 	return 0;
 }

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 07/15] megaraid_sas: Reply Descriptor Post Queue(RDPQ) support
  2015-12-18 13:27 ` [PATCH 07/15] megaraid_sas: Reply Descriptor Post Queue(RDPQ) support Sumit Saxena
  2015-12-18 14:49   ` [PATCH] megaraid_sas: fix kzalloc-simple.cocci warnings kbuild test robot
@ 2015-12-18 14:49   ` kbuild test robot
  2016-01-14 17:38   ` Tomas Henzl
  2 siblings, 0 replies; 50+ messages in thread
From: kbuild test robot @ 2015-12-18 14:49 UTC (permalink / raw)
  Cc: kbuild-all, jbottomley, hch, martin.petersen, linux-scsi,
	kashyap.desai, sumit.saxena

Hi Sumit,

[auto build test WARNING on scsi/for-next]
[also build test WARNING on v4.4-rc5 next-20151218]

url:    https://github.com/0day-ci/linux/commits/Sumit-Saxena/megaraid_sas-Do-not-allow-PCI-access-during-OCR/20151218-213231
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git for-next


coccinelle warnings: (new ones prefixed by >>)

>> drivers/scsi/megaraid/megaraid_sas_fusion.c:331:20-27: WARNING: kzalloc should be used for fusion -> cmd_list, instead of kmalloc/memset
>> drivers/scsi/megaraid/megaraid_sas_fusion.c:342:24-31: WARNING: kzalloc should be used for fusion -> cmd_list [ i ], instead of kmalloc/memset

Please review and possibly fold the followup patch.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply	[flat|nested] 50+ messages in thread

* RE: [PATCH 15/15] megaraid_sas: SPERC boot driver reorder
  2015-12-18 14:05   ` Christoph Hellwig
@ 2016-01-08  7:07     ` Sumit Saxena
  2016-01-12  5:26     ` Sumit Saxena
  1 sibling, 0 replies; 50+ messages in thread
From: Sumit Saxena @ 2016-01-08  7:07 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: jbottomley, martin.petersen, linux-scsi, Kashyap Desai, Uday Lingala

> -----Original Message-----
> From: Christoph Hellwig [mailto:hch@infradead.org]
> Sent: Friday, December 18, 2015 7:35 PM
> To: Sumit Saxena
> Cc: jbottomley@parallels.com; hch@infradead.org;
> martin.petersen@oracle.com; linux-scsi@vger.kernel.org;
> kashyap.desai@avagotech.com; Uday Lingala
> Subject: Re: [PATCH 15/15] megaraid_sas: SPERC boot driver reorder
>
> On Fri, Dec 18, 2015 at 06:57:08PM +0530, Sumit Saxena wrote:
> > This patch will add support for drive ordering for a particular set of
device ID
> (0x005D, 0x005F) & subsystem vendor ID(0x1028).
>
> This really has no business in Linux.  Everyone should be using uuid
based disk
> addressing if they care.  Tell Dell they should stop coming up with this
crap, as
> they keep leaking this weird ordering things in again and again.

This patch can be ignored. We discussed with Dell on this and they are
fine to backout the patch.
Can you provide any feedback on rest of the patches?

Thanks,
Sumit

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 01/15] megaraid_sas: Do not allow PCI access during OCR
  2015-12-18 13:26 ` [PATCH 01/15] megaraid_sas: Do not allow PCI access during OCR Sumit Saxena
@ 2016-01-11 17:02   ` Tomas Henzl
  0 siblings, 0 replies; 50+ messages in thread
From: Tomas Henzl @ 2016-01-11 17:02 UTC (permalink / raw)
  To: Sumit Saxena, jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai

On 18.12.2015 14:26, Sumit Saxena wrote:
> This patch will do synhronization between OCR function and AEN function using "reset_mutex" lock.
> reset_mutex will be acquire only in first half of the AEN function which issue DCMD. Second half
> of the function calls SCSI API (scsi_add_device/scsi_remove_device) should be out of reset_mutex
> to avoid deadlock between scsi_eh thread and Driver.
>
> During chip reset(inside OCR function), there should not be any PCI access and AEN function
> (which is called in delayed context) may be firirng DCMDs(doing PCI writes) when chip reset is
> happening in parallel which will cause FW fault. This patch will solve the problem by making
> AEN thread and OCR thread mutually exclusive.
>
> Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
> Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>

You have removed the no more aen_mutex from megasas_instance
later in 5/15 , that's ok for me.

Reviewed-by: Tomas Henzl <thenzl@redhat.com>

Tomas


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 02/15] megaraid_sas: MFI IO timeout handling
  2015-12-18 13:26 ` [PATCH 02/15] megaraid_sas: MFI IO timeout handling Sumit Saxena
@ 2016-01-11 17:02   ` Tomas Henzl
  0 siblings, 0 replies; 50+ messages in thread
From: Tomas Henzl @ 2016-01-11 17:02 UTC (permalink / raw)
  To: Sumit Saxena, jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai

On 18.12.2015 14:26, Sumit Saxena wrote:
> This patch will do proper error handling for DCMD timeout and failed cases for fusion adapters.
> Below are few key design points-
> 1. For MFI adapters, in case of DCMD timeout(DCMD which must return SUCCESS) driver will call kill adapter. 
> 2. What action needs to be taken in case of DCMD timeout is decided by function dcmd_timeout_ocr_possible().
> DCMD timeout causing OCR is applicable to below DCMDs-
>
> MR_DCMD_PD_LIST_QUERY
> MR_DCMD_LD_GET_LIST
> MR_DCMD_LD_LIST_QUERY
> MR_DCMD_CTRL_SET_CRASH_DUMP_PARAMS
> MR_DCMD_SYSTEM_PD_MAP_GET_INFO(for non pended DCMD)
> MR_DCMD_LD_MAP_GET_INFO(for non pended DCMD)
>
> 3. If DCMD fails from Driver init path, there are certain DCMD which is must to be return SUCCESS. If those DCMD fails,
> driver bail out load. For optional DCMD like pd_info etc, driver continue without executing certain functionality.
>
> Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
> Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>

Reviewed-by: Tomas Henzl <thenzl@redhat.com>

Tomas


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 03/15] megaraid_sas: Syncing request flags macro names with firmware
  2015-12-18 13:26 ` [PATCH 03/15] megaraid_sas: Syncing request flags macro names with firmware Sumit Saxena
@ 2016-01-11 17:03   ` Tomas Henzl
  0 siblings, 0 replies; 50+ messages in thread
From: Tomas Henzl @ 2016-01-11 17:03 UTC (permalink / raw)
  To: Sumit Saxena, jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai

On 18.12.2015 14:26, Sumit Saxena wrote:
> Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>

Reviewed-by: Tomas Henzl <thenzl@redhat.com>

Tomas


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 04/15] megaraid_sas: Task management support
  2015-12-18 13:26 ` [PATCH 04/15] megaraid_sas: Task management support Sumit Saxena
@ 2016-01-11 17:03   ` Tomas Henzl
  2016-01-14 12:04     ` Sumit Saxena
  0 siblings, 1 reply; 50+ messages in thread
From: Tomas Henzl @ 2016-01-11 17:03 UTC (permalink / raw)
  To: Sumit Saxena, jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai

On 18.12.2015 14:26, Sumit Saxena wrote:
> This patch will add task management(TM) support for SCSI commands in megaraid_sas driver.
> Added TM functions are below-
> 1)Task abort
> 2)Target reset
>
> Below are few key points-
>
> 1. Currently, megaraid_sas driver performs Controller reset when any IO times out.
> With these TM support added in driver, in case of IO timeout task abort and target
> reset will be tried to recover timed out IO. If both fails to recover IO, then
> Controller reset will be called. If the TM request times out, fail the TM and escalate
> to the next level(Controller reset).
>
> 2. mr_device_priv_data will be allocated for all generation of controller, but is_tm_capable
> flag will never be set for older controllers (prior to Invader series) as firmware support is not
> available for T.M functionality.
>
> 3. whichever firmware is capable for TM will set is_tm_capable flag in firmware API, which will be used
> by Driver to pass TM frame to firmware or return back to OS as Failure to escalate next level of Error handling.
>
> Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
> Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
> ---
>  drivers/scsi/megaraid/megaraid_sas.h        |   13 +
>  drivers/scsi/megaraid/megaraid_sas_base.c   |   63 +++-
>  drivers/scsi/megaraid/megaraid_sas_fusion.c |  479 ++++++++++++++++++++++++++-
>  drivers/scsi/megaraid/megaraid_sas_fusion.h |  117 +++++++-
>  4 files changed, 653 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
> index dcc6ff8..0fcb156 100644
> --- a/drivers/scsi/megaraid/megaraid_sas.h
> +++ b/drivers/scsi/megaraid/megaraid_sas.h
> @@ -1520,6 +1520,15 @@ union megasas_frame {
>  	u8 raw_bytes[64];
>  };
>  
> +/**
> + * struct MR_PRIV_DEVICE - sdev private hostdata
> + * @is_tm_capable: firmware managed tm_capable flag
> + * @tm_busy: TM request is in progress
> + */
> +struct MR_PRIV_DEVICE {
> +	bool is_tm_capable;
> +	bool tm_busy;
> +};
>  struct megasas_cmd;
>  
>  union megasas_evt_class_locale {
> @@ -2073,4 +2082,8 @@ void megasas_return_mfi_mpt_pthr(struct megasas_instance *instance,
>  int megasas_cmd_type(struct scsi_cmnd *cmd);
>  void megasas_setup_jbod_map(struct megasas_instance *instance);
>  
> +void megasas_update_sdev_properties(struct scsi_device *sdev);
> +int megasas_reset_fusion(struct Scsi_Host *shost, int reason);
> +int megasas_task_abort_fusion(struct scsi_cmnd *scmd);
> +int megasas_reset_target_fusion(struct scsi_cmnd *scmd);
>  #endif				/*LSI_MEGARAID_SAS_H */
> diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
> index 380c627..c1dc23c 100644
> --- a/drivers/scsi/megaraid/megaraid_sas_base.c
> +++ b/drivers/scsi/megaraid/megaraid_sas_base.c
> @@ -189,7 +189,6 @@ int
>  wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
>  	int seconds);
>  void megasas_reset_reply_desc(struct megasas_instance *instance);
> -int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout);
>  void megasas_fusion_ocr_wq(struct work_struct *work);
>  static int megasas_get_ld_vf_affiliation(struct megasas_instance *instance,
>  					 int initial);
> @@ -1645,6 +1644,7 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
>  {
>  	struct megasas_instance *instance;
>  	unsigned long flags;
> +	struct MR_PRIV_DEVICE *mr_device_priv_data;
>  
>  	instance = (struct megasas_instance *)
>  	    scmd->device->host->hostdata;
> @@ -1681,11 +1681,24 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
>  		return 0;
>  	}
>  
> +	mr_device_priv_data = scmd->device->hostdata;
> +	if (!mr_device_priv_data) {
> +		spin_unlock_irqrestore(&instance->hba_lock, flags);
> +		scmd->result = DID_NO_CONNECT << 16;
> +		scmd->scsi_done(scmd);
> +		return 0;
> +	}
> +
>  	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
>  		spin_unlock_irqrestore(&instance->hba_lock, flags);
>  		return SCSI_MLQUEUE_HOST_BUSY;
>  	}
>  
> +	if (mr_device_priv_data->tm_busy) {
> +		spin_unlock_irqrestore(&instance->hba_lock, flags);
> +		return SCSI_MLQUEUE_DEVICE_BUSY;
> +	}
> +
>  	spin_unlock_irqrestore(&instance->hba_lock, flags);
>  
>  	scmd->result = 0;
> @@ -1736,27 +1749,39 @@ static struct megasas_instance *megasas_lookup_instance(u16 host_no)
>  }
>  
>  /*
> -* megasas_set_dma_alignment - Set DMA alignment for PI enabled VD
> +* megasas_update_sdev_properties - Update sdev structure based on controller's FW capabilities
>  *
>  * @sdev: OS provided scsi device
>  *
>  * Returns void
>  */
> -static void megasas_set_dma_alignment(struct scsi_device *sdev)
> +void megasas_update_sdev_properties(struct scsi_device *sdev)
>  {
> +	u16 pd_index = 0;
>  	u32 device_id, ld;
>  	struct megasas_instance *instance;
>  	struct fusion_context *fusion;
> +	struct MR_PRIV_DEVICE *mr_device_priv_data;
> +	struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync;
>  	struct MR_LD_RAID *raid;
>  	struct MR_DRV_RAID_MAP_ALL *local_map_ptr;
>  
>  	instance = megasas_lookup_instance(sdev->host->host_no);
>  	fusion = instance->ctrl_context;
> +	mr_device_priv_data = sdev->hostdata;
>  
> -	if (!fusion)
> +	if (!fusion || !mr_device_priv_data)
>  		return;

How can this happen that mr_device_priv_data is NULL,
and if isn't it a problem that you do not set the dma alignment
and other megasas_instance values?

>  
> -	if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS) {
> +	if (sdev->channel < MEGASAS_MAX_PD_CHANNELS &&
> +		instance->use_seqnum_jbod_fp) {
> +		pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
> +			sdev->id;
> +		pd_sync = (void *)fusion->pd_seq_sync
> +				[(instance->pd_seq_map_id - 1) & 1];
> +		mr_device_priv_data->is_tm_capable =
> +			pd_sync->seq[pd_index].capability.tmCapable;
> +	} else {
>  		device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL)
>  					+ sdev->id;
>  		local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
> @@ -1764,10 +1789,14 @@ static void megasas_set_dma_alignment(struct scsi_device *sdev)
>  		raid = MR_LdRaidGet(ld, local_map_ptr);
>  
>  		if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER)
> -			blk_queue_update_dma_alignment(sdev->request_queue, 0x7);
> +		blk_queue_update_dma_alignment(sdev->request_queue, 0x7);

Please keep the whitespace above.

> +
> +		mr_device_priv_data->is_tm_capable =
> +			raid->capability.tmCapable;
>  	}
>  }
>  
> +
>  static int megasas_slave_configure(struct scsi_device *sdev)
>  {
>  	u16 pd_index = 0;
> @@ -1784,7 +1813,8 @@ static int megasas_slave_configure(struct scsi_device *sdev)
>  				return -ENXIO;
>  		}
>  	}
> -	megasas_set_dma_alignment(sdev);
> +	megasas_update_sdev_properties(sdev);
> +
>  	/*
>  	 * The RAID firmware may require extended timeouts.
>  	 */
> @@ -1798,6 +1828,7 @@ static int megasas_slave_alloc(struct scsi_device *sdev)
>  {
>  	u16 pd_index = 0;
>  	struct megasas_instance *instance ;
> +	struct MR_PRIV_DEVICE *mr_device_priv_data;
>  
>  	instance = megasas_lookup_instance(sdev->host->host_no);
>  	if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
> @@ -1809,13 +1840,26 @@ static int megasas_slave_alloc(struct scsi_device *sdev)
>  			sdev->id;
>  		if ((instance->allow_fw_scan || instance->pd_list[pd_index].driveState ==
>  			MR_PD_STATE_SYSTEM)) {
> -			return 0;
> +			goto scan_target;
>  		}
>  		return -ENXIO;
>  	}
> +
> +scan_target:
> +	mr_device_priv_data = kzalloc(sizeof(*mr_device_priv_data),
> +					GFP_KERNEL);
> +	if (!mr_device_priv_data)
> +		return -ENOMEM;
> +	sdev->hostdata = mr_device_priv_data;
>  	return 0;
>  }
>  
> +static void megasas_slave_destroy(struct scsi_device *sdev)
> +{
> +	kfree(sdev->hostdata);
> +	sdev->hostdata = NULL;
> +}
> +
>  /*
>  * megasas_complete_outstanding_ioctls - Complete outstanding ioctls after a
>  *                                       kill adapter
> @@ -2885,6 +2929,7 @@ static struct scsi_host_template megasas_template = {
>  	.proc_name = "megaraid_sas",
>  	.slave_configure = megasas_slave_configure,
>  	.slave_alloc = megasas_slave_alloc,
> +	.slave_destroy = megasas_slave_destroy,
>  	.queuecommand = megasas_queue_command,
>  	.eh_device_reset_handler = megasas_reset_device,
>  	.eh_bus_reset_handler = megasas_reset_bus_host,
> @@ -5434,6 +5479,8 @@ static int megasas_io_attach(struct megasas_instance *instance)
>  	if (instance->ctrl_context) {
>  		host->hostt->eh_device_reset_handler = NULL;
>  		host->hostt->eh_bus_reset_handler = NULL;
> +		host->hostt->eh_target_reset_handler = megasas_reset_target_fusion;
> +		host->hostt->eh_abort_handler = megasas_task_abort_fusion;
>  	}
>  
>  	/*
> diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> index 1dc4537..0b31f5a 100644
> --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
> +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> @@ -2100,6 +2100,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
>  	struct LD_LOAD_BALANCE_INFO *lbinfo;
>  	int threshold_reply_count = 0;
>  	struct scsi_cmnd *scmd_local = NULL;
> +	struct MR_TASK_MANAGE_REQUEST *mr_tm_req;
> +	struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_tm_req;
>  
>  	fusion = instance->ctrl_context;
>  
> @@ -2141,6 +2143,16 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
>  		extStatus = scsi_io_req->RaidContext.exStatus;
>  
>  		switch (scsi_io_req->Function) {
> +		case MPI2_FUNCTION_SCSI_TASK_MGMT:
> +			mr_tm_req = (struct MR_TASK_MANAGE_REQUEST *)
> +						cmd_fusion->io_request;
> +			mpi_tm_req = (struct MPI2_SCSI_TASK_MANAGE_REQUEST *)
> +						&mr_tm_req->TmRequest;
> +			dev_dbg(&instance->pdev->dev, "TM completion:"
> +				"type: 0x%x TaskMID: 0x%x\n",
> +				mpi_tm_req->TaskType, mpi_tm_req->TaskMID);
> +			complete(&cmd_fusion->done);
> +			break;
>  		case MPI2_FUNCTION_SCSI_IO_REQUEST:  /*Fast Path IO.*/
>  			/* Update load balancing info */
>  			device_id = MEGASAS_DEV_INDEX(scmd_local);
> @@ -2727,6 +2739,457 @@ void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
>  	}
>  }
>  
> +/*
> + * megasas_track_scsiio : Track SCSI IOs outstanding to a SCSI device
> + * @instance: per adapter struct
> + * @channel: the channel assigned by the OS
> + * @id: the id assigned by the OS
> + *
> + * Returns SUCCESS if no IOs pending to SCSI device, else return FAILED
> + */
> +
> +static int megasas_track_scsiio(struct megasas_instance *instance,
> +		int id, int channel)
> +{
> +	int i, found = 0;
> +	struct megasas_cmd_fusion *cmd_fusion;
> +	struct fusion_context *fusion;
> +	fusion = instance->ctrl_context;
> +
> +	for (i = 0 ; i < instance->max_scsi_cmds; i++) {
> +		cmd_fusion = fusion->cmd_list[i];
> +		if (cmd_fusion->scmd &&
> +			(cmd_fusion->scmd->device->id == id &&
> +			cmd_fusion->scmd->device->channel == channel)) {
> +			dev_info(&instance->pdev->dev,
> +				"SCSI commands pending to target"
> +				"channel %d id %d \tSMID: 0x%x\n",
> +				channel, id, cmd_fusion->index);
> +			scsi_print_command(cmd_fusion->scmd);
> +			found = 1;
> +			break;
> +		}
> +	}
> +
> +	return found ? FAILED : SUCCESS;
> +}
> +
> +/**
> + * megasas_tm_response_code - translation of device response code
> + * @ioc: per adapter object
> + * @mpi_reply: MPI reply returned by firmware
> + *
> + * Return nothing.
> + */
> +static void
> +megasas_tm_response_code(struct megasas_instance *instance,
> +		struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply)
> +{
> +	char *desc;
> +
> +	switch (mpi_reply->ResponseCode) {
> +	case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE:
> +		desc = "task management request completed";
> +		break;
> +	case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME:
> +		desc = "invalid frame";
> +		break;
> +	case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
> +		desc = "task management request not supported";
> +		break;
> +	case MPI2_SCSITASKMGMT_RSP_TM_FAILED:
> +		desc = "task management request failed";
> +		break;
> +	case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED:
> +		desc = "task management request succeeded";
> +		break;
> +	case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN:
> +		desc = "invalid lun";
> +		break;
> +	case 0xA:
> +		desc = "overlapped tag attempted";
> +		break;
> +	case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
> +		desc = "task queued, however not sent to target";
> +		break;
> +	default:
> +		desc = "unknown";
> +		break;
> +	}
> +	dev_dbg(&instance->pdev->dev, "response_code(%01x): %s\n",
> +		mpi_reply->ResponseCode, desc);
> +	dev_dbg(&instance->pdev->dev,
> +		"TerminationCount/DevHandle/Function/TaskType/IOCStat/IOCLoginfo"
> +		" 0x%x/0x%x/0x%x/0x%x/0x%x/0x%x\n",
> +		mpi_reply->TerminationCount, mpi_reply->DevHandle,
> +		mpi_reply->Function, mpi_reply->TaskType,
> +		mpi_reply->IOCStatus, mpi_reply->IOCLogInfo);
> +}
> +
> +/**
> + * megasas_issue_tm - main routine for sending tm requests
> + * @instance: per adapter struct
> + * @device_handle: device handle
> + * @channel: the channel assigned by the OS
> + * @id: the id assigned by the OS
> + * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in megaraid_sas_fusion.c)
> + * @smid_task: smid assigned to the task
> + * @m_type: TM_MUTEX_ON or TM_MUTEX_OFF
> + * Context: user
> + *
> + * MegaRaid use MPT interface for Task Magement request.
> + * A generic API for sending task management requests to firmware.
> + *
> + * Return SUCCESS or FAILED.
> + */
> +static int
> +megasas_issue_tm(struct megasas_instance *instance, u16 device_handle,
> +	uint channel, uint id, u16 smid_task, u8 type)
> +{
> +	struct MR_TASK_MANAGE_REQUEST *mr_request;
> +	struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_request;
> +	unsigned long timeleft;
> +	struct megasas_cmd_fusion *cmd_fusion;
> +	struct megasas_cmd *cmd_mfi;
> +	union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
> +	struct fusion_context *fusion;
> +	struct megasas_cmd_fusion *scsi_lookup;
> +	int rc;
> +	struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply;
> +
> +	fusion = instance->ctrl_context;
> +
> +	cmd_mfi = megasas_get_cmd(instance);
> +
> +	if (!cmd_mfi) {
> +		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
> +			__func__, __LINE__);
> +		return -ENOMEM;
> +	}
> +
> +	cmd_fusion = megasas_get_cmd_fusion(instance,
> +			instance->max_scsi_cmds + cmd_mfi->index);
> +
> +	/*  Save the smid. To be used for returning the cmd */
> +	cmd_mfi->context.smid = cmd_fusion->index;
> +
> +	req_desc = megasas_get_request_descriptor(instance,
> +			(cmd_fusion->index - 1));
> +	if (!req_desc) {
> +		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
> +			__func__, __LINE__);

	megasas_return_cmd should be called here?

> +		return -ENOMEM;
> +	}
> +
> +	cmd_fusion->request_desc = req_desc;
> +	req_desc->Words = 0;
> +
> +	scsi_lookup = fusion->cmd_list[smid_task - 1];
> +
> +	mr_request = (struct MR_TASK_MANAGE_REQUEST *) cmd_fusion->io_request;
> +	memset(mr_request, 0, sizeof(struct MR_TASK_MANAGE_REQUEST));
> +	mpi_request = (struct MPI2_SCSI_TASK_MANAGE_REQUEST *) &mr_request->TmRequest;
> +	mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
> +	mpi_request->DevHandle = cpu_to_le16(device_handle);
> +	mpi_request->TaskType = type;
> +	mpi_request->TaskMID = cpu_to_le16(smid_task);
> +	mpi_request->LUN[1] = 0;
> +
> +
> +	req_desc = cmd_fusion->request_desc;
> +	req_desc->HighPriority.SMID = cpu_to_le16(cmd_fusion->index);
> +	req_desc->HighPriority.RequestFlags =
> +		(MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
> +		MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
> +	req_desc->HighPriority.MSIxIndex =  0;
> +	req_desc->HighPriority.LMID = 0;
> +	req_desc->HighPriority.Reserved1 = 0;
> +
> +	if (channel < MEGASAS_MAX_PD_CHANNELS)
> +		mr_request->tmReqFlags.isTMForPD = 1;
> +	else
> +		mr_request->tmReqFlags.isTMForLD = 1;
> +
> +	init_completion(&cmd_fusion->done);
> +	megasas_fire_cmd_fusion(instance, req_desc);
> +
> +	timeleft = wait_for_completion_timeout(&cmd_fusion->done, 50 * HZ);
> +
> +	if (!timeleft) {
> +		dev_err(&instance->pdev->dev,
> +			"task mgmt type 0x%x timed out\n", type);
> +		mutex_unlock(&instance->reset_mutex);
> +		rc = megasas_reset_fusion(instance->host, MFI_IO_TIMEOUT_OCR);
> +		mutex_lock(&instance->reset_mutex);

	megasas_return_cmd should be called here too?

> +		return rc;
> +	}
> +
> +	mpi_reply = (struct MPI2_SCSI_TASK_MANAGE_REPLY *) &mr_request->TMReply;
> +	megasas_tm_response_code(instance, mpi_reply);
> +
> +	megasas_return_cmd(instance, cmd_mfi);
> +	rc = SUCCESS;
> +	switch (type) {
> +	case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
> +		if (scsi_lookup->scmd == NULL)
> +			break;
> +		else {
> +			instance->instancet->disable_intr(instance);
> +			msleep(1000);
> +			megasas_complete_cmd_dpc_fusion
> +					((unsigned long)instance);
> +			instance->instancet->enable_intr(instance);
> +			if (scsi_lookup->scmd == NULL)
> +				break;
> +		}
> +		rc = FAILED;
> +		break;
> +
> +	case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
> +		if ((channel == 0xFFFFFFFF) && (id == 0xFFFFFFFF))
> +			break;
> +		instance->instancet->disable_intr(instance);
> +		msleep(1000);
> +		megasas_complete_cmd_dpc_fusion
> +				((unsigned long)instance);
> +		rc = megasas_track_scsiio(instance, id, channel);
> +		instance->instancet->enable_intr(instance);
> +
> +		break;
> +	case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:
> +	case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK:
> +		break;
> +	default:
> +		rc = FAILED;
> +		break;
> +	}
> +
> +	return rc;
> +
> +}
> +
> +/*
> + * megasas_fusion_smid_lookup : Look for fusion command correpspodning to SCSI
> + * @instance: per adapter struct
> + *
> + * Return Non Zero index, if SMID found in outstanding commands
> + */
> +static u16 megasas_fusion_smid_lookup(struct scsi_cmnd *scmd)
> +{
> +	int i, ret = 0;
> +	struct megasas_instance *instance;
> +	struct megasas_cmd_fusion *cmd_fusion;
> +	struct fusion_context *fusion;
> +
> +	instance = (struct megasas_instance *)scmd->device->host->hostdata;
> +
> +	fusion = instance->ctrl_context;
> +
> +	for (i = 0; i < instance->max_scsi_cmds; i++) {
> +		cmd_fusion = fusion->cmd_list[i];
> +		if (cmd_fusion->scmd && (cmd_fusion->scmd == scmd)) {
> +			scmd_printk(KERN_NOTICE, scmd, "Abort request is for"
> +				" SMID: %d\n", cmd_fusion->index);
> +			ret = cmd_fusion->index;
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +/*
> +* megasas_get_tm_devhandle - Get devhandle for TM request
> +* @sdev-		     OS provided scsi device
> +*
> +* Returns-		     devhandle/targetID of SCSI device
> +*/
> +static u16 megasas_get_tm_devhandle(struct scsi_device *sdev)
> +{
> +	u16 pd_index = 0;
> +	u32 device_id;
> +	struct megasas_instance *instance;
> +	struct fusion_context *fusion;
> +	struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync;
> +	u16 devhandle = (u16)ULONG_MAX;
> +
> +	instance = (struct megasas_instance *)sdev->host->hostdata;
> +	fusion = instance->ctrl_context;
> +
> +	if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
> +		if (instance->use_seqnum_jbod_fp) {
> +				pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
> +						sdev->id;
> +				pd_sync = (void *)fusion->pd_seq_sync
> +						[(instance->pd_seq_map_id - 1) & 1];
> +				devhandle = pd_sync->seq[pd_index].devHandle;
> +		} else
> +			sdev_printk(KERN_ERR, sdev, "Firmware expose tmCapable"
> +				" without JBOD MAP support from %s %d\n", __func__, __LINE__);
> +	} else {
> +		device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL)
> +				+ sdev->id;
> +		devhandle = device_id;
> +	}
> +
> +	return devhandle;
> +}
> +
> +/*
> + * megasas_task_abort_fusion : SCSI task abort function for fusion adapters
> + * @scmd : pointer to scsi command object
> + *
> + * Return SUCCESS, if command aborted else FAILED
> + */
> +
> +int megasas_task_abort_fusion(struct scsi_cmnd *scmd)
> +{
> +	struct megasas_instance *instance;
> +	u16 smid, devhandle;
> +	struct fusion_context *fusion;
> +	int ret;
> +	struct MR_PRIV_DEVICE *mr_device_priv_data;
> +	mr_device_priv_data = scmd->device->hostdata;
> +
> +
> +	instance = (struct megasas_instance *)scmd->device->host->hostdata;
> +	fusion = instance->ctrl_context;
> +
> +	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
> +		dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL,"
> +		"SCSI host:%d\n", instance->host->host_no);
> +		ret = FAILED;
> +		return ret;
> +	}
> +
> +	if (!mr_device_priv_data) {
> +		sdev_printk(KERN_INFO, scmd->device, "device been deleted! "
> +			"scmd(%p)\n", scmd);
> +		scmd->result = DID_NO_CONNECT << 16;
> +		scmd->scsi_done(scmd);

Device has been deleted doesn't that imply that all commands had to be before
finished - so you should not call scsi_done ?

> +		ret = SUCCESS;
> +		goto out;
> +	}
> +
> +
> +	if (!mr_device_priv_data->is_tm_capable) {
> +		scmd->result = DID_RESET << 16;

I think that setting scmd->result makes no sense here (too)
a FAILED return should be enough. 

> +		ret = FAILED;
> +		goto out;
> +	}
> +
> +	mutex_lock(&instance->reset_mutex);
> +
> +	smid = megasas_fusion_smid_lookup(scmd);
> +
> +	if (!smid) {
> +		scmd->result = DID_RESET << 16;

I think that setting scmd->result makes no sense here (too)
a SUCCESS return should be enough. 

> +		ret = SUCCESS;
> +		scmd_printk(KERN_NOTICE, scmd, "Command for which abort is"
> +			" issued is not found in oustanding commands\n");
> +		mutex_unlock(&instance->reset_mutex);
> +		goto out;
> +	}
> +
> +	devhandle = megasas_get_tm_devhandle(scmd->device);
> +
> +	if (devhandle == (u16)ULONG_MAX) {
> +		scmd->result = DID_RESET << 16;

same here and on other places 

> +		ret = SUCCESS;
> +		sdev_printk(KERN_INFO, scmd->device,
> +			"task abort issued for invalid devhandle\n");
> +		mutex_unlock(&instance->reset_mutex);
> +		goto out;
> +	}
> +	sdev_printk(KERN_INFO, scmd->device,
> +		"attempting task abort! scmd(%p) tm_dev_handle 0x%x\n",
> +		scmd, devhandle);
> +
> +	mr_device_priv_data->tm_busy = 1;
> +	ret = megasas_issue_tm(instance, devhandle,
> +			scmd->device->channel, scmd->device->id, smid,
> +			MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
> +	mr_device_priv_data->tm_busy = 0;
> +
> +	mutex_unlock(&instance->reset_mutex);
> +out:
> +	sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n",
> +			((ret == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
> +
> +	return ret;
> +}
> +
> +/*
> + * megasas_reset_target_fusion : target reset function for fusion adapters
> + * scmd: SCSI command pointer
> + *
> + * Returns SUCCESS if all commands associated with target aborted else FAILED
> + */
> +
> +int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
> +{
> +
> +	struct megasas_instance *instance;
> +	int ret = FAILED;
> +	u16 devhandle;
> +	struct fusion_context *fusion;
> +	struct MR_PRIV_DEVICE *mr_device_priv_data;
> +	mr_device_priv_data = scmd->device->hostdata;
> +
> +	instance = (struct megasas_instance *)scmd->device->host->hostdata;
> +	fusion = instance->ctrl_context;
> +
> +	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
> +		dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL,"
> +		"SCSI host:%d\n", instance->host->host_no);
> +		ret = FAILED;
> +		return ret;
> +	}
> +
> +	if (!mr_device_priv_data) {
> +		sdev_printk(KERN_INFO, scmd->device, "device been deleted! "
> +			"scmd(%p)\n", scmd);
> +		scmd->result = DID_NO_CONNECT << 16;
> +		scmd->scsi_done(scmd);
> +		ret = SUCCESS;
> +		goto out;
> +	}
> +
> +
> +	if (!mr_device_priv_data->is_tm_capable) {
> +		scmd->result = DID_RESET << 16;
> +		ret = FAILED;
> +		goto out;
> +	}
> +
> +	mutex_lock(&instance->reset_mutex);
> +	devhandle = megasas_get_tm_devhandle(scmd->device);
> +
> +	if (devhandle == (u16)ULONG_MAX) {
> +		scmd->result = DID_RESET << 16;
> +		ret = SUCCESS;
> +		sdev_printk(KERN_INFO, scmd->device,
> +			"target reset issued for invalid devhandle\n");
> +		mutex_unlock(&instance->reset_mutex);
> +		goto out;
> +	}
> +
> +	sdev_printk(KERN_INFO, scmd->device,
> +		"attempting target reset! scmd(%p) tm_dev_handle 0x%x\n",
> +		scmd, devhandle);
> +	mr_device_priv_data->tm_busy = 1;
> +	ret = megasas_issue_tm(instance, devhandle,
> +			scmd->device->channel, scmd->device->id, 0,
> +			MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET);
> +	mr_device_priv_data->tm_busy = 0;
> +	mutex_unlock(&instance->reset_mutex);
> +out:
> +	scmd_printk(KERN_NOTICE, scmd, "megasas: target reset %s!!\n",
> +		(ret == SUCCESS) ? "SUCCESS" : "FAILED");
> +
> +	return ret;
> +}
> +
>  /* Check for a second path that is currently UP */
>  int megasas_check_mpio_paths(struct megasas_instance *instance,
>  	struct scsi_cmnd *scmd)
> @@ -2752,7 +3215,7 @@ out:
>  }
>  
>  /* Core fusion reset function */
> -int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
> +int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
>  {
>  	int retval = SUCCESS, i, convert = 0;
>  	struct megasas_instance *instance;
> @@ -2761,6 +3224,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
>  	u32 abs_state, status_reg, reset_adapter;
>  	u32 io_timeout_in_crash_mode = 0;
>  	struct scsi_cmnd *scmd_local = NULL;
> +	struct scsi_device *sdev;
>  
>  	instance = (struct megasas_instance *)shost->hostdata;
>  	fusion = instance->ctrl_context;
> @@ -2779,8 +3243,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
>  
>  	/* IO timeout detected, forcibly put FW in FAULT state */
>  	if (abs_state != MFI_STATE_FAULT && instance->crash_dump_buf &&
> -		instance->crash_dump_app_support && iotimeout) {
> -		dev_info(&instance->pdev->dev, "IO timeout is detected, "
> +		instance->crash_dump_app_support && reason) {
> +		dev_info(&instance->pdev->dev, "IO/DCMD timeout is detected, "
>  			"forcibly FAULT Firmware\n");
>  		instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
>  		status_reg = readl(&instance->reg_set->doorbell);
> @@ -2819,13 +3283,13 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
>  	msleep(1000);
>  
>  	/* First try waiting for commands to complete */
> -	if (megasas_wait_for_outstanding_fusion(instance, iotimeout,
> +	if (megasas_wait_for_outstanding_fusion(instance, reason,
>  						&convert)) {
>  		instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
>  		dev_warn(&instance->pdev->dev, "resetting fusion "
>  		       "adapter scsi%d.\n", instance->host->host_no);
>  		if (convert)
> -			iotimeout = 0;
> +			reason = 0;
>  
>  		/* Now return commands back to the OS */
>  		for (i = 0 ; i < instance->max_scsi_cmds; i++) {
> @@ -2859,7 +3323,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
>  		}
>  
>  		/* Let SR-IOV VF & PF sync up if there was a HB failure */
> -		if (instance->requestorId && !iotimeout) {
> +		if (instance->requestorId && !reason) {
>  			msleep(MEGASAS_OCR_SETTLE_TIME_VF);
>  			/* Look for a late HB update after VF settle time */
>  			if (abs_state == MFI_STATE_OPERATIONAL &&
> @@ -2954,6 +3418,9 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
>  
>  			megasas_setup_jbod_map(instance);
>  
> +			shost_for_each_device(sdev, shost)
> +				megasas_update_sdev_properties(sdev);
> +
>  			clear_bit(MEGASAS_FUSION_IN_RESET,
>  				  &instance->reset_flags);
>  			instance->instancet->enable_intr(instance);
> diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
> index a9e10c4..a1f1c0b 100644
> --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
> +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
> @@ -176,6 +176,7 @@ enum REGION_TYPE {
>  #define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD           (0x0100)
>  #define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP             (0x0004)
>  #define MPI2_FUNCTION_SCSI_IO_REQUEST               (0x00) /* SCSI IO */
> +#define MPI2_FUNCTION_SCSI_TASK_MGMT                (0x01)
>  #define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY       (0x03)
>  #define MPI2_REQ_DESCRIPT_FLAGS_FP_IO               (0x06)
>  #define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO                 (0x00)
> @@ -278,6 +279,100 @@ union MPI2_SCSI_IO_CDB_UNION {
>  	struct MPI2_SGE_SIMPLE_UNION SGE;
>  };
>  
> +/****************************************************************************
> +*  SCSI Task Management messages
> +****************************************************************************/
> +
> +/*SCSI Task Management Request Message */
> +struct MPI2_SCSI_TASK_MANAGE_REQUEST {
> +	u16 DevHandle;		/*0x00 */
> +	u8 ChainOffset;		/*0x02 */
> +	u8 Function;		/*0x03 */
> +	u8 Reserved1;		/*0x04 */
> +	u8 TaskType;		/*0x05 */
> +	u8 Reserved2;		/*0x06 */
> +	u8 MsgFlags;		/*0x07 */
> +	u8 VP_ID;		/*0x08 */
> +	u8 VF_ID;		/*0x09 */
> +	u16 Reserved3;		/*0x0A */
> +	u8 LUN[8];		/*0x0C */
> +	u32 Reserved4[7];	/*0x14 */
> +	u16 TaskMID;		/*0x30 */
> +	u16 Reserved5;		/*0x32 */
> +};
> +
> +
> +/*SCSI Task Management Reply Message */
> +struct MPI2_SCSI_TASK_MANAGE_REPLY {
> +	u16 DevHandle;		/*0x00 */
> +	u8 MsgLength;		/*0x02 */
> +	u8 Function;		/*0x03 */
> +	u8 ResponseCode;	/*0x04 */
> +	u8 TaskType;		/*0x05 */
> +	u8 Reserved1;		/*0x06 */
> +	u8 MsgFlags;		/*0x07 */
> +	u8 VP_ID;		/*0x08 */
> +	u8 VF_ID;		/*0x09 */
> +	u16 Reserved2;		/*0x0A */
> +	u16 Reserved3;		/*0x0C */
> +	u16 IOCStatus;		/*0x0E */
> +	u32 IOCLogInfo;		/*0x10 */
> +	u32 TerminationCount;	/*0x14 */
> +	u32 ResponseInfo;	/*0x18 */
> +};
> +
> +struct MR_TM_REQUEST {
> +	char request[128];
> +};
> +
> +struct MR_TM_REPLY {
> +	char reply[128];
> +};
> +
> +/* SCSI Task Management Request Message */
> +struct MR_TASK_MANAGE_REQUEST {
> +	/*To be type casted to struct MPI2_SCSI_TASK_MANAGE_REQUEST */
> +	struct MR_TM_REQUEST         TmRequest;
> +	union {
> +		struct {
> +#if   defined(__BIG_ENDIAN_BITFIELD)
> +			u32 reserved1:30;
> +			u32 isTMForPD:1;
> +			u32 isTMForLD:1;
> +#else
> +			u32 isTMForLD:1;
> +			u32 isTMForPD:1;
> +			u32 reserved1:30;
> +#endif
> +			u32 reserved2;
> +		} tmReqFlags;
> +		struct MR_TM_REPLY   TMReply;
> +	};
> +};
> +
> +/* TaskType values */
> +
> +#define MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK           (0x01)
> +#define MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET        (0x02)
> +#define MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET         (0x03)
> +#define MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET   (0x05)
> +#define MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET       (0x06)
> +#define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK           (0x07)
> +#define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA              (0x08)
> +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET         (0x09)
> +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT      (0x0A)
> +
> +/* ResponseCode values */
> +
> +#define MPI2_SCSITASKMGMT_RSP_TM_COMPLETE               (0x00)
> +#define MPI2_SCSITASKMGMT_RSP_INVALID_FRAME             (0x02)
> +#define MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED          (0x04)
> +#define MPI2_SCSITASKMGMT_RSP_TM_FAILED                 (0x05)
> +#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED              (0x08)
> +#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN            (0x09)
> +#define MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG         (0x0A)
> +#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC          (0x80)
> +
>  /*
>   * RAID SCSI IO Request Message
>   * Total SGE count will be one less than  _MPI2_SCSI_IO_REQUEST
> @@ -548,7 +643,8 @@ struct MR_SPAN_BLOCK_INFO {
>  struct MR_LD_RAID {
>  	struct {
>  #if   defined(__BIG_ENDIAN_BITFIELD)
> -		u32     reserved4:7;
> +		u32     reserved4:6;
> +		u32     tmCapable:1;
>  		u32	fpNonRWCapable:1;
>  		u32     fpReadAcrossStripe:1;
>  		u32     fpWriteAcrossStripe:1;
> @@ -570,7 +666,8 @@ struct MR_LD_RAID {
>  		u32     fpWriteAcrossStripe:1;
>  		u32     fpReadAcrossStripe:1;
>  		u32	fpNonRWCapable:1;
> -		u32     reserved4:7;
> +		u32     tmCapable:1;
> +		u32     reserved4:6;
>  #endif
>  	} capability;
>  	__le32     reserved6;
> @@ -695,6 +792,7 @@ struct megasas_cmd_fusion {
>  	u32 sync_cmd_idx;
>  	u32 index;
>  	u8 pd_r1_lb;
> +	struct completion done;
>  };
>  
>  struct LD_LOAD_BALANCE_INFO {
> @@ -808,9 +906,18 @@ struct MR_FW_RAID_MAP_EXT {
>   *  * define MR_PD_CFG_SEQ structure for system PDs
>   *   */
>  struct MR_PD_CFG_SEQ {
> -	__le16 seqNum;
> -	__le16 devHandle;
> -	u8  reserved[4];
> +	u16 seqNum;
> +	u16 devHandle;
> +	struct {
> +#if   defined(__BIG_ENDIAN_BITFIELD)
> +		u8     reserved:7;
> +		u8     tmCapable:1;
> +#else
> +		u8     tmCapable:1;
> +		u8     reserved:7;
> +#endif
> +	} capability;
> +	u8  reserved[3];
>  } __packed;
>  
>  struct MR_PD_CFG_SEQ_NUM_SYNC {


^ permalink raw reply	[flat|nested] 50+ messages in thread

* RE: [PATCH 15/15] megaraid_sas: SPERC boot driver reorder
  2015-12-18 14:05   ` Christoph Hellwig
  2016-01-08  7:07     ` Sumit Saxena
@ 2016-01-12  5:26     ` Sumit Saxena
  1 sibling, 0 replies; 50+ messages in thread
From: Sumit Saxena @ 2016-01-12  5:26 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: jbottomley, martin.petersen, linux-scsi, Kashyap Desai, Uday Lingala

> -----Original Message-----
> From: Sumit Saxena [mailto:sumit.saxena@avagotech.com]
> Sent: Friday, January 08, 2016 12:37 PM
> To: 'Christoph Hellwig'
> Cc: 'jbottomley@parallels.com'; 'martin.petersen@oracle.com'; 'linux-
> scsi@vger.kernel.org'; Kashyap Desai; Uday Lingala
> Subject: RE: [PATCH 15/15] megaraid_sas: SPERC boot driver reorder
>
>
>
> > -----Original Message-----
> > From: Christoph Hellwig [mailto:hch@infradead.org]
> > Sent: Friday, December 18, 2015 7:35 PM
> > To: Sumit Saxena
> > Cc: jbottomley@parallels.com; hch@infradead.org;
> > martin.petersen@oracle.com; linux-scsi@vger.kernel.org;
> > kashyap.desai@avagotech.com; Uday Lingala
> > Subject: Re: [PATCH 15/15] megaraid_sas: SPERC boot driver reorder
> >
> > On Fri, Dec 18, 2015 at 06:57:08PM +0530, Sumit Saxena wrote:
> > > This patch will add support for drive ordering for a particular set
> > > of device ID
> > (0x005D, 0x005F) & subsystem vendor ID(0x1028).
> >
> > This really has no business in Linux.  Everyone should be using uuid
> > based disk addressing if they care.  Tell Dell they should stop coming
> > up with this crap, as they keep leaking this weird ordering things in
again and
> again.
>
> This patch can be ignored. We discussed with Dell on this and they are
fine to
> backout the patch.
> Can you provide any feedback on rest of the patches?

Gentle reminder..

>
> Thanks,
> Sumit

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 05/15] megaraid_sas: Update device Queue depth based on interface type
  2015-12-18 13:26 ` [PATCH 05/15] megaraid_sas: Update device Queue depth based on interface type Sumit Saxena
@ 2016-01-12 14:16   ` Tomas Henzl
  2016-01-14 11:48     ` Sumit Saxena
  0 siblings, 1 reply; 50+ messages in thread
From: Tomas Henzl @ 2016-01-12 14:16 UTC (permalink / raw)
  To: Sumit Saxena, jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai

On 18.12.2015 14:26, Sumit Saxena wrote:
> This patch will update device Queue depth based on interface type(SAS, SATA..) for sysPDs.
> For Virtual disks(VDs), there will be no change in queue depth(will remain 256).
> To fetch interface type(SAS or SATA or FC..) of syspD, driver will send DCMD MR_DCMD_PD_GET_INFO per sysPD.
>
> Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
> Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
>
> ---
>  drivers/scsi/megaraid/megaraid_sas.h      |  270 ++++++++++++++++++++++++++++-
>  drivers/scsi/megaraid/megaraid_sas_base.c |  127 ++++++++++++++
>  2 files changed, 396 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
> index 0fcb156..773fc54 100644
> --- a/drivers/scsi/megaraid/megaraid_sas.h
> +++ b/drivers/scsi/megaraid/megaraid_sas.h
> @@ -215,6 +215,7 @@
>  
>  #define MR_DCMD_CTRL_SET_CRASH_DUMP_PARAMS	0x01190100
>  #define MR_DRIVER_SET_APP_CRASHDUMP_MODE	(0xF0010000 | 0x0600)
> +#define MR_DCMD_PD_GET_INFO			0x02020000
>  
>  /*
>   * Global functions
> @@ -435,6 +436,257 @@ enum MR_PD_STATE {
>  	MR_PD_STATE_SYSTEM              = 0x40,
>   };
>  
> +union MR_PD_REF {
> +	struct {
> +		u16	 deviceId;
> +		u16	 seqNum;
> +	} mrPdRef;
> +	u32	 ref;
> +};
> +
> +/*
> + * define the DDF Type bit structure
> + */
> +union MR_PD_DDF_TYPE {
> +	 struct {
> +		union {
> +			struct {
> +#ifndef __BIG_ENDIAN_BITFIELD
> +				 u16	 forcedPDGUID:1;
> +				 u16	 inVD:1;
> +				 u16	 isGlobalSpare:1;
> +				 u16	 isSpare:1;
> +				 u16	 isForeign:1;
> +				 u16	 reserved:7;
> +				 u16	 intf:4;
> +#else
> +				 u16	 intf:4;
> +				 u16	 reserved:7;
> +				 u16	 isForeign:1;
> +				 u16	 isSpare:1;
> +				 u16	 isGlobalSpare:1;
> +				 u16	 inVD:1;
> +				 u16	 forcedPDGUID:1;
> +#endif
> +			 } pdType;
> +			 u16	 type;
> +		 };
> +		 u16	 reserved;
> +	 } ddf;
> +	 struct {
> +		 u32	reserved;
> +	 } nonDisk;
> +	 u32	 type;
> +} __packed;
> +
> +/*
> + * defines the progress structure
> + */
> +union MR_PROGRESS {
> +	struct  {
> +		u16 progress;
> +		union {
> +			u16 elapsedSecs;
> +			u16 elapsedSecsForLastPercent;
> +		};
> +	} mrProgress;
> +	u32 w;
> +} __packed;
> +
> +/*
> + * defines the physical drive progress structure
> + */
> +struct MR_PD_PROGRESS {
> +	struct {
> +#ifndef MFI_BIG_ENDIAN
> +		u32     rbld:1;
> +		u32     patrol:1;
> +		u32     clear:1;
> +		u32     copyBack:1;
> +		u32     erase:1;
> +		u32     locate:1;
> +		u32     reserved:26;
> +#else
> +		u32     reserved:26;
> +		u32     locate:1;
> +		u32     erase:1;
> +		u32     copyBack:1;
> +		u32     clear:1;
> +		u32     patrol:1;
> +		u32     rbld:1;
> +#endif
> +	} active;
> +	union MR_PROGRESS     rbld;
> +	union MR_PROGRESS     patrol;
> +	union {
> +		union MR_PROGRESS     clear;
> +		union MR_PROGRESS     erase;
> +	};
> +
> +	struct {
> +#ifndef MFI_BIG_ENDIAN
> +		u32     rbld:1;
> +		u32     patrol:1;
> +		u32     clear:1;
> +		u32     copyBack:1;
> +		u32     erase:1;
> +		u32     reserved:27;
> +#else
> +		u32     reserved:27;
> +		u32     erase:1;
> +		u32     copyBack:1;
> +		u32     clear:1;
> +		u32     patrol:1;
> +		u32     rbld:1;
> +#endif
> +	} pause;
> +
> +	union MR_PROGRESS     reserved[3];
> +} __packed;
> +
> +struct  MR_PD_INFO {
> +	union MR_PD_REF	ref;
> +	u8 inquiryData[96];
> +	u8 vpdPage83[64];
> +	u8 notSupported;
> +	u8 scsiDevType;
> +
> +	union {
> +		u8 connectedPortBitmap;
> +		u8 connectedPortNumbers;
> +	};
> +
> +	u8 deviceSpeed;
> +	u32 mediaErrCount;
> +	u32 otherErrCount;
> +	u32 predFailCount;
> +	u32 lastPredFailEventSeqNum;
> +
> +	u16 fwState;
> +	u8 disabledForRemoval;
> +	u8 linkSpeed;
> +	union MR_PD_DDF_TYPE state;
> +
> +	struct {
> +		u8 count;
> +#ifndef __BIG_ENDIAN_BITFIELD
> +		u8 isPathBroken:4;
> +		u8 reserved3:3;
> +		u8 widePortCapable:1;
> +#else
> +		u8 widePortCapable:1;
> +		u8 reserved3:3;
> +		u8 isPathBroken:4;
> +#endif
> +
> +		u8 connectorIndex[2];
> +		u8 reserved[4];
> +		u64 sasAddr[2];
> +		u8 reserved2[16];
> +	} pathInfo;
> +
> +	u64 rawSize;
> +	u64 nonCoercedSize;
> +	u64 coercedSize;
> +	u16 enclDeviceId;
> +	u8 enclIndex;
> +
> +	union {
> +		u8 slotNumber;
> +		u8 enclConnectorIndex;
> +	};
> +
> +	struct MR_PD_PROGRESS progInfo;
> +	u8 badBlockTableFull;
> +	u8 unusableInCurrentConfig;
> +	u8 vpdPage83Ext[64];
> +	u8 powerState;
> +	u8 enclPosition;
> +	u32 allowedOps;
> +	u16 copyBackPartnerId;
> +	u16 enclPartnerDeviceId;
> +	struct {
> +#ifndef __BIG_ENDIAN_BITFIELD
> +		u16 fdeCapable:1;
> +		u16 fdeEnabled:1;
> +		u16 secured:1;
> +		u16 locked:1;
> +		u16 foreign:1;
> +		u16 needsEKM:1;
> +		u16 reserved:10;
> +#else
> +		u16 reserved:10;
> +		u16 needsEKM:1;
> +		u16 foreign:1;
> +		u16 locked:1;
> +		u16 secured:1;
> +		u16 fdeEnabled:1;
> +		u16 fdeCapable:1;
> +#endif
> +	} security;
> +	u8 mediaType;
> +	u8 notCertified;
> +	u8 bridgeVendor[8];
> +	u8 bridgeProductIdentification[16];
> +	u8 bridgeProductRevisionLevel[4];
> +	u8 satBridgeExists;
> +
> +	u8 interfaceType;
> +	u8 temperature;
> +	u8 emulatedBlockSize;
> +	u16 userDataBlockSize;
> +	u16 reserved2;
> +
> +	struct {
> +#ifndef __BIG_ENDIAN_BITFIELD
> +		u32 piType:3;
> +		u32 piFormatted:1;
> +		u32 piEligible:1;
> +		u32 NCQ:1;
> +		u32 WCE:1;
> +		u32 commissionedSpare:1;
> +		u32 emergencySpare:1;
> +		u32 ineligibleForSSCD:1;
> +		u32 ineligibleForLd:1;
> +		u32 useSSEraseType:1;
> +		u32 wceUnchanged:1;
> +		u32 supportScsiUnmap:1;
> +		u32 reserved:18;
> +#else
> +		u32 reserved:18;
> +		u32 supportScsiUnmap:1;
> +		u32 wceUnchanged:1;
> +		u32 useSSEraseType:1;
> +		u32 ineligibleForLd:1;
> +		u32 ineligibleForSSCD:1;
> +		u32 emergencySpare:1;
> +		u32 commissionedSpare:1;
> +		u32 WCE:1;
> +		u32 NCQ:1;
> +		u32 piEligible:1;
> +		u32 piFormatted:1;
> +		u32 piType:3;
> +#endif
> +	} properties;
> +
> +	u64 shieldDiagCompletionTime;
> +	u8 shieldCounter;
> +
> +	u8 linkSpeedOther;
> +	u8 reserved4[2];
> +
> +	struct {
> +#ifndef __BIG_ENDIAN_BITFIELD
> +		u32 bbmErrCountSupported:1;
> +		u32 bbmErrCount:31;
> +#else
> +		u32 bbmErrCount:31;
> +		u32 bbmErrCountSupported:1;
> +#endif
> +	} bbmErr;
> +
> +	u8 reserved1[512-428];
> +} __packed;
>  
>   /*
>   * defines the physical drive address structure
> @@ -474,6 +726,7 @@ struct megasas_pd_list {
>  	u16             tid;
>  	u8             driveType;
>  	u8             driveState;
> +	u8             interface;
>  } __packed;
>  
>   /*
> @@ -1718,6 +1971,19 @@ struct MR_DRV_SYSTEM_INFO {
>  	u8	reserved[1980];
>  };
>  
> +enum MR_PD_TYPE {
> +		 UNKNOWN_DRIVE = 0,
> +		 PARALLEL_SCSI = 1,
> +		 SAS_PD = 2,
> +		 SATA_PD = 3,
> +		 FC_PD = 4,
> +};
> +
> +/* JBOD Queue depth definitions */
> +#define MEGASAS_SATA_QD	32
> +#define MEGASAS_SAS_QD	64
> +#define MEGASAS_DEFAULT_PD_QD	64
> +
>  struct megasas_instance {
>  
>  	__le32 *producer;
> @@ -1732,6 +1998,8 @@ struct megasas_instance {
>  	dma_addr_t vf_affiliation_111_h;
>  	struct MR_CTRL_HB_HOST_MEM *hb_host_mem;
>  	dma_addr_t hb_host_mem_h;
> +	struct MR_PD_INFO *pd_info;
> +	dma_addr_t pd_info_h;
>  
>  	__le32 *reply_queue;
>  	dma_addr_t reply_queue_h;
> @@ -1780,7 +2048,7 @@ struct megasas_instance {
>  	struct megasas_evt_detail *evt_detail;
>  	dma_addr_t evt_detail_h;
>  	struct megasas_cmd *aen_cmd;
> -	struct mutex aen_mutex;
> +	struct mutex hba_mutex;
>  	struct semaphore ioctl_sem;
>  
>  	struct Scsi_Host *host;
> diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
> index c1dc23c..df93fa1 100644
> --- a/drivers/scsi/megaraid/megaraid_sas_base.c
> +++ b/drivers/scsi/megaraid/megaraid_sas_base.c
> @@ -104,6 +104,8 @@ static int megasas_ld_list_query(struct megasas_instance *instance,
>  static int megasas_issue_init_mfi(struct megasas_instance *instance);
>  static int megasas_register_aen(struct megasas_instance *instance,
>  				u32 seq_num, u32 class_locale_word);
> +static int
> +megasas_get_pd_info(struct megasas_instance *instance, u16 device_id);
>  /*
>   * PCI ID table for all supported controllers
>   */
> @@ -1796,6 +1798,44 @@ void megasas_update_sdev_properties(struct scsi_device *sdev)
>  	}
>  }
>  
> +static void megasas_set_device_queue_depth(struct scsi_device *sdev)
> +{
> +	u16				pd_index = 0;
> +	int		ret = DCMD_FAILED;
> +	struct megasas_instance *instance;
> +
> +	instance = megasas_lookup_instance(sdev->host->host_no);
> +
> +	if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
> +		pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id;
> +
> +		if (instance->pd_info) {
> +			mutex_lock(&instance->hba_mutex);
> +			ret = megasas_get_pd_info(instance, pd_index);
> +			mutex_unlock(&instance->hba_mutex);
> +		}
> +
> +		if (ret != DCMD_SUCCESS)
> +			return;
> +
> +		if (instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) {
> +
> +			switch (instance->pd_list[pd_index].interface) {
> +			case SAS_PD:
> +				scsi_change_queue_depth(sdev, MEGASAS_SAS_QD);
> +				break;
> +
> +			case SATA_PD:
> +				scsi_change_queue_depth(sdev, MEGASAS_SATA_QD);
> +				break;
> +
> +			default:
> +				scsi_change_queue_depth(sdev, MEGASAS_DEFAULT_PD_QD);
> +			}
> +		}
> +	}
> +}
> +
>  
>  static int megasas_slave_configure(struct scsi_device *sdev)
>  {
> @@ -1813,6 +1853,7 @@ static int megasas_slave_configure(struct scsi_device *sdev)
>  				return -ENXIO;
>  		}
>  	}
> +	megasas_set_device_queue_depth(sdev);
>  	megasas_update_sdev_properties(sdev);
>  
>  	/*
> @@ -3922,6 +3963,73 @@ dcmd_timeout_ocr_possible(struct megasas_instance *instance) {
>  		return INITIATE_OCR;
>  }
>  
> +static int
> +megasas_get_pd_info(struct megasas_instance *instance, u16 device_id)
> +{
> +	int ret;
> +	struct megasas_cmd *cmd;
> +	struct megasas_dcmd_frame *dcmd;
> +
> +	cmd = megasas_get_cmd(instance);
> +
> +	if (!cmd) {
> +		dev_err(&instance->pdev->dev, "Failed to get cmd %s\n", __func__);
> +		return -ENOMEM;
> +	}
> +
> +	dcmd = &cmd->frame->dcmd;
> +
> +	memset(instance->pd_info, 0, sizeof(*instance->pd_info));
> +	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
> +
> +	dcmd->mbox.s[0] = cpu_to_le16(device_id);
> +	dcmd->cmd = MFI_CMD_DCMD;
> +	dcmd->cmd_status = 0xFF;
> +	dcmd->sge_count = 1;
> +	dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ);
> +	dcmd->timeout = 0;
> +	dcmd->pad_0 = 0;
> +	dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_PD_INFO));
> +	dcmd->opcode = cpu_to_le32(MR_DCMD_PD_GET_INFO);
> +	dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(instance->pd_info_h);
> +	dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct MR_PD_INFO));
> +
> +	if (instance->ctrl_context && !instance->mask_interrupts)
> +		ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
> +	else
> +		ret = megasas_issue_polled(instance, cmd);
> +
> +	switch (ret) {
> +	case DCMD_SUCCESS:
> +		instance->pd_list[device_id].interface =
> +				instance->pd_info->state.ddf.pdType.intf;
> +		break;
> +
> +	case DCMD_TIMEOUT:
> +
> +		switch (dcmd_timeout_ocr_possible(instance)) {
> +		case INITIATE_OCR:
> +			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
> +			megasas_reset_fusion(instance->host,
> +				MFI_IO_TIMEOUT_OCR);
> +			break;
> +		case KILL_ADAPTER:
> +			megaraid_sas_kill_hba(instance);
> +			break;
> +		case IGNORE_TIMEOUT:
> +			dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
> +				__func__, __LINE__);
> +			break;
> +		}
> +
> +		break;
> +	}
> +
> +	if (ret != DCMD_TIMEOUT)
> +		megasas_return_cmd(instance, cmd);
> +
> +	return ret;
> +}
>  /*
>   * megasas_get_pd_list_info -	Returns FW's pd_list structure
>   * @instance:				Adapter soft state
> @@ -5680,6 +5788,12 @@ static int megasas_probe_one(struct pci_dev *pdev,
>  		goto fail_alloc_dma_buf;
>  	}
>  
> +	instance->pd_info = pci_alloc_consistent(pdev,
> +		sizeof(struct MR_PD_INFO), &instance->pd_info_h);

Hi,
is it possible to use here 'dma_alloc_coherent + GFP_KERNEL' 
instead of pci_alloc_consistent with GFP_ATOMIC ?
--tm

> +
> +	if (!instance->pd_info)
> +		dev_err(&instance->pdev->dev, "Failed to alloc mem for pd_info\n");
> +
>  	/*
>  	 * Initialize locks and queues
>  	 */
> @@ -5696,6 +5810,7 @@ static int megasas_probe_one(struct pci_dev *pdev,
>  	spin_lock_init(&instance->completion_lock);
>  
>  	mutex_init(&instance->reset_mutex);
> +	mutex_init(&instance->hba_mutex);
>  
>  	/*
>  	 * Initialize PCI related and misc parameters
> @@ -5810,6 +5925,10 @@ fail_alloc_dma_buf:
>  				    instance->evt_detail,
>  				    instance->evt_detail_h);
>  
> +	if (instance->pd_info)
> +		pci_free_consistent(pdev, sizeof(struct MR_PD_INFO),
> +					instance->pd_info,
> +					instance->pd_info_h);
>  	if (instance->producer)
>  		pci_free_consistent(pdev, sizeof(u32), instance->producer,
>  				    instance->producer_h);
> @@ -6071,6 +6190,10 @@ fail_init_mfi:
>  				instance->evt_detail,
>  				instance->evt_detail_h);
>  
> +	if (instance->pd_info)
> +		pci_free_consistent(pdev, sizeof(struct MR_PD_INFO),
> +					instance->pd_info,
> +					instance->pd_info_h);
>  	if (instance->producer)
>  		pci_free_consistent(pdev, sizeof(u32), instance->producer,
>  				instance->producer_h);
> @@ -6189,6 +6312,10 @@ static void megasas_detach_one(struct pci_dev *pdev)
>  		pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
>  				instance->evt_detail, instance->evt_detail_h);
>  
> +	if (instance->pd_info)
> +		pci_free_consistent(pdev, sizeof(struct MR_PD_INFO),
> +					instance->pd_info,
> +					instance->pd_info_h);
>  	if (instance->vf_affiliation)
>  		pci_free_consistent(pdev, (MAX_LOGICAL_DRIVES + 1) *
>  				    sizeof(struct MR_LD_VF_AFFILIATION),


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 06/15] megaraid_sas: Fastpath region lock bypass
  2015-12-18 13:26 ` [PATCH 06/15] megaraid_sas: Fastpath region lock bypass Sumit Saxena
@ 2016-01-12 14:44   ` Tomas Henzl
  0 siblings, 0 replies; 50+ messages in thread
From: Tomas Henzl @ 2016-01-12 14:44 UTC (permalink / raw)
  To: Sumit Saxena, jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai

On 18.12.2015 14:26, Sumit Saxena wrote:
> Firmware will fill per LD data to tell driver that particular LD supports Region lock bypass or not. If yes, then 
> Driver will send non FP LDIO to region lock bypass FIFO. With this change in driver, firmware will optimize certain
> code to improve performance.
>
> Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
> Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>

Reviewed-by: Tomas Henzl <thenzl@redhat.com>

Tomas


^ permalink raw reply	[flat|nested] 50+ messages in thread

* RE: [PATCH 05/15] megaraid_sas: Update device Queue depth based on interface type
  2016-01-12 14:16   ` Tomas Henzl
@ 2016-01-14 11:48     ` Sumit Saxena
  0 siblings, 0 replies; 50+ messages in thread
From: Sumit Saxena @ 2016-01-14 11:48 UTC (permalink / raw)
  To: Tomas Henzl, jbottomley, hch, martin.petersen; +Cc: linux-scsi, Kashyap Desai

> -----Original Message-----
> From: Tomas Henzl [mailto:thenzl@redhat.com]
> Sent: Tuesday, January 12, 2016 7:47 PM
> To: Sumit Saxena; jbottomley@parallels.com; hch@infradead.org;
> martin.petersen@oracle.com
> Cc: linux-scsi@vger.kernel.org; kashyap.desai@avagotech.com
> Subject: Re: [PATCH 05/15] megaraid_sas: Update device Queue depth based
on
> interface type
>
> On 18.12.2015 14:26, Sumit Saxena wrote:
> > This patch will update device Queue depth based on interface type(SAS,
SATA..)
> for sysPDs.
> > For Virtual disks(VDs), there will be no change in queue depth(will
remain 256).
> > To fetch interface type(SAS or SATA or FC..) of syspD, driver will
send DCMD
> MR_DCMD_PD_GET_INFO per sysPD.
> >
> > Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
> > Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
> >
> > ---
> >  drivers/scsi/megaraid/megaraid_sas.h      |  270
> ++++++++++++++++++++++++++++-
> >  drivers/scsi/megaraid/megaraid_sas_base.c |  127 ++++++++++++++
> >  2 files changed, 396 insertions(+), 1 deletions(-)
> >
> > diff --git a/drivers/scsi/megaraid/megaraid_sas.h
> > b/drivers/scsi/megaraid/megaraid_sas.h
> > index 0fcb156..773fc54 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas.h
> > +++ b/drivers/scsi/megaraid/megaraid_sas.h
> > @@ -215,6 +215,7 @@
> >
> >  #define MR_DCMD_CTRL_SET_CRASH_DUMP_PARAMS	0x01190100
> >  #define MR_DRIVER_SET_APP_CRASHDUMP_MODE	(0xF0010000 | 0x0600)
> > +#define MR_DCMD_PD_GET_INFO			0x02020000
> >
> >  /*
> >   * Global functions
> > @@ -435,6 +436,257 @@ enum MR_PD_STATE {
> >  	MR_PD_STATE_SYSTEM              = 0x40,
> >   };
> >
> > +union MR_PD_REF {
> > +	struct {
> > +		u16	 deviceId;
> > +		u16	 seqNum;
> > +	} mrPdRef;
> > +	u32	 ref;
> > +};
> > +
> > +/*
> > + * define the DDF Type bit structure
> > + */
> > +union MR_PD_DDF_TYPE {
> > +	 struct {
> > +		union {
> > +			struct {
> > +#ifndef __BIG_ENDIAN_BITFIELD
> > +				 u16	 forcedPDGUID:1;
> > +				 u16	 inVD:1;
> > +				 u16	 isGlobalSpare:1;
> > +				 u16	 isSpare:1;
> > +				 u16	 isForeign:1;
> > +				 u16	 reserved:7;
> > +				 u16	 intf:4;
> > +#else
> > +				 u16	 intf:4;
> > +				 u16	 reserved:7;
> > +				 u16	 isForeign:1;
> > +				 u16	 isSpare:1;
> > +				 u16	 isGlobalSpare:1;
> > +				 u16	 inVD:1;
> > +				 u16	 forcedPDGUID:1;
> > +#endif
> > +			 } pdType;
> > +			 u16	 type;
> > +		 };
> > +		 u16	 reserved;
> > +	 } ddf;
> > +	 struct {
> > +		 u32	reserved;
> > +	 } nonDisk;
> > +	 u32	 type;
> > +} __packed;
> > +
> > +/*
> > + * defines the progress structure
> > + */
> > +union MR_PROGRESS {
> > +	struct  {
> > +		u16 progress;
> > +		union {
> > +			u16 elapsedSecs;
> > +			u16 elapsedSecsForLastPercent;
> > +		};
> > +	} mrProgress;
> > +	u32 w;
> > +} __packed;
> > +
> > +/*
> > + * defines the physical drive progress structure  */ struct
> > +MR_PD_PROGRESS {
> > +	struct {
> > +#ifndef MFI_BIG_ENDIAN
> > +		u32     rbld:1;
> > +		u32     patrol:1;
> > +		u32     clear:1;
> > +		u32     copyBack:1;
> > +		u32     erase:1;
> > +		u32     locate:1;
> > +		u32     reserved:26;
> > +#else
> > +		u32     reserved:26;
> > +		u32     locate:1;
> > +		u32     erase:1;
> > +		u32     copyBack:1;
> > +		u32     clear:1;
> > +		u32     patrol:1;
> > +		u32     rbld:1;
> > +#endif
> > +	} active;
> > +	union MR_PROGRESS     rbld;
> > +	union MR_PROGRESS     patrol;
> > +	union {
> > +		union MR_PROGRESS     clear;
> > +		union MR_PROGRESS     erase;
> > +	};
> > +
> > +	struct {
> > +#ifndef MFI_BIG_ENDIAN
> > +		u32     rbld:1;
> > +		u32     patrol:1;
> > +		u32     clear:1;
> > +		u32     copyBack:1;
> > +		u32     erase:1;
> > +		u32     reserved:27;
> > +#else
> > +		u32     reserved:27;
> > +		u32     erase:1;
> > +		u32     copyBack:1;
> > +		u32     clear:1;
> > +		u32     patrol:1;
> > +		u32     rbld:1;
> > +#endif
> > +	} pause;
> > +
> > +	union MR_PROGRESS     reserved[3];
> > +} __packed;
> > +
> > +struct  MR_PD_INFO {
> > +	union MR_PD_REF	ref;
> > +	u8 inquiryData[96];
> > +	u8 vpdPage83[64];
> > +	u8 notSupported;
> > +	u8 scsiDevType;
> > +
> > +	union {
> > +		u8 connectedPortBitmap;
> > +		u8 connectedPortNumbers;
> > +	};
> > +
> > +	u8 deviceSpeed;
> > +	u32 mediaErrCount;
> > +	u32 otherErrCount;
> > +	u32 predFailCount;
> > +	u32 lastPredFailEventSeqNum;
> > +
> > +	u16 fwState;
> > +	u8 disabledForRemoval;
> > +	u8 linkSpeed;
> > +	union MR_PD_DDF_TYPE state;
> > +
> > +	struct {
> > +		u8 count;
> > +#ifndef __BIG_ENDIAN_BITFIELD
> > +		u8 isPathBroken:4;
> > +		u8 reserved3:3;
> > +		u8 widePortCapable:1;
> > +#else
> > +		u8 widePortCapable:1;
> > +		u8 reserved3:3;
> > +		u8 isPathBroken:4;
> > +#endif
> > +
> > +		u8 connectorIndex[2];
> > +		u8 reserved[4];
> > +		u64 sasAddr[2];
> > +		u8 reserved2[16];
> > +	} pathInfo;
> > +
> > +	u64 rawSize;
> > +	u64 nonCoercedSize;
> > +	u64 coercedSize;
> > +	u16 enclDeviceId;
> > +	u8 enclIndex;
> > +
> > +	union {
> > +		u8 slotNumber;
> > +		u8 enclConnectorIndex;
> > +	};
> > +
> > +	struct MR_PD_PROGRESS progInfo;
> > +	u8 badBlockTableFull;
> > +	u8 unusableInCurrentConfig;
> > +	u8 vpdPage83Ext[64];
> > +	u8 powerState;
> > +	u8 enclPosition;
> > +	u32 allowedOps;
> > +	u16 copyBackPartnerId;
> > +	u16 enclPartnerDeviceId;
> > +	struct {
> > +#ifndef __BIG_ENDIAN_BITFIELD
> > +		u16 fdeCapable:1;
> > +		u16 fdeEnabled:1;
> > +		u16 secured:1;
> > +		u16 locked:1;
> > +		u16 foreign:1;
> > +		u16 needsEKM:1;
> > +		u16 reserved:10;
> > +#else
> > +		u16 reserved:10;
> > +		u16 needsEKM:1;
> > +		u16 foreign:1;
> > +		u16 locked:1;
> > +		u16 secured:1;
> > +		u16 fdeEnabled:1;
> > +		u16 fdeCapable:1;
> > +#endif
> > +	} security;
> > +	u8 mediaType;
> > +	u8 notCertified;
> > +	u8 bridgeVendor[8];
> > +	u8 bridgeProductIdentification[16];
> > +	u8 bridgeProductRevisionLevel[4];
> > +	u8 satBridgeExists;
> > +
> > +	u8 interfaceType;
> > +	u8 temperature;
> > +	u8 emulatedBlockSize;
> > +	u16 userDataBlockSize;
> > +	u16 reserved2;
> > +
> > +	struct {
> > +#ifndef __BIG_ENDIAN_BITFIELD
> > +		u32 piType:3;
> > +		u32 piFormatted:1;
> > +		u32 piEligible:1;
> > +		u32 NCQ:1;
> > +		u32 WCE:1;
> > +		u32 commissionedSpare:1;
> > +		u32 emergencySpare:1;
> > +		u32 ineligibleForSSCD:1;
> > +		u32 ineligibleForLd:1;
> > +		u32 useSSEraseType:1;
> > +		u32 wceUnchanged:1;
> > +		u32 supportScsiUnmap:1;
> > +		u32 reserved:18;
> > +#else
> > +		u32 reserved:18;
> > +		u32 supportScsiUnmap:1;
> > +		u32 wceUnchanged:1;
> > +		u32 useSSEraseType:1;
> > +		u32 ineligibleForLd:1;
> > +		u32 ineligibleForSSCD:1;
> > +		u32 emergencySpare:1;
> > +		u32 commissionedSpare:1;
> > +		u32 WCE:1;
> > +		u32 NCQ:1;
> > +		u32 piEligible:1;
> > +		u32 piFormatted:1;
> > +		u32 piType:3;
> > +#endif
> > +	} properties;
> > +
> > +	u64 shieldDiagCompletionTime;
> > +	u8 shieldCounter;
> > +
> > +	u8 linkSpeedOther;
> > +	u8 reserved4[2];
> > +
> > +	struct {
> > +#ifndef __BIG_ENDIAN_BITFIELD
> > +		u32 bbmErrCountSupported:1;
> > +		u32 bbmErrCount:31;
> > +#else
> > +		u32 bbmErrCount:31;
> > +		u32 bbmErrCountSupported:1;
> > +#endif
> > +	} bbmErr;
> > +
> > +	u8 reserved1[512-428];
> > +} __packed;
> >
> >   /*
> >   * defines the physical drive address structure @@ -474,6 +726,7 @@
> > struct megasas_pd_list {
> >  	u16             tid;
> >  	u8             driveType;
> >  	u8             driveState;
> > +	u8             interface;
> >  } __packed;
> >
> >   /*
> > @@ -1718,6 +1971,19 @@ struct MR_DRV_SYSTEM_INFO {
> >  	u8	reserved[1980];
> >  };
> >
> > +enum MR_PD_TYPE {
> > +		 UNKNOWN_DRIVE = 0,
> > +		 PARALLEL_SCSI = 1,
> > +		 SAS_PD = 2,
> > +		 SATA_PD = 3,
> > +		 FC_PD = 4,
> > +};
> > +
> > +/* JBOD Queue depth definitions */
> > +#define MEGASAS_SATA_QD	32
> > +#define MEGASAS_SAS_QD	64
> > +#define MEGASAS_DEFAULT_PD_QD	64
> > +
> >  struct megasas_instance {
> >
> >  	__le32 *producer;
> > @@ -1732,6 +1998,8 @@ struct megasas_instance {
> >  	dma_addr_t vf_affiliation_111_h;
> >  	struct MR_CTRL_HB_HOST_MEM *hb_host_mem;
> >  	dma_addr_t hb_host_mem_h;
> > +	struct MR_PD_INFO *pd_info;
> > +	dma_addr_t pd_info_h;
> >
> >  	__le32 *reply_queue;
> >  	dma_addr_t reply_queue_h;
> > @@ -1780,7 +2048,7 @@ struct megasas_instance {
> >  	struct megasas_evt_detail *evt_detail;
> >  	dma_addr_t evt_detail_h;
> >  	struct megasas_cmd *aen_cmd;
> > -	struct mutex aen_mutex;
> > +	struct mutex hba_mutex;
> >  	struct semaphore ioctl_sem;
> >
> >  	struct Scsi_Host *host;
> > diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c
> > b/drivers/scsi/megaraid/megaraid_sas_base.c
> > index c1dc23c..df93fa1 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas_base.c
> > +++ b/drivers/scsi/megaraid/megaraid_sas_base.c
> > @@ -104,6 +104,8 @@ static int megasas_ld_list_query(struct
> > megasas_instance *instance,  static int megasas_issue_init_mfi(struct
> > megasas_instance *instance);  static int megasas_register_aen(struct
> megasas_instance *instance,
> >  				u32 seq_num, u32 class_locale_word);
> > +static int
> > +megasas_get_pd_info(struct megasas_instance *instance, u16
> > +device_id);
> >  /*
> >   * PCI ID table for all supported controllers
> >   */
> > @@ -1796,6 +1798,44 @@ void megasas_update_sdev_properties(struct
> scsi_device *sdev)
> >  	}
> >  }
> >
> > +static void megasas_set_device_queue_depth(struct scsi_device *sdev)
> > +{
> > +	u16				pd_index = 0;
> > +	int		ret = DCMD_FAILED;
> > +	struct megasas_instance *instance;
> > +
> > +	instance = megasas_lookup_instance(sdev->host->host_no);
> > +
> > +	if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
> > +		pd_index = (sdev->channel *
> MEGASAS_MAX_DEV_PER_CHANNEL) +
> > +sdev->id;
> > +
> > +		if (instance->pd_info) {
> > +			mutex_lock(&instance->hba_mutex);
> > +			ret = megasas_get_pd_info(instance, pd_index);
> > +			mutex_unlock(&instance->hba_mutex);
> > +		}
> > +
> > +		if (ret != DCMD_SUCCESS)
> > +			return;
> > +
> > +		if (instance->pd_list[pd_index].driveState ==
> MR_PD_STATE_SYSTEM) {
> > +
> > +			switch (instance->pd_list[pd_index].interface) {
> > +			case SAS_PD:
> > +				scsi_change_queue_depth(sdev,
> MEGASAS_SAS_QD);
> > +				break;
> > +
> > +			case SATA_PD:
> > +				scsi_change_queue_depth(sdev,
> MEGASAS_SATA_QD);
> > +				break;
> > +
> > +			default:
> > +				scsi_change_queue_depth(sdev,
> MEGASAS_DEFAULT_PD_QD);
> > +			}
> > +		}
> > +	}
> > +}
> > +
> >
> >  static int megasas_slave_configure(struct scsi_device *sdev)  { @@
> > -1813,6 +1853,7 @@ static int megasas_slave_configure(struct
scsi_device
> *sdev)
> >  				return -ENXIO;
> >  		}
> >  	}
> > +	megasas_set_device_queue_depth(sdev);
> >  	megasas_update_sdev_properties(sdev);
> >
> >  	/*
> > @@ -3922,6 +3963,73 @@ dcmd_timeout_ocr_possible(struct
> megasas_instance *instance) {
> >  		return INITIATE_OCR;
> >  }
> >
> > +static int
> > +megasas_get_pd_info(struct megasas_instance *instance, u16 device_id)
> > +{
> > +	int ret;
> > +	struct megasas_cmd *cmd;
> > +	struct megasas_dcmd_frame *dcmd;
> > +
> > +	cmd = megasas_get_cmd(instance);
> > +
> > +	if (!cmd) {
> > +		dev_err(&instance->pdev->dev, "Failed to get cmd %s\n",
> __func__);
> > +		return -ENOMEM;
> > +	}
> > +
> > +	dcmd = &cmd->frame->dcmd;
> > +
> > +	memset(instance->pd_info, 0, sizeof(*instance->pd_info));
> > +	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
> > +
> > +	dcmd->mbox.s[0] = cpu_to_le16(device_id);
> > +	dcmd->cmd = MFI_CMD_DCMD;
> > +	dcmd->cmd_status = 0xFF;
> > +	dcmd->sge_count = 1;
> > +	dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ);
> > +	dcmd->timeout = 0;
> > +	dcmd->pad_0 = 0;
> > +	dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_PD_INFO));
> > +	dcmd->opcode = cpu_to_le32(MR_DCMD_PD_GET_INFO);
> > +	dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(instance->pd_info_h);
> > +	dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct
MR_PD_INFO));
> > +
> > +	if (instance->ctrl_context && !instance->mask_interrupts)
> > +		ret = megasas_issue_blocked_cmd(instance, cmd,
> MFI_IO_TIMEOUT_SECS);
> > +	else
> > +		ret = megasas_issue_polled(instance, cmd);
> > +
> > +	switch (ret) {
> > +	case DCMD_SUCCESS:
> > +		instance->pd_list[device_id].interface =
> > +				instance->pd_info->state.ddf.pdType.intf;
> > +		break;
> > +
> > +	case DCMD_TIMEOUT:
> > +
> > +		switch (dcmd_timeout_ocr_possible(instance)) {
> > +		case INITIATE_OCR:
> > +			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
> > +			megasas_reset_fusion(instance->host,
> > +				MFI_IO_TIMEOUT_OCR);
> > +			break;
> > +		case KILL_ADAPTER:
> > +			megaraid_sas_kill_hba(instance);
> > +			break;
> > +		case IGNORE_TIMEOUT:
> > +			dev_info(&instance->pdev->dev, "Ignore DCMD
> timeout: %s %d\n",
> > +				__func__, __LINE__);
> > +			break;
> > +		}
> > +
> > +		break;
> > +	}
> > +
> > +	if (ret != DCMD_TIMEOUT)
> > +		megasas_return_cmd(instance, cmd);
> > +
> > +	return ret;
> > +}
> >  /*
> >   * megasas_get_pd_list_info -	Returns FW's pd_list structure
> >   * @instance:				Adapter soft state
> > @@ -5680,6 +5788,12 @@ static int megasas_probe_one(struct pci_dev
> *pdev,
> >  		goto fail_alloc_dma_buf;
> >  	}
> >
> > +	instance->pd_info = pci_alloc_consistent(pdev,
> > +		sizeof(struct MR_PD_INFO), &instance->pd_info_h);
>
> Hi,
> is it possible to use here 'dma_alloc_coherent + GFP_KERNEL'
> instead of pci_alloc_consistent with GFP_ATOMIC ?
> --tm

Yes, I will modify this to use dma_alloc_coherent with GFP_KERNEL flag.

Thanks,
Sumit
>
> > +
> > +	if (!instance->pd_info)
> > +		dev_err(&instance->pdev->dev, "Failed to alloc mem for
> pd_info\n");
> > +
> >  	/*
> >  	 * Initialize locks and queues
> >  	 */
> > @@ -5696,6 +5810,7 @@ static int megasas_probe_one(struct pci_dev
*pdev,
> >  	spin_lock_init(&instance->completion_lock);
> >
> >  	mutex_init(&instance->reset_mutex);
> > +	mutex_init(&instance->hba_mutex);
> >
> >  	/*
> >  	 * Initialize PCI related and misc parameters @@ -5810,6 +5925,10
@@
> > fail_alloc_dma_buf:
> >  				    instance->evt_detail,
> >  				    instance->evt_detail_h);
> >
> > +	if (instance->pd_info)
> > +		pci_free_consistent(pdev, sizeof(struct MR_PD_INFO),
> > +					instance->pd_info,
> > +					instance->pd_info_h);
> >  	if (instance->producer)
> >  		pci_free_consistent(pdev, sizeof(u32), instance->producer,
> >  				    instance->producer_h);
> > @@ -6071,6 +6190,10 @@ fail_init_mfi:
> >  				instance->evt_detail,
> >  				instance->evt_detail_h);
> >
> > +	if (instance->pd_info)
> > +		pci_free_consistent(pdev, sizeof(struct MR_PD_INFO),
> > +					instance->pd_info,
> > +					instance->pd_info_h);
> >  	if (instance->producer)
> >  		pci_free_consistent(pdev, sizeof(u32), instance->producer,
> >  				instance->producer_h);
> > @@ -6189,6 +6312,10 @@ static void megasas_detach_one(struct pci_dev
> *pdev)
> >  		pci_free_consistent(pdev, sizeof(struct
megasas_evt_detail),
> >  				instance->evt_detail,
instance->evt_detail_h);
> >
> > +	if (instance->pd_info)
> > +		pci_free_consistent(pdev, sizeof(struct MR_PD_INFO),
> > +					instance->pd_info,
> > +					instance->pd_info_h);
> >  	if (instance->vf_affiliation)
> >  		pci_free_consistent(pdev, (MAX_LOGICAL_DRIVES + 1) *
> >  				    sizeof(struct MR_LD_VF_AFFILIATION),

^ permalink raw reply	[flat|nested] 50+ messages in thread

* RE: [PATCH 04/15] megaraid_sas: Task management support
  2016-01-11 17:03   ` Tomas Henzl
@ 2016-01-14 12:04     ` Sumit Saxena
  0 siblings, 0 replies; 50+ messages in thread
From: Sumit Saxena @ 2016-01-14 12:04 UTC (permalink / raw)
  To: Tomas Henzl, jbottomley, hch, martin.petersen; +Cc: linux-scsi, Kashyap Desai

> -----Original Message-----
> From: Tomas Henzl [mailto:thenzl@redhat.com]
> Sent: Monday, January 11, 2016 10:34 PM
> To: Sumit Saxena; jbottomley@parallels.com; hch@infradead.org;
> martin.petersen@oracle.com
> Cc: linux-scsi@vger.kernel.org; kashyap.desai@avagotech.com
> Subject: Re: [PATCH 04/15] megaraid_sas: Task management support
>
> On 18.12.2015 14:26, Sumit Saxena wrote:
> > This patch will add task management(TM) support for SCSI commands in
> megaraid_sas driver.
> > Added TM functions are below-
> > 1)Task abort
> > 2)Target reset
> >
> > Below are few key points-
> >
> > 1. Currently, megaraid_sas driver performs Controller reset when any
IO times
> out.
> > With these TM support added in driver, in case of IO timeout task
> > abort and target reset will be tried to recover timed out IO. If both
> > fails to recover IO, then Controller reset will be called. If the TM
> > request times out, fail the TM and escalate to the next
level(Controller reset).
> >
> > 2. mr_device_priv_data will be allocated for all generation of
> > controller, but is_tm_capable flag will never be set for older
> > controllers (prior to Invader series) as firmware support is not
available for
> T.M functionality.
> >
> > 3. whichever firmware is capable for TM will set is_tm_capable flag in
> > firmware API, which will be used by Driver to pass TM frame to
firmware or
> return back to OS as Failure to escalate next level of Error handling.
> >
> > Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
> > Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
> > ---
> >  drivers/scsi/megaraid/megaraid_sas.h        |   13 +
> >  drivers/scsi/megaraid/megaraid_sas_base.c   |   63 +++-
> >  drivers/scsi/megaraid/megaraid_sas_fusion.c |  479
> > ++++++++++++++++++++++++++-
> > drivers/scsi/megaraid/megaraid_sas_fusion.h |  117 +++++++-
> >  4 files changed, 653 insertions(+), 19 deletions(-)
> >
> > diff --git a/drivers/scsi/megaraid/megaraid_sas.h
> > b/drivers/scsi/megaraid/megaraid_sas.h
> > index dcc6ff8..0fcb156 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas.h
> > +++ b/drivers/scsi/megaraid/megaraid_sas.h
> > @@ -1520,6 +1520,15 @@ union megasas_frame {
> >  	u8 raw_bytes[64];
> >  };
> >
> > +/**
> > + * struct MR_PRIV_DEVICE - sdev private hostdata
> > + * @is_tm_capable: firmware managed tm_capable flag
> > + * @tm_busy: TM request is in progress  */ struct MR_PRIV_DEVICE {
> > +	bool is_tm_capable;
> > +	bool tm_busy;
> > +};
> >  struct megasas_cmd;
> >
> >  union megasas_evt_class_locale {
> > @@ -2073,4 +2082,8 @@ void megasas_return_mfi_mpt_pthr(struct
> > megasas_instance *instance,  int megasas_cmd_type(struct scsi_cmnd
> > *cmd);  void megasas_setup_jbod_map(struct megasas_instance
> > *instance);
> >
> > +void megasas_update_sdev_properties(struct scsi_device *sdev); int
> > +megasas_reset_fusion(struct Scsi_Host *shost, int reason); int
> > +megasas_task_abort_fusion(struct scsi_cmnd *scmd); int
> > +megasas_reset_target_fusion(struct scsi_cmnd *scmd);
> >  #endif				/*LSI_MEGARAID_SAS_H */
> > diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c
> > b/drivers/scsi/megaraid/megaraid_sas_base.c
> > index 380c627..c1dc23c 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas_base.c
> > +++ b/drivers/scsi/megaraid/megaraid_sas_base.c
> > @@ -189,7 +189,6 @@ int
> >  wait_and_poll(struct megasas_instance *instance, struct megasas_cmd
*cmd,
> >  	int seconds);
> >  void megasas_reset_reply_desc(struct megasas_instance *instance);
> > -int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout);
> > void megasas_fusion_ocr_wq(struct work_struct *work);  static int
> > megasas_get_ld_vf_affiliation(struct megasas_instance *instance,
> >  					 int initial);
> > @@ -1645,6 +1644,7 @@ megasas_queue_command(struct Scsi_Host *shost,
> > struct scsi_cmnd *scmd)  {
> >  	struct megasas_instance *instance;
> >  	unsigned long flags;
> > +	struct MR_PRIV_DEVICE *mr_device_priv_data;
> >
> >  	instance = (struct megasas_instance *)
> >  	    scmd->device->host->hostdata;
> > @@ -1681,11 +1681,24 @@ megasas_queue_command(struct Scsi_Host
> *shost, struct scsi_cmnd *scmd)
> >  		return 0;
> >  	}
> >
> > +	mr_device_priv_data = scmd->device->hostdata;
> > +	if (!mr_device_priv_data) {
> > +		spin_unlock_irqrestore(&instance->hba_lock, flags);
> > +		scmd->result = DID_NO_CONNECT << 16;
> > +		scmd->scsi_done(scmd);
> > +		return 0;
> > +	}
> > +
> >  	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
> >  		spin_unlock_irqrestore(&instance->hba_lock, flags);
> >  		return SCSI_MLQUEUE_HOST_BUSY;
> >  	}
> >
> > +	if (mr_device_priv_data->tm_busy) {
> > +		spin_unlock_irqrestore(&instance->hba_lock, flags);
> > +		return SCSI_MLQUEUE_DEVICE_BUSY;
> > +	}
> > +
> >  	spin_unlock_irqrestore(&instance->hba_lock, flags);
> >
> >  	scmd->result = 0;
> > @@ -1736,27 +1749,39 @@ static struct megasas_instance
> > *megasas_lookup_instance(u16 host_no)  }
> >
> >  /*
> > -* megasas_set_dma_alignment - Set DMA alignment for PI enabled VD
> > +* megasas_update_sdev_properties - Update sdev structure based on
> > +controller's FW capabilities
> >  *
> >  * @sdev: OS provided scsi device
> >  *
> >  * Returns void
> >  */
> > -static void megasas_set_dma_alignment(struct scsi_device *sdev)
> > +void megasas_update_sdev_properties(struct scsi_device *sdev)
> >  {
> > +	u16 pd_index = 0;
> >  	u32 device_id, ld;
> >  	struct megasas_instance *instance;
> >  	struct fusion_context *fusion;
> > +	struct MR_PRIV_DEVICE *mr_device_priv_data;
> > +	struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync;
> >  	struct MR_LD_RAID *raid;
> >  	struct MR_DRV_RAID_MAP_ALL *local_map_ptr;
> >
> >  	instance = megasas_lookup_instance(sdev->host->host_no);
> >  	fusion = instance->ctrl_context;
> > +	mr_device_priv_data = sdev->hostdata;
> >
> > -	if (!fusion)
> > +	if (!fusion || !mr_device_priv_data)
> >  		return;
>
> How can this happen that mr_device_priv_data is NULL, and if isn't it a
problem
> that you do not set the dma alignment and other megasas_instance values?
>
Yes, "mr_device_priv_data" cannot be NULL. If allocation of
"mr_device_priv_data" is failed inside slave_alloc then slave_config will
not be called at all for that particular "sdev".
I will send modified patch.
> >
> > -	if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS) {
> > +	if (sdev->channel < MEGASAS_MAX_PD_CHANNELS &&
> > +		instance->use_seqnum_jbod_fp) {
> > +		pd_index = (sdev->channel *
> MEGASAS_MAX_DEV_PER_CHANNEL) +
> > +			sdev->id;
> > +		pd_sync = (void *)fusion->pd_seq_sync
> > +				[(instance->pd_seq_map_id - 1) & 1];
> > +		mr_device_priv_data->is_tm_capable =
> > +			pd_sync->seq[pd_index].capability.tmCapable;
> > +	} else {
> >  		device_id = ((sdev->channel % 2) *
> MEGASAS_MAX_DEV_PER_CHANNEL)
> >  					+ sdev->id;
> >  		local_map_ptr = fusion->ld_drv_map[(instance->map_id &
1)];
> @@
> > -1764,10 +1789,14 @@ static void megasas_set_dma_alignment(struct
> scsi_device *sdev)
> >  		raid = MR_LdRaidGet(ld, local_map_ptr);
> >
> >  		if (raid->capability.ldPiMode ==
> MR_PROT_INFO_TYPE_CONTROLLER)
> > -			blk_queue_update_dma_alignment(sdev-
> >request_queue, 0x7);
> > +		blk_queue_update_dma_alignment(sdev->request_queue, 0x7);
>
> Please keep the whitespace above.
Ok..
>
> > +
> > +		mr_device_priv_data->is_tm_capable =
> > +			raid->capability.tmCapable;
> >  	}
> >  }
> >
> > +
> >  static int megasas_slave_configure(struct scsi_device *sdev)  {
> >  	u16 pd_index = 0;
> > @@ -1784,7 +1813,8 @@ static int megasas_slave_configure(struct
> scsi_device *sdev)
> >  				return -ENXIO;
> >  		}
> >  	}
> > -	megasas_set_dma_alignment(sdev);
> > +	megasas_update_sdev_properties(sdev);
> > +
> >  	/*
> >  	 * The RAID firmware may require extended timeouts.
> >  	 */
> > @@ -1798,6 +1828,7 @@ static int megasas_slave_alloc(struct
> > scsi_device *sdev)  {
> >  	u16 pd_index = 0;
> >  	struct megasas_instance *instance ;
> > +	struct MR_PRIV_DEVICE *mr_device_priv_data;
> >
> >  	instance = megasas_lookup_instance(sdev->host->host_no);
> >  	if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) { @@ -1809,13
> +1840,26
> > @@ static int megasas_slave_alloc(struct scsi_device *sdev)
> >  			sdev->id;
> >  		if ((instance->allow_fw_scan || instance-
> >pd_list[pd_index].driveState ==
> >  			MR_PD_STATE_SYSTEM)) {
> > -			return 0;
> > +			goto scan_target;
> >  		}
> >  		return -ENXIO;
> >  	}
> > +
> > +scan_target:
> > +	mr_device_priv_data = kzalloc(sizeof(*mr_device_priv_data),
> > +					GFP_KERNEL);
> > +	if (!mr_device_priv_data)
> > +		return -ENOMEM;
> > +	sdev->hostdata = mr_device_priv_data;
> >  	return 0;
> >  }
> >
> > +static void megasas_slave_destroy(struct scsi_device *sdev) {
> > +	kfree(sdev->hostdata);
> > +	sdev->hostdata = NULL;
> > +}
> > +
> >  /*
> >  * megasas_complete_outstanding_ioctls - Complete outstanding ioctls
after a
> >  *                                       kill adapter
> > @@ -2885,6 +2929,7 @@ static struct scsi_host_template
megasas_template
> = {
> >  	.proc_name = "megaraid_sas",
> >  	.slave_configure = megasas_slave_configure,
> >  	.slave_alloc = megasas_slave_alloc,
> > +	.slave_destroy = megasas_slave_destroy,
> >  	.queuecommand = megasas_queue_command,
> >  	.eh_device_reset_handler = megasas_reset_device,
> >  	.eh_bus_reset_handler = megasas_reset_bus_host, @@ -5434,6
> +5479,8
> > @@ static int megasas_io_attach(struct megasas_instance *instance)
> >  	if (instance->ctrl_context) {
> >  		host->hostt->eh_device_reset_handler = NULL;
> >  		host->hostt->eh_bus_reset_handler = NULL;
> > +		host->hostt->eh_target_reset_handler =
> megasas_reset_target_fusion;
> > +		host->hostt->eh_abort_handler = megasas_task_abort_fusion;
> >  	}
> >
> >  	/*
> > diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > index 1dc4537..0b31f5a 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > @@ -2100,6 +2100,8 @@ complete_cmd_fusion(struct megasas_instance
> *instance, u32 MSIxIndex)
> >  	struct LD_LOAD_BALANCE_INFO *lbinfo;
> >  	int threshold_reply_count = 0;
> >  	struct scsi_cmnd *scmd_local = NULL;
> > +	struct MR_TASK_MANAGE_REQUEST *mr_tm_req;
> > +	struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_tm_req;
> >
> >  	fusion = instance->ctrl_context;
> >
> > @@ -2141,6 +2143,16 @@ complete_cmd_fusion(struct megasas_instance
> *instance, u32 MSIxIndex)
> >  		extStatus = scsi_io_req->RaidContext.exStatus;
> >
> >  		switch (scsi_io_req->Function) {
> > +		case MPI2_FUNCTION_SCSI_TASK_MGMT:
> > +			mr_tm_req = (struct MR_TASK_MANAGE_REQUEST *)
> > +						cmd_fusion->io_request;
> > +			mpi_tm_req = (struct
> MPI2_SCSI_TASK_MANAGE_REQUEST *)
> > +						&mr_tm_req->TmRequest;
> > +			dev_dbg(&instance->pdev->dev, "TM completion:"
> > +				"type: 0x%x TaskMID: 0x%x\n",
> > +				mpi_tm_req->TaskType, mpi_tm_req-
> >TaskMID);
> > +			complete(&cmd_fusion->done);
> > +			break;
> >  		case MPI2_FUNCTION_SCSI_IO_REQUEST:  /*Fast Path IO.*/
> >  			/* Update load balancing info */
> >  			device_id = MEGASAS_DEV_INDEX(scmd_local); @@ -
> 2727,6 +2739,457 @@
> > void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
> >  	}
> >  }
> >
> > +/*
> > + * megasas_track_scsiio : Track SCSI IOs outstanding to a SCSI device
> > + * @instance: per adapter struct
> > + * @channel: the channel assigned by the OS
> > + * @id: the id assigned by the OS
> > + *
> > + * Returns SUCCESS if no IOs pending to SCSI device, else return
> > +FAILED  */
> > +
> > +static int megasas_track_scsiio(struct megasas_instance *instance,
> > +		int id, int channel)
> > +{
> > +	int i, found = 0;
> > +	struct megasas_cmd_fusion *cmd_fusion;
> > +	struct fusion_context *fusion;
> > +	fusion = instance->ctrl_context;
> > +
> > +	for (i = 0 ; i < instance->max_scsi_cmds; i++) {
> > +		cmd_fusion = fusion->cmd_list[i];
> > +		if (cmd_fusion->scmd &&
> > +			(cmd_fusion->scmd->device->id == id &&
> > +			cmd_fusion->scmd->device->channel == channel)) {
> > +			dev_info(&instance->pdev->dev,
> > +				"SCSI commands pending to target"
> > +				"channel %d id %d \tSMID: 0x%x\n",
> > +				channel, id, cmd_fusion->index);
> > +			scsi_print_command(cmd_fusion->scmd);
> > +			found = 1;
> > +			break;
> > +		}
> > +	}
> > +
> > +	return found ? FAILED : SUCCESS;
> > +}
> > +
> > +/**
> > + * megasas_tm_response_code - translation of device response code
> > + * @ioc: per adapter object
> > + * @mpi_reply: MPI reply returned by firmware
> > + *
> > + * Return nothing.
> > + */
> > +static void
> > +megasas_tm_response_code(struct megasas_instance *instance,
> > +		struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply) {
> > +	char *desc;
> > +
> > +	switch (mpi_reply->ResponseCode) {
> > +	case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE:
> > +		desc = "task management request completed";
> > +		break;
> > +	case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME:
> > +		desc = "invalid frame";
> > +		break;
> > +	case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
> > +		desc = "task management request not supported";
> > +		break;
> > +	case MPI2_SCSITASKMGMT_RSP_TM_FAILED:
> > +		desc = "task management request failed";
> > +		break;
> > +	case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED:
> > +		desc = "task management request succeeded";
> > +		break;
> > +	case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN:
> > +		desc = "invalid lun";
> > +		break;
> > +	case 0xA:
> > +		desc = "overlapped tag attempted";
> > +		break;
> > +	case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
> > +		desc = "task queued, however not sent to target";
> > +		break;
> > +	default:
> > +		desc = "unknown";
> > +		break;
> > +	}
> > +	dev_dbg(&instance->pdev->dev, "response_code(%01x): %s\n",
> > +		mpi_reply->ResponseCode, desc);
> > +	dev_dbg(&instance->pdev->dev,
> > +
> 	"TerminationCount/DevHandle/Function/TaskType/IOCStat/IOCLoginfo
> "
> > +		" 0x%x/0x%x/0x%x/0x%x/0x%x/0x%x\n",
> > +		mpi_reply->TerminationCount, mpi_reply->DevHandle,
> > +		mpi_reply->Function, mpi_reply->TaskType,
> > +		mpi_reply->IOCStatus, mpi_reply->IOCLogInfo); }
> > +
> > +/**
> > + * megasas_issue_tm - main routine for sending tm requests
> > + * @instance: per adapter struct
> > + * @device_handle: device handle
> > + * @channel: the channel assigned by the OS
> > + * @id: the id assigned by the OS
> > + * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in
> > +megaraid_sas_fusion.c)
> > + * @smid_task: smid assigned to the task
> > + * @m_type: TM_MUTEX_ON or TM_MUTEX_OFF
> > + * Context: user
> > + *
> > + * MegaRaid use MPT interface for Task Magement request.
> > + * A generic API for sending task management requests to firmware.
> > + *
> > + * Return SUCCESS or FAILED.
> > + */
> > +static int
> > +megasas_issue_tm(struct megasas_instance *instance, u16
device_handle,
> > +	uint channel, uint id, u16 smid_task, u8 type) {
> > +	struct MR_TASK_MANAGE_REQUEST *mr_request;
> > +	struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_request;
> > +	unsigned long timeleft;
> > +	struct megasas_cmd_fusion *cmd_fusion;
> > +	struct megasas_cmd *cmd_mfi;
> > +	union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
> > +	struct fusion_context *fusion;
> > +	struct megasas_cmd_fusion *scsi_lookup;
> > +	int rc;
> > +	struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply;
> > +
> > +	fusion = instance->ctrl_context;
> > +
> > +	cmd_mfi = megasas_get_cmd(instance);
> > +
> > +	if (!cmd_mfi) {
> > +		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
> > +			__func__, __LINE__);
> > +		return -ENOMEM;
> > +	}
> > +
> > +	cmd_fusion = megasas_get_cmd_fusion(instance,
> > +			instance->max_scsi_cmds + cmd_mfi->index);
> > +
> > +	/*  Save the smid. To be used for returning the cmd */
> > +	cmd_mfi->context.smid = cmd_fusion->index;
> > +
> > +	req_desc = megasas_get_request_descriptor(instance,
> > +			(cmd_fusion->index - 1));
> > +	if (!req_desc) {
> > +		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
> > +			__func__, __LINE__);
>
> 	megasas_return_cmd should be called here?
 I will handle this and send updated patch.

>
> > +		return -ENOMEM;
> > +	}
> > +
> > +	cmd_fusion->request_desc = req_desc;
> > +	req_desc->Words = 0;
> > +
> > +	scsi_lookup = fusion->cmd_list[smid_task - 1];
> > +
> > +	mr_request = (struct MR_TASK_MANAGE_REQUEST *) cmd_fusion-
> >io_request;
> > +	memset(mr_request, 0, sizeof(struct MR_TASK_MANAGE_REQUEST));
> > +	mpi_request = (struct MPI2_SCSI_TASK_MANAGE_REQUEST *)
> &mr_request->TmRequest;
> > +	mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
> > +	mpi_request->DevHandle = cpu_to_le16(device_handle);
> > +	mpi_request->TaskType = type;
> > +	mpi_request->TaskMID = cpu_to_le16(smid_task);
> > +	mpi_request->LUN[1] = 0;
> > +
> > +
> > +	req_desc = cmd_fusion->request_desc;
> > +	req_desc->HighPriority.SMID = cpu_to_le16(cmd_fusion->index);
> > +	req_desc->HighPriority.RequestFlags =
> > +		(MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
> > +		MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
> > +	req_desc->HighPriority.MSIxIndex =  0;
> > +	req_desc->HighPriority.LMID = 0;
> > +	req_desc->HighPriority.Reserved1 = 0;
> > +
> > +	if (channel < MEGASAS_MAX_PD_CHANNELS)
> > +		mr_request->tmReqFlags.isTMForPD = 1;
> > +	else
> > +		mr_request->tmReqFlags.isTMForLD = 1;
> > +
> > +	init_completion(&cmd_fusion->done);
> > +	megasas_fire_cmd_fusion(instance, req_desc);
> > +
> > +	timeleft = wait_for_completion_timeout(&cmd_fusion->done, 50 *
HZ);
> > +
> > +	if (!timeleft) {
> > +		dev_err(&instance->pdev->dev,
> > +			"task mgmt type 0x%x timed out\n", type);
> > +		mutex_unlock(&instance->reset_mutex);
> > +		rc = megasas_reset_fusion(instance->host,
> MFI_IO_TIMEOUT_OCR);
> > +		mutex_lock(&instance->reset_mutex);
>
> 	megasas_return_cmd should be called here too?

Agree, I will fix this.
>
> > +		return rc;
> > +	}
> > +
> > +	mpi_reply = (struct MPI2_SCSI_TASK_MANAGE_REPLY *) &mr_request-
> >TMReply;
> > +	megasas_tm_response_code(instance, mpi_reply);
> > +
> > +	megasas_return_cmd(instance, cmd_mfi);
> > +	rc = SUCCESS;
> > +	switch (type) {
> > +	case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
> > +		if (scsi_lookup->scmd == NULL)
> > +			break;
> > +		else {
> > +			instance->instancet->disable_intr(instance);
> > +			msleep(1000);
> > +			megasas_complete_cmd_dpc_fusion
> > +					((unsigned long)instance);
> > +			instance->instancet->enable_intr(instance);
> > +			if (scsi_lookup->scmd == NULL)
> > +				break;
> > +		}
> > +		rc = FAILED;
> > +		break;
> > +
> > +	case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
> > +		if ((channel == 0xFFFFFFFF) && (id == 0xFFFFFFFF))
> > +			break;
> > +		instance->instancet->disable_intr(instance);
> > +		msleep(1000);
> > +		megasas_complete_cmd_dpc_fusion
> > +				((unsigned long)instance);
> > +		rc = megasas_track_scsiio(instance, id, channel);
> > +		instance->instancet->enable_intr(instance);
> > +
> > +		break;
> > +	case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:
> > +	case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK:
> > +		break;
> > +	default:
> > +		rc = FAILED;
> > +		break;
> > +	}
> > +
> > +	return rc;
> > +
> > +}
> > +
> > +/*
> > + * megasas_fusion_smid_lookup : Look for fusion command
> > +correpspodning to SCSI
> > + * @instance: per adapter struct
> > + *
> > + * Return Non Zero index, if SMID found in outstanding commands  */
> > +static u16 megasas_fusion_smid_lookup(struct scsi_cmnd *scmd) {
> > +	int i, ret = 0;
> > +	struct megasas_instance *instance;
> > +	struct megasas_cmd_fusion *cmd_fusion;
> > +	struct fusion_context *fusion;
> > +
> > +	instance = (struct megasas_instance
*)scmd->device->host->hostdata;
> > +
> > +	fusion = instance->ctrl_context;
> > +
> > +	for (i = 0; i < instance->max_scsi_cmds; i++) {
> > +		cmd_fusion = fusion->cmd_list[i];
> > +		if (cmd_fusion->scmd && (cmd_fusion->scmd == scmd)) {
> > +			scmd_printk(KERN_NOTICE, scmd, "Abort request is
> for"
> > +				" SMID: %d\n", cmd_fusion->index);
> > +			ret = cmd_fusion->index;
> > +			break;
> > +		}
> > +	}
> > +
> > +	return ret;
> > +}
> > +
> > +/*
> > +* megasas_get_tm_devhandle - Get devhandle for TM request
> > +* @sdev-		     OS provided scsi device
> > +*
> > +* Returns-		     devhandle/targetID of SCSI device
> > +*/
> > +static u16 megasas_get_tm_devhandle(struct scsi_device *sdev) {
> > +	u16 pd_index = 0;
> > +	u32 device_id;
> > +	struct megasas_instance *instance;
> > +	struct fusion_context *fusion;
> > +	struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync;
> > +	u16 devhandle = (u16)ULONG_MAX;
> > +
> > +	instance = (struct megasas_instance *)sdev->host->hostdata;
> > +	fusion = instance->ctrl_context;
> > +
> > +	if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
> > +		if (instance->use_seqnum_jbod_fp) {
> > +				pd_index = (sdev->channel *
> MEGASAS_MAX_DEV_PER_CHANNEL) +
> > +						sdev->id;
> > +				pd_sync = (void *)fusion->pd_seq_sync
> > +						[(instance->pd_seq_map_id
-
> 1) & 1];
> > +				devhandle = pd_sync-
> >seq[pd_index].devHandle;
> > +		} else
> > +			sdev_printk(KERN_ERR, sdev, "Firmware expose
> tmCapable"
> > +				" without JBOD MAP support from %s %d\n",
> __func__, __LINE__);
> > +	} else {
> > +		device_id = ((sdev->channel % 2) *
> MEGASAS_MAX_DEV_PER_CHANNEL)
> > +				+ sdev->id;
> > +		devhandle = device_id;
> > +	}
> > +
> > +	return devhandle;
> > +}
> > +
> > +/*
> > + * megasas_task_abort_fusion : SCSI task abort function for fusion
> > +adapters
> > + * @scmd : pointer to scsi command object
> > + *
> > + * Return SUCCESS, if command aborted else FAILED  */
> > +
> > +int megasas_task_abort_fusion(struct scsi_cmnd *scmd) {
> > +	struct megasas_instance *instance;
> > +	u16 smid, devhandle;
> > +	struct fusion_context *fusion;
> > +	int ret;
> > +	struct MR_PRIV_DEVICE *mr_device_priv_data;
> > +	mr_device_priv_data = scmd->device->hostdata;
> > +
> > +
> > +	instance = (struct megasas_instance
*)scmd->device->host->hostdata;
> > +	fusion = instance->ctrl_context;
> > +
> > +	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
> > +		dev_err(&instance->pdev->dev, "Controller is not
> OPERATIONAL,"
> > +		"SCSI host:%d\n", instance->host->host_no);
> > +		ret = FAILED;
> > +		return ret;
> > +	}
> > +
> > +	if (!mr_device_priv_data) {
> > +		sdev_printk(KERN_INFO, scmd->device, "device been deleted!
"
> > +			"scmd(%p)\n", scmd);
> > +		scmd->result = DID_NO_CONNECT << 16;
> > +		scmd->scsi_done(scmd);
>
> Device has been deleted doesn't that imply that all commands had to be
before
> finished - so you should not call scsi_done ?

Agree, I will modify this.
>
> > +		ret = SUCCESS;
> > +		goto out;
> > +	}
> > +
> > +
> > +	if (!mr_device_priv_data->is_tm_capable) {
> > +		scmd->result = DID_RESET << 16;
>
> I think that setting scmd->result makes no sense here (too) a FAILED
return
> should be enough.
Agree..
>
> > +		ret = FAILED;
> > +		goto out;
> > +	}
> > +
> > +	mutex_lock(&instance->reset_mutex);
> > +
> > +	smid = megasas_fusion_smid_lookup(scmd);
> > +
> > +	if (!smid) {
> > +		scmd->result = DID_RESET << 16;
>
> I think that setting scmd->result makes no sense here (too) a SUCCESS
return
> should be enough.
Agree..
>
> > +		ret = SUCCESS;
> > +		scmd_printk(KERN_NOTICE, scmd, "Command for which abort
> is"
> > +			" issued is not found in oustanding commands\n");
> > +		mutex_unlock(&instance->reset_mutex);
> > +		goto out;
> > +	}
> > +
> > +	devhandle = megasas_get_tm_devhandle(scmd->device);
> > +
> > +	if (devhandle == (u16)ULONG_MAX) {
> > +		scmd->result = DID_RESET << 16;
>
> same here and on other places
Hmm..I agree.
>
> > +		ret = SUCCESS;
> > +		sdev_printk(KERN_INFO, scmd->device,
> > +			"task abort issued for invalid devhandle\n");
> > +		mutex_unlock(&instance->reset_mutex);
> > +		goto out;
> > +	}
> > +	sdev_printk(KERN_INFO, scmd->device,
> > +		"attempting task abort! scmd(%p) tm_dev_handle 0x%x\n",
> > +		scmd, devhandle);
> > +
> > +	mr_device_priv_data->tm_busy = 1;
> > +	ret = megasas_issue_tm(instance, devhandle,
> > +			scmd->device->channel, scmd->device->id, smid,
> > +			MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
> > +	mr_device_priv_data->tm_busy = 0;
> > +
> > +	mutex_unlock(&instance->reset_mutex);
> > +out:
> > +	sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n",
> > +			((ret == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
> > +
> > +	return ret;
> > +}
> > +
> > +/*
> > + * megasas_reset_target_fusion : target reset function for fusion
> > +adapters
> > + * scmd: SCSI command pointer
> > + *
> > + * Returns SUCCESS if all commands associated with target aborted
> > +else FAILED  */
> > +
> > +int megasas_reset_target_fusion(struct scsi_cmnd *scmd) {
> > +
> > +	struct megasas_instance *instance;
> > +	int ret = FAILED;
> > +	u16 devhandle;
> > +	struct fusion_context *fusion;
> > +	struct MR_PRIV_DEVICE *mr_device_priv_data;
> > +	mr_device_priv_data = scmd->device->hostdata;
> > +
> > +	instance = (struct megasas_instance
*)scmd->device->host->hostdata;
> > +	fusion = instance->ctrl_context;
> > +
> > +	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
> > +		dev_err(&instance->pdev->dev, "Controller is not
> OPERATIONAL,"
> > +		"SCSI host:%d\n", instance->host->host_no);
> > +		ret = FAILED;
> > +		return ret;
> > +	}
> > +
> > +	if (!mr_device_priv_data) {
> > +		sdev_printk(KERN_INFO, scmd->device, "device been deleted!
"
> > +			"scmd(%p)\n", scmd);
> > +		scmd->result = DID_NO_CONNECT << 16;
> > +		scmd->scsi_done(scmd);
> > +		ret = SUCCESS;
> > +		goto out;
> > +	}
> > +
> > +
> > +	if (!mr_device_priv_data->is_tm_capable) {
> > +		scmd->result = DID_RESET << 16;
> > +		ret = FAILED;
> > +		goto out;
> > +	}
> > +
> > +	mutex_lock(&instance->reset_mutex);
> > +	devhandle = megasas_get_tm_devhandle(scmd->device);
> > +
> > +	if (devhandle == (u16)ULONG_MAX) {
> > +		scmd->result = DID_RESET << 16;
> > +		ret = SUCCESS;
> > +		sdev_printk(KERN_INFO, scmd->device,
> > +			"target reset issued for invalid devhandle\n");
> > +		mutex_unlock(&instance->reset_mutex);
> > +		goto out;
> > +	}
> > +
> > +	sdev_printk(KERN_INFO, scmd->device,
> > +		"attempting target reset! scmd(%p) tm_dev_handle 0x%x\n",
> > +		scmd, devhandle);
> > +	mr_device_priv_data->tm_busy = 1;
> > +	ret = megasas_issue_tm(instance, devhandle,
> > +			scmd->device->channel, scmd->device->id, 0,
> > +			MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET);
> > +	mr_device_priv_data->tm_busy = 0;
> > +	mutex_unlock(&instance->reset_mutex);
> > +out:
> > +	scmd_printk(KERN_NOTICE, scmd, "megasas: target reset %s!!\n",
> > +		(ret == SUCCESS) ? "SUCCESS" : "FAILED");
> > +
> > +	return ret;
> > +}
> > +
> >  /* Check for a second path that is currently UP */  int
> > megasas_check_mpio_paths(struct megasas_instance *instance,
> >  	struct scsi_cmnd *scmd)
> > @@ -2752,7 +3215,7 @@ out:
> >  }
> >
> >  /* Core fusion reset function */
> > -int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
> > +int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
> >  {
> >  	int retval = SUCCESS, i, convert = 0;
> >  	struct megasas_instance *instance;
> > @@ -2761,6 +3224,7 @@ int megasas_reset_fusion(struct Scsi_Host
*shost,
> int iotimeout)
> >  	u32 abs_state, status_reg, reset_adapter;
> >  	u32 io_timeout_in_crash_mode = 0;
> >  	struct scsi_cmnd *scmd_local = NULL;
> > +	struct scsi_device *sdev;
> >
> >  	instance = (struct megasas_instance *)shost->hostdata;
> >  	fusion = instance->ctrl_context;
> > @@ -2779,8 +3243,8 @@ int megasas_reset_fusion(struct Scsi_Host
> > *shost, int iotimeout)
> >
> >  	/* IO timeout detected, forcibly put FW in FAULT state */
> >  	if (abs_state != MFI_STATE_FAULT && instance->crash_dump_buf &&
> > -		instance->crash_dump_app_support && iotimeout) {
> > -		dev_info(&instance->pdev->dev, "IO timeout is detected, "
> > +		instance->crash_dump_app_support && reason) {
> > +		dev_info(&instance->pdev->dev, "IO/DCMD timeout is
> detected, "
> >  			"forcibly FAULT Firmware\n");
> >  		instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
> >  		status_reg = readl(&instance->reg_set->doorbell);
> > @@ -2819,13 +3283,13 @@ int megasas_reset_fusion(struct Scsi_Host
> *shost, int iotimeout)
> >  	msleep(1000);
> >
> >  	/* First try waiting for commands to complete */
> > -	if (megasas_wait_for_outstanding_fusion(instance, iotimeout,
> > +	if (megasas_wait_for_outstanding_fusion(instance, reason,
> >  						&convert)) {
> >  		instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
> >  		dev_warn(&instance->pdev->dev, "resetting fusion "
> >  		       "adapter scsi%d.\n", instance->host->host_no);
> >  		if (convert)
> > -			iotimeout = 0;
> > +			reason = 0;
> >
> >  		/* Now return commands back to the OS */
> >  		for (i = 0 ; i < instance->max_scsi_cmds; i++) { @@
-2859,7
> +3323,7
> > @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
> >  		}
> >
> >  		/* Let SR-IOV VF & PF sync up if there was a HB failure */
> > -		if (instance->requestorId && !iotimeout) {
> > +		if (instance->requestorId && !reason) {
> >  			msleep(MEGASAS_OCR_SETTLE_TIME_VF);
> >  			/* Look for a late HB update after VF settle time
*/
> >  			if (abs_state == MFI_STATE_OPERATIONAL && @@ -
> 2954,6 +3418,9 @@
> > int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
> >
> >  			megasas_setup_jbod_map(instance);
> >
> > +			shost_for_each_device(sdev, shost)
> > +				megasas_update_sdev_properties(sdev);
> > +
> >  			clear_bit(MEGASAS_FUSION_IN_RESET,
> >  				  &instance->reset_flags);
> >  			instance->instancet->enable_intr(instance);
> > diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h
> > b/drivers/scsi/megaraid/megaraid_sas_fusion.h
> > index a9e10c4..a1f1c0b 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
> > +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
> > @@ -176,6 +176,7 @@ enum REGION_TYPE {
> >  #define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD           (0x0100)
> >  #define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP             (0x0004)
> >  #define MPI2_FUNCTION_SCSI_IO_REQUEST               (0x00) /* SCSI IO
*/
> > +#define MPI2_FUNCTION_SCSI_TASK_MGMT                (0x01)
> >  #define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY       (0x03)
> >  #define MPI2_REQ_DESCRIPT_FLAGS_FP_IO               (0x06)
> >  #define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO                 (0x00)
> > @@ -278,6 +279,100 @@ union MPI2_SCSI_IO_CDB_UNION {
> >  	struct MPI2_SGE_SIMPLE_UNION SGE;
> >  };
> >
> >
> +/***************************************************************
> *****
> > +********
> > +*  SCSI Task Management messages
> >
> +****************************************************************
> *****
> > +*******/
> > +
> > +/*SCSI Task Management Request Message */ struct
> > +MPI2_SCSI_TASK_MANAGE_REQUEST {
> > +	u16 DevHandle;		/*0x00 */
> > +	u8 ChainOffset;		/*0x02 */
> > +	u8 Function;		/*0x03 */
> > +	u8 Reserved1;		/*0x04 */
> > +	u8 TaskType;		/*0x05 */
> > +	u8 Reserved2;		/*0x06 */
> > +	u8 MsgFlags;		/*0x07 */
> > +	u8 VP_ID;		/*0x08 */
> > +	u8 VF_ID;		/*0x09 */
> > +	u16 Reserved3;		/*0x0A */
> > +	u8 LUN[8];		/*0x0C */
> > +	u32 Reserved4[7];	/*0x14 */
> > +	u16 TaskMID;		/*0x30 */
> > +	u16 Reserved5;		/*0x32 */
> > +};
> > +
> > +
> > +/*SCSI Task Management Reply Message */ struct
> > +MPI2_SCSI_TASK_MANAGE_REPLY {
> > +	u16 DevHandle;		/*0x00 */
> > +	u8 MsgLength;		/*0x02 */
> > +	u8 Function;		/*0x03 */
> > +	u8 ResponseCode;	/*0x04 */
> > +	u8 TaskType;		/*0x05 */
> > +	u8 Reserved1;		/*0x06 */
> > +	u8 MsgFlags;		/*0x07 */
> > +	u8 VP_ID;		/*0x08 */
> > +	u8 VF_ID;		/*0x09 */
> > +	u16 Reserved2;		/*0x0A */
> > +	u16 Reserved3;		/*0x0C */
> > +	u16 IOCStatus;		/*0x0E */
> > +	u32 IOCLogInfo;		/*0x10 */
> > +	u32 TerminationCount;	/*0x14 */
> > +	u32 ResponseInfo;	/*0x18 */
> > +};
> > +
> > +struct MR_TM_REQUEST {
> > +	char request[128];
> > +};
> > +
> > +struct MR_TM_REPLY {
> > +	char reply[128];
> > +};
> > +
> > +/* SCSI Task Management Request Message */ struct
> > +MR_TASK_MANAGE_REQUEST {
> > +	/*To be type casted to struct MPI2_SCSI_TASK_MANAGE_REQUEST */
> > +	struct MR_TM_REQUEST         TmRequest;
> > +	union {
> > +		struct {
> > +#if   defined(__BIG_ENDIAN_BITFIELD)
> > +			u32 reserved1:30;
> > +			u32 isTMForPD:1;
> > +			u32 isTMForLD:1;
> > +#else
> > +			u32 isTMForLD:1;
> > +			u32 isTMForPD:1;
> > +			u32 reserved1:30;
> > +#endif
> > +			u32 reserved2;
> > +		} tmReqFlags;
> > +		struct MR_TM_REPLY   TMReply;
> > +	};
> > +};
> > +
> > +/* TaskType values */
> > +
> > +#define MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK           (0x01)
> > +#define MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET        (0x02)
> > +#define MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET         (0x03)
> > +#define MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET   (0x05)
> > +#define MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET       (0x06)
> > +#define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK           (0x07)
> > +#define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA              (0x08)
> > +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET         (0x09)
> > +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT      (0x0A)
> > +
> > +/* ResponseCode values */
> > +
> > +#define MPI2_SCSITASKMGMT_RSP_TM_COMPLETE               (0x00)
> > +#define MPI2_SCSITASKMGMT_RSP_INVALID_FRAME             (0x02)
> > +#define MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED          (0x04)
> > +#define MPI2_SCSITASKMGMT_RSP_TM_FAILED                 (0x05)
> > +#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED              (0x08)
> > +#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN            (0x09)
> > +#define MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG         (0x0A)
> > +#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC          (0x80)
> > +
> >  /*
> >   * RAID SCSI IO Request Message
> >   * Total SGE count will be one less than  _MPI2_SCSI_IO_REQUEST @@
> > -548,7 +643,8 @@ struct MR_SPAN_BLOCK_INFO {  struct MR_LD_RAID {
> >  	struct {
> >  #if   defined(__BIG_ENDIAN_BITFIELD)
> > -		u32     reserved4:7;
> > +		u32     reserved4:6;
> > +		u32     tmCapable:1;
> >  		u32	fpNonRWCapable:1;
> >  		u32     fpReadAcrossStripe:1;
> >  		u32     fpWriteAcrossStripe:1;
> > @@ -570,7 +666,8 @@ struct MR_LD_RAID {
> >  		u32     fpWriteAcrossStripe:1;
> >  		u32     fpReadAcrossStripe:1;
> >  		u32	fpNonRWCapable:1;
> > -		u32     reserved4:7;
> > +		u32     tmCapable:1;
> > +		u32     reserved4:6;
> >  #endif
> >  	} capability;
> >  	__le32     reserved6;
> > @@ -695,6 +792,7 @@ struct megasas_cmd_fusion {
> >  	u32 sync_cmd_idx;
> >  	u32 index;
> >  	u8 pd_r1_lb;
> > +	struct completion done;
> >  };
> >
> >  struct LD_LOAD_BALANCE_INFO {
> > @@ -808,9 +906,18 @@ struct MR_FW_RAID_MAP_EXT {
> >   *  * define MR_PD_CFG_SEQ structure for system PDs
> >   *   */
> >  struct MR_PD_CFG_SEQ {
> > -	__le16 seqNum;
> > -	__le16 devHandle;
> > -	u8  reserved[4];
> > +	u16 seqNum;
> > +	u16 devHandle;
> > +	struct {
> > +#if   defined(__BIG_ENDIAN_BITFIELD)
> > +		u8     reserved:7;
> > +		u8     tmCapable:1;
> > +#else
> > +		u8     tmCapable:1;
> > +		u8     reserved:7;
> > +#endif
> > +	} capability;
> > +	u8  reserved[3];
> >  } __packed;
> >
> >  struct MR_PD_CFG_SEQ_NUM_SYNC {

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 07/15] megaraid_sas: Reply Descriptor Post Queue(RDPQ) support
  2015-12-18 13:27 ` [PATCH 07/15] megaraid_sas: Reply Descriptor Post Queue(RDPQ) support Sumit Saxena
  2015-12-18 14:49   ` [PATCH] megaraid_sas: fix kzalloc-simple.cocci warnings kbuild test robot
  2015-12-18 14:49   ` [PATCH 07/15] megaraid_sas: Reply Descriptor Post Queue(RDPQ) support kbuild test robot
@ 2016-01-14 17:38   ` Tomas Henzl
  2016-01-27 18:15     ` Sumit Saxena
  2 siblings, 1 reply; 50+ messages in thread
From: Tomas Henzl @ 2016-01-14 17:38 UTC (permalink / raw)
  To: Sumit Saxena, jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai

On 18.12.2015 14:27, Sumit Saxena wrote:
> This patch will create reply queue pool for each MSI-x index and will provide array of all reply queue base address
> instead of single base address of legacy mode. Using this new interface Driver can support higher Queue depth allocating
> more reply queue as scattered DMA pool. 
>
> If array mode is not supported driver will fall back to legacy method of allocation reply pool. 
> This method fall back controller queue depth to 1K max. To enable more than 1K QD, driver expect FW to support Array mode 
> and scratch_pad3 should provide new queue depth value.
>
> Using this method, Firmware should not allow downgrade (OFU) if latest driver and latest FW report 4K QD and Array mode reply queue.
> This type of FW upgrade may cause firmware fault and it should not be supported. Upgrade of FW will work, 
> but queue depth of the controller will be unchanged until reboot/driver reload.
>
> Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
> Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
> ---
>  drivers/scsi/megaraid/megaraid_sas.h        |    6 +-
>  drivers/scsi/megaraid/megaraid_sas_base.c   |    9 +
>  drivers/scsi/megaraid/megaraid_sas_fusion.c |  543 +++++++++++++++------------
>  drivers/scsi/megaraid/megaraid_sas_fusion.h |   12 +-
>  4 files changed, 330 insertions(+), 240 deletions(-)
>
> diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
> index 01135be..c539516 100644
> --- a/drivers/scsi/megaraid/megaraid_sas.h
> +++ b/drivers/scsi/megaraid/megaraid_sas.h
> @@ -152,6 +152,7 @@
>  #define MFI_RESET_FLAGS				MFI_INIT_READY| \
>  						MFI_INIT_MFIMODE| \
>  						MFI_INIT_ABORT
> +#define MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE    (0x01)
>  
>  /*
>   * MFI frame flags
> @@ -1416,6 +1417,7 @@ enum DCMD_TIMEOUT_ACTION {
>  #define MR_MAX_REPLY_QUEUES_EXT_OFFSET          0X003FC000
>  #define MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT    14
>  #define MR_MAX_MSIX_REG_ARRAY                   16
> +#define MR_RDPQ_MODE_OFFSET			0X00800000
>  /*
>  * register set for both 1068 and 1078 controllers
>  * structure extended for 1078 registers
> @@ -1455,8 +1457,9 @@ struct megasas_register_set {
>  
>  	u32 	outbound_scratch_pad ;		/*00B0h*/
>  	u32	outbound_scratch_pad_2;         /*00B4h*/
> +	u32	outbound_scratch_pad_3;         /*00B8h*/
>  
> -	u32	reserved_4[2];			/*00B8h*/
> +	u32	reserved_4;			/*00BCh*/
>  
>  	u32 	inbound_low_queue_port ;	/*00C0h*/
>  
> @@ -2117,6 +2120,7 @@ struct megasas_instance {
>  	u8 mask_interrupts;
>  	u16 max_chain_frame_sz;
>  	u8 is_imr;
> +	u8 is_rdpq;
>  	bool dev_handle;
>  };
>  struct MR_LD_VF_MAP {
> diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
> index df93fa1..a3b63fa 100644
> --- a/drivers/scsi/megaraid/megaraid_sas_base.c
> +++ b/drivers/scsi/megaraid/megaraid_sas_base.c
> @@ -92,6 +92,10 @@ int smp_affinity_enable = 1;
>  module_param(smp_affinity_enable, int, S_IRUGO);
>  MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disbale Default: enable(1)");
>  
> +int rdpq_enable = 1;
> +module_param(rdpq_enable, int, S_IRUGO);
> +MODULE_PARM_DESC(rdpq_enable, " Allocate reply queue in chunks for large queue depth enable/disbale Default: disable(0)");

Is it enabled or disabled by default (-> int rdpq_enable = 1;) ? also fix 'disbale'

> +
>  MODULE_LICENSE("GPL");
>  MODULE_VERSION(MEGASAS_VERSION);
>  MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com");
> @@ -5081,6 +5085,9 @@ static int megasas_init_fw(struct megasas_instance *instance)
>  				instance->msix_vectors = ((scratch_pad_2
>  					& MR_MAX_REPLY_QUEUES_EXT_OFFSET)
>  					>> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1;
> +				if (rdpq_enable)
> +					instance->is_rdpq = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ?
> +								1 : 0;
>  				fw_msix_count = instance->msix_vectors;
>  				/* Save 1-15 reply post index address to local memory
>  				 * Index 0 is already saved from reg offset
> @@ -5117,6 +5124,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
>  	dev_info(&instance->pdev->dev,
>  		"current msix/online cpus\t: (%d/%d)\n",
>  		instance->msix_vectors, (unsigned int)num_online_cpus());
> +	dev_info(&instance->pdev->dev,
> +		"firmware supports rdpq mode\t: (%d)\n", instance->is_rdpq);

just a nit, but is_rdpq depends also on rdpq_enable, so the text is not precise

>  
>  	tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
>  		(unsigned long)instance);
> diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> index e8730ef..aca0cd3 100644
> --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
> +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> @@ -92,6 +92,8 @@ void megasas_start_timer(struct megasas_instance *instance,
>  			 void *fn, unsigned long interval);
>  extern struct megasas_mgmt_info megasas_mgmt_info;
>  extern int resetwaittime;
> +static void megasas_free_rdpq_fusion(struct megasas_instance *instance);
> +static void megasas_free_reply_fusion(struct megasas_instance *instance);
>  
>  
>  
> @@ -205,112 +207,71 @@ megasas_fire_cmd_fusion(struct megasas_instance *instance,
>  #endif
>  }
>  
> -
>  /**
> - * megasas_teardown_frame_pool_fusion -	Destroy the cmd frame DMA pool
> - * @instance:				Adapter soft state
> + * megasas_free_cmds_fusion -	Free all the cmds in the free cmd pool
> + * @instance:		Adapter soft state
>   */
> -static void megasas_teardown_frame_pool_fusion(
> -	struct megasas_instance *instance)
> +void
> +megasas_free_cmds_fusion(struct megasas_instance *instance)
>  {
>  	int i;
>  	struct fusion_context *fusion = instance->ctrl_context;
> -
> -	u16 max_cmd = instance->max_fw_cmds;
> -
>  	struct megasas_cmd_fusion *cmd;
>  
> -	if (!fusion->sg_dma_pool || !fusion->sense_dma_pool) {
> -		dev_err(&instance->pdev->dev, "dma pool is null. SG Pool %p, "
> -		       "sense pool : %p\n", fusion->sg_dma_pool,
> -		       fusion->sense_dma_pool);
> -		return;
> -	}
> -
> -	/*
> -	 * Return all frames to pool
> -	 */
> -	for (i = 0; i < max_cmd; i++) {
> -
> +	/* SG, Sense */
> +	for (i = 0; i < instance->max_fw_cmds; i++) {
>  		cmd = fusion->cmd_list[i];

cmd might be NULL here, add a test please

> -
>  		if (cmd->sg_frame)
>  			pci_pool_free(fusion->sg_dma_pool, cmd->sg_frame,
> -				      cmd->sg_frame_phys_addr);
> -
> +			      cmd->sg_frame_phys_addr);
>  		if (cmd->sense)
>  			pci_pool_free(fusion->sense_dma_pool, cmd->sense,
> -				      cmd->sense_phys_addr);
> +			      cmd->sense_phys_addr);
>  	}
>  
> -	/*
> -	 * Now destroy the pool itself
> -	 */
> -	pci_pool_destroy(fusion->sg_dma_pool);
> -	pci_pool_destroy(fusion->sense_dma_pool);
> -
> -	fusion->sg_dma_pool = NULL;
> -	fusion->sense_dma_pool = NULL;
> -}
> -
> -/**
> - * megasas_free_cmds_fusion -	Free all the cmds in the free cmd pool
> - * @instance:		Adapter soft state
> - */
> -void
> -megasas_free_cmds_fusion(struct megasas_instance *instance)
> -{
> -	int i;
> -	struct fusion_context *fusion = instance->ctrl_context;
> -
> -	u32 max_cmds, req_sz, reply_sz, io_frames_sz;
> -
> +	if (fusion->sg_dma_pool) {
> +		pci_pool_destroy(fusion->sg_dma_pool);
> +		fusion->sg_dma_pool = NULL;
> +	}
> +	if (fusion->sense_dma_pool) {
> +		pci_pool_destroy(fusion->sense_dma_pool);
> +		fusion->sense_dma_pool = NULL;

If this is needed (fusion->sense_dma_pool = NULL;), why don't we need
it few lines below for example for fusion->io_request_frames_pool ?
(there should be some consistency here)
 

> +	}
>  
> -	req_sz = fusion->request_alloc_sz;
> -	reply_sz = fusion->reply_alloc_sz;
> -	io_frames_sz = fusion->io_frames_alloc_sz;
>  
> -	max_cmds = instance->max_fw_cmds;
> +	/* Reply Frame, Desc*/
> +	if (instance->is_rdpq)
> +		megasas_free_rdpq_fusion(instance);
> +	else
> +		megasas_free_reply_fusion(instance);
>  
> -	/* Free descriptors and request Frames memory */
> +	/* Request Frame, Desc*/
>  	if (fusion->req_frames_desc)
> -		dma_free_coherent(&instance->pdev->dev, req_sz,
> -				  fusion->req_frames_desc,
> -				  fusion->req_frames_desc_phys);
> -
> -	if (fusion->reply_frames_desc) {
> -		pci_pool_free(fusion->reply_frames_desc_pool,
> -			      fusion->reply_frames_desc,
> -			      fusion->reply_frames_desc_phys);
> -		pci_pool_destroy(fusion->reply_frames_desc_pool);
> -	}
> -
> -	if (fusion->io_request_frames) {
> +		dma_free_coherent(&instance->pdev->dev,
> +			fusion->request_alloc_sz, fusion->req_frames_desc,
> +			fusion->req_frames_desc_phys);
> +	if (fusion->io_request_frames)
>  		pci_pool_free(fusion->io_request_frames_pool,
> -			      fusion->io_request_frames,
> -			      fusion->io_request_frames_phys);
> +			fusion->io_request_frames,
> +			fusion->io_request_frames_phys);
> +	if (fusion->io_request_frames_pool)
>  		pci_pool_destroy(fusion->io_request_frames_pool);
> -	}
>  
> -	/* Free the Fusion frame pool */
> -	megasas_teardown_frame_pool_fusion(instance);
>  
> -	/* Free all the commands in the cmd_list */
> -	for (i = 0; i < max_cmds; i++)
> +	/* cmd_list */
> +	for (i = 0; i < instance->max_fw_cmds; i++)
>  		kfree(fusion->cmd_list[i]);
>  
> -	/* Free the cmd_list buffer itself */
>  	kfree(fusion->cmd_list);
>  	fusion->cmd_list = NULL;

It is a good idea to set (fusion->cmd_list = NULL;), but a test
to the kfree should be added  

> -
>  }
>  
>  /**
> - * megasas_create_frame_pool_fusion -	Creates DMA pool for cmd frames
> + * megasas_create_sg_sense_fusion -	Creates DMA pool for cmd frames
>   * @instance:			Adapter soft state
>   *
>   */
> -static int megasas_create_frame_pool_fusion(struct megasas_instance *instance)
> +static int megasas_create_sg_sense_fusion(struct megasas_instance *instance)
>  {
>  	int i;
>  	u32 max_cmd;
> @@ -321,186 +282,299 @@ static int megasas_create_frame_pool_fusion(struct megasas_instance *instance)
>  	max_cmd = instance->max_fw_cmds;
>  
>  
> -	/*
> -	 * Use DMA pool facility provided by PCI layer
> -	 */
> -
> -	fusion->sg_dma_pool = pci_pool_create("sg_pool_fusion", instance->pdev,
> -						instance->max_chain_frame_sz,
> -						4, 0);
> -	if (!fusion->sg_dma_pool) {
> -		dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup request pool fusion\n");
> -		return -ENOMEM;
> -	}
> -	fusion->sense_dma_pool = pci_pool_create("sense pool fusion",
> -						 instance->pdev,
> -						 SCSI_SENSE_BUFFERSIZE, 64, 0);
> +	fusion->sg_dma_pool =
> +			pci_pool_create("mr_sg", instance->pdev,
> +				instance->max_chain_frame_sz, 4, 0);
> +	/* SCSI_SENSE_BUFFERSIZE  = 96 bytes */
> +	fusion->sense_dma_pool =
> +			pci_pool_create("mr_sense", instance->pdev,
> +				SCSI_SENSE_BUFFERSIZE, 64, 0);
>  
> -	if (!fusion->sense_dma_pool) {
> -		dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup sense pool fusion\n");
> -		pci_pool_destroy(fusion->sg_dma_pool);
> -		fusion->sg_dma_pool = NULL;
> -		return -ENOMEM;
> -	}
> +	if (!fusion->sense_dma_pool || !fusion->sg_dma_pool)
> +		dev_err(&instance->pdev->dev,
> +			"Failed from %s %d\n",  __func__, __LINE__);

Allocation failed - I don't think we can ignore it.

>  
>  	/*
>  	 * Allocate and attach a frame to each of the commands in cmd_list
>  	 */
>  	for (i = 0; i < max_cmd; i++) {
> -
>  		cmd = fusion->cmd_list[i];
> -
>  		cmd->sg_frame = pci_pool_alloc(fusion->sg_dma_pool,
> -					       GFP_KERNEL,
> -					       &cmd->sg_frame_phys_addr);
> +					GFP_KERNEL, &cmd->sg_frame_phys_addr);
>  
>  		cmd->sense = pci_pool_alloc(fusion->sense_dma_pool,
> -					    GFP_KERNEL, &cmd->sense_phys_addr);
> -		/*
> -		 * megasas_teardown_frame_pool_fusion() takes care of freeing
> -		 * whatever has been allocated
> -		 */
> +					GFP_KERNEL, &cmd->sense_phys_addr);
>  		if (!cmd->sg_frame || !cmd->sense) {
> -			dev_printk(KERN_DEBUG, &instance->pdev->dev, "pci_pool_alloc failed\n");
> -			megasas_teardown_frame_pool_fusion(instance);
> +			dev_err(&instance->pdev->dev,
> +				"Failed from %s %d\n",  __func__, __LINE__);
>  			return -ENOMEM;
>  		}
>  	}
>  	return 0;
>  }
>  
> -/**
> - * megasas_alloc_cmds_fusion -	Allocates the command packets
> - * @instance:		Adapter soft state
> - *
> - *
> - * Each frame has a 32-bit field called context. This context is used to get
> - * back the megasas_cmd_fusion from the frame when a frame gets completed
> - * In this driver, the 32 bit values are the indices into an array cmd_list.
> - * This array is used only to look up the megasas_cmd_fusion given the context.
> - * The free commands themselves are maintained in a linked list called cmd_pool.
> - *
> - * cmds are formed in the io_request and sg_frame members of the
> - * megasas_cmd_fusion. The context field is used to get a request descriptor
> - * and is used as SMID of the cmd.
> - * SMID value range is from 1 to max_fw_cmds.
> - */
>  int
> -megasas_alloc_cmds_fusion(struct megasas_instance *instance)
> +megasas_alloc_cmdlist_fusion(struct megasas_instance *instance)
>  {
> -	int i, j, count;
> -	u32 max_cmd, io_frames_sz;
> +	u32 max_cmd, i;
>  	struct fusion_context *fusion;
> -	struct megasas_cmd_fusion *cmd;
> -	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
> -	u32 offset;
> -	dma_addr_t io_req_base_phys;
> -	u8 *io_req_base;
>  
>  	fusion = instance->ctrl_context;
>  
>  	max_cmd = instance->max_fw_cmds;
>  
> +	/*
> +	 * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers.
> +	 * Allocate the dynamic array first and then allocate individual
> +	 * commands.
> +	 */
> +	fusion->cmd_list = kmalloc(sizeof(struct megasas_cmd_fusion *) * max_cmd,
> +						GFP_KERNEL);
> +	if (!fusion->cmd_list) {
> +		dev_err(&instance->pdev->dev,
> +			"Failed from %s %d\n",  __func__, __LINE__);
> +		return -ENOMEM;
> +	}
> +	memset(fusion->cmd_list, 0,
> +		sizeof(struct megasas_cmd_fusion *) * max_cmd);
> +
> +	for (i = 0; i < max_cmd; i++) {
> +		fusion->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd_fusion),
> +					      GFP_KERNEL);

kzalloc here and there, as the kbuild script already wrote

> +		if (!fusion->cmd_list[i]) {
> +			dev_err(&instance->pdev->dev,
> +				"Failed from %s %d\n",  __func__, __LINE__);
> +			return -ENOMEM;
> +		}
> +		memset(fusion->cmd_list[i], 0, sizeof(struct megasas_cmd_fusion));
> +	}
> +	return 0;
> +}
> +int
> +megasas_alloc_request_fusion(struct megasas_instance *instance)
> +{
> +	struct fusion_context *fusion;
> +
> +	fusion = instance->ctrl_context;
> +
>  	fusion->req_frames_desc =
>  		dma_alloc_coherent(&instance->pdev->dev,
> -				   fusion->request_alloc_sz,
> -				   &fusion->req_frames_desc_phys, GFP_KERNEL);
> -
> +			fusion->request_alloc_sz,
> +			&fusion->req_frames_desc_phys, GFP_KERNEL);
>  	if (!fusion->req_frames_desc) {
> -		dev_err(&instance->pdev->dev, "Could not allocate memory for "
> -		       "request_frames\n");
> -		goto fail_req_desc;
> +		dev_err(&instance->pdev->dev,
> +			"Failed from %s %d\n",  __func__, __LINE__);
> +		return -ENOMEM;
> +	}
> +
> +	fusion->io_request_frames_pool =
> +			pci_pool_create("mr_ioreq", instance->pdev,
> +				fusion->io_frames_alloc_sz, 16, 0);

Why do you need a pool, you just allocate once a single region, or not?
Please turn it into a dma_alloc_coherent.

> +
> +	if (!fusion->io_request_frames_pool) {
> +		dev_err(&instance->pdev->dev,
> +			"Failed from %s %d\n",  __func__, __LINE__);
> +		return -ENOMEM;
> +	}
> +
> +	fusion->io_request_frames =
> +			pci_pool_alloc(fusion->io_request_frames_pool,
> +				GFP_KERNEL, &fusion->io_request_frames_phys);
> +	if (!fusion->io_request_frames) {
> +		dev_err(&instance->pdev->dev,
> +			"Failed from %s %d\n",  __func__, __LINE__);
> +		return -ENOMEM;
>  	}
> +	return 0;
> +}
> +
> +int
> +megasas_alloc_reply_fusion(struct megasas_instance *instance)
> +{
> +	int i, count;
> +	struct fusion_context *fusion;
> +	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
> +	fusion = instance->ctrl_context;
>  
>  	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
>  	fusion->reply_frames_desc_pool =
> -		pci_pool_create("reply_frames pool", instance->pdev,
> +			pci_pool_create("mr_reply", instance->pdev,
>  				fusion->reply_alloc_sz * count, 16, 0);
>  
>  	if (!fusion->reply_frames_desc_pool) {
> -		dev_err(&instance->pdev->dev, "Could not allocate memory for "
> -		       "reply_frame pool\n");
> -		goto fail_reply_desc;
> +		dev_err(&instance->pdev->dev,
> +			"Failed from %s %d\n",  __func__, __LINE__);
> +		return -ENOMEM;
>  	}

Same here, I could understand it if the code were merged with megasas_alloc_rdpq_fusion
but it is not. Why a pool?

>  
> -	fusion->reply_frames_desc =
> -		pci_pool_alloc(fusion->reply_frames_desc_pool, GFP_KERNEL,
> -			       &fusion->reply_frames_desc_phys);
> -	if (!fusion->reply_frames_desc) {
> -		dev_err(&instance->pdev->dev, "Could not allocate memory for "
> -		       "reply_frame pool\n");
> -		pci_pool_destroy(fusion->reply_frames_desc_pool);
> -		goto fail_reply_desc;
> +	fusion->reply_frames_desc[0] =
> +		pci_pool_alloc(fusion->reply_frames_desc_pool,
> +			GFP_KERNEL, &fusion->reply_frames_desc_phys[0]);
> +	if (!fusion->reply_frames_desc[0]) {
> +		dev_err(&instance->pdev->dev,
> +			"Failed from %s %d\n",  __func__, __LINE__);
> +		return -ENOMEM;
>  	}
> -
> -	reply_desc = fusion->reply_frames_desc;
> +	reply_desc = fusion->reply_frames_desc[0];
>  	for (i = 0; i < fusion->reply_q_depth * count; i++, reply_desc++)
> -		reply_desc->Words = cpu_to_le64(ULLONG_MAX);
> +		reply_desc->Words = ULLONG_MAX;

The megasas_reset_reply_desc function seems to be used for this kind of resetting,
could it be used here ? (and in megasas_alloc_rdpq_fusion)
There you also kept the cpu_to_le64(..) that doesn't matter,
but again for consistency...

>  
> -	io_frames_sz = fusion->io_frames_alloc_sz;
> +	/* This is not a rdpq mode, but driver still populate
> +	 * reply_frame_desc array to use same msix index in ISR path.
> +	 */
> +	for (i = 0; i < (count - 1); i++)
> +		fusion->reply_frames_desc[i + 1] =
> +			fusion->reply_frames_desc[i] +
> +			(fusion->reply_alloc_sz)/sizeof(union MPI2_REPLY_DESCRIPTORS_UNION);
>  
> -	fusion->io_request_frames_pool =
> -		pci_pool_create("io_request_frames pool", instance->pdev,
> -				fusion->io_frames_alloc_sz, 16, 0);
> +	return 0;
> +}
>  
> -	if (!fusion->io_request_frames_pool) {
> -		dev_err(&instance->pdev->dev, "Could not allocate memory for "
> -		       "io_request_frame pool\n");
> -		goto fail_io_frames;
> +int
> +megasas_alloc_rdpq_fusion(struct megasas_instance *instance)
> +{
> +	int i, j, count;
> +	struct fusion_context *fusion;
> +	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
> +
> +	fusion = instance->ctrl_context;
> +
> +	fusion->rdpq_virt = pci_alloc_consistent(instance->pdev,
> +				sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION,

is dma_alloc_coherent possible here?

> +				&fusion->rdpq_phys);
> +	if (!fusion->rdpq_virt) {
> +		dev_err(&instance->pdev->dev,
> +			"Failed from %s %d\n",  __func__, __LINE__);
> +		return -ENOMEM;
>  	}
>  
> -	fusion->io_request_frames =
> -		pci_pool_alloc(fusion->io_request_frames_pool, GFP_KERNEL,
> -			       &fusion->io_request_frames_phys);
> -	if (!fusion->io_request_frames) {
> -		dev_err(&instance->pdev->dev, "Could not allocate memory for "
> -		       "io_request_frames frames\n");
> -		pci_pool_destroy(fusion->io_request_frames_pool);
> -		goto fail_io_frames;
> +	memset(fusion->rdpq_virt, 0,
> +			sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION);
> +	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
> +	fusion->reply_frames_desc_pool = pci_pool_create("mr_rdpq",
> +							 instance->pdev, fusion->reply_alloc_sz, 16, 0);
> +
> +	if (!fusion->reply_frames_desc_pool) {
> +		dev_err(&instance->pdev->dev,
> +			"Failed from %s %d\n",  __func__, __LINE__);
> +		return -ENOMEM;
>  	}
>  
> -	/*
> -	 * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers.
> -	 * Allocate the dynamic array first and then allocate individual
> -	 * commands.
> -	 */
> -	fusion->cmd_list = kzalloc(sizeof(struct megasas_cmd_fusion *)
> -				   * max_cmd, GFP_KERNEL);
> +	for (i = 0; i < count; i++) {
> +		fusion->reply_frames_desc[i] =
> +				pci_pool_alloc(fusion->reply_frames_desc_pool,
> +					GFP_KERNEL, &fusion->reply_frames_desc_phys[i]);
> +		if (!fusion->reply_frames_desc[i]) {
> +			dev_err(&instance->pdev->dev,
> +				"Failed from %s %d\n",  __func__, __LINE__);
> +			return -ENOMEM;
> +		}
>  
> -	if (!fusion->cmd_list) {
> -		dev_printk(KERN_DEBUG, &instance->pdev->dev, "out of memory. Could not alloc "
> -		       "memory for cmd_list_fusion\n");
> -		goto fail_cmd_list;
> +		fusion->rdpq_virt[i].RDPQBaseAddress =
> +			fusion->reply_frames_desc_phys[i];
> +
> +		reply_desc = fusion->reply_frames_desc[i];
> +		for (j = 0; j < fusion->reply_q_depth; j++, reply_desc++)
> +			reply_desc->Words = ULLONG_MAX;
>  	}
> +	return 0;
> +}
>  
> -	max_cmd = instance->max_fw_cmds;
> -	for (i = 0; i < max_cmd; i++) {
> -		fusion->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd_fusion),
> -					      GFP_KERNEL);
> -		if (!fusion->cmd_list[i]) {
> -			dev_err(&instance->pdev->dev, "Could not alloc cmd list fusion\n");
> +static void
> +megasas_free_rdpq_fusion(struct megasas_instance *instance) {
>  
> -			for (j = 0; j < i; j++)
> -				kfree(fusion->cmd_list[j]);
> +	int i;
> +	struct fusion_context *fusion;
>  
> -			kfree(fusion->cmd_list);
> -			fusion->cmd_list = NULL;
> -			goto fail_cmd_list;
> -		}
> +	fusion = instance->ctrl_context;
> +
> +	for (i = 0; i < MAX_MSIX_QUEUES_FUSION; i++) {
> +		if (fusion->reply_frames_desc[i])
> +			pci_pool_free(fusion->reply_frames_desc_pool,
> +				fusion->reply_frames_desc[i],
> +				fusion->reply_frames_desc_phys[i]);
>  	}
>  
> -	/* The first 256 bytes (SMID 0) is not used. Don't add to cmd list */
> -	io_req_base = fusion->io_request_frames +
> -		MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
> -	io_req_base_phys = fusion->io_request_frames_phys +
> -		MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
> +	if (fusion->reply_frames_desc_pool)
> +		pci_pool_destroy(fusion->reply_frames_desc_pool);
> +
> +	if (fusion->rdpq_virt)
> +		pci_free_consistent(instance->pdev,
> +			sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION,
> +			fusion->rdpq_virt, fusion->rdpq_phys);
> +}
> +
> +static void
> +megasas_free_reply_fusion(struct megasas_instance *instance) {
> +
> +	struct fusion_context *fusion;
> +
> +	fusion = instance->ctrl_context;
> +
> +	if (fusion->reply_frames_desc[0])
> +		pci_pool_free(fusion->reply_frames_desc_pool,
> +			fusion->reply_frames_desc[0],
> +			fusion->reply_frames_desc_phys[0]);
> +
> +	if (fusion->reply_frames_desc_pool)
> +		pci_pool_destroy(fusion->reply_frames_desc_pool);
> +
> +}
> +
> +
> +/**
> + * megasas_alloc_cmds_fusion -	Allocates the command packets
> + * @instance:		Adapter soft state
> + *
> + *
> + * Each frame has a 32-bit field called context. This context is used to get
> + * back the megasas_cmd_fusion from the frame when a frame gets completed
> + * In this driver, the 32 bit values are the indices into an array cmd_list.
> + * This array is used only to look up the megasas_cmd_fusion given the context.
> + * The free commands themselves are maintained in a linked list called cmd_pool.
> + *
> + * cmds are formed in the io_request and sg_frame members of the
> + * megasas_cmd_fusion. The context field is used to get a request descriptor
> + * and is used as SMID of the cmd.
> + * SMID value range is from 1 to max_fw_cmds.
> + */
> +int
> +megasas_alloc_cmds_fusion(struct megasas_instance *instance)
> +{
> +	int i;
> +	struct fusion_context *fusion;
> +	struct megasas_cmd_fusion *cmd;
> +	u32 offset;
> +	dma_addr_t io_req_base_phys;
> +	u8 *io_req_base;
> +
> +
> +	fusion = instance->ctrl_context;
> +
> +	if (megasas_alloc_cmdlist_fusion(instance))

We may need to call megasas_free_cmds_fusion here too
(to free fusion->cmd_list)

> +		return -ENOMEM;
> +
> +	if (megasas_alloc_request_fusion(instance))
> +		goto fail_exit;
> +
> +	if (instance->is_rdpq) {
> +		if (megasas_alloc_rdpq_fusion(instance))
> +			goto fail_exit;
> +	} else
> +		if (megasas_alloc_reply_fusion(instance))
> +			goto fail_exit;
> +
> +
> +	/* The first 256 bytes (SMID 0) is not used. Don't add to the cmd list */
> +	io_req_base = fusion->io_request_frames + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
> +	io_req_base_phys = fusion->io_request_frames_phys + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
>  
>  	/*
>  	 * Add all the commands to command pool (fusion->cmd_pool)
>  	 */
>  
>  	/* SMID 0 is reserved. Set SMID/index from 1 */
> -	for (i = 0; i < max_cmd; i++) {
> +	for (i = 0; i < instance->max_fw_cmds; i++) {
>  		cmd = fusion->cmd_list[i];
>  		offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i;
>  		memset(cmd, 0, sizeof(struct megasas_cmd_fusion));

That memset was already done in megasas_alloc_cmdlist_fusion

> @@ -518,35 +592,13 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance)
>  		cmd->io_request_phys_addr = io_req_base_phys + offset;
>  	}/
>  
> -	/*
> -	 * Create a frame pool and assign one frame to each cmd
> -	 */
> -	if (megasas_create_frame_pool_fusion(instance)) {
> -		dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error creating frame DMA pool\n");
> -		megasas_free_cmds_fusion(instance);
> -		goto fail_req_desc;
> -	}
> +	if (megasas_create_sg_sense_fusion(instance))
> +		goto fail_exit;
>  
>  	return 0;
>  
> -fail_cmd_list:
> -	pci_pool_free(fusion->io_request_frames_pool, fusion->io_request_frames,
> -		      fusion->io_request_frames_phys);
> -	pci_pool_destroy(fusion->io_request_frames_pool);
> -fail_io_frames:
> -	dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
> -			  fusion->reply_frames_desc,
> -			  fusion->reply_frames_desc_phys);
> -	pci_pool_free(fusion->reply_frames_desc_pool,
> -		      fusion->reply_frames_desc,
> -		      fusion->reply_frames_desc_phys);
> -	pci_pool_destroy(fusion->reply_frames_desc_pool);
> -
> -fail_reply_desc:
> -	dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
> -			  fusion->req_frames_desc,
> -			  fusion->req_frames_desc_phys);
> -fail_req_desc:
> +fail_exit:
> +	megasas_free_cmds_fusion(instance);
>  	return -ENOMEM;
>  }
>  
> @@ -594,16 +646,17 @@ int
>  megasas_ioc_init_fusion(struct megasas_instance *instance)
>  {
>  	struct megasas_init_frame *init_frame;
> -	struct MPI2_IOC_INIT_REQUEST *IOCInitMessage;
> +	struct MPI2_IOC_INIT_REQUEST *IOCInitMessage = NULL;
>  	dma_addr_t	ioc_init_handle;
>  	struct megasas_cmd *cmd;
> -	u8 ret;
> +	u8 ret, cur_rdpq_mode;
>  	struct fusion_context *fusion;
>  	union MEGASAS_REQUEST_DESCRIPTOR_UNION req_desc;
>  	int i;
>  	struct megasas_header *frame_hdr;
>  	const char *sys_info;
>  	MFI_CAPABILITIES *drv_ops;
> +	u32 scratch_pad_2;
>  
>  	fusion = instance->ctrl_context;
>  
> @@ -615,6 +668,18 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
>  		goto fail_get_cmd;
>  	}
>  
> +	scratch_pad_2 = readl
> +		(&instance->reg_set->outbound_scratch_pad_2);
> +
> +	cur_rdpq_mode = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ? 1 : 0;
> +
> +	if (instance->is_rdpq && !cur_rdpq_mode) {
> +		dev_err(&instance->pdev->dev, "Firmware downgrade *NOT SUPPORTED*"
> +			" from RDPQ mode to non RDPQ mode\n");

How does this work ? is_rdpq is set in megasas_init_fw only when the fw
supports it, why do you test it here again ? I think I'm miss something.

Tomas

> +		ret = 1;
> +		goto fail_fw_init;
> +	}
> +
>  	IOCInitMessage =
>  	  dma_alloc_coherent(&instance->pdev->dev,
>  			     sizeof(struct MPI2_IOC_INIT_REQUEST),
> @@ -636,7 +701,11 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
>  	IOCInitMessage->SystemRequestFrameSize = cpu_to_le16(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4);
>  
>  	IOCInitMessage->ReplyDescriptorPostQueueDepth = cpu_to_le16(fusion->reply_q_depth);
> -	IOCInitMessage->ReplyDescriptorPostQueueAddress	= cpu_to_le64(fusion->reply_frames_desc_phys);
> +	IOCInitMessage->ReplyDescriptorPostQueueAddress = instance->is_rdpq ?
> +			cpu_to_le64(fusion->rdpq_phys) :
> +			cpu_to_le64(fusion->reply_frames_desc_phys[0]);
> +	IOCInitMessage->MsgFlags = instance->is_rdpq ?
> +			MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE : 0;
>  	IOCInitMessage->SystemRequestFrameBaseAddress = cpu_to_le64(fusion->io_request_frames_phys);
>  	IOCInitMessage->HostMSIxVectors = instance->msix_vectors;
>  	init_frame = (struct megasas_init_frame *)cmd->frame;
> @@ -1087,7 +1156,10 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
>  	 */
>  	instance->max_fw_cmds =
>  		instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
> -	instance->max_fw_cmds = min(instance->max_fw_cmds, (u16)1008);
> +	dev_info(&instance->pdev->dev,
> +		"firmware support max fw cmd\t: (%d)\n", instance->max_fw_cmds);
> +	if (!instance->is_rdpq)
> +		instance->max_fw_cmds = min_t(u16, instance->max_fw_cmds, 1024);
>  
>  	/*
>  	 * Reduce the max supported cmds by 1. This is to ensure that the
> @@ -2110,10 +2182,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
>  	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
>  		return IRQ_HANDLED;
>  
> -	desc = fusion->reply_frames_desc;
> -	desc += ((MSIxIndex * fusion->reply_alloc_sz)/
> -		 sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)) +
> -		fusion->last_reply_idx[MSIxIndex];
> +	desc = fusion->reply_frames_desc[MSIxIndex] +
> +				fusion->last_reply_idx[MSIxIndex];
>  
>  	reply_desc = (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc;
>  
> @@ -2208,9 +2278,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
>  
>  		/* Get the next reply descriptor */
>  		if (!fusion->last_reply_idx[MSIxIndex])
> -			desc = fusion->reply_frames_desc +
> -				((MSIxIndex * fusion->reply_alloc_sz)/
> -				 sizeof(union MPI2_REPLY_DESCRIPTORS_UNION));
> +			desc = fusion->reply_frames_desc[MSIxIndex];
>  		else
>  			desc++;
>  
> @@ -2688,17 +2756,18 @@ out:
>  
>  void  megasas_reset_reply_desc(struct megasas_instance *instance)
>  {
> -	int i, count;
> +	int i, j, count;
>  	struct fusion_context *fusion;
>  	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
>  
>  	fusion = instance->ctrl_context;
>  	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
> -	for (i = 0 ; i < count ; i++)
> +	for (i = 0 ; i < count ; i++) {
>  		fusion->last_reply_idx[i] = 0;
> -	reply_desc = fusion->reply_frames_desc;
> -	for (i = 0 ; i < fusion->reply_q_depth * count; i++, reply_desc++)
> -		reply_desc->Words = cpu_to_le64(ULLONG_MAX);
> +		reply_desc = fusion->reply_frames_desc[i];
> +		for (j = 0 ; j < fusion->reply_q_depth; j++, reply_desc++)
> +			reply_desc->Words = cpu_to_le64(ULLONG_MAX);
> +	}
>  }
>  
>  /*
> diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
> index db0978d..80eaee2 100644
> --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
> +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
> @@ -928,6 +928,12 @@ struct MR_PD_CFG_SEQ_NUM_SYNC {
>  	struct MR_PD_CFG_SEQ seq[1];
>  } __packed;
>  
> +struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY {
> +	u64 RDPQBaseAddress;
> +	u32 Reserved1;
> +	u32 Reserved2;
> +};
> +
>  struct fusion_context {
>  	struct megasas_cmd_fusion **cmd_list;
>  	dma_addr_t req_frames_desc_phys;
> @@ -940,8 +946,8 @@ struct fusion_context {
>  	struct dma_pool *sg_dma_pool;
>  	struct dma_pool *sense_dma_pool;
>  
> -	dma_addr_t reply_frames_desc_phys;
> -	union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc;
> +	dma_addr_t reply_frames_desc_phys[MAX_MSIX_QUEUES_FUSION];
> +	union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc[MAX_MSIX_QUEUES_FUSION];
>  	struct dma_pool *reply_frames_desc_pool;
>  
>  	u16 last_reply_idx[MAX_MSIX_QUEUES_FUSION];
> @@ -951,6 +957,8 @@ struct fusion_context {
>  	u32 reply_alloc_sz;
>  	u32 io_frames_alloc_sz;
>  
> +	struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY *rdpq_virt;
> +	dma_addr_t rdpq_phys;
>  	u16	max_sge_in_main_msg;
>  	u16	max_sge_in_chain;
>  


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 08/15] megaraid_sas: Code optimization build_and_issue_cmd return-type
  2015-12-18 13:27 ` [PATCH 08/15] megaraid_sas: Code optimization build_and_issue_cmd return-type Sumit Saxena
@ 2016-01-14 18:05   ` Tomas Henzl
  0 siblings, 0 replies; 50+ messages in thread
From: Tomas Henzl @ 2016-01-14 18:05 UTC (permalink / raw)
  To: Sumit Saxena, jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai

On 18.12.2015 14:27, Sumit Saxena wrote:
> build_and_issue_cmd should return SCSI_MLQUEUE_HOST_BUSY for few error case instead of returning 1.
>
> Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>

Reviewed-by: Tomas Henzl <thenzl@redhat.com>

Tomas


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 09/15] megaraid_sas: Dual Queue depth support
  2015-12-18 13:27 ` [PATCH 09/15] megaraid_sas: Dual Queue depth support Sumit Saxena
@ 2016-01-19 13:34   ` Tomas Henzl
  2016-01-19 13:44     ` Sumit Saxena
  0 siblings, 1 reply; 50+ messages in thread
From: Tomas Henzl @ 2016-01-19 13:34 UTC (permalink / raw)
  To: Sumit Saxena, jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai

On 18.12.2015 14:27, Sumit Saxena wrote:
> This patch will add support for Dual Queue depth reported by firmware.
>
> Below are key points-
>
> 1. For iMR controllers, firmware will report two queue depths- 1. Controller wide Queue depth 2. LDIO Queue depth(240).
> Ofcourse, Controller wide Queue depth will be greater among two. Using this new method, iMR can provide larger Queue depth(QD)
> for JBOD and limited QD for Virtual Disk(VD). This feature gives benefit for iMR product which will be used for deployment
> with large number of JBOD and limited number of VD on setup. 
> 2. megaraid_sas driver will throttle Read write LDIOs based when RW LDIOs reaches "LDIO Queue Depth".
> 3. This feature of dual queue depth can enabled/disabled via module parameter. Default behavior is: Dual Queue depth is enabled.
> 4. Added sysfs parameter "ldio_outstanding" for user to read LDIO outstanding at run time.
>
>
> Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
> Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
> ---
>  drivers/scsi/megaraid/megaraid_sas.h        |    9 +++
>  drivers/scsi/megaraid/megaraid_sas_base.c   |   20 ++++++-
>  drivers/scsi/megaraid/megaraid_sas_fusion.c |   89 ++++++++++++++++++++++++---
>  3 files changed, 108 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
> index c539516..4595ef4 100644
> --- a/drivers/scsi/megaraid/megaraid_sas.h
> +++ b/drivers/scsi/megaraid/megaraid_sas.h
> @@ -1353,6 +1353,12 @@ enum DCMD_TIMEOUT_ACTION {
>  	KILL_ADAPTER = 1,
>  	IGNORE_TIMEOUT = 2,
>  };
> +
> +enum FW_BOOT_CONTEXT {
> +	PROBE_CONTEXT = 0,
> +	OCR_CONTEXT = 1,
> +};
> +
>  /* Frame Type */
>  #define IO_FRAME				0
>  #define PTHRU_FRAME				1
> @@ -2038,6 +2044,8 @@ struct megasas_instance {
>  	u16 max_fw_cmds;
>  	u16 max_mfi_cmds;
>  	u16 max_scsi_cmds;
> +	u16 ldio_threshold;
> +	u16 cur_can_queue;
>  	u32 max_sectors_per_req;
>  	struct megasas_aen_event *ev;
>  
> @@ -2068,6 +2076,7 @@ struct megasas_instance {
>  	u32 fw_support_ieee;
>  
>  	atomic_t fw_outstanding;
> +	atomic_t ldio_outstanding;
>  	atomic_t fw_reset_no_pci_access;
>  
>  	struct megasas_instance_template *instancet;
> diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
> index 3454c5e..edc26fb 100644
> --- a/drivers/scsi/megaraid/megaraid_sas_base.c
> +++ b/drivers/scsi/megaraid/megaraid_sas_base.c
> @@ -96,6 +96,10 @@ int rdpq_enable = 1;
>  module_param(rdpq_enable, int, S_IRUGO);
>  MODULE_PARM_DESC(rdpq_enable, " Allocate reply queue in chunks for large queue depth enable/disbale Default: disable(0)");
>  
> +unsigned int dual_qdepth_disable;
> +module_param(dual_qdepth_disable, int, S_IRUGO);
> +MODULE_PARM_DESC(dual_qdepth_disable, "Disable dual queue depth feature. Default: 0");
> +
>  MODULE_LICENSE("GPL");
>  MODULE_VERSION(MEGASAS_VERSION);
>  MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com");
> @@ -1977,7 +1981,7 @@ megasas_check_and_restore_queue_depth(struct megasas_instance *instance)
>  		spin_lock_irqsave(instance->host->host_lock, flags);
>  		instance->flag &= ~MEGASAS_FW_BUSY;
>  
> -		instance->host->can_queue = instance->max_scsi_cmds;
> +		instance->host->can_queue = instance->cur_can_queue;
>  		spin_unlock_irqrestore(instance->host->host_lock, flags);
>  	}
>  }
> @@ -2942,6 +2946,16 @@ megasas_page_size_show(struct device *cdev,
>  	return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long)PAGE_SIZE - 1);
>  }
>  
> +static ssize_t
> +megasas_ldio_outstanding_show(struct device *cdev, struct device_attribute *attr,
> +	char *buf)
> +{
> +	struct Scsi_Host *shost = class_to_shost(cdev);
> +	struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata;
> +
> +	return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&instance->ldio_outstanding));
> +}
> +
>  static DEVICE_ATTR(fw_crash_buffer, S_IRUGO | S_IWUSR,
>  	megasas_fw_crash_buffer_show, megasas_fw_crash_buffer_store);
>  static DEVICE_ATTR(fw_crash_buffer_size, S_IRUGO,
> @@ -2950,12 +2964,15 @@ static DEVICE_ATTR(fw_crash_state, S_IRUGO | S_IWUSR,
>  	megasas_fw_crash_state_show, megasas_fw_crash_state_store);
>  static DEVICE_ATTR(page_size, S_IRUGO,
>  	megasas_page_size_show, NULL);
> +static DEVICE_ATTR(ldio_outstanding, S_IRUGO,
> +	megasas_ldio_outstanding_show, NULL);
>  
>  struct device_attribute *megaraid_host_attrs[] = {
>  	&dev_attr_fw_crash_buffer_size,
>  	&dev_attr_fw_crash_buffer,
>  	&dev_attr_fw_crash_state,
>  	&dev_attr_page_size,
> +	&dev_attr_ldio_outstanding,
>  	NULL,
>  };
>  
> @@ -4750,6 +4767,7 @@ megasas_init_adapter_mfi(struct megasas_instance *instance)
>  		sema_init(&instance->ioctl_sem, (MEGASAS_MFI_IOCTL_CMDS));
>  	}
>  
> +	instance->cur_can_queue = instance->max_scsi_cmds;
>  	/*
>  	 * Create a pool of commands
>  	 */
> diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> index 9ad779d..7cc7806 100644
> --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
> +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> @@ -92,6 +92,7 @@ void megasas_start_timer(struct megasas_instance *instance,
>  			 void *fn, unsigned long interval);
>  extern struct megasas_mgmt_info megasas_mgmt_info;
>  extern int resetwaittime;
> +extern unsigned int dual_qdepth_disable;
>  static void megasas_free_rdpq_fusion(struct megasas_instance *instance);
>  static void megasas_free_reply_fusion(struct megasas_instance *instance);
>  
> @@ -208,6 +209,67 @@ megasas_fire_cmd_fusion(struct megasas_instance *instance,
>  }
>  
>  /**
> + * megasas_fusion_update_can_queue -	Do all Adapter Queue depth related calculations here
> + * @instance:							Adapter soft state
> + * fw_boot_context:						Whether this function called during probe or after OCR
> + *
> + * This function is only for fusion controllers.
> + * Update host can queue, if firmware downgrade max supported firmware commands.
> + * Firmware upgrade case will be skiped because underlying firmware has
> + * more resource than exposed to the OS.
> + *
> + */
> +static void
> +megasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_context)
> +{
> +	u16 cur_max_fw_cmds = 0;
> +	u16 ldio_threshold = 0;
> +	struct megasas_register_set __iomem *reg_set;
> +
> +	reg_set = instance->reg_set;
> +
> +	cur_max_fw_cmds = readl(&instance->reg_set->outbound_scratch_pad_3) & 0x00FFFF;
> +
> +	if (dual_qdepth_disable || !cur_max_fw_cmds)
> +		cur_max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
> +	else
> +		ldio_threshold =
> +			(instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF) - MEGASAS_FUSION_IOCTL_CMDS;
> +
> +	dev_info(&instance->pdev->dev,
> +			"Current firmware maximum commands: %d\t LDIO thershold: %d\n",

a typo in "thershold"

> +			cur_max_fw_cmds, ldio_threshold);
> +
> +	if (fw_boot_context == OCR_CONTEXT) {
> +		cur_max_fw_cmds = cur_max_fw_cmds - 1;
> +		if (cur_max_fw_cmds <= instance->max_fw_cmds) {

probably '<' instead of '<=" could be here ?

> +			instance->cur_can_queue =
> +				cur_max_fw_cmds - (MEGASAS_FUSION_INTERNAL_CMDS +
> +						MEGASAS_FUSION_IOCTL_CMDS);
> +			instance->host->can_queue = instance->cur_can_queue;
> +			instance->ldio_threshold = ldio_threshold;
> +		}
> +	} else {
> +		instance->max_fw_cmds = cur_max_fw_cmds;
> +		instance->ldio_threshold = ldio_threshold;
> +
> +		if (!instance->is_rdpq)
> +			instance->max_fw_cmds = min_t(u16, instance->max_fw_cmds, 1024);
> +
> +		/*
> +		* Reduce the max supported cmds by 1. This is to ensure that the
> +		* reply_q_sz (1 more than the max cmd that driver may send)
> +		* does not exceed max cmds that the FW can support
> +		*/
> +		instance->max_fw_cmds = instance->max_fw_cmds-1;
> +
> +		instance->max_scsi_cmds = instance->max_fw_cmds -
> +				(MEGASAS_FUSION_INTERNAL_CMDS +
> +				MEGASAS_FUSION_IOCTL_CMDS);
> +		instance->cur_can_queue = instance->max_scsi_cmds;
> +	}
> +}
> +/**
>   * megasas_free_cmds_fusion -	Free all the cmds in the free cmd pool
>   * @instance:		Adapter soft state
>   */
> @@ -736,6 +798,8 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
>  		drv_ops->mfi_capabilities.support_ext_io_size = 1;
>  
>  	drv_ops->mfi_capabilities.support_fp_rlbypass = 1;
> +	if (!dual_qdepth_disable)
> +		drv_ops->mfi_capabilities.support_ext_queue_depth = 1;
>  
>  	/* Convert capability to LE32 */
>  	cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities);
> @@ -1151,15 +1215,7 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
>  
>  	reg_set = instance->reg_set;
>  
> -	/*
> -	 * Get various operational parameters from status register
> -	 */
> -	instance->max_fw_cmds =
> -		instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
> -	dev_info(&instance->pdev->dev,
> -		"firmware support max fw cmd\t: (%d)\n", instance->max_fw_cmds);
> -	if (!instance->is_rdpq)
> -		instance->max_fw_cmds = min_t(u16, instance->max_fw_cmds, 1024);
> +	megasas_fusion_update_can_queue(instance, PROBE_CONTEXT);
>  
>  	/*
>  	 * Reduce the max supported cmds by 1. This is to ensure that the
> @@ -2117,6 +2173,15 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
>  
>  	fusion = instance->ctrl_context;
>  
> +	if (megasas_cmd_type(scmd) == READ_WRITE_LDIO) {
> +		if (instance->ldio_threshold &&
> +			(atomic_read(&instance->ldio_outstanding) >=
> +			instance->ldio_threshold))

This test above won't you protect when several processes read the same value in parallel,
so it may happen that you get over the limit set for ldio_threshold.
(You might use instead a construction with atomic_dec_and_test for example) 

tomash


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 10/15] megaraid_sas: IO throttling support
  2015-12-18 13:27 ` [PATCH 10/15] megaraid_sas: IO throttling support Sumit Saxena
@ 2016-01-19 13:38   ` Tomas Henzl
  2016-01-28  7:18     ` Sumit Saxena
  0 siblings, 1 reply; 50+ messages in thread
From: Tomas Henzl @ 2016-01-19 13:38 UTC (permalink / raw)
  To: Sumit Saxena, jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai

On 18.12.2015 14:27, Sumit Saxena wrote:
> This patch will add capability in driver to tell firmware that it can throttle IOs in case Controller's Queue depth is downgraded post OFU
> (Online firmware upgrade). This feature will ensure firmware can be downgraded from higher queue depth to lower queue depth without needing system reboot.
> Added throttling code in IO path of driver, in case OS tries to send more IOs than post OFU firmware's queue depth.
>
> Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
> Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
> ---
>  drivers/scsi/megaraid/megaraid_sas.h        |    6 ++++--
>  drivers/scsi/megaraid/megaraid_sas_fusion.c |    7 +++++++
>  2 files changed, 11 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
> index 4595ef4..9d2b3da 100644
> --- a/drivers/scsi/megaraid/megaraid_sas.h
> +++ b/drivers/scsi/megaraid/megaraid_sas.h
> @@ -1537,7 +1537,8 @@ union megasas_sgl_frame {
>  typedef union _MFI_CAPABILITIES {
>  	struct {
>  #if   defined(__BIG_ENDIAN_BITFIELD)
> -		u32     reserved:21;
> +		u32     reserved:20;
> +		u32     support_qd_throttling:1;
>  		u32     support_fp_rlbypass:1;
>  		u32     support_vfid_in_ioframe:1;
>  		u32     support_ext_io_size:1;
> @@ -1561,7 +1562,8 @@ typedef union _MFI_CAPABILITIES {
>  		u32     support_ext_io_size:1;
>  		u32     support_vfid_in_ioframe:1;
>  		u32     support_fp_rlbypass:1;
> -		u32     reserved:21;
> +		u32     support_qd_throttling:1;
> +		u32     reserved:20;
>  #endif
>  	} mfi_capabilities;
>  	__le32		reg;
> diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> index 7cc7806..1248c7a 100644
> --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
> +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> @@ -801,6 +801,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
>  	if (!dual_qdepth_disable)
>  		drv_ops->mfi_capabilities.support_ext_queue_depth = 1;
>  
> +	drv_ops->mfi_capabilities.support_qd_throttling = 1;
>  	/* Convert capability to LE32 */
>  	cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities);
>  
> @@ -2182,6 +2183,12 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
>  			atomic_inc(&instance->ldio_outstanding);
>  	}
>  
> +	if (atomic_read(&instance->fw_outstanding) >=
> +			instance->host->can_queue) {
> +		dev_err(&instance->pdev->dev, "Throttle IOs beyond Controller queue depth\n");
> +		return SCSI_MLQUEUE_HOST_BUSY;
> +	}

Same as in the previous patch, this this test above won't you protect when several
processes read the same value in parallel. In addition to that, when the scsi layer
knows the new smaller can_queue value it will not queue new commands above the limit.

> +
>  	cmd = megasas_get_cmd_fusion(instance, scmd->request->tag);
>  
>  	index = cmd->index;


^ permalink raw reply	[flat|nested] 50+ messages in thread

* RE: [PATCH 09/15] megaraid_sas: Dual Queue depth support
  2016-01-19 13:34   ` Tomas Henzl
@ 2016-01-19 13:44     ` Sumit Saxena
  2016-01-20 13:55       ` Tomas Henzl
  0 siblings, 1 reply; 50+ messages in thread
From: Sumit Saxena @ 2016-01-19 13:44 UTC (permalink / raw)
  To: Tomas Henzl, jbottomley, hch, martin.petersen; +Cc: linux-scsi, Kashyap Desai

> -----Original Message-----
> From: Tomas Henzl [mailto:thenzl@redhat.com]
> Sent: Tuesday, January 19, 2016 7:04 PM
> To: Sumit Saxena; jbottomley@parallels.com; hch@infradead.org;
> martin.petersen@oracle.com
> Cc: linux-scsi@vger.kernel.org; kashyap.desai@avagotech.com
> Subject: Re: [PATCH 09/15] megaraid_sas: Dual Queue depth support
>
> On 18.12.2015 14:27, Sumit Saxena wrote:
> > This patch will add support for Dual Queue depth reported by firmware.
> >
> > Below are key points-
> >
> > 1. For iMR controllers, firmware will report two queue depths- 1.
Controller
> wide Queue depth 2. LDIO Queue depth(240).
> > Ofcourse, Controller wide Queue depth will be greater among two. Using
> > this new method, iMR can provide larger Queue depth(QD) for JBOD and
> > limited QD for Virtual Disk(VD). This feature gives benefit for iMR
product
> which will be used for deployment with large number of JBOD and limited
> number of VD on setup.
> > 2. megaraid_sas driver will throttle Read write LDIOs based when RW
LDIOs
> reaches "LDIO Queue Depth".
> > 3. This feature of dual queue depth can enabled/disabled via module
> parameter. Default behavior is: Dual Queue depth is enabled.
> > 4. Added sysfs parameter "ldio_outstanding" for user to read LDIO
outstanding
> at run time.
> >
> >
> > Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
> > Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
> > ---
> >  drivers/scsi/megaraid/megaraid_sas.h        |    9 +++
> >  drivers/scsi/megaraid/megaraid_sas_base.c   |   20 ++++++-
> >  drivers/scsi/megaraid/megaraid_sas_fusion.c |   89
> ++++++++++++++++++++++++---
> >  3 files changed, 108 insertions(+), 10 deletions(-)
> >
> > diff --git a/drivers/scsi/megaraid/megaraid_sas.h
> > b/drivers/scsi/megaraid/megaraid_sas.h
> > index c539516..4595ef4 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas.h
> > +++ b/drivers/scsi/megaraid/megaraid_sas.h
> > @@ -1353,6 +1353,12 @@ enum DCMD_TIMEOUT_ACTION {
> >  	KILL_ADAPTER = 1,
> >  	IGNORE_TIMEOUT = 2,
> >  };
> > +
> > +enum FW_BOOT_CONTEXT {
> > +	PROBE_CONTEXT = 0,
> > +	OCR_CONTEXT = 1,
> > +};
> > +
> >  /* Frame Type */
> >  #define IO_FRAME				0
> >  #define PTHRU_FRAME				1
> > @@ -2038,6 +2044,8 @@ struct megasas_instance {
> >  	u16 max_fw_cmds;
> >  	u16 max_mfi_cmds;
> >  	u16 max_scsi_cmds;
> > +	u16 ldio_threshold;
> > +	u16 cur_can_queue;
> >  	u32 max_sectors_per_req;
> >  	struct megasas_aen_event *ev;
> >
> > @@ -2068,6 +2076,7 @@ struct megasas_instance {
> >  	u32 fw_support_ieee;
> >
> >  	atomic_t fw_outstanding;
> > +	atomic_t ldio_outstanding;
> >  	atomic_t fw_reset_no_pci_access;
> >
> >  	struct megasas_instance_template *instancet; diff --git
> > a/drivers/scsi/megaraid/megaraid_sas_base.c
> > b/drivers/scsi/megaraid/megaraid_sas_base.c
> > index 3454c5e..edc26fb 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas_base.c
> > +++ b/drivers/scsi/megaraid/megaraid_sas_base.c
> > @@ -96,6 +96,10 @@ int rdpq_enable = 1;  module_param(rdpq_enable,
> > int, S_IRUGO);  MODULE_PARM_DESC(rdpq_enable, " Allocate reply queue
> > in chunks for large queue depth enable/disbale Default: disable(0)");
> >
> > +unsigned int dual_qdepth_disable;
> > +module_param(dual_qdepth_disable, int, S_IRUGO);
> > +MODULE_PARM_DESC(dual_qdepth_disable, "Disable dual queue depth
> > +feature. Default: 0");
> > +
> >  MODULE_LICENSE("GPL");
> >  MODULE_VERSION(MEGASAS_VERSION);
> >  MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com");
> > @@ -1977,7 +1981,7 @@ megasas_check_and_restore_queue_depth(struct
> megasas_instance *instance)
> >  		spin_lock_irqsave(instance->host->host_lock, flags);
> >  		instance->flag &= ~MEGASAS_FW_BUSY;
> >
> > -		instance->host->can_queue = instance->max_scsi_cmds;
> > +		instance->host->can_queue = instance->cur_can_queue;
> >  		spin_unlock_irqrestore(instance->host->host_lock, flags);
> >  	}
> >  }
> > @@ -2942,6 +2946,16 @@ megasas_page_size_show(struct device *cdev,
> >  	return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long)PAGE_SIZE
-
> > 1);  }
> >
> > +static ssize_t
> > +megasas_ldio_outstanding_show(struct device *cdev, struct
device_attribute
> *attr,
> > +	char *buf)
> > +{
> > +	struct Scsi_Host *shost = class_to_shost(cdev);
> > +	struct megasas_instance *instance = (struct megasas_instance
> > +*)shost->hostdata;
> > +
> > +	return snprintf(buf, PAGE_SIZE, "%d\n",
> > +atomic_read(&instance->ldio_outstanding));
> > +}
> > +
> >  static DEVICE_ATTR(fw_crash_buffer, S_IRUGO | S_IWUSR,
> >  	megasas_fw_crash_buffer_show, megasas_fw_crash_buffer_store);
> > static DEVICE_ATTR(fw_crash_buffer_size, S_IRUGO, @@ -2950,12 +2964,15
> > @@ static DEVICE_ATTR(fw_crash_state, S_IRUGO | S_IWUSR,
> >  	megasas_fw_crash_state_show, megasas_fw_crash_state_store);
> static
> > DEVICE_ATTR(page_size, S_IRUGO,
> >  	megasas_page_size_show, NULL);
> > +static DEVICE_ATTR(ldio_outstanding, S_IRUGO,
> > +	megasas_ldio_outstanding_show, NULL);
> >
> >  struct device_attribute *megaraid_host_attrs[] = {
> >  	&dev_attr_fw_crash_buffer_size,
> >  	&dev_attr_fw_crash_buffer,
> >  	&dev_attr_fw_crash_state,
> >  	&dev_attr_page_size,
> > +	&dev_attr_ldio_outstanding,
> >  	NULL,
> >  };
> >
> > @@ -4750,6 +4767,7 @@ megasas_init_adapter_mfi(struct megasas_instance
> *instance)
> >  		sema_init(&instance->ioctl_sem,
> (MEGASAS_MFI_IOCTL_CMDS));
> >  	}
> >
> > +	instance->cur_can_queue = instance->max_scsi_cmds;
> >  	/*
> >  	 * Create a pool of commands
> >  	 */
> > diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > index 9ad779d..7cc7806 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > @@ -92,6 +92,7 @@ void megasas_start_timer(struct megasas_instance
> *instance,
> >  			 void *fn, unsigned long interval);  extern struct
> > megasas_mgmt_info megasas_mgmt_info;  extern int resetwaittime;
> > +extern unsigned int dual_qdepth_disable;
> >  static void megasas_free_rdpq_fusion(struct megasas_instance
> > *instance);  static void megasas_free_reply_fusion(struct
> > megasas_instance *instance);
> >
> > @@ -208,6 +209,67 @@ megasas_fire_cmd_fusion(struct megasas_instance
> > *instance,  }
> >
> >  /**
> > + * megasas_fusion_update_can_queue -	Do all Adapter Queue depth
> related calculations here
> > + * @instance:
> 	Adapter soft state
> > + * fw_boot_context:
Whether this
> function called during probe or after OCR
> > + *
> > + * This function is only for fusion controllers.
> > + * Update host can queue, if firmware downgrade max supported
firmware
> commands.
> > + * Firmware upgrade case will be skiped because underlying firmware
> > +has
> > + * more resource than exposed to the OS.
> > + *
> > + */
> > +static void
> > +megasas_fusion_update_can_queue(struct megasas_instance *instance,
> > +int fw_boot_context) {
> > +	u16 cur_max_fw_cmds = 0;
> > +	u16 ldio_threshold = 0;
> > +	struct megasas_register_set __iomem *reg_set;
> > +
> > +	reg_set = instance->reg_set;
> > +
> > +	cur_max_fw_cmds = readl(&instance->reg_set-
> >outbound_scratch_pad_3)
> > +& 0x00FFFF;
> > +
> > +	if (dual_qdepth_disable || !cur_max_fw_cmds)
> > +		cur_max_fw_cmds = instance->instancet-
> >read_fw_status_reg(reg_set) & 0x00FFFF;
> > +	else
> > +		ldio_threshold =
> > +			(instance->instancet->read_fw_status_reg(reg_set)
&
> 0x00FFFF) -
> > +MEGASAS_FUSION_IOCTL_CMDS;
> > +
> > +	dev_info(&instance->pdev->dev,
> > +			"Current firmware maximum commands: %d\t LDIO
> thershold: %d\n",
>
> a typo in "thershold"
>
> > +			cur_max_fw_cmds, ldio_threshold);
> > +
> > +	if (fw_boot_context == OCR_CONTEXT) {
> > +		cur_max_fw_cmds = cur_max_fw_cmds - 1;
> > +		if (cur_max_fw_cmds <= instance->max_fw_cmds) {
>
> probably '<' instead of '<=" could be here ?
>
> > +			instance->cur_can_queue =
> > +				cur_max_fw_cmds -
> (MEGASAS_FUSION_INTERNAL_CMDS +
> > +
> 	MEGASAS_FUSION_IOCTL_CMDS);
> > +			instance->host->can_queue = instance-
> >cur_can_queue;
> > +			instance->ldio_threshold = ldio_threshold;
> > +		}
> > +	} else {
> > +		instance->max_fw_cmds = cur_max_fw_cmds;
> > +		instance->ldio_threshold = ldio_threshold;
> > +
> > +		if (!instance->is_rdpq)
> > +			instance->max_fw_cmds = min_t(u16, instance-
> >max_fw_cmds, 1024);
> > +
> > +		/*
> > +		* Reduce the max supported cmds by 1. This is to ensure
that
> the
> > +		* reply_q_sz (1 more than the max cmd that driver may
send)
> > +		* does not exceed max cmds that the FW can support
> > +		*/
> > +		instance->max_fw_cmds = instance->max_fw_cmds-1;
> > +
> > +		instance->max_scsi_cmds = instance->max_fw_cmds -
> > +				(MEGASAS_FUSION_INTERNAL_CMDS +
> > +				MEGASAS_FUSION_IOCTL_CMDS);
> > +		instance->cur_can_queue = instance->max_scsi_cmds;
> > +	}
> > +}
> > +/**
> >   * megasas_free_cmds_fusion -	Free all the cmds in the free cmd
pool
> >   * @instance:		Adapter soft state
> >   */
> > @@ -736,6 +798,8 @@ megasas_ioc_init_fusion(struct megasas_instance
> *instance)
> >  		drv_ops->mfi_capabilities.support_ext_io_size = 1;
> >
> >  	drv_ops->mfi_capabilities.support_fp_rlbypass = 1;
> > +	if (!dual_qdepth_disable)
> > +		drv_ops->mfi_capabilities.support_ext_queue_depth = 1;
> >
> >  	/* Convert capability to LE32 */
> >  	cpu_to_le32s((u32
> > *)&init_frame->driver_operations.mfi_capabilities);
> > @@ -1151,15 +1215,7 @@ megasas_init_adapter_fusion(struct
> > megasas_instance *instance)
> >
> >  	reg_set = instance->reg_set;
> >
> > -	/*
> > -	 * Get various operational parameters from status register
> > -	 */
> > -	instance->max_fw_cmds =
> > -		instance->instancet->read_fw_status_reg(reg_set) &
0x00FFFF;
> > -	dev_info(&instance->pdev->dev,
> > -		"firmware support max fw cmd\t: (%d)\n", instance-
> >max_fw_cmds);
> > -	if (!instance->is_rdpq)
> > -		instance->max_fw_cmds = min_t(u16, instance-
> >max_fw_cmds, 1024);
> > +	megasas_fusion_update_can_queue(instance, PROBE_CONTEXT);
> >
> >  	/*
> >  	 * Reduce the max supported cmds by 1. This is to ensure that the
@@
> > -2117,6 +2173,15 @@ megasas_build_and_issue_cmd_fusion(struct
> > megasas_instance *instance,
> >
> >  	fusion = instance->ctrl_context;
> >
> > +	if (megasas_cmd_type(scmd) == READ_WRITE_LDIO) {
> > +		if (instance->ldio_threshold &&
> > +			(atomic_read(&instance->ldio_outstanding) >=
> > +			instance->ldio_threshold))
>
> This test above won't you protect when several processes read the same
value
> in parallel, so it may happen that you get over the limit set for
ldio_threshold.
> (You might use instead a construction with atomic_dec_and_test for
example)

Agree..I will fix this and send updated patch.
>
> tomash

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 11/15] megaraid_sas: Make adprecovery variable atomic
  2015-12-18 13:27 ` [PATCH 11/15] megaraid_sas: Make adprecovery variable atomic Sumit Saxena
@ 2016-01-19 13:52   ` Tomas Henzl
  2016-01-28  8:30     ` Sumit Saxena
  0 siblings, 1 reply; 50+ messages in thread
From: Tomas Henzl @ 2016-01-19 13:52 UTC (permalink / raw)
  To: Sumit Saxena, jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai

On 18.12.2015 14:27, Sumit Saxena wrote:
> Make instance->adprecovery variable atomic and removes hba_lock spinlock while accessing instance->adprecovery.

adprecovery is a 8bit int, you don't do any arithmetic with it, the newly set values
do not depend on previous values - I think that an atomic variable is not needed. 

-tm

>
> Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
> Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
> ---
>  drivers/scsi/megaraid/megaraid_sas.h        |    2 +-
>  drivers/scsi/megaraid/megaraid_sas_base.c   |   95 ++++++++++-----------------
>  drivers/scsi/megaraid/megaraid_sas_fusion.c |   27 ++++----
>  3 files changed, 50 insertions(+), 74 deletions(-)
>
> diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
> index 9d2b3da..ac19d53 100644
> --- a/drivers/scsi/megaraid/megaraid_sas.h
> +++ b/drivers/scsi/megaraid/megaraid_sas.h
> @@ -2101,7 +2101,7 @@ struct megasas_instance {
>  	u16 drv_supported_vd_count;
>  	u16 drv_supported_pd_count;
>  
> -	u8 adprecovery;
> +	atomic_t adprecovery;
>  	unsigned long last_time;
>  	u32 mfiStatus;
>  	u32 last_seq_num;
> diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
> index edc26fb..5eaf6fd 100644
> --- a/drivers/scsi/megaraid/megaraid_sas_base.c
> +++ b/drivers/scsi/megaraid/megaraid_sas_base.c
> @@ -483,7 +483,7 @@ static int
>  megasas_check_reset_xscale(struct megasas_instance *instance,
>  		struct megasas_register_set __iomem *regs)
>  {
> -	if ((instance->adprecovery != MEGASAS_HBA_OPERATIONAL) &&
> +	if ((atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) &&
>  	    (le32_to_cpu(*instance->consumer) ==
>  		MEGASAS_ADPRESET_INPROG_SIGN))
>  		return 1;
> @@ -619,7 +619,7 @@ static int
>  megasas_check_reset_ppc(struct megasas_instance *instance,
>  			struct megasas_register_set __iomem *regs)
>  {
> -	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL)
> +	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
>  		return 1;
>  
>  	return 0;
> @@ -756,7 +756,7 @@ static int
>  megasas_check_reset_skinny(struct megasas_instance *instance,
>  				struct megasas_register_set __iomem *regs)
>  {
> -	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL)
> +	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
>  		return 1;
>  
>  	return 0;
> @@ -950,9 +950,8 @@ static int
>  megasas_check_reset_gen2(struct megasas_instance *instance,
>  		struct megasas_register_set __iomem *regs)
>  {
> -	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
> +	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
>  		return 1;
> -	}
>  
>  	return 0;
>  }
> @@ -998,7 +997,7 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
>  	frame_hdr->cmd_status = MFI_STAT_INVALID_STATUS;
>  	frame_hdr->flags |= cpu_to_le16(MFI_FRAME_DONT_POST_IN_REPLY_QUEUE);
>  
> -	if ((instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) ||
> +	if ((atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) ||
>  		(instance->instancet->issue_dcmd(instance, cmd))) {
>  		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
>  			__func__, __LINE__);
> @@ -1026,7 +1025,7 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
>  	int ret = 0;
>  	cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
>  
> -	if ((instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) ||
> +	if ((atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) ||
>  		(instance->instancet->issue_dcmd(instance, cmd))) {
>  		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
>  			__func__, __LINE__);
> @@ -1090,7 +1089,7 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
>  	cmd->sync_cmd = 1;
>  	cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
>  
> -	if ((instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) ||
> +	if ((atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) ||
>  		(instance->instancet->issue_dcmd(instance, cmd))) {
>  		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
>  			__func__, __LINE__);
> @@ -1653,7 +1652,6 @@ static int
>  megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
>  {
>  	struct megasas_instance *instance;
> -	unsigned long flags;
>  	struct MR_PRIV_DEVICE *mr_device_priv_data;
>  
>  	instance = (struct megasas_instance *)
> @@ -1668,24 +1666,20 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
>  	if (instance->issuepend_done == 0)
>  		return SCSI_MLQUEUE_HOST_BUSY;
>  
> -	spin_lock_irqsave(&instance->hba_lock, flags);
>  
>  	/* Check for an mpio path and adjust behavior */
> -	if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) {
> +	if (atomic_read(&instance->adprecovery) == MEGASAS_ADPRESET_SM_INFAULT) {
>  		if (megasas_check_mpio_paths(instance, scmd) ==
>  		    (DID_RESET << 16)) {
> -			spin_unlock_irqrestore(&instance->hba_lock, flags);
>  			return SCSI_MLQUEUE_HOST_BUSY;
>  		} else {
> -			spin_unlock_irqrestore(&instance->hba_lock, flags);
>  			scmd->result = DID_NO_CONNECT << 16;
>  			scmd->scsi_done(scmd);
>  			return 0;
>  		}
>  	}
>  
> -	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
> -		spin_unlock_irqrestore(&instance->hba_lock, flags);
> +	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
>  		scmd->result = DID_NO_CONNECT << 16;
>  		scmd->scsi_done(scmd);
>  		return 0;
> @@ -1693,23 +1687,17 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
>  
>  	mr_device_priv_data = scmd->device->hostdata;
>  	if (!mr_device_priv_data) {
> -		spin_unlock_irqrestore(&instance->hba_lock, flags);
>  		scmd->result = DID_NO_CONNECT << 16;
>  		scmd->scsi_done(scmd);
>  		return 0;
>  	}
>  
> -	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
> -		spin_unlock_irqrestore(&instance->hba_lock, flags);
> +	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
>  		return SCSI_MLQUEUE_HOST_BUSY;
> -	}
>  
> -	if (mr_device_priv_data->tm_busy) {
> -		spin_unlock_irqrestore(&instance->hba_lock, flags);
> +	if (mr_device_priv_data->tm_busy)
>  		return SCSI_MLQUEUE_DEVICE_BUSY;
> -	}
>  
> -	spin_unlock_irqrestore(&instance->hba_lock, flags);
>  
>  	scmd->result = 0;
>  
> @@ -1943,7 +1931,7 @@ static void megasas_complete_outstanding_ioctls(struct megasas_instance *instanc
>  void megaraid_sas_kill_hba(struct megasas_instance *instance)
>  {
>  	/* Set critical error to block I/O & ioctls in case caller didn't */
> -	instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
> +	atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
>  	/* Wait 1 second to ensure IO or ioctls in build have posted */
>  	msleep(1000);
>  	if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
> @@ -2003,7 +1991,7 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
>  	unsigned long flags;
>  
>  	/* If we have already declared adapter dead, donot complete cmds */
> -	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
> +	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
>  		return;
>  
>  	spin_lock_irqsave(&instance->completion_lock, flags);
> @@ -2072,7 +2060,7 @@ void megasas_do_ocr(struct megasas_instance *instance)
>  		*instance->consumer = cpu_to_le32(MEGASAS_ADPRESET_INPROG_SIGN);
>  	}
>  	instance->instancet->disable_intr(instance);
> -	instance->adprecovery   = MEGASAS_ADPRESET_SM_INFAULT;
> +	atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
>  	instance->issuepend_done = 0;
>  
>  	atomic_set(&instance->fw_outstanding, 0);
> @@ -2471,18 +2459,14 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
>  	int i;
>  	u32 reset_index;
>  	u32 wait_time = MEGASAS_RESET_WAIT_TIME;
> -	u8 adprecovery;
>  	unsigned long flags;
>  	struct list_head clist_local;
>  	struct megasas_cmd *reset_cmd;
>  	u32 fw_state;
>  	u8 kill_adapter_flag;
>  
> -	spin_lock_irqsave(&instance->hba_lock, flags);
> -	adprecovery = instance->adprecovery;
> -	spin_unlock_irqrestore(&instance->hba_lock, flags);
>  
> -	if (adprecovery != MEGASAS_HBA_OPERATIONAL) {
> +	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
>  
>  		INIT_LIST_HEAD(&clist_local);
>  		spin_lock_irqsave(&instance->hba_lock, flags);
> @@ -2493,18 +2477,13 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
>  		dev_notice(&instance->pdev->dev, "HBA reset wait ...\n");
>  		for (i = 0; i < wait_time; i++) {
>  			msleep(1000);
> -			spin_lock_irqsave(&instance->hba_lock, flags);
> -			adprecovery = instance->adprecovery;
> -			spin_unlock_irqrestore(&instance->hba_lock, flags);
> -			if (adprecovery == MEGASAS_HBA_OPERATIONAL)
> +			if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL)
>  				break;
>  		}
>  
> -		if (adprecovery != MEGASAS_HBA_OPERATIONAL) {
> +		if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
>  			dev_notice(&instance->pdev->dev, "reset: Stopping HBA.\n");
> -			spin_lock_irqsave(&instance->hba_lock, flags);
> -			instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
> -			spin_unlock_irqrestore(&instance->hba_lock, flags);
> +			atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
>  			return FAILED;
>  		}
>  
> @@ -2613,9 +2592,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
>  				&instance->reg_set->inbound_doorbell);
>  		}
>  		megasas_dump_pending_frames(instance);
> -		spin_lock_irqsave(&instance->hba_lock, flags);
> -		instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
> -		spin_unlock_irqrestore(&instance->hba_lock, flags);
> +		atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
>  		return FAILED;
>  	}
>  
> @@ -2642,7 +2619,7 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd)
>  	scmd_printk(KERN_NOTICE, scmd, "megasas: RESET cmd=%x retries=%x\n",
>  		 scmd->cmnd[0], scmd->retries);
>  
> -	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
> +	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
>  		dev_err(&instance->pdev->dev, "cannot recover from previous reset failures\n");
>  		return FAILED;
>  	}
> @@ -3386,13 +3363,13 @@ process_fw_state_change_wq(struct work_struct *work)
>  	u32 wait;
>  	unsigned long flags;
>  
> -	if (instance->adprecovery != MEGASAS_ADPRESET_SM_INFAULT) {
> +    if (atomic_read(&instance->adprecovery) != MEGASAS_ADPRESET_SM_INFAULT) {
>  		dev_notice(&instance->pdev->dev, "error, recovery st %x\n",
> -				instance->adprecovery);
> +				atomic_read(&instance->adprecovery));
>  		return ;
>  	}
>  
> -	if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) {
> +	if (atomic_read(&instance->adprecovery) == MEGASAS_ADPRESET_SM_INFAULT) {
>  		dev_notice(&instance->pdev->dev, "FW detected to be in fault"
>  					"state, restarting it...\n");
>  
> @@ -3435,7 +3412,7 @@ process_fw_state_change_wq(struct work_struct *work)
>  		megasas_issue_init_mfi(instance);
>  
>  		spin_lock_irqsave(&instance->hba_lock, flags);
> -		instance->adprecovery	= MEGASAS_HBA_OPERATIONAL;
> +		atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
>  		spin_unlock_irqrestore(&instance->hba_lock, flags);
>  		instance->instancet->enable_intr(instance);
>  
> @@ -3500,14 +3477,14 @@ megasas_deplete_reply_queue(struct megasas_instance *instance,
>  
>  
>  			instance->instancet->disable_intr(instance);
> -			instance->adprecovery	= MEGASAS_ADPRESET_SM_INFAULT;
> +			atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
>  			instance->issuepend_done = 0;
>  
>  			atomic_set(&instance->fw_outstanding, 0);
>  			megasas_internal_reset_defer_cmds(instance);
>  
>  			dev_notice(&instance->pdev->dev, "fwState=%x, stage:%d\n",
> -					fw_state, instance->adprecovery);
> +					fw_state, atomic_read(&instance->adprecovery));
>  
>  			schedule_work(&instance->work_init);
>  			return IRQ_HANDLED;
> @@ -5796,7 +5773,7 @@ static int megasas_probe_one(struct pci_dev *pdev,
>  	instance->flag_ieee = 0;
>  	instance->ev = NULL;
>  	instance->issuepend_done = 1;
> -	instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
> +	atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
>  	instance->is_imr = 0;
>  
>  	instance->evt_detail = pci_alloc_consistent(pdev,
> @@ -5975,7 +5952,7 @@ static void megasas_flush_cache(struct megasas_instance *instance)
>  	struct megasas_cmd *cmd;
>  	struct megasas_dcmd_frame *dcmd;
>  
> -	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
> +	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
>  		return;
>  
>  	cmd = megasas_get_cmd(instance);
> @@ -6018,7 +5995,7 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
>  	struct megasas_cmd *cmd;
>  	struct megasas_dcmd_frame *dcmd;
>  
> -	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
> +	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
>  		return;
>  
>  	cmd = megasas_get_cmd(instance);
> @@ -6463,7 +6440,7 @@ static int megasas_set_crash_dump_params_ioctl(struct megasas_cmd *cmd)
>  	for (i = 0; i < megasas_mgmt_info.max_index; i++) {
>  		local_instance = megasas_mgmt_info.instance[i];
>  		if (local_instance && local_instance->crash_dump_drv_support) {
> -			if ((local_instance->adprecovery ==
> +			if ((atomic_read(&local_instance->adprecovery) ==
>  				MEGASAS_HBA_OPERATIONAL) &&
>  				!megasas_set_crash_dump_params(local_instance,
>  					crash_support)) {
> @@ -6711,7 +6688,7 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
>  		goto out_kfree_ioc;
>  	}
>  
> -	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
> +	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
>  		dev_err(&instance->pdev->dev, "Controller in crit error\n");
>  		error = -ENODEV;
>  		goto out_kfree_ioc;
> @@ -6730,7 +6707,7 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
>  	for (i = 0; i < wait_time; i++) {
>  
>  		spin_lock_irqsave(&instance->hba_lock, flags);
> -		if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
> +		if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL) {
>  			spin_unlock_irqrestore(&instance->hba_lock, flags);
>  			break;
>  		}
> @@ -6745,7 +6722,7 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
>  	}
>  
>  	spin_lock_irqsave(&instance->hba_lock, flags);
> -	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
> +	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
>  		spin_unlock_irqrestore(&instance->hba_lock, flags);
>  
>  		dev_err(&instance->pdev->dev, "timed out while"
> @@ -6787,7 +6764,7 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
>  	if (!instance)
>  		return -ENODEV;
>  
> -	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
> +	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
>  		return -ENODEV;
>  	}
>  
> @@ -6798,7 +6775,7 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
>  	for (i = 0; i < wait_time; i++) {
>  
>  		spin_lock_irqsave(&instance->hba_lock, flags);
> -		if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
> +		if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL) {
>  			spin_unlock_irqrestore(&instance->hba_lock,
>  						flags);
>  			break;
> @@ -6815,7 +6792,7 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
>  	}
>  
>  	spin_lock_irqsave(&instance->hba_lock, flags);
> -	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
> +	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
>  		spin_unlock_irqrestore(&instance->hba_lock, flags);
>  		dev_err(&instance->pdev->dev, "timed out while waiting"
>  				"for HBA to recover\n");
> diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> index 1248c7a..96e8d80 100644
> --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
> +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> @@ -2251,7 +2251,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
>  
>  	fusion = instance->ctrl_context;
>  
> -	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
> +	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
>  		return IRQ_HANDLED;
>  
>  	desc = fusion->reply_frames_desc[MSIxIndex] +
> @@ -2418,7 +2418,7 @@ megasas_complete_cmd_dpc_fusion(unsigned long instance_addr)
>  
>  	/* If we have already declared adapter dead, donot complete cmds */
>  	spin_lock_irqsave(&instance->hba_lock, flags);
> -	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
> +	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
>  		spin_unlock_irqrestore(&instance->hba_lock, flags);
>  		return;
>  	}
> @@ -3200,7 +3200,7 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd)
>  	instance = (struct megasas_instance *)scmd->device->host->hostdata;
>  	fusion = instance->ctrl_context;
>  
> -	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
> +	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
>  		dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL,"
>  		"SCSI host:%d\n", instance->host->host_no);
>  		ret = FAILED;
> @@ -3284,7 +3284,7 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
>  	instance = (struct megasas_instance *)scmd->device->host->hostdata;
>  	fusion = instance->ctrl_context;
>  
> -	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
> +	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
>  		dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL,"
>  		"SCSI host:%d\n", instance->host->host_no);
>  		ret = FAILED;
> @@ -3376,7 +3376,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
>  
>  	mutex_lock(&instance->reset_mutex);
>  
> -	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
> +	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
>  		dev_warn(&instance->pdev->dev, "Hardware critical error, "
>  		       "returning FAILED for scsi%d.\n",
>  			instance->host->host_no);
> @@ -3391,7 +3391,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
>  		instance->crash_dump_app_support && reason) {
>  		dev_info(&instance->pdev->dev, "IO/DCMD timeout is detected, "
>  			"forcibly FAULT Firmware\n");
> -		instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
> +		atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
>  		status_reg = readl(&instance->reg_set->doorbell);
>  		writel(status_reg | MFI_STATE_FORCE_OCR,
>  			&instance->reg_set->doorbell);
> @@ -3403,10 +3403,10 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
>  			dev_dbg(&instance->pdev->dev, "waiting for [%d] "
>  				"seconds for crash dump collection and OCR "
>  				"to be done\n", (io_timeout_in_crash_mode * 3));
> -		} while ((instance->adprecovery != MEGASAS_HBA_OPERATIONAL) &&
> +		} while ((atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) &&
>  			(io_timeout_in_crash_mode < 80));
>  
> -		if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
> +		if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL) {
>  			dev_info(&instance->pdev->dev, "OCR done for IO "
>  				"timeout case\n");
>  			retval = SUCCESS;
> @@ -3423,14 +3423,14 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
>  	if (instance->requestorId && !instance->skip_heartbeat_timer_del)
>  		del_timer_sync(&instance->sriov_heartbeat_timer);
>  	set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
> -	instance->adprecovery = MEGASAS_ADPRESET_SM_POLLING;
> +	atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_POLLING);
>  	instance->instancet->disable_intr(instance);
>  	msleep(1000);
>  
>  	/* First try waiting for commands to complete */
>  	if (megasas_wait_for_outstanding_fusion(instance, reason,
>  						&convert)) {
> -		instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
> +		atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
>  		dev_warn(&instance->pdev->dev, "resetting fusion "
>  		       "adapter scsi%d.\n", instance->host->host_no);
>  		if (convert)
> @@ -3513,8 +3513,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
>  					       status_reg);
>  					megaraid_sas_kill_hba(instance);
>  					instance->skip_heartbeat_timer_del = 1;
> -					instance->adprecovery =
> -						MEGASAS_HW_CRITICAL_ERROR;
> +					atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
>  					retval = FAILED;
>  					goto out;
>  				}
> @@ -3573,7 +3572,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
>  			clear_bit(MEGASAS_FUSION_IN_RESET,
>  				  &instance->reset_flags);
>  			instance->instancet->enable_intr(instance);
> -			instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
> +			atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
>  
>  			/* Restart SR-IOV heartbeat */
>  			if (instance->requestorId) {
> @@ -3618,7 +3617,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
>  		}
>  		clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
>  		instance->instancet->enable_intr(instance);
> -		instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
> +		atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
>  	}
>  out:
>  	clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 12/15] megaraid_sas: MFI adapter's OCR changes
  2015-12-18 13:27 ` [PATCH 12/15] megaraid_sas: MFI adapter's OCR changes Sumit Saxena
@ 2016-01-19 14:22   ` Tomas Henzl
  2016-01-28 11:12     ` Sumit Saxena
  0 siblings, 1 reply; 50+ messages in thread
From: Tomas Henzl @ 2016-01-19 14:22 UTC (permalink / raw)
  To: Sumit Saxena, jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai

On 18.12.2015 14:27, Sumit Saxena wrote:
> Optimized MFI adapters' OCR path, particularly megasas_wait_for_outstanding() function.
>
> Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
> Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
> ---
>  drivers/scsi/megaraid/megaraid_sas_base.c |  104 +++++++++++++++--------------
>  1 files changed, 54 insertions(+), 50 deletions(-)
>
> diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
> index 5eaf6fd..cc843d6 100644
> --- a/drivers/scsi/megaraid/megaraid_sas_base.c
> +++ b/drivers/scsi/megaraid/megaraid_sas_base.c
> @@ -2456,15 +2456,19 @@ void megasas_sriov_heartbeat_handler(unsigned long instance_addr)
>   */
>  static int megasas_wait_for_outstanding(struct megasas_instance *instance)
>  {
> -	int i;
> +	int i, sl, outstanding;
>  	u32 reset_index;
>  	u32 wait_time = MEGASAS_RESET_WAIT_TIME;
>  	unsigned long flags;
>  	struct list_head clist_local;
>  	struct megasas_cmd *reset_cmd;
>  	u32 fw_state;
> -	u8 kill_adapter_flag;
>  
> +	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
> +		dev_info(&instance->pdev->dev, "%s:%d HBA is killed.\n",
> +		__func__, __LINE__);
> +		return FAILED;
> +	}
>  
>  	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
>  
> @@ -2521,7 +2525,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
>  	}
>  
>  	for (i = 0; i < resetwaittime; i++) {
> -		int outstanding = atomic_read(&instance->fw_outstanding);
> +		outstanding = atomic_read(&instance->fw_outstanding);
>  
>  		if (!outstanding)
>  			break;
> @@ -2540,65 +2544,65 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
>  	}
>  
>  	i = 0;
> -	kill_adapter_flag = 0;
> +	outstanding = atomic_read(&instance->fw_outstanding);
> +	fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
> +
> +	if ((!outstanding && (fw_state == MFI_STATE_OPERATIONAL)))
> +		goto no_outstanding;
> +
> +	if (instance->disableOnlineCtrlReset)
> +		goto kill_hba_and_failed;
>  	do {
> -		fw_state = instance->instancet->read_fw_status_reg(
> -					instance->reg_set) & MFI_STATE_MASK;
> -		if ((fw_state == MFI_STATE_FAULT) &&
> -			(instance->disableOnlineCtrlReset == 0)) {
> -			if (i == 3) {
> -				kill_adapter_flag = 2;
> -				break;
> -			}
> +		if ((fw_state == MFI_STATE_FAULT) || atomic_read(&instance->fw_outstanding)) {
> +			dev_info(&instance->pdev->dev,
> +				"%s:%d waiting_for_outstanding: before issue OCR. FW state = 0x%x, oustanding 0x%x\n",
> +				__func__, __LINE__, fw_state, atomic_read(&instance->fw_outstanding));
> +			if (i == 3)
> +				goto kill_hba_and_failed;
>  			megasas_do_ocr(instance);
> -			kill_adapter_flag = 1;
>  
> -			/* wait for 1 secs to let FW finish the pending cmds */
> -			msleep(1000);
> +			if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
> +				dev_info(&instance->pdev->dev, "%s:%d OCR failed and HBA is killed.\n",
> +				__func__, __LINE__);
> +				return FAILED;
> +			}
> +			dev_info(&instance->pdev->dev, "%s:%d waiting_for_outstanding: after issue OCR.\n",
> +				__func__, __LINE__);
> +
> +			for (sl = 0; sl < 10; sl++)
> +				msleep(500);

		ssleep(5); ?

> +
> +			outstanding = atomic_read(&instance->fw_outstanding);
> +
> +			fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
> +			if ((!outstanding && (fw_state == MFI_STATE_OPERATIONAL)))
> +				goto no_outstanding;
>  		}
>  		i++;
>  	} while (i <= 3);
>  
> -	if (atomic_read(&instance->fw_outstanding) && !kill_adapter_flag) {
> -		if (instance->disableOnlineCtrlReset == 0) {
> -			megasas_do_ocr(instance);
> +no_outstanding:
>  
> -			/* wait for 5 secs to let FW finish the pending cmds */
> -			for (i = 0; i < wait_time; i++) {
> -				int outstanding =
> -					atomic_read(&instance->fw_outstanding);
> -				if (!outstanding)
> -					return SUCCESS;
> -				msleep(1000);
> -			}
> -		}
> -	}
> +	dev_info(&instance->pdev->dev, "%s:%d no more pending commands remain after reset handling.\n",
> +		__func__, __LINE__);
> +	return SUCCESS;
>  
> -	if (atomic_read(&instance->fw_outstanding) ||
> -					(kill_adapter_flag == 2)) {
> -		dev_notice(&instance->pdev->dev, "pending cmds after reset\n");
> -		/*
> -		 * Send signal to FW to stop processing any pending cmds.
> -		 * The controller will be taken offline by the OS now.
> -		 */
> -		if ((instance->pdev->device ==
> -			PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
> -			(instance->pdev->device ==
> -			PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
> -			writel(MFI_STOP_ADP,
> -				&instance->reg_set->doorbell);
> -		} else {
> -			writel(MFI_STOP_ADP,
> -				&instance->reg_set->inbound_doorbell);
> -		}
> +kill_hba_and_failed:
> +
> +	fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
> +	if (instance->disableOnlineCtrlReset ||
> +		atomic_read(&instance->fw_outstanding) ||
> +		(fw_state == MFI_STATE_FAULT)) {

You have tested all that many times before (fw_state etc.), so when you after all that
have arrived at kill_hba_and_failed: please just kill the HBA and return FAILED.

> +		/* Reset not supported, kill adapter */
> +		dev_info(&instance->pdev->dev, "%s:%d killing adapter scsi%d"
> +			" disableOnlineCtrlReset %d fw_outstanding %d \n",
> +			__func__, __LINE__, instance->host->host_no, instance->disableOnlineCtrlReset,
> +			atomic_read(&instance->fw_outstanding));
>  		megasas_dump_pending_frames(instance);
> -		atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
> -		return FAILED;
> +		megaraid_sas_kill_hba(instance);
>  	}
>  
> -	dev_notice(&instance->pdev->dev, "no pending cmds after reset\n");
> -
> -	return SUCCESS;
> +	return FAILED;
>  }
>  
>  /**


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 13/15] megaraid_sas: Introduce module parameter for SCSI command-timeout
  2015-12-18 13:27 ` [PATCH 13/15] megaraid_sas: Introduce module parameter for SCSI command-timeout Sumit Saxena
@ 2016-01-19 14:57   ` Tomas Henzl
  2016-01-28 11:17     ` Sumit Saxena
  0 siblings, 1 reply; 50+ messages in thread
From: Tomas Henzl @ 2016-01-19 14:57 UTC (permalink / raw)
  To: Sumit Saxena, jbottomley, hch, martin.petersen; +Cc: linux-scsi, kashyap.desai

On 18.12.2015 14:27, Sumit Saxena wrote:
> This patch will introduce module-parameter for SCSI command timeout value and fix setting of resetwaitime beyond a value.
>
> Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
> Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
> ---
>  drivers/scsi/megaraid/megaraid_sas_base.c   |   15 ++++++++++++---
>  drivers/scsi/megaraid/megaraid_sas_fusion.c |    2 +-
>  2 files changed, 13 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
> index cc843d6..316d5a0 100644
> --- a/drivers/scsi/megaraid/megaraid_sas_base.c
> +++ b/drivers/scsi/megaraid/megaraid_sas_base.c
> @@ -83,7 +83,7 @@ module_param(throttlequeuedepth, int, S_IRUGO);
>  MODULE_PARM_DESC(throttlequeuedepth,
>  	"Adapter queue depth when throttled due to I/O timeout. Default: 16");
>  
> -int resetwaittime = MEGASAS_RESET_WAIT_TIME;
> +unsigned int resetwaittime = MEGASAS_RESET_WAIT_TIME;
>  module_param(resetwaittime, int, S_IRUGO);
>  MODULE_PARM_DESC(resetwaittime, "Wait time in seconds after I/O timeout "
>  		 "before resetting adapter. Default: 180");
> @@ -100,6 +100,10 @@ unsigned int dual_qdepth_disable;
>  module_param(dual_qdepth_disable, int, S_IRUGO);
>  MODULE_PARM_DESC(dual_qdepth_disable, "Disable dual queue depth feature. Default: 0");
>  
> +unsigned int scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT;
> +module_param(scmd_timeout, int, S_IRUGO);
> +MODULE_PARM_DESC(scmd_timeout, "scsi command timeout (10-90s), default 90s. See megasas_reset_timer.");

When you know that "The RAID firmware may require extended timeouts" what do you expect
when an user sets a short timeout value ?
Other than that, I don't think that lot of tunables in a driver makes it better,
from my point of view you could remove both resetwaittime + scmd_timeout.
Okay, I don't want to stay in the way if you really need it so -

Reviewed-by: Tomas Henzl <thenzl@redhat.com>

Tomas


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 14/15] megaraid_sas: SPERC OCR changes
  2015-12-18 13:27 ` [PATCH 14/15] megaraid_sas: SPERC OCR changes Sumit Saxena
@ 2016-01-19 15:14   ` Tomas Henzl
  0 siblings, 0 replies; 50+ messages in thread
From: Tomas Henzl @ 2016-01-19 15:14 UTC (permalink / raw)
  To: Sumit Saxena, jbottomley, hch, martin.petersen
  Cc: linux-scsi, kashyap.desai, Uday Lingala

On 18.12.2015 14:27, Sumit Saxena wrote:
> This patch will do some fixes in OCR path of SRIOV enabled series of Avago controllers.
>
> 1)Removing late detection HB. 
> 2)Change in the behavior if the FW found in READY/OPERAETIONAL state.
>
> Signed-off-by: Uday Lingala <uday.lingala@avagotech.com>
> Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>

Reviewed-by: Tomas Henzl <thenzl@redhat.com>

Tomas


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 09/15] megaraid_sas: Dual Queue depth support
  2016-01-19 13:44     ` Sumit Saxena
@ 2016-01-20 13:55       ` Tomas Henzl
  2016-01-20 14:09         ` Sumit Saxena
  0 siblings, 1 reply; 50+ messages in thread
From: Tomas Henzl @ 2016-01-20 13:55 UTC (permalink / raw)
  To: Sumit Saxena, jbottomley, hch, martin.petersen; +Cc: linux-scsi, Kashyap Desai

On 19.1.2016 14:44, Sumit Saxena wrote:
>> -----Original Message-----
>> From: Tomas Henzl [mailto:thenzl@redhat.com]
>> Sent: Tuesday, January 19, 2016 7:04 PM
>> To: Sumit Saxena; jbottomley@parallels.com; hch@infradead.org;
>> martin.petersen@oracle.com
>> Cc: linux-scsi@vger.kernel.org; kashyap.desai@avagotech.com
>> Subject: Re: [PATCH 09/15] megaraid_sas: Dual Queue depth support
>>
>> On 18.12.2015 14:27, Sumit Saxena wrote:
>>> This patch will add support for Dual Queue depth reported by firmware.
>>>
>>> Below are key points-
>>>
>>> 1. For iMR controllers, firmware will report two queue depths- 1.
> Controller
>> wide Queue depth 2. LDIO Queue depth(240).
>>> Ofcourse, Controller wide Queue depth will be greater among two. Using
>>> this new method, iMR can provide larger Queue depth(QD) for JBOD and
>>> limited QD for Virtual Disk(VD). This feature gives benefit for iMR
> product
>> which will be used for deployment with large number of JBOD and limited
>> number of VD on setup.
>>> 2. megaraid_sas driver will throttle Read write LDIOs based when RW
> LDIOs
>> reaches "LDIO Queue Depth".
>>> 3. This feature of dual queue depth can enabled/disabled via module
>> parameter. Default behavior is: Dual Queue depth is enabled.
>>> 4. Added sysfs parameter "ldio_outstanding" for user to read LDIO
> outstanding
>> at run time.
>>>
>>> Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
>>> Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
>>> ---
>>>  drivers/scsi/megaraid/megaraid_sas.h        |    9 +++
>>>  drivers/scsi/megaraid/megaraid_sas_base.c   |   20 ++++++-
>>>  drivers/scsi/megaraid/megaraid_sas_fusion.c |   89
>> ++++++++++++++++++++++++---
>>>  3 files changed, 108 insertions(+), 10 deletions(-)
>>>
>>> diff --git a/drivers/scsi/megaraid/megaraid_sas.h
>>> b/drivers/scsi/megaraid/megaraid_sas.h
>>> index c539516..4595ef4 100644
>>> --- a/drivers/scsi/megaraid/megaraid_sas.h
>>> +++ b/drivers/scsi/megaraid/megaraid_sas.h
>>> @@ -1353,6 +1353,12 @@ enum DCMD_TIMEOUT_ACTION {
>>>  	KILL_ADAPTER = 1,
>>>  	IGNORE_TIMEOUT = 2,
>>>  };
>>> +
>>> +enum FW_BOOT_CONTEXT {
>>> +	PROBE_CONTEXT = 0,
>>> +	OCR_CONTEXT = 1,
>>> +};
>>> +
>>>  /* Frame Type */
>>>  #define IO_FRAME				0
>>>  #define PTHRU_FRAME				1
>>> @@ -2038,6 +2044,8 @@ struct megasas_instance {
>>>  	u16 max_fw_cmds;
>>>  	u16 max_mfi_cmds;
>>>  	u16 max_scsi_cmds;
>>> +	u16 ldio_threshold;
>>> +	u16 cur_can_queue;
>>>  	u32 max_sectors_per_req;
>>>  	struct megasas_aen_event *ev;
>>>
>>> @@ -2068,6 +2076,7 @@ struct megasas_instance {
>>>  	u32 fw_support_ieee;
>>>
>>>  	atomic_t fw_outstanding;
>>> +	atomic_t ldio_outstanding;
>>>  	atomic_t fw_reset_no_pci_access;
>>>
>>>  	struct megasas_instance_template *instancet; diff --git
>>> a/drivers/scsi/megaraid/megaraid_sas_base.c
>>> b/drivers/scsi/megaraid/megaraid_sas_base.c
>>> index 3454c5e..edc26fb 100644
>>> --- a/drivers/scsi/megaraid/megaraid_sas_base.c
>>> +++ b/drivers/scsi/megaraid/megaraid_sas_base.c
>>> @@ -96,6 +96,10 @@ int rdpq_enable = 1;  module_param(rdpq_enable,
>>> int, S_IRUGO);  MODULE_PARM_DESC(rdpq_enable, " Allocate reply queue
>>> in chunks for large queue depth enable/disbale Default: disable(0)");
>>>
>>> +unsigned int dual_qdepth_disable;
>>> +module_param(dual_qdepth_disable, int, S_IRUGO);
>>> +MODULE_PARM_DESC(dual_qdepth_disable, "Disable dual queue depth
>>> +feature. Default: 0");
>>> +
>>>  MODULE_LICENSE("GPL");
>>>  MODULE_VERSION(MEGASAS_VERSION);
>>>  MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com");
>>> @@ -1977,7 +1981,7 @@ megasas_check_and_restore_queue_depth(struct
>> megasas_instance *instance)
>>>  		spin_lock_irqsave(instance->host->host_lock, flags);
>>>  		instance->flag &= ~MEGASAS_FW_BUSY;
>>>
>>> -		instance->host->can_queue = instance->max_scsi_cmds;
>>> +		instance->host->can_queue = instance->cur_can_queue;
>>>  		spin_unlock_irqrestore(instance->host->host_lock, flags);
>>>  	}
>>>  }
>>> @@ -2942,6 +2946,16 @@ megasas_page_size_show(struct device *cdev,
>>>  	return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long)PAGE_SIZE
> -
>>> 1);  }
>>>
>>> +static ssize_t
>>> +megasas_ldio_outstanding_show(struct device *cdev, struct
> device_attribute
>> *attr,
>>> +	char *buf)
>>> +{
>>> +	struct Scsi_Host *shost = class_to_shost(cdev);
>>> +	struct megasas_instance *instance = (struct megasas_instance
>>> +*)shost->hostdata;
>>> +
>>> +	return snprintf(buf, PAGE_SIZE, "%d\n",
>>> +atomic_read(&instance->ldio_outstanding));
>>> +}
>>> +
>>>  static DEVICE_ATTR(fw_crash_buffer, S_IRUGO | S_IWUSR,
>>>  	megasas_fw_crash_buffer_show, megasas_fw_crash_buffer_store);
>>> static DEVICE_ATTR(fw_crash_buffer_size, S_IRUGO, @@ -2950,12 +2964,15
>>> @@ static DEVICE_ATTR(fw_crash_state, S_IRUGO | S_IWUSR,
>>>  	megasas_fw_crash_state_show, megasas_fw_crash_state_store);
>> static
>>> DEVICE_ATTR(page_size, S_IRUGO,
>>>  	megasas_page_size_show, NULL);
>>> +static DEVICE_ATTR(ldio_outstanding, S_IRUGO,
>>> +	megasas_ldio_outstanding_show, NULL);
>>>
>>>  struct device_attribute *megaraid_host_attrs[] = {
>>>  	&dev_attr_fw_crash_buffer_size,
>>>  	&dev_attr_fw_crash_buffer,
>>>  	&dev_attr_fw_crash_state,
>>>  	&dev_attr_page_size,
>>> +	&dev_attr_ldio_outstanding,
>>>  	NULL,
>>>  };
>>>
>>> @@ -4750,6 +4767,7 @@ megasas_init_adapter_mfi(struct megasas_instance
>> *instance)
>>>  		sema_init(&instance->ioctl_sem,
>> (MEGASAS_MFI_IOCTL_CMDS));
>>>  	}
>>>
>>> +	instance->cur_can_queue = instance->max_scsi_cmds;
>>>  	/*
>>>  	 * Create a pool of commands
>>>  	 */
>>> diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c
>>> b/drivers/scsi/megaraid/megaraid_sas_fusion.c
>>> index 9ad779d..7cc7806 100644
>>> --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
>>> +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
>>> @@ -92,6 +92,7 @@ void megasas_start_timer(struct megasas_instance
>> *instance,
>>>  			 void *fn, unsigned long interval);  extern struct
>>> megasas_mgmt_info megasas_mgmt_info;  extern int resetwaittime;
>>> +extern unsigned int dual_qdepth_disable;
>>>  static void megasas_free_rdpq_fusion(struct megasas_instance
>>> *instance);  static void megasas_free_reply_fusion(struct
>>> megasas_instance *instance);
>>>
>>> @@ -208,6 +209,67 @@ megasas_fire_cmd_fusion(struct megasas_instance
>>> *instance,  }
>>>
>>>  /**
>>> + * megasas_fusion_update_can_queue -	Do all Adapter Queue depth
>> related calculations here
>>> + * @instance:
>> 	Adapter soft state
>>> + * fw_boot_context:
> Whether this
>> function called during probe or after OCR
>>> + *
>>> + * This function is only for fusion controllers.
>>> + * Update host can queue, if firmware downgrade max supported
> firmware
>> commands.
>>> + * Firmware upgrade case will be skiped because underlying firmware
>>> +has
>>> + * more resource than exposed to the OS.
>>> + *
>>> + */
>>> +static void
>>> +megasas_fusion_update_can_queue(struct megasas_instance *instance,
>>> +int fw_boot_context) {
>>> +	u16 cur_max_fw_cmds = 0;
>>> +	u16 ldio_threshold = 0;
>>> +	struct megasas_register_set __iomem *reg_set;
>>> +
>>> +	reg_set = instance->reg_set;
>>> +
>>> +	cur_max_fw_cmds = readl(&instance->reg_set-
>>> outbound_scratch_pad_3)
>>> +& 0x00FFFF;
>>> +
>>> +	if (dual_qdepth_disable || !cur_max_fw_cmds)
>>> +		cur_max_fw_cmds = instance->instancet-
>>> read_fw_status_reg(reg_set) & 0x00FFFF;
>>> +	else
>>> +		ldio_threshold =
>>> +			(instance->instancet->read_fw_status_reg(reg_set)
> &
>> 0x00FFFF) -
>>> +MEGASAS_FUSION_IOCTL_CMDS;
>>> +
>>> +	dev_info(&instance->pdev->dev,
>>> +			"Current firmware maximum commands: %d\t LDIO
>> thershold: %d\n",
>>
>> a typo in "thershold"
>>
>>> +			cur_max_fw_cmds, ldio_threshold);
>>> +
>>> +	if (fw_boot_context == OCR_CONTEXT) {
>>> +		cur_max_fw_cmds = cur_max_fw_cmds - 1;
>>> +		if (cur_max_fw_cmds <= instance->max_fw_cmds) {
>> probably '<' instead of '<=" could be here ?
>>
>>> +			instance->cur_can_queue =
>>> +				cur_max_fw_cmds -
>> (MEGASAS_FUSION_INTERNAL_CMDS +
>>> +
>> 	MEGASAS_FUSION_IOCTL_CMDS);
>>> +			instance->host->can_queue = instance-
>>> cur_can_queue;
>>> +			instance->ldio_threshold = ldio_threshold;
>>> +		}
>>> +	} else {
>>> +		instance->max_fw_cmds = cur_max_fw_cmds;
>>> +		instance->ldio_threshold = ldio_threshold;
>>> +
>>> +		if (!instance->is_rdpq)
>>> +			instance->max_fw_cmds = min_t(u16, instance-
>>> max_fw_cmds, 1024);
>>> +
>>> +		/*
>>> +		* Reduce the max supported cmds by 1. This is to ensure
> that
>> the
>>> +		* reply_q_sz (1 more than the max cmd that driver may
> send)
>>> +		* does not exceed max cmds that the FW can support
>>> +		*/
>>> +		instance->max_fw_cmds = instance->max_fw_cmds-1;
>>> +
>>> +		instance->max_scsi_cmds = instance->max_fw_cmds -
>>> +				(MEGASAS_FUSION_INTERNAL_CMDS +
>>> +				MEGASAS_FUSION_IOCTL_CMDS);
>>> +		instance->cur_can_queue = instance->max_scsi_cmds;
>>> +	}
>>> +}
>>> +/**
>>>   * megasas_free_cmds_fusion -	Free all the cmds in the free cmd
> pool
>>>   * @instance:		Adapter soft state
>>>   */
>>> @@ -736,6 +798,8 @@ megasas_ioc_init_fusion(struct megasas_instance
>> *instance)
>>>  		drv_ops->mfi_capabilities.support_ext_io_size = 1;
>>>
>>>  	drv_ops->mfi_capabilities.support_fp_rlbypass = 1;
>>> +	if (!dual_qdepth_disable)
>>> +		drv_ops->mfi_capabilities.support_ext_queue_depth = 1;
>>>
>>>  	/* Convert capability to LE32 */
>>>  	cpu_to_le32s((u32
>>> *)&init_frame->driver_operations.mfi_capabilities);
>>> @@ -1151,15 +1215,7 @@ megasas_init_adapter_fusion(struct
>>> megasas_instance *instance)
>>>
>>>  	reg_set = instance->reg_set;
>>>
>>> -	/*
>>> -	 * Get various operational parameters from status register
>>> -	 */
>>> -	instance->max_fw_cmds =
>>> -		instance->instancet->read_fw_status_reg(reg_set) &
> 0x00FFFF;
>>> -	dev_info(&instance->pdev->dev,
>>> -		"firmware support max fw cmd\t: (%d)\n", instance-
>>> max_fw_cmds);
>>> -	if (!instance->is_rdpq)
>>> -		instance->max_fw_cmds = min_t(u16, instance-
>>> max_fw_cmds, 1024);
>>> +	megasas_fusion_update_can_queue(instance, PROBE_CONTEXT);
>>>
>>>  	/*
>>>  	 * Reduce the max supported cmds by 1. This is to ensure that the
> @@
>>> -2117,6 +2173,15 @@ megasas_build_and_issue_cmd_fusion(struct
>>> megasas_instance *instance,
>>>
>>>  	fusion = instance->ctrl_context;
>>>
>>> +	if (megasas_cmd_type(scmd) == READ_WRITE_LDIO) {
>>> +		if (instance->ldio_threshold &&
>>> +			(atomic_read(&instance->ldio_outstanding) >=
>>> +			instance->ldio_threshold))
>> This test above won't you protect when several processes read the same
> value
>> in parallel, so it may happen that you get over the limit set for
> ldio_threshold.
>> (You might use instead a construction with atomic_dec_and_test for
> example)
>
> Agree..I will fix this and send updated patch.

In addition to my previous comments - I'm no sure if the idea of two queues
doesn't have some pitfalls - your parallel queue is based on returning commands
to the midlayer with SCSI_MLQUEUE_DEVICE_BUSY - that makes it repeatedly post it
to your queue again. Isn't there a performance loss with Virtual Disks ?


>> tomash
>


^ permalink raw reply	[flat|nested] 50+ messages in thread

* RE: [PATCH 09/15] megaraid_sas: Dual Queue depth support
  2016-01-20 13:55       ` Tomas Henzl
@ 2016-01-20 14:09         ` Sumit Saxena
  2016-01-20 14:16           ` Tomas Henzl
  0 siblings, 1 reply; 50+ messages in thread
From: Sumit Saxena @ 2016-01-20 14:09 UTC (permalink / raw)
  To: Tomas Henzl, jbottomley, hch, martin.petersen; +Cc: linux-scsi, Kashyap Desai

> -----Original Message-----
> From: Tomas Henzl [mailto:thenzl@redhat.com]
> Sent: Wednesday, January 20, 2016 7:26 PM
> To: Sumit Saxena; jbottomley@parallels.com; hch@infradead.org;
> martin.petersen@oracle.com
> Cc: linux-scsi@vger.kernel.org; Kashyap Desai
> Subject: Re: [PATCH 09/15] megaraid_sas: Dual Queue depth support
>
> On 19.1.2016 14:44, Sumit Saxena wrote:
> >> -----Original Message-----
> >> From: Tomas Henzl [mailto:thenzl@redhat.com]
> >> Sent: Tuesday, January 19, 2016 7:04 PM
> >> To: Sumit Saxena; jbottomley@parallels.com; hch@infradead.org;
> >> martin.petersen@oracle.com
> >> Cc: linux-scsi@vger.kernel.org; kashyap.desai@avagotech.com
> >> Subject: Re: [PATCH 09/15] megaraid_sas: Dual Queue depth support
> >>
> >> On 18.12.2015 14:27, Sumit Saxena wrote:
> >>> This patch will add support for Dual Queue depth reported by firmware.
> >>>
> >>> Below are key points-
> >>>
> >>> 1. For iMR controllers, firmware will report two queue depths- 1.
> > Controller
> >> wide Queue depth 2. LDIO Queue depth(240).
> >>> Ofcourse, Controller wide Queue depth will be greater among two.
> >>> Using this new method, iMR can provide larger Queue depth(QD) for
> >>> JBOD and limited QD for Virtual Disk(VD). This feature gives benefit
> >>> for iMR
> > product
> >> which will be used for deployment with large number of JBOD and
> >> limited number of VD on setup.
> >>> 2. megaraid_sas driver will throttle Read write LDIOs based when RW
> > LDIOs
> >> reaches "LDIO Queue Depth".
> >>> 3. This feature of dual queue depth can enabled/disabled via module
> >> parameter. Default behavior is: Dual Queue depth is enabled.
> >>> 4. Added sysfs parameter "ldio_outstanding" for user to read LDIO
> > outstanding
> >> at run time.
> >>>
> >>> Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
> >>> Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
> >>> ---
> >>>  drivers/scsi/megaraid/megaraid_sas.h        |    9 +++
> >>>  drivers/scsi/megaraid/megaraid_sas_base.c   |   20 ++++++-
> >>>  drivers/scsi/megaraid/megaraid_sas_fusion.c |   89
> >> ++++++++++++++++++++++++---
> >>>  3 files changed, 108 insertions(+), 10 deletions(-)
> >>>
> >>> diff --git a/drivers/scsi/megaraid/megaraid_sas.h
> >>> b/drivers/scsi/megaraid/megaraid_sas.h
> >>> index c539516..4595ef4 100644
> >>> --- a/drivers/scsi/megaraid/megaraid_sas.h
> >>> +++ b/drivers/scsi/megaraid/megaraid_sas.h
> >>> @@ -1353,6 +1353,12 @@ enum DCMD_TIMEOUT_ACTION {
> >>>  	KILL_ADAPTER = 1,
> >>>  	IGNORE_TIMEOUT = 2,
> >>>  };
> >>> +
> >>> +enum FW_BOOT_CONTEXT {
> >>> +	PROBE_CONTEXT = 0,
> >>> +	OCR_CONTEXT = 1,
> >>> +};
> >>> +
> >>>  /* Frame Type */
> >>>  #define IO_FRAME				0
> >>>  #define PTHRU_FRAME				1
> >>> @@ -2038,6 +2044,8 @@ struct megasas_instance {
> >>>  	u16 max_fw_cmds;
> >>>  	u16 max_mfi_cmds;
> >>>  	u16 max_scsi_cmds;
> >>> +	u16 ldio_threshold;
> >>> +	u16 cur_can_queue;
> >>>  	u32 max_sectors_per_req;
> >>>  	struct megasas_aen_event *ev;
> >>>
> >>> @@ -2068,6 +2076,7 @@ struct megasas_instance {
> >>>  	u32 fw_support_ieee;
> >>>
> >>>  	atomic_t fw_outstanding;
> >>> +	atomic_t ldio_outstanding;
> >>>  	atomic_t fw_reset_no_pci_access;
> >>>
> >>>  	struct megasas_instance_template *instancet; diff --git
> >>> a/drivers/scsi/megaraid/megaraid_sas_base.c
> >>> b/drivers/scsi/megaraid/megaraid_sas_base.c
> >>> index 3454c5e..edc26fb 100644
> >>> --- a/drivers/scsi/megaraid/megaraid_sas_base.c
> >>> +++ b/drivers/scsi/megaraid/megaraid_sas_base.c
> >>> @@ -96,6 +96,10 @@ int rdpq_enable = 1;  module_param(rdpq_enable,
> >>> int, S_IRUGO);  MODULE_PARM_DESC(rdpq_enable, " Allocate reply queue
> >>> in chunks for large queue depth enable/disbale Default:
> >>> disable(0)");
> >>>
> >>> +unsigned int dual_qdepth_disable;
> >>> +module_param(dual_qdepth_disable, int, S_IRUGO);
> >>> +MODULE_PARM_DESC(dual_qdepth_disable, "Disable dual queue depth
> >>> +feature. Default: 0");
> >>> +
> >>>  MODULE_LICENSE("GPL");
> >>>  MODULE_VERSION(MEGASAS_VERSION);
> >>>  MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com");
> >>> @@ -1977,7 +1981,7 @@
> megasas_check_and_restore_queue_depth(struct
> >> megasas_instance *instance)
> >>>  		spin_lock_irqsave(instance->host->host_lock, flags);
> >>>  		instance->flag &= ~MEGASAS_FW_BUSY;
> >>>
> >>> -		instance->host->can_queue = instance->max_scsi_cmds;
> >>> +		instance->host->can_queue = instance->cur_can_queue;
> >>>  		spin_unlock_irqrestore(instance->host->host_lock, flags);
> >>>  	}
> >>>  }
> >>> @@ -2942,6 +2946,16 @@ megasas_page_size_show(struct device *cdev,
> >>>  	return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long)PAGE_SIZE
> > -
> >>> 1);  }
> >>>
> >>> +static ssize_t
> >>> +megasas_ldio_outstanding_show(struct device *cdev, struct
> > device_attribute
> >> *attr,
> >>> +	char *buf)
> >>> +{
> >>> +	struct Scsi_Host *shost = class_to_shost(cdev);
> >>> +	struct megasas_instance *instance = (struct megasas_instance
> >>> +*)shost->hostdata;
> >>> +
> >>> +	return snprintf(buf, PAGE_SIZE, "%d\n",
> >>> +atomic_read(&instance->ldio_outstanding));
> >>> +}
> >>> +
> >>>  static DEVICE_ATTR(fw_crash_buffer, S_IRUGO | S_IWUSR,
> >>>  	megasas_fw_crash_buffer_show, megasas_fw_crash_buffer_store);
> >>> static DEVICE_ATTR(fw_crash_buffer_size, S_IRUGO, @@ -2950,12
> >>> +2964,15 @@ static DEVICE_ATTR(fw_crash_state, S_IRUGO | S_IWUSR,
> >>>  	megasas_fw_crash_state_show, megasas_fw_crash_state_store);
> >> static
> >>> DEVICE_ATTR(page_size, S_IRUGO,
> >>>  	megasas_page_size_show, NULL);
> >>> +static DEVICE_ATTR(ldio_outstanding, S_IRUGO,
> >>> +	megasas_ldio_outstanding_show, NULL);
> >>>
> >>>  struct device_attribute *megaraid_host_attrs[] = {
> >>>  	&dev_attr_fw_crash_buffer_size,
> >>>  	&dev_attr_fw_crash_buffer,
> >>>  	&dev_attr_fw_crash_state,
> >>>  	&dev_attr_page_size,
> >>> +	&dev_attr_ldio_outstanding,
> >>>  	NULL,
> >>>  };
> >>>
> >>> @@ -4750,6 +4767,7 @@ megasas_init_adapter_mfi(struct
> >>> megasas_instance
> >> *instance)
> >>>  		sema_init(&instance->ioctl_sem,
> >> (MEGASAS_MFI_IOCTL_CMDS));
> >>>  	}
> >>>
> >>> +	instance->cur_can_queue = instance->max_scsi_cmds;
> >>>  	/*
> >>>  	 * Create a pool of commands
> >>>  	 */
> >>> diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c
> >>> b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> >>> index 9ad779d..7cc7806 100644
> >>> --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
> >>> +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> >>> @@ -92,6 +92,7 @@ void megasas_start_timer(struct megasas_instance
> >> *instance,
> >>>  			 void *fn, unsigned long interval);  extern struct
> >>> megasas_mgmt_info megasas_mgmt_info;  extern int resetwaittime;
> >>> +extern unsigned int dual_qdepth_disable;
> >>>  static void megasas_free_rdpq_fusion(struct megasas_instance
> >>> *instance);  static void megasas_free_reply_fusion(struct
> >>> megasas_instance *instance);
> >>>
> >>> @@ -208,6 +209,67 @@ megasas_fire_cmd_fusion(struct
> megasas_instance
> >>> *instance,  }
> >>>
> >>>  /**
> >>> + * megasas_fusion_update_can_queue -	Do all Adapter Queue depth
> >> related calculations here
> >>> + * @instance:
> >> 	Adapter soft state
> >>> + * fw_boot_context:
> > Whether this
> >> function called during probe or after OCR
> >>> + *
> >>> + * This function is only for fusion controllers.
> >>> + * Update host can queue, if firmware downgrade max supported
> > firmware
> >> commands.
> >>> + * Firmware upgrade case will be skiped because underlying firmware
> >>> +has
> >>> + * more resource than exposed to the OS.
> >>> + *
> >>> + */
> >>> +static void
> >>> +megasas_fusion_update_can_queue(struct megasas_instance *instance,
> >>> +int fw_boot_context) {
> >>> +	u16 cur_max_fw_cmds = 0;
> >>> +	u16 ldio_threshold = 0;
> >>> +	struct megasas_register_set __iomem *reg_set;
> >>> +
> >>> +	reg_set = instance->reg_set;
> >>> +
> >>> +	cur_max_fw_cmds = readl(&instance->reg_set-
> >>> outbound_scratch_pad_3)
> >>> +& 0x00FFFF;
> >>> +
> >>> +	if (dual_qdepth_disable || !cur_max_fw_cmds)
> >>> +		cur_max_fw_cmds = instance->instancet-
> >>> read_fw_status_reg(reg_set) & 0x00FFFF;
> >>> +	else
> >>> +		ldio_threshold =
> >>> +			(instance->instancet->read_fw_status_reg(reg_set)
> > &
> >> 0x00FFFF) -
> >>> +MEGASAS_FUSION_IOCTL_CMDS;
> >>> +
> >>> +	dev_info(&instance->pdev->dev,
> >>> +			"Current firmware maximum commands: %d\t LDIO
> >> thershold: %d\n",
> >>
> >> a typo in "thershold"
> >>
> >>> +			cur_max_fw_cmds, ldio_threshold);
> >>> +
> >>> +	if (fw_boot_context == OCR_CONTEXT) {
> >>> +		cur_max_fw_cmds = cur_max_fw_cmds - 1;
> >>> +		if (cur_max_fw_cmds <= instance->max_fw_cmds) {
> >> probably '<' instead of '<=" could be here ?
> >>
> >>> +			instance->cur_can_queue =
> >>> +				cur_max_fw_cmds -
> >> (MEGASAS_FUSION_INTERNAL_CMDS +
> >>> +
> >> 	MEGASAS_FUSION_IOCTL_CMDS);
> >>> +			instance->host->can_queue = instance-
> >>> cur_can_queue;
> >>> +			instance->ldio_threshold = ldio_threshold;
> >>> +		}
> >>> +	} else {
> >>> +		instance->max_fw_cmds = cur_max_fw_cmds;
> >>> +		instance->ldio_threshold = ldio_threshold;
> >>> +
> >>> +		if (!instance->is_rdpq)
> >>> +			instance->max_fw_cmds = min_t(u16, instance-
> >>> max_fw_cmds, 1024);
> >>> +
> >>> +		/*
> >>> +		* Reduce the max supported cmds by 1. This is to ensure
> > that
> >> the
> >>> +		* reply_q_sz (1 more than the max cmd that driver may
> > send)
> >>> +		* does not exceed max cmds that the FW can support
> >>> +		*/
> >>> +		instance->max_fw_cmds = instance->max_fw_cmds-1;
> >>> +
> >>> +		instance->max_scsi_cmds = instance->max_fw_cmds -
> >>> +				(MEGASAS_FUSION_INTERNAL_CMDS +
> >>> +				MEGASAS_FUSION_IOCTL_CMDS);
> >>> +		instance->cur_can_queue = instance->max_scsi_cmds;
> >>> +	}
> >>> +}
> >>> +/**
> >>>   * megasas_free_cmds_fusion -	Free all the cmds in the free cmd
> > pool
> >>>   * @instance:		Adapter soft state
> >>>   */
> >>> @@ -736,6 +798,8 @@ megasas_ioc_init_fusion(struct megasas_instance
> >> *instance)
> >>>  		drv_ops->mfi_capabilities.support_ext_io_size = 1;
> >>>
> >>>  	drv_ops->mfi_capabilities.support_fp_rlbypass = 1;
> >>> +	if (!dual_qdepth_disable)
> >>> +		drv_ops->mfi_capabilities.support_ext_queue_depth = 1;
> >>>
> >>>  	/* Convert capability to LE32 */
> >>>  	cpu_to_le32s((u32
> >>> *)&init_frame->driver_operations.mfi_capabilities);
> >>> @@ -1151,15 +1215,7 @@ megasas_init_adapter_fusion(struct
> >>> megasas_instance *instance)
> >>>
> >>>  	reg_set = instance->reg_set;
> >>>
> >>> -	/*
> >>> -	 * Get various operational parameters from status register
> >>> -	 */
> >>> -	instance->max_fw_cmds =
> >>> -		instance->instancet->read_fw_status_reg(reg_set) &
> > 0x00FFFF;
> >>> -	dev_info(&instance->pdev->dev,
> >>> -		"firmware support max fw cmd\t: (%d)\n", instance-
> >>> max_fw_cmds);
> >>> -	if (!instance->is_rdpq)
> >>> -		instance->max_fw_cmds = min_t(u16, instance-
> >>> max_fw_cmds, 1024);
> >>> +	megasas_fusion_update_can_queue(instance, PROBE_CONTEXT);
> >>>
> >>>  	/*
> >>>  	 * Reduce the max supported cmds by 1. This is to ensure that the
> > @@
> >>> -2117,6 +2173,15 @@ megasas_build_and_issue_cmd_fusion(struct
> >>> megasas_instance *instance,
> >>>
> >>>  	fusion = instance->ctrl_context;
> >>>
> >>> +	if (megasas_cmd_type(scmd) == READ_WRITE_LDIO) {
> >>> +		if (instance->ldio_threshold &&
> >>> +			(atomic_read(&instance->ldio_outstanding) >=
> >>> +			instance->ldio_threshold))
> >> This test above won't you protect when several processes read the
> >> same
> > value
> >> in parallel, so it may happen that you get over the limit set for
> > ldio_threshold.
> >> (You might use instead a construction with atomic_dec_and_test for
> > example)
> >
> > Agree..I will fix this and send updated patch.
>
> In addition to my previous comments - I'm no sure if the idea of two
> queues
> doesn't have some pitfalls - your parallel queue is based on returning
> commands
> to the midlayer with SCSI_MLQUEUE_DEVICE_BUSY - that makes it repeatedly
> post it to your queue again. Isn't there a performance loss with Virtual
> Disks ?

Yes this is already covered internally, there would be perf penalty with VDs
in configuration but this feature will be turned on based on firmware
settings and that specific firmware deployment has primary purpose
of increasing JBOD performance. This focuses on firmware deployment with
less VDs(or no) and more JBODs in configuration.

Thanks,
Sumit

>
>
> >> tomash
> >

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 09/15] megaraid_sas: Dual Queue depth support
  2016-01-20 14:09         ` Sumit Saxena
@ 2016-01-20 14:16           ` Tomas Henzl
  2016-01-20 15:08             ` Sumit Saxena
  2016-01-27  2:02             ` Martin K. Petersen
  0 siblings, 2 replies; 50+ messages in thread
From: Tomas Henzl @ 2016-01-20 14:16 UTC (permalink / raw)
  To: Sumit Saxena, jbottomley, hch, martin.petersen; +Cc: linux-scsi, Kashyap Desai

On 20.1.2016 15:09, Sumit Saxena wrote:
>> -----Original Message-----
>> From: Tomas Henzl [mailto:thenzl@redhat.com]
>> Sent: Wednesday, January 20, 2016 7:26 PM
>> To: Sumit Saxena; jbottomley@parallels.com; hch@infradead.org;
>> martin.petersen@oracle.com
>> Cc: linux-scsi@vger.kernel.org; Kashyap Desai
>> Subject: Re: [PATCH 09/15] megaraid_sas: Dual Queue depth support
>>
>> On 19.1.2016 14:44, Sumit Saxena wrote:
>>>> -----Original Message-----
>>>> From: Tomas Henzl [mailto:thenzl@redhat.com]
>>>> Sent: Tuesday, January 19, 2016 7:04 PM
>>>> To: Sumit Saxena; jbottomley@parallels.com; hch@infradead.org;
>>>> martin.petersen@oracle.com
>>>> Cc: linux-scsi@vger.kernel.org; kashyap.desai@avagotech.com
>>>> Subject: Re: [PATCH 09/15] megaraid_sas: Dual Queue depth support
>>>>
>>>> On 18.12.2015 14:27, Sumit Saxena wrote:
>>>>> This patch will add support for Dual Queue depth reported by firmware.
>>>>>
>>>>> Below are key points-
>>>>>
>>>>> 1. For iMR controllers, firmware will report two queue depths- 1.
>>> Controller
>>>> wide Queue depth 2. LDIO Queue depth(240).
>>>>> Ofcourse, Controller wide Queue depth will be greater among two.
>>>>> Using this new method, iMR can provide larger Queue depth(QD) for
>>>>> JBOD and limited QD for Virtual Disk(VD). This feature gives benefit
>>>>> for iMR
>>> product
>>>> which will be used for deployment with large number of JBOD and
>>>> limited number of VD on setup.
>>>>> 2. megaraid_sas driver will throttle Read write LDIOs based when RW
>>> LDIOs
>>>> reaches "LDIO Queue Depth".
>>>>> 3. This feature of dual queue depth can enabled/disabled via module
>>>> parameter. Default behavior is: Dual Queue depth is enabled.
>>>>> 4. Added sysfs parameter "ldio_outstanding" for user to read LDIO
>>> outstanding
>>>> at run time.
>>>>> Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
>>>>> Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
>>>>> ---
>>>>>  drivers/scsi/megaraid/megaraid_sas.h        |    9 +++
>>>>>  drivers/scsi/megaraid/megaraid_sas_base.c   |   20 ++++++-
>>>>>  drivers/scsi/megaraid/megaraid_sas_fusion.c |   89
>>>> ++++++++++++++++++++++++---
>>>>>  3 files changed, 108 insertions(+), 10 deletions(-)
>>>>>
>>>>> diff --git a/drivers/scsi/megaraid/megaraid_sas.h
>>>>> b/drivers/scsi/megaraid/megaraid_sas.h
>>>>> index c539516..4595ef4 100644
>>>>> --- a/drivers/scsi/megaraid/megaraid_sas.h
>>>>> +++ b/drivers/scsi/megaraid/megaraid_sas.h
>>>>> @@ -1353,6 +1353,12 @@ enum DCMD_TIMEOUT_ACTION {
>>>>>  	KILL_ADAPTER = 1,
>>>>>  	IGNORE_TIMEOUT = 2,
>>>>>  };
>>>>> +
>>>>> +enum FW_BOOT_CONTEXT {
>>>>> +	PROBE_CONTEXT = 0,
>>>>> +	OCR_CONTEXT = 1,
>>>>> +};
>>>>> +
>>>>>  /* Frame Type */
>>>>>  #define IO_FRAME				0
>>>>>  #define PTHRU_FRAME				1
>>>>> @@ -2038,6 +2044,8 @@ struct megasas_instance {
>>>>>  	u16 max_fw_cmds;
>>>>>  	u16 max_mfi_cmds;
>>>>>  	u16 max_scsi_cmds;
>>>>> +	u16 ldio_threshold;
>>>>> +	u16 cur_can_queue;
>>>>>  	u32 max_sectors_per_req;
>>>>>  	struct megasas_aen_event *ev;
>>>>>
>>>>> @@ -2068,6 +2076,7 @@ struct megasas_instance {
>>>>>  	u32 fw_support_ieee;
>>>>>
>>>>>  	atomic_t fw_outstanding;
>>>>> +	atomic_t ldio_outstanding;
>>>>>  	atomic_t fw_reset_no_pci_access;
>>>>>
>>>>>  	struct megasas_instance_template *instancet; diff --git
>>>>> a/drivers/scsi/megaraid/megaraid_sas_base.c
>>>>> b/drivers/scsi/megaraid/megaraid_sas_base.c
>>>>> index 3454c5e..edc26fb 100644
>>>>> --- a/drivers/scsi/megaraid/megaraid_sas_base.c
>>>>> +++ b/drivers/scsi/megaraid/megaraid_sas_base.c
>>>>> @@ -96,6 +96,10 @@ int rdpq_enable = 1;  module_param(rdpq_enable,
>>>>> int, S_IRUGO);  MODULE_PARM_DESC(rdpq_enable, " Allocate reply queue
>>>>> in chunks for large queue depth enable/disbale Default:
>>>>> disable(0)");
>>>>>
>>>>> +unsigned int dual_qdepth_disable;
>>>>> +module_param(dual_qdepth_disable, int, S_IRUGO);
>>>>> +MODULE_PARM_DESC(dual_qdepth_disable, "Disable dual queue depth
>>>>> +feature. Default: 0");
>>>>> +
>>>>>  MODULE_LICENSE("GPL");
>>>>>  MODULE_VERSION(MEGASAS_VERSION);
>>>>>  MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com");
>>>>> @@ -1977,7 +1981,7 @@
>> megasas_check_and_restore_queue_depth(struct
>>>> megasas_instance *instance)
>>>>>  		spin_lock_irqsave(instance->host->host_lock, flags);
>>>>>  		instance->flag &= ~MEGASAS_FW_BUSY;
>>>>>
>>>>> -		instance->host->can_queue = instance->max_scsi_cmds;
>>>>> +		instance->host->can_queue = instance->cur_can_queue;
>>>>>  		spin_unlock_irqrestore(instance->host->host_lock, flags);
>>>>>  	}
>>>>>  }
>>>>> @@ -2942,6 +2946,16 @@ megasas_page_size_show(struct device *cdev,
>>>>>  	return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long)PAGE_SIZE
>>> -
>>>>> 1);  }
>>>>>
>>>>> +static ssize_t
>>>>> +megasas_ldio_outstanding_show(struct device *cdev, struct
>>> device_attribute
>>>> *attr,
>>>>> +	char *buf)
>>>>> +{
>>>>> +	struct Scsi_Host *shost = class_to_shost(cdev);
>>>>> +	struct megasas_instance *instance = (struct megasas_instance
>>>>> +*)shost->hostdata;
>>>>> +
>>>>> +	return snprintf(buf, PAGE_SIZE, "%d\n",
>>>>> +atomic_read(&instance->ldio_outstanding));
>>>>> +}
>>>>> +
>>>>>  static DEVICE_ATTR(fw_crash_buffer, S_IRUGO | S_IWUSR,
>>>>>  	megasas_fw_crash_buffer_show, megasas_fw_crash_buffer_store);
>>>>> static DEVICE_ATTR(fw_crash_buffer_size, S_IRUGO, @@ -2950,12
>>>>> +2964,15 @@ static DEVICE_ATTR(fw_crash_state, S_IRUGO | S_IWUSR,
>>>>>  	megasas_fw_crash_state_show, megasas_fw_crash_state_store);
>>>> static
>>>>> DEVICE_ATTR(page_size, S_IRUGO,
>>>>>  	megasas_page_size_show, NULL);
>>>>> +static DEVICE_ATTR(ldio_outstanding, S_IRUGO,
>>>>> +	megasas_ldio_outstanding_show, NULL);
>>>>>
>>>>>  struct device_attribute *megaraid_host_attrs[] = {
>>>>>  	&dev_attr_fw_crash_buffer_size,
>>>>>  	&dev_attr_fw_crash_buffer,
>>>>>  	&dev_attr_fw_crash_state,
>>>>>  	&dev_attr_page_size,
>>>>> +	&dev_attr_ldio_outstanding,
>>>>>  	NULL,
>>>>>  };
>>>>>
>>>>> @@ -4750,6 +4767,7 @@ megasas_init_adapter_mfi(struct
>>>>> megasas_instance
>>>> *instance)
>>>>>  		sema_init(&instance->ioctl_sem,
>>>> (MEGASAS_MFI_IOCTL_CMDS));
>>>>>  	}
>>>>>
>>>>> +	instance->cur_can_queue = instance->max_scsi_cmds;
>>>>>  	/*
>>>>>  	 * Create a pool of commands
>>>>>  	 */
>>>>> diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c
>>>>> b/drivers/scsi/megaraid/megaraid_sas_fusion.c
>>>>> index 9ad779d..7cc7806 100644
>>>>> --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
>>>>> +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
>>>>> @@ -92,6 +92,7 @@ void megasas_start_timer(struct megasas_instance
>>>> *instance,
>>>>>  			 void *fn, unsigned long interval);  extern struct
>>>>> megasas_mgmt_info megasas_mgmt_info;  extern int resetwaittime;
>>>>> +extern unsigned int dual_qdepth_disable;
>>>>>  static void megasas_free_rdpq_fusion(struct megasas_instance
>>>>> *instance);  static void megasas_free_reply_fusion(struct
>>>>> megasas_instance *instance);
>>>>>
>>>>> @@ -208,6 +209,67 @@ megasas_fire_cmd_fusion(struct
>> megasas_instance
>>>>> *instance,  }
>>>>>
>>>>>  /**
>>>>> + * megasas_fusion_update_can_queue -	Do all Adapter Queue depth
>>>> related calculations here
>>>>> + * @instance:
>>>> 	Adapter soft state
>>>>> + * fw_boot_context:
>>> Whether this
>>>> function called during probe or after OCR
>>>>> + *
>>>>> + * This function is only for fusion controllers.
>>>>> + * Update host can queue, if firmware downgrade max supported
>>> firmware
>>>> commands.
>>>>> + * Firmware upgrade case will be skiped because underlying firmware
>>>>> +has
>>>>> + * more resource than exposed to the OS.
>>>>> + *
>>>>> + */
>>>>> +static void
>>>>> +megasas_fusion_update_can_queue(struct megasas_instance *instance,
>>>>> +int fw_boot_context) {
>>>>> +	u16 cur_max_fw_cmds = 0;
>>>>> +	u16 ldio_threshold = 0;
>>>>> +	struct megasas_register_set __iomem *reg_set;
>>>>> +
>>>>> +	reg_set = instance->reg_set;
>>>>> +
>>>>> +	cur_max_fw_cmds = readl(&instance->reg_set-
>>>>> outbound_scratch_pad_3)
>>>>> +& 0x00FFFF;
>>>>> +
>>>>> +	if (dual_qdepth_disable || !cur_max_fw_cmds)
>>>>> +		cur_max_fw_cmds = instance->instancet-
>>>>> read_fw_status_reg(reg_set) & 0x00FFFF;
>>>>> +	else
>>>>> +		ldio_threshold =
>>>>> +			(instance->instancet->read_fw_status_reg(reg_set)
>>> &
>>>> 0x00FFFF) -
>>>>> +MEGASAS_FUSION_IOCTL_CMDS;
>>>>> +
>>>>> +	dev_info(&instance->pdev->dev,
>>>>> +			"Current firmware maximum commands: %d\t LDIO
>>>> thershold: %d\n",
>>>>
>>>> a typo in "thershold"
>>>>
>>>>> +			cur_max_fw_cmds, ldio_threshold);
>>>>> +
>>>>> +	if (fw_boot_context == OCR_CONTEXT) {
>>>>> +		cur_max_fw_cmds = cur_max_fw_cmds - 1;
>>>>> +		if (cur_max_fw_cmds <= instance->max_fw_cmds) {
>>>> probably '<' instead of '<=" could be here ?
>>>>
>>>>> +			instance->cur_can_queue =
>>>>> +				cur_max_fw_cmds -
>>>> (MEGASAS_FUSION_INTERNAL_CMDS +
>>>>> +
>>>> 	MEGASAS_FUSION_IOCTL_CMDS);
>>>>> +			instance->host->can_queue = instance-
>>>>> cur_can_queue;
>>>>> +			instance->ldio_threshold = ldio_threshold;
>>>>> +		}
>>>>> +	} else {
>>>>> +		instance->max_fw_cmds = cur_max_fw_cmds;
>>>>> +		instance->ldio_threshold = ldio_threshold;
>>>>> +
>>>>> +		if (!instance->is_rdpq)
>>>>> +			instance->max_fw_cmds = min_t(u16, instance-
>>>>> max_fw_cmds, 1024);
>>>>> +
>>>>> +		/*
>>>>> +		* Reduce the max supported cmds by 1. This is to ensure
>>> that
>>>> the
>>>>> +		* reply_q_sz (1 more than the max cmd that driver may
>>> send)
>>>>> +		* does not exceed max cmds that the FW can support
>>>>> +		*/
>>>>> +		instance->max_fw_cmds = instance->max_fw_cmds-1;
>>>>> +
>>>>> +		instance->max_scsi_cmds = instance->max_fw_cmds -
>>>>> +				(MEGASAS_FUSION_INTERNAL_CMDS +
>>>>> +				MEGASAS_FUSION_IOCTL_CMDS);
>>>>> +		instance->cur_can_queue = instance->max_scsi_cmds;
>>>>> +	}
>>>>> +}
>>>>> +/**
>>>>>   * megasas_free_cmds_fusion -	Free all the cmds in the free cmd
>>> pool
>>>>>   * @instance:		Adapter soft state
>>>>>   */
>>>>> @@ -736,6 +798,8 @@ megasas_ioc_init_fusion(struct megasas_instance
>>>> *instance)
>>>>>  		drv_ops->mfi_capabilities.support_ext_io_size = 1;
>>>>>
>>>>>  	drv_ops->mfi_capabilities.support_fp_rlbypass = 1;
>>>>> +	if (!dual_qdepth_disable)
>>>>> +		drv_ops->mfi_capabilities.support_ext_queue_depth = 1;
>>>>>
>>>>>  	/* Convert capability to LE32 */
>>>>>  	cpu_to_le32s((u32
>>>>> *)&init_frame->driver_operations.mfi_capabilities);
>>>>> @@ -1151,15 +1215,7 @@ megasas_init_adapter_fusion(struct
>>>>> megasas_instance *instance)
>>>>>
>>>>>  	reg_set = instance->reg_set;
>>>>>
>>>>> -	/*
>>>>> -	 * Get various operational parameters from status register
>>>>> -	 */
>>>>> -	instance->max_fw_cmds =
>>>>> -		instance->instancet->read_fw_status_reg(reg_set) &
>>> 0x00FFFF;
>>>>> -	dev_info(&instance->pdev->dev,
>>>>> -		"firmware support max fw cmd\t: (%d)\n", instance-
>>>>> max_fw_cmds);
>>>>> -	if (!instance->is_rdpq)
>>>>> -		instance->max_fw_cmds = min_t(u16, instance-
>>>>> max_fw_cmds, 1024);
>>>>> +	megasas_fusion_update_can_queue(instance, PROBE_CONTEXT);
>>>>>
>>>>>  	/*
>>>>>  	 * Reduce the max supported cmds by 1. This is to ensure that the
>>> @@
>>>>> -2117,6 +2173,15 @@ megasas_build_and_issue_cmd_fusion(struct
>>>>> megasas_instance *instance,
>>>>>
>>>>>  	fusion = instance->ctrl_context;
>>>>>
>>>>> +	if (megasas_cmd_type(scmd) == READ_WRITE_LDIO) {
>>>>> +		if (instance->ldio_threshold &&
>>>>> +			(atomic_read(&instance->ldio_outstanding) >=
>>>>> +			instance->ldio_threshold))
>>>> This test above won't you protect when several processes read the
>>>> same
>>> value
>>>> in parallel, so it may happen that you get over the limit set for
>>> ldio_threshold.
>>>> (You might use instead a construction with atomic_dec_and_test for
>>> example)
>>>
>>> Agree..I will fix this and send updated patch.
>> In addition to my previous comments - I'm no sure if the idea of two
>> queues
>> doesn't have some pitfalls - your parallel queue is based on returning
>> commands
>> to the midlayer with SCSI_MLQUEUE_DEVICE_BUSY - that makes it repeatedly
>> post it to your queue again. Isn't there a performance loss with Virtual
>> Disks ?
> Yes this is already covered internally, there would be perf penalty with VDs
> in configuration but this feature will be turned on based on firmware
> settings and that specific firmware deployment has primary purpose
> of increasing JBOD performance. This focuses on firmware deployment with
> less VDs(or no) and more JBODs in configuration.

OK, so it is switched off by default in the firmware and the user
and an educated user can switch it on ? if so, it's fine for me.

>
> Thanks,
> Sumit
>
>>
>>>> tomash


^ permalink raw reply	[flat|nested] 50+ messages in thread

* RE: [PATCH 09/15] megaraid_sas: Dual Queue depth support
  2016-01-20 14:16           ` Tomas Henzl
@ 2016-01-20 15:08             ` Sumit Saxena
  2016-01-20 16:00               ` Tomas Henzl
  2016-01-27  2:02             ` Martin K. Petersen
  1 sibling, 1 reply; 50+ messages in thread
From: Sumit Saxena @ 2016-01-20 15:08 UTC (permalink / raw)
  To: Tomas Henzl, jbottomley, hch, martin.petersen; +Cc: linux-scsi, Kashyap Desai

> -----Original Message-----
> From: Tomas Henzl [mailto:thenzl@redhat.com]
> Sent: Wednesday, January 20, 2016 7:46 PM
> To: Sumit Saxena; jbottomley@parallels.com; hch@infradead.org;
> martin.petersen@oracle.com
> Cc: linux-scsi@vger.kernel.org; Kashyap Desai
> Subject: Re: [PATCH 09/15] megaraid_sas: Dual Queue depth support
>
> On 20.1.2016 15:09, Sumit Saxena wrote:
> >> -----Original Message-----
> >> From: Tomas Henzl [mailto:thenzl@redhat.com]
> >> Sent: Wednesday, January 20, 2016 7:26 PM
> >> To: Sumit Saxena; jbottomley@parallels.com; hch@infradead.org;
> >> martin.petersen@oracle.com
> >> Cc: linux-scsi@vger.kernel.org; Kashyap Desai
> >> Subject: Re: [PATCH 09/15] megaraid_sas: Dual Queue depth support
> >>
> >> On 19.1.2016 14:44, Sumit Saxena wrote:
> >>>> -----Original Message-----
> >>>> From: Tomas Henzl [mailto:thenzl@redhat.com]
> >>>> Sent: Tuesday, January 19, 2016 7:04 PM
> >>>> To: Sumit Saxena; jbottomley@parallels.com; hch@infradead.org;
> >>>> martin.petersen@oracle.com
> >>>> Cc: linux-scsi@vger.kernel.org; kashyap.desai@avagotech.com
> >>>> Subject: Re: [PATCH 09/15] megaraid_sas: Dual Queue depth support
> >>>>
> >>>> On 18.12.2015 14:27, Sumit Saxena wrote:
> >>>>> This patch will add support for Dual Queue depth reported by
> >>>>> firmware.
> >>>>>
> >>>>> Below are key points-
> >>>>>
> >>>>> 1. For iMR controllers, firmware will report two queue depths- 1.
> >>> Controller
> >>>> wide Queue depth 2. LDIO Queue depth(240).
> >>>>> Ofcourse, Controller wide Queue depth will be greater among two.
> >>>>> Using this new method, iMR can provide larger Queue depth(QD) for
> >>>>> JBOD and limited QD for Virtual Disk(VD). This feature gives
> >>>>> benefit for iMR
> >>> product
> >>>> which will be used for deployment with large number of JBOD and
> >>>> limited number of VD on setup.
> >>>>> 2. megaraid_sas driver will throttle Read write LDIOs based when
> >>>>> RW
> >>> LDIOs
> >>>> reaches "LDIO Queue Depth".
> >>>>> 3. This feature of dual queue depth can enabled/disabled via
> >>>>> module
> >>>> parameter. Default behavior is: Dual Queue depth is enabled.
> >>>>> 4. Added sysfs parameter "ldio_outstanding" for user to read LDIO
> >>> outstanding
> >>>> at run time.
> >>>>> Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
> >>>>> Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
> >>>>> ---
> >>>>>  drivers/scsi/megaraid/megaraid_sas.h        |    9 +++
> >>>>>  drivers/scsi/megaraid/megaraid_sas_base.c   |   20 ++++++-
> >>>>>  drivers/scsi/megaraid/megaraid_sas_fusion.c |   89
> >>>> ++++++++++++++++++++++++---
> >>>>>  3 files changed, 108 insertions(+), 10 deletions(-)
> >>>>>
> >>>>> diff --git a/drivers/scsi/megaraid/megaraid_sas.h
> >>>>> b/drivers/scsi/megaraid/megaraid_sas.h
> >>>>> index c539516..4595ef4 100644
> >>>>> --- a/drivers/scsi/megaraid/megaraid_sas.h
> >>>>> +++ b/drivers/scsi/megaraid/megaraid_sas.h
> >>>>> @@ -1353,6 +1353,12 @@ enum DCMD_TIMEOUT_ACTION {
> >>>>>  	KILL_ADAPTER = 1,
> >>>>>  	IGNORE_TIMEOUT = 2,
> >>>>>  };
> >>>>> +
> >>>>> +enum FW_BOOT_CONTEXT {
> >>>>> +	PROBE_CONTEXT = 0,
> >>>>> +	OCR_CONTEXT = 1,
> >>>>> +};
> >>>>> +
> >>>>>  /* Frame Type */
> >>>>>  #define IO_FRAME				0
> >>>>>  #define PTHRU_FRAME				1
> >>>>> @@ -2038,6 +2044,8 @@ struct megasas_instance {
> >>>>>  	u16 max_fw_cmds;
> >>>>>  	u16 max_mfi_cmds;
> >>>>>  	u16 max_scsi_cmds;
> >>>>> +	u16 ldio_threshold;
> >>>>> +	u16 cur_can_queue;
> >>>>>  	u32 max_sectors_per_req;
> >>>>>  	struct megasas_aen_event *ev;
> >>>>>
> >>>>> @@ -2068,6 +2076,7 @@ struct megasas_instance {
> >>>>>  	u32 fw_support_ieee;
> >>>>>
> >>>>>  	atomic_t fw_outstanding;
> >>>>> +	atomic_t ldio_outstanding;
> >>>>>  	atomic_t fw_reset_no_pci_access;
> >>>>>
> >>>>>  	struct megasas_instance_template *instancet; diff --git
> >>>>> a/drivers/scsi/megaraid/megaraid_sas_base.c
> >>>>> b/drivers/scsi/megaraid/megaraid_sas_base.c
> >>>>> index 3454c5e..edc26fb 100644
> >>>>> --- a/drivers/scsi/megaraid/megaraid_sas_base.c
> >>>>> +++ b/drivers/scsi/megaraid/megaraid_sas_base.c
> >>>>> @@ -96,6 +96,10 @@ int rdpq_enable = 1;  module_param(rdpq_enable,
> >>>>> int, S_IRUGO);  MODULE_PARM_DESC(rdpq_enable, " Allocate reply
> >>>>> queue in chunks for large queue depth enable/disbale Default:
> >>>>> disable(0)");
> >>>>>
> >>>>> +unsigned int dual_qdepth_disable;
> >>>>> +module_param(dual_qdepth_disable, int, S_IRUGO);
> >>>>> +MODULE_PARM_DESC(dual_qdepth_disable, "Disable dual queue depth
> >>>>> +feature. Default: 0");
> >>>>> +
> >>>>>  MODULE_LICENSE("GPL");
> >>>>>  MODULE_VERSION(MEGASAS_VERSION);
> >>>>>  MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com");
> >>>>> @@ -1977,7 +1981,7 @@
> >> megasas_check_and_restore_queue_depth(struct
> >>>> megasas_instance *instance)
> >>>>>  		spin_lock_irqsave(instance->host->host_lock, flags);
> >>>>>  		instance->flag &= ~MEGASAS_FW_BUSY;
> >>>>>
> >>>>> -		instance->host->can_queue = instance->max_scsi_cmds;
> >>>>> +		instance->host->can_queue = instance->cur_can_queue;
> >>>>>  		spin_unlock_irqrestore(instance->host->host_lock, flags);
> >>>>>  	}
> >>>>>  }
> >>>>> @@ -2942,6 +2946,16 @@ megasas_page_size_show(struct device
> *cdev,
> >>>>>  	return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned
> >>>>> long)PAGE_SIZE
> >>> -
> >>>>> 1);  }
> >>>>>
> >>>>> +static ssize_t
> >>>>> +megasas_ldio_outstanding_show(struct device *cdev, struct
> >>> device_attribute
> >>>> *attr,
> >>>>> +	char *buf)
> >>>>> +{
> >>>>> +	struct Scsi_Host *shost = class_to_shost(cdev);
> >>>>> +	struct megasas_instance *instance = (struct megasas_instance
> >>>>> +*)shost->hostdata;
> >>>>> +
> >>>>> +	return snprintf(buf, PAGE_SIZE, "%d\n",
> >>>>> +atomic_read(&instance->ldio_outstanding));
> >>>>> +}
> >>>>> +
> >>>>>  static DEVICE_ATTR(fw_crash_buffer, S_IRUGO | S_IWUSR,
> >>>>>  	megasas_fw_crash_buffer_show, megasas_fw_crash_buffer_store);
> >>>>> static DEVICE_ATTR(fw_crash_buffer_size, S_IRUGO, @@ -2950,12
> >>>>> +2964,15 @@ static DEVICE_ATTR(fw_crash_state, S_IRUGO | S_IWUSR,
> >>>>>  	megasas_fw_crash_state_show, megasas_fw_crash_state_store);
> >>>> static
> >>>>> DEVICE_ATTR(page_size, S_IRUGO,
> >>>>>  	megasas_page_size_show, NULL);
> >>>>> +static DEVICE_ATTR(ldio_outstanding, S_IRUGO,
> >>>>> +	megasas_ldio_outstanding_show, NULL);
> >>>>>
> >>>>>  struct device_attribute *megaraid_host_attrs[] = {
> >>>>>  	&dev_attr_fw_crash_buffer_size,
> >>>>>  	&dev_attr_fw_crash_buffer,
> >>>>>  	&dev_attr_fw_crash_state,
> >>>>>  	&dev_attr_page_size,
> >>>>> +	&dev_attr_ldio_outstanding,
> >>>>>  	NULL,
> >>>>>  };
> >>>>>
> >>>>> @@ -4750,6 +4767,7 @@ megasas_init_adapter_mfi(struct
> >>>>> megasas_instance
> >>>> *instance)
> >>>>>  		sema_init(&instance->ioctl_sem,
> >>>> (MEGASAS_MFI_IOCTL_CMDS));
> >>>>>  	}
> >>>>>
> >>>>> +	instance->cur_can_queue = instance->max_scsi_cmds;
> >>>>>  	/*
> >>>>>  	 * Create a pool of commands
> >>>>>  	 */
> >>>>> diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c
> >>>>> b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> >>>>> index 9ad779d..7cc7806 100644
> >>>>> --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
> >>>>> +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> >>>>> @@ -92,6 +92,7 @@ void megasas_start_timer(struct megasas_instance
> >>>> *instance,
> >>>>>  			 void *fn, unsigned long interval);  extern struct
> >>>>> megasas_mgmt_info megasas_mgmt_info;  extern int resetwaittime;
> >>>>> +extern unsigned int dual_qdepth_disable;
> >>>>>  static void megasas_free_rdpq_fusion(struct megasas_instance
> >>>>> *instance);  static void megasas_free_reply_fusion(struct
> >>>>> megasas_instance *instance);
> >>>>>
> >>>>> @@ -208,6 +209,67 @@ megasas_fire_cmd_fusion(struct
> >> megasas_instance
> >>>>> *instance,  }
> >>>>>
> >>>>>  /**
> >>>>> + * megasas_fusion_update_can_queue -	Do all Adapter Queue depth
> >>>> related calculations here
> >>>>> + * @instance:
> >>>> 	Adapter soft state
> >>>>> + * fw_boot_context:
> >>> Whether this
> >>>> function called during probe or after OCR
> >>>>> + *
> >>>>> + * This function is only for fusion controllers.
> >>>>> + * Update host can queue, if firmware downgrade max supported
> >>> firmware
> >>>> commands.
> >>>>> + * Firmware upgrade case will be skiped because underlying
> >>>>> +firmware has
> >>>>> + * more resource than exposed to the OS.
> >>>>> + *
> >>>>> + */
> >>>>> +static void
> >>>>> +megasas_fusion_update_can_queue(struct megasas_instance
> >>>>> +*instance, int fw_boot_context) {
> >>>>> +	u16 cur_max_fw_cmds = 0;
> >>>>> +	u16 ldio_threshold = 0;
> >>>>> +	struct megasas_register_set __iomem *reg_set;
> >>>>> +
> >>>>> +	reg_set = instance->reg_set;
> >>>>> +
> >>>>> +	cur_max_fw_cmds = readl(&instance->reg_set-
> >>>>> outbound_scratch_pad_3)
> >>>>> +& 0x00FFFF;
> >>>>> +
> >>>>> +	if (dual_qdepth_disable || !cur_max_fw_cmds)
> >>>>> +		cur_max_fw_cmds = instance->instancet-
> >>>>> read_fw_status_reg(reg_set) & 0x00FFFF;
> >>>>> +	else
> >>>>> +		ldio_threshold =
> >>>>> +			(instance->instancet->read_fw_status_reg(reg_set)
> >>> &
> >>>> 0x00FFFF) -
> >>>>> +MEGASAS_FUSION_IOCTL_CMDS;
> >>>>> +
> >>>>> +	dev_info(&instance->pdev->dev,
> >>>>> +			"Current firmware maximum commands: %d\t LDIO
> >>>> thershold: %d\n",
> >>>>
> >>>> a typo in "thershold"
> >>>>
> >>>>> +			cur_max_fw_cmds, ldio_threshold);
> >>>>> +
> >>>>> +	if (fw_boot_context == OCR_CONTEXT) {
> >>>>> +		cur_max_fw_cmds = cur_max_fw_cmds - 1;
> >>>>> +		if (cur_max_fw_cmds <= instance->max_fw_cmds) {
> >>>> probably '<' instead of '<=" could be here ?
> >>>>
> >>>>> +			instance->cur_can_queue =
> >>>>> +				cur_max_fw_cmds -
> >>>> (MEGASAS_FUSION_INTERNAL_CMDS +
> >>>>> +
> >>>> 	MEGASAS_FUSION_IOCTL_CMDS);
> >>>>> +			instance->host->can_queue = instance-
> >>>>> cur_can_queue;
> >>>>> +			instance->ldio_threshold = ldio_threshold;
> >>>>> +		}
> >>>>> +	} else {
> >>>>> +		instance->max_fw_cmds = cur_max_fw_cmds;
> >>>>> +		instance->ldio_threshold = ldio_threshold;
> >>>>> +
> >>>>> +		if (!instance->is_rdpq)
> >>>>> +			instance->max_fw_cmds = min_t(u16, instance-
> >>>>> max_fw_cmds, 1024);
> >>>>> +
> >>>>> +		/*
> >>>>> +		* Reduce the max supported cmds by 1. This is to ensure
> >>> that
> >>>> the
> >>>>> +		* reply_q_sz (1 more than the max cmd that driver may
> >>> send)
> >>>>> +		* does not exceed max cmds that the FW can support
> >>>>> +		*/
> >>>>> +		instance->max_fw_cmds = instance->max_fw_cmds-1;
> >>>>> +
> >>>>> +		instance->max_scsi_cmds = instance->max_fw_cmds -
> >>>>> +				(MEGASAS_FUSION_INTERNAL_CMDS +
> >>>>> +				MEGASAS_FUSION_IOCTL_CMDS);
> >>>>> +		instance->cur_can_queue = instance->max_scsi_cmds;
> >>>>> +	}
> >>>>> +}
> >>>>> +/**
> >>>>>   * megasas_free_cmds_fusion -	Free all the cmds in the free cmd
> >>> pool
> >>>>>   * @instance:		Adapter soft state
> >>>>>   */
> >>>>> @@ -736,6 +798,8 @@ megasas_ioc_init_fusion(struct
> >>>>> megasas_instance
> >>>> *instance)
> >>>>>  		drv_ops->mfi_capabilities.support_ext_io_size = 1;
> >>>>>
> >>>>>  	drv_ops->mfi_capabilities.support_fp_rlbypass = 1;
> >>>>> +	if (!dual_qdepth_disable)
> >>>>> +		drv_ops->mfi_capabilities.support_ext_queue_depth = 1;
> >>>>>
> >>>>>  	/* Convert capability to LE32 */
> >>>>>  	cpu_to_le32s((u32
> >>>>> *)&init_frame->driver_operations.mfi_capabilities);
> >>>>> @@ -1151,15 +1215,7 @@ megasas_init_adapter_fusion(struct
> >>>>> megasas_instance *instance)
> >>>>>
> >>>>>  	reg_set = instance->reg_set;
> >>>>>
> >>>>> -	/*
> >>>>> -	 * Get various operational parameters from status register
> >>>>> -	 */
> >>>>> -	instance->max_fw_cmds =
> >>>>> -		instance->instancet->read_fw_status_reg(reg_set) &
> >>> 0x00FFFF;
> >>>>> -	dev_info(&instance->pdev->dev,
> >>>>> -		"firmware support max fw cmd\t: (%d)\n", instance-
> >>>>> max_fw_cmds);
> >>>>> -	if (!instance->is_rdpq)
> >>>>> -		instance->max_fw_cmds = min_t(u16, instance-
> >>>>> max_fw_cmds, 1024);
> >>>>> +	megasas_fusion_update_can_queue(instance, PROBE_CONTEXT);
> >>>>>
> >>>>>  	/*
> >>>>>  	 * Reduce the max supported cmds by 1. This is to ensure that
> >>>>> the
> >>> @@
> >>>>> -2117,6 +2173,15 @@ megasas_build_and_issue_cmd_fusion(struct
> >>>>> megasas_instance *instance,
> >>>>>
> >>>>>  	fusion = instance->ctrl_context;
> >>>>>
> >>>>> +	if (megasas_cmd_type(scmd) == READ_WRITE_LDIO) {
> >>>>> +		if (instance->ldio_threshold &&
> >>>>> +			(atomic_read(&instance->ldio_outstanding) >=
> >>>>> +			instance->ldio_threshold))
> >>>> This test above won't you protect when several processes read the
> >>>> same
> >>> value
> >>>> in parallel, so it may happen that you get over the limit set for
> >>> ldio_threshold.
> >>>> (You might use instead a construction with atomic_dec_and_test for
> >>> example)
> >>>
> >>> Agree..I will fix this and send updated patch.
> >> In addition to my previous comments - I'm no sure if the idea of two
> >> queues doesn't have some pitfalls - your parallel queue is based on
> >> returning commands to the midlayer with SCSI_MLQUEUE_DEVICE_BUSY -
> >> that makes it repeatedly post it to your queue again. Isn't there a
> >> performance loss with Virtual Disks ?
> > Yes this is already covered internally, there would be perf penalty
> > with VDs in configuration but this feature will be turned on based on
> > firmware settings and that specific firmware deployment has primary
> > purpose of increasing JBOD performance. This focuses on firmware
> > deployment with less VDs(or no) and more JBODs in configuration.
>
> OK, so it is switched off by default in the firmware and the user and an
> educated
> user can switch it on ? if so, it's fine for me.

There are different flavors of firmware using same driver and for specific
firmware this will be turned on(by default) where it's really needed.
For rest of firmware flavors, this will be switched off(not supported).
>
> >
> > Thanks,
> > Sumit
> >
> >>
> >>>> tomash

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 09/15] megaraid_sas: Dual Queue depth support
  2016-01-20 15:08             ` Sumit Saxena
@ 2016-01-20 16:00               ` Tomas Henzl
  0 siblings, 0 replies; 50+ messages in thread
From: Tomas Henzl @ 2016-01-20 16:00 UTC (permalink / raw)
  To: Sumit Saxena, jbottomley, hch, martin.petersen; +Cc: linux-scsi, Kashyap Desai

On 20.1.2016 16:08, Sumit Saxena wrote:
>> -----Original Message-----
>> From: Tomas Henzl [mailto:thenzl@redhat.com]
>> Sent: Wednesday, January 20, 2016 7:46 PM
>> To: Sumit Saxena; jbottomley@parallels.com; hch@infradead.org;
>> martin.petersen@oracle.com
>> Cc: linux-scsi@vger.kernel.org; Kashyap Desai
>> Subject: Re: [PATCH 09/15] megaraid_sas: Dual Queue depth support
>>
>> On 20.1.2016 15:09, Sumit Saxena wrote:
>>>> -----Original Message-----
>>>> From: Tomas Henzl [mailto:thenzl@redhat.com]
>>>> Sent: Wednesday, January 20, 2016 7:26 PM
>>>> To: Sumit Saxena; jbottomley@parallels.com; hch@infradead.org;
>>>> martin.petersen@oracle.com
>>>> Cc: linux-scsi@vger.kernel.org; Kashyap Desai
>>>> Subject: Re: [PATCH 09/15] megaraid_sas: Dual Queue depth support
>>>>
>>>> On 19.1.2016 14:44, Sumit Saxena wrote:
>>>>>> -----Original Message-----
>>>>>> From: Tomas Henzl [mailto:thenzl@redhat.com]
>>>>>> Sent: Tuesday, January 19, 2016 7:04 PM
>>>>>> To: Sumit Saxena; jbottomley@parallels.com; hch@infradead.org;
>>>>>> martin.petersen@oracle.com
>>>>>> Cc: linux-scsi@vger.kernel.org; kashyap.desai@avagotech.com
>>>>>> Subject: Re: [PATCH 09/15] megaraid_sas: Dual Queue depth support
>>>>>>
>>>>>> On 18.12.2015 14:27, Sumit Saxena wrote:
>>>>>>> This patch will add support for Dual Queue depth reported by
>>>>>>> firmware.
>>>>>>>
>>>>>>> Below are key points-
>>>>>>>
>>>>>>> 1. For iMR controllers, firmware will report two queue depths- 1.
>>>>> Controller
>>>>>> wide Queue depth 2. LDIO Queue depth(240).
>>>>>>> Ofcourse, Controller wide Queue depth will be greater among two.
>>>>>>> Using this new method, iMR can provide larger Queue depth(QD) for
>>>>>>> JBOD and limited QD for Virtual Disk(VD). This feature gives
>>>>>>> benefit for iMR
>>>>> product
>>>>>> which will be used for deployment with large number of JBOD and
>>>>>> limited number of VD on setup.
>>>>>>> 2. megaraid_sas driver will throttle Read write LDIOs based when
>>>>>>> RW
>>>>> LDIOs
>>>>>> reaches "LDIO Queue Depth".
>>>>>>> 3. This feature of dual queue depth can enabled/disabled via
>>>>>>> module
>>>>>> parameter. Default behavior is: Dual Queue depth is enabled.
>>>>>>> 4. Added sysfs parameter "ldio_outstanding" for user to read LDIO
>>>>> outstanding
>>>>>> at run time.
>>>>>>> Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
>>>>>>> Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
>>>>>>> ---
>>>>>>>  drivers/scsi/megaraid/megaraid_sas.h        |    9 +++
>>>>>>>  drivers/scsi/megaraid/megaraid_sas_base.c   |   20 ++++++-
>>>>>>>  drivers/scsi/megaraid/megaraid_sas_fusion.c |   89
>>>>>> ++++++++++++++++++++++++---
>>>>>>>  3 files changed, 108 insertions(+), 10 deletions(-)
>>>>>>>
>>>>>>> diff --git a/drivers/scsi/megaraid/megaraid_sas.h
>>>>>>> b/drivers/scsi/megaraid/megaraid_sas.h
>>>>>>> index c539516..4595ef4 100644
>>>>>>> --- a/drivers/scsi/megaraid/megaraid_sas.h
>>>>>>> +++ b/drivers/scsi/megaraid/megaraid_sas.h
>>>>>>> @@ -1353,6 +1353,12 @@ enum DCMD_TIMEOUT_ACTION {
>>>>>>>  	KILL_ADAPTER = 1,
>>>>>>>  	IGNORE_TIMEOUT = 2,
>>>>>>>  };
>>>>>>> +
>>>>>>> +enum FW_BOOT_CONTEXT {
>>>>>>> +	PROBE_CONTEXT = 0,
>>>>>>> +	OCR_CONTEXT = 1,
>>>>>>> +};
>>>>>>> +
>>>>>>>  /* Frame Type */
>>>>>>>  #define IO_FRAME				0
>>>>>>>  #define PTHRU_FRAME				1
>>>>>>> @@ -2038,6 +2044,8 @@ struct megasas_instance {
>>>>>>>  	u16 max_fw_cmds;
>>>>>>>  	u16 max_mfi_cmds;
>>>>>>>  	u16 max_scsi_cmds;
>>>>>>> +	u16 ldio_threshold;
>>>>>>> +	u16 cur_can_queue;
>>>>>>>  	u32 max_sectors_per_req;
>>>>>>>  	struct megasas_aen_event *ev;
>>>>>>>
>>>>>>> @@ -2068,6 +2076,7 @@ struct megasas_instance {
>>>>>>>  	u32 fw_support_ieee;
>>>>>>>
>>>>>>>  	atomic_t fw_outstanding;
>>>>>>> +	atomic_t ldio_outstanding;
>>>>>>>  	atomic_t fw_reset_no_pci_access;
>>>>>>>
>>>>>>>  	struct megasas_instance_template *instancet; diff --git
>>>>>>> a/drivers/scsi/megaraid/megaraid_sas_base.c
>>>>>>> b/drivers/scsi/megaraid/megaraid_sas_base.c
>>>>>>> index 3454c5e..edc26fb 100644
>>>>>>> --- a/drivers/scsi/megaraid/megaraid_sas_base.c
>>>>>>> +++ b/drivers/scsi/megaraid/megaraid_sas_base.c
>>>>>>> @@ -96,6 +96,10 @@ int rdpq_enable = 1;  module_param(rdpq_enable,
>>>>>>> int, S_IRUGO);  MODULE_PARM_DESC(rdpq_enable, " Allocate reply
>>>>>>> queue in chunks for large queue depth enable/disbale Default:
>>>>>>> disable(0)");
>>>>>>>
>>>>>>> +unsigned int dual_qdepth_disable;
>>>>>>> +module_param(dual_qdepth_disable, int, S_IRUGO);
>>>>>>> +MODULE_PARM_DESC(dual_qdepth_disable, "Disable dual queue depth
>>>>>>> +feature. Default: 0");
>>>>>>> +
>>>>>>>  MODULE_LICENSE("GPL");
>>>>>>>  MODULE_VERSION(MEGASAS_VERSION);
>>>>>>>  MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com");
>>>>>>> @@ -1977,7 +1981,7 @@
>>>> megasas_check_and_restore_queue_depth(struct
>>>>>> megasas_instance *instance)
>>>>>>>  		spin_lock_irqsave(instance->host->host_lock, flags);
>>>>>>>  		instance->flag &= ~MEGASAS_FW_BUSY;
>>>>>>>
>>>>>>> -		instance->host->can_queue = instance->max_scsi_cmds;
>>>>>>> +		instance->host->can_queue = instance->cur_can_queue;
>>>>>>>  		spin_unlock_irqrestore(instance->host->host_lock, flags);
>>>>>>>  	}
>>>>>>>  }
>>>>>>> @@ -2942,6 +2946,16 @@ megasas_page_size_show(struct device
>> *cdev,
>>>>>>>  	return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned
>>>>>>> long)PAGE_SIZE
>>>>> -
>>>>>>> 1);  }
>>>>>>>
>>>>>>> +static ssize_t
>>>>>>> +megasas_ldio_outstanding_show(struct device *cdev, struct
>>>>> device_attribute
>>>>>> *attr,
>>>>>>> +	char *buf)
>>>>>>> +{
>>>>>>> +	struct Scsi_Host *shost = class_to_shost(cdev);
>>>>>>> +	struct megasas_instance *instance = (struct megasas_instance
>>>>>>> +*)shost->hostdata;
>>>>>>> +
>>>>>>> +	return snprintf(buf, PAGE_SIZE, "%d\n",
>>>>>>> +atomic_read(&instance->ldio_outstanding));
>>>>>>> +}
>>>>>>> +
>>>>>>>  static DEVICE_ATTR(fw_crash_buffer, S_IRUGO | S_IWUSR,
>>>>>>>  	megasas_fw_crash_buffer_show, megasas_fw_crash_buffer_store);
>>>>>>> static DEVICE_ATTR(fw_crash_buffer_size, S_IRUGO, @@ -2950,12
>>>>>>> +2964,15 @@ static DEVICE_ATTR(fw_crash_state, S_IRUGO | S_IWUSR,
>>>>>>>  	megasas_fw_crash_state_show, megasas_fw_crash_state_store);
>>>>>> static
>>>>>>> DEVICE_ATTR(page_size, S_IRUGO,
>>>>>>>  	megasas_page_size_show, NULL);
>>>>>>> +static DEVICE_ATTR(ldio_outstanding, S_IRUGO,
>>>>>>> +	megasas_ldio_outstanding_show, NULL);
>>>>>>>
>>>>>>>  struct device_attribute *megaraid_host_attrs[] = {
>>>>>>>  	&dev_attr_fw_crash_buffer_size,
>>>>>>>  	&dev_attr_fw_crash_buffer,
>>>>>>>  	&dev_attr_fw_crash_state,
>>>>>>>  	&dev_attr_page_size,
>>>>>>> +	&dev_attr_ldio_outstanding,
>>>>>>>  	NULL,
>>>>>>>  };
>>>>>>>
>>>>>>> @@ -4750,6 +4767,7 @@ megasas_init_adapter_mfi(struct
>>>>>>> megasas_instance
>>>>>> *instance)
>>>>>>>  		sema_init(&instance->ioctl_sem,
>>>>>> (MEGASAS_MFI_IOCTL_CMDS));
>>>>>>>  	}
>>>>>>>
>>>>>>> +	instance->cur_can_queue = instance->max_scsi_cmds;
>>>>>>>  	/*
>>>>>>>  	 * Create a pool of commands
>>>>>>>  	 */
>>>>>>> diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c
>>>>>>> b/drivers/scsi/megaraid/megaraid_sas_fusion.c
>>>>>>> index 9ad779d..7cc7806 100644
>>>>>>> --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
>>>>>>> +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
>>>>>>> @@ -92,6 +92,7 @@ void megasas_start_timer(struct megasas_instance
>>>>>> *instance,
>>>>>>>  			 void *fn, unsigned long interval);  extern struct
>>>>>>> megasas_mgmt_info megasas_mgmt_info;  extern int resetwaittime;
>>>>>>> +extern unsigned int dual_qdepth_disable;
>>>>>>>  static void megasas_free_rdpq_fusion(struct megasas_instance
>>>>>>> *instance);  static void megasas_free_reply_fusion(struct
>>>>>>> megasas_instance *instance);
>>>>>>>
>>>>>>> @@ -208,6 +209,67 @@ megasas_fire_cmd_fusion(struct
>>>> megasas_instance
>>>>>>> *instance,  }
>>>>>>>
>>>>>>>  /**
>>>>>>> + * megasas_fusion_update_can_queue -	Do all Adapter Queue depth
>>>>>> related calculations here
>>>>>>> + * @instance:
>>>>>> 	Adapter soft state
>>>>>>> + * fw_boot_context:
>>>>> Whether this
>>>>>> function called during probe or after OCR
>>>>>>> + *
>>>>>>> + * This function is only for fusion controllers.
>>>>>>> + * Update host can queue, if firmware downgrade max supported
>>>>> firmware
>>>>>> commands.
>>>>>>> + * Firmware upgrade case will be skiped because underlying
>>>>>>> +firmware has
>>>>>>> + * more resource than exposed to the OS.
>>>>>>> + *
>>>>>>> + */
>>>>>>> +static void
>>>>>>> +megasas_fusion_update_can_queue(struct megasas_instance
>>>>>>> +*instance, int fw_boot_context) {
>>>>>>> +	u16 cur_max_fw_cmds = 0;
>>>>>>> +	u16 ldio_threshold = 0;
>>>>>>> +	struct megasas_register_set __iomem *reg_set;
>>>>>>> +
>>>>>>> +	reg_set = instance->reg_set;
>>>>>>> +
>>>>>>> +	cur_max_fw_cmds = readl(&instance->reg_set-
>>>>>>> outbound_scratch_pad_3)
>>>>>>> +& 0x00FFFF;
>>>>>>> +
>>>>>>> +	if (dual_qdepth_disable || !cur_max_fw_cmds)
>>>>>>> +		cur_max_fw_cmds = instance->instancet-
>>>>>>> read_fw_status_reg(reg_set) & 0x00FFFF;
>>>>>>> +	else
>>>>>>> +		ldio_threshold =
>>>>>>> +			(instance->instancet->read_fw_status_reg(reg_set)
>>>>> &
>>>>>> 0x00FFFF) -
>>>>>>> +MEGASAS_FUSION_IOCTL_CMDS;
>>>>>>> +
>>>>>>> +	dev_info(&instance->pdev->dev,
>>>>>>> +			"Current firmware maximum commands: %d\t LDIO
>>>>>> thershold: %d\n",
>>>>>>
>>>>>> a typo in "thershold"
>>>>>>
>>>>>>> +			cur_max_fw_cmds, ldio_threshold);
>>>>>>> +
>>>>>>> +	if (fw_boot_context == OCR_CONTEXT) {
>>>>>>> +		cur_max_fw_cmds = cur_max_fw_cmds - 1;
>>>>>>> +		if (cur_max_fw_cmds <= instance->max_fw_cmds) {
>>>>>> probably '<' instead of '<=" could be here ?
>>>>>>
>>>>>>> +			instance->cur_can_queue =
>>>>>>> +				cur_max_fw_cmds -
>>>>>> (MEGASAS_FUSION_INTERNAL_CMDS +
>>>>>>> +
>>>>>> 	MEGASAS_FUSION_IOCTL_CMDS);
>>>>>>> +			instance->host->can_queue = instance-
>>>>>>> cur_can_queue;
>>>>>>> +			instance->ldio_threshold = ldio_threshold;
>>>>>>> +		}
>>>>>>> +	} else {
>>>>>>> +		instance->max_fw_cmds = cur_max_fw_cmds;
>>>>>>> +		instance->ldio_threshold = ldio_threshold;
>>>>>>> +
>>>>>>> +		if (!instance->is_rdpq)
>>>>>>> +			instance->max_fw_cmds = min_t(u16, instance-
>>>>>>> max_fw_cmds, 1024);
>>>>>>> +
>>>>>>> +		/*
>>>>>>> +		* Reduce the max supported cmds by 1. This is to ensure
>>>>> that
>>>>>> the
>>>>>>> +		* reply_q_sz (1 more than the max cmd that driver may
>>>>> send)
>>>>>>> +		* does not exceed max cmds that the FW can support
>>>>>>> +		*/
>>>>>>> +		instance->max_fw_cmds = instance->max_fw_cmds-1;
>>>>>>> +
>>>>>>> +		instance->max_scsi_cmds = instance->max_fw_cmds -
>>>>>>> +				(MEGASAS_FUSION_INTERNAL_CMDS +
>>>>>>> +				MEGASAS_FUSION_IOCTL_CMDS);
>>>>>>> +		instance->cur_can_queue = instance->max_scsi_cmds;
>>>>>>> +	}
>>>>>>> +}
>>>>>>> +/**
>>>>>>>   * megasas_free_cmds_fusion -	Free all the cmds in the free cmd
>>>>> pool
>>>>>>>   * @instance:		Adapter soft state
>>>>>>>   */
>>>>>>> @@ -736,6 +798,8 @@ megasas_ioc_init_fusion(struct
>>>>>>> megasas_instance
>>>>>> *instance)
>>>>>>>  		drv_ops->mfi_capabilities.support_ext_io_size = 1;
>>>>>>>
>>>>>>>  	drv_ops->mfi_capabilities.support_fp_rlbypass = 1;
>>>>>>> +	if (!dual_qdepth_disable)
>>>>>>> +		drv_ops->mfi_capabilities.support_ext_queue_depth = 1;
>>>>>>>
>>>>>>>  	/* Convert capability to LE32 */
>>>>>>>  	cpu_to_le32s((u32
>>>>>>> *)&init_frame->driver_operations.mfi_capabilities);
>>>>>>> @@ -1151,15 +1215,7 @@ megasas_init_adapter_fusion(struct
>>>>>>> megasas_instance *instance)
>>>>>>>
>>>>>>>  	reg_set = instance->reg_set;
>>>>>>>
>>>>>>> -	/*
>>>>>>> -	 * Get various operational parameters from status register
>>>>>>> -	 */
>>>>>>> -	instance->max_fw_cmds =
>>>>>>> -		instance->instancet->read_fw_status_reg(reg_set) &
>>>>> 0x00FFFF;
>>>>>>> -	dev_info(&instance->pdev->dev,
>>>>>>> -		"firmware support max fw cmd\t: (%d)\n", instance-
>>>>>>> max_fw_cmds);
>>>>>>> -	if (!instance->is_rdpq)
>>>>>>> -		instance->max_fw_cmds = min_t(u16, instance-
>>>>>>> max_fw_cmds, 1024);
>>>>>>> +	megasas_fusion_update_can_queue(instance, PROBE_CONTEXT);
>>>>>>>
>>>>>>>  	/*
>>>>>>>  	 * Reduce the max supported cmds by 1. This is to ensure that
>>>>>>> the
>>>>> @@
>>>>>>> -2117,6 +2173,15 @@ megasas_build_and_issue_cmd_fusion(struct
>>>>>>> megasas_instance *instance,
>>>>>>>
>>>>>>>  	fusion = instance->ctrl_context;
>>>>>>>
>>>>>>> +	if (megasas_cmd_type(scmd) == READ_WRITE_LDIO) {
>>>>>>> +		if (instance->ldio_threshold &&
>>>>>>> +			(atomic_read(&instance->ldio_outstanding) >=
>>>>>>> +			instance->ldio_threshold))
>>>>>> This test above won't you protect when several processes read the
>>>>>> same
>>>>> value
>>>>>> in parallel, so it may happen that you get over the limit set for
>>>>> ldio_threshold.
>>>>>> (You might use instead a construction with atomic_dec_and_test for
>>>>> example)
>>>>>
>>>>> Agree..I will fix this and send updated patch.
>>>> In addition to my previous comments - I'm no sure if the idea of two
>>>> queues doesn't have some pitfalls - your parallel queue is based on
>>>> returning commands to the midlayer with SCSI_MLQUEUE_DEVICE_BUSY -
>>>> that makes it repeatedly post it to your queue again. Isn't there a
>>>> performance loss with Virtual Disks ?
>>> Yes this is already covered internally, there would be perf penalty
>>> with VDs in configuration but this feature will be turned on based on
>>> firmware settings and that specific firmware deployment has primary
>>> purpose of increasing JBOD performance. This focuses on firmware
>>> deployment with less VDs(or no) and more JBODs in configuration.
>> OK, so it is switched off by default in the firmware and the user and an
>> educated
>> user can switch it on ? if so, it's fine for me.
> There are different flavors of firmware using same driver and for specific
> firmware this will be turned on(by default) where it's really needed.
> For rest of firmware flavors, this will be switched off(not supported).

Please add this information to the patch when you will resend it.

>>> Thanks,
>>> Sumit
>>>
>>>>>> tomash
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 09/15] megaraid_sas: Dual Queue depth support
  2016-01-20 14:16           ` Tomas Henzl
  2016-01-20 15:08             ` Sumit Saxena
@ 2016-01-27  2:02             ` Martin K. Petersen
  2016-01-27  7:09               ` Sumit Saxena
  1 sibling, 1 reply; 50+ messages in thread
From: Martin K. Petersen @ 2016-01-27  2:02 UTC (permalink / raw)
  To: Tomas Henzl
  Cc: Sumit Saxena, jbottomley, hch, martin.petersen, linux-scsi,
	Kashyap Desai

>>>>> "Tomas" == Tomas Henzl <thenzl@redhat.com> writes:

>> Yes this is already covered internally, there would be perf penalty
>> with VDs in configuration but this feature will be turned on based on
>> firmware settings and that specific firmware deployment has primary
>> purpose of increasing JBOD performance. This focuses on firmware
>> deployment with less VDs(or no) and more JBODs in configuration.

Tomas> OK, so it is switched off by default in the firmware and the user
Tomas> and an educated user can switch it on ? if so, it's fine for me.

Sumit?

-- 
Martin K. Petersen	Oracle Linux Engineering

^ permalink raw reply	[flat|nested] 50+ messages in thread

* RE: [PATCH 09/15] megaraid_sas: Dual Queue depth support
  2016-01-27  2:02             ` Martin K. Petersen
@ 2016-01-27  7:09               ` Sumit Saxena
  0 siblings, 0 replies; 50+ messages in thread
From: Sumit Saxena @ 2016-01-27  7:09 UTC (permalink / raw)
  To: Martin K. Petersen, Tomas Henzl
  Cc: jbottomley, hch, linux-scsi, Kashyap Desai

> -----Original Message-----
> From: Martin K. Petersen [mailto:martin.petersen@oracle.com]
> Sent: Wednesday, January 27, 2016 7:32 AM
> To: Tomas Henzl
> Cc: Sumit Saxena; jbottomley@parallels.com; hch@infradead.org;
> martin.petersen@oracle.com; linux-scsi@vger.kernel.org; Kashyap Desai
> Subject: Re: [PATCH 09/15] megaraid_sas: Dual Queue depth support
>
> >>>>> "Tomas" == Tomas Henzl <thenzl@redhat.com> writes:
>
> >> Yes this is already covered internally, there would be perf penalty
> >> with VDs in configuration but this feature will be turned on based on
> >> firmware settings and that specific firmware deployment has primary
> >> purpose of increasing JBOD performance. This focuses on firmware
> >> deployment with less VDs(or no) and more JBODs in configuration.
>
> Tomas> OK, so it is switched off by default in the firmware and the user
> Tomas> and an educated user can switch it on ? if so, it's fine for me.
>
> Sumit?

Yes, this feature will be enabled for specific firmware only. On rest of
firmware types, it will be disabled(not supported).

Thanks,
Sumit
>
> --
> Martin K. Petersen	Oracle Linux Engineering

^ permalink raw reply	[flat|nested] 50+ messages in thread

* RE: [PATCH 07/15] megaraid_sas: Reply Descriptor Post Queue(RDPQ) support
  2016-01-14 17:38   ` Tomas Henzl
@ 2016-01-27 18:15     ` Sumit Saxena
  0 siblings, 0 replies; 50+ messages in thread
From: Sumit Saxena @ 2016-01-27 18:15 UTC (permalink / raw)
  To: Tomas Henzl, jbottomley, hch, martin.petersen; +Cc: linux-scsi, Kashyap Desai

Tomas,
This reply was stuck in my outbox(was not sent). Just realized now this
when reworking on patches to accommodate your feedback. Apologies for late
reply.

Thanks,
Sumit

> -----Original Message-----
> From: Tomas Henzl [mailto:thenzl@redhat.com]
> Sent: Thursday, January 14, 2016 11:09 PM
> To: Sumit Saxena; jbottomley@parallels.com; hch@infradead.org;
> martin.petersen@oracle.com
> Cc: linux-scsi@vger.kernel.org; kashyap.desai@avagotech.com
> Subject: Re: [PATCH 07/15] megaraid_sas: Reply Descriptor Post
Queue(RDPQ)
> support
>
> On 18.12.2015 14:27, Sumit Saxena wrote:
> > This patch will create reply queue pool for each MSI-x index and will
> > provide array of all reply queue base address instead of single base
> > address of legacy mode. Using this new interface Driver can support
higher
> Queue depth allocating more reply queue as scattered DMA pool.
> >
> > If array mode is not supported driver will fall back to legacy method
of
> allocation reply pool.
> > This method fall back controller queue depth to 1K max. To enable more
> > than 1K QD, driver expect FW to support Array mode and scratch_pad3
should
> provide new queue depth value.
> >
> > Using this method, Firmware should not allow downgrade (OFU) if latest
driver
> and latest FW report 4K QD and Array mode reply queue.
> > This type of FW upgrade may cause firmware fault and it should not be
> > supported. Upgrade of FW will work, but queue depth of the controller
will be
> unchanged until reboot/driver reload.
> >
> > Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
> > Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
> > ---
> >  drivers/scsi/megaraid/megaraid_sas.h        |    6 +-
> >  drivers/scsi/megaraid/megaraid_sas_base.c   |    9 +
> >  drivers/scsi/megaraid/megaraid_sas_fusion.c |  543
+++++++++++++++--------
> ----
> >  drivers/scsi/megaraid/megaraid_sas_fusion.h |   12 +-
> >  4 files changed, 330 insertions(+), 240 deletions(-)
> >
> > diff --git a/drivers/scsi/megaraid/megaraid_sas.h
> > b/drivers/scsi/megaraid/megaraid_sas.h
> > index 01135be..c539516 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas.h
> > +++ b/drivers/scsi/megaraid/megaraid_sas.h
> > @@ -152,6 +152,7 @@
> >  #define MFI_RESET_FLAGS				MFI_INIT_READY| \
> >  						MFI_INIT_MFIMODE| \
> >  						MFI_INIT_ABORT
> > +#define MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE    (0x01)
> >
> >  /*
> >   * MFI frame flags
> > @@ -1416,6 +1417,7 @@ enum DCMD_TIMEOUT_ACTION {
> >  #define MR_MAX_REPLY_QUEUES_EXT_OFFSET          0X003FC000
> >  #define MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT    14
> >  #define MR_MAX_MSIX_REG_ARRAY                   16
> > +#define MR_RDPQ_MODE_OFFSET			0X00800000
> >  /*
> >  * register set for both 1068 and 1078 controllers
> >  * structure extended for 1078 registers @@ -1455,8 +1457,9 @@ struct
> > megasas_register_set {
> >
> >  	u32 	outbound_scratch_pad ;		/*00B0h*/
> >  	u32	outbound_scratch_pad_2;         /*00B4h*/
> > +	u32	outbound_scratch_pad_3;         /*00B8h*/
> >
> > -	u32	reserved_4[2];			/*00B8h*/
> > +	u32	reserved_4;			/*00BCh*/
> >
> >  	u32 	inbound_low_queue_port ;	/*00C0h*/
> >
> > @@ -2117,6 +2120,7 @@ struct megasas_instance {
> >  	u8 mask_interrupts;
> >  	u16 max_chain_frame_sz;
> >  	u8 is_imr;
> > +	u8 is_rdpq;
> >  	bool dev_handle;
> >  };
> >  struct MR_LD_VF_MAP {
> > diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c
> > b/drivers/scsi/megaraid/megaraid_sas_base.c
> > index df93fa1..a3b63fa 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas_base.c
> > +++ b/drivers/scsi/megaraid/megaraid_sas_base.c
> > @@ -92,6 +92,10 @@ int smp_affinity_enable = 1;
> > module_param(smp_affinity_enable, int, S_IRUGO);
> > MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature
> > enable/disbale Default: enable(1)");
> >
> > +int rdpq_enable = 1;
> > +module_param(rdpq_enable, int, S_IRUGO);
> > +MODULE_PARM_DESC(rdpq_enable, " Allocate reply queue in chunks for
> > +large queue depth enable/disbale Default: disable(0)");
>
> Is it enabled or disabled by default (-> int rdpq_enable = 1;) ? also
fix 'disbale'

It's enabled by default. I will fix typo.
>
> > +
> >  MODULE_LICENSE("GPL");
> >  MODULE_VERSION(MEGASAS_VERSION);
> >  MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com");
> > @@ -5081,6 +5085,9 @@ static int megasas_init_fw(struct
megasas_instance
> *instance)
> >  				instance->msix_vectors = ((scratch_pad_2
> >  					&
> MR_MAX_REPLY_QUEUES_EXT_OFFSET)
> >  					>>
> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1;
> > +				if (rdpq_enable)
> > +					instance->is_rdpq = (scratch_pad_2
&
> MR_RDPQ_MODE_OFFSET) ?
> > +								1 : 0;
> >  				fw_msix_count = instance->msix_vectors;
> >  				/* Save 1-15 reply post index address to
local
> memory
> >  				 * Index 0 is already saved from reg
offset @@
> -5117,6 +5124,8 @@
> > static int megasas_init_fw(struct megasas_instance *instance)
> >  	dev_info(&instance->pdev->dev,
> >  		"current msix/online cpus\t: (%d/%d)\n",
> >  		instance->msix_vectors, (unsigned int)num_online_cpus());
> > +	dev_info(&instance->pdev->dev,
> > +		"firmware supports rdpq mode\t: (%d)\n",
instance->is_rdpq);
>
> just a nit, but is_rdpq depends also on rdpq_enable, so the text is not
precise


I will modify text to reflect the correct information.
>
> >
> >  	tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
> >  		(unsigned long)instance);
> > diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > index e8730ef..aca0cd3 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > @@ -92,6 +92,8 @@ void megasas_start_timer(struct megasas_instance
> *instance,
> >  			 void *fn, unsigned long interval);  extern struct
> > megasas_mgmt_info megasas_mgmt_info;  extern int resetwaittime;
> > +static void megasas_free_rdpq_fusion(struct megasas_instance
> > +*instance); static void megasas_free_reply_fusion(struct
> > +megasas_instance *instance);
> >
> >
> >
> > @@ -205,112 +207,71 @@ megasas_fire_cmd_fusion(struct
> megasas_instance
> > *instance,  #endif  }
> >
> > -
> >  /**
> > - * megasas_teardown_frame_pool_fusion -	Destroy the cmd frame DMA
> pool
> > - * @instance:				Adapter soft state
> > + * megasas_free_cmds_fusion -	Free all the cmds in the free cmd
pool
> > + * @instance:		Adapter soft state
> >   */
> > -static void megasas_teardown_frame_pool_fusion(
> > -	struct megasas_instance *instance)
> > +void
> > +megasas_free_cmds_fusion(struct megasas_instance *instance)
> >  {
> >  	int i;
> >  	struct fusion_context *fusion = instance->ctrl_context;
> > -
> > -	u16 max_cmd = instance->max_fw_cmds;
> > -
> >  	struct megasas_cmd_fusion *cmd;
> >
> > -	if (!fusion->sg_dma_pool || !fusion->sense_dma_pool) {
> > -		dev_err(&instance->pdev->dev, "dma pool is null. SG Pool
%p, "
> > -		       "sense pool : %p\n", fusion->sg_dma_pool,
> > -		       fusion->sense_dma_pool);
> > -		return;
> > -	}
> > -
> > -	/*
> > -	 * Return all frames to pool
> > -	 */
> > -	for (i = 0; i < max_cmd; i++) {
> > -
> > +	/* SG, Sense */
> > +	for (i = 0; i < instance->max_fw_cmds; i++) {
> >  		cmd = fusion->cmd_list[i];
>
> cmd might be NULL here, add a test please

Cmd cannot be NULL. If I am missing, do you see any instance where cmd
might be NULL?
>
> > -
> >  		if (cmd->sg_frame)
> >  			pci_pool_free(fusion->sg_dma_pool, cmd->sg_frame,
> > -				      cmd->sg_frame_phys_addr);
> > -
> > +			      cmd->sg_frame_phys_addr);
> >  		if (cmd->sense)
> >  			pci_pool_free(fusion->sense_dma_pool, cmd->sense,
> > -				      cmd->sense_phys_addr);
> > +			      cmd->sense_phys_addr);
> >  	}
> >
> > -	/*
> > -	 * Now destroy the pool itself
> > -	 */
> > -	pci_pool_destroy(fusion->sg_dma_pool);
> > -	pci_pool_destroy(fusion->sense_dma_pool);
> > -
> > -	fusion->sg_dma_pool = NULL;
> > -	fusion->sense_dma_pool = NULL;
> > -}
> > -
> > -/**
> > - * megasas_free_cmds_fusion -	Free all the cmds in the free cmd
pool
> > - * @instance:		Adapter soft state
> > - */
> > -void
> > -megasas_free_cmds_fusion(struct megasas_instance *instance) -{
> > -	int i;
> > -	struct fusion_context *fusion = instance->ctrl_context;
> > -
> > -	u32 max_cmds, req_sz, reply_sz, io_frames_sz;
> > -
> > +	if (fusion->sg_dma_pool) {
> > +		pci_pool_destroy(fusion->sg_dma_pool);
> > +		fusion->sg_dma_pool = NULL;
> > +	}
> > +	if (fusion->sense_dma_pool) {
> > +		pci_pool_destroy(fusion->sense_dma_pool);
> > +		fusion->sense_dma_pool = NULL;
>
> If this is needed (fusion->sense_dma_pool = NULL;), why don't we need it
few
> lines below for example for fusion->io_request_frames_pool ?
> (there should be some consistency here)
>
Agree.. will add (fusion->io_request_frames_pool=NULL).
>
> > +	}
> >
> > -	req_sz = fusion->request_alloc_sz;
> > -	reply_sz = fusion->reply_alloc_sz;
> > -	io_frames_sz = fusion->io_frames_alloc_sz;
> >
> > -	max_cmds = instance->max_fw_cmds;
> > +	/* Reply Frame, Desc*/
> > +	if (instance->is_rdpq)
> > +		megasas_free_rdpq_fusion(instance);
> > +	else
> > +		megasas_free_reply_fusion(instance);
> >
> > -	/* Free descriptors and request Frames memory */
> > +	/* Request Frame, Desc*/
> >  	if (fusion->req_frames_desc)
> > -		dma_free_coherent(&instance->pdev->dev, req_sz,
> > -				  fusion->req_frames_desc,
> > -				  fusion->req_frames_desc_phys);
> > -
> > -	if (fusion->reply_frames_desc) {
> > -		pci_pool_free(fusion->reply_frames_desc_pool,
> > -			      fusion->reply_frames_desc,
> > -			      fusion->reply_frames_desc_phys);
> > -		pci_pool_destroy(fusion->reply_frames_desc_pool);
> > -	}
> > -
> > -	if (fusion->io_request_frames) {
> > +		dma_free_coherent(&instance->pdev->dev,
> > +			fusion->request_alloc_sz, fusion->req_frames_desc,
> > +			fusion->req_frames_desc_phys);
> > +	if (fusion->io_request_frames)
> >  		pci_pool_free(fusion->io_request_frames_pool,
> > -			      fusion->io_request_frames,
> > -			      fusion->io_request_frames_phys);
> > +			fusion->io_request_frames,
> > +			fusion->io_request_frames_phys);
> > +	if (fusion->io_request_frames_pool)
> >  		pci_pool_destroy(fusion->io_request_frames_pool);
> > -	}
> >
> > -	/* Free the Fusion frame pool */
> > -	megasas_teardown_frame_pool_fusion(instance);
> >
> > -	/* Free all the commands in the cmd_list */
> > -	for (i = 0; i < max_cmds; i++)
> > +	/* cmd_list */
> > +	for (i = 0; i < instance->max_fw_cmds; i++)
> >  		kfree(fusion->cmd_list[i]);
> >
> > -	/* Free the cmd_list buffer itself */
> >  	kfree(fusion->cmd_list);
> >  	fusion->cmd_list = NULL;
>
> It is a good idea to set (fusion->cmd_list = NULL;), but a test to the
kfree should
> be added
Kfree returns void. What test is needed here? Please clarify if you mean
something elase.
>
> > -
> >  }
> >
> >  /**
> > - * megasas_create_frame_pool_fusion -	Creates DMA pool for cmd
> frames
> > + * megasas_create_sg_sense_fusion -	Creates DMA pool for cmd
frames
> >   * @instance:			Adapter soft state
> >   *
> >   */
> > -static int megasas_create_frame_pool_fusion(struct megasas_instance
> > *instance)
> > +static int megasas_create_sg_sense_fusion(struct megasas_instance
> > +*instance)
> >  {
> >  	int i;
> >  	u32 max_cmd;
> > @@ -321,186 +282,299 @@ static int
> megasas_create_frame_pool_fusion(struct megasas_instance *instance)
> >  	max_cmd = instance->max_fw_cmds;
> >
> >
> > -	/*
> > -	 * Use DMA pool facility provided by PCI layer
> > -	 */
> > -
> > -	fusion->sg_dma_pool = pci_pool_create("sg_pool_fusion", instance-
> >pdev,
> > -						instance-
> >max_chain_frame_sz,
> > -						4, 0);
> > -	if (!fusion->sg_dma_pool) {
> > -		dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to
> setup request pool fusion\n");
> > -		return -ENOMEM;
> > -	}
> > -	fusion->sense_dma_pool = pci_pool_create("sense pool fusion",
> > -						 instance->pdev,
> > -						 SCSI_SENSE_BUFFERSIZE,
64,
> 0);
> > +	fusion->sg_dma_pool =
> > +			pci_pool_create("mr_sg", instance->pdev,
> > +				instance->max_chain_frame_sz, 4, 0);
> > +	/* SCSI_SENSE_BUFFERSIZE  = 96 bytes */
> > +	fusion->sense_dma_pool =
> > +			pci_pool_create("mr_sense", instance->pdev,
> > +				SCSI_SENSE_BUFFERSIZE, 64, 0);
> >
> > -	if (!fusion->sense_dma_pool) {
> > -		dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to
> setup sense pool fusion\n");
> > -		pci_pool_destroy(fusion->sg_dma_pool);
> > -		fusion->sg_dma_pool = NULL;
> > -		return -ENOMEM;
> > -	}
> > +	if (!fusion->sense_dma_pool || !fusion->sg_dma_pool)
> > +		dev_err(&instance->pdev->dev,
> > +			"Failed from %s %d\n",  __func__, __LINE__);
>
> Allocation failed - I don't think we can ignore it.
Agreed..Will rectify this.
>
> >
> >  	/*
> >  	 * Allocate and attach a frame to each of the commands in cmd_list
> >  	 */
> >  	for (i = 0; i < max_cmd; i++) {
> > -
> >  		cmd = fusion->cmd_list[i];
> > -
> >  		cmd->sg_frame = pci_pool_alloc(fusion->sg_dma_pool,
> > -					       GFP_KERNEL,
> > -					       &cmd->sg_frame_phys_addr);
> > +					GFP_KERNEL, &cmd-
> >sg_frame_phys_addr);
> >
> >  		cmd->sense = pci_pool_alloc(fusion->sense_dma_pool,
> > -					    GFP_KERNEL, &cmd-
> >sense_phys_addr);
> > -		/*
> > -		 * megasas_teardown_frame_pool_fusion() takes care of
> freeing
> > -		 * whatever has been allocated
> > -		 */
> > +					GFP_KERNEL, &cmd-
> >sense_phys_addr);
> >  		if (!cmd->sg_frame || !cmd->sense) {
> > -			dev_printk(KERN_DEBUG, &instance->pdev->dev,
> "pci_pool_alloc failed\n");
> > -			megasas_teardown_frame_pool_fusion(instance);
> > +			dev_err(&instance->pdev->dev,
> > +				"Failed from %s %d\n",  __func__,
__LINE__);
> >  			return -ENOMEM;
> >  		}
> >  	}
> >  	return 0;
> >  }
> >
> > -/**
> > - * megasas_alloc_cmds_fusion -	Allocates the command packets
> > - * @instance:		Adapter soft state
> > - *
> > - *
> > - * Each frame has a 32-bit field called context. This context is used
> > to get
> > - * back the megasas_cmd_fusion from the frame when a frame gets
> > completed
> > - * In this driver, the 32 bit values are the indices into an array
cmd_list.
> > - * This array is used only to look up the megasas_cmd_fusion given
the
> context.
> > - * The free commands themselves are maintained in a linked list
called
> cmd_pool.
> > - *
> > - * cmds are formed in the io_request and sg_frame members of the
> > - * megasas_cmd_fusion. The context field is used to get a request
> > descriptor
> > - * and is used as SMID of the cmd.
> > - * SMID value range is from 1 to max_fw_cmds.
> > - */
> >  int
> > -megasas_alloc_cmds_fusion(struct megasas_instance *instance)
> > +megasas_alloc_cmdlist_fusion(struct megasas_instance *instance)
> >  {
> > -	int i, j, count;
> > -	u32 max_cmd, io_frames_sz;
> > +	u32 max_cmd, i;
> >  	struct fusion_context *fusion;
> > -	struct megasas_cmd_fusion *cmd;
> > -	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
> > -	u32 offset;
> > -	dma_addr_t io_req_base_phys;
> > -	u8 *io_req_base;
> >
> >  	fusion = instance->ctrl_context;
> >
> >  	max_cmd = instance->max_fw_cmds;
> >
> > +	/*
> > +	 * fusion->cmd_list is an array of struct megasas_cmd_fusion
pointers.
> > +	 * Allocate the dynamic array first and then allocate individual
> > +	 * commands.
> > +	 */
> > +	fusion->cmd_list = kmalloc(sizeof(struct megasas_cmd_fusion *) *
> max_cmd,
> > +						GFP_KERNEL);
> > +	if (!fusion->cmd_list) {
> > +		dev_err(&instance->pdev->dev,
> > +			"Failed from %s %d\n",  __func__, __LINE__);
> > +		return -ENOMEM;
> > +	}
> > +	memset(fusion->cmd_list, 0,
> > +		sizeof(struct megasas_cmd_fusion *) * max_cmd);
> > +
> > +	for (i = 0; i < max_cmd; i++) {
> > +		fusion->cmd_list[i] = kmalloc(sizeof(struct
> megasas_cmd_fusion),
> > +					      GFP_KERNEL);
>
> kzalloc here and there, as the kbuild script already wrote
>
> > +		if (!fusion->cmd_list[i]) {
> > +			dev_err(&instance->pdev->dev,
> > +				"Failed from %s %d\n",  __func__,
__LINE__);
> > +			return -ENOMEM;
> > +		}
> > +		memset(fusion->cmd_list[i], 0, sizeof(struct
> megasas_cmd_fusion));
> > +	}
> > +	return 0;
> > +}
> > +int
> > +megasas_alloc_request_fusion(struct megasas_instance *instance) {
> > +	struct fusion_context *fusion;
> > +
> > +	fusion = instance->ctrl_context;
> > +
> >  	fusion->req_frames_desc =
> >  		dma_alloc_coherent(&instance->pdev->dev,
> > -				   fusion->request_alloc_sz,
> > -				   &fusion->req_frames_desc_phys,
> GFP_KERNEL);
> > -
> > +			fusion->request_alloc_sz,
> > +			&fusion->req_frames_desc_phys, GFP_KERNEL);
> >  	if (!fusion->req_frames_desc) {
> > -		dev_err(&instance->pdev->dev, "Could not allocate memory
for
> "
> > -		       "request_frames\n");
> > -		goto fail_req_desc;
> > +		dev_err(&instance->pdev->dev,
> > +			"Failed from %s %d\n",  __func__, __LINE__);
> > +		return -ENOMEM;
> > +	}
> > +
> > +	fusion->io_request_frames_pool =
> > +			pci_pool_create("mr_ioreq", instance->pdev,
> > +				fusion->io_frames_alloc_sz, 16, 0);
>
> Why do you need a pool, you just allocate once a single region, or not?
> Please turn it into a dma_alloc_coherent.

There are some places where dma_alloc_coherent can be used instead of PCI
APIs. If you are OK with ignoring this for now,
I will be sending followup patch to address all such issues.
>
> > +
> > +	if (!fusion->io_request_frames_pool) {
> > +		dev_err(&instance->pdev->dev,
> > +			"Failed from %s %d\n",  __func__, __LINE__);
> > +		return -ENOMEM;
> > +	}
> > +
> > +	fusion->io_request_frames =
> > +			pci_pool_alloc(fusion->io_request_frames_pool,
> > +				GFP_KERNEL, &fusion-
> >io_request_frames_phys);
> > +	if (!fusion->io_request_frames) {
> > +		dev_err(&instance->pdev->dev,
> > +			"Failed from %s %d\n",  __func__, __LINE__);
> > +		return -ENOMEM;
> >  	}
> > +	return 0;
> > +}
> > +
> > +int
> > +megasas_alloc_reply_fusion(struct megasas_instance *instance) {
> > +	int i, count;
> > +	struct fusion_context *fusion;
> > +	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
> > +	fusion = instance->ctrl_context;
> >
> >  	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
> >  	fusion->reply_frames_desc_pool =
> > -		pci_pool_create("reply_frames pool", instance->pdev,
> > +			pci_pool_create("mr_reply", instance->pdev,
> >  				fusion->reply_alloc_sz * count, 16, 0);
> >
> >  	if (!fusion->reply_frames_desc_pool) {
> > -		dev_err(&instance->pdev->dev, "Could not allocate memory
for
> "
> > -		       "reply_frame pool\n");
> > -		goto fail_reply_desc;
> > +		dev_err(&instance->pdev->dev,
> > +			"Failed from %s %d\n",  __func__, __LINE__);
> > +		return -ENOMEM;
> >  	}
>
> Same here, I could understand it if the code were merged with
> megasas_alloc_rdpq_fusion but it is not. Why a pool?
Same reason for this..
>
> >
> > -	fusion->reply_frames_desc =
> > -		pci_pool_alloc(fusion->reply_frames_desc_pool, GFP_KERNEL,
> > -			       &fusion->reply_frames_desc_phys);
> > -	if (!fusion->reply_frames_desc) {
> > -		dev_err(&instance->pdev->dev, "Could not allocate memory
for
> "
> > -		       "reply_frame pool\n");
> > -		pci_pool_destroy(fusion->reply_frames_desc_pool);
> > -		goto fail_reply_desc;
> > +	fusion->reply_frames_desc[0] =
> > +		pci_pool_alloc(fusion->reply_frames_desc_pool,
> > +			GFP_KERNEL, &fusion->reply_frames_desc_phys[0]);
> > +	if (!fusion->reply_frames_desc[0]) {
> > +		dev_err(&instance->pdev->dev,
> > +			"Failed from %s %d\n",  __func__, __LINE__);
> > +		return -ENOMEM;
> >  	}
> > -
> > -	reply_desc = fusion->reply_frames_desc;
> > +	reply_desc = fusion->reply_frames_desc[0];
> >  	for (i = 0; i < fusion->reply_q_depth * count; i++, reply_desc++)
> > -		reply_desc->Words = cpu_to_le64(ULLONG_MAX);
> > +		reply_desc->Words = ULLONG_MAX;
>
> The megasas_reset_reply_desc function seems to be used for this kind of
> resetting, could it be used here ? (and in megasas_alloc_rdpq_fusion)
There you
> also kept the cpu_to_le64(..) that doesn't matter, but again for
consistency...

I will take care of all this in next patchset.
>
> >
> > -	io_frames_sz = fusion->io_frames_alloc_sz;
> > +	/* This is not a rdpq mode, but driver still populate
> > +	 * reply_frame_desc array to use same msix index in ISR path.
> > +	 */
> > +	for (i = 0; i < (count - 1); i++)
> > +		fusion->reply_frames_desc[i + 1] =
> > +			fusion->reply_frames_desc[i] +
> > +			(fusion->reply_alloc_sz)/sizeof(union
> > +MPI2_REPLY_DESCRIPTORS_UNION);
> >
> > -	fusion->io_request_frames_pool =
> > -		pci_pool_create("io_request_frames pool", instance->pdev,
> > -				fusion->io_frames_alloc_sz, 16, 0);
> > +	return 0;
> > +}
> >
> > -	if (!fusion->io_request_frames_pool) {
> > -		dev_err(&instance->pdev->dev, "Could not allocate memory
for
> "
> > -		       "io_request_frame pool\n");
> > -		goto fail_io_frames;
> > +int
> > +megasas_alloc_rdpq_fusion(struct megasas_instance *instance) {
> > +	int i, j, count;
> > +	struct fusion_context *fusion;
> > +	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
> > +
> > +	fusion = instance->ctrl_context;
> > +
> > +	fusion->rdpq_virt = pci_alloc_consistent(instance->pdev,
> > +				sizeof(struct
> MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) *
> > +MAX_MSIX_QUEUES_FUSION,
>
> is dma_alloc_coherent possible here?
>
> > +				&fusion->rdpq_phys);
> > +	if (!fusion->rdpq_virt) {
> > +		dev_err(&instance->pdev->dev,
> > +			"Failed from %s %d\n",  __func__, __LINE__);
> > +		return -ENOMEM;
> >  	}
> >
> > -	fusion->io_request_frames =
> > -		pci_pool_alloc(fusion->io_request_frames_pool, GFP_KERNEL,
> > -			       &fusion->io_request_frames_phys);
> > -	if (!fusion->io_request_frames) {
> > -		dev_err(&instance->pdev->dev, "Could not allocate memory
for
> "
> > -		       "io_request_frames frames\n");
> > -		pci_pool_destroy(fusion->io_request_frames_pool);
> > -		goto fail_io_frames;
> > +	memset(fusion->rdpq_virt, 0,
> > +			sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) *
> MAX_MSIX_QUEUES_FUSION);
> > +	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
> > +	fusion->reply_frames_desc_pool = pci_pool_create("mr_rdpq",
> > +							 instance->pdev,
> fusion->reply_alloc_sz, 16, 0);
> > +
> > +	if (!fusion->reply_frames_desc_pool) {
> > +		dev_err(&instance->pdev->dev,
> > +			"Failed from %s %d\n",  __func__, __LINE__);
> > +		return -ENOMEM;
> >  	}
> >
> > -	/*
> > -	 * fusion->cmd_list is an array of struct megasas_cmd_fusion
pointers.
> > -	 * Allocate the dynamic array first and then allocate individual
> > -	 * commands.
> > -	 */
> > -	fusion->cmd_list = kzalloc(sizeof(struct megasas_cmd_fusion *)
> > -				   * max_cmd, GFP_KERNEL);
> > +	for (i = 0; i < count; i++) {
> > +		fusion->reply_frames_desc[i] =
> > +				pci_pool_alloc(fusion-
> >reply_frames_desc_pool,
> > +					GFP_KERNEL, &fusion-
> >reply_frames_desc_phys[i]);
> > +		if (!fusion->reply_frames_desc[i]) {
> > +			dev_err(&instance->pdev->dev,
> > +				"Failed from %s %d\n",  __func__,
__LINE__);
> > +			return -ENOMEM;
> > +		}
> >
> > -	if (!fusion->cmd_list) {
> > -		dev_printk(KERN_DEBUG, &instance->pdev->dev, "out of
> memory. Could not alloc "
> > -		       "memory for cmd_list_fusion\n");
> > -		goto fail_cmd_list;
> > +		fusion->rdpq_virt[i].RDPQBaseAddress =
> > +			fusion->reply_frames_desc_phys[i];
> > +
> > +		reply_desc = fusion->reply_frames_desc[i];
> > +		for (j = 0; j < fusion->reply_q_depth; j++, reply_desc++)
> > +			reply_desc->Words = ULLONG_MAX;
> >  	}
> > +	return 0;
> > +}
> >
> > -	max_cmd = instance->max_fw_cmds;
> > -	for (i = 0; i < max_cmd; i++) {
> > -		fusion->cmd_list[i] = kmalloc(sizeof(struct
> megasas_cmd_fusion),
> > -					      GFP_KERNEL);
> > -		if (!fusion->cmd_list[i]) {
> > -			dev_err(&instance->pdev->dev, "Could not alloc cmd
> list fusion\n");
> > +static void
> > +megasas_free_rdpq_fusion(struct megasas_instance *instance) {
> >
> > -			for (j = 0; j < i; j++)
> > -				kfree(fusion->cmd_list[j]);
> > +	int i;
> > +	struct fusion_context *fusion;
> >
> > -			kfree(fusion->cmd_list);
> > -			fusion->cmd_list = NULL;
> > -			goto fail_cmd_list;
> > -		}
> > +	fusion = instance->ctrl_context;
> > +
> > +	for (i = 0; i < MAX_MSIX_QUEUES_FUSION; i++) {
> > +		if (fusion->reply_frames_desc[i])
> > +			pci_pool_free(fusion->reply_frames_desc_pool,
> > +				fusion->reply_frames_desc[i],
> > +				fusion->reply_frames_desc_phys[i]);
> >  	}
> >
> > -	/* The first 256 bytes (SMID 0) is not used. Don't add to cmd list
*/
> > -	io_req_base = fusion->io_request_frames +
> > -		MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
> > -	io_req_base_phys = fusion->io_request_frames_phys +
> > -		MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
> > +	if (fusion->reply_frames_desc_pool)
> > +		pci_pool_destroy(fusion->reply_frames_desc_pool);
> > +
> > +	if (fusion->rdpq_virt)
> > +		pci_free_consistent(instance->pdev,
> > +			sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) *
> MAX_MSIX_QUEUES_FUSION,
> > +			fusion->rdpq_virt, fusion->rdpq_phys); }
> > +
> > +static void
> > +megasas_free_reply_fusion(struct megasas_instance *instance) {
> > +
> > +	struct fusion_context *fusion;
> > +
> > +	fusion = instance->ctrl_context;
> > +
> > +	if (fusion->reply_frames_desc[0])
> > +		pci_pool_free(fusion->reply_frames_desc_pool,
> > +			fusion->reply_frames_desc[0],
> > +			fusion->reply_frames_desc_phys[0]);
> > +
> > +	if (fusion->reply_frames_desc_pool)
> > +		pci_pool_destroy(fusion->reply_frames_desc_pool);
> > +
> > +}
> > +
> > +
> > +/**
> > + * megasas_alloc_cmds_fusion -	Allocates the command packets
> > + * @instance:		Adapter soft state
> > + *
> > + *
> > + * Each frame has a 32-bit field called context. This context is used
> > +to get
> > + * back the megasas_cmd_fusion from the frame when a frame gets
> > +completed
> > + * In this driver, the 32 bit values are the indices into an array
cmd_list.
> > + * This array is used only to look up the megasas_cmd_fusion given
the
> context.
> > + * The free commands themselves are maintained in a linked list
called
> cmd_pool.
> > + *
> > + * cmds are formed in the io_request and sg_frame members of the
> > + * megasas_cmd_fusion. The context field is used to get a request
> > +descriptor
> > + * and is used as SMID of the cmd.
> > + * SMID value range is from 1 to max_fw_cmds.
> > + */
> > +int
> > +megasas_alloc_cmds_fusion(struct megasas_instance *instance) {
> > +	int i;
> > +	struct fusion_context *fusion;
> > +	struct megasas_cmd_fusion *cmd;
> > +	u32 offset;
> > +	dma_addr_t io_req_base_phys;
> > +	u8 *io_req_base;
> > +
> > +
> > +	fusion = instance->ctrl_context;
> > +
> > +	if (megasas_alloc_cmdlist_fusion(instance))
>
> We may need to call megasas_free_cmds_fusion here too (to free fusion-
> >cmd_list)
I will work on all error condition handling stuff..
>
> > +		return -ENOMEM;
> > +
> > +	if (megasas_alloc_request_fusion(instance))
> > +		goto fail_exit;
> > +
> > +	if (instance->is_rdpq) {
> > +		if (megasas_alloc_rdpq_fusion(instance))
> > +			goto fail_exit;
> > +	} else
> > +		if (megasas_alloc_reply_fusion(instance))
> > +			goto fail_exit;
> > +
> > +
> > +	/* The first 256 bytes (SMID 0) is not used. Don't add to the cmd
list */
> > +	io_req_base = fusion->io_request_frames +
> MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
> > +	io_req_base_phys = fusion->io_request_frames_phys +
> > +MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
> >
> >  	/*
> >  	 * Add all the commands to command pool (fusion->cmd_pool)
> >  	 */
> >
> >  	/* SMID 0 is reserved. Set SMID/index from 1 */
> > -	for (i = 0; i < max_cmd; i++) {
> > +	for (i = 0; i < instance->max_fw_cmds; i++) {
> >  		cmd = fusion->cmd_list[i];
> >  		offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i;
> >  		memset(cmd, 0, sizeof(struct megasas_cmd_fusion));
>
> That memset was already done in megasas_alloc_cmdlist_fusion
Will use kzalloc instead of kmalloc to avoid all memset to zero
instructions.
>
> > @@ -518,35 +592,13 @@ megasas_alloc_cmds_fusion(struct
> megasas_instance *instance)
> >  		cmd->io_request_phys_addr = io_req_base_phys + offset;
> >  	}/
> >
> > -	/*
> > -	 * Create a frame pool and assign one frame to each cmd
> > -	 */
> > -	if (megasas_create_frame_pool_fusion(instance)) {
> > -		dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error
> creating frame DMA pool\n");
> > -		megasas_free_cmds_fusion(instance);
> > -		goto fail_req_desc;
> > -	}
> > +	if (megasas_create_sg_sense_fusion(instance))
> > +		goto fail_exit;
> >
> >  	return 0;
> >
> > -fail_cmd_list:
> > -	pci_pool_free(fusion->io_request_frames_pool, fusion-
> >io_request_frames,
> > -		      fusion->io_request_frames_phys);
> > -	pci_pool_destroy(fusion->io_request_frames_pool);
> > -fail_io_frames:
> > -	dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
> > -			  fusion->reply_frames_desc,
> > -			  fusion->reply_frames_desc_phys);
> > -	pci_pool_free(fusion->reply_frames_desc_pool,
> > -		      fusion->reply_frames_desc,
> > -		      fusion->reply_frames_desc_phys);
> > -	pci_pool_destroy(fusion->reply_frames_desc_pool);
> > -
> > -fail_reply_desc:
> > -	dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
> > -			  fusion->req_frames_desc,
> > -			  fusion->req_frames_desc_phys);
> > -fail_req_desc:
> > +fail_exit:
> > +	megasas_free_cmds_fusion(instance);
> >  	return -ENOMEM;
> >  }
> >
> > @@ -594,16 +646,17 @@ int
> >  megasas_ioc_init_fusion(struct megasas_instance *instance)  {
> >  	struct megasas_init_frame *init_frame;
> > -	struct MPI2_IOC_INIT_REQUEST *IOCInitMessage;
> > +	struct MPI2_IOC_INIT_REQUEST *IOCInitMessage = NULL;
> >  	dma_addr_t	ioc_init_handle;
> >  	struct megasas_cmd *cmd;
> > -	u8 ret;
> > +	u8 ret, cur_rdpq_mode;
> >  	struct fusion_context *fusion;
> >  	union MEGASAS_REQUEST_DESCRIPTOR_UNION req_desc;
> >  	int i;
> >  	struct megasas_header *frame_hdr;
> >  	const char *sys_info;
> >  	MFI_CAPABILITIES *drv_ops;
> > +	u32 scratch_pad_2;
> >
> >  	fusion = instance->ctrl_context;
> >
> > @@ -615,6 +668,18 @@ megasas_ioc_init_fusion(struct megasas_instance
> *instance)
> >  		goto fail_get_cmd;
> >  	}
> >
> > +	scratch_pad_2 = readl
> > +		(&instance->reg_set->outbound_scratch_pad_2);
> > +
> > +	cur_rdpq_mode = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ? 1 : 0;
> > +
> > +	if (instance->is_rdpq && !cur_rdpq_mode) {
> > +		dev_err(&instance->pdev->dev, "Firmware downgrade *NOT
> SUPPORTED*"
> > +			" from RDPQ mode to non RDPQ mode\n");
>
> How does this work ? is_rdpq is set in megasas_init_fw only when the fw
> supports it, why do you test it here again ? I think I'm miss something.

"is_rdpq" stores the capability of firmware flashed during driver load and
"cur_rdpq_mode" tells capability of upgraded/downgraded firmware(OFU)
without reloading driver.
This condition is just to ensure that firmware downgrade from RDPQ mode to
non RDPQ mode should not be allowed.
>
> Tomas
>
> > +		ret = 1;
> > +		goto fail_fw_init;
> > +	}
> > +
> >  	IOCInitMessage =
> >  	  dma_alloc_coherent(&instance->pdev->dev,
> >  			     sizeof(struct MPI2_IOC_INIT_REQUEST), @@
-636,7
> +701,11 @@
> > megasas_ioc_init_fusion(struct megasas_instance *instance)
> >  	IOCInitMessage->SystemRequestFrameSize =
> > cpu_to_le16(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4);
> >
> >  	IOCInitMessage->ReplyDescriptorPostQueueDepth =
> cpu_to_le16(fusion->reply_q_depth);
> > -	IOCInitMessage->ReplyDescriptorPostQueueAddress	=
> cpu_to_le64(fusion->reply_frames_desc_phys);
> > +	IOCInitMessage->ReplyDescriptorPostQueueAddress = instance-
> >is_rdpq ?
> > +			cpu_to_le64(fusion->rdpq_phys) :
> > +			cpu_to_le64(fusion->reply_frames_desc_phys[0]);
> > +	IOCInitMessage->MsgFlags = instance->is_rdpq ?
> > +			MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE : 0;
> >  	IOCInitMessage->SystemRequestFrameBaseAddress =
> cpu_to_le64(fusion->io_request_frames_phys);
> >  	IOCInitMessage->HostMSIxVectors = instance->msix_vectors;
> >  	init_frame = (struct megasas_init_frame *)cmd->frame; @@ -1087,7
> > +1156,10 @@ megasas_init_adapter_fusion(struct megasas_instance
> *instance)
> >  	 */
> >  	instance->max_fw_cmds =
> >  		instance->instancet->read_fw_status_reg(reg_set) &
0x00FFFF;
> > -	instance->max_fw_cmds = min(instance->max_fw_cmds, (u16)1008);
> > +	dev_info(&instance->pdev->dev,
> > +		"firmware support max fw cmd\t: (%d)\n", instance-
> >max_fw_cmds);
> > +	if (!instance->is_rdpq)
> > +		instance->max_fw_cmds = min_t(u16, instance-
> >max_fw_cmds, 1024);
> >
> >  	/*
> >  	 * Reduce the max supported cmds by 1. This is to ensure that the
@@
> > -2110,10 +2182,8 @@ complete_cmd_fusion(struct megasas_instance
> *instance, u32 MSIxIndex)
> >  	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
> >  		return IRQ_HANDLED;
> >
> > -	desc = fusion->reply_frames_desc;
> > -	desc += ((MSIxIndex * fusion->reply_alloc_sz)/
> > -		 sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)) +
> > -		fusion->last_reply_idx[MSIxIndex];
> > +	desc = fusion->reply_frames_desc[MSIxIndex] +
> > +				fusion->last_reply_idx[MSIxIndex];
> >
> >  	reply_desc = (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR
> *)desc;
> >
> > @@ -2208,9 +2278,7 @@ complete_cmd_fusion(struct megasas_instance
> > *instance, u32 MSIxIndex)
> >
> >  		/* Get the next reply descriptor */
> >  		if (!fusion->last_reply_idx[MSIxIndex])
> > -			desc = fusion->reply_frames_desc +
> > -				((MSIxIndex * fusion->reply_alloc_sz)/
> > -				 sizeof(union
> MPI2_REPLY_DESCRIPTORS_UNION));
> > +			desc = fusion->reply_frames_desc[MSIxIndex];
> >  		else
> >  			desc++;
> >
> > @@ -2688,17 +2756,18 @@ out:
> >
> >  void  megasas_reset_reply_desc(struct megasas_instance *instance)  {
> > -	int i, count;
> > +	int i, j, count;
> >  	struct fusion_context *fusion;
> >  	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
> >
> >  	fusion = instance->ctrl_context;
> >  	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
> > -	for (i = 0 ; i < count ; i++)
> > +	for (i = 0 ; i < count ; i++) {
> >  		fusion->last_reply_idx[i] = 0;
> > -	reply_desc = fusion->reply_frames_desc;
> > -	for (i = 0 ; i < fusion->reply_q_depth * count; i++, reply_desc++)
> > -		reply_desc->Words = cpu_to_le64(ULLONG_MAX);
> > +		reply_desc = fusion->reply_frames_desc[i];
> > +		for (j = 0 ; j < fusion->reply_q_depth; j++, reply_desc++)
> > +			reply_desc->Words = cpu_to_le64(ULLONG_MAX);
> > +	}
> >  }
> >
> >  /*
> > diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h
> > b/drivers/scsi/megaraid/megaraid_sas_fusion.h
> > index db0978d..80eaee2 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
> > +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
> > @@ -928,6 +928,12 @@ struct MR_PD_CFG_SEQ_NUM_SYNC {
> >  	struct MR_PD_CFG_SEQ seq[1];
> >  } __packed;
> >
> > +struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY {
> > +	u64 RDPQBaseAddress;
> > +	u32 Reserved1;
> > +	u32 Reserved2;
> > +};
> > +
> >  struct fusion_context {
> >  	struct megasas_cmd_fusion **cmd_list;
> >  	dma_addr_t req_frames_desc_phys;
> > @@ -940,8 +946,8 @@ struct fusion_context {
> >  	struct dma_pool *sg_dma_pool;
> >  	struct dma_pool *sense_dma_pool;
> >
> > -	dma_addr_t reply_frames_desc_phys;
> > -	union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc;
> > +	dma_addr_t reply_frames_desc_phys[MAX_MSIX_QUEUES_FUSION];
> > +	union MPI2_REPLY_DESCRIPTORS_UNION
> > +*reply_frames_desc[MAX_MSIX_QUEUES_FUSION];
> >  	struct dma_pool *reply_frames_desc_pool;
> >
> >  	u16 last_reply_idx[MAX_MSIX_QUEUES_FUSION];
> > @@ -951,6 +957,8 @@ struct fusion_context {
> >  	u32 reply_alloc_sz;
> >  	u32 io_frames_alloc_sz;
> >
> > +	struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY *rdpq_virt;
> > +	dma_addr_t rdpq_phys;
> >  	u16	max_sge_in_main_msg;
> >  	u16	max_sge_in_chain;
> >

^ permalink raw reply	[flat|nested] 50+ messages in thread

* RE: [PATCH 10/15] megaraid_sas: IO throttling support
  2016-01-19 13:38   ` Tomas Henzl
@ 2016-01-28  7:18     ` Sumit Saxena
  0 siblings, 0 replies; 50+ messages in thread
From: Sumit Saxena @ 2016-01-28  7:18 UTC (permalink / raw)
  To: Tomas Henzl, jbottomley, hch, martin.petersen; +Cc: linux-scsi, Kashyap Desai

> -----Original Message-----
> From: Tomas Henzl [mailto:thenzl@redhat.com]
> Sent: Tuesday, January 19, 2016 7:08 PM
> To: Sumit Saxena; jbottomley@parallels.com; hch@infradead.org;
> martin.petersen@oracle.com
> Cc: linux-scsi@vger.kernel.org; kashyap.desai@avagotech.com
> Subject: Re: [PATCH 10/15] megaraid_sas: IO throttling support
>
> On 18.12.2015 14:27, Sumit Saxena wrote:
> > This patch will add capability in driver to tell firmware that it can
> > throttle IOs in case Controller's Queue depth is downgraded post OFU
(Online
> firmware upgrade). This feature will ensure firmware can be downgraded
from
> higher queue depth to lower queue depth without needing system reboot.
> > Added throttling code in IO path of driver, in case OS tries to send
more IOs
> than post OFU firmware's queue depth.
> >
> > Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
> > Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
> > ---
> >  drivers/scsi/megaraid/megaraid_sas.h        |    6 ++++--
> >  drivers/scsi/megaraid/megaraid_sas_fusion.c |    7 +++++++
> >  2 files changed, 11 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/scsi/megaraid/megaraid_sas.h
> > b/drivers/scsi/megaraid/megaraid_sas.h
> > index 4595ef4..9d2b3da 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas.h
> > +++ b/drivers/scsi/megaraid/megaraid_sas.h
> > @@ -1537,7 +1537,8 @@ union megasas_sgl_frame {  typedef union
> > _MFI_CAPABILITIES {
> >  	struct {
> >  #if   defined(__BIG_ENDIAN_BITFIELD)
> > -		u32     reserved:21;
> > +		u32     reserved:20;
> > +		u32     support_qd_throttling:1;
> >  		u32     support_fp_rlbypass:1;
> >  		u32     support_vfid_in_ioframe:1;
> >  		u32     support_ext_io_size:1;
> > @@ -1561,7 +1562,8 @@ typedef union _MFI_CAPABILITIES {
> >  		u32     support_ext_io_size:1;
> >  		u32     support_vfid_in_ioframe:1;
> >  		u32     support_fp_rlbypass:1;
> > -		u32     reserved:21;
> > +		u32     support_qd_throttling:1;
> > +		u32     reserved:20;
> >  #endif
> >  	} mfi_capabilities;
> >  	__le32		reg;
> > diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > index 7cc7806..1248c7a 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > @@ -801,6 +801,7 @@ megasas_ioc_init_fusion(struct megasas_instance
> *instance)
> >  	if (!dual_qdepth_disable)
> >  		drv_ops->mfi_capabilities.support_ext_queue_depth = 1;
> >
> > +	drv_ops->mfi_capabilities.support_qd_throttling = 1;
> >  	/* Convert capability to LE32 */
> >  	cpu_to_le32s((u32
> > *)&init_frame->driver_operations.mfi_capabilities);
> >
> > @@ -2182,6 +2183,12 @@ megasas_build_and_issue_cmd_fusion(struct
> megasas_instance *instance,
> >  			atomic_inc(&instance->ldio_outstanding);
> >  	}
> >
> > +	if (atomic_read(&instance->fw_outstanding) >=
> > +			instance->host->can_queue) {
> > +		dev_err(&instance->pdev->dev, "Throttle IOs beyond
Controller
> queue depth\n");
> > +		return SCSI_MLQUEUE_HOST_BUSY;
> > +	}
>
> Same as in the previous patch, this this test above won't you protect
when
> several processes read the same value in parallel. In addition to that,
when the
> scsi layer knows the new smaller can_queue value it will not queue new
> commands above the limit.

Agree that SCSI mid layer itself will not send IOs beyond can_queue value
and we can remove this code. This code was just extra check for older
kernels- if IOs returned to SCSI mid layer by driver with DID_RESET status
does not check updated can_queue value(not sure if it was always taken
care of so added this code).
>
> > +
> >  	cmd = megasas_get_cmd_fusion(instance, scmd->request->tag);
> >
> >  	index = cmd->index;

^ permalink raw reply	[flat|nested] 50+ messages in thread

* RE: [PATCH 11/15] megaraid_sas: Make adprecovery variable atomic
  2016-01-19 13:52   ` Tomas Henzl
@ 2016-01-28  8:30     ` Sumit Saxena
  0 siblings, 0 replies; 50+ messages in thread
From: Sumit Saxena @ 2016-01-28  8:30 UTC (permalink / raw)
  To: Tomas Henzl, jbottomley, hch, martin.petersen; +Cc: linux-scsi, Kashyap Desai

> -----Original Message-----
> From: Tomas Henzl [mailto:thenzl@redhat.com]
> Sent: Tuesday, January 19, 2016 7:23 PM
> To: Sumit Saxena; jbottomley@parallels.com; hch@infradead.org;
> martin.petersen@oracle.com
> Cc: linux-scsi@vger.kernel.org; kashyap.desai@avagotech.com
> Subject: Re: [PATCH 11/15] megaraid_sas: Make adprecovery variable
atomic
>
> On 18.12.2015 14:27, Sumit Saxena wrote:
> > Make instance->adprecovery variable atomic and removes hba_lock
spinlock
> while accessing instance->adprecovery.
>
> adprecovery is a 8bit int, you don't do any arithmetic with it, the
newly set
> values do not depend on previous values - I think that an atomic
variable is not
> needed.

I agree that this adprecovery can be made uint8_t but the purpose of
making "adprecovery"  atomic was to remove "hba_lock" while reading and
setting adprecovery. hba_lock around reading/setting adprecovery was added
when OCR was implemented for MFI adapters. Here is the old patch which had
done this- http://www.spinics.net/lists/linux-scsi/msg43496.html

The reason of adding "hba_lock" around reading/setting adprecovery is
unknown so the intent was to keep the flow of original code same and make
it less costly by making adprecovery atomic instead of using "hba_lock" .
MFI adapters' support is EOL and we may not get test coverage if we do
major changes in MFI adapters' code path so keep this less riskier this
approach of making variable atomic was adopted.
>
> -tm
>
> >
> > Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
> > Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
> > ---
> >  drivers/scsi/megaraid/megaraid_sas.h        |    2 +-
> >  drivers/scsi/megaraid/megaraid_sas_base.c   |   95
++++++++++-----------------
> >  drivers/scsi/megaraid/megaraid_sas_fusion.c |   27 ++++----
> >  3 files changed, 50 insertions(+), 74 deletions(-)
> >
> > diff --git a/drivers/scsi/megaraid/megaraid_sas.h
> > b/drivers/scsi/megaraid/megaraid_sas.h
> > index 9d2b3da..ac19d53 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas.h
> > +++ b/drivers/scsi/megaraid/megaraid_sas.h
> > @@ -2101,7 +2101,7 @@ struct megasas_instance {
> >  	u16 drv_supported_vd_count;
> >  	u16 drv_supported_pd_count;
> >
> > -	u8 adprecovery;
> > +	atomic_t adprecovery;
> >  	unsigned long last_time;
> >  	u32 mfiStatus;
> >  	u32 last_seq_num;'
> > diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c
> > b/drivers/scsi/megaraid/megaraid_sas_base.c
> > index edc26fb..5eaf6fd 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas_base.c
> > +++ b/drivers/scsi/megaraid/megaraid_sas_base.c
> > @@ -483,7 +483,7 @@ static int
> >  megasas_check_reset_xscale(struct megasas_instance *instance,
> >  		struct megasas_register_set __iomem *regs)  {
> > -	if ((instance->adprecovery != MEGASAS_HBA_OPERATIONAL) &&
> > +	if ((atomic_read(&instance->adprecovery) !=
> MEGASAS_HBA_OPERATIONAL)
> > +&&
> >  	    (le32_to_cpu(*instance->consumer) ==
> >  		MEGASAS_ADPRESET_INPROG_SIGN))
> >  		return 1;
> > @@ -619,7 +619,7 @@ static int
> >  megasas_check_reset_ppc(struct megasas_instance *instance,
> >  			struct megasas_register_set __iomem *regs)  {
> > -	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL)
> > +	if (atomic_read(&instance->adprecovery) !=
> MEGASAS_HBA_OPERATIONAL)
> >  		return 1;
> >
> >  	return 0;
> > @@ -756,7 +756,7 @@ static int
> >  megasas_check_reset_skinny(struct megasas_instance *instance,
> >  				struct megasas_register_set __iomem *regs)
{
> > -	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL)
> > +	if (atomic_read(&instance->adprecovery) !=
> MEGASAS_HBA_OPERATIONAL)
> >  		return 1;
> >
> >  	return 0;
> > @@ -950,9 +950,8 @@ static int
> >  megasas_check_reset_gen2(struct megasas_instance *instance,
> >  		struct megasas_register_set __iomem *regs)  {
> > -	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
> > +	if (atomic_read(&instance->adprecovery) !=
> MEGASAS_HBA_OPERATIONAL)
> >  		return 1;
> > -	}
> >
> >  	return 0;
> >  }
> > @@ -998,7 +997,7 @@ megasas_issue_polled(struct megasas_instance
> *instance, struct megasas_cmd *cmd)
> >  	frame_hdr->cmd_status = MFI_STAT_INVALID_STATUS;
> >  	frame_hdr->flags |=
> cpu_to_le16(MFI_FRAME_DONT_POST_IN_REPLY_QUEUE);
> >
> > -	if ((instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) ||
> > +	if ((atomic_read(&instance->adprecovery) ==
> > +MEGASAS_HW_CRITICAL_ERROR) ||
> >  		(instance->instancet->issue_dcmd(instance, cmd))) {
> >  		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
> >  			__func__, __LINE__);
> > @@ -1026,7 +1025,7 @@ megasas_issue_blocked_cmd(struct
> megasas_instance *instance,
> >  	int ret = 0;
> >  	cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
> >
> > -	if ((instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) ||
> > +	if ((atomic_read(&instance->adprecovery) ==
> > +MEGASAS_HW_CRITICAL_ERROR) ||
> >  		(instance->instancet->issue_dcmd(instance, cmd))) {
> >  		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
> >  			__func__, __LINE__);
> > @@ -1090,7 +1089,7 @@ megasas_issue_blocked_abort_cmd(struct
> megasas_instance *instance,
> >  	cmd->sync_cmd = 1;
> >  	cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
> >
> > -	if ((instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) ||
> > +	if ((atomic_read(&instance->adprecovery) ==
> > +MEGASAS_HW_CRITICAL_ERROR) ||
> >  		(instance->instancet->issue_dcmd(instance, cmd))) {
> >  		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
> >  			__func__, __LINE__);
> > @@ -1653,7 +1652,6 @@ static int
> >  megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd
> > *scmd)  {
> >  	struct megasas_instance *instance;
> > -	unsigned long flags;
> >  	struct MR_PRIV_DEVICE *mr_device_priv_data;
> >
> >  	instance = (struct megasas_instance *) @@ -1668,24 +1666,20 @@
> > megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
> >  	if (instance->issuepend_done == 0)
> >  		return SCSI_MLQUEUE_HOST_BUSY;
> >
> > -	spin_lock_irqsave(&instance->hba_lock, flags);
> >
> >  	/* Check for an mpio path and adjust behavior */
> > -	if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) {
> > +	if (atomic_read(&instance->adprecovery) ==
> > +MEGASAS_ADPRESET_SM_INFAULT) {
> >  		if (megasas_check_mpio_paths(instance, scmd) ==
> >  		    (DID_RESET << 16)) {
> > -			spin_unlock_irqrestore(&instance->hba_lock,
flags);
> >  			return SCSI_MLQUEUE_HOST_BUSY;
> >  		} else {
> > -			spin_unlock_irqrestore(&instance->hba_lock,
flags);
> >  			scmd->result = DID_NO_CONNECT << 16;
> >  			scmd->scsi_done(scmd);
> >  			return 0;
> >  		}
> >  	}
> >
> > -	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
> > -		spin_unlock_irqrestore(&instance->hba_lock, flags);
> > +	if (atomic_read(&instance->adprecovery) ==
> > +MEGASAS_HW_CRITICAL_ERROR) {
> >  		scmd->result = DID_NO_CONNECT << 16;
> >  		scmd->scsi_done(scmd);
> >  		return 0;
> > @@ -1693,23 +1687,17 @@ megasas_queue_command(struct Scsi_Host
> *shost,
> > struct scsi_cmnd *scmd)
> >
> >  	mr_device_priv_data = scmd->device->hostdata;
> >  	if (!mr_device_priv_data) {
> > -		spin_unlock_irqrestore(&instance->hba_lock, flags);
> >  		scmd->result = DID_NO_CONNECT << 16;
> >  		scmd->scsi_done(scmd);
> >  		return 0;
> >  	}
> >
> > -	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
> > -		spin_unlock_irqrestore(&instance->hba_lock, flags);
> > +	if (atomic_read(&instance->adprecovery) !=
> MEGASAS_HBA_OPERATIONAL)
> >  		return SCSI_MLQUEUE_HOST_BUSY;
> > -	}
> >
> > -	if (mr_device_priv_data->tm_busy) {
> > -		spin_unlock_irqrestore(&instance->hba_lock, flags);
> > +	if (mr_device_priv_data->tm_busy)
> >  		return SCSI_MLQUEUE_DEVICE_BUSY;
> > -	}
> >
> > -	spin_unlock_irqrestore(&instance->hba_lock, flags);
> >
> >  	scmd->result = 0;
> >
> > @@ -1943,7 +1931,7 @@ static void
> > megasas_complete_outstanding_ioctls(struct megasas_instance *instanc
> > void megaraid_sas_kill_hba(struct megasas_instance *instance)  {
> >  	/* Set critical error to block I/O & ioctls in case caller didn't
*/
> > -	instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
> > +	atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
> >  	/* Wait 1 second to ensure IO or ioctls in build have posted */
> >  	msleep(1000);
> >  	if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
> > @@ -2003,7 +1991,7 @@ static void megasas_complete_cmd_dpc(unsigned
> long instance_addr)
> >  	unsigned long flags;
> >
> >  	/* If we have already declared adapter dead, donot complete cmds
*/
> > -	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
> > +	if (atomic_read(&instance->adprecovery) ==
> > +MEGASAS_HW_CRITICAL_ERROR)
> >  		return;
> >
> >  	spin_lock_irqsave(&instance->completion_lock, flags); @@ -2072,7
> > +2060,7 @@ void megasas_do_ocr(struct megasas_instance *instance)
> >  		*instance->consumer =
> cpu_to_le32(MEGASAS_ADPRESET_INPROG_SIGN);
> >  	}
> >  	instance->instancet->disable_intr(instance);
> > -	instance->adprecovery   = MEGASAS_ADPRESET_SM_INFAULT;
> > +	atomic_set(&instance->adprecovery,
> MEGASAS_ADPRESET_SM_INFAULT);
> >  	instance->issuepend_done = 0;
> >
> >  	atomic_set(&instance->fw_outstanding, 0); @@ -2471,18 +2459,14
> @@
> > static int megasas_wait_for_outstanding(struct megasas_instance
*instance)
> >  	int i;
> >  	u32 reset_index;
> >  	u32 wait_time = MEGASAS_RESET_WAIT_TIME;
> > -	u8 adprecovery;
> >  	unsigned long flags;
> >  	struct list_head clist_local;
> >  	struct megasas_cmd *reset_cmd;
> >  	u32 fw_state;
> >  	u8 kill_adapter_flag;
> >
> > -	spin_lock_irqsave(&instance->hba_lock, flags);
> > -	adprecovery = instance->adprecovery;
> > -	spin_unlock_irqrestore(&instance->hba_lock, flags);
> >
> > -	if (adprecovery != MEGASAS_HBA_OPERATIONAL) {
> > +	if (atomic_read(&instance->adprecovery) !=
> MEGASAS_HBA_OPERATIONAL)
> > +{
> >
> >  		INIT_LIST_HEAD(&clist_local);
> >  		spin_lock_irqsave(&instance->hba_lock, flags); @@ -2493,18
> +2477,13
> > @@ static int megasas_wait_for_outstanding(struct megasas_instance
> *instance)
> >  		dev_notice(&instance->pdev->dev, "HBA reset wait ...\n");
> >  		for (i = 0; i < wait_time; i++) {
> >  			msleep(1000);
> > -			spin_lock_irqsave(&instance->hba_lock, flags);
> > -			adprecovery = instance->adprecovery;
> > -			spin_unlock_irqrestore(&instance->hba_lock,
flags);
> > -			if (adprecovery == MEGASAS_HBA_OPERATIONAL)
> > +			if (atomic_read(&instance->adprecovery) ==
> > +MEGASAS_HBA_OPERATIONAL)
> >  				break;
> >  		}
> >
> > -		if (adprecovery != MEGASAS_HBA_OPERATIONAL) {
> > +		if (atomic_read(&instance->adprecovery) !=
> MEGASAS_HBA_OPERATIONAL)
> > +{
> >  			dev_notice(&instance->pdev->dev, "reset: Stopping
> HBA.\n");
> > -			spin_lock_irqsave(&instance->hba_lock, flags);
> > -			instance->adprecovery =
> MEGASAS_HW_CRITICAL_ERROR;
> > -			spin_unlock_irqrestore(&instance->hba_lock,
flags);
> > +			atomic_set(&instance->adprecovery,
> MEGASAS_HW_CRITICAL_ERROR);
> >  			return FAILED;
> >  		}
> >
> > @@ -2613,9 +2592,7 @@ static int megasas_wait_for_outstanding(struct
> megasas_instance *instance)
> >  				&instance->reg_set->inbound_doorbell);
> >  		}
> >  		megasas_dump_pending_frames(instance);
> > -		spin_lock_irqsave(&instance->hba_lock, flags);
> > -		instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
> > -		spin_unlock_irqrestore(&instance->hba_lock, flags);
> > +		atomic_set(&instance->adprecovery,
> MEGASAS_HW_CRITICAL_ERROR);
> >  		return FAILED;
> >  	}
> >
> > @@ -2642,7 +2619,7 @@ static int megasas_generic_reset(struct
scsi_cmnd
> *scmd)
> >  	scmd_printk(KERN_NOTICE, scmd, "megasas: RESET cmd=%x
> retries=%x\n",
> >  		 scmd->cmnd[0], scmd->retries);
> >
> > -	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
> > +	if (atomic_read(&instance->adprecovery) ==
> > +MEGASAS_HW_CRITICAL_ERROR) {
> >  		dev_err(&instance->pdev->dev, "cannot recover from
previous
> reset failures\n");
> >  		return FAILED;
> >  	}
> > @@ -3386,13 +3363,13 @@ process_fw_state_change_wq(struct work_struct
> *work)
> >  	u32 wait;
> >  	unsigned long flags;
> >
> > -	if (instance->adprecovery != MEGASAS_ADPRESET_SM_INFAULT) {
> > +    if (atomic_read(&instance->adprecovery) !=
> > + MEGASAS_ADPRESET_SM_INFAULT) {
> >  		dev_notice(&instance->pdev->dev, "error, recovery st
%x\n",
> > -				instance->adprecovery);
> > +				atomic_read(&instance->adprecovery));
> >  		return ;
> >  	}
> >
> > -	if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) {
> > +	if (atomic_read(&instance->adprecovery) ==
> > +MEGASAS_ADPRESET_SM_INFAULT) {
> >  		dev_notice(&instance->pdev->dev, "FW detected to be in
fault"
> >  					"state, restarting it...\n");
> >
> > @@ -3435,7 +3412,7 @@ process_fw_state_change_wq(struct work_struct
> *work)
> >  		megasas_issue_init_mfi(instance);
> >
> >  		spin_lock_irqsave(&instance->hba_lock, flags);
> > -		instance->adprecovery	= MEGASAS_HBA_OPERATIONAL;
> > +		atomic_set(&instance->adprecovery,
> MEGASAS_HBA_OPERATIONAL);
> >  		spin_unlock_irqrestore(&instance->hba_lock, flags);
> >  		instance->instancet->enable_intr(instance);
> >
> > @@ -3500,14 +3477,14 @@ megasas_deplete_reply_queue(struct
> > megasas_instance *instance,
> >
> >
> >  			instance->instancet->disable_intr(instance);
> > -			instance->adprecovery	=
> MEGASAS_ADPRESET_SM_INFAULT;
> > +			atomic_set(&instance->adprecovery,
> MEGASAS_ADPRESET_SM_INFAULT);
> >  			instance->issuepend_done = 0;
> >
> >  			atomic_set(&instance->fw_outstanding, 0);
> >  			megasas_internal_reset_defer_cmds(instance);
> >
> >  			dev_notice(&instance->pdev->dev, "fwState=%x,
> stage:%d\n",
> > -					fw_state, instance->adprecovery);
> > +					fw_state, atomic_read(&instance-
> >adprecovery));
> >
> >  			schedule_work(&instance->work_init);
> >  			return IRQ_HANDLED;
> > @@ -5796,7 +5773,7 @@ static int megasas_probe_one(struct pci_dev
*pdev,
> >  	instance->flag_ieee = 0;
> >  	instance->ev = NULL;
> >  	instance->issuepend_done = 1;
> > -	instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
> > +	atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
> >  	instance->is_imr = 0;
> >
> >  	instance->evt_detail = pci_alloc_consistent(pdev, @@ -5975,7
+5952,7
> > @@ static void megasas_flush_cache(struct megasas_instance *instance)
> >  	struct megasas_cmd *cmd;
> >  	struct megasas_dcmd_frame *dcmd;
> >
> > -	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
> > +	if (atomic_read(&instance->adprecovery) ==
> > +MEGASAS_HW_CRITICAL_ERROR)
> >  		return;
> >
> >  	cmd = megasas_get_cmd(instance);
> > @@ -6018,7 +5995,7 @@ static void megasas_shutdown_controller(struct
> megasas_instance *instance,
> >  	struct megasas_cmd *cmd;
> >  	struct megasas_dcmd_frame *dcmd;
> >
> > -	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
> > +	if (atomic_read(&instance->adprecovery) ==
> > +MEGASAS_HW_CRITICAL_ERROR)
> >  		return;
> >
> >  	cmd = megasas_get_cmd(instance);
> > @@ -6463,7 +6440,7 @@ static int
> megasas_set_crash_dump_params_ioctl(struct megasas_cmd *cmd)
> >  	for (i = 0; i < megasas_mgmt_info.max_index; i++) {
> >  		local_instance = megasas_mgmt_info.instance[i];
> >  		if (local_instance &&
local_instance->crash_dump_drv_support)
> {
> > -			if ((local_instance->adprecovery ==
> > +			if ((atomic_read(&local_instance->adprecovery) ==
> >  				MEGASAS_HBA_OPERATIONAL) &&
> >
> 	!megasas_set_crash_dump_params(local_instance,
> >  					crash_support)) {
> > @@ -6711,7 +6688,7 @@ static int megasas_mgmt_ioctl_fw(struct file
*file,
> unsigned long arg)
> >  		goto out_kfree_ioc;
> >  	}
> >
> > -	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
> > +	if (atomic_read(&instance->adprecovery) ==
> > +MEGASAS_HW_CRITICAL_ERROR) {
> >  		dev_err(&instance->pdev->dev, "Controller in crit
error\n");
> >  		error = -ENODEV;
> >  		goto out_kfree_ioc;
> > @@ -6730,7 +6707,7 @@ static int megasas_mgmt_ioctl_fw(struct file
*file,
> unsigned long arg)
> >  	for (i = 0; i < wait_time; i++) {
> >
> >  		spin_lock_irqsave(&instance->hba_lock, flags);
> > -		if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
> > +		if (atomic_read(&instance->adprecovery) ==
> MEGASAS_HBA_OPERATIONAL)
> > +{
> >  			spin_unlock_irqrestore(&instance->hba_lock,
flags);
> >  			break;
> >  		}
> > @@ -6745,7 +6722,7 @@ static int megasas_mgmt_ioctl_fw(struct file
*file,
> unsigned long arg)
> >  	}
> >
> >  	spin_lock_irqsave(&instance->hba_lock, flags);
> > -	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
> > +	if (atomic_read(&instance->adprecovery) !=
> MEGASAS_HBA_OPERATIONAL)
> > +{
> >  		spin_unlock_irqrestore(&instance->hba_lock, flags);
> >
> >  		dev_err(&instance->pdev->dev, "timed out while"
> > @@ -6787,7 +6764,7 @@ static int megasas_mgmt_ioctl_aen(struct file
*file,
> unsigned long arg)
> >  	if (!instance)
> >  		return -ENODEV;
> >
> > -	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
> > +	if (atomic_read(&instance->adprecovery) ==
> > +MEGASAS_HW_CRITICAL_ERROR) {
> >  		return -ENODEV;
> >  	}
> >
> > @@ -6798,7 +6775,7 @@ static int megasas_mgmt_ioctl_aen(struct file
*file,
> unsigned long arg)
> >  	for (i = 0; i < wait_time; i++) {
> >
> >  		spin_lock_irqsave(&instance->hba_lock, flags);
> > -		if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
> > +		if (atomic_read(&instance->adprecovery) ==
> MEGASAS_HBA_OPERATIONAL)
> > +{
> >  			spin_unlock_irqrestore(&instance->hba_lock,
> >  						flags);
> >  			break;
> > @@ -6815,7 +6792,7 @@ static int megasas_mgmt_ioctl_aen(struct file
*file,
> unsigned long arg)
> >  	}
> >
> >  	spin_lock_irqsave(&instance->hba_lock, flags);
> > -	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
> > +	if (atomic_read(&instance->adprecovery) !=
> MEGASAS_HBA_OPERATIONAL)
> > +{
> >  		spin_unlock_irqrestore(&instance->hba_lock, flags);
> >  		dev_err(&instance->pdev->dev, "timed out while waiting"
> >  				"for HBA to recover\n");
> > diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > index 1248c7a..96e8d80 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > @@ -2251,7 +2251,7 @@ complete_cmd_fusion(struct megasas_instance
> > *instance, u32 MSIxIndex)
> >
> >  	fusion = instance->ctrl_context;
> >
> > -	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
> > +	if (atomic_read(&instance->adprecovery) ==
> > +MEGASAS_HW_CRITICAL_ERROR)
> >  		return IRQ_HANDLED;
> >
> >  	desc = fusion->reply_frames_desc[MSIxIndex] + @@ -2418,7 +2418,7
> @@
> > megasas_complete_cmd_dpc_fusion(unsigned long instance_addr)
> >
> >  	/* If we have already declared adapter dead, donot complete cmds
*/
> >  	spin_lock_irqsave(&instance->hba_lock, flags);
> > -	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
> > +	if (atomic_read(&instance->adprecovery) ==
> > +MEGASAS_HW_CRITICAL_ERROR) {
> >  		spin_unlock_irqrestore(&instance->hba_lock, flags);
> >  		return;
> >  	}
> > @@ -3200,7 +3200,7 @@ int megasas_task_abort_fusion(struct scsi_cmnd
> *scmd)
> >  	instance = (struct megasas_instance
*)scmd->device->host->hostdata;
> >  	fusion = instance->ctrl_context;
> >
> > -	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
> > +	if (atomic_read(&instance->adprecovery) !=
> MEGASAS_HBA_OPERATIONAL)
> > +{
> >  		dev_err(&instance->pdev->dev, "Controller is not
> OPERATIONAL,"
> >  		"SCSI host:%d\n", instance->host->host_no);
> >  		ret = FAILED;
> > @@ -3284,7 +3284,7 @@ int megasas_reset_target_fusion(struct scsi_cmnd
> *scmd)
> >  	instance = (struct megasas_instance
*)scmd->device->host->hostdata;
> >  	fusion = instance->ctrl_context;
> >
> > -	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
> > +	if (atomic_read(&instance->adprecovery) !=
> MEGASAS_HBA_OPERATIONAL)
> > +{
> >  		dev_err(&instance->pdev->dev, "Controller is not
> OPERATIONAL,"
> >  		"SCSI host:%d\n", instance->host->host_no);
> >  		ret = FAILED;
> > @@ -3376,7 +3376,7 @@ int megasas_reset_fusion(struct Scsi_Host
> > *shost, int reason)
> >
> >  	mutex_lock(&instance->reset_mutex);
> >
> > -	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
> > +	if (atomic_read(&instance->adprecovery) ==
> > +MEGASAS_HW_CRITICAL_ERROR) {
> >  		dev_warn(&instance->pdev->dev, "Hardware critical error, "
> >  		       "returning FAILED for scsi%d.\n",
> >  			instance->host->host_no);
> > @@ -3391,7 +3391,7 @@ int megasas_reset_fusion(struct Scsi_Host
*shost,
> int reason)
> >  		instance->crash_dump_app_support && reason) {
> >  		dev_info(&instance->pdev->dev, "IO/DCMD timeout is
> detected, "
> >  			"forcibly FAULT Firmware\n");
> > -		instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
> > +		atomic_set(&instance->adprecovery,
> MEGASAS_ADPRESET_SM_INFAULT);
> >  		status_reg = readl(&instance->reg_set->doorbell);
> >  		writel(status_reg | MFI_STATE_FORCE_OCR,
> >  			&instance->reg_set->doorbell);
> > @@ -3403,10 +3403,10 @@ int megasas_reset_fusion(struct Scsi_Host
> *shost, int reason)
> >  			dev_dbg(&instance->pdev->dev, "waiting for [%d] "
> >  				"seconds for crash dump collection and OCR
"
> >  				"to be done\n", (io_timeout_in_crash_mode
*
> 3));
> > -		} while ((instance->adprecovery !=
> MEGASAS_HBA_OPERATIONAL) &&
> > +		} while ((atomic_read(&instance->adprecovery) !=
> > +MEGASAS_HBA_OPERATIONAL) &&
> >  			(io_timeout_in_crash_mode < 80));
> >
> > -		if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
> > +		if (atomic_read(&instance->adprecovery) ==
> MEGASAS_HBA_OPERATIONAL)
> > +{
> >  			dev_info(&instance->pdev->dev, "OCR done for IO "
> >  				"timeout case\n");
> >  			retval = SUCCESS;
> > @@ -3423,14 +3423,14 @@ int megasas_reset_fusion(struct Scsi_Host
> *shost, int reason)
> >  	if (instance->requestorId && !instance->skip_heartbeat_timer_del)
> >  		del_timer_sync(&instance->sriov_heartbeat_timer);
> >  	set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
> > -	instance->adprecovery = MEGASAS_ADPRESET_SM_POLLING;
> > +	atomic_set(&instance->adprecovery,
> MEGASAS_ADPRESET_SM_POLLING);
> >  	instance->instancet->disable_intr(instance);
> >  	msleep(1000);
> >
> >  	/* First try waiting for commands to complete */
> >  	if (megasas_wait_for_outstanding_fusion(instance, reason,
> >  						&convert)) {
> > -		instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
> > +		atomic_set(&instance->adprecovery,
> MEGASAS_ADPRESET_SM_INFAULT);
> >  		dev_warn(&instance->pdev->dev, "resetting fusion "
> >  		       "adapter scsi%d.\n", instance->host->host_no);
> >  		if (convert)
> > @@ -3513,8 +3513,7 @@ int megasas_reset_fusion(struct Scsi_Host
*shost,
> int reason)
> >  					       status_reg);
> >  					megaraid_sas_kill_hba(instance);
> >  					instance->skip_heartbeat_timer_del
=
> 1;
> > -					instance->adprecovery =
> > -
> 	MEGASAS_HW_CRITICAL_ERROR;
> > +					atomic_set(&instance->adprecovery,
> MEGASAS_HW_CRITICAL_ERROR);
> >  					retval = FAILED;
> >  					goto out;
> >  				}
> > @@ -3573,7 +3572,7 @@ int megasas_reset_fusion(struct Scsi_Host
*shost,
> int reason)
> >  			clear_bit(MEGASAS_FUSION_IN_RESET,
> >  				  &instance->reset_flags);
> >  			instance->instancet->enable_intr(instance);
> > -			instance->adprecovery =
> MEGASAS_HBA_OPERATIONAL;
> > +			atomic_set(&instance->adprecovery,
> MEGASAS_HBA_OPERATIONAL);
> >
> >  			/* Restart SR-IOV heartbeat */
> >  			if (instance->requestorId) {
> > @@ -3618,7 +3617,7 @@ int megasas_reset_fusion(struct Scsi_Host
*shost,
> int reason)
> >  		}
> >  		clear_bit(MEGASAS_FUSION_IN_RESET, &instance-
> >reset_flags);
> >  		instance->instancet->enable_intr(instance);
> > -		instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
> > +		atomic_set(&instance->adprecovery,
> MEGASAS_HBA_OPERATIONAL);
> >  	}
> >  out:
> >  	clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);

^ permalink raw reply	[flat|nested] 50+ messages in thread

* RE: [PATCH 12/15] megaraid_sas: MFI adapter's OCR changes
  2016-01-19 14:22   ` Tomas Henzl
@ 2016-01-28 11:12     ` Sumit Saxena
  0 siblings, 0 replies; 50+ messages in thread
From: Sumit Saxena @ 2016-01-28 11:12 UTC (permalink / raw)
  To: Tomas Henzl, jbottomley, hch, martin.petersen; +Cc: linux-scsi, Kashyap Desai

> -----Original Message-----
> From: Tomas Henzl [mailto:thenzl@redhat.com]
> Sent: Tuesday, January 19, 2016 7:53 PM
> To: Sumit Saxena; jbottomley@parallels.com; hch@infradead.org;
> martin.petersen@oracle.com
> Cc: linux-scsi@vger.kernel.org; kashyap.desai@avagotech.com
> Subject: Re: [PATCH 12/15] megaraid_sas: MFI adapter's OCR changes
>
> On 18.12.2015 14:27, Sumit Saxena wrote:
> > Optimized MFI adapters' OCR path, particularly
> megasas_wait_for_outstanding() function.
> >
> > Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
> > Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
> > ---
> >  drivers/scsi/megaraid/megaraid_sas_base.c |  104
> > +++++++++++++++--------------
> >  1 files changed, 54 insertions(+), 50 deletions(-)
> >
> > diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c
> > b/drivers/scsi/megaraid/megaraid_sas_base.c
> > index 5eaf6fd..cc843d6 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas_base.c
> > +++ b/drivers/scsi/megaraid/megaraid_sas_base.c
> > @@ -2456,15 +2456,19 @@ void megasas_sriov_heartbeat_handler(unsigned
> long instance_addr)
> >   */
> >  static int megasas_wait_for_outstanding(struct megasas_instance
> > *instance)  {
> > -	int i;
> > +	int i, sl, outstanding;
> >  	u32 reset_index;
> >  	u32 wait_time = MEGASAS_RESET_WAIT_TIME;
> >  	unsigned long flags;
> >  	struct list_head clist_local;
> >  	struct megasas_cmd *reset_cmd;
> >  	u32 fw_state;
> > -	u8 kill_adapter_flag;
> >
> > +	if (atomic_read(&instance->adprecovery) ==
> MEGASAS_HW_CRITICAL_ERROR) {
> > +		dev_info(&instance->pdev->dev, "%s:%d HBA is killed.\n",
> > +		__func__, __LINE__);
> > +		return FAILED;
> > +	}
> >
> >  	if (atomic_read(&instance->adprecovery) !=
> MEGASAS_HBA_OPERATIONAL)
> > {
> >
> > @@ -2521,7 +2525,7 @@ static int megasas_wait_for_outstanding(struct
> megasas_instance *instance)
> >  	}
> >
> >  	for (i = 0; i < resetwaittime; i++) {
> > -		int outstanding = atomic_read(&instance->fw_outstanding);
> > +		outstanding = atomic_read(&instance->fw_outstanding);
> >
> >  		if (!outstanding)
> >  			break;
> > @@ -2540,65 +2544,65 @@ static int megasas_wait_for_outstanding(struct
> megasas_instance *instance)
> >  	}
> >
> >  	i = 0;
> > -	kill_adapter_flag = 0;
> > +	outstanding = atomic_read(&instance->fw_outstanding);
> > +	fw_state =
> > +instance->instancet->read_fw_status_reg(instance->reg_set) &
> > +MFI_STATE_MASK;
> > +
> > +	if ((!outstanding && (fw_state == MFI_STATE_OPERATIONAL)))
> > +		goto no_outstanding;
> > +
> > +	if (instance->disableOnlineCtrlReset)
> > +		goto kill_hba_and_failed;
> >  	do {
> > -		fw_state = instance->instancet->read_fw_status_reg(
> > -					instance->reg_set) &
> MFI_STATE_MASK;
> > -		if ((fw_state == MFI_STATE_FAULT) &&
> > -			(instance->disableOnlineCtrlReset == 0)) {
> > -			if (i == 3) {
> > -				kill_adapter_flag = 2;
> > -				break;
> > -			}
> > +		if ((fw_state == MFI_STATE_FAULT) ||
atomic_read(&instance-
> >fw_outstanding)) {
> > +			dev_info(&instance->pdev->dev,
> > +				"%s:%d waiting_for_outstanding: before
issue
> OCR. FW state = 0x%x, oustanding 0x%x\n",
> > +				__func__, __LINE__, fw_state,
> atomic_read(&instance->fw_outstanding));
> > +			if (i == 3)
> > +				goto kill_hba_and_failed;
> >  			megasas_do_ocr(instance);
> > -			kill_adapter_flag = 1;
> >
> > -			/* wait for 1 secs to let FW finish the pending
cmds */
> > -			msleep(1000);
> > +			if (atomic_read(&instance->adprecovery) ==
> MEGASAS_HW_CRITICAL_ERROR) {
> > +				dev_info(&instance->pdev->dev, "%s:%d OCR
> failed and HBA is killed.\n",
> > +				__func__, __LINE__);
> > +				return FAILED;
> > +			}
> > +			dev_info(&instance->pdev->dev, "%s:%d
> waiting_for_outstanding: after issue OCR.\n",
> > +				__func__, __LINE__);
> > +
> > +			for (sl = 0; sl < 10; sl++)
> > +				msleep(500);
>
> 		ssleep(5); ?
>
> > +
> > +			outstanding = atomic_read(&instance-
> >fw_outstanding);
> > +
> > +			fw_state = instance->instancet-
> >read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
> > +			if ((!outstanding && (fw_state ==
> MFI_STATE_OPERATIONAL)))
> > +				goto no_outstanding;
> >  		}
> >  		i++;
> >  	} while (i <= 3);
> >
> > -	if (atomic_read(&instance->fw_outstanding) && !kill_adapter_flag)
{
> > -		if (instance->disableOnlineCtrlReset == 0) {
> > -			megasas_do_ocr(instance);
> > +no_outstanding:
> >
> > -			/* wait for 5 secs to let FW finish the pending
cmds */
> > -			for (i = 0; i < wait_time; i++) {
> > -				int outstanding =
> > -					atomic_read(&instance-
> >fw_outstanding);
> > -				if (!outstanding)
> > -					return SUCCESS;
> > -				msleep(1000);
> > -			}
> > -		}
> > -	}
> > +	dev_info(&instance->pdev->dev, "%s:%d no more pending commands
> remain after reset handling.\n",
> > +		__func__, __LINE__);
> > +	return SUCCESS;
> >
> > -	if (atomic_read(&instance->fw_outstanding) ||
> > -					(kill_adapter_flag == 2)) {
> > -		dev_notice(&instance->pdev->dev, "pending cmds after
> reset\n");
> > -		/*
> > -		 * Send signal to FW to stop processing any pending cmds.
> > -		 * The controller will be taken offline by the OS now.
> > -		 */
> > -		if ((instance->pdev->device ==
> > -			PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
> > -			(instance->pdev->device ==
> > -			PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
> > -			writel(MFI_STOP_ADP,
> > -				&instance->reg_set->doorbell);
> > -		} else {
> > -			writel(MFI_STOP_ADP,
> > -				&instance->reg_set->inbound_doorbell);
> > -		}
> > +kill_hba_and_failed:
> > +
> > +	fw_state =
instance->instancet->read_fw_status_reg(instance->reg_set)
> & MFI_STATE_MASK;
> > +	if (instance->disableOnlineCtrlReset ||
> > +		atomic_read(&instance->fw_outstanding) ||
> > +		(fw_state == MFI_STATE_FAULT)) {
>
> You have tested all that many times before (fw_state etc.), so when you
after all
> that have arrived at kill_hba_and_failed: please just kill the HBA and
return
> FAILED.

Agree..will be accommodating this while resending patch.
>
> > +		/* Reset not supported, kill adapter */
> > +		dev_info(&instance->pdev->dev, "%s:%d killing adapter
scsi%d"
> > +			" disableOnlineCtrlReset %d fw_outstanding %d \n",
> > +			__func__, __LINE__, instance->host->host_no,
> instance->disableOnlineCtrlReset,
> > +			atomic_read(&instance->fw_outstanding));
> >  		megasas_dump_pending_frames(instance);
> > -		atomic_set(&instance->adprecovery,
> MEGASAS_HW_CRITICAL_ERROR);
> > -		return FAILED;
> > +		megaraid_sas_kill_hba(instance);
> >  	}
> >
> > -	dev_notice(&instance->pdev->dev, "no pending cmds after reset\n");
> > -
> > -	return SUCCESS;
> > +	return FAILED;
> >  }
> >
> >  /**

^ permalink raw reply	[flat|nested] 50+ messages in thread

* RE: [PATCH 13/15] megaraid_sas: Introduce module parameter for SCSI command-timeout
  2016-01-19 14:57   ` Tomas Henzl
@ 2016-01-28 11:17     ` Sumit Saxena
  0 siblings, 0 replies; 50+ messages in thread
From: Sumit Saxena @ 2016-01-28 11:17 UTC (permalink / raw)
  To: Tomas Henzl, jbottomley, hch, martin.petersen; +Cc: linux-scsi, Kashyap Desai

> -----Original Message-----
> From: Tomas Henzl [mailto:thenzl@redhat.com]
> Sent: Tuesday, January 19, 2016 8:27 PM
> To: Sumit Saxena; jbottomley@parallels.com; hch@infradead.org;
> martin.petersen@oracle.com
> Cc: linux-scsi@vger.kernel.org; kashyap.desai@avagotech.com
> Subject: Re: [PATCH 13/15] megaraid_sas: Introduce module parameter for
SCSI
> command-timeout
>
> On 18.12.2015 14:27, Sumit Saxena wrote:
> > This patch will introduce module-parameter for SCSI command timeout
value
> and fix setting of resetwaitime beyond a value.
> >
> > Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
> > Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
> > ---
> >  drivers/scsi/megaraid/megaraid_sas_base.c   |   15 ++++++++++++---
> >  drivers/scsi/megaraid/megaraid_sas_fusion.c |    2 +-
> >  2 files changed, 13 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c
> > b/drivers/scsi/megaraid/megaraid_sas_base.c
> > index cc843d6..316d5a0 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas_base.c
> > +++ b/drivers/scsi/megaraid/megaraid_sas_base.c
> > @@ -83,7 +83,7 @@ module_param(throttlequeuedepth, int, S_IRUGO);
> > MODULE_PARM_DESC(throttlequeuedepth,
> >  	"Adapter queue depth when throttled due to I/O timeout. Default:
> > 16");
> >
> > -int resetwaittime = MEGASAS_RESET_WAIT_TIME;
> > +unsigned int resetwaittime = MEGASAS_RESET_WAIT_TIME;
> >  module_param(resetwaittime, int, S_IRUGO);
> > MODULE_PARM_DESC(resetwaittime, "Wait time in seconds after I/O
timeout
> "
> >  		 "before resetting adapter. Default: 180"); @@ -100,6
+100,10
> @@
> > unsigned int dual_qdepth_disable;  module_param(dual_qdepth_disable,
> > int, S_IRUGO);  MODULE_PARM_DESC(dual_qdepth_disable, "Disable dual
> > queue depth feature. Default: 0");
> >
> > +unsigned int scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT;
> > +module_param(scmd_timeout, int, S_IRUGO);
> > +MODULE_PARM_DESC(scmd_timeout, "scsi command timeout (10-90s),
> > +default 90s. See megasas_reset_timer.");
>
> When you know that "The RAID firmware may require extended timeouts"
what
> do you expect when an user sets a short timeout value ?

The requirement here was to have scmd_timeout be tunable at driver load
time so have to add
Module parameter to do so.

> Other than that, I don't think that lot of tunables in a driver makes it
better, from
> my point of view you could remove both resetwaittime + scmd_timeout.
> Okay, I don't want to stay in the way if you really need it so -
>
> Reviewed-by: Tomas Henzl <thenzl@redhat.com>
>
> Tomas

^ permalink raw reply	[flat|nested] 50+ messages in thread

end of thread, other threads:[~2016-01-28 11:18 UTC | newest]

Thread overview: 50+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-12-18 13:26 [PATCH 00/15] megaraid_sas: Updates for scsi-next Sumit Saxena
2015-12-18 13:26 ` [PATCH 01/15] megaraid_sas: Do not allow PCI access during OCR Sumit Saxena
2016-01-11 17:02   ` Tomas Henzl
2015-12-18 13:26 ` [PATCH 02/15] megaraid_sas: MFI IO timeout handling Sumit Saxena
2016-01-11 17:02   ` Tomas Henzl
2015-12-18 13:26 ` [PATCH 03/15] megaraid_sas: Syncing request flags macro names with firmware Sumit Saxena
2016-01-11 17:03   ` Tomas Henzl
2015-12-18 13:26 ` [PATCH 04/15] megaraid_sas: Task management support Sumit Saxena
2016-01-11 17:03   ` Tomas Henzl
2016-01-14 12:04     ` Sumit Saxena
2015-12-18 13:26 ` [PATCH 05/15] megaraid_sas: Update device Queue depth based on interface type Sumit Saxena
2016-01-12 14:16   ` Tomas Henzl
2016-01-14 11:48     ` Sumit Saxena
2015-12-18 13:26 ` [PATCH 06/15] megaraid_sas: Fastpath region lock bypass Sumit Saxena
2016-01-12 14:44   ` Tomas Henzl
2015-12-18 13:27 ` [PATCH 07/15] megaraid_sas: Reply Descriptor Post Queue(RDPQ) support Sumit Saxena
2015-12-18 14:49   ` [PATCH] megaraid_sas: fix kzalloc-simple.cocci warnings kbuild test robot
2015-12-18 14:49   ` [PATCH 07/15] megaraid_sas: Reply Descriptor Post Queue(RDPQ) support kbuild test robot
2016-01-14 17:38   ` Tomas Henzl
2016-01-27 18:15     ` Sumit Saxena
2015-12-18 13:27 ` [PATCH 08/15] megaraid_sas: Code optimization build_and_issue_cmd return-type Sumit Saxena
2016-01-14 18:05   ` Tomas Henzl
2015-12-18 13:27 ` [PATCH 09/15] megaraid_sas: Dual Queue depth support Sumit Saxena
2016-01-19 13:34   ` Tomas Henzl
2016-01-19 13:44     ` Sumit Saxena
2016-01-20 13:55       ` Tomas Henzl
2016-01-20 14:09         ` Sumit Saxena
2016-01-20 14:16           ` Tomas Henzl
2016-01-20 15:08             ` Sumit Saxena
2016-01-20 16:00               ` Tomas Henzl
2016-01-27  2:02             ` Martin K. Petersen
2016-01-27  7:09               ` Sumit Saxena
2015-12-18 13:27 ` [PATCH 10/15] megaraid_sas: IO throttling support Sumit Saxena
2016-01-19 13:38   ` Tomas Henzl
2016-01-28  7:18     ` Sumit Saxena
2015-12-18 13:27 ` [PATCH 11/15] megaraid_sas: Make adprecovery variable atomic Sumit Saxena
2016-01-19 13:52   ` Tomas Henzl
2016-01-28  8:30     ` Sumit Saxena
2015-12-18 13:27 ` [PATCH 12/15] megaraid_sas: MFI adapter's OCR changes Sumit Saxena
2016-01-19 14:22   ` Tomas Henzl
2016-01-28 11:12     ` Sumit Saxena
2015-12-18 13:27 ` [PATCH 13/15] megaraid_sas: Introduce module parameter for SCSI command-timeout Sumit Saxena
2016-01-19 14:57   ` Tomas Henzl
2016-01-28 11:17     ` Sumit Saxena
2015-12-18 13:27 ` [PATCH 14/15] megaraid_sas: SPERC OCR changes Sumit Saxena
2016-01-19 15:14   ` Tomas Henzl
2015-12-18 13:27 ` [PATCH 15/15] megaraid_sas: SPERC boot driver reorder Sumit Saxena
2015-12-18 14:05   ` Christoph Hellwig
2016-01-08  7:07     ` Sumit Saxena
2016-01-12  5:26     ` Sumit Saxena

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.