a8a466
From a28d10b2a9bec8714f59e12fe7fb53bfe8c6ef17 Mon Sep 17 00:00:00 2001
a8a466
From: Sasikumar Chandrasekaran <sasikumar.pc@broadcom.com>
a8a466
Date: Tue, 10 Jan 2017 18:20:46 -0500
a8a466
Subject: [PATCH 04/11] scsi: megaraid_sas: SAS3.5 Generic Megaraid Controllers
a8a466
 Stream Detection and IO Coalescing
a8a466
a8a466
Detect sequential Write IOs and pass the hint that it is part of sequential
a8a466
stream to help HBA Firmware do the Full Stripe Writes. For read IOs on
a8a466
certain RAID volumes like Read Ahead volumes,this will help driver to
a8a466
send it to Firmware even if the IOs can potentially be sent to
a8a466
hardware directly (called fast path) bypassing firmware.
a8a466
a8a466
Design: 8 streams are maintained per RAID volume as per the combined
a8a466
firmware/driver design. When there is no stream detected the LRU stream
a8a466
is used for next potential stream and LRU/MRU map is updated to make this
a8a466
as MRU stream. Every time a stream is detected the MRU map
a8a466
is updated to make the current stream as MRU stream.
a8a466
a8a466
Signed-off-by: Sasikumar Chandrasekaran <sasikumar.pc@broadcom.com>
a8a466
Reviewed-by: Tomas Henzl <thenzl@redhat.com>
a8a466
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
a8a466
---
a8a466
 drivers/scsi/megaraid/megaraid_sas.h        |   1 +
a8a466
 drivers/scsi/megaraid/megaraid_sas_base.c   |  43 +++++++-
a8a466
 drivers/scsi/megaraid/megaraid_sas_fp.c     |   2 +
a8a466
 drivers/scsi/megaraid/megaraid_sas_fusion.c | 165 +++++++++++++++++++++++-----
a8a466
 drivers/scsi/megaraid/megaraid_sas_fusion.h | 117 +++++++++++++++++++-
a8a466
 5 files changed, 297 insertions(+), 31 deletions(-)
a8a466
a8a466
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
a8a466
index ccef47b..f387b32 100644
a8a466
--- a/drivers/scsi/megaraid/megaraid_sas.h
a8a466
+++ b/drivers/scsi/megaraid/megaraid_sas.h
a8a466
@@ -2070,6 +2070,7 @@ struct megasas_instance {
a8a466
 	/* used to sync fire the cmd to fw */
a8a466
 	spinlock_t hba_lock;
a8a466
 	/* used to synch producer, consumer ptrs in dpc */
a8a466
+	spinlock_t stream_lock;
a8a466
 	spinlock_t completion_lock;
a8a466
 	struct dma_pool *frame_dma_pool;
a8a466
 	struct dma_pool *sense_dma_pool;
a8a466
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
a8a466
index c78d7ee..0722286 100644
a8a466
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
a8a466
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
a8a466
@@ -5048,7 +5048,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
a8a466
 	struct megasas_register_set __iomem *reg_set;
a8a466
 	struct megasas_ctrl_info *ctrl_info = NULL;
a8a466
 	unsigned long bar_list;
a8a466
-	int i, loop, fw_msix_count = 0;
a8a466
+	int i, j, loop, fw_msix_count = 0;
a8a466
 	struct IOV_111 *iovPtr;
a8a466
 	struct fusion_context *fusion;
a8a466
 
a8a466
@@ -5235,6 +5235,36 @@ static int megasas_init_fw(struct megasas_instance *instance)
a8a466
 	}
a8a466
 
a8a466
 	memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
