162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * This is the Fusion MPT base driver providing common API layer interface
362306a36Sopenharmony_ci * for access to MPT (Message Passing Technology) firmware.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * This code is based on drivers/scsi/mpt3sas/mpt3sas_base.c
662306a36Sopenharmony_ci * Copyright (C) 2012-2014  LSI Corporation
762306a36Sopenharmony_ci * Copyright (C) 2013-2014 Avago Technologies
862306a36Sopenharmony_ci *  (mailto: MPT-FusionLinux.pdl@avagotech.com)
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or
1162306a36Sopenharmony_ci * modify it under the terms of the GNU General Public License
1262306a36Sopenharmony_ci * as published by the Free Software Foundation; either version 2
1362306a36Sopenharmony_ci * of the License, or (at your option) any later version.
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * This program is distributed in the hope that it will be useful,
1662306a36Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
1762306a36Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1862306a36Sopenharmony_ci * GNU General Public License for more details.
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci * NO WARRANTY
2162306a36Sopenharmony_ci * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
2262306a36Sopenharmony_ci * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
2362306a36Sopenharmony_ci * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
2462306a36Sopenharmony_ci * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
2562306a36Sopenharmony_ci * solely responsible for determining the appropriateness of using and
2662306a36Sopenharmony_ci * distributing the Program and assumes all risks associated with its
2762306a36Sopenharmony_ci * exercise of rights under this Agreement, including but not limited to
2862306a36Sopenharmony_ci * the risks and costs of program errors, damage to or loss of data,
2962306a36Sopenharmony_ci * programs or equipment, and unavailability or interruption of operations.
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci * DISCLAIMER OF LIABILITY
3262306a36Sopenharmony_ci * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
3362306a36Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3462306a36Sopenharmony_ci * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
3562306a36Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
3662306a36Sopenharmony_ci * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
3762306a36Sopenharmony_ci * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
3862306a36Sopenharmony_ci * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci * You should have received a copy of the GNU General Public License
4162306a36Sopenharmony_ci * along with this program; if not, write to the Free Software
4262306a36Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
4362306a36Sopenharmony_ci * USA.
4462306a36Sopenharmony_ci */
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#include <linux/kernel.h>
4762306a36Sopenharmony_ci#include <linux/module.h>
4862306a36Sopenharmony_ci#include <linux/errno.h>
4962306a36Sopenharmony_ci#include <linux/init.h>
5062306a36Sopenharmony_ci#include <linux/slab.h>
5162306a36Sopenharmony_ci#include <linux/types.h>
5262306a36Sopenharmony_ci#include <linux/pci.h>
5362306a36Sopenharmony_ci#include <linux/kdev_t.h>
5462306a36Sopenharmony_ci#include <linux/blkdev.h>
5562306a36Sopenharmony_ci#include <linux/delay.h>
5662306a36Sopenharmony_ci#include <linux/interrupt.h>
5762306a36Sopenharmony_ci#include <linux/dma-mapping.h>
5862306a36Sopenharmony_ci#include <linux/io.h>
5962306a36Sopenharmony_ci#include <linux/time.h>
6062306a36Sopenharmony_ci#include <linux/ktime.h>
6162306a36Sopenharmony_ci#include <linux/kthread.h>
6262306a36Sopenharmony_ci#include <asm/page.h>        /* To get host page size per arch */
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#include "mpt3sas_base.h"
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic MPT_CALLBACK	mpt_callbacks[MPT_MAX_CALLBACKS];
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci#define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci /* maximum controller queue depth */
7362306a36Sopenharmony_ci#define MAX_HBA_QUEUE_DEPTH	30000
7462306a36Sopenharmony_ci#define MAX_CHAIN_DEPTH		100000
7562306a36Sopenharmony_cistatic int max_queue_depth = -1;
7662306a36Sopenharmony_cimodule_param(max_queue_depth, int, 0444);
7762306a36Sopenharmony_ciMODULE_PARM_DESC(max_queue_depth, " max controller queue depth ");
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic int max_sgl_entries = -1;
8062306a36Sopenharmony_cimodule_param(max_sgl_entries, int, 0444);
8162306a36Sopenharmony_ciMODULE_PARM_DESC(max_sgl_entries, " max sg entries ");
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic int msix_disable = -1;
8462306a36Sopenharmony_cimodule_param(msix_disable, int, 0444);
8562306a36Sopenharmony_ciMODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)");
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic int smp_affinity_enable = 1;
8862306a36Sopenharmony_cimodule_param(smp_affinity_enable, int, 0444);
8962306a36Sopenharmony_ciMODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disable Default: enable(1)");
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic int max_msix_vectors = -1;
9262306a36Sopenharmony_cimodule_param(max_msix_vectors, int, 0444);
9362306a36Sopenharmony_ciMODULE_PARM_DESC(max_msix_vectors,
9462306a36Sopenharmony_ci	" max msix vectors");
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic int irqpoll_weight = -1;
9762306a36Sopenharmony_cimodule_param(irqpoll_weight, int, 0444);
9862306a36Sopenharmony_ciMODULE_PARM_DESC(irqpoll_weight,
9962306a36Sopenharmony_ci	"irq poll weight (default= one fourth of HBA queue depth)");
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic int mpt3sas_fwfault_debug;
10262306a36Sopenharmony_ciMODULE_PARM_DESC(mpt3sas_fwfault_debug,
10362306a36Sopenharmony_ci	" enable detection of firmware fault and halt firmware - (default=0)");
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic int perf_mode = -1;
10662306a36Sopenharmony_cimodule_param(perf_mode, int, 0444);
10762306a36Sopenharmony_ciMODULE_PARM_DESC(perf_mode,
10862306a36Sopenharmony_ci	"Performance mode (only for Aero/Sea Generation), options:\n\t\t"
10962306a36Sopenharmony_ci	"0 - balanced: high iops mode is enabled &\n\t\t"
11062306a36Sopenharmony_ci	"interrupt coalescing is enabled only on high iops queues,\n\t\t"
11162306a36Sopenharmony_ci	"1 - iops: high iops mode is disabled &\n\t\t"
11262306a36Sopenharmony_ci	"interrupt coalescing is enabled on all queues,\n\t\t"
11362306a36Sopenharmony_ci	"2 - latency: high iops mode is disabled &\n\t\t"
11462306a36Sopenharmony_ci	"interrupt coalescing is enabled on all queues with timeout value 0xA,\n"
11562306a36Sopenharmony_ci	"\t\tdefault - default perf_mode is 'balanced'"
11662306a36Sopenharmony_ci	);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic int poll_queues;
11962306a36Sopenharmony_cimodule_param(poll_queues, int, 0444);
12062306a36Sopenharmony_ciMODULE_PARM_DESC(poll_queues, "Number of queues to be use for io_uring poll mode.\n\t\t"
12162306a36Sopenharmony_ci	"This parameter is effective only if host_tagset_enable=1. &\n\t\t"
12262306a36Sopenharmony_ci	"when poll_queues are enabled then &\n\t\t"
12362306a36Sopenharmony_ci	"perf_mode is set to latency mode. &\n\t\t"
12462306a36Sopenharmony_ci	);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cienum mpt3sas_perf_mode {
12762306a36Sopenharmony_ci	MPT_PERF_MODE_DEFAULT	= -1,
12862306a36Sopenharmony_ci	MPT_PERF_MODE_BALANCED	= 0,
12962306a36Sopenharmony_ci	MPT_PERF_MODE_IOPS	= 1,
13062306a36Sopenharmony_ci	MPT_PERF_MODE_LATENCY	= 2,
13162306a36Sopenharmony_ci};
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic int
13462306a36Sopenharmony_ci_base_wait_on_iocstate(struct MPT3SAS_ADAPTER *ioc,
13562306a36Sopenharmony_ci		u32 ioc_state, int timeout);
13662306a36Sopenharmony_cistatic int
13762306a36Sopenharmony_ci_base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc);
13862306a36Sopenharmony_cistatic void
13962306a36Sopenharmony_ci_base_clear_outstanding_commands(struct MPT3SAS_ADAPTER *ioc);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic u32
14262306a36Sopenharmony_ci_base_readl_ext_retry(const void __iomem *addr);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci/**
14562306a36Sopenharmony_ci * mpt3sas_base_check_cmd_timeout - Function
14662306a36Sopenharmony_ci *		to check timeout and command termination due
14762306a36Sopenharmony_ci *		to Host reset.
14862306a36Sopenharmony_ci *
14962306a36Sopenharmony_ci * @ioc:	per adapter object.
15062306a36Sopenharmony_ci * @status:	Status of issued command.
15162306a36Sopenharmony_ci * @mpi_request:mf request pointer.
15262306a36Sopenharmony_ci * @sz:		size of buffer.
15362306a36Sopenharmony_ci *
15462306a36Sopenharmony_ci * Return: 1/0 Reset to be done or Not
15562306a36Sopenharmony_ci */
15662306a36Sopenharmony_ciu8
15762306a36Sopenharmony_cimpt3sas_base_check_cmd_timeout(struct MPT3SAS_ADAPTER *ioc,
15862306a36Sopenharmony_ci		u8 status, void *mpi_request, int sz)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	u8 issue_reset = 0;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	if (!(status & MPT3_CMD_RESET))
16362306a36Sopenharmony_ci		issue_reset = 1;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	ioc_err(ioc, "Command %s\n",
16662306a36Sopenharmony_ci		issue_reset == 0 ? "terminated due to Host Reset" : "Timeout");
16762306a36Sopenharmony_ci	_debug_dump_mf(mpi_request, sz);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	return issue_reset;
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci/**
17362306a36Sopenharmony_ci * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug.
17462306a36Sopenharmony_ci * @val: ?
17562306a36Sopenharmony_ci * @kp: ?
17662306a36Sopenharmony_ci *
17762306a36Sopenharmony_ci * Return: ?
17862306a36Sopenharmony_ci */
17962306a36Sopenharmony_cistatic int
18062306a36Sopenharmony_ci_scsih_set_fwfault_debug(const char *val, const struct kernel_param *kp)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	int ret = param_set_int(val, kp);
18362306a36Sopenharmony_ci	struct MPT3SAS_ADAPTER *ioc;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (ret)
18662306a36Sopenharmony_ci		return ret;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	/* global ioc spinlock to protect controller list on list operations */
18962306a36Sopenharmony_ci	pr_info("setting fwfault_debug(%d)\n", mpt3sas_fwfault_debug);
19062306a36Sopenharmony_ci	spin_lock(&gioc_lock);
19162306a36Sopenharmony_ci	list_for_each_entry(ioc, &mpt3sas_ioc_list, list)
19262306a36Sopenharmony_ci		ioc->fwfault_debug = mpt3sas_fwfault_debug;
19362306a36Sopenharmony_ci	spin_unlock(&gioc_lock);
19462306a36Sopenharmony_ci	return 0;
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_cimodule_param_call(mpt3sas_fwfault_debug, _scsih_set_fwfault_debug,
19762306a36Sopenharmony_ci	param_get_int, &mpt3sas_fwfault_debug, 0644);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci/**
20062306a36Sopenharmony_ci * _base_readl_aero - retry readl for max three times.
20162306a36Sopenharmony_ci * @addr: MPT Fusion system interface register address
20262306a36Sopenharmony_ci *
20362306a36Sopenharmony_ci * Retry the readl() for max three times if it gets zero value
20462306a36Sopenharmony_ci * while reading the system interface register.
20562306a36Sopenharmony_ci */
20662306a36Sopenharmony_cistatic inline u32
20762306a36Sopenharmony_ci_base_readl_aero(const void __iomem *addr)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	u32 i = 0, ret_val;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	do {
21262306a36Sopenharmony_ci		ret_val = readl(addr);
21362306a36Sopenharmony_ci		i++;
21462306a36Sopenharmony_ci	} while (ret_val == 0 && i < 3);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	return ret_val;
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic u32
22062306a36Sopenharmony_ci_base_readl_ext_retry(const void __iomem *addr)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	u32 i, ret_val;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	for (i = 0 ; i < 30 ; i++) {
22562306a36Sopenharmony_ci		ret_val = readl(addr);
22662306a36Sopenharmony_ci		if (ret_val != 0)
22762306a36Sopenharmony_ci			break;
22862306a36Sopenharmony_ci	}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	return ret_val;
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistatic inline u32
23462306a36Sopenharmony_ci_base_readl(const void __iomem *addr)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	return readl(addr);
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci/**
24062306a36Sopenharmony_ci * _base_clone_reply_to_sys_mem - copies reply to reply free iomem
24162306a36Sopenharmony_ci *				  in BAR0 space.
24262306a36Sopenharmony_ci *
24362306a36Sopenharmony_ci * @ioc: per adapter object
24462306a36Sopenharmony_ci * @reply: reply message frame(lower 32bit addr)
24562306a36Sopenharmony_ci * @index: System request message index.
24662306a36Sopenharmony_ci */
24762306a36Sopenharmony_cistatic void
24862306a36Sopenharmony_ci_base_clone_reply_to_sys_mem(struct MPT3SAS_ADAPTER *ioc, u32 reply,
24962306a36Sopenharmony_ci		u32 index)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	/*
25262306a36Sopenharmony_ci	 * 256 is offset within sys register.
25362306a36Sopenharmony_ci	 * 256 offset MPI frame starts. Max MPI frame supported is 32.
25462306a36Sopenharmony_ci	 * 32 * 128 = 4K. From here, Clone of reply free for mcpu starts
25562306a36Sopenharmony_ci	 */
25662306a36Sopenharmony_ci	u16 cmd_credit = ioc->facts.RequestCredit + 1;
25762306a36Sopenharmony_ci	void __iomem *reply_free_iomem = (void __iomem *)ioc->chip +
25862306a36Sopenharmony_ci			MPI_FRAME_START_OFFSET +
25962306a36Sopenharmony_ci			(cmd_credit * ioc->request_sz) + (index * sizeof(u32));
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	writel(reply, reply_free_iomem);
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci/**
26562306a36Sopenharmony_ci * _base_clone_mpi_to_sys_mem - Writes/copies MPI frames
26662306a36Sopenharmony_ci *				to system/BAR0 region.
26762306a36Sopenharmony_ci *
26862306a36Sopenharmony_ci * @dst_iomem: Pointer to the destination location in BAR0 space.
26962306a36Sopenharmony_ci * @src: Pointer to the Source data.
27062306a36Sopenharmony_ci * @size: Size of data to be copied.
27162306a36Sopenharmony_ci */
27262306a36Sopenharmony_cistatic void
27362306a36Sopenharmony_ci_base_clone_mpi_to_sys_mem(void *dst_iomem, void *src, u32 size)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	int i;
27662306a36Sopenharmony_ci	u32 *src_virt_mem = (u32 *)src;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	for (i = 0; i < size/4; i++)
27962306a36Sopenharmony_ci		writel((u32)src_virt_mem[i],
28062306a36Sopenharmony_ci				(void __iomem *)dst_iomem + (i * 4));
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci/**
28462306a36Sopenharmony_ci * _base_clone_to_sys_mem - Writes/copies data to system/BAR0 region
28562306a36Sopenharmony_ci *
28662306a36Sopenharmony_ci * @dst_iomem: Pointer to the destination location in BAR0 space.
28762306a36Sopenharmony_ci * @src: Pointer to the Source data.
28862306a36Sopenharmony_ci * @size: Size of data to be copied.
28962306a36Sopenharmony_ci */
29062306a36Sopenharmony_cistatic void
29162306a36Sopenharmony_ci_base_clone_to_sys_mem(void __iomem *dst_iomem, void *src, u32 size)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	int i;
29462306a36Sopenharmony_ci	u32 *src_virt_mem = (u32 *)(src);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	for (i = 0; i < size/4; i++)
29762306a36Sopenharmony_ci		writel((u32)src_virt_mem[i],
29862306a36Sopenharmony_ci			(void __iomem *)dst_iomem + (i * 4));
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci/**
30262306a36Sopenharmony_ci * _base_get_chain - Calculates and Returns virtual chain address
30362306a36Sopenharmony_ci *			 for the provided smid in BAR0 space.
30462306a36Sopenharmony_ci *
30562306a36Sopenharmony_ci * @ioc: per adapter object
30662306a36Sopenharmony_ci * @smid: system request message index
30762306a36Sopenharmony_ci * @sge_chain_count: Scatter gather chain count.
30862306a36Sopenharmony_ci *
30962306a36Sopenharmony_ci * Return: the chain address.
31062306a36Sopenharmony_ci */
31162306a36Sopenharmony_cistatic inline void __iomem*
31262306a36Sopenharmony_ci_base_get_chain(struct MPT3SAS_ADAPTER *ioc, u16 smid,
31362306a36Sopenharmony_ci		u8 sge_chain_count)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci	void __iomem *base_chain, *chain_virt;
31662306a36Sopenharmony_ci	u16 cmd_credit = ioc->facts.RequestCredit + 1;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	base_chain  = (void __iomem *)ioc->chip + MPI_FRAME_START_OFFSET +
31962306a36Sopenharmony_ci		(cmd_credit * ioc->request_sz) +
32062306a36Sopenharmony_ci		REPLY_FREE_POOL_SIZE;
32162306a36Sopenharmony_ci	chain_virt = base_chain + (smid * ioc->facts.MaxChainDepth *
32262306a36Sopenharmony_ci			ioc->request_sz) + (sge_chain_count * ioc->request_sz);
32362306a36Sopenharmony_ci	return chain_virt;
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci/**
32762306a36Sopenharmony_ci * _base_get_chain_phys - Calculates and Returns physical address
32862306a36Sopenharmony_ci *			in BAR0 for scatter gather chains, for
32962306a36Sopenharmony_ci *			the provided smid.
33062306a36Sopenharmony_ci *
33162306a36Sopenharmony_ci * @ioc: per adapter object
33262306a36Sopenharmony_ci * @smid: system request message index
33362306a36Sopenharmony_ci * @sge_chain_count: Scatter gather chain count.
33462306a36Sopenharmony_ci *
33562306a36Sopenharmony_ci * Return: Physical chain address.
33662306a36Sopenharmony_ci */
33762306a36Sopenharmony_cistatic inline phys_addr_t
33862306a36Sopenharmony_ci_base_get_chain_phys(struct MPT3SAS_ADAPTER *ioc, u16 smid,
33962306a36Sopenharmony_ci		u8 sge_chain_count)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	phys_addr_t base_chain_phys, chain_phys;
34262306a36Sopenharmony_ci	u16 cmd_credit = ioc->facts.RequestCredit + 1;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	base_chain_phys  = ioc->chip_phys + MPI_FRAME_START_OFFSET +
34562306a36Sopenharmony_ci		(cmd_credit * ioc->request_sz) +
34662306a36Sopenharmony_ci		REPLY_FREE_POOL_SIZE;
34762306a36Sopenharmony_ci	chain_phys = base_chain_phys + (smid * ioc->facts.MaxChainDepth *
34862306a36Sopenharmony_ci			ioc->request_sz) + (sge_chain_count * ioc->request_sz);
34962306a36Sopenharmony_ci	return chain_phys;
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci/**
35362306a36Sopenharmony_ci * _base_get_buffer_bar0 - Calculates and Returns BAR0 mapped Host
35462306a36Sopenharmony_ci *			buffer address for the provided smid.
35562306a36Sopenharmony_ci *			(Each smid can have 64K starts from 17024)
35662306a36Sopenharmony_ci *
35762306a36Sopenharmony_ci * @ioc: per adapter object
35862306a36Sopenharmony_ci * @smid: system request message index
35962306a36Sopenharmony_ci *
36062306a36Sopenharmony_ci * Return: Pointer to buffer location in BAR0.
36162306a36Sopenharmony_ci */
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cistatic void __iomem *
36462306a36Sopenharmony_ci_base_get_buffer_bar0(struct MPT3SAS_ADAPTER *ioc, u16 smid)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	u16 cmd_credit = ioc->facts.RequestCredit + 1;
36762306a36Sopenharmony_ci	// Added extra 1 to reach end of chain.
36862306a36Sopenharmony_ci	void __iomem *chain_end = _base_get_chain(ioc,
36962306a36Sopenharmony_ci			cmd_credit + 1,
37062306a36Sopenharmony_ci			ioc->facts.MaxChainDepth);
37162306a36Sopenharmony_ci	return chain_end + (smid * 64 * 1024);
37262306a36Sopenharmony_ci}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci/**
37562306a36Sopenharmony_ci * _base_get_buffer_phys_bar0 - Calculates and Returns BAR0 mapped
37662306a36Sopenharmony_ci *		Host buffer Physical address for the provided smid.
37762306a36Sopenharmony_ci *		(Each smid can have 64K starts from 17024)
37862306a36Sopenharmony_ci *
37962306a36Sopenharmony_ci * @ioc: per adapter object
38062306a36Sopenharmony_ci * @smid: system request message index
38162306a36Sopenharmony_ci *
38262306a36Sopenharmony_ci * Return: Pointer to buffer location in BAR0.
38362306a36Sopenharmony_ci */
38462306a36Sopenharmony_cistatic phys_addr_t
38562306a36Sopenharmony_ci_base_get_buffer_phys_bar0(struct MPT3SAS_ADAPTER *ioc, u16 smid)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	u16 cmd_credit = ioc->facts.RequestCredit + 1;
38862306a36Sopenharmony_ci	phys_addr_t chain_end_phys = _base_get_chain_phys(ioc,
38962306a36Sopenharmony_ci			cmd_credit + 1,
39062306a36Sopenharmony_ci			ioc->facts.MaxChainDepth);
39162306a36Sopenharmony_ci	return chain_end_phys + (smid * 64 * 1024);
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci/**
39562306a36Sopenharmony_ci * _base_get_chain_buffer_dma_to_chain_buffer - Iterates chain
39662306a36Sopenharmony_ci *			lookup list and Provides chain_buffer
39762306a36Sopenharmony_ci *			address for the matching dma address.
39862306a36Sopenharmony_ci *			(Each smid can have 64K starts from 17024)
39962306a36Sopenharmony_ci *
40062306a36Sopenharmony_ci * @ioc: per adapter object
40162306a36Sopenharmony_ci * @chain_buffer_dma: Chain buffer dma address.
40262306a36Sopenharmony_ci *
40362306a36Sopenharmony_ci * Return: Pointer to chain buffer. Or Null on Failure.
40462306a36Sopenharmony_ci */
40562306a36Sopenharmony_cistatic void *
40662306a36Sopenharmony_ci_base_get_chain_buffer_dma_to_chain_buffer(struct MPT3SAS_ADAPTER *ioc,
40762306a36Sopenharmony_ci		dma_addr_t chain_buffer_dma)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	u16 index, j;
41062306a36Sopenharmony_ci	struct chain_tracker *ct;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	for (index = 0; index < ioc->scsiio_depth; index++) {
41362306a36Sopenharmony_ci		for (j = 0; j < ioc->chains_needed_per_io; j++) {
41462306a36Sopenharmony_ci			ct = &ioc->chain_lookup[index].chains_per_smid[j];
41562306a36Sopenharmony_ci			if (ct && ct->chain_buffer_dma == chain_buffer_dma)
41662306a36Sopenharmony_ci				return ct->chain_buffer;
41762306a36Sopenharmony_ci		}
41862306a36Sopenharmony_ci	}
41962306a36Sopenharmony_ci	ioc_info(ioc, "Provided chain_buffer_dma address is not in the lookup list\n");
42062306a36Sopenharmony_ci	return NULL;
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci/**
42462306a36Sopenharmony_ci * _clone_sg_entries -	MPI EP's scsiio and config requests
42562306a36Sopenharmony_ci *			are handled here. Base function for
42662306a36Sopenharmony_ci *			double buffering, before submitting
42762306a36Sopenharmony_ci *			the requests.
42862306a36Sopenharmony_ci *
42962306a36Sopenharmony_ci * @ioc: per adapter object.
43062306a36Sopenharmony_ci * @mpi_request: mf request pointer.
43162306a36Sopenharmony_ci * @smid: system request message index.
43262306a36Sopenharmony_ci */
43362306a36Sopenharmony_cistatic void _clone_sg_entries(struct MPT3SAS_ADAPTER *ioc,
43462306a36Sopenharmony_ci		void *mpi_request, u16 smid)
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	Mpi2SGESimple32_t *sgel, *sgel_next;
43762306a36Sopenharmony_ci	u32  sgl_flags, sge_chain_count = 0;
43862306a36Sopenharmony_ci	bool is_write = false;
43962306a36Sopenharmony_ci	u16 i = 0;
44062306a36Sopenharmony_ci	void __iomem *buffer_iomem;
44162306a36Sopenharmony_ci	phys_addr_t buffer_iomem_phys;
44262306a36Sopenharmony_ci	void __iomem *buff_ptr;
44362306a36Sopenharmony_ci	phys_addr_t buff_ptr_phys;
44462306a36Sopenharmony_ci	void __iomem *dst_chain_addr[MCPU_MAX_CHAINS_PER_IO];
44562306a36Sopenharmony_ci	void *src_chain_addr[MCPU_MAX_CHAINS_PER_IO];
44662306a36Sopenharmony_ci	phys_addr_t dst_addr_phys;
44762306a36Sopenharmony_ci	MPI2RequestHeader_t *request_hdr;
44862306a36Sopenharmony_ci	struct scsi_cmnd *scmd;
44962306a36Sopenharmony_ci	struct scatterlist *sg_scmd = NULL;
45062306a36Sopenharmony_ci	int is_scsiio_req = 0;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	request_hdr = (MPI2RequestHeader_t *) mpi_request;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	if (request_hdr->Function == MPI2_FUNCTION_SCSI_IO_REQUEST) {
45562306a36Sopenharmony_ci		Mpi25SCSIIORequest_t *scsiio_request =
45662306a36Sopenharmony_ci			(Mpi25SCSIIORequest_t *)mpi_request;
45762306a36Sopenharmony_ci		sgel = (Mpi2SGESimple32_t *) &scsiio_request->SGL;
45862306a36Sopenharmony_ci		is_scsiio_req = 1;
45962306a36Sopenharmony_ci	} else if (request_hdr->Function == MPI2_FUNCTION_CONFIG) {
46062306a36Sopenharmony_ci		Mpi2ConfigRequest_t  *config_req =
46162306a36Sopenharmony_ci			(Mpi2ConfigRequest_t *)mpi_request;
46262306a36Sopenharmony_ci		sgel = (Mpi2SGESimple32_t *) &config_req->PageBufferSGE;
46362306a36Sopenharmony_ci	} else
46462306a36Sopenharmony_ci		return;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	/* From smid we can get scsi_cmd, once we have sg_scmd,
46762306a36Sopenharmony_ci	 * we just need to get sg_virt and sg_next to get virtual
46862306a36Sopenharmony_ci	 * address associated with sgel->Address.
46962306a36Sopenharmony_ci	 */
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	if (is_scsiio_req) {
47262306a36Sopenharmony_ci		/* Get scsi_cmd using smid */
47362306a36Sopenharmony_ci		scmd = mpt3sas_scsih_scsi_lookup_get(ioc, smid);
47462306a36Sopenharmony_ci		if (scmd == NULL) {
47562306a36Sopenharmony_ci			ioc_err(ioc, "scmd is NULL\n");
47662306a36Sopenharmony_ci			return;
47762306a36Sopenharmony_ci		}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci		/* Get sg_scmd from scmd provided */
48062306a36Sopenharmony_ci		sg_scmd = scsi_sglist(scmd);
48162306a36Sopenharmony_ci	}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	/*
48462306a36Sopenharmony_ci	 * 0 - 255	System register
48562306a36Sopenharmony_ci	 * 256 - 4352	MPI Frame. (This is based on maxCredit 32)
48662306a36Sopenharmony_ci	 * 4352 - 4864	Reply_free pool (512 byte is reserved
48762306a36Sopenharmony_ci	 *		considering maxCredit 32. Reply need extra
48862306a36Sopenharmony_ci	 *		room, for mCPU case kept four times of
48962306a36Sopenharmony_ci	 *		maxCredit).
49062306a36Sopenharmony_ci	 * 4864 - 17152	SGE chain element. (32cmd * 3 chain of
49162306a36Sopenharmony_ci	 *		128 byte size = 12288)
49262306a36Sopenharmony_ci	 * 17152 - x	Host buffer mapped with smid.
49362306a36Sopenharmony_ci	 *		(Each smid can have 64K Max IO.)
49462306a36Sopenharmony_ci	 * BAR0+Last 1K MSIX Addr and Data
49562306a36Sopenharmony_ci	 * Total size in use 2113664 bytes of 4MB BAR0
49662306a36Sopenharmony_ci	 */
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	buffer_iomem = _base_get_buffer_bar0(ioc, smid);
49962306a36Sopenharmony_ci	buffer_iomem_phys = _base_get_buffer_phys_bar0(ioc, smid);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	buff_ptr = buffer_iomem;
50262306a36Sopenharmony_ci	buff_ptr_phys = buffer_iomem_phys;
50362306a36Sopenharmony_ci	WARN_ON(buff_ptr_phys > U32_MAX);
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	if (le32_to_cpu(sgel->FlagsLength) &
50662306a36Sopenharmony_ci			(MPI2_SGE_FLAGS_HOST_TO_IOC << MPI2_SGE_FLAGS_SHIFT))
50762306a36Sopenharmony_ci		is_write = true;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	for (i = 0; i < MPT_MIN_PHYS_SEGMENTS + ioc->facts.MaxChainDepth; i++) {
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci		sgl_flags =
51262306a36Sopenharmony_ci		    (le32_to_cpu(sgel->FlagsLength) >> MPI2_SGE_FLAGS_SHIFT);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci		switch (sgl_flags & MPI2_SGE_FLAGS_ELEMENT_MASK) {
51562306a36Sopenharmony_ci		case MPI2_SGE_FLAGS_CHAIN_ELEMENT:
51662306a36Sopenharmony_ci			/*
51762306a36Sopenharmony_ci			 * Helper function which on passing
51862306a36Sopenharmony_ci			 * chain_buffer_dma returns chain_buffer. Get
51962306a36Sopenharmony_ci			 * the virtual address for sgel->Address
52062306a36Sopenharmony_ci			 */
52162306a36Sopenharmony_ci			sgel_next =
52262306a36Sopenharmony_ci				_base_get_chain_buffer_dma_to_chain_buffer(ioc,
52362306a36Sopenharmony_ci						le32_to_cpu(sgel->Address));
52462306a36Sopenharmony_ci			if (sgel_next == NULL)
52562306a36Sopenharmony_ci				return;
52662306a36Sopenharmony_ci			/*
52762306a36Sopenharmony_ci			 * This is coping 128 byte chain
52862306a36Sopenharmony_ci			 * frame (not a host buffer)
52962306a36Sopenharmony_ci			 */
53062306a36Sopenharmony_ci			dst_chain_addr[sge_chain_count] =
53162306a36Sopenharmony_ci				_base_get_chain(ioc,
53262306a36Sopenharmony_ci					smid, sge_chain_count);
53362306a36Sopenharmony_ci			src_chain_addr[sge_chain_count] =
53462306a36Sopenharmony_ci						(void *) sgel_next;
53562306a36Sopenharmony_ci			dst_addr_phys = _base_get_chain_phys(ioc,
53662306a36Sopenharmony_ci						smid, sge_chain_count);
53762306a36Sopenharmony_ci			WARN_ON(dst_addr_phys > U32_MAX);
53862306a36Sopenharmony_ci			sgel->Address =
53962306a36Sopenharmony_ci				cpu_to_le32(lower_32_bits(dst_addr_phys));
54062306a36Sopenharmony_ci			sgel = sgel_next;
54162306a36Sopenharmony_ci			sge_chain_count++;
54262306a36Sopenharmony_ci			break;
54362306a36Sopenharmony_ci		case MPI2_SGE_FLAGS_SIMPLE_ELEMENT:
54462306a36Sopenharmony_ci			if (is_write) {
54562306a36Sopenharmony_ci				if (is_scsiio_req) {
54662306a36Sopenharmony_ci					_base_clone_to_sys_mem(buff_ptr,
54762306a36Sopenharmony_ci					    sg_virt(sg_scmd),
54862306a36Sopenharmony_ci					    (le32_to_cpu(sgel->FlagsLength) &
54962306a36Sopenharmony_ci					    0x00ffffff));
55062306a36Sopenharmony_ci					/*
55162306a36Sopenharmony_ci					 * FIXME: this relies on a a zero
55262306a36Sopenharmony_ci					 * PCI mem_offset.
55362306a36Sopenharmony_ci					 */
55462306a36Sopenharmony_ci					sgel->Address =
55562306a36Sopenharmony_ci					    cpu_to_le32((u32)buff_ptr_phys);
55662306a36Sopenharmony_ci				} else {
55762306a36Sopenharmony_ci					_base_clone_to_sys_mem(buff_ptr,
55862306a36Sopenharmony_ci					    ioc->config_vaddr,
55962306a36Sopenharmony_ci					    (le32_to_cpu(sgel->FlagsLength) &
56062306a36Sopenharmony_ci					    0x00ffffff));
56162306a36Sopenharmony_ci					sgel->Address =
56262306a36Sopenharmony_ci					    cpu_to_le32((u32)buff_ptr_phys);
56362306a36Sopenharmony_ci				}
56462306a36Sopenharmony_ci			}
56562306a36Sopenharmony_ci			buff_ptr += (le32_to_cpu(sgel->FlagsLength) &
56662306a36Sopenharmony_ci			    0x00ffffff);
56762306a36Sopenharmony_ci			buff_ptr_phys += (le32_to_cpu(sgel->FlagsLength) &
56862306a36Sopenharmony_ci			    0x00ffffff);
56962306a36Sopenharmony_ci			if ((le32_to_cpu(sgel->FlagsLength) &
57062306a36Sopenharmony_ci			    (MPI2_SGE_FLAGS_END_OF_BUFFER
57162306a36Sopenharmony_ci					<< MPI2_SGE_FLAGS_SHIFT)))
57262306a36Sopenharmony_ci				goto eob_clone_chain;
57362306a36Sopenharmony_ci			else {
57462306a36Sopenharmony_ci				/*
57562306a36Sopenharmony_ci				 * Every single element in MPT will have
57662306a36Sopenharmony_ci				 * associated sg_next. Better to sanity that
57762306a36Sopenharmony_ci				 * sg_next is not NULL, but it will be a bug
57862306a36Sopenharmony_ci				 * if it is null.
57962306a36Sopenharmony_ci				 */
58062306a36Sopenharmony_ci				if (is_scsiio_req) {
58162306a36Sopenharmony_ci					sg_scmd = sg_next(sg_scmd);
58262306a36Sopenharmony_ci					if (sg_scmd)
58362306a36Sopenharmony_ci						sgel++;
58462306a36Sopenharmony_ci					else
58562306a36Sopenharmony_ci						goto eob_clone_chain;
58662306a36Sopenharmony_ci				}
58762306a36Sopenharmony_ci			}
58862306a36Sopenharmony_ci			break;
58962306a36Sopenharmony_ci		}
59062306a36Sopenharmony_ci	}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_cieob_clone_chain:
59362306a36Sopenharmony_ci	for (i = 0; i < sge_chain_count; i++) {
59462306a36Sopenharmony_ci		if (is_scsiio_req)
59562306a36Sopenharmony_ci			_base_clone_to_sys_mem(dst_chain_addr[i],
59662306a36Sopenharmony_ci				src_chain_addr[i], ioc->request_sz);
59762306a36Sopenharmony_ci	}
59862306a36Sopenharmony_ci}
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci/**
60162306a36Sopenharmony_ci *  mpt3sas_remove_dead_ioc_func - kthread context to remove dead ioc
60262306a36Sopenharmony_ci * @arg: input argument, used to derive ioc
60362306a36Sopenharmony_ci *
60462306a36Sopenharmony_ci * Return:
60562306a36Sopenharmony_ci * 0 if controller is removed from pci subsystem.
60662306a36Sopenharmony_ci * -1 for other case.
60762306a36Sopenharmony_ci */
60862306a36Sopenharmony_cistatic int mpt3sas_remove_dead_ioc_func(void *arg)
60962306a36Sopenharmony_ci{
61062306a36Sopenharmony_ci	struct MPT3SAS_ADAPTER *ioc = (struct MPT3SAS_ADAPTER *)arg;
61162306a36Sopenharmony_ci	struct pci_dev *pdev;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	if (!ioc)
61462306a36Sopenharmony_ci		return -1;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	pdev = ioc->pdev;
61762306a36Sopenharmony_ci	if (!pdev)
61862306a36Sopenharmony_ci		return -1;
61962306a36Sopenharmony_ci	pci_stop_and_remove_bus_device_locked(pdev);
62062306a36Sopenharmony_ci	return 0;
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci/**
62462306a36Sopenharmony_ci * _base_sync_drv_fw_timestamp - Sync Drive-Fw TimeStamp.
62562306a36Sopenharmony_ci * @ioc: Per Adapter Object
62662306a36Sopenharmony_ci *
62762306a36Sopenharmony_ci * Return: nothing.
62862306a36Sopenharmony_ci */
62962306a36Sopenharmony_cistatic void _base_sync_drv_fw_timestamp(struct MPT3SAS_ADAPTER *ioc)
63062306a36Sopenharmony_ci{
63162306a36Sopenharmony_ci	Mpi26IoUnitControlRequest_t *mpi_request;
63262306a36Sopenharmony_ci	Mpi26IoUnitControlReply_t *mpi_reply;
63362306a36Sopenharmony_ci	u16 smid;
63462306a36Sopenharmony_ci	ktime_t current_time;
63562306a36Sopenharmony_ci	u64 TimeStamp = 0;
63662306a36Sopenharmony_ci	u8 issue_reset = 0;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	mutex_lock(&ioc->scsih_cmds.mutex);
63962306a36Sopenharmony_ci	if (ioc->scsih_cmds.status != MPT3_CMD_NOT_USED) {
64062306a36Sopenharmony_ci		ioc_err(ioc, "scsih_cmd in use %s\n", __func__);
64162306a36Sopenharmony_ci		goto out;
64262306a36Sopenharmony_ci	}
64362306a36Sopenharmony_ci	ioc->scsih_cmds.status = MPT3_CMD_PENDING;
64462306a36Sopenharmony_ci	smid = mpt3sas_base_get_smid(ioc, ioc->scsih_cb_idx);
64562306a36Sopenharmony_ci	if (!smid) {
64662306a36Sopenharmony_ci		ioc_err(ioc, "Failed obtaining a smid %s\n", __func__);
64762306a36Sopenharmony_ci		ioc->scsih_cmds.status = MPT3_CMD_NOT_USED;
64862306a36Sopenharmony_ci		goto out;
64962306a36Sopenharmony_ci	}
65062306a36Sopenharmony_ci	mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
65162306a36Sopenharmony_ci	ioc->scsih_cmds.smid = smid;
65262306a36Sopenharmony_ci	memset(mpi_request, 0, sizeof(Mpi26IoUnitControlRequest_t));
65362306a36Sopenharmony_ci	mpi_request->Function = MPI2_FUNCTION_IO_UNIT_CONTROL;
65462306a36Sopenharmony_ci	mpi_request->Operation = MPI26_CTRL_OP_SET_IOC_PARAMETER;
65562306a36Sopenharmony_ci	mpi_request->IOCParameter = MPI26_SET_IOC_PARAMETER_SYNC_TIMESTAMP;
65662306a36Sopenharmony_ci	current_time = ktime_get_real();
65762306a36Sopenharmony_ci	TimeStamp = ktime_to_ms(current_time);
65862306a36Sopenharmony_ci	mpi_request->Reserved7 = cpu_to_le32(TimeStamp >> 32);
65962306a36Sopenharmony_ci	mpi_request->IOCParameterValue = cpu_to_le32(TimeStamp & 0xFFFFFFFF);
66062306a36Sopenharmony_ci	init_completion(&ioc->scsih_cmds.done);
66162306a36Sopenharmony_ci	ioc->put_smid_default(ioc, smid);
66262306a36Sopenharmony_ci	dinitprintk(ioc, ioc_info(ioc,
66362306a36Sopenharmony_ci	    "Io Unit Control Sync TimeStamp (sending), @time %lld ms\n",
66462306a36Sopenharmony_ci	    TimeStamp));
66562306a36Sopenharmony_ci	wait_for_completion_timeout(&ioc->scsih_cmds.done,
66662306a36Sopenharmony_ci		MPT3SAS_TIMESYNC_TIMEOUT_SECONDS*HZ);
66762306a36Sopenharmony_ci	if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) {
66862306a36Sopenharmony_ci		mpt3sas_check_cmd_timeout(ioc,
66962306a36Sopenharmony_ci		    ioc->scsih_cmds.status, mpi_request,
67062306a36Sopenharmony_ci		    sizeof(Mpi2SasIoUnitControlRequest_t)/4, issue_reset);
67162306a36Sopenharmony_ci		goto issue_host_reset;
67262306a36Sopenharmony_ci	}
67362306a36Sopenharmony_ci	if (ioc->scsih_cmds.status & MPT3_CMD_REPLY_VALID) {
67462306a36Sopenharmony_ci		mpi_reply = ioc->scsih_cmds.reply;
67562306a36Sopenharmony_ci		dinitprintk(ioc, ioc_info(ioc,
67662306a36Sopenharmony_ci		    "Io Unit Control sync timestamp (complete): ioc_status(0x%04x), loginfo(0x%08x)\n",
67762306a36Sopenharmony_ci		    le16_to_cpu(mpi_reply->IOCStatus),
67862306a36Sopenharmony_ci		    le32_to_cpu(mpi_reply->IOCLogInfo)));
67962306a36Sopenharmony_ci	}
68062306a36Sopenharmony_ciissue_host_reset:
68162306a36Sopenharmony_ci	if (issue_reset)
68262306a36Sopenharmony_ci		mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
68362306a36Sopenharmony_ci	ioc->scsih_cmds.status = MPT3_CMD_NOT_USED;
68462306a36Sopenharmony_ciout:
68562306a36Sopenharmony_ci	mutex_unlock(&ioc->scsih_cmds.mutex);
68662306a36Sopenharmony_ci}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci/**
68962306a36Sopenharmony_ci * _base_fault_reset_work - workq handling ioc fault conditions
69062306a36Sopenharmony_ci * @work: input argument, used to derive ioc
69162306a36Sopenharmony_ci *
69262306a36Sopenharmony_ci * Context: sleep.
69362306a36Sopenharmony_ci */
69462306a36Sopenharmony_cistatic void
69562306a36Sopenharmony_ci_base_fault_reset_work(struct work_struct *work)
69662306a36Sopenharmony_ci{
69762306a36Sopenharmony_ci	struct MPT3SAS_ADAPTER *ioc =
69862306a36Sopenharmony_ci	    container_of(work, struct MPT3SAS_ADAPTER, fault_reset_work.work);
69962306a36Sopenharmony_ci	unsigned long	 flags;
70062306a36Sopenharmony_ci	u32 doorbell;
70162306a36Sopenharmony_ci	int rc;
70262306a36Sopenharmony_ci	struct task_struct *p;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
70662306a36Sopenharmony_ci	if ((ioc->shost_recovery && (ioc->ioc_coredump_loop == 0)) ||
70762306a36Sopenharmony_ci			ioc->pci_error_recovery)
70862306a36Sopenharmony_ci		goto rearm_timer;
70962306a36Sopenharmony_ci	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	doorbell = mpt3sas_base_get_iocstate(ioc, 0);
71262306a36Sopenharmony_ci	if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_MASK) {
71362306a36Sopenharmony_ci		ioc_err(ioc, "SAS host is non-operational !!!!\n");
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci		/* It may be possible that EEH recovery can resolve some of
71662306a36Sopenharmony_ci		 * pci bus failure issues rather removing the dead ioc function
71762306a36Sopenharmony_ci		 * by considering controller is in a non-operational state. So
71862306a36Sopenharmony_ci		 * here priority is given to the EEH recovery. If it doesn't
71962306a36Sopenharmony_ci		 * not resolve this issue, mpt3sas driver will consider this
72062306a36Sopenharmony_ci		 * controller to non-operational state and remove the dead ioc
72162306a36Sopenharmony_ci		 * function.
72262306a36Sopenharmony_ci		 */
72362306a36Sopenharmony_ci		if (ioc->non_operational_loop++ < 5) {
72462306a36Sopenharmony_ci			spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock,
72562306a36Sopenharmony_ci							 flags);
72662306a36Sopenharmony_ci			goto rearm_timer;
72762306a36Sopenharmony_ci		}
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci		/*
73062306a36Sopenharmony_ci		 * Call _scsih_flush_pending_cmds callback so that we flush all
73162306a36Sopenharmony_ci		 * pending commands back to OS. This call is required to avoid
73262306a36Sopenharmony_ci		 * deadlock at block layer. Dead IOC will fail to do diag reset,
73362306a36Sopenharmony_ci		 * and this call is safe since dead ioc will never return any
73462306a36Sopenharmony_ci		 * command back from HW.
73562306a36Sopenharmony_ci		 */
73662306a36Sopenharmony_ci		mpt3sas_base_pause_mq_polling(ioc);
73762306a36Sopenharmony_ci		ioc->schedule_dead_ioc_flush_running_cmds(ioc);
73862306a36Sopenharmony_ci		/*
73962306a36Sopenharmony_ci		 * Set remove_host flag early since kernel thread will
74062306a36Sopenharmony_ci		 * take some time to execute.
74162306a36Sopenharmony_ci		 */
74262306a36Sopenharmony_ci		ioc->remove_host = 1;
74362306a36Sopenharmony_ci		/*Remove the Dead Host */
74462306a36Sopenharmony_ci		p = kthread_run(mpt3sas_remove_dead_ioc_func, ioc,
74562306a36Sopenharmony_ci		    "%s_dead_ioc_%d", ioc->driver_name, ioc->id);
74662306a36Sopenharmony_ci		if (IS_ERR(p))
74762306a36Sopenharmony_ci			ioc_err(ioc, "%s: Running mpt3sas_dead_ioc thread failed !!!!\n",
74862306a36Sopenharmony_ci				__func__);
74962306a36Sopenharmony_ci		else
75062306a36Sopenharmony_ci			ioc_err(ioc, "%s: Running mpt3sas_dead_ioc thread success !!!!\n",
75162306a36Sopenharmony_ci				__func__);
75262306a36Sopenharmony_ci		return; /* don't rearm timer */
75362306a36Sopenharmony_ci	}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_COREDUMP) {
75662306a36Sopenharmony_ci		u8 timeout = (ioc->manu_pg11.CoreDumpTOSec) ?
75762306a36Sopenharmony_ci		    ioc->manu_pg11.CoreDumpTOSec :
75862306a36Sopenharmony_ci		    MPT3SAS_DEFAULT_COREDUMP_TIMEOUT_SECONDS;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci		timeout /= (FAULT_POLLING_INTERVAL/1000);
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci		if (ioc->ioc_coredump_loop == 0) {
76362306a36Sopenharmony_ci			mpt3sas_print_coredump_info(ioc,
76462306a36Sopenharmony_ci			    doorbell & MPI2_DOORBELL_DATA_MASK);
76562306a36Sopenharmony_ci			/* do not accept any IOs and disable the interrupts */
76662306a36Sopenharmony_ci			spin_lock_irqsave(
76762306a36Sopenharmony_ci			    &ioc->ioc_reset_in_progress_lock, flags);
76862306a36Sopenharmony_ci			ioc->shost_recovery = 1;
76962306a36Sopenharmony_ci			spin_unlock_irqrestore(
77062306a36Sopenharmony_ci			    &ioc->ioc_reset_in_progress_lock, flags);
77162306a36Sopenharmony_ci			mpt3sas_base_mask_interrupts(ioc);
77262306a36Sopenharmony_ci			mpt3sas_base_pause_mq_polling(ioc);
77362306a36Sopenharmony_ci			_base_clear_outstanding_commands(ioc);
77462306a36Sopenharmony_ci		}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci		ioc_info(ioc, "%s: CoreDump loop %d.",
77762306a36Sopenharmony_ci		    __func__, ioc->ioc_coredump_loop);
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci		/* Wait until CoreDump completes or times out */
78062306a36Sopenharmony_ci		if (ioc->ioc_coredump_loop++ < timeout) {
78162306a36Sopenharmony_ci			spin_lock_irqsave(
78262306a36Sopenharmony_ci			    &ioc->ioc_reset_in_progress_lock, flags);
78362306a36Sopenharmony_ci			goto rearm_timer;
78462306a36Sopenharmony_ci		}
78562306a36Sopenharmony_ci	}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	if (ioc->ioc_coredump_loop) {
78862306a36Sopenharmony_ci		if ((doorbell & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_COREDUMP)
78962306a36Sopenharmony_ci			ioc_err(ioc, "%s: CoreDump completed. LoopCount: %d",
79062306a36Sopenharmony_ci			    __func__, ioc->ioc_coredump_loop);
79162306a36Sopenharmony_ci		else
79262306a36Sopenharmony_ci			ioc_err(ioc, "%s: CoreDump Timed out. LoopCount: %d",
79362306a36Sopenharmony_ci			    __func__, ioc->ioc_coredump_loop);
79462306a36Sopenharmony_ci		ioc->ioc_coredump_loop = MPT3SAS_COREDUMP_LOOP_DONE;
79562306a36Sopenharmony_ci	}
79662306a36Sopenharmony_ci	ioc->non_operational_loop = 0;
79762306a36Sopenharmony_ci	if ((doorbell & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL) {
79862306a36Sopenharmony_ci		rc = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
79962306a36Sopenharmony_ci		ioc_warn(ioc, "%s: hard reset: %s\n",
80062306a36Sopenharmony_ci			 __func__, rc == 0 ? "success" : "failed");
80162306a36Sopenharmony_ci		doorbell = mpt3sas_base_get_iocstate(ioc, 0);
80262306a36Sopenharmony_ci		if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
80362306a36Sopenharmony_ci			mpt3sas_print_fault_code(ioc, doorbell &
80462306a36Sopenharmony_ci			    MPI2_DOORBELL_DATA_MASK);
80562306a36Sopenharmony_ci		} else if ((doorbell & MPI2_IOC_STATE_MASK) ==
80662306a36Sopenharmony_ci		    MPI2_IOC_STATE_COREDUMP)
80762306a36Sopenharmony_ci			mpt3sas_print_coredump_info(ioc, doorbell &
80862306a36Sopenharmony_ci			    MPI2_DOORBELL_DATA_MASK);
80962306a36Sopenharmony_ci		if (rc && (doorbell & MPI2_IOC_STATE_MASK) !=
81062306a36Sopenharmony_ci		    MPI2_IOC_STATE_OPERATIONAL)
81162306a36Sopenharmony_ci			return; /* don't rearm timer */
81262306a36Sopenharmony_ci	}
81362306a36Sopenharmony_ci	ioc->ioc_coredump_loop = 0;
81462306a36Sopenharmony_ci	if (ioc->time_sync_interval &&
81562306a36Sopenharmony_ci	    ++ioc->timestamp_update_count >= ioc->time_sync_interval) {
81662306a36Sopenharmony_ci		ioc->timestamp_update_count = 0;
81762306a36Sopenharmony_ci		_base_sync_drv_fw_timestamp(ioc);
81862306a36Sopenharmony_ci	}
81962306a36Sopenharmony_ci	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
82062306a36Sopenharmony_ci rearm_timer:
82162306a36Sopenharmony_ci	if (ioc->fault_reset_work_q)
82262306a36Sopenharmony_ci		queue_delayed_work(ioc->fault_reset_work_q,
82362306a36Sopenharmony_ci		    &ioc->fault_reset_work,
82462306a36Sopenharmony_ci		    msecs_to_jiffies(FAULT_POLLING_INTERVAL));
82562306a36Sopenharmony_ci	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
82662306a36Sopenharmony_ci}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci/**
82962306a36Sopenharmony_ci * mpt3sas_base_start_watchdog - start the fault_reset_work_q
83062306a36Sopenharmony_ci * @ioc: per adapter object
83162306a36Sopenharmony_ci *
83262306a36Sopenharmony_ci * Context: sleep.
83362306a36Sopenharmony_ci */
83462306a36Sopenharmony_civoid
83562306a36Sopenharmony_cimpt3sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc)
83662306a36Sopenharmony_ci{
83762306a36Sopenharmony_ci	unsigned long	 flags;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	if (ioc->fault_reset_work_q)
84062306a36Sopenharmony_ci		return;
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	ioc->timestamp_update_count = 0;
84362306a36Sopenharmony_ci	/* initialize fault polling */
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work);
84662306a36Sopenharmony_ci	snprintf(ioc->fault_reset_work_q_name,
84762306a36Sopenharmony_ci	    sizeof(ioc->fault_reset_work_q_name), "poll_%s%d_status",
84862306a36Sopenharmony_ci	    ioc->driver_name, ioc->id);
84962306a36Sopenharmony_ci	ioc->fault_reset_work_q =
85062306a36Sopenharmony_ci		create_singlethread_workqueue(ioc->fault_reset_work_q_name);
85162306a36Sopenharmony_ci	if (!ioc->fault_reset_work_q) {
85262306a36Sopenharmony_ci		ioc_err(ioc, "%s: failed (line=%d)\n", __func__, __LINE__);
85362306a36Sopenharmony_ci		return;
85462306a36Sopenharmony_ci	}
85562306a36Sopenharmony_ci	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
85662306a36Sopenharmony_ci	if (ioc->fault_reset_work_q)
85762306a36Sopenharmony_ci		queue_delayed_work(ioc->fault_reset_work_q,
85862306a36Sopenharmony_ci		    &ioc->fault_reset_work,
85962306a36Sopenharmony_ci		    msecs_to_jiffies(FAULT_POLLING_INTERVAL));
86062306a36Sopenharmony_ci	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
86162306a36Sopenharmony_ci}
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci/**
86462306a36Sopenharmony_ci * mpt3sas_base_stop_watchdog - stop the fault_reset_work_q
86562306a36Sopenharmony_ci * @ioc: per adapter object
86662306a36Sopenharmony_ci *
86762306a36Sopenharmony_ci * Context: sleep.
86862306a36Sopenharmony_ci */
86962306a36Sopenharmony_civoid
87062306a36Sopenharmony_cimpt3sas_base_stop_watchdog(struct MPT3SAS_ADAPTER *ioc)
87162306a36Sopenharmony_ci{
87262306a36Sopenharmony_ci	unsigned long flags;
87362306a36Sopenharmony_ci	struct workqueue_struct *wq;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
87662306a36Sopenharmony_ci	wq = ioc->fault_reset_work_q;
87762306a36Sopenharmony_ci	ioc->fault_reset_work_q = NULL;
87862306a36Sopenharmony_ci	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
87962306a36Sopenharmony_ci	if (wq) {
88062306a36Sopenharmony_ci		if (!cancel_delayed_work_sync(&ioc->fault_reset_work))
88162306a36Sopenharmony_ci			flush_workqueue(wq);
88262306a36Sopenharmony_ci		destroy_workqueue(wq);
88362306a36Sopenharmony_ci	}
88462306a36Sopenharmony_ci}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci/**
88762306a36Sopenharmony_ci * mpt3sas_base_fault_info - verbose translation of firmware FAULT code
88862306a36Sopenharmony_ci * @ioc: per adapter object
88962306a36Sopenharmony_ci * @fault_code: fault code
89062306a36Sopenharmony_ci */
89162306a36Sopenharmony_civoid
89262306a36Sopenharmony_cimpt3sas_base_fault_info(struct MPT3SAS_ADAPTER *ioc, u16 fault_code)
89362306a36Sopenharmony_ci{
89462306a36Sopenharmony_ci	ioc_err(ioc, "fault_state(0x%04x)!\n", fault_code);
89562306a36Sopenharmony_ci}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci/**
89862306a36Sopenharmony_ci * mpt3sas_base_coredump_info - verbose translation of firmware CoreDump state
89962306a36Sopenharmony_ci * @ioc: per adapter object
90062306a36Sopenharmony_ci * @fault_code: fault code
90162306a36Sopenharmony_ci *
90262306a36Sopenharmony_ci * Return: nothing.
90362306a36Sopenharmony_ci */
90462306a36Sopenharmony_civoid
90562306a36Sopenharmony_cimpt3sas_base_coredump_info(struct MPT3SAS_ADAPTER *ioc, u16 fault_code)
90662306a36Sopenharmony_ci{
90762306a36Sopenharmony_ci	ioc_err(ioc, "coredump_state(0x%04x)!\n", fault_code);
90862306a36Sopenharmony_ci}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci/**
91162306a36Sopenharmony_ci * mpt3sas_base_wait_for_coredump_completion - Wait until coredump
91262306a36Sopenharmony_ci * completes or times out
91362306a36Sopenharmony_ci * @ioc: per adapter object
91462306a36Sopenharmony_ci * @caller: caller function name
91562306a36Sopenharmony_ci *
91662306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
91762306a36Sopenharmony_ci */
91862306a36Sopenharmony_ciint
91962306a36Sopenharmony_cimpt3sas_base_wait_for_coredump_completion(struct MPT3SAS_ADAPTER *ioc,
92062306a36Sopenharmony_ci		const char *caller)
92162306a36Sopenharmony_ci{
92262306a36Sopenharmony_ci	u8 timeout = (ioc->manu_pg11.CoreDumpTOSec) ?
92362306a36Sopenharmony_ci			ioc->manu_pg11.CoreDumpTOSec :
92462306a36Sopenharmony_ci			MPT3SAS_DEFAULT_COREDUMP_TIMEOUT_SECONDS;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	int ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_FAULT,
92762306a36Sopenharmony_ci					timeout);
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	if (ioc_state)
93062306a36Sopenharmony_ci		ioc_err(ioc,
93162306a36Sopenharmony_ci		    "%s: CoreDump timed out. (ioc_state=0x%x)\n",
93262306a36Sopenharmony_ci		    caller, ioc_state);
93362306a36Sopenharmony_ci	else
93462306a36Sopenharmony_ci		ioc_info(ioc,
93562306a36Sopenharmony_ci		    "%s: CoreDump completed. (ioc_state=0x%x)\n",
93662306a36Sopenharmony_ci		    caller, ioc_state);
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	return ioc_state;
93962306a36Sopenharmony_ci}
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci/**
94262306a36Sopenharmony_ci * mpt3sas_halt_firmware - halt's mpt controller firmware
94362306a36Sopenharmony_ci * @ioc: per adapter object
94462306a36Sopenharmony_ci *
94562306a36Sopenharmony_ci * For debugging timeout related issues.  Writing 0xCOFFEE00
94662306a36Sopenharmony_ci * to the doorbell register will halt controller firmware. With
94762306a36Sopenharmony_ci * the purpose to stop both driver and firmware, the enduser can
94862306a36Sopenharmony_ci * obtain a ring buffer from controller UART.
94962306a36Sopenharmony_ci */
95062306a36Sopenharmony_civoid
95162306a36Sopenharmony_cimpt3sas_halt_firmware(struct MPT3SAS_ADAPTER *ioc)
95262306a36Sopenharmony_ci{
95362306a36Sopenharmony_ci	u32 doorbell;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	if (!ioc->fwfault_debug)
95662306a36Sopenharmony_ci		return;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	dump_stack();
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	doorbell = ioc->base_readl_ext_retry(&ioc->chip->Doorbell);
96162306a36Sopenharmony_ci	if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
96262306a36Sopenharmony_ci		mpt3sas_print_fault_code(ioc, doorbell &
96362306a36Sopenharmony_ci		    MPI2_DOORBELL_DATA_MASK);
96462306a36Sopenharmony_ci	} else if ((doorbell & MPI2_IOC_STATE_MASK) ==
96562306a36Sopenharmony_ci	    MPI2_IOC_STATE_COREDUMP) {
96662306a36Sopenharmony_ci		mpt3sas_print_coredump_info(ioc, doorbell &
96762306a36Sopenharmony_ci		    MPI2_DOORBELL_DATA_MASK);
96862306a36Sopenharmony_ci	} else {
96962306a36Sopenharmony_ci		writel(0xC0FFEE00, &ioc->chip->Doorbell);
97062306a36Sopenharmony_ci		ioc_err(ioc, "Firmware is halted due to command timeout\n");
97162306a36Sopenharmony_ci	}
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	if (ioc->fwfault_debug == 2)
97462306a36Sopenharmony_ci		for (;;)
97562306a36Sopenharmony_ci			;
97662306a36Sopenharmony_ci	else
97762306a36Sopenharmony_ci		panic("panic in %s\n", __func__);
97862306a36Sopenharmony_ci}
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci/**
98162306a36Sopenharmony_ci * _base_sas_ioc_info - verbose translation of the ioc status
98262306a36Sopenharmony_ci * @ioc: per adapter object
98362306a36Sopenharmony_ci * @mpi_reply: reply mf payload returned from firmware
98462306a36Sopenharmony_ci * @request_hdr: request mf
98562306a36Sopenharmony_ci */
98662306a36Sopenharmony_cistatic void
98762306a36Sopenharmony_ci_base_sas_ioc_info(struct MPT3SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply,
98862306a36Sopenharmony_ci	MPI2RequestHeader_t *request_hdr)
98962306a36Sopenharmony_ci{
99062306a36Sopenharmony_ci	u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) &
99162306a36Sopenharmony_ci	    MPI2_IOCSTATUS_MASK;
99262306a36Sopenharmony_ci	char *desc = NULL;
99362306a36Sopenharmony_ci	u16 frame_sz;
99462306a36Sopenharmony_ci	char *func_str = NULL;
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	/* SCSI_IO, RAID_PASS are handled from _scsih_scsi_ioc_info */
99762306a36Sopenharmony_ci	if (request_hdr->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
99862306a36Sopenharmony_ci	    request_hdr->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
99962306a36Sopenharmony_ci	    request_hdr->Function == MPI2_FUNCTION_EVENT_NOTIFICATION)
100062306a36Sopenharmony_ci		return;
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
100362306a36Sopenharmony_ci		return;
100462306a36Sopenharmony_ci	/*
100562306a36Sopenharmony_ci	 * Older Firmware version doesn't support driver trigger pages.
100662306a36Sopenharmony_ci	 * So, skip displaying 'config invalid type' type
100762306a36Sopenharmony_ci	 * of error message.
100862306a36Sopenharmony_ci	 */
100962306a36Sopenharmony_ci	if (request_hdr->Function == MPI2_FUNCTION_CONFIG) {
101062306a36Sopenharmony_ci		Mpi2ConfigRequest_t *rqst = (Mpi2ConfigRequest_t *)request_hdr;
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci		if ((rqst->ExtPageType ==
101362306a36Sopenharmony_ci		    MPI2_CONFIG_EXTPAGETYPE_DRIVER_PERSISTENT_TRIGGER) &&
101462306a36Sopenharmony_ci		    !(ioc->logging_level & MPT_DEBUG_CONFIG)) {
101562306a36Sopenharmony_ci			return;
101662306a36Sopenharmony_ci		}
101762306a36Sopenharmony_ci	}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	switch (ioc_status) {
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci/****************************************************************************
102262306a36Sopenharmony_ci*  Common IOCStatus values for all replies
102362306a36Sopenharmony_ci****************************************************************************/
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	case MPI2_IOCSTATUS_INVALID_FUNCTION:
102662306a36Sopenharmony_ci		desc = "invalid function";
102762306a36Sopenharmony_ci		break;
102862306a36Sopenharmony_ci	case MPI2_IOCSTATUS_BUSY:
102962306a36Sopenharmony_ci		desc = "busy";
103062306a36Sopenharmony_ci		break;
103162306a36Sopenharmony_ci	case MPI2_IOCSTATUS_INVALID_SGL:
103262306a36Sopenharmony_ci		desc = "invalid sgl";
103362306a36Sopenharmony_ci		break;
103462306a36Sopenharmony_ci	case MPI2_IOCSTATUS_INTERNAL_ERROR:
103562306a36Sopenharmony_ci		desc = "internal error";
103662306a36Sopenharmony_ci		break;
103762306a36Sopenharmony_ci	case MPI2_IOCSTATUS_INVALID_VPID:
103862306a36Sopenharmony_ci		desc = "invalid vpid";
103962306a36Sopenharmony_ci		break;
104062306a36Sopenharmony_ci	case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
104162306a36Sopenharmony_ci		desc = "insufficient resources";
104262306a36Sopenharmony_ci		break;
104362306a36Sopenharmony_ci	case MPI2_IOCSTATUS_INSUFFICIENT_POWER:
104462306a36Sopenharmony_ci		desc = "insufficient power";
104562306a36Sopenharmony_ci		break;
104662306a36Sopenharmony_ci	case MPI2_IOCSTATUS_INVALID_FIELD:
104762306a36Sopenharmony_ci		desc = "invalid field";
104862306a36Sopenharmony_ci		break;
104962306a36Sopenharmony_ci	case MPI2_IOCSTATUS_INVALID_STATE:
105062306a36Sopenharmony_ci		desc = "invalid state";
105162306a36Sopenharmony_ci		break;
105262306a36Sopenharmony_ci	case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED:
105362306a36Sopenharmony_ci		desc = "op state not supported";
105462306a36Sopenharmony_ci		break;
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci/****************************************************************************
105762306a36Sopenharmony_ci*  Config IOCStatus values
105862306a36Sopenharmony_ci****************************************************************************/
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	case MPI2_IOCSTATUS_CONFIG_INVALID_ACTION:
106162306a36Sopenharmony_ci		desc = "config invalid action";
106262306a36Sopenharmony_ci		break;
106362306a36Sopenharmony_ci	case MPI2_IOCSTATUS_CONFIG_INVALID_TYPE:
106462306a36Sopenharmony_ci		desc = "config invalid type";
106562306a36Sopenharmony_ci		break;
106662306a36Sopenharmony_ci	case MPI2_IOCSTATUS_CONFIG_INVALID_PAGE:
106762306a36Sopenharmony_ci		desc = "config invalid page";
106862306a36Sopenharmony_ci		break;
106962306a36Sopenharmony_ci	case MPI2_IOCSTATUS_CONFIG_INVALID_DATA:
107062306a36Sopenharmony_ci		desc = "config invalid data";
107162306a36Sopenharmony_ci		break;
107262306a36Sopenharmony_ci	case MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS:
107362306a36Sopenharmony_ci		desc = "config no defaults";
107462306a36Sopenharmony_ci		break;
107562306a36Sopenharmony_ci	case MPI2_IOCSTATUS_CONFIG_CANT_COMMIT:
107662306a36Sopenharmony_ci		desc = "config can't commit";
107762306a36Sopenharmony_ci		break;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci/****************************************************************************
108062306a36Sopenharmony_ci*  SCSI IO Reply
108162306a36Sopenharmony_ci****************************************************************************/
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
108462306a36Sopenharmony_ci	case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
108562306a36Sopenharmony_ci	case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
108662306a36Sopenharmony_ci	case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
108762306a36Sopenharmony_ci	case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
108862306a36Sopenharmony_ci	case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
108962306a36Sopenharmony_ci	case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
109062306a36Sopenharmony_ci	case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
109162306a36Sopenharmony_ci	case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
109262306a36Sopenharmony_ci	case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
109362306a36Sopenharmony_ci	case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
109462306a36Sopenharmony_ci	case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
109562306a36Sopenharmony_ci		break;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci/****************************************************************************
109862306a36Sopenharmony_ci*  For use by SCSI Initiator and SCSI Target end-to-end data protection
109962306a36Sopenharmony_ci****************************************************************************/
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
110262306a36Sopenharmony_ci		desc = "eedp guard error";
110362306a36Sopenharmony_ci		break;
110462306a36Sopenharmony_ci	case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
110562306a36Sopenharmony_ci		desc = "eedp ref tag error";
110662306a36Sopenharmony_ci		break;
110762306a36Sopenharmony_ci	case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
110862306a36Sopenharmony_ci		desc = "eedp app tag error";
110962306a36Sopenharmony_ci		break;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci/****************************************************************************
111262306a36Sopenharmony_ci*  SCSI Target values
111362306a36Sopenharmony_ci****************************************************************************/
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	case MPI2_IOCSTATUS_TARGET_INVALID_IO_INDEX:
111662306a36Sopenharmony_ci		desc = "target invalid io index";
111762306a36Sopenharmony_ci		break;
111862306a36Sopenharmony_ci	case MPI2_IOCSTATUS_TARGET_ABORTED:
111962306a36Sopenharmony_ci		desc = "target aborted";
112062306a36Sopenharmony_ci		break;
112162306a36Sopenharmony_ci	case MPI2_IOCSTATUS_TARGET_NO_CONN_RETRYABLE:
112262306a36Sopenharmony_ci		desc = "target no conn retryable";
112362306a36Sopenharmony_ci		break;
112462306a36Sopenharmony_ci	case MPI2_IOCSTATUS_TARGET_NO_CONNECTION:
112562306a36Sopenharmony_ci		desc = "target no connection";
112662306a36Sopenharmony_ci		break;
112762306a36Sopenharmony_ci	case MPI2_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH:
112862306a36Sopenharmony_ci		desc = "target xfer count mismatch";
112962306a36Sopenharmony_ci		break;
113062306a36Sopenharmony_ci	case MPI2_IOCSTATUS_TARGET_DATA_OFFSET_ERROR:
113162306a36Sopenharmony_ci		desc = "target data offset error";
113262306a36Sopenharmony_ci		break;
113362306a36Sopenharmony_ci	case MPI2_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA:
113462306a36Sopenharmony_ci		desc = "target too much write data";
113562306a36Sopenharmony_ci		break;
113662306a36Sopenharmony_ci	case MPI2_IOCSTATUS_TARGET_IU_TOO_SHORT:
113762306a36Sopenharmony_ci		desc = "target iu too short";
113862306a36Sopenharmony_ci		break;
113962306a36Sopenharmony_ci	case MPI2_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT:
114062306a36Sopenharmony_ci		desc = "target ack nak timeout";
114162306a36Sopenharmony_ci		break;
114262306a36Sopenharmony_ci	case MPI2_IOCSTATUS_TARGET_NAK_RECEIVED:
114362306a36Sopenharmony_ci		desc = "target nak received";
114462306a36Sopenharmony_ci		break;
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci/****************************************************************************
114762306a36Sopenharmony_ci*  Serial Attached SCSI values
114862306a36Sopenharmony_ci****************************************************************************/
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	case MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED:
115162306a36Sopenharmony_ci		desc = "smp request failed";
115262306a36Sopenharmony_ci		break;
115362306a36Sopenharmony_ci	case MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN:
115462306a36Sopenharmony_ci		desc = "smp data overrun";
115562306a36Sopenharmony_ci		break;
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci/****************************************************************************
115862306a36Sopenharmony_ci*  Diagnostic Buffer Post / Diagnostic Release values
115962306a36Sopenharmony_ci****************************************************************************/
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	case MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED:
116262306a36Sopenharmony_ci		desc = "diagnostic released";
116362306a36Sopenharmony_ci		break;
116462306a36Sopenharmony_ci	default:
116562306a36Sopenharmony_ci		break;
116662306a36Sopenharmony_ci	}
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	if (!desc)
116962306a36Sopenharmony_ci		return;
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	switch (request_hdr->Function) {
117262306a36Sopenharmony_ci	case MPI2_FUNCTION_CONFIG:
117362306a36Sopenharmony_ci		frame_sz = sizeof(Mpi2ConfigRequest_t) + ioc->sge_size;
117462306a36Sopenharmony_ci		func_str = "config_page";
117562306a36Sopenharmony_ci		break;
117662306a36Sopenharmony_ci	case MPI2_FUNCTION_SCSI_TASK_MGMT:
117762306a36Sopenharmony_ci		frame_sz = sizeof(Mpi2SCSITaskManagementRequest_t);
117862306a36Sopenharmony_ci		func_str = "task_mgmt";
117962306a36Sopenharmony_ci		break;
118062306a36Sopenharmony_ci	case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL:
118162306a36Sopenharmony_ci		frame_sz = sizeof(Mpi2SasIoUnitControlRequest_t);
118262306a36Sopenharmony_ci		func_str = "sas_iounit_ctl";
118362306a36Sopenharmony_ci		break;
118462306a36Sopenharmony_ci	case MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR:
118562306a36Sopenharmony_ci		frame_sz = sizeof(Mpi2SepRequest_t);
118662306a36Sopenharmony_ci		func_str = "enclosure";
118762306a36Sopenharmony_ci		break;
118862306a36Sopenharmony_ci	case MPI2_FUNCTION_IOC_INIT:
118962306a36Sopenharmony_ci		frame_sz = sizeof(Mpi2IOCInitRequest_t);
119062306a36Sopenharmony_ci		func_str = "ioc_init";
119162306a36Sopenharmony_ci		break;
119262306a36Sopenharmony_ci	case MPI2_FUNCTION_PORT_ENABLE:
119362306a36Sopenharmony_ci		frame_sz = sizeof(Mpi2PortEnableRequest_t);
119462306a36Sopenharmony_ci		func_str = "port_enable";
119562306a36Sopenharmony_ci		break;
119662306a36Sopenharmony_ci	case MPI2_FUNCTION_SMP_PASSTHROUGH:
119762306a36Sopenharmony_ci		frame_sz = sizeof(Mpi2SmpPassthroughRequest_t) + ioc->sge_size;
119862306a36Sopenharmony_ci		func_str = "smp_passthru";
119962306a36Sopenharmony_ci		break;
120062306a36Sopenharmony_ci	case MPI2_FUNCTION_NVME_ENCAPSULATED:
120162306a36Sopenharmony_ci		frame_sz = sizeof(Mpi26NVMeEncapsulatedRequest_t) +
120262306a36Sopenharmony_ci		    ioc->sge_size;
120362306a36Sopenharmony_ci		func_str = "nvme_encapsulated";
120462306a36Sopenharmony_ci		break;
120562306a36Sopenharmony_ci	default:
120662306a36Sopenharmony_ci		frame_sz = 32;
120762306a36Sopenharmony_ci		func_str = "unknown";
120862306a36Sopenharmony_ci		break;
120962306a36Sopenharmony_ci	}
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	ioc_warn(ioc, "ioc_status: %s(0x%04x), request(0x%p),(%s)\n",
121262306a36Sopenharmony_ci		 desc, ioc_status, request_hdr, func_str);
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	_debug_dump_mf(request_hdr, frame_sz/4);
121562306a36Sopenharmony_ci}
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci/**
121862306a36Sopenharmony_ci * _base_display_event_data - verbose translation of firmware asyn events
121962306a36Sopenharmony_ci * @ioc: per adapter object
122062306a36Sopenharmony_ci * @mpi_reply: reply mf payload returned from firmware
122162306a36Sopenharmony_ci */
122262306a36Sopenharmony_cistatic void
122362306a36Sopenharmony_ci_base_display_event_data(struct MPT3SAS_ADAPTER *ioc,
122462306a36Sopenharmony_ci	Mpi2EventNotificationReply_t *mpi_reply)
122562306a36Sopenharmony_ci{
122662306a36Sopenharmony_ci	char *desc = NULL;
122762306a36Sopenharmony_ci	u16 event;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	if (!(ioc->logging_level & MPT_DEBUG_EVENTS))
123062306a36Sopenharmony_ci		return;
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	event = le16_to_cpu(mpi_reply->Event);
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	switch (event) {
123562306a36Sopenharmony_ci	case MPI2_EVENT_LOG_DATA:
123662306a36Sopenharmony_ci		desc = "Log Data";
123762306a36Sopenharmony_ci		break;
123862306a36Sopenharmony_ci	case MPI2_EVENT_STATE_CHANGE:
123962306a36Sopenharmony_ci		desc = "Status Change";
124062306a36Sopenharmony_ci		break;
124162306a36Sopenharmony_ci	case MPI2_EVENT_HARD_RESET_RECEIVED:
124262306a36Sopenharmony_ci		desc = "Hard Reset Received";
124362306a36Sopenharmony_ci		break;
124462306a36Sopenharmony_ci	case MPI2_EVENT_EVENT_CHANGE:
124562306a36Sopenharmony_ci		desc = "Event Change";
124662306a36Sopenharmony_ci		break;
124762306a36Sopenharmony_ci	case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
124862306a36Sopenharmony_ci		desc = "Device Status Change";
124962306a36Sopenharmony_ci		break;
125062306a36Sopenharmony_ci	case MPI2_EVENT_IR_OPERATION_STATUS:
125162306a36Sopenharmony_ci		if (!ioc->hide_ir_msg)
125262306a36Sopenharmony_ci			desc = "IR Operation Status";
125362306a36Sopenharmony_ci		break;
125462306a36Sopenharmony_ci	case MPI2_EVENT_SAS_DISCOVERY:
125562306a36Sopenharmony_ci	{
125662306a36Sopenharmony_ci		Mpi2EventDataSasDiscovery_t *event_data =
125762306a36Sopenharmony_ci		    (Mpi2EventDataSasDiscovery_t *)mpi_reply->EventData;
125862306a36Sopenharmony_ci		ioc_info(ioc, "Discovery: (%s)",
125962306a36Sopenharmony_ci			 event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED ?
126062306a36Sopenharmony_ci			 "start" : "stop");
126162306a36Sopenharmony_ci		if (event_data->DiscoveryStatus)
126262306a36Sopenharmony_ci			pr_cont(" discovery_status(0x%08x)",
126362306a36Sopenharmony_ci			    le32_to_cpu(event_data->DiscoveryStatus));
126462306a36Sopenharmony_ci		pr_cont("\n");
126562306a36Sopenharmony_ci		return;
126662306a36Sopenharmony_ci	}
126762306a36Sopenharmony_ci	case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
126862306a36Sopenharmony_ci		desc = "SAS Broadcast Primitive";
126962306a36Sopenharmony_ci		break;
127062306a36Sopenharmony_ci	case MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
127162306a36Sopenharmony_ci		desc = "SAS Init Device Status Change";
127262306a36Sopenharmony_ci		break;
127362306a36Sopenharmony_ci	case MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW:
127462306a36Sopenharmony_ci		desc = "SAS Init Table Overflow";
127562306a36Sopenharmony_ci		break;
127662306a36Sopenharmony_ci	case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
127762306a36Sopenharmony_ci		desc = "SAS Topology Change List";
127862306a36Sopenharmony_ci		break;
127962306a36Sopenharmony_ci	case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
128062306a36Sopenharmony_ci		desc = "SAS Enclosure Device Status Change";
128162306a36Sopenharmony_ci		break;
128262306a36Sopenharmony_ci	case MPI2_EVENT_IR_VOLUME:
128362306a36Sopenharmony_ci		if (!ioc->hide_ir_msg)
128462306a36Sopenharmony_ci			desc = "IR Volume";
128562306a36Sopenharmony_ci		break;
128662306a36Sopenharmony_ci	case MPI2_EVENT_IR_PHYSICAL_DISK:
128762306a36Sopenharmony_ci		if (!ioc->hide_ir_msg)
128862306a36Sopenharmony_ci			desc = "IR Physical Disk";
128962306a36Sopenharmony_ci		break;
129062306a36Sopenharmony_ci	case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
129162306a36Sopenharmony_ci		if (!ioc->hide_ir_msg)
129262306a36Sopenharmony_ci			desc = "IR Configuration Change List";
129362306a36Sopenharmony_ci		break;
129462306a36Sopenharmony_ci	case MPI2_EVENT_LOG_ENTRY_ADDED:
129562306a36Sopenharmony_ci		if (!ioc->hide_ir_msg)
129662306a36Sopenharmony_ci			desc = "Log Entry Added";
129762306a36Sopenharmony_ci		break;
129862306a36Sopenharmony_ci	case MPI2_EVENT_TEMP_THRESHOLD:
129962306a36Sopenharmony_ci		desc = "Temperature Threshold";
130062306a36Sopenharmony_ci		break;
130162306a36Sopenharmony_ci	case MPI2_EVENT_ACTIVE_CABLE_EXCEPTION:
130262306a36Sopenharmony_ci		desc = "Cable Event";
130362306a36Sopenharmony_ci		break;
130462306a36Sopenharmony_ci	case MPI2_EVENT_SAS_DEVICE_DISCOVERY_ERROR:
130562306a36Sopenharmony_ci		desc = "SAS Device Discovery Error";
130662306a36Sopenharmony_ci		break;
130762306a36Sopenharmony_ci	case MPI2_EVENT_PCIE_DEVICE_STATUS_CHANGE:
130862306a36Sopenharmony_ci		desc = "PCIE Device Status Change";
130962306a36Sopenharmony_ci		break;
131062306a36Sopenharmony_ci	case MPI2_EVENT_PCIE_ENUMERATION:
131162306a36Sopenharmony_ci	{
131262306a36Sopenharmony_ci		Mpi26EventDataPCIeEnumeration_t *event_data =
131362306a36Sopenharmony_ci			(Mpi26EventDataPCIeEnumeration_t *)mpi_reply->EventData;
131462306a36Sopenharmony_ci		ioc_info(ioc, "PCIE Enumeration: (%s)",
131562306a36Sopenharmony_ci			 event_data->ReasonCode == MPI26_EVENT_PCIE_ENUM_RC_STARTED ?
131662306a36Sopenharmony_ci			 "start" : "stop");
131762306a36Sopenharmony_ci		if (event_data->EnumerationStatus)
131862306a36Sopenharmony_ci			pr_cont("enumeration_status(0x%08x)",
131962306a36Sopenharmony_ci				le32_to_cpu(event_data->EnumerationStatus));
132062306a36Sopenharmony_ci		pr_cont("\n");
132162306a36Sopenharmony_ci		return;
132262306a36Sopenharmony_ci	}
132362306a36Sopenharmony_ci	case MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
132462306a36Sopenharmony_ci		desc = "PCIE Topology Change List";
132562306a36Sopenharmony_ci		break;
132662306a36Sopenharmony_ci	}
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	if (!desc)
132962306a36Sopenharmony_ci		return;
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	ioc_info(ioc, "%s\n", desc);
133262306a36Sopenharmony_ci}
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci/**
133562306a36Sopenharmony_ci * _base_sas_log_info - verbose translation of firmware log info
133662306a36Sopenharmony_ci * @ioc: per adapter object
133762306a36Sopenharmony_ci * @log_info: log info
133862306a36Sopenharmony_ci */
133962306a36Sopenharmony_cistatic void
134062306a36Sopenharmony_ci_base_sas_log_info(struct MPT3SAS_ADAPTER *ioc, u32 log_info)
134162306a36Sopenharmony_ci{
134262306a36Sopenharmony_ci	union loginfo_type {
134362306a36Sopenharmony_ci		u32	loginfo;
134462306a36Sopenharmony_ci		struct {
134562306a36Sopenharmony_ci			u32	subcode:16;
134662306a36Sopenharmony_ci			u32	code:8;
134762306a36Sopenharmony_ci			u32	originator:4;
134862306a36Sopenharmony_ci			u32	bus_type:4;
134962306a36Sopenharmony_ci		} dw;
135062306a36Sopenharmony_ci	};
135162306a36Sopenharmony_ci	union loginfo_type sas_loginfo;
135262306a36Sopenharmony_ci	char *originator_str = NULL;
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	sas_loginfo.loginfo = log_info;
135562306a36Sopenharmony_ci	if (sas_loginfo.dw.bus_type != 3 /*SAS*/)
135662306a36Sopenharmony_ci		return;
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	/* each nexus loss loginfo */
135962306a36Sopenharmony_ci	if (log_info == 0x31170000)
136062306a36Sopenharmony_ci		return;
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	/* eat the loginfos associated with task aborts */
136362306a36Sopenharmony_ci	if (ioc->ignore_loginfos && (log_info == 0x30050000 || log_info ==
136462306a36Sopenharmony_ci	    0x31140000 || log_info == 0x31130000))
136562306a36Sopenharmony_ci		return;
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	switch (sas_loginfo.dw.originator) {
136862306a36Sopenharmony_ci	case 0:
136962306a36Sopenharmony_ci		originator_str = "IOP";
137062306a36Sopenharmony_ci		break;
137162306a36Sopenharmony_ci	case 1:
137262306a36Sopenharmony_ci		originator_str = "PL";
137362306a36Sopenharmony_ci		break;
137462306a36Sopenharmony_ci	case 2:
137562306a36Sopenharmony_ci		if (!ioc->hide_ir_msg)
137662306a36Sopenharmony_ci			originator_str = "IR";
137762306a36Sopenharmony_ci		else
137862306a36Sopenharmony_ci			originator_str = "WarpDrive";
137962306a36Sopenharmony_ci		break;
138062306a36Sopenharmony_ci	}
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	ioc_warn(ioc, "log_info(0x%08x): originator(%s), code(0x%02x), sub_code(0x%04x)\n",
138362306a36Sopenharmony_ci		 log_info,
138462306a36Sopenharmony_ci		 originator_str, sas_loginfo.dw.code, sas_loginfo.dw.subcode);
138562306a36Sopenharmony_ci}
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci/**
138862306a36Sopenharmony_ci * _base_display_reply_info - handle reply descriptors depending on IOC Status
138962306a36Sopenharmony_ci * @ioc: per adapter object
139062306a36Sopenharmony_ci * @smid: system request message index
139162306a36Sopenharmony_ci * @msix_index: MSIX table index supplied by the OS
139262306a36Sopenharmony_ci * @reply: reply message frame (lower 32bit addr)
139362306a36Sopenharmony_ci */
139462306a36Sopenharmony_cistatic void
139562306a36Sopenharmony_ci_base_display_reply_info(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
139662306a36Sopenharmony_ci	u32 reply)
139762306a36Sopenharmony_ci{
139862306a36Sopenharmony_ci	MPI2DefaultReply_t *mpi_reply;
139962306a36Sopenharmony_ci	u16 ioc_status;
140062306a36Sopenharmony_ci	u32 loginfo = 0;
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
140362306a36Sopenharmony_ci	if (unlikely(!mpi_reply)) {
140462306a36Sopenharmony_ci		ioc_err(ioc, "mpi_reply not valid at %s:%d/%s()!\n",
140562306a36Sopenharmony_ci			__FILE__, __LINE__, __func__);
140662306a36Sopenharmony_ci		return;
140762306a36Sopenharmony_ci	}
140862306a36Sopenharmony_ci	ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci	if ((ioc_status & MPI2_IOCSTATUS_MASK) &&
141162306a36Sopenharmony_ci	    (ioc->logging_level & MPT_DEBUG_REPLY)) {
141262306a36Sopenharmony_ci		_base_sas_ioc_info(ioc, mpi_reply,
141362306a36Sopenharmony_ci		   mpt3sas_base_get_msg_frame(ioc, smid));
141462306a36Sopenharmony_ci	}
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
141762306a36Sopenharmony_ci		loginfo = le32_to_cpu(mpi_reply->IOCLogInfo);
141862306a36Sopenharmony_ci		_base_sas_log_info(ioc, loginfo);
141962306a36Sopenharmony_ci	}
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	if (ioc_status || loginfo) {
142262306a36Sopenharmony_ci		ioc_status &= MPI2_IOCSTATUS_MASK;
142362306a36Sopenharmony_ci		mpt3sas_trigger_mpi(ioc, ioc_status, loginfo);
142462306a36Sopenharmony_ci	}
142562306a36Sopenharmony_ci}
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci/**
142862306a36Sopenharmony_ci * mpt3sas_base_done - base internal command completion routine
142962306a36Sopenharmony_ci * @ioc: per adapter object
143062306a36Sopenharmony_ci * @smid: system request message index
143162306a36Sopenharmony_ci * @msix_index: MSIX table index supplied by the OS
143262306a36Sopenharmony_ci * @reply: reply message frame(lower 32bit addr)
143362306a36Sopenharmony_ci *
143462306a36Sopenharmony_ci * Return:
143562306a36Sopenharmony_ci * 1 meaning mf should be freed from _base_interrupt
143662306a36Sopenharmony_ci * 0 means the mf is freed from this function.
143762306a36Sopenharmony_ci */
143862306a36Sopenharmony_ciu8
143962306a36Sopenharmony_cimpt3sas_base_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
144062306a36Sopenharmony_ci	u32 reply)
144162306a36Sopenharmony_ci{
144262306a36Sopenharmony_ci	MPI2DefaultReply_t *mpi_reply;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
144562306a36Sopenharmony_ci	if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK)
144662306a36Sopenharmony_ci		return mpt3sas_check_for_pending_internal_cmds(ioc, smid);
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci	if (ioc->base_cmds.status == MPT3_CMD_NOT_USED)
144962306a36Sopenharmony_ci		return 1;
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	ioc->base_cmds.status |= MPT3_CMD_COMPLETE;
145262306a36Sopenharmony_ci	if (mpi_reply) {
145362306a36Sopenharmony_ci		ioc->base_cmds.status |= MPT3_CMD_REPLY_VALID;
145462306a36Sopenharmony_ci		memcpy(ioc->base_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
145562306a36Sopenharmony_ci	}
145662306a36Sopenharmony_ci	ioc->base_cmds.status &= ~MPT3_CMD_PENDING;
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	complete(&ioc->base_cmds.done);
145962306a36Sopenharmony_ci	return 1;
146062306a36Sopenharmony_ci}
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci/**
146362306a36Sopenharmony_ci * _base_async_event - main callback handler for firmware asyn events
146462306a36Sopenharmony_ci * @ioc: per adapter object
146562306a36Sopenharmony_ci * @msix_index: MSIX table index supplied by the OS
146662306a36Sopenharmony_ci * @reply: reply message frame(lower 32bit addr)
146762306a36Sopenharmony_ci *
146862306a36Sopenharmony_ci * Return:
146962306a36Sopenharmony_ci * 1 meaning mf should be freed from _base_interrupt
147062306a36Sopenharmony_ci * 0 means the mf is freed from this function.
147162306a36Sopenharmony_ci */
147262306a36Sopenharmony_cistatic u8
147362306a36Sopenharmony_ci_base_async_event(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, u32 reply)
147462306a36Sopenharmony_ci{
147562306a36Sopenharmony_ci	Mpi2EventNotificationReply_t *mpi_reply;
147662306a36Sopenharmony_ci	Mpi2EventAckRequest_t *ack_request;
147762306a36Sopenharmony_ci	u16 smid;
147862306a36Sopenharmony_ci	struct _event_ack_list *delayed_event_ack;
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
148162306a36Sopenharmony_ci	if (!mpi_reply)
148262306a36Sopenharmony_ci		return 1;
148362306a36Sopenharmony_ci	if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION)
148462306a36Sopenharmony_ci		return 1;
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	_base_display_event_data(ioc, mpi_reply);
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	if (!(mpi_reply->AckRequired & MPI2_EVENT_NOTIFICATION_ACK_REQUIRED))
148962306a36Sopenharmony_ci		goto out;
149062306a36Sopenharmony_ci	smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx);
149162306a36Sopenharmony_ci	if (!smid) {
149262306a36Sopenharmony_ci		delayed_event_ack = kzalloc(sizeof(*delayed_event_ack),
149362306a36Sopenharmony_ci					GFP_ATOMIC);
149462306a36Sopenharmony_ci		if (!delayed_event_ack)
149562306a36Sopenharmony_ci			goto out;
149662306a36Sopenharmony_ci		INIT_LIST_HEAD(&delayed_event_ack->list);
149762306a36Sopenharmony_ci		delayed_event_ack->Event = mpi_reply->Event;
149862306a36Sopenharmony_ci		delayed_event_ack->EventContext = mpi_reply->EventContext;
149962306a36Sopenharmony_ci		list_add_tail(&delayed_event_ack->list,
150062306a36Sopenharmony_ci				&ioc->delayed_event_ack_list);
150162306a36Sopenharmony_ci		dewtprintk(ioc,
150262306a36Sopenharmony_ci			   ioc_info(ioc, "DELAYED: EVENT ACK: event (0x%04x)\n",
150362306a36Sopenharmony_ci				    le16_to_cpu(mpi_reply->Event)));
150462306a36Sopenharmony_ci		goto out;
150562306a36Sopenharmony_ci	}
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci	ack_request = mpt3sas_base_get_msg_frame(ioc, smid);
150862306a36Sopenharmony_ci	memset(ack_request, 0, sizeof(Mpi2EventAckRequest_t));
150962306a36Sopenharmony_ci	ack_request->Function = MPI2_FUNCTION_EVENT_ACK;
151062306a36Sopenharmony_ci	ack_request->Event = mpi_reply->Event;
151162306a36Sopenharmony_ci	ack_request->EventContext = mpi_reply->EventContext;
151262306a36Sopenharmony_ci	ack_request->VF_ID = 0;  /* TODO */
151362306a36Sopenharmony_ci	ack_request->VP_ID = 0;
151462306a36Sopenharmony_ci	ioc->put_smid_default(ioc, smid);
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci out:
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	/* scsih callback handler */
151962306a36Sopenharmony_ci	mpt3sas_scsih_event_callback(ioc, msix_index, reply);
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	/* ctl callback handler */
152262306a36Sopenharmony_ci	mpt3sas_ctl_event_callback(ioc, msix_index, reply);
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	return 1;
152562306a36Sopenharmony_ci}
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_cistatic struct scsiio_tracker *
152862306a36Sopenharmony_ci_get_st_from_smid(struct MPT3SAS_ADAPTER *ioc, u16 smid)
152962306a36Sopenharmony_ci{
153062306a36Sopenharmony_ci	struct scsi_cmnd *cmd;
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci	if (WARN_ON(!smid) ||
153362306a36Sopenharmony_ci	    WARN_ON(smid >= ioc->hi_priority_smid))
153462306a36Sopenharmony_ci		return NULL;
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci	cmd = mpt3sas_scsih_scsi_lookup_get(ioc, smid);
153762306a36Sopenharmony_ci	if (cmd)
153862306a36Sopenharmony_ci		return scsi_cmd_priv(cmd);
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci	return NULL;
154162306a36Sopenharmony_ci}
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci/**
154462306a36Sopenharmony_ci * _base_get_cb_idx - obtain the callback index
154562306a36Sopenharmony_ci * @ioc: per adapter object
154662306a36Sopenharmony_ci * @smid: system request message index
154762306a36Sopenharmony_ci *
154862306a36Sopenharmony_ci * Return: callback index.
154962306a36Sopenharmony_ci */
155062306a36Sopenharmony_cistatic u8
155162306a36Sopenharmony_ci_base_get_cb_idx(struct MPT3SAS_ADAPTER *ioc, u16 smid)
155262306a36Sopenharmony_ci{
155362306a36Sopenharmony_ci	int i;
155462306a36Sopenharmony_ci	u16 ctl_smid = ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT + 1;
155562306a36Sopenharmony_ci	u8 cb_idx = 0xFF;
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	if (smid < ioc->hi_priority_smid) {
155862306a36Sopenharmony_ci		struct scsiio_tracker *st;
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci		if (smid < ctl_smid) {
156162306a36Sopenharmony_ci			st = _get_st_from_smid(ioc, smid);
156262306a36Sopenharmony_ci			if (st)
156362306a36Sopenharmony_ci				cb_idx = st->cb_idx;
156462306a36Sopenharmony_ci		} else if (smid == ctl_smid)
156562306a36Sopenharmony_ci			cb_idx = ioc->ctl_cb_idx;
156662306a36Sopenharmony_ci	} else if (smid < ioc->internal_smid) {
156762306a36Sopenharmony_ci		i = smid - ioc->hi_priority_smid;
156862306a36Sopenharmony_ci		cb_idx = ioc->hpr_lookup[i].cb_idx;
156962306a36Sopenharmony_ci	} else if (smid <= ioc->hba_queue_depth) {
157062306a36Sopenharmony_ci		i = smid - ioc->internal_smid;
157162306a36Sopenharmony_ci		cb_idx = ioc->internal_lookup[i].cb_idx;
157262306a36Sopenharmony_ci	}
157362306a36Sopenharmony_ci	return cb_idx;
157462306a36Sopenharmony_ci}
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci/**
157762306a36Sopenharmony_ci * mpt3sas_base_pause_mq_polling - pause polling on the mq poll queues
157862306a36Sopenharmony_ci *				when driver is flushing out the IOs.
157962306a36Sopenharmony_ci * @ioc: per adapter object
158062306a36Sopenharmony_ci *
158162306a36Sopenharmony_ci * Pause polling on the mq poll (io uring) queues when driver is flushing
158262306a36Sopenharmony_ci * out the IOs. Otherwise we may see the race condition of completing the same
158362306a36Sopenharmony_ci * IO from two paths.
158462306a36Sopenharmony_ci *
158562306a36Sopenharmony_ci * Returns nothing.
158662306a36Sopenharmony_ci */
158762306a36Sopenharmony_civoid
158862306a36Sopenharmony_cimpt3sas_base_pause_mq_polling(struct MPT3SAS_ADAPTER *ioc)
158962306a36Sopenharmony_ci{
159062306a36Sopenharmony_ci	int iopoll_q_count =
159162306a36Sopenharmony_ci	    ioc->reply_queue_count - ioc->iopoll_q_start_index;
159262306a36Sopenharmony_ci	int qid;
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	for (qid = 0; qid < iopoll_q_count; qid++)
159562306a36Sopenharmony_ci		atomic_set(&ioc->io_uring_poll_queues[qid].pause, 1);
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci	/*
159862306a36Sopenharmony_ci	 * wait for current poll to complete.
159962306a36Sopenharmony_ci	 */
160062306a36Sopenharmony_ci	for (qid = 0; qid < iopoll_q_count; qid++) {
160162306a36Sopenharmony_ci		while (atomic_read(&ioc->io_uring_poll_queues[qid].busy)) {
160262306a36Sopenharmony_ci			cpu_relax();
160362306a36Sopenharmony_ci			udelay(500);
160462306a36Sopenharmony_ci		}
160562306a36Sopenharmony_ci	}
160662306a36Sopenharmony_ci}
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci/**
160962306a36Sopenharmony_ci * mpt3sas_base_resume_mq_polling - Resume polling on mq poll queues.
161062306a36Sopenharmony_ci * @ioc: per adapter object
161162306a36Sopenharmony_ci *
161262306a36Sopenharmony_ci * Returns nothing.
161362306a36Sopenharmony_ci */
161462306a36Sopenharmony_civoid
161562306a36Sopenharmony_cimpt3sas_base_resume_mq_polling(struct MPT3SAS_ADAPTER *ioc)
161662306a36Sopenharmony_ci{
161762306a36Sopenharmony_ci	int iopoll_q_count =
161862306a36Sopenharmony_ci	    ioc->reply_queue_count - ioc->iopoll_q_start_index;
161962306a36Sopenharmony_ci	int qid;
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	for (qid = 0; qid < iopoll_q_count; qid++)
162262306a36Sopenharmony_ci		atomic_set(&ioc->io_uring_poll_queues[qid].pause, 0);
162362306a36Sopenharmony_ci}
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci/**
162662306a36Sopenharmony_ci * mpt3sas_base_mask_interrupts - disable interrupts
162762306a36Sopenharmony_ci * @ioc: per adapter object
162862306a36Sopenharmony_ci *
162962306a36Sopenharmony_ci * Disabling ResetIRQ, Reply and Doorbell Interrupts
163062306a36Sopenharmony_ci */
163162306a36Sopenharmony_civoid
163262306a36Sopenharmony_cimpt3sas_base_mask_interrupts(struct MPT3SAS_ADAPTER *ioc)
163362306a36Sopenharmony_ci{
163462306a36Sopenharmony_ci	u32 him_register;
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	ioc->mask_interrupts = 1;
163762306a36Sopenharmony_ci	him_register = ioc->base_readl(&ioc->chip->HostInterruptMask);
163862306a36Sopenharmony_ci	him_register |= MPI2_HIM_DIM + MPI2_HIM_RIM + MPI2_HIM_RESET_IRQ_MASK;
163962306a36Sopenharmony_ci	writel(him_register, &ioc->chip->HostInterruptMask);
164062306a36Sopenharmony_ci	ioc->base_readl(&ioc->chip->HostInterruptMask);
164162306a36Sopenharmony_ci}
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci/**
164462306a36Sopenharmony_ci * mpt3sas_base_unmask_interrupts - enable interrupts
164562306a36Sopenharmony_ci * @ioc: per adapter object
164662306a36Sopenharmony_ci *
164762306a36Sopenharmony_ci * Enabling only Reply Interrupts
164862306a36Sopenharmony_ci */
164962306a36Sopenharmony_civoid
165062306a36Sopenharmony_cimpt3sas_base_unmask_interrupts(struct MPT3SAS_ADAPTER *ioc)
165162306a36Sopenharmony_ci{
165262306a36Sopenharmony_ci	u32 him_register;
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	him_register = ioc->base_readl(&ioc->chip->HostInterruptMask);
165562306a36Sopenharmony_ci	him_register &= ~MPI2_HIM_RIM;
165662306a36Sopenharmony_ci	writel(him_register, &ioc->chip->HostInterruptMask);
165762306a36Sopenharmony_ci	ioc->mask_interrupts = 0;
165862306a36Sopenharmony_ci}
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ciunion reply_descriptor {
166162306a36Sopenharmony_ci	u64 word;
166262306a36Sopenharmony_ci	struct {
166362306a36Sopenharmony_ci		u32 low;
166462306a36Sopenharmony_ci		u32 high;
166562306a36Sopenharmony_ci	} u;
166662306a36Sopenharmony_ci};
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_cistatic u32 base_mod64(u64 dividend, u32 divisor)
166962306a36Sopenharmony_ci{
167062306a36Sopenharmony_ci	u32 remainder;
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	if (!divisor)
167362306a36Sopenharmony_ci		pr_err("mpt3sas: DIVISOR is zero, in div fn\n");
167462306a36Sopenharmony_ci	remainder = do_div(dividend, divisor);
167562306a36Sopenharmony_ci	return remainder;
167662306a36Sopenharmony_ci}
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci/**
167962306a36Sopenharmony_ci * _base_process_reply_queue - Process reply descriptors from reply
168062306a36Sopenharmony_ci *		descriptor post queue.
168162306a36Sopenharmony_ci * @reply_q: per IRQ's reply queue object.
168262306a36Sopenharmony_ci *
168362306a36Sopenharmony_ci * Return: number of reply descriptors processed from reply
168462306a36Sopenharmony_ci *		descriptor queue.
168562306a36Sopenharmony_ci */
168662306a36Sopenharmony_cistatic int
168762306a36Sopenharmony_ci_base_process_reply_queue(struct adapter_reply_queue *reply_q)
168862306a36Sopenharmony_ci{
168962306a36Sopenharmony_ci	union reply_descriptor rd;
169062306a36Sopenharmony_ci	u64 completed_cmds;
169162306a36Sopenharmony_ci	u8 request_descript_type;
169262306a36Sopenharmony_ci	u16 smid;
169362306a36Sopenharmony_ci	u8 cb_idx;
169462306a36Sopenharmony_ci	u32 reply;
169562306a36Sopenharmony_ci	u8 msix_index = reply_q->msix_index;
169662306a36Sopenharmony_ci	struct MPT3SAS_ADAPTER *ioc = reply_q->ioc;
169762306a36Sopenharmony_ci	Mpi2ReplyDescriptorsUnion_t *rpf;
169862306a36Sopenharmony_ci	u8 rc;
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	completed_cmds = 0;
170162306a36Sopenharmony_ci	if (!atomic_add_unless(&reply_q->busy, 1, 1))
170262306a36Sopenharmony_ci		return completed_cmds;
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	rpf = &reply_q->reply_post_free[reply_q->reply_post_host_index];
170562306a36Sopenharmony_ci	request_descript_type = rpf->Default.ReplyFlags
170662306a36Sopenharmony_ci	     & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
170762306a36Sopenharmony_ci	if (request_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) {
170862306a36Sopenharmony_ci		atomic_dec(&reply_q->busy);
170962306a36Sopenharmony_ci		return completed_cmds;
171062306a36Sopenharmony_ci	}
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	cb_idx = 0xFF;
171362306a36Sopenharmony_ci	do {
171462306a36Sopenharmony_ci		rd.word = le64_to_cpu(rpf->Words);
171562306a36Sopenharmony_ci		if (rd.u.low == UINT_MAX || rd.u.high == UINT_MAX)
171662306a36Sopenharmony_ci			goto out;
171762306a36Sopenharmony_ci		reply = 0;
171862306a36Sopenharmony_ci		smid = le16_to_cpu(rpf->Default.DescriptorTypeDependent1);
171962306a36Sopenharmony_ci		if (request_descript_type ==
172062306a36Sopenharmony_ci		    MPI25_RPY_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO_SUCCESS ||
172162306a36Sopenharmony_ci		    request_descript_type ==
172262306a36Sopenharmony_ci		    MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS ||
172362306a36Sopenharmony_ci		    request_descript_type ==
172462306a36Sopenharmony_ci		    MPI26_RPY_DESCRIPT_FLAGS_PCIE_ENCAPSULATED_SUCCESS) {
172562306a36Sopenharmony_ci			cb_idx = _base_get_cb_idx(ioc, smid);
172662306a36Sopenharmony_ci			if ((likely(cb_idx < MPT_MAX_CALLBACKS)) &&
172762306a36Sopenharmony_ci			    (likely(mpt_callbacks[cb_idx] != NULL))) {
172862306a36Sopenharmony_ci				rc = mpt_callbacks[cb_idx](ioc, smid,
172962306a36Sopenharmony_ci				    msix_index, 0);
173062306a36Sopenharmony_ci				if (rc)
173162306a36Sopenharmony_ci					mpt3sas_base_free_smid(ioc, smid);
173262306a36Sopenharmony_ci			}
173362306a36Sopenharmony_ci		} else if (request_descript_type ==
173462306a36Sopenharmony_ci		    MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) {
173562306a36Sopenharmony_ci			reply = le32_to_cpu(
173662306a36Sopenharmony_ci			    rpf->AddressReply.ReplyFrameAddress);
173762306a36Sopenharmony_ci			if (reply > ioc->reply_dma_max_address ||
173862306a36Sopenharmony_ci			    reply < ioc->reply_dma_min_address)
173962306a36Sopenharmony_ci				reply = 0;
174062306a36Sopenharmony_ci			if (smid) {
174162306a36Sopenharmony_ci				cb_idx = _base_get_cb_idx(ioc, smid);
174262306a36Sopenharmony_ci				if ((likely(cb_idx < MPT_MAX_CALLBACKS)) &&
174362306a36Sopenharmony_ci				    (likely(mpt_callbacks[cb_idx] != NULL))) {
174462306a36Sopenharmony_ci					rc = mpt_callbacks[cb_idx](ioc, smid,
174562306a36Sopenharmony_ci					    msix_index, reply);
174662306a36Sopenharmony_ci					if (reply)
174762306a36Sopenharmony_ci						_base_display_reply_info(ioc,
174862306a36Sopenharmony_ci						    smid, msix_index, reply);
174962306a36Sopenharmony_ci					if (rc)
175062306a36Sopenharmony_ci						mpt3sas_base_free_smid(ioc,
175162306a36Sopenharmony_ci						    smid);
175262306a36Sopenharmony_ci				}
175362306a36Sopenharmony_ci			} else {
175462306a36Sopenharmony_ci				_base_async_event(ioc, msix_index, reply);
175562306a36Sopenharmony_ci			}
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci			/* reply free queue handling */
175862306a36Sopenharmony_ci			if (reply) {
175962306a36Sopenharmony_ci				ioc->reply_free_host_index =
176062306a36Sopenharmony_ci				    (ioc->reply_free_host_index ==
176162306a36Sopenharmony_ci				    (ioc->reply_free_queue_depth - 1)) ?
176262306a36Sopenharmony_ci				    0 : ioc->reply_free_host_index + 1;
176362306a36Sopenharmony_ci				ioc->reply_free[ioc->reply_free_host_index] =
176462306a36Sopenharmony_ci				    cpu_to_le32(reply);
176562306a36Sopenharmony_ci				if (ioc->is_mcpu_endpoint)
176662306a36Sopenharmony_ci					_base_clone_reply_to_sys_mem(ioc,
176762306a36Sopenharmony_ci						reply,
176862306a36Sopenharmony_ci						ioc->reply_free_host_index);
176962306a36Sopenharmony_ci				writel(ioc->reply_free_host_index,
177062306a36Sopenharmony_ci				    &ioc->chip->ReplyFreeHostIndex);
177162306a36Sopenharmony_ci			}
177262306a36Sopenharmony_ci		}
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci		rpf->Words = cpu_to_le64(ULLONG_MAX);
177562306a36Sopenharmony_ci		reply_q->reply_post_host_index =
177662306a36Sopenharmony_ci		    (reply_q->reply_post_host_index ==
177762306a36Sopenharmony_ci		    (ioc->reply_post_queue_depth - 1)) ? 0 :
177862306a36Sopenharmony_ci		    reply_q->reply_post_host_index + 1;
177962306a36Sopenharmony_ci		request_descript_type =
178062306a36Sopenharmony_ci		    reply_q->reply_post_free[reply_q->reply_post_host_index].
178162306a36Sopenharmony_ci		    Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
178262306a36Sopenharmony_ci		completed_cmds++;
178362306a36Sopenharmony_ci		/* Update the reply post host index after continuously
178462306a36Sopenharmony_ci		 * processing the threshold number of Reply Descriptors.
178562306a36Sopenharmony_ci		 * So that FW can find enough entries to post the Reply
178662306a36Sopenharmony_ci		 * Descriptors in the reply descriptor post queue.
178762306a36Sopenharmony_ci		 */
178862306a36Sopenharmony_ci		if (completed_cmds >= ioc->thresh_hold) {
178962306a36Sopenharmony_ci			if (ioc->combined_reply_queue) {
179062306a36Sopenharmony_ci				writel(reply_q->reply_post_host_index |
179162306a36Sopenharmony_ci						((msix_index  & 7) <<
179262306a36Sopenharmony_ci						 MPI2_RPHI_MSIX_INDEX_SHIFT),
179362306a36Sopenharmony_ci				    ioc->replyPostRegisterIndex[msix_index/8]);
179462306a36Sopenharmony_ci			} else {
179562306a36Sopenharmony_ci				writel(reply_q->reply_post_host_index |
179662306a36Sopenharmony_ci						(msix_index <<
179762306a36Sopenharmony_ci						 MPI2_RPHI_MSIX_INDEX_SHIFT),
179862306a36Sopenharmony_ci						&ioc->chip->ReplyPostHostIndex);
179962306a36Sopenharmony_ci			}
180062306a36Sopenharmony_ci			if (!reply_q->is_iouring_poll_q &&
180162306a36Sopenharmony_ci			    !reply_q->irq_poll_scheduled) {
180262306a36Sopenharmony_ci				reply_q->irq_poll_scheduled = true;
180362306a36Sopenharmony_ci				irq_poll_sched(&reply_q->irqpoll);
180462306a36Sopenharmony_ci			}
180562306a36Sopenharmony_ci			atomic_dec(&reply_q->busy);
180662306a36Sopenharmony_ci			return completed_cmds;
180762306a36Sopenharmony_ci		}
180862306a36Sopenharmony_ci		if (request_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
180962306a36Sopenharmony_ci			goto out;
181062306a36Sopenharmony_ci		if (!reply_q->reply_post_host_index)
181162306a36Sopenharmony_ci			rpf = reply_q->reply_post_free;
181262306a36Sopenharmony_ci		else
181362306a36Sopenharmony_ci			rpf++;
181462306a36Sopenharmony_ci	} while (1);
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci out:
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	if (!completed_cmds) {
181962306a36Sopenharmony_ci		atomic_dec(&reply_q->busy);
182062306a36Sopenharmony_ci		return completed_cmds;
182162306a36Sopenharmony_ci	}
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	if (ioc->is_warpdrive) {
182462306a36Sopenharmony_ci		writel(reply_q->reply_post_host_index,
182562306a36Sopenharmony_ci		ioc->reply_post_host_index[msix_index]);
182662306a36Sopenharmony_ci		atomic_dec(&reply_q->busy);
182762306a36Sopenharmony_ci		return completed_cmds;
182862306a36Sopenharmony_ci	}
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	/* Update Reply Post Host Index.
183162306a36Sopenharmony_ci	 * For those HBA's which support combined reply queue feature
183262306a36Sopenharmony_ci	 * 1. Get the correct Supplemental Reply Post Host Index Register.
183362306a36Sopenharmony_ci	 *    i.e. (msix_index / 8)th entry from Supplemental Reply Post Host
183462306a36Sopenharmony_ci	 *    Index Register address bank i.e replyPostRegisterIndex[],
183562306a36Sopenharmony_ci	 * 2. Then update this register with new reply host index value
183662306a36Sopenharmony_ci	 *    in ReplyPostIndex field and the MSIxIndex field with
183762306a36Sopenharmony_ci	 *    msix_index value reduced to a value between 0 and 7,
183862306a36Sopenharmony_ci	 *    using a modulo 8 operation. Since each Supplemental Reply Post
183962306a36Sopenharmony_ci	 *    Host Index Register supports 8 MSI-X vectors.
184062306a36Sopenharmony_ci	 *
184162306a36Sopenharmony_ci	 * For other HBA's just update the Reply Post Host Index register with
184262306a36Sopenharmony_ci	 * new reply host index value in ReplyPostIndex Field and msix_index
184362306a36Sopenharmony_ci	 * value in MSIxIndex field.
184462306a36Sopenharmony_ci	 */
184562306a36Sopenharmony_ci	if (ioc->combined_reply_queue)
184662306a36Sopenharmony_ci		writel(reply_q->reply_post_host_index | ((msix_index  & 7) <<
184762306a36Sopenharmony_ci			MPI2_RPHI_MSIX_INDEX_SHIFT),
184862306a36Sopenharmony_ci			ioc->replyPostRegisterIndex[msix_index/8]);
184962306a36Sopenharmony_ci	else
185062306a36Sopenharmony_ci		writel(reply_q->reply_post_host_index | (msix_index <<
185162306a36Sopenharmony_ci			MPI2_RPHI_MSIX_INDEX_SHIFT),
185262306a36Sopenharmony_ci			&ioc->chip->ReplyPostHostIndex);
185362306a36Sopenharmony_ci	atomic_dec(&reply_q->busy);
185462306a36Sopenharmony_ci	return completed_cmds;
185562306a36Sopenharmony_ci}
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_ci/**
185862306a36Sopenharmony_ci * mpt3sas_blk_mq_poll - poll the blk mq poll queue
185962306a36Sopenharmony_ci * @shost: Scsi_Host object
186062306a36Sopenharmony_ci * @queue_num: hw ctx queue number
186162306a36Sopenharmony_ci *
186262306a36Sopenharmony_ci * Return number of entries that has been processed from poll queue.
186362306a36Sopenharmony_ci */
186462306a36Sopenharmony_ciint mpt3sas_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
186562306a36Sopenharmony_ci{
186662306a36Sopenharmony_ci	struct MPT3SAS_ADAPTER *ioc =
186762306a36Sopenharmony_ci	    (struct MPT3SAS_ADAPTER *)shost->hostdata;
186862306a36Sopenharmony_ci	struct adapter_reply_queue *reply_q;
186962306a36Sopenharmony_ci	int num_entries = 0;
187062306a36Sopenharmony_ci	int qid = queue_num - ioc->iopoll_q_start_index;
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_ci	if (atomic_read(&ioc->io_uring_poll_queues[qid].pause) ||
187362306a36Sopenharmony_ci	    !atomic_add_unless(&ioc->io_uring_poll_queues[qid].busy, 1, 1))
187462306a36Sopenharmony_ci		return 0;
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	reply_q = ioc->io_uring_poll_queues[qid].reply_q;
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci	num_entries = _base_process_reply_queue(reply_q);
187962306a36Sopenharmony_ci	atomic_dec(&ioc->io_uring_poll_queues[qid].busy);
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	return num_entries;
188262306a36Sopenharmony_ci}
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci/**
188562306a36Sopenharmony_ci * _base_interrupt - MPT adapter (IOC) specific interrupt handler.
188662306a36Sopenharmony_ci * @irq: irq number (not used)
188762306a36Sopenharmony_ci * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
188862306a36Sopenharmony_ci *
188962306a36Sopenharmony_ci * Return: IRQ_HANDLED if processed, else IRQ_NONE.
189062306a36Sopenharmony_ci */
189162306a36Sopenharmony_cistatic irqreturn_t
189262306a36Sopenharmony_ci_base_interrupt(int irq, void *bus_id)
189362306a36Sopenharmony_ci{
189462306a36Sopenharmony_ci	struct adapter_reply_queue *reply_q = bus_id;
189562306a36Sopenharmony_ci	struct MPT3SAS_ADAPTER *ioc = reply_q->ioc;
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ci	if (ioc->mask_interrupts)
189862306a36Sopenharmony_ci		return IRQ_NONE;
189962306a36Sopenharmony_ci	if (reply_q->irq_poll_scheduled)
190062306a36Sopenharmony_ci		return IRQ_HANDLED;
190162306a36Sopenharmony_ci	return ((_base_process_reply_queue(reply_q) > 0) ?
190262306a36Sopenharmony_ci			IRQ_HANDLED : IRQ_NONE);
190362306a36Sopenharmony_ci}
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci/**
190662306a36Sopenharmony_ci * _base_irqpoll - IRQ poll callback handler
190762306a36Sopenharmony_ci * @irqpoll: irq_poll object
190862306a36Sopenharmony_ci * @budget: irq poll weight
190962306a36Sopenharmony_ci *
191062306a36Sopenharmony_ci * Return: number of reply descriptors processed
191162306a36Sopenharmony_ci */
191262306a36Sopenharmony_cistatic int
191362306a36Sopenharmony_ci_base_irqpoll(struct irq_poll *irqpoll, int budget)
191462306a36Sopenharmony_ci{
191562306a36Sopenharmony_ci	struct adapter_reply_queue *reply_q;
191662306a36Sopenharmony_ci	int num_entries = 0;
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci	reply_q = container_of(irqpoll, struct adapter_reply_queue,
191962306a36Sopenharmony_ci			irqpoll);
192062306a36Sopenharmony_ci	if (reply_q->irq_line_enable) {
192162306a36Sopenharmony_ci		disable_irq_nosync(reply_q->os_irq);
192262306a36Sopenharmony_ci		reply_q->irq_line_enable = false;
192362306a36Sopenharmony_ci	}
192462306a36Sopenharmony_ci	num_entries = _base_process_reply_queue(reply_q);
192562306a36Sopenharmony_ci	if (num_entries < budget) {
192662306a36Sopenharmony_ci		irq_poll_complete(irqpoll);
192762306a36Sopenharmony_ci		reply_q->irq_poll_scheduled = false;
192862306a36Sopenharmony_ci		reply_q->irq_line_enable = true;
192962306a36Sopenharmony_ci		enable_irq(reply_q->os_irq);
193062306a36Sopenharmony_ci		/*
193162306a36Sopenharmony_ci		 * Go for one more round of processing the
193262306a36Sopenharmony_ci		 * reply descriptor post queue in case the HBA
193362306a36Sopenharmony_ci		 * Firmware has posted some reply descriptors
193462306a36Sopenharmony_ci		 * while reenabling the IRQ.
193562306a36Sopenharmony_ci		 */
193662306a36Sopenharmony_ci		_base_process_reply_queue(reply_q);
193762306a36Sopenharmony_ci	}
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	return num_entries;
194062306a36Sopenharmony_ci}
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci/**
194362306a36Sopenharmony_ci * _base_init_irqpolls - initliaze IRQ polls
194462306a36Sopenharmony_ci * @ioc: per adapter object
194562306a36Sopenharmony_ci *
194662306a36Sopenharmony_ci * Return: nothing
194762306a36Sopenharmony_ci */
194862306a36Sopenharmony_cistatic void
194962306a36Sopenharmony_ci_base_init_irqpolls(struct MPT3SAS_ADAPTER *ioc)
195062306a36Sopenharmony_ci{
195162306a36Sopenharmony_ci	struct adapter_reply_queue *reply_q, *next;
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_ci	if (list_empty(&ioc->reply_queue_list))
195462306a36Sopenharmony_ci		return;
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) {
195762306a36Sopenharmony_ci		if (reply_q->is_iouring_poll_q)
195862306a36Sopenharmony_ci			continue;
195962306a36Sopenharmony_ci		irq_poll_init(&reply_q->irqpoll,
196062306a36Sopenharmony_ci			ioc->hba_queue_depth/4, _base_irqpoll);
196162306a36Sopenharmony_ci		reply_q->irq_poll_scheduled = false;
196262306a36Sopenharmony_ci		reply_q->irq_line_enable = true;
196362306a36Sopenharmony_ci		reply_q->os_irq = pci_irq_vector(ioc->pdev,
196462306a36Sopenharmony_ci		    reply_q->msix_index);
196562306a36Sopenharmony_ci	}
196662306a36Sopenharmony_ci}
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci/**
196962306a36Sopenharmony_ci * _base_is_controller_msix_enabled - is controller support muli-reply queues
197062306a36Sopenharmony_ci * @ioc: per adapter object
197162306a36Sopenharmony_ci *
197262306a36Sopenharmony_ci * Return: Whether or not MSI/X is enabled.
197362306a36Sopenharmony_ci */
197462306a36Sopenharmony_cistatic inline int
197562306a36Sopenharmony_ci_base_is_controller_msix_enabled(struct MPT3SAS_ADAPTER *ioc)
197662306a36Sopenharmony_ci{
197762306a36Sopenharmony_ci	return (ioc->facts.IOCCapabilities &
197862306a36Sopenharmony_ci	    MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable;
197962306a36Sopenharmony_ci}
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci/**
198262306a36Sopenharmony_ci * mpt3sas_base_sync_reply_irqs - flush pending MSIX interrupts
198362306a36Sopenharmony_ci * @ioc: per adapter object
198462306a36Sopenharmony_ci * @poll: poll over reply descriptor pools incase interrupt for
198562306a36Sopenharmony_ci *		timed-out SCSI command got delayed
198662306a36Sopenharmony_ci * Context: non-ISR context
198762306a36Sopenharmony_ci *
198862306a36Sopenharmony_ci * Called when a Task Management request has completed.
198962306a36Sopenharmony_ci */
199062306a36Sopenharmony_civoid
199162306a36Sopenharmony_cimpt3sas_base_sync_reply_irqs(struct MPT3SAS_ADAPTER *ioc, u8 poll)
199262306a36Sopenharmony_ci{
199362306a36Sopenharmony_ci	struct adapter_reply_queue *reply_q;
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci	/* If MSIX capability is turned off
199662306a36Sopenharmony_ci	 * then multi-queues are not enabled
199762306a36Sopenharmony_ci	 */
199862306a36Sopenharmony_ci	if (!_base_is_controller_msix_enabled(ioc))
199962306a36Sopenharmony_ci		return;
200062306a36Sopenharmony_ci
200162306a36Sopenharmony_ci	list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
200262306a36Sopenharmony_ci		if (ioc->shost_recovery || ioc->remove_host ||
200362306a36Sopenharmony_ci				ioc->pci_error_recovery)
200462306a36Sopenharmony_ci			return;
200562306a36Sopenharmony_ci		/* TMs are on msix_index == 0 */
200662306a36Sopenharmony_ci		if (reply_q->msix_index == 0)
200762306a36Sopenharmony_ci			continue;
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci		if (reply_q->is_iouring_poll_q) {
201062306a36Sopenharmony_ci			_base_process_reply_queue(reply_q);
201162306a36Sopenharmony_ci			continue;
201262306a36Sopenharmony_ci		}
201362306a36Sopenharmony_ci
201462306a36Sopenharmony_ci		synchronize_irq(pci_irq_vector(ioc->pdev, reply_q->msix_index));
201562306a36Sopenharmony_ci		if (reply_q->irq_poll_scheduled) {
201662306a36Sopenharmony_ci			/* Calling irq_poll_disable will wait for any pending
201762306a36Sopenharmony_ci			 * callbacks to have completed.
201862306a36Sopenharmony_ci			 */
201962306a36Sopenharmony_ci			irq_poll_disable(&reply_q->irqpoll);
202062306a36Sopenharmony_ci			irq_poll_enable(&reply_q->irqpoll);
202162306a36Sopenharmony_ci			/* check how the scheduled poll has ended,
202262306a36Sopenharmony_ci			 * clean up only if necessary
202362306a36Sopenharmony_ci			 */
202462306a36Sopenharmony_ci			if (reply_q->irq_poll_scheduled) {
202562306a36Sopenharmony_ci				reply_q->irq_poll_scheduled = false;
202662306a36Sopenharmony_ci				reply_q->irq_line_enable = true;
202762306a36Sopenharmony_ci				enable_irq(reply_q->os_irq);
202862306a36Sopenharmony_ci			}
202962306a36Sopenharmony_ci		}
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci		if (poll)
203262306a36Sopenharmony_ci			_base_process_reply_queue(reply_q);
203362306a36Sopenharmony_ci	}
203462306a36Sopenharmony_ci}
203562306a36Sopenharmony_ci
203662306a36Sopenharmony_ci/**
203762306a36Sopenharmony_ci * mpt3sas_base_release_callback_handler - clear interrupt callback handler
203862306a36Sopenharmony_ci * @cb_idx: callback index
203962306a36Sopenharmony_ci */
204062306a36Sopenharmony_civoid
204162306a36Sopenharmony_cimpt3sas_base_release_callback_handler(u8 cb_idx)
204262306a36Sopenharmony_ci{
204362306a36Sopenharmony_ci	mpt_callbacks[cb_idx] = NULL;
204462306a36Sopenharmony_ci}
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci/**
204762306a36Sopenharmony_ci * mpt3sas_base_register_callback_handler - obtain index for the interrupt callback handler
204862306a36Sopenharmony_ci * @cb_func: callback function
204962306a36Sopenharmony_ci *
205062306a36Sopenharmony_ci * Return: Index of @cb_func.
205162306a36Sopenharmony_ci */
205262306a36Sopenharmony_ciu8
205362306a36Sopenharmony_cimpt3sas_base_register_callback_handler(MPT_CALLBACK cb_func)
205462306a36Sopenharmony_ci{
205562306a36Sopenharmony_ci	u8 cb_idx;
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	for (cb_idx = MPT_MAX_CALLBACKS-1; cb_idx; cb_idx--)
205862306a36Sopenharmony_ci		if (mpt_callbacks[cb_idx] == NULL)
205962306a36Sopenharmony_ci			break;
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci	mpt_callbacks[cb_idx] = cb_func;
206262306a36Sopenharmony_ci	return cb_idx;
206362306a36Sopenharmony_ci}
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci/**
206662306a36Sopenharmony_ci * mpt3sas_base_initialize_callback_handler - initialize the interrupt callback handler
206762306a36Sopenharmony_ci */
206862306a36Sopenharmony_civoid
206962306a36Sopenharmony_cimpt3sas_base_initialize_callback_handler(void)
207062306a36Sopenharmony_ci{
207162306a36Sopenharmony_ci	u8 cb_idx;
207262306a36Sopenharmony_ci
207362306a36Sopenharmony_ci	for (cb_idx = 0; cb_idx < MPT_MAX_CALLBACKS; cb_idx++)
207462306a36Sopenharmony_ci		mpt3sas_base_release_callback_handler(cb_idx);
207562306a36Sopenharmony_ci}
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_ci/**
207962306a36Sopenharmony_ci * _base_build_zero_len_sge - build zero length sg entry
208062306a36Sopenharmony_ci * @ioc: per adapter object
208162306a36Sopenharmony_ci * @paddr: virtual address for SGE
208262306a36Sopenharmony_ci *
208362306a36Sopenharmony_ci * Create a zero length scatter gather entry to insure the IOCs hardware has
208462306a36Sopenharmony_ci * something to use if the target device goes brain dead and tries
208562306a36Sopenharmony_ci * to send data even when none is asked for.
208662306a36Sopenharmony_ci */
208762306a36Sopenharmony_cistatic void
208862306a36Sopenharmony_ci_base_build_zero_len_sge(struct MPT3SAS_ADAPTER *ioc, void *paddr)
208962306a36Sopenharmony_ci{
209062306a36Sopenharmony_ci	u32 flags_length = (u32)((MPI2_SGE_FLAGS_LAST_ELEMENT |
209162306a36Sopenharmony_ci	    MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST |
209262306a36Sopenharmony_ci	    MPI2_SGE_FLAGS_SIMPLE_ELEMENT) <<
209362306a36Sopenharmony_ci	    MPI2_SGE_FLAGS_SHIFT);
209462306a36Sopenharmony_ci	ioc->base_add_sg_single(paddr, flags_length, -1);
209562306a36Sopenharmony_ci}
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci/**
209862306a36Sopenharmony_ci * _base_add_sg_single_32 - Place a simple 32 bit SGE at address pAddr.
209962306a36Sopenharmony_ci * @paddr: virtual address for SGE
210062306a36Sopenharmony_ci * @flags_length: SGE flags and data transfer length
210162306a36Sopenharmony_ci * @dma_addr: Physical address
210262306a36Sopenharmony_ci */
210362306a36Sopenharmony_cistatic void
210462306a36Sopenharmony_ci_base_add_sg_single_32(void *paddr, u32 flags_length, dma_addr_t dma_addr)
210562306a36Sopenharmony_ci{
210662306a36Sopenharmony_ci	Mpi2SGESimple32_t *sgel = paddr;
210762306a36Sopenharmony_ci
210862306a36Sopenharmony_ci	flags_length |= (MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
210962306a36Sopenharmony_ci	    MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT;
211062306a36Sopenharmony_ci	sgel->FlagsLength = cpu_to_le32(flags_length);
211162306a36Sopenharmony_ci	sgel->Address = cpu_to_le32(dma_addr);
211262306a36Sopenharmony_ci}
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci/**
211662306a36Sopenharmony_ci * _base_add_sg_single_64 - Place a simple 64 bit SGE at address pAddr.
211762306a36Sopenharmony_ci * @paddr: virtual address for SGE
211862306a36Sopenharmony_ci * @flags_length: SGE flags and data transfer length
211962306a36Sopenharmony_ci * @dma_addr: Physical address
212062306a36Sopenharmony_ci */
212162306a36Sopenharmony_cistatic void
212262306a36Sopenharmony_ci_base_add_sg_single_64(void *paddr, u32 flags_length, dma_addr_t dma_addr)
212362306a36Sopenharmony_ci{
212462306a36Sopenharmony_ci	Mpi2SGESimple64_t *sgel = paddr;
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	flags_length |= (MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
212762306a36Sopenharmony_ci	    MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT;
212862306a36Sopenharmony_ci	sgel->FlagsLength = cpu_to_le32(flags_length);
212962306a36Sopenharmony_ci	sgel->Address = cpu_to_le64(dma_addr);
213062306a36Sopenharmony_ci}
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_ci/**
213362306a36Sopenharmony_ci * _base_get_chain_buffer_tracker - obtain chain tracker
213462306a36Sopenharmony_ci * @ioc: per adapter object
213562306a36Sopenharmony_ci * @scmd: SCSI commands of the IO request
213662306a36Sopenharmony_ci *
213762306a36Sopenharmony_ci * Return: chain tracker from chain_lookup table using key as
213862306a36Sopenharmony_ci * smid and smid's chain_offset.
213962306a36Sopenharmony_ci */
214062306a36Sopenharmony_cistatic struct chain_tracker *
214162306a36Sopenharmony_ci_base_get_chain_buffer_tracker(struct MPT3SAS_ADAPTER *ioc,
214262306a36Sopenharmony_ci			       struct scsi_cmnd *scmd)
214362306a36Sopenharmony_ci{
214462306a36Sopenharmony_ci	struct chain_tracker *chain_req;
214562306a36Sopenharmony_ci	struct scsiio_tracker *st = scsi_cmd_priv(scmd);
214662306a36Sopenharmony_ci	u16 smid = st->smid;
214762306a36Sopenharmony_ci	u8 chain_offset =
214862306a36Sopenharmony_ci	   atomic_read(&ioc->chain_lookup[smid - 1].chain_offset);
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	if (chain_offset == ioc->chains_needed_per_io)
215162306a36Sopenharmony_ci		return NULL;
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	chain_req = &ioc->chain_lookup[smid - 1].chains_per_smid[chain_offset];
215462306a36Sopenharmony_ci	atomic_inc(&ioc->chain_lookup[smid - 1].chain_offset);
215562306a36Sopenharmony_ci	return chain_req;
215662306a36Sopenharmony_ci}
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci/**
216062306a36Sopenharmony_ci * _base_build_sg - build generic sg
216162306a36Sopenharmony_ci * @ioc: per adapter object
216262306a36Sopenharmony_ci * @psge: virtual address for SGE
216362306a36Sopenharmony_ci * @data_out_dma: physical address for WRITES
216462306a36Sopenharmony_ci * @data_out_sz: data xfer size for WRITES
216562306a36Sopenharmony_ci * @data_in_dma: physical address for READS
216662306a36Sopenharmony_ci * @data_in_sz: data xfer size for READS
216762306a36Sopenharmony_ci */
216862306a36Sopenharmony_cistatic void
216962306a36Sopenharmony_ci_base_build_sg(struct MPT3SAS_ADAPTER *ioc, void *psge,
217062306a36Sopenharmony_ci	dma_addr_t data_out_dma, size_t data_out_sz, dma_addr_t data_in_dma,
217162306a36Sopenharmony_ci	size_t data_in_sz)
217262306a36Sopenharmony_ci{
217362306a36Sopenharmony_ci	u32 sgl_flags;
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci	if (!data_out_sz && !data_in_sz) {
217662306a36Sopenharmony_ci		_base_build_zero_len_sge(ioc, psge);
217762306a36Sopenharmony_ci		return;
217862306a36Sopenharmony_ci	}
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci	if (data_out_sz && data_in_sz) {
218162306a36Sopenharmony_ci		/* WRITE sgel first */
218262306a36Sopenharmony_ci		sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
218362306a36Sopenharmony_ci		    MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
218462306a36Sopenharmony_ci		sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
218562306a36Sopenharmony_ci		ioc->base_add_sg_single(psge, sgl_flags |
218662306a36Sopenharmony_ci		    data_out_sz, data_out_dma);
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci		/* incr sgel */
218962306a36Sopenharmony_ci		psge += ioc->sge_size;
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_ci		/* READ sgel last */
219262306a36Sopenharmony_ci		sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
219362306a36Sopenharmony_ci		    MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
219462306a36Sopenharmony_ci		    MPI2_SGE_FLAGS_END_OF_LIST);
219562306a36Sopenharmony_ci		sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
219662306a36Sopenharmony_ci		ioc->base_add_sg_single(psge, sgl_flags |
219762306a36Sopenharmony_ci		    data_in_sz, data_in_dma);
219862306a36Sopenharmony_ci	} else if (data_out_sz) /* WRITE */ {
219962306a36Sopenharmony_ci		sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
220062306a36Sopenharmony_ci		    MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
220162306a36Sopenharmony_ci		    MPI2_SGE_FLAGS_END_OF_LIST | MPI2_SGE_FLAGS_HOST_TO_IOC);
220262306a36Sopenharmony_ci		sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
220362306a36Sopenharmony_ci		ioc->base_add_sg_single(psge, sgl_flags |
220462306a36Sopenharmony_ci		    data_out_sz, data_out_dma);
220562306a36Sopenharmony_ci	} else if (data_in_sz) /* READ */ {
220662306a36Sopenharmony_ci		sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
220762306a36Sopenharmony_ci		    MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
220862306a36Sopenharmony_ci		    MPI2_SGE_FLAGS_END_OF_LIST);
220962306a36Sopenharmony_ci		sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
221062306a36Sopenharmony_ci		ioc->base_add_sg_single(psge, sgl_flags |
221162306a36Sopenharmony_ci		    data_in_sz, data_in_dma);
221262306a36Sopenharmony_ci	}
221362306a36Sopenharmony_ci}
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci/* IEEE format sgls */
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_ci/**
221862306a36Sopenharmony_ci * _base_build_nvme_prp - This function is called for NVMe end devices to build
221962306a36Sopenharmony_ci *                        a native SGL (NVMe PRP).
222062306a36Sopenharmony_ci * @ioc: per adapter object
222162306a36Sopenharmony_ci * @smid: system request message index for getting asscociated SGL
222262306a36Sopenharmony_ci * @nvme_encap_request: the NVMe request msg frame pointer
222362306a36Sopenharmony_ci * @data_out_dma: physical address for WRITES
222462306a36Sopenharmony_ci * @data_out_sz: data xfer size for WRITES
222562306a36Sopenharmony_ci * @data_in_dma: physical address for READS
222662306a36Sopenharmony_ci * @data_in_sz: data xfer size for READS
222762306a36Sopenharmony_ci *
222862306a36Sopenharmony_ci * The native SGL is built starting in the first PRP
222962306a36Sopenharmony_ci * entry of the NVMe message (PRP1).  If the data buffer is small enough to be
223062306a36Sopenharmony_ci * described entirely using PRP1, then PRP2 is not used.  If needed, PRP2 is
223162306a36Sopenharmony_ci * used to describe a larger data buffer.  If the data buffer is too large to
223262306a36Sopenharmony_ci * describe using the two PRP entriess inside the NVMe message, then PRP1
223362306a36Sopenharmony_ci * describes the first data memory segment, and PRP2 contains a pointer to a PRP
223462306a36Sopenharmony_ci * list located elsewhere in memory to describe the remaining data memory
223562306a36Sopenharmony_ci * segments.  The PRP list will be contiguous.
223662306a36Sopenharmony_ci *
223762306a36Sopenharmony_ci * The native SGL for NVMe devices is a Physical Region Page (PRP).  A PRP
223862306a36Sopenharmony_ci * consists of a list of PRP entries to describe a number of noncontigous
223962306a36Sopenharmony_ci * physical memory segments as a single memory buffer, just as a SGL does.  Note
224062306a36Sopenharmony_ci * however, that this function is only used by the IOCTL call, so the memory
224162306a36Sopenharmony_ci * given will be guaranteed to be contiguous.  There is no need to translate
224262306a36Sopenharmony_ci * non-contiguous SGL into a PRP in this case.  All PRPs will describe
224362306a36Sopenharmony_ci * contiguous space that is one page size each.
224462306a36Sopenharmony_ci *
224562306a36Sopenharmony_ci * Each NVMe message contains two PRP entries.  The first (PRP1) either contains
224662306a36Sopenharmony_ci * a PRP list pointer or a PRP element, depending upon the command.  PRP2
224762306a36Sopenharmony_ci * contains the second PRP element if the memory being described fits within 2
224862306a36Sopenharmony_ci * PRP entries, or a PRP list pointer if the PRP spans more than two entries.
224962306a36Sopenharmony_ci *
225062306a36Sopenharmony_ci * A PRP list pointer contains the address of a PRP list, structured as a linear
225162306a36Sopenharmony_ci * array of PRP entries.  Each PRP entry in this list describes a segment of
225262306a36Sopenharmony_ci * physical memory.
225362306a36Sopenharmony_ci *
225462306a36Sopenharmony_ci * Each 64-bit PRP entry comprises an address and an offset field.  The address
225562306a36Sopenharmony_ci * always points at the beginning of a 4KB physical memory page, and the offset
225662306a36Sopenharmony_ci * describes where within that 4KB page the memory segment begins.  Only the
225762306a36Sopenharmony_ci * first element in a PRP list may contain a non-zero offset, implying that all
225862306a36Sopenharmony_ci * memory segments following the first begin at the start of a 4KB page.
225962306a36Sopenharmony_ci *
226062306a36Sopenharmony_ci * Each PRP element normally describes 4KB of physical memory, with exceptions
226162306a36Sopenharmony_ci * for the first and last elements in the list.  If the memory being described
226262306a36Sopenharmony_ci * by the list begins at a non-zero offset within the first 4KB page, then the
226362306a36Sopenharmony_ci * first PRP element will contain a non-zero offset indicating where the region
226462306a36Sopenharmony_ci * begins within the 4KB page.  The last memory segment may end before the end
226562306a36Sopenharmony_ci * of the 4KB segment, depending upon the overall size of the memory being
226662306a36Sopenharmony_ci * described by the PRP list.
226762306a36Sopenharmony_ci *
226862306a36Sopenharmony_ci * Since PRP entries lack any indication of size, the overall data buffer length
226962306a36Sopenharmony_ci * is used to determine where the end of the data memory buffer is located, and
227062306a36Sopenharmony_ci * how many PRP entries are required to describe it.
227162306a36Sopenharmony_ci */
227262306a36Sopenharmony_cistatic void
227362306a36Sopenharmony_ci_base_build_nvme_prp(struct MPT3SAS_ADAPTER *ioc, u16 smid,
227462306a36Sopenharmony_ci	Mpi26NVMeEncapsulatedRequest_t *nvme_encap_request,
227562306a36Sopenharmony_ci	dma_addr_t data_out_dma, size_t data_out_sz, dma_addr_t data_in_dma,
227662306a36Sopenharmony_ci	size_t data_in_sz)
227762306a36Sopenharmony_ci{
227862306a36Sopenharmony_ci	int		prp_size = NVME_PRP_SIZE;
227962306a36Sopenharmony_ci	__le64		*prp_entry, *prp1_entry, *prp2_entry;
228062306a36Sopenharmony_ci	__le64		*prp_page;
228162306a36Sopenharmony_ci	dma_addr_t	prp_entry_dma, prp_page_dma, dma_addr;
228262306a36Sopenharmony_ci	u32		offset, entry_len;
228362306a36Sopenharmony_ci	u32		page_mask_result, page_mask;
228462306a36Sopenharmony_ci	size_t		length;
228562306a36Sopenharmony_ci	struct mpt3sas_nvme_cmd *nvme_cmd =
228662306a36Sopenharmony_ci		(void *)nvme_encap_request->NVMe_Command;
228762306a36Sopenharmony_ci
228862306a36Sopenharmony_ci	/*
228962306a36Sopenharmony_ci	 * Not all commands require a data transfer. If no data, just return
229062306a36Sopenharmony_ci	 * without constructing any PRP.
229162306a36Sopenharmony_ci	 */
229262306a36Sopenharmony_ci	if (!data_in_sz && !data_out_sz)
229362306a36Sopenharmony_ci		return;
229462306a36Sopenharmony_ci	prp1_entry = &nvme_cmd->prp1;
229562306a36Sopenharmony_ci	prp2_entry = &nvme_cmd->prp2;
229662306a36Sopenharmony_ci	prp_entry = prp1_entry;
229762306a36Sopenharmony_ci	/*
229862306a36Sopenharmony_ci	 * For the PRP entries, use the specially allocated buffer of
229962306a36Sopenharmony_ci	 * contiguous memory.
230062306a36Sopenharmony_ci	 */
230162306a36Sopenharmony_ci	prp_page = (__le64 *)mpt3sas_base_get_pcie_sgl(ioc, smid);
230262306a36Sopenharmony_ci	prp_page_dma = mpt3sas_base_get_pcie_sgl_dma(ioc, smid);
230362306a36Sopenharmony_ci
230462306a36Sopenharmony_ci	/*
230562306a36Sopenharmony_ci	 * Check if we are within 1 entry of a page boundary we don't
230662306a36Sopenharmony_ci	 * want our first entry to be a PRP List entry.
230762306a36Sopenharmony_ci	 */
230862306a36Sopenharmony_ci	page_mask = ioc->page_size - 1;
230962306a36Sopenharmony_ci	page_mask_result = (uintptr_t)((u8 *)prp_page + prp_size) & page_mask;
231062306a36Sopenharmony_ci	if (!page_mask_result) {
231162306a36Sopenharmony_ci		/* Bump up to next page boundary. */
231262306a36Sopenharmony_ci		prp_page = (__le64 *)((u8 *)prp_page + prp_size);
231362306a36Sopenharmony_ci		prp_page_dma = prp_page_dma + prp_size;
231462306a36Sopenharmony_ci	}
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci	/*
231762306a36Sopenharmony_ci	 * Set PRP physical pointer, which initially points to the current PRP
231862306a36Sopenharmony_ci	 * DMA memory page.
231962306a36Sopenharmony_ci	 */
232062306a36Sopenharmony_ci	prp_entry_dma = prp_page_dma;
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci	/* Get physical address and length of the data buffer. */
232362306a36Sopenharmony_ci	if (data_in_sz) {
232462306a36Sopenharmony_ci		dma_addr = data_in_dma;
232562306a36Sopenharmony_ci		length = data_in_sz;
232662306a36Sopenharmony_ci	} else {
232762306a36Sopenharmony_ci		dma_addr = data_out_dma;
232862306a36Sopenharmony_ci		length = data_out_sz;
232962306a36Sopenharmony_ci	}
233062306a36Sopenharmony_ci
233162306a36Sopenharmony_ci	/* Loop while the length is not zero. */
233262306a36Sopenharmony_ci	while (length) {
233362306a36Sopenharmony_ci		/*
233462306a36Sopenharmony_ci		 * Check if we need to put a list pointer here if we are at
233562306a36Sopenharmony_ci		 * page boundary - prp_size (8 bytes).
233662306a36Sopenharmony_ci		 */
233762306a36Sopenharmony_ci		page_mask_result = (prp_entry_dma + prp_size) & page_mask;
233862306a36Sopenharmony_ci		if (!page_mask_result) {
233962306a36Sopenharmony_ci			/*
234062306a36Sopenharmony_ci			 * This is the last entry in a PRP List, so we need to
234162306a36Sopenharmony_ci			 * put a PRP list pointer here.  What this does is:
234262306a36Sopenharmony_ci			 *   - bump the current memory pointer to the next
234362306a36Sopenharmony_ci			 *     address, which will be the next full page.
234462306a36Sopenharmony_ci			 *   - set the PRP Entry to point to that page.  This
234562306a36Sopenharmony_ci			 *     is now the PRP List pointer.
234662306a36Sopenharmony_ci			 *   - bump the PRP Entry pointer the start of the
234762306a36Sopenharmony_ci			 *     next page.  Since all of this PRP memory is
234862306a36Sopenharmony_ci			 *     contiguous, no need to get a new page - it's
234962306a36Sopenharmony_ci			 *     just the next address.
235062306a36Sopenharmony_ci			 */
235162306a36Sopenharmony_ci			prp_entry_dma++;
235262306a36Sopenharmony_ci			*prp_entry = cpu_to_le64(prp_entry_dma);
235362306a36Sopenharmony_ci			prp_entry++;
235462306a36Sopenharmony_ci		}
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci		/* Need to handle if entry will be part of a page. */
235762306a36Sopenharmony_ci		offset = dma_addr & page_mask;
235862306a36Sopenharmony_ci		entry_len = ioc->page_size - offset;
235962306a36Sopenharmony_ci
236062306a36Sopenharmony_ci		if (prp_entry == prp1_entry) {
236162306a36Sopenharmony_ci			/*
236262306a36Sopenharmony_ci			 * Must fill in the first PRP pointer (PRP1) before
236362306a36Sopenharmony_ci			 * moving on.
236462306a36Sopenharmony_ci			 */
236562306a36Sopenharmony_ci			*prp1_entry = cpu_to_le64(dma_addr);
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci			/*
236862306a36Sopenharmony_ci			 * Now point to the second PRP entry within the
236962306a36Sopenharmony_ci			 * command (PRP2).
237062306a36Sopenharmony_ci			 */
237162306a36Sopenharmony_ci			prp_entry = prp2_entry;
237262306a36Sopenharmony_ci		} else if (prp_entry == prp2_entry) {
237362306a36Sopenharmony_ci			/*
237462306a36Sopenharmony_ci			 * Should the PRP2 entry be a PRP List pointer or just
237562306a36Sopenharmony_ci			 * a regular PRP pointer?  If there is more than one
237662306a36Sopenharmony_ci			 * more page of data, must use a PRP List pointer.
237762306a36Sopenharmony_ci			 */
237862306a36Sopenharmony_ci			if (length > ioc->page_size) {
237962306a36Sopenharmony_ci				/*
238062306a36Sopenharmony_ci				 * PRP2 will contain a PRP List pointer because
238162306a36Sopenharmony_ci				 * more PRP's are needed with this command. The
238262306a36Sopenharmony_ci				 * list will start at the beginning of the
238362306a36Sopenharmony_ci				 * contiguous buffer.
238462306a36Sopenharmony_ci				 */
238562306a36Sopenharmony_ci				*prp2_entry = cpu_to_le64(prp_entry_dma);
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_ci				/*
238862306a36Sopenharmony_ci				 * The next PRP Entry will be the start of the
238962306a36Sopenharmony_ci				 * first PRP List.
239062306a36Sopenharmony_ci				 */
239162306a36Sopenharmony_ci				prp_entry = prp_page;
239262306a36Sopenharmony_ci			} else {
239362306a36Sopenharmony_ci				/*
239462306a36Sopenharmony_ci				 * After this, the PRP Entries are complete.
239562306a36Sopenharmony_ci				 * This command uses 2 PRP's and no PRP list.
239662306a36Sopenharmony_ci				 */
239762306a36Sopenharmony_ci				*prp2_entry = cpu_to_le64(dma_addr);
239862306a36Sopenharmony_ci			}
239962306a36Sopenharmony_ci		} else {
240062306a36Sopenharmony_ci			/*
240162306a36Sopenharmony_ci			 * Put entry in list and bump the addresses.
240262306a36Sopenharmony_ci			 *
240362306a36Sopenharmony_ci			 * After PRP1 and PRP2 are filled in, this will fill in
240462306a36Sopenharmony_ci			 * all remaining PRP entries in a PRP List, one per
240562306a36Sopenharmony_ci			 * each time through the loop.
240662306a36Sopenharmony_ci			 */
240762306a36Sopenharmony_ci			*prp_entry = cpu_to_le64(dma_addr);
240862306a36Sopenharmony_ci			prp_entry++;
240962306a36Sopenharmony_ci			prp_entry_dma++;
241062306a36Sopenharmony_ci		}
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_ci		/*
241362306a36Sopenharmony_ci		 * Bump the phys address of the command's data buffer by the
241462306a36Sopenharmony_ci		 * entry_len.
241562306a36Sopenharmony_ci		 */
241662306a36Sopenharmony_ci		dma_addr += entry_len;
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_ci		/* Decrement length accounting for last partial page. */
241962306a36Sopenharmony_ci		if (entry_len > length)
242062306a36Sopenharmony_ci			length = 0;
242162306a36Sopenharmony_ci		else
242262306a36Sopenharmony_ci			length -= entry_len;
242362306a36Sopenharmony_ci	}
242462306a36Sopenharmony_ci}
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci/**
242762306a36Sopenharmony_ci * base_make_prp_nvme - Prepare PRPs (Physical Region Page) -
242862306a36Sopenharmony_ci *			SGLs specific to NVMe drives only
242962306a36Sopenharmony_ci *
243062306a36Sopenharmony_ci * @ioc:		per adapter object
243162306a36Sopenharmony_ci * @scmd:		SCSI command from the mid-layer
243262306a36Sopenharmony_ci * @mpi_request:	mpi request
243362306a36Sopenharmony_ci * @smid:		msg Index
243462306a36Sopenharmony_ci * @sge_count:		scatter gather element count.
243562306a36Sopenharmony_ci *
243662306a36Sopenharmony_ci * Return:		true: PRPs are built
243762306a36Sopenharmony_ci *			false: IEEE SGLs needs to be built
243862306a36Sopenharmony_ci */
243962306a36Sopenharmony_cistatic void
244062306a36Sopenharmony_cibase_make_prp_nvme(struct MPT3SAS_ADAPTER *ioc,
244162306a36Sopenharmony_ci		struct scsi_cmnd *scmd,
244262306a36Sopenharmony_ci		Mpi25SCSIIORequest_t *mpi_request,
244362306a36Sopenharmony_ci		u16 smid, int sge_count)
244462306a36Sopenharmony_ci{
244562306a36Sopenharmony_ci	int sge_len, num_prp_in_chain = 0;
244662306a36Sopenharmony_ci	Mpi25IeeeSgeChain64_t *main_chain_element, *ptr_first_sgl;
244762306a36Sopenharmony_ci	__le64 *curr_buff;
244862306a36Sopenharmony_ci	dma_addr_t msg_dma, sge_addr, offset;
244962306a36Sopenharmony_ci	u32 page_mask, page_mask_result;
245062306a36Sopenharmony_ci	struct scatterlist *sg_scmd;
245162306a36Sopenharmony_ci	u32 first_prp_len;
245262306a36Sopenharmony_ci	int data_len = scsi_bufflen(scmd);
245362306a36Sopenharmony_ci	u32 nvme_pg_size;
245462306a36Sopenharmony_ci
245562306a36Sopenharmony_ci	nvme_pg_size = max_t(u32, ioc->page_size, NVME_PRP_PAGE_SIZE);
245662306a36Sopenharmony_ci	/*
245762306a36Sopenharmony_ci	 * Nvme has a very convoluted prp format.  One prp is required
245862306a36Sopenharmony_ci	 * for each page or partial page. Driver need to split up OS sg_list
245962306a36Sopenharmony_ci	 * entries if it is longer than one page or cross a page
246062306a36Sopenharmony_ci	 * boundary.  Driver also have to insert a PRP list pointer entry as
246162306a36Sopenharmony_ci	 * the last entry in each physical page of the PRP list.
246262306a36Sopenharmony_ci	 *
246362306a36Sopenharmony_ci	 * NOTE: The first PRP "entry" is actually placed in the first
246462306a36Sopenharmony_ci	 * SGL entry in the main message as IEEE 64 format.  The 2nd
246562306a36Sopenharmony_ci	 * entry in the main message is the chain element, and the rest
246662306a36Sopenharmony_ci	 * of the PRP entries are built in the contiguous pcie buffer.
246762306a36Sopenharmony_ci	 */
246862306a36Sopenharmony_ci	page_mask = nvme_pg_size - 1;
246962306a36Sopenharmony_ci
247062306a36Sopenharmony_ci	/*
247162306a36Sopenharmony_ci	 * Native SGL is needed.
247262306a36Sopenharmony_ci	 * Put a chain element in main message frame that points to the first
247362306a36Sopenharmony_ci	 * chain buffer.
247462306a36Sopenharmony_ci	 *
247562306a36Sopenharmony_ci	 * NOTE:  The ChainOffset field must be 0 when using a chain pointer to
247662306a36Sopenharmony_ci	 *        a native SGL.
247762306a36Sopenharmony_ci	 */
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci	/* Set main message chain element pointer */
248062306a36Sopenharmony_ci	main_chain_element = (pMpi25IeeeSgeChain64_t)&mpi_request->SGL;
248162306a36Sopenharmony_ci	/*
248262306a36Sopenharmony_ci	 * For NVMe the chain element needs to be the 2nd SG entry in the main
248362306a36Sopenharmony_ci	 * message.
248462306a36Sopenharmony_ci	 */
248562306a36Sopenharmony_ci	main_chain_element = (Mpi25IeeeSgeChain64_t *)
248662306a36Sopenharmony_ci		((u8 *)main_chain_element + sizeof(MPI25_IEEE_SGE_CHAIN64));
248762306a36Sopenharmony_ci
248862306a36Sopenharmony_ci	/*
248962306a36Sopenharmony_ci	 * For the PRP entries, use the specially allocated buffer of
249062306a36Sopenharmony_ci	 * contiguous memory.  Normal chain buffers can't be used
249162306a36Sopenharmony_ci	 * because each chain buffer would need to be the size of an OS
249262306a36Sopenharmony_ci	 * page (4k).
249362306a36Sopenharmony_ci	 */
249462306a36Sopenharmony_ci	curr_buff = mpt3sas_base_get_pcie_sgl(ioc, smid);
249562306a36Sopenharmony_ci	msg_dma = mpt3sas_base_get_pcie_sgl_dma(ioc, smid);
249662306a36Sopenharmony_ci
249762306a36Sopenharmony_ci	main_chain_element->Address = cpu_to_le64(msg_dma);
249862306a36Sopenharmony_ci	main_chain_element->NextChainOffset = 0;
249962306a36Sopenharmony_ci	main_chain_element->Flags = MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT |
250062306a36Sopenharmony_ci			MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR |
250162306a36Sopenharmony_ci			MPI26_IEEE_SGE_FLAGS_NSF_NVME_PRP;
250262306a36Sopenharmony_ci
250362306a36Sopenharmony_ci	/* Build first prp, sge need not to be page aligned*/
250462306a36Sopenharmony_ci	ptr_first_sgl = (pMpi25IeeeSgeChain64_t)&mpi_request->SGL;
250562306a36Sopenharmony_ci	sg_scmd = scsi_sglist(scmd);
250662306a36Sopenharmony_ci	sge_addr = sg_dma_address(sg_scmd);
250762306a36Sopenharmony_ci	sge_len = sg_dma_len(sg_scmd);
250862306a36Sopenharmony_ci
250962306a36Sopenharmony_ci	offset = sge_addr & page_mask;
251062306a36Sopenharmony_ci	first_prp_len = nvme_pg_size - offset;
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_ci	ptr_first_sgl->Address = cpu_to_le64(sge_addr);
251362306a36Sopenharmony_ci	ptr_first_sgl->Length = cpu_to_le32(first_prp_len);
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_ci	data_len -= first_prp_len;
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_ci	if (sge_len > first_prp_len) {
251862306a36Sopenharmony_ci		sge_addr += first_prp_len;
251962306a36Sopenharmony_ci		sge_len -= first_prp_len;
252062306a36Sopenharmony_ci	} else if (data_len && (sge_len == first_prp_len)) {
252162306a36Sopenharmony_ci		sg_scmd = sg_next(sg_scmd);
252262306a36Sopenharmony_ci		sge_addr = sg_dma_address(sg_scmd);
252362306a36Sopenharmony_ci		sge_len = sg_dma_len(sg_scmd);
252462306a36Sopenharmony_ci	}
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_ci	for (;;) {
252762306a36Sopenharmony_ci		offset = sge_addr & page_mask;
252862306a36Sopenharmony_ci
252962306a36Sopenharmony_ci		/* Put PRP pointer due to page boundary*/
253062306a36Sopenharmony_ci		page_mask_result = (uintptr_t)(curr_buff + 1) & page_mask;
253162306a36Sopenharmony_ci		if (unlikely(!page_mask_result)) {
253262306a36Sopenharmony_ci			scmd_printk(KERN_NOTICE,
253362306a36Sopenharmony_ci				scmd, "page boundary curr_buff: 0x%p\n",
253462306a36Sopenharmony_ci				curr_buff);
253562306a36Sopenharmony_ci			msg_dma += 8;
253662306a36Sopenharmony_ci			*curr_buff = cpu_to_le64(msg_dma);
253762306a36Sopenharmony_ci			curr_buff++;
253862306a36Sopenharmony_ci			num_prp_in_chain++;
253962306a36Sopenharmony_ci		}
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_ci		*curr_buff = cpu_to_le64(sge_addr);
254262306a36Sopenharmony_ci		curr_buff++;
254362306a36Sopenharmony_ci		msg_dma += 8;
254462306a36Sopenharmony_ci		num_prp_in_chain++;
254562306a36Sopenharmony_ci
254662306a36Sopenharmony_ci		sge_addr += nvme_pg_size;
254762306a36Sopenharmony_ci		sge_len -= nvme_pg_size;
254862306a36Sopenharmony_ci		data_len -= nvme_pg_size;
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_ci		if (data_len <= 0)
255162306a36Sopenharmony_ci			break;
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci		if (sge_len > 0)
255462306a36Sopenharmony_ci			continue;
255562306a36Sopenharmony_ci
255662306a36Sopenharmony_ci		sg_scmd = sg_next(sg_scmd);
255762306a36Sopenharmony_ci		sge_addr = sg_dma_address(sg_scmd);
255862306a36Sopenharmony_ci		sge_len = sg_dma_len(sg_scmd);
255962306a36Sopenharmony_ci	}
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci	main_chain_element->Length =
256262306a36Sopenharmony_ci		cpu_to_le32(num_prp_in_chain * sizeof(u64));
256362306a36Sopenharmony_ci	return;
256462306a36Sopenharmony_ci}
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_cistatic bool
256762306a36Sopenharmony_cibase_is_prp_possible(struct MPT3SAS_ADAPTER *ioc,
256862306a36Sopenharmony_ci	struct _pcie_device *pcie_device, struct scsi_cmnd *scmd, int sge_count)
256962306a36Sopenharmony_ci{
257062306a36Sopenharmony_ci	u32 data_length = 0;
257162306a36Sopenharmony_ci	bool build_prp = true;
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci	data_length = scsi_bufflen(scmd);
257462306a36Sopenharmony_ci	if (pcie_device &&
257562306a36Sopenharmony_ci	    (mpt3sas_scsih_is_pcie_scsi_device(pcie_device->device_info))) {
257662306a36Sopenharmony_ci		build_prp = false;
257762306a36Sopenharmony_ci		return build_prp;
257862306a36Sopenharmony_ci	}
257962306a36Sopenharmony_ci
258062306a36Sopenharmony_ci	/* If Datalenth is <= 16K and number of SGE’s entries are <= 2
258162306a36Sopenharmony_ci	 * we built IEEE SGL
258262306a36Sopenharmony_ci	 */
258362306a36Sopenharmony_ci	if ((data_length <= NVME_PRP_PAGE_SIZE*4) && (sge_count <= 2))
258462306a36Sopenharmony_ci		build_prp = false;
258562306a36Sopenharmony_ci
258662306a36Sopenharmony_ci	return build_prp;
258762306a36Sopenharmony_ci}
258862306a36Sopenharmony_ci
258962306a36Sopenharmony_ci/**
259062306a36Sopenharmony_ci * _base_check_pcie_native_sgl - This function is called for PCIe end devices to
259162306a36Sopenharmony_ci * determine if the driver needs to build a native SGL.  If so, that native
259262306a36Sopenharmony_ci * SGL is built in the special contiguous buffers allocated especially for
259362306a36Sopenharmony_ci * PCIe SGL creation.  If the driver will not build a native SGL, return
259462306a36Sopenharmony_ci * TRUE and a normal IEEE SGL will be built.  Currently this routine
259562306a36Sopenharmony_ci * supports NVMe.
259662306a36Sopenharmony_ci * @ioc: per adapter object
259762306a36Sopenharmony_ci * @mpi_request: mf request pointer
259862306a36Sopenharmony_ci * @smid: system request message index
259962306a36Sopenharmony_ci * @scmd: scsi command
260062306a36Sopenharmony_ci * @pcie_device: points to the PCIe device's info
260162306a36Sopenharmony_ci *
260262306a36Sopenharmony_ci * Return: 0 if native SGL was built, 1 if no SGL was built
260362306a36Sopenharmony_ci */
260462306a36Sopenharmony_cistatic int
260562306a36Sopenharmony_ci_base_check_pcie_native_sgl(struct MPT3SAS_ADAPTER *ioc,
260662306a36Sopenharmony_ci	Mpi25SCSIIORequest_t *mpi_request, u16 smid, struct scsi_cmnd *scmd,
260762306a36Sopenharmony_ci	struct _pcie_device *pcie_device)
260862306a36Sopenharmony_ci{
260962306a36Sopenharmony_ci	int sges_left;
261062306a36Sopenharmony_ci
261162306a36Sopenharmony_ci	/* Get the SG list pointer and info. */
261262306a36Sopenharmony_ci	sges_left = scsi_dma_map(scmd);
261362306a36Sopenharmony_ci	if (sges_left < 0)
261462306a36Sopenharmony_ci		return 1;
261562306a36Sopenharmony_ci
261662306a36Sopenharmony_ci	/* Check if we need to build a native SG list. */
261762306a36Sopenharmony_ci	if (!base_is_prp_possible(ioc, pcie_device,
261862306a36Sopenharmony_ci				scmd, sges_left)) {
261962306a36Sopenharmony_ci		/* We built a native SG list, just return. */
262062306a36Sopenharmony_ci		goto out;
262162306a36Sopenharmony_ci	}
262262306a36Sopenharmony_ci
262362306a36Sopenharmony_ci	/*
262462306a36Sopenharmony_ci	 * Build native NVMe PRP.
262562306a36Sopenharmony_ci	 */
262662306a36Sopenharmony_ci	base_make_prp_nvme(ioc, scmd, mpi_request,
262762306a36Sopenharmony_ci			smid, sges_left);
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci	return 0;
263062306a36Sopenharmony_ciout:
263162306a36Sopenharmony_ci	scsi_dma_unmap(scmd);
263262306a36Sopenharmony_ci	return 1;
263362306a36Sopenharmony_ci}
263462306a36Sopenharmony_ci
263562306a36Sopenharmony_ci/**
263662306a36Sopenharmony_ci * _base_add_sg_single_ieee - add sg element for IEEE format
263762306a36Sopenharmony_ci * @paddr: virtual address for SGE
263862306a36Sopenharmony_ci * @flags: SGE flags
263962306a36Sopenharmony_ci * @chain_offset: number of 128 byte elements from start of segment
264062306a36Sopenharmony_ci * @length: data transfer length
264162306a36Sopenharmony_ci * @dma_addr: Physical address
264262306a36Sopenharmony_ci */
264362306a36Sopenharmony_cistatic void
264462306a36Sopenharmony_ci_base_add_sg_single_ieee(void *paddr, u8 flags, u8 chain_offset, u32 length,
264562306a36Sopenharmony_ci	dma_addr_t dma_addr)
264662306a36Sopenharmony_ci{
264762306a36Sopenharmony_ci	Mpi25IeeeSgeChain64_t *sgel = paddr;
264862306a36Sopenharmony_ci
264962306a36Sopenharmony_ci	sgel->Flags = flags;
265062306a36Sopenharmony_ci	sgel->NextChainOffset = chain_offset;
265162306a36Sopenharmony_ci	sgel->Length = cpu_to_le32(length);
265262306a36Sopenharmony_ci	sgel->Address = cpu_to_le64(dma_addr);
265362306a36Sopenharmony_ci}
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_ci/**
265662306a36Sopenharmony_ci * _base_build_zero_len_sge_ieee - build zero length sg entry for IEEE format
265762306a36Sopenharmony_ci * @ioc: per adapter object
265862306a36Sopenharmony_ci * @paddr: virtual address for SGE
265962306a36Sopenharmony_ci *
266062306a36Sopenharmony_ci * Create a zero length scatter gather entry to insure the IOCs hardware has
266162306a36Sopenharmony_ci * something to use if the target device goes brain dead and tries
266262306a36Sopenharmony_ci * to send data even when none is asked for.
266362306a36Sopenharmony_ci */
266462306a36Sopenharmony_cistatic void
266562306a36Sopenharmony_ci_base_build_zero_len_sge_ieee(struct MPT3SAS_ADAPTER *ioc, void *paddr)
266662306a36Sopenharmony_ci{
266762306a36Sopenharmony_ci	u8 sgl_flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
266862306a36Sopenharmony_ci		MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR |
266962306a36Sopenharmony_ci		MPI25_IEEE_SGE_FLAGS_END_OF_LIST);
267062306a36Sopenharmony_ci
267162306a36Sopenharmony_ci	_base_add_sg_single_ieee(paddr, sgl_flags, 0, 0, -1);
267262306a36Sopenharmony_ci}
267362306a36Sopenharmony_ci
267462306a36Sopenharmony_ci/**
267562306a36Sopenharmony_ci * _base_build_sg_scmd - main sg creation routine
267662306a36Sopenharmony_ci *		pcie_device is unused here!
267762306a36Sopenharmony_ci * @ioc: per adapter object
267862306a36Sopenharmony_ci * @scmd: scsi command
267962306a36Sopenharmony_ci * @smid: system request message index
268062306a36Sopenharmony_ci * @unused: unused pcie_device pointer
268162306a36Sopenharmony_ci * Context: none.
268262306a36Sopenharmony_ci *
268362306a36Sopenharmony_ci * The main routine that builds scatter gather table from a given
268462306a36Sopenharmony_ci * scsi request sent via the .queuecommand main handler.
268562306a36Sopenharmony_ci *
268662306a36Sopenharmony_ci * Return: 0 success, anything else error
268762306a36Sopenharmony_ci */
268862306a36Sopenharmony_cistatic int
268962306a36Sopenharmony_ci_base_build_sg_scmd(struct MPT3SAS_ADAPTER *ioc,
269062306a36Sopenharmony_ci	struct scsi_cmnd *scmd, u16 smid, struct _pcie_device *unused)
269162306a36Sopenharmony_ci{
269262306a36Sopenharmony_ci	Mpi2SCSIIORequest_t *mpi_request;
269362306a36Sopenharmony_ci	dma_addr_t chain_dma;
269462306a36Sopenharmony_ci	struct scatterlist *sg_scmd;
269562306a36Sopenharmony_ci	void *sg_local, *chain;
269662306a36Sopenharmony_ci	u32 chain_offset;
269762306a36Sopenharmony_ci	u32 chain_length;
269862306a36Sopenharmony_ci	u32 chain_flags;
269962306a36Sopenharmony_ci	int sges_left;
270062306a36Sopenharmony_ci	u32 sges_in_segment;
270162306a36Sopenharmony_ci	u32 sgl_flags;
270262306a36Sopenharmony_ci	u32 sgl_flags_last_element;
270362306a36Sopenharmony_ci	u32 sgl_flags_end_buffer;
270462306a36Sopenharmony_ci	struct chain_tracker *chain_req;
270562306a36Sopenharmony_ci
270662306a36Sopenharmony_ci	mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
270762306a36Sopenharmony_ci
270862306a36Sopenharmony_ci	/* init scatter gather flags */
270962306a36Sopenharmony_ci	sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT;
271062306a36Sopenharmony_ci	if (scmd->sc_data_direction == DMA_TO_DEVICE)
271162306a36Sopenharmony_ci		sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC;
271262306a36Sopenharmony_ci	sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT)
271362306a36Sopenharmony_ci	    << MPI2_SGE_FLAGS_SHIFT;
271462306a36Sopenharmony_ci	sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT |
271562306a36Sopenharmony_ci	    MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST)
271662306a36Sopenharmony_ci	    << MPI2_SGE_FLAGS_SHIFT;
271762306a36Sopenharmony_ci	sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
271862306a36Sopenharmony_ci
271962306a36Sopenharmony_ci	sg_scmd = scsi_sglist(scmd);
272062306a36Sopenharmony_ci	sges_left = scsi_dma_map(scmd);
272162306a36Sopenharmony_ci	if (sges_left < 0)
272262306a36Sopenharmony_ci		return -ENOMEM;
272362306a36Sopenharmony_ci
272462306a36Sopenharmony_ci	sg_local = &mpi_request->SGL;
272562306a36Sopenharmony_ci	sges_in_segment = ioc->max_sges_in_main_message;
272662306a36Sopenharmony_ci	if (sges_left <= sges_in_segment)
272762306a36Sopenharmony_ci		goto fill_in_last_segment;
272862306a36Sopenharmony_ci
272962306a36Sopenharmony_ci	mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) +
273062306a36Sopenharmony_ci	    (sges_in_segment * ioc->sge_size))/4;
273162306a36Sopenharmony_ci
273262306a36Sopenharmony_ci	/* fill in main message segment when there is a chain following */
273362306a36Sopenharmony_ci	while (sges_in_segment) {
273462306a36Sopenharmony_ci		if (sges_in_segment == 1)
273562306a36Sopenharmony_ci			ioc->base_add_sg_single(sg_local,
273662306a36Sopenharmony_ci			    sgl_flags_last_element | sg_dma_len(sg_scmd),
273762306a36Sopenharmony_ci			    sg_dma_address(sg_scmd));
273862306a36Sopenharmony_ci		else
273962306a36Sopenharmony_ci			ioc->base_add_sg_single(sg_local, sgl_flags |
274062306a36Sopenharmony_ci			    sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
274162306a36Sopenharmony_ci		sg_scmd = sg_next(sg_scmd);
274262306a36Sopenharmony_ci		sg_local += ioc->sge_size;
274362306a36Sopenharmony_ci		sges_left--;
274462306a36Sopenharmony_ci		sges_in_segment--;
274562306a36Sopenharmony_ci	}
274662306a36Sopenharmony_ci
274762306a36Sopenharmony_ci	/* initializing the chain flags and pointers */
274862306a36Sopenharmony_ci	chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT;
274962306a36Sopenharmony_ci	chain_req = _base_get_chain_buffer_tracker(ioc, scmd);
275062306a36Sopenharmony_ci	if (!chain_req)
275162306a36Sopenharmony_ci		return -1;
275262306a36Sopenharmony_ci	chain = chain_req->chain_buffer;
275362306a36Sopenharmony_ci	chain_dma = chain_req->chain_buffer_dma;
275462306a36Sopenharmony_ci	do {
275562306a36Sopenharmony_ci		sges_in_segment = (sges_left <=
275662306a36Sopenharmony_ci		    ioc->max_sges_in_chain_message) ? sges_left :
275762306a36Sopenharmony_ci		    ioc->max_sges_in_chain_message;
275862306a36Sopenharmony_ci		chain_offset = (sges_left == sges_in_segment) ?
275962306a36Sopenharmony_ci		    0 : (sges_in_segment * ioc->sge_size)/4;
276062306a36Sopenharmony_ci		chain_length = sges_in_segment * ioc->sge_size;
276162306a36Sopenharmony_ci		if (chain_offset) {
276262306a36Sopenharmony_ci			chain_offset = chain_offset <<
276362306a36Sopenharmony_ci			    MPI2_SGE_CHAIN_OFFSET_SHIFT;
276462306a36Sopenharmony_ci			chain_length += ioc->sge_size;
276562306a36Sopenharmony_ci		}
276662306a36Sopenharmony_ci		ioc->base_add_sg_single(sg_local, chain_flags | chain_offset |
276762306a36Sopenharmony_ci		    chain_length, chain_dma);
276862306a36Sopenharmony_ci		sg_local = chain;
276962306a36Sopenharmony_ci		if (!chain_offset)
277062306a36Sopenharmony_ci			goto fill_in_last_segment;
277162306a36Sopenharmony_ci
277262306a36Sopenharmony_ci		/* fill in chain segments */
277362306a36Sopenharmony_ci		while (sges_in_segment) {
277462306a36Sopenharmony_ci			if (sges_in_segment == 1)
277562306a36Sopenharmony_ci				ioc->base_add_sg_single(sg_local,
277662306a36Sopenharmony_ci				    sgl_flags_last_element |
277762306a36Sopenharmony_ci				    sg_dma_len(sg_scmd),
277862306a36Sopenharmony_ci				    sg_dma_address(sg_scmd));
277962306a36Sopenharmony_ci			else
278062306a36Sopenharmony_ci				ioc->base_add_sg_single(sg_local, sgl_flags |
278162306a36Sopenharmony_ci				    sg_dma_len(sg_scmd),
278262306a36Sopenharmony_ci				    sg_dma_address(sg_scmd));
278362306a36Sopenharmony_ci			sg_scmd = sg_next(sg_scmd);
278462306a36Sopenharmony_ci			sg_local += ioc->sge_size;
278562306a36Sopenharmony_ci			sges_left--;
278662306a36Sopenharmony_ci			sges_in_segment--;
278762306a36Sopenharmony_ci		}
278862306a36Sopenharmony_ci
278962306a36Sopenharmony_ci		chain_req = _base_get_chain_buffer_tracker(ioc, scmd);
279062306a36Sopenharmony_ci		if (!chain_req)
279162306a36Sopenharmony_ci			return -1;
279262306a36Sopenharmony_ci		chain = chain_req->chain_buffer;
279362306a36Sopenharmony_ci		chain_dma = chain_req->chain_buffer_dma;
279462306a36Sopenharmony_ci	} while (1);
279562306a36Sopenharmony_ci
279662306a36Sopenharmony_ci
279762306a36Sopenharmony_ci fill_in_last_segment:
279862306a36Sopenharmony_ci
279962306a36Sopenharmony_ci	/* fill the last segment */
280062306a36Sopenharmony_ci	while (sges_left) {
280162306a36Sopenharmony_ci		if (sges_left == 1)
280262306a36Sopenharmony_ci			ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer |
280362306a36Sopenharmony_ci			    sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
280462306a36Sopenharmony_ci		else
280562306a36Sopenharmony_ci			ioc->base_add_sg_single(sg_local, sgl_flags |
280662306a36Sopenharmony_ci			    sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
280762306a36Sopenharmony_ci		sg_scmd = sg_next(sg_scmd);
280862306a36Sopenharmony_ci		sg_local += ioc->sge_size;
280962306a36Sopenharmony_ci		sges_left--;
281062306a36Sopenharmony_ci	}
281162306a36Sopenharmony_ci
281262306a36Sopenharmony_ci	return 0;
281362306a36Sopenharmony_ci}
281462306a36Sopenharmony_ci
281562306a36Sopenharmony_ci/**
281662306a36Sopenharmony_ci * _base_build_sg_scmd_ieee - main sg creation routine for IEEE format
281762306a36Sopenharmony_ci * @ioc: per adapter object
281862306a36Sopenharmony_ci * @scmd: scsi command
281962306a36Sopenharmony_ci * @smid: system request message index
282062306a36Sopenharmony_ci * @pcie_device: Pointer to pcie_device. If set, the pcie native sgl will be
282162306a36Sopenharmony_ci * constructed on need.
282262306a36Sopenharmony_ci * Context: none.
282362306a36Sopenharmony_ci *
282462306a36Sopenharmony_ci * The main routine that builds scatter gather table from a given
282562306a36Sopenharmony_ci * scsi request sent via the .queuecommand main handler.
282662306a36Sopenharmony_ci *
282762306a36Sopenharmony_ci * Return: 0 success, anything else error
282862306a36Sopenharmony_ci */
282962306a36Sopenharmony_cistatic int
283062306a36Sopenharmony_ci_base_build_sg_scmd_ieee(struct MPT3SAS_ADAPTER *ioc,
283162306a36Sopenharmony_ci	struct scsi_cmnd *scmd, u16 smid, struct _pcie_device *pcie_device)
283262306a36Sopenharmony_ci{
283362306a36Sopenharmony_ci	Mpi25SCSIIORequest_t *mpi_request;
283462306a36Sopenharmony_ci	dma_addr_t chain_dma;
283562306a36Sopenharmony_ci	struct scatterlist *sg_scmd;
283662306a36Sopenharmony_ci	void *sg_local, *chain;
283762306a36Sopenharmony_ci	u32 chain_offset;
283862306a36Sopenharmony_ci	u32 chain_length;
283962306a36Sopenharmony_ci	int sges_left;
284062306a36Sopenharmony_ci	u32 sges_in_segment;
284162306a36Sopenharmony_ci	u8 simple_sgl_flags;
284262306a36Sopenharmony_ci	u8 simple_sgl_flags_last;
284362306a36Sopenharmony_ci	u8 chain_sgl_flags;
284462306a36Sopenharmony_ci	struct chain_tracker *chain_req;
284562306a36Sopenharmony_ci
284662306a36Sopenharmony_ci	mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
284762306a36Sopenharmony_ci
284862306a36Sopenharmony_ci	/* init scatter gather flags */
284962306a36Sopenharmony_ci	simple_sgl_flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
285062306a36Sopenharmony_ci	    MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR;
285162306a36Sopenharmony_ci	simple_sgl_flags_last = simple_sgl_flags |
285262306a36Sopenharmony_ci	    MPI25_IEEE_SGE_FLAGS_END_OF_LIST;
285362306a36Sopenharmony_ci	chain_sgl_flags = MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT |
285462306a36Sopenharmony_ci	    MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR;
285562306a36Sopenharmony_ci
285662306a36Sopenharmony_ci	/* Check if we need to build a native SG list. */
285762306a36Sopenharmony_ci	if ((pcie_device) && (_base_check_pcie_native_sgl(ioc, mpi_request,
285862306a36Sopenharmony_ci			smid, scmd, pcie_device) == 0)) {
285962306a36Sopenharmony_ci		/* We built a native SG list, just return. */
286062306a36Sopenharmony_ci		return 0;
286162306a36Sopenharmony_ci	}
286262306a36Sopenharmony_ci
286362306a36Sopenharmony_ci	sg_scmd = scsi_sglist(scmd);
286462306a36Sopenharmony_ci	sges_left = scsi_dma_map(scmd);
286562306a36Sopenharmony_ci	if (sges_left < 0)
286662306a36Sopenharmony_ci		return -ENOMEM;
286762306a36Sopenharmony_ci
286862306a36Sopenharmony_ci	sg_local = &mpi_request->SGL;
286962306a36Sopenharmony_ci	sges_in_segment = (ioc->request_sz -
287062306a36Sopenharmony_ci		   offsetof(Mpi25SCSIIORequest_t, SGL))/ioc->sge_size_ieee;
287162306a36Sopenharmony_ci	if (sges_left <= sges_in_segment)
287262306a36Sopenharmony_ci		goto fill_in_last_segment;
287362306a36Sopenharmony_ci
287462306a36Sopenharmony_ci	mpi_request->ChainOffset = (sges_in_segment - 1 /* chain element */) +
287562306a36Sopenharmony_ci	    (offsetof(Mpi25SCSIIORequest_t, SGL)/ioc->sge_size_ieee);
287662306a36Sopenharmony_ci
287762306a36Sopenharmony_ci	/* fill in main message segment when there is a chain following */
287862306a36Sopenharmony_ci	while (sges_in_segment > 1) {
287962306a36Sopenharmony_ci		_base_add_sg_single_ieee(sg_local, simple_sgl_flags, 0,
288062306a36Sopenharmony_ci		    sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
288162306a36Sopenharmony_ci		sg_scmd = sg_next(sg_scmd);
288262306a36Sopenharmony_ci		sg_local += ioc->sge_size_ieee;
288362306a36Sopenharmony_ci		sges_left--;
288462306a36Sopenharmony_ci		sges_in_segment--;
288562306a36Sopenharmony_ci	}
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_ci	/* initializing the pointers */
288862306a36Sopenharmony_ci	chain_req = _base_get_chain_buffer_tracker(ioc, scmd);
288962306a36Sopenharmony_ci	if (!chain_req)
289062306a36Sopenharmony_ci		return -1;
289162306a36Sopenharmony_ci	chain = chain_req->chain_buffer;
289262306a36Sopenharmony_ci	chain_dma = chain_req->chain_buffer_dma;
289362306a36Sopenharmony_ci	do {
289462306a36Sopenharmony_ci		sges_in_segment = (sges_left <=
289562306a36Sopenharmony_ci		    ioc->max_sges_in_chain_message) ? sges_left :
289662306a36Sopenharmony_ci		    ioc->max_sges_in_chain_message;
289762306a36Sopenharmony_ci		chain_offset = (sges_left == sges_in_segment) ?
289862306a36Sopenharmony_ci		    0 : sges_in_segment;
289962306a36Sopenharmony_ci		chain_length = sges_in_segment * ioc->sge_size_ieee;
290062306a36Sopenharmony_ci		if (chain_offset)
290162306a36Sopenharmony_ci			chain_length += ioc->sge_size_ieee;
290262306a36Sopenharmony_ci		_base_add_sg_single_ieee(sg_local, chain_sgl_flags,
290362306a36Sopenharmony_ci		    chain_offset, chain_length, chain_dma);
290462306a36Sopenharmony_ci
290562306a36Sopenharmony_ci		sg_local = chain;
290662306a36Sopenharmony_ci		if (!chain_offset)
290762306a36Sopenharmony_ci			goto fill_in_last_segment;
290862306a36Sopenharmony_ci
290962306a36Sopenharmony_ci		/* fill in chain segments */
291062306a36Sopenharmony_ci		while (sges_in_segment) {
291162306a36Sopenharmony_ci			_base_add_sg_single_ieee(sg_local, simple_sgl_flags, 0,
291262306a36Sopenharmony_ci			    sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
291362306a36Sopenharmony_ci			sg_scmd = sg_next(sg_scmd);
291462306a36Sopenharmony_ci			sg_local += ioc->sge_size_ieee;
291562306a36Sopenharmony_ci			sges_left--;
291662306a36Sopenharmony_ci			sges_in_segment--;
291762306a36Sopenharmony_ci		}
291862306a36Sopenharmony_ci
291962306a36Sopenharmony_ci		chain_req = _base_get_chain_buffer_tracker(ioc, scmd);
292062306a36Sopenharmony_ci		if (!chain_req)
292162306a36Sopenharmony_ci			return -1;
292262306a36Sopenharmony_ci		chain = chain_req->chain_buffer;
292362306a36Sopenharmony_ci		chain_dma = chain_req->chain_buffer_dma;
292462306a36Sopenharmony_ci	} while (1);
292562306a36Sopenharmony_ci
292662306a36Sopenharmony_ci
292762306a36Sopenharmony_ci fill_in_last_segment:
292862306a36Sopenharmony_ci
292962306a36Sopenharmony_ci	/* fill the last segment */
293062306a36Sopenharmony_ci	while (sges_left > 0) {
293162306a36Sopenharmony_ci		if (sges_left == 1)
293262306a36Sopenharmony_ci			_base_add_sg_single_ieee(sg_local,
293362306a36Sopenharmony_ci			    simple_sgl_flags_last, 0, sg_dma_len(sg_scmd),
293462306a36Sopenharmony_ci			    sg_dma_address(sg_scmd));
293562306a36Sopenharmony_ci		else
293662306a36Sopenharmony_ci			_base_add_sg_single_ieee(sg_local, simple_sgl_flags, 0,
293762306a36Sopenharmony_ci			    sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
293862306a36Sopenharmony_ci		sg_scmd = sg_next(sg_scmd);
293962306a36Sopenharmony_ci		sg_local += ioc->sge_size_ieee;
294062306a36Sopenharmony_ci		sges_left--;
294162306a36Sopenharmony_ci	}
294262306a36Sopenharmony_ci
294362306a36Sopenharmony_ci	return 0;
294462306a36Sopenharmony_ci}
294562306a36Sopenharmony_ci
294662306a36Sopenharmony_ci/**
294762306a36Sopenharmony_ci * _base_build_sg_ieee - build generic sg for IEEE format
294862306a36Sopenharmony_ci * @ioc: per adapter object
294962306a36Sopenharmony_ci * @psge: virtual address for SGE
295062306a36Sopenharmony_ci * @data_out_dma: physical address for WRITES
295162306a36Sopenharmony_ci * @data_out_sz: data xfer size for WRITES
295262306a36Sopenharmony_ci * @data_in_dma: physical address for READS
295362306a36Sopenharmony_ci * @data_in_sz: data xfer size for READS
295462306a36Sopenharmony_ci */
295562306a36Sopenharmony_cistatic void
295662306a36Sopenharmony_ci_base_build_sg_ieee(struct MPT3SAS_ADAPTER *ioc, void *psge,
295762306a36Sopenharmony_ci	dma_addr_t data_out_dma, size_t data_out_sz, dma_addr_t data_in_dma,
295862306a36Sopenharmony_ci	size_t data_in_sz)
295962306a36Sopenharmony_ci{
296062306a36Sopenharmony_ci	u8 sgl_flags;
296162306a36Sopenharmony_ci
296262306a36Sopenharmony_ci	if (!data_out_sz && !data_in_sz) {
296362306a36Sopenharmony_ci		_base_build_zero_len_sge_ieee(ioc, psge);
296462306a36Sopenharmony_ci		return;
296562306a36Sopenharmony_ci	}
296662306a36Sopenharmony_ci
296762306a36Sopenharmony_ci	if (data_out_sz && data_in_sz) {
296862306a36Sopenharmony_ci		/* WRITE sgel first */
296962306a36Sopenharmony_ci		sgl_flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
297062306a36Sopenharmony_ci		    MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR;
297162306a36Sopenharmony_ci		_base_add_sg_single_ieee(psge, sgl_flags, 0, data_out_sz,
297262306a36Sopenharmony_ci		    data_out_dma);
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_ci		/* incr sgel */
297562306a36Sopenharmony_ci		psge += ioc->sge_size_ieee;
297662306a36Sopenharmony_ci
297762306a36Sopenharmony_ci		/* READ sgel last */
297862306a36Sopenharmony_ci		sgl_flags |= MPI25_IEEE_SGE_FLAGS_END_OF_LIST;
297962306a36Sopenharmony_ci		_base_add_sg_single_ieee(psge, sgl_flags, 0, data_in_sz,
298062306a36Sopenharmony_ci		    data_in_dma);
298162306a36Sopenharmony_ci	} else if (data_out_sz) /* WRITE */ {
298262306a36Sopenharmony_ci		sgl_flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
298362306a36Sopenharmony_ci		    MPI25_IEEE_SGE_FLAGS_END_OF_LIST |
298462306a36Sopenharmony_ci		    MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR;
298562306a36Sopenharmony_ci		_base_add_sg_single_ieee(psge, sgl_flags, 0, data_out_sz,
298662306a36Sopenharmony_ci		    data_out_dma);
298762306a36Sopenharmony_ci	} else if (data_in_sz) /* READ */ {
298862306a36Sopenharmony_ci		sgl_flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
298962306a36Sopenharmony_ci		    MPI25_IEEE_SGE_FLAGS_END_OF_LIST |
299062306a36Sopenharmony_ci		    MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR;
299162306a36Sopenharmony_ci		_base_add_sg_single_ieee(psge, sgl_flags, 0, data_in_sz,
299262306a36Sopenharmony_ci		    data_in_dma);
299362306a36Sopenharmony_ci	}
299462306a36Sopenharmony_ci}
299562306a36Sopenharmony_ci
299662306a36Sopenharmony_ci#define convert_to_kb(x) ((x) << (PAGE_SHIFT - 10))
299762306a36Sopenharmony_ci
299862306a36Sopenharmony_ci/**
299962306a36Sopenharmony_ci * _base_config_dma_addressing - set dma addressing
300062306a36Sopenharmony_ci * @ioc: per adapter object
300162306a36Sopenharmony_ci * @pdev: PCI device struct
300262306a36Sopenharmony_ci *
300362306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
300462306a36Sopenharmony_ci */
300562306a36Sopenharmony_cistatic int
300662306a36Sopenharmony_ci_base_config_dma_addressing(struct MPT3SAS_ADAPTER *ioc, struct pci_dev *pdev)
300762306a36Sopenharmony_ci{
300862306a36Sopenharmony_ci	struct sysinfo s;
300962306a36Sopenharmony_ci	u64 coherent_dma_mask, dma_mask;
301062306a36Sopenharmony_ci
301162306a36Sopenharmony_ci	if (ioc->is_mcpu_endpoint || sizeof(dma_addr_t) == 4) {
301262306a36Sopenharmony_ci		ioc->dma_mask = 32;
301362306a36Sopenharmony_ci		coherent_dma_mask = dma_mask = DMA_BIT_MASK(32);
301462306a36Sopenharmony_ci	/* Set 63 bit DMA mask for all SAS3 and SAS35 controllers */
301562306a36Sopenharmony_ci	} else if (ioc->hba_mpi_version_belonged > MPI2_VERSION) {
301662306a36Sopenharmony_ci		ioc->dma_mask = 63;
301762306a36Sopenharmony_ci		coherent_dma_mask = dma_mask = DMA_BIT_MASK(63);
301862306a36Sopenharmony_ci	} else {
301962306a36Sopenharmony_ci		ioc->dma_mask = 64;
302062306a36Sopenharmony_ci		coherent_dma_mask = dma_mask = DMA_BIT_MASK(64);
302162306a36Sopenharmony_ci	}
302262306a36Sopenharmony_ci
302362306a36Sopenharmony_ci	if (ioc->use_32bit_dma)
302462306a36Sopenharmony_ci		coherent_dma_mask = DMA_BIT_MASK(32);
302562306a36Sopenharmony_ci
302662306a36Sopenharmony_ci	if (dma_set_mask(&pdev->dev, dma_mask) ||
302762306a36Sopenharmony_ci	    dma_set_coherent_mask(&pdev->dev, coherent_dma_mask))
302862306a36Sopenharmony_ci		return -ENODEV;
302962306a36Sopenharmony_ci
303062306a36Sopenharmony_ci	if (ioc->dma_mask > 32) {
303162306a36Sopenharmony_ci		ioc->base_add_sg_single = &_base_add_sg_single_64;
303262306a36Sopenharmony_ci		ioc->sge_size = sizeof(Mpi2SGESimple64_t);
303362306a36Sopenharmony_ci	} else {
303462306a36Sopenharmony_ci		ioc->base_add_sg_single = &_base_add_sg_single_32;
303562306a36Sopenharmony_ci		ioc->sge_size = sizeof(Mpi2SGESimple32_t);
303662306a36Sopenharmony_ci	}
303762306a36Sopenharmony_ci
303862306a36Sopenharmony_ci	si_meminfo(&s);
303962306a36Sopenharmony_ci	ioc_info(ioc, "%d BIT PCI BUS DMA ADDRESSING SUPPORTED, total mem (%ld kB)\n",
304062306a36Sopenharmony_ci		ioc->dma_mask, convert_to_kb(s.totalram));
304162306a36Sopenharmony_ci
304262306a36Sopenharmony_ci	return 0;
304362306a36Sopenharmony_ci}
304462306a36Sopenharmony_ci
304562306a36Sopenharmony_ci/**
304662306a36Sopenharmony_ci * _base_check_enable_msix - checks MSIX capabable.
304762306a36Sopenharmony_ci * @ioc: per adapter object
304862306a36Sopenharmony_ci *
304962306a36Sopenharmony_ci * Check to see if card is capable of MSIX, and set number
305062306a36Sopenharmony_ci * of available msix vectors
305162306a36Sopenharmony_ci */
305262306a36Sopenharmony_cistatic int
305362306a36Sopenharmony_ci_base_check_enable_msix(struct MPT3SAS_ADAPTER *ioc)
305462306a36Sopenharmony_ci{
305562306a36Sopenharmony_ci	int base;
305662306a36Sopenharmony_ci	u16 message_control;
305762306a36Sopenharmony_ci
305862306a36Sopenharmony_ci	/* Check whether controller SAS2008 B0 controller,
305962306a36Sopenharmony_ci	 * if it is SAS2008 B0 controller use IO-APIC instead of MSIX
306062306a36Sopenharmony_ci	 */
306162306a36Sopenharmony_ci	if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 &&
306262306a36Sopenharmony_ci	    ioc->pdev->revision == SAS2_PCI_DEVICE_B0_REVISION) {
306362306a36Sopenharmony_ci		return -EINVAL;
306462306a36Sopenharmony_ci	}
306562306a36Sopenharmony_ci
306662306a36Sopenharmony_ci	base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX);
306762306a36Sopenharmony_ci	if (!base) {
306862306a36Sopenharmony_ci		dfailprintk(ioc, ioc_info(ioc, "msix not supported\n"));
306962306a36Sopenharmony_ci		return -EINVAL;
307062306a36Sopenharmony_ci	}
307162306a36Sopenharmony_ci
307262306a36Sopenharmony_ci	/* get msix vector count */
307362306a36Sopenharmony_ci	/* NUMA_IO not supported for older controllers */
307462306a36Sopenharmony_ci	if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2004 ||
307562306a36Sopenharmony_ci	    ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 ||
307662306a36Sopenharmony_ci	    ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_1 ||
307762306a36Sopenharmony_ci	    ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_2 ||
307862306a36Sopenharmony_ci	    ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_3 ||
307962306a36Sopenharmony_ci	    ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_1 ||
308062306a36Sopenharmony_ci	    ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_2)
308162306a36Sopenharmony_ci		ioc->msix_vector_count = 1;
308262306a36Sopenharmony_ci	else {
308362306a36Sopenharmony_ci		pci_read_config_word(ioc->pdev, base + 2, &message_control);
308462306a36Sopenharmony_ci		ioc->msix_vector_count = (message_control & 0x3FF) + 1;
308562306a36Sopenharmony_ci	}
308662306a36Sopenharmony_ci	dinitprintk(ioc, ioc_info(ioc, "msix is supported, vector_count(%d)\n",
308762306a36Sopenharmony_ci				  ioc->msix_vector_count));
308862306a36Sopenharmony_ci	return 0;
308962306a36Sopenharmony_ci}
309062306a36Sopenharmony_ci
309162306a36Sopenharmony_ci/**
309262306a36Sopenharmony_ci * mpt3sas_base_free_irq - free irq
309362306a36Sopenharmony_ci * @ioc: per adapter object
309462306a36Sopenharmony_ci *
309562306a36Sopenharmony_ci * Freeing respective reply_queue from the list.
309662306a36Sopenharmony_ci */
309762306a36Sopenharmony_civoid
309862306a36Sopenharmony_cimpt3sas_base_free_irq(struct MPT3SAS_ADAPTER *ioc)
309962306a36Sopenharmony_ci{
310062306a36Sopenharmony_ci	unsigned int irq;
310162306a36Sopenharmony_ci	struct adapter_reply_queue *reply_q, *next;
310262306a36Sopenharmony_ci
310362306a36Sopenharmony_ci	if (list_empty(&ioc->reply_queue_list))
310462306a36Sopenharmony_ci		return;
310562306a36Sopenharmony_ci
310662306a36Sopenharmony_ci	list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) {
310762306a36Sopenharmony_ci		list_del(&reply_q->list);
310862306a36Sopenharmony_ci		if (reply_q->is_iouring_poll_q) {
310962306a36Sopenharmony_ci			kfree(reply_q);
311062306a36Sopenharmony_ci			continue;
311162306a36Sopenharmony_ci		}
311262306a36Sopenharmony_ci
311362306a36Sopenharmony_ci		if (ioc->smp_affinity_enable) {
311462306a36Sopenharmony_ci			irq = pci_irq_vector(ioc->pdev, reply_q->msix_index);
311562306a36Sopenharmony_ci			irq_update_affinity_hint(irq, NULL);
311662306a36Sopenharmony_ci		}
311762306a36Sopenharmony_ci		free_irq(pci_irq_vector(ioc->pdev, reply_q->msix_index),
311862306a36Sopenharmony_ci			 reply_q);
311962306a36Sopenharmony_ci		kfree(reply_q);
312062306a36Sopenharmony_ci	}
312162306a36Sopenharmony_ci}
312262306a36Sopenharmony_ci
312362306a36Sopenharmony_ci/**
312462306a36Sopenharmony_ci * _base_request_irq - request irq
312562306a36Sopenharmony_ci * @ioc: per adapter object
312662306a36Sopenharmony_ci * @index: msix index into vector table
312762306a36Sopenharmony_ci *
312862306a36Sopenharmony_ci * Inserting respective reply_queue into the list.
312962306a36Sopenharmony_ci */
313062306a36Sopenharmony_cistatic int
313162306a36Sopenharmony_ci_base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index)
313262306a36Sopenharmony_ci{
313362306a36Sopenharmony_ci	struct pci_dev *pdev = ioc->pdev;
313462306a36Sopenharmony_ci	struct adapter_reply_queue *reply_q;
313562306a36Sopenharmony_ci	int r, qid;
313662306a36Sopenharmony_ci
313762306a36Sopenharmony_ci	reply_q =  kzalloc(sizeof(struct adapter_reply_queue), GFP_KERNEL);
313862306a36Sopenharmony_ci	if (!reply_q) {
313962306a36Sopenharmony_ci		ioc_err(ioc, "unable to allocate memory %zu!\n",
314062306a36Sopenharmony_ci			sizeof(struct adapter_reply_queue));
314162306a36Sopenharmony_ci		return -ENOMEM;
314262306a36Sopenharmony_ci	}
314362306a36Sopenharmony_ci	reply_q->ioc = ioc;
314462306a36Sopenharmony_ci	reply_q->msix_index = index;
314562306a36Sopenharmony_ci
314662306a36Sopenharmony_ci	atomic_set(&reply_q->busy, 0);
314762306a36Sopenharmony_ci
314862306a36Sopenharmony_ci	if (index >= ioc->iopoll_q_start_index) {
314962306a36Sopenharmony_ci		qid = index - ioc->iopoll_q_start_index;
315062306a36Sopenharmony_ci		snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-mq-poll%d",
315162306a36Sopenharmony_ci		    ioc->driver_name, ioc->id, qid);
315262306a36Sopenharmony_ci		reply_q->is_iouring_poll_q = 1;
315362306a36Sopenharmony_ci		ioc->io_uring_poll_queues[qid].reply_q = reply_q;
315462306a36Sopenharmony_ci		goto out;
315562306a36Sopenharmony_ci	}
315662306a36Sopenharmony_ci
315762306a36Sopenharmony_ci
315862306a36Sopenharmony_ci	if (ioc->msix_enable)
315962306a36Sopenharmony_ci		snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d",
316062306a36Sopenharmony_ci		    ioc->driver_name, ioc->id, index);
316162306a36Sopenharmony_ci	else
316262306a36Sopenharmony_ci		snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d",
316362306a36Sopenharmony_ci		    ioc->driver_name, ioc->id);
316462306a36Sopenharmony_ci	r = request_irq(pci_irq_vector(pdev, index), _base_interrupt,
316562306a36Sopenharmony_ci			IRQF_SHARED, reply_q->name, reply_q);
316662306a36Sopenharmony_ci	if (r) {
316762306a36Sopenharmony_ci		pr_err("%s: unable to allocate interrupt %d!\n",
316862306a36Sopenharmony_ci		       reply_q->name, pci_irq_vector(pdev, index));
316962306a36Sopenharmony_ci		kfree(reply_q);
317062306a36Sopenharmony_ci		return -EBUSY;
317162306a36Sopenharmony_ci	}
317262306a36Sopenharmony_ciout:
317362306a36Sopenharmony_ci	INIT_LIST_HEAD(&reply_q->list);
317462306a36Sopenharmony_ci	list_add_tail(&reply_q->list, &ioc->reply_queue_list);
317562306a36Sopenharmony_ci	return 0;
317662306a36Sopenharmony_ci}
317762306a36Sopenharmony_ci
317862306a36Sopenharmony_ci/**
317962306a36Sopenharmony_ci * _base_assign_reply_queues - assigning msix index for each cpu
318062306a36Sopenharmony_ci * @ioc: per adapter object
318162306a36Sopenharmony_ci *
318262306a36Sopenharmony_ci * The enduser would need to set the affinity via /proc/irq/#/smp_affinity
318362306a36Sopenharmony_ci */
318462306a36Sopenharmony_cistatic void
318562306a36Sopenharmony_ci_base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc)
318662306a36Sopenharmony_ci{
318762306a36Sopenharmony_ci	unsigned int cpu, nr_cpus, nr_msix, index = 0, irq;
318862306a36Sopenharmony_ci	struct adapter_reply_queue *reply_q;
318962306a36Sopenharmony_ci	int iopoll_q_count = ioc->reply_queue_count -
319062306a36Sopenharmony_ci	    ioc->iopoll_q_start_index;
319162306a36Sopenharmony_ci	const struct cpumask *mask;
319262306a36Sopenharmony_ci
319362306a36Sopenharmony_ci	if (!_base_is_controller_msix_enabled(ioc))
319462306a36Sopenharmony_ci		return;
319562306a36Sopenharmony_ci
319662306a36Sopenharmony_ci	if (ioc->msix_load_balance)
319762306a36Sopenharmony_ci		return;
319862306a36Sopenharmony_ci
319962306a36Sopenharmony_ci	memset(ioc->cpu_msix_table, 0, ioc->cpu_msix_table_sz);
320062306a36Sopenharmony_ci
320162306a36Sopenharmony_ci	nr_cpus = num_online_cpus();
320262306a36Sopenharmony_ci	nr_msix = ioc->reply_queue_count = min(ioc->reply_queue_count,
320362306a36Sopenharmony_ci					       ioc->facts.MaxMSIxVectors);
320462306a36Sopenharmony_ci	if (!nr_msix)
320562306a36Sopenharmony_ci		return;
320662306a36Sopenharmony_ci
320762306a36Sopenharmony_ci	if (ioc->smp_affinity_enable) {
320862306a36Sopenharmony_ci
320962306a36Sopenharmony_ci		/*
321062306a36Sopenharmony_ci		 * set irq affinity to local numa node for those irqs
321162306a36Sopenharmony_ci		 * corresponding to high iops queues.
321262306a36Sopenharmony_ci		 */
321362306a36Sopenharmony_ci		if (ioc->high_iops_queues) {
321462306a36Sopenharmony_ci			mask = cpumask_of_node(dev_to_node(&ioc->pdev->dev));
321562306a36Sopenharmony_ci			for (index = 0; index < ioc->high_iops_queues;
321662306a36Sopenharmony_ci			    index++) {
321762306a36Sopenharmony_ci				irq = pci_irq_vector(ioc->pdev, index);
321862306a36Sopenharmony_ci				irq_set_affinity_and_hint(irq, mask);
321962306a36Sopenharmony_ci			}
322062306a36Sopenharmony_ci		}
322162306a36Sopenharmony_ci
322262306a36Sopenharmony_ci		list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
322362306a36Sopenharmony_ci			const cpumask_t *mask;
322462306a36Sopenharmony_ci
322562306a36Sopenharmony_ci			if (reply_q->msix_index < ioc->high_iops_queues ||
322662306a36Sopenharmony_ci			    reply_q->msix_index >= ioc->iopoll_q_start_index)
322762306a36Sopenharmony_ci				continue;
322862306a36Sopenharmony_ci
322962306a36Sopenharmony_ci			mask = pci_irq_get_affinity(ioc->pdev,
323062306a36Sopenharmony_ci			    reply_q->msix_index);
323162306a36Sopenharmony_ci			if (!mask) {
323262306a36Sopenharmony_ci				ioc_warn(ioc, "no affinity for msi %x\n",
323362306a36Sopenharmony_ci					 reply_q->msix_index);
323462306a36Sopenharmony_ci				goto fall_back;
323562306a36Sopenharmony_ci			}
323662306a36Sopenharmony_ci
323762306a36Sopenharmony_ci			for_each_cpu_and(cpu, mask, cpu_online_mask) {
323862306a36Sopenharmony_ci				if (cpu >= ioc->cpu_msix_table_sz)
323962306a36Sopenharmony_ci					break;
324062306a36Sopenharmony_ci				ioc->cpu_msix_table[cpu] = reply_q->msix_index;
324162306a36Sopenharmony_ci			}
324262306a36Sopenharmony_ci		}
324362306a36Sopenharmony_ci		return;
324462306a36Sopenharmony_ci	}
324562306a36Sopenharmony_ci
324662306a36Sopenharmony_cifall_back:
324762306a36Sopenharmony_ci	cpu = cpumask_first(cpu_online_mask);
324862306a36Sopenharmony_ci	nr_msix -= (ioc->high_iops_queues - iopoll_q_count);
324962306a36Sopenharmony_ci	index = 0;
325062306a36Sopenharmony_ci
325162306a36Sopenharmony_ci	list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
325262306a36Sopenharmony_ci		unsigned int i, group = nr_cpus / nr_msix;
325362306a36Sopenharmony_ci
325462306a36Sopenharmony_ci		if (reply_q->msix_index < ioc->high_iops_queues ||
325562306a36Sopenharmony_ci		    reply_q->msix_index >= ioc->iopoll_q_start_index)
325662306a36Sopenharmony_ci			continue;
325762306a36Sopenharmony_ci
325862306a36Sopenharmony_ci		if (cpu >= nr_cpus)
325962306a36Sopenharmony_ci			break;
326062306a36Sopenharmony_ci
326162306a36Sopenharmony_ci		if (index < nr_cpus % nr_msix)
326262306a36Sopenharmony_ci			group++;
326362306a36Sopenharmony_ci
326462306a36Sopenharmony_ci		for (i = 0 ; i < group ; i++) {
326562306a36Sopenharmony_ci			ioc->cpu_msix_table[cpu] = reply_q->msix_index;
326662306a36Sopenharmony_ci			cpu = cpumask_next(cpu, cpu_online_mask);
326762306a36Sopenharmony_ci		}
326862306a36Sopenharmony_ci		index++;
326962306a36Sopenharmony_ci	}
327062306a36Sopenharmony_ci}
327162306a36Sopenharmony_ci
327262306a36Sopenharmony_ci/**
327362306a36Sopenharmony_ci * _base_check_and_enable_high_iops_queues - enable high iops mode
327462306a36Sopenharmony_ci * @ioc: per adapter object
327562306a36Sopenharmony_ci * @hba_msix_vector_count: msix vectors supported by HBA
327662306a36Sopenharmony_ci *
327762306a36Sopenharmony_ci * Enable high iops queues only if
327862306a36Sopenharmony_ci *  - HBA is a SEA/AERO controller and
327962306a36Sopenharmony_ci *  - MSI-Xs vector supported by the HBA is 128 and
328062306a36Sopenharmony_ci *  - total CPU count in the system >=16 and
328162306a36Sopenharmony_ci *  - loaded driver with default max_msix_vectors module parameter and
328262306a36Sopenharmony_ci *  - system booted in non kdump mode
328362306a36Sopenharmony_ci *
328462306a36Sopenharmony_ci * Return: nothing.
328562306a36Sopenharmony_ci */
328662306a36Sopenharmony_cistatic void
328762306a36Sopenharmony_ci_base_check_and_enable_high_iops_queues(struct MPT3SAS_ADAPTER *ioc,
328862306a36Sopenharmony_ci		int hba_msix_vector_count)
328962306a36Sopenharmony_ci{
329062306a36Sopenharmony_ci	u16 lnksta, speed;
329162306a36Sopenharmony_ci
329262306a36Sopenharmony_ci	/*
329362306a36Sopenharmony_ci	 * Disable high iops queues if io uring poll queues are enabled.
329462306a36Sopenharmony_ci	 */
329562306a36Sopenharmony_ci	if (perf_mode == MPT_PERF_MODE_IOPS ||
329662306a36Sopenharmony_ci	    perf_mode == MPT_PERF_MODE_LATENCY ||
329762306a36Sopenharmony_ci	    ioc->io_uring_poll_queues) {
329862306a36Sopenharmony_ci		ioc->high_iops_queues = 0;
329962306a36Sopenharmony_ci		return;
330062306a36Sopenharmony_ci	}
330162306a36Sopenharmony_ci
330262306a36Sopenharmony_ci	if (perf_mode == MPT_PERF_MODE_DEFAULT) {
330362306a36Sopenharmony_ci
330462306a36Sopenharmony_ci		pcie_capability_read_word(ioc->pdev, PCI_EXP_LNKSTA, &lnksta);
330562306a36Sopenharmony_ci		speed = lnksta & PCI_EXP_LNKSTA_CLS;
330662306a36Sopenharmony_ci
330762306a36Sopenharmony_ci		if (speed < 0x4) {
330862306a36Sopenharmony_ci			ioc->high_iops_queues = 0;
330962306a36Sopenharmony_ci			return;
331062306a36Sopenharmony_ci		}
331162306a36Sopenharmony_ci	}
331262306a36Sopenharmony_ci
331362306a36Sopenharmony_ci	if (!reset_devices && ioc->is_aero_ioc &&
331462306a36Sopenharmony_ci	    hba_msix_vector_count == MPT3SAS_GEN35_MAX_MSIX_QUEUES &&
331562306a36Sopenharmony_ci	    num_online_cpus() >= MPT3SAS_HIGH_IOPS_REPLY_QUEUES &&
331662306a36Sopenharmony_ci	    max_msix_vectors == -1)
331762306a36Sopenharmony_ci		ioc->high_iops_queues = MPT3SAS_HIGH_IOPS_REPLY_QUEUES;
331862306a36Sopenharmony_ci	else
331962306a36Sopenharmony_ci		ioc->high_iops_queues = 0;
332062306a36Sopenharmony_ci}
332162306a36Sopenharmony_ci
332262306a36Sopenharmony_ci/**
332362306a36Sopenharmony_ci * mpt3sas_base_disable_msix - disables msix
332462306a36Sopenharmony_ci * @ioc: per adapter object
332562306a36Sopenharmony_ci *
332662306a36Sopenharmony_ci */
332762306a36Sopenharmony_civoid
332862306a36Sopenharmony_cimpt3sas_base_disable_msix(struct MPT3SAS_ADAPTER *ioc)
332962306a36Sopenharmony_ci{
333062306a36Sopenharmony_ci	if (!ioc->msix_enable)
333162306a36Sopenharmony_ci		return;
333262306a36Sopenharmony_ci	pci_free_irq_vectors(ioc->pdev);
333362306a36Sopenharmony_ci	ioc->msix_enable = 0;
333462306a36Sopenharmony_ci	kfree(ioc->io_uring_poll_queues);
333562306a36Sopenharmony_ci}
333662306a36Sopenharmony_ci
333762306a36Sopenharmony_ci/**
333862306a36Sopenharmony_ci * _base_alloc_irq_vectors - allocate msix vectors
333962306a36Sopenharmony_ci * @ioc: per adapter object
334062306a36Sopenharmony_ci *
334162306a36Sopenharmony_ci */
334262306a36Sopenharmony_cistatic int
334362306a36Sopenharmony_ci_base_alloc_irq_vectors(struct MPT3SAS_ADAPTER *ioc)
334462306a36Sopenharmony_ci{
334562306a36Sopenharmony_ci	int i, irq_flags = PCI_IRQ_MSIX;
334662306a36Sopenharmony_ci	struct irq_affinity desc = { .pre_vectors = ioc->high_iops_queues };
334762306a36Sopenharmony_ci	struct irq_affinity *descp = &desc;
334862306a36Sopenharmony_ci	/*
334962306a36Sopenharmony_ci	 * Don't allocate msix vectors for poll_queues.
335062306a36Sopenharmony_ci	 * msix_vectors is always within a range of FW supported reply queue.
335162306a36Sopenharmony_ci	 */
335262306a36Sopenharmony_ci	int nr_msix_vectors = ioc->iopoll_q_start_index;
335362306a36Sopenharmony_ci
335462306a36Sopenharmony_ci
335562306a36Sopenharmony_ci	if (ioc->smp_affinity_enable)
335662306a36Sopenharmony_ci		irq_flags |= PCI_IRQ_AFFINITY | PCI_IRQ_ALL_TYPES;
335762306a36Sopenharmony_ci	else
335862306a36Sopenharmony_ci		descp = NULL;
335962306a36Sopenharmony_ci
336062306a36Sopenharmony_ci	ioc_info(ioc, " %d %d %d\n", ioc->high_iops_queues,
336162306a36Sopenharmony_ci	    ioc->reply_queue_count, nr_msix_vectors);
336262306a36Sopenharmony_ci
336362306a36Sopenharmony_ci	i = pci_alloc_irq_vectors_affinity(ioc->pdev,
336462306a36Sopenharmony_ci	    ioc->high_iops_queues,
336562306a36Sopenharmony_ci	    nr_msix_vectors, irq_flags, descp);
336662306a36Sopenharmony_ci
336762306a36Sopenharmony_ci	return i;
336862306a36Sopenharmony_ci}
336962306a36Sopenharmony_ci
337062306a36Sopenharmony_ci/**
337162306a36Sopenharmony_ci * _base_enable_msix - enables msix, failback to io_apic
337262306a36Sopenharmony_ci * @ioc: per adapter object
337362306a36Sopenharmony_ci *
337462306a36Sopenharmony_ci */
337562306a36Sopenharmony_cistatic int
337662306a36Sopenharmony_ci_base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
337762306a36Sopenharmony_ci{
337862306a36Sopenharmony_ci	int r;
337962306a36Sopenharmony_ci	int i, local_max_msix_vectors;
338062306a36Sopenharmony_ci	u8 try_msix = 0;
338162306a36Sopenharmony_ci	int iopoll_q_count = 0;
338262306a36Sopenharmony_ci
338362306a36Sopenharmony_ci	ioc->msix_load_balance = false;
338462306a36Sopenharmony_ci
338562306a36Sopenharmony_ci	if (msix_disable == -1 || msix_disable == 0)
338662306a36Sopenharmony_ci		try_msix = 1;
338762306a36Sopenharmony_ci
338862306a36Sopenharmony_ci	if (!try_msix)
338962306a36Sopenharmony_ci		goto try_ioapic;
339062306a36Sopenharmony_ci
339162306a36Sopenharmony_ci	if (_base_check_enable_msix(ioc) != 0)
339262306a36Sopenharmony_ci		goto try_ioapic;
339362306a36Sopenharmony_ci
339462306a36Sopenharmony_ci	ioc_info(ioc, "MSI-X vectors supported: %d\n", ioc->msix_vector_count);
339562306a36Sopenharmony_ci	pr_info("\t no of cores: %d, max_msix_vectors: %d\n",
339662306a36Sopenharmony_ci		ioc->cpu_count, max_msix_vectors);
339762306a36Sopenharmony_ci
339862306a36Sopenharmony_ci	ioc->reply_queue_count =
339962306a36Sopenharmony_ci		min_t(int, ioc->cpu_count, ioc->msix_vector_count);
340062306a36Sopenharmony_ci
340162306a36Sopenharmony_ci	if (!ioc->rdpq_array_enable && max_msix_vectors == -1)
340262306a36Sopenharmony_ci		local_max_msix_vectors = (reset_devices) ? 1 : 8;
340362306a36Sopenharmony_ci	else
340462306a36Sopenharmony_ci		local_max_msix_vectors = max_msix_vectors;
340562306a36Sopenharmony_ci
340662306a36Sopenharmony_ci	if (local_max_msix_vectors == 0)
340762306a36Sopenharmony_ci		goto try_ioapic;
340862306a36Sopenharmony_ci
340962306a36Sopenharmony_ci	/*
341062306a36Sopenharmony_ci	 * Enable msix_load_balance only if combined reply queue mode is
341162306a36Sopenharmony_ci	 * disabled on SAS3 & above generation HBA devices.
341262306a36Sopenharmony_ci	 */
341362306a36Sopenharmony_ci	if (!ioc->combined_reply_queue &&
341462306a36Sopenharmony_ci	    ioc->hba_mpi_version_belonged != MPI2_VERSION) {
341562306a36Sopenharmony_ci		ioc_info(ioc,
341662306a36Sopenharmony_ci		    "combined ReplyQueue is off, Enabling msix load balance\n");
341762306a36Sopenharmony_ci		ioc->msix_load_balance = true;
341862306a36Sopenharmony_ci	}
341962306a36Sopenharmony_ci
342062306a36Sopenharmony_ci	/*
342162306a36Sopenharmony_ci	 * smp affinity setting is not need when msix load balance
342262306a36Sopenharmony_ci	 * is enabled.
342362306a36Sopenharmony_ci	 */
342462306a36Sopenharmony_ci	if (ioc->msix_load_balance)
342562306a36Sopenharmony_ci		ioc->smp_affinity_enable = 0;
342662306a36Sopenharmony_ci
342762306a36Sopenharmony_ci	if (!ioc->smp_affinity_enable || ioc->reply_queue_count <= 1)
342862306a36Sopenharmony_ci		ioc->shost->host_tagset = 0;
342962306a36Sopenharmony_ci
343062306a36Sopenharmony_ci	/*
343162306a36Sopenharmony_ci	 * Enable io uring poll queues only if host_tagset is enabled.
343262306a36Sopenharmony_ci	 */
343362306a36Sopenharmony_ci	if (ioc->shost->host_tagset)
343462306a36Sopenharmony_ci		iopoll_q_count = poll_queues;
343562306a36Sopenharmony_ci
343662306a36Sopenharmony_ci	if (iopoll_q_count) {
343762306a36Sopenharmony_ci		ioc->io_uring_poll_queues = kcalloc(iopoll_q_count,
343862306a36Sopenharmony_ci		    sizeof(struct io_uring_poll_queue), GFP_KERNEL);
343962306a36Sopenharmony_ci		if (!ioc->io_uring_poll_queues)
344062306a36Sopenharmony_ci			iopoll_q_count = 0;
344162306a36Sopenharmony_ci	}
344262306a36Sopenharmony_ci
344362306a36Sopenharmony_ci	if (ioc->is_aero_ioc)
344462306a36Sopenharmony_ci		_base_check_and_enable_high_iops_queues(ioc,
344562306a36Sopenharmony_ci		    ioc->msix_vector_count);
344662306a36Sopenharmony_ci
344762306a36Sopenharmony_ci	/*
344862306a36Sopenharmony_ci	 * Add high iops queues count to reply queue count if high iops queues
344962306a36Sopenharmony_ci	 * are enabled.
345062306a36Sopenharmony_ci	 */
345162306a36Sopenharmony_ci	ioc->reply_queue_count = min_t(int,
345262306a36Sopenharmony_ci	    ioc->reply_queue_count + ioc->high_iops_queues,
345362306a36Sopenharmony_ci	    ioc->msix_vector_count);
345462306a36Sopenharmony_ci
345562306a36Sopenharmony_ci	/*
345662306a36Sopenharmony_ci	 * Adjust the reply queue count incase reply queue count
345762306a36Sopenharmony_ci	 * exceeds the user provided MSIx vectors count.
345862306a36Sopenharmony_ci	 */
345962306a36Sopenharmony_ci	if (local_max_msix_vectors > 0)
346062306a36Sopenharmony_ci		ioc->reply_queue_count = min_t(int, local_max_msix_vectors,
346162306a36Sopenharmony_ci		    ioc->reply_queue_count);
346262306a36Sopenharmony_ci	/*
346362306a36Sopenharmony_ci	 * Add io uring poll queues count to reply queues count
346462306a36Sopenharmony_ci	 * if io uring is enabled in driver.
346562306a36Sopenharmony_ci	 */
346662306a36Sopenharmony_ci	if (iopoll_q_count) {
346762306a36Sopenharmony_ci		if (ioc->reply_queue_count < (iopoll_q_count + MPT3_MIN_IRQS))
346862306a36Sopenharmony_ci			iopoll_q_count = 0;
346962306a36Sopenharmony_ci		ioc->reply_queue_count = min_t(int,
347062306a36Sopenharmony_ci		    ioc->reply_queue_count + iopoll_q_count,
347162306a36Sopenharmony_ci		    ioc->msix_vector_count);
347262306a36Sopenharmony_ci	}
347362306a36Sopenharmony_ci
347462306a36Sopenharmony_ci	/*
347562306a36Sopenharmony_ci	 * Starting index of io uring poll queues in reply queue list.
347662306a36Sopenharmony_ci	 */
347762306a36Sopenharmony_ci	ioc->iopoll_q_start_index =
347862306a36Sopenharmony_ci	    ioc->reply_queue_count - iopoll_q_count;
347962306a36Sopenharmony_ci
348062306a36Sopenharmony_ci	r = _base_alloc_irq_vectors(ioc);
348162306a36Sopenharmony_ci	if (r < 0) {
348262306a36Sopenharmony_ci		ioc_info(ioc, "pci_alloc_irq_vectors failed (r=%d) !!!\n", r);
348362306a36Sopenharmony_ci		goto try_ioapic;
348462306a36Sopenharmony_ci	}
348562306a36Sopenharmony_ci
348662306a36Sopenharmony_ci	/*
348762306a36Sopenharmony_ci	 * Adjust the reply queue count if the allocated
348862306a36Sopenharmony_ci	 * MSIx vectors is less then the requested number
348962306a36Sopenharmony_ci	 * of MSIx vectors.
349062306a36Sopenharmony_ci	 */
349162306a36Sopenharmony_ci	if (r < ioc->iopoll_q_start_index) {
349262306a36Sopenharmony_ci		ioc->reply_queue_count = r + iopoll_q_count;
349362306a36Sopenharmony_ci		ioc->iopoll_q_start_index =
349462306a36Sopenharmony_ci		    ioc->reply_queue_count - iopoll_q_count;
349562306a36Sopenharmony_ci	}
349662306a36Sopenharmony_ci
349762306a36Sopenharmony_ci	ioc->msix_enable = 1;
349862306a36Sopenharmony_ci	for (i = 0; i < ioc->reply_queue_count; i++) {
349962306a36Sopenharmony_ci		r = _base_request_irq(ioc, i);
350062306a36Sopenharmony_ci		if (r) {
350162306a36Sopenharmony_ci			mpt3sas_base_free_irq(ioc);
350262306a36Sopenharmony_ci			mpt3sas_base_disable_msix(ioc);
350362306a36Sopenharmony_ci			goto try_ioapic;
350462306a36Sopenharmony_ci		}
350562306a36Sopenharmony_ci	}
350662306a36Sopenharmony_ci
350762306a36Sopenharmony_ci	ioc_info(ioc, "High IOPs queues : %s\n",
350862306a36Sopenharmony_ci			ioc->high_iops_queues ? "enabled" : "disabled");
350962306a36Sopenharmony_ci
351062306a36Sopenharmony_ci	return 0;
351162306a36Sopenharmony_ci
351262306a36Sopenharmony_ci/* failback to io_apic interrupt routing */
351362306a36Sopenharmony_ci try_ioapic:
351462306a36Sopenharmony_ci	ioc->high_iops_queues = 0;
351562306a36Sopenharmony_ci	ioc_info(ioc, "High IOPs queues : disabled\n");
351662306a36Sopenharmony_ci	ioc->reply_queue_count = 1;
351762306a36Sopenharmony_ci	ioc->iopoll_q_start_index = ioc->reply_queue_count - 0;
351862306a36Sopenharmony_ci	r = pci_alloc_irq_vectors(ioc->pdev, 1, 1, PCI_IRQ_LEGACY);
351962306a36Sopenharmony_ci	if (r < 0) {
352062306a36Sopenharmony_ci		dfailprintk(ioc,
352162306a36Sopenharmony_ci			    ioc_info(ioc, "pci_alloc_irq_vector(legacy) failed (r=%d) !!!\n",
352262306a36Sopenharmony_ci				     r));
352362306a36Sopenharmony_ci	} else
352462306a36Sopenharmony_ci		r = _base_request_irq(ioc, 0);
352562306a36Sopenharmony_ci
352662306a36Sopenharmony_ci	return r;
352762306a36Sopenharmony_ci}
352862306a36Sopenharmony_ci
352962306a36Sopenharmony_ci/**
353062306a36Sopenharmony_ci * mpt3sas_base_unmap_resources - free controller resources
353162306a36Sopenharmony_ci * @ioc: per adapter object
353262306a36Sopenharmony_ci */
353362306a36Sopenharmony_cistatic void
353462306a36Sopenharmony_cimpt3sas_base_unmap_resources(struct MPT3SAS_ADAPTER *ioc)
353562306a36Sopenharmony_ci{
353662306a36Sopenharmony_ci	struct pci_dev *pdev = ioc->pdev;
353762306a36Sopenharmony_ci
353862306a36Sopenharmony_ci	dexitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
353962306a36Sopenharmony_ci
354062306a36Sopenharmony_ci	mpt3sas_base_free_irq(ioc);
354162306a36Sopenharmony_ci	mpt3sas_base_disable_msix(ioc);
354262306a36Sopenharmony_ci
354362306a36Sopenharmony_ci	kfree(ioc->replyPostRegisterIndex);
354462306a36Sopenharmony_ci	ioc->replyPostRegisterIndex = NULL;
354562306a36Sopenharmony_ci
354662306a36Sopenharmony_ci
354762306a36Sopenharmony_ci	if (ioc->chip_phys) {
354862306a36Sopenharmony_ci		iounmap(ioc->chip);
354962306a36Sopenharmony_ci		ioc->chip_phys = 0;
355062306a36Sopenharmony_ci	}
355162306a36Sopenharmony_ci
355262306a36Sopenharmony_ci	if (pci_is_enabled(pdev)) {
355362306a36Sopenharmony_ci		pci_release_selected_regions(ioc->pdev, ioc->bars);
355462306a36Sopenharmony_ci		pci_disable_device(pdev);
355562306a36Sopenharmony_ci	}
355662306a36Sopenharmony_ci}
355762306a36Sopenharmony_ci
355862306a36Sopenharmony_cistatic int
355962306a36Sopenharmony_ci_base_diag_reset(struct MPT3SAS_ADAPTER *ioc);
356062306a36Sopenharmony_ci
356162306a36Sopenharmony_ci/**
356262306a36Sopenharmony_ci * mpt3sas_base_check_for_fault_and_issue_reset - check if IOC is in fault state
356362306a36Sopenharmony_ci *     and if it is in fault state then issue diag reset.
356462306a36Sopenharmony_ci * @ioc: per adapter object
356562306a36Sopenharmony_ci *
356662306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
356762306a36Sopenharmony_ci */
356862306a36Sopenharmony_ciint
356962306a36Sopenharmony_cimpt3sas_base_check_for_fault_and_issue_reset(struct MPT3SAS_ADAPTER *ioc)
357062306a36Sopenharmony_ci{
357162306a36Sopenharmony_ci	u32 ioc_state;
357262306a36Sopenharmony_ci	int rc = -EFAULT;
357362306a36Sopenharmony_ci
357462306a36Sopenharmony_ci	dinitprintk(ioc, pr_info("%s\n", __func__));
357562306a36Sopenharmony_ci	if (ioc->pci_error_recovery)
357662306a36Sopenharmony_ci		return 0;
357762306a36Sopenharmony_ci	ioc_state = mpt3sas_base_get_iocstate(ioc, 0);
357862306a36Sopenharmony_ci	dhsprintk(ioc, pr_info("%s: ioc_state(0x%08x)\n", __func__, ioc_state));
357962306a36Sopenharmony_ci
358062306a36Sopenharmony_ci	if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
358162306a36Sopenharmony_ci		mpt3sas_print_fault_code(ioc, ioc_state &
358262306a36Sopenharmony_ci		    MPI2_DOORBELL_DATA_MASK);
358362306a36Sopenharmony_ci		mpt3sas_base_mask_interrupts(ioc);
358462306a36Sopenharmony_ci		rc = _base_diag_reset(ioc);
358562306a36Sopenharmony_ci	} else if ((ioc_state & MPI2_IOC_STATE_MASK) ==
358662306a36Sopenharmony_ci	    MPI2_IOC_STATE_COREDUMP) {
358762306a36Sopenharmony_ci		mpt3sas_print_coredump_info(ioc, ioc_state &
358862306a36Sopenharmony_ci		     MPI2_DOORBELL_DATA_MASK);
358962306a36Sopenharmony_ci		mpt3sas_base_wait_for_coredump_completion(ioc, __func__);
359062306a36Sopenharmony_ci		mpt3sas_base_mask_interrupts(ioc);
359162306a36Sopenharmony_ci		rc = _base_diag_reset(ioc);
359262306a36Sopenharmony_ci	}
359362306a36Sopenharmony_ci
359462306a36Sopenharmony_ci	return rc;
359562306a36Sopenharmony_ci}
359662306a36Sopenharmony_ci
359762306a36Sopenharmony_ci/**
359862306a36Sopenharmony_ci * mpt3sas_base_map_resources - map in controller resources (io/irq/memap)
359962306a36Sopenharmony_ci * @ioc: per adapter object
360062306a36Sopenharmony_ci *
360162306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
360262306a36Sopenharmony_ci */
360362306a36Sopenharmony_ciint
360462306a36Sopenharmony_cimpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
360562306a36Sopenharmony_ci{
360662306a36Sopenharmony_ci	struct pci_dev *pdev = ioc->pdev;
360762306a36Sopenharmony_ci	u32 memap_sz;
360862306a36Sopenharmony_ci	u32 pio_sz;
360962306a36Sopenharmony_ci	int i, r = 0, rc;
361062306a36Sopenharmony_ci	u64 pio_chip = 0;
361162306a36Sopenharmony_ci	phys_addr_t chip_phys = 0;
361262306a36Sopenharmony_ci	struct adapter_reply_queue *reply_q;
361362306a36Sopenharmony_ci	int iopoll_q_count = 0;
361462306a36Sopenharmony_ci
361562306a36Sopenharmony_ci	dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
361662306a36Sopenharmony_ci
361762306a36Sopenharmony_ci	ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
361862306a36Sopenharmony_ci	if (pci_enable_device_mem(pdev)) {
361962306a36Sopenharmony_ci		ioc_warn(ioc, "pci_enable_device_mem: failed\n");
362062306a36Sopenharmony_ci		ioc->bars = 0;
362162306a36Sopenharmony_ci		return -ENODEV;
362262306a36Sopenharmony_ci	}
362362306a36Sopenharmony_ci
362462306a36Sopenharmony_ci
362562306a36Sopenharmony_ci	if (pci_request_selected_regions(pdev, ioc->bars,
362662306a36Sopenharmony_ci	    ioc->driver_name)) {
362762306a36Sopenharmony_ci		ioc_warn(ioc, "pci_request_selected_regions: failed\n");
362862306a36Sopenharmony_ci		ioc->bars = 0;
362962306a36Sopenharmony_ci		r = -ENODEV;
363062306a36Sopenharmony_ci		goto out_fail;
363162306a36Sopenharmony_ci	}
363262306a36Sopenharmony_ci
363362306a36Sopenharmony_ci	pci_set_master(pdev);
363462306a36Sopenharmony_ci
363562306a36Sopenharmony_ci
363662306a36Sopenharmony_ci	if (_base_config_dma_addressing(ioc, pdev) != 0) {
363762306a36Sopenharmony_ci		ioc_warn(ioc, "no suitable DMA mask for %s\n", pci_name(pdev));
363862306a36Sopenharmony_ci		r = -ENODEV;
363962306a36Sopenharmony_ci		goto out_fail;
364062306a36Sopenharmony_ci	}
364162306a36Sopenharmony_ci
364262306a36Sopenharmony_ci	for (i = 0, memap_sz = 0, pio_sz = 0; (i < DEVICE_COUNT_RESOURCE) &&
364362306a36Sopenharmony_ci	     (!memap_sz || !pio_sz); i++) {
364462306a36Sopenharmony_ci		if (pci_resource_flags(pdev, i) & IORESOURCE_IO) {
364562306a36Sopenharmony_ci			if (pio_sz)
364662306a36Sopenharmony_ci				continue;
364762306a36Sopenharmony_ci			pio_chip = (u64)pci_resource_start(pdev, i);
364862306a36Sopenharmony_ci			pio_sz = pci_resource_len(pdev, i);
364962306a36Sopenharmony_ci		} else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
365062306a36Sopenharmony_ci			if (memap_sz)
365162306a36Sopenharmony_ci				continue;
365262306a36Sopenharmony_ci			ioc->chip_phys = pci_resource_start(pdev, i);
365362306a36Sopenharmony_ci			chip_phys = ioc->chip_phys;
365462306a36Sopenharmony_ci			memap_sz = pci_resource_len(pdev, i);
365562306a36Sopenharmony_ci			ioc->chip = ioremap(ioc->chip_phys, memap_sz);
365662306a36Sopenharmony_ci		}
365762306a36Sopenharmony_ci	}
365862306a36Sopenharmony_ci
365962306a36Sopenharmony_ci	if (ioc->chip == NULL) {
366062306a36Sopenharmony_ci		ioc_err(ioc,
366162306a36Sopenharmony_ci		    "unable to map adapter memory! or resource not found\n");
366262306a36Sopenharmony_ci		r = -EINVAL;
366362306a36Sopenharmony_ci		goto out_fail;
366462306a36Sopenharmony_ci	}
366562306a36Sopenharmony_ci
366662306a36Sopenharmony_ci	mpt3sas_base_mask_interrupts(ioc);
366762306a36Sopenharmony_ci
366862306a36Sopenharmony_ci	r = _base_get_ioc_facts(ioc);
366962306a36Sopenharmony_ci	if (r) {
367062306a36Sopenharmony_ci		rc = mpt3sas_base_check_for_fault_and_issue_reset(ioc);
367162306a36Sopenharmony_ci		if (rc || (_base_get_ioc_facts(ioc)))
367262306a36Sopenharmony_ci			goto out_fail;
367362306a36Sopenharmony_ci	}
367462306a36Sopenharmony_ci
367562306a36Sopenharmony_ci	if (!ioc->rdpq_array_enable_assigned) {
367662306a36Sopenharmony_ci		ioc->rdpq_array_enable = ioc->rdpq_array_capable;
367762306a36Sopenharmony_ci		ioc->rdpq_array_enable_assigned = 1;
367862306a36Sopenharmony_ci	}
367962306a36Sopenharmony_ci
368062306a36Sopenharmony_ci	r = _base_enable_msix(ioc);
368162306a36Sopenharmony_ci	if (r)
368262306a36Sopenharmony_ci		goto out_fail;
368362306a36Sopenharmony_ci
368462306a36Sopenharmony_ci	iopoll_q_count = ioc->reply_queue_count - ioc->iopoll_q_start_index;
368562306a36Sopenharmony_ci	for (i = 0; i < iopoll_q_count; i++) {
368662306a36Sopenharmony_ci		atomic_set(&ioc->io_uring_poll_queues[i].busy, 0);
368762306a36Sopenharmony_ci		atomic_set(&ioc->io_uring_poll_queues[i].pause, 0);
368862306a36Sopenharmony_ci	}
368962306a36Sopenharmony_ci
369062306a36Sopenharmony_ci	if (!ioc->is_driver_loading)
369162306a36Sopenharmony_ci		_base_init_irqpolls(ioc);
369262306a36Sopenharmony_ci	/* Use the Combined reply queue feature only for SAS3 C0 & higher
369362306a36Sopenharmony_ci	 * revision HBAs and also only when reply queue count is greater than 8
369462306a36Sopenharmony_ci	 */
369562306a36Sopenharmony_ci	if (ioc->combined_reply_queue) {
369662306a36Sopenharmony_ci		/* Determine the Supplemental Reply Post Host Index Registers
369762306a36Sopenharmony_ci		 * Addresse. Supplemental Reply Post Host Index Registers
369862306a36Sopenharmony_ci		 * starts at offset MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET and
369962306a36Sopenharmony_ci		 * each register is at offset bytes of
370062306a36Sopenharmony_ci		 * MPT3_SUP_REPLY_POST_HOST_INDEX_REG_OFFSET from previous one.
370162306a36Sopenharmony_ci		 */
370262306a36Sopenharmony_ci		ioc->replyPostRegisterIndex = kcalloc(
370362306a36Sopenharmony_ci		     ioc->combined_reply_index_count,
370462306a36Sopenharmony_ci		     sizeof(resource_size_t *), GFP_KERNEL);
370562306a36Sopenharmony_ci		if (!ioc->replyPostRegisterIndex) {
370662306a36Sopenharmony_ci			ioc_err(ioc,
370762306a36Sopenharmony_ci			    "allocation for replyPostRegisterIndex failed!\n");
370862306a36Sopenharmony_ci			r = -ENOMEM;
370962306a36Sopenharmony_ci			goto out_fail;
371062306a36Sopenharmony_ci		}
371162306a36Sopenharmony_ci
371262306a36Sopenharmony_ci		for (i = 0; i < ioc->combined_reply_index_count; i++) {
371362306a36Sopenharmony_ci			ioc->replyPostRegisterIndex[i] =
371462306a36Sopenharmony_ci				(resource_size_t __iomem *)
371562306a36Sopenharmony_ci				((u8 __force *)&ioc->chip->Doorbell +
371662306a36Sopenharmony_ci				 MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET +
371762306a36Sopenharmony_ci				 (i * MPT3_SUP_REPLY_POST_HOST_INDEX_REG_OFFSET));
371862306a36Sopenharmony_ci		}
371962306a36Sopenharmony_ci	}
372062306a36Sopenharmony_ci
372162306a36Sopenharmony_ci	if (ioc->is_warpdrive) {
372262306a36Sopenharmony_ci		ioc->reply_post_host_index[0] = (resource_size_t __iomem *)
372362306a36Sopenharmony_ci		    &ioc->chip->ReplyPostHostIndex;
372462306a36Sopenharmony_ci
372562306a36Sopenharmony_ci		for (i = 1; i < ioc->cpu_msix_table_sz; i++)
372662306a36Sopenharmony_ci			ioc->reply_post_host_index[i] =
372762306a36Sopenharmony_ci			(resource_size_t __iomem *)
372862306a36Sopenharmony_ci			((u8 __iomem *)&ioc->chip->Doorbell + (0x4000 + ((i - 1)
372962306a36Sopenharmony_ci			* 4)));
373062306a36Sopenharmony_ci	}
373162306a36Sopenharmony_ci
373262306a36Sopenharmony_ci	list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
373362306a36Sopenharmony_ci		if (reply_q->msix_index >= ioc->iopoll_q_start_index) {
373462306a36Sopenharmony_ci			pr_info("%s: enabled: index: %d\n",
373562306a36Sopenharmony_ci			    reply_q->name, reply_q->msix_index);
373662306a36Sopenharmony_ci			continue;
373762306a36Sopenharmony_ci		}
373862306a36Sopenharmony_ci
373962306a36Sopenharmony_ci		pr_info("%s: %s enabled: IRQ %d\n",
374062306a36Sopenharmony_ci			reply_q->name,
374162306a36Sopenharmony_ci			ioc->msix_enable ? "PCI-MSI-X" : "IO-APIC",
374262306a36Sopenharmony_ci			pci_irq_vector(ioc->pdev, reply_q->msix_index));
374362306a36Sopenharmony_ci	}
374462306a36Sopenharmony_ci
374562306a36Sopenharmony_ci	ioc_info(ioc, "iomem(%pap), mapped(0x%p), size(%d)\n",
374662306a36Sopenharmony_ci		 &chip_phys, ioc->chip, memap_sz);
374762306a36Sopenharmony_ci	ioc_info(ioc, "ioport(0x%016llx), size(%d)\n",
374862306a36Sopenharmony_ci		 (unsigned long long)pio_chip, pio_sz);
374962306a36Sopenharmony_ci
375062306a36Sopenharmony_ci	/* Save PCI configuration state for recovery from PCI AER/EEH errors */
375162306a36Sopenharmony_ci	pci_save_state(pdev);
375262306a36Sopenharmony_ci	return 0;
375362306a36Sopenharmony_ci
375462306a36Sopenharmony_ci out_fail:
375562306a36Sopenharmony_ci	mpt3sas_base_unmap_resources(ioc);
375662306a36Sopenharmony_ci	return r;
375762306a36Sopenharmony_ci}
375862306a36Sopenharmony_ci
375962306a36Sopenharmony_ci/**
376062306a36Sopenharmony_ci * mpt3sas_base_get_msg_frame - obtain request mf pointer
376162306a36Sopenharmony_ci * @ioc: per adapter object
376262306a36Sopenharmony_ci * @smid: system request message index(smid zero is invalid)
376362306a36Sopenharmony_ci *
376462306a36Sopenharmony_ci * Return: virt pointer to message frame.
376562306a36Sopenharmony_ci */
376662306a36Sopenharmony_civoid *
376762306a36Sopenharmony_cimpt3sas_base_get_msg_frame(struct MPT3SAS_ADAPTER *ioc, u16 smid)
376862306a36Sopenharmony_ci{
376962306a36Sopenharmony_ci	return (void *)(ioc->request + (smid * ioc->request_sz));
377062306a36Sopenharmony_ci}
377162306a36Sopenharmony_ci
377262306a36Sopenharmony_ci/**
377362306a36Sopenharmony_ci * mpt3sas_base_get_sense_buffer - obtain a sense buffer virt addr
377462306a36Sopenharmony_ci * @ioc: per adapter object
377562306a36Sopenharmony_ci * @smid: system request message index
377662306a36Sopenharmony_ci *
377762306a36Sopenharmony_ci * Return: virt pointer to sense buffer.
377862306a36Sopenharmony_ci */
377962306a36Sopenharmony_civoid *
378062306a36Sopenharmony_cimpt3sas_base_get_sense_buffer(struct MPT3SAS_ADAPTER *ioc, u16 smid)
378162306a36Sopenharmony_ci{
378262306a36Sopenharmony_ci	return (void *)(ioc->sense + ((smid - 1) * SCSI_SENSE_BUFFERSIZE));
378362306a36Sopenharmony_ci}
378462306a36Sopenharmony_ci
378562306a36Sopenharmony_ci/**
378662306a36Sopenharmony_ci * mpt3sas_base_get_sense_buffer_dma - obtain a sense buffer dma addr
378762306a36Sopenharmony_ci * @ioc: per adapter object
378862306a36Sopenharmony_ci * @smid: system request message index
378962306a36Sopenharmony_ci *
379062306a36Sopenharmony_ci * Return: phys pointer to the low 32bit address of the sense buffer.
379162306a36Sopenharmony_ci */
379262306a36Sopenharmony_ci__le32
379362306a36Sopenharmony_cimpt3sas_base_get_sense_buffer_dma(struct MPT3SAS_ADAPTER *ioc, u16 smid)
379462306a36Sopenharmony_ci{
379562306a36Sopenharmony_ci	return cpu_to_le32(ioc->sense_dma + ((smid - 1) *
379662306a36Sopenharmony_ci	    SCSI_SENSE_BUFFERSIZE));
379762306a36Sopenharmony_ci}
379862306a36Sopenharmony_ci
379962306a36Sopenharmony_ci/**
380062306a36Sopenharmony_ci * mpt3sas_base_get_pcie_sgl - obtain a PCIe SGL virt addr
380162306a36Sopenharmony_ci * @ioc: per adapter object
380262306a36Sopenharmony_ci * @smid: system request message index
380362306a36Sopenharmony_ci *
380462306a36Sopenharmony_ci * Return: virt pointer to a PCIe SGL.
380562306a36Sopenharmony_ci */
380662306a36Sopenharmony_civoid *
380762306a36Sopenharmony_cimpt3sas_base_get_pcie_sgl(struct MPT3SAS_ADAPTER *ioc, u16 smid)
380862306a36Sopenharmony_ci{
380962306a36Sopenharmony_ci	return (void *)(ioc->pcie_sg_lookup[smid - 1].pcie_sgl);
381062306a36Sopenharmony_ci}
381162306a36Sopenharmony_ci
381262306a36Sopenharmony_ci/**
381362306a36Sopenharmony_ci * mpt3sas_base_get_pcie_sgl_dma - obtain a PCIe SGL dma addr
381462306a36Sopenharmony_ci * @ioc: per adapter object
381562306a36Sopenharmony_ci * @smid: system request message index
381662306a36Sopenharmony_ci *
381762306a36Sopenharmony_ci * Return: phys pointer to the address of the PCIe buffer.
381862306a36Sopenharmony_ci */
381962306a36Sopenharmony_cidma_addr_t
382062306a36Sopenharmony_cimpt3sas_base_get_pcie_sgl_dma(struct MPT3SAS_ADAPTER *ioc, u16 smid)
382162306a36Sopenharmony_ci{
382262306a36Sopenharmony_ci	return ioc->pcie_sg_lookup[smid - 1].pcie_sgl_dma;
382362306a36Sopenharmony_ci}
382462306a36Sopenharmony_ci
382562306a36Sopenharmony_ci/**
382662306a36Sopenharmony_ci * mpt3sas_base_get_reply_virt_addr - obtain reply frames virt address
382762306a36Sopenharmony_ci * @ioc: per adapter object
382862306a36Sopenharmony_ci * @phys_addr: lower 32 physical addr of the reply
382962306a36Sopenharmony_ci *
383062306a36Sopenharmony_ci * Converts 32bit lower physical addr into a virt address.
383162306a36Sopenharmony_ci */
383262306a36Sopenharmony_civoid *
383362306a36Sopenharmony_cimpt3sas_base_get_reply_virt_addr(struct MPT3SAS_ADAPTER *ioc, u32 phys_addr)
383462306a36Sopenharmony_ci{
383562306a36Sopenharmony_ci	if (!phys_addr)
383662306a36Sopenharmony_ci		return NULL;
383762306a36Sopenharmony_ci	return ioc->reply + (phys_addr - (u32)ioc->reply_dma);
383862306a36Sopenharmony_ci}
383962306a36Sopenharmony_ci
384062306a36Sopenharmony_ci/**
384162306a36Sopenharmony_ci * _base_get_msix_index - get the msix index
384262306a36Sopenharmony_ci * @ioc: per adapter object
384362306a36Sopenharmony_ci * @scmd: scsi_cmnd object
384462306a36Sopenharmony_ci *
384562306a36Sopenharmony_ci * Return: msix index of general reply queues,
384662306a36Sopenharmony_ci * i.e. reply queue on which IO request's reply
384762306a36Sopenharmony_ci * should be posted by the HBA firmware.
384862306a36Sopenharmony_ci */
384962306a36Sopenharmony_cistatic inline u8
385062306a36Sopenharmony_ci_base_get_msix_index(struct MPT3SAS_ADAPTER *ioc,
385162306a36Sopenharmony_ci	struct scsi_cmnd *scmd)
385262306a36Sopenharmony_ci{
385362306a36Sopenharmony_ci	/* Enables reply_queue load balancing */
385462306a36Sopenharmony_ci	if (ioc->msix_load_balance)
385562306a36Sopenharmony_ci		return ioc->reply_queue_count ?
385662306a36Sopenharmony_ci		    base_mod64(atomic64_add_return(1,
385762306a36Sopenharmony_ci		    &ioc->total_io_cnt), ioc->reply_queue_count) : 0;
385862306a36Sopenharmony_ci
385962306a36Sopenharmony_ci	if (scmd && ioc->shost->nr_hw_queues > 1) {
386062306a36Sopenharmony_ci		u32 tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd));
386162306a36Sopenharmony_ci
386262306a36Sopenharmony_ci		return blk_mq_unique_tag_to_hwq(tag) +
386362306a36Sopenharmony_ci			ioc->high_iops_queues;
386462306a36Sopenharmony_ci	}
386562306a36Sopenharmony_ci
386662306a36Sopenharmony_ci	return ioc->cpu_msix_table[raw_smp_processor_id()];
386762306a36Sopenharmony_ci}
386862306a36Sopenharmony_ci
386962306a36Sopenharmony_ci/**
387062306a36Sopenharmony_ci * _base_get_high_iops_msix_index - get the msix index of
387162306a36Sopenharmony_ci *				high iops queues
387262306a36Sopenharmony_ci * @ioc: per adapter object
387362306a36Sopenharmony_ci * @scmd: scsi_cmnd object
387462306a36Sopenharmony_ci *
387562306a36Sopenharmony_ci * Return: msix index of high iops reply queues.
387662306a36Sopenharmony_ci * i.e. high iops reply queue on which IO request's
387762306a36Sopenharmony_ci * reply should be posted by the HBA firmware.
387862306a36Sopenharmony_ci */
387962306a36Sopenharmony_cistatic inline u8
388062306a36Sopenharmony_ci_base_get_high_iops_msix_index(struct MPT3SAS_ADAPTER *ioc,
388162306a36Sopenharmony_ci	struct scsi_cmnd *scmd)
388262306a36Sopenharmony_ci{
388362306a36Sopenharmony_ci	/**
388462306a36Sopenharmony_ci	 * Round robin the IO interrupts among the high iops
388562306a36Sopenharmony_ci	 * reply queues in terms of batch count 16 when outstanding
388662306a36Sopenharmony_ci	 * IOs on the target device is >=8.
388762306a36Sopenharmony_ci	 */
388862306a36Sopenharmony_ci
388962306a36Sopenharmony_ci	if (scsi_device_busy(scmd->device) > MPT3SAS_DEVICE_HIGH_IOPS_DEPTH)
389062306a36Sopenharmony_ci		return base_mod64((
389162306a36Sopenharmony_ci		    atomic64_add_return(1, &ioc->high_iops_outstanding) /
389262306a36Sopenharmony_ci		    MPT3SAS_HIGH_IOPS_BATCH_COUNT),
389362306a36Sopenharmony_ci		    MPT3SAS_HIGH_IOPS_REPLY_QUEUES);
389462306a36Sopenharmony_ci
389562306a36Sopenharmony_ci	return _base_get_msix_index(ioc, scmd);
389662306a36Sopenharmony_ci}
389762306a36Sopenharmony_ci
389862306a36Sopenharmony_ci/**
389962306a36Sopenharmony_ci * mpt3sas_base_get_smid - obtain a free smid from internal queue
390062306a36Sopenharmony_ci * @ioc: per adapter object
390162306a36Sopenharmony_ci * @cb_idx: callback index
390262306a36Sopenharmony_ci *
390362306a36Sopenharmony_ci * Return: smid (zero is invalid)
390462306a36Sopenharmony_ci */
390562306a36Sopenharmony_ciu16
390662306a36Sopenharmony_cimpt3sas_base_get_smid(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx)
390762306a36Sopenharmony_ci{
390862306a36Sopenharmony_ci	unsigned long flags;
390962306a36Sopenharmony_ci	struct request_tracker *request;
391062306a36Sopenharmony_ci	u16 smid;
391162306a36Sopenharmony_ci
391262306a36Sopenharmony_ci	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
391362306a36Sopenharmony_ci	if (list_empty(&ioc->internal_free_list)) {
391462306a36Sopenharmony_ci		spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
391562306a36Sopenharmony_ci		ioc_err(ioc, "%s: smid not available\n", __func__);
391662306a36Sopenharmony_ci		return 0;
391762306a36Sopenharmony_ci	}
391862306a36Sopenharmony_ci
391962306a36Sopenharmony_ci	request = list_entry(ioc->internal_free_list.next,
392062306a36Sopenharmony_ci	    struct request_tracker, tracker_list);
392162306a36Sopenharmony_ci	request->cb_idx = cb_idx;
392262306a36Sopenharmony_ci	smid = request->smid;
392362306a36Sopenharmony_ci	list_del(&request->tracker_list);
392462306a36Sopenharmony_ci	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
392562306a36Sopenharmony_ci	return smid;
392662306a36Sopenharmony_ci}
392762306a36Sopenharmony_ci
392862306a36Sopenharmony_ci/**
392962306a36Sopenharmony_ci * mpt3sas_base_get_smid_scsiio - obtain a free smid from scsiio queue
393062306a36Sopenharmony_ci * @ioc: per adapter object
393162306a36Sopenharmony_ci * @cb_idx: callback index
393262306a36Sopenharmony_ci * @scmd: pointer to scsi command object
393362306a36Sopenharmony_ci *
393462306a36Sopenharmony_ci * Return: smid (zero is invalid)
393562306a36Sopenharmony_ci */
393662306a36Sopenharmony_ciu16
393762306a36Sopenharmony_cimpt3sas_base_get_smid_scsiio(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx,
393862306a36Sopenharmony_ci	struct scsi_cmnd *scmd)
393962306a36Sopenharmony_ci{
394062306a36Sopenharmony_ci	struct scsiio_tracker *request = scsi_cmd_priv(scmd);
394162306a36Sopenharmony_ci	u16 smid;
394262306a36Sopenharmony_ci	u32 tag, unique_tag;
394362306a36Sopenharmony_ci
394462306a36Sopenharmony_ci	unique_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd));
394562306a36Sopenharmony_ci	tag = blk_mq_unique_tag_to_tag(unique_tag);
394662306a36Sopenharmony_ci
394762306a36Sopenharmony_ci	/*
394862306a36Sopenharmony_ci	 * Store hw queue number corresponding to the tag.
394962306a36Sopenharmony_ci	 * This hw queue number is used later to determine
395062306a36Sopenharmony_ci	 * the unique_tag using the logic below. This unique_tag
395162306a36Sopenharmony_ci	 * is used to retrieve the scmd pointer corresponding
395262306a36Sopenharmony_ci	 * to tag using scsi_host_find_tag() API.
395362306a36Sopenharmony_ci	 *
395462306a36Sopenharmony_ci	 * tag = smid - 1;
395562306a36Sopenharmony_ci	 * unique_tag = ioc->io_queue_num[tag] << BLK_MQ_UNIQUE_TAG_BITS | tag;
395662306a36Sopenharmony_ci	 */
395762306a36Sopenharmony_ci	ioc->io_queue_num[tag] = blk_mq_unique_tag_to_hwq(unique_tag);
395862306a36Sopenharmony_ci
395962306a36Sopenharmony_ci	smid = tag + 1;
396062306a36Sopenharmony_ci	request->cb_idx = cb_idx;
396162306a36Sopenharmony_ci	request->smid = smid;
396262306a36Sopenharmony_ci	request->scmd = scmd;
396362306a36Sopenharmony_ci	INIT_LIST_HEAD(&request->chain_list);
396462306a36Sopenharmony_ci	return smid;
396562306a36Sopenharmony_ci}
396662306a36Sopenharmony_ci
396762306a36Sopenharmony_ci/**
396862306a36Sopenharmony_ci * mpt3sas_base_get_smid_hpr - obtain a free smid from hi-priority queue
396962306a36Sopenharmony_ci * @ioc: per adapter object
397062306a36Sopenharmony_ci * @cb_idx: callback index
397162306a36Sopenharmony_ci *
397262306a36Sopenharmony_ci * Return: smid (zero is invalid)
397362306a36Sopenharmony_ci */
397462306a36Sopenharmony_ciu16
397562306a36Sopenharmony_cimpt3sas_base_get_smid_hpr(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx)
397662306a36Sopenharmony_ci{
397762306a36Sopenharmony_ci	unsigned long flags;
397862306a36Sopenharmony_ci	struct request_tracker *request;
397962306a36Sopenharmony_ci	u16 smid;
398062306a36Sopenharmony_ci
398162306a36Sopenharmony_ci	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
398262306a36Sopenharmony_ci	if (list_empty(&ioc->hpr_free_list)) {
398362306a36Sopenharmony_ci		spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
398462306a36Sopenharmony_ci		return 0;
398562306a36Sopenharmony_ci	}
398662306a36Sopenharmony_ci
398762306a36Sopenharmony_ci	request = list_entry(ioc->hpr_free_list.next,
398862306a36Sopenharmony_ci	    struct request_tracker, tracker_list);
398962306a36Sopenharmony_ci	request->cb_idx = cb_idx;
399062306a36Sopenharmony_ci	smid = request->smid;
399162306a36Sopenharmony_ci	list_del(&request->tracker_list);
399262306a36Sopenharmony_ci	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
399362306a36Sopenharmony_ci	return smid;
399462306a36Sopenharmony_ci}
399562306a36Sopenharmony_ci
399662306a36Sopenharmony_cistatic void
399762306a36Sopenharmony_ci_base_recovery_check(struct MPT3SAS_ADAPTER *ioc)
399862306a36Sopenharmony_ci{
399962306a36Sopenharmony_ci	/*
400062306a36Sopenharmony_ci	 * See _wait_for_commands_to_complete() call with regards to this code.
400162306a36Sopenharmony_ci	 */
400262306a36Sopenharmony_ci	if (ioc->shost_recovery && ioc->pending_io_count) {
400362306a36Sopenharmony_ci		ioc->pending_io_count = scsi_host_busy(ioc->shost);
400462306a36Sopenharmony_ci		if (ioc->pending_io_count == 0)
400562306a36Sopenharmony_ci			wake_up(&ioc->reset_wq);
400662306a36Sopenharmony_ci	}
400762306a36Sopenharmony_ci}
400862306a36Sopenharmony_ci
400962306a36Sopenharmony_civoid mpt3sas_base_clear_st(struct MPT3SAS_ADAPTER *ioc,
401062306a36Sopenharmony_ci			   struct scsiio_tracker *st)
401162306a36Sopenharmony_ci{
401262306a36Sopenharmony_ci	if (WARN_ON(st->smid == 0))
401362306a36Sopenharmony_ci		return;
401462306a36Sopenharmony_ci	st->cb_idx = 0xFF;
401562306a36Sopenharmony_ci	st->direct_io = 0;
401662306a36Sopenharmony_ci	st->scmd = NULL;
401762306a36Sopenharmony_ci	atomic_set(&ioc->chain_lookup[st->smid - 1].chain_offset, 0);
401862306a36Sopenharmony_ci	st->smid = 0;
401962306a36Sopenharmony_ci}
402062306a36Sopenharmony_ci
402162306a36Sopenharmony_ci/**
402262306a36Sopenharmony_ci * mpt3sas_base_free_smid - put smid back on free_list
402362306a36Sopenharmony_ci * @ioc: per adapter object
402462306a36Sopenharmony_ci * @smid: system request message index
402562306a36Sopenharmony_ci */
402662306a36Sopenharmony_civoid
402762306a36Sopenharmony_cimpt3sas_base_free_smid(struct MPT3SAS_ADAPTER *ioc, u16 smid)
402862306a36Sopenharmony_ci{
402962306a36Sopenharmony_ci	unsigned long flags;
403062306a36Sopenharmony_ci	int i;
403162306a36Sopenharmony_ci
403262306a36Sopenharmony_ci	if (smid < ioc->hi_priority_smid) {
403362306a36Sopenharmony_ci		struct scsiio_tracker *st;
403462306a36Sopenharmony_ci		void *request;
403562306a36Sopenharmony_ci
403662306a36Sopenharmony_ci		st = _get_st_from_smid(ioc, smid);
403762306a36Sopenharmony_ci		if (!st) {
403862306a36Sopenharmony_ci			_base_recovery_check(ioc);
403962306a36Sopenharmony_ci			return;
404062306a36Sopenharmony_ci		}
404162306a36Sopenharmony_ci
404262306a36Sopenharmony_ci		/* Clear MPI request frame */
404362306a36Sopenharmony_ci		request = mpt3sas_base_get_msg_frame(ioc, smid);
404462306a36Sopenharmony_ci		memset(request, 0, ioc->request_sz);
404562306a36Sopenharmony_ci
404662306a36Sopenharmony_ci		mpt3sas_base_clear_st(ioc, st);
404762306a36Sopenharmony_ci		_base_recovery_check(ioc);
404862306a36Sopenharmony_ci		ioc->io_queue_num[smid - 1] = 0;
404962306a36Sopenharmony_ci		return;
405062306a36Sopenharmony_ci	}
405162306a36Sopenharmony_ci
405262306a36Sopenharmony_ci	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
405362306a36Sopenharmony_ci	if (smid < ioc->internal_smid) {
405462306a36Sopenharmony_ci		/* hi-priority */
405562306a36Sopenharmony_ci		i = smid - ioc->hi_priority_smid;
405662306a36Sopenharmony_ci		ioc->hpr_lookup[i].cb_idx = 0xFF;
405762306a36Sopenharmony_ci		list_add(&ioc->hpr_lookup[i].tracker_list, &ioc->hpr_free_list);
405862306a36Sopenharmony_ci	} else if (smid <= ioc->hba_queue_depth) {
405962306a36Sopenharmony_ci		/* internal queue */
406062306a36Sopenharmony_ci		i = smid - ioc->internal_smid;
406162306a36Sopenharmony_ci		ioc->internal_lookup[i].cb_idx = 0xFF;
406262306a36Sopenharmony_ci		list_add(&ioc->internal_lookup[i].tracker_list,
406362306a36Sopenharmony_ci		    &ioc->internal_free_list);
406462306a36Sopenharmony_ci	}
406562306a36Sopenharmony_ci	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
406662306a36Sopenharmony_ci}
406762306a36Sopenharmony_ci
406862306a36Sopenharmony_ci/**
406962306a36Sopenharmony_ci * _base_mpi_ep_writeq - 32 bit write to MMIO
407062306a36Sopenharmony_ci * @b: data payload
407162306a36Sopenharmony_ci * @addr: address in MMIO space
407262306a36Sopenharmony_ci * @writeq_lock: spin lock
407362306a36Sopenharmony_ci *
407462306a36Sopenharmony_ci * This special handling for MPI EP to take care of 32 bit
407562306a36Sopenharmony_ci * environment where its not quarenteed to send the entire word
407662306a36Sopenharmony_ci * in one transfer.
407762306a36Sopenharmony_ci */
407862306a36Sopenharmony_cistatic inline void
407962306a36Sopenharmony_ci_base_mpi_ep_writeq(__u64 b, volatile void __iomem *addr,
408062306a36Sopenharmony_ci					spinlock_t *writeq_lock)
408162306a36Sopenharmony_ci{
408262306a36Sopenharmony_ci	unsigned long flags;
408362306a36Sopenharmony_ci
408462306a36Sopenharmony_ci	spin_lock_irqsave(writeq_lock, flags);
408562306a36Sopenharmony_ci	__raw_writel((u32)(b), addr);
408662306a36Sopenharmony_ci	__raw_writel((u32)(b >> 32), (addr + 4));
408762306a36Sopenharmony_ci	spin_unlock_irqrestore(writeq_lock, flags);
408862306a36Sopenharmony_ci}
408962306a36Sopenharmony_ci
409062306a36Sopenharmony_ci/**
409162306a36Sopenharmony_ci * _base_writeq - 64 bit write to MMIO
409262306a36Sopenharmony_ci * @b: data payload
409362306a36Sopenharmony_ci * @addr: address in MMIO space
409462306a36Sopenharmony_ci * @writeq_lock: spin lock
409562306a36Sopenharmony_ci *
409662306a36Sopenharmony_ci * Glue for handling an atomic 64 bit word to MMIO. This special handling takes
409762306a36Sopenharmony_ci * care of 32 bit environment where its not quarenteed to send the entire word
409862306a36Sopenharmony_ci * in one transfer.
409962306a36Sopenharmony_ci */
410062306a36Sopenharmony_ci#if defined(writeq) && defined(CONFIG_64BIT)
410162306a36Sopenharmony_cistatic inline void
410262306a36Sopenharmony_ci_base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock)
410362306a36Sopenharmony_ci{
410462306a36Sopenharmony_ci	wmb();
410562306a36Sopenharmony_ci	__raw_writeq(b, addr);
410662306a36Sopenharmony_ci	barrier();
410762306a36Sopenharmony_ci}
410862306a36Sopenharmony_ci#else
410962306a36Sopenharmony_cistatic inline void
411062306a36Sopenharmony_ci_base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock)
411162306a36Sopenharmony_ci{
411262306a36Sopenharmony_ci	_base_mpi_ep_writeq(b, addr, writeq_lock);
411362306a36Sopenharmony_ci}
411462306a36Sopenharmony_ci#endif
411562306a36Sopenharmony_ci
411662306a36Sopenharmony_ci/**
411762306a36Sopenharmony_ci * _base_set_and_get_msix_index - get the msix index and assign to msix_io
411862306a36Sopenharmony_ci *                                variable of scsi tracker
411962306a36Sopenharmony_ci * @ioc: per adapter object
412062306a36Sopenharmony_ci * @smid: system request message index
412162306a36Sopenharmony_ci *
412262306a36Sopenharmony_ci * Return: msix index.
412362306a36Sopenharmony_ci */
412462306a36Sopenharmony_cistatic u8
412562306a36Sopenharmony_ci_base_set_and_get_msix_index(struct MPT3SAS_ADAPTER *ioc, u16 smid)
412662306a36Sopenharmony_ci{
412762306a36Sopenharmony_ci	struct scsiio_tracker *st = NULL;
412862306a36Sopenharmony_ci
412962306a36Sopenharmony_ci	if (smid < ioc->hi_priority_smid)
413062306a36Sopenharmony_ci		st = _get_st_from_smid(ioc, smid);
413162306a36Sopenharmony_ci
413262306a36Sopenharmony_ci	if (st == NULL)
413362306a36Sopenharmony_ci		return  _base_get_msix_index(ioc, NULL);
413462306a36Sopenharmony_ci
413562306a36Sopenharmony_ci	st->msix_io = ioc->get_msix_index_for_smlio(ioc, st->scmd);
413662306a36Sopenharmony_ci	return st->msix_io;
413762306a36Sopenharmony_ci}
413862306a36Sopenharmony_ci
413962306a36Sopenharmony_ci/**
414062306a36Sopenharmony_ci * _base_put_smid_mpi_ep_scsi_io - send SCSI_IO request to firmware
414162306a36Sopenharmony_ci * @ioc: per adapter object
414262306a36Sopenharmony_ci * @smid: system request message index
414362306a36Sopenharmony_ci * @handle: device handle
414462306a36Sopenharmony_ci */
414562306a36Sopenharmony_cistatic void
414662306a36Sopenharmony_ci_base_put_smid_mpi_ep_scsi_io(struct MPT3SAS_ADAPTER *ioc,
414762306a36Sopenharmony_ci	u16 smid, u16 handle)
414862306a36Sopenharmony_ci{
414962306a36Sopenharmony_ci	Mpi2RequestDescriptorUnion_t descriptor;
415062306a36Sopenharmony_ci	u64 *request = (u64 *)&descriptor;
415162306a36Sopenharmony_ci	void *mpi_req_iomem;
415262306a36Sopenharmony_ci	__le32 *mfp = (__le32 *)mpt3sas_base_get_msg_frame(ioc, smid);
415362306a36Sopenharmony_ci
415462306a36Sopenharmony_ci	_clone_sg_entries(ioc, (void *) mfp, smid);
415562306a36Sopenharmony_ci	mpi_req_iomem = (void __force *)ioc->chip +
415662306a36Sopenharmony_ci			MPI_FRAME_START_OFFSET + (smid * ioc->request_sz);
415762306a36Sopenharmony_ci	_base_clone_mpi_to_sys_mem(mpi_req_iomem, (void *)mfp,
415862306a36Sopenharmony_ci					ioc->request_sz);
415962306a36Sopenharmony_ci	descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
416062306a36Sopenharmony_ci	descriptor.SCSIIO.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
416162306a36Sopenharmony_ci	descriptor.SCSIIO.SMID = cpu_to_le16(smid);
416262306a36Sopenharmony_ci	descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);
416362306a36Sopenharmony_ci	descriptor.SCSIIO.LMID = 0;
416462306a36Sopenharmony_ci	_base_mpi_ep_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
416562306a36Sopenharmony_ci	    &ioc->scsi_lookup_lock);
416662306a36Sopenharmony_ci}
416762306a36Sopenharmony_ci
416862306a36Sopenharmony_ci/**
416962306a36Sopenharmony_ci * _base_put_smid_scsi_io - send SCSI_IO request to firmware
417062306a36Sopenharmony_ci * @ioc: per adapter object
417162306a36Sopenharmony_ci * @smid: system request message index
417262306a36Sopenharmony_ci * @handle: device handle
417362306a36Sopenharmony_ci */
417462306a36Sopenharmony_cistatic void
417562306a36Sopenharmony_ci_base_put_smid_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle)
417662306a36Sopenharmony_ci{
417762306a36Sopenharmony_ci	Mpi2RequestDescriptorUnion_t descriptor;
417862306a36Sopenharmony_ci	u64 *request = (u64 *)&descriptor;
417962306a36Sopenharmony_ci
418062306a36Sopenharmony_ci
418162306a36Sopenharmony_ci	descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
418262306a36Sopenharmony_ci	descriptor.SCSIIO.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
418362306a36Sopenharmony_ci	descriptor.SCSIIO.SMID = cpu_to_le16(smid);
418462306a36Sopenharmony_ci	descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);
418562306a36Sopenharmony_ci	descriptor.SCSIIO.LMID = 0;
418662306a36Sopenharmony_ci	_base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
418762306a36Sopenharmony_ci	    &ioc->scsi_lookup_lock);
418862306a36Sopenharmony_ci}
418962306a36Sopenharmony_ci
419062306a36Sopenharmony_ci/**
419162306a36Sopenharmony_ci * _base_put_smid_fast_path - send fast path request to firmware
419262306a36Sopenharmony_ci * @ioc: per adapter object
419362306a36Sopenharmony_ci * @smid: system request message index
419462306a36Sopenharmony_ci * @handle: device handle
419562306a36Sopenharmony_ci */
419662306a36Sopenharmony_cistatic void
419762306a36Sopenharmony_ci_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
419862306a36Sopenharmony_ci	u16 handle)
419962306a36Sopenharmony_ci{
420062306a36Sopenharmony_ci	Mpi2RequestDescriptorUnion_t descriptor;
420162306a36Sopenharmony_ci	u64 *request = (u64 *)&descriptor;
420262306a36Sopenharmony_ci
420362306a36Sopenharmony_ci	descriptor.SCSIIO.RequestFlags =
420462306a36Sopenharmony_ci	    MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
420562306a36Sopenharmony_ci	descriptor.SCSIIO.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
420662306a36Sopenharmony_ci	descriptor.SCSIIO.SMID = cpu_to_le16(smid);
420762306a36Sopenharmony_ci	descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);
420862306a36Sopenharmony_ci	descriptor.SCSIIO.LMID = 0;
420962306a36Sopenharmony_ci	_base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
421062306a36Sopenharmony_ci	    &ioc->scsi_lookup_lock);
421162306a36Sopenharmony_ci}
421262306a36Sopenharmony_ci
421362306a36Sopenharmony_ci/**
421462306a36Sopenharmony_ci * _base_put_smid_hi_priority - send Task Management request to firmware
421562306a36Sopenharmony_ci * @ioc: per adapter object
421662306a36Sopenharmony_ci * @smid: system request message index
421762306a36Sopenharmony_ci * @msix_task: msix_task will be same as msix of IO in case of task abort else 0
421862306a36Sopenharmony_ci */
421962306a36Sopenharmony_cistatic void
422062306a36Sopenharmony_ci_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid,
422162306a36Sopenharmony_ci	u16 msix_task)
422262306a36Sopenharmony_ci{
422362306a36Sopenharmony_ci	Mpi2RequestDescriptorUnion_t descriptor;
422462306a36Sopenharmony_ci	void *mpi_req_iomem;
422562306a36Sopenharmony_ci	u64 *request;
422662306a36Sopenharmony_ci
422762306a36Sopenharmony_ci	if (ioc->is_mcpu_endpoint) {
422862306a36Sopenharmony_ci		__le32 *mfp = (__le32 *)mpt3sas_base_get_msg_frame(ioc, smid);
422962306a36Sopenharmony_ci
423062306a36Sopenharmony_ci		/* TBD 256 is offset within sys register. */
423162306a36Sopenharmony_ci		mpi_req_iomem = (void __force *)ioc->chip
423262306a36Sopenharmony_ci					+ MPI_FRAME_START_OFFSET
423362306a36Sopenharmony_ci					+ (smid * ioc->request_sz);
423462306a36Sopenharmony_ci		_base_clone_mpi_to_sys_mem(mpi_req_iomem, (void *)mfp,
423562306a36Sopenharmony_ci							ioc->request_sz);
423662306a36Sopenharmony_ci	}
423762306a36Sopenharmony_ci
423862306a36Sopenharmony_ci	request = (u64 *)&descriptor;
423962306a36Sopenharmony_ci
424062306a36Sopenharmony_ci	descriptor.HighPriority.RequestFlags =
424162306a36Sopenharmony_ci	    MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
424262306a36Sopenharmony_ci	descriptor.HighPriority.MSIxIndex =  msix_task;
424362306a36Sopenharmony_ci	descriptor.HighPriority.SMID = cpu_to_le16(smid);
424462306a36Sopenharmony_ci	descriptor.HighPriority.LMID = 0;
424562306a36Sopenharmony_ci	descriptor.HighPriority.Reserved1 = 0;
424662306a36Sopenharmony_ci	if (ioc->is_mcpu_endpoint)
424762306a36Sopenharmony_ci		_base_mpi_ep_writeq(*request,
424862306a36Sopenharmony_ci				&ioc->chip->RequestDescriptorPostLow,
424962306a36Sopenharmony_ci				&ioc->scsi_lookup_lock);
425062306a36Sopenharmony_ci	else
425162306a36Sopenharmony_ci		_base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
425262306a36Sopenharmony_ci		    &ioc->scsi_lookup_lock);
425362306a36Sopenharmony_ci}
425462306a36Sopenharmony_ci
425562306a36Sopenharmony_ci/**
425662306a36Sopenharmony_ci * mpt3sas_base_put_smid_nvme_encap - send NVMe encapsulated request to
425762306a36Sopenharmony_ci *  firmware
425862306a36Sopenharmony_ci * @ioc: per adapter object
425962306a36Sopenharmony_ci * @smid: system request message index
426062306a36Sopenharmony_ci */
426162306a36Sopenharmony_civoid
426262306a36Sopenharmony_cimpt3sas_base_put_smid_nvme_encap(struct MPT3SAS_ADAPTER *ioc, u16 smid)
426362306a36Sopenharmony_ci{
426462306a36Sopenharmony_ci	Mpi2RequestDescriptorUnion_t descriptor;
426562306a36Sopenharmony_ci	u64 *request = (u64 *)&descriptor;
426662306a36Sopenharmony_ci
426762306a36Sopenharmony_ci	descriptor.Default.RequestFlags =
426862306a36Sopenharmony_ci		MPI26_REQ_DESCRIPT_FLAGS_PCIE_ENCAPSULATED;
426962306a36Sopenharmony_ci	descriptor.Default.MSIxIndex =  _base_set_and_get_msix_index(ioc, smid);
427062306a36Sopenharmony_ci	descriptor.Default.SMID = cpu_to_le16(smid);
427162306a36Sopenharmony_ci	descriptor.Default.LMID = 0;
427262306a36Sopenharmony_ci	descriptor.Default.DescriptorTypeDependent = 0;
427362306a36Sopenharmony_ci	_base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
427462306a36Sopenharmony_ci	    &ioc->scsi_lookup_lock);
427562306a36Sopenharmony_ci}
427662306a36Sopenharmony_ci
427762306a36Sopenharmony_ci/**
427862306a36Sopenharmony_ci * _base_put_smid_default - Default, primarily used for config pages
427962306a36Sopenharmony_ci * @ioc: per adapter object
428062306a36Sopenharmony_ci * @smid: system request message index
428162306a36Sopenharmony_ci */
428262306a36Sopenharmony_cistatic void
428362306a36Sopenharmony_ci_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid)
428462306a36Sopenharmony_ci{
428562306a36Sopenharmony_ci	Mpi2RequestDescriptorUnion_t descriptor;
428662306a36Sopenharmony_ci	void *mpi_req_iomem;
428762306a36Sopenharmony_ci	u64 *request;
428862306a36Sopenharmony_ci
428962306a36Sopenharmony_ci	if (ioc->is_mcpu_endpoint) {
429062306a36Sopenharmony_ci		__le32 *mfp = (__le32 *)mpt3sas_base_get_msg_frame(ioc, smid);
429162306a36Sopenharmony_ci
429262306a36Sopenharmony_ci		_clone_sg_entries(ioc, (void *) mfp, smid);
429362306a36Sopenharmony_ci		/* TBD 256 is offset within sys register */
429462306a36Sopenharmony_ci		mpi_req_iomem = (void __force *)ioc->chip +
429562306a36Sopenharmony_ci			MPI_FRAME_START_OFFSET + (smid * ioc->request_sz);
429662306a36Sopenharmony_ci		_base_clone_mpi_to_sys_mem(mpi_req_iomem, (void *)mfp,
429762306a36Sopenharmony_ci							ioc->request_sz);
429862306a36Sopenharmony_ci	}
429962306a36Sopenharmony_ci	request = (u64 *)&descriptor;
430062306a36Sopenharmony_ci	descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
430162306a36Sopenharmony_ci	descriptor.Default.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
430262306a36Sopenharmony_ci	descriptor.Default.SMID = cpu_to_le16(smid);
430362306a36Sopenharmony_ci	descriptor.Default.LMID = 0;
430462306a36Sopenharmony_ci	descriptor.Default.DescriptorTypeDependent = 0;
430562306a36Sopenharmony_ci	if (ioc->is_mcpu_endpoint)
430662306a36Sopenharmony_ci		_base_mpi_ep_writeq(*request,
430762306a36Sopenharmony_ci				&ioc->chip->RequestDescriptorPostLow,
430862306a36Sopenharmony_ci				&ioc->scsi_lookup_lock);
430962306a36Sopenharmony_ci	else
431062306a36Sopenharmony_ci		_base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
431162306a36Sopenharmony_ci				&ioc->scsi_lookup_lock);
431262306a36Sopenharmony_ci}
431362306a36Sopenharmony_ci
431462306a36Sopenharmony_ci/**
431562306a36Sopenharmony_ci * _base_put_smid_scsi_io_atomic - send SCSI_IO request to firmware using
431662306a36Sopenharmony_ci *   Atomic Request Descriptor
431762306a36Sopenharmony_ci * @ioc: per adapter object
431862306a36Sopenharmony_ci * @smid: system request message index
431962306a36Sopenharmony_ci * @handle: device handle, unused in this function, for function type match
432062306a36Sopenharmony_ci *
432162306a36Sopenharmony_ci * Return: nothing.
432262306a36Sopenharmony_ci */
432362306a36Sopenharmony_cistatic void
432462306a36Sopenharmony_ci_base_put_smid_scsi_io_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid,
432562306a36Sopenharmony_ci	u16 handle)
432662306a36Sopenharmony_ci{
432762306a36Sopenharmony_ci	Mpi26AtomicRequestDescriptor_t descriptor;
432862306a36Sopenharmony_ci	u32 *request = (u32 *)&descriptor;
432962306a36Sopenharmony_ci
433062306a36Sopenharmony_ci	descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
433162306a36Sopenharmony_ci	descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
433262306a36Sopenharmony_ci	descriptor.SMID = cpu_to_le16(smid);
433362306a36Sopenharmony_ci
433462306a36Sopenharmony_ci	writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost);
433562306a36Sopenharmony_ci}
433662306a36Sopenharmony_ci
433762306a36Sopenharmony_ci/**
433862306a36Sopenharmony_ci * _base_put_smid_fast_path_atomic - send fast path request to firmware
433962306a36Sopenharmony_ci * using Atomic Request Descriptor
434062306a36Sopenharmony_ci * @ioc: per adapter object
434162306a36Sopenharmony_ci * @smid: system request message index
434262306a36Sopenharmony_ci * @handle: device handle, unused in this function, for function type match
434362306a36Sopenharmony_ci * Return: nothing
434462306a36Sopenharmony_ci */
434562306a36Sopenharmony_cistatic void
434662306a36Sopenharmony_ci_base_put_smid_fast_path_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid,
434762306a36Sopenharmony_ci	u16 handle)
434862306a36Sopenharmony_ci{
434962306a36Sopenharmony_ci	Mpi26AtomicRequestDescriptor_t descriptor;
435062306a36Sopenharmony_ci	u32 *request = (u32 *)&descriptor;
435162306a36Sopenharmony_ci
435262306a36Sopenharmony_ci	descriptor.RequestFlags = MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
435362306a36Sopenharmony_ci	descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
435462306a36Sopenharmony_ci	descriptor.SMID = cpu_to_le16(smid);
435562306a36Sopenharmony_ci
435662306a36Sopenharmony_ci	writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost);
435762306a36Sopenharmony_ci}
435862306a36Sopenharmony_ci
435962306a36Sopenharmony_ci/**
436062306a36Sopenharmony_ci * _base_put_smid_hi_priority_atomic - send Task Management request to
436162306a36Sopenharmony_ci * firmware using Atomic Request Descriptor
436262306a36Sopenharmony_ci * @ioc: per adapter object
436362306a36Sopenharmony_ci * @smid: system request message index
436462306a36Sopenharmony_ci * @msix_task: msix_task will be same as msix of IO in case of task abort else 0
436562306a36Sopenharmony_ci *
436662306a36Sopenharmony_ci * Return: nothing.
436762306a36Sopenharmony_ci */
436862306a36Sopenharmony_cistatic void
436962306a36Sopenharmony_ci_base_put_smid_hi_priority_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid,
437062306a36Sopenharmony_ci	u16 msix_task)
437162306a36Sopenharmony_ci{
437262306a36Sopenharmony_ci	Mpi26AtomicRequestDescriptor_t descriptor;
437362306a36Sopenharmony_ci	u32 *request = (u32 *)&descriptor;
437462306a36Sopenharmony_ci
437562306a36Sopenharmony_ci	descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
437662306a36Sopenharmony_ci	descriptor.MSIxIndex = msix_task;
437762306a36Sopenharmony_ci	descriptor.SMID = cpu_to_le16(smid);
437862306a36Sopenharmony_ci
437962306a36Sopenharmony_ci	writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost);
438062306a36Sopenharmony_ci}
438162306a36Sopenharmony_ci
438262306a36Sopenharmony_ci/**
438362306a36Sopenharmony_ci * _base_put_smid_default_atomic - Default, primarily used for config pages
438462306a36Sopenharmony_ci * use Atomic Request Descriptor
438562306a36Sopenharmony_ci * @ioc: per adapter object
438662306a36Sopenharmony_ci * @smid: system request message index
438762306a36Sopenharmony_ci *
438862306a36Sopenharmony_ci * Return: nothing.
438962306a36Sopenharmony_ci */
439062306a36Sopenharmony_cistatic void
439162306a36Sopenharmony_ci_base_put_smid_default_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid)
439262306a36Sopenharmony_ci{
439362306a36Sopenharmony_ci	Mpi26AtomicRequestDescriptor_t descriptor;
439462306a36Sopenharmony_ci	u32 *request = (u32 *)&descriptor;
439562306a36Sopenharmony_ci
439662306a36Sopenharmony_ci	descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
439762306a36Sopenharmony_ci	descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
439862306a36Sopenharmony_ci	descriptor.SMID = cpu_to_le16(smid);
439962306a36Sopenharmony_ci
440062306a36Sopenharmony_ci	writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost);
440162306a36Sopenharmony_ci}
440262306a36Sopenharmony_ci
440362306a36Sopenharmony_ci/**
440462306a36Sopenharmony_ci * _base_display_OEMs_branding - Display branding string
440562306a36Sopenharmony_ci * @ioc: per adapter object
440662306a36Sopenharmony_ci */
440762306a36Sopenharmony_cistatic void
440862306a36Sopenharmony_ci_base_display_OEMs_branding(struct MPT3SAS_ADAPTER *ioc)
440962306a36Sopenharmony_ci{
441062306a36Sopenharmony_ci	if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_INTEL)
441162306a36Sopenharmony_ci		return;
441262306a36Sopenharmony_ci
441362306a36Sopenharmony_ci	switch (ioc->pdev->subsystem_vendor) {
441462306a36Sopenharmony_ci	case PCI_VENDOR_ID_INTEL:
441562306a36Sopenharmony_ci		switch (ioc->pdev->device) {
441662306a36Sopenharmony_ci		case MPI2_MFGPAGE_DEVID_SAS2008:
441762306a36Sopenharmony_ci			switch (ioc->pdev->subsystem_device) {
441862306a36Sopenharmony_ci			case MPT2SAS_INTEL_RMS2LL080_SSDID:
441962306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
442062306a36Sopenharmony_ci					 MPT2SAS_INTEL_RMS2LL080_BRANDING);
442162306a36Sopenharmony_ci				break;
442262306a36Sopenharmony_ci			case MPT2SAS_INTEL_RMS2LL040_SSDID:
442362306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
442462306a36Sopenharmony_ci					 MPT2SAS_INTEL_RMS2LL040_BRANDING);
442562306a36Sopenharmony_ci				break;
442662306a36Sopenharmony_ci			case MPT2SAS_INTEL_SSD910_SSDID:
442762306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
442862306a36Sopenharmony_ci					 MPT2SAS_INTEL_SSD910_BRANDING);
442962306a36Sopenharmony_ci				break;
443062306a36Sopenharmony_ci			default:
443162306a36Sopenharmony_ci				ioc_info(ioc, "Intel(R) Controller: Subsystem ID: 0x%X\n",
443262306a36Sopenharmony_ci					 ioc->pdev->subsystem_device);
443362306a36Sopenharmony_ci				break;
443462306a36Sopenharmony_ci			}
443562306a36Sopenharmony_ci			break;
443662306a36Sopenharmony_ci		case MPI2_MFGPAGE_DEVID_SAS2308_2:
443762306a36Sopenharmony_ci			switch (ioc->pdev->subsystem_device) {
443862306a36Sopenharmony_ci			case MPT2SAS_INTEL_RS25GB008_SSDID:
443962306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
444062306a36Sopenharmony_ci					 MPT2SAS_INTEL_RS25GB008_BRANDING);
444162306a36Sopenharmony_ci				break;
444262306a36Sopenharmony_ci			case MPT2SAS_INTEL_RMS25JB080_SSDID:
444362306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
444462306a36Sopenharmony_ci					 MPT2SAS_INTEL_RMS25JB080_BRANDING);
444562306a36Sopenharmony_ci				break;
444662306a36Sopenharmony_ci			case MPT2SAS_INTEL_RMS25JB040_SSDID:
444762306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
444862306a36Sopenharmony_ci					 MPT2SAS_INTEL_RMS25JB040_BRANDING);
444962306a36Sopenharmony_ci				break;
445062306a36Sopenharmony_ci			case MPT2SAS_INTEL_RMS25KB080_SSDID:
445162306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
445262306a36Sopenharmony_ci					 MPT2SAS_INTEL_RMS25KB080_BRANDING);
445362306a36Sopenharmony_ci				break;
445462306a36Sopenharmony_ci			case MPT2SAS_INTEL_RMS25KB040_SSDID:
445562306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
445662306a36Sopenharmony_ci					 MPT2SAS_INTEL_RMS25KB040_BRANDING);
445762306a36Sopenharmony_ci				break;
445862306a36Sopenharmony_ci			case MPT2SAS_INTEL_RMS25LB040_SSDID:
445962306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
446062306a36Sopenharmony_ci					 MPT2SAS_INTEL_RMS25LB040_BRANDING);
446162306a36Sopenharmony_ci				break;
446262306a36Sopenharmony_ci			case MPT2SAS_INTEL_RMS25LB080_SSDID:
446362306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
446462306a36Sopenharmony_ci					 MPT2SAS_INTEL_RMS25LB080_BRANDING);
446562306a36Sopenharmony_ci				break;
446662306a36Sopenharmony_ci			default:
446762306a36Sopenharmony_ci				ioc_info(ioc, "Intel(R) Controller: Subsystem ID: 0x%X\n",
446862306a36Sopenharmony_ci					 ioc->pdev->subsystem_device);
446962306a36Sopenharmony_ci				break;
447062306a36Sopenharmony_ci			}
447162306a36Sopenharmony_ci			break;
447262306a36Sopenharmony_ci		case MPI25_MFGPAGE_DEVID_SAS3008:
447362306a36Sopenharmony_ci			switch (ioc->pdev->subsystem_device) {
447462306a36Sopenharmony_ci			case MPT3SAS_INTEL_RMS3JC080_SSDID:
447562306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
447662306a36Sopenharmony_ci					 MPT3SAS_INTEL_RMS3JC080_BRANDING);
447762306a36Sopenharmony_ci				break;
447862306a36Sopenharmony_ci
447962306a36Sopenharmony_ci			case MPT3SAS_INTEL_RS3GC008_SSDID:
448062306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
448162306a36Sopenharmony_ci					 MPT3SAS_INTEL_RS3GC008_BRANDING);
448262306a36Sopenharmony_ci				break;
448362306a36Sopenharmony_ci			case MPT3SAS_INTEL_RS3FC044_SSDID:
448462306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
448562306a36Sopenharmony_ci					 MPT3SAS_INTEL_RS3FC044_BRANDING);
448662306a36Sopenharmony_ci				break;
448762306a36Sopenharmony_ci			case MPT3SAS_INTEL_RS3UC080_SSDID:
448862306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
448962306a36Sopenharmony_ci					 MPT3SAS_INTEL_RS3UC080_BRANDING);
449062306a36Sopenharmony_ci				break;
449162306a36Sopenharmony_ci			default:
449262306a36Sopenharmony_ci				ioc_info(ioc, "Intel(R) Controller: Subsystem ID: 0x%X\n",
449362306a36Sopenharmony_ci					 ioc->pdev->subsystem_device);
449462306a36Sopenharmony_ci				break;
449562306a36Sopenharmony_ci			}
449662306a36Sopenharmony_ci			break;
449762306a36Sopenharmony_ci		default:
449862306a36Sopenharmony_ci			ioc_info(ioc, "Intel(R) Controller: Subsystem ID: 0x%X\n",
449962306a36Sopenharmony_ci				 ioc->pdev->subsystem_device);
450062306a36Sopenharmony_ci			break;
450162306a36Sopenharmony_ci		}
450262306a36Sopenharmony_ci		break;
450362306a36Sopenharmony_ci	case PCI_VENDOR_ID_DELL:
450462306a36Sopenharmony_ci		switch (ioc->pdev->device) {
450562306a36Sopenharmony_ci		case MPI2_MFGPAGE_DEVID_SAS2008:
450662306a36Sopenharmony_ci			switch (ioc->pdev->subsystem_device) {
450762306a36Sopenharmony_ci			case MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID:
450862306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
450962306a36Sopenharmony_ci					 MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING);
451062306a36Sopenharmony_ci				break;
451162306a36Sopenharmony_ci			case MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID:
451262306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
451362306a36Sopenharmony_ci					 MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING);
451462306a36Sopenharmony_ci				break;
451562306a36Sopenharmony_ci			case MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID:
451662306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
451762306a36Sopenharmony_ci					 MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING);
451862306a36Sopenharmony_ci				break;
451962306a36Sopenharmony_ci			case MPT2SAS_DELL_PERC_H200_MODULAR_SSDID:
452062306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
452162306a36Sopenharmony_ci					 MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING);
452262306a36Sopenharmony_ci				break;
452362306a36Sopenharmony_ci			case MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID:
452462306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
452562306a36Sopenharmony_ci					 MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING);
452662306a36Sopenharmony_ci				break;
452762306a36Sopenharmony_ci			case MPT2SAS_DELL_PERC_H200_SSDID:
452862306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
452962306a36Sopenharmony_ci					 MPT2SAS_DELL_PERC_H200_BRANDING);
453062306a36Sopenharmony_ci				break;
453162306a36Sopenharmony_ci			case MPT2SAS_DELL_6GBPS_SAS_SSDID:
453262306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
453362306a36Sopenharmony_ci					 MPT2SAS_DELL_6GBPS_SAS_BRANDING);
453462306a36Sopenharmony_ci				break;
453562306a36Sopenharmony_ci			default:
453662306a36Sopenharmony_ci				ioc_info(ioc, "Dell 6Gbps HBA: Subsystem ID: 0x%X\n",
453762306a36Sopenharmony_ci					 ioc->pdev->subsystem_device);
453862306a36Sopenharmony_ci				break;
453962306a36Sopenharmony_ci			}
454062306a36Sopenharmony_ci			break;
454162306a36Sopenharmony_ci		case MPI25_MFGPAGE_DEVID_SAS3008:
454262306a36Sopenharmony_ci			switch (ioc->pdev->subsystem_device) {
454362306a36Sopenharmony_ci			case MPT3SAS_DELL_12G_HBA_SSDID:
454462306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
454562306a36Sopenharmony_ci					 MPT3SAS_DELL_12G_HBA_BRANDING);
454662306a36Sopenharmony_ci				break;
454762306a36Sopenharmony_ci			default:
454862306a36Sopenharmony_ci				ioc_info(ioc, "Dell 12Gbps HBA: Subsystem ID: 0x%X\n",
454962306a36Sopenharmony_ci					 ioc->pdev->subsystem_device);
455062306a36Sopenharmony_ci				break;
455162306a36Sopenharmony_ci			}
455262306a36Sopenharmony_ci			break;
455362306a36Sopenharmony_ci		default:
455462306a36Sopenharmony_ci			ioc_info(ioc, "Dell HBA: Subsystem ID: 0x%X\n",
455562306a36Sopenharmony_ci				 ioc->pdev->subsystem_device);
455662306a36Sopenharmony_ci			break;
455762306a36Sopenharmony_ci		}
455862306a36Sopenharmony_ci		break;
455962306a36Sopenharmony_ci	case PCI_VENDOR_ID_CISCO:
456062306a36Sopenharmony_ci		switch (ioc->pdev->device) {
456162306a36Sopenharmony_ci		case MPI25_MFGPAGE_DEVID_SAS3008:
456262306a36Sopenharmony_ci			switch (ioc->pdev->subsystem_device) {
456362306a36Sopenharmony_ci			case MPT3SAS_CISCO_12G_8E_HBA_SSDID:
456462306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
456562306a36Sopenharmony_ci					 MPT3SAS_CISCO_12G_8E_HBA_BRANDING);
456662306a36Sopenharmony_ci				break;
456762306a36Sopenharmony_ci			case MPT3SAS_CISCO_12G_8I_HBA_SSDID:
456862306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
456962306a36Sopenharmony_ci					 MPT3SAS_CISCO_12G_8I_HBA_BRANDING);
457062306a36Sopenharmony_ci				break;
457162306a36Sopenharmony_ci			case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID:
457262306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
457362306a36Sopenharmony_ci					 MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING);
457462306a36Sopenharmony_ci				break;
457562306a36Sopenharmony_ci			default:
457662306a36Sopenharmony_ci				ioc_info(ioc, "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n",
457762306a36Sopenharmony_ci					 ioc->pdev->subsystem_device);
457862306a36Sopenharmony_ci				break;
457962306a36Sopenharmony_ci			}
458062306a36Sopenharmony_ci			break;
458162306a36Sopenharmony_ci		case MPI25_MFGPAGE_DEVID_SAS3108_1:
458262306a36Sopenharmony_ci			switch (ioc->pdev->subsystem_device) {
458362306a36Sopenharmony_ci			case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID:
458462306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
458562306a36Sopenharmony_ci					 MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING);
458662306a36Sopenharmony_ci				break;
458762306a36Sopenharmony_ci			case MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_SSDID:
458862306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
458962306a36Sopenharmony_ci					 MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING);
459062306a36Sopenharmony_ci				break;
459162306a36Sopenharmony_ci			default:
459262306a36Sopenharmony_ci				ioc_info(ioc, "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n",
459362306a36Sopenharmony_ci					 ioc->pdev->subsystem_device);
459462306a36Sopenharmony_ci				break;
459562306a36Sopenharmony_ci			}
459662306a36Sopenharmony_ci			break;
459762306a36Sopenharmony_ci		default:
459862306a36Sopenharmony_ci			ioc_info(ioc, "Cisco SAS HBA: Subsystem ID: 0x%X\n",
459962306a36Sopenharmony_ci				 ioc->pdev->subsystem_device);
460062306a36Sopenharmony_ci			break;
460162306a36Sopenharmony_ci		}
460262306a36Sopenharmony_ci		break;
460362306a36Sopenharmony_ci	case MPT2SAS_HP_3PAR_SSVID:
460462306a36Sopenharmony_ci		switch (ioc->pdev->device) {
460562306a36Sopenharmony_ci		case MPI2_MFGPAGE_DEVID_SAS2004:
460662306a36Sopenharmony_ci			switch (ioc->pdev->subsystem_device) {
460762306a36Sopenharmony_ci			case MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID:
460862306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
460962306a36Sopenharmony_ci					 MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING);
461062306a36Sopenharmony_ci				break;
461162306a36Sopenharmony_ci			default:
461262306a36Sopenharmony_ci				ioc_info(ioc, "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n",
461362306a36Sopenharmony_ci					 ioc->pdev->subsystem_device);
461462306a36Sopenharmony_ci				break;
461562306a36Sopenharmony_ci			}
461662306a36Sopenharmony_ci			break;
461762306a36Sopenharmony_ci		case MPI2_MFGPAGE_DEVID_SAS2308_2:
461862306a36Sopenharmony_ci			switch (ioc->pdev->subsystem_device) {
461962306a36Sopenharmony_ci			case MPT2SAS_HP_2_4_INTERNAL_SSDID:
462062306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
462162306a36Sopenharmony_ci					 MPT2SAS_HP_2_4_INTERNAL_BRANDING);
462262306a36Sopenharmony_ci				break;
462362306a36Sopenharmony_ci			case MPT2SAS_HP_2_4_EXTERNAL_SSDID:
462462306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
462562306a36Sopenharmony_ci					 MPT2SAS_HP_2_4_EXTERNAL_BRANDING);
462662306a36Sopenharmony_ci				break;
462762306a36Sopenharmony_ci			case MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID:
462862306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
462962306a36Sopenharmony_ci					 MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING);
463062306a36Sopenharmony_ci				break;
463162306a36Sopenharmony_ci			case MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID:
463262306a36Sopenharmony_ci				ioc_info(ioc, "%s\n",
463362306a36Sopenharmony_ci					 MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING);
463462306a36Sopenharmony_ci				break;
463562306a36Sopenharmony_ci			default:
463662306a36Sopenharmony_ci				ioc_info(ioc, "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n",
463762306a36Sopenharmony_ci					 ioc->pdev->subsystem_device);
463862306a36Sopenharmony_ci				break;
463962306a36Sopenharmony_ci			}
464062306a36Sopenharmony_ci			break;
464162306a36Sopenharmony_ci		default:
464262306a36Sopenharmony_ci			ioc_info(ioc, "HP SAS HBA: Subsystem ID: 0x%X\n",
464362306a36Sopenharmony_ci				 ioc->pdev->subsystem_device);
464462306a36Sopenharmony_ci			break;
464562306a36Sopenharmony_ci		}
464662306a36Sopenharmony_ci		break;
464762306a36Sopenharmony_ci	default:
464862306a36Sopenharmony_ci		break;
464962306a36Sopenharmony_ci	}
465062306a36Sopenharmony_ci}
465162306a36Sopenharmony_ci
465262306a36Sopenharmony_ci/**
465362306a36Sopenharmony_ci * _base_display_fwpkg_version - sends FWUpload request to pull FWPkg
465462306a36Sopenharmony_ci *				version from FW Image Header.
465562306a36Sopenharmony_ci * @ioc: per adapter object
465662306a36Sopenharmony_ci *
465762306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
465862306a36Sopenharmony_ci */
465962306a36Sopenharmony_ci	static int
466062306a36Sopenharmony_ci_base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc)
466162306a36Sopenharmony_ci{
466262306a36Sopenharmony_ci	Mpi2FWImageHeader_t *fw_img_hdr;
466362306a36Sopenharmony_ci	Mpi26ComponentImageHeader_t *cmp_img_hdr;
466462306a36Sopenharmony_ci	Mpi25FWUploadRequest_t *mpi_request;
466562306a36Sopenharmony_ci	Mpi2FWUploadReply_t mpi_reply;
466662306a36Sopenharmony_ci	int r = 0, issue_diag_reset = 0;
466762306a36Sopenharmony_ci	u32  package_version = 0;
466862306a36Sopenharmony_ci	void *fwpkg_data = NULL;
466962306a36Sopenharmony_ci	dma_addr_t fwpkg_data_dma;
467062306a36Sopenharmony_ci	u16 smid, ioc_status;
467162306a36Sopenharmony_ci	size_t data_length;
467262306a36Sopenharmony_ci
467362306a36Sopenharmony_ci	dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
467462306a36Sopenharmony_ci
467562306a36Sopenharmony_ci	if (ioc->base_cmds.status & MPT3_CMD_PENDING) {
467662306a36Sopenharmony_ci		ioc_err(ioc, "%s: internal command already in use\n", __func__);
467762306a36Sopenharmony_ci		return -EAGAIN;
467862306a36Sopenharmony_ci	}
467962306a36Sopenharmony_ci
468062306a36Sopenharmony_ci	data_length = sizeof(Mpi2FWImageHeader_t);
468162306a36Sopenharmony_ci	fwpkg_data = dma_alloc_coherent(&ioc->pdev->dev, data_length,
468262306a36Sopenharmony_ci			&fwpkg_data_dma, GFP_KERNEL);
468362306a36Sopenharmony_ci	if (!fwpkg_data) {
468462306a36Sopenharmony_ci		ioc_err(ioc,
468562306a36Sopenharmony_ci		    "Memory allocation for fwpkg data failed at %s:%d/%s()!\n",
468662306a36Sopenharmony_ci			__FILE__, __LINE__, __func__);
468762306a36Sopenharmony_ci		return -ENOMEM;
468862306a36Sopenharmony_ci	}
468962306a36Sopenharmony_ci
469062306a36Sopenharmony_ci	smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx);
469162306a36Sopenharmony_ci	if (!smid) {
469262306a36Sopenharmony_ci		ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
469362306a36Sopenharmony_ci		r = -EAGAIN;
469462306a36Sopenharmony_ci		goto out;
469562306a36Sopenharmony_ci	}
469662306a36Sopenharmony_ci
469762306a36Sopenharmony_ci	ioc->base_cmds.status = MPT3_CMD_PENDING;
469862306a36Sopenharmony_ci	mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
469962306a36Sopenharmony_ci	ioc->base_cmds.smid = smid;
470062306a36Sopenharmony_ci	memset(mpi_request, 0, sizeof(Mpi25FWUploadRequest_t));
470162306a36Sopenharmony_ci	mpi_request->Function = MPI2_FUNCTION_FW_UPLOAD;
470262306a36Sopenharmony_ci	mpi_request->ImageType = MPI2_FW_UPLOAD_ITYPE_FW_FLASH;
470362306a36Sopenharmony_ci	mpi_request->ImageSize = cpu_to_le32(data_length);
470462306a36Sopenharmony_ci	ioc->build_sg(ioc, &mpi_request->SGL, 0, 0, fwpkg_data_dma,
470562306a36Sopenharmony_ci			data_length);
470662306a36Sopenharmony_ci	init_completion(&ioc->base_cmds.done);
470762306a36Sopenharmony_ci	ioc->put_smid_default(ioc, smid);
470862306a36Sopenharmony_ci	/* Wait for 15 seconds */
470962306a36Sopenharmony_ci	wait_for_completion_timeout(&ioc->base_cmds.done,
471062306a36Sopenharmony_ci			FW_IMG_HDR_READ_TIMEOUT*HZ);
471162306a36Sopenharmony_ci	ioc_info(ioc, "%s: complete\n", __func__);
471262306a36Sopenharmony_ci	if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
471362306a36Sopenharmony_ci		ioc_err(ioc, "%s: timeout\n", __func__);
471462306a36Sopenharmony_ci		_debug_dump_mf(mpi_request,
471562306a36Sopenharmony_ci				sizeof(Mpi25FWUploadRequest_t)/4);
471662306a36Sopenharmony_ci		issue_diag_reset = 1;
471762306a36Sopenharmony_ci	} else {
471862306a36Sopenharmony_ci		memset(&mpi_reply, 0, sizeof(Mpi2FWUploadReply_t));
471962306a36Sopenharmony_ci		if (ioc->base_cmds.status & MPT3_CMD_REPLY_VALID) {
472062306a36Sopenharmony_ci			memcpy(&mpi_reply, ioc->base_cmds.reply,
472162306a36Sopenharmony_ci					sizeof(Mpi2FWUploadReply_t));
472262306a36Sopenharmony_ci			ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
472362306a36Sopenharmony_ci						MPI2_IOCSTATUS_MASK;
472462306a36Sopenharmony_ci			if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
472562306a36Sopenharmony_ci				fw_img_hdr = (Mpi2FWImageHeader_t *)fwpkg_data;
472662306a36Sopenharmony_ci				if (le32_to_cpu(fw_img_hdr->Signature) ==
472762306a36Sopenharmony_ci				    MPI26_IMAGE_HEADER_SIGNATURE0_MPI26) {
472862306a36Sopenharmony_ci					cmp_img_hdr =
472962306a36Sopenharmony_ci					    (Mpi26ComponentImageHeader_t *)
473062306a36Sopenharmony_ci					    (fwpkg_data);
473162306a36Sopenharmony_ci					package_version =
473262306a36Sopenharmony_ci					    le32_to_cpu(
473362306a36Sopenharmony_ci					    cmp_img_hdr->ApplicationSpecific);
473462306a36Sopenharmony_ci				} else
473562306a36Sopenharmony_ci					package_version =
473662306a36Sopenharmony_ci					    le32_to_cpu(
473762306a36Sopenharmony_ci					    fw_img_hdr->PackageVersion.Word);
473862306a36Sopenharmony_ci				if (package_version)
473962306a36Sopenharmony_ci					ioc_info(ioc,
474062306a36Sopenharmony_ci					"FW Package Ver(%02d.%02d.%02d.%02d)\n",
474162306a36Sopenharmony_ci					((package_version) & 0xFF000000) >> 24,
474262306a36Sopenharmony_ci					((package_version) & 0x00FF0000) >> 16,
474362306a36Sopenharmony_ci					((package_version) & 0x0000FF00) >> 8,
474462306a36Sopenharmony_ci					(package_version) & 0x000000FF);
474562306a36Sopenharmony_ci			} else {
474662306a36Sopenharmony_ci				_debug_dump_mf(&mpi_reply,
474762306a36Sopenharmony_ci						sizeof(Mpi2FWUploadReply_t)/4);
474862306a36Sopenharmony_ci			}
474962306a36Sopenharmony_ci		}
475062306a36Sopenharmony_ci	}
475162306a36Sopenharmony_ci	ioc->base_cmds.status = MPT3_CMD_NOT_USED;
475262306a36Sopenharmony_ciout:
475362306a36Sopenharmony_ci	if (fwpkg_data)
475462306a36Sopenharmony_ci		dma_free_coherent(&ioc->pdev->dev, data_length, fwpkg_data,
475562306a36Sopenharmony_ci				fwpkg_data_dma);
475662306a36Sopenharmony_ci	if (issue_diag_reset) {
475762306a36Sopenharmony_ci		if (ioc->drv_internal_flags & MPT_DRV_INTERNAL_FIRST_PE_ISSUED)
475862306a36Sopenharmony_ci			return -EFAULT;
475962306a36Sopenharmony_ci		if (mpt3sas_base_check_for_fault_and_issue_reset(ioc))
476062306a36Sopenharmony_ci			return -EFAULT;
476162306a36Sopenharmony_ci		r = -EAGAIN;
476262306a36Sopenharmony_ci	}
476362306a36Sopenharmony_ci	return r;
476462306a36Sopenharmony_ci}
476562306a36Sopenharmony_ci
476662306a36Sopenharmony_ci/**
476762306a36Sopenharmony_ci * _base_display_ioc_capabilities - Display IOC's capabilities.
476862306a36Sopenharmony_ci * @ioc: per adapter object
476962306a36Sopenharmony_ci */
477062306a36Sopenharmony_cistatic void
477162306a36Sopenharmony_ci_base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc)
477262306a36Sopenharmony_ci{
477362306a36Sopenharmony_ci	int i = 0;
477462306a36Sopenharmony_ci	char desc[17] = {0};
477562306a36Sopenharmony_ci	u32 iounit_pg1_flags;
477662306a36Sopenharmony_ci
477762306a36Sopenharmony_ci	strncpy(desc, ioc->manu_pg0.ChipName, 16);
477862306a36Sopenharmony_ci	ioc_info(ioc, "%s: FWVersion(%02d.%02d.%02d.%02d), ChipRevision(0x%02x)\n",
477962306a36Sopenharmony_ci		 desc,
478062306a36Sopenharmony_ci		 (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
478162306a36Sopenharmony_ci		 (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
478262306a36Sopenharmony_ci		 (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
478362306a36Sopenharmony_ci		 ioc->facts.FWVersion.Word & 0x000000FF,
478462306a36Sopenharmony_ci		 ioc->pdev->revision);
478562306a36Sopenharmony_ci
478662306a36Sopenharmony_ci	_base_display_OEMs_branding(ioc);
478762306a36Sopenharmony_ci
478862306a36Sopenharmony_ci	if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_NVME_DEVICES) {
478962306a36Sopenharmony_ci		pr_info("%sNVMe", i ? "," : "");
479062306a36Sopenharmony_ci		i++;
479162306a36Sopenharmony_ci	}
479262306a36Sopenharmony_ci
479362306a36Sopenharmony_ci	ioc_info(ioc, "Protocol=(");
479462306a36Sopenharmony_ci
479562306a36Sopenharmony_ci	if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR) {
479662306a36Sopenharmony_ci		pr_cont("Initiator");
479762306a36Sopenharmony_ci		i++;
479862306a36Sopenharmony_ci	}
479962306a36Sopenharmony_ci
480062306a36Sopenharmony_ci	if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET) {
480162306a36Sopenharmony_ci		pr_cont("%sTarget", i ? "," : "");
480262306a36Sopenharmony_ci		i++;
480362306a36Sopenharmony_ci	}
480462306a36Sopenharmony_ci
480562306a36Sopenharmony_ci	i = 0;
480662306a36Sopenharmony_ci	pr_cont("), Capabilities=(");
480762306a36Sopenharmony_ci
480862306a36Sopenharmony_ci	if (!ioc->hide_ir_msg) {
480962306a36Sopenharmony_ci		if (ioc->facts.IOCCapabilities &
481062306a36Sopenharmony_ci		    MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) {
481162306a36Sopenharmony_ci			pr_cont("Raid");
481262306a36Sopenharmony_ci			i++;
481362306a36Sopenharmony_ci		}
481462306a36Sopenharmony_ci	}
481562306a36Sopenharmony_ci
481662306a36Sopenharmony_ci	if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) {
481762306a36Sopenharmony_ci		pr_cont("%sTLR", i ? "," : "");
481862306a36Sopenharmony_ci		i++;
481962306a36Sopenharmony_ci	}
482062306a36Sopenharmony_ci
482162306a36Sopenharmony_ci	if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_MULTICAST) {
482262306a36Sopenharmony_ci		pr_cont("%sMulticast", i ? "," : "");
482362306a36Sopenharmony_ci		i++;
482462306a36Sopenharmony_ci	}
482562306a36Sopenharmony_ci
482662306a36Sopenharmony_ci	if (ioc->facts.IOCCapabilities &
482762306a36Sopenharmony_ci	    MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET) {
482862306a36Sopenharmony_ci		pr_cont("%sBIDI Target", i ? "," : "");
482962306a36Sopenharmony_ci		i++;
483062306a36Sopenharmony_ci	}
483162306a36Sopenharmony_ci
483262306a36Sopenharmony_ci	if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP) {
483362306a36Sopenharmony_ci		pr_cont("%sEEDP", i ? "," : "");
483462306a36Sopenharmony_ci		i++;
483562306a36Sopenharmony_ci	}
483662306a36Sopenharmony_ci
483762306a36Sopenharmony_ci	if (ioc->facts.IOCCapabilities &
483862306a36Sopenharmony_ci	    MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) {
483962306a36Sopenharmony_ci		pr_cont("%sSnapshot Buffer", i ? "," : "");
484062306a36Sopenharmony_ci		i++;
484162306a36Sopenharmony_ci	}
484262306a36Sopenharmony_ci
484362306a36Sopenharmony_ci	if (ioc->facts.IOCCapabilities &
484462306a36Sopenharmony_ci	    MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) {
484562306a36Sopenharmony_ci		pr_cont("%sDiag Trace Buffer", i ? "," : "");
484662306a36Sopenharmony_ci		i++;
484762306a36Sopenharmony_ci	}
484862306a36Sopenharmony_ci
484962306a36Sopenharmony_ci	if (ioc->facts.IOCCapabilities &
485062306a36Sopenharmony_ci	    MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) {
485162306a36Sopenharmony_ci		pr_cont("%sDiag Extended Buffer", i ? "," : "");
485262306a36Sopenharmony_ci		i++;
485362306a36Sopenharmony_ci	}
485462306a36Sopenharmony_ci
485562306a36Sopenharmony_ci	if (ioc->facts.IOCCapabilities &
485662306a36Sopenharmony_ci	    MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING) {
485762306a36Sopenharmony_ci		pr_cont("%sTask Set Full", i ? "," : "");
485862306a36Sopenharmony_ci		i++;
485962306a36Sopenharmony_ci	}
486062306a36Sopenharmony_ci
486162306a36Sopenharmony_ci	iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags);
486262306a36Sopenharmony_ci	if (!(iounit_pg1_flags & MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE)) {
486362306a36Sopenharmony_ci		pr_cont("%sNCQ", i ? "," : "");
486462306a36Sopenharmony_ci		i++;
486562306a36Sopenharmony_ci	}
486662306a36Sopenharmony_ci
486762306a36Sopenharmony_ci	pr_cont(")\n");
486862306a36Sopenharmony_ci}
486962306a36Sopenharmony_ci
487062306a36Sopenharmony_ci/**
487162306a36Sopenharmony_ci * mpt3sas_base_update_missing_delay - change the missing delay timers
487262306a36Sopenharmony_ci * @ioc: per adapter object
487362306a36Sopenharmony_ci * @device_missing_delay: amount of time till device is reported missing
487462306a36Sopenharmony_ci * @io_missing_delay: interval IO is returned when there is a missing device
487562306a36Sopenharmony_ci *
487662306a36Sopenharmony_ci * Passed on the command line, this function will modify the device missing
487762306a36Sopenharmony_ci * delay, as well as the io missing delay. This should be called at driver
487862306a36Sopenharmony_ci * load time.
487962306a36Sopenharmony_ci */
488062306a36Sopenharmony_civoid
488162306a36Sopenharmony_cimpt3sas_base_update_missing_delay(struct MPT3SAS_ADAPTER *ioc,
488262306a36Sopenharmony_ci	u16 device_missing_delay, u8 io_missing_delay)
488362306a36Sopenharmony_ci{
488462306a36Sopenharmony_ci	u16 dmd, dmd_new, dmd_orignal;
488562306a36Sopenharmony_ci	u8 io_missing_delay_original;
488662306a36Sopenharmony_ci	u16 sz;
488762306a36Sopenharmony_ci	Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
488862306a36Sopenharmony_ci	Mpi2ConfigReply_t mpi_reply;
488962306a36Sopenharmony_ci	u8 num_phys = 0;
489062306a36Sopenharmony_ci	u16 ioc_status;
489162306a36Sopenharmony_ci
489262306a36Sopenharmony_ci	mpt3sas_config_get_number_hba_phys(ioc, &num_phys);
489362306a36Sopenharmony_ci	if (!num_phys)
489462306a36Sopenharmony_ci		return;
489562306a36Sopenharmony_ci
489662306a36Sopenharmony_ci	sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (num_phys *
489762306a36Sopenharmony_ci	    sizeof(Mpi2SasIOUnit1PhyData_t));
489862306a36Sopenharmony_ci	sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
489962306a36Sopenharmony_ci	if (!sas_iounit_pg1) {
490062306a36Sopenharmony_ci		ioc_err(ioc, "failure at %s:%d/%s()!\n",
490162306a36Sopenharmony_ci			__FILE__, __LINE__, __func__);
490262306a36Sopenharmony_ci		goto out;
490362306a36Sopenharmony_ci	}
490462306a36Sopenharmony_ci	if ((mpt3sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
490562306a36Sopenharmony_ci	    sas_iounit_pg1, sz))) {
490662306a36Sopenharmony_ci		ioc_err(ioc, "failure at %s:%d/%s()!\n",
490762306a36Sopenharmony_ci			__FILE__, __LINE__, __func__);
490862306a36Sopenharmony_ci		goto out;
490962306a36Sopenharmony_ci	}
491062306a36Sopenharmony_ci	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
491162306a36Sopenharmony_ci	    MPI2_IOCSTATUS_MASK;
491262306a36Sopenharmony_ci	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
491362306a36Sopenharmony_ci		ioc_err(ioc, "failure at %s:%d/%s()!\n",
491462306a36Sopenharmony_ci			__FILE__, __LINE__, __func__);
491562306a36Sopenharmony_ci		goto out;
491662306a36Sopenharmony_ci	}
491762306a36Sopenharmony_ci
491862306a36Sopenharmony_ci	/* device missing delay */
491962306a36Sopenharmony_ci	dmd = sas_iounit_pg1->ReportDeviceMissingDelay;
492062306a36Sopenharmony_ci	if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
492162306a36Sopenharmony_ci		dmd = (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
492262306a36Sopenharmony_ci	else
492362306a36Sopenharmony_ci		dmd = dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
492462306a36Sopenharmony_ci	dmd_orignal = dmd;
492562306a36Sopenharmony_ci	if (device_missing_delay > 0x7F) {
492662306a36Sopenharmony_ci		dmd = (device_missing_delay > 0x7F0) ? 0x7F0 :
492762306a36Sopenharmony_ci		    device_missing_delay;
492862306a36Sopenharmony_ci		dmd = dmd / 16;
492962306a36Sopenharmony_ci		dmd |= MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16;
493062306a36Sopenharmony_ci	} else
493162306a36Sopenharmony_ci		dmd = device_missing_delay;
493262306a36Sopenharmony_ci	sas_iounit_pg1->ReportDeviceMissingDelay = dmd;
493362306a36Sopenharmony_ci
493462306a36Sopenharmony_ci	/* io missing delay */
493562306a36Sopenharmony_ci	io_missing_delay_original = sas_iounit_pg1->IODeviceMissingDelay;
493662306a36Sopenharmony_ci	sas_iounit_pg1->IODeviceMissingDelay = io_missing_delay;
493762306a36Sopenharmony_ci
493862306a36Sopenharmony_ci	if (!mpt3sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1,
493962306a36Sopenharmony_ci	    sz)) {
494062306a36Sopenharmony_ci		if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
494162306a36Sopenharmony_ci			dmd_new = (dmd &
494262306a36Sopenharmony_ci			    MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
494362306a36Sopenharmony_ci		else
494462306a36Sopenharmony_ci			dmd_new =
494562306a36Sopenharmony_ci		    dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
494662306a36Sopenharmony_ci		ioc_info(ioc, "device_missing_delay: old(%d), new(%d)\n",
494762306a36Sopenharmony_ci			 dmd_orignal, dmd_new);
494862306a36Sopenharmony_ci		ioc_info(ioc, "ioc_missing_delay: old(%d), new(%d)\n",
494962306a36Sopenharmony_ci			 io_missing_delay_original,
495062306a36Sopenharmony_ci			 io_missing_delay);
495162306a36Sopenharmony_ci		ioc->device_missing_delay = dmd_new;
495262306a36Sopenharmony_ci		ioc->io_missing_delay = io_missing_delay;
495362306a36Sopenharmony_ci	}
495462306a36Sopenharmony_ci
495562306a36Sopenharmony_ciout:
495662306a36Sopenharmony_ci	kfree(sas_iounit_pg1);
495762306a36Sopenharmony_ci}
495862306a36Sopenharmony_ci
495962306a36Sopenharmony_ci/**
496062306a36Sopenharmony_ci * _base_update_ioc_page1_inlinewith_perf_mode - Update IOC Page1 fields
496162306a36Sopenharmony_ci *    according to performance mode.
496262306a36Sopenharmony_ci * @ioc : per adapter object
496362306a36Sopenharmony_ci *
496462306a36Sopenharmony_ci * Return: zero on success; otherwise return EAGAIN error code asking the
496562306a36Sopenharmony_ci * caller to retry.
496662306a36Sopenharmony_ci */
496762306a36Sopenharmony_cistatic int
496862306a36Sopenharmony_ci_base_update_ioc_page1_inlinewith_perf_mode(struct MPT3SAS_ADAPTER *ioc)
496962306a36Sopenharmony_ci{
497062306a36Sopenharmony_ci	Mpi2IOCPage1_t ioc_pg1;
497162306a36Sopenharmony_ci	Mpi2ConfigReply_t mpi_reply;
497262306a36Sopenharmony_ci	int rc;
497362306a36Sopenharmony_ci
497462306a36Sopenharmony_ci	rc = mpt3sas_config_get_ioc_pg1(ioc, &mpi_reply, &ioc->ioc_pg1_copy);
497562306a36Sopenharmony_ci	if (rc)
497662306a36Sopenharmony_ci		return rc;
497762306a36Sopenharmony_ci	memcpy(&ioc_pg1, &ioc->ioc_pg1_copy, sizeof(Mpi2IOCPage1_t));
497862306a36Sopenharmony_ci
497962306a36Sopenharmony_ci	switch (perf_mode) {
498062306a36Sopenharmony_ci	case MPT_PERF_MODE_DEFAULT:
498162306a36Sopenharmony_ci	case MPT_PERF_MODE_BALANCED:
498262306a36Sopenharmony_ci		if (ioc->high_iops_queues) {
498362306a36Sopenharmony_ci			ioc_info(ioc,
498462306a36Sopenharmony_ci				"Enable interrupt coalescing only for first\t"
498562306a36Sopenharmony_ci				"%d reply queues\n",
498662306a36Sopenharmony_ci				MPT3SAS_HIGH_IOPS_REPLY_QUEUES);
498762306a36Sopenharmony_ci			/*
498862306a36Sopenharmony_ci			 * If 31st bit is zero then interrupt coalescing is
498962306a36Sopenharmony_ci			 * enabled for all reply descriptor post queues.
499062306a36Sopenharmony_ci			 * If 31st bit is set to one then user can
499162306a36Sopenharmony_ci			 * enable/disable interrupt coalescing on per reply
499262306a36Sopenharmony_ci			 * descriptor post queue group(8) basis. So to enable
499362306a36Sopenharmony_ci			 * interrupt coalescing only on first reply descriptor
499462306a36Sopenharmony_ci			 * post queue group 31st bit and zero th bit is enabled.
499562306a36Sopenharmony_ci			 */
499662306a36Sopenharmony_ci			ioc_pg1.ProductSpecific = cpu_to_le32(0x80000000 |
499762306a36Sopenharmony_ci			    ((1 << MPT3SAS_HIGH_IOPS_REPLY_QUEUES/8) - 1));
499862306a36Sopenharmony_ci			rc = mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1);
499962306a36Sopenharmony_ci			if (rc)
500062306a36Sopenharmony_ci				return rc;
500162306a36Sopenharmony_ci			ioc_info(ioc, "performance mode: balanced\n");
500262306a36Sopenharmony_ci			return 0;
500362306a36Sopenharmony_ci		}
500462306a36Sopenharmony_ci		fallthrough;
500562306a36Sopenharmony_ci	case MPT_PERF_MODE_LATENCY:
500662306a36Sopenharmony_ci		/*
500762306a36Sopenharmony_ci		 * Enable interrupt coalescing on all reply queues
500862306a36Sopenharmony_ci		 * with timeout value 0xA
500962306a36Sopenharmony_ci		 */
501062306a36Sopenharmony_ci		ioc_pg1.CoalescingTimeout = cpu_to_le32(0xa);
501162306a36Sopenharmony_ci		ioc_pg1.Flags |= cpu_to_le32(MPI2_IOCPAGE1_REPLY_COALESCING);
501262306a36Sopenharmony_ci		ioc_pg1.ProductSpecific = 0;
501362306a36Sopenharmony_ci		rc = mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1);
501462306a36Sopenharmony_ci		if (rc)
501562306a36Sopenharmony_ci			return rc;
501662306a36Sopenharmony_ci		ioc_info(ioc, "performance mode: latency\n");
501762306a36Sopenharmony_ci		break;
501862306a36Sopenharmony_ci	case MPT_PERF_MODE_IOPS:
501962306a36Sopenharmony_ci		/*
502062306a36Sopenharmony_ci		 * Enable interrupt coalescing on all reply queues.
502162306a36Sopenharmony_ci		 */
502262306a36Sopenharmony_ci		ioc_info(ioc,
502362306a36Sopenharmony_ci		    "performance mode: iops with coalescing timeout: 0x%x\n",
502462306a36Sopenharmony_ci		    le32_to_cpu(ioc_pg1.CoalescingTimeout));
502562306a36Sopenharmony_ci		ioc_pg1.Flags |= cpu_to_le32(MPI2_IOCPAGE1_REPLY_COALESCING);
502662306a36Sopenharmony_ci		ioc_pg1.ProductSpecific = 0;
502762306a36Sopenharmony_ci		rc = mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1);
502862306a36Sopenharmony_ci		if (rc)
502962306a36Sopenharmony_ci			return rc;
503062306a36Sopenharmony_ci		break;
503162306a36Sopenharmony_ci	}
503262306a36Sopenharmony_ci	return 0;
503362306a36Sopenharmony_ci}
503462306a36Sopenharmony_ci
503562306a36Sopenharmony_ci/**
503662306a36Sopenharmony_ci * _base_get_event_diag_triggers - get event diag trigger values from
503762306a36Sopenharmony_ci *				persistent pages
503862306a36Sopenharmony_ci * @ioc : per adapter object
503962306a36Sopenharmony_ci *
504062306a36Sopenharmony_ci * Return: nothing.
504162306a36Sopenharmony_ci */
504262306a36Sopenharmony_cistatic int
504362306a36Sopenharmony_ci_base_get_event_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
504462306a36Sopenharmony_ci{
504562306a36Sopenharmony_ci	Mpi26DriverTriggerPage2_t trigger_pg2;
504662306a36Sopenharmony_ci	struct SL_WH_EVENT_TRIGGER_T *event_tg;
504762306a36Sopenharmony_ci	MPI26_DRIVER_MPI_EVENT_TIGGER_ENTRY *mpi_event_tg;
504862306a36Sopenharmony_ci	Mpi2ConfigReply_t mpi_reply;
504962306a36Sopenharmony_ci	int r = 0, i = 0;
505062306a36Sopenharmony_ci	u16 count = 0;
505162306a36Sopenharmony_ci	u16 ioc_status;
505262306a36Sopenharmony_ci
505362306a36Sopenharmony_ci	r = mpt3sas_config_get_driver_trigger_pg2(ioc, &mpi_reply,
505462306a36Sopenharmony_ci	    &trigger_pg2);
505562306a36Sopenharmony_ci	if (r)
505662306a36Sopenharmony_ci		return r;
505762306a36Sopenharmony_ci
505862306a36Sopenharmony_ci	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
505962306a36Sopenharmony_ci	    MPI2_IOCSTATUS_MASK;
506062306a36Sopenharmony_ci	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
506162306a36Sopenharmony_ci		dinitprintk(ioc,
506262306a36Sopenharmony_ci		    ioc_err(ioc,
506362306a36Sopenharmony_ci		    "%s: Failed to get trigger pg2, ioc_status(0x%04x)\n",
506462306a36Sopenharmony_ci		   __func__, ioc_status));
506562306a36Sopenharmony_ci		return 0;
506662306a36Sopenharmony_ci	}
506762306a36Sopenharmony_ci
506862306a36Sopenharmony_ci	if (le16_to_cpu(trigger_pg2.NumMPIEventTrigger)) {
506962306a36Sopenharmony_ci		count = le16_to_cpu(trigger_pg2.NumMPIEventTrigger);
507062306a36Sopenharmony_ci		count = min_t(u16, NUM_VALID_ENTRIES, count);
507162306a36Sopenharmony_ci		ioc->diag_trigger_event.ValidEntries = count;
507262306a36Sopenharmony_ci
507362306a36Sopenharmony_ci		event_tg = &ioc->diag_trigger_event.EventTriggerEntry[0];
507462306a36Sopenharmony_ci		mpi_event_tg = &trigger_pg2.MPIEventTriggers[0];
507562306a36Sopenharmony_ci		for (i = 0; i < count; i++) {
507662306a36Sopenharmony_ci			event_tg->EventValue = le16_to_cpu(
507762306a36Sopenharmony_ci			    mpi_event_tg->MPIEventCode);
507862306a36Sopenharmony_ci			event_tg->LogEntryQualifier = le16_to_cpu(
507962306a36Sopenharmony_ci			    mpi_event_tg->MPIEventCodeSpecific);
508062306a36Sopenharmony_ci			event_tg++;
508162306a36Sopenharmony_ci			mpi_event_tg++;
508262306a36Sopenharmony_ci		}
508362306a36Sopenharmony_ci	}
508462306a36Sopenharmony_ci	return 0;
508562306a36Sopenharmony_ci}
508662306a36Sopenharmony_ci
508762306a36Sopenharmony_ci/**
508862306a36Sopenharmony_ci * _base_get_scsi_diag_triggers - get scsi diag trigger values from
508962306a36Sopenharmony_ci *				persistent pages
509062306a36Sopenharmony_ci * @ioc : per adapter object
509162306a36Sopenharmony_ci *
509262306a36Sopenharmony_ci * Return: 0 on success; otherwise return failure status.
509362306a36Sopenharmony_ci */
509462306a36Sopenharmony_cistatic int
509562306a36Sopenharmony_ci_base_get_scsi_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
509662306a36Sopenharmony_ci{
509762306a36Sopenharmony_ci	Mpi26DriverTriggerPage3_t trigger_pg3;
509862306a36Sopenharmony_ci	struct SL_WH_SCSI_TRIGGER_T *scsi_tg;
509962306a36Sopenharmony_ci	MPI26_DRIVER_SCSI_SENSE_TIGGER_ENTRY *mpi_scsi_tg;
510062306a36Sopenharmony_ci	Mpi2ConfigReply_t mpi_reply;
510162306a36Sopenharmony_ci	int r = 0, i = 0;
510262306a36Sopenharmony_ci	u16 count = 0;
510362306a36Sopenharmony_ci	u16 ioc_status;
510462306a36Sopenharmony_ci
510562306a36Sopenharmony_ci	r = mpt3sas_config_get_driver_trigger_pg3(ioc, &mpi_reply,
510662306a36Sopenharmony_ci	    &trigger_pg3);
510762306a36Sopenharmony_ci	if (r)
510862306a36Sopenharmony_ci		return r;
510962306a36Sopenharmony_ci
511062306a36Sopenharmony_ci	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
511162306a36Sopenharmony_ci	    MPI2_IOCSTATUS_MASK;
511262306a36Sopenharmony_ci	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
511362306a36Sopenharmony_ci		dinitprintk(ioc,
511462306a36Sopenharmony_ci		    ioc_err(ioc,
511562306a36Sopenharmony_ci		    "%s: Failed to get trigger pg3, ioc_status(0x%04x)\n",
511662306a36Sopenharmony_ci		    __func__, ioc_status));
511762306a36Sopenharmony_ci		return 0;
511862306a36Sopenharmony_ci	}
511962306a36Sopenharmony_ci
512062306a36Sopenharmony_ci	if (le16_to_cpu(trigger_pg3.NumSCSISenseTrigger)) {
512162306a36Sopenharmony_ci		count = le16_to_cpu(trigger_pg3.NumSCSISenseTrigger);
512262306a36Sopenharmony_ci		count = min_t(u16, NUM_VALID_ENTRIES, count);
512362306a36Sopenharmony_ci		ioc->diag_trigger_scsi.ValidEntries = count;
512462306a36Sopenharmony_ci
512562306a36Sopenharmony_ci		scsi_tg = &ioc->diag_trigger_scsi.SCSITriggerEntry[0];
512662306a36Sopenharmony_ci		mpi_scsi_tg = &trigger_pg3.SCSISenseTriggers[0];
512762306a36Sopenharmony_ci		for (i = 0; i < count; i++) {
512862306a36Sopenharmony_ci			scsi_tg->ASCQ = mpi_scsi_tg->ASCQ;
512962306a36Sopenharmony_ci			scsi_tg->ASC = mpi_scsi_tg->ASC;
513062306a36Sopenharmony_ci			scsi_tg->SenseKey = mpi_scsi_tg->SenseKey;
513162306a36Sopenharmony_ci
513262306a36Sopenharmony_ci			scsi_tg++;
513362306a36Sopenharmony_ci			mpi_scsi_tg++;
513462306a36Sopenharmony_ci		}
513562306a36Sopenharmony_ci	}
513662306a36Sopenharmony_ci	return 0;
513762306a36Sopenharmony_ci}
513862306a36Sopenharmony_ci
513962306a36Sopenharmony_ci/**
514062306a36Sopenharmony_ci * _base_get_mpi_diag_triggers - get mpi diag trigger values from
514162306a36Sopenharmony_ci *				persistent pages
514262306a36Sopenharmony_ci * @ioc : per adapter object
514362306a36Sopenharmony_ci *
514462306a36Sopenharmony_ci * Return: 0 on success; otherwise return failure status.
514562306a36Sopenharmony_ci */
514662306a36Sopenharmony_cistatic int
514762306a36Sopenharmony_ci_base_get_mpi_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
514862306a36Sopenharmony_ci{
514962306a36Sopenharmony_ci	Mpi26DriverTriggerPage4_t trigger_pg4;
515062306a36Sopenharmony_ci	struct SL_WH_MPI_TRIGGER_T *status_tg;
515162306a36Sopenharmony_ci	MPI26_DRIVER_IOCSTATUS_LOGINFO_TIGGER_ENTRY *mpi_status_tg;
515262306a36Sopenharmony_ci	Mpi2ConfigReply_t mpi_reply;
515362306a36Sopenharmony_ci	int r = 0, i = 0;
515462306a36Sopenharmony_ci	u16 count = 0;
515562306a36Sopenharmony_ci	u16 ioc_status;
515662306a36Sopenharmony_ci
515762306a36Sopenharmony_ci	r = mpt3sas_config_get_driver_trigger_pg4(ioc, &mpi_reply,
515862306a36Sopenharmony_ci	    &trigger_pg4);
515962306a36Sopenharmony_ci	if (r)
516062306a36Sopenharmony_ci		return r;
516162306a36Sopenharmony_ci
516262306a36Sopenharmony_ci	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
516362306a36Sopenharmony_ci	    MPI2_IOCSTATUS_MASK;
516462306a36Sopenharmony_ci	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
516562306a36Sopenharmony_ci		dinitprintk(ioc,
516662306a36Sopenharmony_ci		    ioc_err(ioc,
516762306a36Sopenharmony_ci		    "%s: Failed to get trigger pg4, ioc_status(0x%04x)\n",
516862306a36Sopenharmony_ci		    __func__, ioc_status));
516962306a36Sopenharmony_ci		return 0;
517062306a36Sopenharmony_ci	}
517162306a36Sopenharmony_ci
517262306a36Sopenharmony_ci	if (le16_to_cpu(trigger_pg4.NumIOCStatusLogInfoTrigger)) {
517362306a36Sopenharmony_ci		count = le16_to_cpu(trigger_pg4.NumIOCStatusLogInfoTrigger);
517462306a36Sopenharmony_ci		count = min_t(u16, NUM_VALID_ENTRIES, count);
517562306a36Sopenharmony_ci		ioc->diag_trigger_mpi.ValidEntries = count;
517662306a36Sopenharmony_ci
517762306a36Sopenharmony_ci		status_tg = &ioc->diag_trigger_mpi.MPITriggerEntry[0];
517862306a36Sopenharmony_ci		mpi_status_tg = &trigger_pg4.IOCStatusLoginfoTriggers[0];
517962306a36Sopenharmony_ci
518062306a36Sopenharmony_ci		for (i = 0; i < count; i++) {
518162306a36Sopenharmony_ci			status_tg->IOCStatus = le16_to_cpu(
518262306a36Sopenharmony_ci			    mpi_status_tg->IOCStatus);
518362306a36Sopenharmony_ci			status_tg->IocLogInfo = le32_to_cpu(
518462306a36Sopenharmony_ci			    mpi_status_tg->LogInfo);
518562306a36Sopenharmony_ci
518662306a36Sopenharmony_ci			status_tg++;
518762306a36Sopenharmony_ci			mpi_status_tg++;
518862306a36Sopenharmony_ci		}
518962306a36Sopenharmony_ci	}
519062306a36Sopenharmony_ci	return 0;
519162306a36Sopenharmony_ci}
519262306a36Sopenharmony_ci
519362306a36Sopenharmony_ci/**
519462306a36Sopenharmony_ci * _base_get_master_diag_triggers - get master diag trigger values from
519562306a36Sopenharmony_ci *				persistent pages
519662306a36Sopenharmony_ci * @ioc : per adapter object
519762306a36Sopenharmony_ci *
519862306a36Sopenharmony_ci * Return: nothing.
519962306a36Sopenharmony_ci */
520062306a36Sopenharmony_cistatic int
520162306a36Sopenharmony_ci_base_get_master_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
520262306a36Sopenharmony_ci{
520362306a36Sopenharmony_ci	Mpi26DriverTriggerPage1_t trigger_pg1;
520462306a36Sopenharmony_ci	Mpi2ConfigReply_t mpi_reply;
520562306a36Sopenharmony_ci	int r;
520662306a36Sopenharmony_ci	u16 ioc_status;
520762306a36Sopenharmony_ci
520862306a36Sopenharmony_ci	r = mpt3sas_config_get_driver_trigger_pg1(ioc, &mpi_reply,
520962306a36Sopenharmony_ci	    &trigger_pg1);
521062306a36Sopenharmony_ci	if (r)
521162306a36Sopenharmony_ci		return r;
521262306a36Sopenharmony_ci
521362306a36Sopenharmony_ci	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
521462306a36Sopenharmony_ci	    MPI2_IOCSTATUS_MASK;
521562306a36Sopenharmony_ci	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
521662306a36Sopenharmony_ci		dinitprintk(ioc,
521762306a36Sopenharmony_ci		    ioc_err(ioc,
521862306a36Sopenharmony_ci		    "%s: Failed to get trigger pg1, ioc_status(0x%04x)\n",
521962306a36Sopenharmony_ci		   __func__, ioc_status));
522062306a36Sopenharmony_ci		return 0;
522162306a36Sopenharmony_ci	}
522262306a36Sopenharmony_ci
522362306a36Sopenharmony_ci	if (le16_to_cpu(trigger_pg1.NumMasterTrigger))
522462306a36Sopenharmony_ci		ioc->diag_trigger_master.MasterData |=
522562306a36Sopenharmony_ci		    le32_to_cpu(
522662306a36Sopenharmony_ci		    trigger_pg1.MasterTriggers[0].MasterTriggerFlags);
522762306a36Sopenharmony_ci	return 0;
522862306a36Sopenharmony_ci}
522962306a36Sopenharmony_ci
523062306a36Sopenharmony_ci/**
523162306a36Sopenharmony_ci * _base_check_for_trigger_pages_support - checks whether HBA FW supports
523262306a36Sopenharmony_ci *					driver trigger pages or not
523362306a36Sopenharmony_ci * @ioc : per adapter object
523462306a36Sopenharmony_ci * @trigger_flags : address where trigger page0's TriggerFlags value is copied
523562306a36Sopenharmony_ci *
523662306a36Sopenharmony_ci * Return: trigger flags mask if HBA FW supports driver trigger pages;
523762306a36Sopenharmony_ci * otherwise returns %-EFAULT if driver trigger pages are not supported by FW or
523862306a36Sopenharmony_ci * return EAGAIN if diag reset occurred due to FW fault and asking the
523962306a36Sopenharmony_ci * caller to retry the command.
524062306a36Sopenharmony_ci *
524162306a36Sopenharmony_ci */
524262306a36Sopenharmony_cistatic int
524362306a36Sopenharmony_ci_base_check_for_trigger_pages_support(struct MPT3SAS_ADAPTER *ioc, u32 *trigger_flags)
524462306a36Sopenharmony_ci{
524562306a36Sopenharmony_ci	Mpi26DriverTriggerPage0_t trigger_pg0;
524662306a36Sopenharmony_ci	int r = 0;
524762306a36Sopenharmony_ci	Mpi2ConfigReply_t mpi_reply;
524862306a36Sopenharmony_ci	u16 ioc_status;
524962306a36Sopenharmony_ci
525062306a36Sopenharmony_ci	r = mpt3sas_config_get_driver_trigger_pg0(ioc, &mpi_reply,
525162306a36Sopenharmony_ci	    &trigger_pg0);
525262306a36Sopenharmony_ci	if (r)
525362306a36Sopenharmony_ci		return r;
525462306a36Sopenharmony_ci
525562306a36Sopenharmony_ci	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
525662306a36Sopenharmony_ci	    MPI2_IOCSTATUS_MASK;
525762306a36Sopenharmony_ci	if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
525862306a36Sopenharmony_ci		return -EFAULT;
525962306a36Sopenharmony_ci
526062306a36Sopenharmony_ci	*trigger_flags = le16_to_cpu(trigger_pg0.TriggerFlags);
526162306a36Sopenharmony_ci	return 0;
526262306a36Sopenharmony_ci}
526362306a36Sopenharmony_ci
526462306a36Sopenharmony_ci/**
526562306a36Sopenharmony_ci * _base_get_diag_triggers - Retrieve diag trigger values from
526662306a36Sopenharmony_ci *				persistent pages.
526762306a36Sopenharmony_ci * @ioc : per adapter object
526862306a36Sopenharmony_ci *
526962306a36Sopenharmony_ci * Return: zero on success; otherwise return EAGAIN error codes
527062306a36Sopenharmony_ci * asking the caller to retry.
527162306a36Sopenharmony_ci */
527262306a36Sopenharmony_cistatic int
527362306a36Sopenharmony_ci_base_get_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
527462306a36Sopenharmony_ci{
527562306a36Sopenharmony_ci	int trigger_flags;
527662306a36Sopenharmony_ci	int r;
527762306a36Sopenharmony_ci
527862306a36Sopenharmony_ci	/*
527962306a36Sopenharmony_ci	 * Default setting of master trigger.
528062306a36Sopenharmony_ci	 */
528162306a36Sopenharmony_ci	ioc->diag_trigger_master.MasterData =
528262306a36Sopenharmony_ci	    (MASTER_TRIGGER_FW_FAULT + MASTER_TRIGGER_ADAPTER_RESET);
528362306a36Sopenharmony_ci
528462306a36Sopenharmony_ci	r = _base_check_for_trigger_pages_support(ioc, &trigger_flags);
528562306a36Sopenharmony_ci	if (r) {
528662306a36Sopenharmony_ci		if (r == -EAGAIN)
528762306a36Sopenharmony_ci			return r;
528862306a36Sopenharmony_ci		/*
528962306a36Sopenharmony_ci		 * Don't go for error handling when FW doesn't support
529062306a36Sopenharmony_ci		 * driver trigger pages.
529162306a36Sopenharmony_ci		 */
529262306a36Sopenharmony_ci		return 0;
529362306a36Sopenharmony_ci	}
529462306a36Sopenharmony_ci
529562306a36Sopenharmony_ci	ioc->supports_trigger_pages = 1;
529662306a36Sopenharmony_ci
529762306a36Sopenharmony_ci	/*
529862306a36Sopenharmony_ci	 * Retrieve master diag trigger values from driver trigger pg1
529962306a36Sopenharmony_ci	 * if master trigger bit enabled in TriggerFlags.
530062306a36Sopenharmony_ci	 */
530162306a36Sopenharmony_ci	if ((u16)trigger_flags &
530262306a36Sopenharmony_ci	    MPI26_DRIVER_TRIGGER0_FLAG_MASTER_TRIGGER_VALID) {
530362306a36Sopenharmony_ci		r = _base_get_master_diag_triggers(ioc);
530462306a36Sopenharmony_ci		if (r)
530562306a36Sopenharmony_ci			return r;
530662306a36Sopenharmony_ci	}
530762306a36Sopenharmony_ci
530862306a36Sopenharmony_ci	/*
530962306a36Sopenharmony_ci	 * Retrieve event diag trigger values from driver trigger pg2
531062306a36Sopenharmony_ci	 * if event trigger bit enabled in TriggerFlags.
531162306a36Sopenharmony_ci	 */
531262306a36Sopenharmony_ci	if ((u16)trigger_flags &
531362306a36Sopenharmony_ci	    MPI26_DRIVER_TRIGGER0_FLAG_MPI_EVENT_TRIGGER_VALID) {
531462306a36Sopenharmony_ci		r = _base_get_event_diag_triggers(ioc);
531562306a36Sopenharmony_ci		if (r)
531662306a36Sopenharmony_ci			return r;
531762306a36Sopenharmony_ci	}
531862306a36Sopenharmony_ci
531962306a36Sopenharmony_ci	/*
532062306a36Sopenharmony_ci	 * Retrieve scsi diag trigger values from driver trigger pg3
532162306a36Sopenharmony_ci	 * if scsi trigger bit enabled in TriggerFlags.
532262306a36Sopenharmony_ci	 */
532362306a36Sopenharmony_ci	if ((u16)trigger_flags &
532462306a36Sopenharmony_ci	    MPI26_DRIVER_TRIGGER0_FLAG_SCSI_SENSE_TRIGGER_VALID) {
532562306a36Sopenharmony_ci		r = _base_get_scsi_diag_triggers(ioc);
532662306a36Sopenharmony_ci		if (r)
532762306a36Sopenharmony_ci			return r;
532862306a36Sopenharmony_ci	}
532962306a36Sopenharmony_ci	/*
533062306a36Sopenharmony_ci	 * Retrieve mpi error diag trigger values from driver trigger pg4
533162306a36Sopenharmony_ci	 * if loginfo trigger bit enabled in TriggerFlags.
533262306a36Sopenharmony_ci	 */
533362306a36Sopenharmony_ci	if ((u16)trigger_flags &
533462306a36Sopenharmony_ci	    MPI26_DRIVER_TRIGGER0_FLAG_LOGINFO_TRIGGER_VALID) {
533562306a36Sopenharmony_ci		r = _base_get_mpi_diag_triggers(ioc);
533662306a36Sopenharmony_ci		if (r)
533762306a36Sopenharmony_ci			return r;
533862306a36Sopenharmony_ci	}
533962306a36Sopenharmony_ci	return 0;
534062306a36Sopenharmony_ci}
534162306a36Sopenharmony_ci
534262306a36Sopenharmony_ci/**
534362306a36Sopenharmony_ci * _base_update_diag_trigger_pages - Update the driver trigger pages after
534462306a36Sopenharmony_ci *			online FW update, in case updated FW supports driver
534562306a36Sopenharmony_ci *			trigger pages.
534662306a36Sopenharmony_ci * @ioc : per adapter object
534762306a36Sopenharmony_ci *
534862306a36Sopenharmony_ci * Return: nothing.
534962306a36Sopenharmony_ci */
535062306a36Sopenharmony_cistatic void
535162306a36Sopenharmony_ci_base_update_diag_trigger_pages(struct MPT3SAS_ADAPTER *ioc)
535262306a36Sopenharmony_ci{
535362306a36Sopenharmony_ci
535462306a36Sopenharmony_ci	if (ioc->diag_trigger_master.MasterData)
535562306a36Sopenharmony_ci		mpt3sas_config_update_driver_trigger_pg1(ioc,
535662306a36Sopenharmony_ci		    &ioc->diag_trigger_master, 1);
535762306a36Sopenharmony_ci
535862306a36Sopenharmony_ci	if (ioc->diag_trigger_event.ValidEntries)
535962306a36Sopenharmony_ci		mpt3sas_config_update_driver_trigger_pg2(ioc,
536062306a36Sopenharmony_ci		    &ioc->diag_trigger_event, 1);
536162306a36Sopenharmony_ci
536262306a36Sopenharmony_ci	if (ioc->diag_trigger_scsi.ValidEntries)
536362306a36Sopenharmony_ci		mpt3sas_config_update_driver_trigger_pg3(ioc,
536462306a36Sopenharmony_ci		    &ioc->diag_trigger_scsi, 1);
536562306a36Sopenharmony_ci
536662306a36Sopenharmony_ci	if (ioc->diag_trigger_mpi.ValidEntries)
536762306a36Sopenharmony_ci		mpt3sas_config_update_driver_trigger_pg4(ioc,
536862306a36Sopenharmony_ci		    &ioc->diag_trigger_mpi, 1);
536962306a36Sopenharmony_ci}
537062306a36Sopenharmony_ci
537162306a36Sopenharmony_ci/**
537262306a36Sopenharmony_ci * _base_assign_fw_reported_qd	- Get FW reported QD for SAS/SATA devices.
537362306a36Sopenharmony_ci *				- On failure set default QD values.
537462306a36Sopenharmony_ci * @ioc : per adapter object
537562306a36Sopenharmony_ci *
537662306a36Sopenharmony_ci * Returns 0 for success, non-zero for failure.
537762306a36Sopenharmony_ci *
537862306a36Sopenharmony_ci */
537962306a36Sopenharmony_cistatic int _base_assign_fw_reported_qd(struct MPT3SAS_ADAPTER *ioc)
538062306a36Sopenharmony_ci{
538162306a36Sopenharmony_ci	Mpi2ConfigReply_t mpi_reply;
538262306a36Sopenharmony_ci	Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
538362306a36Sopenharmony_ci	Mpi26PCIeIOUnitPage1_t pcie_iounit_pg1;
538462306a36Sopenharmony_ci	u16 depth;
538562306a36Sopenharmony_ci	int sz;
538662306a36Sopenharmony_ci	int rc = 0;
538762306a36Sopenharmony_ci
538862306a36Sopenharmony_ci	ioc->max_wideport_qd = MPT3SAS_SAS_QUEUE_DEPTH;
538962306a36Sopenharmony_ci	ioc->max_narrowport_qd = MPT3SAS_SAS_QUEUE_DEPTH;
539062306a36Sopenharmony_ci	ioc->max_sata_qd = MPT3SAS_SATA_QUEUE_DEPTH;
539162306a36Sopenharmony_ci	ioc->max_nvme_qd = MPT3SAS_NVME_QUEUE_DEPTH;
539262306a36Sopenharmony_ci	if (!ioc->is_gen35_ioc)
539362306a36Sopenharmony_ci		goto out;
539462306a36Sopenharmony_ci	/* sas iounit page 1 */
539562306a36Sopenharmony_ci	sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData);
539662306a36Sopenharmony_ci	sas_iounit_pg1 = kzalloc(sizeof(Mpi2SasIOUnitPage1_t), GFP_KERNEL);
539762306a36Sopenharmony_ci	if (!sas_iounit_pg1) {
539862306a36Sopenharmony_ci		pr_err("%s: failure at %s:%d/%s()!\n",
539962306a36Sopenharmony_ci		    ioc->name, __FILE__, __LINE__, __func__);
540062306a36Sopenharmony_ci		return rc;
540162306a36Sopenharmony_ci	}
540262306a36Sopenharmony_ci	rc = mpt3sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
540362306a36Sopenharmony_ci	    sas_iounit_pg1, sz);
540462306a36Sopenharmony_ci	if (rc) {
540562306a36Sopenharmony_ci		pr_err("%s: failure at %s:%d/%s()!\n",
540662306a36Sopenharmony_ci		    ioc->name, __FILE__, __LINE__, __func__);
540762306a36Sopenharmony_ci		goto out;
540862306a36Sopenharmony_ci	}
540962306a36Sopenharmony_ci
541062306a36Sopenharmony_ci	depth = le16_to_cpu(sas_iounit_pg1->SASWideMaxQueueDepth);
541162306a36Sopenharmony_ci	ioc->max_wideport_qd = (depth ? depth : MPT3SAS_SAS_QUEUE_DEPTH);
541262306a36Sopenharmony_ci
541362306a36Sopenharmony_ci	depth = le16_to_cpu(sas_iounit_pg1->SASNarrowMaxQueueDepth);
541462306a36Sopenharmony_ci	ioc->max_narrowport_qd = (depth ? depth : MPT3SAS_SAS_QUEUE_DEPTH);
541562306a36Sopenharmony_ci
541662306a36Sopenharmony_ci	depth = sas_iounit_pg1->SATAMaxQDepth;
541762306a36Sopenharmony_ci	ioc->max_sata_qd = (depth ? depth : MPT3SAS_SATA_QUEUE_DEPTH);
541862306a36Sopenharmony_ci
541962306a36Sopenharmony_ci	/* pcie iounit page 1 */
542062306a36Sopenharmony_ci	rc = mpt3sas_config_get_pcie_iounit_pg1(ioc, &mpi_reply,
542162306a36Sopenharmony_ci	    &pcie_iounit_pg1, sizeof(Mpi26PCIeIOUnitPage1_t));
542262306a36Sopenharmony_ci	if (rc) {
542362306a36Sopenharmony_ci		pr_err("%s: failure at %s:%d/%s()!\n",
542462306a36Sopenharmony_ci		    ioc->name, __FILE__, __LINE__, __func__);
542562306a36Sopenharmony_ci		goto out;
542662306a36Sopenharmony_ci	}
542762306a36Sopenharmony_ci	ioc->max_nvme_qd = (le16_to_cpu(pcie_iounit_pg1.NVMeMaxQueueDepth)) ?
542862306a36Sopenharmony_ci	    (le16_to_cpu(pcie_iounit_pg1.NVMeMaxQueueDepth)) :
542962306a36Sopenharmony_ci	    MPT3SAS_NVME_QUEUE_DEPTH;
543062306a36Sopenharmony_ciout:
543162306a36Sopenharmony_ci	dinitprintk(ioc, pr_err(
543262306a36Sopenharmony_ci	    "MaxWidePortQD: 0x%x MaxNarrowPortQD: 0x%x MaxSataQD: 0x%x MaxNvmeQD: 0x%x\n",
543362306a36Sopenharmony_ci	    ioc->max_wideport_qd, ioc->max_narrowport_qd,
543462306a36Sopenharmony_ci	    ioc->max_sata_qd, ioc->max_nvme_qd));
543562306a36Sopenharmony_ci	kfree(sas_iounit_pg1);
543662306a36Sopenharmony_ci	return rc;
543762306a36Sopenharmony_ci}
543862306a36Sopenharmony_ci
543962306a36Sopenharmony_ci/**
544062306a36Sopenharmony_ci * mpt3sas_atto_validate_nvram - validate the ATTO nvram read from mfg pg1
544162306a36Sopenharmony_ci *
544262306a36Sopenharmony_ci * @ioc : per adapter object
544362306a36Sopenharmony_ci * @n   : ptr to the ATTO nvram structure
544462306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
544562306a36Sopenharmony_ci */
544662306a36Sopenharmony_cistatic int
544762306a36Sopenharmony_cimpt3sas_atto_validate_nvram(struct MPT3SAS_ADAPTER *ioc,
544862306a36Sopenharmony_ci			    struct ATTO_SAS_NVRAM *n)
544962306a36Sopenharmony_ci{
545062306a36Sopenharmony_ci	int r = -EINVAL;
545162306a36Sopenharmony_ci	union ATTO_SAS_ADDRESS *s1;
545262306a36Sopenharmony_ci	u32 len;
545362306a36Sopenharmony_ci	u8 *pb;
545462306a36Sopenharmony_ci	u8 ckSum;
545562306a36Sopenharmony_ci
545662306a36Sopenharmony_ci	/* validate nvram checksum */
545762306a36Sopenharmony_ci	pb = (u8 *) n;
545862306a36Sopenharmony_ci	ckSum = ATTO_SASNVR_CKSUM_SEED;
545962306a36Sopenharmony_ci	len = sizeof(struct ATTO_SAS_NVRAM);
546062306a36Sopenharmony_ci
546162306a36Sopenharmony_ci	while (len--)
546262306a36Sopenharmony_ci		ckSum = ckSum + pb[len];
546362306a36Sopenharmony_ci
546462306a36Sopenharmony_ci	if (ckSum) {
546562306a36Sopenharmony_ci		ioc_err(ioc, "Invalid ATTO NVRAM checksum\n");
546662306a36Sopenharmony_ci		return r;
546762306a36Sopenharmony_ci	}
546862306a36Sopenharmony_ci
546962306a36Sopenharmony_ci	s1 = (union ATTO_SAS_ADDRESS *) n->SasAddr;
547062306a36Sopenharmony_ci
547162306a36Sopenharmony_ci	if (n->Signature[0] != 'E'
547262306a36Sopenharmony_ci	|| n->Signature[1] != 'S'
547362306a36Sopenharmony_ci	|| n->Signature[2] != 'A'
547462306a36Sopenharmony_ci	|| n->Signature[3] != 'S')
547562306a36Sopenharmony_ci		ioc_err(ioc, "Invalid ATTO NVRAM signature\n");
547662306a36Sopenharmony_ci	else if (n->Version > ATTO_SASNVR_VERSION)
547762306a36Sopenharmony_ci		ioc_info(ioc, "Invalid ATTO NVRAM version");
547862306a36Sopenharmony_ci	else if ((n->SasAddr[7] & (ATTO_SAS_ADDR_ALIGN - 1))
547962306a36Sopenharmony_ci			|| s1->b[0] != 0x50
548062306a36Sopenharmony_ci			|| s1->b[1] != 0x01
548162306a36Sopenharmony_ci			|| s1->b[2] != 0x08
548262306a36Sopenharmony_ci			|| (s1->b[3] & 0xF0) != 0x60
548362306a36Sopenharmony_ci			|| ((s1->b[3] & 0x0F) | le32_to_cpu(s1->d[1])) == 0) {
548462306a36Sopenharmony_ci		ioc_err(ioc, "Invalid ATTO SAS address\n");
548562306a36Sopenharmony_ci	} else
548662306a36Sopenharmony_ci		r = 0;
548762306a36Sopenharmony_ci	return r;
548862306a36Sopenharmony_ci}
548962306a36Sopenharmony_ci
549062306a36Sopenharmony_ci/**
549162306a36Sopenharmony_ci * mpt3sas_atto_get_sas_addr - get the ATTO SAS address from mfg page 1
549262306a36Sopenharmony_ci *
549362306a36Sopenharmony_ci * @ioc : per adapter object
549462306a36Sopenharmony_ci * @*sas_addr : return sas address
549562306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
549662306a36Sopenharmony_ci */
549762306a36Sopenharmony_cistatic int
549862306a36Sopenharmony_cimpt3sas_atto_get_sas_addr(struct MPT3SAS_ADAPTER *ioc, union ATTO_SAS_ADDRESS *sas_addr)
549962306a36Sopenharmony_ci{
550062306a36Sopenharmony_ci	Mpi2ManufacturingPage1_t mfg_pg1;
550162306a36Sopenharmony_ci	Mpi2ConfigReply_t mpi_reply;
550262306a36Sopenharmony_ci	struct ATTO_SAS_NVRAM *nvram;
550362306a36Sopenharmony_ci	int r;
550462306a36Sopenharmony_ci	__be64 addr;
550562306a36Sopenharmony_ci
550662306a36Sopenharmony_ci	r = mpt3sas_config_get_manufacturing_pg1(ioc, &mpi_reply, &mfg_pg1);
550762306a36Sopenharmony_ci	if (r) {
550862306a36Sopenharmony_ci		ioc_err(ioc, "Failed to read manufacturing page 1\n");
550962306a36Sopenharmony_ci		return r;
551062306a36Sopenharmony_ci	}
551162306a36Sopenharmony_ci
551262306a36Sopenharmony_ci	/* validate nvram */
551362306a36Sopenharmony_ci	nvram = (struct ATTO_SAS_NVRAM *) mfg_pg1.VPD;
551462306a36Sopenharmony_ci	r = mpt3sas_atto_validate_nvram(ioc, nvram);
551562306a36Sopenharmony_ci	if (r)
551662306a36Sopenharmony_ci		return r;
551762306a36Sopenharmony_ci
551862306a36Sopenharmony_ci	addr = *((__be64 *) nvram->SasAddr);
551962306a36Sopenharmony_ci	sas_addr->q = cpu_to_le64(be64_to_cpu(addr));
552062306a36Sopenharmony_ci	return r;
552162306a36Sopenharmony_ci}
552262306a36Sopenharmony_ci
552362306a36Sopenharmony_ci/**
552462306a36Sopenharmony_ci * mpt3sas_atto_init - perform initializaion for ATTO branded
552562306a36Sopenharmony_ci *					adapter.
552662306a36Sopenharmony_ci * @ioc : per adapter object
552762306a36Sopenharmony_ci *5
552862306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
552962306a36Sopenharmony_ci */
553062306a36Sopenharmony_cistatic int
553162306a36Sopenharmony_cimpt3sas_atto_init(struct MPT3SAS_ADAPTER *ioc)
553262306a36Sopenharmony_ci{
553362306a36Sopenharmony_ci	int sz = 0;
553462306a36Sopenharmony_ci	Mpi2BiosPage4_t *bios_pg4 = NULL;
553562306a36Sopenharmony_ci	Mpi2ConfigReply_t mpi_reply;
553662306a36Sopenharmony_ci	int r;
553762306a36Sopenharmony_ci	int ix;
553862306a36Sopenharmony_ci	union ATTO_SAS_ADDRESS sas_addr;
553962306a36Sopenharmony_ci	union ATTO_SAS_ADDRESS temp;
554062306a36Sopenharmony_ci	union ATTO_SAS_ADDRESS bias;
554162306a36Sopenharmony_ci
554262306a36Sopenharmony_ci	r = mpt3sas_atto_get_sas_addr(ioc, &sas_addr);
554362306a36Sopenharmony_ci	if (r)
554462306a36Sopenharmony_ci		return r;
554562306a36Sopenharmony_ci
554662306a36Sopenharmony_ci	/* get header first to get size */
554762306a36Sopenharmony_ci	r = mpt3sas_config_get_bios_pg4(ioc, &mpi_reply, NULL, 0);
554862306a36Sopenharmony_ci	if (r) {
554962306a36Sopenharmony_ci		ioc_err(ioc, "Failed to read ATTO bios page 4 header.\n");
555062306a36Sopenharmony_ci		return r;
555162306a36Sopenharmony_ci	}
555262306a36Sopenharmony_ci
555362306a36Sopenharmony_ci	sz = mpi_reply.Header.PageLength * sizeof(u32);
555462306a36Sopenharmony_ci	bios_pg4 = kzalloc(sz, GFP_KERNEL);
555562306a36Sopenharmony_ci	if (!bios_pg4) {
555662306a36Sopenharmony_ci		ioc_err(ioc, "Failed to allocate memory for ATTO bios page.\n");
555762306a36Sopenharmony_ci		return -ENOMEM;
555862306a36Sopenharmony_ci	}
555962306a36Sopenharmony_ci
556062306a36Sopenharmony_ci	/* read bios page 4 */
556162306a36Sopenharmony_ci	r = mpt3sas_config_get_bios_pg4(ioc, &mpi_reply, bios_pg4, sz);
556262306a36Sopenharmony_ci	if (r) {
556362306a36Sopenharmony_ci		ioc_err(ioc, "Failed to read ATTO bios page 4\n");
556462306a36Sopenharmony_ci		goto out;
556562306a36Sopenharmony_ci	}
556662306a36Sopenharmony_ci
556762306a36Sopenharmony_ci	/* Update bios page 4 with the ATTO WWID */
556862306a36Sopenharmony_ci	bias.q = sas_addr.q;
556962306a36Sopenharmony_ci	bias.b[7] += ATTO_SAS_ADDR_DEVNAME_BIAS;
557062306a36Sopenharmony_ci
557162306a36Sopenharmony_ci	for (ix = 0; ix < bios_pg4->NumPhys; ix++) {
557262306a36Sopenharmony_ci		temp.q = sas_addr.q;
557362306a36Sopenharmony_ci		temp.b[7] += ix;
557462306a36Sopenharmony_ci		bios_pg4->Phy[ix].ReassignmentWWID = temp.q;
557562306a36Sopenharmony_ci		bios_pg4->Phy[ix].ReassignmentDeviceName = bias.q;
557662306a36Sopenharmony_ci	}
557762306a36Sopenharmony_ci	r = mpt3sas_config_set_bios_pg4(ioc, &mpi_reply, bios_pg4, sz);
557862306a36Sopenharmony_ci
557962306a36Sopenharmony_ciout:
558062306a36Sopenharmony_ci	kfree(bios_pg4);
558162306a36Sopenharmony_ci	return r;
558262306a36Sopenharmony_ci}
558362306a36Sopenharmony_ci
558462306a36Sopenharmony_ci/**
558562306a36Sopenharmony_ci * _base_static_config_pages - static start of day config pages
558662306a36Sopenharmony_ci * @ioc: per adapter object
558762306a36Sopenharmony_ci */
558862306a36Sopenharmony_cistatic int
558962306a36Sopenharmony_ci_base_static_config_pages(struct MPT3SAS_ADAPTER *ioc)
559062306a36Sopenharmony_ci{
559162306a36Sopenharmony_ci	Mpi2ConfigReply_t mpi_reply;
559262306a36Sopenharmony_ci	u32 iounit_pg1_flags;
559362306a36Sopenharmony_ci	int tg_flags = 0;
559462306a36Sopenharmony_ci	int rc;
559562306a36Sopenharmony_ci	ioc->nvme_abort_timeout = 30;
559662306a36Sopenharmony_ci
559762306a36Sopenharmony_ci	rc = mpt3sas_config_get_manufacturing_pg0(ioc, &mpi_reply,
559862306a36Sopenharmony_ci	    &ioc->manu_pg0);
559962306a36Sopenharmony_ci	if (rc)
560062306a36Sopenharmony_ci		return rc;
560162306a36Sopenharmony_ci	if (ioc->ir_firmware) {
560262306a36Sopenharmony_ci		rc = mpt3sas_config_get_manufacturing_pg10(ioc, &mpi_reply,
560362306a36Sopenharmony_ci		    &ioc->manu_pg10);
560462306a36Sopenharmony_ci		if (rc)
560562306a36Sopenharmony_ci			return rc;
560662306a36Sopenharmony_ci	}
560762306a36Sopenharmony_ci
560862306a36Sopenharmony_ci	if (ioc->pdev->vendor == MPI2_MFGPAGE_VENDORID_ATTO) {
560962306a36Sopenharmony_ci		rc = mpt3sas_atto_init(ioc);
561062306a36Sopenharmony_ci		if (rc)
561162306a36Sopenharmony_ci			return rc;
561262306a36Sopenharmony_ci	}
561362306a36Sopenharmony_ci
561462306a36Sopenharmony_ci	/*
561562306a36Sopenharmony_ci	 * Ensure correct T10 PI operation if vendor left EEDPTagMode
561662306a36Sopenharmony_ci	 * flag unset in NVDATA.
561762306a36Sopenharmony_ci	 */
561862306a36Sopenharmony_ci	rc = mpt3sas_config_get_manufacturing_pg11(ioc, &mpi_reply,
561962306a36Sopenharmony_ci	    &ioc->manu_pg11);
562062306a36Sopenharmony_ci	if (rc)
562162306a36Sopenharmony_ci		return rc;
562262306a36Sopenharmony_ci	if (!ioc->is_gen35_ioc && ioc->manu_pg11.EEDPTagMode == 0) {
562362306a36Sopenharmony_ci		pr_err("%s: overriding NVDATA EEDPTagMode setting\n",
562462306a36Sopenharmony_ci		    ioc->name);
562562306a36Sopenharmony_ci		ioc->manu_pg11.EEDPTagMode &= ~0x3;
562662306a36Sopenharmony_ci		ioc->manu_pg11.EEDPTagMode |= 0x1;
562762306a36Sopenharmony_ci		mpt3sas_config_set_manufacturing_pg11(ioc, &mpi_reply,
562862306a36Sopenharmony_ci		    &ioc->manu_pg11);
562962306a36Sopenharmony_ci	}
563062306a36Sopenharmony_ci	if (ioc->manu_pg11.AddlFlags2 & NVME_TASK_MNGT_CUSTOM_MASK)
563162306a36Sopenharmony_ci		ioc->tm_custom_handling = 1;
563262306a36Sopenharmony_ci	else {
563362306a36Sopenharmony_ci		ioc->tm_custom_handling = 0;
563462306a36Sopenharmony_ci		if (ioc->manu_pg11.NVMeAbortTO < NVME_TASK_ABORT_MIN_TIMEOUT)
563562306a36Sopenharmony_ci			ioc->nvme_abort_timeout = NVME_TASK_ABORT_MIN_TIMEOUT;
563662306a36Sopenharmony_ci		else if (ioc->manu_pg11.NVMeAbortTO >
563762306a36Sopenharmony_ci					NVME_TASK_ABORT_MAX_TIMEOUT)
563862306a36Sopenharmony_ci			ioc->nvme_abort_timeout = NVME_TASK_ABORT_MAX_TIMEOUT;
563962306a36Sopenharmony_ci		else
564062306a36Sopenharmony_ci			ioc->nvme_abort_timeout = ioc->manu_pg11.NVMeAbortTO;
564162306a36Sopenharmony_ci	}
564262306a36Sopenharmony_ci	ioc->time_sync_interval =
564362306a36Sopenharmony_ci	    ioc->manu_pg11.TimeSyncInterval & MPT3SAS_TIMESYNC_MASK;
564462306a36Sopenharmony_ci	if (ioc->time_sync_interval) {
564562306a36Sopenharmony_ci		if (ioc->manu_pg11.TimeSyncInterval & MPT3SAS_TIMESYNC_UNIT_MASK)
564662306a36Sopenharmony_ci			ioc->time_sync_interval =
564762306a36Sopenharmony_ci			    ioc->time_sync_interval * SECONDS_PER_HOUR;
564862306a36Sopenharmony_ci		else
564962306a36Sopenharmony_ci			ioc->time_sync_interval =
565062306a36Sopenharmony_ci			    ioc->time_sync_interval * SECONDS_PER_MIN;
565162306a36Sopenharmony_ci		dinitprintk(ioc, ioc_info(ioc,
565262306a36Sopenharmony_ci		    "Driver-FW TimeSync interval is %d seconds. ManuPg11 TimeSync Unit is in %s\n",
565362306a36Sopenharmony_ci		    ioc->time_sync_interval, (ioc->manu_pg11.TimeSyncInterval &
565462306a36Sopenharmony_ci		    MPT3SAS_TIMESYNC_UNIT_MASK) ? "Hour" : "Minute"));
565562306a36Sopenharmony_ci	} else {
565662306a36Sopenharmony_ci		if (ioc->is_gen35_ioc)
565762306a36Sopenharmony_ci			ioc_warn(ioc,
565862306a36Sopenharmony_ci			    "TimeSync Interval in Manuf page-11 is not enabled. Periodic Time-Sync will be disabled\n");
565962306a36Sopenharmony_ci	}
566062306a36Sopenharmony_ci	rc = _base_assign_fw_reported_qd(ioc);
566162306a36Sopenharmony_ci	if (rc)
566262306a36Sopenharmony_ci		return rc;
566362306a36Sopenharmony_ci
566462306a36Sopenharmony_ci	/*
566562306a36Sopenharmony_ci	 * ATTO doesn't use bios page 2 and 3 for bios settings.
566662306a36Sopenharmony_ci	 */
566762306a36Sopenharmony_ci	if (ioc->pdev->vendor ==  MPI2_MFGPAGE_VENDORID_ATTO)
566862306a36Sopenharmony_ci		ioc->bios_pg3.BiosVersion = 0;
566962306a36Sopenharmony_ci	else {
567062306a36Sopenharmony_ci		rc = mpt3sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2);
567162306a36Sopenharmony_ci		if (rc)
567262306a36Sopenharmony_ci			return rc;
567362306a36Sopenharmony_ci		rc = mpt3sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3);
567462306a36Sopenharmony_ci		if (rc)
567562306a36Sopenharmony_ci			return rc;
567662306a36Sopenharmony_ci	}
567762306a36Sopenharmony_ci
567862306a36Sopenharmony_ci	rc = mpt3sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8);
567962306a36Sopenharmony_ci	if (rc)
568062306a36Sopenharmony_ci		return rc;
568162306a36Sopenharmony_ci	rc = mpt3sas_config_get_iounit_pg0(ioc, &mpi_reply, &ioc->iounit_pg0);
568262306a36Sopenharmony_ci	if (rc)
568362306a36Sopenharmony_ci		return rc;
568462306a36Sopenharmony_ci	rc = mpt3sas_config_get_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1);
568562306a36Sopenharmony_ci	if (rc)
568662306a36Sopenharmony_ci		return rc;
568762306a36Sopenharmony_ci	rc = mpt3sas_config_get_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8);
568862306a36Sopenharmony_ci	if (rc)
568962306a36Sopenharmony_ci		return rc;
569062306a36Sopenharmony_ci	_base_display_ioc_capabilities(ioc);
569162306a36Sopenharmony_ci
569262306a36Sopenharmony_ci	/*
569362306a36Sopenharmony_ci	 * Enable task_set_full handling in iounit_pg1 when the
569462306a36Sopenharmony_ci	 * facts capabilities indicate that its supported.
569562306a36Sopenharmony_ci	 */
569662306a36Sopenharmony_ci	iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags);
569762306a36Sopenharmony_ci	if ((ioc->facts.IOCCapabilities &
569862306a36Sopenharmony_ci	    MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING))
569962306a36Sopenharmony_ci		iounit_pg1_flags &=
570062306a36Sopenharmony_ci		    ~MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING;
570162306a36Sopenharmony_ci	else
570262306a36Sopenharmony_ci		iounit_pg1_flags |=
570362306a36Sopenharmony_ci		    MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING;
570462306a36Sopenharmony_ci	ioc->iounit_pg1.Flags = cpu_to_le32(iounit_pg1_flags);
570562306a36Sopenharmony_ci	rc = mpt3sas_config_set_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1);
570662306a36Sopenharmony_ci	if (rc)
570762306a36Sopenharmony_ci		return rc;
570862306a36Sopenharmony_ci
570962306a36Sopenharmony_ci	if (ioc->iounit_pg8.NumSensors)
571062306a36Sopenharmony_ci		ioc->temp_sensors_count = ioc->iounit_pg8.NumSensors;
571162306a36Sopenharmony_ci	if (ioc->is_aero_ioc) {
571262306a36Sopenharmony_ci		rc = _base_update_ioc_page1_inlinewith_perf_mode(ioc);
571362306a36Sopenharmony_ci		if (rc)
571462306a36Sopenharmony_ci			return rc;
571562306a36Sopenharmony_ci	}
571662306a36Sopenharmony_ci	if (ioc->is_gen35_ioc) {
571762306a36Sopenharmony_ci		if (ioc->is_driver_loading) {
571862306a36Sopenharmony_ci			rc = _base_get_diag_triggers(ioc);
571962306a36Sopenharmony_ci			if (rc)
572062306a36Sopenharmony_ci				return rc;
572162306a36Sopenharmony_ci		} else {
572262306a36Sopenharmony_ci			/*
572362306a36Sopenharmony_ci			 * In case of online HBA FW update operation,
572462306a36Sopenharmony_ci			 * check whether updated FW supports the driver trigger
572562306a36Sopenharmony_ci			 * pages or not.
572662306a36Sopenharmony_ci			 * - If previous FW has not supported driver trigger
572762306a36Sopenharmony_ci			 *   pages and newer FW supports them then update these
572862306a36Sopenharmony_ci			 *   pages with current diag trigger values.
572962306a36Sopenharmony_ci			 * - If previous FW has supported driver trigger pages
573062306a36Sopenharmony_ci			 *   and new FW doesn't support them then disable
573162306a36Sopenharmony_ci			 *   support_trigger_pages flag.
573262306a36Sopenharmony_ci			 */
573362306a36Sopenharmony_ci			_base_check_for_trigger_pages_support(ioc, &tg_flags);
573462306a36Sopenharmony_ci			if (!ioc->supports_trigger_pages && tg_flags != -EFAULT)
573562306a36Sopenharmony_ci				_base_update_diag_trigger_pages(ioc);
573662306a36Sopenharmony_ci			else if (ioc->supports_trigger_pages &&
573762306a36Sopenharmony_ci			    tg_flags == -EFAULT)
573862306a36Sopenharmony_ci				ioc->supports_trigger_pages = 0;
573962306a36Sopenharmony_ci		}
574062306a36Sopenharmony_ci	}
574162306a36Sopenharmony_ci	return 0;
574262306a36Sopenharmony_ci}
574362306a36Sopenharmony_ci
574462306a36Sopenharmony_ci/**
574562306a36Sopenharmony_ci * mpt3sas_free_enclosure_list - release memory
574662306a36Sopenharmony_ci * @ioc: per adapter object
574762306a36Sopenharmony_ci *
574862306a36Sopenharmony_ci * Free memory allocated during enclosure add.
574962306a36Sopenharmony_ci */
575062306a36Sopenharmony_civoid
575162306a36Sopenharmony_cimpt3sas_free_enclosure_list(struct MPT3SAS_ADAPTER *ioc)
575262306a36Sopenharmony_ci{
575362306a36Sopenharmony_ci	struct _enclosure_node *enclosure_dev, *enclosure_dev_next;
575462306a36Sopenharmony_ci
575562306a36Sopenharmony_ci	/* Free enclosure list */
575662306a36Sopenharmony_ci	list_for_each_entry_safe(enclosure_dev,
575762306a36Sopenharmony_ci			enclosure_dev_next, &ioc->enclosure_list, list) {
575862306a36Sopenharmony_ci		list_del(&enclosure_dev->list);
575962306a36Sopenharmony_ci		kfree(enclosure_dev);
576062306a36Sopenharmony_ci	}
576162306a36Sopenharmony_ci}
576262306a36Sopenharmony_ci
576362306a36Sopenharmony_ci/**
576462306a36Sopenharmony_ci * _base_release_memory_pools - release memory
576562306a36Sopenharmony_ci * @ioc: per adapter object
576662306a36Sopenharmony_ci *
576762306a36Sopenharmony_ci * Free memory allocated from _base_allocate_memory_pools.
576862306a36Sopenharmony_ci */
576962306a36Sopenharmony_cistatic void
577062306a36Sopenharmony_ci_base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc)
577162306a36Sopenharmony_ci{
577262306a36Sopenharmony_ci	int i = 0;
577362306a36Sopenharmony_ci	int j = 0;
577462306a36Sopenharmony_ci	int dma_alloc_count = 0;
577562306a36Sopenharmony_ci	struct chain_tracker *ct;
577662306a36Sopenharmony_ci	int count = ioc->rdpq_array_enable ? ioc->reply_queue_count : 1;
577762306a36Sopenharmony_ci
577862306a36Sopenharmony_ci	dexitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
577962306a36Sopenharmony_ci
578062306a36Sopenharmony_ci	if (ioc->request) {
578162306a36Sopenharmony_ci		dma_free_coherent(&ioc->pdev->dev, ioc->request_dma_sz,
578262306a36Sopenharmony_ci		    ioc->request,  ioc->request_dma);
578362306a36Sopenharmony_ci		dexitprintk(ioc,
578462306a36Sopenharmony_ci			    ioc_info(ioc, "request_pool(0x%p): free\n",
578562306a36Sopenharmony_ci				     ioc->request));
578662306a36Sopenharmony_ci		ioc->request = NULL;
578762306a36Sopenharmony_ci	}
578862306a36Sopenharmony_ci
578962306a36Sopenharmony_ci	if (ioc->sense) {
579062306a36Sopenharmony_ci		dma_pool_free(ioc->sense_dma_pool, ioc->sense, ioc->sense_dma);
579162306a36Sopenharmony_ci		dma_pool_destroy(ioc->sense_dma_pool);
579262306a36Sopenharmony_ci		dexitprintk(ioc,
579362306a36Sopenharmony_ci			    ioc_info(ioc, "sense_pool(0x%p): free\n",
579462306a36Sopenharmony_ci				     ioc->sense));
579562306a36Sopenharmony_ci		ioc->sense = NULL;
579662306a36Sopenharmony_ci	}
579762306a36Sopenharmony_ci
579862306a36Sopenharmony_ci	if (ioc->reply) {
579962306a36Sopenharmony_ci		dma_pool_free(ioc->reply_dma_pool, ioc->reply, ioc->reply_dma);
580062306a36Sopenharmony_ci		dma_pool_destroy(ioc->reply_dma_pool);
580162306a36Sopenharmony_ci		dexitprintk(ioc,
580262306a36Sopenharmony_ci			    ioc_info(ioc, "reply_pool(0x%p): free\n",
580362306a36Sopenharmony_ci				     ioc->reply));
580462306a36Sopenharmony_ci		ioc->reply = NULL;
580562306a36Sopenharmony_ci	}
580662306a36Sopenharmony_ci
580762306a36Sopenharmony_ci	if (ioc->reply_free) {
580862306a36Sopenharmony_ci		dma_pool_free(ioc->reply_free_dma_pool, ioc->reply_free,
580962306a36Sopenharmony_ci		    ioc->reply_free_dma);
581062306a36Sopenharmony_ci		dma_pool_destroy(ioc->reply_free_dma_pool);
581162306a36Sopenharmony_ci		dexitprintk(ioc,
581262306a36Sopenharmony_ci			    ioc_info(ioc, "reply_free_pool(0x%p): free\n",
581362306a36Sopenharmony_ci				     ioc->reply_free));
581462306a36Sopenharmony_ci		ioc->reply_free = NULL;
581562306a36Sopenharmony_ci	}
581662306a36Sopenharmony_ci
581762306a36Sopenharmony_ci	if (ioc->reply_post) {
581862306a36Sopenharmony_ci		dma_alloc_count = DIV_ROUND_UP(count,
581962306a36Sopenharmony_ci				RDPQ_MAX_INDEX_IN_ONE_CHUNK);
582062306a36Sopenharmony_ci		for (i = 0; i < count; i++) {
582162306a36Sopenharmony_ci			if (i % RDPQ_MAX_INDEX_IN_ONE_CHUNK == 0
582262306a36Sopenharmony_ci			    && dma_alloc_count) {
582362306a36Sopenharmony_ci				if (ioc->reply_post[i].reply_post_free) {
582462306a36Sopenharmony_ci					dma_pool_free(
582562306a36Sopenharmony_ci					    ioc->reply_post_free_dma_pool,
582662306a36Sopenharmony_ci					    ioc->reply_post[i].reply_post_free,
582762306a36Sopenharmony_ci					ioc->reply_post[i].reply_post_free_dma);
582862306a36Sopenharmony_ci					dexitprintk(ioc, ioc_info(ioc,
582962306a36Sopenharmony_ci					   "reply_post_free_pool(0x%p): free\n",
583062306a36Sopenharmony_ci					   ioc->reply_post[i].reply_post_free));
583162306a36Sopenharmony_ci					ioc->reply_post[i].reply_post_free =
583262306a36Sopenharmony_ci									NULL;
583362306a36Sopenharmony_ci				}
583462306a36Sopenharmony_ci				--dma_alloc_count;
583562306a36Sopenharmony_ci			}
583662306a36Sopenharmony_ci		}
583762306a36Sopenharmony_ci		dma_pool_destroy(ioc->reply_post_free_dma_pool);
583862306a36Sopenharmony_ci		if (ioc->reply_post_free_array &&
583962306a36Sopenharmony_ci			ioc->rdpq_array_enable) {
584062306a36Sopenharmony_ci			dma_pool_free(ioc->reply_post_free_array_dma_pool,
584162306a36Sopenharmony_ci			    ioc->reply_post_free_array,
584262306a36Sopenharmony_ci			    ioc->reply_post_free_array_dma);
584362306a36Sopenharmony_ci			ioc->reply_post_free_array = NULL;
584462306a36Sopenharmony_ci		}
584562306a36Sopenharmony_ci		dma_pool_destroy(ioc->reply_post_free_array_dma_pool);
584662306a36Sopenharmony_ci		kfree(ioc->reply_post);
584762306a36Sopenharmony_ci	}
584862306a36Sopenharmony_ci
584962306a36Sopenharmony_ci	if (ioc->pcie_sgl_dma_pool) {
585062306a36Sopenharmony_ci		for (i = 0; i < ioc->scsiio_depth; i++) {
585162306a36Sopenharmony_ci			dma_pool_free(ioc->pcie_sgl_dma_pool,
585262306a36Sopenharmony_ci					ioc->pcie_sg_lookup[i].pcie_sgl,
585362306a36Sopenharmony_ci					ioc->pcie_sg_lookup[i].pcie_sgl_dma);
585462306a36Sopenharmony_ci			ioc->pcie_sg_lookup[i].pcie_sgl = NULL;
585562306a36Sopenharmony_ci		}
585662306a36Sopenharmony_ci		dma_pool_destroy(ioc->pcie_sgl_dma_pool);
585762306a36Sopenharmony_ci	}
585862306a36Sopenharmony_ci	kfree(ioc->pcie_sg_lookup);
585962306a36Sopenharmony_ci	ioc->pcie_sg_lookup = NULL;
586062306a36Sopenharmony_ci
586162306a36Sopenharmony_ci	if (ioc->config_page) {
586262306a36Sopenharmony_ci		dexitprintk(ioc,
586362306a36Sopenharmony_ci			    ioc_info(ioc, "config_page(0x%p): free\n",
586462306a36Sopenharmony_ci				     ioc->config_page));
586562306a36Sopenharmony_ci		dma_free_coherent(&ioc->pdev->dev, ioc->config_page_sz,
586662306a36Sopenharmony_ci		    ioc->config_page, ioc->config_page_dma);
586762306a36Sopenharmony_ci	}
586862306a36Sopenharmony_ci
586962306a36Sopenharmony_ci	kfree(ioc->hpr_lookup);
587062306a36Sopenharmony_ci	ioc->hpr_lookup = NULL;
587162306a36Sopenharmony_ci	kfree(ioc->internal_lookup);
587262306a36Sopenharmony_ci	ioc->internal_lookup = NULL;
587362306a36Sopenharmony_ci	if (ioc->chain_lookup) {
587462306a36Sopenharmony_ci		for (i = 0; i < ioc->scsiio_depth; i++) {
587562306a36Sopenharmony_ci			for (j = ioc->chains_per_prp_buffer;
587662306a36Sopenharmony_ci			    j < ioc->chains_needed_per_io; j++) {
587762306a36Sopenharmony_ci				ct = &ioc->chain_lookup[i].chains_per_smid[j];
587862306a36Sopenharmony_ci				if (ct && ct->chain_buffer)
587962306a36Sopenharmony_ci					dma_pool_free(ioc->chain_dma_pool,
588062306a36Sopenharmony_ci						ct->chain_buffer,
588162306a36Sopenharmony_ci						ct->chain_buffer_dma);
588262306a36Sopenharmony_ci			}
588362306a36Sopenharmony_ci			kfree(ioc->chain_lookup[i].chains_per_smid);
588462306a36Sopenharmony_ci		}
588562306a36Sopenharmony_ci		dma_pool_destroy(ioc->chain_dma_pool);
588662306a36Sopenharmony_ci		kfree(ioc->chain_lookup);
588762306a36Sopenharmony_ci		ioc->chain_lookup = NULL;
588862306a36Sopenharmony_ci	}
588962306a36Sopenharmony_ci
589062306a36Sopenharmony_ci	kfree(ioc->io_queue_num);
589162306a36Sopenharmony_ci	ioc->io_queue_num = NULL;
589262306a36Sopenharmony_ci}
589362306a36Sopenharmony_ci
589462306a36Sopenharmony_ci/**
589562306a36Sopenharmony_ci * mpt3sas_check_same_4gb_region - checks whether all reply queues in a set are
589662306a36Sopenharmony_ci *	having same upper 32bits in their base memory address.
589762306a36Sopenharmony_ci * @start_address: Base address of a reply queue set
589862306a36Sopenharmony_ci * @pool_sz: Size of single Reply Descriptor Post Queues pool size
589962306a36Sopenharmony_ci *
590062306a36Sopenharmony_ci * Return: 1 if reply queues in a set have a same upper 32bits in their base
590162306a36Sopenharmony_ci * memory address, else 0.
590262306a36Sopenharmony_ci */
590362306a36Sopenharmony_cistatic int
590462306a36Sopenharmony_cimpt3sas_check_same_4gb_region(dma_addr_t start_address, u32 pool_sz)
590562306a36Sopenharmony_ci{
590662306a36Sopenharmony_ci	dma_addr_t end_address;
590762306a36Sopenharmony_ci
590862306a36Sopenharmony_ci	end_address = start_address + pool_sz - 1;
590962306a36Sopenharmony_ci
591062306a36Sopenharmony_ci	if (upper_32_bits(start_address) == upper_32_bits(end_address))
591162306a36Sopenharmony_ci		return 1;
591262306a36Sopenharmony_ci	else
591362306a36Sopenharmony_ci		return 0;
591462306a36Sopenharmony_ci}
591562306a36Sopenharmony_ci
591662306a36Sopenharmony_ci/**
591762306a36Sopenharmony_ci * _base_reduce_hba_queue_depth- Retry with reduced queue depth
591862306a36Sopenharmony_ci * @ioc: Adapter object
591962306a36Sopenharmony_ci *
592062306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
592162306a36Sopenharmony_ci **/
592262306a36Sopenharmony_cistatic inline int
592362306a36Sopenharmony_ci_base_reduce_hba_queue_depth(struct MPT3SAS_ADAPTER *ioc)
592462306a36Sopenharmony_ci{
592562306a36Sopenharmony_ci	int reduce_sz = 64;
592662306a36Sopenharmony_ci
592762306a36Sopenharmony_ci	if ((ioc->hba_queue_depth - reduce_sz) >
592862306a36Sopenharmony_ci	    (ioc->internal_depth + INTERNAL_SCSIIO_CMDS_COUNT)) {
592962306a36Sopenharmony_ci		ioc->hba_queue_depth -= reduce_sz;
593062306a36Sopenharmony_ci		return 0;
593162306a36Sopenharmony_ci	} else
593262306a36Sopenharmony_ci		return -ENOMEM;
593362306a36Sopenharmony_ci}
593462306a36Sopenharmony_ci
593562306a36Sopenharmony_ci/**
593662306a36Sopenharmony_ci * _base_allocate_pcie_sgl_pool - Allocating DMA'able memory
593762306a36Sopenharmony_ci *			for pcie sgl pools.
593862306a36Sopenharmony_ci * @ioc: Adapter object
593962306a36Sopenharmony_ci * @sz: DMA Pool size
594062306a36Sopenharmony_ci *
594162306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
594262306a36Sopenharmony_ci */
594362306a36Sopenharmony_ci
594462306a36Sopenharmony_cistatic int
594562306a36Sopenharmony_ci_base_allocate_pcie_sgl_pool(struct MPT3SAS_ADAPTER *ioc, u32 sz)
594662306a36Sopenharmony_ci{
594762306a36Sopenharmony_ci	int i = 0, j = 0;
594862306a36Sopenharmony_ci	struct chain_tracker *ct;
594962306a36Sopenharmony_ci
595062306a36Sopenharmony_ci	ioc->pcie_sgl_dma_pool =
595162306a36Sopenharmony_ci	    dma_pool_create("PCIe SGL pool", &ioc->pdev->dev, sz,
595262306a36Sopenharmony_ci	    ioc->page_size, 0);
595362306a36Sopenharmony_ci	if (!ioc->pcie_sgl_dma_pool) {
595462306a36Sopenharmony_ci		ioc_err(ioc, "PCIe SGL pool: dma_pool_create failed\n");
595562306a36Sopenharmony_ci		return -ENOMEM;
595662306a36Sopenharmony_ci	}
595762306a36Sopenharmony_ci
595862306a36Sopenharmony_ci	ioc->chains_per_prp_buffer = sz/ioc->chain_segment_sz;
595962306a36Sopenharmony_ci	ioc->chains_per_prp_buffer =
596062306a36Sopenharmony_ci	    min(ioc->chains_per_prp_buffer, ioc->chains_needed_per_io);
596162306a36Sopenharmony_ci	for (i = 0; i < ioc->scsiio_depth; i++) {
596262306a36Sopenharmony_ci		ioc->pcie_sg_lookup[i].pcie_sgl =
596362306a36Sopenharmony_ci		    dma_pool_alloc(ioc->pcie_sgl_dma_pool, GFP_KERNEL,
596462306a36Sopenharmony_ci		    &ioc->pcie_sg_lookup[i].pcie_sgl_dma);
596562306a36Sopenharmony_ci		if (!ioc->pcie_sg_lookup[i].pcie_sgl) {
596662306a36Sopenharmony_ci			ioc_err(ioc, "PCIe SGL pool: dma_pool_alloc failed\n");
596762306a36Sopenharmony_ci			return -EAGAIN;
596862306a36Sopenharmony_ci		}
596962306a36Sopenharmony_ci
597062306a36Sopenharmony_ci		if (!mpt3sas_check_same_4gb_region(
597162306a36Sopenharmony_ci		    ioc->pcie_sg_lookup[i].pcie_sgl_dma, sz)) {
597262306a36Sopenharmony_ci			ioc_err(ioc, "PCIE SGLs are not in same 4G !! pcie sgl (0x%p) dma = (0x%llx)\n",
597362306a36Sopenharmony_ci			    ioc->pcie_sg_lookup[i].pcie_sgl,
597462306a36Sopenharmony_ci			    (unsigned long long)
597562306a36Sopenharmony_ci			    ioc->pcie_sg_lookup[i].pcie_sgl_dma);
597662306a36Sopenharmony_ci			ioc->use_32bit_dma = true;
597762306a36Sopenharmony_ci			return -EAGAIN;
597862306a36Sopenharmony_ci		}
597962306a36Sopenharmony_ci
598062306a36Sopenharmony_ci		for (j = 0; j < ioc->chains_per_prp_buffer; j++) {
598162306a36Sopenharmony_ci			ct = &ioc->chain_lookup[i].chains_per_smid[j];
598262306a36Sopenharmony_ci			ct->chain_buffer =
598362306a36Sopenharmony_ci			    ioc->pcie_sg_lookup[i].pcie_sgl +
598462306a36Sopenharmony_ci			    (j * ioc->chain_segment_sz);
598562306a36Sopenharmony_ci			ct->chain_buffer_dma =
598662306a36Sopenharmony_ci			    ioc->pcie_sg_lookup[i].pcie_sgl_dma +
598762306a36Sopenharmony_ci			    (j * ioc->chain_segment_sz);
598862306a36Sopenharmony_ci		}
598962306a36Sopenharmony_ci	}
599062306a36Sopenharmony_ci	dinitprintk(ioc, ioc_info(ioc,
599162306a36Sopenharmony_ci	    "PCIe sgl pool depth(%d), element_size(%d), pool_size(%d kB)\n",
599262306a36Sopenharmony_ci	    ioc->scsiio_depth, sz, (sz * ioc->scsiio_depth)/1024));
599362306a36Sopenharmony_ci	dinitprintk(ioc, ioc_info(ioc,
599462306a36Sopenharmony_ci	    "Number of chains can fit in a PRP page(%d)\n",
599562306a36Sopenharmony_ci	    ioc->chains_per_prp_buffer));
599662306a36Sopenharmony_ci	return 0;
599762306a36Sopenharmony_ci}
599862306a36Sopenharmony_ci
599962306a36Sopenharmony_ci/**
600062306a36Sopenharmony_ci * _base_allocate_chain_dma_pool - Allocating DMA'able memory
600162306a36Sopenharmony_ci *			for chain dma pool.
600262306a36Sopenharmony_ci * @ioc: Adapter object
600362306a36Sopenharmony_ci * @sz: DMA Pool size
600462306a36Sopenharmony_ci *
600562306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
600662306a36Sopenharmony_ci */
600762306a36Sopenharmony_cistatic int
600862306a36Sopenharmony_ci_base_allocate_chain_dma_pool(struct MPT3SAS_ADAPTER *ioc, u32 sz)
600962306a36Sopenharmony_ci{
601062306a36Sopenharmony_ci	int i = 0, j = 0;
601162306a36Sopenharmony_ci	struct chain_tracker *ctr;
601262306a36Sopenharmony_ci
601362306a36Sopenharmony_ci	ioc->chain_dma_pool = dma_pool_create("chain pool", &ioc->pdev->dev,
601462306a36Sopenharmony_ci	    ioc->chain_segment_sz, 16, 0);
601562306a36Sopenharmony_ci	if (!ioc->chain_dma_pool)
601662306a36Sopenharmony_ci		return -ENOMEM;
601762306a36Sopenharmony_ci
601862306a36Sopenharmony_ci	for (i = 0; i < ioc->scsiio_depth; i++) {
601962306a36Sopenharmony_ci		for (j = ioc->chains_per_prp_buffer;
602062306a36Sopenharmony_ci		    j < ioc->chains_needed_per_io; j++) {
602162306a36Sopenharmony_ci			ctr = &ioc->chain_lookup[i].chains_per_smid[j];
602262306a36Sopenharmony_ci			ctr->chain_buffer = dma_pool_alloc(ioc->chain_dma_pool,
602362306a36Sopenharmony_ci			    GFP_KERNEL, &ctr->chain_buffer_dma);
602462306a36Sopenharmony_ci			if (!ctr->chain_buffer)
602562306a36Sopenharmony_ci				return -EAGAIN;
602662306a36Sopenharmony_ci			if (!mpt3sas_check_same_4gb_region(
602762306a36Sopenharmony_ci			    ctr->chain_buffer_dma, ioc->chain_segment_sz)) {
602862306a36Sopenharmony_ci				ioc_err(ioc,
602962306a36Sopenharmony_ci				    "Chain buffers are not in same 4G !!! Chain buff (0x%p) dma = (0x%llx)\n",
603062306a36Sopenharmony_ci				    ctr->chain_buffer,
603162306a36Sopenharmony_ci				    (unsigned long long)ctr->chain_buffer_dma);
603262306a36Sopenharmony_ci				ioc->use_32bit_dma = true;
603362306a36Sopenharmony_ci				return -EAGAIN;
603462306a36Sopenharmony_ci			}
603562306a36Sopenharmony_ci		}
603662306a36Sopenharmony_ci	}
603762306a36Sopenharmony_ci	dinitprintk(ioc, ioc_info(ioc,
603862306a36Sopenharmony_ci	    "chain_lookup depth (%d), frame_size(%d), pool_size(%d kB)\n",
603962306a36Sopenharmony_ci	    ioc->scsiio_depth, ioc->chain_segment_sz, ((ioc->scsiio_depth *
604062306a36Sopenharmony_ci	    (ioc->chains_needed_per_io - ioc->chains_per_prp_buffer) *
604162306a36Sopenharmony_ci	    ioc->chain_segment_sz))/1024));
604262306a36Sopenharmony_ci	return 0;
604362306a36Sopenharmony_ci}
604462306a36Sopenharmony_ci
604562306a36Sopenharmony_ci/**
604662306a36Sopenharmony_ci * _base_allocate_sense_dma_pool - Allocating DMA'able memory
604762306a36Sopenharmony_ci *			for sense dma pool.
604862306a36Sopenharmony_ci * @ioc: Adapter object
604962306a36Sopenharmony_ci * @sz: DMA Pool size
605062306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
605162306a36Sopenharmony_ci */
605262306a36Sopenharmony_cistatic int
605362306a36Sopenharmony_ci_base_allocate_sense_dma_pool(struct MPT3SAS_ADAPTER *ioc, u32 sz)
605462306a36Sopenharmony_ci{
605562306a36Sopenharmony_ci	ioc->sense_dma_pool =
605662306a36Sopenharmony_ci	    dma_pool_create("sense pool", &ioc->pdev->dev, sz, 4, 0);
605762306a36Sopenharmony_ci	if (!ioc->sense_dma_pool)
605862306a36Sopenharmony_ci		return -ENOMEM;
605962306a36Sopenharmony_ci	ioc->sense = dma_pool_alloc(ioc->sense_dma_pool,
606062306a36Sopenharmony_ci	    GFP_KERNEL, &ioc->sense_dma);
606162306a36Sopenharmony_ci	if (!ioc->sense)
606262306a36Sopenharmony_ci		return -EAGAIN;
606362306a36Sopenharmony_ci	if (!mpt3sas_check_same_4gb_region(ioc->sense_dma, sz)) {
606462306a36Sopenharmony_ci		dinitprintk(ioc, pr_err(
606562306a36Sopenharmony_ci		    "Bad Sense Pool! sense (0x%p) sense_dma = (0x%llx)\n",
606662306a36Sopenharmony_ci		    ioc->sense, (unsigned long long) ioc->sense_dma));
606762306a36Sopenharmony_ci		ioc->use_32bit_dma = true;
606862306a36Sopenharmony_ci		return -EAGAIN;
606962306a36Sopenharmony_ci	}
607062306a36Sopenharmony_ci	ioc_info(ioc,
607162306a36Sopenharmony_ci	    "sense pool(0x%p) - dma(0x%llx): depth(%d), element_size(%d), pool_size (%d kB)\n",
607262306a36Sopenharmony_ci	    ioc->sense, (unsigned long long)ioc->sense_dma,
607362306a36Sopenharmony_ci	    ioc->scsiio_depth, SCSI_SENSE_BUFFERSIZE, sz/1024);
607462306a36Sopenharmony_ci	return 0;
607562306a36Sopenharmony_ci}
607662306a36Sopenharmony_ci
607762306a36Sopenharmony_ci/**
607862306a36Sopenharmony_ci * _base_allocate_reply_pool - Allocating DMA'able memory
607962306a36Sopenharmony_ci *			for reply pool.
608062306a36Sopenharmony_ci * @ioc: Adapter object
608162306a36Sopenharmony_ci * @sz: DMA Pool size
608262306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
608362306a36Sopenharmony_ci */
608462306a36Sopenharmony_cistatic int
608562306a36Sopenharmony_ci_base_allocate_reply_pool(struct MPT3SAS_ADAPTER *ioc, u32 sz)
608662306a36Sopenharmony_ci{
608762306a36Sopenharmony_ci	/* reply pool, 4 byte align */
608862306a36Sopenharmony_ci	ioc->reply_dma_pool = dma_pool_create("reply pool",
608962306a36Sopenharmony_ci	    &ioc->pdev->dev, sz, 4, 0);
609062306a36Sopenharmony_ci	if (!ioc->reply_dma_pool)
609162306a36Sopenharmony_ci		return -ENOMEM;
609262306a36Sopenharmony_ci	ioc->reply = dma_pool_alloc(ioc->reply_dma_pool, GFP_KERNEL,
609362306a36Sopenharmony_ci	    &ioc->reply_dma);
609462306a36Sopenharmony_ci	if (!ioc->reply)
609562306a36Sopenharmony_ci		return -EAGAIN;
609662306a36Sopenharmony_ci	if (!mpt3sas_check_same_4gb_region(ioc->reply_dma, sz)) {
609762306a36Sopenharmony_ci		dinitprintk(ioc, pr_err(
609862306a36Sopenharmony_ci		    "Bad Reply Pool! Reply (0x%p) Reply dma = (0x%llx)\n",
609962306a36Sopenharmony_ci		    ioc->reply, (unsigned long long) ioc->reply_dma));
610062306a36Sopenharmony_ci		ioc->use_32bit_dma = true;
610162306a36Sopenharmony_ci		return -EAGAIN;
610262306a36Sopenharmony_ci	}
610362306a36Sopenharmony_ci	ioc->reply_dma_min_address = (u32)(ioc->reply_dma);
610462306a36Sopenharmony_ci	ioc->reply_dma_max_address = (u32)(ioc->reply_dma) + sz;
610562306a36Sopenharmony_ci	ioc_info(ioc,
610662306a36Sopenharmony_ci	    "reply pool(0x%p) - dma(0x%llx): depth(%d), frame_size(%d), pool_size(%d kB)\n",
610762306a36Sopenharmony_ci	    ioc->reply, (unsigned long long)ioc->reply_dma,
610862306a36Sopenharmony_ci	    ioc->reply_free_queue_depth, ioc->reply_sz, sz/1024);
610962306a36Sopenharmony_ci	return 0;
611062306a36Sopenharmony_ci}
611162306a36Sopenharmony_ci
611262306a36Sopenharmony_ci/**
611362306a36Sopenharmony_ci * _base_allocate_reply_free_dma_pool - Allocating DMA'able memory
611462306a36Sopenharmony_ci *			for reply free dma pool.
611562306a36Sopenharmony_ci * @ioc: Adapter object
611662306a36Sopenharmony_ci * @sz: DMA Pool size
611762306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
611862306a36Sopenharmony_ci */
611962306a36Sopenharmony_cistatic int
612062306a36Sopenharmony_ci_base_allocate_reply_free_dma_pool(struct MPT3SAS_ADAPTER *ioc, u32 sz)
612162306a36Sopenharmony_ci{
612262306a36Sopenharmony_ci	/* reply free queue, 16 byte align */
612362306a36Sopenharmony_ci	ioc->reply_free_dma_pool = dma_pool_create(
612462306a36Sopenharmony_ci	    "reply_free pool", &ioc->pdev->dev, sz, 16, 0);
612562306a36Sopenharmony_ci	if (!ioc->reply_free_dma_pool)
612662306a36Sopenharmony_ci		return -ENOMEM;
612762306a36Sopenharmony_ci	ioc->reply_free = dma_pool_alloc(ioc->reply_free_dma_pool,
612862306a36Sopenharmony_ci	    GFP_KERNEL, &ioc->reply_free_dma);
612962306a36Sopenharmony_ci	if (!ioc->reply_free)
613062306a36Sopenharmony_ci		return -EAGAIN;
613162306a36Sopenharmony_ci	if (!mpt3sas_check_same_4gb_region(ioc->reply_free_dma, sz)) {
613262306a36Sopenharmony_ci		dinitprintk(ioc,
613362306a36Sopenharmony_ci		    pr_err("Bad Reply Free Pool! Reply Free (0x%p) Reply Free dma = (0x%llx)\n",
613462306a36Sopenharmony_ci		    ioc->reply_free, (unsigned long long) ioc->reply_free_dma));
613562306a36Sopenharmony_ci		ioc->use_32bit_dma = true;
613662306a36Sopenharmony_ci		return -EAGAIN;
613762306a36Sopenharmony_ci	}
613862306a36Sopenharmony_ci	memset(ioc->reply_free, 0, sz);
613962306a36Sopenharmony_ci	dinitprintk(ioc, ioc_info(ioc,
614062306a36Sopenharmony_ci	    "reply_free pool(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n",
614162306a36Sopenharmony_ci	    ioc->reply_free, ioc->reply_free_queue_depth, 4, sz/1024));
614262306a36Sopenharmony_ci	dinitprintk(ioc, ioc_info(ioc,
614362306a36Sopenharmony_ci	    "reply_free_dma (0x%llx)\n",
614462306a36Sopenharmony_ci	    (unsigned long long)ioc->reply_free_dma));
614562306a36Sopenharmony_ci	return 0;
614662306a36Sopenharmony_ci}
614762306a36Sopenharmony_ci
614862306a36Sopenharmony_ci/**
614962306a36Sopenharmony_ci * _base_allocate_reply_post_free_array - Allocating DMA'able memory
615062306a36Sopenharmony_ci *			for reply post free array.
615162306a36Sopenharmony_ci * @ioc: Adapter object
615262306a36Sopenharmony_ci * @reply_post_free_array_sz: DMA Pool size
615362306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
615462306a36Sopenharmony_ci */
615562306a36Sopenharmony_ci
615662306a36Sopenharmony_cistatic int
615762306a36Sopenharmony_ci_base_allocate_reply_post_free_array(struct MPT3SAS_ADAPTER *ioc,
615862306a36Sopenharmony_ci	u32 reply_post_free_array_sz)
615962306a36Sopenharmony_ci{
616062306a36Sopenharmony_ci	ioc->reply_post_free_array_dma_pool =
616162306a36Sopenharmony_ci	    dma_pool_create("reply_post_free_array pool",
616262306a36Sopenharmony_ci	    &ioc->pdev->dev, reply_post_free_array_sz, 16, 0);
616362306a36Sopenharmony_ci	if (!ioc->reply_post_free_array_dma_pool)
616462306a36Sopenharmony_ci		return -ENOMEM;
616562306a36Sopenharmony_ci	ioc->reply_post_free_array =
616662306a36Sopenharmony_ci	    dma_pool_alloc(ioc->reply_post_free_array_dma_pool,
616762306a36Sopenharmony_ci	    GFP_KERNEL, &ioc->reply_post_free_array_dma);
616862306a36Sopenharmony_ci	if (!ioc->reply_post_free_array)
616962306a36Sopenharmony_ci		return -EAGAIN;
617062306a36Sopenharmony_ci	if (!mpt3sas_check_same_4gb_region(ioc->reply_post_free_array_dma,
617162306a36Sopenharmony_ci	    reply_post_free_array_sz)) {
617262306a36Sopenharmony_ci		dinitprintk(ioc, pr_err(
617362306a36Sopenharmony_ci		    "Bad Reply Free Pool! Reply Free (0x%p) Reply Free dma = (0x%llx)\n",
617462306a36Sopenharmony_ci		    ioc->reply_free,
617562306a36Sopenharmony_ci		    (unsigned long long) ioc->reply_free_dma));
617662306a36Sopenharmony_ci		ioc->use_32bit_dma = true;
617762306a36Sopenharmony_ci		return -EAGAIN;
617862306a36Sopenharmony_ci	}
617962306a36Sopenharmony_ci	return 0;
618062306a36Sopenharmony_ci}
618162306a36Sopenharmony_ci/**
618262306a36Sopenharmony_ci * base_alloc_rdpq_dma_pool - Allocating DMA'able memory
618362306a36Sopenharmony_ci *                     for reply queues.
618462306a36Sopenharmony_ci * @ioc: per adapter object
618562306a36Sopenharmony_ci * @sz: DMA Pool size
618662306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
618762306a36Sopenharmony_ci */
618862306a36Sopenharmony_cistatic int
618962306a36Sopenharmony_cibase_alloc_rdpq_dma_pool(struct MPT3SAS_ADAPTER *ioc, int sz)
619062306a36Sopenharmony_ci{
619162306a36Sopenharmony_ci	int i = 0;
619262306a36Sopenharmony_ci	u32 dma_alloc_count = 0;
619362306a36Sopenharmony_ci	int reply_post_free_sz = ioc->reply_post_queue_depth *
619462306a36Sopenharmony_ci		sizeof(Mpi2DefaultReplyDescriptor_t);
619562306a36Sopenharmony_ci	int count = ioc->rdpq_array_enable ? ioc->reply_queue_count : 1;
619662306a36Sopenharmony_ci
619762306a36Sopenharmony_ci	ioc->reply_post = kcalloc(count, sizeof(struct reply_post_struct),
619862306a36Sopenharmony_ci			GFP_KERNEL);
619962306a36Sopenharmony_ci	if (!ioc->reply_post)
620062306a36Sopenharmony_ci		return -ENOMEM;
620162306a36Sopenharmony_ci	/*
620262306a36Sopenharmony_ci	 *  For INVADER_SERIES each set of 8 reply queues(0-7, 8-15, ..) and
620362306a36Sopenharmony_ci	 *  VENTURA_SERIES each set of 16 reply queues(0-15, 16-31, ..) should
620462306a36Sopenharmony_ci	 *  be within 4GB boundary i.e reply queues in a set must have same
620562306a36Sopenharmony_ci	 *  upper 32-bits in their memory address. so here driver is allocating
620662306a36Sopenharmony_ci	 *  the DMA'able memory for reply queues according.
620762306a36Sopenharmony_ci	 *  Driver uses limitation of
620862306a36Sopenharmony_ci	 *  VENTURA_SERIES to manage INVADER_SERIES as well.
620962306a36Sopenharmony_ci	 */
621062306a36Sopenharmony_ci	dma_alloc_count = DIV_ROUND_UP(count,
621162306a36Sopenharmony_ci				RDPQ_MAX_INDEX_IN_ONE_CHUNK);
621262306a36Sopenharmony_ci	ioc->reply_post_free_dma_pool =
621362306a36Sopenharmony_ci		dma_pool_create("reply_post_free pool",
621462306a36Sopenharmony_ci		    &ioc->pdev->dev, sz, 16, 0);
621562306a36Sopenharmony_ci	if (!ioc->reply_post_free_dma_pool)
621662306a36Sopenharmony_ci		return -ENOMEM;
621762306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
621862306a36Sopenharmony_ci		if ((i % RDPQ_MAX_INDEX_IN_ONE_CHUNK == 0) && dma_alloc_count) {
621962306a36Sopenharmony_ci			ioc->reply_post[i].reply_post_free =
622062306a36Sopenharmony_ci			    dma_pool_zalloc(ioc->reply_post_free_dma_pool,
622162306a36Sopenharmony_ci				GFP_KERNEL,
622262306a36Sopenharmony_ci				&ioc->reply_post[i].reply_post_free_dma);
622362306a36Sopenharmony_ci			if (!ioc->reply_post[i].reply_post_free)
622462306a36Sopenharmony_ci				return -ENOMEM;
622562306a36Sopenharmony_ci			/*
622662306a36Sopenharmony_ci			 * Each set of RDPQ pool must satisfy 4gb boundary
622762306a36Sopenharmony_ci			 * restriction.
622862306a36Sopenharmony_ci			 * 1) Check if allocated resources for RDPQ pool are in
622962306a36Sopenharmony_ci			 *	the same 4GB range.
623062306a36Sopenharmony_ci			 * 2) If #1 is true, continue with 64 bit DMA.
623162306a36Sopenharmony_ci			 * 3) If #1 is false, return 1. which means free all the
623262306a36Sopenharmony_ci			 * resources and set DMA mask to 32 and allocate.
623362306a36Sopenharmony_ci			 */
623462306a36Sopenharmony_ci			if (!mpt3sas_check_same_4gb_region(
623562306a36Sopenharmony_ci				ioc->reply_post[i].reply_post_free_dma, sz)) {
623662306a36Sopenharmony_ci				dinitprintk(ioc,
623762306a36Sopenharmony_ci				    ioc_err(ioc, "bad Replypost free pool(0x%p)"
623862306a36Sopenharmony_ci				    "reply_post_free_dma = (0x%llx)\n",
623962306a36Sopenharmony_ci				    ioc->reply_post[i].reply_post_free,
624062306a36Sopenharmony_ci				    (unsigned long long)
624162306a36Sopenharmony_ci				    ioc->reply_post[i].reply_post_free_dma));
624262306a36Sopenharmony_ci				return -EAGAIN;
624362306a36Sopenharmony_ci			}
624462306a36Sopenharmony_ci			dma_alloc_count--;
624562306a36Sopenharmony_ci
624662306a36Sopenharmony_ci		} else {
624762306a36Sopenharmony_ci			ioc->reply_post[i].reply_post_free =
624862306a36Sopenharmony_ci			    (Mpi2ReplyDescriptorsUnion_t *)
624962306a36Sopenharmony_ci			    ((long)ioc->reply_post[i-1].reply_post_free
625062306a36Sopenharmony_ci			    + reply_post_free_sz);
625162306a36Sopenharmony_ci			ioc->reply_post[i].reply_post_free_dma =
625262306a36Sopenharmony_ci			    (dma_addr_t)
625362306a36Sopenharmony_ci			    (ioc->reply_post[i-1].reply_post_free_dma +
625462306a36Sopenharmony_ci			    reply_post_free_sz);
625562306a36Sopenharmony_ci		}
625662306a36Sopenharmony_ci	}
625762306a36Sopenharmony_ci	return 0;
625862306a36Sopenharmony_ci}
625962306a36Sopenharmony_ci
626062306a36Sopenharmony_ci/**
626162306a36Sopenharmony_ci * _base_allocate_memory_pools - allocate start of day memory pools
626262306a36Sopenharmony_ci * @ioc: per adapter object
626362306a36Sopenharmony_ci *
626462306a36Sopenharmony_ci * Return: 0 success, anything else error.
626562306a36Sopenharmony_ci */
626662306a36Sopenharmony_cistatic int
626762306a36Sopenharmony_ci_base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
626862306a36Sopenharmony_ci{
626962306a36Sopenharmony_ci	struct mpt3sas_facts *facts;
627062306a36Sopenharmony_ci	u16 max_sge_elements;
627162306a36Sopenharmony_ci	u16 chains_needed_per_io;
627262306a36Sopenharmony_ci	u32 sz, total_sz, reply_post_free_sz, reply_post_free_array_sz;
627362306a36Sopenharmony_ci	u32 retry_sz;
627462306a36Sopenharmony_ci	u32 rdpq_sz = 0, sense_sz = 0;
627562306a36Sopenharmony_ci	u16 max_request_credit, nvme_blocks_needed;
627662306a36Sopenharmony_ci	unsigned short sg_tablesize;
627762306a36Sopenharmony_ci	u16 sge_size;
627862306a36Sopenharmony_ci	int i;
627962306a36Sopenharmony_ci	int ret = 0, rc = 0;
628062306a36Sopenharmony_ci
628162306a36Sopenharmony_ci	dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
628262306a36Sopenharmony_ci
628362306a36Sopenharmony_ci
628462306a36Sopenharmony_ci	retry_sz = 0;
628562306a36Sopenharmony_ci	facts = &ioc->facts;
628662306a36Sopenharmony_ci
628762306a36Sopenharmony_ci	/* command line tunables for max sgl entries */
628862306a36Sopenharmony_ci	if (max_sgl_entries != -1)
628962306a36Sopenharmony_ci		sg_tablesize = max_sgl_entries;
629062306a36Sopenharmony_ci	else {
629162306a36Sopenharmony_ci		if (ioc->hba_mpi_version_belonged == MPI2_VERSION)
629262306a36Sopenharmony_ci			sg_tablesize = MPT2SAS_SG_DEPTH;
629362306a36Sopenharmony_ci		else
629462306a36Sopenharmony_ci			sg_tablesize = MPT3SAS_SG_DEPTH;
629562306a36Sopenharmony_ci	}
629662306a36Sopenharmony_ci
629762306a36Sopenharmony_ci	/* max sgl entries <= MPT_KDUMP_MIN_PHYS_SEGMENTS in KDUMP mode */
629862306a36Sopenharmony_ci	if (reset_devices)
629962306a36Sopenharmony_ci		sg_tablesize = min_t(unsigned short, sg_tablesize,
630062306a36Sopenharmony_ci		   MPT_KDUMP_MIN_PHYS_SEGMENTS);
630162306a36Sopenharmony_ci
630262306a36Sopenharmony_ci	if (ioc->is_mcpu_endpoint)
630362306a36Sopenharmony_ci		ioc->shost->sg_tablesize = MPT_MIN_PHYS_SEGMENTS;
630462306a36Sopenharmony_ci	else {
630562306a36Sopenharmony_ci		if (sg_tablesize < MPT_MIN_PHYS_SEGMENTS)
630662306a36Sopenharmony_ci			sg_tablesize = MPT_MIN_PHYS_SEGMENTS;
630762306a36Sopenharmony_ci		else if (sg_tablesize > MPT_MAX_PHYS_SEGMENTS) {
630862306a36Sopenharmony_ci			sg_tablesize = min_t(unsigned short, sg_tablesize,
630962306a36Sopenharmony_ci					SG_MAX_SEGMENTS);
631062306a36Sopenharmony_ci			ioc_warn(ioc, "sg_tablesize(%u) is bigger than kernel defined SG_CHUNK_SIZE(%u)\n",
631162306a36Sopenharmony_ci				 sg_tablesize, MPT_MAX_PHYS_SEGMENTS);
631262306a36Sopenharmony_ci		}
631362306a36Sopenharmony_ci		ioc->shost->sg_tablesize = sg_tablesize;
631462306a36Sopenharmony_ci	}
631562306a36Sopenharmony_ci
631662306a36Sopenharmony_ci	ioc->internal_depth = min_t(int, (facts->HighPriorityCredit + (5)),
631762306a36Sopenharmony_ci		(facts->RequestCredit / 4));
631862306a36Sopenharmony_ci	if (ioc->internal_depth < INTERNAL_CMDS_COUNT) {
631962306a36Sopenharmony_ci		if (facts->RequestCredit <= (INTERNAL_CMDS_COUNT +
632062306a36Sopenharmony_ci				INTERNAL_SCSIIO_CMDS_COUNT)) {
632162306a36Sopenharmony_ci			ioc_err(ioc, "IOC doesn't have enough Request Credits, it has just %d number of credits\n",
632262306a36Sopenharmony_ci				facts->RequestCredit);
632362306a36Sopenharmony_ci			return -ENOMEM;
632462306a36Sopenharmony_ci		}
632562306a36Sopenharmony_ci		ioc->internal_depth = 10;
632662306a36Sopenharmony_ci	}
632762306a36Sopenharmony_ci
632862306a36Sopenharmony_ci	ioc->hi_priority_depth = ioc->internal_depth - (5);
632962306a36Sopenharmony_ci	/* command line tunables  for max controller queue depth */
633062306a36Sopenharmony_ci	if (max_queue_depth != -1 && max_queue_depth != 0) {
633162306a36Sopenharmony_ci		max_request_credit = min_t(u16, max_queue_depth +
633262306a36Sopenharmony_ci			ioc->internal_depth, facts->RequestCredit);
633362306a36Sopenharmony_ci		if (max_request_credit > MAX_HBA_QUEUE_DEPTH)
633462306a36Sopenharmony_ci			max_request_credit =  MAX_HBA_QUEUE_DEPTH;
633562306a36Sopenharmony_ci	} else if (reset_devices)
633662306a36Sopenharmony_ci		max_request_credit = min_t(u16, facts->RequestCredit,
633762306a36Sopenharmony_ci		    (MPT3SAS_KDUMP_SCSI_IO_DEPTH + ioc->internal_depth));
633862306a36Sopenharmony_ci	else
633962306a36Sopenharmony_ci		max_request_credit = min_t(u16, facts->RequestCredit,
634062306a36Sopenharmony_ci		    MAX_HBA_QUEUE_DEPTH);
634162306a36Sopenharmony_ci
634262306a36Sopenharmony_ci	/* Firmware maintains additional facts->HighPriorityCredit number of
634362306a36Sopenharmony_ci	 * credits for HiPriprity Request messages, so hba queue depth will be
634462306a36Sopenharmony_ci	 * sum of max_request_credit and high priority queue depth.
634562306a36Sopenharmony_ci	 */
634662306a36Sopenharmony_ci	ioc->hba_queue_depth = max_request_credit + ioc->hi_priority_depth;
634762306a36Sopenharmony_ci
634862306a36Sopenharmony_ci	/* request frame size */
634962306a36Sopenharmony_ci	ioc->request_sz = facts->IOCRequestFrameSize * 4;
635062306a36Sopenharmony_ci
635162306a36Sopenharmony_ci	/* reply frame size */
635262306a36Sopenharmony_ci	ioc->reply_sz = facts->ReplyFrameSize * 4;
635362306a36Sopenharmony_ci
635462306a36Sopenharmony_ci	/* chain segment size */
635562306a36Sopenharmony_ci	if (ioc->hba_mpi_version_belonged != MPI2_VERSION) {
635662306a36Sopenharmony_ci		if (facts->IOCMaxChainSegmentSize)
635762306a36Sopenharmony_ci			ioc->chain_segment_sz =
635862306a36Sopenharmony_ci					facts->IOCMaxChainSegmentSize *
635962306a36Sopenharmony_ci					MAX_CHAIN_ELEMT_SZ;
636062306a36Sopenharmony_ci		else
636162306a36Sopenharmony_ci		/* set to 128 bytes size if IOCMaxChainSegmentSize is zero */
636262306a36Sopenharmony_ci			ioc->chain_segment_sz = DEFAULT_NUM_FWCHAIN_ELEMTS *
636362306a36Sopenharmony_ci						    MAX_CHAIN_ELEMT_SZ;
636462306a36Sopenharmony_ci	} else
636562306a36Sopenharmony_ci		ioc->chain_segment_sz = ioc->request_sz;
636662306a36Sopenharmony_ci
636762306a36Sopenharmony_ci	/* calculate the max scatter element size */
636862306a36Sopenharmony_ci	sge_size = max_t(u16, ioc->sge_size, ioc->sge_size_ieee);
636962306a36Sopenharmony_ci
637062306a36Sopenharmony_ci retry_allocation:
637162306a36Sopenharmony_ci	total_sz = 0;
637262306a36Sopenharmony_ci	/* calculate number of sg elements left over in the 1st frame */
637362306a36Sopenharmony_ci	max_sge_elements = ioc->request_sz - ((sizeof(Mpi2SCSIIORequest_t) -
637462306a36Sopenharmony_ci	    sizeof(Mpi2SGEIOUnion_t)) + sge_size);
637562306a36Sopenharmony_ci	ioc->max_sges_in_main_message = max_sge_elements/sge_size;
637662306a36Sopenharmony_ci
637762306a36Sopenharmony_ci	/* now do the same for a chain buffer */
637862306a36Sopenharmony_ci	max_sge_elements = ioc->chain_segment_sz - sge_size;
637962306a36Sopenharmony_ci	ioc->max_sges_in_chain_message = max_sge_elements/sge_size;
638062306a36Sopenharmony_ci
638162306a36Sopenharmony_ci	/*
638262306a36Sopenharmony_ci	 *  MPT3SAS_SG_DEPTH = CONFIG_FUSION_MAX_SGE
638362306a36Sopenharmony_ci	 */
638462306a36Sopenharmony_ci	chains_needed_per_io = ((ioc->shost->sg_tablesize -
638562306a36Sopenharmony_ci	   ioc->max_sges_in_main_message)/ioc->max_sges_in_chain_message)
638662306a36Sopenharmony_ci	    + 1;
638762306a36Sopenharmony_ci	if (chains_needed_per_io > facts->MaxChainDepth) {
638862306a36Sopenharmony_ci		chains_needed_per_io = facts->MaxChainDepth;
638962306a36Sopenharmony_ci		ioc->shost->sg_tablesize = min_t(u16,
639062306a36Sopenharmony_ci		ioc->max_sges_in_main_message + (ioc->max_sges_in_chain_message
639162306a36Sopenharmony_ci		* chains_needed_per_io), ioc->shost->sg_tablesize);
639262306a36Sopenharmony_ci	}
639362306a36Sopenharmony_ci	ioc->chains_needed_per_io = chains_needed_per_io;
639462306a36Sopenharmony_ci
639562306a36Sopenharmony_ci	/* reply free queue sizing - taking into account for 64 FW events */
639662306a36Sopenharmony_ci	ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64;
639762306a36Sopenharmony_ci
639862306a36Sopenharmony_ci	/* mCPU manage single counters for simplicity */
639962306a36Sopenharmony_ci	if (ioc->is_mcpu_endpoint)
640062306a36Sopenharmony_ci		ioc->reply_post_queue_depth = ioc->reply_free_queue_depth;
640162306a36Sopenharmony_ci	else {
640262306a36Sopenharmony_ci		/* calculate reply descriptor post queue depth */
640362306a36Sopenharmony_ci		ioc->reply_post_queue_depth = ioc->hba_queue_depth +
640462306a36Sopenharmony_ci			ioc->reply_free_queue_depth +  1;
640562306a36Sopenharmony_ci		/* align the reply post queue on the next 16 count boundary */
640662306a36Sopenharmony_ci		if (ioc->reply_post_queue_depth % 16)
640762306a36Sopenharmony_ci			ioc->reply_post_queue_depth += 16 -
640862306a36Sopenharmony_ci				(ioc->reply_post_queue_depth % 16);
640962306a36Sopenharmony_ci	}
641062306a36Sopenharmony_ci
641162306a36Sopenharmony_ci	if (ioc->reply_post_queue_depth >
641262306a36Sopenharmony_ci	    facts->MaxReplyDescriptorPostQueueDepth) {
641362306a36Sopenharmony_ci		ioc->reply_post_queue_depth =
641462306a36Sopenharmony_ci				facts->MaxReplyDescriptorPostQueueDepth -
641562306a36Sopenharmony_ci		    (facts->MaxReplyDescriptorPostQueueDepth % 16);
641662306a36Sopenharmony_ci		ioc->hba_queue_depth =
641762306a36Sopenharmony_ci				((ioc->reply_post_queue_depth - 64) / 2) - 1;
641862306a36Sopenharmony_ci		ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64;
641962306a36Sopenharmony_ci	}
642062306a36Sopenharmony_ci
642162306a36Sopenharmony_ci	ioc_info(ioc,
642262306a36Sopenharmony_ci	    "scatter gather: sge_in_main_msg(%d), sge_per_chain(%d), "
642362306a36Sopenharmony_ci	    "sge_per_io(%d), chains_per_io(%d)\n",
642462306a36Sopenharmony_ci	    ioc->max_sges_in_main_message,
642562306a36Sopenharmony_ci	    ioc->max_sges_in_chain_message,
642662306a36Sopenharmony_ci	    ioc->shost->sg_tablesize,
642762306a36Sopenharmony_ci	    ioc->chains_needed_per_io);
642862306a36Sopenharmony_ci
642962306a36Sopenharmony_ci	/* reply post queue, 16 byte align */
643062306a36Sopenharmony_ci	reply_post_free_sz = ioc->reply_post_queue_depth *
643162306a36Sopenharmony_ci	    sizeof(Mpi2DefaultReplyDescriptor_t);
643262306a36Sopenharmony_ci	rdpq_sz = reply_post_free_sz * RDPQ_MAX_INDEX_IN_ONE_CHUNK;
643362306a36Sopenharmony_ci	if ((_base_is_controller_msix_enabled(ioc) && !ioc->rdpq_array_enable)
643462306a36Sopenharmony_ci	    || (ioc->reply_queue_count < RDPQ_MAX_INDEX_IN_ONE_CHUNK))
643562306a36Sopenharmony_ci		rdpq_sz = reply_post_free_sz * ioc->reply_queue_count;
643662306a36Sopenharmony_ci	ret = base_alloc_rdpq_dma_pool(ioc, rdpq_sz);
643762306a36Sopenharmony_ci	if (ret == -EAGAIN) {
643862306a36Sopenharmony_ci		/*
643962306a36Sopenharmony_ci		 * Free allocated bad RDPQ memory pools.
644062306a36Sopenharmony_ci		 * Change dma coherent mask to 32 bit and reallocate RDPQ
644162306a36Sopenharmony_ci		 */
644262306a36Sopenharmony_ci		_base_release_memory_pools(ioc);
644362306a36Sopenharmony_ci		ioc->use_32bit_dma = true;
644462306a36Sopenharmony_ci		if (_base_config_dma_addressing(ioc, ioc->pdev) != 0) {
644562306a36Sopenharmony_ci			ioc_err(ioc,
644662306a36Sopenharmony_ci			    "32 DMA mask failed %s\n", pci_name(ioc->pdev));
644762306a36Sopenharmony_ci			return -ENODEV;
644862306a36Sopenharmony_ci		}
644962306a36Sopenharmony_ci		if (base_alloc_rdpq_dma_pool(ioc, rdpq_sz))
645062306a36Sopenharmony_ci			return -ENOMEM;
645162306a36Sopenharmony_ci	} else if (ret == -ENOMEM)
645262306a36Sopenharmony_ci		return -ENOMEM;
645362306a36Sopenharmony_ci	total_sz = rdpq_sz * (!ioc->rdpq_array_enable ? 1 :
645462306a36Sopenharmony_ci	    DIV_ROUND_UP(ioc->reply_queue_count, RDPQ_MAX_INDEX_IN_ONE_CHUNK));
645562306a36Sopenharmony_ci	ioc->scsiio_depth = ioc->hba_queue_depth -
645662306a36Sopenharmony_ci	    ioc->hi_priority_depth - ioc->internal_depth;
645762306a36Sopenharmony_ci
645862306a36Sopenharmony_ci	/* set the scsi host can_queue depth
645962306a36Sopenharmony_ci	 * with some internal commands that could be outstanding
646062306a36Sopenharmony_ci	 */
646162306a36Sopenharmony_ci	ioc->shost->can_queue = ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT;
646262306a36Sopenharmony_ci	dinitprintk(ioc,
646362306a36Sopenharmony_ci		    ioc_info(ioc, "scsi host: can_queue depth (%d)\n",
646462306a36Sopenharmony_ci			     ioc->shost->can_queue));
646562306a36Sopenharmony_ci
646662306a36Sopenharmony_ci	/* contiguous pool for request and chains, 16 byte align, one extra "
646762306a36Sopenharmony_ci	 * "frame for smid=0
646862306a36Sopenharmony_ci	 */
646962306a36Sopenharmony_ci	ioc->chain_depth = ioc->chains_needed_per_io * ioc->scsiio_depth;
647062306a36Sopenharmony_ci	sz = ((ioc->scsiio_depth + 1) * ioc->request_sz);
647162306a36Sopenharmony_ci
647262306a36Sopenharmony_ci	/* hi-priority queue */
647362306a36Sopenharmony_ci	sz += (ioc->hi_priority_depth * ioc->request_sz);
647462306a36Sopenharmony_ci
647562306a36Sopenharmony_ci	/* internal queue */
647662306a36Sopenharmony_ci	sz += (ioc->internal_depth * ioc->request_sz);
647762306a36Sopenharmony_ci
647862306a36Sopenharmony_ci	ioc->request_dma_sz = sz;
647962306a36Sopenharmony_ci	ioc->request = dma_alloc_coherent(&ioc->pdev->dev, sz,
648062306a36Sopenharmony_ci			&ioc->request_dma, GFP_KERNEL);
648162306a36Sopenharmony_ci	if (!ioc->request) {
648262306a36Sopenharmony_ci		ioc_err(ioc, "request pool: dma_alloc_coherent failed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), total(%d kB)\n",
648362306a36Sopenharmony_ci			ioc->hba_queue_depth, ioc->chains_needed_per_io,
648462306a36Sopenharmony_ci			ioc->request_sz, sz / 1024);
648562306a36Sopenharmony_ci		if (ioc->scsiio_depth < MPT3SAS_SAS_QUEUE_DEPTH)
648662306a36Sopenharmony_ci			goto out;
648762306a36Sopenharmony_ci		retry_sz = 64;
648862306a36Sopenharmony_ci		ioc->hba_queue_depth -= retry_sz;
648962306a36Sopenharmony_ci		_base_release_memory_pools(ioc);
649062306a36Sopenharmony_ci		goto retry_allocation;
649162306a36Sopenharmony_ci	}
649262306a36Sopenharmony_ci
649362306a36Sopenharmony_ci	if (retry_sz)
649462306a36Sopenharmony_ci		ioc_err(ioc, "request pool: dma_alloc_coherent succeed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), total(%d kb)\n",
649562306a36Sopenharmony_ci			ioc->hba_queue_depth, ioc->chains_needed_per_io,
649662306a36Sopenharmony_ci			ioc->request_sz, sz / 1024);
649762306a36Sopenharmony_ci
649862306a36Sopenharmony_ci	/* hi-priority queue */
649962306a36Sopenharmony_ci	ioc->hi_priority = ioc->request + ((ioc->scsiio_depth + 1) *
650062306a36Sopenharmony_ci	    ioc->request_sz);
650162306a36Sopenharmony_ci	ioc->hi_priority_dma = ioc->request_dma + ((ioc->scsiio_depth + 1) *
650262306a36Sopenharmony_ci	    ioc->request_sz);
650362306a36Sopenharmony_ci
650462306a36Sopenharmony_ci	/* internal queue */
650562306a36Sopenharmony_ci	ioc->internal = ioc->hi_priority + (ioc->hi_priority_depth *
650662306a36Sopenharmony_ci	    ioc->request_sz);
650762306a36Sopenharmony_ci	ioc->internal_dma = ioc->hi_priority_dma + (ioc->hi_priority_depth *
650862306a36Sopenharmony_ci	    ioc->request_sz);
650962306a36Sopenharmony_ci
651062306a36Sopenharmony_ci	ioc_info(ioc,
651162306a36Sopenharmony_ci	    "request pool(0x%p) - dma(0x%llx): "
651262306a36Sopenharmony_ci	    "depth(%d), frame_size(%d), pool_size(%d kB)\n",
651362306a36Sopenharmony_ci	    ioc->request, (unsigned long long) ioc->request_dma,
651462306a36Sopenharmony_ci	    ioc->hba_queue_depth, ioc->request_sz,
651562306a36Sopenharmony_ci	    (ioc->hba_queue_depth * ioc->request_sz) / 1024);
651662306a36Sopenharmony_ci
651762306a36Sopenharmony_ci	total_sz += sz;
651862306a36Sopenharmony_ci
651962306a36Sopenharmony_ci	dinitprintk(ioc,
652062306a36Sopenharmony_ci		    ioc_info(ioc, "scsiio(0x%p): depth(%d)\n",
652162306a36Sopenharmony_ci			     ioc->request, ioc->scsiio_depth));
652262306a36Sopenharmony_ci
652362306a36Sopenharmony_ci	ioc->chain_depth = min_t(u32, ioc->chain_depth, MAX_CHAIN_DEPTH);
652462306a36Sopenharmony_ci	sz = ioc->scsiio_depth * sizeof(struct chain_lookup);
652562306a36Sopenharmony_ci	ioc->chain_lookup = kzalloc(sz, GFP_KERNEL);
652662306a36Sopenharmony_ci	if (!ioc->chain_lookup) {
652762306a36Sopenharmony_ci		ioc_err(ioc, "chain_lookup: __get_free_pages failed\n");
652862306a36Sopenharmony_ci		goto out;
652962306a36Sopenharmony_ci	}
653062306a36Sopenharmony_ci
653162306a36Sopenharmony_ci	sz = ioc->chains_needed_per_io * sizeof(struct chain_tracker);
653262306a36Sopenharmony_ci	for (i = 0; i < ioc->scsiio_depth; i++) {
653362306a36Sopenharmony_ci		ioc->chain_lookup[i].chains_per_smid = kzalloc(sz, GFP_KERNEL);
653462306a36Sopenharmony_ci		if (!ioc->chain_lookup[i].chains_per_smid) {
653562306a36Sopenharmony_ci			ioc_err(ioc, "chain_lookup: kzalloc failed\n");
653662306a36Sopenharmony_ci			goto out;
653762306a36Sopenharmony_ci		}
653862306a36Sopenharmony_ci	}
653962306a36Sopenharmony_ci
654062306a36Sopenharmony_ci	/* initialize hi-priority queue smid's */
654162306a36Sopenharmony_ci	ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth,
654262306a36Sopenharmony_ci	    sizeof(struct request_tracker), GFP_KERNEL);
654362306a36Sopenharmony_ci	if (!ioc->hpr_lookup) {
654462306a36Sopenharmony_ci		ioc_err(ioc, "hpr_lookup: kcalloc failed\n");
654562306a36Sopenharmony_ci		goto out;
654662306a36Sopenharmony_ci	}
654762306a36Sopenharmony_ci	ioc->hi_priority_smid = ioc->scsiio_depth + 1;
654862306a36Sopenharmony_ci	dinitprintk(ioc,
654962306a36Sopenharmony_ci		    ioc_info(ioc, "hi_priority(0x%p): depth(%d), start smid(%d)\n",
655062306a36Sopenharmony_ci			     ioc->hi_priority,
655162306a36Sopenharmony_ci			     ioc->hi_priority_depth, ioc->hi_priority_smid));
655262306a36Sopenharmony_ci
655362306a36Sopenharmony_ci	/* initialize internal queue smid's */
655462306a36Sopenharmony_ci	ioc->internal_lookup = kcalloc(ioc->internal_depth,
655562306a36Sopenharmony_ci	    sizeof(struct request_tracker), GFP_KERNEL);
655662306a36Sopenharmony_ci	if (!ioc->internal_lookup) {
655762306a36Sopenharmony_ci		ioc_err(ioc, "internal_lookup: kcalloc failed\n");
655862306a36Sopenharmony_ci		goto out;
655962306a36Sopenharmony_ci	}
656062306a36Sopenharmony_ci	ioc->internal_smid = ioc->hi_priority_smid + ioc->hi_priority_depth;
656162306a36Sopenharmony_ci	dinitprintk(ioc,
656262306a36Sopenharmony_ci		    ioc_info(ioc, "internal(0x%p): depth(%d), start smid(%d)\n",
656362306a36Sopenharmony_ci			     ioc->internal,
656462306a36Sopenharmony_ci			     ioc->internal_depth, ioc->internal_smid));
656562306a36Sopenharmony_ci
656662306a36Sopenharmony_ci	ioc->io_queue_num = kcalloc(ioc->scsiio_depth,
656762306a36Sopenharmony_ci	    sizeof(u16), GFP_KERNEL);
656862306a36Sopenharmony_ci	if (!ioc->io_queue_num)
656962306a36Sopenharmony_ci		goto out;
657062306a36Sopenharmony_ci	/*
657162306a36Sopenharmony_ci	 * The number of NVMe page sized blocks needed is:
657262306a36Sopenharmony_ci	 *     (((sg_tablesize * 8) - 1) / (page_size - 8)) + 1
657362306a36Sopenharmony_ci	 * ((sg_tablesize * 8) - 1) is the max PRP's minus the first PRP entry
657462306a36Sopenharmony_ci	 * that is placed in the main message frame.  8 is the size of each PRP
657562306a36Sopenharmony_ci	 * entry or PRP list pointer entry.  8 is subtracted from page_size
657662306a36Sopenharmony_ci	 * because of the PRP list pointer entry at the end of a page, so this
657762306a36Sopenharmony_ci	 * is not counted as a PRP entry.  The 1 added page is a round up.
657862306a36Sopenharmony_ci	 *
657962306a36Sopenharmony_ci	 * To avoid allocation failures due to the amount of memory that could
658062306a36Sopenharmony_ci	 * be required for NVMe PRP's, only each set of NVMe blocks will be
658162306a36Sopenharmony_ci	 * contiguous, so a new set is allocated for each possible I/O.
658262306a36Sopenharmony_ci	 */
658362306a36Sopenharmony_ci
658462306a36Sopenharmony_ci	ioc->chains_per_prp_buffer = 0;
658562306a36Sopenharmony_ci	if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_NVME_DEVICES) {
658662306a36Sopenharmony_ci		nvme_blocks_needed =
658762306a36Sopenharmony_ci			(ioc->shost->sg_tablesize * NVME_PRP_SIZE) - 1;
658862306a36Sopenharmony_ci		nvme_blocks_needed /= (ioc->page_size - NVME_PRP_SIZE);
658962306a36Sopenharmony_ci		nvme_blocks_needed++;
659062306a36Sopenharmony_ci
659162306a36Sopenharmony_ci		sz = sizeof(struct pcie_sg_list) * ioc->scsiio_depth;
659262306a36Sopenharmony_ci		ioc->pcie_sg_lookup = kzalloc(sz, GFP_KERNEL);
659362306a36Sopenharmony_ci		if (!ioc->pcie_sg_lookup) {
659462306a36Sopenharmony_ci			ioc_info(ioc, "PCIe SGL lookup: kzalloc failed\n");
659562306a36Sopenharmony_ci			goto out;
659662306a36Sopenharmony_ci		}
659762306a36Sopenharmony_ci		sz = nvme_blocks_needed * ioc->page_size;
659862306a36Sopenharmony_ci		rc = _base_allocate_pcie_sgl_pool(ioc, sz);
659962306a36Sopenharmony_ci		if (rc == -ENOMEM)
660062306a36Sopenharmony_ci			return -ENOMEM;
660162306a36Sopenharmony_ci		else if (rc == -EAGAIN)
660262306a36Sopenharmony_ci			goto try_32bit_dma;
660362306a36Sopenharmony_ci		total_sz += sz * ioc->scsiio_depth;
660462306a36Sopenharmony_ci	}
660562306a36Sopenharmony_ci
660662306a36Sopenharmony_ci	rc = _base_allocate_chain_dma_pool(ioc, ioc->chain_segment_sz);
660762306a36Sopenharmony_ci	if (rc == -ENOMEM)
660862306a36Sopenharmony_ci		return -ENOMEM;
660962306a36Sopenharmony_ci	else if (rc == -EAGAIN)
661062306a36Sopenharmony_ci		goto try_32bit_dma;
661162306a36Sopenharmony_ci	total_sz += ioc->chain_segment_sz * ((ioc->chains_needed_per_io -
661262306a36Sopenharmony_ci		ioc->chains_per_prp_buffer) * ioc->scsiio_depth);
661362306a36Sopenharmony_ci	dinitprintk(ioc,
661462306a36Sopenharmony_ci	    ioc_info(ioc, "chain pool depth(%d), frame_size(%d), pool_size(%d kB)\n",
661562306a36Sopenharmony_ci	    ioc->chain_depth, ioc->chain_segment_sz,
661662306a36Sopenharmony_ci	    (ioc->chain_depth * ioc->chain_segment_sz) / 1024));
661762306a36Sopenharmony_ci	/* sense buffers, 4 byte align */
661862306a36Sopenharmony_ci	sense_sz = ioc->scsiio_depth * SCSI_SENSE_BUFFERSIZE;
661962306a36Sopenharmony_ci	rc = _base_allocate_sense_dma_pool(ioc, sense_sz);
662062306a36Sopenharmony_ci	if (rc  == -ENOMEM)
662162306a36Sopenharmony_ci		return -ENOMEM;
662262306a36Sopenharmony_ci	else if (rc == -EAGAIN)
662362306a36Sopenharmony_ci		goto try_32bit_dma;
662462306a36Sopenharmony_ci	total_sz += sense_sz;
662562306a36Sopenharmony_ci	/* reply pool, 4 byte align */
662662306a36Sopenharmony_ci	sz = ioc->reply_free_queue_depth * ioc->reply_sz;
662762306a36Sopenharmony_ci	rc = _base_allocate_reply_pool(ioc, sz);
662862306a36Sopenharmony_ci	if (rc == -ENOMEM)
662962306a36Sopenharmony_ci		return -ENOMEM;
663062306a36Sopenharmony_ci	else if (rc == -EAGAIN)
663162306a36Sopenharmony_ci		goto try_32bit_dma;
663262306a36Sopenharmony_ci	total_sz += sz;
663362306a36Sopenharmony_ci
663462306a36Sopenharmony_ci	/* reply free queue, 16 byte align */
663562306a36Sopenharmony_ci	sz = ioc->reply_free_queue_depth * 4;
663662306a36Sopenharmony_ci	rc = _base_allocate_reply_free_dma_pool(ioc, sz);
663762306a36Sopenharmony_ci	if (rc  == -ENOMEM)
663862306a36Sopenharmony_ci		return -ENOMEM;
663962306a36Sopenharmony_ci	else if (rc == -EAGAIN)
664062306a36Sopenharmony_ci		goto try_32bit_dma;
664162306a36Sopenharmony_ci	dinitprintk(ioc,
664262306a36Sopenharmony_ci		    ioc_info(ioc, "reply_free_dma (0x%llx)\n",
664362306a36Sopenharmony_ci			     (unsigned long long)ioc->reply_free_dma));
664462306a36Sopenharmony_ci	total_sz += sz;
664562306a36Sopenharmony_ci	if (ioc->rdpq_array_enable) {
664662306a36Sopenharmony_ci		reply_post_free_array_sz = ioc->reply_queue_count *
664762306a36Sopenharmony_ci		    sizeof(Mpi2IOCInitRDPQArrayEntry);
664862306a36Sopenharmony_ci		rc = _base_allocate_reply_post_free_array(ioc,
664962306a36Sopenharmony_ci		    reply_post_free_array_sz);
665062306a36Sopenharmony_ci		if (rc == -ENOMEM)
665162306a36Sopenharmony_ci			return -ENOMEM;
665262306a36Sopenharmony_ci		else if (rc == -EAGAIN)
665362306a36Sopenharmony_ci			goto try_32bit_dma;
665462306a36Sopenharmony_ci	}
665562306a36Sopenharmony_ci	ioc->config_page_sz = 512;
665662306a36Sopenharmony_ci	ioc->config_page = dma_alloc_coherent(&ioc->pdev->dev,
665762306a36Sopenharmony_ci			ioc->config_page_sz, &ioc->config_page_dma, GFP_KERNEL);
665862306a36Sopenharmony_ci	if (!ioc->config_page) {
665962306a36Sopenharmony_ci		ioc_err(ioc, "config page: dma_pool_alloc failed\n");
666062306a36Sopenharmony_ci		goto out;
666162306a36Sopenharmony_ci	}
666262306a36Sopenharmony_ci
666362306a36Sopenharmony_ci	ioc_info(ioc, "config page(0x%p) - dma(0x%llx): size(%d)\n",
666462306a36Sopenharmony_ci	    ioc->config_page, (unsigned long long)ioc->config_page_dma,
666562306a36Sopenharmony_ci	    ioc->config_page_sz);
666662306a36Sopenharmony_ci	total_sz += ioc->config_page_sz;
666762306a36Sopenharmony_ci
666862306a36Sopenharmony_ci	ioc_info(ioc, "Allocated physical memory: size(%d kB)\n",
666962306a36Sopenharmony_ci		 total_sz / 1024);
667062306a36Sopenharmony_ci	ioc_info(ioc, "Current Controller Queue Depth(%d),Max Controller Queue Depth(%d)\n",
667162306a36Sopenharmony_ci		 ioc->shost->can_queue, facts->RequestCredit);
667262306a36Sopenharmony_ci	ioc_info(ioc, "Scatter Gather Elements per IO(%d)\n",
667362306a36Sopenharmony_ci		 ioc->shost->sg_tablesize);
667462306a36Sopenharmony_ci	return 0;
667562306a36Sopenharmony_ci
667662306a36Sopenharmony_citry_32bit_dma:
667762306a36Sopenharmony_ci	_base_release_memory_pools(ioc);
667862306a36Sopenharmony_ci	if (ioc->use_32bit_dma && (ioc->dma_mask > 32)) {
667962306a36Sopenharmony_ci		/* Change dma coherent mask to 32 bit and reallocate */
668062306a36Sopenharmony_ci		if (_base_config_dma_addressing(ioc, ioc->pdev) != 0) {
668162306a36Sopenharmony_ci			pr_err("Setting 32 bit coherent DMA mask Failed %s\n",
668262306a36Sopenharmony_ci			    pci_name(ioc->pdev));
668362306a36Sopenharmony_ci			return -ENODEV;
668462306a36Sopenharmony_ci		}
668562306a36Sopenharmony_ci	} else if (_base_reduce_hba_queue_depth(ioc) != 0)
668662306a36Sopenharmony_ci		return -ENOMEM;
668762306a36Sopenharmony_ci	goto retry_allocation;
668862306a36Sopenharmony_ci
668962306a36Sopenharmony_ci out:
669062306a36Sopenharmony_ci	return -ENOMEM;
669162306a36Sopenharmony_ci}
669262306a36Sopenharmony_ci
669362306a36Sopenharmony_ci/**
669462306a36Sopenharmony_ci * mpt3sas_base_get_iocstate - Get the current state of a MPT adapter.
669562306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure
669662306a36Sopenharmony_ci * @cooked: Request raw or cooked IOC state
669762306a36Sopenharmony_ci *
669862306a36Sopenharmony_ci * Return: all IOC Doorbell register bits if cooked==0, else just the
669962306a36Sopenharmony_ci * Doorbell bits in MPI_IOC_STATE_MASK.
670062306a36Sopenharmony_ci */
670162306a36Sopenharmony_ciu32
670262306a36Sopenharmony_cimpt3sas_base_get_iocstate(struct MPT3SAS_ADAPTER *ioc, int cooked)
670362306a36Sopenharmony_ci{
670462306a36Sopenharmony_ci	u32 s, sc;
670562306a36Sopenharmony_ci
670662306a36Sopenharmony_ci	s = ioc->base_readl_ext_retry(&ioc->chip->Doorbell);
670762306a36Sopenharmony_ci	sc = s & MPI2_IOC_STATE_MASK;
670862306a36Sopenharmony_ci	return cooked ? sc : s;
670962306a36Sopenharmony_ci}
671062306a36Sopenharmony_ci
671162306a36Sopenharmony_ci/**
671262306a36Sopenharmony_ci * _base_wait_on_iocstate - waiting on a particular ioc state
671362306a36Sopenharmony_ci * @ioc: ?
671462306a36Sopenharmony_ci * @ioc_state: controller state { READY, OPERATIONAL, or RESET }
671562306a36Sopenharmony_ci * @timeout: timeout in second
671662306a36Sopenharmony_ci *
671762306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
671862306a36Sopenharmony_ci */
671962306a36Sopenharmony_cistatic int
672062306a36Sopenharmony_ci_base_wait_on_iocstate(struct MPT3SAS_ADAPTER *ioc, u32 ioc_state, int timeout)
672162306a36Sopenharmony_ci{
672262306a36Sopenharmony_ci	u32 count, cntdn;
672362306a36Sopenharmony_ci	u32 current_state;
672462306a36Sopenharmony_ci
672562306a36Sopenharmony_ci	count = 0;
672662306a36Sopenharmony_ci	cntdn = 1000 * timeout;
672762306a36Sopenharmony_ci	do {
672862306a36Sopenharmony_ci		current_state = mpt3sas_base_get_iocstate(ioc, 1);
672962306a36Sopenharmony_ci		if (current_state == ioc_state)
673062306a36Sopenharmony_ci			return 0;
673162306a36Sopenharmony_ci		if (count && current_state == MPI2_IOC_STATE_FAULT)
673262306a36Sopenharmony_ci			break;
673362306a36Sopenharmony_ci		if (count && current_state == MPI2_IOC_STATE_COREDUMP)
673462306a36Sopenharmony_ci			break;
673562306a36Sopenharmony_ci
673662306a36Sopenharmony_ci		usleep_range(1000, 1500);
673762306a36Sopenharmony_ci		count++;
673862306a36Sopenharmony_ci	} while (--cntdn);
673962306a36Sopenharmony_ci
674062306a36Sopenharmony_ci	return current_state;
674162306a36Sopenharmony_ci}
674262306a36Sopenharmony_ci
674362306a36Sopenharmony_ci/**
674462306a36Sopenharmony_ci * _base_dump_reg_set -	This function will print hexdump of register set.
674562306a36Sopenharmony_ci * @ioc: per adapter object
674662306a36Sopenharmony_ci *
674762306a36Sopenharmony_ci * Return: nothing.
674862306a36Sopenharmony_ci */
674962306a36Sopenharmony_cistatic inline void
675062306a36Sopenharmony_ci_base_dump_reg_set(struct MPT3SAS_ADAPTER *ioc)
675162306a36Sopenharmony_ci{
675262306a36Sopenharmony_ci	unsigned int i, sz = 256;
675362306a36Sopenharmony_ci	u32 __iomem *reg = (u32 __iomem *)ioc->chip;
675462306a36Sopenharmony_ci
675562306a36Sopenharmony_ci	ioc_info(ioc, "System Register set:\n");
675662306a36Sopenharmony_ci	for (i = 0; i < (sz / sizeof(u32)); i++)
675762306a36Sopenharmony_ci		pr_info("%08x: %08x\n", (i * 4), readl(&reg[i]));
675862306a36Sopenharmony_ci}
675962306a36Sopenharmony_ci
676062306a36Sopenharmony_ci/**
676162306a36Sopenharmony_ci * _base_wait_for_doorbell_int - waiting for controller interrupt(generated by
676262306a36Sopenharmony_ci * a write to the doorbell)
676362306a36Sopenharmony_ci * @ioc: per adapter object
676462306a36Sopenharmony_ci * @timeout: timeout in seconds
676562306a36Sopenharmony_ci *
676662306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
676762306a36Sopenharmony_ci *
676862306a36Sopenharmony_ci * Notes: MPI2_HIS_IOC2SYS_DB_STATUS - set to one when IOC writes to doorbell.
676962306a36Sopenharmony_ci */
677062306a36Sopenharmony_ci
677162306a36Sopenharmony_cistatic int
677262306a36Sopenharmony_ci_base_wait_for_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout)
677362306a36Sopenharmony_ci{
677462306a36Sopenharmony_ci	u32 cntdn, count;
677562306a36Sopenharmony_ci	u32 int_status;
677662306a36Sopenharmony_ci
677762306a36Sopenharmony_ci	count = 0;
677862306a36Sopenharmony_ci	cntdn = 1000 * timeout;
677962306a36Sopenharmony_ci	do {
678062306a36Sopenharmony_ci		int_status = ioc->base_readl(&ioc->chip->HostInterruptStatus);
678162306a36Sopenharmony_ci		if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
678262306a36Sopenharmony_ci			dhsprintk(ioc,
678362306a36Sopenharmony_ci				  ioc_info(ioc, "%s: successful count(%d), timeout(%d)\n",
678462306a36Sopenharmony_ci					   __func__, count, timeout));
678562306a36Sopenharmony_ci			return 0;
678662306a36Sopenharmony_ci		}
678762306a36Sopenharmony_ci
678862306a36Sopenharmony_ci		usleep_range(1000, 1500);
678962306a36Sopenharmony_ci		count++;
679062306a36Sopenharmony_ci	} while (--cntdn);
679162306a36Sopenharmony_ci
679262306a36Sopenharmony_ci	ioc_err(ioc, "%s: failed due to timeout count(%d), int_status(%x)!\n",
679362306a36Sopenharmony_ci		__func__, count, int_status);
679462306a36Sopenharmony_ci	return -EFAULT;
679562306a36Sopenharmony_ci}
679662306a36Sopenharmony_ci
679762306a36Sopenharmony_cistatic int
679862306a36Sopenharmony_ci_base_spin_on_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout)
679962306a36Sopenharmony_ci{
680062306a36Sopenharmony_ci	u32 cntdn, count;
680162306a36Sopenharmony_ci	u32 int_status;
680262306a36Sopenharmony_ci
680362306a36Sopenharmony_ci	count = 0;
680462306a36Sopenharmony_ci	cntdn = 2000 * timeout;
680562306a36Sopenharmony_ci	do {
680662306a36Sopenharmony_ci		int_status = ioc->base_readl(&ioc->chip->HostInterruptStatus);
680762306a36Sopenharmony_ci		if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
680862306a36Sopenharmony_ci			dhsprintk(ioc,
680962306a36Sopenharmony_ci				  ioc_info(ioc, "%s: successful count(%d), timeout(%d)\n",
681062306a36Sopenharmony_ci					   __func__, count, timeout));
681162306a36Sopenharmony_ci			return 0;
681262306a36Sopenharmony_ci		}
681362306a36Sopenharmony_ci
681462306a36Sopenharmony_ci		udelay(500);
681562306a36Sopenharmony_ci		count++;
681662306a36Sopenharmony_ci	} while (--cntdn);
681762306a36Sopenharmony_ci
681862306a36Sopenharmony_ci	ioc_err(ioc, "%s: failed due to timeout count(%d), int_status(%x)!\n",
681962306a36Sopenharmony_ci		__func__, count, int_status);
682062306a36Sopenharmony_ci	return -EFAULT;
682162306a36Sopenharmony_ci
682262306a36Sopenharmony_ci}
682362306a36Sopenharmony_ci
682462306a36Sopenharmony_ci/**
682562306a36Sopenharmony_ci * _base_wait_for_doorbell_ack - waiting for controller to read the doorbell.
682662306a36Sopenharmony_ci * @ioc: per adapter object
682762306a36Sopenharmony_ci * @timeout: timeout in second
682862306a36Sopenharmony_ci *
682962306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
683062306a36Sopenharmony_ci *
683162306a36Sopenharmony_ci * Notes: MPI2_HIS_SYS2IOC_DB_STATUS - set to one when host writes to
683262306a36Sopenharmony_ci * doorbell.
683362306a36Sopenharmony_ci */
683462306a36Sopenharmony_cistatic int
683562306a36Sopenharmony_ci_base_wait_for_doorbell_ack(struct MPT3SAS_ADAPTER *ioc, int timeout)
683662306a36Sopenharmony_ci{
683762306a36Sopenharmony_ci	u32 cntdn, count;
683862306a36Sopenharmony_ci	u32 int_status;
683962306a36Sopenharmony_ci	u32 doorbell;
684062306a36Sopenharmony_ci
684162306a36Sopenharmony_ci	count = 0;
684262306a36Sopenharmony_ci	cntdn = 1000 * timeout;
684362306a36Sopenharmony_ci	do {
684462306a36Sopenharmony_ci		int_status = ioc->base_readl(&ioc->chip->HostInterruptStatus);
684562306a36Sopenharmony_ci		if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) {
684662306a36Sopenharmony_ci			dhsprintk(ioc,
684762306a36Sopenharmony_ci				  ioc_info(ioc, "%s: successful count(%d), timeout(%d)\n",
684862306a36Sopenharmony_ci					   __func__, count, timeout));
684962306a36Sopenharmony_ci			return 0;
685062306a36Sopenharmony_ci		} else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
685162306a36Sopenharmony_ci			doorbell = ioc->base_readl_ext_retry(&ioc->chip->Doorbell);
685262306a36Sopenharmony_ci			if ((doorbell & MPI2_IOC_STATE_MASK) ==
685362306a36Sopenharmony_ci			    MPI2_IOC_STATE_FAULT) {
685462306a36Sopenharmony_ci				mpt3sas_print_fault_code(ioc, doorbell);
685562306a36Sopenharmony_ci				return -EFAULT;
685662306a36Sopenharmony_ci			}
685762306a36Sopenharmony_ci			if ((doorbell & MPI2_IOC_STATE_MASK) ==
685862306a36Sopenharmony_ci			    MPI2_IOC_STATE_COREDUMP) {
685962306a36Sopenharmony_ci				mpt3sas_print_coredump_info(ioc, doorbell);
686062306a36Sopenharmony_ci				return -EFAULT;
686162306a36Sopenharmony_ci			}
686262306a36Sopenharmony_ci		} else if (int_status == 0xFFFFFFFF)
686362306a36Sopenharmony_ci			goto out;
686462306a36Sopenharmony_ci
686562306a36Sopenharmony_ci		usleep_range(1000, 1500);
686662306a36Sopenharmony_ci		count++;
686762306a36Sopenharmony_ci	} while (--cntdn);
686862306a36Sopenharmony_ci
686962306a36Sopenharmony_ci out:
687062306a36Sopenharmony_ci	ioc_err(ioc, "%s: failed due to timeout count(%d), int_status(%x)!\n",
687162306a36Sopenharmony_ci		__func__, count, int_status);
687262306a36Sopenharmony_ci	return -EFAULT;
687362306a36Sopenharmony_ci}
687462306a36Sopenharmony_ci
687562306a36Sopenharmony_ci/**
687662306a36Sopenharmony_ci * _base_wait_for_doorbell_not_used - waiting for doorbell to not be in use
687762306a36Sopenharmony_ci * @ioc: per adapter object
687862306a36Sopenharmony_ci * @timeout: timeout in second
687962306a36Sopenharmony_ci *
688062306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
688162306a36Sopenharmony_ci */
688262306a36Sopenharmony_cistatic int
688362306a36Sopenharmony_ci_base_wait_for_doorbell_not_used(struct MPT3SAS_ADAPTER *ioc, int timeout)
688462306a36Sopenharmony_ci{
688562306a36Sopenharmony_ci	u32 cntdn, count;
688662306a36Sopenharmony_ci	u32 doorbell_reg;
688762306a36Sopenharmony_ci
688862306a36Sopenharmony_ci	count = 0;
688962306a36Sopenharmony_ci	cntdn = 1000 * timeout;
689062306a36Sopenharmony_ci	do {
689162306a36Sopenharmony_ci		doorbell_reg = ioc->base_readl_ext_retry(&ioc->chip->Doorbell);
689262306a36Sopenharmony_ci		if (!(doorbell_reg & MPI2_DOORBELL_USED)) {
689362306a36Sopenharmony_ci			dhsprintk(ioc,
689462306a36Sopenharmony_ci				  ioc_info(ioc, "%s: successful count(%d), timeout(%d)\n",
689562306a36Sopenharmony_ci					   __func__, count, timeout));
689662306a36Sopenharmony_ci			return 0;
689762306a36Sopenharmony_ci		}
689862306a36Sopenharmony_ci
689962306a36Sopenharmony_ci		usleep_range(1000, 1500);
690062306a36Sopenharmony_ci		count++;
690162306a36Sopenharmony_ci	} while (--cntdn);
690262306a36Sopenharmony_ci
690362306a36Sopenharmony_ci	ioc_err(ioc, "%s: failed due to timeout count(%d), doorbell_reg(%x)!\n",
690462306a36Sopenharmony_ci		__func__, count, doorbell_reg);
690562306a36Sopenharmony_ci	return -EFAULT;
690662306a36Sopenharmony_ci}
690762306a36Sopenharmony_ci
690862306a36Sopenharmony_ci/**
690962306a36Sopenharmony_ci * _base_send_ioc_reset - send doorbell reset
691062306a36Sopenharmony_ci * @ioc: per adapter object
691162306a36Sopenharmony_ci * @reset_type: currently only supports: MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET
691262306a36Sopenharmony_ci * @timeout: timeout in second
691362306a36Sopenharmony_ci *
691462306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
691562306a36Sopenharmony_ci */
691662306a36Sopenharmony_cistatic int
691762306a36Sopenharmony_ci_base_send_ioc_reset(struct MPT3SAS_ADAPTER *ioc, u8 reset_type, int timeout)
691862306a36Sopenharmony_ci{
691962306a36Sopenharmony_ci	u32 ioc_state;
692062306a36Sopenharmony_ci	int r = 0;
692162306a36Sopenharmony_ci	unsigned long flags;
692262306a36Sopenharmony_ci
692362306a36Sopenharmony_ci	if (reset_type != MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET) {
692462306a36Sopenharmony_ci		ioc_err(ioc, "%s: unknown reset_type\n", __func__);
692562306a36Sopenharmony_ci		return -EFAULT;
692662306a36Sopenharmony_ci	}
692762306a36Sopenharmony_ci
692862306a36Sopenharmony_ci	if (!(ioc->facts.IOCCapabilities &
692962306a36Sopenharmony_ci	   MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY))
693062306a36Sopenharmony_ci		return -EFAULT;
693162306a36Sopenharmony_ci
693262306a36Sopenharmony_ci	ioc_info(ioc, "sending message unit reset !!\n");
693362306a36Sopenharmony_ci
693462306a36Sopenharmony_ci	writel(reset_type << MPI2_DOORBELL_FUNCTION_SHIFT,
693562306a36Sopenharmony_ci	    &ioc->chip->Doorbell);
693662306a36Sopenharmony_ci	if ((_base_wait_for_doorbell_ack(ioc, 15))) {
693762306a36Sopenharmony_ci		r = -EFAULT;
693862306a36Sopenharmony_ci		goto out;
693962306a36Sopenharmony_ci	}
694062306a36Sopenharmony_ci
694162306a36Sopenharmony_ci	ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, timeout);
694262306a36Sopenharmony_ci	if (ioc_state) {
694362306a36Sopenharmony_ci		ioc_err(ioc, "%s: failed going to ready state (ioc_state=0x%x)\n",
694462306a36Sopenharmony_ci			__func__, ioc_state);
694562306a36Sopenharmony_ci		r = -EFAULT;
694662306a36Sopenharmony_ci		goto out;
694762306a36Sopenharmony_ci	}
694862306a36Sopenharmony_ci out:
694962306a36Sopenharmony_ci	if (r != 0) {
695062306a36Sopenharmony_ci		ioc_state = mpt3sas_base_get_iocstate(ioc, 0);
695162306a36Sopenharmony_ci		spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
695262306a36Sopenharmony_ci		/*
695362306a36Sopenharmony_ci		 * Wait for IOC state CoreDump to clear only during
695462306a36Sopenharmony_ci		 * HBA initialization & release time.
695562306a36Sopenharmony_ci		 */
695662306a36Sopenharmony_ci		if ((ioc_state & MPI2_IOC_STATE_MASK) ==
695762306a36Sopenharmony_ci		    MPI2_IOC_STATE_COREDUMP && (ioc->is_driver_loading == 1 ||
695862306a36Sopenharmony_ci		    ioc->fault_reset_work_q == NULL)) {
695962306a36Sopenharmony_ci			spin_unlock_irqrestore(
696062306a36Sopenharmony_ci			    &ioc->ioc_reset_in_progress_lock, flags);
696162306a36Sopenharmony_ci			mpt3sas_print_coredump_info(ioc, ioc_state);
696262306a36Sopenharmony_ci			mpt3sas_base_wait_for_coredump_completion(ioc,
696362306a36Sopenharmony_ci			    __func__);
696462306a36Sopenharmony_ci			spin_lock_irqsave(
696562306a36Sopenharmony_ci			    &ioc->ioc_reset_in_progress_lock, flags);
696662306a36Sopenharmony_ci		}
696762306a36Sopenharmony_ci		spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
696862306a36Sopenharmony_ci	}
696962306a36Sopenharmony_ci	ioc_info(ioc, "message unit reset: %s\n",
697062306a36Sopenharmony_ci		 r == 0 ? "SUCCESS" : "FAILED");
697162306a36Sopenharmony_ci	return r;
697262306a36Sopenharmony_ci}
697362306a36Sopenharmony_ci
697462306a36Sopenharmony_ci/**
697562306a36Sopenharmony_ci * mpt3sas_wait_for_ioc - IOC's operational state is checked here.
697662306a36Sopenharmony_ci * @ioc: per adapter object
697762306a36Sopenharmony_ci * @timeout: timeout in seconds
697862306a36Sopenharmony_ci *
697962306a36Sopenharmony_ci * Return: Waits up to timeout seconds for the IOC to
698062306a36Sopenharmony_ci * become operational. Returns 0 if IOC is present
698162306a36Sopenharmony_ci * and operational; otherwise returns %-EFAULT.
698262306a36Sopenharmony_ci */
698362306a36Sopenharmony_ci
698462306a36Sopenharmony_ciint
698562306a36Sopenharmony_cimpt3sas_wait_for_ioc(struct MPT3SAS_ADAPTER *ioc, int timeout)
698662306a36Sopenharmony_ci{
698762306a36Sopenharmony_ci	int wait_state_count = 0;
698862306a36Sopenharmony_ci	u32 ioc_state;
698962306a36Sopenharmony_ci
699062306a36Sopenharmony_ci	do {
699162306a36Sopenharmony_ci		ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
699262306a36Sopenharmony_ci		if (ioc_state == MPI2_IOC_STATE_OPERATIONAL)
699362306a36Sopenharmony_ci			break;
699462306a36Sopenharmony_ci
699562306a36Sopenharmony_ci		/*
699662306a36Sopenharmony_ci		 * Watchdog thread will be started after IOC Initialization, so
699762306a36Sopenharmony_ci		 * no need to wait here for IOC state to become operational
699862306a36Sopenharmony_ci		 * when IOC Initialization is on. Instead the driver will
699962306a36Sopenharmony_ci		 * return ETIME status, so that calling function can issue
700062306a36Sopenharmony_ci		 * diag reset operation and retry the command.
700162306a36Sopenharmony_ci		 */
700262306a36Sopenharmony_ci		if (ioc->is_driver_loading)
700362306a36Sopenharmony_ci			return -ETIME;
700462306a36Sopenharmony_ci
700562306a36Sopenharmony_ci		ssleep(1);
700662306a36Sopenharmony_ci		ioc_info(ioc, "%s: waiting for operational state(count=%d)\n",
700762306a36Sopenharmony_ci				__func__, ++wait_state_count);
700862306a36Sopenharmony_ci	} while (--timeout);
700962306a36Sopenharmony_ci	if (!timeout) {
701062306a36Sopenharmony_ci		ioc_err(ioc, "%s: failed due to ioc not operational\n", __func__);
701162306a36Sopenharmony_ci		return -EFAULT;
701262306a36Sopenharmony_ci	}
701362306a36Sopenharmony_ci	if (wait_state_count)
701462306a36Sopenharmony_ci		ioc_info(ioc, "ioc is operational\n");
701562306a36Sopenharmony_ci	return 0;
701662306a36Sopenharmony_ci}
701762306a36Sopenharmony_ci
701862306a36Sopenharmony_ci/**
701962306a36Sopenharmony_ci * _base_handshake_req_reply_wait - send request thru doorbell interface
702062306a36Sopenharmony_ci * @ioc: per adapter object
702162306a36Sopenharmony_ci * @request_bytes: request length
702262306a36Sopenharmony_ci * @request: pointer having request payload
702362306a36Sopenharmony_ci * @reply_bytes: reply length
702462306a36Sopenharmony_ci * @reply: pointer to reply payload
702562306a36Sopenharmony_ci * @timeout: timeout in second
702662306a36Sopenharmony_ci *
702762306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
702862306a36Sopenharmony_ci */
702962306a36Sopenharmony_cistatic int
703062306a36Sopenharmony_ci_base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes,
703162306a36Sopenharmony_ci	u32 *request, int reply_bytes, u16 *reply, int timeout)
703262306a36Sopenharmony_ci{
703362306a36Sopenharmony_ci	MPI2DefaultReply_t *default_reply = (MPI2DefaultReply_t *)reply;
703462306a36Sopenharmony_ci	int i;
703562306a36Sopenharmony_ci	u8 failed;
703662306a36Sopenharmony_ci	__le32 *mfp;
703762306a36Sopenharmony_ci
703862306a36Sopenharmony_ci	/* make sure doorbell is not in use */
703962306a36Sopenharmony_ci	if ((ioc->base_readl_ext_retry(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) {
704062306a36Sopenharmony_ci		ioc_err(ioc, "doorbell is in use (line=%d)\n", __LINE__);
704162306a36Sopenharmony_ci		return -EFAULT;
704262306a36Sopenharmony_ci	}
704362306a36Sopenharmony_ci
704462306a36Sopenharmony_ci	/* clear pending doorbell interrupts from previous state changes */
704562306a36Sopenharmony_ci	if (ioc->base_readl(&ioc->chip->HostInterruptStatus) &
704662306a36Sopenharmony_ci	    MPI2_HIS_IOC2SYS_DB_STATUS)
704762306a36Sopenharmony_ci		writel(0, &ioc->chip->HostInterruptStatus);
704862306a36Sopenharmony_ci
704962306a36Sopenharmony_ci	/* send message to ioc */
705062306a36Sopenharmony_ci	writel(((MPI2_FUNCTION_HANDSHAKE<<MPI2_DOORBELL_FUNCTION_SHIFT) |
705162306a36Sopenharmony_ci	    ((request_bytes/4)<<MPI2_DOORBELL_ADD_DWORDS_SHIFT)),
705262306a36Sopenharmony_ci	    &ioc->chip->Doorbell);
705362306a36Sopenharmony_ci
705462306a36Sopenharmony_ci	if ((_base_spin_on_doorbell_int(ioc, 5))) {
705562306a36Sopenharmony_ci		ioc_err(ioc, "doorbell handshake int failed (line=%d)\n",
705662306a36Sopenharmony_ci			__LINE__);
705762306a36Sopenharmony_ci		return -EFAULT;
705862306a36Sopenharmony_ci	}
705962306a36Sopenharmony_ci	writel(0, &ioc->chip->HostInterruptStatus);
706062306a36Sopenharmony_ci
706162306a36Sopenharmony_ci	if ((_base_wait_for_doorbell_ack(ioc, 5))) {
706262306a36Sopenharmony_ci		ioc_err(ioc, "doorbell handshake ack failed (line=%d)\n",
706362306a36Sopenharmony_ci			__LINE__);
706462306a36Sopenharmony_ci		return -EFAULT;
706562306a36Sopenharmony_ci	}
706662306a36Sopenharmony_ci
706762306a36Sopenharmony_ci	/* send message 32-bits at a time */
706862306a36Sopenharmony_ci	for (i = 0, failed = 0; i < request_bytes/4 && !failed; i++) {
706962306a36Sopenharmony_ci		writel(cpu_to_le32(request[i]), &ioc->chip->Doorbell);
707062306a36Sopenharmony_ci		if ((_base_wait_for_doorbell_ack(ioc, 5)))
707162306a36Sopenharmony_ci			failed = 1;
707262306a36Sopenharmony_ci	}
707362306a36Sopenharmony_ci
707462306a36Sopenharmony_ci	if (failed) {
707562306a36Sopenharmony_ci		ioc_err(ioc, "doorbell handshake sending request failed (line=%d)\n",
707662306a36Sopenharmony_ci			__LINE__);
707762306a36Sopenharmony_ci		return -EFAULT;
707862306a36Sopenharmony_ci	}
707962306a36Sopenharmony_ci
708062306a36Sopenharmony_ci	/* now wait for the reply */
708162306a36Sopenharmony_ci	if ((_base_wait_for_doorbell_int(ioc, timeout))) {
708262306a36Sopenharmony_ci		ioc_err(ioc, "doorbell handshake int failed (line=%d)\n",
708362306a36Sopenharmony_ci			__LINE__);
708462306a36Sopenharmony_ci		return -EFAULT;
708562306a36Sopenharmony_ci	}
708662306a36Sopenharmony_ci
708762306a36Sopenharmony_ci	/* read the first two 16-bits, it gives the total length of the reply */
708862306a36Sopenharmony_ci	reply[0] = le16_to_cpu(ioc->base_readl_ext_retry(&ioc->chip->Doorbell)
708962306a36Sopenharmony_ci	    & MPI2_DOORBELL_DATA_MASK);
709062306a36Sopenharmony_ci	writel(0, &ioc->chip->HostInterruptStatus);
709162306a36Sopenharmony_ci	if ((_base_wait_for_doorbell_int(ioc, 5))) {
709262306a36Sopenharmony_ci		ioc_err(ioc, "doorbell handshake int failed (line=%d)\n",
709362306a36Sopenharmony_ci			__LINE__);
709462306a36Sopenharmony_ci		return -EFAULT;
709562306a36Sopenharmony_ci	}
709662306a36Sopenharmony_ci	reply[1] = le16_to_cpu(ioc->base_readl_ext_retry(&ioc->chip->Doorbell)
709762306a36Sopenharmony_ci	    & MPI2_DOORBELL_DATA_MASK);
709862306a36Sopenharmony_ci	writel(0, &ioc->chip->HostInterruptStatus);
709962306a36Sopenharmony_ci
710062306a36Sopenharmony_ci	for (i = 2; i < default_reply->MsgLength * 2; i++)  {
710162306a36Sopenharmony_ci		if ((_base_wait_for_doorbell_int(ioc, 5))) {
710262306a36Sopenharmony_ci			ioc_err(ioc, "doorbell handshake int failed (line=%d)\n",
710362306a36Sopenharmony_ci				__LINE__);
710462306a36Sopenharmony_ci			return -EFAULT;
710562306a36Sopenharmony_ci		}
710662306a36Sopenharmony_ci		if (i >=  reply_bytes/2) /* overflow case */
710762306a36Sopenharmony_ci			ioc->base_readl_ext_retry(&ioc->chip->Doorbell);
710862306a36Sopenharmony_ci		else
710962306a36Sopenharmony_ci			reply[i] = le16_to_cpu(
711062306a36Sopenharmony_ci			    ioc->base_readl_ext_retry(&ioc->chip->Doorbell)
711162306a36Sopenharmony_ci			    & MPI2_DOORBELL_DATA_MASK);
711262306a36Sopenharmony_ci		writel(0, &ioc->chip->HostInterruptStatus);
711362306a36Sopenharmony_ci	}
711462306a36Sopenharmony_ci
711562306a36Sopenharmony_ci	_base_wait_for_doorbell_int(ioc, 5);
711662306a36Sopenharmony_ci	if (_base_wait_for_doorbell_not_used(ioc, 5) != 0) {
711762306a36Sopenharmony_ci		dhsprintk(ioc,
711862306a36Sopenharmony_ci			  ioc_info(ioc, "doorbell is in use (line=%d)\n",
711962306a36Sopenharmony_ci				   __LINE__));
712062306a36Sopenharmony_ci	}
712162306a36Sopenharmony_ci	writel(0, &ioc->chip->HostInterruptStatus);
712262306a36Sopenharmony_ci
712362306a36Sopenharmony_ci	if (ioc->logging_level & MPT_DEBUG_INIT) {
712462306a36Sopenharmony_ci		mfp = (__le32 *)reply;
712562306a36Sopenharmony_ci		pr_info("\toffset:data\n");
712662306a36Sopenharmony_ci		for (i = 0; i < reply_bytes/4; i++)
712762306a36Sopenharmony_ci			ioc_info(ioc, "\t[0x%02x]:%08x\n", i*4,
712862306a36Sopenharmony_ci			    le32_to_cpu(mfp[i]));
712962306a36Sopenharmony_ci	}
713062306a36Sopenharmony_ci	return 0;
713162306a36Sopenharmony_ci}
713262306a36Sopenharmony_ci
713362306a36Sopenharmony_ci/**
713462306a36Sopenharmony_ci * mpt3sas_base_sas_iounit_control - send sas iounit control to FW
713562306a36Sopenharmony_ci * @ioc: per adapter object
713662306a36Sopenharmony_ci * @mpi_reply: the reply payload from FW
713762306a36Sopenharmony_ci * @mpi_request: the request payload sent to FW
713862306a36Sopenharmony_ci *
713962306a36Sopenharmony_ci * The SAS IO Unit Control Request message allows the host to perform low-level
714062306a36Sopenharmony_ci * operations, such as resets on the PHYs of the IO Unit, also allows the host
714162306a36Sopenharmony_ci * to obtain the IOC assigned device handles for a device if it has other
714262306a36Sopenharmony_ci * identifying information about the device, in addition allows the host to
714362306a36Sopenharmony_ci * remove IOC resources associated with the device.
714462306a36Sopenharmony_ci *
714562306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
714662306a36Sopenharmony_ci */
714762306a36Sopenharmony_ciint
714862306a36Sopenharmony_cimpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc,
714962306a36Sopenharmony_ci	Mpi2SasIoUnitControlReply_t *mpi_reply,
715062306a36Sopenharmony_ci	Mpi2SasIoUnitControlRequest_t *mpi_request)
715162306a36Sopenharmony_ci{
715262306a36Sopenharmony_ci	u16 smid;
715362306a36Sopenharmony_ci	u8 issue_reset = 0;
715462306a36Sopenharmony_ci	int rc;
715562306a36Sopenharmony_ci	void *request;
715662306a36Sopenharmony_ci
715762306a36Sopenharmony_ci	dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
715862306a36Sopenharmony_ci
715962306a36Sopenharmony_ci	mutex_lock(&ioc->base_cmds.mutex);
716062306a36Sopenharmony_ci
716162306a36Sopenharmony_ci	if (ioc->base_cmds.status != MPT3_CMD_NOT_USED) {
716262306a36Sopenharmony_ci		ioc_err(ioc, "%s: base_cmd in use\n", __func__);
716362306a36Sopenharmony_ci		rc = -EAGAIN;
716462306a36Sopenharmony_ci		goto out;
716562306a36Sopenharmony_ci	}
716662306a36Sopenharmony_ci
716762306a36Sopenharmony_ci	rc = mpt3sas_wait_for_ioc(ioc, IOC_OPERATIONAL_WAIT_COUNT);
716862306a36Sopenharmony_ci	if (rc)
716962306a36Sopenharmony_ci		goto out;
717062306a36Sopenharmony_ci
717162306a36Sopenharmony_ci	smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx);
717262306a36Sopenharmony_ci	if (!smid) {
717362306a36Sopenharmony_ci		ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
717462306a36Sopenharmony_ci		rc = -EAGAIN;
717562306a36Sopenharmony_ci		goto out;
717662306a36Sopenharmony_ci	}
717762306a36Sopenharmony_ci
717862306a36Sopenharmony_ci	rc = 0;
717962306a36Sopenharmony_ci	ioc->base_cmds.status = MPT3_CMD_PENDING;
718062306a36Sopenharmony_ci	request = mpt3sas_base_get_msg_frame(ioc, smid);
718162306a36Sopenharmony_ci	ioc->base_cmds.smid = smid;
718262306a36Sopenharmony_ci	memcpy(request, mpi_request, sizeof(Mpi2SasIoUnitControlRequest_t));
718362306a36Sopenharmony_ci	if (mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET ||
718462306a36Sopenharmony_ci	    mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET)
718562306a36Sopenharmony_ci		ioc->ioc_link_reset_in_progress = 1;
718662306a36Sopenharmony_ci	init_completion(&ioc->base_cmds.done);
718762306a36Sopenharmony_ci	ioc->put_smid_default(ioc, smid);
718862306a36Sopenharmony_ci	wait_for_completion_timeout(&ioc->base_cmds.done,
718962306a36Sopenharmony_ci	    msecs_to_jiffies(10000));
719062306a36Sopenharmony_ci	if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET ||
719162306a36Sopenharmony_ci	    mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET) &&
719262306a36Sopenharmony_ci	    ioc->ioc_link_reset_in_progress)
719362306a36Sopenharmony_ci		ioc->ioc_link_reset_in_progress = 0;
719462306a36Sopenharmony_ci	if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
719562306a36Sopenharmony_ci		mpt3sas_check_cmd_timeout(ioc, ioc->base_cmds.status,
719662306a36Sopenharmony_ci		    mpi_request, sizeof(Mpi2SasIoUnitControlRequest_t)/4,
719762306a36Sopenharmony_ci		    issue_reset);
719862306a36Sopenharmony_ci		goto issue_host_reset;
719962306a36Sopenharmony_ci	}
720062306a36Sopenharmony_ci	if (ioc->base_cmds.status & MPT3_CMD_REPLY_VALID)
720162306a36Sopenharmony_ci		memcpy(mpi_reply, ioc->base_cmds.reply,
720262306a36Sopenharmony_ci		    sizeof(Mpi2SasIoUnitControlReply_t));
720362306a36Sopenharmony_ci	else
720462306a36Sopenharmony_ci		memset(mpi_reply, 0, sizeof(Mpi2SasIoUnitControlReply_t));
720562306a36Sopenharmony_ci	ioc->base_cmds.status = MPT3_CMD_NOT_USED;
720662306a36Sopenharmony_ci	goto out;
720762306a36Sopenharmony_ci
720862306a36Sopenharmony_ci issue_host_reset:
720962306a36Sopenharmony_ci	if (issue_reset)
721062306a36Sopenharmony_ci		mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
721162306a36Sopenharmony_ci	ioc->base_cmds.status = MPT3_CMD_NOT_USED;
721262306a36Sopenharmony_ci	rc = -EFAULT;
721362306a36Sopenharmony_ci out:
721462306a36Sopenharmony_ci	mutex_unlock(&ioc->base_cmds.mutex);
721562306a36Sopenharmony_ci	return rc;
721662306a36Sopenharmony_ci}
721762306a36Sopenharmony_ci
721862306a36Sopenharmony_ci/**
721962306a36Sopenharmony_ci * mpt3sas_base_scsi_enclosure_processor - sending request to sep device
722062306a36Sopenharmony_ci * @ioc: per adapter object
722162306a36Sopenharmony_ci * @mpi_reply: the reply payload from FW
722262306a36Sopenharmony_ci * @mpi_request: the request payload sent to FW
722362306a36Sopenharmony_ci *
722462306a36Sopenharmony_ci * The SCSI Enclosure Processor request message causes the IOC to
722562306a36Sopenharmony_ci * communicate with SES devices to control LED status signals.
722662306a36Sopenharmony_ci *
722762306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
722862306a36Sopenharmony_ci */
722962306a36Sopenharmony_ciint
723062306a36Sopenharmony_cimpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc,
723162306a36Sopenharmony_ci	Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request)
723262306a36Sopenharmony_ci{
723362306a36Sopenharmony_ci	u16 smid;
723462306a36Sopenharmony_ci	u8 issue_reset = 0;
723562306a36Sopenharmony_ci	int rc;
723662306a36Sopenharmony_ci	void *request;
723762306a36Sopenharmony_ci
723862306a36Sopenharmony_ci	dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
723962306a36Sopenharmony_ci
724062306a36Sopenharmony_ci	mutex_lock(&ioc->base_cmds.mutex);
724162306a36Sopenharmony_ci
724262306a36Sopenharmony_ci	if (ioc->base_cmds.status != MPT3_CMD_NOT_USED) {
724362306a36Sopenharmony_ci		ioc_err(ioc, "%s: base_cmd in use\n", __func__);
724462306a36Sopenharmony_ci		rc = -EAGAIN;
724562306a36Sopenharmony_ci		goto out;
724662306a36Sopenharmony_ci	}
724762306a36Sopenharmony_ci
724862306a36Sopenharmony_ci	rc = mpt3sas_wait_for_ioc(ioc, IOC_OPERATIONAL_WAIT_COUNT);
724962306a36Sopenharmony_ci	if (rc)
725062306a36Sopenharmony_ci		goto out;
725162306a36Sopenharmony_ci
725262306a36Sopenharmony_ci	smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx);
725362306a36Sopenharmony_ci	if (!smid) {
725462306a36Sopenharmony_ci		ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
725562306a36Sopenharmony_ci		rc = -EAGAIN;
725662306a36Sopenharmony_ci		goto out;
725762306a36Sopenharmony_ci	}
725862306a36Sopenharmony_ci
725962306a36Sopenharmony_ci	rc = 0;
726062306a36Sopenharmony_ci	ioc->base_cmds.status = MPT3_CMD_PENDING;
726162306a36Sopenharmony_ci	request = mpt3sas_base_get_msg_frame(ioc, smid);
726262306a36Sopenharmony_ci	ioc->base_cmds.smid = smid;
726362306a36Sopenharmony_ci	memset(request, 0, ioc->request_sz);
726462306a36Sopenharmony_ci	memcpy(request, mpi_request, sizeof(Mpi2SepReply_t));
726562306a36Sopenharmony_ci	init_completion(&ioc->base_cmds.done);
726662306a36Sopenharmony_ci	ioc->put_smid_default(ioc, smid);
726762306a36Sopenharmony_ci	wait_for_completion_timeout(&ioc->base_cmds.done,
726862306a36Sopenharmony_ci	    msecs_to_jiffies(10000));
726962306a36Sopenharmony_ci	if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
727062306a36Sopenharmony_ci		mpt3sas_check_cmd_timeout(ioc,
727162306a36Sopenharmony_ci		    ioc->base_cmds.status, mpi_request,
727262306a36Sopenharmony_ci		    sizeof(Mpi2SepRequest_t)/4, issue_reset);
727362306a36Sopenharmony_ci		goto issue_host_reset;
727462306a36Sopenharmony_ci	}
727562306a36Sopenharmony_ci	if (ioc->base_cmds.status & MPT3_CMD_REPLY_VALID)
727662306a36Sopenharmony_ci		memcpy(mpi_reply, ioc->base_cmds.reply,
727762306a36Sopenharmony_ci		    sizeof(Mpi2SepReply_t));
727862306a36Sopenharmony_ci	else
727962306a36Sopenharmony_ci		memset(mpi_reply, 0, sizeof(Mpi2SepReply_t));
728062306a36Sopenharmony_ci	ioc->base_cmds.status = MPT3_CMD_NOT_USED;
728162306a36Sopenharmony_ci	goto out;
728262306a36Sopenharmony_ci
728362306a36Sopenharmony_ci issue_host_reset:
728462306a36Sopenharmony_ci	if (issue_reset)
728562306a36Sopenharmony_ci		mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
728662306a36Sopenharmony_ci	ioc->base_cmds.status = MPT3_CMD_NOT_USED;
728762306a36Sopenharmony_ci	rc = -EFAULT;
728862306a36Sopenharmony_ci out:
728962306a36Sopenharmony_ci	mutex_unlock(&ioc->base_cmds.mutex);
729062306a36Sopenharmony_ci	return rc;
729162306a36Sopenharmony_ci}
729262306a36Sopenharmony_ci
729362306a36Sopenharmony_ci/**
729462306a36Sopenharmony_ci * _base_get_port_facts - obtain port facts reply and save in ioc
729562306a36Sopenharmony_ci * @ioc: per adapter object
729662306a36Sopenharmony_ci * @port: ?
729762306a36Sopenharmony_ci *
729862306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
729962306a36Sopenharmony_ci */
730062306a36Sopenharmony_cistatic int
730162306a36Sopenharmony_ci_base_get_port_facts(struct MPT3SAS_ADAPTER *ioc, int port)
730262306a36Sopenharmony_ci{
730362306a36Sopenharmony_ci	Mpi2PortFactsRequest_t mpi_request;
730462306a36Sopenharmony_ci	Mpi2PortFactsReply_t mpi_reply;
730562306a36Sopenharmony_ci	struct mpt3sas_port_facts *pfacts;
730662306a36Sopenharmony_ci	int mpi_reply_sz, mpi_request_sz, r;
730762306a36Sopenharmony_ci
730862306a36Sopenharmony_ci	dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
730962306a36Sopenharmony_ci
731062306a36Sopenharmony_ci	mpi_reply_sz = sizeof(Mpi2PortFactsReply_t);
731162306a36Sopenharmony_ci	mpi_request_sz = sizeof(Mpi2PortFactsRequest_t);
731262306a36Sopenharmony_ci	memset(&mpi_request, 0, mpi_request_sz);
731362306a36Sopenharmony_ci	mpi_request.Function = MPI2_FUNCTION_PORT_FACTS;
731462306a36Sopenharmony_ci	mpi_request.PortNumber = port;
731562306a36Sopenharmony_ci	r = _base_handshake_req_reply_wait(ioc, mpi_request_sz,
731662306a36Sopenharmony_ci	    (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5);
731762306a36Sopenharmony_ci
731862306a36Sopenharmony_ci	if (r != 0) {
731962306a36Sopenharmony_ci		ioc_err(ioc, "%s: handshake failed (r=%d)\n", __func__, r);
732062306a36Sopenharmony_ci		return r;
732162306a36Sopenharmony_ci	}
732262306a36Sopenharmony_ci
732362306a36Sopenharmony_ci	pfacts = &ioc->pfacts[port];
732462306a36Sopenharmony_ci	memset(pfacts, 0, sizeof(struct mpt3sas_port_facts));
732562306a36Sopenharmony_ci	pfacts->PortNumber = mpi_reply.PortNumber;
732662306a36Sopenharmony_ci	pfacts->VP_ID = mpi_reply.VP_ID;
732762306a36Sopenharmony_ci	pfacts->VF_ID = mpi_reply.VF_ID;
732862306a36Sopenharmony_ci	pfacts->MaxPostedCmdBuffers =
732962306a36Sopenharmony_ci	    le16_to_cpu(mpi_reply.MaxPostedCmdBuffers);
733062306a36Sopenharmony_ci
733162306a36Sopenharmony_ci	return 0;
733262306a36Sopenharmony_ci}
733362306a36Sopenharmony_ci
733462306a36Sopenharmony_ci/**
733562306a36Sopenharmony_ci * _base_wait_for_iocstate - Wait until the card is in READY or OPERATIONAL
733662306a36Sopenharmony_ci * @ioc: per adapter object
733762306a36Sopenharmony_ci * @timeout:
733862306a36Sopenharmony_ci *
733962306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
734062306a36Sopenharmony_ci */
734162306a36Sopenharmony_cistatic int
734262306a36Sopenharmony_ci_base_wait_for_iocstate(struct MPT3SAS_ADAPTER *ioc, int timeout)
734362306a36Sopenharmony_ci{
734462306a36Sopenharmony_ci	u32 ioc_state;
734562306a36Sopenharmony_ci	int rc;
734662306a36Sopenharmony_ci
734762306a36Sopenharmony_ci	dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
734862306a36Sopenharmony_ci
734962306a36Sopenharmony_ci	if (ioc->pci_error_recovery) {
735062306a36Sopenharmony_ci		dfailprintk(ioc,
735162306a36Sopenharmony_ci			    ioc_info(ioc, "%s: host in pci error recovery\n",
735262306a36Sopenharmony_ci				     __func__));
735362306a36Sopenharmony_ci		return -EFAULT;
735462306a36Sopenharmony_ci	}
735562306a36Sopenharmony_ci
735662306a36Sopenharmony_ci	ioc_state = mpt3sas_base_get_iocstate(ioc, 0);
735762306a36Sopenharmony_ci	dhsprintk(ioc,
735862306a36Sopenharmony_ci		  ioc_info(ioc, "%s: ioc_state(0x%08x)\n",
735962306a36Sopenharmony_ci			   __func__, ioc_state));
736062306a36Sopenharmony_ci
736162306a36Sopenharmony_ci	if (((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY) ||
736262306a36Sopenharmony_ci	    (ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL)
736362306a36Sopenharmony_ci		return 0;
736462306a36Sopenharmony_ci
736562306a36Sopenharmony_ci	if (ioc_state & MPI2_DOORBELL_USED) {
736662306a36Sopenharmony_ci		dhsprintk(ioc, ioc_info(ioc, "unexpected doorbell active!\n"));
736762306a36Sopenharmony_ci		goto issue_diag_reset;
736862306a36Sopenharmony_ci	}
736962306a36Sopenharmony_ci
737062306a36Sopenharmony_ci	if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
737162306a36Sopenharmony_ci		mpt3sas_print_fault_code(ioc, ioc_state &
737262306a36Sopenharmony_ci		    MPI2_DOORBELL_DATA_MASK);
737362306a36Sopenharmony_ci		goto issue_diag_reset;
737462306a36Sopenharmony_ci	} else if ((ioc_state & MPI2_IOC_STATE_MASK) ==
737562306a36Sopenharmony_ci	    MPI2_IOC_STATE_COREDUMP) {
737662306a36Sopenharmony_ci		ioc_info(ioc,
737762306a36Sopenharmony_ci		    "%s: Skipping the diag reset here. (ioc_state=0x%x)\n",
737862306a36Sopenharmony_ci		    __func__, ioc_state);
737962306a36Sopenharmony_ci		return -EFAULT;
738062306a36Sopenharmony_ci	}
738162306a36Sopenharmony_ci
738262306a36Sopenharmony_ci	ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, timeout);
738362306a36Sopenharmony_ci	if (ioc_state) {
738462306a36Sopenharmony_ci		dfailprintk(ioc,
738562306a36Sopenharmony_ci			    ioc_info(ioc, "%s: failed going to ready state (ioc_state=0x%x)\n",
738662306a36Sopenharmony_ci				     __func__, ioc_state));
738762306a36Sopenharmony_ci		return -EFAULT;
738862306a36Sopenharmony_ci	}
738962306a36Sopenharmony_ci
739062306a36Sopenharmony_ci	return 0;
739162306a36Sopenharmony_ci
739262306a36Sopenharmony_ciissue_diag_reset:
739362306a36Sopenharmony_ci	rc = _base_diag_reset(ioc);
739462306a36Sopenharmony_ci	return rc;
739562306a36Sopenharmony_ci}
739662306a36Sopenharmony_ci
739762306a36Sopenharmony_ci/**
739862306a36Sopenharmony_ci * _base_get_ioc_facts - obtain ioc facts reply and save in ioc
739962306a36Sopenharmony_ci * @ioc: per adapter object
740062306a36Sopenharmony_ci *
740162306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
740262306a36Sopenharmony_ci */
740362306a36Sopenharmony_cistatic int
740462306a36Sopenharmony_ci_base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc)
740562306a36Sopenharmony_ci{
740662306a36Sopenharmony_ci	Mpi2IOCFactsRequest_t mpi_request;
740762306a36Sopenharmony_ci	Mpi2IOCFactsReply_t mpi_reply;
740862306a36Sopenharmony_ci	struct mpt3sas_facts *facts;
740962306a36Sopenharmony_ci	int mpi_reply_sz, mpi_request_sz, r;
741062306a36Sopenharmony_ci
741162306a36Sopenharmony_ci	dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
741262306a36Sopenharmony_ci
741362306a36Sopenharmony_ci	r = _base_wait_for_iocstate(ioc, 10);
741462306a36Sopenharmony_ci	if (r) {
741562306a36Sopenharmony_ci		dfailprintk(ioc,
741662306a36Sopenharmony_ci			    ioc_info(ioc, "%s: failed getting to correct state\n",
741762306a36Sopenharmony_ci				     __func__));
741862306a36Sopenharmony_ci		return r;
741962306a36Sopenharmony_ci	}
742062306a36Sopenharmony_ci	mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t);
742162306a36Sopenharmony_ci	mpi_request_sz = sizeof(Mpi2IOCFactsRequest_t);
742262306a36Sopenharmony_ci	memset(&mpi_request, 0, mpi_request_sz);
742362306a36Sopenharmony_ci	mpi_request.Function = MPI2_FUNCTION_IOC_FACTS;
742462306a36Sopenharmony_ci	r = _base_handshake_req_reply_wait(ioc, mpi_request_sz,
742562306a36Sopenharmony_ci	    (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5);
742662306a36Sopenharmony_ci
742762306a36Sopenharmony_ci	if (r != 0) {
742862306a36Sopenharmony_ci		ioc_err(ioc, "%s: handshake failed (r=%d)\n", __func__, r);
742962306a36Sopenharmony_ci		return r;
743062306a36Sopenharmony_ci	}
743162306a36Sopenharmony_ci
743262306a36Sopenharmony_ci	facts = &ioc->facts;
743362306a36Sopenharmony_ci	memset(facts, 0, sizeof(struct mpt3sas_facts));
743462306a36Sopenharmony_ci	facts->MsgVersion = le16_to_cpu(mpi_reply.MsgVersion);
743562306a36Sopenharmony_ci	facts->HeaderVersion = le16_to_cpu(mpi_reply.HeaderVersion);
743662306a36Sopenharmony_ci	facts->VP_ID = mpi_reply.VP_ID;
743762306a36Sopenharmony_ci	facts->VF_ID = mpi_reply.VF_ID;
743862306a36Sopenharmony_ci	facts->IOCExceptions = le16_to_cpu(mpi_reply.IOCExceptions);
743962306a36Sopenharmony_ci	facts->MaxChainDepth = mpi_reply.MaxChainDepth;
744062306a36Sopenharmony_ci	facts->WhoInit = mpi_reply.WhoInit;
744162306a36Sopenharmony_ci	facts->NumberOfPorts = mpi_reply.NumberOfPorts;
744262306a36Sopenharmony_ci	facts->MaxMSIxVectors = mpi_reply.MaxMSIxVectors;
744362306a36Sopenharmony_ci	if (ioc->msix_enable && (facts->MaxMSIxVectors <=
744462306a36Sopenharmony_ci	    MAX_COMBINED_MSIX_VECTORS(ioc->is_gen35_ioc)))
744562306a36Sopenharmony_ci		ioc->combined_reply_queue = 0;
744662306a36Sopenharmony_ci	facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit);
744762306a36Sopenharmony_ci	facts->MaxReplyDescriptorPostQueueDepth =
744862306a36Sopenharmony_ci	    le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth);
744962306a36Sopenharmony_ci	facts->ProductID = le16_to_cpu(mpi_reply.ProductID);
745062306a36Sopenharmony_ci	facts->IOCCapabilities = le32_to_cpu(mpi_reply.IOCCapabilities);
745162306a36Sopenharmony_ci	if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID))
745262306a36Sopenharmony_ci		ioc->ir_firmware = 1;
745362306a36Sopenharmony_ci	if ((facts->IOCCapabilities &
745462306a36Sopenharmony_ci	      MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE) && (!reset_devices))
745562306a36Sopenharmony_ci		ioc->rdpq_array_capable = 1;
745662306a36Sopenharmony_ci	if ((facts->IOCCapabilities & MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ)
745762306a36Sopenharmony_ci	    && ioc->is_aero_ioc)
745862306a36Sopenharmony_ci		ioc->atomic_desc_capable = 1;
745962306a36Sopenharmony_ci	facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
746062306a36Sopenharmony_ci	facts->IOCRequestFrameSize =
746162306a36Sopenharmony_ci	    le16_to_cpu(mpi_reply.IOCRequestFrameSize);
746262306a36Sopenharmony_ci	if (ioc->hba_mpi_version_belonged != MPI2_VERSION) {
746362306a36Sopenharmony_ci		facts->IOCMaxChainSegmentSize =
746462306a36Sopenharmony_ci			le16_to_cpu(mpi_reply.IOCMaxChainSegmentSize);
746562306a36Sopenharmony_ci	}
746662306a36Sopenharmony_ci	facts->MaxInitiators = le16_to_cpu(mpi_reply.MaxInitiators);
746762306a36Sopenharmony_ci	facts->MaxTargets = le16_to_cpu(mpi_reply.MaxTargets);
746862306a36Sopenharmony_ci	ioc->shost->max_id = -1;
746962306a36Sopenharmony_ci	facts->MaxSasExpanders = le16_to_cpu(mpi_reply.MaxSasExpanders);
747062306a36Sopenharmony_ci	facts->MaxEnclosures = le16_to_cpu(mpi_reply.MaxEnclosures);
747162306a36Sopenharmony_ci	facts->ProtocolFlags = le16_to_cpu(mpi_reply.ProtocolFlags);
747262306a36Sopenharmony_ci	facts->HighPriorityCredit =
747362306a36Sopenharmony_ci	    le16_to_cpu(mpi_reply.HighPriorityCredit);
747462306a36Sopenharmony_ci	facts->ReplyFrameSize = mpi_reply.ReplyFrameSize;
747562306a36Sopenharmony_ci	facts->MaxDevHandle = le16_to_cpu(mpi_reply.MaxDevHandle);
747662306a36Sopenharmony_ci	facts->CurrentHostPageSize = mpi_reply.CurrentHostPageSize;
747762306a36Sopenharmony_ci
747862306a36Sopenharmony_ci	/*
747962306a36Sopenharmony_ci	 * Get the Page Size from IOC Facts. If it's 0, default to 4k.
748062306a36Sopenharmony_ci	 */
748162306a36Sopenharmony_ci	ioc->page_size = 1 << facts->CurrentHostPageSize;
748262306a36Sopenharmony_ci	if (ioc->page_size == 1) {
748362306a36Sopenharmony_ci		ioc_info(ioc, "CurrentHostPageSize is 0: Setting default host page size to 4k\n");
748462306a36Sopenharmony_ci		ioc->page_size = 1 << MPT3SAS_HOST_PAGE_SIZE_4K;
748562306a36Sopenharmony_ci	}
748662306a36Sopenharmony_ci	dinitprintk(ioc,
748762306a36Sopenharmony_ci		    ioc_info(ioc, "CurrentHostPageSize(%d)\n",
748862306a36Sopenharmony_ci			     facts->CurrentHostPageSize));
748962306a36Sopenharmony_ci
749062306a36Sopenharmony_ci	dinitprintk(ioc,
749162306a36Sopenharmony_ci		    ioc_info(ioc, "hba queue depth(%d), max chains per io(%d)\n",
749262306a36Sopenharmony_ci			     facts->RequestCredit, facts->MaxChainDepth));
749362306a36Sopenharmony_ci	dinitprintk(ioc,
749462306a36Sopenharmony_ci		    ioc_info(ioc, "request frame size(%d), reply frame size(%d)\n",
749562306a36Sopenharmony_ci			     facts->IOCRequestFrameSize * 4,
749662306a36Sopenharmony_ci			     facts->ReplyFrameSize * 4));
749762306a36Sopenharmony_ci	return 0;
749862306a36Sopenharmony_ci}
749962306a36Sopenharmony_ci
750062306a36Sopenharmony_ci/**
750162306a36Sopenharmony_ci * _base_send_ioc_init - send ioc_init to firmware
750262306a36Sopenharmony_ci * @ioc: per adapter object
750362306a36Sopenharmony_ci *
750462306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
750562306a36Sopenharmony_ci */
750662306a36Sopenharmony_cistatic int
750762306a36Sopenharmony_ci_base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc)
750862306a36Sopenharmony_ci{
750962306a36Sopenharmony_ci	Mpi2IOCInitRequest_t mpi_request;
751062306a36Sopenharmony_ci	Mpi2IOCInitReply_t mpi_reply;
751162306a36Sopenharmony_ci	int i, r = 0;
751262306a36Sopenharmony_ci	ktime_t current_time;
751362306a36Sopenharmony_ci	u16 ioc_status;
751462306a36Sopenharmony_ci	u32 reply_post_free_array_sz = 0;
751562306a36Sopenharmony_ci
751662306a36Sopenharmony_ci	dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
751762306a36Sopenharmony_ci
751862306a36Sopenharmony_ci	memset(&mpi_request, 0, sizeof(Mpi2IOCInitRequest_t));
751962306a36Sopenharmony_ci	mpi_request.Function = MPI2_FUNCTION_IOC_INIT;
752062306a36Sopenharmony_ci	mpi_request.WhoInit = MPI2_WHOINIT_HOST_DRIVER;
752162306a36Sopenharmony_ci	mpi_request.VF_ID = 0; /* TODO */
752262306a36Sopenharmony_ci	mpi_request.VP_ID = 0;
752362306a36Sopenharmony_ci	mpi_request.MsgVersion = cpu_to_le16(ioc->hba_mpi_version_belonged);
752462306a36Sopenharmony_ci	mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION);
752562306a36Sopenharmony_ci	mpi_request.HostPageSize = MPT3SAS_HOST_PAGE_SIZE_4K;
752662306a36Sopenharmony_ci
752762306a36Sopenharmony_ci	if (_base_is_controller_msix_enabled(ioc))
752862306a36Sopenharmony_ci		mpi_request.HostMSIxVectors = ioc->reply_queue_count;
752962306a36Sopenharmony_ci	mpi_request.SystemRequestFrameSize = cpu_to_le16(ioc->request_sz/4);
753062306a36Sopenharmony_ci	mpi_request.ReplyDescriptorPostQueueDepth =
753162306a36Sopenharmony_ci	    cpu_to_le16(ioc->reply_post_queue_depth);
753262306a36Sopenharmony_ci	mpi_request.ReplyFreeQueueDepth =
753362306a36Sopenharmony_ci	    cpu_to_le16(ioc->reply_free_queue_depth);
753462306a36Sopenharmony_ci
753562306a36Sopenharmony_ci	mpi_request.SenseBufferAddressHigh =
753662306a36Sopenharmony_ci	    cpu_to_le32((u64)ioc->sense_dma >> 32);
753762306a36Sopenharmony_ci	mpi_request.SystemReplyAddressHigh =
753862306a36Sopenharmony_ci	    cpu_to_le32((u64)ioc->reply_dma >> 32);
753962306a36Sopenharmony_ci	mpi_request.SystemRequestFrameBaseAddress =
754062306a36Sopenharmony_ci	    cpu_to_le64((u64)ioc->request_dma);
754162306a36Sopenharmony_ci	mpi_request.ReplyFreeQueueAddress =
754262306a36Sopenharmony_ci	    cpu_to_le64((u64)ioc->reply_free_dma);
754362306a36Sopenharmony_ci
754462306a36Sopenharmony_ci	if (ioc->rdpq_array_enable) {
754562306a36Sopenharmony_ci		reply_post_free_array_sz = ioc->reply_queue_count *
754662306a36Sopenharmony_ci		    sizeof(Mpi2IOCInitRDPQArrayEntry);
754762306a36Sopenharmony_ci		memset(ioc->reply_post_free_array, 0, reply_post_free_array_sz);
754862306a36Sopenharmony_ci		for (i = 0; i < ioc->reply_queue_count; i++)
754962306a36Sopenharmony_ci			ioc->reply_post_free_array[i].RDPQBaseAddress =
755062306a36Sopenharmony_ci			    cpu_to_le64(
755162306a36Sopenharmony_ci				(u64)ioc->reply_post[i].reply_post_free_dma);
755262306a36Sopenharmony_ci		mpi_request.MsgFlags = MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE;
755362306a36Sopenharmony_ci		mpi_request.ReplyDescriptorPostQueueAddress =
755462306a36Sopenharmony_ci		    cpu_to_le64((u64)ioc->reply_post_free_array_dma);
755562306a36Sopenharmony_ci	} else {
755662306a36Sopenharmony_ci		mpi_request.ReplyDescriptorPostQueueAddress =
755762306a36Sopenharmony_ci		    cpu_to_le64((u64)ioc->reply_post[0].reply_post_free_dma);
755862306a36Sopenharmony_ci	}
755962306a36Sopenharmony_ci
756062306a36Sopenharmony_ci	/*
756162306a36Sopenharmony_ci	 * Set the flag to enable CoreDump state feature in IOC firmware.
756262306a36Sopenharmony_ci	 */
756362306a36Sopenharmony_ci	mpi_request.ConfigurationFlags |=
756462306a36Sopenharmony_ci	    cpu_to_le16(MPI26_IOCINIT_CFGFLAGS_COREDUMP_ENABLE);
756562306a36Sopenharmony_ci
756662306a36Sopenharmony_ci	/* This time stamp specifies number of milliseconds
756762306a36Sopenharmony_ci	 * since epoch ~ midnight January 1, 1970.
756862306a36Sopenharmony_ci	 */
756962306a36Sopenharmony_ci	current_time = ktime_get_real();
757062306a36Sopenharmony_ci	mpi_request.TimeStamp = cpu_to_le64(ktime_to_ms(current_time));
757162306a36Sopenharmony_ci
757262306a36Sopenharmony_ci	if (ioc->logging_level & MPT_DEBUG_INIT) {
757362306a36Sopenharmony_ci		__le32 *mfp;
757462306a36Sopenharmony_ci		int i;
757562306a36Sopenharmony_ci
757662306a36Sopenharmony_ci		mfp = (__le32 *)&mpi_request;
757762306a36Sopenharmony_ci		ioc_info(ioc, "\toffset:data\n");
757862306a36Sopenharmony_ci		for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++)
757962306a36Sopenharmony_ci			ioc_info(ioc, "\t[0x%02x]:%08x\n", i*4,
758062306a36Sopenharmony_ci			    le32_to_cpu(mfp[i]));
758162306a36Sopenharmony_ci	}
758262306a36Sopenharmony_ci
758362306a36Sopenharmony_ci	r = _base_handshake_req_reply_wait(ioc,
758462306a36Sopenharmony_ci	    sizeof(Mpi2IOCInitRequest_t), (u32 *)&mpi_request,
758562306a36Sopenharmony_ci	    sizeof(Mpi2IOCInitReply_t), (u16 *)&mpi_reply, 30);
758662306a36Sopenharmony_ci
758762306a36Sopenharmony_ci	if (r != 0) {
758862306a36Sopenharmony_ci		ioc_err(ioc, "%s: handshake failed (r=%d)\n", __func__, r);
758962306a36Sopenharmony_ci		return r;
759062306a36Sopenharmony_ci	}
759162306a36Sopenharmony_ci
759262306a36Sopenharmony_ci	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
759362306a36Sopenharmony_ci	if (ioc_status != MPI2_IOCSTATUS_SUCCESS ||
759462306a36Sopenharmony_ci	    mpi_reply.IOCLogInfo) {
759562306a36Sopenharmony_ci		ioc_err(ioc, "%s: failed\n", __func__);
759662306a36Sopenharmony_ci		r = -EIO;
759762306a36Sopenharmony_ci	}
759862306a36Sopenharmony_ci
759962306a36Sopenharmony_ci	/* Reset TimeSync Counter*/
760062306a36Sopenharmony_ci	ioc->timestamp_update_count = 0;
760162306a36Sopenharmony_ci	return r;
760262306a36Sopenharmony_ci}
760362306a36Sopenharmony_ci
760462306a36Sopenharmony_ci/**
760562306a36Sopenharmony_ci * mpt3sas_port_enable_done - command completion routine for port enable
760662306a36Sopenharmony_ci * @ioc: per adapter object
760762306a36Sopenharmony_ci * @smid: system request message index
760862306a36Sopenharmony_ci * @msix_index: MSIX table index supplied by the OS
760962306a36Sopenharmony_ci * @reply: reply message frame(lower 32bit addr)
761062306a36Sopenharmony_ci *
761162306a36Sopenharmony_ci * Return: 1 meaning mf should be freed from _base_interrupt
761262306a36Sopenharmony_ci *          0 means the mf is freed from this function.
761362306a36Sopenharmony_ci */
761462306a36Sopenharmony_ciu8
761562306a36Sopenharmony_cimpt3sas_port_enable_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
761662306a36Sopenharmony_ci	u32 reply)
761762306a36Sopenharmony_ci{
761862306a36Sopenharmony_ci	MPI2DefaultReply_t *mpi_reply;
761962306a36Sopenharmony_ci	u16 ioc_status;
762062306a36Sopenharmony_ci
762162306a36Sopenharmony_ci	if (ioc->port_enable_cmds.status == MPT3_CMD_NOT_USED)
762262306a36Sopenharmony_ci		return 1;
762362306a36Sopenharmony_ci
762462306a36Sopenharmony_ci	mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
762562306a36Sopenharmony_ci	if (!mpi_reply)
762662306a36Sopenharmony_ci		return 1;
762762306a36Sopenharmony_ci
762862306a36Sopenharmony_ci	if (mpi_reply->Function != MPI2_FUNCTION_PORT_ENABLE)
762962306a36Sopenharmony_ci		return 1;
763062306a36Sopenharmony_ci
763162306a36Sopenharmony_ci	ioc->port_enable_cmds.status &= ~MPT3_CMD_PENDING;
763262306a36Sopenharmony_ci	ioc->port_enable_cmds.status |= MPT3_CMD_COMPLETE;
763362306a36Sopenharmony_ci	ioc->port_enable_cmds.status |= MPT3_CMD_REPLY_VALID;
763462306a36Sopenharmony_ci	memcpy(ioc->port_enable_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
763562306a36Sopenharmony_ci	ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
763662306a36Sopenharmony_ci	if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
763762306a36Sopenharmony_ci		ioc->port_enable_failed = 1;
763862306a36Sopenharmony_ci
763962306a36Sopenharmony_ci	if (ioc->port_enable_cmds.status & MPT3_CMD_COMPLETE_ASYNC) {
764062306a36Sopenharmony_ci		ioc->port_enable_cmds.status &= ~MPT3_CMD_COMPLETE_ASYNC;
764162306a36Sopenharmony_ci		if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
764262306a36Sopenharmony_ci			mpt3sas_port_enable_complete(ioc);
764362306a36Sopenharmony_ci			return 1;
764462306a36Sopenharmony_ci		} else {
764562306a36Sopenharmony_ci			ioc->start_scan_failed = ioc_status;
764662306a36Sopenharmony_ci			ioc->start_scan = 0;
764762306a36Sopenharmony_ci			return 1;
764862306a36Sopenharmony_ci		}
764962306a36Sopenharmony_ci	}
765062306a36Sopenharmony_ci	complete(&ioc->port_enable_cmds.done);
765162306a36Sopenharmony_ci	return 1;
765262306a36Sopenharmony_ci}
765362306a36Sopenharmony_ci
765462306a36Sopenharmony_ci/**
765562306a36Sopenharmony_ci * _base_send_port_enable - send port_enable(discovery stuff) to firmware
765662306a36Sopenharmony_ci * @ioc: per adapter object
765762306a36Sopenharmony_ci *
765862306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
765962306a36Sopenharmony_ci */
766062306a36Sopenharmony_cistatic int
766162306a36Sopenharmony_ci_base_send_port_enable(struct MPT3SAS_ADAPTER *ioc)
766262306a36Sopenharmony_ci{
766362306a36Sopenharmony_ci	Mpi2PortEnableRequest_t *mpi_request;
766462306a36Sopenharmony_ci	Mpi2PortEnableReply_t *mpi_reply;
766562306a36Sopenharmony_ci	int r = 0;
766662306a36Sopenharmony_ci	u16 smid;
766762306a36Sopenharmony_ci	u16 ioc_status;
766862306a36Sopenharmony_ci
766962306a36Sopenharmony_ci	ioc_info(ioc, "sending port enable !!\n");
767062306a36Sopenharmony_ci
767162306a36Sopenharmony_ci	if (ioc->port_enable_cmds.status & MPT3_CMD_PENDING) {
767262306a36Sopenharmony_ci		ioc_err(ioc, "%s: internal command already in use\n", __func__);
767362306a36Sopenharmony_ci		return -EAGAIN;
767462306a36Sopenharmony_ci	}
767562306a36Sopenharmony_ci
767662306a36Sopenharmony_ci	smid = mpt3sas_base_get_smid(ioc, ioc->port_enable_cb_idx);
767762306a36Sopenharmony_ci	if (!smid) {
767862306a36Sopenharmony_ci		ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
767962306a36Sopenharmony_ci		return -EAGAIN;
768062306a36Sopenharmony_ci	}
768162306a36Sopenharmony_ci
768262306a36Sopenharmony_ci	ioc->port_enable_cmds.status = MPT3_CMD_PENDING;
768362306a36Sopenharmony_ci	mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
768462306a36Sopenharmony_ci	ioc->port_enable_cmds.smid = smid;
768562306a36Sopenharmony_ci	memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t));
768662306a36Sopenharmony_ci	mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE;
768762306a36Sopenharmony_ci
768862306a36Sopenharmony_ci	init_completion(&ioc->port_enable_cmds.done);
768962306a36Sopenharmony_ci	ioc->put_smid_default(ioc, smid);
769062306a36Sopenharmony_ci	wait_for_completion_timeout(&ioc->port_enable_cmds.done, 300*HZ);
769162306a36Sopenharmony_ci	if (!(ioc->port_enable_cmds.status & MPT3_CMD_COMPLETE)) {
769262306a36Sopenharmony_ci		ioc_err(ioc, "%s: timeout\n", __func__);
769362306a36Sopenharmony_ci		_debug_dump_mf(mpi_request,
769462306a36Sopenharmony_ci		    sizeof(Mpi2PortEnableRequest_t)/4);
769562306a36Sopenharmony_ci		if (ioc->port_enable_cmds.status & MPT3_CMD_RESET)
769662306a36Sopenharmony_ci			r = -EFAULT;
769762306a36Sopenharmony_ci		else
769862306a36Sopenharmony_ci			r = -ETIME;
769962306a36Sopenharmony_ci		goto out;
770062306a36Sopenharmony_ci	}
770162306a36Sopenharmony_ci
770262306a36Sopenharmony_ci	mpi_reply = ioc->port_enable_cmds.reply;
770362306a36Sopenharmony_ci	ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
770462306a36Sopenharmony_ci	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
770562306a36Sopenharmony_ci		ioc_err(ioc, "%s: failed with (ioc_status=0x%08x)\n",
770662306a36Sopenharmony_ci			__func__, ioc_status);
770762306a36Sopenharmony_ci		r = -EFAULT;
770862306a36Sopenharmony_ci		goto out;
770962306a36Sopenharmony_ci	}
771062306a36Sopenharmony_ci
771162306a36Sopenharmony_ci out:
771262306a36Sopenharmony_ci	ioc->port_enable_cmds.status = MPT3_CMD_NOT_USED;
771362306a36Sopenharmony_ci	ioc_info(ioc, "port enable: %s\n", r == 0 ? "SUCCESS" : "FAILED");
771462306a36Sopenharmony_ci	return r;
771562306a36Sopenharmony_ci}
771662306a36Sopenharmony_ci
771762306a36Sopenharmony_ci/**
771862306a36Sopenharmony_ci * mpt3sas_port_enable - initiate firmware discovery (don't wait for reply)
771962306a36Sopenharmony_ci * @ioc: per adapter object
772062306a36Sopenharmony_ci *
772162306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
772262306a36Sopenharmony_ci */
772362306a36Sopenharmony_ciint
772462306a36Sopenharmony_cimpt3sas_port_enable(struct MPT3SAS_ADAPTER *ioc)
772562306a36Sopenharmony_ci{
772662306a36Sopenharmony_ci	Mpi2PortEnableRequest_t *mpi_request;
772762306a36Sopenharmony_ci	u16 smid;
772862306a36Sopenharmony_ci
772962306a36Sopenharmony_ci	ioc_info(ioc, "sending port enable !!\n");
773062306a36Sopenharmony_ci
773162306a36Sopenharmony_ci	if (ioc->port_enable_cmds.status & MPT3_CMD_PENDING) {
773262306a36Sopenharmony_ci		ioc_err(ioc, "%s: internal command already in use\n", __func__);
773362306a36Sopenharmony_ci		return -EAGAIN;
773462306a36Sopenharmony_ci	}
773562306a36Sopenharmony_ci
773662306a36Sopenharmony_ci	smid = mpt3sas_base_get_smid(ioc, ioc->port_enable_cb_idx);
773762306a36Sopenharmony_ci	if (!smid) {
773862306a36Sopenharmony_ci		ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
773962306a36Sopenharmony_ci		return -EAGAIN;
774062306a36Sopenharmony_ci	}
774162306a36Sopenharmony_ci	ioc->drv_internal_flags |= MPT_DRV_INTERNAL_FIRST_PE_ISSUED;
774262306a36Sopenharmony_ci	ioc->port_enable_cmds.status = MPT3_CMD_PENDING;
774362306a36Sopenharmony_ci	ioc->port_enable_cmds.status |= MPT3_CMD_COMPLETE_ASYNC;
774462306a36Sopenharmony_ci	mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
774562306a36Sopenharmony_ci	ioc->port_enable_cmds.smid = smid;
774662306a36Sopenharmony_ci	memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t));
774762306a36Sopenharmony_ci	mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE;
774862306a36Sopenharmony_ci
774962306a36Sopenharmony_ci	ioc->put_smid_default(ioc, smid);
775062306a36Sopenharmony_ci	return 0;
775162306a36Sopenharmony_ci}
775262306a36Sopenharmony_ci
775362306a36Sopenharmony_ci/**
775462306a36Sopenharmony_ci * _base_determine_wait_on_discovery - desposition
775562306a36Sopenharmony_ci * @ioc: per adapter object
775662306a36Sopenharmony_ci *
775762306a36Sopenharmony_ci * Decide whether to wait on discovery to complete. Used to either
775862306a36Sopenharmony_ci * locate boot device, or report volumes ahead of physical devices.
775962306a36Sopenharmony_ci *
776062306a36Sopenharmony_ci * Return: 1 for wait, 0 for don't wait.
776162306a36Sopenharmony_ci */
776262306a36Sopenharmony_cistatic int
776362306a36Sopenharmony_ci_base_determine_wait_on_discovery(struct MPT3SAS_ADAPTER *ioc)
776462306a36Sopenharmony_ci{
776562306a36Sopenharmony_ci	/* We wait for discovery to complete if IR firmware is loaded.
776662306a36Sopenharmony_ci	 * The sas topology events arrive before PD events, so we need time to
776762306a36Sopenharmony_ci	 * turn on the bit in ioc->pd_handles to indicate PD
776862306a36Sopenharmony_ci	 * Also, it maybe required to report Volumes ahead of physical
776962306a36Sopenharmony_ci	 * devices when MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING is set.
777062306a36Sopenharmony_ci	 */
777162306a36Sopenharmony_ci	if (ioc->ir_firmware)
777262306a36Sopenharmony_ci		return 1;
777362306a36Sopenharmony_ci
777462306a36Sopenharmony_ci	/* if no Bios, then we don't need to wait */
777562306a36Sopenharmony_ci	if (!ioc->bios_pg3.BiosVersion)
777662306a36Sopenharmony_ci		return 0;
777762306a36Sopenharmony_ci
777862306a36Sopenharmony_ci	/* Bios is present, then we drop down here.
777962306a36Sopenharmony_ci	 *
778062306a36Sopenharmony_ci	 * If there any entries in the Bios Page 2, then we wait
778162306a36Sopenharmony_ci	 * for discovery to complete.
778262306a36Sopenharmony_ci	 */
778362306a36Sopenharmony_ci
778462306a36Sopenharmony_ci	/* Current Boot Device */
778562306a36Sopenharmony_ci	if ((ioc->bios_pg2.CurrentBootDeviceForm &
778662306a36Sopenharmony_ci	    MPI2_BIOSPAGE2_FORM_MASK) ==
778762306a36Sopenharmony_ci	    MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED &&
778862306a36Sopenharmony_ci	/* Request Boot Device */
778962306a36Sopenharmony_ci	   (ioc->bios_pg2.ReqBootDeviceForm &
779062306a36Sopenharmony_ci	    MPI2_BIOSPAGE2_FORM_MASK) ==
779162306a36Sopenharmony_ci	    MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED &&
779262306a36Sopenharmony_ci	/* Alternate Request Boot Device */
779362306a36Sopenharmony_ci	   (ioc->bios_pg2.ReqAltBootDeviceForm &
779462306a36Sopenharmony_ci	    MPI2_BIOSPAGE2_FORM_MASK) ==
779562306a36Sopenharmony_ci	    MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED)
779662306a36Sopenharmony_ci		return 0;
779762306a36Sopenharmony_ci
779862306a36Sopenharmony_ci	return 1;
779962306a36Sopenharmony_ci}
780062306a36Sopenharmony_ci
780162306a36Sopenharmony_ci/**
780262306a36Sopenharmony_ci * _base_unmask_events - turn on notification for this event
780362306a36Sopenharmony_ci * @ioc: per adapter object
780462306a36Sopenharmony_ci * @event: firmware event
780562306a36Sopenharmony_ci *
780662306a36Sopenharmony_ci * The mask is stored in ioc->event_masks.
780762306a36Sopenharmony_ci */
780862306a36Sopenharmony_cistatic void
780962306a36Sopenharmony_ci_base_unmask_events(struct MPT3SAS_ADAPTER *ioc, u16 event)
781062306a36Sopenharmony_ci{
781162306a36Sopenharmony_ci	u32 desired_event;
781262306a36Sopenharmony_ci
781362306a36Sopenharmony_ci	if (event >= 128)
781462306a36Sopenharmony_ci		return;
781562306a36Sopenharmony_ci
781662306a36Sopenharmony_ci	desired_event = (1 << (event % 32));
781762306a36Sopenharmony_ci
781862306a36Sopenharmony_ci	if (event < 32)
781962306a36Sopenharmony_ci		ioc->event_masks[0] &= ~desired_event;
782062306a36Sopenharmony_ci	else if (event < 64)
782162306a36Sopenharmony_ci		ioc->event_masks[1] &= ~desired_event;
782262306a36Sopenharmony_ci	else if (event < 96)
782362306a36Sopenharmony_ci		ioc->event_masks[2] &= ~desired_event;
782462306a36Sopenharmony_ci	else if (event < 128)
782562306a36Sopenharmony_ci		ioc->event_masks[3] &= ~desired_event;
782662306a36Sopenharmony_ci}
782762306a36Sopenharmony_ci
782862306a36Sopenharmony_ci/**
782962306a36Sopenharmony_ci * _base_event_notification - send event notification
783062306a36Sopenharmony_ci * @ioc: per adapter object
783162306a36Sopenharmony_ci *
783262306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
783362306a36Sopenharmony_ci */
783462306a36Sopenharmony_cistatic int
783562306a36Sopenharmony_ci_base_event_notification(struct MPT3SAS_ADAPTER *ioc)
783662306a36Sopenharmony_ci{
783762306a36Sopenharmony_ci	Mpi2EventNotificationRequest_t *mpi_request;
783862306a36Sopenharmony_ci	u16 smid;
783962306a36Sopenharmony_ci	int r = 0;
784062306a36Sopenharmony_ci	int i, issue_diag_reset = 0;
784162306a36Sopenharmony_ci
784262306a36Sopenharmony_ci	dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
784362306a36Sopenharmony_ci
784462306a36Sopenharmony_ci	if (ioc->base_cmds.status & MPT3_CMD_PENDING) {
784562306a36Sopenharmony_ci		ioc_err(ioc, "%s: internal command already in use\n", __func__);
784662306a36Sopenharmony_ci		return -EAGAIN;
784762306a36Sopenharmony_ci	}
784862306a36Sopenharmony_ci
784962306a36Sopenharmony_ci	smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx);
785062306a36Sopenharmony_ci	if (!smid) {
785162306a36Sopenharmony_ci		ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
785262306a36Sopenharmony_ci		return -EAGAIN;
785362306a36Sopenharmony_ci	}
785462306a36Sopenharmony_ci	ioc->base_cmds.status = MPT3_CMD_PENDING;
785562306a36Sopenharmony_ci	mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
785662306a36Sopenharmony_ci	ioc->base_cmds.smid = smid;
785762306a36Sopenharmony_ci	memset(mpi_request, 0, sizeof(Mpi2EventNotificationRequest_t));
785862306a36Sopenharmony_ci	mpi_request->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
785962306a36Sopenharmony_ci	mpi_request->VF_ID = 0; /* TODO */
786062306a36Sopenharmony_ci	mpi_request->VP_ID = 0;
786162306a36Sopenharmony_ci	for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
786262306a36Sopenharmony_ci		mpi_request->EventMasks[i] =
786362306a36Sopenharmony_ci		    cpu_to_le32(ioc->event_masks[i]);
786462306a36Sopenharmony_ci	init_completion(&ioc->base_cmds.done);
786562306a36Sopenharmony_ci	ioc->put_smid_default(ioc, smid);
786662306a36Sopenharmony_ci	wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ);
786762306a36Sopenharmony_ci	if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
786862306a36Sopenharmony_ci		ioc_err(ioc, "%s: timeout\n", __func__);
786962306a36Sopenharmony_ci		_debug_dump_mf(mpi_request,
787062306a36Sopenharmony_ci		    sizeof(Mpi2EventNotificationRequest_t)/4);
787162306a36Sopenharmony_ci		if (ioc->base_cmds.status & MPT3_CMD_RESET)
787262306a36Sopenharmony_ci			r = -EFAULT;
787362306a36Sopenharmony_ci		else
787462306a36Sopenharmony_ci			issue_diag_reset = 1;
787562306a36Sopenharmony_ci
787662306a36Sopenharmony_ci	} else
787762306a36Sopenharmony_ci		dinitprintk(ioc, ioc_info(ioc, "%s: complete\n", __func__));
787862306a36Sopenharmony_ci	ioc->base_cmds.status = MPT3_CMD_NOT_USED;
787962306a36Sopenharmony_ci
788062306a36Sopenharmony_ci	if (issue_diag_reset) {
788162306a36Sopenharmony_ci		if (ioc->drv_internal_flags & MPT_DRV_INTERNAL_FIRST_PE_ISSUED)
788262306a36Sopenharmony_ci			return -EFAULT;
788362306a36Sopenharmony_ci		if (mpt3sas_base_check_for_fault_and_issue_reset(ioc))
788462306a36Sopenharmony_ci			return -EFAULT;
788562306a36Sopenharmony_ci		r = -EAGAIN;
788662306a36Sopenharmony_ci	}
788762306a36Sopenharmony_ci	return r;
788862306a36Sopenharmony_ci}
788962306a36Sopenharmony_ci
789062306a36Sopenharmony_ci/**
789162306a36Sopenharmony_ci * mpt3sas_base_validate_event_type - validating event types
789262306a36Sopenharmony_ci * @ioc: per adapter object
789362306a36Sopenharmony_ci * @event_type: firmware event
789462306a36Sopenharmony_ci *
789562306a36Sopenharmony_ci * This will turn on firmware event notification when application
789662306a36Sopenharmony_ci * ask for that event. We don't mask events that are already enabled.
789762306a36Sopenharmony_ci */
789862306a36Sopenharmony_civoid
789962306a36Sopenharmony_cimpt3sas_base_validate_event_type(struct MPT3SAS_ADAPTER *ioc, u32 *event_type)
790062306a36Sopenharmony_ci{
790162306a36Sopenharmony_ci	int i, j;
790262306a36Sopenharmony_ci	u32 event_mask, desired_event;
790362306a36Sopenharmony_ci	u8 send_update_to_fw;
790462306a36Sopenharmony_ci
790562306a36Sopenharmony_ci	for (i = 0, send_update_to_fw = 0; i <
790662306a36Sopenharmony_ci	    MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) {
790762306a36Sopenharmony_ci		event_mask = ~event_type[i];
790862306a36Sopenharmony_ci		desired_event = 1;
790962306a36Sopenharmony_ci		for (j = 0; j < 32; j++) {
791062306a36Sopenharmony_ci			if (!(event_mask & desired_event) &&
791162306a36Sopenharmony_ci			    (ioc->event_masks[i] & desired_event)) {
791262306a36Sopenharmony_ci				ioc->event_masks[i] &= ~desired_event;
791362306a36Sopenharmony_ci				send_update_to_fw = 1;
791462306a36Sopenharmony_ci			}
791562306a36Sopenharmony_ci			desired_event = (desired_event << 1);
791662306a36Sopenharmony_ci		}
791762306a36Sopenharmony_ci	}
791862306a36Sopenharmony_ci
791962306a36Sopenharmony_ci	if (!send_update_to_fw)
792062306a36Sopenharmony_ci		return;
792162306a36Sopenharmony_ci
792262306a36Sopenharmony_ci	mutex_lock(&ioc->base_cmds.mutex);
792362306a36Sopenharmony_ci	_base_event_notification(ioc);
792462306a36Sopenharmony_ci	mutex_unlock(&ioc->base_cmds.mutex);
792562306a36Sopenharmony_ci}
792662306a36Sopenharmony_ci
792762306a36Sopenharmony_ci/**
792862306a36Sopenharmony_ci * _base_diag_reset - the "big hammer" start of day reset
792962306a36Sopenharmony_ci * @ioc: per adapter object
793062306a36Sopenharmony_ci *
793162306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
793262306a36Sopenharmony_ci */
793362306a36Sopenharmony_cistatic int
793462306a36Sopenharmony_ci_base_diag_reset(struct MPT3SAS_ADAPTER *ioc)
793562306a36Sopenharmony_ci{
793662306a36Sopenharmony_ci	u32 host_diagnostic;
793762306a36Sopenharmony_ci	u32 ioc_state;
793862306a36Sopenharmony_ci	u32 count;
793962306a36Sopenharmony_ci	u32 hcb_size;
794062306a36Sopenharmony_ci
794162306a36Sopenharmony_ci	ioc_info(ioc, "sending diag reset !!\n");
794262306a36Sopenharmony_ci
794362306a36Sopenharmony_ci	pci_cfg_access_lock(ioc->pdev);
794462306a36Sopenharmony_ci
794562306a36Sopenharmony_ci	drsprintk(ioc, ioc_info(ioc, "clear interrupts\n"));
794662306a36Sopenharmony_ci
794762306a36Sopenharmony_ci	count = 0;
794862306a36Sopenharmony_ci	do {
794962306a36Sopenharmony_ci		/* Write magic sequence to WriteSequence register
795062306a36Sopenharmony_ci		 * Loop until in diagnostic mode
795162306a36Sopenharmony_ci		 */
795262306a36Sopenharmony_ci		drsprintk(ioc, ioc_info(ioc, "write magic sequence\n"));
795362306a36Sopenharmony_ci		writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence);
795462306a36Sopenharmony_ci		writel(MPI2_WRSEQ_1ST_KEY_VALUE, &ioc->chip->WriteSequence);
795562306a36Sopenharmony_ci		writel(MPI2_WRSEQ_2ND_KEY_VALUE, &ioc->chip->WriteSequence);
795662306a36Sopenharmony_ci		writel(MPI2_WRSEQ_3RD_KEY_VALUE, &ioc->chip->WriteSequence);
795762306a36Sopenharmony_ci		writel(MPI2_WRSEQ_4TH_KEY_VALUE, &ioc->chip->WriteSequence);
795862306a36Sopenharmony_ci		writel(MPI2_WRSEQ_5TH_KEY_VALUE, &ioc->chip->WriteSequence);
795962306a36Sopenharmony_ci		writel(MPI2_WRSEQ_6TH_KEY_VALUE, &ioc->chip->WriteSequence);
796062306a36Sopenharmony_ci
796162306a36Sopenharmony_ci		/* wait 100 msec */
796262306a36Sopenharmony_ci		msleep(100);
796362306a36Sopenharmony_ci
796462306a36Sopenharmony_ci		if (count++ > 20) {
796562306a36Sopenharmony_ci			ioc_info(ioc,
796662306a36Sopenharmony_ci			    "Stop writing magic sequence after 20 retries\n");
796762306a36Sopenharmony_ci			_base_dump_reg_set(ioc);
796862306a36Sopenharmony_ci			goto out;
796962306a36Sopenharmony_ci		}
797062306a36Sopenharmony_ci
797162306a36Sopenharmony_ci		host_diagnostic = ioc->base_readl_ext_retry(&ioc->chip->HostDiagnostic);
797262306a36Sopenharmony_ci		drsprintk(ioc,
797362306a36Sopenharmony_ci			  ioc_info(ioc, "wrote magic sequence: count(%d), host_diagnostic(0x%08x)\n",
797462306a36Sopenharmony_ci				   count, host_diagnostic));
797562306a36Sopenharmony_ci
797662306a36Sopenharmony_ci	} while ((host_diagnostic & MPI2_DIAG_DIAG_WRITE_ENABLE) == 0);
797762306a36Sopenharmony_ci
797862306a36Sopenharmony_ci	hcb_size = ioc->base_readl(&ioc->chip->HCBSize);
797962306a36Sopenharmony_ci
798062306a36Sopenharmony_ci	drsprintk(ioc, ioc_info(ioc, "diag reset: issued\n"));
798162306a36Sopenharmony_ci	writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER,
798262306a36Sopenharmony_ci	     &ioc->chip->HostDiagnostic);
798362306a36Sopenharmony_ci
798462306a36Sopenharmony_ci	/*This delay allows the chip PCIe hardware time to finish reset tasks*/
798562306a36Sopenharmony_ci	msleep(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000);
798662306a36Sopenharmony_ci
798762306a36Sopenharmony_ci	/* Approximately 300 second max wait */
798862306a36Sopenharmony_ci	for (count = 0; count < (300000000 /
798962306a36Sopenharmony_ci		MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC); count++) {
799062306a36Sopenharmony_ci
799162306a36Sopenharmony_ci		host_diagnostic = ioc->base_readl_ext_retry(&ioc->chip->HostDiagnostic);
799262306a36Sopenharmony_ci
799362306a36Sopenharmony_ci		if (host_diagnostic == 0xFFFFFFFF) {
799462306a36Sopenharmony_ci			ioc_info(ioc,
799562306a36Sopenharmony_ci			    "Invalid host diagnostic register value\n");
799662306a36Sopenharmony_ci			_base_dump_reg_set(ioc);
799762306a36Sopenharmony_ci			goto out;
799862306a36Sopenharmony_ci		}
799962306a36Sopenharmony_ci		if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER))
800062306a36Sopenharmony_ci			break;
800162306a36Sopenharmony_ci
800262306a36Sopenharmony_ci		msleep(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC / 1000);
800362306a36Sopenharmony_ci	}
800462306a36Sopenharmony_ci
800562306a36Sopenharmony_ci	if (host_diagnostic & MPI2_DIAG_HCB_MODE) {
800662306a36Sopenharmony_ci
800762306a36Sopenharmony_ci		drsprintk(ioc,
800862306a36Sopenharmony_ci			  ioc_info(ioc, "restart the adapter assuming the HCB Address points to good F/W\n"));
800962306a36Sopenharmony_ci		host_diagnostic &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK;
801062306a36Sopenharmony_ci		host_diagnostic |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW;
801162306a36Sopenharmony_ci		writel(host_diagnostic, &ioc->chip->HostDiagnostic);
801262306a36Sopenharmony_ci
801362306a36Sopenharmony_ci		drsprintk(ioc, ioc_info(ioc, "re-enable the HCDW\n"));
801462306a36Sopenharmony_ci		writel(hcb_size | MPI2_HCB_SIZE_HCB_ENABLE,
801562306a36Sopenharmony_ci		    &ioc->chip->HCBSize);
801662306a36Sopenharmony_ci	}
801762306a36Sopenharmony_ci
801862306a36Sopenharmony_ci	drsprintk(ioc, ioc_info(ioc, "restart the adapter\n"));
801962306a36Sopenharmony_ci	writel(host_diagnostic & ~MPI2_DIAG_HOLD_IOC_RESET,
802062306a36Sopenharmony_ci	    &ioc->chip->HostDiagnostic);
802162306a36Sopenharmony_ci
802262306a36Sopenharmony_ci	drsprintk(ioc,
802362306a36Sopenharmony_ci		  ioc_info(ioc, "disable writes to the diagnostic register\n"));
802462306a36Sopenharmony_ci	writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence);
802562306a36Sopenharmony_ci
802662306a36Sopenharmony_ci	drsprintk(ioc, ioc_info(ioc, "Wait for FW to go to the READY state\n"));
802762306a36Sopenharmony_ci	ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20);
802862306a36Sopenharmony_ci	if (ioc_state) {
802962306a36Sopenharmony_ci		ioc_err(ioc, "%s: failed going to ready state (ioc_state=0x%x)\n",
803062306a36Sopenharmony_ci			__func__, ioc_state);
803162306a36Sopenharmony_ci		_base_dump_reg_set(ioc);
803262306a36Sopenharmony_ci		goto out;
803362306a36Sopenharmony_ci	}
803462306a36Sopenharmony_ci
803562306a36Sopenharmony_ci	pci_cfg_access_unlock(ioc->pdev);
803662306a36Sopenharmony_ci	ioc_info(ioc, "diag reset: SUCCESS\n");
803762306a36Sopenharmony_ci	return 0;
803862306a36Sopenharmony_ci
803962306a36Sopenharmony_ci out:
804062306a36Sopenharmony_ci	pci_cfg_access_unlock(ioc->pdev);
804162306a36Sopenharmony_ci	ioc_err(ioc, "diag reset: FAILED\n");
804262306a36Sopenharmony_ci	return -EFAULT;
804362306a36Sopenharmony_ci}
804462306a36Sopenharmony_ci
804562306a36Sopenharmony_ci/**
804662306a36Sopenharmony_ci * mpt3sas_base_make_ioc_ready - put controller in READY state
804762306a36Sopenharmony_ci * @ioc: per adapter object
804862306a36Sopenharmony_ci * @type: FORCE_BIG_HAMMER or SOFT_RESET
804962306a36Sopenharmony_ci *
805062306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
805162306a36Sopenharmony_ci */
805262306a36Sopenharmony_ciint
805362306a36Sopenharmony_cimpt3sas_base_make_ioc_ready(struct MPT3SAS_ADAPTER *ioc, enum reset_type type)
805462306a36Sopenharmony_ci{
805562306a36Sopenharmony_ci	u32 ioc_state;
805662306a36Sopenharmony_ci	int rc;
805762306a36Sopenharmony_ci	int count;
805862306a36Sopenharmony_ci
805962306a36Sopenharmony_ci	dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
806062306a36Sopenharmony_ci
806162306a36Sopenharmony_ci	if (ioc->pci_error_recovery)
806262306a36Sopenharmony_ci		return 0;
806362306a36Sopenharmony_ci
806462306a36Sopenharmony_ci	ioc_state = mpt3sas_base_get_iocstate(ioc, 0);
806562306a36Sopenharmony_ci	dhsprintk(ioc,
806662306a36Sopenharmony_ci		  ioc_info(ioc, "%s: ioc_state(0x%08x)\n",
806762306a36Sopenharmony_ci			   __func__, ioc_state));
806862306a36Sopenharmony_ci
806962306a36Sopenharmony_ci	/* if in RESET state, it should move to READY state shortly */
807062306a36Sopenharmony_ci	count = 0;
807162306a36Sopenharmony_ci	if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_RESET) {
807262306a36Sopenharmony_ci		while ((ioc_state & MPI2_IOC_STATE_MASK) !=
807362306a36Sopenharmony_ci		    MPI2_IOC_STATE_READY) {
807462306a36Sopenharmony_ci			if (count++ == 10) {
807562306a36Sopenharmony_ci				ioc_err(ioc, "%s: failed going to ready state (ioc_state=0x%x)\n",
807662306a36Sopenharmony_ci					__func__, ioc_state);
807762306a36Sopenharmony_ci				return -EFAULT;
807862306a36Sopenharmony_ci			}
807962306a36Sopenharmony_ci			ssleep(1);
808062306a36Sopenharmony_ci			ioc_state = mpt3sas_base_get_iocstate(ioc, 0);
808162306a36Sopenharmony_ci		}
808262306a36Sopenharmony_ci	}
808362306a36Sopenharmony_ci
808462306a36Sopenharmony_ci	if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY)
808562306a36Sopenharmony_ci		return 0;
808662306a36Sopenharmony_ci
808762306a36Sopenharmony_ci	if (ioc_state & MPI2_DOORBELL_USED) {
808862306a36Sopenharmony_ci		ioc_info(ioc, "unexpected doorbell active!\n");
808962306a36Sopenharmony_ci		goto issue_diag_reset;
809062306a36Sopenharmony_ci	}
809162306a36Sopenharmony_ci
809262306a36Sopenharmony_ci	if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
809362306a36Sopenharmony_ci		mpt3sas_print_fault_code(ioc, ioc_state &
809462306a36Sopenharmony_ci		    MPI2_DOORBELL_DATA_MASK);
809562306a36Sopenharmony_ci		goto issue_diag_reset;
809662306a36Sopenharmony_ci	}
809762306a36Sopenharmony_ci
809862306a36Sopenharmony_ci	if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_COREDUMP) {
809962306a36Sopenharmony_ci		/*
810062306a36Sopenharmony_ci		 * if host reset is invoked while watch dog thread is waiting
810162306a36Sopenharmony_ci		 * for IOC state to be changed to Fault state then driver has
810262306a36Sopenharmony_ci		 * to wait here for CoreDump state to clear otherwise reset
810362306a36Sopenharmony_ci		 * will be issued to the FW and FW move the IOC state to
810462306a36Sopenharmony_ci		 * reset state without copying the FW logs to coredump region.
810562306a36Sopenharmony_ci		 */
810662306a36Sopenharmony_ci		if (ioc->ioc_coredump_loop != MPT3SAS_COREDUMP_LOOP_DONE) {
810762306a36Sopenharmony_ci			mpt3sas_print_coredump_info(ioc, ioc_state &
810862306a36Sopenharmony_ci			    MPI2_DOORBELL_DATA_MASK);
810962306a36Sopenharmony_ci			mpt3sas_base_wait_for_coredump_completion(ioc,
811062306a36Sopenharmony_ci			    __func__);
811162306a36Sopenharmony_ci		}
811262306a36Sopenharmony_ci		goto issue_diag_reset;
811362306a36Sopenharmony_ci	}
811462306a36Sopenharmony_ci
811562306a36Sopenharmony_ci	if (type == FORCE_BIG_HAMMER)
811662306a36Sopenharmony_ci		goto issue_diag_reset;
811762306a36Sopenharmony_ci
811862306a36Sopenharmony_ci	if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL)
811962306a36Sopenharmony_ci		if (!(_base_send_ioc_reset(ioc,
812062306a36Sopenharmony_ci		    MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET, 15))) {
812162306a36Sopenharmony_ci			return 0;
812262306a36Sopenharmony_ci	}
812362306a36Sopenharmony_ci
812462306a36Sopenharmony_ci issue_diag_reset:
812562306a36Sopenharmony_ci	rc = _base_diag_reset(ioc);
812662306a36Sopenharmony_ci	return rc;
812762306a36Sopenharmony_ci}
812862306a36Sopenharmony_ci
812962306a36Sopenharmony_ci/**
813062306a36Sopenharmony_ci * _base_make_ioc_operational - put controller in OPERATIONAL state
813162306a36Sopenharmony_ci * @ioc: per adapter object
813262306a36Sopenharmony_ci *
813362306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
813462306a36Sopenharmony_ci */
813562306a36Sopenharmony_cistatic int
813662306a36Sopenharmony_ci_base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc)
813762306a36Sopenharmony_ci{
813862306a36Sopenharmony_ci	int r, i, index, rc;
813962306a36Sopenharmony_ci	unsigned long	flags;
814062306a36Sopenharmony_ci	u32 reply_address;
814162306a36Sopenharmony_ci	u16 smid;
814262306a36Sopenharmony_ci	struct _tr_list *delayed_tr, *delayed_tr_next;
814362306a36Sopenharmony_ci	struct _sc_list *delayed_sc, *delayed_sc_next;
814462306a36Sopenharmony_ci	struct _event_ack_list *delayed_event_ack, *delayed_event_ack_next;
814562306a36Sopenharmony_ci	u8 hide_flag;
814662306a36Sopenharmony_ci	struct adapter_reply_queue *reply_q;
814762306a36Sopenharmony_ci	Mpi2ReplyDescriptorsUnion_t *reply_post_free_contig;
814862306a36Sopenharmony_ci
814962306a36Sopenharmony_ci	dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
815062306a36Sopenharmony_ci
815162306a36Sopenharmony_ci	/* clean the delayed target reset list */
815262306a36Sopenharmony_ci	list_for_each_entry_safe(delayed_tr, delayed_tr_next,
815362306a36Sopenharmony_ci	    &ioc->delayed_tr_list, list) {
815462306a36Sopenharmony_ci		list_del(&delayed_tr->list);
815562306a36Sopenharmony_ci		kfree(delayed_tr);
815662306a36Sopenharmony_ci	}
815762306a36Sopenharmony_ci
815862306a36Sopenharmony_ci
815962306a36Sopenharmony_ci	list_for_each_entry_safe(delayed_tr, delayed_tr_next,
816062306a36Sopenharmony_ci	    &ioc->delayed_tr_volume_list, list) {
816162306a36Sopenharmony_ci		list_del(&delayed_tr->list);
816262306a36Sopenharmony_ci		kfree(delayed_tr);
816362306a36Sopenharmony_ci	}
816462306a36Sopenharmony_ci
816562306a36Sopenharmony_ci	list_for_each_entry_safe(delayed_sc, delayed_sc_next,
816662306a36Sopenharmony_ci	    &ioc->delayed_sc_list, list) {
816762306a36Sopenharmony_ci		list_del(&delayed_sc->list);
816862306a36Sopenharmony_ci		kfree(delayed_sc);
816962306a36Sopenharmony_ci	}
817062306a36Sopenharmony_ci
817162306a36Sopenharmony_ci	list_for_each_entry_safe(delayed_event_ack, delayed_event_ack_next,
817262306a36Sopenharmony_ci	    &ioc->delayed_event_ack_list, list) {
817362306a36Sopenharmony_ci		list_del(&delayed_event_ack->list);
817462306a36Sopenharmony_ci		kfree(delayed_event_ack);
817562306a36Sopenharmony_ci	}
817662306a36Sopenharmony_ci
817762306a36Sopenharmony_ci	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
817862306a36Sopenharmony_ci
817962306a36Sopenharmony_ci	/* hi-priority queue */
818062306a36Sopenharmony_ci	INIT_LIST_HEAD(&ioc->hpr_free_list);
818162306a36Sopenharmony_ci	smid = ioc->hi_priority_smid;
818262306a36Sopenharmony_ci	for (i = 0; i < ioc->hi_priority_depth; i++, smid++) {
818362306a36Sopenharmony_ci		ioc->hpr_lookup[i].cb_idx = 0xFF;
818462306a36Sopenharmony_ci		ioc->hpr_lookup[i].smid = smid;
818562306a36Sopenharmony_ci		list_add_tail(&ioc->hpr_lookup[i].tracker_list,
818662306a36Sopenharmony_ci		    &ioc->hpr_free_list);
818762306a36Sopenharmony_ci	}
818862306a36Sopenharmony_ci
818962306a36Sopenharmony_ci	/* internal queue */
819062306a36Sopenharmony_ci	INIT_LIST_HEAD(&ioc->internal_free_list);
819162306a36Sopenharmony_ci	smid = ioc->internal_smid;
819262306a36Sopenharmony_ci	for (i = 0; i < ioc->internal_depth; i++, smid++) {
819362306a36Sopenharmony_ci		ioc->internal_lookup[i].cb_idx = 0xFF;
819462306a36Sopenharmony_ci		ioc->internal_lookup[i].smid = smid;
819562306a36Sopenharmony_ci		list_add_tail(&ioc->internal_lookup[i].tracker_list,
819662306a36Sopenharmony_ci		    &ioc->internal_free_list);
819762306a36Sopenharmony_ci	}
819862306a36Sopenharmony_ci
819962306a36Sopenharmony_ci	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
820062306a36Sopenharmony_ci
820162306a36Sopenharmony_ci	/* initialize Reply Free Queue */
820262306a36Sopenharmony_ci	for (i = 0, reply_address = (u32)ioc->reply_dma ;
820362306a36Sopenharmony_ci	    i < ioc->reply_free_queue_depth ; i++, reply_address +=
820462306a36Sopenharmony_ci	    ioc->reply_sz) {
820562306a36Sopenharmony_ci		ioc->reply_free[i] = cpu_to_le32(reply_address);
820662306a36Sopenharmony_ci		if (ioc->is_mcpu_endpoint)
820762306a36Sopenharmony_ci			_base_clone_reply_to_sys_mem(ioc,
820862306a36Sopenharmony_ci					reply_address, i);
820962306a36Sopenharmony_ci	}
821062306a36Sopenharmony_ci
821162306a36Sopenharmony_ci	/* initialize reply queues */
821262306a36Sopenharmony_ci	if (ioc->is_driver_loading)
821362306a36Sopenharmony_ci		_base_assign_reply_queues(ioc);
821462306a36Sopenharmony_ci
821562306a36Sopenharmony_ci	/* initialize Reply Post Free Queue */
821662306a36Sopenharmony_ci	index = 0;
821762306a36Sopenharmony_ci	reply_post_free_contig = ioc->reply_post[0].reply_post_free;
821862306a36Sopenharmony_ci	list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
821962306a36Sopenharmony_ci		/*
822062306a36Sopenharmony_ci		 * If RDPQ is enabled, switch to the next allocation.
822162306a36Sopenharmony_ci		 * Otherwise advance within the contiguous region.
822262306a36Sopenharmony_ci		 */
822362306a36Sopenharmony_ci		if (ioc->rdpq_array_enable) {
822462306a36Sopenharmony_ci			reply_q->reply_post_free =
822562306a36Sopenharmony_ci				ioc->reply_post[index++].reply_post_free;
822662306a36Sopenharmony_ci		} else {
822762306a36Sopenharmony_ci			reply_q->reply_post_free = reply_post_free_contig;
822862306a36Sopenharmony_ci			reply_post_free_contig += ioc->reply_post_queue_depth;
822962306a36Sopenharmony_ci		}
823062306a36Sopenharmony_ci
823162306a36Sopenharmony_ci		reply_q->reply_post_host_index = 0;
823262306a36Sopenharmony_ci		for (i = 0; i < ioc->reply_post_queue_depth; i++)
823362306a36Sopenharmony_ci			reply_q->reply_post_free[i].Words =
823462306a36Sopenharmony_ci			    cpu_to_le64(ULLONG_MAX);
823562306a36Sopenharmony_ci		if (!_base_is_controller_msix_enabled(ioc))
823662306a36Sopenharmony_ci			goto skip_init_reply_post_free_queue;
823762306a36Sopenharmony_ci	}
823862306a36Sopenharmony_ci skip_init_reply_post_free_queue:
823962306a36Sopenharmony_ci
824062306a36Sopenharmony_ci	r = _base_send_ioc_init(ioc);
824162306a36Sopenharmony_ci	if (r) {
824262306a36Sopenharmony_ci		/*
824362306a36Sopenharmony_ci		 * No need to check IOC state for fault state & issue
824462306a36Sopenharmony_ci		 * diag reset during host reset. This check is need
824562306a36Sopenharmony_ci		 * only during driver load time.
824662306a36Sopenharmony_ci		 */
824762306a36Sopenharmony_ci		if (!ioc->is_driver_loading)
824862306a36Sopenharmony_ci			return r;
824962306a36Sopenharmony_ci
825062306a36Sopenharmony_ci		rc = mpt3sas_base_check_for_fault_and_issue_reset(ioc);
825162306a36Sopenharmony_ci		if (rc || (_base_send_ioc_init(ioc)))
825262306a36Sopenharmony_ci			return r;
825362306a36Sopenharmony_ci	}
825462306a36Sopenharmony_ci
825562306a36Sopenharmony_ci	/* initialize reply free host index */
825662306a36Sopenharmony_ci	ioc->reply_free_host_index = ioc->reply_free_queue_depth - 1;
825762306a36Sopenharmony_ci	writel(ioc->reply_free_host_index, &ioc->chip->ReplyFreeHostIndex);
825862306a36Sopenharmony_ci
825962306a36Sopenharmony_ci	/* initialize reply post host index */
826062306a36Sopenharmony_ci	list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
826162306a36Sopenharmony_ci		if (ioc->combined_reply_queue)
826262306a36Sopenharmony_ci			writel((reply_q->msix_index & 7)<<
826362306a36Sopenharmony_ci			   MPI2_RPHI_MSIX_INDEX_SHIFT,
826462306a36Sopenharmony_ci			   ioc->replyPostRegisterIndex[reply_q->msix_index/8]);
826562306a36Sopenharmony_ci		else
826662306a36Sopenharmony_ci			writel(reply_q->msix_index <<
826762306a36Sopenharmony_ci				MPI2_RPHI_MSIX_INDEX_SHIFT,
826862306a36Sopenharmony_ci				&ioc->chip->ReplyPostHostIndex);
826962306a36Sopenharmony_ci
827062306a36Sopenharmony_ci		if (!_base_is_controller_msix_enabled(ioc))
827162306a36Sopenharmony_ci			goto skip_init_reply_post_host_index;
827262306a36Sopenharmony_ci	}
827362306a36Sopenharmony_ci
827462306a36Sopenharmony_ci skip_init_reply_post_host_index:
827562306a36Sopenharmony_ci
827662306a36Sopenharmony_ci	mpt3sas_base_unmask_interrupts(ioc);
827762306a36Sopenharmony_ci
827862306a36Sopenharmony_ci	if (ioc->hba_mpi_version_belonged != MPI2_VERSION) {
827962306a36Sopenharmony_ci		r = _base_display_fwpkg_version(ioc);
828062306a36Sopenharmony_ci		if (r)
828162306a36Sopenharmony_ci			return r;
828262306a36Sopenharmony_ci	}
828362306a36Sopenharmony_ci
828462306a36Sopenharmony_ci	r = _base_static_config_pages(ioc);
828562306a36Sopenharmony_ci	if (r)
828662306a36Sopenharmony_ci		return r;
828762306a36Sopenharmony_ci
828862306a36Sopenharmony_ci	r = _base_event_notification(ioc);
828962306a36Sopenharmony_ci	if (r)
829062306a36Sopenharmony_ci		return r;
829162306a36Sopenharmony_ci
829262306a36Sopenharmony_ci	if (!ioc->shost_recovery) {
829362306a36Sopenharmony_ci
829462306a36Sopenharmony_ci		if (ioc->is_warpdrive && ioc->manu_pg10.OEMIdentifier
829562306a36Sopenharmony_ci		    == 0x80) {
829662306a36Sopenharmony_ci			hide_flag = (u8) (
829762306a36Sopenharmony_ci			    le32_to_cpu(ioc->manu_pg10.OEMSpecificFlags0) &
829862306a36Sopenharmony_ci			    MFG_PAGE10_HIDE_SSDS_MASK);
829962306a36Sopenharmony_ci			if (hide_flag != MFG_PAGE10_HIDE_SSDS_MASK)
830062306a36Sopenharmony_ci				ioc->mfg_pg10_hide_flag = hide_flag;
830162306a36Sopenharmony_ci		}
830262306a36Sopenharmony_ci
830362306a36Sopenharmony_ci		ioc->wait_for_discovery_to_complete =
830462306a36Sopenharmony_ci		    _base_determine_wait_on_discovery(ioc);
830562306a36Sopenharmony_ci
830662306a36Sopenharmony_ci		return r; /* scan_start and scan_finished support */
830762306a36Sopenharmony_ci	}
830862306a36Sopenharmony_ci
830962306a36Sopenharmony_ci	r = _base_send_port_enable(ioc);
831062306a36Sopenharmony_ci	if (r)
831162306a36Sopenharmony_ci		return r;
831262306a36Sopenharmony_ci
831362306a36Sopenharmony_ci	return r;
831462306a36Sopenharmony_ci}
831562306a36Sopenharmony_ci
831662306a36Sopenharmony_ci/**
831762306a36Sopenharmony_ci * mpt3sas_base_free_resources - free resources controller resources
831862306a36Sopenharmony_ci * @ioc: per adapter object
831962306a36Sopenharmony_ci */
832062306a36Sopenharmony_civoid
832162306a36Sopenharmony_cimpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc)
832262306a36Sopenharmony_ci{
832362306a36Sopenharmony_ci	dexitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
832462306a36Sopenharmony_ci
832562306a36Sopenharmony_ci	/* synchronizing freeing resource with pci_access_mutex lock */
832662306a36Sopenharmony_ci	mutex_lock(&ioc->pci_access_mutex);
832762306a36Sopenharmony_ci	if (ioc->chip_phys && ioc->chip) {
832862306a36Sopenharmony_ci		mpt3sas_base_mask_interrupts(ioc);
832962306a36Sopenharmony_ci		ioc->shost_recovery = 1;
833062306a36Sopenharmony_ci		mpt3sas_base_make_ioc_ready(ioc, SOFT_RESET);
833162306a36Sopenharmony_ci		ioc->shost_recovery = 0;
833262306a36Sopenharmony_ci	}
833362306a36Sopenharmony_ci
833462306a36Sopenharmony_ci	mpt3sas_base_unmap_resources(ioc);
833562306a36Sopenharmony_ci	mutex_unlock(&ioc->pci_access_mutex);
833662306a36Sopenharmony_ci	return;
833762306a36Sopenharmony_ci}
833862306a36Sopenharmony_ci
833962306a36Sopenharmony_ci/**
834062306a36Sopenharmony_ci * mpt3sas_base_attach - attach controller instance
834162306a36Sopenharmony_ci * @ioc: per adapter object
834262306a36Sopenharmony_ci *
834362306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
834462306a36Sopenharmony_ci */
834562306a36Sopenharmony_ciint
834662306a36Sopenharmony_cimpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
834762306a36Sopenharmony_ci{
834862306a36Sopenharmony_ci	int r, i, rc;
834962306a36Sopenharmony_ci	int cpu_id, last_cpu_id = 0;
835062306a36Sopenharmony_ci
835162306a36Sopenharmony_ci	dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
835262306a36Sopenharmony_ci
835362306a36Sopenharmony_ci	/* setup cpu_msix_table */
835462306a36Sopenharmony_ci	ioc->cpu_count = num_online_cpus();
835562306a36Sopenharmony_ci	for_each_online_cpu(cpu_id)
835662306a36Sopenharmony_ci		last_cpu_id = cpu_id;
835762306a36Sopenharmony_ci	ioc->cpu_msix_table_sz = last_cpu_id + 1;
835862306a36Sopenharmony_ci	ioc->cpu_msix_table = kzalloc(ioc->cpu_msix_table_sz, GFP_KERNEL);
835962306a36Sopenharmony_ci	ioc->reply_queue_count = 1;
836062306a36Sopenharmony_ci	if (!ioc->cpu_msix_table) {
836162306a36Sopenharmony_ci		ioc_info(ioc, "Allocation for cpu_msix_table failed!!!\n");
836262306a36Sopenharmony_ci		r = -ENOMEM;
836362306a36Sopenharmony_ci		goto out_free_resources;
836462306a36Sopenharmony_ci	}
836562306a36Sopenharmony_ci
836662306a36Sopenharmony_ci	if (ioc->is_warpdrive) {
836762306a36Sopenharmony_ci		ioc->reply_post_host_index = kcalloc(ioc->cpu_msix_table_sz,
836862306a36Sopenharmony_ci		    sizeof(resource_size_t *), GFP_KERNEL);
836962306a36Sopenharmony_ci		if (!ioc->reply_post_host_index) {
837062306a36Sopenharmony_ci			ioc_info(ioc, "Allocation for reply_post_host_index failed!!!\n");
837162306a36Sopenharmony_ci			r = -ENOMEM;
837262306a36Sopenharmony_ci			goto out_free_resources;
837362306a36Sopenharmony_ci		}
837462306a36Sopenharmony_ci	}
837562306a36Sopenharmony_ci
837662306a36Sopenharmony_ci	ioc->smp_affinity_enable = smp_affinity_enable;
837762306a36Sopenharmony_ci
837862306a36Sopenharmony_ci	ioc->rdpq_array_enable_assigned = 0;
837962306a36Sopenharmony_ci	ioc->use_32bit_dma = false;
838062306a36Sopenharmony_ci	ioc->dma_mask = 64;
838162306a36Sopenharmony_ci	if (ioc->is_aero_ioc) {
838262306a36Sopenharmony_ci		ioc->base_readl = &_base_readl_aero;
838362306a36Sopenharmony_ci		ioc->base_readl_ext_retry = &_base_readl_ext_retry;
838462306a36Sopenharmony_ci	} else {
838562306a36Sopenharmony_ci		ioc->base_readl = &_base_readl;
838662306a36Sopenharmony_ci		ioc->base_readl_ext_retry = &_base_readl;
838762306a36Sopenharmony_ci	}
838862306a36Sopenharmony_ci	r = mpt3sas_base_map_resources(ioc);
838962306a36Sopenharmony_ci	if (r)
839062306a36Sopenharmony_ci		goto out_free_resources;
839162306a36Sopenharmony_ci
839262306a36Sopenharmony_ci	pci_set_drvdata(ioc->pdev, ioc->shost);
839362306a36Sopenharmony_ci	r = _base_get_ioc_facts(ioc);
839462306a36Sopenharmony_ci	if (r) {
839562306a36Sopenharmony_ci		rc = mpt3sas_base_check_for_fault_and_issue_reset(ioc);
839662306a36Sopenharmony_ci		if (rc || (_base_get_ioc_facts(ioc)))
839762306a36Sopenharmony_ci			goto out_free_resources;
839862306a36Sopenharmony_ci	}
839962306a36Sopenharmony_ci
840062306a36Sopenharmony_ci	switch (ioc->hba_mpi_version_belonged) {
840162306a36Sopenharmony_ci	case MPI2_VERSION:
840262306a36Sopenharmony_ci		ioc->build_sg_scmd = &_base_build_sg_scmd;
840362306a36Sopenharmony_ci		ioc->build_sg = &_base_build_sg;
840462306a36Sopenharmony_ci		ioc->build_zero_len_sge = &_base_build_zero_len_sge;
840562306a36Sopenharmony_ci		ioc->get_msix_index_for_smlio = &_base_get_msix_index;
840662306a36Sopenharmony_ci		break;
840762306a36Sopenharmony_ci	case MPI25_VERSION:
840862306a36Sopenharmony_ci	case MPI26_VERSION:
840962306a36Sopenharmony_ci		/*
841062306a36Sopenharmony_ci		 * In SAS3.0,
841162306a36Sopenharmony_ci		 * SCSI_IO, SMP_PASSTHRU, SATA_PASSTHRU, Target Assist, and
841262306a36Sopenharmony_ci		 * Target Status - all require the IEEE formatted scatter gather
841362306a36Sopenharmony_ci		 * elements.
841462306a36Sopenharmony_ci		 */
841562306a36Sopenharmony_ci		ioc->build_sg_scmd = &_base_build_sg_scmd_ieee;
841662306a36Sopenharmony_ci		ioc->build_sg = &_base_build_sg_ieee;
841762306a36Sopenharmony_ci		ioc->build_nvme_prp = &_base_build_nvme_prp;
841862306a36Sopenharmony_ci		ioc->build_zero_len_sge = &_base_build_zero_len_sge_ieee;
841962306a36Sopenharmony_ci		ioc->sge_size_ieee = sizeof(Mpi2IeeeSgeSimple64_t);
842062306a36Sopenharmony_ci		if (ioc->high_iops_queues)
842162306a36Sopenharmony_ci			ioc->get_msix_index_for_smlio =
842262306a36Sopenharmony_ci					&_base_get_high_iops_msix_index;
842362306a36Sopenharmony_ci		else
842462306a36Sopenharmony_ci			ioc->get_msix_index_for_smlio = &_base_get_msix_index;
842562306a36Sopenharmony_ci		break;
842662306a36Sopenharmony_ci	}
842762306a36Sopenharmony_ci	if (ioc->atomic_desc_capable) {
842862306a36Sopenharmony_ci		ioc->put_smid_default = &_base_put_smid_default_atomic;
842962306a36Sopenharmony_ci		ioc->put_smid_scsi_io = &_base_put_smid_scsi_io_atomic;
843062306a36Sopenharmony_ci		ioc->put_smid_fast_path =
843162306a36Sopenharmony_ci				&_base_put_smid_fast_path_atomic;
843262306a36Sopenharmony_ci		ioc->put_smid_hi_priority =
843362306a36Sopenharmony_ci				&_base_put_smid_hi_priority_atomic;
843462306a36Sopenharmony_ci	} else {
843562306a36Sopenharmony_ci		ioc->put_smid_default = &_base_put_smid_default;
843662306a36Sopenharmony_ci		ioc->put_smid_fast_path = &_base_put_smid_fast_path;
843762306a36Sopenharmony_ci		ioc->put_smid_hi_priority = &_base_put_smid_hi_priority;
843862306a36Sopenharmony_ci		if (ioc->is_mcpu_endpoint)
843962306a36Sopenharmony_ci			ioc->put_smid_scsi_io =
844062306a36Sopenharmony_ci				&_base_put_smid_mpi_ep_scsi_io;
844162306a36Sopenharmony_ci		else
844262306a36Sopenharmony_ci			ioc->put_smid_scsi_io = &_base_put_smid_scsi_io;
844362306a36Sopenharmony_ci	}
844462306a36Sopenharmony_ci	/*
844562306a36Sopenharmony_ci	 * These function pointers for other requests that don't
844662306a36Sopenharmony_ci	 * the require IEEE scatter gather elements.
844762306a36Sopenharmony_ci	 *
844862306a36Sopenharmony_ci	 * For example Configuration Pages and SAS IOUNIT Control don't.
844962306a36Sopenharmony_ci	 */
845062306a36Sopenharmony_ci	ioc->build_sg_mpi = &_base_build_sg;
845162306a36Sopenharmony_ci	ioc->build_zero_len_sge_mpi = &_base_build_zero_len_sge;
845262306a36Sopenharmony_ci
845362306a36Sopenharmony_ci	r = mpt3sas_base_make_ioc_ready(ioc, SOFT_RESET);
845462306a36Sopenharmony_ci	if (r)
845562306a36Sopenharmony_ci		goto out_free_resources;
845662306a36Sopenharmony_ci
845762306a36Sopenharmony_ci	ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts,
845862306a36Sopenharmony_ci	    sizeof(struct mpt3sas_port_facts), GFP_KERNEL);
845962306a36Sopenharmony_ci	if (!ioc->pfacts) {
846062306a36Sopenharmony_ci		r = -ENOMEM;
846162306a36Sopenharmony_ci		goto out_free_resources;
846262306a36Sopenharmony_ci	}
846362306a36Sopenharmony_ci
846462306a36Sopenharmony_ci	for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) {
846562306a36Sopenharmony_ci		r = _base_get_port_facts(ioc, i);
846662306a36Sopenharmony_ci		if (r) {
846762306a36Sopenharmony_ci			rc = mpt3sas_base_check_for_fault_and_issue_reset(ioc);
846862306a36Sopenharmony_ci			if (rc || (_base_get_port_facts(ioc, i)))
846962306a36Sopenharmony_ci				goto out_free_resources;
847062306a36Sopenharmony_ci		}
847162306a36Sopenharmony_ci	}
847262306a36Sopenharmony_ci
847362306a36Sopenharmony_ci	r = _base_allocate_memory_pools(ioc);
847462306a36Sopenharmony_ci	if (r)
847562306a36Sopenharmony_ci		goto out_free_resources;
847662306a36Sopenharmony_ci
847762306a36Sopenharmony_ci	if (irqpoll_weight > 0)
847862306a36Sopenharmony_ci		ioc->thresh_hold = irqpoll_weight;
847962306a36Sopenharmony_ci	else
848062306a36Sopenharmony_ci		ioc->thresh_hold = ioc->hba_queue_depth/4;
848162306a36Sopenharmony_ci
848262306a36Sopenharmony_ci	_base_init_irqpolls(ioc);
848362306a36Sopenharmony_ci	init_waitqueue_head(&ioc->reset_wq);
848462306a36Sopenharmony_ci
848562306a36Sopenharmony_ci	/* allocate memory pd handle bitmask list */
848662306a36Sopenharmony_ci	ioc->pd_handles_sz = (ioc->facts.MaxDevHandle / 8);
848762306a36Sopenharmony_ci	if (ioc->facts.MaxDevHandle % 8)
848862306a36Sopenharmony_ci		ioc->pd_handles_sz++;
848962306a36Sopenharmony_ci	ioc->pd_handles = kzalloc(ioc->pd_handles_sz,
849062306a36Sopenharmony_ci	    GFP_KERNEL);
849162306a36Sopenharmony_ci	if (!ioc->pd_handles) {
849262306a36Sopenharmony_ci		r = -ENOMEM;
849362306a36Sopenharmony_ci		goto out_free_resources;
849462306a36Sopenharmony_ci	}
849562306a36Sopenharmony_ci	ioc->blocking_handles = kzalloc(ioc->pd_handles_sz,
849662306a36Sopenharmony_ci	    GFP_KERNEL);
849762306a36Sopenharmony_ci	if (!ioc->blocking_handles) {
849862306a36Sopenharmony_ci		r = -ENOMEM;
849962306a36Sopenharmony_ci		goto out_free_resources;
850062306a36Sopenharmony_ci	}
850162306a36Sopenharmony_ci
850262306a36Sopenharmony_ci	/* allocate memory for pending OS device add list */
850362306a36Sopenharmony_ci	ioc->pend_os_device_add_sz = (ioc->facts.MaxDevHandle / 8);
850462306a36Sopenharmony_ci	if (ioc->facts.MaxDevHandle % 8)
850562306a36Sopenharmony_ci		ioc->pend_os_device_add_sz++;
850662306a36Sopenharmony_ci	ioc->pend_os_device_add = kzalloc(ioc->pend_os_device_add_sz,
850762306a36Sopenharmony_ci	    GFP_KERNEL);
850862306a36Sopenharmony_ci	if (!ioc->pend_os_device_add) {
850962306a36Sopenharmony_ci		r = -ENOMEM;
851062306a36Sopenharmony_ci		goto out_free_resources;
851162306a36Sopenharmony_ci	}
851262306a36Sopenharmony_ci
851362306a36Sopenharmony_ci	ioc->device_remove_in_progress_sz = ioc->pend_os_device_add_sz;
851462306a36Sopenharmony_ci	ioc->device_remove_in_progress =
851562306a36Sopenharmony_ci		kzalloc(ioc->device_remove_in_progress_sz, GFP_KERNEL);
851662306a36Sopenharmony_ci	if (!ioc->device_remove_in_progress) {
851762306a36Sopenharmony_ci		r = -ENOMEM;
851862306a36Sopenharmony_ci		goto out_free_resources;
851962306a36Sopenharmony_ci	}
852062306a36Sopenharmony_ci
852162306a36Sopenharmony_ci	ioc->fwfault_debug = mpt3sas_fwfault_debug;
852262306a36Sopenharmony_ci
852362306a36Sopenharmony_ci	/* base internal command bits */
852462306a36Sopenharmony_ci	mutex_init(&ioc->base_cmds.mutex);
852562306a36Sopenharmony_ci	ioc->base_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
852662306a36Sopenharmony_ci	ioc->base_cmds.status = MPT3_CMD_NOT_USED;
852762306a36Sopenharmony_ci
852862306a36Sopenharmony_ci	/* port_enable command bits */
852962306a36Sopenharmony_ci	ioc->port_enable_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
853062306a36Sopenharmony_ci	ioc->port_enable_cmds.status = MPT3_CMD_NOT_USED;
853162306a36Sopenharmony_ci
853262306a36Sopenharmony_ci	/* transport internal command bits */
853362306a36Sopenharmony_ci	ioc->transport_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
853462306a36Sopenharmony_ci	ioc->transport_cmds.status = MPT3_CMD_NOT_USED;
853562306a36Sopenharmony_ci	mutex_init(&ioc->transport_cmds.mutex);
853662306a36Sopenharmony_ci
853762306a36Sopenharmony_ci	/* scsih internal command bits */
853862306a36Sopenharmony_ci	ioc->scsih_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
853962306a36Sopenharmony_ci	ioc->scsih_cmds.status = MPT3_CMD_NOT_USED;
854062306a36Sopenharmony_ci	mutex_init(&ioc->scsih_cmds.mutex);
854162306a36Sopenharmony_ci
854262306a36Sopenharmony_ci	/* task management internal command bits */
854362306a36Sopenharmony_ci	ioc->tm_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
854462306a36Sopenharmony_ci	ioc->tm_cmds.status = MPT3_CMD_NOT_USED;
854562306a36Sopenharmony_ci	mutex_init(&ioc->tm_cmds.mutex);
854662306a36Sopenharmony_ci
854762306a36Sopenharmony_ci	/* config page internal command bits */
854862306a36Sopenharmony_ci	ioc->config_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
854962306a36Sopenharmony_ci	ioc->config_cmds.status = MPT3_CMD_NOT_USED;
855062306a36Sopenharmony_ci	mutex_init(&ioc->config_cmds.mutex);
855162306a36Sopenharmony_ci
855262306a36Sopenharmony_ci	/* ctl module internal command bits */
855362306a36Sopenharmony_ci	ioc->ctl_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
855462306a36Sopenharmony_ci	ioc->ctl_cmds.sense = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL);
855562306a36Sopenharmony_ci	ioc->ctl_cmds.status = MPT3_CMD_NOT_USED;
855662306a36Sopenharmony_ci	mutex_init(&ioc->ctl_cmds.mutex);
855762306a36Sopenharmony_ci
855862306a36Sopenharmony_ci	if (!ioc->base_cmds.reply || !ioc->port_enable_cmds.reply ||
855962306a36Sopenharmony_ci	    !ioc->transport_cmds.reply || !ioc->scsih_cmds.reply ||
856062306a36Sopenharmony_ci	    !ioc->tm_cmds.reply || !ioc->config_cmds.reply ||
856162306a36Sopenharmony_ci	    !ioc->ctl_cmds.reply || !ioc->ctl_cmds.sense) {
856262306a36Sopenharmony_ci		r = -ENOMEM;
856362306a36Sopenharmony_ci		goto out_free_resources;
856462306a36Sopenharmony_ci	}
856562306a36Sopenharmony_ci
856662306a36Sopenharmony_ci	for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
856762306a36Sopenharmony_ci		ioc->event_masks[i] = -1;
856862306a36Sopenharmony_ci
856962306a36Sopenharmony_ci	/* here we enable the events we care about */
857062306a36Sopenharmony_ci	_base_unmask_events(ioc, MPI2_EVENT_SAS_DISCOVERY);
857162306a36Sopenharmony_ci	_base_unmask_events(ioc, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE);
857262306a36Sopenharmony_ci	_base_unmask_events(ioc, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
857362306a36Sopenharmony_ci	_base_unmask_events(ioc, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
857462306a36Sopenharmony_ci	_base_unmask_events(ioc, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE);
857562306a36Sopenharmony_ci	_base_unmask_events(ioc, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST);
857662306a36Sopenharmony_ci	_base_unmask_events(ioc, MPI2_EVENT_IR_VOLUME);
857762306a36Sopenharmony_ci	_base_unmask_events(ioc, MPI2_EVENT_IR_PHYSICAL_DISK);
857862306a36Sopenharmony_ci	_base_unmask_events(ioc, MPI2_EVENT_IR_OPERATION_STATUS);
857962306a36Sopenharmony_ci	_base_unmask_events(ioc, MPI2_EVENT_LOG_ENTRY_ADDED);
858062306a36Sopenharmony_ci	_base_unmask_events(ioc, MPI2_EVENT_TEMP_THRESHOLD);
858162306a36Sopenharmony_ci	_base_unmask_events(ioc, MPI2_EVENT_ACTIVE_CABLE_EXCEPTION);
858262306a36Sopenharmony_ci	_base_unmask_events(ioc, MPI2_EVENT_SAS_DEVICE_DISCOVERY_ERROR);
858362306a36Sopenharmony_ci	if (ioc->hba_mpi_version_belonged == MPI26_VERSION) {
858462306a36Sopenharmony_ci		if (ioc->is_gen35_ioc) {
858562306a36Sopenharmony_ci			_base_unmask_events(ioc,
858662306a36Sopenharmony_ci				MPI2_EVENT_PCIE_DEVICE_STATUS_CHANGE);
858762306a36Sopenharmony_ci			_base_unmask_events(ioc, MPI2_EVENT_PCIE_ENUMERATION);
858862306a36Sopenharmony_ci			_base_unmask_events(ioc,
858962306a36Sopenharmony_ci				MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST);
859062306a36Sopenharmony_ci		}
859162306a36Sopenharmony_ci	}
859262306a36Sopenharmony_ci	r = _base_make_ioc_operational(ioc);
859362306a36Sopenharmony_ci	if (r == -EAGAIN) {
859462306a36Sopenharmony_ci		r = _base_make_ioc_operational(ioc);
859562306a36Sopenharmony_ci		if (r)
859662306a36Sopenharmony_ci			goto out_free_resources;
859762306a36Sopenharmony_ci	}
859862306a36Sopenharmony_ci
859962306a36Sopenharmony_ci	/*
860062306a36Sopenharmony_ci	 * Copy current copy of IOCFacts in prev_fw_facts
860162306a36Sopenharmony_ci	 * and it will be used during online firmware upgrade.
860262306a36Sopenharmony_ci	 */
860362306a36Sopenharmony_ci	memcpy(&ioc->prev_fw_facts, &ioc->facts,
860462306a36Sopenharmony_ci	    sizeof(struct mpt3sas_facts));
860562306a36Sopenharmony_ci
860662306a36Sopenharmony_ci	ioc->non_operational_loop = 0;
860762306a36Sopenharmony_ci	ioc->ioc_coredump_loop = 0;
860862306a36Sopenharmony_ci	ioc->got_task_abort_from_ioctl = 0;
860962306a36Sopenharmony_ci	return 0;
861062306a36Sopenharmony_ci
861162306a36Sopenharmony_ci out_free_resources:
861262306a36Sopenharmony_ci
861362306a36Sopenharmony_ci	ioc->remove_host = 1;
861462306a36Sopenharmony_ci
861562306a36Sopenharmony_ci	mpt3sas_base_free_resources(ioc);
861662306a36Sopenharmony_ci	_base_release_memory_pools(ioc);
861762306a36Sopenharmony_ci	pci_set_drvdata(ioc->pdev, NULL);
861862306a36Sopenharmony_ci	kfree(ioc->cpu_msix_table);
861962306a36Sopenharmony_ci	if (ioc->is_warpdrive)
862062306a36Sopenharmony_ci		kfree(ioc->reply_post_host_index);
862162306a36Sopenharmony_ci	kfree(ioc->pd_handles);
862262306a36Sopenharmony_ci	kfree(ioc->blocking_handles);
862362306a36Sopenharmony_ci	kfree(ioc->device_remove_in_progress);
862462306a36Sopenharmony_ci	kfree(ioc->pend_os_device_add);
862562306a36Sopenharmony_ci	kfree(ioc->tm_cmds.reply);
862662306a36Sopenharmony_ci	kfree(ioc->transport_cmds.reply);
862762306a36Sopenharmony_ci	kfree(ioc->scsih_cmds.reply);
862862306a36Sopenharmony_ci	kfree(ioc->config_cmds.reply);
862962306a36Sopenharmony_ci	kfree(ioc->base_cmds.reply);
863062306a36Sopenharmony_ci	kfree(ioc->port_enable_cmds.reply);
863162306a36Sopenharmony_ci	kfree(ioc->ctl_cmds.reply);
863262306a36Sopenharmony_ci	kfree(ioc->ctl_cmds.sense);
863362306a36Sopenharmony_ci	kfree(ioc->pfacts);
863462306a36Sopenharmony_ci	ioc->ctl_cmds.reply = NULL;
863562306a36Sopenharmony_ci	ioc->base_cmds.reply = NULL;
863662306a36Sopenharmony_ci	ioc->tm_cmds.reply = NULL;
863762306a36Sopenharmony_ci	ioc->scsih_cmds.reply = NULL;
863862306a36Sopenharmony_ci	ioc->transport_cmds.reply = NULL;
863962306a36Sopenharmony_ci	ioc->config_cmds.reply = NULL;
864062306a36Sopenharmony_ci	ioc->pfacts = NULL;
864162306a36Sopenharmony_ci	return r;
864262306a36Sopenharmony_ci}
864362306a36Sopenharmony_ci
864462306a36Sopenharmony_ci
864562306a36Sopenharmony_ci/**
864662306a36Sopenharmony_ci * mpt3sas_base_detach - remove controller instance
864762306a36Sopenharmony_ci * @ioc: per adapter object
864862306a36Sopenharmony_ci */
864962306a36Sopenharmony_civoid
865062306a36Sopenharmony_cimpt3sas_base_detach(struct MPT3SAS_ADAPTER *ioc)
865162306a36Sopenharmony_ci{
865262306a36Sopenharmony_ci	dexitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
865362306a36Sopenharmony_ci
865462306a36Sopenharmony_ci	mpt3sas_base_stop_watchdog(ioc);
865562306a36Sopenharmony_ci	mpt3sas_base_free_resources(ioc);
865662306a36Sopenharmony_ci	_base_release_memory_pools(ioc);
865762306a36Sopenharmony_ci	mpt3sas_free_enclosure_list(ioc);
865862306a36Sopenharmony_ci	pci_set_drvdata(ioc->pdev, NULL);
865962306a36Sopenharmony_ci	kfree(ioc->cpu_msix_table);
866062306a36Sopenharmony_ci	if (ioc->is_warpdrive)
866162306a36Sopenharmony_ci		kfree(ioc->reply_post_host_index);
866262306a36Sopenharmony_ci	kfree(ioc->pd_handles);
866362306a36Sopenharmony_ci	kfree(ioc->blocking_handles);
866462306a36Sopenharmony_ci	kfree(ioc->device_remove_in_progress);
866562306a36Sopenharmony_ci	kfree(ioc->pend_os_device_add);
866662306a36Sopenharmony_ci	kfree(ioc->pfacts);
866762306a36Sopenharmony_ci	kfree(ioc->ctl_cmds.reply);
866862306a36Sopenharmony_ci	kfree(ioc->ctl_cmds.sense);
866962306a36Sopenharmony_ci	kfree(ioc->base_cmds.reply);
867062306a36Sopenharmony_ci	kfree(ioc->port_enable_cmds.reply);
867162306a36Sopenharmony_ci	kfree(ioc->tm_cmds.reply);
867262306a36Sopenharmony_ci	kfree(ioc->transport_cmds.reply);
867362306a36Sopenharmony_ci	kfree(ioc->scsih_cmds.reply);
867462306a36Sopenharmony_ci	kfree(ioc->config_cmds.reply);
867562306a36Sopenharmony_ci}
867662306a36Sopenharmony_ci
867762306a36Sopenharmony_ci/**
867862306a36Sopenharmony_ci * _base_pre_reset_handler - pre reset handler
867962306a36Sopenharmony_ci * @ioc: per adapter object
868062306a36Sopenharmony_ci */
868162306a36Sopenharmony_cistatic void _base_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc)
868262306a36Sopenharmony_ci{
868362306a36Sopenharmony_ci	mpt3sas_scsih_pre_reset_handler(ioc);
868462306a36Sopenharmony_ci	mpt3sas_ctl_pre_reset_handler(ioc);
868562306a36Sopenharmony_ci	dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_PRE_RESET\n", __func__));
868662306a36Sopenharmony_ci}
868762306a36Sopenharmony_ci
868862306a36Sopenharmony_ci/**
868962306a36Sopenharmony_ci * _base_clear_outstanding_mpt_commands - clears outstanding mpt commands
869062306a36Sopenharmony_ci * @ioc: per adapter object
869162306a36Sopenharmony_ci */
869262306a36Sopenharmony_cistatic void
869362306a36Sopenharmony_ci_base_clear_outstanding_mpt_commands(struct MPT3SAS_ADAPTER *ioc)
869462306a36Sopenharmony_ci{
869562306a36Sopenharmony_ci	dtmprintk(ioc,
869662306a36Sopenharmony_ci	    ioc_info(ioc, "%s: clear outstanding mpt cmds\n", __func__));
869762306a36Sopenharmony_ci	if (ioc->transport_cmds.status & MPT3_CMD_PENDING) {
869862306a36Sopenharmony_ci		ioc->transport_cmds.status |= MPT3_CMD_RESET;
869962306a36Sopenharmony_ci		mpt3sas_base_free_smid(ioc, ioc->transport_cmds.smid);
870062306a36Sopenharmony_ci		complete(&ioc->transport_cmds.done);
870162306a36Sopenharmony_ci	}
870262306a36Sopenharmony_ci	if (ioc->base_cmds.status & MPT3_CMD_PENDING) {
870362306a36Sopenharmony_ci		ioc->base_cmds.status |= MPT3_CMD_RESET;
870462306a36Sopenharmony_ci		mpt3sas_base_free_smid(ioc, ioc->base_cmds.smid);
870562306a36Sopenharmony_ci		complete(&ioc->base_cmds.done);
870662306a36Sopenharmony_ci	}
870762306a36Sopenharmony_ci	if (ioc->port_enable_cmds.status & MPT3_CMD_PENDING) {
870862306a36Sopenharmony_ci		ioc->port_enable_failed = 1;
870962306a36Sopenharmony_ci		ioc->port_enable_cmds.status |= MPT3_CMD_RESET;
871062306a36Sopenharmony_ci		mpt3sas_base_free_smid(ioc, ioc->port_enable_cmds.smid);
871162306a36Sopenharmony_ci		if (ioc->is_driver_loading) {
871262306a36Sopenharmony_ci			ioc->start_scan_failed =
871362306a36Sopenharmony_ci				MPI2_IOCSTATUS_INTERNAL_ERROR;
871462306a36Sopenharmony_ci			ioc->start_scan = 0;
871562306a36Sopenharmony_ci		} else {
871662306a36Sopenharmony_ci			complete(&ioc->port_enable_cmds.done);
871762306a36Sopenharmony_ci		}
871862306a36Sopenharmony_ci	}
871962306a36Sopenharmony_ci	if (ioc->config_cmds.status & MPT3_CMD_PENDING) {
872062306a36Sopenharmony_ci		ioc->config_cmds.status |= MPT3_CMD_RESET;
872162306a36Sopenharmony_ci		mpt3sas_base_free_smid(ioc, ioc->config_cmds.smid);
872262306a36Sopenharmony_ci		ioc->config_cmds.smid = USHRT_MAX;
872362306a36Sopenharmony_ci		complete(&ioc->config_cmds.done);
872462306a36Sopenharmony_ci	}
872562306a36Sopenharmony_ci}
872662306a36Sopenharmony_ci
872762306a36Sopenharmony_ci/**
872862306a36Sopenharmony_ci * _base_clear_outstanding_commands - clear all outstanding commands
872962306a36Sopenharmony_ci * @ioc: per adapter object
873062306a36Sopenharmony_ci */
873162306a36Sopenharmony_cistatic void _base_clear_outstanding_commands(struct MPT3SAS_ADAPTER *ioc)
873262306a36Sopenharmony_ci{
873362306a36Sopenharmony_ci	mpt3sas_scsih_clear_outstanding_scsi_tm_commands(ioc);
873462306a36Sopenharmony_ci	mpt3sas_ctl_clear_outstanding_ioctls(ioc);
873562306a36Sopenharmony_ci	_base_clear_outstanding_mpt_commands(ioc);
873662306a36Sopenharmony_ci}
873762306a36Sopenharmony_ci
873862306a36Sopenharmony_ci/**
873962306a36Sopenharmony_ci * _base_reset_done_handler - reset done handler
874062306a36Sopenharmony_ci * @ioc: per adapter object
874162306a36Sopenharmony_ci */
874262306a36Sopenharmony_cistatic void _base_reset_done_handler(struct MPT3SAS_ADAPTER *ioc)
874362306a36Sopenharmony_ci{
874462306a36Sopenharmony_ci	mpt3sas_scsih_reset_done_handler(ioc);
874562306a36Sopenharmony_ci	mpt3sas_ctl_reset_done_handler(ioc);
874662306a36Sopenharmony_ci	dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_DONE_RESET\n", __func__));
874762306a36Sopenharmony_ci}
874862306a36Sopenharmony_ci
874962306a36Sopenharmony_ci/**
875062306a36Sopenharmony_ci * mpt3sas_wait_for_commands_to_complete - reset controller
875162306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure
875262306a36Sopenharmony_ci *
875362306a36Sopenharmony_ci * This function is waiting 10s for all pending commands to complete
875462306a36Sopenharmony_ci * prior to putting controller in reset.
875562306a36Sopenharmony_ci */
875662306a36Sopenharmony_civoid
875762306a36Sopenharmony_cimpt3sas_wait_for_commands_to_complete(struct MPT3SAS_ADAPTER *ioc)
875862306a36Sopenharmony_ci{
875962306a36Sopenharmony_ci	u32 ioc_state;
876062306a36Sopenharmony_ci
876162306a36Sopenharmony_ci	ioc->pending_io_count = 0;
876262306a36Sopenharmony_ci
876362306a36Sopenharmony_ci	ioc_state = mpt3sas_base_get_iocstate(ioc, 0);
876462306a36Sopenharmony_ci	if ((ioc_state & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL)
876562306a36Sopenharmony_ci		return;
876662306a36Sopenharmony_ci
876762306a36Sopenharmony_ci	/* pending command count */
876862306a36Sopenharmony_ci	ioc->pending_io_count = scsi_host_busy(ioc->shost);
876962306a36Sopenharmony_ci
877062306a36Sopenharmony_ci	if (!ioc->pending_io_count)
877162306a36Sopenharmony_ci		return;
877262306a36Sopenharmony_ci
877362306a36Sopenharmony_ci	/* wait for pending commands to complete */
877462306a36Sopenharmony_ci	wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, 10 * HZ);
877562306a36Sopenharmony_ci}
877662306a36Sopenharmony_ci
877762306a36Sopenharmony_ci/**
877862306a36Sopenharmony_ci * _base_check_ioc_facts_changes - Look for increase/decrease of IOCFacts
877962306a36Sopenharmony_ci *     attributes during online firmware upgrade and update the corresponding
878062306a36Sopenharmony_ci *     IOC variables accordingly.
878162306a36Sopenharmony_ci *
878262306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure
878362306a36Sopenharmony_ci */
878462306a36Sopenharmony_cistatic int
878562306a36Sopenharmony_ci_base_check_ioc_facts_changes(struct MPT3SAS_ADAPTER *ioc)
878662306a36Sopenharmony_ci{
878762306a36Sopenharmony_ci	u16 pd_handles_sz;
878862306a36Sopenharmony_ci	void *pd_handles = NULL, *blocking_handles = NULL;
878962306a36Sopenharmony_ci	void *pend_os_device_add = NULL, *device_remove_in_progress = NULL;
879062306a36Sopenharmony_ci	struct mpt3sas_facts *old_facts = &ioc->prev_fw_facts;
879162306a36Sopenharmony_ci
879262306a36Sopenharmony_ci	if (ioc->facts.MaxDevHandle > old_facts->MaxDevHandle) {
879362306a36Sopenharmony_ci		pd_handles_sz = (ioc->facts.MaxDevHandle / 8);
879462306a36Sopenharmony_ci		if (ioc->facts.MaxDevHandle % 8)
879562306a36Sopenharmony_ci			pd_handles_sz++;
879662306a36Sopenharmony_ci
879762306a36Sopenharmony_ci		pd_handles = krealloc(ioc->pd_handles, pd_handles_sz,
879862306a36Sopenharmony_ci		    GFP_KERNEL);
879962306a36Sopenharmony_ci		if (!pd_handles) {
880062306a36Sopenharmony_ci			ioc_info(ioc,
880162306a36Sopenharmony_ci			    "Unable to allocate the memory for pd_handles of sz: %d\n",
880262306a36Sopenharmony_ci			    pd_handles_sz);
880362306a36Sopenharmony_ci			return -ENOMEM;
880462306a36Sopenharmony_ci		}
880562306a36Sopenharmony_ci		memset(pd_handles + ioc->pd_handles_sz, 0,
880662306a36Sopenharmony_ci		    (pd_handles_sz - ioc->pd_handles_sz));
880762306a36Sopenharmony_ci		ioc->pd_handles = pd_handles;
880862306a36Sopenharmony_ci
880962306a36Sopenharmony_ci		blocking_handles = krealloc(ioc->blocking_handles,
881062306a36Sopenharmony_ci		    pd_handles_sz, GFP_KERNEL);
881162306a36Sopenharmony_ci		if (!blocking_handles) {
881262306a36Sopenharmony_ci			ioc_info(ioc,
881362306a36Sopenharmony_ci			    "Unable to allocate the memory for "
881462306a36Sopenharmony_ci			    "blocking_handles of sz: %d\n",
881562306a36Sopenharmony_ci			    pd_handles_sz);
881662306a36Sopenharmony_ci			return -ENOMEM;
881762306a36Sopenharmony_ci		}
881862306a36Sopenharmony_ci		memset(blocking_handles + ioc->pd_handles_sz, 0,
881962306a36Sopenharmony_ci		    (pd_handles_sz - ioc->pd_handles_sz));
882062306a36Sopenharmony_ci		ioc->blocking_handles = blocking_handles;
882162306a36Sopenharmony_ci		ioc->pd_handles_sz = pd_handles_sz;
882262306a36Sopenharmony_ci
882362306a36Sopenharmony_ci		pend_os_device_add = krealloc(ioc->pend_os_device_add,
882462306a36Sopenharmony_ci		    pd_handles_sz, GFP_KERNEL);
882562306a36Sopenharmony_ci		if (!pend_os_device_add) {
882662306a36Sopenharmony_ci			ioc_info(ioc,
882762306a36Sopenharmony_ci			    "Unable to allocate the memory for pend_os_device_add of sz: %d\n",
882862306a36Sopenharmony_ci			    pd_handles_sz);
882962306a36Sopenharmony_ci			return -ENOMEM;
883062306a36Sopenharmony_ci		}
883162306a36Sopenharmony_ci		memset(pend_os_device_add + ioc->pend_os_device_add_sz, 0,
883262306a36Sopenharmony_ci		    (pd_handles_sz - ioc->pend_os_device_add_sz));
883362306a36Sopenharmony_ci		ioc->pend_os_device_add = pend_os_device_add;
883462306a36Sopenharmony_ci		ioc->pend_os_device_add_sz = pd_handles_sz;
883562306a36Sopenharmony_ci
883662306a36Sopenharmony_ci		device_remove_in_progress = krealloc(
883762306a36Sopenharmony_ci		    ioc->device_remove_in_progress, pd_handles_sz, GFP_KERNEL);
883862306a36Sopenharmony_ci		if (!device_remove_in_progress) {
883962306a36Sopenharmony_ci			ioc_info(ioc,
884062306a36Sopenharmony_ci			    "Unable to allocate the memory for "
884162306a36Sopenharmony_ci			    "device_remove_in_progress of sz: %d\n "
884262306a36Sopenharmony_ci			    , pd_handles_sz);
884362306a36Sopenharmony_ci			return -ENOMEM;
884462306a36Sopenharmony_ci		}
884562306a36Sopenharmony_ci		memset(device_remove_in_progress +
884662306a36Sopenharmony_ci		    ioc->device_remove_in_progress_sz, 0,
884762306a36Sopenharmony_ci		    (pd_handles_sz - ioc->device_remove_in_progress_sz));
884862306a36Sopenharmony_ci		ioc->device_remove_in_progress = device_remove_in_progress;
884962306a36Sopenharmony_ci		ioc->device_remove_in_progress_sz = pd_handles_sz;
885062306a36Sopenharmony_ci	}
885162306a36Sopenharmony_ci
885262306a36Sopenharmony_ci	memcpy(&ioc->prev_fw_facts, &ioc->facts, sizeof(struct mpt3sas_facts));
885362306a36Sopenharmony_ci	return 0;
885462306a36Sopenharmony_ci}
885562306a36Sopenharmony_ci
885662306a36Sopenharmony_ci/**
885762306a36Sopenharmony_ci * mpt3sas_base_hard_reset_handler - reset controller
885862306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure
885962306a36Sopenharmony_ci * @type: FORCE_BIG_HAMMER or SOFT_RESET
886062306a36Sopenharmony_ci *
886162306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure.
886262306a36Sopenharmony_ci */
886362306a36Sopenharmony_ciint
886462306a36Sopenharmony_cimpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc,
886562306a36Sopenharmony_ci	enum reset_type type)
886662306a36Sopenharmony_ci{
886762306a36Sopenharmony_ci	int r;
886862306a36Sopenharmony_ci	unsigned long flags;
886962306a36Sopenharmony_ci	u32 ioc_state;
887062306a36Sopenharmony_ci	u8 is_fault = 0, is_trigger = 0;
887162306a36Sopenharmony_ci
887262306a36Sopenharmony_ci	dtmprintk(ioc, ioc_info(ioc, "%s: enter\n", __func__));
887362306a36Sopenharmony_ci
887462306a36Sopenharmony_ci	if (ioc->pci_error_recovery) {
887562306a36Sopenharmony_ci		ioc_err(ioc, "%s: pci error recovery reset\n", __func__);
887662306a36Sopenharmony_ci		r = 0;
887762306a36Sopenharmony_ci		goto out_unlocked;
887862306a36Sopenharmony_ci	}
887962306a36Sopenharmony_ci
888062306a36Sopenharmony_ci	if (mpt3sas_fwfault_debug)
888162306a36Sopenharmony_ci		mpt3sas_halt_firmware(ioc);
888262306a36Sopenharmony_ci
888362306a36Sopenharmony_ci	/* wait for an active reset in progress to complete */
888462306a36Sopenharmony_ci	mutex_lock(&ioc->reset_in_progress_mutex);
888562306a36Sopenharmony_ci
888662306a36Sopenharmony_ci	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
888762306a36Sopenharmony_ci	ioc->shost_recovery = 1;
888862306a36Sopenharmony_ci	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
888962306a36Sopenharmony_ci
889062306a36Sopenharmony_ci	if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
889162306a36Sopenharmony_ci	    MPT3_DIAG_BUFFER_IS_REGISTERED) &&
889262306a36Sopenharmony_ci	    (!(ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
889362306a36Sopenharmony_ci	    MPT3_DIAG_BUFFER_IS_RELEASED))) {
889462306a36Sopenharmony_ci		is_trigger = 1;
889562306a36Sopenharmony_ci		ioc_state = mpt3sas_base_get_iocstate(ioc, 0);
889662306a36Sopenharmony_ci		if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT ||
889762306a36Sopenharmony_ci		    (ioc_state & MPI2_IOC_STATE_MASK) ==
889862306a36Sopenharmony_ci		    MPI2_IOC_STATE_COREDUMP) {
889962306a36Sopenharmony_ci			is_fault = 1;
890062306a36Sopenharmony_ci			ioc->htb_rel.trigger_info_dwords[1] =
890162306a36Sopenharmony_ci			    (ioc_state & MPI2_DOORBELL_DATA_MASK);
890262306a36Sopenharmony_ci		}
890362306a36Sopenharmony_ci	}
890462306a36Sopenharmony_ci	_base_pre_reset_handler(ioc);
890562306a36Sopenharmony_ci	mpt3sas_wait_for_commands_to_complete(ioc);
890662306a36Sopenharmony_ci	mpt3sas_base_mask_interrupts(ioc);
890762306a36Sopenharmony_ci	mpt3sas_base_pause_mq_polling(ioc);
890862306a36Sopenharmony_ci	r = mpt3sas_base_make_ioc_ready(ioc, type);
890962306a36Sopenharmony_ci	if (r)
891062306a36Sopenharmony_ci		goto out;
891162306a36Sopenharmony_ci	_base_clear_outstanding_commands(ioc);
891262306a36Sopenharmony_ci
891362306a36Sopenharmony_ci	/* If this hard reset is called while port enable is active, then
891462306a36Sopenharmony_ci	 * there is no reason to call make_ioc_operational
891562306a36Sopenharmony_ci	 */
891662306a36Sopenharmony_ci	if (ioc->is_driver_loading && ioc->port_enable_failed) {
891762306a36Sopenharmony_ci		ioc->remove_host = 1;
891862306a36Sopenharmony_ci		r = -EFAULT;
891962306a36Sopenharmony_ci		goto out;
892062306a36Sopenharmony_ci	}
892162306a36Sopenharmony_ci	r = _base_get_ioc_facts(ioc);
892262306a36Sopenharmony_ci	if (r)
892362306a36Sopenharmony_ci		goto out;
892462306a36Sopenharmony_ci
892562306a36Sopenharmony_ci	r = _base_check_ioc_facts_changes(ioc);
892662306a36Sopenharmony_ci	if (r) {
892762306a36Sopenharmony_ci		ioc_info(ioc,
892862306a36Sopenharmony_ci		    "Some of the parameters got changed in this new firmware"
892962306a36Sopenharmony_ci		    " image and it requires system reboot\n");
893062306a36Sopenharmony_ci		goto out;
893162306a36Sopenharmony_ci	}
893262306a36Sopenharmony_ci	if (ioc->rdpq_array_enable && !ioc->rdpq_array_capable)
893362306a36Sopenharmony_ci		panic("%s: Issue occurred with flashing controller firmware."
893462306a36Sopenharmony_ci		      "Please reboot the system and ensure that the correct"
893562306a36Sopenharmony_ci		      " firmware version is running\n", ioc->name);
893662306a36Sopenharmony_ci
893762306a36Sopenharmony_ci	r = _base_make_ioc_operational(ioc);
893862306a36Sopenharmony_ci	if (!r)
893962306a36Sopenharmony_ci		_base_reset_done_handler(ioc);
894062306a36Sopenharmony_ci
894162306a36Sopenharmony_ci out:
894262306a36Sopenharmony_ci	ioc_info(ioc, "%s: %s\n", __func__, r == 0 ? "SUCCESS" : "FAILED");
894362306a36Sopenharmony_ci
894462306a36Sopenharmony_ci	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
894562306a36Sopenharmony_ci	ioc->shost_recovery = 0;
894662306a36Sopenharmony_ci	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
894762306a36Sopenharmony_ci	ioc->ioc_reset_count++;
894862306a36Sopenharmony_ci	mutex_unlock(&ioc->reset_in_progress_mutex);
894962306a36Sopenharmony_ci	mpt3sas_base_resume_mq_polling(ioc);
895062306a36Sopenharmony_ci
895162306a36Sopenharmony_ci out_unlocked:
895262306a36Sopenharmony_ci	if ((r == 0) && is_trigger) {
895362306a36Sopenharmony_ci		if (is_fault)
895462306a36Sopenharmony_ci			mpt3sas_trigger_master(ioc, MASTER_TRIGGER_FW_FAULT);
895562306a36Sopenharmony_ci		else
895662306a36Sopenharmony_ci			mpt3sas_trigger_master(ioc,
895762306a36Sopenharmony_ci			    MASTER_TRIGGER_ADAPTER_RESET);
895862306a36Sopenharmony_ci	}
895962306a36Sopenharmony_ci	dtmprintk(ioc, ioc_info(ioc, "%s: exit\n", __func__));
896062306a36Sopenharmony_ci	return r;
896162306a36Sopenharmony_ci}
8962