xref: /linux/drivers/scsi/mpi3mr/mpi3mr_fw.c (revision a3d27dfdcfc27ac3f46de5391bb6d24f04af7941)
1824a1566SKashyap Desai // SPDX-License-Identifier: GPL-2.0-or-later
2824a1566SKashyap Desai /*
3824a1566SKashyap Desai  * Driver for Broadcom MPI3 Storage Controllers
4824a1566SKashyap Desai  *
521401408SSreekanth Reddy  * Copyright (C) 2017-2022 Broadcom Inc.
6824a1566SKashyap Desai  *  (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
7824a1566SKashyap Desai  *
8824a1566SKashyap Desai  */
9824a1566SKashyap Desai 
10824a1566SKashyap Desai #include "mpi3mr.h"
11824a1566SKashyap Desai #include <linux/io-64-nonatomic-lo-hi.h>
12824a1566SKashyap Desai 
1359bd9cfeSSreekanth Reddy static int
1459bd9cfeSSreekanth Reddy mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, u32 reset_reason);
1559bd9cfeSSreekanth Reddy static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc);
16c5758fc7SSreekanth Reddy static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc,
17c5758fc7SSreekanth Reddy 	struct mpi3_ioc_facts_data *facts_data);
1843ca1100SSumit Saxena static void mpi3mr_pel_wait_complete(struct mpi3mr_ioc *mrioc,
1943ca1100SSumit Saxena 	struct mpi3mr_drv_cmd *drv_cmd);
2059bd9cfeSSreekanth Reddy 
21afd3a579SSreekanth Reddy static int poll_queues;
22afd3a579SSreekanth Reddy module_param(poll_queues, int, 0444);
23afd3a579SSreekanth Reddy MODULE_PARM_DESC(poll_queues, "Number of queues for io_uring poll mode. (Range 1 - 126)");
24afd3a579SSreekanth Reddy 
25824a1566SKashyap Desai #if defined(writeq) && defined(CONFIG_64BIT)
26824a1566SKashyap Desai static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr)
27824a1566SKashyap Desai {
28824a1566SKashyap Desai 	writeq(b, addr);
29824a1566SKashyap Desai }
30824a1566SKashyap Desai #else
31824a1566SKashyap Desai static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr)
32824a1566SKashyap Desai {
33824a1566SKashyap Desai 	__u64 data_out = b;
34824a1566SKashyap Desai 
35824a1566SKashyap Desai 	writel((u32)(data_out), addr);
36824a1566SKashyap Desai 	writel((u32)(data_out >> 32), (addr + 4));
37824a1566SKashyap Desai }
38824a1566SKashyap Desai #endif
39824a1566SKashyap Desai 
40023ab2a9SKashyap Desai static inline bool
41023ab2a9SKashyap Desai mpi3mr_check_req_qfull(struct op_req_qinfo *op_req_q)
42023ab2a9SKashyap Desai {
43023ab2a9SKashyap Desai 	u16 pi, ci, max_entries;
44023ab2a9SKashyap Desai 	bool is_qfull = false;
45023ab2a9SKashyap Desai 
46023ab2a9SKashyap Desai 	pi = op_req_q->pi;
47023ab2a9SKashyap Desai 	ci = READ_ONCE(op_req_q->ci);
48023ab2a9SKashyap Desai 	max_entries = op_req_q->num_requests;
49023ab2a9SKashyap Desai 
50023ab2a9SKashyap Desai 	if ((ci == (pi + 1)) || ((!ci) && (pi == (max_entries - 1))))
51023ab2a9SKashyap Desai 		is_qfull = true;
52023ab2a9SKashyap Desai 
53023ab2a9SKashyap Desai 	return is_qfull;
54023ab2a9SKashyap Desai }
55023ab2a9SKashyap Desai 
56824a1566SKashyap Desai static void mpi3mr_sync_irqs(struct mpi3mr_ioc *mrioc)
57824a1566SKashyap Desai {
58824a1566SKashyap Desai 	u16 i, max_vectors;
59824a1566SKashyap Desai 
60824a1566SKashyap Desai 	max_vectors = mrioc->intr_info_count;
61824a1566SKashyap Desai 
62824a1566SKashyap Desai 	for (i = 0; i < max_vectors; i++)
63824a1566SKashyap Desai 		synchronize_irq(pci_irq_vector(mrioc->pdev, i));
64824a1566SKashyap Desai }
65824a1566SKashyap Desai 
66824a1566SKashyap Desai void mpi3mr_ioc_disable_intr(struct mpi3mr_ioc *mrioc)
67824a1566SKashyap Desai {
68824a1566SKashyap Desai 	mrioc->intr_enabled = 0;
69824a1566SKashyap Desai 	mpi3mr_sync_irqs(mrioc);
70824a1566SKashyap Desai }
71824a1566SKashyap Desai 
72824a1566SKashyap Desai void mpi3mr_ioc_enable_intr(struct mpi3mr_ioc *mrioc)
73824a1566SKashyap Desai {
74824a1566SKashyap Desai 	mrioc->intr_enabled = 1;
75824a1566SKashyap Desai }
76824a1566SKashyap Desai 
77824a1566SKashyap Desai static void mpi3mr_cleanup_isr(struct mpi3mr_ioc *mrioc)
78824a1566SKashyap Desai {
79824a1566SKashyap Desai 	u16 i;
80824a1566SKashyap Desai 
81824a1566SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
82824a1566SKashyap Desai 
83824a1566SKashyap Desai 	if (!mrioc->intr_info)
84824a1566SKashyap Desai 		return;
85824a1566SKashyap Desai 
86824a1566SKashyap Desai 	for (i = 0; i < mrioc->intr_info_count; i++)
87824a1566SKashyap Desai 		free_irq(pci_irq_vector(mrioc->pdev, i),
88824a1566SKashyap Desai 		    (mrioc->intr_info + i));
89824a1566SKashyap Desai 
90824a1566SKashyap Desai 	kfree(mrioc->intr_info);
91824a1566SKashyap Desai 	mrioc->intr_info = NULL;
92824a1566SKashyap Desai 	mrioc->intr_info_count = 0;
93fe6db615SSreekanth Reddy 	mrioc->is_intr_info_set = false;
94824a1566SKashyap Desai 	pci_free_irq_vectors(mrioc->pdev);
95824a1566SKashyap Desai }
96824a1566SKashyap Desai 
97824a1566SKashyap Desai void mpi3mr_add_sg_single(void *paddr, u8 flags, u32 length,
98824a1566SKashyap Desai 	dma_addr_t dma_addr)
99824a1566SKashyap Desai {
100824a1566SKashyap Desai 	struct mpi3_sge_common *sgel = paddr;
101824a1566SKashyap Desai 
102824a1566SKashyap Desai 	sgel->flags = flags;
103824a1566SKashyap Desai 	sgel->length = cpu_to_le32(length);
104824a1566SKashyap Desai 	sgel->address = cpu_to_le64(dma_addr);
105824a1566SKashyap Desai }
106824a1566SKashyap Desai 
107824a1566SKashyap Desai void mpi3mr_build_zero_len_sge(void *paddr)
108824a1566SKashyap Desai {
109824a1566SKashyap Desai 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
110824a1566SKashyap Desai 
111824a1566SKashyap Desai 	mpi3mr_add_sg_single(paddr, sgl_flags, 0, -1);
112824a1566SKashyap Desai }
113824a1566SKashyap Desai 
114824a1566SKashyap Desai void *mpi3mr_get_reply_virt_addr(struct mpi3mr_ioc *mrioc,
115824a1566SKashyap Desai 	dma_addr_t phys_addr)
116824a1566SKashyap Desai {
117824a1566SKashyap Desai 	if (!phys_addr)
118824a1566SKashyap Desai 		return NULL;
119824a1566SKashyap Desai 
120824a1566SKashyap Desai 	if ((phys_addr < mrioc->reply_buf_dma) ||
121824a1566SKashyap Desai 	    (phys_addr > mrioc->reply_buf_dma_max_address))
122824a1566SKashyap Desai 		return NULL;
123824a1566SKashyap Desai 
124824a1566SKashyap Desai 	return mrioc->reply_buf + (phys_addr - mrioc->reply_buf_dma);
125824a1566SKashyap Desai }
126824a1566SKashyap Desai 
127824a1566SKashyap Desai void *mpi3mr_get_sensebuf_virt_addr(struct mpi3mr_ioc *mrioc,
128824a1566SKashyap Desai 	dma_addr_t phys_addr)
129824a1566SKashyap Desai {
130824a1566SKashyap Desai 	if (!phys_addr)
131824a1566SKashyap Desai 		return NULL;
132824a1566SKashyap Desai 
133824a1566SKashyap Desai 	return mrioc->sense_buf + (phys_addr - mrioc->sense_buf_dma);
134824a1566SKashyap Desai }
135824a1566SKashyap Desai 
136824a1566SKashyap Desai static void mpi3mr_repost_reply_buf(struct mpi3mr_ioc *mrioc,
137824a1566SKashyap Desai 	u64 reply_dma)
138824a1566SKashyap Desai {
139824a1566SKashyap Desai 	u32 old_idx = 0;
140a83ec831SSreekanth Reddy 	unsigned long flags;
141824a1566SKashyap Desai 
142a83ec831SSreekanth Reddy 	spin_lock_irqsave(&mrioc->reply_free_queue_lock, flags);
143824a1566SKashyap Desai 	old_idx  =  mrioc->reply_free_queue_host_index;
144824a1566SKashyap Desai 	mrioc->reply_free_queue_host_index = (
145824a1566SKashyap Desai 	    (mrioc->reply_free_queue_host_index ==
146824a1566SKashyap Desai 	    (mrioc->reply_free_qsz - 1)) ? 0 :
147824a1566SKashyap Desai 	    (mrioc->reply_free_queue_host_index + 1));
148824a1566SKashyap Desai 	mrioc->reply_free_q[old_idx] = cpu_to_le64(reply_dma);
149824a1566SKashyap Desai 	writel(mrioc->reply_free_queue_host_index,
150824a1566SKashyap Desai 	    &mrioc->sysif_regs->reply_free_host_index);
151a83ec831SSreekanth Reddy 	spin_unlock_irqrestore(&mrioc->reply_free_queue_lock, flags);
152824a1566SKashyap Desai }
153824a1566SKashyap Desai 
154824a1566SKashyap Desai void mpi3mr_repost_sense_buf(struct mpi3mr_ioc *mrioc,
155824a1566SKashyap Desai 	u64 sense_buf_dma)
156824a1566SKashyap Desai {
157824a1566SKashyap Desai 	u32 old_idx = 0;
158a83ec831SSreekanth Reddy 	unsigned long flags;
159824a1566SKashyap Desai 
160a83ec831SSreekanth Reddy 	spin_lock_irqsave(&mrioc->sbq_lock, flags);
161824a1566SKashyap Desai 	old_idx  =  mrioc->sbq_host_index;
162824a1566SKashyap Desai 	mrioc->sbq_host_index = ((mrioc->sbq_host_index ==
163824a1566SKashyap Desai 	    (mrioc->sense_buf_q_sz - 1)) ? 0 :
164824a1566SKashyap Desai 	    (mrioc->sbq_host_index + 1));
165824a1566SKashyap Desai 	mrioc->sense_buf_q[old_idx] = cpu_to_le64(sense_buf_dma);
166824a1566SKashyap Desai 	writel(mrioc->sbq_host_index,
167824a1566SKashyap Desai 	    &mrioc->sysif_regs->sense_buffer_free_host_index);
168a83ec831SSreekanth Reddy 	spin_unlock_irqrestore(&mrioc->sbq_lock, flags);
169824a1566SKashyap Desai }
170824a1566SKashyap Desai 
1719fc4abfeSKashyap Desai static void mpi3mr_print_event_data(struct mpi3mr_ioc *mrioc,
1729fc4abfeSKashyap Desai 	struct mpi3_event_notification_reply *event_reply)
1739fc4abfeSKashyap Desai {
1749fc4abfeSKashyap Desai 	char *desc = NULL;
1759fc4abfeSKashyap Desai 	u16 event;
1769fc4abfeSKashyap Desai 
1779fc4abfeSKashyap Desai 	event = event_reply->event;
1789fc4abfeSKashyap Desai 
1799fc4abfeSKashyap Desai 	switch (event) {
1809fc4abfeSKashyap Desai 	case MPI3_EVENT_LOG_DATA:
1819fc4abfeSKashyap Desai 		desc = "Log Data";
1829fc4abfeSKashyap Desai 		break;
1839fc4abfeSKashyap Desai 	case MPI3_EVENT_CHANGE:
1849fc4abfeSKashyap Desai 		desc = "Event Change";
1859fc4abfeSKashyap Desai 		break;
1869fc4abfeSKashyap Desai 	case MPI3_EVENT_GPIO_INTERRUPT:
1879fc4abfeSKashyap Desai 		desc = "GPIO Interrupt";
1889fc4abfeSKashyap Desai 		break;
1899fc4abfeSKashyap Desai 	case MPI3_EVENT_CABLE_MGMT:
1909fc4abfeSKashyap Desai 		desc = "Cable Management";
1919fc4abfeSKashyap Desai 		break;
1929fc4abfeSKashyap Desai 	case MPI3_EVENT_ENERGY_PACK_CHANGE:
1939fc4abfeSKashyap Desai 		desc = "Energy Pack Change";
1949fc4abfeSKashyap Desai 		break;
1959fc4abfeSKashyap Desai 	case MPI3_EVENT_DEVICE_ADDED:
1969fc4abfeSKashyap Desai 	{
1979fc4abfeSKashyap Desai 		struct mpi3_device_page0 *event_data =
1989fc4abfeSKashyap Desai 		    (struct mpi3_device_page0 *)event_reply->event_data;
1999fc4abfeSKashyap Desai 		ioc_info(mrioc, "Device Added: dev=0x%04x Form=0x%x\n",
2009fc4abfeSKashyap Desai 		    event_data->dev_handle, event_data->device_form);
2019fc4abfeSKashyap Desai 		return;
2029fc4abfeSKashyap Desai 	}
2039fc4abfeSKashyap Desai 	case MPI3_EVENT_DEVICE_INFO_CHANGED:
2049fc4abfeSKashyap Desai 	{
2059fc4abfeSKashyap Desai 		struct mpi3_device_page0 *event_data =
2069fc4abfeSKashyap Desai 		    (struct mpi3_device_page0 *)event_reply->event_data;
2079fc4abfeSKashyap Desai 		ioc_info(mrioc, "Device Info Changed: dev=0x%04x Form=0x%x\n",
2089fc4abfeSKashyap Desai 		    event_data->dev_handle, event_data->device_form);
2099fc4abfeSKashyap Desai 		return;
2109fc4abfeSKashyap Desai 	}
2119fc4abfeSKashyap Desai 	case MPI3_EVENT_DEVICE_STATUS_CHANGE:
2129fc4abfeSKashyap Desai 	{
2139fc4abfeSKashyap Desai 		struct mpi3_event_data_device_status_change *event_data =
2149fc4abfeSKashyap Desai 		    (struct mpi3_event_data_device_status_change *)event_reply->event_data;
2159fc4abfeSKashyap Desai 		ioc_info(mrioc, "Device status Change: dev=0x%04x RC=0x%x\n",
2169fc4abfeSKashyap Desai 		    event_data->dev_handle, event_data->reason_code);
2179fc4abfeSKashyap Desai 		return;
2189fc4abfeSKashyap Desai 	}
2199fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_DISCOVERY:
2209fc4abfeSKashyap Desai 	{
2219fc4abfeSKashyap Desai 		struct mpi3_event_data_sas_discovery *event_data =
2229fc4abfeSKashyap Desai 		    (struct mpi3_event_data_sas_discovery *)event_reply->event_data;
2239fc4abfeSKashyap Desai 		ioc_info(mrioc, "SAS Discovery: (%s) status (0x%08x)\n",
2249fc4abfeSKashyap Desai 		    (event_data->reason_code == MPI3_EVENT_SAS_DISC_RC_STARTED) ?
2259fc4abfeSKashyap Desai 		    "start" : "stop",
2269fc4abfeSKashyap Desai 		    le32_to_cpu(event_data->discovery_status));
2279fc4abfeSKashyap Desai 		return;
2289fc4abfeSKashyap Desai 	}
2299fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE:
2309fc4abfeSKashyap Desai 		desc = "SAS Broadcast Primitive";
2319fc4abfeSKashyap Desai 		break;
2329fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_NOTIFY_PRIMITIVE:
2339fc4abfeSKashyap Desai 		desc = "SAS Notify Primitive";
2349fc4abfeSKashyap Desai 		break;
2359fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
2369fc4abfeSKashyap Desai 		desc = "SAS Init Device Status Change";
2379fc4abfeSKashyap Desai 		break;
2389fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_INIT_TABLE_OVERFLOW:
2399fc4abfeSKashyap Desai 		desc = "SAS Init Table Overflow";
2409fc4abfeSKashyap Desai 		break;
2419fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
2429fc4abfeSKashyap Desai 		desc = "SAS Topology Change List";
2439fc4abfeSKashyap Desai 		break;
2449fc4abfeSKashyap Desai 	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
2459fc4abfeSKashyap Desai 		desc = "Enclosure Device Status Change";
2469fc4abfeSKashyap Desai 		break;
2477188c03fSSreekanth Reddy 	case MPI3_EVENT_ENCL_DEVICE_ADDED:
2487188c03fSSreekanth Reddy 		desc = "Enclosure Added";
2497188c03fSSreekanth Reddy 		break;
2509fc4abfeSKashyap Desai 	case MPI3_EVENT_HARD_RESET_RECEIVED:
2519fc4abfeSKashyap Desai 		desc = "Hard Reset Received";
2529fc4abfeSKashyap Desai 		break;
2539fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_PHY_COUNTER:
2549fc4abfeSKashyap Desai 		desc = "SAS PHY Counter";
2559fc4abfeSKashyap Desai 		break;
2569fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR:
2579fc4abfeSKashyap Desai 		desc = "SAS Device Discovery Error";
2589fc4abfeSKashyap Desai 		break;
2599fc4abfeSKashyap Desai 	case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
2609fc4abfeSKashyap Desai 		desc = "PCIE Topology Change List";
2619fc4abfeSKashyap Desai 		break;
2629fc4abfeSKashyap Desai 	case MPI3_EVENT_PCIE_ENUMERATION:
2639fc4abfeSKashyap Desai 	{
2649fc4abfeSKashyap Desai 		struct mpi3_event_data_pcie_enumeration *event_data =
2659fc4abfeSKashyap Desai 		    (struct mpi3_event_data_pcie_enumeration *)event_reply->event_data;
2669fc4abfeSKashyap Desai 		ioc_info(mrioc, "PCIE Enumeration: (%s)",
2679fc4abfeSKashyap Desai 		    (event_data->reason_code ==
2689fc4abfeSKashyap Desai 		    MPI3_EVENT_PCIE_ENUM_RC_STARTED) ? "start" : "stop");
2699fc4abfeSKashyap Desai 		if (event_data->enumeration_status)
2709fc4abfeSKashyap Desai 			ioc_info(mrioc, "enumeration_status(0x%08x)\n",
2719fc4abfeSKashyap Desai 			    le32_to_cpu(event_data->enumeration_status));
2729fc4abfeSKashyap Desai 		return;
2739fc4abfeSKashyap Desai 	}
2749fc4abfeSKashyap Desai 	case MPI3_EVENT_PREPARE_FOR_RESET:
2759fc4abfeSKashyap Desai 		desc = "Prepare For Reset";
2769fc4abfeSKashyap Desai 		break;
2779fc4abfeSKashyap Desai 	}
2789fc4abfeSKashyap Desai 
2799fc4abfeSKashyap Desai 	if (!desc)
2809fc4abfeSKashyap Desai 		return;
2819fc4abfeSKashyap Desai 
2829fc4abfeSKashyap Desai 	ioc_info(mrioc, "%s\n", desc);
2839fc4abfeSKashyap Desai }
2849fc4abfeSKashyap Desai 
285824a1566SKashyap Desai static void mpi3mr_handle_events(struct mpi3mr_ioc *mrioc,
286824a1566SKashyap Desai 	struct mpi3_default_reply *def_reply)
287824a1566SKashyap Desai {
288824a1566SKashyap Desai 	struct mpi3_event_notification_reply *event_reply =
289824a1566SKashyap Desai 	    (struct mpi3_event_notification_reply *)def_reply;
290824a1566SKashyap Desai 
291824a1566SKashyap Desai 	mrioc->change_count = le16_to_cpu(event_reply->ioc_change_count);
2929fc4abfeSKashyap Desai 	mpi3mr_print_event_data(mrioc, event_reply);
29313ef29eaSKashyap Desai 	mpi3mr_os_handle_events(mrioc, event_reply);
294824a1566SKashyap Desai }
295824a1566SKashyap Desai 
296824a1566SKashyap Desai static struct mpi3mr_drv_cmd *
297824a1566SKashyap Desai mpi3mr_get_drv_cmd(struct mpi3mr_ioc *mrioc, u16 host_tag,
298824a1566SKashyap Desai 	struct mpi3_default_reply *def_reply)
299824a1566SKashyap Desai {
30013ef29eaSKashyap Desai 	u16 idx;
30113ef29eaSKashyap Desai 
302824a1566SKashyap Desai 	switch (host_tag) {
303824a1566SKashyap Desai 	case MPI3MR_HOSTTAG_INITCMDS:
304824a1566SKashyap Desai 		return &mrioc->init_cmds;
30532d457d5SSreekanth Reddy 	case MPI3MR_HOSTTAG_CFG_CMDS:
30632d457d5SSreekanth Reddy 		return &mrioc->cfg_cmds;
307f5e6d5a3SSumit Saxena 	case MPI3MR_HOSTTAG_BSG_CMDS:
308f5e6d5a3SSumit Saxena 		return &mrioc->bsg_cmds;
309e844adb1SKashyap Desai 	case MPI3MR_HOSTTAG_BLK_TMS:
310e844adb1SKashyap Desai 		return &mrioc->host_tm_cmds;
31143ca1100SSumit Saxena 	case MPI3MR_HOSTTAG_PEL_ABORT:
31243ca1100SSumit Saxena 		return &mrioc->pel_abort_cmd;
31343ca1100SSumit Saxena 	case MPI3MR_HOSTTAG_PEL_WAIT:
31443ca1100SSumit Saxena 		return &mrioc->pel_cmds;
3152bd37e28SSreekanth Reddy 	case MPI3MR_HOSTTAG_TRANSPORT_CMDS:
3162bd37e28SSreekanth Reddy 		return &mrioc->transport_cmds;
317824a1566SKashyap Desai 	case MPI3MR_HOSTTAG_INVALID:
318824a1566SKashyap Desai 		if (def_reply && def_reply->function ==
319824a1566SKashyap Desai 		    MPI3_FUNCTION_EVENT_NOTIFICATION)
320824a1566SKashyap Desai 			mpi3mr_handle_events(mrioc, def_reply);
321824a1566SKashyap Desai 		return NULL;
322824a1566SKashyap Desai 	default:
323824a1566SKashyap Desai 		break;
324824a1566SKashyap Desai 	}
32513ef29eaSKashyap Desai 	if (host_tag >= MPI3MR_HOSTTAG_DEVRMCMD_MIN &&
32613ef29eaSKashyap Desai 	    host_tag <= MPI3MR_HOSTTAG_DEVRMCMD_MAX) {
32713ef29eaSKashyap Desai 		idx = host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
32813ef29eaSKashyap Desai 		return &mrioc->dev_rmhs_cmds[idx];
32913ef29eaSKashyap Desai 	}
330824a1566SKashyap Desai 
331c1af985dSSreekanth Reddy 	if (host_tag >= MPI3MR_HOSTTAG_EVTACKCMD_MIN &&
332c1af985dSSreekanth Reddy 	    host_tag <= MPI3MR_HOSTTAG_EVTACKCMD_MAX) {
333c1af985dSSreekanth Reddy 		idx = host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN;
334c1af985dSSreekanth Reddy 		return &mrioc->evtack_cmds[idx];
335c1af985dSSreekanth Reddy 	}
336c1af985dSSreekanth Reddy 
337824a1566SKashyap Desai 	return NULL;
338824a1566SKashyap Desai }
339824a1566SKashyap Desai 
340824a1566SKashyap Desai static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc,
341824a1566SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc, u64 *reply_dma)
342824a1566SKashyap Desai {
343824a1566SKashyap Desai 	u16 reply_desc_type, host_tag = 0;
344824a1566SKashyap Desai 	u16 ioc_status = MPI3_IOCSTATUS_SUCCESS;
345824a1566SKashyap Desai 	u32 ioc_loginfo = 0;
346824a1566SKashyap Desai 	struct mpi3_status_reply_descriptor *status_desc;
347824a1566SKashyap Desai 	struct mpi3_address_reply_descriptor *addr_desc;
348824a1566SKashyap Desai 	struct mpi3_success_reply_descriptor *success_desc;
349824a1566SKashyap Desai 	struct mpi3_default_reply *def_reply = NULL;
350824a1566SKashyap Desai 	struct mpi3mr_drv_cmd *cmdptr = NULL;
351824a1566SKashyap Desai 	struct mpi3_scsi_io_reply *scsi_reply;
352824a1566SKashyap Desai 	u8 *sense_buf = NULL;
353824a1566SKashyap Desai 
354824a1566SKashyap Desai 	*reply_dma = 0;
355824a1566SKashyap Desai 	reply_desc_type = le16_to_cpu(reply_desc->reply_flags) &
356824a1566SKashyap Desai 	    MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK;
357824a1566SKashyap Desai 	switch (reply_desc_type) {
358824a1566SKashyap Desai 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS:
359824a1566SKashyap Desai 		status_desc = (struct mpi3_status_reply_descriptor *)reply_desc;
360824a1566SKashyap Desai 		host_tag = le16_to_cpu(status_desc->host_tag);
361824a1566SKashyap Desai 		ioc_status = le16_to_cpu(status_desc->ioc_status);
362824a1566SKashyap Desai 		if (ioc_status &
363824a1566SKashyap Desai 		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
364824a1566SKashyap Desai 			ioc_loginfo = le32_to_cpu(status_desc->ioc_log_info);
365824a1566SKashyap Desai 		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
366824a1566SKashyap Desai 		break;
367824a1566SKashyap Desai 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY:
368824a1566SKashyap Desai 		addr_desc = (struct mpi3_address_reply_descriptor *)reply_desc;
369824a1566SKashyap Desai 		*reply_dma = le64_to_cpu(addr_desc->reply_frame_address);
370824a1566SKashyap Desai 		def_reply = mpi3mr_get_reply_virt_addr(mrioc, *reply_dma);
371824a1566SKashyap Desai 		if (!def_reply)
372824a1566SKashyap Desai 			goto out;
373824a1566SKashyap Desai 		host_tag = le16_to_cpu(def_reply->host_tag);
374824a1566SKashyap Desai 		ioc_status = le16_to_cpu(def_reply->ioc_status);
375824a1566SKashyap Desai 		if (ioc_status &
376824a1566SKashyap Desai 		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
377824a1566SKashyap Desai 			ioc_loginfo = le32_to_cpu(def_reply->ioc_log_info);
378824a1566SKashyap Desai 		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
379824a1566SKashyap Desai 		if (def_reply->function == MPI3_FUNCTION_SCSI_IO) {
380824a1566SKashyap Desai 			scsi_reply = (struct mpi3_scsi_io_reply *)def_reply;
381824a1566SKashyap Desai 			sense_buf = mpi3mr_get_sensebuf_virt_addr(mrioc,
382824a1566SKashyap Desai 			    le64_to_cpu(scsi_reply->sense_data_buffer_address));
383824a1566SKashyap Desai 		}
384824a1566SKashyap Desai 		break;
385824a1566SKashyap Desai 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS:
386824a1566SKashyap Desai 		success_desc = (struct mpi3_success_reply_descriptor *)reply_desc;
387824a1566SKashyap Desai 		host_tag = le16_to_cpu(success_desc->host_tag);
388824a1566SKashyap Desai 		break;
389824a1566SKashyap Desai 	default:
390824a1566SKashyap Desai 		break;
391824a1566SKashyap Desai 	}
392824a1566SKashyap Desai 
393824a1566SKashyap Desai 	cmdptr = mpi3mr_get_drv_cmd(mrioc, host_tag, def_reply);
394824a1566SKashyap Desai 	if (cmdptr) {
395824a1566SKashyap Desai 		if (cmdptr->state & MPI3MR_CMD_PENDING) {
396824a1566SKashyap Desai 			cmdptr->state |= MPI3MR_CMD_COMPLETE;
397824a1566SKashyap Desai 			cmdptr->ioc_loginfo = ioc_loginfo;
398824a1566SKashyap Desai 			cmdptr->ioc_status = ioc_status;
399824a1566SKashyap Desai 			cmdptr->state &= ~MPI3MR_CMD_PENDING;
400824a1566SKashyap Desai 			if (def_reply) {
401824a1566SKashyap Desai 				cmdptr->state |= MPI3MR_CMD_REPLY_VALID;
402824a1566SKashyap Desai 				memcpy((u8 *)cmdptr->reply, (u8 *)def_reply,
403c5758fc7SSreekanth Reddy 				    mrioc->reply_sz);
404824a1566SKashyap Desai 			}
405824a1566SKashyap Desai 			if (cmdptr->is_waiting) {
406824a1566SKashyap Desai 				complete(&cmdptr->done);
407824a1566SKashyap Desai 				cmdptr->is_waiting = 0;
408824a1566SKashyap Desai 			} else if (cmdptr->callback)
409824a1566SKashyap Desai 				cmdptr->callback(mrioc, cmdptr);
410824a1566SKashyap Desai 		}
411824a1566SKashyap Desai 	}
412824a1566SKashyap Desai out:
413824a1566SKashyap Desai 	if (sense_buf)
414824a1566SKashyap Desai 		mpi3mr_repost_sense_buf(mrioc,
415824a1566SKashyap Desai 		    le64_to_cpu(scsi_reply->sense_data_buffer_address));
416824a1566SKashyap Desai }
417824a1566SKashyap Desai 
41802ca7da2SRanjan Kumar int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc)
419824a1566SKashyap Desai {
420824a1566SKashyap Desai 	u32 exp_phase = mrioc->admin_reply_ephase;
421824a1566SKashyap Desai 	u32 admin_reply_ci = mrioc->admin_reply_ci;
422824a1566SKashyap Desai 	u32 num_admin_replies = 0;
423824a1566SKashyap Desai 	u64 reply_dma = 0;
424824a1566SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc;
425824a1566SKashyap Desai 
42602ca7da2SRanjan Kumar 	if (!atomic_add_unless(&mrioc->admin_reply_q_in_use, 1, 1))
42702ca7da2SRanjan Kumar 		return 0;
42802ca7da2SRanjan Kumar 
429824a1566SKashyap Desai 	reply_desc = (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base +
430824a1566SKashyap Desai 	    admin_reply_ci;
431824a1566SKashyap Desai 
432824a1566SKashyap Desai 	if ((le16_to_cpu(reply_desc->reply_flags) &
43302ca7da2SRanjan Kumar 	    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) {
43402ca7da2SRanjan Kumar 		atomic_dec(&mrioc->admin_reply_q_in_use);
435824a1566SKashyap Desai 		return 0;
43602ca7da2SRanjan Kumar 	}
437824a1566SKashyap Desai 
438824a1566SKashyap Desai 	do {
439f2a79d20SSreekanth Reddy 		if (mrioc->unrecoverable)
440f2a79d20SSreekanth Reddy 			break;
441f2a79d20SSreekanth Reddy 
442824a1566SKashyap Desai 		mrioc->admin_req_ci = le16_to_cpu(reply_desc->request_queue_ci);
443824a1566SKashyap Desai 		mpi3mr_process_admin_reply_desc(mrioc, reply_desc, &reply_dma);
444824a1566SKashyap Desai 		if (reply_dma)
445824a1566SKashyap Desai 			mpi3mr_repost_reply_buf(mrioc, reply_dma);
446824a1566SKashyap Desai 		num_admin_replies++;
447824a1566SKashyap Desai 		if (++admin_reply_ci == mrioc->num_admin_replies) {
448824a1566SKashyap Desai 			admin_reply_ci = 0;
449824a1566SKashyap Desai 			exp_phase ^= 1;
450824a1566SKashyap Desai 		}
451824a1566SKashyap Desai 		reply_desc =
452824a1566SKashyap Desai 		    (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base +
453824a1566SKashyap Desai 		    admin_reply_ci;
454824a1566SKashyap Desai 		if ((le16_to_cpu(reply_desc->reply_flags) &
455824a1566SKashyap Desai 		    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
456824a1566SKashyap Desai 			break;
457824a1566SKashyap Desai 	} while (1);
458824a1566SKashyap Desai 
459824a1566SKashyap Desai 	writel(admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci);
460824a1566SKashyap Desai 	mrioc->admin_reply_ci = admin_reply_ci;
461824a1566SKashyap Desai 	mrioc->admin_reply_ephase = exp_phase;
46202ca7da2SRanjan Kumar 	atomic_dec(&mrioc->admin_reply_q_in_use);
463824a1566SKashyap Desai 
464824a1566SKashyap Desai 	return num_admin_replies;
465824a1566SKashyap Desai }
466824a1566SKashyap Desai 
467023ab2a9SKashyap Desai /**
468023ab2a9SKashyap Desai  * mpi3mr_get_reply_desc - get reply descriptor frame corresponding to
469023ab2a9SKashyap Desai  *	queue's consumer index from operational reply descriptor queue.
470023ab2a9SKashyap Desai  * @op_reply_q: op_reply_qinfo object
471023ab2a9SKashyap Desai  * @reply_ci: operational reply descriptor's queue consumer index
472023ab2a9SKashyap Desai  *
473023ab2a9SKashyap Desai  * Returns reply descriptor frame address
474023ab2a9SKashyap Desai  */
475023ab2a9SKashyap Desai static inline struct mpi3_default_reply_descriptor *
476023ab2a9SKashyap Desai mpi3mr_get_reply_desc(struct op_reply_qinfo *op_reply_q, u32 reply_ci)
477023ab2a9SKashyap Desai {
478023ab2a9SKashyap Desai 	void *segment_base_addr;
479023ab2a9SKashyap Desai 	struct segments *segments = op_reply_q->q_segments;
480023ab2a9SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc = NULL;
481023ab2a9SKashyap Desai 
482023ab2a9SKashyap Desai 	segment_base_addr =
483023ab2a9SKashyap Desai 	    segments[reply_ci / op_reply_q->segment_qd].segment;
484023ab2a9SKashyap Desai 	reply_desc = (struct mpi3_default_reply_descriptor *)segment_base_addr +
485023ab2a9SKashyap Desai 	    (reply_ci % op_reply_q->segment_qd);
486023ab2a9SKashyap Desai 	return reply_desc;
487023ab2a9SKashyap Desai }
488023ab2a9SKashyap Desai 
489afd3a579SSreekanth Reddy /**
490afd3a579SSreekanth Reddy  * mpi3mr_process_op_reply_q - Operational reply queue handler
491afd3a579SSreekanth Reddy  * @mrioc: Adapter instance reference
492afd3a579SSreekanth Reddy  * @op_reply_q: Operational reply queue info
493afd3a579SSreekanth Reddy  *
494afd3a579SSreekanth Reddy  * Checks the specific operational reply queue and drains the
495afd3a579SSreekanth Reddy  * reply queue entries until the queue is empty and process the
496afd3a579SSreekanth Reddy  * individual reply descriptors.
497afd3a579SSreekanth Reddy  *
498afd3a579SSreekanth Reddy  * Return: 0 if queue is already processed,or number of reply
499afd3a579SSreekanth Reddy  *	    descriptors processed.
500afd3a579SSreekanth Reddy  */
501afd3a579SSreekanth Reddy int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc,
502afd3a579SSreekanth Reddy 	struct op_reply_qinfo *op_reply_q)
503023ab2a9SKashyap Desai {
504023ab2a9SKashyap Desai 	struct op_req_qinfo *op_req_q;
505023ab2a9SKashyap Desai 	u32 exp_phase;
506023ab2a9SKashyap Desai 	u32 reply_ci;
507023ab2a9SKashyap Desai 	u32 num_op_reply = 0;
508023ab2a9SKashyap Desai 	u64 reply_dma = 0;
509023ab2a9SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc;
510023ab2a9SKashyap Desai 	u16 req_q_idx = 0, reply_qidx;
511023ab2a9SKashyap Desai 
512023ab2a9SKashyap Desai 	reply_qidx = op_reply_q->qid - 1;
513023ab2a9SKashyap Desai 
514463429f8SKashyap Desai 	if (!atomic_add_unless(&op_reply_q->in_use, 1, 1))
515463429f8SKashyap Desai 		return 0;
516463429f8SKashyap Desai 
517023ab2a9SKashyap Desai 	exp_phase = op_reply_q->ephase;
518023ab2a9SKashyap Desai 	reply_ci = op_reply_q->ci;
519023ab2a9SKashyap Desai 
520023ab2a9SKashyap Desai 	reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci);
521023ab2a9SKashyap Desai 	if ((le16_to_cpu(reply_desc->reply_flags) &
522023ab2a9SKashyap Desai 	    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) {
523463429f8SKashyap Desai 		atomic_dec(&op_reply_q->in_use);
524023ab2a9SKashyap Desai 		return 0;
525023ab2a9SKashyap Desai 	}
526023ab2a9SKashyap Desai 
527023ab2a9SKashyap Desai 	do {
528f2a79d20SSreekanth Reddy 		if (mrioc->unrecoverable)
529f2a79d20SSreekanth Reddy 			break;
530f2a79d20SSreekanth Reddy 
531023ab2a9SKashyap Desai 		req_q_idx = le16_to_cpu(reply_desc->request_queue_id) - 1;
532023ab2a9SKashyap Desai 		op_req_q = &mrioc->req_qinfo[req_q_idx];
533023ab2a9SKashyap Desai 
534023ab2a9SKashyap Desai 		WRITE_ONCE(op_req_q->ci, le16_to_cpu(reply_desc->request_queue_ci));
535023ab2a9SKashyap Desai 		mpi3mr_process_op_reply_desc(mrioc, reply_desc, &reply_dma,
536023ab2a9SKashyap Desai 		    reply_qidx);
537463429f8SKashyap Desai 		atomic_dec(&op_reply_q->pend_ios);
538023ab2a9SKashyap Desai 		if (reply_dma)
539023ab2a9SKashyap Desai 			mpi3mr_repost_reply_buf(mrioc, reply_dma);
540023ab2a9SKashyap Desai 		num_op_reply++;
541023ab2a9SKashyap Desai 
542023ab2a9SKashyap Desai 		if (++reply_ci == op_reply_q->num_replies) {
543023ab2a9SKashyap Desai 			reply_ci = 0;
544023ab2a9SKashyap Desai 			exp_phase ^= 1;
545023ab2a9SKashyap Desai 		}
546023ab2a9SKashyap Desai 
547023ab2a9SKashyap Desai 		reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci);
548023ab2a9SKashyap Desai 
549023ab2a9SKashyap Desai 		if ((le16_to_cpu(reply_desc->reply_flags) &
550023ab2a9SKashyap Desai 		    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
551023ab2a9SKashyap Desai 			break;
5527f9f953dSSreekanth Reddy #ifndef CONFIG_PREEMPT_RT
553463429f8SKashyap Desai 		/*
554463429f8SKashyap Desai 		 * Exit completion loop to avoid CPU lockup
555463429f8SKashyap Desai 		 * Ensure remaining completion happens from threaded ISR.
556463429f8SKashyap Desai 		 */
557463429f8SKashyap Desai 		if (num_op_reply > mrioc->max_host_ios) {
558afd3a579SSreekanth Reddy 			op_reply_q->enable_irq_poll = true;
559463429f8SKashyap Desai 			break;
560463429f8SKashyap Desai 		}
5617f9f953dSSreekanth Reddy #endif
562023ab2a9SKashyap Desai 	} while (1);
563023ab2a9SKashyap Desai 
564023ab2a9SKashyap Desai 	writel(reply_ci,
565023ab2a9SKashyap Desai 	    &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].consumer_index);
566023ab2a9SKashyap Desai 	op_reply_q->ci = reply_ci;
567023ab2a9SKashyap Desai 	op_reply_q->ephase = exp_phase;
568023ab2a9SKashyap Desai 
569463429f8SKashyap Desai 	atomic_dec(&op_reply_q->in_use);
570023ab2a9SKashyap Desai 	return num_op_reply;
571023ab2a9SKashyap Desai }
572023ab2a9SKashyap Desai 
573afd3a579SSreekanth Reddy /**
574afd3a579SSreekanth Reddy  * mpi3mr_blk_mq_poll - Operational reply queue handler
575afd3a579SSreekanth Reddy  * @shost: SCSI Host reference
576afd3a579SSreekanth Reddy  * @queue_num: Request queue number (w.r.t OS it is hardware context number)
577afd3a579SSreekanth Reddy  *
578afd3a579SSreekanth Reddy  * Checks the specific operational reply queue and drains the
579afd3a579SSreekanth Reddy  * reply queue entries until the queue is empty and process the
580afd3a579SSreekanth Reddy  * individual reply descriptors.
581afd3a579SSreekanth Reddy  *
582afd3a579SSreekanth Reddy  * Return: 0 if queue is already processed,or number of reply
583afd3a579SSreekanth Reddy  *	    descriptors processed.
584afd3a579SSreekanth Reddy  */
585afd3a579SSreekanth Reddy int mpi3mr_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
586afd3a579SSreekanth Reddy {
587afd3a579SSreekanth Reddy 	int num_entries = 0;
588afd3a579SSreekanth Reddy 	struct mpi3mr_ioc *mrioc;
589afd3a579SSreekanth Reddy 
590afd3a579SSreekanth Reddy 	mrioc = (struct mpi3mr_ioc *)shost->hostdata;
591afd3a579SSreekanth Reddy 
592f2a79d20SSreekanth Reddy 	if ((mrioc->reset_in_progress || mrioc->prepare_for_reset ||
593f2a79d20SSreekanth Reddy 	    mrioc->unrecoverable))
594afd3a579SSreekanth Reddy 		return 0;
595afd3a579SSreekanth Reddy 
596afd3a579SSreekanth Reddy 	num_entries = mpi3mr_process_op_reply_q(mrioc,
597afd3a579SSreekanth Reddy 			&mrioc->op_reply_qinfo[queue_num]);
598afd3a579SSreekanth Reddy 
599afd3a579SSreekanth Reddy 	return num_entries;
600afd3a579SSreekanth Reddy }
601afd3a579SSreekanth Reddy 
602824a1566SKashyap Desai static irqreturn_t mpi3mr_isr_primary(int irq, void *privdata)
603824a1566SKashyap Desai {
604824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info = privdata;
605824a1566SKashyap Desai 	struct mpi3mr_ioc *mrioc;
606824a1566SKashyap Desai 	u16 midx;
607463429f8SKashyap Desai 	u32 num_admin_replies = 0, num_op_reply = 0;
608824a1566SKashyap Desai 
609824a1566SKashyap Desai 	if (!intr_info)
610824a1566SKashyap Desai 		return IRQ_NONE;
611824a1566SKashyap Desai 
612824a1566SKashyap Desai 	mrioc = intr_info->mrioc;
613824a1566SKashyap Desai 
614824a1566SKashyap Desai 	if (!mrioc->intr_enabled)
615824a1566SKashyap Desai 		return IRQ_NONE;
616824a1566SKashyap Desai 
617824a1566SKashyap Desai 	midx = intr_info->msix_index;
618824a1566SKashyap Desai 
619824a1566SKashyap Desai 	if (!midx)
620824a1566SKashyap Desai 		num_admin_replies = mpi3mr_process_admin_reply_q(mrioc);
621463429f8SKashyap Desai 	if (intr_info->op_reply_q)
622afd3a579SSreekanth Reddy 		num_op_reply = mpi3mr_process_op_reply_q(mrioc,
623afd3a579SSreekanth Reddy 		    intr_info->op_reply_q);
624824a1566SKashyap Desai 
625463429f8SKashyap Desai 	if (num_admin_replies || num_op_reply)
626824a1566SKashyap Desai 		return IRQ_HANDLED;
627824a1566SKashyap Desai 	else
628824a1566SKashyap Desai 		return IRQ_NONE;
629824a1566SKashyap Desai }
630824a1566SKashyap Desai 
6317f9f953dSSreekanth Reddy #ifndef CONFIG_PREEMPT_RT
6327f9f953dSSreekanth Reddy 
633824a1566SKashyap Desai static irqreturn_t mpi3mr_isr(int irq, void *privdata)
634824a1566SKashyap Desai {
635824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info = privdata;
636824a1566SKashyap Desai 	int ret;
637824a1566SKashyap Desai 
638824a1566SKashyap Desai 	if (!intr_info)
639824a1566SKashyap Desai 		return IRQ_NONE;
640824a1566SKashyap Desai 
641824a1566SKashyap Desai 	/* Call primary ISR routine */
642824a1566SKashyap Desai 	ret = mpi3mr_isr_primary(irq, privdata);
643824a1566SKashyap Desai 
644463429f8SKashyap Desai 	/*
645463429f8SKashyap Desai 	 * If more IOs are expected, schedule IRQ polling thread.
646463429f8SKashyap Desai 	 * Otherwise exit from ISR.
647463429f8SKashyap Desai 	 */
648463429f8SKashyap Desai 	if (!intr_info->op_reply_q)
649824a1566SKashyap Desai 		return ret;
650463429f8SKashyap Desai 
651463429f8SKashyap Desai 	if (!intr_info->op_reply_q->enable_irq_poll ||
652463429f8SKashyap Desai 	    !atomic_read(&intr_info->op_reply_q->pend_ios))
653463429f8SKashyap Desai 		return ret;
654463429f8SKashyap Desai 
6552e31be86SSreekanth Reddy 	disable_irq_nosync(intr_info->os_irq);
656463429f8SKashyap Desai 
657463429f8SKashyap Desai 	return IRQ_WAKE_THREAD;
658824a1566SKashyap Desai }
659824a1566SKashyap Desai 
660824a1566SKashyap Desai /**
661824a1566SKashyap Desai  * mpi3mr_isr_poll - Reply queue polling routine
662824a1566SKashyap Desai  * @irq: IRQ
663824a1566SKashyap Desai  * @privdata: Interrupt info
664824a1566SKashyap Desai  *
665824a1566SKashyap Desai  * poll for pending I/O completions in a loop until pending I/Os
666824a1566SKashyap Desai  * present or controller queue depth I/Os are processed.
667824a1566SKashyap Desai  *
668824a1566SKashyap Desai  * Return: IRQ_NONE or IRQ_HANDLED
669824a1566SKashyap Desai  */
670824a1566SKashyap Desai static irqreturn_t mpi3mr_isr_poll(int irq, void *privdata)
671824a1566SKashyap Desai {
672463429f8SKashyap Desai 	struct mpi3mr_intr_info *intr_info = privdata;
673463429f8SKashyap Desai 	struct mpi3mr_ioc *mrioc;
674463429f8SKashyap Desai 	u16 midx;
675463429f8SKashyap Desai 	u32 num_op_reply = 0;
676463429f8SKashyap Desai 
677463429f8SKashyap Desai 	if (!intr_info || !intr_info->op_reply_q)
678463429f8SKashyap Desai 		return IRQ_NONE;
679463429f8SKashyap Desai 
680463429f8SKashyap Desai 	mrioc = intr_info->mrioc;
681463429f8SKashyap Desai 	midx = intr_info->msix_index;
682463429f8SKashyap Desai 
683463429f8SKashyap Desai 	/* Poll for pending IOs completions */
684463429f8SKashyap Desai 	do {
685f2a79d20SSreekanth Reddy 		if (!mrioc->intr_enabled || mrioc->unrecoverable)
686463429f8SKashyap Desai 			break;
687463429f8SKashyap Desai 
688463429f8SKashyap Desai 		if (!midx)
689463429f8SKashyap Desai 			mpi3mr_process_admin_reply_q(mrioc);
690463429f8SKashyap Desai 		if (intr_info->op_reply_q)
691463429f8SKashyap Desai 			num_op_reply +=
692afd3a579SSreekanth Reddy 			    mpi3mr_process_op_reply_q(mrioc,
693afd3a579SSreekanth Reddy 				intr_info->op_reply_q);
694463429f8SKashyap Desai 
695afd3a579SSreekanth Reddy 		usleep_range(MPI3MR_IRQ_POLL_SLEEP, 10 * MPI3MR_IRQ_POLL_SLEEP);
696463429f8SKashyap Desai 
697463429f8SKashyap Desai 	} while (atomic_read(&intr_info->op_reply_q->pend_ios) &&
698463429f8SKashyap Desai 	    (num_op_reply < mrioc->max_host_ios));
699463429f8SKashyap Desai 
700463429f8SKashyap Desai 	intr_info->op_reply_q->enable_irq_poll = false;
7012e31be86SSreekanth Reddy 	enable_irq(intr_info->os_irq);
702463429f8SKashyap Desai 
703824a1566SKashyap Desai 	return IRQ_HANDLED;
704824a1566SKashyap Desai }
705824a1566SKashyap Desai 
7067f9f953dSSreekanth Reddy #endif
7077f9f953dSSreekanth Reddy 
708824a1566SKashyap Desai /**
709824a1566SKashyap Desai  * mpi3mr_request_irq - Request IRQ and register ISR
710824a1566SKashyap Desai  * @mrioc: Adapter instance reference
711824a1566SKashyap Desai  * @index: IRQ vector index
712824a1566SKashyap Desai  *
713824a1566SKashyap Desai  * Request threaded ISR with primary ISR and secondary
714824a1566SKashyap Desai  *
715824a1566SKashyap Desai  * Return: 0 on success and non zero on failures.
716824a1566SKashyap Desai  */
717824a1566SKashyap Desai static inline int mpi3mr_request_irq(struct mpi3mr_ioc *mrioc, u16 index)
718824a1566SKashyap Desai {
719824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
720824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info = mrioc->intr_info + index;
721824a1566SKashyap Desai 	int retval = 0;
722824a1566SKashyap Desai 
723824a1566SKashyap Desai 	intr_info->mrioc = mrioc;
724824a1566SKashyap Desai 	intr_info->msix_index = index;
725824a1566SKashyap Desai 	intr_info->op_reply_q = NULL;
726824a1566SKashyap Desai 
727824a1566SKashyap Desai 	snprintf(intr_info->name, MPI3MR_NAME_LENGTH, "%s%d-msix%d",
728824a1566SKashyap Desai 	    mrioc->driver_name, mrioc->id, index);
729824a1566SKashyap Desai 
7307f9f953dSSreekanth Reddy #ifndef CONFIG_PREEMPT_RT
731824a1566SKashyap Desai 	retval = request_threaded_irq(pci_irq_vector(pdev, index), mpi3mr_isr,
732824a1566SKashyap Desai 	    mpi3mr_isr_poll, IRQF_SHARED, intr_info->name, intr_info);
7337f9f953dSSreekanth Reddy #else
7347f9f953dSSreekanth Reddy 	retval = request_threaded_irq(pci_irq_vector(pdev, index), mpi3mr_isr_primary,
7357f9f953dSSreekanth Reddy 	    NULL, IRQF_SHARED, intr_info->name, intr_info);
7367f9f953dSSreekanth Reddy #endif
737824a1566SKashyap Desai 	if (retval) {
738824a1566SKashyap Desai 		ioc_err(mrioc, "%s: Unable to allocate interrupt %d!\n",
739824a1566SKashyap Desai 		    intr_info->name, pci_irq_vector(pdev, index));
740824a1566SKashyap Desai 		return retval;
741824a1566SKashyap Desai 	}
742824a1566SKashyap Desai 
7432e31be86SSreekanth Reddy 	intr_info->os_irq = pci_irq_vector(pdev, index);
744824a1566SKashyap Desai 	return retval;
745824a1566SKashyap Desai }
746824a1566SKashyap Desai 
747afd3a579SSreekanth Reddy static void mpi3mr_calc_poll_queues(struct mpi3mr_ioc *mrioc, u16 max_vectors)
748afd3a579SSreekanth Reddy {
749afd3a579SSreekanth Reddy 	if (!mrioc->requested_poll_qcount)
750afd3a579SSreekanth Reddy 		return;
751afd3a579SSreekanth Reddy 
752afd3a579SSreekanth Reddy 	/* Reserved for Admin and Default Queue */
753afd3a579SSreekanth Reddy 	if (max_vectors > 2 &&
754afd3a579SSreekanth Reddy 		(mrioc->requested_poll_qcount < max_vectors - 2)) {
755afd3a579SSreekanth Reddy 		ioc_info(mrioc,
756afd3a579SSreekanth Reddy 		    "enabled polled queues (%d) msix (%d)\n",
757afd3a579SSreekanth Reddy 		    mrioc->requested_poll_qcount, max_vectors);
758afd3a579SSreekanth Reddy 	} else {
759afd3a579SSreekanth Reddy 		ioc_info(mrioc,
760afd3a579SSreekanth Reddy 		    "disabled polled queues (%d) msix (%d) because of no resources for default queue\n",
761afd3a579SSreekanth Reddy 		    mrioc->requested_poll_qcount, max_vectors);
762afd3a579SSreekanth Reddy 		mrioc->requested_poll_qcount = 0;
763afd3a579SSreekanth Reddy 	}
764afd3a579SSreekanth Reddy }
765afd3a579SSreekanth Reddy 
766824a1566SKashyap Desai /**
767824a1566SKashyap Desai  * mpi3mr_setup_isr - Setup ISR for the controller
768824a1566SKashyap Desai  * @mrioc: Adapter instance reference
769824a1566SKashyap Desai  * @setup_one: Request one IRQ or more
770824a1566SKashyap Desai  *
771824a1566SKashyap Desai  * Allocate IRQ vectors and call mpi3mr_request_irq to setup ISR
772824a1566SKashyap Desai  *
773824a1566SKashyap Desai  * Return: 0 on success and non zero on failures.
774824a1566SKashyap Desai  */
775824a1566SKashyap Desai static int mpi3mr_setup_isr(struct mpi3mr_ioc *mrioc, u8 setup_one)
776824a1566SKashyap Desai {
777824a1566SKashyap Desai 	unsigned int irq_flags = PCI_IRQ_MSIX;
778afd3a579SSreekanth Reddy 	int max_vectors, min_vec;
7792938beddSDan Carpenter 	int retval;
7802938beddSDan Carpenter 	int i;
781afd3a579SSreekanth Reddy 	struct irq_affinity desc = { .pre_vectors =  1, .post_vectors = 1 };
782824a1566SKashyap Desai 
783fe6db615SSreekanth Reddy 	if (mrioc->is_intr_info_set)
784fe6db615SSreekanth Reddy 		return 0;
785fe6db615SSreekanth Reddy 
786824a1566SKashyap Desai 	mpi3mr_cleanup_isr(mrioc);
787824a1566SKashyap Desai 
788afd3a579SSreekanth Reddy 	if (setup_one || reset_devices) {
789824a1566SKashyap Desai 		max_vectors = 1;
790afd3a579SSreekanth Reddy 		retval = pci_alloc_irq_vectors(mrioc->pdev,
791afd3a579SSreekanth Reddy 		    1, max_vectors, irq_flags);
792afd3a579SSreekanth Reddy 		if (retval < 0) {
793afd3a579SSreekanth Reddy 			ioc_err(mrioc, "cannot allocate irq vectors, ret %d\n",
794afd3a579SSreekanth Reddy 			    retval);
795afd3a579SSreekanth Reddy 			goto out_failed;
796afd3a579SSreekanth Reddy 		}
797afd3a579SSreekanth Reddy 	} else {
798824a1566SKashyap Desai 		max_vectors =
799afd3a579SSreekanth Reddy 		    min_t(int, mrioc->cpu_count + 1 +
800afd3a579SSreekanth Reddy 			mrioc->requested_poll_qcount, mrioc->msix_count);
801afd3a579SSreekanth Reddy 
802afd3a579SSreekanth Reddy 		mpi3mr_calc_poll_queues(mrioc, max_vectors);
803824a1566SKashyap Desai 
804824a1566SKashyap Desai 		ioc_info(mrioc,
805824a1566SKashyap Desai 		    "MSI-X vectors supported: %d, no of cores: %d,",
806824a1566SKashyap Desai 		    mrioc->msix_count, mrioc->cpu_count);
807824a1566SKashyap Desai 		ioc_info(mrioc,
808afd3a579SSreekanth Reddy 		    "MSI-x vectors requested: %d poll_queues %d\n",
809afd3a579SSreekanth Reddy 		    max_vectors, mrioc->requested_poll_qcount);
810824a1566SKashyap Desai 
811afd3a579SSreekanth Reddy 		desc.post_vectors = mrioc->requested_poll_qcount;
812afd3a579SSreekanth Reddy 		min_vec = desc.pre_vectors + desc.post_vectors;
813824a1566SKashyap Desai 		irq_flags |= PCI_IRQ_AFFINITY | PCI_IRQ_ALL_TYPES;
814824a1566SKashyap Desai 
8152938beddSDan Carpenter 		retval = pci_alloc_irq_vectors_affinity(mrioc->pdev,
816afd3a579SSreekanth Reddy 			min_vec, max_vectors, irq_flags, &desc);
817afd3a579SSreekanth Reddy 
8182938beddSDan Carpenter 		if (retval < 0) {
819afd3a579SSreekanth Reddy 			ioc_err(mrioc, "cannot allocate irq vectors, ret %d\n",
820afd3a579SSreekanth Reddy 			    retval);
821824a1566SKashyap Desai 			goto out_failed;
822824a1566SKashyap Desai 		}
823afd3a579SSreekanth Reddy 
824afd3a579SSreekanth Reddy 
825c9566231SKashyap Desai 		/*
826c9566231SKashyap Desai 		 * If only one MSI-x is allocated, then MSI-x 0 will be shared
827c9566231SKashyap Desai 		 * between Admin queue and operational queue
828c9566231SKashyap Desai 		 */
829afd3a579SSreekanth Reddy 		if (retval == min_vec)
830c9566231SKashyap Desai 			mrioc->op_reply_q_offset = 0;
831afd3a579SSreekanth Reddy 		else if (retval != (max_vectors)) {
832afd3a579SSreekanth Reddy 			ioc_info(mrioc,
833afd3a579SSreekanth Reddy 			    "allocated vectors (%d) are less than configured (%d)\n",
834afd3a579SSreekanth Reddy 			    retval, max_vectors);
835afd3a579SSreekanth Reddy 		}
836824a1566SKashyap Desai 
8372938beddSDan Carpenter 		max_vectors = retval;
838afd3a579SSreekanth Reddy 		mrioc->op_reply_q_offset = (max_vectors > 1) ? 1 : 0;
839afd3a579SSreekanth Reddy 
840afd3a579SSreekanth Reddy 		mpi3mr_calc_poll_queues(mrioc, max_vectors);
841afd3a579SSreekanth Reddy 
842824a1566SKashyap Desai 	}
843afd3a579SSreekanth Reddy 
844824a1566SKashyap Desai 	mrioc->intr_info = kzalloc(sizeof(struct mpi3mr_intr_info) * max_vectors,
845824a1566SKashyap Desai 	    GFP_KERNEL);
846824a1566SKashyap Desai 	if (!mrioc->intr_info) {
8472938beddSDan Carpenter 		retval = -ENOMEM;
848824a1566SKashyap Desai 		pci_free_irq_vectors(mrioc->pdev);
849824a1566SKashyap Desai 		goto out_failed;
850824a1566SKashyap Desai 	}
851824a1566SKashyap Desai 	for (i = 0; i < max_vectors; i++) {
852824a1566SKashyap Desai 		retval = mpi3mr_request_irq(mrioc, i);
853824a1566SKashyap Desai 		if (retval) {
854824a1566SKashyap Desai 			mrioc->intr_info_count = i;
855824a1566SKashyap Desai 			goto out_failed;
856824a1566SKashyap Desai 		}
857824a1566SKashyap Desai 	}
858fe6db615SSreekanth Reddy 	if (reset_devices || !setup_one)
859fe6db615SSreekanth Reddy 		mrioc->is_intr_info_set = true;
860824a1566SKashyap Desai 	mrioc->intr_info_count = max_vectors;
861824a1566SKashyap Desai 	mpi3mr_ioc_enable_intr(mrioc);
8622938beddSDan Carpenter 	return 0;
8632938beddSDan Carpenter 
864824a1566SKashyap Desai out_failed:
865824a1566SKashyap Desai 	mpi3mr_cleanup_isr(mrioc);
866824a1566SKashyap Desai 
867824a1566SKashyap Desai 	return retval;
868824a1566SKashyap Desai }
869824a1566SKashyap Desai 
870824a1566SKashyap Desai static const struct {
871824a1566SKashyap Desai 	enum mpi3mr_iocstate value;
872824a1566SKashyap Desai 	char *name;
873824a1566SKashyap Desai } mrioc_states[] = {
874824a1566SKashyap Desai 	{ MRIOC_STATE_READY, "ready" },
875824a1566SKashyap Desai 	{ MRIOC_STATE_FAULT, "fault" },
876824a1566SKashyap Desai 	{ MRIOC_STATE_RESET, "reset" },
877824a1566SKashyap Desai 	{ MRIOC_STATE_BECOMING_READY, "becoming ready" },
878824a1566SKashyap Desai 	{ MRIOC_STATE_RESET_REQUESTED, "reset requested" },
879824a1566SKashyap Desai 	{ MRIOC_STATE_UNRECOVERABLE, "unrecoverable error" },
880824a1566SKashyap Desai };
881824a1566SKashyap Desai 
882824a1566SKashyap Desai static const char *mpi3mr_iocstate_name(enum mpi3mr_iocstate mrioc_state)
883824a1566SKashyap Desai {
884824a1566SKashyap Desai 	int i;
885824a1566SKashyap Desai 	char *name = NULL;
886824a1566SKashyap Desai 
887824a1566SKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mrioc_states); i++) {
888824a1566SKashyap Desai 		if (mrioc_states[i].value == mrioc_state) {
889824a1566SKashyap Desai 			name = mrioc_states[i].name;
890824a1566SKashyap Desai 			break;
891824a1566SKashyap Desai 		}
892824a1566SKashyap Desai 	}
893824a1566SKashyap Desai 	return name;
894824a1566SKashyap Desai }
895824a1566SKashyap Desai 
896f061178eSKashyap Desai /* Reset reason to name mapper structure*/
897f061178eSKashyap Desai static const struct {
898f061178eSKashyap Desai 	enum mpi3mr_reset_reason value;
899f061178eSKashyap Desai 	char *name;
900f061178eSKashyap Desai } mpi3mr_reset_reason_codes[] = {
901f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_BRINGUP, "timeout in bringup" },
902f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_FAULT_WATCH, "fault" },
903f5e6d5a3SSumit Saxena 	{ MPI3MR_RESET_FROM_APP, "application invocation" },
904f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_EH_HOS, "error handling" },
905f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_TM_TIMEOUT, "TM timeout" },
906f5e6d5a3SSumit Saxena 	{ MPI3MR_RESET_FROM_APP_TIMEOUT, "application command timeout" },
907f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_MUR_FAILURE, "MUR failure" },
908f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_CTLR_CLEANUP, "timeout in controller cleanup" },
909f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_CIACTIV_FAULT, "component image activation fault" },
910f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_PE_TIMEOUT, "port enable timeout" },
911f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_TSU_TIMEOUT, "time stamp update timeout" },
912f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_DELREQQ_TIMEOUT, "delete request queue timeout" },
913f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_DELREPQ_TIMEOUT, "delete reply queue timeout" },
914f061178eSKashyap Desai 	{
915f061178eSKashyap Desai 		MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT,
916f061178eSKashyap Desai 		"create request queue timeout"
917f061178eSKashyap Desai 	},
918f061178eSKashyap Desai 	{
919f061178eSKashyap Desai 		MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT,
920f061178eSKashyap Desai 		"create reply queue timeout"
921f061178eSKashyap Desai 	},
922f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT, "IOC facts timeout" },
923f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_IOCINIT_TIMEOUT, "IOC init timeout" },
924f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT, "event notify timeout" },
925f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_EVTACK_TIMEOUT, "event acknowledgment timeout" },
926f061178eSKashyap Desai 	{
927f061178eSKashyap Desai 		MPI3MR_RESET_FROM_CIACTVRST_TIMER,
928f061178eSKashyap Desai 		"component image activation timeout"
929f061178eSKashyap Desai 	},
930f061178eSKashyap Desai 	{
931f061178eSKashyap Desai 		MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT,
932f061178eSKashyap Desai 		"get package version timeout"
933f061178eSKashyap Desai 	},
934f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_SYSFS, "sysfs invocation" },
935f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_SYSFS_TIMEOUT, "sysfs TM timeout" },
9365867b856SColin Ian King 	{ MPI3MR_RESET_FROM_FIRMWARE, "firmware asynchronous reset" },
93732d457d5SSreekanth Reddy 	{ MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT, "configuration request timeout"},
9382bd37e28SSreekanth Reddy 	{ MPI3MR_RESET_FROM_SAS_TRANSPORT_TIMEOUT, "timeout of a SAS transport layer request" },
939f061178eSKashyap Desai };
940f061178eSKashyap Desai 
941f061178eSKashyap Desai /**
942f061178eSKashyap Desai  * mpi3mr_reset_rc_name - get reset reason code name
943f061178eSKashyap Desai  * @reason_code: reset reason code value
944f061178eSKashyap Desai  *
945f061178eSKashyap Desai  * Map reset reason to an NULL terminated ASCII string
946f061178eSKashyap Desai  *
947f061178eSKashyap Desai  * Return: name corresponding to reset reason value or NULL.
948f061178eSKashyap Desai  */
949f061178eSKashyap Desai static const char *mpi3mr_reset_rc_name(enum mpi3mr_reset_reason reason_code)
950f061178eSKashyap Desai {
951f061178eSKashyap Desai 	int i;
952f061178eSKashyap Desai 	char *name = NULL;
953f061178eSKashyap Desai 
954f061178eSKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mpi3mr_reset_reason_codes); i++) {
955f061178eSKashyap Desai 		if (mpi3mr_reset_reason_codes[i].value == reason_code) {
956f061178eSKashyap Desai 			name = mpi3mr_reset_reason_codes[i].name;
957f061178eSKashyap Desai 			break;
958f061178eSKashyap Desai 		}
959f061178eSKashyap Desai 	}
960f061178eSKashyap Desai 	return name;
961f061178eSKashyap Desai }
962f061178eSKashyap Desai 
963f061178eSKashyap Desai /* Reset type to name mapper structure*/
964f061178eSKashyap Desai static const struct {
965f061178eSKashyap Desai 	u16 reset_type;
966f061178eSKashyap Desai 	char *name;
967f061178eSKashyap Desai } mpi3mr_reset_types[] = {
968f061178eSKashyap Desai 	{ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, "soft" },
969f061178eSKashyap Desai 	{ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, "diag fault" },
970f061178eSKashyap Desai };
971f061178eSKashyap Desai 
972f061178eSKashyap Desai /**
973f061178eSKashyap Desai  * mpi3mr_reset_type_name - get reset type name
974f061178eSKashyap Desai  * @reset_type: reset type value
975f061178eSKashyap Desai  *
976f061178eSKashyap Desai  * Map reset type to an NULL terminated ASCII string
977f061178eSKashyap Desai  *
978f061178eSKashyap Desai  * Return: name corresponding to reset type value or NULL.
979f061178eSKashyap Desai  */
980f061178eSKashyap Desai static const char *mpi3mr_reset_type_name(u16 reset_type)
981f061178eSKashyap Desai {
982f061178eSKashyap Desai 	int i;
983f061178eSKashyap Desai 	char *name = NULL;
984f061178eSKashyap Desai 
985f061178eSKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mpi3mr_reset_types); i++) {
986f061178eSKashyap Desai 		if (mpi3mr_reset_types[i].reset_type == reset_type) {
987f061178eSKashyap Desai 			name = mpi3mr_reset_types[i].name;
988f061178eSKashyap Desai 			break;
989f061178eSKashyap Desai 		}
990f061178eSKashyap Desai 	}
991f061178eSKashyap Desai 	return name;
992f061178eSKashyap Desai }
993f061178eSKashyap Desai 
994824a1566SKashyap Desai /**
995824a1566SKashyap Desai  * mpi3mr_print_fault_info - Display fault information
996824a1566SKashyap Desai  * @mrioc: Adapter instance reference
997824a1566SKashyap Desai  *
998824a1566SKashyap Desai  * Display the controller fault information if there is a
999824a1566SKashyap Desai  * controller fault.
1000824a1566SKashyap Desai  *
1001824a1566SKashyap Desai  * Return: Nothing.
1002824a1566SKashyap Desai  */
1003b64845a7SSreekanth Reddy void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc)
1004824a1566SKashyap Desai {
1005824a1566SKashyap Desai 	u32 ioc_status, code, code1, code2, code3;
1006824a1566SKashyap Desai 
1007824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
1008824a1566SKashyap Desai 
1009824a1566SKashyap Desai 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) {
1010824a1566SKashyap Desai 		code = readl(&mrioc->sysif_regs->fault);
1011824a1566SKashyap Desai 		code1 = readl(&mrioc->sysif_regs->fault_info[0]);
1012824a1566SKashyap Desai 		code2 = readl(&mrioc->sysif_regs->fault_info[1]);
1013824a1566SKashyap Desai 		code3 = readl(&mrioc->sysif_regs->fault_info[2]);
1014824a1566SKashyap Desai 
1015824a1566SKashyap Desai 		ioc_info(mrioc,
1016824a1566SKashyap Desai 		    "fault code(0x%08X): Additional code: (0x%08X:0x%08X:0x%08X)\n",
1017824a1566SKashyap Desai 		    code, code1, code2, code3);
1018824a1566SKashyap Desai 	}
1019824a1566SKashyap Desai }
1020824a1566SKashyap Desai 
1021824a1566SKashyap Desai /**
1022824a1566SKashyap Desai  * mpi3mr_get_iocstate - Get IOC State
1023824a1566SKashyap Desai  * @mrioc: Adapter instance reference
1024824a1566SKashyap Desai  *
1025824a1566SKashyap Desai  * Return a proper IOC state enum based on the IOC status and
1026824a1566SKashyap Desai  * IOC configuration and unrcoverable state of the controller.
1027824a1566SKashyap Desai  *
1028824a1566SKashyap Desai  * Return: Current IOC state.
1029824a1566SKashyap Desai  */
1030824a1566SKashyap Desai enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc)
1031824a1566SKashyap Desai {
1032824a1566SKashyap Desai 	u32 ioc_status, ioc_config;
1033824a1566SKashyap Desai 	u8 ready, enabled;
1034824a1566SKashyap Desai 
1035824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
1036824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
1037824a1566SKashyap Desai 
1038824a1566SKashyap Desai 	if (mrioc->unrecoverable)
1039824a1566SKashyap Desai 		return MRIOC_STATE_UNRECOVERABLE;
1040824a1566SKashyap Desai 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)
1041824a1566SKashyap Desai 		return MRIOC_STATE_FAULT;
1042824a1566SKashyap Desai 
1043824a1566SKashyap Desai 	ready = (ioc_status & MPI3_SYSIF_IOC_STATUS_READY);
1044824a1566SKashyap Desai 	enabled = (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC);
1045824a1566SKashyap Desai 
1046824a1566SKashyap Desai 	if (ready && enabled)
1047824a1566SKashyap Desai 		return MRIOC_STATE_READY;
1048824a1566SKashyap Desai 	if ((!ready) && (!enabled))
1049824a1566SKashyap Desai 		return MRIOC_STATE_RESET;
1050824a1566SKashyap Desai 	if ((!ready) && (enabled))
1051824a1566SKashyap Desai 		return MRIOC_STATE_BECOMING_READY;
1052824a1566SKashyap Desai 
1053824a1566SKashyap Desai 	return MRIOC_STATE_RESET_REQUESTED;
1054824a1566SKashyap Desai }
1055824a1566SKashyap Desai 
1056824a1566SKashyap Desai /**
1057824a1566SKashyap Desai  * mpi3mr_clear_reset_history - clear reset history
1058824a1566SKashyap Desai  * @mrioc: Adapter instance reference
1059824a1566SKashyap Desai  *
1060824a1566SKashyap Desai  * Write the reset history bit in IOC status to clear the bit,
1061824a1566SKashyap Desai  * if it is already set.
1062824a1566SKashyap Desai  *
1063824a1566SKashyap Desai  * Return: Nothing.
1064824a1566SKashyap Desai  */
1065824a1566SKashyap Desai static inline void mpi3mr_clear_reset_history(struct mpi3mr_ioc *mrioc)
1066824a1566SKashyap Desai {
1067824a1566SKashyap Desai 	u32 ioc_status;
1068824a1566SKashyap Desai 
1069824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
1070824a1566SKashyap Desai 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)
1071824a1566SKashyap Desai 		writel(ioc_status, &mrioc->sysif_regs->ioc_status);
1072824a1566SKashyap Desai }
1073824a1566SKashyap Desai 
1074824a1566SKashyap Desai /**
1075824a1566SKashyap Desai  * mpi3mr_issue_and_process_mur - Message unit Reset handler
1076824a1566SKashyap Desai  * @mrioc: Adapter instance reference
1077824a1566SKashyap Desai  * @reset_reason: Reset reason code
1078824a1566SKashyap Desai  *
1079824a1566SKashyap Desai  * Issue Message unit Reset to the controller and wait for it to
1080824a1566SKashyap Desai  * be complete.
1081824a1566SKashyap Desai  *
1082824a1566SKashyap Desai  * Return: 0 on success, -1 on failure.
1083824a1566SKashyap Desai  */
1084824a1566SKashyap Desai static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc,
1085824a1566SKashyap Desai 	u32 reset_reason)
1086824a1566SKashyap Desai {
1087824a1566SKashyap Desai 	u32 ioc_config, timeout, ioc_status;
1088824a1566SKashyap Desai 	int retval = -1;
1089824a1566SKashyap Desai 
1090824a1566SKashyap Desai 	ioc_info(mrioc, "Issuing Message unit Reset(MUR)\n");
1091824a1566SKashyap Desai 	if (mrioc->unrecoverable) {
1092824a1566SKashyap Desai 		ioc_info(mrioc, "IOC is unrecoverable MUR not issued\n");
1093824a1566SKashyap Desai 		return retval;
1094824a1566SKashyap Desai 	}
1095824a1566SKashyap Desai 	mpi3mr_clear_reset_history(mrioc);
1096824a1566SKashyap Desai 	writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]);
1097824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
1098824a1566SKashyap Desai 	ioc_config &= ~MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
1099824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
1100824a1566SKashyap Desai 
1101b64845a7SSreekanth Reddy 	timeout = MPI3MR_RESET_ACK_TIMEOUT * 10;
1102824a1566SKashyap Desai 	do {
1103824a1566SKashyap Desai 		ioc_status = readl(&mrioc->sysif_regs->ioc_status);
1104824a1566SKashyap Desai 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)) {
1105824a1566SKashyap Desai 			mpi3mr_clear_reset_history(mrioc);
1106824a1566SKashyap Desai 			break;
1107824a1566SKashyap Desai 		}
1108b64845a7SSreekanth Reddy 		if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) {
1109b64845a7SSreekanth Reddy 			mpi3mr_print_fault_info(mrioc);
1110b64845a7SSreekanth Reddy 			break;
1111824a1566SKashyap Desai 		}
1112824a1566SKashyap Desai 		msleep(100);
1113824a1566SKashyap Desai 	} while (--timeout);
1114824a1566SKashyap Desai 
1115824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
1116b64845a7SSreekanth Reddy 	if (timeout && !((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) ||
1117b64845a7SSreekanth Reddy 	      (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) ||
1118b64845a7SSreekanth Reddy 	      (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC)))
1119b64845a7SSreekanth Reddy 		retval = 0;
1120824a1566SKashyap Desai 
1121824a1566SKashyap Desai 	ioc_info(mrioc, "Base IOC Sts/Config after %s MUR is (0x%x)/(0x%x)\n",
1122824a1566SKashyap Desai 	    (!retval) ? "successful" : "failed", ioc_status, ioc_config);
1123824a1566SKashyap Desai 	return retval;
1124824a1566SKashyap Desai }
1125824a1566SKashyap Desai 
1126824a1566SKashyap Desai /**
1127c5758fc7SSreekanth Reddy  * mpi3mr_revalidate_factsdata - validate IOCFacts parameters
1128c5758fc7SSreekanth Reddy  * during reset/resume
1129c5758fc7SSreekanth Reddy  * @mrioc: Adapter instance reference
1130c5758fc7SSreekanth Reddy  *
1131c5758fc7SSreekanth Reddy  * Return zero if the new IOCFacts parameters value is compatible with
1132c5758fc7SSreekanth Reddy  * older values else return -EPERM
1133c5758fc7SSreekanth Reddy  */
1134c5758fc7SSreekanth Reddy static int
1135c5758fc7SSreekanth Reddy mpi3mr_revalidate_factsdata(struct mpi3mr_ioc *mrioc)
1136c5758fc7SSreekanth Reddy {
1137c5758fc7SSreekanth Reddy 	void *removepend_bitmap;
1138c5758fc7SSreekanth Reddy 
1139c5758fc7SSreekanth Reddy 	if (mrioc->facts.reply_sz > mrioc->reply_sz) {
1140c5758fc7SSreekanth Reddy 		ioc_err(mrioc,
1141c5758fc7SSreekanth Reddy 		    "cannot increase reply size from %d to %d\n",
1142c5758fc7SSreekanth Reddy 		    mrioc->reply_sz, mrioc->facts.reply_sz);
1143c5758fc7SSreekanth Reddy 		return -EPERM;
1144c5758fc7SSreekanth Reddy 	}
1145c5758fc7SSreekanth Reddy 
1146c5758fc7SSreekanth Reddy 	if (mrioc->facts.max_op_reply_q < mrioc->num_op_reply_q) {
1147c5758fc7SSreekanth Reddy 		ioc_err(mrioc,
1148c5758fc7SSreekanth Reddy 		    "cannot reduce number of operational reply queues from %d to %d\n",
1149c5758fc7SSreekanth Reddy 		    mrioc->num_op_reply_q,
1150c5758fc7SSreekanth Reddy 		    mrioc->facts.max_op_reply_q);
1151c5758fc7SSreekanth Reddy 		return -EPERM;
1152c5758fc7SSreekanth Reddy 	}
1153c5758fc7SSreekanth Reddy 
1154c5758fc7SSreekanth Reddy 	if (mrioc->facts.max_op_req_q < mrioc->num_op_req_q) {
1155c5758fc7SSreekanth Reddy 		ioc_err(mrioc,
1156c5758fc7SSreekanth Reddy 		    "cannot reduce number of operational request queues from %d to %d\n",
1157c5758fc7SSreekanth Reddy 		    mrioc->num_op_req_q, mrioc->facts.max_op_req_q);
1158c5758fc7SSreekanth Reddy 		return -EPERM;
1159c5758fc7SSreekanth Reddy 	}
1160c5758fc7SSreekanth Reddy 
1161c4723e68SSreekanth Reddy 	if ((mrioc->sas_transport_enabled) && (mrioc->facts.ioc_capabilities &
1162c4723e68SSreekanth Reddy 	    MPI3_IOCFACTS_CAPABILITY_MULTIPATH_ENABLED))
1163c4723e68SSreekanth Reddy 		ioc_err(mrioc,
1164c4723e68SSreekanth Reddy 		    "critical error: multipath capability is enabled at the\n"
1165c4723e68SSreekanth Reddy 		    "\tcontroller while sas transport support is enabled at the\n"
1166c4723e68SSreekanth Reddy 		    "\tdriver, please reboot the system or reload the driver\n");
1167c4723e68SSreekanth Reddy 
1168339e6156SShin'ichiro Kawasaki 	if (mrioc->facts.max_devhandle > mrioc->dev_handle_bitmap_bits) {
1169339e6156SShin'ichiro Kawasaki 		removepend_bitmap = bitmap_zalloc(mrioc->facts.max_devhandle,
1170339e6156SShin'ichiro Kawasaki 						  GFP_KERNEL);
1171c5758fc7SSreekanth Reddy 		if (!removepend_bitmap) {
1172c5758fc7SSreekanth Reddy 			ioc_err(mrioc,
1173339e6156SShin'ichiro Kawasaki 				"failed to increase removepend_bitmap bits from %d to %d\n",
1174339e6156SShin'ichiro Kawasaki 				mrioc->dev_handle_bitmap_bits,
1175339e6156SShin'ichiro Kawasaki 				mrioc->facts.max_devhandle);
1176c5758fc7SSreekanth Reddy 			return -EPERM;
1177c5758fc7SSreekanth Reddy 		}
1178339e6156SShin'ichiro Kawasaki 		bitmap_free(mrioc->removepend_bitmap);
1179c5758fc7SSreekanth Reddy 		mrioc->removepend_bitmap = removepend_bitmap;
1180c5758fc7SSreekanth Reddy 		ioc_info(mrioc,
1181339e6156SShin'ichiro Kawasaki 			 "increased bits of dev_handle_bitmap from %d to %d\n",
1182339e6156SShin'ichiro Kawasaki 			 mrioc->dev_handle_bitmap_bits,
1183339e6156SShin'ichiro Kawasaki 			 mrioc->facts.max_devhandle);
1184339e6156SShin'ichiro Kawasaki 		mrioc->dev_handle_bitmap_bits = mrioc->facts.max_devhandle;
1185c5758fc7SSreekanth Reddy 	}
1186c5758fc7SSreekanth Reddy 
1187c5758fc7SSreekanth Reddy 	return 0;
1188c5758fc7SSreekanth Reddy }
1189c5758fc7SSreekanth Reddy 
1190c5758fc7SSreekanth Reddy /**
1191824a1566SKashyap Desai  * mpi3mr_bring_ioc_ready - Bring controller to ready state
1192824a1566SKashyap Desai  * @mrioc: Adapter instance reference
1193824a1566SKashyap Desai  *
1194824a1566SKashyap Desai  * Set Enable IOC bit in IOC configuration register and wait for
1195824a1566SKashyap Desai  * the controller to become ready.
1196824a1566SKashyap Desai  *
119759bd9cfeSSreekanth Reddy  * Return: 0 on success, appropriate error on failure.
1198824a1566SKashyap Desai  */
1199824a1566SKashyap Desai static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc)
1200824a1566SKashyap Desai {
12010a319f16SRanjan Kumar 	u32 ioc_config, ioc_status, timeout, host_diagnostic;
120259bd9cfeSSreekanth Reddy 	int retval = 0;
120359bd9cfeSSreekanth Reddy 	enum mpi3mr_iocstate ioc_state;
120459bd9cfeSSreekanth Reddy 	u64 base_info;
1205824a1566SKashyap Desai 
120659bd9cfeSSreekanth Reddy 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
120759bd9cfeSSreekanth Reddy 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
120859bd9cfeSSreekanth Reddy 	base_info = lo_hi_readq(&mrioc->sysif_regs->ioc_information);
120959bd9cfeSSreekanth Reddy 	ioc_info(mrioc, "ioc_status(0x%08x), ioc_config(0x%08x), ioc_info(0x%016llx) at the bringup\n",
121059bd9cfeSSreekanth Reddy 	    ioc_status, ioc_config, base_info);
121159bd9cfeSSreekanth Reddy 
121259bd9cfeSSreekanth Reddy 	/*The timeout value is in 2sec unit, changing it to seconds*/
121359bd9cfeSSreekanth Reddy 	mrioc->ready_timeout =
121459bd9cfeSSreekanth Reddy 	    ((base_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >>
121559bd9cfeSSreekanth Reddy 	    MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT) * 2;
121659bd9cfeSSreekanth Reddy 
121759bd9cfeSSreekanth Reddy 	ioc_info(mrioc, "ready timeout: %d seconds\n", mrioc->ready_timeout);
121859bd9cfeSSreekanth Reddy 
121959bd9cfeSSreekanth Reddy 	ioc_state = mpi3mr_get_iocstate(mrioc);
122059bd9cfeSSreekanth Reddy 	ioc_info(mrioc, "controller is in %s state during detection\n",
122159bd9cfeSSreekanth Reddy 	    mpi3mr_iocstate_name(ioc_state));
122259bd9cfeSSreekanth Reddy 
122359bd9cfeSSreekanth Reddy 	if (ioc_state == MRIOC_STATE_BECOMING_READY ||
122459bd9cfeSSreekanth Reddy 	    ioc_state == MRIOC_STATE_RESET_REQUESTED) {
122559bd9cfeSSreekanth Reddy 		timeout = mrioc->ready_timeout * 10;
122659bd9cfeSSreekanth Reddy 		do {
122759bd9cfeSSreekanth Reddy 			msleep(100);
122859bd9cfeSSreekanth Reddy 		} while (--timeout);
122959bd9cfeSSreekanth Reddy 
1230f2a79d20SSreekanth Reddy 		if (!pci_device_is_present(mrioc->pdev)) {
1231f2a79d20SSreekanth Reddy 			mrioc->unrecoverable = 1;
1232f2a79d20SSreekanth Reddy 			ioc_err(mrioc,
1233f2a79d20SSreekanth Reddy 			    "controller is not present while waiting to reset\n");
1234f2a79d20SSreekanth Reddy 			retval = -1;
1235f2a79d20SSreekanth Reddy 			goto out_device_not_present;
1236f2a79d20SSreekanth Reddy 		}
1237f2a79d20SSreekanth Reddy 
123859bd9cfeSSreekanth Reddy 		ioc_state = mpi3mr_get_iocstate(mrioc);
123959bd9cfeSSreekanth Reddy 		ioc_info(mrioc,
124059bd9cfeSSreekanth Reddy 		    "controller is in %s state after waiting to reset\n",
124159bd9cfeSSreekanth Reddy 		    mpi3mr_iocstate_name(ioc_state));
124259bd9cfeSSreekanth Reddy 	}
124359bd9cfeSSreekanth Reddy 
124459bd9cfeSSreekanth Reddy 	if (ioc_state == MRIOC_STATE_READY) {
124559bd9cfeSSreekanth Reddy 		ioc_info(mrioc, "issuing message unit reset (MUR) to bring to reset state\n");
124659bd9cfeSSreekanth Reddy 		retval = mpi3mr_issue_and_process_mur(mrioc,
124759bd9cfeSSreekanth Reddy 		    MPI3MR_RESET_FROM_BRINGUP);
124859bd9cfeSSreekanth Reddy 		ioc_state = mpi3mr_get_iocstate(mrioc);
124959bd9cfeSSreekanth Reddy 		if (retval)
125059bd9cfeSSreekanth Reddy 			ioc_err(mrioc,
125159bd9cfeSSreekanth Reddy 			    "message unit reset failed with error %d current state %s\n",
125259bd9cfeSSreekanth Reddy 			    retval, mpi3mr_iocstate_name(ioc_state));
125359bd9cfeSSreekanth Reddy 	}
125459bd9cfeSSreekanth Reddy 	if (ioc_state != MRIOC_STATE_RESET) {
12550a319f16SRanjan Kumar 		if (ioc_state == MRIOC_STATE_FAULT) {
12560a319f16SRanjan Kumar 			timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10;
12570a319f16SRanjan Kumar 			mpi3mr_print_fault_info(mrioc);
12580a319f16SRanjan Kumar 			do {
12590a319f16SRanjan Kumar 				host_diagnostic =
12600a319f16SRanjan Kumar 					readl(&mrioc->sysif_regs->host_diagnostic);
12610a319f16SRanjan Kumar 				if (!(host_diagnostic &
12620a319f16SRanjan Kumar 				      MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS))
12630a319f16SRanjan Kumar 					break;
12640a319f16SRanjan Kumar 				if (!pci_device_is_present(mrioc->pdev)) {
12650a319f16SRanjan Kumar 					mrioc->unrecoverable = 1;
12660a319f16SRanjan Kumar 					ioc_err(mrioc, "controller is not present at the bringup\n");
12670a319f16SRanjan Kumar 					goto out_device_not_present;
12680a319f16SRanjan Kumar 				}
12690a319f16SRanjan Kumar 				msleep(100);
12700a319f16SRanjan Kumar 			} while (--timeout);
12710a319f16SRanjan Kumar 		}
127259bd9cfeSSreekanth Reddy 		mpi3mr_print_fault_info(mrioc);
127359bd9cfeSSreekanth Reddy 		ioc_info(mrioc, "issuing soft reset to bring to reset state\n");
127459bd9cfeSSreekanth Reddy 		retval = mpi3mr_issue_reset(mrioc,
127559bd9cfeSSreekanth Reddy 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
127659bd9cfeSSreekanth Reddy 		    MPI3MR_RESET_FROM_BRINGUP);
127759bd9cfeSSreekanth Reddy 		if (retval) {
127859bd9cfeSSreekanth Reddy 			ioc_err(mrioc,
127959bd9cfeSSreekanth Reddy 			    "soft reset failed with error %d\n", retval);
128059bd9cfeSSreekanth Reddy 			goto out_failed;
128159bd9cfeSSreekanth Reddy 		}
128259bd9cfeSSreekanth Reddy 	}
128359bd9cfeSSreekanth Reddy 	ioc_state = mpi3mr_get_iocstate(mrioc);
128459bd9cfeSSreekanth Reddy 	if (ioc_state != MRIOC_STATE_RESET) {
128559bd9cfeSSreekanth Reddy 		ioc_err(mrioc,
128659bd9cfeSSreekanth Reddy 		    "cannot bring controller to reset state, current state: %s\n",
128759bd9cfeSSreekanth Reddy 		    mpi3mr_iocstate_name(ioc_state));
128859bd9cfeSSreekanth Reddy 		goto out_failed;
128959bd9cfeSSreekanth Reddy 	}
129059bd9cfeSSreekanth Reddy 	mpi3mr_clear_reset_history(mrioc);
129159bd9cfeSSreekanth Reddy 	retval = mpi3mr_setup_admin_qpair(mrioc);
129259bd9cfeSSreekanth Reddy 	if (retval) {
129359bd9cfeSSreekanth Reddy 		ioc_err(mrioc, "failed to setup admin queues: error %d\n",
129459bd9cfeSSreekanth Reddy 		    retval);
129559bd9cfeSSreekanth Reddy 		goto out_failed;
129659bd9cfeSSreekanth Reddy 	}
129759bd9cfeSSreekanth Reddy 
129859bd9cfeSSreekanth Reddy 	ioc_info(mrioc, "bringing controller to ready state\n");
1299824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
1300824a1566SKashyap Desai 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
1301824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
1302824a1566SKashyap Desai 
1303824a1566SKashyap Desai 	timeout = mrioc->ready_timeout * 10;
1304824a1566SKashyap Desai 	do {
130559bd9cfeSSreekanth Reddy 		ioc_state = mpi3mr_get_iocstate(mrioc);
130659bd9cfeSSreekanth Reddy 		if (ioc_state == MRIOC_STATE_READY) {
130759bd9cfeSSreekanth Reddy 			ioc_info(mrioc,
13085867b856SColin Ian King 			    "successfully transitioned to %s state\n",
130959bd9cfeSSreekanth Reddy 			    mpi3mr_iocstate_name(ioc_state));
1310824a1566SKashyap Desai 			return 0;
131159bd9cfeSSreekanth Reddy 		}
1312f2a79d20SSreekanth Reddy 		if (!pci_device_is_present(mrioc->pdev)) {
1313f2a79d20SSreekanth Reddy 			mrioc->unrecoverable = 1;
1314f2a79d20SSreekanth Reddy 			ioc_err(mrioc,
1315f2a79d20SSreekanth Reddy 			    "controller is not present at the bringup\n");
1316f2a79d20SSreekanth Reddy 			retval = -1;
1317f2a79d20SSreekanth Reddy 			goto out_device_not_present;
1318f2a79d20SSreekanth Reddy 		}
1319824a1566SKashyap Desai 		msleep(100);
1320824a1566SKashyap Desai 	} while (--timeout);
1321824a1566SKashyap Desai 
132259bd9cfeSSreekanth Reddy out_failed:
132359bd9cfeSSreekanth Reddy 	ioc_state = mpi3mr_get_iocstate(mrioc);
132459bd9cfeSSreekanth Reddy 	ioc_err(mrioc,
132559bd9cfeSSreekanth Reddy 	    "failed to bring to ready state,  current state: %s\n",
132659bd9cfeSSreekanth Reddy 	    mpi3mr_iocstate_name(ioc_state));
1327f2a79d20SSreekanth Reddy out_device_not_present:
132859bd9cfeSSreekanth Reddy 	return retval;
1329824a1566SKashyap Desai }
1330824a1566SKashyap Desai 
1331824a1566SKashyap Desai /**
1332f061178eSKashyap Desai  * mpi3mr_soft_reset_success - Check softreset is success or not
1333f061178eSKashyap Desai  * @ioc_status: IOC status register value
1334f061178eSKashyap Desai  * @ioc_config: IOC config register value
1335f061178eSKashyap Desai  *
1336f061178eSKashyap Desai  * Check whether the soft reset is successful or not based on
1337f061178eSKashyap Desai  * IOC status and IOC config register values.
1338f061178eSKashyap Desai  *
1339f061178eSKashyap Desai  * Return: True when the soft reset is success, false otherwise.
1340f061178eSKashyap Desai  */
1341f061178eSKashyap Desai static inline bool
1342f061178eSKashyap Desai mpi3mr_soft_reset_success(u32 ioc_status, u32 ioc_config)
1343f061178eSKashyap Desai {
1344f061178eSKashyap Desai 	if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) ||
1345f061178eSKashyap Desai 	    (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC)))
1346f061178eSKashyap Desai 		return true;
1347f061178eSKashyap Desai 	return false;
1348f061178eSKashyap Desai }
1349f061178eSKashyap Desai 
1350f061178eSKashyap Desai /**
1351f061178eSKashyap Desai  * mpi3mr_diagfault_success - Check diag fault is success or not
1352f061178eSKashyap Desai  * @mrioc: Adapter reference
1353f061178eSKashyap Desai  * @ioc_status: IOC status register value
1354f061178eSKashyap Desai  *
1355f061178eSKashyap Desai  * Check whether the controller hit diag reset fault code.
1356f061178eSKashyap Desai  *
1357f061178eSKashyap Desai  * Return: True when there is diag fault, false otherwise.
1358f061178eSKashyap Desai  */
1359f061178eSKashyap Desai static inline bool mpi3mr_diagfault_success(struct mpi3mr_ioc *mrioc,
1360f061178eSKashyap Desai 	u32 ioc_status)
1361f061178eSKashyap Desai {
1362f061178eSKashyap Desai 	u32 fault;
1363f061178eSKashyap Desai 
1364f061178eSKashyap Desai 	if (!(ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT))
1365f061178eSKashyap Desai 		return false;
1366f061178eSKashyap Desai 	fault = readl(&mrioc->sysif_regs->fault) & MPI3_SYSIF_FAULT_CODE_MASK;
1367b64845a7SSreekanth Reddy 	if (fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET) {
1368b64845a7SSreekanth Reddy 		mpi3mr_print_fault_info(mrioc);
1369f061178eSKashyap Desai 		return true;
1370b64845a7SSreekanth Reddy 	}
1371f061178eSKashyap Desai 	return false;
1372f061178eSKashyap Desai }
1373f061178eSKashyap Desai 
1374f061178eSKashyap Desai /**
1375824a1566SKashyap Desai  * mpi3mr_set_diagsave - Set diag save bit for snapdump
1376824a1566SKashyap Desai  * @mrioc: Adapter reference
1377824a1566SKashyap Desai  *
1378824a1566SKashyap Desai  * Set diag save bit in IOC configuration register to enable
1379824a1566SKashyap Desai  * snapdump.
1380824a1566SKashyap Desai  *
1381824a1566SKashyap Desai  * Return: Nothing.
1382824a1566SKashyap Desai  */
1383824a1566SKashyap Desai static inline void mpi3mr_set_diagsave(struct mpi3mr_ioc *mrioc)
1384824a1566SKashyap Desai {
1385824a1566SKashyap Desai 	u32 ioc_config;
1386824a1566SKashyap Desai 
1387824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
1388824a1566SKashyap Desai 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_DIAG_SAVE;
1389824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
1390824a1566SKashyap Desai }
1391824a1566SKashyap Desai 
1392824a1566SKashyap Desai /**
1393824a1566SKashyap Desai  * mpi3mr_issue_reset - Issue reset to the controller
1394824a1566SKashyap Desai  * @mrioc: Adapter reference
1395824a1566SKashyap Desai  * @reset_type: Reset type
1396824a1566SKashyap Desai  * @reset_reason: Reset reason code
1397824a1566SKashyap Desai  *
1398f061178eSKashyap Desai  * Unlock the host diagnostic registers and write the specific
1399f061178eSKashyap Desai  * reset type to that, wait for reset acknowledgment from the
1400f061178eSKashyap Desai  * controller, if the reset is not successful retry for the
1401f061178eSKashyap Desai  * predefined number of times.
1402824a1566SKashyap Desai  *
1403824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
1404824a1566SKashyap Desai  */
1405824a1566SKashyap Desai static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type,
1406824a1566SKashyap Desai 	u32 reset_reason)
1407824a1566SKashyap Desai {
1408f061178eSKashyap Desai 	int retval = -1;
1409b64845a7SSreekanth Reddy 	u8 unlock_retry_count = 0;
1410b64845a7SSreekanth Reddy 	u32 host_diagnostic, ioc_status, ioc_config;
1411b64845a7SSreekanth Reddy 	u32 timeout = MPI3MR_RESET_ACK_TIMEOUT * 10;
1412f061178eSKashyap Desai 
1413f061178eSKashyap Desai 	if ((reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET) &&
1414f061178eSKashyap Desai 	    (reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT))
1415b64845a7SSreekanth Reddy 		return retval;
1416f061178eSKashyap Desai 	if (mrioc->unrecoverable)
1417b64845a7SSreekanth Reddy 		return retval;
1418b64845a7SSreekanth Reddy 	if (reset_reason == MPI3MR_RESET_FROM_FIRMWARE) {
1419b64845a7SSreekanth Reddy 		retval = 0;
1420b64845a7SSreekanth Reddy 		return retval;
1421b64845a7SSreekanth Reddy 	}
1422b64845a7SSreekanth Reddy 
1423b64845a7SSreekanth Reddy 	ioc_info(mrioc, "%s reset due to %s(0x%x)\n",
1424b64845a7SSreekanth Reddy 	    mpi3mr_reset_type_name(reset_type),
1425b64845a7SSreekanth Reddy 	    mpi3mr_reset_rc_name(reset_reason), reset_reason);
1426b64845a7SSreekanth Reddy 
1427f061178eSKashyap Desai 	mpi3mr_clear_reset_history(mrioc);
1428f061178eSKashyap Desai 	do {
1429f061178eSKashyap Desai 		ioc_info(mrioc,
1430f061178eSKashyap Desai 		    "Write magic sequence to unlock host diag register (retry=%d)\n",
1431f061178eSKashyap Desai 		    ++unlock_retry_count);
1432f061178eSKashyap Desai 		if (unlock_retry_count >= MPI3MR_HOSTDIAG_UNLOCK_RETRY_COUNT) {
1433b64845a7SSreekanth Reddy 			ioc_err(mrioc,
1434b64845a7SSreekanth Reddy 			    "%s reset failed due to unlock failure, host_diagnostic(0x%08x)\n",
1435b64845a7SSreekanth Reddy 			    mpi3mr_reset_type_name(reset_type),
1436b64845a7SSreekanth Reddy 			    host_diagnostic);
1437f061178eSKashyap Desai 			mrioc->unrecoverable = 1;
1438b64845a7SSreekanth Reddy 			return retval;
1439f061178eSKashyap Desai 		}
1440f061178eSKashyap Desai 
1441f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_FLUSH,
1442f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1443f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_1ST,
1444f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1445f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND,
1446f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1447f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_3RD,
1448f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1449f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_4TH,
1450f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1451f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_5TH,
1452f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1453f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_6TH,
1454f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1455f061178eSKashyap Desai 		usleep_range(1000, 1100);
1456f061178eSKashyap Desai 		host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic);
1457f061178eSKashyap Desai 		ioc_info(mrioc,
1458f061178eSKashyap Desai 		    "wrote magic sequence: retry_count(%d), host_diagnostic(0x%08x)\n",
1459f061178eSKashyap Desai 		    unlock_retry_count, host_diagnostic);
1460f061178eSKashyap Desai 	} while (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_DIAG_WRITE_ENABLE));
1461f061178eSKashyap Desai 
1462f061178eSKashyap Desai 	writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]);
1463f061178eSKashyap Desai 	writel(host_diagnostic | reset_type,
1464f061178eSKashyap Desai 	    &mrioc->sysif_regs->host_diagnostic);
1465b64845a7SSreekanth Reddy 	switch (reset_type) {
1466b64845a7SSreekanth Reddy 	case MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET:
1467f061178eSKashyap Desai 		do {
1468f061178eSKashyap Desai 			ioc_status = readl(&mrioc->sysif_regs->ioc_status);
1469f061178eSKashyap Desai 			ioc_config =
1470f061178eSKashyap Desai 			    readl(&mrioc->sysif_regs->ioc_configuration);
1471b64845a7SSreekanth Reddy 			if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)
1472b64845a7SSreekanth Reddy 			    && mpi3mr_soft_reset_success(ioc_status, ioc_config)
1473b64845a7SSreekanth Reddy 			    ) {
1474b64845a7SSreekanth Reddy 				mpi3mr_clear_reset_history(mrioc);
1475f061178eSKashyap Desai 				retval = 0;
1476f061178eSKashyap Desai 				break;
1477f061178eSKashyap Desai 			}
1478f061178eSKashyap Desai 			msleep(100);
1479f061178eSKashyap Desai 		} while (--timeout);
1480b64845a7SSreekanth Reddy 		mpi3mr_print_fault_info(mrioc);
1481b64845a7SSreekanth Reddy 		break;
1482b64845a7SSreekanth Reddy 	case MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT:
1483f061178eSKashyap Desai 		do {
1484f061178eSKashyap Desai 			ioc_status = readl(&mrioc->sysif_regs->ioc_status);
1485f061178eSKashyap Desai 			if (mpi3mr_diagfault_success(mrioc, ioc_status)) {
1486f061178eSKashyap Desai 				retval = 0;
1487f061178eSKashyap Desai 				break;
1488f061178eSKashyap Desai 			}
1489f061178eSKashyap Desai 			msleep(100);
1490f061178eSKashyap Desai 		} while (--timeout);
1491b64845a7SSreekanth Reddy 		break;
1492b64845a7SSreekanth Reddy 	default:
1493b64845a7SSreekanth Reddy 		break;
1494b64845a7SSreekanth Reddy 	}
1495b64845a7SSreekanth Reddy 
1496f061178eSKashyap Desai 	writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND,
1497f061178eSKashyap Desai 	    &mrioc->sysif_regs->write_sequence);
1498f061178eSKashyap Desai 
1499f061178eSKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
1500b64845a7SSreekanth Reddy 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
1501f061178eSKashyap Desai 	ioc_info(mrioc,
1502b64845a7SSreekanth Reddy 	    "ioc_status/ioc_onfig after %s reset is (0x%x)/(0x%x)\n",
1503f061178eSKashyap Desai 	    (!retval)?"successful":"failed", ioc_status,
1504f061178eSKashyap Desai 	    ioc_config);
1505b64845a7SSreekanth Reddy 	if (retval)
1506b64845a7SSreekanth Reddy 		mrioc->unrecoverable = 1;
1507f061178eSKashyap Desai 	return retval;
1508824a1566SKashyap Desai }
1509824a1566SKashyap Desai 
1510824a1566SKashyap Desai /**
1511824a1566SKashyap Desai  * mpi3mr_admin_request_post - Post request to admin queue
1512824a1566SKashyap Desai  * @mrioc: Adapter reference
1513824a1566SKashyap Desai  * @admin_req: MPI3 request
1514824a1566SKashyap Desai  * @admin_req_sz: Request size
1515824a1566SKashyap Desai  * @ignore_reset: Ignore reset in process
1516824a1566SKashyap Desai  *
1517824a1566SKashyap Desai  * Post the MPI3 request into admin request queue and
1518824a1566SKashyap Desai  * inform the controller, if the queue is full return
1519824a1566SKashyap Desai  * appropriate error.
1520824a1566SKashyap Desai  *
1521824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
1522824a1566SKashyap Desai  */
1523824a1566SKashyap Desai int mpi3mr_admin_request_post(struct mpi3mr_ioc *mrioc, void *admin_req,
1524824a1566SKashyap Desai 	u16 admin_req_sz, u8 ignore_reset)
1525824a1566SKashyap Desai {
1526824a1566SKashyap Desai 	u16 areq_pi = 0, areq_ci = 0, max_entries = 0;
1527824a1566SKashyap Desai 	int retval = 0;
1528824a1566SKashyap Desai 	unsigned long flags;
1529824a1566SKashyap Desai 	u8 *areq_entry;
1530824a1566SKashyap Desai 
1531824a1566SKashyap Desai 	if (mrioc->unrecoverable) {
1532824a1566SKashyap Desai 		ioc_err(mrioc, "%s : Unrecoverable controller\n", __func__);
1533824a1566SKashyap Desai 		return -EFAULT;
1534824a1566SKashyap Desai 	}
1535824a1566SKashyap Desai 
1536824a1566SKashyap Desai 	spin_lock_irqsave(&mrioc->admin_req_lock, flags);
1537824a1566SKashyap Desai 	areq_pi = mrioc->admin_req_pi;
1538824a1566SKashyap Desai 	areq_ci = mrioc->admin_req_ci;
1539824a1566SKashyap Desai 	max_entries = mrioc->num_admin_req;
1540824a1566SKashyap Desai 	if ((areq_ci == (areq_pi + 1)) || ((!areq_ci) &&
1541824a1566SKashyap Desai 	    (areq_pi == (max_entries - 1)))) {
1542824a1566SKashyap Desai 		ioc_err(mrioc, "AdminReqQ full condition detected\n");
1543824a1566SKashyap Desai 		retval = -EAGAIN;
1544824a1566SKashyap Desai 		goto out;
1545824a1566SKashyap Desai 	}
1546824a1566SKashyap Desai 	if (!ignore_reset && mrioc->reset_in_progress) {
1547824a1566SKashyap Desai 		ioc_err(mrioc, "AdminReqQ submit reset in progress\n");
1548824a1566SKashyap Desai 		retval = -EAGAIN;
1549824a1566SKashyap Desai 		goto out;
1550824a1566SKashyap Desai 	}
1551824a1566SKashyap Desai 	areq_entry = (u8 *)mrioc->admin_req_base +
1552824a1566SKashyap Desai 	    (areq_pi * MPI3MR_ADMIN_REQ_FRAME_SZ);
1553824a1566SKashyap Desai 	memset(areq_entry, 0, MPI3MR_ADMIN_REQ_FRAME_SZ);
1554824a1566SKashyap Desai 	memcpy(areq_entry, (u8 *)admin_req, admin_req_sz);
1555824a1566SKashyap Desai 
1556824a1566SKashyap Desai 	if (++areq_pi == max_entries)
1557824a1566SKashyap Desai 		areq_pi = 0;
1558824a1566SKashyap Desai 	mrioc->admin_req_pi = areq_pi;
1559824a1566SKashyap Desai 
1560824a1566SKashyap Desai 	writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi);
1561824a1566SKashyap Desai 
1562824a1566SKashyap Desai out:
1563824a1566SKashyap Desai 	spin_unlock_irqrestore(&mrioc->admin_req_lock, flags);
1564824a1566SKashyap Desai 
1565824a1566SKashyap Desai 	return retval;
1566824a1566SKashyap Desai }
1567824a1566SKashyap Desai 
1568824a1566SKashyap Desai /**
1569c9566231SKashyap Desai  * mpi3mr_free_op_req_q_segments - free request memory segments
1570c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1571c9566231SKashyap Desai  * @q_idx: operational request queue index
1572c9566231SKashyap Desai  *
1573c9566231SKashyap Desai  * Free memory segments allocated for operational request queue
1574c9566231SKashyap Desai  *
1575c9566231SKashyap Desai  * Return: Nothing.
1576c9566231SKashyap Desai  */
1577c9566231SKashyap Desai static void mpi3mr_free_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx)
1578c9566231SKashyap Desai {
1579c9566231SKashyap Desai 	u16 j;
1580c9566231SKashyap Desai 	int size;
1581c9566231SKashyap Desai 	struct segments *segments;
1582c9566231SKashyap Desai 
1583c9566231SKashyap Desai 	segments = mrioc->req_qinfo[q_idx].q_segments;
1584c9566231SKashyap Desai 	if (!segments)
1585c9566231SKashyap Desai 		return;
1586c9566231SKashyap Desai 
1587c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1588c9566231SKashyap Desai 		size = MPI3MR_OP_REQ_Q_SEG_SIZE;
1589c9566231SKashyap Desai 		if (mrioc->req_qinfo[q_idx].q_segment_list) {
1590c9566231SKashyap Desai 			dma_free_coherent(&mrioc->pdev->dev,
1591c9566231SKashyap Desai 			    MPI3MR_MAX_SEG_LIST_SIZE,
1592c9566231SKashyap Desai 			    mrioc->req_qinfo[q_idx].q_segment_list,
1593c9566231SKashyap Desai 			    mrioc->req_qinfo[q_idx].q_segment_list_dma);
1594d44b5fefSSreekanth Reddy 			mrioc->req_qinfo[q_idx].q_segment_list = NULL;
1595c9566231SKashyap Desai 		}
1596c9566231SKashyap Desai 	} else
1597243bcc8eSSreekanth Reddy 		size = mrioc->req_qinfo[q_idx].segment_qd *
1598c9566231SKashyap Desai 		    mrioc->facts.op_req_sz;
1599c9566231SKashyap Desai 
1600c9566231SKashyap Desai 	for (j = 0; j < mrioc->req_qinfo[q_idx].num_segments; j++) {
1601c9566231SKashyap Desai 		if (!segments[j].segment)
1602c9566231SKashyap Desai 			continue;
1603c9566231SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev,
1604c9566231SKashyap Desai 		    size, segments[j].segment, segments[j].segment_dma);
1605c9566231SKashyap Desai 		segments[j].segment = NULL;
1606c9566231SKashyap Desai 	}
1607c9566231SKashyap Desai 	kfree(mrioc->req_qinfo[q_idx].q_segments);
1608c9566231SKashyap Desai 	mrioc->req_qinfo[q_idx].q_segments = NULL;
1609c9566231SKashyap Desai 	mrioc->req_qinfo[q_idx].qid = 0;
1610c9566231SKashyap Desai }
1611c9566231SKashyap Desai 
1612c9566231SKashyap Desai /**
1613c9566231SKashyap Desai  * mpi3mr_free_op_reply_q_segments - free reply memory segments
1614c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1615c9566231SKashyap Desai  * @q_idx: operational reply queue index
1616c9566231SKashyap Desai  *
1617c9566231SKashyap Desai  * Free memory segments allocated for operational reply queue
1618c9566231SKashyap Desai  *
1619c9566231SKashyap Desai  * Return: Nothing.
1620c9566231SKashyap Desai  */
1621c9566231SKashyap Desai static void mpi3mr_free_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx)
1622c9566231SKashyap Desai {
1623c9566231SKashyap Desai 	u16 j;
1624c9566231SKashyap Desai 	int size;
1625c9566231SKashyap Desai 	struct segments *segments;
1626c9566231SKashyap Desai 
1627c9566231SKashyap Desai 	segments = mrioc->op_reply_qinfo[q_idx].q_segments;
1628c9566231SKashyap Desai 	if (!segments)
1629c9566231SKashyap Desai 		return;
1630c9566231SKashyap Desai 
1631c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1632c9566231SKashyap Desai 		size = MPI3MR_OP_REP_Q_SEG_SIZE;
1633c9566231SKashyap Desai 		if (mrioc->op_reply_qinfo[q_idx].q_segment_list) {
1634c9566231SKashyap Desai 			dma_free_coherent(&mrioc->pdev->dev,
1635c9566231SKashyap Desai 			    MPI3MR_MAX_SEG_LIST_SIZE,
1636c9566231SKashyap Desai 			    mrioc->op_reply_qinfo[q_idx].q_segment_list,
1637c9566231SKashyap Desai 			    mrioc->op_reply_qinfo[q_idx].q_segment_list_dma);
1638c9566231SKashyap Desai 			mrioc->op_reply_qinfo[q_idx].q_segment_list = NULL;
1639c9566231SKashyap Desai 		}
1640c9566231SKashyap Desai 	} else
1641c9566231SKashyap Desai 		size = mrioc->op_reply_qinfo[q_idx].segment_qd *
1642c9566231SKashyap Desai 		    mrioc->op_reply_desc_sz;
1643c9566231SKashyap Desai 
1644c9566231SKashyap Desai 	for (j = 0; j < mrioc->op_reply_qinfo[q_idx].num_segments; j++) {
1645c9566231SKashyap Desai 		if (!segments[j].segment)
1646c9566231SKashyap Desai 			continue;
1647c9566231SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev,
1648c9566231SKashyap Desai 		    size, segments[j].segment, segments[j].segment_dma);
1649c9566231SKashyap Desai 		segments[j].segment = NULL;
1650c9566231SKashyap Desai 	}
1651c9566231SKashyap Desai 
1652c9566231SKashyap Desai 	kfree(mrioc->op_reply_qinfo[q_idx].q_segments);
1653c9566231SKashyap Desai 	mrioc->op_reply_qinfo[q_idx].q_segments = NULL;
1654c9566231SKashyap Desai 	mrioc->op_reply_qinfo[q_idx].qid = 0;
1655c9566231SKashyap Desai }
1656c9566231SKashyap Desai 
1657c9566231SKashyap Desai /**
1658c9566231SKashyap Desai  * mpi3mr_delete_op_reply_q - delete operational reply queue
1659c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1660c9566231SKashyap Desai  * @qidx: operational reply queue index
1661c9566231SKashyap Desai  *
1662c9566231SKashyap Desai  * Delete operatinal reply queue by issuing MPI request
1663c9566231SKashyap Desai  * through admin queue.
1664c9566231SKashyap Desai  *
1665c9566231SKashyap Desai  * Return:  0 on success, non-zero on failure.
1666c9566231SKashyap Desai  */
1667c9566231SKashyap Desai static int mpi3mr_delete_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx)
1668c9566231SKashyap Desai {
1669c9566231SKashyap Desai 	struct mpi3_delete_reply_queue_request delq_req;
1670afd3a579SSreekanth Reddy 	struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
1671c9566231SKashyap Desai 	int retval = 0;
1672c9566231SKashyap Desai 	u16 reply_qid = 0, midx;
1673c9566231SKashyap Desai 
1674afd3a579SSreekanth Reddy 	reply_qid = op_reply_q->qid;
1675c9566231SKashyap Desai 
1676c9566231SKashyap Desai 	midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset);
1677c9566231SKashyap Desai 
1678c9566231SKashyap Desai 	if (!reply_qid)	{
1679c9566231SKashyap Desai 		retval = -1;
1680c9566231SKashyap Desai 		ioc_err(mrioc, "Issue DelRepQ: called with invalid ReqQID\n");
1681c9566231SKashyap Desai 		goto out;
1682c9566231SKashyap Desai 	}
1683c9566231SKashyap Desai 
1684afd3a579SSreekanth Reddy 	(op_reply_q->qtype == MPI3MR_DEFAULT_QUEUE) ? mrioc->default_qcount-- :
1685afd3a579SSreekanth Reddy 	    mrioc->active_poll_qcount--;
1686afd3a579SSreekanth Reddy 
1687c9566231SKashyap Desai 	memset(&delq_req, 0, sizeof(delq_req));
1688c9566231SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
1689c9566231SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
1690c9566231SKashyap Desai 		retval = -1;
1691c9566231SKashyap Desai 		ioc_err(mrioc, "Issue DelRepQ: Init command is in use\n");
1692c9566231SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
1693c9566231SKashyap Desai 		goto out;
1694c9566231SKashyap Desai 	}
1695c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
1696c9566231SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
1697c9566231SKashyap Desai 	mrioc->init_cmds.callback = NULL;
1698c9566231SKashyap Desai 	delq_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
1699c9566231SKashyap Desai 	delq_req.function = MPI3_FUNCTION_DELETE_REPLY_QUEUE;
1700c9566231SKashyap Desai 	delq_req.queue_id = cpu_to_le16(reply_qid);
1701c9566231SKashyap Desai 
1702c9566231SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
1703c9566231SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &delq_req, sizeof(delq_req),
1704c9566231SKashyap Desai 	    1);
1705c9566231SKashyap Desai 	if (retval) {
1706c9566231SKashyap Desai 		ioc_err(mrioc, "Issue DelRepQ: Admin Post failed\n");
1707c9566231SKashyap Desai 		goto out_unlock;
1708c9566231SKashyap Desai 	}
1709c9566231SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
1710c9566231SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
1711c9566231SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
1712a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "delete reply queue timed out\n");
1713a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
1714c9566231SKashyap Desai 		    MPI3MR_RESET_FROM_DELREPQ_TIMEOUT);
1715c9566231SKashyap Desai 		retval = -1;
1716c9566231SKashyap Desai 		goto out_unlock;
1717c9566231SKashyap Desai 	}
1718c9566231SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
1719c9566231SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
1720c9566231SKashyap Desai 		ioc_err(mrioc,
1721c9566231SKashyap Desai 		    "Issue DelRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
1722c9566231SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
1723c9566231SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
1724c9566231SKashyap Desai 		retval = -1;
1725c9566231SKashyap Desai 		goto out_unlock;
1726c9566231SKashyap Desai 	}
1727c9566231SKashyap Desai 	mrioc->intr_info[midx].op_reply_q = NULL;
1728c9566231SKashyap Desai 
1729c9566231SKashyap Desai 	mpi3mr_free_op_reply_q_segments(mrioc, qidx);
1730c9566231SKashyap Desai out_unlock:
1731c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
1732c9566231SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
1733c9566231SKashyap Desai out:
1734c9566231SKashyap Desai 
1735c9566231SKashyap Desai 	return retval;
1736c9566231SKashyap Desai }
1737c9566231SKashyap Desai 
1738c9566231SKashyap Desai /**
1739c9566231SKashyap Desai  * mpi3mr_alloc_op_reply_q_segments -Alloc segmented reply pool
1740c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1741c9566231SKashyap Desai  * @qidx: request queue index
1742c9566231SKashyap Desai  *
1743c9566231SKashyap Desai  * Allocate segmented memory pools for operational reply
1744c9566231SKashyap Desai  * queue.
1745c9566231SKashyap Desai  *
1746c9566231SKashyap Desai  * Return: 0 on success, non-zero on failure.
1747c9566231SKashyap Desai  */
1748c9566231SKashyap Desai static int mpi3mr_alloc_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx)
1749c9566231SKashyap Desai {
1750c9566231SKashyap Desai 	struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
1751c9566231SKashyap Desai 	int i, size;
1752c9566231SKashyap Desai 	u64 *q_segment_list_entry = NULL;
1753c9566231SKashyap Desai 	struct segments *segments;
1754c9566231SKashyap Desai 
1755c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1756c9566231SKashyap Desai 		op_reply_q->segment_qd =
1757c9566231SKashyap Desai 		    MPI3MR_OP_REP_Q_SEG_SIZE / mrioc->op_reply_desc_sz;
1758c9566231SKashyap Desai 
1759c9566231SKashyap Desai 		size = MPI3MR_OP_REP_Q_SEG_SIZE;
1760c9566231SKashyap Desai 
1761c9566231SKashyap Desai 		op_reply_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev,
1762c9566231SKashyap Desai 		    MPI3MR_MAX_SEG_LIST_SIZE, &op_reply_q->q_segment_list_dma,
1763c9566231SKashyap Desai 		    GFP_KERNEL);
1764c9566231SKashyap Desai 		if (!op_reply_q->q_segment_list)
1765c9566231SKashyap Desai 			return -ENOMEM;
1766c9566231SKashyap Desai 		q_segment_list_entry = (u64 *)op_reply_q->q_segment_list;
1767c9566231SKashyap Desai 	} else {
1768c9566231SKashyap Desai 		op_reply_q->segment_qd = op_reply_q->num_replies;
1769c9566231SKashyap Desai 		size = op_reply_q->num_replies * mrioc->op_reply_desc_sz;
1770c9566231SKashyap Desai 	}
1771c9566231SKashyap Desai 
1772c9566231SKashyap Desai 	op_reply_q->num_segments = DIV_ROUND_UP(op_reply_q->num_replies,
1773c9566231SKashyap Desai 	    op_reply_q->segment_qd);
1774c9566231SKashyap Desai 
1775c9566231SKashyap Desai 	op_reply_q->q_segments = kcalloc(op_reply_q->num_segments,
1776c9566231SKashyap Desai 	    sizeof(struct segments), GFP_KERNEL);
1777c9566231SKashyap Desai 	if (!op_reply_q->q_segments)
1778c9566231SKashyap Desai 		return -ENOMEM;
1779c9566231SKashyap Desai 
1780c9566231SKashyap Desai 	segments = op_reply_q->q_segments;
1781c9566231SKashyap Desai 	for (i = 0; i < op_reply_q->num_segments; i++) {
1782c9566231SKashyap Desai 		segments[i].segment =
1783c9566231SKashyap Desai 		    dma_alloc_coherent(&mrioc->pdev->dev,
1784c9566231SKashyap Desai 		    size, &segments[i].segment_dma, GFP_KERNEL);
1785c9566231SKashyap Desai 		if (!segments[i].segment)
1786c9566231SKashyap Desai 			return -ENOMEM;
1787c9566231SKashyap Desai 		if (mrioc->enable_segqueue)
1788c9566231SKashyap Desai 			q_segment_list_entry[i] =
1789c9566231SKashyap Desai 			    (unsigned long)segments[i].segment_dma;
1790c9566231SKashyap Desai 	}
1791c9566231SKashyap Desai 
1792c9566231SKashyap Desai 	return 0;
1793c9566231SKashyap Desai }
1794c9566231SKashyap Desai 
1795c9566231SKashyap Desai /**
1796c9566231SKashyap Desai  * mpi3mr_alloc_op_req_q_segments - Alloc segmented req pool.
1797c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1798c9566231SKashyap Desai  * @qidx: request queue index
1799c9566231SKashyap Desai  *
1800c9566231SKashyap Desai  * Allocate segmented memory pools for operational request
1801c9566231SKashyap Desai  * queue.
1802c9566231SKashyap Desai  *
1803c9566231SKashyap Desai  * Return: 0 on success, non-zero on failure.
1804c9566231SKashyap Desai  */
1805c9566231SKashyap Desai static int mpi3mr_alloc_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx)
1806c9566231SKashyap Desai {
1807c9566231SKashyap Desai 	struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx;
1808c9566231SKashyap Desai 	int i, size;
1809c9566231SKashyap Desai 	u64 *q_segment_list_entry = NULL;
1810c9566231SKashyap Desai 	struct segments *segments;
1811c9566231SKashyap Desai 
1812c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1813c9566231SKashyap Desai 		op_req_q->segment_qd =
1814c9566231SKashyap Desai 		    MPI3MR_OP_REQ_Q_SEG_SIZE / mrioc->facts.op_req_sz;
1815c9566231SKashyap Desai 
1816c9566231SKashyap Desai 		size = MPI3MR_OP_REQ_Q_SEG_SIZE;
1817c9566231SKashyap Desai 
1818c9566231SKashyap Desai 		op_req_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev,
1819c9566231SKashyap Desai 		    MPI3MR_MAX_SEG_LIST_SIZE, &op_req_q->q_segment_list_dma,
1820c9566231SKashyap Desai 		    GFP_KERNEL);
1821c9566231SKashyap Desai 		if (!op_req_q->q_segment_list)
1822c9566231SKashyap Desai 			return -ENOMEM;
1823c9566231SKashyap Desai 		q_segment_list_entry = (u64 *)op_req_q->q_segment_list;
1824c9566231SKashyap Desai 
1825c9566231SKashyap Desai 	} else {
1826c9566231SKashyap Desai 		op_req_q->segment_qd = op_req_q->num_requests;
1827c9566231SKashyap Desai 		size = op_req_q->num_requests * mrioc->facts.op_req_sz;
1828c9566231SKashyap Desai 	}
1829c9566231SKashyap Desai 
1830c9566231SKashyap Desai 	op_req_q->num_segments = DIV_ROUND_UP(op_req_q->num_requests,
1831c9566231SKashyap Desai 	    op_req_q->segment_qd);
1832c9566231SKashyap Desai 
1833c9566231SKashyap Desai 	op_req_q->q_segments = kcalloc(op_req_q->num_segments,
1834c9566231SKashyap Desai 	    sizeof(struct segments), GFP_KERNEL);
1835c9566231SKashyap Desai 	if (!op_req_q->q_segments)
1836c9566231SKashyap Desai 		return -ENOMEM;
1837c9566231SKashyap Desai 
1838c9566231SKashyap Desai 	segments = op_req_q->q_segments;
1839c9566231SKashyap Desai 	for (i = 0; i < op_req_q->num_segments; i++) {
1840c9566231SKashyap Desai 		segments[i].segment =
1841c9566231SKashyap Desai 		    dma_alloc_coherent(&mrioc->pdev->dev,
1842c9566231SKashyap Desai 		    size, &segments[i].segment_dma, GFP_KERNEL);
1843c9566231SKashyap Desai 		if (!segments[i].segment)
1844c9566231SKashyap Desai 			return -ENOMEM;
1845c9566231SKashyap Desai 		if (mrioc->enable_segqueue)
1846c9566231SKashyap Desai 			q_segment_list_entry[i] =
1847c9566231SKashyap Desai 			    (unsigned long)segments[i].segment_dma;
1848c9566231SKashyap Desai 	}
1849c9566231SKashyap Desai 
1850c9566231SKashyap Desai 	return 0;
1851c9566231SKashyap Desai }
1852c9566231SKashyap Desai 
1853c9566231SKashyap Desai /**
1854c9566231SKashyap Desai  * mpi3mr_create_op_reply_q - create operational reply queue
1855c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1856c9566231SKashyap Desai  * @qidx: operational reply queue index
1857c9566231SKashyap Desai  *
1858c9566231SKashyap Desai  * Create operatinal reply queue by issuing MPI request
1859c9566231SKashyap Desai  * through admin queue.
1860c9566231SKashyap Desai  *
1861c9566231SKashyap Desai  * Return:  0 on success, non-zero on failure.
1862c9566231SKashyap Desai  */
1863c9566231SKashyap Desai static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx)
1864c9566231SKashyap Desai {
1865c9566231SKashyap Desai 	struct mpi3_create_reply_queue_request create_req;
1866c9566231SKashyap Desai 	struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
1867c9566231SKashyap Desai 	int retval = 0;
1868c9566231SKashyap Desai 	u16 reply_qid = 0, midx;
1869c9566231SKashyap Desai 
1870c9566231SKashyap Desai 	reply_qid = op_reply_q->qid;
1871c9566231SKashyap Desai 
1872c9566231SKashyap Desai 	midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset);
1873c9566231SKashyap Desai 
1874c9566231SKashyap Desai 	if (reply_qid) {
1875c9566231SKashyap Desai 		retval = -1;
1876c9566231SKashyap Desai 		ioc_err(mrioc, "CreateRepQ: called for duplicate qid %d\n",
1877c9566231SKashyap Desai 		    reply_qid);
1878c9566231SKashyap Desai 
1879c9566231SKashyap Desai 		return retval;
1880c9566231SKashyap Desai 	}
1881c9566231SKashyap Desai 
1882c9566231SKashyap Desai 	reply_qid = qidx + 1;
1883c9566231SKashyap Desai 	op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD;
1884243bcc8eSSreekanth Reddy 	if (!mrioc->pdev->revision)
1885243bcc8eSSreekanth Reddy 		op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD4K;
1886c9566231SKashyap Desai 	op_reply_q->ci = 0;
1887c9566231SKashyap Desai 	op_reply_q->ephase = 1;
1888463429f8SKashyap Desai 	atomic_set(&op_reply_q->pend_ios, 0);
1889463429f8SKashyap Desai 	atomic_set(&op_reply_q->in_use, 0);
1890463429f8SKashyap Desai 	op_reply_q->enable_irq_poll = false;
1891c9566231SKashyap Desai 
1892c9566231SKashyap Desai 	if (!op_reply_q->q_segments) {
1893c9566231SKashyap Desai 		retval = mpi3mr_alloc_op_reply_q_segments(mrioc, qidx);
1894c9566231SKashyap Desai 		if (retval) {
1895c9566231SKashyap Desai 			mpi3mr_free_op_reply_q_segments(mrioc, qidx);
1896c9566231SKashyap Desai 			goto out;
1897c9566231SKashyap Desai 		}
1898c9566231SKashyap Desai 	}
1899c9566231SKashyap Desai 
1900c9566231SKashyap Desai 	memset(&create_req, 0, sizeof(create_req));
1901c9566231SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
1902c9566231SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
1903c9566231SKashyap Desai 		retval = -1;
1904c9566231SKashyap Desai 		ioc_err(mrioc, "CreateRepQ: Init command is in use\n");
1905f9dc034dSYang Yingliang 		goto out_unlock;
1906c9566231SKashyap Desai 	}
1907c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
1908c9566231SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
1909c9566231SKashyap Desai 	mrioc->init_cmds.callback = NULL;
1910c9566231SKashyap Desai 	create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
1911c9566231SKashyap Desai 	create_req.function = MPI3_FUNCTION_CREATE_REPLY_QUEUE;
1912c9566231SKashyap Desai 	create_req.queue_id = cpu_to_le16(reply_qid);
1913afd3a579SSreekanth Reddy 
1914afd3a579SSreekanth Reddy 	if (midx < (mrioc->intr_info_count - mrioc->requested_poll_qcount))
1915afd3a579SSreekanth Reddy 		op_reply_q->qtype = MPI3MR_DEFAULT_QUEUE;
1916afd3a579SSreekanth Reddy 	else
1917afd3a579SSreekanth Reddy 		op_reply_q->qtype = MPI3MR_POLL_QUEUE;
1918afd3a579SSreekanth Reddy 
1919afd3a579SSreekanth Reddy 	if (op_reply_q->qtype == MPI3MR_DEFAULT_QUEUE) {
1920afd3a579SSreekanth Reddy 		create_req.flags =
1921afd3a579SSreekanth Reddy 			MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_ENABLE;
1922afd3a579SSreekanth Reddy 		create_req.msix_index =
1923afd3a579SSreekanth Reddy 			cpu_to_le16(mrioc->intr_info[midx].msix_index);
1924afd3a579SSreekanth Reddy 	} else {
1925afd3a579SSreekanth Reddy 		create_req.msix_index = cpu_to_le16(mrioc->intr_info_count - 1);
1926afd3a579SSreekanth Reddy 		ioc_info(mrioc, "create reply queue(polled): for qid(%d), midx(%d)\n",
1927afd3a579SSreekanth Reddy 			reply_qid, midx);
1928afd3a579SSreekanth Reddy 		if (!mrioc->active_poll_qcount)
1929afd3a579SSreekanth Reddy 			disable_irq_nosync(pci_irq_vector(mrioc->pdev,
1930afd3a579SSreekanth Reddy 			    mrioc->intr_info_count - 1));
1931afd3a579SSreekanth Reddy 	}
1932afd3a579SSreekanth Reddy 
1933c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1934c9566231SKashyap Desai 		create_req.flags |=
1935c9566231SKashyap Desai 		    MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED;
1936c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
1937c9566231SKashyap Desai 		    op_reply_q->q_segment_list_dma);
1938c9566231SKashyap Desai 	} else
1939c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
1940c9566231SKashyap Desai 		    op_reply_q->q_segments[0].segment_dma);
1941c9566231SKashyap Desai 
1942c9566231SKashyap Desai 	create_req.size = cpu_to_le16(op_reply_q->num_replies);
1943c9566231SKashyap Desai 
1944c9566231SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
1945c9566231SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &create_req,
1946c9566231SKashyap Desai 	    sizeof(create_req), 1);
1947c9566231SKashyap Desai 	if (retval) {
1948c9566231SKashyap Desai 		ioc_err(mrioc, "CreateRepQ: Admin Post failed\n");
1949c9566231SKashyap Desai 		goto out_unlock;
1950c9566231SKashyap Desai 	}
1951c9566231SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
1952c9566231SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
1953c9566231SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
1954a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "create reply queue timed out\n");
1955a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
1956c9566231SKashyap Desai 		    MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT);
1957c9566231SKashyap Desai 		retval = -1;
1958c9566231SKashyap Desai 		goto out_unlock;
1959c9566231SKashyap Desai 	}
1960c9566231SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
1961c9566231SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
1962c9566231SKashyap Desai 		ioc_err(mrioc,
1963c9566231SKashyap Desai 		    "CreateRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
1964c9566231SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
1965c9566231SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
1966c9566231SKashyap Desai 		retval = -1;
1967c9566231SKashyap Desai 		goto out_unlock;
1968c9566231SKashyap Desai 	}
1969c9566231SKashyap Desai 	op_reply_q->qid = reply_qid;
1970fe6db615SSreekanth Reddy 	if (midx < mrioc->intr_info_count)
1971c9566231SKashyap Desai 		mrioc->intr_info[midx].op_reply_q = op_reply_q;
1972c9566231SKashyap Desai 
1973afd3a579SSreekanth Reddy 	(op_reply_q->qtype == MPI3MR_DEFAULT_QUEUE) ? mrioc->default_qcount++ :
1974afd3a579SSreekanth Reddy 	    mrioc->active_poll_qcount++;
1975afd3a579SSreekanth Reddy 
1976c9566231SKashyap Desai out_unlock:
1977c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
1978c9566231SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
1979c9566231SKashyap Desai out:
1980c9566231SKashyap Desai 
1981c9566231SKashyap Desai 	return retval;
1982c9566231SKashyap Desai }
1983c9566231SKashyap Desai 
1984c9566231SKashyap Desai /**
1985c9566231SKashyap Desai  * mpi3mr_create_op_req_q - create operational request queue
1986c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1987c9566231SKashyap Desai  * @idx: operational request queue index
1988c9566231SKashyap Desai  * @reply_qid: Reply queue ID
1989c9566231SKashyap Desai  *
1990c9566231SKashyap Desai  * Create operatinal request queue by issuing MPI request
1991c9566231SKashyap Desai  * through admin queue.
1992c9566231SKashyap Desai  *
1993c9566231SKashyap Desai  * Return:  0 on success, non-zero on failure.
1994c9566231SKashyap Desai  */
1995c9566231SKashyap Desai static int mpi3mr_create_op_req_q(struct mpi3mr_ioc *mrioc, u16 idx,
1996c9566231SKashyap Desai 	u16 reply_qid)
1997c9566231SKashyap Desai {
1998c9566231SKashyap Desai 	struct mpi3_create_request_queue_request create_req;
1999c9566231SKashyap Desai 	struct op_req_qinfo *op_req_q = mrioc->req_qinfo + idx;
2000c9566231SKashyap Desai 	int retval = 0;
2001c9566231SKashyap Desai 	u16 req_qid = 0;
2002c9566231SKashyap Desai 
2003c9566231SKashyap Desai 	req_qid = op_req_q->qid;
2004c9566231SKashyap Desai 
2005c9566231SKashyap Desai 	if (req_qid) {
2006c9566231SKashyap Desai 		retval = -1;
2007c9566231SKashyap Desai 		ioc_err(mrioc, "CreateReqQ: called for duplicate qid %d\n",
2008c9566231SKashyap Desai 		    req_qid);
2009c9566231SKashyap Desai 
2010c9566231SKashyap Desai 		return retval;
2011c9566231SKashyap Desai 	}
2012c9566231SKashyap Desai 	req_qid = idx + 1;
2013c9566231SKashyap Desai 
2014c9566231SKashyap Desai 	op_req_q->num_requests = MPI3MR_OP_REQ_Q_QD;
2015c9566231SKashyap Desai 	op_req_q->ci = 0;
2016c9566231SKashyap Desai 	op_req_q->pi = 0;
2017c9566231SKashyap Desai 	op_req_q->reply_qid = reply_qid;
2018c9566231SKashyap Desai 	spin_lock_init(&op_req_q->q_lock);
2019c9566231SKashyap Desai 
2020c9566231SKashyap Desai 	if (!op_req_q->q_segments) {
2021c9566231SKashyap Desai 		retval = mpi3mr_alloc_op_req_q_segments(mrioc, idx);
2022c9566231SKashyap Desai 		if (retval) {
2023c9566231SKashyap Desai 			mpi3mr_free_op_req_q_segments(mrioc, idx);
2024c9566231SKashyap Desai 			goto out;
2025c9566231SKashyap Desai 		}
2026c9566231SKashyap Desai 	}
2027c9566231SKashyap Desai 
2028c9566231SKashyap Desai 	memset(&create_req, 0, sizeof(create_req));
2029c9566231SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
2030c9566231SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
2031c9566231SKashyap Desai 		retval = -1;
2032c9566231SKashyap Desai 		ioc_err(mrioc, "CreateReqQ: Init command is in use\n");
2033f9dc034dSYang Yingliang 		goto out_unlock;
2034c9566231SKashyap Desai 	}
2035c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
2036c9566231SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
2037c9566231SKashyap Desai 	mrioc->init_cmds.callback = NULL;
2038c9566231SKashyap Desai 	create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
2039c9566231SKashyap Desai 	create_req.function = MPI3_FUNCTION_CREATE_REQUEST_QUEUE;
2040c9566231SKashyap Desai 	create_req.queue_id = cpu_to_le16(req_qid);
2041c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
2042c9566231SKashyap Desai 		create_req.flags =
2043c9566231SKashyap Desai 		    MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED;
2044c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
2045c9566231SKashyap Desai 		    op_req_q->q_segment_list_dma);
2046c9566231SKashyap Desai 	} else
2047c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
2048c9566231SKashyap Desai 		    op_req_q->q_segments[0].segment_dma);
2049c9566231SKashyap Desai 	create_req.reply_queue_id = cpu_to_le16(reply_qid);
2050c9566231SKashyap Desai 	create_req.size = cpu_to_le16(op_req_q->num_requests);
2051c9566231SKashyap Desai 
2052c9566231SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
2053c9566231SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &create_req,
2054c9566231SKashyap Desai 	    sizeof(create_req), 1);
2055c9566231SKashyap Desai 	if (retval) {
2056c9566231SKashyap Desai 		ioc_err(mrioc, "CreateReqQ: Admin Post failed\n");
2057c9566231SKashyap Desai 		goto out_unlock;
2058c9566231SKashyap Desai 	}
2059c9566231SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
2060c9566231SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
2061c9566231SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
2062a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "create request queue timed out\n");
2063a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
2064a6856cc4SSreekanth Reddy 		    MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT);
2065c9566231SKashyap Desai 		retval = -1;
2066c9566231SKashyap Desai 		goto out_unlock;
2067c9566231SKashyap Desai 	}
2068c9566231SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
2069c9566231SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
2070c9566231SKashyap Desai 		ioc_err(mrioc,
2071c9566231SKashyap Desai 		    "CreateReqQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
2072c9566231SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
2073c9566231SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
2074c9566231SKashyap Desai 		retval = -1;
2075c9566231SKashyap Desai 		goto out_unlock;
2076c9566231SKashyap Desai 	}
2077c9566231SKashyap Desai 	op_req_q->qid = req_qid;
2078c9566231SKashyap Desai 
2079c9566231SKashyap Desai out_unlock:
2080c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
2081c9566231SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
2082c9566231SKashyap Desai out:
2083c9566231SKashyap Desai 
2084c9566231SKashyap Desai 	return retval;
2085c9566231SKashyap Desai }
2086c9566231SKashyap Desai 
2087c9566231SKashyap Desai /**
2088c9566231SKashyap Desai  * mpi3mr_create_op_queues - create operational queue pairs
2089c9566231SKashyap Desai  * @mrioc: Adapter instance reference
2090c9566231SKashyap Desai  *
2091c9566231SKashyap Desai  * Allocate memory for operational queue meta data and call
2092c9566231SKashyap Desai  * create request and reply queue functions.
2093c9566231SKashyap Desai  *
2094c9566231SKashyap Desai  * Return: 0 on success, non-zero on failures.
2095c9566231SKashyap Desai  */
2096c9566231SKashyap Desai static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc)
2097c9566231SKashyap Desai {
2098c9566231SKashyap Desai 	int retval = 0;
2099c9566231SKashyap Desai 	u16 num_queues = 0, i = 0, msix_count_op_q = 1;
2100c9566231SKashyap Desai 
2101c9566231SKashyap Desai 	num_queues = min_t(int, mrioc->facts.max_op_reply_q,
2102c9566231SKashyap Desai 	    mrioc->facts.max_op_req_q);
2103c9566231SKashyap Desai 
2104c9566231SKashyap Desai 	msix_count_op_q =
2105c9566231SKashyap Desai 	    mrioc->intr_info_count - mrioc->op_reply_q_offset;
2106c9566231SKashyap Desai 	if (!mrioc->num_queues)
2107c9566231SKashyap Desai 		mrioc->num_queues = min_t(int, num_queues, msix_count_op_q);
2108c5758fc7SSreekanth Reddy 	/*
2109c5758fc7SSreekanth Reddy 	 * During reset set the num_queues to the number of queues
2110c5758fc7SSreekanth Reddy 	 * that was set before the reset.
2111c5758fc7SSreekanth Reddy 	 */
2112c5758fc7SSreekanth Reddy 	num_queues = mrioc->num_op_reply_q ?
2113c5758fc7SSreekanth Reddy 	    mrioc->num_op_reply_q : mrioc->num_queues;
2114c5758fc7SSreekanth Reddy 	ioc_info(mrioc, "trying to create %d operational queue pairs\n",
2115c9566231SKashyap Desai 	    num_queues);
2116c9566231SKashyap Desai 
2117c9566231SKashyap Desai 	if (!mrioc->req_qinfo) {
2118c9566231SKashyap Desai 		mrioc->req_qinfo = kcalloc(num_queues,
2119c9566231SKashyap Desai 		    sizeof(struct op_req_qinfo), GFP_KERNEL);
2120c9566231SKashyap Desai 		if (!mrioc->req_qinfo) {
2121c9566231SKashyap Desai 			retval = -1;
2122c9566231SKashyap Desai 			goto out_failed;
2123c9566231SKashyap Desai 		}
2124c9566231SKashyap Desai 
2125c9566231SKashyap Desai 		mrioc->op_reply_qinfo = kzalloc(sizeof(struct op_reply_qinfo) *
2126c9566231SKashyap Desai 		    num_queues, GFP_KERNEL);
2127c9566231SKashyap Desai 		if (!mrioc->op_reply_qinfo) {
2128c9566231SKashyap Desai 			retval = -1;
2129c9566231SKashyap Desai 			goto out_failed;
2130c9566231SKashyap Desai 		}
2131c9566231SKashyap Desai 	}
2132c9566231SKashyap Desai 
2133c9566231SKashyap Desai 	if (mrioc->enable_segqueue)
2134c9566231SKashyap Desai 		ioc_info(mrioc,
2135c9566231SKashyap Desai 		    "allocating operational queues through segmented queues\n");
2136c9566231SKashyap Desai 
2137c9566231SKashyap Desai 	for (i = 0; i < num_queues; i++) {
2138c9566231SKashyap Desai 		if (mpi3mr_create_op_reply_q(mrioc, i)) {
2139c9566231SKashyap Desai 			ioc_err(mrioc, "Cannot create OP RepQ %d\n", i);
2140c9566231SKashyap Desai 			break;
2141c9566231SKashyap Desai 		}
2142c9566231SKashyap Desai 		if (mpi3mr_create_op_req_q(mrioc, i,
2143c9566231SKashyap Desai 		    mrioc->op_reply_qinfo[i].qid)) {
2144c9566231SKashyap Desai 			ioc_err(mrioc, "Cannot create OP ReqQ %d\n", i);
2145c9566231SKashyap Desai 			mpi3mr_delete_op_reply_q(mrioc, i);
2146c9566231SKashyap Desai 			break;
2147c9566231SKashyap Desai 		}
2148c9566231SKashyap Desai 	}
2149c9566231SKashyap Desai 
2150c9566231SKashyap Desai 	if (i == 0) {
2151c9566231SKashyap Desai 		/* Not even one queue is created successfully*/
2152c9566231SKashyap Desai 		retval = -1;
2153c9566231SKashyap Desai 		goto out_failed;
2154c9566231SKashyap Desai 	}
2155c9566231SKashyap Desai 	mrioc->num_op_reply_q = mrioc->num_op_req_q = i;
2156afd3a579SSreekanth Reddy 	ioc_info(mrioc,
2157afd3a579SSreekanth Reddy 	    "successfully created %d operational queue pairs(default/polled) queue = (%d/%d)\n",
2158afd3a579SSreekanth Reddy 	    mrioc->num_op_reply_q, mrioc->default_qcount,
2159afd3a579SSreekanth Reddy 	    mrioc->active_poll_qcount);
2160c9566231SKashyap Desai 
2161c9566231SKashyap Desai 	return retval;
2162c9566231SKashyap Desai out_failed:
2163c9566231SKashyap Desai 	kfree(mrioc->req_qinfo);
2164c9566231SKashyap Desai 	mrioc->req_qinfo = NULL;
2165c9566231SKashyap Desai 
2166c9566231SKashyap Desai 	kfree(mrioc->op_reply_qinfo);
2167c9566231SKashyap Desai 	mrioc->op_reply_qinfo = NULL;
2168c9566231SKashyap Desai 
2169c9566231SKashyap Desai 	return retval;
2170c9566231SKashyap Desai }
2171c9566231SKashyap Desai 
2172c9566231SKashyap Desai /**
2173023ab2a9SKashyap Desai  * mpi3mr_op_request_post - Post request to operational queue
2174023ab2a9SKashyap Desai  * @mrioc: Adapter reference
2175023ab2a9SKashyap Desai  * @op_req_q: Operational request queue info
2176023ab2a9SKashyap Desai  * @req: MPI3 request
2177023ab2a9SKashyap Desai  *
2178023ab2a9SKashyap Desai  * Post the MPI3 request into operational request queue and
2179023ab2a9SKashyap Desai  * inform the controller, if the queue is full return
2180023ab2a9SKashyap Desai  * appropriate error.
2181023ab2a9SKashyap Desai  *
2182023ab2a9SKashyap Desai  * Return: 0 on success, non-zero on failure.
2183023ab2a9SKashyap Desai  */
2184023ab2a9SKashyap Desai int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc,
2185023ab2a9SKashyap Desai 	struct op_req_qinfo *op_req_q, u8 *req)
2186023ab2a9SKashyap Desai {
2187023ab2a9SKashyap Desai 	u16 pi = 0, max_entries, reply_qidx = 0, midx;
2188023ab2a9SKashyap Desai 	int retval = 0;
2189023ab2a9SKashyap Desai 	unsigned long flags;
2190023ab2a9SKashyap Desai 	u8 *req_entry;
2191023ab2a9SKashyap Desai 	void *segment_base_addr;
2192023ab2a9SKashyap Desai 	u16 req_sz = mrioc->facts.op_req_sz;
2193023ab2a9SKashyap Desai 	struct segments *segments = op_req_q->q_segments;
2194023ab2a9SKashyap Desai 
2195023ab2a9SKashyap Desai 	reply_qidx = op_req_q->reply_qid - 1;
2196023ab2a9SKashyap Desai 
2197023ab2a9SKashyap Desai 	if (mrioc->unrecoverable)
2198023ab2a9SKashyap Desai 		return -EFAULT;
2199023ab2a9SKashyap Desai 
2200023ab2a9SKashyap Desai 	spin_lock_irqsave(&op_req_q->q_lock, flags);
2201023ab2a9SKashyap Desai 	pi = op_req_q->pi;
2202023ab2a9SKashyap Desai 	max_entries = op_req_q->num_requests;
2203023ab2a9SKashyap Desai 
2204023ab2a9SKashyap Desai 	if (mpi3mr_check_req_qfull(op_req_q)) {
2205023ab2a9SKashyap Desai 		midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(
2206023ab2a9SKashyap Desai 		    reply_qidx, mrioc->op_reply_q_offset);
2207afd3a579SSreekanth Reddy 		mpi3mr_process_op_reply_q(mrioc, mrioc->intr_info[midx].op_reply_q);
2208023ab2a9SKashyap Desai 
2209023ab2a9SKashyap Desai 		if (mpi3mr_check_req_qfull(op_req_q)) {
2210023ab2a9SKashyap Desai 			retval = -EAGAIN;
2211023ab2a9SKashyap Desai 			goto out;
2212023ab2a9SKashyap Desai 		}
2213023ab2a9SKashyap Desai 	}
2214023ab2a9SKashyap Desai 
2215023ab2a9SKashyap Desai 	if (mrioc->reset_in_progress) {
2216023ab2a9SKashyap Desai 		ioc_err(mrioc, "OpReqQ submit reset in progress\n");
2217023ab2a9SKashyap Desai 		retval = -EAGAIN;
2218023ab2a9SKashyap Desai 		goto out;
2219023ab2a9SKashyap Desai 	}
2220023ab2a9SKashyap Desai 
2221023ab2a9SKashyap Desai 	segment_base_addr = segments[pi / op_req_q->segment_qd].segment;
2222023ab2a9SKashyap Desai 	req_entry = (u8 *)segment_base_addr +
2223023ab2a9SKashyap Desai 	    ((pi % op_req_q->segment_qd) * req_sz);
2224023ab2a9SKashyap Desai 
2225023ab2a9SKashyap Desai 	memset(req_entry, 0, req_sz);
2226023ab2a9SKashyap Desai 	memcpy(req_entry, req, MPI3MR_ADMIN_REQ_FRAME_SZ);
2227023ab2a9SKashyap Desai 
2228023ab2a9SKashyap Desai 	if (++pi == max_entries)
2229023ab2a9SKashyap Desai 		pi = 0;
2230023ab2a9SKashyap Desai 	op_req_q->pi = pi;
2231023ab2a9SKashyap Desai 
22327f9f953dSSreekanth Reddy #ifndef CONFIG_PREEMPT_RT
2233463429f8SKashyap Desai 	if (atomic_inc_return(&mrioc->op_reply_qinfo[reply_qidx].pend_ios)
2234463429f8SKashyap Desai 	    > MPI3MR_IRQ_POLL_TRIGGER_IOCOUNT)
2235463429f8SKashyap Desai 		mrioc->op_reply_qinfo[reply_qidx].enable_irq_poll = true;
22367f9f953dSSreekanth Reddy #else
22377f9f953dSSreekanth Reddy 	atomic_inc_return(&mrioc->op_reply_qinfo[reply_qidx].pend_ios);
22387f9f953dSSreekanth Reddy #endif
2239463429f8SKashyap Desai 
2240023ab2a9SKashyap Desai 	writel(op_req_q->pi,
2241023ab2a9SKashyap Desai 	    &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].producer_index);
2242023ab2a9SKashyap Desai 
2243023ab2a9SKashyap Desai out:
2244023ab2a9SKashyap Desai 	spin_unlock_irqrestore(&op_req_q->q_lock, flags);
2245023ab2a9SKashyap Desai 	return retval;
2246023ab2a9SKashyap Desai }
2247023ab2a9SKashyap Desai 
2248023ab2a9SKashyap Desai /**
2249a6856cc4SSreekanth Reddy  * mpi3mr_check_rh_fault_ioc - check reset history and fault
2250a6856cc4SSreekanth Reddy  * controller
2251a6856cc4SSreekanth Reddy  * @mrioc: Adapter instance reference
22523bb3c24eSYang Li  * @reason_code: reason code for the fault.
2253a6856cc4SSreekanth Reddy  *
2254a6856cc4SSreekanth Reddy  * This routine will save snapdump and fault the controller with
2255a6856cc4SSreekanth Reddy  * the given reason code if it is not already in the fault or
2256a6856cc4SSreekanth Reddy  * not asynchronosuly reset. This will be used to handle
2257a6856cc4SSreekanth Reddy  * initilaization time faults/resets/timeout as in those cases
2258a6856cc4SSreekanth Reddy  * immediate soft reset invocation is not required.
2259a6856cc4SSreekanth Reddy  *
2260a6856cc4SSreekanth Reddy  * Return:  None.
2261a6856cc4SSreekanth Reddy  */
2262a6856cc4SSreekanth Reddy void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code)
2263a6856cc4SSreekanth Reddy {
2264a6856cc4SSreekanth Reddy 	u32 ioc_status, host_diagnostic, timeout;
2265a6856cc4SSreekanth Reddy 
2266f2a79d20SSreekanth Reddy 	if (mrioc->unrecoverable) {
2267f2a79d20SSreekanth Reddy 		ioc_err(mrioc, "controller is unrecoverable\n");
2268f2a79d20SSreekanth Reddy 		return;
2269f2a79d20SSreekanth Reddy 	}
2270f2a79d20SSreekanth Reddy 
2271f2a79d20SSreekanth Reddy 	if (!pci_device_is_present(mrioc->pdev)) {
2272f2a79d20SSreekanth Reddy 		mrioc->unrecoverable = 1;
2273f2a79d20SSreekanth Reddy 		ioc_err(mrioc, "controller is not present\n");
2274f2a79d20SSreekanth Reddy 		return;
2275f2a79d20SSreekanth Reddy 	}
2276f2a79d20SSreekanth Reddy 
2277a6856cc4SSreekanth Reddy 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
2278a6856cc4SSreekanth Reddy 	if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) ||
2279a6856cc4SSreekanth Reddy 	    (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) {
2280a6856cc4SSreekanth Reddy 		mpi3mr_print_fault_info(mrioc);
2281a6856cc4SSreekanth Reddy 		return;
2282a6856cc4SSreekanth Reddy 	}
2283a6856cc4SSreekanth Reddy 	mpi3mr_set_diagsave(mrioc);
2284a6856cc4SSreekanth Reddy 	mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
2285a6856cc4SSreekanth Reddy 	    reason_code);
2286a6856cc4SSreekanth Reddy 	timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10;
2287a6856cc4SSreekanth Reddy 	do {
2288a6856cc4SSreekanth Reddy 		host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic);
2289a6856cc4SSreekanth Reddy 		if (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS))
2290a6856cc4SSreekanth Reddy 			break;
2291a6856cc4SSreekanth Reddy 		msleep(100);
2292a6856cc4SSreekanth Reddy 	} while (--timeout);
2293a6856cc4SSreekanth Reddy }
2294a6856cc4SSreekanth Reddy 
2295a6856cc4SSreekanth Reddy /**
229654dfcffbSKashyap Desai  * mpi3mr_sync_timestamp - Issue time stamp sync request
229754dfcffbSKashyap Desai  * @mrioc: Adapter reference
229854dfcffbSKashyap Desai  *
229954dfcffbSKashyap Desai  * Issue IO unit control MPI request to synchornize firmware
230054dfcffbSKashyap Desai  * timestamp with host time.
230154dfcffbSKashyap Desai  *
230254dfcffbSKashyap Desai  * Return: 0 on success, non-zero on failure.
230354dfcffbSKashyap Desai  */
230454dfcffbSKashyap Desai static int mpi3mr_sync_timestamp(struct mpi3mr_ioc *mrioc)
230554dfcffbSKashyap Desai {
230654dfcffbSKashyap Desai 	ktime_t current_time;
230754dfcffbSKashyap Desai 	struct mpi3_iounit_control_request iou_ctrl;
230854dfcffbSKashyap Desai 	int retval = 0;
230954dfcffbSKashyap Desai 
231054dfcffbSKashyap Desai 	memset(&iou_ctrl, 0, sizeof(iou_ctrl));
231154dfcffbSKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
231254dfcffbSKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
231354dfcffbSKashyap Desai 		retval = -1;
231454dfcffbSKashyap Desai 		ioc_err(mrioc, "Issue IOUCTL time_stamp: command is in use\n");
231554dfcffbSKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
231654dfcffbSKashyap Desai 		goto out;
231754dfcffbSKashyap Desai 	}
231854dfcffbSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
231954dfcffbSKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
232054dfcffbSKashyap Desai 	mrioc->init_cmds.callback = NULL;
232154dfcffbSKashyap Desai 	iou_ctrl.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
232254dfcffbSKashyap Desai 	iou_ctrl.function = MPI3_FUNCTION_IO_UNIT_CONTROL;
232354dfcffbSKashyap Desai 	iou_ctrl.operation = MPI3_CTRL_OP_UPDATE_TIMESTAMP;
232454dfcffbSKashyap Desai 	current_time = ktime_get_real();
232554dfcffbSKashyap Desai 	iou_ctrl.param64[0] = cpu_to_le64(ktime_to_ms(current_time));
232654dfcffbSKashyap Desai 
232754dfcffbSKashyap Desai 	init_completion(&mrioc->init_cmds.done);
232854dfcffbSKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &iou_ctrl,
232954dfcffbSKashyap Desai 	    sizeof(iou_ctrl), 0);
233054dfcffbSKashyap Desai 	if (retval) {
233154dfcffbSKashyap Desai 		ioc_err(mrioc, "Issue IOUCTL time_stamp: Admin Post failed\n");
233254dfcffbSKashyap Desai 		goto out_unlock;
233354dfcffbSKashyap Desai 	}
233454dfcffbSKashyap Desai 
233554dfcffbSKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
233654dfcffbSKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
233754dfcffbSKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
233854dfcffbSKashyap Desai 		ioc_err(mrioc, "Issue IOUCTL time_stamp: command timed out\n");
233954dfcffbSKashyap Desai 		mrioc->init_cmds.is_waiting = 0;
2340fbaa9aa4SSreekanth Reddy 		if (!(mrioc->init_cmds.state & MPI3MR_CMD_RESET))
234154dfcffbSKashyap Desai 			mpi3mr_soft_reset_handler(mrioc,
234254dfcffbSKashyap Desai 			    MPI3MR_RESET_FROM_TSU_TIMEOUT, 1);
234354dfcffbSKashyap Desai 		retval = -1;
234454dfcffbSKashyap Desai 		goto out_unlock;
234554dfcffbSKashyap Desai 	}
234654dfcffbSKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
234754dfcffbSKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
234854dfcffbSKashyap Desai 		ioc_err(mrioc,
234954dfcffbSKashyap Desai 		    "Issue IOUCTL time_stamp: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
235054dfcffbSKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
235154dfcffbSKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
235254dfcffbSKashyap Desai 		retval = -1;
235354dfcffbSKashyap Desai 		goto out_unlock;
235454dfcffbSKashyap Desai 	}
235554dfcffbSKashyap Desai 
235654dfcffbSKashyap Desai out_unlock:
235754dfcffbSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
235854dfcffbSKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
235954dfcffbSKashyap Desai 
236054dfcffbSKashyap Desai out:
236154dfcffbSKashyap Desai 	return retval;
236254dfcffbSKashyap Desai }
236354dfcffbSKashyap Desai 
236454dfcffbSKashyap Desai /**
23652ac794baSSreekanth Reddy  * mpi3mr_print_pkg_ver - display controller fw package version
23662ac794baSSreekanth Reddy  * @mrioc: Adapter reference
23672ac794baSSreekanth Reddy  *
23682ac794baSSreekanth Reddy  * Retrieve firmware package version from the component image
23692ac794baSSreekanth Reddy  * header of the controller flash and display it.
23702ac794baSSreekanth Reddy  *
23712ac794baSSreekanth Reddy  * Return: 0 on success and non-zero on failure.
23722ac794baSSreekanth Reddy  */
23732ac794baSSreekanth Reddy static int mpi3mr_print_pkg_ver(struct mpi3mr_ioc *mrioc)
23742ac794baSSreekanth Reddy {
23752ac794baSSreekanth Reddy 	struct mpi3_ci_upload_request ci_upload;
23762ac794baSSreekanth Reddy 	int retval = -1;
23772ac794baSSreekanth Reddy 	void *data = NULL;
23782ac794baSSreekanth Reddy 	dma_addr_t data_dma;
23792ac794baSSreekanth Reddy 	struct mpi3_ci_manifest_mpi *manifest;
23802ac794baSSreekanth Reddy 	u32 data_len = sizeof(struct mpi3_ci_manifest_mpi);
23812ac794baSSreekanth Reddy 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
23822ac794baSSreekanth Reddy 
23832ac794baSSreekanth Reddy 	data = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma,
23842ac794baSSreekanth Reddy 	    GFP_KERNEL);
23852ac794baSSreekanth Reddy 	if (!data)
23862ac794baSSreekanth Reddy 		return -ENOMEM;
23872ac794baSSreekanth Reddy 
23882ac794baSSreekanth Reddy 	memset(&ci_upload, 0, sizeof(ci_upload));
23892ac794baSSreekanth Reddy 	mutex_lock(&mrioc->init_cmds.mutex);
23902ac794baSSreekanth Reddy 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
23912ac794baSSreekanth Reddy 		ioc_err(mrioc, "sending get package version failed due to command in use\n");
23922ac794baSSreekanth Reddy 		mutex_unlock(&mrioc->init_cmds.mutex);
23932ac794baSSreekanth Reddy 		goto out;
23942ac794baSSreekanth Reddy 	}
23952ac794baSSreekanth Reddy 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
23962ac794baSSreekanth Reddy 	mrioc->init_cmds.is_waiting = 1;
23972ac794baSSreekanth Reddy 	mrioc->init_cmds.callback = NULL;
23982ac794baSSreekanth Reddy 	ci_upload.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
23992ac794baSSreekanth Reddy 	ci_upload.function = MPI3_FUNCTION_CI_UPLOAD;
24002ac794baSSreekanth Reddy 	ci_upload.msg_flags = MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_PRIMARY;
24012ac794baSSreekanth Reddy 	ci_upload.signature1 = cpu_to_le32(MPI3_IMAGE_HEADER_SIGNATURE1_MANIFEST);
24022ac794baSSreekanth Reddy 	ci_upload.image_offset = cpu_to_le32(MPI3_IMAGE_HEADER_SIZE);
24032ac794baSSreekanth Reddy 	ci_upload.segment_size = cpu_to_le32(data_len);
24042ac794baSSreekanth Reddy 
24052ac794baSSreekanth Reddy 	mpi3mr_add_sg_single(&ci_upload.sgl, sgl_flags, data_len,
24062ac794baSSreekanth Reddy 	    data_dma);
24072ac794baSSreekanth Reddy 	init_completion(&mrioc->init_cmds.done);
24082ac794baSSreekanth Reddy 	retval = mpi3mr_admin_request_post(mrioc, &ci_upload,
24092ac794baSSreekanth Reddy 	    sizeof(ci_upload), 1);
24102ac794baSSreekanth Reddy 	if (retval) {
24112ac794baSSreekanth Reddy 		ioc_err(mrioc, "posting get package version failed\n");
24122ac794baSSreekanth Reddy 		goto out_unlock;
24132ac794baSSreekanth Reddy 	}
24142ac794baSSreekanth Reddy 	wait_for_completion_timeout(&mrioc->init_cmds.done,
24152ac794baSSreekanth Reddy 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
24162ac794baSSreekanth Reddy 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
24172ac794baSSreekanth Reddy 		ioc_err(mrioc, "get package version timed out\n");
2418a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
2419a6856cc4SSreekanth Reddy 		    MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT);
24202ac794baSSreekanth Reddy 		retval = -1;
24212ac794baSSreekanth Reddy 		goto out_unlock;
24222ac794baSSreekanth Reddy 	}
24232ac794baSSreekanth Reddy 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
24242ac794baSSreekanth Reddy 	    == MPI3_IOCSTATUS_SUCCESS) {
24252ac794baSSreekanth Reddy 		manifest = (struct mpi3_ci_manifest_mpi *) data;
24262ac794baSSreekanth Reddy 		if (manifest->manifest_type == MPI3_CI_MANIFEST_TYPE_MPI) {
24272ac794baSSreekanth Reddy 			ioc_info(mrioc,
24282ac794baSSreekanth Reddy 			    "firmware package version(%d.%d.%d.%d.%05d-%05d)\n",
24292ac794baSSreekanth Reddy 			    manifest->package_version.gen_major,
24302ac794baSSreekanth Reddy 			    manifest->package_version.gen_minor,
24312ac794baSSreekanth Reddy 			    manifest->package_version.phase_major,
24322ac794baSSreekanth Reddy 			    manifest->package_version.phase_minor,
24332ac794baSSreekanth Reddy 			    manifest->package_version.customer_id,
24342ac794baSSreekanth Reddy 			    manifest->package_version.build_num);
24352ac794baSSreekanth Reddy 		}
24362ac794baSSreekanth Reddy 	}
24372ac794baSSreekanth Reddy 	retval = 0;
24382ac794baSSreekanth Reddy out_unlock:
24392ac794baSSreekanth Reddy 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
24402ac794baSSreekanth Reddy 	mutex_unlock(&mrioc->init_cmds.mutex);
24412ac794baSSreekanth Reddy 
24422ac794baSSreekanth Reddy out:
24432ac794baSSreekanth Reddy 	if (data)
24442ac794baSSreekanth Reddy 		dma_free_coherent(&mrioc->pdev->dev, data_len, data,
24452ac794baSSreekanth Reddy 		    data_dma);
24462ac794baSSreekanth Reddy 	return retval;
24472ac794baSSreekanth Reddy }
24482ac794baSSreekanth Reddy 
24492ac794baSSreekanth Reddy /**
2450672ae26cSKashyap Desai  * mpi3mr_watchdog_work - watchdog thread to monitor faults
2451672ae26cSKashyap Desai  * @work: work struct
2452672ae26cSKashyap Desai  *
2453672ae26cSKashyap Desai  * Watch dog work periodically executed (1 second interval) to
2454672ae26cSKashyap Desai  * monitor firmware fault and to issue periodic timer sync to
2455672ae26cSKashyap Desai  * the firmware.
2456672ae26cSKashyap Desai  *
2457672ae26cSKashyap Desai  * Return: Nothing.
2458672ae26cSKashyap Desai  */
2459672ae26cSKashyap Desai static void mpi3mr_watchdog_work(struct work_struct *work)
2460672ae26cSKashyap Desai {
2461672ae26cSKashyap Desai 	struct mpi3mr_ioc *mrioc =
2462672ae26cSKashyap Desai 	    container_of(work, struct mpi3mr_ioc, watchdog_work.work);
2463672ae26cSKashyap Desai 	unsigned long flags;
2464672ae26cSKashyap Desai 	enum mpi3mr_iocstate ioc_state;
246578b76a07SSreekanth Reddy 	u32 fault, host_diagnostic, ioc_status;
246678b76a07SSreekanth Reddy 	u32 reset_reason = MPI3MR_RESET_FROM_FAULT_WATCH;
2467672ae26cSKashyap Desai 
2468f2a79d20SSreekanth Reddy 	if (mrioc->reset_in_progress)
2469b64845a7SSreekanth Reddy 		return;
2470b64845a7SSreekanth Reddy 
2471f2a79d20SSreekanth Reddy 	if (!mrioc->unrecoverable && !pci_device_is_present(mrioc->pdev)) {
2472f2a79d20SSreekanth Reddy 		ioc_err(mrioc, "watchdog could not detect the controller\n");
2473f2a79d20SSreekanth Reddy 		mrioc->unrecoverable = 1;
2474f2a79d20SSreekanth Reddy 	}
2475f2a79d20SSreekanth Reddy 
2476f2a79d20SSreekanth Reddy 	if (mrioc->unrecoverable) {
2477f2a79d20SSreekanth Reddy 		ioc_err(mrioc,
2478f2a79d20SSreekanth Reddy 		    "flush pending commands for unrecoverable controller\n");
2479f2a79d20SSreekanth Reddy 		mpi3mr_flush_cmds_for_unrecovered_controller(mrioc);
2480f2a79d20SSreekanth Reddy 		return;
2481f2a79d20SSreekanth Reddy 	}
2482f2a79d20SSreekanth Reddy 
248354dfcffbSKashyap Desai 	if (mrioc->ts_update_counter++ >= MPI3MR_TSUPDATE_INTERVAL) {
248454dfcffbSKashyap Desai 		mrioc->ts_update_counter = 0;
248554dfcffbSKashyap Desai 		mpi3mr_sync_timestamp(mrioc);
248654dfcffbSKashyap Desai 	}
248754dfcffbSKashyap Desai 
248878b76a07SSreekanth Reddy 	if ((mrioc->prepare_for_reset) &&
248978b76a07SSreekanth Reddy 	    ((mrioc->prepare_for_reset_timeout_counter++) >=
249078b76a07SSreekanth Reddy 	     MPI3MR_PREPARE_FOR_RESET_TIMEOUT)) {
249178b76a07SSreekanth Reddy 		mpi3mr_soft_reset_handler(mrioc,
249278b76a07SSreekanth Reddy 		    MPI3MR_RESET_FROM_CIACTVRST_TIMER, 1);
249378b76a07SSreekanth Reddy 		return;
249478b76a07SSreekanth Reddy 	}
249578b76a07SSreekanth Reddy 
249678b76a07SSreekanth Reddy 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
249778b76a07SSreekanth Reddy 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) {
249878b76a07SSreekanth Reddy 		mpi3mr_soft_reset_handler(mrioc, MPI3MR_RESET_FROM_FIRMWARE, 0);
249978b76a07SSreekanth Reddy 		return;
250078b76a07SSreekanth Reddy 	}
250178b76a07SSreekanth Reddy 
2502672ae26cSKashyap Desai 	/*Check for fault state every one second and issue Soft reset*/
2503672ae26cSKashyap Desai 	ioc_state = mpi3mr_get_iocstate(mrioc);
250478b76a07SSreekanth Reddy 	if (ioc_state != MRIOC_STATE_FAULT)
250578b76a07SSreekanth Reddy 		goto schedule_work;
250678b76a07SSreekanth Reddy 
250778b76a07SSreekanth Reddy 	fault = readl(&mrioc->sysif_regs->fault) & MPI3_SYSIF_FAULT_CODE_MASK;
2508672ae26cSKashyap Desai 	host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic);
2509672ae26cSKashyap Desai 	if (host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS) {
2510672ae26cSKashyap Desai 		if (!mrioc->diagsave_timeout) {
2511672ae26cSKashyap Desai 			mpi3mr_print_fault_info(mrioc);
251278b76a07SSreekanth Reddy 			ioc_warn(mrioc, "diag save in progress\n");
2513672ae26cSKashyap Desai 		}
251478b76a07SSreekanth Reddy 		if ((mrioc->diagsave_timeout++) <= MPI3_SYSIF_DIAG_SAVE_TIMEOUT)
2515672ae26cSKashyap Desai 			goto schedule_work;
251678b76a07SSreekanth Reddy 	}
251778b76a07SSreekanth Reddy 
2518672ae26cSKashyap Desai 	mpi3mr_print_fault_info(mrioc);
2519672ae26cSKashyap Desai 	mrioc->diagsave_timeout = 0;
2520672ae26cSKashyap Desai 
252178b76a07SSreekanth Reddy 	switch (fault) {
2522bad2f28dSSreekanth Reddy 	case MPI3_SYSIF_FAULT_CODE_COMPLETE_RESET_NEEDED:
252378b76a07SSreekanth Reddy 	case MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED:
2524bad2f28dSSreekanth Reddy 		ioc_warn(mrioc,
252578b76a07SSreekanth Reddy 		    "controller requires system power cycle, marking controller as unrecoverable\n");
2526672ae26cSKashyap Desai 		mrioc->unrecoverable = 1;
2527f2a79d20SSreekanth Reddy 		goto schedule_work;
252878b76a07SSreekanth Reddy 	case MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS:
2529*a3d27dfdSRanjan Kumar 		goto schedule_work;
253078b76a07SSreekanth Reddy 	case MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET:
253178b76a07SSreekanth Reddy 		reset_reason = MPI3MR_RESET_FROM_CIACTIV_FAULT;
253278b76a07SSreekanth Reddy 		break;
253378b76a07SSreekanth Reddy 	default:
253478b76a07SSreekanth Reddy 		break;
2535672ae26cSKashyap Desai 	}
253678b76a07SSreekanth Reddy 	mpi3mr_soft_reset_handler(mrioc, reset_reason, 0);
253778b76a07SSreekanth Reddy 	return;
2538672ae26cSKashyap Desai 
2539672ae26cSKashyap Desai schedule_work:
2540672ae26cSKashyap Desai 	spin_lock_irqsave(&mrioc->watchdog_lock, flags);
2541672ae26cSKashyap Desai 	if (mrioc->watchdog_work_q)
2542672ae26cSKashyap Desai 		queue_delayed_work(mrioc->watchdog_work_q,
2543672ae26cSKashyap Desai 		    &mrioc->watchdog_work,
2544672ae26cSKashyap Desai 		    msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL));
2545672ae26cSKashyap Desai 	spin_unlock_irqrestore(&mrioc->watchdog_lock, flags);
2546672ae26cSKashyap Desai 	return;
2547672ae26cSKashyap Desai }
2548672ae26cSKashyap Desai 
2549672ae26cSKashyap Desai /**
2550672ae26cSKashyap Desai  * mpi3mr_start_watchdog - Start watchdog
2551672ae26cSKashyap Desai  * @mrioc: Adapter instance reference
2552672ae26cSKashyap Desai  *
2553672ae26cSKashyap Desai  * Create and start the watchdog thread to monitor controller
2554672ae26cSKashyap Desai  * faults.
2555672ae26cSKashyap Desai  *
2556672ae26cSKashyap Desai  * Return: Nothing.
2557672ae26cSKashyap Desai  */
2558672ae26cSKashyap Desai void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc)
2559672ae26cSKashyap Desai {
2560672ae26cSKashyap Desai 	if (mrioc->watchdog_work_q)
2561672ae26cSKashyap Desai 		return;
2562672ae26cSKashyap Desai 
2563672ae26cSKashyap Desai 	INIT_DELAYED_WORK(&mrioc->watchdog_work, mpi3mr_watchdog_work);
2564672ae26cSKashyap Desai 	snprintf(mrioc->watchdog_work_q_name,
2565672ae26cSKashyap Desai 	    sizeof(mrioc->watchdog_work_q_name), "watchdog_%s%d", mrioc->name,
2566672ae26cSKashyap Desai 	    mrioc->id);
2567672ae26cSKashyap Desai 	mrioc->watchdog_work_q =
2568672ae26cSKashyap Desai 	    create_singlethread_workqueue(mrioc->watchdog_work_q_name);
2569672ae26cSKashyap Desai 	if (!mrioc->watchdog_work_q) {
2570672ae26cSKashyap Desai 		ioc_err(mrioc, "%s: failed (line=%d)\n", __func__, __LINE__);
2571672ae26cSKashyap Desai 		return;
2572672ae26cSKashyap Desai 	}
2573672ae26cSKashyap Desai 
2574672ae26cSKashyap Desai 	if (mrioc->watchdog_work_q)
2575672ae26cSKashyap Desai 		queue_delayed_work(mrioc->watchdog_work_q,
2576672ae26cSKashyap Desai 		    &mrioc->watchdog_work,
2577672ae26cSKashyap Desai 		    msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL));
2578672ae26cSKashyap Desai }
2579672ae26cSKashyap Desai 
2580672ae26cSKashyap Desai /**
2581672ae26cSKashyap Desai  * mpi3mr_stop_watchdog - Stop watchdog
2582672ae26cSKashyap Desai  * @mrioc: Adapter instance reference
2583672ae26cSKashyap Desai  *
2584672ae26cSKashyap Desai  * Stop the watchdog thread created to monitor controller
2585672ae26cSKashyap Desai  * faults.
2586672ae26cSKashyap Desai  *
2587672ae26cSKashyap Desai  * Return: Nothing.
2588672ae26cSKashyap Desai  */
2589672ae26cSKashyap Desai void mpi3mr_stop_watchdog(struct mpi3mr_ioc *mrioc)
2590672ae26cSKashyap Desai {
2591672ae26cSKashyap Desai 	unsigned long flags;
2592672ae26cSKashyap Desai 	struct workqueue_struct *wq;
2593672ae26cSKashyap Desai 
2594672ae26cSKashyap Desai 	spin_lock_irqsave(&mrioc->watchdog_lock, flags);
2595672ae26cSKashyap Desai 	wq = mrioc->watchdog_work_q;
2596672ae26cSKashyap Desai 	mrioc->watchdog_work_q = NULL;
2597672ae26cSKashyap Desai 	spin_unlock_irqrestore(&mrioc->watchdog_lock, flags);
2598672ae26cSKashyap Desai 	if (wq) {
2599672ae26cSKashyap Desai 		if (!cancel_delayed_work_sync(&mrioc->watchdog_work))
2600672ae26cSKashyap Desai 			flush_workqueue(wq);
2601672ae26cSKashyap Desai 		destroy_workqueue(wq);
2602672ae26cSKashyap Desai 	}
2603672ae26cSKashyap Desai }
2604672ae26cSKashyap Desai 
2605672ae26cSKashyap Desai /**
2606824a1566SKashyap Desai  * mpi3mr_setup_admin_qpair - Setup admin queue pair
2607824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2608824a1566SKashyap Desai  *
2609824a1566SKashyap Desai  * Allocate memory for admin queue pair if required and register
2610824a1566SKashyap Desai  * the admin queue with the controller.
2611824a1566SKashyap Desai  *
2612824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
2613824a1566SKashyap Desai  */
2614824a1566SKashyap Desai static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc)
2615824a1566SKashyap Desai {
2616824a1566SKashyap Desai 	int retval = 0;
2617824a1566SKashyap Desai 	u32 num_admin_entries = 0;
2618824a1566SKashyap Desai 
2619824a1566SKashyap Desai 	mrioc->admin_req_q_sz = MPI3MR_ADMIN_REQ_Q_SIZE;
2620824a1566SKashyap Desai 	mrioc->num_admin_req = mrioc->admin_req_q_sz /
2621824a1566SKashyap Desai 	    MPI3MR_ADMIN_REQ_FRAME_SZ;
2622824a1566SKashyap Desai 	mrioc->admin_req_ci = mrioc->admin_req_pi = 0;
2623824a1566SKashyap Desai 	mrioc->admin_req_base = NULL;
2624824a1566SKashyap Desai 
2625824a1566SKashyap Desai 	mrioc->admin_reply_q_sz = MPI3MR_ADMIN_REPLY_Q_SIZE;
2626824a1566SKashyap Desai 	mrioc->num_admin_replies = mrioc->admin_reply_q_sz /
2627824a1566SKashyap Desai 	    MPI3MR_ADMIN_REPLY_FRAME_SZ;
2628824a1566SKashyap Desai 	mrioc->admin_reply_ci = 0;
2629824a1566SKashyap Desai 	mrioc->admin_reply_ephase = 1;
2630824a1566SKashyap Desai 	mrioc->admin_reply_base = NULL;
263102ca7da2SRanjan Kumar 	atomic_set(&mrioc->admin_reply_q_in_use, 0);
2632824a1566SKashyap Desai 
2633824a1566SKashyap Desai 	if (!mrioc->admin_req_base) {
2634824a1566SKashyap Desai 		mrioc->admin_req_base = dma_alloc_coherent(&mrioc->pdev->dev,
2635824a1566SKashyap Desai 		    mrioc->admin_req_q_sz, &mrioc->admin_req_dma, GFP_KERNEL);
2636824a1566SKashyap Desai 
2637824a1566SKashyap Desai 		if (!mrioc->admin_req_base) {
2638824a1566SKashyap Desai 			retval = -1;
2639824a1566SKashyap Desai 			goto out_failed;
2640824a1566SKashyap Desai 		}
2641824a1566SKashyap Desai 
2642824a1566SKashyap Desai 		mrioc->admin_reply_base = dma_alloc_coherent(&mrioc->pdev->dev,
2643824a1566SKashyap Desai 		    mrioc->admin_reply_q_sz, &mrioc->admin_reply_dma,
2644824a1566SKashyap Desai 		    GFP_KERNEL);
2645824a1566SKashyap Desai 
2646824a1566SKashyap Desai 		if (!mrioc->admin_reply_base) {
2647824a1566SKashyap Desai 			retval = -1;
2648824a1566SKashyap Desai 			goto out_failed;
2649824a1566SKashyap Desai 		}
2650824a1566SKashyap Desai 	}
2651824a1566SKashyap Desai 
2652824a1566SKashyap Desai 	num_admin_entries = (mrioc->num_admin_replies << 16) |
2653824a1566SKashyap Desai 	    (mrioc->num_admin_req);
2654824a1566SKashyap Desai 	writel(num_admin_entries, &mrioc->sysif_regs->admin_queue_num_entries);
2655824a1566SKashyap Desai 	mpi3mr_writeq(mrioc->admin_req_dma,
2656824a1566SKashyap Desai 	    &mrioc->sysif_regs->admin_request_queue_address);
2657824a1566SKashyap Desai 	mpi3mr_writeq(mrioc->admin_reply_dma,
2658824a1566SKashyap Desai 	    &mrioc->sysif_regs->admin_reply_queue_address);
2659824a1566SKashyap Desai 	writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi);
2660824a1566SKashyap Desai 	writel(mrioc->admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci);
2661824a1566SKashyap Desai 	return retval;
2662824a1566SKashyap Desai 
2663824a1566SKashyap Desai out_failed:
2664824a1566SKashyap Desai 
2665824a1566SKashyap Desai 	if (mrioc->admin_reply_base) {
2666824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz,
2667824a1566SKashyap Desai 		    mrioc->admin_reply_base, mrioc->admin_reply_dma);
2668824a1566SKashyap Desai 		mrioc->admin_reply_base = NULL;
2669824a1566SKashyap Desai 	}
2670824a1566SKashyap Desai 	if (mrioc->admin_req_base) {
2671824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz,
2672824a1566SKashyap Desai 		    mrioc->admin_req_base, mrioc->admin_req_dma);
2673824a1566SKashyap Desai 		mrioc->admin_req_base = NULL;
2674824a1566SKashyap Desai 	}
2675824a1566SKashyap Desai 	return retval;
2676824a1566SKashyap Desai }
2677824a1566SKashyap Desai 
2678824a1566SKashyap Desai /**
2679824a1566SKashyap Desai  * mpi3mr_issue_iocfacts - Send IOC Facts
2680824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2681824a1566SKashyap Desai  * @facts_data: Cached IOC facts data
2682824a1566SKashyap Desai  *
2683824a1566SKashyap Desai  * Issue IOC Facts MPI request through admin queue and wait for
2684824a1566SKashyap Desai  * the completion of it or time out.
2685824a1566SKashyap Desai  *
2686824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
2687824a1566SKashyap Desai  */
2688824a1566SKashyap Desai static int mpi3mr_issue_iocfacts(struct mpi3mr_ioc *mrioc,
2689824a1566SKashyap Desai 	struct mpi3_ioc_facts_data *facts_data)
2690824a1566SKashyap Desai {
2691824a1566SKashyap Desai 	struct mpi3_ioc_facts_request iocfacts_req;
2692824a1566SKashyap Desai 	void *data = NULL;
2693824a1566SKashyap Desai 	dma_addr_t data_dma;
2694824a1566SKashyap Desai 	u32 data_len = sizeof(*facts_data);
2695824a1566SKashyap Desai 	int retval = 0;
2696824a1566SKashyap Desai 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
2697824a1566SKashyap Desai 
2698824a1566SKashyap Desai 	data = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma,
2699824a1566SKashyap Desai 	    GFP_KERNEL);
2700824a1566SKashyap Desai 
2701824a1566SKashyap Desai 	if (!data) {
2702824a1566SKashyap Desai 		retval = -1;
2703824a1566SKashyap Desai 		goto out;
2704824a1566SKashyap Desai 	}
2705824a1566SKashyap Desai 
2706824a1566SKashyap Desai 	memset(&iocfacts_req, 0, sizeof(iocfacts_req));
2707824a1566SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
2708824a1566SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
2709824a1566SKashyap Desai 		retval = -1;
2710824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCFacts: Init command is in use\n");
2711824a1566SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
2712824a1566SKashyap Desai 		goto out;
2713824a1566SKashyap Desai 	}
2714824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
2715824a1566SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
2716824a1566SKashyap Desai 	mrioc->init_cmds.callback = NULL;
2717824a1566SKashyap Desai 	iocfacts_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
2718824a1566SKashyap Desai 	iocfacts_req.function = MPI3_FUNCTION_IOC_FACTS;
2719824a1566SKashyap Desai 
2720824a1566SKashyap Desai 	mpi3mr_add_sg_single(&iocfacts_req.sgl, sgl_flags, data_len,
2721824a1566SKashyap Desai 	    data_dma);
2722824a1566SKashyap Desai 
2723824a1566SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
2724824a1566SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &iocfacts_req,
2725824a1566SKashyap Desai 	    sizeof(iocfacts_req), 1);
2726824a1566SKashyap Desai 	if (retval) {
2727824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCFacts: Admin Post failed\n");
2728824a1566SKashyap Desai 		goto out_unlock;
2729824a1566SKashyap Desai 	}
2730824a1566SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
2731824a1566SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
2732824a1566SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
2733a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "ioc_facts timed out\n");
2734a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
2735824a1566SKashyap Desai 		    MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT);
2736824a1566SKashyap Desai 		retval = -1;
2737824a1566SKashyap Desai 		goto out_unlock;
2738824a1566SKashyap Desai 	}
2739824a1566SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
2740824a1566SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
2741824a1566SKashyap Desai 		ioc_err(mrioc,
2742824a1566SKashyap Desai 		    "Issue IOCFacts: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
2743824a1566SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
2744824a1566SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
2745824a1566SKashyap Desai 		retval = -1;
2746824a1566SKashyap Desai 		goto out_unlock;
2747824a1566SKashyap Desai 	}
2748824a1566SKashyap Desai 	memcpy(facts_data, (u8 *)data, data_len);
2749c5758fc7SSreekanth Reddy 	mpi3mr_process_factsdata(mrioc, facts_data);
2750824a1566SKashyap Desai out_unlock:
2751824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
2752824a1566SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
2753824a1566SKashyap Desai 
2754824a1566SKashyap Desai out:
2755824a1566SKashyap Desai 	if (data)
2756824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, data_len, data, data_dma);
2757824a1566SKashyap Desai 
2758824a1566SKashyap Desai 	return retval;
2759824a1566SKashyap Desai }
2760824a1566SKashyap Desai 
2761824a1566SKashyap Desai /**
2762824a1566SKashyap Desai  * mpi3mr_check_reset_dma_mask - Process IOC facts data
2763824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2764824a1566SKashyap Desai  *
2765824a1566SKashyap Desai  * Check whether the new DMA mask requested through IOCFacts by
2766824a1566SKashyap Desai  * firmware needs to be set, if so set it .
2767824a1566SKashyap Desai  *
2768824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
2769824a1566SKashyap Desai  */
2770824a1566SKashyap Desai static inline int mpi3mr_check_reset_dma_mask(struct mpi3mr_ioc *mrioc)
2771824a1566SKashyap Desai {
2772824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
2773824a1566SKashyap Desai 	int r;
2774824a1566SKashyap Desai 	u64 facts_dma_mask = DMA_BIT_MASK(mrioc->facts.dma_mask);
2775824a1566SKashyap Desai 
2776824a1566SKashyap Desai 	if (!mrioc->facts.dma_mask || (mrioc->dma_mask <= facts_dma_mask))
2777824a1566SKashyap Desai 		return 0;
2778824a1566SKashyap Desai 
2779824a1566SKashyap Desai 	ioc_info(mrioc, "Changing DMA mask from 0x%016llx to 0x%016llx\n",
2780824a1566SKashyap Desai 	    mrioc->dma_mask, facts_dma_mask);
2781824a1566SKashyap Desai 
2782824a1566SKashyap Desai 	r = dma_set_mask_and_coherent(&pdev->dev, facts_dma_mask);
2783824a1566SKashyap Desai 	if (r) {
2784824a1566SKashyap Desai 		ioc_err(mrioc, "Setting DMA mask to 0x%016llx failed: %d\n",
2785824a1566SKashyap Desai 		    facts_dma_mask, r);
2786824a1566SKashyap Desai 		return r;
2787824a1566SKashyap Desai 	}
2788824a1566SKashyap Desai 	mrioc->dma_mask = facts_dma_mask;
2789824a1566SKashyap Desai 	return r;
2790824a1566SKashyap Desai }
2791824a1566SKashyap Desai 
2792824a1566SKashyap Desai /**
2793824a1566SKashyap Desai  * mpi3mr_process_factsdata - Process IOC facts data
2794824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2795824a1566SKashyap Desai  * @facts_data: Cached IOC facts data
2796824a1566SKashyap Desai  *
2797824a1566SKashyap Desai  * Convert IOC facts data into cpu endianness and cache it in
2798824a1566SKashyap Desai  * the driver .
2799824a1566SKashyap Desai  *
2800824a1566SKashyap Desai  * Return: Nothing.
2801824a1566SKashyap Desai  */
2802824a1566SKashyap Desai static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc,
2803824a1566SKashyap Desai 	struct mpi3_ioc_facts_data *facts_data)
2804824a1566SKashyap Desai {
2805824a1566SKashyap Desai 	u32 ioc_config, req_sz, facts_flags;
2806824a1566SKashyap Desai 
2807824a1566SKashyap Desai 	if ((le16_to_cpu(facts_data->ioc_facts_data_length)) !=
2808824a1566SKashyap Desai 	    (sizeof(*facts_data) / 4)) {
2809824a1566SKashyap Desai 		ioc_warn(mrioc,
2810824a1566SKashyap Desai 		    "IOCFactsdata length mismatch driver_sz(%zu) firmware_sz(%d)\n",
2811824a1566SKashyap Desai 		    sizeof(*facts_data),
2812824a1566SKashyap Desai 		    le16_to_cpu(facts_data->ioc_facts_data_length) * 4);
2813824a1566SKashyap Desai 	}
2814824a1566SKashyap Desai 
2815824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
2816824a1566SKashyap Desai 	req_sz = 1 << ((ioc_config & MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ) >>
2817824a1566SKashyap Desai 	    MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ_SHIFT);
2818824a1566SKashyap Desai 	if (le16_to_cpu(facts_data->ioc_request_frame_size) != (req_sz / 4)) {
2819824a1566SKashyap Desai 		ioc_err(mrioc,
2820824a1566SKashyap Desai 		    "IOCFacts data reqFrameSize mismatch hw_size(%d) firmware_sz(%d)\n",
2821824a1566SKashyap Desai 		    req_sz / 4, le16_to_cpu(facts_data->ioc_request_frame_size));
2822824a1566SKashyap Desai 	}
2823824a1566SKashyap Desai 
2824824a1566SKashyap Desai 	memset(&mrioc->facts, 0, sizeof(mrioc->facts));
2825824a1566SKashyap Desai 
2826824a1566SKashyap Desai 	facts_flags = le32_to_cpu(facts_data->flags);
2827824a1566SKashyap Desai 	mrioc->facts.op_req_sz = req_sz;
2828824a1566SKashyap Desai 	mrioc->op_reply_desc_sz = 1 << ((ioc_config &
2829824a1566SKashyap Desai 	    MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ) >>
2830824a1566SKashyap Desai 	    MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ_SHIFT);
2831824a1566SKashyap Desai 
2832824a1566SKashyap Desai 	mrioc->facts.ioc_num = facts_data->ioc_number;
2833824a1566SKashyap Desai 	mrioc->facts.who_init = facts_data->who_init;
2834824a1566SKashyap Desai 	mrioc->facts.max_msix_vectors = le16_to_cpu(facts_data->max_msix_vectors);
2835824a1566SKashyap Desai 	mrioc->facts.personality = (facts_flags &
2836824a1566SKashyap Desai 	    MPI3_IOCFACTS_FLAGS_PERSONALITY_MASK);
2837824a1566SKashyap Desai 	mrioc->facts.dma_mask = (facts_flags &
2838824a1566SKashyap Desai 	    MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >>
2839824a1566SKashyap Desai 	    MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT;
2840824a1566SKashyap Desai 	mrioc->facts.protocol_flags = facts_data->protocol_flags;
2841824a1566SKashyap Desai 	mrioc->facts.mpi_version = le32_to_cpu(facts_data->mpi_version.word);
284204b27e53SSreekanth Reddy 	mrioc->facts.max_reqs = le16_to_cpu(facts_data->max_outstanding_requests);
2843824a1566SKashyap Desai 	mrioc->facts.product_id = le16_to_cpu(facts_data->product_id);
2844824a1566SKashyap Desai 	mrioc->facts.reply_sz = le16_to_cpu(facts_data->reply_frame_size) * 4;
2845824a1566SKashyap Desai 	mrioc->facts.exceptions = le16_to_cpu(facts_data->ioc_exceptions);
2846824a1566SKashyap Desai 	mrioc->facts.max_perids = le16_to_cpu(facts_data->max_persistent_id);
2847824a1566SKashyap Desai 	mrioc->facts.max_vds = le16_to_cpu(facts_data->max_vds);
2848824a1566SKashyap Desai 	mrioc->facts.max_hpds = le16_to_cpu(facts_data->max_host_pds);
2849ec5ebd2cSSreekanth Reddy 	mrioc->facts.max_advhpds = le16_to_cpu(facts_data->max_adv_host_pds);
2850ec5ebd2cSSreekanth Reddy 	mrioc->facts.max_raid_pds = le16_to_cpu(facts_data->max_raid_pds);
2851824a1566SKashyap Desai 	mrioc->facts.max_nvme = le16_to_cpu(facts_data->max_nvme);
2852824a1566SKashyap Desai 	mrioc->facts.max_pcie_switches =
2853ec5ebd2cSSreekanth Reddy 	    le16_to_cpu(facts_data->max_pcie_switches);
2854824a1566SKashyap Desai 	mrioc->facts.max_sasexpanders =
2855824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_sas_expanders);
2856824a1566SKashyap Desai 	mrioc->facts.max_sasinitiators =
2857824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_sas_initiators);
2858824a1566SKashyap Desai 	mrioc->facts.max_enclosures = le16_to_cpu(facts_data->max_enclosures);
2859824a1566SKashyap Desai 	mrioc->facts.min_devhandle = le16_to_cpu(facts_data->min_dev_handle);
2860824a1566SKashyap Desai 	mrioc->facts.max_devhandle = le16_to_cpu(facts_data->max_dev_handle);
2861824a1566SKashyap Desai 	mrioc->facts.max_op_req_q =
2862824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_operational_request_queues);
2863824a1566SKashyap Desai 	mrioc->facts.max_op_reply_q =
2864824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_operational_reply_queues);
2865824a1566SKashyap Desai 	mrioc->facts.ioc_capabilities =
2866824a1566SKashyap Desai 	    le32_to_cpu(facts_data->ioc_capabilities);
2867824a1566SKashyap Desai 	mrioc->facts.fw_ver.build_num =
2868824a1566SKashyap Desai 	    le16_to_cpu(facts_data->fw_version.build_num);
2869824a1566SKashyap Desai 	mrioc->facts.fw_ver.cust_id =
2870824a1566SKashyap Desai 	    le16_to_cpu(facts_data->fw_version.customer_id);
2871824a1566SKashyap Desai 	mrioc->facts.fw_ver.ph_minor = facts_data->fw_version.phase_minor;
2872824a1566SKashyap Desai 	mrioc->facts.fw_ver.ph_major = facts_data->fw_version.phase_major;
2873824a1566SKashyap Desai 	mrioc->facts.fw_ver.gen_minor = facts_data->fw_version.gen_minor;
2874824a1566SKashyap Desai 	mrioc->facts.fw_ver.gen_major = facts_data->fw_version.gen_major;
2875824a1566SKashyap Desai 	mrioc->msix_count = min_t(int, mrioc->msix_count,
2876824a1566SKashyap Desai 	    mrioc->facts.max_msix_vectors);
2877824a1566SKashyap Desai 	mrioc->facts.sge_mod_mask = facts_data->sge_modifier_mask;
2878824a1566SKashyap Desai 	mrioc->facts.sge_mod_value = facts_data->sge_modifier_value;
2879824a1566SKashyap Desai 	mrioc->facts.sge_mod_shift = facts_data->sge_modifier_shift;
2880824a1566SKashyap Desai 	mrioc->facts.shutdown_timeout =
2881824a1566SKashyap Desai 	    le16_to_cpu(facts_data->shutdown_timeout);
2882824a1566SKashyap Desai 
2883f10af057SSreekanth Reddy 	mrioc->facts.max_dev_per_tg =
2884f10af057SSreekanth Reddy 	    facts_data->max_devices_per_throttle_group;
2885f10af057SSreekanth Reddy 	mrioc->facts.io_throttle_data_length =
2886f10af057SSreekanth Reddy 	    le16_to_cpu(facts_data->io_throttle_data_length);
2887f10af057SSreekanth Reddy 	mrioc->facts.max_io_throttle_group =
2888f10af057SSreekanth Reddy 	    le16_to_cpu(facts_data->max_io_throttle_group);
2889f10af057SSreekanth Reddy 	mrioc->facts.io_throttle_low = le16_to_cpu(facts_data->io_throttle_low);
2890f10af057SSreekanth Reddy 	mrioc->facts.io_throttle_high =
2891f10af057SSreekanth Reddy 	    le16_to_cpu(facts_data->io_throttle_high);
2892f10af057SSreekanth Reddy 
2893f10af057SSreekanth Reddy 	/* Store in 512b block count */
2894f10af057SSreekanth Reddy 	if (mrioc->facts.io_throttle_data_length)
2895f10af057SSreekanth Reddy 		mrioc->io_throttle_data_length =
2896f10af057SSreekanth Reddy 		    (mrioc->facts.io_throttle_data_length * 2 * 4);
2897f10af057SSreekanth Reddy 	else
2898f10af057SSreekanth Reddy 		/* set the length to 1MB + 1K to disable throttle */
2899f10af057SSreekanth Reddy 		mrioc->io_throttle_data_length = MPI3MR_MAX_SECTORS + 2;
2900f10af057SSreekanth Reddy 
2901f10af057SSreekanth Reddy 	mrioc->io_throttle_high = (mrioc->facts.io_throttle_high * 2 * 1024);
2902f10af057SSreekanth Reddy 	mrioc->io_throttle_low = (mrioc->facts.io_throttle_low * 2 * 1024);
2903f10af057SSreekanth Reddy 
2904824a1566SKashyap Desai 	ioc_info(mrioc, "ioc_num(%d), maxopQ(%d), maxopRepQ(%d), maxdh(%d),",
2905824a1566SKashyap Desai 	    mrioc->facts.ioc_num, mrioc->facts.max_op_req_q,
2906824a1566SKashyap Desai 	    mrioc->facts.max_op_reply_q, mrioc->facts.max_devhandle);
2907824a1566SKashyap Desai 	ioc_info(mrioc,
2908ec5ebd2cSSreekanth Reddy 	    "maxreqs(%d), mindh(%d) maxvectors(%d) maxperids(%d)\n",
2909824a1566SKashyap Desai 	    mrioc->facts.max_reqs, mrioc->facts.min_devhandle,
2910ec5ebd2cSSreekanth Reddy 	    mrioc->facts.max_msix_vectors, mrioc->facts.max_perids);
2911824a1566SKashyap Desai 	ioc_info(mrioc, "SGEModMask 0x%x SGEModVal 0x%x SGEModShift 0x%x ",
2912824a1566SKashyap Desai 	    mrioc->facts.sge_mod_mask, mrioc->facts.sge_mod_value,
2913824a1566SKashyap Desai 	    mrioc->facts.sge_mod_shift);
2914824a1566SKashyap Desai 	ioc_info(mrioc, "DMA mask %d InitialPE status 0x%x\n",
2915824a1566SKashyap Desai 	    mrioc->facts.dma_mask, (facts_flags &
2916824a1566SKashyap Desai 	    MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK));
2917f10af057SSreekanth Reddy 	ioc_info(mrioc,
2918f10af057SSreekanth Reddy 	    "max_dev_per_throttle_group(%d), max_throttle_groups(%d)\n",
2919f10af057SSreekanth Reddy 	    mrioc->facts.max_dev_per_tg, mrioc->facts.max_io_throttle_group);
2920f10af057SSreekanth Reddy 	ioc_info(mrioc,
2921f10af057SSreekanth Reddy 	   "io_throttle_data_len(%dKiB), io_throttle_high(%dMiB), io_throttle_low(%dMiB)\n",
2922f10af057SSreekanth Reddy 	   mrioc->facts.io_throttle_data_length * 4,
2923f10af057SSreekanth Reddy 	   mrioc->facts.io_throttle_high, mrioc->facts.io_throttle_low);
2924824a1566SKashyap Desai }
2925824a1566SKashyap Desai 
2926824a1566SKashyap Desai /**
2927824a1566SKashyap Desai  * mpi3mr_alloc_reply_sense_bufs - Send IOC Init
2928824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2929824a1566SKashyap Desai  *
2930824a1566SKashyap Desai  * Allocate and initialize the reply free buffers, sense
2931824a1566SKashyap Desai  * buffers, reply free queue and sense buffer queue.
2932824a1566SKashyap Desai  *
2933824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
2934824a1566SKashyap Desai  */
2935824a1566SKashyap Desai static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc)
2936824a1566SKashyap Desai {
2937824a1566SKashyap Desai 	int retval = 0;
2938824a1566SKashyap Desai 	u32 sz, i;
2939824a1566SKashyap Desai 
2940824a1566SKashyap Desai 	if (mrioc->init_cmds.reply)
2941e3605f65SSreekanth Reddy 		return retval;
2942824a1566SKashyap Desai 
2943c5758fc7SSreekanth Reddy 	mrioc->init_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL);
2944824a1566SKashyap Desai 	if (!mrioc->init_cmds.reply)
2945824a1566SKashyap Desai 		goto out_failed;
2946824a1566SKashyap Desai 
2947f5e6d5a3SSumit Saxena 	mrioc->bsg_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL);
2948f5e6d5a3SSumit Saxena 	if (!mrioc->bsg_cmds.reply)
2949f5e6d5a3SSumit Saxena 		goto out_failed;
2950f5e6d5a3SSumit Saxena 
29512bd37e28SSreekanth Reddy 	mrioc->transport_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL);
29522bd37e28SSreekanth Reddy 	if (!mrioc->transport_cmds.reply)
29532bd37e28SSreekanth Reddy 		goto out_failed;
29542bd37e28SSreekanth Reddy 
295513ef29eaSKashyap Desai 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
2956c5758fc7SSreekanth Reddy 		mrioc->dev_rmhs_cmds[i].reply = kzalloc(mrioc->reply_sz,
295713ef29eaSKashyap Desai 		    GFP_KERNEL);
295813ef29eaSKashyap Desai 		if (!mrioc->dev_rmhs_cmds[i].reply)
295913ef29eaSKashyap Desai 			goto out_failed;
296013ef29eaSKashyap Desai 	}
296113ef29eaSKashyap Desai 
2962c1af985dSSreekanth Reddy 	for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) {
2963c1af985dSSreekanth Reddy 		mrioc->evtack_cmds[i].reply = kzalloc(mrioc->reply_sz,
2964c1af985dSSreekanth Reddy 		    GFP_KERNEL);
2965c1af985dSSreekanth Reddy 		if (!mrioc->evtack_cmds[i].reply)
2966c1af985dSSreekanth Reddy 			goto out_failed;
2967c1af985dSSreekanth Reddy 	}
2968c1af985dSSreekanth Reddy 
2969c5758fc7SSreekanth Reddy 	mrioc->host_tm_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL);
2970e844adb1SKashyap Desai 	if (!mrioc->host_tm_cmds.reply)
2971e844adb1SKashyap Desai 		goto out_failed;
2972e844adb1SKashyap Desai 
297343ca1100SSumit Saxena 	mrioc->pel_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL);
297443ca1100SSumit Saxena 	if (!mrioc->pel_cmds.reply)
297543ca1100SSumit Saxena 		goto out_failed;
297643ca1100SSumit Saxena 
297743ca1100SSumit Saxena 	mrioc->pel_abort_cmd.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL);
297843ca1100SSumit Saxena 	if (!mrioc->pel_abort_cmd.reply)
297943ca1100SSumit Saxena 		goto out_failed;
298043ca1100SSumit Saxena 
2981339e6156SShin'ichiro Kawasaki 	mrioc->dev_handle_bitmap_bits = mrioc->facts.max_devhandle;
2982339e6156SShin'ichiro Kawasaki 	mrioc->removepend_bitmap = bitmap_zalloc(mrioc->dev_handle_bitmap_bits,
2983e844adb1SKashyap Desai 						 GFP_KERNEL);
2984e844adb1SKashyap Desai 	if (!mrioc->removepend_bitmap)
2985e844adb1SKashyap Desai 		goto out_failed;
2986e844adb1SKashyap Desai 
2987339e6156SShin'ichiro Kawasaki 	mrioc->devrem_bitmap = bitmap_zalloc(MPI3MR_NUM_DEVRMCMD, GFP_KERNEL);
2988e844adb1SKashyap Desai 	if (!mrioc->devrem_bitmap)
2989e844adb1SKashyap Desai 		goto out_failed;
2990e844adb1SKashyap Desai 
2991339e6156SShin'ichiro Kawasaki 	mrioc->evtack_cmds_bitmap = bitmap_zalloc(MPI3MR_NUM_EVTACKCMD,
2992c1af985dSSreekanth Reddy 						  GFP_KERNEL);
2993c1af985dSSreekanth Reddy 	if (!mrioc->evtack_cmds_bitmap)
2994c1af985dSSreekanth Reddy 		goto out_failed;
2995c1af985dSSreekanth Reddy 
2996824a1566SKashyap Desai 	mrioc->num_reply_bufs = mrioc->facts.max_reqs + MPI3MR_NUM_EVT_REPLIES;
2997824a1566SKashyap Desai 	mrioc->reply_free_qsz = mrioc->num_reply_bufs + 1;
2998824a1566SKashyap Desai 	mrioc->num_sense_bufs = mrioc->facts.max_reqs / MPI3MR_SENSEBUF_FACTOR;
2999824a1566SKashyap Desai 	mrioc->sense_buf_q_sz = mrioc->num_sense_bufs + 1;
3000824a1566SKashyap Desai 
3001824a1566SKashyap Desai 	/* reply buffer pool, 16 byte align */
3002c5758fc7SSreekanth Reddy 	sz = mrioc->num_reply_bufs * mrioc->reply_sz;
3003824a1566SKashyap Desai 	mrioc->reply_buf_pool = dma_pool_create("reply_buf pool",
3004824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 16, 0);
3005824a1566SKashyap Desai 	if (!mrioc->reply_buf_pool) {
3006824a1566SKashyap Desai 		ioc_err(mrioc, "reply buf pool: dma_pool_create failed\n");
3007824a1566SKashyap Desai 		goto out_failed;
3008824a1566SKashyap Desai 	}
3009824a1566SKashyap Desai 
3010824a1566SKashyap Desai 	mrioc->reply_buf = dma_pool_zalloc(mrioc->reply_buf_pool, GFP_KERNEL,
3011824a1566SKashyap Desai 	    &mrioc->reply_buf_dma);
3012824a1566SKashyap Desai 	if (!mrioc->reply_buf)
3013824a1566SKashyap Desai 		goto out_failed;
3014824a1566SKashyap Desai 
3015824a1566SKashyap Desai 	mrioc->reply_buf_dma_max_address = mrioc->reply_buf_dma + sz;
3016824a1566SKashyap Desai 
3017824a1566SKashyap Desai 	/* reply free queue, 8 byte align */
3018824a1566SKashyap Desai 	sz = mrioc->reply_free_qsz * 8;
3019824a1566SKashyap Desai 	mrioc->reply_free_q_pool = dma_pool_create("reply_free_q pool",
3020824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 8, 0);
3021824a1566SKashyap Desai 	if (!mrioc->reply_free_q_pool) {
3022824a1566SKashyap Desai 		ioc_err(mrioc, "reply_free_q pool: dma_pool_create failed\n");
3023824a1566SKashyap Desai 		goto out_failed;
3024824a1566SKashyap Desai 	}
3025824a1566SKashyap Desai 	mrioc->reply_free_q = dma_pool_zalloc(mrioc->reply_free_q_pool,
3026824a1566SKashyap Desai 	    GFP_KERNEL, &mrioc->reply_free_q_dma);
3027824a1566SKashyap Desai 	if (!mrioc->reply_free_q)
3028824a1566SKashyap Desai 		goto out_failed;
3029824a1566SKashyap Desai 
3030824a1566SKashyap Desai 	/* sense buffer pool,  4 byte align */
3031ec5ebd2cSSreekanth Reddy 	sz = mrioc->num_sense_bufs * MPI3MR_SENSE_BUF_SZ;
3032824a1566SKashyap Desai 	mrioc->sense_buf_pool = dma_pool_create("sense_buf pool",
3033824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 4, 0);
3034824a1566SKashyap Desai 	if (!mrioc->sense_buf_pool) {
3035824a1566SKashyap Desai 		ioc_err(mrioc, "sense_buf pool: dma_pool_create failed\n");
3036824a1566SKashyap Desai 		goto out_failed;
3037824a1566SKashyap Desai 	}
3038824a1566SKashyap Desai 	mrioc->sense_buf = dma_pool_zalloc(mrioc->sense_buf_pool, GFP_KERNEL,
3039824a1566SKashyap Desai 	    &mrioc->sense_buf_dma);
3040824a1566SKashyap Desai 	if (!mrioc->sense_buf)
3041824a1566SKashyap Desai 		goto out_failed;
3042824a1566SKashyap Desai 
3043824a1566SKashyap Desai 	/* sense buffer queue, 8 byte align */
3044824a1566SKashyap Desai 	sz = mrioc->sense_buf_q_sz * 8;
3045824a1566SKashyap Desai 	mrioc->sense_buf_q_pool = dma_pool_create("sense_buf_q pool",
3046824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 8, 0);
3047824a1566SKashyap Desai 	if (!mrioc->sense_buf_q_pool) {
3048824a1566SKashyap Desai 		ioc_err(mrioc, "sense_buf_q pool: dma_pool_create failed\n");
3049824a1566SKashyap Desai 		goto out_failed;
3050824a1566SKashyap Desai 	}
3051824a1566SKashyap Desai 	mrioc->sense_buf_q = dma_pool_zalloc(mrioc->sense_buf_q_pool,
3052824a1566SKashyap Desai 	    GFP_KERNEL, &mrioc->sense_buf_q_dma);
3053824a1566SKashyap Desai 	if (!mrioc->sense_buf_q)
3054824a1566SKashyap Desai 		goto out_failed;
3055824a1566SKashyap Desai 
3056e3605f65SSreekanth Reddy 	return retval;
3057e3605f65SSreekanth Reddy 
3058e3605f65SSreekanth Reddy out_failed:
3059e3605f65SSreekanth Reddy 	retval = -1;
3060e3605f65SSreekanth Reddy 	return retval;
3061e3605f65SSreekanth Reddy }
3062e3605f65SSreekanth Reddy 
3063e3605f65SSreekanth Reddy /**
3064e3605f65SSreekanth Reddy  * mpimr_initialize_reply_sbuf_queues - initialize reply sense
3065e3605f65SSreekanth Reddy  * buffers
3066e3605f65SSreekanth Reddy  * @mrioc: Adapter instance reference
3067e3605f65SSreekanth Reddy  *
3068e3605f65SSreekanth Reddy  * Helper function to initialize reply and sense buffers along
3069e3605f65SSreekanth Reddy  * with some debug prints.
3070e3605f65SSreekanth Reddy  *
3071e3605f65SSreekanth Reddy  * Return:  None.
3072e3605f65SSreekanth Reddy  */
3073e3605f65SSreekanth Reddy static void mpimr_initialize_reply_sbuf_queues(struct mpi3mr_ioc *mrioc)
3074e3605f65SSreekanth Reddy {
3075e3605f65SSreekanth Reddy 	u32 sz, i;
3076e3605f65SSreekanth Reddy 	dma_addr_t phy_addr;
3077e3605f65SSreekanth Reddy 
3078c5758fc7SSreekanth Reddy 	sz = mrioc->num_reply_bufs * mrioc->reply_sz;
3079824a1566SKashyap Desai 	ioc_info(mrioc,
3080824a1566SKashyap Desai 	    "reply buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n",
3081c5758fc7SSreekanth Reddy 	    mrioc->reply_buf, mrioc->num_reply_bufs, mrioc->reply_sz,
3082824a1566SKashyap Desai 	    (sz / 1024), (unsigned long long)mrioc->reply_buf_dma);
3083824a1566SKashyap Desai 	sz = mrioc->reply_free_qsz * 8;
3084824a1566SKashyap Desai 	ioc_info(mrioc,
3085824a1566SKashyap Desai 	    "reply_free_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n",
3086824a1566SKashyap Desai 	    mrioc->reply_free_q, mrioc->reply_free_qsz, 8, (sz / 1024),
3087824a1566SKashyap Desai 	    (unsigned long long)mrioc->reply_free_q_dma);
3088ec5ebd2cSSreekanth Reddy 	sz = mrioc->num_sense_bufs * MPI3MR_SENSE_BUF_SZ;
3089824a1566SKashyap Desai 	ioc_info(mrioc,
3090824a1566SKashyap Desai 	    "sense_buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n",
3091ec5ebd2cSSreekanth Reddy 	    mrioc->sense_buf, mrioc->num_sense_bufs, MPI3MR_SENSE_BUF_SZ,
3092824a1566SKashyap Desai 	    (sz / 1024), (unsigned long long)mrioc->sense_buf_dma);
3093824a1566SKashyap Desai 	sz = mrioc->sense_buf_q_sz * 8;
3094824a1566SKashyap Desai 	ioc_info(mrioc,
3095824a1566SKashyap Desai 	    "sense_buf_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n",
3096824a1566SKashyap Desai 	    mrioc->sense_buf_q, mrioc->sense_buf_q_sz, 8, (sz / 1024),
3097824a1566SKashyap Desai 	    (unsigned long long)mrioc->sense_buf_q_dma);
3098824a1566SKashyap Desai 
3099824a1566SKashyap Desai 	/* initialize Reply buffer Queue */
3100824a1566SKashyap Desai 	for (i = 0, phy_addr = mrioc->reply_buf_dma;
3101c5758fc7SSreekanth Reddy 	    i < mrioc->num_reply_bufs; i++, phy_addr += mrioc->reply_sz)
3102824a1566SKashyap Desai 		mrioc->reply_free_q[i] = cpu_to_le64(phy_addr);
3103824a1566SKashyap Desai 	mrioc->reply_free_q[i] = cpu_to_le64(0);
3104824a1566SKashyap Desai 
3105824a1566SKashyap Desai 	/* initialize Sense Buffer Queue */
3106824a1566SKashyap Desai 	for (i = 0, phy_addr = mrioc->sense_buf_dma;
3107ec5ebd2cSSreekanth Reddy 	    i < mrioc->num_sense_bufs; i++, phy_addr += MPI3MR_SENSE_BUF_SZ)
3108824a1566SKashyap Desai 		mrioc->sense_buf_q[i] = cpu_to_le64(phy_addr);
3109824a1566SKashyap Desai 	mrioc->sense_buf_q[i] = cpu_to_le64(0);
3110824a1566SKashyap Desai }
3111824a1566SKashyap Desai 
3112824a1566SKashyap Desai /**
3113824a1566SKashyap Desai  * mpi3mr_issue_iocinit - Send IOC Init
3114824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3115824a1566SKashyap Desai  *
3116824a1566SKashyap Desai  * Issue IOC Init MPI request through admin queue and wait for
3117824a1566SKashyap Desai  * the completion of it or time out.
3118824a1566SKashyap Desai  *
3119824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
3120824a1566SKashyap Desai  */
3121824a1566SKashyap Desai static int mpi3mr_issue_iocinit(struct mpi3mr_ioc *mrioc)
3122824a1566SKashyap Desai {
3123824a1566SKashyap Desai 	struct mpi3_ioc_init_request iocinit_req;
3124824a1566SKashyap Desai 	struct mpi3_driver_info_layout *drv_info;
3125824a1566SKashyap Desai 	dma_addr_t data_dma;
3126824a1566SKashyap Desai 	u32 data_len = sizeof(*drv_info);
3127824a1566SKashyap Desai 	int retval = 0;
3128824a1566SKashyap Desai 	ktime_t current_time;
3129824a1566SKashyap Desai 
3130824a1566SKashyap Desai 	drv_info = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma,
3131824a1566SKashyap Desai 	    GFP_KERNEL);
3132824a1566SKashyap Desai 	if (!drv_info) {
3133824a1566SKashyap Desai 		retval = -1;
3134824a1566SKashyap Desai 		goto out;
3135824a1566SKashyap Desai 	}
3136e3605f65SSreekanth Reddy 	mpimr_initialize_reply_sbuf_queues(mrioc);
3137e3605f65SSreekanth Reddy 
3138824a1566SKashyap Desai 	drv_info->information_length = cpu_to_le32(data_len);
3139aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->driver_signature, "Broadcom", sizeof(drv_info->driver_signature));
3140aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->os_name, utsname()->sysname, sizeof(drv_info->os_name));
3141aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->os_version, utsname()->release, sizeof(drv_info->os_version));
3142aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->driver_name, MPI3MR_DRIVER_NAME, sizeof(drv_info->driver_name));
3143aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->driver_version, MPI3MR_DRIVER_VERSION, sizeof(drv_info->driver_version));
3144aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->driver_release_date, MPI3MR_DRIVER_RELDATE,
3145aa0dc6a7SSreekanth Reddy 	    sizeof(drv_info->driver_release_date));
3146824a1566SKashyap Desai 	drv_info->driver_capabilities = 0;
3147824a1566SKashyap Desai 	memcpy((u8 *)&mrioc->driver_info, (u8 *)drv_info,
3148824a1566SKashyap Desai 	    sizeof(mrioc->driver_info));
3149824a1566SKashyap Desai 
3150824a1566SKashyap Desai 	memset(&iocinit_req, 0, sizeof(iocinit_req));
3151824a1566SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
3152824a1566SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
3153824a1566SKashyap Desai 		retval = -1;
3154824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCInit: Init command is in use\n");
3155824a1566SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
3156824a1566SKashyap Desai 		goto out;
3157824a1566SKashyap Desai 	}
3158824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
3159824a1566SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
3160824a1566SKashyap Desai 	mrioc->init_cmds.callback = NULL;
3161824a1566SKashyap Desai 	iocinit_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
3162824a1566SKashyap Desai 	iocinit_req.function = MPI3_FUNCTION_IOC_INIT;
3163824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.dev = MPI3_VERSION_DEV;
3164824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.unit = MPI3_VERSION_UNIT;
3165824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.major = MPI3_VERSION_MAJOR;
3166824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.minor = MPI3_VERSION_MINOR;
3167824a1566SKashyap Desai 	iocinit_req.who_init = MPI3_WHOINIT_HOST_DRIVER;
3168824a1566SKashyap Desai 	iocinit_req.reply_free_queue_depth = cpu_to_le16(mrioc->reply_free_qsz);
3169824a1566SKashyap Desai 	iocinit_req.reply_free_queue_address =
3170824a1566SKashyap Desai 	    cpu_to_le64(mrioc->reply_free_q_dma);
3171ec5ebd2cSSreekanth Reddy 	iocinit_req.sense_buffer_length = cpu_to_le16(MPI3MR_SENSE_BUF_SZ);
3172824a1566SKashyap Desai 	iocinit_req.sense_buffer_free_queue_depth =
3173824a1566SKashyap Desai 	    cpu_to_le16(mrioc->sense_buf_q_sz);
3174824a1566SKashyap Desai 	iocinit_req.sense_buffer_free_queue_address =
3175824a1566SKashyap Desai 	    cpu_to_le64(mrioc->sense_buf_q_dma);
3176824a1566SKashyap Desai 	iocinit_req.driver_information_address = cpu_to_le64(data_dma);
3177824a1566SKashyap Desai 
3178824a1566SKashyap Desai 	current_time = ktime_get_real();
3179824a1566SKashyap Desai 	iocinit_req.time_stamp = cpu_to_le64(ktime_to_ms(current_time));
3180824a1566SKashyap Desai 
3181824a1566SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
3182824a1566SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &iocinit_req,
3183824a1566SKashyap Desai 	    sizeof(iocinit_req), 1);
3184824a1566SKashyap Desai 	if (retval) {
3185824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCInit: Admin Post failed\n");
3186824a1566SKashyap Desai 		goto out_unlock;
3187824a1566SKashyap Desai 	}
3188824a1566SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
3189824a1566SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
3190824a1566SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
3191a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
3192824a1566SKashyap Desai 		    MPI3MR_RESET_FROM_IOCINIT_TIMEOUT);
3193a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "ioc_init timed out\n");
3194824a1566SKashyap Desai 		retval = -1;
3195824a1566SKashyap Desai 		goto out_unlock;
3196824a1566SKashyap Desai 	}
3197824a1566SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
3198824a1566SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
3199824a1566SKashyap Desai 		ioc_err(mrioc,
3200824a1566SKashyap Desai 		    "Issue IOCInit: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
3201824a1566SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
3202824a1566SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
3203824a1566SKashyap Desai 		retval = -1;
3204824a1566SKashyap Desai 		goto out_unlock;
3205824a1566SKashyap Desai 	}
3206824a1566SKashyap Desai 
3207e3605f65SSreekanth Reddy 	mrioc->reply_free_queue_host_index = mrioc->num_reply_bufs;
3208e3605f65SSreekanth Reddy 	writel(mrioc->reply_free_queue_host_index,
3209e3605f65SSreekanth Reddy 	    &mrioc->sysif_regs->reply_free_host_index);
3210e3605f65SSreekanth Reddy 
3211e3605f65SSreekanth Reddy 	mrioc->sbq_host_index = mrioc->num_sense_bufs;
3212e3605f65SSreekanth Reddy 	writel(mrioc->sbq_host_index,
3213e3605f65SSreekanth Reddy 	    &mrioc->sysif_regs->sense_buffer_free_host_index);
3214824a1566SKashyap Desai out_unlock:
3215824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
3216824a1566SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
3217824a1566SKashyap Desai 
3218824a1566SKashyap Desai out:
3219824a1566SKashyap Desai 	if (drv_info)
3220824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, data_len, drv_info,
3221824a1566SKashyap Desai 		    data_dma);
3222824a1566SKashyap Desai 
3223824a1566SKashyap Desai 	return retval;
3224824a1566SKashyap Desai }
3225824a1566SKashyap Desai 
3226824a1566SKashyap Desai /**
322713ef29eaSKashyap Desai  * mpi3mr_unmask_events - Unmask events in event mask bitmap
322813ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
322913ef29eaSKashyap Desai  * @event: MPI event ID
323013ef29eaSKashyap Desai  *
323113ef29eaSKashyap Desai  * Un mask the specific event by resetting the event_mask
323213ef29eaSKashyap Desai  * bitmap.
323313ef29eaSKashyap Desai  *
323413ef29eaSKashyap Desai  * Return: 0 on success, non-zero on failures.
323513ef29eaSKashyap Desai  */
323613ef29eaSKashyap Desai static void mpi3mr_unmask_events(struct mpi3mr_ioc *mrioc, u16 event)
323713ef29eaSKashyap Desai {
323813ef29eaSKashyap Desai 	u32 desired_event;
323913ef29eaSKashyap Desai 	u8 word;
324013ef29eaSKashyap Desai 
324113ef29eaSKashyap Desai 	if (event >= 128)
324213ef29eaSKashyap Desai 		return;
324313ef29eaSKashyap Desai 
324413ef29eaSKashyap Desai 	desired_event = (1 << (event % 32));
324513ef29eaSKashyap Desai 	word = event / 32;
324613ef29eaSKashyap Desai 
324713ef29eaSKashyap Desai 	mrioc->event_masks[word] &= ~desired_event;
324813ef29eaSKashyap Desai }
324913ef29eaSKashyap Desai 
325013ef29eaSKashyap Desai /**
325113ef29eaSKashyap Desai  * mpi3mr_issue_event_notification - Send event notification
325213ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
325313ef29eaSKashyap Desai  *
325413ef29eaSKashyap Desai  * Issue event notification MPI request through admin queue and
325513ef29eaSKashyap Desai  * wait for the completion of it or time out.
325613ef29eaSKashyap Desai  *
325713ef29eaSKashyap Desai  * Return: 0 on success, non-zero on failures.
325813ef29eaSKashyap Desai  */
325913ef29eaSKashyap Desai static int mpi3mr_issue_event_notification(struct mpi3mr_ioc *mrioc)
326013ef29eaSKashyap Desai {
326113ef29eaSKashyap Desai 	struct mpi3_event_notification_request evtnotify_req;
326213ef29eaSKashyap Desai 	int retval = 0;
326313ef29eaSKashyap Desai 	u8 i;
326413ef29eaSKashyap Desai 
326513ef29eaSKashyap Desai 	memset(&evtnotify_req, 0, sizeof(evtnotify_req));
326613ef29eaSKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
326713ef29eaSKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
326813ef29eaSKashyap Desai 		retval = -1;
326913ef29eaSKashyap Desai 		ioc_err(mrioc, "Issue EvtNotify: Init command is in use\n");
327013ef29eaSKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
327113ef29eaSKashyap Desai 		goto out;
327213ef29eaSKashyap Desai 	}
327313ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
327413ef29eaSKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
327513ef29eaSKashyap Desai 	mrioc->init_cmds.callback = NULL;
327613ef29eaSKashyap Desai 	evtnotify_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
327713ef29eaSKashyap Desai 	evtnotify_req.function = MPI3_FUNCTION_EVENT_NOTIFICATION;
327813ef29eaSKashyap Desai 	for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
327913ef29eaSKashyap Desai 		evtnotify_req.event_masks[i] =
328013ef29eaSKashyap Desai 		    cpu_to_le32(mrioc->event_masks[i]);
328113ef29eaSKashyap Desai 	init_completion(&mrioc->init_cmds.done);
328213ef29eaSKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &evtnotify_req,
328313ef29eaSKashyap Desai 	    sizeof(evtnotify_req), 1);
328413ef29eaSKashyap Desai 	if (retval) {
328513ef29eaSKashyap Desai 		ioc_err(mrioc, "Issue EvtNotify: Admin Post failed\n");
328613ef29eaSKashyap Desai 		goto out_unlock;
328713ef29eaSKashyap Desai 	}
328813ef29eaSKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
328913ef29eaSKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
329013ef29eaSKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
3291a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "event notification timed out\n");
3292a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
329313ef29eaSKashyap Desai 		    MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT);
329413ef29eaSKashyap Desai 		retval = -1;
329513ef29eaSKashyap Desai 		goto out_unlock;
329613ef29eaSKashyap Desai 	}
329713ef29eaSKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
329813ef29eaSKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
329913ef29eaSKashyap Desai 		ioc_err(mrioc,
330013ef29eaSKashyap Desai 		    "Issue EvtNotify: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
330113ef29eaSKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
330213ef29eaSKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
330313ef29eaSKashyap Desai 		retval = -1;
330413ef29eaSKashyap Desai 		goto out_unlock;
330513ef29eaSKashyap Desai 	}
330613ef29eaSKashyap Desai 
330713ef29eaSKashyap Desai out_unlock:
330813ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
330913ef29eaSKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
331013ef29eaSKashyap Desai out:
331113ef29eaSKashyap Desai 	return retval;
331213ef29eaSKashyap Desai }
331313ef29eaSKashyap Desai 
331413ef29eaSKashyap Desai /**
3315c1af985dSSreekanth Reddy  * mpi3mr_process_event_ack - Process event acknowledgment
331613ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
331713ef29eaSKashyap Desai  * @event: MPI3 event ID
3318c1af985dSSreekanth Reddy  * @event_ctx: event context
331913ef29eaSKashyap Desai  *
332013ef29eaSKashyap Desai  * Send event acknowledgment through admin queue and wait for
332113ef29eaSKashyap Desai  * it to complete.
332213ef29eaSKashyap Desai  *
332313ef29eaSKashyap Desai  * Return: 0 on success, non-zero on failures.
332413ef29eaSKashyap Desai  */
3325c1af985dSSreekanth Reddy int mpi3mr_process_event_ack(struct mpi3mr_ioc *mrioc, u8 event,
332613ef29eaSKashyap Desai 	u32 event_ctx)
332713ef29eaSKashyap Desai {
332813ef29eaSKashyap Desai 	struct mpi3_event_ack_request evtack_req;
332913ef29eaSKashyap Desai 	int retval = 0;
333013ef29eaSKashyap Desai 
333113ef29eaSKashyap Desai 	memset(&evtack_req, 0, sizeof(evtack_req));
333213ef29eaSKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
333313ef29eaSKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
333413ef29eaSKashyap Desai 		retval = -1;
333513ef29eaSKashyap Desai 		ioc_err(mrioc, "Send EvtAck: Init command is in use\n");
333613ef29eaSKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
333713ef29eaSKashyap Desai 		goto out;
333813ef29eaSKashyap Desai 	}
333913ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
334013ef29eaSKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
334113ef29eaSKashyap Desai 	mrioc->init_cmds.callback = NULL;
334213ef29eaSKashyap Desai 	evtack_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
334313ef29eaSKashyap Desai 	evtack_req.function = MPI3_FUNCTION_EVENT_ACK;
334413ef29eaSKashyap Desai 	evtack_req.event = event;
334513ef29eaSKashyap Desai 	evtack_req.event_context = cpu_to_le32(event_ctx);
334613ef29eaSKashyap Desai 
334713ef29eaSKashyap Desai 	init_completion(&mrioc->init_cmds.done);
334813ef29eaSKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &evtack_req,
334913ef29eaSKashyap Desai 	    sizeof(evtack_req), 1);
335013ef29eaSKashyap Desai 	if (retval) {
335113ef29eaSKashyap Desai 		ioc_err(mrioc, "Send EvtAck: Admin Post failed\n");
335213ef29eaSKashyap Desai 		goto out_unlock;
335313ef29eaSKashyap Desai 	}
335413ef29eaSKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
335513ef29eaSKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
335613ef29eaSKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
335713ef29eaSKashyap Desai 		ioc_err(mrioc, "Issue EvtNotify: command timed out\n");
3358fbaa9aa4SSreekanth Reddy 		if (!(mrioc->init_cmds.state & MPI3MR_CMD_RESET))
335913ef29eaSKashyap Desai 			mpi3mr_soft_reset_handler(mrioc,
336013ef29eaSKashyap Desai 			    MPI3MR_RESET_FROM_EVTACK_TIMEOUT, 1);
336113ef29eaSKashyap Desai 		retval = -1;
336213ef29eaSKashyap Desai 		goto out_unlock;
336313ef29eaSKashyap Desai 	}
336413ef29eaSKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
336513ef29eaSKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
336613ef29eaSKashyap Desai 		ioc_err(mrioc,
336713ef29eaSKashyap Desai 		    "Send EvtAck: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
336813ef29eaSKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
336913ef29eaSKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
337013ef29eaSKashyap Desai 		retval = -1;
337113ef29eaSKashyap Desai 		goto out_unlock;
337213ef29eaSKashyap Desai 	}
337313ef29eaSKashyap Desai 
337413ef29eaSKashyap Desai out_unlock:
337513ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
337613ef29eaSKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
337713ef29eaSKashyap Desai out:
337813ef29eaSKashyap Desai 	return retval;
337913ef29eaSKashyap Desai }
338013ef29eaSKashyap Desai 
338113ef29eaSKashyap Desai /**
3382824a1566SKashyap Desai  * mpi3mr_alloc_chain_bufs - Allocate chain buffers
3383824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3384824a1566SKashyap Desai  *
3385824a1566SKashyap Desai  * Allocate chain buffers and set a bitmap to indicate free
3386824a1566SKashyap Desai  * chain buffers. Chain buffers are used to pass the SGE
3387824a1566SKashyap Desai  * information along with MPI3 SCSI IO requests for host I/O.
3388824a1566SKashyap Desai  *
3389824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure
3390824a1566SKashyap Desai  */
3391824a1566SKashyap Desai static int mpi3mr_alloc_chain_bufs(struct mpi3mr_ioc *mrioc)
3392824a1566SKashyap Desai {
3393824a1566SKashyap Desai 	int retval = 0;
3394824a1566SKashyap Desai 	u32 sz, i;
3395824a1566SKashyap Desai 	u16 num_chains;
3396824a1566SKashyap Desai 
3397fe6db615SSreekanth Reddy 	if (mrioc->chain_sgl_list)
3398fe6db615SSreekanth Reddy 		return retval;
3399fe6db615SSreekanth Reddy 
3400824a1566SKashyap Desai 	num_chains = mrioc->max_host_ios / MPI3MR_CHAINBUF_FACTOR;
3401824a1566SKashyap Desai 
340274e1f30aSKashyap Desai 	if (prot_mask & (SHOST_DIX_TYPE0_PROTECTION
340374e1f30aSKashyap Desai 	    | SHOST_DIX_TYPE1_PROTECTION
340474e1f30aSKashyap Desai 	    | SHOST_DIX_TYPE2_PROTECTION
340574e1f30aSKashyap Desai 	    | SHOST_DIX_TYPE3_PROTECTION))
340674e1f30aSKashyap Desai 		num_chains += (num_chains / MPI3MR_CHAINBUFDIX_FACTOR);
340774e1f30aSKashyap Desai 
3408824a1566SKashyap Desai 	mrioc->chain_buf_count = num_chains;
3409824a1566SKashyap Desai 	sz = sizeof(struct chain_element) * num_chains;
3410824a1566SKashyap Desai 	mrioc->chain_sgl_list = kzalloc(sz, GFP_KERNEL);
3411824a1566SKashyap Desai 	if (!mrioc->chain_sgl_list)
3412824a1566SKashyap Desai 		goto out_failed;
3413824a1566SKashyap Desai 
3414824a1566SKashyap Desai 	sz = MPI3MR_PAGE_SIZE_4K;
3415824a1566SKashyap Desai 	mrioc->chain_buf_pool = dma_pool_create("chain_buf pool",
3416824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 16, 0);
3417824a1566SKashyap Desai 	if (!mrioc->chain_buf_pool) {
3418824a1566SKashyap Desai 		ioc_err(mrioc, "chain buf pool: dma_pool_create failed\n");
3419824a1566SKashyap Desai 		goto out_failed;
3420824a1566SKashyap Desai 	}
3421824a1566SKashyap Desai 
3422824a1566SKashyap Desai 	for (i = 0; i < num_chains; i++) {
3423824a1566SKashyap Desai 		mrioc->chain_sgl_list[i].addr =
3424824a1566SKashyap Desai 		    dma_pool_zalloc(mrioc->chain_buf_pool, GFP_KERNEL,
3425824a1566SKashyap Desai 		    &mrioc->chain_sgl_list[i].dma_addr);
3426824a1566SKashyap Desai 
3427824a1566SKashyap Desai 		if (!mrioc->chain_sgl_list[i].addr)
3428824a1566SKashyap Desai 			goto out_failed;
3429824a1566SKashyap Desai 	}
3430339e6156SShin'ichiro Kawasaki 	mrioc->chain_bitmap = bitmap_zalloc(num_chains, GFP_KERNEL);
3431824a1566SKashyap Desai 	if (!mrioc->chain_bitmap)
3432824a1566SKashyap Desai 		goto out_failed;
3433824a1566SKashyap Desai 	return retval;
3434824a1566SKashyap Desai out_failed:
3435824a1566SKashyap Desai 	retval = -1;
3436824a1566SKashyap Desai 	return retval;
3437824a1566SKashyap Desai }
3438824a1566SKashyap Desai 
3439824a1566SKashyap Desai /**
3440023ab2a9SKashyap Desai  * mpi3mr_port_enable_complete - Mark port enable complete
3441023ab2a9SKashyap Desai  * @mrioc: Adapter instance reference
3442023ab2a9SKashyap Desai  * @drv_cmd: Internal command tracker
3443023ab2a9SKashyap Desai  *
3444023ab2a9SKashyap Desai  * Call back for asynchronous port enable request sets the
3445023ab2a9SKashyap Desai  * driver command to indicate port enable request is complete.
3446023ab2a9SKashyap Desai  *
3447023ab2a9SKashyap Desai  * Return: Nothing
3448023ab2a9SKashyap Desai  */
3449023ab2a9SKashyap Desai static void mpi3mr_port_enable_complete(struct mpi3mr_ioc *mrioc,
3450023ab2a9SKashyap Desai 	struct mpi3mr_drv_cmd *drv_cmd)
3451023ab2a9SKashyap Desai {
3452023ab2a9SKashyap Desai 	drv_cmd->callback = NULL;
3453023ab2a9SKashyap Desai 	mrioc->scan_started = 0;
3454f2a79d20SSreekanth Reddy 	if (drv_cmd->state & MPI3MR_CMD_RESET)
3455f2a79d20SSreekanth Reddy 		mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR;
3456f2a79d20SSreekanth Reddy 	else
3457f2a79d20SSreekanth Reddy 		mrioc->scan_failed = drv_cmd->ioc_status;
3458f2a79d20SSreekanth Reddy 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
3459023ab2a9SKashyap Desai }
3460023ab2a9SKashyap Desai 
3461023ab2a9SKashyap Desai /**
3462023ab2a9SKashyap Desai  * mpi3mr_issue_port_enable - Issue Port Enable
3463023ab2a9SKashyap Desai  * @mrioc: Adapter instance reference
3464023ab2a9SKashyap Desai  * @async: Flag to wait for completion or not
3465023ab2a9SKashyap Desai  *
3466023ab2a9SKashyap Desai  * Issue Port Enable MPI request through admin queue and if the
3467023ab2a9SKashyap Desai  * async flag is not set wait for the completion of the port
3468023ab2a9SKashyap Desai  * enable or time out.
3469023ab2a9SKashyap Desai  *
3470023ab2a9SKashyap Desai  * Return: 0 on success, non-zero on failures.
3471023ab2a9SKashyap Desai  */
3472023ab2a9SKashyap Desai int mpi3mr_issue_port_enable(struct mpi3mr_ioc *mrioc, u8 async)
3473023ab2a9SKashyap Desai {
3474023ab2a9SKashyap Desai 	struct mpi3_port_enable_request pe_req;
3475023ab2a9SKashyap Desai 	int retval = 0;
3476023ab2a9SKashyap Desai 	u32 pe_timeout = MPI3MR_PORTENABLE_TIMEOUT;
3477023ab2a9SKashyap Desai 
3478023ab2a9SKashyap Desai 	memset(&pe_req, 0, sizeof(pe_req));
3479023ab2a9SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
3480023ab2a9SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
3481023ab2a9SKashyap Desai 		retval = -1;
3482023ab2a9SKashyap Desai 		ioc_err(mrioc, "Issue PortEnable: Init command is in use\n");
3483023ab2a9SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
3484023ab2a9SKashyap Desai 		goto out;
3485023ab2a9SKashyap Desai 	}
3486023ab2a9SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
3487023ab2a9SKashyap Desai 	if (async) {
3488023ab2a9SKashyap Desai 		mrioc->init_cmds.is_waiting = 0;
3489023ab2a9SKashyap Desai 		mrioc->init_cmds.callback = mpi3mr_port_enable_complete;
3490023ab2a9SKashyap Desai 	} else {
3491023ab2a9SKashyap Desai 		mrioc->init_cmds.is_waiting = 1;
3492023ab2a9SKashyap Desai 		mrioc->init_cmds.callback = NULL;
3493023ab2a9SKashyap Desai 		init_completion(&mrioc->init_cmds.done);
3494023ab2a9SKashyap Desai 	}
3495023ab2a9SKashyap Desai 	pe_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
3496023ab2a9SKashyap Desai 	pe_req.function = MPI3_FUNCTION_PORT_ENABLE;
3497023ab2a9SKashyap Desai 
3498023ab2a9SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &pe_req, sizeof(pe_req), 1);
3499023ab2a9SKashyap Desai 	if (retval) {
3500023ab2a9SKashyap Desai 		ioc_err(mrioc, "Issue PortEnable: Admin Post failed\n");
3501023ab2a9SKashyap Desai 		goto out_unlock;
3502023ab2a9SKashyap Desai 	}
3503a6856cc4SSreekanth Reddy 	if (async) {
3504a6856cc4SSreekanth Reddy 		mutex_unlock(&mrioc->init_cmds.mutex);
3505a6856cc4SSreekanth Reddy 		goto out;
3506a6856cc4SSreekanth Reddy 	}
3507a6856cc4SSreekanth Reddy 
3508a6856cc4SSreekanth Reddy 	wait_for_completion_timeout(&mrioc->init_cmds.done, (pe_timeout * HZ));
3509023ab2a9SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
3510a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "port enable timed out\n");
3511023ab2a9SKashyap Desai 		retval = -1;
3512a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc, MPI3MR_RESET_FROM_PE_TIMEOUT);
3513023ab2a9SKashyap Desai 		goto out_unlock;
3514023ab2a9SKashyap Desai 	}
3515023ab2a9SKashyap Desai 	mpi3mr_port_enable_complete(mrioc, &mrioc->init_cmds);
3516a6856cc4SSreekanth Reddy 
3517023ab2a9SKashyap Desai out_unlock:
3518a6856cc4SSreekanth Reddy 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
3519023ab2a9SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
3520023ab2a9SKashyap Desai out:
3521023ab2a9SKashyap Desai 	return retval;
3522023ab2a9SKashyap Desai }
3523023ab2a9SKashyap Desai 
3524ff9561e9SKashyap Desai /* Protocol type to name mapper structure */
3525ff9561e9SKashyap Desai static const struct {
3526ff9561e9SKashyap Desai 	u8 protocol;
3527ff9561e9SKashyap Desai 	char *name;
3528ff9561e9SKashyap Desai } mpi3mr_protocols[] = {
3529ff9561e9SKashyap Desai 	{ MPI3_IOCFACTS_PROTOCOL_SCSI_INITIATOR, "Initiator" },
3530ff9561e9SKashyap Desai 	{ MPI3_IOCFACTS_PROTOCOL_SCSI_TARGET, "Target" },
3531ff9561e9SKashyap Desai 	{ MPI3_IOCFACTS_PROTOCOL_NVME, "NVMe attachment" },
3532ff9561e9SKashyap Desai };
3533ff9561e9SKashyap Desai 
3534ff9561e9SKashyap Desai /* Capability to name mapper structure*/
3535ff9561e9SKashyap Desai static const struct {
3536ff9561e9SKashyap Desai 	u32 capability;
3537ff9561e9SKashyap Desai 	char *name;
3538ff9561e9SKashyap Desai } mpi3mr_capabilities[] = {
3539ff9561e9SKashyap Desai 	{ MPI3_IOCFACTS_CAPABILITY_RAID_CAPABLE, "RAID" },
3540c4723e68SSreekanth Reddy 	{ MPI3_IOCFACTS_CAPABILITY_MULTIPATH_ENABLED, "MultiPath" },
3541ff9561e9SKashyap Desai };
3542ff9561e9SKashyap Desai 
3543ff9561e9SKashyap Desai /**
3544ff9561e9SKashyap Desai  * mpi3mr_print_ioc_info - Display controller information
3545ff9561e9SKashyap Desai  * @mrioc: Adapter instance reference
3546ff9561e9SKashyap Desai  *
3547ff9561e9SKashyap Desai  * Display controller personalit, capability, supported
3548ff9561e9SKashyap Desai  * protocols etc.
3549ff9561e9SKashyap Desai  *
3550ff9561e9SKashyap Desai  * Return: Nothing
3551ff9561e9SKashyap Desai  */
3552ff9561e9SKashyap Desai static void
3553ff9561e9SKashyap Desai mpi3mr_print_ioc_info(struct mpi3mr_ioc *mrioc)
3554ff9561e9SKashyap Desai {
355576a4f7ccSDan Carpenter 	int i = 0, bytes_written = 0;
3556ff9561e9SKashyap Desai 	char personality[16];
3557ff9561e9SKashyap Desai 	char protocol[50] = {0};
3558ff9561e9SKashyap Desai 	char capabilities[100] = {0};
3559ff9561e9SKashyap Desai 	struct mpi3mr_compimg_ver *fwver = &mrioc->facts.fw_ver;
3560ff9561e9SKashyap Desai 
3561ff9561e9SKashyap Desai 	switch (mrioc->facts.personality) {
3562ff9561e9SKashyap Desai 	case MPI3_IOCFACTS_FLAGS_PERSONALITY_EHBA:
3563ff9561e9SKashyap Desai 		strncpy(personality, "Enhanced HBA", sizeof(personality));
3564ff9561e9SKashyap Desai 		break;
3565ff9561e9SKashyap Desai 	case MPI3_IOCFACTS_FLAGS_PERSONALITY_RAID_DDR:
3566ff9561e9SKashyap Desai 		strncpy(personality, "RAID", sizeof(personality));
3567ff9561e9SKashyap Desai 		break;
3568ff9561e9SKashyap Desai 	default:
3569ff9561e9SKashyap Desai 		strncpy(personality, "Unknown", sizeof(personality));
3570ff9561e9SKashyap Desai 		break;
3571ff9561e9SKashyap Desai 	}
3572ff9561e9SKashyap Desai 
3573ff9561e9SKashyap Desai 	ioc_info(mrioc, "Running in %s Personality", personality);
3574ff9561e9SKashyap Desai 
3575ff9561e9SKashyap Desai 	ioc_info(mrioc, "FW version(%d.%d.%d.%d.%d.%d)\n",
3576ff9561e9SKashyap Desai 	    fwver->gen_major, fwver->gen_minor, fwver->ph_major,
3577ff9561e9SKashyap Desai 	    fwver->ph_minor, fwver->cust_id, fwver->build_num);
3578ff9561e9SKashyap Desai 
3579ff9561e9SKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mpi3mr_protocols); i++) {
3580ff9561e9SKashyap Desai 		if (mrioc->facts.protocol_flags &
3581ff9561e9SKashyap Desai 		    mpi3mr_protocols[i].protocol) {
358230e99f05SDan Carpenter 			bytes_written += scnprintf(protocol + bytes_written,
358376a4f7ccSDan Carpenter 				    sizeof(protocol) - bytes_written, "%s%s",
358476a4f7ccSDan Carpenter 				    bytes_written ? "," : "",
3585ff9561e9SKashyap Desai 				    mpi3mr_protocols[i].name);
3586ff9561e9SKashyap Desai 		}
3587ff9561e9SKashyap Desai 	}
3588ff9561e9SKashyap Desai 
358976a4f7ccSDan Carpenter 	bytes_written = 0;
3590ff9561e9SKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mpi3mr_capabilities); i++) {
3591ff9561e9SKashyap Desai 		if (mrioc->facts.protocol_flags &
3592ff9561e9SKashyap Desai 		    mpi3mr_capabilities[i].capability) {
359330e99f05SDan Carpenter 			bytes_written += scnprintf(capabilities + bytes_written,
359476a4f7ccSDan Carpenter 				    sizeof(capabilities) - bytes_written, "%s%s",
359576a4f7ccSDan Carpenter 				    bytes_written ? "," : "",
3596ff9561e9SKashyap Desai 				    mpi3mr_capabilities[i].name);
3597ff9561e9SKashyap Desai 		}
3598ff9561e9SKashyap Desai 	}
3599ff9561e9SKashyap Desai 
3600ff9561e9SKashyap Desai 	ioc_info(mrioc, "Protocol=(%s), Capabilities=(%s)\n",
3601ff9561e9SKashyap Desai 		 protocol, capabilities);
3602ff9561e9SKashyap Desai }
3603ff9561e9SKashyap Desai 
3604023ab2a9SKashyap Desai /**
3605824a1566SKashyap Desai  * mpi3mr_cleanup_resources - Free PCI resources
3606824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3607824a1566SKashyap Desai  *
3608824a1566SKashyap Desai  * Unmap PCI device memory and disable PCI device.
3609824a1566SKashyap Desai  *
3610824a1566SKashyap Desai  * Return: 0 on success and non-zero on failure.
3611824a1566SKashyap Desai  */
3612824a1566SKashyap Desai void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc)
3613824a1566SKashyap Desai {
3614824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
3615824a1566SKashyap Desai 
3616824a1566SKashyap Desai 	mpi3mr_cleanup_isr(mrioc);
3617824a1566SKashyap Desai 
3618824a1566SKashyap Desai 	if (mrioc->sysif_regs) {
3619824a1566SKashyap Desai 		iounmap((void __iomem *)mrioc->sysif_regs);
3620824a1566SKashyap Desai 		mrioc->sysif_regs = NULL;
3621824a1566SKashyap Desai 	}
3622824a1566SKashyap Desai 
3623824a1566SKashyap Desai 	if (pci_is_enabled(pdev)) {
3624824a1566SKashyap Desai 		if (mrioc->bars)
3625824a1566SKashyap Desai 			pci_release_selected_regions(pdev, mrioc->bars);
3626824a1566SKashyap Desai 		pci_disable_device(pdev);
3627824a1566SKashyap Desai 	}
3628824a1566SKashyap Desai }
3629824a1566SKashyap Desai 
3630824a1566SKashyap Desai /**
3631824a1566SKashyap Desai  * mpi3mr_setup_resources - Enable PCI resources
3632824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3633824a1566SKashyap Desai  *
3634824a1566SKashyap Desai  * Enable PCI device memory, MSI-x registers and set DMA mask.
3635824a1566SKashyap Desai  *
3636824a1566SKashyap Desai  * Return: 0 on success and non-zero on failure.
3637824a1566SKashyap Desai  */
3638824a1566SKashyap Desai int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc)
3639824a1566SKashyap Desai {
3640824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
3641824a1566SKashyap Desai 	u32 memap_sz = 0;
3642824a1566SKashyap Desai 	int i, retval = 0, capb = 0;
3643824a1566SKashyap Desai 	u16 message_control;
3644824a1566SKashyap Desai 	u64 dma_mask = mrioc->dma_mask ? mrioc->dma_mask :
3645d347a951SSreekanth Reddy 	    ((sizeof(dma_addr_t) > 4) ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32));
3646824a1566SKashyap Desai 
3647824a1566SKashyap Desai 	if (pci_enable_device_mem(pdev)) {
3648824a1566SKashyap Desai 		ioc_err(mrioc, "pci_enable_device_mem: failed\n");
3649824a1566SKashyap Desai 		retval = -ENODEV;
3650824a1566SKashyap Desai 		goto out_failed;
3651824a1566SKashyap Desai 	}
3652824a1566SKashyap Desai 
3653824a1566SKashyap Desai 	capb = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
3654824a1566SKashyap Desai 	if (!capb) {
3655824a1566SKashyap Desai 		ioc_err(mrioc, "Unable to find MSI-X Capabilities\n");
3656824a1566SKashyap Desai 		retval = -ENODEV;
3657824a1566SKashyap Desai 		goto out_failed;
3658824a1566SKashyap Desai 	}
3659824a1566SKashyap Desai 	mrioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
3660824a1566SKashyap Desai 
3661824a1566SKashyap Desai 	if (pci_request_selected_regions(pdev, mrioc->bars,
3662824a1566SKashyap Desai 	    mrioc->driver_name)) {
3663824a1566SKashyap Desai 		ioc_err(mrioc, "pci_request_selected_regions: failed\n");
3664824a1566SKashyap Desai 		retval = -ENODEV;
3665824a1566SKashyap Desai 		goto out_failed;
3666824a1566SKashyap Desai 	}
3667824a1566SKashyap Desai 
3668824a1566SKashyap Desai 	for (i = 0; (i < DEVICE_COUNT_RESOURCE); i++) {
3669824a1566SKashyap Desai 		if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
3670824a1566SKashyap Desai 			mrioc->sysif_regs_phys = pci_resource_start(pdev, i);
3671824a1566SKashyap Desai 			memap_sz = pci_resource_len(pdev, i);
3672824a1566SKashyap Desai 			mrioc->sysif_regs =
3673824a1566SKashyap Desai 			    ioremap(mrioc->sysif_regs_phys, memap_sz);
3674824a1566SKashyap Desai 			break;
3675824a1566SKashyap Desai 		}
3676824a1566SKashyap Desai 	}
3677824a1566SKashyap Desai 
3678824a1566SKashyap Desai 	pci_set_master(pdev);
3679824a1566SKashyap Desai 
3680824a1566SKashyap Desai 	retval = dma_set_mask_and_coherent(&pdev->dev, dma_mask);
3681824a1566SKashyap Desai 	if (retval) {
3682824a1566SKashyap Desai 		if (dma_mask != DMA_BIT_MASK(32)) {
3683824a1566SKashyap Desai 			ioc_warn(mrioc, "Setting 64 bit DMA mask failed\n");
3684824a1566SKashyap Desai 			dma_mask = DMA_BIT_MASK(32);
3685824a1566SKashyap Desai 			retval = dma_set_mask_and_coherent(&pdev->dev,
3686824a1566SKashyap Desai 			    dma_mask);
3687824a1566SKashyap Desai 		}
3688824a1566SKashyap Desai 		if (retval) {
3689824a1566SKashyap Desai 			mrioc->dma_mask = 0;
3690824a1566SKashyap Desai 			ioc_err(mrioc, "Setting 32 bit DMA mask also failed\n");
3691824a1566SKashyap Desai 			goto out_failed;
3692824a1566SKashyap Desai 		}
3693824a1566SKashyap Desai 	}
3694824a1566SKashyap Desai 	mrioc->dma_mask = dma_mask;
3695824a1566SKashyap Desai 
3696824a1566SKashyap Desai 	if (!mrioc->sysif_regs) {
3697824a1566SKashyap Desai 		ioc_err(mrioc,
3698824a1566SKashyap Desai 		    "Unable to map adapter memory or resource not found\n");
3699824a1566SKashyap Desai 		retval = -EINVAL;
3700824a1566SKashyap Desai 		goto out_failed;
3701824a1566SKashyap Desai 	}
3702824a1566SKashyap Desai 
3703824a1566SKashyap Desai 	pci_read_config_word(pdev, capb + 2, &message_control);
3704824a1566SKashyap Desai 	mrioc->msix_count = (message_control & 0x3FF) + 1;
3705824a1566SKashyap Desai 
3706824a1566SKashyap Desai 	pci_save_state(pdev);
3707824a1566SKashyap Desai 
3708824a1566SKashyap Desai 	pci_set_drvdata(pdev, mrioc->shost);
3709824a1566SKashyap Desai 
3710824a1566SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
3711824a1566SKashyap Desai 
3712824a1566SKashyap Desai 	ioc_info(mrioc, "iomem(0x%016llx), mapped(0x%p), size(%d)\n",
3713824a1566SKashyap Desai 	    (unsigned long long)mrioc->sysif_regs_phys,
3714824a1566SKashyap Desai 	    mrioc->sysif_regs, memap_sz);
3715824a1566SKashyap Desai 	ioc_info(mrioc, "Number of MSI-X vectors found in capabilities: (%d)\n",
3716824a1566SKashyap Desai 	    mrioc->msix_count);
3717afd3a579SSreekanth Reddy 
3718afd3a579SSreekanth Reddy 	if (!reset_devices && poll_queues > 0)
3719afd3a579SSreekanth Reddy 		mrioc->requested_poll_qcount = min_t(int, poll_queues,
3720afd3a579SSreekanth Reddy 				mrioc->msix_count - 2);
3721824a1566SKashyap Desai 	return retval;
3722824a1566SKashyap Desai 
3723824a1566SKashyap Desai out_failed:
3724824a1566SKashyap Desai 	mpi3mr_cleanup_resources(mrioc);
3725824a1566SKashyap Desai 	return retval;
3726824a1566SKashyap Desai }
3727824a1566SKashyap Desai 
3728824a1566SKashyap Desai /**
3729e3605f65SSreekanth Reddy  * mpi3mr_enable_events - Enable required events
3730e3605f65SSreekanth Reddy  * @mrioc: Adapter instance reference
3731e3605f65SSreekanth Reddy  *
3732e3605f65SSreekanth Reddy  * This routine unmasks the events required by the driver by
3733e3605f65SSreekanth Reddy  * sennding appropriate event mask bitmapt through an event
3734e3605f65SSreekanth Reddy  * notification request.
3735e3605f65SSreekanth Reddy  *
3736e3605f65SSreekanth Reddy  * Return: 0 on success and non-zero on failure.
3737e3605f65SSreekanth Reddy  */
3738e3605f65SSreekanth Reddy static int mpi3mr_enable_events(struct mpi3mr_ioc *mrioc)
3739e3605f65SSreekanth Reddy {
3740e3605f65SSreekanth Reddy 	int retval = 0;
3741e3605f65SSreekanth Reddy 	u32  i;
3742e3605f65SSreekanth Reddy 
3743e3605f65SSreekanth Reddy 	for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
3744e3605f65SSreekanth Reddy 		mrioc->event_masks[i] = -1;
3745e3605f65SSreekanth Reddy 
3746e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_ADDED);
3747e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_INFO_CHANGED);
3748e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_STATUS_CHANGE);
3749e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE);
37507188c03fSSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_ADDED);
3751e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
3752e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DISCOVERY);
3753e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR);
3754e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_BROADCAST_PRIMITIVE);
3755e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST);
3756e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_ENUMERATION);
375778b76a07SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_PREPARE_FOR_RESET);
3758e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_CABLE_MGMT);
3759e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENERGY_PACK_CHANGE);
3760e3605f65SSreekanth Reddy 
3761e3605f65SSreekanth Reddy 	retval = mpi3mr_issue_event_notification(mrioc);
3762e3605f65SSreekanth Reddy 	if (retval)
3763e3605f65SSreekanth Reddy 		ioc_err(mrioc, "failed to issue event notification %d\n",
3764e3605f65SSreekanth Reddy 		    retval);
3765e3605f65SSreekanth Reddy 	return retval;
3766e3605f65SSreekanth Reddy }
3767e3605f65SSreekanth Reddy 
3768e3605f65SSreekanth Reddy /**
3769824a1566SKashyap Desai  * mpi3mr_init_ioc - Initialize the controller
3770824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3771824a1566SKashyap Desai  *
3772824a1566SKashyap Desai  * This the controller initialization routine, executed either
3773824a1566SKashyap Desai  * after soft reset or from pci probe callback.
3774824a1566SKashyap Desai  * Setup the required resources, memory map the controller
3775824a1566SKashyap Desai  * registers, create admin and operational reply queue pairs,
3776824a1566SKashyap Desai  * allocate required memory for reply pool, sense buffer pool,
3777824a1566SKashyap Desai  * issue IOC init request to the firmware, unmask the events and
3778824a1566SKashyap Desai  * issue port enable to discover SAS/SATA/NVMe devies and RAID
3779824a1566SKashyap Desai  * volumes.
3780824a1566SKashyap Desai  *
3781824a1566SKashyap Desai  * Return: 0 on success and non-zero on failure.
3782824a1566SKashyap Desai  */
3783fe6db615SSreekanth Reddy int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc)
3784824a1566SKashyap Desai {
3785824a1566SKashyap Desai 	int retval = 0;
3786fe6db615SSreekanth Reddy 	u8 retry = 0;
3787824a1566SKashyap Desai 	struct mpi3_ioc_facts_data facts_data;
3788f10af057SSreekanth Reddy 	u32 sz;
3789824a1566SKashyap Desai 
3790fe6db615SSreekanth Reddy retry_init:
3791824a1566SKashyap Desai 	retval = mpi3mr_bring_ioc_ready(mrioc);
3792824a1566SKashyap Desai 	if (retval) {
3793824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to bring ioc ready: error %d\n",
3794824a1566SKashyap Desai 		    retval);
3795fe6db615SSreekanth Reddy 		goto out_failed_noretry;
3796824a1566SKashyap Desai 	}
3797824a1566SKashyap Desai 
3798824a1566SKashyap Desai 	retval = mpi3mr_setup_isr(mrioc, 1);
3799824a1566SKashyap Desai 	if (retval) {
3800824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to setup ISR error %d\n",
3801824a1566SKashyap Desai 		    retval);
3802fe6db615SSreekanth Reddy 		goto out_failed_noretry;
3803824a1566SKashyap Desai 	}
3804824a1566SKashyap Desai 
3805824a1566SKashyap Desai 	retval = mpi3mr_issue_iocfacts(mrioc, &facts_data);
3806824a1566SKashyap Desai 	if (retval) {
3807824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to Issue IOC Facts %d\n",
3808824a1566SKashyap Desai 		    retval);
3809824a1566SKashyap Desai 		goto out_failed;
3810824a1566SKashyap Desai 	}
3811824a1566SKashyap Desai 
3812c5758fc7SSreekanth Reddy 	mrioc->max_host_ios = mrioc->facts.max_reqs - MPI3MR_INTERNAL_CMDS_RESVD;
3813c5758fc7SSreekanth Reddy 
3814f10af057SSreekanth Reddy 	mrioc->num_io_throttle_group = mrioc->facts.max_io_throttle_group;
3815f10af057SSreekanth Reddy 	atomic_set(&mrioc->pend_large_data_sz, 0);
3816f10af057SSreekanth Reddy 
3817c5758fc7SSreekanth Reddy 	if (reset_devices)
3818c5758fc7SSreekanth Reddy 		mrioc->max_host_ios = min_t(int, mrioc->max_host_ios,
3819c5758fc7SSreekanth Reddy 		    MPI3MR_HOST_IOS_KDUMP);
3820c5758fc7SSreekanth Reddy 
3821c4723e68SSreekanth Reddy 	if (!(mrioc->facts.ioc_capabilities &
3822c4723e68SSreekanth Reddy 	    MPI3_IOCFACTS_CAPABILITY_MULTIPATH_ENABLED)) {
3823c4723e68SSreekanth Reddy 		mrioc->sas_transport_enabled = 1;
3824626665e9SSreekanth Reddy 		mrioc->scsi_device_channel = 1;
3825626665e9SSreekanth Reddy 		mrioc->shost->max_channel = 1;
3826176d4aa6SSreekanth Reddy 		mrioc->shost->transportt = mpi3mr_transport_template;
3827c4723e68SSreekanth Reddy 	}
3828c4723e68SSreekanth Reddy 
3829c5758fc7SSreekanth Reddy 	mrioc->reply_sz = mrioc->facts.reply_sz;
3830fe6db615SSreekanth Reddy 
3831824a1566SKashyap Desai 	retval = mpi3mr_check_reset_dma_mask(mrioc);
3832824a1566SKashyap Desai 	if (retval) {
3833824a1566SKashyap Desai 		ioc_err(mrioc, "Resetting dma mask failed %d\n",
3834824a1566SKashyap Desai 		    retval);
3835fe6db615SSreekanth Reddy 		goto out_failed_noretry;
3836fb9b0457SKashyap Desai 	}
3837824a1566SKashyap Desai 
3838ff9561e9SKashyap Desai 	mpi3mr_print_ioc_info(mrioc);
3839ff9561e9SKashyap Desai 
3840c7983044STomas Henzl 	if (!mrioc->cfg_page) {
384132d457d5SSreekanth Reddy 		dprint_init(mrioc, "allocating config page buffers\n");
3842c7983044STomas Henzl 		mrioc->cfg_page_sz = MPI3MR_DEFAULT_CFG_PAGE_SZ;
384332d457d5SSreekanth Reddy 		mrioc->cfg_page = dma_alloc_coherent(&mrioc->pdev->dev,
3844c7983044STomas Henzl 		    mrioc->cfg_page_sz, &mrioc->cfg_page_dma, GFP_KERNEL);
3845ba8a9ba4SRanjan Kumar 		if (!mrioc->cfg_page) {
3846ba8a9ba4SRanjan Kumar 			retval = -1;
384732d457d5SSreekanth Reddy 			goto out_failed_noretry;
3848ba8a9ba4SRanjan Kumar 		}
3849c7983044STomas Henzl 	}
385032d457d5SSreekanth Reddy 
3851c7983044STomas Henzl 	if (!mrioc->init_cmds.reply) {
3852824a1566SKashyap Desai 		retval = mpi3mr_alloc_reply_sense_bufs(mrioc);
3853824a1566SKashyap Desai 		if (retval) {
3854824a1566SKashyap Desai 			ioc_err(mrioc,
3855824a1566SKashyap Desai 			    "%s :Failed to allocated reply sense buffers %d\n",
3856824a1566SKashyap Desai 			    __func__, retval);
3857fe6db615SSreekanth Reddy 			goto out_failed_noretry;
3858824a1566SKashyap Desai 		}
3859c7983044STomas Henzl 	}
3860824a1566SKashyap Desai 
3861c7983044STomas Henzl 	if (!mrioc->chain_sgl_list) {
3862824a1566SKashyap Desai 		retval = mpi3mr_alloc_chain_bufs(mrioc);
3863824a1566SKashyap Desai 		if (retval) {
3864824a1566SKashyap Desai 			ioc_err(mrioc, "Failed to allocated chain buffers %d\n",
3865824a1566SKashyap Desai 			    retval);
3866fe6db615SSreekanth Reddy 			goto out_failed_noretry;
3867fb9b0457SKashyap Desai 		}
3868c7983044STomas Henzl 	}
3869824a1566SKashyap Desai 
3870824a1566SKashyap Desai 	retval = mpi3mr_issue_iocinit(mrioc);
3871824a1566SKashyap Desai 	if (retval) {
3872824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to Issue IOC Init %d\n",
3873824a1566SKashyap Desai 		    retval);
3874824a1566SKashyap Desai 		goto out_failed;
3875824a1566SKashyap Desai 	}
3876824a1566SKashyap Desai 
38772ac794baSSreekanth Reddy 	retval = mpi3mr_print_pkg_ver(mrioc);
38782ac794baSSreekanth Reddy 	if (retval) {
38792ac794baSSreekanth Reddy 		ioc_err(mrioc, "failed to get package version\n");
38802ac794baSSreekanth Reddy 		goto out_failed;
38812ac794baSSreekanth Reddy 	}
38822ac794baSSreekanth Reddy 
3883824a1566SKashyap Desai 	retval = mpi3mr_setup_isr(mrioc, 0);
3884824a1566SKashyap Desai 	if (retval) {
3885824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to re-setup ISR, error %d\n",
3886824a1566SKashyap Desai 		    retval);
3887fe6db615SSreekanth Reddy 		goto out_failed_noretry;
3888fb9b0457SKashyap Desai 	}
3889824a1566SKashyap Desai 
3890c9566231SKashyap Desai 	retval = mpi3mr_create_op_queues(mrioc);
3891c9566231SKashyap Desai 	if (retval) {
3892c9566231SKashyap Desai 		ioc_err(mrioc, "Failed to create OpQueues error %d\n",
3893c9566231SKashyap Desai 		    retval);
3894c9566231SKashyap Desai 		goto out_failed;
3895c9566231SKashyap Desai 	}
3896c9566231SKashyap Desai 
389743ca1100SSumit Saxena 	if (!mrioc->pel_seqnum_virt) {
389843ca1100SSumit Saxena 		dprint_init(mrioc, "allocating memory for pel_seqnum_virt\n");
389943ca1100SSumit Saxena 		mrioc->pel_seqnum_sz = sizeof(struct mpi3_pel_seq);
390043ca1100SSumit Saxena 		mrioc->pel_seqnum_virt = dma_alloc_coherent(&mrioc->pdev->dev,
390143ca1100SSumit Saxena 		    mrioc->pel_seqnum_sz, &mrioc->pel_seqnum_dma,
390243ca1100SSumit Saxena 		    GFP_KERNEL);
3903bc7896d3SDan Carpenter 		if (!mrioc->pel_seqnum_virt) {
3904bc7896d3SDan Carpenter 			retval = -ENOMEM;
390543ca1100SSumit Saxena 			goto out_failed_noretry;
390643ca1100SSumit Saxena 		}
3907bc7896d3SDan Carpenter 	}
390843ca1100SSumit Saxena 
3909f10af057SSreekanth Reddy 	if (!mrioc->throttle_groups && mrioc->num_io_throttle_group) {
3910f10af057SSreekanth Reddy 		dprint_init(mrioc, "allocating memory for throttle groups\n");
3911f10af057SSreekanth Reddy 		sz = sizeof(struct mpi3mr_throttle_group_info);
3912c863a2dcSJules Irenge 		mrioc->throttle_groups = kcalloc(mrioc->num_io_throttle_group, sz, GFP_KERNEL);
3913ba8a9ba4SRanjan Kumar 		if (!mrioc->throttle_groups) {
3914ba8a9ba4SRanjan Kumar 			retval = -1;
3915f10af057SSreekanth Reddy 			goto out_failed_noretry;
3916f10af057SSreekanth Reddy 		}
3917ba8a9ba4SRanjan Kumar 	}
3918f10af057SSreekanth Reddy 
3919e3605f65SSreekanth Reddy 	retval = mpi3mr_enable_events(mrioc);
392013ef29eaSKashyap Desai 	if (retval) {
3921e3605f65SSreekanth Reddy 		ioc_err(mrioc, "failed to enable events %d\n",
392213ef29eaSKashyap Desai 		    retval);
392313ef29eaSKashyap Desai 		goto out_failed;
392413ef29eaSKashyap Desai 	}
392513ef29eaSKashyap Desai 
3926fe6db615SSreekanth Reddy 	ioc_info(mrioc, "controller initialization completed successfully\n");
3927824a1566SKashyap Desai 	return retval;
3928824a1566SKashyap Desai out_failed:
3929fe6db615SSreekanth Reddy 	if (retry < 2) {
3930fe6db615SSreekanth Reddy 		retry++;
3931fe6db615SSreekanth Reddy 		ioc_warn(mrioc, "retrying controller initialization, retry_count:%d\n",
3932fe6db615SSreekanth Reddy 		    retry);
3933fe6db615SSreekanth Reddy 		mpi3mr_memset_buffers(mrioc);
3934fe6db615SSreekanth Reddy 		goto retry_init;
3935fe6db615SSreekanth Reddy 	}
3936ba8a9ba4SRanjan Kumar 	retval = -1;
3937fe6db615SSreekanth Reddy out_failed_noretry:
3938fe6db615SSreekanth Reddy 	ioc_err(mrioc, "controller initialization failed\n");
3939fe6db615SSreekanth Reddy 	mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
3940fe6db615SSreekanth Reddy 	    MPI3MR_RESET_FROM_CTLR_CLEANUP);
3941fe6db615SSreekanth Reddy 	mrioc->unrecoverable = 1;
3942824a1566SKashyap Desai 	return retval;
3943824a1566SKashyap Desai }
3944824a1566SKashyap Desai 
3945c0b00a93SSreekanth Reddy /**
3946c0b00a93SSreekanth Reddy  * mpi3mr_reinit_ioc - Re-Initialize the controller
3947c0b00a93SSreekanth Reddy  * @mrioc: Adapter instance reference
3948c0b00a93SSreekanth Reddy  * @is_resume: Called from resume or reset path
3949c0b00a93SSreekanth Reddy  *
3950c0b00a93SSreekanth Reddy  * This the controller re-initialization routine, executed from
3951c0b00a93SSreekanth Reddy  * the soft reset handler or resume callback. Creates
3952c0b00a93SSreekanth Reddy  * operational reply queue pairs, allocate required memory for
3953c0b00a93SSreekanth Reddy  * reply pool, sense buffer pool, issue IOC init request to the
3954c0b00a93SSreekanth Reddy  * firmware, unmask the events and issue port enable to discover
3955c0b00a93SSreekanth Reddy  * SAS/SATA/NVMe devices and RAID volumes.
3956c0b00a93SSreekanth Reddy  *
3957c0b00a93SSreekanth Reddy  * Return: 0 on success and non-zero on failure.
3958c0b00a93SSreekanth Reddy  */
3959fe6db615SSreekanth Reddy int mpi3mr_reinit_ioc(struct mpi3mr_ioc *mrioc, u8 is_resume)
3960fe6db615SSreekanth Reddy {
3961c0b00a93SSreekanth Reddy 	int retval = 0;
3962c0b00a93SSreekanth Reddy 	u8 retry = 0;
3963c0b00a93SSreekanth Reddy 	struct mpi3_ioc_facts_data facts_data;
3964f2a79d20SSreekanth Reddy 	u32 pe_timeout, ioc_status;
3965fe6db615SSreekanth Reddy 
3966c0b00a93SSreekanth Reddy retry_init:
3967f2a79d20SSreekanth Reddy 	pe_timeout =
3968f2a79d20SSreekanth Reddy 	    (MPI3MR_PORTENABLE_TIMEOUT / MPI3MR_PORTENABLE_POLL_INTERVAL);
3969f2a79d20SSreekanth Reddy 
3970c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "bringing up the controller to ready state\n");
3971c0b00a93SSreekanth Reddy 	retval = mpi3mr_bring_ioc_ready(mrioc);
3972c0b00a93SSreekanth Reddy 	if (retval) {
3973c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to bring to ready state\n");
3974c0b00a93SSreekanth Reddy 		goto out_failed_noretry;
3975c0b00a93SSreekanth Reddy 	}
3976c0b00a93SSreekanth Reddy 
3977c0b00a93SSreekanth Reddy 	if (is_resume) {
3978c0b00a93SSreekanth Reddy 		dprint_reset(mrioc, "setting up single ISR\n");
3979c0b00a93SSreekanth Reddy 		retval = mpi3mr_setup_isr(mrioc, 1);
3980c0b00a93SSreekanth Reddy 		if (retval) {
3981c0b00a93SSreekanth Reddy 			ioc_err(mrioc, "failed to setup ISR\n");
3982c0b00a93SSreekanth Reddy 			goto out_failed_noretry;
3983c0b00a93SSreekanth Reddy 		}
3984c0b00a93SSreekanth Reddy 	} else
3985c0b00a93SSreekanth Reddy 		mpi3mr_ioc_enable_intr(mrioc);
3986c0b00a93SSreekanth Reddy 
3987c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "getting ioc_facts\n");
3988c0b00a93SSreekanth Reddy 	retval = mpi3mr_issue_iocfacts(mrioc, &facts_data);
3989c0b00a93SSreekanth Reddy 	if (retval) {
3990c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to get ioc_facts\n");
3991c0b00a93SSreekanth Reddy 		goto out_failed;
3992c0b00a93SSreekanth Reddy 	}
3993c0b00a93SSreekanth Reddy 
3994c5758fc7SSreekanth Reddy 	dprint_reset(mrioc, "validating ioc_facts\n");
3995c5758fc7SSreekanth Reddy 	retval = mpi3mr_revalidate_factsdata(mrioc);
3996c5758fc7SSreekanth Reddy 	if (retval) {
3997c5758fc7SSreekanth Reddy 		ioc_err(mrioc, "failed to revalidate ioc_facts data\n");
3998c5758fc7SSreekanth Reddy 		goto out_failed_noretry;
3999c5758fc7SSreekanth Reddy 	}
4000c0b00a93SSreekanth Reddy 
4001c0b00a93SSreekanth Reddy 	mpi3mr_print_ioc_info(mrioc);
4002c0b00a93SSreekanth Reddy 
4003c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "sending ioc_init\n");
4004c0b00a93SSreekanth Reddy 	retval = mpi3mr_issue_iocinit(mrioc);
4005c0b00a93SSreekanth Reddy 	if (retval) {
4006c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to send ioc_init\n");
4007c0b00a93SSreekanth Reddy 		goto out_failed;
4008c0b00a93SSreekanth Reddy 	}
4009c0b00a93SSreekanth Reddy 
4010c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "getting package version\n");
4011c0b00a93SSreekanth Reddy 	retval = mpi3mr_print_pkg_ver(mrioc);
4012c0b00a93SSreekanth Reddy 	if (retval) {
4013c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to get package version\n");
4014c0b00a93SSreekanth Reddy 		goto out_failed;
4015c0b00a93SSreekanth Reddy 	}
4016c0b00a93SSreekanth Reddy 
4017c0b00a93SSreekanth Reddy 	if (is_resume) {
4018c0b00a93SSreekanth Reddy 		dprint_reset(mrioc, "setting up multiple ISR\n");
4019c0b00a93SSreekanth Reddy 		retval = mpi3mr_setup_isr(mrioc, 0);
4020c0b00a93SSreekanth Reddy 		if (retval) {
4021c0b00a93SSreekanth Reddy 			ioc_err(mrioc, "failed to re-setup ISR\n");
4022c0b00a93SSreekanth Reddy 			goto out_failed_noretry;
4023c0b00a93SSreekanth Reddy 		}
4024c0b00a93SSreekanth Reddy 	}
4025c0b00a93SSreekanth Reddy 
4026c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "creating operational queue pairs\n");
4027c0b00a93SSreekanth Reddy 	retval = mpi3mr_create_op_queues(mrioc);
4028c0b00a93SSreekanth Reddy 	if (retval) {
4029c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to create operational queue pairs\n");
4030c0b00a93SSreekanth Reddy 		goto out_failed;
4031c0b00a93SSreekanth Reddy 	}
4032c0b00a93SSreekanth Reddy 
403343ca1100SSumit Saxena 	if (!mrioc->pel_seqnum_virt) {
403443ca1100SSumit Saxena 		dprint_reset(mrioc, "allocating memory for pel_seqnum_virt\n");
403543ca1100SSumit Saxena 		mrioc->pel_seqnum_sz = sizeof(struct mpi3_pel_seq);
403643ca1100SSumit Saxena 		mrioc->pel_seqnum_virt = dma_alloc_coherent(&mrioc->pdev->dev,
403743ca1100SSumit Saxena 		    mrioc->pel_seqnum_sz, &mrioc->pel_seqnum_dma,
403843ca1100SSumit Saxena 		    GFP_KERNEL);
4039bc7896d3SDan Carpenter 		if (!mrioc->pel_seqnum_virt) {
4040bc7896d3SDan Carpenter 			retval = -ENOMEM;
404143ca1100SSumit Saxena 			goto out_failed_noretry;
404243ca1100SSumit Saxena 		}
4043bc7896d3SDan Carpenter 	}
404443ca1100SSumit Saxena 
4045c0b00a93SSreekanth Reddy 	if (mrioc->shost->nr_hw_queues > mrioc->num_op_reply_q) {
4046c0b00a93SSreekanth Reddy 		ioc_err(mrioc,
40475867b856SColin Ian King 		    "cannot create minimum number of operational queues expected:%d created:%d\n",
4048c0b00a93SSreekanth Reddy 		    mrioc->shost->nr_hw_queues, mrioc->num_op_reply_q);
4049ba8a9ba4SRanjan Kumar 		retval = -1;
4050c0b00a93SSreekanth Reddy 		goto out_failed_noretry;
4051c0b00a93SSreekanth Reddy 	}
4052c0b00a93SSreekanth Reddy 
4053c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "enabling events\n");
4054c0b00a93SSreekanth Reddy 	retval = mpi3mr_enable_events(mrioc);
4055c0b00a93SSreekanth Reddy 	if (retval) {
4056c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to enable events\n");
4057c0b00a93SSreekanth Reddy 		goto out_failed;
4058c0b00a93SSreekanth Reddy 	}
4059c0b00a93SSreekanth Reddy 
40602745ce0eSSreekanth Reddy 	mrioc->device_refresh_on = 1;
40612745ce0eSSreekanth Reddy 	mpi3mr_add_event_wait_for_device_refresh(mrioc);
40622745ce0eSSreekanth Reddy 
4063c0b00a93SSreekanth Reddy 	ioc_info(mrioc, "sending port enable\n");
4064f2a79d20SSreekanth Reddy 	retval = mpi3mr_issue_port_enable(mrioc, 1);
4065c0b00a93SSreekanth Reddy 	if (retval) {
4066c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to issue port enable\n");
4067c0b00a93SSreekanth Reddy 		goto out_failed;
4068c0b00a93SSreekanth Reddy 	}
4069f2a79d20SSreekanth Reddy 	do {
4070f2a79d20SSreekanth Reddy 		ssleep(MPI3MR_PORTENABLE_POLL_INTERVAL);
4071f2a79d20SSreekanth Reddy 		if (mrioc->init_cmds.state == MPI3MR_CMD_NOTUSED)
4072f2a79d20SSreekanth Reddy 			break;
4073f2a79d20SSreekanth Reddy 		if (!pci_device_is_present(mrioc->pdev))
4074f2a79d20SSreekanth Reddy 			mrioc->unrecoverable = 1;
4075f2a79d20SSreekanth Reddy 		if (mrioc->unrecoverable) {
4076f2a79d20SSreekanth Reddy 			retval = -1;
4077f2a79d20SSreekanth Reddy 			goto out_failed_noretry;
4078f2a79d20SSreekanth Reddy 		}
4079f2a79d20SSreekanth Reddy 		ioc_status = readl(&mrioc->sysif_regs->ioc_status);
4080f2a79d20SSreekanth Reddy 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) ||
4081f2a79d20SSreekanth Reddy 		    (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) {
4082f2a79d20SSreekanth Reddy 			mpi3mr_print_fault_info(mrioc);
4083f2a79d20SSreekanth Reddy 			mrioc->init_cmds.is_waiting = 0;
4084f2a79d20SSreekanth Reddy 			mrioc->init_cmds.callback = NULL;
4085f2a79d20SSreekanth Reddy 			mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
4086f2a79d20SSreekanth Reddy 			goto out_failed;
4087f2a79d20SSreekanth Reddy 		}
4088f2a79d20SSreekanth Reddy 	} while (--pe_timeout);
4089f2a79d20SSreekanth Reddy 
4090f2a79d20SSreekanth Reddy 	if (!pe_timeout) {
4091f2a79d20SSreekanth Reddy 		ioc_err(mrioc, "port enable timed out\n");
4092f2a79d20SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
4093f2a79d20SSreekanth Reddy 		    MPI3MR_RESET_FROM_PE_TIMEOUT);
4094f2a79d20SSreekanth Reddy 		mrioc->init_cmds.is_waiting = 0;
4095f2a79d20SSreekanth Reddy 		mrioc->init_cmds.callback = NULL;
4096f2a79d20SSreekanth Reddy 		mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
4097f2a79d20SSreekanth Reddy 		goto out_failed;
4098f2a79d20SSreekanth Reddy 	} else if (mrioc->scan_failed) {
4099f2a79d20SSreekanth Reddy 		ioc_err(mrioc,
4100f2a79d20SSreekanth Reddy 		    "port enable failed with status=0x%04x\n",
4101f2a79d20SSreekanth Reddy 		    mrioc->scan_failed);
4102f2a79d20SSreekanth Reddy 	} else
4103f2a79d20SSreekanth Reddy 		ioc_info(mrioc, "port enable completed successfully\n");
4104c0b00a93SSreekanth Reddy 
4105c0b00a93SSreekanth Reddy 	ioc_info(mrioc, "controller %s completed successfully\n",
4106c0b00a93SSreekanth Reddy 	    (is_resume)?"resume":"re-initialization");
4107c0b00a93SSreekanth Reddy 	return retval;
4108c0b00a93SSreekanth Reddy out_failed:
4109c0b00a93SSreekanth Reddy 	if (retry < 2) {
4110c0b00a93SSreekanth Reddy 		retry++;
4111c0b00a93SSreekanth Reddy 		ioc_warn(mrioc, "retrying controller %s, retry_count:%d\n",
4112c0b00a93SSreekanth Reddy 		    (is_resume)?"resume":"re-initialization", retry);
4113c0b00a93SSreekanth Reddy 		mpi3mr_memset_buffers(mrioc);
4114c0b00a93SSreekanth Reddy 		goto retry_init;
4115c0b00a93SSreekanth Reddy 	}
4116ba8a9ba4SRanjan Kumar 	retval = -1;
4117c0b00a93SSreekanth Reddy out_failed_noretry:
4118c0b00a93SSreekanth Reddy 	ioc_err(mrioc, "controller %s is failed\n",
4119c0b00a93SSreekanth Reddy 	    (is_resume)?"resume":"re-initialization");
4120c0b00a93SSreekanth Reddy 	mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
4121c0b00a93SSreekanth Reddy 	    MPI3MR_RESET_FROM_CTLR_CLEANUP);
4122c0b00a93SSreekanth Reddy 	mrioc->unrecoverable = 1;
4123c0b00a93SSreekanth Reddy 	return retval;
4124fe6db615SSreekanth Reddy }
4125fe6db615SSreekanth Reddy 
4126824a1566SKashyap Desai /**
4127fb9b0457SKashyap Desai  * mpi3mr_memset_op_reply_q_buffers - memset the operational reply queue's
4128fb9b0457SKashyap Desai  *					segments
4129fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
4130fb9b0457SKashyap Desai  * @qidx: Operational reply queue index
4131fb9b0457SKashyap Desai  *
4132fb9b0457SKashyap Desai  * Return: Nothing.
4133fb9b0457SKashyap Desai  */
4134fb9b0457SKashyap Desai static void mpi3mr_memset_op_reply_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx)
4135fb9b0457SKashyap Desai {
4136fb9b0457SKashyap Desai 	struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
4137fb9b0457SKashyap Desai 	struct segments *segments;
4138fb9b0457SKashyap Desai 	int i, size;
4139fb9b0457SKashyap Desai 
4140fb9b0457SKashyap Desai 	if (!op_reply_q->q_segments)
4141fb9b0457SKashyap Desai 		return;
4142fb9b0457SKashyap Desai 
4143fb9b0457SKashyap Desai 	size = op_reply_q->segment_qd * mrioc->op_reply_desc_sz;
4144fb9b0457SKashyap Desai 	segments = op_reply_q->q_segments;
4145fb9b0457SKashyap Desai 	for (i = 0; i < op_reply_q->num_segments; i++)
4146fb9b0457SKashyap Desai 		memset(segments[i].segment, 0, size);
4147fb9b0457SKashyap Desai }
4148fb9b0457SKashyap Desai 
4149fb9b0457SKashyap Desai /**
4150fb9b0457SKashyap Desai  * mpi3mr_memset_op_req_q_buffers - memset the operational request queue's
4151fb9b0457SKashyap Desai  *					segments
4152fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
4153fb9b0457SKashyap Desai  * @qidx: Operational request queue index
4154fb9b0457SKashyap Desai  *
4155fb9b0457SKashyap Desai  * Return: Nothing.
4156fb9b0457SKashyap Desai  */
4157fb9b0457SKashyap Desai static void mpi3mr_memset_op_req_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx)
4158fb9b0457SKashyap Desai {
4159fb9b0457SKashyap Desai 	struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx;
4160fb9b0457SKashyap Desai 	struct segments *segments;
4161fb9b0457SKashyap Desai 	int i, size;
4162fb9b0457SKashyap Desai 
4163fb9b0457SKashyap Desai 	if (!op_req_q->q_segments)
4164fb9b0457SKashyap Desai 		return;
4165fb9b0457SKashyap Desai 
4166fb9b0457SKashyap Desai 	size = op_req_q->segment_qd * mrioc->facts.op_req_sz;
4167fb9b0457SKashyap Desai 	segments = op_req_q->q_segments;
4168fb9b0457SKashyap Desai 	for (i = 0; i < op_req_q->num_segments; i++)
4169fb9b0457SKashyap Desai 		memset(segments[i].segment, 0, size);
4170fb9b0457SKashyap Desai }
4171fb9b0457SKashyap Desai 
4172fb9b0457SKashyap Desai /**
4173fb9b0457SKashyap Desai  * mpi3mr_memset_buffers - memset memory for a controller
4174fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
4175fb9b0457SKashyap Desai  *
4176fb9b0457SKashyap Desai  * clear all the memory allocated for a controller, typically
4177fb9b0457SKashyap Desai  * called post reset to reuse the memory allocated during the
4178fb9b0457SKashyap Desai  * controller init.
4179fb9b0457SKashyap Desai  *
4180fb9b0457SKashyap Desai  * Return: Nothing.
4181fb9b0457SKashyap Desai  */
41820da66348SKashyap Desai void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc)
4183fb9b0457SKashyap Desai {
4184fb9b0457SKashyap Desai 	u16 i;
4185f10af057SSreekanth Reddy 	struct mpi3mr_throttle_group_info *tg;
4186fb9b0457SKashyap Desai 
4187fe6db615SSreekanth Reddy 	mrioc->change_count = 0;
4188afd3a579SSreekanth Reddy 	mrioc->active_poll_qcount = 0;
4189afd3a579SSreekanth Reddy 	mrioc->default_qcount = 0;
4190fe6db615SSreekanth Reddy 	if (mrioc->admin_req_base)
4191fb9b0457SKashyap Desai 		memset(mrioc->admin_req_base, 0, mrioc->admin_req_q_sz);
4192fe6db615SSreekanth Reddy 	if (mrioc->admin_reply_base)
4193fb9b0457SKashyap Desai 		memset(mrioc->admin_reply_base, 0, mrioc->admin_reply_q_sz);
419402ca7da2SRanjan Kumar 	atomic_set(&mrioc->admin_reply_q_in_use, 0);
4195fb9b0457SKashyap Desai 
4196fe6db615SSreekanth Reddy 	if (mrioc->init_cmds.reply) {
4197fb9b0457SKashyap Desai 		memset(mrioc->init_cmds.reply, 0, sizeof(*mrioc->init_cmds.reply));
4198f5e6d5a3SSumit Saxena 		memset(mrioc->bsg_cmds.reply, 0,
4199f5e6d5a3SSumit Saxena 		    sizeof(*mrioc->bsg_cmds.reply));
4200e844adb1SKashyap Desai 		memset(mrioc->host_tm_cmds.reply, 0,
4201e844adb1SKashyap Desai 		    sizeof(*mrioc->host_tm_cmds.reply));
420243ca1100SSumit Saxena 		memset(mrioc->pel_cmds.reply, 0,
420343ca1100SSumit Saxena 		    sizeof(*mrioc->pel_cmds.reply));
420443ca1100SSumit Saxena 		memset(mrioc->pel_abort_cmd.reply, 0,
420543ca1100SSumit Saxena 		    sizeof(*mrioc->pel_abort_cmd.reply));
42062bd37e28SSreekanth Reddy 		memset(mrioc->transport_cmds.reply, 0,
42072bd37e28SSreekanth Reddy 		    sizeof(*mrioc->transport_cmds.reply));
4208fb9b0457SKashyap Desai 		for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++)
4209fb9b0457SKashyap Desai 			memset(mrioc->dev_rmhs_cmds[i].reply, 0,
4210fb9b0457SKashyap Desai 			    sizeof(*mrioc->dev_rmhs_cmds[i].reply));
4211c1af985dSSreekanth Reddy 		for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++)
4212c1af985dSSreekanth Reddy 			memset(mrioc->evtack_cmds[i].reply, 0,
4213c1af985dSSreekanth Reddy 			    sizeof(*mrioc->evtack_cmds[i].reply));
4214339e6156SShin'ichiro Kawasaki 		bitmap_clear(mrioc->removepend_bitmap, 0,
4215339e6156SShin'ichiro Kawasaki 			     mrioc->dev_handle_bitmap_bits);
4216339e6156SShin'ichiro Kawasaki 		bitmap_clear(mrioc->devrem_bitmap, 0, MPI3MR_NUM_DEVRMCMD);
4217339e6156SShin'ichiro Kawasaki 		bitmap_clear(mrioc->evtack_cmds_bitmap, 0,
4218339e6156SShin'ichiro Kawasaki 			     MPI3MR_NUM_EVTACKCMD);
4219fe6db615SSreekanth Reddy 	}
4220fb9b0457SKashyap Desai 
4221fb9b0457SKashyap Desai 	for (i = 0; i < mrioc->num_queues; i++) {
4222fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].qid = 0;
4223fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].ci = 0;
4224fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].num_replies = 0;
4225fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].ephase = 0;
4226463429f8SKashyap Desai 		atomic_set(&mrioc->op_reply_qinfo[i].pend_ios, 0);
4227463429f8SKashyap Desai 		atomic_set(&mrioc->op_reply_qinfo[i].in_use, 0);
4228fb9b0457SKashyap Desai 		mpi3mr_memset_op_reply_q_buffers(mrioc, i);
4229fb9b0457SKashyap Desai 
4230fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].ci = 0;
4231fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].pi = 0;
4232fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].num_requests = 0;
4233fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].qid = 0;
4234fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].reply_qid = 0;
4235fb9b0457SKashyap Desai 		spin_lock_init(&mrioc->req_qinfo[i].q_lock);
4236fb9b0457SKashyap Desai 		mpi3mr_memset_op_req_q_buffers(mrioc, i);
4237fb9b0457SKashyap Desai 	}
4238f10af057SSreekanth Reddy 
4239f10af057SSreekanth Reddy 	atomic_set(&mrioc->pend_large_data_sz, 0);
4240f10af057SSreekanth Reddy 	if (mrioc->throttle_groups) {
4241f10af057SSreekanth Reddy 		tg = mrioc->throttle_groups;
4242f10af057SSreekanth Reddy 		for (i = 0; i < mrioc->num_io_throttle_group; i++, tg++) {
4243f10af057SSreekanth Reddy 			tg->id = 0;
4244cf1ce8b7SSreekanth Reddy 			tg->fw_qd = 0;
4245cf1ce8b7SSreekanth Reddy 			tg->modified_qd = 0;
4246f10af057SSreekanth Reddy 			tg->io_divert = 0;
4247cf1ce8b7SSreekanth Reddy 			tg->need_qd_reduction = 0;
4248f10af057SSreekanth Reddy 			tg->high = 0;
4249f10af057SSreekanth Reddy 			tg->low = 0;
4250cf1ce8b7SSreekanth Reddy 			tg->qd_reduction = 0;
4251f10af057SSreekanth Reddy 			atomic_set(&tg->pend_large_data_sz, 0);
4252f10af057SSreekanth Reddy 		}
4253f10af057SSreekanth Reddy 	}
4254fb9b0457SKashyap Desai }
4255fb9b0457SKashyap Desai 
4256fb9b0457SKashyap Desai /**
4257824a1566SKashyap Desai  * mpi3mr_free_mem - Free memory allocated for a controller
4258824a1566SKashyap Desai  * @mrioc: Adapter instance reference
4259824a1566SKashyap Desai  *
4260824a1566SKashyap Desai  * Free all the memory allocated for a controller.
4261824a1566SKashyap Desai  *
4262824a1566SKashyap Desai  * Return: Nothing.
4263824a1566SKashyap Desai  */
4264fe6db615SSreekanth Reddy void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc)
4265824a1566SKashyap Desai {
4266824a1566SKashyap Desai 	u16 i;
4267824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info;
4268824a1566SKashyap Desai 
4269130fc180SSreekanth Reddy 	mpi3mr_free_enclosure_list(mrioc);
4270130fc180SSreekanth Reddy 
4271824a1566SKashyap Desai 	if (mrioc->sense_buf_pool) {
4272824a1566SKashyap Desai 		if (mrioc->sense_buf)
4273824a1566SKashyap Desai 			dma_pool_free(mrioc->sense_buf_pool, mrioc->sense_buf,
4274824a1566SKashyap Desai 			    mrioc->sense_buf_dma);
4275824a1566SKashyap Desai 		dma_pool_destroy(mrioc->sense_buf_pool);
4276824a1566SKashyap Desai 		mrioc->sense_buf = NULL;
4277824a1566SKashyap Desai 		mrioc->sense_buf_pool = NULL;
4278824a1566SKashyap Desai 	}
4279824a1566SKashyap Desai 	if (mrioc->sense_buf_q_pool) {
4280824a1566SKashyap Desai 		if (mrioc->sense_buf_q)
4281824a1566SKashyap Desai 			dma_pool_free(mrioc->sense_buf_q_pool,
4282824a1566SKashyap Desai 			    mrioc->sense_buf_q, mrioc->sense_buf_q_dma);
4283824a1566SKashyap Desai 		dma_pool_destroy(mrioc->sense_buf_q_pool);
4284824a1566SKashyap Desai 		mrioc->sense_buf_q = NULL;
4285824a1566SKashyap Desai 		mrioc->sense_buf_q_pool = NULL;
4286824a1566SKashyap Desai 	}
4287824a1566SKashyap Desai 
4288824a1566SKashyap Desai 	if (mrioc->reply_buf_pool) {
4289824a1566SKashyap Desai 		if (mrioc->reply_buf)
4290824a1566SKashyap Desai 			dma_pool_free(mrioc->reply_buf_pool, mrioc->reply_buf,
4291824a1566SKashyap Desai 			    mrioc->reply_buf_dma);
4292824a1566SKashyap Desai 		dma_pool_destroy(mrioc->reply_buf_pool);
4293824a1566SKashyap Desai 		mrioc->reply_buf = NULL;
4294824a1566SKashyap Desai 		mrioc->reply_buf_pool = NULL;
4295824a1566SKashyap Desai 	}
4296824a1566SKashyap Desai 	if (mrioc->reply_free_q_pool) {
4297824a1566SKashyap Desai 		if (mrioc->reply_free_q)
4298824a1566SKashyap Desai 			dma_pool_free(mrioc->reply_free_q_pool,
4299824a1566SKashyap Desai 			    mrioc->reply_free_q, mrioc->reply_free_q_dma);
4300824a1566SKashyap Desai 		dma_pool_destroy(mrioc->reply_free_q_pool);
4301824a1566SKashyap Desai 		mrioc->reply_free_q = NULL;
4302824a1566SKashyap Desai 		mrioc->reply_free_q_pool = NULL;
4303824a1566SKashyap Desai 	}
4304824a1566SKashyap Desai 
4305c9566231SKashyap Desai 	for (i = 0; i < mrioc->num_op_req_q; i++)
4306c9566231SKashyap Desai 		mpi3mr_free_op_req_q_segments(mrioc, i);
4307c9566231SKashyap Desai 
4308c9566231SKashyap Desai 	for (i = 0; i < mrioc->num_op_reply_q; i++)
4309c9566231SKashyap Desai 		mpi3mr_free_op_reply_q_segments(mrioc, i);
4310c9566231SKashyap Desai 
4311824a1566SKashyap Desai 	for (i = 0; i < mrioc->intr_info_count; i++) {
4312824a1566SKashyap Desai 		intr_info = mrioc->intr_info + i;
4313824a1566SKashyap Desai 		intr_info->op_reply_q = NULL;
4314824a1566SKashyap Desai 	}
4315824a1566SKashyap Desai 
4316824a1566SKashyap Desai 	kfree(mrioc->req_qinfo);
4317824a1566SKashyap Desai 	mrioc->req_qinfo = NULL;
4318824a1566SKashyap Desai 	mrioc->num_op_req_q = 0;
4319824a1566SKashyap Desai 
4320824a1566SKashyap Desai 	kfree(mrioc->op_reply_qinfo);
4321824a1566SKashyap Desai 	mrioc->op_reply_qinfo = NULL;
4322824a1566SKashyap Desai 	mrioc->num_op_reply_q = 0;
4323824a1566SKashyap Desai 
4324824a1566SKashyap Desai 	kfree(mrioc->init_cmds.reply);
4325824a1566SKashyap Desai 	mrioc->init_cmds.reply = NULL;
4326824a1566SKashyap Desai 
4327f5e6d5a3SSumit Saxena 	kfree(mrioc->bsg_cmds.reply);
4328f5e6d5a3SSumit Saxena 	mrioc->bsg_cmds.reply = NULL;
4329f5e6d5a3SSumit Saxena 
4330e844adb1SKashyap Desai 	kfree(mrioc->host_tm_cmds.reply);
4331e844adb1SKashyap Desai 	mrioc->host_tm_cmds.reply = NULL;
4332e844adb1SKashyap Desai 
433343ca1100SSumit Saxena 	kfree(mrioc->pel_cmds.reply);
433443ca1100SSumit Saxena 	mrioc->pel_cmds.reply = NULL;
433543ca1100SSumit Saxena 
433643ca1100SSumit Saxena 	kfree(mrioc->pel_abort_cmd.reply);
433743ca1100SSumit Saxena 	mrioc->pel_abort_cmd.reply = NULL;
433843ca1100SSumit Saxena 
4339c1af985dSSreekanth Reddy 	for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) {
4340c1af985dSSreekanth Reddy 		kfree(mrioc->evtack_cmds[i].reply);
4341c1af985dSSreekanth Reddy 		mrioc->evtack_cmds[i].reply = NULL;
4342c1af985dSSreekanth Reddy 	}
4343c1af985dSSreekanth Reddy 
4344339e6156SShin'ichiro Kawasaki 	bitmap_free(mrioc->removepend_bitmap);
4345e844adb1SKashyap Desai 	mrioc->removepend_bitmap = NULL;
4346e844adb1SKashyap Desai 
4347339e6156SShin'ichiro Kawasaki 	bitmap_free(mrioc->devrem_bitmap);
4348e844adb1SKashyap Desai 	mrioc->devrem_bitmap = NULL;
4349e844adb1SKashyap Desai 
4350339e6156SShin'ichiro Kawasaki 	bitmap_free(mrioc->evtack_cmds_bitmap);
4351c1af985dSSreekanth Reddy 	mrioc->evtack_cmds_bitmap = NULL;
4352c1af985dSSreekanth Reddy 
4353339e6156SShin'ichiro Kawasaki 	bitmap_free(mrioc->chain_bitmap);
4354824a1566SKashyap Desai 	mrioc->chain_bitmap = NULL;
4355824a1566SKashyap Desai 
43562bd37e28SSreekanth Reddy 	kfree(mrioc->transport_cmds.reply);
43572bd37e28SSreekanth Reddy 	mrioc->transport_cmds.reply = NULL;
43582bd37e28SSreekanth Reddy 
435913ef29eaSKashyap Desai 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
436013ef29eaSKashyap Desai 		kfree(mrioc->dev_rmhs_cmds[i].reply);
436113ef29eaSKashyap Desai 		mrioc->dev_rmhs_cmds[i].reply = NULL;
436213ef29eaSKashyap Desai 	}
436313ef29eaSKashyap Desai 
4364824a1566SKashyap Desai 	if (mrioc->chain_buf_pool) {
4365824a1566SKashyap Desai 		for (i = 0; i < mrioc->chain_buf_count; i++) {
4366824a1566SKashyap Desai 			if (mrioc->chain_sgl_list[i].addr) {
4367824a1566SKashyap Desai 				dma_pool_free(mrioc->chain_buf_pool,
4368824a1566SKashyap Desai 				    mrioc->chain_sgl_list[i].addr,
4369824a1566SKashyap Desai 				    mrioc->chain_sgl_list[i].dma_addr);
4370824a1566SKashyap Desai 				mrioc->chain_sgl_list[i].addr = NULL;
4371824a1566SKashyap Desai 			}
4372824a1566SKashyap Desai 		}
4373824a1566SKashyap Desai 		dma_pool_destroy(mrioc->chain_buf_pool);
4374824a1566SKashyap Desai 		mrioc->chain_buf_pool = NULL;
4375824a1566SKashyap Desai 	}
4376824a1566SKashyap Desai 
4377824a1566SKashyap Desai 	kfree(mrioc->chain_sgl_list);
4378824a1566SKashyap Desai 	mrioc->chain_sgl_list = NULL;
4379824a1566SKashyap Desai 
4380824a1566SKashyap Desai 	if (mrioc->admin_reply_base) {
4381824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz,
4382824a1566SKashyap Desai 		    mrioc->admin_reply_base, mrioc->admin_reply_dma);
4383824a1566SKashyap Desai 		mrioc->admin_reply_base = NULL;
4384824a1566SKashyap Desai 	}
4385824a1566SKashyap Desai 	if (mrioc->admin_req_base) {
4386824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz,
4387824a1566SKashyap Desai 		    mrioc->admin_req_base, mrioc->admin_req_dma);
4388824a1566SKashyap Desai 		mrioc->admin_req_base = NULL;
4389824a1566SKashyap Desai 	}
43907d2b0217STomas Henzl 	if (mrioc->cfg_page) {
43917d2b0217STomas Henzl 		dma_free_coherent(&mrioc->pdev->dev, mrioc->cfg_page_sz,
43927d2b0217STomas Henzl 		    mrioc->cfg_page, mrioc->cfg_page_dma);
43937d2b0217STomas Henzl 		mrioc->cfg_page = NULL;
43947d2b0217STomas Henzl 	}
439543ca1100SSumit Saxena 	if (mrioc->pel_seqnum_virt) {
439643ca1100SSumit Saxena 		dma_free_coherent(&mrioc->pdev->dev, mrioc->pel_seqnum_sz,
439743ca1100SSumit Saxena 		    mrioc->pel_seqnum_virt, mrioc->pel_seqnum_dma);
439843ca1100SSumit Saxena 		mrioc->pel_seqnum_virt = NULL;
439943ca1100SSumit Saxena 	}
440043ca1100SSumit Saxena 
4401f305a7b6STomas Henzl 	kfree(mrioc->throttle_groups);
4402f305a7b6STomas Henzl 	mrioc->throttle_groups = NULL;
4403f305a7b6STomas Henzl 
440443ca1100SSumit Saxena 	kfree(mrioc->logdata_buf);
440543ca1100SSumit Saxena 	mrioc->logdata_buf = NULL;
440643ca1100SSumit Saxena 
4407824a1566SKashyap Desai }
4408824a1566SKashyap Desai 
4409824a1566SKashyap Desai /**
4410824a1566SKashyap Desai  * mpi3mr_issue_ioc_shutdown - shutdown controller
4411824a1566SKashyap Desai  * @mrioc: Adapter instance reference
4412824a1566SKashyap Desai  *
4413824a1566SKashyap Desai  * Send shutodwn notification to the controller and wait for the
4414824a1566SKashyap Desai  * shutdown_timeout for it to be completed.
4415824a1566SKashyap Desai  *
4416824a1566SKashyap Desai  * Return: Nothing.
4417824a1566SKashyap Desai  */
4418824a1566SKashyap Desai static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc)
4419824a1566SKashyap Desai {
4420824a1566SKashyap Desai 	u32 ioc_config, ioc_status;
4421824a1566SKashyap Desai 	u8 retval = 1;
4422824a1566SKashyap Desai 	u32 timeout = MPI3MR_DEFAULT_SHUTDOWN_TIME * 10;
4423824a1566SKashyap Desai 
4424824a1566SKashyap Desai 	ioc_info(mrioc, "Issuing shutdown Notification\n");
4425824a1566SKashyap Desai 	if (mrioc->unrecoverable) {
4426824a1566SKashyap Desai 		ioc_warn(mrioc,
4427824a1566SKashyap Desai 		    "IOC is unrecoverable shutdown is not issued\n");
4428824a1566SKashyap Desai 		return;
4429824a1566SKashyap Desai 	}
4430824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
4431824a1566SKashyap Desai 	if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
4432824a1566SKashyap Desai 	    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS) {
4433824a1566SKashyap Desai 		ioc_info(mrioc, "shutdown already in progress\n");
4434824a1566SKashyap Desai 		return;
4435824a1566SKashyap Desai 	}
4436824a1566SKashyap Desai 
4437824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
4438824a1566SKashyap Desai 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL;
4439ec5ebd2cSSreekanth Reddy 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN_SEND_REQ;
4440824a1566SKashyap Desai 
4441824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
4442824a1566SKashyap Desai 
4443824a1566SKashyap Desai 	if (mrioc->facts.shutdown_timeout)
4444824a1566SKashyap Desai 		timeout = mrioc->facts.shutdown_timeout * 10;
4445824a1566SKashyap Desai 
4446824a1566SKashyap Desai 	do {
4447824a1566SKashyap Desai 		ioc_status = readl(&mrioc->sysif_regs->ioc_status);
4448824a1566SKashyap Desai 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
4449824a1566SKashyap Desai 		    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_COMPLETE) {
4450824a1566SKashyap Desai 			retval = 0;
4451824a1566SKashyap Desai 			break;
4452824a1566SKashyap Desai 		}
4453824a1566SKashyap Desai 		msleep(100);
4454824a1566SKashyap Desai 	} while (--timeout);
4455824a1566SKashyap Desai 
4456824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
4457824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
4458824a1566SKashyap Desai 
4459824a1566SKashyap Desai 	if (retval) {
4460824a1566SKashyap Desai 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
4461824a1566SKashyap Desai 		    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS)
4462824a1566SKashyap Desai 			ioc_warn(mrioc,
4463824a1566SKashyap Desai 			    "shutdown still in progress after timeout\n");
4464824a1566SKashyap Desai 	}
4465824a1566SKashyap Desai 
4466824a1566SKashyap Desai 	ioc_info(mrioc,
4467824a1566SKashyap Desai 	    "Base IOC Sts/Config after %s shutdown is (0x%x)/(0x%x)\n",
4468824a1566SKashyap Desai 	    (!retval) ? "successful" : "failed", ioc_status,
4469824a1566SKashyap Desai 	    ioc_config);
4470824a1566SKashyap Desai }
4471824a1566SKashyap Desai 
4472824a1566SKashyap Desai /**
4473824a1566SKashyap Desai  * mpi3mr_cleanup_ioc - Cleanup controller
4474824a1566SKashyap Desai  * @mrioc: Adapter instance reference
44753bb3c24eSYang Li  *
4476824a1566SKashyap Desai  * controller cleanup handler, Message unit reset or soft reset
4477fe6db615SSreekanth Reddy  * and shutdown notification is issued to the controller.
4478824a1566SKashyap Desai  *
4479824a1566SKashyap Desai  * Return: Nothing.
4480824a1566SKashyap Desai  */
4481fe6db615SSreekanth Reddy void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc)
4482824a1566SKashyap Desai {
4483824a1566SKashyap Desai 	enum mpi3mr_iocstate ioc_state;
4484824a1566SKashyap Desai 
4485fe6db615SSreekanth Reddy 	dprint_exit(mrioc, "cleaning up the controller\n");
4486824a1566SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
4487824a1566SKashyap Desai 
4488824a1566SKashyap Desai 	ioc_state = mpi3mr_get_iocstate(mrioc);
4489824a1566SKashyap Desai 
4490824a1566SKashyap Desai 	if ((!mrioc->unrecoverable) && (!mrioc->reset_in_progress) &&
4491824a1566SKashyap Desai 	    (ioc_state == MRIOC_STATE_READY)) {
4492824a1566SKashyap Desai 		if (mpi3mr_issue_and_process_mur(mrioc,
4493824a1566SKashyap Desai 		    MPI3MR_RESET_FROM_CTLR_CLEANUP))
4494824a1566SKashyap Desai 			mpi3mr_issue_reset(mrioc,
4495824a1566SKashyap Desai 			    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
4496824a1566SKashyap Desai 			    MPI3MR_RESET_FROM_MUR_FAILURE);
4497824a1566SKashyap Desai 		mpi3mr_issue_ioc_shutdown(mrioc);
4498824a1566SKashyap Desai 	}
4499fe6db615SSreekanth Reddy 	dprint_exit(mrioc, "controller cleanup completed\n");
4500fb9b0457SKashyap Desai }
4501fb9b0457SKashyap Desai 
4502fb9b0457SKashyap Desai /**
4503fb9b0457SKashyap Desai  * mpi3mr_drv_cmd_comp_reset - Flush a internal driver command
4504fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
4505fb9b0457SKashyap Desai  * @cmdptr: Internal command tracker
4506fb9b0457SKashyap Desai  *
4507fb9b0457SKashyap Desai  * Complete an internal driver commands with state indicating it
4508fb9b0457SKashyap Desai  * is completed due to reset.
4509fb9b0457SKashyap Desai  *
4510fb9b0457SKashyap Desai  * Return: Nothing.
4511fb9b0457SKashyap Desai  */
4512fb9b0457SKashyap Desai static inline void mpi3mr_drv_cmd_comp_reset(struct mpi3mr_ioc *mrioc,
4513fb9b0457SKashyap Desai 	struct mpi3mr_drv_cmd *cmdptr)
4514fb9b0457SKashyap Desai {
4515fb9b0457SKashyap Desai 	if (cmdptr->state & MPI3MR_CMD_PENDING) {
4516fb9b0457SKashyap Desai 		cmdptr->state |= MPI3MR_CMD_RESET;
4517fb9b0457SKashyap Desai 		cmdptr->state &= ~MPI3MR_CMD_PENDING;
4518fb9b0457SKashyap Desai 		if (cmdptr->is_waiting) {
4519fb9b0457SKashyap Desai 			complete(&cmdptr->done);
4520fb9b0457SKashyap Desai 			cmdptr->is_waiting = 0;
4521fb9b0457SKashyap Desai 		} else if (cmdptr->callback)
4522fb9b0457SKashyap Desai 			cmdptr->callback(mrioc, cmdptr);
4523fb9b0457SKashyap Desai 	}
4524fb9b0457SKashyap Desai }
4525fb9b0457SKashyap Desai 
4526fb9b0457SKashyap Desai /**
4527fb9b0457SKashyap Desai  * mpi3mr_flush_drv_cmds - Flush internaldriver commands
4528fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
4529fb9b0457SKashyap Desai  *
4530fb9b0457SKashyap Desai  * Flush all internal driver commands post reset
4531fb9b0457SKashyap Desai  *
4532fb9b0457SKashyap Desai  * Return: Nothing.
4533fb9b0457SKashyap Desai  */
4534f2a79d20SSreekanth Reddy void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc)
4535fb9b0457SKashyap Desai {
4536fb9b0457SKashyap Desai 	struct mpi3mr_drv_cmd *cmdptr;
4537fb9b0457SKashyap Desai 	u8 i;
4538fb9b0457SKashyap Desai 
4539fb9b0457SKashyap Desai 	cmdptr = &mrioc->init_cmds;
4540fb9b0457SKashyap Desai 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
454132d457d5SSreekanth Reddy 
454232d457d5SSreekanth Reddy 	cmdptr = &mrioc->cfg_cmds;
454332d457d5SSreekanth Reddy 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
454432d457d5SSreekanth Reddy 
4545f5e6d5a3SSumit Saxena 	cmdptr = &mrioc->bsg_cmds;
4546f5e6d5a3SSumit Saxena 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
4547e844adb1SKashyap Desai 	cmdptr = &mrioc->host_tm_cmds;
4548e844adb1SKashyap Desai 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
4549fb9b0457SKashyap Desai 
4550fb9b0457SKashyap Desai 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
4551fb9b0457SKashyap Desai 		cmdptr = &mrioc->dev_rmhs_cmds[i];
4552fb9b0457SKashyap Desai 		mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
4553fb9b0457SKashyap Desai 	}
4554c1af985dSSreekanth Reddy 
4555c1af985dSSreekanth Reddy 	for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) {
4556c1af985dSSreekanth Reddy 		cmdptr = &mrioc->evtack_cmds[i];
4557c1af985dSSreekanth Reddy 		mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
4558c1af985dSSreekanth Reddy 	}
455943ca1100SSumit Saxena 
456043ca1100SSumit Saxena 	cmdptr = &mrioc->pel_cmds;
456143ca1100SSumit Saxena 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
456243ca1100SSumit Saxena 
456343ca1100SSumit Saxena 	cmdptr = &mrioc->pel_abort_cmd;
456443ca1100SSumit Saxena 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
456543ca1100SSumit Saxena 
45662bd37e28SSreekanth Reddy 	cmdptr = &mrioc->transport_cmds;
45672bd37e28SSreekanth Reddy 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
456843ca1100SSumit Saxena }
456943ca1100SSumit Saxena 
457043ca1100SSumit Saxena /**
457143ca1100SSumit Saxena  * mpi3mr_pel_wait_post - Issue PEL Wait
457243ca1100SSumit Saxena  * @mrioc: Adapter instance reference
457343ca1100SSumit Saxena  * @drv_cmd: Internal command tracker
457443ca1100SSumit Saxena  *
457543ca1100SSumit Saxena  * Issue PEL Wait MPI request through admin queue and return.
457643ca1100SSumit Saxena  *
457743ca1100SSumit Saxena  * Return: Nothing.
457843ca1100SSumit Saxena  */
457943ca1100SSumit Saxena static void mpi3mr_pel_wait_post(struct mpi3mr_ioc *mrioc,
458043ca1100SSumit Saxena 	struct mpi3mr_drv_cmd *drv_cmd)
458143ca1100SSumit Saxena {
458243ca1100SSumit Saxena 	struct mpi3_pel_req_action_wait pel_wait;
458343ca1100SSumit Saxena 
458443ca1100SSumit Saxena 	mrioc->pel_abort_requested = false;
458543ca1100SSumit Saxena 
458643ca1100SSumit Saxena 	memset(&pel_wait, 0, sizeof(pel_wait));
458743ca1100SSumit Saxena 	drv_cmd->state = MPI3MR_CMD_PENDING;
458843ca1100SSumit Saxena 	drv_cmd->is_waiting = 0;
458943ca1100SSumit Saxena 	drv_cmd->callback = mpi3mr_pel_wait_complete;
459043ca1100SSumit Saxena 	drv_cmd->ioc_status = 0;
459143ca1100SSumit Saxena 	drv_cmd->ioc_loginfo = 0;
459243ca1100SSumit Saxena 	pel_wait.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_PEL_WAIT);
459343ca1100SSumit Saxena 	pel_wait.function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG;
459443ca1100SSumit Saxena 	pel_wait.action = MPI3_PEL_ACTION_WAIT;
459543ca1100SSumit Saxena 	pel_wait.starting_sequence_number = cpu_to_le32(mrioc->pel_newest_seqnum);
459643ca1100SSumit Saxena 	pel_wait.locale = cpu_to_le16(mrioc->pel_locale);
459743ca1100SSumit Saxena 	pel_wait.class = cpu_to_le16(mrioc->pel_class);
459843ca1100SSumit Saxena 	pel_wait.wait_time = MPI3_PEL_WAITTIME_INFINITE_WAIT;
459943ca1100SSumit Saxena 	dprint_bsg_info(mrioc, "sending pel_wait seqnum(%d), class(%d), locale(0x%08x)\n",
460043ca1100SSumit Saxena 	    mrioc->pel_newest_seqnum, mrioc->pel_class, mrioc->pel_locale);
460143ca1100SSumit Saxena 
460243ca1100SSumit Saxena 	if (mpi3mr_admin_request_post(mrioc, &pel_wait, sizeof(pel_wait), 0)) {
460343ca1100SSumit Saxena 		dprint_bsg_err(mrioc,
460443ca1100SSumit Saxena 			    "Issuing PELWait: Admin post failed\n");
460543ca1100SSumit Saxena 		drv_cmd->state = MPI3MR_CMD_NOTUSED;
460643ca1100SSumit Saxena 		drv_cmd->callback = NULL;
460743ca1100SSumit Saxena 		drv_cmd->retry_count = 0;
460843ca1100SSumit Saxena 		mrioc->pel_enabled = false;
460943ca1100SSumit Saxena 	}
461043ca1100SSumit Saxena }
461143ca1100SSumit Saxena 
461243ca1100SSumit Saxena /**
461343ca1100SSumit Saxena  * mpi3mr_pel_get_seqnum_post - Issue PEL Get Sequence number
461443ca1100SSumit Saxena  * @mrioc: Adapter instance reference
461543ca1100SSumit Saxena  * @drv_cmd: Internal command tracker
461643ca1100SSumit Saxena  *
461743ca1100SSumit Saxena  * Issue PEL get sequence number MPI request through admin queue
461843ca1100SSumit Saxena  * and return.
461943ca1100SSumit Saxena  *
462043ca1100SSumit Saxena  * Return: 0 on success, non-zero on failure.
462143ca1100SSumit Saxena  */
462243ca1100SSumit Saxena int mpi3mr_pel_get_seqnum_post(struct mpi3mr_ioc *mrioc,
462343ca1100SSumit Saxena 	struct mpi3mr_drv_cmd *drv_cmd)
462443ca1100SSumit Saxena {
462543ca1100SSumit Saxena 	struct mpi3_pel_req_action_get_sequence_numbers pel_getseq_req;
462643ca1100SSumit Saxena 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
462743ca1100SSumit Saxena 	int retval = 0;
462843ca1100SSumit Saxena 
462943ca1100SSumit Saxena 	memset(&pel_getseq_req, 0, sizeof(pel_getseq_req));
463043ca1100SSumit Saxena 	mrioc->pel_cmds.state = MPI3MR_CMD_PENDING;
463143ca1100SSumit Saxena 	mrioc->pel_cmds.is_waiting = 0;
463243ca1100SSumit Saxena 	mrioc->pel_cmds.ioc_status = 0;
463343ca1100SSumit Saxena 	mrioc->pel_cmds.ioc_loginfo = 0;
463443ca1100SSumit Saxena 	mrioc->pel_cmds.callback = mpi3mr_pel_get_seqnum_complete;
463543ca1100SSumit Saxena 	pel_getseq_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_PEL_WAIT);
463643ca1100SSumit Saxena 	pel_getseq_req.function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG;
463743ca1100SSumit Saxena 	pel_getseq_req.action = MPI3_PEL_ACTION_GET_SEQNUM;
463843ca1100SSumit Saxena 	mpi3mr_add_sg_single(&pel_getseq_req.sgl, sgl_flags,
463943ca1100SSumit Saxena 	    mrioc->pel_seqnum_sz, mrioc->pel_seqnum_dma);
464043ca1100SSumit Saxena 
464143ca1100SSumit Saxena 	retval = mpi3mr_admin_request_post(mrioc, &pel_getseq_req,
464243ca1100SSumit Saxena 			sizeof(pel_getseq_req), 0);
464343ca1100SSumit Saxena 	if (retval) {
464443ca1100SSumit Saxena 		if (drv_cmd) {
464543ca1100SSumit Saxena 			drv_cmd->state = MPI3MR_CMD_NOTUSED;
464643ca1100SSumit Saxena 			drv_cmd->callback = NULL;
464743ca1100SSumit Saxena 			drv_cmd->retry_count = 0;
464843ca1100SSumit Saxena 		}
464943ca1100SSumit Saxena 		mrioc->pel_enabled = false;
465043ca1100SSumit Saxena 	}
465143ca1100SSumit Saxena 
465243ca1100SSumit Saxena 	return retval;
465343ca1100SSumit Saxena }
465443ca1100SSumit Saxena 
465543ca1100SSumit Saxena /**
465643ca1100SSumit Saxena  * mpi3mr_pel_wait_complete - PELWait Completion callback
465743ca1100SSumit Saxena  * @mrioc: Adapter instance reference
465843ca1100SSumit Saxena  * @drv_cmd: Internal command tracker
465943ca1100SSumit Saxena  *
466043ca1100SSumit Saxena  * This is a callback handler for the PELWait request and
466143ca1100SSumit Saxena  * firmware completes a PELWait request when it is aborted or a
466243ca1100SSumit Saxena  * new PEL entry is available. This sends AEN to the application
466343ca1100SSumit Saxena  * and if the PELwait completion is not due to PELAbort then
466443ca1100SSumit Saxena  * this will send a request for new PEL Sequence number
466543ca1100SSumit Saxena  *
466643ca1100SSumit Saxena  * Return: Nothing.
466743ca1100SSumit Saxena  */
466843ca1100SSumit Saxena static void mpi3mr_pel_wait_complete(struct mpi3mr_ioc *mrioc,
466943ca1100SSumit Saxena 	struct mpi3mr_drv_cmd *drv_cmd)
467043ca1100SSumit Saxena {
467143ca1100SSumit Saxena 	struct mpi3_pel_reply *pel_reply = NULL;
467243ca1100SSumit Saxena 	u16 ioc_status, pe_log_status;
467343ca1100SSumit Saxena 	bool do_retry = false;
467443ca1100SSumit Saxena 
467543ca1100SSumit Saxena 	if (drv_cmd->state & MPI3MR_CMD_RESET)
467643ca1100SSumit Saxena 		goto cleanup_drv_cmd;
467743ca1100SSumit Saxena 
467843ca1100SSumit Saxena 	ioc_status = drv_cmd->ioc_status & MPI3_IOCSTATUS_STATUS_MASK;
467943ca1100SSumit Saxena 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
468043ca1100SSumit Saxena 		ioc_err(mrioc, "%s: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
468143ca1100SSumit Saxena 			__func__, ioc_status, drv_cmd->ioc_loginfo);
468243ca1100SSumit Saxena 		dprint_bsg_err(mrioc,
468343ca1100SSumit Saxena 		    "pel_wait: failed with ioc_status(0x%04x), log_info(0x%08x)\n",
468443ca1100SSumit Saxena 		    ioc_status, drv_cmd->ioc_loginfo);
468543ca1100SSumit Saxena 		do_retry = true;
468643ca1100SSumit Saxena 	}
468743ca1100SSumit Saxena 
468843ca1100SSumit Saxena 	if (drv_cmd->state & MPI3MR_CMD_REPLY_VALID)
468943ca1100SSumit Saxena 		pel_reply = (struct mpi3_pel_reply *)drv_cmd->reply;
469043ca1100SSumit Saxena 
469143ca1100SSumit Saxena 	if (!pel_reply) {
469243ca1100SSumit Saxena 		dprint_bsg_err(mrioc,
469343ca1100SSumit Saxena 		    "pel_wait: failed due to no reply\n");
469443ca1100SSumit Saxena 		goto out_failed;
469543ca1100SSumit Saxena 	}
469643ca1100SSumit Saxena 
469743ca1100SSumit Saxena 	pe_log_status = le16_to_cpu(pel_reply->pe_log_status);
469843ca1100SSumit Saxena 	if ((pe_log_status != MPI3_PEL_STATUS_SUCCESS) &&
469943ca1100SSumit Saxena 	    (pe_log_status != MPI3_PEL_STATUS_ABORTED)) {
470043ca1100SSumit Saxena 		ioc_err(mrioc, "%s: Failed pe_log_status(0x%04x)\n",
470143ca1100SSumit Saxena 			__func__, pe_log_status);
470243ca1100SSumit Saxena 		dprint_bsg_err(mrioc,
470343ca1100SSumit Saxena 		    "pel_wait: failed due to pel_log_status(0x%04x)\n",
470443ca1100SSumit Saxena 		    pe_log_status);
470543ca1100SSumit Saxena 		do_retry = true;
470643ca1100SSumit Saxena 	}
470743ca1100SSumit Saxena 
470843ca1100SSumit Saxena 	if (do_retry) {
470943ca1100SSumit Saxena 		if (drv_cmd->retry_count < MPI3MR_PEL_RETRY_COUNT) {
471043ca1100SSumit Saxena 			drv_cmd->retry_count++;
471143ca1100SSumit Saxena 			dprint_bsg_err(mrioc, "pel_wait: retrying(%d)\n",
471243ca1100SSumit Saxena 			    drv_cmd->retry_count);
471343ca1100SSumit Saxena 			mpi3mr_pel_wait_post(mrioc, drv_cmd);
471443ca1100SSumit Saxena 			return;
471543ca1100SSumit Saxena 		}
471643ca1100SSumit Saxena 		dprint_bsg_err(mrioc,
471743ca1100SSumit Saxena 		    "pel_wait: failed after all retries(%d)\n",
471843ca1100SSumit Saxena 		    drv_cmd->retry_count);
471943ca1100SSumit Saxena 		goto out_failed;
472043ca1100SSumit Saxena 	}
472143ca1100SSumit Saxena 	atomic64_inc(&event_counter);
472243ca1100SSumit Saxena 	if (!mrioc->pel_abort_requested) {
472343ca1100SSumit Saxena 		mrioc->pel_cmds.retry_count = 0;
472443ca1100SSumit Saxena 		mpi3mr_pel_get_seqnum_post(mrioc, &mrioc->pel_cmds);
472543ca1100SSumit Saxena 	}
472643ca1100SSumit Saxena 
472743ca1100SSumit Saxena 	return;
472843ca1100SSumit Saxena out_failed:
472943ca1100SSumit Saxena 	mrioc->pel_enabled = false;
473043ca1100SSumit Saxena cleanup_drv_cmd:
473143ca1100SSumit Saxena 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
473243ca1100SSumit Saxena 	drv_cmd->callback = NULL;
473343ca1100SSumit Saxena 	drv_cmd->retry_count = 0;
473443ca1100SSumit Saxena }
473543ca1100SSumit Saxena 
473643ca1100SSumit Saxena /**
473743ca1100SSumit Saxena  * mpi3mr_pel_get_seqnum_complete - PELGetSeqNum Completion callback
473843ca1100SSumit Saxena  * @mrioc: Adapter instance reference
473943ca1100SSumit Saxena  * @drv_cmd: Internal command tracker
474043ca1100SSumit Saxena  *
474143ca1100SSumit Saxena  * This is a callback handler for the PEL get sequence number
474243ca1100SSumit Saxena  * request and a new PEL wait request will be issued to the
474343ca1100SSumit Saxena  * firmware from this
474443ca1100SSumit Saxena  *
474543ca1100SSumit Saxena  * Return: Nothing.
474643ca1100SSumit Saxena  */
474743ca1100SSumit Saxena void mpi3mr_pel_get_seqnum_complete(struct mpi3mr_ioc *mrioc,
474843ca1100SSumit Saxena 	struct mpi3mr_drv_cmd *drv_cmd)
474943ca1100SSumit Saxena {
475043ca1100SSumit Saxena 	struct mpi3_pel_reply *pel_reply = NULL;
475143ca1100SSumit Saxena 	struct mpi3_pel_seq *pel_seqnum_virt;
475243ca1100SSumit Saxena 	u16 ioc_status;
475343ca1100SSumit Saxena 	bool do_retry = false;
475443ca1100SSumit Saxena 
475543ca1100SSumit Saxena 	pel_seqnum_virt = (struct mpi3_pel_seq *)mrioc->pel_seqnum_virt;
475643ca1100SSumit Saxena 
475743ca1100SSumit Saxena 	if (drv_cmd->state & MPI3MR_CMD_RESET)
475843ca1100SSumit Saxena 		goto cleanup_drv_cmd;
475943ca1100SSumit Saxena 
476043ca1100SSumit Saxena 	ioc_status = drv_cmd->ioc_status & MPI3_IOCSTATUS_STATUS_MASK;
476143ca1100SSumit Saxena 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
476243ca1100SSumit Saxena 		dprint_bsg_err(mrioc,
476343ca1100SSumit Saxena 		    "pel_get_seqnum: failed with ioc_status(0x%04x), log_info(0x%08x)\n",
476443ca1100SSumit Saxena 		    ioc_status, drv_cmd->ioc_loginfo);
476543ca1100SSumit Saxena 		do_retry = true;
476643ca1100SSumit Saxena 	}
476743ca1100SSumit Saxena 
476843ca1100SSumit Saxena 	if (drv_cmd->state & MPI3MR_CMD_REPLY_VALID)
476943ca1100SSumit Saxena 		pel_reply = (struct mpi3_pel_reply *)drv_cmd->reply;
477043ca1100SSumit Saxena 	if (!pel_reply) {
477143ca1100SSumit Saxena 		dprint_bsg_err(mrioc,
477243ca1100SSumit Saxena 		    "pel_get_seqnum: failed due to no reply\n");
477343ca1100SSumit Saxena 		goto out_failed;
477443ca1100SSumit Saxena 	}
477543ca1100SSumit Saxena 
477643ca1100SSumit Saxena 	if (le16_to_cpu(pel_reply->pe_log_status) != MPI3_PEL_STATUS_SUCCESS) {
477743ca1100SSumit Saxena 		dprint_bsg_err(mrioc,
477843ca1100SSumit Saxena 		    "pel_get_seqnum: failed due to pel_log_status(0x%04x)\n",
477943ca1100SSumit Saxena 		    le16_to_cpu(pel_reply->pe_log_status));
478043ca1100SSumit Saxena 		do_retry = true;
478143ca1100SSumit Saxena 	}
478243ca1100SSumit Saxena 
478343ca1100SSumit Saxena 	if (do_retry) {
478443ca1100SSumit Saxena 		if (drv_cmd->retry_count < MPI3MR_PEL_RETRY_COUNT) {
478543ca1100SSumit Saxena 			drv_cmd->retry_count++;
478643ca1100SSumit Saxena 			dprint_bsg_err(mrioc,
478743ca1100SSumit Saxena 			    "pel_get_seqnum: retrying(%d)\n",
478843ca1100SSumit Saxena 			    drv_cmd->retry_count);
478943ca1100SSumit Saxena 			mpi3mr_pel_get_seqnum_post(mrioc, drv_cmd);
479043ca1100SSumit Saxena 			return;
479143ca1100SSumit Saxena 		}
479243ca1100SSumit Saxena 
479343ca1100SSumit Saxena 		dprint_bsg_err(mrioc,
479443ca1100SSumit Saxena 		    "pel_get_seqnum: failed after all retries(%d)\n",
479543ca1100SSumit Saxena 		    drv_cmd->retry_count);
479643ca1100SSumit Saxena 		goto out_failed;
479743ca1100SSumit Saxena 	}
479843ca1100SSumit Saxena 	mrioc->pel_newest_seqnum = le32_to_cpu(pel_seqnum_virt->newest) + 1;
479943ca1100SSumit Saxena 	drv_cmd->retry_count = 0;
480043ca1100SSumit Saxena 	mpi3mr_pel_wait_post(mrioc, drv_cmd);
480143ca1100SSumit Saxena 
480243ca1100SSumit Saxena 	return;
480343ca1100SSumit Saxena out_failed:
480443ca1100SSumit Saxena 	mrioc->pel_enabled = false;
480543ca1100SSumit Saxena cleanup_drv_cmd:
480643ca1100SSumit Saxena 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
480743ca1100SSumit Saxena 	drv_cmd->callback = NULL;
480843ca1100SSumit Saxena 	drv_cmd->retry_count = 0;
4809fb9b0457SKashyap Desai }
4810fb9b0457SKashyap Desai 
4811fb9b0457SKashyap Desai /**
4812824a1566SKashyap Desai  * mpi3mr_soft_reset_handler - Reset the controller
4813824a1566SKashyap Desai  * @mrioc: Adapter instance reference
4814824a1566SKashyap Desai  * @reset_reason: Reset reason code
4815824a1566SKashyap Desai  * @snapdump: Flag to generate snapdump in firmware or not
4816824a1566SKashyap Desai  *
4817fb9b0457SKashyap Desai  * This is an handler for recovering controller by issuing soft
4818fb9b0457SKashyap Desai  * reset are diag fault reset.  This is a blocking function and
4819fb9b0457SKashyap Desai  * when one reset is executed if any other resets they will be
4820f5e6d5a3SSumit Saxena  * blocked. All BSG requests will be blocked during the reset. If
4821fb9b0457SKashyap Desai  * controller reset is successful then the controller will be
4822fb9b0457SKashyap Desai  * reinitalized, otherwise the controller will be marked as not
4823fb9b0457SKashyap Desai  * recoverable
4824fb9b0457SKashyap Desai  *
4825fb9b0457SKashyap Desai  * In snapdump bit is set, the controller is issued with diag
4826fb9b0457SKashyap Desai  * fault reset so that the firmware can create a snap dump and
4827fb9b0457SKashyap Desai  * post that the firmware will result in F000 fault and the
4828fb9b0457SKashyap Desai  * driver will issue soft reset to recover from that.
4829824a1566SKashyap Desai  *
4830824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
4831824a1566SKashyap Desai  */
4832824a1566SKashyap Desai int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
4833824a1566SKashyap Desai 	u32 reset_reason, u8 snapdump)
4834824a1566SKashyap Desai {
4835fb9b0457SKashyap Desai 	int retval = 0, i;
4836fb9b0457SKashyap Desai 	unsigned long flags;
4837fb9b0457SKashyap Desai 	u32 host_diagnostic, timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10;
4838fb9b0457SKashyap Desai 
4839b64845a7SSreekanth Reddy 	/* Block the reset handler until diag save in progress*/
4840b64845a7SSreekanth Reddy 	dprint_reset(mrioc,
4841b64845a7SSreekanth Reddy 	    "soft_reset_handler: check and block on diagsave_timeout(%d)\n",
4842b64845a7SSreekanth Reddy 	    mrioc->diagsave_timeout);
4843b64845a7SSreekanth Reddy 	while (mrioc->diagsave_timeout)
4844b64845a7SSreekanth Reddy 		ssleep(1);
4845fb9b0457SKashyap Desai 	/*
4846fb9b0457SKashyap Desai 	 * Block new resets until the currently executing one is finished and
4847fb9b0457SKashyap Desai 	 * return the status of the existing reset for all blocked resets
4848fb9b0457SKashyap Desai 	 */
4849b64845a7SSreekanth Reddy 	dprint_reset(mrioc, "soft_reset_handler: acquiring reset_mutex\n");
4850fb9b0457SKashyap Desai 	if (!mutex_trylock(&mrioc->reset_mutex)) {
4851b64845a7SSreekanth Reddy 		ioc_info(mrioc,
4852b64845a7SSreekanth Reddy 		    "controller reset triggered by %s is blocked due to another reset in progress\n",
4853b64845a7SSreekanth Reddy 		    mpi3mr_reset_rc_name(reset_reason));
4854b64845a7SSreekanth Reddy 		do {
4855b64845a7SSreekanth Reddy 			ssleep(1);
4856b64845a7SSreekanth Reddy 		} while (mrioc->reset_in_progress == 1);
4857b64845a7SSreekanth Reddy 		ioc_info(mrioc,
4858b64845a7SSreekanth Reddy 		    "returning previous reset result(%d) for the reset triggered by %s\n",
4859b64845a7SSreekanth Reddy 		    mrioc->prev_reset_result,
4860b64845a7SSreekanth Reddy 		    mpi3mr_reset_rc_name(reset_reason));
4861b64845a7SSreekanth Reddy 		return mrioc->prev_reset_result;
4862fb9b0457SKashyap Desai 	}
4863b64845a7SSreekanth Reddy 	ioc_info(mrioc, "controller reset is triggered by %s\n",
4864b64845a7SSreekanth Reddy 	    mpi3mr_reset_rc_name(reset_reason));
4865b64845a7SSreekanth Reddy 
48662745ce0eSSreekanth Reddy 	mrioc->device_refresh_on = 0;
4867fb9b0457SKashyap Desai 	mrioc->reset_in_progress = 1;
4868f5e6d5a3SSumit Saxena 	mrioc->stop_bsgs = 1;
4869b64845a7SSreekanth Reddy 	mrioc->prev_reset_result = -1;
4870fb9b0457SKashyap Desai 
4871fb9b0457SKashyap Desai 	if ((!snapdump) && (reset_reason != MPI3MR_RESET_FROM_FAULT_WATCH) &&
4872b64845a7SSreekanth Reddy 	    (reset_reason != MPI3MR_RESET_FROM_FIRMWARE) &&
4873fb9b0457SKashyap Desai 	    (reset_reason != MPI3MR_RESET_FROM_CIACTIV_FAULT)) {
4874fb9b0457SKashyap Desai 		for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
4875fb9b0457SKashyap Desai 			mrioc->event_masks[i] = -1;
4876fb9b0457SKashyap Desai 
4877b64845a7SSreekanth Reddy 		dprint_reset(mrioc, "soft_reset_handler: masking events\n");
4878b64845a7SSreekanth Reddy 		mpi3mr_issue_event_notification(mrioc);
4879fb9b0457SKashyap Desai 	}
4880fb9b0457SKashyap Desai 
488144dc724fSKashyap Desai 	mpi3mr_wait_for_host_io(mrioc, MPI3MR_RESET_HOST_IOWAIT_TIMEOUT);
488244dc724fSKashyap Desai 
4883fb9b0457SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
4884fb9b0457SKashyap Desai 
4885fb9b0457SKashyap Desai 	if (snapdump) {
4886fb9b0457SKashyap Desai 		mpi3mr_set_diagsave(mrioc);
4887fb9b0457SKashyap Desai 		retval = mpi3mr_issue_reset(mrioc,
4888fb9b0457SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
4889fb9b0457SKashyap Desai 		if (!retval) {
4890fb9b0457SKashyap Desai 			do {
4891fb9b0457SKashyap Desai 				host_diagnostic =
4892fb9b0457SKashyap Desai 				    readl(&mrioc->sysif_regs->host_diagnostic);
4893fb9b0457SKashyap Desai 				if (!(host_diagnostic &
4894fb9b0457SKashyap Desai 				    MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS))
4895fb9b0457SKashyap Desai 					break;
4896fb9b0457SKashyap Desai 				msleep(100);
4897fb9b0457SKashyap Desai 			} while (--timeout);
4898fb9b0457SKashyap Desai 		}
4899fb9b0457SKashyap Desai 	}
4900fb9b0457SKashyap Desai 
4901fb9b0457SKashyap Desai 	retval = mpi3mr_issue_reset(mrioc,
4902fb9b0457SKashyap Desai 	    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, reset_reason);
4903fb9b0457SKashyap Desai 	if (retval) {
4904fb9b0457SKashyap Desai 		ioc_err(mrioc, "Failed to issue soft reset to the ioc\n");
4905fb9b0457SKashyap Desai 		goto out;
4906fb9b0457SKashyap Desai 	}
4907f10af057SSreekanth Reddy 	if (mrioc->num_io_throttle_group !=
4908f10af057SSreekanth Reddy 	    mrioc->facts.max_io_throttle_group) {
4909f10af057SSreekanth Reddy 		ioc_err(mrioc,
4910f10af057SSreekanth Reddy 		    "max io throttle group doesn't match old(%d), new(%d)\n",
4911f10af057SSreekanth Reddy 		    mrioc->num_io_throttle_group,
4912f10af057SSreekanth Reddy 		    mrioc->facts.max_io_throttle_group);
49132a8a0147SDan Carpenter 		retval = -EPERM;
49142a8a0147SDan Carpenter 		goto out;
4915f10af057SSreekanth Reddy 	}
4916fb9b0457SKashyap Desai 
4917c1af985dSSreekanth Reddy 	mpi3mr_flush_delayed_cmd_lists(mrioc);
4918fb9b0457SKashyap Desai 	mpi3mr_flush_drv_cmds(mrioc);
4919339e6156SShin'ichiro Kawasaki 	bitmap_clear(mrioc->devrem_bitmap, 0, MPI3MR_NUM_DEVRMCMD);
4920339e6156SShin'ichiro Kawasaki 	bitmap_clear(mrioc->removepend_bitmap, 0,
4921339e6156SShin'ichiro Kawasaki 		     mrioc->dev_handle_bitmap_bits);
4922339e6156SShin'ichiro Kawasaki 	bitmap_clear(mrioc->evtack_cmds_bitmap, 0, MPI3MR_NUM_EVTACKCMD);
4923fb9b0457SKashyap Desai 	mpi3mr_flush_host_io(mrioc);
4924580e6742SSreekanth Reddy 	mpi3mr_cleanup_fwevt_list(mrioc);
4925fb9b0457SKashyap Desai 	mpi3mr_invalidate_devhandles(mrioc);
4926130fc180SSreekanth Reddy 	mpi3mr_free_enclosure_list(mrioc);
4927130fc180SSreekanth Reddy 
492878b76a07SSreekanth Reddy 	if (mrioc->prepare_for_reset) {
492978b76a07SSreekanth Reddy 		mrioc->prepare_for_reset = 0;
493078b76a07SSreekanth Reddy 		mrioc->prepare_for_reset_timeout_counter = 0;
493178b76a07SSreekanth Reddy 	}
4932fb9b0457SKashyap Desai 	mpi3mr_memset_buffers(mrioc);
4933fe6db615SSreekanth Reddy 	retval = mpi3mr_reinit_ioc(mrioc, 0);
4934fb9b0457SKashyap Desai 	if (retval) {
4935fb9b0457SKashyap Desai 		pr_err(IOCNAME "reinit after soft reset failed: reason %d\n",
4936fb9b0457SKashyap Desai 		    mrioc->name, reset_reason);
4937fb9b0457SKashyap Desai 		goto out;
4938fb9b0457SKashyap Desai 	}
4939f84e8b5bSSreekanth Reddy 	ssleep(MPI3MR_RESET_TOPOLOGY_SETTLE_TIME);
4940fb9b0457SKashyap Desai 
4941fb9b0457SKashyap Desai out:
4942fb9b0457SKashyap Desai 	if (!retval) {
4943b64845a7SSreekanth Reddy 		mrioc->diagsave_timeout = 0;
4944fb9b0457SKashyap Desai 		mrioc->reset_in_progress = 0;
494543ca1100SSumit Saxena 		mrioc->pel_abort_requested = 0;
494643ca1100SSumit Saxena 		if (mrioc->pel_enabled) {
494743ca1100SSumit Saxena 			mrioc->pel_cmds.retry_count = 0;
494843ca1100SSumit Saxena 			mpi3mr_pel_wait_post(mrioc, &mrioc->pel_cmds);
494943ca1100SSumit Saxena 		}
495043ca1100SSumit Saxena 
49512745ce0eSSreekanth Reddy 		mrioc->device_refresh_on = 0;
49522745ce0eSSreekanth Reddy 
495354dfcffbSKashyap Desai 		mrioc->ts_update_counter = 0;
4954fb9b0457SKashyap Desai 		spin_lock_irqsave(&mrioc->watchdog_lock, flags);
4955fb9b0457SKashyap Desai 		if (mrioc->watchdog_work_q)
4956fb9b0457SKashyap Desai 			queue_delayed_work(mrioc->watchdog_work_q,
4957fb9b0457SKashyap Desai 			    &mrioc->watchdog_work,
4958fb9b0457SKashyap Desai 			    msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL));
4959fb9b0457SKashyap Desai 		spin_unlock_irqrestore(&mrioc->watchdog_lock, flags);
4960f5e6d5a3SSumit Saxena 		mrioc->stop_bsgs = 0;
496143ca1100SSumit Saxena 		if (mrioc->pel_enabled)
496243ca1100SSumit Saxena 			atomic64_inc(&event_counter);
4963fb9b0457SKashyap Desai 	} else {
4964fb9b0457SKashyap Desai 		mpi3mr_issue_reset(mrioc,
4965fb9b0457SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
49662745ce0eSSreekanth Reddy 		mrioc->device_refresh_on = 0;
4967fb9b0457SKashyap Desai 		mrioc->unrecoverable = 1;
4968fb9b0457SKashyap Desai 		mrioc->reset_in_progress = 0;
4969fb9b0457SKashyap Desai 		retval = -1;
4970f2a79d20SSreekanth Reddy 		mpi3mr_flush_cmds_for_unrecovered_controller(mrioc);
4971fb9b0457SKashyap Desai 	}
4972b64845a7SSreekanth Reddy 	mrioc->prev_reset_result = retval;
4973fb9b0457SKashyap Desai 	mutex_unlock(&mrioc->reset_mutex);
4974b64845a7SSreekanth Reddy 	ioc_info(mrioc, "controller reset is %s\n",
4975b64845a7SSreekanth Reddy 	    ((retval == 0) ? "successful" : "failed"));
4976fb9b0457SKashyap Desai 	return retval;
4977824a1566SKashyap Desai }
497832d457d5SSreekanth Reddy 
497932d457d5SSreekanth Reddy 
498032d457d5SSreekanth Reddy /**
498132d457d5SSreekanth Reddy  * mpi3mr_free_config_dma_memory - free memory for config page
498232d457d5SSreekanth Reddy  * @mrioc: Adapter instance reference
498332d457d5SSreekanth Reddy  * @mem_desc: memory descriptor structure
498432d457d5SSreekanth Reddy  *
498532d457d5SSreekanth Reddy  * Check whether the size of the buffer specified by the memory
498632d457d5SSreekanth Reddy  * descriptor is greater than the default page size if so then
498732d457d5SSreekanth Reddy  * free the memory pointed by the descriptor.
498832d457d5SSreekanth Reddy  *
498932d457d5SSreekanth Reddy  * Return: Nothing.
499032d457d5SSreekanth Reddy  */
499132d457d5SSreekanth Reddy static void mpi3mr_free_config_dma_memory(struct mpi3mr_ioc *mrioc,
499232d457d5SSreekanth Reddy 	struct dma_memory_desc *mem_desc)
499332d457d5SSreekanth Reddy {
499432d457d5SSreekanth Reddy 	if ((mem_desc->size > mrioc->cfg_page_sz) && mem_desc->addr) {
499532d457d5SSreekanth Reddy 		dma_free_coherent(&mrioc->pdev->dev, mem_desc->size,
499632d457d5SSreekanth Reddy 		    mem_desc->addr, mem_desc->dma_addr);
499732d457d5SSreekanth Reddy 		mem_desc->addr = NULL;
499832d457d5SSreekanth Reddy 	}
499932d457d5SSreekanth Reddy }
500032d457d5SSreekanth Reddy 
500132d457d5SSreekanth Reddy /**
500232d457d5SSreekanth Reddy  * mpi3mr_alloc_config_dma_memory - Alloc memory for config page
500332d457d5SSreekanth Reddy  * @mrioc: Adapter instance reference
500432d457d5SSreekanth Reddy  * @mem_desc: Memory descriptor to hold dma memory info
500532d457d5SSreekanth Reddy  *
500632d457d5SSreekanth Reddy  * This function allocates new dmaable memory or provides the
500732d457d5SSreekanth Reddy  * default config page dmaable memory based on the memory size
500832d457d5SSreekanth Reddy  * described by the descriptor.
500932d457d5SSreekanth Reddy  *
501032d457d5SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
501132d457d5SSreekanth Reddy  */
501232d457d5SSreekanth Reddy static int mpi3mr_alloc_config_dma_memory(struct mpi3mr_ioc *mrioc,
501332d457d5SSreekanth Reddy 	struct dma_memory_desc *mem_desc)
501432d457d5SSreekanth Reddy {
501532d457d5SSreekanth Reddy 	if (mem_desc->size > mrioc->cfg_page_sz) {
501632d457d5SSreekanth Reddy 		mem_desc->addr = dma_alloc_coherent(&mrioc->pdev->dev,
501732d457d5SSreekanth Reddy 		    mem_desc->size, &mem_desc->dma_addr, GFP_KERNEL);
501832d457d5SSreekanth Reddy 		if (!mem_desc->addr)
501932d457d5SSreekanth Reddy 			return -ENOMEM;
502032d457d5SSreekanth Reddy 	} else {
502132d457d5SSreekanth Reddy 		mem_desc->addr = mrioc->cfg_page;
502232d457d5SSreekanth Reddy 		mem_desc->dma_addr = mrioc->cfg_page_dma;
502332d457d5SSreekanth Reddy 		memset(mem_desc->addr, 0, mrioc->cfg_page_sz);
502432d457d5SSreekanth Reddy 	}
502532d457d5SSreekanth Reddy 	return 0;
502632d457d5SSreekanth Reddy }
502732d457d5SSreekanth Reddy 
502832d457d5SSreekanth Reddy /**
502932d457d5SSreekanth Reddy  * mpi3mr_post_cfg_req - Issue config requests and wait
503032d457d5SSreekanth Reddy  * @mrioc: Adapter instance reference
503132d457d5SSreekanth Reddy  * @cfg_req: Configuration request
503232d457d5SSreekanth Reddy  * @timeout: Timeout in seconds
503332d457d5SSreekanth Reddy  * @ioc_status: Pointer to return ioc status
503432d457d5SSreekanth Reddy  *
503532d457d5SSreekanth Reddy  * A generic function for posting MPI3 configuration request to
503632d457d5SSreekanth Reddy  * the firmware. This blocks for the completion of request for
503732d457d5SSreekanth Reddy  * timeout seconds and if the request times out this function
503832d457d5SSreekanth Reddy  * faults the controller with proper reason code.
503932d457d5SSreekanth Reddy  *
504032d457d5SSreekanth Reddy  * On successful completion of the request this function returns
504132d457d5SSreekanth Reddy  * appropriate ioc status from the firmware back to the caller.
504232d457d5SSreekanth Reddy  *
504332d457d5SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
504432d457d5SSreekanth Reddy  */
504532d457d5SSreekanth Reddy static int mpi3mr_post_cfg_req(struct mpi3mr_ioc *mrioc,
504632d457d5SSreekanth Reddy 	struct mpi3_config_request *cfg_req, int timeout, u16 *ioc_status)
504732d457d5SSreekanth Reddy {
504832d457d5SSreekanth Reddy 	int retval = 0;
504932d457d5SSreekanth Reddy 
505032d457d5SSreekanth Reddy 	mutex_lock(&mrioc->cfg_cmds.mutex);
505132d457d5SSreekanth Reddy 	if (mrioc->cfg_cmds.state & MPI3MR_CMD_PENDING) {
505232d457d5SSreekanth Reddy 		retval = -1;
505332d457d5SSreekanth Reddy 		ioc_err(mrioc, "sending config request failed due to command in use\n");
505432d457d5SSreekanth Reddy 		mutex_unlock(&mrioc->cfg_cmds.mutex);
505532d457d5SSreekanth Reddy 		goto out;
505632d457d5SSreekanth Reddy 	}
505732d457d5SSreekanth Reddy 	mrioc->cfg_cmds.state = MPI3MR_CMD_PENDING;
505832d457d5SSreekanth Reddy 	mrioc->cfg_cmds.is_waiting = 1;
505932d457d5SSreekanth Reddy 	mrioc->cfg_cmds.callback = NULL;
506032d457d5SSreekanth Reddy 	mrioc->cfg_cmds.ioc_status = 0;
506132d457d5SSreekanth Reddy 	mrioc->cfg_cmds.ioc_loginfo = 0;
506232d457d5SSreekanth Reddy 
506332d457d5SSreekanth Reddy 	cfg_req->host_tag = cpu_to_le16(MPI3MR_HOSTTAG_CFG_CMDS);
506432d457d5SSreekanth Reddy 	cfg_req->function = MPI3_FUNCTION_CONFIG;
506532d457d5SSreekanth Reddy 
506632d457d5SSreekanth Reddy 	init_completion(&mrioc->cfg_cmds.done);
506732d457d5SSreekanth Reddy 	dprint_cfg_info(mrioc, "posting config request\n");
506832d457d5SSreekanth Reddy 	if (mrioc->logging_level & MPI3_DEBUG_CFG_INFO)
506932d457d5SSreekanth Reddy 		dprint_dump(cfg_req, sizeof(struct mpi3_config_request),
507032d457d5SSreekanth Reddy 		    "mpi3_cfg_req");
507132d457d5SSreekanth Reddy 	retval = mpi3mr_admin_request_post(mrioc, cfg_req, sizeof(*cfg_req), 1);
507232d457d5SSreekanth Reddy 	if (retval) {
507332d457d5SSreekanth Reddy 		ioc_err(mrioc, "posting config request failed\n");
507432d457d5SSreekanth Reddy 		goto out_unlock;
507532d457d5SSreekanth Reddy 	}
507632d457d5SSreekanth Reddy 	wait_for_completion_timeout(&mrioc->cfg_cmds.done, (timeout * HZ));
507732d457d5SSreekanth Reddy 	if (!(mrioc->cfg_cmds.state & MPI3MR_CMD_COMPLETE)) {
507832d457d5SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
507932d457d5SSreekanth Reddy 		    MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT);
508032d457d5SSreekanth Reddy 		ioc_err(mrioc, "config request timed out\n");
508132d457d5SSreekanth Reddy 		retval = -1;
508232d457d5SSreekanth Reddy 		goto out_unlock;
508332d457d5SSreekanth Reddy 	}
508432d457d5SSreekanth Reddy 	*ioc_status = mrioc->cfg_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK;
508532d457d5SSreekanth Reddy 	if ((*ioc_status) != MPI3_IOCSTATUS_SUCCESS)
508632d457d5SSreekanth Reddy 		dprint_cfg_err(mrioc,
508732d457d5SSreekanth Reddy 		    "cfg_page request returned with ioc_status(0x%04x), log_info(0x%08x)\n",
508832d457d5SSreekanth Reddy 		    *ioc_status, mrioc->cfg_cmds.ioc_loginfo);
508932d457d5SSreekanth Reddy 
509032d457d5SSreekanth Reddy out_unlock:
509132d457d5SSreekanth Reddy 	mrioc->cfg_cmds.state = MPI3MR_CMD_NOTUSED;
509232d457d5SSreekanth Reddy 	mutex_unlock(&mrioc->cfg_cmds.mutex);
509332d457d5SSreekanth Reddy 
509432d457d5SSreekanth Reddy out:
509532d457d5SSreekanth Reddy 	return retval;
509632d457d5SSreekanth Reddy }
509732d457d5SSreekanth Reddy 
509832d457d5SSreekanth Reddy /**
509932d457d5SSreekanth Reddy  * mpi3mr_process_cfg_req - config page request processor
510032d457d5SSreekanth Reddy  * @mrioc: Adapter instance reference
510132d457d5SSreekanth Reddy  * @cfg_req: Configuration request
510232d457d5SSreekanth Reddy  * @cfg_hdr: Configuration page header
510332d457d5SSreekanth Reddy  * @timeout: Timeout in seconds
510432d457d5SSreekanth Reddy  * @ioc_status: Pointer to return ioc status
510532d457d5SSreekanth Reddy  * @cfg_buf: Memory pointer to copy config page or header
510632d457d5SSreekanth Reddy  * @cfg_buf_sz: Size of the memory to get config page or header
510732d457d5SSreekanth Reddy  *
510832d457d5SSreekanth Reddy  * This is handler for config page read, write and config page
510932d457d5SSreekanth Reddy  * header read operations.
511032d457d5SSreekanth Reddy  *
511132d457d5SSreekanth Reddy  * This function expects the cfg_req to be populated with page
511232d457d5SSreekanth Reddy  * type, page number, action for the header read and with page
511332d457d5SSreekanth Reddy  * address for all other operations.
511432d457d5SSreekanth Reddy  *
511532d457d5SSreekanth Reddy  * The cfg_hdr can be passed as null for reading required header
511632d457d5SSreekanth Reddy  * details for read/write pages the cfg_hdr should point valid
511732d457d5SSreekanth Reddy  * configuration page header.
511832d457d5SSreekanth Reddy  *
511932d457d5SSreekanth Reddy  * This allocates dmaable memory based on the size of the config
512032d457d5SSreekanth Reddy  * buffer and set the SGE of the cfg_req.
512132d457d5SSreekanth Reddy  *
512232d457d5SSreekanth Reddy  * For write actions, the config page data has to be passed in
512332d457d5SSreekanth Reddy  * the cfg_buf and size of the data has to be mentioned in the
512432d457d5SSreekanth Reddy  * cfg_buf_sz.
512532d457d5SSreekanth Reddy  *
512632d457d5SSreekanth Reddy  * For read/header actions, on successful completion of the
512732d457d5SSreekanth Reddy  * request with successful ioc_status the data will be copied
512832d457d5SSreekanth Reddy  * into the cfg_buf limited to a minimum of actual page size and
512932d457d5SSreekanth Reddy  * cfg_buf_sz
513032d457d5SSreekanth Reddy  *
513132d457d5SSreekanth Reddy  *
513232d457d5SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
513332d457d5SSreekanth Reddy  */
513432d457d5SSreekanth Reddy static int mpi3mr_process_cfg_req(struct mpi3mr_ioc *mrioc,
513532d457d5SSreekanth Reddy 	struct mpi3_config_request *cfg_req,
513632d457d5SSreekanth Reddy 	struct mpi3_config_page_header *cfg_hdr, int timeout, u16 *ioc_status,
513732d457d5SSreekanth Reddy 	void *cfg_buf, u32 cfg_buf_sz)
513832d457d5SSreekanth Reddy {
513932d457d5SSreekanth Reddy 	struct dma_memory_desc mem_desc;
514032d457d5SSreekanth Reddy 	int retval = -1;
514132d457d5SSreekanth Reddy 	u8 invalid_action = 0;
514232d457d5SSreekanth Reddy 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
514332d457d5SSreekanth Reddy 
514432d457d5SSreekanth Reddy 	memset(&mem_desc, 0, sizeof(struct dma_memory_desc));
514532d457d5SSreekanth Reddy 
514632d457d5SSreekanth Reddy 	if (cfg_req->action == MPI3_CONFIG_ACTION_PAGE_HEADER)
514732d457d5SSreekanth Reddy 		mem_desc.size = sizeof(struct mpi3_config_page_header);
514832d457d5SSreekanth Reddy 	else {
514932d457d5SSreekanth Reddy 		if (!cfg_hdr) {
515032d457d5SSreekanth Reddy 			ioc_err(mrioc, "null config header passed for config action(%d), page_type(0x%02x), page_num(%d)\n",
515132d457d5SSreekanth Reddy 			    cfg_req->action, cfg_req->page_type,
515232d457d5SSreekanth Reddy 			    cfg_req->page_number);
515332d457d5SSreekanth Reddy 			goto out;
515432d457d5SSreekanth Reddy 		}
515532d457d5SSreekanth Reddy 		switch (cfg_hdr->page_attribute & MPI3_CONFIG_PAGEATTR_MASK) {
515632d457d5SSreekanth Reddy 		case MPI3_CONFIG_PAGEATTR_READ_ONLY:
515732d457d5SSreekanth Reddy 			if (cfg_req->action
515832d457d5SSreekanth Reddy 			    != MPI3_CONFIG_ACTION_READ_CURRENT)
515932d457d5SSreekanth Reddy 				invalid_action = 1;
516032d457d5SSreekanth Reddy 			break;
516132d457d5SSreekanth Reddy 		case MPI3_CONFIG_PAGEATTR_CHANGEABLE:
516232d457d5SSreekanth Reddy 			if ((cfg_req->action ==
516332d457d5SSreekanth Reddy 			     MPI3_CONFIG_ACTION_READ_PERSISTENT) ||
516432d457d5SSreekanth Reddy 			    (cfg_req->action ==
516532d457d5SSreekanth Reddy 			     MPI3_CONFIG_ACTION_WRITE_PERSISTENT))
516632d457d5SSreekanth Reddy 				invalid_action = 1;
516732d457d5SSreekanth Reddy 			break;
516832d457d5SSreekanth Reddy 		case MPI3_CONFIG_PAGEATTR_PERSISTENT:
516932d457d5SSreekanth Reddy 		default:
517032d457d5SSreekanth Reddy 			break;
517132d457d5SSreekanth Reddy 		}
517232d457d5SSreekanth Reddy 		if (invalid_action) {
517332d457d5SSreekanth Reddy 			ioc_err(mrioc,
517432d457d5SSreekanth Reddy 			    "config action(%d) is not allowed for page_type(0x%02x), page_num(%d) with page_attribute(0x%02x)\n",
517532d457d5SSreekanth Reddy 			    cfg_req->action, cfg_req->page_type,
517632d457d5SSreekanth Reddy 			    cfg_req->page_number, cfg_hdr->page_attribute);
517732d457d5SSreekanth Reddy 			goto out;
517832d457d5SSreekanth Reddy 		}
517932d457d5SSreekanth Reddy 		mem_desc.size = le16_to_cpu(cfg_hdr->page_length) * 4;
518032d457d5SSreekanth Reddy 		cfg_req->page_length = cfg_hdr->page_length;
518132d457d5SSreekanth Reddy 		cfg_req->page_version = cfg_hdr->page_version;
518232d457d5SSreekanth Reddy 	}
518332d457d5SSreekanth Reddy 	if (mpi3mr_alloc_config_dma_memory(mrioc, &mem_desc))
518432d457d5SSreekanth Reddy 		goto out;
518532d457d5SSreekanth Reddy 
518632d457d5SSreekanth Reddy 	mpi3mr_add_sg_single(&cfg_req->sgl, sgl_flags, mem_desc.size,
518732d457d5SSreekanth Reddy 	    mem_desc.dma_addr);
518832d457d5SSreekanth Reddy 
518932d457d5SSreekanth Reddy 	if ((cfg_req->action == MPI3_CONFIG_ACTION_WRITE_PERSISTENT) ||
519032d457d5SSreekanth Reddy 	    (cfg_req->action == MPI3_CONFIG_ACTION_WRITE_CURRENT)) {
519132d457d5SSreekanth Reddy 		memcpy(mem_desc.addr, cfg_buf, min_t(u16, mem_desc.size,
519232d457d5SSreekanth Reddy 		    cfg_buf_sz));
519332d457d5SSreekanth Reddy 		dprint_cfg_info(mrioc, "config buffer to be written\n");
519432d457d5SSreekanth Reddy 		if (mrioc->logging_level & MPI3_DEBUG_CFG_INFO)
519532d457d5SSreekanth Reddy 			dprint_dump(mem_desc.addr, mem_desc.size, "cfg_buf");
519632d457d5SSreekanth Reddy 	}
519732d457d5SSreekanth Reddy 
519832d457d5SSreekanth Reddy 	if (mpi3mr_post_cfg_req(mrioc, cfg_req, timeout, ioc_status))
519932d457d5SSreekanth Reddy 		goto out;
520032d457d5SSreekanth Reddy 
520132d457d5SSreekanth Reddy 	retval = 0;
520232d457d5SSreekanth Reddy 	if ((*ioc_status == MPI3_IOCSTATUS_SUCCESS) &&
520332d457d5SSreekanth Reddy 	    (cfg_req->action != MPI3_CONFIG_ACTION_WRITE_PERSISTENT) &&
520432d457d5SSreekanth Reddy 	    (cfg_req->action != MPI3_CONFIG_ACTION_WRITE_CURRENT)) {
520532d457d5SSreekanth Reddy 		memcpy(cfg_buf, mem_desc.addr, min_t(u16, mem_desc.size,
520632d457d5SSreekanth Reddy 		    cfg_buf_sz));
520732d457d5SSreekanth Reddy 		dprint_cfg_info(mrioc, "config buffer read\n");
520832d457d5SSreekanth Reddy 		if (mrioc->logging_level & MPI3_DEBUG_CFG_INFO)
520932d457d5SSreekanth Reddy 			dprint_dump(mem_desc.addr, mem_desc.size, "cfg_buf");
521032d457d5SSreekanth Reddy 	}
521132d457d5SSreekanth Reddy 
521232d457d5SSreekanth Reddy out:
521332d457d5SSreekanth Reddy 	mpi3mr_free_config_dma_memory(mrioc, &mem_desc);
521432d457d5SSreekanth Reddy 	return retval;
521532d457d5SSreekanth Reddy }
521664a8d931SSreekanth Reddy 
521764a8d931SSreekanth Reddy /**
521864a8d931SSreekanth Reddy  * mpi3mr_cfg_get_dev_pg0 - Read current device page0
521964a8d931SSreekanth Reddy  * @mrioc: Adapter instance reference
522064a8d931SSreekanth Reddy  * @ioc_status: Pointer to return ioc status
522164a8d931SSreekanth Reddy  * @dev_pg0: Pointer to return device page 0
522264a8d931SSreekanth Reddy  * @pg_sz: Size of the memory allocated to the page pointer
522364a8d931SSreekanth Reddy  * @form: The form to be used for addressing the page
522464a8d931SSreekanth Reddy  * @form_spec: Form specific information like device handle
522564a8d931SSreekanth Reddy  *
522664a8d931SSreekanth Reddy  * This is handler for config page read for a specific device
522764a8d931SSreekanth Reddy  * page0. The ioc_status has the controller returned ioc_status.
522864a8d931SSreekanth Reddy  * This routine doesn't check ioc_status to decide whether the
522964a8d931SSreekanth Reddy  * page read is success or not and it is the callers
523064a8d931SSreekanth Reddy  * responsibility.
523164a8d931SSreekanth Reddy  *
523264a8d931SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
523364a8d931SSreekanth Reddy  */
523464a8d931SSreekanth Reddy int mpi3mr_cfg_get_dev_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
523564a8d931SSreekanth Reddy 	struct mpi3_device_page0 *dev_pg0, u16 pg_sz, u32 form, u32 form_spec)
523664a8d931SSreekanth Reddy {
523764a8d931SSreekanth Reddy 	struct mpi3_config_page_header cfg_hdr;
523864a8d931SSreekanth Reddy 	struct mpi3_config_request cfg_req;
523964a8d931SSreekanth Reddy 	u32 page_address;
524064a8d931SSreekanth Reddy 
524164a8d931SSreekanth Reddy 	memset(dev_pg0, 0, pg_sz);
524264a8d931SSreekanth Reddy 	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
524364a8d931SSreekanth Reddy 	memset(&cfg_req, 0, sizeof(cfg_req));
524464a8d931SSreekanth Reddy 
524564a8d931SSreekanth Reddy 	cfg_req.function = MPI3_FUNCTION_CONFIG;
524664a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
524764a8d931SSreekanth Reddy 	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_DEVICE;
524864a8d931SSreekanth Reddy 	cfg_req.page_number = 0;
524964a8d931SSreekanth Reddy 	cfg_req.page_address = 0;
525064a8d931SSreekanth Reddy 
525164a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
525264a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
525364a8d931SSreekanth Reddy 		ioc_err(mrioc, "device page0 header read failed\n");
525464a8d931SSreekanth Reddy 		goto out_failed;
525564a8d931SSreekanth Reddy 	}
525664a8d931SSreekanth Reddy 	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
525764a8d931SSreekanth Reddy 		ioc_err(mrioc, "device page0 header read failed with ioc_status(0x%04x)\n",
525864a8d931SSreekanth Reddy 		    *ioc_status);
525964a8d931SSreekanth Reddy 		goto out_failed;
526064a8d931SSreekanth Reddy 	}
526164a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
526264a8d931SSreekanth Reddy 	page_address = ((form & MPI3_DEVICE_PGAD_FORM_MASK) |
526364a8d931SSreekanth Reddy 	    (form_spec & MPI3_DEVICE_PGAD_HANDLE_MASK));
526464a8d931SSreekanth Reddy 	cfg_req.page_address = cpu_to_le32(page_address);
526564a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
526664a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, dev_pg0, pg_sz)) {
526764a8d931SSreekanth Reddy 		ioc_err(mrioc, "device page0 read failed\n");
526864a8d931SSreekanth Reddy 		goto out_failed;
526964a8d931SSreekanth Reddy 	}
527064a8d931SSreekanth Reddy 	return 0;
527164a8d931SSreekanth Reddy out_failed:
527264a8d931SSreekanth Reddy 	return -1;
527364a8d931SSreekanth Reddy }
527464a8d931SSreekanth Reddy 
527564a8d931SSreekanth Reddy 
527664a8d931SSreekanth Reddy /**
527764a8d931SSreekanth Reddy  * mpi3mr_cfg_get_sas_phy_pg0 - Read current SAS Phy page0
527864a8d931SSreekanth Reddy  * @mrioc: Adapter instance reference
527964a8d931SSreekanth Reddy  * @ioc_status: Pointer to return ioc status
528064a8d931SSreekanth Reddy  * @phy_pg0: Pointer to return SAS Phy page 0
528164a8d931SSreekanth Reddy  * @pg_sz: Size of the memory allocated to the page pointer
528264a8d931SSreekanth Reddy  * @form: The form to be used for addressing the page
528364a8d931SSreekanth Reddy  * @form_spec: Form specific information like phy number
528464a8d931SSreekanth Reddy  *
528564a8d931SSreekanth Reddy  * This is handler for config page read for a specific SAS Phy
528664a8d931SSreekanth Reddy  * page0. The ioc_status has the controller returned ioc_status.
528764a8d931SSreekanth Reddy  * This routine doesn't check ioc_status to decide whether the
528864a8d931SSreekanth Reddy  * page read is success or not and it is the callers
528964a8d931SSreekanth Reddy  * responsibility.
529064a8d931SSreekanth Reddy  *
529164a8d931SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
529264a8d931SSreekanth Reddy  */
529364a8d931SSreekanth Reddy int mpi3mr_cfg_get_sas_phy_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
529464a8d931SSreekanth Reddy 	struct mpi3_sas_phy_page0 *phy_pg0, u16 pg_sz, u32 form,
529564a8d931SSreekanth Reddy 	u32 form_spec)
529664a8d931SSreekanth Reddy {
529764a8d931SSreekanth Reddy 	struct mpi3_config_page_header cfg_hdr;
529864a8d931SSreekanth Reddy 	struct mpi3_config_request cfg_req;
529964a8d931SSreekanth Reddy 	u32 page_address;
530064a8d931SSreekanth Reddy 
530164a8d931SSreekanth Reddy 	memset(phy_pg0, 0, pg_sz);
530264a8d931SSreekanth Reddy 	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
530364a8d931SSreekanth Reddy 	memset(&cfg_req, 0, sizeof(cfg_req));
530464a8d931SSreekanth Reddy 
530564a8d931SSreekanth Reddy 	cfg_req.function = MPI3_FUNCTION_CONFIG;
530664a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
530764a8d931SSreekanth Reddy 	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_PHY;
530864a8d931SSreekanth Reddy 	cfg_req.page_number = 0;
530964a8d931SSreekanth Reddy 	cfg_req.page_address = 0;
531064a8d931SSreekanth Reddy 
531164a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
531264a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
531364a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas phy page0 header read failed\n");
531464a8d931SSreekanth Reddy 		goto out_failed;
531564a8d931SSreekanth Reddy 	}
531664a8d931SSreekanth Reddy 	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
531764a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas phy page0 header read failed with ioc_status(0x%04x)\n",
531864a8d931SSreekanth Reddy 		    *ioc_status);
531964a8d931SSreekanth Reddy 		goto out_failed;
532064a8d931SSreekanth Reddy 	}
532164a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
532264a8d931SSreekanth Reddy 	page_address = ((form & MPI3_SAS_PHY_PGAD_FORM_MASK) |
532364a8d931SSreekanth Reddy 	    (form_spec & MPI3_SAS_PHY_PGAD_PHY_NUMBER_MASK));
532464a8d931SSreekanth Reddy 	cfg_req.page_address = cpu_to_le32(page_address);
532564a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
532664a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, phy_pg0, pg_sz)) {
532764a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas phy page0 read failed\n");
532864a8d931SSreekanth Reddy 		goto out_failed;
532964a8d931SSreekanth Reddy 	}
533064a8d931SSreekanth Reddy 	return 0;
533164a8d931SSreekanth Reddy out_failed:
533264a8d931SSreekanth Reddy 	return -1;
533364a8d931SSreekanth Reddy }
533464a8d931SSreekanth Reddy 
533564a8d931SSreekanth Reddy /**
533664a8d931SSreekanth Reddy  * mpi3mr_cfg_get_sas_phy_pg1 - Read current SAS Phy page1
533764a8d931SSreekanth Reddy  * @mrioc: Adapter instance reference
533864a8d931SSreekanth Reddy  * @ioc_status: Pointer to return ioc status
533964a8d931SSreekanth Reddy  * @phy_pg1: Pointer to return SAS Phy page 1
534064a8d931SSreekanth Reddy  * @pg_sz: Size of the memory allocated to the page pointer
534164a8d931SSreekanth Reddy  * @form: The form to be used for addressing the page
534264a8d931SSreekanth Reddy  * @form_spec: Form specific information like phy number
534364a8d931SSreekanth Reddy  *
534464a8d931SSreekanth Reddy  * This is handler for config page read for a specific SAS Phy
534564a8d931SSreekanth Reddy  * page1. The ioc_status has the controller returned ioc_status.
534664a8d931SSreekanth Reddy  * This routine doesn't check ioc_status to decide whether the
534764a8d931SSreekanth Reddy  * page read is success or not and it is the callers
534864a8d931SSreekanth Reddy  * responsibility.
534964a8d931SSreekanth Reddy  *
535064a8d931SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
535164a8d931SSreekanth Reddy  */
535264a8d931SSreekanth Reddy int mpi3mr_cfg_get_sas_phy_pg1(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
535364a8d931SSreekanth Reddy 	struct mpi3_sas_phy_page1 *phy_pg1, u16 pg_sz, u32 form,
535464a8d931SSreekanth Reddy 	u32 form_spec)
535564a8d931SSreekanth Reddy {
535664a8d931SSreekanth Reddy 	struct mpi3_config_page_header cfg_hdr;
535764a8d931SSreekanth Reddy 	struct mpi3_config_request cfg_req;
535864a8d931SSreekanth Reddy 	u32 page_address;
535964a8d931SSreekanth Reddy 
536064a8d931SSreekanth Reddy 	memset(phy_pg1, 0, pg_sz);
536164a8d931SSreekanth Reddy 	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
536264a8d931SSreekanth Reddy 	memset(&cfg_req, 0, sizeof(cfg_req));
536364a8d931SSreekanth Reddy 
536464a8d931SSreekanth Reddy 	cfg_req.function = MPI3_FUNCTION_CONFIG;
536564a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
536664a8d931SSreekanth Reddy 	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_PHY;
536764a8d931SSreekanth Reddy 	cfg_req.page_number = 1;
536864a8d931SSreekanth Reddy 	cfg_req.page_address = 0;
536964a8d931SSreekanth Reddy 
537064a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
537164a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
537264a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas phy page1 header read failed\n");
537364a8d931SSreekanth Reddy 		goto out_failed;
537464a8d931SSreekanth Reddy 	}
537564a8d931SSreekanth Reddy 	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
537664a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas phy page1 header read failed with ioc_status(0x%04x)\n",
537764a8d931SSreekanth Reddy 		    *ioc_status);
537864a8d931SSreekanth Reddy 		goto out_failed;
537964a8d931SSreekanth Reddy 	}
538064a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
538164a8d931SSreekanth Reddy 	page_address = ((form & MPI3_SAS_PHY_PGAD_FORM_MASK) |
538264a8d931SSreekanth Reddy 	    (form_spec & MPI3_SAS_PHY_PGAD_PHY_NUMBER_MASK));
538364a8d931SSreekanth Reddy 	cfg_req.page_address = cpu_to_le32(page_address);
538464a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
538564a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, phy_pg1, pg_sz)) {
538664a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas phy page1 read failed\n");
538764a8d931SSreekanth Reddy 		goto out_failed;
538864a8d931SSreekanth Reddy 	}
538964a8d931SSreekanth Reddy 	return 0;
539064a8d931SSreekanth Reddy out_failed:
539164a8d931SSreekanth Reddy 	return -1;
539264a8d931SSreekanth Reddy }
539364a8d931SSreekanth Reddy 
539464a8d931SSreekanth Reddy 
539564a8d931SSreekanth Reddy /**
539664a8d931SSreekanth Reddy  * mpi3mr_cfg_get_sas_exp_pg0 - Read current SAS Expander page0
539764a8d931SSreekanth Reddy  * @mrioc: Adapter instance reference
539864a8d931SSreekanth Reddy  * @ioc_status: Pointer to return ioc status
539964a8d931SSreekanth Reddy  * @exp_pg0: Pointer to return SAS Expander page 0
540064a8d931SSreekanth Reddy  * @pg_sz: Size of the memory allocated to the page pointer
540164a8d931SSreekanth Reddy  * @form: The form to be used for addressing the page
540264a8d931SSreekanth Reddy  * @form_spec: Form specific information like device handle
540364a8d931SSreekanth Reddy  *
540464a8d931SSreekanth Reddy  * This is handler for config page read for a specific SAS
540564a8d931SSreekanth Reddy  * Expander page0. The ioc_status has the controller returned
540664a8d931SSreekanth Reddy  * ioc_status. This routine doesn't check ioc_status to decide
540764a8d931SSreekanth Reddy  * whether the page read is success or not and it is the callers
540864a8d931SSreekanth Reddy  * responsibility.
540964a8d931SSreekanth Reddy  *
541064a8d931SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
541164a8d931SSreekanth Reddy  */
541264a8d931SSreekanth Reddy int mpi3mr_cfg_get_sas_exp_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
541364a8d931SSreekanth Reddy 	struct mpi3_sas_expander_page0 *exp_pg0, u16 pg_sz, u32 form,
541464a8d931SSreekanth Reddy 	u32 form_spec)
541564a8d931SSreekanth Reddy {
541664a8d931SSreekanth Reddy 	struct mpi3_config_page_header cfg_hdr;
541764a8d931SSreekanth Reddy 	struct mpi3_config_request cfg_req;
541864a8d931SSreekanth Reddy 	u32 page_address;
541964a8d931SSreekanth Reddy 
542064a8d931SSreekanth Reddy 	memset(exp_pg0, 0, pg_sz);
542164a8d931SSreekanth Reddy 	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
542264a8d931SSreekanth Reddy 	memset(&cfg_req, 0, sizeof(cfg_req));
542364a8d931SSreekanth Reddy 
542464a8d931SSreekanth Reddy 	cfg_req.function = MPI3_FUNCTION_CONFIG;
542564a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
542664a8d931SSreekanth Reddy 	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_EXPANDER;
542764a8d931SSreekanth Reddy 	cfg_req.page_number = 0;
542864a8d931SSreekanth Reddy 	cfg_req.page_address = 0;
542964a8d931SSreekanth Reddy 
543064a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
543164a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
543264a8d931SSreekanth Reddy 		ioc_err(mrioc, "expander page0 header read failed\n");
543364a8d931SSreekanth Reddy 		goto out_failed;
543464a8d931SSreekanth Reddy 	}
543564a8d931SSreekanth Reddy 	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
543664a8d931SSreekanth Reddy 		ioc_err(mrioc, "expander page0 header read failed with ioc_status(0x%04x)\n",
543764a8d931SSreekanth Reddy 		    *ioc_status);
543864a8d931SSreekanth Reddy 		goto out_failed;
543964a8d931SSreekanth Reddy 	}
544064a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
544164a8d931SSreekanth Reddy 	page_address = ((form & MPI3_SAS_EXPAND_PGAD_FORM_MASK) |
544264a8d931SSreekanth Reddy 	    (form_spec & (MPI3_SAS_EXPAND_PGAD_PHYNUM_MASK |
544364a8d931SSreekanth Reddy 	    MPI3_SAS_EXPAND_PGAD_HANDLE_MASK)));
544464a8d931SSreekanth Reddy 	cfg_req.page_address = cpu_to_le32(page_address);
544564a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
544664a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, exp_pg0, pg_sz)) {
544764a8d931SSreekanth Reddy 		ioc_err(mrioc, "expander page0 read failed\n");
544864a8d931SSreekanth Reddy 		goto out_failed;
544964a8d931SSreekanth Reddy 	}
545064a8d931SSreekanth Reddy 	return 0;
545164a8d931SSreekanth Reddy out_failed:
545264a8d931SSreekanth Reddy 	return -1;
545364a8d931SSreekanth Reddy }
545464a8d931SSreekanth Reddy 
545564a8d931SSreekanth Reddy /**
545664a8d931SSreekanth Reddy  * mpi3mr_cfg_get_sas_exp_pg1 - Read current SAS Expander page1
545764a8d931SSreekanth Reddy  * @mrioc: Adapter instance reference
545864a8d931SSreekanth Reddy  * @ioc_status: Pointer to return ioc status
545964a8d931SSreekanth Reddy  * @exp_pg1: Pointer to return SAS Expander page 1
546064a8d931SSreekanth Reddy  * @pg_sz: Size of the memory allocated to the page pointer
546164a8d931SSreekanth Reddy  * @form: The form to be used for addressing the page
546264a8d931SSreekanth Reddy  * @form_spec: Form specific information like phy number
546364a8d931SSreekanth Reddy  *
546464a8d931SSreekanth Reddy  * This is handler for config page read for a specific SAS
546564a8d931SSreekanth Reddy  * Expander page1. The ioc_status has the controller returned
546664a8d931SSreekanth Reddy  * ioc_status. This routine doesn't check ioc_status to decide
546764a8d931SSreekanth Reddy  * whether the page read is success or not and it is the callers
546864a8d931SSreekanth Reddy  * responsibility.
546964a8d931SSreekanth Reddy  *
547064a8d931SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
547164a8d931SSreekanth Reddy  */
547264a8d931SSreekanth Reddy int mpi3mr_cfg_get_sas_exp_pg1(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
547364a8d931SSreekanth Reddy 	struct mpi3_sas_expander_page1 *exp_pg1, u16 pg_sz, u32 form,
547464a8d931SSreekanth Reddy 	u32 form_spec)
547564a8d931SSreekanth Reddy {
547664a8d931SSreekanth Reddy 	struct mpi3_config_page_header cfg_hdr;
547764a8d931SSreekanth Reddy 	struct mpi3_config_request cfg_req;
547864a8d931SSreekanth Reddy 	u32 page_address;
547964a8d931SSreekanth Reddy 
548064a8d931SSreekanth Reddy 	memset(exp_pg1, 0, pg_sz);
548164a8d931SSreekanth Reddy 	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
548264a8d931SSreekanth Reddy 	memset(&cfg_req, 0, sizeof(cfg_req));
548364a8d931SSreekanth Reddy 
548464a8d931SSreekanth Reddy 	cfg_req.function = MPI3_FUNCTION_CONFIG;
548564a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
548664a8d931SSreekanth Reddy 	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_EXPANDER;
548764a8d931SSreekanth Reddy 	cfg_req.page_number = 1;
548864a8d931SSreekanth Reddy 	cfg_req.page_address = 0;
548964a8d931SSreekanth Reddy 
549064a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
549164a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
549264a8d931SSreekanth Reddy 		ioc_err(mrioc, "expander page1 header read failed\n");
549364a8d931SSreekanth Reddy 		goto out_failed;
549464a8d931SSreekanth Reddy 	}
549564a8d931SSreekanth Reddy 	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
549664a8d931SSreekanth Reddy 		ioc_err(mrioc, "expander page1 header read failed with ioc_status(0x%04x)\n",
549764a8d931SSreekanth Reddy 		    *ioc_status);
549864a8d931SSreekanth Reddy 		goto out_failed;
549964a8d931SSreekanth Reddy 	}
550064a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
550164a8d931SSreekanth Reddy 	page_address = ((form & MPI3_SAS_EXPAND_PGAD_FORM_MASK) |
550264a8d931SSreekanth Reddy 	    (form_spec & (MPI3_SAS_EXPAND_PGAD_PHYNUM_MASK |
550364a8d931SSreekanth Reddy 	    MPI3_SAS_EXPAND_PGAD_HANDLE_MASK)));
550464a8d931SSreekanth Reddy 	cfg_req.page_address = cpu_to_le32(page_address);
550564a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
550664a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, exp_pg1, pg_sz)) {
550764a8d931SSreekanth Reddy 		ioc_err(mrioc, "expander page1 read failed\n");
550864a8d931SSreekanth Reddy 		goto out_failed;
550964a8d931SSreekanth Reddy 	}
551064a8d931SSreekanth Reddy 	return 0;
551164a8d931SSreekanth Reddy out_failed:
551264a8d931SSreekanth Reddy 	return -1;
551364a8d931SSreekanth Reddy }
551464a8d931SSreekanth Reddy 
551564a8d931SSreekanth Reddy /**
551664a8d931SSreekanth Reddy  * mpi3mr_cfg_get_enclosure_pg0 - Read current Enclosure page0
551764a8d931SSreekanth Reddy  * @mrioc: Adapter instance reference
551864a8d931SSreekanth Reddy  * @ioc_status: Pointer to return ioc status
551964a8d931SSreekanth Reddy  * @encl_pg0: Pointer to return Enclosure page 0
552064a8d931SSreekanth Reddy  * @pg_sz: Size of the memory allocated to the page pointer
552164a8d931SSreekanth Reddy  * @form: The form to be used for addressing the page
552264a8d931SSreekanth Reddy  * @form_spec: Form specific information like device handle
552364a8d931SSreekanth Reddy  *
552464a8d931SSreekanth Reddy  * This is handler for config page read for a specific Enclosure
552564a8d931SSreekanth Reddy  * page0. The ioc_status has the controller returned ioc_status.
552664a8d931SSreekanth Reddy  * This routine doesn't check ioc_status to decide whether the
552764a8d931SSreekanth Reddy  * page read is success or not and it is the callers
552864a8d931SSreekanth Reddy  * responsibility.
552964a8d931SSreekanth Reddy  *
553064a8d931SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
553164a8d931SSreekanth Reddy  */
553264a8d931SSreekanth Reddy int mpi3mr_cfg_get_enclosure_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
553364a8d931SSreekanth Reddy 	struct mpi3_enclosure_page0 *encl_pg0, u16 pg_sz, u32 form,
553464a8d931SSreekanth Reddy 	u32 form_spec)
553564a8d931SSreekanth Reddy {
553664a8d931SSreekanth Reddy 	struct mpi3_config_page_header cfg_hdr;
553764a8d931SSreekanth Reddy 	struct mpi3_config_request cfg_req;
553864a8d931SSreekanth Reddy 	u32 page_address;
553964a8d931SSreekanth Reddy 
554064a8d931SSreekanth Reddy 	memset(encl_pg0, 0, pg_sz);
554164a8d931SSreekanth Reddy 	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
554264a8d931SSreekanth Reddy 	memset(&cfg_req, 0, sizeof(cfg_req));
554364a8d931SSreekanth Reddy 
554464a8d931SSreekanth Reddy 	cfg_req.function = MPI3_FUNCTION_CONFIG;
554564a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
554664a8d931SSreekanth Reddy 	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_ENCLOSURE;
554764a8d931SSreekanth Reddy 	cfg_req.page_number = 0;
554864a8d931SSreekanth Reddy 	cfg_req.page_address = 0;
554964a8d931SSreekanth Reddy 
555064a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
555164a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
555264a8d931SSreekanth Reddy 		ioc_err(mrioc, "enclosure page0 header read failed\n");
555364a8d931SSreekanth Reddy 		goto out_failed;
555464a8d931SSreekanth Reddy 	}
555564a8d931SSreekanth Reddy 	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
555664a8d931SSreekanth Reddy 		ioc_err(mrioc, "enclosure page0 header read failed with ioc_status(0x%04x)\n",
555764a8d931SSreekanth Reddy 		    *ioc_status);
555864a8d931SSreekanth Reddy 		goto out_failed;
555964a8d931SSreekanth Reddy 	}
556064a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
556164a8d931SSreekanth Reddy 	page_address = ((form & MPI3_ENCLOS_PGAD_FORM_MASK) |
556264a8d931SSreekanth Reddy 	    (form_spec & MPI3_ENCLOS_PGAD_HANDLE_MASK));
556364a8d931SSreekanth Reddy 	cfg_req.page_address = cpu_to_le32(page_address);
556464a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
556564a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, encl_pg0, pg_sz)) {
556664a8d931SSreekanth Reddy 		ioc_err(mrioc, "enclosure page0 read failed\n");
556764a8d931SSreekanth Reddy 		goto out_failed;
556864a8d931SSreekanth Reddy 	}
556964a8d931SSreekanth Reddy 	return 0;
557064a8d931SSreekanth Reddy out_failed:
557164a8d931SSreekanth Reddy 	return -1;
557264a8d931SSreekanth Reddy }
557364a8d931SSreekanth Reddy 
557464a8d931SSreekanth Reddy 
557564a8d931SSreekanth Reddy /**
557664a8d931SSreekanth Reddy  * mpi3mr_cfg_get_sas_io_unit_pg0 - Read current SASIOUnit page0
557764a8d931SSreekanth Reddy  * @mrioc: Adapter instance reference
557864a8d931SSreekanth Reddy  * @sas_io_unit_pg0: Pointer to return SAS IO Unit page 0
557964a8d931SSreekanth Reddy  * @pg_sz: Size of the memory allocated to the page pointer
558064a8d931SSreekanth Reddy  *
558164a8d931SSreekanth Reddy  * This is handler for config page read for the SAS IO Unit
558264a8d931SSreekanth Reddy  * page0. This routine checks ioc_status to decide whether the
558364a8d931SSreekanth Reddy  * page read is success or not.
558464a8d931SSreekanth Reddy  *
558564a8d931SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
558664a8d931SSreekanth Reddy  */
558764a8d931SSreekanth Reddy int mpi3mr_cfg_get_sas_io_unit_pg0(struct mpi3mr_ioc *mrioc,
558864a8d931SSreekanth Reddy 	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0, u16 pg_sz)
558964a8d931SSreekanth Reddy {
559064a8d931SSreekanth Reddy 	struct mpi3_config_page_header cfg_hdr;
559164a8d931SSreekanth Reddy 	struct mpi3_config_request cfg_req;
559264a8d931SSreekanth Reddy 	u16 ioc_status = 0;
559364a8d931SSreekanth Reddy 
559464a8d931SSreekanth Reddy 	memset(sas_io_unit_pg0, 0, pg_sz);
559564a8d931SSreekanth Reddy 	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
559664a8d931SSreekanth Reddy 	memset(&cfg_req, 0, sizeof(cfg_req));
559764a8d931SSreekanth Reddy 
559864a8d931SSreekanth Reddy 	cfg_req.function = MPI3_FUNCTION_CONFIG;
559964a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
560064a8d931SSreekanth Reddy 	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_IO_UNIT;
560164a8d931SSreekanth Reddy 	cfg_req.page_number = 0;
560264a8d931SSreekanth Reddy 	cfg_req.page_address = 0;
560364a8d931SSreekanth Reddy 
560464a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
560564a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
560664a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page0 header read failed\n");
560764a8d931SSreekanth Reddy 		goto out_failed;
560864a8d931SSreekanth Reddy 	}
560964a8d931SSreekanth Reddy 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
561064a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page0 header read failed with ioc_status(0x%04x)\n",
561164a8d931SSreekanth Reddy 		    ioc_status);
561264a8d931SSreekanth Reddy 		goto out_failed;
561364a8d931SSreekanth Reddy 	}
561464a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
561564a8d931SSreekanth Reddy 
561664a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
561764a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, sas_io_unit_pg0, pg_sz)) {
561864a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page0 read failed\n");
561964a8d931SSreekanth Reddy 		goto out_failed;
562064a8d931SSreekanth Reddy 	}
562164a8d931SSreekanth Reddy 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
562264a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page0 read failed with ioc_status(0x%04x)\n",
562364a8d931SSreekanth Reddy 		    ioc_status);
562464a8d931SSreekanth Reddy 		goto out_failed;
562564a8d931SSreekanth Reddy 	}
562664a8d931SSreekanth Reddy 	return 0;
562764a8d931SSreekanth Reddy out_failed:
562864a8d931SSreekanth Reddy 	return -1;
562964a8d931SSreekanth Reddy }
563064a8d931SSreekanth Reddy 
563164a8d931SSreekanth Reddy /**
563264a8d931SSreekanth Reddy  * mpi3mr_cfg_get_sas_io_unit_pg1 - Read current SASIOUnit page1
563364a8d931SSreekanth Reddy  * @mrioc: Adapter instance reference
563464a8d931SSreekanth Reddy  * @sas_io_unit_pg1: Pointer to return SAS IO Unit page 1
563564a8d931SSreekanth Reddy  * @pg_sz: Size of the memory allocated to the page pointer
563664a8d931SSreekanth Reddy  *
563764a8d931SSreekanth Reddy  * This is handler for config page read for the SAS IO Unit
563864a8d931SSreekanth Reddy  * page1. This routine checks ioc_status to decide whether the
563964a8d931SSreekanth Reddy  * page read is success or not.
564064a8d931SSreekanth Reddy  *
564164a8d931SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
564264a8d931SSreekanth Reddy  */
564364a8d931SSreekanth Reddy int mpi3mr_cfg_get_sas_io_unit_pg1(struct mpi3mr_ioc *mrioc,
564464a8d931SSreekanth Reddy 	struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1, u16 pg_sz)
564564a8d931SSreekanth Reddy {
564664a8d931SSreekanth Reddy 	struct mpi3_config_page_header cfg_hdr;
564764a8d931SSreekanth Reddy 	struct mpi3_config_request cfg_req;
564864a8d931SSreekanth Reddy 	u16 ioc_status = 0;
564964a8d931SSreekanth Reddy 
565064a8d931SSreekanth Reddy 	memset(sas_io_unit_pg1, 0, pg_sz);
565164a8d931SSreekanth Reddy 	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
565264a8d931SSreekanth Reddy 	memset(&cfg_req, 0, sizeof(cfg_req));
565364a8d931SSreekanth Reddy 
565464a8d931SSreekanth Reddy 	cfg_req.function = MPI3_FUNCTION_CONFIG;
565564a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
565664a8d931SSreekanth Reddy 	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_IO_UNIT;
565764a8d931SSreekanth Reddy 	cfg_req.page_number = 1;
565864a8d931SSreekanth Reddy 	cfg_req.page_address = 0;
565964a8d931SSreekanth Reddy 
566064a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
566164a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
566264a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page1 header read failed\n");
566364a8d931SSreekanth Reddy 		goto out_failed;
566464a8d931SSreekanth Reddy 	}
566564a8d931SSreekanth Reddy 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
566664a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page1 header read failed with ioc_status(0x%04x)\n",
566764a8d931SSreekanth Reddy 		    ioc_status);
566864a8d931SSreekanth Reddy 		goto out_failed;
566964a8d931SSreekanth Reddy 	}
567064a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
567164a8d931SSreekanth Reddy 
567264a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
567364a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, sas_io_unit_pg1, pg_sz)) {
567464a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page1 read failed\n");
567564a8d931SSreekanth Reddy 		goto out_failed;
567664a8d931SSreekanth Reddy 	}
567764a8d931SSreekanth Reddy 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
567864a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page1 read failed with ioc_status(0x%04x)\n",
567964a8d931SSreekanth Reddy 		    ioc_status);
568064a8d931SSreekanth Reddy 		goto out_failed;
568164a8d931SSreekanth Reddy 	}
568264a8d931SSreekanth Reddy 	return 0;
568364a8d931SSreekanth Reddy out_failed:
568464a8d931SSreekanth Reddy 	return -1;
568564a8d931SSreekanth Reddy }
568664a8d931SSreekanth Reddy 
568764a8d931SSreekanth Reddy /**
568864a8d931SSreekanth Reddy  * mpi3mr_cfg_set_sas_io_unit_pg1 - Write SASIOUnit page1
568964a8d931SSreekanth Reddy  * @mrioc: Adapter instance reference
569064a8d931SSreekanth Reddy  * @sas_io_unit_pg1: Pointer to the SAS IO Unit page 1 to write
569164a8d931SSreekanth Reddy  * @pg_sz: Size of the memory allocated to the page pointer
569264a8d931SSreekanth Reddy  *
569364a8d931SSreekanth Reddy  * This is handler for config page write for the SAS IO Unit
569464a8d931SSreekanth Reddy  * page1. This routine checks ioc_status to decide whether the
569564a8d931SSreekanth Reddy  * page read is success or not. This will modify both current
569664a8d931SSreekanth Reddy  * and persistent page.
569764a8d931SSreekanth Reddy  *
569864a8d931SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
569964a8d931SSreekanth Reddy  */
570064a8d931SSreekanth Reddy int mpi3mr_cfg_set_sas_io_unit_pg1(struct mpi3mr_ioc *mrioc,
570164a8d931SSreekanth Reddy 	struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1, u16 pg_sz)
570264a8d931SSreekanth Reddy {
570364a8d931SSreekanth Reddy 	struct mpi3_config_page_header cfg_hdr;
570464a8d931SSreekanth Reddy 	struct mpi3_config_request cfg_req;
570564a8d931SSreekanth Reddy 	u16 ioc_status = 0;
570664a8d931SSreekanth Reddy 
570764a8d931SSreekanth Reddy 	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
570864a8d931SSreekanth Reddy 	memset(&cfg_req, 0, sizeof(cfg_req));
570964a8d931SSreekanth Reddy 
571064a8d931SSreekanth Reddy 	cfg_req.function = MPI3_FUNCTION_CONFIG;
571164a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
571264a8d931SSreekanth Reddy 	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_IO_UNIT;
571364a8d931SSreekanth Reddy 	cfg_req.page_number = 1;
571464a8d931SSreekanth Reddy 	cfg_req.page_address = 0;
571564a8d931SSreekanth Reddy 
571664a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
571764a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
571864a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page1 header read failed\n");
571964a8d931SSreekanth Reddy 		goto out_failed;
572064a8d931SSreekanth Reddy 	}
572164a8d931SSreekanth Reddy 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
572264a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page1 header read failed with ioc_status(0x%04x)\n",
572364a8d931SSreekanth Reddy 		    ioc_status);
572464a8d931SSreekanth Reddy 		goto out_failed;
572564a8d931SSreekanth Reddy 	}
572664a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_WRITE_CURRENT;
572764a8d931SSreekanth Reddy 
572864a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
572964a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, sas_io_unit_pg1, pg_sz)) {
573064a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page1 write current failed\n");
573164a8d931SSreekanth Reddy 		goto out_failed;
573264a8d931SSreekanth Reddy 	}
573364a8d931SSreekanth Reddy 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
573464a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page1 write current failed with ioc_status(0x%04x)\n",
573564a8d931SSreekanth Reddy 		    ioc_status);
573664a8d931SSreekanth Reddy 		goto out_failed;
573764a8d931SSreekanth Reddy 	}
573864a8d931SSreekanth Reddy 
573964a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_WRITE_PERSISTENT;
574064a8d931SSreekanth Reddy 
574164a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
574264a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, sas_io_unit_pg1, pg_sz)) {
574364a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page1 write persistent failed\n");
574464a8d931SSreekanth Reddy 		goto out_failed;
574564a8d931SSreekanth Reddy 	}
574664a8d931SSreekanth Reddy 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
574764a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page1 write persistent failed with ioc_status(0x%04x)\n",
574864a8d931SSreekanth Reddy 		    ioc_status);
574964a8d931SSreekanth Reddy 		goto out_failed;
575064a8d931SSreekanth Reddy 	}
575164a8d931SSreekanth Reddy 	return 0;
575264a8d931SSreekanth Reddy out_failed:
575364a8d931SSreekanth Reddy 	return -1;
575464a8d931SSreekanth Reddy }
575564a8d931SSreekanth Reddy 
575664a8d931SSreekanth Reddy /**
575764a8d931SSreekanth Reddy  * mpi3mr_cfg_get_driver_pg1 - Read current Driver page1
575864a8d931SSreekanth Reddy  * @mrioc: Adapter instance reference
575964a8d931SSreekanth Reddy  * @driver_pg1: Pointer to return Driver page 1
576064a8d931SSreekanth Reddy  * @pg_sz: Size of the memory allocated to the page pointer
576164a8d931SSreekanth Reddy  *
576264a8d931SSreekanth Reddy  * This is handler for config page read for the Driver page1.
576364a8d931SSreekanth Reddy  * This routine checks ioc_status to decide whether the page
576464a8d931SSreekanth Reddy  * read is success or not.
576564a8d931SSreekanth Reddy  *
576664a8d931SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
576764a8d931SSreekanth Reddy  */
576864a8d931SSreekanth Reddy int mpi3mr_cfg_get_driver_pg1(struct mpi3mr_ioc *mrioc,
576964a8d931SSreekanth Reddy 	struct mpi3_driver_page1 *driver_pg1, u16 pg_sz)
577064a8d931SSreekanth Reddy {
577164a8d931SSreekanth Reddy 	struct mpi3_config_page_header cfg_hdr;
577264a8d931SSreekanth Reddy 	struct mpi3_config_request cfg_req;
577364a8d931SSreekanth Reddy 	u16 ioc_status = 0;
577464a8d931SSreekanth Reddy 
577564a8d931SSreekanth Reddy 	memset(driver_pg1, 0, pg_sz);
577664a8d931SSreekanth Reddy 	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
577764a8d931SSreekanth Reddy 	memset(&cfg_req, 0, sizeof(cfg_req));
577864a8d931SSreekanth Reddy 
577964a8d931SSreekanth Reddy 	cfg_req.function = MPI3_FUNCTION_CONFIG;
578064a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
578164a8d931SSreekanth Reddy 	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_DRIVER;
578264a8d931SSreekanth Reddy 	cfg_req.page_number = 1;
578364a8d931SSreekanth Reddy 	cfg_req.page_address = 0;
578464a8d931SSreekanth Reddy 
578564a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
578664a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
578764a8d931SSreekanth Reddy 		ioc_err(mrioc, "driver page1 header read failed\n");
578864a8d931SSreekanth Reddy 		goto out_failed;
578964a8d931SSreekanth Reddy 	}
579064a8d931SSreekanth Reddy 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
579164a8d931SSreekanth Reddy 		ioc_err(mrioc, "driver page1 header read failed with ioc_status(0x%04x)\n",
579264a8d931SSreekanth Reddy 		    ioc_status);
579364a8d931SSreekanth Reddy 		goto out_failed;
579464a8d931SSreekanth Reddy 	}
579564a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
579664a8d931SSreekanth Reddy 
579764a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
579864a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, driver_pg1, pg_sz)) {
579964a8d931SSreekanth Reddy 		ioc_err(mrioc, "driver page1 read failed\n");
580064a8d931SSreekanth Reddy 		goto out_failed;
580164a8d931SSreekanth Reddy 	}
580264a8d931SSreekanth Reddy 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
580364a8d931SSreekanth Reddy 		ioc_err(mrioc, "driver page1 read failed with ioc_status(0x%04x)\n",
580464a8d931SSreekanth Reddy 		    ioc_status);
580564a8d931SSreekanth Reddy 		goto out_failed;
580664a8d931SSreekanth Reddy 	}
580764a8d931SSreekanth Reddy 	return 0;
580864a8d931SSreekanth Reddy out_failed:
580964a8d931SSreekanth Reddy 	return -1;
581064a8d931SSreekanth Reddy }
5811