[PATCH 05/11] megaraid_sas: SAS3.5 Generic Megaraid Controllers Fast Path for RAID 1/10 Writes
From: Sasikumar Chandrasekaran
Date: Thu Dec 01 2016 - 14:23:18 EST
From: root <sasikumar.pc@xxxxxxxxxxxx>
To improve RAID 1/10 Write performance, OS drivers need to issue the required Write
IOs as Fast Path IOs (after the appropriate checks allowing Fast Path to be used)
to the appropriate physical drives (translated from the OS logical IO) and wait for
all Write IOs to complete. If any of the Write IOs fail or time out, the IO will be
re issued to FW as an LD IO so FW can perform the error handling.
This patch is depending on patch 4
Signed-off-by: Sasikumar Chandrasekaran <sasikumar.pc@xxxxxxxxxxxx>
---
drivers/scsi/megaraid/megaraid_sas.h | 1 +
drivers/scsi/megaraid/megaraid_sas_fp.c | 32 ++-
drivers/scsi/megaraid/megaraid_sas_fusion.c | 325 ++++++++++++++++++++++++----
drivers/scsi/megaraid/megaraid_sas_fusion.h | 15 +-
4 files changed, 317 insertions(+), 56 deletions(-)
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index ee6bd5c..9263ba3 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -2059,6 +2059,7 @@ struct megasas_instance {
u16 max_num_sge;
u16 max_fw_cmds;
+ u16 max_mpt_cmds;
u16 max_mfi_cmds;
u16 max_scsi_cmds;
u16 ldio_threshold;
diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c
index d9483bc..5922d15 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fp.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fp.c
@@ -737,7 +737,7 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld,
struct MR_DRV_RAID_MAP_ALL *map)
{
struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
- u32 pd, arRef;
+ u32 pd, arRef, r1_alt_pd;
u8 physArm, span;
u64 row;
u8 retval = TRUE;
@@ -772,9 +772,15 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld,
arRef = MR_LdSpanArrayGet(ld, span, map);
pd = MR_ArPdGet(arRef, physArm, map);
- if (pd != MR_PD_INVALID)
+ if (pd != MR_PD_INVALID) {
*pDevHandle = MR_PdDevHandleGet(pd, map);
- else {
+ /* get second pd also for raid 1/10 fast path writes*/
+ if (raid->level == 1) {
+ r1_alt_pd = MR_ArPdGet(arRef, physArm + 1, map);
+ if (r1_alt_pd != MR_PD_INVALID)
+ io_info->r1_alt_dev_handle = MR_PdDevHandleGet(r1_alt_pd, map);
+ }
+ } else {
*pDevHandle = cpu_to_le16(MR_PD_INVALID);
if ((raid->level >= 5) &&
((fusion->adapter_type == THUNDERBOLT_SERIES) ||
@@ -819,7 +825,7 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow,
struct MR_DRV_RAID_MAP_ALL *map)
{
struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
- u32 pd, arRef;
+ u32 pd, arRef, r1_alt_pd;
u8 physArm, span;
u64 row;
u8 retval = TRUE;
@@ -867,10 +873,15 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow,
arRef = MR_LdSpanArrayGet(ld, span, map);
pd = MR_ArPdGet(arRef, physArm, map); /* Get the pd */
- if (pd != MR_PD_INVALID)
- /* Get dev handle from Pd. */
- *pDevHandle = MR_PdDevHandleGet(pd, map);
- else {
+ if (pd != MR_PD_INVALID) {
+ *pDevHandle = MR_PdDevHandleGet(pd, map); /* Get dev handle from Pd. */
+ /* get second pd also for raid 1/10 fast path writes*/
+ if (raid->level == 1) {
+ r1_alt_pd = MR_ArPdGet(arRef, physArm + 1, map);
+ if (r1_alt_pd != MR_PD_INVALID)
+ io_info->r1_alt_dev_handle = MR_PdDevHandleGet(r1_alt_pd, map);
+ }
+ } else {
/* set dev handle as invalid. */
*pDevHandle = cpu_to_le16(MR_PD_INVALID);
if ((raid->level >= 5) &&
@@ -1126,6 +1137,11 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow,
/* If IO on an invalid Pd, then FP is not possible.*/
if (io_info->devHandle == cpu_to_le16(MR_PD_INVALID))
io_info->fpOkForIo = FALSE;
+ /* set raid 1/10 fast path write capable bit in io_info */
+ if (io_info->fpOkForIo &&
+ (io_info->r1_alt_dev_handle != MR_PD_INVALID) &&
+ (raid->level == 1) && !isRead)
+ io_info->isRaid_1_fp_write = 1;
return retval;
} else if (isRead) {
uint stripIdx;
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index 3ad929b..116f300 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -269,8 +269,15 @@ inline void megasas_return_cmd_fusion(struct megasas_instance *instance,
instance->max_fw_cmds = cur_max_fw_cmds;
instance->ldio_threshold = ldio_threshold;
- if (!instance->is_rdpq)
- instance->max_fw_cmds = min_t(u16, instance->max_fw_cmds, 1024);
+ /*
+ * Do not lower Queue Depth for Ventura because RDPQ is not
+ * supported. Also NOTE that the driver will fail to load for
+ * more than 64 CPUs under Ventura because the maximum
+ * contiguous allocation is 4MB, which is only enough for 64
+ * MSIx vectors.
+ */
+
+ instance->max_fw_cmds = min_t(u16, instance->max_fw_cmds, 1024);
if (reset_devices)
instance->max_fw_cmds = min(instance->max_fw_cmds,
@@ -286,7 +293,13 @@ inline void megasas_return_cmd_fusion(struct megasas_instance *instance,
(MEGASAS_FUSION_INTERNAL_CMDS +
MEGASAS_FUSION_IOCTL_CMDS);
instance->cur_can_queue = instance->max_scsi_cmds;
+ instance->host->can_queue = instance->cur_can_queue;
}
+
+ if (instance->is_ventura)
+ instance->max_mpt_cmds = instance->max_fw_cmds * RAID_1_10_RMW_CMDS;
+ else
+ instance->max_mpt_cmds = instance->max_fw_cmds;
}
/**
* megasas_free_cmds_fusion - Free all the cmds in the free cmd pool
@@ -300,7 +313,7 @@ inline void megasas_return_cmd_fusion(struct megasas_instance *instance,
struct megasas_cmd_fusion *cmd;
/* SG, Sense */
- for (i = 0; i < instance->max_fw_cmds; i++) {
+ for (i = 0; i < instance->max_mpt_cmds; i++) {
cmd = fusion->cmd_list[i];
if (cmd) {
if (cmd->sg_frame)
@@ -344,7 +357,7 @@ inline void megasas_return_cmd_fusion(struct megasas_instance *instance,
/* cmd_list */
- for (i = 0; i < instance->max_fw_cmds; i++)
+ for (i = 0; i < instance->max_mpt_cmds; i++)
kfree(fusion->cmd_list[i]);
kfree(fusion->cmd_list);
@@ -396,33 +409,49 @@ static int megasas_create_sg_sense_fusion(struct megasas_instance *instance)
return -ENOMEM;
}
}
+
+ /* create sense buffer for the raid 1/10 fp */
+ for (i = max_cmd; i < instance->max_mpt_cmds; i++) {
+ cmd = fusion->cmd_list[i];
+ cmd->sense = pci_pool_alloc(fusion->sense_dma_pool,
+ GFP_KERNEL, &cmd->sense_phys_addr);
+ if (!cmd->sense) {
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+ }
+
return 0;
}
int
megasas_alloc_cmdlist_fusion(struct megasas_instance *instance)
{
- u32 max_cmd, i;
+ u32 max_mpt_cmd, i;
struct fusion_context *fusion;
fusion = instance->ctrl_context;
- max_cmd = instance->max_fw_cmds;
+ max_mpt_cmd = instance->max_mpt_cmds;
/*
* fusion->cmd_list is an array of struct megasas_cmd_fusion pointers.
* Allocate the dynamic array first and then allocate individual
* commands.
*/
- fusion->cmd_list = kzalloc(sizeof(struct megasas_cmd_fusion *) * max_cmd,
- GFP_KERNEL);
+ fusion->cmd_list =
+ kmalloc(sizeof(struct megasas_cmd_fusion *) * max_mpt_cmd, GFP_KERNEL);
if (!fusion->cmd_list) {
dev_err(&instance->pdev->dev,
"Failed from %s %d\n", __func__, __LINE__);
return -ENOMEM;
}
- for (i = 0; i < max_cmd; i++) {
+ memset(fusion->cmd_list, 0,
+ sizeof(struct megasas_cmd_fusion *) * max_mpt_cmd);
+
+ for (i = 0; i < max_mpt_cmd; i++) {
fusion->cmd_list[i] = kzalloc(sizeof(struct megasas_cmd_fusion),
GFP_KERNEL);
if (!fusion->cmd_list[i]) {
@@ -657,13 +686,14 @@ static int megasas_create_sg_sense_fusion(struct megasas_instance *instance)
*/
/* SMID 0 is reserved. Set SMID/index from 1 */
- for (i = 0; i < instance->max_fw_cmds; i++) {
+ for (i = 0; i < instance->max_mpt_cmds; i++) {
cmd = fusion->cmd_list[i];
offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i;
memset(cmd, 0, sizeof(struct megasas_cmd_fusion));
cmd->index = i + 1;
cmd->scmd = NULL;
- cmd->sync_cmd_idx = (i >= instance->max_scsi_cmds) ?
+ cmd->sync_cmd_idx =
+ (i >= instance->max_scsi_cmds && i < instance->max_fw_cmds) ?
(i - instance->max_scsi_cmds) :
(u32)ULONG_MAX; /* Set to Invalid */
cmd->instance = instance;
@@ -673,6 +703,7 @@ static int megasas_create_sg_sense_fusion(struct megasas_instance *instance)
memset(cmd->io_request, 0,
sizeof(struct MPI2_RAID_SCSI_IO_REQUEST));
cmd->io_request_phys_addr = io_req_base_phys + offset;
+ cmd->isRaid_1_fp_write = 0;
}
if (megasas_create_sg_sense_fusion(instance))
@@ -1262,12 +1293,12 @@ static int megasas_create_sg_sense_fusion(struct megasas_instance *instance)
fusion->reply_q_depth = 2 * (((max_cmd + 1 + 15)/16)*16);
fusion->request_alloc_sz =
- sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) *max_cmd;
+ sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) * instance->max_mpt_cmds;
fusion->reply_alloc_sz = sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)
*(fusion->reply_q_depth);
fusion->io_frames_alloc_sz = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE +
- (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE *
- (max_cmd + 1)); /* Extra 1 for SMID 0 */
+ (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE
+ * (instance->max_mpt_cmds + 1)); /* Extra 1 for SMID 0 */
scratch_pad_2 = readl(&instance->reg_set->outbound_scratch_pad_2);
/* If scratch_pad_2 & MEGASAS_MAX_CHAIN_SIZE_UNITS_MASK is set,
@@ -1403,42 +1434,43 @@ static int megasas_create_sg_sense_fusion(struct megasas_instance *instance)
*/
void
-map_cmd_status(struct megasas_cmd_fusion *cmd, u8 status, u8 ext_status)
+map_cmd_status(struct fusion_context *fusion,
+ struct scsi_cmnd *scmd, u8 status, u8 ext_status,
+ u32 data_length, u8 *sense)
{
switch (status) {
case MFI_STAT_OK:
- cmd->scmd->result = DID_OK << 16;
+ scmd->result = DID_OK << 16;
break;
case MFI_STAT_SCSI_IO_FAILED:
case MFI_STAT_LD_INIT_IN_PROGRESS:
- cmd->scmd->result = (DID_ERROR << 16) | ext_status;
+ scmd->result = (DID_ERROR << 16) | ext_status;
break;
case MFI_STAT_SCSI_DONE_WITH_ERROR:
- cmd->scmd->result = (DID_OK << 16) | ext_status;
+ scmd->result = (DID_OK << 16) | ext_status;
if (ext_status == SAM_STAT_CHECK_CONDITION) {
- memset(cmd->scmd->sense_buffer, 0,
+ memset(scmd->sense_buffer, 0,
SCSI_SENSE_BUFFERSIZE);
- memcpy(cmd->scmd->sense_buffer, cmd->sense,
+ memcpy(scmd->sense_buffer, sense,
SCSI_SENSE_BUFFERSIZE);
- cmd->scmd->result |= DRIVER_SENSE << 24;
+ scmd->result |= DRIVER_SENSE << 24;
}
break;
case MFI_STAT_LD_OFFLINE:
case MFI_STAT_DEVICE_NOT_FOUND:
- cmd->scmd->result = DID_BAD_TARGET << 16;
+ scmd->result = DID_BAD_TARGET << 16;
break;
case MFI_STAT_CONFIG_SEQ_MISMATCH:
- cmd->scmd->result = DID_IMM_RETRY << 16;
+ scmd->result = DID_IMM_RETRY << 16;
break;
default:
- dev_printk(KERN_DEBUG, &cmd->instance->pdev->dev, "FW status %#x\n", status);
- cmd->scmd->result = DID_ERROR << 16;
+ scmd->result = DID_ERROR << 16;
break;
}
}
@@ -1872,6 +1904,7 @@ static void megasas_stream_detect(struct megasas_instance *instance,
io_info.ldStartBlock = ((u64)start_lba_hi << 32) | start_lba_lo;
io_info.numBlocks = datalength;
io_info.ldTgtId = device_id;
+ io_info.r1_alt_dev_handle = MR_PD_INVALID;
io_request->DataLength = cpu_to_le32(scsi_bufflen(scp));
if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
@@ -1939,6 +1972,10 @@ static void megasas_stream_detect(struct megasas_instance *instance,
} else
scp->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG;
+ cmd->isRaid_1_fp_write = io_info.isRaid_1_fp_write;
+ if (io_info.isRaid_1_fp_write)
+ cmd->r1_alt_dev_handle = io_info.r1_alt_dev_handle;
+
if ((raidLUN[0] == 1) &&
(local_map_ptr->raidMap.devHndlInfo[io_info.pd_after_lb].validHandles > 1)) {
instance->dev_handle = !(instance->dev_handle);
@@ -2261,19 +2298,108 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance,
u8 *p;
struct fusion_context *fusion;
- if (index >= instance->max_fw_cmds) {
+ if (index >= instance->max_mpt_cmds) {
dev_err(&instance->pdev->dev, "Invalid SMID (0x%x)request for "
"descriptor for scsi%d\n", index,
instance->host->host_no);
return NULL;
}
fusion = instance->ctrl_context;
- p = fusion->req_frames_desc
- +sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) *index;
+ p = fusion->req_frames_desc +
+ sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) * index;
return (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)p;
}
+/*
+ * megasas_fpio_to_ldio-
+ * This function converts an fp io to ldio
+*/
+
+void megasas_fpio_to_ldio(struct megasas_instance *instance,
+ struct megasas_cmd_fusion *cmd, struct scsi_cmnd *scmd)
+{
+ struct fusion_context *fusion;
+ fusion = instance->ctrl_context;
+
+ cmd->request_desc->SCSIIO.RequestFlags =
+ (MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO
+ << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+ cmd->io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
+ cmd->io_request->DevHandle = cpu_to_le16(MEGASAS_DEV_INDEX(scmd));
+
+ /*remove FAST PATH ENABLE bit in IoFlags */
+ cmd->io_request->IoFlags &=
+ cpu_to_le16(~MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
+
+ /* if the numSGE > max_sge_in_main_sge set the chain offset*/
+ if (cmd->io_request->RaidContext.raid_context_g35.numSGE >
+ fusion->max_sge_in_main_msg)
+ cmd->io_request->ChainOffset = fusion->chain_offset_io_request;
+ memcpy(cmd->io_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
+ cmd->io_request->CDB.EEDP32.PrimaryReferenceTag = 0;
+ cmd->io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0;
+ cmd->io_request->EEDPFlags = 0;
+ cmd->io_request->Control = 0;
+ cmd->io_request->EEDPBlockSize = 0;
+ cmd->isRaid_1_fp_write = 0;
+}
+/*megasas_prepate_secondRaid1_IO
+ * It prepares the raid 1 second IO
+ * */
+void megasas_prepare_secondRaid1_IO(struct megasas_instance *instance,
+ struct megasas_cmd_fusion *cmd,
+ struct megasas_cmd_fusion *r1_cmd)
+{
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc, *req_desc2 = NULL;
+ struct fusion_context *fusion;
+ fusion = instance->ctrl_context;
+ req_desc = cmd->request_desc;
+ if (r1_cmd) {
+ /* copy the io request frame as well as 8 SGEs data for r1 command*/
+ memcpy(r1_cmd->io_request, cmd->io_request,
+ sizeof(struct MPI2_RAID_SCSI_IO_REQUEST));
+ memcpy(&r1_cmd->io_request->SGL, &cmd->io_request->SGL,
+ (fusion->max_sge_in_main_msg *
+ sizeof(union MPI2_SGE_IO_UNION)));
+ /*sense buffer is different for r1 command*/
+ r1_cmd->io_request->SenseBufferLowAddress =
+ cpu_to_le32(r1_cmd->sense_phys_addr);
+ r1_cmd->scmd = cmd->scmd;
+ req_desc2 = megasas_get_request_descriptor(instance, r1_cmd->index-1);
+ if (req_desc2) {
+ req_desc2->Words = 0;
+ r1_cmd->request_desc = req_desc2;
+ req_desc2->SCSIIO.SMID = cpu_to_le16(r1_cmd->index);
+ req_desc2->SCSIIO.RequestFlags = req_desc->SCSIIO.RequestFlags;
+ r1_cmd->isRaid_1_fp_write = 1;
+ r1_cmd->request_desc->SCSIIO.DevHandle = cmd->r1_alt_dev_handle;
+ r1_cmd->io_request->DevHandle = cmd->r1_alt_dev_handle;
+ cmd->io_request->RaidContext.raid_context_g35.smid.peerSMID =
+ cpu_to_le16(r1_cmd->index);
+ r1_cmd->io_request->RaidContext.raid_context_g35.smid.peerSMID =
+ cpu_to_le16(cmd->index);
+ /*MSIxIndex of both commands request descriptors should be same*/
+ r1_cmd->request_desc->SCSIIO.MSIxIndex =
+ cmd->request_desc->SCSIIO.MSIxIndex;
+ /*span arm is different for r1 cmd*/
+ r1_cmd->io_request->RaidContext.raid_context_g35.spanArm =
+ cmd->io_request->RaidContext.raid_context_g35.spanArm + 1;
+ } else {
+ megasas_return_cmd_fusion(instance, r1_cmd);
+ dev_info(&instance->pdev->dev,
+ "unable to get request descriptor, firing as normal IO\n");
+ atomic_dec(&instance->fw_outstanding);
+ megasas_fpio_to_ldio(instance, cmd, cmd->scmd);
+ }
+ } else {
+ dev_info(&instance->pdev->dev,
+ "unable to get command, firing as normal IO\n");
+ atomic_dec(&instance->fw_outstanding);
+ megasas_fpio_to_ldio(instance, cmd, cmd->scmd);
+ }
+}
+
/**
* megasas_build_and_issue_cmd_fusion -Main routine for building and
* issuing non IOCTL cmd
@@ -2284,7 +2410,7 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance,
megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
struct scsi_cmnd *scmd)
{
- struct megasas_cmd_fusion *cmd;
+ struct megasas_cmd_fusion *cmd, *r1_cmd = NULL;
union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
u32 index;
struct fusion_context *fusion;
@@ -2299,13 +2425,28 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance,
return SCSI_MLQUEUE_DEVICE_BUSY;
}
+ if (atomic_inc_return(&instance->fw_outstanding) >
+ instance->host->can_queue) {
+ dev_err(&instance->pdev->dev, "Throttle IOs beyond"
+ "Controller queue depth\n");
+ atomic_dec(&instance->fw_outstanding);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
cmd = megasas_get_cmd_fusion(instance, scmd->request->tag);
+ if (!cmd) {
+ atomic_dec(&instance->fw_outstanding);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
index = cmd->index;
req_desc = megasas_get_request_descriptor(instance, index-1);
- if (!req_desc)
+ if (!req_desc) {
+ atomic_dec(&instance->fw_outstanding);
return SCSI_MLQUEUE_HOST_BUSY;
+ }
req_desc->Words = 0;
cmd->request_desc = req_desc;
@@ -2314,6 +2455,7 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance,
megasas_return_cmd_fusion(instance, cmd);
dev_err(&instance->pdev->dev, "Error building command\n");
cmd->request_desc = NULL;
+ atomic_dec(&instance->fw_outstanding);
return SCSI_MLQUEUE_HOST_BUSY;
}
@@ -2324,14 +2466,40 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance,
cmd->io_request->ChainOffset != 0xF)
dev_err(&instance->pdev->dev, "The chain offset value is not "
"correct : %x\n", cmd->io_request->ChainOffset);
+ /*
+ * if it is raid 1/10 fp write capable.
+ * try to get second command from pool and construct it.
+ * From FW, it has confirmed that lba values of two PDs corresponds to
+ * single R1/10 LD are always same
+ *
+ */
+
+ /* driver side count always should be less than max_fw_cmds
+ * to get new command
+ */
+ if (cmd->isRaid_1_fp_write &&
+ atomic_inc_return(&instance->fw_outstanding) >
+ (instance->host->can_queue)) {
+ megasas_fpio_to_ldio(instance, cmd, cmd->scmd);
+ atomic_dec(&instance->fw_outstanding);
+ } else if (cmd->isRaid_1_fp_write) {
+ r1_cmd = megasas_get_cmd_fusion(instance,
+ (scmd->request->tag + instance->max_fw_cmds));
+ megasas_prepare_secondRaid1_IO(instance, cmd, r1_cmd);
+ }
+
/*
* Issue the command to the FW
*/
- atomic_inc(&instance->fw_outstanding);
megasas_fire_cmd_fusion(instance, req_desc, instance->is_ventura);
+ if (r1_cmd)
+ megasas_fire_cmd_fusion(instance, r1_cmd->request_desc,
+ instance->is_ventura);
+
+
return 0;
}
@@ -2348,10 +2516,10 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance,
struct MPI2_RAID_SCSI_IO_REQUEST *scsi_io_req;
struct fusion_context *fusion;
struct megasas_cmd *cmd_mfi;
- struct megasas_cmd_fusion *cmd_fusion;
+ struct megasas_cmd_fusion *cmd_fusion, *r1_cmd = NULL;
u16 smid, num_completed;
- u8 reply_descript_type;
- u32 status, extStatus, device_id;
+ u8 reply_descript_type, *sense;
+ u32 status, extStatus, device_id, data_length;
union desc_value d_val;
struct LD_LOAD_BALANCE_INFO *lbinfo;
int threshold_reply_count = 0;
@@ -2381,6 +2549,14 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance,
while (d_val.u.low != cpu_to_le32(UINT_MAX) &&
d_val.u.high != cpu_to_le32(UINT_MAX)) {
+ /*
+ * Ensure that the peer command is NULL here in case a command
+ * has completed but the R1 FP Write peer has not completed yet.
+ * If not null, it's possible that another thread will complete
+ * the peer command and should not.
+ */
+ r1_cmd = NULL;
+
smid = le16_to_cpu(reply_desc->SMID);
cmd_fusion = fusion->cmd_list[smid - 1];
@@ -2395,6 +2571,8 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance,
scmd_local = cmd_fusion->scmd;
status = scsi_io_req->RaidContext.raid_context.status;
extStatus = scsi_io_req->RaidContext.raid_context.exStatus;
+ sense = cmd_fusion->sense;
+ data_length = scsi_io_req->DataLength;
switch (scsi_io_req->Function) {
case MPI2_FUNCTION_SCSI_TASK_MGMT:
@@ -2411,12 +2589,27 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance,
/* Update load balancing info */
device_id = MEGASAS_DEV_INDEX(scmd_local);
lbinfo = &fusion->load_balance_info[device_id];
- if (cmd_fusion->scmd->SCp.Status &
- MEGASAS_LOAD_BALANCE_FLAG) {
+ /*
+ * check for the raid 1/10 fast path writes
+ */
+ if (!cmd_fusion->isRaid_1_fp_write &&
+ (cmd_fusion->scmd->SCp.Status &
+ MEGASAS_LOAD_BALANCE_FLAG)) {
atomic_dec(&lbinfo->scsi_pending_cmds[cmd_fusion->pd_r1_lb]);
cmd_fusion->scmd->SCp.Status &=
~MEGASAS_LOAD_BALANCE_FLAG;
+ } else if (cmd_fusion->isRaid_1_fp_write) {
+ /* get peer command */
+ if (cmd_fusion->index < instance->max_fw_cmds)
+ r1_cmd = fusion->cmd_list[(cmd_fusion->index +
+ instance->max_fw_cmds)-1];
+ else {
+ r1_cmd = fusion->cmd_list[(cmd_fusion->index -
+ instance->max_fw_cmds)-1];
+ }
+ cmd_fusion->cmd_completed = true; /* mark it as completed */
}
+
if (reply_descript_type ==
MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS) {
if (megasas_dbg_lvl == 5)
@@ -2426,14 +2619,43 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance,
/* Fall thru and complete IO */
case MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST: /* LD-IO Path */
/* Map the FW Cmd Status */
- map_cmd_status(cmd_fusion, status, extStatus);
- scsi_io_req->RaidContext.raid_context.status = 0;
- scsi_io_req->RaidContext.raid_context.exStatus = 0;
- if (megasas_cmd_type(scmd_local) == READ_WRITE_LDIO)
- atomic_dec(&instance->ldio_outstanding);
- megasas_return_cmd_fusion(instance, cmd_fusion);
- scsi_dma_unmap(scmd_local);
- scmd_local->scsi_done(scmd_local);
+ /*
+ * check for the raid 1/10 fast path writes
+ */
+ if (r1_cmd && r1_cmd->isRaid_1_fp_write
+ && r1_cmd->cmd_completed) {
+ /*
+ * if the peer Raid 1/10 fast path failed,
+ * mark IO as failed to the scsi layer.
+ * over write the current status by the failed status
+ * makes sure that if any one of command fails,
+ * return fail status to scsi layer
+ */
+ if (r1_cmd->io_request->RaidContext.raid_context.status !=
+ MFI_STAT_OK) {
+ status =
+ r1_cmd->io_request->RaidContext.raid_context.status;
+ extStatus =
+ r1_cmd->io_request->RaidContext.raid_context.exStatus;
+ data_length = r1_cmd->io_request->DataLength;
+ sense = r1_cmd->sense;
+ }
+ r1_cmd->io_request->RaidContext.raid_context.status = 0;
+ r1_cmd->io_request->RaidContext.raid_context.exStatus = 0;
+ cmd_fusion->isRaid_1_fp_write = 0;
+ r1_cmd->isRaid_1_fp_write = 0;
+ r1_cmd->cmd_completed = cmd_fusion->cmd_completed = false;
+ megasas_return_cmd_fusion(instance, r1_cmd);
+ }
+ if (!cmd_fusion->isRaid_1_fp_write) {
+ map_cmd_status(fusion, scmd_local, status,
+ extStatus, data_length, sense);
+ scsi_io_req->RaidContext.raid_context.status = 0;
+ scsi_io_req->RaidContext.raid_context.exStatus = 0;
+ megasas_return_cmd_fusion(instance, cmd_fusion);
+ scsi_dma_unmap(scmd_local);
+ scmd_local->scsi_done(scmd_local);
+ }
atomic_dec(&instance->fw_outstanding);
break;
@@ -3485,7 +3707,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
{
int retval = SUCCESS, i, j, convert = 0;
struct megasas_instance *instance;
- struct megasas_cmd_fusion *cmd_fusion;
+ struct megasas_cmd_fusion *cmd_fusion, *mpt_cmd_fusion;
struct fusion_context *fusion;
u32 abs_state, status_reg, reset_adapter;
u32 io_timeout_in_crash_mode = 0;
@@ -3560,6 +3782,16 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
/* Now return commands back to the OS */
for (i = 0 ; i < instance->max_scsi_cmds; i++) {
cmd_fusion = fusion->cmd_list[i];
+ /*check for extra commands issued by driver*/
+ if (instance->is_ventura) {
+ cmd_fusion->isRaid_1_fp_write = 0;
+ cmd_fusion->cmd_completed = false;
+ mpt_cmd_fusion = fusion->cmd_list[i + instance->max_fw_cmds];
+ mpt_cmd_fusion->isRaid_1_fp_write = 0;
+ mpt_cmd_fusion->cmd_completed = false;
+ if (mpt_cmd_fusion->scmd)
+ megasas_return_cmd_fusion(instance, mpt_cmd_fusion);
+ }
scmd_local = cmd_fusion->scmd;
if (cmd_fusion->scmd) {
scmd_local->result =
@@ -3570,10 +3802,11 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
megasas_return_cmd_fusion(instance, cmd_fusion);
scsi_dma_unmap(scmd_local);
scmd_local->scsi_done(scmd_local);
- atomic_dec(&instance->fw_outstanding);
}
}
+ atomic_set(&instance->fw_outstanding, 0);
+
status_reg = instance->instancet->read_fw_status_reg(
instance->reg_set);
abs_state = status_reg & MFI_STATE_MASK;
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
index 9bb2f40..aaa4924 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
@@ -94,6 +94,7 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE {
#define MEGASAS_FP_CMD_LEN 16
#define MEGASAS_FUSION_IN_RESET 0
#define THRESHOLD_REPLY_COUNT 50
+#define RAID_1_10_RMW_CMDS 3
#define JBOD_MAPS_COUNT 2
enum MR_FUSION_ADAPTER_TYPE {
@@ -733,7 +734,9 @@ struct MR_SPAN_BLOCK_INFO {
struct MR_LD_RAID {
struct {
#if defined(__BIG_ENDIAN_BITFIELD)
- u32 reserved4:5;
+ u32 reserved4:3;
+ u32 fpCacheBypassCapable:1;
+ u32 fpRmwCapable:1;
u32 fpBypassRegionLock:1;
u32 tmCapable:1;
u32 fpNonRWCapable:1;
@@ -761,7 +764,9 @@ struct MR_LD_RAID {
u32 fpNonRWCapable:1;
u32 tmCapable:1;
u32 fpBypassRegionLock:1;
- u32 reserved4:5;
+ u32 fpRmwCapable:1;
+ u32 fpCacheBypassCapable:1;
+ u32 reserved4:3;
#endif
} capability;
__le32 reserved6;
@@ -835,6 +840,8 @@ struct IO_REQUEST_INFO {
u64 start_row;
u8 span_arm; /* span[7:5], arm[4:0] */
u8 pd_after_lb;
+ u16 r1_alt_dev_handle; /* raid 1/10 only */
+ bool isRaid_1_fp_write;
bool raCapable;
};
@@ -888,6 +895,10 @@ struct megasas_cmd_fusion {
u32 index;
u8 pd_r1_lb;
struct completion done;
+ bool isRaid_1_fp_write;
+ u16 r1_alt_dev_handle; /* raid 1/10 only*/
+ bool cmd_completed; /* raid 1/10 fp writes status holder */
+
};
struct LD_LOAD_BALANCE_INFO {
--
1.8.3.1