b312fc
From 9fb69ac5aa175b55ba7d48596a3929e3206cbd4b Mon Sep 17 00:00:00 2001
b312fc
From: Sasikumar Chandrasekaran <sasikumar.pc@broadcom.com>
b312fc
Date: Tue, 10 Jan 2017 18:20:47 -0500
b312fc
Subject: [PATCH 05/11] scsi: megaraid_sas: SAS3.5 Generic Megaraid Controllers
b312fc
 Fast Path for RAID 1/10 Writes
b312fc
b312fc
To improve RAID 1/10 Write performance, OS drivers need to issue the
b312fc
required Write IOs as Fast Path IOs (after the appropriate checks
b312fc
allowing Fast Path to be used) to the appropriate physical drives
b312fc
(translated from the OS logical IO) and wait for all Write IOs to complete.
b312fc
b312fc
Design: A write IO on RAID volume will be examined if it can be sent in
b312fc
Fast Path based on IO size and starting LBA and ending LBA falling on to
b312fc
a Physical Drive boundary. If the underlying RAID volume is a RAID 1/10,
b312fc
driver issues two fast path write IOs one for each corresponding physical
b312fc
drive after computing the corresponding start LBA for each physical drive.
b312fc
Both write IOs will have the same payload and are posted to HW such that
b312fc
replies land in the same reply queue.
b312fc
b312fc
If there are no resources available for sending two IOs, driver will send
b312fc
the original IO from SCSI layer to RAID volume through the Firmware.
b312fc
b312fc
Based on PCI bandwidth and write payload, every second this feature is
b312fc
enabled/disabled.
b312fc
b312fc
When both IOs are completed by HW, the resources will be released
b312fc
and SCSI IO completion handler will be called.
b312fc
b312fc
Signed-off-by: Sasikumar Chandrasekaran <sasikumar.pc@broadcom.com>
b312fc
Reviewed-by: Tomas Henzl <thenzl@redhat.com>
b312fc
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
b312fc
---
b312fc
 drivers/scsi/megaraid/megaraid_sas.h        |   1 +
b312fc
 drivers/scsi/megaraid/megaraid_sas_fp.c     |  31 ++-
b312fc
 drivers/scsi/megaraid/megaraid_sas_fusion.c | 335 ++++++++++++++++++++++++----
b312fc
 drivers/scsi/megaraid/megaraid_sas_fusion.h |  15 +-
b312fc
 4 files changed, 329 insertions(+), 53 deletions(-)
b312fc
b312fc
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
b312fc
index f387b32..0b4d37b 100644
b312fc
--- a/drivers/scsi/megaraid/megaraid_sas.h
b312fc
+++ b/drivers/scsi/megaraid/megaraid_sas.h
b312fc
@@ -2056,6 +2056,7 @@ struct megasas_instance {
b312fc
 
b312fc
 	u16 max_num_sge;
b312fc
 	u16 max_fw_cmds;
b312fc
+	u16 max_mpt_cmds;
b312fc
 	u16 max_mfi_cmds;
b312fc
 	u16 max_scsi_cmds;
b312fc
 	u16 ldio_threshold;
b312fc
diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c
b312fc
index fe5b074..3644dbc 100644
b312fc
--- a/drivers/scsi/megaraid/megaraid_sas_fp.c
b312fc
+++ b/drivers/scsi/megaraid/megaraid_sas_fp.c
b312fc
@@ -737,7 +737,7 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld,
b312fc
 		struct MR_DRV_RAID_MAP_ALL *map)
