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