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) 2009-2013  LSI Corporation
662306a36Sopenharmony_ci *  Copyright (c) 2013-2016  Avago Technologies
762306a36Sopenharmony_ci *  Copyright (c) 2016-2018  Broadcom Inc.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *  FILE: megaraid_sas_fusion.c
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci *  Authors: Broadcom Inc.
1262306a36Sopenharmony_ci *           Sumant Patro
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/uaccess.h>
3162306a36Sopenharmony_ci#include <linux/fs.h>
3262306a36Sopenharmony_ci#include <linux/compat.h>
3362306a36Sopenharmony_ci#include <linux/blkdev.h>
3462306a36Sopenharmony_ci#include <linux/mutex.h>
3562306a36Sopenharmony_ci#include <linux/poll.h>
3662306a36Sopenharmony_ci#include <linux/vmalloc.h>
3762306a36Sopenharmony_ci#include <linux/workqueue.h>
3862306a36Sopenharmony_ci#include <linux/irq_poll.h>
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#include <scsi/scsi.h>
4162306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h>
4262306a36Sopenharmony_ci#include <scsi/scsi_device.h>
4362306a36Sopenharmony_ci#include <scsi/scsi_host.h>
4462306a36Sopenharmony_ci#include <scsi/scsi_dbg.h>
4562306a36Sopenharmony_ci#include <linux/dmi.h>
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#include "megaraid_sas_fusion.h"
4862306a36Sopenharmony_ci#include "megaraid_sas.h"
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ciextern void
5262306a36Sopenharmony_cimegasas_complete_cmd(struct megasas_instance *instance,
5362306a36Sopenharmony_ci		     struct megasas_cmd *cmd, u8 alt_status);
5462306a36Sopenharmony_ciint
5562306a36Sopenharmony_ciwait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
5662306a36Sopenharmony_ci	      int seconds);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ciint
5962306a36Sopenharmony_cimegasas_clear_intr_fusion(struct megasas_instance *instance);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ciint megasas_transition_to_ready(struct megasas_instance *instance, int ocr);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ciextern u32 megasas_dbg_lvl;
6462306a36Sopenharmony_ciint megasas_sriov_start_heartbeat(struct megasas_instance *instance,
6562306a36Sopenharmony_ci				  int initial);
6662306a36Sopenharmony_ciextern struct megasas_mgmt_info megasas_mgmt_info;
6762306a36Sopenharmony_ciextern unsigned int resetwaittime;
6862306a36Sopenharmony_ciextern unsigned int dual_qdepth_disable;
6962306a36Sopenharmony_cistatic void megasas_free_rdpq_fusion(struct megasas_instance *instance);
7062306a36Sopenharmony_cistatic void megasas_free_reply_fusion(struct megasas_instance *instance);
7162306a36Sopenharmony_cistatic inline
7262306a36Sopenharmony_civoid megasas_configure_queue_sizes(struct megasas_instance *instance);
7362306a36Sopenharmony_cistatic void megasas_fusion_crash_dump(struct megasas_instance *instance);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci/**
7662306a36Sopenharmony_ci * megasas_adp_reset_wait_for_ready -	initiate chip reset and wait for
7762306a36Sopenharmony_ci *					controller to come to ready state
7862306a36Sopenharmony_ci * @instance:				adapter's soft state
7962306a36Sopenharmony_ci * @do_adp_reset:			If true, do a chip reset
8062306a36Sopenharmony_ci * @ocr_context:			If called from OCR context this will
8162306a36Sopenharmony_ci *					be set to 1, else 0
8262306a36Sopenharmony_ci *
8362306a36Sopenharmony_ci * This function initiates a chip reset followed by a wait for controller to
8462306a36Sopenharmony_ci * transition to ready state.
8562306a36Sopenharmony_ci * During this, driver will block all access to PCI config space from userspace
8662306a36Sopenharmony_ci */
8762306a36Sopenharmony_ciint
8862306a36Sopenharmony_cimegasas_adp_reset_wait_for_ready(struct megasas_instance *instance,
8962306a36Sopenharmony_ci				 bool do_adp_reset,
9062306a36Sopenharmony_ci				 int ocr_context)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	int ret = FAILED;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	/*
9562306a36Sopenharmony_ci	 * Block access to PCI config space from userspace
9662306a36Sopenharmony_ci	 * when diag reset is initiated from driver
9762306a36Sopenharmony_ci	 */
9862306a36Sopenharmony_ci	if (megasas_dbg_lvl & OCR_DEBUG)
9962306a36Sopenharmony_ci		dev_info(&instance->pdev->dev,
10062306a36Sopenharmony_ci			 "Block access to PCI config space %s %d\n",
10162306a36Sopenharmony_ci			 __func__, __LINE__);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	pci_cfg_access_lock(instance->pdev);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (do_adp_reset) {
10662306a36Sopenharmony_ci		if (instance->instancet->adp_reset
10762306a36Sopenharmony_ci			(instance, instance->reg_set))
10862306a36Sopenharmony_ci			goto out;
10962306a36Sopenharmony_ci	}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	/* Wait for FW to become ready */
11262306a36Sopenharmony_ci	if (megasas_transition_to_ready(instance, ocr_context)) {
11362306a36Sopenharmony_ci		dev_warn(&instance->pdev->dev,
11462306a36Sopenharmony_ci			 "Failed to transition controller to ready for scsi%d.\n",
11562306a36Sopenharmony_ci			 instance->host->host_no);
11662306a36Sopenharmony_ci		goto out;
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	ret = SUCCESS;
12062306a36Sopenharmony_ciout:
12162306a36Sopenharmony_ci	if (megasas_dbg_lvl & OCR_DEBUG)
12262306a36Sopenharmony_ci		dev_info(&instance->pdev->dev,
12362306a36Sopenharmony_ci			 "Unlock access to PCI config space %s %d\n",
12462306a36Sopenharmony_ci			 __func__, __LINE__);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	pci_cfg_access_unlock(instance->pdev);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	return ret;
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci/**
13262306a36Sopenharmony_ci * megasas_check_same_4gb_region -	check if allocation
13362306a36Sopenharmony_ci *					crosses same 4GB boundary or not
13462306a36Sopenharmony_ci * @instance:				adapter's soft instance
13562306a36Sopenharmony_ci * @start_addr:				start address of DMA allocation
13662306a36Sopenharmony_ci * @size:				size of allocation in bytes
13762306a36Sopenharmony_ci * @return:				true : allocation does not cross same
13862306a36Sopenharmony_ci *					4GB boundary
13962306a36Sopenharmony_ci *					false: allocation crosses same
14062306a36Sopenharmony_ci *					4GB boundary
14162306a36Sopenharmony_ci */
14262306a36Sopenharmony_cistatic inline bool megasas_check_same_4gb_region
14362306a36Sopenharmony_ci	(struct megasas_instance *instance, dma_addr_t start_addr, size_t size)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	dma_addr_t end_addr;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	end_addr = start_addr + size;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	if (upper_32_bits(start_addr) != upper_32_bits(end_addr)) {
15062306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
15162306a36Sopenharmony_ci			"Failed to get same 4GB boundary: start_addr: 0x%llx end_addr: 0x%llx\n",
15262306a36Sopenharmony_ci			(unsigned long long)start_addr,
15362306a36Sopenharmony_ci			(unsigned long long)end_addr);
15462306a36Sopenharmony_ci		return false;
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	return true;
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci/**
16162306a36Sopenharmony_ci * megasas_enable_intr_fusion -	Enables interrupts
16262306a36Sopenharmony_ci * @instance:	adapter's soft instance
16362306a36Sopenharmony_ci */
16462306a36Sopenharmony_cistatic void
16562306a36Sopenharmony_cimegasas_enable_intr_fusion(struct megasas_instance *instance)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	struct megasas_register_set __iomem *regs;
16862306a36Sopenharmony_ci	regs = instance->reg_set;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	instance->mask_interrupts = 0;
17162306a36Sopenharmony_ci	/* For Thunderbolt/Invader also clear intr on enable */
17262306a36Sopenharmony_ci	writel(~0, &regs->outbound_intr_status);
17362306a36Sopenharmony_ci	readl(&regs->outbound_intr_status);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	writel(~MFI_FUSION_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	/* Dummy readl to force pci flush */
17862306a36Sopenharmony_ci	dev_info(&instance->pdev->dev, "%s is called outbound_intr_mask:0x%08x\n",
17962306a36Sopenharmony_ci		 __func__, readl(&regs->outbound_intr_mask));
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci/**
18362306a36Sopenharmony_ci * megasas_disable_intr_fusion - Disables interrupt
18462306a36Sopenharmony_ci * @instance:	adapter's soft instance
18562306a36Sopenharmony_ci */
18662306a36Sopenharmony_cistatic void
18762306a36Sopenharmony_cimegasas_disable_intr_fusion(struct megasas_instance *instance)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	u32 mask = 0xFFFFFFFF;
19062306a36Sopenharmony_ci	struct megasas_register_set __iomem *regs;
19162306a36Sopenharmony_ci	regs = instance->reg_set;
19262306a36Sopenharmony_ci	instance->mask_interrupts = 1;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	writel(mask, &regs->outbound_intr_mask);
19562306a36Sopenharmony_ci	/* Dummy readl to force pci flush */
19662306a36Sopenharmony_ci	dev_info(&instance->pdev->dev, "%s is called outbound_intr_mask:0x%08x\n",
19762306a36Sopenharmony_ci		 __func__, readl(&regs->outbound_intr_mask));
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ciint
20162306a36Sopenharmony_cimegasas_clear_intr_fusion(struct megasas_instance *instance)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	u32 status;
20462306a36Sopenharmony_ci	struct megasas_register_set __iomem *regs;
20562306a36Sopenharmony_ci	regs = instance->reg_set;
20662306a36Sopenharmony_ci	/*
20762306a36Sopenharmony_ci	 * Check if it is our interrupt
20862306a36Sopenharmony_ci	 */
20962306a36Sopenharmony_ci	status = megasas_readl(instance,
21062306a36Sopenharmony_ci			       &regs->outbound_intr_status);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	if (status & 1) {
21362306a36Sopenharmony_ci		writel(status, &regs->outbound_intr_status);
21462306a36Sopenharmony_ci		readl(&regs->outbound_intr_status);
21562306a36Sopenharmony_ci		return 1;
21662306a36Sopenharmony_ci	}
21762306a36Sopenharmony_ci	if (!(status & MFI_FUSION_ENABLE_INTERRUPT_MASK))
21862306a36Sopenharmony_ci		return 0;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	return 1;
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic inline void
22462306a36Sopenharmony_cimegasas_sdev_busy_inc(struct megasas_instance *instance,
22562306a36Sopenharmony_ci		      struct scsi_cmnd *scmd)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	if (instance->perf_mode == MR_BALANCED_PERF_MODE) {
22862306a36Sopenharmony_ci		struct MR_PRIV_DEVICE *mr_device_priv_data =
22962306a36Sopenharmony_ci			scmd->device->hostdata;
23062306a36Sopenharmony_ci		atomic_inc(&mr_device_priv_data->sdev_priv_busy);
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic inline void
23562306a36Sopenharmony_cimegasas_sdev_busy_dec(struct megasas_instance *instance,
23662306a36Sopenharmony_ci		      struct scsi_cmnd *scmd)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	if (instance->perf_mode == MR_BALANCED_PERF_MODE) {
23962306a36Sopenharmony_ci		struct MR_PRIV_DEVICE *mr_device_priv_data =
24062306a36Sopenharmony_ci			scmd->device->hostdata;
24162306a36Sopenharmony_ci		atomic_dec(&mr_device_priv_data->sdev_priv_busy);
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic inline int
24662306a36Sopenharmony_cimegasas_sdev_busy_read(struct megasas_instance *instance,
24762306a36Sopenharmony_ci		       struct scsi_cmnd *scmd)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	if (instance->perf_mode == MR_BALANCED_PERF_MODE) {
25062306a36Sopenharmony_ci		struct MR_PRIV_DEVICE *mr_device_priv_data =
25162306a36Sopenharmony_ci			scmd->device->hostdata;
25262306a36Sopenharmony_ci		return atomic_read(&mr_device_priv_data->sdev_priv_busy);
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci	return 0;
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci/**
25862306a36Sopenharmony_ci * megasas_get_cmd_fusion -	Get a command from the free pool
25962306a36Sopenharmony_ci * @instance:		Adapter soft state
26062306a36Sopenharmony_ci * @blk_tag:		Command tag
26162306a36Sopenharmony_ci *
26262306a36Sopenharmony_ci * Returns a blk_tag indexed mpt frame
26362306a36Sopenharmony_ci */
26462306a36Sopenharmony_ciinline struct megasas_cmd_fusion *megasas_get_cmd_fusion(struct megasas_instance
26562306a36Sopenharmony_ci						  *instance, u32 blk_tag)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	struct fusion_context *fusion;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	fusion = instance->ctrl_context;
27062306a36Sopenharmony_ci	return fusion->cmd_list[blk_tag];
27162306a36Sopenharmony_ci}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci/**
27462306a36Sopenharmony_ci * megasas_return_cmd_fusion -	Return a cmd to free command pool
27562306a36Sopenharmony_ci * @instance:		Adapter soft state
27662306a36Sopenharmony_ci * @cmd:		Command packet to be returned to free command pool
27762306a36Sopenharmony_ci */
27862306a36Sopenharmony_ciinline void megasas_return_cmd_fusion(struct megasas_instance *instance,
27962306a36Sopenharmony_ci	struct megasas_cmd_fusion *cmd)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	cmd->scmd = NULL;
28262306a36Sopenharmony_ci	memset(cmd->io_request, 0, MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE);
28362306a36Sopenharmony_ci	cmd->r1_alt_dev_handle = MR_DEVHANDLE_INVALID;
28462306a36Sopenharmony_ci	cmd->cmd_completed = false;
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci/**
28862306a36Sopenharmony_ci * megasas_write_64bit_req_desc -	PCI writes 64bit request descriptor
28962306a36Sopenharmony_ci * @instance:				Adapter soft state
29062306a36Sopenharmony_ci * @req_desc:				64bit Request descriptor
29162306a36Sopenharmony_ci */
29262306a36Sopenharmony_cistatic void
29362306a36Sopenharmony_cimegasas_write_64bit_req_desc(struct megasas_instance *instance,
29462306a36Sopenharmony_ci		union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci#if defined(writeq) && defined(CONFIG_64BIT)
29762306a36Sopenharmony_ci	u64 req_data = (((u64)le32_to_cpu(req_desc->u.high) << 32) |
29862306a36Sopenharmony_ci		le32_to_cpu(req_desc->u.low));
29962306a36Sopenharmony_ci	writeq(req_data, &instance->reg_set->inbound_low_queue_port);
30062306a36Sopenharmony_ci#else
30162306a36Sopenharmony_ci	unsigned long flags;
30262306a36Sopenharmony_ci	spin_lock_irqsave(&instance->hba_lock, flags);
30362306a36Sopenharmony_ci	writel(le32_to_cpu(req_desc->u.low),
30462306a36Sopenharmony_ci		&instance->reg_set->inbound_low_queue_port);
30562306a36Sopenharmony_ci	writel(le32_to_cpu(req_desc->u.high),
30662306a36Sopenharmony_ci		&instance->reg_set->inbound_high_queue_port);
30762306a36Sopenharmony_ci	spin_unlock_irqrestore(&instance->hba_lock, flags);
30862306a36Sopenharmony_ci#endif
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci/**
31262306a36Sopenharmony_ci * megasas_fire_cmd_fusion -	Sends command to the FW
31362306a36Sopenharmony_ci * @instance:			Adapter soft state
31462306a36Sopenharmony_ci * @req_desc:			32bit or 64bit Request descriptor
31562306a36Sopenharmony_ci *
31662306a36Sopenharmony_ci * Perform PCI Write. AERO SERIES supports 32 bit Descriptor.
31762306a36Sopenharmony_ci * Prior to AERO_SERIES support 64 bit Descriptor.
31862306a36Sopenharmony_ci */
31962306a36Sopenharmony_cistatic void
32062306a36Sopenharmony_cimegasas_fire_cmd_fusion(struct megasas_instance *instance,
32162306a36Sopenharmony_ci		union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	if (instance->atomic_desc_support)
32462306a36Sopenharmony_ci		writel(le32_to_cpu(req_desc->u.low),
32562306a36Sopenharmony_ci			&instance->reg_set->inbound_single_queue_port);
32662306a36Sopenharmony_ci	else
32762306a36Sopenharmony_ci		megasas_write_64bit_req_desc(instance, req_desc);
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci/**
33162306a36Sopenharmony_ci * megasas_fusion_update_can_queue -	Do all Adapter Queue depth related calculations here
33262306a36Sopenharmony_ci * @instance:		Adapter soft state
33362306a36Sopenharmony_ci * @fw_boot_context:	Whether this function called during probe or after OCR
33462306a36Sopenharmony_ci *
33562306a36Sopenharmony_ci * This function is only for fusion controllers.
33662306a36Sopenharmony_ci * Update host can queue, if firmware downgrade max supported firmware commands.
33762306a36Sopenharmony_ci * Firmware upgrade case will be skipped because underlying firmware has
33862306a36Sopenharmony_ci * more resource than exposed to the OS.
33962306a36Sopenharmony_ci *
34062306a36Sopenharmony_ci */
34162306a36Sopenharmony_cistatic void
34262306a36Sopenharmony_cimegasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_context)
34362306a36Sopenharmony_ci{
34462306a36Sopenharmony_ci	u16 cur_max_fw_cmds = 0;
34562306a36Sopenharmony_ci	u16 ldio_threshold = 0;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	/* ventura FW does not fill outbound_scratch_pad_2 with queue depth */
34862306a36Sopenharmony_ci	if (instance->adapter_type < VENTURA_SERIES)
34962306a36Sopenharmony_ci		cur_max_fw_cmds =
35062306a36Sopenharmony_ci		megasas_readl(instance,
35162306a36Sopenharmony_ci			      &instance->reg_set->outbound_scratch_pad_2) & 0x00FFFF;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	if (dual_qdepth_disable || !cur_max_fw_cmds)
35462306a36Sopenharmony_ci		cur_max_fw_cmds = instance->instancet->read_fw_status_reg(instance) & 0x00FFFF;
35562306a36Sopenharmony_ci	else
35662306a36Sopenharmony_ci		ldio_threshold =
35762306a36Sopenharmony_ci			(instance->instancet->read_fw_status_reg(instance) & 0x00FFFF) - MEGASAS_FUSION_IOCTL_CMDS;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	dev_info(&instance->pdev->dev,
36062306a36Sopenharmony_ci		 "Current firmware supports maximum commands: %d\t LDIO threshold: %d\n",
36162306a36Sopenharmony_ci		 cur_max_fw_cmds, ldio_threshold);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	if (fw_boot_context == OCR_CONTEXT) {
36462306a36Sopenharmony_ci		cur_max_fw_cmds = cur_max_fw_cmds - 1;
36562306a36Sopenharmony_ci		if (cur_max_fw_cmds < instance->max_fw_cmds) {
36662306a36Sopenharmony_ci			instance->cur_can_queue =
36762306a36Sopenharmony_ci				cur_max_fw_cmds - (MEGASAS_FUSION_INTERNAL_CMDS +
36862306a36Sopenharmony_ci						MEGASAS_FUSION_IOCTL_CMDS);
36962306a36Sopenharmony_ci			instance->host->can_queue = instance->cur_can_queue;
37062306a36Sopenharmony_ci			instance->ldio_threshold = ldio_threshold;
37162306a36Sopenharmony_ci		}
37262306a36Sopenharmony_ci	} else {
37362306a36Sopenharmony_ci		instance->max_fw_cmds = cur_max_fw_cmds;
37462306a36Sopenharmony_ci		instance->ldio_threshold = ldio_threshold;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci		if (reset_devices)
37762306a36Sopenharmony_ci			instance->max_fw_cmds = min(instance->max_fw_cmds,
37862306a36Sopenharmony_ci						(u16)MEGASAS_KDUMP_QUEUE_DEPTH);
37962306a36Sopenharmony_ci		/*
38062306a36Sopenharmony_ci		* Reduce the max supported cmds by 1. This is to ensure that the
38162306a36Sopenharmony_ci		* reply_q_sz (1 more than the max cmd that driver may send)
38262306a36Sopenharmony_ci		* does not exceed max cmds that the FW can support
38362306a36Sopenharmony_ci		*/
38462306a36Sopenharmony_ci		instance->max_fw_cmds = instance->max_fw_cmds-1;
38562306a36Sopenharmony_ci	}
38662306a36Sopenharmony_ci}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_cistatic inline void
38962306a36Sopenharmony_cimegasas_get_msix_index(struct megasas_instance *instance,
39062306a36Sopenharmony_ci		       struct scsi_cmnd *scmd,
39162306a36Sopenharmony_ci		       struct megasas_cmd_fusion *cmd,
39262306a36Sopenharmony_ci		       u8 data_arms)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	if (instance->perf_mode == MR_BALANCED_PERF_MODE &&
39562306a36Sopenharmony_ci	    (megasas_sdev_busy_read(instance, scmd) >
39662306a36Sopenharmony_ci	     (data_arms * MR_DEVICE_HIGH_IOPS_DEPTH))) {
39762306a36Sopenharmony_ci		cmd->request_desc->SCSIIO.MSIxIndex =
39862306a36Sopenharmony_ci			mega_mod64((atomic64_add_return(1, &instance->high_iops_outstanding) /
39962306a36Sopenharmony_ci					MR_HIGH_IOPS_BATCH_COUNT), instance->low_latency_index_start);
40062306a36Sopenharmony_ci	} else if (instance->msix_load_balance) {
40162306a36Sopenharmony_ci		cmd->request_desc->SCSIIO.MSIxIndex =
40262306a36Sopenharmony_ci			(mega_mod64(atomic64_add_return(1, &instance->total_io_count),
40362306a36Sopenharmony_ci				instance->msix_vectors));
40462306a36Sopenharmony_ci	} else if (instance->host->nr_hw_queues > 1) {
40562306a36Sopenharmony_ci		u32 tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd));
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci		cmd->request_desc->SCSIIO.MSIxIndex = blk_mq_unique_tag_to_hwq(tag) +
40862306a36Sopenharmony_ci			instance->low_latency_index_start;
40962306a36Sopenharmony_ci	} else {
41062306a36Sopenharmony_ci		cmd->request_desc->SCSIIO.MSIxIndex =
41162306a36Sopenharmony_ci			instance->reply_map[raw_smp_processor_id()];
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci/**
41662306a36Sopenharmony_ci * megasas_free_cmds_fusion -	Free all the cmds in the free cmd pool
41762306a36Sopenharmony_ci * @instance:		Adapter soft state
41862306a36Sopenharmony_ci */
41962306a36Sopenharmony_civoid
42062306a36Sopenharmony_cimegasas_free_cmds_fusion(struct megasas_instance *instance)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	int i;
42362306a36Sopenharmony_ci	struct fusion_context *fusion = instance->ctrl_context;
42462306a36Sopenharmony_ci	struct megasas_cmd_fusion *cmd;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	if (fusion->sense)
42762306a36Sopenharmony_ci		dma_pool_free(fusion->sense_dma_pool, fusion->sense,
42862306a36Sopenharmony_ci			      fusion->sense_phys_addr);
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	/* SG */
43162306a36Sopenharmony_ci	if (fusion->cmd_list) {
43262306a36Sopenharmony_ci		for (i = 0; i < instance->max_mpt_cmds; i++) {
43362306a36Sopenharmony_ci			cmd = fusion->cmd_list[i];
43462306a36Sopenharmony_ci			if (cmd) {
43562306a36Sopenharmony_ci				if (cmd->sg_frame)
43662306a36Sopenharmony_ci					dma_pool_free(fusion->sg_dma_pool,
43762306a36Sopenharmony_ci						      cmd->sg_frame,
43862306a36Sopenharmony_ci						      cmd->sg_frame_phys_addr);
43962306a36Sopenharmony_ci			}
44062306a36Sopenharmony_ci			kfree(cmd);
44162306a36Sopenharmony_ci		}
44262306a36Sopenharmony_ci		kfree(fusion->cmd_list);
44362306a36Sopenharmony_ci	}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	if (fusion->sg_dma_pool) {
44662306a36Sopenharmony_ci		dma_pool_destroy(fusion->sg_dma_pool);
44762306a36Sopenharmony_ci		fusion->sg_dma_pool = NULL;
44862306a36Sopenharmony_ci	}
44962306a36Sopenharmony_ci	if (fusion->sense_dma_pool) {
45062306a36Sopenharmony_ci		dma_pool_destroy(fusion->sense_dma_pool);
45162306a36Sopenharmony_ci		fusion->sense_dma_pool = NULL;
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	/* Reply Frame, Desc*/
45662306a36Sopenharmony_ci	if (instance->is_rdpq)
45762306a36Sopenharmony_ci		megasas_free_rdpq_fusion(instance);
45862306a36Sopenharmony_ci	else
45962306a36Sopenharmony_ci		megasas_free_reply_fusion(instance);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	/* Request Frame, Desc*/
46262306a36Sopenharmony_ci	if (fusion->req_frames_desc)
46362306a36Sopenharmony_ci		dma_free_coherent(&instance->pdev->dev,
46462306a36Sopenharmony_ci			fusion->request_alloc_sz, fusion->req_frames_desc,
46562306a36Sopenharmony_ci			fusion->req_frames_desc_phys);
46662306a36Sopenharmony_ci	if (fusion->io_request_frames)
46762306a36Sopenharmony_ci		dma_pool_free(fusion->io_request_frames_pool,
46862306a36Sopenharmony_ci			fusion->io_request_frames,
46962306a36Sopenharmony_ci			fusion->io_request_frames_phys);
47062306a36Sopenharmony_ci	if (fusion->io_request_frames_pool) {
47162306a36Sopenharmony_ci		dma_pool_destroy(fusion->io_request_frames_pool);
47262306a36Sopenharmony_ci		fusion->io_request_frames_pool = NULL;
47362306a36Sopenharmony_ci	}
47462306a36Sopenharmony_ci}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci/**
47762306a36Sopenharmony_ci * megasas_create_sg_sense_fusion -	Creates DMA pool for cmd frames
47862306a36Sopenharmony_ci * @instance:			Adapter soft state
47962306a36Sopenharmony_ci *
48062306a36Sopenharmony_ci */
48162306a36Sopenharmony_cistatic int megasas_create_sg_sense_fusion(struct megasas_instance *instance)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	int i;
48462306a36Sopenharmony_ci	u16 max_cmd;
48562306a36Sopenharmony_ci	struct fusion_context *fusion;
48662306a36Sopenharmony_ci	struct megasas_cmd_fusion *cmd;
48762306a36Sopenharmony_ci	int sense_sz;
48862306a36Sopenharmony_ci	u32 offset;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	fusion = instance->ctrl_context;
49162306a36Sopenharmony_ci	max_cmd = instance->max_fw_cmds;
49262306a36Sopenharmony_ci	sense_sz = instance->max_mpt_cmds * SCSI_SENSE_BUFFERSIZE;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	fusion->sg_dma_pool =
49562306a36Sopenharmony_ci			dma_pool_create("mr_sg", &instance->pdev->dev,
49662306a36Sopenharmony_ci				instance->max_chain_frame_sz,
49762306a36Sopenharmony_ci				MR_DEFAULT_NVME_PAGE_SIZE, 0);
49862306a36Sopenharmony_ci	/* SCSI_SENSE_BUFFERSIZE  = 96 bytes */
49962306a36Sopenharmony_ci	fusion->sense_dma_pool =
50062306a36Sopenharmony_ci			dma_pool_create("mr_sense", &instance->pdev->dev,
50162306a36Sopenharmony_ci				sense_sz, 64, 0);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	if (!fusion->sense_dma_pool || !fusion->sg_dma_pool) {
50462306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
50562306a36Sopenharmony_ci			"Failed from %s %d\n",  __func__, __LINE__);
50662306a36Sopenharmony_ci		return -ENOMEM;
50762306a36Sopenharmony_ci	}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	fusion->sense = dma_pool_alloc(fusion->sense_dma_pool,
51062306a36Sopenharmony_ci				       GFP_KERNEL, &fusion->sense_phys_addr);
51162306a36Sopenharmony_ci	if (!fusion->sense) {
51262306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
51362306a36Sopenharmony_ci			"failed from %s %d\n",  __func__, __LINE__);
51462306a36Sopenharmony_ci		return -ENOMEM;
51562306a36Sopenharmony_ci	}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	/* sense buffer, request frame and reply desc pool requires to be in
51862306a36Sopenharmony_ci	 * same 4 gb region. Below function will check this.
51962306a36Sopenharmony_ci	 * In case of failure, new pci pool will be created with updated
52062306a36Sopenharmony_ci	 * alignment.
52162306a36Sopenharmony_ci	 * Older allocation and pool will be destroyed.
52262306a36Sopenharmony_ci	 * Alignment will be used such a way that next allocation if success,
52362306a36Sopenharmony_ci	 * will always meet same 4gb region requirement.
52462306a36Sopenharmony_ci	 * Actual requirement is not alignment, but we need start and end of
52562306a36Sopenharmony_ci	 * DMA address must have same upper 32 bit address.
52662306a36Sopenharmony_ci	 */
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	if (!megasas_check_same_4gb_region(instance, fusion->sense_phys_addr,
52962306a36Sopenharmony_ci					   sense_sz)) {
53062306a36Sopenharmony_ci		dma_pool_free(fusion->sense_dma_pool, fusion->sense,
53162306a36Sopenharmony_ci			      fusion->sense_phys_addr);
53262306a36Sopenharmony_ci		fusion->sense = NULL;
53362306a36Sopenharmony_ci		dma_pool_destroy(fusion->sense_dma_pool);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci		fusion->sense_dma_pool =
53662306a36Sopenharmony_ci			dma_pool_create("mr_sense_align", &instance->pdev->dev,
53762306a36Sopenharmony_ci					sense_sz, roundup_pow_of_two(sense_sz),
53862306a36Sopenharmony_ci					0);
53962306a36Sopenharmony_ci		if (!fusion->sense_dma_pool) {
54062306a36Sopenharmony_ci			dev_err(&instance->pdev->dev,
54162306a36Sopenharmony_ci				"Failed from %s %d\n",  __func__, __LINE__);
54262306a36Sopenharmony_ci			return -ENOMEM;
54362306a36Sopenharmony_ci		}
54462306a36Sopenharmony_ci		fusion->sense = dma_pool_alloc(fusion->sense_dma_pool,
54562306a36Sopenharmony_ci					       GFP_KERNEL,
54662306a36Sopenharmony_ci					       &fusion->sense_phys_addr);
54762306a36Sopenharmony_ci		if (!fusion->sense) {
54862306a36Sopenharmony_ci			dev_err(&instance->pdev->dev,
54962306a36Sopenharmony_ci				"failed from %s %d\n",  __func__, __LINE__);
55062306a36Sopenharmony_ci			return -ENOMEM;
55162306a36Sopenharmony_ci		}
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	/*
55562306a36Sopenharmony_ci	 * Allocate and attach a frame to each of the commands in cmd_list
55662306a36Sopenharmony_ci	 */
55762306a36Sopenharmony_ci	for (i = 0; i < max_cmd; i++) {
55862306a36Sopenharmony_ci		cmd = fusion->cmd_list[i];
55962306a36Sopenharmony_ci		cmd->sg_frame = dma_pool_alloc(fusion->sg_dma_pool,
56062306a36Sopenharmony_ci					GFP_KERNEL, &cmd->sg_frame_phys_addr);
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci		offset = SCSI_SENSE_BUFFERSIZE * i;
56362306a36Sopenharmony_ci		cmd->sense = (u8 *)fusion->sense + offset;
56462306a36Sopenharmony_ci		cmd->sense_phys_addr = fusion->sense_phys_addr + offset;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci		if (!cmd->sg_frame) {
56762306a36Sopenharmony_ci			dev_err(&instance->pdev->dev,
56862306a36Sopenharmony_ci				"Failed from %s %d\n",  __func__, __LINE__);
56962306a36Sopenharmony_ci			return -ENOMEM;
57062306a36Sopenharmony_ci		}
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	/* create sense buffer for the raid 1/10 fp */
57462306a36Sopenharmony_ci	for (i = max_cmd; i < instance->max_mpt_cmds; i++) {
57562306a36Sopenharmony_ci		cmd = fusion->cmd_list[i];
57662306a36Sopenharmony_ci		offset = SCSI_SENSE_BUFFERSIZE * i;
57762306a36Sopenharmony_ci		cmd->sense = (u8 *)fusion->sense + offset;
57862306a36Sopenharmony_ci		cmd->sense_phys_addr = fusion->sense_phys_addr + offset;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	return 0;
58362306a36Sopenharmony_ci}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_cistatic int
58662306a36Sopenharmony_cimegasas_alloc_cmdlist_fusion(struct megasas_instance *instance)
58762306a36Sopenharmony_ci{
58862306a36Sopenharmony_ci	u32 max_mpt_cmd, i, j;
58962306a36Sopenharmony_ci	struct fusion_context *fusion;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	fusion = instance->ctrl_context;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	max_mpt_cmd = instance->max_mpt_cmds;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	/*
59662306a36Sopenharmony_ci	 * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers.
59762306a36Sopenharmony_ci	 * Allocate the dynamic array first and then allocate individual
59862306a36Sopenharmony_ci	 * commands.
59962306a36Sopenharmony_ci	 */
60062306a36Sopenharmony_ci	fusion->cmd_list =
60162306a36Sopenharmony_ci		kcalloc(max_mpt_cmd, sizeof(struct megasas_cmd_fusion *),
60262306a36Sopenharmony_ci			GFP_KERNEL);
60362306a36Sopenharmony_ci	if (!fusion->cmd_list) {
60462306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
60562306a36Sopenharmony_ci			"Failed from %s %d\n",  __func__, __LINE__);
60662306a36Sopenharmony_ci		return -ENOMEM;
60762306a36Sopenharmony_ci	}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	for (i = 0; i < max_mpt_cmd; i++) {
61062306a36Sopenharmony_ci		fusion->cmd_list[i] = kzalloc(sizeof(struct megasas_cmd_fusion),
61162306a36Sopenharmony_ci					      GFP_KERNEL);
61262306a36Sopenharmony_ci		if (!fusion->cmd_list[i]) {
61362306a36Sopenharmony_ci			for (j = 0; j < i; j++)
61462306a36Sopenharmony_ci				kfree(fusion->cmd_list[j]);
61562306a36Sopenharmony_ci			kfree(fusion->cmd_list);
61662306a36Sopenharmony_ci			dev_err(&instance->pdev->dev,
61762306a36Sopenharmony_ci				"Failed from %s %d\n",  __func__, __LINE__);
61862306a36Sopenharmony_ci			return -ENOMEM;
61962306a36Sopenharmony_ci		}
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	return 0;
62362306a36Sopenharmony_ci}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_cistatic int
62662306a36Sopenharmony_cimegasas_alloc_request_fusion(struct megasas_instance *instance)
62762306a36Sopenharmony_ci{
62862306a36Sopenharmony_ci	struct fusion_context *fusion;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	fusion = instance->ctrl_context;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ciretry_alloc:
63362306a36Sopenharmony_ci	fusion->io_request_frames_pool =
63462306a36Sopenharmony_ci			dma_pool_create("mr_ioreq", &instance->pdev->dev,
63562306a36Sopenharmony_ci				fusion->io_frames_alloc_sz, 16, 0);
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	if (!fusion->io_request_frames_pool) {
63862306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
63962306a36Sopenharmony_ci			"Failed from %s %d\n",  __func__, __LINE__);
64062306a36Sopenharmony_ci		return -ENOMEM;
64162306a36Sopenharmony_ci	}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	fusion->io_request_frames =
64462306a36Sopenharmony_ci			dma_pool_alloc(fusion->io_request_frames_pool,
64562306a36Sopenharmony_ci				GFP_KERNEL | __GFP_NOWARN,
64662306a36Sopenharmony_ci				&fusion->io_request_frames_phys);
64762306a36Sopenharmony_ci	if (!fusion->io_request_frames) {
64862306a36Sopenharmony_ci		if (instance->max_fw_cmds >= (MEGASAS_REDUCE_QD_COUNT * 2)) {
64962306a36Sopenharmony_ci			instance->max_fw_cmds -= MEGASAS_REDUCE_QD_COUNT;
65062306a36Sopenharmony_ci			dma_pool_destroy(fusion->io_request_frames_pool);
65162306a36Sopenharmony_ci			megasas_configure_queue_sizes(instance);
65262306a36Sopenharmony_ci			goto retry_alloc;
65362306a36Sopenharmony_ci		} else {
65462306a36Sopenharmony_ci			dev_err(&instance->pdev->dev,
65562306a36Sopenharmony_ci				"Failed from %s %d\n",  __func__, __LINE__);
65662306a36Sopenharmony_ci			return -ENOMEM;
65762306a36Sopenharmony_ci		}
65862306a36Sopenharmony_ci	}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	if (!megasas_check_same_4gb_region(instance,
66162306a36Sopenharmony_ci					   fusion->io_request_frames_phys,
66262306a36Sopenharmony_ci					   fusion->io_frames_alloc_sz)) {
66362306a36Sopenharmony_ci		dma_pool_free(fusion->io_request_frames_pool,
66462306a36Sopenharmony_ci			      fusion->io_request_frames,
66562306a36Sopenharmony_ci			      fusion->io_request_frames_phys);
66662306a36Sopenharmony_ci		fusion->io_request_frames = NULL;
66762306a36Sopenharmony_ci		dma_pool_destroy(fusion->io_request_frames_pool);
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci		fusion->io_request_frames_pool =
67062306a36Sopenharmony_ci			dma_pool_create("mr_ioreq_align",
67162306a36Sopenharmony_ci					&instance->pdev->dev,
67262306a36Sopenharmony_ci					fusion->io_frames_alloc_sz,
67362306a36Sopenharmony_ci					roundup_pow_of_two(fusion->io_frames_alloc_sz),
67462306a36Sopenharmony_ci					0);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci		if (!fusion->io_request_frames_pool) {
67762306a36Sopenharmony_ci			dev_err(&instance->pdev->dev,
67862306a36Sopenharmony_ci				"Failed from %s %d\n",  __func__, __LINE__);
67962306a36Sopenharmony_ci			return -ENOMEM;
68062306a36Sopenharmony_ci		}
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci		fusion->io_request_frames =
68362306a36Sopenharmony_ci			dma_pool_alloc(fusion->io_request_frames_pool,
68462306a36Sopenharmony_ci				       GFP_KERNEL | __GFP_NOWARN,
68562306a36Sopenharmony_ci				       &fusion->io_request_frames_phys);
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci		if (!fusion->io_request_frames) {
68862306a36Sopenharmony_ci			dev_err(&instance->pdev->dev,
68962306a36Sopenharmony_ci				"Failed from %s %d\n",  __func__, __LINE__);
69062306a36Sopenharmony_ci			return -ENOMEM;
69162306a36Sopenharmony_ci		}
69262306a36Sopenharmony_ci	}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	fusion->req_frames_desc =
69562306a36Sopenharmony_ci		dma_alloc_coherent(&instance->pdev->dev,
69662306a36Sopenharmony_ci				   fusion->request_alloc_sz,
69762306a36Sopenharmony_ci				   &fusion->req_frames_desc_phys, GFP_KERNEL);
69862306a36Sopenharmony_ci	if (!fusion->req_frames_desc) {
69962306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
70062306a36Sopenharmony_ci			"Failed from %s %d\n",  __func__, __LINE__);
70162306a36Sopenharmony_ci		return -ENOMEM;
70262306a36Sopenharmony_ci	}
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	return 0;
70562306a36Sopenharmony_ci}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_cistatic int
70862306a36Sopenharmony_cimegasas_alloc_reply_fusion(struct megasas_instance *instance)
70962306a36Sopenharmony_ci{
71062306a36Sopenharmony_ci	int i, count;
71162306a36Sopenharmony_ci	struct fusion_context *fusion;
71262306a36Sopenharmony_ci	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
71362306a36Sopenharmony_ci	fusion = instance->ctrl_context;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
71662306a36Sopenharmony_ci	count += instance->iopoll_q_count;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	fusion->reply_frames_desc_pool =
71962306a36Sopenharmony_ci			dma_pool_create("mr_reply", &instance->pdev->dev,
72062306a36Sopenharmony_ci				fusion->reply_alloc_sz * count, 16, 0);
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	if (!fusion->reply_frames_desc_pool) {
72362306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
72462306a36Sopenharmony_ci			"Failed from %s %d\n",  __func__, __LINE__);
72562306a36Sopenharmony_ci		return -ENOMEM;
72662306a36Sopenharmony_ci	}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	fusion->reply_frames_desc[0] =
72962306a36Sopenharmony_ci		dma_pool_alloc(fusion->reply_frames_desc_pool,
73062306a36Sopenharmony_ci			GFP_KERNEL, &fusion->reply_frames_desc_phys[0]);
73162306a36Sopenharmony_ci	if (!fusion->reply_frames_desc[0]) {
73262306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
73362306a36Sopenharmony_ci			"Failed from %s %d\n",  __func__, __LINE__);
73462306a36Sopenharmony_ci		return -ENOMEM;
73562306a36Sopenharmony_ci	}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	if (!megasas_check_same_4gb_region(instance,
73862306a36Sopenharmony_ci					   fusion->reply_frames_desc_phys[0],
73962306a36Sopenharmony_ci					   (fusion->reply_alloc_sz * count))) {
74062306a36Sopenharmony_ci		dma_pool_free(fusion->reply_frames_desc_pool,
74162306a36Sopenharmony_ci			      fusion->reply_frames_desc[0],
74262306a36Sopenharmony_ci			      fusion->reply_frames_desc_phys[0]);
74362306a36Sopenharmony_ci		fusion->reply_frames_desc[0] = NULL;
74462306a36Sopenharmony_ci		dma_pool_destroy(fusion->reply_frames_desc_pool);
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci		fusion->reply_frames_desc_pool =
74762306a36Sopenharmony_ci			dma_pool_create("mr_reply_align",
74862306a36Sopenharmony_ci					&instance->pdev->dev,
74962306a36Sopenharmony_ci					fusion->reply_alloc_sz * count,
75062306a36Sopenharmony_ci					roundup_pow_of_two(fusion->reply_alloc_sz * count),
75162306a36Sopenharmony_ci					0);
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci		if (!fusion->reply_frames_desc_pool) {
75462306a36Sopenharmony_ci			dev_err(&instance->pdev->dev,
75562306a36Sopenharmony_ci				"Failed from %s %d\n",  __func__, __LINE__);
75662306a36Sopenharmony_ci			return -ENOMEM;
75762306a36Sopenharmony_ci		}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci		fusion->reply_frames_desc[0] =
76062306a36Sopenharmony_ci			dma_pool_alloc(fusion->reply_frames_desc_pool,
76162306a36Sopenharmony_ci				       GFP_KERNEL,
76262306a36Sopenharmony_ci				       &fusion->reply_frames_desc_phys[0]);
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci		if (!fusion->reply_frames_desc[0]) {
76562306a36Sopenharmony_ci			dev_err(&instance->pdev->dev,
76662306a36Sopenharmony_ci				"Failed from %s %d\n",  __func__, __LINE__);
76762306a36Sopenharmony_ci			return -ENOMEM;
76862306a36Sopenharmony_ci		}
76962306a36Sopenharmony_ci	}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	reply_desc = fusion->reply_frames_desc[0];
77262306a36Sopenharmony_ci	for (i = 0; i < fusion->reply_q_depth * count; i++, reply_desc++)
77362306a36Sopenharmony_ci		reply_desc->Words = cpu_to_le64(ULLONG_MAX);
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	/* This is not a rdpq mode, but driver still populate
77662306a36Sopenharmony_ci	 * reply_frame_desc array to use same msix index in ISR path.
77762306a36Sopenharmony_ci	 */
77862306a36Sopenharmony_ci	for (i = 0; i < (count - 1); i++)
77962306a36Sopenharmony_ci		fusion->reply_frames_desc[i + 1] =
78062306a36Sopenharmony_ci			fusion->reply_frames_desc[i] +
78162306a36Sopenharmony_ci			(fusion->reply_alloc_sz)/sizeof(union MPI2_REPLY_DESCRIPTORS_UNION);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	return 0;
78462306a36Sopenharmony_ci}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_cistatic int
78762306a36Sopenharmony_cimegasas_alloc_rdpq_fusion(struct megasas_instance *instance)
78862306a36Sopenharmony_ci{
78962306a36Sopenharmony_ci	int i, j, k, msix_count;
79062306a36Sopenharmony_ci	struct fusion_context *fusion;
79162306a36Sopenharmony_ci	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
79262306a36Sopenharmony_ci	union MPI2_REPLY_DESCRIPTORS_UNION *rdpq_chunk_virt[RDPQ_MAX_CHUNK_COUNT];
79362306a36Sopenharmony_ci	dma_addr_t rdpq_chunk_phys[RDPQ_MAX_CHUNK_COUNT];
79462306a36Sopenharmony_ci	u8 dma_alloc_count, abs_index;
79562306a36Sopenharmony_ci	u32 chunk_size, array_size, offset;
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	fusion = instance->ctrl_context;
79862306a36Sopenharmony_ci	chunk_size = fusion->reply_alloc_sz * RDPQ_MAX_INDEX_IN_ONE_CHUNK;
79962306a36Sopenharmony_ci	array_size = sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) *
80062306a36Sopenharmony_ci		     MAX_MSIX_QUEUES_FUSION;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	fusion->rdpq_virt = dma_alloc_coherent(&instance->pdev->dev,
80362306a36Sopenharmony_ci					       array_size, &fusion->rdpq_phys,
80462306a36Sopenharmony_ci					       GFP_KERNEL);
80562306a36Sopenharmony_ci	if (!fusion->rdpq_virt) {
80662306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
80762306a36Sopenharmony_ci			"Failed from %s %d\n",  __func__, __LINE__);
80862306a36Sopenharmony_ci		return -ENOMEM;
80962306a36Sopenharmony_ci	}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	msix_count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
81262306a36Sopenharmony_ci	msix_count += instance->iopoll_q_count;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	fusion->reply_frames_desc_pool = dma_pool_create("mr_rdpq",
81562306a36Sopenharmony_ci							 &instance->pdev->dev,
81662306a36Sopenharmony_ci							 chunk_size, 16, 0);
81762306a36Sopenharmony_ci	fusion->reply_frames_desc_pool_align =
81862306a36Sopenharmony_ci				dma_pool_create("mr_rdpq_align",
81962306a36Sopenharmony_ci						&instance->pdev->dev,
82062306a36Sopenharmony_ci						chunk_size,
82162306a36Sopenharmony_ci						roundup_pow_of_two(chunk_size),
82262306a36Sopenharmony_ci						0);
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	if (!fusion->reply_frames_desc_pool ||
82562306a36Sopenharmony_ci	    !fusion->reply_frames_desc_pool_align) {
82662306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
82762306a36Sopenharmony_ci			"Failed from %s %d\n",  __func__, __LINE__);
82862306a36Sopenharmony_ci		return -ENOMEM;
82962306a36Sopenharmony_ci	}
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci/*
83262306a36Sopenharmony_ci * For INVADER_SERIES each set of 8 reply queues(0-7, 8-15, ..) and
83362306a36Sopenharmony_ci * VENTURA_SERIES each set of 16 reply queues(0-15, 16-31, ..) should be
83462306a36Sopenharmony_ci * within 4GB boundary and also reply queues in a set must have same
83562306a36Sopenharmony_ci * upper 32-bits in their memory address. so here driver is allocating the
83662306a36Sopenharmony_ci * DMA'able memory for reply queues according. Driver uses limitation of
83762306a36Sopenharmony_ci * VENTURA_SERIES to manage INVADER_SERIES as well.
83862306a36Sopenharmony_ci */
83962306a36Sopenharmony_ci	dma_alloc_count = DIV_ROUND_UP(msix_count, RDPQ_MAX_INDEX_IN_ONE_CHUNK);
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	for (i = 0; i < dma_alloc_count; i++) {
84262306a36Sopenharmony_ci		rdpq_chunk_virt[i] =
84362306a36Sopenharmony_ci			dma_pool_alloc(fusion->reply_frames_desc_pool,
84462306a36Sopenharmony_ci				       GFP_KERNEL, &rdpq_chunk_phys[i]);
84562306a36Sopenharmony_ci		if (!rdpq_chunk_virt[i]) {
84662306a36Sopenharmony_ci			dev_err(&instance->pdev->dev,
84762306a36Sopenharmony_ci				"Failed from %s %d\n",  __func__, __LINE__);
84862306a36Sopenharmony_ci			return -ENOMEM;
84962306a36Sopenharmony_ci		}
85062306a36Sopenharmony_ci		/* reply desc pool requires to be in same 4 gb region.
85162306a36Sopenharmony_ci		 * Below function will check this.
85262306a36Sopenharmony_ci		 * In case of failure, new pci pool will be created with updated
85362306a36Sopenharmony_ci		 * alignment.
85462306a36Sopenharmony_ci		 * For RDPQ buffers, driver always allocate two separate pci pool.
85562306a36Sopenharmony_ci		 * Alignment will be used such a way that next allocation if
85662306a36Sopenharmony_ci		 * success, will always meet same 4gb region requirement.
85762306a36Sopenharmony_ci		 * rdpq_tracker keep track of each buffer's physical,
85862306a36Sopenharmony_ci		 * virtual address and pci pool descriptor. It will help driver
85962306a36Sopenharmony_ci		 * while freeing the resources.
86062306a36Sopenharmony_ci		 *
86162306a36Sopenharmony_ci		 */
86262306a36Sopenharmony_ci		if (!megasas_check_same_4gb_region(instance, rdpq_chunk_phys[i],
86362306a36Sopenharmony_ci						   chunk_size)) {
86462306a36Sopenharmony_ci			dma_pool_free(fusion->reply_frames_desc_pool,
86562306a36Sopenharmony_ci				      rdpq_chunk_virt[i],
86662306a36Sopenharmony_ci				      rdpq_chunk_phys[i]);
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci			rdpq_chunk_virt[i] =
86962306a36Sopenharmony_ci				dma_pool_alloc(fusion->reply_frames_desc_pool_align,
87062306a36Sopenharmony_ci					       GFP_KERNEL, &rdpq_chunk_phys[i]);
87162306a36Sopenharmony_ci			if (!rdpq_chunk_virt[i]) {
87262306a36Sopenharmony_ci				dev_err(&instance->pdev->dev,
87362306a36Sopenharmony_ci					"Failed from %s %d\n",
87462306a36Sopenharmony_ci					__func__, __LINE__);
87562306a36Sopenharmony_ci				return -ENOMEM;
87662306a36Sopenharmony_ci			}
87762306a36Sopenharmony_ci			fusion->rdpq_tracker[i].dma_pool_ptr =
87862306a36Sopenharmony_ci					fusion->reply_frames_desc_pool_align;
87962306a36Sopenharmony_ci		} else {
88062306a36Sopenharmony_ci			fusion->rdpq_tracker[i].dma_pool_ptr =
88162306a36Sopenharmony_ci					fusion->reply_frames_desc_pool;
88262306a36Sopenharmony_ci		}
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci		fusion->rdpq_tracker[i].pool_entry_phys = rdpq_chunk_phys[i];
88562306a36Sopenharmony_ci		fusion->rdpq_tracker[i].pool_entry_virt = rdpq_chunk_virt[i];
88662306a36Sopenharmony_ci	}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	for (k = 0; k < dma_alloc_count; k++) {
88962306a36Sopenharmony_ci		for (i = 0; i < RDPQ_MAX_INDEX_IN_ONE_CHUNK; i++) {
89062306a36Sopenharmony_ci			abs_index = (k * RDPQ_MAX_INDEX_IN_ONE_CHUNK) + i;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci			if (abs_index == msix_count)
89362306a36Sopenharmony_ci				break;
89462306a36Sopenharmony_ci			offset = fusion->reply_alloc_sz * i;
89562306a36Sopenharmony_ci			fusion->rdpq_virt[abs_index].RDPQBaseAddress =
89662306a36Sopenharmony_ci					cpu_to_le64(rdpq_chunk_phys[k] + offset);
89762306a36Sopenharmony_ci			fusion->reply_frames_desc_phys[abs_index] =
89862306a36Sopenharmony_ci					rdpq_chunk_phys[k] + offset;
89962306a36Sopenharmony_ci			fusion->reply_frames_desc[abs_index] =
90062306a36Sopenharmony_ci					(union MPI2_REPLY_DESCRIPTORS_UNION *)((u8 *)rdpq_chunk_virt[k] + offset);
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci			reply_desc = fusion->reply_frames_desc[abs_index];
90362306a36Sopenharmony_ci			for (j = 0; j < fusion->reply_q_depth; j++, reply_desc++)
90462306a36Sopenharmony_ci				reply_desc->Words = ULLONG_MAX;
90562306a36Sopenharmony_ci		}
90662306a36Sopenharmony_ci	}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	return 0;
90962306a36Sopenharmony_ci}
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_cistatic void
91262306a36Sopenharmony_cimegasas_free_rdpq_fusion(struct megasas_instance *instance) {
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	int i;
91562306a36Sopenharmony_ci	struct fusion_context *fusion;
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	fusion = instance->ctrl_context;
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	for (i = 0; i < RDPQ_MAX_CHUNK_COUNT; i++) {
92062306a36Sopenharmony_ci		if (fusion->rdpq_tracker[i].pool_entry_virt)
92162306a36Sopenharmony_ci			dma_pool_free(fusion->rdpq_tracker[i].dma_pool_ptr,
92262306a36Sopenharmony_ci				      fusion->rdpq_tracker[i].pool_entry_virt,
92362306a36Sopenharmony_ci				      fusion->rdpq_tracker[i].pool_entry_phys);
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	}
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	dma_pool_destroy(fusion->reply_frames_desc_pool);
92862306a36Sopenharmony_ci	dma_pool_destroy(fusion->reply_frames_desc_pool_align);
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	if (fusion->rdpq_virt)
93162306a36Sopenharmony_ci		dma_free_coherent(&instance->pdev->dev,
93262306a36Sopenharmony_ci			sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION,
93362306a36Sopenharmony_ci			fusion->rdpq_virt, fusion->rdpq_phys);
93462306a36Sopenharmony_ci}
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_cistatic void
93762306a36Sopenharmony_cimegasas_free_reply_fusion(struct megasas_instance *instance) {
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	struct fusion_context *fusion;
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	fusion = instance->ctrl_context;
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	if (fusion->reply_frames_desc[0])
94462306a36Sopenharmony_ci		dma_pool_free(fusion->reply_frames_desc_pool,
94562306a36Sopenharmony_ci			fusion->reply_frames_desc[0],
94662306a36Sopenharmony_ci			fusion->reply_frames_desc_phys[0]);
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	dma_pool_destroy(fusion->reply_frames_desc_pool);
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci/**
95462306a36Sopenharmony_ci * megasas_alloc_cmds_fusion -	Allocates the command packets
95562306a36Sopenharmony_ci * @instance:		Adapter soft state
95662306a36Sopenharmony_ci *
95762306a36Sopenharmony_ci *
95862306a36Sopenharmony_ci * Each frame has a 32-bit field called context. This context is used to get
95962306a36Sopenharmony_ci * back the megasas_cmd_fusion from the frame when a frame gets completed
96062306a36Sopenharmony_ci * In this driver, the 32 bit values are the indices into an array cmd_list.
96162306a36Sopenharmony_ci * This array is used only to look up the megasas_cmd_fusion given the context.
96262306a36Sopenharmony_ci * The free commands themselves are maintained in a linked list called cmd_pool.
96362306a36Sopenharmony_ci *
96462306a36Sopenharmony_ci * cmds are formed in the io_request and sg_frame members of the
96562306a36Sopenharmony_ci * megasas_cmd_fusion. The context field is used to get a request descriptor
96662306a36Sopenharmony_ci * and is used as SMID of the cmd.
96762306a36Sopenharmony_ci * SMID value range is from 1 to max_fw_cmds.
96862306a36Sopenharmony_ci */
96962306a36Sopenharmony_cistatic int
97062306a36Sopenharmony_cimegasas_alloc_cmds_fusion(struct megasas_instance *instance)
97162306a36Sopenharmony_ci{
97262306a36Sopenharmony_ci	int i;
97362306a36Sopenharmony_ci	struct fusion_context *fusion;
97462306a36Sopenharmony_ci	struct megasas_cmd_fusion *cmd;
97562306a36Sopenharmony_ci	u32 offset;
97662306a36Sopenharmony_ci	dma_addr_t io_req_base_phys;
97762306a36Sopenharmony_ci	u8 *io_req_base;
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	fusion = instance->ctrl_context;
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	if (megasas_alloc_request_fusion(instance))
98362306a36Sopenharmony_ci		goto fail_exit;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	if (instance->is_rdpq) {
98662306a36Sopenharmony_ci		if (megasas_alloc_rdpq_fusion(instance))
98762306a36Sopenharmony_ci			goto fail_exit;
98862306a36Sopenharmony_ci	} else
98962306a36Sopenharmony_ci		if (megasas_alloc_reply_fusion(instance))
99062306a36Sopenharmony_ci			goto fail_exit;
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	if (megasas_alloc_cmdlist_fusion(instance))
99362306a36Sopenharmony_ci		goto fail_exit;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	/* The first 256 bytes (SMID 0) is not used. Don't add to the cmd list */
99662306a36Sopenharmony_ci	io_req_base = fusion->io_request_frames + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
99762306a36Sopenharmony_ci	io_req_base_phys = fusion->io_request_frames_phys + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	/*
100062306a36Sopenharmony_ci	 * Add all the commands to command pool (fusion->cmd_pool)
100162306a36Sopenharmony_ci	 */
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	/* SMID 0 is reserved. Set SMID/index from 1 */
100462306a36Sopenharmony_ci	for (i = 0; i < instance->max_mpt_cmds; i++) {
100562306a36Sopenharmony_ci		cmd = fusion->cmd_list[i];
100662306a36Sopenharmony_ci		offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i;
100762306a36Sopenharmony_ci		memset(cmd, 0, sizeof(struct megasas_cmd_fusion));
100862306a36Sopenharmony_ci		cmd->index = i + 1;
100962306a36Sopenharmony_ci		cmd->scmd = NULL;
101062306a36Sopenharmony_ci		cmd->sync_cmd_idx =
101162306a36Sopenharmony_ci		(i >= instance->max_scsi_cmds && i < instance->max_fw_cmds) ?
101262306a36Sopenharmony_ci				(i - instance->max_scsi_cmds) :
101362306a36Sopenharmony_ci				(u32)ULONG_MAX; /* Set to Invalid */
101462306a36Sopenharmony_ci		cmd->instance = instance;
101562306a36Sopenharmony_ci		cmd->io_request =
101662306a36Sopenharmony_ci			(struct MPI2_RAID_SCSI_IO_REQUEST *)
101762306a36Sopenharmony_ci		  (io_req_base + offset);
101862306a36Sopenharmony_ci		memset(cmd->io_request, 0,
101962306a36Sopenharmony_ci		       sizeof(struct MPI2_RAID_SCSI_IO_REQUEST));
102062306a36Sopenharmony_ci		cmd->io_request_phys_addr = io_req_base_phys + offset;
102162306a36Sopenharmony_ci		cmd->r1_alt_dev_handle = MR_DEVHANDLE_INVALID;
102262306a36Sopenharmony_ci	}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	if (megasas_create_sg_sense_fusion(instance))
102562306a36Sopenharmony_ci		goto fail_exit;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	return 0;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_cifail_exit:
103062306a36Sopenharmony_ci	megasas_free_cmds_fusion(instance);
103162306a36Sopenharmony_ci	return -ENOMEM;
103262306a36Sopenharmony_ci}
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci/**
103562306a36Sopenharmony_ci * wait_and_poll -	Issues a polling command
103662306a36Sopenharmony_ci * @instance:			Adapter soft state
103762306a36Sopenharmony_ci * @cmd:			Command packet to be issued
103862306a36Sopenharmony_ci * @seconds:			Maximum poll time
103962306a36Sopenharmony_ci *
104062306a36Sopenharmony_ci * For polling, MFI requires the cmd_status to be set to 0xFF before posting.
104162306a36Sopenharmony_ci */
104262306a36Sopenharmony_ciint
104362306a36Sopenharmony_ciwait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
104462306a36Sopenharmony_ci	int seconds)
104562306a36Sopenharmony_ci{
104662306a36Sopenharmony_ci	int i;
104762306a36Sopenharmony_ci	struct megasas_header *frame_hdr = &cmd->frame->hdr;
104862306a36Sopenharmony_ci	u32 status_reg;
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	u32 msecs = seconds * 1000;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	/*
105362306a36Sopenharmony_ci	 * Wait for cmd_status to change
105462306a36Sopenharmony_ci	 */
105562306a36Sopenharmony_ci	for (i = 0; (i < msecs) && (frame_hdr->cmd_status == 0xff); i += 20) {
105662306a36Sopenharmony_ci		rmb();
105762306a36Sopenharmony_ci		msleep(20);
105862306a36Sopenharmony_ci		if (!(i % 5000)) {
105962306a36Sopenharmony_ci			status_reg = instance->instancet->read_fw_status_reg(instance)
106062306a36Sopenharmony_ci					& MFI_STATE_MASK;
106162306a36Sopenharmony_ci			if (status_reg == MFI_STATE_FAULT)
106262306a36Sopenharmony_ci				break;
106362306a36Sopenharmony_ci		}
106462306a36Sopenharmony_ci	}
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	if (frame_hdr->cmd_status == MFI_STAT_INVALID_STATUS)
106762306a36Sopenharmony_ci		return DCMD_TIMEOUT;
106862306a36Sopenharmony_ci	else if (frame_hdr->cmd_status == MFI_STAT_OK)
106962306a36Sopenharmony_ci		return DCMD_SUCCESS;
107062306a36Sopenharmony_ci	else
107162306a36Sopenharmony_ci		return DCMD_FAILED;
107262306a36Sopenharmony_ci}
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci/**
107562306a36Sopenharmony_ci * megasas_ioc_init_fusion -	Initializes the FW
107662306a36Sopenharmony_ci * @instance:		Adapter soft state
107762306a36Sopenharmony_ci *
107862306a36Sopenharmony_ci * Issues the IOC Init cmd
107962306a36Sopenharmony_ci */
108062306a36Sopenharmony_ciint
108162306a36Sopenharmony_cimegasas_ioc_init_fusion(struct megasas_instance *instance)
108262306a36Sopenharmony_ci{
108362306a36Sopenharmony_ci	struct megasas_init_frame *init_frame;
108462306a36Sopenharmony_ci	struct MPI2_IOC_INIT_REQUEST *IOCInitMessage = NULL;
108562306a36Sopenharmony_ci	dma_addr_t	ioc_init_handle;
108662306a36Sopenharmony_ci	struct megasas_cmd *cmd;
108762306a36Sopenharmony_ci	u8 ret, cur_rdpq_mode;
108862306a36Sopenharmony_ci	struct fusion_context *fusion;
108962306a36Sopenharmony_ci	union MEGASAS_REQUEST_DESCRIPTOR_UNION req_desc;
109062306a36Sopenharmony_ci	int i;
109162306a36Sopenharmony_ci	struct megasas_header *frame_hdr;
109262306a36Sopenharmony_ci	const char *sys_info;
109362306a36Sopenharmony_ci	MFI_CAPABILITIES *drv_ops;
109462306a36Sopenharmony_ci	u32 scratch_pad_1;
109562306a36Sopenharmony_ci	ktime_t time;
109662306a36Sopenharmony_ci	bool cur_fw_64bit_dma_capable;
109762306a36Sopenharmony_ci	bool cur_intr_coalescing;
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	fusion = instance->ctrl_context;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	ioc_init_handle = fusion->ioc_init_request_phys;
110262306a36Sopenharmony_ci	IOCInitMessage = fusion->ioc_init_request;
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	cmd = fusion->ioc_init_cmd;
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	scratch_pad_1 = megasas_readl
110762306a36Sopenharmony_ci		(instance, &instance->reg_set->outbound_scratch_pad_1);
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	cur_rdpq_mode = (scratch_pad_1 & MR_RDPQ_MODE_OFFSET) ? 1 : 0;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	if (instance->adapter_type == INVADER_SERIES) {
111262306a36Sopenharmony_ci		cur_fw_64bit_dma_capable =
111362306a36Sopenharmony_ci			(scratch_pad_1 & MR_CAN_HANDLE_64_BIT_DMA_OFFSET) ? true : false;
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci		if (instance->consistent_mask_64bit && !cur_fw_64bit_dma_capable) {
111662306a36Sopenharmony_ci			dev_err(&instance->pdev->dev, "Driver was operating on 64bit "
111762306a36Sopenharmony_ci				"DMA mask, but upcoming FW does not support 64bit DMA mask\n");
111862306a36Sopenharmony_ci			megaraid_sas_kill_hba(instance);
111962306a36Sopenharmony_ci			ret = 1;
112062306a36Sopenharmony_ci			goto fail_fw_init;
112162306a36Sopenharmony_ci		}
112262306a36Sopenharmony_ci	}
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	if (instance->is_rdpq && !cur_rdpq_mode) {
112562306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "Firmware downgrade *NOT SUPPORTED*"
112662306a36Sopenharmony_ci			" from RDPQ mode to non RDPQ mode\n");
112762306a36Sopenharmony_ci		ret = 1;
112862306a36Sopenharmony_ci		goto fail_fw_init;
112962306a36Sopenharmony_ci	}
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	cur_intr_coalescing = (scratch_pad_1 & MR_INTR_COALESCING_SUPPORT_OFFSET) ?
113262306a36Sopenharmony_ci							true : false;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	if ((instance->low_latency_index_start ==
113562306a36Sopenharmony_ci		MR_HIGH_IOPS_QUEUE_COUNT) && cur_intr_coalescing)
113662306a36Sopenharmony_ci		instance->perf_mode = MR_BALANCED_PERF_MODE;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	dev_info(&instance->pdev->dev, "Performance mode :%s (latency index = %d)\n",
113962306a36Sopenharmony_ci		MEGASAS_PERF_MODE_2STR(instance->perf_mode),
114062306a36Sopenharmony_ci		instance->low_latency_index_start);
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	instance->fw_sync_cache_support = (scratch_pad_1 &
114362306a36Sopenharmony_ci		MR_CAN_HANDLE_SYNC_CACHE_OFFSET) ? 1 : 0;
114462306a36Sopenharmony_ci	dev_info(&instance->pdev->dev, "FW supports sync cache\t: %s\n",
114562306a36Sopenharmony_ci		 instance->fw_sync_cache_support ? "Yes" : "No");
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	memset(IOCInitMessage, 0, sizeof(struct MPI2_IOC_INIT_REQUEST));
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	IOCInitMessage->Function = MPI2_FUNCTION_IOC_INIT;
115062306a36Sopenharmony_ci	IOCInitMessage->WhoInit	= MPI2_WHOINIT_HOST_DRIVER;
115162306a36Sopenharmony_ci	IOCInitMessage->MsgVersion = cpu_to_le16(MPI2_VERSION);
115262306a36Sopenharmony_ci	IOCInitMessage->HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION);
115362306a36Sopenharmony_ci	IOCInitMessage->SystemRequestFrameSize = cpu_to_le16(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4);
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	IOCInitMessage->ReplyDescriptorPostQueueDepth = cpu_to_le16(fusion->reply_q_depth);
115662306a36Sopenharmony_ci	IOCInitMessage->ReplyDescriptorPostQueueAddress = instance->is_rdpq ?
115762306a36Sopenharmony_ci			cpu_to_le64(fusion->rdpq_phys) :
115862306a36Sopenharmony_ci			cpu_to_le64(fusion->reply_frames_desc_phys[0]);
115962306a36Sopenharmony_ci	IOCInitMessage->MsgFlags = instance->is_rdpq ?
116062306a36Sopenharmony_ci			MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE : 0;
116162306a36Sopenharmony_ci	IOCInitMessage->SystemRequestFrameBaseAddress = cpu_to_le64(fusion->io_request_frames_phys);
116262306a36Sopenharmony_ci	IOCInitMessage->SenseBufferAddressHigh = cpu_to_le32(upper_32_bits(fusion->sense_phys_addr));
116362306a36Sopenharmony_ci	IOCInitMessage->HostMSIxVectors = instance->msix_vectors + instance->iopoll_q_count;
116462306a36Sopenharmony_ci	IOCInitMessage->HostPageSize = MR_DEFAULT_NVME_PAGE_SHIFT;
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	time = ktime_get_real();
116762306a36Sopenharmony_ci	/* Convert to milliseconds as per FW requirement */
116862306a36Sopenharmony_ci	IOCInitMessage->TimeStamp = cpu_to_le64(ktime_to_ms(time));
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	init_frame = (struct megasas_init_frame *)cmd->frame;
117162306a36Sopenharmony_ci	memset(init_frame, 0, IOC_INIT_FRAME_SIZE);
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	frame_hdr = &cmd->frame->hdr;
117462306a36Sopenharmony_ci	frame_hdr->cmd_status = 0xFF;
117562306a36Sopenharmony_ci	frame_hdr->flags |= cpu_to_le16(MFI_FRAME_DONT_POST_IN_REPLY_QUEUE);
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	init_frame->cmd	= MFI_CMD_INIT;
117862306a36Sopenharmony_ci	init_frame->cmd_status = 0xFF;
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	drv_ops = (MFI_CAPABILITIES *) &(init_frame->driver_operations);
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	/* driver support Extended MSIX */
118362306a36Sopenharmony_ci	if (instance->adapter_type >= INVADER_SERIES)
118462306a36Sopenharmony_ci		drv_ops->mfi_capabilities.support_additional_msix = 1;
118562306a36Sopenharmony_ci	/* driver supports HA / Remote LUN over Fast Path interface */
118662306a36Sopenharmony_ci	drv_ops->mfi_capabilities.support_fp_remote_lun = 1;
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	drv_ops->mfi_capabilities.support_max_255lds = 1;
118962306a36Sopenharmony_ci	drv_ops->mfi_capabilities.support_ndrive_r1_lb = 1;
119062306a36Sopenharmony_ci	drv_ops->mfi_capabilities.security_protocol_cmds_fw = 1;
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	if (instance->max_chain_frame_sz > MEGASAS_CHAIN_FRAME_SZ_MIN)
119362306a36Sopenharmony_ci		drv_ops->mfi_capabilities.support_ext_io_size = 1;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	drv_ops->mfi_capabilities.support_fp_rlbypass = 1;
119662306a36Sopenharmony_ci	if (!dual_qdepth_disable)
119762306a36Sopenharmony_ci		drv_ops->mfi_capabilities.support_ext_queue_depth = 1;
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	drv_ops->mfi_capabilities.support_qd_throttling = 1;
120062306a36Sopenharmony_ci	drv_ops->mfi_capabilities.support_pd_map_target_id = 1;
120162306a36Sopenharmony_ci	drv_ops->mfi_capabilities.support_nvme_passthru = 1;
120262306a36Sopenharmony_ci	drv_ops->mfi_capabilities.support_fw_exposed_dev_list = 1;
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	if (reset_devices)
120562306a36Sopenharmony_ci		drv_ops->mfi_capabilities.support_memdump = 1;
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	if (instance->consistent_mask_64bit)
120862306a36Sopenharmony_ci		drv_ops->mfi_capabilities.support_64bit_mode = 1;
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	/* Convert capability to LE32 */
121162306a36Sopenharmony_ci	cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities);
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	sys_info = dmi_get_system_info(DMI_PRODUCT_UUID);
121462306a36Sopenharmony_ci	if (instance->system_info_buf && sys_info) {
121562306a36Sopenharmony_ci		memcpy(instance->system_info_buf->systemId, sys_info,
121662306a36Sopenharmony_ci			strlen(sys_info) > 64 ? 64 : strlen(sys_info));
121762306a36Sopenharmony_ci		instance->system_info_buf->systemIdLength =
121862306a36Sopenharmony_ci			strlen(sys_info) > 64 ? 64 : strlen(sys_info);
121962306a36Sopenharmony_ci		init_frame->system_info_lo = cpu_to_le32(lower_32_bits(instance->system_info_h));
122062306a36Sopenharmony_ci		init_frame->system_info_hi = cpu_to_le32(upper_32_bits(instance->system_info_h));
122162306a36Sopenharmony_ci	}
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	init_frame->queue_info_new_phys_addr_hi =
122462306a36Sopenharmony_ci		cpu_to_le32(upper_32_bits(ioc_init_handle));
122562306a36Sopenharmony_ci	init_frame->queue_info_new_phys_addr_lo =
122662306a36Sopenharmony_ci		cpu_to_le32(lower_32_bits(ioc_init_handle));
122762306a36Sopenharmony_ci	init_frame->data_xfer_len = cpu_to_le32(sizeof(struct MPI2_IOC_INIT_REQUEST));
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	/*
123062306a36Sopenharmony_ci	 * Each bit in replyqueue_mask represents one group of MSI-x vectors
123162306a36Sopenharmony_ci	 * (each group has 8 vectors)
123262306a36Sopenharmony_ci	 */
123362306a36Sopenharmony_ci	switch (instance->perf_mode) {
123462306a36Sopenharmony_ci	case MR_BALANCED_PERF_MODE:
123562306a36Sopenharmony_ci		init_frame->replyqueue_mask =
123662306a36Sopenharmony_ci		       cpu_to_le16(~(~0 << instance->low_latency_index_start/8));
123762306a36Sopenharmony_ci		break;
123862306a36Sopenharmony_ci	case MR_IOPS_PERF_MODE:
123962306a36Sopenharmony_ci		init_frame->replyqueue_mask =
124062306a36Sopenharmony_ci		       cpu_to_le16(~(~0 << instance->msix_vectors/8));
124162306a36Sopenharmony_ci		break;
124262306a36Sopenharmony_ci	}
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	req_desc.u.low = cpu_to_le32(lower_32_bits(cmd->frame_phys_addr));
124662306a36Sopenharmony_ci	req_desc.u.high = cpu_to_le32(upper_32_bits(cmd->frame_phys_addr));
124762306a36Sopenharmony_ci	req_desc.MFAIo.RequestFlags =
124862306a36Sopenharmony_ci		(MEGASAS_REQ_DESCRIPT_FLAGS_MFA <<
124962306a36Sopenharmony_ci		MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	/*
125262306a36Sopenharmony_ci	 * disable the intr before firing the init frame
125362306a36Sopenharmony_ci	 */
125462306a36Sopenharmony_ci	instance->instancet->disable_intr(instance);
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	for (i = 0; i < (10 * 1000); i += 20) {
125762306a36Sopenharmony_ci		if (megasas_readl(instance, &instance->reg_set->doorbell) & 1)
125862306a36Sopenharmony_ci			msleep(20);
125962306a36Sopenharmony_ci		else
126062306a36Sopenharmony_ci			break;
126162306a36Sopenharmony_ci	}
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	/* For AERO also, IOC_INIT requires 64 bit descriptor write */
126462306a36Sopenharmony_ci	megasas_write_64bit_req_desc(instance, &req_desc);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	wait_and_poll(instance, cmd, MFI_IO_TIMEOUT_SECS);
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	frame_hdr = &cmd->frame->hdr;
126962306a36Sopenharmony_ci	if (frame_hdr->cmd_status != 0) {
127062306a36Sopenharmony_ci		ret = 1;
127162306a36Sopenharmony_ci		goto fail_fw_init;
127262306a36Sopenharmony_ci	}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	if (instance->adapter_type >= AERO_SERIES) {
127562306a36Sopenharmony_ci		scratch_pad_1 = megasas_readl
127662306a36Sopenharmony_ci			(instance, &instance->reg_set->outbound_scratch_pad_1);
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci		instance->atomic_desc_support =
127962306a36Sopenharmony_ci			(scratch_pad_1 & MR_ATOMIC_DESCRIPTOR_SUPPORT_OFFSET) ? 1 : 0;
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci		dev_info(&instance->pdev->dev, "FW supports atomic descriptor\t: %s\n",
128262306a36Sopenharmony_ci			instance->atomic_desc_support ? "Yes" : "No");
128362306a36Sopenharmony_ci	}
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	return 0;
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_cifail_fw_init:
128862306a36Sopenharmony_ci	dev_err(&instance->pdev->dev,
128962306a36Sopenharmony_ci		"Init cmd return status FAILED for SCSI host %d\n",
129062306a36Sopenharmony_ci		instance->host->host_no);
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	return ret;
129362306a36Sopenharmony_ci}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci/**
129662306a36Sopenharmony_ci * megasas_sync_pd_seq_num -	JBOD SEQ MAP
129762306a36Sopenharmony_ci * @instance:		Adapter soft state
129862306a36Sopenharmony_ci * @pend:		set to 1, if it is pended jbod map.
129962306a36Sopenharmony_ci *
130062306a36Sopenharmony_ci * Issue Jbod map to the firmware. If it is pended command,
130162306a36Sopenharmony_ci * issue command and return. If it is first instance of jbod map
130262306a36Sopenharmony_ci * issue and receive command.
130362306a36Sopenharmony_ci */
130462306a36Sopenharmony_ciint
130562306a36Sopenharmony_cimegasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) {
130662306a36Sopenharmony_ci	int ret = 0;
130762306a36Sopenharmony_ci	size_t pd_seq_map_sz;
130862306a36Sopenharmony_ci	struct megasas_cmd *cmd;
130962306a36Sopenharmony_ci	struct megasas_dcmd_frame *dcmd;
131062306a36Sopenharmony_ci	struct fusion_context *fusion = instance->ctrl_context;
131162306a36Sopenharmony_ci	struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync;
131262306a36Sopenharmony_ci	dma_addr_t pd_seq_h;
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	pd_sync = (void *)fusion->pd_seq_sync[(instance->pd_seq_map_id & 1)];
131562306a36Sopenharmony_ci	pd_seq_h = fusion->pd_seq_phys[(instance->pd_seq_map_id & 1)];
131662306a36Sopenharmony_ci	pd_seq_map_sz = struct_size(pd_sync, seq, MAX_PHYSICAL_DEVICES);
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	cmd = megasas_get_cmd(instance);
131962306a36Sopenharmony_ci	if (!cmd) {
132062306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
132162306a36Sopenharmony_ci			"Could not get mfi cmd. Fail from %s %d\n",
132262306a36Sopenharmony_ci			__func__, __LINE__);
132362306a36Sopenharmony_ci		return -ENOMEM;
132462306a36Sopenharmony_ci	}
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	dcmd = &cmd->frame->dcmd;
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	memset(pd_sync, 0, pd_seq_map_sz);
132962306a36Sopenharmony_ci	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	if (pend) {
133262306a36Sopenharmony_ci		dcmd->mbox.b[0] = MEGASAS_DCMD_MBOX_PEND_FLAG;
133362306a36Sopenharmony_ci		dcmd->flags = MFI_FRAME_DIR_WRITE;
133462306a36Sopenharmony_ci		instance->jbod_seq_cmd = cmd;
133562306a36Sopenharmony_ci	} else {
133662306a36Sopenharmony_ci		dcmd->flags = MFI_FRAME_DIR_READ;
133762306a36Sopenharmony_ci	}
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	dcmd->cmd = MFI_CMD_DCMD;
134062306a36Sopenharmony_ci	dcmd->cmd_status = 0xFF;
134162306a36Sopenharmony_ci	dcmd->sge_count = 1;
134262306a36Sopenharmony_ci	dcmd->timeout = 0;
134362306a36Sopenharmony_ci	dcmd->pad_0 = 0;
134462306a36Sopenharmony_ci	dcmd->data_xfer_len = cpu_to_le32(pd_seq_map_sz);
134562306a36Sopenharmony_ci	dcmd->opcode = cpu_to_le32(MR_DCMD_SYSTEM_PD_MAP_GET_INFO);
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	megasas_set_dma_settings(instance, dcmd, pd_seq_h, pd_seq_map_sz);
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	if (pend) {
135062306a36Sopenharmony_ci		instance->instancet->issue_dcmd(instance, cmd);
135162306a36Sopenharmony_ci		return 0;
135262306a36Sopenharmony_ci	}
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	/* Below code is only for non pended DCMD */
135562306a36Sopenharmony_ci	if (!instance->mask_interrupts)
135662306a36Sopenharmony_ci		ret = megasas_issue_blocked_cmd(instance, cmd,
135762306a36Sopenharmony_ci			MFI_IO_TIMEOUT_SECS);
135862306a36Sopenharmony_ci	else
135962306a36Sopenharmony_ci		ret = megasas_issue_polled(instance, cmd);
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	if (le32_to_cpu(pd_sync->count) > MAX_PHYSICAL_DEVICES) {
136262306a36Sopenharmony_ci		dev_warn(&instance->pdev->dev,
136362306a36Sopenharmony_ci			"driver supports max %d JBOD, but FW reports %d\n",
136462306a36Sopenharmony_ci			MAX_PHYSICAL_DEVICES, le32_to_cpu(pd_sync->count));
136562306a36Sopenharmony_ci		ret = -EINVAL;
136662306a36Sopenharmony_ci	}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	if (ret == DCMD_TIMEOUT)
136962306a36Sopenharmony_ci		dev_warn(&instance->pdev->dev,
137062306a36Sopenharmony_ci			 "%s DCMD timed out, continue without JBOD sequence map\n",
137162306a36Sopenharmony_ci			 __func__);
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	if (ret == DCMD_SUCCESS)
137462306a36Sopenharmony_ci		instance->pd_seq_map_id++;
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	megasas_return_cmd(instance, cmd);
137762306a36Sopenharmony_ci	return ret;
137862306a36Sopenharmony_ci}
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci/*
138162306a36Sopenharmony_ci * megasas_get_ld_map_info -	Returns FW's ld_map structure
138262306a36Sopenharmony_ci * @instance:				Adapter soft state
138362306a36Sopenharmony_ci * @pend:				Pend the command or not
138462306a36Sopenharmony_ci * Issues an internal command (DCMD) to get the FW's controller PD
138562306a36Sopenharmony_ci * list structure.  This information is mainly used to find out SYSTEM
138662306a36Sopenharmony_ci * supported by the FW.
138762306a36Sopenharmony_ci * dcmd.mbox value setting for MR_DCMD_LD_MAP_GET_INFO
138862306a36Sopenharmony_ci * dcmd.mbox.b[0]	- number of LDs being sync'd
138962306a36Sopenharmony_ci * dcmd.mbox.b[1]	- 0 - complete command immediately.
139062306a36Sopenharmony_ci *			- 1 - pend till config change
139162306a36Sopenharmony_ci * dcmd.mbox.b[2]	- 0 - supports max 64 lds and uses legacy MR_FW_RAID_MAP
139262306a36Sopenharmony_ci *			- 1 - supports max MAX_LOGICAL_DRIVES_EXT lds and
139362306a36Sopenharmony_ci *				uses extended struct MR_FW_RAID_MAP_EXT
139462306a36Sopenharmony_ci */
139562306a36Sopenharmony_cistatic int
139662306a36Sopenharmony_cimegasas_get_ld_map_info(struct megasas_instance *instance)
139762306a36Sopenharmony_ci{
139862306a36Sopenharmony_ci	int ret = 0;
139962306a36Sopenharmony_ci	struct megasas_cmd *cmd;
140062306a36Sopenharmony_ci	struct megasas_dcmd_frame *dcmd;
140162306a36Sopenharmony_ci	void *ci;
140262306a36Sopenharmony_ci	dma_addr_t ci_h = 0;
140362306a36Sopenharmony_ci	u32 size_map_info;
140462306a36Sopenharmony_ci	struct fusion_context *fusion;
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	cmd = megasas_get_cmd(instance);
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	if (!cmd) {
140962306a36Sopenharmony_ci		dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to get cmd for map info\n");
141062306a36Sopenharmony_ci		return -ENOMEM;
141162306a36Sopenharmony_ci	}
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	fusion = instance->ctrl_context;
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	if (!fusion) {
141662306a36Sopenharmony_ci		megasas_return_cmd(instance, cmd);
141762306a36Sopenharmony_ci		return -ENXIO;
141862306a36Sopenharmony_ci	}
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	dcmd = &cmd->frame->dcmd;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	size_map_info = fusion->current_map_sz;
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	ci = (void *) fusion->ld_map[(instance->map_id & 1)];
142562306a36Sopenharmony_ci	ci_h = fusion->ld_map_phys[(instance->map_id & 1)];
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	if (!ci) {
142862306a36Sopenharmony_ci		dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to alloc mem for ld_map_info\n");
142962306a36Sopenharmony_ci		megasas_return_cmd(instance, cmd);
143062306a36Sopenharmony_ci		return -ENOMEM;
143162306a36Sopenharmony_ci	}
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci	memset(ci, 0, fusion->max_map_sz);
143462306a36Sopenharmony_ci	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
143562306a36Sopenharmony_ci	dcmd->cmd = MFI_CMD_DCMD;
143662306a36Sopenharmony_ci	dcmd->cmd_status = 0xFF;
143762306a36Sopenharmony_ci	dcmd->sge_count = 1;
143862306a36Sopenharmony_ci	dcmd->flags = MFI_FRAME_DIR_READ;
143962306a36Sopenharmony_ci	dcmd->timeout = 0;
144062306a36Sopenharmony_ci	dcmd->pad_0 = 0;
144162306a36Sopenharmony_ci	dcmd->data_xfer_len = cpu_to_le32(size_map_info);
144262306a36Sopenharmony_ci	dcmd->opcode = cpu_to_le32(MR_DCMD_LD_MAP_GET_INFO);
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	megasas_set_dma_settings(instance, dcmd, ci_h, size_map_info);
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	if (!instance->mask_interrupts)
144762306a36Sopenharmony_ci		ret = megasas_issue_blocked_cmd(instance, cmd,
144862306a36Sopenharmony_ci			MFI_IO_TIMEOUT_SECS);
144962306a36Sopenharmony_ci	else
145062306a36Sopenharmony_ci		ret = megasas_issue_polled(instance, cmd);
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	if (ret == DCMD_TIMEOUT)
145362306a36Sopenharmony_ci		dev_warn(&instance->pdev->dev,
145462306a36Sopenharmony_ci			 "%s DCMD timed out, RAID map is disabled\n",
145562306a36Sopenharmony_ci			 __func__);
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	megasas_return_cmd(instance, cmd);
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	return ret;
146062306a36Sopenharmony_ci}
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ciu8
146362306a36Sopenharmony_cimegasas_get_map_info(struct megasas_instance *instance)
146462306a36Sopenharmony_ci{
146562306a36Sopenharmony_ci	struct fusion_context *fusion = instance->ctrl_context;
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	fusion->fast_path_io = 0;
146862306a36Sopenharmony_ci	if (!megasas_get_ld_map_info(instance)) {
146962306a36Sopenharmony_ci		if (MR_ValidateMapInfo(instance, instance->map_id)) {
147062306a36Sopenharmony_ci			fusion->fast_path_io = 1;
147162306a36Sopenharmony_ci			return 0;
147262306a36Sopenharmony_ci		}
147362306a36Sopenharmony_ci	}
147462306a36Sopenharmony_ci	return 1;
147562306a36Sopenharmony_ci}
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci/*
147862306a36Sopenharmony_ci * megasas_sync_map_info -	Returns FW's ld_map structure
147962306a36Sopenharmony_ci * @instance:				Adapter soft state
148062306a36Sopenharmony_ci *
148162306a36Sopenharmony_ci * Issues an internal command (DCMD) to get the FW's controller PD
148262306a36Sopenharmony_ci * list structure.  This information is mainly used to find out SYSTEM
148362306a36Sopenharmony_ci * supported by the FW.
148462306a36Sopenharmony_ci */
148562306a36Sopenharmony_ciint
148662306a36Sopenharmony_cimegasas_sync_map_info(struct megasas_instance *instance)
148762306a36Sopenharmony_ci{
148862306a36Sopenharmony_ci	int i;
148962306a36Sopenharmony_ci	struct megasas_cmd *cmd;
149062306a36Sopenharmony_ci	struct megasas_dcmd_frame *dcmd;
149162306a36Sopenharmony_ci	u16 num_lds;
149262306a36Sopenharmony_ci	struct fusion_context *fusion;
149362306a36Sopenharmony_ci	struct MR_LD_TARGET_SYNC *ci = NULL;
149462306a36Sopenharmony_ci	struct MR_DRV_RAID_MAP_ALL *map;
149562306a36Sopenharmony_ci	struct MR_LD_RAID  *raid;
149662306a36Sopenharmony_ci	struct MR_LD_TARGET_SYNC *ld_sync;
149762306a36Sopenharmony_ci	dma_addr_t ci_h = 0;
149862306a36Sopenharmony_ci	u32 size_map_info;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	cmd = megasas_get_cmd(instance);
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	if (!cmd) {
150362306a36Sopenharmony_ci		dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to get cmd for sync info\n");
150462306a36Sopenharmony_ci		return -ENOMEM;
150562306a36Sopenharmony_ci	}
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci	fusion = instance->ctrl_context;
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	if (!fusion) {
151062306a36Sopenharmony_ci		megasas_return_cmd(instance, cmd);
151162306a36Sopenharmony_ci		return 1;
151262306a36Sopenharmony_ci	}
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	map = fusion->ld_drv_map[instance->map_id & 1];
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	num_lds = le16_to_cpu(map->raidMap.ldCount);
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	dcmd = &cmd->frame->dcmd;
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	ci = (struct MR_LD_TARGET_SYNC *)
152362306a36Sopenharmony_ci	  fusion->ld_map[(instance->map_id - 1) & 1];
152462306a36Sopenharmony_ci	memset(ci, 0, fusion->max_map_sz);
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	ci_h = fusion->ld_map_phys[(instance->map_id - 1) & 1];
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	ld_sync = (struct MR_LD_TARGET_SYNC *)ci;
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	for (i = 0; i < num_lds; i++, ld_sync++) {
153162306a36Sopenharmony_ci		raid = MR_LdRaidGet(i, map);
153262306a36Sopenharmony_ci		ld_sync->targetId = MR_GetLDTgtId(i, map);
153362306a36Sopenharmony_ci		ld_sync->seqNum = raid->seqNum;
153462306a36Sopenharmony_ci	}
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci	size_map_info = fusion->current_map_sz;
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci	dcmd->cmd = MFI_CMD_DCMD;
153962306a36Sopenharmony_ci	dcmd->cmd_status = 0xFF;
154062306a36Sopenharmony_ci	dcmd->sge_count = 1;
154162306a36Sopenharmony_ci	dcmd->flags = MFI_FRAME_DIR_WRITE;
154262306a36Sopenharmony_ci	dcmd->timeout = 0;
154362306a36Sopenharmony_ci	dcmd->pad_0 = 0;
154462306a36Sopenharmony_ci	dcmd->data_xfer_len = cpu_to_le32(size_map_info);
154562306a36Sopenharmony_ci	dcmd->mbox.b[0] = num_lds;
154662306a36Sopenharmony_ci	dcmd->mbox.b[1] = MEGASAS_DCMD_MBOX_PEND_FLAG;
154762306a36Sopenharmony_ci	dcmd->opcode = cpu_to_le32(MR_DCMD_LD_MAP_GET_INFO);
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	megasas_set_dma_settings(instance, dcmd, ci_h, size_map_info);
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	instance->map_update_cmd = cmd;
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	instance->instancet->issue_dcmd(instance, cmd);
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci	return 0;
155662306a36Sopenharmony_ci}
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci/*
155962306a36Sopenharmony_ci * meagasas_display_intel_branding - Display branding string
156062306a36Sopenharmony_ci * @instance: per adapter object
156162306a36Sopenharmony_ci *
156262306a36Sopenharmony_ci * Return nothing.
156362306a36Sopenharmony_ci */
156462306a36Sopenharmony_cistatic void
156562306a36Sopenharmony_cimegasas_display_intel_branding(struct megasas_instance *instance)
156662306a36Sopenharmony_ci{
156762306a36Sopenharmony_ci	if (instance->pdev->subsystem_vendor != PCI_VENDOR_ID_INTEL)
156862306a36Sopenharmony_ci		return;
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci	switch (instance->pdev->device) {
157162306a36Sopenharmony_ci	case PCI_DEVICE_ID_LSI_INVADER:
157262306a36Sopenharmony_ci		switch (instance->pdev->subsystem_device) {
157362306a36Sopenharmony_ci		case MEGARAID_INTEL_RS3DC080_SSDID:
157462306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "scsi host %d: %s\n",
157562306a36Sopenharmony_ci				instance->host->host_no,
157662306a36Sopenharmony_ci				MEGARAID_INTEL_RS3DC080_BRANDING);
157762306a36Sopenharmony_ci			break;
157862306a36Sopenharmony_ci		case MEGARAID_INTEL_RS3DC040_SSDID:
157962306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "scsi host %d: %s\n",
158062306a36Sopenharmony_ci				instance->host->host_no,
158162306a36Sopenharmony_ci				MEGARAID_INTEL_RS3DC040_BRANDING);
158262306a36Sopenharmony_ci			break;
158362306a36Sopenharmony_ci		case MEGARAID_INTEL_RS3SC008_SSDID:
158462306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "scsi host %d: %s\n",
158562306a36Sopenharmony_ci				instance->host->host_no,
158662306a36Sopenharmony_ci				MEGARAID_INTEL_RS3SC008_BRANDING);
158762306a36Sopenharmony_ci			break;
158862306a36Sopenharmony_ci		case MEGARAID_INTEL_RS3MC044_SSDID:
158962306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "scsi host %d: %s\n",
159062306a36Sopenharmony_ci				instance->host->host_no,
159162306a36Sopenharmony_ci				MEGARAID_INTEL_RS3MC044_BRANDING);
159262306a36Sopenharmony_ci			break;
159362306a36Sopenharmony_ci		default:
159462306a36Sopenharmony_ci			break;
159562306a36Sopenharmony_ci		}
159662306a36Sopenharmony_ci		break;
159762306a36Sopenharmony_ci	case PCI_DEVICE_ID_LSI_FURY:
159862306a36Sopenharmony_ci		switch (instance->pdev->subsystem_device) {
159962306a36Sopenharmony_ci		case MEGARAID_INTEL_RS3WC080_SSDID:
160062306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "scsi host %d: %s\n",
160162306a36Sopenharmony_ci				instance->host->host_no,
160262306a36Sopenharmony_ci				MEGARAID_INTEL_RS3WC080_BRANDING);
160362306a36Sopenharmony_ci			break;
160462306a36Sopenharmony_ci		case MEGARAID_INTEL_RS3WC040_SSDID:
160562306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "scsi host %d: %s\n",
160662306a36Sopenharmony_ci				instance->host->host_no,
160762306a36Sopenharmony_ci				MEGARAID_INTEL_RS3WC040_BRANDING);
160862306a36Sopenharmony_ci			break;
160962306a36Sopenharmony_ci		default:
161062306a36Sopenharmony_ci			break;
161162306a36Sopenharmony_ci		}
161262306a36Sopenharmony_ci		break;
161362306a36Sopenharmony_ci	case PCI_DEVICE_ID_LSI_CUTLASS_52:
161462306a36Sopenharmony_ci	case PCI_DEVICE_ID_LSI_CUTLASS_53:
161562306a36Sopenharmony_ci		switch (instance->pdev->subsystem_device) {
161662306a36Sopenharmony_ci		case MEGARAID_INTEL_RMS3BC160_SSDID:
161762306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "scsi host %d: %s\n",
161862306a36Sopenharmony_ci				instance->host->host_no,
161962306a36Sopenharmony_ci				MEGARAID_INTEL_RMS3BC160_BRANDING);
162062306a36Sopenharmony_ci			break;
162162306a36Sopenharmony_ci		default:
162262306a36Sopenharmony_ci			break;
162362306a36Sopenharmony_ci		}
162462306a36Sopenharmony_ci		break;
162562306a36Sopenharmony_ci	default:
162662306a36Sopenharmony_ci		break;
162762306a36Sopenharmony_ci	}
162862306a36Sopenharmony_ci}
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci/**
163162306a36Sopenharmony_ci * megasas_allocate_raid_maps -	Allocate memory for RAID maps
163262306a36Sopenharmony_ci * @instance:				Adapter soft state
163362306a36Sopenharmony_ci *
163462306a36Sopenharmony_ci * return:				if success: return 0
163562306a36Sopenharmony_ci *					failed:  return -ENOMEM
163662306a36Sopenharmony_ci */
163762306a36Sopenharmony_cistatic inline int megasas_allocate_raid_maps(struct megasas_instance *instance)
163862306a36Sopenharmony_ci{
163962306a36Sopenharmony_ci	struct fusion_context *fusion;
164062306a36Sopenharmony_ci	int i = 0;
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	fusion = instance->ctrl_context;
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	fusion->drv_map_pages = get_order(fusion->drv_map_sz);
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
164762306a36Sopenharmony_ci		fusion->ld_map[i] = NULL;
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci		fusion->ld_drv_map[i] = (void *)
165062306a36Sopenharmony_ci			__get_free_pages(__GFP_ZERO | GFP_KERNEL,
165162306a36Sopenharmony_ci					 fusion->drv_map_pages);
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci		if (!fusion->ld_drv_map[i]) {
165462306a36Sopenharmony_ci			fusion->ld_drv_map[i] = vzalloc(fusion->drv_map_sz);
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci			if (!fusion->ld_drv_map[i]) {
165762306a36Sopenharmony_ci				dev_err(&instance->pdev->dev,
165862306a36Sopenharmony_ci					"Could not allocate memory for local map"
165962306a36Sopenharmony_ci					" size requested: %d\n",
166062306a36Sopenharmony_ci					fusion->drv_map_sz);
166162306a36Sopenharmony_ci				goto ld_drv_map_alloc_fail;
166262306a36Sopenharmony_ci			}
166362306a36Sopenharmony_ci		}
166462306a36Sopenharmony_ci	}
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
166762306a36Sopenharmony_ci		fusion->ld_map[i] = dma_alloc_coherent(&instance->pdev->dev,
166862306a36Sopenharmony_ci						       fusion->max_map_sz,
166962306a36Sopenharmony_ci						       &fusion->ld_map_phys[i],
167062306a36Sopenharmony_ci						       GFP_KERNEL);
167162306a36Sopenharmony_ci		if (!fusion->ld_map[i]) {
167262306a36Sopenharmony_ci			dev_err(&instance->pdev->dev,
167362306a36Sopenharmony_ci				"Could not allocate memory for map info %s:%d\n",
167462306a36Sopenharmony_ci				__func__, __LINE__);
167562306a36Sopenharmony_ci			goto ld_map_alloc_fail;
167662306a36Sopenharmony_ci		}
167762306a36Sopenharmony_ci	}
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	return 0;
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_cild_map_alloc_fail:
168262306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
168362306a36Sopenharmony_ci		if (fusion->ld_map[i])
168462306a36Sopenharmony_ci			dma_free_coherent(&instance->pdev->dev,
168562306a36Sopenharmony_ci					  fusion->max_map_sz,
168662306a36Sopenharmony_ci					  fusion->ld_map[i],
168762306a36Sopenharmony_ci					  fusion->ld_map_phys[i]);
168862306a36Sopenharmony_ci	}
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_cild_drv_map_alloc_fail:
169162306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
169262306a36Sopenharmony_ci		if (fusion->ld_drv_map[i]) {
169362306a36Sopenharmony_ci			if (is_vmalloc_addr(fusion->ld_drv_map[i]))
169462306a36Sopenharmony_ci				vfree(fusion->ld_drv_map[i]);
169562306a36Sopenharmony_ci			else
169662306a36Sopenharmony_ci				free_pages((ulong)fusion->ld_drv_map[i],
169762306a36Sopenharmony_ci					   fusion->drv_map_pages);
169862306a36Sopenharmony_ci		}
169962306a36Sopenharmony_ci	}
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	return -ENOMEM;
170262306a36Sopenharmony_ci}
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci/**
170562306a36Sopenharmony_ci * megasas_configure_queue_sizes -	Calculate size of request desc queue,
170662306a36Sopenharmony_ci *					reply desc queue,
170762306a36Sopenharmony_ci *					IO request frame queue, set can_queue.
170862306a36Sopenharmony_ci * @instance:				Adapter soft state
170962306a36Sopenharmony_ci * @return:				void
171062306a36Sopenharmony_ci */
171162306a36Sopenharmony_cistatic inline
171262306a36Sopenharmony_civoid megasas_configure_queue_sizes(struct megasas_instance *instance)
171362306a36Sopenharmony_ci{
171462306a36Sopenharmony_ci	struct fusion_context *fusion;
171562306a36Sopenharmony_ci	u16 max_cmd;
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci	fusion = instance->ctrl_context;
171862306a36Sopenharmony_ci	max_cmd = instance->max_fw_cmds;
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	if (instance->adapter_type >= VENTURA_SERIES)
172162306a36Sopenharmony_ci		instance->max_mpt_cmds = instance->max_fw_cmds * RAID_1_PEER_CMDS;
172262306a36Sopenharmony_ci	else
172362306a36Sopenharmony_ci		instance->max_mpt_cmds = instance->max_fw_cmds;
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_ci	instance->max_scsi_cmds = instance->max_fw_cmds - instance->max_mfi_cmds;
172662306a36Sopenharmony_ci	instance->cur_can_queue = instance->max_scsi_cmds;
172762306a36Sopenharmony_ci	instance->host->can_queue = instance->cur_can_queue;
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	fusion->reply_q_depth = 2 * ((max_cmd + 1 + 15) / 16) * 16;
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	fusion->request_alloc_sz = sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) *
173262306a36Sopenharmony_ci					  instance->max_mpt_cmds;
173362306a36Sopenharmony_ci	fusion->reply_alloc_sz = sizeof(union MPI2_REPLY_DESCRIPTORS_UNION) *
173462306a36Sopenharmony_ci					(fusion->reply_q_depth);
173562306a36Sopenharmony_ci	fusion->io_frames_alloc_sz = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE +
173662306a36Sopenharmony_ci		(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE
173762306a36Sopenharmony_ci		 * (instance->max_mpt_cmds + 1)); /* Extra 1 for SMID 0 */
173862306a36Sopenharmony_ci}
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_cistatic int megasas_alloc_ioc_init_frame(struct megasas_instance *instance)
174162306a36Sopenharmony_ci{
174262306a36Sopenharmony_ci	struct fusion_context *fusion;
174362306a36Sopenharmony_ci	struct megasas_cmd *cmd;
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	fusion = instance->ctrl_context;
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	cmd = kzalloc(sizeof(struct megasas_cmd), GFP_KERNEL);
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_ci	if (!cmd) {
175062306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "Failed from func: %s line: %d\n",
175162306a36Sopenharmony_ci			__func__, __LINE__);
175262306a36Sopenharmony_ci		return -ENOMEM;
175362306a36Sopenharmony_ci	}
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_ci	cmd->frame = dma_alloc_coherent(&instance->pdev->dev,
175662306a36Sopenharmony_ci					IOC_INIT_FRAME_SIZE,
175762306a36Sopenharmony_ci					&cmd->frame_phys_addr, GFP_KERNEL);
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci	if (!cmd->frame) {
176062306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "Failed from func: %s line: %d\n",
176162306a36Sopenharmony_ci			__func__, __LINE__);
176262306a36Sopenharmony_ci		kfree(cmd);
176362306a36Sopenharmony_ci		return -ENOMEM;
176462306a36Sopenharmony_ci	}
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci	fusion->ioc_init_cmd = cmd;
176762306a36Sopenharmony_ci	return 0;
176862306a36Sopenharmony_ci}
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci/**
177162306a36Sopenharmony_ci * megasas_free_ioc_init_cmd -	Free IOC INIT command frame
177262306a36Sopenharmony_ci * @instance:		Adapter soft state
177362306a36Sopenharmony_ci */
177462306a36Sopenharmony_cistatic inline void megasas_free_ioc_init_cmd(struct megasas_instance *instance)
177562306a36Sopenharmony_ci{
177662306a36Sopenharmony_ci	struct fusion_context *fusion;
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci	fusion = instance->ctrl_context;
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	if (fusion->ioc_init_cmd && fusion->ioc_init_cmd->frame)
178162306a36Sopenharmony_ci		dma_free_coherent(&instance->pdev->dev,
178262306a36Sopenharmony_ci				  IOC_INIT_FRAME_SIZE,
178362306a36Sopenharmony_ci				  fusion->ioc_init_cmd->frame,
178462306a36Sopenharmony_ci				  fusion->ioc_init_cmd->frame_phys_addr);
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci	kfree(fusion->ioc_init_cmd);
178762306a36Sopenharmony_ci}
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci/**
179062306a36Sopenharmony_ci * megasas_init_adapter_fusion -	Initializes the FW
179162306a36Sopenharmony_ci * @instance:		Adapter soft state
179262306a36Sopenharmony_ci *
179362306a36Sopenharmony_ci * This is the main function for initializing firmware.
179462306a36Sopenharmony_ci */
179562306a36Sopenharmony_cistatic u32
179662306a36Sopenharmony_cimegasas_init_adapter_fusion(struct megasas_instance *instance)
179762306a36Sopenharmony_ci{
179862306a36Sopenharmony_ci	struct fusion_context *fusion;
179962306a36Sopenharmony_ci	u32 scratch_pad_1;
180062306a36Sopenharmony_ci	int i = 0, count;
180162306a36Sopenharmony_ci	u32 status_reg;
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	fusion = instance->ctrl_context;
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	megasas_fusion_update_can_queue(instance, PROBE_CONTEXT);
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	/*
180862306a36Sopenharmony_ci	 * Only Driver's internal DCMDs and IOCTL DCMDs needs to have MFI frames
180962306a36Sopenharmony_ci	 */
181062306a36Sopenharmony_ci	instance->max_mfi_cmds =
181162306a36Sopenharmony_ci		MEGASAS_FUSION_INTERNAL_CMDS + MEGASAS_FUSION_IOCTL_CMDS;
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	megasas_configure_queue_sizes(instance);
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci	scratch_pad_1 = megasas_readl(instance,
181662306a36Sopenharmony_ci				      &instance->reg_set->outbound_scratch_pad_1);
181762306a36Sopenharmony_ci	/* If scratch_pad_1 & MEGASAS_MAX_CHAIN_SIZE_UNITS_MASK is set,
181862306a36Sopenharmony_ci	 * Firmware support extended IO chain frame which is 4 times more than
181962306a36Sopenharmony_ci	 * legacy Firmware.
182062306a36Sopenharmony_ci	 * Legacy Firmware - Frame size is (8 * 128) = 1K
182162306a36Sopenharmony_ci	 * 1M IO Firmware  - Frame size is (8 * 128 * 4)  = 4K
182262306a36Sopenharmony_ci	 */
182362306a36Sopenharmony_ci	if (scratch_pad_1 & MEGASAS_MAX_CHAIN_SIZE_UNITS_MASK)
182462306a36Sopenharmony_ci		instance->max_chain_frame_sz =
182562306a36Sopenharmony_ci			((scratch_pad_1 & MEGASAS_MAX_CHAIN_SIZE_MASK) >>
182662306a36Sopenharmony_ci			MEGASAS_MAX_CHAIN_SHIFT) * MEGASAS_1MB_IO;
182762306a36Sopenharmony_ci	else
182862306a36Sopenharmony_ci		instance->max_chain_frame_sz =
182962306a36Sopenharmony_ci			((scratch_pad_1 & MEGASAS_MAX_CHAIN_SIZE_MASK) >>
183062306a36Sopenharmony_ci			MEGASAS_MAX_CHAIN_SHIFT) * MEGASAS_256K_IO;
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci	if (instance->max_chain_frame_sz < MEGASAS_CHAIN_FRAME_SZ_MIN) {
183362306a36Sopenharmony_ci		dev_warn(&instance->pdev->dev, "frame size %d invalid, fall back to legacy max frame size %d\n",
183462306a36Sopenharmony_ci			instance->max_chain_frame_sz,
183562306a36Sopenharmony_ci			MEGASAS_CHAIN_FRAME_SZ_MIN);
183662306a36Sopenharmony_ci		instance->max_chain_frame_sz = MEGASAS_CHAIN_FRAME_SZ_MIN;
183762306a36Sopenharmony_ci	}
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci	fusion->max_sge_in_main_msg =
184062306a36Sopenharmony_ci		(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE
184162306a36Sopenharmony_ci			- offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL))/16;
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci	fusion->max_sge_in_chain =
184462306a36Sopenharmony_ci		instance->max_chain_frame_sz
184562306a36Sopenharmony_ci			/ sizeof(union MPI2_SGE_IO_UNION);
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci	instance->max_num_sge =
184862306a36Sopenharmony_ci		rounddown_pow_of_two(fusion->max_sge_in_main_msg
184962306a36Sopenharmony_ci			+ fusion->max_sge_in_chain - 2);
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci	/* Used for pass thru MFI frame (DCMD) */
185262306a36Sopenharmony_ci	fusion->chain_offset_mfi_pthru =
185362306a36Sopenharmony_ci		offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL)/16;
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	fusion->chain_offset_io_request =
185662306a36Sopenharmony_ci		(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE -
185762306a36Sopenharmony_ci		 sizeof(union MPI2_SGE_IO_UNION))/16;
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
186062306a36Sopenharmony_ci	count += instance->iopoll_q_count;
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	for (i = 0 ; i < count; i++)
186362306a36Sopenharmony_ci		fusion->last_reply_idx[i] = 0;
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_ci	/*
186662306a36Sopenharmony_ci	 * For fusion adapters, 3 commands for IOCTL and 8 commands
186762306a36Sopenharmony_ci	 * for driver's internal DCMDs.
186862306a36Sopenharmony_ci	 */
186962306a36Sopenharmony_ci	instance->max_scsi_cmds = instance->max_fw_cmds -
187062306a36Sopenharmony_ci				(MEGASAS_FUSION_INTERNAL_CMDS +
187162306a36Sopenharmony_ci				MEGASAS_FUSION_IOCTL_CMDS);
187262306a36Sopenharmony_ci	sema_init(&instance->ioctl_sem, MEGASAS_FUSION_IOCTL_CMDS);
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci	for (i = 0; i < MAX_MSIX_QUEUES_FUSION; i++)
187562306a36Sopenharmony_ci		atomic_set(&fusion->busy_mq_poll[i], 0);
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci	if (megasas_alloc_ioc_init_frame(instance))
187862306a36Sopenharmony_ci		return 1;
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci	/*
188162306a36Sopenharmony_ci	 * Allocate memory for descriptors
188262306a36Sopenharmony_ci	 * Create a pool of commands
188362306a36Sopenharmony_ci	 */
188462306a36Sopenharmony_ci	if (megasas_alloc_cmds(instance))
188562306a36Sopenharmony_ci		goto fail_alloc_mfi_cmds;
188662306a36Sopenharmony_ci	if (megasas_alloc_cmds_fusion(instance))
188762306a36Sopenharmony_ci		goto fail_alloc_cmds;
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci	if (megasas_ioc_init_fusion(instance)) {
189062306a36Sopenharmony_ci		status_reg = instance->instancet->read_fw_status_reg(instance);
189162306a36Sopenharmony_ci		if (((status_reg & MFI_STATE_MASK) == MFI_STATE_FAULT) &&
189262306a36Sopenharmony_ci		    (status_reg & MFI_RESET_ADAPTER)) {
189362306a36Sopenharmony_ci			/* Do a chip reset and then retry IOC INIT once */
189462306a36Sopenharmony_ci			if (megasas_adp_reset_wait_for_ready
189562306a36Sopenharmony_ci				(instance, true, 0) == FAILED)
189662306a36Sopenharmony_ci				goto fail_ioc_init;
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci			if (megasas_ioc_init_fusion(instance))
189962306a36Sopenharmony_ci				goto fail_ioc_init;
190062306a36Sopenharmony_ci		} else {
190162306a36Sopenharmony_ci			goto fail_ioc_init;
190262306a36Sopenharmony_ci		}
190362306a36Sopenharmony_ci	}
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	megasas_display_intel_branding(instance);
190662306a36Sopenharmony_ci	if (megasas_get_ctrl_info(instance)) {
190762306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
190862306a36Sopenharmony_ci			"Could not get controller info. Fail from %s %d\n",
190962306a36Sopenharmony_ci			__func__, __LINE__);
191062306a36Sopenharmony_ci		goto fail_ioc_init;
191162306a36Sopenharmony_ci	}
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	instance->flag_ieee = 1;
191462306a36Sopenharmony_ci	instance->r1_ldio_hint_default =  MR_R1_LDIO_PIGGYBACK_DEFAULT;
191562306a36Sopenharmony_ci	instance->threshold_reply_count = instance->max_fw_cmds / 4;
191662306a36Sopenharmony_ci	fusion->fast_path_io = 0;
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci	if (megasas_allocate_raid_maps(instance))
191962306a36Sopenharmony_ci		goto fail_ioc_init;
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	if (!megasas_get_map_info(instance))
192262306a36Sopenharmony_ci		megasas_sync_map_info(instance);
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci	return 0;
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_cifail_ioc_init:
192762306a36Sopenharmony_ci	megasas_free_cmds_fusion(instance);
192862306a36Sopenharmony_cifail_alloc_cmds:
192962306a36Sopenharmony_ci	megasas_free_cmds(instance);
193062306a36Sopenharmony_cifail_alloc_mfi_cmds:
193162306a36Sopenharmony_ci	megasas_free_ioc_init_cmd(instance);
193262306a36Sopenharmony_ci	return 1;
193362306a36Sopenharmony_ci}
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci/**
193662306a36Sopenharmony_ci * megasas_fault_detect_work	-	Worker function of
193762306a36Sopenharmony_ci *					FW fault handling workqueue.
193862306a36Sopenharmony_ci * @work:	FW fault work struct
193962306a36Sopenharmony_ci */
194062306a36Sopenharmony_cistatic void
194162306a36Sopenharmony_cimegasas_fault_detect_work(struct work_struct *work)
194262306a36Sopenharmony_ci{
194362306a36Sopenharmony_ci	struct megasas_instance *instance =
194462306a36Sopenharmony_ci		container_of(work, struct megasas_instance,
194562306a36Sopenharmony_ci			     fw_fault_work.work);
194662306a36Sopenharmony_ci	u32 fw_state, dma_state, status;
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci	/* Check the fw state */
194962306a36Sopenharmony_ci	fw_state = instance->instancet->read_fw_status_reg(instance) &
195062306a36Sopenharmony_ci			MFI_STATE_MASK;
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_ci	if (fw_state == MFI_STATE_FAULT) {
195362306a36Sopenharmony_ci		dma_state = instance->instancet->read_fw_status_reg(instance) &
195462306a36Sopenharmony_ci				MFI_STATE_DMADONE;
195562306a36Sopenharmony_ci		/* Start collecting crash, if DMA bit is done */
195662306a36Sopenharmony_ci		if (instance->crash_dump_drv_support &&
195762306a36Sopenharmony_ci		    instance->crash_dump_app_support && dma_state) {
195862306a36Sopenharmony_ci			megasas_fusion_crash_dump(instance);
195962306a36Sopenharmony_ci		} else {
196062306a36Sopenharmony_ci			if (instance->unload == 0) {
196162306a36Sopenharmony_ci				status = megasas_reset_fusion(instance->host, 0);
196262306a36Sopenharmony_ci				if (status != SUCCESS) {
196362306a36Sopenharmony_ci					dev_err(&instance->pdev->dev,
196462306a36Sopenharmony_ci						"Failed from %s %d, do not re-arm timer\n",
196562306a36Sopenharmony_ci						__func__, __LINE__);
196662306a36Sopenharmony_ci					return;
196762306a36Sopenharmony_ci				}
196862306a36Sopenharmony_ci			}
196962306a36Sopenharmony_ci		}
197062306a36Sopenharmony_ci	}
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci	if (instance->fw_fault_work_q)
197362306a36Sopenharmony_ci		queue_delayed_work(instance->fw_fault_work_q,
197462306a36Sopenharmony_ci			&instance->fw_fault_work,
197562306a36Sopenharmony_ci			msecs_to_jiffies(MEGASAS_WATCHDOG_THREAD_INTERVAL));
197662306a36Sopenharmony_ci}
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ciint
197962306a36Sopenharmony_cimegasas_fusion_start_watchdog(struct megasas_instance *instance)
198062306a36Sopenharmony_ci{
198162306a36Sopenharmony_ci	/* Check if the Fault WQ is already started */
198262306a36Sopenharmony_ci	if (instance->fw_fault_work_q)
198362306a36Sopenharmony_ci		return SUCCESS;
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	INIT_DELAYED_WORK(&instance->fw_fault_work, megasas_fault_detect_work);
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_ci	snprintf(instance->fault_handler_work_q_name,
198862306a36Sopenharmony_ci		 sizeof(instance->fault_handler_work_q_name),
198962306a36Sopenharmony_ci		 "poll_megasas%d_status", instance->host->host_no);
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci	instance->fw_fault_work_q =
199262306a36Sopenharmony_ci		create_singlethread_workqueue(instance->fault_handler_work_q_name);
199362306a36Sopenharmony_ci	if (!instance->fw_fault_work_q) {
199462306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
199562306a36Sopenharmony_ci			__func__, __LINE__);
199662306a36Sopenharmony_ci		return FAILED;
199762306a36Sopenharmony_ci	}
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	queue_delayed_work(instance->fw_fault_work_q,
200062306a36Sopenharmony_ci			   &instance->fw_fault_work,
200162306a36Sopenharmony_ci			   msecs_to_jiffies(MEGASAS_WATCHDOG_THREAD_INTERVAL));
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci	return SUCCESS;
200462306a36Sopenharmony_ci}
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_civoid
200762306a36Sopenharmony_cimegasas_fusion_stop_watchdog(struct megasas_instance *instance)
200862306a36Sopenharmony_ci{
200962306a36Sopenharmony_ci	struct workqueue_struct *wq;
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ci	if (instance->fw_fault_work_q) {
201262306a36Sopenharmony_ci		wq = instance->fw_fault_work_q;
201362306a36Sopenharmony_ci		instance->fw_fault_work_q = NULL;
201462306a36Sopenharmony_ci		if (!cancel_delayed_work_sync(&instance->fw_fault_work))
201562306a36Sopenharmony_ci			flush_workqueue(wq);
201662306a36Sopenharmony_ci		destroy_workqueue(wq);
201762306a36Sopenharmony_ci	}
201862306a36Sopenharmony_ci}
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci/**
202162306a36Sopenharmony_ci * map_cmd_status -	Maps FW cmd status to OS cmd status
202262306a36Sopenharmony_ci * @fusion:		fusion context
202362306a36Sopenharmony_ci * @scmd:		Pointer to cmd
202462306a36Sopenharmony_ci * @status:		status of cmd returned by FW
202562306a36Sopenharmony_ci * @ext_status:		ext status of cmd returned by FW
202662306a36Sopenharmony_ci * @data_length:	command data length
202762306a36Sopenharmony_ci * @sense:		command sense data
202862306a36Sopenharmony_ci */
202962306a36Sopenharmony_cistatic void
203062306a36Sopenharmony_cimap_cmd_status(struct fusion_context *fusion,
203162306a36Sopenharmony_ci		struct scsi_cmnd *scmd, u8 status, u8 ext_status,
203262306a36Sopenharmony_ci		u32 data_length, u8 *sense)
203362306a36Sopenharmony_ci{
203462306a36Sopenharmony_ci	u8 cmd_type;
203562306a36Sopenharmony_ci	int resid;
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	cmd_type = megasas_cmd_type(scmd);
203862306a36Sopenharmony_ci	switch (status) {
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci	case MFI_STAT_OK:
204162306a36Sopenharmony_ci		scmd->result = DID_OK << 16;
204262306a36Sopenharmony_ci		break;
204362306a36Sopenharmony_ci
204462306a36Sopenharmony_ci	case MFI_STAT_SCSI_IO_FAILED:
204562306a36Sopenharmony_ci	case MFI_STAT_LD_INIT_IN_PROGRESS:
204662306a36Sopenharmony_ci		scmd->result = (DID_ERROR << 16) | ext_status;
204762306a36Sopenharmony_ci		break;
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci	case MFI_STAT_SCSI_DONE_WITH_ERROR:
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_ci		scmd->result = (DID_OK << 16) | ext_status;
205262306a36Sopenharmony_ci		if (ext_status == SAM_STAT_CHECK_CONDITION) {
205362306a36Sopenharmony_ci			memcpy(scmd->sense_buffer, sense,
205462306a36Sopenharmony_ci			       SCSI_SENSE_BUFFERSIZE);
205562306a36Sopenharmony_ci		}
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci		/*
205862306a36Sopenharmony_ci		 * If the  IO request is partially completed, then MR FW will
205962306a36Sopenharmony_ci		 * update "io_request->DataLength" field with actual number of
206062306a36Sopenharmony_ci		 * bytes transferred.Driver will set residual bytes count in
206162306a36Sopenharmony_ci		 * SCSI command structure.
206262306a36Sopenharmony_ci		 */
206362306a36Sopenharmony_ci		resid = (scsi_bufflen(scmd) - data_length);
206462306a36Sopenharmony_ci		scsi_set_resid(scmd, resid);
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci		if (resid &&
206762306a36Sopenharmony_ci			((cmd_type == READ_WRITE_LDIO) ||
206862306a36Sopenharmony_ci			(cmd_type == READ_WRITE_SYSPDIO)))
206962306a36Sopenharmony_ci			scmd_printk(KERN_INFO, scmd, "BRCM Debug mfi stat 0x%x, data len"
207062306a36Sopenharmony_ci				" requested/completed 0x%x/0x%x\n",
207162306a36Sopenharmony_ci				status, scsi_bufflen(scmd), data_length);
207262306a36Sopenharmony_ci		break;
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci	case MFI_STAT_LD_OFFLINE:
207562306a36Sopenharmony_ci	case MFI_STAT_DEVICE_NOT_FOUND:
207662306a36Sopenharmony_ci		scmd->result = DID_BAD_TARGET << 16;
207762306a36Sopenharmony_ci		break;
207862306a36Sopenharmony_ci	case MFI_STAT_CONFIG_SEQ_MISMATCH:
207962306a36Sopenharmony_ci		scmd->result = DID_IMM_RETRY << 16;
208062306a36Sopenharmony_ci		break;
208162306a36Sopenharmony_ci	default:
208262306a36Sopenharmony_ci		scmd->result = DID_ERROR << 16;
208362306a36Sopenharmony_ci		break;
208462306a36Sopenharmony_ci	}
208562306a36Sopenharmony_ci}
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci/**
208862306a36Sopenharmony_ci * megasas_is_prp_possible -
208962306a36Sopenharmony_ci * Checks if native NVMe PRPs can be built for the IO
209062306a36Sopenharmony_ci *
209162306a36Sopenharmony_ci * @instance:		Adapter soft state
209262306a36Sopenharmony_ci * @scmd:		SCSI command from the mid-layer
209362306a36Sopenharmony_ci * @sge_count:		scatter gather element count.
209462306a36Sopenharmony_ci *
209562306a36Sopenharmony_ci * Returns:		true: PRPs can be built
209662306a36Sopenharmony_ci *			false: IEEE SGLs needs to be built
209762306a36Sopenharmony_ci */
209862306a36Sopenharmony_cistatic bool
209962306a36Sopenharmony_cimegasas_is_prp_possible(struct megasas_instance *instance,
210062306a36Sopenharmony_ci			struct scsi_cmnd *scmd, int sge_count)
210162306a36Sopenharmony_ci{
210262306a36Sopenharmony_ci	u32 data_length = 0;
210362306a36Sopenharmony_ci	struct scatterlist *sg_scmd;
210462306a36Sopenharmony_ci	bool build_prp = false;
210562306a36Sopenharmony_ci	u32 mr_nvme_pg_size;
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci	mr_nvme_pg_size = max_t(u32, instance->nvme_page_size,
210862306a36Sopenharmony_ci				MR_DEFAULT_NVME_PAGE_SIZE);
210962306a36Sopenharmony_ci	data_length = scsi_bufflen(scmd);
211062306a36Sopenharmony_ci	sg_scmd = scsi_sglist(scmd);
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci	/*
211362306a36Sopenharmony_ci	 * NVMe uses one PRP for each page (or part of a page)
211462306a36Sopenharmony_ci	 * look at the data length - if 4 pages or less then IEEE is OK
211562306a36Sopenharmony_ci	 * if  > 5 pages then we need to build a native SGL
211662306a36Sopenharmony_ci	 * if > 4 and <= 5 pages, then check physical address of 1st SG entry
211762306a36Sopenharmony_ci	 * if this first size in the page is >= the residual beyond 4 pages
211862306a36Sopenharmony_ci	 * then use IEEE, otherwise use native SGL
211962306a36Sopenharmony_ci	 */
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci	if (data_length > (mr_nvme_pg_size * 5)) {
212262306a36Sopenharmony_ci		build_prp = true;
212362306a36Sopenharmony_ci	} else if ((data_length > (mr_nvme_pg_size * 4)) &&
212462306a36Sopenharmony_ci			(data_length <= (mr_nvme_pg_size * 5)))  {
212562306a36Sopenharmony_ci		/* check if 1st SG entry size is < residual beyond 4 pages */
212662306a36Sopenharmony_ci		if (sg_dma_len(sg_scmd) < (data_length - (mr_nvme_pg_size * 4)))
212762306a36Sopenharmony_ci			build_prp = true;
212862306a36Sopenharmony_ci	}
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci	return build_prp;
213162306a36Sopenharmony_ci}
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ci/**
213462306a36Sopenharmony_ci * megasas_make_prp_nvme -
213562306a36Sopenharmony_ci * Prepare PRPs(Physical Region Page)- SGLs specific to NVMe drives only
213662306a36Sopenharmony_ci *
213762306a36Sopenharmony_ci * @instance:		Adapter soft state
213862306a36Sopenharmony_ci * @scmd:		SCSI command from the mid-layer
213962306a36Sopenharmony_ci * @sgl_ptr:		SGL to be filled in
214062306a36Sopenharmony_ci * @cmd:		Fusion command frame
214162306a36Sopenharmony_ci * @sge_count:		scatter gather element count.
214262306a36Sopenharmony_ci *
214362306a36Sopenharmony_ci * Returns:		true: PRPs are built
214462306a36Sopenharmony_ci *			false: IEEE SGLs needs to be built
214562306a36Sopenharmony_ci */
214662306a36Sopenharmony_cistatic bool
214762306a36Sopenharmony_cimegasas_make_prp_nvme(struct megasas_instance *instance, struct scsi_cmnd *scmd,
214862306a36Sopenharmony_ci		      struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr,
214962306a36Sopenharmony_ci		      struct megasas_cmd_fusion *cmd, int sge_count)
215062306a36Sopenharmony_ci{
215162306a36Sopenharmony_ci	int sge_len, offset, num_prp_in_chain = 0;
215262306a36Sopenharmony_ci	struct MPI25_IEEE_SGE_CHAIN64 *main_chain_element, *ptr_first_sgl;
215362306a36Sopenharmony_ci	u64 *ptr_sgl;
215462306a36Sopenharmony_ci	dma_addr_t ptr_sgl_phys;
215562306a36Sopenharmony_ci	u64 sge_addr;
215662306a36Sopenharmony_ci	u32 page_mask, page_mask_result;
215762306a36Sopenharmony_ci	struct scatterlist *sg_scmd;
215862306a36Sopenharmony_ci	u32 first_prp_len;
215962306a36Sopenharmony_ci	bool build_prp = false;
216062306a36Sopenharmony_ci	int data_len = scsi_bufflen(scmd);
216162306a36Sopenharmony_ci	u32 mr_nvme_pg_size = max_t(u32, instance->nvme_page_size,
216262306a36Sopenharmony_ci					MR_DEFAULT_NVME_PAGE_SIZE);
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci	build_prp = megasas_is_prp_possible(instance, scmd, sge_count);
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci	if (!build_prp)
216762306a36Sopenharmony_ci		return false;
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci	/*
217062306a36Sopenharmony_ci	 * Nvme has a very convoluted prp format.  One prp is required
217162306a36Sopenharmony_ci	 * for each page or partial page. Driver need to split up OS sg_list
217262306a36Sopenharmony_ci	 * entries if it is longer than one page or cross a page
217362306a36Sopenharmony_ci	 * boundary.  Driver also have to insert a PRP list pointer entry as
217462306a36Sopenharmony_ci	 * the last entry in each physical page of the PRP list.
217562306a36Sopenharmony_ci	 *
217662306a36Sopenharmony_ci	 * NOTE: The first PRP "entry" is actually placed in the first
217762306a36Sopenharmony_ci	 * SGL entry in the main message as IEEE 64 format.  The 2nd
217862306a36Sopenharmony_ci	 * entry in the main message is the chain element, and the rest
217962306a36Sopenharmony_ci	 * of the PRP entries are built in the contiguous pcie buffer.
218062306a36Sopenharmony_ci	 */
218162306a36Sopenharmony_ci	page_mask = mr_nvme_pg_size - 1;
218262306a36Sopenharmony_ci	ptr_sgl = (u64 *)cmd->sg_frame;
218362306a36Sopenharmony_ci	ptr_sgl_phys = cmd->sg_frame_phys_addr;
218462306a36Sopenharmony_ci	memset(ptr_sgl, 0, instance->max_chain_frame_sz);
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci	/* Build chain frame element which holds all prps except first*/
218762306a36Sopenharmony_ci	main_chain_element = (struct MPI25_IEEE_SGE_CHAIN64 *)
218862306a36Sopenharmony_ci	    ((u8 *)sgl_ptr + sizeof(struct MPI25_IEEE_SGE_CHAIN64));
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	main_chain_element->Address = cpu_to_le64(ptr_sgl_phys);
219162306a36Sopenharmony_ci	main_chain_element->NextChainOffset = 0;
219262306a36Sopenharmony_ci	main_chain_element->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT |
219362306a36Sopenharmony_ci					IEEE_SGE_FLAGS_SYSTEM_ADDR |
219462306a36Sopenharmony_ci					MPI26_IEEE_SGE_FLAGS_NSF_NVME_PRP;
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci	/* Build first prp, sge need not to be page aligned*/
219762306a36Sopenharmony_ci	ptr_first_sgl = sgl_ptr;
219862306a36Sopenharmony_ci	sg_scmd = scsi_sglist(scmd);
219962306a36Sopenharmony_ci	sge_addr = sg_dma_address(sg_scmd);
220062306a36Sopenharmony_ci	sge_len = sg_dma_len(sg_scmd);
220162306a36Sopenharmony_ci
220262306a36Sopenharmony_ci	offset = (u32)(sge_addr & page_mask);
220362306a36Sopenharmony_ci	first_prp_len = mr_nvme_pg_size - offset;
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_ci	ptr_first_sgl->Address = cpu_to_le64(sge_addr);
220662306a36Sopenharmony_ci	ptr_first_sgl->Length = cpu_to_le32(first_prp_len);
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_ci	data_len -= first_prp_len;
220962306a36Sopenharmony_ci
221062306a36Sopenharmony_ci	if (sge_len > first_prp_len) {
221162306a36Sopenharmony_ci		sge_addr += first_prp_len;
221262306a36Sopenharmony_ci		sge_len -= first_prp_len;
221362306a36Sopenharmony_ci	} else if (sge_len == first_prp_len) {
221462306a36Sopenharmony_ci		sg_scmd = sg_next(sg_scmd);
221562306a36Sopenharmony_ci		sge_addr = sg_dma_address(sg_scmd);
221662306a36Sopenharmony_ci		sge_len = sg_dma_len(sg_scmd);
221762306a36Sopenharmony_ci	}
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	for (;;) {
222062306a36Sopenharmony_ci		offset = (u32)(sge_addr & page_mask);
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci		/* Put PRP pointer due to page boundary*/
222362306a36Sopenharmony_ci		page_mask_result = (uintptr_t)(ptr_sgl + 1) & page_mask;
222462306a36Sopenharmony_ci		if (unlikely(!page_mask_result)) {
222562306a36Sopenharmony_ci			scmd_printk(KERN_NOTICE,
222662306a36Sopenharmony_ci				    scmd, "page boundary ptr_sgl: 0x%p\n",
222762306a36Sopenharmony_ci				    ptr_sgl);
222862306a36Sopenharmony_ci			ptr_sgl_phys += 8;
222962306a36Sopenharmony_ci			*ptr_sgl = cpu_to_le64(ptr_sgl_phys);
223062306a36Sopenharmony_ci			ptr_sgl++;
223162306a36Sopenharmony_ci			num_prp_in_chain++;
223262306a36Sopenharmony_ci		}
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci		*ptr_sgl = cpu_to_le64(sge_addr);
223562306a36Sopenharmony_ci		ptr_sgl++;
223662306a36Sopenharmony_ci		ptr_sgl_phys += 8;
223762306a36Sopenharmony_ci		num_prp_in_chain++;
223862306a36Sopenharmony_ci
223962306a36Sopenharmony_ci		sge_addr += mr_nvme_pg_size;
224062306a36Sopenharmony_ci		sge_len -= mr_nvme_pg_size;
224162306a36Sopenharmony_ci		data_len -= mr_nvme_pg_size;
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci		if (data_len <= 0)
224462306a36Sopenharmony_ci			break;
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci		if (sge_len > 0)
224762306a36Sopenharmony_ci			continue;
224862306a36Sopenharmony_ci
224962306a36Sopenharmony_ci		sg_scmd = sg_next(sg_scmd);
225062306a36Sopenharmony_ci		sge_addr = sg_dma_address(sg_scmd);
225162306a36Sopenharmony_ci		sge_len = sg_dma_len(sg_scmd);
225262306a36Sopenharmony_ci	}
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci	main_chain_element->Length =
225562306a36Sopenharmony_ci			cpu_to_le32(num_prp_in_chain * sizeof(u64));
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_ci	return build_prp;
225862306a36Sopenharmony_ci}
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_ci/**
226162306a36Sopenharmony_ci * megasas_make_sgl_fusion -	Prepares 32-bit SGL
226262306a36Sopenharmony_ci * @instance:		Adapter soft state
226362306a36Sopenharmony_ci * @scp:		SCSI command from the mid-layer
226462306a36Sopenharmony_ci * @sgl_ptr:		SGL to be filled in
226562306a36Sopenharmony_ci * @cmd:		cmd we are working on
226662306a36Sopenharmony_ci * @sge_count:		sge count
226762306a36Sopenharmony_ci *
226862306a36Sopenharmony_ci */
226962306a36Sopenharmony_cistatic void
227062306a36Sopenharmony_cimegasas_make_sgl_fusion(struct megasas_instance *instance,
227162306a36Sopenharmony_ci			struct scsi_cmnd *scp,
227262306a36Sopenharmony_ci			struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr,
227362306a36Sopenharmony_ci			struct megasas_cmd_fusion *cmd, int sge_count)
227462306a36Sopenharmony_ci{
227562306a36Sopenharmony_ci	int i, sg_processed;
227662306a36Sopenharmony_ci	struct scatterlist *os_sgl;
227762306a36Sopenharmony_ci	struct fusion_context *fusion;
227862306a36Sopenharmony_ci
227962306a36Sopenharmony_ci	fusion = instance->ctrl_context;
228062306a36Sopenharmony_ci
228162306a36Sopenharmony_ci	if (instance->adapter_type >= INVADER_SERIES) {
228262306a36Sopenharmony_ci		struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end = sgl_ptr;
228362306a36Sopenharmony_ci		sgl_ptr_end += fusion->max_sge_in_main_msg - 1;
228462306a36Sopenharmony_ci		sgl_ptr_end->Flags = 0;
228562306a36Sopenharmony_ci	}
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_ci	scsi_for_each_sg(scp, os_sgl, sge_count, i) {
228862306a36Sopenharmony_ci		sgl_ptr->Length = cpu_to_le32(sg_dma_len(os_sgl));
228962306a36Sopenharmony_ci		sgl_ptr->Address = cpu_to_le64(sg_dma_address(os_sgl));
229062306a36Sopenharmony_ci		sgl_ptr->Flags = 0;
229162306a36Sopenharmony_ci		if (instance->adapter_type >= INVADER_SERIES)
229262306a36Sopenharmony_ci			if (i == sge_count - 1)
229362306a36Sopenharmony_ci				sgl_ptr->Flags = IEEE_SGE_FLAGS_END_OF_LIST;
229462306a36Sopenharmony_ci		sgl_ptr++;
229562306a36Sopenharmony_ci		sg_processed = i + 1;
229662306a36Sopenharmony_ci
229762306a36Sopenharmony_ci		if ((sg_processed ==  (fusion->max_sge_in_main_msg - 1)) &&
229862306a36Sopenharmony_ci		    (sge_count > fusion->max_sge_in_main_msg)) {
229962306a36Sopenharmony_ci
230062306a36Sopenharmony_ci			struct MPI25_IEEE_SGE_CHAIN64 *sg_chain;
230162306a36Sopenharmony_ci			if (instance->adapter_type >= INVADER_SERIES) {
230262306a36Sopenharmony_ci				if ((le16_to_cpu(cmd->io_request->IoFlags) &
230362306a36Sopenharmony_ci					MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) !=
230462306a36Sopenharmony_ci					MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH)
230562306a36Sopenharmony_ci					cmd->io_request->ChainOffset =
230662306a36Sopenharmony_ci						fusion->
230762306a36Sopenharmony_ci						chain_offset_io_request;
230862306a36Sopenharmony_ci				else
230962306a36Sopenharmony_ci					cmd->io_request->ChainOffset = 0;
231062306a36Sopenharmony_ci			} else
231162306a36Sopenharmony_ci				cmd->io_request->ChainOffset =
231262306a36Sopenharmony_ci					fusion->chain_offset_io_request;
231362306a36Sopenharmony_ci
231462306a36Sopenharmony_ci			sg_chain = sgl_ptr;
231562306a36Sopenharmony_ci			/* Prepare chain element */
231662306a36Sopenharmony_ci			sg_chain->NextChainOffset = 0;
231762306a36Sopenharmony_ci			if (instance->adapter_type >= INVADER_SERIES)
231862306a36Sopenharmony_ci				sg_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT;
231962306a36Sopenharmony_ci			else
232062306a36Sopenharmony_ci				sg_chain->Flags =
232162306a36Sopenharmony_ci					(IEEE_SGE_FLAGS_CHAIN_ELEMENT |
232262306a36Sopenharmony_ci					 MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR);
232362306a36Sopenharmony_ci			sg_chain->Length =  cpu_to_le32((sizeof(union MPI2_SGE_IO_UNION) * (sge_count - sg_processed)));
232462306a36Sopenharmony_ci			sg_chain->Address = cpu_to_le64(cmd->sg_frame_phys_addr);
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci			sgl_ptr =
232762306a36Sopenharmony_ci			  (struct MPI25_IEEE_SGE_CHAIN64 *)cmd->sg_frame;
232862306a36Sopenharmony_ci			memset(sgl_ptr, 0, instance->max_chain_frame_sz);
232962306a36Sopenharmony_ci		}
233062306a36Sopenharmony_ci	}
233162306a36Sopenharmony_ci}
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ci/**
233462306a36Sopenharmony_ci * megasas_make_sgl -	Build Scatter Gather List(SGLs)
233562306a36Sopenharmony_ci * @scp:		SCSI command pointer
233662306a36Sopenharmony_ci * @instance:		Soft instance of controller
233762306a36Sopenharmony_ci * @cmd:		Fusion command pointer
233862306a36Sopenharmony_ci *
233962306a36Sopenharmony_ci * This function will build sgls based on device type.
234062306a36Sopenharmony_ci * For nvme drives, there is different way of building sgls in nvme native
234162306a36Sopenharmony_ci * format- PRPs(Physical Region Page).
234262306a36Sopenharmony_ci *
234362306a36Sopenharmony_ci * Returns the number of sg lists actually used, zero if the sg lists
234462306a36Sopenharmony_ci * is NULL, or -ENOMEM if the mapping failed
234562306a36Sopenharmony_ci */
234662306a36Sopenharmony_cistatic
234762306a36Sopenharmony_ciint megasas_make_sgl(struct megasas_instance *instance, struct scsi_cmnd *scp,
234862306a36Sopenharmony_ci		     struct megasas_cmd_fusion *cmd)
234962306a36Sopenharmony_ci{
235062306a36Sopenharmony_ci	int sge_count;
235162306a36Sopenharmony_ci	bool build_prp = false;
235262306a36Sopenharmony_ci	struct MPI25_IEEE_SGE_CHAIN64 *sgl_chain64;
235362306a36Sopenharmony_ci
235462306a36Sopenharmony_ci	sge_count = scsi_dma_map(scp);
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci	if ((sge_count > instance->max_num_sge) || (sge_count <= 0))
235762306a36Sopenharmony_ci		return sge_count;
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci	sgl_chain64 = (struct MPI25_IEEE_SGE_CHAIN64 *)&cmd->io_request->SGL;
236062306a36Sopenharmony_ci	if ((le16_to_cpu(cmd->io_request->IoFlags) &
236162306a36Sopenharmony_ci	    MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) &&
236262306a36Sopenharmony_ci	    (cmd->pd_interface == NVME_PD))
236362306a36Sopenharmony_ci		build_prp = megasas_make_prp_nvme(instance, scp, sgl_chain64,
236462306a36Sopenharmony_ci						  cmd, sge_count);
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_ci	if (!build_prp)
236762306a36Sopenharmony_ci		megasas_make_sgl_fusion(instance, scp, sgl_chain64,
236862306a36Sopenharmony_ci					cmd, sge_count);
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_ci	return sge_count;
237162306a36Sopenharmony_ci}
237262306a36Sopenharmony_ci
237362306a36Sopenharmony_ci/**
237462306a36Sopenharmony_ci * megasas_set_pd_lba -	Sets PD LBA
237562306a36Sopenharmony_ci * @io_request:		IO request
237662306a36Sopenharmony_ci * @cdb_len:		cdb length
237762306a36Sopenharmony_ci * @io_info:		IO information
237862306a36Sopenharmony_ci * @scp:		SCSI command
237962306a36Sopenharmony_ci * @local_map_ptr:	Raid map
238062306a36Sopenharmony_ci * @ref_tag:		Primary reference tag
238162306a36Sopenharmony_ci *
238262306a36Sopenharmony_ci * Used to set the PD LBA in CDB for FP IOs
238362306a36Sopenharmony_ci */
238462306a36Sopenharmony_cistatic void
238562306a36Sopenharmony_cimegasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len,
238662306a36Sopenharmony_ci		   struct IO_REQUEST_INFO *io_info, struct scsi_cmnd *scp,
238762306a36Sopenharmony_ci		   struct MR_DRV_RAID_MAP_ALL *local_map_ptr, u32 ref_tag)
238862306a36Sopenharmony_ci{
238962306a36Sopenharmony_ci	struct MR_LD_RAID *raid;
239062306a36Sopenharmony_ci	u16 ld;
239162306a36Sopenharmony_ci	u64 start_blk = io_info->pdBlock;
239262306a36Sopenharmony_ci	u8 *cdb = io_request->CDB.CDB32;
239362306a36Sopenharmony_ci	u32 num_blocks = io_info->numBlocks;
239462306a36Sopenharmony_ci	u8 opcode = 0, flagvals = 0, groupnum = 0, control = 0;
239562306a36Sopenharmony_ci
239662306a36Sopenharmony_ci	/* Check if T10 PI (DIF) is enabled for this LD */
239762306a36Sopenharmony_ci	ld = MR_TargetIdToLdGet(io_info->ldTgtId, local_map_ptr);
239862306a36Sopenharmony_ci	raid = MR_LdRaidGet(ld, local_map_ptr);
239962306a36Sopenharmony_ci	if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER) {
240062306a36Sopenharmony_ci		memset(cdb, 0, sizeof(io_request->CDB.CDB32));
240162306a36Sopenharmony_ci		cdb[0] =  MEGASAS_SCSI_VARIABLE_LENGTH_CMD;
240262306a36Sopenharmony_ci		cdb[7] =  MEGASAS_SCSI_ADDL_CDB_LEN;
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci		if (scp->sc_data_direction == DMA_FROM_DEVICE)
240562306a36Sopenharmony_ci			cdb[9] = MEGASAS_SCSI_SERVICE_ACTION_READ32;
240662306a36Sopenharmony_ci		else
240762306a36Sopenharmony_ci			cdb[9] = MEGASAS_SCSI_SERVICE_ACTION_WRITE32;
240862306a36Sopenharmony_ci		cdb[10] = MEGASAS_RD_WR_PROTECT_CHECK_ALL;
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci		/* LBA */
241162306a36Sopenharmony_ci		cdb[12] = (u8)((start_blk >> 56) & 0xff);
241262306a36Sopenharmony_ci		cdb[13] = (u8)((start_blk >> 48) & 0xff);
241362306a36Sopenharmony_ci		cdb[14] = (u8)((start_blk >> 40) & 0xff);
241462306a36Sopenharmony_ci		cdb[15] = (u8)((start_blk >> 32) & 0xff);
241562306a36Sopenharmony_ci		cdb[16] = (u8)((start_blk >> 24) & 0xff);
241662306a36Sopenharmony_ci		cdb[17] = (u8)((start_blk >> 16) & 0xff);
241762306a36Sopenharmony_ci		cdb[18] = (u8)((start_blk >> 8) & 0xff);
241862306a36Sopenharmony_ci		cdb[19] = (u8)(start_blk & 0xff);
241962306a36Sopenharmony_ci
242062306a36Sopenharmony_ci		/* Logical block reference tag */
242162306a36Sopenharmony_ci		io_request->CDB.EEDP32.PrimaryReferenceTag =
242262306a36Sopenharmony_ci			cpu_to_be32(ref_tag);
242362306a36Sopenharmony_ci		io_request->CDB.EEDP32.PrimaryApplicationTagMask = cpu_to_be16(0xffff);
242462306a36Sopenharmony_ci		io_request->IoFlags = cpu_to_le16(32); /* Specify 32-byte cdb */
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci		/* Transfer length */
242762306a36Sopenharmony_ci		cdb[28] = (u8)((num_blocks >> 24) & 0xff);
242862306a36Sopenharmony_ci		cdb[29] = (u8)((num_blocks >> 16) & 0xff);
242962306a36Sopenharmony_ci		cdb[30] = (u8)((num_blocks >> 8) & 0xff);
243062306a36Sopenharmony_ci		cdb[31] = (u8)(num_blocks & 0xff);
243162306a36Sopenharmony_ci
243262306a36Sopenharmony_ci		/* set SCSI IO EEDPFlags */
243362306a36Sopenharmony_ci		if (scp->sc_data_direction == DMA_FROM_DEVICE) {
243462306a36Sopenharmony_ci			io_request->EEDPFlags = cpu_to_le16(
243562306a36Sopenharmony_ci				MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG  |
243662306a36Sopenharmony_ci				MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
243762306a36Sopenharmony_ci				MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP |
243862306a36Sopenharmony_ci				MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG |
243962306a36Sopenharmony_ci				MPI25_SCSIIO_EEDPFLAGS_DO_NOT_DISABLE_MODE |
244062306a36Sopenharmony_ci				MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD);
244162306a36Sopenharmony_ci		} else {
244262306a36Sopenharmony_ci			io_request->EEDPFlags = cpu_to_le16(
244362306a36Sopenharmony_ci				MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
244462306a36Sopenharmony_ci				MPI2_SCSIIO_EEDPFLAGS_INSERT_OP);
244562306a36Sopenharmony_ci		}
244662306a36Sopenharmony_ci		io_request->Control |= cpu_to_le32((0x4 << 26));
244762306a36Sopenharmony_ci		io_request->EEDPBlockSize = cpu_to_le32(scp->device->sector_size);
244862306a36Sopenharmony_ci	} else {
244962306a36Sopenharmony_ci		/* Some drives don't support 16/12 byte CDB's, convert to 10 */
245062306a36Sopenharmony_ci		if (((cdb_len == 12) || (cdb_len == 16)) &&
245162306a36Sopenharmony_ci		    (start_blk <= 0xffffffff)) {
245262306a36Sopenharmony_ci			if (cdb_len == 16) {
245362306a36Sopenharmony_ci				opcode = cdb[0] == READ_16 ? READ_10 : WRITE_10;
245462306a36Sopenharmony_ci				flagvals = cdb[1];
245562306a36Sopenharmony_ci				groupnum = cdb[14];
245662306a36Sopenharmony_ci				control = cdb[15];
245762306a36Sopenharmony_ci			} else {
245862306a36Sopenharmony_ci				opcode = cdb[0] == READ_12 ? READ_10 : WRITE_10;
245962306a36Sopenharmony_ci				flagvals = cdb[1];
246062306a36Sopenharmony_ci				groupnum = cdb[10];
246162306a36Sopenharmony_ci				control = cdb[11];
246262306a36Sopenharmony_ci			}
246362306a36Sopenharmony_ci
246462306a36Sopenharmony_ci			memset(cdb, 0, sizeof(io_request->CDB.CDB32));
246562306a36Sopenharmony_ci
246662306a36Sopenharmony_ci			cdb[0] = opcode;
246762306a36Sopenharmony_ci			cdb[1] = flagvals;
246862306a36Sopenharmony_ci			cdb[6] = groupnum;
246962306a36Sopenharmony_ci			cdb[9] = control;
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_ci			/* Transfer length */
247262306a36Sopenharmony_ci			cdb[8] = (u8)(num_blocks & 0xff);
247362306a36Sopenharmony_ci			cdb[7] = (u8)((num_blocks >> 8) & 0xff);
247462306a36Sopenharmony_ci
247562306a36Sopenharmony_ci			io_request->IoFlags = cpu_to_le16(10); /* Specify 10-byte cdb */
247662306a36Sopenharmony_ci			cdb_len = 10;
247762306a36Sopenharmony_ci		} else if ((cdb_len < 16) && (start_blk > 0xffffffff)) {
247862306a36Sopenharmony_ci			/* Convert to 16 byte CDB for large LBA's */
247962306a36Sopenharmony_ci			switch (cdb_len) {
248062306a36Sopenharmony_ci			case 6:
248162306a36Sopenharmony_ci				opcode = cdb[0] == READ_6 ? READ_16 : WRITE_16;
248262306a36Sopenharmony_ci				control = cdb[5];
248362306a36Sopenharmony_ci				break;
248462306a36Sopenharmony_ci			case 10:
248562306a36Sopenharmony_ci				opcode =
248662306a36Sopenharmony_ci					cdb[0] == READ_10 ? READ_16 : WRITE_16;
248762306a36Sopenharmony_ci				flagvals = cdb[1];
248862306a36Sopenharmony_ci				groupnum = cdb[6];
248962306a36Sopenharmony_ci				control = cdb[9];
249062306a36Sopenharmony_ci				break;
249162306a36Sopenharmony_ci			case 12:
249262306a36Sopenharmony_ci				opcode =
249362306a36Sopenharmony_ci					cdb[0] == READ_12 ? READ_16 : WRITE_16;
249462306a36Sopenharmony_ci				flagvals = cdb[1];
249562306a36Sopenharmony_ci				groupnum = cdb[10];
249662306a36Sopenharmony_ci				control = cdb[11];
249762306a36Sopenharmony_ci				break;
249862306a36Sopenharmony_ci			}
249962306a36Sopenharmony_ci
250062306a36Sopenharmony_ci			memset(cdb, 0, sizeof(io_request->CDB.CDB32));
250162306a36Sopenharmony_ci
250262306a36Sopenharmony_ci			cdb[0] = opcode;
250362306a36Sopenharmony_ci			cdb[1] = flagvals;
250462306a36Sopenharmony_ci			cdb[14] = groupnum;
250562306a36Sopenharmony_ci			cdb[15] = control;
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_ci			/* Transfer length */
250862306a36Sopenharmony_ci			cdb[13] = (u8)(num_blocks & 0xff);
250962306a36Sopenharmony_ci			cdb[12] = (u8)((num_blocks >> 8) & 0xff);
251062306a36Sopenharmony_ci			cdb[11] = (u8)((num_blocks >> 16) & 0xff);
251162306a36Sopenharmony_ci			cdb[10] = (u8)((num_blocks >> 24) & 0xff);
251262306a36Sopenharmony_ci
251362306a36Sopenharmony_ci			io_request->IoFlags = cpu_to_le16(16); /* Specify 16-byte cdb */
251462306a36Sopenharmony_ci			cdb_len = 16;
251562306a36Sopenharmony_ci		}
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_ci		/* Normal case, just load LBA here */
251862306a36Sopenharmony_ci		switch (cdb_len) {
251962306a36Sopenharmony_ci		case 6:
252062306a36Sopenharmony_ci		{
252162306a36Sopenharmony_ci			u8 val = cdb[1] & 0xE0;
252262306a36Sopenharmony_ci			cdb[3] = (u8)(start_blk & 0xff);
252362306a36Sopenharmony_ci			cdb[2] = (u8)((start_blk >> 8) & 0xff);
252462306a36Sopenharmony_ci			cdb[1] = val | ((u8)(start_blk >> 16) & 0x1f);
252562306a36Sopenharmony_ci			break;
252662306a36Sopenharmony_ci		}
252762306a36Sopenharmony_ci		case 10:
252862306a36Sopenharmony_ci			cdb[5] = (u8)(start_blk & 0xff);
252962306a36Sopenharmony_ci			cdb[4] = (u8)((start_blk >> 8) & 0xff);
253062306a36Sopenharmony_ci			cdb[3] = (u8)((start_blk >> 16) & 0xff);
253162306a36Sopenharmony_ci			cdb[2] = (u8)((start_blk >> 24) & 0xff);
253262306a36Sopenharmony_ci			break;
253362306a36Sopenharmony_ci		case 12:
253462306a36Sopenharmony_ci			cdb[5]    = (u8)(start_blk & 0xff);
253562306a36Sopenharmony_ci			cdb[4]    = (u8)((start_blk >> 8) & 0xff);
253662306a36Sopenharmony_ci			cdb[3]    = (u8)((start_blk >> 16) & 0xff);
253762306a36Sopenharmony_ci			cdb[2]    = (u8)((start_blk >> 24) & 0xff);
253862306a36Sopenharmony_ci			break;
253962306a36Sopenharmony_ci		case 16:
254062306a36Sopenharmony_ci			cdb[9]    = (u8)(start_blk & 0xff);
254162306a36Sopenharmony_ci			cdb[8]    = (u8)((start_blk >> 8) & 0xff);
254262306a36Sopenharmony_ci			cdb[7]    = (u8)((start_blk >> 16) & 0xff);
254362306a36Sopenharmony_ci			cdb[6]    = (u8)((start_blk >> 24) & 0xff);
254462306a36Sopenharmony_ci			cdb[5]    = (u8)((start_blk >> 32) & 0xff);
254562306a36Sopenharmony_ci			cdb[4]    = (u8)((start_blk >> 40) & 0xff);
254662306a36Sopenharmony_ci			cdb[3]    = (u8)((start_blk >> 48) & 0xff);
254762306a36Sopenharmony_ci			cdb[2]    = (u8)((start_blk >> 56) & 0xff);
254862306a36Sopenharmony_ci			break;
254962306a36Sopenharmony_ci		}
255062306a36Sopenharmony_ci	}
255162306a36Sopenharmony_ci}
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci/**
255462306a36Sopenharmony_ci * megasas_stream_detect -	stream detection on read and and write IOs
255562306a36Sopenharmony_ci * @instance:		Adapter soft state
255662306a36Sopenharmony_ci * @cmd:		    Command to be prepared
255762306a36Sopenharmony_ci * @io_info:		IO Request info
255862306a36Sopenharmony_ci *
255962306a36Sopenharmony_ci */
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci/** stream detection on read and and write IOs */
256262306a36Sopenharmony_cistatic void megasas_stream_detect(struct megasas_instance *instance,
256362306a36Sopenharmony_ci				  struct megasas_cmd_fusion *cmd,
256462306a36Sopenharmony_ci				  struct IO_REQUEST_INFO *io_info)
256562306a36Sopenharmony_ci{
256662306a36Sopenharmony_ci	struct fusion_context *fusion = instance->ctrl_context;
256762306a36Sopenharmony_ci	u32 device_id = io_info->ldTgtId;
256862306a36Sopenharmony_ci	struct LD_STREAM_DETECT *current_ld_sd
256962306a36Sopenharmony_ci		= fusion->stream_detect_by_ld[device_id];
257062306a36Sopenharmony_ci	u32 *track_stream = &current_ld_sd->mru_bit_map, stream_num;
257162306a36Sopenharmony_ci	u32 shifted_values, unshifted_values;
257262306a36Sopenharmony_ci	u32 index_value_mask, shifted_values_mask;
257362306a36Sopenharmony_ci	int i;
257462306a36Sopenharmony_ci	bool is_read_ahead = false;
257562306a36Sopenharmony_ci	struct STREAM_DETECT *current_sd;
257662306a36Sopenharmony_ci	/* find possible stream */
257762306a36Sopenharmony_ci	for (i = 0; i < MAX_STREAMS_TRACKED; ++i) {
257862306a36Sopenharmony_ci		stream_num = (*track_stream >>
257962306a36Sopenharmony_ci			(i * BITS_PER_INDEX_STREAM)) &
258062306a36Sopenharmony_ci			STREAM_MASK;
258162306a36Sopenharmony_ci		current_sd = &current_ld_sd->stream_track[stream_num];
258262306a36Sopenharmony_ci		/* if we found a stream, update the raid
258362306a36Sopenharmony_ci		 *  context and also update the mruBitMap
258462306a36Sopenharmony_ci		 */
258562306a36Sopenharmony_ci		/*	boundary condition */
258662306a36Sopenharmony_ci		if ((current_sd->next_seq_lba) &&
258762306a36Sopenharmony_ci		    (io_info->ldStartBlock >= current_sd->next_seq_lba) &&
258862306a36Sopenharmony_ci		    (io_info->ldStartBlock <= (current_sd->next_seq_lba + 32)) &&
258962306a36Sopenharmony_ci		    (current_sd->is_read == io_info->isRead)) {
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci			if ((io_info->ldStartBlock != current_sd->next_seq_lba)	&&
259262306a36Sopenharmony_ci			    ((!io_info->isRead) || (!is_read_ahead)))
259362306a36Sopenharmony_ci				/*
259462306a36Sopenharmony_ci				 * Once the API is available we need to change this.
259562306a36Sopenharmony_ci				 * At this point we are not allowing any gap
259662306a36Sopenharmony_ci				 */
259762306a36Sopenharmony_ci				continue;
259862306a36Sopenharmony_ci
259962306a36Sopenharmony_ci			SET_STREAM_DETECTED(cmd->io_request->RaidContext.raid_context_g35);
260062306a36Sopenharmony_ci			current_sd->next_seq_lba =
260162306a36Sopenharmony_ci			io_info->ldStartBlock + io_info->numBlocks;
260262306a36Sopenharmony_ci			/*
260362306a36Sopenharmony_ci			 *	update the mruBitMap LRU
260462306a36Sopenharmony_ci			 */
260562306a36Sopenharmony_ci			shifted_values_mask =
260662306a36Sopenharmony_ci				(1 <<  i * BITS_PER_INDEX_STREAM) - 1;
260762306a36Sopenharmony_ci			shifted_values = ((*track_stream & shifted_values_mask)
260862306a36Sopenharmony_ci						<< BITS_PER_INDEX_STREAM);
260962306a36Sopenharmony_ci			index_value_mask =
261062306a36Sopenharmony_ci				STREAM_MASK << i * BITS_PER_INDEX_STREAM;
261162306a36Sopenharmony_ci			unshifted_values =
261262306a36Sopenharmony_ci				*track_stream & ~(shifted_values_mask |
261362306a36Sopenharmony_ci				index_value_mask);
261462306a36Sopenharmony_ci			*track_stream =
261562306a36Sopenharmony_ci				unshifted_values | shifted_values | stream_num;
261662306a36Sopenharmony_ci			return;
261762306a36Sopenharmony_ci		}
261862306a36Sopenharmony_ci	}
261962306a36Sopenharmony_ci	/*
262062306a36Sopenharmony_ci	 * if we did not find any stream, create a new one
262162306a36Sopenharmony_ci	 * from the least recently used
262262306a36Sopenharmony_ci	 */
262362306a36Sopenharmony_ci	stream_num = (*track_stream >>
262462306a36Sopenharmony_ci		((MAX_STREAMS_TRACKED - 1) * BITS_PER_INDEX_STREAM)) &
262562306a36Sopenharmony_ci		STREAM_MASK;
262662306a36Sopenharmony_ci	current_sd = &current_ld_sd->stream_track[stream_num];
262762306a36Sopenharmony_ci	current_sd->is_read = io_info->isRead;
262862306a36Sopenharmony_ci	current_sd->next_seq_lba = io_info->ldStartBlock + io_info->numBlocks;
262962306a36Sopenharmony_ci	*track_stream = (((*track_stream & ZERO_LAST_STREAM) << 4) | stream_num);
263062306a36Sopenharmony_ci	return;
263162306a36Sopenharmony_ci}
263262306a36Sopenharmony_ci
263362306a36Sopenharmony_ci/**
263462306a36Sopenharmony_ci * megasas_set_raidflag_cpu_affinity - This function sets the cpu
263562306a36Sopenharmony_ci * affinity (cpu of the controller) and raid_flags in the raid context
263662306a36Sopenharmony_ci * based on IO type.
263762306a36Sopenharmony_ci *
263862306a36Sopenharmony_ci * @fusion:		Fusion context
263962306a36Sopenharmony_ci * @praid_context:	IO RAID context
264062306a36Sopenharmony_ci * @raid:		LD raid map
264162306a36Sopenharmony_ci * @fp_possible:	Is fast path possible?
264262306a36Sopenharmony_ci * @is_read:		Is read IO?
264362306a36Sopenharmony_ci * @scsi_buff_len:	SCSI command buffer length
264462306a36Sopenharmony_ci *
264562306a36Sopenharmony_ci */
264662306a36Sopenharmony_cistatic void
264762306a36Sopenharmony_cimegasas_set_raidflag_cpu_affinity(struct fusion_context *fusion,
264862306a36Sopenharmony_ci				union RAID_CONTEXT_UNION *praid_context,
264962306a36Sopenharmony_ci				struct MR_LD_RAID *raid, bool fp_possible,
265062306a36Sopenharmony_ci				u8 is_read, u32 scsi_buff_len)
265162306a36Sopenharmony_ci{
265262306a36Sopenharmony_ci	u8 cpu_sel = MR_RAID_CTX_CPUSEL_0;
265362306a36Sopenharmony_ci	struct RAID_CONTEXT_G35 *rctx_g35;
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_ci	rctx_g35 = &praid_context->raid_context_g35;
265662306a36Sopenharmony_ci	if (fp_possible) {
265762306a36Sopenharmony_ci		if (is_read) {
265862306a36Sopenharmony_ci			if ((raid->cpuAffinity.pdRead.cpu0) &&
265962306a36Sopenharmony_ci			    (raid->cpuAffinity.pdRead.cpu1))
266062306a36Sopenharmony_ci				cpu_sel = MR_RAID_CTX_CPUSEL_FCFS;
266162306a36Sopenharmony_ci			else if (raid->cpuAffinity.pdRead.cpu1)
266262306a36Sopenharmony_ci				cpu_sel = MR_RAID_CTX_CPUSEL_1;
266362306a36Sopenharmony_ci		} else {
266462306a36Sopenharmony_ci			if ((raid->cpuAffinity.pdWrite.cpu0) &&
266562306a36Sopenharmony_ci			    (raid->cpuAffinity.pdWrite.cpu1))
266662306a36Sopenharmony_ci				cpu_sel = MR_RAID_CTX_CPUSEL_FCFS;
266762306a36Sopenharmony_ci			else if (raid->cpuAffinity.pdWrite.cpu1)
266862306a36Sopenharmony_ci				cpu_sel = MR_RAID_CTX_CPUSEL_1;
266962306a36Sopenharmony_ci			/* Fast path cache by pass capable R0/R1 VD */
267062306a36Sopenharmony_ci			if ((raid->level <= 1) &&
267162306a36Sopenharmony_ci			    (raid->capability.fp_cache_bypass_capable)) {
267262306a36Sopenharmony_ci				rctx_g35->routing_flags |=
267362306a36Sopenharmony_ci					(1 << MR_RAID_CTX_ROUTINGFLAGS_SLD_SHIFT);
267462306a36Sopenharmony_ci				rctx_g35->raid_flags =
267562306a36Sopenharmony_ci					(MR_RAID_FLAGS_IO_SUB_TYPE_CACHE_BYPASS
267662306a36Sopenharmony_ci					<< MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT);
267762306a36Sopenharmony_ci			}
267862306a36Sopenharmony_ci		}
267962306a36Sopenharmony_ci	} else {
268062306a36Sopenharmony_ci		if (is_read) {
268162306a36Sopenharmony_ci			if ((raid->cpuAffinity.ldRead.cpu0) &&
268262306a36Sopenharmony_ci			    (raid->cpuAffinity.ldRead.cpu1))
268362306a36Sopenharmony_ci				cpu_sel = MR_RAID_CTX_CPUSEL_FCFS;
268462306a36Sopenharmony_ci			else if (raid->cpuAffinity.ldRead.cpu1)
268562306a36Sopenharmony_ci				cpu_sel = MR_RAID_CTX_CPUSEL_1;
268662306a36Sopenharmony_ci		} else {
268762306a36Sopenharmony_ci			if ((raid->cpuAffinity.ldWrite.cpu0) &&
268862306a36Sopenharmony_ci			    (raid->cpuAffinity.ldWrite.cpu1))
268962306a36Sopenharmony_ci				cpu_sel = MR_RAID_CTX_CPUSEL_FCFS;
269062306a36Sopenharmony_ci			else if (raid->cpuAffinity.ldWrite.cpu1)
269162306a36Sopenharmony_ci				cpu_sel = MR_RAID_CTX_CPUSEL_1;
269262306a36Sopenharmony_ci
269362306a36Sopenharmony_ci			if (is_stream_detected(rctx_g35) &&
269462306a36Sopenharmony_ci			    ((raid->level == 5) || (raid->level == 6)) &&
269562306a36Sopenharmony_ci			    (raid->writeMode == MR_RL_WRITE_THROUGH_MODE) &&
269662306a36Sopenharmony_ci			    (cpu_sel == MR_RAID_CTX_CPUSEL_FCFS))
269762306a36Sopenharmony_ci				cpu_sel = MR_RAID_CTX_CPUSEL_0;
269862306a36Sopenharmony_ci		}
269962306a36Sopenharmony_ci	}
270062306a36Sopenharmony_ci
270162306a36Sopenharmony_ci	rctx_g35->routing_flags |=
270262306a36Sopenharmony_ci		(cpu_sel << MR_RAID_CTX_ROUTINGFLAGS_CPUSEL_SHIFT);
270362306a36Sopenharmony_ci
270462306a36Sopenharmony_ci	/* Always give priority to MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT
270562306a36Sopenharmony_ci	 * vs MR_RAID_FLAGS_IO_SUB_TYPE_CACHE_BYPASS.
270662306a36Sopenharmony_ci	 * IO Subtype is not bitmap.
270762306a36Sopenharmony_ci	 */
270862306a36Sopenharmony_ci	if ((fusion->pcie_bw_limitation) && (raid->level == 1) && (!is_read) &&
270962306a36Sopenharmony_ci			(scsi_buff_len > MR_LARGE_IO_MIN_SIZE)) {
271062306a36Sopenharmony_ci		praid_context->raid_context_g35.raid_flags =
271162306a36Sopenharmony_ci			(MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT
271262306a36Sopenharmony_ci			<< MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT);
271362306a36Sopenharmony_ci	}
271462306a36Sopenharmony_ci}
271562306a36Sopenharmony_ci
271662306a36Sopenharmony_ci/**
271762306a36Sopenharmony_ci * megasas_build_ldio_fusion -	Prepares IOs to devices
271862306a36Sopenharmony_ci * @instance:		Adapter soft state
271962306a36Sopenharmony_ci * @scp:		SCSI command
272062306a36Sopenharmony_ci * @cmd:		Command to be prepared
272162306a36Sopenharmony_ci *
272262306a36Sopenharmony_ci * Prepares the io_request and chain elements (sg_frame) for IO
272362306a36Sopenharmony_ci * The IO can be for PD (Fast Path) or LD
272462306a36Sopenharmony_ci */
272562306a36Sopenharmony_cistatic void
272662306a36Sopenharmony_cimegasas_build_ldio_fusion(struct megasas_instance *instance,
272762306a36Sopenharmony_ci			  struct scsi_cmnd *scp,
272862306a36Sopenharmony_ci			  struct megasas_cmd_fusion *cmd)
272962306a36Sopenharmony_ci{
273062306a36Sopenharmony_ci	bool fp_possible;
273162306a36Sopenharmony_ci	u16 ld;
273262306a36Sopenharmony_ci	u32 start_lba_lo, start_lba_hi, device_id, datalength = 0;
273362306a36Sopenharmony_ci	u32 scsi_buff_len;
273462306a36Sopenharmony_ci	struct MPI2_RAID_SCSI_IO_REQUEST *io_request;
273562306a36Sopenharmony_ci	struct IO_REQUEST_INFO io_info;
273662306a36Sopenharmony_ci	struct fusion_context *fusion;
273762306a36Sopenharmony_ci	struct MR_DRV_RAID_MAP_ALL *local_map_ptr;
273862306a36Sopenharmony_ci	u8 *raidLUN;
273962306a36Sopenharmony_ci	unsigned long spinlock_flags;
274062306a36Sopenharmony_ci	struct MR_LD_RAID *raid = NULL;
274162306a36Sopenharmony_ci	struct MR_PRIV_DEVICE *mrdev_priv;
274262306a36Sopenharmony_ci	struct RAID_CONTEXT *rctx;
274362306a36Sopenharmony_ci	struct RAID_CONTEXT_G35 *rctx_g35;
274462306a36Sopenharmony_ci
274562306a36Sopenharmony_ci	device_id = MEGASAS_DEV_INDEX(scp);
274662306a36Sopenharmony_ci
274762306a36Sopenharmony_ci	fusion = instance->ctrl_context;
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_ci	io_request = cmd->io_request;
275062306a36Sopenharmony_ci	rctx = &io_request->RaidContext.raid_context;
275162306a36Sopenharmony_ci	rctx_g35 = &io_request->RaidContext.raid_context_g35;
275262306a36Sopenharmony_ci
275362306a36Sopenharmony_ci	rctx->virtual_disk_tgt_id = cpu_to_le16(device_id);
275462306a36Sopenharmony_ci	rctx->status = 0;
275562306a36Sopenharmony_ci	rctx->ex_status = 0;
275662306a36Sopenharmony_ci
275762306a36Sopenharmony_ci	start_lba_lo = 0;
275862306a36Sopenharmony_ci	start_lba_hi = 0;
275962306a36Sopenharmony_ci	fp_possible = false;
276062306a36Sopenharmony_ci
276162306a36Sopenharmony_ci	/*
276262306a36Sopenharmony_ci	 * 6-byte READ(0x08) or WRITE(0x0A) cdb
276362306a36Sopenharmony_ci	 */
276462306a36Sopenharmony_ci	if (scp->cmd_len == 6) {
276562306a36Sopenharmony_ci		datalength = (u32) scp->cmnd[4];
276662306a36Sopenharmony_ci		start_lba_lo = ((u32) scp->cmnd[1] << 16) |
276762306a36Sopenharmony_ci			((u32) scp->cmnd[2] << 8) | (u32) scp->cmnd[3];
276862306a36Sopenharmony_ci
276962306a36Sopenharmony_ci		start_lba_lo &= 0x1FFFFF;
277062306a36Sopenharmony_ci	}
277162306a36Sopenharmony_ci
277262306a36Sopenharmony_ci	/*
277362306a36Sopenharmony_ci	 * 10-byte READ(0x28) or WRITE(0x2A) cdb
277462306a36Sopenharmony_ci	 */
277562306a36Sopenharmony_ci	else if (scp->cmd_len == 10) {
277662306a36Sopenharmony_ci		datalength = (u32) scp->cmnd[8] |
277762306a36Sopenharmony_ci			((u32) scp->cmnd[7] << 8);
277862306a36Sopenharmony_ci		start_lba_lo = ((u32) scp->cmnd[2] << 24) |
277962306a36Sopenharmony_ci			((u32) scp->cmnd[3] << 16) |
278062306a36Sopenharmony_ci			((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
278162306a36Sopenharmony_ci	}
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_ci	/*
278462306a36Sopenharmony_ci	 * 12-byte READ(0xA8) or WRITE(0xAA) cdb
278562306a36Sopenharmony_ci	 */
278662306a36Sopenharmony_ci	else if (scp->cmd_len == 12) {
278762306a36Sopenharmony_ci		datalength = ((u32) scp->cmnd[6] << 24) |
278862306a36Sopenharmony_ci			((u32) scp->cmnd[7] << 16) |
278962306a36Sopenharmony_ci			((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9];
279062306a36Sopenharmony_ci		start_lba_lo = ((u32) scp->cmnd[2] << 24) |
279162306a36Sopenharmony_ci			((u32) scp->cmnd[3] << 16) |
279262306a36Sopenharmony_ci			((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
279362306a36Sopenharmony_ci	}
279462306a36Sopenharmony_ci
279562306a36Sopenharmony_ci	/*
279662306a36Sopenharmony_ci	 * 16-byte READ(0x88) or WRITE(0x8A) cdb
279762306a36Sopenharmony_ci	 */
279862306a36Sopenharmony_ci	else if (scp->cmd_len == 16) {
279962306a36Sopenharmony_ci		datalength = ((u32) scp->cmnd[10] << 24) |
280062306a36Sopenharmony_ci			((u32) scp->cmnd[11] << 16) |
280162306a36Sopenharmony_ci			((u32) scp->cmnd[12] << 8) | (u32) scp->cmnd[13];
280262306a36Sopenharmony_ci		start_lba_lo = ((u32) scp->cmnd[6] << 24) |
280362306a36Sopenharmony_ci			((u32) scp->cmnd[7] << 16) |
280462306a36Sopenharmony_ci			((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9];
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci		start_lba_hi = ((u32) scp->cmnd[2] << 24) |
280762306a36Sopenharmony_ci			((u32) scp->cmnd[3] << 16) |
280862306a36Sopenharmony_ci			((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
280962306a36Sopenharmony_ci	}
281062306a36Sopenharmony_ci
281162306a36Sopenharmony_ci	memset(&io_info, 0, sizeof(struct IO_REQUEST_INFO));
281262306a36Sopenharmony_ci	io_info.ldStartBlock = ((u64)start_lba_hi << 32) | start_lba_lo;
281362306a36Sopenharmony_ci	io_info.numBlocks = datalength;
281462306a36Sopenharmony_ci	io_info.ldTgtId = device_id;
281562306a36Sopenharmony_ci	io_info.r1_alt_dev_handle = MR_DEVHANDLE_INVALID;
281662306a36Sopenharmony_ci	scsi_buff_len = scsi_bufflen(scp);
281762306a36Sopenharmony_ci	io_request->DataLength = cpu_to_le32(scsi_buff_len);
281862306a36Sopenharmony_ci	io_info.data_arms = 1;
281962306a36Sopenharmony_ci
282062306a36Sopenharmony_ci	if (scp->sc_data_direction == DMA_FROM_DEVICE)
282162306a36Sopenharmony_ci		io_info.isRead = 1;
282262306a36Sopenharmony_ci
282362306a36Sopenharmony_ci	local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
282462306a36Sopenharmony_ci	ld = MR_TargetIdToLdGet(device_id, local_map_ptr);
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_ci	if (ld < instance->fw_supported_vd_count)
282762306a36Sopenharmony_ci		raid = MR_LdRaidGet(ld, local_map_ptr);
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_ci	if (!raid || (!fusion->fast_path_io)) {
283062306a36Sopenharmony_ci		rctx->reg_lock_flags  = 0;
283162306a36Sopenharmony_ci		fp_possible = false;
283262306a36Sopenharmony_ci	} else {
283362306a36Sopenharmony_ci		if (MR_BuildRaidContext(instance, &io_info, rctx,
283462306a36Sopenharmony_ci					local_map_ptr, &raidLUN))
283562306a36Sopenharmony_ci			fp_possible = (io_info.fpOkForIo > 0) ? true : false;
283662306a36Sopenharmony_ci	}
283762306a36Sopenharmony_ci
283862306a36Sopenharmony_ci	megasas_get_msix_index(instance, scp, cmd, io_info.data_arms);
283962306a36Sopenharmony_ci
284062306a36Sopenharmony_ci	if (instance->adapter_type >= VENTURA_SERIES) {
284162306a36Sopenharmony_ci		/* FP for Optimal raid level 1.
284262306a36Sopenharmony_ci		 * All large RAID-1 writes (> 32 KiB, both WT and WB modes)
284362306a36Sopenharmony_ci		 * are built by the driver as LD I/Os.
284462306a36Sopenharmony_ci		 * All small RAID-1 WT writes (<= 32 KiB) are built as FP I/Os
284562306a36Sopenharmony_ci		 * (there is never a reason to process these as buffered writes)
284662306a36Sopenharmony_ci		 * All small RAID-1 WB writes (<= 32 KiB) are built as FP I/Os
284762306a36Sopenharmony_ci		 * with the SLD bit asserted.
284862306a36Sopenharmony_ci		 */
284962306a36Sopenharmony_ci		if (io_info.r1_alt_dev_handle != MR_DEVHANDLE_INVALID) {
285062306a36Sopenharmony_ci			mrdev_priv = scp->device->hostdata;
285162306a36Sopenharmony_ci
285262306a36Sopenharmony_ci			if (atomic_inc_return(&instance->fw_outstanding) >
285362306a36Sopenharmony_ci				(instance->host->can_queue)) {
285462306a36Sopenharmony_ci				fp_possible = false;
285562306a36Sopenharmony_ci				atomic_dec(&instance->fw_outstanding);
285662306a36Sopenharmony_ci			} else if (fusion->pcie_bw_limitation &&
285762306a36Sopenharmony_ci				((scsi_buff_len > MR_LARGE_IO_MIN_SIZE) ||
285862306a36Sopenharmony_ci				   (atomic_dec_if_positive(&mrdev_priv->r1_ldio_hint) > 0))) {
285962306a36Sopenharmony_ci				fp_possible = false;
286062306a36Sopenharmony_ci				atomic_dec(&instance->fw_outstanding);
286162306a36Sopenharmony_ci				if (scsi_buff_len > MR_LARGE_IO_MIN_SIZE)
286262306a36Sopenharmony_ci					atomic_set(&mrdev_priv->r1_ldio_hint,
286362306a36Sopenharmony_ci						   instance->r1_ldio_hint_default);
286462306a36Sopenharmony_ci			}
286562306a36Sopenharmony_ci		}
286662306a36Sopenharmony_ci
286762306a36Sopenharmony_ci		if (!fp_possible ||
286862306a36Sopenharmony_ci		    (io_info.isRead && io_info.ra_capable)) {
286962306a36Sopenharmony_ci			spin_lock_irqsave(&instance->stream_lock,
287062306a36Sopenharmony_ci					  spinlock_flags);
287162306a36Sopenharmony_ci			megasas_stream_detect(instance, cmd, &io_info);
287262306a36Sopenharmony_ci			spin_unlock_irqrestore(&instance->stream_lock,
287362306a36Sopenharmony_ci					       spinlock_flags);
287462306a36Sopenharmony_ci			/* In ventura if stream detected for a read and it is
287562306a36Sopenharmony_ci			 * read ahead capable make this IO as LDIO
287662306a36Sopenharmony_ci			 */
287762306a36Sopenharmony_ci			if (is_stream_detected(rctx_g35))
287862306a36Sopenharmony_ci				fp_possible = false;
287962306a36Sopenharmony_ci		}
288062306a36Sopenharmony_ci
288162306a36Sopenharmony_ci		/* If raid is NULL, set CPU affinity to default CPU0 */
288262306a36Sopenharmony_ci		if (raid)
288362306a36Sopenharmony_ci			megasas_set_raidflag_cpu_affinity(fusion, &io_request->RaidContext,
288462306a36Sopenharmony_ci				raid, fp_possible, io_info.isRead,
288562306a36Sopenharmony_ci				scsi_buff_len);
288662306a36Sopenharmony_ci		else
288762306a36Sopenharmony_ci			rctx_g35->routing_flags |=
288862306a36Sopenharmony_ci				(MR_RAID_CTX_CPUSEL_0 << MR_RAID_CTX_ROUTINGFLAGS_CPUSEL_SHIFT);
288962306a36Sopenharmony_ci	}
289062306a36Sopenharmony_ci
289162306a36Sopenharmony_ci	if (fp_possible) {
289262306a36Sopenharmony_ci		megasas_set_pd_lba(io_request, scp->cmd_len, &io_info, scp,
289362306a36Sopenharmony_ci				   local_map_ptr, start_lba_lo);
289462306a36Sopenharmony_ci		io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
289562306a36Sopenharmony_ci		cmd->request_desc->SCSIIO.RequestFlags =
289662306a36Sopenharmony_ci			(MPI2_REQ_DESCRIPT_FLAGS_FP_IO
289762306a36Sopenharmony_ci			 << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
289862306a36Sopenharmony_ci		if (instance->adapter_type == INVADER_SERIES) {
289962306a36Sopenharmony_ci			rctx->type = MPI2_TYPE_CUDA;
290062306a36Sopenharmony_ci			rctx->nseg = 0x1;
290162306a36Sopenharmony_ci			io_request->IoFlags |= cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
290262306a36Sopenharmony_ci			rctx->reg_lock_flags |=
290362306a36Sopenharmony_ci			  (MR_RL_FLAGS_GRANT_DESTINATION_CUDA |
290462306a36Sopenharmony_ci			   MR_RL_FLAGS_SEQ_NUM_ENABLE);
290562306a36Sopenharmony_ci		} else if (instance->adapter_type >= VENTURA_SERIES) {
290662306a36Sopenharmony_ci			rctx_g35->nseg_type |= (1 << RAID_CONTEXT_NSEG_SHIFT);
290762306a36Sopenharmony_ci			rctx_g35->nseg_type |= (MPI2_TYPE_CUDA << RAID_CONTEXT_TYPE_SHIFT);
290862306a36Sopenharmony_ci			rctx_g35->routing_flags |= (1 << MR_RAID_CTX_ROUTINGFLAGS_SQN_SHIFT);
290962306a36Sopenharmony_ci			io_request->IoFlags |=
291062306a36Sopenharmony_ci				cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
291162306a36Sopenharmony_ci		}
291262306a36Sopenharmony_ci		if (fusion->load_balance_info &&
291362306a36Sopenharmony_ci			(fusion->load_balance_info[device_id].loadBalanceFlag) &&
291462306a36Sopenharmony_ci			(io_info.isRead)) {
291562306a36Sopenharmony_ci			io_info.devHandle =
291662306a36Sopenharmony_ci				get_updated_dev_handle(instance,
291762306a36Sopenharmony_ci					&fusion->load_balance_info[device_id],
291862306a36Sopenharmony_ci					&io_info, local_map_ptr);
291962306a36Sopenharmony_ci			megasas_priv(scp)->status |= MEGASAS_LOAD_BALANCE_FLAG;
292062306a36Sopenharmony_ci			cmd->pd_r1_lb = io_info.pd_after_lb;
292162306a36Sopenharmony_ci			if (instance->adapter_type >= VENTURA_SERIES)
292262306a36Sopenharmony_ci				rctx_g35->span_arm = io_info.span_arm;
292362306a36Sopenharmony_ci			else
292462306a36Sopenharmony_ci				rctx->span_arm = io_info.span_arm;
292562306a36Sopenharmony_ci
292662306a36Sopenharmony_ci		} else
292762306a36Sopenharmony_ci			megasas_priv(scp)->status &= ~MEGASAS_LOAD_BALANCE_FLAG;
292862306a36Sopenharmony_ci
292962306a36Sopenharmony_ci		if (instance->adapter_type >= VENTURA_SERIES)
293062306a36Sopenharmony_ci			cmd->r1_alt_dev_handle = io_info.r1_alt_dev_handle;
293162306a36Sopenharmony_ci		else
293262306a36Sopenharmony_ci			cmd->r1_alt_dev_handle = MR_DEVHANDLE_INVALID;
293362306a36Sopenharmony_ci
293462306a36Sopenharmony_ci		if ((raidLUN[0] == 1) &&
293562306a36Sopenharmony_ci			(local_map_ptr->raidMap.devHndlInfo[io_info.pd_after_lb].validHandles > 1)) {
293662306a36Sopenharmony_ci			instance->dev_handle = !(instance->dev_handle);
293762306a36Sopenharmony_ci			io_info.devHandle =
293862306a36Sopenharmony_ci				local_map_ptr->raidMap.devHndlInfo[io_info.pd_after_lb].devHandle[instance->dev_handle];
293962306a36Sopenharmony_ci		}
294062306a36Sopenharmony_ci
294162306a36Sopenharmony_ci		cmd->request_desc->SCSIIO.DevHandle = io_info.devHandle;
294262306a36Sopenharmony_ci		io_request->DevHandle = io_info.devHandle;
294362306a36Sopenharmony_ci		cmd->pd_interface = io_info.pd_interface;
294462306a36Sopenharmony_ci		/* populate the LUN field */
294562306a36Sopenharmony_ci		memcpy(io_request->LUN, raidLUN, 8);
294662306a36Sopenharmony_ci	} else {
294762306a36Sopenharmony_ci		rctx->timeout_value =
294862306a36Sopenharmony_ci			cpu_to_le16(local_map_ptr->raidMap.fpPdIoTimeoutSec);
294962306a36Sopenharmony_ci		cmd->request_desc->SCSIIO.RequestFlags =
295062306a36Sopenharmony_ci			(MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO
295162306a36Sopenharmony_ci			 << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
295262306a36Sopenharmony_ci		if (instance->adapter_type == INVADER_SERIES) {
295362306a36Sopenharmony_ci			if (io_info.do_fp_rlbypass ||
295462306a36Sopenharmony_ci			(rctx->reg_lock_flags == REGION_TYPE_UNUSED))
295562306a36Sopenharmony_ci				cmd->request_desc->SCSIIO.RequestFlags =
295662306a36Sopenharmony_ci					(MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK <<
295762306a36Sopenharmony_ci					MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
295862306a36Sopenharmony_ci			rctx->type = MPI2_TYPE_CUDA;
295962306a36Sopenharmony_ci			rctx->reg_lock_flags |=
296062306a36Sopenharmony_ci				(MR_RL_FLAGS_GRANT_DESTINATION_CPU0 |
296162306a36Sopenharmony_ci					MR_RL_FLAGS_SEQ_NUM_ENABLE);
296262306a36Sopenharmony_ci			rctx->nseg = 0x1;
296362306a36Sopenharmony_ci		} else if (instance->adapter_type >= VENTURA_SERIES) {
296462306a36Sopenharmony_ci			rctx_g35->routing_flags |= (1 << MR_RAID_CTX_ROUTINGFLAGS_SQN_SHIFT);
296562306a36Sopenharmony_ci			rctx_g35->nseg_type |= (1 << RAID_CONTEXT_NSEG_SHIFT);
296662306a36Sopenharmony_ci			rctx_g35->nseg_type |= (MPI2_TYPE_CUDA << RAID_CONTEXT_TYPE_SHIFT);
296762306a36Sopenharmony_ci		}
296862306a36Sopenharmony_ci		io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
296962306a36Sopenharmony_ci		io_request->DevHandle = cpu_to_le16(device_id);
297062306a36Sopenharmony_ci
297162306a36Sopenharmony_ci	} /* Not FP */
297262306a36Sopenharmony_ci}
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_ci/**
297562306a36Sopenharmony_ci * megasas_build_ld_nonrw_fusion - prepares non rw ios for virtual disk
297662306a36Sopenharmony_ci * @instance:		Adapter soft state
297762306a36Sopenharmony_ci * @scmd:		SCSI command
297862306a36Sopenharmony_ci * @cmd:		Command to be prepared
297962306a36Sopenharmony_ci *
298062306a36Sopenharmony_ci * Prepares the io_request frame for non-rw io cmds for vd.
298162306a36Sopenharmony_ci */
298262306a36Sopenharmony_cistatic void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance,
298362306a36Sopenharmony_ci			  struct scsi_cmnd *scmd, struct megasas_cmd_fusion *cmd)
298462306a36Sopenharmony_ci{
298562306a36Sopenharmony_ci	u32 device_id;
298662306a36Sopenharmony_ci	struct MPI2_RAID_SCSI_IO_REQUEST *io_request;
298762306a36Sopenharmony_ci	u16 ld;
298862306a36Sopenharmony_ci	struct MR_DRV_RAID_MAP_ALL *local_map_ptr;
298962306a36Sopenharmony_ci	struct fusion_context *fusion = instance->ctrl_context;
299062306a36Sopenharmony_ci	u8                          span, physArm;
299162306a36Sopenharmony_ci	__le16                      devHandle;
299262306a36Sopenharmony_ci	u32                         arRef, pd;
299362306a36Sopenharmony_ci	struct MR_LD_RAID                  *raid;
299462306a36Sopenharmony_ci	struct RAID_CONTEXT                *pRAID_Context;
299562306a36Sopenharmony_ci	u8 fp_possible = 1;
299662306a36Sopenharmony_ci
299762306a36Sopenharmony_ci	io_request = cmd->io_request;
299862306a36Sopenharmony_ci	device_id = MEGASAS_DEV_INDEX(scmd);
299962306a36Sopenharmony_ci	local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
300062306a36Sopenharmony_ci	io_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
300162306a36Sopenharmony_ci	/* get RAID_Context pointer */
300262306a36Sopenharmony_ci	pRAID_Context = &io_request->RaidContext.raid_context;
300362306a36Sopenharmony_ci	/* Check with FW team */
300462306a36Sopenharmony_ci	pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id);
300562306a36Sopenharmony_ci	pRAID_Context->reg_lock_row_lba    = 0;
300662306a36Sopenharmony_ci	pRAID_Context->reg_lock_length    = 0;
300762306a36Sopenharmony_ci
300862306a36Sopenharmony_ci	if (fusion->fast_path_io && (
300962306a36Sopenharmony_ci		device_id < instance->fw_supported_vd_count)) {
301062306a36Sopenharmony_ci
301162306a36Sopenharmony_ci		ld = MR_TargetIdToLdGet(device_id, local_map_ptr);
301262306a36Sopenharmony_ci		if (ld >= instance->fw_supported_vd_count - 1)
301362306a36Sopenharmony_ci			fp_possible = 0;
301462306a36Sopenharmony_ci		else {
301562306a36Sopenharmony_ci			raid = MR_LdRaidGet(ld, local_map_ptr);
301662306a36Sopenharmony_ci			if (!(raid->capability.fpNonRWCapable))
301762306a36Sopenharmony_ci				fp_possible = 0;
301862306a36Sopenharmony_ci		}
301962306a36Sopenharmony_ci	} else
302062306a36Sopenharmony_ci		fp_possible = 0;
302162306a36Sopenharmony_ci
302262306a36Sopenharmony_ci	if (!fp_possible) {
302362306a36Sopenharmony_ci		io_request->Function  = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
302462306a36Sopenharmony_ci		io_request->DevHandle = cpu_to_le16(device_id);
302562306a36Sopenharmony_ci		io_request->LUN[1] = scmd->device->lun;
302662306a36Sopenharmony_ci		pRAID_Context->timeout_value =
302762306a36Sopenharmony_ci			cpu_to_le16(scsi_cmd_to_rq(scmd)->timeout / HZ);
302862306a36Sopenharmony_ci		cmd->request_desc->SCSIIO.RequestFlags =
302962306a36Sopenharmony_ci			(MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
303062306a36Sopenharmony_ci			MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
303162306a36Sopenharmony_ci	} else {
303262306a36Sopenharmony_ci
303362306a36Sopenharmony_ci		/* set RAID context values */
303462306a36Sopenharmony_ci		pRAID_Context->config_seq_num = raid->seqNum;
303562306a36Sopenharmony_ci		if (instance->adapter_type < VENTURA_SERIES)
303662306a36Sopenharmony_ci			pRAID_Context->reg_lock_flags = REGION_TYPE_SHARED_READ;
303762306a36Sopenharmony_ci		pRAID_Context->timeout_value =
303862306a36Sopenharmony_ci			cpu_to_le16(raid->fpIoTimeoutForLd);
303962306a36Sopenharmony_ci
304062306a36Sopenharmony_ci		/* get the DevHandle for the PD (since this is
304162306a36Sopenharmony_ci		   fpNonRWCapable, this is a single disk RAID0) */
304262306a36Sopenharmony_ci		span = physArm = 0;
304362306a36Sopenharmony_ci		arRef = MR_LdSpanArrayGet(ld, span, local_map_ptr);
304462306a36Sopenharmony_ci		pd = MR_ArPdGet(arRef, physArm, local_map_ptr);
304562306a36Sopenharmony_ci		devHandle = MR_PdDevHandleGet(pd, local_map_ptr);
304662306a36Sopenharmony_ci
304762306a36Sopenharmony_ci		/* build request descriptor */
304862306a36Sopenharmony_ci		cmd->request_desc->SCSIIO.RequestFlags =
304962306a36Sopenharmony_ci			(MPI2_REQ_DESCRIPT_FLAGS_FP_IO <<
305062306a36Sopenharmony_ci			MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
305162306a36Sopenharmony_ci		cmd->request_desc->SCSIIO.DevHandle = devHandle;
305262306a36Sopenharmony_ci
305362306a36Sopenharmony_ci		/* populate the LUN field */
305462306a36Sopenharmony_ci		memcpy(io_request->LUN, raid->LUN, 8);
305562306a36Sopenharmony_ci
305662306a36Sopenharmony_ci		/* build the raidScsiIO structure */
305762306a36Sopenharmony_ci		io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
305862306a36Sopenharmony_ci		io_request->DevHandle = devHandle;
305962306a36Sopenharmony_ci	}
306062306a36Sopenharmony_ci}
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_ci/**
306362306a36Sopenharmony_ci * megasas_build_syspd_fusion - prepares rw/non-rw ios for syspd
306462306a36Sopenharmony_ci * @instance:		Adapter soft state
306562306a36Sopenharmony_ci * @scmd:		SCSI command
306662306a36Sopenharmony_ci * @cmd:		Command to be prepared
306762306a36Sopenharmony_ci * @fp_possible:	parameter to detect fast path or firmware path io.
306862306a36Sopenharmony_ci *
306962306a36Sopenharmony_ci * Prepares the io_request frame for rw/non-rw io cmds for syspds
307062306a36Sopenharmony_ci */
307162306a36Sopenharmony_cistatic void
307262306a36Sopenharmony_cimegasas_build_syspd_fusion(struct megasas_instance *instance,
307362306a36Sopenharmony_ci	struct scsi_cmnd *scmd, struct megasas_cmd_fusion *cmd,
307462306a36Sopenharmony_ci	bool fp_possible)
307562306a36Sopenharmony_ci{
307662306a36Sopenharmony_ci	u32 device_id;
307762306a36Sopenharmony_ci	struct MPI2_RAID_SCSI_IO_REQUEST *io_request;
307862306a36Sopenharmony_ci	u16 pd_index = 0;
307962306a36Sopenharmony_ci	u16 os_timeout_value;
308062306a36Sopenharmony_ci	u16 timeout_limit;
308162306a36Sopenharmony_ci	struct MR_DRV_RAID_MAP_ALL *local_map_ptr;
308262306a36Sopenharmony_ci	struct RAID_CONTEXT	*pRAID_Context;
308362306a36Sopenharmony_ci	struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync;
308462306a36Sopenharmony_ci	struct MR_PRIV_DEVICE *mr_device_priv_data;
308562306a36Sopenharmony_ci	struct fusion_context *fusion = instance->ctrl_context;
308662306a36Sopenharmony_ci	pd_sync = (void *)fusion->pd_seq_sync[(instance->pd_seq_map_id - 1) & 1];
308762306a36Sopenharmony_ci
308862306a36Sopenharmony_ci	device_id = MEGASAS_DEV_INDEX(scmd);
308962306a36Sopenharmony_ci	pd_index = MEGASAS_PD_INDEX(scmd);
309062306a36Sopenharmony_ci	os_timeout_value = scsi_cmd_to_rq(scmd)->timeout / HZ;
309162306a36Sopenharmony_ci	mr_device_priv_data = scmd->device->hostdata;
309262306a36Sopenharmony_ci	cmd->pd_interface = mr_device_priv_data->interface_type;
309362306a36Sopenharmony_ci
309462306a36Sopenharmony_ci	io_request = cmd->io_request;
309562306a36Sopenharmony_ci	/* get RAID_Context pointer */
309662306a36Sopenharmony_ci	pRAID_Context = &io_request->RaidContext.raid_context;
309762306a36Sopenharmony_ci	pRAID_Context->reg_lock_flags = 0;
309862306a36Sopenharmony_ci	pRAID_Context->reg_lock_row_lba = 0;
309962306a36Sopenharmony_ci	pRAID_Context->reg_lock_length = 0;
310062306a36Sopenharmony_ci	io_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
310162306a36Sopenharmony_ci	io_request->LUN[1] = scmd->device->lun;
310262306a36Sopenharmony_ci	pRAID_Context->raid_flags = MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD
310362306a36Sopenharmony_ci		<< MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT;
310462306a36Sopenharmony_ci
310562306a36Sopenharmony_ci	/* If FW supports PD sequence number */
310662306a36Sopenharmony_ci	if (instance->support_seqnum_jbod_fp) {
310762306a36Sopenharmony_ci		if (instance->use_seqnum_jbod_fp &&
310862306a36Sopenharmony_ci			instance->pd_list[pd_index].driveType == TYPE_DISK) {
310962306a36Sopenharmony_ci
311062306a36Sopenharmony_ci			/* More than 256 PD/JBOD support for Ventura */
311162306a36Sopenharmony_ci			if (instance->support_morethan256jbod)
311262306a36Sopenharmony_ci				pRAID_Context->virtual_disk_tgt_id =
311362306a36Sopenharmony_ci					pd_sync->seq[pd_index].pd_target_id;
311462306a36Sopenharmony_ci			else
311562306a36Sopenharmony_ci				pRAID_Context->virtual_disk_tgt_id =
311662306a36Sopenharmony_ci					cpu_to_le16(device_id +
311762306a36Sopenharmony_ci					(MAX_PHYSICAL_DEVICES - 1));
311862306a36Sopenharmony_ci			pRAID_Context->config_seq_num =
311962306a36Sopenharmony_ci				pd_sync->seq[pd_index].seqNum;
312062306a36Sopenharmony_ci			io_request->DevHandle =
312162306a36Sopenharmony_ci				pd_sync->seq[pd_index].devHandle;
312262306a36Sopenharmony_ci			if (instance->adapter_type >= VENTURA_SERIES) {
312362306a36Sopenharmony_ci				io_request->RaidContext.raid_context_g35.routing_flags |=
312462306a36Sopenharmony_ci					(1 << MR_RAID_CTX_ROUTINGFLAGS_SQN_SHIFT);
312562306a36Sopenharmony_ci				io_request->RaidContext.raid_context_g35.nseg_type |=
312662306a36Sopenharmony_ci					(1 << RAID_CONTEXT_NSEG_SHIFT);
312762306a36Sopenharmony_ci				io_request->RaidContext.raid_context_g35.nseg_type |=
312862306a36Sopenharmony_ci					(MPI2_TYPE_CUDA << RAID_CONTEXT_TYPE_SHIFT);
312962306a36Sopenharmony_ci			} else {
313062306a36Sopenharmony_ci				pRAID_Context->type = MPI2_TYPE_CUDA;
313162306a36Sopenharmony_ci				pRAID_Context->nseg = 0x1;
313262306a36Sopenharmony_ci				pRAID_Context->reg_lock_flags |=
313362306a36Sopenharmony_ci					(MR_RL_FLAGS_SEQ_NUM_ENABLE |
313462306a36Sopenharmony_ci					 MR_RL_FLAGS_GRANT_DESTINATION_CUDA);
313562306a36Sopenharmony_ci			}
313662306a36Sopenharmony_ci		} else {
313762306a36Sopenharmony_ci			pRAID_Context->virtual_disk_tgt_id =
313862306a36Sopenharmony_ci				cpu_to_le16(device_id +
313962306a36Sopenharmony_ci				(MAX_PHYSICAL_DEVICES - 1));
314062306a36Sopenharmony_ci			pRAID_Context->config_seq_num = 0;
314162306a36Sopenharmony_ci			io_request->DevHandle = cpu_to_le16(0xFFFF);
314262306a36Sopenharmony_ci		}
314362306a36Sopenharmony_ci	} else {
314462306a36Sopenharmony_ci		pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id);
314562306a36Sopenharmony_ci		pRAID_Context->config_seq_num = 0;
314662306a36Sopenharmony_ci
314762306a36Sopenharmony_ci		if (fusion->fast_path_io) {
314862306a36Sopenharmony_ci			local_map_ptr =
314962306a36Sopenharmony_ci				fusion->ld_drv_map[(instance->map_id & 1)];
315062306a36Sopenharmony_ci			io_request->DevHandle =
315162306a36Sopenharmony_ci				local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
315262306a36Sopenharmony_ci		} else {
315362306a36Sopenharmony_ci			io_request->DevHandle = cpu_to_le16(0xFFFF);
315462306a36Sopenharmony_ci		}
315562306a36Sopenharmony_ci	}
315662306a36Sopenharmony_ci
315762306a36Sopenharmony_ci	cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle;
315862306a36Sopenharmony_ci
315962306a36Sopenharmony_ci	megasas_get_msix_index(instance, scmd, cmd, 1);
316062306a36Sopenharmony_ci
316162306a36Sopenharmony_ci	if (!fp_possible) {
316262306a36Sopenharmony_ci		/* system pd firmware path */
316362306a36Sopenharmony_ci		io_request->Function  = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
316462306a36Sopenharmony_ci		cmd->request_desc->SCSIIO.RequestFlags =
316562306a36Sopenharmony_ci			(MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
316662306a36Sopenharmony_ci				MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
316762306a36Sopenharmony_ci		pRAID_Context->timeout_value = cpu_to_le16(os_timeout_value);
316862306a36Sopenharmony_ci		pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id);
316962306a36Sopenharmony_ci	} else {
317062306a36Sopenharmony_ci		if (os_timeout_value)
317162306a36Sopenharmony_ci			os_timeout_value++;
317262306a36Sopenharmony_ci
317362306a36Sopenharmony_ci		/* system pd Fast Path */
317462306a36Sopenharmony_ci		io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
317562306a36Sopenharmony_ci		timeout_limit = (scmd->device->type == TYPE_DISK) ?
317662306a36Sopenharmony_ci				255 : 0xFFFF;
317762306a36Sopenharmony_ci		pRAID_Context->timeout_value =
317862306a36Sopenharmony_ci			cpu_to_le16((os_timeout_value > timeout_limit) ?
317962306a36Sopenharmony_ci			timeout_limit : os_timeout_value);
318062306a36Sopenharmony_ci		if (instance->adapter_type >= INVADER_SERIES)
318162306a36Sopenharmony_ci			io_request->IoFlags |=
318262306a36Sopenharmony_ci				cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
318362306a36Sopenharmony_ci
318462306a36Sopenharmony_ci		cmd->request_desc->SCSIIO.RequestFlags =
318562306a36Sopenharmony_ci			(MPI2_REQ_DESCRIPT_FLAGS_FP_IO <<
318662306a36Sopenharmony_ci				MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
318762306a36Sopenharmony_ci	}
318862306a36Sopenharmony_ci}
318962306a36Sopenharmony_ci
319062306a36Sopenharmony_ci/**
319162306a36Sopenharmony_ci * megasas_build_io_fusion -	Prepares IOs to devices
319262306a36Sopenharmony_ci * @instance:		Adapter soft state
319362306a36Sopenharmony_ci * @scp:		SCSI command
319462306a36Sopenharmony_ci * @cmd:		Command to be prepared
319562306a36Sopenharmony_ci *
319662306a36Sopenharmony_ci * Invokes helper functions to prepare request frames
319762306a36Sopenharmony_ci * and sets flags appropriate for IO/Non-IO cmd
319862306a36Sopenharmony_ci */
319962306a36Sopenharmony_cistatic int
320062306a36Sopenharmony_cimegasas_build_io_fusion(struct megasas_instance *instance,
320162306a36Sopenharmony_ci			struct scsi_cmnd *scp,
320262306a36Sopenharmony_ci			struct megasas_cmd_fusion *cmd)
320362306a36Sopenharmony_ci{
320462306a36Sopenharmony_ci	int sge_count;
320562306a36Sopenharmony_ci	u16 pd_index = 0;
320662306a36Sopenharmony_ci	u8 drive_type = 0;
320762306a36Sopenharmony_ci	struct MPI2_RAID_SCSI_IO_REQUEST *io_request = cmd->io_request;
320862306a36Sopenharmony_ci	struct MR_PRIV_DEVICE *mr_device_priv_data;
320962306a36Sopenharmony_ci	mr_device_priv_data = scp->device->hostdata;
321062306a36Sopenharmony_ci
321162306a36Sopenharmony_ci	/* Zero out some fields so they don't get reused */
321262306a36Sopenharmony_ci	memset(io_request->LUN, 0x0, 8);
321362306a36Sopenharmony_ci	io_request->CDB.EEDP32.PrimaryReferenceTag = 0;
321462306a36Sopenharmony_ci	io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0;
321562306a36Sopenharmony_ci	io_request->EEDPFlags = 0;
321662306a36Sopenharmony_ci	io_request->Control = 0;
321762306a36Sopenharmony_ci	io_request->EEDPBlockSize = 0;
321862306a36Sopenharmony_ci	io_request->ChainOffset = 0;
321962306a36Sopenharmony_ci	io_request->RaidContext.raid_context.raid_flags = 0;
322062306a36Sopenharmony_ci	io_request->RaidContext.raid_context.type = 0;
322162306a36Sopenharmony_ci	io_request->RaidContext.raid_context.nseg = 0;
322262306a36Sopenharmony_ci
322362306a36Sopenharmony_ci	memcpy(io_request->CDB.CDB32, scp->cmnd, scp->cmd_len);
322462306a36Sopenharmony_ci	/*
322562306a36Sopenharmony_ci	 * Just the CDB length,rest of the Flags are zero
322662306a36Sopenharmony_ci	 * This will be modified for FP in build_ldio_fusion
322762306a36Sopenharmony_ci	 */
322862306a36Sopenharmony_ci	io_request->IoFlags = cpu_to_le16(scp->cmd_len);
322962306a36Sopenharmony_ci
323062306a36Sopenharmony_ci	switch (megasas_cmd_type(scp)) {
323162306a36Sopenharmony_ci	case READ_WRITE_LDIO:
323262306a36Sopenharmony_ci		megasas_build_ldio_fusion(instance, scp, cmd);
323362306a36Sopenharmony_ci		break;
323462306a36Sopenharmony_ci	case NON_READ_WRITE_LDIO:
323562306a36Sopenharmony_ci		megasas_build_ld_nonrw_fusion(instance, scp, cmd);
323662306a36Sopenharmony_ci		break;
323762306a36Sopenharmony_ci	case READ_WRITE_SYSPDIO:
323862306a36Sopenharmony_ci		megasas_build_syspd_fusion(instance, scp, cmd, true);
323962306a36Sopenharmony_ci		break;
324062306a36Sopenharmony_ci	case NON_READ_WRITE_SYSPDIO:
324162306a36Sopenharmony_ci		pd_index = MEGASAS_PD_INDEX(scp);
324262306a36Sopenharmony_ci		drive_type = instance->pd_list[pd_index].driveType;
324362306a36Sopenharmony_ci		if ((instance->secure_jbod_support ||
324462306a36Sopenharmony_ci		     mr_device_priv_data->is_tm_capable) ||
324562306a36Sopenharmony_ci		     (instance->adapter_type >= VENTURA_SERIES &&
324662306a36Sopenharmony_ci		     drive_type == TYPE_ENCLOSURE))
324762306a36Sopenharmony_ci			megasas_build_syspd_fusion(instance, scp, cmd, false);
324862306a36Sopenharmony_ci		else
324962306a36Sopenharmony_ci			megasas_build_syspd_fusion(instance, scp, cmd, true);
325062306a36Sopenharmony_ci		break;
325162306a36Sopenharmony_ci	default:
325262306a36Sopenharmony_ci		break;
325362306a36Sopenharmony_ci	}
325462306a36Sopenharmony_ci
325562306a36Sopenharmony_ci	/*
325662306a36Sopenharmony_ci	 * Construct SGL
325762306a36Sopenharmony_ci	 */
325862306a36Sopenharmony_ci
325962306a36Sopenharmony_ci	sge_count = megasas_make_sgl(instance, scp, cmd);
326062306a36Sopenharmony_ci
326162306a36Sopenharmony_ci	if (sge_count > instance->max_num_sge || (sge_count < 0)) {
326262306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
326362306a36Sopenharmony_ci			"%s %d sge_count (%d) is out of range. Range is:  0-%d\n",
326462306a36Sopenharmony_ci			__func__, __LINE__, sge_count, instance->max_num_sge);
326562306a36Sopenharmony_ci		return 1;
326662306a36Sopenharmony_ci	}
326762306a36Sopenharmony_ci
326862306a36Sopenharmony_ci	if (instance->adapter_type >= VENTURA_SERIES) {
326962306a36Sopenharmony_ci		set_num_sge(&io_request->RaidContext.raid_context_g35, sge_count);
327062306a36Sopenharmony_ci		cpu_to_le16s(&io_request->RaidContext.raid_context_g35.routing_flags);
327162306a36Sopenharmony_ci		cpu_to_le16s(&io_request->RaidContext.raid_context_g35.nseg_type);
327262306a36Sopenharmony_ci	} else {
327362306a36Sopenharmony_ci		/* numSGE store lower 8 bit of sge_count.
327462306a36Sopenharmony_ci		 * numSGEExt store higher 8 bit of sge_count
327562306a36Sopenharmony_ci		 */
327662306a36Sopenharmony_ci		io_request->RaidContext.raid_context.num_sge = sge_count;
327762306a36Sopenharmony_ci		io_request->RaidContext.raid_context.num_sge_ext =
327862306a36Sopenharmony_ci			(u8)(sge_count >> 8);
327962306a36Sopenharmony_ci	}
328062306a36Sopenharmony_ci
328162306a36Sopenharmony_ci	io_request->SGLFlags = cpu_to_le16(MPI2_SGE_FLAGS_64_BIT_ADDRESSING);
328262306a36Sopenharmony_ci
328362306a36Sopenharmony_ci	if (scp->sc_data_direction == DMA_TO_DEVICE)
328462306a36Sopenharmony_ci		io_request->Control |= cpu_to_le32(MPI2_SCSIIO_CONTROL_WRITE);
328562306a36Sopenharmony_ci	else if (scp->sc_data_direction == DMA_FROM_DEVICE)
328662306a36Sopenharmony_ci		io_request->Control |= cpu_to_le32(MPI2_SCSIIO_CONTROL_READ);
328762306a36Sopenharmony_ci
328862306a36Sopenharmony_ci	io_request->SGLOffset0 =
328962306a36Sopenharmony_ci		offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL) / 4;
329062306a36Sopenharmony_ci
329162306a36Sopenharmony_ci	io_request->SenseBufferLowAddress =
329262306a36Sopenharmony_ci		cpu_to_le32(lower_32_bits(cmd->sense_phys_addr));
329362306a36Sopenharmony_ci	io_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
329462306a36Sopenharmony_ci
329562306a36Sopenharmony_ci	cmd->scmd = scp;
329662306a36Sopenharmony_ci	megasas_priv(scp)->cmd_priv = cmd;
329762306a36Sopenharmony_ci
329862306a36Sopenharmony_ci	return 0;
329962306a36Sopenharmony_ci}
330062306a36Sopenharmony_ci
330162306a36Sopenharmony_cistatic union MEGASAS_REQUEST_DESCRIPTOR_UNION *
330262306a36Sopenharmony_cimegasas_get_request_descriptor(struct megasas_instance *instance, u16 index)
330362306a36Sopenharmony_ci{
330462306a36Sopenharmony_ci	u8 *p;
330562306a36Sopenharmony_ci	struct fusion_context *fusion;
330662306a36Sopenharmony_ci
330762306a36Sopenharmony_ci	fusion = instance->ctrl_context;
330862306a36Sopenharmony_ci	p = fusion->req_frames_desc +
330962306a36Sopenharmony_ci		sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) * index;
331062306a36Sopenharmony_ci
331162306a36Sopenharmony_ci	return (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)p;
331262306a36Sopenharmony_ci}
331362306a36Sopenharmony_ci
331462306a36Sopenharmony_ci
331562306a36Sopenharmony_ci/* megasas_prepate_secondRaid1_IO
331662306a36Sopenharmony_ci *  It prepares the raid 1 second IO
331762306a36Sopenharmony_ci */
331862306a36Sopenharmony_cistatic void megasas_prepare_secondRaid1_IO(struct megasas_instance *instance,
331962306a36Sopenharmony_ci					   struct megasas_cmd_fusion *cmd,
332062306a36Sopenharmony_ci					   struct megasas_cmd_fusion *r1_cmd)
332162306a36Sopenharmony_ci{
332262306a36Sopenharmony_ci	union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc, *req_desc2 = NULL;
332362306a36Sopenharmony_ci	struct fusion_context *fusion;
332462306a36Sopenharmony_ci	fusion = instance->ctrl_context;
332562306a36Sopenharmony_ci	req_desc = cmd->request_desc;
332662306a36Sopenharmony_ci	/* copy the io request frame as well as 8 SGEs data for r1 command*/
332762306a36Sopenharmony_ci	memcpy(r1_cmd->io_request, cmd->io_request,
332862306a36Sopenharmony_ci	       (sizeof(struct MPI2_RAID_SCSI_IO_REQUEST)));
332962306a36Sopenharmony_ci	memcpy(r1_cmd->io_request->SGLs, cmd->io_request->SGLs,
333062306a36Sopenharmony_ci	       (fusion->max_sge_in_main_msg * sizeof(union MPI2_SGE_IO_UNION)));
333162306a36Sopenharmony_ci	/*sense buffer is different for r1 command*/
333262306a36Sopenharmony_ci	r1_cmd->io_request->SenseBufferLowAddress =
333362306a36Sopenharmony_ci			cpu_to_le32(lower_32_bits(r1_cmd->sense_phys_addr));
333462306a36Sopenharmony_ci	r1_cmd->scmd = cmd->scmd;
333562306a36Sopenharmony_ci	req_desc2 = megasas_get_request_descriptor(instance,
333662306a36Sopenharmony_ci						   (r1_cmd->index - 1));
333762306a36Sopenharmony_ci	req_desc2->Words = 0;
333862306a36Sopenharmony_ci	r1_cmd->request_desc = req_desc2;
333962306a36Sopenharmony_ci	req_desc2->SCSIIO.SMID = cpu_to_le16(r1_cmd->index);
334062306a36Sopenharmony_ci	req_desc2->SCSIIO.RequestFlags = req_desc->SCSIIO.RequestFlags;
334162306a36Sopenharmony_ci	r1_cmd->request_desc->SCSIIO.DevHandle = cmd->r1_alt_dev_handle;
334262306a36Sopenharmony_ci	r1_cmd->io_request->DevHandle = cmd->r1_alt_dev_handle;
334362306a36Sopenharmony_ci	r1_cmd->r1_alt_dev_handle = cmd->io_request->DevHandle;
334462306a36Sopenharmony_ci	cmd->io_request->RaidContext.raid_context_g35.flow_specific.peer_smid =
334562306a36Sopenharmony_ci			cpu_to_le16(r1_cmd->index);
334662306a36Sopenharmony_ci	r1_cmd->io_request->RaidContext.raid_context_g35.flow_specific.peer_smid =
334762306a36Sopenharmony_ci			cpu_to_le16(cmd->index);
334862306a36Sopenharmony_ci	/*MSIxIndex of both commands request descriptors should be same*/
334962306a36Sopenharmony_ci	r1_cmd->request_desc->SCSIIO.MSIxIndex =
335062306a36Sopenharmony_ci			cmd->request_desc->SCSIIO.MSIxIndex;
335162306a36Sopenharmony_ci	/*span arm is different for r1 cmd*/
335262306a36Sopenharmony_ci	r1_cmd->io_request->RaidContext.raid_context_g35.span_arm =
335362306a36Sopenharmony_ci			cmd->io_request->RaidContext.raid_context_g35.span_arm + 1;
335462306a36Sopenharmony_ci}
335562306a36Sopenharmony_ci
335662306a36Sopenharmony_ci/**
335762306a36Sopenharmony_ci * megasas_build_and_issue_cmd_fusion -Main routine for building and
335862306a36Sopenharmony_ci *                                     issuing non IOCTL cmd
335962306a36Sopenharmony_ci * @instance:			Adapter soft state
336062306a36Sopenharmony_ci * @scmd:			pointer to scsi cmd from OS
336162306a36Sopenharmony_ci */
336262306a36Sopenharmony_cistatic u32
336362306a36Sopenharmony_cimegasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
336462306a36Sopenharmony_ci				   struct scsi_cmnd *scmd)
336562306a36Sopenharmony_ci{
336662306a36Sopenharmony_ci	struct megasas_cmd_fusion *cmd, *r1_cmd = NULL;
336762306a36Sopenharmony_ci	union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
336862306a36Sopenharmony_ci	u32 index;
336962306a36Sopenharmony_ci
337062306a36Sopenharmony_ci	if ((megasas_cmd_type(scmd) == READ_WRITE_LDIO) &&
337162306a36Sopenharmony_ci		instance->ldio_threshold &&
337262306a36Sopenharmony_ci		(atomic_inc_return(&instance->ldio_outstanding) >
337362306a36Sopenharmony_ci		instance->ldio_threshold)) {
337462306a36Sopenharmony_ci		atomic_dec(&instance->ldio_outstanding);
337562306a36Sopenharmony_ci		return SCSI_MLQUEUE_DEVICE_BUSY;
337662306a36Sopenharmony_ci	}
337762306a36Sopenharmony_ci
337862306a36Sopenharmony_ci	if (atomic_inc_return(&instance->fw_outstanding) >
337962306a36Sopenharmony_ci			instance->host->can_queue) {
338062306a36Sopenharmony_ci		atomic_dec(&instance->fw_outstanding);
338162306a36Sopenharmony_ci		return SCSI_MLQUEUE_HOST_BUSY;
338262306a36Sopenharmony_ci	}
338362306a36Sopenharmony_ci
338462306a36Sopenharmony_ci	cmd = megasas_get_cmd_fusion(instance, scsi_cmd_to_rq(scmd)->tag);
338562306a36Sopenharmony_ci
338662306a36Sopenharmony_ci	if (!cmd) {
338762306a36Sopenharmony_ci		atomic_dec(&instance->fw_outstanding);
338862306a36Sopenharmony_ci		return SCSI_MLQUEUE_HOST_BUSY;
338962306a36Sopenharmony_ci	}
339062306a36Sopenharmony_ci
339162306a36Sopenharmony_ci	index = cmd->index;
339262306a36Sopenharmony_ci
339362306a36Sopenharmony_ci	req_desc = megasas_get_request_descriptor(instance, index-1);
339462306a36Sopenharmony_ci
339562306a36Sopenharmony_ci	req_desc->Words = 0;
339662306a36Sopenharmony_ci	cmd->request_desc = req_desc;
339762306a36Sopenharmony_ci
339862306a36Sopenharmony_ci	if (megasas_build_io_fusion(instance, scmd, cmd)) {
339962306a36Sopenharmony_ci		megasas_return_cmd_fusion(instance, cmd);
340062306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "Error building command\n");
340162306a36Sopenharmony_ci		cmd->request_desc = NULL;
340262306a36Sopenharmony_ci		atomic_dec(&instance->fw_outstanding);
340362306a36Sopenharmony_ci		return SCSI_MLQUEUE_HOST_BUSY;
340462306a36Sopenharmony_ci	}
340562306a36Sopenharmony_ci
340662306a36Sopenharmony_ci	req_desc = cmd->request_desc;
340762306a36Sopenharmony_ci	req_desc->SCSIIO.SMID = cpu_to_le16(index);
340862306a36Sopenharmony_ci
340962306a36Sopenharmony_ci	if (cmd->io_request->ChainOffset != 0 &&
341062306a36Sopenharmony_ci	    cmd->io_request->ChainOffset != 0xF)
341162306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "The chain offset value is not "
341262306a36Sopenharmony_ci		       "correct : %x\n", cmd->io_request->ChainOffset);
341362306a36Sopenharmony_ci	/*
341462306a36Sopenharmony_ci	 *	if it is raid 1/10 fp write capable.
341562306a36Sopenharmony_ci	 *	try to get second command from pool and construct it.
341662306a36Sopenharmony_ci	 *	From FW, it has confirmed that lba values of two PDs
341762306a36Sopenharmony_ci	 *	corresponds to single R1/10 LD are always same
341862306a36Sopenharmony_ci	 *
341962306a36Sopenharmony_ci	 */
342062306a36Sopenharmony_ci	/*	driver side count always should be less than max_fw_cmds
342162306a36Sopenharmony_ci	 *	to get new command
342262306a36Sopenharmony_ci	 */
342362306a36Sopenharmony_ci	if (cmd->r1_alt_dev_handle != MR_DEVHANDLE_INVALID) {
342462306a36Sopenharmony_ci		r1_cmd = megasas_get_cmd_fusion(instance,
342562306a36Sopenharmony_ci				scsi_cmd_to_rq(scmd)->tag + instance->max_fw_cmds);
342662306a36Sopenharmony_ci		megasas_prepare_secondRaid1_IO(instance, cmd, r1_cmd);
342762306a36Sopenharmony_ci	}
342862306a36Sopenharmony_ci
342962306a36Sopenharmony_ci
343062306a36Sopenharmony_ci	/*
343162306a36Sopenharmony_ci	 * Issue the command to the FW
343262306a36Sopenharmony_ci	 */
343362306a36Sopenharmony_ci
343462306a36Sopenharmony_ci	megasas_sdev_busy_inc(instance, scmd);
343562306a36Sopenharmony_ci	megasas_fire_cmd_fusion(instance, req_desc);
343662306a36Sopenharmony_ci
343762306a36Sopenharmony_ci	if (r1_cmd)
343862306a36Sopenharmony_ci		megasas_fire_cmd_fusion(instance, r1_cmd->request_desc);
343962306a36Sopenharmony_ci
344062306a36Sopenharmony_ci
344162306a36Sopenharmony_ci	return 0;
344262306a36Sopenharmony_ci}
344362306a36Sopenharmony_ci
344462306a36Sopenharmony_ci/**
344562306a36Sopenharmony_ci * megasas_complete_r1_command -
344662306a36Sopenharmony_ci * completes R1 FP write commands which has valid peer smid
344762306a36Sopenharmony_ci * @instance:			Adapter soft state
344862306a36Sopenharmony_ci * @cmd:			MPT command frame
344962306a36Sopenharmony_ci *
345062306a36Sopenharmony_ci */
345162306a36Sopenharmony_cistatic inline void
345262306a36Sopenharmony_cimegasas_complete_r1_command(struct megasas_instance *instance,
345362306a36Sopenharmony_ci			    struct megasas_cmd_fusion *cmd)
345462306a36Sopenharmony_ci{
345562306a36Sopenharmony_ci	u8 *sense, status, ex_status;
345662306a36Sopenharmony_ci	u32 data_length;
345762306a36Sopenharmony_ci	u16 peer_smid;
345862306a36Sopenharmony_ci	struct fusion_context *fusion;
345962306a36Sopenharmony_ci	struct megasas_cmd_fusion *r1_cmd = NULL;
346062306a36Sopenharmony_ci	struct scsi_cmnd *scmd_local = NULL;
346162306a36Sopenharmony_ci	struct RAID_CONTEXT_G35 *rctx_g35;
346262306a36Sopenharmony_ci
346362306a36Sopenharmony_ci	rctx_g35 = &cmd->io_request->RaidContext.raid_context_g35;
346462306a36Sopenharmony_ci	fusion = instance->ctrl_context;
346562306a36Sopenharmony_ci	peer_smid = le16_to_cpu(rctx_g35->flow_specific.peer_smid);
346662306a36Sopenharmony_ci
346762306a36Sopenharmony_ci	r1_cmd = fusion->cmd_list[peer_smid - 1];
346862306a36Sopenharmony_ci	scmd_local = cmd->scmd;
346962306a36Sopenharmony_ci	status = rctx_g35->status;
347062306a36Sopenharmony_ci	ex_status = rctx_g35->ex_status;
347162306a36Sopenharmony_ci	data_length = cmd->io_request->DataLength;
347262306a36Sopenharmony_ci	sense = cmd->sense;
347362306a36Sopenharmony_ci
347462306a36Sopenharmony_ci	cmd->cmd_completed = true;
347562306a36Sopenharmony_ci
347662306a36Sopenharmony_ci	/* Check if peer command is completed or not*/
347762306a36Sopenharmony_ci	if (r1_cmd->cmd_completed) {
347862306a36Sopenharmony_ci		rctx_g35 = &r1_cmd->io_request->RaidContext.raid_context_g35;
347962306a36Sopenharmony_ci		if (rctx_g35->status != MFI_STAT_OK) {
348062306a36Sopenharmony_ci			status = rctx_g35->status;
348162306a36Sopenharmony_ci			ex_status = rctx_g35->ex_status;
348262306a36Sopenharmony_ci			data_length = r1_cmd->io_request->DataLength;
348362306a36Sopenharmony_ci			sense = r1_cmd->sense;
348462306a36Sopenharmony_ci		}
348562306a36Sopenharmony_ci
348662306a36Sopenharmony_ci		megasas_return_cmd_fusion(instance, r1_cmd);
348762306a36Sopenharmony_ci		map_cmd_status(fusion, scmd_local, status, ex_status,
348862306a36Sopenharmony_ci			       le32_to_cpu(data_length), sense);
348962306a36Sopenharmony_ci		if (instance->ldio_threshold &&
349062306a36Sopenharmony_ci		    megasas_cmd_type(scmd_local) == READ_WRITE_LDIO)
349162306a36Sopenharmony_ci			atomic_dec(&instance->ldio_outstanding);
349262306a36Sopenharmony_ci		megasas_priv(scmd_local)->cmd_priv = NULL;
349362306a36Sopenharmony_ci		megasas_return_cmd_fusion(instance, cmd);
349462306a36Sopenharmony_ci		scsi_dma_unmap(scmd_local);
349562306a36Sopenharmony_ci		megasas_sdev_busy_dec(instance, scmd_local);
349662306a36Sopenharmony_ci		scsi_done(scmd_local);
349762306a36Sopenharmony_ci	}
349862306a36Sopenharmony_ci}
349962306a36Sopenharmony_ci
350062306a36Sopenharmony_ci/**
350162306a36Sopenharmony_ci * access_irq_context:		Access to reply processing
350262306a36Sopenharmony_ci * @irq_context:		IRQ context
350362306a36Sopenharmony_ci *
350462306a36Sopenharmony_ci * Synchronize access to reply processing.
350562306a36Sopenharmony_ci *
350662306a36Sopenharmony_ci * Return:  true on success, false on failure.
350762306a36Sopenharmony_ci */
350862306a36Sopenharmony_cistatic inline
350962306a36Sopenharmony_cibool access_irq_context(struct megasas_irq_context  *irq_context)
351062306a36Sopenharmony_ci{
351162306a36Sopenharmony_ci	if (!irq_context)
351262306a36Sopenharmony_ci		return true;
351362306a36Sopenharmony_ci
351462306a36Sopenharmony_ci	if (atomic_add_unless(&irq_context->in_used, 1, 1))
351562306a36Sopenharmony_ci		return true;
351662306a36Sopenharmony_ci
351762306a36Sopenharmony_ci	return false;
351862306a36Sopenharmony_ci}
351962306a36Sopenharmony_ci
352062306a36Sopenharmony_ci/**
352162306a36Sopenharmony_ci * release_irq_context:		Release reply processing
352262306a36Sopenharmony_ci * @irq_context:		IRQ context
352362306a36Sopenharmony_ci *
352462306a36Sopenharmony_ci * Release access of reply processing.
352562306a36Sopenharmony_ci *
352662306a36Sopenharmony_ci * Return: Nothing.
352762306a36Sopenharmony_ci */
352862306a36Sopenharmony_cistatic inline
352962306a36Sopenharmony_civoid release_irq_context(struct megasas_irq_context  *irq_context)
353062306a36Sopenharmony_ci{
353162306a36Sopenharmony_ci	if (irq_context)
353262306a36Sopenharmony_ci		atomic_dec(&irq_context->in_used);
353362306a36Sopenharmony_ci}
353462306a36Sopenharmony_ci
353562306a36Sopenharmony_ci/**
353662306a36Sopenharmony_ci * complete_cmd_fusion -	Completes command
353762306a36Sopenharmony_ci * @instance:			Adapter soft state
353862306a36Sopenharmony_ci * @MSIxIndex:			MSI number
353962306a36Sopenharmony_ci * @irq_context:		IRQ context
354062306a36Sopenharmony_ci *
354162306a36Sopenharmony_ci * Completes all commands that is in reply descriptor queue
354262306a36Sopenharmony_ci */
354362306a36Sopenharmony_cistatic int
354462306a36Sopenharmony_cicomplete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex,
354562306a36Sopenharmony_ci		    struct megasas_irq_context *irq_context)
354662306a36Sopenharmony_ci{
354762306a36Sopenharmony_ci	union MPI2_REPLY_DESCRIPTORS_UNION *desc;
354862306a36Sopenharmony_ci	struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *reply_desc;
354962306a36Sopenharmony_ci	struct MPI2_RAID_SCSI_IO_REQUEST *scsi_io_req;
355062306a36Sopenharmony_ci	struct fusion_context *fusion;
355162306a36Sopenharmony_ci	struct megasas_cmd *cmd_mfi;
355262306a36Sopenharmony_ci	struct megasas_cmd_fusion *cmd_fusion;
355362306a36Sopenharmony_ci	u16 smid, num_completed;
355462306a36Sopenharmony_ci	u8 reply_descript_type, *sense, status, extStatus;
355562306a36Sopenharmony_ci	u32 device_id, data_length;
355662306a36Sopenharmony_ci	union desc_value d_val;
355762306a36Sopenharmony_ci	struct LD_LOAD_BALANCE_INFO *lbinfo;
355862306a36Sopenharmony_ci	int threshold_reply_count = 0;
355962306a36Sopenharmony_ci	struct scsi_cmnd *scmd_local = NULL;
356062306a36Sopenharmony_ci	struct MR_TASK_MANAGE_REQUEST *mr_tm_req;
356162306a36Sopenharmony_ci	struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_tm_req;
356262306a36Sopenharmony_ci
356362306a36Sopenharmony_ci	fusion = instance->ctrl_context;
356462306a36Sopenharmony_ci
356562306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
356662306a36Sopenharmony_ci		return IRQ_HANDLED;
356762306a36Sopenharmony_ci
356862306a36Sopenharmony_ci	if (!access_irq_context(irq_context))
356962306a36Sopenharmony_ci		return 0;
357062306a36Sopenharmony_ci
357162306a36Sopenharmony_ci	desc = fusion->reply_frames_desc[MSIxIndex] +
357262306a36Sopenharmony_ci				fusion->last_reply_idx[MSIxIndex];
357362306a36Sopenharmony_ci
357462306a36Sopenharmony_ci	reply_desc = (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc;
357562306a36Sopenharmony_ci
357662306a36Sopenharmony_ci	d_val.word = desc->Words;
357762306a36Sopenharmony_ci
357862306a36Sopenharmony_ci	reply_descript_type = reply_desc->ReplyFlags &
357962306a36Sopenharmony_ci		MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
358062306a36Sopenharmony_ci
358162306a36Sopenharmony_ci	if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) {
358262306a36Sopenharmony_ci		release_irq_context(irq_context);
358362306a36Sopenharmony_ci		return IRQ_NONE;
358462306a36Sopenharmony_ci	}
358562306a36Sopenharmony_ci
358662306a36Sopenharmony_ci	num_completed = 0;
358762306a36Sopenharmony_ci
358862306a36Sopenharmony_ci	while (d_val.u.low != cpu_to_le32(UINT_MAX) &&
358962306a36Sopenharmony_ci	       d_val.u.high != cpu_to_le32(UINT_MAX)) {
359062306a36Sopenharmony_ci
359162306a36Sopenharmony_ci		smid = le16_to_cpu(reply_desc->SMID);
359262306a36Sopenharmony_ci		cmd_fusion = fusion->cmd_list[smid - 1];
359362306a36Sopenharmony_ci		scsi_io_req = (struct MPI2_RAID_SCSI_IO_REQUEST *)
359462306a36Sopenharmony_ci						cmd_fusion->io_request;
359562306a36Sopenharmony_ci
359662306a36Sopenharmony_ci		scmd_local = cmd_fusion->scmd;
359762306a36Sopenharmony_ci		status = scsi_io_req->RaidContext.raid_context.status;
359862306a36Sopenharmony_ci		extStatus = scsi_io_req->RaidContext.raid_context.ex_status;
359962306a36Sopenharmony_ci		sense = cmd_fusion->sense;
360062306a36Sopenharmony_ci		data_length = scsi_io_req->DataLength;
360162306a36Sopenharmony_ci
360262306a36Sopenharmony_ci		switch (scsi_io_req->Function) {
360362306a36Sopenharmony_ci		case MPI2_FUNCTION_SCSI_TASK_MGMT:
360462306a36Sopenharmony_ci			mr_tm_req = (struct MR_TASK_MANAGE_REQUEST *)
360562306a36Sopenharmony_ci						cmd_fusion->io_request;
360662306a36Sopenharmony_ci			mpi_tm_req = (struct MPI2_SCSI_TASK_MANAGE_REQUEST *)
360762306a36Sopenharmony_ci						&mr_tm_req->TmRequest;
360862306a36Sopenharmony_ci			dev_dbg(&instance->pdev->dev, "TM completion:"
360962306a36Sopenharmony_ci				"type: 0x%x TaskMID: 0x%x\n",
361062306a36Sopenharmony_ci				mpi_tm_req->TaskType, mpi_tm_req->TaskMID);
361162306a36Sopenharmony_ci			complete(&cmd_fusion->done);
361262306a36Sopenharmony_ci			break;
361362306a36Sopenharmony_ci		case MPI2_FUNCTION_SCSI_IO_REQUEST:  /*Fast Path IO.*/
361462306a36Sopenharmony_ci			/* Update load balancing info */
361562306a36Sopenharmony_ci			if (fusion->load_balance_info &&
361662306a36Sopenharmony_ci			    (megasas_priv(cmd_fusion->scmd)->status &
361762306a36Sopenharmony_ci			    MEGASAS_LOAD_BALANCE_FLAG)) {
361862306a36Sopenharmony_ci				device_id = MEGASAS_DEV_INDEX(scmd_local);
361962306a36Sopenharmony_ci				lbinfo = &fusion->load_balance_info[device_id];
362062306a36Sopenharmony_ci				atomic_dec(&lbinfo->scsi_pending_cmds[cmd_fusion->pd_r1_lb]);
362162306a36Sopenharmony_ci				megasas_priv(cmd_fusion->scmd)->status &=
362262306a36Sopenharmony_ci					~MEGASAS_LOAD_BALANCE_FLAG;
362362306a36Sopenharmony_ci			}
362462306a36Sopenharmony_ci			fallthrough;	/* and complete IO */
362562306a36Sopenharmony_ci		case MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST: /* LD-IO Path */
362662306a36Sopenharmony_ci			atomic_dec(&instance->fw_outstanding);
362762306a36Sopenharmony_ci			if (cmd_fusion->r1_alt_dev_handle == MR_DEVHANDLE_INVALID) {
362862306a36Sopenharmony_ci				map_cmd_status(fusion, scmd_local, status,
362962306a36Sopenharmony_ci					       extStatus, le32_to_cpu(data_length),
363062306a36Sopenharmony_ci					       sense);
363162306a36Sopenharmony_ci				if (instance->ldio_threshold &&
363262306a36Sopenharmony_ci				    (megasas_cmd_type(scmd_local) == READ_WRITE_LDIO))
363362306a36Sopenharmony_ci					atomic_dec(&instance->ldio_outstanding);
363462306a36Sopenharmony_ci				megasas_priv(scmd_local)->cmd_priv = NULL;
363562306a36Sopenharmony_ci				megasas_return_cmd_fusion(instance, cmd_fusion);
363662306a36Sopenharmony_ci				scsi_dma_unmap(scmd_local);
363762306a36Sopenharmony_ci				megasas_sdev_busy_dec(instance, scmd_local);
363862306a36Sopenharmony_ci				scsi_done(scmd_local);
363962306a36Sopenharmony_ci			} else	/* Optimal VD - R1 FP command completion. */
364062306a36Sopenharmony_ci				megasas_complete_r1_command(instance, cmd_fusion);
364162306a36Sopenharmony_ci			break;
364262306a36Sopenharmony_ci		case MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST: /*MFI command */
364362306a36Sopenharmony_ci			cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx];
364462306a36Sopenharmony_ci			/* Poll mode. Dummy free.
364562306a36Sopenharmony_ci			 * In case of Interrupt mode, caller has reverse check.
364662306a36Sopenharmony_ci			 */
364762306a36Sopenharmony_ci			if (cmd_mfi->flags & DRV_DCMD_POLLED_MODE) {
364862306a36Sopenharmony_ci				cmd_mfi->flags &= ~DRV_DCMD_POLLED_MODE;
364962306a36Sopenharmony_ci				megasas_return_cmd(instance, cmd_mfi);
365062306a36Sopenharmony_ci			} else
365162306a36Sopenharmony_ci				megasas_complete_cmd(instance, cmd_mfi, DID_OK);
365262306a36Sopenharmony_ci			break;
365362306a36Sopenharmony_ci		}
365462306a36Sopenharmony_ci
365562306a36Sopenharmony_ci		fusion->last_reply_idx[MSIxIndex]++;
365662306a36Sopenharmony_ci		if (fusion->last_reply_idx[MSIxIndex] >=
365762306a36Sopenharmony_ci		    fusion->reply_q_depth)
365862306a36Sopenharmony_ci			fusion->last_reply_idx[MSIxIndex] = 0;
365962306a36Sopenharmony_ci
366062306a36Sopenharmony_ci		desc->Words = cpu_to_le64(ULLONG_MAX);
366162306a36Sopenharmony_ci		num_completed++;
366262306a36Sopenharmony_ci		threshold_reply_count++;
366362306a36Sopenharmony_ci
366462306a36Sopenharmony_ci		/* Get the next reply descriptor */
366562306a36Sopenharmony_ci		if (!fusion->last_reply_idx[MSIxIndex])
366662306a36Sopenharmony_ci			desc = fusion->reply_frames_desc[MSIxIndex];
366762306a36Sopenharmony_ci		else
366862306a36Sopenharmony_ci			desc++;
366962306a36Sopenharmony_ci
367062306a36Sopenharmony_ci		reply_desc =
367162306a36Sopenharmony_ci		  (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc;
367262306a36Sopenharmony_ci
367362306a36Sopenharmony_ci		d_val.word = desc->Words;
367462306a36Sopenharmony_ci
367562306a36Sopenharmony_ci		reply_descript_type = reply_desc->ReplyFlags &
367662306a36Sopenharmony_ci			MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
367762306a36Sopenharmony_ci
367862306a36Sopenharmony_ci		if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
367962306a36Sopenharmony_ci			break;
368062306a36Sopenharmony_ci		/*
368162306a36Sopenharmony_ci		 * Write to reply post host index register after completing threshold
368262306a36Sopenharmony_ci		 * number of reply counts and still there are more replies in reply queue
368362306a36Sopenharmony_ci		 * pending to be completed
368462306a36Sopenharmony_ci		 */
368562306a36Sopenharmony_ci		if (threshold_reply_count >= instance->threshold_reply_count) {
368662306a36Sopenharmony_ci			if (instance->msix_combined)
368762306a36Sopenharmony_ci				writel(((MSIxIndex & 0x7) << 24) |
368862306a36Sopenharmony_ci					fusion->last_reply_idx[MSIxIndex],
368962306a36Sopenharmony_ci					instance->reply_post_host_index_addr[MSIxIndex/8]);
369062306a36Sopenharmony_ci			else
369162306a36Sopenharmony_ci				writel((MSIxIndex << 24) |
369262306a36Sopenharmony_ci					fusion->last_reply_idx[MSIxIndex],
369362306a36Sopenharmony_ci					instance->reply_post_host_index_addr[0]);
369462306a36Sopenharmony_ci			threshold_reply_count = 0;
369562306a36Sopenharmony_ci			if (irq_context) {
369662306a36Sopenharmony_ci				if (!irq_context->irq_poll_scheduled) {
369762306a36Sopenharmony_ci					irq_context->irq_poll_scheduled = true;
369862306a36Sopenharmony_ci					irq_context->irq_line_enable = true;
369962306a36Sopenharmony_ci					irq_poll_sched(&irq_context->irqpoll);
370062306a36Sopenharmony_ci				}
370162306a36Sopenharmony_ci				release_irq_context(irq_context);
370262306a36Sopenharmony_ci				return num_completed;
370362306a36Sopenharmony_ci			}
370462306a36Sopenharmony_ci		}
370562306a36Sopenharmony_ci	}
370662306a36Sopenharmony_ci
370762306a36Sopenharmony_ci	if (num_completed) {
370862306a36Sopenharmony_ci		wmb();
370962306a36Sopenharmony_ci		if (instance->msix_combined)
371062306a36Sopenharmony_ci			writel(((MSIxIndex & 0x7) << 24) |
371162306a36Sopenharmony_ci				fusion->last_reply_idx[MSIxIndex],
371262306a36Sopenharmony_ci				instance->reply_post_host_index_addr[MSIxIndex/8]);
371362306a36Sopenharmony_ci		else
371462306a36Sopenharmony_ci			writel((MSIxIndex << 24) |
371562306a36Sopenharmony_ci				fusion->last_reply_idx[MSIxIndex],
371662306a36Sopenharmony_ci				instance->reply_post_host_index_addr[0]);
371762306a36Sopenharmony_ci		megasas_check_and_restore_queue_depth(instance);
371862306a36Sopenharmony_ci	}
371962306a36Sopenharmony_ci
372062306a36Sopenharmony_ci	release_irq_context(irq_context);
372162306a36Sopenharmony_ci
372262306a36Sopenharmony_ci	return num_completed;
372362306a36Sopenharmony_ci}
372462306a36Sopenharmony_ci
372562306a36Sopenharmony_ciint megasas_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
372662306a36Sopenharmony_ci{
372762306a36Sopenharmony_ci
372862306a36Sopenharmony_ci	struct megasas_instance *instance;
372962306a36Sopenharmony_ci	int num_entries = 0;
373062306a36Sopenharmony_ci	struct fusion_context *fusion;
373162306a36Sopenharmony_ci
373262306a36Sopenharmony_ci	instance = (struct megasas_instance *)shost->hostdata;
373362306a36Sopenharmony_ci
373462306a36Sopenharmony_ci	fusion = instance->ctrl_context;
373562306a36Sopenharmony_ci
373662306a36Sopenharmony_ci	queue_num = queue_num + instance->low_latency_index_start;
373762306a36Sopenharmony_ci
373862306a36Sopenharmony_ci	if (!atomic_add_unless(&fusion->busy_mq_poll[queue_num], 1, 1))
373962306a36Sopenharmony_ci		return 0;
374062306a36Sopenharmony_ci
374162306a36Sopenharmony_ci	num_entries = complete_cmd_fusion(instance, queue_num, NULL);
374262306a36Sopenharmony_ci	atomic_dec(&fusion->busy_mq_poll[queue_num]);
374362306a36Sopenharmony_ci
374462306a36Sopenharmony_ci	return num_entries;
374562306a36Sopenharmony_ci}
374662306a36Sopenharmony_ci
374762306a36Sopenharmony_ci/**
374862306a36Sopenharmony_ci * megasas_enable_irq_poll() - enable irqpoll
374962306a36Sopenharmony_ci * @instance:			Adapter soft state
375062306a36Sopenharmony_ci */
375162306a36Sopenharmony_cistatic void megasas_enable_irq_poll(struct megasas_instance *instance)
375262306a36Sopenharmony_ci{
375362306a36Sopenharmony_ci	u32 count, i;
375462306a36Sopenharmony_ci	struct megasas_irq_context *irq_ctx;
375562306a36Sopenharmony_ci
375662306a36Sopenharmony_ci	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
375762306a36Sopenharmony_ci
375862306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
375962306a36Sopenharmony_ci		irq_ctx = &instance->irq_context[i];
376062306a36Sopenharmony_ci		irq_poll_enable(&irq_ctx->irqpoll);
376162306a36Sopenharmony_ci	}
376262306a36Sopenharmony_ci}
376362306a36Sopenharmony_ci
376462306a36Sopenharmony_ci/**
376562306a36Sopenharmony_ci * megasas_sync_irqs -	Synchronizes all IRQs owned by adapter
376662306a36Sopenharmony_ci * @instance_addr:			Adapter soft state address
376762306a36Sopenharmony_ci */
376862306a36Sopenharmony_cistatic void megasas_sync_irqs(unsigned long instance_addr)
376962306a36Sopenharmony_ci{
377062306a36Sopenharmony_ci	u32 count, i;
377162306a36Sopenharmony_ci	struct megasas_instance *instance =
377262306a36Sopenharmony_ci		(struct megasas_instance *)instance_addr;
377362306a36Sopenharmony_ci	struct megasas_irq_context *irq_ctx;
377462306a36Sopenharmony_ci
377562306a36Sopenharmony_ci	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
377662306a36Sopenharmony_ci
377762306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
377862306a36Sopenharmony_ci		synchronize_irq(pci_irq_vector(instance->pdev, i));
377962306a36Sopenharmony_ci		irq_ctx = &instance->irq_context[i];
378062306a36Sopenharmony_ci		irq_poll_disable(&irq_ctx->irqpoll);
378162306a36Sopenharmony_ci		if (irq_ctx->irq_poll_scheduled) {
378262306a36Sopenharmony_ci			irq_ctx->irq_poll_scheduled = false;
378362306a36Sopenharmony_ci			enable_irq(irq_ctx->os_irq);
378462306a36Sopenharmony_ci			complete_cmd_fusion(instance, irq_ctx->MSIxIndex, irq_ctx);
378562306a36Sopenharmony_ci		}
378662306a36Sopenharmony_ci	}
378762306a36Sopenharmony_ci}
378862306a36Sopenharmony_ci
378962306a36Sopenharmony_ci/**
379062306a36Sopenharmony_ci * megasas_irqpoll() - process a queue for completed reply descriptors
379162306a36Sopenharmony_ci * @irqpoll:	IRQ poll structure associated with queue to poll.
379262306a36Sopenharmony_ci * @budget:	Threshold of reply descriptors to process per poll.
379362306a36Sopenharmony_ci *
379462306a36Sopenharmony_ci * Return: The number of entries processed.
379562306a36Sopenharmony_ci */
379662306a36Sopenharmony_ci
379762306a36Sopenharmony_ciint megasas_irqpoll(struct irq_poll *irqpoll, int budget)
379862306a36Sopenharmony_ci{
379962306a36Sopenharmony_ci	struct megasas_irq_context *irq_ctx;
380062306a36Sopenharmony_ci	struct megasas_instance *instance;
380162306a36Sopenharmony_ci	int num_entries;
380262306a36Sopenharmony_ci
380362306a36Sopenharmony_ci	irq_ctx = container_of(irqpoll, struct megasas_irq_context, irqpoll);
380462306a36Sopenharmony_ci	instance = irq_ctx->instance;
380562306a36Sopenharmony_ci
380662306a36Sopenharmony_ci	if (irq_ctx->irq_line_enable) {
380762306a36Sopenharmony_ci		disable_irq_nosync(irq_ctx->os_irq);
380862306a36Sopenharmony_ci		irq_ctx->irq_line_enable = false;
380962306a36Sopenharmony_ci	}
381062306a36Sopenharmony_ci
381162306a36Sopenharmony_ci	num_entries = complete_cmd_fusion(instance, irq_ctx->MSIxIndex, irq_ctx);
381262306a36Sopenharmony_ci	if (num_entries < budget) {
381362306a36Sopenharmony_ci		irq_poll_complete(irqpoll);
381462306a36Sopenharmony_ci		irq_ctx->irq_poll_scheduled = false;
381562306a36Sopenharmony_ci		enable_irq(irq_ctx->os_irq);
381662306a36Sopenharmony_ci		complete_cmd_fusion(instance, irq_ctx->MSIxIndex, irq_ctx);
381762306a36Sopenharmony_ci	}
381862306a36Sopenharmony_ci
381962306a36Sopenharmony_ci	return num_entries;
382062306a36Sopenharmony_ci}
382162306a36Sopenharmony_ci
382262306a36Sopenharmony_ci/**
382362306a36Sopenharmony_ci * megasas_complete_cmd_dpc_fusion -	Completes command
382462306a36Sopenharmony_ci * @instance_addr:			Adapter soft state address
382562306a36Sopenharmony_ci *
382662306a36Sopenharmony_ci * Tasklet to complete cmds
382762306a36Sopenharmony_ci */
382862306a36Sopenharmony_cistatic void
382962306a36Sopenharmony_cimegasas_complete_cmd_dpc_fusion(unsigned long instance_addr)
383062306a36Sopenharmony_ci{
383162306a36Sopenharmony_ci	struct megasas_instance *instance =
383262306a36Sopenharmony_ci		(struct megasas_instance *)instance_addr;
383362306a36Sopenharmony_ci	struct megasas_irq_context *irq_ctx = NULL;
383462306a36Sopenharmony_ci	u32 count, MSIxIndex;
383562306a36Sopenharmony_ci
383662306a36Sopenharmony_ci	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
383762306a36Sopenharmony_ci
383862306a36Sopenharmony_ci	/* If we have already declared adapter dead, donot complete cmds */
383962306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
384062306a36Sopenharmony_ci		return;
384162306a36Sopenharmony_ci
384262306a36Sopenharmony_ci	for (MSIxIndex = 0 ; MSIxIndex < count; MSIxIndex++) {
384362306a36Sopenharmony_ci		irq_ctx = &instance->irq_context[MSIxIndex];
384462306a36Sopenharmony_ci		complete_cmd_fusion(instance, MSIxIndex, irq_ctx);
384562306a36Sopenharmony_ci	}
384662306a36Sopenharmony_ci}
384762306a36Sopenharmony_ci
384862306a36Sopenharmony_ci/**
384962306a36Sopenharmony_ci * megasas_isr_fusion - isr entry point
385062306a36Sopenharmony_ci * @irq:	IRQ number
385162306a36Sopenharmony_ci * @devp:	IRQ context
385262306a36Sopenharmony_ci */
385362306a36Sopenharmony_cistatic irqreturn_t megasas_isr_fusion(int irq, void *devp)
385462306a36Sopenharmony_ci{
385562306a36Sopenharmony_ci	struct megasas_irq_context *irq_context = devp;
385662306a36Sopenharmony_ci	struct megasas_instance *instance = irq_context->instance;
385762306a36Sopenharmony_ci	u32 mfiStatus;
385862306a36Sopenharmony_ci
385962306a36Sopenharmony_ci	if (instance->mask_interrupts)
386062306a36Sopenharmony_ci		return IRQ_NONE;
386162306a36Sopenharmony_ci
386262306a36Sopenharmony_ci	if (irq_context->irq_poll_scheduled)
386362306a36Sopenharmony_ci		return IRQ_HANDLED;
386462306a36Sopenharmony_ci
386562306a36Sopenharmony_ci	if (!instance->msix_vectors) {
386662306a36Sopenharmony_ci		mfiStatus = instance->instancet->clear_intr(instance);
386762306a36Sopenharmony_ci		if (!mfiStatus)
386862306a36Sopenharmony_ci			return IRQ_NONE;
386962306a36Sopenharmony_ci	}
387062306a36Sopenharmony_ci
387162306a36Sopenharmony_ci	/* If we are resetting, bail */
387262306a36Sopenharmony_ci	if (test_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags)) {
387362306a36Sopenharmony_ci		instance->instancet->clear_intr(instance);
387462306a36Sopenharmony_ci		return IRQ_HANDLED;
387562306a36Sopenharmony_ci	}
387662306a36Sopenharmony_ci
387762306a36Sopenharmony_ci	return complete_cmd_fusion(instance, irq_context->MSIxIndex, irq_context)
387862306a36Sopenharmony_ci			? IRQ_HANDLED : IRQ_NONE;
387962306a36Sopenharmony_ci}
388062306a36Sopenharmony_ci
388162306a36Sopenharmony_ci/**
388262306a36Sopenharmony_ci * build_mpt_mfi_pass_thru - builds a cmd fo MFI Pass thru
388362306a36Sopenharmony_ci * @instance:			Adapter soft state
388462306a36Sopenharmony_ci * @mfi_cmd:			megasas_cmd pointer
388562306a36Sopenharmony_ci *
388662306a36Sopenharmony_ci */
388762306a36Sopenharmony_cistatic void
388862306a36Sopenharmony_cibuild_mpt_mfi_pass_thru(struct megasas_instance *instance,
388962306a36Sopenharmony_ci			struct megasas_cmd *mfi_cmd)
389062306a36Sopenharmony_ci{
389162306a36Sopenharmony_ci	struct MPI25_IEEE_SGE_CHAIN64 *mpi25_ieee_chain;
389262306a36Sopenharmony_ci	struct MPI2_RAID_SCSI_IO_REQUEST *io_req;
389362306a36Sopenharmony_ci	struct megasas_cmd_fusion *cmd;
389462306a36Sopenharmony_ci	struct fusion_context *fusion;
389562306a36Sopenharmony_ci	struct megasas_header *frame_hdr = &mfi_cmd->frame->hdr;
389662306a36Sopenharmony_ci
389762306a36Sopenharmony_ci	fusion = instance->ctrl_context;
389862306a36Sopenharmony_ci
389962306a36Sopenharmony_ci	cmd = megasas_get_cmd_fusion(instance,
390062306a36Sopenharmony_ci			instance->max_scsi_cmds + mfi_cmd->index);
390162306a36Sopenharmony_ci
390262306a36Sopenharmony_ci	/*  Save the smid. To be used for returning the cmd */
390362306a36Sopenharmony_ci	mfi_cmd->context.smid = cmd->index;
390462306a36Sopenharmony_ci
390562306a36Sopenharmony_ci	/*
390662306a36Sopenharmony_ci	 * For cmds where the flag is set, store the flag and check
390762306a36Sopenharmony_ci	 * on completion. For cmds with this flag, don't call
390862306a36Sopenharmony_ci	 * megasas_complete_cmd
390962306a36Sopenharmony_ci	 */
391062306a36Sopenharmony_ci
391162306a36Sopenharmony_ci	if (frame_hdr->flags & cpu_to_le16(MFI_FRAME_DONT_POST_IN_REPLY_QUEUE))
391262306a36Sopenharmony_ci		mfi_cmd->flags |= DRV_DCMD_POLLED_MODE;
391362306a36Sopenharmony_ci
391462306a36Sopenharmony_ci	io_req = cmd->io_request;
391562306a36Sopenharmony_ci
391662306a36Sopenharmony_ci	if (instance->adapter_type >= INVADER_SERIES) {
391762306a36Sopenharmony_ci		struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end =
391862306a36Sopenharmony_ci			(struct MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL;
391962306a36Sopenharmony_ci		sgl_ptr_end += fusion->max_sge_in_main_msg - 1;
392062306a36Sopenharmony_ci		sgl_ptr_end->Flags = 0;
392162306a36Sopenharmony_ci	}
392262306a36Sopenharmony_ci
392362306a36Sopenharmony_ci	mpi25_ieee_chain =
392462306a36Sopenharmony_ci	  (struct MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL.IeeeChain;
392562306a36Sopenharmony_ci
392662306a36Sopenharmony_ci	io_req->Function    = MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST;
392762306a36Sopenharmony_ci	io_req->SGLOffset0  = offsetof(struct MPI2_RAID_SCSI_IO_REQUEST,
392862306a36Sopenharmony_ci				       SGL) / 4;
392962306a36Sopenharmony_ci	io_req->ChainOffset = fusion->chain_offset_mfi_pthru;
393062306a36Sopenharmony_ci
393162306a36Sopenharmony_ci	mpi25_ieee_chain->Address = cpu_to_le64(mfi_cmd->frame_phys_addr);
393262306a36Sopenharmony_ci
393362306a36Sopenharmony_ci	mpi25_ieee_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT |
393462306a36Sopenharmony_ci		MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR;
393562306a36Sopenharmony_ci
393662306a36Sopenharmony_ci	mpi25_ieee_chain->Length = cpu_to_le32(instance->mfi_frame_size);
393762306a36Sopenharmony_ci}
393862306a36Sopenharmony_ci
393962306a36Sopenharmony_ci/**
394062306a36Sopenharmony_ci * build_mpt_cmd - Calls helper function to build a cmd MFI Pass thru cmd
394162306a36Sopenharmony_ci * @instance:			Adapter soft state
394262306a36Sopenharmony_ci * @cmd:			mfi cmd to build
394362306a36Sopenharmony_ci *
394462306a36Sopenharmony_ci */
394562306a36Sopenharmony_cistatic union MEGASAS_REQUEST_DESCRIPTOR_UNION *
394662306a36Sopenharmony_cibuild_mpt_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
394762306a36Sopenharmony_ci{
394862306a36Sopenharmony_ci	union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc = NULL;
394962306a36Sopenharmony_ci	u16 index;
395062306a36Sopenharmony_ci
395162306a36Sopenharmony_ci	build_mpt_mfi_pass_thru(instance, cmd);
395262306a36Sopenharmony_ci	index = cmd->context.smid;
395362306a36Sopenharmony_ci
395462306a36Sopenharmony_ci	req_desc = megasas_get_request_descriptor(instance, index - 1);
395562306a36Sopenharmony_ci
395662306a36Sopenharmony_ci	req_desc->Words = 0;
395762306a36Sopenharmony_ci	req_desc->SCSIIO.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
395862306a36Sopenharmony_ci					 MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
395962306a36Sopenharmony_ci
396062306a36Sopenharmony_ci	req_desc->SCSIIO.SMID = cpu_to_le16(index);
396162306a36Sopenharmony_ci
396262306a36Sopenharmony_ci	return req_desc;
396362306a36Sopenharmony_ci}
396462306a36Sopenharmony_ci
396562306a36Sopenharmony_ci/**
396662306a36Sopenharmony_ci * megasas_issue_dcmd_fusion - Issues a MFI Pass thru cmd
396762306a36Sopenharmony_ci * @instance:			Adapter soft state
396862306a36Sopenharmony_ci * @cmd:			mfi cmd pointer
396962306a36Sopenharmony_ci *
397062306a36Sopenharmony_ci */
397162306a36Sopenharmony_cistatic void
397262306a36Sopenharmony_cimegasas_issue_dcmd_fusion(struct megasas_instance *instance,
397362306a36Sopenharmony_ci			  struct megasas_cmd *cmd)
397462306a36Sopenharmony_ci{
397562306a36Sopenharmony_ci	union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
397662306a36Sopenharmony_ci
397762306a36Sopenharmony_ci	req_desc = build_mpt_cmd(instance, cmd);
397862306a36Sopenharmony_ci
397962306a36Sopenharmony_ci	megasas_fire_cmd_fusion(instance, req_desc);
398062306a36Sopenharmony_ci	return;
398162306a36Sopenharmony_ci}
398262306a36Sopenharmony_ci
398362306a36Sopenharmony_ci/**
398462306a36Sopenharmony_ci * megasas_release_fusion -	Reverses the FW initialization
398562306a36Sopenharmony_ci * @instance:			Adapter soft state
398662306a36Sopenharmony_ci */
398762306a36Sopenharmony_civoid
398862306a36Sopenharmony_cimegasas_release_fusion(struct megasas_instance *instance)
398962306a36Sopenharmony_ci{
399062306a36Sopenharmony_ci	megasas_free_ioc_init_cmd(instance);
399162306a36Sopenharmony_ci	megasas_free_cmds(instance);
399262306a36Sopenharmony_ci	megasas_free_cmds_fusion(instance);
399362306a36Sopenharmony_ci
399462306a36Sopenharmony_ci	iounmap(instance->reg_set);
399562306a36Sopenharmony_ci
399662306a36Sopenharmony_ci	pci_release_selected_regions(instance->pdev, 1<<instance->bar);
399762306a36Sopenharmony_ci}
399862306a36Sopenharmony_ci
399962306a36Sopenharmony_ci/**
400062306a36Sopenharmony_ci * megasas_read_fw_status_reg_fusion - returns the current FW status value
400162306a36Sopenharmony_ci * @instance:			Adapter soft state
400262306a36Sopenharmony_ci */
400362306a36Sopenharmony_cistatic u32
400462306a36Sopenharmony_cimegasas_read_fw_status_reg_fusion(struct megasas_instance *instance)
400562306a36Sopenharmony_ci{
400662306a36Sopenharmony_ci	return megasas_readl(instance, &instance->reg_set->outbound_scratch_pad_0);
400762306a36Sopenharmony_ci}
400862306a36Sopenharmony_ci
400962306a36Sopenharmony_ci/**
401062306a36Sopenharmony_ci * megasas_alloc_host_crash_buffer -	Host buffers for Crash dump collection from Firmware
401162306a36Sopenharmony_ci * @instance:				Controller's soft instance
401262306a36Sopenharmony_ci * @return:			        Number of allocated host crash buffers
401362306a36Sopenharmony_ci */
401462306a36Sopenharmony_cistatic void
401562306a36Sopenharmony_cimegasas_alloc_host_crash_buffer(struct megasas_instance *instance)
401662306a36Sopenharmony_ci{
401762306a36Sopenharmony_ci	unsigned int i;
401862306a36Sopenharmony_ci
401962306a36Sopenharmony_ci	for (i = 0; i < MAX_CRASH_DUMP_SIZE; i++) {
402062306a36Sopenharmony_ci		instance->crash_buf[i] = vzalloc(CRASH_DMA_BUF_SIZE);
402162306a36Sopenharmony_ci		if (!instance->crash_buf[i]) {
402262306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "Firmware crash dump "
402362306a36Sopenharmony_ci				"memory allocation failed at index %d\n", i);
402462306a36Sopenharmony_ci			break;
402562306a36Sopenharmony_ci		}
402662306a36Sopenharmony_ci	}
402762306a36Sopenharmony_ci	instance->drv_buf_alloc = i;
402862306a36Sopenharmony_ci}
402962306a36Sopenharmony_ci
403062306a36Sopenharmony_ci/**
403162306a36Sopenharmony_ci * megasas_free_host_crash_buffer -	Host buffers for Crash dump collection from Firmware
403262306a36Sopenharmony_ci * @instance:				Controller's soft instance
403362306a36Sopenharmony_ci */
403462306a36Sopenharmony_civoid
403562306a36Sopenharmony_cimegasas_free_host_crash_buffer(struct megasas_instance *instance)
403662306a36Sopenharmony_ci{
403762306a36Sopenharmony_ci	unsigned int i;
403862306a36Sopenharmony_ci	for (i = 0; i < instance->drv_buf_alloc; i++) {
403962306a36Sopenharmony_ci		vfree(instance->crash_buf[i]);
404062306a36Sopenharmony_ci	}
404162306a36Sopenharmony_ci	instance->drv_buf_index = 0;
404262306a36Sopenharmony_ci	instance->drv_buf_alloc = 0;
404362306a36Sopenharmony_ci	instance->fw_crash_state = UNAVAILABLE;
404462306a36Sopenharmony_ci	instance->fw_crash_buffer_size = 0;
404562306a36Sopenharmony_ci}
404662306a36Sopenharmony_ci
404762306a36Sopenharmony_ci/**
404862306a36Sopenharmony_ci * megasas_adp_reset_fusion -	For controller reset
404962306a36Sopenharmony_ci * @instance:				Controller's soft instance
405062306a36Sopenharmony_ci * @regs:				MFI register set
405162306a36Sopenharmony_ci */
405262306a36Sopenharmony_cistatic int
405362306a36Sopenharmony_cimegasas_adp_reset_fusion(struct megasas_instance *instance,
405462306a36Sopenharmony_ci			 struct megasas_register_set __iomem *regs)
405562306a36Sopenharmony_ci{
405662306a36Sopenharmony_ci	u32 host_diag, abs_state, retry;
405762306a36Sopenharmony_ci
405862306a36Sopenharmony_ci	/* Now try to reset the chip */
405962306a36Sopenharmony_ci	writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
406062306a36Sopenharmony_ci	writel(MPI2_WRSEQ_1ST_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
406162306a36Sopenharmony_ci	writel(MPI2_WRSEQ_2ND_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
406262306a36Sopenharmony_ci	writel(MPI2_WRSEQ_3RD_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
406362306a36Sopenharmony_ci	writel(MPI2_WRSEQ_4TH_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
406462306a36Sopenharmony_ci	writel(MPI2_WRSEQ_5TH_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
406562306a36Sopenharmony_ci	writel(MPI2_WRSEQ_6TH_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
406662306a36Sopenharmony_ci
406762306a36Sopenharmony_ci	/* Check that the diag write enable (DRWE) bit is on */
406862306a36Sopenharmony_ci	host_diag = megasas_readl(instance, &instance->reg_set->fusion_host_diag);
406962306a36Sopenharmony_ci	retry = 0;
407062306a36Sopenharmony_ci	while (!(host_diag & HOST_DIAG_WRITE_ENABLE)) {
407162306a36Sopenharmony_ci		msleep(100);
407262306a36Sopenharmony_ci		host_diag = megasas_readl(instance,
407362306a36Sopenharmony_ci					  &instance->reg_set->fusion_host_diag);
407462306a36Sopenharmony_ci		if (retry++ == 100) {
407562306a36Sopenharmony_ci			dev_warn(&instance->pdev->dev,
407662306a36Sopenharmony_ci				"Host diag unlock failed from %s %d\n",
407762306a36Sopenharmony_ci				__func__, __LINE__);
407862306a36Sopenharmony_ci			break;
407962306a36Sopenharmony_ci		}
408062306a36Sopenharmony_ci	}
408162306a36Sopenharmony_ci	if (!(host_diag & HOST_DIAG_WRITE_ENABLE))
408262306a36Sopenharmony_ci		return -1;
408362306a36Sopenharmony_ci
408462306a36Sopenharmony_ci	/* Send chip reset command */
408562306a36Sopenharmony_ci	writel(host_diag | HOST_DIAG_RESET_ADAPTER,
408662306a36Sopenharmony_ci		&instance->reg_set->fusion_host_diag);
408762306a36Sopenharmony_ci	msleep(3000);
408862306a36Sopenharmony_ci
408962306a36Sopenharmony_ci	/* Make sure reset adapter bit is cleared */
409062306a36Sopenharmony_ci	host_diag = megasas_readl(instance, &instance->reg_set->fusion_host_diag);
409162306a36Sopenharmony_ci	retry = 0;
409262306a36Sopenharmony_ci	while (host_diag & HOST_DIAG_RESET_ADAPTER) {
409362306a36Sopenharmony_ci		msleep(100);
409462306a36Sopenharmony_ci		host_diag = megasas_readl(instance,
409562306a36Sopenharmony_ci					  &instance->reg_set->fusion_host_diag);
409662306a36Sopenharmony_ci		if (retry++ == 1000) {
409762306a36Sopenharmony_ci			dev_warn(&instance->pdev->dev,
409862306a36Sopenharmony_ci				"Diag reset adapter never cleared %s %d\n",
409962306a36Sopenharmony_ci				__func__, __LINE__);
410062306a36Sopenharmony_ci			break;
410162306a36Sopenharmony_ci		}
410262306a36Sopenharmony_ci	}
410362306a36Sopenharmony_ci	if (host_diag & HOST_DIAG_RESET_ADAPTER)
410462306a36Sopenharmony_ci		return -1;
410562306a36Sopenharmony_ci
410662306a36Sopenharmony_ci	abs_state = instance->instancet->read_fw_status_reg(instance)
410762306a36Sopenharmony_ci			& MFI_STATE_MASK;
410862306a36Sopenharmony_ci	retry = 0;
410962306a36Sopenharmony_ci
411062306a36Sopenharmony_ci	while ((abs_state <= MFI_STATE_FW_INIT) && (retry++ < 1000)) {
411162306a36Sopenharmony_ci		msleep(100);
411262306a36Sopenharmony_ci		abs_state = instance->instancet->
411362306a36Sopenharmony_ci			read_fw_status_reg(instance) & MFI_STATE_MASK;
411462306a36Sopenharmony_ci	}
411562306a36Sopenharmony_ci	if (abs_state <= MFI_STATE_FW_INIT) {
411662306a36Sopenharmony_ci		dev_warn(&instance->pdev->dev,
411762306a36Sopenharmony_ci			"fw state < MFI_STATE_FW_INIT, state = 0x%x %s %d\n",
411862306a36Sopenharmony_ci			abs_state, __func__, __LINE__);
411962306a36Sopenharmony_ci		return -1;
412062306a36Sopenharmony_ci	}
412162306a36Sopenharmony_ci
412262306a36Sopenharmony_ci	return 0;
412362306a36Sopenharmony_ci}
412462306a36Sopenharmony_ci
412562306a36Sopenharmony_ci/**
412662306a36Sopenharmony_ci * megasas_check_reset_fusion -	For controller reset check
412762306a36Sopenharmony_ci * @instance:				Controller's soft instance
412862306a36Sopenharmony_ci * @regs:				MFI register set
412962306a36Sopenharmony_ci */
413062306a36Sopenharmony_cistatic int
413162306a36Sopenharmony_cimegasas_check_reset_fusion(struct megasas_instance *instance,
413262306a36Sopenharmony_ci			   struct megasas_register_set __iomem *regs)
413362306a36Sopenharmony_ci{
413462306a36Sopenharmony_ci	return 0;
413562306a36Sopenharmony_ci}
413662306a36Sopenharmony_ci
413762306a36Sopenharmony_ci/**
413862306a36Sopenharmony_ci * megasas_trigger_snap_dump -	Trigger snap dump in FW
413962306a36Sopenharmony_ci * @instance:			Soft instance of adapter
414062306a36Sopenharmony_ci */
414162306a36Sopenharmony_cistatic inline void megasas_trigger_snap_dump(struct megasas_instance *instance)
414262306a36Sopenharmony_ci{
414362306a36Sopenharmony_ci	int j;
414462306a36Sopenharmony_ci	u32 fw_state, abs_state;
414562306a36Sopenharmony_ci
414662306a36Sopenharmony_ci	if (!instance->disableOnlineCtrlReset) {
414762306a36Sopenharmony_ci		dev_info(&instance->pdev->dev, "Trigger snap dump\n");
414862306a36Sopenharmony_ci		writel(MFI_ADP_TRIGGER_SNAP_DUMP,
414962306a36Sopenharmony_ci		       &instance->reg_set->doorbell);
415062306a36Sopenharmony_ci		readl(&instance->reg_set->doorbell);
415162306a36Sopenharmony_ci	}
415262306a36Sopenharmony_ci
415362306a36Sopenharmony_ci	for (j = 0; j < instance->snapdump_wait_time; j++) {
415462306a36Sopenharmony_ci		abs_state = instance->instancet->read_fw_status_reg(instance);
415562306a36Sopenharmony_ci		fw_state = abs_state & MFI_STATE_MASK;
415662306a36Sopenharmony_ci		if (fw_state == MFI_STATE_FAULT) {
415762306a36Sopenharmony_ci			dev_printk(KERN_ERR, &instance->pdev->dev,
415862306a36Sopenharmony_ci				   "FW in FAULT state Fault code:0x%x subcode:0x%x func:%s\n",
415962306a36Sopenharmony_ci				   abs_state & MFI_STATE_FAULT_CODE,
416062306a36Sopenharmony_ci				   abs_state & MFI_STATE_FAULT_SUBCODE, __func__);
416162306a36Sopenharmony_ci			return;
416262306a36Sopenharmony_ci		}
416362306a36Sopenharmony_ci		msleep(1000);
416462306a36Sopenharmony_ci	}
416562306a36Sopenharmony_ci}
416662306a36Sopenharmony_ci
416762306a36Sopenharmony_ci/* This function waits for outstanding commands on fusion to complete */
416862306a36Sopenharmony_cistatic int
416962306a36Sopenharmony_cimegasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
417062306a36Sopenharmony_ci				    int reason, int *convert)
417162306a36Sopenharmony_ci{
417262306a36Sopenharmony_ci	int i, outstanding, retval = 0, hb_seconds_missed = 0;
417362306a36Sopenharmony_ci	u32 fw_state, abs_state;
417462306a36Sopenharmony_ci	u32 waittime_for_io_completion;
417562306a36Sopenharmony_ci
417662306a36Sopenharmony_ci	waittime_for_io_completion =
417762306a36Sopenharmony_ci		min_t(u32, resetwaittime,
417862306a36Sopenharmony_ci			(resetwaittime - instance->snapdump_wait_time));
417962306a36Sopenharmony_ci
418062306a36Sopenharmony_ci	if (reason == MFI_IO_TIMEOUT_OCR) {
418162306a36Sopenharmony_ci		dev_info(&instance->pdev->dev,
418262306a36Sopenharmony_ci			"MFI command is timed out\n");
418362306a36Sopenharmony_ci		megasas_complete_cmd_dpc_fusion((unsigned long)instance);
418462306a36Sopenharmony_ci		if (instance->snapdump_wait_time)
418562306a36Sopenharmony_ci			megasas_trigger_snap_dump(instance);
418662306a36Sopenharmony_ci		retval = 1;
418762306a36Sopenharmony_ci		goto out;
418862306a36Sopenharmony_ci	}
418962306a36Sopenharmony_ci
419062306a36Sopenharmony_ci	for (i = 0; i < waittime_for_io_completion; i++) {
419162306a36Sopenharmony_ci		/* Check if firmware is in fault state */
419262306a36Sopenharmony_ci		abs_state = instance->instancet->read_fw_status_reg(instance);
419362306a36Sopenharmony_ci		fw_state = abs_state & MFI_STATE_MASK;
419462306a36Sopenharmony_ci		if (fw_state == MFI_STATE_FAULT) {
419562306a36Sopenharmony_ci			dev_printk(KERN_ERR, &instance->pdev->dev,
419662306a36Sopenharmony_ci				   "FW in FAULT state Fault code:0x%x subcode:0x%x func:%s\n",
419762306a36Sopenharmony_ci				   abs_state & MFI_STATE_FAULT_CODE,
419862306a36Sopenharmony_ci				   abs_state & MFI_STATE_FAULT_SUBCODE, __func__);
419962306a36Sopenharmony_ci			megasas_complete_cmd_dpc_fusion((unsigned long)instance);
420062306a36Sopenharmony_ci			if (instance->requestorId && reason) {
420162306a36Sopenharmony_ci				dev_warn(&instance->pdev->dev, "SR-IOV Found FW in FAULT"
420262306a36Sopenharmony_ci				" state while polling during"
420362306a36Sopenharmony_ci				" I/O timeout handling for %d\n",
420462306a36Sopenharmony_ci				instance->host->host_no);
420562306a36Sopenharmony_ci				*convert = 1;
420662306a36Sopenharmony_ci			}
420762306a36Sopenharmony_ci
420862306a36Sopenharmony_ci			retval = 1;
420962306a36Sopenharmony_ci			goto out;
421062306a36Sopenharmony_ci		}
421162306a36Sopenharmony_ci
421262306a36Sopenharmony_ci
421362306a36Sopenharmony_ci		/* If SR-IOV VF mode & heartbeat timeout, don't wait */
421462306a36Sopenharmony_ci		if (instance->requestorId && !reason) {
421562306a36Sopenharmony_ci			retval = 1;
421662306a36Sopenharmony_ci			goto out;
421762306a36Sopenharmony_ci		}
421862306a36Sopenharmony_ci
421962306a36Sopenharmony_ci		/* If SR-IOV VF mode & I/O timeout, check for HB timeout */
422062306a36Sopenharmony_ci		if (instance->requestorId && (reason == SCSIIO_TIMEOUT_OCR)) {
422162306a36Sopenharmony_ci			if (instance->hb_host_mem->HB.fwCounter !=
422262306a36Sopenharmony_ci			    instance->hb_host_mem->HB.driverCounter) {
422362306a36Sopenharmony_ci				instance->hb_host_mem->HB.driverCounter =
422462306a36Sopenharmony_ci					instance->hb_host_mem->HB.fwCounter;
422562306a36Sopenharmony_ci				hb_seconds_missed = 0;
422662306a36Sopenharmony_ci			} else {
422762306a36Sopenharmony_ci				hb_seconds_missed++;
422862306a36Sopenharmony_ci				if (hb_seconds_missed ==
422962306a36Sopenharmony_ci				    (MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF/HZ)) {
423062306a36Sopenharmony_ci					dev_warn(&instance->pdev->dev, "SR-IOV:"
423162306a36Sopenharmony_ci					       " Heartbeat never completed "
423262306a36Sopenharmony_ci					       " while polling during I/O "
423362306a36Sopenharmony_ci					       " timeout handling for "
423462306a36Sopenharmony_ci					       "scsi%d.\n",
423562306a36Sopenharmony_ci					       instance->host->host_no);
423662306a36Sopenharmony_ci					       *convert = 1;
423762306a36Sopenharmony_ci					       retval = 1;
423862306a36Sopenharmony_ci					       goto out;
423962306a36Sopenharmony_ci				}
424062306a36Sopenharmony_ci			}
424162306a36Sopenharmony_ci		}
424262306a36Sopenharmony_ci
424362306a36Sopenharmony_ci		megasas_complete_cmd_dpc_fusion((unsigned long)instance);
424462306a36Sopenharmony_ci		outstanding = atomic_read(&instance->fw_outstanding);
424562306a36Sopenharmony_ci		if (!outstanding)
424662306a36Sopenharmony_ci			goto out;
424762306a36Sopenharmony_ci
424862306a36Sopenharmony_ci		if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
424962306a36Sopenharmony_ci			dev_notice(&instance->pdev->dev, "[%2d]waiting for %d "
425062306a36Sopenharmony_ci			       "commands to complete for scsi%d\n", i,
425162306a36Sopenharmony_ci			       outstanding, instance->host->host_no);
425262306a36Sopenharmony_ci		}
425362306a36Sopenharmony_ci		msleep(1000);
425462306a36Sopenharmony_ci	}
425562306a36Sopenharmony_ci
425662306a36Sopenharmony_ci	if (instance->snapdump_wait_time) {
425762306a36Sopenharmony_ci		megasas_trigger_snap_dump(instance);
425862306a36Sopenharmony_ci		retval = 1;
425962306a36Sopenharmony_ci		goto out;
426062306a36Sopenharmony_ci	}
426162306a36Sopenharmony_ci
426262306a36Sopenharmony_ci	if (atomic_read(&instance->fw_outstanding)) {
426362306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "pending commands remain after waiting, "
426462306a36Sopenharmony_ci		       "will reset adapter scsi%d.\n",
426562306a36Sopenharmony_ci		       instance->host->host_no);
426662306a36Sopenharmony_ci		*convert = 1;
426762306a36Sopenharmony_ci		retval = 1;
426862306a36Sopenharmony_ci	}
426962306a36Sopenharmony_ci
427062306a36Sopenharmony_ciout:
427162306a36Sopenharmony_ci	return retval;
427262306a36Sopenharmony_ci}
427362306a36Sopenharmony_ci
427462306a36Sopenharmony_civoid  megasas_reset_reply_desc(struct megasas_instance *instance)
427562306a36Sopenharmony_ci{
427662306a36Sopenharmony_ci	int i, j, count;
427762306a36Sopenharmony_ci	struct fusion_context *fusion;
427862306a36Sopenharmony_ci	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
427962306a36Sopenharmony_ci
428062306a36Sopenharmony_ci	fusion = instance->ctrl_context;
428162306a36Sopenharmony_ci	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
428262306a36Sopenharmony_ci	count += instance->iopoll_q_count;
428362306a36Sopenharmony_ci
428462306a36Sopenharmony_ci	for (i = 0 ; i < count ; i++) {
428562306a36Sopenharmony_ci		fusion->last_reply_idx[i] = 0;
428662306a36Sopenharmony_ci		reply_desc = fusion->reply_frames_desc[i];
428762306a36Sopenharmony_ci		for (j = 0 ; j < fusion->reply_q_depth; j++, reply_desc++)
428862306a36Sopenharmony_ci			reply_desc->Words = cpu_to_le64(ULLONG_MAX);
428962306a36Sopenharmony_ci	}
429062306a36Sopenharmony_ci}
429162306a36Sopenharmony_ci
429262306a36Sopenharmony_ci/*
429362306a36Sopenharmony_ci * megasas_refire_mgmt_cmd :	Re-fire management commands
429462306a36Sopenharmony_ci * @instance:				Controller's soft instance
429562306a36Sopenharmony_ci*/
429662306a36Sopenharmony_cistatic void megasas_refire_mgmt_cmd(struct megasas_instance *instance,
429762306a36Sopenharmony_ci			     bool return_ioctl)
429862306a36Sopenharmony_ci{
429962306a36Sopenharmony_ci	int j;
430062306a36Sopenharmony_ci	struct megasas_cmd_fusion *cmd_fusion;
430162306a36Sopenharmony_ci	struct fusion_context *fusion;
430262306a36Sopenharmony_ci	struct megasas_cmd *cmd_mfi;
430362306a36Sopenharmony_ci	union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
430462306a36Sopenharmony_ci	struct MPI2_RAID_SCSI_IO_REQUEST *scsi_io_req;
430562306a36Sopenharmony_ci	u16 smid;
430662306a36Sopenharmony_ci	bool refire_cmd = false;
430762306a36Sopenharmony_ci	u8 result;
430862306a36Sopenharmony_ci	u32 opcode = 0;
430962306a36Sopenharmony_ci
431062306a36Sopenharmony_ci	fusion = instance->ctrl_context;
431162306a36Sopenharmony_ci
431262306a36Sopenharmony_ci	/* Re-fire management commands.
431362306a36Sopenharmony_ci	 * Do not traverse complet MPT frame pool. Start from max_scsi_cmds.
431462306a36Sopenharmony_ci	 */
431562306a36Sopenharmony_ci	for (j = instance->max_scsi_cmds ; j < instance->max_fw_cmds; j++) {
431662306a36Sopenharmony_ci		cmd_fusion = fusion->cmd_list[j];
431762306a36Sopenharmony_ci		cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx];
431862306a36Sopenharmony_ci		smid = le16_to_cpu(cmd_mfi->context.smid);
431962306a36Sopenharmony_ci		result = REFIRE_CMD;
432062306a36Sopenharmony_ci
432162306a36Sopenharmony_ci		if (!smid)
432262306a36Sopenharmony_ci			continue;
432362306a36Sopenharmony_ci
432462306a36Sopenharmony_ci		req_desc = megasas_get_request_descriptor(instance, smid - 1);
432562306a36Sopenharmony_ci
432662306a36Sopenharmony_ci		switch (cmd_mfi->frame->hdr.cmd) {
432762306a36Sopenharmony_ci		case MFI_CMD_DCMD:
432862306a36Sopenharmony_ci			opcode = le32_to_cpu(cmd_mfi->frame->dcmd.opcode);
432962306a36Sopenharmony_ci			 /* Do not refire shutdown command */
433062306a36Sopenharmony_ci			if (opcode == MR_DCMD_CTRL_SHUTDOWN) {
433162306a36Sopenharmony_ci				cmd_mfi->frame->dcmd.cmd_status = MFI_STAT_OK;
433262306a36Sopenharmony_ci				result = COMPLETE_CMD;
433362306a36Sopenharmony_ci				break;
433462306a36Sopenharmony_ci			}
433562306a36Sopenharmony_ci
433662306a36Sopenharmony_ci			refire_cmd = ((opcode != MR_DCMD_LD_MAP_GET_INFO)) &&
433762306a36Sopenharmony_ci				      (opcode != MR_DCMD_SYSTEM_PD_MAP_GET_INFO) &&
433862306a36Sopenharmony_ci				      !(cmd_mfi->flags & DRV_DCMD_SKIP_REFIRE);
433962306a36Sopenharmony_ci
434062306a36Sopenharmony_ci			if (!refire_cmd)
434162306a36Sopenharmony_ci				result = RETURN_CMD;
434262306a36Sopenharmony_ci
434362306a36Sopenharmony_ci			break;
434462306a36Sopenharmony_ci		case MFI_CMD_NVME:
434562306a36Sopenharmony_ci			if (!instance->support_nvme_passthru) {
434662306a36Sopenharmony_ci				cmd_mfi->frame->hdr.cmd_status = MFI_STAT_INVALID_CMD;
434762306a36Sopenharmony_ci				result = COMPLETE_CMD;
434862306a36Sopenharmony_ci			}
434962306a36Sopenharmony_ci
435062306a36Sopenharmony_ci			break;
435162306a36Sopenharmony_ci		case MFI_CMD_TOOLBOX:
435262306a36Sopenharmony_ci			if (!instance->support_pci_lane_margining) {
435362306a36Sopenharmony_ci				cmd_mfi->frame->hdr.cmd_status = MFI_STAT_INVALID_CMD;
435462306a36Sopenharmony_ci				result = COMPLETE_CMD;
435562306a36Sopenharmony_ci			}
435662306a36Sopenharmony_ci
435762306a36Sopenharmony_ci			break;
435862306a36Sopenharmony_ci		default:
435962306a36Sopenharmony_ci			break;
436062306a36Sopenharmony_ci		}
436162306a36Sopenharmony_ci
436262306a36Sopenharmony_ci		if (return_ioctl && cmd_mfi->sync_cmd &&
436362306a36Sopenharmony_ci		    cmd_mfi->frame->hdr.cmd != MFI_CMD_ABORT) {
436462306a36Sopenharmony_ci			dev_err(&instance->pdev->dev,
436562306a36Sopenharmony_ci				"return -EBUSY from %s %d cmd 0x%x opcode 0x%x\n",
436662306a36Sopenharmony_ci				__func__, __LINE__, cmd_mfi->frame->hdr.cmd,
436762306a36Sopenharmony_ci				le32_to_cpu(cmd_mfi->frame->dcmd.opcode));
436862306a36Sopenharmony_ci			cmd_mfi->cmd_status_drv = DCMD_BUSY;
436962306a36Sopenharmony_ci			result = COMPLETE_CMD;
437062306a36Sopenharmony_ci		}
437162306a36Sopenharmony_ci
437262306a36Sopenharmony_ci		scsi_io_req = (struct MPI2_RAID_SCSI_IO_REQUEST *)
437362306a36Sopenharmony_ci				cmd_fusion->io_request;
437462306a36Sopenharmony_ci		if (scsi_io_req->Function == MPI2_FUNCTION_SCSI_TASK_MGMT)
437562306a36Sopenharmony_ci			result = RETURN_CMD;
437662306a36Sopenharmony_ci
437762306a36Sopenharmony_ci		switch (result) {
437862306a36Sopenharmony_ci		case REFIRE_CMD:
437962306a36Sopenharmony_ci			megasas_fire_cmd_fusion(instance, req_desc);
438062306a36Sopenharmony_ci			break;
438162306a36Sopenharmony_ci		case RETURN_CMD:
438262306a36Sopenharmony_ci			megasas_return_cmd(instance, cmd_mfi);
438362306a36Sopenharmony_ci			break;
438462306a36Sopenharmony_ci		case COMPLETE_CMD:
438562306a36Sopenharmony_ci			megasas_complete_cmd(instance, cmd_mfi, DID_OK);
438662306a36Sopenharmony_ci			break;
438762306a36Sopenharmony_ci		}
438862306a36Sopenharmony_ci	}
438962306a36Sopenharmony_ci}
439062306a36Sopenharmony_ci
439162306a36Sopenharmony_ci/*
439262306a36Sopenharmony_ci * megasas_return_polled_cmds: Return polled mode commands back to the pool
439362306a36Sopenharmony_ci *			       before initiating an OCR.
439462306a36Sopenharmony_ci * @instance:                  Controller's soft instance
439562306a36Sopenharmony_ci */
439662306a36Sopenharmony_cistatic void
439762306a36Sopenharmony_cimegasas_return_polled_cmds(struct megasas_instance *instance)
439862306a36Sopenharmony_ci{
439962306a36Sopenharmony_ci	int i;
440062306a36Sopenharmony_ci	struct megasas_cmd_fusion *cmd_fusion;
440162306a36Sopenharmony_ci	struct fusion_context *fusion;
440262306a36Sopenharmony_ci	struct megasas_cmd *cmd_mfi;
440362306a36Sopenharmony_ci
440462306a36Sopenharmony_ci	fusion = instance->ctrl_context;
440562306a36Sopenharmony_ci
440662306a36Sopenharmony_ci	for (i = instance->max_scsi_cmds; i < instance->max_fw_cmds; i++) {
440762306a36Sopenharmony_ci		cmd_fusion = fusion->cmd_list[i];
440862306a36Sopenharmony_ci		cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx];
440962306a36Sopenharmony_ci
441062306a36Sopenharmony_ci		if (cmd_mfi->flags & DRV_DCMD_POLLED_MODE) {
441162306a36Sopenharmony_ci			if (megasas_dbg_lvl & OCR_DEBUG)
441262306a36Sopenharmony_ci				dev_info(&instance->pdev->dev,
441362306a36Sopenharmony_ci					 "%s %d return cmd 0x%x opcode 0x%x\n",
441462306a36Sopenharmony_ci					 __func__, __LINE__, cmd_mfi->frame->hdr.cmd,
441562306a36Sopenharmony_ci					 le32_to_cpu(cmd_mfi->frame->dcmd.opcode));
441662306a36Sopenharmony_ci			cmd_mfi->flags &= ~DRV_DCMD_POLLED_MODE;
441762306a36Sopenharmony_ci			megasas_return_cmd(instance, cmd_mfi);
441862306a36Sopenharmony_ci		}
441962306a36Sopenharmony_ci	}
442062306a36Sopenharmony_ci}
442162306a36Sopenharmony_ci
442262306a36Sopenharmony_ci/*
442362306a36Sopenharmony_ci * megasas_track_scsiio : Track SCSI IOs outstanding to a SCSI device
442462306a36Sopenharmony_ci * @instance: per adapter struct
442562306a36Sopenharmony_ci * @channel: the channel assigned by the OS
442662306a36Sopenharmony_ci * @id: the id assigned by the OS
442762306a36Sopenharmony_ci *
442862306a36Sopenharmony_ci * Returns SUCCESS if no IOs pending to SCSI device, else return FAILED
442962306a36Sopenharmony_ci */
443062306a36Sopenharmony_ci
443162306a36Sopenharmony_cistatic int megasas_track_scsiio(struct megasas_instance *instance,
443262306a36Sopenharmony_ci		int id, int channel)
443362306a36Sopenharmony_ci{
443462306a36Sopenharmony_ci	int i, found = 0;
443562306a36Sopenharmony_ci	struct megasas_cmd_fusion *cmd_fusion;
443662306a36Sopenharmony_ci	struct fusion_context *fusion;
443762306a36Sopenharmony_ci	fusion = instance->ctrl_context;
443862306a36Sopenharmony_ci
443962306a36Sopenharmony_ci	for (i = 0 ; i < instance->max_scsi_cmds; i++) {
444062306a36Sopenharmony_ci		cmd_fusion = fusion->cmd_list[i];
444162306a36Sopenharmony_ci		if (cmd_fusion->scmd &&
444262306a36Sopenharmony_ci			(cmd_fusion->scmd->device->id == id &&
444362306a36Sopenharmony_ci			cmd_fusion->scmd->device->channel == channel)) {
444462306a36Sopenharmony_ci			dev_info(&instance->pdev->dev,
444562306a36Sopenharmony_ci				"SCSI commands pending to target"
444662306a36Sopenharmony_ci				"channel %d id %d \tSMID: 0x%x\n",
444762306a36Sopenharmony_ci				channel, id, cmd_fusion->index);
444862306a36Sopenharmony_ci			scsi_print_command(cmd_fusion->scmd);
444962306a36Sopenharmony_ci			found = 1;
445062306a36Sopenharmony_ci			break;
445162306a36Sopenharmony_ci		}
445262306a36Sopenharmony_ci	}
445362306a36Sopenharmony_ci
445462306a36Sopenharmony_ci	return found ? FAILED : SUCCESS;
445562306a36Sopenharmony_ci}
445662306a36Sopenharmony_ci
445762306a36Sopenharmony_ci/**
445862306a36Sopenharmony_ci * megasas_tm_response_code - translation of device response code
445962306a36Sopenharmony_ci * @instance:	Controller's soft instance
446062306a36Sopenharmony_ci * @mpi_reply:	MPI reply returned by firmware
446162306a36Sopenharmony_ci *
446262306a36Sopenharmony_ci * Return nothing.
446362306a36Sopenharmony_ci */
446462306a36Sopenharmony_cistatic void
446562306a36Sopenharmony_cimegasas_tm_response_code(struct megasas_instance *instance,
446662306a36Sopenharmony_ci		struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply)
446762306a36Sopenharmony_ci{
446862306a36Sopenharmony_ci	char *desc;
446962306a36Sopenharmony_ci
447062306a36Sopenharmony_ci	switch (mpi_reply->ResponseCode) {
447162306a36Sopenharmony_ci	case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE:
447262306a36Sopenharmony_ci		desc = "task management request completed";
447362306a36Sopenharmony_ci		break;
447462306a36Sopenharmony_ci	case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME:
447562306a36Sopenharmony_ci		desc = "invalid frame";
447662306a36Sopenharmony_ci		break;
447762306a36Sopenharmony_ci	case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
447862306a36Sopenharmony_ci		desc = "task management request not supported";
447962306a36Sopenharmony_ci		break;
448062306a36Sopenharmony_ci	case MPI2_SCSITASKMGMT_RSP_TM_FAILED:
448162306a36Sopenharmony_ci		desc = "task management request failed";
448262306a36Sopenharmony_ci		break;
448362306a36Sopenharmony_ci	case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED:
448462306a36Sopenharmony_ci		desc = "task management request succeeded";
448562306a36Sopenharmony_ci		break;
448662306a36Sopenharmony_ci	case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN:
448762306a36Sopenharmony_ci		desc = "invalid lun";
448862306a36Sopenharmony_ci		break;
448962306a36Sopenharmony_ci	case 0xA:
449062306a36Sopenharmony_ci		desc = "overlapped tag attempted";
449162306a36Sopenharmony_ci		break;
449262306a36Sopenharmony_ci	case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
449362306a36Sopenharmony_ci		desc = "task queued, however not sent to target";
449462306a36Sopenharmony_ci		break;
449562306a36Sopenharmony_ci	default:
449662306a36Sopenharmony_ci		desc = "unknown";
449762306a36Sopenharmony_ci		break;
449862306a36Sopenharmony_ci	}
449962306a36Sopenharmony_ci	dev_dbg(&instance->pdev->dev, "response_code(%01x): %s\n",
450062306a36Sopenharmony_ci		mpi_reply->ResponseCode, desc);
450162306a36Sopenharmony_ci	dev_dbg(&instance->pdev->dev,
450262306a36Sopenharmony_ci		"TerminationCount/DevHandle/Function/TaskType/IOCStat/IOCLoginfo"
450362306a36Sopenharmony_ci		" 0x%x/0x%x/0x%x/0x%x/0x%x/0x%x\n",
450462306a36Sopenharmony_ci		mpi_reply->TerminationCount, mpi_reply->DevHandle,
450562306a36Sopenharmony_ci		mpi_reply->Function, mpi_reply->TaskType,
450662306a36Sopenharmony_ci		mpi_reply->IOCStatus, mpi_reply->IOCLogInfo);
450762306a36Sopenharmony_ci}
450862306a36Sopenharmony_ci
450962306a36Sopenharmony_ci/**
451062306a36Sopenharmony_ci * megasas_issue_tm - main routine for sending tm requests
451162306a36Sopenharmony_ci * @instance: per adapter struct
451262306a36Sopenharmony_ci * @device_handle: device handle
451362306a36Sopenharmony_ci * @channel: the channel assigned by the OS
451462306a36Sopenharmony_ci * @id: the id assigned by the OS
451562306a36Sopenharmony_ci * @smid_task: smid assigned to the task
451662306a36Sopenharmony_ci * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in megaraid_sas_fusion.c)
451762306a36Sopenharmony_ci * @mr_device_priv_data: private data
451862306a36Sopenharmony_ci * Context: user
451962306a36Sopenharmony_ci *
452062306a36Sopenharmony_ci * MegaRaid use MPT interface for Task Magement request.
452162306a36Sopenharmony_ci * A generic API for sending task management requests to firmware.
452262306a36Sopenharmony_ci *
452362306a36Sopenharmony_ci * Return SUCCESS or FAILED.
452462306a36Sopenharmony_ci */
452562306a36Sopenharmony_cistatic int
452662306a36Sopenharmony_cimegasas_issue_tm(struct megasas_instance *instance, u16 device_handle,
452762306a36Sopenharmony_ci	uint channel, uint id, u16 smid_task, u8 type,
452862306a36Sopenharmony_ci	struct MR_PRIV_DEVICE *mr_device_priv_data)
452962306a36Sopenharmony_ci{
453062306a36Sopenharmony_ci	struct MR_TASK_MANAGE_REQUEST *mr_request;
453162306a36Sopenharmony_ci	struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_request;
453262306a36Sopenharmony_ci	unsigned long timeleft;
453362306a36Sopenharmony_ci	struct megasas_cmd_fusion *cmd_fusion;
453462306a36Sopenharmony_ci	struct megasas_cmd *cmd_mfi;
453562306a36Sopenharmony_ci	union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
453662306a36Sopenharmony_ci	struct fusion_context *fusion = NULL;
453762306a36Sopenharmony_ci	struct megasas_cmd_fusion *scsi_lookup;
453862306a36Sopenharmony_ci	int rc;
453962306a36Sopenharmony_ci	int timeout = MEGASAS_DEFAULT_TM_TIMEOUT;
454062306a36Sopenharmony_ci	struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply;
454162306a36Sopenharmony_ci
454262306a36Sopenharmony_ci	fusion = instance->ctrl_context;
454362306a36Sopenharmony_ci
454462306a36Sopenharmony_ci	cmd_mfi = megasas_get_cmd(instance);
454562306a36Sopenharmony_ci
454662306a36Sopenharmony_ci	if (!cmd_mfi) {
454762306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
454862306a36Sopenharmony_ci			__func__, __LINE__);
454962306a36Sopenharmony_ci		return -ENOMEM;
455062306a36Sopenharmony_ci	}
455162306a36Sopenharmony_ci
455262306a36Sopenharmony_ci	cmd_fusion = megasas_get_cmd_fusion(instance,
455362306a36Sopenharmony_ci			instance->max_scsi_cmds + cmd_mfi->index);
455462306a36Sopenharmony_ci
455562306a36Sopenharmony_ci	/*  Save the smid. To be used for returning the cmd */
455662306a36Sopenharmony_ci	cmd_mfi->context.smid = cmd_fusion->index;
455762306a36Sopenharmony_ci
455862306a36Sopenharmony_ci	req_desc = megasas_get_request_descriptor(instance,
455962306a36Sopenharmony_ci			(cmd_fusion->index - 1));
456062306a36Sopenharmony_ci
456162306a36Sopenharmony_ci	cmd_fusion->request_desc = req_desc;
456262306a36Sopenharmony_ci	req_desc->Words = 0;
456362306a36Sopenharmony_ci
456462306a36Sopenharmony_ci	mr_request = (struct MR_TASK_MANAGE_REQUEST *) cmd_fusion->io_request;
456562306a36Sopenharmony_ci	memset(mr_request, 0, sizeof(struct MR_TASK_MANAGE_REQUEST));
456662306a36Sopenharmony_ci	mpi_request = (struct MPI2_SCSI_TASK_MANAGE_REQUEST *) &mr_request->TmRequest;
456762306a36Sopenharmony_ci	mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
456862306a36Sopenharmony_ci	mpi_request->DevHandle = cpu_to_le16(device_handle);
456962306a36Sopenharmony_ci	mpi_request->TaskType = type;
457062306a36Sopenharmony_ci	mpi_request->TaskMID = cpu_to_le16(smid_task);
457162306a36Sopenharmony_ci	mpi_request->LUN[1] = 0;
457262306a36Sopenharmony_ci
457362306a36Sopenharmony_ci
457462306a36Sopenharmony_ci	req_desc = cmd_fusion->request_desc;
457562306a36Sopenharmony_ci	req_desc->HighPriority.SMID = cpu_to_le16(cmd_fusion->index);
457662306a36Sopenharmony_ci	req_desc->HighPriority.RequestFlags =
457762306a36Sopenharmony_ci		(MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
457862306a36Sopenharmony_ci		MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
457962306a36Sopenharmony_ci	req_desc->HighPriority.MSIxIndex =  0;
458062306a36Sopenharmony_ci	req_desc->HighPriority.LMID = 0;
458162306a36Sopenharmony_ci	req_desc->HighPriority.Reserved1 = 0;
458262306a36Sopenharmony_ci
458362306a36Sopenharmony_ci	if (channel < MEGASAS_MAX_PD_CHANNELS)
458462306a36Sopenharmony_ci		mr_request->tmReqFlags.isTMForPD = 1;
458562306a36Sopenharmony_ci	else
458662306a36Sopenharmony_ci		mr_request->tmReqFlags.isTMForLD = 1;
458762306a36Sopenharmony_ci
458862306a36Sopenharmony_ci	init_completion(&cmd_fusion->done);
458962306a36Sopenharmony_ci	megasas_fire_cmd_fusion(instance, req_desc);
459062306a36Sopenharmony_ci
459162306a36Sopenharmony_ci	switch (type) {
459262306a36Sopenharmony_ci	case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
459362306a36Sopenharmony_ci		timeout = mr_device_priv_data->task_abort_tmo;
459462306a36Sopenharmony_ci		break;
459562306a36Sopenharmony_ci	case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
459662306a36Sopenharmony_ci		timeout = mr_device_priv_data->target_reset_tmo;
459762306a36Sopenharmony_ci		break;
459862306a36Sopenharmony_ci	}
459962306a36Sopenharmony_ci
460062306a36Sopenharmony_ci	timeleft = wait_for_completion_timeout(&cmd_fusion->done, timeout * HZ);
460162306a36Sopenharmony_ci
460262306a36Sopenharmony_ci	if (!timeleft) {
460362306a36Sopenharmony_ci		dev_err(&instance->pdev->dev,
460462306a36Sopenharmony_ci			"task mgmt type 0x%x timed out\n", type);
460562306a36Sopenharmony_ci		mutex_unlock(&instance->reset_mutex);
460662306a36Sopenharmony_ci		rc = megasas_reset_fusion(instance->host, MFI_IO_TIMEOUT_OCR);
460762306a36Sopenharmony_ci		mutex_lock(&instance->reset_mutex);
460862306a36Sopenharmony_ci		return rc;
460962306a36Sopenharmony_ci	}
461062306a36Sopenharmony_ci
461162306a36Sopenharmony_ci	mpi_reply = (struct MPI2_SCSI_TASK_MANAGE_REPLY *) &mr_request->TMReply;
461262306a36Sopenharmony_ci	megasas_tm_response_code(instance, mpi_reply);
461362306a36Sopenharmony_ci
461462306a36Sopenharmony_ci	megasas_return_cmd(instance, cmd_mfi);
461562306a36Sopenharmony_ci	rc = SUCCESS;
461662306a36Sopenharmony_ci	switch (type) {
461762306a36Sopenharmony_ci	case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
461862306a36Sopenharmony_ci		scsi_lookup = fusion->cmd_list[smid_task - 1];
461962306a36Sopenharmony_ci
462062306a36Sopenharmony_ci		if (scsi_lookup->scmd == NULL)
462162306a36Sopenharmony_ci			break;
462262306a36Sopenharmony_ci		else {
462362306a36Sopenharmony_ci			instance->instancet->disable_intr(instance);
462462306a36Sopenharmony_ci			megasas_sync_irqs((unsigned long)instance);
462562306a36Sopenharmony_ci			instance->instancet->enable_intr(instance);
462662306a36Sopenharmony_ci			megasas_enable_irq_poll(instance);
462762306a36Sopenharmony_ci			if (scsi_lookup->scmd == NULL)
462862306a36Sopenharmony_ci				break;
462962306a36Sopenharmony_ci		}
463062306a36Sopenharmony_ci		rc = FAILED;
463162306a36Sopenharmony_ci		break;
463262306a36Sopenharmony_ci
463362306a36Sopenharmony_ci	case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
463462306a36Sopenharmony_ci		if ((channel == 0xFFFFFFFF) && (id == 0xFFFFFFFF))
463562306a36Sopenharmony_ci			break;
463662306a36Sopenharmony_ci		instance->instancet->disable_intr(instance);
463762306a36Sopenharmony_ci		megasas_sync_irqs((unsigned long)instance);
463862306a36Sopenharmony_ci		rc = megasas_track_scsiio(instance, id, channel);
463962306a36Sopenharmony_ci		instance->instancet->enable_intr(instance);
464062306a36Sopenharmony_ci		megasas_enable_irq_poll(instance);
464162306a36Sopenharmony_ci
464262306a36Sopenharmony_ci		break;
464362306a36Sopenharmony_ci	case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:
464462306a36Sopenharmony_ci	case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK:
464562306a36Sopenharmony_ci		break;
464662306a36Sopenharmony_ci	default:
464762306a36Sopenharmony_ci		rc = FAILED;
464862306a36Sopenharmony_ci		break;
464962306a36Sopenharmony_ci	}
465062306a36Sopenharmony_ci
465162306a36Sopenharmony_ci	return rc;
465262306a36Sopenharmony_ci
465362306a36Sopenharmony_ci}
465462306a36Sopenharmony_ci
465562306a36Sopenharmony_ci/*
465662306a36Sopenharmony_ci * megasas_fusion_smid_lookup : Look for fusion command corresponding to SCSI
465762306a36Sopenharmony_ci * @instance: per adapter struct
465862306a36Sopenharmony_ci *
465962306a36Sopenharmony_ci * Return Non Zero index, if SMID found in outstanding commands
466062306a36Sopenharmony_ci */
466162306a36Sopenharmony_cistatic u16 megasas_fusion_smid_lookup(struct scsi_cmnd *scmd)
466262306a36Sopenharmony_ci{
466362306a36Sopenharmony_ci	int i, ret = 0;
466462306a36Sopenharmony_ci	struct megasas_instance *instance;
466562306a36Sopenharmony_ci	struct megasas_cmd_fusion *cmd_fusion;
466662306a36Sopenharmony_ci	struct fusion_context *fusion;
466762306a36Sopenharmony_ci
466862306a36Sopenharmony_ci	instance = (struct megasas_instance *)scmd->device->host->hostdata;
466962306a36Sopenharmony_ci
467062306a36Sopenharmony_ci	fusion = instance->ctrl_context;
467162306a36Sopenharmony_ci
467262306a36Sopenharmony_ci	for (i = 0; i < instance->max_scsi_cmds; i++) {
467362306a36Sopenharmony_ci		cmd_fusion = fusion->cmd_list[i];
467462306a36Sopenharmony_ci		if (cmd_fusion->scmd && (cmd_fusion->scmd == scmd)) {
467562306a36Sopenharmony_ci			scmd_printk(KERN_NOTICE, scmd, "Abort request is for"
467662306a36Sopenharmony_ci				" SMID: %d\n", cmd_fusion->index);
467762306a36Sopenharmony_ci			ret = cmd_fusion->index;
467862306a36Sopenharmony_ci			break;
467962306a36Sopenharmony_ci		}
468062306a36Sopenharmony_ci	}
468162306a36Sopenharmony_ci
468262306a36Sopenharmony_ci	return ret;
468362306a36Sopenharmony_ci}
468462306a36Sopenharmony_ci
468562306a36Sopenharmony_ci/*
468662306a36Sopenharmony_ci* megasas_get_tm_devhandle - Get devhandle for TM request
468762306a36Sopenharmony_ci* @sdev-		     OS provided scsi device
468862306a36Sopenharmony_ci*
468962306a36Sopenharmony_ci* Returns-		     devhandle/targetID of SCSI device
469062306a36Sopenharmony_ci*/
469162306a36Sopenharmony_cistatic u16 megasas_get_tm_devhandle(struct scsi_device *sdev)
469262306a36Sopenharmony_ci{
469362306a36Sopenharmony_ci	u16 pd_index = 0;
469462306a36Sopenharmony_ci	u32 device_id;
469562306a36Sopenharmony_ci	struct megasas_instance *instance;
469662306a36Sopenharmony_ci	struct fusion_context *fusion;
469762306a36Sopenharmony_ci	struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync;
469862306a36Sopenharmony_ci	u16 devhandle = (u16)ULONG_MAX;
469962306a36Sopenharmony_ci
470062306a36Sopenharmony_ci	instance = (struct megasas_instance *)sdev->host->hostdata;
470162306a36Sopenharmony_ci	fusion = instance->ctrl_context;
470262306a36Sopenharmony_ci
470362306a36Sopenharmony_ci	if (!MEGASAS_IS_LOGICAL(sdev)) {
470462306a36Sopenharmony_ci		if (instance->use_seqnum_jbod_fp) {
470562306a36Sopenharmony_ci			pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL)
470662306a36Sopenharmony_ci				    + sdev->id;
470762306a36Sopenharmony_ci			pd_sync = (void *)fusion->pd_seq_sync
470862306a36Sopenharmony_ci					[(instance->pd_seq_map_id - 1) & 1];
470962306a36Sopenharmony_ci			devhandle = pd_sync->seq[pd_index].devHandle;
471062306a36Sopenharmony_ci		} else
471162306a36Sopenharmony_ci			sdev_printk(KERN_ERR, sdev, "Firmware expose tmCapable"
471262306a36Sopenharmony_ci				" without JBOD MAP support from %s %d\n", __func__, __LINE__);
471362306a36Sopenharmony_ci	} else {
471462306a36Sopenharmony_ci		device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL)
471562306a36Sopenharmony_ci				+ sdev->id;
471662306a36Sopenharmony_ci		devhandle = device_id;
471762306a36Sopenharmony_ci	}
471862306a36Sopenharmony_ci
471962306a36Sopenharmony_ci	return devhandle;
472062306a36Sopenharmony_ci}
472162306a36Sopenharmony_ci
472262306a36Sopenharmony_ci/*
472362306a36Sopenharmony_ci * megasas_task_abort_fusion : SCSI task abort function for fusion adapters
472462306a36Sopenharmony_ci * @scmd : pointer to scsi command object
472562306a36Sopenharmony_ci *
472662306a36Sopenharmony_ci * Return SUCCESS, if command aborted else FAILED
472762306a36Sopenharmony_ci */
472862306a36Sopenharmony_ci
472962306a36Sopenharmony_ciint megasas_task_abort_fusion(struct scsi_cmnd *scmd)
473062306a36Sopenharmony_ci{
473162306a36Sopenharmony_ci	struct megasas_instance *instance;
473262306a36Sopenharmony_ci	u16 smid, devhandle;
473362306a36Sopenharmony_ci	int ret;
473462306a36Sopenharmony_ci	struct MR_PRIV_DEVICE *mr_device_priv_data;
473562306a36Sopenharmony_ci	mr_device_priv_data = scmd->device->hostdata;
473662306a36Sopenharmony_ci
473762306a36Sopenharmony_ci	instance = (struct megasas_instance *)scmd->device->host->hostdata;
473862306a36Sopenharmony_ci
473962306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
474062306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL,"
474162306a36Sopenharmony_ci		"SCSI host:%d\n", instance->host->host_no);
474262306a36Sopenharmony_ci		ret = FAILED;
474362306a36Sopenharmony_ci		return ret;
474462306a36Sopenharmony_ci	}
474562306a36Sopenharmony_ci
474662306a36Sopenharmony_ci	if (!mr_device_priv_data) {
474762306a36Sopenharmony_ci		sdev_printk(KERN_INFO, scmd->device, "device been deleted! "
474862306a36Sopenharmony_ci			"scmd(%p)\n", scmd);
474962306a36Sopenharmony_ci		scmd->result = DID_NO_CONNECT << 16;
475062306a36Sopenharmony_ci		ret = SUCCESS;
475162306a36Sopenharmony_ci		goto out;
475262306a36Sopenharmony_ci	}
475362306a36Sopenharmony_ci
475462306a36Sopenharmony_ci	if (!mr_device_priv_data->is_tm_capable) {
475562306a36Sopenharmony_ci		ret = FAILED;
475662306a36Sopenharmony_ci		goto out;
475762306a36Sopenharmony_ci	}
475862306a36Sopenharmony_ci
475962306a36Sopenharmony_ci	mutex_lock(&instance->reset_mutex);
476062306a36Sopenharmony_ci
476162306a36Sopenharmony_ci	smid = megasas_fusion_smid_lookup(scmd);
476262306a36Sopenharmony_ci
476362306a36Sopenharmony_ci	if (!smid) {
476462306a36Sopenharmony_ci		ret = SUCCESS;
476562306a36Sopenharmony_ci		scmd_printk(KERN_NOTICE, scmd, "Command for which abort is"
476662306a36Sopenharmony_ci			" issued is not found in outstanding commands\n");
476762306a36Sopenharmony_ci		mutex_unlock(&instance->reset_mutex);
476862306a36Sopenharmony_ci		goto out;
476962306a36Sopenharmony_ci	}
477062306a36Sopenharmony_ci
477162306a36Sopenharmony_ci	devhandle = megasas_get_tm_devhandle(scmd->device);
477262306a36Sopenharmony_ci
477362306a36Sopenharmony_ci	if (devhandle == (u16)ULONG_MAX) {
477462306a36Sopenharmony_ci		ret = FAILED;
477562306a36Sopenharmony_ci		sdev_printk(KERN_INFO, scmd->device,
477662306a36Sopenharmony_ci			"task abort issued for invalid devhandle\n");
477762306a36Sopenharmony_ci		mutex_unlock(&instance->reset_mutex);
477862306a36Sopenharmony_ci		goto out;
477962306a36Sopenharmony_ci	}
478062306a36Sopenharmony_ci	sdev_printk(KERN_INFO, scmd->device,
478162306a36Sopenharmony_ci		"attempting task abort! scmd(0x%p) tm_dev_handle 0x%x\n",
478262306a36Sopenharmony_ci		scmd, devhandle);
478362306a36Sopenharmony_ci
478462306a36Sopenharmony_ci	mr_device_priv_data->tm_busy = true;
478562306a36Sopenharmony_ci	ret = megasas_issue_tm(instance, devhandle,
478662306a36Sopenharmony_ci			scmd->device->channel, scmd->device->id, smid,
478762306a36Sopenharmony_ci			MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
478862306a36Sopenharmony_ci			mr_device_priv_data);
478962306a36Sopenharmony_ci	mr_device_priv_data->tm_busy = false;
479062306a36Sopenharmony_ci
479162306a36Sopenharmony_ci	mutex_unlock(&instance->reset_mutex);
479262306a36Sopenharmony_ci	scmd_printk(KERN_INFO, scmd, "task abort %s!! scmd(0x%p)\n",
479362306a36Sopenharmony_ci			((ret == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
479462306a36Sopenharmony_ciout:
479562306a36Sopenharmony_ci	scsi_print_command(scmd);
479662306a36Sopenharmony_ci	if (megasas_dbg_lvl & TM_DEBUG)
479762306a36Sopenharmony_ci		megasas_dump_fusion_io(scmd);
479862306a36Sopenharmony_ci
479962306a36Sopenharmony_ci	return ret;
480062306a36Sopenharmony_ci}
480162306a36Sopenharmony_ci
480262306a36Sopenharmony_ci/*
480362306a36Sopenharmony_ci * megasas_reset_target_fusion : target reset function for fusion adapters
480462306a36Sopenharmony_ci * scmd: SCSI command pointer
480562306a36Sopenharmony_ci *
480662306a36Sopenharmony_ci * Returns SUCCESS if all commands associated with target aborted else FAILED
480762306a36Sopenharmony_ci */
480862306a36Sopenharmony_ci
480962306a36Sopenharmony_ciint megasas_reset_target_fusion(struct scsi_cmnd *scmd)
481062306a36Sopenharmony_ci{
481162306a36Sopenharmony_ci
481262306a36Sopenharmony_ci	struct megasas_instance *instance;
481362306a36Sopenharmony_ci	int ret = FAILED;
481462306a36Sopenharmony_ci	u16 devhandle;
481562306a36Sopenharmony_ci	struct MR_PRIV_DEVICE *mr_device_priv_data;
481662306a36Sopenharmony_ci	mr_device_priv_data = scmd->device->hostdata;
481762306a36Sopenharmony_ci
481862306a36Sopenharmony_ci	instance = (struct megasas_instance *)scmd->device->host->hostdata;
481962306a36Sopenharmony_ci
482062306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
482162306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL,"
482262306a36Sopenharmony_ci		"SCSI host:%d\n", instance->host->host_no);
482362306a36Sopenharmony_ci		ret = FAILED;
482462306a36Sopenharmony_ci		return ret;
482562306a36Sopenharmony_ci	}
482662306a36Sopenharmony_ci
482762306a36Sopenharmony_ci	if (!mr_device_priv_data) {
482862306a36Sopenharmony_ci		sdev_printk(KERN_INFO, scmd->device,
482962306a36Sopenharmony_ci			    "device been deleted! scmd: (0x%p)\n", scmd);
483062306a36Sopenharmony_ci		scmd->result = DID_NO_CONNECT << 16;
483162306a36Sopenharmony_ci		ret = SUCCESS;
483262306a36Sopenharmony_ci		goto out;
483362306a36Sopenharmony_ci	}
483462306a36Sopenharmony_ci
483562306a36Sopenharmony_ci	if (!mr_device_priv_data->is_tm_capable) {
483662306a36Sopenharmony_ci		ret = FAILED;
483762306a36Sopenharmony_ci		goto out;
483862306a36Sopenharmony_ci	}
483962306a36Sopenharmony_ci
484062306a36Sopenharmony_ci	mutex_lock(&instance->reset_mutex);
484162306a36Sopenharmony_ci	devhandle = megasas_get_tm_devhandle(scmd->device);
484262306a36Sopenharmony_ci
484362306a36Sopenharmony_ci	if (devhandle == (u16)ULONG_MAX) {
484462306a36Sopenharmony_ci		ret = FAILED;
484562306a36Sopenharmony_ci		sdev_printk(KERN_INFO, scmd->device,
484662306a36Sopenharmony_ci			"target reset issued for invalid devhandle\n");
484762306a36Sopenharmony_ci		mutex_unlock(&instance->reset_mutex);
484862306a36Sopenharmony_ci		goto out;
484962306a36Sopenharmony_ci	}
485062306a36Sopenharmony_ci
485162306a36Sopenharmony_ci	sdev_printk(KERN_INFO, scmd->device,
485262306a36Sopenharmony_ci		"attempting target reset! scmd(0x%p) tm_dev_handle: 0x%x\n",
485362306a36Sopenharmony_ci		scmd, devhandle);
485462306a36Sopenharmony_ci	mr_device_priv_data->tm_busy = true;
485562306a36Sopenharmony_ci	ret = megasas_issue_tm(instance, devhandle,
485662306a36Sopenharmony_ci			scmd->device->channel, scmd->device->id, 0,
485762306a36Sopenharmony_ci			MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
485862306a36Sopenharmony_ci			mr_device_priv_data);
485962306a36Sopenharmony_ci	mr_device_priv_data->tm_busy = false;
486062306a36Sopenharmony_ci	mutex_unlock(&instance->reset_mutex);
486162306a36Sopenharmony_ci	scmd_printk(KERN_NOTICE, scmd, "target reset %s!!\n",
486262306a36Sopenharmony_ci		(ret == SUCCESS) ? "SUCCESS" : "FAILED");
486362306a36Sopenharmony_ci
486462306a36Sopenharmony_ciout:
486562306a36Sopenharmony_ci	return ret;
486662306a36Sopenharmony_ci}
486762306a36Sopenharmony_ci
486862306a36Sopenharmony_ci/*SRIOV get other instance in cluster if any*/
486962306a36Sopenharmony_cistatic struct
487062306a36Sopenharmony_cimegasas_instance *megasas_get_peer_instance(struct megasas_instance *instance)
487162306a36Sopenharmony_ci{
487262306a36Sopenharmony_ci	int i;
487362306a36Sopenharmony_ci
487462306a36Sopenharmony_ci	for (i = 0; i < MAX_MGMT_ADAPTERS; i++) {
487562306a36Sopenharmony_ci		if (megasas_mgmt_info.instance[i] &&
487662306a36Sopenharmony_ci			(megasas_mgmt_info.instance[i] != instance) &&
487762306a36Sopenharmony_ci			 megasas_mgmt_info.instance[i]->requestorId &&
487862306a36Sopenharmony_ci			 megasas_mgmt_info.instance[i]->peerIsPresent &&
487962306a36Sopenharmony_ci			(memcmp((megasas_mgmt_info.instance[i]->clusterId),
488062306a36Sopenharmony_ci			instance->clusterId, MEGASAS_CLUSTER_ID_SIZE) == 0))
488162306a36Sopenharmony_ci			return megasas_mgmt_info.instance[i];
488262306a36Sopenharmony_ci	}
488362306a36Sopenharmony_ci	return NULL;
488462306a36Sopenharmony_ci}
488562306a36Sopenharmony_ci
488662306a36Sopenharmony_ci/* Check for a second path that is currently UP */
488762306a36Sopenharmony_ciint megasas_check_mpio_paths(struct megasas_instance *instance,
488862306a36Sopenharmony_ci	struct scsi_cmnd *scmd)
488962306a36Sopenharmony_ci{
489062306a36Sopenharmony_ci	struct megasas_instance *peer_instance = NULL;
489162306a36Sopenharmony_ci	int retval = (DID_REQUEUE << 16);
489262306a36Sopenharmony_ci
489362306a36Sopenharmony_ci	if (instance->peerIsPresent) {
489462306a36Sopenharmony_ci		peer_instance = megasas_get_peer_instance(instance);
489562306a36Sopenharmony_ci		if ((peer_instance) &&
489662306a36Sopenharmony_ci			(atomic_read(&peer_instance->adprecovery) ==
489762306a36Sopenharmony_ci			MEGASAS_HBA_OPERATIONAL))
489862306a36Sopenharmony_ci			retval = (DID_NO_CONNECT << 16);
489962306a36Sopenharmony_ci	}
490062306a36Sopenharmony_ci	return retval;
490162306a36Sopenharmony_ci}
490262306a36Sopenharmony_ci
490362306a36Sopenharmony_ci/* Core fusion reset function */
490462306a36Sopenharmony_ciint megasas_reset_fusion(struct Scsi_Host *shost, int reason)
490562306a36Sopenharmony_ci{
490662306a36Sopenharmony_ci	int retval = SUCCESS, i, j, convert = 0;
490762306a36Sopenharmony_ci	struct megasas_instance *instance;
490862306a36Sopenharmony_ci	struct megasas_cmd_fusion *cmd_fusion, *r1_cmd;
490962306a36Sopenharmony_ci	struct fusion_context *fusion;
491062306a36Sopenharmony_ci	u32 abs_state, status_reg, reset_adapter, fpio_count = 0;
491162306a36Sopenharmony_ci	u32 io_timeout_in_crash_mode = 0;
491262306a36Sopenharmony_ci	struct scsi_cmnd *scmd_local = NULL;
491362306a36Sopenharmony_ci	struct scsi_device *sdev;
491462306a36Sopenharmony_ci	int ret_target_prop = DCMD_FAILED;
491562306a36Sopenharmony_ci	bool is_target_prop = false;
491662306a36Sopenharmony_ci	bool do_adp_reset = true;
491762306a36Sopenharmony_ci	int max_reset_tries = MEGASAS_FUSION_MAX_RESET_TRIES;
491862306a36Sopenharmony_ci
491962306a36Sopenharmony_ci	instance = (struct megasas_instance *)shost->hostdata;
492062306a36Sopenharmony_ci	fusion = instance->ctrl_context;
492162306a36Sopenharmony_ci
492262306a36Sopenharmony_ci	mutex_lock(&instance->reset_mutex);
492362306a36Sopenharmony_ci
492462306a36Sopenharmony_ci	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
492562306a36Sopenharmony_ci		dev_warn(&instance->pdev->dev, "Hardware critical error, "
492662306a36Sopenharmony_ci		       "returning FAILED for scsi%d.\n",
492762306a36Sopenharmony_ci			instance->host->host_no);
492862306a36Sopenharmony_ci		mutex_unlock(&instance->reset_mutex);
492962306a36Sopenharmony_ci		return FAILED;
493062306a36Sopenharmony_ci	}
493162306a36Sopenharmony_ci	status_reg = instance->instancet->read_fw_status_reg(instance);
493262306a36Sopenharmony_ci	abs_state = status_reg & MFI_STATE_MASK;
493362306a36Sopenharmony_ci
493462306a36Sopenharmony_ci	/* IO timeout detected, forcibly put FW in FAULT state */
493562306a36Sopenharmony_ci	if (abs_state != MFI_STATE_FAULT && instance->crash_dump_buf &&
493662306a36Sopenharmony_ci		instance->crash_dump_app_support && reason) {
493762306a36Sopenharmony_ci		dev_info(&instance->pdev->dev, "IO/DCMD timeout is detected, "
493862306a36Sopenharmony_ci			"forcibly FAULT Firmware\n");
493962306a36Sopenharmony_ci		atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
494062306a36Sopenharmony_ci		status_reg = megasas_readl(instance, &instance->reg_set->doorbell);
494162306a36Sopenharmony_ci		writel(status_reg | MFI_STATE_FORCE_OCR,
494262306a36Sopenharmony_ci			&instance->reg_set->doorbell);
494362306a36Sopenharmony_ci		readl(&instance->reg_set->doorbell);
494462306a36Sopenharmony_ci		mutex_unlock(&instance->reset_mutex);
494562306a36Sopenharmony_ci		do {
494662306a36Sopenharmony_ci			ssleep(3);
494762306a36Sopenharmony_ci			io_timeout_in_crash_mode++;
494862306a36Sopenharmony_ci			dev_dbg(&instance->pdev->dev, "waiting for [%d] "
494962306a36Sopenharmony_ci				"seconds for crash dump collection and OCR "
495062306a36Sopenharmony_ci				"to be done\n", (io_timeout_in_crash_mode * 3));
495162306a36Sopenharmony_ci		} while ((atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) &&
495262306a36Sopenharmony_ci			(io_timeout_in_crash_mode < 80));
495362306a36Sopenharmony_ci
495462306a36Sopenharmony_ci		if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL) {
495562306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "OCR done for IO "
495662306a36Sopenharmony_ci				"timeout case\n");
495762306a36Sopenharmony_ci			retval = SUCCESS;
495862306a36Sopenharmony_ci		} else {
495962306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "Controller is not "
496062306a36Sopenharmony_ci				"operational after 240 seconds wait for IO "
496162306a36Sopenharmony_ci				"timeout case in FW crash dump mode\n do "
496262306a36Sopenharmony_ci				"OCR/kill adapter\n");
496362306a36Sopenharmony_ci			retval = megasas_reset_fusion(shost, 0);
496462306a36Sopenharmony_ci		}
496562306a36Sopenharmony_ci		return retval;
496662306a36Sopenharmony_ci	}
496762306a36Sopenharmony_ci
496862306a36Sopenharmony_ci	if (instance->requestorId && !instance->skip_heartbeat_timer_del)
496962306a36Sopenharmony_ci		del_timer_sync(&instance->sriov_heartbeat_timer);
497062306a36Sopenharmony_ci	set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
497162306a36Sopenharmony_ci	set_bit(MEGASAS_FUSION_OCR_NOT_POSSIBLE, &instance->reset_flags);
497262306a36Sopenharmony_ci	atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_POLLING);
497362306a36Sopenharmony_ci	instance->instancet->disable_intr(instance);
497462306a36Sopenharmony_ci	megasas_sync_irqs((unsigned long)instance);
497562306a36Sopenharmony_ci
497662306a36Sopenharmony_ci	/* First try waiting for commands to complete */
497762306a36Sopenharmony_ci	if (megasas_wait_for_outstanding_fusion(instance, reason,
497862306a36Sopenharmony_ci						&convert)) {
497962306a36Sopenharmony_ci		atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
498062306a36Sopenharmony_ci		dev_warn(&instance->pdev->dev, "resetting fusion "
498162306a36Sopenharmony_ci		       "adapter scsi%d.\n", instance->host->host_no);
498262306a36Sopenharmony_ci		if (convert)
498362306a36Sopenharmony_ci			reason = 0;
498462306a36Sopenharmony_ci
498562306a36Sopenharmony_ci		if (megasas_dbg_lvl & OCR_DEBUG)
498662306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "\nPending SCSI commands:\n");
498762306a36Sopenharmony_ci
498862306a36Sopenharmony_ci		/* Now return commands back to the OS */
498962306a36Sopenharmony_ci		for (i = 0 ; i < instance->max_scsi_cmds; i++) {
499062306a36Sopenharmony_ci			cmd_fusion = fusion->cmd_list[i];
499162306a36Sopenharmony_ci			/*check for extra commands issued by driver*/
499262306a36Sopenharmony_ci			if (instance->adapter_type >= VENTURA_SERIES) {
499362306a36Sopenharmony_ci				r1_cmd = fusion->cmd_list[i + instance->max_fw_cmds];
499462306a36Sopenharmony_ci				megasas_return_cmd_fusion(instance, r1_cmd);
499562306a36Sopenharmony_ci			}
499662306a36Sopenharmony_ci			scmd_local = cmd_fusion->scmd;
499762306a36Sopenharmony_ci			if (cmd_fusion->scmd) {
499862306a36Sopenharmony_ci				if (megasas_dbg_lvl & OCR_DEBUG) {
499962306a36Sopenharmony_ci					sdev_printk(KERN_INFO,
500062306a36Sopenharmony_ci						cmd_fusion->scmd->device, "SMID: 0x%x\n",
500162306a36Sopenharmony_ci						cmd_fusion->index);
500262306a36Sopenharmony_ci					megasas_dump_fusion_io(cmd_fusion->scmd);
500362306a36Sopenharmony_ci				}
500462306a36Sopenharmony_ci
500562306a36Sopenharmony_ci				if (cmd_fusion->io_request->Function ==
500662306a36Sopenharmony_ci					MPI2_FUNCTION_SCSI_IO_REQUEST)
500762306a36Sopenharmony_ci					fpio_count++;
500862306a36Sopenharmony_ci
500962306a36Sopenharmony_ci				scmd_local->result =
501062306a36Sopenharmony_ci					megasas_check_mpio_paths(instance,
501162306a36Sopenharmony_ci							scmd_local);
501262306a36Sopenharmony_ci				if (instance->ldio_threshold &&
501362306a36Sopenharmony_ci					megasas_cmd_type(scmd_local) == READ_WRITE_LDIO)
501462306a36Sopenharmony_ci					atomic_dec(&instance->ldio_outstanding);
501562306a36Sopenharmony_ci				megasas_return_cmd_fusion(instance, cmd_fusion);
501662306a36Sopenharmony_ci				scsi_dma_unmap(scmd_local);
501762306a36Sopenharmony_ci				scsi_done(scmd_local);
501862306a36Sopenharmony_ci			}
501962306a36Sopenharmony_ci		}
502062306a36Sopenharmony_ci
502162306a36Sopenharmony_ci		dev_info(&instance->pdev->dev, "Outstanding fastpath IOs: %d\n",
502262306a36Sopenharmony_ci			fpio_count);
502362306a36Sopenharmony_ci
502462306a36Sopenharmony_ci		atomic_set(&instance->fw_outstanding, 0);
502562306a36Sopenharmony_ci
502662306a36Sopenharmony_ci		status_reg = instance->instancet->read_fw_status_reg(instance);
502762306a36Sopenharmony_ci		abs_state = status_reg & MFI_STATE_MASK;
502862306a36Sopenharmony_ci		reset_adapter = status_reg & MFI_RESET_ADAPTER;
502962306a36Sopenharmony_ci		if (instance->disableOnlineCtrlReset ||
503062306a36Sopenharmony_ci		    (abs_state == MFI_STATE_FAULT && !reset_adapter)) {
503162306a36Sopenharmony_ci			/* Reset not supported, kill adapter */
503262306a36Sopenharmony_ci			dev_warn(&instance->pdev->dev, "Reset not supported"
503362306a36Sopenharmony_ci			       ", killing adapter scsi%d.\n",
503462306a36Sopenharmony_ci				instance->host->host_no);
503562306a36Sopenharmony_ci			goto kill_hba;
503662306a36Sopenharmony_ci		}
503762306a36Sopenharmony_ci
503862306a36Sopenharmony_ci		/* Let SR-IOV VF & PF sync up if there was a HB failure */
503962306a36Sopenharmony_ci		if (instance->requestorId && !reason) {
504062306a36Sopenharmony_ci			msleep(MEGASAS_OCR_SETTLE_TIME_VF);
504162306a36Sopenharmony_ci			do_adp_reset = false;
504262306a36Sopenharmony_ci			max_reset_tries = MEGASAS_SRIOV_MAX_RESET_TRIES_VF;
504362306a36Sopenharmony_ci		}
504462306a36Sopenharmony_ci
504562306a36Sopenharmony_ci		/* Now try to reset the chip */
504662306a36Sopenharmony_ci		for (i = 0; i < max_reset_tries; i++) {
504762306a36Sopenharmony_ci			/*
504862306a36Sopenharmony_ci			 * Do adp reset and wait for
504962306a36Sopenharmony_ci			 * controller to transition to ready
505062306a36Sopenharmony_ci			 */
505162306a36Sopenharmony_ci			if (megasas_adp_reset_wait_for_ready(instance,
505262306a36Sopenharmony_ci				do_adp_reset, 1) == FAILED)
505362306a36Sopenharmony_ci				continue;
505462306a36Sopenharmony_ci
505562306a36Sopenharmony_ci			/* Wait for FW to become ready */
505662306a36Sopenharmony_ci			if (megasas_transition_to_ready(instance, 1)) {
505762306a36Sopenharmony_ci				dev_warn(&instance->pdev->dev,
505862306a36Sopenharmony_ci					"Failed to transition controller to ready for "
505962306a36Sopenharmony_ci					"scsi%d.\n", instance->host->host_no);
506062306a36Sopenharmony_ci				continue;
506162306a36Sopenharmony_ci			}
506262306a36Sopenharmony_ci			megasas_reset_reply_desc(instance);
506362306a36Sopenharmony_ci			megasas_fusion_update_can_queue(instance, OCR_CONTEXT);
506462306a36Sopenharmony_ci
506562306a36Sopenharmony_ci			if (megasas_ioc_init_fusion(instance)) {
506662306a36Sopenharmony_ci				continue;
506762306a36Sopenharmony_ci			}
506862306a36Sopenharmony_ci
506962306a36Sopenharmony_ci			if (megasas_get_ctrl_info(instance)) {
507062306a36Sopenharmony_ci				dev_info(&instance->pdev->dev,
507162306a36Sopenharmony_ci					"Failed from %s %d\n",
507262306a36Sopenharmony_ci					__func__, __LINE__);
507362306a36Sopenharmony_ci				goto kill_hba;
507462306a36Sopenharmony_ci			}
507562306a36Sopenharmony_ci
507662306a36Sopenharmony_ci			megasas_refire_mgmt_cmd(instance,
507762306a36Sopenharmony_ci						(i == (MEGASAS_FUSION_MAX_RESET_TRIES - 1)
507862306a36Sopenharmony_ci							? 1 : 0));
507962306a36Sopenharmony_ci
508062306a36Sopenharmony_ci			/* Reset load balance info */
508162306a36Sopenharmony_ci			if (fusion->load_balance_info)
508262306a36Sopenharmony_ci				memset(fusion->load_balance_info, 0,
508362306a36Sopenharmony_ci				       (sizeof(struct LD_LOAD_BALANCE_INFO) *
508462306a36Sopenharmony_ci				       MAX_LOGICAL_DRIVES_EXT));
508562306a36Sopenharmony_ci
508662306a36Sopenharmony_ci			if (!megasas_get_map_info(instance)) {
508762306a36Sopenharmony_ci				megasas_sync_map_info(instance);
508862306a36Sopenharmony_ci			} else {
508962306a36Sopenharmony_ci				/*
509062306a36Sopenharmony_ci				 * Return pending polled mode cmds before
509162306a36Sopenharmony_ci				 * retrying OCR
509262306a36Sopenharmony_ci				 */
509362306a36Sopenharmony_ci				megasas_return_polled_cmds(instance);
509462306a36Sopenharmony_ci				continue;
509562306a36Sopenharmony_ci			}
509662306a36Sopenharmony_ci
509762306a36Sopenharmony_ci			megasas_setup_jbod_map(instance);
509862306a36Sopenharmony_ci
509962306a36Sopenharmony_ci			/* reset stream detection array */
510062306a36Sopenharmony_ci			if (instance->adapter_type >= VENTURA_SERIES) {
510162306a36Sopenharmony_ci				for (j = 0; j < MAX_LOGICAL_DRIVES_EXT; ++j) {
510262306a36Sopenharmony_ci					memset(fusion->stream_detect_by_ld[j],
510362306a36Sopenharmony_ci					       0, sizeof(struct LD_STREAM_DETECT));
510462306a36Sopenharmony_ci					fusion->stream_detect_by_ld[j]->mru_bit_map
510562306a36Sopenharmony_ci						= MR_STREAM_BITMAP;
510662306a36Sopenharmony_ci				}
510762306a36Sopenharmony_ci			}
510862306a36Sopenharmony_ci
510962306a36Sopenharmony_ci			clear_bit(MEGASAS_FUSION_IN_RESET,
511062306a36Sopenharmony_ci				  &instance->reset_flags);
511162306a36Sopenharmony_ci			instance->instancet->enable_intr(instance);
511262306a36Sopenharmony_ci			megasas_enable_irq_poll(instance);
511362306a36Sopenharmony_ci			shost_for_each_device(sdev, shost) {
511462306a36Sopenharmony_ci				if ((instance->tgt_prop) &&
511562306a36Sopenharmony_ci				    (instance->nvme_page_size))
511662306a36Sopenharmony_ci					ret_target_prop = megasas_get_target_prop(instance, sdev);
511762306a36Sopenharmony_ci
511862306a36Sopenharmony_ci				is_target_prop = (ret_target_prop == DCMD_SUCCESS) ? true : false;
511962306a36Sopenharmony_ci				megasas_set_dynamic_target_properties(sdev, is_target_prop);
512062306a36Sopenharmony_ci			}
512162306a36Sopenharmony_ci
512262306a36Sopenharmony_ci			status_reg = instance->instancet->read_fw_status_reg
512362306a36Sopenharmony_ci					(instance);
512462306a36Sopenharmony_ci			abs_state = status_reg & MFI_STATE_MASK;
512562306a36Sopenharmony_ci			if (abs_state != MFI_STATE_OPERATIONAL) {
512662306a36Sopenharmony_ci				dev_info(&instance->pdev->dev,
512762306a36Sopenharmony_ci					 "Adapter is not OPERATIONAL, state 0x%x for scsi:%d\n",
512862306a36Sopenharmony_ci					 abs_state, instance->host->host_no);
512962306a36Sopenharmony_ci				goto out;
513062306a36Sopenharmony_ci			}
513162306a36Sopenharmony_ci			atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
513262306a36Sopenharmony_ci
513362306a36Sopenharmony_ci			dev_info(&instance->pdev->dev,
513462306a36Sopenharmony_ci				 "Adapter is OPERATIONAL for scsi:%d\n",
513562306a36Sopenharmony_ci				 instance->host->host_no);
513662306a36Sopenharmony_ci
513762306a36Sopenharmony_ci			/* Restart SR-IOV heartbeat */
513862306a36Sopenharmony_ci			if (instance->requestorId) {
513962306a36Sopenharmony_ci				if (!megasas_sriov_start_heartbeat(instance, 0))
514062306a36Sopenharmony_ci					megasas_start_timer(instance);
514162306a36Sopenharmony_ci				else
514262306a36Sopenharmony_ci					instance->skip_heartbeat_timer_del = 1;
514362306a36Sopenharmony_ci			}
514462306a36Sopenharmony_ci
514562306a36Sopenharmony_ci			if (instance->crash_dump_drv_support &&
514662306a36Sopenharmony_ci				instance->crash_dump_app_support)
514762306a36Sopenharmony_ci				megasas_set_crash_dump_params(instance,
514862306a36Sopenharmony_ci					MR_CRASH_BUF_TURN_ON);
514962306a36Sopenharmony_ci			else
515062306a36Sopenharmony_ci				megasas_set_crash_dump_params(instance,
515162306a36Sopenharmony_ci					MR_CRASH_BUF_TURN_OFF);
515262306a36Sopenharmony_ci
515362306a36Sopenharmony_ci			if (instance->snapdump_wait_time) {
515462306a36Sopenharmony_ci				megasas_get_snapdump_properties(instance);
515562306a36Sopenharmony_ci				dev_info(&instance->pdev->dev,
515662306a36Sopenharmony_ci					 "Snap dump wait time\t: %d\n",
515762306a36Sopenharmony_ci					 instance->snapdump_wait_time);
515862306a36Sopenharmony_ci			}
515962306a36Sopenharmony_ci
516062306a36Sopenharmony_ci			retval = SUCCESS;
516162306a36Sopenharmony_ci
516262306a36Sopenharmony_ci			/* Adapter reset completed successfully */
516362306a36Sopenharmony_ci			dev_warn(&instance->pdev->dev,
516462306a36Sopenharmony_ci				 "Reset successful for scsi%d.\n",
516562306a36Sopenharmony_ci				 instance->host->host_no);
516662306a36Sopenharmony_ci
516762306a36Sopenharmony_ci			goto out;
516862306a36Sopenharmony_ci		}
516962306a36Sopenharmony_ci		/* Reset failed, kill the adapter */
517062306a36Sopenharmony_ci		dev_warn(&instance->pdev->dev, "Reset failed, killing "
517162306a36Sopenharmony_ci		       "adapter scsi%d.\n", instance->host->host_no);
517262306a36Sopenharmony_ci		goto kill_hba;
517362306a36Sopenharmony_ci	} else {
517462306a36Sopenharmony_ci		/* For VF: Restart HB timer if we didn't OCR */
517562306a36Sopenharmony_ci		if (instance->requestorId) {
517662306a36Sopenharmony_ci			megasas_start_timer(instance);
517762306a36Sopenharmony_ci		}
517862306a36Sopenharmony_ci		clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
517962306a36Sopenharmony_ci		instance->instancet->enable_intr(instance);
518062306a36Sopenharmony_ci		megasas_enable_irq_poll(instance);
518162306a36Sopenharmony_ci		atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
518262306a36Sopenharmony_ci		goto out;
518362306a36Sopenharmony_ci	}
518462306a36Sopenharmony_cikill_hba:
518562306a36Sopenharmony_ci	megaraid_sas_kill_hba(instance);
518662306a36Sopenharmony_ci	megasas_enable_irq_poll(instance);
518762306a36Sopenharmony_ci	instance->skip_heartbeat_timer_del = 1;
518862306a36Sopenharmony_ci	retval = FAILED;
518962306a36Sopenharmony_ciout:
519062306a36Sopenharmony_ci	clear_bit(MEGASAS_FUSION_OCR_NOT_POSSIBLE, &instance->reset_flags);
519162306a36Sopenharmony_ci	mutex_unlock(&instance->reset_mutex);
519262306a36Sopenharmony_ci	return retval;
519362306a36Sopenharmony_ci}
519462306a36Sopenharmony_ci
519562306a36Sopenharmony_ci/* Fusion Crash dump collection */
519662306a36Sopenharmony_cistatic void  megasas_fusion_crash_dump(struct megasas_instance *instance)
519762306a36Sopenharmony_ci{
519862306a36Sopenharmony_ci	u32 status_reg;
519962306a36Sopenharmony_ci	u8 partial_copy = 0;
520062306a36Sopenharmony_ci	int wait = 0;
520162306a36Sopenharmony_ci
520262306a36Sopenharmony_ci
520362306a36Sopenharmony_ci	status_reg = instance->instancet->read_fw_status_reg(instance);
520462306a36Sopenharmony_ci
520562306a36Sopenharmony_ci	/*
520662306a36Sopenharmony_ci	 * Allocate host crash buffers to copy data from 1 MB DMA crash buffer
520762306a36Sopenharmony_ci	 * to host crash buffers
520862306a36Sopenharmony_ci	 */
520962306a36Sopenharmony_ci	if (instance->drv_buf_index == 0) {
521062306a36Sopenharmony_ci		/* Buffer is already allocated for old Crash dump.
521162306a36Sopenharmony_ci		 * Do OCR and do not wait for crash dump collection
521262306a36Sopenharmony_ci		 */
521362306a36Sopenharmony_ci		if (instance->drv_buf_alloc) {
521462306a36Sopenharmony_ci			dev_info(&instance->pdev->dev, "earlier crash dump is "
521562306a36Sopenharmony_ci				"not yet copied by application, ignoring this "
521662306a36Sopenharmony_ci				"crash dump and initiating OCR\n");
521762306a36Sopenharmony_ci			status_reg |= MFI_STATE_CRASH_DUMP_DONE;
521862306a36Sopenharmony_ci			writel(status_reg,
521962306a36Sopenharmony_ci				&instance->reg_set->outbound_scratch_pad_0);
522062306a36Sopenharmony_ci			readl(&instance->reg_set->outbound_scratch_pad_0);
522162306a36Sopenharmony_ci			return;
522262306a36Sopenharmony_ci		}
522362306a36Sopenharmony_ci		megasas_alloc_host_crash_buffer(instance);
522462306a36Sopenharmony_ci		dev_info(&instance->pdev->dev, "Number of host crash buffers "
522562306a36Sopenharmony_ci			"allocated: %d\n", instance->drv_buf_alloc);
522662306a36Sopenharmony_ci	}
522762306a36Sopenharmony_ci
522862306a36Sopenharmony_ci	while (!(status_reg & MFI_STATE_CRASH_DUMP_DONE) &&
522962306a36Sopenharmony_ci	       (wait < MEGASAS_WATCHDOG_WAIT_COUNT)) {
523062306a36Sopenharmony_ci		if (!(status_reg & MFI_STATE_DMADONE)) {
523162306a36Sopenharmony_ci			/*
523262306a36Sopenharmony_ci			 * Next crash dump buffer is not yet DMA'd by FW
523362306a36Sopenharmony_ci			 * Check after 10ms. Wait for 1 second for FW to
523462306a36Sopenharmony_ci			 * post the next buffer. If not bail out.
523562306a36Sopenharmony_ci			 */
523662306a36Sopenharmony_ci			wait++;
523762306a36Sopenharmony_ci			msleep(MEGASAS_WAIT_FOR_NEXT_DMA_MSECS);
523862306a36Sopenharmony_ci			status_reg = instance->instancet->read_fw_status_reg(
523962306a36Sopenharmony_ci					instance);
524062306a36Sopenharmony_ci			continue;
524162306a36Sopenharmony_ci		}
524262306a36Sopenharmony_ci
524362306a36Sopenharmony_ci		wait = 0;
524462306a36Sopenharmony_ci		if (instance->drv_buf_index >= instance->drv_buf_alloc) {
524562306a36Sopenharmony_ci			dev_info(&instance->pdev->dev,
524662306a36Sopenharmony_ci				 "Driver is done copying the buffer: %d\n",
524762306a36Sopenharmony_ci				 instance->drv_buf_alloc);
524862306a36Sopenharmony_ci			status_reg |= MFI_STATE_CRASH_DUMP_DONE;
524962306a36Sopenharmony_ci			partial_copy = 1;
525062306a36Sopenharmony_ci			break;
525162306a36Sopenharmony_ci		} else {
525262306a36Sopenharmony_ci			memcpy(instance->crash_buf[instance->drv_buf_index],
525362306a36Sopenharmony_ci			       instance->crash_dump_buf, CRASH_DMA_BUF_SIZE);
525462306a36Sopenharmony_ci			instance->drv_buf_index++;
525562306a36Sopenharmony_ci			status_reg &= ~MFI_STATE_DMADONE;
525662306a36Sopenharmony_ci		}
525762306a36Sopenharmony_ci
525862306a36Sopenharmony_ci		writel(status_reg, &instance->reg_set->outbound_scratch_pad_0);
525962306a36Sopenharmony_ci		readl(&instance->reg_set->outbound_scratch_pad_0);
526062306a36Sopenharmony_ci
526162306a36Sopenharmony_ci		msleep(MEGASAS_WAIT_FOR_NEXT_DMA_MSECS);
526262306a36Sopenharmony_ci		status_reg = instance->instancet->read_fw_status_reg(instance);
526362306a36Sopenharmony_ci	}
526462306a36Sopenharmony_ci
526562306a36Sopenharmony_ci	if (status_reg & MFI_STATE_CRASH_DUMP_DONE) {
526662306a36Sopenharmony_ci		dev_info(&instance->pdev->dev, "Crash Dump is available,number "
526762306a36Sopenharmony_ci			"of copied buffers: %d\n", instance->drv_buf_index);
526862306a36Sopenharmony_ci		instance->fw_crash_buffer_size =  instance->drv_buf_index;
526962306a36Sopenharmony_ci		instance->fw_crash_state = AVAILABLE;
527062306a36Sopenharmony_ci		instance->drv_buf_index = 0;
527162306a36Sopenharmony_ci		writel(status_reg, &instance->reg_set->outbound_scratch_pad_0);
527262306a36Sopenharmony_ci		readl(&instance->reg_set->outbound_scratch_pad_0);
527362306a36Sopenharmony_ci		if (!partial_copy)
527462306a36Sopenharmony_ci			megasas_reset_fusion(instance->host, 0);
527562306a36Sopenharmony_ci	}
527662306a36Sopenharmony_ci}
527762306a36Sopenharmony_ci
527862306a36Sopenharmony_ci
527962306a36Sopenharmony_ci/* Fusion OCR work queue */
528062306a36Sopenharmony_civoid megasas_fusion_ocr_wq(struct work_struct *work)
528162306a36Sopenharmony_ci{
528262306a36Sopenharmony_ci	struct megasas_instance *instance =
528362306a36Sopenharmony_ci		container_of(work, struct megasas_instance, work_init);
528462306a36Sopenharmony_ci
528562306a36Sopenharmony_ci	megasas_reset_fusion(instance->host, 0);
528662306a36Sopenharmony_ci}
528762306a36Sopenharmony_ci
528862306a36Sopenharmony_ci/* Allocate fusion context */
528962306a36Sopenharmony_ciint
529062306a36Sopenharmony_cimegasas_alloc_fusion_context(struct megasas_instance *instance)
529162306a36Sopenharmony_ci{
529262306a36Sopenharmony_ci	struct fusion_context *fusion;
529362306a36Sopenharmony_ci
529462306a36Sopenharmony_ci	instance->ctrl_context = kzalloc(sizeof(struct fusion_context),
529562306a36Sopenharmony_ci					 GFP_KERNEL);
529662306a36Sopenharmony_ci	if (!instance->ctrl_context) {
529762306a36Sopenharmony_ci		dev_err(&instance->pdev->dev, "Failed from %s %d\n",
529862306a36Sopenharmony_ci			__func__, __LINE__);
529962306a36Sopenharmony_ci		return -ENOMEM;
530062306a36Sopenharmony_ci	}
530162306a36Sopenharmony_ci
530262306a36Sopenharmony_ci	fusion = instance->ctrl_context;
530362306a36Sopenharmony_ci
530462306a36Sopenharmony_ci	fusion->log_to_span_pages = get_order(MAX_LOGICAL_DRIVES_EXT *
530562306a36Sopenharmony_ci					      sizeof(LD_SPAN_INFO));
530662306a36Sopenharmony_ci	fusion->log_to_span =
530762306a36Sopenharmony_ci		(PLD_SPAN_INFO)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
530862306a36Sopenharmony_ci						fusion->log_to_span_pages);
530962306a36Sopenharmony_ci	if (!fusion->log_to_span) {
531062306a36Sopenharmony_ci		fusion->log_to_span =
531162306a36Sopenharmony_ci			vzalloc(array_size(MAX_LOGICAL_DRIVES_EXT,
531262306a36Sopenharmony_ci					   sizeof(LD_SPAN_INFO)));
531362306a36Sopenharmony_ci		if (!fusion->log_to_span) {
531462306a36Sopenharmony_ci			dev_err(&instance->pdev->dev, "Failed from %s %d\n",
531562306a36Sopenharmony_ci				__func__, __LINE__);
531662306a36Sopenharmony_ci			return -ENOMEM;
531762306a36Sopenharmony_ci		}
531862306a36Sopenharmony_ci	}
531962306a36Sopenharmony_ci
532062306a36Sopenharmony_ci	fusion->load_balance_info_pages = get_order(MAX_LOGICAL_DRIVES_EXT *
532162306a36Sopenharmony_ci		sizeof(struct LD_LOAD_BALANCE_INFO));
532262306a36Sopenharmony_ci	fusion->load_balance_info =
532362306a36Sopenharmony_ci		(struct LD_LOAD_BALANCE_INFO *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
532462306a36Sopenharmony_ci		fusion->load_balance_info_pages);
532562306a36Sopenharmony_ci	if (!fusion->load_balance_info) {
532662306a36Sopenharmony_ci		fusion->load_balance_info =
532762306a36Sopenharmony_ci			vzalloc(array_size(MAX_LOGICAL_DRIVES_EXT,
532862306a36Sopenharmony_ci					   sizeof(struct LD_LOAD_BALANCE_INFO)));
532962306a36Sopenharmony_ci		if (!fusion->load_balance_info)
533062306a36Sopenharmony_ci			dev_err(&instance->pdev->dev, "Failed to allocate load_balance_info, "
533162306a36Sopenharmony_ci				"continuing without Load Balance support\n");
533262306a36Sopenharmony_ci	}
533362306a36Sopenharmony_ci
533462306a36Sopenharmony_ci	return 0;
533562306a36Sopenharmony_ci}
533662306a36Sopenharmony_ci
533762306a36Sopenharmony_civoid
533862306a36Sopenharmony_cimegasas_free_fusion_context(struct megasas_instance *instance)
533962306a36Sopenharmony_ci{
534062306a36Sopenharmony_ci	struct fusion_context *fusion = instance->ctrl_context;
534162306a36Sopenharmony_ci
534262306a36Sopenharmony_ci	if (fusion) {
534362306a36Sopenharmony_ci		if (fusion->load_balance_info) {
534462306a36Sopenharmony_ci			if (is_vmalloc_addr(fusion->load_balance_info))
534562306a36Sopenharmony_ci				vfree(fusion->load_balance_info);
534662306a36Sopenharmony_ci			else
534762306a36Sopenharmony_ci				free_pages((ulong)fusion->load_balance_info,
534862306a36Sopenharmony_ci					fusion->load_balance_info_pages);
534962306a36Sopenharmony_ci		}
535062306a36Sopenharmony_ci
535162306a36Sopenharmony_ci		if (fusion->log_to_span) {
535262306a36Sopenharmony_ci			if (is_vmalloc_addr(fusion->log_to_span))
535362306a36Sopenharmony_ci				vfree(fusion->log_to_span);
535462306a36Sopenharmony_ci			else
535562306a36Sopenharmony_ci				free_pages((ulong)fusion->log_to_span,
535662306a36Sopenharmony_ci					   fusion->log_to_span_pages);
535762306a36Sopenharmony_ci		}
535862306a36Sopenharmony_ci
535962306a36Sopenharmony_ci		kfree(fusion);
536062306a36Sopenharmony_ci	}
536162306a36Sopenharmony_ci}
536262306a36Sopenharmony_ci
536362306a36Sopenharmony_cistruct megasas_instance_template megasas_instance_template_fusion = {
536462306a36Sopenharmony_ci	.enable_intr = megasas_enable_intr_fusion,
536562306a36Sopenharmony_ci	.disable_intr = megasas_disable_intr_fusion,
536662306a36Sopenharmony_ci	.clear_intr = megasas_clear_intr_fusion,
536762306a36Sopenharmony_ci	.read_fw_status_reg = megasas_read_fw_status_reg_fusion,
536862306a36Sopenharmony_ci	.adp_reset = megasas_adp_reset_fusion,
536962306a36Sopenharmony_ci	.check_reset = megasas_check_reset_fusion,
537062306a36Sopenharmony_ci	.service_isr = megasas_isr_fusion,
537162306a36Sopenharmony_ci	.tasklet = megasas_complete_cmd_dpc_fusion,
537262306a36Sopenharmony_ci	.init_adapter = megasas_init_adapter_fusion,
537362306a36Sopenharmony_ci	.build_and_issue_cmd = megasas_build_and_issue_cmd_fusion,
537462306a36Sopenharmony_ci	.issue_dcmd = megasas_issue_dcmd_fusion,
537562306a36Sopenharmony_ci};
5376