b312fc
 {
b312fc
 	struct MR_LD_RAID  *raid = MR_LdRaidGet(ld, map);
b312fc
-	u32     pd, arRef;
b312fc
+	u32     pd, arRef, r1_alt_pd;
b312fc
 	u8      physArm, span;
b312fc
 	u64     row;
b312fc
 	u8	retval = TRUE;
b312fc
@@ -772,9 +772,16 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld,
b312fc
 	arRef       = MR_LdSpanArrayGet(ld, span, map);
b312fc
 	pd          = MR_ArPdGet(arRef, physArm, map);
b312fc
 
b312fc
-	if (pd != MR_PD_INVALID)
b312fc
+	if (pd != MR_PD_INVALID) {
b312fc
 		*pDevHandle = MR_PdDevHandleGet(pd, map);
b312fc
-	else {
b312fc
+		/* get second pd also for raid 1/10 fast path writes*/
b312fc
+		if (raid->level == 1) {
b312fc
+			r1_alt_pd = MR_ArPdGet(arRef, physArm + 1, map);
b312fc
+			if (r1_alt_pd != MR_PD_INVALID)
b312fc
+				io_info->r1_alt_dev_handle =
b312fc
+				MR_PdDevHandleGet(r1_alt_pd, map);
b312fc
+		}
b312fc
+	} else {
b312fc
 		*pDevHandle = cpu_to_le16(MR_PD_INVALID);
b312fc
 		if ((raid->level >= 5) &&
b312fc
 			((fusion->adapter_type == THUNDERBOLT_SERIES)  ||
b312fc
@@ -818,7 +825,7 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow,
b312fc
 		struct MR_DRV_RAID_MAP_ALL *map)
b312fc
 {
b312fc
 	struct MR_LD_RAID  *raid = MR_LdRaidGet(ld, map);
b312fc
-	u32         pd, arRef;
b312fc
+	u32         pd, arRef, r1_alt_pd;
b312fc
 	u8          physArm, span;
b312fc
 	u64         row;
b312fc
 	u8	    retval = TRUE;
b312fc
@@ -866,10 +873,17 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow,
b312fc
 	arRef       = MR_LdSpanArrayGet(ld, span, map);
b312fc
 	pd          = MR_ArPdGet(arRef, physArm, map); /* Get the pd */
b312fc
 
b312fc
-	if (pd != MR_PD_INVALID)
b312fc
+	if (pd != MR_PD_INVALID) {
b312fc
 		/* Get dev handle from Pd. */
b312fc
 		*pDevHandle = MR_PdDevHandleGet(pd, map);
b312fc
-	else {
b312fc
+		/* get second pd also for raid 1/10 fast path writes*/
b312fc
+		if (raid->level == 1) {
b312fc
+			r1_alt_pd = MR_ArPdGet(arRef, physArm + 1, map);
b312fc
+			if (r1_alt_pd != MR_PD_INVALID)
b312fc
+				io_info->r1_alt_dev_handle =
b312fc
+				MR_PdDevHandleGet(r1_alt_pd, map);
b312fc
+		}
b312fc
+	} else {
b312fc
 		/* set dev handle as invalid. */
b312fc
 		*pDevHandle = cpu_to_le16(MR_PD_INVALID);
b312fc
 		if ((raid->level >= 5) &&
b312fc
@@ -1124,6 +1138,11 @@ MR_BuildRaidContext(struct megasas_instance *instance,
b312fc
 		/* If IO on an invalid Pd, then FP is not possible.*/
b312fc
 		if (io_info->devHandle == cpu_to_le16(MR_PD_INVALID))
b312fc
 			io_info->fpOkForIo = FALSE;
b312fc
+		/* set raid 1/10 fast path write capable bit in io_info */
b312fc
+		if (io_info->fpOkForIo &&
b312fc
+		    (io_info->r1_alt_dev_handle != MR_PD_INVALID) &&
b312fc
+		    (raid->level == 1) && !isRead)
b312fc
+			io_info->is_raid_1_fp_write = 1;
b312fc
 		return retval;
b312fc
 	} else if (isRead) {
b312fc
 		uint stripIdx;
b312fc
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
b312fc
index 946f7c0..b146cd1 100644
b312fc
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
b312fc
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
b312fc
@@ -270,7 +270,8 @@ megasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_c
b312fc
 		instance->ldio_threshold = ldio_threshold;
b312fc
 
b312fc
 		if (!instance->is_rdpq)
b312fc
-			instance->max_fw_cmds = min_t(u16, instance->max_fw_cmds, 1024);
b312fc
+			instance->max_fw_cmds =
b312fc
+				min_t(u16, instance->max_fw_cmds, 1024);
b312fc
 
b312fc
 		if (reset_devices)
b312fc
 			instance->max_fw_cmds = min(instance->max_fw_cmds,
b312fc
@@ -286,7 +287,14 @@ megasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_c
b312fc
 				(MEGASAS_FUSION_INTERNAL_CMDS +
b312fc
 				MEGASAS_FUSION_IOCTL_CMDS);
b312fc
 		instance->cur_can_queue = instance->max_scsi_cmds;
b312fc
+		instance->host->can_queue = instance->cur_can_queue;
b312fc
 	}
b312fc
+
b312fc
+	if (instance->is_ventura)
b312fc
+		instance->max_mpt_cmds =
b312fc
+		instance->max_fw_cmds * RAID_1_10_RMW_CMDS;
b312fc
+	else
b312fc
+		instance->max_mpt_cmds = instance->max_fw_cmds;
b312fc
 }
b312fc
 /**
b312fc
  * megasas_free_cmds_fusion -	Free all the cmds in the free cmd pool
b312fc
@@ -300,7 +308,7 @@ megasas_free_cmds_fusion(struct megasas_instance *instance)
b312fc
 	struct megasas_cmd_fusion *cmd;
b312fc
 
b312fc
 	/* SG, Sense */
b312fc
-	for (i = 0; i < instance->max_fw_cmds; i++) {
b312fc
+	for (i = 0; i < instance->max_mpt_cmds; i++) {
b312fc
 		cmd = fusion->cmd_list[i];
b312fc
 		if (cmd) {
b312fc
 			if (cmd->sg_frame)
b312fc
@@ -344,7 +352,7 @@ megasas_free_cmds_fusion(struct megasas_instance *instance)
b312fc
 
b312fc
 
b312fc
 	/* cmd_list */
b312fc
-	for (i = 0; i < instance->max_fw_cmds; i++)
b312fc
+	for (i = 0; i < instance->max_mpt_cmds; i++)
b312fc
 		kfree(fusion->cmd_list[i]);
b312fc
 
b312fc
 	kfree(fusion->cmd_list);
b312fc
@@ -396,33 +404,49 @@ static int megasas_create_sg_sense_fusion(struct megasas_instance *instance)
b312fc
 			return -ENOMEM;
b312fc
 		}
b312fc
 	}
b312fc
+
b312fc
+	/* create sense buffer for the raid 1/10 fp */
b312fc
+	for (i = max_cmd; i < instance->max_mpt_cmds; i++) {
b312fc
+		cmd = fusion->cmd_list[i];
b312fc
+		cmd->sense = pci_pool_alloc(fusion->sense_dma_pool,
b312fc
+			GFP_KERNEL, &cmd->sense_phys_addr);
b312fc
+		if (!cmd->sense) {
b312fc
+			dev_err(&instance->pdev->dev,
b312fc
+				"Failed from %s %d\n",  __func__, __LINE__);
b312fc
+			return -ENOMEM;
b312fc
+		}
b312fc
+	}
b312fc
+
b312fc
 	return 0;
b312fc
 }
b312fc
 
b312fc
 int
b312fc
 megasas_alloc_cmdlist_fusion(struct megasas_instance *instance)
b312fc
 {
b312fc
-	u32 max_cmd, i;
b312fc
+	u32 max_mpt_cmd, i;
b312fc
 	struct fusion_context *fusion;
b312fc
 
b312fc
 	fusion = instance->ctrl_context;
b312fc
 
b312fc
-	max_cmd = instance->max_fw_cmds;
b312fc
+	max_mpt_cmd = instance->max_mpt_cmds;
b312fc
 
b312fc
 	/*
b312fc
 	 * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers.
b312fc
 	 * Allocate the dynamic array first and then allocate individual
b312fc
 	 * commands.
b312fc
 	 */
b312fc
-	fusion->cmd_list = kzalloc(sizeof(struct megasas_cmd_fusion *) * max_cmd,
b312fc
-						GFP_KERNEL);
b312fc
+	fusion->cmd_list =
b312fc
+		kzalloc(sizeof(struct megasas_cmd_fusion *) * max_mpt_cmd,
b312fc
+			GFP_KERNEL);
b312fc
 	if (!fusion->cmd_list) {
b312fc
 		dev_err(&instance->pdev->dev,
b312fc
 			"Failed from %s %d\n",  __func__, __LINE__);
b312fc
 		return -ENOMEM;
b312fc
 	}
b312fc
 
b312fc
-	for (i = 0; i < max_cmd; i++) {
b312fc
+
b312fc
+
b312fc
+	for (i = 0; i < max_mpt_cmd; i++) {
b312fc
 		fusion->cmd_list[i] = kzalloc(sizeof(struct megasas_cmd_fusion),
b312fc
 					      GFP_KERNEL);
b312fc
 		if (!fusion->cmd_list[i]) {
b312fc
@@ -657,13 +681,14 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance)
b312fc
 	 */
b312fc
 
b312fc
 	/* SMID 0 is reserved. Set SMID/index from 1 */
b312fc
-	for (i = 0; i < instance->max_fw_cmds; i++) {
b312fc
+	for (i = 0; i < instance->max_mpt_cmds; i++) {
b312fc
 		cmd = fusion->cmd_list[i];
b312fc
 		offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i;
b312fc
 		memset(cmd, 0, sizeof(struct megasas_cmd_fusion));
b312fc
 		cmd->index = i + 1;
b312fc
 		cmd->scmd = NULL;
b312fc
-		cmd->sync_cmd_idx = (i >= instance->max_scsi_cmds) ?
b312fc
+		cmd->sync_cmd_idx =
b312fc
+		(i >= instance->max_scsi_cmds && i < instance->max_fw_cmds) ?
b312fc
 				(i - instance->max_scsi_cmds) :
b312fc
 				(u32)ULONG_MAX; /* Set to Invalid */
b312fc
 		cmd->instance = instance;
b312fc
@@ -673,6 +698,7 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance)
b312fc
 		memset(cmd->io_request, 0,
b312fc
 		       sizeof(struct MPI2_RAID_SCSI_IO_REQUEST));
b312fc
 		cmd->io_request_phys_addr = io_req_base_phys + offset;
b312fc
+		cmd->is_raid_1_fp_write = 0;
b312fc
 	}
b312fc
 
b312fc
 	if (megasas_create_sg_sense_fusion(instance))
b312fc
@@ -1262,12 +1288,12 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
b312fc
 	fusion->reply_q_depth = 2 * (((max_cmd + 1 + 15)/16)*16);
b312fc
 
b312fc
 	fusion->request_alloc_sz =
b312fc
-		sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) *max_cmd;
b312fc
+	sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) * instance->max_mpt_cmds;
b312fc
 	fusion->reply_alloc_sz = sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)
b312fc
 		*(fusion->reply_q_depth);
b312fc
 	fusion->io_frames_alloc_sz = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE +
b312fc
-		(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE *
b312fc
-		 (max_cmd + 1)); /* Extra 1 for SMID 0 */
b312fc
+		(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE
b312fc
+		* (instance->max_mpt_cmds + 1)); /* Extra 1 for SMID 0 */
b312fc
 
b312fc
 	scratch_pad_2 = readl(&instance->reg_set->outbound_scratch_pad_2);
b312fc
 	/* If scratch_pad_2 & MEGASAS_MAX_CHAIN_SIZE_UNITS_MASK is set,
b312fc
@@ -1403,42 +1429,43 @@ fail_alloc_mfi_cmds:
b312fc
  */
b312fc
 
b312fc
 void
b312fc
-map_cmd_status(struct megasas_cmd_fusion *cmd, u8 status, u8 ext_status)
b312fc
+map_cmd_status(struct fusion_context *fusion,
b312fc
+	struct scsi_cmnd *scmd, u8 status, u8 ext_status,
b312fc
+			u32 data_length, u8 *sense)
b312fc
 {
b312fc
 
b312fc
 	switch (status) {
b312fc
 
b312fc
 	case MFI_STAT_OK:
b312fc
-		cmd->scmd->result = DID_OK << 16;
b312fc
+		scmd->result = DID_OK << 16;
b312fc
 		break;
b312fc
 
b312fc
 	case MFI_STAT_SCSI_IO_FAILED:
b312fc
 	case MFI_STAT_LD_INIT_IN_PROGRESS:
b312fc
-		cmd->scmd->result = (DID_ERROR << 16) | ext_status;
b312fc
+		scmd->result = (DID_ERROR << 16) | ext_status;
b312fc
 		break;
b312fc
 
b312fc
 	case MFI_STAT_SCSI_DONE_WITH_ERROR:
b312fc
 
b312fc
-		cmd->scmd->result = (DID_OK << 16) | ext_status;
b312fc
+		scmd->result = (DID_OK << 16) | ext_status;
b312fc
 		if (ext_status == SAM_STAT_CHECK_CONDITION) {
b312fc
-			memset(cmd->scmd->sense_buffer, 0,
b312fc
+			memset(scmd->sense_buffer, 0,
b312fc
 			       SCSI_SENSE_BUFFERSIZE);
b312fc
-			memcpy(cmd->scmd->sense_buffer, cmd->sense,
b312fc
+			memcpy(scmd->sense_buffer, sense,
b312fc
 			       SCSI_SENSE_BUFFERSIZE);
b312fc
-			cmd->scmd->result |= DRIVER_SENSE << 24;
b312fc
+			scmd->result |= DRIVER_SENSE << 24;
b312fc
 		}
b312fc
 		break;
b312fc
 
b312fc
 	case MFI_STAT_LD_OFFLINE:
b312fc
 	case MFI_STAT_DEVICE_NOT_FOUND:
b312fc
-		cmd->scmd->result = DID_BAD_TARGET << 16;
b312fc
+		scmd->result = DID_BAD_TARGET << 16;
b312fc
 		break;
b312fc
 	case MFI_STAT_CONFIG_SEQ_MISMATCH:
b312fc
-		cmd->scmd->result = DID_IMM_RETRY << 16;
b312fc
+		scmd->result = DID_IMM_RETRY << 16;
b312fc
 		break;
b312fc
 	default:
b312fc
-		dev_printk(KERN_DEBUG, &cmd->instance->pdev->dev, "FW status %#x\n", status);
b312fc
-		cmd->scmd->result = DID_ERROR << 16;
b312fc
+		scmd->result = DID_ERROR << 16;
b312fc
 		break;
b312fc
 	}
b312fc
 }
b312fc
@@ -1881,6 +1908,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
b312fc
 	io_info.ldStartBlock = ((u64)start_lba_hi << 32) | start_lba_lo;
b312fc
 	io_info.numBlocks = datalength;
b312fc
 	io_info.ldTgtId = device_id;
b312fc
+	io_info.r1_alt_dev_handle = MR_PD_INVALID;
b312fc
 	io_request->DataLength = cpu_to_le32(scsi_bufflen(scp));
b312fc
 
b312fc
 	if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
b312fc
@@ -1949,6 +1977,10 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
b312fc
 		} else
b312fc
 			scp->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG;
b312fc
 
b312fc
+		cmd->is_raid_1_fp_write = io_info.is_raid_1_fp_write;
b312fc
+		if (io_info.is_raid_1_fp_write)
b312fc
+			cmd->r1_alt_dev_handle = io_info.r1_alt_dev_handle;
b312fc
+
b312fc
 		if ((raidLUN[0] == 1) &&
b312fc
 			(local_map_ptr->raidMap.devHndlInfo[io_info.pd_after_lb].validHandles > 1)) {
b312fc
 			instance->dev_handle = !(instance->dev_handle);
b312fc
@@ -2272,19 +2304,118 @@ megasas_get_request_descriptor(struct megasas_instance *instance, u16 index)
b312fc
 	u8 *p;
b312fc
 	struct fusion_context *fusion;
b312fc
 
b312fc
-	if (index >= instance->max_fw_cmds) {
b312fc
+	if (index >= instance->max_mpt_cmds) {
b312fc
 		dev_err(&instance->pdev->dev, "Invalid SMID (0x%x)request for "
b312fc
 		       "descriptor for scsi%d\n", index,
b312fc
 			instance->host->host_no);
b312fc
 		return NULL;
b312fc
 	}
b312fc
 	fusion = instance->ctrl_context;
b312fc
-	p = fusion->req_frames_desc
b312fc
-		+sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) *index;
b312fc
+	p = fusion->req_frames_desc +
b312fc
+		sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) * index;
b312fc
 
b312fc
 	return (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)p;
b312fc
 }
b312fc
 
b312fc
+/*
b312fc
+ * megasas_fpio_to_ldio-
b312fc
+ * This function converts an fp io to ldio
b312fc
+ */
b312fc
+
b312fc
+void megasas_fpio_to_ldio(struct megasas_instance *instance,
b312fc
+	struct megasas_cmd_fusion *cmd, struct scsi_cmnd *scmd)
b312fc
+{
b312fc
+	struct fusion_context *fusion;
b312fc
+
b312fc
+	fusion = instance->ctrl_context;
b312fc
+	cmd->request_desc->SCSIIO.RequestFlags =
b312fc
+		(MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO
b312fc
+		<< MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
b312fc
+	cmd->io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
b312fc
+	cmd->io_request->DevHandle = cpu_to_le16(MEGASAS_DEV_INDEX(scmd));
b312fc
+
b312fc
+	/*remove FAST PATH ENABLE bit in IoFlags */
b312fc
+	cmd->io_request->IoFlags &=
b312fc
+	cpu_to_le16(~MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
b312fc
+
b312fc
+	/* if the numSGE > max_sge_in_main_sge set the chain offset*/
b312fc
+	if (cmd->io_request->RaidContext.raid_context_g35.num_sge >
b312fc
+		fusion->max_sge_in_main_msg)
b312fc
+		cmd->io_request->ChainOffset = fusion->chain_offset_io_request;
b312fc
+	memcpy(cmd->io_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
b312fc
+	cmd->io_request->CDB.EEDP32.PrimaryReferenceTag = 0;
b312fc
+	cmd->io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0;
b312fc
+	cmd->io_request->EEDPFlags = 0;
b312fc
+	cmd->io_request->Control = 0;
b312fc
+	cmd->io_request->EEDPBlockSize = 0;
b312fc
+	cmd->is_raid_1_fp_write = 0;
b312fc
+}
b312fc
+
b312fc
+/* megasas_prepate_secondRaid1_IO
b312fc
+ *  It prepares the raid 1 second IO
b312fc
+ */
b312fc
+void megasas_prepare_secondRaid1_IO(struct megasas_instance *instance,
b312fc
+			    struct megasas_cmd_fusion *cmd,
b312fc
+			    struct megasas_cmd_fusion *r1_cmd)
b312fc
+{
b312fc
+	union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc, *req_desc2 = NULL;
b312fc
+	struct fusion_context *fusion;
b312fc
+
b312fc
+	fusion = instance->ctrl_context;
b312fc
+	req_desc = cmd->request_desc;
b312fc
+	if (r1_cmd) {
b312fc
+		/* copy the io request frame as well
b312fc
+		 *  as 8 SGEs data for r1 command
b312fc
+		 */
b312fc
+		memcpy(r1_cmd->io_request, cmd->io_request,
b312fc
+			sizeof(struct MPI2_RAID_SCSI_IO_REQUEST));
b312fc
+		memcpy(&r1_cmd->io_request->SGL, &cmd->io_request->SGL,
b312fc
+				(fusion->max_sge_in_main_msg *
b312fc
+				sizeof(union MPI2_SGE_IO_UNION)));
b312fc
+		/*sense buffer is different for r1 command*/
b312fc
+		r1_cmd->io_request->SenseBufferLowAddress =
b312fc
+				cpu_to_le32(r1_cmd->sense_phys_addr);
b312fc
+		r1_cmd->scmd = cmd->scmd;
b312fc
+		req_desc2 =
b312fc
+		megasas_get_request_descriptor(instance, r1_cmd->index-1);
b312fc
+		if (req_desc2) {
b312fc
+			req_desc2->Words = 0;
b312fc
+			r1_cmd->request_desc = req_desc2;
b312fc
+			req_desc2->SCSIIO.SMID =
b312fc
+				cpu_to_le16(r1_cmd->index);
b312fc
+			req_desc2->SCSIIO.RequestFlags =
b312fc
+				req_desc->SCSIIO.RequestFlags;
b312fc
+			r1_cmd->is_raid_1_fp_write = 1;
b312fc
+			r1_cmd->request_desc->SCSIIO.DevHandle =
b312fc
+				cmd->r1_alt_dev_handle;
b312fc
+			r1_cmd->io_request->DevHandle = cmd->r1_alt_dev_handle;
b312fc
+			cmd->io_request->RaidContext.raid_context_g35.smid.peer_smid =
b312fc
+				 cpu_to_le16(r1_cmd->index);
b312fc
+			r1_cmd->io_request->RaidContext.raid_context_g35.smid.peer_smid =
b312fc
+				cpu_to_le16(cmd->index);
b312fc
+			/* MSIxIndex of both commands request
b312fc
+			 * descriptors should be same
b312fc
+			 */
b312fc
+			r1_cmd->request_desc->SCSIIO.MSIxIndex =
b312fc
+				cmd->request_desc->SCSIIO.MSIxIndex;
b312fc
+			/*span arm is different for r1 cmd*/
b312fc
+			r1_cmd->io_request->RaidContext.raid_context_g35.span_arm =
b312fc
+			cmd->io_request->RaidContext.raid_context_g35.span_arm + 1;
b312fc
+		} else {
b312fc
+			megasas_return_cmd_fusion(instance, r1_cmd);
b312fc
+			dev_info(&instance->pdev->dev,
b312fc
+				"unable to get request descriptor, firing as normal IO\n");
b312fc
+			atomic_dec(&instance->fw_outstanding);
b312fc
+			megasas_fpio_to_ldio(instance, cmd, cmd->scmd);
b312fc
+		}
b312fc
+	} else {
b312fc
+		dev_info(&instance->pdev->dev,
b312fc
+			"unable to get command, firing as normal IO\n");
b312fc
+		atomic_dec(&instance->fw_outstanding);
b312fc
+		megasas_fpio_to_ldio(instance, cmd, cmd->scmd);
b312fc
+	}
b312fc
+}
b312fc
+
b312fc
 /**
b312fc
  * megasas_build_and_issue_cmd_fusion -Main routine for building and
b312fc
  *                                     issuing non IOCTL cmd
b312fc
@@ -2295,7 +2426,7 @@ static u32
b312fc
 megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
b312fc
 				   struct scsi_cmnd *scmd)
b312fc
 {
b312fc
-	struct megasas_cmd_fusion *cmd;
b312fc
+	struct megasas_cmd_fusion *cmd, *r1_cmd = NULL;
b312fc
 	union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
b312fc
 	u32 index;
b312fc
 	struct fusion_context *fusion;
b312fc
@@ -2310,13 +2441,27 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
b312fc
 		return SCSI_MLQUEUE_DEVICE_BUSY;
b312fc
 	}
b312fc
 
b312fc
+	if (atomic_inc_return(&instance->fw_outstanding) >
b312fc
+			instance->host->can_queue) {
b312fc
+		dev_err(&instance->pdev->dev, "Throttle IOs beyond Controller queue depth\n");
b312fc
+		atomic_dec(&instance->fw_outstanding);
b312fc
+		return SCSI_MLQUEUE_HOST_BUSY;
b312fc
+	}
b312fc
+
b312fc
 	cmd = megasas_get_cmd_fusion(instance, scmd->request->tag);
b312fc
 
b312fc
+	if (!cmd) {
b312fc
+		atomic_dec(&instance->fw_outstanding);
b312fc
+		return SCSI_MLQUEUE_HOST_BUSY;
b312fc
+	}
b312fc
+
b312fc
 	index = cmd->index;
b312fc
 
b312fc
 	req_desc = megasas_get_request_descriptor(instance, index-1);
b312fc
-	if (!req_desc)
b312fc
+	if (!req_desc) {
b312fc
+		atomic_dec(&instance->fw_outstanding);
b312fc
 		return SCSI_MLQUEUE_HOST_BUSY;
b312fc
+	}
b312fc
 
b312fc
 	req_desc->Words = 0;
b312fc
 	cmd->request_desc = req_desc;
b312fc
@@ -2325,6 +2470,7 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
b312fc
 		megasas_return_cmd_fusion(instance, cmd);
b312fc
 		dev_err(&instance->pdev->dev, "Error building command\n");
b312fc
 		cmd->request_desc = NULL;
b312fc
+		atomic_dec(&instance->fw_outstanding);
b312fc
 		return SCSI_MLQUEUE_HOST_BUSY;
b312fc
 	}
b312fc
 
b312fc
@@ -2335,14 +2481,39 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
b312fc
 	    cmd->io_request->ChainOffset != 0xF)
b312fc
 		dev_err(&instance->pdev->dev, "The chain offset value is not "
b312fc
 		       "correct : %x\n", cmd->io_request->ChainOffset);
b312fc
+	/*
b312fc
+	 *	if it is raid 1/10 fp write capable.
b312fc
+	 *	try to get second command from pool and construct it.
b312fc
+	 *	From FW, it has confirmed that lba values of two PDs
b312fc
+	 *	corresponds to single R1/10 LD are always same
b312fc
+	 *
b312fc
+	 */
b312fc
+	/*	driver side count always should be less than max_fw_cmds
b312fc
+	 *	to get new command
b312fc
+	 */
b312fc
+	if (cmd->is_raid_1_fp_write &&
b312fc
+		atomic_inc_return(&instance->fw_outstanding) >
b312fc
+			(instance->host->can_queue)) {
b312fc
+		megasas_fpio_to_ldio(instance, cmd, cmd->scmd);
b312fc
+		atomic_dec(&instance->fw_outstanding);
b312fc
+	} else if (cmd->is_raid_1_fp_write) {
b312fc
+		r1_cmd = megasas_get_cmd_fusion(instance,
b312fc
+				(scmd->request->tag + instance->max_fw_cmds));
b312fc
+		megasas_prepare_secondRaid1_IO(instance, cmd, r1_cmd);
b312fc
+	}
b312fc
+
b312fc
 
b312fc
 	/*
b312fc
 	 * Issue the command to the FW
b312fc
 	 */
b312fc
-	atomic_inc(&instance->fw_outstanding);
b312fc
 
b312fc
 	megasas_fire_cmd_fusion(instance, req_desc, instance->is_ventura);
b312fc
 
b312fc
+	if (r1_cmd)
b312fc
+		megasas_fire_cmd_fusion(instance, r1_cmd->request_desc,
b312fc
+				instance->is_ventura);
b312fc
+
b312fc
+
b312fc
 	return 0;
b312fc
 }
b312fc
 
b312fc
@@ -2359,10 +2530,10 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
b312fc
 	struct MPI2_RAID_SCSI_IO_REQUEST *scsi_io_req;
b312fc
 	struct fusion_context *fusion;
b312fc
 	struct megasas_cmd *cmd_mfi;
b312fc
-	struct megasas_cmd_fusion *cmd_fusion;
b312fc
+	struct megasas_cmd_fusion *cmd_fusion, *r1_cmd = NULL;
b312fc
 	u16 smid, num_completed;
b312fc
-	u8 reply_descript_type;
b312fc
-	u32 status, extStatus, device_id;
b312fc
+	u8 reply_descript_type, *sense;
b312fc
+	u32 status, extStatus, device_id, data_length;
b312fc
 	union desc_value d_val;
b312fc
 	struct LD_LOAD_BALANCE_INFO *lbinfo;
b312fc
 	int threshold_reply_count = 0;
b312fc
@@ -2392,6 +2563,15 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
b312fc
 
b312fc
 	while (d_val.u.low != cpu_to_le32(UINT_MAX) &&
b312fc
 	       d_val.u.high != cpu_to_le32(UINT_MAX)) {
b312fc
+		   /*
b312fc
+		    * Ensure that the peer command is NULL here in case a
b312fc
+		    * command has completed but the R1 FP Write peer has
b312fc
+		    * not completed yet.If not null, it's possible that
b312fc
+		    * another thread will complete the peer
b312fc
+		    * command and should not.
b312fc
+		    */
b312fc
+		r1_cmd = NULL;
b312fc
+
b312fc
 		smid = le16_to_cpu(reply_desc->SMID);
b312fc
 
b312fc
 		cmd_fusion = fusion->cmd_list[smid - 1];
b312fc
@@ -2406,6 +2586,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
b312fc
 		scmd_local = cmd_fusion->scmd;
b312fc
 		status = scsi_io_req->RaidContext.raid_context.status;
b312fc
 		extStatus = scsi_io_req->RaidContext.raid_context.exStatus;
b312fc
+		sense = cmd_fusion->sense;
b312fc
+		data_length = scsi_io_req->DataLength;
b312fc
 
b312fc
 		switch (scsi_io_req->Function) {
b312fc
 		case MPI2_FUNCTION_SCSI_TASK_MGMT:
b312fc
@@ -2422,12 +2604,28 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
b312fc
 			/* Update load balancing info */
b312fc
 			device_id = MEGASAS_DEV_INDEX(scmd_local);
b312fc
 			lbinfo = &fusion->load_balance_info[device_id];
b312fc
-			if (cmd_fusion->scmd->SCp.Status &
b312fc
-			    MEGASAS_LOAD_BALANCE_FLAG) {
b312fc
+			/*
b312fc
+			 * check for the raid 1/10 fast path writes
b312fc
+			 */
b312fc
+			if (!cmd_fusion->is_raid_1_fp_write &&
b312fc
+				(cmd_fusion->scmd->SCp.Status &
b312fc
+					MEGASAS_LOAD_BALANCE_FLAG)) {
b312fc
 				atomic_dec(&lbinfo->scsi_pending_cmds[cmd_fusion->pd_r1_lb]);
b312fc
 				cmd_fusion->scmd->SCp.Status &=
b312fc
 					~MEGASAS_LOAD_BALANCE_FLAG;
b312fc
+			} else if (cmd_fusion->is_raid_1_fp_write) {
b312fc
+				/* get peer command */
b312fc
+				if (cmd_fusion->index < instance->max_fw_cmds)
b312fc
+					r1_cmd = fusion->cmd_list[(cmd_fusion->index +
b312fc
+					instance->max_fw_cmds)-1];
b312fc
+				else {
b312fc
+					r1_cmd =
b312fc
+					fusion->cmd_list[(cmd_fusion->index -
b312fc
+						 instance->max_fw_cmds)-1];
b312fc
+				}
b312fc
+				cmd_fusion->cmd_completed = true;
b312fc
 			}
b312fc
+
b312fc
 			if (reply_descript_type ==
b312fc
 			    MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS) {
b312fc
 				if (megasas_dbg_lvl == 5)
b312fc
@@ -2437,14 +2635,48 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
b312fc
 			/* Fall thru and complete IO */
b312fc
 		case MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST: /* LD-IO Path */
b312fc
 			/* Map the FW Cmd Status */
b312fc
-			map_cmd_status(cmd_fusion, status, extStatus);
b312fc
-			scsi_io_req->RaidContext.raid_context.status = 0;
b312fc
-			scsi_io_req->RaidContext.raid_context.exStatus = 0;
b312fc
-			if (megasas_cmd_type(scmd_local) == READ_WRITE_LDIO)
b312fc
-				atomic_dec(&instance->ldio_outstanding);
b312fc
-			megasas_return_cmd_fusion(instance, cmd_fusion);
b312fc
-			scsi_dma_unmap(scmd_local);
b312fc
-			scmd_local->scsi_done(scmd_local);
b312fc
+			/*
b312fc
+			 * check for the raid 1/10 fast path writes
b312fc
+			 */
b312fc
+			if (r1_cmd &&  r1_cmd->is_raid_1_fp_write
b312fc
+				&& r1_cmd->cmd_completed) {
b312fc
+				/*
b312fc
+				 * if the peer  Raid  1/10 fast path failed,
b312fc
+				 * mark IO as failed to the scsi layer.
b312fc
+				 * over write the current status by the failed
b312fc
+				 * status makes sure that if any one of
b312fc
+				 * command fails,return fail status to
b312fc
+				 * scsi layer
b312fc
+				 */
b312fc
+				if (r1_cmd->io_request->RaidContext.raid_context.status !=
b312fc
+								MFI_STAT_OK) {
b312fc
+					status =
b312fc
+					r1_cmd->io_request->RaidContext.raid_context.status;
b312fc
+					extStatus =
b312fc
+					r1_cmd->io_request->RaidContext.raid_context.exStatus;
b312fc
+					data_length =
b312fc
+						r1_cmd->io_request->DataLength;
b312fc
+					sense = r1_cmd->sense;
b312fc
+				}
b312fc
+				r1_cmd->io_request->RaidContext.raid_context.status = 0;
b312fc
+				r1_cmd->io_request->RaidContext.raid_context.exStatus = 0;
b312fc
+				cmd_fusion->is_raid_1_fp_write = 0;
b312fc
+				r1_cmd->is_raid_1_fp_write = 0;
b312fc
+				r1_cmd->cmd_completed = false;
b312fc
+				cmd_fusion->cmd_completed = false;
b312fc
+				megasas_return_cmd_fusion(instance, r1_cmd);
b312fc
+			}
b312fc
+			if (!cmd_fusion->is_raid_1_fp_write) {
b312fc
+				map_cmd_status(fusion, scmd_local, status,
b312fc
+					extStatus, data_length, sense);
b312fc
+				scsi_io_req->RaidContext.raid_context.status
b312fc
+				= 0;
b312fc
+				scsi_io_req->RaidContext.raid_context.exStatus
b312fc
+				= 0;
b312fc
+				megasas_return_cmd_fusion(instance, cmd_fusion);
b312fc
+				scsi_dma_unmap(scmd_local);
b312fc
+				scmd_local->scsi_done(scmd_local);
b312fc
+			}
b312fc
 			atomic_dec(&instance->fw_outstanding);
b312fc
 
b312fc
 			break;
b312fc
@@ -3493,7 +3725,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
b312fc
 {
b312fc
 	int retval = SUCCESS, i, j, convert = 0;
b312fc
 	struct megasas_instance *instance;
b312fc
-	struct megasas_cmd_fusion *cmd_fusion;
b312fc
+	struct megasas_cmd_fusion *cmd_fusion, *mpt_cmd_fusion;
b312fc
 	struct fusion_context *fusion;
b312fc
 	u32 abs_state, status_reg, reset_adapter;
b312fc
 	u32 io_timeout_in_crash_mode = 0;
b312fc
@@ -3568,6 +3800,18 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
b312fc
 		/* Now return commands back to the OS */
b312fc
 		for (i = 0 ; i < instance->max_scsi_cmds; i++) {
b312fc
 			cmd_fusion = fusion->cmd_list[i];
b312fc
+			/*check for extra commands issued by driver*/
b312fc
+			if (instance->is_ventura) {
b312fc
+				cmd_fusion->is_raid_1_fp_write = 0;
b312fc
+				cmd_fusion->cmd_completed = false;
b312fc
+				mpt_cmd_fusion =
b312fc
+				fusion->cmd_list[i + instance->max_fw_cmds];
b312fc
+				mpt_cmd_fusion->is_raid_1_fp_write = 0;
b312fc
+				mpt_cmd_fusion->cmd_completed = false;
b312fc
+				if (mpt_cmd_fusion->scmd)
b312fc
+					megasas_return_cmd_fusion(instance,
b312fc
+						mpt_cmd_fusion);
b312fc
+			}
b312fc
 			scmd_local = cmd_fusion->scmd;
b312fc
 			if (cmd_fusion->scmd) {
b312fc
 				scmd_local->result =
b312fc
@@ -3578,10 +3822,11 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
b312fc
 				megasas_return_cmd_fusion(instance, cmd_fusion);
b312fc
 				scsi_dma_unmap(scmd_local);
b312fc
 				scmd_local->scsi_done(scmd_local);
b312fc
-				atomic_dec(&instance->fw_outstanding);
b312fc
 			}
b312fc
 		}
b312fc
 
b312fc
+		atomic_set(&instance->fw_outstanding, 0);
b312fc
+
b312fc
 		status_reg = instance->instancet->read_fw_status_reg(
b312fc
 			instance->reg_set);
b312fc
 		abs_state = status_reg & MFI_STATE_MASK;
b312fc
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
b312fc
index d9cf496..7a3c3d1 100644
b312fc
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
b312fc
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
b312fc
@@ -94,6 +94,7 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE {
b312fc
 #define MEGASAS_FP_CMD_LEN	16
b312fc
 #define MEGASAS_FUSION_IN_RESET 0
b312fc
 #define THRESHOLD_REPLY_COUNT 50
b312fc
+#define RAID_1_10_RMW_CMDS 3
b312fc
 #define JBOD_MAPS_COUNT	2
b312fc
 
b312fc
 enum MR_FUSION_ADAPTER_TYPE {
b312fc
@@ -728,7 +729,9 @@ struct MR_SPAN_BLOCK_INFO {
b312fc
 struct MR_LD_RAID {
b312fc
 	struct {
b312fc
 #if   defined(__BIG_ENDIAN_BITFIELD)
b312fc
-		u32     reserved4:5;
b312fc
+		u32     reserved4:3;
b312fc
+		u32     fp_cache_bypass_capable:1;
b312fc
+		u32     fp_rmw_capable:1;
b312fc
 		u32     fpBypassRegionLock:1;
b312fc
 		u32     tmCapable:1;
b312fc
 		u32	fpNonRWCapable:1;
b312fc
@@ -756,7 +759,9 @@ struct MR_LD_RAID {
b312fc
 		u32	fpNonRWCapable:1;
b312fc
 		u32     tmCapable:1;
b312fc
 		u32     fpBypassRegionLock:1;
b312fc
-		u32     reserved4:5;
b312fc
+		u32     fp_rmw_capable:1;
b312fc
+		u32     fp_cache_bypass_capable:1;
b312fc
+		u32     reserved4:3;
b312fc
 #endif
b312fc
 	} capability;
b312fc
 	__le32     reserved6;
b312fc
@@ -830,6 +835,8 @@ struct IO_REQUEST_INFO {
b312fc
 	u64 start_row;
b312fc
 	u8  span_arm;	/* span[7:5], arm[4:0] */
b312fc
 	u8  pd_after_lb;
b312fc
+	u16 r1_alt_dev_handle; /* raid 1/10 only */
b312fc
+	bool is_raid_1_fp_write;
b312fc
 	bool ra_capable;
b312fc
 };
b312fc
 
b312fc
@@ -883,6 +890,10 @@ struct megasas_cmd_fusion {
b312fc
 	u32 index;
b312fc
 	u8 pd_r1_lb;
b312fc
 	struct completion done;
b312fc
+	bool is_raid_1_fp_write;
b312fc
+	u16 r1_alt_dev_handle; /* raid 1/10 only*/
b312fc
+	bool cmd_completed;  /* raid 1/10 fp writes status holder */
b312fc
+
b312fc
 };
b312fc
 
b312fc
 struct LD_LOAD_BALANCE_INFO {
b312fc
-- 
b312fc
1.8.3.1
b312fc