diff options
Diffstat (limited to 'drivers/scsi/megaraid/megaraid_sas_base.c')
| -rw-r--r-- | drivers/scsi/megaraid/megaraid_sas_base.c | 887 |
1 files changed, 527 insertions, 360 deletions
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 00668335c2af..abbbc4b36cd1 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -29,7 +29,7 @@ #include <linux/uio.h> #include <linux/slab.h> #include <linux/uaccess.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include <linux/fs.h> #include <linux/compat.h> #include <linux/blkdev.h> @@ -77,7 +77,7 @@ 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)"); @@ -93,7 +93,7 @@ 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."); -int perf_mode = -1; +static 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" "0 - balanced: High iops and low latency queues are allocated &\n\t\t" @@ -105,14 +105,27 @@ MODULE_PARM_DESC(perf_mode, "Performance mode (only for Aero adapters), options: "default mode is 'balanced'" ); -int event_log_level = MFI_EVT_CLASS_CRITICAL; +static 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)"); -unsigned int enable_sdev_max_qd; +static 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"); +static 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" + ); + +static 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,11 +140,13 @@ 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 */ -static struct pci_device_id megasas_pci_table[] = { +static const struct pci_device_id megasas_pci_table[] = { {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064R)}, /* xscale IOP */ @@ -199,13 +214,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, @@ -250,13 +262,13 @@ u32 megasas_readl(struct megasas_instance *instance, * Fusion registers could intermittently return all zeroes. * This behavior is transient in nature and subsequent reads will * return valid value. As a workaround in driver, retry readl for - * upto three times until a non-zero value is read. + * up to thirty times until a non-zero value is read. */ if (instance->adapter_type == AERO_SERIES) { do { ret_val = readl(addr); i++; - } while (ret_val == 0 && i < 3); + } while (ret_val == 0 && i < 30); return ret_val; } else { return readl(addr); @@ -425,16 +437,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 +468,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 +484,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 +492,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 +527,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 +548,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 +590,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 +620,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 +650,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 +666,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 +675,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 +709,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 +730,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 +761,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 +779,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 +795,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 +804,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 +848,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 +871,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 +901,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 +927,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 +943,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 +952,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 +986,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 +1010,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 +1071,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 +1100,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 +1450,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 +1638,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 +1759,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 +1778,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 +1808,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 +1856,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; } @@ -1853,7 +1887,7 @@ static struct megasas_instance *megasas_lookup_instance(u16 host_no) * Returns void */ void megasas_set_dynamic_target_properties(struct scsi_device *sdev, - bool is_target_prop) + struct queue_limits *lim, bool is_target_prop) { u16 pd_index = 0, ld; u32 device_id; @@ -1880,8 +1914,10 @@ void megasas_set_dynamic_target_properties(struct scsi_device *sdev, return; 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); + if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER) { + if (lim) + lim->dma_alignment = 0x7; + } mr_device_priv_data->is_tm_capable = raid->capability.tmCapable; @@ -1932,7 +1968,8 @@ void megasas_set_dynamic_target_properties(struct scsi_device *sdev, * */ static inline void -megasas_set_nvme_device_properties(struct scsi_device *sdev, u32 max_io_size) +megasas_set_nvme_device_properties(struct scsi_device *sdev, + struct queue_limits *lim, u32 max_io_size) { struct megasas_instance *instance; u32 mr_nvme_pg_size; @@ -1941,10 +1978,8 @@ 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)); - - blk_queue_flag_set(QUEUE_FLAG_NOMERGES, sdev->request_queue); - blk_queue_virt_boundary(sdev->request_queue, mr_nvme_pg_size - 1); + lim->max_hw_sectors = max_io_size / 512; + lim->virt_boundary_mask = mr_nvme_pg_size - 1; } /* @@ -2006,7 +2041,7 @@ static void megasas_set_fw_assisted_qd(struct scsi_device *sdev, * @is_target_prop true, if fw provided target properties. */ static void megasas_set_static_target_properties(struct scsi_device *sdev, - bool is_target_prop) + struct queue_limits *lim, bool is_target_prop) { u32 max_io_size_kb = MR_DEFAULT_NVME_MDTS_KB; struct megasas_instance *instance; @@ -2025,13 +2060,15 @@ static void megasas_set_static_target_properties(struct scsi_device *sdev, max_io_size_kb = le32_to_cpu(instance->tgt_prop->max_io_size_kb); if (instance->nvme_page_size && max_io_size_kb) - megasas_set_nvme_device_properties(sdev, (max_io_size_kb << 10)); + megasas_set_nvme_device_properties(sdev, lim, + max_io_size_kb << 10); megasas_set_fw_assisted_qd(sdev, is_target_prop); } -static int megasas_slave_configure(struct scsi_device *sdev) +static int megasas_sdev_configure(struct scsi_device *sdev, + struct queue_limits *lim) { u16 pd_index = 0; struct megasas_instance *instance; @@ -2061,19 +2098,22 @@ static int megasas_slave_configure(struct scsi_device *sdev) ret_target_prop = megasas_get_target_prop(instance, sdev); is_target_prop = (ret_target_prop == DCMD_SUCCESS) ? true : false; - megasas_set_static_target_properties(sdev, is_target_prop); + megasas_set_static_target_properties(sdev, lim, is_target_prop); /* This sdev property may change post OCR */ - megasas_set_dynamic_target_properties(sdev, is_target_prop); + megasas_set_dynamic_target_properties(sdev, lim, is_target_prop); + + if (!MEGASAS_IS_LOGICAL(sdev)) + sdev->no_vpd_size = 1; mutex_unlock(&instance->reset_mutex); return 0; } -static int megasas_slave_alloc(struct scsi_device *sdev) +static int megasas_sdev_init(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 +2131,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 +2141,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, @@ -2105,8 +2156,25 @@ scan_target: return 0; } -static void megasas_slave_destroy(struct scsi_device *sdev) +static void megasas_sdev_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; } @@ -2656,7 +2724,7 @@ out: static void megasas_sriov_heartbeat_handler(struct timer_list *t) { struct megasas_instance *instance = - from_timer(instance, t, sriov_heartbeat_timer); + timer_container_of(instance, t, sriov_heartbeat_timer); if (instance->hb_host_mem->HB.fwCounter != instance->hb_host_mem->HB.driverCounter) { @@ -2727,7 +2795,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" @@ -2864,15 +2932,14 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd) * Sets the FW busy flag and reduces the host->can_queue if the * cmd has not been completed within the timeout period. */ -static enum -blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd) +static enum scsi_timeout_action megasas_reset_timer(struct scsi_cmnd *scmd) { struct megasas_instance *instance; unsigned long flags; if (time_after(jiffies, scmd->jiffies_at_alloc + (scmd_timeout * 2) * HZ)) { - return BLK_EH_DONE; + return SCSI_EH_NOT_HANDLED; } instance = (struct megasas_instance *)scmd->device->host->hostdata; @@ -2886,7 +2953,7 @@ blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd) spin_unlock_irqrestore(instance->host->host_lock, flags); } - return BLK_EH_RESET_TIMER; + return SCSI_EH_RESET_TIMER; } /** @@ -2916,11 +2983,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 +3003,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, @@ -2997,6 +3059,7 @@ megasas_dump_sys_regs(void __iomem *reg_set, char *buf) /** * 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) { @@ -3074,12 +3137,12 @@ static int megasas_reset_target(struct scsi_cmnd *scmd) /** * megasas_bios_param - Returns disk geometry for a disk * @sdev: device handle - * @bdev: block device + * @unused: gendisk * @capacity: drive capacity * @geom: geometry parameters */ static int -megasas_bios_param(struct scsi_device *sdev, struct block_device *bdev, +megasas_bios_param(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]) { int heads; @@ -3115,6 +3178,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_map_hw_queues(map, &instance->pdev->dev, 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); /** @@ -3176,14 +3276,13 @@ fw_crash_buffer_store(struct device *cdev, struct megasas_instance *instance = (struct megasas_instance *) shost->hostdata; int val = 0; - unsigned long flags; if (kstrtoint(buf, 0, &val) != 0) return -EINVAL; - spin_lock_irqsave(&instance->crashdump_lock, flags); + mutex_lock(&instance->crashdump_lock); instance->fw_crash_buffer_offset = val; - spin_unlock_irqrestore(&instance->crashdump_lock, flags); + mutex_unlock(&instance->crashdump_lock); return strlen(buf); } @@ -3198,24 +3297,23 @@ fw_crash_buffer_show(struct device *cdev, unsigned long dmachunk = CRASH_DMA_BUF_SIZE; unsigned long chunk_left_bytes; unsigned long src_addr; - unsigned long flags; u32 buff_offset; - spin_lock_irqsave(&instance->crashdump_lock, flags); + mutex_lock(&instance->crashdump_lock); buff_offset = instance->fw_crash_buffer_offset; - if (!instance->crash_dump_buf && + if (!instance->crash_dump_buf || !((instance->fw_crash_state == AVAILABLE) || (instance->fw_crash_state == COPYING))) { dev_err(&instance->pdev->dev, "Firmware crash dump is not available\n"); - spin_unlock_irqrestore(&instance->crashdump_lock, flags); + mutex_unlock(&instance->crashdump_lock); 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"); - spin_unlock_irqrestore(&instance->crashdump_lock, flags); + mutex_unlock(&instance->crashdump_lock); return 0; } @@ -3227,7 +3325,7 @@ fw_crash_buffer_show(struct device *cdev, src_addr = (unsigned long)instance->crash_buf[buff_offset / dmachunk] + (buff_offset % dmachunk); memcpy(buf, (void *)src_addr, size); - spin_unlock_irqrestore(&instance->crashdump_lock, flags); + mutex_unlock(&instance->crashdump_lock); return size; } @@ -3252,7 +3350,6 @@ fw_crash_state_store(struct device *cdev, struct megasas_instance *instance = (struct megasas_instance *) shost->hostdata; int val = 0; - unsigned long flags; if (kstrtoint(buf, 0, &val) != 0) return -EINVAL; @@ -3266,9 +3363,9 @@ fw_crash_state_store(struct device *cdev, instance->fw_crash_state = val; if ((val == COPIED) || (val == COPY_ERROR)) { - spin_lock_irqsave(&instance->crashdump_lock, flags); + mutex_lock(&instance->crashdump_lock); megasas_free_host_crash_buffer(instance); - spin_unlock_irqrestore(&instance->crashdump_lock, flags); + mutex_unlock(&instance->crashdump_lock); if (val == COPY_ERROR) dev_info(&instance->pdev->dev, "application failed to " "copy Firmware crash dump\n"); @@ -3392,39 +3489,44 @@ 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 */ -static struct scsi_host_template megasas_template = { +static const struct scsi_host_template megasas_template = { .module = THIS_MODULE, .name = "Avago SAS based MegaRAID driver", .proc_name = "megaraid_sas", - .slave_configure = megasas_slave_configure, - .slave_alloc = megasas_slave_alloc, - .slave_destroy = megasas_slave_destroy, + .sdev_configure = megasas_sdev_configure, + .sdev_init = megasas_sdev_init, + .sdev_destroy = megasas_sdev_destroy, .queuecommand = megasas_queue_command, .eh_target_reset_handler = megasas_reset_target, .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), }; /** @@ -3468,6 +3570,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 @@ -3492,7 +3610,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: @@ -3518,7 +3636,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: @@ -3533,7 +3651,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; @@ -3547,8 +3665,10 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, case MFI_STAT_SCSI_IO_FAILED: case MFI_STAT_LD_INIT_IN_PROGRESS: - cmd->scmd->result = - (DID_ERROR << 16) | hdr->scsi_status; + if (hdr->scsi_status == 0xf0) + cmd->scmd->result = (DID_ERROR << 16) | SAM_STAT_CHECK_CONDITION; + else + cmd->scmd->result = (DID_ERROR << 16) | hdr->scsi_status; break; case MFI_STAT_SCSI_DONE_WITH_ERROR: @@ -3560,8 +3680,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; @@ -3581,7 +3699,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; @@ -3630,9 +3748,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 || @@ -3777,7 +3899,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 @@ -3785,7 +3907,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) { @@ -3829,9 +3951,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 ; } @@ -3902,10 +4024,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) { @@ -3963,8 +4083,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) { @@ -3986,6 +4109,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 @@ -4351,8 +4475,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); @@ -4743,7 +4865,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 @@ -4857,6 +4979,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 @@ -5033,9 +5156,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_t(struct MR_FW_RAID_MAP, ldSpanMap, + instance->fw_supported_vd_count); fusion->new_map_sz = sizeof(struct MR_FW_RAID_MAP_EXT); fusion->max_map_sz = @@ -5134,7 +5257,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. @@ -5602,9 +5725,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; @@ -5642,6 +5769,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]); } @@ -5653,7 +5783,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. */ @@ -5662,10 +5791,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_t(struct MR_PD_CFG_SEQ_NUM_SYNC, seq, + MAX_PHYSICAL_DEVICES); instance->use_seqnum_jbod_fp = instance->support_seqnum_jbod_fp; @@ -5748,10 +5877,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; @@ -5772,22 +5897,29 @@ 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); + int nid = 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)); + if (nid == NUMA_NO_NODE) + nid = 0; + mask = cpumask_of_node(nid); + + for (i = 0; i < instance->low_latency_index_start; i++) { + irq = pci_irq_vector(instance->pdev, i); + irq_set_affinity_and_hint(irq, mask); + } } } @@ -5801,13 +5933,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; } @@ -5823,26 +5958,51 @@ 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 = blk_mq_num_online_queues(0) + + 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 */ instance->perf_mode = MR_LATENCY_PERF_MODE; instance->low_latency_index_start = 1; - num_msix_req = num_online_cpus() + instance->low_latency_index_start; + num_msix_req = blk_mq_num_online_queues(0) + + 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); } 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; @@ -5850,7 +6010,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); } /** @@ -6085,7 +6245,7 @@ static int megasas_init_fw(struct megasas_instance *instance) intr_coalescing = (scratch_pad_1 & MR_INTR_COALESCING_SUPPORT_OFFSET) ? true : false; if (intr_coalescing && - (num_online_cpus() >= MR_HIGH_IOPS_QUEUE_COUNT) && + (blk_mq_num_online_queues(0) >= MR_HIGH_IOPS_QUEUE_COUNT) && (instance->msix_vectors == MEGASAS_MAX_MSIX_QUEUES)) instance->perf_mode = MR_BALANCED_PERF_MODE; else @@ -6129,7 +6289,8 @@ static int megasas_init_fw(struct megasas_instance *instance) else instance->low_latency_index_start = 1; - num_msix_req = num_online_cpus() + instance->low_latency_index_start; + num_msix_req = blk_mq_num_online_queues(0) + + instance->low_latency_index_start; instance->msix_vectors = min(num_msix_req, instance->msix_vectors); @@ -6153,7 +6314,7 @@ static int megasas_init_fw(struct megasas_instance *instance) } if (!instance->msix_vectors) { - i = pci_alloc_irq_vectors(instance->pdev, 1, 1, PCI_IRQ_LEGACY); + i = pci_alloc_irq_vectors(instance->pdev, 1, 1, PCI_IRQ_INTX); if (i < 0) goto fail_init_adapter; } @@ -6161,8 +6322,8 @@ static int megasas_init_fw(struct megasas_instance *instance) megasas_setup_reply_map(instance); dev_info(&instance->pdev->dev, - "current msix/online cpus\t: (%d/%d)\n", - instance->msix_vectors, (unsigned int)num_online_cpus()); + "current msix/max num queues\t: (%d/%u)\n", + instance->msix_vectors, blk_mq_num_online_queues(0)); dev_info(&instance->pdev->dev, "RDPQ mode\t: (%s)\n", instance->is_rdpq ? "enabled" : "disabled"); @@ -6230,7 +6391,7 @@ static int megasas_init_fw(struct megasas_instance *instance) GFP_KERNEL); if (!fusion->stream_detect_by_ld[i]) { dev_err(&instance->pdev->dev, - "unable to allocate stream detect by LD\n "); + "unable to allocate stream detect by LD\n"); for (j = 0; j < i; ++j) kfree(fusion->stream_detect_by_ld[j]); kfree(fusion->stream_detect_by_ld); @@ -6372,7 +6533,7 @@ static int megasas_init_fw(struct megasas_instance *instance) fail_start_watchdog: if (instance->requestorId && !instance->skip_heartbeat_timer_del) - del_timer_sync(&instance->sriov_heartbeat_timer); + timer_delete_sync(&instance->sriov_heartbeat_timer); fail_get_ld_pd_list: instance->instancet->disable_intr(instance); megasas_destroy_irqs(instance); @@ -6494,7 +6655,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 @@ -6794,6 +6955,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 */ @@ -6968,22 +7155,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; } /* @@ -7014,8 +7197,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) @@ -7042,7 +7226,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; } @@ -7249,7 +7433,7 @@ static inline void megasas_init_ctrl_params(struct megasas_instance *instance) init_waitqueue_head(&instance->int_cmd_wait_q); init_waitqueue_head(&instance->abort_cmd_wait_q); - spin_lock_init(&instance->crashdump_lock); + mutex_init(&instance->crashdump_lock); spin_lock_init(&instance->mfi_pool_lock); spin_lock_init(&instance->hba_lock); spin_lock_init(&instance->stream_lock); @@ -7261,7 +7445,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; @@ -7346,7 +7529,7 @@ static int megasas_probe_one(struct pci_dev *pdev, */ instance->pdev = pdev; instance->host = host; - instance->unique_id = pdev->bus->number << 8 | pdev->devfn; + instance->unique_id = pci_dev_id(pdev); instance->init_id = MEGASAS_DEFAULT_INIT_ID; megasas_set_adapter_type(instance); @@ -7424,11 +7607,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) + timer_delete_sync(&instance->sriov_heartbeat_timer); + instance->instancet->disable_intr(instance); megasas_destroy_irqs(instance); @@ -7436,8 +7624,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: @@ -7539,29 +7735,27 @@ 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) - del_timer_sync(&instance->sriov_heartbeat_timer); + timer_delete_sync(&instance->sriov_heartbeat_timer); /* Stop the FW fault detection watchdog */ if (instance->adapter_type != MFI_SERIES) @@ -7587,48 +7781,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 @@ -7678,7 +7853,7 @@ megasas_resume(struct pci_dev *pdev) if (!instance->msix_vectors) { rval = pci_alloc_irq_vectors(instance->pdev, 1, 1, - PCI_IRQ_LEGACY); + PCI_IRQ_INTX); if (rval < 0) goto fail_reenable_msix; } @@ -7744,7 +7919,7 @@ megasas_resume(struct pci_dev *pdev) fail_start_watchdog: if (instance->requestorId && !instance->skip_heartbeat_timer_del) - del_timer_sync(&instance->sriov_heartbeat_timer); + timer_delete_sync(&instance->sriov_heartbeat_timer); fail_init_mfi: megasas_free_ctrl_dma_buffers(instance); megasas_free_ctrl_mem(instance); @@ -7754,14 +7929,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) @@ -7802,7 +7971,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); @@ -7814,7 +7983,7 @@ static void megasas_detach_one(struct pci_dev *pdev) /* Shutdown SR-IOV heartbeat timer */ if (instance->requestorId && !instance->skip_heartbeat_timer_del) - del_timer_sync(&instance->sriov_heartbeat_timer); + timer_delete_sync(&instance->sriov_heartbeat_timer); /* Stop the FW fault detection watchdog */ if (instance->adapter_type != MFI_SERIES) @@ -7874,9 +8043,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_t(struct MR_PD_CFG_SEQ_NUM_SYNC, + seq, MAX_PHYSICAL_DEVICES); for (i = 0; i < 2 ; i++) { if (fusion->ld_map[i]) dma_free_coherent(&instance->pdev->dev, @@ -7931,7 +8100,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) { @@ -7956,8 +8125,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) { @@ -7970,8 +8141,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. @@ -7997,9 +8171,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; @@ -8057,7 +8233,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, @@ -8072,7 +8249,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; @@ -8195,6 +8372,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) { @@ -8202,12 +8386,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); } /* @@ -8251,16 +8432,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; @@ -8303,6 +8487,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 = @@ -8311,7 +8527,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); @@ -8397,6 +8617,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) @@ -8413,78 +8636,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); } @@ -8508,6 +8666,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 */ @@ -8517,8 +8677,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, }; @@ -8608,34 +8767,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; } /** @@ -8734,8 +8885,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"); @@ -8758,12 +8911,26 @@ 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) { + mutex_unlock(&instance->reset_mutex); + megasas_remove_scsi_device(sdev1); + mutex_lock(&instance->reset_mutex); + } + + 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: @@ -8842,6 +9009,7 @@ static int __init megasas_init(void) msix_vectors = 1; rdpq_enable = 0; dual_qdepth_disable = 1; + poll_queues = 0; } /* @@ -8849,8 +9017,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; |
