162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Linux MegaRAID driver for SAS based RAID controllers
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (c) 2003-2013  LSI Corporation
662306a36Sopenharmony_ci *  Copyright (c) 2013-2016  Avago Technologies
762306a36Sopenharmony_ci *  Copyright (c) 2016-2018  Broadcom Inc.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *  Authors: Broadcom Inc.
1062306a36Sopenharmony_ci *           Sreenivas Bagalkote
1162306a36Sopenharmony_ci *           Sumant Patro
1262306a36Sopenharmony_ci *           Bo Yang
1362306a36Sopenharmony_ci *           Adam Radford
1462306a36Sopenharmony_ci *           Kashyap Desai <kashyap.desai@broadcom.com>
1562306a36Sopenharmony_ci *           Sumit Saxena <sumit.saxena@broadcom.com>
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci *  Send feedback to: megaraidlinux.pdl@broadcom.com
1862306a36Sopenharmony_ci */
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <linux/kernel.h>
2162306a36Sopenharmony_ci#include <linux/types.h>
2262306a36Sopenharmony_ci#include <linux/pci.h>
2362306a36Sopenharmony_ci#include <linux/list.h>
2462306a36Sopenharmony_ci#include <linux/moduleparam.h>
2562306a36Sopenharmony_ci#include <linux/module.h>
2662306a36Sopenharmony_ci#include <linux/spinlock.h>
2762306a36Sopenharmony_ci#include <linux/interrupt.h>
2862306a36Sopenharmony_ci#include <linux/delay.h>
2962306a36Sopenharmony_ci#include <linux/uio.h>
3062306a36Sopenharmony_ci#include <linux/slab.h>
3162306a36Sopenharmony_ci#include <linux/uaccess.h>
3262306a36Sopenharmony_ci#include <asm/unaligned.h>
3362306a36Sopenharmony_ci#include <linux/fs.h>
3462306a36Sopenharmony_ci#include <linux/compat.h>
3562306a36Sopenharmony_ci#include <linux/blkdev.h>
3662306a36Sopenharmony_ci#include <linux/mutex.h>
3762306a36Sopenharmony_ci#include <linux/poll.h>
3862306a36Sopenharmony_ci#include <linux/vmalloc.h>
3962306a36Sopenharmony_ci#include <linux/irq_poll.h>
4062306a36Sopenharmony_ci#include <linux/blk-mq-pci.h>
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#include <scsi/scsi.h>
4362306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h>
4462306a36Sopenharmony_ci#include <scsi/scsi_device.h>
4562306a36Sopenharmony_ci#include <scsi/scsi_host.h>
4662306a36Sopenharmony_ci#include <scsi/scsi_tcq.h>
4762306a36Sopenharmony_ci#include <scsi/scsi_dbg.h>
4862306a36Sopenharmony_ci#include "megaraid_sas_fusion.h"
4962306a36Sopenharmony_ci#include "megaraid_sas.h"
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/*
5262306a36Sopenharmony_ci * Number of sectors per IO command
5362306a36Sopenharmony_ci * Will be set in megasas_init_mfi if user does not provide
5462306a36Sopenharmony_ci */
5562306a36Sopenharmony_cistatic unsigned int max_sectors;
5662306a36Sopenharmony_cimodule_param_named(max_sectors, max_sectors, int, 0444);
5762306a36Sopenharmony_ciMODULE_PARM_DESC(max_sectors,
5862306a36Sopenharmony_ci	"Maximum number of sectors per IO command");
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic int msix_disable;
6162306a36Sopenharmony_cimodule_param(msix_disable, int, 0444);
6262306a36Sopenharmony_ciMODULE_PARM_DESC(msix_disable, "Disable MSI-X interrupt handling. Default: 0");
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic unsigned int msix_vectors;
6562306a36Sopenharmony_cimodule_param(msix_vectors, int, 0444);
6662306a36Sopenharmony_ciMODULE_PARM_DESC(msix_vectors, "MSI-X max vector count. Default: Set by FW");
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic int allow_vf_ioctls;
6962306a36Sopenharmony_cimodule_param(allow_vf_ioctls, int, 0444);
7062306a36Sopenharmony_ciMODULE_PARM_DESC(allow_vf_ioctls, "Allow ioctls in SR-IOV VF mode. Default: 0");
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic unsigned int throttlequeuedepth = MEGASAS_THROTTLE_QUEUE_DEPTH;
7362306a36Sopenharmony_cimodule_param(throttlequeuedepth, int, 0444);
7462306a36Sopenharmony_ciMODULE_PARM_DESC(throttlequeuedepth,
7562306a36Sopenharmony_ci	"Adapter queue depth when throttled due to I/O timeout. Default: 16");
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ciunsigned int resetwaittime = MEGASAS_RESET_WAIT_TIME;
7862306a36Sopenharmony_cimodule_param(resetwaittime, int, 0444);
7962306a36Sopenharmony_ciMODULE_PARM_DESC(resetwaittime, "Wait time in (1-180s) after I/O timeout before resetting adapter. Default: 180s");
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic int smp_affinity_enable = 1;
8262306a36Sopenharmony_cimodule_param(smp_affinity_enable, int, 0444);
8362306a36Sopenharmony_ciMODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disable Default: enable(1)");
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic int rdpq_enable = 1;
8662306a36Sopenharmony_cimodule_param(rdpq_enable, int, 0444);
8762306a36Sopenharmony_ciMODULE_PARM_DESC(rdpq_enable, "Allocate reply queue in chunks for large queue depth enable/disable Default: enable(1)");
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ciunsigned int dual_qdepth_disable;
9062306a36Sopenharmony_cimodule_param(dual_qdepth_disable, int, 0444);
9162306a36Sopenharmony_ciMODULE_PARM_DESC(dual_qdepth_disable, "Disable dual queue depth feature. Default: 0");
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic unsigned int scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT;
9462306a36Sopenharmony_cimodule_param(scmd_timeout, int, 0444);
9562306a36Sopenharmony_ciMODULE_PARM_DESC(scmd_timeout, "scsi command timeout (10-90s), default 90s. See megasas_reset_timer.");
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ciint perf_mode = -1;
9862306a36Sopenharmony_cimodule_param(perf_mode, int, 0444);
9962306a36Sopenharmony_ciMODULE_PARM_DESC(perf_mode, "Performance mode (only for Aero adapters), options:\n\t\t"
10062306a36Sopenharmony_ci		"0 - balanced: High iops and low latency queues are allocated &\n\t\t"
10162306a36Sopenharmony_ci		"interrupt coalescing is enabled only on high iops queues\n\t\t"
10262306a36Sopenharmony_ci		"1 - iops: High iops queues are not allocated &\n\t\t"
10362306a36Sopenharmony_ci		"interrupt coalescing is enabled on all queues\n\t\t"
10462306a36Sopenharmony_ci		"2 - latency: High iops queues are not allocated &\n\t\t"
10562306a36Sopenharmony_ci		"interrupt coalescing is disabled on all queues\n\t\t"
10662306a36Sopenharmony_ci		"default mode is 'balanced'"
10762306a36Sopenharmony_ci		);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ciint event_log_level = MFI_EVT_CLASS_CRITICAL;
11062306a36Sopenharmony_cimodule_param(event_log_level, int, 0644);
11162306a36Sopenharmony_ciMODULE_PARM_DESC(event_log_level, "Asynchronous event logging level- range is: -2(CLASS_DEBUG) to 4(CLASS_DEAD), Default: 2(CLASS_CRITICAL)");
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ciunsigned int enable_sdev_max_qd;
11462306a36Sopenharmony_cimodule_param(enable_sdev_max_qd, int, 0444);
11562306a36Sopenharmony_ciMODULE_PARM_DESC(enable_sdev_max_qd, "Enable sdev max qd as can_queue. Default: 0");
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ciint poll_queues;
11862306a36Sopenharmony_cimodule_param(poll_queues, int, 0444);
11962306a36Sopenharmony_ciMODULE_PARM_DESC(poll_queues, "Number of queues to be use for io_uring poll mode.\n\t\t"
12062306a36Sopenharmony_ci		"This parameter is effective only if host_tagset_enable=1 &\n\t\t"
12162306a36Sopenharmony_ci		"It is not applicable for MFI_SERIES. &\n\t\t"
12262306a36Sopenharmony_ci		"Driver will work in latency mode. &\n\t\t"
12362306a36Sopenharmony_ci		"High iops queues are not allocated &\n\t\t"
12462306a36Sopenharmony_ci		);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ciint host_tagset_enable = 1;
12762306a36Sopenharmony_cimodule_param(host_tagset_enable, int, 0444);
12862306a36Sopenharmony_ciMODULE_PARM_DESC(host_tagset_enable, "Shared host tagset enable/disable Default: enable(1)");
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ciMODULE_LICENSE("GPL");
13162306a36Sopenharmony_ciMODULE_VERSION(MEGASAS_VERSION);
13262306a36Sopenharmony_ciMODULE_AUTHOR("megaraidlinux.pdl@broadcom.com");
13362306a36Sopenharmony_ciMODULE_DESCRIPTION("Broadcom MegaRAID SAS Driver");
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ciint megasas_transition_to_ready(struct megasas_instance *instance, int ocr);
13662306a36Sopenharmony_cistatic int megasas_get_pd_list(struct megasas_instance *instance);
13762306a36Sopenharmony_cistatic int megasas_ld_list_query(struct megasas_instance *instance,
13862306a36Sopenharmony_ci				 u8 query_type);
13962306a36Sopenharmony_cistatic int megasas_issue_init_mfi(struct megasas_instance *instance);
14062306a36Sopenharmony_cistatic int megasas_register_aen(struct megasas_instance *instance,
14162306a36Sopenharmony_ci				u32 seq_num, u32 class_locale_word);
14262306a36Sopenharmony_cistatic void megasas_get_pd_info(struct megasas_instance *instance,
14362306a36Sopenharmony_ci				struct scsi_device *sdev);
14462306a36Sopenharmony_cistatic void
14562306a36Sopenharmony_cimegasas_set_ld_removed_by_fw(struct megasas_instance *instance);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci/*
14862306a36Sopenharmony_ci * PCI ID table for all supported controllers
14962306a36Sopenharmony_ci */
15062306a36Sopenharmony_cistatic struct pci_device_id megasas_pci_table[] = {
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064R)},
15362306a36Sopenharmony_ci	/* xscale IOP */
15462306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078R)},
15562306a36Sopenharmony_ci	/* ppc IOP */
15662306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078DE)},
15762306a36Sopenharmony_ci	/* ppc IOP */
15862306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078GEN2)},
15962306a36Sopenharmony_ci	/* gen2*/
16062306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0079GEN2)},
16162306a36Sopenharmony_ci	/* gen2*/
16262306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0073SKINNY)},
16362306a36Sopenharmony_ci	/* skinny*/
16462306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0071SKINNY)},
16562306a36Sopenharmony_ci	/* skinny*/
16662306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VERDE_ZCR)},
16762306a36Sopenharmony_ci	/* xscale IOP, vega */
16862306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_PERC5)},
16962306a36Sopenharmony_ci	/* xscale IOP */
17062306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FUSION)},
17162306a36Sopenharmony_ci	/* Fusion */
17262306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_PLASMA)},
17362306a36Sopenharmony_ci	/* Plasma */
17462306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_INVADER)},
17562306a36Sopenharmony_ci	/* Invader */
17662306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FURY)},
17762306a36Sopenharmony_ci	/* Fury */
17862306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_INTRUDER)},
17962306a36Sopenharmony_ci	/* Intruder */
18062306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_INTRUDER_24)},
18162306a36Sopenharmony_ci	/* Intruder 24 port*/
18262306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CUTLASS_52)},
18362306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CUTLASS_53)},
18462306a36Sopenharmony_ci	/* VENTURA */
18562306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VENTURA)},
18662306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CRUSADER)},
18762306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_HARPOON)},
18862306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_TOMCAT)},
18962306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VENTURA_4PORT)},
19062306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CRUSADER_4PORT)},
19162306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E1)},
19262306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E2)},
19362306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E5)},
19462306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E6)},
19562306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E0)},
19662306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E3)},
19762306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E4)},
19862306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E7)},
19962306a36Sopenharmony_ci	{}
20062306a36Sopenharmony_ci};
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, megasas_pci_table);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic int megasas_mgmt_majorno;
20562306a36Sopenharmony_cistruct megasas_mgmt_info megasas_mgmt_info;
20662306a36Sopenharmony_cistatic struct fasync_struct *megasas_async_queue;
20762306a36Sopenharmony_cistatic DEFINE_MUTEX(megasas_async_queue_mutex);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_cistatic int megasas_poll_wait_aen;
21062306a36Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(megasas_poll_wait);
21162306a36Sopenharmony_cistatic u32 support_poll_for_event;
21262306a36Sopenharmony_ciu32 megasas_dbg_lvl;
21362306a36Sopenharmony_cistatic u32 support_device_change;
21462306a36Sopenharmony_cistatic bool support_nvme_encapsulation;
21562306a36Sopenharmony_cistatic bool support_pci_lane_margining;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci/* define lock for aen poll */
21862306a36Sopenharmony_cistatic DEFINE_SPINLOCK(poll_aen_lock);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ciextern struct dentry *megasas_debugfs_root;
22162306a36Sopenharmony_ciextern int megasas_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_civoid
22462306a36Sopenharmony_cimegasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
22562306a36Sopenharmony_ci		     u8 alt_status);
22662306a36Sopenharmony_cistatic u32
22762306a36Sopenharmony_cimegasas_read_fw_status_reg_gen2(struct megasas_instance *instance);
22862306a36Sopenharmony_cistatic int
22962306a36Sopenharmony_cimegasas_adp_reset_gen2(struct megasas_instance *instance,
23062306a36Sopenharmony_ci		       struct megasas_register_set __iomem *reg_set);
23162306a36Sopenharmony_cistatic irqreturn_t megasas_isr(int irq, void *devp);
23262306a36Sopenharmony_cistatic u32
23362306a36Sopenharmony_cimegasas_init_adapter_mfi(struct megasas_instance *instance);
23462306a36Sopenharmony_ciu32
23562306a36Sopenharmony_cimegasas_build_and_issue_cmd(struct megasas_instance *instance,
23662306a36Sopenharmony_ci			    struct scsi_cmnd *scmd);
23762306a36Sopenharmony_cistatic void megasas_complete_cmd_dpc(unsigned long instance_addr);
23862306a36Sopenharmony_ciint
23962306a36Sopenharmony_ciwait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
24062306a36Sopenharmony_ci	int seconds);
24162306a36Sopenharmony_civoid megasas_fusion_ocr_wq(struct work_struct *work);
24262306a36Sopenharmony_cistatic int megasas_get_ld_vf_affiliation(struct megasas_instance *instance,
24362306a36Sopenharmony_ci					 int initial);
24462306a36Sopenharmony_cistatic int
24562306a36Sopenharmony_cimegasas_set_dma_mask(struct megasas_instance *instance);
24662306a36Sopenharmony_cistatic int
24762306a36Sopenharmony_cimegasas_alloc_ctrl_mem(struct megasas_instance *instance);
24862306a36Sopenharmony_cistatic inline void
24962306a36Sopenharmony_cimegasas_free_ctrl_mem(struct megasas_instance *instance);
25062306a36Sopenharmony_cistatic inline int
25162306a36Sopenharmony_cimegasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance);
25262306a36Sopenharmony_cistatic inline void
25362306a36Sopenharmony_cimegasas_free_ctrl_dma_buffers(struct megasas_instance *instance);
25462306a36Sopenharmony_cistatic inline void
25562306a36Sopenharmony_cimegasas_init_ctrl_params(struct megasas_instance *instance);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ciu32 megasas_readl(struct megasas_instance *instance,
25862306a36Sopenharmony_ci		  const volatile void __iomem *addr)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	u32 i = 0, ret_val;
26162306a36Sopenharmony_ci	/*
26262306a36Sopenharmony_ci	 * Due to a HW errata in Aero controllers, reads to certain
26362306a36Sopenharmony_ci	 * Fusion registers could intermittently return all zeroes.
26462306a36Sopenharmony_ci	 * This behavior is transient in nature and subsequent reads will
26562306a36Sopenharmony_ci	 * return valid value. As a workaround in driver, retry readl for
26662306a36Sopenharmony_ci	 * up to thirty times until a non-zero value is read.
26762306a36Sopenharmony_ci	 */
26862306a36Sopenharmony_ci	if (instance->adapter_type == AERO_SERIES) {
26962306a36Sopenharmony_ci		do {
27062306a36Sopenharmony_ci			ret_val = readl(addr);
27162306a36Sopenharmony_ci			i++;
27262306a36Sopenharmony_ci		} while (ret_val == 0 && i < 30);
27362306a36Sopenharmony_ci		return ret_val;
27462306a36Sopenharmony_ci	} else {
27562306a36Sopenharmony_ci		return readl(addr);
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci/**
28062306a36Sopenharmony_ci * megasas_set_dma_settings -	Populate DMA address, length and flags for DCMDs
28162306a36Sopenharmony_ci * @instance:			Adapter soft state
28262306a36Sopenharmony_ci * @dcmd:			DCMD frame inside MFI command
28362306a36Sopenharmony_ci * @dma_addr:			DMA address of buffer to be passed to FW
28462306a36Sopenharmony_ci * @dma_len:			Length of DMA buffer to be passed to FW
28562306a36Sopenharmony_ci * @return:			void
28662306a36Sopenharmony_ci */
28762306a36Sopenharmony_civoid megasas_set_dma_settings(struct megasas_instance *instance,
28862306a36Sopenharmony_ci			      struct megasas_dcmd_frame *dcmd,
28962306a36Sopenharmony_ci			      dma_addr_t dma_addr, u32 dma_len)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	if (instance->consistent_mask_64bit) {
29262306a36Sopenharmony_ci		dcmd->sgl.sge64[0].phys_addr = cpu_to_le64(dma_addr);
29362306a36Sopenharmony_ci		dcmd->sgl.sge64[0].length = cpu_to_le32(dma_len);
29462306a36Sopenharmony_ci		dcmd->flags = cpu_to_le16(dcmd->flags | MFI_FRAME_SGL64);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	} else {
29762306a36Sopenharmony_ci		dcmd->sgl.sge32[0].phys_addr =
29862306a36Sopenharmony_ci				cpu_to_le32(lower_32_bits(dma_addr));
29962306a36Sopenharmony_ci		dcmd->sgl.sge32[0].length = cpu_to_le32(dma_len);
30062306a36Sopenharmony_ci		dcmd->flags = cpu_to_le16(dcmd->flags);
30162306a36Sopenharmony_ci	}
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic void
30562306a36Sopenharmony_cimegasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	instance->instancet->fire_cmd(instance,
30862306a36Sopenharmony_ci		cmd->frame_phys_addr, 0, instance->reg_set);
30962306a36Sopenharmony_ci	return;
31062306a36Sopenharmony_ci}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci/**
31362306a36Sopenharmony_ci * megasas_get_cmd -	Get a command from the free pool
31462306a36Sopenharmony_ci * @instance:		Adapter soft state
31562306a36Sopenharmony_ci *
31662306a36Sopenharmony_ci * Returns a free command from the pool
31762306a36Sopenharmony_ci */
31862306a36Sopenharmony_cistruct megasas_cmd *megasas_get_cmd(struct megasas_instance
31962306a36Sopenharmony_ci						  *instance)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	unsigned long flags;
32262306a36Sopenharmony_ci	struct megasas_cmd *cmd = NULL;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	spin_lock_irqsave(&instance->mfi_pool_lock, flags);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	if (!list_empty(&instance->cmd_pool)) {
32762306a36Sopenharmony_ci		cmd = list_entry((&instance->cmd_pool)->next,
32862306a36Sopenharmony_ci				 struct megasas_cmd, list);
32962306a36Sopenharmony_ci		list_del_init(&cmd->list);
33062306a36Sopenharmony_ci	} else {
33162306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "Command pool empty!\n");
33262306a36Sopenharmony_ci	}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	spin_unlock_irqrestore(&instance->mfi_pool_lock, flags);
33562306a36Sopenharmony_ci	return cmd;
33662306a36Sopenharmony_ci}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci/**
33962306a36Sopenharmony_ci * megasas_return_cmd -	Return a cmd to free command pool
34062306a36Sopenharmony_ci * @instance:		Adapter soft state
34162306a36Sopenharmony_ci * @cmd:		Command packet to be returned to free command pool
34262306a36Sopenharmony_ci */
34362306a36Sopenharmony_civoid
34462306a36Sopenharmony_cimegasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	unsigned long flags;
34762306a36Sopenharmony_ci	u32 blk_tags;
34862306a36Sopenharmony_ci	struct megasas_cmd_fusion *cmd_fusion;
34962306a36Sopenharmony_ci	struct fusion_context *fusion = instance->ctrl_context;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	/* This flag is used only for fusion adapter.
35262306a36Sopenharmony_ci	 * Wait for Interrupt for Polled mode DCMD
35362306a36Sopenharmony_ci	 */
35462306a36Sopenharmony_ci	if (cmd->flags & DRV_DCMD_POLLED_MODE)
35562306a36Sopenharmony_ci		return;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	spin_lock_irqsave(&instance->mfi_pool_lock, flags);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if (fusion) {
36062306a36Sopenharmony_ci		blk_tags = instance->max_scsi_cmds + cmd->index;
36162306a36Sopenharmony_ci		cmd_fusion = fusion->cmd_list[blk_tags];
36262306a36Sopenharmony_ci		megasas_return_cmd_fusion(instance, cmd_fusion);
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci	cmd->scmd = NULL;
36562306a36Sopenharmony_ci	cmd->frame_count = 0;
36662306a36Sopenharmony_ci	cmd->flags = 0;
36762306a36Sopenharmony_ci	memset(cmd->frame, 0, instance->mfi_frame_size);
36862306a36Sopenharmony_ci	cmd->frame->io.context = cpu_to_le32(cmd->index);
36962306a36Sopenharmony_ci	if (!fusion && reset_devices)
37062306a36Sopenharmony_ci		cmd->frame->hdr.cmd = MFI_CMD_INVALID;
37162306a36Sopenharmony_ci	list_add(&cmd->list, (&instance->cmd_pool)->next);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	spin_unlock_irqrestore(&instance->mfi_pool_lock, flags);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_cistatic const char *
37862306a36Sopenharmony_ciformat_timestamp(uint32_t timestamp)
37962306a36Sopenharmony_ci{
38062306a36Sopenharmony_ci	static char buffer[32];
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	if ((timestamp & 0xff000000) == 0xff000000)
38362306a36Sopenharmony_ci		snprintf(buffer, sizeof(buffer), "boot + %us", timestamp &
38462306a36Sopenharmony_ci		0x00ffffff);
38562306a36Sopenharmony_ci	else
38662306a36Sopenharmony_ci		snprintf(buffer, sizeof(buffer), "%us", timestamp);
38762306a36Sopenharmony_ci	return buffer;
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_cistatic const char *
39162306a36Sopenharmony_ciformat_class(int8_t class)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	static char buffer[6];
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	switch (class) {
39662306a36Sopenharmony_ci	case MFI_EVT_CLASS_DEBUG:
39762306a36Sopenharmony_ci		return "debug";
39862306a36Sopenharmony_ci	case MFI_EVT_CLASS_PROGRESS:
39962306a36Sopenharmony_ci		return "progress";
40062306a36Sopenharmony_ci	case MFI_EVT_CLASS_INFO:
40162306a36Sopenharmony_ci		return "info";
40262306a36Sopenharmony_ci	case MFI_EVT_CLASS_WARNING:
40362306a36Sopenharmony_ci		return "WARN";
40462306a36Sopenharmony_ci	case MFI_EVT_CLASS_CRITICAL:
40562306a36Sopenharmony_ci		return "CRIT";
40662306a36Sopenharmony_ci	case MFI_EVT_CLASS_FATAL:
40762306a36Sopenharmony_ci		return "FATAL";
40862306a36Sopenharmony_ci	case MFI_EVT_CLASS_DEAD:
40962306a36Sopenharmony_ci		return "DEAD";
41062306a36Sopenharmony_ci	default:
41162306a36Sopenharmony_ci		snprintf(buffer, sizeof(buffer), "%d", class);
41262306a36Sopenharmony_ci		return buffer;
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci/**
41762306a36Sopenharmony_ci  * megasas_decode_evt: Decode FW AEN event and print critical event
41862306a36Sopenharmony_ci  * for information.
41962306a36Sopenharmony_ci  * @instance:			Adapter soft state
42062306a36Sopenharmony_ci  */
42162306a36Sopenharmony_cistatic void
42262306a36Sopenharmony_cimegasas_decode_evt(struct megasas_instance *instance)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	struct megasas_evt_detail *evt_detail = instance->evt_detail;
42562306a36Sopenharmony_ci	union megasas_evt_class_locale class_locale;
42662306a36Sopenharmony_ci	class_locale.word = le32_to_cpu(evt_detail->cl.word);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	if ((event_log_level < MFI_EVT_CLASS_DEBUG) ||
42962306a36Sopenharmony_ci	    (event_log_level > MFI_EVT_CLASS_DEAD)) {
43062306a36Sopenharmony_ci		printk(KERN_WARNING "megaraid_sas: provided event log level is out of range, setting it to default 2(CLASS_CRITICAL), permissible range is: -2 to 4\n");
43162306a36Sopenharmony_ci		event_log_level = MFI_EVT_CLASS_CRITICAL;
43262306a36Sopenharmony_ci	}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	if (class_locale.members.class >= event_log_level)
43562306a36Sopenharmony_ci		dev_info(&instance->pdev->dev, "%d (%s/0x%04x/%s) - %s\n",
43662306a36Sopenharmony_ci			le32_to_cpu(evt_detail->seq_num),
43762306a36Sopenharmony_ci			format_timestamp(le32_to_cpu(evt_detail->time_stamp)),
43862306a36Sopenharmony_ci			(class_locale.members.locale),
43962306a36Sopenharmony_ci			format_class(class_locale.members.class),
44062306a36Sopenharmony_ci			evt_detail->description);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	if (megasas_dbg_lvl & LD_PD_DEBUG)
44362306a36Sopenharmony_ci		dev_info(&instance->pdev->dev,
44462306a36Sopenharmony_ci			 "evt_detail.args.ld.target_id/index %d/%d\n",
44562306a36Sopenharmony_ci			 evt_detail->args.ld.target_id, evt_detail->args.ld.ld_index);
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci/*
45062306a36Sopenharmony_ci * The following functions are defined for xscale
45162306a36Sopenharmony_ci * (deviceid : 1064R, PERC5) controllers
45262306a36Sopenharmony_ci */
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci/**
45562306a36Sopenharmony_ci * megasas_enable_intr_xscale -	Enables interrupts
45662306a36Sopenharmony_ci * @instance:	Adapter soft state
45762306a36Sopenharmony_ci */
45862306a36Sopenharmony_cistatic inline void
45962306a36Sopenharmony_cimegasas_enable_intr_xscale(struct megasas_instance *instance)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	struct megasas_register_set __iomem *regs;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	regs = instance->reg_set;
46462306a36Sopenharmony_ci	writel(0, &(regs)->outbound_intr_mask);
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	/* Dummy readl to force pci flush */
46762306a36Sopenharmony_ci	readl(&regs->outbound_intr_mask);
46862306a36Sopenharmony_ci}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci/**
47162306a36Sopenharmony_ci * megasas_disable_intr_xscale -Disables interrupt
47262306a36Sopenharmony_ci * @instance:	Adapter soft state
47362306a36Sopenharmony_ci */
47462306a36Sopenharmony_cistatic inline void
47562306a36Sopenharmony_cimegasas_disable_intr_xscale(struct megasas_instance *instance)
47662306a36Sopenharmony_ci{
47762306a36Sopenharmony_ci	struct megasas_register_set __iomem *regs;
47862306a36Sopenharmony_ci	u32 mask = 0x1f;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	regs = instance->reg_set;
48162306a36Sopenharmony_ci	writel(mask, &regs->outbound_intr_mask);
48262306a36Sopenharmony_ci	/* Dummy readl to force pci flush */
48362306a36Sopenharmony_ci	readl(&regs->outbound_intr_mask);
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci/**
48762306a36Sopenharmony_ci * megasas_read_fw_status_reg_xscale - returns the current FW status value
48862306a36Sopenharmony_ci * @instance:	Adapter soft state
48962306a36Sopenharmony_ci */
49062306a36Sopenharmony_cistatic u32
49162306a36Sopenharmony_cimegasas_read_fw_status_reg_xscale(struct megasas_instance *instance)
49262306a36Sopenharmony_ci{
49362306a36Sopenharmony_ci	return readl(&instance->reg_set->outbound_msg_0);
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci/**
49662306a36Sopenharmony_ci * megasas_clear_intr_xscale -	Check & clear interrupt
49762306a36Sopenharmony_ci * @instance:	Adapter soft state
49862306a36Sopenharmony_ci */
49962306a36Sopenharmony_cistatic int
50062306a36Sopenharmony_cimegasas_clear_intr_xscale(struct megasas_instance *instance)
50162306a36Sopenharmony_ci{
50262306a36Sopenharmony_ci	u32 status;
50362306a36Sopenharmony_ci	u32 mfiStatus = 0;
50462306a36Sopenharmony_ci	struct megasas_register_set __iomem *regs;
50562306a36Sopenharmony_ci	regs = instance->reg_set;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	/*
50862306a36Sopenharmony_ci	 * Check if it is our interrupt
50962306a36Sopenharmony_ci	 */
51062306a36Sopenharmony_ci	status = readl(&regs->outbound_intr_status);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	if (status & MFI_OB_INTR_STATUS_MASK)
51362306a36Sopenharmony_ci		mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE;
51462306a36Sopenharmony_ci	if (status & MFI_XSCALE_OMR0_CHANGE_INTERRUPT)
51562306a36Sopenharmony_ci		mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	/*
51862306a36Sopenharmony_ci	 * Clear the interrupt by writing back the same value
51962306a36Sopenharmony_ci	 */
52062306a36Sopenharmony_ci	if (mfiStatus)
52162306a36Sopenharmony_ci		writel(status, &regs->outbound_intr_status);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	/* Dummy readl to force pci flush */
52462306a36Sopenharmony_ci	readl(&regs->outbound_intr_status);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	return mfiStatus;
52762306a36Sopenharmony_ci}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci/**
53062306a36Sopenharmony_ci * megasas_fire_cmd_xscale -	Sends command to the FW
53162306a36Sopenharmony_ci * @instance:		Adapter soft state
53262306a36Sopenharmony_ci * @frame_phys_addr :	Physical address of cmd
53362306a36Sopenharmony_ci * @frame_count :	Number of frames for the command
53462306a36Sopenharmony_ci * @regs :		MFI register set
53562306a36Sopenharmony_ci */
53662306a36Sopenharmony_cistatic inline void
53762306a36Sopenharmony_cimegasas_fire_cmd_xscale(struct megasas_instance *instance,
53862306a36Sopenharmony_ci		dma_addr_t frame_phys_addr,
53962306a36Sopenharmony_ci		u32 frame_count,
54062306a36Sopenharmony_ci		struct megasas_register_set __iomem *regs)
54162306a36Sopenharmony_ci{
54262306a36Sopenharmony_ci	unsigned long flags;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	spin_lock_irqsave(&instance->hba_lock, flags);
54562306a36Sopenharmony_ci	writel((frame_phys_addr >> 3)|(frame_count),
54662306a36Sopenharmony_ci	       &(regs)->inbound_queue_port);
54762306a36Sopenharmony_ci	spin_unlock_irqrestore(&instance->hba_lock, flags);
54862306a36Sopenharmony_ci}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci/**
55162306a36Sopenharmony_ci * megasas_adp_reset_xscale -  For controller reset
55262306a36Sopenharmony_ci * @instance:	Adapter soft state
55362306a36Sopenharmony_ci * @regs:	MFI register set
55462306a36Sopenharmony_ci */
55562306a36Sopenharmony_cistatic int
55662306a36Sopenharmony_cimegasas_adp_reset_xscale(struct megasas_instance *instance,
55762306a36Sopenharmony_ci	struct megasas_register_set __iomem *regs)
55862306a36Sopenharmony_ci{
55962306a36Sopenharmony_ci	u32 i;
56062306a36Sopenharmony_ci	u32 pcidata;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	writel(MFI_ADP_RESET, &regs->inbound_doorbell);
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	for (i = 0; i < 3; i++)
56562306a36Sopenharmony_ci		msleep(1000); /* sleep for 3 secs */
56662306a36Sopenharmony_ci	pcidata  = 0;
56762306a36Sopenharmony_ci	pci_read_config_dword(instance->pdev, MFI_1068_PCSR_OFFSET, &pcidata);
56862306a36Sopenharmony_ci	dev_notice(&instance->pdev->dev, "pcidata = %x\n", pcidata);
56962306a36Sopenharmony_ci	if (pcidata & 0x2) {
57062306a36Sopenharmony_ci		dev_notice(&instance->pdev->dev, "mfi 1068 offset read=%x\n", pcidata);
57162306a36Sopenharmony_ci		pcidata &= ~0x2;
57262306a36Sopenharmony_ci		pci_write_config_dword(instance->pdev,
57362306a36Sopenharmony_ci				MFI_1068_PCSR_OFFSET, pcidata);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci		for (i = 0; i < 2; i++)
57662306a36Sopenharmony_ci			msleep(1000); /* need to wait 2 secs again */
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci		pcidata  = 0;
57962306a36Sopenharmony_ci		pci_read_config_dword(instance->pdev,
58062306a36Sopenharmony_ci				MFI_1068_FW_HANDSHAKE_OFFSET, &pcidata);
58162306a36Sopenharmony_ci		dev_notice(&instance->pdev->dev, "1068 offset handshake read=%x\n", pcidata);
58262306a36Sopenharmony_ci		if ((pcidata & 0xffff0000) == MFI_1068_FW_READY) {
58362306a36Sopenharmony_ci			dev_notice(&instance->pdev->dev, "1068 offset pcidt=%x\n", pcidata);
58462306a36Sopenharmony_ci			pcidata = 0;
58562306a36Sopenharmony_ci			pci_write_config_dword(instance->pdev,
58662306a36Sopenharmony_ci				MFI_1068_FW_HANDSHAKE_OFFSET, pcidata);
58762306a36Sopenharmony_ci		}
58862306a36Sopenharmony_ci	}
58962306a36Sopenharmony_ci	return 0;
59062306a36Sopenharmony_ci}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci/**
59362306a36Sopenharmony_ci * megasas_check_reset_xscale -	For controller reset check
59462306a36Sopenharmony_ci * @instance:	Adapter soft state
59562306a36Sopenharmony_ci * @regs:	MFI register set
59662306a36Sopenharmony_ci */
59762306a36Sopenharmony_cistatic int
59862306a36Sopenharmony_cimegasas_check_reset_xscale(struct megasas_instance *instance,
59962306a36Sopenharmony_ci		struct megasas_register_set __iomem *regs)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	if ((atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) &&
60262306a36Sopenharmony_ci	    (le32_to_cpu(*instance->consumer) ==
60362306a36Sopenharmony_ci		MEGASAS_ADPRESET_INPROG_SIGN))
60462306a36Sopenharmony_ci		return 1;
60562306a36Sopenharmony_ci	return 0;
60662306a36Sopenharmony_ci}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_cistatic struct megasas_instance_template megasas_instance_template_xscale = {
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	.fire_cmd = megasas_fire_cmd_xscale,
61162306a36Sopenharmony_ci	.enable_intr = megasas_enable_intr_xscale,
61262306a36Sopenharmony_ci	.disable_intr = megasas_disable_intr_xscale,
61362306a36Sopenharmony_ci	.clear_intr = megasas_clear_intr_xscale,
61462306a36Sopenharmony_ci	.read_fw_status_reg = megasas_read_fw_status_reg_xscale,
61562306a36Sopenharmony_ci	.adp_reset = megasas_adp_reset_xscale,
61662306a36Sopenharmony_ci	.check_reset = megasas_check_reset_xscale,
61762306a36Sopenharmony_ci	.service_isr = megasas_isr,
61862306a36Sopenharmony_ci	.tasklet = megasas_complete_cmd_dpc,
61962306a36Sopenharmony_ci	.init_adapter = megasas_init_adapter_mfi,
62062306a36Sopenharmony_ci	.build_and_issue_cmd = megasas_build_and_issue_cmd,
62162306a36Sopenharmony_ci	.issue_dcmd = megasas_issue_dcmd,
62262306a36Sopenharmony_ci};
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci/*
62562306a36Sopenharmony_ci * This is the end of set of functions & definitions specific
62662306a36Sopenharmony_ci * to xscale (deviceid : 1064R, PERC5) controllers
62762306a36Sopenharmony_ci */
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci/*
63062306a36Sopenharmony_ci * The following functions are defined for ppc (deviceid : 0x60)
63162306a36Sopenharmony_ci * controllers
63262306a36Sopenharmony_ci */
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci/**
63562306a36Sopenharmony_ci * megasas_enable_intr_ppc -	Enables interrupts
63662306a36Sopenharmony_ci * @instance:	Adapter soft state
63762306a36Sopenharmony_ci */
63862306a36Sopenharmony_cistatic inline void
63962306a36Sopenharmony_cimegasas_enable_intr_ppc(struct megasas_instance *instance)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	struct megasas_register_set __iomem *regs;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	regs = instance->reg_set;
64462306a36Sopenharmony_ci	writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear);
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	writel(~0x80000000, &(regs)->outbound_intr_mask);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	/* Dummy readl to force pci flush */
64962306a36Sopenharmony_ci	readl(&regs->outbound_intr_mask);
65062306a36Sopenharmony_ci}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci/**
65362306a36Sopenharmony_ci * megasas_disable_intr_ppc -	Disable interrupt
65462306a36Sopenharmony_ci * @instance:	Adapter soft state
65562306a36Sopenharmony_ci */
65662306a36Sopenharmony_cistatic inline void
65762306a36Sopenharmony_cimegasas_disable_intr_ppc(struct megasas_instance *instance)
65862306a36Sopenharmony_ci{
65962306a36Sopenharmony_ci	struct megasas_register_set __iomem *regs;
66062306a36Sopenharmony_ci	u32 mask = 0xFFFFFFFF;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	regs = instance->reg_set;
66362306a36Sopenharmony_ci	writel(mask, &regs->outbound_intr_mask);
66462306a36Sopenharmony_ci	/* Dummy readl to force pci flush */
66562306a36Sopenharmony_ci	readl(&regs->outbound_intr_mask);
66662306a36Sopenharmony_ci}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci/**
66962306a36Sopenharmony_ci * megasas_read_fw_status_reg_ppc - returns the current FW status value
67062306a36Sopenharmony_ci * @instance:	Adapter soft state
67162306a36Sopenharmony_ci */
67262306a36Sopenharmony_cistatic u32
67362306a36Sopenharmony_cimegasas_read_fw_status_reg_ppc(struct megasas_instance *instance)
67462306a36Sopenharmony_ci{
67562306a36Sopenharmony_ci	return readl(&instance->reg_set->outbound_scratch_pad_0);
67662306a36Sopenharmony_ci}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci/**
67962306a36Sopenharmony_ci * megasas_clear_intr_ppc -	Check & clear interrupt
68062306a36Sopenharmony_ci * @instance:	Adapter soft state
68162306a36Sopenharmony_ci */
68262306a36Sopenharmony_cistatic int
68362306a36Sopenharmony_cimegasas_clear_intr_ppc(struct megasas_instance *instance)
68462306a36Sopenharmony_ci{
68562306a36Sopenharmony_ci	u32 status, mfiStatus = 0;
68662306a36Sopenharmony_ci	struct megasas_register_set __iomem *regs;
68762306a36Sopenharmony_ci	regs = instance->reg_set;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	/*
69062306a36Sopenharmony_ci	 * Check if it is our interrupt
69162306a36Sopenharmony_ci	 */
69262306a36Sopenharmony_ci	status = readl(&regs->outbound_intr_status);
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	if (status & MFI_REPLY_1078_MESSAGE_INTERRUPT)
69562306a36Sopenharmony_ci		mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE;
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	if (status & MFI_G2_OUTBOUND_DOORBELL_CHANGE_INTERRUPT)
69862306a36Sopenharmony_ci		mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	/*
70162306a36Sopenharmony_ci	 * Clear the interrupt by writing back the same value
70262306a36Sopenharmony_ci	 */
70362306a36Sopenharmony_ci	writel(status, &regs->outbound_doorbell_clear);
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	/* Dummy readl to force pci flush */
70662306a36Sopenharmony_ci	readl(&regs->outbound_doorbell_clear);
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	return mfiStatus;
70962306a36Sopenharmony_ci}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci/**
71262306a36Sopenharmony_ci * megasas_fire_cmd_ppc -	Sends command to the FW
71362306a36Sopenharmony_ci * @instance:		Adapter soft state
71462306a36Sopenharmony_ci * @frame_phys_addr:	Physical address of cmd
71562306a36Sopenharmony_ci * @frame_count:	Number of frames for the command
71662306a36Sopenharmony_ci * @regs:		MFI register set
71762306a36Sopenharmony_ci */
71862306a36Sopenharmony_cistatic inline void
71962306a36Sopenharmony_cimegasas_fire_cmd_ppc(struct megasas_instance *instance,
72062306a36Sopenharmony_ci		dma_addr_t frame_phys_addr,
72162306a36Sopenharmony_ci		u32 frame_count,
72262306a36Sopenharmony_ci		struct megasas_register_set __iomem *regs)
72362306a36Sopenharmony_ci{
72462306a36Sopenharmony_ci	unsigned long flags;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	spin_lock_irqsave(&instance->hba_lock, flags);
72762306a36Sopenharmony_ci	writel((frame_phys_addr | (frame_count<<1))|1,
72862306a36Sopenharmony_ci			&(regs)->inbound_queue_port);
72962306a36Sopenharmony_ci	spin_unlock_irqrestore(&instance->hba_lock, flags);
73062306a36Sopenharmony_ci}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci/**
73362306a36Sopenharmony_ci * megasas_check_reset_ppc -	For controller reset check
73462306a36Sopenharmony_ci * @instance:	Adapter soft state
73562306a36Sopenharmony_ci * @regs:	MFI register set
73662306a36Sopenharmony_ci */
73762306a36Sopenharmony_cistatic int
73862306a36Sopenharmony_cimegasas_check_reset_ppc(struct megasas_instance *instance,
73962306a36Sopenharmony_ci			struct megasas_register_set __iomem *regs)
74062306a36Sopenharmony_ci{
74162306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
74262306a36Sopenharmony_ci		return 1;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	return 0;
74562306a36Sopenharmony_ci}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_cistatic struct megasas_instance_template megasas_instance_template_ppc = {
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	.fire_cmd = megasas_fire_cmd_ppc,
75062306a36Sopenharmony_ci	.enable_intr = megasas_enable_intr_ppc,
75162306a36Sopenharmony_ci	.disable_intr = megasas_disable_intr_ppc,
75262306a36Sopenharmony_ci	.clear_intr = megasas_clear_intr_ppc,
75362306a36Sopenharmony_ci	.read_fw_status_reg = megasas_read_fw_status_reg_ppc,
75462306a36Sopenharmony_ci	.adp_reset = megasas_adp_reset_xscale,
75562306a36Sopenharmony_ci	.check_reset = megasas_check_reset_ppc,
75662306a36Sopenharmony_ci	.service_isr = megasas_isr,
75762306a36Sopenharmony_ci	.tasklet = megasas_complete_cmd_dpc,
75862306a36Sopenharmony_ci	.init_adapter = megasas_init_adapter_mfi,
75962306a36Sopenharmony_ci	.build_and_issue_cmd = megasas_build_and_issue_cmd,
76062306a36Sopenharmony_ci	.issue_dcmd = megasas_issue_dcmd,
76162306a36Sopenharmony_ci};
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci/**
76462306a36Sopenharmony_ci * megasas_enable_intr_skinny -	Enables interrupts
76562306a36Sopenharmony_ci * @instance:	Adapter soft state
76662306a36Sopenharmony_ci */
76762306a36Sopenharmony_cistatic inline void
76862306a36Sopenharmony_cimegasas_enable_intr_skinny(struct megasas_instance *instance)
76962306a36Sopenharmony_ci{
77062306a36Sopenharmony_ci	struct megasas_register_set __iomem *regs;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	regs = instance->reg_set;
77362306a36Sopenharmony_ci	writel(0xFFFFFFFF, &(regs)->outbound_intr_mask);
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	writel(~MFI_SKINNY_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask);
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	/* Dummy readl to force pci flush */
77862306a36Sopenharmony_ci	readl(&regs->outbound_intr_mask);
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci/**
78262306a36Sopenharmony_ci * megasas_disable_intr_skinny -	Disables interrupt
78362306a36Sopenharmony_ci * @instance:	Adapter soft state
78462306a36Sopenharmony_ci */
78562306a36Sopenharmony_cistatic inline void
78662306a36Sopenharmony_cimegasas_disable_intr_skinny(struct megasas_instance *instance)
78762306a36Sopenharmony_ci{
78862306a36Sopenharmony_ci	struct megasas_register_set __iomem *regs;
78962306a36Sopenharmony_ci	u32 mask = 0xFFFFFFFF;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	regs = instance->reg_set;
79262306a36Sopenharmony_ci	writel(mask, &regs->outbound_intr_mask);
79362306a36Sopenharmony_ci	/* Dummy readl to force pci flush */
79462306a36Sopenharmony_ci	readl(&regs->outbound_intr_mask);
79562306a36Sopenharmony_ci}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci/**
79862306a36Sopenharmony_ci * megasas_read_fw_status_reg_skinny - returns the current FW status value
79962306a36Sopenharmony_ci * @instance:	Adapter soft state
80062306a36Sopenharmony_ci */
80162306a36Sopenharmony_cistatic u32
80262306a36Sopenharmony_cimegasas_read_fw_status_reg_skinny(struct megasas_instance *instance)
80362306a36Sopenharmony_ci{
80462306a36Sopenharmony_ci	return readl(&instance->reg_set->outbound_scratch_pad_0);
80562306a36Sopenharmony_ci}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci/**
80862306a36Sopenharmony_ci * megasas_clear_intr_skinny -	Check & clear interrupt
80962306a36Sopenharmony_ci * @instance:	Adapter soft state
81062306a36Sopenharmony_ci */
81162306a36Sopenharmony_cistatic int
81262306a36Sopenharmony_cimegasas_clear_intr_skinny(struct megasas_instance *instance)
81362306a36Sopenharmony_ci{
81462306a36Sopenharmony_ci	u32 status;
81562306a36Sopenharmony_ci	u32 mfiStatus = 0;
81662306a36Sopenharmony_ci	struct megasas_register_set __iomem *regs;
81762306a36Sopenharmony_ci	regs = instance->reg_set;
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	/*
82062306a36Sopenharmony_ci	 * Check if it is our interrupt
82162306a36Sopenharmony_ci	 */
82262306a36Sopenharmony_ci	status = readl(&regs->outbound_intr_status);
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	if (!(status & MFI_SKINNY_ENABLE_INTERRUPT_MASK)) {
82562306a36Sopenharmony_ci		return 0;
82662306a36Sopenharmony_ci	}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	/*
82962306a36Sopenharmony_ci	 * Check if it is our interrupt
83062306a36Sopenharmony_ci	 */
83162306a36Sopenharmony_ci	if ((megasas_read_fw_status_reg_skinny(instance) & MFI_STATE_MASK) ==
83262306a36Sopenharmony_ci	    MFI_STATE_FAULT) {
83362306a36Sopenharmony_ci		mfiStatus = MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE;
83462306a36Sopenharmony_ci	} else
83562306a36Sopenharmony_ci		mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE;
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	/*
83862306a36Sopenharmony_ci	 * Clear the interrupt by writing back the same value
83962306a36Sopenharmony_ci	 */
84062306a36Sopenharmony_ci	writel(status, &regs->outbound_intr_status);
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	/*
84362306a36Sopenharmony_ci	 * dummy read to flush PCI
84462306a36Sopenharmony_ci	 */
84562306a36Sopenharmony_ci	readl(&regs->outbound_intr_status);
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	return mfiStatus;
84862306a36Sopenharmony_ci}
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci/**
85162306a36Sopenharmony_ci * megasas_fire_cmd_skinny -	Sends command to the FW
85262306a36Sopenharmony_ci * @instance:		Adapter soft state
85362306a36Sopenharmony_ci * @frame_phys_addr:	Physical address of cmd
85462306a36Sopenharmony_ci * @frame_count:	Number of frames for the command
85562306a36Sopenharmony_ci * @regs:		MFI register set
85662306a36Sopenharmony_ci */
85762306a36Sopenharmony_cistatic inline void
85862306a36Sopenharmony_cimegasas_fire_cmd_skinny(struct megasas_instance *instance,
85962306a36Sopenharmony_ci			dma_addr_t frame_phys_addr,
86062306a36Sopenharmony_ci			u32 frame_count,
86162306a36Sopenharmony_ci			struct megasas_register_set __iomem *regs)
86262306a36Sopenharmony_ci{
86362306a36Sopenharmony_ci	unsigned long flags;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	spin_lock_irqsave(&instance->hba_lock, flags);
86662306a36Sopenharmony_ci	writel(upper_32_bits(frame_phys_addr),
86762306a36Sopenharmony_ci	       &(regs)->inbound_high_queue_port);
86862306a36Sopenharmony_ci	writel((lower_32_bits(frame_phys_addr) | (frame_count<<1))|1,
86962306a36Sopenharmony_ci	       &(regs)->inbound_low_queue_port);
87062306a36Sopenharmony_ci	spin_unlock_irqrestore(&instance->hba_lock, flags);
87162306a36Sopenharmony_ci}
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci/**
87462306a36Sopenharmony_ci * megasas_check_reset_skinny -	For controller reset check
87562306a36Sopenharmony_ci * @instance:	Adapter soft state
87662306a36Sopenharmony_ci * @regs:	MFI register set
87762306a36Sopenharmony_ci */
87862306a36Sopenharmony_cistatic int
87962306a36Sopenharmony_cimegasas_check_reset_skinny(struct megasas_instance *instance,
88062306a36Sopenharmony_ci				struct megasas_register_set __iomem *regs)
88162306a36Sopenharmony_ci{
88262306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
88362306a36Sopenharmony_ci		return 1;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	return 0;
88662306a36Sopenharmony_ci}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_cistatic struct megasas_instance_template megasas_instance_template_skinny = {
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	.fire_cmd = megasas_fire_cmd_skinny,
89162306a36Sopenharmony_ci	.enable_intr = megasas_enable_intr_skinny,
89262306a36Sopenharmony_ci	.disable_intr = megasas_disable_intr_skinny,
89362306a36Sopenharmony_ci	.clear_intr = megasas_clear_intr_skinny,
89462306a36Sopenharmony_ci	.read_fw_status_reg = megasas_read_fw_status_reg_skinny,
89562306a36Sopenharmony_ci	.adp_reset = megasas_adp_reset_gen2,
89662306a36Sopenharmony_ci	.check_reset = megasas_check_reset_skinny,
89762306a36Sopenharmony_ci	.service_isr = megasas_isr,
89862306a36Sopenharmony_ci	.tasklet = megasas_complete_cmd_dpc,
89962306a36Sopenharmony_ci	.init_adapter = megasas_init_adapter_mfi,
90062306a36Sopenharmony_ci	.build_and_issue_cmd = megasas_build_and_issue_cmd,
90162306a36Sopenharmony_ci	.issue_dcmd = megasas_issue_dcmd,
90262306a36Sopenharmony_ci};
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci/*
90662306a36Sopenharmony_ci * The following functions are defined for gen2 (deviceid : 0x78 0x79)
90762306a36Sopenharmony_ci * controllers
90862306a36Sopenharmony_ci */
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci/**
91162306a36Sopenharmony_ci * megasas_enable_intr_gen2 -  Enables interrupts
91262306a36Sopenharmony_ci * @instance:	Adapter soft state
91362306a36Sopenharmony_ci */
91462306a36Sopenharmony_cistatic inline void
91562306a36Sopenharmony_cimegasas_enable_intr_gen2(struct megasas_instance *instance)
91662306a36Sopenharmony_ci{
91762306a36Sopenharmony_ci	struct megasas_register_set __iomem *regs;
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	regs = instance->reg_set;
92062306a36Sopenharmony_ci	writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear);
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	/* write ~0x00000005 (4 & 1) to the intr mask*/
92362306a36Sopenharmony_ci	writel(~MFI_GEN2_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask);
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	/* Dummy readl to force pci flush */
92662306a36Sopenharmony_ci	readl(&regs->outbound_intr_mask);
92762306a36Sopenharmony_ci}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci/**
93062306a36Sopenharmony_ci * megasas_disable_intr_gen2 - Disables interrupt
93162306a36Sopenharmony_ci * @instance:	Adapter soft state
93262306a36Sopenharmony_ci */
93362306a36Sopenharmony_cistatic inline void
93462306a36Sopenharmony_cimegasas_disable_intr_gen2(struct megasas_instance *instance)
93562306a36Sopenharmony_ci{
93662306a36Sopenharmony_ci	struct megasas_register_set __iomem *regs;
93762306a36Sopenharmony_ci	u32 mask = 0xFFFFFFFF;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	regs = instance->reg_set;
94062306a36Sopenharmony_ci	writel(mask, &regs->outbound_intr_mask);
94162306a36Sopenharmony_ci	/* Dummy readl to force pci flush */
94262306a36Sopenharmony_ci	readl(&regs->outbound_intr_mask);
94362306a36Sopenharmony_ci}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci/**
94662306a36Sopenharmony_ci * megasas_read_fw_status_reg_gen2 - returns the current FW status value
94762306a36Sopenharmony_ci * @instance:	Adapter soft state
94862306a36Sopenharmony_ci */
94962306a36Sopenharmony_cistatic u32
95062306a36Sopenharmony_cimegasas_read_fw_status_reg_gen2(struct megasas_instance *instance)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	return readl(&instance->reg_set->outbound_scratch_pad_0);
95362306a36Sopenharmony_ci}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci/**
95662306a36Sopenharmony_ci * megasas_clear_intr_gen2 -      Check & clear interrupt
95762306a36Sopenharmony_ci * @instance:	Adapter soft state
95862306a36Sopenharmony_ci */
95962306a36Sopenharmony_cistatic int
96062306a36Sopenharmony_cimegasas_clear_intr_gen2(struct megasas_instance *instance)
96162306a36Sopenharmony_ci{
96262306a36Sopenharmony_ci	u32 status;
96362306a36Sopenharmony_ci	u32 mfiStatus = 0;
96462306a36Sopenharmony_ci	struct megasas_register_set __iomem *regs;
96562306a36Sopenharmony_ci	regs = instance->reg_set;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	/*
96862306a36Sopenharmony_ci	 * Check if it is our interrupt
96962306a36Sopenharmony_ci	 */
97062306a36Sopenharmony_ci	status = readl(&regs->outbound_intr_status);
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	if (status & MFI_INTR_FLAG_REPLY_MESSAGE) {
97362306a36Sopenharmony_ci		mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE;
97462306a36Sopenharmony_ci	}
97562306a36Sopenharmony_ci	if (status & MFI_G2_OUTBOUND_DOORBELL_CHANGE_INTERRUPT) {
97662306a36Sopenharmony_ci		mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE;
97762306a36Sopenharmony_ci	}
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	/*
98062306a36Sopenharmony_ci	 * Clear the interrupt by writing back the same value
98162306a36Sopenharmony_ci	 */
98262306a36Sopenharmony_ci	if (mfiStatus)
98362306a36Sopenharmony_ci		writel(status, &regs->outbound_doorbell_clear);
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	/* Dummy readl to force pci flush */
98662306a36Sopenharmony_ci	readl(&regs->outbound_intr_status);
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	return mfiStatus;
98962306a36Sopenharmony_ci}
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci/**
99262306a36Sopenharmony_ci * megasas_fire_cmd_gen2 -     Sends command to the FW
99362306a36Sopenharmony_ci * @instance:		Adapter soft state
99462306a36Sopenharmony_ci * @frame_phys_addr:	Physical address of cmd
99562306a36Sopenharmony_ci * @frame_count:	Number of frames for the command
99662306a36Sopenharmony_ci * @regs:		MFI register set
99762306a36Sopenharmony_ci */
99862306a36Sopenharmony_cistatic inline void
99962306a36Sopenharmony_cimegasas_fire_cmd_gen2(struct megasas_instance *instance,
100062306a36Sopenharmony_ci			dma_addr_t frame_phys_addr,
100162306a36Sopenharmony_ci			u32 frame_count,
100262306a36Sopenharmony_ci			struct megasas_register_set __iomem *regs)
100362306a36Sopenharmony_ci{
100462306a36Sopenharmony_ci	unsigned long flags;
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	spin_lock_irqsave(&instance->hba_lock, flags);
100762306a36Sopenharmony_ci	writel((frame_phys_addr | (frame_count<<1))|1,
100862306a36Sopenharmony_ci			&(regs)->inbound_queue_port);
100962306a36Sopenharmony_ci	spin_unlock_irqrestore(&instance->hba_lock, flags);
101062306a36Sopenharmony_ci}
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci/**
101362306a36Sopenharmony_ci * megasas_adp_reset_gen2 -	For controller reset
101462306a36Sopenharmony_ci * @instance:	Adapter soft state
101562306a36Sopenharmony_ci * @reg_set:	MFI register set
101662306a36Sopenharmony_ci */
101762306a36Sopenharmony_cistatic int
101862306a36Sopenharmony_cimegasas_adp_reset_gen2(struct megasas_instance *instance,
101962306a36Sopenharmony_ci			struct megasas_register_set __iomem *reg_set)
102062306a36Sopenharmony_ci{
102162306a36Sopenharmony_ci	u32 retry = 0 ;
102262306a36Sopenharmony_ci	u32 HostDiag;
102362306a36Sopenharmony_ci	u32 __iomem *seq_offset = &reg_set->seq_offset;
102462306a36Sopenharmony_ci	u32 __iomem *hostdiag_offset = &reg_set->host_diag;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	if (instance->instancet == &megasas_instance_template_skinny) {
102762306a36Sopenharmony_ci		seq_offset = &reg_set->fusion_seq_offset;
102862306a36Sopenharmony_ci		hostdiag_offset = &reg_set->fusion_host_diag;
102962306a36Sopenharmony_ci	}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	writel(0, seq_offset);
103262306a36Sopenharmony_ci	writel(4, seq_offset);
103362306a36Sopenharmony_ci	writel(0xb, seq_offset);
103462306a36Sopenharmony_ci	writel(2, seq_offset);
103562306a36Sopenharmony_ci	writel(7, seq_offset);
103662306a36Sopenharmony_ci	writel(0xd, seq_offset);
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	msleep(1000);
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	HostDiag = (u32)readl(hostdiag_offset);
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	while (!(HostDiag & DIAG_WRITE_ENABLE)) {
104362306a36Sopenharmony_ci		msleep(100);
104462306a36Sopenharmony_ci		HostDiag = (u32)readl(hostdiag_offset);
104562306a36Sopenharmony_ci		dev_notice(&instance->pdev->dev, "RESETGEN2: retry=%x, hostdiag=%x\n",
104662306a36Sopenharmony_ci					retry, HostDiag);
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci		if (retry++ >= 100)
104962306a36Sopenharmony_ci			return 1;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	dev_notice(&instance->pdev->dev, "ADP_RESET_GEN2: HostDiag=%x\n", HostDiag);
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	writel((HostDiag | DIAG_RESET_ADAPTER), hostdiag_offset);
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	ssleep(10);
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	HostDiag = (u32)readl(hostdiag_offset);
106062306a36Sopenharmony_ci	while (HostDiag & DIAG_RESET_ADAPTER) {
106162306a36Sopenharmony_ci		msleep(100);
106262306a36Sopenharmony_ci		HostDiag = (u32)readl(hostdiag_offset);
106362306a36Sopenharmony_ci		dev_notice(&instance->pdev->dev, "RESET_GEN2: retry=%x, hostdiag=%x\n",
106462306a36Sopenharmony_ci				retry, HostDiag);
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci		if (retry++ >= 1000)
106762306a36Sopenharmony_ci			return 1;
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	}
107062306a36Sopenharmony_ci	return 0;
107162306a36Sopenharmony_ci}
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci/**
107462306a36Sopenharmony_ci * megasas_check_reset_gen2 -	For controller reset check
107562306a36Sopenharmony_ci * @instance:	Adapter soft state
107662306a36Sopenharmony_ci * @regs:	MFI register set
107762306a36Sopenharmony_ci */
107862306a36Sopenharmony_cistatic int
107962306a36Sopenharmony_cimegasas_check_reset_gen2(struct megasas_instance *instance,
108062306a36Sopenharmony_ci		struct megasas_register_set __iomem *regs)
108162306a36Sopenharmony_ci{
108262306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
108362306a36Sopenharmony_ci		return 1;
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	return 0;
108662306a36Sopenharmony_ci}
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_cistatic struct megasas_instance_template megasas_instance_template_gen2 = {
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	.fire_cmd = megasas_fire_cmd_gen2,
109162306a36Sopenharmony_ci	.enable_intr = megasas_enable_intr_gen2,
109262306a36Sopenharmony_ci	.disable_intr = megasas_disable_intr_gen2,
109362306a36Sopenharmony_ci	.clear_intr = megasas_clear_intr_gen2,
109462306a36Sopenharmony_ci	.read_fw_status_reg = megasas_read_fw_status_reg_gen2,
109562306a36Sopenharmony_ci	.adp_reset = megasas_adp_reset_gen2,
109662306a36Sopenharmony_ci	.check_reset = megasas_check_reset_gen2,
109762306a36Sopenharmony_ci	.service_isr = megasas_isr,
109862306a36Sopenharmony_ci	.tasklet = megasas_complete_cmd_dpc,
109962306a36Sopenharmony_ci	.init_adapter = megasas_init_adapter_mfi,
110062306a36Sopenharmony_ci	.build_and_issue_cmd = megasas_build_and_issue_cmd,
110162306a36Sopenharmony_ci	.issue_dcmd = megasas_issue_dcmd,
110262306a36Sopenharmony_ci};
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci/*
110562306a36Sopenharmony_ci * This is the end of set of functions & definitions
110662306a36Sopenharmony_ci * specific to gen2 (deviceid : 0x78, 0x79) controllers
110762306a36Sopenharmony_ci */
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci/*
111062306a36Sopenharmony_ci * Template added for TB (Fusion)
111162306a36Sopenharmony_ci */
111262306a36Sopenharmony_ciextern struct megasas_instance_template megasas_instance_template_fusion;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci/**
111562306a36Sopenharmony_ci * megasas_issue_polled -	Issues a polling command
111662306a36Sopenharmony_ci * @instance:			Adapter soft state
111762306a36Sopenharmony_ci * @cmd:			Command packet to be issued
111862306a36Sopenharmony_ci *
111962306a36Sopenharmony_ci * For polling, MFI requires the cmd_status to be set to MFI_STAT_INVALID_STATUS before posting.
112062306a36Sopenharmony_ci */
112162306a36Sopenharmony_ciint
112262306a36Sopenharmony_cimegasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
112362306a36Sopenharmony_ci{
112462306a36Sopenharmony_ci	struct megasas_header *frame_hdr = &cmd->frame->hdr;
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	frame_hdr->cmd_status = MFI_STAT_INVALID_STATUS;
112762306a36Sopenharmony_ci	frame_hdr->flags |= cpu_to_le16(MFI_FRAME_DONT_POST_IN_REPLY_QUEUE);
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
113062306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
113162306a36Sopenharmony_ci			__func__, __LINE__);
113262306a36Sopenharmony_ci		return DCMD_INIT;
113362306a36Sopenharmony_ci	}
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	instance->instancet->issue_dcmd(instance, cmd);
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	return wait_and_poll(instance, cmd, instance->requestorId ?
113862306a36Sopenharmony_ci			MEGASAS_ROUTINE_WAIT_TIME_VF : MFI_IO_TIMEOUT_SECS);
113962306a36Sopenharmony_ci}
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci/**
114262306a36Sopenharmony_ci * megasas_issue_blocked_cmd -	Synchronous wrapper around regular FW cmds
114362306a36Sopenharmony_ci * @instance:			Adapter soft state
114462306a36Sopenharmony_ci * @cmd:			Command to be issued
114562306a36Sopenharmony_ci * @timeout:			Timeout in seconds
114662306a36Sopenharmony_ci *
114762306a36Sopenharmony_ci * This function waits on an event for the command to be returned from ISR.
114862306a36Sopenharmony_ci * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
114962306a36Sopenharmony_ci * Used to issue ioctl commands.
115062306a36Sopenharmony_ci */
115162306a36Sopenharmony_ciint
115262306a36Sopenharmony_cimegasas_issue_blocked_cmd(struct megasas_instance *instance,
115362306a36Sopenharmony_ci			  struct megasas_cmd *cmd, int timeout)
115462306a36Sopenharmony_ci{
115562306a36Sopenharmony_ci	int ret = 0;
115662306a36Sopenharmony_ci	cmd->cmd_status_drv = DCMD_INIT;
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
115962306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
116062306a36Sopenharmony_ci			__func__, __LINE__);
116162306a36Sopenharmony_ci		return DCMD_INIT;
116262306a36Sopenharmony_ci	}
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	instance->instancet->issue_dcmd(instance, cmd);
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	if (timeout) {
116762306a36Sopenharmony_ci		ret = wait_event_timeout(instance->int_cmd_wait_q,
116862306a36Sopenharmony_ci		cmd->cmd_status_drv != DCMD_INIT, timeout * HZ);
116962306a36Sopenharmony_ci		if (!ret) {
117062306a36Sopenharmony_ci			dev_err(&instance->pdev->dev,
117162306a36Sopenharmony_ci				"DCMD(opcode: 0x%x) is timed out, func:%s\n",
117262306a36Sopenharmony_ci				cmd->frame->dcmd.opcode, __func__);
117362306a36Sopenharmony_ci			return DCMD_TIMEOUT;
117462306a36Sopenharmony_ci		}
117562306a36Sopenharmony_ci	} else
117662306a36Sopenharmony_ci		wait_event(instance->int_cmd_wait_q,
117762306a36Sopenharmony_ci				cmd->cmd_status_drv != DCMD_INIT);
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	return cmd->cmd_status_drv;
118062306a36Sopenharmony_ci}
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci/**
118362306a36Sopenharmony_ci * megasas_issue_blocked_abort_cmd -	Aborts previously issued cmd
118462306a36Sopenharmony_ci * @instance:				Adapter soft state
118562306a36Sopenharmony_ci * @cmd_to_abort:			Previously issued cmd to be aborted
118662306a36Sopenharmony_ci * @timeout:				Timeout in seconds
118762306a36Sopenharmony_ci *
118862306a36Sopenharmony_ci * MFI firmware can abort previously issued AEN comamnd (automatic event
118962306a36Sopenharmony_ci * notification). The megasas_issue_blocked_abort_cmd() issues such abort
119062306a36Sopenharmony_ci * cmd and waits for return status.
119162306a36Sopenharmony_ci * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
119262306a36Sopenharmony_ci */
119362306a36Sopenharmony_cistatic int
119462306a36Sopenharmony_cimegasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
119562306a36Sopenharmony_ci				struct megasas_cmd *cmd_to_abort, int timeout)
119662306a36Sopenharmony_ci{
119762306a36Sopenharmony_ci	struct megasas_cmd *cmd;
119862306a36Sopenharmony_ci	struct megasas_abort_frame *abort_fr;
119962306a36Sopenharmony_ci	int ret = 0;
120062306a36Sopenharmony_ci	u32 opcode;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	cmd = megasas_get_cmd(instance);
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	if (!cmd)
120562306a36Sopenharmony_ci		return -1;
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	abort_fr = &cmd->frame->abort;
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	/*
121062306a36Sopenharmony_ci	 * Prepare and issue the abort frame
121162306a36Sopenharmony_ci	 */
121262306a36Sopenharmony_ci	abort_fr->cmd = MFI_CMD_ABORT;
121362306a36Sopenharmony_ci	abort_fr->cmd_status = MFI_STAT_INVALID_STATUS;
121462306a36Sopenharmony_ci	abort_fr->flags = cpu_to_le16(0);
121562306a36Sopenharmony_ci	abort_fr->abort_context = cpu_to_le32(cmd_to_abort->index);
121662306a36Sopenharmony_ci	abort_fr->abort_mfi_phys_addr_lo =
121762306a36Sopenharmony_ci		cpu_to_le32(lower_32_bits(cmd_to_abort->frame_phys_addr));
121862306a36Sopenharmony_ci	abort_fr->abort_mfi_phys_addr_hi =
121962306a36Sopenharmony_ci		cpu_to_le32(upper_32_bits(cmd_to_abort->frame_phys_addr));
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	cmd->sync_cmd = 1;
122262306a36Sopenharmony_ci	cmd->cmd_status_drv = DCMD_INIT;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
122562306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
122662306a36Sopenharmony_ci			__func__, __LINE__);
122762306a36Sopenharmony_ci		return DCMD_INIT;
122862306a36Sopenharmony_ci	}
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	instance->instancet->issue_dcmd(instance, cmd);
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	if (timeout) {
123362306a36Sopenharmony_ci		ret = wait_event_timeout(instance->abort_cmd_wait_q,
123462306a36Sopenharmony_ci		cmd->cmd_status_drv != DCMD_INIT, timeout * HZ);
123562306a36Sopenharmony_ci		if (!ret) {
123662306a36Sopenharmony_ci			opcode = cmd_to_abort->frame->dcmd.opcode;
123762306a36Sopenharmony_ci			dev_err(&instance->pdev->dev,
123862306a36Sopenharmony_ci				"Abort(to be aborted DCMD opcode: 0x%x) is timed out func:%s\n",
123962306a36Sopenharmony_ci				opcode,  __func__);
124062306a36Sopenharmony_ci			return DCMD_TIMEOUT;
124162306a36Sopenharmony_ci		}
124262306a36Sopenharmony_ci	} else
124362306a36Sopenharmony_ci		wait_event(instance->abort_cmd_wait_q,
124462306a36Sopenharmony_ci		cmd->cmd_status_drv != DCMD_INIT);
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	cmd->sync_cmd = 0;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	megasas_return_cmd(instance, cmd);
124962306a36Sopenharmony_ci	return cmd->cmd_status_drv;
125062306a36Sopenharmony_ci}
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci/**
125362306a36Sopenharmony_ci * megasas_make_sgl32 -	Prepares 32-bit SGL
125462306a36Sopenharmony_ci * @instance:		Adapter soft state
125562306a36Sopenharmony_ci * @scp:		SCSI command from the mid-layer
125662306a36Sopenharmony_ci * @mfi_sgl:		SGL to be filled in
125762306a36Sopenharmony_ci *
125862306a36Sopenharmony_ci * If successful, this function returns the number of SG elements. Otherwise,
125962306a36Sopenharmony_ci * it returnes -1.
126062306a36Sopenharmony_ci */
126162306a36Sopenharmony_cistatic int
126262306a36Sopenharmony_cimegasas_make_sgl32(struct megasas_instance *instance, struct scsi_cmnd *scp,
126362306a36Sopenharmony_ci		   union megasas_sgl *mfi_sgl)
126462306a36Sopenharmony_ci{
126562306a36Sopenharmony_ci	int i;
126662306a36Sopenharmony_ci	int sge_count;
126762306a36Sopenharmony_ci	struct scatterlist *os_sgl;
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	sge_count = scsi_dma_map(scp);
127062306a36Sopenharmony_ci	BUG_ON(sge_count < 0);
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	if (sge_count) {
127362306a36Sopenharmony_ci		scsi_for_each_sg(scp, os_sgl, sge_count, i) {
127462306a36Sopenharmony_ci			mfi_sgl->sge32[i].length = cpu_to_le32(sg_dma_len(os_sgl));
127562306a36Sopenharmony_ci			mfi_sgl->sge32[i].phys_addr = cpu_to_le32(sg_dma_address(os_sgl));
127662306a36Sopenharmony_ci		}
127762306a36Sopenharmony_ci	}
127862306a36Sopenharmony_ci	return sge_count;
127962306a36Sopenharmony_ci}
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci/**
128262306a36Sopenharmony_ci * megasas_make_sgl64 -	Prepares 64-bit SGL
128362306a36Sopenharmony_ci * @instance:		Adapter soft state
128462306a36Sopenharmony_ci * @scp:		SCSI command from the mid-layer
128562306a36Sopenharmony_ci * @mfi_sgl:		SGL to be filled in
128662306a36Sopenharmony_ci *
128762306a36Sopenharmony_ci * If successful, this function returns the number of SG elements. Otherwise,
128862306a36Sopenharmony_ci * it returnes -1.
128962306a36Sopenharmony_ci */
129062306a36Sopenharmony_cistatic int
129162306a36Sopenharmony_cimegasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
129262306a36Sopenharmony_ci		   union megasas_sgl *mfi_sgl)
129362306a36Sopenharmony_ci{
129462306a36Sopenharmony_ci	int i;
129562306a36Sopenharmony_ci	int sge_count;
129662306a36Sopenharmony_ci	struct scatterlist *os_sgl;
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	sge_count = scsi_dma_map(scp);
129962306a36Sopenharmony_ci	BUG_ON(sge_count < 0);
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	if (sge_count) {
130262306a36Sopenharmony_ci		scsi_for_each_sg(scp, os_sgl, sge_count, i) {
130362306a36Sopenharmony_ci			mfi_sgl->sge64[i].length = cpu_to_le32(sg_dma_len(os_sgl));
130462306a36Sopenharmony_ci			mfi_sgl->sge64[i].phys_addr = cpu_to_le64(sg_dma_address(os_sgl));
130562306a36Sopenharmony_ci		}
130662306a36Sopenharmony_ci	}
130762306a36Sopenharmony_ci	return sge_count;
130862306a36Sopenharmony_ci}
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci/**
131162306a36Sopenharmony_ci * megasas_make_sgl_skinny - Prepares IEEE SGL
131262306a36Sopenharmony_ci * @instance:           Adapter soft state
131362306a36Sopenharmony_ci * @scp:                SCSI command from the mid-layer
131462306a36Sopenharmony_ci * @mfi_sgl:            SGL to be filled in
131562306a36Sopenharmony_ci *
131662306a36Sopenharmony_ci * If successful, this function returns the number of SG elements. Otherwise,
131762306a36Sopenharmony_ci * it returnes -1.
131862306a36Sopenharmony_ci */
131962306a36Sopenharmony_cistatic int
132062306a36Sopenharmony_cimegasas_make_sgl_skinny(struct megasas_instance *instance,
132162306a36Sopenharmony_ci		struct scsi_cmnd *scp, union megasas_sgl *mfi_sgl)
132262306a36Sopenharmony_ci{
132362306a36Sopenharmony_ci	int i;
132462306a36Sopenharmony_ci	int sge_count;
132562306a36Sopenharmony_ci	struct scatterlist *os_sgl;
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	sge_count = scsi_dma_map(scp);
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	if (sge_count) {
133062306a36Sopenharmony_ci		scsi_for_each_sg(scp, os_sgl, sge_count, i) {
133162306a36Sopenharmony_ci			mfi_sgl->sge_skinny[i].length =
133262306a36Sopenharmony_ci				cpu_to_le32(sg_dma_len(os_sgl));
133362306a36Sopenharmony_ci			mfi_sgl->sge_skinny[i].phys_addr =
133462306a36Sopenharmony_ci				cpu_to_le64(sg_dma_address(os_sgl));
133562306a36Sopenharmony_ci			mfi_sgl->sge_skinny[i].flag = cpu_to_le32(0);
133662306a36Sopenharmony_ci		}
133762306a36Sopenharmony_ci	}
133862306a36Sopenharmony_ci	return sge_count;
133962306a36Sopenharmony_ci}
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci /**
134262306a36Sopenharmony_ci * megasas_get_frame_count - Computes the number of frames
134362306a36Sopenharmony_ci * @frame_type		: type of frame- io or pthru frame
134462306a36Sopenharmony_ci * @sge_count		: number of sg elements
134562306a36Sopenharmony_ci *
134662306a36Sopenharmony_ci * Returns the number of frames required for numnber of sge's (sge_count)
134762306a36Sopenharmony_ci */
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_cistatic u32 megasas_get_frame_count(struct megasas_instance *instance,
135062306a36Sopenharmony_ci			u8 sge_count, u8 frame_type)
135162306a36Sopenharmony_ci{
135262306a36Sopenharmony_ci	int num_cnt;
135362306a36Sopenharmony_ci	int sge_bytes;
135462306a36Sopenharmony_ci	u32 sge_sz;
135562306a36Sopenharmony_ci	u32 frame_count = 0;
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
135862306a36Sopenharmony_ci	    sizeof(struct megasas_sge32);
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	if (instance->flag_ieee) {
136162306a36Sopenharmony_ci		sge_sz = sizeof(struct megasas_sge_skinny);
136262306a36Sopenharmony_ci	}
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	/*
136562306a36Sopenharmony_ci	 * Main frame can contain 2 SGEs for 64-bit SGLs and
136662306a36Sopenharmony_ci	 * 3 SGEs for 32-bit SGLs for ldio &
136762306a36Sopenharmony_ci	 * 1 SGEs for 64-bit SGLs and
136862306a36Sopenharmony_ci	 * 2 SGEs for 32-bit SGLs for pthru frame
136962306a36Sopenharmony_ci	 */
137062306a36Sopenharmony_ci	if (unlikely(frame_type == PTHRU_FRAME)) {
137162306a36Sopenharmony_ci		if (instance->flag_ieee == 1) {
137262306a36Sopenharmony_ci			num_cnt = sge_count - 1;
137362306a36Sopenharmony_ci		} else if (IS_DMA64)
137462306a36Sopenharmony_ci			num_cnt = sge_count - 1;
137562306a36Sopenharmony_ci		else
137662306a36Sopenharmony_ci			num_cnt = sge_count - 2;
137762306a36Sopenharmony_ci	} else {
137862306a36Sopenharmony_ci		if (instance->flag_ieee == 1) {
137962306a36Sopenharmony_ci			num_cnt = sge_count - 1;
138062306a36Sopenharmony_ci		} else if (IS_DMA64)
138162306a36Sopenharmony_ci			num_cnt = sge_count - 2;
138262306a36Sopenharmony_ci		else
138362306a36Sopenharmony_ci			num_cnt = sge_count - 3;
138462306a36Sopenharmony_ci	}
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	if (num_cnt > 0) {
138762306a36Sopenharmony_ci		sge_bytes = sge_sz * num_cnt;
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci		frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
139062306a36Sopenharmony_ci		    ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) ;
139162306a36Sopenharmony_ci	}
139262306a36Sopenharmony_ci	/* Main frame */
139362306a36Sopenharmony_ci	frame_count += 1;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	if (frame_count > 7)
139662306a36Sopenharmony_ci		frame_count = 8;
139762306a36Sopenharmony_ci	return frame_count;
139862306a36Sopenharmony_ci}
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci/**
140162306a36Sopenharmony_ci * megasas_build_dcdb -	Prepares a direct cdb (DCDB) command
140262306a36Sopenharmony_ci * @instance:		Adapter soft state
140362306a36Sopenharmony_ci * @scp:		SCSI command
140462306a36Sopenharmony_ci * @cmd:		Command to be prepared in
140562306a36Sopenharmony_ci *
140662306a36Sopenharmony_ci * This function prepares CDB commands. These are typcially pass-through
140762306a36Sopenharmony_ci * commands to the devices.
140862306a36Sopenharmony_ci */
140962306a36Sopenharmony_cistatic int
141062306a36Sopenharmony_cimegasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
141162306a36Sopenharmony_ci		   struct megasas_cmd *cmd)
141262306a36Sopenharmony_ci{
141362306a36Sopenharmony_ci	u32 is_logical;
141462306a36Sopenharmony_ci	u32 device_id;
141562306a36Sopenharmony_ci	u16 flags = 0;
141662306a36Sopenharmony_ci	struct megasas_pthru_frame *pthru;
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	is_logical = MEGASAS_IS_LOGICAL(scp->device);
141962306a36Sopenharmony_ci	device_id = MEGASAS_DEV_INDEX(scp);
142062306a36Sopenharmony_ci	pthru = (struct megasas_pthru_frame *)cmd->frame;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	if (scp->sc_data_direction == DMA_TO_DEVICE)
142362306a36Sopenharmony_ci		flags = MFI_FRAME_DIR_WRITE;
142462306a36Sopenharmony_ci	else if (scp->sc_data_direction == DMA_FROM_DEVICE)
142562306a36Sopenharmony_ci		flags = MFI_FRAME_DIR_READ;
142662306a36Sopenharmony_ci	else if (scp->sc_data_direction == DMA_NONE)
142762306a36Sopenharmony_ci		flags = MFI_FRAME_DIR_NONE;
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	if (instance->flag_ieee == 1) {
143062306a36Sopenharmony_ci		flags |= MFI_FRAME_IEEE;
143162306a36Sopenharmony_ci	}
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci	/*
143462306a36Sopenharmony_ci	 * Prepare the DCDB frame
143562306a36Sopenharmony_ci	 */
143662306a36Sopenharmony_ci	pthru->cmd = (is_logical) ? MFI_CMD_LD_SCSI_IO : MFI_CMD_PD_SCSI_IO;
143762306a36Sopenharmony_ci	pthru->cmd_status = 0x0;
143862306a36Sopenharmony_ci	pthru->scsi_status = 0x0;
143962306a36Sopenharmony_ci	pthru->target_id = device_id;
144062306a36Sopenharmony_ci	pthru->lun = scp->device->lun;
144162306a36Sopenharmony_ci	pthru->cdb_len = scp->cmd_len;
144262306a36Sopenharmony_ci	pthru->timeout = 0;
144362306a36Sopenharmony_ci	pthru->pad_0 = 0;
144462306a36Sopenharmony_ci	pthru->flags = cpu_to_le16(flags);
144562306a36Sopenharmony_ci	pthru->data_xfer_len = cpu_to_le32(scsi_bufflen(scp));
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	/*
145062306a36Sopenharmony_ci	 * If the command is for the tape device, set the
145162306a36Sopenharmony_ci	 * pthru timeout to the os layer timeout value.
145262306a36Sopenharmony_ci	 */
145362306a36Sopenharmony_ci	if (scp->device->type == TYPE_TAPE) {
145462306a36Sopenharmony_ci		if (scsi_cmd_to_rq(scp)->timeout / HZ > 0xFFFF)
145562306a36Sopenharmony_ci			pthru->timeout = cpu_to_le16(0xFFFF);
145662306a36Sopenharmony_ci		else
145762306a36Sopenharmony_ci			pthru->timeout = cpu_to_le16(scsi_cmd_to_rq(scp)->timeout / HZ);
145862306a36Sopenharmony_ci	}
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	/*
146162306a36Sopenharmony_ci	 * Construct SGL
146262306a36Sopenharmony_ci	 */
146362306a36Sopenharmony_ci	if (instance->flag_ieee == 1) {
146462306a36Sopenharmony_ci		pthru->flags |= cpu_to_le16(MFI_FRAME_SGL64);
146562306a36Sopenharmony_ci		pthru->sge_count = megasas_make_sgl_skinny(instance, scp,
146662306a36Sopenharmony_ci						      &pthru->sgl);
146762306a36Sopenharmony_ci	} else if (IS_DMA64) {
146862306a36Sopenharmony_ci		pthru->flags |= cpu_to_le16(MFI_FRAME_SGL64);
146962306a36Sopenharmony_ci		pthru->sge_count = megasas_make_sgl64(instance, scp,
147062306a36Sopenharmony_ci						      &pthru->sgl);
147162306a36Sopenharmony_ci	} else
147262306a36Sopenharmony_ci		pthru->sge_count = megasas_make_sgl32(instance, scp,
147362306a36Sopenharmony_ci						      &pthru->sgl);
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	if (pthru->sge_count > instance->max_num_sge) {
147662306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "DCDB too many SGE NUM=%x\n",
147762306a36Sopenharmony_ci			pthru->sge_count);
147862306a36Sopenharmony_ci		return 0;
147962306a36Sopenharmony_ci	}
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	/*
148262306a36Sopenharmony_ci	 * Sense info specific
148362306a36Sopenharmony_ci	 */
148462306a36Sopenharmony_ci	pthru->sense_len = SCSI_SENSE_BUFFERSIZE;
148562306a36Sopenharmony_ci	pthru->sense_buf_phys_addr_hi =
148662306a36Sopenharmony_ci		cpu_to_le32(upper_32_bits(cmd->sense_phys_addr));
148762306a36Sopenharmony_ci	pthru->sense_buf_phys_addr_lo =
148862306a36Sopenharmony_ci		cpu_to_le32(lower_32_bits(cmd->sense_phys_addr));
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	/*
149162306a36Sopenharmony_ci	 * Compute the total number of frames this command consumes. FW uses
149262306a36Sopenharmony_ci	 * this number to pull sufficient number of frames from host memory.
149362306a36Sopenharmony_ci	 */
149462306a36Sopenharmony_ci	cmd->frame_count = megasas_get_frame_count(instance, pthru->sge_count,
149562306a36Sopenharmony_ci							PTHRU_FRAME);
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	return cmd->frame_count;
149862306a36Sopenharmony_ci}
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci/**
150162306a36Sopenharmony_ci * megasas_build_ldio -	Prepares IOs to logical devices
150262306a36Sopenharmony_ci * @instance:		Adapter soft state
150362306a36Sopenharmony_ci * @scp:		SCSI command
150462306a36Sopenharmony_ci * @cmd:		Command to be prepared
150562306a36Sopenharmony_ci *
150662306a36Sopenharmony_ci * Frames (and accompanying SGLs) for regular SCSI IOs use this function.
150762306a36Sopenharmony_ci */
150862306a36Sopenharmony_cistatic int
150962306a36Sopenharmony_cimegasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
151062306a36Sopenharmony_ci		   struct megasas_cmd *cmd)
151162306a36Sopenharmony_ci{
151262306a36Sopenharmony_ci	u32 device_id;
151362306a36Sopenharmony_ci	u8 sc = scp->cmnd[0];
151462306a36Sopenharmony_ci	u16 flags = 0;
151562306a36Sopenharmony_ci	struct megasas_io_frame *ldio;
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	device_id = MEGASAS_DEV_INDEX(scp);
151862306a36Sopenharmony_ci	ldio = (struct megasas_io_frame *)cmd->frame;
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	if (scp->sc_data_direction == DMA_TO_DEVICE)
152162306a36Sopenharmony_ci		flags = MFI_FRAME_DIR_WRITE;
152262306a36Sopenharmony_ci	else if (scp->sc_data_direction == DMA_FROM_DEVICE)
152362306a36Sopenharmony_ci		flags = MFI_FRAME_DIR_READ;
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	if (instance->flag_ieee == 1) {
152662306a36Sopenharmony_ci		flags |= MFI_FRAME_IEEE;
152762306a36Sopenharmony_ci	}
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	/*
153062306a36Sopenharmony_ci	 * Prepare the Logical IO frame: 2nd bit is zero for all read cmds
153162306a36Sopenharmony_ci	 */
153262306a36Sopenharmony_ci	ldio->cmd = (sc & 0x02) ? MFI_CMD_LD_WRITE : MFI_CMD_LD_READ;
153362306a36Sopenharmony_ci	ldio->cmd_status = 0x0;
153462306a36Sopenharmony_ci	ldio->scsi_status = 0x0;
153562306a36Sopenharmony_ci	ldio->target_id = device_id;
153662306a36Sopenharmony_ci	ldio->timeout = 0;
153762306a36Sopenharmony_ci	ldio->reserved_0 = 0;
153862306a36Sopenharmony_ci	ldio->pad_0 = 0;
153962306a36Sopenharmony_ci	ldio->flags = cpu_to_le16(flags);
154062306a36Sopenharmony_ci	ldio->start_lba_hi = 0;
154162306a36Sopenharmony_ci	ldio->access_byte = (scp->cmd_len != 6) ? scp->cmnd[1] : 0;
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci	/*
154462306a36Sopenharmony_ci	 * 6-byte READ(0x08) or WRITE(0x0A) cdb
154562306a36Sopenharmony_ci	 */
154662306a36Sopenharmony_ci	if (scp->cmd_len == 6) {
154762306a36Sopenharmony_ci		ldio->lba_count = cpu_to_le32((u32) scp->cmnd[4]);
154862306a36Sopenharmony_ci		ldio->start_lba_lo = cpu_to_le32(((u32) scp->cmnd[1] << 16) |
154962306a36Sopenharmony_ci						 ((u32) scp->cmnd[2] << 8) |
155062306a36Sopenharmony_ci						 (u32) scp->cmnd[3]);
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci		ldio->start_lba_lo &= cpu_to_le32(0x1FFFFF);
155362306a36Sopenharmony_ci	}
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci	/*
155662306a36Sopenharmony_ci	 * 10-byte READ(0x28) or WRITE(0x2A) cdb
155762306a36Sopenharmony_ci	 */
155862306a36Sopenharmony_ci	else if (scp->cmd_len == 10) {
155962306a36Sopenharmony_ci		ldio->lba_count = cpu_to_le32((u32) scp->cmnd[8] |
156062306a36Sopenharmony_ci					      ((u32) scp->cmnd[7] << 8));
156162306a36Sopenharmony_ci		ldio->start_lba_lo = cpu_to_le32(((u32) scp->cmnd[2] << 24) |
156262306a36Sopenharmony_ci						 ((u32) scp->cmnd[3] << 16) |
156362306a36Sopenharmony_ci						 ((u32) scp->cmnd[4] << 8) |
156462306a36Sopenharmony_ci						 (u32) scp->cmnd[5]);
156562306a36Sopenharmony_ci	}
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	/*
156862306a36Sopenharmony_ci	 * 12-byte READ(0xA8) or WRITE(0xAA) cdb
156962306a36Sopenharmony_ci	 */
157062306a36Sopenharmony_ci	else if (scp->cmd_len == 12) {
157162306a36Sopenharmony_ci		ldio->lba_count = cpu_to_le32(((u32) scp->cmnd[6] << 24) |
157262306a36Sopenharmony_ci					      ((u32) scp->cmnd[7] << 16) |
157362306a36Sopenharmony_ci					      ((u32) scp->cmnd[8] << 8) |
157462306a36Sopenharmony_ci					      (u32) scp->cmnd[9]);
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci		ldio->start_lba_lo = cpu_to_le32(((u32) scp->cmnd[2] << 24) |
157762306a36Sopenharmony_ci						 ((u32) scp->cmnd[3] << 16) |
157862306a36Sopenharmony_ci						 ((u32) scp->cmnd[4] << 8) |
157962306a36Sopenharmony_ci						 (u32) scp->cmnd[5]);
158062306a36Sopenharmony_ci	}
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	/*
158362306a36Sopenharmony_ci	 * 16-byte READ(0x88) or WRITE(0x8A) cdb
158462306a36Sopenharmony_ci	 */
158562306a36Sopenharmony_ci	else if (scp->cmd_len == 16) {
158662306a36Sopenharmony_ci		ldio->lba_count = cpu_to_le32(((u32) scp->cmnd[10] << 24) |
158762306a36Sopenharmony_ci					      ((u32) scp->cmnd[11] << 16) |
158862306a36Sopenharmony_ci					      ((u32) scp->cmnd[12] << 8) |
158962306a36Sopenharmony_ci					      (u32) scp->cmnd[13]);
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci		ldio->start_lba_lo = cpu_to_le32(((u32) scp->cmnd[6] << 24) |
159262306a36Sopenharmony_ci						 ((u32) scp->cmnd[7] << 16) |
159362306a36Sopenharmony_ci						 ((u32) scp->cmnd[8] << 8) |
159462306a36Sopenharmony_ci						 (u32) scp->cmnd[9]);
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci		ldio->start_lba_hi = cpu_to_le32(((u32) scp->cmnd[2] << 24) |
159762306a36Sopenharmony_ci						 ((u32) scp->cmnd[3] << 16) |
159862306a36Sopenharmony_ci						 ((u32) scp->cmnd[4] << 8) |
159962306a36Sopenharmony_ci						 (u32) scp->cmnd[5]);
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	}
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	/*
160462306a36Sopenharmony_ci	 * Construct SGL
160562306a36Sopenharmony_ci	 */
160662306a36Sopenharmony_ci	if (instance->flag_ieee) {
160762306a36Sopenharmony_ci		ldio->flags |= cpu_to_le16(MFI_FRAME_SGL64);
160862306a36Sopenharmony_ci		ldio->sge_count = megasas_make_sgl_skinny(instance, scp,
160962306a36Sopenharmony_ci					      &ldio->sgl);
161062306a36Sopenharmony_ci	} else if (IS_DMA64) {
161162306a36Sopenharmony_ci		ldio->flags |= cpu_to_le16(MFI_FRAME_SGL64);
161262306a36Sopenharmony_ci		ldio->sge_count = megasas_make_sgl64(instance, scp, &ldio->sgl);
161362306a36Sopenharmony_ci	} else
161462306a36Sopenharmony_ci		ldio->sge_count = megasas_make_sgl32(instance, scp, &ldio->sgl);
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci	if (ldio->sge_count > instance->max_num_sge) {
161762306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "build_ld_io: sge_count = %x\n",
161862306a36Sopenharmony_ci			ldio->sge_count);
161962306a36Sopenharmony_ci		return 0;
162062306a36Sopenharmony_ci	}
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci	/*
162362306a36Sopenharmony_ci	 * Sense info specific
162462306a36Sopenharmony_ci	 */
162562306a36Sopenharmony_ci	ldio->sense_len = SCSI_SENSE_BUFFERSIZE;
162662306a36Sopenharmony_ci	ldio->sense_buf_phys_addr_hi = 0;
162762306a36Sopenharmony_ci	ldio->sense_buf_phys_addr_lo = cpu_to_le32(cmd->sense_phys_addr);
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci	/*
163062306a36Sopenharmony_ci	 * Compute the total number of frames this command consumes. FW uses
163162306a36Sopenharmony_ci	 * this number to pull sufficient number of frames from host memory.
163262306a36Sopenharmony_ci	 */
163362306a36Sopenharmony_ci	cmd->frame_count = megasas_get_frame_count(instance,
163462306a36Sopenharmony_ci			ldio->sge_count, IO_FRAME);
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	return cmd->frame_count;
163762306a36Sopenharmony_ci}
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci/**
164062306a36Sopenharmony_ci * megasas_cmd_type -		Checks if the cmd is for logical drive/sysPD
164162306a36Sopenharmony_ci *				and whether it's RW or non RW
164262306a36Sopenharmony_ci * @cmd:			SCSI command
164362306a36Sopenharmony_ci *
164462306a36Sopenharmony_ci */
164562306a36Sopenharmony_ciinline int megasas_cmd_type(struct scsi_cmnd *cmd)
164662306a36Sopenharmony_ci{
164762306a36Sopenharmony_ci	int ret;
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci	switch (cmd->cmnd[0]) {
165062306a36Sopenharmony_ci	case READ_10:
165162306a36Sopenharmony_ci	case WRITE_10:
165262306a36Sopenharmony_ci	case READ_12:
165362306a36Sopenharmony_ci	case WRITE_12:
165462306a36Sopenharmony_ci	case READ_6:
165562306a36Sopenharmony_ci	case WRITE_6:
165662306a36Sopenharmony_ci	case READ_16:
165762306a36Sopenharmony_ci	case WRITE_16:
165862306a36Sopenharmony_ci		ret = (MEGASAS_IS_LOGICAL(cmd->device)) ?
165962306a36Sopenharmony_ci			READ_WRITE_LDIO : READ_WRITE_SYSPDIO;
166062306a36Sopenharmony_ci		break;
166162306a36Sopenharmony_ci	default:
166262306a36Sopenharmony_ci		ret = (MEGASAS_IS_LOGICAL(cmd->device)) ?
166362306a36Sopenharmony_ci			NON_READ_WRITE_LDIO : NON_READ_WRITE_SYSPDIO;
166462306a36Sopenharmony_ci	}
166562306a36Sopenharmony_ci	return ret;
166662306a36Sopenharmony_ci}
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci /**
166962306a36Sopenharmony_ci * megasas_dump_pending_frames -	Dumps the frame address of all pending cmds
167062306a36Sopenharmony_ci *					in FW
167162306a36Sopenharmony_ci * @instance:				Adapter soft state
167262306a36Sopenharmony_ci */
167362306a36Sopenharmony_cistatic inline void
167462306a36Sopenharmony_cimegasas_dump_pending_frames(struct megasas_instance *instance)
167562306a36Sopenharmony_ci{
167662306a36Sopenharmony_ci	struct megasas_cmd *cmd;
167762306a36Sopenharmony_ci	int i,n;
167862306a36Sopenharmony_ci	union megasas_sgl *mfi_sgl;
167962306a36Sopenharmony_ci	struct megasas_io_frame *ldio;
168062306a36Sopenharmony_ci	struct megasas_pthru_frame *pthru;
168162306a36Sopenharmony_ci	u32 sgcount;
168262306a36Sopenharmony_ci	u16 max_cmd = instance->max_fw_cmds;
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	dev_err(&instance->pdev->dev, "[%d]: Dumping Frame Phys Address of all pending cmds in FW\n",instance->host->host_no);
168562306a36Sopenharmony_ci	dev_err(&instance->pdev->dev, "[%d]: Total OS Pending cmds : %d\n",instance->host->host_no,atomic_read(&instance->fw_outstanding));
168662306a36Sopenharmony_ci	if (IS_DMA64)
168762306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "[%d]: 64 bit SGLs were sent to FW\n",instance->host->host_no);
168862306a36Sopenharmony_ci	else
168962306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "[%d]: 32 bit SGLs were sent to FW\n",instance->host->host_no);
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	dev_err(&instance->pdev->dev, "[%d]: Pending OS cmds in FW : \n",instance->host->host_no);
169262306a36Sopenharmony_ci	for (i = 0; i < max_cmd; i++) {
169362306a36Sopenharmony_ci		cmd = instance->cmd_list[i];
169462306a36Sopenharmony_ci		if (!cmd->scmd)
169562306a36Sopenharmony_ci			continue;
169662306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "[%d]: Frame addr :0x%08lx : ",instance->host->host_no,(unsigned long)cmd->frame_phys_addr);
169762306a36Sopenharmony_ci		if (megasas_cmd_type(cmd->scmd) == READ_WRITE_LDIO) {
169862306a36Sopenharmony_ci			ldio = (struct megasas_io_frame *)cmd->frame;
169962306a36Sopenharmony_ci			mfi_sgl = &ldio->sgl;
170062306a36Sopenharmony_ci			sgcount = ldio->sge_count;
170162306a36Sopenharmony_ci			dev_err(&instance->pdev->dev, "[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x,"
170262306a36Sopenharmony_ci			" lba lo : 0x%x, lba_hi : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",
170362306a36Sopenharmony_ci			instance->host->host_no, cmd->frame_count, ldio->cmd, ldio->target_id,
170462306a36Sopenharmony_ci			le32_to_cpu(ldio->start_lba_lo), le32_to_cpu(ldio->start_lba_hi),
170562306a36Sopenharmony_ci			le32_to_cpu(ldio->sense_buf_phys_addr_lo), sgcount);
170662306a36Sopenharmony_ci		} else {
170762306a36Sopenharmony_ci			pthru = (struct megasas_pthru_frame *) cmd->frame;
170862306a36Sopenharmony_ci			mfi_sgl = &pthru->sgl;
170962306a36Sopenharmony_ci			sgcount = pthru->sge_count;
171062306a36Sopenharmony_ci			dev_err(&instance->pdev->dev, "[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, "
171162306a36Sopenharmony_ci			"lun : 0x%x, cdb_len : 0x%x, data xfer len : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",
171262306a36Sopenharmony_ci			instance->host->host_no, cmd->frame_count, pthru->cmd, pthru->target_id,
171362306a36Sopenharmony_ci			pthru->lun, pthru->cdb_len, le32_to_cpu(pthru->data_xfer_len),
171462306a36Sopenharmony_ci			le32_to_cpu(pthru->sense_buf_phys_addr_lo), sgcount);
171562306a36Sopenharmony_ci		}
171662306a36Sopenharmony_ci		if (megasas_dbg_lvl & MEGASAS_DBG_LVL) {
171762306a36Sopenharmony_ci			for (n = 0; n < sgcount; n++) {
171862306a36Sopenharmony_ci				if (IS_DMA64)
171962306a36Sopenharmony_ci					dev_err(&instance->pdev->dev, "sgl len : 0x%x, sgl addr : 0x%llx\n",
172062306a36Sopenharmony_ci						le32_to_cpu(mfi_sgl->sge64[n].length),
172162306a36Sopenharmony_ci						le64_to_cpu(mfi_sgl->sge64[n].phys_addr));
172262306a36Sopenharmony_ci				else
172362306a36Sopenharmony_ci					dev_err(&instance->pdev->dev, "sgl len : 0x%x, sgl addr : 0x%x\n",
172462306a36Sopenharmony_ci						le32_to_cpu(mfi_sgl->sge32[n].length),
172562306a36Sopenharmony_ci						le32_to_cpu(mfi_sgl->sge32[n].phys_addr));
172662306a36Sopenharmony_ci			}
172762306a36Sopenharmony_ci		}
172862306a36Sopenharmony_ci	} /*for max_cmd*/
172962306a36Sopenharmony_ci	dev_err(&instance->pdev->dev, "[%d]: Pending Internal cmds in FW : \n",instance->host->host_no);
173062306a36Sopenharmony_ci	for (i = 0; i < max_cmd; i++) {
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci		cmd = instance->cmd_list[i];
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci		if (cmd->sync_cmd == 1)
173562306a36Sopenharmony_ci			dev_err(&instance->pdev->dev, "0x%08lx : ", (unsigned long)cmd->frame_phys_addr);
173662306a36Sopenharmony_ci	}
173762306a36Sopenharmony_ci	dev_err(&instance->pdev->dev, "[%d]: Dumping Done\n\n",instance->host->host_no);
173862306a36Sopenharmony_ci}
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ciu32
174162306a36Sopenharmony_cimegasas_build_and_issue_cmd(struct megasas_instance *instance,
174262306a36Sopenharmony_ci			    struct scsi_cmnd *scmd)
174362306a36Sopenharmony_ci{
174462306a36Sopenharmony_ci	struct megasas_cmd *cmd;
174562306a36Sopenharmony_ci	u32 frame_count;
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	cmd = megasas_get_cmd(instance);
174862306a36Sopenharmony_ci	if (!cmd)
174962306a36Sopenharmony_ci		return SCSI_MLQUEUE_HOST_BUSY;
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci	/*
175262306a36Sopenharmony_ci	 * Logical drive command
175362306a36Sopenharmony_ci	 */
175462306a36Sopenharmony_ci	if (megasas_cmd_type(scmd) == READ_WRITE_LDIO)
175562306a36Sopenharmony_ci		frame_count = megasas_build_ldio(instance, scmd, cmd);
175662306a36Sopenharmony_ci	else
175762306a36Sopenharmony_ci		frame_count = megasas_build_dcdb(instance, scmd, cmd);
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci	if (!frame_count)
176062306a36Sopenharmony_ci		goto out_return_cmd;
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	cmd->scmd = scmd;
176362306a36Sopenharmony_ci	megasas_priv(scmd)->cmd_priv = cmd;
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	/*
176662306a36Sopenharmony_ci	 * Issue the command to the FW
176762306a36Sopenharmony_ci	 */
176862306a36Sopenharmony_ci	atomic_inc(&instance->fw_outstanding);
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci	instance->instancet->fire_cmd(instance, cmd->frame_phys_addr,
177162306a36Sopenharmony_ci				cmd->frame_count-1, instance->reg_set);
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci	return 0;
177462306a36Sopenharmony_ciout_return_cmd:
177562306a36Sopenharmony_ci	megasas_return_cmd(instance, cmd);
177662306a36Sopenharmony_ci	return SCSI_MLQUEUE_HOST_BUSY;
177762306a36Sopenharmony_ci}
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci/**
178162306a36Sopenharmony_ci * megasas_queue_command -	Queue entry point
178262306a36Sopenharmony_ci * @shost:			adapter SCSI host
178362306a36Sopenharmony_ci * @scmd:			SCSI command to be queued
178462306a36Sopenharmony_ci */
178562306a36Sopenharmony_cistatic int
178662306a36Sopenharmony_cimegasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
178762306a36Sopenharmony_ci{
178862306a36Sopenharmony_ci	struct megasas_instance *instance;
178962306a36Sopenharmony_ci	struct MR_PRIV_DEVICE *mr_device_priv_data;
179062306a36Sopenharmony_ci	u32 ld_tgt_id;
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	instance = (struct megasas_instance *)
179362306a36Sopenharmony_ci	    scmd->device->host->hostdata;
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	if (instance->unload == 1) {
179662306a36Sopenharmony_ci		scmd->result = DID_NO_CONNECT << 16;
179762306a36Sopenharmony_ci		scsi_done(scmd);
179862306a36Sopenharmony_ci		return 0;
179962306a36Sopenharmony_ci	}
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci	if (instance->issuepend_done == 0)
180262306a36Sopenharmony_ci		return SCSI_MLQUEUE_HOST_BUSY;
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	/* Check for an mpio path and adjust behavior */
180662306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) == MEGASAS_ADPRESET_SM_INFAULT) {
180762306a36Sopenharmony_ci		if (megasas_check_mpio_paths(instance, scmd) ==
180862306a36Sopenharmony_ci		    (DID_REQUEUE << 16)) {
180962306a36Sopenharmony_ci			return SCSI_MLQUEUE_HOST_BUSY;
181062306a36Sopenharmony_ci		} else {
181162306a36Sopenharmony_ci			scmd->result = DID_NO_CONNECT << 16;
181262306a36Sopenharmony_ci			scsi_done(scmd);
181362306a36Sopenharmony_ci			return 0;
181462306a36Sopenharmony_ci		}
181562306a36Sopenharmony_ci	}
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	mr_device_priv_data = scmd->device->hostdata;
181862306a36Sopenharmony_ci	if (!mr_device_priv_data ||
181962306a36Sopenharmony_ci	    (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)) {
182062306a36Sopenharmony_ci		scmd->result = DID_NO_CONNECT << 16;
182162306a36Sopenharmony_ci		scsi_done(scmd);
182262306a36Sopenharmony_ci		return 0;
182362306a36Sopenharmony_ci	}
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci	if (MEGASAS_IS_LOGICAL(scmd->device)) {
182662306a36Sopenharmony_ci		ld_tgt_id = MEGASAS_TARGET_ID(scmd->device);
182762306a36Sopenharmony_ci		if (instance->ld_tgtid_status[ld_tgt_id] == LD_TARGET_ID_DELETED) {
182862306a36Sopenharmony_ci			scmd->result = DID_NO_CONNECT << 16;
182962306a36Sopenharmony_ci			scsi_done(scmd);
183062306a36Sopenharmony_ci			return 0;
183162306a36Sopenharmony_ci		}
183262306a36Sopenharmony_ci	}
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
183562306a36Sopenharmony_ci		return SCSI_MLQUEUE_HOST_BUSY;
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	if (mr_device_priv_data->tm_busy)
183862306a36Sopenharmony_ci		return SCSI_MLQUEUE_DEVICE_BUSY;
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	scmd->result = 0;
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci	if (MEGASAS_IS_LOGICAL(scmd->device) &&
184462306a36Sopenharmony_ci	    (scmd->device->id >= instance->fw_supported_vd_count ||
184562306a36Sopenharmony_ci		scmd->device->lun)) {
184662306a36Sopenharmony_ci		scmd->result = DID_BAD_TARGET << 16;
184762306a36Sopenharmony_ci		goto out_done;
184862306a36Sopenharmony_ci	}
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci	if ((scmd->cmnd[0] == SYNCHRONIZE_CACHE) &&
185162306a36Sopenharmony_ci	    MEGASAS_IS_LOGICAL(scmd->device) &&
185262306a36Sopenharmony_ci	    (!instance->fw_sync_cache_support)) {
185362306a36Sopenharmony_ci		scmd->result = DID_OK << 16;
185462306a36Sopenharmony_ci		goto out_done;
185562306a36Sopenharmony_ci	}
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_ci	return instance->instancet->build_and_issue_cmd(instance, scmd);
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci out_done:
186062306a36Sopenharmony_ci	scsi_done(scmd);
186162306a36Sopenharmony_ci	return 0;
186262306a36Sopenharmony_ci}
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_cistatic struct megasas_instance *megasas_lookup_instance(u16 host_no)
186562306a36Sopenharmony_ci{
186662306a36Sopenharmony_ci	int i;
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci	for (i = 0; i < megasas_mgmt_info.max_index; i++) {
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci		if ((megasas_mgmt_info.instance[i]) &&
187162306a36Sopenharmony_ci		    (megasas_mgmt_info.instance[i]->host->host_no == host_no))
187262306a36Sopenharmony_ci			return megasas_mgmt_info.instance[i];
187362306a36Sopenharmony_ci	}
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci	return NULL;
187662306a36Sopenharmony_ci}
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci/*
187962306a36Sopenharmony_ci* megasas_set_dynamic_target_properties -
188062306a36Sopenharmony_ci* Device property set by driver may not be static and it is required to be
188162306a36Sopenharmony_ci* updated after OCR
188262306a36Sopenharmony_ci*
188362306a36Sopenharmony_ci* set tm_capable.
188462306a36Sopenharmony_ci* set dma alignment (only for eedp protection enable vd).
188562306a36Sopenharmony_ci*
188662306a36Sopenharmony_ci* @sdev: OS provided scsi device
188762306a36Sopenharmony_ci*
188862306a36Sopenharmony_ci* Returns void
188962306a36Sopenharmony_ci*/
189062306a36Sopenharmony_civoid megasas_set_dynamic_target_properties(struct scsi_device *sdev,
189162306a36Sopenharmony_ci					   bool is_target_prop)
189262306a36Sopenharmony_ci{
189362306a36Sopenharmony_ci	u16 pd_index = 0, ld;
189462306a36Sopenharmony_ci	u32 device_id;
189562306a36Sopenharmony_ci	struct megasas_instance *instance;
189662306a36Sopenharmony_ci	struct fusion_context *fusion;
189762306a36Sopenharmony_ci	struct MR_PRIV_DEVICE *mr_device_priv_data;
189862306a36Sopenharmony_ci	struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync;
189962306a36Sopenharmony_ci	struct MR_LD_RAID *raid;
190062306a36Sopenharmony_ci	struct MR_DRV_RAID_MAP_ALL *local_map_ptr;
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci	instance = megasas_lookup_instance(sdev->host->host_no);
190362306a36Sopenharmony_ci	fusion = instance->ctrl_context;
190462306a36Sopenharmony_ci	mr_device_priv_data = sdev->hostdata;
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci	if (!fusion || !mr_device_priv_data)
190762306a36Sopenharmony_ci		return;
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	if (MEGASAS_IS_LOGICAL(sdev)) {
191062306a36Sopenharmony_ci		device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL)
191162306a36Sopenharmony_ci					+ sdev->id;
191262306a36Sopenharmony_ci		local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
191362306a36Sopenharmony_ci		ld = MR_TargetIdToLdGet(device_id, local_map_ptr);
191462306a36Sopenharmony_ci		if (ld >= instance->fw_supported_vd_count)
191562306a36Sopenharmony_ci			return;
191662306a36Sopenharmony_ci		raid = MR_LdRaidGet(ld, local_map_ptr);
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci		if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER)
191962306a36Sopenharmony_ci			blk_queue_update_dma_alignment(sdev->request_queue, 0x7);
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci		mr_device_priv_data->is_tm_capable =
192262306a36Sopenharmony_ci			raid->capability.tmCapable;
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci		if (!raid->flags.isEPD)
192562306a36Sopenharmony_ci			sdev->no_write_same = 1;
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci	} else if (instance->use_seqnum_jbod_fp) {
192862306a36Sopenharmony_ci		pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
192962306a36Sopenharmony_ci			sdev->id;
193062306a36Sopenharmony_ci		pd_sync = (void *)fusion->pd_seq_sync
193162306a36Sopenharmony_ci				[(instance->pd_seq_map_id - 1) & 1];
193262306a36Sopenharmony_ci		mr_device_priv_data->is_tm_capable =
193362306a36Sopenharmony_ci			pd_sync->seq[pd_index].capability.tmCapable;
193462306a36Sopenharmony_ci	}
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci	if (is_target_prop && instance->tgt_prop->reset_tmo) {
193762306a36Sopenharmony_ci		/*
193862306a36Sopenharmony_ci		 * If FW provides a target reset timeout value, driver will use
193962306a36Sopenharmony_ci		 * it. If not set, fallback to default values.
194062306a36Sopenharmony_ci		 */
194162306a36Sopenharmony_ci		mr_device_priv_data->target_reset_tmo =
194262306a36Sopenharmony_ci			min_t(u8, instance->max_reset_tmo,
194362306a36Sopenharmony_ci			      instance->tgt_prop->reset_tmo);
194462306a36Sopenharmony_ci		mr_device_priv_data->task_abort_tmo = instance->task_abort_tmo;
194562306a36Sopenharmony_ci	} else {
194662306a36Sopenharmony_ci		mr_device_priv_data->target_reset_tmo =
194762306a36Sopenharmony_ci						MEGASAS_DEFAULT_TM_TIMEOUT;
194862306a36Sopenharmony_ci		mr_device_priv_data->task_abort_tmo =
194962306a36Sopenharmony_ci						MEGASAS_DEFAULT_TM_TIMEOUT;
195062306a36Sopenharmony_ci	}
195162306a36Sopenharmony_ci}
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_ci/*
195462306a36Sopenharmony_ci * megasas_set_nvme_device_properties -
195562306a36Sopenharmony_ci * set nomerges=2
195662306a36Sopenharmony_ci * set virtual page boundary = 4K (current mr_nvme_pg_size is 4K).
195762306a36Sopenharmony_ci * set maximum io transfer = MDTS of NVME device provided by MR firmware.
195862306a36Sopenharmony_ci *
195962306a36Sopenharmony_ci * MR firmware provides value in KB. Caller of this function converts
196062306a36Sopenharmony_ci * kb into bytes.
196162306a36Sopenharmony_ci *
196262306a36Sopenharmony_ci * e.a MDTS=5 means 2^5 * nvme page size. (In case of 4K page size,
196362306a36Sopenharmony_ci * MR firmware provides value 128 as (32 * 4K) = 128K.
196462306a36Sopenharmony_ci *
196562306a36Sopenharmony_ci * @sdev:				scsi device
196662306a36Sopenharmony_ci * @max_io_size:				maximum io transfer size
196762306a36Sopenharmony_ci *
196862306a36Sopenharmony_ci */
196962306a36Sopenharmony_cistatic inline void
197062306a36Sopenharmony_cimegasas_set_nvme_device_properties(struct scsi_device *sdev, u32 max_io_size)
197162306a36Sopenharmony_ci{
197262306a36Sopenharmony_ci	struct megasas_instance *instance;
197362306a36Sopenharmony_ci	u32 mr_nvme_pg_size;
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci	instance = (struct megasas_instance *)sdev->host->hostdata;
197662306a36Sopenharmony_ci	mr_nvme_pg_size = max_t(u32, instance->nvme_page_size,
197762306a36Sopenharmony_ci				MR_DEFAULT_NVME_PAGE_SIZE);
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_ci	blk_queue_max_hw_sectors(sdev->request_queue, (max_io_size / 512));
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci	blk_queue_flag_set(QUEUE_FLAG_NOMERGES, sdev->request_queue);
198262306a36Sopenharmony_ci	blk_queue_virt_boundary(sdev->request_queue, mr_nvme_pg_size - 1);
198362306a36Sopenharmony_ci}
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci/*
198662306a36Sopenharmony_ci * megasas_set_fw_assisted_qd -
198762306a36Sopenharmony_ci * set device queue depth to can_queue
198862306a36Sopenharmony_ci * set device queue depth to fw assisted qd
198962306a36Sopenharmony_ci *
199062306a36Sopenharmony_ci * @sdev:				scsi device
199162306a36Sopenharmony_ci * @is_target_prop			true, if fw provided target properties.
199262306a36Sopenharmony_ci */
199362306a36Sopenharmony_cistatic void megasas_set_fw_assisted_qd(struct scsi_device *sdev,
199462306a36Sopenharmony_ci						 bool is_target_prop)
199562306a36Sopenharmony_ci{
199662306a36Sopenharmony_ci	u8 interface_type;
199762306a36Sopenharmony_ci	u32 device_qd = MEGASAS_DEFAULT_CMD_PER_LUN;
199862306a36Sopenharmony_ci	u32 tgt_device_qd;
199962306a36Sopenharmony_ci	struct megasas_instance *instance;
200062306a36Sopenharmony_ci	struct MR_PRIV_DEVICE *mr_device_priv_data;
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci	instance = megasas_lookup_instance(sdev->host->host_no);
200362306a36Sopenharmony_ci	mr_device_priv_data = sdev->hostdata;
200462306a36Sopenharmony_ci	interface_type  = mr_device_priv_data->interface_type;
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	switch (interface_type) {
200762306a36Sopenharmony_ci	case SAS_PD:
200862306a36Sopenharmony_ci		device_qd = MEGASAS_SAS_QD;
200962306a36Sopenharmony_ci		break;
201062306a36Sopenharmony_ci	case SATA_PD:
201162306a36Sopenharmony_ci		device_qd = MEGASAS_SATA_QD;
201262306a36Sopenharmony_ci		break;
201362306a36Sopenharmony_ci	case NVME_PD:
201462306a36Sopenharmony_ci		device_qd = MEGASAS_NVME_QD;
201562306a36Sopenharmony_ci		break;
201662306a36Sopenharmony_ci	}
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_ci	if (is_target_prop) {
201962306a36Sopenharmony_ci		tgt_device_qd = le32_to_cpu(instance->tgt_prop->device_qdepth);
202062306a36Sopenharmony_ci		if (tgt_device_qd)
202162306a36Sopenharmony_ci			device_qd = min(instance->host->can_queue,
202262306a36Sopenharmony_ci					(int)tgt_device_qd);
202362306a36Sopenharmony_ci	}
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci	if (instance->enable_sdev_max_qd && interface_type != UNKNOWN_DRIVE)
202662306a36Sopenharmony_ci		device_qd = instance->host->can_queue;
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	scsi_change_queue_depth(sdev, device_qd);
202962306a36Sopenharmony_ci}
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci/*
203262306a36Sopenharmony_ci * megasas_set_static_target_properties -
203362306a36Sopenharmony_ci * Device property set by driver are static and it is not required to be
203462306a36Sopenharmony_ci * updated after OCR.
203562306a36Sopenharmony_ci *
203662306a36Sopenharmony_ci * set io timeout
203762306a36Sopenharmony_ci * set device queue depth
203862306a36Sopenharmony_ci * set nvme device properties. see - megasas_set_nvme_device_properties
203962306a36Sopenharmony_ci *
204062306a36Sopenharmony_ci * @sdev:				scsi device
204162306a36Sopenharmony_ci * @is_target_prop			true, if fw provided target properties.
204262306a36Sopenharmony_ci */
204362306a36Sopenharmony_cistatic void megasas_set_static_target_properties(struct scsi_device *sdev,
204462306a36Sopenharmony_ci						 bool is_target_prop)
204562306a36Sopenharmony_ci{
204662306a36Sopenharmony_ci	u32 max_io_size_kb = MR_DEFAULT_NVME_MDTS_KB;
204762306a36Sopenharmony_ci	struct megasas_instance *instance;
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci	instance = megasas_lookup_instance(sdev->host->host_no);
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_ci	/*
205262306a36Sopenharmony_ci	 * The RAID firmware may require extended timeouts.
205362306a36Sopenharmony_ci	 */
205462306a36Sopenharmony_ci	blk_queue_rq_timeout(sdev->request_queue, scmd_timeout * HZ);
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	/* max_io_size_kb will be set to non zero for
205762306a36Sopenharmony_ci	 * nvme based vd and syspd.
205862306a36Sopenharmony_ci	 */
205962306a36Sopenharmony_ci	if (is_target_prop)
206062306a36Sopenharmony_ci		max_io_size_kb = le32_to_cpu(instance->tgt_prop->max_io_size_kb);
206162306a36Sopenharmony_ci
206262306a36Sopenharmony_ci	if (instance->nvme_page_size && max_io_size_kb)
206362306a36Sopenharmony_ci		megasas_set_nvme_device_properties(sdev, (max_io_size_kb << 10));
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci	megasas_set_fw_assisted_qd(sdev, is_target_prop);
206662306a36Sopenharmony_ci}
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_cistatic int megasas_slave_configure(struct scsi_device *sdev)
207062306a36Sopenharmony_ci{
207162306a36Sopenharmony_ci	u16 pd_index = 0;
207262306a36Sopenharmony_ci	struct megasas_instance *instance;
207362306a36Sopenharmony_ci	int ret_target_prop = DCMD_FAILED;
207462306a36Sopenharmony_ci	bool is_target_prop = false;
207562306a36Sopenharmony_ci
207662306a36Sopenharmony_ci	instance = megasas_lookup_instance(sdev->host->host_no);
207762306a36Sopenharmony_ci	if (instance->pd_list_not_supported) {
207862306a36Sopenharmony_ci		if (!MEGASAS_IS_LOGICAL(sdev) && sdev->type == TYPE_DISK) {
207962306a36Sopenharmony_ci			pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
208062306a36Sopenharmony_ci				sdev->id;
208162306a36Sopenharmony_ci			if (instance->pd_list[pd_index].driveState !=
208262306a36Sopenharmony_ci				MR_PD_STATE_SYSTEM)
208362306a36Sopenharmony_ci				return -ENXIO;
208462306a36Sopenharmony_ci		}
208562306a36Sopenharmony_ci	}
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci	mutex_lock(&instance->reset_mutex);
208862306a36Sopenharmony_ci	/* Send DCMD to Firmware and cache the information */
208962306a36Sopenharmony_ci	if ((instance->pd_info) && !MEGASAS_IS_LOGICAL(sdev))
209062306a36Sopenharmony_ci		megasas_get_pd_info(instance, sdev);
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci	/* Some ventura firmware may not have instance->nvme_page_size set.
209362306a36Sopenharmony_ci	 * Do not send MR_DCMD_DRV_GET_TARGET_PROP
209462306a36Sopenharmony_ci	 */
209562306a36Sopenharmony_ci	if ((instance->tgt_prop) && (instance->nvme_page_size))
209662306a36Sopenharmony_ci		ret_target_prop = megasas_get_target_prop(instance, sdev);
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_ci	is_target_prop = (ret_target_prop == DCMD_SUCCESS) ? true : false;
209962306a36Sopenharmony_ci	megasas_set_static_target_properties(sdev, is_target_prop);
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci	/* This sdev property may change post OCR */
210262306a36Sopenharmony_ci	megasas_set_dynamic_target_properties(sdev, is_target_prop);
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_ci	mutex_unlock(&instance->reset_mutex);
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci	return 0;
210762306a36Sopenharmony_ci}
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_cistatic int megasas_slave_alloc(struct scsi_device *sdev)
211062306a36Sopenharmony_ci{
211162306a36Sopenharmony_ci	u16 pd_index = 0, ld_tgt_id;
211262306a36Sopenharmony_ci	struct megasas_instance *instance ;
211362306a36Sopenharmony_ci	struct MR_PRIV_DEVICE *mr_device_priv_data;
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	instance = megasas_lookup_instance(sdev->host->host_no);
211662306a36Sopenharmony_ci	if (!MEGASAS_IS_LOGICAL(sdev)) {
211762306a36Sopenharmony_ci		/*
211862306a36Sopenharmony_ci		 * Open the OS scan to the SYSTEM PD
211962306a36Sopenharmony_ci		 */
212062306a36Sopenharmony_ci		pd_index =
212162306a36Sopenharmony_ci			(sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
212262306a36Sopenharmony_ci			sdev->id;
212362306a36Sopenharmony_ci		if ((instance->pd_list_not_supported ||
212462306a36Sopenharmony_ci			instance->pd_list[pd_index].driveState ==
212562306a36Sopenharmony_ci			MR_PD_STATE_SYSTEM)) {
212662306a36Sopenharmony_ci			goto scan_target;
212762306a36Sopenharmony_ci		}
212862306a36Sopenharmony_ci		return -ENXIO;
212962306a36Sopenharmony_ci	} else if (!MEGASAS_IS_LUN_VALID(sdev)) {
213062306a36Sopenharmony_ci		sdev_printk(KERN_INFO, sdev, "%s: invalid LUN\n", __func__);
213162306a36Sopenharmony_ci		return -ENXIO;
213262306a36Sopenharmony_ci	}
213362306a36Sopenharmony_ci
213462306a36Sopenharmony_ciscan_target:
213562306a36Sopenharmony_ci	mr_device_priv_data = kzalloc(sizeof(*mr_device_priv_data),
213662306a36Sopenharmony_ci					GFP_KERNEL);
213762306a36Sopenharmony_ci	if (!mr_device_priv_data)
213862306a36Sopenharmony_ci		return -ENOMEM;
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_ci	if (MEGASAS_IS_LOGICAL(sdev)) {
214162306a36Sopenharmony_ci		ld_tgt_id = MEGASAS_TARGET_ID(sdev);
214262306a36Sopenharmony_ci		instance->ld_tgtid_status[ld_tgt_id] = LD_TARGET_ID_ACTIVE;
214362306a36Sopenharmony_ci		if (megasas_dbg_lvl & LD_PD_DEBUG)
214462306a36Sopenharmony_ci			sdev_printk(KERN_INFO, sdev, "LD target ID %d created.\n", ld_tgt_id);
214562306a36Sopenharmony_ci	}
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci	sdev->hostdata = mr_device_priv_data;
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci	atomic_set(&mr_device_priv_data->r1_ldio_hint,
215062306a36Sopenharmony_ci		   instance->r1_ldio_hint_default);
215162306a36Sopenharmony_ci	return 0;
215262306a36Sopenharmony_ci}
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_cistatic void megasas_slave_destroy(struct scsi_device *sdev)
215562306a36Sopenharmony_ci{
215662306a36Sopenharmony_ci	u16 ld_tgt_id;
215762306a36Sopenharmony_ci	struct megasas_instance *instance;
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci	instance = megasas_lookup_instance(sdev->host->host_no);
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci	if (MEGASAS_IS_LOGICAL(sdev)) {
216262306a36Sopenharmony_ci		if (!MEGASAS_IS_LUN_VALID(sdev)) {
216362306a36Sopenharmony_ci			sdev_printk(KERN_INFO, sdev, "%s: invalid LUN\n", __func__);
216462306a36Sopenharmony_ci			return;
216562306a36Sopenharmony_ci		}
216662306a36Sopenharmony_ci		ld_tgt_id = MEGASAS_TARGET_ID(sdev);
216762306a36Sopenharmony_ci		instance->ld_tgtid_status[ld_tgt_id] = LD_TARGET_ID_DELETED;
216862306a36Sopenharmony_ci		if (megasas_dbg_lvl & LD_PD_DEBUG)
216962306a36Sopenharmony_ci			sdev_printk(KERN_INFO, sdev,
217062306a36Sopenharmony_ci				    "LD target ID %d removed from OS stack\n", ld_tgt_id);
217162306a36Sopenharmony_ci	}
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci	kfree(sdev->hostdata);
217462306a36Sopenharmony_ci	sdev->hostdata = NULL;
217562306a36Sopenharmony_ci}
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_ci/*
217862306a36Sopenharmony_ci* megasas_complete_outstanding_ioctls - Complete outstanding ioctls after a
217962306a36Sopenharmony_ci*                                       kill adapter
218062306a36Sopenharmony_ci* @instance:				Adapter soft state
218162306a36Sopenharmony_ci*
218262306a36Sopenharmony_ci*/
218362306a36Sopenharmony_cistatic void megasas_complete_outstanding_ioctls(struct megasas_instance *instance)
218462306a36Sopenharmony_ci{
218562306a36Sopenharmony_ci	int i;
218662306a36Sopenharmony_ci	struct megasas_cmd *cmd_mfi;
218762306a36Sopenharmony_ci	struct megasas_cmd_fusion *cmd_fusion;
218862306a36Sopenharmony_ci	struct fusion_context *fusion = instance->ctrl_context;
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	/* Find all outstanding ioctls */
219162306a36Sopenharmony_ci	if (fusion) {
219262306a36Sopenharmony_ci		for (i = 0; i < instance->max_fw_cmds; i++) {
219362306a36Sopenharmony_ci			cmd_fusion = fusion->cmd_list[i];
219462306a36Sopenharmony_ci			if (cmd_fusion->sync_cmd_idx != (u32)ULONG_MAX) {
219562306a36Sopenharmony_ci				cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx];
219662306a36Sopenharmony_ci				if (cmd_mfi->sync_cmd &&
219762306a36Sopenharmony_ci				    (cmd_mfi->frame->hdr.cmd != MFI_CMD_ABORT)) {
219862306a36Sopenharmony_ci					cmd_mfi->frame->hdr.cmd_status =
219962306a36Sopenharmony_ci							MFI_STAT_WRONG_STATE;
220062306a36Sopenharmony_ci					megasas_complete_cmd(instance,
220162306a36Sopenharmony_ci							     cmd_mfi, DID_OK);
220262306a36Sopenharmony_ci				}
220362306a36Sopenharmony_ci			}
220462306a36Sopenharmony_ci		}
220562306a36Sopenharmony_ci	} else {
220662306a36Sopenharmony_ci		for (i = 0; i < instance->max_fw_cmds; i++) {
220762306a36Sopenharmony_ci			cmd_mfi = instance->cmd_list[i];
220862306a36Sopenharmony_ci			if (cmd_mfi->sync_cmd && cmd_mfi->frame->hdr.cmd !=
220962306a36Sopenharmony_ci				MFI_CMD_ABORT)
221062306a36Sopenharmony_ci				megasas_complete_cmd(instance, cmd_mfi, DID_OK);
221162306a36Sopenharmony_ci		}
221262306a36Sopenharmony_ci	}
221362306a36Sopenharmony_ci}
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_civoid megaraid_sas_kill_hba(struct megasas_instance *instance)
221762306a36Sopenharmony_ci{
221862306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
221962306a36Sopenharmony_ci		dev_warn(&instance->pdev->dev,
222062306a36Sopenharmony_ci			 "Adapter already dead, skipping kill HBA\n");
222162306a36Sopenharmony_ci		return;
222262306a36Sopenharmony_ci	}
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_ci	/* Set critical error to block I/O & ioctls in case caller didn't */
222562306a36Sopenharmony_ci	atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
222662306a36Sopenharmony_ci	/* Wait 1 second to ensure IO or ioctls in build have posted */
222762306a36Sopenharmony_ci	msleep(1000);
222862306a36Sopenharmony_ci	if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
222962306a36Sopenharmony_ci		(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
223062306a36Sopenharmony_ci		(instance->adapter_type != MFI_SERIES)) {
223162306a36Sopenharmony_ci		if (!instance->requestorId) {
223262306a36Sopenharmony_ci			writel(MFI_STOP_ADP, &instance->reg_set->doorbell);
223362306a36Sopenharmony_ci			/* Flush */
223462306a36Sopenharmony_ci			readl(&instance->reg_set->doorbell);
223562306a36Sopenharmony_ci		}
223662306a36Sopenharmony_ci		if (instance->requestorId && instance->peerIsPresent)
223762306a36Sopenharmony_ci			memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
223862306a36Sopenharmony_ci	} else {
223962306a36Sopenharmony_ci		writel(MFI_STOP_ADP,
224062306a36Sopenharmony_ci			&instance->reg_set->inbound_doorbell);
224162306a36Sopenharmony_ci	}
224262306a36Sopenharmony_ci	/* Complete outstanding ioctls when adapter is killed */
224362306a36Sopenharmony_ci	megasas_complete_outstanding_ioctls(instance);
224462306a36Sopenharmony_ci}
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci /**
224762306a36Sopenharmony_ci  * megasas_check_and_restore_queue_depth - Check if queue depth needs to be
224862306a36Sopenharmony_ci  *					restored to max value
224962306a36Sopenharmony_ci  * @instance:			Adapter soft state
225062306a36Sopenharmony_ci  *
225162306a36Sopenharmony_ci  */
225262306a36Sopenharmony_civoid
225362306a36Sopenharmony_cimegasas_check_and_restore_queue_depth(struct megasas_instance *instance)
225462306a36Sopenharmony_ci{
225562306a36Sopenharmony_ci	unsigned long flags;
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_ci	if (instance->flag & MEGASAS_FW_BUSY
225862306a36Sopenharmony_ci	    && time_after(jiffies, instance->last_time + 5 * HZ)
225962306a36Sopenharmony_ci	    && atomic_read(&instance->fw_outstanding) <
226062306a36Sopenharmony_ci	    instance->throttlequeuedepth + 1) {
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci		spin_lock_irqsave(instance->host->host_lock, flags);
226362306a36Sopenharmony_ci		instance->flag &= ~MEGASAS_FW_BUSY;
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci		instance->host->can_queue = instance->cur_can_queue;
226662306a36Sopenharmony_ci		spin_unlock_irqrestore(instance->host->host_lock, flags);
226762306a36Sopenharmony_ci	}
226862306a36Sopenharmony_ci}
226962306a36Sopenharmony_ci
227062306a36Sopenharmony_ci/**
227162306a36Sopenharmony_ci * megasas_complete_cmd_dpc	 -	Returns FW's controller structure
227262306a36Sopenharmony_ci * @instance_addr:			Address of adapter soft state
227362306a36Sopenharmony_ci *
227462306a36Sopenharmony_ci * Tasklet to complete cmds
227562306a36Sopenharmony_ci */
227662306a36Sopenharmony_cistatic void megasas_complete_cmd_dpc(unsigned long instance_addr)
227762306a36Sopenharmony_ci{
227862306a36Sopenharmony_ci	u32 producer;
227962306a36Sopenharmony_ci	u32 consumer;
228062306a36Sopenharmony_ci	u32 context;
228162306a36Sopenharmony_ci	struct megasas_cmd *cmd;
228262306a36Sopenharmony_ci	struct megasas_instance *instance =
228362306a36Sopenharmony_ci				(struct megasas_instance *)instance_addr;
228462306a36Sopenharmony_ci	unsigned long flags;
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_ci	/* If we have already declared adapter dead, donot complete cmds */
228762306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
228862306a36Sopenharmony_ci		return;
228962306a36Sopenharmony_ci
229062306a36Sopenharmony_ci	spin_lock_irqsave(&instance->completion_lock, flags);
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci	producer = le32_to_cpu(*instance->producer);
229362306a36Sopenharmony_ci	consumer = le32_to_cpu(*instance->consumer);
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci	while (consumer != producer) {
229662306a36Sopenharmony_ci		context = le32_to_cpu(instance->reply_queue[consumer]);
229762306a36Sopenharmony_ci		if (context >= instance->max_fw_cmds) {
229862306a36Sopenharmony_ci			dev_err(&instance->pdev->dev, "Unexpected context value %x\n",
229962306a36Sopenharmony_ci				context);
230062306a36Sopenharmony_ci			BUG();
230162306a36Sopenharmony_ci		}
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci		cmd = instance->cmd_list[context];
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_ci		megasas_complete_cmd(instance, cmd, DID_OK);
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_ci		consumer++;
230862306a36Sopenharmony_ci		if (consumer == (instance->max_fw_cmds + 1)) {
230962306a36Sopenharmony_ci			consumer = 0;
231062306a36Sopenharmony_ci		}
231162306a36Sopenharmony_ci	}
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_ci	*instance->consumer = cpu_to_le32(producer);
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_ci	spin_unlock_irqrestore(&instance->completion_lock, flags);
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_ci	/*
231862306a36Sopenharmony_ci	 * Check if we can restore can_queue
231962306a36Sopenharmony_ci	 */
232062306a36Sopenharmony_ci	megasas_check_and_restore_queue_depth(instance);
232162306a36Sopenharmony_ci}
232262306a36Sopenharmony_ci
232362306a36Sopenharmony_cistatic void megasas_sriov_heartbeat_handler(struct timer_list *t);
232462306a36Sopenharmony_ci
232562306a36Sopenharmony_ci/**
232662306a36Sopenharmony_ci * megasas_start_timer - Initializes sriov heartbeat timer object
232762306a36Sopenharmony_ci * @instance:		Adapter soft state
232862306a36Sopenharmony_ci *
232962306a36Sopenharmony_ci */
233062306a36Sopenharmony_civoid megasas_start_timer(struct megasas_instance *instance)
233162306a36Sopenharmony_ci{
233262306a36Sopenharmony_ci	struct timer_list *timer = &instance->sriov_heartbeat_timer;
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci	timer_setup(timer, megasas_sriov_heartbeat_handler, 0);
233562306a36Sopenharmony_ci	timer->expires = jiffies + MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF;
233662306a36Sopenharmony_ci	add_timer(timer);
233762306a36Sopenharmony_ci}
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_cistatic void
234062306a36Sopenharmony_cimegasas_internal_reset_defer_cmds(struct megasas_instance *instance);
234162306a36Sopenharmony_ci
234262306a36Sopenharmony_cistatic void
234362306a36Sopenharmony_ciprocess_fw_state_change_wq(struct work_struct *work);
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_cistatic void megasas_do_ocr(struct megasas_instance *instance)
234662306a36Sopenharmony_ci{
234762306a36Sopenharmony_ci	if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) ||
234862306a36Sopenharmony_ci	(instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) ||
234962306a36Sopenharmony_ci	(instance->pdev->device == PCI_DEVICE_ID_LSI_VERDE_ZCR)) {
235062306a36Sopenharmony_ci		*instance->consumer = cpu_to_le32(MEGASAS_ADPRESET_INPROG_SIGN);
235162306a36Sopenharmony_ci	}
235262306a36Sopenharmony_ci	instance->instancet->disable_intr(instance);
235362306a36Sopenharmony_ci	atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
235462306a36Sopenharmony_ci	instance->issuepend_done = 0;
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci	atomic_set(&instance->fw_outstanding, 0);
235762306a36Sopenharmony_ci	megasas_internal_reset_defer_cmds(instance);
235862306a36Sopenharmony_ci	process_fw_state_change_wq(&instance->work_init);
235962306a36Sopenharmony_ci}
236062306a36Sopenharmony_ci
236162306a36Sopenharmony_cistatic int megasas_get_ld_vf_affiliation_111(struct megasas_instance *instance,
236262306a36Sopenharmony_ci					    int initial)
236362306a36Sopenharmony_ci{
236462306a36Sopenharmony_ci	struct megasas_cmd *cmd;
236562306a36Sopenharmony_ci	struct megasas_dcmd_frame *dcmd;
236662306a36Sopenharmony_ci	struct MR_LD_VF_AFFILIATION_111 *new_affiliation_111 = NULL;
236762306a36Sopenharmony_ci	dma_addr_t new_affiliation_111_h;
236862306a36Sopenharmony_ci	int ld, retval = 0;
236962306a36Sopenharmony_ci	u8 thisVf;
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_ci	cmd = megasas_get_cmd(instance);
237262306a36Sopenharmony_ci
237362306a36Sopenharmony_ci	if (!cmd) {
237462306a36Sopenharmony_ci		dev_printk(KERN_DEBUG, &instance->pdev->dev, "megasas_get_ld_vf_affiliation_111:"
237562306a36Sopenharmony_ci		       "Failed to get cmd for scsi%d\n",
237662306a36Sopenharmony_ci			instance->host->host_no);
237762306a36Sopenharmony_ci		return -ENOMEM;
237862306a36Sopenharmony_ci	}
237962306a36Sopenharmony_ci
238062306a36Sopenharmony_ci	dcmd = &cmd->frame->dcmd;
238162306a36Sopenharmony_ci
238262306a36Sopenharmony_ci	if (!instance->vf_affiliation_111) {
238362306a36Sopenharmony_ci		dev_warn(&instance->pdev->dev, "SR-IOV: Couldn't get LD/VF "
238462306a36Sopenharmony_ci		       "affiliation for scsi%d\n", instance->host->host_no);
238562306a36Sopenharmony_ci		megasas_return_cmd(instance, cmd);
238662306a36Sopenharmony_ci		return -ENOMEM;
238762306a36Sopenharmony_ci	}
238862306a36Sopenharmony_ci
238962306a36Sopenharmony_ci	if (initial)
239062306a36Sopenharmony_ci			memset(instance->vf_affiliation_111, 0,
239162306a36Sopenharmony_ci			       sizeof(struct MR_LD_VF_AFFILIATION_111));
239262306a36Sopenharmony_ci	else {
239362306a36Sopenharmony_ci		new_affiliation_111 =
239462306a36Sopenharmony_ci			dma_alloc_coherent(&instance->pdev->dev,
239562306a36Sopenharmony_ci					   sizeof(struct MR_LD_VF_AFFILIATION_111),
239662306a36Sopenharmony_ci					   &new_affiliation_111_h, GFP_KERNEL);
239762306a36Sopenharmony_ci		if (!new_affiliation_111) {
239862306a36Sopenharmony_ci			dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate "
239962306a36Sopenharmony_ci			       "memory for new affiliation for scsi%d\n",
240062306a36Sopenharmony_ci			       instance->host->host_no);
240162306a36Sopenharmony_ci			megasas_return_cmd(instance, cmd);
240262306a36Sopenharmony_ci			return -ENOMEM;
240362306a36Sopenharmony_ci		}
240462306a36Sopenharmony_ci	}
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_ci	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_ci	dcmd->cmd = MFI_CMD_DCMD;
240962306a36Sopenharmony_ci	dcmd->cmd_status = MFI_STAT_INVALID_STATUS;
241062306a36Sopenharmony_ci	dcmd->sge_count = 1;
241162306a36Sopenharmony_ci	dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_BOTH);
241262306a36Sopenharmony_ci	dcmd->timeout = 0;
241362306a36Sopenharmony_ci	dcmd->pad_0 = 0;
241462306a36Sopenharmony_ci	dcmd->data_xfer_len =
241562306a36Sopenharmony_ci		cpu_to_le32(sizeof(struct MR_LD_VF_AFFILIATION_111));
241662306a36Sopenharmony_ci	dcmd->opcode = cpu_to_le32(MR_DCMD_LD_VF_MAP_GET_ALL_LDS_111);
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_ci	if (initial)
241962306a36Sopenharmony_ci		dcmd->sgl.sge32[0].phys_addr =
242062306a36Sopenharmony_ci			cpu_to_le32(instance->vf_affiliation_111_h);
242162306a36Sopenharmony_ci	else
242262306a36Sopenharmony_ci		dcmd->sgl.sge32[0].phys_addr =
242362306a36Sopenharmony_ci			cpu_to_le32(new_affiliation_111_h);
242462306a36Sopenharmony_ci
242562306a36Sopenharmony_ci	dcmd->sgl.sge32[0].length = cpu_to_le32(
242662306a36Sopenharmony_ci		sizeof(struct MR_LD_VF_AFFILIATION_111));
242762306a36Sopenharmony_ci
242862306a36Sopenharmony_ci	dev_warn(&instance->pdev->dev, "SR-IOV: Getting LD/VF affiliation for "
242962306a36Sopenharmony_ci	       "scsi%d\n", instance->host->host_no);
243062306a36Sopenharmony_ci
243162306a36Sopenharmony_ci	if (megasas_issue_blocked_cmd(instance, cmd, 0) != DCMD_SUCCESS) {
243262306a36Sopenharmony_ci		dev_warn(&instance->pdev->dev, "SR-IOV: LD/VF affiliation DCMD"
243362306a36Sopenharmony_ci		       " failed with status 0x%x for scsi%d\n",
243462306a36Sopenharmony_ci		       dcmd->cmd_status, instance->host->host_no);
243562306a36Sopenharmony_ci		retval = 1; /* Do a scan if we couldn't get affiliation */
243662306a36Sopenharmony_ci		goto out;
243762306a36Sopenharmony_ci	}
243862306a36Sopenharmony_ci
243962306a36Sopenharmony_ci	if (!initial) {
244062306a36Sopenharmony_ci		thisVf = new_affiliation_111->thisVf;
244162306a36Sopenharmony_ci		for (ld = 0 ; ld < new_affiliation_111->vdCount; ld++)
244262306a36Sopenharmony_ci			if (instance->vf_affiliation_111->map[ld].policy[thisVf] !=
244362306a36Sopenharmony_ci			    new_affiliation_111->map[ld].policy[thisVf]) {
244462306a36Sopenharmony_ci				dev_warn(&instance->pdev->dev, "SR-IOV: "
244562306a36Sopenharmony_ci				       "Got new LD/VF affiliation for scsi%d\n",
244662306a36Sopenharmony_ci				       instance->host->host_no);
244762306a36Sopenharmony_ci				memcpy(instance->vf_affiliation_111,
244862306a36Sopenharmony_ci				       new_affiliation_111,
244962306a36Sopenharmony_ci				       sizeof(struct MR_LD_VF_AFFILIATION_111));
245062306a36Sopenharmony_ci				retval = 1;
245162306a36Sopenharmony_ci				goto out;
245262306a36Sopenharmony_ci			}
245362306a36Sopenharmony_ci	}
245462306a36Sopenharmony_ciout:
245562306a36Sopenharmony_ci	if (new_affiliation_111) {
245662306a36Sopenharmony_ci		dma_free_coherent(&instance->pdev->dev,
245762306a36Sopenharmony_ci				    sizeof(struct MR_LD_VF_AFFILIATION_111),
245862306a36Sopenharmony_ci				    new_affiliation_111,
245962306a36Sopenharmony_ci				    new_affiliation_111_h);
246062306a36Sopenharmony_ci	}
246162306a36Sopenharmony_ci
246262306a36Sopenharmony_ci	megasas_return_cmd(instance, cmd);
246362306a36Sopenharmony_ci
246462306a36Sopenharmony_ci	return retval;
246562306a36Sopenharmony_ci}
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_cistatic int megasas_get_ld_vf_affiliation_12(struct megasas_instance *instance,
246862306a36Sopenharmony_ci					    int initial)
246962306a36Sopenharmony_ci{
247062306a36Sopenharmony_ci	struct megasas_cmd *cmd;
247162306a36Sopenharmony_ci	struct megasas_dcmd_frame *dcmd;
247262306a36Sopenharmony_ci	struct MR_LD_VF_AFFILIATION *new_affiliation = NULL;
247362306a36Sopenharmony_ci	struct MR_LD_VF_MAP *newmap = NULL, *savedmap = NULL;
247462306a36Sopenharmony_ci	dma_addr_t new_affiliation_h;
247562306a36Sopenharmony_ci	int i, j, retval = 0, found = 0, doscan = 0;
247662306a36Sopenharmony_ci	u8 thisVf;
247762306a36Sopenharmony_ci
247862306a36Sopenharmony_ci	cmd = megasas_get_cmd(instance);
247962306a36Sopenharmony_ci
248062306a36Sopenharmony_ci	if (!cmd) {
248162306a36Sopenharmony_ci		dev_printk(KERN_DEBUG, &instance->pdev->dev, "megasas_get_ld_vf_affiliation12: "
248262306a36Sopenharmony_ci		       "Failed to get cmd for scsi%d\n",
248362306a36Sopenharmony_ci		       instance->host->host_no);
248462306a36Sopenharmony_ci		return -ENOMEM;
248562306a36Sopenharmony_ci	}
248662306a36Sopenharmony_ci
248762306a36Sopenharmony_ci	dcmd = &cmd->frame->dcmd;
248862306a36Sopenharmony_ci
248962306a36Sopenharmony_ci	if (!instance->vf_affiliation) {
249062306a36Sopenharmony_ci		dev_warn(&instance->pdev->dev, "SR-IOV: Couldn't get LD/VF "
249162306a36Sopenharmony_ci		       "affiliation for scsi%d\n", instance->host->host_no);
249262306a36Sopenharmony_ci		megasas_return_cmd(instance, cmd);
249362306a36Sopenharmony_ci		return -ENOMEM;
249462306a36Sopenharmony_ci	}
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci	if (initial)
249762306a36Sopenharmony_ci		memset(instance->vf_affiliation, 0, (MAX_LOGICAL_DRIVES + 1) *
249862306a36Sopenharmony_ci		       sizeof(struct MR_LD_VF_AFFILIATION));
249962306a36Sopenharmony_ci	else {
250062306a36Sopenharmony_ci		new_affiliation =
250162306a36Sopenharmony_ci			dma_alloc_coherent(&instance->pdev->dev,
250262306a36Sopenharmony_ci					   (MAX_LOGICAL_DRIVES + 1) * sizeof(struct MR_LD_VF_AFFILIATION),
250362306a36Sopenharmony_ci					   &new_affiliation_h, GFP_KERNEL);
250462306a36Sopenharmony_ci		if (!new_affiliation) {
250562306a36Sopenharmony_ci			dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate "
250662306a36Sopenharmony_ci			       "memory for new affiliation for scsi%d\n",
250762306a36Sopenharmony_ci			       instance->host->host_no);
250862306a36Sopenharmony_ci			megasas_return_cmd(instance, cmd);
250962306a36Sopenharmony_ci			return -ENOMEM;
251062306a36Sopenharmony_ci		}
251162306a36Sopenharmony_ci	}
251262306a36Sopenharmony_ci
251362306a36Sopenharmony_ci	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_ci	dcmd->cmd = MFI_CMD_DCMD;
251662306a36Sopenharmony_ci	dcmd->cmd_status = MFI_STAT_INVALID_STATUS;
251762306a36Sopenharmony_ci	dcmd->sge_count = 1;
251862306a36Sopenharmony_ci	dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_BOTH);
251962306a36Sopenharmony_ci	dcmd->timeout = 0;
252062306a36Sopenharmony_ci	dcmd->pad_0 = 0;
252162306a36Sopenharmony_ci	dcmd->data_xfer_len = cpu_to_le32((MAX_LOGICAL_DRIVES + 1) *
252262306a36Sopenharmony_ci		sizeof(struct MR_LD_VF_AFFILIATION));
252362306a36Sopenharmony_ci	dcmd->opcode = cpu_to_le32(MR_DCMD_LD_VF_MAP_GET_ALL_LDS);
252462306a36Sopenharmony_ci
252562306a36Sopenharmony_ci	if (initial)
252662306a36Sopenharmony_ci		dcmd->sgl.sge32[0].phys_addr =
252762306a36Sopenharmony_ci			cpu_to_le32(instance->vf_affiliation_h);
252862306a36Sopenharmony_ci	else
252962306a36Sopenharmony_ci		dcmd->sgl.sge32[0].phys_addr =
253062306a36Sopenharmony_ci			cpu_to_le32(new_affiliation_h);
253162306a36Sopenharmony_ci
253262306a36Sopenharmony_ci	dcmd->sgl.sge32[0].length = cpu_to_le32((MAX_LOGICAL_DRIVES + 1) *
253362306a36Sopenharmony_ci		sizeof(struct MR_LD_VF_AFFILIATION));
253462306a36Sopenharmony_ci
253562306a36Sopenharmony_ci	dev_warn(&instance->pdev->dev, "SR-IOV: Getting LD/VF affiliation for "
253662306a36Sopenharmony_ci	       "scsi%d\n", instance->host->host_no);
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_ci
253962306a36Sopenharmony_ci	if (megasas_issue_blocked_cmd(instance, cmd, 0) != DCMD_SUCCESS) {
254062306a36Sopenharmony_ci		dev_warn(&instance->pdev->dev, "SR-IOV: LD/VF affiliation DCMD"
254162306a36Sopenharmony_ci		       " failed with status 0x%x for scsi%d\n",
254262306a36Sopenharmony_ci		       dcmd->cmd_status, instance->host->host_no);
254362306a36Sopenharmony_ci		retval = 1; /* Do a scan if we couldn't get affiliation */
254462306a36Sopenharmony_ci		goto out;
254562306a36Sopenharmony_ci	}
254662306a36Sopenharmony_ci
254762306a36Sopenharmony_ci	if (!initial) {
254862306a36Sopenharmony_ci		if (!new_affiliation->ldCount) {
254962306a36Sopenharmony_ci			dev_warn(&instance->pdev->dev, "SR-IOV: Got new LD/VF "
255062306a36Sopenharmony_ci			       "affiliation for passive path for scsi%d\n",
255162306a36Sopenharmony_ci			       instance->host->host_no);
255262306a36Sopenharmony_ci			retval = 1;
255362306a36Sopenharmony_ci			goto out;
255462306a36Sopenharmony_ci		}
255562306a36Sopenharmony_ci		newmap = new_affiliation->map;
255662306a36Sopenharmony_ci		savedmap = instance->vf_affiliation->map;
255762306a36Sopenharmony_ci		thisVf = new_affiliation->thisVf;
255862306a36Sopenharmony_ci		for (i = 0 ; i < new_affiliation->ldCount; i++) {
255962306a36Sopenharmony_ci			found = 0;
256062306a36Sopenharmony_ci			for (j = 0; j < instance->vf_affiliation->ldCount;
256162306a36Sopenharmony_ci			     j++) {
256262306a36Sopenharmony_ci				if (newmap->ref.targetId ==
256362306a36Sopenharmony_ci				    savedmap->ref.targetId) {
256462306a36Sopenharmony_ci					found = 1;
256562306a36Sopenharmony_ci					if (newmap->policy[thisVf] !=
256662306a36Sopenharmony_ci					    savedmap->policy[thisVf]) {
256762306a36Sopenharmony_ci						doscan = 1;
256862306a36Sopenharmony_ci						goto out;
256962306a36Sopenharmony_ci					}
257062306a36Sopenharmony_ci				}
257162306a36Sopenharmony_ci				savedmap = (struct MR_LD_VF_MAP *)
257262306a36Sopenharmony_ci					((unsigned char *)savedmap +
257362306a36Sopenharmony_ci					 savedmap->size);
257462306a36Sopenharmony_ci			}
257562306a36Sopenharmony_ci			if (!found && newmap->policy[thisVf] !=
257662306a36Sopenharmony_ci			    MR_LD_ACCESS_HIDDEN) {
257762306a36Sopenharmony_ci				doscan = 1;
257862306a36Sopenharmony_ci				goto out;
257962306a36Sopenharmony_ci			}
258062306a36Sopenharmony_ci			newmap = (struct MR_LD_VF_MAP *)
258162306a36Sopenharmony_ci				((unsigned char *)newmap + newmap->size);
258262306a36Sopenharmony_ci		}
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci		newmap = new_affiliation->map;
258562306a36Sopenharmony_ci		savedmap = instance->vf_affiliation->map;
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ci		for (i = 0 ; i < instance->vf_affiliation->ldCount; i++) {
258862306a36Sopenharmony_ci			found = 0;
258962306a36Sopenharmony_ci			for (j = 0 ; j < new_affiliation->ldCount; j++) {
259062306a36Sopenharmony_ci				if (savedmap->ref.targetId ==
259162306a36Sopenharmony_ci				    newmap->ref.targetId) {
259262306a36Sopenharmony_ci					found = 1;
259362306a36Sopenharmony_ci					if (savedmap->policy[thisVf] !=
259462306a36Sopenharmony_ci					    newmap->policy[thisVf]) {
259562306a36Sopenharmony_ci						doscan = 1;
259662306a36Sopenharmony_ci						goto out;
259762306a36Sopenharmony_ci					}
259862306a36Sopenharmony_ci				}
259962306a36Sopenharmony_ci				newmap = (struct MR_LD_VF_MAP *)
260062306a36Sopenharmony_ci					((unsigned char *)newmap +
260162306a36Sopenharmony_ci					 newmap->size);
260262306a36Sopenharmony_ci			}
260362306a36Sopenharmony_ci			if (!found && savedmap->policy[thisVf] !=
260462306a36Sopenharmony_ci			    MR_LD_ACCESS_HIDDEN) {
260562306a36Sopenharmony_ci				doscan = 1;
260662306a36Sopenharmony_ci				goto out;
260762306a36Sopenharmony_ci			}
260862306a36Sopenharmony_ci			savedmap = (struct MR_LD_VF_MAP *)
260962306a36Sopenharmony_ci				((unsigned char *)savedmap +
261062306a36Sopenharmony_ci				 savedmap->size);
261162306a36Sopenharmony_ci		}
261262306a36Sopenharmony_ci	}
261362306a36Sopenharmony_ciout:
261462306a36Sopenharmony_ci	if (doscan) {
261562306a36Sopenharmony_ci		dev_warn(&instance->pdev->dev, "SR-IOV: Got new LD/VF "
261662306a36Sopenharmony_ci		       "affiliation for scsi%d\n", instance->host->host_no);
261762306a36Sopenharmony_ci		memcpy(instance->vf_affiliation, new_affiliation,
261862306a36Sopenharmony_ci		       new_affiliation->size);
261962306a36Sopenharmony_ci		retval = 1;
262062306a36Sopenharmony_ci	}
262162306a36Sopenharmony_ci
262262306a36Sopenharmony_ci	if (new_affiliation)
262362306a36Sopenharmony_ci		dma_free_coherent(&instance->pdev->dev,
262462306a36Sopenharmony_ci				    (MAX_LOGICAL_DRIVES + 1) *
262562306a36Sopenharmony_ci				    sizeof(struct MR_LD_VF_AFFILIATION),
262662306a36Sopenharmony_ci				    new_affiliation, new_affiliation_h);
262762306a36Sopenharmony_ci	megasas_return_cmd(instance, cmd);
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci	return retval;
263062306a36Sopenharmony_ci}
263162306a36Sopenharmony_ci
263262306a36Sopenharmony_ci/* This function will get the current SR-IOV LD/VF affiliation */
263362306a36Sopenharmony_cistatic int megasas_get_ld_vf_affiliation(struct megasas_instance *instance,
263462306a36Sopenharmony_ci	int initial)
263562306a36Sopenharmony_ci{
263662306a36Sopenharmony_ci	int retval;
263762306a36Sopenharmony_ci
263862306a36Sopenharmony_ci	if (instance->PlasmaFW111)
263962306a36Sopenharmony_ci		retval = megasas_get_ld_vf_affiliation_111(instance, initial);
264062306a36Sopenharmony_ci	else
264162306a36Sopenharmony_ci		retval = megasas_get_ld_vf_affiliation_12(instance, initial);
264262306a36Sopenharmony_ci	return retval;
264362306a36Sopenharmony_ci}
264462306a36Sopenharmony_ci
264562306a36Sopenharmony_ci/* This function will tell FW to start the SR-IOV heartbeat */
264662306a36Sopenharmony_ciint megasas_sriov_start_heartbeat(struct megasas_instance *instance,
264762306a36Sopenharmony_ci					 int initial)
264862306a36Sopenharmony_ci{
264962306a36Sopenharmony_ci	struct megasas_cmd *cmd;
265062306a36Sopenharmony_ci	struct megasas_dcmd_frame *dcmd;
265162306a36Sopenharmony_ci	int retval = 0;
265262306a36Sopenharmony_ci
265362306a36Sopenharmony_ci	cmd = megasas_get_cmd(instance);
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_ci	if (!cmd) {
265662306a36Sopenharmony_ci		dev_printk(KERN_DEBUG, &instance->pdev->dev, "megasas_sriov_start_heartbeat: "
265762306a36Sopenharmony_ci		       "Failed to get cmd for scsi%d\n",
265862306a36Sopenharmony_ci		       instance->host->host_no);
265962306a36Sopenharmony_ci		return -ENOMEM;
266062306a36Sopenharmony_ci	}
266162306a36Sopenharmony_ci
266262306a36Sopenharmony_ci	dcmd = &cmd->frame->dcmd;
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_ci	if (initial) {
266562306a36Sopenharmony_ci		instance->hb_host_mem =
266662306a36Sopenharmony_ci			dma_alloc_coherent(&instance->pdev->dev,
266762306a36Sopenharmony_ci					   sizeof(struct MR_CTRL_HB_HOST_MEM),
266862306a36Sopenharmony_ci					   &instance->hb_host_mem_h,
266962306a36Sopenharmony_ci					   GFP_KERNEL);
267062306a36Sopenharmony_ci		if (!instance->hb_host_mem) {
267162306a36Sopenharmony_ci			dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate"
267262306a36Sopenharmony_ci			       " memory for heartbeat host memory for scsi%d\n",
267362306a36Sopenharmony_ci			       instance->host->host_no);
267462306a36Sopenharmony_ci			retval = -ENOMEM;
267562306a36Sopenharmony_ci			goto out;
267662306a36Sopenharmony_ci		}
267762306a36Sopenharmony_ci	}
267862306a36Sopenharmony_ci
267962306a36Sopenharmony_ci	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
268062306a36Sopenharmony_ci
268162306a36Sopenharmony_ci	dcmd->mbox.s[0] = cpu_to_le16(sizeof(struct MR_CTRL_HB_HOST_MEM));
268262306a36Sopenharmony_ci	dcmd->cmd = MFI_CMD_DCMD;
268362306a36Sopenharmony_ci	dcmd->cmd_status = MFI_STAT_INVALID_STATUS;
268462306a36Sopenharmony_ci	dcmd->sge_count = 1;
268562306a36Sopenharmony_ci	dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_BOTH);
268662306a36Sopenharmony_ci	dcmd->timeout = 0;
268762306a36Sopenharmony_ci	dcmd->pad_0 = 0;
268862306a36Sopenharmony_ci	dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_CTRL_HB_HOST_MEM));
268962306a36Sopenharmony_ci	dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_SHARED_HOST_MEM_ALLOC);
269062306a36Sopenharmony_ci
269162306a36Sopenharmony_ci	megasas_set_dma_settings(instance, dcmd, instance->hb_host_mem_h,
269262306a36Sopenharmony_ci				 sizeof(struct MR_CTRL_HB_HOST_MEM));
269362306a36Sopenharmony_ci
269462306a36Sopenharmony_ci	dev_warn(&instance->pdev->dev, "SR-IOV: Starting heartbeat for scsi%d\n",
269562306a36Sopenharmony_ci	       instance->host->host_no);
269662306a36Sopenharmony_ci
269762306a36Sopenharmony_ci	if ((instance->adapter_type != MFI_SERIES) &&
269862306a36Sopenharmony_ci	    !instance->mask_interrupts)
269962306a36Sopenharmony_ci		retval = megasas_issue_blocked_cmd(instance, cmd,
270062306a36Sopenharmony_ci			MEGASAS_ROUTINE_WAIT_TIME_VF);
270162306a36Sopenharmony_ci	else
270262306a36Sopenharmony_ci		retval = megasas_issue_polled(instance, cmd);
270362306a36Sopenharmony_ci
270462306a36Sopenharmony_ci	if (retval) {
270562306a36Sopenharmony_ci		dev_warn(&instance->pdev->dev, "SR-IOV: MR_DCMD_CTRL_SHARED_HOST"
270662306a36Sopenharmony_ci			"_MEM_ALLOC DCMD %s for scsi%d\n",
270762306a36Sopenharmony_ci			(dcmd->cmd_status == MFI_STAT_INVALID_STATUS) ?
270862306a36Sopenharmony_ci			"timed out" : "failed", instance->host->host_no);
270962306a36Sopenharmony_ci		retval = 1;
271062306a36Sopenharmony_ci	}
271162306a36Sopenharmony_ci
271262306a36Sopenharmony_ciout:
271362306a36Sopenharmony_ci	megasas_return_cmd(instance, cmd);
271462306a36Sopenharmony_ci
271562306a36Sopenharmony_ci	return retval;
271662306a36Sopenharmony_ci}
271762306a36Sopenharmony_ci
271862306a36Sopenharmony_ci/* Handler for SR-IOV heartbeat */
271962306a36Sopenharmony_cistatic void megasas_sriov_heartbeat_handler(struct timer_list *t)
272062306a36Sopenharmony_ci{
272162306a36Sopenharmony_ci	struct megasas_instance *instance =
272262306a36Sopenharmony_ci		from_timer(instance, t, sriov_heartbeat_timer);
272362306a36Sopenharmony_ci
272462306a36Sopenharmony_ci	if (instance->hb_host_mem->HB.fwCounter !=
272562306a36Sopenharmony_ci	    instance->hb_host_mem->HB.driverCounter) {
272662306a36Sopenharmony_ci		instance->hb_host_mem->HB.driverCounter =
272762306a36Sopenharmony_ci			instance->hb_host_mem->HB.fwCounter;
272862306a36Sopenharmony_ci		mod_timer(&instance->sriov_heartbeat_timer,
272962306a36Sopenharmony_ci			  jiffies + MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
273062306a36Sopenharmony_ci	} else {
273162306a36Sopenharmony_ci		dev_warn(&instance->pdev->dev, "SR-IOV: Heartbeat never "
273262306a36Sopenharmony_ci		       "completed for scsi%d\n", instance->host->host_no);
273362306a36Sopenharmony_ci		schedule_work(&instance->work_init);
273462306a36Sopenharmony_ci	}
273562306a36Sopenharmony_ci}
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_ci/**
273862306a36Sopenharmony_ci * megasas_wait_for_outstanding -	Wait for all outstanding cmds
273962306a36Sopenharmony_ci * @instance:				Adapter soft state
274062306a36Sopenharmony_ci *
274162306a36Sopenharmony_ci * This function waits for up to MEGASAS_RESET_WAIT_TIME seconds for FW to
274262306a36Sopenharmony_ci * complete all its outstanding commands. Returns error if one or more IOs
274362306a36Sopenharmony_ci * are pending after this time period. It also marks the controller dead.
274462306a36Sopenharmony_ci */
274562306a36Sopenharmony_cistatic int megasas_wait_for_outstanding(struct megasas_instance *instance)
274662306a36Sopenharmony_ci{
274762306a36Sopenharmony_ci	int i, sl, outstanding;
274862306a36Sopenharmony_ci	u32 reset_index;
274962306a36Sopenharmony_ci	u32 wait_time = MEGASAS_RESET_WAIT_TIME;
275062306a36Sopenharmony_ci	unsigned long flags;
275162306a36Sopenharmony_ci	struct list_head clist_local;
275262306a36Sopenharmony_ci	struct megasas_cmd *reset_cmd;
275362306a36Sopenharmony_ci	u32 fw_state;
275462306a36Sopenharmony_ci
275562306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
275662306a36Sopenharmony_ci		dev_info(&instance->pdev->dev, "%s:%d HBA is killed.\n",
275762306a36Sopenharmony_ci		__func__, __LINE__);
275862306a36Sopenharmony_ci		return FAILED;
275962306a36Sopenharmony_ci	}
276062306a36Sopenharmony_ci
276162306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
276262306a36Sopenharmony_ci
276362306a36Sopenharmony_ci		INIT_LIST_HEAD(&clist_local);
276462306a36Sopenharmony_ci		spin_lock_irqsave(&instance->hba_lock, flags);
276562306a36Sopenharmony_ci		list_splice_init(&instance->internal_reset_pending_q,
276662306a36Sopenharmony_ci				&clist_local);
276762306a36Sopenharmony_ci		spin_unlock_irqrestore(&instance->hba_lock, flags);
276862306a36Sopenharmony_ci
276962306a36Sopenharmony_ci		dev_notice(&instance->pdev->dev, "HBA reset wait ...\n");
277062306a36Sopenharmony_ci		for (i = 0; i < wait_time; i++) {
277162306a36Sopenharmony_ci			msleep(1000);
277262306a36Sopenharmony_ci			if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL)
277362306a36Sopenharmony_ci				break;
277462306a36Sopenharmony_ci		}
277562306a36Sopenharmony_ci
277662306a36Sopenharmony_ci		if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
277762306a36Sopenharmony_ci			dev_notice(&instance->pdev->dev, "reset: Stopping HBA.\n");
277862306a36Sopenharmony_ci			atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
277962306a36Sopenharmony_ci			return FAILED;
278062306a36Sopenharmony_ci		}
278162306a36Sopenharmony_ci
278262306a36Sopenharmony_ci		reset_index = 0;
278362306a36Sopenharmony_ci		while (!list_empty(&clist_local)) {
278462306a36Sopenharmony_ci			reset_cmd = list_entry((&clist_local)->next,
278562306a36Sopenharmony_ci						struct megasas_cmd, list);
278662306a36Sopenharmony_ci			list_del_init(&reset_cmd->list);
278762306a36Sopenharmony_ci			if (reset_cmd->scmd) {
278862306a36Sopenharmony_ci				reset_cmd->scmd->result = DID_REQUEUE << 16;
278962306a36Sopenharmony_ci				dev_notice(&instance->pdev->dev, "%d:%p reset [%02x]\n",
279062306a36Sopenharmony_ci					reset_index, reset_cmd,
279162306a36Sopenharmony_ci					reset_cmd->scmd->cmnd[0]);
279262306a36Sopenharmony_ci
279362306a36Sopenharmony_ci				scsi_done(reset_cmd->scmd);
279462306a36Sopenharmony_ci				megasas_return_cmd(instance, reset_cmd);
279562306a36Sopenharmony_ci			} else if (reset_cmd->sync_cmd) {
279662306a36Sopenharmony_ci				dev_notice(&instance->pdev->dev, "%p synch cmds"
279762306a36Sopenharmony_ci						"reset queue\n",
279862306a36Sopenharmony_ci						reset_cmd);
279962306a36Sopenharmony_ci
280062306a36Sopenharmony_ci				reset_cmd->cmd_status_drv = DCMD_INIT;
280162306a36Sopenharmony_ci				instance->instancet->fire_cmd(instance,
280262306a36Sopenharmony_ci						reset_cmd->frame_phys_addr,
280362306a36Sopenharmony_ci						0, instance->reg_set);
280462306a36Sopenharmony_ci			} else {
280562306a36Sopenharmony_ci				dev_notice(&instance->pdev->dev, "%p unexpected"
280662306a36Sopenharmony_ci					"cmds lst\n",
280762306a36Sopenharmony_ci					reset_cmd);
280862306a36Sopenharmony_ci			}
280962306a36Sopenharmony_ci			reset_index++;
281062306a36Sopenharmony_ci		}
281162306a36Sopenharmony_ci
281262306a36Sopenharmony_ci		return SUCCESS;
281362306a36Sopenharmony_ci	}
281462306a36Sopenharmony_ci
281562306a36Sopenharmony_ci	for (i = 0; i < resetwaittime; i++) {
281662306a36Sopenharmony_ci		outstanding = atomic_read(&instance->fw_outstanding);
281762306a36Sopenharmony_ci
281862306a36Sopenharmony_ci		if (!outstanding)
281962306a36Sopenharmony_ci			break;
282062306a36Sopenharmony_ci
282162306a36Sopenharmony_ci		if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
282262306a36Sopenharmony_ci			dev_notice(&instance->pdev->dev, "[%2d]waiting for %d "
282362306a36Sopenharmony_ci			       "commands to complete\n",i,outstanding);
282462306a36Sopenharmony_ci			/*
282562306a36Sopenharmony_ci			 * Call cmd completion routine. Cmd to be
282662306a36Sopenharmony_ci			 * be completed directly without depending on isr.
282762306a36Sopenharmony_ci			 */
282862306a36Sopenharmony_ci			megasas_complete_cmd_dpc((unsigned long)instance);
282962306a36Sopenharmony_ci		}
283062306a36Sopenharmony_ci
283162306a36Sopenharmony_ci		msleep(1000);
283262306a36Sopenharmony_ci	}
283362306a36Sopenharmony_ci
283462306a36Sopenharmony_ci	i = 0;
283562306a36Sopenharmony_ci	outstanding = atomic_read(&instance->fw_outstanding);
283662306a36Sopenharmony_ci	fw_state = instance->instancet->read_fw_status_reg(instance) & MFI_STATE_MASK;
283762306a36Sopenharmony_ci
283862306a36Sopenharmony_ci	if ((!outstanding && (fw_state == MFI_STATE_OPERATIONAL)))
283962306a36Sopenharmony_ci		goto no_outstanding;
284062306a36Sopenharmony_ci
284162306a36Sopenharmony_ci	if (instance->disableOnlineCtrlReset)
284262306a36Sopenharmony_ci		goto kill_hba_and_failed;
284362306a36Sopenharmony_ci	do {
284462306a36Sopenharmony_ci		if ((fw_state == MFI_STATE_FAULT) || atomic_read(&instance->fw_outstanding)) {
284562306a36Sopenharmony_ci			dev_info(&instance->pdev->dev,
284662306a36Sopenharmony_ci				"%s:%d waiting_for_outstanding: before issue OCR. FW state = 0x%x, outstanding 0x%x\n",
284762306a36Sopenharmony_ci				__func__, __LINE__, fw_state, atomic_read(&instance->fw_outstanding));
284862306a36Sopenharmony_ci			if (i == 3)
284962306a36Sopenharmony_ci				goto kill_hba_and_failed;
285062306a36Sopenharmony_ci			megasas_do_ocr(instance);
285162306a36Sopenharmony_ci
285262306a36Sopenharmony_ci			if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
285362306a36Sopenharmony_ci				dev_info(&instance->pdev->dev, "%s:%d OCR failed and HBA is killed.\n",
285462306a36Sopenharmony_ci				__func__, __LINE__);
285562306a36Sopenharmony_ci				return FAILED;
285662306a36Sopenharmony_ci			}
285762306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "%s:%d waiting_for_outstanding: after issue OCR.\n",
285862306a36Sopenharmony_ci				__func__, __LINE__);
285962306a36Sopenharmony_ci
286062306a36Sopenharmony_ci			for (sl = 0; sl < 10; sl++)
286162306a36Sopenharmony_ci				msleep(500);
286262306a36Sopenharmony_ci
286362306a36Sopenharmony_ci			outstanding = atomic_read(&instance->fw_outstanding);
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci			fw_state = instance->instancet->read_fw_status_reg(instance) & MFI_STATE_MASK;
286662306a36Sopenharmony_ci			if ((!outstanding && (fw_state == MFI_STATE_OPERATIONAL)))
286762306a36Sopenharmony_ci				goto no_outstanding;
286862306a36Sopenharmony_ci		}
286962306a36Sopenharmony_ci		i++;
287062306a36Sopenharmony_ci	} while (i <= 3);
287162306a36Sopenharmony_ci
287262306a36Sopenharmony_cino_outstanding:
287362306a36Sopenharmony_ci
287462306a36Sopenharmony_ci	dev_info(&instance->pdev->dev, "%s:%d no more pending commands remain after reset handling.\n",
287562306a36Sopenharmony_ci		__func__, __LINE__);
287662306a36Sopenharmony_ci	return SUCCESS;
287762306a36Sopenharmony_ci
287862306a36Sopenharmony_cikill_hba_and_failed:
287962306a36Sopenharmony_ci
288062306a36Sopenharmony_ci	/* Reset not supported, kill adapter */
288162306a36Sopenharmony_ci	dev_info(&instance->pdev->dev, "%s:%d killing adapter scsi%d"
288262306a36Sopenharmony_ci		" disableOnlineCtrlReset %d fw_outstanding %d \n",
288362306a36Sopenharmony_ci		__func__, __LINE__, instance->host->host_no, instance->disableOnlineCtrlReset,
288462306a36Sopenharmony_ci		atomic_read(&instance->fw_outstanding));
288562306a36Sopenharmony_ci	megasas_dump_pending_frames(instance);
288662306a36Sopenharmony_ci	megaraid_sas_kill_hba(instance);
288762306a36Sopenharmony_ci
288862306a36Sopenharmony_ci	return FAILED;
288962306a36Sopenharmony_ci}
289062306a36Sopenharmony_ci
289162306a36Sopenharmony_ci/**
289262306a36Sopenharmony_ci * megasas_generic_reset -	Generic reset routine
289362306a36Sopenharmony_ci * @scmd:			Mid-layer SCSI command
289462306a36Sopenharmony_ci *
289562306a36Sopenharmony_ci * This routine implements a generic reset handler for device, bus and host
289662306a36Sopenharmony_ci * reset requests. Device, bus and host specific reset handlers can use this
289762306a36Sopenharmony_ci * function after they do their specific tasks.
289862306a36Sopenharmony_ci */
289962306a36Sopenharmony_cistatic int megasas_generic_reset(struct scsi_cmnd *scmd)
290062306a36Sopenharmony_ci{
290162306a36Sopenharmony_ci	int ret_val;
290262306a36Sopenharmony_ci	struct megasas_instance *instance;
290362306a36Sopenharmony_ci
290462306a36Sopenharmony_ci	instance = (struct megasas_instance *)scmd->device->host->hostdata;
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_ci	scmd_printk(KERN_NOTICE, scmd, "megasas: RESET cmd=%x retries=%x\n",
290762306a36Sopenharmony_ci		 scmd->cmnd[0], scmd->retries);
290862306a36Sopenharmony_ci
290962306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
291062306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "cannot recover from previous reset failures\n");
291162306a36Sopenharmony_ci		return FAILED;
291262306a36Sopenharmony_ci	}
291362306a36Sopenharmony_ci
291462306a36Sopenharmony_ci	ret_val = megasas_wait_for_outstanding(instance);
291562306a36Sopenharmony_ci	if (ret_val == SUCCESS)
291662306a36Sopenharmony_ci		dev_notice(&instance->pdev->dev, "reset successful\n");
291762306a36Sopenharmony_ci	else
291862306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "failed to do reset\n");
291962306a36Sopenharmony_ci
292062306a36Sopenharmony_ci	return ret_val;
292162306a36Sopenharmony_ci}
292262306a36Sopenharmony_ci
292362306a36Sopenharmony_ci/**
292462306a36Sopenharmony_ci * megasas_reset_timer - quiesce the adapter if required
292562306a36Sopenharmony_ci * @scmd:		scsi cmnd
292662306a36Sopenharmony_ci *
292762306a36Sopenharmony_ci * Sets the FW busy flag and reduces the host->can_queue if the
292862306a36Sopenharmony_ci * cmd has not been completed within the timeout period.
292962306a36Sopenharmony_ci */
293062306a36Sopenharmony_cistatic enum scsi_timeout_action megasas_reset_timer(struct scsi_cmnd *scmd)
293162306a36Sopenharmony_ci{
293262306a36Sopenharmony_ci	struct megasas_instance *instance;
293362306a36Sopenharmony_ci	unsigned long flags;
293462306a36Sopenharmony_ci
293562306a36Sopenharmony_ci	if (time_after(jiffies, scmd->jiffies_at_alloc +
293662306a36Sopenharmony_ci				(scmd_timeout * 2) * HZ)) {
293762306a36Sopenharmony_ci		return SCSI_EH_NOT_HANDLED;
293862306a36Sopenharmony_ci	}
293962306a36Sopenharmony_ci
294062306a36Sopenharmony_ci	instance = (struct megasas_instance *)scmd->device->host->hostdata;
294162306a36Sopenharmony_ci	if (!(instance->flag & MEGASAS_FW_BUSY)) {
294262306a36Sopenharmony_ci		/* FW is busy, throttle IO */
294362306a36Sopenharmony_ci		spin_lock_irqsave(instance->host->host_lock, flags);
294462306a36Sopenharmony_ci
294562306a36Sopenharmony_ci		instance->host->can_queue = instance->throttlequeuedepth;
294662306a36Sopenharmony_ci		instance->last_time = jiffies;
294762306a36Sopenharmony_ci		instance->flag |= MEGASAS_FW_BUSY;
294862306a36Sopenharmony_ci
294962306a36Sopenharmony_ci		spin_unlock_irqrestore(instance->host->host_lock, flags);
295062306a36Sopenharmony_ci	}
295162306a36Sopenharmony_ci	return SCSI_EH_RESET_TIMER;
295262306a36Sopenharmony_ci}
295362306a36Sopenharmony_ci
295462306a36Sopenharmony_ci/**
295562306a36Sopenharmony_ci * megasas_dump -	This function will print hexdump of provided buffer.
295662306a36Sopenharmony_ci * @buf:		Buffer to be dumped
295762306a36Sopenharmony_ci * @sz:		Size in bytes
295862306a36Sopenharmony_ci * @format:		Different formats of dumping e.g. format=n will
295962306a36Sopenharmony_ci *			cause only 'n' 32 bit words to be dumped in a single
296062306a36Sopenharmony_ci *			line.
296162306a36Sopenharmony_ci */
296262306a36Sopenharmony_ciinline void
296362306a36Sopenharmony_cimegasas_dump(void *buf, int sz, int format)
296462306a36Sopenharmony_ci{
296562306a36Sopenharmony_ci	int i;
296662306a36Sopenharmony_ci	__le32 *buf_loc = (__le32 *)buf;
296762306a36Sopenharmony_ci
296862306a36Sopenharmony_ci	for (i = 0; i < (sz / sizeof(__le32)); i++) {
296962306a36Sopenharmony_ci		if ((i % format) == 0) {
297062306a36Sopenharmony_ci			if (i != 0)
297162306a36Sopenharmony_ci				printk(KERN_CONT "\n");
297262306a36Sopenharmony_ci			printk(KERN_CONT "%08x: ", (i * 4));
297362306a36Sopenharmony_ci		}
297462306a36Sopenharmony_ci		printk(KERN_CONT "%08x ", le32_to_cpu(buf_loc[i]));
297562306a36Sopenharmony_ci	}
297662306a36Sopenharmony_ci	printk(KERN_CONT "\n");
297762306a36Sopenharmony_ci}
297862306a36Sopenharmony_ci
297962306a36Sopenharmony_ci/**
298062306a36Sopenharmony_ci * megasas_dump_reg_set -	This function will print hexdump of register set
298162306a36Sopenharmony_ci * @reg_set:	Register set to be dumped
298262306a36Sopenharmony_ci */
298362306a36Sopenharmony_ciinline void
298462306a36Sopenharmony_cimegasas_dump_reg_set(void __iomem *reg_set)
298562306a36Sopenharmony_ci{
298662306a36Sopenharmony_ci	unsigned int i, sz = 256;
298762306a36Sopenharmony_ci	u32 __iomem *reg = (u32 __iomem *)reg_set;
298862306a36Sopenharmony_ci
298962306a36Sopenharmony_ci	for (i = 0; i < (sz / sizeof(u32)); i++)
299062306a36Sopenharmony_ci		printk("%08x: %08x\n", (i * 4), readl(&reg[i]));
299162306a36Sopenharmony_ci}
299262306a36Sopenharmony_ci
299362306a36Sopenharmony_ci/**
299462306a36Sopenharmony_ci * megasas_dump_fusion_io -	This function will print key details
299562306a36Sopenharmony_ci *				of SCSI IO
299662306a36Sopenharmony_ci * @scmd:			SCSI command pointer of SCSI IO
299762306a36Sopenharmony_ci */
299862306a36Sopenharmony_civoid
299962306a36Sopenharmony_cimegasas_dump_fusion_io(struct scsi_cmnd *scmd)
300062306a36Sopenharmony_ci{
300162306a36Sopenharmony_ci	struct megasas_cmd_fusion *cmd = megasas_priv(scmd)->cmd_priv;
300262306a36Sopenharmony_ci	union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
300362306a36Sopenharmony_ci	struct megasas_instance *instance;
300462306a36Sopenharmony_ci
300562306a36Sopenharmony_ci	instance = (struct megasas_instance *)scmd->device->host->hostdata;
300662306a36Sopenharmony_ci
300762306a36Sopenharmony_ci	scmd_printk(KERN_INFO, scmd,
300862306a36Sopenharmony_ci		    "scmd: (0x%p)  retries: 0x%x  allowed: 0x%x\n",
300962306a36Sopenharmony_ci		    scmd, scmd->retries, scmd->allowed);
301062306a36Sopenharmony_ci	scsi_print_command(scmd);
301162306a36Sopenharmony_ci
301262306a36Sopenharmony_ci	if (cmd) {
301362306a36Sopenharmony_ci		req_desc = (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)cmd->request_desc;
301462306a36Sopenharmony_ci		scmd_printk(KERN_INFO, scmd, "Request descriptor details:\n");
301562306a36Sopenharmony_ci		scmd_printk(KERN_INFO, scmd,
301662306a36Sopenharmony_ci			    "RequestFlags:0x%x  MSIxIndex:0x%x  SMID:0x%x  LMID:0x%x  DevHandle:0x%x\n",
301762306a36Sopenharmony_ci			    req_desc->SCSIIO.RequestFlags,
301862306a36Sopenharmony_ci			    req_desc->SCSIIO.MSIxIndex, req_desc->SCSIIO.SMID,
301962306a36Sopenharmony_ci			    req_desc->SCSIIO.LMID, req_desc->SCSIIO.DevHandle);
302062306a36Sopenharmony_ci
302162306a36Sopenharmony_ci		printk(KERN_INFO "IO request frame:\n");
302262306a36Sopenharmony_ci		megasas_dump(cmd->io_request,
302362306a36Sopenharmony_ci			     MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE, 8);
302462306a36Sopenharmony_ci		printk(KERN_INFO "Chain frame:\n");
302562306a36Sopenharmony_ci		megasas_dump(cmd->sg_frame,
302662306a36Sopenharmony_ci			     instance->max_chain_frame_sz, 8);
302762306a36Sopenharmony_ci	}
302862306a36Sopenharmony_ci
302962306a36Sopenharmony_ci}
303062306a36Sopenharmony_ci
303162306a36Sopenharmony_ci/*
303262306a36Sopenharmony_ci * megasas_dump_sys_regs - This function will dump system registers through
303362306a36Sopenharmony_ci *			    sysfs.
303462306a36Sopenharmony_ci * @reg_set:		    Pointer to System register set.
303562306a36Sopenharmony_ci * @buf:		    Buffer to which output is to be written.
303662306a36Sopenharmony_ci * @return:		    Number of bytes written to buffer.
303762306a36Sopenharmony_ci */
303862306a36Sopenharmony_cistatic inline ssize_t
303962306a36Sopenharmony_cimegasas_dump_sys_regs(void __iomem *reg_set, char *buf)
304062306a36Sopenharmony_ci{
304162306a36Sopenharmony_ci	unsigned int i, sz = 256;
304262306a36Sopenharmony_ci	int bytes_wrote = 0;
304362306a36Sopenharmony_ci	char *loc = (char *)buf;
304462306a36Sopenharmony_ci	u32 __iomem *reg = (u32 __iomem *)reg_set;
304562306a36Sopenharmony_ci
304662306a36Sopenharmony_ci	for (i = 0; i < sz / sizeof(u32); i++) {
304762306a36Sopenharmony_ci		bytes_wrote += scnprintf(loc + bytes_wrote,
304862306a36Sopenharmony_ci					 PAGE_SIZE - bytes_wrote,
304962306a36Sopenharmony_ci					 "%08x: %08x\n", (i * 4),
305062306a36Sopenharmony_ci					 readl(&reg[i]));
305162306a36Sopenharmony_ci	}
305262306a36Sopenharmony_ci	return bytes_wrote;
305362306a36Sopenharmony_ci}
305462306a36Sopenharmony_ci
305562306a36Sopenharmony_ci/**
305662306a36Sopenharmony_ci * megasas_reset_bus_host -	Bus & host reset handler entry point
305762306a36Sopenharmony_ci * @scmd:			Mid-layer SCSI command
305862306a36Sopenharmony_ci */
305962306a36Sopenharmony_cistatic int megasas_reset_bus_host(struct scsi_cmnd *scmd)
306062306a36Sopenharmony_ci{
306162306a36Sopenharmony_ci	int ret;
306262306a36Sopenharmony_ci	struct megasas_instance *instance;
306362306a36Sopenharmony_ci
306462306a36Sopenharmony_ci	instance = (struct megasas_instance *)scmd->device->host->hostdata;
306562306a36Sopenharmony_ci
306662306a36Sopenharmony_ci	scmd_printk(KERN_INFO, scmd,
306762306a36Sopenharmony_ci		"OCR is requested due to IO timeout!!\n");
306862306a36Sopenharmony_ci
306962306a36Sopenharmony_ci	scmd_printk(KERN_INFO, scmd,
307062306a36Sopenharmony_ci		"SCSI host state: %d  SCSI host busy: %d  FW outstanding: %d\n",
307162306a36Sopenharmony_ci		scmd->device->host->shost_state,
307262306a36Sopenharmony_ci		scsi_host_busy(scmd->device->host),
307362306a36Sopenharmony_ci		atomic_read(&instance->fw_outstanding));
307462306a36Sopenharmony_ci	/*
307562306a36Sopenharmony_ci	 * First wait for all commands to complete
307662306a36Sopenharmony_ci	 */
307762306a36Sopenharmony_ci	if (instance->adapter_type == MFI_SERIES) {
307862306a36Sopenharmony_ci		ret = megasas_generic_reset(scmd);
307962306a36Sopenharmony_ci	} else {
308062306a36Sopenharmony_ci		megasas_dump_fusion_io(scmd);
308162306a36Sopenharmony_ci		ret = megasas_reset_fusion(scmd->device->host,
308262306a36Sopenharmony_ci				SCSIIO_TIMEOUT_OCR);
308362306a36Sopenharmony_ci	}
308462306a36Sopenharmony_ci
308562306a36Sopenharmony_ci	return ret;
308662306a36Sopenharmony_ci}
308762306a36Sopenharmony_ci
308862306a36Sopenharmony_ci/**
308962306a36Sopenharmony_ci * megasas_task_abort - Issues task abort request to firmware
309062306a36Sopenharmony_ci *			(supported only for fusion adapters)
309162306a36Sopenharmony_ci * @scmd:		SCSI command pointer
309262306a36Sopenharmony_ci */
309362306a36Sopenharmony_cistatic int megasas_task_abort(struct scsi_cmnd *scmd)
309462306a36Sopenharmony_ci{
309562306a36Sopenharmony_ci	int ret;
309662306a36Sopenharmony_ci	struct megasas_instance *instance;
309762306a36Sopenharmony_ci
309862306a36Sopenharmony_ci	instance = (struct megasas_instance *)scmd->device->host->hostdata;
309962306a36Sopenharmony_ci
310062306a36Sopenharmony_ci	if (instance->adapter_type != MFI_SERIES)
310162306a36Sopenharmony_ci		ret = megasas_task_abort_fusion(scmd);
310262306a36Sopenharmony_ci	else {
310362306a36Sopenharmony_ci		sdev_printk(KERN_NOTICE, scmd->device, "TASK ABORT not supported\n");
310462306a36Sopenharmony_ci		ret = FAILED;
310562306a36Sopenharmony_ci	}
310662306a36Sopenharmony_ci
310762306a36Sopenharmony_ci	return ret;
310862306a36Sopenharmony_ci}
310962306a36Sopenharmony_ci
311062306a36Sopenharmony_ci/**
311162306a36Sopenharmony_ci * megasas_reset_target:  Issues target reset request to firmware
311262306a36Sopenharmony_ci *                        (supported only for fusion adapters)
311362306a36Sopenharmony_ci * @scmd:                 SCSI command pointer
311462306a36Sopenharmony_ci */
311562306a36Sopenharmony_cistatic int megasas_reset_target(struct scsi_cmnd *scmd)
311662306a36Sopenharmony_ci{
311762306a36Sopenharmony_ci	int ret;
311862306a36Sopenharmony_ci	struct megasas_instance *instance;
311962306a36Sopenharmony_ci
312062306a36Sopenharmony_ci	instance = (struct megasas_instance *)scmd->device->host->hostdata;
312162306a36Sopenharmony_ci
312262306a36Sopenharmony_ci	if (instance->adapter_type != MFI_SERIES)
312362306a36Sopenharmony_ci		ret = megasas_reset_target_fusion(scmd);
312462306a36Sopenharmony_ci	else {
312562306a36Sopenharmony_ci		sdev_printk(KERN_NOTICE, scmd->device, "TARGET RESET not supported\n");
312662306a36Sopenharmony_ci		ret = FAILED;
312762306a36Sopenharmony_ci	}
312862306a36Sopenharmony_ci
312962306a36Sopenharmony_ci	return ret;
313062306a36Sopenharmony_ci}
313162306a36Sopenharmony_ci
313262306a36Sopenharmony_ci/**
313362306a36Sopenharmony_ci * megasas_bios_param - Returns disk geometry for a disk
313462306a36Sopenharmony_ci * @sdev:		device handle
313562306a36Sopenharmony_ci * @bdev:		block device
313662306a36Sopenharmony_ci * @capacity:		drive capacity
313762306a36Sopenharmony_ci * @geom:		geometry parameters
313862306a36Sopenharmony_ci */
313962306a36Sopenharmony_cistatic int
314062306a36Sopenharmony_cimegasas_bios_param(struct scsi_device *sdev, struct block_device *bdev,
314162306a36Sopenharmony_ci		 sector_t capacity, int geom[])
314262306a36Sopenharmony_ci{
314362306a36Sopenharmony_ci	int heads;
314462306a36Sopenharmony_ci	int sectors;
314562306a36Sopenharmony_ci	sector_t cylinders;
314662306a36Sopenharmony_ci	unsigned long tmp;
314762306a36Sopenharmony_ci
314862306a36Sopenharmony_ci	/* Default heads (64) & sectors (32) */
314962306a36Sopenharmony_ci	heads = 64;
315062306a36Sopenharmony_ci	sectors = 32;
315162306a36Sopenharmony_ci
315262306a36Sopenharmony_ci	tmp = heads * sectors;
315362306a36Sopenharmony_ci	cylinders = capacity;
315462306a36Sopenharmony_ci
315562306a36Sopenharmony_ci	sector_div(cylinders, tmp);
315662306a36Sopenharmony_ci
315762306a36Sopenharmony_ci	/*
315862306a36Sopenharmony_ci	 * Handle extended translation size for logical drives > 1Gb
315962306a36Sopenharmony_ci	 */
316062306a36Sopenharmony_ci
316162306a36Sopenharmony_ci	if (capacity >= 0x200000) {
316262306a36Sopenharmony_ci		heads = 255;
316362306a36Sopenharmony_ci		sectors = 63;
316462306a36Sopenharmony_ci		tmp = heads*sectors;
316562306a36Sopenharmony_ci		cylinders = capacity;
316662306a36Sopenharmony_ci		sector_div(cylinders, tmp);
316762306a36Sopenharmony_ci	}
316862306a36Sopenharmony_ci
316962306a36Sopenharmony_ci	geom[0] = heads;
317062306a36Sopenharmony_ci	geom[1] = sectors;
317162306a36Sopenharmony_ci	geom[2] = cylinders;
317262306a36Sopenharmony_ci
317362306a36Sopenharmony_ci	return 0;
317462306a36Sopenharmony_ci}
317562306a36Sopenharmony_ci
317662306a36Sopenharmony_cistatic void megasas_map_queues(struct Scsi_Host *shost)
317762306a36Sopenharmony_ci{
317862306a36Sopenharmony_ci	struct megasas_instance *instance;
317962306a36Sopenharmony_ci	int qoff = 0, offset;
318062306a36Sopenharmony_ci	struct blk_mq_queue_map *map;
318162306a36Sopenharmony_ci
318262306a36Sopenharmony_ci	instance = (struct megasas_instance *)shost->hostdata;
318362306a36Sopenharmony_ci
318462306a36Sopenharmony_ci	if (shost->nr_hw_queues == 1)
318562306a36Sopenharmony_ci		return;
318662306a36Sopenharmony_ci
318762306a36Sopenharmony_ci	offset = instance->low_latency_index_start;
318862306a36Sopenharmony_ci
318962306a36Sopenharmony_ci	/* Setup Default hctx */
319062306a36Sopenharmony_ci	map = &shost->tag_set.map[HCTX_TYPE_DEFAULT];
319162306a36Sopenharmony_ci	map->nr_queues = instance->msix_vectors - offset;
319262306a36Sopenharmony_ci	map->queue_offset = 0;
319362306a36Sopenharmony_ci	blk_mq_pci_map_queues(map, instance->pdev, offset);
319462306a36Sopenharmony_ci	qoff += map->nr_queues;
319562306a36Sopenharmony_ci	offset += map->nr_queues;
319662306a36Sopenharmony_ci
319762306a36Sopenharmony_ci	/* we never use READ queue, so can't cheat blk-mq */
319862306a36Sopenharmony_ci	shost->tag_set.map[HCTX_TYPE_READ].nr_queues = 0;
319962306a36Sopenharmony_ci
320062306a36Sopenharmony_ci	/* Setup Poll hctx */
320162306a36Sopenharmony_ci	map = &shost->tag_set.map[HCTX_TYPE_POLL];
320262306a36Sopenharmony_ci	map->nr_queues = instance->iopoll_q_count;
320362306a36Sopenharmony_ci	if (map->nr_queues) {
320462306a36Sopenharmony_ci		/*
320562306a36Sopenharmony_ci		 * The poll queue(s) doesn't have an IRQ (and hence IRQ
320662306a36Sopenharmony_ci		 * affinity), so use the regular blk-mq cpu mapping
320762306a36Sopenharmony_ci		 */
320862306a36Sopenharmony_ci		map->queue_offset = qoff;
320962306a36Sopenharmony_ci		blk_mq_map_queues(map);
321062306a36Sopenharmony_ci	}
321162306a36Sopenharmony_ci}
321262306a36Sopenharmony_ci
321362306a36Sopenharmony_cistatic void megasas_aen_polling(struct work_struct *work);
321462306a36Sopenharmony_ci
321562306a36Sopenharmony_ci/**
321662306a36Sopenharmony_ci * megasas_service_aen -	Processes an event notification
321762306a36Sopenharmony_ci * @instance:			Adapter soft state
321862306a36Sopenharmony_ci * @cmd:			AEN command completed by the ISR
321962306a36Sopenharmony_ci *
322062306a36Sopenharmony_ci * For AEN, driver sends a command down to FW that is held by the FW till an
322162306a36Sopenharmony_ci * event occurs. When an event of interest occurs, FW completes the command
322262306a36Sopenharmony_ci * that it was previously holding.
322362306a36Sopenharmony_ci *
322462306a36Sopenharmony_ci * This routines sends SIGIO signal to processes that have registered with the
322562306a36Sopenharmony_ci * driver for AEN.
322662306a36Sopenharmony_ci */
322762306a36Sopenharmony_cistatic void
322862306a36Sopenharmony_cimegasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
322962306a36Sopenharmony_ci{
323062306a36Sopenharmony_ci	unsigned long flags;
323162306a36Sopenharmony_ci
323262306a36Sopenharmony_ci	/*
323362306a36Sopenharmony_ci	 * Don't signal app if it is just an aborted previously registered aen
323462306a36Sopenharmony_ci	 */
323562306a36Sopenharmony_ci	if ((!cmd->abort_aen) && (instance->unload == 0)) {
323662306a36Sopenharmony_ci		spin_lock_irqsave(&poll_aen_lock, flags);
323762306a36Sopenharmony_ci		megasas_poll_wait_aen = 1;
323862306a36Sopenharmony_ci		spin_unlock_irqrestore(&poll_aen_lock, flags);
323962306a36Sopenharmony_ci		wake_up(&megasas_poll_wait);
324062306a36Sopenharmony_ci		kill_fasync(&megasas_async_queue, SIGIO, POLL_IN);
324162306a36Sopenharmony_ci	}
324262306a36Sopenharmony_ci	else
324362306a36Sopenharmony_ci		cmd->abort_aen = 0;
324462306a36Sopenharmony_ci
324562306a36Sopenharmony_ci	instance->aen_cmd = NULL;
324662306a36Sopenharmony_ci
324762306a36Sopenharmony_ci	megasas_return_cmd(instance, cmd);
324862306a36Sopenharmony_ci
324962306a36Sopenharmony_ci	if ((instance->unload == 0) &&
325062306a36Sopenharmony_ci		((instance->issuepend_done == 1))) {
325162306a36Sopenharmony_ci		struct megasas_aen_event *ev;
325262306a36Sopenharmony_ci
325362306a36Sopenharmony_ci		ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
325462306a36Sopenharmony_ci		if (!ev) {
325562306a36Sopenharmony_ci			dev_err(&instance->pdev->dev, "megasas_service_aen: out of memory\n");
325662306a36Sopenharmony_ci		} else {
325762306a36Sopenharmony_ci			ev->instance = instance;
325862306a36Sopenharmony_ci			instance->ev = ev;
325962306a36Sopenharmony_ci			INIT_DELAYED_WORK(&ev->hotplug_work,
326062306a36Sopenharmony_ci					  megasas_aen_polling);
326162306a36Sopenharmony_ci			schedule_delayed_work(&ev->hotplug_work, 0);
326262306a36Sopenharmony_ci		}
326362306a36Sopenharmony_ci	}
326462306a36Sopenharmony_ci}
326562306a36Sopenharmony_ci
326662306a36Sopenharmony_cistatic ssize_t
326762306a36Sopenharmony_cifw_crash_buffer_store(struct device *cdev,
326862306a36Sopenharmony_ci	struct device_attribute *attr, const char *buf, size_t count)
326962306a36Sopenharmony_ci{
327062306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(cdev);
327162306a36Sopenharmony_ci	struct megasas_instance *instance =
327262306a36Sopenharmony_ci		(struct megasas_instance *) shost->hostdata;
327362306a36Sopenharmony_ci	int val = 0;
327462306a36Sopenharmony_ci
327562306a36Sopenharmony_ci	if (kstrtoint(buf, 0, &val) != 0)
327662306a36Sopenharmony_ci		return -EINVAL;
327762306a36Sopenharmony_ci
327862306a36Sopenharmony_ci	mutex_lock(&instance->crashdump_lock);
327962306a36Sopenharmony_ci	instance->fw_crash_buffer_offset = val;
328062306a36Sopenharmony_ci	mutex_unlock(&instance->crashdump_lock);
328162306a36Sopenharmony_ci	return strlen(buf);
328262306a36Sopenharmony_ci}
328362306a36Sopenharmony_ci
328462306a36Sopenharmony_cistatic ssize_t
328562306a36Sopenharmony_cifw_crash_buffer_show(struct device *cdev,
328662306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
328762306a36Sopenharmony_ci{
328862306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(cdev);
328962306a36Sopenharmony_ci	struct megasas_instance *instance =
329062306a36Sopenharmony_ci		(struct megasas_instance *) shost->hostdata;
329162306a36Sopenharmony_ci	u32 size;
329262306a36Sopenharmony_ci	unsigned long dmachunk = CRASH_DMA_BUF_SIZE;
329362306a36Sopenharmony_ci	unsigned long chunk_left_bytes;
329462306a36Sopenharmony_ci	unsigned long src_addr;
329562306a36Sopenharmony_ci	u32 buff_offset;
329662306a36Sopenharmony_ci
329762306a36Sopenharmony_ci	mutex_lock(&instance->crashdump_lock);
329862306a36Sopenharmony_ci	buff_offset = instance->fw_crash_buffer_offset;
329962306a36Sopenharmony_ci	if (!instance->crash_dump_buf ||
330062306a36Sopenharmony_ci		!((instance->fw_crash_state == AVAILABLE) ||
330162306a36Sopenharmony_ci		(instance->fw_crash_state == COPYING))) {
330262306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
330362306a36Sopenharmony_ci			"Firmware crash dump is not available\n");
330462306a36Sopenharmony_ci		mutex_unlock(&instance->crashdump_lock);
330562306a36Sopenharmony_ci		return -EINVAL;
330662306a36Sopenharmony_ci	}
330762306a36Sopenharmony_ci
330862306a36Sopenharmony_ci	if (buff_offset > (instance->fw_crash_buffer_size * dmachunk)) {
330962306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
331062306a36Sopenharmony_ci			"Firmware crash dump offset is out of range\n");
331162306a36Sopenharmony_ci		mutex_unlock(&instance->crashdump_lock);
331262306a36Sopenharmony_ci		return 0;
331362306a36Sopenharmony_ci	}
331462306a36Sopenharmony_ci
331562306a36Sopenharmony_ci	size = (instance->fw_crash_buffer_size * dmachunk) - buff_offset;
331662306a36Sopenharmony_ci	chunk_left_bytes = dmachunk - (buff_offset % dmachunk);
331762306a36Sopenharmony_ci	size = (size > chunk_left_bytes) ? chunk_left_bytes : size;
331862306a36Sopenharmony_ci	size = (size >= PAGE_SIZE) ? (PAGE_SIZE - 1) : size;
331962306a36Sopenharmony_ci
332062306a36Sopenharmony_ci	src_addr = (unsigned long)instance->crash_buf[buff_offset / dmachunk] +
332162306a36Sopenharmony_ci		(buff_offset % dmachunk);
332262306a36Sopenharmony_ci	memcpy(buf, (void *)src_addr, size);
332362306a36Sopenharmony_ci	mutex_unlock(&instance->crashdump_lock);
332462306a36Sopenharmony_ci
332562306a36Sopenharmony_ci	return size;
332662306a36Sopenharmony_ci}
332762306a36Sopenharmony_ci
332862306a36Sopenharmony_cistatic ssize_t
332962306a36Sopenharmony_cifw_crash_buffer_size_show(struct device *cdev,
333062306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
333162306a36Sopenharmony_ci{
333262306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(cdev);
333362306a36Sopenharmony_ci	struct megasas_instance *instance =
333462306a36Sopenharmony_ci		(struct megasas_instance *) shost->hostdata;
333562306a36Sopenharmony_ci
333662306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long)
333762306a36Sopenharmony_ci		((instance->fw_crash_buffer_size) * 1024 * 1024)/PAGE_SIZE);
333862306a36Sopenharmony_ci}
333962306a36Sopenharmony_ci
334062306a36Sopenharmony_cistatic ssize_t
334162306a36Sopenharmony_cifw_crash_state_store(struct device *cdev,
334262306a36Sopenharmony_ci	struct device_attribute *attr, const char *buf, size_t count)
334362306a36Sopenharmony_ci{
334462306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(cdev);
334562306a36Sopenharmony_ci	struct megasas_instance *instance =
334662306a36Sopenharmony_ci		(struct megasas_instance *) shost->hostdata;
334762306a36Sopenharmony_ci	int val = 0;
334862306a36Sopenharmony_ci
334962306a36Sopenharmony_ci	if (kstrtoint(buf, 0, &val) != 0)
335062306a36Sopenharmony_ci		return -EINVAL;
335162306a36Sopenharmony_ci
335262306a36Sopenharmony_ci	if ((val <= AVAILABLE || val > COPY_ERROR)) {
335362306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "application updates invalid "
335462306a36Sopenharmony_ci			"firmware crash state\n");
335562306a36Sopenharmony_ci		return -EINVAL;
335662306a36Sopenharmony_ci	}
335762306a36Sopenharmony_ci
335862306a36Sopenharmony_ci	instance->fw_crash_state = val;
335962306a36Sopenharmony_ci
336062306a36Sopenharmony_ci	if ((val == COPIED) || (val == COPY_ERROR)) {
336162306a36Sopenharmony_ci		mutex_lock(&instance->crashdump_lock);
336262306a36Sopenharmony_ci		megasas_free_host_crash_buffer(instance);
336362306a36Sopenharmony_ci		mutex_unlock(&instance->crashdump_lock);
336462306a36Sopenharmony_ci		if (val == COPY_ERROR)
336562306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "application failed to "
336662306a36Sopenharmony_ci				"copy Firmware crash dump\n");
336762306a36Sopenharmony_ci		else
336862306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "Firmware crash dump "
336962306a36Sopenharmony_ci				"copied successfully\n");
337062306a36Sopenharmony_ci	}
337162306a36Sopenharmony_ci	return strlen(buf);
337262306a36Sopenharmony_ci}
337362306a36Sopenharmony_ci
337462306a36Sopenharmony_cistatic ssize_t
337562306a36Sopenharmony_cifw_crash_state_show(struct device *cdev,
337662306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
337762306a36Sopenharmony_ci{
337862306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(cdev);
337962306a36Sopenharmony_ci	struct megasas_instance *instance =
338062306a36Sopenharmony_ci		(struct megasas_instance *) shost->hostdata;
338162306a36Sopenharmony_ci
338262306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%d\n", instance->fw_crash_state);
338362306a36Sopenharmony_ci}
338462306a36Sopenharmony_ci
338562306a36Sopenharmony_cistatic ssize_t
338662306a36Sopenharmony_cipage_size_show(struct device *cdev,
338762306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
338862306a36Sopenharmony_ci{
338962306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long)PAGE_SIZE - 1);
339062306a36Sopenharmony_ci}
339162306a36Sopenharmony_ci
339262306a36Sopenharmony_cistatic ssize_t
339362306a36Sopenharmony_cildio_outstanding_show(struct device *cdev, struct device_attribute *attr,
339462306a36Sopenharmony_ci	char *buf)
339562306a36Sopenharmony_ci{
339662306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(cdev);
339762306a36Sopenharmony_ci	struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata;
339862306a36Sopenharmony_ci
339962306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&instance->ldio_outstanding));
340062306a36Sopenharmony_ci}
340162306a36Sopenharmony_ci
340262306a36Sopenharmony_cistatic ssize_t
340362306a36Sopenharmony_cifw_cmds_outstanding_show(struct device *cdev,
340462306a36Sopenharmony_ci				 struct device_attribute *attr, char *buf)
340562306a36Sopenharmony_ci{
340662306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(cdev);
340762306a36Sopenharmony_ci	struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata;
340862306a36Sopenharmony_ci
340962306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&instance->fw_outstanding));
341062306a36Sopenharmony_ci}
341162306a36Sopenharmony_ci
341262306a36Sopenharmony_cistatic ssize_t
341362306a36Sopenharmony_cienable_sdev_max_qd_show(struct device *cdev,
341462306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
341562306a36Sopenharmony_ci{
341662306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(cdev);
341762306a36Sopenharmony_ci	struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata;
341862306a36Sopenharmony_ci
341962306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%d\n", instance->enable_sdev_max_qd);
342062306a36Sopenharmony_ci}
342162306a36Sopenharmony_ci
342262306a36Sopenharmony_cistatic ssize_t
342362306a36Sopenharmony_cienable_sdev_max_qd_store(struct device *cdev,
342462306a36Sopenharmony_ci	struct device_attribute *attr, const char *buf, size_t count)
342562306a36Sopenharmony_ci{
342662306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(cdev);
342762306a36Sopenharmony_ci	struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata;
342862306a36Sopenharmony_ci	u32 val = 0;
342962306a36Sopenharmony_ci	bool is_target_prop;
343062306a36Sopenharmony_ci	int ret_target_prop = DCMD_FAILED;
343162306a36Sopenharmony_ci	struct scsi_device *sdev;
343262306a36Sopenharmony_ci
343362306a36Sopenharmony_ci	if (kstrtou32(buf, 0, &val) != 0) {
343462306a36Sopenharmony_ci		pr_err("megasas: could not set enable_sdev_max_qd\n");
343562306a36Sopenharmony_ci		return -EINVAL;
343662306a36Sopenharmony_ci	}
343762306a36Sopenharmony_ci
343862306a36Sopenharmony_ci	mutex_lock(&instance->reset_mutex);
343962306a36Sopenharmony_ci	if (val)
344062306a36Sopenharmony_ci		instance->enable_sdev_max_qd = true;
344162306a36Sopenharmony_ci	else
344262306a36Sopenharmony_ci		instance->enable_sdev_max_qd = false;
344362306a36Sopenharmony_ci
344462306a36Sopenharmony_ci	shost_for_each_device(sdev, shost) {
344562306a36Sopenharmony_ci		ret_target_prop = megasas_get_target_prop(instance, sdev);
344662306a36Sopenharmony_ci		is_target_prop = (ret_target_prop == DCMD_SUCCESS) ? true : false;
344762306a36Sopenharmony_ci		megasas_set_fw_assisted_qd(sdev, is_target_prop);
344862306a36Sopenharmony_ci	}
344962306a36Sopenharmony_ci	mutex_unlock(&instance->reset_mutex);
345062306a36Sopenharmony_ci
345162306a36Sopenharmony_ci	return strlen(buf);
345262306a36Sopenharmony_ci}
345362306a36Sopenharmony_ci
345462306a36Sopenharmony_cistatic ssize_t
345562306a36Sopenharmony_cidump_system_regs_show(struct device *cdev,
345662306a36Sopenharmony_ci			       struct device_attribute *attr, char *buf)
345762306a36Sopenharmony_ci{
345862306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(cdev);
345962306a36Sopenharmony_ci	struct megasas_instance *instance =
346062306a36Sopenharmony_ci			(struct megasas_instance *)shost->hostdata;
346162306a36Sopenharmony_ci
346262306a36Sopenharmony_ci	return megasas_dump_sys_regs(instance->reg_set, buf);
346362306a36Sopenharmony_ci}
346462306a36Sopenharmony_ci
346562306a36Sopenharmony_cistatic ssize_t
346662306a36Sopenharmony_ciraid_map_id_show(struct device *cdev, struct device_attribute *attr,
346762306a36Sopenharmony_ci			  char *buf)
346862306a36Sopenharmony_ci{
346962306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(cdev);
347062306a36Sopenharmony_ci	struct megasas_instance *instance =
347162306a36Sopenharmony_ci			(struct megasas_instance *)shost->hostdata;
347262306a36Sopenharmony_ci
347362306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%ld\n",
347462306a36Sopenharmony_ci			(unsigned long)instance->map_id);
347562306a36Sopenharmony_ci}
347662306a36Sopenharmony_ci
347762306a36Sopenharmony_cistatic DEVICE_ATTR_RW(fw_crash_buffer);
347862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(fw_crash_buffer_size);
347962306a36Sopenharmony_cistatic DEVICE_ATTR_RW(fw_crash_state);
348062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(page_size);
348162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(ldio_outstanding);
348262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(fw_cmds_outstanding);
348362306a36Sopenharmony_cistatic DEVICE_ATTR_RW(enable_sdev_max_qd);
348462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(dump_system_regs);
348562306a36Sopenharmony_cistatic DEVICE_ATTR_RO(raid_map_id);
348662306a36Sopenharmony_ci
348762306a36Sopenharmony_cistatic struct attribute *megaraid_host_attrs[] = {
348862306a36Sopenharmony_ci	&dev_attr_fw_crash_buffer_size.attr,
348962306a36Sopenharmony_ci	&dev_attr_fw_crash_buffer.attr,
349062306a36Sopenharmony_ci	&dev_attr_fw_crash_state.attr,
349162306a36Sopenharmony_ci	&dev_attr_page_size.attr,
349262306a36Sopenharmony_ci	&dev_attr_ldio_outstanding.attr,
349362306a36Sopenharmony_ci	&dev_attr_fw_cmds_outstanding.attr,
349462306a36Sopenharmony_ci	&dev_attr_enable_sdev_max_qd.attr,
349562306a36Sopenharmony_ci	&dev_attr_dump_system_regs.attr,
349662306a36Sopenharmony_ci	&dev_attr_raid_map_id.attr,
349762306a36Sopenharmony_ci	NULL,
349862306a36Sopenharmony_ci};
349962306a36Sopenharmony_ci
350062306a36Sopenharmony_ciATTRIBUTE_GROUPS(megaraid_host);
350162306a36Sopenharmony_ci
350262306a36Sopenharmony_ci/*
350362306a36Sopenharmony_ci * Scsi host template for megaraid_sas driver
350462306a36Sopenharmony_ci */
350562306a36Sopenharmony_cistatic const struct scsi_host_template megasas_template = {
350662306a36Sopenharmony_ci
350762306a36Sopenharmony_ci	.module = THIS_MODULE,
350862306a36Sopenharmony_ci	.name = "Avago SAS based MegaRAID driver",
350962306a36Sopenharmony_ci	.proc_name = "megaraid_sas",
351062306a36Sopenharmony_ci	.slave_configure = megasas_slave_configure,
351162306a36Sopenharmony_ci	.slave_alloc = megasas_slave_alloc,
351262306a36Sopenharmony_ci	.slave_destroy = megasas_slave_destroy,
351362306a36Sopenharmony_ci	.queuecommand = megasas_queue_command,
351462306a36Sopenharmony_ci	.eh_target_reset_handler = megasas_reset_target,
351562306a36Sopenharmony_ci	.eh_abort_handler = megasas_task_abort,
351662306a36Sopenharmony_ci	.eh_host_reset_handler = megasas_reset_bus_host,
351762306a36Sopenharmony_ci	.eh_timed_out = megasas_reset_timer,
351862306a36Sopenharmony_ci	.shost_groups = megaraid_host_groups,
351962306a36Sopenharmony_ci	.bios_param = megasas_bios_param,
352062306a36Sopenharmony_ci	.map_queues = megasas_map_queues,
352162306a36Sopenharmony_ci	.mq_poll = megasas_blk_mq_poll,
352262306a36Sopenharmony_ci	.change_queue_depth = scsi_change_queue_depth,
352362306a36Sopenharmony_ci	.max_segment_size = 0xffffffff,
352462306a36Sopenharmony_ci	.cmd_size = sizeof(struct megasas_cmd_priv),
352562306a36Sopenharmony_ci};
352662306a36Sopenharmony_ci
352762306a36Sopenharmony_ci/**
352862306a36Sopenharmony_ci * megasas_complete_int_cmd -	Completes an internal command
352962306a36Sopenharmony_ci * @instance:			Adapter soft state
353062306a36Sopenharmony_ci * @cmd:			Command to be completed
353162306a36Sopenharmony_ci *
353262306a36Sopenharmony_ci * The megasas_issue_blocked_cmd() function waits for a command to complete
353362306a36Sopenharmony_ci * after it issues a command. This function wakes up that waiting routine by
353462306a36Sopenharmony_ci * calling wake_up() on the wait queue.
353562306a36Sopenharmony_ci */
353662306a36Sopenharmony_cistatic void
353762306a36Sopenharmony_cimegasas_complete_int_cmd(struct megasas_instance *instance,
353862306a36Sopenharmony_ci			 struct megasas_cmd *cmd)
353962306a36Sopenharmony_ci{
354062306a36Sopenharmony_ci	if (cmd->cmd_status_drv == DCMD_INIT)
354162306a36Sopenharmony_ci		cmd->cmd_status_drv =
354262306a36Sopenharmony_ci		(cmd->frame->io.cmd_status == MFI_STAT_OK) ?
354362306a36Sopenharmony_ci		DCMD_SUCCESS : DCMD_FAILED;
354462306a36Sopenharmony_ci
354562306a36Sopenharmony_ci	wake_up(&instance->int_cmd_wait_q);
354662306a36Sopenharmony_ci}
354762306a36Sopenharmony_ci
354862306a36Sopenharmony_ci/**
354962306a36Sopenharmony_ci * megasas_complete_abort -	Completes aborting a command
355062306a36Sopenharmony_ci * @instance:			Adapter soft state
355162306a36Sopenharmony_ci * @cmd:			Cmd that was issued to abort another cmd
355262306a36Sopenharmony_ci *
355362306a36Sopenharmony_ci * The megasas_issue_blocked_abort_cmd() function waits on abort_cmd_wait_q
355462306a36Sopenharmony_ci * after it issues an abort on a previously issued command. This function
355562306a36Sopenharmony_ci * wakes up all functions waiting on the same wait queue.
355662306a36Sopenharmony_ci */
355762306a36Sopenharmony_cistatic void
355862306a36Sopenharmony_cimegasas_complete_abort(struct megasas_instance *instance,
355962306a36Sopenharmony_ci		       struct megasas_cmd *cmd)
356062306a36Sopenharmony_ci{
356162306a36Sopenharmony_ci	if (cmd->sync_cmd) {
356262306a36Sopenharmony_ci		cmd->sync_cmd = 0;
356362306a36Sopenharmony_ci		cmd->cmd_status_drv = DCMD_SUCCESS;
356462306a36Sopenharmony_ci		wake_up(&instance->abort_cmd_wait_q);
356562306a36Sopenharmony_ci	}
356662306a36Sopenharmony_ci}
356762306a36Sopenharmony_ci
356862306a36Sopenharmony_cistatic void
356962306a36Sopenharmony_cimegasas_set_ld_removed_by_fw(struct megasas_instance *instance)
357062306a36Sopenharmony_ci{
357162306a36Sopenharmony_ci	uint i;
357262306a36Sopenharmony_ci
357362306a36Sopenharmony_ci	for (i = 0; (i < MEGASAS_MAX_LD_IDS); i++) {
357462306a36Sopenharmony_ci		if (instance->ld_ids_prev[i] != 0xff &&
357562306a36Sopenharmony_ci		    instance->ld_ids_from_raidmap[i] == 0xff) {
357662306a36Sopenharmony_ci			if (megasas_dbg_lvl & LD_PD_DEBUG)
357762306a36Sopenharmony_ci				dev_info(&instance->pdev->dev,
357862306a36Sopenharmony_ci					 "LD target ID %d removed from RAID map\n", i);
357962306a36Sopenharmony_ci			instance->ld_tgtid_status[i] = LD_TARGET_ID_DELETED;
358062306a36Sopenharmony_ci		}
358162306a36Sopenharmony_ci	}
358262306a36Sopenharmony_ci}
358362306a36Sopenharmony_ci
358462306a36Sopenharmony_ci/**
358562306a36Sopenharmony_ci * megasas_complete_cmd -	Completes a command
358662306a36Sopenharmony_ci * @instance:			Adapter soft state
358762306a36Sopenharmony_ci * @cmd:			Command to be completed
358862306a36Sopenharmony_ci * @alt_status:			If non-zero, use this value as status to
358962306a36Sopenharmony_ci *				SCSI mid-layer instead of the value returned
359062306a36Sopenharmony_ci *				by the FW. This should be used if caller wants
359162306a36Sopenharmony_ci *				an alternate status (as in the case of aborted
359262306a36Sopenharmony_ci *				commands)
359362306a36Sopenharmony_ci */
359462306a36Sopenharmony_civoid
359562306a36Sopenharmony_cimegasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
359662306a36Sopenharmony_ci		     u8 alt_status)
359762306a36Sopenharmony_ci{
359862306a36Sopenharmony_ci	int exception = 0;
359962306a36Sopenharmony_ci	struct megasas_header *hdr = &cmd->frame->hdr;
360062306a36Sopenharmony_ci	unsigned long flags;
360162306a36Sopenharmony_ci	struct fusion_context *fusion = instance->ctrl_context;
360262306a36Sopenharmony_ci	u32 opcode, status;
360362306a36Sopenharmony_ci
360462306a36Sopenharmony_ci	/* flag for the retry reset */
360562306a36Sopenharmony_ci	cmd->retry_for_fw_reset = 0;
360662306a36Sopenharmony_ci
360762306a36Sopenharmony_ci	if (cmd->scmd)
360862306a36Sopenharmony_ci		megasas_priv(cmd->scmd)->cmd_priv = NULL;
360962306a36Sopenharmony_ci
361062306a36Sopenharmony_ci	switch (hdr->cmd) {
361162306a36Sopenharmony_ci	case MFI_CMD_INVALID:
361262306a36Sopenharmony_ci		/* Some older 1068 controller FW may keep a pended
361362306a36Sopenharmony_ci		   MR_DCMD_CTRL_EVENT_GET_INFO left over from the main kernel
361462306a36Sopenharmony_ci		   when booting the kdump kernel.  Ignore this command to
361562306a36Sopenharmony_ci		   prevent a kernel panic on shutdown of the kdump kernel. */
361662306a36Sopenharmony_ci		dev_warn(&instance->pdev->dev, "MFI_CMD_INVALID command "
361762306a36Sopenharmony_ci		       "completed\n");
361862306a36Sopenharmony_ci		dev_warn(&instance->pdev->dev, "If you have a controller "
361962306a36Sopenharmony_ci		       "other than PERC5, please upgrade your firmware\n");
362062306a36Sopenharmony_ci		break;
362162306a36Sopenharmony_ci	case MFI_CMD_PD_SCSI_IO:
362262306a36Sopenharmony_ci	case MFI_CMD_LD_SCSI_IO:
362362306a36Sopenharmony_ci
362462306a36Sopenharmony_ci		/*
362562306a36Sopenharmony_ci		 * MFI_CMD_PD_SCSI_IO and MFI_CMD_LD_SCSI_IO could have been
362662306a36Sopenharmony_ci		 * issued either through an IO path or an IOCTL path. If it
362762306a36Sopenharmony_ci		 * was via IOCTL, we will send it to internal completion.
362862306a36Sopenharmony_ci		 */
362962306a36Sopenharmony_ci		if (cmd->sync_cmd) {
363062306a36Sopenharmony_ci			cmd->sync_cmd = 0;
363162306a36Sopenharmony_ci			megasas_complete_int_cmd(instance, cmd);
363262306a36Sopenharmony_ci			break;
363362306a36Sopenharmony_ci		}
363462306a36Sopenharmony_ci		fallthrough;
363562306a36Sopenharmony_ci
363662306a36Sopenharmony_ci	case MFI_CMD_LD_READ:
363762306a36Sopenharmony_ci	case MFI_CMD_LD_WRITE:
363862306a36Sopenharmony_ci
363962306a36Sopenharmony_ci		if (alt_status) {
364062306a36Sopenharmony_ci			cmd->scmd->result = alt_status << 16;
364162306a36Sopenharmony_ci			exception = 1;
364262306a36Sopenharmony_ci		}
364362306a36Sopenharmony_ci
364462306a36Sopenharmony_ci		if (exception) {
364562306a36Sopenharmony_ci
364662306a36Sopenharmony_ci			atomic_dec(&instance->fw_outstanding);
364762306a36Sopenharmony_ci
364862306a36Sopenharmony_ci			scsi_dma_unmap(cmd->scmd);
364962306a36Sopenharmony_ci			scsi_done(cmd->scmd);
365062306a36Sopenharmony_ci			megasas_return_cmd(instance, cmd);
365162306a36Sopenharmony_ci
365262306a36Sopenharmony_ci			break;
365362306a36Sopenharmony_ci		}
365462306a36Sopenharmony_ci
365562306a36Sopenharmony_ci		switch (hdr->cmd_status) {
365662306a36Sopenharmony_ci
365762306a36Sopenharmony_ci		case MFI_STAT_OK:
365862306a36Sopenharmony_ci			cmd->scmd->result = DID_OK << 16;
365962306a36Sopenharmony_ci			break;
366062306a36Sopenharmony_ci
366162306a36Sopenharmony_ci		case MFI_STAT_SCSI_IO_FAILED:
366262306a36Sopenharmony_ci		case MFI_STAT_LD_INIT_IN_PROGRESS:
366362306a36Sopenharmony_ci			cmd->scmd->result =
366462306a36Sopenharmony_ci			    (DID_ERROR << 16) | hdr->scsi_status;
366562306a36Sopenharmony_ci			break;
366662306a36Sopenharmony_ci
366762306a36Sopenharmony_ci		case MFI_STAT_SCSI_DONE_WITH_ERROR:
366862306a36Sopenharmony_ci
366962306a36Sopenharmony_ci			cmd->scmd->result = (DID_OK << 16) | hdr->scsi_status;
367062306a36Sopenharmony_ci
367162306a36Sopenharmony_ci			if (hdr->scsi_status == SAM_STAT_CHECK_CONDITION) {
367262306a36Sopenharmony_ci				memset(cmd->scmd->sense_buffer, 0,
367362306a36Sopenharmony_ci				       SCSI_SENSE_BUFFERSIZE);
367462306a36Sopenharmony_ci				memcpy(cmd->scmd->sense_buffer, cmd->sense,
367562306a36Sopenharmony_ci				       hdr->sense_len);
367662306a36Sopenharmony_ci			}
367762306a36Sopenharmony_ci
367862306a36Sopenharmony_ci			break;
367962306a36Sopenharmony_ci
368062306a36Sopenharmony_ci		case MFI_STAT_LD_OFFLINE:
368162306a36Sopenharmony_ci		case MFI_STAT_DEVICE_NOT_FOUND:
368262306a36Sopenharmony_ci			cmd->scmd->result = DID_BAD_TARGET << 16;
368362306a36Sopenharmony_ci			break;
368462306a36Sopenharmony_ci
368562306a36Sopenharmony_ci		default:
368662306a36Sopenharmony_ci			dev_printk(KERN_DEBUG, &instance->pdev->dev, "MFI FW status %#x\n",
368762306a36Sopenharmony_ci			       hdr->cmd_status);
368862306a36Sopenharmony_ci			cmd->scmd->result = DID_ERROR << 16;
368962306a36Sopenharmony_ci			break;
369062306a36Sopenharmony_ci		}
369162306a36Sopenharmony_ci
369262306a36Sopenharmony_ci		atomic_dec(&instance->fw_outstanding);
369362306a36Sopenharmony_ci
369462306a36Sopenharmony_ci		scsi_dma_unmap(cmd->scmd);
369562306a36Sopenharmony_ci		scsi_done(cmd->scmd);
369662306a36Sopenharmony_ci		megasas_return_cmd(instance, cmd);
369762306a36Sopenharmony_ci
369862306a36Sopenharmony_ci		break;
369962306a36Sopenharmony_ci
370062306a36Sopenharmony_ci	case MFI_CMD_SMP:
370162306a36Sopenharmony_ci	case MFI_CMD_STP:
370262306a36Sopenharmony_ci	case MFI_CMD_NVME:
370362306a36Sopenharmony_ci	case MFI_CMD_TOOLBOX:
370462306a36Sopenharmony_ci		megasas_complete_int_cmd(instance, cmd);
370562306a36Sopenharmony_ci		break;
370662306a36Sopenharmony_ci
370762306a36Sopenharmony_ci	case MFI_CMD_DCMD:
370862306a36Sopenharmony_ci		opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
370962306a36Sopenharmony_ci		/* Check for LD map update */
371062306a36Sopenharmony_ci		if ((opcode == MR_DCMD_LD_MAP_GET_INFO)
371162306a36Sopenharmony_ci			&& (cmd->frame->dcmd.mbox.b[1] == 1)) {
371262306a36Sopenharmony_ci			fusion->fast_path_io = 0;
371362306a36Sopenharmony_ci			spin_lock_irqsave(instance->host->host_lock, flags);
371462306a36Sopenharmony_ci			status = cmd->frame->hdr.cmd_status;
371562306a36Sopenharmony_ci			instance->map_update_cmd = NULL;
371662306a36Sopenharmony_ci			if (status != MFI_STAT_OK) {
371762306a36Sopenharmony_ci				if (status != MFI_STAT_NOT_FOUND)
371862306a36Sopenharmony_ci					dev_warn(&instance->pdev->dev, "map syncfailed, status = 0x%x\n",
371962306a36Sopenharmony_ci					       cmd->frame->hdr.cmd_status);
372062306a36Sopenharmony_ci				else {
372162306a36Sopenharmony_ci					megasas_return_cmd(instance, cmd);
372262306a36Sopenharmony_ci					spin_unlock_irqrestore(
372362306a36Sopenharmony_ci						instance->host->host_lock,
372462306a36Sopenharmony_ci						flags);
372562306a36Sopenharmony_ci					break;
372662306a36Sopenharmony_ci				}
372762306a36Sopenharmony_ci			}
372862306a36Sopenharmony_ci
372962306a36Sopenharmony_ci			megasas_return_cmd(instance, cmd);
373062306a36Sopenharmony_ci
373162306a36Sopenharmony_ci			/*
373262306a36Sopenharmony_ci			 * Set fast path IO to ZERO.
373362306a36Sopenharmony_ci			 * Validate Map will set proper value.
373462306a36Sopenharmony_ci			 * Meanwhile all IOs will go as LD IO.
373562306a36Sopenharmony_ci			 */
373662306a36Sopenharmony_ci			if (status == MFI_STAT_OK &&
373762306a36Sopenharmony_ci			    (MR_ValidateMapInfo(instance, (instance->map_id + 1)))) {
373862306a36Sopenharmony_ci				instance->map_id++;
373962306a36Sopenharmony_ci				fusion->fast_path_io = 1;
374062306a36Sopenharmony_ci			} else {
374162306a36Sopenharmony_ci				fusion->fast_path_io = 0;
374262306a36Sopenharmony_ci			}
374362306a36Sopenharmony_ci
374462306a36Sopenharmony_ci			if (instance->adapter_type >= INVADER_SERIES)
374562306a36Sopenharmony_ci				megasas_set_ld_removed_by_fw(instance);
374662306a36Sopenharmony_ci
374762306a36Sopenharmony_ci			megasas_sync_map_info(instance);
374862306a36Sopenharmony_ci			spin_unlock_irqrestore(instance->host->host_lock,
374962306a36Sopenharmony_ci					       flags);
375062306a36Sopenharmony_ci
375162306a36Sopenharmony_ci			break;
375262306a36Sopenharmony_ci		}
375362306a36Sopenharmony_ci		if (opcode == MR_DCMD_CTRL_EVENT_GET_INFO ||
375462306a36Sopenharmony_ci		    opcode == MR_DCMD_CTRL_EVENT_GET) {
375562306a36Sopenharmony_ci			spin_lock_irqsave(&poll_aen_lock, flags);
375662306a36Sopenharmony_ci			megasas_poll_wait_aen = 0;
375762306a36Sopenharmony_ci			spin_unlock_irqrestore(&poll_aen_lock, flags);
375862306a36Sopenharmony_ci		}
375962306a36Sopenharmony_ci
376062306a36Sopenharmony_ci		/* FW has an updated PD sequence */
376162306a36Sopenharmony_ci		if ((opcode == MR_DCMD_SYSTEM_PD_MAP_GET_INFO) &&
376262306a36Sopenharmony_ci			(cmd->frame->dcmd.mbox.b[0] == 1)) {
376362306a36Sopenharmony_ci
376462306a36Sopenharmony_ci			spin_lock_irqsave(instance->host->host_lock, flags);
376562306a36Sopenharmony_ci			status = cmd->frame->hdr.cmd_status;
376662306a36Sopenharmony_ci			instance->jbod_seq_cmd = NULL;
376762306a36Sopenharmony_ci			megasas_return_cmd(instance, cmd);
376862306a36Sopenharmony_ci
376962306a36Sopenharmony_ci			if (status == MFI_STAT_OK) {
377062306a36Sopenharmony_ci				instance->pd_seq_map_id++;
377162306a36Sopenharmony_ci				/* Re-register a pd sync seq num cmd */
377262306a36Sopenharmony_ci				if (megasas_sync_pd_seq_num(instance, true))
377362306a36Sopenharmony_ci					instance->use_seqnum_jbod_fp = false;
377462306a36Sopenharmony_ci			} else
377562306a36Sopenharmony_ci				instance->use_seqnum_jbod_fp = false;
377662306a36Sopenharmony_ci
377762306a36Sopenharmony_ci			spin_unlock_irqrestore(instance->host->host_lock, flags);
377862306a36Sopenharmony_ci			break;
377962306a36Sopenharmony_ci		}
378062306a36Sopenharmony_ci
378162306a36Sopenharmony_ci		/*
378262306a36Sopenharmony_ci		 * See if got an event notification
378362306a36Sopenharmony_ci		 */
378462306a36Sopenharmony_ci		if (opcode == MR_DCMD_CTRL_EVENT_WAIT)
378562306a36Sopenharmony_ci			megasas_service_aen(instance, cmd);
378662306a36Sopenharmony_ci		else
378762306a36Sopenharmony_ci			megasas_complete_int_cmd(instance, cmd);
378862306a36Sopenharmony_ci
378962306a36Sopenharmony_ci		break;
379062306a36Sopenharmony_ci
379162306a36Sopenharmony_ci	case MFI_CMD_ABORT:
379262306a36Sopenharmony_ci		/*
379362306a36Sopenharmony_ci		 * Cmd issued to abort another cmd returned
379462306a36Sopenharmony_ci		 */
379562306a36Sopenharmony_ci		megasas_complete_abort(instance, cmd);
379662306a36Sopenharmony_ci		break;
379762306a36Sopenharmony_ci
379862306a36Sopenharmony_ci	default:
379962306a36Sopenharmony_ci		dev_info(&instance->pdev->dev, "Unknown command completed! [0x%X]\n",
380062306a36Sopenharmony_ci		       hdr->cmd);
380162306a36Sopenharmony_ci		megasas_complete_int_cmd(instance, cmd);
380262306a36Sopenharmony_ci		break;
380362306a36Sopenharmony_ci	}
380462306a36Sopenharmony_ci}
380562306a36Sopenharmony_ci
380662306a36Sopenharmony_ci/**
380762306a36Sopenharmony_ci * megasas_issue_pending_cmds_again -	issue all pending cmds
380862306a36Sopenharmony_ci *					in FW again because of the fw reset
380962306a36Sopenharmony_ci * @instance:				Adapter soft state
381062306a36Sopenharmony_ci */
381162306a36Sopenharmony_cistatic inline void
381262306a36Sopenharmony_cimegasas_issue_pending_cmds_again(struct megasas_instance *instance)
381362306a36Sopenharmony_ci{
381462306a36Sopenharmony_ci	struct megasas_cmd *cmd;
381562306a36Sopenharmony_ci	struct list_head clist_local;
381662306a36Sopenharmony_ci	union megasas_evt_class_locale class_locale;
381762306a36Sopenharmony_ci	unsigned long flags;
381862306a36Sopenharmony_ci	u32 seq_num;
381962306a36Sopenharmony_ci
382062306a36Sopenharmony_ci	INIT_LIST_HEAD(&clist_local);
382162306a36Sopenharmony_ci	spin_lock_irqsave(&instance->hba_lock, flags);
382262306a36Sopenharmony_ci	list_splice_init(&instance->internal_reset_pending_q, &clist_local);
382362306a36Sopenharmony_ci	spin_unlock_irqrestore(&instance->hba_lock, flags);
382462306a36Sopenharmony_ci
382562306a36Sopenharmony_ci	while (!list_empty(&clist_local)) {
382662306a36Sopenharmony_ci		cmd = list_entry((&clist_local)->next,
382762306a36Sopenharmony_ci					struct megasas_cmd, list);
382862306a36Sopenharmony_ci		list_del_init(&cmd->list);
382962306a36Sopenharmony_ci
383062306a36Sopenharmony_ci		if (cmd->sync_cmd || cmd->scmd) {
383162306a36Sopenharmony_ci			dev_notice(&instance->pdev->dev, "command %p, %p:%d"
383262306a36Sopenharmony_ci				"detected to be pending while HBA reset\n",
383362306a36Sopenharmony_ci					cmd, cmd->scmd, cmd->sync_cmd);
383462306a36Sopenharmony_ci
383562306a36Sopenharmony_ci			cmd->retry_for_fw_reset++;
383662306a36Sopenharmony_ci
383762306a36Sopenharmony_ci			if (cmd->retry_for_fw_reset == 3) {
383862306a36Sopenharmony_ci				dev_notice(&instance->pdev->dev, "cmd %p, %p:%d"
383962306a36Sopenharmony_ci					"was tried multiple times during reset."
384062306a36Sopenharmony_ci					"Shutting down the HBA\n",
384162306a36Sopenharmony_ci					cmd, cmd->scmd, cmd->sync_cmd);
384262306a36Sopenharmony_ci				instance->instancet->disable_intr(instance);
384362306a36Sopenharmony_ci				atomic_set(&instance->fw_reset_no_pci_access, 1);
384462306a36Sopenharmony_ci				megaraid_sas_kill_hba(instance);
384562306a36Sopenharmony_ci				return;
384662306a36Sopenharmony_ci			}
384762306a36Sopenharmony_ci		}
384862306a36Sopenharmony_ci
384962306a36Sopenharmony_ci		if (cmd->sync_cmd == 1) {
385062306a36Sopenharmony_ci			if (cmd->scmd) {
385162306a36Sopenharmony_ci				dev_notice(&instance->pdev->dev, "unexpected"
385262306a36Sopenharmony_ci					"cmd attached to internal command!\n");
385362306a36Sopenharmony_ci			}
385462306a36Sopenharmony_ci			dev_notice(&instance->pdev->dev, "%p synchronous cmd"
385562306a36Sopenharmony_ci						"on the internal reset queue,"
385662306a36Sopenharmony_ci						"issue it again.\n", cmd);
385762306a36Sopenharmony_ci			cmd->cmd_status_drv = DCMD_INIT;
385862306a36Sopenharmony_ci			instance->instancet->fire_cmd(instance,
385962306a36Sopenharmony_ci							cmd->frame_phys_addr,
386062306a36Sopenharmony_ci							0, instance->reg_set);
386162306a36Sopenharmony_ci		} else if (cmd->scmd) {
386262306a36Sopenharmony_ci			dev_notice(&instance->pdev->dev, "%p scsi cmd [%02x]"
386362306a36Sopenharmony_ci			"detected on the internal queue, issue again.\n",
386462306a36Sopenharmony_ci			cmd, cmd->scmd->cmnd[0]);
386562306a36Sopenharmony_ci
386662306a36Sopenharmony_ci			atomic_inc(&instance->fw_outstanding);
386762306a36Sopenharmony_ci			instance->instancet->fire_cmd(instance,
386862306a36Sopenharmony_ci					cmd->frame_phys_addr,
386962306a36Sopenharmony_ci					cmd->frame_count-1, instance->reg_set);
387062306a36Sopenharmony_ci		} else {
387162306a36Sopenharmony_ci			dev_notice(&instance->pdev->dev, "%p unexpected cmd on the"
387262306a36Sopenharmony_ci				"internal reset defer list while re-issue!!\n",
387362306a36Sopenharmony_ci				cmd);
387462306a36Sopenharmony_ci		}
387562306a36Sopenharmony_ci	}
387662306a36Sopenharmony_ci
387762306a36Sopenharmony_ci	if (instance->aen_cmd) {
387862306a36Sopenharmony_ci		dev_notice(&instance->pdev->dev, "aen_cmd in def process\n");
387962306a36Sopenharmony_ci		megasas_return_cmd(instance, instance->aen_cmd);
388062306a36Sopenharmony_ci
388162306a36Sopenharmony_ci		instance->aen_cmd = NULL;
388262306a36Sopenharmony_ci	}
388362306a36Sopenharmony_ci
388462306a36Sopenharmony_ci	/*
388562306a36Sopenharmony_ci	 * Initiate AEN (Asynchronous Event Notification)
388662306a36Sopenharmony_ci	 */
388762306a36Sopenharmony_ci	seq_num = instance->last_seq_num;
388862306a36Sopenharmony_ci	class_locale.members.reserved = 0;
388962306a36Sopenharmony_ci	class_locale.members.locale = MR_EVT_LOCALE_ALL;
389062306a36Sopenharmony_ci	class_locale.members.class = MR_EVT_CLASS_DEBUG;
389162306a36Sopenharmony_ci
389262306a36Sopenharmony_ci	megasas_register_aen(instance, seq_num, class_locale.word);
389362306a36Sopenharmony_ci}
389462306a36Sopenharmony_ci
389562306a36Sopenharmony_ci/*
389662306a36Sopenharmony_ci * Move the internal reset pending commands to a deferred queue.
389762306a36Sopenharmony_ci *
389862306a36Sopenharmony_ci * We move the commands pending at internal reset time to a
389962306a36Sopenharmony_ci * pending queue. This queue would be flushed after successful
390062306a36Sopenharmony_ci * completion of the internal reset sequence. if the internal reset
390162306a36Sopenharmony_ci * did not complete in time, the kernel reset handler would flush
390262306a36Sopenharmony_ci * these commands.
390362306a36Sopenharmony_ci */
390462306a36Sopenharmony_cistatic void
390562306a36Sopenharmony_cimegasas_internal_reset_defer_cmds(struct megasas_instance *instance)
390662306a36Sopenharmony_ci{
390762306a36Sopenharmony_ci	struct megasas_cmd *cmd;
390862306a36Sopenharmony_ci	int i;
390962306a36Sopenharmony_ci	u16 max_cmd = instance->max_fw_cmds;
391062306a36Sopenharmony_ci	u32 defer_index;
391162306a36Sopenharmony_ci	unsigned long flags;
391262306a36Sopenharmony_ci
391362306a36Sopenharmony_ci	defer_index = 0;
391462306a36Sopenharmony_ci	spin_lock_irqsave(&instance->mfi_pool_lock, flags);
391562306a36Sopenharmony_ci	for (i = 0; i < max_cmd; i++) {
391662306a36Sopenharmony_ci		cmd = instance->cmd_list[i];
391762306a36Sopenharmony_ci		if (cmd->sync_cmd == 1 || cmd->scmd) {
391862306a36Sopenharmony_ci			dev_notice(&instance->pdev->dev, "moving cmd[%d]:%p:%d:%p"
391962306a36Sopenharmony_ci					"on the defer queue as internal\n",
392062306a36Sopenharmony_ci				defer_index, cmd, cmd->sync_cmd, cmd->scmd);
392162306a36Sopenharmony_ci
392262306a36Sopenharmony_ci			if (!list_empty(&cmd->list)) {
392362306a36Sopenharmony_ci				dev_notice(&instance->pdev->dev, "ERROR while"
392462306a36Sopenharmony_ci					" moving this cmd:%p, %d %p, it was"
392562306a36Sopenharmony_ci					"discovered on some list?\n",
392662306a36Sopenharmony_ci					cmd, cmd->sync_cmd, cmd->scmd);
392762306a36Sopenharmony_ci
392862306a36Sopenharmony_ci				list_del_init(&cmd->list);
392962306a36Sopenharmony_ci			}
393062306a36Sopenharmony_ci			defer_index++;
393162306a36Sopenharmony_ci			list_add_tail(&cmd->list,
393262306a36Sopenharmony_ci				&instance->internal_reset_pending_q);
393362306a36Sopenharmony_ci		}
393462306a36Sopenharmony_ci	}
393562306a36Sopenharmony_ci	spin_unlock_irqrestore(&instance->mfi_pool_lock, flags);
393662306a36Sopenharmony_ci}
393762306a36Sopenharmony_ci
393862306a36Sopenharmony_ci
393962306a36Sopenharmony_cistatic void
394062306a36Sopenharmony_ciprocess_fw_state_change_wq(struct work_struct *work)
394162306a36Sopenharmony_ci{
394262306a36Sopenharmony_ci	struct megasas_instance *instance =
394362306a36Sopenharmony_ci		container_of(work, struct megasas_instance, work_init);
394462306a36Sopenharmony_ci	u32 wait;
394562306a36Sopenharmony_ci	unsigned long flags;
394662306a36Sopenharmony_ci
394762306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) != MEGASAS_ADPRESET_SM_INFAULT) {
394862306a36Sopenharmony_ci		dev_notice(&instance->pdev->dev, "error, recovery st %x\n",
394962306a36Sopenharmony_ci			   atomic_read(&instance->adprecovery));
395062306a36Sopenharmony_ci		return ;
395162306a36Sopenharmony_ci	}
395262306a36Sopenharmony_ci
395362306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) == MEGASAS_ADPRESET_SM_INFAULT) {
395462306a36Sopenharmony_ci		dev_notice(&instance->pdev->dev, "FW detected to be in fault"
395562306a36Sopenharmony_ci					"state, restarting it...\n");
395662306a36Sopenharmony_ci
395762306a36Sopenharmony_ci		instance->instancet->disable_intr(instance);
395862306a36Sopenharmony_ci		atomic_set(&instance->fw_outstanding, 0);
395962306a36Sopenharmony_ci
396062306a36Sopenharmony_ci		atomic_set(&instance->fw_reset_no_pci_access, 1);
396162306a36Sopenharmony_ci		instance->instancet->adp_reset(instance, instance->reg_set);
396262306a36Sopenharmony_ci		atomic_set(&instance->fw_reset_no_pci_access, 0);
396362306a36Sopenharmony_ci
396462306a36Sopenharmony_ci		dev_notice(&instance->pdev->dev, "FW restarted successfully,"
396562306a36Sopenharmony_ci					"initiating next stage...\n");
396662306a36Sopenharmony_ci
396762306a36Sopenharmony_ci		dev_notice(&instance->pdev->dev, "HBA recovery state machine,"
396862306a36Sopenharmony_ci					"state 2 starting...\n");
396962306a36Sopenharmony_ci
397062306a36Sopenharmony_ci		/* waiting for about 20 second before start the second init */
397162306a36Sopenharmony_ci		for (wait = 0; wait < 30; wait++) {
397262306a36Sopenharmony_ci			msleep(1000);
397362306a36Sopenharmony_ci		}
397462306a36Sopenharmony_ci
397562306a36Sopenharmony_ci		if (megasas_transition_to_ready(instance, 1)) {
397662306a36Sopenharmony_ci			dev_notice(&instance->pdev->dev, "adapter not ready\n");
397762306a36Sopenharmony_ci
397862306a36Sopenharmony_ci			atomic_set(&instance->fw_reset_no_pci_access, 1);
397962306a36Sopenharmony_ci			megaraid_sas_kill_hba(instance);
398062306a36Sopenharmony_ci			return ;
398162306a36Sopenharmony_ci		}
398262306a36Sopenharmony_ci
398362306a36Sopenharmony_ci		if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) ||
398462306a36Sopenharmony_ci			(instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) ||
398562306a36Sopenharmony_ci			(instance->pdev->device == PCI_DEVICE_ID_LSI_VERDE_ZCR)
398662306a36Sopenharmony_ci			) {
398762306a36Sopenharmony_ci			*instance->consumer = *instance->producer;
398862306a36Sopenharmony_ci		} else {
398962306a36Sopenharmony_ci			*instance->consumer = 0;
399062306a36Sopenharmony_ci			*instance->producer = 0;
399162306a36Sopenharmony_ci		}
399262306a36Sopenharmony_ci
399362306a36Sopenharmony_ci		megasas_issue_init_mfi(instance);
399462306a36Sopenharmony_ci
399562306a36Sopenharmony_ci		spin_lock_irqsave(&instance->hba_lock, flags);
399662306a36Sopenharmony_ci		atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
399762306a36Sopenharmony_ci		spin_unlock_irqrestore(&instance->hba_lock, flags);
399862306a36Sopenharmony_ci		instance->instancet->enable_intr(instance);
399962306a36Sopenharmony_ci
400062306a36Sopenharmony_ci		megasas_issue_pending_cmds_again(instance);
400162306a36Sopenharmony_ci		instance->issuepend_done = 1;
400262306a36Sopenharmony_ci	}
400362306a36Sopenharmony_ci}
400462306a36Sopenharmony_ci
400562306a36Sopenharmony_ci/**
400662306a36Sopenharmony_ci * megasas_deplete_reply_queue -	Processes all completed commands
400762306a36Sopenharmony_ci * @instance:				Adapter soft state
400862306a36Sopenharmony_ci * @alt_status:				Alternate status to be returned to
400962306a36Sopenharmony_ci *					SCSI mid-layer instead of the status
401062306a36Sopenharmony_ci *					returned by the FW
401162306a36Sopenharmony_ci * Note: this must be called with hba lock held
401262306a36Sopenharmony_ci */
401362306a36Sopenharmony_cistatic int
401462306a36Sopenharmony_cimegasas_deplete_reply_queue(struct megasas_instance *instance,
401562306a36Sopenharmony_ci					u8 alt_status)
401662306a36Sopenharmony_ci{
401762306a36Sopenharmony_ci	u32 mfiStatus;
401862306a36Sopenharmony_ci	u32 fw_state;
401962306a36Sopenharmony_ci
402062306a36Sopenharmony_ci	if (instance->instancet->check_reset(instance, instance->reg_set) == 1)
402162306a36Sopenharmony_ci		return IRQ_HANDLED;
402262306a36Sopenharmony_ci
402362306a36Sopenharmony_ci	mfiStatus = instance->instancet->clear_intr(instance);
402462306a36Sopenharmony_ci	if (mfiStatus == 0) {
402562306a36Sopenharmony_ci		/* Hardware may not set outbound_intr_status in MSI-X mode */
402662306a36Sopenharmony_ci		if (!instance->msix_vectors)
402762306a36Sopenharmony_ci			return IRQ_NONE;
402862306a36Sopenharmony_ci	}
402962306a36Sopenharmony_ci
403062306a36Sopenharmony_ci	instance->mfiStatus = mfiStatus;
403162306a36Sopenharmony_ci
403262306a36Sopenharmony_ci	if ((mfiStatus & MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE)) {
403362306a36Sopenharmony_ci		fw_state = instance->instancet->read_fw_status_reg(
403462306a36Sopenharmony_ci				instance) & MFI_STATE_MASK;
403562306a36Sopenharmony_ci
403662306a36Sopenharmony_ci		if (fw_state != MFI_STATE_FAULT) {
403762306a36Sopenharmony_ci			dev_notice(&instance->pdev->dev, "fw state:%x\n",
403862306a36Sopenharmony_ci						fw_state);
403962306a36Sopenharmony_ci		}
404062306a36Sopenharmony_ci
404162306a36Sopenharmony_ci		if ((fw_state == MFI_STATE_FAULT) &&
404262306a36Sopenharmony_ci				(instance->disableOnlineCtrlReset == 0)) {
404362306a36Sopenharmony_ci			dev_notice(&instance->pdev->dev, "wait adp restart\n");
404462306a36Sopenharmony_ci
404562306a36Sopenharmony_ci			if ((instance->pdev->device ==
404662306a36Sopenharmony_ci					PCI_DEVICE_ID_LSI_SAS1064R) ||
404762306a36Sopenharmony_ci				(instance->pdev->device ==
404862306a36Sopenharmony_ci					PCI_DEVICE_ID_DELL_PERC5) ||
404962306a36Sopenharmony_ci				(instance->pdev->device ==
405062306a36Sopenharmony_ci					PCI_DEVICE_ID_LSI_VERDE_ZCR)) {
405162306a36Sopenharmony_ci
405262306a36Sopenharmony_ci				*instance->consumer =
405362306a36Sopenharmony_ci					cpu_to_le32(MEGASAS_ADPRESET_INPROG_SIGN);
405462306a36Sopenharmony_ci			}
405562306a36Sopenharmony_ci
405662306a36Sopenharmony_ci
405762306a36Sopenharmony_ci			instance->instancet->disable_intr(instance);
405862306a36Sopenharmony_ci			atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
405962306a36Sopenharmony_ci			instance->issuepend_done = 0;
406062306a36Sopenharmony_ci
406162306a36Sopenharmony_ci			atomic_set(&instance->fw_outstanding, 0);
406262306a36Sopenharmony_ci			megasas_internal_reset_defer_cmds(instance);
406362306a36Sopenharmony_ci
406462306a36Sopenharmony_ci			dev_notice(&instance->pdev->dev, "fwState=%x, stage:%d\n",
406562306a36Sopenharmony_ci					fw_state, atomic_read(&instance->adprecovery));
406662306a36Sopenharmony_ci
406762306a36Sopenharmony_ci			schedule_work(&instance->work_init);
406862306a36Sopenharmony_ci			return IRQ_HANDLED;
406962306a36Sopenharmony_ci
407062306a36Sopenharmony_ci		} else {
407162306a36Sopenharmony_ci			dev_notice(&instance->pdev->dev, "fwstate:%x, dis_OCR=%x\n",
407262306a36Sopenharmony_ci				fw_state, instance->disableOnlineCtrlReset);
407362306a36Sopenharmony_ci		}
407462306a36Sopenharmony_ci	}
407562306a36Sopenharmony_ci
407662306a36Sopenharmony_ci	tasklet_schedule(&instance->isr_tasklet);
407762306a36Sopenharmony_ci	return IRQ_HANDLED;
407862306a36Sopenharmony_ci}
407962306a36Sopenharmony_ci
408062306a36Sopenharmony_ci/**
408162306a36Sopenharmony_ci * megasas_isr - isr entry point
408262306a36Sopenharmony_ci * @irq:	IRQ number
408362306a36Sopenharmony_ci * @devp:	IRQ context address
408462306a36Sopenharmony_ci */
408562306a36Sopenharmony_cistatic irqreturn_t megasas_isr(int irq, void *devp)
408662306a36Sopenharmony_ci{
408762306a36Sopenharmony_ci	struct megasas_irq_context *irq_context = devp;
408862306a36Sopenharmony_ci	struct megasas_instance *instance = irq_context->instance;
408962306a36Sopenharmony_ci	unsigned long flags;
409062306a36Sopenharmony_ci	irqreturn_t rc;
409162306a36Sopenharmony_ci
409262306a36Sopenharmony_ci	if (atomic_read(&instance->fw_reset_no_pci_access))
409362306a36Sopenharmony_ci		return IRQ_HANDLED;
409462306a36Sopenharmony_ci
409562306a36Sopenharmony_ci	spin_lock_irqsave(&instance->hba_lock, flags);
409662306a36Sopenharmony_ci	rc = megasas_deplete_reply_queue(instance, DID_OK);
409762306a36Sopenharmony_ci	spin_unlock_irqrestore(&instance->hba_lock, flags);
409862306a36Sopenharmony_ci
409962306a36Sopenharmony_ci	return rc;
410062306a36Sopenharmony_ci}
410162306a36Sopenharmony_ci
410262306a36Sopenharmony_ci/**
410362306a36Sopenharmony_ci * megasas_transition_to_ready -	Move the FW to READY state
410462306a36Sopenharmony_ci * @instance:				Adapter soft state
410562306a36Sopenharmony_ci * @ocr:				Adapter reset state
410662306a36Sopenharmony_ci *
410762306a36Sopenharmony_ci * During the initialization, FW passes can potentially be in any one of
410862306a36Sopenharmony_ci * several possible states. If the FW in operational, waiting-for-handshake
410962306a36Sopenharmony_ci * states, driver must take steps to bring it to ready state. Otherwise, it
411062306a36Sopenharmony_ci * has to wait for the ready state.
411162306a36Sopenharmony_ci */
411262306a36Sopenharmony_ciint
411362306a36Sopenharmony_cimegasas_transition_to_ready(struct megasas_instance *instance, int ocr)
411462306a36Sopenharmony_ci{
411562306a36Sopenharmony_ci	int i;
411662306a36Sopenharmony_ci	u8 max_wait;
411762306a36Sopenharmony_ci	u32 fw_state;
411862306a36Sopenharmony_ci	u32 abs_state, curr_abs_state;
411962306a36Sopenharmony_ci
412062306a36Sopenharmony_ci	abs_state = instance->instancet->read_fw_status_reg(instance);
412162306a36Sopenharmony_ci	fw_state = abs_state & MFI_STATE_MASK;
412262306a36Sopenharmony_ci
412362306a36Sopenharmony_ci	if (fw_state != MFI_STATE_READY)
412462306a36Sopenharmony_ci		dev_info(&instance->pdev->dev, "Waiting for FW to come to ready"
412562306a36Sopenharmony_ci		       " state\n");
412662306a36Sopenharmony_ci
412762306a36Sopenharmony_ci	while (fw_state != MFI_STATE_READY) {
412862306a36Sopenharmony_ci
412962306a36Sopenharmony_ci		switch (fw_state) {
413062306a36Sopenharmony_ci
413162306a36Sopenharmony_ci		case MFI_STATE_FAULT:
413262306a36Sopenharmony_ci			dev_printk(KERN_ERR, &instance->pdev->dev,
413362306a36Sopenharmony_ci				   "FW in FAULT state, Fault code:0x%x subcode:0x%x func:%s\n",
413462306a36Sopenharmony_ci				   abs_state & MFI_STATE_FAULT_CODE,
413562306a36Sopenharmony_ci				   abs_state & MFI_STATE_FAULT_SUBCODE, __func__);
413662306a36Sopenharmony_ci			if (ocr) {
413762306a36Sopenharmony_ci				max_wait = MEGASAS_RESET_WAIT_TIME;
413862306a36Sopenharmony_ci				break;
413962306a36Sopenharmony_ci			} else {
414062306a36Sopenharmony_ci				dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n");
414162306a36Sopenharmony_ci				megasas_dump_reg_set(instance->reg_set);
414262306a36Sopenharmony_ci				return -ENODEV;
414362306a36Sopenharmony_ci			}
414462306a36Sopenharmony_ci
414562306a36Sopenharmony_ci		case MFI_STATE_WAIT_HANDSHAKE:
414662306a36Sopenharmony_ci			/*
414762306a36Sopenharmony_ci			 * Set the CLR bit in inbound doorbell
414862306a36Sopenharmony_ci			 */
414962306a36Sopenharmony_ci			if ((instance->pdev->device ==
415062306a36Sopenharmony_ci				PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
415162306a36Sopenharmony_ci				(instance->pdev->device ==
415262306a36Sopenharmony_ci				 PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
415362306a36Sopenharmony_ci				(instance->adapter_type != MFI_SERIES))
415462306a36Sopenharmony_ci				writel(
415562306a36Sopenharmony_ci				  MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
415662306a36Sopenharmony_ci				  &instance->reg_set->doorbell);
415762306a36Sopenharmony_ci			else
415862306a36Sopenharmony_ci				writel(
415962306a36Sopenharmony_ci				    MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
416062306a36Sopenharmony_ci					&instance->reg_set->inbound_doorbell);
416162306a36Sopenharmony_ci
416262306a36Sopenharmony_ci			max_wait = MEGASAS_RESET_WAIT_TIME;
416362306a36Sopenharmony_ci			break;
416462306a36Sopenharmony_ci
416562306a36Sopenharmony_ci		case MFI_STATE_BOOT_MESSAGE_PENDING:
416662306a36Sopenharmony_ci			if ((instance->pdev->device ==
416762306a36Sopenharmony_ci			     PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
416862306a36Sopenharmony_ci				(instance->pdev->device ==
416962306a36Sopenharmony_ci				 PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
417062306a36Sopenharmony_ci				(instance->adapter_type != MFI_SERIES))
417162306a36Sopenharmony_ci				writel(MFI_INIT_HOTPLUG,
417262306a36Sopenharmony_ci				       &instance->reg_set->doorbell);
417362306a36Sopenharmony_ci			else
417462306a36Sopenharmony_ci				writel(MFI_INIT_HOTPLUG,
417562306a36Sopenharmony_ci					&instance->reg_set->inbound_doorbell);
417662306a36Sopenharmony_ci
417762306a36Sopenharmony_ci			max_wait = MEGASAS_RESET_WAIT_TIME;
417862306a36Sopenharmony_ci			break;
417962306a36Sopenharmony_ci
418062306a36Sopenharmony_ci		case MFI_STATE_OPERATIONAL:
418162306a36Sopenharmony_ci			/*
418262306a36Sopenharmony_ci			 * Bring it to READY state; assuming max wait 10 secs
418362306a36Sopenharmony_ci			 */
418462306a36Sopenharmony_ci			instance->instancet->disable_intr(instance);
418562306a36Sopenharmony_ci			if ((instance->pdev->device ==
418662306a36Sopenharmony_ci				PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
418762306a36Sopenharmony_ci				(instance->pdev->device ==
418862306a36Sopenharmony_ci				PCI_DEVICE_ID_LSI_SAS0071SKINNY)  ||
418962306a36Sopenharmony_ci				(instance->adapter_type != MFI_SERIES)) {
419062306a36Sopenharmony_ci				writel(MFI_RESET_FLAGS,
419162306a36Sopenharmony_ci					&instance->reg_set->doorbell);
419262306a36Sopenharmony_ci
419362306a36Sopenharmony_ci				if (instance->adapter_type != MFI_SERIES) {
419462306a36Sopenharmony_ci					for (i = 0; i < (10 * 1000); i += 20) {
419562306a36Sopenharmony_ci						if (megasas_readl(
419662306a36Sopenharmony_ci							    instance,
419762306a36Sopenharmony_ci							    &instance->
419862306a36Sopenharmony_ci							    reg_set->
419962306a36Sopenharmony_ci							    doorbell) & 1)
420062306a36Sopenharmony_ci							msleep(20);
420162306a36Sopenharmony_ci						else
420262306a36Sopenharmony_ci							break;
420362306a36Sopenharmony_ci					}
420462306a36Sopenharmony_ci				}
420562306a36Sopenharmony_ci			} else
420662306a36Sopenharmony_ci				writel(MFI_RESET_FLAGS,
420762306a36Sopenharmony_ci					&instance->reg_set->inbound_doorbell);
420862306a36Sopenharmony_ci
420962306a36Sopenharmony_ci			max_wait = MEGASAS_RESET_WAIT_TIME;
421062306a36Sopenharmony_ci			break;
421162306a36Sopenharmony_ci
421262306a36Sopenharmony_ci		case MFI_STATE_UNDEFINED:
421362306a36Sopenharmony_ci			/*
421462306a36Sopenharmony_ci			 * This state should not last for more than 2 seconds
421562306a36Sopenharmony_ci			 */
421662306a36Sopenharmony_ci			max_wait = MEGASAS_RESET_WAIT_TIME;
421762306a36Sopenharmony_ci			break;
421862306a36Sopenharmony_ci
421962306a36Sopenharmony_ci		case MFI_STATE_BB_INIT:
422062306a36Sopenharmony_ci			max_wait = MEGASAS_RESET_WAIT_TIME;
422162306a36Sopenharmony_ci			break;
422262306a36Sopenharmony_ci
422362306a36Sopenharmony_ci		case MFI_STATE_FW_INIT:
422462306a36Sopenharmony_ci			max_wait = MEGASAS_RESET_WAIT_TIME;
422562306a36Sopenharmony_ci			break;
422662306a36Sopenharmony_ci
422762306a36Sopenharmony_ci		case MFI_STATE_FW_INIT_2:
422862306a36Sopenharmony_ci			max_wait = MEGASAS_RESET_WAIT_TIME;
422962306a36Sopenharmony_ci			break;
423062306a36Sopenharmony_ci
423162306a36Sopenharmony_ci		case MFI_STATE_DEVICE_SCAN:
423262306a36Sopenharmony_ci			max_wait = MEGASAS_RESET_WAIT_TIME;
423362306a36Sopenharmony_ci			break;
423462306a36Sopenharmony_ci
423562306a36Sopenharmony_ci		case MFI_STATE_FLUSH_CACHE:
423662306a36Sopenharmony_ci			max_wait = MEGASAS_RESET_WAIT_TIME;
423762306a36Sopenharmony_ci			break;
423862306a36Sopenharmony_ci
423962306a36Sopenharmony_ci		default:
424062306a36Sopenharmony_ci			dev_printk(KERN_DEBUG, &instance->pdev->dev, "Unknown state 0x%x\n",
424162306a36Sopenharmony_ci			       fw_state);
424262306a36Sopenharmony_ci			dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n");
424362306a36Sopenharmony_ci			megasas_dump_reg_set(instance->reg_set);
424462306a36Sopenharmony_ci			return -ENODEV;
424562306a36Sopenharmony_ci		}
424662306a36Sopenharmony_ci
424762306a36Sopenharmony_ci		/*
424862306a36Sopenharmony_ci		 * The cur_state should not last for more than max_wait secs
424962306a36Sopenharmony_ci		 */
425062306a36Sopenharmony_ci		for (i = 0; i < max_wait * 50; i++) {
425162306a36Sopenharmony_ci			curr_abs_state = instance->instancet->
425262306a36Sopenharmony_ci				read_fw_status_reg(instance);
425362306a36Sopenharmony_ci
425462306a36Sopenharmony_ci			if (abs_state == curr_abs_state) {
425562306a36Sopenharmony_ci				msleep(20);
425662306a36Sopenharmony_ci			} else
425762306a36Sopenharmony_ci				break;
425862306a36Sopenharmony_ci		}
425962306a36Sopenharmony_ci
426062306a36Sopenharmony_ci		/*
426162306a36Sopenharmony_ci		 * Return error if fw_state hasn't changed after max_wait
426262306a36Sopenharmony_ci		 */
426362306a36Sopenharmony_ci		if (curr_abs_state == abs_state) {
426462306a36Sopenharmony_ci			dev_printk(KERN_DEBUG, &instance->pdev->dev, "FW state [%d] hasn't changed "
426562306a36Sopenharmony_ci			       "in %d secs\n", fw_state, max_wait);
426662306a36Sopenharmony_ci			dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n");
426762306a36Sopenharmony_ci			megasas_dump_reg_set(instance->reg_set);
426862306a36Sopenharmony_ci			return -ENODEV;
426962306a36Sopenharmony_ci		}
427062306a36Sopenharmony_ci
427162306a36Sopenharmony_ci		abs_state = curr_abs_state;
427262306a36Sopenharmony_ci		fw_state = curr_abs_state & MFI_STATE_MASK;
427362306a36Sopenharmony_ci	}
427462306a36Sopenharmony_ci	dev_info(&instance->pdev->dev, "FW now in Ready state\n");
427562306a36Sopenharmony_ci
427662306a36Sopenharmony_ci	return 0;
427762306a36Sopenharmony_ci}
427862306a36Sopenharmony_ci
427962306a36Sopenharmony_ci/**
428062306a36Sopenharmony_ci * megasas_teardown_frame_pool -	Destroy the cmd frame DMA pool
428162306a36Sopenharmony_ci * @instance:				Adapter soft state
428262306a36Sopenharmony_ci */
428362306a36Sopenharmony_cistatic void megasas_teardown_frame_pool(struct megasas_instance *instance)
428462306a36Sopenharmony_ci{
428562306a36Sopenharmony_ci	int i;
428662306a36Sopenharmony_ci	u16 max_cmd = instance->max_mfi_cmds;
428762306a36Sopenharmony_ci	struct megasas_cmd *cmd;
428862306a36Sopenharmony_ci
428962306a36Sopenharmony_ci	if (!instance->frame_dma_pool)
429062306a36Sopenharmony_ci		return;
429162306a36Sopenharmony_ci
429262306a36Sopenharmony_ci	/*
429362306a36Sopenharmony_ci	 * Return all frames to pool
429462306a36Sopenharmony_ci	 */
429562306a36Sopenharmony_ci	for (i = 0; i < max_cmd; i++) {
429662306a36Sopenharmony_ci
429762306a36Sopenharmony_ci		cmd = instance->cmd_list[i];
429862306a36Sopenharmony_ci
429962306a36Sopenharmony_ci		if (cmd->frame)
430062306a36Sopenharmony_ci			dma_pool_free(instance->frame_dma_pool, cmd->frame,
430162306a36Sopenharmony_ci				      cmd->frame_phys_addr);
430262306a36Sopenharmony_ci
430362306a36Sopenharmony_ci		if (cmd->sense)
430462306a36Sopenharmony_ci			dma_pool_free(instance->sense_dma_pool, cmd->sense,
430562306a36Sopenharmony_ci				      cmd->sense_phys_addr);
430662306a36Sopenharmony_ci	}
430762306a36Sopenharmony_ci
430862306a36Sopenharmony_ci	/*
430962306a36Sopenharmony_ci	 * Now destroy the pool itself
431062306a36Sopenharmony_ci	 */
431162306a36Sopenharmony_ci	dma_pool_destroy(instance->frame_dma_pool);
431262306a36Sopenharmony_ci	dma_pool_destroy(instance->sense_dma_pool);
431362306a36Sopenharmony_ci
431462306a36Sopenharmony_ci	instance->frame_dma_pool = NULL;
431562306a36Sopenharmony_ci	instance->sense_dma_pool = NULL;
431662306a36Sopenharmony_ci}
431762306a36Sopenharmony_ci
431862306a36Sopenharmony_ci/**
431962306a36Sopenharmony_ci * megasas_create_frame_pool -	Creates DMA pool for cmd frames
432062306a36Sopenharmony_ci * @instance:			Adapter soft state
432162306a36Sopenharmony_ci *
432262306a36Sopenharmony_ci * Each command packet has an embedded DMA memory buffer that is used for
432362306a36Sopenharmony_ci * filling MFI frame and the SG list that immediately follows the frame. This
432462306a36Sopenharmony_ci * function creates those DMA memory buffers for each command packet by using
432562306a36Sopenharmony_ci * PCI pool facility.
432662306a36Sopenharmony_ci */
432762306a36Sopenharmony_cistatic int megasas_create_frame_pool(struct megasas_instance *instance)
432862306a36Sopenharmony_ci{
432962306a36Sopenharmony_ci	int i;
433062306a36Sopenharmony_ci	u16 max_cmd;
433162306a36Sopenharmony_ci	u32 frame_count;
433262306a36Sopenharmony_ci	struct megasas_cmd *cmd;
433362306a36Sopenharmony_ci
433462306a36Sopenharmony_ci	max_cmd = instance->max_mfi_cmds;
433562306a36Sopenharmony_ci
433662306a36Sopenharmony_ci	/*
433762306a36Sopenharmony_ci	 * For MFI controllers.
433862306a36Sopenharmony_ci	 * max_num_sge = 60
433962306a36Sopenharmony_ci	 * max_sge_sz  = 16 byte (sizeof megasas_sge_skinny)
434062306a36Sopenharmony_ci	 * Total 960 byte (15 MFI frame of 64 byte)
434162306a36Sopenharmony_ci	 *
434262306a36Sopenharmony_ci	 * Fusion adapter require only 3 extra frame.
434362306a36Sopenharmony_ci	 * max_num_sge = 16 (defined as MAX_IOCTL_SGE)
434462306a36Sopenharmony_ci	 * max_sge_sz  = 12 byte (sizeof  megasas_sge64)
434562306a36Sopenharmony_ci	 * Total 192 byte (3 MFI frame of 64 byte)
434662306a36Sopenharmony_ci	 */
434762306a36Sopenharmony_ci	frame_count = (instance->adapter_type == MFI_SERIES) ?
434862306a36Sopenharmony_ci			(15 + 1) : (3 + 1);
434962306a36Sopenharmony_ci	instance->mfi_frame_size = MEGAMFI_FRAME_SIZE * frame_count;
435062306a36Sopenharmony_ci	/*
435162306a36Sopenharmony_ci	 * Use DMA pool facility provided by PCI layer
435262306a36Sopenharmony_ci	 */
435362306a36Sopenharmony_ci	instance->frame_dma_pool = dma_pool_create("megasas frame pool",
435462306a36Sopenharmony_ci					&instance->pdev->dev,
435562306a36Sopenharmony_ci					instance->mfi_frame_size, 256, 0);
435662306a36Sopenharmony_ci
435762306a36Sopenharmony_ci	if (!instance->frame_dma_pool) {
435862306a36Sopenharmony_ci		dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup frame pool\n");
435962306a36Sopenharmony_ci		return -ENOMEM;
436062306a36Sopenharmony_ci	}
436162306a36Sopenharmony_ci
436262306a36Sopenharmony_ci	instance->sense_dma_pool = dma_pool_create("megasas sense pool",
436362306a36Sopenharmony_ci						   &instance->pdev->dev, 128,
436462306a36Sopenharmony_ci						   4, 0);
436562306a36Sopenharmony_ci
436662306a36Sopenharmony_ci	if (!instance->sense_dma_pool) {
436762306a36Sopenharmony_ci		dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup sense pool\n");
436862306a36Sopenharmony_ci
436962306a36Sopenharmony_ci		dma_pool_destroy(instance->frame_dma_pool);
437062306a36Sopenharmony_ci		instance->frame_dma_pool = NULL;
437162306a36Sopenharmony_ci
437262306a36Sopenharmony_ci		return -ENOMEM;
437362306a36Sopenharmony_ci	}
437462306a36Sopenharmony_ci
437562306a36Sopenharmony_ci	/*
437662306a36Sopenharmony_ci	 * Allocate and attach a frame to each of the commands in cmd_list.
437762306a36Sopenharmony_ci	 * By making cmd->index as the context instead of the &cmd, we can
437862306a36Sopenharmony_ci	 * always use 32bit context regardless of the architecture
437962306a36Sopenharmony_ci	 */
438062306a36Sopenharmony_ci	for (i = 0; i < max_cmd; i++) {
438162306a36Sopenharmony_ci
438262306a36Sopenharmony_ci		cmd = instance->cmd_list[i];
438362306a36Sopenharmony_ci
438462306a36Sopenharmony_ci		cmd->frame = dma_pool_zalloc(instance->frame_dma_pool,
438562306a36Sopenharmony_ci					    GFP_KERNEL, &cmd->frame_phys_addr);
438662306a36Sopenharmony_ci
438762306a36Sopenharmony_ci		cmd->sense = dma_pool_alloc(instance->sense_dma_pool,
438862306a36Sopenharmony_ci					    GFP_KERNEL, &cmd->sense_phys_addr);
438962306a36Sopenharmony_ci
439062306a36Sopenharmony_ci		/*
439162306a36Sopenharmony_ci		 * megasas_teardown_frame_pool() takes care of freeing
439262306a36Sopenharmony_ci		 * whatever has been allocated
439362306a36Sopenharmony_ci		 */
439462306a36Sopenharmony_ci		if (!cmd->frame || !cmd->sense) {
439562306a36Sopenharmony_ci			dev_printk(KERN_DEBUG, &instance->pdev->dev, "dma_pool_alloc failed\n");
439662306a36Sopenharmony_ci			megasas_teardown_frame_pool(instance);
439762306a36Sopenharmony_ci			return -ENOMEM;
439862306a36Sopenharmony_ci		}
439962306a36Sopenharmony_ci
440062306a36Sopenharmony_ci		cmd->frame->io.context = cpu_to_le32(cmd->index);
440162306a36Sopenharmony_ci		cmd->frame->io.pad_0 = 0;
440262306a36Sopenharmony_ci		if ((instance->adapter_type == MFI_SERIES) && reset_devices)
440362306a36Sopenharmony_ci			cmd->frame->hdr.cmd = MFI_CMD_INVALID;
440462306a36Sopenharmony_ci	}
440562306a36Sopenharmony_ci
440662306a36Sopenharmony_ci	return 0;
440762306a36Sopenharmony_ci}
440862306a36Sopenharmony_ci
440962306a36Sopenharmony_ci/**
441062306a36Sopenharmony_ci * megasas_free_cmds -	Free all the cmds in the free cmd pool
441162306a36Sopenharmony_ci * @instance:		Adapter soft state
441262306a36Sopenharmony_ci */
441362306a36Sopenharmony_civoid megasas_free_cmds(struct megasas_instance *instance)
441462306a36Sopenharmony_ci{
441562306a36Sopenharmony_ci	int i;
441662306a36Sopenharmony_ci
441762306a36Sopenharmony_ci	/* First free the MFI frame pool */
441862306a36Sopenharmony_ci	megasas_teardown_frame_pool(instance);
441962306a36Sopenharmony_ci
442062306a36Sopenharmony_ci	/* Free all the commands in the cmd_list */
442162306a36Sopenharmony_ci	for (i = 0; i < instance->max_mfi_cmds; i++)
442262306a36Sopenharmony_ci
442362306a36Sopenharmony_ci		kfree(instance->cmd_list[i]);
442462306a36Sopenharmony_ci
442562306a36Sopenharmony_ci	/* Free the cmd_list buffer itself */
442662306a36Sopenharmony_ci	kfree(instance->cmd_list);
442762306a36Sopenharmony_ci	instance->cmd_list = NULL;
442862306a36Sopenharmony_ci
442962306a36Sopenharmony_ci	INIT_LIST_HEAD(&instance->cmd_pool);
443062306a36Sopenharmony_ci}
443162306a36Sopenharmony_ci
443262306a36Sopenharmony_ci/**
443362306a36Sopenharmony_ci * megasas_alloc_cmds -	Allocates the command packets
443462306a36Sopenharmony_ci * @instance:		Adapter soft state
443562306a36Sopenharmony_ci *
443662306a36Sopenharmony_ci * Each command that is issued to the FW, whether IO commands from the OS or
443762306a36Sopenharmony_ci * internal commands like IOCTLs, are wrapped in local data structure called
443862306a36Sopenharmony_ci * megasas_cmd. The frame embedded in this megasas_cmd is actually issued to
443962306a36Sopenharmony_ci * the FW.
444062306a36Sopenharmony_ci *
444162306a36Sopenharmony_ci * Each frame has a 32-bit field called context (tag). This context is used
444262306a36Sopenharmony_ci * to get back the megasas_cmd from the frame when a frame gets completed in
444362306a36Sopenharmony_ci * the ISR. Typically the address of the megasas_cmd itself would be used as
444462306a36Sopenharmony_ci * the context. But we wanted to keep the differences between 32 and 64 bit
444562306a36Sopenharmony_ci * systems to the mininum. We always use 32 bit integers for the context. In
444662306a36Sopenharmony_ci * this driver, the 32 bit values are the indices into an array cmd_list.
444762306a36Sopenharmony_ci * This array is used only to look up the megasas_cmd given the context. The
444862306a36Sopenharmony_ci * free commands themselves are maintained in a linked list called cmd_pool.
444962306a36Sopenharmony_ci */
445062306a36Sopenharmony_ciint megasas_alloc_cmds(struct megasas_instance *instance)
445162306a36Sopenharmony_ci{
445262306a36Sopenharmony_ci	int i;
445362306a36Sopenharmony_ci	int j;
445462306a36Sopenharmony_ci	u16 max_cmd;
445562306a36Sopenharmony_ci	struct megasas_cmd *cmd;
445662306a36Sopenharmony_ci
445762306a36Sopenharmony_ci	max_cmd = instance->max_mfi_cmds;
445862306a36Sopenharmony_ci
445962306a36Sopenharmony_ci	/*
446062306a36Sopenharmony_ci	 * instance->cmd_list is an array of struct megasas_cmd pointers.
446162306a36Sopenharmony_ci	 * Allocate the dynamic array first and then allocate individual
446262306a36Sopenharmony_ci	 * commands.
446362306a36Sopenharmony_ci	 */
446462306a36Sopenharmony_ci	instance->cmd_list = kcalloc(max_cmd, sizeof(struct megasas_cmd*), GFP_KERNEL);
446562306a36Sopenharmony_ci
446662306a36Sopenharmony_ci	if (!instance->cmd_list) {
446762306a36Sopenharmony_ci		dev_printk(KERN_DEBUG, &instance->pdev->dev, "out of memory\n");
446862306a36Sopenharmony_ci		return -ENOMEM;
446962306a36Sopenharmony_ci	}
447062306a36Sopenharmony_ci
447162306a36Sopenharmony_ci	for (i = 0; i < max_cmd; i++) {
447262306a36Sopenharmony_ci		instance->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd),
447362306a36Sopenharmony_ci						GFP_KERNEL);
447462306a36Sopenharmony_ci
447562306a36Sopenharmony_ci		if (!instance->cmd_list[i]) {
447662306a36Sopenharmony_ci
447762306a36Sopenharmony_ci			for (j = 0; j < i; j++)
447862306a36Sopenharmony_ci				kfree(instance->cmd_list[j]);
447962306a36Sopenharmony_ci
448062306a36Sopenharmony_ci			kfree(instance->cmd_list);
448162306a36Sopenharmony_ci			instance->cmd_list = NULL;
448262306a36Sopenharmony_ci
448362306a36Sopenharmony_ci			return -ENOMEM;
448462306a36Sopenharmony_ci		}
448562306a36Sopenharmony_ci	}
448662306a36Sopenharmony_ci
448762306a36Sopenharmony_ci	for (i = 0; i < max_cmd; i++) {
448862306a36Sopenharmony_ci		cmd = instance->cmd_list[i];
448962306a36Sopenharmony_ci		memset(cmd, 0, sizeof(struct megasas_cmd));
449062306a36Sopenharmony_ci		cmd->index = i;
449162306a36Sopenharmony_ci		cmd->scmd = NULL;
449262306a36Sopenharmony_ci		cmd->instance = instance;
449362306a36Sopenharmony_ci
449462306a36Sopenharmony_ci		list_add_tail(&cmd->list, &instance->cmd_pool);
449562306a36Sopenharmony_ci	}
449662306a36Sopenharmony_ci
449762306a36Sopenharmony_ci	/*
449862306a36Sopenharmony_ci	 * Create a frame pool and assign one frame to each cmd
449962306a36Sopenharmony_ci	 */
450062306a36Sopenharmony_ci	if (megasas_create_frame_pool(instance)) {
450162306a36Sopenharmony_ci		dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error creating frame DMA pool\n");
450262306a36Sopenharmony_ci		megasas_free_cmds(instance);
450362306a36Sopenharmony_ci		return -ENOMEM;
450462306a36Sopenharmony_ci	}
450562306a36Sopenharmony_ci
450662306a36Sopenharmony_ci	return 0;
450762306a36Sopenharmony_ci}
450862306a36Sopenharmony_ci
450962306a36Sopenharmony_ci/*
451062306a36Sopenharmony_ci * dcmd_timeout_ocr_possible -	Check if OCR is possible based on Driver/FW state.
451162306a36Sopenharmony_ci * @instance:				Adapter soft state
451262306a36Sopenharmony_ci *
451362306a36Sopenharmony_ci * Return 0 for only Fusion adapter, if driver load/unload is not in progress
451462306a36Sopenharmony_ci * or FW is not under OCR.
451562306a36Sopenharmony_ci */
451662306a36Sopenharmony_ciinline int
451762306a36Sopenharmony_cidcmd_timeout_ocr_possible(struct megasas_instance *instance) {
451862306a36Sopenharmony_ci
451962306a36Sopenharmony_ci	if (instance->adapter_type == MFI_SERIES)
452062306a36Sopenharmony_ci		return KILL_ADAPTER;
452162306a36Sopenharmony_ci	else if (instance->unload ||
452262306a36Sopenharmony_ci			test_bit(MEGASAS_FUSION_OCR_NOT_POSSIBLE,
452362306a36Sopenharmony_ci				 &instance->reset_flags))
452462306a36Sopenharmony_ci		return IGNORE_TIMEOUT;
452562306a36Sopenharmony_ci	else
452662306a36Sopenharmony_ci		return INITIATE_OCR;
452762306a36Sopenharmony_ci}
452862306a36Sopenharmony_ci
452962306a36Sopenharmony_cistatic void
453062306a36Sopenharmony_cimegasas_get_pd_info(struct megasas_instance *instance, struct scsi_device *sdev)
453162306a36Sopenharmony_ci{
453262306a36Sopenharmony_ci	int ret;
453362306a36Sopenharmony_ci	struct megasas_cmd *cmd;
453462306a36Sopenharmony_ci	struct megasas_dcmd_frame *dcmd;
453562306a36Sopenharmony_ci
453662306a36Sopenharmony_ci	struct MR_PRIV_DEVICE *mr_device_priv_data;
453762306a36Sopenharmony_ci	u16 device_id = 0;
453862306a36Sopenharmony_ci
453962306a36Sopenharmony_ci	device_id = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id;
454062306a36Sopenharmony_ci	cmd = megasas_get_cmd(instance);
454162306a36Sopenharmony_ci
454262306a36Sopenharmony_ci	if (!cmd) {
454362306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "Failed to get cmd %s\n", __func__);
454462306a36Sopenharmony_ci		return;
454562306a36Sopenharmony_ci	}
454662306a36Sopenharmony_ci
454762306a36Sopenharmony_ci	dcmd = &cmd->frame->dcmd;
454862306a36Sopenharmony_ci
454962306a36Sopenharmony_ci	memset(instance->pd_info, 0, sizeof(*instance->pd_info));
455062306a36Sopenharmony_ci	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
455162306a36Sopenharmony_ci
455262306a36Sopenharmony_ci	dcmd->mbox.s[0] = cpu_to_le16(device_id);
455362306a36Sopenharmony_ci	dcmd->cmd = MFI_CMD_DCMD;
455462306a36Sopenharmony_ci	dcmd->cmd_status = 0xFF;
455562306a36Sopenharmony_ci	dcmd->sge_count = 1;
455662306a36Sopenharmony_ci	dcmd->flags = MFI_FRAME_DIR_READ;
455762306a36Sopenharmony_ci	dcmd->timeout = 0;
455862306a36Sopenharmony_ci	dcmd->pad_0 = 0;
455962306a36Sopenharmony_ci	dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_PD_INFO));
456062306a36Sopenharmony_ci	dcmd->opcode = cpu_to_le32(MR_DCMD_PD_GET_INFO);
456162306a36Sopenharmony_ci
456262306a36Sopenharmony_ci	megasas_set_dma_settings(instance, dcmd, instance->pd_info_h,
456362306a36Sopenharmony_ci				 sizeof(struct MR_PD_INFO));
456462306a36Sopenharmony_ci
456562306a36Sopenharmony_ci	if ((instance->adapter_type != MFI_SERIES) &&
456662306a36Sopenharmony_ci	    !instance->mask_interrupts)
456762306a36Sopenharmony_ci		ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
456862306a36Sopenharmony_ci	else
456962306a36Sopenharmony_ci		ret = megasas_issue_polled(instance, cmd);
457062306a36Sopenharmony_ci
457162306a36Sopenharmony_ci	switch (ret) {
457262306a36Sopenharmony_ci	case DCMD_SUCCESS:
457362306a36Sopenharmony_ci		mr_device_priv_data = sdev->hostdata;
457462306a36Sopenharmony_ci		le16_to_cpus((u16 *)&instance->pd_info->state.ddf.pdType);
457562306a36Sopenharmony_ci		mr_device_priv_data->interface_type =
457662306a36Sopenharmony_ci				instance->pd_info->state.ddf.pdType.intf;
457762306a36Sopenharmony_ci		break;
457862306a36Sopenharmony_ci
457962306a36Sopenharmony_ci	case DCMD_TIMEOUT:
458062306a36Sopenharmony_ci
458162306a36Sopenharmony_ci		switch (dcmd_timeout_ocr_possible(instance)) {
458262306a36Sopenharmony_ci		case INITIATE_OCR:
458362306a36Sopenharmony_ci			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
458462306a36Sopenharmony_ci			mutex_unlock(&instance->reset_mutex);
458562306a36Sopenharmony_ci			megasas_reset_fusion(instance->host,
458662306a36Sopenharmony_ci				MFI_IO_TIMEOUT_OCR);
458762306a36Sopenharmony_ci			mutex_lock(&instance->reset_mutex);
458862306a36Sopenharmony_ci			break;
458962306a36Sopenharmony_ci		case KILL_ADAPTER:
459062306a36Sopenharmony_ci			megaraid_sas_kill_hba(instance);
459162306a36Sopenharmony_ci			break;
459262306a36Sopenharmony_ci		case IGNORE_TIMEOUT:
459362306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
459462306a36Sopenharmony_ci				__func__, __LINE__);
459562306a36Sopenharmony_ci			break;
459662306a36Sopenharmony_ci		}
459762306a36Sopenharmony_ci
459862306a36Sopenharmony_ci		break;
459962306a36Sopenharmony_ci	}
460062306a36Sopenharmony_ci
460162306a36Sopenharmony_ci	if (ret != DCMD_TIMEOUT)
460262306a36Sopenharmony_ci		megasas_return_cmd(instance, cmd);
460362306a36Sopenharmony_ci
460462306a36Sopenharmony_ci	return;
460562306a36Sopenharmony_ci}
460662306a36Sopenharmony_ci/*
460762306a36Sopenharmony_ci * megasas_get_pd_list_info -	Returns FW's pd_list structure
460862306a36Sopenharmony_ci * @instance:				Adapter soft state
460962306a36Sopenharmony_ci * @pd_list:				pd_list structure
461062306a36Sopenharmony_ci *
461162306a36Sopenharmony_ci * Issues an internal command (DCMD) to get the FW's controller PD
461262306a36Sopenharmony_ci * list structure.  This information is mainly used to find out SYSTEM
461362306a36Sopenharmony_ci * supported by the FW.
461462306a36Sopenharmony_ci */
461562306a36Sopenharmony_cistatic int
461662306a36Sopenharmony_cimegasas_get_pd_list(struct megasas_instance *instance)
461762306a36Sopenharmony_ci{
461862306a36Sopenharmony_ci	int ret = 0, pd_index = 0;
461962306a36Sopenharmony_ci	struct megasas_cmd *cmd;
462062306a36Sopenharmony_ci	struct megasas_dcmd_frame *dcmd;
462162306a36Sopenharmony_ci	struct MR_PD_LIST *ci;
462262306a36Sopenharmony_ci	struct MR_PD_ADDRESS *pd_addr;
462362306a36Sopenharmony_ci
462462306a36Sopenharmony_ci	if (instance->pd_list_not_supported) {
462562306a36Sopenharmony_ci		dev_info(&instance->pdev->dev, "MR_DCMD_PD_LIST_QUERY "
462662306a36Sopenharmony_ci		"not supported by firmware\n");
462762306a36Sopenharmony_ci		return ret;
462862306a36Sopenharmony_ci	}
462962306a36Sopenharmony_ci
463062306a36Sopenharmony_ci	ci = instance->pd_list_buf;
463162306a36Sopenharmony_ci
463262306a36Sopenharmony_ci	cmd = megasas_get_cmd(instance);
463362306a36Sopenharmony_ci
463462306a36Sopenharmony_ci	if (!cmd) {
463562306a36Sopenharmony_ci		dev_printk(KERN_DEBUG, &instance->pdev->dev, "(get_pd_list): Failed to get cmd\n");
463662306a36Sopenharmony_ci		return -ENOMEM;
463762306a36Sopenharmony_ci	}
463862306a36Sopenharmony_ci
463962306a36Sopenharmony_ci	dcmd = &cmd->frame->dcmd;
464062306a36Sopenharmony_ci
464162306a36Sopenharmony_ci	memset(ci, 0, sizeof(*ci));
464262306a36Sopenharmony_ci	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
464362306a36Sopenharmony_ci
464462306a36Sopenharmony_ci	dcmd->mbox.b[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST;
464562306a36Sopenharmony_ci	dcmd->mbox.b[1] = 0;
464662306a36Sopenharmony_ci	dcmd->cmd = MFI_CMD_DCMD;
464762306a36Sopenharmony_ci	dcmd->cmd_status = MFI_STAT_INVALID_STATUS;
464862306a36Sopenharmony_ci	dcmd->sge_count = 1;
464962306a36Sopenharmony_ci	dcmd->flags = MFI_FRAME_DIR_READ;
465062306a36Sopenharmony_ci	dcmd->timeout = 0;
465162306a36Sopenharmony_ci	dcmd->pad_0 = 0;
465262306a36Sopenharmony_ci	dcmd->data_xfer_len = cpu_to_le32(MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST));
465362306a36Sopenharmony_ci	dcmd->opcode = cpu_to_le32(MR_DCMD_PD_LIST_QUERY);
465462306a36Sopenharmony_ci
465562306a36Sopenharmony_ci	megasas_set_dma_settings(instance, dcmd, instance->pd_list_buf_h,
465662306a36Sopenharmony_ci				 (MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST)));
465762306a36Sopenharmony_ci
465862306a36Sopenharmony_ci	if ((instance->adapter_type != MFI_SERIES) &&
465962306a36Sopenharmony_ci	    !instance->mask_interrupts)
466062306a36Sopenharmony_ci		ret = megasas_issue_blocked_cmd(instance, cmd,
466162306a36Sopenharmony_ci			MFI_IO_TIMEOUT_SECS);
466262306a36Sopenharmony_ci	else
466362306a36Sopenharmony_ci		ret = megasas_issue_polled(instance, cmd);
466462306a36Sopenharmony_ci
466562306a36Sopenharmony_ci	switch (ret) {
466662306a36Sopenharmony_ci	case DCMD_FAILED:
466762306a36Sopenharmony_ci		dev_info(&instance->pdev->dev, "MR_DCMD_PD_LIST_QUERY "
466862306a36Sopenharmony_ci			"failed/not supported by firmware\n");
466962306a36Sopenharmony_ci
467062306a36Sopenharmony_ci		if (instance->adapter_type != MFI_SERIES)
467162306a36Sopenharmony_ci			megaraid_sas_kill_hba(instance);
467262306a36Sopenharmony_ci		else
467362306a36Sopenharmony_ci			instance->pd_list_not_supported = 1;
467462306a36Sopenharmony_ci		break;
467562306a36Sopenharmony_ci	case DCMD_TIMEOUT:
467662306a36Sopenharmony_ci
467762306a36Sopenharmony_ci		switch (dcmd_timeout_ocr_possible(instance)) {
467862306a36Sopenharmony_ci		case INITIATE_OCR:
467962306a36Sopenharmony_ci			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
468062306a36Sopenharmony_ci			/*
468162306a36Sopenharmony_ci			 * DCMD failed from AEN path.
468262306a36Sopenharmony_ci			 * AEN path already hold reset_mutex to avoid PCI access
468362306a36Sopenharmony_ci			 * while OCR is in progress.
468462306a36Sopenharmony_ci			 */
468562306a36Sopenharmony_ci			mutex_unlock(&instance->reset_mutex);
468662306a36Sopenharmony_ci			megasas_reset_fusion(instance->host,
468762306a36Sopenharmony_ci						MFI_IO_TIMEOUT_OCR);
468862306a36Sopenharmony_ci			mutex_lock(&instance->reset_mutex);
468962306a36Sopenharmony_ci			break;
469062306a36Sopenharmony_ci		case KILL_ADAPTER:
469162306a36Sopenharmony_ci			megaraid_sas_kill_hba(instance);
469262306a36Sopenharmony_ci			break;
469362306a36Sopenharmony_ci		case IGNORE_TIMEOUT:
469462306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d \n",
469562306a36Sopenharmony_ci				__func__, __LINE__);
469662306a36Sopenharmony_ci			break;
469762306a36Sopenharmony_ci		}
469862306a36Sopenharmony_ci
469962306a36Sopenharmony_ci		break;
470062306a36Sopenharmony_ci
470162306a36Sopenharmony_ci	case DCMD_SUCCESS:
470262306a36Sopenharmony_ci		pd_addr = ci->addr;
470362306a36Sopenharmony_ci		if (megasas_dbg_lvl & LD_PD_DEBUG)
470462306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "%s, sysPD count: 0x%x\n",
470562306a36Sopenharmony_ci				 __func__, le32_to_cpu(ci->count));
470662306a36Sopenharmony_ci
470762306a36Sopenharmony_ci		if ((le32_to_cpu(ci->count) >
470862306a36Sopenharmony_ci			(MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL)))
470962306a36Sopenharmony_ci			break;
471062306a36Sopenharmony_ci
471162306a36Sopenharmony_ci		memset(instance->local_pd_list, 0,
471262306a36Sopenharmony_ci				MEGASAS_MAX_PD * sizeof(struct megasas_pd_list));
471362306a36Sopenharmony_ci
471462306a36Sopenharmony_ci		for (pd_index = 0; pd_index < le32_to_cpu(ci->count); pd_index++) {
471562306a36Sopenharmony_ci			instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].tid	=
471662306a36Sopenharmony_ci					le16_to_cpu(pd_addr->deviceId);
471762306a36Sopenharmony_ci			instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].driveType	=
471862306a36Sopenharmony_ci					pd_addr->scsiDevType;
471962306a36Sopenharmony_ci			instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].driveState	=
472062306a36Sopenharmony_ci					MR_PD_STATE_SYSTEM;
472162306a36Sopenharmony_ci			if (megasas_dbg_lvl & LD_PD_DEBUG)
472262306a36Sopenharmony_ci				dev_info(&instance->pdev->dev,
472362306a36Sopenharmony_ci					 "PD%d: targetID: 0x%03x deviceType:0x%x\n",
472462306a36Sopenharmony_ci					 pd_index, le16_to_cpu(pd_addr->deviceId),
472562306a36Sopenharmony_ci					 pd_addr->scsiDevType);
472662306a36Sopenharmony_ci			pd_addr++;
472762306a36Sopenharmony_ci		}
472862306a36Sopenharmony_ci
472962306a36Sopenharmony_ci		memcpy(instance->pd_list, instance->local_pd_list,
473062306a36Sopenharmony_ci			sizeof(instance->pd_list));
473162306a36Sopenharmony_ci		break;
473262306a36Sopenharmony_ci
473362306a36Sopenharmony_ci	}
473462306a36Sopenharmony_ci
473562306a36Sopenharmony_ci	if (ret != DCMD_TIMEOUT)
473662306a36Sopenharmony_ci		megasas_return_cmd(instance, cmd);
473762306a36Sopenharmony_ci
473862306a36Sopenharmony_ci	return ret;
473962306a36Sopenharmony_ci}
474062306a36Sopenharmony_ci
474162306a36Sopenharmony_ci/*
474262306a36Sopenharmony_ci * megasas_get_ld_list_info -	Returns FW's ld_list structure
474362306a36Sopenharmony_ci * @instance:				Adapter soft state
474462306a36Sopenharmony_ci * @ld_list:				ld_list structure
474562306a36Sopenharmony_ci *
474662306a36Sopenharmony_ci * Issues an internal command (DCMD) to get the FW's controller PD
474762306a36Sopenharmony_ci * list structure.  This information is mainly used to find out SYSTEM
474862306a36Sopenharmony_ci * supported by the FW.
474962306a36Sopenharmony_ci */
475062306a36Sopenharmony_cistatic int
475162306a36Sopenharmony_cimegasas_get_ld_list(struct megasas_instance *instance)
475262306a36Sopenharmony_ci{
475362306a36Sopenharmony_ci	int ret = 0, ld_index = 0, ids = 0;
475462306a36Sopenharmony_ci	struct megasas_cmd *cmd;
475562306a36Sopenharmony_ci	struct megasas_dcmd_frame *dcmd;
475662306a36Sopenharmony_ci	struct MR_LD_LIST *ci;
475762306a36Sopenharmony_ci	dma_addr_t ci_h = 0;
475862306a36Sopenharmony_ci	u32 ld_count;
475962306a36Sopenharmony_ci
476062306a36Sopenharmony_ci	ci = instance->ld_list_buf;
476162306a36Sopenharmony_ci	ci_h = instance->ld_list_buf_h;
476262306a36Sopenharmony_ci
476362306a36Sopenharmony_ci	cmd = megasas_get_cmd(instance);
476462306a36Sopenharmony_ci
476562306a36Sopenharmony_ci	if (!cmd) {
476662306a36Sopenharmony_ci		dev_printk(KERN_DEBUG, &instance->pdev->dev, "megasas_get_ld_list: Failed to get cmd\n");
476762306a36Sopenharmony_ci		return -ENOMEM;
476862306a36Sopenharmony_ci	}
476962306a36Sopenharmony_ci
477062306a36Sopenharmony_ci	dcmd = &cmd->frame->dcmd;
477162306a36Sopenharmony_ci
477262306a36Sopenharmony_ci	memset(ci, 0, sizeof(*ci));
477362306a36Sopenharmony_ci	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
477462306a36Sopenharmony_ci
477562306a36Sopenharmony_ci	if (instance->supportmax256vd)
477662306a36Sopenharmony_ci		dcmd->mbox.b[0] = 1;
477762306a36Sopenharmony_ci	dcmd->cmd = MFI_CMD_DCMD;
477862306a36Sopenharmony_ci	dcmd->cmd_status = MFI_STAT_INVALID_STATUS;
477962306a36Sopenharmony_ci	dcmd->sge_count = 1;
478062306a36Sopenharmony_ci	dcmd->flags = MFI_FRAME_DIR_READ;
478162306a36Sopenharmony_ci	dcmd->timeout = 0;
478262306a36Sopenharmony_ci	dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_LD_LIST));
478362306a36Sopenharmony_ci	dcmd->opcode = cpu_to_le32(MR_DCMD_LD_GET_LIST);
478462306a36Sopenharmony_ci	dcmd->pad_0  = 0;
478562306a36Sopenharmony_ci
478662306a36Sopenharmony_ci	megasas_set_dma_settings(instance, dcmd, ci_h,
478762306a36Sopenharmony_ci				 sizeof(struct MR_LD_LIST));
478862306a36Sopenharmony_ci
478962306a36Sopenharmony_ci	if ((instance->adapter_type != MFI_SERIES) &&
479062306a36Sopenharmony_ci	    !instance->mask_interrupts)
479162306a36Sopenharmony_ci		ret = megasas_issue_blocked_cmd(instance, cmd,
479262306a36Sopenharmony_ci			MFI_IO_TIMEOUT_SECS);
479362306a36Sopenharmony_ci	else
479462306a36Sopenharmony_ci		ret = megasas_issue_polled(instance, cmd);
479562306a36Sopenharmony_ci
479662306a36Sopenharmony_ci	ld_count = le32_to_cpu(ci->ldCount);
479762306a36Sopenharmony_ci
479862306a36Sopenharmony_ci	switch (ret) {
479962306a36Sopenharmony_ci	case DCMD_FAILED:
480062306a36Sopenharmony_ci		megaraid_sas_kill_hba(instance);
480162306a36Sopenharmony_ci		break;
480262306a36Sopenharmony_ci	case DCMD_TIMEOUT:
480362306a36Sopenharmony_ci
480462306a36Sopenharmony_ci		switch (dcmd_timeout_ocr_possible(instance)) {
480562306a36Sopenharmony_ci		case INITIATE_OCR:
480662306a36Sopenharmony_ci			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
480762306a36Sopenharmony_ci			/*
480862306a36Sopenharmony_ci			 * DCMD failed from AEN path.
480962306a36Sopenharmony_ci			 * AEN path already hold reset_mutex to avoid PCI access
481062306a36Sopenharmony_ci			 * while OCR is in progress.
481162306a36Sopenharmony_ci			 */
481262306a36Sopenharmony_ci			mutex_unlock(&instance->reset_mutex);
481362306a36Sopenharmony_ci			megasas_reset_fusion(instance->host,
481462306a36Sopenharmony_ci						MFI_IO_TIMEOUT_OCR);
481562306a36Sopenharmony_ci			mutex_lock(&instance->reset_mutex);
481662306a36Sopenharmony_ci			break;
481762306a36Sopenharmony_ci		case KILL_ADAPTER:
481862306a36Sopenharmony_ci			megaraid_sas_kill_hba(instance);
481962306a36Sopenharmony_ci			break;
482062306a36Sopenharmony_ci		case IGNORE_TIMEOUT:
482162306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
482262306a36Sopenharmony_ci				__func__, __LINE__);
482362306a36Sopenharmony_ci			break;
482462306a36Sopenharmony_ci		}
482562306a36Sopenharmony_ci
482662306a36Sopenharmony_ci		break;
482762306a36Sopenharmony_ci
482862306a36Sopenharmony_ci	case DCMD_SUCCESS:
482962306a36Sopenharmony_ci		if (megasas_dbg_lvl & LD_PD_DEBUG)
483062306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "%s, LD count: 0x%x\n",
483162306a36Sopenharmony_ci				 __func__, ld_count);
483262306a36Sopenharmony_ci
483362306a36Sopenharmony_ci		if (ld_count > instance->fw_supported_vd_count)
483462306a36Sopenharmony_ci			break;
483562306a36Sopenharmony_ci
483662306a36Sopenharmony_ci		memset(instance->ld_ids, 0xff, MAX_LOGICAL_DRIVES_EXT);
483762306a36Sopenharmony_ci
483862306a36Sopenharmony_ci		for (ld_index = 0; ld_index < ld_count; ld_index++) {
483962306a36Sopenharmony_ci			if (ci->ldList[ld_index].state != 0) {
484062306a36Sopenharmony_ci				ids = ci->ldList[ld_index].ref.targetId;
484162306a36Sopenharmony_ci				instance->ld_ids[ids] = ci->ldList[ld_index].ref.targetId;
484262306a36Sopenharmony_ci				if (megasas_dbg_lvl & LD_PD_DEBUG)
484362306a36Sopenharmony_ci					dev_info(&instance->pdev->dev,
484462306a36Sopenharmony_ci						 "LD%d: targetID: 0x%03x\n",
484562306a36Sopenharmony_ci						 ld_index, ids);
484662306a36Sopenharmony_ci			}
484762306a36Sopenharmony_ci		}
484862306a36Sopenharmony_ci
484962306a36Sopenharmony_ci		break;
485062306a36Sopenharmony_ci	}
485162306a36Sopenharmony_ci
485262306a36Sopenharmony_ci	if (ret != DCMD_TIMEOUT)
485362306a36Sopenharmony_ci		megasas_return_cmd(instance, cmd);
485462306a36Sopenharmony_ci
485562306a36Sopenharmony_ci	return ret;
485662306a36Sopenharmony_ci}
485762306a36Sopenharmony_ci
485862306a36Sopenharmony_ci/**
485962306a36Sopenharmony_ci * megasas_ld_list_query -	Returns FW's ld_list structure
486062306a36Sopenharmony_ci * @instance:				Adapter soft state
486162306a36Sopenharmony_ci * @query_type:				ld_list structure type
486262306a36Sopenharmony_ci *
486362306a36Sopenharmony_ci * Issues an internal command (DCMD) to get the FW's controller PD
486462306a36Sopenharmony_ci * list structure.  This information is mainly used to find out SYSTEM
486562306a36Sopenharmony_ci * supported by the FW.
486662306a36Sopenharmony_ci */
486762306a36Sopenharmony_cistatic int
486862306a36Sopenharmony_cimegasas_ld_list_query(struct megasas_instance *instance, u8 query_type)
486962306a36Sopenharmony_ci{
487062306a36Sopenharmony_ci	int ret = 0, ld_index = 0, ids = 0;
487162306a36Sopenharmony_ci	struct megasas_cmd *cmd;
487262306a36Sopenharmony_ci	struct megasas_dcmd_frame *dcmd;
487362306a36Sopenharmony_ci	struct MR_LD_TARGETID_LIST *ci;
487462306a36Sopenharmony_ci	dma_addr_t ci_h = 0;
487562306a36Sopenharmony_ci	u32 tgtid_count;
487662306a36Sopenharmony_ci
487762306a36Sopenharmony_ci	ci = instance->ld_targetid_list_buf;
487862306a36Sopenharmony_ci	ci_h = instance->ld_targetid_list_buf_h;
487962306a36Sopenharmony_ci
488062306a36Sopenharmony_ci	cmd = megasas_get_cmd(instance);
488162306a36Sopenharmony_ci
488262306a36Sopenharmony_ci	if (!cmd) {
488362306a36Sopenharmony_ci		dev_warn(&instance->pdev->dev,
488462306a36Sopenharmony_ci		         "megasas_ld_list_query: Failed to get cmd\n");
488562306a36Sopenharmony_ci		return -ENOMEM;
488662306a36Sopenharmony_ci	}
488762306a36Sopenharmony_ci
488862306a36Sopenharmony_ci	dcmd = &cmd->frame->dcmd;
488962306a36Sopenharmony_ci
489062306a36Sopenharmony_ci	memset(ci, 0, sizeof(*ci));
489162306a36Sopenharmony_ci	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
489262306a36Sopenharmony_ci
489362306a36Sopenharmony_ci	dcmd->mbox.b[0] = query_type;
489462306a36Sopenharmony_ci	if (instance->supportmax256vd)
489562306a36Sopenharmony_ci		dcmd->mbox.b[2] = 1;
489662306a36Sopenharmony_ci
489762306a36Sopenharmony_ci	dcmd->cmd = MFI_CMD_DCMD;
489862306a36Sopenharmony_ci	dcmd->cmd_status = MFI_STAT_INVALID_STATUS;
489962306a36Sopenharmony_ci	dcmd->sge_count = 1;
490062306a36Sopenharmony_ci	dcmd->flags = MFI_FRAME_DIR_READ;
490162306a36Sopenharmony_ci	dcmd->timeout = 0;
490262306a36Sopenharmony_ci	dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_LD_TARGETID_LIST));
490362306a36Sopenharmony_ci	dcmd->opcode = cpu_to_le32(MR_DCMD_LD_LIST_QUERY);
490462306a36Sopenharmony_ci	dcmd->pad_0  = 0;
490562306a36Sopenharmony_ci
490662306a36Sopenharmony_ci	megasas_set_dma_settings(instance, dcmd, ci_h,
490762306a36Sopenharmony_ci				 sizeof(struct MR_LD_TARGETID_LIST));
490862306a36Sopenharmony_ci
490962306a36Sopenharmony_ci	if ((instance->adapter_type != MFI_SERIES) &&
491062306a36Sopenharmony_ci	    !instance->mask_interrupts)
491162306a36Sopenharmony_ci		ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
491262306a36Sopenharmony_ci	else
491362306a36Sopenharmony_ci		ret = megasas_issue_polled(instance, cmd);
491462306a36Sopenharmony_ci
491562306a36Sopenharmony_ci	switch (ret) {
491662306a36Sopenharmony_ci	case DCMD_FAILED:
491762306a36Sopenharmony_ci		dev_info(&instance->pdev->dev,
491862306a36Sopenharmony_ci			"DCMD not supported by firmware - %s %d\n",
491962306a36Sopenharmony_ci				__func__, __LINE__);
492062306a36Sopenharmony_ci		ret = megasas_get_ld_list(instance);
492162306a36Sopenharmony_ci		break;
492262306a36Sopenharmony_ci	case DCMD_TIMEOUT:
492362306a36Sopenharmony_ci		switch (dcmd_timeout_ocr_possible(instance)) {
492462306a36Sopenharmony_ci		case INITIATE_OCR:
492562306a36Sopenharmony_ci			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
492662306a36Sopenharmony_ci			/*
492762306a36Sopenharmony_ci			 * DCMD failed from AEN path.
492862306a36Sopenharmony_ci			 * AEN path already hold reset_mutex to avoid PCI access
492962306a36Sopenharmony_ci			 * while OCR is in progress.
493062306a36Sopenharmony_ci			 */
493162306a36Sopenharmony_ci			mutex_unlock(&instance->reset_mutex);
493262306a36Sopenharmony_ci			megasas_reset_fusion(instance->host,
493362306a36Sopenharmony_ci						MFI_IO_TIMEOUT_OCR);
493462306a36Sopenharmony_ci			mutex_lock(&instance->reset_mutex);
493562306a36Sopenharmony_ci			break;
493662306a36Sopenharmony_ci		case KILL_ADAPTER:
493762306a36Sopenharmony_ci			megaraid_sas_kill_hba(instance);
493862306a36Sopenharmony_ci			break;
493962306a36Sopenharmony_ci		case IGNORE_TIMEOUT:
494062306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
494162306a36Sopenharmony_ci				__func__, __LINE__);
494262306a36Sopenharmony_ci			break;
494362306a36Sopenharmony_ci		}
494462306a36Sopenharmony_ci
494562306a36Sopenharmony_ci		break;
494662306a36Sopenharmony_ci	case DCMD_SUCCESS:
494762306a36Sopenharmony_ci		tgtid_count = le32_to_cpu(ci->count);
494862306a36Sopenharmony_ci
494962306a36Sopenharmony_ci		if (megasas_dbg_lvl & LD_PD_DEBUG)
495062306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "%s, LD count: 0x%x\n",
495162306a36Sopenharmony_ci				 __func__, tgtid_count);
495262306a36Sopenharmony_ci
495362306a36Sopenharmony_ci		if ((tgtid_count > (instance->fw_supported_vd_count)))
495462306a36Sopenharmony_ci			break;
495562306a36Sopenharmony_ci
495662306a36Sopenharmony_ci		memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
495762306a36Sopenharmony_ci		for (ld_index = 0; ld_index < tgtid_count; ld_index++) {
495862306a36Sopenharmony_ci			ids = ci->targetId[ld_index];
495962306a36Sopenharmony_ci			instance->ld_ids[ids] = ci->targetId[ld_index];
496062306a36Sopenharmony_ci			if (megasas_dbg_lvl & LD_PD_DEBUG)
496162306a36Sopenharmony_ci				dev_info(&instance->pdev->dev, "LD%d: targetID: 0x%03x\n",
496262306a36Sopenharmony_ci					 ld_index, ci->targetId[ld_index]);
496362306a36Sopenharmony_ci		}
496462306a36Sopenharmony_ci
496562306a36Sopenharmony_ci		break;
496662306a36Sopenharmony_ci	}
496762306a36Sopenharmony_ci
496862306a36Sopenharmony_ci	if (ret != DCMD_TIMEOUT)
496962306a36Sopenharmony_ci		megasas_return_cmd(instance, cmd);
497062306a36Sopenharmony_ci
497162306a36Sopenharmony_ci	return ret;
497262306a36Sopenharmony_ci}
497362306a36Sopenharmony_ci
497462306a36Sopenharmony_ci/**
497562306a36Sopenharmony_ci * megasas_host_device_list_query
497662306a36Sopenharmony_ci * dcmd.opcode            - MR_DCMD_CTRL_DEVICE_LIST_GET
497762306a36Sopenharmony_ci * dcmd.mbox              - reserved
497862306a36Sopenharmony_ci * dcmd.sge IN            - ptr to return MR_HOST_DEVICE_LIST structure
497962306a36Sopenharmony_ci * Desc:    This DCMD will return the combined device list
498062306a36Sopenharmony_ci * Status:  MFI_STAT_OK - List returned successfully
498162306a36Sopenharmony_ci *          MFI_STAT_INVALID_CMD - Firmware support for the feature has been
498262306a36Sopenharmony_ci *                                 disabled
498362306a36Sopenharmony_ci * @instance:			Adapter soft state
498462306a36Sopenharmony_ci * @is_probe:			Driver probe check
498562306a36Sopenharmony_ci * Return:			0 if DCMD succeeded
498662306a36Sopenharmony_ci *				 non-zero if failed
498762306a36Sopenharmony_ci */
498862306a36Sopenharmony_cistatic int
498962306a36Sopenharmony_cimegasas_host_device_list_query(struct megasas_instance *instance,
499062306a36Sopenharmony_ci			       bool is_probe)
499162306a36Sopenharmony_ci{
499262306a36Sopenharmony_ci	int ret, i, target_id;
499362306a36Sopenharmony_ci	struct megasas_cmd *cmd;
499462306a36Sopenharmony_ci	struct megasas_dcmd_frame *dcmd;
499562306a36Sopenharmony_ci	struct MR_HOST_DEVICE_LIST *ci;
499662306a36Sopenharmony_ci	u32 count;
499762306a36Sopenharmony_ci	dma_addr_t ci_h;
499862306a36Sopenharmony_ci
499962306a36Sopenharmony_ci	ci = instance->host_device_list_buf;
500062306a36Sopenharmony_ci	ci_h = instance->host_device_list_buf_h;
500162306a36Sopenharmony_ci
500262306a36Sopenharmony_ci	cmd = megasas_get_cmd(instance);
500362306a36Sopenharmony_ci
500462306a36Sopenharmony_ci	if (!cmd) {
500562306a36Sopenharmony_ci		dev_warn(&instance->pdev->dev,
500662306a36Sopenharmony_ci			 "%s: failed to get cmd\n",
500762306a36Sopenharmony_ci			 __func__);
500862306a36Sopenharmony_ci		return -ENOMEM;
500962306a36Sopenharmony_ci	}
501062306a36Sopenharmony_ci
501162306a36Sopenharmony_ci	dcmd = &cmd->frame->dcmd;
501262306a36Sopenharmony_ci
501362306a36Sopenharmony_ci	memset(ci, 0, sizeof(*ci));
501462306a36Sopenharmony_ci	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
501562306a36Sopenharmony_ci
501662306a36Sopenharmony_ci	dcmd->mbox.b[0] = is_probe ? 0 : 1;
501762306a36Sopenharmony_ci	dcmd->cmd = MFI_CMD_DCMD;
501862306a36Sopenharmony_ci	dcmd->cmd_status = MFI_STAT_INVALID_STATUS;
501962306a36Sopenharmony_ci	dcmd->sge_count = 1;
502062306a36Sopenharmony_ci	dcmd->flags = MFI_FRAME_DIR_READ;
502162306a36Sopenharmony_ci	dcmd->timeout = 0;
502262306a36Sopenharmony_ci	dcmd->pad_0 = 0;
502362306a36Sopenharmony_ci	dcmd->data_xfer_len = cpu_to_le32(HOST_DEVICE_LIST_SZ);
502462306a36Sopenharmony_ci	dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_DEVICE_LIST_GET);
502562306a36Sopenharmony_ci
502662306a36Sopenharmony_ci	megasas_set_dma_settings(instance, dcmd, ci_h, HOST_DEVICE_LIST_SZ);
502762306a36Sopenharmony_ci
502862306a36Sopenharmony_ci	if (!instance->mask_interrupts) {
502962306a36Sopenharmony_ci		ret = megasas_issue_blocked_cmd(instance, cmd,
503062306a36Sopenharmony_ci						MFI_IO_TIMEOUT_SECS);
503162306a36Sopenharmony_ci	} else {
503262306a36Sopenharmony_ci		ret = megasas_issue_polled(instance, cmd);
503362306a36Sopenharmony_ci		cmd->flags |= DRV_DCMD_SKIP_REFIRE;
503462306a36Sopenharmony_ci	}
503562306a36Sopenharmony_ci
503662306a36Sopenharmony_ci	switch (ret) {
503762306a36Sopenharmony_ci	case DCMD_SUCCESS:
503862306a36Sopenharmony_ci		/* Fill the internal pd_list and ld_ids array based on
503962306a36Sopenharmony_ci		 * targetIds returned by FW
504062306a36Sopenharmony_ci		 */
504162306a36Sopenharmony_ci		count = le32_to_cpu(ci->count);
504262306a36Sopenharmony_ci
504362306a36Sopenharmony_ci		if (count > (MEGASAS_MAX_PD + MAX_LOGICAL_DRIVES_EXT))
504462306a36Sopenharmony_ci			break;
504562306a36Sopenharmony_ci
504662306a36Sopenharmony_ci		if (megasas_dbg_lvl & LD_PD_DEBUG)
504762306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "%s, Device count: 0x%x\n",
504862306a36Sopenharmony_ci				 __func__, count);
504962306a36Sopenharmony_ci
505062306a36Sopenharmony_ci		memset(instance->local_pd_list, 0,
505162306a36Sopenharmony_ci		       MEGASAS_MAX_PD * sizeof(struct megasas_pd_list));
505262306a36Sopenharmony_ci		memset(instance->ld_ids, 0xff, MAX_LOGICAL_DRIVES_EXT);
505362306a36Sopenharmony_ci		for (i = 0; i < count; i++) {
505462306a36Sopenharmony_ci			target_id = le16_to_cpu(ci->host_device_list[i].target_id);
505562306a36Sopenharmony_ci			if (ci->host_device_list[i].flags.u.bits.is_sys_pd) {
505662306a36Sopenharmony_ci				instance->local_pd_list[target_id].tid = target_id;
505762306a36Sopenharmony_ci				instance->local_pd_list[target_id].driveType =
505862306a36Sopenharmony_ci						ci->host_device_list[i].scsi_type;
505962306a36Sopenharmony_ci				instance->local_pd_list[target_id].driveState =
506062306a36Sopenharmony_ci						MR_PD_STATE_SYSTEM;
506162306a36Sopenharmony_ci				if (megasas_dbg_lvl & LD_PD_DEBUG)
506262306a36Sopenharmony_ci					dev_info(&instance->pdev->dev,
506362306a36Sopenharmony_ci						 "Device %d: PD targetID: 0x%03x deviceType:0x%x\n",
506462306a36Sopenharmony_ci						 i, target_id, ci->host_device_list[i].scsi_type);
506562306a36Sopenharmony_ci			} else {
506662306a36Sopenharmony_ci				instance->ld_ids[target_id] = target_id;
506762306a36Sopenharmony_ci				if (megasas_dbg_lvl & LD_PD_DEBUG)
506862306a36Sopenharmony_ci					dev_info(&instance->pdev->dev,
506962306a36Sopenharmony_ci						 "Device %d: LD targetID: 0x%03x\n",
507062306a36Sopenharmony_ci						 i, target_id);
507162306a36Sopenharmony_ci			}
507262306a36Sopenharmony_ci		}
507362306a36Sopenharmony_ci
507462306a36Sopenharmony_ci		memcpy(instance->pd_list, instance->local_pd_list,
507562306a36Sopenharmony_ci		       sizeof(instance->pd_list));
507662306a36Sopenharmony_ci		break;
507762306a36Sopenharmony_ci
507862306a36Sopenharmony_ci	case DCMD_TIMEOUT:
507962306a36Sopenharmony_ci		switch (dcmd_timeout_ocr_possible(instance)) {
508062306a36Sopenharmony_ci		case INITIATE_OCR:
508162306a36Sopenharmony_ci			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
508262306a36Sopenharmony_ci			mutex_unlock(&instance->reset_mutex);
508362306a36Sopenharmony_ci			megasas_reset_fusion(instance->host,
508462306a36Sopenharmony_ci				MFI_IO_TIMEOUT_OCR);
508562306a36Sopenharmony_ci			mutex_lock(&instance->reset_mutex);
508662306a36Sopenharmony_ci			break;
508762306a36Sopenharmony_ci		case KILL_ADAPTER:
508862306a36Sopenharmony_ci			megaraid_sas_kill_hba(instance);
508962306a36Sopenharmony_ci			break;
509062306a36Sopenharmony_ci		case IGNORE_TIMEOUT:
509162306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
509262306a36Sopenharmony_ci				 __func__, __LINE__);
509362306a36Sopenharmony_ci			break;
509462306a36Sopenharmony_ci		}
509562306a36Sopenharmony_ci		break;
509662306a36Sopenharmony_ci	case DCMD_FAILED:
509762306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
509862306a36Sopenharmony_ci			"%s: MR_DCMD_CTRL_DEVICE_LIST_GET failed\n",
509962306a36Sopenharmony_ci			__func__);
510062306a36Sopenharmony_ci		break;
510162306a36Sopenharmony_ci	}
510262306a36Sopenharmony_ci
510362306a36Sopenharmony_ci	if (ret != DCMD_TIMEOUT)
510462306a36Sopenharmony_ci		megasas_return_cmd(instance, cmd);
510562306a36Sopenharmony_ci
510662306a36Sopenharmony_ci	return ret;
510762306a36Sopenharmony_ci}
510862306a36Sopenharmony_ci
510962306a36Sopenharmony_ci/*
511062306a36Sopenharmony_ci * megasas_update_ext_vd_details : Update details w.r.t Extended VD
511162306a36Sopenharmony_ci * instance			 : Controller's instance
511262306a36Sopenharmony_ci*/
511362306a36Sopenharmony_cistatic void megasas_update_ext_vd_details(struct megasas_instance *instance)
511462306a36Sopenharmony_ci{
511562306a36Sopenharmony_ci	struct fusion_context *fusion;
511662306a36Sopenharmony_ci	u32 ventura_map_sz = 0;
511762306a36Sopenharmony_ci
511862306a36Sopenharmony_ci	fusion = instance->ctrl_context;
511962306a36Sopenharmony_ci	/* For MFI based controllers return dummy success */
512062306a36Sopenharmony_ci	if (!fusion)
512162306a36Sopenharmony_ci		return;
512262306a36Sopenharmony_ci
512362306a36Sopenharmony_ci	instance->supportmax256vd =
512462306a36Sopenharmony_ci		instance->ctrl_info_buf->adapterOperations3.supportMaxExtLDs;
512562306a36Sopenharmony_ci	/* Below is additional check to address future FW enhancement */
512662306a36Sopenharmony_ci	if (instance->ctrl_info_buf->max_lds > 64)
512762306a36Sopenharmony_ci		instance->supportmax256vd = 1;
512862306a36Sopenharmony_ci
512962306a36Sopenharmony_ci	instance->drv_supported_vd_count = MEGASAS_MAX_LD_CHANNELS
513062306a36Sopenharmony_ci					* MEGASAS_MAX_DEV_PER_CHANNEL;
513162306a36Sopenharmony_ci	instance->drv_supported_pd_count = MEGASAS_MAX_PD_CHANNELS
513262306a36Sopenharmony_ci					* MEGASAS_MAX_DEV_PER_CHANNEL;
513362306a36Sopenharmony_ci	if (instance->supportmax256vd) {
513462306a36Sopenharmony_ci		instance->fw_supported_vd_count = MAX_LOGICAL_DRIVES_EXT;
513562306a36Sopenharmony_ci		instance->fw_supported_pd_count = MAX_PHYSICAL_DEVICES;
513662306a36Sopenharmony_ci	} else {
513762306a36Sopenharmony_ci		instance->fw_supported_vd_count = MAX_LOGICAL_DRIVES;
513862306a36Sopenharmony_ci		instance->fw_supported_pd_count = MAX_PHYSICAL_DEVICES;
513962306a36Sopenharmony_ci	}
514062306a36Sopenharmony_ci
514162306a36Sopenharmony_ci	dev_info(&instance->pdev->dev,
514262306a36Sopenharmony_ci		"FW provided supportMaxExtLDs: %d\tmax_lds: %d\n",
514362306a36Sopenharmony_ci		instance->ctrl_info_buf->adapterOperations3.supportMaxExtLDs ? 1 : 0,
514462306a36Sopenharmony_ci		instance->ctrl_info_buf->max_lds);
514562306a36Sopenharmony_ci
514662306a36Sopenharmony_ci	if (instance->max_raid_mapsize) {
514762306a36Sopenharmony_ci		ventura_map_sz = instance->max_raid_mapsize *
514862306a36Sopenharmony_ci						MR_MIN_MAP_SIZE; /* 64k */
514962306a36Sopenharmony_ci		fusion->current_map_sz = ventura_map_sz;
515062306a36Sopenharmony_ci		fusion->max_map_sz = ventura_map_sz;
515162306a36Sopenharmony_ci	} else {
515262306a36Sopenharmony_ci		fusion->old_map_sz =
515362306a36Sopenharmony_ci			struct_size_t(struct MR_FW_RAID_MAP, ldSpanMap,
515462306a36Sopenharmony_ci				      instance->fw_supported_vd_count);
515562306a36Sopenharmony_ci		fusion->new_map_sz =  sizeof(struct MR_FW_RAID_MAP_EXT);
515662306a36Sopenharmony_ci
515762306a36Sopenharmony_ci		fusion->max_map_sz =
515862306a36Sopenharmony_ci			max(fusion->old_map_sz, fusion->new_map_sz);
515962306a36Sopenharmony_ci
516062306a36Sopenharmony_ci		if (instance->supportmax256vd)
516162306a36Sopenharmony_ci			fusion->current_map_sz = fusion->new_map_sz;
516262306a36Sopenharmony_ci		else
516362306a36Sopenharmony_ci			fusion->current_map_sz = fusion->old_map_sz;
516462306a36Sopenharmony_ci	}
516562306a36Sopenharmony_ci	/* irrespective of FW raid maps, driver raid map is constant */
516662306a36Sopenharmony_ci	fusion->drv_map_sz = sizeof(struct MR_DRV_RAID_MAP_ALL);
516762306a36Sopenharmony_ci}
516862306a36Sopenharmony_ci
516962306a36Sopenharmony_ci/*
517062306a36Sopenharmony_ci * dcmd.opcode                - MR_DCMD_CTRL_SNAPDUMP_GET_PROPERTIES
517162306a36Sopenharmony_ci * dcmd.hdr.length            - number of bytes to read
517262306a36Sopenharmony_ci * dcmd.sge                   - Ptr to MR_SNAPDUMP_PROPERTIES
517362306a36Sopenharmony_ci * Desc:			 Fill in snapdump properties
517462306a36Sopenharmony_ci * Status:			 MFI_STAT_OK- Command successful
517562306a36Sopenharmony_ci */
517662306a36Sopenharmony_civoid megasas_get_snapdump_properties(struct megasas_instance *instance)
517762306a36Sopenharmony_ci{
517862306a36Sopenharmony_ci	int ret = 0;
517962306a36Sopenharmony_ci	struct megasas_cmd *cmd;
518062306a36Sopenharmony_ci	struct megasas_dcmd_frame *dcmd;
518162306a36Sopenharmony_ci	struct MR_SNAPDUMP_PROPERTIES *ci;
518262306a36Sopenharmony_ci	dma_addr_t ci_h = 0;
518362306a36Sopenharmony_ci
518462306a36Sopenharmony_ci	ci = instance->snapdump_prop;
518562306a36Sopenharmony_ci	ci_h = instance->snapdump_prop_h;
518662306a36Sopenharmony_ci
518762306a36Sopenharmony_ci	if (!ci)
518862306a36Sopenharmony_ci		return;
518962306a36Sopenharmony_ci
519062306a36Sopenharmony_ci	cmd = megasas_get_cmd(instance);
519162306a36Sopenharmony_ci
519262306a36Sopenharmony_ci	if (!cmd) {
519362306a36Sopenharmony_ci		dev_dbg(&instance->pdev->dev, "Failed to get a free cmd\n");
519462306a36Sopenharmony_ci		return;
519562306a36Sopenharmony_ci	}
519662306a36Sopenharmony_ci
519762306a36Sopenharmony_ci	dcmd = &cmd->frame->dcmd;
519862306a36Sopenharmony_ci
519962306a36Sopenharmony_ci	memset(ci, 0, sizeof(*ci));
520062306a36Sopenharmony_ci	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
520162306a36Sopenharmony_ci
520262306a36Sopenharmony_ci	dcmd->cmd = MFI_CMD_DCMD;
520362306a36Sopenharmony_ci	dcmd->cmd_status = MFI_STAT_INVALID_STATUS;
520462306a36Sopenharmony_ci	dcmd->sge_count = 1;
520562306a36Sopenharmony_ci	dcmd->flags = MFI_FRAME_DIR_READ;
520662306a36Sopenharmony_ci	dcmd->timeout = 0;
520762306a36Sopenharmony_ci	dcmd->pad_0 = 0;
520862306a36Sopenharmony_ci	dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_SNAPDUMP_PROPERTIES));
520962306a36Sopenharmony_ci	dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_SNAPDUMP_GET_PROPERTIES);
521062306a36Sopenharmony_ci
521162306a36Sopenharmony_ci	megasas_set_dma_settings(instance, dcmd, ci_h,
521262306a36Sopenharmony_ci				 sizeof(struct MR_SNAPDUMP_PROPERTIES));
521362306a36Sopenharmony_ci
521462306a36Sopenharmony_ci	if (!instance->mask_interrupts) {
521562306a36Sopenharmony_ci		ret = megasas_issue_blocked_cmd(instance, cmd,
521662306a36Sopenharmony_ci						MFI_IO_TIMEOUT_SECS);
521762306a36Sopenharmony_ci	} else {
521862306a36Sopenharmony_ci		ret = megasas_issue_polled(instance, cmd);
521962306a36Sopenharmony_ci		cmd->flags |= DRV_DCMD_SKIP_REFIRE;
522062306a36Sopenharmony_ci	}
522162306a36Sopenharmony_ci
522262306a36Sopenharmony_ci	switch (ret) {
522362306a36Sopenharmony_ci	case DCMD_SUCCESS:
522462306a36Sopenharmony_ci		instance->snapdump_wait_time =
522562306a36Sopenharmony_ci			min_t(u8, ci->trigger_min_num_sec_before_ocr,
522662306a36Sopenharmony_ci				MEGASAS_MAX_SNAP_DUMP_WAIT_TIME);
522762306a36Sopenharmony_ci		break;
522862306a36Sopenharmony_ci
522962306a36Sopenharmony_ci	case DCMD_TIMEOUT:
523062306a36Sopenharmony_ci		switch (dcmd_timeout_ocr_possible(instance)) {
523162306a36Sopenharmony_ci		case INITIATE_OCR:
523262306a36Sopenharmony_ci			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
523362306a36Sopenharmony_ci			mutex_unlock(&instance->reset_mutex);
523462306a36Sopenharmony_ci			megasas_reset_fusion(instance->host,
523562306a36Sopenharmony_ci				MFI_IO_TIMEOUT_OCR);
523662306a36Sopenharmony_ci			mutex_lock(&instance->reset_mutex);
523762306a36Sopenharmony_ci			break;
523862306a36Sopenharmony_ci		case KILL_ADAPTER:
523962306a36Sopenharmony_ci			megaraid_sas_kill_hba(instance);
524062306a36Sopenharmony_ci			break;
524162306a36Sopenharmony_ci		case IGNORE_TIMEOUT:
524262306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
524362306a36Sopenharmony_ci				__func__, __LINE__);
524462306a36Sopenharmony_ci			break;
524562306a36Sopenharmony_ci		}
524662306a36Sopenharmony_ci	}
524762306a36Sopenharmony_ci
524862306a36Sopenharmony_ci	if (ret != DCMD_TIMEOUT)
524962306a36Sopenharmony_ci		megasas_return_cmd(instance, cmd);
525062306a36Sopenharmony_ci}
525162306a36Sopenharmony_ci
525262306a36Sopenharmony_ci/**
525362306a36Sopenharmony_ci * megasas_get_ctrl_info -	Returns FW's controller structure
525462306a36Sopenharmony_ci * @instance:				Adapter soft state
525562306a36Sopenharmony_ci *
525662306a36Sopenharmony_ci * Issues an internal command (DCMD) to get the FW's controller structure.
525762306a36Sopenharmony_ci * This information is mainly used to find out the maximum IO transfer per
525862306a36Sopenharmony_ci * command supported by the FW.
525962306a36Sopenharmony_ci */
526062306a36Sopenharmony_ciint
526162306a36Sopenharmony_cimegasas_get_ctrl_info(struct megasas_instance *instance)
526262306a36Sopenharmony_ci{
526362306a36Sopenharmony_ci	int ret = 0;
526462306a36Sopenharmony_ci	struct megasas_cmd *cmd;
526562306a36Sopenharmony_ci	struct megasas_dcmd_frame *dcmd;
526662306a36Sopenharmony_ci	struct megasas_ctrl_info *ci;
526762306a36Sopenharmony_ci	dma_addr_t ci_h = 0;
526862306a36Sopenharmony_ci
526962306a36Sopenharmony_ci	ci = instance->ctrl_info_buf;
527062306a36Sopenharmony_ci	ci_h = instance->ctrl_info_buf_h;
527162306a36Sopenharmony_ci
527262306a36Sopenharmony_ci	cmd = megasas_get_cmd(instance);
527362306a36Sopenharmony_ci
527462306a36Sopenharmony_ci	if (!cmd) {
527562306a36Sopenharmony_ci		dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to get a free cmd\n");
527662306a36Sopenharmony_ci		return -ENOMEM;
527762306a36Sopenharmony_ci	}
527862306a36Sopenharmony_ci
527962306a36Sopenharmony_ci	dcmd = &cmd->frame->dcmd;
528062306a36Sopenharmony_ci
528162306a36Sopenharmony_ci	memset(ci, 0, sizeof(*ci));
528262306a36Sopenharmony_ci	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
528362306a36Sopenharmony_ci
528462306a36Sopenharmony_ci	dcmd->cmd = MFI_CMD_DCMD;
528562306a36Sopenharmony_ci	dcmd->cmd_status = MFI_STAT_INVALID_STATUS;
528662306a36Sopenharmony_ci	dcmd->sge_count = 1;
528762306a36Sopenharmony_ci	dcmd->flags = MFI_FRAME_DIR_READ;
528862306a36Sopenharmony_ci	dcmd->timeout = 0;
528962306a36Sopenharmony_ci	dcmd->pad_0 = 0;
529062306a36Sopenharmony_ci	dcmd->data_xfer_len = cpu_to_le32(sizeof(struct megasas_ctrl_info));
529162306a36Sopenharmony_ci	dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_GET_INFO);
529262306a36Sopenharmony_ci	dcmd->mbox.b[0] = 1;
529362306a36Sopenharmony_ci
529462306a36Sopenharmony_ci	megasas_set_dma_settings(instance, dcmd, ci_h,
529562306a36Sopenharmony_ci				 sizeof(struct megasas_ctrl_info));
529662306a36Sopenharmony_ci
529762306a36Sopenharmony_ci	if ((instance->adapter_type != MFI_SERIES) &&
529862306a36Sopenharmony_ci	    !instance->mask_interrupts) {
529962306a36Sopenharmony_ci		ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
530062306a36Sopenharmony_ci	} else {
530162306a36Sopenharmony_ci		ret = megasas_issue_polled(instance, cmd);
530262306a36Sopenharmony_ci		cmd->flags |= DRV_DCMD_SKIP_REFIRE;
530362306a36Sopenharmony_ci	}
530462306a36Sopenharmony_ci
530562306a36Sopenharmony_ci	switch (ret) {
530662306a36Sopenharmony_ci	case DCMD_SUCCESS:
530762306a36Sopenharmony_ci		/* Save required controller information in
530862306a36Sopenharmony_ci		 * CPU endianness format.
530962306a36Sopenharmony_ci		 */
531062306a36Sopenharmony_ci		le32_to_cpus((u32 *)&ci->properties.OnOffProperties);
531162306a36Sopenharmony_ci		le16_to_cpus((u16 *)&ci->properties.on_off_properties2);
531262306a36Sopenharmony_ci		le32_to_cpus((u32 *)&ci->adapterOperations2);
531362306a36Sopenharmony_ci		le32_to_cpus((u32 *)&ci->adapterOperations3);
531462306a36Sopenharmony_ci		le16_to_cpus((u16 *)&ci->adapter_operations4);
531562306a36Sopenharmony_ci		le32_to_cpus((u32 *)&ci->adapter_operations5);
531662306a36Sopenharmony_ci
531762306a36Sopenharmony_ci		/* Update the latest Ext VD info.
531862306a36Sopenharmony_ci		 * From Init path, store current firmware details.
531962306a36Sopenharmony_ci		 * From OCR path, detect any firmware properties changes.
532062306a36Sopenharmony_ci		 * in case of Firmware upgrade without system reboot.
532162306a36Sopenharmony_ci		 */
532262306a36Sopenharmony_ci		megasas_update_ext_vd_details(instance);
532362306a36Sopenharmony_ci		instance->support_seqnum_jbod_fp =
532462306a36Sopenharmony_ci			ci->adapterOperations3.useSeqNumJbodFP;
532562306a36Sopenharmony_ci		instance->support_morethan256jbod =
532662306a36Sopenharmony_ci			ci->adapter_operations4.support_pd_map_target_id;
532762306a36Sopenharmony_ci		instance->support_nvme_passthru =
532862306a36Sopenharmony_ci			ci->adapter_operations4.support_nvme_passthru;
532962306a36Sopenharmony_ci		instance->support_pci_lane_margining =
533062306a36Sopenharmony_ci			ci->adapter_operations5.support_pci_lane_margining;
533162306a36Sopenharmony_ci		instance->task_abort_tmo = ci->TaskAbortTO;
533262306a36Sopenharmony_ci		instance->max_reset_tmo = ci->MaxResetTO;
533362306a36Sopenharmony_ci
533462306a36Sopenharmony_ci		/*Check whether controller is iMR or MR */
533562306a36Sopenharmony_ci		instance->is_imr = (ci->memory_size ? 0 : 1);
533662306a36Sopenharmony_ci
533762306a36Sopenharmony_ci		instance->snapdump_wait_time =
533862306a36Sopenharmony_ci			(ci->properties.on_off_properties2.enable_snap_dump ?
533962306a36Sopenharmony_ci			 MEGASAS_DEFAULT_SNAP_DUMP_WAIT_TIME : 0);
534062306a36Sopenharmony_ci
534162306a36Sopenharmony_ci		instance->enable_fw_dev_list =
534262306a36Sopenharmony_ci			ci->properties.on_off_properties2.enable_fw_dev_list;
534362306a36Sopenharmony_ci
534462306a36Sopenharmony_ci		dev_info(&instance->pdev->dev,
534562306a36Sopenharmony_ci			"controller type\t: %s(%dMB)\n",
534662306a36Sopenharmony_ci			instance->is_imr ? "iMR" : "MR",
534762306a36Sopenharmony_ci			le16_to_cpu(ci->memory_size));
534862306a36Sopenharmony_ci
534962306a36Sopenharmony_ci		instance->disableOnlineCtrlReset =
535062306a36Sopenharmony_ci			ci->properties.OnOffProperties.disableOnlineCtrlReset;
535162306a36Sopenharmony_ci		instance->secure_jbod_support =
535262306a36Sopenharmony_ci			ci->adapterOperations3.supportSecurityonJBOD;
535362306a36Sopenharmony_ci		dev_info(&instance->pdev->dev, "Online Controller Reset(OCR)\t: %s\n",
535462306a36Sopenharmony_ci			instance->disableOnlineCtrlReset ? "Disabled" : "Enabled");
535562306a36Sopenharmony_ci		dev_info(&instance->pdev->dev, "Secure JBOD support\t: %s\n",
535662306a36Sopenharmony_ci			instance->secure_jbod_support ? "Yes" : "No");
535762306a36Sopenharmony_ci		dev_info(&instance->pdev->dev, "NVMe passthru support\t: %s\n",
535862306a36Sopenharmony_ci			 instance->support_nvme_passthru ? "Yes" : "No");
535962306a36Sopenharmony_ci		dev_info(&instance->pdev->dev,
536062306a36Sopenharmony_ci			 "FW provided TM TaskAbort/Reset timeout\t: %d secs/%d secs\n",
536162306a36Sopenharmony_ci			 instance->task_abort_tmo, instance->max_reset_tmo);
536262306a36Sopenharmony_ci		dev_info(&instance->pdev->dev, "JBOD sequence map support\t: %s\n",
536362306a36Sopenharmony_ci			 instance->support_seqnum_jbod_fp ? "Yes" : "No");
536462306a36Sopenharmony_ci		dev_info(&instance->pdev->dev, "PCI Lane Margining support\t: %s\n",
536562306a36Sopenharmony_ci			 instance->support_pci_lane_margining ? "Yes" : "No");
536662306a36Sopenharmony_ci
536762306a36Sopenharmony_ci		break;
536862306a36Sopenharmony_ci
536962306a36Sopenharmony_ci	case DCMD_TIMEOUT:
537062306a36Sopenharmony_ci		switch (dcmd_timeout_ocr_possible(instance)) {
537162306a36Sopenharmony_ci		case INITIATE_OCR:
537262306a36Sopenharmony_ci			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
537362306a36Sopenharmony_ci			mutex_unlock(&instance->reset_mutex);
537462306a36Sopenharmony_ci			megasas_reset_fusion(instance->host,
537562306a36Sopenharmony_ci				MFI_IO_TIMEOUT_OCR);
537662306a36Sopenharmony_ci			mutex_lock(&instance->reset_mutex);
537762306a36Sopenharmony_ci			break;
537862306a36Sopenharmony_ci		case KILL_ADAPTER:
537962306a36Sopenharmony_ci			megaraid_sas_kill_hba(instance);
538062306a36Sopenharmony_ci			break;
538162306a36Sopenharmony_ci		case IGNORE_TIMEOUT:
538262306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
538362306a36Sopenharmony_ci				__func__, __LINE__);
538462306a36Sopenharmony_ci			break;
538562306a36Sopenharmony_ci		}
538662306a36Sopenharmony_ci		break;
538762306a36Sopenharmony_ci	case DCMD_FAILED:
538862306a36Sopenharmony_ci		megaraid_sas_kill_hba(instance);
538962306a36Sopenharmony_ci		break;
539062306a36Sopenharmony_ci
539162306a36Sopenharmony_ci	}
539262306a36Sopenharmony_ci
539362306a36Sopenharmony_ci	if (ret != DCMD_TIMEOUT)
539462306a36Sopenharmony_ci		megasas_return_cmd(instance, cmd);
539562306a36Sopenharmony_ci
539662306a36Sopenharmony_ci	return ret;
539762306a36Sopenharmony_ci}
539862306a36Sopenharmony_ci
539962306a36Sopenharmony_ci/*
540062306a36Sopenharmony_ci * megasas_set_crash_dump_params -	Sends address of crash dump DMA buffer
540162306a36Sopenharmony_ci *					to firmware
540262306a36Sopenharmony_ci *
540362306a36Sopenharmony_ci * @instance:				Adapter soft state
540462306a36Sopenharmony_ci * @crash_buf_state		-	tell FW to turn ON/OFF crash dump feature
540562306a36Sopenharmony_ci					MR_CRASH_BUF_TURN_OFF = 0
540662306a36Sopenharmony_ci					MR_CRASH_BUF_TURN_ON = 1
540762306a36Sopenharmony_ci * @return 0 on success non-zero on failure.
540862306a36Sopenharmony_ci * Issues an internal command (DCMD) to set parameters for crash dump feature.
540962306a36Sopenharmony_ci * Driver will send address of crash dump DMA buffer and set mbox to tell FW
541062306a36Sopenharmony_ci * that driver supports crash dump feature. This DCMD will be sent only if
541162306a36Sopenharmony_ci * crash dump feature is supported by the FW.
541262306a36Sopenharmony_ci *
541362306a36Sopenharmony_ci */
541462306a36Sopenharmony_ciint megasas_set_crash_dump_params(struct megasas_instance *instance,
541562306a36Sopenharmony_ci	u8 crash_buf_state)
541662306a36Sopenharmony_ci{
541762306a36Sopenharmony_ci	int ret = 0;
541862306a36Sopenharmony_ci	struct megasas_cmd *cmd;
541962306a36Sopenharmony_ci	struct megasas_dcmd_frame *dcmd;
542062306a36Sopenharmony_ci
542162306a36Sopenharmony_ci	cmd = megasas_get_cmd(instance);
542262306a36Sopenharmony_ci
542362306a36Sopenharmony_ci	if (!cmd) {
542462306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "Failed to get a free cmd\n");
542562306a36Sopenharmony_ci		return -ENOMEM;
542662306a36Sopenharmony_ci	}
542762306a36Sopenharmony_ci
542862306a36Sopenharmony_ci
542962306a36Sopenharmony_ci	dcmd = &cmd->frame->dcmd;
543062306a36Sopenharmony_ci
543162306a36Sopenharmony_ci	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
543262306a36Sopenharmony_ci	dcmd->mbox.b[0] = crash_buf_state;
543362306a36Sopenharmony_ci	dcmd->cmd = MFI_CMD_DCMD;
543462306a36Sopenharmony_ci	dcmd->cmd_status = MFI_STAT_INVALID_STATUS;
543562306a36Sopenharmony_ci	dcmd->sge_count = 1;
543662306a36Sopenharmony_ci	dcmd->flags = MFI_FRAME_DIR_NONE;
543762306a36Sopenharmony_ci	dcmd->timeout = 0;
543862306a36Sopenharmony_ci	dcmd->pad_0 = 0;
543962306a36Sopenharmony_ci	dcmd->data_xfer_len = cpu_to_le32(CRASH_DMA_BUF_SIZE);
544062306a36Sopenharmony_ci	dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_SET_CRASH_DUMP_PARAMS);
544162306a36Sopenharmony_ci
544262306a36Sopenharmony_ci	megasas_set_dma_settings(instance, dcmd, instance->crash_dump_h,
544362306a36Sopenharmony_ci				 CRASH_DMA_BUF_SIZE);
544462306a36Sopenharmony_ci
544562306a36Sopenharmony_ci	if ((instance->adapter_type != MFI_SERIES) &&
544662306a36Sopenharmony_ci	    !instance->mask_interrupts)
544762306a36Sopenharmony_ci		ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
544862306a36Sopenharmony_ci	else
544962306a36Sopenharmony_ci		ret = megasas_issue_polled(instance, cmd);
545062306a36Sopenharmony_ci
545162306a36Sopenharmony_ci	if (ret == DCMD_TIMEOUT) {
545262306a36Sopenharmony_ci		switch (dcmd_timeout_ocr_possible(instance)) {
545362306a36Sopenharmony_ci		case INITIATE_OCR:
545462306a36Sopenharmony_ci			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
545562306a36Sopenharmony_ci			megasas_reset_fusion(instance->host,
545662306a36Sopenharmony_ci					MFI_IO_TIMEOUT_OCR);
545762306a36Sopenharmony_ci			break;
545862306a36Sopenharmony_ci		case KILL_ADAPTER:
545962306a36Sopenharmony_ci			megaraid_sas_kill_hba(instance);
546062306a36Sopenharmony_ci			break;
546162306a36Sopenharmony_ci		case IGNORE_TIMEOUT:
546262306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
546362306a36Sopenharmony_ci				__func__, __LINE__);
546462306a36Sopenharmony_ci			break;
546562306a36Sopenharmony_ci		}
546662306a36Sopenharmony_ci	} else
546762306a36Sopenharmony_ci		megasas_return_cmd(instance, cmd);
546862306a36Sopenharmony_ci
546962306a36Sopenharmony_ci	return ret;
547062306a36Sopenharmony_ci}
547162306a36Sopenharmony_ci
547262306a36Sopenharmony_ci/**
547362306a36Sopenharmony_ci * megasas_issue_init_mfi -	Initializes the FW
547462306a36Sopenharmony_ci * @instance:		Adapter soft state
547562306a36Sopenharmony_ci *
547662306a36Sopenharmony_ci * Issues the INIT MFI cmd
547762306a36Sopenharmony_ci */
547862306a36Sopenharmony_cistatic int
547962306a36Sopenharmony_cimegasas_issue_init_mfi(struct megasas_instance *instance)
548062306a36Sopenharmony_ci{
548162306a36Sopenharmony_ci	__le32 context;
548262306a36Sopenharmony_ci	struct megasas_cmd *cmd;
548362306a36Sopenharmony_ci	struct megasas_init_frame *init_frame;
548462306a36Sopenharmony_ci	struct megasas_init_queue_info *initq_info;
548562306a36Sopenharmony_ci	dma_addr_t init_frame_h;
548662306a36Sopenharmony_ci	dma_addr_t initq_info_h;
548762306a36Sopenharmony_ci
548862306a36Sopenharmony_ci	/*
548962306a36Sopenharmony_ci	 * Prepare a init frame. Note the init frame points to queue info
549062306a36Sopenharmony_ci	 * structure. Each frame has SGL allocated after first 64 bytes. For
549162306a36Sopenharmony_ci	 * this frame - since we don't need any SGL - we use SGL's space as
549262306a36Sopenharmony_ci	 * queue info structure
549362306a36Sopenharmony_ci	 *
549462306a36Sopenharmony_ci	 * We will not get a NULL command below. We just created the pool.
549562306a36Sopenharmony_ci	 */
549662306a36Sopenharmony_ci	cmd = megasas_get_cmd(instance);
549762306a36Sopenharmony_ci
549862306a36Sopenharmony_ci	init_frame = (struct megasas_init_frame *)cmd->frame;
549962306a36Sopenharmony_ci	initq_info = (struct megasas_init_queue_info *)
550062306a36Sopenharmony_ci		((unsigned long)init_frame + 64);
550162306a36Sopenharmony_ci
550262306a36Sopenharmony_ci	init_frame_h = cmd->frame_phys_addr;
550362306a36Sopenharmony_ci	initq_info_h = init_frame_h + 64;
550462306a36Sopenharmony_ci
550562306a36Sopenharmony_ci	context = init_frame->context;
550662306a36Sopenharmony_ci	memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
550762306a36Sopenharmony_ci	memset(initq_info, 0, sizeof(struct megasas_init_queue_info));
550862306a36Sopenharmony_ci	init_frame->context = context;
550962306a36Sopenharmony_ci
551062306a36Sopenharmony_ci	initq_info->reply_queue_entries = cpu_to_le32(instance->max_fw_cmds + 1);
551162306a36Sopenharmony_ci	initq_info->reply_queue_start_phys_addr_lo = cpu_to_le32(instance->reply_queue_h);
551262306a36Sopenharmony_ci
551362306a36Sopenharmony_ci	initq_info->producer_index_phys_addr_lo = cpu_to_le32(instance->producer_h);
551462306a36Sopenharmony_ci	initq_info->consumer_index_phys_addr_lo = cpu_to_le32(instance->consumer_h);
551562306a36Sopenharmony_ci
551662306a36Sopenharmony_ci	init_frame->cmd = MFI_CMD_INIT;
551762306a36Sopenharmony_ci	init_frame->cmd_status = MFI_STAT_INVALID_STATUS;
551862306a36Sopenharmony_ci	init_frame->queue_info_new_phys_addr_lo =
551962306a36Sopenharmony_ci		cpu_to_le32(lower_32_bits(initq_info_h));
552062306a36Sopenharmony_ci	init_frame->queue_info_new_phys_addr_hi =
552162306a36Sopenharmony_ci		cpu_to_le32(upper_32_bits(initq_info_h));
552262306a36Sopenharmony_ci
552362306a36Sopenharmony_ci	init_frame->data_xfer_len = cpu_to_le32(sizeof(struct megasas_init_queue_info));
552462306a36Sopenharmony_ci
552562306a36Sopenharmony_ci	/*
552662306a36Sopenharmony_ci	 * disable the intr before firing the init frame to FW
552762306a36Sopenharmony_ci	 */
552862306a36Sopenharmony_ci	instance->instancet->disable_intr(instance);
552962306a36Sopenharmony_ci
553062306a36Sopenharmony_ci	/*
553162306a36Sopenharmony_ci	 * Issue the init frame in polled mode
553262306a36Sopenharmony_ci	 */
553362306a36Sopenharmony_ci
553462306a36Sopenharmony_ci	if (megasas_issue_polled(instance, cmd)) {
553562306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "Failed to init firmware\n");
553662306a36Sopenharmony_ci		megasas_return_cmd(instance, cmd);
553762306a36Sopenharmony_ci		goto fail_fw_init;
553862306a36Sopenharmony_ci	}
553962306a36Sopenharmony_ci
554062306a36Sopenharmony_ci	megasas_return_cmd(instance, cmd);
554162306a36Sopenharmony_ci
554262306a36Sopenharmony_ci	return 0;
554362306a36Sopenharmony_ci
554462306a36Sopenharmony_cifail_fw_init:
554562306a36Sopenharmony_ci	return -EINVAL;
554662306a36Sopenharmony_ci}
554762306a36Sopenharmony_ci
554862306a36Sopenharmony_cistatic u32
554962306a36Sopenharmony_cimegasas_init_adapter_mfi(struct megasas_instance *instance)
555062306a36Sopenharmony_ci{
555162306a36Sopenharmony_ci	u32 context_sz;
555262306a36Sopenharmony_ci	u32 reply_q_sz;
555362306a36Sopenharmony_ci
555462306a36Sopenharmony_ci	/*
555562306a36Sopenharmony_ci	 * Get various operational parameters from status register
555662306a36Sopenharmony_ci	 */
555762306a36Sopenharmony_ci	instance->max_fw_cmds = instance->instancet->read_fw_status_reg(instance) & 0x00FFFF;
555862306a36Sopenharmony_ci	/*
555962306a36Sopenharmony_ci	 * Reduce the max supported cmds by 1. This is to ensure that the
556062306a36Sopenharmony_ci	 * reply_q_sz (1 more than the max cmd that driver may send)
556162306a36Sopenharmony_ci	 * does not exceed max cmds that the FW can support
556262306a36Sopenharmony_ci	 */
556362306a36Sopenharmony_ci	instance->max_fw_cmds = instance->max_fw_cmds-1;
556462306a36Sopenharmony_ci	instance->max_mfi_cmds = instance->max_fw_cmds;
556562306a36Sopenharmony_ci	instance->max_num_sge = (instance->instancet->read_fw_status_reg(instance) & 0xFF0000) >>
556662306a36Sopenharmony_ci					0x10;
556762306a36Sopenharmony_ci	/*
556862306a36Sopenharmony_ci	 * For MFI skinny adapters, MEGASAS_SKINNY_INT_CMDS commands
556962306a36Sopenharmony_ci	 * are reserved for IOCTL + driver's internal DCMDs.
557062306a36Sopenharmony_ci	 */
557162306a36Sopenharmony_ci	if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
557262306a36Sopenharmony_ci		(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
557362306a36Sopenharmony_ci		instance->max_scsi_cmds = (instance->max_fw_cmds -
557462306a36Sopenharmony_ci			MEGASAS_SKINNY_INT_CMDS);
557562306a36Sopenharmony_ci		sema_init(&instance->ioctl_sem, MEGASAS_SKINNY_INT_CMDS);
557662306a36Sopenharmony_ci	} else {
557762306a36Sopenharmony_ci		instance->max_scsi_cmds = (instance->max_fw_cmds -
557862306a36Sopenharmony_ci			MEGASAS_INT_CMDS);
557962306a36Sopenharmony_ci		sema_init(&instance->ioctl_sem, (MEGASAS_MFI_IOCTL_CMDS));
558062306a36Sopenharmony_ci	}
558162306a36Sopenharmony_ci
558262306a36Sopenharmony_ci	instance->cur_can_queue = instance->max_scsi_cmds;
558362306a36Sopenharmony_ci	/*
558462306a36Sopenharmony_ci	 * Create a pool of commands
558562306a36Sopenharmony_ci	 */
558662306a36Sopenharmony_ci	if (megasas_alloc_cmds(instance))
558762306a36Sopenharmony_ci		goto fail_alloc_cmds;
558862306a36Sopenharmony_ci
558962306a36Sopenharmony_ci	/*
559062306a36Sopenharmony_ci	 * Allocate memory for reply queue. Length of reply queue should
559162306a36Sopenharmony_ci	 * be _one_ more than the maximum commands handled by the firmware.
559262306a36Sopenharmony_ci	 *
559362306a36Sopenharmony_ci	 * Note: When FW completes commands, it places corresponding contex
559462306a36Sopenharmony_ci	 * values in this circular reply queue. This circular queue is a fairly
559562306a36Sopenharmony_ci	 * typical producer-consumer queue. FW is the producer (of completed
559662306a36Sopenharmony_ci	 * commands) and the driver is the consumer.
559762306a36Sopenharmony_ci	 */
559862306a36Sopenharmony_ci	context_sz = sizeof(u32);
559962306a36Sopenharmony_ci	reply_q_sz = context_sz * (instance->max_fw_cmds + 1);
560062306a36Sopenharmony_ci
560162306a36Sopenharmony_ci	instance->reply_queue = dma_alloc_coherent(&instance->pdev->dev,
560262306a36Sopenharmony_ci			reply_q_sz, &instance->reply_queue_h, GFP_KERNEL);
560362306a36Sopenharmony_ci
560462306a36Sopenharmony_ci	if (!instance->reply_queue) {
560562306a36Sopenharmony_ci		dev_printk(KERN_DEBUG, &instance->pdev->dev, "Out of DMA mem for reply queue\n");
560662306a36Sopenharmony_ci		goto fail_reply_queue;
560762306a36Sopenharmony_ci	}
560862306a36Sopenharmony_ci
560962306a36Sopenharmony_ci	if (megasas_issue_init_mfi(instance))
561062306a36Sopenharmony_ci		goto fail_fw_init;
561162306a36Sopenharmony_ci
561262306a36Sopenharmony_ci	if (megasas_get_ctrl_info(instance)) {
561362306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "(%d): Could get controller info "
561462306a36Sopenharmony_ci			"Fail from %s %d\n", instance->unique_id,
561562306a36Sopenharmony_ci			__func__, __LINE__);
561662306a36Sopenharmony_ci		goto fail_fw_init;
561762306a36Sopenharmony_ci	}
561862306a36Sopenharmony_ci
561962306a36Sopenharmony_ci	instance->fw_support_ieee = 0;
562062306a36Sopenharmony_ci	instance->fw_support_ieee =
562162306a36Sopenharmony_ci		(instance->instancet->read_fw_status_reg(instance) &
562262306a36Sopenharmony_ci		0x04000000);
562362306a36Sopenharmony_ci
562462306a36Sopenharmony_ci	dev_notice(&instance->pdev->dev, "megasas_init_mfi: fw_support_ieee=%d",
562562306a36Sopenharmony_ci			instance->fw_support_ieee);
562662306a36Sopenharmony_ci
562762306a36Sopenharmony_ci	if (instance->fw_support_ieee)
562862306a36Sopenharmony_ci		instance->flag_ieee = 1;
562962306a36Sopenharmony_ci
563062306a36Sopenharmony_ci	return 0;
563162306a36Sopenharmony_ci
563262306a36Sopenharmony_cifail_fw_init:
563362306a36Sopenharmony_ci
563462306a36Sopenharmony_ci	dma_free_coherent(&instance->pdev->dev, reply_q_sz,
563562306a36Sopenharmony_ci			    instance->reply_queue, instance->reply_queue_h);
563662306a36Sopenharmony_cifail_reply_queue:
563762306a36Sopenharmony_ci	megasas_free_cmds(instance);
563862306a36Sopenharmony_ci
563962306a36Sopenharmony_cifail_alloc_cmds:
564062306a36Sopenharmony_ci	return 1;
564162306a36Sopenharmony_ci}
564262306a36Sopenharmony_ci
564362306a36Sopenharmony_cistatic
564462306a36Sopenharmony_civoid megasas_setup_irq_poll(struct megasas_instance *instance)
564562306a36Sopenharmony_ci{
564662306a36Sopenharmony_ci	struct megasas_irq_context *irq_ctx;
564762306a36Sopenharmony_ci	u32 count, i;
564862306a36Sopenharmony_ci
564962306a36Sopenharmony_ci	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
565062306a36Sopenharmony_ci
565162306a36Sopenharmony_ci	/* Initialize IRQ poll */
565262306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
565362306a36Sopenharmony_ci		irq_ctx = &instance->irq_context[i];
565462306a36Sopenharmony_ci		irq_ctx->os_irq = pci_irq_vector(instance->pdev, i);
565562306a36Sopenharmony_ci		irq_ctx->irq_poll_scheduled = false;
565662306a36Sopenharmony_ci		irq_poll_init(&irq_ctx->irqpoll,
565762306a36Sopenharmony_ci			      instance->threshold_reply_count,
565862306a36Sopenharmony_ci			      megasas_irqpoll);
565962306a36Sopenharmony_ci	}
566062306a36Sopenharmony_ci}
566162306a36Sopenharmony_ci
566262306a36Sopenharmony_ci/*
566362306a36Sopenharmony_ci * megasas_setup_irqs_ioapic -		register legacy interrupts.
566462306a36Sopenharmony_ci * @instance:				Adapter soft state
566562306a36Sopenharmony_ci *
566662306a36Sopenharmony_ci * Do not enable interrupt, only setup ISRs.
566762306a36Sopenharmony_ci *
566862306a36Sopenharmony_ci * Return 0 on success.
566962306a36Sopenharmony_ci */
567062306a36Sopenharmony_cistatic int
567162306a36Sopenharmony_cimegasas_setup_irqs_ioapic(struct megasas_instance *instance)
567262306a36Sopenharmony_ci{
567362306a36Sopenharmony_ci	struct pci_dev *pdev;
567462306a36Sopenharmony_ci
567562306a36Sopenharmony_ci	pdev = instance->pdev;
567662306a36Sopenharmony_ci	instance->irq_context[0].instance = instance;
567762306a36Sopenharmony_ci	instance->irq_context[0].MSIxIndex = 0;
567862306a36Sopenharmony_ci	snprintf(instance->irq_context->name, MEGASAS_MSIX_NAME_LEN, "%s%u",
567962306a36Sopenharmony_ci		"megasas", instance->host->host_no);
568062306a36Sopenharmony_ci	if (request_irq(pci_irq_vector(pdev, 0),
568162306a36Sopenharmony_ci			instance->instancet->service_isr, IRQF_SHARED,
568262306a36Sopenharmony_ci			instance->irq_context->name, &instance->irq_context[0])) {
568362306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
568462306a36Sopenharmony_ci				"Failed to register IRQ from %s %d\n",
568562306a36Sopenharmony_ci				__func__, __LINE__);
568662306a36Sopenharmony_ci		return -1;
568762306a36Sopenharmony_ci	}
568862306a36Sopenharmony_ci	instance->perf_mode = MR_LATENCY_PERF_MODE;
568962306a36Sopenharmony_ci	instance->low_latency_index_start = 0;
569062306a36Sopenharmony_ci	return 0;
569162306a36Sopenharmony_ci}
569262306a36Sopenharmony_ci
569362306a36Sopenharmony_ci/**
569462306a36Sopenharmony_ci * megasas_setup_irqs_msix -		register MSI-x interrupts.
569562306a36Sopenharmony_ci * @instance:				Adapter soft state
569662306a36Sopenharmony_ci * @is_probe:				Driver probe check
569762306a36Sopenharmony_ci *
569862306a36Sopenharmony_ci * Do not enable interrupt, only setup ISRs.
569962306a36Sopenharmony_ci *
570062306a36Sopenharmony_ci * Return 0 on success.
570162306a36Sopenharmony_ci */
570262306a36Sopenharmony_cistatic int
570362306a36Sopenharmony_cimegasas_setup_irqs_msix(struct megasas_instance *instance, u8 is_probe)
570462306a36Sopenharmony_ci{
570562306a36Sopenharmony_ci	int i, j;
570662306a36Sopenharmony_ci	struct pci_dev *pdev;
570762306a36Sopenharmony_ci
570862306a36Sopenharmony_ci	pdev = instance->pdev;
570962306a36Sopenharmony_ci
571062306a36Sopenharmony_ci	/* Try MSI-x */
571162306a36Sopenharmony_ci	for (i = 0; i < instance->msix_vectors; i++) {
571262306a36Sopenharmony_ci		instance->irq_context[i].instance = instance;
571362306a36Sopenharmony_ci		instance->irq_context[i].MSIxIndex = i;
571462306a36Sopenharmony_ci		snprintf(instance->irq_context[i].name, MEGASAS_MSIX_NAME_LEN, "%s%u-msix%u",
571562306a36Sopenharmony_ci			"megasas", instance->host->host_no, i);
571662306a36Sopenharmony_ci		if (request_irq(pci_irq_vector(pdev, i),
571762306a36Sopenharmony_ci			instance->instancet->service_isr, 0, instance->irq_context[i].name,
571862306a36Sopenharmony_ci			&instance->irq_context[i])) {
571962306a36Sopenharmony_ci			dev_err(&instance->pdev->dev,
572062306a36Sopenharmony_ci				"Failed to register IRQ for vector %d.\n", i);
572162306a36Sopenharmony_ci			for (j = 0; j < i; j++) {
572262306a36Sopenharmony_ci				if (j < instance->low_latency_index_start)
572362306a36Sopenharmony_ci					irq_update_affinity_hint(
572462306a36Sopenharmony_ci						pci_irq_vector(pdev, j), NULL);
572562306a36Sopenharmony_ci				free_irq(pci_irq_vector(pdev, j),
572662306a36Sopenharmony_ci					 &instance->irq_context[j]);
572762306a36Sopenharmony_ci			}
572862306a36Sopenharmony_ci			/* Retry irq register for IO_APIC*/
572962306a36Sopenharmony_ci			instance->msix_vectors = 0;
573062306a36Sopenharmony_ci			instance->msix_load_balance = false;
573162306a36Sopenharmony_ci			if (is_probe) {
573262306a36Sopenharmony_ci				pci_free_irq_vectors(instance->pdev);
573362306a36Sopenharmony_ci				return megasas_setup_irqs_ioapic(instance);
573462306a36Sopenharmony_ci			} else {
573562306a36Sopenharmony_ci				return -1;
573662306a36Sopenharmony_ci			}
573762306a36Sopenharmony_ci		}
573862306a36Sopenharmony_ci	}
573962306a36Sopenharmony_ci
574062306a36Sopenharmony_ci	return 0;
574162306a36Sopenharmony_ci}
574262306a36Sopenharmony_ci
574362306a36Sopenharmony_ci/*
574462306a36Sopenharmony_ci * megasas_destroy_irqs-		unregister interrupts.
574562306a36Sopenharmony_ci * @instance:				Adapter soft state
574662306a36Sopenharmony_ci * return:				void
574762306a36Sopenharmony_ci */
574862306a36Sopenharmony_cistatic void
574962306a36Sopenharmony_cimegasas_destroy_irqs(struct megasas_instance *instance) {
575062306a36Sopenharmony_ci
575162306a36Sopenharmony_ci	int i;
575262306a36Sopenharmony_ci	int count;
575362306a36Sopenharmony_ci	struct megasas_irq_context *irq_ctx;
575462306a36Sopenharmony_ci
575562306a36Sopenharmony_ci	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
575662306a36Sopenharmony_ci	if (instance->adapter_type != MFI_SERIES) {
575762306a36Sopenharmony_ci		for (i = 0; i < count; i++) {
575862306a36Sopenharmony_ci			irq_ctx = &instance->irq_context[i];
575962306a36Sopenharmony_ci			irq_poll_disable(&irq_ctx->irqpoll);
576062306a36Sopenharmony_ci		}
576162306a36Sopenharmony_ci	}
576262306a36Sopenharmony_ci
576362306a36Sopenharmony_ci	if (instance->msix_vectors)
576462306a36Sopenharmony_ci		for (i = 0; i < instance->msix_vectors; i++) {
576562306a36Sopenharmony_ci			if (i < instance->low_latency_index_start)
576662306a36Sopenharmony_ci				irq_update_affinity_hint(
576762306a36Sopenharmony_ci				    pci_irq_vector(instance->pdev, i), NULL);
576862306a36Sopenharmony_ci			free_irq(pci_irq_vector(instance->pdev, i),
576962306a36Sopenharmony_ci				 &instance->irq_context[i]);
577062306a36Sopenharmony_ci		}
577162306a36Sopenharmony_ci	else
577262306a36Sopenharmony_ci		free_irq(pci_irq_vector(instance->pdev, 0),
577362306a36Sopenharmony_ci			 &instance->irq_context[0]);
577462306a36Sopenharmony_ci}
577562306a36Sopenharmony_ci
577662306a36Sopenharmony_ci/**
577762306a36Sopenharmony_ci * megasas_setup_jbod_map -	setup jbod map for FP seq_number.
577862306a36Sopenharmony_ci * @instance:				Adapter soft state
577962306a36Sopenharmony_ci *
578062306a36Sopenharmony_ci * Return 0 on success.
578162306a36Sopenharmony_ci */
578262306a36Sopenharmony_civoid
578362306a36Sopenharmony_cimegasas_setup_jbod_map(struct megasas_instance *instance)
578462306a36Sopenharmony_ci{
578562306a36Sopenharmony_ci	int i;
578662306a36Sopenharmony_ci	struct fusion_context *fusion = instance->ctrl_context;
578762306a36Sopenharmony_ci	size_t pd_seq_map_sz;
578862306a36Sopenharmony_ci
578962306a36Sopenharmony_ci	pd_seq_map_sz = struct_size_t(struct MR_PD_CFG_SEQ_NUM_SYNC, seq,
579062306a36Sopenharmony_ci				      MAX_PHYSICAL_DEVICES);
579162306a36Sopenharmony_ci
579262306a36Sopenharmony_ci	instance->use_seqnum_jbod_fp =
579362306a36Sopenharmony_ci		instance->support_seqnum_jbod_fp;
579462306a36Sopenharmony_ci	if (reset_devices || !fusion ||
579562306a36Sopenharmony_ci		!instance->support_seqnum_jbod_fp) {
579662306a36Sopenharmony_ci		dev_info(&instance->pdev->dev,
579762306a36Sopenharmony_ci			"JBOD sequence map is disabled %s %d\n",
579862306a36Sopenharmony_ci			__func__, __LINE__);
579962306a36Sopenharmony_ci		instance->use_seqnum_jbod_fp = false;
580062306a36Sopenharmony_ci		return;
580162306a36Sopenharmony_ci	}
580262306a36Sopenharmony_ci
580362306a36Sopenharmony_ci	if (fusion->pd_seq_sync[0])
580462306a36Sopenharmony_ci		goto skip_alloc;
580562306a36Sopenharmony_ci
580662306a36Sopenharmony_ci	for (i = 0; i < JBOD_MAPS_COUNT; i++) {
580762306a36Sopenharmony_ci		fusion->pd_seq_sync[i] = dma_alloc_coherent
580862306a36Sopenharmony_ci			(&instance->pdev->dev, pd_seq_map_sz,
580962306a36Sopenharmony_ci			&fusion->pd_seq_phys[i], GFP_KERNEL);
581062306a36Sopenharmony_ci		if (!fusion->pd_seq_sync[i]) {
581162306a36Sopenharmony_ci			dev_err(&instance->pdev->dev,
581262306a36Sopenharmony_ci				"Failed to allocate memory from %s %d\n",
581362306a36Sopenharmony_ci				__func__, __LINE__);
581462306a36Sopenharmony_ci			if (i == 1) {
581562306a36Sopenharmony_ci				dma_free_coherent(&instance->pdev->dev,
581662306a36Sopenharmony_ci					pd_seq_map_sz, fusion->pd_seq_sync[0],
581762306a36Sopenharmony_ci					fusion->pd_seq_phys[0]);
581862306a36Sopenharmony_ci				fusion->pd_seq_sync[0] = NULL;
581962306a36Sopenharmony_ci			}
582062306a36Sopenharmony_ci			instance->use_seqnum_jbod_fp = false;
582162306a36Sopenharmony_ci			return;
582262306a36Sopenharmony_ci		}
582362306a36Sopenharmony_ci	}
582462306a36Sopenharmony_ci
582562306a36Sopenharmony_ciskip_alloc:
582662306a36Sopenharmony_ci	if (!megasas_sync_pd_seq_num(instance, false) &&
582762306a36Sopenharmony_ci		!megasas_sync_pd_seq_num(instance, true))
582862306a36Sopenharmony_ci		instance->use_seqnum_jbod_fp = true;
582962306a36Sopenharmony_ci	else
583062306a36Sopenharmony_ci		instance->use_seqnum_jbod_fp = false;
583162306a36Sopenharmony_ci}
583262306a36Sopenharmony_ci
583362306a36Sopenharmony_cistatic void megasas_setup_reply_map(struct megasas_instance *instance)
583462306a36Sopenharmony_ci{
583562306a36Sopenharmony_ci	const struct cpumask *mask;
583662306a36Sopenharmony_ci	unsigned int queue, cpu, low_latency_index_start;
583762306a36Sopenharmony_ci
583862306a36Sopenharmony_ci	low_latency_index_start = instance->low_latency_index_start;
583962306a36Sopenharmony_ci
584062306a36Sopenharmony_ci	for (queue = low_latency_index_start; queue < instance->msix_vectors; queue++) {
584162306a36Sopenharmony_ci		mask = pci_irq_get_affinity(instance->pdev, queue);
584262306a36Sopenharmony_ci		if (!mask)
584362306a36Sopenharmony_ci			goto fallback;
584462306a36Sopenharmony_ci
584562306a36Sopenharmony_ci		for_each_cpu(cpu, mask)
584662306a36Sopenharmony_ci			instance->reply_map[cpu] = queue;
584762306a36Sopenharmony_ci	}
584862306a36Sopenharmony_ci	return;
584962306a36Sopenharmony_ci
585062306a36Sopenharmony_cifallback:
585162306a36Sopenharmony_ci	queue = low_latency_index_start;
585262306a36Sopenharmony_ci	for_each_possible_cpu(cpu) {
585362306a36Sopenharmony_ci		instance->reply_map[cpu] = queue;
585462306a36Sopenharmony_ci		if (queue == (instance->msix_vectors - 1))
585562306a36Sopenharmony_ci			queue = low_latency_index_start;
585662306a36Sopenharmony_ci		else
585762306a36Sopenharmony_ci			queue++;
585862306a36Sopenharmony_ci	}
585962306a36Sopenharmony_ci}
586062306a36Sopenharmony_ci
586162306a36Sopenharmony_ci/**
586262306a36Sopenharmony_ci * megasas_get_device_list -	Get the PD and LD device list from FW.
586362306a36Sopenharmony_ci * @instance:			Adapter soft state
586462306a36Sopenharmony_ci * @return:			Success or failure
586562306a36Sopenharmony_ci *
586662306a36Sopenharmony_ci * Issue DCMDs to Firmware to get the PD and LD list.
586762306a36Sopenharmony_ci * Based on the FW support, driver sends the HOST_DEVICE_LIST or combination
586862306a36Sopenharmony_ci * of PD_LIST/LD_LIST_QUERY DCMDs to get the device list.
586962306a36Sopenharmony_ci */
587062306a36Sopenharmony_cistatic
587162306a36Sopenharmony_ciint megasas_get_device_list(struct megasas_instance *instance)
587262306a36Sopenharmony_ci{
587362306a36Sopenharmony_ci	if (instance->enable_fw_dev_list) {
587462306a36Sopenharmony_ci		if (megasas_host_device_list_query(instance, true))
587562306a36Sopenharmony_ci			return FAILED;
587662306a36Sopenharmony_ci	} else {
587762306a36Sopenharmony_ci		if (megasas_get_pd_list(instance) < 0) {
587862306a36Sopenharmony_ci			dev_err(&instance->pdev->dev, "failed to get PD list\n");
587962306a36Sopenharmony_ci			return FAILED;
588062306a36Sopenharmony_ci		}
588162306a36Sopenharmony_ci
588262306a36Sopenharmony_ci		if (megasas_ld_list_query(instance,
588362306a36Sopenharmony_ci					  MR_LD_QUERY_TYPE_EXPOSED_TO_HOST)) {
588462306a36Sopenharmony_ci			dev_err(&instance->pdev->dev, "failed to get LD list\n");
588562306a36Sopenharmony_ci			return FAILED;
588662306a36Sopenharmony_ci		}
588762306a36Sopenharmony_ci	}
588862306a36Sopenharmony_ci
588962306a36Sopenharmony_ci	return SUCCESS;
589062306a36Sopenharmony_ci}
589162306a36Sopenharmony_ci
589262306a36Sopenharmony_ci/**
589362306a36Sopenharmony_ci * megasas_set_high_iops_queue_affinity_and_hint -	Set affinity and hint
589462306a36Sopenharmony_ci *							for high IOPS queues
589562306a36Sopenharmony_ci * @instance:						Adapter soft state
589662306a36Sopenharmony_ci * return:						void
589762306a36Sopenharmony_ci */
589862306a36Sopenharmony_cistatic inline void
589962306a36Sopenharmony_cimegasas_set_high_iops_queue_affinity_and_hint(struct megasas_instance *instance)
590062306a36Sopenharmony_ci{
590162306a36Sopenharmony_ci	int i;
590262306a36Sopenharmony_ci	unsigned int irq;
590362306a36Sopenharmony_ci	const struct cpumask *mask;
590462306a36Sopenharmony_ci
590562306a36Sopenharmony_ci	if (instance->perf_mode == MR_BALANCED_PERF_MODE) {
590662306a36Sopenharmony_ci		mask = cpumask_of_node(dev_to_node(&instance->pdev->dev));
590762306a36Sopenharmony_ci
590862306a36Sopenharmony_ci		for (i = 0; i < instance->low_latency_index_start; i++) {
590962306a36Sopenharmony_ci			irq = pci_irq_vector(instance->pdev, i);
591062306a36Sopenharmony_ci			irq_set_affinity_and_hint(irq, mask);
591162306a36Sopenharmony_ci		}
591262306a36Sopenharmony_ci	}
591362306a36Sopenharmony_ci}
591462306a36Sopenharmony_ci
591562306a36Sopenharmony_cistatic int
591662306a36Sopenharmony_ci__megasas_alloc_irq_vectors(struct megasas_instance *instance)
591762306a36Sopenharmony_ci{
591862306a36Sopenharmony_ci	int i, irq_flags;
591962306a36Sopenharmony_ci	struct irq_affinity desc = { .pre_vectors = instance->low_latency_index_start };
592062306a36Sopenharmony_ci	struct irq_affinity *descp = &desc;
592162306a36Sopenharmony_ci
592262306a36Sopenharmony_ci	irq_flags = PCI_IRQ_MSIX;
592362306a36Sopenharmony_ci
592462306a36Sopenharmony_ci	if (instance->smp_affinity_enable)
592562306a36Sopenharmony_ci		irq_flags |= PCI_IRQ_AFFINITY | PCI_IRQ_ALL_TYPES;
592662306a36Sopenharmony_ci	else
592762306a36Sopenharmony_ci		descp = NULL;
592862306a36Sopenharmony_ci
592962306a36Sopenharmony_ci	/* Do not allocate msix vectors for poll_queues.
593062306a36Sopenharmony_ci	 * msix_vectors is always within a range of FW supported reply queue.
593162306a36Sopenharmony_ci	 */
593262306a36Sopenharmony_ci	i = pci_alloc_irq_vectors_affinity(instance->pdev,
593362306a36Sopenharmony_ci		instance->low_latency_index_start,
593462306a36Sopenharmony_ci		instance->msix_vectors - instance->iopoll_q_count, irq_flags, descp);
593562306a36Sopenharmony_ci
593662306a36Sopenharmony_ci	return i;
593762306a36Sopenharmony_ci}
593862306a36Sopenharmony_ci
593962306a36Sopenharmony_ci/**
594062306a36Sopenharmony_ci * megasas_alloc_irq_vectors -	Allocate IRQ vectors/enable MSI-x vectors
594162306a36Sopenharmony_ci * @instance:			Adapter soft state
594262306a36Sopenharmony_ci * return:			void
594362306a36Sopenharmony_ci */
594462306a36Sopenharmony_cistatic void
594562306a36Sopenharmony_cimegasas_alloc_irq_vectors(struct megasas_instance *instance)
594662306a36Sopenharmony_ci{
594762306a36Sopenharmony_ci	int i;
594862306a36Sopenharmony_ci	unsigned int num_msix_req;
594962306a36Sopenharmony_ci
595062306a36Sopenharmony_ci	instance->iopoll_q_count = 0;
595162306a36Sopenharmony_ci	if ((instance->adapter_type != MFI_SERIES) &&
595262306a36Sopenharmony_ci		poll_queues) {
595362306a36Sopenharmony_ci
595462306a36Sopenharmony_ci		instance->perf_mode = MR_LATENCY_PERF_MODE;
595562306a36Sopenharmony_ci		instance->low_latency_index_start = 1;
595662306a36Sopenharmony_ci
595762306a36Sopenharmony_ci		/* reserve for default and non-mananged pre-vector. */
595862306a36Sopenharmony_ci		if (instance->msix_vectors > (poll_queues + 2))
595962306a36Sopenharmony_ci			instance->iopoll_q_count = poll_queues;
596062306a36Sopenharmony_ci		else
596162306a36Sopenharmony_ci			instance->iopoll_q_count = 0;
596262306a36Sopenharmony_ci
596362306a36Sopenharmony_ci		num_msix_req = num_online_cpus() + instance->low_latency_index_start;
596462306a36Sopenharmony_ci		instance->msix_vectors = min(num_msix_req,
596562306a36Sopenharmony_ci				instance->msix_vectors);
596662306a36Sopenharmony_ci
596762306a36Sopenharmony_ci	}
596862306a36Sopenharmony_ci
596962306a36Sopenharmony_ci	i = __megasas_alloc_irq_vectors(instance);
597062306a36Sopenharmony_ci
597162306a36Sopenharmony_ci	if (((instance->perf_mode == MR_BALANCED_PERF_MODE)
597262306a36Sopenharmony_ci		|| instance->iopoll_q_count) &&
597362306a36Sopenharmony_ci	    (i != (instance->msix_vectors - instance->iopoll_q_count))) {
597462306a36Sopenharmony_ci		if (instance->msix_vectors)
597562306a36Sopenharmony_ci			pci_free_irq_vectors(instance->pdev);
597662306a36Sopenharmony_ci		/* Disable Balanced IOPS mode and try realloc vectors */
597762306a36Sopenharmony_ci		instance->perf_mode = MR_LATENCY_PERF_MODE;
597862306a36Sopenharmony_ci		instance->low_latency_index_start = 1;
597962306a36Sopenharmony_ci		num_msix_req = num_online_cpus() + instance->low_latency_index_start;
598062306a36Sopenharmony_ci
598162306a36Sopenharmony_ci		instance->msix_vectors = min(num_msix_req,
598262306a36Sopenharmony_ci				instance->msix_vectors);
598362306a36Sopenharmony_ci
598462306a36Sopenharmony_ci		instance->iopoll_q_count = 0;
598562306a36Sopenharmony_ci		i = __megasas_alloc_irq_vectors(instance);
598662306a36Sopenharmony_ci
598762306a36Sopenharmony_ci	}
598862306a36Sopenharmony_ci
598962306a36Sopenharmony_ci	dev_info(&instance->pdev->dev,
599062306a36Sopenharmony_ci		"requested/available msix %d/%d poll_queue %d\n",
599162306a36Sopenharmony_ci			instance->msix_vectors - instance->iopoll_q_count,
599262306a36Sopenharmony_ci			i, instance->iopoll_q_count);
599362306a36Sopenharmony_ci
599462306a36Sopenharmony_ci	if (i > 0)
599562306a36Sopenharmony_ci		instance->msix_vectors = i;
599662306a36Sopenharmony_ci	else
599762306a36Sopenharmony_ci		instance->msix_vectors = 0;
599862306a36Sopenharmony_ci
599962306a36Sopenharmony_ci	if (instance->smp_affinity_enable)
600062306a36Sopenharmony_ci		megasas_set_high_iops_queue_affinity_and_hint(instance);
600162306a36Sopenharmony_ci}
600262306a36Sopenharmony_ci
600362306a36Sopenharmony_ci/**
600462306a36Sopenharmony_ci * megasas_init_fw -	Initializes the FW
600562306a36Sopenharmony_ci * @instance:		Adapter soft state
600662306a36Sopenharmony_ci *
600762306a36Sopenharmony_ci * This is the main function for initializing firmware
600862306a36Sopenharmony_ci */
600962306a36Sopenharmony_ci
601062306a36Sopenharmony_cistatic int megasas_init_fw(struct megasas_instance *instance)
601162306a36Sopenharmony_ci{
601262306a36Sopenharmony_ci	u32 max_sectors_1;
601362306a36Sopenharmony_ci	u32 max_sectors_2, tmp_sectors, msix_enable;
601462306a36Sopenharmony_ci	u32 scratch_pad_1, scratch_pad_2, scratch_pad_3, status_reg;
601562306a36Sopenharmony_ci	resource_size_t base_addr;
601662306a36Sopenharmony_ci	void *base_addr_phys;
601762306a36Sopenharmony_ci	struct megasas_ctrl_info *ctrl_info = NULL;
601862306a36Sopenharmony_ci	unsigned long bar_list;
601962306a36Sopenharmony_ci	int i, j, loop;
602062306a36Sopenharmony_ci	struct IOV_111 *iovPtr;
602162306a36Sopenharmony_ci	struct fusion_context *fusion;
602262306a36Sopenharmony_ci	bool intr_coalescing;
602362306a36Sopenharmony_ci	unsigned int num_msix_req;
602462306a36Sopenharmony_ci	u16 lnksta, speed;
602562306a36Sopenharmony_ci
602662306a36Sopenharmony_ci	fusion = instance->ctrl_context;
602762306a36Sopenharmony_ci
602862306a36Sopenharmony_ci	/* Find first memory bar */
602962306a36Sopenharmony_ci	bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM);
603062306a36Sopenharmony_ci	instance->bar = find_first_bit(&bar_list, BITS_PER_LONG);
603162306a36Sopenharmony_ci	if (pci_request_selected_regions(instance->pdev, 1<<instance->bar,
603262306a36Sopenharmony_ci					 "megasas: LSI")) {
603362306a36Sopenharmony_ci		dev_printk(KERN_DEBUG, &instance->pdev->dev, "IO memory region busy!\n");
603462306a36Sopenharmony_ci		return -EBUSY;
603562306a36Sopenharmony_ci	}
603662306a36Sopenharmony_ci
603762306a36Sopenharmony_ci	base_addr = pci_resource_start(instance->pdev, instance->bar);
603862306a36Sopenharmony_ci	instance->reg_set = ioremap(base_addr, 8192);
603962306a36Sopenharmony_ci
604062306a36Sopenharmony_ci	if (!instance->reg_set) {
604162306a36Sopenharmony_ci		dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to map IO mem\n");
604262306a36Sopenharmony_ci		goto fail_ioremap;
604362306a36Sopenharmony_ci	}
604462306a36Sopenharmony_ci
604562306a36Sopenharmony_ci	base_addr_phys = &base_addr;
604662306a36Sopenharmony_ci	dev_printk(KERN_DEBUG, &instance->pdev->dev,
604762306a36Sopenharmony_ci		   "BAR:0x%lx  BAR's base_addr(phys):%pa  mapped virt_addr:0x%p\n",
604862306a36Sopenharmony_ci		   instance->bar, base_addr_phys, instance->reg_set);
604962306a36Sopenharmony_ci
605062306a36Sopenharmony_ci	if (instance->adapter_type != MFI_SERIES)
605162306a36Sopenharmony_ci		instance->instancet = &megasas_instance_template_fusion;
605262306a36Sopenharmony_ci	else {
605362306a36Sopenharmony_ci		switch (instance->pdev->device) {
605462306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_SAS1078R:
605562306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_SAS1078DE:
605662306a36Sopenharmony_ci			instance->instancet = &megasas_instance_template_ppc;
605762306a36Sopenharmony_ci			break;
605862306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_SAS1078GEN2:
605962306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_SAS0079GEN2:
606062306a36Sopenharmony_ci			instance->instancet = &megasas_instance_template_gen2;
606162306a36Sopenharmony_ci			break;
606262306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_SAS0073SKINNY:
606362306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_SAS0071SKINNY:
606462306a36Sopenharmony_ci			instance->instancet = &megasas_instance_template_skinny;
606562306a36Sopenharmony_ci			break;
606662306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_SAS1064R:
606762306a36Sopenharmony_ci		case PCI_DEVICE_ID_DELL_PERC5:
606862306a36Sopenharmony_ci		default:
606962306a36Sopenharmony_ci			instance->instancet = &megasas_instance_template_xscale;
607062306a36Sopenharmony_ci			instance->pd_list_not_supported = 1;
607162306a36Sopenharmony_ci			break;
607262306a36Sopenharmony_ci		}
607362306a36Sopenharmony_ci	}
607462306a36Sopenharmony_ci
607562306a36Sopenharmony_ci	if (megasas_transition_to_ready(instance, 0)) {
607662306a36Sopenharmony_ci		dev_info(&instance->pdev->dev,
607762306a36Sopenharmony_ci			 "Failed to transition controller to ready from %s!\n",
607862306a36Sopenharmony_ci			 __func__);
607962306a36Sopenharmony_ci		if (instance->adapter_type != MFI_SERIES) {
608062306a36Sopenharmony_ci			status_reg = instance->instancet->read_fw_status_reg(
608162306a36Sopenharmony_ci					instance);
608262306a36Sopenharmony_ci			if (status_reg & MFI_RESET_ADAPTER) {
608362306a36Sopenharmony_ci				if (megasas_adp_reset_wait_for_ready
608462306a36Sopenharmony_ci					(instance, true, 0) == FAILED)
608562306a36Sopenharmony_ci					goto fail_ready_state;
608662306a36Sopenharmony_ci			} else {
608762306a36Sopenharmony_ci				goto fail_ready_state;
608862306a36Sopenharmony_ci			}
608962306a36Sopenharmony_ci		} else {
609062306a36Sopenharmony_ci			atomic_set(&instance->fw_reset_no_pci_access, 1);
609162306a36Sopenharmony_ci			instance->instancet->adp_reset
609262306a36Sopenharmony_ci				(instance, instance->reg_set);
609362306a36Sopenharmony_ci			atomic_set(&instance->fw_reset_no_pci_access, 0);
609462306a36Sopenharmony_ci
609562306a36Sopenharmony_ci			/*waiting for about 30 second before retry*/
609662306a36Sopenharmony_ci			ssleep(30);
609762306a36Sopenharmony_ci
609862306a36Sopenharmony_ci			if (megasas_transition_to_ready(instance, 0))
609962306a36Sopenharmony_ci				goto fail_ready_state;
610062306a36Sopenharmony_ci		}
610162306a36Sopenharmony_ci
610262306a36Sopenharmony_ci		dev_info(&instance->pdev->dev,
610362306a36Sopenharmony_ci			 "FW restarted successfully from %s!\n",
610462306a36Sopenharmony_ci			 __func__);
610562306a36Sopenharmony_ci	}
610662306a36Sopenharmony_ci
610762306a36Sopenharmony_ci	megasas_init_ctrl_params(instance);
610862306a36Sopenharmony_ci
610962306a36Sopenharmony_ci	if (megasas_set_dma_mask(instance))
611062306a36Sopenharmony_ci		goto fail_ready_state;
611162306a36Sopenharmony_ci
611262306a36Sopenharmony_ci	if (megasas_alloc_ctrl_mem(instance))
611362306a36Sopenharmony_ci		goto fail_alloc_dma_buf;
611462306a36Sopenharmony_ci
611562306a36Sopenharmony_ci	if (megasas_alloc_ctrl_dma_buffers(instance))
611662306a36Sopenharmony_ci		goto fail_alloc_dma_buf;
611762306a36Sopenharmony_ci
611862306a36Sopenharmony_ci	fusion = instance->ctrl_context;
611962306a36Sopenharmony_ci
612062306a36Sopenharmony_ci	if (instance->adapter_type >= VENTURA_SERIES) {
612162306a36Sopenharmony_ci		scratch_pad_2 =
612262306a36Sopenharmony_ci			megasas_readl(instance,
612362306a36Sopenharmony_ci				      &instance->reg_set->outbound_scratch_pad_2);
612462306a36Sopenharmony_ci		instance->max_raid_mapsize = ((scratch_pad_2 >>
612562306a36Sopenharmony_ci			MR_MAX_RAID_MAP_SIZE_OFFSET_SHIFT) &
612662306a36Sopenharmony_ci			MR_MAX_RAID_MAP_SIZE_MASK);
612762306a36Sopenharmony_ci	}
612862306a36Sopenharmony_ci
612962306a36Sopenharmony_ci	instance->enable_sdev_max_qd = enable_sdev_max_qd;
613062306a36Sopenharmony_ci
613162306a36Sopenharmony_ci	switch (instance->adapter_type) {
613262306a36Sopenharmony_ci	case VENTURA_SERIES:
613362306a36Sopenharmony_ci		fusion->pcie_bw_limitation = true;
613462306a36Sopenharmony_ci		break;
613562306a36Sopenharmony_ci	case AERO_SERIES:
613662306a36Sopenharmony_ci		fusion->r56_div_offload = true;
613762306a36Sopenharmony_ci		break;
613862306a36Sopenharmony_ci	default:
613962306a36Sopenharmony_ci		break;
614062306a36Sopenharmony_ci	}
614162306a36Sopenharmony_ci
614262306a36Sopenharmony_ci	/* Check if MSI-X is supported while in ready state */
614362306a36Sopenharmony_ci	msix_enable = (instance->instancet->read_fw_status_reg(instance) &
614462306a36Sopenharmony_ci		       0x4000000) >> 0x1a;
614562306a36Sopenharmony_ci	if (msix_enable && !msix_disable) {
614662306a36Sopenharmony_ci
614762306a36Sopenharmony_ci		scratch_pad_1 = megasas_readl
614862306a36Sopenharmony_ci			(instance, &instance->reg_set->outbound_scratch_pad_1);
614962306a36Sopenharmony_ci		/* Check max MSI-X vectors */
615062306a36Sopenharmony_ci		if (fusion) {
615162306a36Sopenharmony_ci			if (instance->adapter_type == THUNDERBOLT_SERIES) {
615262306a36Sopenharmony_ci				/* Thunderbolt Series*/
615362306a36Sopenharmony_ci				instance->msix_vectors = (scratch_pad_1
615462306a36Sopenharmony_ci					& MR_MAX_REPLY_QUEUES_OFFSET) + 1;
615562306a36Sopenharmony_ci			} else {
615662306a36Sopenharmony_ci				instance->msix_vectors = ((scratch_pad_1
615762306a36Sopenharmony_ci					& MR_MAX_REPLY_QUEUES_EXT_OFFSET)
615862306a36Sopenharmony_ci					>> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1;
615962306a36Sopenharmony_ci
616062306a36Sopenharmony_ci				/*
616162306a36Sopenharmony_ci				 * For Invader series, > 8 MSI-x vectors
616262306a36Sopenharmony_ci				 * supported by FW/HW implies combined
616362306a36Sopenharmony_ci				 * reply queue mode is enabled.
616462306a36Sopenharmony_ci				 * For Ventura series, > 16 MSI-x vectors
616562306a36Sopenharmony_ci				 * supported by FW/HW implies combined
616662306a36Sopenharmony_ci				 * reply queue mode is enabled.
616762306a36Sopenharmony_ci				 */
616862306a36Sopenharmony_ci				switch (instance->adapter_type) {
616962306a36Sopenharmony_ci				case INVADER_SERIES:
617062306a36Sopenharmony_ci					if (instance->msix_vectors > 8)
617162306a36Sopenharmony_ci						instance->msix_combined = true;
617262306a36Sopenharmony_ci					break;
617362306a36Sopenharmony_ci				case AERO_SERIES:
617462306a36Sopenharmony_ci				case VENTURA_SERIES:
617562306a36Sopenharmony_ci					if (instance->msix_vectors > 16)
617662306a36Sopenharmony_ci						instance->msix_combined = true;
617762306a36Sopenharmony_ci					break;
617862306a36Sopenharmony_ci				}
617962306a36Sopenharmony_ci
618062306a36Sopenharmony_ci				if (rdpq_enable)
618162306a36Sopenharmony_ci					instance->is_rdpq = (scratch_pad_1 & MR_RDPQ_MODE_OFFSET) ?
618262306a36Sopenharmony_ci								1 : 0;
618362306a36Sopenharmony_ci
618462306a36Sopenharmony_ci				if (instance->adapter_type >= INVADER_SERIES &&
618562306a36Sopenharmony_ci				    !instance->msix_combined) {
618662306a36Sopenharmony_ci					instance->msix_load_balance = true;
618762306a36Sopenharmony_ci					instance->smp_affinity_enable = false;
618862306a36Sopenharmony_ci				}
618962306a36Sopenharmony_ci
619062306a36Sopenharmony_ci				/* Save 1-15 reply post index address to local memory
619162306a36Sopenharmony_ci				 * Index 0 is already saved from reg offset
619262306a36Sopenharmony_ci				 * MPI2_REPLY_POST_HOST_INDEX_OFFSET
619362306a36Sopenharmony_ci				 */
619462306a36Sopenharmony_ci				for (loop = 1; loop < MR_MAX_MSIX_REG_ARRAY; loop++) {
619562306a36Sopenharmony_ci					instance->reply_post_host_index_addr[loop] =
619662306a36Sopenharmony_ci						(u32 __iomem *)
619762306a36Sopenharmony_ci						((u8 __iomem *)instance->reg_set +
619862306a36Sopenharmony_ci						MPI2_SUP_REPLY_POST_HOST_INDEX_OFFSET
619962306a36Sopenharmony_ci						+ (loop * 0x10));
620062306a36Sopenharmony_ci				}
620162306a36Sopenharmony_ci			}
620262306a36Sopenharmony_ci
620362306a36Sopenharmony_ci			dev_info(&instance->pdev->dev,
620462306a36Sopenharmony_ci				 "firmware supports msix\t: (%d)",
620562306a36Sopenharmony_ci				 instance->msix_vectors);
620662306a36Sopenharmony_ci			if (msix_vectors)
620762306a36Sopenharmony_ci				instance->msix_vectors = min(msix_vectors,
620862306a36Sopenharmony_ci					instance->msix_vectors);
620962306a36Sopenharmony_ci		} else /* MFI adapters */
621062306a36Sopenharmony_ci			instance->msix_vectors = 1;
621162306a36Sopenharmony_ci
621262306a36Sopenharmony_ci
621362306a36Sopenharmony_ci		/*
621462306a36Sopenharmony_ci		 * For Aero (if some conditions are met), driver will configure a
621562306a36Sopenharmony_ci		 * few additional reply queues with interrupt coalescing enabled.
621662306a36Sopenharmony_ci		 * These queues with interrupt coalescing enabled are called
621762306a36Sopenharmony_ci		 * High IOPS queues and rest of reply queues (based on number of
621862306a36Sopenharmony_ci		 * logical CPUs) are termed as Low latency queues.
621962306a36Sopenharmony_ci		 *
622062306a36Sopenharmony_ci		 * Total Number of reply queues = High IOPS queues + low latency queues
622162306a36Sopenharmony_ci		 *
622262306a36Sopenharmony_ci		 * For rest of fusion adapters, 1 additional reply queue will be
622362306a36Sopenharmony_ci		 * reserved for management commands, rest of reply queues
622462306a36Sopenharmony_ci		 * (based on number of logical CPUs) will be used for IOs and
622562306a36Sopenharmony_ci		 * referenced as IO queues.
622662306a36Sopenharmony_ci		 * Total Number of reply queues = 1 + IO queues
622762306a36Sopenharmony_ci		 *
622862306a36Sopenharmony_ci		 * MFI adapters supports single MSI-x so single reply queue
622962306a36Sopenharmony_ci		 * will be used for IO and management commands.
623062306a36Sopenharmony_ci		 */
623162306a36Sopenharmony_ci
623262306a36Sopenharmony_ci		intr_coalescing = (scratch_pad_1 & MR_INTR_COALESCING_SUPPORT_OFFSET) ?
623362306a36Sopenharmony_ci								true : false;
623462306a36Sopenharmony_ci		if (intr_coalescing &&
623562306a36Sopenharmony_ci			(num_online_cpus() >= MR_HIGH_IOPS_QUEUE_COUNT) &&
623662306a36Sopenharmony_ci			(instance->msix_vectors == MEGASAS_MAX_MSIX_QUEUES))
623762306a36Sopenharmony_ci			instance->perf_mode = MR_BALANCED_PERF_MODE;
623862306a36Sopenharmony_ci		else
623962306a36Sopenharmony_ci			instance->perf_mode = MR_LATENCY_PERF_MODE;
624062306a36Sopenharmony_ci
624162306a36Sopenharmony_ci
624262306a36Sopenharmony_ci		if (instance->adapter_type == AERO_SERIES) {
624362306a36Sopenharmony_ci			pcie_capability_read_word(instance->pdev, PCI_EXP_LNKSTA, &lnksta);
624462306a36Sopenharmony_ci			speed = lnksta & PCI_EXP_LNKSTA_CLS;
624562306a36Sopenharmony_ci
624662306a36Sopenharmony_ci			/*
624762306a36Sopenharmony_ci			 * For Aero, if PCIe link speed is <16 GT/s, then driver should operate
624862306a36Sopenharmony_ci			 * in latency perf mode and enable R1 PCI bandwidth algorithm
624962306a36Sopenharmony_ci			 */
625062306a36Sopenharmony_ci			if (speed < 0x4) {
625162306a36Sopenharmony_ci				instance->perf_mode = MR_LATENCY_PERF_MODE;
625262306a36Sopenharmony_ci				fusion->pcie_bw_limitation = true;
625362306a36Sopenharmony_ci			}
625462306a36Sopenharmony_ci
625562306a36Sopenharmony_ci			/*
625662306a36Sopenharmony_ci			 * Performance mode settings provided through module parameter-perf_mode will
625762306a36Sopenharmony_ci			 * take affect only for:
625862306a36Sopenharmony_ci			 * 1. Aero family of adapters.
625962306a36Sopenharmony_ci			 * 2. When user sets module parameter- perf_mode in range of 0-2.
626062306a36Sopenharmony_ci			 */
626162306a36Sopenharmony_ci			if ((perf_mode >= MR_BALANCED_PERF_MODE) &&
626262306a36Sopenharmony_ci				(perf_mode <= MR_LATENCY_PERF_MODE))
626362306a36Sopenharmony_ci				instance->perf_mode = perf_mode;
626462306a36Sopenharmony_ci			/*
626562306a36Sopenharmony_ci			 * If intr coalescing is not supported by controller FW, then IOPS
626662306a36Sopenharmony_ci			 * and Balanced modes are not feasible.
626762306a36Sopenharmony_ci			 */
626862306a36Sopenharmony_ci			if (!intr_coalescing)
626962306a36Sopenharmony_ci				instance->perf_mode = MR_LATENCY_PERF_MODE;
627062306a36Sopenharmony_ci
627162306a36Sopenharmony_ci		}
627262306a36Sopenharmony_ci
627362306a36Sopenharmony_ci		if (instance->perf_mode == MR_BALANCED_PERF_MODE)
627462306a36Sopenharmony_ci			instance->low_latency_index_start =
627562306a36Sopenharmony_ci				MR_HIGH_IOPS_QUEUE_COUNT;
627662306a36Sopenharmony_ci		else
627762306a36Sopenharmony_ci			instance->low_latency_index_start = 1;
627862306a36Sopenharmony_ci
627962306a36Sopenharmony_ci		num_msix_req = num_online_cpus() + instance->low_latency_index_start;
628062306a36Sopenharmony_ci
628162306a36Sopenharmony_ci		instance->msix_vectors = min(num_msix_req,
628262306a36Sopenharmony_ci				instance->msix_vectors);
628362306a36Sopenharmony_ci
628462306a36Sopenharmony_ci		megasas_alloc_irq_vectors(instance);
628562306a36Sopenharmony_ci		if (!instance->msix_vectors)
628662306a36Sopenharmony_ci			instance->msix_load_balance = false;
628762306a36Sopenharmony_ci	}
628862306a36Sopenharmony_ci	/*
628962306a36Sopenharmony_ci	 * MSI-X host index 0 is common for all adapter.
629062306a36Sopenharmony_ci	 * It is used for all MPT based Adapters.
629162306a36Sopenharmony_ci	 */
629262306a36Sopenharmony_ci	if (instance->msix_combined) {
629362306a36Sopenharmony_ci		instance->reply_post_host_index_addr[0] =
629462306a36Sopenharmony_ci				(u32 *)((u8 *)instance->reg_set +
629562306a36Sopenharmony_ci				MPI2_SUP_REPLY_POST_HOST_INDEX_OFFSET);
629662306a36Sopenharmony_ci	} else {
629762306a36Sopenharmony_ci		instance->reply_post_host_index_addr[0] =
629862306a36Sopenharmony_ci			(u32 *)((u8 *)instance->reg_set +
629962306a36Sopenharmony_ci			MPI2_REPLY_POST_HOST_INDEX_OFFSET);
630062306a36Sopenharmony_ci	}
630162306a36Sopenharmony_ci
630262306a36Sopenharmony_ci	if (!instance->msix_vectors) {
630362306a36Sopenharmony_ci		i = pci_alloc_irq_vectors(instance->pdev, 1, 1, PCI_IRQ_LEGACY);
630462306a36Sopenharmony_ci		if (i < 0)
630562306a36Sopenharmony_ci			goto fail_init_adapter;
630662306a36Sopenharmony_ci	}
630762306a36Sopenharmony_ci
630862306a36Sopenharmony_ci	megasas_setup_reply_map(instance);
630962306a36Sopenharmony_ci
631062306a36Sopenharmony_ci	dev_info(&instance->pdev->dev,
631162306a36Sopenharmony_ci		"current msix/online cpus\t: (%d/%d)\n",
631262306a36Sopenharmony_ci		instance->msix_vectors, (unsigned int)num_online_cpus());
631362306a36Sopenharmony_ci	dev_info(&instance->pdev->dev,
631462306a36Sopenharmony_ci		"RDPQ mode\t: (%s)\n", instance->is_rdpq ? "enabled" : "disabled");
631562306a36Sopenharmony_ci
631662306a36Sopenharmony_ci	tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
631762306a36Sopenharmony_ci		(unsigned long)instance);
631862306a36Sopenharmony_ci
631962306a36Sopenharmony_ci	/*
632062306a36Sopenharmony_ci	 * Below are default value for legacy Firmware.
632162306a36Sopenharmony_ci	 * non-fusion based controllers
632262306a36Sopenharmony_ci	 */
632362306a36Sopenharmony_ci	instance->fw_supported_vd_count = MAX_LOGICAL_DRIVES;
632462306a36Sopenharmony_ci	instance->fw_supported_pd_count = MAX_PHYSICAL_DEVICES;
632562306a36Sopenharmony_ci	/* Get operational params, sge flags, send init cmd to controller */
632662306a36Sopenharmony_ci	if (instance->instancet->init_adapter(instance))
632762306a36Sopenharmony_ci		goto fail_init_adapter;
632862306a36Sopenharmony_ci
632962306a36Sopenharmony_ci	if (instance->adapter_type >= VENTURA_SERIES) {
633062306a36Sopenharmony_ci		scratch_pad_3 =
633162306a36Sopenharmony_ci			megasas_readl(instance,
633262306a36Sopenharmony_ci				      &instance->reg_set->outbound_scratch_pad_3);
633362306a36Sopenharmony_ci		if ((scratch_pad_3 & MR_NVME_PAGE_SIZE_MASK) >=
633462306a36Sopenharmony_ci			MR_DEFAULT_NVME_PAGE_SHIFT)
633562306a36Sopenharmony_ci			instance->nvme_page_size =
633662306a36Sopenharmony_ci				(1 << (scratch_pad_3 & MR_NVME_PAGE_SIZE_MASK));
633762306a36Sopenharmony_ci
633862306a36Sopenharmony_ci		dev_info(&instance->pdev->dev,
633962306a36Sopenharmony_ci			 "NVME page size\t: (%d)\n", instance->nvme_page_size);
634062306a36Sopenharmony_ci	}
634162306a36Sopenharmony_ci
634262306a36Sopenharmony_ci	if (instance->msix_vectors ?
634362306a36Sopenharmony_ci		megasas_setup_irqs_msix(instance, 1) :
634462306a36Sopenharmony_ci		megasas_setup_irqs_ioapic(instance))
634562306a36Sopenharmony_ci		goto fail_init_adapter;
634662306a36Sopenharmony_ci
634762306a36Sopenharmony_ci	if (instance->adapter_type != MFI_SERIES)
634862306a36Sopenharmony_ci		megasas_setup_irq_poll(instance);
634962306a36Sopenharmony_ci
635062306a36Sopenharmony_ci	instance->instancet->enable_intr(instance);
635162306a36Sopenharmony_ci
635262306a36Sopenharmony_ci	dev_info(&instance->pdev->dev, "INIT adapter done\n");
635362306a36Sopenharmony_ci
635462306a36Sopenharmony_ci	megasas_setup_jbod_map(instance);
635562306a36Sopenharmony_ci
635662306a36Sopenharmony_ci	if (megasas_get_device_list(instance) != SUCCESS) {
635762306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
635862306a36Sopenharmony_ci			"%s: megasas_get_device_list failed\n",
635962306a36Sopenharmony_ci			__func__);
636062306a36Sopenharmony_ci		goto fail_get_ld_pd_list;
636162306a36Sopenharmony_ci	}
636262306a36Sopenharmony_ci
636362306a36Sopenharmony_ci	/* stream detection initialization */
636462306a36Sopenharmony_ci	if (instance->adapter_type >= VENTURA_SERIES) {
636562306a36Sopenharmony_ci		fusion->stream_detect_by_ld =
636662306a36Sopenharmony_ci			kcalloc(MAX_LOGICAL_DRIVES_EXT,
636762306a36Sopenharmony_ci				sizeof(struct LD_STREAM_DETECT *),
636862306a36Sopenharmony_ci				GFP_KERNEL);
636962306a36Sopenharmony_ci		if (!fusion->stream_detect_by_ld) {
637062306a36Sopenharmony_ci			dev_err(&instance->pdev->dev,
637162306a36Sopenharmony_ci				"unable to allocate stream detection for pool of LDs\n");
637262306a36Sopenharmony_ci			goto fail_get_ld_pd_list;
637362306a36Sopenharmony_ci		}
637462306a36Sopenharmony_ci		for (i = 0; i < MAX_LOGICAL_DRIVES_EXT; ++i) {
637562306a36Sopenharmony_ci			fusion->stream_detect_by_ld[i] =
637662306a36Sopenharmony_ci				kzalloc(sizeof(struct LD_STREAM_DETECT),
637762306a36Sopenharmony_ci				GFP_KERNEL);
637862306a36Sopenharmony_ci			if (!fusion->stream_detect_by_ld[i]) {
637962306a36Sopenharmony_ci				dev_err(&instance->pdev->dev,
638062306a36Sopenharmony_ci					"unable to allocate stream detect by LD\n ");
638162306a36Sopenharmony_ci				for (j = 0; j < i; ++j)
638262306a36Sopenharmony_ci					kfree(fusion->stream_detect_by_ld[j]);
638362306a36Sopenharmony_ci				kfree(fusion->stream_detect_by_ld);
638462306a36Sopenharmony_ci				fusion->stream_detect_by_ld = NULL;
638562306a36Sopenharmony_ci				goto fail_get_ld_pd_list;
638662306a36Sopenharmony_ci			}
638762306a36Sopenharmony_ci			fusion->stream_detect_by_ld[i]->mru_bit_map
638862306a36Sopenharmony_ci				= MR_STREAM_BITMAP;
638962306a36Sopenharmony_ci		}
639062306a36Sopenharmony_ci	}
639162306a36Sopenharmony_ci
639262306a36Sopenharmony_ci	/*
639362306a36Sopenharmony_ci	 * Compute the max allowed sectors per IO: The controller info has two
639462306a36Sopenharmony_ci	 * limits on max sectors. Driver should use the minimum of these two.
639562306a36Sopenharmony_ci	 *
639662306a36Sopenharmony_ci	 * 1 << stripe_sz_ops.min = max sectors per strip
639762306a36Sopenharmony_ci	 *
639862306a36Sopenharmony_ci	 * Note that older firmwares ( < FW ver 30) didn't report information
639962306a36Sopenharmony_ci	 * to calculate max_sectors_1. So the number ended up as zero always.
640062306a36Sopenharmony_ci	 */
640162306a36Sopenharmony_ci	tmp_sectors = 0;
640262306a36Sopenharmony_ci	ctrl_info = instance->ctrl_info_buf;
640362306a36Sopenharmony_ci
640462306a36Sopenharmony_ci	max_sectors_1 = (1 << ctrl_info->stripe_sz_ops.min) *
640562306a36Sopenharmony_ci		le16_to_cpu(ctrl_info->max_strips_per_io);
640662306a36Sopenharmony_ci	max_sectors_2 = le32_to_cpu(ctrl_info->max_request_size);
640762306a36Sopenharmony_ci
640862306a36Sopenharmony_ci	tmp_sectors = min_t(u32, max_sectors_1, max_sectors_2);
640962306a36Sopenharmony_ci
641062306a36Sopenharmony_ci	instance->peerIsPresent = ctrl_info->cluster.peerIsPresent;
641162306a36Sopenharmony_ci	instance->passive = ctrl_info->cluster.passive;
641262306a36Sopenharmony_ci	memcpy(instance->clusterId, ctrl_info->clusterId, sizeof(instance->clusterId));
641362306a36Sopenharmony_ci	instance->UnevenSpanSupport =
641462306a36Sopenharmony_ci		ctrl_info->adapterOperations2.supportUnevenSpans;
641562306a36Sopenharmony_ci	if (instance->UnevenSpanSupport) {
641662306a36Sopenharmony_ci		struct fusion_context *fusion = instance->ctrl_context;
641762306a36Sopenharmony_ci		if (MR_ValidateMapInfo(instance, instance->map_id))
641862306a36Sopenharmony_ci			fusion->fast_path_io = 1;
641962306a36Sopenharmony_ci		else
642062306a36Sopenharmony_ci			fusion->fast_path_io = 0;
642162306a36Sopenharmony_ci
642262306a36Sopenharmony_ci	}
642362306a36Sopenharmony_ci	if (ctrl_info->host_interface.SRIOV) {
642462306a36Sopenharmony_ci		instance->requestorId = ctrl_info->iov.requestorId;
642562306a36Sopenharmony_ci		if (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) {
642662306a36Sopenharmony_ci			if (!ctrl_info->adapterOperations2.activePassive)
642762306a36Sopenharmony_ci			    instance->PlasmaFW111 = 1;
642862306a36Sopenharmony_ci
642962306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "SR-IOV: firmware type: %s\n",
643062306a36Sopenharmony_ci			    instance->PlasmaFW111 ? "1.11" : "new");
643162306a36Sopenharmony_ci
643262306a36Sopenharmony_ci			if (instance->PlasmaFW111) {
643362306a36Sopenharmony_ci			    iovPtr = (struct IOV_111 *)
643462306a36Sopenharmony_ci				((unsigned char *)ctrl_info + IOV_111_OFFSET);
643562306a36Sopenharmony_ci			    instance->requestorId = iovPtr->requestorId;
643662306a36Sopenharmony_ci			}
643762306a36Sopenharmony_ci		}
643862306a36Sopenharmony_ci		dev_info(&instance->pdev->dev, "SRIOV: VF requestorId %d\n",
643962306a36Sopenharmony_ci			instance->requestorId);
644062306a36Sopenharmony_ci	}
644162306a36Sopenharmony_ci
644262306a36Sopenharmony_ci	instance->crash_dump_fw_support =
644362306a36Sopenharmony_ci		ctrl_info->adapterOperations3.supportCrashDump;
644462306a36Sopenharmony_ci	instance->crash_dump_drv_support =
644562306a36Sopenharmony_ci		(instance->crash_dump_fw_support &&
644662306a36Sopenharmony_ci		instance->crash_dump_buf);
644762306a36Sopenharmony_ci	if (instance->crash_dump_drv_support)
644862306a36Sopenharmony_ci		megasas_set_crash_dump_params(instance,
644962306a36Sopenharmony_ci			MR_CRASH_BUF_TURN_OFF);
645062306a36Sopenharmony_ci
645162306a36Sopenharmony_ci	else {
645262306a36Sopenharmony_ci		if (instance->crash_dump_buf)
645362306a36Sopenharmony_ci			dma_free_coherent(&instance->pdev->dev,
645462306a36Sopenharmony_ci				CRASH_DMA_BUF_SIZE,
645562306a36Sopenharmony_ci				instance->crash_dump_buf,
645662306a36Sopenharmony_ci				instance->crash_dump_h);
645762306a36Sopenharmony_ci		instance->crash_dump_buf = NULL;
645862306a36Sopenharmony_ci	}
645962306a36Sopenharmony_ci
646062306a36Sopenharmony_ci	if (instance->snapdump_wait_time) {
646162306a36Sopenharmony_ci		megasas_get_snapdump_properties(instance);
646262306a36Sopenharmony_ci		dev_info(&instance->pdev->dev, "Snap dump wait time\t: %d\n",
646362306a36Sopenharmony_ci			 instance->snapdump_wait_time);
646462306a36Sopenharmony_ci	}
646562306a36Sopenharmony_ci
646662306a36Sopenharmony_ci	dev_info(&instance->pdev->dev,
646762306a36Sopenharmony_ci		"pci id\t\t: (0x%04x)/(0x%04x)/(0x%04x)/(0x%04x)\n",
646862306a36Sopenharmony_ci		le16_to_cpu(ctrl_info->pci.vendor_id),
646962306a36Sopenharmony_ci		le16_to_cpu(ctrl_info->pci.device_id),
647062306a36Sopenharmony_ci		le16_to_cpu(ctrl_info->pci.sub_vendor_id),
647162306a36Sopenharmony_ci		le16_to_cpu(ctrl_info->pci.sub_device_id));
647262306a36Sopenharmony_ci	dev_info(&instance->pdev->dev, "unevenspan support	: %s\n",
647362306a36Sopenharmony_ci		instance->UnevenSpanSupport ? "yes" : "no");
647462306a36Sopenharmony_ci	dev_info(&instance->pdev->dev, "firmware crash dump	: %s\n",
647562306a36Sopenharmony_ci		instance->crash_dump_drv_support ? "yes" : "no");
647662306a36Sopenharmony_ci	dev_info(&instance->pdev->dev, "JBOD sequence map	: %s\n",
647762306a36Sopenharmony_ci		instance->use_seqnum_jbod_fp ? "enabled" : "disabled");
647862306a36Sopenharmony_ci
647962306a36Sopenharmony_ci	instance->max_sectors_per_req = instance->max_num_sge *
648062306a36Sopenharmony_ci						SGE_BUFFER_SIZE / 512;
648162306a36Sopenharmony_ci	if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors))
648262306a36Sopenharmony_ci		instance->max_sectors_per_req = tmp_sectors;
648362306a36Sopenharmony_ci
648462306a36Sopenharmony_ci	/* Check for valid throttlequeuedepth module parameter */
648562306a36Sopenharmony_ci	if (throttlequeuedepth &&
648662306a36Sopenharmony_ci			throttlequeuedepth <= instance->max_scsi_cmds)
648762306a36Sopenharmony_ci		instance->throttlequeuedepth = throttlequeuedepth;
648862306a36Sopenharmony_ci	else
648962306a36Sopenharmony_ci		instance->throttlequeuedepth =
649062306a36Sopenharmony_ci				MEGASAS_THROTTLE_QUEUE_DEPTH;
649162306a36Sopenharmony_ci
649262306a36Sopenharmony_ci	if ((resetwaittime < 1) ||
649362306a36Sopenharmony_ci	    (resetwaittime > MEGASAS_RESET_WAIT_TIME))
649462306a36Sopenharmony_ci		resetwaittime = MEGASAS_RESET_WAIT_TIME;
649562306a36Sopenharmony_ci
649662306a36Sopenharmony_ci	if ((scmd_timeout < 10) || (scmd_timeout > MEGASAS_DEFAULT_CMD_TIMEOUT))
649762306a36Sopenharmony_ci		scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT;
649862306a36Sopenharmony_ci
649962306a36Sopenharmony_ci	/* Launch SR-IOV heartbeat timer */
650062306a36Sopenharmony_ci	if (instance->requestorId) {
650162306a36Sopenharmony_ci		if (!megasas_sriov_start_heartbeat(instance, 1)) {
650262306a36Sopenharmony_ci			megasas_start_timer(instance);
650362306a36Sopenharmony_ci		} else {
650462306a36Sopenharmony_ci			instance->skip_heartbeat_timer_del = 1;
650562306a36Sopenharmony_ci			goto fail_get_ld_pd_list;
650662306a36Sopenharmony_ci		}
650762306a36Sopenharmony_ci	}
650862306a36Sopenharmony_ci
650962306a36Sopenharmony_ci	/*
651062306a36Sopenharmony_ci	 * Create and start watchdog thread which will monitor
651162306a36Sopenharmony_ci	 * controller state every 1 sec and trigger OCR when
651262306a36Sopenharmony_ci	 * it enters fault state
651362306a36Sopenharmony_ci	 */
651462306a36Sopenharmony_ci	if (instance->adapter_type != MFI_SERIES)
651562306a36Sopenharmony_ci		if (megasas_fusion_start_watchdog(instance) != SUCCESS)
651662306a36Sopenharmony_ci			goto fail_start_watchdog;
651762306a36Sopenharmony_ci
651862306a36Sopenharmony_ci	return 0;
651962306a36Sopenharmony_ci
652062306a36Sopenharmony_cifail_start_watchdog:
652162306a36Sopenharmony_ci	if (instance->requestorId && !instance->skip_heartbeat_timer_del)
652262306a36Sopenharmony_ci		del_timer_sync(&instance->sriov_heartbeat_timer);
652362306a36Sopenharmony_cifail_get_ld_pd_list:
652462306a36Sopenharmony_ci	instance->instancet->disable_intr(instance);
652562306a36Sopenharmony_ci	megasas_destroy_irqs(instance);
652662306a36Sopenharmony_cifail_init_adapter:
652762306a36Sopenharmony_ci	if (instance->msix_vectors)
652862306a36Sopenharmony_ci		pci_free_irq_vectors(instance->pdev);
652962306a36Sopenharmony_ci	instance->msix_vectors = 0;
653062306a36Sopenharmony_cifail_alloc_dma_buf:
653162306a36Sopenharmony_ci	megasas_free_ctrl_dma_buffers(instance);
653262306a36Sopenharmony_ci	megasas_free_ctrl_mem(instance);
653362306a36Sopenharmony_cifail_ready_state:
653462306a36Sopenharmony_ci	iounmap(instance->reg_set);
653562306a36Sopenharmony_ci
653662306a36Sopenharmony_cifail_ioremap:
653762306a36Sopenharmony_ci	pci_release_selected_regions(instance->pdev, 1<<instance->bar);
653862306a36Sopenharmony_ci
653962306a36Sopenharmony_ci	dev_err(&instance->pdev->dev, "Failed from %s %d\n",
654062306a36Sopenharmony_ci		__func__, __LINE__);
654162306a36Sopenharmony_ci	return -EINVAL;
654262306a36Sopenharmony_ci}
654362306a36Sopenharmony_ci
654462306a36Sopenharmony_ci/**
654562306a36Sopenharmony_ci * megasas_release_mfi -	Reverses the FW initialization
654662306a36Sopenharmony_ci * @instance:			Adapter soft state
654762306a36Sopenharmony_ci */
654862306a36Sopenharmony_cistatic void megasas_release_mfi(struct megasas_instance *instance)
654962306a36Sopenharmony_ci{
655062306a36Sopenharmony_ci	u32 reply_q_sz = sizeof(u32) *(instance->max_mfi_cmds + 1);
655162306a36Sopenharmony_ci
655262306a36Sopenharmony_ci	if (instance->reply_queue)
655362306a36Sopenharmony_ci		dma_free_coherent(&instance->pdev->dev, reply_q_sz,
655462306a36Sopenharmony_ci			    instance->reply_queue, instance->reply_queue_h);
655562306a36Sopenharmony_ci
655662306a36Sopenharmony_ci	megasas_free_cmds(instance);
655762306a36Sopenharmony_ci
655862306a36Sopenharmony_ci	iounmap(instance->reg_set);
655962306a36Sopenharmony_ci
656062306a36Sopenharmony_ci	pci_release_selected_regions(instance->pdev, 1<<instance->bar);
656162306a36Sopenharmony_ci}
656262306a36Sopenharmony_ci
656362306a36Sopenharmony_ci/**
656462306a36Sopenharmony_ci * megasas_get_seq_num -	Gets latest event sequence numbers
656562306a36Sopenharmony_ci * @instance:			Adapter soft state
656662306a36Sopenharmony_ci * @eli:			FW event log sequence numbers information
656762306a36Sopenharmony_ci *
656862306a36Sopenharmony_ci * FW maintains a log of all events in a non-volatile area. Upper layers would
656962306a36Sopenharmony_ci * usually find out the latest sequence number of the events, the seq number at
657062306a36Sopenharmony_ci * the boot etc. They would "read" all the events below the latest seq number
657162306a36Sopenharmony_ci * by issuing a direct fw cmd (DCMD). For the future events (beyond latest seq
657262306a36Sopenharmony_ci * number), they would subsribe to AEN (asynchronous event notification) and
657362306a36Sopenharmony_ci * wait for the events to happen.
657462306a36Sopenharmony_ci */
657562306a36Sopenharmony_cistatic int
657662306a36Sopenharmony_cimegasas_get_seq_num(struct megasas_instance *instance,
657762306a36Sopenharmony_ci		    struct megasas_evt_log_info *eli)
657862306a36Sopenharmony_ci{
657962306a36Sopenharmony_ci	struct megasas_cmd *cmd;
658062306a36Sopenharmony_ci	struct megasas_dcmd_frame *dcmd;
658162306a36Sopenharmony_ci	struct megasas_evt_log_info *el_info;
658262306a36Sopenharmony_ci	dma_addr_t el_info_h = 0;
658362306a36Sopenharmony_ci	int ret;
658462306a36Sopenharmony_ci
658562306a36Sopenharmony_ci	cmd = megasas_get_cmd(instance);
658662306a36Sopenharmony_ci
658762306a36Sopenharmony_ci	if (!cmd) {
658862306a36Sopenharmony_ci		return -ENOMEM;
658962306a36Sopenharmony_ci	}
659062306a36Sopenharmony_ci
659162306a36Sopenharmony_ci	dcmd = &cmd->frame->dcmd;
659262306a36Sopenharmony_ci	el_info = dma_alloc_coherent(&instance->pdev->dev,
659362306a36Sopenharmony_ci				     sizeof(struct megasas_evt_log_info),
659462306a36Sopenharmony_ci				     &el_info_h, GFP_KERNEL);
659562306a36Sopenharmony_ci	if (!el_info) {
659662306a36Sopenharmony_ci		megasas_return_cmd(instance, cmd);
659762306a36Sopenharmony_ci		return -ENOMEM;
659862306a36Sopenharmony_ci	}
659962306a36Sopenharmony_ci
660062306a36Sopenharmony_ci	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
660162306a36Sopenharmony_ci
660262306a36Sopenharmony_ci	dcmd->cmd = MFI_CMD_DCMD;
660362306a36Sopenharmony_ci	dcmd->cmd_status = 0x0;
660462306a36Sopenharmony_ci	dcmd->sge_count = 1;
660562306a36Sopenharmony_ci	dcmd->flags = MFI_FRAME_DIR_READ;
660662306a36Sopenharmony_ci	dcmd->timeout = 0;
660762306a36Sopenharmony_ci	dcmd->pad_0 = 0;
660862306a36Sopenharmony_ci	dcmd->data_xfer_len = cpu_to_le32(sizeof(struct megasas_evt_log_info));
660962306a36Sopenharmony_ci	dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_EVENT_GET_INFO);
661062306a36Sopenharmony_ci
661162306a36Sopenharmony_ci	megasas_set_dma_settings(instance, dcmd, el_info_h,
661262306a36Sopenharmony_ci				 sizeof(struct megasas_evt_log_info));
661362306a36Sopenharmony_ci
661462306a36Sopenharmony_ci	ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
661562306a36Sopenharmony_ci	if (ret != DCMD_SUCCESS) {
661662306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
661762306a36Sopenharmony_ci			__func__, __LINE__);
661862306a36Sopenharmony_ci		goto dcmd_failed;
661962306a36Sopenharmony_ci	}
662062306a36Sopenharmony_ci
662162306a36Sopenharmony_ci	/*
662262306a36Sopenharmony_ci	 * Copy the data back into callers buffer
662362306a36Sopenharmony_ci	 */
662462306a36Sopenharmony_ci	eli->newest_seq_num = el_info->newest_seq_num;
662562306a36Sopenharmony_ci	eli->oldest_seq_num = el_info->oldest_seq_num;
662662306a36Sopenharmony_ci	eli->clear_seq_num = el_info->clear_seq_num;
662762306a36Sopenharmony_ci	eli->shutdown_seq_num = el_info->shutdown_seq_num;
662862306a36Sopenharmony_ci	eli->boot_seq_num = el_info->boot_seq_num;
662962306a36Sopenharmony_ci
663062306a36Sopenharmony_cidcmd_failed:
663162306a36Sopenharmony_ci	dma_free_coherent(&instance->pdev->dev,
663262306a36Sopenharmony_ci			sizeof(struct megasas_evt_log_info),
663362306a36Sopenharmony_ci			el_info, el_info_h);
663462306a36Sopenharmony_ci
663562306a36Sopenharmony_ci	megasas_return_cmd(instance, cmd);
663662306a36Sopenharmony_ci
663762306a36Sopenharmony_ci	return ret;
663862306a36Sopenharmony_ci}
663962306a36Sopenharmony_ci
664062306a36Sopenharmony_ci/**
664162306a36Sopenharmony_ci * megasas_register_aen -	Registers for asynchronous event notification
664262306a36Sopenharmony_ci * @instance:			Adapter soft state
664362306a36Sopenharmony_ci * @seq_num:			The starting sequence number
664462306a36Sopenharmony_ci * @class_locale_word:		Class of the event
664562306a36Sopenharmony_ci *
664662306a36Sopenharmony_ci * This function subscribes for AEN for events beyond the @seq_num. It requests
664762306a36Sopenharmony_ci * to be notified if and only if the event is of type @class_locale
664862306a36Sopenharmony_ci */
664962306a36Sopenharmony_cistatic int
665062306a36Sopenharmony_cimegasas_register_aen(struct megasas_instance *instance, u32 seq_num,
665162306a36Sopenharmony_ci		     u32 class_locale_word)
665262306a36Sopenharmony_ci{
665362306a36Sopenharmony_ci	int ret_val;
665462306a36Sopenharmony_ci	struct megasas_cmd *cmd;
665562306a36Sopenharmony_ci	struct megasas_dcmd_frame *dcmd;
665662306a36Sopenharmony_ci	union megasas_evt_class_locale curr_aen;
665762306a36Sopenharmony_ci	union megasas_evt_class_locale prev_aen;
665862306a36Sopenharmony_ci
665962306a36Sopenharmony_ci	/*
666062306a36Sopenharmony_ci	 * If there an AEN pending already (aen_cmd), check if the
666162306a36Sopenharmony_ci	 * class_locale of that pending AEN is inclusive of the new
666262306a36Sopenharmony_ci	 * AEN request we currently have. If it is, then we don't have
666362306a36Sopenharmony_ci	 * to do anything. In other words, whichever events the current
666462306a36Sopenharmony_ci	 * AEN request is subscribing to, have already been subscribed
666562306a36Sopenharmony_ci	 * to.
666662306a36Sopenharmony_ci	 *
666762306a36Sopenharmony_ci	 * If the old_cmd is _not_ inclusive, then we have to abort
666862306a36Sopenharmony_ci	 * that command, form a class_locale that is superset of both
666962306a36Sopenharmony_ci	 * old and current and re-issue to the FW
667062306a36Sopenharmony_ci	 */
667162306a36Sopenharmony_ci
667262306a36Sopenharmony_ci	curr_aen.word = class_locale_word;
667362306a36Sopenharmony_ci
667462306a36Sopenharmony_ci	if (instance->aen_cmd) {
667562306a36Sopenharmony_ci
667662306a36Sopenharmony_ci		prev_aen.word =
667762306a36Sopenharmony_ci			le32_to_cpu(instance->aen_cmd->frame->dcmd.mbox.w[1]);
667862306a36Sopenharmony_ci
667962306a36Sopenharmony_ci		if ((curr_aen.members.class < MFI_EVT_CLASS_DEBUG) ||
668062306a36Sopenharmony_ci		    (curr_aen.members.class > MFI_EVT_CLASS_DEAD)) {
668162306a36Sopenharmony_ci			dev_info(&instance->pdev->dev,
668262306a36Sopenharmony_ci				 "%s %d out of range class %d send by application\n",
668362306a36Sopenharmony_ci				 __func__, __LINE__, curr_aen.members.class);
668462306a36Sopenharmony_ci			return 0;
668562306a36Sopenharmony_ci		}
668662306a36Sopenharmony_ci
668762306a36Sopenharmony_ci		/*
668862306a36Sopenharmony_ci		 * A class whose enum value is smaller is inclusive of all
668962306a36Sopenharmony_ci		 * higher values. If a PROGRESS (= -1) was previously
669062306a36Sopenharmony_ci		 * registered, then a new registration requests for higher
669162306a36Sopenharmony_ci		 * classes need not be sent to FW. They are automatically
669262306a36Sopenharmony_ci		 * included.
669362306a36Sopenharmony_ci		 *
669462306a36Sopenharmony_ci		 * Locale numbers don't have such hierarchy. They are bitmap
669562306a36Sopenharmony_ci		 * values
669662306a36Sopenharmony_ci		 */
669762306a36Sopenharmony_ci		if ((prev_aen.members.class <= curr_aen.members.class) &&
669862306a36Sopenharmony_ci		    !((prev_aen.members.locale & curr_aen.members.locale) ^
669962306a36Sopenharmony_ci		      curr_aen.members.locale)) {
670062306a36Sopenharmony_ci			/*
670162306a36Sopenharmony_ci			 * Previously issued event registration includes
670262306a36Sopenharmony_ci			 * current request. Nothing to do.
670362306a36Sopenharmony_ci			 */
670462306a36Sopenharmony_ci			return 0;
670562306a36Sopenharmony_ci		} else {
670662306a36Sopenharmony_ci			curr_aen.members.locale |= prev_aen.members.locale;
670762306a36Sopenharmony_ci
670862306a36Sopenharmony_ci			if (prev_aen.members.class < curr_aen.members.class)
670962306a36Sopenharmony_ci				curr_aen.members.class = prev_aen.members.class;
671062306a36Sopenharmony_ci
671162306a36Sopenharmony_ci			instance->aen_cmd->abort_aen = 1;
671262306a36Sopenharmony_ci			ret_val = megasas_issue_blocked_abort_cmd(instance,
671362306a36Sopenharmony_ci								  instance->
671462306a36Sopenharmony_ci								  aen_cmd, 30);
671562306a36Sopenharmony_ci
671662306a36Sopenharmony_ci			if (ret_val) {
671762306a36Sopenharmony_ci				dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to abort "
671862306a36Sopenharmony_ci				       "previous AEN command\n");
671962306a36Sopenharmony_ci				return ret_val;
672062306a36Sopenharmony_ci			}
672162306a36Sopenharmony_ci		}
672262306a36Sopenharmony_ci	}
672362306a36Sopenharmony_ci
672462306a36Sopenharmony_ci	cmd = megasas_get_cmd(instance);
672562306a36Sopenharmony_ci
672662306a36Sopenharmony_ci	if (!cmd)
672762306a36Sopenharmony_ci		return -ENOMEM;
672862306a36Sopenharmony_ci
672962306a36Sopenharmony_ci	dcmd = &cmd->frame->dcmd;
673062306a36Sopenharmony_ci
673162306a36Sopenharmony_ci	memset(instance->evt_detail, 0, sizeof(struct megasas_evt_detail));
673262306a36Sopenharmony_ci
673362306a36Sopenharmony_ci	/*
673462306a36Sopenharmony_ci	 * Prepare DCMD for aen registration
673562306a36Sopenharmony_ci	 */
673662306a36Sopenharmony_ci	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
673762306a36Sopenharmony_ci
673862306a36Sopenharmony_ci	dcmd->cmd = MFI_CMD_DCMD;
673962306a36Sopenharmony_ci	dcmd->cmd_status = 0x0;
674062306a36Sopenharmony_ci	dcmd->sge_count = 1;
674162306a36Sopenharmony_ci	dcmd->flags = MFI_FRAME_DIR_READ;
674262306a36Sopenharmony_ci	dcmd->timeout = 0;
674362306a36Sopenharmony_ci	dcmd->pad_0 = 0;
674462306a36Sopenharmony_ci	dcmd->data_xfer_len = cpu_to_le32(sizeof(struct megasas_evt_detail));
674562306a36Sopenharmony_ci	dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_EVENT_WAIT);
674662306a36Sopenharmony_ci	dcmd->mbox.w[0] = cpu_to_le32(seq_num);
674762306a36Sopenharmony_ci	instance->last_seq_num = seq_num;
674862306a36Sopenharmony_ci	dcmd->mbox.w[1] = cpu_to_le32(curr_aen.word);
674962306a36Sopenharmony_ci
675062306a36Sopenharmony_ci	megasas_set_dma_settings(instance, dcmd, instance->evt_detail_h,
675162306a36Sopenharmony_ci				 sizeof(struct megasas_evt_detail));
675262306a36Sopenharmony_ci
675362306a36Sopenharmony_ci	if (instance->aen_cmd != NULL) {
675462306a36Sopenharmony_ci		megasas_return_cmd(instance, cmd);
675562306a36Sopenharmony_ci		return 0;
675662306a36Sopenharmony_ci	}
675762306a36Sopenharmony_ci
675862306a36Sopenharmony_ci	/*
675962306a36Sopenharmony_ci	 * Store reference to the cmd used to register for AEN. When an
676062306a36Sopenharmony_ci	 * application wants us to register for AEN, we have to abort this
676162306a36Sopenharmony_ci	 * cmd and re-register with a new EVENT LOCALE supplied by that app
676262306a36Sopenharmony_ci	 */
676362306a36Sopenharmony_ci	instance->aen_cmd = cmd;
676462306a36Sopenharmony_ci
676562306a36Sopenharmony_ci	/*
676662306a36Sopenharmony_ci	 * Issue the aen registration frame
676762306a36Sopenharmony_ci	 */
676862306a36Sopenharmony_ci	instance->instancet->issue_dcmd(instance, cmd);
676962306a36Sopenharmony_ci
677062306a36Sopenharmony_ci	return 0;
677162306a36Sopenharmony_ci}
677262306a36Sopenharmony_ci
677362306a36Sopenharmony_ci/* megasas_get_target_prop - Send DCMD with below details to firmware.
677462306a36Sopenharmony_ci *
677562306a36Sopenharmony_ci * This DCMD will fetch few properties of LD/system PD defined
677662306a36Sopenharmony_ci * in MR_TARGET_DEV_PROPERTIES. eg. Queue Depth, MDTS value.
677762306a36Sopenharmony_ci *
677862306a36Sopenharmony_ci * DCMD send by drivers whenever new target is added to the OS.
677962306a36Sopenharmony_ci *
678062306a36Sopenharmony_ci * dcmd.opcode         - MR_DCMD_DEV_GET_TARGET_PROP
678162306a36Sopenharmony_ci * dcmd.mbox.b[0]      - DCMD is to be fired for LD or system PD.
678262306a36Sopenharmony_ci *                       0 = system PD, 1 = LD.
678362306a36Sopenharmony_ci * dcmd.mbox.s[1]      - TargetID for LD/system PD.
678462306a36Sopenharmony_ci * dcmd.sge IN         - Pointer to return MR_TARGET_DEV_PROPERTIES.
678562306a36Sopenharmony_ci *
678662306a36Sopenharmony_ci * @instance:		Adapter soft state
678762306a36Sopenharmony_ci * @sdev:		OS provided scsi device
678862306a36Sopenharmony_ci *
678962306a36Sopenharmony_ci * Returns 0 on success non-zero on failure.
679062306a36Sopenharmony_ci */
679162306a36Sopenharmony_ciint
679262306a36Sopenharmony_cimegasas_get_target_prop(struct megasas_instance *instance,
679362306a36Sopenharmony_ci			struct scsi_device *sdev)
679462306a36Sopenharmony_ci{
679562306a36Sopenharmony_ci	int ret;
679662306a36Sopenharmony_ci	struct megasas_cmd *cmd;
679762306a36Sopenharmony_ci	struct megasas_dcmd_frame *dcmd;
679862306a36Sopenharmony_ci	u16 targetId = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) +
679962306a36Sopenharmony_ci			sdev->id;
680062306a36Sopenharmony_ci
680162306a36Sopenharmony_ci	cmd = megasas_get_cmd(instance);
680262306a36Sopenharmony_ci
680362306a36Sopenharmony_ci	if (!cmd) {
680462306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
680562306a36Sopenharmony_ci			"Failed to get cmd %s\n", __func__);
680662306a36Sopenharmony_ci		return -ENOMEM;
680762306a36Sopenharmony_ci	}
680862306a36Sopenharmony_ci
680962306a36Sopenharmony_ci	dcmd = &cmd->frame->dcmd;
681062306a36Sopenharmony_ci
681162306a36Sopenharmony_ci	memset(instance->tgt_prop, 0, sizeof(*instance->tgt_prop));
681262306a36Sopenharmony_ci	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
681362306a36Sopenharmony_ci	dcmd->mbox.b[0] = MEGASAS_IS_LOGICAL(sdev);
681462306a36Sopenharmony_ci
681562306a36Sopenharmony_ci	dcmd->mbox.s[1] = cpu_to_le16(targetId);
681662306a36Sopenharmony_ci	dcmd->cmd = MFI_CMD_DCMD;
681762306a36Sopenharmony_ci	dcmd->cmd_status = 0xFF;
681862306a36Sopenharmony_ci	dcmd->sge_count = 1;
681962306a36Sopenharmony_ci	dcmd->flags = MFI_FRAME_DIR_READ;
682062306a36Sopenharmony_ci	dcmd->timeout = 0;
682162306a36Sopenharmony_ci	dcmd->pad_0 = 0;
682262306a36Sopenharmony_ci	dcmd->data_xfer_len =
682362306a36Sopenharmony_ci		cpu_to_le32(sizeof(struct MR_TARGET_PROPERTIES));
682462306a36Sopenharmony_ci	dcmd->opcode = cpu_to_le32(MR_DCMD_DRV_GET_TARGET_PROP);
682562306a36Sopenharmony_ci
682662306a36Sopenharmony_ci	megasas_set_dma_settings(instance, dcmd, instance->tgt_prop_h,
682762306a36Sopenharmony_ci				 sizeof(struct MR_TARGET_PROPERTIES));
682862306a36Sopenharmony_ci
682962306a36Sopenharmony_ci	if ((instance->adapter_type != MFI_SERIES) &&
683062306a36Sopenharmony_ci	    !instance->mask_interrupts)
683162306a36Sopenharmony_ci		ret = megasas_issue_blocked_cmd(instance,
683262306a36Sopenharmony_ci						cmd, MFI_IO_TIMEOUT_SECS);
683362306a36Sopenharmony_ci	else
683462306a36Sopenharmony_ci		ret = megasas_issue_polled(instance, cmd);
683562306a36Sopenharmony_ci
683662306a36Sopenharmony_ci	switch (ret) {
683762306a36Sopenharmony_ci	case DCMD_TIMEOUT:
683862306a36Sopenharmony_ci		switch (dcmd_timeout_ocr_possible(instance)) {
683962306a36Sopenharmony_ci		case INITIATE_OCR:
684062306a36Sopenharmony_ci			cmd->flags |= DRV_DCMD_SKIP_REFIRE;
684162306a36Sopenharmony_ci			mutex_unlock(&instance->reset_mutex);
684262306a36Sopenharmony_ci			megasas_reset_fusion(instance->host,
684362306a36Sopenharmony_ci					     MFI_IO_TIMEOUT_OCR);
684462306a36Sopenharmony_ci			mutex_lock(&instance->reset_mutex);
684562306a36Sopenharmony_ci			break;
684662306a36Sopenharmony_ci		case KILL_ADAPTER:
684762306a36Sopenharmony_ci			megaraid_sas_kill_hba(instance);
684862306a36Sopenharmony_ci			break;
684962306a36Sopenharmony_ci		case IGNORE_TIMEOUT:
685062306a36Sopenharmony_ci			dev_info(&instance->pdev->dev,
685162306a36Sopenharmony_ci				 "Ignore DCMD timeout: %s %d\n",
685262306a36Sopenharmony_ci				 __func__, __LINE__);
685362306a36Sopenharmony_ci			break;
685462306a36Sopenharmony_ci		}
685562306a36Sopenharmony_ci		break;
685662306a36Sopenharmony_ci
685762306a36Sopenharmony_ci	default:
685862306a36Sopenharmony_ci		megasas_return_cmd(instance, cmd);
685962306a36Sopenharmony_ci	}
686062306a36Sopenharmony_ci	if (ret != DCMD_SUCCESS)
686162306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
686262306a36Sopenharmony_ci			"return from %s %d return value %d\n",
686362306a36Sopenharmony_ci			__func__, __LINE__, ret);
686462306a36Sopenharmony_ci
686562306a36Sopenharmony_ci	return ret;
686662306a36Sopenharmony_ci}
686762306a36Sopenharmony_ci
686862306a36Sopenharmony_ci/**
686962306a36Sopenharmony_ci * megasas_start_aen -	Subscribes to AEN during driver load time
687062306a36Sopenharmony_ci * @instance:		Adapter soft state
687162306a36Sopenharmony_ci */
687262306a36Sopenharmony_cistatic int megasas_start_aen(struct megasas_instance *instance)
687362306a36Sopenharmony_ci{
687462306a36Sopenharmony_ci	struct megasas_evt_log_info eli;
687562306a36Sopenharmony_ci	union megasas_evt_class_locale class_locale;
687662306a36Sopenharmony_ci
687762306a36Sopenharmony_ci	/*
687862306a36Sopenharmony_ci	 * Get the latest sequence number from FW
687962306a36Sopenharmony_ci	 */
688062306a36Sopenharmony_ci	memset(&eli, 0, sizeof(eli));
688162306a36Sopenharmony_ci
688262306a36Sopenharmony_ci	if (megasas_get_seq_num(instance, &eli))
688362306a36Sopenharmony_ci		return -1;
688462306a36Sopenharmony_ci
688562306a36Sopenharmony_ci	/*
688662306a36Sopenharmony_ci	 * Register AEN with FW for latest sequence number plus 1
688762306a36Sopenharmony_ci	 */
688862306a36Sopenharmony_ci	class_locale.members.reserved = 0;
688962306a36Sopenharmony_ci	class_locale.members.locale = MR_EVT_LOCALE_ALL;
689062306a36Sopenharmony_ci	class_locale.members.class = MR_EVT_CLASS_DEBUG;
689162306a36Sopenharmony_ci
689262306a36Sopenharmony_ci	return megasas_register_aen(instance,
689362306a36Sopenharmony_ci			le32_to_cpu(eli.newest_seq_num) + 1,
689462306a36Sopenharmony_ci			class_locale.word);
689562306a36Sopenharmony_ci}
689662306a36Sopenharmony_ci
689762306a36Sopenharmony_ci/**
689862306a36Sopenharmony_ci * megasas_io_attach -	Attaches this driver to SCSI mid-layer
689962306a36Sopenharmony_ci * @instance:		Adapter soft state
690062306a36Sopenharmony_ci */
690162306a36Sopenharmony_cistatic int megasas_io_attach(struct megasas_instance *instance)
690262306a36Sopenharmony_ci{
690362306a36Sopenharmony_ci	struct Scsi_Host *host = instance->host;
690462306a36Sopenharmony_ci
690562306a36Sopenharmony_ci	/*
690662306a36Sopenharmony_ci	 * Export parameters required by SCSI mid-layer
690762306a36Sopenharmony_ci	 */
690862306a36Sopenharmony_ci	host->unique_id = instance->unique_id;
690962306a36Sopenharmony_ci	host->can_queue = instance->max_scsi_cmds;
691062306a36Sopenharmony_ci	host->this_id = instance->init_id;
691162306a36Sopenharmony_ci	host->sg_tablesize = instance->max_num_sge;
691262306a36Sopenharmony_ci
691362306a36Sopenharmony_ci	if (instance->fw_support_ieee)
691462306a36Sopenharmony_ci		instance->max_sectors_per_req = MEGASAS_MAX_SECTORS_IEEE;
691562306a36Sopenharmony_ci
691662306a36Sopenharmony_ci	/*
691762306a36Sopenharmony_ci	 * Check if the module parameter value for max_sectors can be used
691862306a36Sopenharmony_ci	 */
691962306a36Sopenharmony_ci	if (max_sectors && max_sectors < instance->max_sectors_per_req)
692062306a36Sopenharmony_ci		instance->max_sectors_per_req = max_sectors;
692162306a36Sopenharmony_ci	else {
692262306a36Sopenharmony_ci		if (max_sectors) {
692362306a36Sopenharmony_ci			if (((instance->pdev->device ==
692462306a36Sopenharmony_ci				PCI_DEVICE_ID_LSI_SAS1078GEN2) ||
692562306a36Sopenharmony_ci				(instance->pdev->device ==
692662306a36Sopenharmony_ci				PCI_DEVICE_ID_LSI_SAS0079GEN2)) &&
692762306a36Sopenharmony_ci				(max_sectors <= MEGASAS_MAX_SECTORS)) {
692862306a36Sopenharmony_ci				instance->max_sectors_per_req = max_sectors;
692962306a36Sopenharmony_ci			} else {
693062306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "max_sectors should be > 0"
693162306a36Sopenharmony_ci				"and <= %d (or < 1MB for GEN2 controller)\n",
693262306a36Sopenharmony_ci				instance->max_sectors_per_req);
693362306a36Sopenharmony_ci			}
693462306a36Sopenharmony_ci		}
693562306a36Sopenharmony_ci	}
693662306a36Sopenharmony_ci
693762306a36Sopenharmony_ci	host->max_sectors = instance->max_sectors_per_req;
693862306a36Sopenharmony_ci	host->cmd_per_lun = MEGASAS_DEFAULT_CMD_PER_LUN;
693962306a36Sopenharmony_ci	host->max_channel = MEGASAS_MAX_CHANNELS - 1;
694062306a36Sopenharmony_ci	host->max_id = MEGASAS_MAX_DEV_PER_CHANNEL;
694162306a36Sopenharmony_ci	host->max_lun = MEGASAS_MAX_LUN;
694262306a36Sopenharmony_ci	host->max_cmd_len = 16;
694362306a36Sopenharmony_ci
694462306a36Sopenharmony_ci	/* Use shared host tagset only for fusion adaptors
694562306a36Sopenharmony_ci	 * if there are managed interrupts (smp affinity enabled case).
694662306a36Sopenharmony_ci	 * Single msix_vectors in kdump, so shared host tag is also disabled.
694762306a36Sopenharmony_ci	 */
694862306a36Sopenharmony_ci
694962306a36Sopenharmony_ci	host->host_tagset = 0;
695062306a36Sopenharmony_ci	host->nr_hw_queues = 1;
695162306a36Sopenharmony_ci
695262306a36Sopenharmony_ci	if ((instance->adapter_type != MFI_SERIES) &&
695362306a36Sopenharmony_ci		(instance->msix_vectors > instance->low_latency_index_start) &&
695462306a36Sopenharmony_ci		host_tagset_enable &&
695562306a36Sopenharmony_ci		instance->smp_affinity_enable) {
695662306a36Sopenharmony_ci		host->host_tagset = 1;
695762306a36Sopenharmony_ci		host->nr_hw_queues = instance->msix_vectors -
695862306a36Sopenharmony_ci			instance->low_latency_index_start + instance->iopoll_q_count;
695962306a36Sopenharmony_ci		if (instance->iopoll_q_count)
696062306a36Sopenharmony_ci			host->nr_maps = 3;
696162306a36Sopenharmony_ci	} else {
696262306a36Sopenharmony_ci		instance->iopoll_q_count = 0;
696362306a36Sopenharmony_ci	}
696462306a36Sopenharmony_ci
696562306a36Sopenharmony_ci	dev_info(&instance->pdev->dev,
696662306a36Sopenharmony_ci		"Max firmware commands: %d shared with default "
696762306a36Sopenharmony_ci		"hw_queues = %d poll_queues %d\n", instance->max_fw_cmds,
696862306a36Sopenharmony_ci		host->nr_hw_queues - instance->iopoll_q_count,
696962306a36Sopenharmony_ci		instance->iopoll_q_count);
697062306a36Sopenharmony_ci	/*
697162306a36Sopenharmony_ci	 * Notify the mid-layer about the new controller
697262306a36Sopenharmony_ci	 */
697362306a36Sopenharmony_ci	if (scsi_add_host(host, &instance->pdev->dev)) {
697462306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
697562306a36Sopenharmony_ci			"Failed to add host from %s %d\n",
697662306a36Sopenharmony_ci			__func__, __LINE__);
697762306a36Sopenharmony_ci		return -ENODEV;
697862306a36Sopenharmony_ci	}
697962306a36Sopenharmony_ci
698062306a36Sopenharmony_ci	return 0;
698162306a36Sopenharmony_ci}
698262306a36Sopenharmony_ci
698362306a36Sopenharmony_ci/**
698462306a36Sopenharmony_ci * megasas_set_dma_mask -	Set DMA mask for supported controllers
698562306a36Sopenharmony_ci *
698662306a36Sopenharmony_ci * @instance:		Adapter soft state
698762306a36Sopenharmony_ci * Description:
698862306a36Sopenharmony_ci *
698962306a36Sopenharmony_ci * For Ventura, driver/FW will operate in 63bit DMA addresses.
699062306a36Sopenharmony_ci *
699162306a36Sopenharmony_ci * For invader-
699262306a36Sopenharmony_ci *	By default, driver/FW will operate in 32bit DMA addresses
699362306a36Sopenharmony_ci *	for consistent DMA mapping but if 32 bit consistent
699462306a36Sopenharmony_ci *	DMA mask fails, driver will try with 63 bit consistent
699562306a36Sopenharmony_ci *	mask provided FW is true 63bit DMA capable
699662306a36Sopenharmony_ci *
699762306a36Sopenharmony_ci * For older controllers(Thunderbolt and MFI based adapters)-
699862306a36Sopenharmony_ci *	driver/FW will operate in 32 bit consistent DMA addresses.
699962306a36Sopenharmony_ci */
700062306a36Sopenharmony_cistatic int
700162306a36Sopenharmony_cimegasas_set_dma_mask(struct megasas_instance *instance)
700262306a36Sopenharmony_ci{
700362306a36Sopenharmony_ci	u64 consistent_mask;
700462306a36Sopenharmony_ci	struct pci_dev *pdev;
700562306a36Sopenharmony_ci	u32 scratch_pad_1;
700662306a36Sopenharmony_ci
700762306a36Sopenharmony_ci	pdev = instance->pdev;
700862306a36Sopenharmony_ci	consistent_mask = (instance->adapter_type >= VENTURA_SERIES) ?
700962306a36Sopenharmony_ci				DMA_BIT_MASK(63) : DMA_BIT_MASK(32);
701062306a36Sopenharmony_ci
701162306a36Sopenharmony_ci	if (IS_DMA64) {
701262306a36Sopenharmony_ci		if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(63)) &&
701362306a36Sopenharmony_ci		    dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)))
701462306a36Sopenharmony_ci			goto fail_set_dma_mask;
701562306a36Sopenharmony_ci
701662306a36Sopenharmony_ci		if ((*pdev->dev.dma_mask == DMA_BIT_MASK(63)) &&
701762306a36Sopenharmony_ci		    (dma_set_coherent_mask(&pdev->dev, consistent_mask) &&
701862306a36Sopenharmony_ci		     dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)))) {
701962306a36Sopenharmony_ci			/*
702062306a36Sopenharmony_ci			 * If 32 bit DMA mask fails, then try for 64 bit mask
702162306a36Sopenharmony_ci			 * for FW capable of handling 64 bit DMA.
702262306a36Sopenharmony_ci			 */
702362306a36Sopenharmony_ci			scratch_pad_1 = megasas_readl
702462306a36Sopenharmony_ci				(instance, &instance->reg_set->outbound_scratch_pad_1);
702562306a36Sopenharmony_ci
702662306a36Sopenharmony_ci			if (!(scratch_pad_1 & MR_CAN_HANDLE_64_BIT_DMA_OFFSET))
702762306a36Sopenharmony_ci				goto fail_set_dma_mask;
702862306a36Sopenharmony_ci			else if (dma_set_mask_and_coherent(&pdev->dev,
702962306a36Sopenharmony_ci							   DMA_BIT_MASK(63)))
703062306a36Sopenharmony_ci				goto fail_set_dma_mask;
703162306a36Sopenharmony_ci		}
703262306a36Sopenharmony_ci	} else if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)))
703362306a36Sopenharmony_ci		goto fail_set_dma_mask;
703462306a36Sopenharmony_ci
703562306a36Sopenharmony_ci	if (pdev->dev.coherent_dma_mask == DMA_BIT_MASK(32))
703662306a36Sopenharmony_ci		instance->consistent_mask_64bit = false;
703762306a36Sopenharmony_ci	else
703862306a36Sopenharmony_ci		instance->consistent_mask_64bit = true;
703962306a36Sopenharmony_ci
704062306a36Sopenharmony_ci	dev_info(&pdev->dev, "%s bit DMA mask and %s bit consistent mask\n",
704162306a36Sopenharmony_ci		 ((*pdev->dev.dma_mask == DMA_BIT_MASK(63)) ? "63" : "32"),
704262306a36Sopenharmony_ci		 (instance->consistent_mask_64bit ? "63" : "32"));
704362306a36Sopenharmony_ci
704462306a36Sopenharmony_ci	return 0;
704562306a36Sopenharmony_ci
704662306a36Sopenharmony_cifail_set_dma_mask:
704762306a36Sopenharmony_ci	dev_err(&pdev->dev, "Failed to set DMA mask\n");
704862306a36Sopenharmony_ci	return -1;
704962306a36Sopenharmony_ci
705062306a36Sopenharmony_ci}
705162306a36Sopenharmony_ci
705262306a36Sopenharmony_ci/*
705362306a36Sopenharmony_ci * megasas_set_adapter_type -	Set adapter type.
705462306a36Sopenharmony_ci *				Supported controllers can be divided in
705562306a36Sopenharmony_ci *				different categories-
705662306a36Sopenharmony_ci *					enum MR_ADAPTER_TYPE {
705762306a36Sopenharmony_ci *						MFI_SERIES = 1,
705862306a36Sopenharmony_ci *						THUNDERBOLT_SERIES = 2,
705962306a36Sopenharmony_ci *						INVADER_SERIES = 3,
706062306a36Sopenharmony_ci *						VENTURA_SERIES = 4,
706162306a36Sopenharmony_ci *						AERO_SERIES = 5,
706262306a36Sopenharmony_ci *					};
706362306a36Sopenharmony_ci * @instance:			Adapter soft state
706462306a36Sopenharmony_ci * return:			void
706562306a36Sopenharmony_ci */
706662306a36Sopenharmony_cistatic inline void megasas_set_adapter_type(struct megasas_instance *instance)
706762306a36Sopenharmony_ci{
706862306a36Sopenharmony_ci	if ((instance->pdev->vendor == PCI_VENDOR_ID_DELL) &&
706962306a36Sopenharmony_ci	    (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5)) {
707062306a36Sopenharmony_ci		instance->adapter_type = MFI_SERIES;
707162306a36Sopenharmony_ci	} else {
707262306a36Sopenharmony_ci		switch (instance->pdev->device) {
707362306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_AERO_10E1:
707462306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_AERO_10E2:
707562306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_AERO_10E5:
707662306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_AERO_10E6:
707762306a36Sopenharmony_ci			instance->adapter_type = AERO_SERIES;
707862306a36Sopenharmony_ci			break;
707962306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_VENTURA:
708062306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_CRUSADER:
708162306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_HARPOON:
708262306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_TOMCAT:
708362306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_VENTURA_4PORT:
708462306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_CRUSADER_4PORT:
708562306a36Sopenharmony_ci			instance->adapter_type = VENTURA_SERIES;
708662306a36Sopenharmony_ci			break;
708762306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_FUSION:
708862306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_PLASMA:
708962306a36Sopenharmony_ci			instance->adapter_type = THUNDERBOLT_SERIES;
709062306a36Sopenharmony_ci			break;
709162306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_INVADER:
709262306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_INTRUDER:
709362306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_INTRUDER_24:
709462306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_CUTLASS_52:
709562306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_CUTLASS_53:
709662306a36Sopenharmony_ci		case PCI_DEVICE_ID_LSI_FURY:
709762306a36Sopenharmony_ci			instance->adapter_type = INVADER_SERIES;
709862306a36Sopenharmony_ci			break;
709962306a36Sopenharmony_ci		default: /* For all other supported controllers */
710062306a36Sopenharmony_ci			instance->adapter_type = MFI_SERIES;
710162306a36Sopenharmony_ci			break;
710262306a36Sopenharmony_ci		}
710362306a36Sopenharmony_ci	}
710462306a36Sopenharmony_ci}
710562306a36Sopenharmony_ci
710662306a36Sopenharmony_cistatic inline int megasas_alloc_mfi_ctrl_mem(struct megasas_instance *instance)
710762306a36Sopenharmony_ci{
710862306a36Sopenharmony_ci	instance->producer = dma_alloc_coherent(&instance->pdev->dev,
710962306a36Sopenharmony_ci			sizeof(u32), &instance->producer_h, GFP_KERNEL);
711062306a36Sopenharmony_ci	instance->consumer = dma_alloc_coherent(&instance->pdev->dev,
711162306a36Sopenharmony_ci			sizeof(u32), &instance->consumer_h, GFP_KERNEL);
711262306a36Sopenharmony_ci
711362306a36Sopenharmony_ci	if (!instance->producer || !instance->consumer) {
711462306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
711562306a36Sopenharmony_ci			"Failed to allocate memory for producer, consumer\n");
711662306a36Sopenharmony_ci		return -1;
711762306a36Sopenharmony_ci	}
711862306a36Sopenharmony_ci
711962306a36Sopenharmony_ci	*instance->producer = 0;
712062306a36Sopenharmony_ci	*instance->consumer = 0;
712162306a36Sopenharmony_ci	return 0;
712262306a36Sopenharmony_ci}
712362306a36Sopenharmony_ci
712462306a36Sopenharmony_ci/**
712562306a36Sopenharmony_ci * megasas_alloc_ctrl_mem -	Allocate per controller memory for core data
712662306a36Sopenharmony_ci *				structures which are not common across MFI
712762306a36Sopenharmony_ci *				adapters and fusion adapters.
712862306a36Sopenharmony_ci *				For MFI based adapters, allocate producer and
712962306a36Sopenharmony_ci *				consumer buffers. For fusion adapters, allocate
713062306a36Sopenharmony_ci *				memory for fusion context.
713162306a36Sopenharmony_ci * @instance:			Adapter soft state
713262306a36Sopenharmony_ci * return:			0 for SUCCESS
713362306a36Sopenharmony_ci */
713462306a36Sopenharmony_cistatic int megasas_alloc_ctrl_mem(struct megasas_instance *instance)
713562306a36Sopenharmony_ci{
713662306a36Sopenharmony_ci	instance->reply_map = kcalloc(nr_cpu_ids, sizeof(unsigned int),
713762306a36Sopenharmony_ci				      GFP_KERNEL);
713862306a36Sopenharmony_ci	if (!instance->reply_map)
713962306a36Sopenharmony_ci		return -ENOMEM;
714062306a36Sopenharmony_ci
714162306a36Sopenharmony_ci	switch (instance->adapter_type) {
714262306a36Sopenharmony_ci	case MFI_SERIES:
714362306a36Sopenharmony_ci		if (megasas_alloc_mfi_ctrl_mem(instance))
714462306a36Sopenharmony_ci			return -ENOMEM;
714562306a36Sopenharmony_ci		break;
714662306a36Sopenharmony_ci	case AERO_SERIES:
714762306a36Sopenharmony_ci	case VENTURA_SERIES:
714862306a36Sopenharmony_ci	case THUNDERBOLT_SERIES:
714962306a36Sopenharmony_ci	case INVADER_SERIES:
715062306a36Sopenharmony_ci		if (megasas_alloc_fusion_context(instance))
715162306a36Sopenharmony_ci			return -ENOMEM;
715262306a36Sopenharmony_ci		break;
715362306a36Sopenharmony_ci	}
715462306a36Sopenharmony_ci
715562306a36Sopenharmony_ci	return 0;
715662306a36Sopenharmony_ci}
715762306a36Sopenharmony_ci
715862306a36Sopenharmony_ci/*
715962306a36Sopenharmony_ci * megasas_free_ctrl_mem -	Free fusion context for fusion adapters and
716062306a36Sopenharmony_ci *				producer, consumer buffers for MFI adapters
716162306a36Sopenharmony_ci *
716262306a36Sopenharmony_ci * @instance -			Adapter soft instance
716362306a36Sopenharmony_ci *
716462306a36Sopenharmony_ci */
716562306a36Sopenharmony_cistatic inline void megasas_free_ctrl_mem(struct megasas_instance *instance)
716662306a36Sopenharmony_ci{
716762306a36Sopenharmony_ci	kfree(instance->reply_map);
716862306a36Sopenharmony_ci	if (instance->adapter_type == MFI_SERIES) {
716962306a36Sopenharmony_ci		if (instance->producer)
717062306a36Sopenharmony_ci			dma_free_coherent(&instance->pdev->dev, sizeof(u32),
717162306a36Sopenharmony_ci					    instance->producer,
717262306a36Sopenharmony_ci					    instance->producer_h);
717362306a36Sopenharmony_ci		if (instance->consumer)
717462306a36Sopenharmony_ci			dma_free_coherent(&instance->pdev->dev, sizeof(u32),
717562306a36Sopenharmony_ci					    instance->consumer,
717662306a36Sopenharmony_ci					    instance->consumer_h);
717762306a36Sopenharmony_ci	} else {
717862306a36Sopenharmony_ci		megasas_free_fusion_context(instance);
717962306a36Sopenharmony_ci	}
718062306a36Sopenharmony_ci}
718162306a36Sopenharmony_ci
718262306a36Sopenharmony_ci/**
718362306a36Sopenharmony_ci * megasas_alloc_ctrl_dma_buffers -	Allocate consistent DMA buffers during
718462306a36Sopenharmony_ci *					driver load time
718562306a36Sopenharmony_ci *
718662306a36Sopenharmony_ci * @instance:				Adapter soft instance
718762306a36Sopenharmony_ci *
718862306a36Sopenharmony_ci * @return:				O for SUCCESS
718962306a36Sopenharmony_ci */
719062306a36Sopenharmony_cistatic inline
719162306a36Sopenharmony_ciint megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance)
719262306a36Sopenharmony_ci{
719362306a36Sopenharmony_ci	struct pci_dev *pdev = instance->pdev;
719462306a36Sopenharmony_ci	struct fusion_context *fusion = instance->ctrl_context;
719562306a36Sopenharmony_ci
719662306a36Sopenharmony_ci	instance->evt_detail = dma_alloc_coherent(&pdev->dev,
719762306a36Sopenharmony_ci			sizeof(struct megasas_evt_detail),
719862306a36Sopenharmony_ci			&instance->evt_detail_h, GFP_KERNEL);
719962306a36Sopenharmony_ci
720062306a36Sopenharmony_ci	if (!instance->evt_detail) {
720162306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
720262306a36Sopenharmony_ci			"Failed to allocate event detail buffer\n");
720362306a36Sopenharmony_ci		return -ENOMEM;
720462306a36Sopenharmony_ci	}
720562306a36Sopenharmony_ci
720662306a36Sopenharmony_ci	if (fusion) {
720762306a36Sopenharmony_ci		fusion->ioc_init_request =
720862306a36Sopenharmony_ci			dma_alloc_coherent(&pdev->dev,
720962306a36Sopenharmony_ci					   sizeof(struct MPI2_IOC_INIT_REQUEST),
721062306a36Sopenharmony_ci					   &fusion->ioc_init_request_phys,
721162306a36Sopenharmony_ci					   GFP_KERNEL);
721262306a36Sopenharmony_ci
721362306a36Sopenharmony_ci		if (!fusion->ioc_init_request) {
721462306a36Sopenharmony_ci			dev_err(&pdev->dev,
721562306a36Sopenharmony_ci				"Failed to allocate ioc init request\n");
721662306a36Sopenharmony_ci			return -ENOMEM;
721762306a36Sopenharmony_ci		}
721862306a36Sopenharmony_ci
721962306a36Sopenharmony_ci		instance->snapdump_prop = dma_alloc_coherent(&pdev->dev,
722062306a36Sopenharmony_ci				sizeof(struct MR_SNAPDUMP_PROPERTIES),
722162306a36Sopenharmony_ci				&instance->snapdump_prop_h, GFP_KERNEL);
722262306a36Sopenharmony_ci
722362306a36Sopenharmony_ci		if (!instance->snapdump_prop)
722462306a36Sopenharmony_ci			dev_err(&pdev->dev,
722562306a36Sopenharmony_ci				"Failed to allocate snapdump properties buffer\n");
722662306a36Sopenharmony_ci
722762306a36Sopenharmony_ci		instance->host_device_list_buf = dma_alloc_coherent(&pdev->dev,
722862306a36Sopenharmony_ci							HOST_DEVICE_LIST_SZ,
722962306a36Sopenharmony_ci							&instance->host_device_list_buf_h,
723062306a36Sopenharmony_ci							GFP_KERNEL);
723162306a36Sopenharmony_ci
723262306a36Sopenharmony_ci		if (!instance->host_device_list_buf) {
723362306a36Sopenharmony_ci			dev_err(&pdev->dev,
723462306a36Sopenharmony_ci				"Failed to allocate targetid list buffer\n");
723562306a36Sopenharmony_ci			return -ENOMEM;
723662306a36Sopenharmony_ci		}
723762306a36Sopenharmony_ci
723862306a36Sopenharmony_ci	}
723962306a36Sopenharmony_ci
724062306a36Sopenharmony_ci	instance->pd_list_buf =
724162306a36Sopenharmony_ci		dma_alloc_coherent(&pdev->dev,
724262306a36Sopenharmony_ci				     MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST),
724362306a36Sopenharmony_ci				     &instance->pd_list_buf_h, GFP_KERNEL);
724462306a36Sopenharmony_ci
724562306a36Sopenharmony_ci	if (!instance->pd_list_buf) {
724662306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to allocate PD list buffer\n");
724762306a36Sopenharmony_ci		return -ENOMEM;
724862306a36Sopenharmony_ci	}
724962306a36Sopenharmony_ci
725062306a36Sopenharmony_ci	instance->ctrl_info_buf =
725162306a36Sopenharmony_ci		dma_alloc_coherent(&pdev->dev,
725262306a36Sopenharmony_ci				     sizeof(struct megasas_ctrl_info),
725362306a36Sopenharmony_ci				     &instance->ctrl_info_buf_h, GFP_KERNEL);
725462306a36Sopenharmony_ci
725562306a36Sopenharmony_ci	if (!instance->ctrl_info_buf) {
725662306a36Sopenharmony_ci		dev_err(&pdev->dev,
725762306a36Sopenharmony_ci			"Failed to allocate controller info buffer\n");
725862306a36Sopenharmony_ci		return -ENOMEM;
725962306a36Sopenharmony_ci	}
726062306a36Sopenharmony_ci
726162306a36Sopenharmony_ci	instance->ld_list_buf =
726262306a36Sopenharmony_ci		dma_alloc_coherent(&pdev->dev,
726362306a36Sopenharmony_ci				     sizeof(struct MR_LD_LIST),
726462306a36Sopenharmony_ci				     &instance->ld_list_buf_h, GFP_KERNEL);
726562306a36Sopenharmony_ci
726662306a36Sopenharmony_ci	if (!instance->ld_list_buf) {
726762306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to allocate LD list buffer\n");
726862306a36Sopenharmony_ci		return -ENOMEM;
726962306a36Sopenharmony_ci	}
727062306a36Sopenharmony_ci
727162306a36Sopenharmony_ci	instance->ld_targetid_list_buf =
727262306a36Sopenharmony_ci		dma_alloc_coherent(&pdev->dev,
727362306a36Sopenharmony_ci				sizeof(struct MR_LD_TARGETID_LIST),
727462306a36Sopenharmony_ci				&instance->ld_targetid_list_buf_h, GFP_KERNEL);
727562306a36Sopenharmony_ci
727662306a36Sopenharmony_ci	if (!instance->ld_targetid_list_buf) {
727762306a36Sopenharmony_ci		dev_err(&pdev->dev,
727862306a36Sopenharmony_ci			"Failed to allocate LD targetid list buffer\n");
727962306a36Sopenharmony_ci		return -ENOMEM;
728062306a36Sopenharmony_ci	}
728162306a36Sopenharmony_ci
728262306a36Sopenharmony_ci	if (!reset_devices) {
728362306a36Sopenharmony_ci		instance->system_info_buf =
728462306a36Sopenharmony_ci			dma_alloc_coherent(&pdev->dev,
728562306a36Sopenharmony_ci					sizeof(struct MR_DRV_SYSTEM_INFO),
728662306a36Sopenharmony_ci					&instance->system_info_h, GFP_KERNEL);
728762306a36Sopenharmony_ci		instance->pd_info =
728862306a36Sopenharmony_ci			dma_alloc_coherent(&pdev->dev,
728962306a36Sopenharmony_ci					sizeof(struct MR_PD_INFO),
729062306a36Sopenharmony_ci					&instance->pd_info_h, GFP_KERNEL);
729162306a36Sopenharmony_ci		instance->tgt_prop =
729262306a36Sopenharmony_ci			dma_alloc_coherent(&pdev->dev,
729362306a36Sopenharmony_ci					sizeof(struct MR_TARGET_PROPERTIES),
729462306a36Sopenharmony_ci					&instance->tgt_prop_h, GFP_KERNEL);
729562306a36Sopenharmony_ci		instance->crash_dump_buf =
729662306a36Sopenharmony_ci			dma_alloc_coherent(&pdev->dev, CRASH_DMA_BUF_SIZE,
729762306a36Sopenharmony_ci					&instance->crash_dump_h, GFP_KERNEL);
729862306a36Sopenharmony_ci
729962306a36Sopenharmony_ci		if (!instance->system_info_buf)
730062306a36Sopenharmony_ci			dev_err(&instance->pdev->dev,
730162306a36Sopenharmony_ci				"Failed to allocate system info buffer\n");
730262306a36Sopenharmony_ci
730362306a36Sopenharmony_ci		if (!instance->pd_info)
730462306a36Sopenharmony_ci			dev_err(&instance->pdev->dev,
730562306a36Sopenharmony_ci				"Failed to allocate pd_info buffer\n");
730662306a36Sopenharmony_ci
730762306a36Sopenharmony_ci		if (!instance->tgt_prop)
730862306a36Sopenharmony_ci			dev_err(&instance->pdev->dev,
730962306a36Sopenharmony_ci				"Failed to allocate tgt_prop buffer\n");
731062306a36Sopenharmony_ci
731162306a36Sopenharmony_ci		if (!instance->crash_dump_buf)
731262306a36Sopenharmony_ci			dev_err(&instance->pdev->dev,
731362306a36Sopenharmony_ci				"Failed to allocate crash dump buffer\n");
731462306a36Sopenharmony_ci	}
731562306a36Sopenharmony_ci
731662306a36Sopenharmony_ci	return 0;
731762306a36Sopenharmony_ci}
731862306a36Sopenharmony_ci
731962306a36Sopenharmony_ci/*
732062306a36Sopenharmony_ci * megasas_free_ctrl_dma_buffers -	Free consistent DMA buffers allocated
732162306a36Sopenharmony_ci *					during driver load time
732262306a36Sopenharmony_ci *
732362306a36Sopenharmony_ci * @instance-				Adapter soft instance
732462306a36Sopenharmony_ci *
732562306a36Sopenharmony_ci */
732662306a36Sopenharmony_cistatic inline
732762306a36Sopenharmony_civoid megasas_free_ctrl_dma_buffers(struct megasas_instance *instance)
732862306a36Sopenharmony_ci{
732962306a36Sopenharmony_ci	struct pci_dev *pdev = instance->pdev;
733062306a36Sopenharmony_ci	struct fusion_context *fusion = instance->ctrl_context;
733162306a36Sopenharmony_ci
733262306a36Sopenharmony_ci	if (instance->evt_detail)
733362306a36Sopenharmony_ci		dma_free_coherent(&pdev->dev, sizeof(struct megasas_evt_detail),
733462306a36Sopenharmony_ci				    instance->evt_detail,
733562306a36Sopenharmony_ci				    instance->evt_detail_h);
733662306a36Sopenharmony_ci
733762306a36Sopenharmony_ci	if (fusion && fusion->ioc_init_request)
733862306a36Sopenharmony_ci		dma_free_coherent(&pdev->dev,
733962306a36Sopenharmony_ci				  sizeof(struct MPI2_IOC_INIT_REQUEST),
734062306a36Sopenharmony_ci				  fusion->ioc_init_request,
734162306a36Sopenharmony_ci				  fusion->ioc_init_request_phys);
734262306a36Sopenharmony_ci
734362306a36Sopenharmony_ci	if (instance->pd_list_buf)
734462306a36Sopenharmony_ci		dma_free_coherent(&pdev->dev,
734562306a36Sopenharmony_ci				    MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST),
734662306a36Sopenharmony_ci				    instance->pd_list_buf,
734762306a36Sopenharmony_ci				    instance->pd_list_buf_h);
734862306a36Sopenharmony_ci
734962306a36Sopenharmony_ci	if (instance->ld_list_buf)
735062306a36Sopenharmony_ci		dma_free_coherent(&pdev->dev, sizeof(struct MR_LD_LIST),
735162306a36Sopenharmony_ci				    instance->ld_list_buf,
735262306a36Sopenharmony_ci				    instance->ld_list_buf_h);
735362306a36Sopenharmony_ci
735462306a36Sopenharmony_ci	if (instance->ld_targetid_list_buf)
735562306a36Sopenharmony_ci		dma_free_coherent(&pdev->dev, sizeof(struct MR_LD_TARGETID_LIST),
735662306a36Sopenharmony_ci				    instance->ld_targetid_list_buf,
735762306a36Sopenharmony_ci				    instance->ld_targetid_list_buf_h);
735862306a36Sopenharmony_ci
735962306a36Sopenharmony_ci	if (instance->ctrl_info_buf)
736062306a36Sopenharmony_ci		dma_free_coherent(&pdev->dev, sizeof(struct megasas_ctrl_info),
736162306a36Sopenharmony_ci				    instance->ctrl_info_buf,
736262306a36Sopenharmony_ci				    instance->ctrl_info_buf_h);
736362306a36Sopenharmony_ci
736462306a36Sopenharmony_ci	if (instance->system_info_buf)
736562306a36Sopenharmony_ci		dma_free_coherent(&pdev->dev, sizeof(struct MR_DRV_SYSTEM_INFO),
736662306a36Sopenharmony_ci				    instance->system_info_buf,
736762306a36Sopenharmony_ci				    instance->system_info_h);
736862306a36Sopenharmony_ci
736962306a36Sopenharmony_ci	if (instance->pd_info)
737062306a36Sopenharmony_ci		dma_free_coherent(&pdev->dev, sizeof(struct MR_PD_INFO),
737162306a36Sopenharmony_ci				    instance->pd_info, instance->pd_info_h);
737262306a36Sopenharmony_ci
737362306a36Sopenharmony_ci	if (instance->tgt_prop)
737462306a36Sopenharmony_ci		dma_free_coherent(&pdev->dev, sizeof(struct MR_TARGET_PROPERTIES),
737562306a36Sopenharmony_ci				    instance->tgt_prop, instance->tgt_prop_h);
737662306a36Sopenharmony_ci
737762306a36Sopenharmony_ci	if (instance->crash_dump_buf)
737862306a36Sopenharmony_ci		dma_free_coherent(&pdev->dev, CRASH_DMA_BUF_SIZE,
737962306a36Sopenharmony_ci				    instance->crash_dump_buf,
738062306a36Sopenharmony_ci				    instance->crash_dump_h);
738162306a36Sopenharmony_ci
738262306a36Sopenharmony_ci	if (instance->snapdump_prop)
738362306a36Sopenharmony_ci		dma_free_coherent(&pdev->dev,
738462306a36Sopenharmony_ci				  sizeof(struct MR_SNAPDUMP_PROPERTIES),
738562306a36Sopenharmony_ci				  instance->snapdump_prop,
738662306a36Sopenharmony_ci				  instance->snapdump_prop_h);
738762306a36Sopenharmony_ci
738862306a36Sopenharmony_ci	if (instance->host_device_list_buf)
738962306a36Sopenharmony_ci		dma_free_coherent(&pdev->dev,
739062306a36Sopenharmony_ci				  HOST_DEVICE_LIST_SZ,
739162306a36Sopenharmony_ci				  instance->host_device_list_buf,
739262306a36Sopenharmony_ci				  instance->host_device_list_buf_h);
739362306a36Sopenharmony_ci
739462306a36Sopenharmony_ci}
739562306a36Sopenharmony_ci
739662306a36Sopenharmony_ci/*
739762306a36Sopenharmony_ci * megasas_init_ctrl_params -		Initialize controller's instance
739862306a36Sopenharmony_ci *					parameters before FW init
739962306a36Sopenharmony_ci * @instance -				Adapter soft instance
740062306a36Sopenharmony_ci * @return -				void
740162306a36Sopenharmony_ci */
740262306a36Sopenharmony_cistatic inline void megasas_init_ctrl_params(struct megasas_instance *instance)
740362306a36Sopenharmony_ci{
740462306a36Sopenharmony_ci	instance->fw_crash_state = UNAVAILABLE;
740562306a36Sopenharmony_ci
740662306a36Sopenharmony_ci	megasas_poll_wait_aen = 0;
740762306a36Sopenharmony_ci	instance->issuepend_done = 1;
740862306a36Sopenharmony_ci	atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
740962306a36Sopenharmony_ci
741062306a36Sopenharmony_ci	/*
741162306a36Sopenharmony_ci	 * Initialize locks and queues
741262306a36Sopenharmony_ci	 */
741362306a36Sopenharmony_ci	INIT_LIST_HEAD(&instance->cmd_pool);
741462306a36Sopenharmony_ci	INIT_LIST_HEAD(&instance->internal_reset_pending_q);
741562306a36Sopenharmony_ci
741662306a36Sopenharmony_ci	atomic_set(&instance->fw_outstanding, 0);
741762306a36Sopenharmony_ci	atomic64_set(&instance->total_io_count, 0);
741862306a36Sopenharmony_ci
741962306a36Sopenharmony_ci	init_waitqueue_head(&instance->int_cmd_wait_q);
742062306a36Sopenharmony_ci	init_waitqueue_head(&instance->abort_cmd_wait_q);
742162306a36Sopenharmony_ci
742262306a36Sopenharmony_ci	mutex_init(&instance->crashdump_lock);
742362306a36Sopenharmony_ci	spin_lock_init(&instance->mfi_pool_lock);
742462306a36Sopenharmony_ci	spin_lock_init(&instance->hba_lock);
742562306a36Sopenharmony_ci	spin_lock_init(&instance->stream_lock);
742662306a36Sopenharmony_ci	spin_lock_init(&instance->completion_lock);
742762306a36Sopenharmony_ci
742862306a36Sopenharmony_ci	mutex_init(&instance->reset_mutex);
742962306a36Sopenharmony_ci
743062306a36Sopenharmony_ci	if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
743162306a36Sopenharmony_ci	    (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY))
743262306a36Sopenharmony_ci		instance->flag_ieee = 1;
743362306a36Sopenharmony_ci
743462306a36Sopenharmony_ci	instance->flag = 0;
743562306a36Sopenharmony_ci	instance->unload = 1;
743662306a36Sopenharmony_ci	instance->last_time = 0;
743762306a36Sopenharmony_ci	instance->disableOnlineCtrlReset = 1;
743862306a36Sopenharmony_ci	instance->UnevenSpanSupport = 0;
743962306a36Sopenharmony_ci	instance->smp_affinity_enable = smp_affinity_enable ? true : false;
744062306a36Sopenharmony_ci	instance->msix_load_balance = false;
744162306a36Sopenharmony_ci
744262306a36Sopenharmony_ci	if (instance->adapter_type != MFI_SERIES)
744362306a36Sopenharmony_ci		INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq);
744462306a36Sopenharmony_ci	else
744562306a36Sopenharmony_ci		INIT_WORK(&instance->work_init, process_fw_state_change_wq);
744662306a36Sopenharmony_ci}
744762306a36Sopenharmony_ci
744862306a36Sopenharmony_ci/**
744962306a36Sopenharmony_ci * megasas_probe_one -	PCI hotplug entry point
745062306a36Sopenharmony_ci * @pdev:		PCI device structure
745162306a36Sopenharmony_ci * @id:			PCI ids of supported hotplugged adapter
745262306a36Sopenharmony_ci */
745362306a36Sopenharmony_cistatic int megasas_probe_one(struct pci_dev *pdev,
745462306a36Sopenharmony_ci			     const struct pci_device_id *id)
745562306a36Sopenharmony_ci{
745662306a36Sopenharmony_ci	int rval, pos;
745762306a36Sopenharmony_ci	struct Scsi_Host *host;
745862306a36Sopenharmony_ci	struct megasas_instance *instance;
745962306a36Sopenharmony_ci	u16 control = 0;
746062306a36Sopenharmony_ci
746162306a36Sopenharmony_ci	switch (pdev->device) {
746262306a36Sopenharmony_ci	case PCI_DEVICE_ID_LSI_AERO_10E0:
746362306a36Sopenharmony_ci	case PCI_DEVICE_ID_LSI_AERO_10E3:
746462306a36Sopenharmony_ci	case PCI_DEVICE_ID_LSI_AERO_10E4:
746562306a36Sopenharmony_ci	case PCI_DEVICE_ID_LSI_AERO_10E7:
746662306a36Sopenharmony_ci		dev_err(&pdev->dev, "Adapter is in non secure mode\n");
746762306a36Sopenharmony_ci		return 1;
746862306a36Sopenharmony_ci	case PCI_DEVICE_ID_LSI_AERO_10E1:
746962306a36Sopenharmony_ci	case PCI_DEVICE_ID_LSI_AERO_10E5:
747062306a36Sopenharmony_ci		dev_info(&pdev->dev, "Adapter is in configurable secure mode\n");
747162306a36Sopenharmony_ci		break;
747262306a36Sopenharmony_ci	}
747362306a36Sopenharmony_ci
747462306a36Sopenharmony_ci	/* Reset MSI-X in the kdump kernel */
747562306a36Sopenharmony_ci	if (reset_devices) {
747662306a36Sopenharmony_ci		pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
747762306a36Sopenharmony_ci		if (pos) {
747862306a36Sopenharmony_ci			pci_read_config_word(pdev, pos + PCI_MSIX_FLAGS,
747962306a36Sopenharmony_ci					     &control);
748062306a36Sopenharmony_ci			if (control & PCI_MSIX_FLAGS_ENABLE) {
748162306a36Sopenharmony_ci				dev_info(&pdev->dev, "resetting MSI-X\n");
748262306a36Sopenharmony_ci				pci_write_config_word(pdev,
748362306a36Sopenharmony_ci						      pos + PCI_MSIX_FLAGS,
748462306a36Sopenharmony_ci						      control &
748562306a36Sopenharmony_ci						      ~PCI_MSIX_FLAGS_ENABLE);
748662306a36Sopenharmony_ci			}
748762306a36Sopenharmony_ci		}
748862306a36Sopenharmony_ci	}
748962306a36Sopenharmony_ci
749062306a36Sopenharmony_ci	/*
749162306a36Sopenharmony_ci	 * PCI prepping: enable device set bus mastering and dma mask
749262306a36Sopenharmony_ci	 */
749362306a36Sopenharmony_ci	rval = pci_enable_device_mem(pdev);
749462306a36Sopenharmony_ci
749562306a36Sopenharmony_ci	if (rval) {
749662306a36Sopenharmony_ci		return rval;
749762306a36Sopenharmony_ci	}
749862306a36Sopenharmony_ci
749962306a36Sopenharmony_ci	pci_set_master(pdev);
750062306a36Sopenharmony_ci
750162306a36Sopenharmony_ci	host = scsi_host_alloc(&megasas_template,
750262306a36Sopenharmony_ci			       sizeof(struct megasas_instance));
750362306a36Sopenharmony_ci
750462306a36Sopenharmony_ci	if (!host) {
750562306a36Sopenharmony_ci		dev_printk(KERN_DEBUG, &pdev->dev, "scsi_host_alloc failed\n");
750662306a36Sopenharmony_ci		goto fail_alloc_instance;
750762306a36Sopenharmony_ci	}
750862306a36Sopenharmony_ci
750962306a36Sopenharmony_ci	instance = (struct megasas_instance *)host->hostdata;
751062306a36Sopenharmony_ci	memset(instance, 0, sizeof(*instance));
751162306a36Sopenharmony_ci	atomic_set(&instance->fw_reset_no_pci_access, 0);
751262306a36Sopenharmony_ci
751362306a36Sopenharmony_ci	/*
751462306a36Sopenharmony_ci	 * Initialize PCI related and misc parameters
751562306a36Sopenharmony_ci	 */
751662306a36Sopenharmony_ci	instance->pdev = pdev;
751762306a36Sopenharmony_ci	instance->host = host;
751862306a36Sopenharmony_ci	instance->unique_id = pci_dev_id(pdev);
751962306a36Sopenharmony_ci	instance->init_id = MEGASAS_DEFAULT_INIT_ID;
752062306a36Sopenharmony_ci
752162306a36Sopenharmony_ci	megasas_set_adapter_type(instance);
752262306a36Sopenharmony_ci
752362306a36Sopenharmony_ci	/*
752462306a36Sopenharmony_ci	 * Initialize MFI Firmware
752562306a36Sopenharmony_ci	 */
752662306a36Sopenharmony_ci	if (megasas_init_fw(instance))
752762306a36Sopenharmony_ci		goto fail_init_mfi;
752862306a36Sopenharmony_ci
752962306a36Sopenharmony_ci	if (instance->requestorId) {
753062306a36Sopenharmony_ci		if (instance->PlasmaFW111) {
753162306a36Sopenharmony_ci			instance->vf_affiliation_111 =
753262306a36Sopenharmony_ci				dma_alloc_coherent(&pdev->dev,
753362306a36Sopenharmony_ci					sizeof(struct MR_LD_VF_AFFILIATION_111),
753462306a36Sopenharmony_ci					&instance->vf_affiliation_111_h,
753562306a36Sopenharmony_ci					GFP_KERNEL);
753662306a36Sopenharmony_ci			if (!instance->vf_affiliation_111)
753762306a36Sopenharmony_ci				dev_warn(&pdev->dev, "Can't allocate "
753862306a36Sopenharmony_ci				       "memory for VF affiliation buffer\n");
753962306a36Sopenharmony_ci		} else {
754062306a36Sopenharmony_ci			instance->vf_affiliation =
754162306a36Sopenharmony_ci				dma_alloc_coherent(&pdev->dev,
754262306a36Sopenharmony_ci					(MAX_LOGICAL_DRIVES + 1) *
754362306a36Sopenharmony_ci					sizeof(struct MR_LD_VF_AFFILIATION),
754462306a36Sopenharmony_ci					&instance->vf_affiliation_h,
754562306a36Sopenharmony_ci					GFP_KERNEL);
754662306a36Sopenharmony_ci			if (!instance->vf_affiliation)
754762306a36Sopenharmony_ci				dev_warn(&pdev->dev, "Can't allocate "
754862306a36Sopenharmony_ci				       "memory for VF affiliation buffer\n");
754962306a36Sopenharmony_ci		}
755062306a36Sopenharmony_ci	}
755162306a36Sopenharmony_ci
755262306a36Sopenharmony_ci	/*
755362306a36Sopenharmony_ci	 * Store instance in PCI softstate
755462306a36Sopenharmony_ci	 */
755562306a36Sopenharmony_ci	pci_set_drvdata(pdev, instance);
755662306a36Sopenharmony_ci
755762306a36Sopenharmony_ci	/*
755862306a36Sopenharmony_ci	 * Add this controller to megasas_mgmt_info structure so that it
755962306a36Sopenharmony_ci	 * can be exported to management applications
756062306a36Sopenharmony_ci	 */
756162306a36Sopenharmony_ci	megasas_mgmt_info.count++;
756262306a36Sopenharmony_ci	megasas_mgmt_info.instance[megasas_mgmt_info.max_index] = instance;
756362306a36Sopenharmony_ci	megasas_mgmt_info.max_index++;
756462306a36Sopenharmony_ci
756562306a36Sopenharmony_ci	/*
756662306a36Sopenharmony_ci	 * Register with SCSI mid-layer
756762306a36Sopenharmony_ci	 */
756862306a36Sopenharmony_ci	if (megasas_io_attach(instance))
756962306a36Sopenharmony_ci		goto fail_io_attach;
757062306a36Sopenharmony_ci
757162306a36Sopenharmony_ci	instance->unload = 0;
757262306a36Sopenharmony_ci	/*
757362306a36Sopenharmony_ci	 * Trigger SCSI to scan our drives
757462306a36Sopenharmony_ci	 */
757562306a36Sopenharmony_ci	if (!instance->enable_fw_dev_list ||
757662306a36Sopenharmony_ci	    (instance->host_device_list_buf->count > 0))
757762306a36Sopenharmony_ci		scsi_scan_host(host);
757862306a36Sopenharmony_ci
757962306a36Sopenharmony_ci	/*
758062306a36Sopenharmony_ci	 * Initiate AEN (Asynchronous Event Notification)
758162306a36Sopenharmony_ci	 */
758262306a36Sopenharmony_ci	if (megasas_start_aen(instance)) {
758362306a36Sopenharmony_ci		dev_printk(KERN_DEBUG, &pdev->dev, "start aen failed\n");
758462306a36Sopenharmony_ci		goto fail_start_aen;
758562306a36Sopenharmony_ci	}
758662306a36Sopenharmony_ci
758762306a36Sopenharmony_ci	megasas_setup_debugfs(instance);
758862306a36Sopenharmony_ci
758962306a36Sopenharmony_ci	/* Get current SR-IOV LD/VF affiliation */
759062306a36Sopenharmony_ci	if (instance->requestorId)
759162306a36Sopenharmony_ci		megasas_get_ld_vf_affiliation(instance, 1);
759262306a36Sopenharmony_ci
759362306a36Sopenharmony_ci	return 0;
759462306a36Sopenharmony_ci
759562306a36Sopenharmony_cifail_start_aen:
759662306a36Sopenharmony_ci	instance->unload = 1;
759762306a36Sopenharmony_ci	scsi_remove_host(instance->host);
759862306a36Sopenharmony_cifail_io_attach:
759962306a36Sopenharmony_ci	megasas_mgmt_info.count--;
760062306a36Sopenharmony_ci	megasas_mgmt_info.max_index--;
760162306a36Sopenharmony_ci	megasas_mgmt_info.instance[megasas_mgmt_info.max_index] = NULL;
760262306a36Sopenharmony_ci
760362306a36Sopenharmony_ci	if (instance->requestorId && !instance->skip_heartbeat_timer_del)
760462306a36Sopenharmony_ci		del_timer_sync(&instance->sriov_heartbeat_timer);
760562306a36Sopenharmony_ci
760662306a36Sopenharmony_ci	instance->instancet->disable_intr(instance);
760762306a36Sopenharmony_ci	megasas_destroy_irqs(instance);
760862306a36Sopenharmony_ci
760962306a36Sopenharmony_ci	if (instance->adapter_type != MFI_SERIES)
761062306a36Sopenharmony_ci		megasas_release_fusion(instance);
761162306a36Sopenharmony_ci	else
761262306a36Sopenharmony_ci		megasas_release_mfi(instance);
761362306a36Sopenharmony_ci
761462306a36Sopenharmony_ci	if (instance->msix_vectors)
761562306a36Sopenharmony_ci		pci_free_irq_vectors(instance->pdev);
761662306a36Sopenharmony_ci	instance->msix_vectors = 0;
761762306a36Sopenharmony_ci
761862306a36Sopenharmony_ci	if (instance->fw_crash_state != UNAVAILABLE)
761962306a36Sopenharmony_ci		megasas_free_host_crash_buffer(instance);
762062306a36Sopenharmony_ci
762162306a36Sopenharmony_ci	if (instance->adapter_type != MFI_SERIES)
762262306a36Sopenharmony_ci		megasas_fusion_stop_watchdog(instance);
762362306a36Sopenharmony_cifail_init_mfi:
762462306a36Sopenharmony_ci	scsi_host_put(host);
762562306a36Sopenharmony_cifail_alloc_instance:
762662306a36Sopenharmony_ci	pci_disable_device(pdev);
762762306a36Sopenharmony_ci
762862306a36Sopenharmony_ci	return -ENODEV;
762962306a36Sopenharmony_ci}
763062306a36Sopenharmony_ci
763162306a36Sopenharmony_ci/**
763262306a36Sopenharmony_ci * megasas_flush_cache -	Requests FW to flush all its caches
763362306a36Sopenharmony_ci * @instance:			Adapter soft state
763462306a36Sopenharmony_ci */
763562306a36Sopenharmony_cistatic void megasas_flush_cache(struct megasas_instance *instance)
763662306a36Sopenharmony_ci{
763762306a36Sopenharmony_ci	struct megasas_cmd *cmd;
763862306a36Sopenharmony_ci	struct megasas_dcmd_frame *dcmd;
763962306a36Sopenharmony_ci
764062306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
764162306a36Sopenharmony_ci		return;
764262306a36Sopenharmony_ci
764362306a36Sopenharmony_ci	cmd = megasas_get_cmd(instance);
764462306a36Sopenharmony_ci
764562306a36Sopenharmony_ci	if (!cmd)
764662306a36Sopenharmony_ci		return;
764762306a36Sopenharmony_ci
764862306a36Sopenharmony_ci	dcmd = &cmd->frame->dcmd;
764962306a36Sopenharmony_ci
765062306a36Sopenharmony_ci	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
765162306a36Sopenharmony_ci
765262306a36Sopenharmony_ci	dcmd->cmd = MFI_CMD_DCMD;
765362306a36Sopenharmony_ci	dcmd->cmd_status = 0x0;
765462306a36Sopenharmony_ci	dcmd->sge_count = 0;
765562306a36Sopenharmony_ci	dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_NONE);
765662306a36Sopenharmony_ci	dcmd->timeout = 0;
765762306a36Sopenharmony_ci	dcmd->pad_0 = 0;
765862306a36Sopenharmony_ci	dcmd->data_xfer_len = 0;
765962306a36Sopenharmony_ci	dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_CACHE_FLUSH);
766062306a36Sopenharmony_ci	dcmd->mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
766162306a36Sopenharmony_ci
766262306a36Sopenharmony_ci	if (megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS)
766362306a36Sopenharmony_ci			!= DCMD_SUCCESS) {
766462306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
766562306a36Sopenharmony_ci			"return from %s %d\n", __func__, __LINE__);
766662306a36Sopenharmony_ci		return;
766762306a36Sopenharmony_ci	}
766862306a36Sopenharmony_ci
766962306a36Sopenharmony_ci	megasas_return_cmd(instance, cmd);
767062306a36Sopenharmony_ci}
767162306a36Sopenharmony_ci
767262306a36Sopenharmony_ci/**
767362306a36Sopenharmony_ci * megasas_shutdown_controller -	Instructs FW to shutdown the controller
767462306a36Sopenharmony_ci * @instance:				Adapter soft state
767562306a36Sopenharmony_ci * @opcode:				Shutdown/Hibernate
767662306a36Sopenharmony_ci */
767762306a36Sopenharmony_cistatic void megasas_shutdown_controller(struct megasas_instance *instance,
767862306a36Sopenharmony_ci					u32 opcode)
767962306a36Sopenharmony_ci{
768062306a36Sopenharmony_ci	struct megasas_cmd *cmd;
768162306a36Sopenharmony_ci	struct megasas_dcmd_frame *dcmd;
768262306a36Sopenharmony_ci
768362306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
768462306a36Sopenharmony_ci		return;
768562306a36Sopenharmony_ci
768662306a36Sopenharmony_ci	cmd = megasas_get_cmd(instance);
768762306a36Sopenharmony_ci
768862306a36Sopenharmony_ci	if (!cmd)
768962306a36Sopenharmony_ci		return;
769062306a36Sopenharmony_ci
769162306a36Sopenharmony_ci	if (instance->aen_cmd)
769262306a36Sopenharmony_ci		megasas_issue_blocked_abort_cmd(instance,
769362306a36Sopenharmony_ci			instance->aen_cmd, MFI_IO_TIMEOUT_SECS);
769462306a36Sopenharmony_ci	if (instance->map_update_cmd)
769562306a36Sopenharmony_ci		megasas_issue_blocked_abort_cmd(instance,
769662306a36Sopenharmony_ci			instance->map_update_cmd, MFI_IO_TIMEOUT_SECS);
769762306a36Sopenharmony_ci	if (instance->jbod_seq_cmd)
769862306a36Sopenharmony_ci		megasas_issue_blocked_abort_cmd(instance,
769962306a36Sopenharmony_ci			instance->jbod_seq_cmd, MFI_IO_TIMEOUT_SECS);
770062306a36Sopenharmony_ci
770162306a36Sopenharmony_ci	dcmd = &cmd->frame->dcmd;
770262306a36Sopenharmony_ci
770362306a36Sopenharmony_ci	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
770462306a36Sopenharmony_ci
770562306a36Sopenharmony_ci	dcmd->cmd = MFI_CMD_DCMD;
770662306a36Sopenharmony_ci	dcmd->cmd_status = 0x0;
770762306a36Sopenharmony_ci	dcmd->sge_count = 0;
770862306a36Sopenharmony_ci	dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_NONE);
770962306a36Sopenharmony_ci	dcmd->timeout = 0;
771062306a36Sopenharmony_ci	dcmd->pad_0 = 0;
771162306a36Sopenharmony_ci	dcmd->data_xfer_len = 0;
771262306a36Sopenharmony_ci	dcmd->opcode = cpu_to_le32(opcode);
771362306a36Sopenharmony_ci
771462306a36Sopenharmony_ci	if (megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS)
771562306a36Sopenharmony_ci			!= DCMD_SUCCESS) {
771662306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
771762306a36Sopenharmony_ci			"return from %s %d\n", __func__, __LINE__);
771862306a36Sopenharmony_ci		return;
771962306a36Sopenharmony_ci	}
772062306a36Sopenharmony_ci
772162306a36Sopenharmony_ci	megasas_return_cmd(instance, cmd);
772262306a36Sopenharmony_ci}
772362306a36Sopenharmony_ci
772462306a36Sopenharmony_ci/**
772562306a36Sopenharmony_ci * megasas_suspend -	driver suspend entry point
772662306a36Sopenharmony_ci * @dev:		Device structure
772762306a36Sopenharmony_ci */
772862306a36Sopenharmony_cistatic int __maybe_unused
772962306a36Sopenharmony_cimegasas_suspend(struct device *dev)
773062306a36Sopenharmony_ci{
773162306a36Sopenharmony_ci	struct megasas_instance *instance;
773262306a36Sopenharmony_ci
773362306a36Sopenharmony_ci	instance = dev_get_drvdata(dev);
773462306a36Sopenharmony_ci
773562306a36Sopenharmony_ci	if (!instance)
773662306a36Sopenharmony_ci		return 0;
773762306a36Sopenharmony_ci
773862306a36Sopenharmony_ci	instance->unload = 1;
773962306a36Sopenharmony_ci
774062306a36Sopenharmony_ci	dev_info(dev, "%s is called\n", __func__);
774162306a36Sopenharmony_ci
774262306a36Sopenharmony_ci	/* Shutdown SR-IOV heartbeat timer */
774362306a36Sopenharmony_ci	if (instance->requestorId && !instance->skip_heartbeat_timer_del)
774462306a36Sopenharmony_ci		del_timer_sync(&instance->sriov_heartbeat_timer);
774562306a36Sopenharmony_ci
774662306a36Sopenharmony_ci	/* Stop the FW fault detection watchdog */
774762306a36Sopenharmony_ci	if (instance->adapter_type != MFI_SERIES)
774862306a36Sopenharmony_ci		megasas_fusion_stop_watchdog(instance);
774962306a36Sopenharmony_ci
775062306a36Sopenharmony_ci	megasas_flush_cache(instance);
775162306a36Sopenharmony_ci	megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN);
775262306a36Sopenharmony_ci
775362306a36Sopenharmony_ci	/* cancel the delayed work if this work still in queue */
775462306a36Sopenharmony_ci	if (instance->ev != NULL) {
775562306a36Sopenharmony_ci		struct megasas_aen_event *ev = instance->ev;
775662306a36Sopenharmony_ci		cancel_delayed_work_sync(&ev->hotplug_work);
775762306a36Sopenharmony_ci		instance->ev = NULL;
775862306a36Sopenharmony_ci	}
775962306a36Sopenharmony_ci
776062306a36Sopenharmony_ci	tasklet_kill(&instance->isr_tasklet);
776162306a36Sopenharmony_ci
776262306a36Sopenharmony_ci	pci_set_drvdata(instance->pdev, instance);
776362306a36Sopenharmony_ci	instance->instancet->disable_intr(instance);
776462306a36Sopenharmony_ci
776562306a36Sopenharmony_ci	megasas_destroy_irqs(instance);
776662306a36Sopenharmony_ci
776762306a36Sopenharmony_ci	if (instance->msix_vectors)
776862306a36Sopenharmony_ci		pci_free_irq_vectors(instance->pdev);
776962306a36Sopenharmony_ci
777062306a36Sopenharmony_ci	return 0;
777162306a36Sopenharmony_ci}
777262306a36Sopenharmony_ci
777362306a36Sopenharmony_ci/**
777462306a36Sopenharmony_ci * megasas_resume-      driver resume entry point
777562306a36Sopenharmony_ci * @dev:		Device structure
777662306a36Sopenharmony_ci */
777762306a36Sopenharmony_cistatic int __maybe_unused
777862306a36Sopenharmony_cimegasas_resume(struct device *dev)
777962306a36Sopenharmony_ci{
778062306a36Sopenharmony_ci	int rval;
778162306a36Sopenharmony_ci	struct Scsi_Host *host;
778262306a36Sopenharmony_ci	struct megasas_instance *instance;
778362306a36Sopenharmony_ci	u32 status_reg;
778462306a36Sopenharmony_ci
778562306a36Sopenharmony_ci	instance = dev_get_drvdata(dev);
778662306a36Sopenharmony_ci
778762306a36Sopenharmony_ci	if (!instance)
778862306a36Sopenharmony_ci		return 0;
778962306a36Sopenharmony_ci
779062306a36Sopenharmony_ci	host = instance->host;
779162306a36Sopenharmony_ci
779262306a36Sopenharmony_ci	dev_info(dev, "%s is called\n", __func__);
779362306a36Sopenharmony_ci
779462306a36Sopenharmony_ci	/*
779562306a36Sopenharmony_ci	 * We expect the FW state to be READY
779662306a36Sopenharmony_ci	 */
779762306a36Sopenharmony_ci
779862306a36Sopenharmony_ci	if (megasas_transition_to_ready(instance, 0)) {
779962306a36Sopenharmony_ci		dev_info(&instance->pdev->dev,
780062306a36Sopenharmony_ci			 "Failed to transition controller to ready from %s!\n",
780162306a36Sopenharmony_ci			 __func__);
780262306a36Sopenharmony_ci		if (instance->adapter_type != MFI_SERIES) {
780362306a36Sopenharmony_ci			status_reg =
780462306a36Sopenharmony_ci				instance->instancet->read_fw_status_reg(instance);
780562306a36Sopenharmony_ci			if (!(status_reg & MFI_RESET_ADAPTER) ||
780662306a36Sopenharmony_ci				((megasas_adp_reset_wait_for_ready
780762306a36Sopenharmony_ci				(instance, true, 0)) == FAILED))
780862306a36Sopenharmony_ci				goto fail_ready_state;
780962306a36Sopenharmony_ci		} else {
781062306a36Sopenharmony_ci			atomic_set(&instance->fw_reset_no_pci_access, 1);
781162306a36Sopenharmony_ci			instance->instancet->adp_reset
781262306a36Sopenharmony_ci				(instance, instance->reg_set);
781362306a36Sopenharmony_ci			atomic_set(&instance->fw_reset_no_pci_access, 0);
781462306a36Sopenharmony_ci
781562306a36Sopenharmony_ci			/* waiting for about 30 seconds before retry */
781662306a36Sopenharmony_ci			ssleep(30);
781762306a36Sopenharmony_ci
781862306a36Sopenharmony_ci			if (megasas_transition_to_ready(instance, 0))
781962306a36Sopenharmony_ci				goto fail_ready_state;
782062306a36Sopenharmony_ci		}
782162306a36Sopenharmony_ci
782262306a36Sopenharmony_ci		dev_info(&instance->pdev->dev,
782362306a36Sopenharmony_ci			 "FW restarted successfully from %s!\n",
782462306a36Sopenharmony_ci			 __func__);
782562306a36Sopenharmony_ci	}
782662306a36Sopenharmony_ci	if (megasas_set_dma_mask(instance))
782762306a36Sopenharmony_ci		goto fail_set_dma_mask;
782862306a36Sopenharmony_ci
782962306a36Sopenharmony_ci	/*
783062306a36Sopenharmony_ci	 * Initialize MFI Firmware
783162306a36Sopenharmony_ci	 */
783262306a36Sopenharmony_ci
783362306a36Sopenharmony_ci	atomic_set(&instance->fw_outstanding, 0);
783462306a36Sopenharmony_ci	atomic_set(&instance->ldio_outstanding, 0);
783562306a36Sopenharmony_ci
783662306a36Sopenharmony_ci	/* Now re-enable MSI-X */
783762306a36Sopenharmony_ci	if (instance->msix_vectors)
783862306a36Sopenharmony_ci		megasas_alloc_irq_vectors(instance);
783962306a36Sopenharmony_ci
784062306a36Sopenharmony_ci	if (!instance->msix_vectors) {
784162306a36Sopenharmony_ci		rval = pci_alloc_irq_vectors(instance->pdev, 1, 1,
784262306a36Sopenharmony_ci					     PCI_IRQ_LEGACY);
784362306a36Sopenharmony_ci		if (rval < 0)
784462306a36Sopenharmony_ci			goto fail_reenable_msix;
784562306a36Sopenharmony_ci	}
784662306a36Sopenharmony_ci
784762306a36Sopenharmony_ci	megasas_setup_reply_map(instance);
784862306a36Sopenharmony_ci
784962306a36Sopenharmony_ci	if (instance->adapter_type != MFI_SERIES) {
785062306a36Sopenharmony_ci		megasas_reset_reply_desc(instance);
785162306a36Sopenharmony_ci		if (megasas_ioc_init_fusion(instance)) {
785262306a36Sopenharmony_ci			megasas_free_cmds(instance);
785362306a36Sopenharmony_ci			megasas_free_cmds_fusion(instance);
785462306a36Sopenharmony_ci			goto fail_init_mfi;
785562306a36Sopenharmony_ci		}
785662306a36Sopenharmony_ci		if (!megasas_get_map_info(instance))
785762306a36Sopenharmony_ci			megasas_sync_map_info(instance);
785862306a36Sopenharmony_ci	} else {
785962306a36Sopenharmony_ci		*instance->producer = 0;
786062306a36Sopenharmony_ci		*instance->consumer = 0;
786162306a36Sopenharmony_ci		if (megasas_issue_init_mfi(instance))
786262306a36Sopenharmony_ci			goto fail_init_mfi;
786362306a36Sopenharmony_ci	}
786462306a36Sopenharmony_ci
786562306a36Sopenharmony_ci	if (megasas_get_ctrl_info(instance) != DCMD_SUCCESS)
786662306a36Sopenharmony_ci		goto fail_init_mfi;
786762306a36Sopenharmony_ci
786862306a36Sopenharmony_ci	tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
786962306a36Sopenharmony_ci		     (unsigned long)instance);
787062306a36Sopenharmony_ci
787162306a36Sopenharmony_ci	if (instance->msix_vectors ?
787262306a36Sopenharmony_ci			megasas_setup_irqs_msix(instance, 0) :
787362306a36Sopenharmony_ci			megasas_setup_irqs_ioapic(instance))
787462306a36Sopenharmony_ci		goto fail_init_mfi;
787562306a36Sopenharmony_ci
787662306a36Sopenharmony_ci	if (instance->adapter_type != MFI_SERIES)
787762306a36Sopenharmony_ci		megasas_setup_irq_poll(instance);
787862306a36Sopenharmony_ci
787962306a36Sopenharmony_ci	/* Re-launch SR-IOV heartbeat timer */
788062306a36Sopenharmony_ci	if (instance->requestorId) {
788162306a36Sopenharmony_ci		if (!megasas_sriov_start_heartbeat(instance, 0))
788262306a36Sopenharmony_ci			megasas_start_timer(instance);
788362306a36Sopenharmony_ci		else {
788462306a36Sopenharmony_ci			instance->skip_heartbeat_timer_del = 1;
788562306a36Sopenharmony_ci			goto fail_init_mfi;
788662306a36Sopenharmony_ci		}
788762306a36Sopenharmony_ci	}
788862306a36Sopenharmony_ci
788962306a36Sopenharmony_ci	instance->instancet->enable_intr(instance);
789062306a36Sopenharmony_ci	megasas_setup_jbod_map(instance);
789162306a36Sopenharmony_ci	instance->unload = 0;
789262306a36Sopenharmony_ci
789362306a36Sopenharmony_ci	/*
789462306a36Sopenharmony_ci	 * Initiate AEN (Asynchronous Event Notification)
789562306a36Sopenharmony_ci	 */
789662306a36Sopenharmony_ci	if (megasas_start_aen(instance))
789762306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "Start AEN failed\n");
789862306a36Sopenharmony_ci
789962306a36Sopenharmony_ci	/* Re-launch FW fault watchdog */
790062306a36Sopenharmony_ci	if (instance->adapter_type != MFI_SERIES)
790162306a36Sopenharmony_ci		if (megasas_fusion_start_watchdog(instance) != SUCCESS)
790262306a36Sopenharmony_ci			goto fail_start_watchdog;
790362306a36Sopenharmony_ci
790462306a36Sopenharmony_ci	return 0;
790562306a36Sopenharmony_ci
790662306a36Sopenharmony_cifail_start_watchdog:
790762306a36Sopenharmony_ci	if (instance->requestorId && !instance->skip_heartbeat_timer_del)
790862306a36Sopenharmony_ci		del_timer_sync(&instance->sriov_heartbeat_timer);
790962306a36Sopenharmony_cifail_init_mfi:
791062306a36Sopenharmony_ci	megasas_free_ctrl_dma_buffers(instance);
791162306a36Sopenharmony_ci	megasas_free_ctrl_mem(instance);
791262306a36Sopenharmony_ci	scsi_host_put(host);
791362306a36Sopenharmony_ci
791462306a36Sopenharmony_cifail_reenable_msix:
791562306a36Sopenharmony_cifail_set_dma_mask:
791662306a36Sopenharmony_cifail_ready_state:
791762306a36Sopenharmony_ci
791862306a36Sopenharmony_ci	return -ENODEV;
791962306a36Sopenharmony_ci}
792062306a36Sopenharmony_ci
792162306a36Sopenharmony_cistatic inline int
792262306a36Sopenharmony_cimegasas_wait_for_adapter_operational(struct megasas_instance *instance)
792362306a36Sopenharmony_ci{
792462306a36Sopenharmony_ci	int wait_time = MEGASAS_RESET_WAIT_TIME * 2;
792562306a36Sopenharmony_ci	int i;
792662306a36Sopenharmony_ci	u8 adp_state;
792762306a36Sopenharmony_ci
792862306a36Sopenharmony_ci	for (i = 0; i < wait_time; i++) {
792962306a36Sopenharmony_ci		adp_state = atomic_read(&instance->adprecovery);
793062306a36Sopenharmony_ci		if ((adp_state == MEGASAS_HBA_OPERATIONAL) ||
793162306a36Sopenharmony_ci		    (adp_state == MEGASAS_HW_CRITICAL_ERROR))
793262306a36Sopenharmony_ci			break;
793362306a36Sopenharmony_ci
793462306a36Sopenharmony_ci		if (!(i % MEGASAS_RESET_NOTICE_INTERVAL))
793562306a36Sopenharmony_ci			dev_notice(&instance->pdev->dev, "waiting for controller reset to finish\n");
793662306a36Sopenharmony_ci
793762306a36Sopenharmony_ci		msleep(1000);
793862306a36Sopenharmony_ci	}
793962306a36Sopenharmony_ci
794062306a36Sopenharmony_ci	if (adp_state != MEGASAS_HBA_OPERATIONAL) {
794162306a36Sopenharmony_ci		dev_info(&instance->pdev->dev,
794262306a36Sopenharmony_ci			 "%s HBA failed to become operational, adp_state %d\n",
794362306a36Sopenharmony_ci			 __func__, adp_state);
794462306a36Sopenharmony_ci		return 1;
794562306a36Sopenharmony_ci	}
794662306a36Sopenharmony_ci
794762306a36Sopenharmony_ci	return 0;
794862306a36Sopenharmony_ci}
794962306a36Sopenharmony_ci
795062306a36Sopenharmony_ci/**
795162306a36Sopenharmony_ci * megasas_detach_one -	PCI hot"un"plug entry point
795262306a36Sopenharmony_ci * @pdev:		PCI device structure
795362306a36Sopenharmony_ci */
795462306a36Sopenharmony_cistatic void megasas_detach_one(struct pci_dev *pdev)
795562306a36Sopenharmony_ci{
795662306a36Sopenharmony_ci	int i;
795762306a36Sopenharmony_ci	struct Scsi_Host *host;
795862306a36Sopenharmony_ci	struct megasas_instance *instance;
795962306a36Sopenharmony_ci	struct fusion_context *fusion;
796062306a36Sopenharmony_ci	size_t pd_seq_map_sz;
796162306a36Sopenharmony_ci
796262306a36Sopenharmony_ci	instance = pci_get_drvdata(pdev);
796362306a36Sopenharmony_ci
796462306a36Sopenharmony_ci	if (!instance)
796562306a36Sopenharmony_ci		return;
796662306a36Sopenharmony_ci
796762306a36Sopenharmony_ci	host = instance->host;
796862306a36Sopenharmony_ci	fusion = instance->ctrl_context;
796962306a36Sopenharmony_ci
797062306a36Sopenharmony_ci	/* Shutdown SR-IOV heartbeat timer */
797162306a36Sopenharmony_ci	if (instance->requestorId && !instance->skip_heartbeat_timer_del)
797262306a36Sopenharmony_ci		del_timer_sync(&instance->sriov_heartbeat_timer);
797362306a36Sopenharmony_ci
797462306a36Sopenharmony_ci	/* Stop the FW fault detection watchdog */
797562306a36Sopenharmony_ci	if (instance->adapter_type != MFI_SERIES)
797662306a36Sopenharmony_ci		megasas_fusion_stop_watchdog(instance);
797762306a36Sopenharmony_ci
797862306a36Sopenharmony_ci	if (instance->fw_crash_state != UNAVAILABLE)
797962306a36Sopenharmony_ci		megasas_free_host_crash_buffer(instance);
798062306a36Sopenharmony_ci	scsi_remove_host(instance->host);
798162306a36Sopenharmony_ci	instance->unload = 1;
798262306a36Sopenharmony_ci
798362306a36Sopenharmony_ci	if (megasas_wait_for_adapter_operational(instance))
798462306a36Sopenharmony_ci		goto skip_firing_dcmds;
798562306a36Sopenharmony_ci
798662306a36Sopenharmony_ci	megasas_flush_cache(instance);
798762306a36Sopenharmony_ci	megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
798862306a36Sopenharmony_ci
798962306a36Sopenharmony_ciskip_firing_dcmds:
799062306a36Sopenharmony_ci	/* cancel the delayed work if this work still in queue*/
799162306a36Sopenharmony_ci	if (instance->ev != NULL) {
799262306a36Sopenharmony_ci		struct megasas_aen_event *ev = instance->ev;
799362306a36Sopenharmony_ci		cancel_delayed_work_sync(&ev->hotplug_work);
799462306a36Sopenharmony_ci		instance->ev = NULL;
799562306a36Sopenharmony_ci	}
799662306a36Sopenharmony_ci
799762306a36Sopenharmony_ci	/* cancel all wait events */
799862306a36Sopenharmony_ci	wake_up_all(&instance->int_cmd_wait_q);
799962306a36Sopenharmony_ci
800062306a36Sopenharmony_ci	tasklet_kill(&instance->isr_tasklet);
800162306a36Sopenharmony_ci
800262306a36Sopenharmony_ci	/*
800362306a36Sopenharmony_ci	 * Take the instance off the instance array. Note that we will not
800462306a36Sopenharmony_ci	 * decrement the max_index. We let this array be sparse array
800562306a36Sopenharmony_ci	 */
800662306a36Sopenharmony_ci	for (i = 0; i < megasas_mgmt_info.max_index; i++) {
800762306a36Sopenharmony_ci		if (megasas_mgmt_info.instance[i] == instance) {
800862306a36Sopenharmony_ci			megasas_mgmt_info.count--;
800962306a36Sopenharmony_ci			megasas_mgmt_info.instance[i] = NULL;
801062306a36Sopenharmony_ci
801162306a36Sopenharmony_ci			break;
801262306a36Sopenharmony_ci		}
801362306a36Sopenharmony_ci	}
801462306a36Sopenharmony_ci
801562306a36Sopenharmony_ci	instance->instancet->disable_intr(instance);
801662306a36Sopenharmony_ci
801762306a36Sopenharmony_ci	megasas_destroy_irqs(instance);
801862306a36Sopenharmony_ci
801962306a36Sopenharmony_ci	if (instance->msix_vectors)
802062306a36Sopenharmony_ci		pci_free_irq_vectors(instance->pdev);
802162306a36Sopenharmony_ci
802262306a36Sopenharmony_ci	if (instance->adapter_type >= VENTURA_SERIES) {
802362306a36Sopenharmony_ci		for (i = 0; i < MAX_LOGICAL_DRIVES_EXT; ++i)
802462306a36Sopenharmony_ci			kfree(fusion->stream_detect_by_ld[i]);
802562306a36Sopenharmony_ci		kfree(fusion->stream_detect_by_ld);
802662306a36Sopenharmony_ci		fusion->stream_detect_by_ld = NULL;
802762306a36Sopenharmony_ci	}
802862306a36Sopenharmony_ci
802962306a36Sopenharmony_ci
803062306a36Sopenharmony_ci	if (instance->adapter_type != MFI_SERIES) {
803162306a36Sopenharmony_ci		megasas_release_fusion(instance);
803262306a36Sopenharmony_ci		pd_seq_map_sz =
803362306a36Sopenharmony_ci			struct_size_t(struct MR_PD_CFG_SEQ_NUM_SYNC,
803462306a36Sopenharmony_ci				      seq, MAX_PHYSICAL_DEVICES);
803562306a36Sopenharmony_ci		for (i = 0; i < 2 ; i++) {
803662306a36Sopenharmony_ci			if (fusion->ld_map[i])
803762306a36Sopenharmony_ci				dma_free_coherent(&instance->pdev->dev,
803862306a36Sopenharmony_ci						  fusion->max_map_sz,
803962306a36Sopenharmony_ci						  fusion->ld_map[i],
804062306a36Sopenharmony_ci						  fusion->ld_map_phys[i]);
804162306a36Sopenharmony_ci			if (fusion->ld_drv_map[i]) {
804262306a36Sopenharmony_ci				if (is_vmalloc_addr(fusion->ld_drv_map[i]))
804362306a36Sopenharmony_ci					vfree(fusion->ld_drv_map[i]);
804462306a36Sopenharmony_ci				else
804562306a36Sopenharmony_ci					free_pages((ulong)fusion->ld_drv_map[i],
804662306a36Sopenharmony_ci						   fusion->drv_map_pages);
804762306a36Sopenharmony_ci			}
804862306a36Sopenharmony_ci
804962306a36Sopenharmony_ci			if (fusion->pd_seq_sync[i])
805062306a36Sopenharmony_ci				dma_free_coherent(&instance->pdev->dev,
805162306a36Sopenharmony_ci					pd_seq_map_sz,
805262306a36Sopenharmony_ci					fusion->pd_seq_sync[i],
805362306a36Sopenharmony_ci					fusion->pd_seq_phys[i]);
805462306a36Sopenharmony_ci		}
805562306a36Sopenharmony_ci	} else {
805662306a36Sopenharmony_ci		megasas_release_mfi(instance);
805762306a36Sopenharmony_ci	}
805862306a36Sopenharmony_ci
805962306a36Sopenharmony_ci	if (instance->vf_affiliation)
806062306a36Sopenharmony_ci		dma_free_coherent(&pdev->dev, (MAX_LOGICAL_DRIVES + 1) *
806162306a36Sopenharmony_ci				    sizeof(struct MR_LD_VF_AFFILIATION),
806262306a36Sopenharmony_ci				    instance->vf_affiliation,
806362306a36Sopenharmony_ci				    instance->vf_affiliation_h);
806462306a36Sopenharmony_ci
806562306a36Sopenharmony_ci	if (instance->vf_affiliation_111)
806662306a36Sopenharmony_ci		dma_free_coherent(&pdev->dev,
806762306a36Sopenharmony_ci				    sizeof(struct MR_LD_VF_AFFILIATION_111),
806862306a36Sopenharmony_ci				    instance->vf_affiliation_111,
806962306a36Sopenharmony_ci				    instance->vf_affiliation_111_h);
807062306a36Sopenharmony_ci
807162306a36Sopenharmony_ci	if (instance->hb_host_mem)
807262306a36Sopenharmony_ci		dma_free_coherent(&pdev->dev, sizeof(struct MR_CTRL_HB_HOST_MEM),
807362306a36Sopenharmony_ci				    instance->hb_host_mem,
807462306a36Sopenharmony_ci				    instance->hb_host_mem_h);
807562306a36Sopenharmony_ci
807662306a36Sopenharmony_ci	megasas_free_ctrl_dma_buffers(instance);
807762306a36Sopenharmony_ci
807862306a36Sopenharmony_ci	megasas_free_ctrl_mem(instance);
807962306a36Sopenharmony_ci
808062306a36Sopenharmony_ci	megasas_destroy_debugfs(instance);
808162306a36Sopenharmony_ci
808262306a36Sopenharmony_ci	scsi_host_put(host);
808362306a36Sopenharmony_ci
808462306a36Sopenharmony_ci	pci_disable_device(pdev);
808562306a36Sopenharmony_ci}
808662306a36Sopenharmony_ci
808762306a36Sopenharmony_ci/**
808862306a36Sopenharmony_ci * megasas_shutdown -	Shutdown entry point
808962306a36Sopenharmony_ci * @pdev:		PCI device structure
809062306a36Sopenharmony_ci */
809162306a36Sopenharmony_cistatic void megasas_shutdown(struct pci_dev *pdev)
809262306a36Sopenharmony_ci{
809362306a36Sopenharmony_ci	struct megasas_instance *instance = pci_get_drvdata(pdev);
809462306a36Sopenharmony_ci
809562306a36Sopenharmony_ci	if (!instance)
809662306a36Sopenharmony_ci		return;
809762306a36Sopenharmony_ci
809862306a36Sopenharmony_ci	instance->unload = 1;
809962306a36Sopenharmony_ci
810062306a36Sopenharmony_ci	if (megasas_wait_for_adapter_operational(instance))
810162306a36Sopenharmony_ci		goto skip_firing_dcmds;
810262306a36Sopenharmony_ci
810362306a36Sopenharmony_ci	megasas_flush_cache(instance);
810462306a36Sopenharmony_ci	megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
810562306a36Sopenharmony_ci
810662306a36Sopenharmony_ciskip_firing_dcmds:
810762306a36Sopenharmony_ci	instance->instancet->disable_intr(instance);
810862306a36Sopenharmony_ci	megasas_destroy_irqs(instance);
810962306a36Sopenharmony_ci
811062306a36Sopenharmony_ci	if (instance->msix_vectors)
811162306a36Sopenharmony_ci		pci_free_irq_vectors(instance->pdev);
811262306a36Sopenharmony_ci}
811362306a36Sopenharmony_ci
811462306a36Sopenharmony_ci/*
811562306a36Sopenharmony_ci * megasas_mgmt_open -	char node "open" entry point
811662306a36Sopenharmony_ci * @inode:	char node inode
811762306a36Sopenharmony_ci * @filep:	char node file
811862306a36Sopenharmony_ci */
811962306a36Sopenharmony_cistatic int megasas_mgmt_open(struct inode *inode, struct file *filep)
812062306a36Sopenharmony_ci{
812162306a36Sopenharmony_ci	/*
812262306a36Sopenharmony_ci	 * Allow only those users with admin rights
812362306a36Sopenharmony_ci	 */
812462306a36Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN))
812562306a36Sopenharmony_ci		return -EACCES;
812662306a36Sopenharmony_ci
812762306a36Sopenharmony_ci	return 0;
812862306a36Sopenharmony_ci}
812962306a36Sopenharmony_ci
813062306a36Sopenharmony_ci/*
813162306a36Sopenharmony_ci * megasas_mgmt_fasync -	Async notifier registration from applications
813262306a36Sopenharmony_ci * @fd:		char node file descriptor number
813362306a36Sopenharmony_ci * @filep:	char node file
813462306a36Sopenharmony_ci * @mode:	notifier on/off
813562306a36Sopenharmony_ci *
813662306a36Sopenharmony_ci * This function adds the calling process to a driver global queue. When an
813762306a36Sopenharmony_ci * event occurs, SIGIO will be sent to all processes in this queue.
813862306a36Sopenharmony_ci */
813962306a36Sopenharmony_cistatic int megasas_mgmt_fasync(int fd, struct file *filep, int mode)
814062306a36Sopenharmony_ci{
814162306a36Sopenharmony_ci	int rc;
814262306a36Sopenharmony_ci
814362306a36Sopenharmony_ci	mutex_lock(&megasas_async_queue_mutex);
814462306a36Sopenharmony_ci
814562306a36Sopenharmony_ci	rc = fasync_helper(fd, filep, mode, &megasas_async_queue);
814662306a36Sopenharmony_ci
814762306a36Sopenharmony_ci	mutex_unlock(&megasas_async_queue_mutex);
814862306a36Sopenharmony_ci
814962306a36Sopenharmony_ci	if (rc >= 0) {
815062306a36Sopenharmony_ci		/* For sanity check when we get ioctl */
815162306a36Sopenharmony_ci		filep->private_data = filep;
815262306a36Sopenharmony_ci		return 0;
815362306a36Sopenharmony_ci	}
815462306a36Sopenharmony_ci
815562306a36Sopenharmony_ci	printk(KERN_DEBUG "megasas: fasync_helper failed [%d]\n", rc);
815662306a36Sopenharmony_ci
815762306a36Sopenharmony_ci	return rc;
815862306a36Sopenharmony_ci}
815962306a36Sopenharmony_ci
816062306a36Sopenharmony_ci/*
816162306a36Sopenharmony_ci * megasas_mgmt_poll -  char node "poll" entry point
816262306a36Sopenharmony_ci * @filep:	char node file
816362306a36Sopenharmony_ci * @wait:	Events to poll for
816462306a36Sopenharmony_ci */
816562306a36Sopenharmony_cistatic __poll_t megasas_mgmt_poll(struct file *file, poll_table *wait)
816662306a36Sopenharmony_ci{
816762306a36Sopenharmony_ci	__poll_t mask;
816862306a36Sopenharmony_ci	unsigned long flags;
816962306a36Sopenharmony_ci
817062306a36Sopenharmony_ci	poll_wait(file, &megasas_poll_wait, wait);
817162306a36Sopenharmony_ci	spin_lock_irqsave(&poll_aen_lock, flags);
817262306a36Sopenharmony_ci	if (megasas_poll_wait_aen)
817362306a36Sopenharmony_ci		mask = (EPOLLIN | EPOLLRDNORM);
817462306a36Sopenharmony_ci	else
817562306a36Sopenharmony_ci		mask = 0;
817662306a36Sopenharmony_ci	megasas_poll_wait_aen = 0;
817762306a36Sopenharmony_ci	spin_unlock_irqrestore(&poll_aen_lock, flags);
817862306a36Sopenharmony_ci	return mask;
817962306a36Sopenharmony_ci}
818062306a36Sopenharmony_ci
818162306a36Sopenharmony_ci/*
818262306a36Sopenharmony_ci * megasas_set_crash_dump_params_ioctl:
818362306a36Sopenharmony_ci *		Send CRASH_DUMP_MODE DCMD to all controllers
818462306a36Sopenharmony_ci * @cmd:	MFI command frame
818562306a36Sopenharmony_ci */
818662306a36Sopenharmony_ci
818762306a36Sopenharmony_cistatic int megasas_set_crash_dump_params_ioctl(struct megasas_cmd *cmd)
818862306a36Sopenharmony_ci{
818962306a36Sopenharmony_ci	struct megasas_instance *local_instance;
819062306a36Sopenharmony_ci	int i, error = 0;
819162306a36Sopenharmony_ci	int crash_support;
819262306a36Sopenharmony_ci
819362306a36Sopenharmony_ci	crash_support = cmd->frame->dcmd.mbox.w[0];
819462306a36Sopenharmony_ci
819562306a36Sopenharmony_ci	for (i = 0; i < megasas_mgmt_info.max_index; i++) {
819662306a36Sopenharmony_ci		local_instance = megasas_mgmt_info.instance[i];
819762306a36Sopenharmony_ci		if (local_instance && local_instance->crash_dump_drv_support) {
819862306a36Sopenharmony_ci			if ((atomic_read(&local_instance->adprecovery) ==
819962306a36Sopenharmony_ci				MEGASAS_HBA_OPERATIONAL) &&
820062306a36Sopenharmony_ci				!megasas_set_crash_dump_params(local_instance,
820162306a36Sopenharmony_ci					crash_support)) {
820262306a36Sopenharmony_ci				local_instance->crash_dump_app_support =
820362306a36Sopenharmony_ci					crash_support;
820462306a36Sopenharmony_ci				dev_info(&local_instance->pdev->dev,
820562306a36Sopenharmony_ci					"Application firmware crash "
820662306a36Sopenharmony_ci					"dump mode set success\n");
820762306a36Sopenharmony_ci				error = 0;
820862306a36Sopenharmony_ci			} else {
820962306a36Sopenharmony_ci				dev_info(&local_instance->pdev->dev,
821062306a36Sopenharmony_ci					"Application firmware crash "
821162306a36Sopenharmony_ci					"dump mode set failed\n");
821262306a36Sopenharmony_ci				error = -1;
821362306a36Sopenharmony_ci			}
821462306a36Sopenharmony_ci		}
821562306a36Sopenharmony_ci	}
821662306a36Sopenharmony_ci	return error;
821762306a36Sopenharmony_ci}
821862306a36Sopenharmony_ci
821962306a36Sopenharmony_ci/**
822062306a36Sopenharmony_ci * megasas_mgmt_fw_ioctl -	Issues management ioctls to FW
822162306a36Sopenharmony_ci * @instance:			Adapter soft state
822262306a36Sopenharmony_ci * @user_ioc:			User's ioctl packet
822362306a36Sopenharmony_ci * @ioc:			ioctl packet
822462306a36Sopenharmony_ci */
822562306a36Sopenharmony_cistatic int
822662306a36Sopenharmony_cimegasas_mgmt_fw_ioctl(struct megasas_instance *instance,
822762306a36Sopenharmony_ci		      struct megasas_iocpacket __user * user_ioc,
822862306a36Sopenharmony_ci		      struct megasas_iocpacket *ioc)
822962306a36Sopenharmony_ci{
823062306a36Sopenharmony_ci	struct megasas_sge64 *kern_sge64 = NULL;
823162306a36Sopenharmony_ci	struct megasas_sge32 *kern_sge32 = NULL;
823262306a36Sopenharmony_ci	struct megasas_cmd *cmd;
823362306a36Sopenharmony_ci	void *kbuff_arr[MAX_IOCTL_SGE];
823462306a36Sopenharmony_ci	dma_addr_t buf_handle = 0;
823562306a36Sopenharmony_ci	int error = 0, i;
823662306a36Sopenharmony_ci	void *sense = NULL;
823762306a36Sopenharmony_ci	dma_addr_t sense_handle;
823862306a36Sopenharmony_ci	void *sense_ptr;
823962306a36Sopenharmony_ci	u32 opcode = 0;
824062306a36Sopenharmony_ci	int ret = DCMD_SUCCESS;
824162306a36Sopenharmony_ci
824262306a36Sopenharmony_ci	memset(kbuff_arr, 0, sizeof(kbuff_arr));
824362306a36Sopenharmony_ci
824462306a36Sopenharmony_ci	if (ioc->sge_count > MAX_IOCTL_SGE) {
824562306a36Sopenharmony_ci		dev_printk(KERN_DEBUG, &instance->pdev->dev, "SGE count [%d] >  max limit [%d]\n",
824662306a36Sopenharmony_ci		       ioc->sge_count, MAX_IOCTL_SGE);
824762306a36Sopenharmony_ci		return -EINVAL;
824862306a36Sopenharmony_ci	}
824962306a36Sopenharmony_ci
825062306a36Sopenharmony_ci	if ((ioc->frame.hdr.cmd >= MFI_CMD_OP_COUNT) ||
825162306a36Sopenharmony_ci	    ((ioc->frame.hdr.cmd == MFI_CMD_NVME) &&
825262306a36Sopenharmony_ci	    !instance->support_nvme_passthru) ||
825362306a36Sopenharmony_ci	    ((ioc->frame.hdr.cmd == MFI_CMD_TOOLBOX) &&
825462306a36Sopenharmony_ci	    !instance->support_pci_lane_margining)) {
825562306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
825662306a36Sopenharmony_ci			"Received invalid ioctl command 0x%x\n",
825762306a36Sopenharmony_ci			ioc->frame.hdr.cmd);
825862306a36Sopenharmony_ci		return -ENOTSUPP;
825962306a36Sopenharmony_ci	}
826062306a36Sopenharmony_ci
826162306a36Sopenharmony_ci	cmd = megasas_get_cmd(instance);
826262306a36Sopenharmony_ci	if (!cmd) {
826362306a36Sopenharmony_ci		dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to get a cmd packet\n");
826462306a36Sopenharmony_ci		return -ENOMEM;
826562306a36Sopenharmony_ci	}
826662306a36Sopenharmony_ci
826762306a36Sopenharmony_ci	/*
826862306a36Sopenharmony_ci	 * User's IOCTL packet has 2 frames (maximum). Copy those two
826962306a36Sopenharmony_ci	 * frames into our cmd's frames. cmd->frame's context will get
827062306a36Sopenharmony_ci	 * overwritten when we copy from user's frames. So set that value
827162306a36Sopenharmony_ci	 * alone separately
827262306a36Sopenharmony_ci	 */
827362306a36Sopenharmony_ci	memcpy(cmd->frame, ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE);
827462306a36Sopenharmony_ci	cmd->frame->hdr.context = cpu_to_le32(cmd->index);
827562306a36Sopenharmony_ci	cmd->frame->hdr.pad_0 = 0;
827662306a36Sopenharmony_ci
827762306a36Sopenharmony_ci	cmd->frame->hdr.flags &= (~MFI_FRAME_IEEE);
827862306a36Sopenharmony_ci
827962306a36Sopenharmony_ci	if (instance->consistent_mask_64bit)
828062306a36Sopenharmony_ci		cmd->frame->hdr.flags |= cpu_to_le16((MFI_FRAME_SGL64 |
828162306a36Sopenharmony_ci				       MFI_FRAME_SENSE64));
828262306a36Sopenharmony_ci	else
828362306a36Sopenharmony_ci		cmd->frame->hdr.flags &= cpu_to_le16(~(MFI_FRAME_SGL64 |
828462306a36Sopenharmony_ci					       MFI_FRAME_SENSE64));
828562306a36Sopenharmony_ci
828662306a36Sopenharmony_ci	if (cmd->frame->hdr.cmd == MFI_CMD_DCMD)
828762306a36Sopenharmony_ci		opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
828862306a36Sopenharmony_ci
828962306a36Sopenharmony_ci	if (opcode == MR_DCMD_CTRL_SHUTDOWN) {
829062306a36Sopenharmony_ci		mutex_lock(&instance->reset_mutex);
829162306a36Sopenharmony_ci		if (megasas_get_ctrl_info(instance) != DCMD_SUCCESS) {
829262306a36Sopenharmony_ci			megasas_return_cmd(instance, cmd);
829362306a36Sopenharmony_ci			mutex_unlock(&instance->reset_mutex);
829462306a36Sopenharmony_ci			return -1;
829562306a36Sopenharmony_ci		}
829662306a36Sopenharmony_ci		mutex_unlock(&instance->reset_mutex);
829762306a36Sopenharmony_ci	}
829862306a36Sopenharmony_ci
829962306a36Sopenharmony_ci	if (opcode == MR_DRIVER_SET_APP_CRASHDUMP_MODE) {
830062306a36Sopenharmony_ci		error = megasas_set_crash_dump_params_ioctl(cmd);
830162306a36Sopenharmony_ci		megasas_return_cmd(instance, cmd);
830262306a36Sopenharmony_ci		return error;
830362306a36Sopenharmony_ci	}
830462306a36Sopenharmony_ci
830562306a36Sopenharmony_ci	/*
830662306a36Sopenharmony_ci	 * The management interface between applications and the fw uses
830762306a36Sopenharmony_ci	 * MFI frames. E.g, RAID configuration changes, LD property changes
830862306a36Sopenharmony_ci	 * etc are accomplishes through different kinds of MFI frames. The
830962306a36Sopenharmony_ci	 * driver needs to care only about substituting user buffers with
831062306a36Sopenharmony_ci	 * kernel buffers in SGLs. The location of SGL is embedded in the
831162306a36Sopenharmony_ci	 * struct iocpacket itself.
831262306a36Sopenharmony_ci	 */
831362306a36Sopenharmony_ci	if (instance->consistent_mask_64bit)
831462306a36Sopenharmony_ci		kern_sge64 = (struct megasas_sge64 *)
831562306a36Sopenharmony_ci			((unsigned long)cmd->frame + ioc->sgl_off);
831662306a36Sopenharmony_ci	else
831762306a36Sopenharmony_ci		kern_sge32 = (struct megasas_sge32 *)
831862306a36Sopenharmony_ci			((unsigned long)cmd->frame + ioc->sgl_off);
831962306a36Sopenharmony_ci
832062306a36Sopenharmony_ci	/*
832162306a36Sopenharmony_ci	 * For each user buffer, create a mirror buffer and copy in
832262306a36Sopenharmony_ci	 */
832362306a36Sopenharmony_ci	for (i = 0; i < ioc->sge_count; i++) {
832462306a36Sopenharmony_ci		if (!ioc->sgl[i].iov_len)
832562306a36Sopenharmony_ci			continue;
832662306a36Sopenharmony_ci
832762306a36Sopenharmony_ci		kbuff_arr[i] = dma_alloc_coherent(&instance->pdev->dev,
832862306a36Sopenharmony_ci						    ioc->sgl[i].iov_len,
832962306a36Sopenharmony_ci						    &buf_handle, GFP_KERNEL);
833062306a36Sopenharmony_ci		if (!kbuff_arr[i]) {
833162306a36Sopenharmony_ci			dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to alloc "
833262306a36Sopenharmony_ci			       "kernel SGL buffer for IOCTL\n");
833362306a36Sopenharmony_ci			error = -ENOMEM;
833462306a36Sopenharmony_ci			goto out;
833562306a36Sopenharmony_ci		}
833662306a36Sopenharmony_ci
833762306a36Sopenharmony_ci		/*
833862306a36Sopenharmony_ci		 * We don't change the dma_coherent_mask, so
833962306a36Sopenharmony_ci		 * dma_alloc_coherent only returns 32bit addresses
834062306a36Sopenharmony_ci		 */
834162306a36Sopenharmony_ci		if (instance->consistent_mask_64bit) {
834262306a36Sopenharmony_ci			kern_sge64[i].phys_addr = cpu_to_le64(buf_handle);
834362306a36Sopenharmony_ci			kern_sge64[i].length = cpu_to_le32(ioc->sgl[i].iov_len);
834462306a36Sopenharmony_ci		} else {
834562306a36Sopenharmony_ci			kern_sge32[i].phys_addr = cpu_to_le32(buf_handle);
834662306a36Sopenharmony_ci			kern_sge32[i].length = cpu_to_le32(ioc->sgl[i].iov_len);
834762306a36Sopenharmony_ci		}
834862306a36Sopenharmony_ci
834962306a36Sopenharmony_ci		/*
835062306a36Sopenharmony_ci		 * We created a kernel buffer corresponding to the
835162306a36Sopenharmony_ci		 * user buffer. Now copy in from the user buffer
835262306a36Sopenharmony_ci		 */
835362306a36Sopenharmony_ci		if (copy_from_user(kbuff_arr[i], ioc->sgl[i].iov_base,
835462306a36Sopenharmony_ci				   (u32) (ioc->sgl[i].iov_len))) {
835562306a36Sopenharmony_ci			error = -EFAULT;
835662306a36Sopenharmony_ci			goto out;
835762306a36Sopenharmony_ci		}
835862306a36Sopenharmony_ci	}
835962306a36Sopenharmony_ci
836062306a36Sopenharmony_ci	if (ioc->sense_len) {
836162306a36Sopenharmony_ci		/* make sure the pointer is part of the frame */
836262306a36Sopenharmony_ci		if (ioc->sense_off >
836362306a36Sopenharmony_ci		    (sizeof(union megasas_frame) - sizeof(__le64))) {
836462306a36Sopenharmony_ci			error = -EINVAL;
836562306a36Sopenharmony_ci			goto out;
836662306a36Sopenharmony_ci		}
836762306a36Sopenharmony_ci
836862306a36Sopenharmony_ci		sense = dma_alloc_coherent(&instance->pdev->dev, ioc->sense_len,
836962306a36Sopenharmony_ci					     &sense_handle, GFP_KERNEL);
837062306a36Sopenharmony_ci		if (!sense) {
837162306a36Sopenharmony_ci			error = -ENOMEM;
837262306a36Sopenharmony_ci			goto out;
837362306a36Sopenharmony_ci		}
837462306a36Sopenharmony_ci
837562306a36Sopenharmony_ci		/* always store 64 bits regardless of addressing */
837662306a36Sopenharmony_ci		sense_ptr = (void *)cmd->frame + ioc->sense_off;
837762306a36Sopenharmony_ci		put_unaligned_le64(sense_handle, sense_ptr);
837862306a36Sopenharmony_ci	}
837962306a36Sopenharmony_ci
838062306a36Sopenharmony_ci	/*
838162306a36Sopenharmony_ci	 * Set the sync_cmd flag so that the ISR knows not to complete this
838262306a36Sopenharmony_ci	 * cmd to the SCSI mid-layer
838362306a36Sopenharmony_ci	 */
838462306a36Sopenharmony_ci	cmd->sync_cmd = 1;
838562306a36Sopenharmony_ci
838662306a36Sopenharmony_ci	ret = megasas_issue_blocked_cmd(instance, cmd, 0);
838762306a36Sopenharmony_ci	switch (ret) {
838862306a36Sopenharmony_ci	case DCMD_INIT:
838962306a36Sopenharmony_ci	case DCMD_BUSY:
839062306a36Sopenharmony_ci		cmd->sync_cmd = 0;
839162306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
839262306a36Sopenharmony_ci			"return -EBUSY from %s %d cmd 0x%x opcode 0x%x cmd->cmd_status_drv 0x%x\n",
839362306a36Sopenharmony_ci			 __func__, __LINE__, cmd->frame->hdr.cmd, opcode,
839462306a36Sopenharmony_ci			 cmd->cmd_status_drv);
839562306a36Sopenharmony_ci		error = -EBUSY;
839662306a36Sopenharmony_ci		goto out;
839762306a36Sopenharmony_ci	}
839862306a36Sopenharmony_ci
839962306a36Sopenharmony_ci	cmd->sync_cmd = 0;
840062306a36Sopenharmony_ci
840162306a36Sopenharmony_ci	if (instance->unload == 1) {
840262306a36Sopenharmony_ci		dev_info(&instance->pdev->dev, "Driver unload is in progress "
840362306a36Sopenharmony_ci			"don't submit data to application\n");
840462306a36Sopenharmony_ci		goto out;
840562306a36Sopenharmony_ci	}
840662306a36Sopenharmony_ci	/*
840762306a36Sopenharmony_ci	 * copy out the kernel buffers to user buffers
840862306a36Sopenharmony_ci	 */
840962306a36Sopenharmony_ci	for (i = 0; i < ioc->sge_count; i++) {
841062306a36Sopenharmony_ci		if (copy_to_user(ioc->sgl[i].iov_base, kbuff_arr[i],
841162306a36Sopenharmony_ci				 ioc->sgl[i].iov_len)) {
841262306a36Sopenharmony_ci			error = -EFAULT;
841362306a36Sopenharmony_ci			goto out;
841462306a36Sopenharmony_ci		}
841562306a36Sopenharmony_ci	}
841662306a36Sopenharmony_ci
841762306a36Sopenharmony_ci	/*
841862306a36Sopenharmony_ci	 * copy out the sense
841962306a36Sopenharmony_ci	 */
842062306a36Sopenharmony_ci	if (ioc->sense_len) {
842162306a36Sopenharmony_ci		void __user *uptr;
842262306a36Sopenharmony_ci		/*
842362306a36Sopenharmony_ci		 * sense_ptr points to the location that has the user
842462306a36Sopenharmony_ci		 * sense buffer address
842562306a36Sopenharmony_ci		 */
842662306a36Sopenharmony_ci		sense_ptr = (void *)ioc->frame.raw + ioc->sense_off;
842762306a36Sopenharmony_ci		if (in_compat_syscall())
842862306a36Sopenharmony_ci			uptr = compat_ptr(get_unaligned((compat_uptr_t *)
842962306a36Sopenharmony_ci							sense_ptr));
843062306a36Sopenharmony_ci		else
843162306a36Sopenharmony_ci			uptr = get_unaligned((void __user **)sense_ptr);
843262306a36Sopenharmony_ci
843362306a36Sopenharmony_ci		if (copy_to_user(uptr, sense, ioc->sense_len)) {
843462306a36Sopenharmony_ci			dev_err(&instance->pdev->dev, "Failed to copy out to user "
843562306a36Sopenharmony_ci					"sense data\n");
843662306a36Sopenharmony_ci			error = -EFAULT;
843762306a36Sopenharmony_ci			goto out;
843862306a36Sopenharmony_ci		}
843962306a36Sopenharmony_ci	}
844062306a36Sopenharmony_ci
844162306a36Sopenharmony_ci	/*
844262306a36Sopenharmony_ci	 * copy the status codes returned by the fw
844362306a36Sopenharmony_ci	 */
844462306a36Sopenharmony_ci	if (copy_to_user(&user_ioc->frame.hdr.cmd_status,
844562306a36Sopenharmony_ci			 &cmd->frame->hdr.cmd_status, sizeof(u8))) {
844662306a36Sopenharmony_ci		dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error copying out cmd_status\n");
844762306a36Sopenharmony_ci		error = -EFAULT;
844862306a36Sopenharmony_ci	}
844962306a36Sopenharmony_ci
845062306a36Sopenharmony_ciout:
845162306a36Sopenharmony_ci	if (sense) {
845262306a36Sopenharmony_ci		dma_free_coherent(&instance->pdev->dev, ioc->sense_len,
845362306a36Sopenharmony_ci				    sense, sense_handle);
845462306a36Sopenharmony_ci	}
845562306a36Sopenharmony_ci
845662306a36Sopenharmony_ci	for (i = 0; i < ioc->sge_count; i++) {
845762306a36Sopenharmony_ci		if (kbuff_arr[i]) {
845862306a36Sopenharmony_ci			if (instance->consistent_mask_64bit)
845962306a36Sopenharmony_ci				dma_free_coherent(&instance->pdev->dev,
846062306a36Sopenharmony_ci					le32_to_cpu(kern_sge64[i].length),
846162306a36Sopenharmony_ci					kbuff_arr[i],
846262306a36Sopenharmony_ci					le64_to_cpu(kern_sge64[i].phys_addr));
846362306a36Sopenharmony_ci			else
846462306a36Sopenharmony_ci				dma_free_coherent(&instance->pdev->dev,
846562306a36Sopenharmony_ci					le32_to_cpu(kern_sge32[i].length),
846662306a36Sopenharmony_ci					kbuff_arr[i],
846762306a36Sopenharmony_ci					le32_to_cpu(kern_sge32[i].phys_addr));
846862306a36Sopenharmony_ci			kbuff_arr[i] = NULL;
846962306a36Sopenharmony_ci		}
847062306a36Sopenharmony_ci	}
847162306a36Sopenharmony_ci
847262306a36Sopenharmony_ci	megasas_return_cmd(instance, cmd);
847362306a36Sopenharmony_ci	return error;
847462306a36Sopenharmony_ci}
847562306a36Sopenharmony_ci
847662306a36Sopenharmony_cistatic struct megasas_iocpacket *
847762306a36Sopenharmony_cimegasas_compat_iocpacket_get_user(void __user *arg)
847862306a36Sopenharmony_ci{
847962306a36Sopenharmony_ci	struct megasas_iocpacket *ioc;
848062306a36Sopenharmony_ci	struct compat_megasas_iocpacket __user *cioc = arg;
848162306a36Sopenharmony_ci	size_t size;
848262306a36Sopenharmony_ci	int err = -EFAULT;
848362306a36Sopenharmony_ci	int i;
848462306a36Sopenharmony_ci
848562306a36Sopenharmony_ci	ioc = kzalloc(sizeof(*ioc), GFP_KERNEL);
848662306a36Sopenharmony_ci	if (!ioc)
848762306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
848862306a36Sopenharmony_ci	size = offsetof(struct megasas_iocpacket, frame) + sizeof(ioc->frame);
848962306a36Sopenharmony_ci	if (copy_from_user(ioc, arg, size))
849062306a36Sopenharmony_ci		goto out;
849162306a36Sopenharmony_ci
849262306a36Sopenharmony_ci	for (i = 0; i < MAX_IOCTL_SGE; i++) {
849362306a36Sopenharmony_ci		compat_uptr_t iov_base;
849462306a36Sopenharmony_ci
849562306a36Sopenharmony_ci		if (get_user(iov_base, &cioc->sgl[i].iov_base) ||
849662306a36Sopenharmony_ci		    get_user(ioc->sgl[i].iov_len, &cioc->sgl[i].iov_len))
849762306a36Sopenharmony_ci			goto out;
849862306a36Sopenharmony_ci
849962306a36Sopenharmony_ci		ioc->sgl[i].iov_base = compat_ptr(iov_base);
850062306a36Sopenharmony_ci	}
850162306a36Sopenharmony_ci
850262306a36Sopenharmony_ci	return ioc;
850362306a36Sopenharmony_ciout:
850462306a36Sopenharmony_ci	kfree(ioc);
850562306a36Sopenharmony_ci	return ERR_PTR(err);
850662306a36Sopenharmony_ci}
850762306a36Sopenharmony_ci
850862306a36Sopenharmony_cistatic int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
850962306a36Sopenharmony_ci{
851062306a36Sopenharmony_ci	struct megasas_iocpacket __user *user_ioc =
851162306a36Sopenharmony_ci	    (struct megasas_iocpacket __user *)arg;
851262306a36Sopenharmony_ci	struct megasas_iocpacket *ioc;
851362306a36Sopenharmony_ci	struct megasas_instance *instance;
851462306a36Sopenharmony_ci	int error;
851562306a36Sopenharmony_ci
851662306a36Sopenharmony_ci	if (in_compat_syscall())
851762306a36Sopenharmony_ci		ioc = megasas_compat_iocpacket_get_user(user_ioc);
851862306a36Sopenharmony_ci	else
851962306a36Sopenharmony_ci		ioc = memdup_user(user_ioc, sizeof(struct megasas_iocpacket));
852062306a36Sopenharmony_ci
852162306a36Sopenharmony_ci	if (IS_ERR(ioc))
852262306a36Sopenharmony_ci		return PTR_ERR(ioc);
852362306a36Sopenharmony_ci
852462306a36Sopenharmony_ci	instance = megasas_lookup_instance(ioc->host_no);
852562306a36Sopenharmony_ci	if (!instance) {
852662306a36Sopenharmony_ci		error = -ENODEV;
852762306a36Sopenharmony_ci		goto out_kfree_ioc;
852862306a36Sopenharmony_ci	}
852962306a36Sopenharmony_ci
853062306a36Sopenharmony_ci	/* Block ioctls in VF mode */
853162306a36Sopenharmony_ci	if (instance->requestorId && !allow_vf_ioctls) {
853262306a36Sopenharmony_ci		error = -ENODEV;
853362306a36Sopenharmony_ci		goto out_kfree_ioc;
853462306a36Sopenharmony_ci	}
853562306a36Sopenharmony_ci
853662306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
853762306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "Controller in crit error\n");
853862306a36Sopenharmony_ci		error = -ENODEV;
853962306a36Sopenharmony_ci		goto out_kfree_ioc;
854062306a36Sopenharmony_ci	}
854162306a36Sopenharmony_ci
854262306a36Sopenharmony_ci	if (instance->unload == 1) {
854362306a36Sopenharmony_ci		error = -ENODEV;
854462306a36Sopenharmony_ci		goto out_kfree_ioc;
854562306a36Sopenharmony_ci	}
854662306a36Sopenharmony_ci
854762306a36Sopenharmony_ci	if (down_interruptible(&instance->ioctl_sem)) {
854862306a36Sopenharmony_ci		error = -ERESTARTSYS;
854962306a36Sopenharmony_ci		goto out_kfree_ioc;
855062306a36Sopenharmony_ci	}
855162306a36Sopenharmony_ci
855262306a36Sopenharmony_ci	if  (megasas_wait_for_adapter_operational(instance)) {
855362306a36Sopenharmony_ci		error = -ENODEV;
855462306a36Sopenharmony_ci		goto out_up;
855562306a36Sopenharmony_ci	}
855662306a36Sopenharmony_ci
855762306a36Sopenharmony_ci	error = megasas_mgmt_fw_ioctl(instance, user_ioc, ioc);
855862306a36Sopenharmony_ciout_up:
855962306a36Sopenharmony_ci	up(&instance->ioctl_sem);
856062306a36Sopenharmony_ci
856162306a36Sopenharmony_ciout_kfree_ioc:
856262306a36Sopenharmony_ci	kfree(ioc);
856362306a36Sopenharmony_ci	return error;
856462306a36Sopenharmony_ci}
856562306a36Sopenharmony_ci
856662306a36Sopenharmony_cistatic int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
856762306a36Sopenharmony_ci{
856862306a36Sopenharmony_ci	struct megasas_instance *instance;
856962306a36Sopenharmony_ci	struct megasas_aen aen;
857062306a36Sopenharmony_ci	int error;
857162306a36Sopenharmony_ci
857262306a36Sopenharmony_ci	if (file->private_data != file) {
857362306a36Sopenharmony_ci		printk(KERN_DEBUG "megasas: fasync_helper was not "
857462306a36Sopenharmony_ci		       "called first\n");
857562306a36Sopenharmony_ci		return -EINVAL;
857662306a36Sopenharmony_ci	}
857762306a36Sopenharmony_ci
857862306a36Sopenharmony_ci	if (copy_from_user(&aen, (void __user *)arg, sizeof(aen)))
857962306a36Sopenharmony_ci		return -EFAULT;
858062306a36Sopenharmony_ci
858162306a36Sopenharmony_ci	instance = megasas_lookup_instance(aen.host_no);
858262306a36Sopenharmony_ci
858362306a36Sopenharmony_ci	if (!instance)
858462306a36Sopenharmony_ci		return -ENODEV;
858562306a36Sopenharmony_ci
858662306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
858762306a36Sopenharmony_ci		return -ENODEV;
858862306a36Sopenharmony_ci	}
858962306a36Sopenharmony_ci
859062306a36Sopenharmony_ci	if (instance->unload == 1) {
859162306a36Sopenharmony_ci		return -ENODEV;
859262306a36Sopenharmony_ci	}
859362306a36Sopenharmony_ci
859462306a36Sopenharmony_ci	if  (megasas_wait_for_adapter_operational(instance))
859562306a36Sopenharmony_ci		return -ENODEV;
859662306a36Sopenharmony_ci
859762306a36Sopenharmony_ci	mutex_lock(&instance->reset_mutex);
859862306a36Sopenharmony_ci	error = megasas_register_aen(instance, aen.seq_num,
859962306a36Sopenharmony_ci				     aen.class_locale_word);
860062306a36Sopenharmony_ci	mutex_unlock(&instance->reset_mutex);
860162306a36Sopenharmony_ci	return error;
860262306a36Sopenharmony_ci}
860362306a36Sopenharmony_ci
860462306a36Sopenharmony_ci/**
860562306a36Sopenharmony_ci * megasas_mgmt_ioctl -	char node ioctl entry point
860662306a36Sopenharmony_ci * @file:	char device file pointer
860762306a36Sopenharmony_ci * @cmd:	ioctl command
860862306a36Sopenharmony_ci * @arg:	ioctl command arguments address
860962306a36Sopenharmony_ci */
861062306a36Sopenharmony_cistatic long
861162306a36Sopenharmony_cimegasas_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
861262306a36Sopenharmony_ci{
861362306a36Sopenharmony_ci	switch (cmd) {
861462306a36Sopenharmony_ci	case MEGASAS_IOC_FIRMWARE:
861562306a36Sopenharmony_ci		return megasas_mgmt_ioctl_fw(file, arg);
861662306a36Sopenharmony_ci
861762306a36Sopenharmony_ci	case MEGASAS_IOC_GET_AEN:
861862306a36Sopenharmony_ci		return megasas_mgmt_ioctl_aen(file, arg);
861962306a36Sopenharmony_ci	}
862062306a36Sopenharmony_ci
862162306a36Sopenharmony_ci	return -ENOTTY;
862262306a36Sopenharmony_ci}
862362306a36Sopenharmony_ci
862462306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
862562306a36Sopenharmony_cistatic long
862662306a36Sopenharmony_cimegasas_mgmt_compat_ioctl(struct file *file, unsigned int cmd,
862762306a36Sopenharmony_ci			  unsigned long arg)
862862306a36Sopenharmony_ci{
862962306a36Sopenharmony_ci	switch (cmd) {
863062306a36Sopenharmony_ci	case MEGASAS_IOC_FIRMWARE32:
863162306a36Sopenharmony_ci		return megasas_mgmt_ioctl_fw(file, arg);
863262306a36Sopenharmony_ci	case MEGASAS_IOC_GET_AEN:
863362306a36Sopenharmony_ci		return megasas_mgmt_ioctl_aen(file, arg);
863462306a36Sopenharmony_ci	}
863562306a36Sopenharmony_ci
863662306a36Sopenharmony_ci	return -ENOTTY;
863762306a36Sopenharmony_ci}
863862306a36Sopenharmony_ci#endif
863962306a36Sopenharmony_ci
864062306a36Sopenharmony_ci/*
864162306a36Sopenharmony_ci * File operations structure for management interface
864262306a36Sopenharmony_ci */
864362306a36Sopenharmony_cistatic const struct file_operations megasas_mgmt_fops = {
864462306a36Sopenharmony_ci	.owner = THIS_MODULE,
864562306a36Sopenharmony_ci	.open = megasas_mgmt_open,
864662306a36Sopenharmony_ci	.fasync = megasas_mgmt_fasync,
864762306a36Sopenharmony_ci	.unlocked_ioctl = megasas_mgmt_ioctl,
864862306a36Sopenharmony_ci	.poll = megasas_mgmt_poll,
864962306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
865062306a36Sopenharmony_ci	.compat_ioctl = megasas_mgmt_compat_ioctl,
865162306a36Sopenharmony_ci#endif
865262306a36Sopenharmony_ci	.llseek = noop_llseek,
865362306a36Sopenharmony_ci};
865462306a36Sopenharmony_ci
865562306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(megasas_pm_ops, megasas_suspend, megasas_resume);
865662306a36Sopenharmony_ci
865762306a36Sopenharmony_ci/*
865862306a36Sopenharmony_ci * PCI hotplug support registration structure
865962306a36Sopenharmony_ci */
866062306a36Sopenharmony_cistatic struct pci_driver megasas_pci_driver = {
866162306a36Sopenharmony_ci
866262306a36Sopenharmony_ci	.name = "megaraid_sas",
866362306a36Sopenharmony_ci	.id_table = megasas_pci_table,
866462306a36Sopenharmony_ci	.probe = megasas_probe_one,
866562306a36Sopenharmony_ci	.remove = megasas_detach_one,
866662306a36Sopenharmony_ci	.driver.pm = &megasas_pm_ops,
866762306a36Sopenharmony_ci	.shutdown = megasas_shutdown,
866862306a36Sopenharmony_ci};
866962306a36Sopenharmony_ci
867062306a36Sopenharmony_ci/*
867162306a36Sopenharmony_ci * Sysfs driver attributes
867262306a36Sopenharmony_ci */
867362306a36Sopenharmony_cistatic ssize_t version_show(struct device_driver *dd, char *buf)
867462306a36Sopenharmony_ci{
867562306a36Sopenharmony_ci	return snprintf(buf, strlen(MEGASAS_VERSION) + 2, "%s\n",
867662306a36Sopenharmony_ci			MEGASAS_VERSION);
867762306a36Sopenharmony_ci}
867862306a36Sopenharmony_cistatic DRIVER_ATTR_RO(version);
867962306a36Sopenharmony_ci
868062306a36Sopenharmony_cistatic ssize_t release_date_show(struct device_driver *dd, char *buf)
868162306a36Sopenharmony_ci{
868262306a36Sopenharmony_ci	return snprintf(buf, strlen(MEGASAS_RELDATE) + 2, "%s\n",
868362306a36Sopenharmony_ci		MEGASAS_RELDATE);
868462306a36Sopenharmony_ci}
868562306a36Sopenharmony_cistatic DRIVER_ATTR_RO(release_date);
868662306a36Sopenharmony_ci
868762306a36Sopenharmony_cistatic ssize_t support_poll_for_event_show(struct device_driver *dd, char *buf)
868862306a36Sopenharmony_ci{
868962306a36Sopenharmony_ci	return sprintf(buf, "%u\n", support_poll_for_event);
869062306a36Sopenharmony_ci}
869162306a36Sopenharmony_cistatic DRIVER_ATTR_RO(support_poll_for_event);
869262306a36Sopenharmony_ci
869362306a36Sopenharmony_cistatic ssize_t support_device_change_show(struct device_driver *dd, char *buf)
869462306a36Sopenharmony_ci{
869562306a36Sopenharmony_ci	return sprintf(buf, "%u\n", support_device_change);
869662306a36Sopenharmony_ci}
869762306a36Sopenharmony_cistatic DRIVER_ATTR_RO(support_device_change);
869862306a36Sopenharmony_ci
869962306a36Sopenharmony_cistatic ssize_t dbg_lvl_show(struct device_driver *dd, char *buf)
870062306a36Sopenharmony_ci{
870162306a36Sopenharmony_ci	return sprintf(buf, "%u\n", megasas_dbg_lvl);
870262306a36Sopenharmony_ci}
870362306a36Sopenharmony_ci
870462306a36Sopenharmony_cistatic ssize_t dbg_lvl_store(struct device_driver *dd, const char *buf,
870562306a36Sopenharmony_ci			     size_t count)
870662306a36Sopenharmony_ci{
870762306a36Sopenharmony_ci	int retval = count;
870862306a36Sopenharmony_ci
870962306a36Sopenharmony_ci	if (sscanf(buf, "%u", &megasas_dbg_lvl) < 1) {
871062306a36Sopenharmony_ci		printk(KERN_ERR "megasas: could not set dbg_lvl\n");
871162306a36Sopenharmony_ci		retval = -EINVAL;
871262306a36Sopenharmony_ci	}
871362306a36Sopenharmony_ci	return retval;
871462306a36Sopenharmony_ci}
871562306a36Sopenharmony_cistatic DRIVER_ATTR_RW(dbg_lvl);
871662306a36Sopenharmony_ci
871762306a36Sopenharmony_cistatic ssize_t
871862306a36Sopenharmony_cisupport_nvme_encapsulation_show(struct device_driver *dd, char *buf)
871962306a36Sopenharmony_ci{
872062306a36Sopenharmony_ci	return sprintf(buf, "%u\n", support_nvme_encapsulation);
872162306a36Sopenharmony_ci}
872262306a36Sopenharmony_ci
872362306a36Sopenharmony_cistatic DRIVER_ATTR_RO(support_nvme_encapsulation);
872462306a36Sopenharmony_ci
872562306a36Sopenharmony_cistatic ssize_t
872662306a36Sopenharmony_cisupport_pci_lane_margining_show(struct device_driver *dd, char *buf)
872762306a36Sopenharmony_ci{
872862306a36Sopenharmony_ci	return sprintf(buf, "%u\n", support_pci_lane_margining);
872962306a36Sopenharmony_ci}
873062306a36Sopenharmony_ci
873162306a36Sopenharmony_cistatic DRIVER_ATTR_RO(support_pci_lane_margining);
873262306a36Sopenharmony_ci
873362306a36Sopenharmony_cistatic inline void megasas_remove_scsi_device(struct scsi_device *sdev)
873462306a36Sopenharmony_ci{
873562306a36Sopenharmony_ci	sdev_printk(KERN_INFO, sdev, "SCSI device is removed\n");
873662306a36Sopenharmony_ci	scsi_remove_device(sdev);
873762306a36Sopenharmony_ci	scsi_device_put(sdev);
873862306a36Sopenharmony_ci}
873962306a36Sopenharmony_ci
874062306a36Sopenharmony_ci/**
874162306a36Sopenharmony_ci * megasas_update_device_list -	Update the PD and LD device list from FW
874262306a36Sopenharmony_ci *				after an AEN event notification
874362306a36Sopenharmony_ci * @instance:			Adapter soft state
874462306a36Sopenharmony_ci * @event_type:			Indicates type of event (PD or LD event)
874562306a36Sopenharmony_ci *
874662306a36Sopenharmony_ci * @return:			Success or failure
874762306a36Sopenharmony_ci *
874862306a36Sopenharmony_ci * Issue DCMDs to Firmware to update the internal device list in driver.
874962306a36Sopenharmony_ci * Based on the FW support, driver sends the HOST_DEVICE_LIST or combination
875062306a36Sopenharmony_ci * of PD_LIST/LD_LIST_QUERY DCMDs to get the device list.
875162306a36Sopenharmony_ci */
875262306a36Sopenharmony_cistatic
875362306a36Sopenharmony_ciint megasas_update_device_list(struct megasas_instance *instance,
875462306a36Sopenharmony_ci			       int event_type)
875562306a36Sopenharmony_ci{
875662306a36Sopenharmony_ci	int dcmd_ret;
875762306a36Sopenharmony_ci
875862306a36Sopenharmony_ci	if (instance->enable_fw_dev_list) {
875962306a36Sopenharmony_ci		return megasas_host_device_list_query(instance, false);
876062306a36Sopenharmony_ci	} else {
876162306a36Sopenharmony_ci		if (event_type & SCAN_PD_CHANNEL) {
876262306a36Sopenharmony_ci			dcmd_ret = megasas_get_pd_list(instance);
876362306a36Sopenharmony_ci			if (dcmd_ret != DCMD_SUCCESS)
876462306a36Sopenharmony_ci				return dcmd_ret;
876562306a36Sopenharmony_ci		}
876662306a36Sopenharmony_ci
876762306a36Sopenharmony_ci		if (event_type & SCAN_VD_CHANNEL) {
876862306a36Sopenharmony_ci			if (!instance->requestorId ||
876962306a36Sopenharmony_ci			megasas_get_ld_vf_affiliation(instance, 0)) {
877062306a36Sopenharmony_ci				return megasas_ld_list_query(instance,
877162306a36Sopenharmony_ci						MR_LD_QUERY_TYPE_EXPOSED_TO_HOST);
877262306a36Sopenharmony_ci			}
877362306a36Sopenharmony_ci		}
877462306a36Sopenharmony_ci	}
877562306a36Sopenharmony_ci	return DCMD_SUCCESS;
877662306a36Sopenharmony_ci}
877762306a36Sopenharmony_ci
877862306a36Sopenharmony_ci/**
877962306a36Sopenharmony_ci * megasas_add_remove_devices -	Add/remove devices to SCSI mid-layer
878062306a36Sopenharmony_ci *				after an AEN event notification
878162306a36Sopenharmony_ci * @instance:			Adapter soft state
878262306a36Sopenharmony_ci * @scan_type:			Indicates type of devices (PD/LD) to add
878362306a36Sopenharmony_ci * @return			void
878462306a36Sopenharmony_ci */
878562306a36Sopenharmony_cistatic
878662306a36Sopenharmony_civoid megasas_add_remove_devices(struct megasas_instance *instance,
878762306a36Sopenharmony_ci				int scan_type)
878862306a36Sopenharmony_ci{
878962306a36Sopenharmony_ci	int i, j;
879062306a36Sopenharmony_ci	u16 pd_index = 0;
879162306a36Sopenharmony_ci	u16 ld_index = 0;
879262306a36Sopenharmony_ci	u16 channel = 0, id = 0;
879362306a36Sopenharmony_ci	struct Scsi_Host *host;
879462306a36Sopenharmony_ci	struct scsi_device *sdev1;
879562306a36Sopenharmony_ci	struct MR_HOST_DEVICE_LIST *targetid_list = NULL;
879662306a36Sopenharmony_ci	struct MR_HOST_DEVICE_LIST_ENTRY *targetid_entry = NULL;
879762306a36Sopenharmony_ci
879862306a36Sopenharmony_ci	host = instance->host;
879962306a36Sopenharmony_ci
880062306a36Sopenharmony_ci	if (instance->enable_fw_dev_list) {
880162306a36Sopenharmony_ci		targetid_list = instance->host_device_list_buf;
880262306a36Sopenharmony_ci		for (i = 0; i < targetid_list->count; i++) {
880362306a36Sopenharmony_ci			targetid_entry = &targetid_list->host_device_list[i];
880462306a36Sopenharmony_ci			if (targetid_entry->flags.u.bits.is_sys_pd) {
880562306a36Sopenharmony_ci				channel = le16_to_cpu(targetid_entry->target_id) /
880662306a36Sopenharmony_ci						MEGASAS_MAX_DEV_PER_CHANNEL;
880762306a36Sopenharmony_ci				id = le16_to_cpu(targetid_entry->target_id) %
880862306a36Sopenharmony_ci						MEGASAS_MAX_DEV_PER_CHANNEL;
880962306a36Sopenharmony_ci			} else {
881062306a36Sopenharmony_ci				channel = MEGASAS_MAX_PD_CHANNELS +
881162306a36Sopenharmony_ci					  (le16_to_cpu(targetid_entry->target_id) /
881262306a36Sopenharmony_ci					   MEGASAS_MAX_DEV_PER_CHANNEL);
881362306a36Sopenharmony_ci				id = le16_to_cpu(targetid_entry->target_id) %
881462306a36Sopenharmony_ci						MEGASAS_MAX_DEV_PER_CHANNEL;
881562306a36Sopenharmony_ci			}
881662306a36Sopenharmony_ci			sdev1 = scsi_device_lookup(host, channel, id, 0);
881762306a36Sopenharmony_ci			if (!sdev1) {
881862306a36Sopenharmony_ci				scsi_add_device(host, channel, id, 0);
881962306a36Sopenharmony_ci			} else {
882062306a36Sopenharmony_ci				scsi_device_put(sdev1);
882162306a36Sopenharmony_ci			}
882262306a36Sopenharmony_ci		}
882362306a36Sopenharmony_ci	}
882462306a36Sopenharmony_ci
882562306a36Sopenharmony_ci	if (scan_type & SCAN_PD_CHANNEL) {
882662306a36Sopenharmony_ci		for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
882762306a36Sopenharmony_ci			for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
882862306a36Sopenharmony_ci				pd_index = i * MEGASAS_MAX_DEV_PER_CHANNEL + j;
882962306a36Sopenharmony_ci				sdev1 = scsi_device_lookup(host, i, j, 0);
883062306a36Sopenharmony_ci				if (instance->pd_list[pd_index].driveState ==
883162306a36Sopenharmony_ci							MR_PD_STATE_SYSTEM) {
883262306a36Sopenharmony_ci					if (!sdev1)
883362306a36Sopenharmony_ci						scsi_add_device(host, i, j, 0);
883462306a36Sopenharmony_ci					else
883562306a36Sopenharmony_ci						scsi_device_put(sdev1);
883662306a36Sopenharmony_ci				} else {
883762306a36Sopenharmony_ci					if (sdev1)
883862306a36Sopenharmony_ci						megasas_remove_scsi_device(sdev1);
883962306a36Sopenharmony_ci				}
884062306a36Sopenharmony_ci			}
884162306a36Sopenharmony_ci		}
884262306a36Sopenharmony_ci	}
884362306a36Sopenharmony_ci
884462306a36Sopenharmony_ci	if (scan_type & SCAN_VD_CHANNEL) {
884562306a36Sopenharmony_ci		for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
884662306a36Sopenharmony_ci			for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
884762306a36Sopenharmony_ci				ld_index = (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
884862306a36Sopenharmony_ci				sdev1 = scsi_device_lookup(host,
884962306a36Sopenharmony_ci						MEGASAS_MAX_PD_CHANNELS + i, j, 0);
885062306a36Sopenharmony_ci				if (instance->ld_ids[ld_index] != 0xff) {
885162306a36Sopenharmony_ci					if (!sdev1)
885262306a36Sopenharmony_ci						scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
885362306a36Sopenharmony_ci					else
885462306a36Sopenharmony_ci						scsi_device_put(sdev1);
885562306a36Sopenharmony_ci				} else {
885662306a36Sopenharmony_ci					if (sdev1)
885762306a36Sopenharmony_ci						megasas_remove_scsi_device(sdev1);
885862306a36Sopenharmony_ci				}
885962306a36Sopenharmony_ci			}
886062306a36Sopenharmony_ci		}
886162306a36Sopenharmony_ci	}
886262306a36Sopenharmony_ci
886362306a36Sopenharmony_ci}
886462306a36Sopenharmony_ci
886562306a36Sopenharmony_cistatic void
886662306a36Sopenharmony_cimegasas_aen_polling(struct work_struct *work)
886762306a36Sopenharmony_ci{
886862306a36Sopenharmony_ci	struct megasas_aen_event *ev =
886962306a36Sopenharmony_ci		container_of(work, struct megasas_aen_event, hotplug_work.work);
887062306a36Sopenharmony_ci	struct megasas_instance *instance = ev->instance;
887162306a36Sopenharmony_ci	union megasas_evt_class_locale class_locale;
887262306a36Sopenharmony_ci	int event_type = 0;
887362306a36Sopenharmony_ci	u32 seq_num;
887462306a36Sopenharmony_ci	u16 ld_target_id;
887562306a36Sopenharmony_ci	int error;
887662306a36Sopenharmony_ci	u8  dcmd_ret = DCMD_SUCCESS;
887762306a36Sopenharmony_ci	struct scsi_device *sdev1;
887862306a36Sopenharmony_ci
887962306a36Sopenharmony_ci	if (!instance) {
888062306a36Sopenharmony_ci		printk(KERN_ERR "invalid instance!\n");
888162306a36Sopenharmony_ci		kfree(ev);
888262306a36Sopenharmony_ci		return;
888362306a36Sopenharmony_ci	}
888462306a36Sopenharmony_ci
888562306a36Sopenharmony_ci	/* Don't run the event workqueue thread if OCR is running */
888662306a36Sopenharmony_ci	mutex_lock(&instance->reset_mutex);
888762306a36Sopenharmony_ci
888862306a36Sopenharmony_ci	instance->ev = NULL;
888962306a36Sopenharmony_ci	if (instance->evt_detail) {
889062306a36Sopenharmony_ci		megasas_decode_evt(instance);
889162306a36Sopenharmony_ci
889262306a36Sopenharmony_ci		switch (le32_to_cpu(instance->evt_detail->code)) {
889362306a36Sopenharmony_ci
889462306a36Sopenharmony_ci		case MR_EVT_PD_INSERTED:
889562306a36Sopenharmony_ci		case MR_EVT_PD_REMOVED:
889662306a36Sopenharmony_ci			event_type = SCAN_PD_CHANNEL;
889762306a36Sopenharmony_ci			break;
889862306a36Sopenharmony_ci
889962306a36Sopenharmony_ci		case MR_EVT_LD_OFFLINE:
890062306a36Sopenharmony_ci		case MR_EVT_LD_DELETED:
890162306a36Sopenharmony_ci			ld_target_id = instance->evt_detail->args.ld.target_id;
890262306a36Sopenharmony_ci			sdev1 = scsi_device_lookup(instance->host,
890362306a36Sopenharmony_ci						   MEGASAS_MAX_PD_CHANNELS +
890462306a36Sopenharmony_ci						   (ld_target_id / MEGASAS_MAX_DEV_PER_CHANNEL),
890562306a36Sopenharmony_ci						   (ld_target_id % MEGASAS_MAX_DEV_PER_CHANNEL),
890662306a36Sopenharmony_ci						   0);
890762306a36Sopenharmony_ci			if (sdev1)
890862306a36Sopenharmony_ci				megasas_remove_scsi_device(sdev1);
890962306a36Sopenharmony_ci
891062306a36Sopenharmony_ci			event_type = SCAN_VD_CHANNEL;
891162306a36Sopenharmony_ci			break;
891262306a36Sopenharmony_ci		case MR_EVT_LD_CREATED:
891362306a36Sopenharmony_ci			event_type = SCAN_VD_CHANNEL;
891462306a36Sopenharmony_ci			break;
891562306a36Sopenharmony_ci
891662306a36Sopenharmony_ci		case MR_EVT_CFG_CLEARED:
891762306a36Sopenharmony_ci		case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
891862306a36Sopenharmony_ci		case MR_EVT_FOREIGN_CFG_IMPORTED:
891962306a36Sopenharmony_ci		case MR_EVT_LD_STATE_CHANGE:
892062306a36Sopenharmony_ci			event_type = SCAN_PD_CHANNEL | SCAN_VD_CHANNEL;
892162306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "scanning for scsi%d...\n",
892262306a36Sopenharmony_ci				instance->host->host_no);
892362306a36Sopenharmony_ci			break;
892462306a36Sopenharmony_ci
892562306a36Sopenharmony_ci		case MR_EVT_CTRL_PROP_CHANGED:
892662306a36Sopenharmony_ci			dcmd_ret = megasas_get_ctrl_info(instance);
892762306a36Sopenharmony_ci			if (dcmd_ret == DCMD_SUCCESS &&
892862306a36Sopenharmony_ci			    instance->snapdump_wait_time) {
892962306a36Sopenharmony_ci				megasas_get_snapdump_properties(instance);
893062306a36Sopenharmony_ci				dev_info(&instance->pdev->dev,
893162306a36Sopenharmony_ci					 "Snap dump wait time\t: %d\n",
893262306a36Sopenharmony_ci					 instance->snapdump_wait_time);
893362306a36Sopenharmony_ci			}
893462306a36Sopenharmony_ci			break;
893562306a36Sopenharmony_ci		default:
893662306a36Sopenharmony_ci			event_type = 0;
893762306a36Sopenharmony_ci			break;
893862306a36Sopenharmony_ci		}
893962306a36Sopenharmony_ci	} else {
894062306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "invalid evt_detail!\n");
894162306a36Sopenharmony_ci		mutex_unlock(&instance->reset_mutex);
894262306a36Sopenharmony_ci		kfree(ev);
894362306a36Sopenharmony_ci		return;
894462306a36Sopenharmony_ci	}
894562306a36Sopenharmony_ci
894662306a36Sopenharmony_ci	if (event_type)
894762306a36Sopenharmony_ci		dcmd_ret = megasas_update_device_list(instance, event_type);
894862306a36Sopenharmony_ci
894962306a36Sopenharmony_ci	mutex_unlock(&instance->reset_mutex);
895062306a36Sopenharmony_ci
895162306a36Sopenharmony_ci	if (event_type && dcmd_ret == DCMD_SUCCESS)
895262306a36Sopenharmony_ci		megasas_add_remove_devices(instance, event_type);
895362306a36Sopenharmony_ci
895462306a36Sopenharmony_ci	if (dcmd_ret == DCMD_SUCCESS)
895562306a36Sopenharmony_ci		seq_num = le32_to_cpu(instance->evt_detail->seq_num) + 1;
895662306a36Sopenharmony_ci	else
895762306a36Sopenharmony_ci		seq_num = instance->last_seq_num;
895862306a36Sopenharmony_ci
895962306a36Sopenharmony_ci	/* Register AEN with FW for latest sequence number plus 1 */
896062306a36Sopenharmony_ci	class_locale.members.reserved = 0;
896162306a36Sopenharmony_ci	class_locale.members.locale = MR_EVT_LOCALE_ALL;
896262306a36Sopenharmony_ci	class_locale.members.class = MR_EVT_CLASS_DEBUG;
896362306a36Sopenharmony_ci
896462306a36Sopenharmony_ci	if (instance->aen_cmd != NULL) {
896562306a36Sopenharmony_ci		kfree(ev);
896662306a36Sopenharmony_ci		return;
896762306a36Sopenharmony_ci	}
896862306a36Sopenharmony_ci
896962306a36Sopenharmony_ci	mutex_lock(&instance->reset_mutex);
897062306a36Sopenharmony_ci	error = megasas_register_aen(instance, seq_num,
897162306a36Sopenharmony_ci					class_locale.word);
897262306a36Sopenharmony_ci	if (error)
897362306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
897462306a36Sopenharmony_ci			"register aen failed error %x\n", error);
897562306a36Sopenharmony_ci
897662306a36Sopenharmony_ci	mutex_unlock(&instance->reset_mutex);
897762306a36Sopenharmony_ci	kfree(ev);
897862306a36Sopenharmony_ci}
897962306a36Sopenharmony_ci
898062306a36Sopenharmony_ci/**
898162306a36Sopenharmony_ci * megasas_init - Driver load entry point
898262306a36Sopenharmony_ci */
898362306a36Sopenharmony_cistatic int __init megasas_init(void)
898462306a36Sopenharmony_ci{
898562306a36Sopenharmony_ci	int rval;
898662306a36Sopenharmony_ci
898762306a36Sopenharmony_ci	/*
898862306a36Sopenharmony_ci	 * Booted in kdump kernel, minimize memory footprints by
898962306a36Sopenharmony_ci	 * disabling few features
899062306a36Sopenharmony_ci	 */
899162306a36Sopenharmony_ci	if (reset_devices) {
899262306a36Sopenharmony_ci		msix_vectors = 1;
899362306a36Sopenharmony_ci		rdpq_enable = 0;
899462306a36Sopenharmony_ci		dual_qdepth_disable = 1;
899562306a36Sopenharmony_ci		poll_queues = 0;
899662306a36Sopenharmony_ci	}
899762306a36Sopenharmony_ci
899862306a36Sopenharmony_ci	/*
899962306a36Sopenharmony_ci	 * Announce driver version and other information
900062306a36Sopenharmony_ci	 */
900162306a36Sopenharmony_ci	pr_info("megasas: %s\n", MEGASAS_VERSION);
900262306a36Sopenharmony_ci
900362306a36Sopenharmony_ci	megasas_dbg_lvl = 0;
900462306a36Sopenharmony_ci	support_poll_for_event = 2;
900562306a36Sopenharmony_ci	support_device_change = 1;
900662306a36Sopenharmony_ci	support_nvme_encapsulation = true;
900762306a36Sopenharmony_ci	support_pci_lane_margining = true;
900862306a36Sopenharmony_ci
900962306a36Sopenharmony_ci	memset(&megasas_mgmt_info, 0, sizeof(megasas_mgmt_info));
901062306a36Sopenharmony_ci
901162306a36Sopenharmony_ci	/*
901262306a36Sopenharmony_ci	 * Register character device node
901362306a36Sopenharmony_ci	 */
901462306a36Sopenharmony_ci	rval = register_chrdev(0, "megaraid_sas_ioctl", &megasas_mgmt_fops);
901562306a36Sopenharmony_ci
901662306a36Sopenharmony_ci	if (rval < 0) {
901762306a36Sopenharmony_ci		printk(KERN_DEBUG "megasas: failed to open device node\n");
901862306a36Sopenharmony_ci		return rval;
901962306a36Sopenharmony_ci	}
902062306a36Sopenharmony_ci
902162306a36Sopenharmony_ci	megasas_mgmt_majorno = rval;
902262306a36Sopenharmony_ci
902362306a36Sopenharmony_ci	megasas_init_debugfs();
902462306a36Sopenharmony_ci
902562306a36Sopenharmony_ci	/*
902662306a36Sopenharmony_ci	 * Register ourselves as PCI hotplug module
902762306a36Sopenharmony_ci	 */
902862306a36Sopenharmony_ci	rval = pci_register_driver(&megasas_pci_driver);
902962306a36Sopenharmony_ci
903062306a36Sopenharmony_ci	if (rval) {
903162306a36Sopenharmony_ci		printk(KERN_DEBUG "megasas: PCI hotplug registration failed \n");
903262306a36Sopenharmony_ci		goto err_pcidrv;
903362306a36Sopenharmony_ci	}
903462306a36Sopenharmony_ci
903562306a36Sopenharmony_ci	if ((event_log_level < MFI_EVT_CLASS_DEBUG) ||
903662306a36Sopenharmony_ci	    (event_log_level > MFI_EVT_CLASS_DEAD)) {
903762306a36Sopenharmony_ci		pr_warn("megaraid_sas: provided event log level is out of range, setting it to default 2(CLASS_CRITICAL), permissible range is: -2 to 4\n");
903862306a36Sopenharmony_ci		event_log_level = MFI_EVT_CLASS_CRITICAL;
903962306a36Sopenharmony_ci	}
904062306a36Sopenharmony_ci
904162306a36Sopenharmony_ci	rval = driver_create_file(&megasas_pci_driver.driver,
904262306a36Sopenharmony_ci				  &driver_attr_version);
904362306a36Sopenharmony_ci	if (rval)
904462306a36Sopenharmony_ci		goto err_dcf_attr_ver;
904562306a36Sopenharmony_ci
904662306a36Sopenharmony_ci	rval = driver_create_file(&megasas_pci_driver.driver,
904762306a36Sopenharmony_ci				  &driver_attr_release_date);
904862306a36Sopenharmony_ci	if (rval)
904962306a36Sopenharmony_ci		goto err_dcf_rel_date;
905062306a36Sopenharmony_ci
905162306a36Sopenharmony_ci	rval = driver_create_file(&megasas_pci_driver.driver,
905262306a36Sopenharmony_ci				&driver_attr_support_poll_for_event);
905362306a36Sopenharmony_ci	if (rval)
905462306a36Sopenharmony_ci		goto err_dcf_support_poll_for_event;
905562306a36Sopenharmony_ci
905662306a36Sopenharmony_ci	rval = driver_create_file(&megasas_pci_driver.driver,
905762306a36Sopenharmony_ci				  &driver_attr_dbg_lvl);
905862306a36Sopenharmony_ci	if (rval)
905962306a36Sopenharmony_ci		goto err_dcf_dbg_lvl;
906062306a36Sopenharmony_ci	rval = driver_create_file(&megasas_pci_driver.driver,
906162306a36Sopenharmony_ci				&driver_attr_support_device_change);
906262306a36Sopenharmony_ci	if (rval)
906362306a36Sopenharmony_ci		goto err_dcf_support_device_change;
906462306a36Sopenharmony_ci
906562306a36Sopenharmony_ci	rval = driver_create_file(&megasas_pci_driver.driver,
906662306a36Sopenharmony_ci				  &driver_attr_support_nvme_encapsulation);
906762306a36Sopenharmony_ci	if (rval)
906862306a36Sopenharmony_ci		goto err_dcf_support_nvme_encapsulation;
906962306a36Sopenharmony_ci
907062306a36Sopenharmony_ci	rval = driver_create_file(&megasas_pci_driver.driver,
907162306a36Sopenharmony_ci				  &driver_attr_support_pci_lane_margining);
907262306a36Sopenharmony_ci	if (rval)
907362306a36Sopenharmony_ci		goto err_dcf_support_pci_lane_margining;
907462306a36Sopenharmony_ci
907562306a36Sopenharmony_ci	return rval;
907662306a36Sopenharmony_ci
907762306a36Sopenharmony_cierr_dcf_support_pci_lane_margining:
907862306a36Sopenharmony_ci	driver_remove_file(&megasas_pci_driver.driver,
907962306a36Sopenharmony_ci			   &driver_attr_support_nvme_encapsulation);
908062306a36Sopenharmony_ci
908162306a36Sopenharmony_cierr_dcf_support_nvme_encapsulation:
908262306a36Sopenharmony_ci	driver_remove_file(&megasas_pci_driver.driver,
908362306a36Sopenharmony_ci			   &driver_attr_support_device_change);
908462306a36Sopenharmony_ci
908562306a36Sopenharmony_cierr_dcf_support_device_change:
908662306a36Sopenharmony_ci	driver_remove_file(&megasas_pci_driver.driver,
908762306a36Sopenharmony_ci			   &driver_attr_dbg_lvl);
908862306a36Sopenharmony_cierr_dcf_dbg_lvl:
908962306a36Sopenharmony_ci	driver_remove_file(&megasas_pci_driver.driver,
909062306a36Sopenharmony_ci			&driver_attr_support_poll_for_event);
909162306a36Sopenharmony_cierr_dcf_support_poll_for_event:
909262306a36Sopenharmony_ci	driver_remove_file(&megasas_pci_driver.driver,
909362306a36Sopenharmony_ci			   &driver_attr_release_date);
909462306a36Sopenharmony_cierr_dcf_rel_date:
909562306a36Sopenharmony_ci	driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
909662306a36Sopenharmony_cierr_dcf_attr_ver:
909762306a36Sopenharmony_ci	pci_unregister_driver(&megasas_pci_driver);
909862306a36Sopenharmony_cierr_pcidrv:
909962306a36Sopenharmony_ci	megasas_exit_debugfs();
910062306a36Sopenharmony_ci	unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
910162306a36Sopenharmony_ci	return rval;
910262306a36Sopenharmony_ci}
910362306a36Sopenharmony_ci
910462306a36Sopenharmony_ci/**
910562306a36Sopenharmony_ci * megasas_exit - Driver unload entry point
910662306a36Sopenharmony_ci */
910762306a36Sopenharmony_cistatic void __exit megasas_exit(void)
910862306a36Sopenharmony_ci{
910962306a36Sopenharmony_ci	driver_remove_file(&megasas_pci_driver.driver,
911062306a36Sopenharmony_ci			   &driver_attr_dbg_lvl);
911162306a36Sopenharmony_ci	driver_remove_file(&megasas_pci_driver.driver,
911262306a36Sopenharmony_ci			&driver_attr_support_poll_for_event);
911362306a36Sopenharmony_ci	driver_remove_file(&megasas_pci_driver.driver,
911462306a36Sopenharmony_ci			&driver_attr_support_device_change);
911562306a36Sopenharmony_ci	driver_remove_file(&megasas_pci_driver.driver,
911662306a36Sopenharmony_ci			   &driver_attr_release_date);
911762306a36Sopenharmony_ci	driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
911862306a36Sopenharmony_ci	driver_remove_file(&megasas_pci_driver.driver,
911962306a36Sopenharmony_ci			   &driver_attr_support_nvme_encapsulation);
912062306a36Sopenharmony_ci	driver_remove_file(&megasas_pci_driver.driver,
912162306a36Sopenharmony_ci			   &driver_attr_support_pci_lane_margining);
912262306a36Sopenharmony_ci
912362306a36Sopenharmony_ci	pci_unregister_driver(&megasas_pci_driver);
912462306a36Sopenharmony_ci	megasas_exit_debugfs();
912562306a36Sopenharmony_ci	unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
912662306a36Sopenharmony_ci}
912762306a36Sopenharmony_ci
912862306a36Sopenharmony_cimodule_init(megasas_init);
912962306a36Sopenharmony_cimodule_exit(megasas_exit);
9130