chengshan / rpms / kernel

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