diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index a6e788c02..b7f697882 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -1,10 +1,22 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Linux MegaRAID driver for SAS based RAID controllers
*
- * Copyright (c) 2003-2013 LSI Corporation
- * Copyright (c) 2013-2016 Avago Technologies
- * Copyright (c) 2016-2018 Broadcom Inc.
+ * Copyright (c) 2003-2018 LSI Corporation.
+ * Copyright (c) 2003-2018 Avago Technologies.
+ * Copyright (c) 2003-2018 Broadcom Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
*
* FILE: megaraid_sas.h
*
@@ -18,11 +30,37 @@
#ifndef LSI_MEGARAID_SAS_H
#define LSI_MEGARAID_SAS_H
+#if ((defined(RHEL_MAJOR) && (RHEL_MAJOR == 7) && (RHEL_MINOR >= 3)) || \
+ (defined(CONFIG_SUSE_KERNEL) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,21))) || \
+ (LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0)))
+#include
+#define ENABLE_IRQ_POLL
+#endif
+
+#if ((defined(RHEL_MAJOR) && (RHEL_MAJOR == 8) && (RHEL_MINOR >= 2)) || \
+ (LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)))
+#define USE_MANAGED_IRQ_API
+#endif
+
+#if ((defined(RHEL_MAJOR) && (RHEL_MAJOR == 8) && (RHEL_MINOR >= 4)) || \
+ (LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0)))
+#include
+#define HOST_TAGSET_SUPPORT
+#endif
+
+#if defined(HOST_TAGSET_SUPPORT) && !defined(USE_MANAGED_IRQ_API)
+#error "Please use Managed IRQs APIs for shared host tagset to work"
+#endif
+
/*
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "07.710.50.00-rc1"
-#define MEGASAS_RELDATE "June 28, 2019"
+#define MEGASAS_VERSION "07.721.02.00"
+#define MEGASAS_RELDATE "Jan 07, 2022"
+#define MEGASAS_EXT_VERSION "Jan 07, 17:00:00 PDT 2022"
+
+#define MEGASAS_MSIX_NAME_LEN 32
+
/*
* Device IDs
@@ -48,14 +86,14 @@
#define PCI_DEVICE_ID_LSI_TOMCAT 0x0017
#define PCI_DEVICE_ID_LSI_VENTURA_4PORT 0x001B
#define PCI_DEVICE_ID_LSI_CRUSADER_4PORT 0x001C
-#define PCI_DEVICE_ID_LSI_AERO_10E1 0x10e1
-#define PCI_DEVICE_ID_LSI_AERO_10E2 0x10e2
-#define PCI_DEVICE_ID_LSI_AERO_10E5 0x10e5
-#define PCI_DEVICE_ID_LSI_AERO_10E6 0x10e6
-#define PCI_DEVICE_ID_LSI_AERO_10E0 0x10e0
-#define PCI_DEVICE_ID_LSI_AERO_10E3 0x10e3
-#define PCI_DEVICE_ID_LSI_AERO_10E4 0x10e4
-#define PCI_DEVICE_ID_LSI_AERO_10E7 0x10e7
+#define PCI_DEVICE_ID_LSI_AERO_10E1 0x10e1
+#define PCI_DEVICE_ID_LSI_AERO_10E2 0x10e2
+#define PCI_DEVICE_ID_LSI_AERO_10E5 0x10e5
+#define PCI_DEVICE_ID_LSI_AERO_10E6 0x10e6
+#define PCI_DEVICE_ID_LSI_AERO_10E0 0x10e0
+#define PCI_DEVICE_ID_LSI_AERO_10E3 0x10e3
+#define PCI_DEVICE_ID_LSI_AERO_10E4 0x10e4
+#define PCI_DEVICE_ID_LSI_AERO_10E7 0x10e7
/*
* Intel HBA SSDIDs
@@ -177,6 +215,10 @@
#define DRV_DCMD_POLLED_MODE 0x1
#define DRV_DCMD_SKIP_REFIRE 0x2
+#define MR_HIGH_IOPS_QUEUE_COUNT 8
+#define MR_DEVICE_HIGH_IOPS_DEPTH 8
+#define MR_HIGH_IOPS_BATCH_COUNT 16
+
/*
* Definition for cmd_status
*/
@@ -193,8 +235,8 @@ enum MFI_CMD_OP {
MFI_CMD_PD_SCSI_IO = 0x4,
MFI_CMD_DCMD = 0x5,
MFI_CMD_ABORT = 0x6,
- MFI_CMD_SMP = 0x7,
- MFI_CMD_STP = 0x8,
+ MFI_CMD_SMP = 0x7,
+ MFI_CMD_STP = 0x8,
MFI_CMD_NVME = 0x9,
MFI_CMD_TOOLBOX = 0xa,
MFI_CMD_OP_COUNT,
@@ -509,7 +551,7 @@ union MR_PROGRESS {
*/
struct MR_PD_PROGRESS {
struct {
-#ifndef MFI_BIG_ENDIAN
+#ifndef __BIG_ENDIAN_BITFIELD
u32 rbld:1;
u32 patrol:1;
u32 clear:1;
@@ -535,7 +577,7 @@ struct MR_PD_PROGRESS {
};
struct {
-#ifndef MFI_BIG_ENDIAN
+#ifndef __BIG_ENDIAN_BITFIELD
u32 rbld:1;
u32 patrol:1;
u32 clear:1;
@@ -1453,12 +1495,11 @@ struct megasas_ctrl_info {
u32 size;
u32 pad1;
-
u8 reserved6[64];
-
+
struct {
#if defined(__BIG_ENDIAN_BITFIELD)
- u32 reserved:19;
+ u32 reserved:19;
u32 support_pci_lane_margining: 1;
u32 support_psoc_update:1;
u32 support_force_personality_change:1;
@@ -1492,7 +1533,7 @@ struct megasas_ctrl_info {
u8 reserved7[3];
- u8 TaskAbortTO; /* Timeout value in seconds used by Abort Task TM */
+ u8 TaskAbortTO; /* Timeout value in seconds used by Abort Task TM Request. */
u8 MaxResetTO; /* Max Supported Reset timeout in seconds. */
u8 reserved8[3];
} __packed;
@@ -1515,6 +1556,7 @@ struct megasas_ctrl_info {
#define MEGASAS_MAX_LD_IDS (MEGASAS_MAX_LD_CHANNELS * \
MEGASAS_MAX_DEV_PER_CHANNEL)
+#define MEGASAS_MAX_NAME 32
#define MEGASAS_MAX_SECTORS (2*1024)
#define MEGASAS_MAX_SECTORS_IEEE (2*128)
#define MEGASAS_DBG_LVL 1
@@ -1679,7 +1721,7 @@ struct megasas_register_set {
u32 reserved_3[3]; /*00A4h*/
- u32 outbound_scratch_pad_0; /*00B0h*/
+ u32 outbound_scratch_pad_0; /*00B0h*/
u32 outbound_scratch_pad_1; /*00B4h*/
u32 outbound_scratch_pad_2; /*00B8h*/
u32 outbound_scratch_pad_3; /*00BCh*/
@@ -1814,10 +1856,11 @@ struct megasas_init_frame {
__le32 queue_info_new_phys_addr_hi; /*1Ch */
__le32 queue_info_old_phys_addr_lo; /*20h */
__le32 queue_info_old_phys_addr_hi; /*24h */
- __le32 reserved_4[2]; /*28h */
+ __le32 driver_ver_lo; /*28h */
+ __le32 driver_ver_hi; /*2Ch */
__le32 system_info_lo; /*30h */
__le32 system_info_hi; /*34h */
- __le32 reserved_5[2]; /*38h */
+ __le32 reserved_3[2]; /*38h */
} __attribute__ ((packed));
@@ -2020,11 +2063,16 @@ union megasas_frame {
*/
struct MR_PRIV_DEVICE {
bool is_tm_capable;
+ bool is_epd;
bool tm_busy;
+ bool device_removed_by_fw;
atomic_t r1_ldio_hint;
u8 interface_type;
u8 task_abort_tmo;
u8 target_reset_tmo;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0))
+ atomic_t sdev_priv_busy;
+#endif
};
struct megasas_cmd;
@@ -2203,12 +2251,16 @@ struct megasas_aen_event {
};
struct megasas_irq_context {
+ char name[MEGASAS_MSIX_NAME_LEN];
struct megasas_instance *instance;
u32 MSIxIndex;
+#if defined(ENABLE_IRQ_POLL)
u32 os_irq;
struct irq_poll irqpoll;
bool irq_poll_scheduled;
bool irq_line_enable;
+#endif
+ atomic_t in_use;
};
struct MR_DRV_SYSTEM_INFO {
@@ -2230,39 +2282,33 @@ enum MR_PD_TYPE {
/* JBOD Queue depth definitions */
#define MEGASAS_SATA_QD 32
-#define MEGASAS_SAS_QD 64
+#define MEGASAS_SAS_QD 256
#define MEGASAS_DEFAULT_PD_QD 64
-#define MEGASAS_NVME_QD 32
+#define MEGASAS_NVME_QD 64
#define MR_DEFAULT_NVME_PAGE_SIZE 4096
#define MR_DEFAULT_NVME_PAGE_SHIFT 12
#define MR_DEFAULT_NVME_MDTS_KB 128
#define MR_NVME_PAGE_SIZE_MASK 0x000000FF
-/*Aero performance parameters*/
-#define MR_HIGH_IOPS_QUEUE_COUNT 8
-#define MR_DEVICE_HIGH_IOPS_DEPTH 8
-#define MR_HIGH_IOPS_BATCH_COUNT 16
-
-enum MR_PERF_MODE {
- MR_BALANCED_PERF_MODE = 0,
- MR_IOPS_PERF_MODE = 1,
- MR_LATENCY_PERF_MODE = 2,
+enum MEGASAS_LD_TARGET_ID_STATUS {
+ LD_TARGET_ID_INITIAL,
+ LD_TARGET_ID_ACTIVE,
+ LD_TARGET_ID_DELETED,
};
-#define MEGASAS_PERF_MODE_2STR(mode) \
- ((mode) == MR_BALANCED_PERF_MODE ? "Balanced" : \
- (mode) == MR_IOPS_PERF_MODE ? "IOPS" : \
- (mode) == MR_LATENCY_PERF_MODE ? "Latency" : \
- "Unknown")
+#define MEGASAS_TARGET_ID(sdev) \
+ (((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) + \
+ sdev->id)
struct megasas_instance {
- unsigned int *reply_map;
__le32 *producer;
dma_addr_t producer_h;
__le32 *consumer;
dma_addr_t consumer_h;
+ __le32 *verbuf;
+ dma_addr_t verbuf_h;
struct MR_DRV_SYSTEM_INFO *system_info_buf;
dma_addr_t system_info_h;
struct MR_LD_VF_AFFILIATION *vf_affiliation;
@@ -2320,6 +2366,9 @@ struct megasas_instance {
struct megasas_pd_list pd_list[MEGASAS_MAX_PD];
struct megasas_pd_list local_pd_list[MEGASAS_MAX_PD];
u8 ld_ids[MEGASAS_MAX_LD_IDS];
+ u8 ld_tgtid_status[MEGASAS_MAX_LD_IDS];
+ u8 ld_ids_prev[MEGASAS_MAX_LD_IDS];
+ u8 ld_ids_from_raidmap[MEGASAS_MAX_LD_IDS];
s8 init_id;
u16 max_num_sge;
@@ -2398,6 +2447,8 @@ struct megasas_instance {
/* Ptr to hba specific information */
void *ctrl_context;
unsigned int msix_vectors;
+ u8 *reply_map;
+ struct msix_entry msixentry[MEGASAS_MAX_MSIX_QUEUES];
struct megasas_irq_context irq_context[MEGASAS_MAX_MSIX_QUEUES];
u64 map_id;
u64 pd_seq_map_id;
@@ -2434,8 +2485,8 @@ struct megasas_instance {
u8 max_reset_tmo;
u8 snapdump_wait_time;
#ifdef CONFIG_DEBUG_FS
- struct dentry *debugfs_root;
- struct dentry *raidmap_dump;
+ struct dentry *debugfs_root;
+ struct dentry *raidmap_dump;
#endif
u8 enable_fw_dev_list;
bool atomic_desc_support;
@@ -2443,6 +2494,8 @@ struct megasas_instance {
bool support_pci_lane_margining;
u8 low_latency_index_start;
int perf_mode;
+ bool use_blk_mq;
+ int iopoll_q_count;
};
struct MR_LD_VF_MAP {
@@ -2539,6 +2592,9 @@ struct megasas_instance_template {
#define MEGASAS_IS_LOGICAL(sdev) \
((sdev->channel < MEGASAS_MAX_PD_CHANNELS) ? 0 : 1)
+#define MEGASAS_IS_LUN_VALID(sdev) \
+ ((sdev->lun == 0) ? 1 : 0)
+
#define MEGASAS_DEV_INDEX(scp) \
(((scp->device->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) + \
scp->device->id)
@@ -2637,12 +2693,32 @@ enum MEGASAS_OCR_CAUSE {
};
enum DCMD_RETURN_STATUS {
- DCMD_SUCCESS = 0,
- DCMD_TIMEOUT = 1,
- DCMD_FAILED = 2,
- DCMD_NOT_FIRED = 3,
+ DCMD_SUCCESS = 0x00,
+ DCMD_TIMEOUT = 0x01,
+ DCMD_FAILED = 0x02,
+ DCMD_BUSY = 0x03,
+ DCMD_INIT = 0xff,
};
+enum MR_PERF_MODE {
+ MR_BALANCED_PERF_MODE = 0,
+ MR_IOPS_PERF_MODE = 1,
+ MR_LATENCY_PERF_MODE = 2,
+};
+
+#define MEGASAS_PERF_MODE_2STR(mode) \
+ ((mode) == MR_BALANCED_PERF_MODE ? "Balanced" : \
+ (mode) == MR_IOPS_PERF_MODE ? "IOPs" : \
+ (mode) == MR_LATENCY_PERF_MODE ? "Latency": \
+ "Unknown")
+
+#define MEGASAS_PCIE_SPEED2STR(speed) \
+ ((speed) == MEGASAS_PCIE_SPEED_16_0GT ? "16 GT/s" : \
+ (speed) == MEGASAS_PCIE_SPEED_8_0GT ? "8 GT/s" : \
+ (speed) == MEGASAS_PCIE_SPEED_5_0GT ? "5 GT/s" : \
+ (speed) == MEGASAS_PCIE_SPEED_2_5GT ? "2.5 GT/s" : \
+ "Unknown speed")
+
u8
MR_BuildRaidContext(struct megasas_instance *instance,
struct IO_REQUEST_INFO *io_info,
@@ -2700,9 +2776,14 @@ void megasas_fusion_stop_watchdog(struct megasas_instance *instance);
void megasas_set_dma_settings(struct megasas_instance *instance,
struct megasas_dcmd_frame *dcmd,
dma_addr_t dma_addr, u32 dma_len);
+unsigned int megasas_get_irq(struct megasas_instance *instance, int msix_index);
+#if defined(ENABLE_IRQ_POLL)
+extern int megasas_irqpoll(struct irq_poll *irqpoll, int budget);
+#endif
+void megasas_dump_fusion_io(struct scsi_cmnd *scmd);
int megasas_adp_reset_wait_for_ready(struct megasas_instance *instance,
bool do_adp_reset,
int ocr_context);
-int megasas_irqpoll(struct irq_poll *irqpoll, int budget);
-void megasas_dump_fusion_io(struct scsi_cmnd *scmd);
+int megasas_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num);
+
#endif /*LSI_MEGARAID_SAS_H */
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index b9c1f722f..ee2b31c01 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -1,10 +1,22 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Linux MegaRAID driver for SAS based RAID controllers
*
- * Copyright (c) 2003-2013 LSI Corporation
- * Copyright (c) 2013-2016 Avago Technologies
- * Copyright (c) 2016-2018 Broadcom Inc.
+ * Copyright (c) 2003-2018 LSI Corporation.
+ * Copyright (c) 2003-2018 Avago Technologies.
+ * Copyright (c) 2003-2018 Broadcom Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
*
* Authors: Broadcom Inc.
* Sreenivas Bagalkote
@@ -17,6 +29,7 @@
* Send feedback to: megaraidlinux.pdl@broadcom.com
*/
+#include
#include
#include
#include
@@ -36,7 +49,6 @@
#include
#include
#include
-#include
#include
#include
@@ -44,6 +56,7 @@
#include
#include
#include
+
#include "megaraid_sas_fusion.h"
#include "megaraid_sas.h"
@@ -93,6 +106,9 @@ unsigned int scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT;
module_param(scmd_timeout, int, 0444);
MODULE_PARM_DESC(scmd_timeout, "scsi command timeout (10-90s), default 90s. See megasas_reset_timer.");
+int crashdump_enable = 1;
+module_param(crashdump_enable, int, 0444);
+MODULE_PARM_DESC(crashdump_enable, "Firmware Crash dump feature enable/disbale Default: enable(1)");
int perf_mode = -1;
module_param(perf_mode, int, 0444);
MODULE_PARM_DESC(perf_mode, "Performance mode (only for Aero adapters), options:\n\t\t"
@@ -109,10 +125,43 @@ int event_log_level = MFI_EVT_CLASS_CRITICAL;
module_param(event_log_level, int, 0644);
MODULE_PARM_DESC(event_log_level, "Asynchronous event logging level- range is: -2(CLASS_DEBUG) to 4(CLASS_DEAD), Default: 2(CLASS_CRITICAL)");
+int disable_ext_io;
+module_param(disable_ext_io, int, 0444);
+MODULE_PARM_DESC(disable_ext_io, "Disable 1M IO support Default: 0(1M IO enabled)");
+
unsigned int enable_sdev_max_qd;
module_param(enable_sdev_max_qd, int, 0444);
MODULE_PARM_DESC(enable_sdev_max_qd, "Enable sdev max qd as can_queue. Default: 0");
+int poll_queues;
+module_param(poll_queues, int, 0444);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,12,0))
+MODULE_PARM_DESC(poll_queues, "Number of queues to be use for io_uring poll mode.\n\t\t"
+ "This parameter is effective only if host_tagset_enable=1 &\n\t\t"
+ "It is not applicable for MFI_SERIES. &\n\t\t"
+ "Driver will work in latency mode. &\n\t\t"
+ "High iops queues are not allocated &\n\t\t"
+ );
+#else
+MODULE_PARM_DESC(poll_queues, "Not supported for this kernel.");
+#endif
+
+#if defined(HOST_TAGSET_SUPPORT)
+
+#if ((defined(RHEL_MAJOR) && (RHEL_MAJOR == 8) && (RHEL_MINOR > 5)) || \
+ (LINUX_VERSION_CODE >= KERNEL_VERSION(5,16,0)))
+int host_tagset_enable = 1;
+module_param(host_tagset_enable, int, 0444);
+MODULE_PARM_DESC(host_tagset_enable, "Shared host tagset enable/disable Default: enable(1)");
+#else
+int host_tagset_enable = 0;
+module_param(host_tagset_enable, int, 0444);
+MODULE_PARM_DESC(host_tagset_enable, "Shared host tagset enable/disable Default: disable(0)\n\t\t"
+ "Enabling Shared host tagset is experimental.");
+#endif
+
+#endif
+
MODULE_LICENSE("GPL");
MODULE_VERSION(MEGASAS_VERSION);
MODULE_AUTHOR("megaraidlinux.pdl@broadcom.com");
@@ -200,8 +249,8 @@ static bool support_pci_lane_margining;
/* define lock for aen poll */
spinlock_t poll_aen_lock;
-
extern struct dentry *megasas_debugfs_root;
+extern int megasas_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num);
extern void megasas_init_debugfs(void);
extern void megasas_exit_debugfs(void);
extern void megasas_setup_debugfs(struct megasas_instance *instance);
@@ -210,6 +259,7 @@ extern void megasas_destroy_debugfs(struct megasas_instance *instance);
void
megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
u8 alt_status);
+void megasas_free_irq_vectors(struct megasas_instance *instance);
static u32
megasas_read_fw_status_reg_gen2(struct megasas_instance *instance);
static int
@@ -257,6 +307,7 @@ u32 megasas_readl(struct megasas_instance *instance,
ret_val = readl(addr);
i++;
} while (ret_val == 0 && i < 3);
+
return ret_val;
} else {
return readl(addr);
@@ -413,8 +464,9 @@ megasas_decode_evt(struct megasas_instance *instance)
class_locale.word = le32_to_cpu(evt_detail->cl.word);
if ((event_log_level < MFI_EVT_CLASS_DEBUG) ||
- (event_log_level > MFI_EVT_CLASS_DEAD)) {
- printk(KERN_WARNING "megaraid_sas: provided event log level is out of range, setting it to default 2(CLASS_CRITICAL), permissible range is: -2 to 4\n");
+ (event_log_level > MFI_EVT_CLASS_DEAD)) {
+ pr_warn("megaraid_sas: provided event log level is out of range, setting"
+ " it to default 2(CLASS_CRITICAL), permissible range is: -2 to 4\n");
event_log_level = MFI_EVT_CLASS_CRITICAL;
}
@@ -425,6 +477,13 @@ megasas_decode_evt(struct megasas_instance *instance)
(class_locale.members.locale),
format_class(class_locale.members.class),
evt_detail->description);
+
+
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ dev_info(&instance->pdev->dev,
+ "evt_detail.args.ld.target_id/index %d/%d\n",
+ evt_detail->args.ld.target_id, evt_detail->args.ld.ld_index);
+
}
/**
@@ -842,6 +901,10 @@ megasas_fire_cmd_skinny(struct megasas_instance *instance,
&(regs)->inbound_high_queue_port);
writel((lower_32_bits(frame_phys_addr) | (frame_count<<1))|1,
&(regs)->inbound_low_queue_port);
+#if !((defined(RHEL_MAJOR) && (RHEL_MAJOR == 8) && (RHEL_MINOR >= 2)) || \
+ (LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0)))
+ mmiowb();
+#endif
spin_unlock_irqrestore(&instance->hba_lock, flags);
}
@@ -1099,7 +1162,7 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
dev_err(&instance->pdev->dev, "Failed from %s %d\n",
__func__, __LINE__);
- return DCMD_NOT_FIRED;
+ return DCMD_INIT;
}
instance->instancet->issue_dcmd(instance, cmd);
@@ -1123,19 +1186,19 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
struct megasas_cmd *cmd, int timeout)
{
int ret = 0;
- cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
+ cmd->cmd_status_drv = DCMD_INIT;
if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
dev_err(&instance->pdev->dev, "Failed from %s %d\n",
__func__, __LINE__);
- return DCMD_NOT_FIRED;
+ return DCMD_INIT;
}
instance->instancet->issue_dcmd(instance, cmd);
if (timeout) {
ret = wait_event_timeout(instance->int_cmd_wait_q,
- cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS, timeout * HZ);
+ cmd->cmd_status_drv != DCMD_INIT, timeout * HZ);
if (!ret) {
dev_err(&instance->pdev->dev,
"DCMD(opcode: 0x%x) is timed out, func:%s\n",
@@ -1144,10 +1207,9 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
}
} else
wait_event(instance->int_cmd_wait_q,
- cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS);
+ cmd->cmd_status_drv != DCMD_INIT);
- return (cmd->cmd_status_drv == MFI_STAT_OK) ?
- DCMD_SUCCESS : DCMD_FAILED;
+ return cmd->cmd_status_drv;
}
/**
@@ -1190,35 +1252,33 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
cpu_to_le32(upper_32_bits(cmd_to_abort->frame_phys_addr));
cmd->sync_cmd = 1;
- cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
+ cmd->cmd_status_drv = DCMD_INIT;
if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
dev_err(&instance->pdev->dev, "Failed from %s %d\n",
__func__, __LINE__);
- return DCMD_NOT_FIRED;
+ return DCMD_INIT;
}
instance->instancet->issue_dcmd(instance, cmd);
if (timeout) {
ret = wait_event_timeout(instance->abort_cmd_wait_q,
- cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS, timeout * HZ);
+ cmd->cmd_status_drv != DCMD_INIT, timeout * HZ);
if (!ret) {
opcode = cmd_to_abort->frame->dcmd.opcode;
- dev_err(&instance->pdev->dev,
- "Abort(to be aborted DCMD opcode: 0x%x) is timed out func:%s\n",
- opcode, __func__);
+ dev_err(&instance->pdev->dev, "Abort(to be aborted DCMD opcode: 0x%x)"
+ " is timed out func:%s\n", opcode, __func__);
return DCMD_TIMEOUT;
}
} else
wait_event(instance->abort_cmd_wait_q,
- cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS);
+ cmd->cmd_status_drv != DCMD_INIT);
cmd->sync_cmd = 0;
megasas_return_cmd(instance, cmd);
- return (cmd->cmd_status_drv == MFI_STAT_OK) ?
- DCMD_SUCCESS : DCMD_FAILED;
+ return cmd->cmd_status_drv;
}
/**
@@ -1759,6 +1819,7 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
{
struct megasas_instance *instance;
struct MR_PRIV_DEVICE *mr_device_priv_data;
+ u32 ld_tgt_id;
instance = (struct megasas_instance *)
scmd->device->host->hostdata;
@@ -1785,17 +1846,22 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
}
}
- if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
+ mr_device_priv_data = scmd->device->hostdata;
+
+ if (!mr_device_priv_data ||
+ (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)) {
scmd->result = DID_NO_CONNECT << 16;
scmd->scsi_done(scmd);
return 0;
}
- mr_device_priv_data = scmd->device->hostdata;
- if (!mr_device_priv_data) {
- scmd->result = DID_NO_CONNECT << 16;
- scmd->scsi_done(scmd);
- return 0;
+ if (MEGASAS_IS_LOGICAL(scmd->device)) {
+ ld_tgt_id = MEGASAS_TARGET_ID(scmd->device);
+ if (instance->ld_tgtid_status[ld_tgt_id] == LD_TARGET_ID_DELETED) {
+ scmd->result = DID_NO_CONNECT << 16;
+ scmd->scsi_done(scmd);
+ return 0;
+ }
}
if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
@@ -1887,6 +1953,8 @@ void megasas_set_dynamic_target_properties(struct scsi_device *sdev,
mr_device_priv_data->is_tm_capable =
raid->capability.tmCapable;
+ mr_device_priv_data->is_epd =
+ raid->flags.isEPD;
} else if (instance->use_seqnum_jbod_fp) {
pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
sdev->id;
@@ -1898,21 +1966,59 @@ void megasas_set_dynamic_target_properties(struct scsi_device *sdev,
if (is_target_prop && instance->tgt_prop->reset_tmo) {
/*
- * If FW provides a target reset timeout value, driver will use
- * it. If not set, fallback to default values.
+ * FW provides a non-zero reset_tmo for NVMe EPD only.
+ * For rest of the cases, set the timeout values to default.
*/
mr_device_priv_data->target_reset_tmo =
min_t(u8, instance->max_reset_tmo,
instance->tgt_prop->reset_tmo);
mr_device_priv_data->task_abort_tmo = instance->task_abort_tmo;
} else {
- mr_device_priv_data->target_reset_tmo =
- MEGASAS_DEFAULT_TM_TIMEOUT;
- mr_device_priv_data->task_abort_tmo =
- MEGASAS_DEFAULT_TM_TIMEOUT;
+ mr_device_priv_data->target_reset_tmo = MEGASAS_DEFAULT_TM_TIMEOUT;
+ mr_device_priv_data->task_abort_tmo = MEGASAS_DEFAULT_TM_TIMEOUT;
}
}
+inline void megasas_update_device_queue_depth(struct scsi_device *sdev,
+ u32 queue_depth)
+{
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0))
+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), queue_depth);
+#else
+ scsi_change_queue_depth(sdev, queue_depth);
+#endif
+}
+
+/**
+ * megasas_blk_limits_max_hw_sectors - set hard and soft limit of max sectors for request
+ * @limits: the queue limits
+ * @max_hw_sectors: max hardware sectors in the usual 512b unit
+ */
+void megasas_blk_limits_max_hw_sectors(struct queue_limits *limits, unsigned int max_hw_sectors)
+{
+ if ((max_hw_sectors << 9) < PAGE_SIZE) {
+ max_hw_sectors = 1 << (PAGE_SHIFT - 9);
+ printk(KERN_INFO "%s: set to minimum %d\n",
+ __func__, max_hw_sectors);
+ }
+
+ limits->max_hw_sectors = max_hw_sectors;
+ limits->max_sectors = min_t(unsigned int, max_hw_sectors,
+ 1024);
+}
+
+/**
+ * megasas_queue_flag_set - atomically set a queue flag
+ *
+ * @flag: flag to be set
+ * @q: request queue
+ */
+static inline void
+megasas_queue_flag_set(unsigned int flag, struct request_queue *q)
+{
+ set_bit(flag, &q->queue_flags);
+}
+
/*
* megasas_set_nvme_device_properties -
* set nomerges=2
@@ -1939,12 +2045,11 @@ megasas_set_nvme_device_properties(struct scsi_device *sdev, u32 max_io_size)
mr_nvme_pg_size = max_t(u32, instance->nvme_page_size,
MR_DEFAULT_NVME_PAGE_SIZE);
- blk_queue_max_hw_sectors(sdev->request_queue, (max_io_size / 512));
+ megasas_blk_limits_max_hw_sectors(&sdev->request_queue->limits,
+ (max_io_size / 512));
- blk_queue_flag_set(QUEUE_FLAG_NOMERGES, sdev->request_queue);
blk_queue_virt_boundary(sdev->request_queue, mr_nvme_pg_size - 1);
}
-
/*
* megasas_set_fw_assisted_qd -
* set device queue depth to can_queue
@@ -1964,6 +2069,7 @@ static void megasas_set_fw_assisted_qd(struct scsi_device *sdev,
instance = megasas_lookup_instance(sdev->host->host_no);
mr_device_priv_data = sdev->hostdata;
+
interface_type = mr_device_priv_data->interface_type;
switch (interface_type) {
@@ -1980,15 +2086,16 @@ static void megasas_set_fw_assisted_qd(struct scsi_device *sdev,
if (is_target_prop) {
tgt_device_qd = le32_to_cpu(instance->tgt_prop->device_qdepth);
- if (tgt_device_qd &&
- (tgt_device_qd <= instance->host->can_queue))
- device_qd = tgt_device_qd;
+ if (tgt_device_qd)
+ device_qd = min(instance->host->can_queue, (int)tgt_device_qd);
}
- if (instance->enable_sdev_max_qd && interface_type != UNKNOWN_DRIVE)
+ if (instance->enable_sdev_max_qd &&
+ (MEGASAS_IS_LOGICAL(sdev) || (interface_type != UNKNOWN_DRIVE))) {
device_qd = instance->host->can_queue;
+ }
- scsi_change_queue_depth(sdev, device_qd);
+ megasas_update_device_queue_depth(sdev, device_qd);
}
/*
@@ -2035,6 +2142,7 @@ static int megasas_slave_configure(struct scsi_device *sdev)
struct megasas_instance *instance;
int ret_target_prop = DCMD_FAILED;
bool is_target_prop = false;
+ struct MR_PRIV_DEVICE *mr_device_priv_data;
instance = megasas_lookup_instance(sdev->host->host_no);
if (instance->pd_list_not_supported) {
@@ -2064,6 +2172,10 @@ static int megasas_slave_configure(struct scsi_device *sdev)
/* This sdev property may change post OCR */
megasas_set_dynamic_target_properties(sdev, is_target_prop);
+ mr_device_priv_data = sdev->hostdata;
+ if (!mr_device_priv_data->is_epd && MEGASAS_IS_LOGICAL(sdev))
+ sdev->no_write_same = 1;
+
mutex_unlock(&instance->reset_mutex);
return 0;
@@ -2071,7 +2183,7 @@ static int megasas_slave_configure(struct scsi_device *sdev)
static int megasas_slave_alloc(struct scsi_device *sdev)
{
- u16 pd_index = 0;
+ u16 pd_index = 0, ld_tgt_id;
struct megasas_instance *instance ;
struct MR_PRIV_DEVICE *mr_device_priv_data;
@@ -2089,6 +2201,9 @@ static int megasas_slave_alloc(struct scsi_device *sdev)
goto scan_target;
}
return -ENXIO;
+ } else if (!MEGASAS_IS_LUN_VALID(sdev)) {
+ sdev_printk(KERN_INFO, sdev, "%s: invalid LUN\n", __func__);
+ return -ENXIO;
}
scan_target:
@@ -2096,19 +2211,65 @@ scan_target:
GFP_KERNEL);
if (!mr_device_priv_data)
return -ENOMEM;
- sdev->hostdata = mr_device_priv_data;
+ if (MEGASAS_IS_LOGICAL(sdev)) {
+ ld_tgt_id = MEGASAS_TARGET_ID(sdev);
+ instance->ld_tgtid_status[ld_tgt_id] = LD_TARGET_ID_ACTIVE;
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ sdev_printk(KERN_INFO, sdev, "LD target ID %d created. \n", ld_tgt_id);
+ }
+
+ sdev->hostdata = mr_device_priv_data;
+
atomic_set(&mr_device_priv_data->r1_ldio_hint,
instance->r1_ldio_hint_default);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0))
+ sdev->tagged_supported = 1;
+ scsi_activate_tcq(sdev, sdev->queue_depth);
+#endif
+
return 0;
}
static void megasas_slave_destroy(struct scsi_device *sdev)
{
+ u16 ld_tgt_id;
+ struct megasas_instance *instance;
+
+ instance = megasas_lookup_instance(sdev->host->host_no);
+
+ if (MEGASAS_IS_LOGICAL(sdev)) {
+ if (!MEGASAS_IS_LUN_VALID(sdev)) {
+ sdev_printk(KERN_INFO, sdev, "%s: invalid LUN\n", __func__);
+ return;
+ }
+ ld_tgt_id = MEGASAS_TARGET_ID(sdev);
+ instance->ld_tgtid_status[ld_tgt_id] = LD_TARGET_ID_DELETED;
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ sdev_printk(KERN_INFO, sdev,
+ "LD target ID %d removed from OS stack \n", ld_tgt_id);
+ }
+
kfree(sdev->hostdata);
sdev->hostdata = NULL;
}
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0))
+static int megasas_change_queue_depth(struct scsi_device *sdev,
+ int queue_depth, int reason)
+{
+ if (reason != SCSI_QDEPTH_DEFAULT)
+ return -EOPNOTSUPP;
+
+ if (queue_depth > sdev->host->can_queue)
+ queue_depth = sdev->host->can_queue;
+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev),
+ queue_depth);
+
+ return queue_depth;
+}
+#endif
+
/*
* megasas_complete_outstanding_ioctls - Complete outstanding ioctls after a
* kill adapter
@@ -2150,6 +2311,16 @@ static void megasas_complete_outstanding_ioctls(struct megasas_instance *instanc
void megaraid_sas_kill_hba(struct megasas_instance *instance)
{
+ dev_warn(&instance->pdev->dev,
+ "Kill HBA from %s %d\n", __func__, __LINE__);
+
+ /* If adapter is already declared dead, do not issue kill HBA again */
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
+ dev_warn(&instance->pdev->dev,
+ "Adapter already dead, skipping kill HBA\n");
+ return;
+ }
+
/* Set critical error to block I/O & ioctls in case caller didn't */
atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
/* Wait 1 second to ensure IO or ioctls in build have posted */
@@ -2249,7 +2420,11 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
megasas_check_and_restore_queue_depth(instance);
}
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0))
+static void megasas_sriov_heartbeat_handler(unsigned long instance_addr);
+#else
static void megasas_sriov_heartbeat_handler(struct timer_list *t);
+#endif
/**
* megasas_start_timer - Initializes sriov heartbeat timer object
@@ -2259,8 +2434,13 @@ static void megasas_sriov_heartbeat_handler(struct timer_list *t);
void megasas_start_timer(struct megasas_instance *instance)
{
struct timer_list *timer = &instance->sriov_heartbeat_timer;
-
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0))
+ init_timer(timer);
+ timer->data = (unsigned long)instance;
+ timer->function = megasas_sriov_heartbeat_handler;
+#else
timer_setup(timer, megasas_sriov_heartbeat_handler, 0);
+#endif
timer->expires = jiffies + MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF;
add_timer(timer);
}
@@ -2330,6 +2510,8 @@ static int megasas_get_ld_vf_affiliation_111(struct megasas_instance *instance,
megasas_return_cmd(instance, cmd);
return -ENOMEM;
}
+ memset(new_affiliation_111, 0,
+ sizeof(struct MR_LD_VF_AFFILIATION_111));
}
memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
@@ -2437,6 +2619,8 @@ static int megasas_get_ld_vf_affiliation_12(struct megasas_instance *instance,
megasas_return_cmd(instance, cmd);
return -ENOMEM;
}
+ memset(new_affiliation, 0, (MAX_LOGICAL_DRIVES + 1) *
+ sizeof(struct MR_LD_VF_AFFILIATION));
}
memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
@@ -2603,6 +2787,8 @@ int megasas_sriov_start_heartbeat(struct megasas_instance *instance,
retval = -ENOMEM;
goto out;
}
+ memset(instance->hb_host_mem, 0,
+ sizeof(struct MR_CTRL_HB_HOST_MEM));
}
memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
@@ -2645,11 +2831,17 @@ out:
}
/* Handler for SR-IOV heartbeat */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0))
+static void megasas_sriov_heartbeat_handler(unsigned long instance_addr)
+{
+ struct megasas_instance *instance =
+ (struct megasas_instance *)instance_addr;
+#else
static void megasas_sriov_heartbeat_handler(struct timer_list *t)
{
struct megasas_instance *instance =
from_timer(instance, t, sriov_heartbeat_timer);
-
+#endif
if (instance->hb_host_mem->HB.fwCounter !=
instance->hb_host_mem->HB.driverCounter) {
instance->hb_host_mem->HB.driverCounter =
@@ -2726,7 +2918,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
"reset queue\n",
reset_cmd);
- reset_cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
+ reset_cmd->cmd_status_drv = DCMD_INIT;
instance->instancet->fire_cmd(instance,
reset_cmd->frame_phys_addr,
0, instance->reg_set);
@@ -2864,7 +3056,11 @@ blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
if (time_after(jiffies, scmd->jiffies_at_alloc +
(scmd_timeout * 2) * HZ)) {
- return BLK_EH_DONE;
+ /* BLK_EH_NOT_HANDLED and BLK_EH_DONE are macros provided by
+ * different kernels for return value, as both macros are defined as 0
+ * so returning 0 to avoid kernel version based checks.
+ */
+ return 0;
}
instance = (struct megasas_instance *)scmd->device->host->hostdata;
@@ -2878,16 +3074,18 @@ blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
spin_unlock_irqrestore(instance->host->host_lock, flags);
}
+
return BLK_EH_RESET_TIMER;
}
/**
- * megasas_dump - This function will print hexdump of provided buffer.
- * @buf: Buffer to be dumped
- * @sz: Size in bytes
- * @format: Different formats of dumping e.g. format=n will
- * cause only 'n' 32 bit words to be dumped in a single
- * line.
+ * megasas_dump - This function will print hexdump of provided
+ * buffer.
+ * buf- Buffer to be dumped
+ * sz- Size in bytes
+ * format- Different formats of dumping e.g. format=n will
+ * cause only 'n' 32 bit words to be dumped in a single
+ * line.
*/
inline void
megasas_dump(void *buf, int sz, int format)
@@ -2906,28 +3104,28 @@ megasas_dump(void *buf, int sz, int format)
printk(KERN_CONT "\n");
}
-/**
- * megasas_dump_reg_set - This function will print hexdump of register set
- * @buf: Buffer to be dumped
- * @sz: Size in bytes
- * @format: Different formats of dumping e.g. format=n will
- * cause only 'n' 32 bit words to be dumped in a
- * single line.
+/*
+ * megasas_dump_reg_set - This function will print hexdump of register set
+ * @buf: Buffer to be dumped
+ * @sz: Size in bytes
+ * @format: Different formats of dumping e.g. format=n will
+ * cause only 'n' 32 bit words to be dumped in a
+ * single line.
*/
inline void
megasas_dump_reg_set(void __iomem *reg_set)
{
- unsigned int i, sz = 256;
- u32 __iomem *reg = (u32 __iomem *)reg_set;
+ unsigned int i, sz = 256;
+ u32 __iomem *reg = (u32 __iomem *)reg_set;
- for (i = 0; i < (sz / sizeof(u32)); i++)
- printk("%08x: %08x\n", (i * 4), readl(®[i]));
+ for (i = 0; i < (sz / sizeof(u32)); i++)
+ printk("%08x: %08x\n", (i * 4), readl(®[i]));
}
/**
* megasas_dump_fusion_io - This function will print key details
- * of SCSI IO
- * @scmd: SCSI command pointer of SCSI IO
+ * of SCSI IO
+ * scmd- SCSI command pointer of SCSI IO
*/
void
megasas_dump_fusion_io(struct scsi_cmnd *scmd)
@@ -2935,40 +3133,40 @@ megasas_dump_fusion_io(struct scsi_cmnd *scmd)
struct megasas_cmd_fusion *cmd;
union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
struct megasas_instance *instance;
-
+
cmd = (struct megasas_cmd_fusion *)scmd->SCp.ptr;
instance = (struct megasas_instance *)scmd->device->host->hostdata;
-
+
scmd_printk(KERN_INFO, scmd,
- "scmd: (0x%p) retries: 0x%x allowed: 0x%x\n",
- scmd, scmd->retries, scmd->allowed);
+ "scmd: (0x%p) retries: 0x%x allowed: 0x%x\n",
+ scmd, scmd->retries, scmd->allowed);
scsi_print_command(scmd);
if (cmd) {
req_desc = (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)cmd->request_desc;
scmd_printk(KERN_INFO, scmd, "Request descriptor details:\n");
- scmd_printk(KERN_INFO, scmd,
- "RequestFlags:0x%x MSIxIndex:0x%x SMID:0x%x LMID:0x%x DevHandle:0x%x\n",
- req_desc->SCSIIO.RequestFlags,
- req_desc->SCSIIO.MSIxIndex, req_desc->SCSIIO.SMID,
- req_desc->SCSIIO.LMID, req_desc->SCSIIO.DevHandle);
+ scmd_printk(KERN_INFO, scmd, "RequestFlags:0x%x "
+ "MSIxIndex:0x%x SMID:0x%x LMID:0x%x DevHandle:0x%x\n",
+ req_desc->SCSIIO.RequestFlags,req_desc->SCSIIO.MSIxIndex,
+ req_desc->SCSIIO.SMID, req_desc->SCSIIO.LMID,
+ req_desc->SCSIIO.DevHandle);
printk(KERN_INFO "IO request frame:\n");
megasas_dump(cmd->io_request,
- MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE, 8);
+ MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE, 8);
printk(KERN_INFO "Chain frame:\n");
megasas_dump(cmd->sg_frame,
- instance->max_chain_frame_sz, 8);
+ instance->max_chain_frame_sz, 8);
}
}
/*
- * megasas_dump_sys_regs - This function will dump system registers through
- * sysfs.
- * @reg_set: Pointer to System register set.
- * @buf: Buffer to which output is to be written.
- * @return: Number of bytes written to buffer.
+ * megasas_dump_sys_regs -This function will dump system registers through
+ * sysfs.
+ * reg_set- Pointer to System register set.
+ * buf- Buffer to which output is to be written.
+ * return- Number of bytes written to buffer.
*/
static inline ssize_t
megasas_dump_sys_regs(void __iomem *reg_set, char *buf)
@@ -2985,7 +3183,6 @@ megasas_dump_sys_regs(void __iomem *reg_set, char *buf)
}
return bytes_wrote;
}
-
/**
* megasas_reset_bus_host - Bus & host reset handler entry point
*/
@@ -2998,11 +3195,11 @@ static int megasas_reset_bus_host(struct scsi_cmnd *scmd)
scmd_printk(KERN_INFO, scmd,
"OCR is requested due to IO timeout!!\n");
-
+
scmd_printk(KERN_INFO, scmd,
- "SCSI host state: %d SCSI host busy: %d FW outstanding: %d\n",
+ "SCSI host state: %d "
+ "FW outstanding: %d\n",
scmd->device->host->shost_state,
- scsi_host_busy(scmd->device->host),
atomic_read(&instance->fw_outstanding));
/*
* First wait for all commands to complete
@@ -3106,6 +3303,48 @@ megasas_bios_param(struct scsi_device *sdev, struct block_device *bdev,
return 0;
}
+#if defined(HOST_TAGSET_SUPPORT)
+static int megasas_map_queues(struct Scsi_Host *shost)
+{
+ struct megasas_instance *instance;
+ int qoff, offset;
+ struct blk_mq_queue_map *map;
+
+ instance = (struct megasas_instance *)shost->hostdata;
+
+ if (shost->nr_hw_queues == 1)
+ return 0;
+
+ offset = instance->low_latency_index_start;
+ qoff = 0;
+
+ /* Setup Default hctx */
+ map = &shost->tag_set.map[HCTX_TYPE_DEFAULT];
+ map->nr_queues = instance->msix_vectors - offset;
+ map->queue_offset = 0;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0))
+ return blk_mq_pci_map_queues(map, instance->pdev, offset);
+#else
+ blk_mq_pci_map_queues(map, instance->pdev, offset);
+ qoff += map->nr_queues;
+
+ /* Setup Poll hctx */
+ map = &shost->tag_set.map[HCTX_TYPE_POLL];
+ map->nr_queues = instance->iopoll_q_count;
+ if (map->nr_queues) {
+ /*
+ * The poll queue(s) doesn't have an IRQ (and hence IRQ
+ * affinity), so use the regular blk-mq cpu mapping
+ */
+ map->queue_offset = qoff;
+ blk_mq_map_queues(map);
+ }
+ return 0;
+#endif
+}
+
+#endif
+
static void megasas_aen_polling(struct work_struct *work);
/**
@@ -3160,7 +3399,7 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
}
static ssize_t
-fw_crash_buffer_store(struct device *cdev,
+megasas_fw_crash_buffer_store(struct device *cdev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3179,7 +3418,7 @@ fw_crash_buffer_store(struct device *cdev,
}
static ssize_t
-fw_crash_buffer_show(struct device *cdev,
+megasas_fw_crash_buffer_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3203,6 +3442,7 @@ fw_crash_buffer_show(struct device *cdev,
return -EINVAL;
}
+
if (buff_offset > (instance->fw_crash_buffer_size * dmachunk)) {
dev_err(&instance->pdev->dev,
"Firmware crash dump offset is out of range\n");
@@ -3224,7 +3464,7 @@ fw_crash_buffer_show(struct device *cdev,
}
static ssize_t
-fw_crash_buffer_size_show(struct device *cdev,
+megasas_fw_crash_buffer_size_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3236,7 +3476,7 @@ fw_crash_buffer_size_show(struct device *cdev,
}
static ssize_t
-fw_crash_state_store(struct device *cdev,
+megasas_fw_crash_state_store(struct device *cdev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3271,7 +3511,7 @@ fw_crash_state_store(struct device *cdev,
}
static ssize_t
-fw_crash_state_show(struct device *cdev,
+megasas_fw_crash_state_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3282,14 +3522,14 @@ fw_crash_state_show(struct device *cdev,
}
static ssize_t
-page_size_show(struct device *cdev,
+megasas_page_size_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long)PAGE_SIZE - 1);
}
static ssize_t
-ldio_outstanding_show(struct device *cdev, struct device_attribute *attr,
+megasas_ldio_outstanding_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3299,7 +3539,7 @@ ldio_outstanding_show(struct device *cdev, struct device_attribute *attr,
}
static ssize_t
-fw_cmds_outstanding_show(struct device *cdev,
+megasas_fw_cmds_outstanding_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3309,18 +3549,47 @@ fw_cmds_outstanding_show(struct device *cdev,
}
static ssize_t
-enable_sdev_max_qd_show(struct device *cdev,
- struct device_attribute *attr, char *buf)
+megasas_ldio_hint_count_store(struct device *cdev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata;
+ u32 val = 0;
+
+ sscanf(buf, "%u", &val);
+
+ if (val < 4 || val > 16)
+ instance->r1_ldio_hint_default = MR_R1_LDIO_PIGGYBACK_DEFAULT;
+ else
+ instance->r1_ldio_hint_default = val;
+
+ return strlen(buf);
+}
+
+static ssize_t
+megasas_ldio_hint_count_show(struct device *cdev, struct device_attribute *attr,
+ char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata;
- return snprintf(buf, PAGE_SIZE, "%d\n", instance->enable_sdev_max_qd);
+ return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long) instance->r1_ldio_hint_default);
}
static ssize_t
-enable_sdev_max_qd_store(struct device *cdev,
- struct device_attribute *attr, const char *buf, size_t count)
+megasas_enable_sdev_max_qd_show(struct device *cdev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata;
+
+ return snprintf(buf, PAGE_SIZE, "%ld\n",
+ (unsigned long) instance->enable_sdev_max_qd);
+}
+
+static ssize_t
+megasas_enable_sdev_max_qd_store(struct device *cdev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct Scsi_Host *shost = class_to_shost(cdev);
struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata;
@@ -3328,7 +3597,7 @@ enable_sdev_max_qd_store(struct device *cdev,
bool is_target_prop;
int ret_target_prop = DCMD_FAILED;
struct scsi_device *sdev;
-
+
if (kstrtou32(buf, 0, &val) != 0) {
pr_err("megasas: could not set enable_sdev_max_qd\n");
return -EINVAL;
@@ -3339,7 +3608,7 @@ enable_sdev_max_qd_store(struct device *cdev,
instance->enable_sdev_max_qd = true;
else
instance->enable_sdev_max_qd = false;
-
+
shost_for_each_device(sdev, shost) {
ret_target_prop = megasas_get_target_prop(instance, sdev);
is_target_prop = (ret_target_prop == DCMD_SUCCESS) ? true : false;
@@ -3351,37 +3620,47 @@ enable_sdev_max_qd_store(struct device *cdev,
}
static ssize_t
-dump_system_regs_show(struct device *cdev,
- struct device_attribute *attr, char *buf)
+megasas_dump_system_regs_show(struct device *cdev, struct device_attribute *attr,
+ char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
- struct megasas_instance *instance =
- (struct megasas_instance *)shost->hostdata;
-
+ struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata;
return megasas_dump_sys_regs(instance->reg_set, buf);
+
}
static ssize_t
-raid_map_id_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
+megasas_raid_map_id_show(struct device *cdev, struct device_attribute *attr,
+ char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
- struct megasas_instance *instance =
- (struct megasas_instance *)shost->hostdata;
+ struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata;
+
+ return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long)instance->map_id);
- return snprintf(buf, PAGE_SIZE, "%ld\n",
- (unsigned long)instance->map_id);
}
-static DEVICE_ATTR_RW(fw_crash_buffer);
-static DEVICE_ATTR_RO(fw_crash_buffer_size);
-static DEVICE_ATTR_RW(fw_crash_state);
-static DEVICE_ATTR_RO(page_size);
-static DEVICE_ATTR_RO(ldio_outstanding);
-static DEVICE_ATTR_RO(fw_cmds_outstanding);
-static DEVICE_ATTR_RW(enable_sdev_max_qd);
-static DEVICE_ATTR_RO(dump_system_regs);
-static DEVICE_ATTR_RO(raid_map_id);
+static DEVICE_ATTR(fw_crash_buffer, S_IRUGO | S_IWUSR,
+ megasas_fw_crash_buffer_show, megasas_fw_crash_buffer_store);
+static DEVICE_ATTR(fw_crash_buffer_size, S_IRUGO,
+ megasas_fw_crash_buffer_size_show, NULL);
+static DEVICE_ATTR(fw_crash_state, S_IRUGO | S_IWUSR,
+ megasas_fw_crash_state_show, megasas_fw_crash_state_store);
+static DEVICE_ATTR(page_size, S_IRUGO,
+ megasas_page_size_show, NULL);
+static DEVICE_ATTR(ldio_outstanding, S_IRUGO,
+ megasas_ldio_outstanding_show, NULL);
+static DEVICE_ATTR(fw_cmds_outstanding, S_IRUGO,
+ megasas_fw_cmds_outstanding_show, NULL);
+static DEVICE_ATTR(ldio_hint_count, S_IRUGO | S_IWUSR,
+ megasas_ldio_hint_count_show, megasas_ldio_hint_count_store);
+static DEVICE_ATTR(enable_sdev_max_qd, S_IRUGO | S_IWUSR,
+ megasas_enable_sdev_max_qd_show, megasas_enable_sdev_max_qd_store);
+static DEVICE_ATTR(dump_system_regs, S_IRUGO,
+ megasas_dump_system_regs_show, NULL);
+static DEVICE_ATTR(raid_map_id, S_IRUGO,
+ megasas_raid_map_id_show, NULL);
+
static struct device_attribute *megaraid_host_attrs[] = {
&dev_attr_fw_crash_buffer_size,
@@ -3390,6 +3669,7 @@ static struct device_attribute *megaraid_host_attrs[] = {
&dev_attr_page_size,
&dev_attr_ldio_outstanding,
&dev_attr_fw_cmds_outstanding,
+ &dev_attr_ldio_hint_count,
&dev_attr_enable_sdev_max_qd,
&dev_attr_dump_system_regs,
&dev_attr_raid_map_id,
@@ -3402,7 +3682,7 @@ static struct device_attribute *megaraid_host_attrs[] = {
static struct scsi_host_template megasas_template = {
.module = THIS_MODULE,
- .name = "Avago SAS based MegaRAID driver",
+ .name = "Broadcom SAS based MegaRAID driver",
.proc_name = "megaraid_sas",
.slave_configure = megasas_slave_configure,
.slave_alloc = megasas_slave_alloc,
@@ -3414,9 +3694,20 @@ static struct scsi_host_template megasas_template = {
.eh_timed_out = megasas_reset_timer,
.shost_attrs = megaraid_host_attrs,
.bios_param = megasas_bios_param,
+#if defined(HOST_TAGSET_SUPPORT)
+ .map_queues = megasas_map_queues,
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,12,0))
+ .mq_poll = megasas_blk_mq_poll,
+#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0))
+ .use_clustering = ENABLE_CLUSTERING,
+#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0))
+ .change_queue_depth = megasas_change_queue_depth,
+#else
.change_queue_depth = scsi_change_queue_depth,
- .max_segment_size = 0xffffffff,
- .no_write_same = 1,
+#endif
};
/**
@@ -3432,7 +3723,12 @@ static void
megasas_complete_int_cmd(struct megasas_instance *instance,
struct megasas_cmd *cmd)
{
- cmd->cmd_status_drv = cmd->frame->io.cmd_status;
+
+ if (cmd->cmd_status_drv == DCMD_INIT)
+ cmd->cmd_status_drv =
+ (cmd->frame->io.cmd_status == MFI_STAT_OK) ?
+ DCMD_SUCCESS : DCMD_FAILED;
+
wake_up(&instance->int_cmd_wait_q);
}
@@ -3451,11 +3747,27 @@ megasas_complete_abort(struct megasas_instance *instance,
{
if (cmd->sync_cmd) {
cmd->sync_cmd = 0;
- cmd->cmd_status_drv = 0;
+ cmd->cmd_status_drv = DCMD_SUCCESS;
wake_up(&instance->abort_cmd_wait_q);
}
}
+static void
+megasas_set_ld_removed_by_fw(struct megasas_instance *instance)
+{
+ uint i;
+
+ for (i = 0; (i < MEGASAS_MAX_LD_IDS); i++) {
+ if ((instance->ld_ids_prev[i] != 0xff) &&
+ (instance->ld_ids_from_raidmap[i] == 0xff)) {
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ dev_info(&instance->pdev->dev,
+ "LD target ID %d removed from RAID map\n", i);
+ instance->ld_tgtid_status[i] = LD_TARGET_ID_DELETED;
+ }
+ }
+}
+
/**
* megasas_complete_cmd - Completes a command
* @instance: Adapter soft state
@@ -3506,8 +3818,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
megasas_complete_int_cmd(instance, cmd);
break;
}
- /* fall through */
-
+ /* Fall through */
case MFI_CMD_LD_READ:
case MFI_CMD_LD_WRITE:
@@ -3618,9 +3929,22 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
fusion->fast_path_io = 0;
}
+ /* Below case is for Invader onwards controller.
+ * Driver will know VDs removed by firmware much earlier than
+ * waiting for events. It will allow driver to avoid sending IOs
+ * to the VDs which are removed.
+ *
+ * Without below check, there can be a small window
+ * possible where driver send IOs to the removed VD but FW might have
+ * reused same target id for other VD.
+ */
+ if (instance->adapter_type >= INVADER_SERIES)
+ megasas_set_ld_removed_by_fw(instance);
+
megasas_sync_map_info(instance);
spin_unlock_irqrestore(instance->host->host_lock,
flags);
+
break;
}
if (opcode == MR_DCMD_CTRL_EVENT_GET_INFO ||
@@ -3727,7 +4051,7 @@ megasas_issue_pending_cmds_again(struct megasas_instance *instance)
dev_notice(&instance->pdev->dev, "%p synchronous cmd"
"on the internal reset queue,"
"issue it again.\n", cmd);
- cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
+ cmd->cmd_status_drv = DCMD_INIT;
instance->instancet->fire_cmd(instance,
cmd->frame_phys_addr,
0, instance->reg_set);
@@ -3894,9 +4218,7 @@ megasas_deplete_reply_queue(struct megasas_instance *instance,
instance->reg_set)) == 1) {
return IRQ_HANDLED;
}
-
- mfiStatus = instance->instancet->clear_intr(instance);
- if (mfiStatus == 0) {
+ if ((mfiStatus = instance->instancet->clear_intr(instance)) == 0 ) {
/* Hardware may not set outbound_intr_status in MSI-X mode */
if (!instance->msix_vectors)
return IRQ_NONE;
@@ -4001,9 +4323,10 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
case MFI_STATE_FAULT:
dev_printk(KERN_ERR, &instance->pdev->dev,
- "FW in FAULT state, Fault code:0x%x subcode:0x%x func:%s\n",
- abs_state & MFI_STATE_FAULT_CODE,
- abs_state & MFI_STATE_FAULT_SUBCODE, __func__);
+ "FW in FAULT state, Fault code:0x%x"
+ " subcode:0x%x func:%s\n",
+ abs_state & MFI_STATE_FAULT_CODE,
+ abs_state & MFI_STATE_FAULT_SUBCODE, __func__);
if (ocr) {
max_wait = MEGASAS_RESET_WAIT_TIME;
break;
@@ -4252,7 +4575,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
cmd = instance->cmd_list[i];
- cmd->frame = dma_pool_zalloc(instance->frame_dma_pool,
+ cmd->frame = dma_pool_alloc(instance->frame_dma_pool,
GFP_KERNEL, &cmd->frame_phys_addr);
cmd->sense = dma_pool_alloc(instance->sense_dma_pool,
@@ -4267,7 +4590,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
megasas_teardown_frame_pool(instance);
return -ENOMEM;
}
-
+ memset(cmd->frame, 0, instance->mfi_frame_size);
cmd->frame->io.context = cpu_to_le32(cmd->index);
cmd->frame->io.pad_0 = 0;
if ((instance->adapter_type == MFI_SERIES) && reset_devices)
@@ -4339,7 +4662,6 @@ int megasas_alloc_cmds(struct megasas_instance *instance)
return -ENOMEM;
}
- memset(instance->cmd_list, 0, sizeof(struct megasas_cmd *) *max_cmd);
for (i = 0; i < max_cmd; i++) {
instance->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd),
@@ -4575,7 +4897,7 @@ megasas_get_pd_list(struct megasas_instance *instance)
pd_addr = ci->addr;
if (megasas_dbg_lvl & LD_PD_DEBUG)
dev_info(&instance->pdev->dev, "%s, sysPD count: 0x%x\n",
- __func__, le32_to_cpu(ci->count));
+ __func__, le32_to_cpu(ci->count));
if ((le32_to_cpu(ci->count) >
(MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL)))
@@ -4593,9 +4915,9 @@ megasas_get_pd_list(struct megasas_instance *instance)
MR_PD_STATE_SYSTEM;
if (megasas_dbg_lvl & LD_PD_DEBUG)
dev_info(&instance->pdev->dev,
- "PD%d: targetID: 0x%03x deviceType:0x%x\n",
- pd_index, le16_to_cpu(pd_addr->deviceId),
- pd_addr->scsiDevType);
+ "PD%d: targetID: 0x%03x deviceType:0x%x\n",
+ pd_index, le16_to_cpu(pd_addr->deviceId),
+ pd_addr->scsiDevType);
pd_addr++;
}
@@ -4701,7 +5023,7 @@ megasas_get_ld_list(struct megasas_instance *instance)
case DCMD_SUCCESS:
if (megasas_dbg_lvl & LD_PD_DEBUG)
dev_info(&instance->pdev->dev, "%s, LD count: 0x%x\n",
- __func__, ld_count);
+ __func__, ld_count);
if (ld_count > instance->fw_supported_vd_count)
break;
@@ -4714,8 +5036,8 @@ megasas_get_ld_list(struct megasas_instance *instance)
instance->ld_ids[ids] = ci->ldList[ld_index].ref.targetId;
if (megasas_dbg_lvl & LD_PD_DEBUG)
dev_info(&instance->pdev->dev,
- "LD%d: targetID: 0x%03x\n",
- ld_index, ids);
+ "LD%d: targetID: 0x%03x\n",
+ ld_index, ids);
}
}
@@ -4821,8 +5143,8 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type)
if (megasas_dbg_lvl & LD_PD_DEBUG)
dev_info(&instance->pdev->dev, "%s, LD count: 0x%x\n",
- __func__, tgtid_count);
-
+ __func__, tgtid_count);
+
if ((tgtid_count > (instance->fw_supported_vd_count)))
break;
@@ -4832,7 +5154,7 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type)
instance->ld_ids[ids] = ci->targetId[ld_index];
if (megasas_dbg_lvl & LD_PD_DEBUG)
dev_info(&instance->pdev->dev, "LD%d: targetID: 0x%03x\n",
- ld_index, ci->targetId[ld_index]);
+ ld_index, ci->targetId[ld_index]);
}
break;
@@ -5038,13 +5360,14 @@ static void megasas_update_ext_vd_details(struct megasas_instance *instance)
fusion->drv_map_sz = sizeof(struct MR_DRV_RAID_MAP_ALL);
}
-/*
+/**
* dcmd.opcode - MR_DCMD_CTRL_SNAPDUMP_GET_PROPERTIES
* dcmd.hdr.length - number of bytes to read
* dcmd.sge - Ptr to MR_SNAPDUMP_PROPERTIES
- * Desc: Fill in snapdump properties
- * Status: MFI_STAT_OK- Command successful
+ * Desc: Fill in snapdump properties
+ * Status: MFI_STAT_OK- Command successful
*/
+
void megasas_get_snapdump_properties(struct megasas_instance *instance)
{
int ret = 0;
@@ -5062,12 +5385,13 @@ void megasas_get_snapdump_properties(struct megasas_instance *instance)
cmd = megasas_get_cmd(instance);
if (!cmd) {
- dev_dbg(&instance->pdev->dev, "Failed to get a free cmd\n");
+ dev_err(&instance->pdev->dev, "Failed to get a free cmd"
+ "Fail from %s %d\n", __func__, __LINE__);
return;
}
dcmd = &cmd->frame->dcmd;
-
+
memset(ci, 0, sizeof(*ci));
memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
@@ -5115,12 +5439,14 @@ void megasas_get_snapdump_properties(struct megasas_instance *instance)
__func__, __LINE__);
break;
}
+
}
if (ret != DCMD_TIMEOUT)
megasas_return_cmd(instance, cmd);
}
+
/**
* megasas_get_controller_info - Returns FW's controller structure
* @instance: Adapter soft state
@@ -5209,7 +5535,7 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
instance->snapdump_wait_time =
(ci->properties.on_off_properties2.enable_snap_dump ?
MEGASAS_DEFAULT_SNAP_DUMP_WAIT_TIME : 0);
-
+
instance->enable_fw_dev_list =
ci->properties.on_off_properties2.enable_fw_dev_list;
@@ -5231,10 +5557,10 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
dev_info(&instance->pdev->dev,
"FW provided TM TaskAbort/Reset timeout\t: %d secs/%d secs\n",
instance->task_abort_tmo, instance->max_reset_tmo);
- dev_info(&instance->pdev->dev, "JBOD sequence map support\t: %s\n",
- instance->support_seqnum_jbod_fp ? "Yes" : "No");
dev_info(&instance->pdev->dev, "PCI Lane Margining support\t: %s\n",
instance->support_pci_lane_margining ? "Yes" : "No");
+ dev_info(&instance->pdev->dev, "JBOD sequence map support\t: %s\n",
+ instance->support_seqnum_jbod_fp ? "Yes" : "No");
break;
@@ -5387,6 +5713,18 @@ megasas_issue_init_mfi(struct megasas_instance *instance)
init_frame->cmd = MFI_CMD_INIT;
init_frame->cmd_status = MFI_STAT_INVALID_STATUS;
+
+ if (instance->verbuf) {
+ snprintf((char *)instance->verbuf, strlen(MEGASAS_VERSION) + 2,
+ "%s", MEGASAS_VERSION);
+
+ if (reset_devices)
+ strcat((char *)instance->verbuf, "-kdump");
+
+ init_frame->driver_ver_lo = cpu_to_le32(instance->verbuf_h);
+ init_frame->driver_ver_hi = 0;
+ }
+
init_frame->queue_info_new_phys_addr_lo =
cpu_to_le32(lower_32_bits(initq_info_h));
init_frame->queue_info_new_phys_addr_hi =
@@ -5512,26 +5850,71 @@ fail_alloc_cmds:
return 1;
}
+/**
+ * megasas_get_irq - Return IRQ vector associated with MSI-x index
+ * @instance: Adapter soft state
+ * @msix_index: MSI-x index
+ *
+ * Return IRQ vector associated with passed MSI-x index.
+ */
+inline unsigned int
+megasas_get_irq(struct megasas_instance *instance, int msix_index)
+{
+
+ unsigned int irq;
+#ifndef USE_MANAGED_IRQ_API
+ if (instance->msix_vectors)
+ irq = instance->msixentry[msix_index].vector;
+ else
+ irq = instance->pdev->irq;
+#else
+ irq = pci_irq_vector(instance->pdev, msix_index);
+#endif
+ return irq;
+
+}
+
+/**
+ * megasas_irq_set_affinity_hint - Set IRQ affinity hint for relevant kernels
+ * @msix_vector: MSI-x vector to which IRQ affinity hint
+ * is provided
+ * @mask: CPU mask
+ * return: true: irq_set_affinity_hint successful
+ * false: irq_set_affinity_hint failed
+ */
+static inline bool
+megasas_irq_set_affinity_hint(struct megasas_instance *instance,
+ unsigned int msix_vector,
+ const struct cpumask *mask)
+{
+ if (instance->smp_affinity_enable) {
+ if (irq_set_affinity_hint(msix_vector, mask))
+ return false;
+ }
+ return true;
+}
+
+#if defined(ENABLE_IRQ_POLL)
static
void megasas_setup_irq_poll(struct megasas_instance *instance)
{
struct megasas_irq_context *irq_ctx;
u32 count, i;
-
count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
/* Initialize IRQ poll */
for (i = 0; i < count; i++) {
irq_ctx = &instance->irq_context[i];
- irq_ctx->os_irq = pci_irq_vector(instance->pdev, i);
+ irq_ctx->os_irq = megasas_get_irq(instance, i);
irq_ctx->irq_poll_scheduled = false;
irq_poll_init(&irq_ctx->irqpoll,
instance->threshold_reply_count,
megasas_irqpoll);
}
}
+#endif
-/*
+/**
* megasas_setup_irqs_ioapic - register legacy interrupts.
* @instance: Adapter soft state
*
@@ -5547,12 +5930,15 @@ megasas_setup_irqs_ioapic(struct megasas_instance *instance)
pdev = instance->pdev;
instance->irq_context[0].instance = instance;
instance->irq_context[0].MSIxIndex = 0;
- if (request_irq(pci_irq_vector(pdev, 0),
- instance->instancet->service_isr, IRQF_SHARED,
- "megasas", &instance->irq_context[0])) {
+ atomic_set(&instance->irq_context[0].in_use, 0);
+ snprintf(instance->irq_context->name, MEGASAS_MSIX_NAME_LEN, "%s%u",
+ "megasas", instance->host->host_no);
+ if (request_irq(megasas_get_irq(instance, 0),
+ instance->instancet->service_isr, IRQF_SHARED,
+ instance->irq_context->name, &instance->irq_context[0])) {
dev_err(&instance->pdev->dev,
- "Failed to register IRQ from %s %d\n",
- __func__, __LINE__);
+ "Failed to register IRQ from %s %d\n",
+ __func__, __LINE__);
return -1;
}
instance->perf_mode = MR_LATENCY_PERF_MODE;
@@ -5560,6 +5946,65 @@ megasas_setup_irqs_ioapic(struct megasas_instance *instance)
return 0;
}
+/**
+ * megasas_setup_reply_map: Create mapping table of CPU-reply queue map
+ * @instance: Adapter soft state
+ * return: void
+ */
+static void megasas_setup_reply_map(struct megasas_instance *instance)
+{
+ unsigned int queue, cpu, low_latency_index_start;
+ const struct cpumask *mask;
+
+ low_latency_index_start = instance->low_latency_index_start;
+#ifndef USE_MANAGED_IRQ_API
+ /* Set affinity for all low latency queues*/
+ cpu = cpumask_first(cpu_online_mask);
+ for (queue = low_latency_index_start; queue < instance->msix_vectors; queue++) {
+ mask = get_cpu_mask(cpu);
+ if (!megasas_irq_set_affinity_hint(instance,
+ megasas_get_irq(instance, queue),
+ mask))
+ dev_err(&instance->pdev->dev,
+ "Failed to set affinity hint for cpu %d\n",
+ cpu);
+
+ cpu = cpumask_next(cpu, cpu_online_mask);
+ }
+
+ /* Setup CPU to reply queues mapping for all low latency queues */
+ queue = low_latency_index_start;
+ for_each_online_cpu(cpu) {
+ instance->reply_map[cpu] = queue;
+ if (queue == (instance->msix_vectors - 1))
+ queue = low_latency_index_start;
+ else
+ queue++;
+ }
+
+#else
+ for (queue = low_latency_index_start; queue < instance->msix_vectors; queue++) {
+ mask = pci_irq_get_affinity(instance->pdev, queue);
+ if (!mask)
+ goto fallback;
+
+ for_each_cpu(cpu, mask)
+ instance->reply_map[cpu] = queue;
+ }
+ return;
+
+fallback:
+ queue = low_latency_index_start;
+ for_each_possible_cpu(cpu) {
+ instance->reply_map[cpu] = queue;
+ if (queue == (instance->msix_vectors - 1))
+ queue = low_latency_index_start;
+ else
+ queue++;
+ }
+#endif
+}
+
/**
* megasas_setup_irqs_msix - register MSI-x interrupts.
* @instance: Adapter soft state
@@ -5576,38 +6021,38 @@ megasas_setup_irqs_msix(struct megasas_instance *instance, u8 is_probe)
struct pci_dev *pdev;
pdev = instance->pdev;
-
+
/* Try MSI-x */
for (i = 0; i < instance->msix_vectors; i++) {
instance->irq_context[i].instance = instance;
instance->irq_context[i].MSIxIndex = i;
- if (request_irq(pci_irq_vector(pdev, i),
- instance->instancet->service_isr, 0, "megasas",
+ atomic_set(&instance->irq_context[i].in_use, 0);
+ snprintf(instance->irq_context[i].name, MEGASAS_MSIX_NAME_LEN, "%s%u-msix%d",
+ "megasas", instance->host->host_no, i);
+ if (request_irq(megasas_get_irq(instance, i),
+ instance->instancet->service_isr, 0, instance->irq_context[i].name,
&instance->irq_context[i])) {
dev_err(&instance->pdev->dev,
"Failed to register IRQ for vector %d.\n", i);
- for (j = 0; j < i; j++) {
- if (j < instance->low_latency_index_start)
- irq_set_affinity_hint(
- pci_irq_vector(pdev, j), NULL);
- free_irq(pci_irq_vector(pdev, j),
+ for (j = 0; j < i; j++)
+ free_irq(megasas_get_irq(instance, j),
&instance->irq_context[j]);
- }
/* Retry irq register for IO_APIC*/
instance->msix_vectors = 0;
instance->msix_load_balance = false;
if (is_probe) {
- pci_free_irq_vectors(instance->pdev);
+ megasas_free_irq_vectors(instance);
return megasas_setup_irqs_ioapic(instance);
} else {
return -1;
}
}
}
+
+ megasas_setup_reply_map(instance);
return 0;
}
-
/*
* megasas_destroy_irqs- unregister interrupts.
* @instance: Adapter soft state
@@ -5617,6 +6062,7 @@ static void
megasas_destroy_irqs(struct megasas_instance *instance) {
int i;
+#if defined(ENABLE_IRQ_POLL)
int count;
struct megasas_irq_context *irq_ctx;
@@ -5627,18 +6073,20 @@ megasas_destroy_irqs(struct megasas_instance *instance) {
irq_poll_disable(&irq_ctx->irqpoll);
}
}
+#endif
- if (instance->msix_vectors)
+ if (instance->msix_vectors) {
for (i = 0; i < instance->msix_vectors; i++) {
- if (i < instance->low_latency_index_start)
- irq_set_affinity_hint(
- pci_irq_vector(instance->pdev, i), NULL);
- free_irq(pci_irq_vector(instance->pdev, i),
+ if (i >= instance->low_latency_index_start)
+ megasas_irq_set_affinity_hint(instance,
+ megasas_get_irq(instance, i),
+ NULL);
+ free_irq(megasas_get_irq(instance, i),
&instance->irq_context[i]);
}
- else
- free_irq(pci_irq_vector(instance->pdev, 0),
- &instance->irq_context[0]);
+ } else {
+ free_irq(megasas_get_irq(instance, 0), &instance->irq_context[0]);
+ }
}
/**
@@ -5699,34 +6147,148 @@ skip_alloc:
instance->use_seqnum_jbod_fp = false;
}
-static void megasas_setup_reply_map(struct megasas_instance *instance)
+#if defined(USE_MANAGED_IRQ_API)
+/**
+ * megasas_set_high_iops_queue_affinity_hint - Set affinity hint for high IOPs queues
+ * @instance: Adapter soft state
+ * return: void
+ */
+static inline void
+megasas_set_high_iops_queue_affinity_hint(struct megasas_instance *instance)
{
- const struct cpumask *mask;
- unsigned int queue, cpu, low_latency_index_start;
+ int i;
+ int local_numa_node;
- low_latency_index_start = instance->low_latency_index_start;
+ if (instance->perf_mode == MR_BALANCED_PERF_MODE) {
+ local_numa_node = dev_to_node(&instance->pdev->dev);
- for (queue = low_latency_index_start; queue < instance->msix_vectors; queue++) {
- mask = pci_irq_get_affinity(instance->pdev, queue);
- if (!mask)
- goto fallback;
-
- for_each_cpu(cpu, mask)
- instance->reply_map[cpu] = queue;
- }
- return;
-
-fallback:
- queue = low_latency_index_start;
- for_each_possible_cpu(cpu) {
- instance->reply_map[cpu] = queue;
- if (queue == (instance->msix_vectors - 1))
- queue = low_latency_index_start;
- else
- queue++;
+ for (i = 0; i < instance->low_latency_index_start; i++)
+ megasas_irq_set_affinity_hint(instance,
+ megasas_get_irq(instance, i),
+ cpumask_of_node(local_numa_node));
}
}
+static int
+__megasas_alloc_irq_vectors(struct megasas_instance *instance)
+{
+ int i, irq_flags;
+ struct irq_affinity desc = { .pre_vectors = instance->low_latency_index_start };
+ struct irq_affinity *descp = &desc;
+
+ irq_flags = PCI_IRQ_MSIX;
+
+ if (instance->smp_affinity_enable)
+ irq_flags |= PCI_IRQ_AFFINITY | PCI_IRQ_ALL_TYPES;
+ else
+ descp = NULL;
+
+ /* Do not allocate msix vectors for poll_queues.
+ * msix_vectors is always within a range of FW supported reply queue.
+ */
+ i = pci_alloc_irq_vectors_affinity(instance->pdev,
+ instance->low_latency_index_start,
+ instance->msix_vectors - instance->iopoll_q_count, irq_flags, descp);
+
+ return i;
+}
+#endif
+
+/**
+ * megasas_alloc_irq_vectors - Allocate IRQ vectors/enable MSI-x vectors
+ * @instance: Adapter soft state
+ * return: void
+ */
+static void
+megasas_alloc_irq_vectors(struct megasas_instance *instance)
+{
+ int i;
+#if defined(USE_MANAGED_IRQ_API)
+ unsigned int num_msix_req;
+ instance->iopoll_q_count = 0;
+
+ if ((instance->adapter_type != MFI_SERIES) &&
+ poll_queues) {
+
+ instance->perf_mode = MR_LATENCY_PERF_MODE;
+ instance->low_latency_index_start = 1;
+
+ /* reserve for default and non-mananged pre-vector. */
+ if (instance->msix_vectors > (poll_queues + 2))
+ instance->iopoll_q_count = poll_queues;
+ else
+ instance->iopoll_q_count = 0;
+
+ num_msix_req = num_online_cpus() + instance->low_latency_index_start;
+ instance->msix_vectors = min(num_msix_req,
+ instance->msix_vectors);
+
+ }
+
+ i = __megasas_alloc_irq_vectors(instance);
+
+ if (((instance->perf_mode == MR_BALANCED_PERF_MODE)
+ || instance->iopoll_q_count) &&
+ (i != (instance->msix_vectors - instance->iopoll_q_count))) {
+ if (instance->msix_vectors)
+ pci_free_irq_vectors(instance->pdev);
+ /* Disable Balanced IOPS mode and try realloc vectors */
+ instance->perf_mode = MR_LATENCY_PERF_MODE;
+ instance->low_latency_index_start = 1;
+ num_msix_req = num_online_cpus() + instance->low_latency_index_start;
+
+ instance->msix_vectors = min(num_msix_req,
+ instance->msix_vectors);
+
+ instance->iopoll_q_count = 0;
+ i = __megasas_alloc_irq_vectors(instance);
+
+ }
+
+ if (instance->smp_affinity_enable)
+ megasas_set_high_iops_queue_affinity_hint(instance);
+
+#else
+ for (i = 0; i < instance->msix_vectors; i++)
+ instance->msixentry[i].entry = i;
+
+ i = pci_enable_msix_range(instance->pdev, instance->msixentry,
+ 1, instance->msix_vectors);
+
+ if (i != instance->msix_vectors) {
+ instance->perf_mode = MR_LATENCY_PERF_MODE;
+ instance->low_latency_index_start = 1;
+ }
+
+#endif
+ dev_info(&instance->pdev->dev,
+ "requested/available msix: %d/%d\n",
+ instance->msix_vectors - instance->iopoll_q_count,
+ i);
+
+ if (i > 0)
+ instance->msix_vectors = i;
+ else
+ instance->msix_vectors = 0;
+
+}
+
+/**
+ * megasas_free_irq_vectors - Freeup IRQ vectors/disable MSI-x vectors
+ * @instance: Adapter soft state
+ */
+void megasas_free_irq_vectors(struct megasas_instance *instance)
+{
+ if (instance->msix_vectors)
+#ifndef USE_MANAGED_IRQ_API
+ pci_disable_msix(instance->pdev);
+#else
+ pci_free_irq_vectors(instance->pdev);
+#endif
+}
+
+
+
/**
* megasas_get_device_list - Get the PD and LD device list from FW.
* @instance: Adapter soft state
@@ -5744,8 +6306,10 @@ int megasas_get_device_list(struct megasas_instance *instance)
memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
if (instance->enable_fw_dev_list) {
- if (megasas_host_device_list_query(instance, true))
+ if (megasas_host_device_list_query(instance, true)) {
+ dev_err(&instance->pdev->dev, "failed to get host device list\n");
return FAILED;
+ }
} else {
if (megasas_get_pd_list(instance) < 0) {
dev_err(&instance->pdev->dev, "failed to get PD list\n");
@@ -5762,87 +6326,6 @@ int megasas_get_device_list(struct megasas_instance *instance)
return SUCCESS;
}
-/**
- * megasas_set_high_iops_queue_affinity_hint - Set affinity hint for high IOPS queues
- * @instance: Adapter soft state
- * return: void
- */
-static inline void
-megasas_set_high_iops_queue_affinity_hint(struct megasas_instance *instance)
-{
- int i;
- int local_numa_node;
-
- if (instance->perf_mode == MR_BALANCED_PERF_MODE) {
- local_numa_node = dev_to_node(&instance->pdev->dev);
-
- for (i = 0; i < instance->low_latency_index_start; i++)
- irq_set_affinity_hint(pci_irq_vector(instance->pdev, i),
- cpumask_of_node(local_numa_node));
- }
-}
-
-static int
-__megasas_alloc_irq_vectors(struct megasas_instance *instance)
-{
- int i, irq_flags;
- struct irq_affinity desc = { .pre_vectors = instance->low_latency_index_start };
- struct irq_affinity *descp = &desc;
-
- irq_flags = PCI_IRQ_MSIX;
-
- if (instance->smp_affinity_enable)
- irq_flags |= PCI_IRQ_AFFINITY;
- else
- descp = NULL;
-
- i = pci_alloc_irq_vectors_affinity(instance->pdev,
- instance->low_latency_index_start,
- instance->msix_vectors, irq_flags, descp);
-
- return i;
-}
-
-/**
- * megasas_alloc_irq_vectors - Allocate IRQ vectors/enable MSI-x vectors
- * @instance: Adapter soft state
- * return: void
- */
-static void
-megasas_alloc_irq_vectors(struct megasas_instance *instance)
-{
- int i;
- unsigned int num_msix_req;
-
- i = __megasas_alloc_irq_vectors(instance);
-
- if ((instance->perf_mode == MR_BALANCED_PERF_MODE) &&
- (i != instance->msix_vectors)) {
- if (instance->msix_vectors)
- pci_free_irq_vectors(instance->pdev);
- /* Disable Balanced IOPS mode and try realloc vectors */
- instance->perf_mode = MR_LATENCY_PERF_MODE;
- instance->low_latency_index_start = 1;
- num_msix_req = num_online_cpus() + instance->low_latency_index_start;
-
- instance->msix_vectors = min(num_msix_req,
- instance->msix_vectors);
-
- i = __megasas_alloc_irq_vectors(instance);
-
- }
-
- dev_info(&instance->pdev->dev,
- "requested/available msix %d/%d\n", instance->msix_vectors, i);
-
- if (i > 0)
- instance->msix_vectors = i;
- else
- instance->msix_vectors = 0;
-
- if (instance->smp_affinity_enable)
- megasas_set_high_iops_queue_affinity_hint(instance);
-}
/**
* megasas_init_fw - Initializes the FW
@@ -5854,7 +6337,7 @@ megasas_alloc_irq_vectors(struct megasas_instance *instance)
static int megasas_init_fw(struct megasas_instance *instance)
{
u32 max_sectors_1;
- u32 max_sectors_2, tmp_sectors, msix_enable;
+ u32 max_sectors_2, tmp_sectors, msix_enable, num_msix_req;
u32 scratch_pad_1, scratch_pad_2, scratch_pad_3, status_reg;
resource_size_t base_addr;
void *base_addr_phys;
@@ -5864,7 +6347,6 @@ static int megasas_init_fw(struct megasas_instance *instance)
struct IOV_111 *iovPtr;
struct fusion_context *fusion;
bool intr_coalescing;
- unsigned int num_msix_req;
u16 lnksta, speed;
fusion = instance->ctrl_context;
@@ -5879,18 +6361,18 @@ static int megasas_init_fw(struct megasas_instance *instance)
}
base_addr = pci_resource_start(instance->pdev, instance->bar);
- instance->reg_set = ioremap_nocache(base_addr, 8192);
+ instance->reg_set = ioremap(base_addr, 8192);
+
+ base_addr_phys = &base_addr;
+ dev_printk(KERN_DEBUG, &instance->pdev->dev,
+ "BAR:0x%lx BAR's base_addr(phys):0x%pa mapped virt_addr:0x%p\n",
+ instance->bar, base_addr_phys, instance->reg_set);
if (!instance->reg_set) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to map IO mem\n");
goto fail_ioremap;
}
- base_addr_phys = &base_addr;
- dev_printk(KERN_DEBUG, &instance->pdev->dev,
- "BAR:0x%lx BAR's base_addr(phys):%pa mapped virt_addr:0x%p\n",
- instance->bar, base_addr_phys, instance->reg_set);
-
if (instance->adapter_type != MFI_SERIES)
instance->instancet = &megasas_instance_template_fusion;
else {
@@ -5922,7 +6404,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
__func__);
if (instance->adapter_type != MFI_SERIES) {
status_reg = instance->instancet->read_fw_status_reg(
- instance);
+ instance);
if (status_reg & MFI_RESET_ADAPTER) {
if (megasas_adp_reset_wait_for_ready
(instance, true, 0) == FAILED)
@@ -5968,6 +6450,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
instance->max_raid_mapsize = ((scratch_pad_2 >>
MR_MAX_RAID_MAP_SIZE_OFFSET_SHIFT) &
MR_MAX_RAID_MAP_SIZE_MASK);
+
}
instance->enable_sdev_max_qd = enable_sdev_max_qd;
@@ -5987,7 +6470,6 @@ static int megasas_init_fw(struct megasas_instance *instance)
msix_enable = (instance->instancet->read_fw_status_reg(instance) &
0x4000000) >> 0x1a;
if (msix_enable && !msix_disable) {
-
scratch_pad_1 = megasas_readl
(instance, &instance->reg_set->outbound_scratch_pad_1);
/* Check max MSI-X vectors */
@@ -6002,13 +6484,11 @@ static int megasas_init_fw(struct megasas_instance *instance)
>> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1;
/*
- * For Invader series, > 8 MSI-x vectors
- * supported by FW/HW implies combined
- * reply queue mode is enabled.
- * For Ventura series, > 16 MSI-x vectors
- * supported by FW/HW implies combined
- * reply queue mode is enabled.
- */
+ * For Invader series, > 8 MSI-x vectors supported by FW/HW implies
+ * combined reply queue mode is enabled.
+ * For Ventura series, > 16 MSI-x vectors supported by FW/HW implies
+ * combined reply queue mode is enabled.
+ */
switch (instance->adapter_type) {
case INVADER_SERIES:
if (instance->msix_vectors > 8)
@@ -6024,13 +6504,6 @@ static int megasas_init_fw(struct megasas_instance *instance)
if (rdpq_enable)
instance->is_rdpq = (scratch_pad_1 & MR_RDPQ_MODE_OFFSET) ?
1 : 0;
-
- if (instance->adapter_type >= INVADER_SERIES &&
- !instance->msix_combined) {
- instance->msix_load_balance = true;
- instance->smp_affinity_enable = false;
- }
-
/* Save 1-15 reply post index address to local memory
* Index 0 is already saved from reg offset
* MPI2_REPLY_POST_HOST_INDEX_OFFSET
@@ -6045,14 +6518,19 @@ static int megasas_init_fw(struct megasas_instance *instance)
}
dev_info(&instance->pdev->dev,
- "firmware supports msix\t: (%d)",
- instance->msix_vectors);
+ "firmware supports msix\t: (%d)",
+ instance->msix_vectors);
+
if (msix_vectors)
instance->msix_vectors = min(msix_vectors,
instance->msix_vectors);
+
+
} else /* MFI adapters */
instance->msix_vectors = 1;
+ intr_coalescing = (scratch_pad_1 & MR_INTR_COALESCING_SUPPORT_OFFSET) ?
+ true : false;
/*
* For Aero (if some conditions are met), driver will configure a
@@ -6073,8 +6551,6 @@ static int megasas_init_fw(struct megasas_instance *instance)
* will be used for IO and management commands.
*/
- intr_coalescing = (scratch_pad_1 & MR_INTR_COALESCING_SUPPORT_OFFSET) ?
- true : false;
if (intr_coalescing &&
(num_online_cpus() >= MR_HIGH_IOPS_QUEUE_COUNT) &&
(instance->msix_vectors == MEGASAS_MAX_MSIX_QUEUES))
@@ -6082,7 +6558,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
else
instance->perf_mode = MR_LATENCY_PERF_MODE;
-
+
if (instance->adapter_type == AERO_SERIES) {
pcie_capability_read_word(instance->pdev, PCI_EXP_LNKSTA, &lnksta);
speed = lnksta & PCI_EXP_LNKSTA_CLS;
@@ -6095,8 +6571,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
instance->perf_mode = MR_LATENCY_PERF_MODE;
fusion->pcie_bw_limitation = true;
}
-
- /*
+
+ /*
* Performance mode settings provided through module parameter-perf_mode will
* take affect only for:
* 1. Aero family of adapters.
@@ -6106,14 +6582,14 @@ static int megasas_init_fw(struct megasas_instance *instance)
(perf_mode <= MR_LATENCY_PERF_MODE))
instance->perf_mode = perf_mode;
/*
- * If intr coalescing is not supported by controller FW, then IOPS
+ * If intr coalescing is not supported by controller FW, then IOPs
* and Balanced modes are not feasible.
*/
- if (!intr_coalescing)
- instance->perf_mode = MR_LATENCY_PERF_MODE;
+ if (!intr_coalescing)
+ instance->perf_mode = MR_LATENCY_PERF_MODE;
}
-
+
if (instance->perf_mode == MR_BALANCED_PERF_MODE)
instance->low_latency_index_start =
MR_HIGH_IOPS_QUEUE_COUNT;
@@ -6125,6 +6601,15 @@ static int megasas_init_fw(struct megasas_instance *instance)
instance->msix_vectors = min(num_msix_req,
instance->msix_vectors);
+ /*
+ * Disable SMP affinity if number of logical CPUs exceeds number of
+ * MSI-x vectors configured
+ */
+ if (!instance->msix_combined) {
+ instance->msix_load_balance = true;
+ instance->smp_affinity_enable = false;
+ }
+
megasas_alloc_irq_vectors(instance);
if (!instance->msix_vectors)
instance->msix_load_balance = false;
@@ -6143,13 +6628,13 @@ static int megasas_init_fw(struct megasas_instance *instance)
MPI2_REPLY_POST_HOST_INDEX_OFFSET);
}
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
if (!instance->msix_vectors) {
i = pci_alloc_irq_vectors(instance->pdev, 1, 1, PCI_IRQ_LEGACY);
if (i < 0)
goto fail_init_adapter;
}
-
- megasas_setup_reply_map(instance);
+#endif
dev_info(&instance->pdev->dev,
"current msix/online cpus\t: (%d/%d)\n",
@@ -6188,9 +6673,10 @@ static int megasas_init_fw(struct megasas_instance *instance)
megasas_setup_irqs_ioapic(instance))
goto fail_init_adapter;
+#if defined(ENABLE_IRQ_POLL)
if (instance->adapter_type != MFI_SERIES)
megasas_setup_irq_poll(instance);
-
+#endif
instance->instancet->enable_intr(instance);
dev_info(&instance->pdev->dev, "INIT adapter done\n");
@@ -6368,8 +6854,7 @@ fail_get_ld_pd_list:
instance->instancet->disable_intr(instance);
megasas_destroy_irqs(instance);
fail_init_adapter:
- if (instance->msix_vectors)
- pci_free_irq_vectors(instance->pdev);
+ megasas_free_irq_vectors(instance);
instance->msix_vectors = 0;
fail_alloc_dma_buf:
megasas_free_ctrl_dma_buffers(instance);
@@ -6440,7 +6925,7 @@ megasas_get_seq_num(struct megasas_instance *instance,
megasas_return_cmd(instance, cmd);
return -ENOMEM;
}
-
+ memset(el_info, 0, sizeof(*el_info));
memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
dcmd->cmd = MFI_CMD_DCMD;
@@ -6677,6 +7162,7 @@ megasas_get_target_prop(struct megasas_instance *instance,
else
ret = megasas_issue_polled(instance, cmd);
+
switch (ret) {
case DCMD_TIMEOUT:
switch (dcmd_timeout_ocr_possible(instance)) {
@@ -6738,6 +7224,32 @@ static int megasas_start_aen(struct megasas_instance *instance)
class_locale.word);
}
+static ssize_t
+sysfs_max_sectors_read(struct file *filep, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+
+ struct Scsi_Host *host = class_to_shost(dev);
+
+ struct megasas_instance *instance =
+ (struct megasas_instance *)host->hostdata;
+
+ count = sprintf(buf,"%u\n", instance->max_sectors_per_req);
+
+ return count+1;
+}
+
+static struct bin_attribute sysfs_max_sectors_attr = {
+ .attr = {
+ .name = "max_sectors",
+ .mode = S_IRUSR|S_IRGRP|S_IROTH,
+ },
+ .size = 7,
+ .read = sysfs_max_sectors_read,
+};
+
/**
* megasas_io_attach - Attaches this driver to SCSI mid-layer
* @instance: Adapter soft state
@@ -6745,10 +7257,14 @@ static int megasas_start_aen(struct megasas_instance *instance)
static int megasas_io_attach(struct megasas_instance *instance)
{
struct Scsi_Host *host = instance->host;
+ u32 error;
/*
* Export parameters required by SCSI mid-layer
*/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
+ host->irq = instance->pdev->irq;
+#endif
host->unique_id = instance->unique_id;
host->can_queue = instance->max_scsi_cmds;
host->this_id = instance->init_id;
@@ -6785,6 +7301,46 @@ static int megasas_io_attach(struct megasas_instance *instance)
host->max_lun = MEGASAS_MAX_LUN;
host->max_cmd_len = 16;
+#if defined(HOST_TAGSET_SUPPORT)
+ /* Use shared host tagset only for fusion adaptors
+ * if there are managed interrupts (smp affinity enabled case).
+ * Single msix_vectors in kdump, so shared host tag is also disabled.
+ */
+
+ host->host_tagset = 0;
+ host->nr_hw_queues = 1;
+
+ if ((instance->adapter_type != MFI_SERIES) &&
+ (instance->msix_vectors > instance->low_latency_index_start) &&
+ host_tagset_enable &&
+ instance->smp_affinity_enable) {
+ host->host_tagset = 1;
+ host->nr_hw_queues = instance->msix_vectors -
+ instance->low_latency_index_start + instance->iopoll_q_count;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,12,0))
+ if (instance->iopoll_q_count)
+ host->nr_maps = 3;
+#endif
+ } else {
+ instance->iopoll_q_count = 0;
+ }
+
+ dev_info(&instance->pdev->dev,
+ "Max firmware commands: %d shared with default "
+ "HW queues: %d poll_queues: %d\n", instance->max_fw_cmds,
+ host->nr_hw_queues - instance->iopoll_q_count,
+ instance->iopoll_q_count);
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,4,0))
+ error = scsi_init_shared_tag_map(host, host->can_queue);
+ if (error) {
+ dev_err(&instance->pdev->dev,
+ "Failed to shared tag from %s %d\n",
+ __func__, __LINE__);
+ return -ENODEV;
+ }
+#endif
/*
* Notify the mid-layer about the new controller
*/
@@ -6795,9 +7351,38 @@ static int megasas_io_attach(struct megasas_instance *instance)
return -ENODEV;
}
+ /*
+ * Create sysfs entries for module paramaters
+ */
+ error = sysfs_create_bin_file(&instance->host->shost_dev.kobj,
+ &sysfs_max_sectors_attr);
+
+ if (error) {
+ dev_err(&instance->pdev->dev,
+ "megasas: Error in creating the sysfs entry"
+ " max_sectors.\n");
+ scsi_remove_host(host);
+ return error;
+ }
+
return 0;
}
+/**
+ * megasas_dma_set_mask_and_coherent- Set streaming and coherent DMA mask
+ * dev- struct representing device inside struct pci_dev
+ * mask- mask to be set
+ * return- 0 for success
+ * non-zero for failure
+ */
+static inline int megasas_dma_set_mask_and_coherent(struct device *dev, u64 mask)
+{
+ int rc = dma_set_mask(dev, mask);
+ if (rc == 0)
+ dma_set_coherent_mask(dev, mask);
+ return rc;
+}
+
/**
* megasas_set_dma_mask - Set DMA mask for supported controllers
*
@@ -6814,6 +7399,11 @@ static int megasas_io_attach(struct megasas_instance *instance)
*
* For older controllers(Thunderbolt and MFI based adapters)-
* driver/FW will operate in 32 bit consistent DMA addresses.
+ *
+ * Although Invader FW supporting full 64-bit DMA, Ventura and Aero controllers
+ * supports 64-bit DMA addressing, due to HW design, address 0xFFFFFFFF-FFFFFFFF
+ * with all 64-bits set will result in PL fault - rollover error.
+ * Use 63-bit mask instead.
*/
static int
megasas_set_dma_mask(struct megasas_instance *instance)
@@ -6824,16 +7414,16 @@ megasas_set_dma_mask(struct megasas_instance *instance)
pdev = instance->pdev;
consistent_mask = (instance->adapter_type >= VENTURA_SERIES) ?
- DMA_BIT_MASK(63) : DMA_BIT_MASK(32);
+ DMA_BIT_MASK(63) : DMA_BIT_MASK(32);
if (IS_DMA64) {
if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(63)) &&
- dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)))
+ megasas_dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)))
goto fail_set_dma_mask;
if ((*pdev->dev.dma_mask == DMA_BIT_MASK(63)) &&
- (dma_set_coherent_mask(&pdev->dev, consistent_mask) &&
- dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)))) {
+ (dma_set_coherent_mask(&pdev->dev, consistent_mask) &&
+ megasas_dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)))) {
/*
* If 32 bit DMA mask fails, then try for 64 bit mask
* for FW capable of handling 64 bit DMA.
@@ -6843,11 +7433,11 @@ megasas_set_dma_mask(struct megasas_instance *instance)
if (!(scratch_pad_1 & MR_CAN_HANDLE_64_BIT_DMA_OFFSET))
goto fail_set_dma_mask;
- else if (dma_set_mask_and_coherent(&pdev->dev,
- DMA_BIT_MASK(63)))
+ else if (megasas_dma_set_mask_and_coherent(&pdev->dev,
+ DMA_BIT_MASK(63)))
goto fail_set_dma_mask;
}
- } else if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)))
+ } else if (megasas_dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)))
goto fail_set_dma_mask;
if (pdev->dev.coherent_dma_mask == DMA_BIT_MASK(32))
@@ -6869,15 +7459,15 @@ fail_set_dma_mask:
/*
* megasas_set_adapter_type - Set adapter type.
- * Supported controllers can be divided in
- * different categories-
- * enum MR_ADAPTER_TYPE {
- * MFI_SERIES = 1,
- * THUNDERBOLT_SERIES = 2,
- * INVADER_SERIES = 3,
- * VENTURA_SERIES = 4,
- * AERO_SERIES = 5,
- * };
+ * Supported controllers can be divided in
+ * different categories-
+ * enum MR_ADAPTER_TYPE {
+ * MFI_SERIES = 1,
+ * THUNDERBOLT_SERIES = 2,
+ * INVADER_SERIES = 3,
+ * VENTURA_SERIES = 4,
+ * AERO_SERIES = 5,
+ * };
* @instance: Adapter soft state
* return: void
*/
@@ -6970,6 +7560,7 @@ static int megasas_alloc_ctrl_mem(struct megasas_instance *instance)
break;
}
+
return 0;
fail:
kfree(instance->reply_map);
@@ -7045,6 +7636,7 @@ int megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance)
dev_err(&pdev->dev,
"Failed to allocate snapdump properties buffer\n");
+
instance->host_device_list_buf = dma_alloc_coherent(&pdev->dev,
HOST_DEVICE_LIST_SZ,
&instance->host_device_list_buf_h,
@@ -7067,7 +7659,7 @@ int megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance)
dev_err(&pdev->dev, "Failed to allocate PD list buffer\n");
return -ENOMEM;
}
-
+
instance->ctrl_info_buf =
dma_alloc_coherent(&pdev->dev,
sizeof(struct megasas_ctrl_info),
@@ -7100,6 +7692,13 @@ int megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance)
return -ENOMEM;
}
+ instance->verbuf = dma_alloc_coherent(&pdev->dev,
+ MEGASAS_MAX_NAME * sizeof(u32),
+ &instance->verbuf_h, GFP_KERNEL);
+
+ if (!instance->verbuf)
+ dev_err(&instance->pdev->dev, "Failed to allocate version buffer\n");
+
if (!reset_devices) {
instance->system_info_buf =
dma_alloc_coherent(&pdev->dev,
@@ -7113,9 +7712,6 @@ int megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance)
dma_alloc_coherent(&pdev->dev,
sizeof(struct MR_TARGET_PROPERTIES),
&instance->tgt_prop_h, GFP_KERNEL);
- instance->crash_dump_buf =
- dma_alloc_coherent(&pdev->dev, CRASH_DMA_BUF_SIZE,
- &instance->crash_dump_h, GFP_KERNEL);
if (!instance->system_info_buf)
dev_err(&instance->pdev->dev,
@@ -7129,6 +7725,15 @@ int megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance)
dev_err(&instance->pdev->dev,
"Failed to allocate tgt_prop buffer\n");
+
+ }
+
+ if (crashdump_enable) {
+ instance->crash_dump_buf =
+ dma_alloc_coherent(&pdev->dev,
+ CRASH_DMA_BUF_SIZE,
+ &instance->crash_dump_h, GFP_KERNEL);
+
if (!instance->crash_dump_buf)
dev_err(&instance->pdev->dev,
"Failed to allocate crash dump buffer\n");
@@ -7182,6 +7787,10 @@ void megasas_free_ctrl_dma_buffers(struct megasas_instance *instance)
instance->ctrl_info_buf,
instance->ctrl_info_buf_h);
+ if (instance->verbuf)
+ dma_free_coherent(&pdev->dev, MEGASAS_MAX_NAME * sizeof(u32),
+ instance->verbuf, instance->verbuf_h);
+
if (instance->system_info_buf)
dma_free_coherent(&pdev->dev, sizeof(struct MR_DRV_SYSTEM_INFO),
instance->system_info_buf,
@@ -7267,32 +7876,58 @@ static inline void megasas_init_ctrl_params(struct megasas_instance *instance)
INIT_WORK(&instance->work_init, process_fw_state_change_wq);
}
+static inline void
+megasas_get_blk_mq(struct megasas_instance *instance)
+{
+#if ((defined(RHEL_MAJOR) && (RHEL_MAJOR == 8)) || \
+ (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)))
+ instance->use_blk_mq = true;
+#elif ((defined(RHEL_MAJOR) && (RHEL_MAJOR == 7) && (RHEL_MINOR >=2)) || \
+ (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) && \
+ (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)))
+ struct Scsi_Host *host = instance->host;
+ if (shost_use_blk_mq(host))
+ instance->use_blk_mq = true;
+#endif
+ return;
+}
+
/**
* megasas_probe_one - PCI hotplug entry point
* @pdev: PCI device structure
* @id: PCI ids of supported hotplugged adapter
*/
-static int megasas_probe_one(struct pci_dev *pdev,
- const struct pci_device_id *id)
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,10))
+static int __devinit
+megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+#else
+static int
+megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+#endif
{
int rval, pos;
struct Scsi_Host *host;
struct megasas_instance *instance;
u16 control = 0;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0))
+ u32 dev_cap = 0;
+#endif
switch (pdev->device) {
case PCI_DEVICE_ID_LSI_AERO_10E0:
- case PCI_DEVICE_ID_LSI_AERO_10E3:
case PCI_DEVICE_ID_LSI_AERO_10E4:
+ dev_err(&pdev->dev, "Adapter is in invalid mode\n");
+ return 1;
+ case PCI_DEVICE_ID_LSI_AERO_10E3:
case PCI_DEVICE_ID_LSI_AERO_10E7:
- dev_err(&pdev->dev, "Adapter is in non secure mode\n");
+ dev_err(&pdev->dev, "Adapter is in tampered mode\n");
return 1;
case PCI_DEVICE_ID_LSI_AERO_10E1:
case PCI_DEVICE_ID_LSI_AERO_10E5:
dev_info(&pdev->dev, "Adapter is in configurable secure mode\n");
break;
}
-
+
/* Reset MSI-X in the kdump kernel */
if (reset_devices) {
pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
@@ -7342,6 +7977,19 @@ static int megasas_probe_one(struct pci_dev *pdev,
megasas_set_adapter_type(instance);
+ /*
+ * Enable PCIe Extended tags for < 4.11 kernels
+ * > 4.11 kernels PCI Subsystem takes care of
+ * enabling PCIe tags
+ */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0))
+ pcie_capability_read_dword(pdev, PCI_EXP_DEVCAP, &dev_cap);
+ if (dev_cap & PCI_EXP_DEVCAP_EXT_TAG){
+ dev_info(&pdev->dev, "enabling Extended Tags\n");
+ pcie_capability_set_word(pdev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_EXT_TAG);
+ }
+#endif
+
/*
* Initialize MFI Firmware
*/
@@ -7389,6 +8037,8 @@ static int megasas_probe_one(struct pci_dev *pdev,
*/
if (megasas_io_attach(instance))
goto fail_io_attach;
+
+ megasas_get_blk_mq(instance);
instance->unload = 0;
/*
@@ -7415,11 +8065,16 @@ static int megasas_probe_one(struct pci_dev *pdev,
return 0;
fail_start_aen:
+ instance->unload = 1;
+ scsi_remove_host(instance->host);
fail_io_attach:
megasas_mgmt_info.count--;
megasas_mgmt_info.max_index--;
megasas_mgmt_info.instance[megasas_mgmt_info.max_index] = NULL;
+ if (instance->requestorId && !instance->skip_heartbeat_timer_del)
+ del_timer_sync(&instance->sriov_heartbeat_timer);
+
instance->instancet->disable_intr(instance);
megasas_destroy_irqs(instance);
@@ -7427,10 +8082,18 @@ fail_io_attach:
megasas_release_fusion(instance);
else
megasas_release_mfi(instance);
- if (instance->msix_vectors)
- pci_free_irq_vectors(instance->pdev);
+ megasas_free_irq_vectors(instance);
+ instance->msix_vectors = 0;
+
+ if (instance->fw_crash_state != UNAVAILABLE)
+ megasas_free_host_crash_buffer(instance);
+
+ if (instance->adapter_type != MFI_SERIES)
+ megasas_fusion_stop_watchdog(instance);
+
fail_init_mfi:
scsi_host_put(host);
+
fail_alloc_instance:
pci_disable_device(pdev);
@@ -7542,7 +8205,7 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
struct megasas_instance *instance;
instance = pci_get_drvdata(pdev);
-
+
if (!instance)
return 0;
@@ -7558,6 +8221,7 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
if (instance->adapter_type != MFI_SERIES)
megasas_fusion_stop_watchdog(instance);
+
megasas_flush_cache(instance);
megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN);
@@ -7574,9 +8238,7 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
instance->instancet->disable_intr(instance);
megasas_destroy_irqs(instance);
-
- if (instance->msix_vectors)
- pci_free_irq_vectors(instance->pdev);
+ megasas_free_irq_vectors(instance);
pci_save_state(pdev);
pci_disable_device(pdev);
@@ -7596,10 +8258,10 @@ megasas_resume(struct pci_dev *pdev)
int rval;
struct Scsi_Host *host;
struct megasas_instance *instance;
- int irq_flags = PCI_IRQ_LEGACY;
+ u32 status_reg;
instance = pci_get_drvdata(pdev);
-
+
if (!instance)
return 0;
@@ -7624,8 +8286,37 @@ megasas_resume(struct pci_dev *pdev)
/*
* We expect the FW state to be READY
*/
- if (megasas_transition_to_ready(instance, 0))
- goto fail_ready_state;
+ if (megasas_transition_to_ready(instance, 0)) {
+ dev_info(&instance->pdev->dev,
+ "Failed to transition controller to ready from %s!\n",
+ __func__);
+ if (instance->adapter_type != MFI_SERIES) {
+ status_reg = instance->instancet->read_fw_status_reg(
+ instance);
+ if (status_reg & MFI_RESET_ADAPTER) {
+ if (megasas_adp_reset_wait_for_ready
+ (instance, true, 0) == FAILED)
+ goto fail_ready_state;
+ } else {
+ goto fail_ready_state;
+ }
+ } else {
+ atomic_set(&instance->fw_reset_no_pci_access, 1);
+ instance->instancet->adp_reset
+ (instance, instance->reg_set);
+ atomic_set(&instance->fw_reset_no_pci_access, 0);
+
+ /*waitting for about 30 second before retry*/
+ ssleep(30);
+
+ if (megasas_transition_to_ready(instance, 0))
+ goto fail_ready_state;
+ }
+
+ dev_info(&instance->pdev->dev,
+ "FW restarted successfully from %s!\n",
+ __func__);
+ }
if (megasas_set_dma_mask(instance))
goto fail_set_dma_mask;
@@ -7638,18 +8329,30 @@ megasas_resume(struct pci_dev *pdev)
atomic_set(&instance->ldio_outstanding, 0);
/* Now re-enable MSI-X */
- if (instance->msix_vectors) {
- irq_flags = PCI_IRQ_MSIX;
- if (instance->smp_affinity_enable)
- irq_flags |= PCI_IRQ_AFFINITY;
- }
- rval = pci_alloc_irq_vectors(instance->pdev, 1,
- instance->msix_vectors ?
- instance->msix_vectors : 1, irq_flags);
+#if defined(USE_MANAGED_IRQ_API)
+ if (instance->msix_vectors)
+ megasas_alloc_irq_vectors(instance);
+ else
+ rval = pci_alloc_irq_vectors(instance->pdev, 1, 1, PCI_IRQ_LEGACY);
+
if (rval < 0)
goto fail_reenable_msix;
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) && \
+ (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0))
+ if (instance->msix_vectors)
+ rval = pci_enable_msix_exact(instance->pdev, instance->msixentry,
+ instance->msix_vectors);
+ else
+ rval = pci_alloc_irq_vectors(instance->pdev, 1, 1, PCI_IRQ_LEGACY);
+
+ if (rval < 0)
+ goto fail_reenable_msix;
- megasas_setup_reply_map(instance);
+#else
+ if (instance->msix_vectors &&
+ pci_enable_msix(instance->pdev, instance->msixentry, instance->msix_vectors))
+ goto fail_reenable_msix;
+#endif
if (instance->adapter_type != MFI_SERIES) {
megasas_reset_reply_desc(instance);
@@ -7678,9 +8381,10 @@ megasas_resume(struct pci_dev *pdev)
megasas_setup_irqs_ioapic(instance))
goto fail_init_mfi;
+#if defined(ENABLE_IRQ_POLL)
if (instance->adapter_type != MFI_SERIES)
megasas_setup_irq_poll(instance);
-
+#endif
/* Re-launch SR-IOV heartbeat timer */
if (instance->requestorId) {
if (!megasas_sriov_start_heartbeat(instance, 0))
@@ -7762,7 +8466,12 @@ megasas_wait_for_adapter_operational(struct megasas_instance *instance)
* megasas_detach_one - PCI hot"un"plug entry point
* @pdev: PCI device structure
*/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,10))
+static void __devexit megasas_detach_one(struct pci_dev *pdev)
+#else
static void megasas_detach_one(struct pci_dev *pdev)
+#endif
+
{
int i;
struct Scsi_Host *host;
@@ -7771,7 +8480,7 @@ static void megasas_detach_one(struct pci_dev *pdev)
u32 pd_seq_map_sz;
instance = pci_get_drvdata(pdev);
-
+
if (!instance)
return;
@@ -7826,9 +8535,7 @@ skip_firing_dcmds:
instance->instancet->disable_intr(instance);
megasas_destroy_irqs(instance);
-
- if (instance->msix_vectors)
- pci_free_irq_vectors(instance->pdev);
+ megasas_free_irq_vectors(instance);
if (instance->adapter_type >= VENTURA_SERIES) {
for (i = 0; i < MAX_LOGICAL_DRIVES_EXT; ++i)
@@ -7917,9 +8624,7 @@ static void megasas_shutdown(struct pci_dev *pdev)
skip_firing_dcmds:
instance->instancet->disable_intr(instance);
megasas_destroy_irqs(instance);
-
- if (instance->msix_vectors)
- pci_free_irq_vectors(instance->pdev);
+ megasas_free_irq_vectors(instance);
}
/**
@@ -7936,6 +8641,17 @@ static int megasas_mgmt_open(struct inode *inode, struct file *filep)
return 0;
}
+/**
+ * megasas_mgmt_release - char node "release" entry point
+ */
+static int megasas_mgmt_release(struct inode *inode, struct file *filep)
+{
+ filep->private_data = NULL;
+ fasync_helper(-1, filep, 0, &megasas_async_queue);
+
+ return 0;
+}
+
/**
* megasas_mgmt_fasync - Async notifier registration from applications
*
@@ -7966,15 +8682,15 @@ static int megasas_mgmt_fasync(int fd, struct file *filep, int mode)
/**
* megasas_mgmt_poll - char node "poll" entry point
* */
-static __poll_t megasas_mgmt_poll(struct file *file, poll_table *wait)
+static unsigned int megasas_mgmt_poll(struct file *file, poll_table *wait)
{
- __poll_t mask;
+ unsigned int mask;
unsigned long flags;
poll_wait(file, &megasas_poll_wait, wait);
spin_lock_irqsave(&poll_aen_lock, flags);
if (megasas_poll_wait_aen)
- mask = (EPOLLIN | EPOLLRDNORM);
+ mask = (POLLIN | POLLRDNORM);
else
mask = 0;
megasas_poll_wait_aen = 0;
@@ -8038,8 +8754,9 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
int error = 0, i;
void *sense = NULL;
dma_addr_t sense_handle;
- void *sense_ptr;
+ unsigned long *sense_ptr;
u32 opcode = 0;
+ int ret = DCMD_SUCCESS;
memset(kbuff_arr, 0, sizeof(kbuff_arr));
@@ -8160,13 +8877,6 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
}
if (ioc->sense_len) {
- /* make sure the pointer is part of the frame */
- if (ioc->sense_off >
- (sizeof(union megasas_frame) - sizeof(__le64))) {
- error = -EINVAL;
- goto out;
- }
-
sense = dma_alloc_coherent(&instance->pdev->dev, ioc->sense_len,
&sense_handle, GFP_KERNEL);
if (!sense) {
@@ -8174,9 +8884,12 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
goto out;
}
- /* always store 64 bits regardless of addressing */
- sense_ptr = (void *)cmd->frame + ioc->sense_off;
- put_unaligned_le64(sense_handle, sense_ptr);
+ sense_ptr =
+ (unsigned long *) ((unsigned long)cmd->frame + ioc->sense_off);
+ if (instance->consistent_mask_64bit)
+ *sense_ptr = cpu_to_le64(sense_handle);
+ else
+ *sense_ptr = cpu_to_le32(sense_handle);
}
/*
@@ -8184,13 +8897,17 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
* cmd to the SCSI mid-layer
*/
cmd->sync_cmd = 1;
- if (megasas_issue_blocked_cmd(instance, cmd, 0) == DCMD_NOT_FIRED) {
+
+ ret = megasas_issue_blocked_cmd(instance, cmd, 0);
+ switch (ret) {
+ case DCMD_INIT:
+ case DCMD_BUSY:
cmd->sync_cmd = 0;
dev_err(&instance->pdev->dev,
"return -EBUSY from %s %d cmd 0x%x opcode 0x%x cmd->cmd_status_drv 0x%x\n",
- __func__, __LINE__, cmd->frame->hdr.cmd, opcode,
- cmd->cmd_status_drv);
- return -EBUSY;
+ __func__, __LINE__, cmd->frame->hdr.cmd, opcode, cmd->cmd_status_drv);
+ error = -EBUSY;
+ goto out;
}
cmd->sync_cmd = 0;
@@ -8241,6 +8958,11 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
error = -EFAULT;
}
+ if (copy_to_user(&user_ioc->frame.hdr.scsi_status,
+ &cmd->frame->hdr.scsi_status, sizeof(u8))) {
+ dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error copying out scsi_status\n");
+ error = -EFAULT;
+ }
out:
if (sense) {
dma_free_coherent(&instance->pdev->dev, ioc->sense_len,
@@ -8439,6 +9161,13 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
printk(KERN_DEBUG "megasas: error copy_in_user cmd_status\n");
return -EFAULT;
}
+
+ if (copy_in_user(&cioc->frame.hdr.scsi_status,
+ &ioc->frame.hdr.scsi_status, sizeof(u8))) {
+ printk(KERN_DEBUG "megasas: error copy_in_user scsi_status\n");
+ return -EFAULT;
+ }
+
return error;
}
@@ -8463,6 +9192,7 @@ megasas_mgmt_compat_ioctl(struct file *file, unsigned int cmd,
static const struct file_operations megasas_mgmt_fops = {
.owner = THIS_MODULE,
.open = megasas_mgmt_open,
+ .release = megasas_mgmt_release,
.fasync = megasas_mgmt_fasync,
.unlocked_ioctl = megasas_mgmt_ioctl,
.poll = megasas_mgmt_poll,
@@ -8480,7 +9210,11 @@ static struct pci_driver megasas_pci_driver = {
.name = "megaraid_sas",
.id_table = megasas_pci_table,
.probe = megasas_probe_one,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,10))
+ .remove = __devexit_p(megasas_detach_one),
+#else
.remove = megasas_detach_one,
+#endif
.suspend = megasas_suspend,
.resume = megasas_resume,
.shutdown = megasas_shutdown,
@@ -8494,26 +9228,22 @@ static ssize_t version_show(struct device_driver *dd, char *buf)
return snprintf(buf, strlen(MEGASAS_VERSION) + 2, "%s\n",
MEGASAS_VERSION);
}
-static DRIVER_ATTR_RO(version);
static ssize_t release_date_show(struct device_driver *dd, char *buf)
{
return snprintf(buf, strlen(MEGASAS_RELDATE) + 2, "%s\n",
MEGASAS_RELDATE);
}
-static DRIVER_ATTR_RO(release_date);
static ssize_t support_poll_for_event_show(struct device_driver *dd, char *buf)
{
return sprintf(buf, "%u\n", support_poll_for_event);
}
-static DRIVER_ATTR_RO(support_poll_for_event);
static ssize_t support_device_change_show(struct device_driver *dd, char *buf)
{
return sprintf(buf, "%u\n", support_device_change);
}
-static DRIVER_ATTR_RO(support_device_change);
static ssize_t dbg_lvl_show(struct device_driver *dd, char *buf)
{
@@ -8531,7 +9261,6 @@ static ssize_t dbg_lvl_store(struct device_driver *dd, const char *buf,
}
return retval;
}
-static DRIVER_ATTR_RW(dbg_lvl);
static ssize_t
support_nvme_encapsulation_show(struct device_driver *dd, char *buf)
@@ -8539,15 +9268,34 @@ support_nvme_encapsulation_show(struct device_driver *dd, char *buf)
return sprintf(buf, "%u\n", support_nvme_encapsulation);
}
-static DRIVER_ATTR_RO(support_nvme_encapsulation);
-
static ssize_t
support_pci_lane_margining_show(struct device_driver *dd, char *buf)
{
return sprintf(buf, "%u\n", support_pci_lane_margining);
}
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0))
+static DRIVER_ATTR_RO(version);
+static DRIVER_ATTR_RO(release_date);
+static DRIVER_ATTR_RO(support_poll_for_event);
+static DRIVER_ATTR_RO(support_device_change);
+static DRIVER_ATTR_RW(dbg_lvl);
+static DRIVER_ATTR_RO(support_nvme_encapsulation);
static DRIVER_ATTR_RO(support_pci_lane_margining);
+#else
+static DRIVER_ATTR(version, S_IRUGO, version_show, NULL);
+static DRIVER_ATTR(release_date, S_IRUGO, release_date_show, NULL);
+static DRIVER_ATTR(support_poll_for_event, S_IRUGO,
+ support_poll_for_event_show, NULL);
+static DRIVER_ATTR(support_device_change, S_IRUGO,
+ support_device_change_show, NULL);
+static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUSR, dbg_lvl_show, dbg_lvl_store);
+static DRIVER_ATTR(support_nvme_encapsulation, S_IRUGO,
+ support_nvme_encapsulation_show, NULL);
+static DRIVER_ATTR(support_pci_lane_margining, S_IRUGO,
+ support_pci_lane_margining_show, NULL);
+
+#endif
static inline void megasas_remove_scsi_device(struct scsi_device *sdev)
{
@@ -8698,8 +9446,10 @@ megasas_aen_polling(struct work_struct *work)
union megasas_evt_class_locale class_locale;
int event_type = 0;
u32 seq_num;
+ u16 ld_target_id;
int error;
u8 dcmd_ret = DCMD_SUCCESS;
+ struct scsi_device *sdev1;
if (!instance) {
printk(KERN_ERR "invalid instance!\n");
@@ -8722,12 +9472,22 @@ megasas_aen_polling(struct work_struct *work)
break;
case MR_EVT_LD_OFFLINE:
- case MR_EVT_CFG_CLEARED:
case MR_EVT_LD_DELETED:
+ ld_target_id = instance->evt_detail->args.ld.target_id;
+ sdev1 = scsi_device_lookup(instance->host,
+ MEGASAS_MAX_PD_CHANNELS +
+ (ld_target_id / MEGASAS_MAX_DEV_PER_CHANNEL),
+ (ld_target_id - MEGASAS_MAX_DEV_PER_CHANNEL), 0);
+ if (sdev1)
+ megasas_remove_scsi_device(sdev1);
+
+ event_type = SCAN_VD_CHANNEL;
+ break;
case MR_EVT_LD_CREATED:
event_type = SCAN_VD_CHANNEL;
break;
+ case MR_EVT_CFG_CLEARED:
case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
case MR_EVT_FOREIGN_CFG_IMPORTED:
case MR_EVT_LD_STATE_CHANGE:
@@ -8738,8 +9498,7 @@ megasas_aen_polling(struct work_struct *work)
case MR_EVT_CTRL_PROP_CHANGED:
dcmd_ret = megasas_get_ctrl_info(instance);
- if (dcmd_ret == DCMD_SUCCESS &&
- instance->snapdump_wait_time) {
+ if (dcmd_ret == DCMD_SUCCESS && instance->snapdump_wait_time) {
megasas_get_snapdump_properties(instance);
dev_info(&instance->pdev->dev,
"Snap dump wait time\t: %d\n",
@@ -8805,9 +9564,19 @@ static int __init megasas_init(void)
if (reset_devices) {
msix_vectors = 1;
rdpq_enable = 0;
+ crashdump_enable = 0;
dual_qdepth_disable = 1;
+ poll_queues = 0;
}
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0))
+ poll_queues = 0;
+#endif
+
+#if defined(HOST_TAGSET_SUPPORT)
+ if (!host_tagset_enable)
+ poll_queues = 0;
+#endif
/*
* Announce driver version and other information
*/
@@ -8835,7 +9604,7 @@ static int __init megasas_init(void)
megasas_mgmt_majorno = rval;
megasas_init_debugfs();
-
+
/*
* Register ourselves as PCI hotplug module
*/
@@ -8847,8 +9616,9 @@ static int __init megasas_init(void)
}
if ((event_log_level < MFI_EVT_CLASS_DEBUG) ||
- (event_log_level > MFI_EVT_CLASS_DEAD)) {
- pr_warn("megaraid_sas: provided event log level is out of range, setting it to default 2(CLASS_CRITICAL), permissible range is: -2 to 4\n");
+ (event_log_level > MFI_EVT_CLASS_DEAD)) {
+ pr_warn("megaraid_sas: provided event log level is out of range, setting"
+ " it to default 2(CLASS_CRITICAL), permissible range is: -2 to 4\n");
event_log_level = MFI_EVT_CLASS_CRITICAL;
}
@@ -8885,7 +9655,6 @@ static int __init megasas_init(void)
&driver_attr_support_pci_lane_margining);
if (rval)
goto err_dcf_support_pci_lane_margining;
-
return rval;
err_dcf_support_pci_lane_margining:
diff --git a/drivers/scsi/megaraid/megaraid_sas_debugfs.c b/drivers/scsi/megaraid/megaraid_sas_debugfs.c
index c69760775..b62c374a6 100644
--- a/drivers/scsi/megaraid/megaraid_sas_debugfs.c
+++ b/drivers/scsi/megaraid/megaraid_sas_debugfs.c
@@ -25,28 +25,31 @@
*
* Send feedback to: megaraidlinux.pdl@broadcom.com
*/
+#include
#include
#include
#include
#include
#include
-#include
+#include
#include
#include
#include
+
#include "megaraid_sas_fusion.h"
#include "megaraid_sas.h"
#ifdef CONFIG_DEBUG_FS
#include
-struct dentry *megasas_debugfs_root;
+struct dentry *megasas_debugfs_root = NULL;
static ssize_t
megasas_debugfs_read(struct file *filp, char __user *ubuf, size_t cnt,
- loff_t *ppos)
+ loff_t *ppos)
+
{
struct megasas_debugfs_buffer *debug = filp->private_data;
@@ -72,7 +75,7 @@ megasas_debugfs_raidmap_open(struct inode *inode, struct file *file)
debug->buf = (void *)fusion->ld_drv_map[(instance->map_id & 1)];
debug->len = fusion->drv_map_sz;
file->private_data = debug;
-
+
return 0;
}
@@ -111,7 +114,8 @@ void megasas_init_debugfs(void)
*/
void megasas_exit_debugfs(void)
{
- debugfs_remove_recursive(megasas_debugfs_root);
+ if (megasas_debugfs_root)
+ debugfs_remove_recursive(megasas_debugfs_root);
}
/*
@@ -127,8 +131,7 @@ megasas_setup_debugfs(struct megasas_instance *instance)
fusion = instance->ctrl_context;
if (fusion) {
- snprintf(name, sizeof(name),
- "scsi_host%d", instance->host->host_no);
+ snprintf(name, sizeof(name), "scsi_host%d", instance->host->host_no);
if (!instance->debugfs_root) {
instance->debugfs_root =
debugfs_create_dir(name, megasas_debugfs_root);
@@ -142,8 +145,8 @@ megasas_setup_debugfs(struct megasas_instance *instance)
snprintf(name, sizeof(name), "raidmap_dump");
instance->raidmap_dump =
debugfs_create_file(name, S_IRUGO,
- instance->debugfs_root, instance,
- &megasas_debugfs_raidmap_fops);
+ instance->debugfs_root,
+ instance, &megasas_debugfs_raidmap_fops);
if (!instance->raidmap_dump) {
dev_err(&instance->pdev->dev,
"Cannot create raidmap debugfs file\n");
@@ -160,7 +163,8 @@ megasas_setup_debugfs(struct megasas_instance *instance)
*/
void megasas_destroy_debugfs(struct megasas_instance *instance)
{
- debugfs_remove_recursive(instance->debugfs_root);
+ if (instance->debugfs_root)
+ debugfs_remove_recursive(instance->debugfs_root);
}
#else
@@ -177,3 +181,4 @@ void megasas_destroy_debugfs(struct megasas_instance *instance)
{
}
#endif /*CONFIG_DEBUG_FS*/
+
diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c
index 50b8c1b12..7b344aba9 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fp.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fp.c
@@ -1,10 +1,22 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Linux MegaRAID driver for SAS based RAID controllers
*
- * Copyright (c) 2009-2013 LSI Corporation
- * Copyright (c) 2013-2016 Avago Technologies
- * Copyright (c) 2016-2018 Broadcom Inc.
+ * Copyright (c) 2009-2018 LSI Corporation.
+ * Copyright (c) 2009-2018 Avago Technologies.
+ * Copyright (c) 2009-2018 Broadcom Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
*
* FILE: megaraid_sas_fp.c
*
@@ -18,6 +30,7 @@
* Send feedback to: megaraidlinux.pdl@broadcom.com
*/
+#include
#include
#include
#include
@@ -33,7 +46,6 @@
#include
#include
#include
-#include
#include
#include
@@ -59,7 +71,7 @@ MODULE_PARM_DESC(lb_pending_cmds, "Change raid-1 load balancing outstanding "
#define SPAN_INVALID 0xff
/* Prototypes */
-static void mr_update_span_set(struct MR_DRV_RAID_MAP_ALL *map,
+static u8 mr_update_span_set(struct MR_DRV_RAID_MAP_ALL *map,
PLD_SPAN_INFO ldSpanInfo);
static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld,
u64 stripRow, u16 stripRef, struct IO_REQUEST_INFO *io_info,
@@ -74,6 +86,7 @@ u32 mega_mod64(u64 dividend, u32 divisor)
if (!divisor)
printk(KERN_ERR "megasas : DIVISOR is zero, in div fn\n");
+
d = dividend;
remainder = do_div(d, divisor);
return remainder;
@@ -343,13 +356,17 @@ u8 MR_ValidateMapInfo(struct megasas_instance *instance, u64 map_id)
}
if (instance->UnevenSpanSupport)
- mr_update_span_set(drv_map, ldSpanInfo);
+ if (mr_update_span_set(drv_map, ldSpanInfo))
+ return 0;
if (lbInfo)
mr_update_load_balance_params(drv_map, lbInfo);
num_lds = le16_to_cpu(drv_map->raidMap.ldCount);
+ memcpy(instance->ld_ids_prev, instance->ld_ids_from_raidmap,
+ sizeof(instance->ld_ids_from_raidmap));
+ memset(instance->ld_ids_from_raidmap, 0xff, MEGASAS_MAX_LD_IDS);
/*Convert Raid capability values to CPU arch */
for (i = 0; (num_lds > 0) && (i < MAX_LOGICAL_DRIVES_EXT); i++) {
ld = MR_TargetIdToLdGet(i, drv_map);
@@ -360,7 +377,7 @@ u8 MR_ValidateMapInfo(struct megasas_instance *instance, u64 map_id)
raid = MR_LdRaidGet(ld, drv_map);
le32_to_cpus((u32 *)&raid->capability);
-
+ instance->ld_ids_from_raidmap[i] = i;
num_lds--;
}
@@ -494,7 +511,7 @@ static u64 get_row_from_strip(struct megasas_instance *instance,
for (info = 0; info < MAX_QUAD_DEPTH; info++) {
span_set = &(ldSpanInfo[ld].span_set[info]);
- if (span_set->span_row_data_width == 0)
+ if ((span_set->span_row_data_width == 0) || (span_set->diff == 0))
break;
if (strip > span_set->data_strip_end)
continue;
@@ -562,6 +579,8 @@ static u64 get_strip_from_row(struct megasas_instance *instance,
block_span_info.noElements) >= info+1) {
quad = &map->raidMap.ldSpanMap[ld].
spanBlock[span].block_span_info.quad[info];
+ if (le32_to_cpu(quad->diff) == 0)
+ return -1;
if (le64_to_cpu(quad->logStart) <= row &&
row <= le64_to_cpu(quad->logEnd) &&
mega_mod64((row - le64_to_cpu(quad->logStart)),
@@ -708,6 +727,8 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld,
row = io_info->start_row;
span = io_info->start_span;
+ if (SPAN_ROW_SIZE(map, ld, span) == 0)
+ return false;
if (raid->level == 6) {
logArm = get_arm_from_strip(instance, ld, stripRow, map);
@@ -901,7 +922,7 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow,
* This routine calculates the logical arm, data Arm, row number and parity arm
* for R56 CTIO write operation.
*/
-static void mr_get_phy_params_r56_rmw(struct megasas_instance *instance,
+static u8 mr_get_phy_params_r56_rmw(struct megasas_instance *instance,
u32 ld, u64 stripNo,
struct IO_REQUEST_INFO *io_info,
struct RAID_CONTEXT_G35 *pRAID_Context,
@@ -918,6 +939,8 @@ static void mr_get_phy_params_r56_rmw(struct megasas_instance *instance,
rowNum = mega_div64_32(stripNo, dataArms);
/* parity disk arm, first arm is 0 */
+ if (arms == 0)
+ return 1;
rightmostParityArm = (arms - 1) - mega_mod64(rowNum, arms);
/* logical arm within row */
@@ -930,7 +953,7 @@ static void mr_get_phy_params_r56_rmw(struct megasas_instance *instance,
} else {
span = (u8)MR_GetSpanBlock(ld, rowNum, pdBlock, map);
if (span == SPAN_INVALID)
- return;
+ return 1;
}
if (raid->level == 6) {
@@ -939,7 +962,7 @@ static void mr_get_phy_params_r56_rmw(struct megasas_instance *instance,
if (PParityArm < 0)
PParityArm += arms;
-
+
/* rightmostParityArm is P-Parity for RAID 5 and Q-Parity for RAID */
pRAID_Context->flow_specific.r56_arm_map = rightmostParityArm;
pRAID_Context->flow_specific.r56_arm_map |=
@@ -957,9 +980,10 @@ static void mr_get_phy_params_r56_rmw(struct megasas_instance *instance,
pRAID_Context->raid_flags = (MR_RAID_FLAGS_IO_SUB_TYPE_R56_DIV_OFFLOAD <<
MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT);
- return;
+ return 0;
}
+
/*
******************************************************************************
*
@@ -1023,10 +1047,11 @@ MR_BuildRaidContext(struct megasas_instance *instance,
}
}
+ io_info->data_arms = raid->rowDataSize;
+
stripSize = 1 << raid->stripeShift;
stripe_mask = stripSize-1;
- io_info->data_arms = raid->rowDataSize;
/*
* calculate starting row and stripe, and number of strips and rows
@@ -1170,9 +1195,10 @@ MR_BuildRaidContext(struct megasas_instance *instance,
/* Aero R5/6 Division Offload for WRITE */
if (fusion->r56_div_offload && (raid->level >= 5) && !isRead) {
- mr_get_phy_params_r56_rmw(instance, ld, start_strip, io_info,
- (struct RAID_CONTEXT_G35 *)pRAID_Context,
- map);
+ if (mr_get_phy_params_r56_rmw(instance, ld, start_strip, io_info,
+ (struct RAID_CONTEXT_G35 *)pRAID_Context,
+ map))
+ return false;
return true;
}
@@ -1219,7 +1245,7 @@ MR_BuildRaidContext(struct megasas_instance *instance,
* ldSpanInfo - ldSpanInfo per HBA instance
*
*/
-void mr_update_span_set(struct MR_DRV_RAID_MAP_ALL *map,
+static u8 mr_update_span_set(struct MR_DRV_RAID_MAP_ALL *map,
PLD_SPAN_INFO ldSpanInfo)
{
u8 span, count;
@@ -1265,6 +1291,8 @@ void mr_update_span_set(struct MR_DRV_RAID_MAP_ALL *map,
}
span_set->span_row_data_width = span_row_width;
+ if (le32_to_cpu(quad->diff) == 0)
+ return 1;
span_row = mega_div64_32(((le64_to_cpu(quad->logEnd) -
le64_to_cpu(quad->logStart)) + le32_to_cpu(quad->diff)),
le32_to_cpu(quad->diff));
@@ -1318,6 +1346,7 @@ void mr_update_span_set(struct MR_DRV_RAID_MAP_ALL *map,
break;
}
}
+ return 0;
}
void mr_update_load_balance_params(struct MR_DRV_RAID_MAP_ALL *drv_map,
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index 17b4496d8..31e2f64c9 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -1,10 +1,22 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Linux MegaRAID driver for SAS based RAID controllers
*
- * Copyright (c) 2009-2013 LSI Corporation
- * Copyright (c) 2013-2016 Avago Technologies
- * Copyright (c) 2016-2018 Broadcom Inc.
+ * Copyright (c) 2009-2018 LSI Corporation.
+ * Copyright (c) 2009-2018 Avago Technologies.
+ * Copyright (c) 2009-2018 Broadcom Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
*
* FILE: megaraid_sas_fusion.c
*
@@ -17,6 +29,7 @@
* Send feedback to: megaraidlinux.pdl@broadcom.com
*/
+#include
#include
#include
#include
@@ -35,7 +48,6 @@
#include
#include
#include
-#include
#include
#include
@@ -73,6 +85,7 @@ int megasas_transition_to_ready(struct megasas_instance *instance, int ocr);
void megaraid_sas_kill_hba(struct megasas_instance *instance);
extern u32 megasas_dbg_lvl;
+extern int disable_ext_io;
int megasas_sriov_start_heartbeat(struct megasas_instance *instance,
int initial);
void megasas_start_timer(struct megasas_instance *instance);
@@ -87,6 +100,7 @@ static void megasas_fusion_crash_dump(struct megasas_instance *instance);
extern u32 megasas_readl(struct megasas_instance *instance,
const volatile void __iomem *addr);
+
/**
* megasas_adp_reset_wait_for_ready - initiate chip reset and wait for
* controller to come to ready state
@@ -95,7 +109,7 @@ extern u32 megasas_readl(struct megasas_instance *instance,
* @ocr_context - If called from OCR context this will
* be set to 1, else 0
*
- * This function initates a chip reset followed by a wait for controller to
+ * This functon initiates a chip reset followed by a wait for controller to
* transition to ready state.
* During this, driver will block all access to PCI config space from userspace
*/
@@ -106,6 +120,7 @@ megasas_adp_reset_wait_for_ready(struct megasas_instance *instance,
{
int ret = FAILED;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0))
/*
* Block access to PCI config space from userspace
* when diag reset is initiated from driver
@@ -116,6 +131,7 @@ megasas_adp_reset_wait_for_ready(struct megasas_instance *instance,
__func__, __LINE__);
pci_cfg_access_lock(instance->pdev);
+#endif
if (do_adp_reset) {
if (instance->instancet->adp_reset
@@ -133,13 +149,14 @@ megasas_adp_reset_wait_for_ready(struct megasas_instance *instance,
ret = SUCCESS;
out:
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0))
if (megasas_dbg_lvl & OCR_DEBUG)
dev_info(&instance->pdev->dev,
"Unlock access to PCI config space %s %d\n",
__func__, __LINE__);
pci_cfg_access_unlock(instance->pdev);
-
+#endif
return ret;
}
@@ -191,7 +208,8 @@ megasas_enable_intr_fusion(struct megasas_instance *instance)
/* Dummy readl to force pci flush */
dev_info(&instance->pdev->dev, "%s is called outbound_intr_mask:0x%08x\n",
- __func__, readl(®s->outbound_intr_mask));
+ __func__, readl(®s->outbound_intr_mask));
+
}
/**
@@ -209,7 +227,7 @@ megasas_disable_intr_fusion(struct megasas_instance *instance)
writel(mask, ®s->outbound_intr_mask);
/* Dummy readl to force pci flush */
dev_info(&instance->pdev->dev, "%s is called outbound_intr_mask:0x%08x\n",
- __func__, readl(®s->outbound_intr_mask));
+ __func__, readl(®s->outbound_intr_mask));
}
int
@@ -235,6 +253,69 @@ megasas_clear_intr_fusion(struct megasas_instance *instance)
return 1;
}
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0))
+
+static inline void
+megasas_sdev_busy_inc(struct megasas_instance *instance,
+ struct scsi_cmnd *scmd)
+{
+ if (instance->perf_mode == MR_BALANCED_PERF_MODE) {
+ struct MR_PRIV_DEVICE *mr_device_priv_data =
+ scmd->device->hostdata;
+ atomic_inc(&mr_device_priv_data->sdev_priv_busy);
+ }
+}
+
+static inline void
+megasas_sdev_busy_dec(struct megasas_instance *instance,
+ struct scsi_cmnd *scmd)
+{
+ if (instance->perf_mode == MR_BALANCED_PERF_MODE) {
+ struct MR_PRIV_DEVICE *mr_device_priv_data =
+ scmd->device->hostdata;
+ atomic_dec(&mr_device_priv_data->sdev_priv_busy);
+ }
+}
+
+static inline int
+megasas_sdev_busy_read(struct megasas_instance *instance,
+ struct scsi_cmnd *scmd)
+{
+ if (instance->perf_mode == MR_BALANCED_PERF_MODE) {
+ struct MR_PRIV_DEVICE *mr_device_priv_data =
+ scmd->device->hostdata;
+ return atomic_read(&mr_device_priv_data->sdev_priv_busy);
+ }
+ return 0;
+}
+
+#else
+
+static inline void
+megasas_sdev_busy_inc(struct megasas_instance *instance,
+ struct scsi_cmnd *scmd)
+{
+ return;
+}
+
+static inline void
+megasas_sdev_busy_dec(struct megasas_instance *instance,
+ struct scsi_cmnd *scmd)
+{
+ return;
+}
+
+static inline int
+megasas_sdev_busy_read(struct megasas_instance *instance,
+ struct scsi_cmnd *scmd)
+{
+ if (instance->perf_mode == MR_BALANCED_PERF_MODE)
+ return atomic_read(&scmd->device->device_busy);
+
+ return 0;
+}
+#endif
+
/**
* megasas_get_cmd_fusion - Get a command from the free pool
* @instance: Adapter soft state
@@ -265,33 +346,37 @@ inline void megasas_return_cmd_fusion(struct megasas_instance *instance,
}
/**
- * megasas_write_64bit_req_desc - PCI writes 64bit request descriptor
- * @instance: Adapter soft state
- * @req_desc: 64bit Request descriptor
+ * megasas_write_64bit_req_desc - PCI writes 64bit request descriptor
+ * @instance: Adapter soft state
+ * @req_desc: 64bit Request descriptor
*/
static void
megasas_write_64bit_req_desc(struct megasas_instance *instance,
union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc)
{
#if defined(writeq) && defined(CONFIG_64BIT)
- u64 req_data = (((u64)le32_to_cpu(req_desc->u.high) << 32) |
- le32_to_cpu(req_desc->u.low));
- writeq(req_data, &instance->reg_set->inbound_low_queue_port);
+ u64 req_data = (((u64)le32_to_cpu(req_desc->u.high) << 32) |
+ le32_to_cpu(req_desc->u.low));
+ writeq(req_data, &instance->reg_set->inbound_low_queue_port);
#else
- unsigned long flags;
- spin_lock_irqsave(&instance->hba_lock, flags);
- writel(le32_to_cpu(req_desc->u.low),
- &instance->reg_set->inbound_low_queue_port);
- writel(le32_to_cpu(req_desc->u.high),
- &instance->reg_set->inbound_high_queue_port);
- spin_unlock_irqrestore(&instance->hba_lock, flags);
+ unsigned long flags;
+ spin_lock_irqsave(&instance->hba_lock, flags);
+ writel(le32_to_cpu(req_desc->u.low),
+ &instance->reg_set->inbound_low_queue_port);
+ writel(le32_to_cpu(req_desc->u.high),
+ &instance->reg_set->inbound_high_queue_port);
+#if !((defined(RHEL_MAJOR) && (RHEL_MAJOR == 8) && (RHEL_MINOR >= 2)) || \
+ (LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0)))
+ mmiowb();
+#endif
+ spin_unlock_irqrestore(&instance->hba_lock, flags);
#endif
}
/**
* megasas_fire_cmd_fusion - Sends command to the FW
- * @instance: Adapter soft state
- * @req_desc: 32bit or 64bit Request descriptor
+ * @instance: Adapter soft state
+ * @req_desc: 32bit or 64bit Request descriptor
*
* Perform PCI Write. AERO SERIES supports 32 bit Descriptor.
* Prior to AERO_SERIES support 64 bit Descriptor.
@@ -323,6 +408,9 @@ megasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_c
{
u16 cur_max_fw_cmds = 0;
u16 ldio_threshold = 0;
+ struct megasas_register_set __iomem *reg_set;
+
+ reg_set = instance->reg_set;
/* ventura FW does not fill outbound_scratch_pad_2 with queue depth */
if (instance->adapter_type < VENTURA_SERIES)
@@ -573,7 +661,6 @@ megasas_alloc_cmdlist_fusion(struct megasas_instance *instance)
return 0;
}
-
static int
megasas_alloc_request_fusion(struct megasas_instance *instance)
{
@@ -592,10 +679,17 @@ retry_alloc:
return -ENOMEM;
}
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0))
fusion->io_request_frames =
- dma_pool_alloc(fusion->io_request_frames_pool,
+ dma_pool_alloc(fusion->io_request_frames_pool,
+ ((GFP_KERNEL & (~__GFP_WAIT)) | __GFP_NOWARN),
+ &fusion->io_request_frames_phys);
+#else
+ fusion->io_request_frames =
+ dma_pool_alloc(fusion->io_request_frames_pool,
GFP_KERNEL | __GFP_NOWARN,
&fusion->io_request_frames_phys);
+#endif
if (!fusion->io_request_frames) {
if (instance->max_fw_cmds >= (MEGASAS_REDUCE_QD_COUNT * 2)) {
instance->max_fw_cmds -= MEGASAS_REDUCE_QD_COUNT;
@@ -630,11 +724,17 @@ retry_alloc:
"Failed from %s %d\n", __func__, __LINE__);
return -ENOMEM;
}
-
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0))
+ fusion->io_request_frames =
+ dma_pool_alloc(fusion->io_request_frames_pool,
+ ((GFP_KERNEL & (~__GFP_WAIT)) | __GFP_NOWARN),
+ &fusion->io_request_frames_phys);
+#else
fusion->io_request_frames =
dma_pool_alloc(fusion->io_request_frames_pool,
GFP_KERNEL | __GFP_NOWARN,
&fusion->io_request_frames_phys);
+#endif
if (!fusion->io_request_frames) {
dev_err(&instance->pdev->dev,
@@ -665,6 +765,8 @@ megasas_alloc_reply_fusion(struct megasas_instance *instance)
fusion = instance->ctrl_context;
count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+ count += instance->iopoll_q_count;
+
fusion->reply_frames_desc_pool =
dma_pool_create("mr_reply", &instance->pdev->dev,
fusion->reply_alloc_sz * count, 16, 0);
@@ -757,8 +859,9 @@ megasas_alloc_rdpq_fusion(struct megasas_instance *instance)
"Failed from %s %d\n", __func__, __LINE__);
return -ENOMEM;
}
-
+ memset(fusion->rdpq_virt, 0, array_size);
msix_count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+ msix_count += instance->iopoll_q_count;
fusion->reply_frames_desc_pool = dma_pool_create("mr_rdpq",
&instance->pdev->dev,
@@ -873,8 +976,10 @@ megasas_free_rdpq_fusion(struct megasas_instance *instance) {
}
- dma_pool_destroy(fusion->reply_frames_desc_pool);
- dma_pool_destroy(fusion->reply_frames_desc_pool_align);
+ if (fusion->reply_frames_desc_pool)
+ dma_pool_destroy(fusion->reply_frames_desc_pool);
+ if (fusion->reply_frames_desc_pool_align)
+ dma_pool_destroy(fusion->reply_frames_desc_pool_align);
if (fusion->rdpq_virt)
dma_free_coherent(&instance->pdev->dev,
@@ -894,7 +999,8 @@ megasas_free_reply_fusion(struct megasas_instance *instance) {
fusion->reply_frames_desc[0],
fusion->reply_frames_desc_phys[0]);
- dma_pool_destroy(fusion->reply_frames_desc_pool);
+ if (fusion->reply_frames_desc_pool)
+ dma_pool_destroy(fusion->reply_frames_desc_pool);
}
@@ -941,9 +1047,6 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance)
if (megasas_alloc_cmdlist_fusion(instance))
goto fail_exit;
- dev_info(&instance->pdev->dev, "Configured max firmware commands: %d\n",
- instance->max_fw_cmds);
-
/* The first 256 bytes (SMID 0) is not used. Don't add to the cmd list */
io_req_base = fusion->io_request_frames + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
io_req_base_phys = fusion->io_request_frames_phys + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
@@ -1086,8 +1189,9 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
MR_HIGH_IOPS_QUEUE_COUNT) && cur_intr_coalescing)
instance->perf_mode = MR_BALANCED_PERF_MODE;
- dev_info(&instance->pdev->dev, "Performance mode :%s\n",
- MEGASAS_PERF_MODE_2STR(instance->perf_mode));
+ dev_info(&instance->pdev->dev, "Performance mode :%s (latency index = %d)\n",
+ MEGASAS_PERF_MODE_2STR(instance->perf_mode),
+ instance->low_latency_index_start);
instance->fw_sync_cache_support = (scratch_pad_1 &
MR_CAN_HANDLE_SYNC_CACHE_OFFSET) ? 1 : 0;
@@ -1110,7 +1214,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE : 0;
IOCInitMessage->SystemRequestFrameBaseAddress = cpu_to_le64(fusion->io_request_frames_phys);
IOCInitMessage->SenseBufferAddressHigh = cpu_to_le32(upper_32_bits(fusion->sense_phys_addr));
- IOCInitMessage->HostMSIxVectors = instance->msix_vectors;
+ IOCInitMessage->HostMSIxVectors = instance->msix_vectors + instance->iopoll_q_count;
IOCInitMessage->HostPageSize = MR_DEFAULT_NVME_PAGE_SHIFT;
time = ktime_get_real();
@@ -1139,7 +1243,8 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
drv_ops->mfi_capabilities.support_ndrive_r1_lb = 1;
drv_ops->mfi_capabilities.security_protocol_cmds_fw = 1;
- if (instance->max_chain_frame_sz > MEGASAS_CHAIN_FRAME_SZ_MIN)
+ if ((!disable_ext_io) &&
+ (instance->max_chain_frame_sz > MEGASAS_CHAIN_FRAME_SZ_MIN))
drv_ops->mfi_capabilities.support_ext_io_size = 1;
drv_ops->mfi_capabilities.support_fp_rlbypass = 1;
@@ -1172,10 +1277,10 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
init_frame->queue_info_new_phys_addr_lo =
cpu_to_le32(lower_32_bits(ioc_init_handle));
init_frame->data_xfer_len = cpu_to_le32(sizeof(struct MPI2_IOC_INIT_REQUEST));
-
+
/*
- * Each bit in replyqueue_mask represents one group of MSI-x vectors
- * (each group has 8 vectors)
+ * Each bit in replyqueue_mask represents one group of MSI-x vectors
+ * (each group has 8 vectors)
*/
switch (instance->perf_mode) {
case MR_BALANCED_PERF_MODE:
@@ -1187,7 +1292,16 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
cpu_to_le16(~(~0 << instance->msix_vectors/8));
break;
}
+
+ if (instance->verbuf) {
+ snprintf((char *)instance->verbuf, strlen(MEGASAS_VERSION) + 2,
+ "%s", MEGASAS_VERSION);
+ if (reset_devices)
+ strcat((char *)instance->verbuf, "-kdump");
+ init_frame->driver_ver_lo = cpu_to_le32(lower_32_bits(instance->verbuf_h));
+ init_frame->driver_ver_hi = cpu_to_le32(upper_32_bits(instance->verbuf_h));
+ }
req_desc.u.low = cpu_to_le32(lower_32_bits(cmd->frame_phys_addr));
req_desc.u.high = cpu_to_le32(upper_32_bits(cmd->frame_phys_addr));
@@ -1218,15 +1332,16 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
goto fail_fw_init;
}
+
if (instance->adapter_type >= AERO_SERIES) {
- scratch_pad_1 = megasas_readl
- (instance, &instance->reg_set->outbound_scratch_pad_1);
+ scratch_pad_1 = megasas_readl
+ (instance, &instance->reg_set->outbound_scratch_pad_1);
- instance->atomic_desc_support =
- (scratch_pad_1 & MR_ATOMIC_DESCRIPTOR_SUPPORT_OFFSET) ? 1 : 0;
+ instance->atomic_desc_support =
+ (scratch_pad_1 & MR_ATOMIC_DESCRIPTOR_SUPPORT_OFFSET) ? 1 : 0;
- dev_info(&instance->pdev->dev, "FW supports atomic descriptor\t: %s\n",
- instance->atomic_desc_support ? "Yes" : "No");
+ dev_info(&instance->pdev->dev, "FW supports atomic descriptor\t: %s\n",
+ instance->atomic_desc_support ? "Yes" : "No");
}
return 0;
@@ -1260,7 +1375,9 @@ megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) {
pd_sync = (void *)fusion->pd_seq_sync[(instance->pd_seq_map_id & 1)];
pd_seq_h = fusion->pd_seq_phys[(instance->pd_seq_map_id & 1)];
- pd_seq_map_sz = struct_size(pd_sync, seq, MAX_PHYSICAL_DEVICES - 1);
+ pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) +
+ (sizeof(struct MR_PD_CFG_SEQ) *
+ (MAX_PHYSICAL_DEVICES - 1));
cmd = megasas_get_cmd(instance);
if (!cmd) {
@@ -1313,7 +1430,9 @@ megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) {
}
if (ret == DCMD_TIMEOUT)
- megaraid_sas_kill_hba(instance);
+ dev_warn(&instance->pdev->dev,
+ "%s DCMD timed out, continue without JBOD sequence map\n",
+ __func__);
if (ret == DCMD_SUCCESS)
instance->pd_seq_map_id++;
@@ -1395,7 +1514,9 @@ megasas_get_ld_map_info(struct megasas_instance *instance)
ret = megasas_issue_polled(instance, cmd);
if (ret == DCMD_TIMEOUT)
- megaraid_sas_kill_hba(instance);
+ dev_warn(&instance->pdev->dev,
+ "%s DCMD timed out, RAID map is disabled\n",
+ __func__);
megasas_return_cmd(instance, cmd);
@@ -1512,6 +1633,8 @@ megasas_display_intel_branding(struct megasas_instance *instance)
switch (instance->pdev->device) {
case PCI_DEVICE_ID_LSI_INVADER:
+ case PCI_DEVICE_ID_LSI_INTRUDER:
+ case PCI_DEVICE_ID_LSI_INTRUDER_24:
switch (instance->pdev->subsystem_device) {
case MEGARAID_INTEL_RS3DC080_SSDID:
dev_info(&instance->pdev->dev, "scsi host %d: %s\n",
@@ -1726,7 +1849,8 @@ static inline void megasas_free_ioc_init_cmd(struct megasas_instance *instance)
fusion->ioc_init_cmd->frame,
fusion->ioc_init_cmd->frame_phys_addr);
- kfree(fusion->ioc_init_cmd);
+ if (fusion->ioc_init_cmd)
+ kfree(fusion->ioc_init_cmd);
}
/**
@@ -1779,6 +1903,13 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
instance->max_chain_frame_sz = MEGASAS_CHAIN_FRAME_SZ_MIN;
}
+ /* 1MB IO support enable/disable only for Invader series */
+ if (instance->adapter_type >= VENTURA_SERIES)
+ disable_ext_io = 0;
+
+ if (disable_ext_io)
+ instance->max_chain_frame_sz = MEGASAS_CHAIN_FRAME_SZ_MIN;
+
fusion->max_sge_in_main_msg =
(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE
- offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL))/16;
@@ -1800,6 +1931,8 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
sizeof(union MPI2_SGE_IO_UNION))/16;
count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+ count += instance->iopoll_q_count;
+
for (i = 0 ; i < count; i++)
fusion->last_reply_idx[i] = 0;
@@ -1812,6 +1945,9 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
MEGASAS_FUSION_IOCTL_CMDS);
sema_init(&instance->ioctl_sem, MEGASAS_FUSION_IOCTL_CMDS);
+ for (i = 0; i < MAX_MSIX_QUEUES_FUSION; i++)
+ atomic_set(&fusion->busy_mq_poll[i], 0);
+
if (megasas_alloc_ioc_init_frame(instance))
return 1;
@@ -1872,7 +2008,7 @@ fail_alloc_mfi_cmds:
/**
* megasas_fault_detect_work - Worker function of
- * FW fault handling workqueue.
+ * FW fault handling workqueue.
*/
static void
megasas_fault_detect_work(struct work_struct *work)
@@ -1887,13 +2023,31 @@ megasas_fault_detect_work(struct work_struct *work)
MFI_STATE_MASK;
if (fw_state == MFI_STATE_FAULT) {
- dma_state = instance->instancet->read_fw_status_reg(instance) &
- MFI_STATE_DMADONE;
- /* Start collecting crash, if DMA bit is done */
if (instance->crash_dump_drv_support &&
- instance->crash_dump_app_support && dma_state) {
- megasas_fusion_crash_dump(instance);
+ instance->crash_dump_app_support) {
+ /* Start collecting crash, if DMA bit is done */
+ dma_state = instance->instancet->read_fw_status_reg(instance) &
+ MFI_STATE_DMADONE;
+ if (dma_state)
+ megasas_fusion_crash_dump(instance);
+ else {
+ dev_warn(&instance->pdev->dev,
+ "Iop2SysDoorbellInt for scsi%d\n",
+ instance->host->host_no);
+ if (instance->unload == 0) {
+ status = megasas_reset_fusion(instance->host, 0);
+ if (status != SUCCESS) {
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d, do not re-arm timer\n",
+ __func__, __LINE__);
+ return;
+ }
+ }
+ }
} else {
+ dev_warn(&instance->pdev->dev,
+ "Iop2SysDoorbellInt for scsi%d\n",
+ instance->host->host_no);
if (instance->unload == 0) {
status = megasas_reset_fusion(instance->host, 0);
if (status != SUCCESS) {
@@ -2037,7 +2191,6 @@ static bool
megasas_is_prp_possible(struct megasas_instance *instance,
struct scsi_cmnd *scmd, int sge_count)
{
- int i;
u32 data_length = 0;
struct scatterlist *sg_scmd;
bool build_prp = false;
@@ -2066,63 +2219,6 @@ megasas_is_prp_possible(struct megasas_instance *instance,
build_prp = true;
}
-/*
- * Below code detects gaps/holes in IO data buffers.
- * What does holes/gaps mean?
- * Any SGE except first one in a SGL starts at non NVME page size
- * aligned address OR Any SGE except last one in a SGL ends at
- * non NVME page size boundary.
- *
- * Driver has already informed block layer by setting boundary rules for
- * bio merging done at NVME page size boundary calling kernel API
- * blk_queue_virt_boundary inside slave_config.
- * Still there is possibility of IO coming with holes to driver because of
- * IO merging done by IO scheduler.
- *
- * With SCSI BLK MQ enabled, there will be no IO with holes as there is no
- * IO scheduling so no IO merging.
- *
- * With SCSI BLK MQ disabled, IO scheduler may attempt to merge IOs and
- * then sending IOs with holes.
- *
- * Though driver can request block layer to disable IO merging by calling-
- * blk_queue_flag_set(QUEUE_FLAG_NOMERGES, sdev->request_queue) but
- * user may tune sysfs parameter- nomerges again to 0 or 1.
- *
- * If in future IO scheduling is enabled with SCSI BLK MQ,
- * this algorithm to detect holes will be required in driver
- * for SCSI BLK MQ enabled case as well.
- *
- *
- */
- scsi_for_each_sg(scmd, sg_scmd, sge_count, i) {
- if ((i != 0) && (i != (sge_count - 1))) {
- if (mega_mod64(sg_dma_len(sg_scmd), mr_nvme_pg_size) ||
- mega_mod64(sg_dma_address(sg_scmd),
- mr_nvme_pg_size)) {
- build_prp = false;
- break;
- }
- }
-
- if ((sge_count > 1) && (i == 0)) {
- if ((mega_mod64((sg_dma_address(sg_scmd) +
- sg_dma_len(sg_scmd)),
- mr_nvme_pg_size))) {
- build_prp = false;
- break;
- }
- }
-
- if ((sge_count > 1) && (i == (sge_count - 1))) {
- if (mega_mod64(sg_dma_address(sg_scmd),
- mr_nvme_pg_size)) {
- build_prp = false;
- break;
- }
- }
- }
-
return build_prp;
}
@@ -2704,6 +2800,55 @@ megasas_set_raidflag_cpu_affinity(struct fusion_context *fusion,
}
}
+/*
+ * megasas_atomic_dec_if_positive - decrement by 1 if old value positive
+ * @v: pointer of type atomic_t
+ *
+ * The function returns the old value of *v minus 1, even if
+ * the atomic variable, v, was not decremented.
+ */
+static inline int megasas_atomic_dec_if_positive(atomic_t *v)
+{
+ int c, old, dec;
+ c = atomic_read(v);
+ for (;;) {
+ dec = c - 1;
+ if (unlikely(dec < 0))
+ break;
+ old = atomic_cmpxchg((v), c, dec);
+ if (likely(old == c))
+ break;
+ c = old;
+ }
+ return dec;
+}
+
+static inline void
+megasas_get_msix_index(struct megasas_instance *instance,
+ struct scsi_cmnd *scmd,
+ struct megasas_cmd_fusion *cmd,
+ u8 data_arms)
+{
+ if ((instance->perf_mode == MR_BALANCED_PERF_MODE) &&
+ (megasas_sdev_busy_read(instance, scmd) >
+ (data_arms * MR_DEVICE_HIGH_IOPS_DEPTH))) {
+ cmd->request_desc->SCSIIO.MSIxIndex =
+ mega_mod64((atomic64_add_return(1, &instance->high_iops_outstanding) /
+ MR_HIGH_IOPS_BATCH_COUNT), instance->low_latency_index_start);
+ } else if (instance->msix_load_balance) {
+ cmd->request_desc->SCSIIO.MSIxIndex =
+ (mega_mod64(atomic64_add_return(1, &instance->total_io_count),
+ instance->msix_vectors));
+ } else if (instance->host->nr_hw_queues > 1) {
+ u32 tag = blk_mq_unique_tag(scmd->request);
+ cmd->request_desc->SCSIIO.MSIxIndex = blk_mq_unique_tag_to_hwq(tag) +
+ instance->low_latency_index_start;
+ } else {
+ cmd->request_desc->SCSIIO.MSIxIndex =
+ instance->reply_map[raw_smp_processor_id()];
+ }
+}
+
/**
* megasas_build_ldio_fusion - Prepares IOs to devices
* @instance: Adapter soft state
@@ -2804,9 +2949,9 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
io_info.numBlocks = datalength;
io_info.ldTgtId = device_id;
io_info.r1_alt_dev_handle = MR_DEVHANDLE_INVALID;
+ io_info.data_arms = 1;
scsi_buff_len = scsi_bufflen(scp);
io_request->DataLength = cpu_to_le32(scsi_buff_len);
- io_info.data_arms = 1;
if (scp->sc_data_direction == DMA_FROM_DEVICE)
io_info.isRead = 1;
@@ -2826,20 +2971,8 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
fp_possible = (io_info.fpOkForIo > 0) ? true : false;
}
- if ((instance->perf_mode == MR_BALANCED_PERF_MODE) &&
- atomic_read(&scp->device->device_busy) >
- (io_info.data_arms * MR_DEVICE_HIGH_IOPS_DEPTH))
- cmd->request_desc->SCSIIO.MSIxIndex =
- mega_mod64((atomic64_add_return(1, &instance->high_iops_outstanding) /
- MR_HIGH_IOPS_BATCH_COUNT), instance->low_latency_index_start);
- else if (instance->msix_load_balance)
- cmd->request_desc->SCSIIO.MSIxIndex =
- (mega_mod64(atomic64_add_return(1, &instance->total_io_count),
- instance->msix_vectors));
- else
- cmd->request_desc->SCSIIO.MSIxIndex =
- instance->reply_map[raw_smp_processor_id()];
-
+ megasas_get_msix_index(instance, scp, cmd, io_info.data_arms);
+
if (instance->adapter_type >= VENTURA_SERIES) {
/* FP for Optimal raid level 1.
* All large RAID-1 writes (> 32 KiB, both WT and WB modes)
@@ -2856,9 +2989,9 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
(instance->host->can_queue)) {
fp_possible = false;
atomic_dec(&instance->fw_outstanding);
- } else if (fusion->pcie_bw_limitation &&
+ } else if ((fusion->pcie_bw_limitation) &&
((scsi_buff_len > MR_LARGE_IO_MIN_SIZE) ||
- (atomic_dec_if_positive(&mrdev_priv->r1_ldio_hint) > 0))) {
+ megasas_atomic_dec_if_positive(&mrdev_priv->r1_ldio_hint) > 0)) {
fp_possible = false;
atomic_dec(&instance->fw_outstanding);
if (scsi_buff_len > MR_LARGE_IO_MIN_SIZE)
@@ -2903,8 +3036,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
rctx->nseg = 0x1;
io_request->IoFlags |= cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
rctx->reg_lock_flags |=
- (MR_RL_FLAGS_GRANT_DESTINATION_CUDA |
- MR_RL_FLAGS_SEQ_NUM_ENABLE);
+ (MR_RL_FLAGS_GRANT_DESTINATION_CUDA | MR_RL_FLAGS_SEQ_NUM_ENABLE);
} else if (instance->adapter_type >= VENTURA_SERIES) {
rctx_g35->nseg_type |= (1 << RAID_CONTEXT_NSEG_SHIFT);
rctx_g35->nseg_type |= (MPI2_TYPE_CUDA << RAID_CONTEXT_TYPE_SHIFT);
@@ -3106,22 +3238,19 @@ megasas_build_syspd_fusion(struct megasas_instance *instance,
<< MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT;
/* If FW supports PD sequence number */
- if (!reset_devices && instance->support_seqnum_jbod_fp) {
+ if (instance->support_seqnum_jbod_fp) {
if (instance->use_seqnum_jbod_fp &&
instance->pd_list[pd_index].driveType == TYPE_DISK) {
-
+
/* More than 256 PD/JBOD support for Ventura */
if (instance->support_morethan256jbod)
pRAID_Context->virtual_disk_tgt_id =
pd_sync->seq[pd_index].pd_target_id;
else
pRAID_Context->virtual_disk_tgt_id =
- cpu_to_le16(device_id +
- (MAX_PHYSICAL_DEVICES - 1));
- pRAID_Context->config_seq_num =
- pd_sync->seq[pd_index].seqNum;
- io_request->DevHandle =
- pd_sync->seq[pd_index].devHandle;
+ cpu_to_le16(device_id + (MAX_PHYSICAL_DEVICES - 1));
+ pRAID_Context->config_seq_num = pd_sync->seq[pd_index].seqNum;
+ io_request->DevHandle = pd_sync->seq[pd_index].devHandle;
if (instance->adapter_type >= VENTURA_SERIES) {
io_request->RaidContext.raid_context_g35.routing_flags |=
(1 << MR_RAID_CTX_ROUTINGFLAGS_SQN_SHIFT);
@@ -3133,23 +3262,27 @@ megasas_build_syspd_fusion(struct megasas_instance *instance,
pRAID_Context->type = MPI2_TYPE_CUDA;
pRAID_Context->nseg = 0x1;
pRAID_Context->reg_lock_flags |=
- (MR_RL_FLAGS_SEQ_NUM_ENABLE |
- MR_RL_FLAGS_GRANT_DESTINATION_CUDA);
+ (MR_RL_FLAGS_SEQ_NUM_ENABLE|MR_RL_FLAGS_GRANT_DESTINATION_CUDA);
}
} else {
- pRAID_Context->virtual_disk_tgt_id =
- cpu_to_le16(device_id +
- (MAX_PHYSICAL_DEVICES - 1));
- pRAID_Context->config_seq_num = 0;
- io_request->DevHandle = cpu_to_le16(0xFFFF);
+ pRAID_Context->virtual_disk_tgt_id =
+ cpu_to_le16(device_id + (MAX_PHYSICAL_DEVICES - 1));
+ pRAID_Context->config_seq_num = 0;
+ io_request->DevHandle = cpu_to_le16(0xFFFF);
+
+ if (instance->pd_list[pd_index].driveType == TYPE_TAPE) {
+ local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
+ io_request->DevHandle =
+ local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
+ }
}
+
} else {
pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id);
pRAID_Context->config_seq_num = 0;
-
+
if (fusion->fast_path_io) {
- local_map_ptr =
- fusion->ld_drv_map[(instance->map_id & 1)];
+ local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
io_request->DevHandle =
local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
} else {
@@ -3158,20 +3291,9 @@ megasas_build_syspd_fusion(struct megasas_instance *instance,
}
cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle;
-
- if ((instance->perf_mode == MR_BALANCED_PERF_MODE) &&
- atomic_read(&scmd->device->device_busy) > MR_DEVICE_HIGH_IOPS_DEPTH)
- cmd->request_desc->SCSIIO.MSIxIndex =
- mega_mod64((atomic64_add_return(1, &instance->high_iops_outstanding) /
- MR_HIGH_IOPS_BATCH_COUNT), instance->low_latency_index_start);
- else if (instance->msix_load_balance)
- cmd->request_desc->SCSIIO.MSIxIndex =
- (mega_mod64(atomic64_add_return(1, &instance->total_io_count),
- instance->msix_vectors));
- else
- cmd->request_desc->SCSIIO.MSIxIndex =
- instance->reply_map[raw_smp_processor_id()];
-
+
+ megasas_get_msix_index(instance, scmd, cmd, 1);
+
if (!fp_possible) {
/* system pd firmware path */
io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
@@ -3181,6 +3303,9 @@ megasas_build_syspd_fusion(struct megasas_instance *instance,
pRAID_Context->timeout_value = cpu_to_le16(os_timeout_value);
pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id);
} else {
+ /* Hardware errata. Fast Path engine need one second extra
+ * to avoid early timeout.
+ */
if (os_timeout_value)
os_timeout_value++;
@@ -3217,6 +3342,8 @@ megasas_build_io_fusion(struct megasas_instance *instance,
{
int sge_count;
u8 cmd_type;
+ u16 pd_index = 0;
+ u8 driveType = 0;
struct MPI2_RAID_SCSI_IO_REQUEST *io_request = cmd->io_request;
struct MR_PRIV_DEVICE *mr_device_priv_data;
mr_device_priv_data = scp->device->hostdata;
@@ -3251,8 +3378,12 @@ megasas_build_io_fusion(struct megasas_instance *instance,
megasas_build_syspd_fusion(instance, scp, cmd, true);
break;
case NON_READ_WRITE_SYSPDIO:
- if (instance->secure_jbod_support ||
- mr_device_priv_data->is_tm_capable)
+ pd_index = MEGASAS_PD_INDEX(scp);
+ driveType = instance->pd_list[pd_index].driveType;
+ if ((instance->secure_jbod_support ||
+ mr_device_priv_data->is_tm_capable) ||
+ (instance->adapter_type >= VENTURA_SERIES &&
+ driveType == TYPE_ENCLOSURE))
megasas_build_syspd_fusion(instance, scp, cmd, false);
else
megasas_build_syspd_fusion(instance, scp, cmd, true);
@@ -3325,8 +3456,8 @@ megasas_get_request_descriptor(struct megasas_instance *instance, u16 index)
* It prepares the raid 1 second IO
*/
static void megasas_prepare_secondRaid1_IO(struct megasas_instance *instance,
- struct megasas_cmd_fusion *cmd,
- struct megasas_cmd_fusion *r1_cmd)
+ 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;
@@ -3440,6 +3571,7 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
* Issue the command to the FW
*/
+ megasas_sdev_busy_inc(instance, scmd);
megasas_fire_cmd_fusion(instance, req_desc);
if (r1_cmd)
@@ -3500,18 +3632,54 @@ megasas_complete_r1_command(struct megasas_instance *instance,
scmd_local->SCp.ptr = NULL;
megasas_return_cmd_fusion(instance, cmd);
scsi_dma_unmap(scmd_local);
+ megasas_sdev_busy_dec(instance, scmd_local);
scmd_local->scsi_done(scmd_local);
}
}
+/**
+ * access_irq_context: Access to reply processing
+ * @irq_context: IRQ context
+ *
+ * Synchronize access to reply processing.
+ *
+ * Return: true on success, false on failure.
+ */
+static inline
+bool access_irq_context(struct megasas_irq_context *irq_context)
+{
+ if (!irq_context)
+ return true;
+
+ if (atomic_add_unless(&irq_context->in_use, 1, 1))
+ return true;
+
+ return false;
+}
+
+/**
+ * release_irq_context: Release reply processing
+ * @irq_context: IRQ context
+ *
+ * Release access of reply processing.
+ *
+ * Return: Nothing.
+ */
+static inline
+void release_irq_context(struct megasas_irq_context *irq_context)
+{
+ if (irq_context)
+ atomic_dec(&irq_context->in_use);
+}
+
/**
* complete_cmd_fusion - Completes command
* @instance: Adapter soft state
* Completes all commands that is in reply descriptor queue
*/
-static int
+int
complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex,
- struct megasas_irq_context *irq_context)
+ struct megasas_irq_context *irq_context)
{
union MPI2_REPLY_DESCRIPTORS_UNION *desc;
struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *reply_desc;
@@ -3519,7 +3687,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex,
struct fusion_context *fusion;
struct megasas_cmd *cmd_mfi;
struct megasas_cmd_fusion *cmd_fusion;
- u16 smid, num_completed;
+ u16 smid, num_completed = 0;
u8 reply_descript_type, *sense, status, extStatus;
u32 device_id, data_length;
union desc_value d_val;
@@ -3534,6 +3702,9 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex,
if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
return IRQ_HANDLED;
+ if (!access_irq_context(irq_context))
+ return 0;
+
desc = fusion->reply_frames_desc[MSIxIndex] +
fusion->last_reply_idx[MSIxIndex];
@@ -3544,10 +3715,10 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex,
reply_descript_type = reply_desc->ReplyFlags &
MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
- if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
+ if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) {
+ release_irq_context(irq_context);
return IRQ_NONE;
-
- num_completed = 0;
+ }
while (d_val.u.low != cpu_to_le32(UINT_MAX) &&
d_val.u.high != cpu_to_le32(UINT_MAX)) {
@@ -3597,6 +3768,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex,
scmd_local->SCp.ptr = NULL;
megasas_return_cmd_fusion(instance, cmd_fusion);
scsi_dma_unmap(scmd_local);
+ megasas_sdev_busy_dec(instance, scmd_local);
scmd_local->scsi_done(scmd_local);
} else /* Optimal VD - R1 FP command completion. */
megasas_complete_r1_command(instance, cmd_fusion);
@@ -3654,14 +3826,17 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex,
fusion->last_reply_idx[MSIxIndex],
instance->reply_post_host_index_addr[0]);
threshold_reply_count = 0;
+#if defined(ENABLE_IRQ_POLL)
if (irq_context) {
if (!irq_context->irq_poll_scheduled) {
irq_context->irq_poll_scheduled = true;
irq_context->irq_line_enable = true;
irq_poll_sched(&irq_context->irqpoll);
}
+ release_irq_context(irq_context);
return num_completed;
}
+#endif
}
}
@@ -3677,14 +3852,46 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex,
instance->reply_post_host_index_addr[0]);
megasas_check_and_restore_queue_depth(instance);
}
+
+ release_irq_context(irq_context);
return num_completed;
}
-/**
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0))
+int megasas_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
+{
+
+ struct megasas_instance *instance;
+ int num_entries = 0;
+ struct fusion_context *fusion;
+
+ instance = (struct megasas_instance *)shost->hostdata;
+
+ fusion = instance->ctrl_context;
+
+ queue_num = queue_num + instance->low_latency_index_start;
+
+ if (!atomic_add_unless(&fusion->busy_mq_poll[queue_num], 1, 1))
+ return 0;
+
+ num_entries = complete_cmd_fusion(instance, queue_num, NULL);
+ atomic_dec(&fusion->busy_mq_poll[queue_num]);
+
+ return num_entries;
+}
+#else
+int megasas_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
+{
+ return 0;
+}
+#endif
+
+/*
* megasas_enable_irq_poll() - enable irqpoll
*/
-static void megasas_enable_irq_poll(struct megasas_instance *instance)
+void megasas_enable_irq_poll(struct megasas_instance *instance)
{
+#if defined(ENABLE_IRQ_POLL)
u32 count, i;
struct megasas_irq_context *irq_ctx;
@@ -3694,33 +3901,40 @@ static void megasas_enable_irq_poll(struct megasas_instance *instance)
irq_ctx = &instance->irq_context[i];
irq_poll_enable(&irq_ctx->irqpoll);
}
+#endif
}
/**
* megasas_sync_irqs - Synchronizes all IRQs owned by adapter
* @instance: Adapter soft state
*/
-static void megasas_sync_irqs(unsigned long instance_addr)
+void megasas_sync_irqs(unsigned long instance_addr)
{
u32 count, i;
struct megasas_instance *instance =
(struct megasas_instance *)instance_addr;
+#if defined(ENABLE_IRQ_POLL)
struct megasas_irq_context *irq_ctx;
+#endif
count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
for (i = 0; i < count; i++) {
- synchronize_irq(pci_irq_vector(instance->pdev, i));
+ synchronize_irq(megasas_get_irq(instance, i));
+#if defined(ENABLE_IRQ_POLL)
irq_ctx = &instance->irq_context[i];
irq_poll_disable(&irq_ctx->irqpoll);
if (irq_ctx->irq_poll_scheduled) {
irq_ctx->irq_poll_scheduled = false;
enable_irq(irq_ctx->os_irq);
+ complete_cmd_fusion(instance, irq_ctx->MSIxIndex, irq_ctx);
}
+#endif
}
}
-/**
+#if defined(ENABLE_IRQ_POLL)
+/*
* megasas_irqpoll() - process a queue for completed reply descriptors
* @irqpoll: IRQ poll structure associated with queue to poll.
* @budget: Threshold of reply descriptors to process per poll.
@@ -3733,7 +3947,6 @@ int megasas_irqpoll(struct irq_poll *irqpoll, int budget)
struct megasas_irq_context *irq_ctx;
struct megasas_instance *instance;
int num_entries;
-
irq_ctx = container_of(irqpoll, struct megasas_irq_context, irqpoll);
instance = irq_ctx->instance;
@@ -3747,10 +3960,12 @@ int megasas_irqpoll(struct irq_poll *irqpoll, int budget)
irq_poll_complete(irqpoll);
irq_ctx->irq_poll_scheduled = false;
enable_irq(irq_ctx->os_irq);
+ complete_cmd_fusion(instance, irq_ctx->MSIxIndex, irq_ctx);
}
return num_entries;
-}
+ }
+#endif
/**
* megasas_complete_cmd_dpc_fusion - Completes command
@@ -3758,12 +3973,13 @@ int megasas_irqpoll(struct irq_poll *irqpoll, int budget)
*
* Tasklet to complete cmds
*/
-static void
+void
megasas_complete_cmd_dpc_fusion(unsigned long instance_addr)
{
struct megasas_instance *instance =
(struct megasas_instance *)instance_addr;
u32 count, MSIxIndex;
+ struct megasas_irq_context *irq_ctx;
count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
@@ -3771,14 +3987,16 @@ megasas_complete_cmd_dpc_fusion(unsigned long instance_addr)
if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
return;
- for (MSIxIndex = 0 ; MSIxIndex < count; MSIxIndex++)
- complete_cmd_fusion(instance, MSIxIndex, NULL);
+ for (MSIxIndex = 0 ; MSIxIndex < count; MSIxIndex++) {
+ irq_ctx = &instance->irq_context[MSIxIndex];
+ complete_cmd_fusion(instance, MSIxIndex, irq_ctx);
+ }
}
/**
* megasas_isr_fusion - isr entry point
*/
-static irqreturn_t megasas_isr_fusion(int irq, void *devp)
+irqreturn_t megasas_isr_fusion(int irq, void *devp)
{
struct megasas_irq_context *irq_context = devp;
struct megasas_instance *instance = irq_context->instance;
@@ -3787,8 +4005,10 @@ static irqreturn_t megasas_isr_fusion(int irq, void *devp)
if (instance->mask_interrupts)
return IRQ_NONE;
+#if defined(ENABLE_IRQ_POLL)
if (irq_context->irq_poll_scheduled)
return IRQ_HANDLED;
+#endif
if (!instance->msix_vectors) {
mfiStatus = instance->instancet->clear_intr(instance);
@@ -3802,8 +4022,7 @@ static irqreturn_t megasas_isr_fusion(int irq, void *devp)
return IRQ_HANDLED;
}
- return complete_cmd_fusion(instance, irq_context->MSIxIndex, irq_context)
- ? IRQ_HANDLED : IRQ_NONE;
+ return complete_cmd_fusion(instance, irq_context->MSIxIndex, irq_context) ? IRQ_HANDLED : IRQ_NONE;
}
/**
@@ -3812,7 +4031,7 @@ static irqreturn_t megasas_isr_fusion(int irq, void *devp)
* mfi_cmd: megasas_cmd pointer
*
*/
-static void
+void
build_mpt_mfi_pass_thru(struct megasas_instance *instance,
struct megasas_cmd *mfi_cmd)
{
@@ -3870,7 +4089,7 @@ build_mpt_mfi_pass_thru(struct megasas_instance *instance,
* @cmd: mfi cmd to build
*
*/
-static union MEGASAS_REQUEST_DESCRIPTOR_UNION *
+union MEGASAS_REQUEST_DESCRIPTOR_UNION *
build_mpt_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
{
union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc = NULL;
@@ -3896,7 +4115,7 @@ build_mpt_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
* @cmd: mfi cmd pointer
*
*/
-static void
+void
megasas_issue_dcmd_fusion(struct megasas_instance *instance,
struct megasas_cmd *cmd)
{
@@ -3931,7 +4150,8 @@ megasas_release_fusion(struct megasas_instance *instance)
static u32
megasas_read_fw_status_reg_fusion(struct megasas_instance *instance)
{
- return megasas_readl(instance, &instance->reg_set->outbound_scratch_pad_0);
+ return megasas_readl(instance,
+ &instance->reg_set->outbound_scratch_pad_0);
}
/**
@@ -4015,7 +4235,8 @@ megasas_adp_reset_fusion(struct megasas_instance *instance,
msleep(3000);
/* Make sure reset adapter bit is cleared */
- host_diag = megasas_readl(instance, &instance->reg_set->fusion_host_diag);
+ host_diag = megasas_readl(instance,
+ &instance->reg_set->fusion_host_diag);
retry = 0;
while (host_diag & HOST_DIAG_RESET_ADAPTER) {
msleep(100);
@@ -4063,7 +4284,7 @@ megasas_check_reset_fusion(struct megasas_instance *instance,
/**
* megasas_trigger_snap_dump - Trigger snap dump in FW
- * @instance: Soft instance of adapter
+ * @instance: Soft instance of adapter
*/
static inline void megasas_trigger_snap_dump(struct megasas_instance *instance)
{
@@ -4073,28 +4294,29 @@ static inline void megasas_trigger_snap_dump(struct megasas_instance *instance)
if (!instance->disableOnlineCtrlReset) {
dev_info(&instance->pdev->dev, "Trigger snap dump\n");
writel(MFI_ADP_TRIGGER_SNAP_DUMP,
- &instance->reg_set->doorbell);
+ &instance->reg_set->doorbell);
readl(&instance->reg_set->doorbell);
}
-
+
for (j = 0; j < instance->snapdump_wait_time; j++) {
abs_state = instance->instancet->read_fw_status_reg(instance);
fw_state = abs_state & MFI_STATE_MASK;
if (fw_state == MFI_STATE_FAULT) {
dev_printk(KERN_ERR, &instance->pdev->dev,
- "FW in FAULT state Fault code:0x%x subcode:0x%x func:%s\n",
- abs_state & MFI_STATE_FAULT_CODE,
- abs_state & MFI_STATE_FAULT_SUBCODE, __func__);
+ "FW in FAULT state Fault code:0x%x"
+ " subcode:0x%x func:%s\n",
+ abs_state & MFI_STATE_FAULT_CODE,
+ abs_state & MFI_STATE_FAULT_SUBCODE, __func__);
return;
}
msleep(1000);
}
+
}
/* This function waits for outstanding commands on fusion to complete */
-static int
-megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
- int reason, int *convert)
+int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
+ int reason, int *convert)
{
int i, outstanding, retval = 0, hb_seconds_missed = 0;
u32 fw_state, abs_state;
@@ -4120,9 +4342,10 @@ megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
fw_state = abs_state & MFI_STATE_MASK;
if (fw_state == MFI_STATE_FAULT) {
dev_printk(KERN_ERR, &instance->pdev->dev,
- "FW in FAULT state Fault code:0x%x subcode:0x%x func:%s\n",
- abs_state & MFI_STATE_FAULT_CODE,
- abs_state & MFI_STATE_FAULT_SUBCODE, __func__);
+ "FW in FAULT state Fault code:0x%x"
+ " subcode:0x%x func:%s\n",
+ abs_state & MFI_STATE_FAULT_CODE,
+ abs_state & MFI_STATE_FAULT_SUBCODE, __func__);
megasas_complete_cmd_dpc_fusion((unsigned long)instance);
if (instance->requestorId && reason) {
dev_warn(&instance->pdev->dev, "SR-IOV Found FW in FAULT"
@@ -4168,7 +4391,10 @@ megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
}
megasas_complete_cmd_dpc_fusion((unsigned long)instance);
+
outstanding = atomic_read(&instance->fw_outstanding);
+
+
if (!outstanding)
goto out;
@@ -4206,6 +4432,8 @@ void megasas_reset_reply_desc(struct megasas_instance *instance)
fusion = instance->ctrl_context;
count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+ count += instance->iopoll_q_count;
+
for (i = 0 ; i < count ; i++) {
fusion->last_reply_idx[i] = 0;
reply_desc = fusion->reply_frames_desc[i];
@@ -4218,7 +4446,7 @@ void megasas_reset_reply_desc(struct megasas_instance *instance)
* megasas_refire_mgmt_cmd : Re-fire management commands
* @instance: Controller's soft instance
*/
-static void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
+void megasas_refire_mgmt_cmd(struct megasas_instance *instance, bool return_ioctl)
{
int j;
struct megasas_cmd_fusion *cmd_fusion;
@@ -4282,9 +4510,18 @@ static void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
default:
break;
}
+
+ if (return_ioctl && cmd_mfi->sync_cmd &&
+ (cmd_mfi->frame->hdr.cmd != MFI_CMD_ABORT)) {
+ dev_err(&instance->pdev->dev,
+ "return -EBUSY from %s %d cmd 0x%x opcode 0x%x \n",
+ __func__, __LINE__, cmd_mfi->frame->hdr.cmd, le32_to_cpu(cmd_mfi->frame->dcmd.opcode));
+ cmd_mfi->cmd_status_drv = DCMD_BUSY;
+ result = COMPLETE_CMD;
+ }
- scsi_io_req = (struct MPI2_RAID_SCSI_IO_REQUEST *)
- cmd_fusion->io_request;
+ /* Do not re-fire TM command */
+ scsi_io_req = (struct MPI2_RAID_SCSI_IO_REQUEST *) cmd_fusion->io_request;
if (scsi_io_req->Function == MPI2_FUNCTION_SCSI_TASK_MGMT)
result = RETURN_CMD;
@@ -4302,6 +4539,37 @@ static void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
}
}
+/*
+ * megasas_return_polled_cmds: Return polled mode commands back to the pool
+ * before initiating an OCR.
+ * @instance: Controller's soft instance
+*/
+static void
+megasas_return_polled_cmds(struct megasas_instance *instance)
+{
+ int i;
+ struct megasas_cmd_fusion *cmd_fusion;
+ struct fusion_context *fusion;
+ struct megasas_cmd *cmd_mfi;
+
+ fusion = instance->ctrl_context;
+
+ for (i = instance->max_scsi_cmds; i < instance->max_fw_cmds; i++) {
+ cmd_fusion = fusion->cmd_list[i];
+ cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx];
+
+ if (cmd_mfi->flags & DRV_DCMD_POLLED_MODE) {
+ if (megasas_dbg_lvl & OCR_DEBUG)
+ dev_info(&instance->pdev->dev,
+ "%s %d return cmd 0x%x opcode 0x%x\n",
+ __func__, __LINE__, cmd_mfi->frame->hdr.cmd,
+ le32_to_cpu(cmd_mfi->frame->dcmd.opcode));
+ cmd_mfi->flags &= ~DRV_DCMD_POLLED_MODE;
+ megasas_return_cmd(instance, cmd_mfi);
+ }
+ }
+}
+
/*
* megasas_track_scsiio : Track SCSI IOs outstanding to a SCSI device
* @instance: per adapter struct
@@ -4708,8 +4976,8 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
}
if (!mr_device_priv_data) {
- sdev_printk(KERN_INFO, scmd->device,
- "device been deleted! scmd: (0x%p)\n", scmd);
+ sdev_printk(KERN_INFO, scmd->device, "device been deleted! "
+ "scmd: (0x%p)\n", scmd);
scmd->result = DID_NO_CONNECT << 16;
ret = SUCCESS;
goto out;
@@ -4743,14 +5011,13 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
mutex_unlock(&instance->reset_mutex);
scmd_printk(KERN_NOTICE, scmd, "target reset %s!!\n",
(ret == SUCCESS) ? "SUCCESS" : "FAILED");
-
out:
+
return ret;
}
/*SRIOV get other instance in cluster if any*/
-static struct
-megasas_instance *megasas_get_peer_instance(struct megasas_instance *instance)
+struct megasas_instance *megasas_get_peer_instance(struct megasas_instance *instance)
{
int i;
@@ -4820,7 +5087,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
dev_info(&instance->pdev->dev, "IO/DCMD timeout is detected, "
"forcibly FAULT Firmware\n");
atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
- status_reg = megasas_readl(instance, &instance->reg_set->doorbell);
+ status_reg = megasas_readl(instance,
+ &instance->reg_set->doorbell);
writel(status_reg | MFI_STATE_FORCE_OCR,
&instance->reg_set->doorbell);
readl(&instance->reg_set->doorbell);
@@ -4900,7 +5168,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
scmd_local->scsi_done(scmd_local);
}
}
-
+
dev_info(&instance->pdev->dev, "Outstanding fastpath IOs: %d\n",
fpio_count);
@@ -4932,16 +5200,10 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
* controller to transition to ready
*/
if (megasas_adp_reset_wait_for_ready(instance,
- do_adp_reset, 1) == FAILED)
- continue;
-
- /* Wait for FW to become ready */
- if (megasas_transition_to_ready(instance, 1)) {
- dev_warn(&instance->pdev->dev,
- "Failed to transition controller to ready for "
- "scsi%d.\n", instance->host->host_no);
+ do_adp_reset, 1) == FAILED) {
continue;
}
+
megasas_reset_reply_desc(instance);
megasas_fusion_update_can_queue(instance, OCR_CONTEXT);
@@ -4956,7 +5218,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
goto kill_hba;
}
- megasas_refire_mgmt_cmd(instance);
+ megasas_refire_mgmt_cmd(instance, (i == (MEGASAS_FUSION_MAX_RESET_TRIES - 1) ? 1 : 0));
/* Reset load balance info */
if (fusion->load_balance_info)
@@ -4964,8 +5226,16 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
(sizeof(struct LD_LOAD_BALANCE_INFO) *
MAX_LOGICAL_DRIVES_EXT));
- if (!megasas_get_map_info(instance))
+ if (!megasas_get_map_info(instance)) {
megasas_sync_map_info(instance);
+ } else {
+ /*
+ * Return pending polled mode cmds before
+ * retrying OCR
+ */
+ megasas_return_polled_cmds(instance);
+ continue;
+ }
megasas_setup_jbod_map(instance);
@@ -4983,20 +5253,29 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
&instance->reset_flags);
instance->instancet->enable_intr(instance);
megasas_enable_irq_poll(instance);
+
shost_for_each_device(sdev, shost) {
- if ((instance->tgt_prop) &&
- (instance->nvme_page_size))
+ if ((instance->tgt_prop) && (instance->nvme_page_size))
ret_target_prop = megasas_get_target_prop(instance, sdev);
is_target_prop = (ret_target_prop == DCMD_SUCCESS) ? true : false;
megasas_set_dynamic_target_properties(sdev, is_target_prop);
}
+ status_reg = instance->instancet->read_fw_status_reg(instance);
+ abs_state = status_reg & MFI_STATE_MASK;
+ if (abs_state != MFI_STATE_OPERATIONAL) {
+ dev_info(&instance->pdev->dev,
+ "Adapter is not OPERATIONAL, state 0x%x for scsi:%d\n",
+ abs_state, instance->host->host_no);
+ goto out;
+ }
+
atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
dev_info(&instance->pdev->dev,
- "Adapter is OPERATIONAL for scsi:%d\n",
- instance->host->host_no);
+ "Adapter is OPERATIONAL for scsi:%d\n",
+ instance->host->host_no);
/* Restart SR-IOV heartbeat */
if (instance->requestorId) {
@@ -5057,7 +5336,7 @@ out:
}
/* Fusion Crash dump collection */
-static void megasas_fusion_crash_dump(struct megasas_instance *instance)
+void megasas_fusion_crash_dump(struct megasas_instance *instance)
{
u32 status_reg;
u8 partial_copy = 0;
@@ -5090,7 +5369,7 @@ static void megasas_fusion_crash_dump(struct megasas_instance *instance)
}
while (!(status_reg & MFI_STATE_CRASH_DUMP_DONE) &&
- (wait < MEGASAS_WATCHDOG_WAIT_COUNT)) {
+ (wait < MEGASAS_WATCHDOG_WAIT_COUNT)) {
if (!(status_reg & MFI_STATE_DMADONE)) {
/*
* Next crash dump buffer is not yet DMA'd by FW
@@ -5099,8 +5378,7 @@ static void megasas_fusion_crash_dump(struct megasas_instance *instance)
*/
wait++;
msleep(MEGASAS_WAIT_FOR_NEXT_DMA_MSECS);
- status_reg = instance->instancet->read_fw_status_reg(
- instance);
+ status_reg = instance->instancet->read_fw_status_reg(instance);
continue;
}
@@ -5109,12 +5387,12 @@ static void megasas_fusion_crash_dump(struct megasas_instance *instance)
dev_info(&instance->pdev->dev,
"Driver is done copying the buffer: %d\n",
instance->drv_buf_alloc);
- status_reg |= MFI_STATE_CRASH_DUMP_DONE;
+ status_reg |= MFI_STATE_CRASH_DUMP_DONE; /* notify FW that driver is done copying crash dump*/
partial_copy = 1;
break;
} else {
- memcpy(instance->crash_buf[instance->drv_buf_index],
- instance->crash_dump_buf, CRASH_DMA_BUF_SIZE);
+ memcpy(instance->crash_buf[instance->drv_buf_index], instance->crash_dump_buf,
+ CRASH_DMA_BUF_SIZE);
instance->drv_buf_index++;
status_reg &= ~MFI_STATE_DMADONE;
}
@@ -5172,11 +5450,12 @@ megasas_alloc_fusion_context(struct megasas_instance *instance)
fusion->log_to_span_pages);
if (!fusion->log_to_span) {
fusion->log_to_span =
- vzalloc(array_size(MAX_LOGICAL_DRIVES_EXT,
- sizeof(LD_SPAN_INFO)));
+ vzalloc(MAX_LOGICAL_DRIVES_EXT *
+ sizeof(LD_SPAN_INFO));
if (!fusion->log_to_span) {
dev_err(&instance->pdev->dev, "Failed from %s %d\n",
__func__, __LINE__);
+ kfree(instance->ctrl_context);
return -ENOMEM;
}
}
@@ -5188,8 +5467,8 @@ megasas_alloc_fusion_context(struct megasas_instance *instance)
fusion->load_balance_info_pages);
if (!fusion->load_balance_info) {
fusion->load_balance_info =
- vzalloc(array_size(MAX_LOGICAL_DRIVES_EXT,
- sizeof(struct LD_LOAD_BALANCE_INFO)));
+ vzalloc(MAX_LOGICAL_DRIVES_EXT *
+ sizeof(struct LD_LOAD_BALANCE_INFO));
if (!fusion->load_balance_info)
dev_err(&instance->pdev->dev, "Failed to allocate load_balance_info, "
"continuing without Load Balance support\n");
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
index dd2e37e40..4879ff8fc 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
@@ -1,10 +1,22 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Linux MegaRAID driver for SAS based RAID controllers
*
- * Copyright (c) 2009-2013 LSI Corporation
- * Copyright (c) 2013-2016 Avago Technologies
- * Copyright (c) 2016-2018 Broadcom Inc.
+ * Copyright (c) 2009-2018 LSI Corporation.
+ * Copyright (c) 2009-2018 Avago Technologies.
+ * Copyright (c) 2009-2018 Broadcom Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
*
* FILE: megaraid_sas_fusion.h
*
@@ -140,16 +152,17 @@ struct RAID_CONTEXT_G35 {
u16 nseg_type;
u16 timeout_value; /* 0x02 -0x03 */
u16 routing_flags; // 0x04 -0x05 routing flags
- u16 virtual_disk_tgt_id; /* 0x06 -0x07 */
- __le64 reg_lock_row_lba; /* 0x08 - 0x0F */
- u32 reg_lock_length; /* 0x10 - 0x13 */
- union { // flow specific
- u16 rmw_op_index; /* 0x14 - 0x15, R5/6 RMW: rmw operation index*/
- u16 peer_smid; /* 0x14 - 0x15, R1 Write: peer smid*/
- u16 r56_arm_map; /* 0x14 - 0x15, Unused [15], LogArm[14:10], P-Arm[9:5], Q-Arm[4:0] */
+ u16 virtual_disk_tgt_id; /* 0x06 -0x07 */
+ __le64 reg_lock_row_lba; /* 0x08 - 0x0F */
+ u32 reg_lock_length; /* 0x10 - 0x13 */
+ union { // flow specific
+ u16 rmw_op_index; /* 0x14 - 0x15, R5/6 RMW: rmw operation index*/
+ u16 peer_smid; /* 0x14 - 0x15, R1 Write: peer smid*/
+ u16 r56_arm_map; /* 0x14 - 0x15, Unused [15], LogArm[14:10], P-Arm[9:5], Q-Arm[4:0] */
} flow_specific;
+
u8 ex_status; /* 0x16 : OUT */
u8 status; /* 0x17 status */
u8 raid_flags; /* 0x18 resvd[7:6], ioSubType[5:4],
@@ -246,7 +259,7 @@ union RAID_CONTEXT_UNION {
#define RAID_CTX_R56_P_ARM_MASK (0x3E0)
#define RAID_CTX_R56_LOG_ARM_SHIFT (10)
#define RAID_CTX_R56_LOG_ARM_MASK (0x7C00)
-
+
/* number of bits per index in U32 TrackStream */
#define BITS_PER_INDEX_STREAM 4
#define INVALID_STREAM_NUM 16
@@ -774,7 +787,7 @@ struct MR_SPAN_BLOCK_INFO {
struct MR_CPU_AFFINITY_MASK {
union {
struct {
-#ifndef MFI_BIG_ENDIAN
+#ifndef __BIG_ENDIAN_BITFIELD
u8 hw_path:1;
u8 cpu0:1;
u8 cpu1:1;
@@ -866,8 +879,19 @@ struct MR_LD_RAID {
__le16 seqNum;
struct {
+#ifndef __BIG_ENDIAN_BITFIELD
u32 ldSyncRequired:1;
- u32 reserved:31;
+ u32 regTypeReqOnReadIsValid:1; // Qualifier bit for regTypeOnRead
+ u32 isEPD:1; // Set if LD is an "Enhanced Physical Drive"
+ u32 enableSLDOnAllRWIOs:1; // If set, driver should unconditionally set SLD bit for all Read Write IOs
+ u32 reserved:28;
+#else
+ u32 reserved:28;
+ u32 enableSLDOnAllRWIOs:1; // If set, driver should unconditionally set SLD bit for all Read Write IOs
+ u32 isEPD:1; // Set if LD is an "Enhanced Physical Drive"
+ u32 regTypeReqOnReadIsValid:1; // Qualifier bit for regTypeOnRead
+ u32 ldSyncRequired:1;
+#endif
} flags;
u8 LUN[8]; /* 0x24 8 byte LUN field used for SCSI IO's */
@@ -878,7 +902,7 @@ struct MR_LD_RAID {
/* 0x30 - 0x33, Logical block size for the LD */
u32 logical_block_length;
struct {
-#ifndef MFI_BIG_ENDIAN
+#ifndef __BIG_ENDIAN_BITFIELD
/* 0x34, P_I_EXPONENT from READ CAPACITY 16 */
u32 ld_pi_exp:4;
/* 0x34, LOGICAL BLOCKS PER PHYSICAL
@@ -1063,6 +1087,7 @@ struct MR_FW_RAID_MAP_DYNAMIC {
#define MPI26_IEEE_SGE_FLAGS_NSF_NVME_PRP (0x08)
#define MPI26_IEEE_SGE_FLAGS_NSF_NVME_SGL (0x10)
+
#define MEGASAS_DEFAULT_SNAP_DUMP_WAIT_TIME 15
#define MEGASAS_MAX_SNAP_DUMP_WAIT_TIME 60
@@ -1292,6 +1317,7 @@ struct fusion_context {
u8 *sense;
dma_addr_t sense_phys_addr;
+ atomic_t busy_mq_poll[MAX_MSIX_QUEUES_FUSION];
dma_addr_t reply_frames_desc_phys[MAX_MSIX_QUEUES_FUSION];
union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc[MAX_MSIX_QUEUES_FUSION];
struct rdpq_alloc_detail rdpq_tracker[RDPQ_MAX_CHUNK_COUNT];
@@ -1355,13 +1381,14 @@ enum CMD_RET_VALUES {
};
struct MR_SNAPDUMP_PROPERTIES {
- u8 offload_num;
- u8 max_num_supported;
- u8 cur_num_supported;
- u8 trigger_min_num_sec_before_ocr;
- u8 reserved[12];
+ u8 offload_num;
+ u8 max_num_supported;
+ u8 cur_num_supported;
+ u8 trigger_min_num_sec_before_ocr;
+ u8 reserved[12];
};
+
struct megasas_debugfs_buffer {
void *buf;
u32 len;