aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/megaraid/megaraid_sas_base.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/megaraid/megaraid_sas_base.c')
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c775
1 files changed, 465 insertions, 310 deletions
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index fd4b5ac6ac5b..d265a2d9d082 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -37,6 +37,7 @@
#include <linux/poll.h>
#include <linux/vmalloc.h>
#include <linux/irq_poll.h>
+#include <linux/blk-mq-pci.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -77,11 +78,11 @@ unsigned int resetwaittime = MEGASAS_RESET_WAIT_TIME;
module_param(resetwaittime, int, 0444);
MODULE_PARM_DESC(resetwaittime, "Wait time in (1-180s) after I/O timeout before resetting adapter. Default: 180s");
-int smp_affinity_enable = 1;
+static int smp_affinity_enable = 1;
module_param(smp_affinity_enable, int, 0444);
MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disable Default: enable(1)");
-int rdpq_enable = 1;
+static int rdpq_enable = 1;
module_param(rdpq_enable, int, 0444);
MODULE_PARM_DESC(rdpq_enable, "Allocate reply queue in chunks for large queue depth enable/disable Default: enable(1)");
@@ -89,7 +90,7 @@ unsigned int dual_qdepth_disable;
module_param(dual_qdepth_disable, int, 0444);
MODULE_PARM_DESC(dual_qdepth_disable, "Disable dual queue depth feature. Default: 0");
-unsigned int scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT;
+static 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.");
@@ -113,6 +114,19 @@ 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);
+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"
+ );
+
+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)");
+
MODULE_LICENSE("GPL");
MODULE_VERSION(MEGASAS_VERSION);
MODULE_AUTHOR("megaraidlinux.pdl@broadcom.com");
@@ -127,6 +141,8 @@ static int megasas_register_aen(struct megasas_instance *instance,
u32 seq_num, u32 class_locale_word);
static void megasas_get_pd_info(struct megasas_instance *instance,
struct scsi_device *sdev);
+static void
+megasas_set_ld_removed_by_fw(struct megasas_instance *instance);
/*
* PCI ID table for all supported controllers
@@ -199,13 +215,10 @@ static bool support_nvme_encapsulation;
static bool support_pci_lane_margining;
/* define lock for aen poll */
-static spinlock_t poll_aen_lock;
+static DEFINE_SPINLOCK(poll_aen_lock);
extern struct dentry *megasas_debugfs_root;
-extern void megasas_init_debugfs(void);
-extern void megasas_exit_debugfs(void);
-extern void megasas_setup_debugfs(struct megasas_instance *instance);
-extern void megasas_destroy_debugfs(struct megasas_instance *instance);
+extern int megasas_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num);
void
megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
@@ -425,16 +438,22 @@ 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);
+
}
-/**
-* The following functions are defined for xscale
-* (deviceid : 1064R, PERC5) controllers
-*/
+/*
+ * The following functions are defined for xscale
+ * (deviceid : 1064R, PERC5) controllers
+ */
/**
* megasas_enable_intr_xscale - Enables interrupts
- * @regs: MFI register set
+ * @instance: Adapter soft state
*/
static inline void
megasas_enable_intr_xscale(struct megasas_instance *instance)
@@ -450,7 +469,7 @@ megasas_enable_intr_xscale(struct megasas_instance *instance)
/**
* megasas_disable_intr_xscale -Disables interrupt
- * @regs: MFI register set
+ * @instance: Adapter soft state
*/
static inline void
megasas_disable_intr_xscale(struct megasas_instance *instance)
@@ -466,7 +485,7 @@ megasas_disable_intr_xscale(struct megasas_instance *instance)
/**
* megasas_read_fw_status_reg_xscale - returns the current FW status value
- * @regs: MFI register set
+ * @instance: Adapter soft state
*/
static u32
megasas_read_fw_status_reg_xscale(struct megasas_instance *instance)
@@ -474,8 +493,8 @@ megasas_read_fw_status_reg_xscale(struct megasas_instance *instance)
return readl(&instance->reg_set->outbound_msg_0);
}
/**
- * megasas_clear_interrupt_xscale - Check & clear interrupt
- * @regs: MFI register set
+ * megasas_clear_intr_xscale - Check & clear interrupt
+ * @instance: Adapter soft state
*/
static int
megasas_clear_intr_xscale(struct megasas_instance *instance)
@@ -509,9 +528,10 @@ megasas_clear_intr_xscale(struct megasas_instance *instance)
/**
* megasas_fire_cmd_xscale - Sends command to the FW
- * @frame_phys_addr : Physical address of cmd
- * @frame_count : Number of frames for the command
- * @regs : MFI register set
+ * @instance: Adapter soft state
+ * @frame_phys_addr : Physical address of cmd
+ * @frame_count : Number of frames for the command
+ * @regs : MFI register set
*/
static inline void
megasas_fire_cmd_xscale(struct megasas_instance *instance,
@@ -529,7 +549,8 @@ megasas_fire_cmd_xscale(struct megasas_instance *instance,
/**
* megasas_adp_reset_xscale - For controller reset
- * @regs: MFI register set
+ * @instance: Adapter soft state
+ * @regs: MFI register set
*/
static int
megasas_adp_reset_xscale(struct megasas_instance *instance,
@@ -570,7 +591,8 @@ megasas_adp_reset_xscale(struct megasas_instance *instance,
/**
* megasas_check_reset_xscale - For controller reset check
- * @regs: MFI register set
+ * @instance: Adapter soft state
+ * @regs: MFI register set
*/
static int
megasas_check_reset_xscale(struct megasas_instance *instance,
@@ -599,19 +621,19 @@ static struct megasas_instance_template megasas_instance_template_xscale = {
.issue_dcmd = megasas_issue_dcmd,
};
-/**
-* This is the end of set of functions & definitions specific
-* to xscale (deviceid : 1064R, PERC5) controllers
-*/
+/*
+ * This is the end of set of functions & definitions specific
+ * to xscale (deviceid : 1064R, PERC5) controllers
+ */
-/**
-* The following functions are defined for ppc (deviceid : 0x60)
-* controllers
-*/
+/*
+ * The following functions are defined for ppc (deviceid : 0x60)
+ * controllers
+ */
/**
* megasas_enable_intr_ppc - Enables interrupts
- * @regs: MFI register set
+ * @instance: Adapter soft state
*/
static inline void
megasas_enable_intr_ppc(struct megasas_instance *instance)
@@ -629,7 +651,7 @@ megasas_enable_intr_ppc(struct megasas_instance *instance)
/**
* megasas_disable_intr_ppc - Disable interrupt
- * @regs: MFI register set
+ * @instance: Adapter soft state
*/
static inline void
megasas_disable_intr_ppc(struct megasas_instance *instance)
@@ -645,7 +667,7 @@ megasas_disable_intr_ppc(struct megasas_instance *instance)
/**
* megasas_read_fw_status_reg_ppc - returns the current FW status value
- * @regs: MFI register set
+ * @instance: Adapter soft state
*/
static u32
megasas_read_fw_status_reg_ppc(struct megasas_instance *instance)
@@ -654,8 +676,8 @@ megasas_read_fw_status_reg_ppc(struct megasas_instance *instance)
}
/**
- * megasas_clear_interrupt_ppc - Check & clear interrupt
- * @regs: MFI register set
+ * megasas_clear_intr_ppc - Check & clear interrupt
+ * @instance: Adapter soft state
*/
static int
megasas_clear_intr_ppc(struct megasas_instance *instance)
@@ -688,9 +710,10 @@ megasas_clear_intr_ppc(struct megasas_instance *instance)
/**
* megasas_fire_cmd_ppc - Sends command to the FW
- * @frame_phys_addr : Physical address of cmd
- * @frame_count : Number of frames for the command
- * @regs : MFI register set
+ * @instance: Adapter soft state
+ * @frame_phys_addr: Physical address of cmd
+ * @frame_count: Number of frames for the command
+ * @regs: MFI register set
*/
static inline void
megasas_fire_cmd_ppc(struct megasas_instance *instance,
@@ -708,7 +731,8 @@ megasas_fire_cmd_ppc(struct megasas_instance *instance,
/**
* megasas_check_reset_ppc - For controller reset check
- * @regs: MFI register set
+ * @instance: Adapter soft state
+ * @regs: MFI register set
*/
static int
megasas_check_reset_ppc(struct megasas_instance *instance,
@@ -738,7 +762,7 @@ static struct megasas_instance_template megasas_instance_template_ppc = {
/**
* megasas_enable_intr_skinny - Enables interrupts
- * @regs: MFI register set
+ * @instance: Adapter soft state
*/
static inline void
megasas_enable_intr_skinny(struct megasas_instance *instance)
@@ -756,7 +780,7 @@ megasas_enable_intr_skinny(struct megasas_instance *instance)
/**
* megasas_disable_intr_skinny - Disables interrupt
- * @regs: MFI register set
+ * @instance: Adapter soft state
*/
static inline void
megasas_disable_intr_skinny(struct megasas_instance *instance)
@@ -772,7 +796,7 @@ megasas_disable_intr_skinny(struct megasas_instance *instance)
/**
* megasas_read_fw_status_reg_skinny - returns the current FW status value
- * @regs: MFI register set
+ * @instance: Adapter soft state
*/
static u32
megasas_read_fw_status_reg_skinny(struct megasas_instance *instance)
@@ -781,8 +805,8 @@ megasas_read_fw_status_reg_skinny(struct megasas_instance *instance)
}
/**
- * megasas_clear_interrupt_skinny - Check & clear interrupt
- * @regs: MFI register set
+ * megasas_clear_intr_skinny - Check & clear interrupt
+ * @instance: Adapter soft state
*/
static int
megasas_clear_intr_skinny(struct megasas_instance *instance)
@@ -825,9 +849,10 @@ megasas_clear_intr_skinny(struct megasas_instance *instance)
/**
* megasas_fire_cmd_skinny - Sends command to the FW
- * @frame_phys_addr : Physical address of cmd
- * @frame_count : Number of frames for the command
- * @regs : MFI register set
+ * @instance: Adapter soft state
+ * @frame_phys_addr: Physical address of cmd
+ * @frame_count: Number of frames for the command
+ * @regs: MFI register set
*/
static inline void
megasas_fire_cmd_skinny(struct megasas_instance *instance,
@@ -847,7 +872,8 @@ megasas_fire_cmd_skinny(struct megasas_instance *instance,
/**
* megasas_check_reset_skinny - For controller reset check
- * @regs: MFI register set
+ * @instance: Adapter soft state
+ * @regs: MFI register set
*/
static int
megasas_check_reset_skinny(struct megasas_instance *instance,
@@ -876,14 +902,14 @@ static struct megasas_instance_template megasas_instance_template_skinny = {
};
-/**
-* The following functions are defined for gen2 (deviceid : 0x78 0x79)
-* controllers
-*/
+/*
+ * The following functions are defined for gen2 (deviceid : 0x78 0x79)
+ * controllers
+ */
/**
* megasas_enable_intr_gen2 - Enables interrupts
- * @regs: MFI register set
+ * @instance: Adapter soft state
*/
static inline void
megasas_enable_intr_gen2(struct megasas_instance *instance)
@@ -902,7 +928,7 @@ megasas_enable_intr_gen2(struct megasas_instance *instance)
/**
* megasas_disable_intr_gen2 - Disables interrupt
- * @regs: MFI register set
+ * @instance: Adapter soft state
*/
static inline void
megasas_disable_intr_gen2(struct megasas_instance *instance)
@@ -918,7 +944,7 @@ megasas_disable_intr_gen2(struct megasas_instance *instance)
/**
* megasas_read_fw_status_reg_gen2 - returns the current FW status value
- * @regs: MFI register set
+ * @instance: Adapter soft state
*/
static u32
megasas_read_fw_status_reg_gen2(struct megasas_instance *instance)
@@ -927,8 +953,8 @@ megasas_read_fw_status_reg_gen2(struct megasas_instance *instance)
}
/**
- * megasas_clear_interrupt_gen2 - Check & clear interrupt
- * @regs: MFI register set
+ * megasas_clear_intr_gen2 - Check & clear interrupt
+ * @instance: Adapter soft state
*/
static int
megasas_clear_intr_gen2(struct megasas_instance *instance)
@@ -961,11 +987,13 @@ megasas_clear_intr_gen2(struct megasas_instance *instance)
return mfiStatus;
}
+
/**
* megasas_fire_cmd_gen2 - Sends command to the FW
- * @frame_phys_addr : Physical address of cmd
- * @frame_count : Number of frames for the command
- * @regs : MFI register set
+ * @instance: Adapter soft state
+ * @frame_phys_addr: Physical address of cmd
+ * @frame_count: Number of frames for the command
+ * @regs: MFI register set
*/
static inline void
megasas_fire_cmd_gen2(struct megasas_instance *instance,
@@ -983,7 +1011,8 @@ megasas_fire_cmd_gen2(struct megasas_instance *instance,
/**
* megasas_adp_reset_gen2 - For controller reset
- * @regs: MFI register set
+ * @instance: Adapter soft state
+ * @reg_set: MFI register set
*/
static int
megasas_adp_reset_gen2(struct megasas_instance *instance,
@@ -1043,7 +1072,8 @@ megasas_adp_reset_gen2(struct megasas_instance *instance,
/**
* megasas_check_reset_gen2 - For controller reset check
- * @regs: MFI register set
+ * @instance: Adapter soft state
+ * @regs: MFI register set
*/
static int
megasas_check_reset_gen2(struct megasas_instance *instance,
@@ -1071,10 +1101,10 @@ static struct megasas_instance_template megasas_instance_template_gen2 = {
.issue_dcmd = megasas_issue_dcmd,
};
-/**
-* This is the end of set of functions & definitions
-* specific to gen2 (deviceid : 0x78, 0x79) controllers
-*/
+/*
+ * This is the end of set of functions & definitions
+ * specific to gen2 (deviceid : 0x78, 0x79) controllers
+ */
/*
* Template added for TB (Fusion)
@@ -1421,10 +1451,10 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
* pthru timeout to the os layer timeout value.
*/
if (scp->device->type == TYPE_TAPE) {
- if ((scp->request->timeout / HZ) > 0xFFFF)
+ if (scsi_cmd_to_rq(scp)->timeout / HZ > 0xFFFF)
pthru->timeout = cpu_to_le16(0xFFFF);
else
- pthru->timeout = cpu_to_le16(scp->request->timeout / HZ);
+ pthru->timeout = cpu_to_le16(scsi_cmd_to_rq(scp)->timeout / HZ);
}
/*
@@ -1609,7 +1639,7 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
/**
* megasas_cmd_type - Checks if the cmd is for logical drive/sysPD
* and whether it's RW or non RW
- * @scmd: SCSI command
+ * @cmd: SCSI command
*
*/
inline int megasas_cmd_type(struct scsi_cmnd *cmd)
@@ -1730,7 +1760,7 @@ megasas_build_and_issue_cmd(struct megasas_instance *instance,
goto out_return_cmd;
cmd->scmd = scmd;
- scmd->SCp.ptr = (char *)cmd;
+ megasas_priv(scmd)->cmd_priv = cmd;
/*
* Issue the command to the FW
@@ -1749,21 +1779,22 @@ out_return_cmd:
/**
* megasas_queue_command - Queue entry point
+ * @shost: adapter SCSI host
* @scmd: SCSI command to be queued
- * @done: Callback entry point
*/
static int
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;
if (instance->unload == 1) {
scmd->result = DID_NO_CONNECT << 16;
- scmd->scsi_done(scmd);
+ scsi_done(scmd);
return 0;
}
@@ -1778,22 +1809,26 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
return SCSI_MLQUEUE_HOST_BUSY;
} else {
scmd->result = DID_NO_CONNECT << 16;
- scmd->scsi_done(scmd);
+ scsi_done(scmd);
return 0;
}
}
- 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);
+ 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;
+ scsi_done(scmd);
+ return 0;
+ }
}
if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
@@ -1822,7 +1857,7 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
return instance->instancet->build_and_issue_cmd(instance, scmd);
out_done:
- scmd->scsi_done(scmd);
+ scsi_done(scmd);
return 0;
}
@@ -1881,7 +1916,7 @@ void megasas_set_dynamic_target_properties(struct scsi_device *sdev,
raid = MR_LdRaidGet(ld, local_map_ptr);
if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER)
- blk_queue_update_dma_alignment(sdev->request_queue, 0x7);
+ blk_queue_update_dma_alignment(sdev->request_queue, 0x7);
mr_device_priv_data->is_tm_capable =
raid->capability.tmCapable;
@@ -1982,9 +2017,9 @@ 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)
@@ -2073,7 +2108,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;
@@ -2091,6 +2126,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:
@@ -2098,6 +2136,14 @@ scan_target:
GFP_KERNEL);
if (!mr_device_priv_data)
return -ENOMEM;
+
+ 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,
@@ -2107,6 +2153,23 @@ scan_target:
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;
}
@@ -2727,7 +2790,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
reset_index, reset_cmd,
reset_cmd->scmd->cmnd[0]);
- reset_cmd->scmd->scsi_done(reset_cmd->scmd);
+ scsi_done(reset_cmd->scmd);
megasas_return_cmd(instance, reset_cmd);
} else if (reset_cmd->sync_cmd) {
dev_notice(&instance->pdev->dev, "%p synch cmds"
@@ -2916,11 +2979,7 @@ megasas_dump(void *buf, int sz, int format)
/**
* 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.
+ * @reg_set: Register set to be dumped
*/
inline void
megasas_dump_reg_set(void __iomem *reg_set)
@@ -2940,11 +2999,10 @@ megasas_dump_reg_set(void __iomem *reg_set)
void
megasas_dump_fusion_io(struct scsi_cmnd *scmd)
{
- struct megasas_cmd_fusion *cmd;
+ struct megasas_cmd_fusion *cmd = megasas_priv(scmd)->cmd_priv;
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,
@@ -2987,15 +3045,17 @@ megasas_dump_sys_regs(void __iomem *reg_set, char *buf)
u32 __iomem *reg = (u32 __iomem *)reg_set;
for (i = 0; i < sz / sizeof(u32); i++) {
- bytes_wrote += snprintf(loc + bytes_wrote, PAGE_SIZE,
- "%08x: %08x\n", (i * 4),
- readl(&reg[i]));
+ bytes_wrote += scnprintf(loc + bytes_wrote,
+ PAGE_SIZE - bytes_wrote,
+ "%08x: %08x\n", (i * 4),
+ readl(&reg[i]));
}
return bytes_wrote;
}
/**
* megasas_reset_bus_host - Bus & host reset handler entry point
+ * @scmd: Mid-layer SCSI command
*/
static int megasas_reset_bus_host(struct scsi_cmnd *scmd)
{
@@ -3114,6 +3174,43 @@ megasas_bios_param(struct scsi_device *sdev, struct block_device *bdev,
return 0;
}
+static void megasas_map_queues(struct Scsi_Host *shost)
+{
+ struct megasas_instance *instance;
+ int qoff = 0, offset;
+ struct blk_mq_queue_map *map;
+
+ instance = (struct megasas_instance *)shost->hostdata;
+
+ if (shost->nr_hw_queues == 1)
+ return;
+
+ offset = instance->low_latency_index_start;
+
+ /* Setup Default hctx */
+ map = &shost->tag_set.map[HCTX_TYPE_DEFAULT];
+ map->nr_queues = instance->msix_vectors - offset;
+ map->queue_offset = 0;
+ blk_mq_pci_map_queues(map, instance->pdev, offset);
+ qoff += map->nr_queues;
+ offset += map->nr_queues;
+
+ /* we never use READ queue, so can't cheat blk-mq */
+ shost->tag_set.map[HCTX_TYPE_READ].nr_queues = 0;
+
+ /* 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);
+ }
+}
+
static void megasas_aen_polling(struct work_struct *work);
/**
@@ -3391,19 +3488,21 @@ static DEVICE_ATTR_RW(enable_sdev_max_qd);
static DEVICE_ATTR_RO(dump_system_regs);
static DEVICE_ATTR_RO(raid_map_id);
-static struct device_attribute *megaraid_host_attrs[] = {
- &dev_attr_fw_crash_buffer_size,
- &dev_attr_fw_crash_buffer,
- &dev_attr_fw_crash_state,
- &dev_attr_page_size,
- &dev_attr_ldio_outstanding,
- &dev_attr_fw_cmds_outstanding,
- &dev_attr_enable_sdev_max_qd,
- &dev_attr_dump_system_regs,
- &dev_attr_raid_map_id,
+static struct attribute *megaraid_host_attrs[] = {
+ &dev_attr_fw_crash_buffer_size.attr,
+ &dev_attr_fw_crash_buffer.attr,
+ &dev_attr_fw_crash_state.attr,
+ &dev_attr_page_size.attr,
+ &dev_attr_ldio_outstanding.attr,
+ &dev_attr_fw_cmds_outstanding.attr,
+ &dev_attr_enable_sdev_max_qd.attr,
+ &dev_attr_dump_system_regs.attr,
+ &dev_attr_raid_map_id.attr,
NULL,
};
+ATTRIBUTE_GROUPS(megaraid_host);
+
/*
* Scsi host template for megaraid_sas driver
*/
@@ -3420,10 +3519,13 @@ static struct scsi_host_template megasas_template = {
.eh_abort_handler = megasas_task_abort,
.eh_host_reset_handler = megasas_reset_bus_host,
.eh_timed_out = megasas_reset_timer,
- .shost_attrs = megaraid_host_attrs,
+ .shost_groups = megaraid_host_groups,
.bios_param = megasas_bios_param,
+ .map_queues = megasas_map_queues,
+ .mq_poll = megasas_blk_mq_poll,
.change_queue_depth = scsi_change_queue_depth,
.max_segment_size = 0xffffffff,
+ .cmd_size = sizeof(struct megasas_cmd_priv),
};
/**
@@ -3467,6 +3569,22 @@ megasas_complete_abort(struct megasas_instance *instance,
}
}
+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
@@ -3491,7 +3609,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
cmd->retry_for_fw_reset = 0;
if (cmd->scmd)
- cmd->scmd->SCp.ptr = NULL;
+ megasas_priv(cmd->scmd)->cmd_priv = NULL;
switch (hdr->cmd) {
case MFI_CMD_INVALID:
@@ -3517,7 +3635,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
megasas_complete_int_cmd(instance, cmd);
break;
}
- /* fall through */
+ fallthrough;
case MFI_CMD_LD_READ:
case MFI_CMD_LD_WRITE:
@@ -3532,7 +3650,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
atomic_dec(&instance->fw_outstanding);
scsi_dma_unmap(cmd->scmd);
- cmd->scmd->scsi_done(cmd->scmd);
+ scsi_done(cmd->scmd);
megasas_return_cmd(instance, cmd);
break;
@@ -3559,8 +3677,6 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
SCSI_SENSE_BUFFERSIZE);
memcpy(cmd->scmd->sense_buffer, cmd->sense,
hdr->sense_len);
-
- cmd->scmd->result |= DRIVER_SENSE << 24;
}
break;
@@ -3580,7 +3696,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
atomic_dec(&instance->fw_outstanding);
scsi_dma_unmap(cmd->scmd);
- cmd->scmd->scsi_done(cmd->scmd);
+ scsi_done(cmd->scmd);
megasas_return_cmd(instance, cmd);
break;
@@ -3629,9 +3745,13 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
fusion->fast_path_io = 0;
}
+ 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 ||
@@ -3776,7 +3896,7 @@ megasas_issue_pending_cmds_again(struct megasas_instance *instance)
megasas_register_aen(instance, seq_num, class_locale.word);
}
-/**
+/*
* Move the internal reset pending commands to a deferred queue.
*
* We move the commands pending at internal reset time to a
@@ -3784,7 +3904,7 @@ megasas_issue_pending_cmds_again(struct megasas_instance *instance)
* completion of the internal reset sequence. if the internal reset
* did not complete in time, the kernel reset handler would flush
* these commands.
- **/
+ */
static void
megasas_internal_reset_defer_cmds(struct megasas_instance *instance)
{
@@ -3828,9 +3948,9 @@ process_fw_state_change_wq(struct work_struct *work)
u32 wait;
unsigned long flags;
- if (atomic_read(&instance->adprecovery) != MEGASAS_ADPRESET_SM_INFAULT) {
+ if (atomic_read(&instance->adprecovery) != MEGASAS_ADPRESET_SM_INFAULT) {
dev_notice(&instance->pdev->dev, "error, recovery st %x\n",
- atomic_read(&instance->adprecovery));
+ atomic_read(&instance->adprecovery));
return ;
}
@@ -3901,10 +4021,8 @@ megasas_deplete_reply_queue(struct megasas_instance *instance,
u32 mfiStatus;
u32 fw_state;
- if ((mfiStatus = instance->instancet->check_reset(instance,
- instance->reg_set)) == 1) {
+ if (instance->instancet->check_reset(instance, instance->reg_set) == 1)
return IRQ_HANDLED;
- }
mfiStatus = instance->instancet->clear_intr(instance);
if (mfiStatus == 0) {
@@ -3962,8 +4080,11 @@ megasas_deplete_reply_queue(struct megasas_instance *instance,
tasklet_schedule(&instance->isr_tasklet);
return IRQ_HANDLED;
}
+
/**
* megasas_isr - isr entry point
+ * @irq: IRQ number
+ * @devp: IRQ context address
*/
static irqreturn_t megasas_isr(int irq, void *devp)
{
@@ -3985,6 +4106,7 @@ static irqreturn_t megasas_isr(int irq, void *devp)
/**
* megasas_transition_to_ready - Move the FW to READY state
* @instance: Adapter soft state
+ * @ocr: Adapter reset state
*
* During the initialization, FW passes can potentially be in any one of
* several possible states. If the FW in operational, waiting-for-handshake
@@ -4350,8 +4472,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),
GFP_KERNEL);
@@ -4742,7 +4862,7 @@ megasas_get_ld_list(struct megasas_instance *instance)
/**
* megasas_ld_list_query - Returns FW's ld_list structure
* @instance: Adapter soft state
- * @ld_list: ld_list structure
+ * @query_type: ld_list structure type
*
* Issues an internal command (DCMD) to get the FW's controller PD
* list structure. This information is mainly used to find out SYSTEM
@@ -4856,6 +4976,7 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type)
}
/**
+ * megasas_host_device_list_query
* dcmd.opcode - MR_DCMD_CTRL_DEVICE_LIST_GET
* dcmd.mbox - reserved
* dcmd.sge IN - ptr to return MR_HOST_DEVICE_LIST structure
@@ -5032,9 +5153,9 @@ static void megasas_update_ext_vd_details(struct megasas_instance *instance)
fusion->current_map_sz = ventura_map_sz;
fusion->max_map_sz = ventura_map_sz;
} else {
- fusion->old_map_sz = sizeof(struct MR_FW_RAID_MAP) +
- (sizeof(struct MR_LD_SPAN_MAP) *
- (instance->fw_supported_vd_count - 1));
+ fusion->old_map_sz =
+ struct_size((struct MR_FW_RAID_MAP *)0, ldSpanMap,
+ instance->fw_supported_vd_count);
fusion->new_map_sz = sizeof(struct MR_FW_RAID_MAP_EXT);
fusion->max_map_sz =
@@ -5133,7 +5254,7 @@ void megasas_get_snapdump_properties(struct megasas_instance *instance)
}
/**
- * megasas_get_controller_info - Returns FW's controller structure
+ * megasas_get_ctrl_info - Returns FW's controller structure
* @instance: Adapter soft state
*
* Issues an internal command (DCMD) to get the FW's controller structure.
@@ -5601,9 +5722,13 @@ megasas_setup_irqs_msix(struct megasas_instance *instance, u8 is_probe)
&instance->irq_context[i])) {
dev_err(&instance->pdev->dev,
"Failed to register IRQ for vector %d.\n", i);
- for (j = 0; j < i; j++)
+ for (j = 0; j < i; j++) {
+ if (j < instance->low_latency_index_start)
+ irq_update_affinity_hint(
+ pci_irq_vector(pdev, j), NULL);
free_irq(pci_irq_vector(pdev, j),
&instance->irq_context[j]);
+ }
/* Retry irq register for IO_APIC*/
instance->msix_vectors = 0;
instance->msix_load_balance = false;
@@ -5641,6 +5766,9 @@ megasas_destroy_irqs(struct megasas_instance *instance) {
if (instance->msix_vectors)
for (i = 0; i < instance->msix_vectors; i++) {
+ if (i < instance->low_latency_index_start)
+ irq_update_affinity_hint(
+ pci_irq_vector(instance->pdev, i), NULL);
free_irq(pci_irq_vector(instance->pdev, i),
&instance->irq_context[i]);
}
@@ -5652,7 +5780,6 @@ megasas_destroy_irqs(struct megasas_instance *instance) {
/**
* megasas_setup_jbod_map - setup jbod map for FP seq_number.
* @instance: Adapter soft state
- * @is_probe: Driver probe check
*
* Return 0 on success.
*/
@@ -5661,10 +5788,10 @@ megasas_setup_jbod_map(struct megasas_instance *instance)
{
int i;
struct fusion_context *fusion = instance->ctrl_context;
- u32 pd_seq_map_sz;
+ size_t pd_seq_map_sz;
- pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) +
- (sizeof(struct MR_PD_CFG_SEQ) * (MAX_PHYSICAL_DEVICES - 1));
+ pd_seq_map_sz = struct_size((struct MR_PD_CFG_SEQ_NUM_SYNC *)0, seq,
+ MAX_PHYSICAL_DEVICES);
instance->use_seqnum_jbod_fp =
instance->support_seqnum_jbod_fp;
@@ -5747,10 +5874,6 @@ fallback:
static
int megasas_get_device_list(struct megasas_instance *instance)
{
- memset(instance->pd_list, 0,
- (MEGASAS_MAX_PD * sizeof(struct megasas_pd_list)));
- memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
-
if (instance->enable_fw_dev_list) {
if (megasas_host_device_list_query(instance, true))
return FAILED;
@@ -5771,22 +5894,25 @@ int megasas_get_device_list(struct megasas_instance *instance)
}
/**
- * megasas_set_high_iops_queue_affinity_hint - Set affinity hint for high IOPS queues
- * @instance: Adapter soft state
- * return: void
+ * megasas_set_high_iops_queue_affinity_and_hint - Set affinity and 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)
+megasas_set_high_iops_queue_affinity_and_hint(struct megasas_instance *instance)
{
int i;
- int local_numa_node;
+ unsigned int irq;
+ const struct cpumask *mask;
if (instance->perf_mode == MR_BALANCED_PERF_MODE) {
- local_numa_node = dev_to_node(&instance->pdev->dev);
+ mask = cpumask_of_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));
+ for (i = 0; i < instance->low_latency_index_start; i++) {
+ irq = pci_irq_vector(instance->pdev, i);
+ irq_set_affinity_and_hint(irq, mask);
+ }
}
}
@@ -5800,13 +5926,16 @@ __megasas_alloc_irq_vectors(struct megasas_instance *instance)
irq_flags = PCI_IRQ_MSIX;
if (instance->smp_affinity_enable)
- irq_flags |= PCI_IRQ_AFFINITY;
+ 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, irq_flags, descp);
+ instance->msix_vectors - instance->iopoll_q_count, irq_flags, descp);
return i;
}
@@ -5822,10 +5951,30 @@ megasas_alloc_irq_vectors(struct megasas_instance *instance)
int i;
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) &&
- (i != instance->msix_vectors)) {
+ 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 */
@@ -5836,12 +5985,15 @@ megasas_alloc_irq_vectors(struct megasas_instance *instance)
instance->msix_vectors = min(num_msix_req,
instance->msix_vectors);
+ instance->iopoll_q_count = 0;
i = __megasas_alloc_irq_vectors(instance);
}
dev_info(&instance->pdev->dev,
- "requested/available msix %d/%d\n", instance->msix_vectors, i);
+ "requested/available msix %d/%d poll_queue %d\n",
+ instance->msix_vectors - instance->iopoll_q_count,
+ i, instance->iopoll_q_count);
if (i > 0)
instance->msix_vectors = i;
@@ -5849,7 +6001,7 @@ megasas_alloc_irq_vectors(struct megasas_instance *instance)
instance->msix_vectors = 0;
if (instance->smp_affinity_enable)
- megasas_set_high_iops_queue_affinity_hint(instance);
+ megasas_set_high_iops_queue_affinity_and_hint(instance);
}
/**
@@ -6493,7 +6645,7 @@ dcmd_failed:
* megasas_register_aen - Registers for asynchronous event notification
* @instance: Adapter soft state
* @seq_num: The starting sequence number
- * @class_locale: Class of the event
+ * @class_locale_word: Class of the event
*
* This function subscribes for AEN for events beyond the @seq_num. It requests
* to be notified if and only if the event is of type @class_locale
@@ -6793,6 +6945,32 @@ static int megasas_io_attach(struct megasas_instance *instance)
host->max_lun = MEGASAS_MAX_LUN;
host->max_cmd_len = 16;
+ /* 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 (instance->iopoll_q_count)
+ host->nr_maps = 3;
+ } 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);
/*
* Notify the mid-layer about the new controller
*/
@@ -6967,22 +7145,18 @@ static int megasas_alloc_ctrl_mem(struct megasas_instance *instance)
switch (instance->adapter_type) {
case MFI_SERIES:
if (megasas_alloc_mfi_ctrl_mem(instance))
- goto fail;
+ return -ENOMEM;
break;
case AERO_SERIES:
case VENTURA_SERIES:
case THUNDERBOLT_SERIES:
case INVADER_SERIES:
if (megasas_alloc_fusion_context(instance))
- goto fail;
+ return -ENOMEM;
break;
}
return 0;
- fail:
- kfree(instance->reply_map);
- instance->reply_map = NULL;
- return -ENOMEM;
}
/*
@@ -7013,8 +7187,9 @@ static inline void megasas_free_ctrl_mem(struct megasas_instance *instance)
* megasas_alloc_ctrl_dma_buffers - Allocate consistent DMA buffers during
* driver load time
*
- * @instance- Adapter soft instance
- * @return- O for SUCCESS
+ * @instance: Adapter soft instance
+ *
+ * @return: O for SUCCESS
*/
static inline
int megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance)
@@ -7041,7 +7216,7 @@ int megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance)
if (!fusion->ioc_init_request) {
dev_err(&pdev->dev,
- "Failed to allocate PD list buffer\n");
+ "Failed to allocate ioc init request\n");
return -ENOMEM;
}
@@ -7260,7 +7435,6 @@ static inline void megasas_init_ctrl_params(struct megasas_instance *instance)
(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY))
instance->flag_ieee = 1;
- megasas_dbg_lvl = 0;
instance->flag = 0;
instance->unload = 1;
instance->last_time = 0;
@@ -7423,11 +7597,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);
@@ -7435,8 +7614,16 @@ fail_io_attach:
megasas_release_fusion(instance);
else
megasas_release_mfi(instance);
+
if (instance->msix_vectors)
pci_free_irq_vectors(instance->pdev);
+ 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:
@@ -7538,25 +7725,23 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
megasas_return_cmd(instance, cmd);
}
-#ifdef CONFIG_PM
/**
* megasas_suspend - driver suspend entry point
- * @pdev: PCI device structure
- * @state: PCI power state to suspend routine
+ * @dev: Device structure
*/
-static int
-megasas_suspend(struct pci_dev *pdev, pm_message_t state)
+static int __maybe_unused
+megasas_suspend(struct device *dev)
{
struct megasas_instance *instance;
- instance = pci_get_drvdata(pdev);
+ instance = dev_get_drvdata(dev);
if (!instance)
return 0;
instance->unload = 1;
- dev_info(&pdev->dev, "%s is called\n", __func__);
+ dev_info(dev, "%s is called\n", __func__);
/* Shutdown SR-IOV heartbeat timer */
if (instance->requestorId && !instance->skip_heartbeat_timer_del)
@@ -7586,48 +7771,29 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
if (instance->msix_vectors)
pci_free_irq_vectors(instance->pdev);
- pci_save_state(pdev);
- pci_disable_device(pdev);
-
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
-
return 0;
}
/**
* megasas_resume- driver resume entry point
- * @pdev: PCI device structure
+ * @dev: Device structure
*/
-static int
-megasas_resume(struct pci_dev *pdev)
+static int __maybe_unused
+megasas_resume(struct device *dev)
{
int rval;
struct Scsi_Host *host;
struct megasas_instance *instance;
u32 status_reg;
- instance = pci_get_drvdata(pdev);
+ instance = dev_get_drvdata(dev);
if (!instance)
return 0;
host = instance->host;
- pci_set_power_state(pdev, PCI_D0);
- pci_enable_wake(pdev, PCI_D0, 0);
- pci_restore_state(pdev);
- dev_info(&pdev->dev, "%s is called\n", __func__);
- /*
- * PCI prepping: enable device set bus mastering and dma mask
- */
- rval = pci_enable_device_mem(pdev);
-
- if (rval) {
- dev_err(&pdev->dev, "Enable device failed\n");
- return rval;
- }
-
- pci_set_master(pdev);
+ dev_info(dev, "%s is called\n", __func__);
/*
* We expect the FW state to be READY
@@ -7753,14 +7919,8 @@ fail_reenable_msix:
fail_set_dma_mask:
fail_ready_state:
- pci_disable_device(pdev);
-
return -ENODEV;
}
-#else
-#define megasas_suspend NULL
-#define megasas_resume NULL
-#endif
static inline int
megasas_wait_for_adapter_operational(struct megasas_instance *instance)
@@ -7801,7 +7961,7 @@ static void megasas_detach_one(struct pci_dev *pdev)
struct Scsi_Host *host;
struct megasas_instance *instance;
struct fusion_context *fusion;
- u32 pd_seq_map_sz;
+ size_t pd_seq_map_sz;
instance = pci_get_drvdata(pdev);
@@ -7873,9 +8033,9 @@ skip_firing_dcmds:
if (instance->adapter_type != MFI_SERIES) {
megasas_release_fusion(instance);
- pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) +
- (sizeof(struct MR_PD_CFG_SEQ) *
- (MAX_PHYSICAL_DEVICES - 1));
+ pd_seq_map_sz =
+ struct_size((struct MR_PD_CFG_SEQ_NUM_SYNC *)0,
+ seq, MAX_PHYSICAL_DEVICES);
for (i = 0; i < 2 ; i++) {
if (fusion->ld_map[i])
dma_free_coherent(&instance->pdev->dev,
@@ -7930,7 +8090,7 @@ skip_firing_dcmds:
/**
* megasas_shutdown - Shutdown entry point
- * @device: Generic device structure
+ * @pdev: PCI device structure
*/
static void megasas_shutdown(struct pci_dev *pdev)
{
@@ -7955,8 +8115,10 @@ skip_firing_dcmds:
pci_free_irq_vectors(instance->pdev);
}
-/**
+/*
* megasas_mgmt_open - char node "open" entry point
+ * @inode: char node inode
+ * @filep: char node file
*/
static int megasas_mgmt_open(struct inode *inode, struct file *filep)
{
@@ -7969,8 +8131,11 @@ static int megasas_mgmt_open(struct inode *inode, struct file *filep)
return 0;
}
-/**
+/*
* megasas_mgmt_fasync - Async notifier registration from applications
+ * @fd: char node file descriptor number
+ * @filep: char node file
+ * @mode: notifier on/off
*
* This function adds the calling process to a driver global queue. When an
* event occurs, SIGIO will be sent to all processes in this queue.
@@ -7996,9 +8161,11 @@ static int megasas_mgmt_fasync(int fd, struct file *filep, int mode)
return rc;
}
-/**
+/*
* megasas_mgmt_poll - char node "poll" entry point
- * */
+ * @filep: char node file
+ * @wait: Events to poll for
+ */
static __poll_t megasas_mgmt_poll(struct file *file, poll_table *wait)
{
__poll_t mask;
@@ -8056,7 +8223,8 @@ static int megasas_set_crash_dump_params_ioctl(struct megasas_cmd *cmd)
/**
* megasas_mgmt_fw_ioctl - Issues management ioctls to FW
* @instance: Adapter soft state
- * @argp: User's ioctl packet
+ * @user_ioc: User's ioctl packet
+ * @ioc: ioctl packet
*/
static int
megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
@@ -8071,7 +8239,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
int error = 0, i;
void *sense = NULL;
dma_addr_t sense_handle;
- unsigned long *sense_ptr;
+ void *sense_ptr;
u32 opcode = 0;
int ret = DCMD_SUCCESS;
@@ -8194,6 +8362,13 @@ 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) {
@@ -8201,12 +8376,9 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
goto out;
}
- 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);
+ /* always store 64 bits regardless of addressing */
+ sense_ptr = (void *)cmd->frame + ioc->sense_off;
+ put_unaligned_le64(sense_handle, sense_ptr);
}
/*
@@ -8224,8 +8396,8 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
"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);
- error = -EBUSY;
- goto out;
+ error = -EBUSY;
+ goto out;
}
cmd->sync_cmd = 0;
@@ -8250,16 +8422,19 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
* copy out the sense
*/
if (ioc->sense_len) {
+ void __user *uptr;
/*
* sense_ptr points to the location that has the user
* sense buffer address
*/
- sense_ptr = (unsigned long *) ((unsigned long)ioc->frame.raw +
- ioc->sense_off);
+ sense_ptr = (void *)ioc->frame.raw + ioc->sense_off;
+ if (in_compat_syscall())
+ uptr = compat_ptr(get_unaligned((compat_uptr_t *)
+ sense_ptr));
+ else
+ uptr = get_unaligned((void __user **)sense_ptr);
- if (copy_to_user((void __user *)((unsigned long)
- get_unaligned((unsigned long *)sense_ptr)),
- sense, ioc->sense_len)) {
+ if (copy_to_user(uptr, sense, ioc->sense_len)) {
dev_err(&instance->pdev->dev, "Failed to copy out to user "
"sense data\n");
error = -EFAULT;
@@ -8302,6 +8477,38 @@ out:
return error;
}
+static struct megasas_iocpacket *
+megasas_compat_iocpacket_get_user(void __user *arg)
+{
+ struct megasas_iocpacket *ioc;
+ struct compat_megasas_iocpacket __user *cioc = arg;
+ size_t size;
+ int err = -EFAULT;
+ int i;
+
+ ioc = kzalloc(sizeof(*ioc), GFP_KERNEL);
+ if (!ioc)
+ return ERR_PTR(-ENOMEM);
+ size = offsetof(struct megasas_iocpacket, frame) + sizeof(ioc->frame);
+ if (copy_from_user(ioc, arg, size))
+ goto out;
+
+ for (i = 0; i < MAX_IOCTL_SGE; i++) {
+ compat_uptr_t iov_base;
+
+ if (get_user(iov_base, &cioc->sgl[i].iov_base) ||
+ get_user(ioc->sgl[i].iov_len, &cioc->sgl[i].iov_len))
+ goto out;
+
+ ioc->sgl[i].iov_base = compat_ptr(iov_base);
+ }
+
+ return ioc;
+out:
+ kfree(ioc);
+ return ERR_PTR(err);
+}
+
static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
{
struct megasas_iocpacket __user *user_ioc =
@@ -8310,7 +8517,11 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
struct megasas_instance *instance;
int error;
- ioc = memdup_user(user_ioc, sizeof(*ioc));
+ if (in_compat_syscall())
+ ioc = megasas_compat_iocpacket_get_user(user_ioc);
+ else
+ ioc = memdup_user(user_ioc, sizeof(struct megasas_iocpacket));
+
if (IS_ERR(ioc))
return PTR_ERR(ioc);
@@ -8396,6 +8607,9 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
/**
* megasas_mgmt_ioctl - char node ioctl entry point
+ * @file: char device file pointer
+ * @cmd: ioctl command
+ * @arg: ioctl command arguments address
*/
static long
megasas_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -8412,78 +8626,13 @@ megasas_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
#ifdef CONFIG_COMPAT
-static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
-{
- struct compat_megasas_iocpacket __user *cioc =
- (struct compat_megasas_iocpacket __user *)arg;
- struct megasas_iocpacket __user *ioc =
- compat_alloc_user_space(sizeof(struct megasas_iocpacket));
- int i;
- int error = 0;
- compat_uptr_t ptr;
- u32 local_sense_off;
- u32 local_sense_len;
- u32 user_sense_off;
-
- if (clear_user(ioc, sizeof(*ioc)))
- return -EFAULT;
-
- if (copy_in_user(&ioc->host_no, &cioc->host_no, sizeof(u16)) ||
- copy_in_user(&ioc->sgl_off, &cioc->sgl_off, sizeof(u32)) ||
- copy_in_user(&ioc->sense_off, &cioc->sense_off, sizeof(u32)) ||
- copy_in_user(&ioc->sense_len, &cioc->sense_len, sizeof(u32)) ||
- copy_in_user(ioc->frame.raw, cioc->frame.raw, 128) ||
- copy_in_user(&ioc->sge_count, &cioc->sge_count, sizeof(u32)))
- return -EFAULT;
-
- /*
- * The sense_ptr is used in megasas_mgmt_fw_ioctl only when
- * sense_len is not null, so prepare the 64bit value under
- * the same condition.
- */
- if (get_user(local_sense_off, &ioc->sense_off) ||
- get_user(local_sense_len, &ioc->sense_len) ||
- get_user(user_sense_off, &cioc->sense_off))
- return -EFAULT;
-
- if (local_sense_off != user_sense_off)
- return -EINVAL;
-
- if (local_sense_len) {
- void __user **sense_ioc_ptr =
- (void __user **)((u8 *)((unsigned long)&ioc->frame.raw) + local_sense_off);
- compat_uptr_t *sense_cioc_ptr =
- (compat_uptr_t *)(((unsigned long)&cioc->frame.raw) + user_sense_off);
- if (get_user(ptr, sense_cioc_ptr) ||
- put_user(compat_ptr(ptr), sense_ioc_ptr))
- return -EFAULT;
- }
-
- for (i = 0; i < MAX_IOCTL_SGE; i++) {
- if (get_user(ptr, &cioc->sgl[i].iov_base) ||
- put_user(compat_ptr(ptr), &ioc->sgl[i].iov_base) ||
- copy_in_user(&ioc->sgl[i].iov_len,
- &cioc->sgl[i].iov_len, sizeof(compat_size_t)))
- return -EFAULT;
- }
-
- error = megasas_mgmt_ioctl_fw(file, (unsigned long)ioc);
-
- if (copy_in_user(&cioc->frame.hdr.cmd_status,
- &ioc->frame.hdr.cmd_status, sizeof(u8))) {
- printk(KERN_DEBUG "megasas: error copy_in_user cmd_status\n");
- return -EFAULT;
- }
- return error;
-}
-
static long
megasas_mgmt_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
switch (cmd) {
case MEGASAS_IOC_FIRMWARE32:
- return megasas_mgmt_compat_ioctl_fw(file, arg);
+ return megasas_mgmt_ioctl_fw(file, arg);
case MEGASAS_IOC_GET_AEN:
return megasas_mgmt_ioctl_aen(file, arg);
}
@@ -8507,6 +8656,8 @@ static const struct file_operations megasas_mgmt_fops = {
.llseek = noop_llseek,
};
+static SIMPLE_DEV_PM_OPS(megasas_pm_ops, megasas_suspend, megasas_resume);
+
/*
* PCI hotplug support registration structure
*/
@@ -8516,8 +8667,7 @@ static struct pci_driver megasas_pci_driver = {
.id_table = megasas_pci_table,
.probe = megasas_probe_one,
.remove = megasas_detach_one,
- .suspend = megasas_suspend,
- .resume = megasas_resume,
+ .driver.pm = &megasas_pm_ops,
.shutdown = megasas_shutdown,
};
@@ -8607,34 +8757,26 @@ static
int megasas_update_device_list(struct megasas_instance *instance,
int event_type)
{
- int dcmd_ret = DCMD_SUCCESS;
+ int dcmd_ret;
if (instance->enable_fw_dev_list) {
- dcmd_ret = megasas_host_device_list_query(instance, false);
- if (dcmd_ret != DCMD_SUCCESS)
- goto out;
+ return megasas_host_device_list_query(instance, false);
} else {
if (event_type & SCAN_PD_CHANNEL) {
dcmd_ret = megasas_get_pd_list(instance);
-
if (dcmd_ret != DCMD_SUCCESS)
- goto out;
+ return dcmd_ret;
}
if (event_type & SCAN_VD_CHANNEL) {
if (!instance->requestorId ||
- (instance->requestorId &&
- megasas_get_ld_vf_affiliation(instance, 0))) {
- dcmd_ret = megasas_ld_list_query(instance,
+ megasas_get_ld_vf_affiliation(instance, 0)) {
+ return megasas_ld_list_query(instance,
MR_LD_QUERY_TYPE_EXPOSED_TO_HOST);
- if (dcmd_ret != DCMD_SUCCESS)
- goto out;
}
}
}
-
-out:
- return dcmd_ret;
+ return DCMD_SUCCESS;
}
/**
@@ -8733,8 +8875,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");
@@ -8757,12 +8901,23 @@ 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:
@@ -8841,6 +8996,7 @@ static int __init megasas_init(void)
msix_vectors = 1;
rdpq_enable = 0;
dual_qdepth_disable = 1;
+ poll_queues = 0;
}
/*
@@ -8848,8 +9004,7 @@ static int __init megasas_init(void)
*/
pr_info("megasas: %s\n", MEGASAS_VERSION);
- spin_lock_init(&poll_aen_lock);
-
+ megasas_dbg_lvl = 0;
support_poll_for_event = 2;
support_device_change = 1;
support_nvme_encapsulation = true;