a8a466
+
a8a466
+	/* stream detection initialization */
a8a466
+	if (instance->is_ventura) {
a8a466
+		fusion->stream_detect_by_ld =
a8a466
+		kzalloc(sizeof(struct LD_STREAM_DETECT *)
a8a466
+		* MAX_LOGICAL_DRIVES_EXT,
a8a466
+		GFP_KERNEL);
a8a466
+		if (!fusion->stream_detect_by_ld) {
a8a466
+			dev_err(&instance->pdev->dev,
a8a466
+					"unable to allocate stream detection for pool of LDs\n");
a8a466
+			goto fail_get_ld_pd_list;
a8a466
+		}
a8a466
+		for (i = 0; i < MAX_LOGICAL_DRIVES_EXT; ++i) {
a8a466
+			fusion->stream_detect_by_ld[i] =
a8a466
+				kmalloc(sizeof(struct LD_STREAM_DETECT),
a8a466
+				GFP_KERNEL);
a8a466
+			if (!fusion->stream_detect_by_ld[i]) {
a8a466
+				dev_err(&instance->pdev->dev,
a8a466
+					"unable to allocate stream detect by LD\n ");
a8a466
+				for (j = 0; j < i; ++j)
a8a466
+					kfree(fusion->stream_detect_by_ld[j]);
a8a466
+				kfree(fusion->stream_detect_by_ld);
a8a466
+				fusion->stream_detect_by_ld = NULL;
a8a466
+				goto fail_get_ld_pd_list;
a8a466
+			}
a8a466
+			fusion->stream_detect_by_ld[i]->mru_bit_map
a8a466
+				= MR_STREAM_BITMAP;
a8a466
+		}
a8a466
+	}
a8a466
+
a8a466
 	if (megasas_ld_list_query(instance,
a8a466
 				  MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
a8a466
 		megasas_get_ld_list(instance);
a8a466
@@ -5354,6 +5384,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
a8a466
 
a8a466
 	return 0;
a8a466
 
a8a466
+fail_get_ld_pd_list:
a8a466
+	instance->instancet->disable_intr(instance);
a8a466
 fail_get_pd_list:
a8a466
 	instance->instancet->disable_intr(instance);
a8a466
 	megasas_destroy_irqs(instance);
a8a466
@@ -5896,6 +5928,7 @@ static int megasas_probe_one(struct pci_dev *pdev,
a8a466
 
a8a466
 	spin_lock_init(&instance->mfi_pool_lock);
a8a466
 	spin_lock_init(&instance->hba_lock);
a8a466
+	spin_lock_init(&instance->stream_lock);
a8a466
 	spin_lock_init(&instance->completion_lock);
a8a466
 
a8a466
 	mutex_init(&instance->reset_mutex);
a8a466
@@ -6363,6 +6396,14 @@ static void megasas_detach_one(struct pci_dev *pdev)
a8a466
 	if (instance->msix_vectors)
a8a466
 		pci_disable_msix(instance->pdev);
a8a466
 
a8a466
+	if (instance->is_ventura) {
a8a466
+		for (i = 0; i < MAX_LOGICAL_DRIVES_EXT; ++i)
a8a466
+			kfree(fusion->stream_detect_by_ld[i]);
a8a466
+		kfree(fusion->stream_detect_by_ld);
a8a466
+		fusion->stream_detect_by_ld = NULL;
a8a466
+	}
a8a466
+
a8a466
+
a8a466
 	if (instance->ctrl_context) {
a8a466
 		megasas_release_fusion(instance);
a8a466
 			pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) +
a8a466
diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c
a8a466
index e413113..fe5b074 100644
a8a466
--- a/drivers/scsi/megaraid/megaraid_sas_fp.c
a8a466
+++ b/drivers/scsi/megaraid/megaraid_sas_fp.c
a8a466
@@ -933,6 +933,8 @@ MR_BuildRaidContext(struct megasas_instance *instance,
a8a466
 
a8a466
 	ld = MR_TargetIdToLdGet(ldTgtId, map);
a8a466
 	raid = MR_LdRaidGet(ld, map);
a8a466
+	/*check read ahead bit*/
a8a466
+	io_info->ra_capable = raid->capability.ra_capable;
a8a466
 
a8a466
 	/*
a8a466
 	 * if rowDataSize @RAID map and spanRowDataSize @SPAN INFO are zero
a8a466
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
a8a466
index 27c6a1f..946f7c0 100644
a8a466
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
a8a466
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
a8a466
@@ -1704,6 +1704,90 @@ megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len,
a8a466
 }
a8a466
 
a8a466
 /**
a8a466
+ * megasas_stream_detect -	stream detection on read and and write IOs
a8a466
+ * @instance:		Adapter soft state
a8a466
+ * @cmd:		    Command to be prepared
a8a466
+ * @io_info:		IO Request info
a8a466
+ *
a8a466
+ */
a8a466
+
a8a466
+/** stream detection on read and and write IOs */
a8a466
+static void megasas_stream_detect(struct megasas_instance *instance,
a8a466
+				struct megasas_cmd_fusion *cmd,
a8a466
+				struct IO_REQUEST_INFO *io_info)
a8a466
+{
a8a466
+	struct fusion_context *fusion = instance->ctrl_context;
a8a466
+	u32 device_id = io_info->ldTgtId;
a8a466
+	struct LD_STREAM_DETECT *current_ld_sd
a8a466
+		= fusion->stream_detect_by_ld[device_id];
a8a466
+	u32 *track_stream = &current_ld_sd->mru_bit_map, stream_num;
a8a466
+	u32 shifted_values, unshifted_values;
a8a466
+	u32 index_value_mask, shifted_values_mask;
a8a466
+	int i;
a8a466
+	bool is_read_ahead = false;
a8a466
+	struct STREAM_DETECT *current_sd;
a8a466
+	/* find possible stream */
a8a466
+	for (i = 0; i < MAX_STREAMS_TRACKED; ++i) {
a8a466
+		stream_num =
a8a466
+		(*track_stream >> (i * BITS_PER_INDEX_STREAM)) &
a8a466
+			STREAM_MASK;
a8a466
+		current_sd = &current_ld_sd->stream_track[stream_num];
a8a466
+	/* if we found a stream, update the raid
a8a466
+	 *  context and also update the mruBitMap
a8a466
+	 */
a8a466
+	/*	boundary condition */
a8a466
+	if ((current_sd->next_seq_lba) &&
a8a466
+		(io_info->ldStartBlock >= current_sd->next_seq_lba) &&
a8a466
+		(io_info->ldStartBlock <= (current_sd->next_seq_lba+32)) &&
a8a466
+		(current_sd->is_read == io_info->isRead)) {
a8a466
+
a8a466
+		if ((io_info->ldStartBlock != current_sd->next_seq_lba)
a8a466
+			&& ((!io_info->isRead) || (!is_read_ahead)))
a8a466
+			/*
a8a466
+			 * Once the API availible we need to change this.
a8a466
+			 * At this point we are not allowing any gap
a8a466
+			 */
a8a466
+			continue;
a8a466
+
a8a466
+		cmd->io_request->RaidContext.raid_context_g35.stream_detected = true;
a8a466
+		current_sd->next_seq_lba =
a8a466
+		io_info->ldStartBlock + io_info->numBlocks;
a8a466
+		/*
a8a466
+		 *	update the mruBitMap LRU
a8a466
+		 */
a8a466
+		shifted_values_mask =
a8a466
+			(1 <<  i * BITS_PER_INDEX_STREAM) - 1;
a8a466
+		shifted_values = ((*track_stream & shifted_values_mask)
a8a466
+					<< BITS_PER_INDEX_STREAM);
a8a466
+		index_value_mask =
a8a466
+			STREAM_MASK << i * BITS_PER_INDEX_STREAM;
a8a466
+		unshifted_values =
a8a466
+			*track_stream & ~(shifted_values_mask |
a8a466
+			index_value_mask);
a8a466
+		*track_stream =
a8a466
+			unshifted_values | shifted_values | stream_num;
a8a466
+		return;
a8a466
+
a8a466
+		}
a8a466
+
a8a466
+	}
a8a466
+	/*
a8a466
+	 * if we did not find any stream, create a new one
a8a466
+	 * from the least recently used
a8a466
+	 */
a8a466
+	stream_num =
a8a466
+	(*track_stream >> ((MAX_STREAMS_TRACKED - 1) * BITS_PER_INDEX_STREAM)) &
a8a466
+			STREAM_MASK;
a8a466
+	current_sd = &current_ld_sd->stream_track[stream_num];
a8a466
+	current_sd->is_read = io_info->isRead;
a8a466
+	current_sd->next_seq_lba = io_info->ldStartBlock + io_info->numBlocks;
a8a466
+	*track_stream =
a8a466
+	(((*track_stream & ZERO_LAST_STREAM) << 4) | stream_num);
a8a466
+	return;
a8a466
+
a8a466
+}
a8a466
+
a8a466
+/**
a8a466
  * megasas_build_ldio_fusion -	Prepares IOs to devices
a8a466
  * @instance:		Adapter soft state
a8a466
  * @scp:		SCSI command
a8a466
@@ -1725,15 +1809,17 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
a8a466
 	struct fusion_context *fusion;
a8a466
 	struct MR_DRV_RAID_MAP_ALL *local_map_ptr;
a8a466
 	u8 *raidLUN;
a8a466
+	unsigned long spinlock_flags;
a8a466
 
a8a466
 	device_id = MEGASAS_DEV_INDEX(scp);
a8a466
 
a8a466
 	fusion = instance->ctrl_context;
a8a466
 
a8a466
 	io_request = cmd->io_request;
a8a466
-	io_request->RaidContext.VirtualDiskTgtId = cpu_to_le16(device_id);
a8a466
-	io_request->RaidContext.status = 0;
a8a466
-	io_request->RaidContext.exStatus = 0;
a8a466
+	io_request->RaidContext.raid_context.VirtualDiskTgtId =
a8a466
+		cpu_to_le16(device_id);
a8a466
+	io_request->RaidContext.raid_context.status = 0;
a8a466
+	io_request->RaidContext.raid_context.exStatus = 0;
a8a466
 
a8a466
 	req_desc = (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)cmd->request_desc;
a8a466
 
a8a466
@@ -1804,11 +1890,11 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
a8a466
 
a8a466
 	if ((MR_TargetIdToLdGet(device_id, local_map_ptr) >=
a8a466
 		instance->fw_supported_vd_count) || (!fusion->fast_path_io)) {
a8a466
-		io_request->RaidContext.regLockFlags  = 0;
a8a466
+		io_request->RaidContext.raid_context.regLockFlags  = 0;
a8a466
 		fp_possible = 0;
a8a466
 	} else {
a8a466
 		if (MR_BuildRaidContext(instance, &io_info,
a8a466
-					&io_request->RaidContext,
a8a466
+					&io_request->RaidContext.raid_context,
a8a466
 					local_map_ptr, &raidLUN))
a8a466
 			fp_possible = io_info.fpOkForIo;
a8a466
 	}
a8a466
@@ -1819,6 +1905,18 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
a8a466
 	cmd->request_desc->SCSIIO.MSIxIndex = instance->msix_vectors ?
a8a466
 		raw_smp_processor_id() % instance->msix_vectors : 0;
a8a466
 
a8a466
+	if (instance->is_ventura) {
a8a466
+		spin_lock_irqsave(&instance->stream_lock, spinlock_flags);
a8a466
+		megasas_stream_detect(instance, cmd, &io_info);
a8a466
+		spin_unlock_irqrestore(&instance->stream_lock, spinlock_flags);
a8a466
+		/* In ventura if stream detected for a read and it is read ahead
a8a466
+		 *  capable make this IO as LDIO
a8a466
+		 */
a8a466
+		if (io_request->RaidContext.raid_context_g35.stream_detected &&
a8a466
+				io_info.isRead && io_info.ra_capable)
a8a466
+			fp_possible = false;
a8a466
+	}
a8a466
+
a8a466
 	if (fp_possible) {
a8a466
 		megasas_set_pd_lba(io_request, scp->cmd_len, &io_info, scp,
a8a466
 				   local_map_ptr, start_lba_lo);
a8a466
@@ -1827,15 +1925,16 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
a8a466
 			(MPI2_REQ_DESCRIPT_FLAGS_FP_IO
a8a466
 			 << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
a8a466
 		if (fusion->adapter_type == INVADER_SERIES) {
a8a466
-			if (io_request->RaidContext.regLockFlags ==
a8a466
+			if (io_request->RaidContext.raid_context.regLockFlags ==
a8a466
 			    REGION_TYPE_UNUSED)
a8a466
 				cmd->request_desc->SCSIIO.RequestFlags =
a8a466
 					(MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK <<
a8a466
 					MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
a8a466
-			io_request->RaidContext.Type = MPI2_TYPE_CUDA;
a8a466
-			io_request->RaidContext.nseg = 0x1;
a8a466
+			io_request->RaidContext.raid_context.Type
a8a466
+				= MPI2_TYPE_CUDA;
a8a466
+			io_request->RaidContext.raid_context.nseg = 0x1;
a8a466
 			io_request->IoFlags |= cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
a8a466
-			io_request->RaidContext.regLockFlags |=
a8a466
+			io_request->RaidContext.raid_context.regLockFlags |=
a8a466
 			  (MR_RL_FLAGS_GRANT_DESTINATION_CUDA |
a8a466
 			   MR_RL_FLAGS_SEQ_NUM_ENABLE);
a8a466
 		}
a8a466
@@ -1862,22 +1961,24 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
a8a466
 		/* populate the LUN field */
a8a466
 		memcpy(io_request->LUN, raidLUN, 8);
a8a466
 	} else {
a8a466
-		io_request->RaidContext.timeoutValue =
a8a466
+		io_request->RaidContext.raid_context.timeoutValue =
a8a466
 			cpu_to_le16(local_map_ptr->raidMap.fpPdIoTimeoutSec);
a8a466
 		cmd->request_desc->SCSIIO.RequestFlags =
a8a466
 			(MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO
a8a466
 			 << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
a8a466
 		if (fusion->adapter_type == INVADER_SERIES) {
a8a466
 			if (io_info.do_fp_rlbypass ||
a8a466
-				(io_request->RaidContext.regLockFlags == REGION_TYPE_UNUSED))
a8a466
+			(io_request->RaidContext.raid_context.regLockFlags
a8a466
+					== REGION_TYPE_UNUSED))
a8a466
 				cmd->request_desc->SCSIIO.RequestFlags =
a8a466
 					(MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK <<
a8a466
 					MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
a8a466
-			io_request->RaidContext.Type = MPI2_TYPE_CUDA;
a8a466
-			io_request->RaidContext.regLockFlags |=
a8a466
+			io_request->RaidContext.raid_context.Type
a8a466
+				= MPI2_TYPE_CUDA;
a8a466
+			io_request->RaidContext.raid_context.regLockFlags |=
a8a466
 				(MR_RL_FLAGS_GRANT_DESTINATION_CPU0 |
a8a466
 				 MR_RL_FLAGS_SEQ_NUM_ENABLE);
a8a466
-			io_request->RaidContext.nseg = 0x1;
a8a466
+			io_request->RaidContext.raid_context.nseg = 0x1;
a8a466
 		}
a8a466
 		io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
a8a466
 		io_request->DevHandle = cpu_to_le16(device_id);
a8a466
@@ -1913,7 +2014,7 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance,
a8a466
 	local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
a8a466
 	io_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
a8a466
 	/* get RAID_Context pointer */
a8a466
-	pRAID_Context = &io_request->RaidContext;
a8a466
+	pRAID_Context = &io_request->RaidContext.raid_context;
a8a466
 	/* Check with FW team */
a8a466
 	pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id);
a8a466
 	pRAID_Context->regLockRowLBA    = 0;
a8a466
@@ -2000,7 +2101,7 @@ megasas_build_syspd_fusion(struct megasas_instance *instance,
a8a466
 
a8a466
 	io_request = cmd->io_request;
a8a466
 	/* get RAID_Context pointer */
a8a466
-	pRAID_Context = &io_request->RaidContext;
a8a466
+	pRAID_Context = &io_request->RaidContext.raid_context;
a8a466
 	pRAID_Context->regLockFlags = 0;
a8a466
 	pRAID_Context->regLockRowLBA = 0;
a8a466
 	pRAID_Context->regLockLength = 0;
a8a466
@@ -2094,9 +2195,9 @@ megasas_build_io_fusion(struct megasas_instance *instance,
a8a466
 	io_request->Control = 0;
a8a466
 	io_request->EEDPBlockSize = 0;
a8a466
 	io_request->ChainOffset = 0;
a8a466
-	io_request->RaidContext.RAIDFlags = 0;
a8a466
-	io_request->RaidContext.Type = 0;
a8a466
-	io_request->RaidContext.nseg = 0;
a8a466
+	io_request->RaidContext.raid_context.RAIDFlags = 0;
a8a466
+	io_request->RaidContext.raid_context.Type = 0;
a8a466
+	io_request->RaidContext.raid_context.nseg = 0;
a8a466
 
a8a466
 	memcpy(io_request->CDB.CDB32, scp->cmnd, scp->cmd_len);
a8a466
 	/*
a8a466
@@ -2143,8 +2244,8 @@ megasas_build_io_fusion(struct megasas_instance *instance,
a8a466
 	/* numSGE store lower 8 bit of sge_count.
a8a466
 	 * numSGEExt store higher 8 bit of sge_count
a8a466
 	 */
a8a466
-	io_request->RaidContext.numSGE = sge_count;
a8a466
-	io_request->RaidContext.numSGEExt = (u8)(sge_count >> 8);
a8a466
+	io_request->RaidContext.raid_context.numSGE = sge_count;
a8a466
+	io_request->RaidContext.raid_context.numSGEExt = (u8)(sge_count >> 8);
a8a466
 
a8a466
 	io_request->SGLFlags = cpu_to_le16(MPI2_SGE_FLAGS_64_BIT_ADDRESSING);
a8a466
 
a8a466
@@ -2303,8 +2404,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
a8a466
 			cmd_fusion->scmd->SCp.ptr = NULL;
a8a466
 
a8a466
 		scmd_local = cmd_fusion->scmd;
a8a466
-		status = scsi_io_req->RaidContext.status;
a8a466
-		extStatus = scsi_io_req->RaidContext.exStatus;
a8a466
+		status = scsi_io_req->RaidContext.raid_context.status;
a8a466
+		extStatus = scsi_io_req->RaidContext.raid_context.exStatus;
a8a466
 
a8a466
 		switch (scsi_io_req->Function) {
a8a466
 		case MPI2_FUNCTION_SCSI_TASK_MGMT:
a8a466
@@ -2337,8 +2438,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
a8a466
 		case MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST: /* LD-IO Path */
a8a466
 			/* Map the FW Cmd Status */
a8a466
 			map_cmd_status(cmd_fusion, status, extStatus);
a8a466
-			scsi_io_req->RaidContext.status = 0;
a8a466
-			scsi_io_req->RaidContext.exStatus = 0;
a8a466
+			scsi_io_req->RaidContext.raid_context.status = 0;
a8a466
+			scsi_io_req->RaidContext.raid_context.exStatus = 0;
a8a466
 			if (megasas_cmd_type(scmd_local) == READ_WRITE_LDIO)
a8a466
 				atomic_dec(&instance->ldio_outstanding);
a8a466
 			megasas_return_cmd_fusion(instance, cmd_fusion);
a8a466
@@ -2901,7 +3002,7 @@ void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
a8a466
 				&& !(cmd_mfi->flags & DRV_DCMD_SKIP_REFIRE);
a8a466
 		if (refire_cmd)
a8a466
 			megasas_fire_cmd_fusion(instance, req_desc,
a8a466
-							instance->is_ventura);
a8a466
+				instance->is_ventura);
a8a466
 		else
a8a466
 			megasas_return_cmd(instance, cmd_mfi);
a8a466
 	}
a8a466
@@ -3390,7 +3491,7 @@ int megasas_check_mpio_paths(struct megasas_instance *instance,
a8a466
 /* Core fusion reset function */
a8a466
 int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
a8a466
 {
a8a466
-	int retval = SUCCESS, i, convert = 0;
a8a466
+	int retval = SUCCESS, i, j, convert = 0;
a8a466
 	struct megasas_instance *instance;
a8a466
 	struct megasas_cmd_fusion *cmd_fusion;
a8a466
 	struct fusion_context *fusion;
a8a466
@@ -3555,6 +3656,16 @@ transition_to_ready:
a8a466
 			shost_for_each_device(sdev, shost)
a8a466
 				megasas_update_sdev_properties(sdev);
a8a466
 
a8a466
+			/* reset stream detection array */
a8a466
+			if (instance->is_ventura) {
a8a466
+				for (j = 0; j < MAX_LOGICAL_DRIVES_EXT; ++j) {
a8a466
+					memset(fusion->stream_detect_by_ld[j],
a8a466
+					0, sizeof(struct LD_STREAM_DETECT));
a8a466
+				 fusion->stream_detect_by_ld[j]->mru_bit_map
a8a466
+						= MR_STREAM_BITMAP;
a8a466
+				}
a8a466
+			}
a8a466
+
a8a466
 			clear_bit(MEGASAS_FUSION_IN_RESET,
a8a466
 				  &instance->reset_flags);
a8a466
 			instance->instancet->enable_intr(instance);
a8a466
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
a8a466
index 3cd3d0a..d9cf496 100644
a8a466
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
a8a466
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
a8a466
@@ -133,12 +133,95 @@ struct RAID_CONTEXT {
a8a466
 	u8      resvd2;
a8a466
 };
a8a466
 
a8a466
+/*
a8a466
+ * Raid Context structure which describes ventura MegaRAID specific
a8a466
+ * IO Paramenters ,This resides at offset 0x60 where the SGL normally
a8a466
+ * starts in MPT IO Frames
a8a466
+ */
a8a466
+struct RAID_CONTEXT_G35 {
a8a466
+#if   defined(__BIG_ENDIAN_BITFIELD)
a8a466
+	u16	resvd0:8;
a8a466
+	u16	nseg:4;
a8a466
+	u16	type:4;
a8a466
+#else
a8a466
+	u16	type:4;		    /* 0x00 */
a8a466
+	u16	nseg:4;		    /* 0x00 */
a8a466
+	u16 resvd0:8;
a8a466
+#endif
a8a466
+	u16 timeout_value; /* 0x02 -0x03 */
a8a466
+	union {
a8a466
+		struct {
a8a466
+#if	defined(__BIG_ENDIAN_BITFIELD)
a8a466
+		u16	set_divert:4;
a8a466
+		u16	cpu_sel:4;
a8a466
+		u16	log:1;
a8a466
+		u16	rw:1;
a8a466
+		u16	sbs:1;
a8a466
+		u16	sqn:1;
a8a466
+		u16	fwn:1;
a8a466
+		u16	c2f:1;
a8a466
+		u16	sld:1;
a8a466
+		u16	reserved:1;
a8a466
+#else
a8a466
+		u16	reserved:1;
a8a466
+		u16	sld:1;
a8a466
+		u16	c2f:1;
a8a466
+		u16	fwn:1;
a8a466
+		u16	sqn:1;
a8a466
+		u16	sbs:1;
a8a466
+		u16	rw:1;
a8a466
+		u16	log:1;
a8a466
+		u16	cpu_sel:4;
a8a466
+		u16	set_divert:4;
a8a466
+#endif
a8a466
+			} bits;
a8a466
+		u16 s;
a8a466
+	} routing_flags;	/* 0x04 -0x05 routing flags */
a8a466
+	u16 virtual_disk_tgt_id;   /* 0x06 -0x07 */
a8a466
+	u64 reg_lock_row_lba;      /* 0x08 - 0x0F */
a8a466
+	u32 reg_lock_length;      /* 0x10 - 0x13 */
a8a466
+	union {
a8a466
+		u16 next_lmid; /* 0x14 - 0x15 */
a8a466
+		u16	peer_smid;	/* used for the raid 1/10 fp writes */
a8a466
+	} smid;
a8a466
+	u8 ex_status;       /* 0x16 : OUT */
a8a466
+	u8 status;          /* 0x17 status */
a8a466
+	u8 RAIDFlags;		/* 0x18 resvd[7:6], ioSubType[5:4],
a8a466
+				 * resvd[3:1], preferredCpu[0]
a8a466
+				 */
a8a466
+	u8 span_arm;            /* 0x1C span[7:5], arm[4:0] */
a8a466
+	u16	config_seq_num;           /* 0x1A -0x1B */
a8a466
+#if   defined(__BIG_ENDIAN_BITFIELD) /* 0x1C - 0x1D */
a8a466
+	u16 stream_detected:1;
a8a466
+	u16 reserved:3;
a8a466
+	u16 num_sge:12;
a8a466
+#else
a8a466
+	u16 num_sge:12;
a8a466
+	u16 reserved:3;
a8a466
+	u16 stream_detected:1;
a8a466
+#endif
a8a466
+	u8 resvd2[2];          /* 0x1E-0x1F */
a8a466
+};
a8a466
+
a8a466
+union RAID_CONTEXT_UNION {
a8a466
+	struct RAID_CONTEXT raid_context;
a8a466
+	struct RAID_CONTEXT_G35 raid_context_g35;
a8a466
+};
a8a466
+
a8a466
 #define RAID_CTX_SPANARM_ARM_SHIFT	(0)
a8a466
 #define RAID_CTX_SPANARM_ARM_MASK	(0x1f)
a8a466
 
a8a466
 #define RAID_CTX_SPANARM_SPAN_SHIFT	(5)
a8a466
 #define RAID_CTX_SPANARM_SPAN_MASK	(0xE0)
a8a466
 
a8a466
+/* number of bits per index in U32 TrackStream */
a8a466
+#define BITS_PER_INDEX_STREAM		4
a8a466
+#define INVALID_STREAM_NUM              16
a8a466
+#define MR_STREAM_BITMAP		0x76543210
a8a466
+#define STREAM_MASK			((1 << BITS_PER_INDEX_STREAM) - 1)
a8a466
+#define ZERO_LAST_STREAM		0x0fffffff
a8a466
+#define MAX_STREAMS_TRACKED		8
a8a466
+
a8a466
 /*
a8a466
  * define region lock types
a8a466
  */
a8a466
@@ -409,7 +492,7 @@ struct MPI2_RAID_SCSI_IO_REQUEST {
a8a466
 	u8                      LUN[8];                         /* 0x34 */
a8a466
 	__le32			Control;                        /* 0x3C */
a8a466
 	union MPI2_SCSI_IO_CDB_UNION  CDB;			/* 0x40 */
a8a466
-	struct RAID_CONTEXT	RaidContext;                    /* 0x60 */
a8a466
+	union RAID_CONTEXT_UNION RaidContext;  /* 0x60 */
a8a466
 	union MPI2_SGE_IO_UNION       SGL;			/* 0x80 */
a8a466
 };
a8a466
 
a8a466
@@ -656,11 +739,13 @@ struct MR_LD_RAID {
a8a466
 		u32     encryptionType:8;
a8a466
 		u32     pdPiMode:4;
a8a466
 		u32     ldPiMode:4;
a8a466
-		u32     reserved5:3;
a8a466
+		u32 reserved5:2;
a8a466
+		u32 ra_capable:1;
a8a466
 		u32     fpCapable:1;
a8a466
 #else
a8a466
 		u32     fpCapable:1;
a8a466
-		u32     reserved5:3;
a8a466
+		u32 ra_capable:1;
a8a466
+		u32 reserved5:2;
a8a466
 		u32     ldPiMode:4;
a8a466
 		u32     pdPiMode:4;
a8a466
 		u32     encryptionType:8;
a8a466
@@ -745,6 +830,7 @@ struct IO_REQUEST_INFO {
a8a466
 	u64 start_row;
a8a466
 	u8  span_arm;	/* span[7:5], arm[4:0] */
a8a466
 	u8  pd_after_lb;
a8a466
+	bool ra_capable;
a8a466
 };
a8a466
 
a8a466
 struct MR_LD_TARGET_SYNC {
a8a466
@@ -930,6 +1016,30 @@ struct MR_PD_CFG_SEQ_NUM_SYNC {
a8a466
 	struct MR_PD_CFG_SEQ seq[1];
a8a466
 } __packed;
a8a466
 
a8a466
+/* stream detection */
a8a466
+struct STREAM_DETECT {
a8a466
+	u64 next_seq_lba; /* next LBA to match sequential access */
a8a466
+	struct megasas_cmd_fusion *first_cmd_fusion; /* first cmd in group */
a8a466
+	struct megasas_cmd_fusion *last_cmd_fusion; /* last cmd in group */
a8a466
+	u32 count_cmds_in_stream; /* count of host commands in this stream */
a8a466
+	u16 num_sges_in_group; /* total number of SGEs in grouped IOs */
a8a466
+	u8 is_read; /* SCSI OpCode for this stream */
a8a466
+	u8 group_depth; /* total number of host commands in group */
a8a466
+	/* TRUE if cannot add any more commands to this group */
a8a466
+	bool group_flush;
a8a466
+	u8 reserved[7]; /* pad to 64-bit alignment */
a8a466
+};
a8a466
+
a8a466
+struct LD_STREAM_DETECT {
a8a466
+	bool write_back; /* TRUE if WB, FALSE if WT */
a8a466
+	bool fp_write_enabled;
a8a466
+	bool members_ssds;
a8a466
+	bool fp_cache_bypass_capable;
a8a466
+	u32 mru_bit_map; /* bitmap used to track MRU and LRU stream indicies */
a8a466
+	/* this is the array of stream detect structures (one per stream) */
a8a466
+	struct STREAM_DETECT stream_track[MAX_STREAMS_TRACKED];
a8a466
+};
a8a466
+
a8a466
 struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY {
a8a466
 	u64 RDPQBaseAddress;
a8a466
 	u32 Reserved1;
a8a466
@@ -983,6 +1093,7 @@ struct fusion_context {
a8a466
 	struct LD_LOAD_BALANCE_INFO load_balance_info[MAX_LOGICAL_DRIVES_EXT];
a8a466
 	LD_SPAN_INFO log_to_span[MAX_LOGICAL_DRIVES_EXT];
a8a466
 	u8 adapter_type;
a8a466
+	struct LD_STREAM_DETECT **stream_detect_by_ld;
a8a466
 };
a8a466
 
a8a466
 union desc_value {
a8a466
-- 
a8a466
1.8.3.1
a8a466