|
|
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 |
|