ignatenkobrain / rpms / kernel

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