xref: /linux/drivers/scsi/mpi3mr/mpi3mr_fw.c (revision afd3a5793fe2a217513bc5eb2228a5ca8e8b556a)
1824a1566SKashyap Desai // SPDX-License-Identifier: GPL-2.0-or-later
2824a1566SKashyap Desai /*
3824a1566SKashyap Desai  * Driver for Broadcom MPI3 Storage Controllers
4824a1566SKashyap Desai  *
5824a1566SKashyap Desai  * Copyright (C) 2017-2021 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);
1859bd9cfeSSreekanth Reddy 
19*afd3a579SSreekanth Reddy static int poll_queues;
20*afd3a579SSreekanth Reddy module_param(poll_queues, int, 0444);
21*afd3a579SSreekanth Reddy MODULE_PARM_DESC(poll_queues, "Number of queues for io_uring poll mode. (Range 1 - 126)");
22*afd3a579SSreekanth Reddy 
23824a1566SKashyap Desai #if defined(writeq) && defined(CONFIG_64BIT)
24824a1566SKashyap Desai static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr)
25824a1566SKashyap Desai {
26824a1566SKashyap Desai 	writeq(b, addr);
27824a1566SKashyap Desai }
28824a1566SKashyap Desai #else
29824a1566SKashyap Desai static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr)
30824a1566SKashyap Desai {
31824a1566SKashyap Desai 	__u64 data_out = b;
32824a1566SKashyap Desai 
33824a1566SKashyap Desai 	writel((u32)(data_out), addr);
34824a1566SKashyap Desai 	writel((u32)(data_out >> 32), (addr + 4));
35824a1566SKashyap Desai }
36824a1566SKashyap Desai #endif
37824a1566SKashyap Desai 
38023ab2a9SKashyap Desai static inline bool
39023ab2a9SKashyap Desai mpi3mr_check_req_qfull(struct op_req_qinfo *op_req_q)
40023ab2a9SKashyap Desai {
41023ab2a9SKashyap Desai 	u16 pi, ci, max_entries;
42023ab2a9SKashyap Desai 	bool is_qfull = false;
43023ab2a9SKashyap Desai 
44023ab2a9SKashyap Desai 	pi = op_req_q->pi;
45023ab2a9SKashyap Desai 	ci = READ_ONCE(op_req_q->ci);
46023ab2a9SKashyap Desai 	max_entries = op_req_q->num_requests;
47023ab2a9SKashyap Desai 
48023ab2a9SKashyap Desai 	if ((ci == (pi + 1)) || ((!ci) && (pi == (max_entries - 1))))
49023ab2a9SKashyap Desai 		is_qfull = true;
50023ab2a9SKashyap Desai 
51023ab2a9SKashyap Desai 	return is_qfull;
52023ab2a9SKashyap Desai }
53023ab2a9SKashyap Desai 
54824a1566SKashyap Desai static void mpi3mr_sync_irqs(struct mpi3mr_ioc *mrioc)
55824a1566SKashyap Desai {
56824a1566SKashyap Desai 	u16 i, max_vectors;
57824a1566SKashyap Desai 
58824a1566SKashyap Desai 	max_vectors = mrioc->intr_info_count;
59824a1566SKashyap Desai 
60824a1566SKashyap Desai 	for (i = 0; i < max_vectors; i++)
61824a1566SKashyap Desai 		synchronize_irq(pci_irq_vector(mrioc->pdev, i));
62824a1566SKashyap Desai }
63824a1566SKashyap Desai 
64824a1566SKashyap Desai void mpi3mr_ioc_disable_intr(struct mpi3mr_ioc *mrioc)
65824a1566SKashyap Desai {
66824a1566SKashyap Desai 	mrioc->intr_enabled = 0;
67824a1566SKashyap Desai 	mpi3mr_sync_irqs(mrioc);
68824a1566SKashyap Desai }
69824a1566SKashyap Desai 
70824a1566SKashyap Desai void mpi3mr_ioc_enable_intr(struct mpi3mr_ioc *mrioc)
71824a1566SKashyap Desai {
72824a1566SKashyap Desai 	mrioc->intr_enabled = 1;
73824a1566SKashyap Desai }
74824a1566SKashyap Desai 
75824a1566SKashyap Desai static void mpi3mr_cleanup_isr(struct mpi3mr_ioc *mrioc)
76824a1566SKashyap Desai {
77824a1566SKashyap Desai 	u16 i;
78824a1566SKashyap Desai 
79824a1566SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
80824a1566SKashyap Desai 
81824a1566SKashyap Desai 	if (!mrioc->intr_info)
82824a1566SKashyap Desai 		return;
83824a1566SKashyap Desai 
84824a1566SKashyap Desai 	for (i = 0; i < mrioc->intr_info_count; i++)
85824a1566SKashyap Desai 		free_irq(pci_irq_vector(mrioc->pdev, i),
86824a1566SKashyap Desai 		    (mrioc->intr_info + i));
87824a1566SKashyap Desai 
88824a1566SKashyap Desai 	kfree(mrioc->intr_info);
89824a1566SKashyap Desai 	mrioc->intr_info = NULL;
90824a1566SKashyap Desai 	mrioc->intr_info_count = 0;
91fe6db615SSreekanth Reddy 	mrioc->is_intr_info_set = false;
92824a1566SKashyap Desai 	pci_free_irq_vectors(mrioc->pdev);
93824a1566SKashyap Desai }
94824a1566SKashyap Desai 
95824a1566SKashyap Desai void mpi3mr_add_sg_single(void *paddr, u8 flags, u32 length,
96824a1566SKashyap Desai 	dma_addr_t dma_addr)
97824a1566SKashyap Desai {
98824a1566SKashyap Desai 	struct mpi3_sge_common *sgel = paddr;
99824a1566SKashyap Desai 
100824a1566SKashyap Desai 	sgel->flags = flags;
101824a1566SKashyap Desai 	sgel->length = cpu_to_le32(length);
102824a1566SKashyap Desai 	sgel->address = cpu_to_le64(dma_addr);
103824a1566SKashyap Desai }
104824a1566SKashyap Desai 
105824a1566SKashyap Desai void mpi3mr_build_zero_len_sge(void *paddr)
106824a1566SKashyap Desai {
107824a1566SKashyap Desai 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
108824a1566SKashyap Desai 
109824a1566SKashyap Desai 	mpi3mr_add_sg_single(paddr, sgl_flags, 0, -1);
110824a1566SKashyap Desai }
111824a1566SKashyap Desai 
112824a1566SKashyap Desai void *mpi3mr_get_reply_virt_addr(struct mpi3mr_ioc *mrioc,
113824a1566SKashyap Desai 	dma_addr_t phys_addr)
114824a1566SKashyap Desai {
115824a1566SKashyap Desai 	if (!phys_addr)
116824a1566SKashyap Desai 		return NULL;
117824a1566SKashyap Desai 
118824a1566SKashyap Desai 	if ((phys_addr < mrioc->reply_buf_dma) ||
119824a1566SKashyap Desai 	    (phys_addr > mrioc->reply_buf_dma_max_address))
120824a1566SKashyap Desai 		return NULL;
121824a1566SKashyap Desai 
122824a1566SKashyap Desai 	return mrioc->reply_buf + (phys_addr - mrioc->reply_buf_dma);
123824a1566SKashyap Desai }
124824a1566SKashyap Desai 
125824a1566SKashyap Desai void *mpi3mr_get_sensebuf_virt_addr(struct mpi3mr_ioc *mrioc,
126824a1566SKashyap Desai 	dma_addr_t phys_addr)
127824a1566SKashyap Desai {
128824a1566SKashyap Desai 	if (!phys_addr)
129824a1566SKashyap Desai 		return NULL;
130824a1566SKashyap Desai 
131824a1566SKashyap Desai 	return mrioc->sense_buf + (phys_addr - mrioc->sense_buf_dma);
132824a1566SKashyap Desai }
133824a1566SKashyap Desai 
134824a1566SKashyap Desai static void mpi3mr_repost_reply_buf(struct mpi3mr_ioc *mrioc,
135824a1566SKashyap Desai 	u64 reply_dma)
136824a1566SKashyap Desai {
137824a1566SKashyap Desai 	u32 old_idx = 0;
138a83ec831SSreekanth Reddy 	unsigned long flags;
139824a1566SKashyap Desai 
140a83ec831SSreekanth Reddy 	spin_lock_irqsave(&mrioc->reply_free_queue_lock, flags);
141824a1566SKashyap Desai 	old_idx  =  mrioc->reply_free_queue_host_index;
142824a1566SKashyap Desai 	mrioc->reply_free_queue_host_index = (
143824a1566SKashyap Desai 	    (mrioc->reply_free_queue_host_index ==
144824a1566SKashyap Desai 	    (mrioc->reply_free_qsz - 1)) ? 0 :
145824a1566SKashyap Desai 	    (mrioc->reply_free_queue_host_index + 1));
146824a1566SKashyap Desai 	mrioc->reply_free_q[old_idx] = cpu_to_le64(reply_dma);
147824a1566SKashyap Desai 	writel(mrioc->reply_free_queue_host_index,
148824a1566SKashyap Desai 	    &mrioc->sysif_regs->reply_free_host_index);
149a83ec831SSreekanth Reddy 	spin_unlock_irqrestore(&mrioc->reply_free_queue_lock, flags);
150824a1566SKashyap Desai }
151824a1566SKashyap Desai 
152824a1566SKashyap Desai void mpi3mr_repost_sense_buf(struct mpi3mr_ioc *mrioc,
153824a1566SKashyap Desai 	u64 sense_buf_dma)
154824a1566SKashyap Desai {
155824a1566SKashyap Desai 	u32 old_idx = 0;
156a83ec831SSreekanth Reddy 	unsigned long flags;
157824a1566SKashyap Desai 
158a83ec831SSreekanth Reddy 	spin_lock_irqsave(&mrioc->sbq_lock, flags);
159824a1566SKashyap Desai 	old_idx  =  mrioc->sbq_host_index;
160824a1566SKashyap Desai 	mrioc->sbq_host_index = ((mrioc->sbq_host_index ==
161824a1566SKashyap Desai 	    (mrioc->sense_buf_q_sz - 1)) ? 0 :
162824a1566SKashyap Desai 	    (mrioc->sbq_host_index + 1));
163824a1566SKashyap Desai 	mrioc->sense_buf_q[old_idx] = cpu_to_le64(sense_buf_dma);
164824a1566SKashyap Desai 	writel(mrioc->sbq_host_index,
165824a1566SKashyap Desai 	    &mrioc->sysif_regs->sense_buffer_free_host_index);
166a83ec831SSreekanth Reddy 	spin_unlock_irqrestore(&mrioc->sbq_lock, flags);
167824a1566SKashyap Desai }
168824a1566SKashyap Desai 
1699fc4abfeSKashyap Desai static void mpi3mr_print_event_data(struct mpi3mr_ioc *mrioc,
1709fc4abfeSKashyap Desai 	struct mpi3_event_notification_reply *event_reply)
1719fc4abfeSKashyap Desai {
1729fc4abfeSKashyap Desai 	char *desc = NULL;
1739fc4abfeSKashyap Desai 	u16 event;
1749fc4abfeSKashyap Desai 
1759fc4abfeSKashyap Desai 	event = event_reply->event;
1769fc4abfeSKashyap Desai 
1779fc4abfeSKashyap Desai 	switch (event) {
1789fc4abfeSKashyap Desai 	case MPI3_EVENT_LOG_DATA:
1799fc4abfeSKashyap Desai 		desc = "Log Data";
1809fc4abfeSKashyap Desai 		break;
1819fc4abfeSKashyap Desai 	case MPI3_EVENT_CHANGE:
1829fc4abfeSKashyap Desai 		desc = "Event Change";
1839fc4abfeSKashyap Desai 		break;
1849fc4abfeSKashyap Desai 	case MPI3_EVENT_GPIO_INTERRUPT:
1859fc4abfeSKashyap Desai 		desc = "GPIO Interrupt";
1869fc4abfeSKashyap Desai 		break;
1879fc4abfeSKashyap Desai 	case MPI3_EVENT_TEMP_THRESHOLD:
1889fc4abfeSKashyap Desai 		desc = "Temperature Threshold";
1899fc4abfeSKashyap Desai 		break;
1909fc4abfeSKashyap Desai 	case MPI3_EVENT_CABLE_MGMT:
1919fc4abfeSKashyap Desai 		desc = "Cable Management";
1929fc4abfeSKashyap Desai 		break;
1939fc4abfeSKashyap Desai 	case MPI3_EVENT_ENERGY_PACK_CHANGE:
1949fc4abfeSKashyap Desai 		desc = "Energy Pack Change";
1959fc4abfeSKashyap Desai 		break;
1969fc4abfeSKashyap Desai 	case MPI3_EVENT_DEVICE_ADDED:
1979fc4abfeSKashyap Desai 	{
1989fc4abfeSKashyap Desai 		struct mpi3_device_page0 *event_data =
1999fc4abfeSKashyap Desai 		    (struct mpi3_device_page0 *)event_reply->event_data;
2009fc4abfeSKashyap Desai 		ioc_info(mrioc, "Device Added: dev=0x%04x Form=0x%x\n",
2019fc4abfeSKashyap Desai 		    event_data->dev_handle, event_data->device_form);
2029fc4abfeSKashyap Desai 		return;
2039fc4abfeSKashyap Desai 	}
2049fc4abfeSKashyap Desai 	case MPI3_EVENT_DEVICE_INFO_CHANGED:
2059fc4abfeSKashyap Desai 	{
2069fc4abfeSKashyap Desai 		struct mpi3_device_page0 *event_data =
2079fc4abfeSKashyap Desai 		    (struct mpi3_device_page0 *)event_reply->event_data;
2089fc4abfeSKashyap Desai 		ioc_info(mrioc, "Device Info Changed: dev=0x%04x Form=0x%x\n",
2099fc4abfeSKashyap Desai 		    event_data->dev_handle, event_data->device_form);
2109fc4abfeSKashyap Desai 		return;
2119fc4abfeSKashyap Desai 	}
2129fc4abfeSKashyap Desai 	case MPI3_EVENT_DEVICE_STATUS_CHANGE:
2139fc4abfeSKashyap Desai 	{
2149fc4abfeSKashyap Desai 		struct mpi3_event_data_device_status_change *event_data =
2159fc4abfeSKashyap Desai 		    (struct mpi3_event_data_device_status_change *)event_reply->event_data;
2169fc4abfeSKashyap Desai 		ioc_info(mrioc, "Device status Change: dev=0x%04x RC=0x%x\n",
2179fc4abfeSKashyap Desai 		    event_data->dev_handle, event_data->reason_code);
2189fc4abfeSKashyap Desai 		return;
2199fc4abfeSKashyap Desai 	}
2209fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_DISCOVERY:
2219fc4abfeSKashyap Desai 	{
2229fc4abfeSKashyap Desai 		struct mpi3_event_data_sas_discovery *event_data =
2239fc4abfeSKashyap Desai 		    (struct mpi3_event_data_sas_discovery *)event_reply->event_data;
2249fc4abfeSKashyap Desai 		ioc_info(mrioc, "SAS Discovery: (%s) status (0x%08x)\n",
2259fc4abfeSKashyap Desai 		    (event_data->reason_code == MPI3_EVENT_SAS_DISC_RC_STARTED) ?
2269fc4abfeSKashyap Desai 		    "start" : "stop",
2279fc4abfeSKashyap Desai 		    le32_to_cpu(event_data->discovery_status));
2289fc4abfeSKashyap Desai 		return;
2299fc4abfeSKashyap Desai 	}
2309fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE:
2319fc4abfeSKashyap Desai 		desc = "SAS Broadcast Primitive";
2329fc4abfeSKashyap Desai 		break;
2339fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_NOTIFY_PRIMITIVE:
2349fc4abfeSKashyap Desai 		desc = "SAS Notify Primitive";
2359fc4abfeSKashyap Desai 		break;
2369fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
2379fc4abfeSKashyap Desai 		desc = "SAS Init Device Status Change";
2389fc4abfeSKashyap Desai 		break;
2399fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_INIT_TABLE_OVERFLOW:
2409fc4abfeSKashyap Desai 		desc = "SAS Init Table Overflow";
2419fc4abfeSKashyap Desai 		break;
2429fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
2439fc4abfeSKashyap Desai 		desc = "SAS Topology Change List";
2449fc4abfeSKashyap Desai 		break;
2459fc4abfeSKashyap Desai 	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
2469fc4abfeSKashyap Desai 		desc = "Enclosure Device Status Change";
2479fc4abfeSKashyap Desai 		break;
2489fc4abfeSKashyap Desai 	case MPI3_EVENT_HARD_RESET_RECEIVED:
2499fc4abfeSKashyap Desai 		desc = "Hard Reset Received";
2509fc4abfeSKashyap Desai 		break;
2519fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_PHY_COUNTER:
2529fc4abfeSKashyap Desai 		desc = "SAS PHY Counter";
2539fc4abfeSKashyap Desai 		break;
2549fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR:
2559fc4abfeSKashyap Desai 		desc = "SAS Device Discovery Error";
2569fc4abfeSKashyap Desai 		break;
2579fc4abfeSKashyap Desai 	case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
2589fc4abfeSKashyap Desai 		desc = "PCIE Topology Change List";
2599fc4abfeSKashyap Desai 		break;
2609fc4abfeSKashyap Desai 	case MPI3_EVENT_PCIE_ENUMERATION:
2619fc4abfeSKashyap Desai 	{
2629fc4abfeSKashyap Desai 		struct mpi3_event_data_pcie_enumeration *event_data =
2639fc4abfeSKashyap Desai 		    (struct mpi3_event_data_pcie_enumeration *)event_reply->event_data;
2649fc4abfeSKashyap Desai 		ioc_info(mrioc, "PCIE Enumeration: (%s)",
2659fc4abfeSKashyap Desai 		    (event_data->reason_code ==
2669fc4abfeSKashyap Desai 		    MPI3_EVENT_PCIE_ENUM_RC_STARTED) ? "start" : "stop");
2679fc4abfeSKashyap Desai 		if (event_data->enumeration_status)
2689fc4abfeSKashyap Desai 			ioc_info(mrioc, "enumeration_status(0x%08x)\n",
2699fc4abfeSKashyap Desai 			    le32_to_cpu(event_data->enumeration_status));
2709fc4abfeSKashyap Desai 		return;
2719fc4abfeSKashyap Desai 	}
2729fc4abfeSKashyap Desai 	case MPI3_EVENT_PREPARE_FOR_RESET:
2739fc4abfeSKashyap Desai 		desc = "Prepare For Reset";
2749fc4abfeSKashyap Desai 		break;
2759fc4abfeSKashyap Desai 	}
2769fc4abfeSKashyap Desai 
2779fc4abfeSKashyap Desai 	if (!desc)
2789fc4abfeSKashyap Desai 		return;
2799fc4abfeSKashyap Desai 
2809fc4abfeSKashyap Desai 	ioc_info(mrioc, "%s\n", desc);
2819fc4abfeSKashyap Desai }
2829fc4abfeSKashyap Desai 
283824a1566SKashyap Desai static void mpi3mr_handle_events(struct mpi3mr_ioc *mrioc,
284824a1566SKashyap Desai 	struct mpi3_default_reply *def_reply)
285824a1566SKashyap Desai {
286824a1566SKashyap Desai 	struct mpi3_event_notification_reply *event_reply =
287824a1566SKashyap Desai 	    (struct mpi3_event_notification_reply *)def_reply;
288824a1566SKashyap Desai 
289824a1566SKashyap Desai 	mrioc->change_count = le16_to_cpu(event_reply->ioc_change_count);
2909fc4abfeSKashyap Desai 	mpi3mr_print_event_data(mrioc, event_reply);
29113ef29eaSKashyap Desai 	mpi3mr_os_handle_events(mrioc, event_reply);
292824a1566SKashyap Desai }
293824a1566SKashyap Desai 
294824a1566SKashyap Desai static struct mpi3mr_drv_cmd *
295824a1566SKashyap Desai mpi3mr_get_drv_cmd(struct mpi3mr_ioc *mrioc, u16 host_tag,
296824a1566SKashyap Desai 	struct mpi3_default_reply *def_reply)
297824a1566SKashyap Desai {
29813ef29eaSKashyap Desai 	u16 idx;
29913ef29eaSKashyap Desai 
300824a1566SKashyap Desai 	switch (host_tag) {
301824a1566SKashyap Desai 	case MPI3MR_HOSTTAG_INITCMDS:
302824a1566SKashyap Desai 		return &mrioc->init_cmds;
303e844adb1SKashyap Desai 	case MPI3MR_HOSTTAG_BLK_TMS:
304e844adb1SKashyap Desai 		return &mrioc->host_tm_cmds;
305824a1566SKashyap Desai 	case MPI3MR_HOSTTAG_INVALID:
306824a1566SKashyap Desai 		if (def_reply && def_reply->function ==
307824a1566SKashyap Desai 		    MPI3_FUNCTION_EVENT_NOTIFICATION)
308824a1566SKashyap Desai 			mpi3mr_handle_events(mrioc, def_reply);
309824a1566SKashyap Desai 		return NULL;
310824a1566SKashyap Desai 	default:
311824a1566SKashyap Desai 		break;
312824a1566SKashyap Desai 	}
31313ef29eaSKashyap Desai 	if (host_tag >= MPI3MR_HOSTTAG_DEVRMCMD_MIN &&
31413ef29eaSKashyap Desai 	    host_tag <= MPI3MR_HOSTTAG_DEVRMCMD_MAX) {
31513ef29eaSKashyap Desai 		idx = host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
31613ef29eaSKashyap Desai 		return &mrioc->dev_rmhs_cmds[idx];
31713ef29eaSKashyap Desai 	}
318824a1566SKashyap Desai 
319c1af985dSSreekanth Reddy 	if (host_tag >= MPI3MR_HOSTTAG_EVTACKCMD_MIN &&
320c1af985dSSreekanth Reddy 	    host_tag <= MPI3MR_HOSTTAG_EVTACKCMD_MAX) {
321c1af985dSSreekanth Reddy 		idx = host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN;
322c1af985dSSreekanth Reddy 		return &mrioc->evtack_cmds[idx];
323c1af985dSSreekanth Reddy 	}
324c1af985dSSreekanth Reddy 
325824a1566SKashyap Desai 	return NULL;
326824a1566SKashyap Desai }
327824a1566SKashyap Desai 
328824a1566SKashyap Desai static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc,
329824a1566SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc, u64 *reply_dma)
330824a1566SKashyap Desai {
331824a1566SKashyap Desai 	u16 reply_desc_type, host_tag = 0;
332824a1566SKashyap Desai 	u16 ioc_status = MPI3_IOCSTATUS_SUCCESS;
333824a1566SKashyap Desai 	u32 ioc_loginfo = 0;
334824a1566SKashyap Desai 	struct mpi3_status_reply_descriptor *status_desc;
335824a1566SKashyap Desai 	struct mpi3_address_reply_descriptor *addr_desc;
336824a1566SKashyap Desai 	struct mpi3_success_reply_descriptor *success_desc;
337824a1566SKashyap Desai 	struct mpi3_default_reply *def_reply = NULL;
338824a1566SKashyap Desai 	struct mpi3mr_drv_cmd *cmdptr = NULL;
339824a1566SKashyap Desai 	struct mpi3_scsi_io_reply *scsi_reply;
340824a1566SKashyap Desai 	u8 *sense_buf = NULL;
341824a1566SKashyap Desai 
342824a1566SKashyap Desai 	*reply_dma = 0;
343824a1566SKashyap Desai 	reply_desc_type = le16_to_cpu(reply_desc->reply_flags) &
344824a1566SKashyap Desai 	    MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK;
345824a1566SKashyap Desai 	switch (reply_desc_type) {
346824a1566SKashyap Desai 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS:
347824a1566SKashyap Desai 		status_desc = (struct mpi3_status_reply_descriptor *)reply_desc;
348824a1566SKashyap Desai 		host_tag = le16_to_cpu(status_desc->host_tag);
349824a1566SKashyap Desai 		ioc_status = le16_to_cpu(status_desc->ioc_status);
350824a1566SKashyap Desai 		if (ioc_status &
351824a1566SKashyap Desai 		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
352824a1566SKashyap Desai 			ioc_loginfo = le32_to_cpu(status_desc->ioc_log_info);
353824a1566SKashyap Desai 		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
354824a1566SKashyap Desai 		break;
355824a1566SKashyap Desai 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY:
356824a1566SKashyap Desai 		addr_desc = (struct mpi3_address_reply_descriptor *)reply_desc;
357824a1566SKashyap Desai 		*reply_dma = le64_to_cpu(addr_desc->reply_frame_address);
358824a1566SKashyap Desai 		def_reply = mpi3mr_get_reply_virt_addr(mrioc, *reply_dma);
359824a1566SKashyap Desai 		if (!def_reply)
360824a1566SKashyap Desai 			goto out;
361824a1566SKashyap Desai 		host_tag = le16_to_cpu(def_reply->host_tag);
362824a1566SKashyap Desai 		ioc_status = le16_to_cpu(def_reply->ioc_status);
363824a1566SKashyap Desai 		if (ioc_status &
364824a1566SKashyap Desai 		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
365824a1566SKashyap Desai 			ioc_loginfo = le32_to_cpu(def_reply->ioc_log_info);
366824a1566SKashyap Desai 		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
367824a1566SKashyap Desai 		if (def_reply->function == MPI3_FUNCTION_SCSI_IO) {
368824a1566SKashyap Desai 			scsi_reply = (struct mpi3_scsi_io_reply *)def_reply;
369824a1566SKashyap Desai 			sense_buf = mpi3mr_get_sensebuf_virt_addr(mrioc,
370824a1566SKashyap Desai 			    le64_to_cpu(scsi_reply->sense_data_buffer_address));
371824a1566SKashyap Desai 		}
372824a1566SKashyap Desai 		break;
373824a1566SKashyap Desai 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS:
374824a1566SKashyap Desai 		success_desc = (struct mpi3_success_reply_descriptor *)reply_desc;
375824a1566SKashyap Desai 		host_tag = le16_to_cpu(success_desc->host_tag);
376824a1566SKashyap Desai 		break;
377824a1566SKashyap Desai 	default:
378824a1566SKashyap Desai 		break;
379824a1566SKashyap Desai 	}
380824a1566SKashyap Desai 
381824a1566SKashyap Desai 	cmdptr = mpi3mr_get_drv_cmd(mrioc, host_tag, def_reply);
382824a1566SKashyap Desai 	if (cmdptr) {
383824a1566SKashyap Desai 		if (cmdptr->state & MPI3MR_CMD_PENDING) {
384824a1566SKashyap Desai 			cmdptr->state |= MPI3MR_CMD_COMPLETE;
385824a1566SKashyap Desai 			cmdptr->ioc_loginfo = ioc_loginfo;
386824a1566SKashyap Desai 			cmdptr->ioc_status = ioc_status;
387824a1566SKashyap Desai 			cmdptr->state &= ~MPI3MR_CMD_PENDING;
388824a1566SKashyap Desai 			if (def_reply) {
389824a1566SKashyap Desai 				cmdptr->state |= MPI3MR_CMD_REPLY_VALID;
390824a1566SKashyap Desai 				memcpy((u8 *)cmdptr->reply, (u8 *)def_reply,
391c5758fc7SSreekanth Reddy 				    mrioc->reply_sz);
392824a1566SKashyap Desai 			}
393824a1566SKashyap Desai 			if (cmdptr->is_waiting) {
394824a1566SKashyap Desai 				complete(&cmdptr->done);
395824a1566SKashyap Desai 				cmdptr->is_waiting = 0;
396824a1566SKashyap Desai 			} else if (cmdptr->callback)
397824a1566SKashyap Desai 				cmdptr->callback(mrioc, cmdptr);
398824a1566SKashyap Desai 		}
399824a1566SKashyap Desai 	}
400824a1566SKashyap Desai out:
401824a1566SKashyap Desai 	if (sense_buf)
402824a1566SKashyap Desai 		mpi3mr_repost_sense_buf(mrioc,
403824a1566SKashyap Desai 		    le64_to_cpu(scsi_reply->sense_data_buffer_address));
404824a1566SKashyap Desai }
405824a1566SKashyap Desai 
406824a1566SKashyap Desai static int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc)
407824a1566SKashyap Desai {
408824a1566SKashyap Desai 	u32 exp_phase = mrioc->admin_reply_ephase;
409824a1566SKashyap Desai 	u32 admin_reply_ci = mrioc->admin_reply_ci;
410824a1566SKashyap Desai 	u32 num_admin_replies = 0;
411824a1566SKashyap Desai 	u64 reply_dma = 0;
412824a1566SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc;
413824a1566SKashyap Desai 
414824a1566SKashyap Desai 	reply_desc = (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base +
415824a1566SKashyap Desai 	    admin_reply_ci;
416824a1566SKashyap Desai 
417824a1566SKashyap Desai 	if ((le16_to_cpu(reply_desc->reply_flags) &
418824a1566SKashyap Desai 	    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
419824a1566SKashyap Desai 		return 0;
420824a1566SKashyap Desai 
421824a1566SKashyap Desai 	do {
422824a1566SKashyap Desai 		mrioc->admin_req_ci = le16_to_cpu(reply_desc->request_queue_ci);
423824a1566SKashyap Desai 		mpi3mr_process_admin_reply_desc(mrioc, reply_desc, &reply_dma);
424824a1566SKashyap Desai 		if (reply_dma)
425824a1566SKashyap Desai 			mpi3mr_repost_reply_buf(mrioc, reply_dma);
426824a1566SKashyap Desai 		num_admin_replies++;
427824a1566SKashyap Desai 		if (++admin_reply_ci == mrioc->num_admin_replies) {
428824a1566SKashyap Desai 			admin_reply_ci = 0;
429824a1566SKashyap Desai 			exp_phase ^= 1;
430824a1566SKashyap Desai 		}
431824a1566SKashyap Desai 		reply_desc =
432824a1566SKashyap Desai 		    (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base +
433824a1566SKashyap Desai 		    admin_reply_ci;
434824a1566SKashyap Desai 		if ((le16_to_cpu(reply_desc->reply_flags) &
435824a1566SKashyap Desai 		    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
436824a1566SKashyap Desai 			break;
437824a1566SKashyap Desai 	} while (1);
438824a1566SKashyap Desai 
439824a1566SKashyap Desai 	writel(admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci);
440824a1566SKashyap Desai 	mrioc->admin_reply_ci = admin_reply_ci;
441824a1566SKashyap Desai 	mrioc->admin_reply_ephase = exp_phase;
442824a1566SKashyap Desai 
443824a1566SKashyap Desai 	return num_admin_replies;
444824a1566SKashyap Desai }
445824a1566SKashyap Desai 
446023ab2a9SKashyap Desai /**
447023ab2a9SKashyap Desai  * mpi3mr_get_reply_desc - get reply descriptor frame corresponding to
448023ab2a9SKashyap Desai  *	queue's consumer index from operational reply descriptor queue.
449023ab2a9SKashyap Desai  * @op_reply_q: op_reply_qinfo object
450023ab2a9SKashyap Desai  * @reply_ci: operational reply descriptor's queue consumer index
451023ab2a9SKashyap Desai  *
452023ab2a9SKashyap Desai  * Returns reply descriptor frame address
453023ab2a9SKashyap Desai  */
454023ab2a9SKashyap Desai static inline struct mpi3_default_reply_descriptor *
455023ab2a9SKashyap Desai mpi3mr_get_reply_desc(struct op_reply_qinfo *op_reply_q, u32 reply_ci)
456023ab2a9SKashyap Desai {
457023ab2a9SKashyap Desai 	void *segment_base_addr;
458023ab2a9SKashyap Desai 	struct segments *segments = op_reply_q->q_segments;
459023ab2a9SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc = NULL;
460023ab2a9SKashyap Desai 
461023ab2a9SKashyap Desai 	segment_base_addr =
462023ab2a9SKashyap Desai 	    segments[reply_ci / op_reply_q->segment_qd].segment;
463023ab2a9SKashyap Desai 	reply_desc = (struct mpi3_default_reply_descriptor *)segment_base_addr +
464023ab2a9SKashyap Desai 	    (reply_ci % op_reply_q->segment_qd);
465023ab2a9SKashyap Desai 	return reply_desc;
466023ab2a9SKashyap Desai }
467023ab2a9SKashyap Desai 
468*afd3a579SSreekanth Reddy /**
469*afd3a579SSreekanth Reddy  * mpi3mr_process_op_reply_q - Operational reply queue handler
470*afd3a579SSreekanth Reddy  * @mrioc: Adapter instance reference
471*afd3a579SSreekanth Reddy  * @op_reply_q: Operational reply queue info
472*afd3a579SSreekanth Reddy  *
473*afd3a579SSreekanth Reddy  * Checks the specific operational reply queue and drains the
474*afd3a579SSreekanth Reddy  * reply queue entries until the queue is empty and process the
475*afd3a579SSreekanth Reddy  * individual reply descriptors.
476*afd3a579SSreekanth Reddy  *
477*afd3a579SSreekanth Reddy  * Return: 0 if queue is already processed,or number of reply
478*afd3a579SSreekanth Reddy  *	    descriptors processed.
479*afd3a579SSreekanth Reddy  */
480*afd3a579SSreekanth Reddy int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc,
481*afd3a579SSreekanth Reddy 	struct op_reply_qinfo *op_reply_q)
482023ab2a9SKashyap Desai {
483023ab2a9SKashyap Desai 	struct op_req_qinfo *op_req_q;
484023ab2a9SKashyap Desai 	u32 exp_phase;
485023ab2a9SKashyap Desai 	u32 reply_ci;
486023ab2a9SKashyap Desai 	u32 num_op_reply = 0;
487023ab2a9SKashyap Desai 	u64 reply_dma = 0;
488023ab2a9SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc;
489023ab2a9SKashyap Desai 	u16 req_q_idx = 0, reply_qidx;
490023ab2a9SKashyap Desai 
491023ab2a9SKashyap Desai 	reply_qidx = op_reply_q->qid - 1;
492023ab2a9SKashyap Desai 
493463429f8SKashyap Desai 	if (!atomic_add_unless(&op_reply_q->in_use, 1, 1))
494463429f8SKashyap Desai 		return 0;
495463429f8SKashyap Desai 
496023ab2a9SKashyap Desai 	exp_phase = op_reply_q->ephase;
497023ab2a9SKashyap Desai 	reply_ci = op_reply_q->ci;
498023ab2a9SKashyap Desai 
499023ab2a9SKashyap Desai 	reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci);
500023ab2a9SKashyap Desai 	if ((le16_to_cpu(reply_desc->reply_flags) &
501023ab2a9SKashyap Desai 	    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) {
502463429f8SKashyap Desai 		atomic_dec(&op_reply_q->in_use);
503023ab2a9SKashyap Desai 		return 0;
504023ab2a9SKashyap Desai 	}
505023ab2a9SKashyap Desai 
506023ab2a9SKashyap Desai 	do {
507023ab2a9SKashyap Desai 		req_q_idx = le16_to_cpu(reply_desc->request_queue_id) - 1;
508023ab2a9SKashyap Desai 		op_req_q = &mrioc->req_qinfo[req_q_idx];
509023ab2a9SKashyap Desai 
510023ab2a9SKashyap Desai 		WRITE_ONCE(op_req_q->ci, le16_to_cpu(reply_desc->request_queue_ci));
511023ab2a9SKashyap Desai 		mpi3mr_process_op_reply_desc(mrioc, reply_desc, &reply_dma,
512023ab2a9SKashyap Desai 		    reply_qidx);
513463429f8SKashyap Desai 		atomic_dec(&op_reply_q->pend_ios);
514023ab2a9SKashyap Desai 		if (reply_dma)
515023ab2a9SKashyap Desai 			mpi3mr_repost_reply_buf(mrioc, reply_dma);
516023ab2a9SKashyap Desai 		num_op_reply++;
517023ab2a9SKashyap Desai 
518023ab2a9SKashyap Desai 		if (++reply_ci == op_reply_q->num_replies) {
519023ab2a9SKashyap Desai 			reply_ci = 0;
520023ab2a9SKashyap Desai 			exp_phase ^= 1;
521023ab2a9SKashyap Desai 		}
522023ab2a9SKashyap Desai 
523023ab2a9SKashyap Desai 		reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci);
524023ab2a9SKashyap Desai 
525023ab2a9SKashyap Desai 		if ((le16_to_cpu(reply_desc->reply_flags) &
526023ab2a9SKashyap Desai 		    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
527023ab2a9SKashyap Desai 			break;
528463429f8SKashyap Desai 		/*
529463429f8SKashyap Desai 		 * Exit completion loop to avoid CPU lockup
530463429f8SKashyap Desai 		 * Ensure remaining completion happens from threaded ISR.
531463429f8SKashyap Desai 		 */
532463429f8SKashyap Desai 		if (num_op_reply > mrioc->max_host_ios) {
533*afd3a579SSreekanth Reddy 			op_reply_q->enable_irq_poll = true;
534463429f8SKashyap Desai 			break;
535463429f8SKashyap Desai 		}
536023ab2a9SKashyap Desai 
537023ab2a9SKashyap Desai 	} while (1);
538023ab2a9SKashyap Desai 
539023ab2a9SKashyap Desai 	writel(reply_ci,
540023ab2a9SKashyap Desai 	    &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].consumer_index);
541023ab2a9SKashyap Desai 	op_reply_q->ci = reply_ci;
542023ab2a9SKashyap Desai 	op_reply_q->ephase = exp_phase;
543023ab2a9SKashyap Desai 
544463429f8SKashyap Desai 	atomic_dec(&op_reply_q->in_use);
545023ab2a9SKashyap Desai 	return num_op_reply;
546023ab2a9SKashyap Desai }
547023ab2a9SKashyap Desai 
548*afd3a579SSreekanth Reddy /**
549*afd3a579SSreekanth Reddy  * mpi3mr_blk_mq_poll - Operational reply queue handler
550*afd3a579SSreekanth Reddy  * @shost: SCSI Host reference
551*afd3a579SSreekanth Reddy  * @queue_num: Request queue number (w.r.t OS it is hardware context number)
552*afd3a579SSreekanth Reddy  *
553*afd3a579SSreekanth Reddy  * Checks the specific operational reply queue and drains the
554*afd3a579SSreekanth Reddy  * reply queue entries until the queue is empty and process the
555*afd3a579SSreekanth Reddy  * individual reply descriptors.
556*afd3a579SSreekanth Reddy  *
557*afd3a579SSreekanth Reddy  * Return: 0 if queue is already processed,or number of reply
558*afd3a579SSreekanth Reddy  *	    descriptors processed.
559*afd3a579SSreekanth Reddy  */
560*afd3a579SSreekanth Reddy int mpi3mr_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
561*afd3a579SSreekanth Reddy {
562*afd3a579SSreekanth Reddy 	int num_entries = 0;
563*afd3a579SSreekanth Reddy 	struct mpi3mr_ioc *mrioc;
564*afd3a579SSreekanth Reddy 
565*afd3a579SSreekanth Reddy 	mrioc = (struct mpi3mr_ioc *)shost->hostdata;
566*afd3a579SSreekanth Reddy 
567*afd3a579SSreekanth Reddy 	if ((mrioc->reset_in_progress || mrioc->prepare_for_reset))
568*afd3a579SSreekanth Reddy 		return 0;
569*afd3a579SSreekanth Reddy 
570*afd3a579SSreekanth Reddy 	num_entries = mpi3mr_process_op_reply_q(mrioc,
571*afd3a579SSreekanth Reddy 			&mrioc->op_reply_qinfo[queue_num]);
572*afd3a579SSreekanth Reddy 
573*afd3a579SSreekanth Reddy 	return num_entries;
574*afd3a579SSreekanth Reddy }
575*afd3a579SSreekanth Reddy 
576824a1566SKashyap Desai static irqreturn_t mpi3mr_isr_primary(int irq, void *privdata)
577824a1566SKashyap Desai {
578824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info = privdata;
579824a1566SKashyap Desai 	struct mpi3mr_ioc *mrioc;
580824a1566SKashyap Desai 	u16 midx;
581463429f8SKashyap Desai 	u32 num_admin_replies = 0, num_op_reply = 0;
582824a1566SKashyap Desai 
583824a1566SKashyap Desai 	if (!intr_info)
584824a1566SKashyap Desai 		return IRQ_NONE;
585824a1566SKashyap Desai 
586824a1566SKashyap Desai 	mrioc = intr_info->mrioc;
587824a1566SKashyap Desai 
588824a1566SKashyap Desai 	if (!mrioc->intr_enabled)
589824a1566SKashyap Desai 		return IRQ_NONE;
590824a1566SKashyap Desai 
591824a1566SKashyap Desai 	midx = intr_info->msix_index;
592824a1566SKashyap Desai 
593824a1566SKashyap Desai 	if (!midx)
594824a1566SKashyap Desai 		num_admin_replies = mpi3mr_process_admin_reply_q(mrioc);
595463429f8SKashyap Desai 	if (intr_info->op_reply_q)
596*afd3a579SSreekanth Reddy 		num_op_reply = mpi3mr_process_op_reply_q(mrioc,
597*afd3a579SSreekanth Reddy 		    intr_info->op_reply_q);
598824a1566SKashyap Desai 
599463429f8SKashyap Desai 	if (num_admin_replies || num_op_reply)
600824a1566SKashyap Desai 		return IRQ_HANDLED;
601824a1566SKashyap Desai 	else
602824a1566SKashyap Desai 		return IRQ_NONE;
603824a1566SKashyap Desai }
604824a1566SKashyap Desai 
605824a1566SKashyap Desai static irqreturn_t mpi3mr_isr(int irq, void *privdata)
606824a1566SKashyap Desai {
607824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info = privdata;
608463429f8SKashyap Desai 	struct mpi3mr_ioc *mrioc;
609463429f8SKashyap Desai 	u16 midx;
610824a1566SKashyap Desai 	int ret;
611824a1566SKashyap Desai 
612824a1566SKashyap Desai 	if (!intr_info)
613824a1566SKashyap Desai 		return IRQ_NONE;
614824a1566SKashyap Desai 
615463429f8SKashyap Desai 	mrioc = intr_info->mrioc;
616463429f8SKashyap Desai 	midx = intr_info->msix_index;
617824a1566SKashyap Desai 	/* Call primary ISR routine */
618824a1566SKashyap Desai 	ret = mpi3mr_isr_primary(irq, privdata);
619824a1566SKashyap Desai 
620463429f8SKashyap Desai 	/*
621463429f8SKashyap Desai 	 * If more IOs are expected, schedule IRQ polling thread.
622463429f8SKashyap Desai 	 * Otherwise exit from ISR.
623463429f8SKashyap Desai 	 */
624463429f8SKashyap Desai 	if (!intr_info->op_reply_q)
625824a1566SKashyap Desai 		return ret;
626463429f8SKashyap Desai 
627463429f8SKashyap Desai 	if (!intr_info->op_reply_q->enable_irq_poll ||
628463429f8SKashyap Desai 	    !atomic_read(&intr_info->op_reply_q->pend_ios))
629463429f8SKashyap Desai 		return ret;
630463429f8SKashyap Desai 
631463429f8SKashyap Desai 	disable_irq_nosync(pci_irq_vector(mrioc->pdev, midx));
632463429f8SKashyap Desai 
633463429f8SKashyap Desai 	return IRQ_WAKE_THREAD;
634824a1566SKashyap Desai }
635824a1566SKashyap Desai 
636824a1566SKashyap Desai /**
637824a1566SKashyap Desai  * mpi3mr_isr_poll - Reply queue polling routine
638824a1566SKashyap Desai  * @irq: IRQ
639824a1566SKashyap Desai  * @privdata: Interrupt info
640824a1566SKashyap Desai  *
641824a1566SKashyap Desai  * poll for pending I/O completions in a loop until pending I/Os
642824a1566SKashyap Desai  * present or controller queue depth I/Os are processed.
643824a1566SKashyap Desai  *
644824a1566SKashyap Desai  * Return: IRQ_NONE or IRQ_HANDLED
645824a1566SKashyap Desai  */
646824a1566SKashyap Desai static irqreturn_t mpi3mr_isr_poll(int irq, void *privdata)
647824a1566SKashyap Desai {
648463429f8SKashyap Desai 	struct mpi3mr_intr_info *intr_info = privdata;
649463429f8SKashyap Desai 	struct mpi3mr_ioc *mrioc;
650463429f8SKashyap Desai 	u16 midx;
651463429f8SKashyap Desai 	u32 num_op_reply = 0;
652463429f8SKashyap Desai 
653463429f8SKashyap Desai 	if (!intr_info || !intr_info->op_reply_q)
654463429f8SKashyap Desai 		return IRQ_NONE;
655463429f8SKashyap Desai 
656463429f8SKashyap Desai 	mrioc = intr_info->mrioc;
657463429f8SKashyap Desai 	midx = intr_info->msix_index;
658463429f8SKashyap Desai 
659463429f8SKashyap Desai 	/* Poll for pending IOs completions */
660463429f8SKashyap Desai 	do {
661463429f8SKashyap Desai 		if (!mrioc->intr_enabled)
662463429f8SKashyap Desai 			break;
663463429f8SKashyap Desai 
664463429f8SKashyap Desai 		if (!midx)
665463429f8SKashyap Desai 			mpi3mr_process_admin_reply_q(mrioc);
666463429f8SKashyap Desai 		if (intr_info->op_reply_q)
667463429f8SKashyap Desai 			num_op_reply +=
668*afd3a579SSreekanth Reddy 			    mpi3mr_process_op_reply_q(mrioc,
669*afd3a579SSreekanth Reddy 				intr_info->op_reply_q);
670463429f8SKashyap Desai 
671*afd3a579SSreekanth Reddy 		usleep_range(MPI3MR_IRQ_POLL_SLEEP, 10 * MPI3MR_IRQ_POLL_SLEEP);
672463429f8SKashyap Desai 
673463429f8SKashyap Desai 	} while (atomic_read(&intr_info->op_reply_q->pend_ios) &&
674463429f8SKashyap Desai 	    (num_op_reply < mrioc->max_host_ios));
675463429f8SKashyap Desai 
676463429f8SKashyap Desai 	intr_info->op_reply_q->enable_irq_poll = false;
677463429f8SKashyap Desai 	enable_irq(pci_irq_vector(mrioc->pdev, midx));
678463429f8SKashyap Desai 
679824a1566SKashyap Desai 	return IRQ_HANDLED;
680824a1566SKashyap Desai }
681824a1566SKashyap Desai 
682824a1566SKashyap Desai /**
683824a1566SKashyap Desai  * mpi3mr_request_irq - Request IRQ and register ISR
684824a1566SKashyap Desai  * @mrioc: Adapter instance reference
685824a1566SKashyap Desai  * @index: IRQ vector index
686824a1566SKashyap Desai  *
687824a1566SKashyap Desai  * Request threaded ISR with primary ISR and secondary
688824a1566SKashyap Desai  *
689824a1566SKashyap Desai  * Return: 0 on success and non zero on failures.
690824a1566SKashyap Desai  */
691824a1566SKashyap Desai static inline int mpi3mr_request_irq(struct mpi3mr_ioc *mrioc, u16 index)
692824a1566SKashyap Desai {
693824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
694824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info = mrioc->intr_info + index;
695824a1566SKashyap Desai 	int retval = 0;
696824a1566SKashyap Desai 
697824a1566SKashyap Desai 	intr_info->mrioc = mrioc;
698824a1566SKashyap Desai 	intr_info->msix_index = index;
699824a1566SKashyap Desai 	intr_info->op_reply_q = NULL;
700824a1566SKashyap Desai 
701824a1566SKashyap Desai 	snprintf(intr_info->name, MPI3MR_NAME_LENGTH, "%s%d-msix%d",
702824a1566SKashyap Desai 	    mrioc->driver_name, mrioc->id, index);
703824a1566SKashyap Desai 
704824a1566SKashyap Desai 	retval = request_threaded_irq(pci_irq_vector(pdev, index), mpi3mr_isr,
705824a1566SKashyap Desai 	    mpi3mr_isr_poll, IRQF_SHARED, intr_info->name, intr_info);
706824a1566SKashyap Desai 	if (retval) {
707824a1566SKashyap Desai 		ioc_err(mrioc, "%s: Unable to allocate interrupt %d!\n",
708824a1566SKashyap Desai 		    intr_info->name, pci_irq_vector(pdev, index));
709824a1566SKashyap Desai 		return retval;
710824a1566SKashyap Desai 	}
711824a1566SKashyap Desai 
712824a1566SKashyap Desai 	return retval;
713824a1566SKashyap Desai }
714824a1566SKashyap Desai 
715*afd3a579SSreekanth Reddy static void mpi3mr_calc_poll_queues(struct mpi3mr_ioc *mrioc, u16 max_vectors)
716*afd3a579SSreekanth Reddy {
717*afd3a579SSreekanth Reddy 	if (!mrioc->requested_poll_qcount)
718*afd3a579SSreekanth Reddy 		return;
719*afd3a579SSreekanth Reddy 
720*afd3a579SSreekanth Reddy 	/* Reserved for Admin and Default Queue */
721*afd3a579SSreekanth Reddy 	if (max_vectors > 2 &&
722*afd3a579SSreekanth Reddy 		(mrioc->requested_poll_qcount < max_vectors - 2)) {
723*afd3a579SSreekanth Reddy 		ioc_info(mrioc,
724*afd3a579SSreekanth Reddy 		    "enabled polled queues (%d) msix (%d)\n",
725*afd3a579SSreekanth Reddy 		    mrioc->requested_poll_qcount, max_vectors);
726*afd3a579SSreekanth Reddy 	} else {
727*afd3a579SSreekanth Reddy 		ioc_info(mrioc,
728*afd3a579SSreekanth Reddy 		    "disabled polled queues (%d) msix (%d) because of no resources for default queue\n",
729*afd3a579SSreekanth Reddy 		    mrioc->requested_poll_qcount, max_vectors);
730*afd3a579SSreekanth Reddy 		mrioc->requested_poll_qcount = 0;
731*afd3a579SSreekanth Reddy 	}
732*afd3a579SSreekanth Reddy }
733*afd3a579SSreekanth Reddy 
734824a1566SKashyap Desai /**
735824a1566SKashyap Desai  * mpi3mr_setup_isr - Setup ISR for the controller
736824a1566SKashyap Desai  * @mrioc: Adapter instance reference
737824a1566SKashyap Desai  * @setup_one: Request one IRQ or more
738824a1566SKashyap Desai  *
739824a1566SKashyap Desai  * Allocate IRQ vectors and call mpi3mr_request_irq to setup ISR
740824a1566SKashyap Desai  *
741824a1566SKashyap Desai  * Return: 0 on success and non zero on failures.
742824a1566SKashyap Desai  */
743824a1566SKashyap Desai static int mpi3mr_setup_isr(struct mpi3mr_ioc *mrioc, u8 setup_one)
744824a1566SKashyap Desai {
745824a1566SKashyap Desai 	unsigned int irq_flags = PCI_IRQ_MSIX;
746*afd3a579SSreekanth Reddy 	int max_vectors, min_vec;
7472938beddSDan Carpenter 	int retval;
7482938beddSDan Carpenter 	int i;
749*afd3a579SSreekanth Reddy 	struct irq_affinity desc = { .pre_vectors =  1, .post_vectors = 1 };
750824a1566SKashyap Desai 
751fe6db615SSreekanth Reddy 	if (mrioc->is_intr_info_set)
752fe6db615SSreekanth Reddy 		return 0;
753fe6db615SSreekanth Reddy 
754824a1566SKashyap Desai 	mpi3mr_cleanup_isr(mrioc);
755824a1566SKashyap Desai 
756*afd3a579SSreekanth Reddy 	if (setup_one || reset_devices) {
757824a1566SKashyap Desai 		max_vectors = 1;
758*afd3a579SSreekanth Reddy 		retval = pci_alloc_irq_vectors(mrioc->pdev,
759*afd3a579SSreekanth Reddy 		    1, max_vectors, irq_flags);
760*afd3a579SSreekanth Reddy 		if (retval < 0) {
761*afd3a579SSreekanth Reddy 			ioc_err(mrioc, "cannot allocate irq vectors, ret %d\n",
762*afd3a579SSreekanth Reddy 			    retval);
763*afd3a579SSreekanth Reddy 			goto out_failed;
764*afd3a579SSreekanth Reddy 		}
765*afd3a579SSreekanth Reddy 	} else {
766824a1566SKashyap Desai 		max_vectors =
767*afd3a579SSreekanth Reddy 		    min_t(int, mrioc->cpu_count + 1 +
768*afd3a579SSreekanth Reddy 			mrioc->requested_poll_qcount, mrioc->msix_count);
769*afd3a579SSreekanth Reddy 
770*afd3a579SSreekanth Reddy 		mpi3mr_calc_poll_queues(mrioc, max_vectors);
771824a1566SKashyap Desai 
772824a1566SKashyap Desai 		ioc_info(mrioc,
773824a1566SKashyap Desai 		    "MSI-X vectors supported: %d, no of cores: %d,",
774824a1566SKashyap Desai 		    mrioc->msix_count, mrioc->cpu_count);
775824a1566SKashyap Desai 		ioc_info(mrioc,
776*afd3a579SSreekanth Reddy 		    "MSI-x vectors requested: %d poll_queues %d\n",
777*afd3a579SSreekanth Reddy 		    max_vectors, mrioc->requested_poll_qcount);
778824a1566SKashyap Desai 
779*afd3a579SSreekanth Reddy 		desc.post_vectors = mrioc->requested_poll_qcount;
780*afd3a579SSreekanth Reddy 		min_vec = desc.pre_vectors + desc.post_vectors;
781824a1566SKashyap Desai 		irq_flags |= PCI_IRQ_AFFINITY | PCI_IRQ_ALL_TYPES;
782824a1566SKashyap Desai 
7832938beddSDan Carpenter 		retval = pci_alloc_irq_vectors_affinity(mrioc->pdev,
784*afd3a579SSreekanth Reddy 			min_vec, max_vectors, irq_flags, &desc);
785*afd3a579SSreekanth Reddy 
7862938beddSDan Carpenter 		if (retval < 0) {
787*afd3a579SSreekanth Reddy 			ioc_err(mrioc, "cannot allocate irq vectors, ret %d\n",
788*afd3a579SSreekanth Reddy 			    retval);
789824a1566SKashyap Desai 			goto out_failed;
790824a1566SKashyap Desai 		}
791*afd3a579SSreekanth Reddy 
792*afd3a579SSreekanth Reddy 
793c9566231SKashyap Desai 		/*
794c9566231SKashyap Desai 		 * If only one MSI-x is allocated, then MSI-x 0 will be shared
795c9566231SKashyap Desai 		 * between Admin queue and operational queue
796c9566231SKashyap Desai 		 */
797*afd3a579SSreekanth Reddy 		if (retval == min_vec)
798c9566231SKashyap Desai 			mrioc->op_reply_q_offset = 0;
799*afd3a579SSreekanth Reddy 		else if (retval != (max_vectors)) {
800*afd3a579SSreekanth Reddy 			ioc_info(mrioc,
801*afd3a579SSreekanth Reddy 			    "allocated vectors (%d) are less than configured (%d)\n",
802*afd3a579SSreekanth Reddy 			    retval, max_vectors);
803*afd3a579SSreekanth Reddy 		}
804824a1566SKashyap Desai 
8052938beddSDan Carpenter 		max_vectors = retval;
806*afd3a579SSreekanth Reddy 		mrioc->op_reply_q_offset = (max_vectors > 1) ? 1 : 0;
807*afd3a579SSreekanth Reddy 
808*afd3a579SSreekanth Reddy 		mpi3mr_calc_poll_queues(mrioc, max_vectors);
809*afd3a579SSreekanth Reddy 
810824a1566SKashyap Desai 	}
811*afd3a579SSreekanth Reddy 
812824a1566SKashyap Desai 	mrioc->intr_info = kzalloc(sizeof(struct mpi3mr_intr_info) * max_vectors,
813824a1566SKashyap Desai 	    GFP_KERNEL);
814824a1566SKashyap Desai 	if (!mrioc->intr_info) {
8152938beddSDan Carpenter 		retval = -ENOMEM;
816824a1566SKashyap Desai 		pci_free_irq_vectors(mrioc->pdev);
817824a1566SKashyap Desai 		goto out_failed;
818824a1566SKashyap Desai 	}
819824a1566SKashyap Desai 	for (i = 0; i < max_vectors; i++) {
820824a1566SKashyap Desai 		retval = mpi3mr_request_irq(mrioc, i);
821824a1566SKashyap Desai 		if (retval) {
822824a1566SKashyap Desai 			mrioc->intr_info_count = i;
823824a1566SKashyap Desai 			goto out_failed;
824824a1566SKashyap Desai 		}
825824a1566SKashyap Desai 	}
826fe6db615SSreekanth Reddy 	if (reset_devices || !setup_one)
827fe6db615SSreekanth Reddy 		mrioc->is_intr_info_set = true;
828824a1566SKashyap Desai 	mrioc->intr_info_count = max_vectors;
829824a1566SKashyap Desai 	mpi3mr_ioc_enable_intr(mrioc);
8302938beddSDan Carpenter 	return 0;
8312938beddSDan Carpenter 
832824a1566SKashyap Desai out_failed:
833824a1566SKashyap Desai 	mpi3mr_cleanup_isr(mrioc);
834824a1566SKashyap Desai 
835824a1566SKashyap Desai 	return retval;
836824a1566SKashyap Desai }
837824a1566SKashyap Desai 
838824a1566SKashyap Desai static const struct {
839824a1566SKashyap Desai 	enum mpi3mr_iocstate value;
840824a1566SKashyap Desai 	char *name;
841824a1566SKashyap Desai } mrioc_states[] = {
842824a1566SKashyap Desai 	{ MRIOC_STATE_READY, "ready" },
843824a1566SKashyap Desai 	{ MRIOC_STATE_FAULT, "fault" },
844824a1566SKashyap Desai 	{ MRIOC_STATE_RESET, "reset" },
845824a1566SKashyap Desai 	{ MRIOC_STATE_BECOMING_READY, "becoming ready" },
846824a1566SKashyap Desai 	{ MRIOC_STATE_RESET_REQUESTED, "reset requested" },
847824a1566SKashyap Desai 	{ MRIOC_STATE_UNRECOVERABLE, "unrecoverable error" },
848824a1566SKashyap Desai };
849824a1566SKashyap Desai 
850824a1566SKashyap Desai static const char *mpi3mr_iocstate_name(enum mpi3mr_iocstate mrioc_state)
851824a1566SKashyap Desai {
852824a1566SKashyap Desai 	int i;
853824a1566SKashyap Desai 	char *name = NULL;
854824a1566SKashyap Desai 
855824a1566SKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mrioc_states); i++) {
856824a1566SKashyap Desai 		if (mrioc_states[i].value == mrioc_state) {
857824a1566SKashyap Desai 			name = mrioc_states[i].name;
858824a1566SKashyap Desai 			break;
859824a1566SKashyap Desai 		}
860824a1566SKashyap Desai 	}
861824a1566SKashyap Desai 	return name;
862824a1566SKashyap Desai }
863824a1566SKashyap Desai 
864f061178eSKashyap Desai /* Reset reason to name mapper structure*/
865f061178eSKashyap Desai static const struct {
866f061178eSKashyap Desai 	enum mpi3mr_reset_reason value;
867f061178eSKashyap Desai 	char *name;
868f061178eSKashyap Desai } mpi3mr_reset_reason_codes[] = {
869f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_BRINGUP, "timeout in bringup" },
870f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_FAULT_WATCH, "fault" },
871f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_IOCTL, "application invocation" },
872f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_EH_HOS, "error handling" },
873f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_TM_TIMEOUT, "TM timeout" },
874f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_IOCTL_TIMEOUT, "IOCTL timeout" },
875f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_MUR_FAILURE, "MUR failure" },
876f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_CTLR_CLEANUP, "timeout in controller cleanup" },
877f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_CIACTIV_FAULT, "component image activation fault" },
878f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_PE_TIMEOUT, "port enable timeout" },
879f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_TSU_TIMEOUT, "time stamp update timeout" },
880f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_DELREQQ_TIMEOUT, "delete request queue timeout" },
881f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_DELREPQ_TIMEOUT, "delete reply queue timeout" },
882f061178eSKashyap Desai 	{
883f061178eSKashyap Desai 		MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT,
884f061178eSKashyap Desai 		"create request queue timeout"
885f061178eSKashyap Desai 	},
886f061178eSKashyap Desai 	{
887f061178eSKashyap Desai 		MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT,
888f061178eSKashyap Desai 		"create reply queue timeout"
889f061178eSKashyap Desai 	},
890f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT, "IOC facts timeout" },
891f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_IOCINIT_TIMEOUT, "IOC init timeout" },
892f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT, "event notify timeout" },
893f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_EVTACK_TIMEOUT, "event acknowledgment timeout" },
894f061178eSKashyap Desai 	{
895f061178eSKashyap Desai 		MPI3MR_RESET_FROM_CIACTVRST_TIMER,
896f061178eSKashyap Desai 		"component image activation timeout"
897f061178eSKashyap Desai 	},
898f061178eSKashyap Desai 	{
899f061178eSKashyap Desai 		MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT,
900f061178eSKashyap Desai 		"get package version timeout"
901f061178eSKashyap Desai 	},
902f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_SYSFS, "sysfs invocation" },
903f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_SYSFS_TIMEOUT, "sysfs TM timeout" },
904b64845a7SSreekanth Reddy 	{ MPI3MR_RESET_FROM_FIRMWARE, "firmware asynchronus reset" },
905f061178eSKashyap Desai };
906f061178eSKashyap Desai 
907f061178eSKashyap Desai /**
908f061178eSKashyap Desai  * mpi3mr_reset_rc_name - get reset reason code name
909f061178eSKashyap Desai  * @reason_code: reset reason code value
910f061178eSKashyap Desai  *
911f061178eSKashyap Desai  * Map reset reason to an NULL terminated ASCII string
912f061178eSKashyap Desai  *
913f061178eSKashyap Desai  * Return: name corresponding to reset reason value or NULL.
914f061178eSKashyap Desai  */
915f061178eSKashyap Desai static const char *mpi3mr_reset_rc_name(enum mpi3mr_reset_reason reason_code)
916f061178eSKashyap Desai {
917f061178eSKashyap Desai 	int i;
918f061178eSKashyap Desai 	char *name = NULL;
919f061178eSKashyap Desai 
920f061178eSKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mpi3mr_reset_reason_codes); i++) {
921f061178eSKashyap Desai 		if (mpi3mr_reset_reason_codes[i].value == reason_code) {
922f061178eSKashyap Desai 			name = mpi3mr_reset_reason_codes[i].name;
923f061178eSKashyap Desai 			break;
924f061178eSKashyap Desai 		}
925f061178eSKashyap Desai 	}
926f061178eSKashyap Desai 	return name;
927f061178eSKashyap Desai }
928f061178eSKashyap Desai 
929f061178eSKashyap Desai /* Reset type to name mapper structure*/
930f061178eSKashyap Desai static const struct {
931f061178eSKashyap Desai 	u16 reset_type;
932f061178eSKashyap Desai 	char *name;
933f061178eSKashyap Desai } mpi3mr_reset_types[] = {
934f061178eSKashyap Desai 	{ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, "soft" },
935f061178eSKashyap Desai 	{ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, "diag fault" },
936f061178eSKashyap Desai };
937f061178eSKashyap Desai 
938f061178eSKashyap Desai /**
939f061178eSKashyap Desai  * mpi3mr_reset_type_name - get reset type name
940f061178eSKashyap Desai  * @reset_type: reset type value
941f061178eSKashyap Desai  *
942f061178eSKashyap Desai  * Map reset type to an NULL terminated ASCII string
943f061178eSKashyap Desai  *
944f061178eSKashyap Desai  * Return: name corresponding to reset type value or NULL.
945f061178eSKashyap Desai  */
946f061178eSKashyap Desai static const char *mpi3mr_reset_type_name(u16 reset_type)
947f061178eSKashyap Desai {
948f061178eSKashyap Desai 	int i;
949f061178eSKashyap Desai 	char *name = NULL;
950f061178eSKashyap Desai 
951f061178eSKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mpi3mr_reset_types); i++) {
952f061178eSKashyap Desai 		if (mpi3mr_reset_types[i].reset_type == reset_type) {
953f061178eSKashyap Desai 			name = mpi3mr_reset_types[i].name;
954f061178eSKashyap Desai 			break;
955f061178eSKashyap Desai 		}
956f061178eSKashyap Desai 	}
957f061178eSKashyap Desai 	return name;
958f061178eSKashyap Desai }
959f061178eSKashyap Desai 
960824a1566SKashyap Desai /**
961824a1566SKashyap Desai  * mpi3mr_print_fault_info - Display fault information
962824a1566SKashyap Desai  * @mrioc: Adapter instance reference
963824a1566SKashyap Desai  *
964824a1566SKashyap Desai  * Display the controller fault information if there is a
965824a1566SKashyap Desai  * controller fault.
966824a1566SKashyap Desai  *
967824a1566SKashyap Desai  * Return: Nothing.
968824a1566SKashyap Desai  */
969b64845a7SSreekanth Reddy void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc)
970824a1566SKashyap Desai {
971824a1566SKashyap Desai 	u32 ioc_status, code, code1, code2, code3;
972824a1566SKashyap Desai 
973824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
974824a1566SKashyap Desai 
975824a1566SKashyap Desai 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) {
976824a1566SKashyap Desai 		code = readl(&mrioc->sysif_regs->fault);
977824a1566SKashyap Desai 		code1 = readl(&mrioc->sysif_regs->fault_info[0]);
978824a1566SKashyap Desai 		code2 = readl(&mrioc->sysif_regs->fault_info[1]);
979824a1566SKashyap Desai 		code3 = readl(&mrioc->sysif_regs->fault_info[2]);
980824a1566SKashyap Desai 
981824a1566SKashyap Desai 		ioc_info(mrioc,
982824a1566SKashyap Desai 		    "fault code(0x%08X): Additional code: (0x%08X:0x%08X:0x%08X)\n",
983824a1566SKashyap Desai 		    code, code1, code2, code3);
984824a1566SKashyap Desai 	}
985824a1566SKashyap Desai }
986824a1566SKashyap Desai 
987824a1566SKashyap Desai /**
988824a1566SKashyap Desai  * mpi3mr_get_iocstate - Get IOC State
989824a1566SKashyap Desai  * @mrioc: Adapter instance reference
990824a1566SKashyap Desai  *
991824a1566SKashyap Desai  * Return a proper IOC state enum based on the IOC status and
992824a1566SKashyap Desai  * IOC configuration and unrcoverable state of the controller.
993824a1566SKashyap Desai  *
994824a1566SKashyap Desai  * Return: Current IOC state.
995824a1566SKashyap Desai  */
996824a1566SKashyap Desai enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc)
997824a1566SKashyap Desai {
998824a1566SKashyap Desai 	u32 ioc_status, ioc_config;
999824a1566SKashyap Desai 	u8 ready, enabled;
1000824a1566SKashyap Desai 
1001824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
1002824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
1003824a1566SKashyap Desai 
1004824a1566SKashyap Desai 	if (mrioc->unrecoverable)
1005824a1566SKashyap Desai 		return MRIOC_STATE_UNRECOVERABLE;
1006824a1566SKashyap Desai 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)
1007824a1566SKashyap Desai 		return MRIOC_STATE_FAULT;
1008824a1566SKashyap Desai 
1009824a1566SKashyap Desai 	ready = (ioc_status & MPI3_SYSIF_IOC_STATUS_READY);
1010824a1566SKashyap Desai 	enabled = (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC);
1011824a1566SKashyap Desai 
1012824a1566SKashyap Desai 	if (ready && enabled)
1013824a1566SKashyap Desai 		return MRIOC_STATE_READY;
1014824a1566SKashyap Desai 	if ((!ready) && (!enabled))
1015824a1566SKashyap Desai 		return MRIOC_STATE_RESET;
1016824a1566SKashyap Desai 	if ((!ready) && (enabled))
1017824a1566SKashyap Desai 		return MRIOC_STATE_BECOMING_READY;
1018824a1566SKashyap Desai 
1019824a1566SKashyap Desai 	return MRIOC_STATE_RESET_REQUESTED;
1020824a1566SKashyap Desai }
1021824a1566SKashyap Desai 
1022824a1566SKashyap Desai /**
1023824a1566SKashyap Desai  * mpi3mr_clear_reset_history - clear reset history
1024824a1566SKashyap Desai  * @mrioc: Adapter instance reference
1025824a1566SKashyap Desai  *
1026824a1566SKashyap Desai  * Write the reset history bit in IOC status to clear the bit,
1027824a1566SKashyap Desai  * if it is already set.
1028824a1566SKashyap Desai  *
1029824a1566SKashyap Desai  * Return: Nothing.
1030824a1566SKashyap Desai  */
1031824a1566SKashyap Desai static inline void mpi3mr_clear_reset_history(struct mpi3mr_ioc *mrioc)
1032824a1566SKashyap Desai {
1033824a1566SKashyap Desai 	u32 ioc_status;
1034824a1566SKashyap Desai 
1035824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
1036824a1566SKashyap Desai 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)
1037824a1566SKashyap Desai 		writel(ioc_status, &mrioc->sysif_regs->ioc_status);
1038824a1566SKashyap Desai }
1039824a1566SKashyap Desai 
1040824a1566SKashyap Desai /**
1041824a1566SKashyap Desai  * mpi3mr_issue_and_process_mur - Message unit Reset handler
1042824a1566SKashyap Desai  * @mrioc: Adapter instance reference
1043824a1566SKashyap Desai  * @reset_reason: Reset reason code
1044824a1566SKashyap Desai  *
1045824a1566SKashyap Desai  * Issue Message unit Reset to the controller and wait for it to
1046824a1566SKashyap Desai  * be complete.
1047824a1566SKashyap Desai  *
1048824a1566SKashyap Desai  * Return: 0 on success, -1 on failure.
1049824a1566SKashyap Desai  */
1050824a1566SKashyap Desai static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc,
1051824a1566SKashyap Desai 	u32 reset_reason)
1052824a1566SKashyap Desai {
1053824a1566SKashyap Desai 	u32 ioc_config, timeout, ioc_status;
1054824a1566SKashyap Desai 	int retval = -1;
1055824a1566SKashyap Desai 
1056824a1566SKashyap Desai 	ioc_info(mrioc, "Issuing Message unit Reset(MUR)\n");
1057824a1566SKashyap Desai 	if (mrioc->unrecoverable) {
1058824a1566SKashyap Desai 		ioc_info(mrioc, "IOC is unrecoverable MUR not issued\n");
1059824a1566SKashyap Desai 		return retval;
1060824a1566SKashyap Desai 	}
1061824a1566SKashyap Desai 	mpi3mr_clear_reset_history(mrioc);
1062824a1566SKashyap Desai 	writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]);
1063824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
1064824a1566SKashyap Desai 	ioc_config &= ~MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
1065824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
1066824a1566SKashyap Desai 
1067b64845a7SSreekanth Reddy 	timeout = MPI3MR_RESET_ACK_TIMEOUT * 10;
1068824a1566SKashyap Desai 	do {
1069824a1566SKashyap Desai 		ioc_status = readl(&mrioc->sysif_regs->ioc_status);
1070824a1566SKashyap Desai 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)) {
1071824a1566SKashyap Desai 			mpi3mr_clear_reset_history(mrioc);
1072824a1566SKashyap Desai 			break;
1073824a1566SKashyap Desai 		}
1074b64845a7SSreekanth Reddy 		if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) {
1075b64845a7SSreekanth Reddy 			mpi3mr_print_fault_info(mrioc);
1076b64845a7SSreekanth Reddy 			break;
1077824a1566SKashyap Desai 		}
1078824a1566SKashyap Desai 		msleep(100);
1079824a1566SKashyap Desai 	} while (--timeout);
1080824a1566SKashyap Desai 
1081824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
1082b64845a7SSreekanth Reddy 	if (timeout && !((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) ||
1083b64845a7SSreekanth Reddy 	      (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) ||
1084b64845a7SSreekanth Reddy 	      (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC)))
1085b64845a7SSreekanth Reddy 		retval = 0;
1086824a1566SKashyap Desai 
1087824a1566SKashyap Desai 	ioc_info(mrioc, "Base IOC Sts/Config after %s MUR is (0x%x)/(0x%x)\n",
1088824a1566SKashyap Desai 	    (!retval) ? "successful" : "failed", ioc_status, ioc_config);
1089824a1566SKashyap Desai 	return retval;
1090824a1566SKashyap Desai }
1091824a1566SKashyap Desai 
1092824a1566SKashyap Desai /**
1093c5758fc7SSreekanth Reddy  * mpi3mr_revalidate_factsdata - validate IOCFacts parameters
1094c5758fc7SSreekanth Reddy  * during reset/resume
1095c5758fc7SSreekanth Reddy  * @mrioc: Adapter instance reference
1096c5758fc7SSreekanth Reddy  *
1097c5758fc7SSreekanth Reddy  * Return zero if the new IOCFacts parameters value is compatible with
1098c5758fc7SSreekanth Reddy  * older values else return -EPERM
1099c5758fc7SSreekanth Reddy  */
1100c5758fc7SSreekanth Reddy static int
1101c5758fc7SSreekanth Reddy mpi3mr_revalidate_factsdata(struct mpi3mr_ioc *mrioc)
1102c5758fc7SSreekanth Reddy {
1103c5758fc7SSreekanth Reddy 	u16 dev_handle_bitmap_sz;
1104c5758fc7SSreekanth Reddy 	void *removepend_bitmap;
1105c5758fc7SSreekanth Reddy 
1106c5758fc7SSreekanth Reddy 	if (mrioc->facts.reply_sz > mrioc->reply_sz) {
1107c5758fc7SSreekanth Reddy 		ioc_err(mrioc,
1108c5758fc7SSreekanth Reddy 		    "cannot increase reply size from %d to %d\n",
1109c5758fc7SSreekanth Reddy 		    mrioc->reply_sz, mrioc->facts.reply_sz);
1110c5758fc7SSreekanth Reddy 		return -EPERM;
1111c5758fc7SSreekanth Reddy 	}
1112c5758fc7SSreekanth Reddy 
1113c5758fc7SSreekanth Reddy 	if (mrioc->facts.max_op_reply_q < mrioc->num_op_reply_q) {
1114c5758fc7SSreekanth Reddy 		ioc_err(mrioc,
1115c5758fc7SSreekanth Reddy 		    "cannot reduce number of operational reply queues from %d to %d\n",
1116c5758fc7SSreekanth Reddy 		    mrioc->num_op_reply_q,
1117c5758fc7SSreekanth Reddy 		    mrioc->facts.max_op_reply_q);
1118c5758fc7SSreekanth Reddy 		return -EPERM;
1119c5758fc7SSreekanth Reddy 	}
1120c5758fc7SSreekanth Reddy 
1121c5758fc7SSreekanth Reddy 	if (mrioc->facts.max_op_req_q < mrioc->num_op_req_q) {
1122c5758fc7SSreekanth Reddy 		ioc_err(mrioc,
1123c5758fc7SSreekanth Reddy 		    "cannot reduce number of operational request queues from %d to %d\n",
1124c5758fc7SSreekanth Reddy 		    mrioc->num_op_req_q, mrioc->facts.max_op_req_q);
1125c5758fc7SSreekanth Reddy 		return -EPERM;
1126c5758fc7SSreekanth Reddy 	}
1127c5758fc7SSreekanth Reddy 
1128c5758fc7SSreekanth Reddy 	dev_handle_bitmap_sz = mrioc->facts.max_devhandle / 8;
1129c5758fc7SSreekanth Reddy 	if (mrioc->facts.max_devhandle % 8)
1130c5758fc7SSreekanth Reddy 		dev_handle_bitmap_sz++;
1131c5758fc7SSreekanth Reddy 	if (dev_handle_bitmap_sz > mrioc->dev_handle_bitmap_sz) {
1132c5758fc7SSreekanth Reddy 		removepend_bitmap = krealloc(mrioc->removepend_bitmap,
1133c5758fc7SSreekanth Reddy 		    dev_handle_bitmap_sz, GFP_KERNEL);
1134c5758fc7SSreekanth Reddy 		if (!removepend_bitmap) {
1135c5758fc7SSreekanth Reddy 			ioc_err(mrioc,
1136c5758fc7SSreekanth Reddy 			    "failed to increase removepend_bitmap sz from: %d to %d\n",
1137c5758fc7SSreekanth Reddy 			    mrioc->dev_handle_bitmap_sz, dev_handle_bitmap_sz);
1138c5758fc7SSreekanth Reddy 			return -EPERM;
1139c5758fc7SSreekanth Reddy 		}
1140c5758fc7SSreekanth Reddy 		memset(removepend_bitmap + mrioc->dev_handle_bitmap_sz, 0,
1141c5758fc7SSreekanth Reddy 		    dev_handle_bitmap_sz - mrioc->dev_handle_bitmap_sz);
1142c5758fc7SSreekanth Reddy 		mrioc->removepend_bitmap = removepend_bitmap;
1143c5758fc7SSreekanth Reddy 		ioc_info(mrioc,
1144c5758fc7SSreekanth Reddy 		    "increased dev_handle_bitmap_sz from %d to %d\n",
1145c5758fc7SSreekanth Reddy 		    mrioc->dev_handle_bitmap_sz, dev_handle_bitmap_sz);
1146c5758fc7SSreekanth Reddy 		mrioc->dev_handle_bitmap_sz = dev_handle_bitmap_sz;
1147c5758fc7SSreekanth Reddy 	}
1148c5758fc7SSreekanth Reddy 
1149c5758fc7SSreekanth Reddy 	return 0;
1150c5758fc7SSreekanth Reddy }
1151c5758fc7SSreekanth Reddy 
1152c5758fc7SSreekanth Reddy /**
1153824a1566SKashyap Desai  * mpi3mr_bring_ioc_ready - Bring controller to ready state
1154824a1566SKashyap Desai  * @mrioc: Adapter instance reference
1155824a1566SKashyap Desai  *
1156824a1566SKashyap Desai  * Set Enable IOC bit in IOC configuration register and wait for
1157824a1566SKashyap Desai  * the controller to become ready.
1158824a1566SKashyap Desai  *
115959bd9cfeSSreekanth Reddy  * Return: 0 on success, appropriate error on failure.
1160824a1566SKashyap Desai  */
1161824a1566SKashyap Desai static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc)
1162824a1566SKashyap Desai {
116359bd9cfeSSreekanth Reddy 	u32 ioc_config, ioc_status, timeout;
116459bd9cfeSSreekanth Reddy 	int retval = 0;
116559bd9cfeSSreekanth Reddy 	enum mpi3mr_iocstate ioc_state;
116659bd9cfeSSreekanth Reddy 	u64 base_info;
1167824a1566SKashyap Desai 
116859bd9cfeSSreekanth Reddy 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
116959bd9cfeSSreekanth Reddy 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
117059bd9cfeSSreekanth Reddy 	base_info = lo_hi_readq(&mrioc->sysif_regs->ioc_information);
117159bd9cfeSSreekanth Reddy 	ioc_info(mrioc, "ioc_status(0x%08x), ioc_config(0x%08x), ioc_info(0x%016llx) at the bringup\n",
117259bd9cfeSSreekanth Reddy 	    ioc_status, ioc_config, base_info);
117359bd9cfeSSreekanth Reddy 
117459bd9cfeSSreekanth Reddy 	/*The timeout value is in 2sec unit, changing it to seconds*/
117559bd9cfeSSreekanth Reddy 	mrioc->ready_timeout =
117659bd9cfeSSreekanth Reddy 	    ((base_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >>
117759bd9cfeSSreekanth Reddy 	    MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT) * 2;
117859bd9cfeSSreekanth Reddy 
117959bd9cfeSSreekanth Reddy 	ioc_info(mrioc, "ready timeout: %d seconds\n", mrioc->ready_timeout);
118059bd9cfeSSreekanth Reddy 
118159bd9cfeSSreekanth Reddy 	ioc_state = mpi3mr_get_iocstate(mrioc);
118259bd9cfeSSreekanth Reddy 	ioc_info(mrioc, "controller is in %s state during detection\n",
118359bd9cfeSSreekanth Reddy 	    mpi3mr_iocstate_name(ioc_state));
118459bd9cfeSSreekanth Reddy 
118559bd9cfeSSreekanth Reddy 	if (ioc_state == MRIOC_STATE_BECOMING_READY ||
118659bd9cfeSSreekanth Reddy 	    ioc_state == MRIOC_STATE_RESET_REQUESTED) {
118759bd9cfeSSreekanth Reddy 		timeout = mrioc->ready_timeout * 10;
118859bd9cfeSSreekanth Reddy 		do {
118959bd9cfeSSreekanth Reddy 			msleep(100);
119059bd9cfeSSreekanth Reddy 		} while (--timeout);
119159bd9cfeSSreekanth Reddy 
119259bd9cfeSSreekanth Reddy 		ioc_state = mpi3mr_get_iocstate(mrioc);
119359bd9cfeSSreekanth Reddy 		ioc_info(mrioc,
119459bd9cfeSSreekanth Reddy 		    "controller is in %s state after waiting to reset\n",
119559bd9cfeSSreekanth Reddy 		    mpi3mr_iocstate_name(ioc_state));
119659bd9cfeSSreekanth Reddy 	}
119759bd9cfeSSreekanth Reddy 
119859bd9cfeSSreekanth Reddy 	if (ioc_state == MRIOC_STATE_READY) {
119959bd9cfeSSreekanth Reddy 		ioc_info(mrioc, "issuing message unit reset (MUR) to bring to reset state\n");
120059bd9cfeSSreekanth Reddy 		retval = mpi3mr_issue_and_process_mur(mrioc,
120159bd9cfeSSreekanth Reddy 		    MPI3MR_RESET_FROM_BRINGUP);
120259bd9cfeSSreekanth Reddy 		ioc_state = mpi3mr_get_iocstate(mrioc);
120359bd9cfeSSreekanth Reddy 		if (retval)
120459bd9cfeSSreekanth Reddy 			ioc_err(mrioc,
120559bd9cfeSSreekanth Reddy 			    "message unit reset failed with error %d current state %s\n",
120659bd9cfeSSreekanth Reddy 			    retval, mpi3mr_iocstate_name(ioc_state));
120759bd9cfeSSreekanth Reddy 	}
120859bd9cfeSSreekanth Reddy 	if (ioc_state != MRIOC_STATE_RESET) {
120959bd9cfeSSreekanth Reddy 		mpi3mr_print_fault_info(mrioc);
121059bd9cfeSSreekanth Reddy 		ioc_info(mrioc, "issuing soft reset to bring to reset state\n");
121159bd9cfeSSreekanth Reddy 		retval = mpi3mr_issue_reset(mrioc,
121259bd9cfeSSreekanth Reddy 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
121359bd9cfeSSreekanth Reddy 		    MPI3MR_RESET_FROM_BRINGUP);
121459bd9cfeSSreekanth Reddy 		if (retval) {
121559bd9cfeSSreekanth Reddy 			ioc_err(mrioc,
121659bd9cfeSSreekanth Reddy 			    "soft reset failed with error %d\n", retval);
121759bd9cfeSSreekanth Reddy 			goto out_failed;
121859bd9cfeSSreekanth Reddy 		}
121959bd9cfeSSreekanth Reddy 	}
122059bd9cfeSSreekanth Reddy 	ioc_state = mpi3mr_get_iocstate(mrioc);
122159bd9cfeSSreekanth Reddy 	if (ioc_state != MRIOC_STATE_RESET) {
122259bd9cfeSSreekanth Reddy 		ioc_err(mrioc,
122359bd9cfeSSreekanth Reddy 		    "cannot bring controller to reset state, current state: %s\n",
122459bd9cfeSSreekanth Reddy 		    mpi3mr_iocstate_name(ioc_state));
122559bd9cfeSSreekanth Reddy 		goto out_failed;
122659bd9cfeSSreekanth Reddy 	}
122759bd9cfeSSreekanth Reddy 	mpi3mr_clear_reset_history(mrioc);
122859bd9cfeSSreekanth Reddy 	retval = mpi3mr_setup_admin_qpair(mrioc);
122959bd9cfeSSreekanth Reddy 	if (retval) {
123059bd9cfeSSreekanth Reddy 		ioc_err(mrioc, "failed to setup admin queues: error %d\n",
123159bd9cfeSSreekanth Reddy 		    retval);
123259bd9cfeSSreekanth Reddy 		goto out_failed;
123359bd9cfeSSreekanth Reddy 	}
123459bd9cfeSSreekanth Reddy 
123559bd9cfeSSreekanth Reddy 	ioc_info(mrioc, "bringing controller to ready state\n");
1236824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
1237824a1566SKashyap Desai 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
1238824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
1239824a1566SKashyap Desai 
1240824a1566SKashyap Desai 	timeout = mrioc->ready_timeout * 10;
1241824a1566SKashyap Desai 	do {
124259bd9cfeSSreekanth Reddy 		ioc_state = mpi3mr_get_iocstate(mrioc);
124359bd9cfeSSreekanth Reddy 		if (ioc_state == MRIOC_STATE_READY) {
124459bd9cfeSSreekanth Reddy 			ioc_info(mrioc,
124559bd9cfeSSreekanth Reddy 			    "successfully transistioned to %s state\n",
124659bd9cfeSSreekanth Reddy 			    mpi3mr_iocstate_name(ioc_state));
1247824a1566SKashyap Desai 			return 0;
124859bd9cfeSSreekanth Reddy 		}
1249824a1566SKashyap Desai 		msleep(100);
1250824a1566SKashyap Desai 	} while (--timeout);
1251824a1566SKashyap Desai 
125259bd9cfeSSreekanth Reddy out_failed:
125359bd9cfeSSreekanth Reddy 	ioc_state = mpi3mr_get_iocstate(mrioc);
125459bd9cfeSSreekanth Reddy 	ioc_err(mrioc,
125559bd9cfeSSreekanth Reddy 	    "failed to bring to ready state,  current state: %s\n",
125659bd9cfeSSreekanth Reddy 	    mpi3mr_iocstate_name(ioc_state));
125759bd9cfeSSreekanth Reddy 	return retval;
1258824a1566SKashyap Desai }
1259824a1566SKashyap Desai 
1260824a1566SKashyap Desai /**
1261f061178eSKashyap Desai  * mpi3mr_soft_reset_success - Check softreset is success or not
1262f061178eSKashyap Desai  * @ioc_status: IOC status register value
1263f061178eSKashyap Desai  * @ioc_config: IOC config register value
1264f061178eSKashyap Desai  *
1265f061178eSKashyap Desai  * Check whether the soft reset is successful or not based on
1266f061178eSKashyap Desai  * IOC status and IOC config register values.
1267f061178eSKashyap Desai  *
1268f061178eSKashyap Desai  * Return: True when the soft reset is success, false otherwise.
1269f061178eSKashyap Desai  */
1270f061178eSKashyap Desai static inline bool
1271f061178eSKashyap Desai mpi3mr_soft_reset_success(u32 ioc_status, u32 ioc_config)
1272f061178eSKashyap Desai {
1273f061178eSKashyap Desai 	if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) ||
1274f061178eSKashyap Desai 	    (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC)))
1275f061178eSKashyap Desai 		return true;
1276f061178eSKashyap Desai 	return false;
1277f061178eSKashyap Desai }
1278f061178eSKashyap Desai 
1279f061178eSKashyap Desai /**
1280f061178eSKashyap Desai  * mpi3mr_diagfault_success - Check diag fault is success or not
1281f061178eSKashyap Desai  * @mrioc: Adapter reference
1282f061178eSKashyap Desai  * @ioc_status: IOC status register value
1283f061178eSKashyap Desai  *
1284f061178eSKashyap Desai  * Check whether the controller hit diag reset fault code.
1285f061178eSKashyap Desai  *
1286f061178eSKashyap Desai  * Return: True when there is diag fault, false otherwise.
1287f061178eSKashyap Desai  */
1288f061178eSKashyap Desai static inline bool mpi3mr_diagfault_success(struct mpi3mr_ioc *mrioc,
1289f061178eSKashyap Desai 	u32 ioc_status)
1290f061178eSKashyap Desai {
1291f061178eSKashyap Desai 	u32 fault;
1292f061178eSKashyap Desai 
1293f061178eSKashyap Desai 	if (!(ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT))
1294f061178eSKashyap Desai 		return false;
1295f061178eSKashyap Desai 	fault = readl(&mrioc->sysif_regs->fault) & MPI3_SYSIF_FAULT_CODE_MASK;
1296b64845a7SSreekanth Reddy 	if (fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET) {
1297b64845a7SSreekanth Reddy 		mpi3mr_print_fault_info(mrioc);
1298f061178eSKashyap Desai 		return true;
1299b64845a7SSreekanth Reddy 	}
1300f061178eSKashyap Desai 	return false;
1301f061178eSKashyap Desai }
1302f061178eSKashyap Desai 
1303f061178eSKashyap Desai /**
1304824a1566SKashyap Desai  * mpi3mr_set_diagsave - Set diag save bit for snapdump
1305824a1566SKashyap Desai  * @mrioc: Adapter reference
1306824a1566SKashyap Desai  *
1307824a1566SKashyap Desai  * Set diag save bit in IOC configuration register to enable
1308824a1566SKashyap Desai  * snapdump.
1309824a1566SKashyap Desai  *
1310824a1566SKashyap Desai  * Return: Nothing.
1311824a1566SKashyap Desai  */
1312824a1566SKashyap Desai static inline void mpi3mr_set_diagsave(struct mpi3mr_ioc *mrioc)
1313824a1566SKashyap Desai {
1314824a1566SKashyap Desai 	u32 ioc_config;
1315824a1566SKashyap Desai 
1316824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
1317824a1566SKashyap Desai 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_DIAG_SAVE;
1318824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
1319824a1566SKashyap Desai }
1320824a1566SKashyap Desai 
1321824a1566SKashyap Desai /**
1322824a1566SKashyap Desai  * mpi3mr_issue_reset - Issue reset to the controller
1323824a1566SKashyap Desai  * @mrioc: Adapter reference
1324824a1566SKashyap Desai  * @reset_type: Reset type
1325824a1566SKashyap Desai  * @reset_reason: Reset reason code
1326824a1566SKashyap Desai  *
1327f061178eSKashyap Desai  * Unlock the host diagnostic registers and write the specific
1328f061178eSKashyap Desai  * reset type to that, wait for reset acknowledgment from the
1329f061178eSKashyap Desai  * controller, if the reset is not successful retry for the
1330f061178eSKashyap Desai  * predefined number of times.
1331824a1566SKashyap Desai  *
1332824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
1333824a1566SKashyap Desai  */
1334824a1566SKashyap Desai static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type,
1335824a1566SKashyap Desai 	u32 reset_reason)
1336824a1566SKashyap Desai {
1337f061178eSKashyap Desai 	int retval = -1;
1338b64845a7SSreekanth Reddy 	u8 unlock_retry_count = 0;
1339b64845a7SSreekanth Reddy 	u32 host_diagnostic, ioc_status, ioc_config;
1340b64845a7SSreekanth Reddy 	u32 timeout = MPI3MR_RESET_ACK_TIMEOUT * 10;
1341f061178eSKashyap Desai 
1342f061178eSKashyap Desai 	if ((reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET) &&
1343f061178eSKashyap Desai 	    (reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT))
1344b64845a7SSreekanth Reddy 		return retval;
1345f061178eSKashyap Desai 	if (mrioc->unrecoverable)
1346b64845a7SSreekanth Reddy 		return retval;
1347b64845a7SSreekanth Reddy 	if (reset_reason == MPI3MR_RESET_FROM_FIRMWARE) {
1348b64845a7SSreekanth Reddy 		retval = 0;
1349b64845a7SSreekanth Reddy 		return retval;
1350b64845a7SSreekanth Reddy 	}
1351b64845a7SSreekanth Reddy 
1352b64845a7SSreekanth Reddy 	ioc_info(mrioc, "%s reset due to %s(0x%x)\n",
1353b64845a7SSreekanth Reddy 	    mpi3mr_reset_type_name(reset_type),
1354b64845a7SSreekanth Reddy 	    mpi3mr_reset_rc_name(reset_reason), reset_reason);
1355b64845a7SSreekanth Reddy 
1356f061178eSKashyap Desai 	mpi3mr_clear_reset_history(mrioc);
1357f061178eSKashyap Desai 	do {
1358f061178eSKashyap Desai 		ioc_info(mrioc,
1359f061178eSKashyap Desai 		    "Write magic sequence to unlock host diag register (retry=%d)\n",
1360f061178eSKashyap Desai 		    ++unlock_retry_count);
1361f061178eSKashyap Desai 		if (unlock_retry_count >= MPI3MR_HOSTDIAG_UNLOCK_RETRY_COUNT) {
1362b64845a7SSreekanth Reddy 			ioc_err(mrioc,
1363b64845a7SSreekanth Reddy 			    "%s reset failed due to unlock failure, host_diagnostic(0x%08x)\n",
1364b64845a7SSreekanth Reddy 			    mpi3mr_reset_type_name(reset_type),
1365b64845a7SSreekanth Reddy 			    host_diagnostic);
1366f061178eSKashyap Desai 			mrioc->unrecoverable = 1;
1367b64845a7SSreekanth Reddy 			return retval;
1368f061178eSKashyap Desai 		}
1369f061178eSKashyap Desai 
1370f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_FLUSH,
1371f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1372f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_1ST,
1373f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1374f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND,
1375f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1376f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_3RD,
1377f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1378f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_4TH,
1379f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1380f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_5TH,
1381f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1382f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_6TH,
1383f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1384f061178eSKashyap Desai 		usleep_range(1000, 1100);
1385f061178eSKashyap Desai 		host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic);
1386f061178eSKashyap Desai 		ioc_info(mrioc,
1387f061178eSKashyap Desai 		    "wrote magic sequence: retry_count(%d), host_diagnostic(0x%08x)\n",
1388f061178eSKashyap Desai 		    unlock_retry_count, host_diagnostic);
1389f061178eSKashyap Desai 	} while (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_DIAG_WRITE_ENABLE));
1390f061178eSKashyap Desai 
1391f061178eSKashyap Desai 	writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]);
1392f061178eSKashyap Desai 	writel(host_diagnostic | reset_type,
1393f061178eSKashyap Desai 	    &mrioc->sysif_regs->host_diagnostic);
1394b64845a7SSreekanth Reddy 	switch (reset_type) {
1395b64845a7SSreekanth Reddy 	case MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET:
1396f061178eSKashyap Desai 		do {
1397f061178eSKashyap Desai 			ioc_status = readl(&mrioc->sysif_regs->ioc_status);
1398f061178eSKashyap Desai 			ioc_config =
1399f061178eSKashyap Desai 			    readl(&mrioc->sysif_regs->ioc_configuration);
1400b64845a7SSreekanth Reddy 			if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)
1401b64845a7SSreekanth Reddy 			    && mpi3mr_soft_reset_success(ioc_status, ioc_config)
1402b64845a7SSreekanth Reddy 			    ) {
1403b64845a7SSreekanth Reddy 				mpi3mr_clear_reset_history(mrioc);
1404f061178eSKashyap Desai 				retval = 0;
1405f061178eSKashyap Desai 				break;
1406f061178eSKashyap Desai 			}
1407f061178eSKashyap Desai 			msleep(100);
1408f061178eSKashyap Desai 		} while (--timeout);
1409b64845a7SSreekanth Reddy 		mpi3mr_print_fault_info(mrioc);
1410b64845a7SSreekanth Reddy 		break;
1411b64845a7SSreekanth Reddy 	case MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT:
1412f061178eSKashyap Desai 		do {
1413f061178eSKashyap Desai 			ioc_status = readl(&mrioc->sysif_regs->ioc_status);
1414f061178eSKashyap Desai 			if (mpi3mr_diagfault_success(mrioc, ioc_status)) {
1415f061178eSKashyap Desai 				retval = 0;
1416f061178eSKashyap Desai 				break;
1417f061178eSKashyap Desai 			}
1418f061178eSKashyap Desai 			msleep(100);
1419f061178eSKashyap Desai 		} while (--timeout);
1420b64845a7SSreekanth Reddy 		break;
1421b64845a7SSreekanth Reddy 	default:
1422b64845a7SSreekanth Reddy 		break;
1423b64845a7SSreekanth Reddy 	}
1424b64845a7SSreekanth Reddy 
1425f061178eSKashyap Desai 	writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND,
1426f061178eSKashyap Desai 	    &mrioc->sysif_regs->write_sequence);
1427f061178eSKashyap Desai 
1428f061178eSKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
1429b64845a7SSreekanth Reddy 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
1430f061178eSKashyap Desai 	ioc_info(mrioc,
1431b64845a7SSreekanth Reddy 	    "ioc_status/ioc_onfig after %s reset is (0x%x)/(0x%x)\n",
1432f061178eSKashyap Desai 	    (!retval)?"successful":"failed", ioc_status,
1433f061178eSKashyap Desai 	    ioc_config);
1434b64845a7SSreekanth Reddy 	if (retval)
1435b64845a7SSreekanth Reddy 		mrioc->unrecoverable = 1;
1436f061178eSKashyap Desai 	return retval;
1437824a1566SKashyap Desai }
1438824a1566SKashyap Desai 
1439824a1566SKashyap Desai /**
1440824a1566SKashyap Desai  * mpi3mr_admin_request_post - Post request to admin queue
1441824a1566SKashyap Desai  * @mrioc: Adapter reference
1442824a1566SKashyap Desai  * @admin_req: MPI3 request
1443824a1566SKashyap Desai  * @admin_req_sz: Request size
1444824a1566SKashyap Desai  * @ignore_reset: Ignore reset in process
1445824a1566SKashyap Desai  *
1446824a1566SKashyap Desai  * Post the MPI3 request into admin request queue and
1447824a1566SKashyap Desai  * inform the controller, if the queue is full return
1448824a1566SKashyap Desai  * appropriate error.
1449824a1566SKashyap Desai  *
1450824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
1451824a1566SKashyap Desai  */
1452824a1566SKashyap Desai int mpi3mr_admin_request_post(struct mpi3mr_ioc *mrioc, void *admin_req,
1453824a1566SKashyap Desai 	u16 admin_req_sz, u8 ignore_reset)
1454824a1566SKashyap Desai {
1455824a1566SKashyap Desai 	u16 areq_pi = 0, areq_ci = 0, max_entries = 0;
1456824a1566SKashyap Desai 	int retval = 0;
1457824a1566SKashyap Desai 	unsigned long flags;
1458824a1566SKashyap Desai 	u8 *areq_entry;
1459824a1566SKashyap Desai 
1460824a1566SKashyap Desai 	if (mrioc->unrecoverable) {
1461824a1566SKashyap Desai 		ioc_err(mrioc, "%s : Unrecoverable controller\n", __func__);
1462824a1566SKashyap Desai 		return -EFAULT;
1463824a1566SKashyap Desai 	}
1464824a1566SKashyap Desai 
1465824a1566SKashyap Desai 	spin_lock_irqsave(&mrioc->admin_req_lock, flags);
1466824a1566SKashyap Desai 	areq_pi = mrioc->admin_req_pi;
1467824a1566SKashyap Desai 	areq_ci = mrioc->admin_req_ci;
1468824a1566SKashyap Desai 	max_entries = mrioc->num_admin_req;
1469824a1566SKashyap Desai 	if ((areq_ci == (areq_pi + 1)) || ((!areq_ci) &&
1470824a1566SKashyap Desai 	    (areq_pi == (max_entries - 1)))) {
1471824a1566SKashyap Desai 		ioc_err(mrioc, "AdminReqQ full condition detected\n");
1472824a1566SKashyap Desai 		retval = -EAGAIN;
1473824a1566SKashyap Desai 		goto out;
1474824a1566SKashyap Desai 	}
1475824a1566SKashyap Desai 	if (!ignore_reset && mrioc->reset_in_progress) {
1476824a1566SKashyap Desai 		ioc_err(mrioc, "AdminReqQ submit reset in progress\n");
1477824a1566SKashyap Desai 		retval = -EAGAIN;
1478824a1566SKashyap Desai 		goto out;
1479824a1566SKashyap Desai 	}
1480824a1566SKashyap Desai 	areq_entry = (u8 *)mrioc->admin_req_base +
1481824a1566SKashyap Desai 	    (areq_pi * MPI3MR_ADMIN_REQ_FRAME_SZ);
1482824a1566SKashyap Desai 	memset(areq_entry, 0, MPI3MR_ADMIN_REQ_FRAME_SZ);
1483824a1566SKashyap Desai 	memcpy(areq_entry, (u8 *)admin_req, admin_req_sz);
1484824a1566SKashyap Desai 
1485824a1566SKashyap Desai 	if (++areq_pi == max_entries)
1486824a1566SKashyap Desai 		areq_pi = 0;
1487824a1566SKashyap Desai 	mrioc->admin_req_pi = areq_pi;
1488824a1566SKashyap Desai 
1489824a1566SKashyap Desai 	writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi);
1490824a1566SKashyap Desai 
1491824a1566SKashyap Desai out:
1492824a1566SKashyap Desai 	spin_unlock_irqrestore(&mrioc->admin_req_lock, flags);
1493824a1566SKashyap Desai 
1494824a1566SKashyap Desai 	return retval;
1495824a1566SKashyap Desai }
1496824a1566SKashyap Desai 
1497824a1566SKashyap Desai /**
1498c9566231SKashyap Desai  * mpi3mr_free_op_req_q_segments - free request memory segments
1499c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1500c9566231SKashyap Desai  * @q_idx: operational request queue index
1501c9566231SKashyap Desai  *
1502c9566231SKashyap Desai  * Free memory segments allocated for operational request queue
1503c9566231SKashyap Desai  *
1504c9566231SKashyap Desai  * Return: Nothing.
1505c9566231SKashyap Desai  */
1506c9566231SKashyap Desai static void mpi3mr_free_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx)
1507c9566231SKashyap Desai {
1508c9566231SKashyap Desai 	u16 j;
1509c9566231SKashyap Desai 	int size;
1510c9566231SKashyap Desai 	struct segments *segments;
1511c9566231SKashyap Desai 
1512c9566231SKashyap Desai 	segments = mrioc->req_qinfo[q_idx].q_segments;
1513c9566231SKashyap Desai 	if (!segments)
1514c9566231SKashyap Desai 		return;
1515c9566231SKashyap Desai 
1516c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1517c9566231SKashyap Desai 		size = MPI3MR_OP_REQ_Q_SEG_SIZE;
1518c9566231SKashyap Desai 		if (mrioc->req_qinfo[q_idx].q_segment_list) {
1519c9566231SKashyap Desai 			dma_free_coherent(&mrioc->pdev->dev,
1520c9566231SKashyap Desai 			    MPI3MR_MAX_SEG_LIST_SIZE,
1521c9566231SKashyap Desai 			    mrioc->req_qinfo[q_idx].q_segment_list,
1522c9566231SKashyap Desai 			    mrioc->req_qinfo[q_idx].q_segment_list_dma);
1523c9566231SKashyap Desai 			mrioc->op_reply_qinfo[q_idx].q_segment_list = NULL;
1524c9566231SKashyap Desai 		}
1525c9566231SKashyap Desai 	} else
1526c9566231SKashyap Desai 		size = mrioc->req_qinfo[q_idx].num_requests *
1527c9566231SKashyap Desai 		    mrioc->facts.op_req_sz;
1528c9566231SKashyap Desai 
1529c9566231SKashyap Desai 	for (j = 0; j < mrioc->req_qinfo[q_idx].num_segments; j++) {
1530c9566231SKashyap Desai 		if (!segments[j].segment)
1531c9566231SKashyap Desai 			continue;
1532c9566231SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev,
1533c9566231SKashyap Desai 		    size, segments[j].segment, segments[j].segment_dma);
1534c9566231SKashyap Desai 		segments[j].segment = NULL;
1535c9566231SKashyap Desai 	}
1536c9566231SKashyap Desai 	kfree(mrioc->req_qinfo[q_idx].q_segments);
1537c9566231SKashyap Desai 	mrioc->req_qinfo[q_idx].q_segments = NULL;
1538c9566231SKashyap Desai 	mrioc->req_qinfo[q_idx].qid = 0;
1539c9566231SKashyap Desai }
1540c9566231SKashyap Desai 
1541c9566231SKashyap Desai /**
1542c9566231SKashyap Desai  * mpi3mr_free_op_reply_q_segments - free reply memory segments
1543c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1544c9566231SKashyap Desai  * @q_idx: operational reply queue index
1545c9566231SKashyap Desai  *
1546c9566231SKashyap Desai  * Free memory segments allocated for operational reply queue
1547c9566231SKashyap Desai  *
1548c9566231SKashyap Desai  * Return: Nothing.
1549c9566231SKashyap Desai  */
1550c9566231SKashyap Desai static void mpi3mr_free_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx)
1551c9566231SKashyap Desai {
1552c9566231SKashyap Desai 	u16 j;
1553c9566231SKashyap Desai 	int size;
1554c9566231SKashyap Desai 	struct segments *segments;
1555c9566231SKashyap Desai 
1556c9566231SKashyap Desai 	segments = mrioc->op_reply_qinfo[q_idx].q_segments;
1557c9566231SKashyap Desai 	if (!segments)
1558c9566231SKashyap Desai 		return;
1559c9566231SKashyap Desai 
1560c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1561c9566231SKashyap Desai 		size = MPI3MR_OP_REP_Q_SEG_SIZE;
1562c9566231SKashyap Desai 		if (mrioc->op_reply_qinfo[q_idx].q_segment_list) {
1563c9566231SKashyap Desai 			dma_free_coherent(&mrioc->pdev->dev,
1564c9566231SKashyap Desai 			    MPI3MR_MAX_SEG_LIST_SIZE,
1565c9566231SKashyap Desai 			    mrioc->op_reply_qinfo[q_idx].q_segment_list,
1566c9566231SKashyap Desai 			    mrioc->op_reply_qinfo[q_idx].q_segment_list_dma);
1567c9566231SKashyap Desai 			mrioc->op_reply_qinfo[q_idx].q_segment_list = NULL;
1568c9566231SKashyap Desai 		}
1569c9566231SKashyap Desai 	} else
1570c9566231SKashyap Desai 		size = mrioc->op_reply_qinfo[q_idx].segment_qd *
1571c9566231SKashyap Desai 		    mrioc->op_reply_desc_sz;
1572c9566231SKashyap Desai 
1573c9566231SKashyap Desai 	for (j = 0; j < mrioc->op_reply_qinfo[q_idx].num_segments; j++) {
1574c9566231SKashyap Desai 		if (!segments[j].segment)
1575c9566231SKashyap Desai 			continue;
1576c9566231SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev,
1577c9566231SKashyap Desai 		    size, segments[j].segment, segments[j].segment_dma);
1578c9566231SKashyap Desai 		segments[j].segment = NULL;
1579c9566231SKashyap Desai 	}
1580c9566231SKashyap Desai 
1581c9566231SKashyap Desai 	kfree(mrioc->op_reply_qinfo[q_idx].q_segments);
1582c9566231SKashyap Desai 	mrioc->op_reply_qinfo[q_idx].q_segments = NULL;
1583c9566231SKashyap Desai 	mrioc->op_reply_qinfo[q_idx].qid = 0;
1584c9566231SKashyap Desai }
1585c9566231SKashyap Desai 
1586c9566231SKashyap Desai /**
1587c9566231SKashyap Desai  * mpi3mr_delete_op_reply_q - delete operational reply queue
1588c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1589c9566231SKashyap Desai  * @qidx: operational reply queue index
1590c9566231SKashyap Desai  *
1591c9566231SKashyap Desai  * Delete operatinal reply queue by issuing MPI request
1592c9566231SKashyap Desai  * through admin queue.
1593c9566231SKashyap Desai  *
1594c9566231SKashyap Desai  * Return:  0 on success, non-zero on failure.
1595c9566231SKashyap Desai  */
1596c9566231SKashyap Desai static int mpi3mr_delete_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx)
1597c9566231SKashyap Desai {
1598c9566231SKashyap Desai 	struct mpi3_delete_reply_queue_request delq_req;
1599*afd3a579SSreekanth Reddy 	struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
1600c9566231SKashyap Desai 	int retval = 0;
1601c9566231SKashyap Desai 	u16 reply_qid = 0, midx;
1602c9566231SKashyap Desai 
1603*afd3a579SSreekanth Reddy 	reply_qid = op_reply_q->qid;
1604c9566231SKashyap Desai 
1605c9566231SKashyap Desai 	midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset);
1606c9566231SKashyap Desai 
1607c9566231SKashyap Desai 	if (!reply_qid)	{
1608c9566231SKashyap Desai 		retval = -1;
1609c9566231SKashyap Desai 		ioc_err(mrioc, "Issue DelRepQ: called with invalid ReqQID\n");
1610c9566231SKashyap Desai 		goto out;
1611c9566231SKashyap Desai 	}
1612c9566231SKashyap Desai 
1613*afd3a579SSreekanth Reddy 	(op_reply_q->qtype == MPI3MR_DEFAULT_QUEUE) ? mrioc->default_qcount-- :
1614*afd3a579SSreekanth Reddy 	    mrioc->active_poll_qcount--;
1615*afd3a579SSreekanth Reddy 
1616c9566231SKashyap Desai 	memset(&delq_req, 0, sizeof(delq_req));
1617c9566231SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
1618c9566231SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
1619c9566231SKashyap Desai 		retval = -1;
1620c9566231SKashyap Desai 		ioc_err(mrioc, "Issue DelRepQ: Init command is in use\n");
1621c9566231SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
1622c9566231SKashyap Desai 		goto out;
1623c9566231SKashyap Desai 	}
1624c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
1625c9566231SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
1626c9566231SKashyap Desai 	mrioc->init_cmds.callback = NULL;
1627c9566231SKashyap Desai 	delq_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
1628c9566231SKashyap Desai 	delq_req.function = MPI3_FUNCTION_DELETE_REPLY_QUEUE;
1629c9566231SKashyap Desai 	delq_req.queue_id = cpu_to_le16(reply_qid);
1630c9566231SKashyap Desai 
1631c9566231SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
1632c9566231SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &delq_req, sizeof(delq_req),
1633c9566231SKashyap Desai 	    1);
1634c9566231SKashyap Desai 	if (retval) {
1635c9566231SKashyap Desai 		ioc_err(mrioc, "Issue DelRepQ: Admin Post failed\n");
1636c9566231SKashyap Desai 		goto out_unlock;
1637c9566231SKashyap Desai 	}
1638c9566231SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
1639c9566231SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
1640c9566231SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
1641a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "delete reply queue timed out\n");
1642a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
1643c9566231SKashyap Desai 		    MPI3MR_RESET_FROM_DELREPQ_TIMEOUT);
1644c9566231SKashyap Desai 		retval = -1;
1645c9566231SKashyap Desai 		goto out_unlock;
1646c9566231SKashyap Desai 	}
1647c9566231SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
1648c9566231SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
1649c9566231SKashyap Desai 		ioc_err(mrioc,
1650c9566231SKashyap Desai 		    "Issue DelRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
1651c9566231SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
1652c9566231SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
1653c9566231SKashyap Desai 		retval = -1;
1654c9566231SKashyap Desai 		goto out_unlock;
1655c9566231SKashyap Desai 	}
1656c9566231SKashyap Desai 	mrioc->intr_info[midx].op_reply_q = NULL;
1657c9566231SKashyap Desai 
1658c9566231SKashyap Desai 	mpi3mr_free_op_reply_q_segments(mrioc, qidx);
1659c9566231SKashyap Desai out_unlock:
1660c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
1661c9566231SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
1662c9566231SKashyap Desai out:
1663c9566231SKashyap Desai 
1664c9566231SKashyap Desai 	return retval;
1665c9566231SKashyap Desai }
1666c9566231SKashyap Desai 
1667c9566231SKashyap Desai /**
1668c9566231SKashyap Desai  * mpi3mr_alloc_op_reply_q_segments -Alloc segmented reply pool
1669c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1670c9566231SKashyap Desai  * @qidx: request queue index
1671c9566231SKashyap Desai  *
1672c9566231SKashyap Desai  * Allocate segmented memory pools for operational reply
1673c9566231SKashyap Desai  * queue.
1674c9566231SKashyap Desai  *
1675c9566231SKashyap Desai  * Return: 0 on success, non-zero on failure.
1676c9566231SKashyap Desai  */
1677c9566231SKashyap Desai static int mpi3mr_alloc_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx)
1678c9566231SKashyap Desai {
1679c9566231SKashyap Desai 	struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
1680c9566231SKashyap Desai 	int i, size;
1681c9566231SKashyap Desai 	u64 *q_segment_list_entry = NULL;
1682c9566231SKashyap Desai 	struct segments *segments;
1683c9566231SKashyap Desai 
1684c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1685c9566231SKashyap Desai 		op_reply_q->segment_qd =
1686c9566231SKashyap Desai 		    MPI3MR_OP_REP_Q_SEG_SIZE / mrioc->op_reply_desc_sz;
1687c9566231SKashyap Desai 
1688c9566231SKashyap Desai 		size = MPI3MR_OP_REP_Q_SEG_SIZE;
1689c9566231SKashyap Desai 
1690c9566231SKashyap Desai 		op_reply_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev,
1691c9566231SKashyap Desai 		    MPI3MR_MAX_SEG_LIST_SIZE, &op_reply_q->q_segment_list_dma,
1692c9566231SKashyap Desai 		    GFP_KERNEL);
1693c9566231SKashyap Desai 		if (!op_reply_q->q_segment_list)
1694c9566231SKashyap Desai 			return -ENOMEM;
1695c9566231SKashyap Desai 		q_segment_list_entry = (u64 *)op_reply_q->q_segment_list;
1696c9566231SKashyap Desai 	} else {
1697c9566231SKashyap Desai 		op_reply_q->segment_qd = op_reply_q->num_replies;
1698c9566231SKashyap Desai 		size = op_reply_q->num_replies * mrioc->op_reply_desc_sz;
1699c9566231SKashyap Desai 	}
1700c9566231SKashyap Desai 
1701c9566231SKashyap Desai 	op_reply_q->num_segments = DIV_ROUND_UP(op_reply_q->num_replies,
1702c9566231SKashyap Desai 	    op_reply_q->segment_qd);
1703c9566231SKashyap Desai 
1704c9566231SKashyap Desai 	op_reply_q->q_segments = kcalloc(op_reply_q->num_segments,
1705c9566231SKashyap Desai 	    sizeof(struct segments), GFP_KERNEL);
1706c9566231SKashyap Desai 	if (!op_reply_q->q_segments)
1707c9566231SKashyap Desai 		return -ENOMEM;
1708c9566231SKashyap Desai 
1709c9566231SKashyap Desai 	segments = op_reply_q->q_segments;
1710c9566231SKashyap Desai 	for (i = 0; i < op_reply_q->num_segments; i++) {
1711c9566231SKashyap Desai 		segments[i].segment =
1712c9566231SKashyap Desai 		    dma_alloc_coherent(&mrioc->pdev->dev,
1713c9566231SKashyap Desai 		    size, &segments[i].segment_dma, GFP_KERNEL);
1714c9566231SKashyap Desai 		if (!segments[i].segment)
1715c9566231SKashyap Desai 			return -ENOMEM;
1716c9566231SKashyap Desai 		if (mrioc->enable_segqueue)
1717c9566231SKashyap Desai 			q_segment_list_entry[i] =
1718c9566231SKashyap Desai 			    (unsigned long)segments[i].segment_dma;
1719c9566231SKashyap Desai 	}
1720c9566231SKashyap Desai 
1721c9566231SKashyap Desai 	return 0;
1722c9566231SKashyap Desai }
1723c9566231SKashyap Desai 
1724c9566231SKashyap Desai /**
1725c9566231SKashyap Desai  * mpi3mr_alloc_op_req_q_segments - Alloc segmented req pool.
1726c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1727c9566231SKashyap Desai  * @qidx: request queue index
1728c9566231SKashyap Desai  *
1729c9566231SKashyap Desai  * Allocate segmented memory pools for operational request
1730c9566231SKashyap Desai  * queue.
1731c9566231SKashyap Desai  *
1732c9566231SKashyap Desai  * Return: 0 on success, non-zero on failure.
1733c9566231SKashyap Desai  */
1734c9566231SKashyap Desai static int mpi3mr_alloc_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx)
1735c9566231SKashyap Desai {
1736c9566231SKashyap Desai 	struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx;
1737c9566231SKashyap Desai 	int i, size;
1738c9566231SKashyap Desai 	u64 *q_segment_list_entry = NULL;
1739c9566231SKashyap Desai 	struct segments *segments;
1740c9566231SKashyap Desai 
1741c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1742c9566231SKashyap Desai 		op_req_q->segment_qd =
1743c9566231SKashyap Desai 		    MPI3MR_OP_REQ_Q_SEG_SIZE / mrioc->facts.op_req_sz;
1744c9566231SKashyap Desai 
1745c9566231SKashyap Desai 		size = MPI3MR_OP_REQ_Q_SEG_SIZE;
1746c9566231SKashyap Desai 
1747c9566231SKashyap Desai 		op_req_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev,
1748c9566231SKashyap Desai 		    MPI3MR_MAX_SEG_LIST_SIZE, &op_req_q->q_segment_list_dma,
1749c9566231SKashyap Desai 		    GFP_KERNEL);
1750c9566231SKashyap Desai 		if (!op_req_q->q_segment_list)
1751c9566231SKashyap Desai 			return -ENOMEM;
1752c9566231SKashyap Desai 		q_segment_list_entry = (u64 *)op_req_q->q_segment_list;
1753c9566231SKashyap Desai 
1754c9566231SKashyap Desai 	} else {
1755c9566231SKashyap Desai 		op_req_q->segment_qd = op_req_q->num_requests;
1756c9566231SKashyap Desai 		size = op_req_q->num_requests * mrioc->facts.op_req_sz;
1757c9566231SKashyap Desai 	}
1758c9566231SKashyap Desai 
1759c9566231SKashyap Desai 	op_req_q->num_segments = DIV_ROUND_UP(op_req_q->num_requests,
1760c9566231SKashyap Desai 	    op_req_q->segment_qd);
1761c9566231SKashyap Desai 
1762c9566231SKashyap Desai 	op_req_q->q_segments = kcalloc(op_req_q->num_segments,
1763c9566231SKashyap Desai 	    sizeof(struct segments), GFP_KERNEL);
1764c9566231SKashyap Desai 	if (!op_req_q->q_segments)
1765c9566231SKashyap Desai 		return -ENOMEM;
1766c9566231SKashyap Desai 
1767c9566231SKashyap Desai 	segments = op_req_q->q_segments;
1768c9566231SKashyap Desai 	for (i = 0; i < op_req_q->num_segments; i++) {
1769c9566231SKashyap Desai 		segments[i].segment =
1770c9566231SKashyap Desai 		    dma_alloc_coherent(&mrioc->pdev->dev,
1771c9566231SKashyap Desai 		    size, &segments[i].segment_dma, GFP_KERNEL);
1772c9566231SKashyap Desai 		if (!segments[i].segment)
1773c9566231SKashyap Desai 			return -ENOMEM;
1774c9566231SKashyap Desai 		if (mrioc->enable_segqueue)
1775c9566231SKashyap Desai 			q_segment_list_entry[i] =
1776c9566231SKashyap Desai 			    (unsigned long)segments[i].segment_dma;
1777c9566231SKashyap Desai 	}
1778c9566231SKashyap Desai 
1779c9566231SKashyap Desai 	return 0;
1780c9566231SKashyap Desai }
1781c9566231SKashyap Desai 
1782c9566231SKashyap Desai /**
1783c9566231SKashyap Desai  * mpi3mr_create_op_reply_q - create operational reply queue
1784c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1785c9566231SKashyap Desai  * @qidx: operational reply queue index
1786c9566231SKashyap Desai  *
1787c9566231SKashyap Desai  * Create operatinal reply queue by issuing MPI request
1788c9566231SKashyap Desai  * through admin queue.
1789c9566231SKashyap Desai  *
1790c9566231SKashyap Desai  * Return:  0 on success, non-zero on failure.
1791c9566231SKashyap Desai  */
1792c9566231SKashyap Desai static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx)
1793c9566231SKashyap Desai {
1794c9566231SKashyap Desai 	struct mpi3_create_reply_queue_request create_req;
1795c9566231SKashyap Desai 	struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
1796c9566231SKashyap Desai 	int retval = 0;
1797c9566231SKashyap Desai 	u16 reply_qid = 0, midx;
1798c9566231SKashyap Desai 
1799c9566231SKashyap Desai 	reply_qid = op_reply_q->qid;
1800c9566231SKashyap Desai 
1801c9566231SKashyap Desai 	midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset);
1802c9566231SKashyap Desai 
1803c9566231SKashyap Desai 	if (reply_qid) {
1804c9566231SKashyap Desai 		retval = -1;
1805c9566231SKashyap Desai 		ioc_err(mrioc, "CreateRepQ: called for duplicate qid %d\n",
1806c9566231SKashyap Desai 		    reply_qid);
1807c9566231SKashyap Desai 
1808c9566231SKashyap Desai 		return retval;
1809c9566231SKashyap Desai 	}
1810c9566231SKashyap Desai 
1811c9566231SKashyap Desai 	reply_qid = qidx + 1;
1812c9566231SKashyap Desai 	op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD;
1813c9566231SKashyap Desai 	op_reply_q->ci = 0;
1814c9566231SKashyap Desai 	op_reply_q->ephase = 1;
1815463429f8SKashyap Desai 	atomic_set(&op_reply_q->pend_ios, 0);
1816463429f8SKashyap Desai 	atomic_set(&op_reply_q->in_use, 0);
1817463429f8SKashyap Desai 	op_reply_q->enable_irq_poll = false;
1818c9566231SKashyap Desai 
1819c9566231SKashyap Desai 	if (!op_reply_q->q_segments) {
1820c9566231SKashyap Desai 		retval = mpi3mr_alloc_op_reply_q_segments(mrioc, qidx);
1821c9566231SKashyap Desai 		if (retval) {
1822c9566231SKashyap Desai 			mpi3mr_free_op_reply_q_segments(mrioc, qidx);
1823c9566231SKashyap Desai 			goto out;
1824c9566231SKashyap Desai 		}
1825c9566231SKashyap Desai 	}
1826c9566231SKashyap Desai 
1827c9566231SKashyap Desai 	memset(&create_req, 0, sizeof(create_req));
1828c9566231SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
1829c9566231SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
1830c9566231SKashyap Desai 		retval = -1;
1831c9566231SKashyap Desai 		ioc_err(mrioc, "CreateRepQ: Init command is in use\n");
1832f9dc034dSYang Yingliang 		goto out_unlock;
1833c9566231SKashyap Desai 	}
1834c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
1835c9566231SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
1836c9566231SKashyap Desai 	mrioc->init_cmds.callback = NULL;
1837c9566231SKashyap Desai 	create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
1838c9566231SKashyap Desai 	create_req.function = MPI3_FUNCTION_CREATE_REPLY_QUEUE;
1839c9566231SKashyap Desai 	create_req.queue_id = cpu_to_le16(reply_qid);
1840*afd3a579SSreekanth Reddy 
1841*afd3a579SSreekanth Reddy 	if (midx < (mrioc->intr_info_count - mrioc->requested_poll_qcount))
1842*afd3a579SSreekanth Reddy 		op_reply_q->qtype = MPI3MR_DEFAULT_QUEUE;
1843*afd3a579SSreekanth Reddy 	else
1844*afd3a579SSreekanth Reddy 		op_reply_q->qtype = MPI3MR_POLL_QUEUE;
1845*afd3a579SSreekanth Reddy 
1846*afd3a579SSreekanth Reddy 	if (op_reply_q->qtype == MPI3MR_DEFAULT_QUEUE) {
1847*afd3a579SSreekanth Reddy 		create_req.flags =
1848*afd3a579SSreekanth Reddy 			MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_ENABLE;
1849*afd3a579SSreekanth Reddy 		create_req.msix_index =
1850*afd3a579SSreekanth Reddy 			cpu_to_le16(mrioc->intr_info[midx].msix_index);
1851*afd3a579SSreekanth Reddy 	} else {
1852*afd3a579SSreekanth Reddy 		create_req.msix_index = cpu_to_le16(mrioc->intr_info_count - 1);
1853*afd3a579SSreekanth Reddy 		ioc_info(mrioc, "create reply queue(polled): for qid(%d), midx(%d)\n",
1854*afd3a579SSreekanth Reddy 			reply_qid, midx);
1855*afd3a579SSreekanth Reddy 		if (!mrioc->active_poll_qcount)
1856*afd3a579SSreekanth Reddy 			disable_irq_nosync(pci_irq_vector(mrioc->pdev,
1857*afd3a579SSreekanth Reddy 			    mrioc->intr_info_count - 1));
1858*afd3a579SSreekanth Reddy 	}
1859*afd3a579SSreekanth Reddy 
1860c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1861c9566231SKashyap Desai 		create_req.flags |=
1862c9566231SKashyap Desai 		    MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED;
1863c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
1864c9566231SKashyap Desai 		    op_reply_q->q_segment_list_dma);
1865c9566231SKashyap Desai 	} else
1866c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
1867c9566231SKashyap Desai 		    op_reply_q->q_segments[0].segment_dma);
1868c9566231SKashyap Desai 
1869c9566231SKashyap Desai 	create_req.size = cpu_to_le16(op_reply_q->num_replies);
1870c9566231SKashyap Desai 
1871c9566231SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
1872c9566231SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &create_req,
1873c9566231SKashyap Desai 	    sizeof(create_req), 1);
1874c9566231SKashyap Desai 	if (retval) {
1875c9566231SKashyap Desai 		ioc_err(mrioc, "CreateRepQ: Admin Post failed\n");
1876c9566231SKashyap Desai 		goto out_unlock;
1877c9566231SKashyap Desai 	}
1878c9566231SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
1879c9566231SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
1880c9566231SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
1881a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "create reply queue timed out\n");
1882a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
1883c9566231SKashyap Desai 		    MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT);
1884c9566231SKashyap Desai 		retval = -1;
1885c9566231SKashyap Desai 		goto out_unlock;
1886c9566231SKashyap Desai 	}
1887c9566231SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
1888c9566231SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
1889c9566231SKashyap Desai 		ioc_err(mrioc,
1890c9566231SKashyap Desai 		    "CreateRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
1891c9566231SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
1892c9566231SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
1893c9566231SKashyap Desai 		retval = -1;
1894c9566231SKashyap Desai 		goto out_unlock;
1895c9566231SKashyap Desai 	}
1896c9566231SKashyap Desai 	op_reply_q->qid = reply_qid;
1897fe6db615SSreekanth Reddy 	if (midx < mrioc->intr_info_count)
1898c9566231SKashyap Desai 		mrioc->intr_info[midx].op_reply_q = op_reply_q;
1899c9566231SKashyap Desai 
1900*afd3a579SSreekanth Reddy 	(op_reply_q->qtype == MPI3MR_DEFAULT_QUEUE) ? mrioc->default_qcount++ :
1901*afd3a579SSreekanth Reddy 	    mrioc->active_poll_qcount++;
1902*afd3a579SSreekanth Reddy 
1903c9566231SKashyap Desai out_unlock:
1904c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
1905c9566231SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
1906c9566231SKashyap Desai out:
1907c9566231SKashyap Desai 
1908c9566231SKashyap Desai 	return retval;
1909c9566231SKashyap Desai }
1910c9566231SKashyap Desai 
1911c9566231SKashyap Desai /**
1912c9566231SKashyap Desai  * mpi3mr_create_op_req_q - create operational request queue
1913c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1914c9566231SKashyap Desai  * @idx: operational request queue index
1915c9566231SKashyap Desai  * @reply_qid: Reply queue ID
1916c9566231SKashyap Desai  *
1917c9566231SKashyap Desai  * Create operatinal request queue by issuing MPI request
1918c9566231SKashyap Desai  * through admin queue.
1919c9566231SKashyap Desai  *
1920c9566231SKashyap Desai  * Return:  0 on success, non-zero on failure.
1921c9566231SKashyap Desai  */
1922c9566231SKashyap Desai static int mpi3mr_create_op_req_q(struct mpi3mr_ioc *mrioc, u16 idx,
1923c9566231SKashyap Desai 	u16 reply_qid)
1924c9566231SKashyap Desai {
1925c9566231SKashyap Desai 	struct mpi3_create_request_queue_request create_req;
1926c9566231SKashyap Desai 	struct op_req_qinfo *op_req_q = mrioc->req_qinfo + idx;
1927c9566231SKashyap Desai 	int retval = 0;
1928c9566231SKashyap Desai 	u16 req_qid = 0;
1929c9566231SKashyap Desai 
1930c9566231SKashyap Desai 	req_qid = op_req_q->qid;
1931c9566231SKashyap Desai 
1932c9566231SKashyap Desai 	if (req_qid) {
1933c9566231SKashyap Desai 		retval = -1;
1934c9566231SKashyap Desai 		ioc_err(mrioc, "CreateReqQ: called for duplicate qid %d\n",
1935c9566231SKashyap Desai 		    req_qid);
1936c9566231SKashyap Desai 
1937c9566231SKashyap Desai 		return retval;
1938c9566231SKashyap Desai 	}
1939c9566231SKashyap Desai 	req_qid = idx + 1;
1940c9566231SKashyap Desai 
1941c9566231SKashyap Desai 	op_req_q->num_requests = MPI3MR_OP_REQ_Q_QD;
1942c9566231SKashyap Desai 	op_req_q->ci = 0;
1943c9566231SKashyap Desai 	op_req_q->pi = 0;
1944c9566231SKashyap Desai 	op_req_q->reply_qid = reply_qid;
1945c9566231SKashyap Desai 	spin_lock_init(&op_req_q->q_lock);
1946c9566231SKashyap Desai 
1947c9566231SKashyap Desai 	if (!op_req_q->q_segments) {
1948c9566231SKashyap Desai 		retval = mpi3mr_alloc_op_req_q_segments(mrioc, idx);
1949c9566231SKashyap Desai 		if (retval) {
1950c9566231SKashyap Desai 			mpi3mr_free_op_req_q_segments(mrioc, idx);
1951c9566231SKashyap Desai 			goto out;
1952c9566231SKashyap Desai 		}
1953c9566231SKashyap Desai 	}
1954c9566231SKashyap Desai 
1955c9566231SKashyap Desai 	memset(&create_req, 0, sizeof(create_req));
1956c9566231SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
1957c9566231SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
1958c9566231SKashyap Desai 		retval = -1;
1959c9566231SKashyap Desai 		ioc_err(mrioc, "CreateReqQ: Init command is in use\n");
1960f9dc034dSYang Yingliang 		goto out_unlock;
1961c9566231SKashyap Desai 	}
1962c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
1963c9566231SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
1964c9566231SKashyap Desai 	mrioc->init_cmds.callback = NULL;
1965c9566231SKashyap Desai 	create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
1966c9566231SKashyap Desai 	create_req.function = MPI3_FUNCTION_CREATE_REQUEST_QUEUE;
1967c9566231SKashyap Desai 	create_req.queue_id = cpu_to_le16(req_qid);
1968c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1969c9566231SKashyap Desai 		create_req.flags =
1970c9566231SKashyap Desai 		    MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED;
1971c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
1972c9566231SKashyap Desai 		    op_req_q->q_segment_list_dma);
1973c9566231SKashyap Desai 	} else
1974c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
1975c9566231SKashyap Desai 		    op_req_q->q_segments[0].segment_dma);
1976c9566231SKashyap Desai 	create_req.reply_queue_id = cpu_to_le16(reply_qid);
1977c9566231SKashyap Desai 	create_req.size = cpu_to_le16(op_req_q->num_requests);
1978c9566231SKashyap Desai 
1979c9566231SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
1980c9566231SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &create_req,
1981c9566231SKashyap Desai 	    sizeof(create_req), 1);
1982c9566231SKashyap Desai 	if (retval) {
1983c9566231SKashyap Desai 		ioc_err(mrioc, "CreateReqQ: Admin Post failed\n");
1984c9566231SKashyap Desai 		goto out_unlock;
1985c9566231SKashyap Desai 	}
1986c9566231SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
1987c9566231SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
1988c9566231SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
1989a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "create request queue timed out\n");
1990a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
1991a6856cc4SSreekanth Reddy 		    MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT);
1992c9566231SKashyap Desai 		retval = -1;
1993c9566231SKashyap Desai 		goto out_unlock;
1994c9566231SKashyap Desai 	}
1995c9566231SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
1996c9566231SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
1997c9566231SKashyap Desai 		ioc_err(mrioc,
1998c9566231SKashyap Desai 		    "CreateReqQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
1999c9566231SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
2000c9566231SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
2001c9566231SKashyap Desai 		retval = -1;
2002c9566231SKashyap Desai 		goto out_unlock;
2003c9566231SKashyap Desai 	}
2004c9566231SKashyap Desai 	op_req_q->qid = req_qid;
2005c9566231SKashyap Desai 
2006c9566231SKashyap Desai out_unlock:
2007c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
2008c9566231SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
2009c9566231SKashyap Desai out:
2010c9566231SKashyap Desai 
2011c9566231SKashyap Desai 	return retval;
2012c9566231SKashyap Desai }
2013c9566231SKashyap Desai 
2014c9566231SKashyap Desai /**
2015c9566231SKashyap Desai  * mpi3mr_create_op_queues - create operational queue pairs
2016c9566231SKashyap Desai  * @mrioc: Adapter instance reference
2017c9566231SKashyap Desai  *
2018c9566231SKashyap Desai  * Allocate memory for operational queue meta data and call
2019c9566231SKashyap Desai  * create request and reply queue functions.
2020c9566231SKashyap Desai  *
2021c9566231SKashyap Desai  * Return: 0 on success, non-zero on failures.
2022c9566231SKashyap Desai  */
2023c9566231SKashyap Desai static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc)
2024c9566231SKashyap Desai {
2025c9566231SKashyap Desai 	int retval = 0;
2026c9566231SKashyap Desai 	u16 num_queues = 0, i = 0, msix_count_op_q = 1;
2027c9566231SKashyap Desai 
2028c9566231SKashyap Desai 	num_queues = min_t(int, mrioc->facts.max_op_reply_q,
2029c9566231SKashyap Desai 	    mrioc->facts.max_op_req_q);
2030c9566231SKashyap Desai 
2031c9566231SKashyap Desai 	msix_count_op_q =
2032c9566231SKashyap Desai 	    mrioc->intr_info_count - mrioc->op_reply_q_offset;
2033c9566231SKashyap Desai 	if (!mrioc->num_queues)
2034c9566231SKashyap Desai 		mrioc->num_queues = min_t(int, num_queues, msix_count_op_q);
2035c5758fc7SSreekanth Reddy 	/*
2036c5758fc7SSreekanth Reddy 	 * During reset set the num_queues to the number of queues
2037c5758fc7SSreekanth Reddy 	 * that was set before the reset.
2038c5758fc7SSreekanth Reddy 	 */
2039c5758fc7SSreekanth Reddy 	num_queues = mrioc->num_op_reply_q ?
2040c5758fc7SSreekanth Reddy 	    mrioc->num_op_reply_q : mrioc->num_queues;
2041c5758fc7SSreekanth Reddy 	ioc_info(mrioc, "trying to create %d operational queue pairs\n",
2042c9566231SKashyap Desai 	    num_queues);
2043c9566231SKashyap Desai 
2044c9566231SKashyap Desai 	if (!mrioc->req_qinfo) {
2045c9566231SKashyap Desai 		mrioc->req_qinfo = kcalloc(num_queues,
2046c9566231SKashyap Desai 		    sizeof(struct op_req_qinfo), GFP_KERNEL);
2047c9566231SKashyap Desai 		if (!mrioc->req_qinfo) {
2048c9566231SKashyap Desai 			retval = -1;
2049c9566231SKashyap Desai 			goto out_failed;
2050c9566231SKashyap Desai 		}
2051c9566231SKashyap Desai 
2052c9566231SKashyap Desai 		mrioc->op_reply_qinfo = kzalloc(sizeof(struct op_reply_qinfo) *
2053c9566231SKashyap Desai 		    num_queues, GFP_KERNEL);
2054c9566231SKashyap Desai 		if (!mrioc->op_reply_qinfo) {
2055c9566231SKashyap Desai 			retval = -1;
2056c9566231SKashyap Desai 			goto out_failed;
2057c9566231SKashyap Desai 		}
2058c9566231SKashyap Desai 	}
2059c9566231SKashyap Desai 
2060c9566231SKashyap Desai 	if (mrioc->enable_segqueue)
2061c9566231SKashyap Desai 		ioc_info(mrioc,
2062c9566231SKashyap Desai 		    "allocating operational queues through segmented queues\n");
2063c9566231SKashyap Desai 
2064c9566231SKashyap Desai 	for (i = 0; i < num_queues; i++) {
2065c9566231SKashyap Desai 		if (mpi3mr_create_op_reply_q(mrioc, i)) {
2066c9566231SKashyap Desai 			ioc_err(mrioc, "Cannot create OP RepQ %d\n", i);
2067c9566231SKashyap Desai 			break;
2068c9566231SKashyap Desai 		}
2069c9566231SKashyap Desai 		if (mpi3mr_create_op_req_q(mrioc, i,
2070c9566231SKashyap Desai 		    mrioc->op_reply_qinfo[i].qid)) {
2071c9566231SKashyap Desai 			ioc_err(mrioc, "Cannot create OP ReqQ %d\n", i);
2072c9566231SKashyap Desai 			mpi3mr_delete_op_reply_q(mrioc, i);
2073c9566231SKashyap Desai 			break;
2074c9566231SKashyap Desai 		}
2075c9566231SKashyap Desai 	}
2076c9566231SKashyap Desai 
2077c9566231SKashyap Desai 	if (i == 0) {
2078c9566231SKashyap Desai 		/* Not even one queue is created successfully*/
2079c9566231SKashyap Desai 		retval = -1;
2080c9566231SKashyap Desai 		goto out_failed;
2081c9566231SKashyap Desai 	}
2082c9566231SKashyap Desai 	mrioc->num_op_reply_q = mrioc->num_op_req_q = i;
2083*afd3a579SSreekanth Reddy 	ioc_info(mrioc,
2084*afd3a579SSreekanth Reddy 	    "successfully created %d operational queue pairs(default/polled) queue = (%d/%d)\n",
2085*afd3a579SSreekanth Reddy 	    mrioc->num_op_reply_q, mrioc->default_qcount,
2086*afd3a579SSreekanth Reddy 	    mrioc->active_poll_qcount);
2087c9566231SKashyap Desai 
2088c9566231SKashyap Desai 	return retval;
2089c9566231SKashyap Desai out_failed:
2090c9566231SKashyap Desai 	kfree(mrioc->req_qinfo);
2091c9566231SKashyap Desai 	mrioc->req_qinfo = NULL;
2092c9566231SKashyap Desai 
2093c9566231SKashyap Desai 	kfree(mrioc->op_reply_qinfo);
2094c9566231SKashyap Desai 	mrioc->op_reply_qinfo = NULL;
2095c9566231SKashyap Desai 
2096c9566231SKashyap Desai 	return retval;
2097c9566231SKashyap Desai }
2098c9566231SKashyap Desai 
2099c9566231SKashyap Desai /**
2100023ab2a9SKashyap Desai  * mpi3mr_op_request_post - Post request to operational queue
2101023ab2a9SKashyap Desai  * @mrioc: Adapter reference
2102023ab2a9SKashyap Desai  * @op_req_q: Operational request queue info
2103023ab2a9SKashyap Desai  * @req: MPI3 request
2104023ab2a9SKashyap Desai  *
2105023ab2a9SKashyap Desai  * Post the MPI3 request into operational request queue and
2106023ab2a9SKashyap Desai  * inform the controller, if the queue is full return
2107023ab2a9SKashyap Desai  * appropriate error.
2108023ab2a9SKashyap Desai  *
2109023ab2a9SKashyap Desai  * Return: 0 on success, non-zero on failure.
2110023ab2a9SKashyap Desai  */
2111023ab2a9SKashyap Desai int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc,
2112023ab2a9SKashyap Desai 	struct op_req_qinfo *op_req_q, u8 *req)
2113023ab2a9SKashyap Desai {
2114023ab2a9SKashyap Desai 	u16 pi = 0, max_entries, reply_qidx = 0, midx;
2115023ab2a9SKashyap Desai 	int retval = 0;
2116023ab2a9SKashyap Desai 	unsigned long flags;
2117023ab2a9SKashyap Desai 	u8 *req_entry;
2118023ab2a9SKashyap Desai 	void *segment_base_addr;
2119023ab2a9SKashyap Desai 	u16 req_sz = mrioc->facts.op_req_sz;
2120023ab2a9SKashyap Desai 	struct segments *segments = op_req_q->q_segments;
2121023ab2a9SKashyap Desai 
2122023ab2a9SKashyap Desai 	reply_qidx = op_req_q->reply_qid - 1;
2123023ab2a9SKashyap Desai 
2124023ab2a9SKashyap Desai 	if (mrioc->unrecoverable)
2125023ab2a9SKashyap Desai 		return -EFAULT;
2126023ab2a9SKashyap Desai 
2127023ab2a9SKashyap Desai 	spin_lock_irqsave(&op_req_q->q_lock, flags);
2128023ab2a9SKashyap Desai 	pi = op_req_q->pi;
2129023ab2a9SKashyap Desai 	max_entries = op_req_q->num_requests;
2130023ab2a9SKashyap Desai 
2131023ab2a9SKashyap Desai 	if (mpi3mr_check_req_qfull(op_req_q)) {
2132023ab2a9SKashyap Desai 		midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(
2133023ab2a9SKashyap Desai 		    reply_qidx, mrioc->op_reply_q_offset);
2134*afd3a579SSreekanth Reddy 		mpi3mr_process_op_reply_q(mrioc, mrioc->intr_info[midx].op_reply_q);
2135023ab2a9SKashyap Desai 
2136023ab2a9SKashyap Desai 		if (mpi3mr_check_req_qfull(op_req_q)) {
2137023ab2a9SKashyap Desai 			retval = -EAGAIN;
2138023ab2a9SKashyap Desai 			goto out;
2139023ab2a9SKashyap Desai 		}
2140023ab2a9SKashyap Desai 	}
2141023ab2a9SKashyap Desai 
2142023ab2a9SKashyap Desai 	if (mrioc->reset_in_progress) {
2143023ab2a9SKashyap Desai 		ioc_err(mrioc, "OpReqQ submit reset in progress\n");
2144023ab2a9SKashyap Desai 		retval = -EAGAIN;
2145023ab2a9SKashyap Desai 		goto out;
2146023ab2a9SKashyap Desai 	}
2147023ab2a9SKashyap Desai 
2148023ab2a9SKashyap Desai 	segment_base_addr = segments[pi / op_req_q->segment_qd].segment;
2149023ab2a9SKashyap Desai 	req_entry = (u8 *)segment_base_addr +
2150023ab2a9SKashyap Desai 	    ((pi % op_req_q->segment_qd) * req_sz);
2151023ab2a9SKashyap Desai 
2152023ab2a9SKashyap Desai 	memset(req_entry, 0, req_sz);
2153023ab2a9SKashyap Desai 	memcpy(req_entry, req, MPI3MR_ADMIN_REQ_FRAME_SZ);
2154023ab2a9SKashyap Desai 
2155023ab2a9SKashyap Desai 	if (++pi == max_entries)
2156023ab2a9SKashyap Desai 		pi = 0;
2157023ab2a9SKashyap Desai 	op_req_q->pi = pi;
2158023ab2a9SKashyap Desai 
2159463429f8SKashyap Desai 	if (atomic_inc_return(&mrioc->op_reply_qinfo[reply_qidx].pend_ios)
2160463429f8SKashyap Desai 	    > MPI3MR_IRQ_POLL_TRIGGER_IOCOUNT)
2161463429f8SKashyap Desai 		mrioc->op_reply_qinfo[reply_qidx].enable_irq_poll = true;
2162463429f8SKashyap Desai 
2163023ab2a9SKashyap Desai 	writel(op_req_q->pi,
2164023ab2a9SKashyap Desai 	    &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].producer_index);
2165023ab2a9SKashyap Desai 
2166023ab2a9SKashyap Desai out:
2167023ab2a9SKashyap Desai 	spin_unlock_irqrestore(&op_req_q->q_lock, flags);
2168023ab2a9SKashyap Desai 	return retval;
2169023ab2a9SKashyap Desai }
2170023ab2a9SKashyap Desai 
2171023ab2a9SKashyap Desai /**
2172a6856cc4SSreekanth Reddy  * mpi3mr_check_rh_fault_ioc - check reset history and fault
2173a6856cc4SSreekanth Reddy  * controller
2174a6856cc4SSreekanth Reddy  * @mrioc: Adapter instance reference
2175a6856cc4SSreekanth Reddy  * @reason_code, reason code for the fault.
2176a6856cc4SSreekanth Reddy  *
2177a6856cc4SSreekanth Reddy  * This routine will save snapdump and fault the controller with
2178a6856cc4SSreekanth Reddy  * the given reason code if it is not already in the fault or
2179a6856cc4SSreekanth Reddy  * not asynchronosuly reset. This will be used to handle
2180a6856cc4SSreekanth Reddy  * initilaization time faults/resets/timeout as in those cases
2181a6856cc4SSreekanth Reddy  * immediate soft reset invocation is not required.
2182a6856cc4SSreekanth Reddy  *
2183a6856cc4SSreekanth Reddy  * Return:  None.
2184a6856cc4SSreekanth Reddy  */
2185a6856cc4SSreekanth Reddy void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code)
2186a6856cc4SSreekanth Reddy {
2187a6856cc4SSreekanth Reddy 	u32 ioc_status, host_diagnostic, timeout;
2188a6856cc4SSreekanth Reddy 
2189a6856cc4SSreekanth Reddy 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
2190a6856cc4SSreekanth Reddy 	if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) ||
2191a6856cc4SSreekanth Reddy 	    (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) {
2192a6856cc4SSreekanth Reddy 		mpi3mr_print_fault_info(mrioc);
2193a6856cc4SSreekanth Reddy 		return;
2194a6856cc4SSreekanth Reddy 	}
2195a6856cc4SSreekanth Reddy 	mpi3mr_set_diagsave(mrioc);
2196a6856cc4SSreekanth Reddy 	mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
2197a6856cc4SSreekanth Reddy 	    reason_code);
2198a6856cc4SSreekanth Reddy 	timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10;
2199a6856cc4SSreekanth Reddy 	do {
2200a6856cc4SSreekanth Reddy 		host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic);
2201a6856cc4SSreekanth Reddy 		if (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS))
2202a6856cc4SSreekanth Reddy 			break;
2203a6856cc4SSreekanth Reddy 		msleep(100);
2204a6856cc4SSreekanth Reddy 	} while (--timeout);
2205a6856cc4SSreekanth Reddy }
2206a6856cc4SSreekanth Reddy 
2207a6856cc4SSreekanth Reddy /**
220854dfcffbSKashyap Desai  * mpi3mr_sync_timestamp - Issue time stamp sync request
220954dfcffbSKashyap Desai  * @mrioc: Adapter reference
221054dfcffbSKashyap Desai  *
221154dfcffbSKashyap Desai  * Issue IO unit control MPI request to synchornize firmware
221254dfcffbSKashyap Desai  * timestamp with host time.
221354dfcffbSKashyap Desai  *
221454dfcffbSKashyap Desai  * Return: 0 on success, non-zero on failure.
221554dfcffbSKashyap Desai  */
221654dfcffbSKashyap Desai static int mpi3mr_sync_timestamp(struct mpi3mr_ioc *mrioc)
221754dfcffbSKashyap Desai {
221854dfcffbSKashyap Desai 	ktime_t current_time;
221954dfcffbSKashyap Desai 	struct mpi3_iounit_control_request iou_ctrl;
222054dfcffbSKashyap Desai 	int retval = 0;
222154dfcffbSKashyap Desai 
222254dfcffbSKashyap Desai 	memset(&iou_ctrl, 0, sizeof(iou_ctrl));
222354dfcffbSKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
222454dfcffbSKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
222554dfcffbSKashyap Desai 		retval = -1;
222654dfcffbSKashyap Desai 		ioc_err(mrioc, "Issue IOUCTL time_stamp: command is in use\n");
222754dfcffbSKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
222854dfcffbSKashyap Desai 		goto out;
222954dfcffbSKashyap Desai 	}
223054dfcffbSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
223154dfcffbSKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
223254dfcffbSKashyap Desai 	mrioc->init_cmds.callback = NULL;
223354dfcffbSKashyap Desai 	iou_ctrl.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
223454dfcffbSKashyap Desai 	iou_ctrl.function = MPI3_FUNCTION_IO_UNIT_CONTROL;
223554dfcffbSKashyap Desai 	iou_ctrl.operation = MPI3_CTRL_OP_UPDATE_TIMESTAMP;
223654dfcffbSKashyap Desai 	current_time = ktime_get_real();
223754dfcffbSKashyap Desai 	iou_ctrl.param64[0] = cpu_to_le64(ktime_to_ms(current_time));
223854dfcffbSKashyap Desai 
223954dfcffbSKashyap Desai 	init_completion(&mrioc->init_cmds.done);
224054dfcffbSKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &iou_ctrl,
224154dfcffbSKashyap Desai 	    sizeof(iou_ctrl), 0);
224254dfcffbSKashyap Desai 	if (retval) {
224354dfcffbSKashyap Desai 		ioc_err(mrioc, "Issue IOUCTL time_stamp: Admin Post failed\n");
224454dfcffbSKashyap Desai 		goto out_unlock;
224554dfcffbSKashyap Desai 	}
224654dfcffbSKashyap Desai 
224754dfcffbSKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
224854dfcffbSKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
224954dfcffbSKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
225054dfcffbSKashyap Desai 		ioc_err(mrioc, "Issue IOUCTL time_stamp: command timed out\n");
225154dfcffbSKashyap Desai 		mrioc->init_cmds.is_waiting = 0;
2252fbaa9aa4SSreekanth Reddy 		if (!(mrioc->init_cmds.state & MPI3MR_CMD_RESET))
225354dfcffbSKashyap Desai 			mpi3mr_soft_reset_handler(mrioc,
225454dfcffbSKashyap Desai 			    MPI3MR_RESET_FROM_TSU_TIMEOUT, 1);
225554dfcffbSKashyap Desai 		retval = -1;
225654dfcffbSKashyap Desai 		goto out_unlock;
225754dfcffbSKashyap Desai 	}
225854dfcffbSKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
225954dfcffbSKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
226054dfcffbSKashyap Desai 		ioc_err(mrioc,
226154dfcffbSKashyap Desai 		    "Issue IOUCTL time_stamp: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
226254dfcffbSKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
226354dfcffbSKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
226454dfcffbSKashyap Desai 		retval = -1;
226554dfcffbSKashyap Desai 		goto out_unlock;
226654dfcffbSKashyap Desai 	}
226754dfcffbSKashyap Desai 
226854dfcffbSKashyap Desai out_unlock:
226954dfcffbSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
227054dfcffbSKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
227154dfcffbSKashyap Desai 
227254dfcffbSKashyap Desai out:
227354dfcffbSKashyap Desai 	return retval;
227454dfcffbSKashyap Desai }
227554dfcffbSKashyap Desai 
227654dfcffbSKashyap Desai /**
22772ac794baSSreekanth Reddy  * mpi3mr_print_pkg_ver - display controller fw package version
22782ac794baSSreekanth Reddy  * @mrioc: Adapter reference
22792ac794baSSreekanth Reddy  *
22802ac794baSSreekanth Reddy  * Retrieve firmware package version from the component image
22812ac794baSSreekanth Reddy  * header of the controller flash and display it.
22822ac794baSSreekanth Reddy  *
22832ac794baSSreekanth Reddy  * Return: 0 on success and non-zero on failure.
22842ac794baSSreekanth Reddy  */
22852ac794baSSreekanth Reddy static int mpi3mr_print_pkg_ver(struct mpi3mr_ioc *mrioc)
22862ac794baSSreekanth Reddy {
22872ac794baSSreekanth Reddy 	struct mpi3_ci_upload_request ci_upload;
22882ac794baSSreekanth Reddy 	int retval = -1;
22892ac794baSSreekanth Reddy 	void *data = NULL;
22902ac794baSSreekanth Reddy 	dma_addr_t data_dma;
22912ac794baSSreekanth Reddy 	struct mpi3_ci_manifest_mpi *manifest;
22922ac794baSSreekanth Reddy 	u32 data_len = sizeof(struct mpi3_ci_manifest_mpi);
22932ac794baSSreekanth Reddy 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
22942ac794baSSreekanth Reddy 
22952ac794baSSreekanth Reddy 	data = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma,
22962ac794baSSreekanth Reddy 	    GFP_KERNEL);
22972ac794baSSreekanth Reddy 	if (!data)
22982ac794baSSreekanth Reddy 		return -ENOMEM;
22992ac794baSSreekanth Reddy 
23002ac794baSSreekanth Reddy 	memset(&ci_upload, 0, sizeof(ci_upload));
23012ac794baSSreekanth Reddy 	mutex_lock(&mrioc->init_cmds.mutex);
23022ac794baSSreekanth Reddy 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
23032ac794baSSreekanth Reddy 		ioc_err(mrioc, "sending get package version failed due to command in use\n");
23042ac794baSSreekanth Reddy 		mutex_unlock(&mrioc->init_cmds.mutex);
23052ac794baSSreekanth Reddy 		goto out;
23062ac794baSSreekanth Reddy 	}
23072ac794baSSreekanth Reddy 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
23082ac794baSSreekanth Reddy 	mrioc->init_cmds.is_waiting = 1;
23092ac794baSSreekanth Reddy 	mrioc->init_cmds.callback = NULL;
23102ac794baSSreekanth Reddy 	ci_upload.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
23112ac794baSSreekanth Reddy 	ci_upload.function = MPI3_FUNCTION_CI_UPLOAD;
23122ac794baSSreekanth Reddy 	ci_upload.msg_flags = MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_PRIMARY;
23132ac794baSSreekanth Reddy 	ci_upload.signature1 = cpu_to_le32(MPI3_IMAGE_HEADER_SIGNATURE1_MANIFEST);
23142ac794baSSreekanth Reddy 	ci_upload.image_offset = cpu_to_le32(MPI3_IMAGE_HEADER_SIZE);
23152ac794baSSreekanth Reddy 	ci_upload.segment_size = cpu_to_le32(data_len);
23162ac794baSSreekanth Reddy 
23172ac794baSSreekanth Reddy 	mpi3mr_add_sg_single(&ci_upload.sgl, sgl_flags, data_len,
23182ac794baSSreekanth Reddy 	    data_dma);
23192ac794baSSreekanth Reddy 	init_completion(&mrioc->init_cmds.done);
23202ac794baSSreekanth Reddy 	retval = mpi3mr_admin_request_post(mrioc, &ci_upload,
23212ac794baSSreekanth Reddy 	    sizeof(ci_upload), 1);
23222ac794baSSreekanth Reddy 	if (retval) {
23232ac794baSSreekanth Reddy 		ioc_err(mrioc, "posting get package version failed\n");
23242ac794baSSreekanth Reddy 		goto out_unlock;
23252ac794baSSreekanth Reddy 	}
23262ac794baSSreekanth Reddy 	wait_for_completion_timeout(&mrioc->init_cmds.done,
23272ac794baSSreekanth Reddy 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
23282ac794baSSreekanth Reddy 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
23292ac794baSSreekanth Reddy 		ioc_err(mrioc, "get package version timed out\n");
2330a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
2331a6856cc4SSreekanth Reddy 		    MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT);
23322ac794baSSreekanth Reddy 		retval = -1;
23332ac794baSSreekanth Reddy 		goto out_unlock;
23342ac794baSSreekanth Reddy 	}
23352ac794baSSreekanth Reddy 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
23362ac794baSSreekanth Reddy 	    == MPI3_IOCSTATUS_SUCCESS) {
23372ac794baSSreekanth Reddy 		manifest = (struct mpi3_ci_manifest_mpi *) data;
23382ac794baSSreekanth Reddy 		if (manifest->manifest_type == MPI3_CI_MANIFEST_TYPE_MPI) {
23392ac794baSSreekanth Reddy 			ioc_info(mrioc,
23402ac794baSSreekanth Reddy 			    "firmware package version(%d.%d.%d.%d.%05d-%05d)\n",
23412ac794baSSreekanth Reddy 			    manifest->package_version.gen_major,
23422ac794baSSreekanth Reddy 			    manifest->package_version.gen_minor,
23432ac794baSSreekanth Reddy 			    manifest->package_version.phase_major,
23442ac794baSSreekanth Reddy 			    manifest->package_version.phase_minor,
23452ac794baSSreekanth Reddy 			    manifest->package_version.customer_id,
23462ac794baSSreekanth Reddy 			    manifest->package_version.build_num);
23472ac794baSSreekanth Reddy 		}
23482ac794baSSreekanth Reddy 	}
23492ac794baSSreekanth Reddy 	retval = 0;
23502ac794baSSreekanth Reddy out_unlock:
23512ac794baSSreekanth Reddy 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
23522ac794baSSreekanth Reddy 	mutex_unlock(&mrioc->init_cmds.mutex);
23532ac794baSSreekanth Reddy 
23542ac794baSSreekanth Reddy out:
23552ac794baSSreekanth Reddy 	if (data)
23562ac794baSSreekanth Reddy 		dma_free_coherent(&mrioc->pdev->dev, data_len, data,
23572ac794baSSreekanth Reddy 		    data_dma);
23582ac794baSSreekanth Reddy 	return retval;
23592ac794baSSreekanth Reddy }
23602ac794baSSreekanth Reddy 
23612ac794baSSreekanth Reddy /**
2362672ae26cSKashyap Desai  * mpi3mr_watchdog_work - watchdog thread to monitor faults
2363672ae26cSKashyap Desai  * @work: work struct
2364672ae26cSKashyap Desai  *
2365672ae26cSKashyap Desai  * Watch dog work periodically executed (1 second interval) to
2366672ae26cSKashyap Desai  * monitor firmware fault and to issue periodic timer sync to
2367672ae26cSKashyap Desai  * the firmware.
2368672ae26cSKashyap Desai  *
2369672ae26cSKashyap Desai  * Return: Nothing.
2370672ae26cSKashyap Desai  */
2371672ae26cSKashyap Desai static void mpi3mr_watchdog_work(struct work_struct *work)
2372672ae26cSKashyap Desai {
2373672ae26cSKashyap Desai 	struct mpi3mr_ioc *mrioc =
2374672ae26cSKashyap Desai 	    container_of(work, struct mpi3mr_ioc, watchdog_work.work);
2375672ae26cSKashyap Desai 	unsigned long flags;
2376672ae26cSKashyap Desai 	enum mpi3mr_iocstate ioc_state;
237778b76a07SSreekanth Reddy 	u32 fault, host_diagnostic, ioc_status;
237878b76a07SSreekanth Reddy 	u32 reset_reason = MPI3MR_RESET_FROM_FAULT_WATCH;
2379672ae26cSKashyap Desai 
2380b64845a7SSreekanth Reddy 	if (mrioc->reset_in_progress || mrioc->unrecoverable)
2381b64845a7SSreekanth Reddy 		return;
2382b64845a7SSreekanth Reddy 
238354dfcffbSKashyap Desai 	if (mrioc->ts_update_counter++ >= MPI3MR_TSUPDATE_INTERVAL) {
238454dfcffbSKashyap Desai 		mrioc->ts_update_counter = 0;
238554dfcffbSKashyap Desai 		mpi3mr_sync_timestamp(mrioc);
238654dfcffbSKashyap Desai 	}
238754dfcffbSKashyap Desai 
238878b76a07SSreekanth Reddy 	if ((mrioc->prepare_for_reset) &&
238978b76a07SSreekanth Reddy 	    ((mrioc->prepare_for_reset_timeout_counter++) >=
239078b76a07SSreekanth Reddy 	     MPI3MR_PREPARE_FOR_RESET_TIMEOUT)) {
239178b76a07SSreekanth Reddy 		mpi3mr_soft_reset_handler(mrioc,
239278b76a07SSreekanth Reddy 		    MPI3MR_RESET_FROM_CIACTVRST_TIMER, 1);
239378b76a07SSreekanth Reddy 		return;
239478b76a07SSreekanth Reddy 	}
239578b76a07SSreekanth Reddy 
239678b76a07SSreekanth Reddy 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
239778b76a07SSreekanth Reddy 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) {
239878b76a07SSreekanth Reddy 		mpi3mr_soft_reset_handler(mrioc, MPI3MR_RESET_FROM_FIRMWARE, 0);
239978b76a07SSreekanth Reddy 		return;
240078b76a07SSreekanth Reddy 	}
240178b76a07SSreekanth Reddy 
2402672ae26cSKashyap Desai 	/*Check for fault state every one second and issue Soft reset*/
2403672ae26cSKashyap Desai 	ioc_state = mpi3mr_get_iocstate(mrioc);
240478b76a07SSreekanth Reddy 	if (ioc_state != MRIOC_STATE_FAULT)
240578b76a07SSreekanth Reddy 		goto schedule_work;
240678b76a07SSreekanth Reddy 
240778b76a07SSreekanth Reddy 	fault = readl(&mrioc->sysif_regs->fault) & MPI3_SYSIF_FAULT_CODE_MASK;
2408672ae26cSKashyap Desai 	host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic);
2409672ae26cSKashyap Desai 	if (host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS) {
2410672ae26cSKashyap Desai 		if (!mrioc->diagsave_timeout) {
2411672ae26cSKashyap Desai 			mpi3mr_print_fault_info(mrioc);
241278b76a07SSreekanth Reddy 			ioc_warn(mrioc, "diag save in progress\n");
2413672ae26cSKashyap Desai 		}
241478b76a07SSreekanth Reddy 		if ((mrioc->diagsave_timeout++) <= MPI3_SYSIF_DIAG_SAVE_TIMEOUT)
2415672ae26cSKashyap Desai 			goto schedule_work;
241678b76a07SSreekanth Reddy 	}
241778b76a07SSreekanth Reddy 
2418672ae26cSKashyap Desai 	mpi3mr_print_fault_info(mrioc);
2419672ae26cSKashyap Desai 	mrioc->diagsave_timeout = 0;
2420672ae26cSKashyap Desai 
242178b76a07SSreekanth Reddy 	switch (fault) {
242278b76a07SSreekanth Reddy 	case MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED:
2423672ae26cSKashyap Desai 		ioc_info(mrioc,
242478b76a07SSreekanth Reddy 		    "controller requires system power cycle, marking controller as unrecoverable\n");
2425672ae26cSKashyap Desai 		mrioc->unrecoverable = 1;
242678b76a07SSreekanth Reddy 		return;
242778b76a07SSreekanth Reddy 	case MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS:
242878b76a07SSreekanth Reddy 		return;
242978b76a07SSreekanth Reddy 	case MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET:
243078b76a07SSreekanth Reddy 		reset_reason = MPI3MR_RESET_FROM_CIACTIV_FAULT;
243178b76a07SSreekanth Reddy 		break;
243278b76a07SSreekanth Reddy 	default:
243378b76a07SSreekanth Reddy 		break;
2434672ae26cSKashyap Desai 	}
243578b76a07SSreekanth Reddy 	mpi3mr_soft_reset_handler(mrioc, reset_reason, 0);
243678b76a07SSreekanth Reddy 	return;
2437672ae26cSKashyap Desai 
2438672ae26cSKashyap Desai schedule_work:
2439672ae26cSKashyap Desai 	spin_lock_irqsave(&mrioc->watchdog_lock, flags);
2440672ae26cSKashyap Desai 	if (mrioc->watchdog_work_q)
2441672ae26cSKashyap Desai 		queue_delayed_work(mrioc->watchdog_work_q,
2442672ae26cSKashyap Desai 		    &mrioc->watchdog_work,
2443672ae26cSKashyap Desai 		    msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL));
2444672ae26cSKashyap Desai 	spin_unlock_irqrestore(&mrioc->watchdog_lock, flags);
2445672ae26cSKashyap Desai 	return;
2446672ae26cSKashyap Desai }
2447672ae26cSKashyap Desai 
2448672ae26cSKashyap Desai /**
2449672ae26cSKashyap Desai  * mpi3mr_start_watchdog - Start watchdog
2450672ae26cSKashyap Desai  * @mrioc: Adapter instance reference
2451672ae26cSKashyap Desai  *
2452672ae26cSKashyap Desai  * Create and start the watchdog thread to monitor controller
2453672ae26cSKashyap Desai  * faults.
2454672ae26cSKashyap Desai  *
2455672ae26cSKashyap Desai  * Return: Nothing.
2456672ae26cSKashyap Desai  */
2457672ae26cSKashyap Desai void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc)
2458672ae26cSKashyap Desai {
2459672ae26cSKashyap Desai 	if (mrioc->watchdog_work_q)
2460672ae26cSKashyap Desai 		return;
2461672ae26cSKashyap Desai 
2462672ae26cSKashyap Desai 	INIT_DELAYED_WORK(&mrioc->watchdog_work, mpi3mr_watchdog_work);
2463672ae26cSKashyap Desai 	snprintf(mrioc->watchdog_work_q_name,
2464672ae26cSKashyap Desai 	    sizeof(mrioc->watchdog_work_q_name), "watchdog_%s%d", mrioc->name,
2465672ae26cSKashyap Desai 	    mrioc->id);
2466672ae26cSKashyap Desai 	mrioc->watchdog_work_q =
2467672ae26cSKashyap Desai 	    create_singlethread_workqueue(mrioc->watchdog_work_q_name);
2468672ae26cSKashyap Desai 	if (!mrioc->watchdog_work_q) {
2469672ae26cSKashyap Desai 		ioc_err(mrioc, "%s: failed (line=%d)\n", __func__, __LINE__);
2470672ae26cSKashyap Desai 		return;
2471672ae26cSKashyap Desai 	}
2472672ae26cSKashyap Desai 
2473672ae26cSKashyap Desai 	if (mrioc->watchdog_work_q)
2474672ae26cSKashyap Desai 		queue_delayed_work(mrioc->watchdog_work_q,
2475672ae26cSKashyap Desai 		    &mrioc->watchdog_work,
2476672ae26cSKashyap Desai 		    msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL));
2477672ae26cSKashyap Desai }
2478672ae26cSKashyap Desai 
2479672ae26cSKashyap Desai /**
2480672ae26cSKashyap Desai  * mpi3mr_stop_watchdog - Stop watchdog
2481672ae26cSKashyap Desai  * @mrioc: Adapter instance reference
2482672ae26cSKashyap Desai  *
2483672ae26cSKashyap Desai  * Stop the watchdog thread created to monitor controller
2484672ae26cSKashyap Desai  * faults.
2485672ae26cSKashyap Desai  *
2486672ae26cSKashyap Desai  * Return: Nothing.
2487672ae26cSKashyap Desai  */
2488672ae26cSKashyap Desai void mpi3mr_stop_watchdog(struct mpi3mr_ioc *mrioc)
2489672ae26cSKashyap Desai {
2490672ae26cSKashyap Desai 	unsigned long flags;
2491672ae26cSKashyap Desai 	struct workqueue_struct *wq;
2492672ae26cSKashyap Desai 
2493672ae26cSKashyap Desai 	spin_lock_irqsave(&mrioc->watchdog_lock, flags);
2494672ae26cSKashyap Desai 	wq = mrioc->watchdog_work_q;
2495672ae26cSKashyap Desai 	mrioc->watchdog_work_q = NULL;
2496672ae26cSKashyap Desai 	spin_unlock_irqrestore(&mrioc->watchdog_lock, flags);
2497672ae26cSKashyap Desai 	if (wq) {
2498672ae26cSKashyap Desai 		if (!cancel_delayed_work_sync(&mrioc->watchdog_work))
2499672ae26cSKashyap Desai 			flush_workqueue(wq);
2500672ae26cSKashyap Desai 		destroy_workqueue(wq);
2501672ae26cSKashyap Desai 	}
2502672ae26cSKashyap Desai }
2503672ae26cSKashyap Desai 
2504672ae26cSKashyap Desai /**
2505824a1566SKashyap Desai  * mpi3mr_setup_admin_qpair - Setup admin queue pair
2506824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2507824a1566SKashyap Desai  *
2508824a1566SKashyap Desai  * Allocate memory for admin queue pair if required and register
2509824a1566SKashyap Desai  * the admin queue with the controller.
2510824a1566SKashyap Desai  *
2511824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
2512824a1566SKashyap Desai  */
2513824a1566SKashyap Desai static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc)
2514824a1566SKashyap Desai {
2515824a1566SKashyap Desai 	int retval = 0;
2516824a1566SKashyap Desai 	u32 num_admin_entries = 0;
2517824a1566SKashyap Desai 
2518824a1566SKashyap Desai 	mrioc->admin_req_q_sz = MPI3MR_ADMIN_REQ_Q_SIZE;
2519824a1566SKashyap Desai 	mrioc->num_admin_req = mrioc->admin_req_q_sz /
2520824a1566SKashyap Desai 	    MPI3MR_ADMIN_REQ_FRAME_SZ;
2521824a1566SKashyap Desai 	mrioc->admin_req_ci = mrioc->admin_req_pi = 0;
2522824a1566SKashyap Desai 	mrioc->admin_req_base = NULL;
2523824a1566SKashyap Desai 
2524824a1566SKashyap Desai 	mrioc->admin_reply_q_sz = MPI3MR_ADMIN_REPLY_Q_SIZE;
2525824a1566SKashyap Desai 	mrioc->num_admin_replies = mrioc->admin_reply_q_sz /
2526824a1566SKashyap Desai 	    MPI3MR_ADMIN_REPLY_FRAME_SZ;
2527824a1566SKashyap Desai 	mrioc->admin_reply_ci = 0;
2528824a1566SKashyap Desai 	mrioc->admin_reply_ephase = 1;
2529824a1566SKashyap Desai 	mrioc->admin_reply_base = NULL;
2530824a1566SKashyap Desai 
2531824a1566SKashyap Desai 	if (!mrioc->admin_req_base) {
2532824a1566SKashyap Desai 		mrioc->admin_req_base = dma_alloc_coherent(&mrioc->pdev->dev,
2533824a1566SKashyap Desai 		    mrioc->admin_req_q_sz, &mrioc->admin_req_dma, GFP_KERNEL);
2534824a1566SKashyap Desai 
2535824a1566SKashyap Desai 		if (!mrioc->admin_req_base) {
2536824a1566SKashyap Desai 			retval = -1;
2537824a1566SKashyap Desai 			goto out_failed;
2538824a1566SKashyap Desai 		}
2539824a1566SKashyap Desai 
2540824a1566SKashyap Desai 		mrioc->admin_reply_base = dma_alloc_coherent(&mrioc->pdev->dev,
2541824a1566SKashyap Desai 		    mrioc->admin_reply_q_sz, &mrioc->admin_reply_dma,
2542824a1566SKashyap Desai 		    GFP_KERNEL);
2543824a1566SKashyap Desai 
2544824a1566SKashyap Desai 		if (!mrioc->admin_reply_base) {
2545824a1566SKashyap Desai 			retval = -1;
2546824a1566SKashyap Desai 			goto out_failed;
2547824a1566SKashyap Desai 		}
2548824a1566SKashyap Desai 	}
2549824a1566SKashyap Desai 
2550824a1566SKashyap Desai 	num_admin_entries = (mrioc->num_admin_replies << 16) |
2551824a1566SKashyap Desai 	    (mrioc->num_admin_req);
2552824a1566SKashyap Desai 	writel(num_admin_entries, &mrioc->sysif_regs->admin_queue_num_entries);
2553824a1566SKashyap Desai 	mpi3mr_writeq(mrioc->admin_req_dma,
2554824a1566SKashyap Desai 	    &mrioc->sysif_regs->admin_request_queue_address);
2555824a1566SKashyap Desai 	mpi3mr_writeq(mrioc->admin_reply_dma,
2556824a1566SKashyap Desai 	    &mrioc->sysif_regs->admin_reply_queue_address);
2557824a1566SKashyap Desai 	writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi);
2558824a1566SKashyap Desai 	writel(mrioc->admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci);
2559824a1566SKashyap Desai 	return retval;
2560824a1566SKashyap Desai 
2561824a1566SKashyap Desai out_failed:
2562824a1566SKashyap Desai 
2563824a1566SKashyap Desai 	if (mrioc->admin_reply_base) {
2564824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz,
2565824a1566SKashyap Desai 		    mrioc->admin_reply_base, mrioc->admin_reply_dma);
2566824a1566SKashyap Desai 		mrioc->admin_reply_base = NULL;
2567824a1566SKashyap Desai 	}
2568824a1566SKashyap Desai 	if (mrioc->admin_req_base) {
2569824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz,
2570824a1566SKashyap Desai 		    mrioc->admin_req_base, mrioc->admin_req_dma);
2571824a1566SKashyap Desai 		mrioc->admin_req_base = NULL;
2572824a1566SKashyap Desai 	}
2573824a1566SKashyap Desai 	return retval;
2574824a1566SKashyap Desai }
2575824a1566SKashyap Desai 
2576824a1566SKashyap Desai /**
2577824a1566SKashyap Desai  * mpi3mr_issue_iocfacts - Send IOC Facts
2578824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2579824a1566SKashyap Desai  * @facts_data: Cached IOC facts data
2580824a1566SKashyap Desai  *
2581824a1566SKashyap Desai  * Issue IOC Facts MPI request through admin queue and wait for
2582824a1566SKashyap Desai  * the completion of it or time out.
2583824a1566SKashyap Desai  *
2584824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
2585824a1566SKashyap Desai  */
2586824a1566SKashyap Desai static int mpi3mr_issue_iocfacts(struct mpi3mr_ioc *mrioc,
2587824a1566SKashyap Desai 	struct mpi3_ioc_facts_data *facts_data)
2588824a1566SKashyap Desai {
2589824a1566SKashyap Desai 	struct mpi3_ioc_facts_request iocfacts_req;
2590824a1566SKashyap Desai 	void *data = NULL;
2591824a1566SKashyap Desai 	dma_addr_t data_dma;
2592824a1566SKashyap Desai 	u32 data_len = sizeof(*facts_data);
2593824a1566SKashyap Desai 	int retval = 0;
2594824a1566SKashyap Desai 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
2595824a1566SKashyap Desai 
2596824a1566SKashyap Desai 	data = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma,
2597824a1566SKashyap Desai 	    GFP_KERNEL);
2598824a1566SKashyap Desai 
2599824a1566SKashyap Desai 	if (!data) {
2600824a1566SKashyap Desai 		retval = -1;
2601824a1566SKashyap Desai 		goto out;
2602824a1566SKashyap Desai 	}
2603824a1566SKashyap Desai 
2604824a1566SKashyap Desai 	memset(&iocfacts_req, 0, sizeof(iocfacts_req));
2605824a1566SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
2606824a1566SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
2607824a1566SKashyap Desai 		retval = -1;
2608824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCFacts: Init command is in use\n");
2609824a1566SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
2610824a1566SKashyap Desai 		goto out;
2611824a1566SKashyap Desai 	}
2612824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
2613824a1566SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
2614824a1566SKashyap Desai 	mrioc->init_cmds.callback = NULL;
2615824a1566SKashyap Desai 	iocfacts_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
2616824a1566SKashyap Desai 	iocfacts_req.function = MPI3_FUNCTION_IOC_FACTS;
2617824a1566SKashyap Desai 
2618824a1566SKashyap Desai 	mpi3mr_add_sg_single(&iocfacts_req.sgl, sgl_flags, data_len,
2619824a1566SKashyap Desai 	    data_dma);
2620824a1566SKashyap Desai 
2621824a1566SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
2622824a1566SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &iocfacts_req,
2623824a1566SKashyap Desai 	    sizeof(iocfacts_req), 1);
2624824a1566SKashyap Desai 	if (retval) {
2625824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCFacts: Admin Post failed\n");
2626824a1566SKashyap Desai 		goto out_unlock;
2627824a1566SKashyap Desai 	}
2628824a1566SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
2629824a1566SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
2630824a1566SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
2631a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "ioc_facts timed out\n");
2632a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
2633824a1566SKashyap Desai 		    MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT);
2634824a1566SKashyap Desai 		retval = -1;
2635824a1566SKashyap Desai 		goto out_unlock;
2636824a1566SKashyap Desai 	}
2637824a1566SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
2638824a1566SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
2639824a1566SKashyap Desai 		ioc_err(mrioc,
2640824a1566SKashyap Desai 		    "Issue IOCFacts: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
2641824a1566SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
2642824a1566SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
2643824a1566SKashyap Desai 		retval = -1;
2644824a1566SKashyap Desai 		goto out_unlock;
2645824a1566SKashyap Desai 	}
2646824a1566SKashyap Desai 	memcpy(facts_data, (u8 *)data, data_len);
2647c5758fc7SSreekanth Reddy 	mpi3mr_process_factsdata(mrioc, facts_data);
2648824a1566SKashyap Desai out_unlock:
2649824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
2650824a1566SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
2651824a1566SKashyap Desai 
2652824a1566SKashyap Desai out:
2653824a1566SKashyap Desai 	if (data)
2654824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, data_len, data, data_dma);
2655824a1566SKashyap Desai 
2656824a1566SKashyap Desai 	return retval;
2657824a1566SKashyap Desai }
2658824a1566SKashyap Desai 
2659824a1566SKashyap Desai /**
2660824a1566SKashyap Desai  * mpi3mr_check_reset_dma_mask - Process IOC facts data
2661824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2662824a1566SKashyap Desai  *
2663824a1566SKashyap Desai  * Check whether the new DMA mask requested through IOCFacts by
2664824a1566SKashyap Desai  * firmware needs to be set, if so set it .
2665824a1566SKashyap Desai  *
2666824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
2667824a1566SKashyap Desai  */
2668824a1566SKashyap Desai static inline int mpi3mr_check_reset_dma_mask(struct mpi3mr_ioc *mrioc)
2669824a1566SKashyap Desai {
2670824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
2671824a1566SKashyap Desai 	int r;
2672824a1566SKashyap Desai 	u64 facts_dma_mask = DMA_BIT_MASK(mrioc->facts.dma_mask);
2673824a1566SKashyap Desai 
2674824a1566SKashyap Desai 	if (!mrioc->facts.dma_mask || (mrioc->dma_mask <= facts_dma_mask))
2675824a1566SKashyap Desai 		return 0;
2676824a1566SKashyap Desai 
2677824a1566SKashyap Desai 	ioc_info(mrioc, "Changing DMA mask from 0x%016llx to 0x%016llx\n",
2678824a1566SKashyap Desai 	    mrioc->dma_mask, facts_dma_mask);
2679824a1566SKashyap Desai 
2680824a1566SKashyap Desai 	r = dma_set_mask_and_coherent(&pdev->dev, facts_dma_mask);
2681824a1566SKashyap Desai 	if (r) {
2682824a1566SKashyap Desai 		ioc_err(mrioc, "Setting DMA mask to 0x%016llx failed: %d\n",
2683824a1566SKashyap Desai 		    facts_dma_mask, r);
2684824a1566SKashyap Desai 		return r;
2685824a1566SKashyap Desai 	}
2686824a1566SKashyap Desai 	mrioc->dma_mask = facts_dma_mask;
2687824a1566SKashyap Desai 	return r;
2688824a1566SKashyap Desai }
2689824a1566SKashyap Desai 
2690824a1566SKashyap Desai /**
2691824a1566SKashyap Desai  * mpi3mr_process_factsdata - Process IOC facts data
2692824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2693824a1566SKashyap Desai  * @facts_data: Cached IOC facts data
2694824a1566SKashyap Desai  *
2695824a1566SKashyap Desai  * Convert IOC facts data into cpu endianness and cache it in
2696824a1566SKashyap Desai  * the driver .
2697824a1566SKashyap Desai  *
2698824a1566SKashyap Desai  * Return: Nothing.
2699824a1566SKashyap Desai  */
2700824a1566SKashyap Desai static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc,
2701824a1566SKashyap Desai 	struct mpi3_ioc_facts_data *facts_data)
2702824a1566SKashyap Desai {
2703824a1566SKashyap Desai 	u32 ioc_config, req_sz, facts_flags;
2704824a1566SKashyap Desai 
2705824a1566SKashyap Desai 	if ((le16_to_cpu(facts_data->ioc_facts_data_length)) !=
2706824a1566SKashyap Desai 	    (sizeof(*facts_data) / 4)) {
2707824a1566SKashyap Desai 		ioc_warn(mrioc,
2708824a1566SKashyap Desai 		    "IOCFactsdata length mismatch driver_sz(%zu) firmware_sz(%d)\n",
2709824a1566SKashyap Desai 		    sizeof(*facts_data),
2710824a1566SKashyap Desai 		    le16_to_cpu(facts_data->ioc_facts_data_length) * 4);
2711824a1566SKashyap Desai 	}
2712824a1566SKashyap Desai 
2713824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
2714824a1566SKashyap Desai 	req_sz = 1 << ((ioc_config & MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ) >>
2715824a1566SKashyap Desai 	    MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ_SHIFT);
2716824a1566SKashyap Desai 	if (le16_to_cpu(facts_data->ioc_request_frame_size) != (req_sz / 4)) {
2717824a1566SKashyap Desai 		ioc_err(mrioc,
2718824a1566SKashyap Desai 		    "IOCFacts data reqFrameSize mismatch hw_size(%d) firmware_sz(%d)\n",
2719824a1566SKashyap Desai 		    req_sz / 4, le16_to_cpu(facts_data->ioc_request_frame_size));
2720824a1566SKashyap Desai 	}
2721824a1566SKashyap Desai 
2722824a1566SKashyap Desai 	memset(&mrioc->facts, 0, sizeof(mrioc->facts));
2723824a1566SKashyap Desai 
2724824a1566SKashyap Desai 	facts_flags = le32_to_cpu(facts_data->flags);
2725824a1566SKashyap Desai 	mrioc->facts.op_req_sz = req_sz;
2726824a1566SKashyap Desai 	mrioc->op_reply_desc_sz = 1 << ((ioc_config &
2727824a1566SKashyap Desai 	    MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ) >>
2728824a1566SKashyap Desai 	    MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ_SHIFT);
2729824a1566SKashyap Desai 
2730824a1566SKashyap Desai 	mrioc->facts.ioc_num = facts_data->ioc_number;
2731824a1566SKashyap Desai 	mrioc->facts.who_init = facts_data->who_init;
2732824a1566SKashyap Desai 	mrioc->facts.max_msix_vectors = le16_to_cpu(facts_data->max_msix_vectors);
2733824a1566SKashyap Desai 	mrioc->facts.personality = (facts_flags &
2734824a1566SKashyap Desai 	    MPI3_IOCFACTS_FLAGS_PERSONALITY_MASK);
2735824a1566SKashyap Desai 	mrioc->facts.dma_mask = (facts_flags &
2736824a1566SKashyap Desai 	    MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >>
2737824a1566SKashyap Desai 	    MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT;
2738824a1566SKashyap Desai 	mrioc->facts.protocol_flags = facts_data->protocol_flags;
2739824a1566SKashyap Desai 	mrioc->facts.mpi_version = le32_to_cpu(facts_data->mpi_version.word);
2740824a1566SKashyap Desai 	mrioc->facts.max_reqs = le16_to_cpu(facts_data->max_outstanding_request);
2741824a1566SKashyap Desai 	mrioc->facts.product_id = le16_to_cpu(facts_data->product_id);
2742824a1566SKashyap Desai 	mrioc->facts.reply_sz = le16_to_cpu(facts_data->reply_frame_size) * 4;
2743824a1566SKashyap Desai 	mrioc->facts.exceptions = le16_to_cpu(facts_data->ioc_exceptions);
2744824a1566SKashyap Desai 	mrioc->facts.max_perids = le16_to_cpu(facts_data->max_persistent_id);
2745824a1566SKashyap Desai 	mrioc->facts.max_vds = le16_to_cpu(facts_data->max_vds);
2746824a1566SKashyap Desai 	mrioc->facts.max_hpds = le16_to_cpu(facts_data->max_host_pds);
2747ec5ebd2cSSreekanth Reddy 	mrioc->facts.max_advhpds = le16_to_cpu(facts_data->max_adv_host_pds);
2748ec5ebd2cSSreekanth Reddy 	mrioc->facts.max_raid_pds = le16_to_cpu(facts_data->max_raid_pds);
2749824a1566SKashyap Desai 	mrioc->facts.max_nvme = le16_to_cpu(facts_data->max_nvme);
2750824a1566SKashyap Desai 	mrioc->facts.max_pcie_switches =
2751ec5ebd2cSSreekanth Reddy 	    le16_to_cpu(facts_data->max_pcie_switches);
2752824a1566SKashyap Desai 	mrioc->facts.max_sasexpanders =
2753824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_sas_expanders);
2754824a1566SKashyap Desai 	mrioc->facts.max_sasinitiators =
2755824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_sas_initiators);
2756824a1566SKashyap Desai 	mrioc->facts.max_enclosures = le16_to_cpu(facts_data->max_enclosures);
2757824a1566SKashyap Desai 	mrioc->facts.min_devhandle = le16_to_cpu(facts_data->min_dev_handle);
2758824a1566SKashyap Desai 	mrioc->facts.max_devhandle = le16_to_cpu(facts_data->max_dev_handle);
2759824a1566SKashyap Desai 	mrioc->facts.max_op_req_q =
2760824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_operational_request_queues);
2761824a1566SKashyap Desai 	mrioc->facts.max_op_reply_q =
2762824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_operational_reply_queues);
2763824a1566SKashyap Desai 	mrioc->facts.ioc_capabilities =
2764824a1566SKashyap Desai 	    le32_to_cpu(facts_data->ioc_capabilities);
2765824a1566SKashyap Desai 	mrioc->facts.fw_ver.build_num =
2766824a1566SKashyap Desai 	    le16_to_cpu(facts_data->fw_version.build_num);
2767824a1566SKashyap Desai 	mrioc->facts.fw_ver.cust_id =
2768824a1566SKashyap Desai 	    le16_to_cpu(facts_data->fw_version.customer_id);
2769824a1566SKashyap Desai 	mrioc->facts.fw_ver.ph_minor = facts_data->fw_version.phase_minor;
2770824a1566SKashyap Desai 	mrioc->facts.fw_ver.ph_major = facts_data->fw_version.phase_major;
2771824a1566SKashyap Desai 	mrioc->facts.fw_ver.gen_minor = facts_data->fw_version.gen_minor;
2772824a1566SKashyap Desai 	mrioc->facts.fw_ver.gen_major = facts_data->fw_version.gen_major;
2773824a1566SKashyap Desai 	mrioc->msix_count = min_t(int, mrioc->msix_count,
2774824a1566SKashyap Desai 	    mrioc->facts.max_msix_vectors);
2775824a1566SKashyap Desai 	mrioc->facts.sge_mod_mask = facts_data->sge_modifier_mask;
2776824a1566SKashyap Desai 	mrioc->facts.sge_mod_value = facts_data->sge_modifier_value;
2777824a1566SKashyap Desai 	mrioc->facts.sge_mod_shift = facts_data->sge_modifier_shift;
2778824a1566SKashyap Desai 	mrioc->facts.shutdown_timeout =
2779824a1566SKashyap Desai 	    le16_to_cpu(facts_data->shutdown_timeout);
2780824a1566SKashyap Desai 
2781824a1566SKashyap Desai 	ioc_info(mrioc, "ioc_num(%d), maxopQ(%d), maxopRepQ(%d), maxdh(%d),",
2782824a1566SKashyap Desai 	    mrioc->facts.ioc_num, mrioc->facts.max_op_req_q,
2783824a1566SKashyap Desai 	    mrioc->facts.max_op_reply_q, mrioc->facts.max_devhandle);
2784824a1566SKashyap Desai 	ioc_info(mrioc,
2785ec5ebd2cSSreekanth Reddy 	    "maxreqs(%d), mindh(%d) maxvectors(%d) maxperids(%d)\n",
2786824a1566SKashyap Desai 	    mrioc->facts.max_reqs, mrioc->facts.min_devhandle,
2787ec5ebd2cSSreekanth Reddy 	    mrioc->facts.max_msix_vectors, mrioc->facts.max_perids);
2788824a1566SKashyap Desai 	ioc_info(mrioc, "SGEModMask 0x%x SGEModVal 0x%x SGEModShift 0x%x ",
2789824a1566SKashyap Desai 	    mrioc->facts.sge_mod_mask, mrioc->facts.sge_mod_value,
2790824a1566SKashyap Desai 	    mrioc->facts.sge_mod_shift);
2791824a1566SKashyap Desai 	ioc_info(mrioc, "DMA mask %d InitialPE status 0x%x\n",
2792824a1566SKashyap Desai 	    mrioc->facts.dma_mask, (facts_flags &
2793824a1566SKashyap Desai 	    MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK));
2794824a1566SKashyap Desai }
2795824a1566SKashyap Desai 
2796824a1566SKashyap Desai /**
2797824a1566SKashyap Desai  * mpi3mr_alloc_reply_sense_bufs - Send IOC Init
2798824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2799824a1566SKashyap Desai  *
2800824a1566SKashyap Desai  * Allocate and initialize the reply free buffers, sense
2801824a1566SKashyap Desai  * buffers, reply free queue and sense buffer queue.
2802824a1566SKashyap Desai  *
2803824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
2804824a1566SKashyap Desai  */
2805824a1566SKashyap Desai static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc)
2806824a1566SKashyap Desai {
2807824a1566SKashyap Desai 	int retval = 0;
2808824a1566SKashyap Desai 	u32 sz, i;
2809824a1566SKashyap Desai 
2810824a1566SKashyap Desai 	if (mrioc->init_cmds.reply)
2811e3605f65SSreekanth Reddy 		return retval;
2812824a1566SKashyap Desai 
2813c5758fc7SSreekanth Reddy 	mrioc->init_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL);
2814824a1566SKashyap Desai 	if (!mrioc->init_cmds.reply)
2815824a1566SKashyap Desai 		goto out_failed;
2816824a1566SKashyap Desai 
281713ef29eaSKashyap Desai 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
2818c5758fc7SSreekanth Reddy 		mrioc->dev_rmhs_cmds[i].reply = kzalloc(mrioc->reply_sz,
281913ef29eaSKashyap Desai 		    GFP_KERNEL);
282013ef29eaSKashyap Desai 		if (!mrioc->dev_rmhs_cmds[i].reply)
282113ef29eaSKashyap Desai 			goto out_failed;
282213ef29eaSKashyap Desai 	}
282313ef29eaSKashyap Desai 
2824c1af985dSSreekanth Reddy 	for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) {
2825c1af985dSSreekanth Reddy 		mrioc->evtack_cmds[i].reply = kzalloc(mrioc->reply_sz,
2826c1af985dSSreekanth Reddy 		    GFP_KERNEL);
2827c1af985dSSreekanth Reddy 		if (!mrioc->evtack_cmds[i].reply)
2828c1af985dSSreekanth Reddy 			goto out_failed;
2829c1af985dSSreekanth Reddy 	}
2830c1af985dSSreekanth Reddy 
2831c5758fc7SSreekanth Reddy 	mrioc->host_tm_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL);
2832e844adb1SKashyap Desai 	if (!mrioc->host_tm_cmds.reply)
2833e844adb1SKashyap Desai 		goto out_failed;
2834e844adb1SKashyap Desai 
2835e844adb1SKashyap Desai 	mrioc->dev_handle_bitmap_sz = mrioc->facts.max_devhandle / 8;
2836e844adb1SKashyap Desai 	if (mrioc->facts.max_devhandle % 8)
2837e844adb1SKashyap Desai 		mrioc->dev_handle_bitmap_sz++;
2838e844adb1SKashyap Desai 	mrioc->removepend_bitmap = kzalloc(mrioc->dev_handle_bitmap_sz,
2839e844adb1SKashyap Desai 	    GFP_KERNEL);
2840e844adb1SKashyap Desai 	if (!mrioc->removepend_bitmap)
2841e844adb1SKashyap Desai 		goto out_failed;
2842e844adb1SKashyap Desai 
2843e844adb1SKashyap Desai 	mrioc->devrem_bitmap_sz = MPI3MR_NUM_DEVRMCMD / 8;
2844e844adb1SKashyap Desai 	if (MPI3MR_NUM_DEVRMCMD % 8)
2845e844adb1SKashyap Desai 		mrioc->devrem_bitmap_sz++;
2846e844adb1SKashyap Desai 	mrioc->devrem_bitmap = kzalloc(mrioc->devrem_bitmap_sz,
2847e844adb1SKashyap Desai 	    GFP_KERNEL);
2848e844adb1SKashyap Desai 	if (!mrioc->devrem_bitmap)
2849e844adb1SKashyap Desai 		goto out_failed;
2850e844adb1SKashyap Desai 
2851c1af985dSSreekanth Reddy 	mrioc->evtack_cmds_bitmap_sz = MPI3MR_NUM_EVTACKCMD / 8;
2852c1af985dSSreekanth Reddy 	if (MPI3MR_NUM_EVTACKCMD % 8)
2853c1af985dSSreekanth Reddy 		mrioc->evtack_cmds_bitmap_sz++;
2854c1af985dSSreekanth Reddy 	mrioc->evtack_cmds_bitmap = kzalloc(mrioc->evtack_cmds_bitmap_sz,
2855c1af985dSSreekanth Reddy 	    GFP_KERNEL);
2856c1af985dSSreekanth Reddy 	if (!mrioc->evtack_cmds_bitmap)
2857c1af985dSSreekanth Reddy 		goto out_failed;
2858c1af985dSSreekanth Reddy 
2859824a1566SKashyap Desai 	mrioc->num_reply_bufs = mrioc->facts.max_reqs + MPI3MR_NUM_EVT_REPLIES;
2860824a1566SKashyap Desai 	mrioc->reply_free_qsz = mrioc->num_reply_bufs + 1;
2861824a1566SKashyap Desai 	mrioc->num_sense_bufs = mrioc->facts.max_reqs / MPI3MR_SENSEBUF_FACTOR;
2862824a1566SKashyap Desai 	mrioc->sense_buf_q_sz = mrioc->num_sense_bufs + 1;
2863824a1566SKashyap Desai 
2864824a1566SKashyap Desai 	/* reply buffer pool, 16 byte align */
2865c5758fc7SSreekanth Reddy 	sz = mrioc->num_reply_bufs * mrioc->reply_sz;
2866824a1566SKashyap Desai 	mrioc->reply_buf_pool = dma_pool_create("reply_buf pool",
2867824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 16, 0);
2868824a1566SKashyap Desai 	if (!mrioc->reply_buf_pool) {
2869824a1566SKashyap Desai 		ioc_err(mrioc, "reply buf pool: dma_pool_create failed\n");
2870824a1566SKashyap Desai 		goto out_failed;
2871824a1566SKashyap Desai 	}
2872824a1566SKashyap Desai 
2873824a1566SKashyap Desai 	mrioc->reply_buf = dma_pool_zalloc(mrioc->reply_buf_pool, GFP_KERNEL,
2874824a1566SKashyap Desai 	    &mrioc->reply_buf_dma);
2875824a1566SKashyap Desai 	if (!mrioc->reply_buf)
2876824a1566SKashyap Desai 		goto out_failed;
2877824a1566SKashyap Desai 
2878824a1566SKashyap Desai 	mrioc->reply_buf_dma_max_address = mrioc->reply_buf_dma + sz;
2879824a1566SKashyap Desai 
2880824a1566SKashyap Desai 	/* reply free queue, 8 byte align */
2881824a1566SKashyap Desai 	sz = mrioc->reply_free_qsz * 8;
2882824a1566SKashyap Desai 	mrioc->reply_free_q_pool = dma_pool_create("reply_free_q pool",
2883824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 8, 0);
2884824a1566SKashyap Desai 	if (!mrioc->reply_free_q_pool) {
2885824a1566SKashyap Desai 		ioc_err(mrioc, "reply_free_q pool: dma_pool_create failed\n");
2886824a1566SKashyap Desai 		goto out_failed;
2887824a1566SKashyap Desai 	}
2888824a1566SKashyap Desai 	mrioc->reply_free_q = dma_pool_zalloc(mrioc->reply_free_q_pool,
2889824a1566SKashyap Desai 	    GFP_KERNEL, &mrioc->reply_free_q_dma);
2890824a1566SKashyap Desai 	if (!mrioc->reply_free_q)
2891824a1566SKashyap Desai 		goto out_failed;
2892824a1566SKashyap Desai 
2893824a1566SKashyap Desai 	/* sense buffer pool,  4 byte align */
2894ec5ebd2cSSreekanth Reddy 	sz = mrioc->num_sense_bufs * MPI3MR_SENSE_BUF_SZ;
2895824a1566SKashyap Desai 	mrioc->sense_buf_pool = dma_pool_create("sense_buf pool",
2896824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 4, 0);
2897824a1566SKashyap Desai 	if (!mrioc->sense_buf_pool) {
2898824a1566SKashyap Desai 		ioc_err(mrioc, "sense_buf pool: dma_pool_create failed\n");
2899824a1566SKashyap Desai 		goto out_failed;
2900824a1566SKashyap Desai 	}
2901824a1566SKashyap Desai 	mrioc->sense_buf = dma_pool_zalloc(mrioc->sense_buf_pool, GFP_KERNEL,
2902824a1566SKashyap Desai 	    &mrioc->sense_buf_dma);
2903824a1566SKashyap Desai 	if (!mrioc->sense_buf)
2904824a1566SKashyap Desai 		goto out_failed;
2905824a1566SKashyap Desai 
2906824a1566SKashyap Desai 	/* sense buffer queue, 8 byte align */
2907824a1566SKashyap Desai 	sz = mrioc->sense_buf_q_sz * 8;
2908824a1566SKashyap Desai 	mrioc->sense_buf_q_pool = dma_pool_create("sense_buf_q pool",
2909824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 8, 0);
2910824a1566SKashyap Desai 	if (!mrioc->sense_buf_q_pool) {
2911824a1566SKashyap Desai 		ioc_err(mrioc, "sense_buf_q pool: dma_pool_create failed\n");
2912824a1566SKashyap Desai 		goto out_failed;
2913824a1566SKashyap Desai 	}
2914824a1566SKashyap Desai 	mrioc->sense_buf_q = dma_pool_zalloc(mrioc->sense_buf_q_pool,
2915824a1566SKashyap Desai 	    GFP_KERNEL, &mrioc->sense_buf_q_dma);
2916824a1566SKashyap Desai 	if (!mrioc->sense_buf_q)
2917824a1566SKashyap Desai 		goto out_failed;
2918824a1566SKashyap Desai 
2919e3605f65SSreekanth Reddy 	return retval;
2920e3605f65SSreekanth Reddy 
2921e3605f65SSreekanth Reddy out_failed:
2922e3605f65SSreekanth Reddy 	retval = -1;
2923e3605f65SSreekanth Reddy 	return retval;
2924e3605f65SSreekanth Reddy }
2925e3605f65SSreekanth Reddy 
2926e3605f65SSreekanth Reddy /**
2927e3605f65SSreekanth Reddy  * mpimr_initialize_reply_sbuf_queues - initialize reply sense
2928e3605f65SSreekanth Reddy  * buffers
2929e3605f65SSreekanth Reddy  * @mrioc: Adapter instance reference
2930e3605f65SSreekanth Reddy  *
2931e3605f65SSreekanth Reddy  * Helper function to initialize reply and sense buffers along
2932e3605f65SSreekanth Reddy  * with some debug prints.
2933e3605f65SSreekanth Reddy  *
2934e3605f65SSreekanth Reddy  * Return:  None.
2935e3605f65SSreekanth Reddy  */
2936e3605f65SSreekanth Reddy static void mpimr_initialize_reply_sbuf_queues(struct mpi3mr_ioc *mrioc)
2937e3605f65SSreekanth Reddy {
2938e3605f65SSreekanth Reddy 	u32 sz, i;
2939e3605f65SSreekanth Reddy 	dma_addr_t phy_addr;
2940e3605f65SSreekanth Reddy 
2941c5758fc7SSreekanth Reddy 	sz = mrioc->num_reply_bufs * mrioc->reply_sz;
2942824a1566SKashyap Desai 	ioc_info(mrioc,
2943824a1566SKashyap Desai 	    "reply buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n",
2944c5758fc7SSreekanth Reddy 	    mrioc->reply_buf, mrioc->num_reply_bufs, mrioc->reply_sz,
2945824a1566SKashyap Desai 	    (sz / 1024), (unsigned long long)mrioc->reply_buf_dma);
2946824a1566SKashyap Desai 	sz = mrioc->reply_free_qsz * 8;
2947824a1566SKashyap Desai 	ioc_info(mrioc,
2948824a1566SKashyap Desai 	    "reply_free_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n",
2949824a1566SKashyap Desai 	    mrioc->reply_free_q, mrioc->reply_free_qsz, 8, (sz / 1024),
2950824a1566SKashyap Desai 	    (unsigned long long)mrioc->reply_free_q_dma);
2951ec5ebd2cSSreekanth Reddy 	sz = mrioc->num_sense_bufs * MPI3MR_SENSE_BUF_SZ;
2952824a1566SKashyap Desai 	ioc_info(mrioc,
2953824a1566SKashyap Desai 	    "sense_buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n",
2954ec5ebd2cSSreekanth Reddy 	    mrioc->sense_buf, mrioc->num_sense_bufs, MPI3MR_SENSE_BUF_SZ,
2955824a1566SKashyap Desai 	    (sz / 1024), (unsigned long long)mrioc->sense_buf_dma);
2956824a1566SKashyap Desai 	sz = mrioc->sense_buf_q_sz * 8;
2957824a1566SKashyap Desai 	ioc_info(mrioc,
2958824a1566SKashyap Desai 	    "sense_buf_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n",
2959824a1566SKashyap Desai 	    mrioc->sense_buf_q, mrioc->sense_buf_q_sz, 8, (sz / 1024),
2960824a1566SKashyap Desai 	    (unsigned long long)mrioc->sense_buf_q_dma);
2961824a1566SKashyap Desai 
2962824a1566SKashyap Desai 	/* initialize Reply buffer Queue */
2963824a1566SKashyap Desai 	for (i = 0, phy_addr = mrioc->reply_buf_dma;
2964c5758fc7SSreekanth Reddy 	    i < mrioc->num_reply_bufs; i++, phy_addr += mrioc->reply_sz)
2965824a1566SKashyap Desai 		mrioc->reply_free_q[i] = cpu_to_le64(phy_addr);
2966824a1566SKashyap Desai 	mrioc->reply_free_q[i] = cpu_to_le64(0);
2967824a1566SKashyap Desai 
2968824a1566SKashyap Desai 	/* initialize Sense Buffer Queue */
2969824a1566SKashyap Desai 	for (i = 0, phy_addr = mrioc->sense_buf_dma;
2970ec5ebd2cSSreekanth Reddy 	    i < mrioc->num_sense_bufs; i++, phy_addr += MPI3MR_SENSE_BUF_SZ)
2971824a1566SKashyap Desai 		mrioc->sense_buf_q[i] = cpu_to_le64(phy_addr);
2972824a1566SKashyap Desai 	mrioc->sense_buf_q[i] = cpu_to_le64(0);
2973824a1566SKashyap Desai }
2974824a1566SKashyap Desai 
2975824a1566SKashyap Desai /**
2976824a1566SKashyap Desai  * mpi3mr_issue_iocinit - Send IOC Init
2977824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2978824a1566SKashyap Desai  *
2979824a1566SKashyap Desai  * Issue IOC Init MPI request through admin queue and wait for
2980824a1566SKashyap Desai  * the completion of it or time out.
2981824a1566SKashyap Desai  *
2982824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
2983824a1566SKashyap Desai  */
2984824a1566SKashyap Desai static int mpi3mr_issue_iocinit(struct mpi3mr_ioc *mrioc)
2985824a1566SKashyap Desai {
2986824a1566SKashyap Desai 	struct mpi3_ioc_init_request iocinit_req;
2987824a1566SKashyap Desai 	struct mpi3_driver_info_layout *drv_info;
2988824a1566SKashyap Desai 	dma_addr_t data_dma;
2989824a1566SKashyap Desai 	u32 data_len = sizeof(*drv_info);
2990824a1566SKashyap Desai 	int retval = 0;
2991824a1566SKashyap Desai 	ktime_t current_time;
2992824a1566SKashyap Desai 
2993824a1566SKashyap Desai 	drv_info = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma,
2994824a1566SKashyap Desai 	    GFP_KERNEL);
2995824a1566SKashyap Desai 	if (!drv_info) {
2996824a1566SKashyap Desai 		retval = -1;
2997824a1566SKashyap Desai 		goto out;
2998824a1566SKashyap Desai 	}
2999e3605f65SSreekanth Reddy 	mpimr_initialize_reply_sbuf_queues(mrioc);
3000e3605f65SSreekanth Reddy 
3001824a1566SKashyap Desai 	drv_info->information_length = cpu_to_le32(data_len);
3002aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->driver_signature, "Broadcom", sizeof(drv_info->driver_signature));
3003aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->os_name, utsname()->sysname, sizeof(drv_info->os_name));
3004aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->os_version, utsname()->release, sizeof(drv_info->os_version));
3005aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->driver_name, MPI3MR_DRIVER_NAME, sizeof(drv_info->driver_name));
3006aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->driver_version, MPI3MR_DRIVER_VERSION, sizeof(drv_info->driver_version));
3007aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->driver_release_date, MPI3MR_DRIVER_RELDATE,
3008aa0dc6a7SSreekanth Reddy 	    sizeof(drv_info->driver_release_date));
3009824a1566SKashyap Desai 	drv_info->driver_capabilities = 0;
3010824a1566SKashyap Desai 	memcpy((u8 *)&mrioc->driver_info, (u8 *)drv_info,
3011824a1566SKashyap Desai 	    sizeof(mrioc->driver_info));
3012824a1566SKashyap Desai 
3013824a1566SKashyap Desai 	memset(&iocinit_req, 0, sizeof(iocinit_req));
3014824a1566SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
3015824a1566SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
3016824a1566SKashyap Desai 		retval = -1;
3017824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCInit: Init command is in use\n");
3018824a1566SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
3019824a1566SKashyap Desai 		goto out;
3020824a1566SKashyap Desai 	}
3021824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
3022824a1566SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
3023824a1566SKashyap Desai 	mrioc->init_cmds.callback = NULL;
3024824a1566SKashyap Desai 	iocinit_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
3025824a1566SKashyap Desai 	iocinit_req.function = MPI3_FUNCTION_IOC_INIT;
3026824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.dev = MPI3_VERSION_DEV;
3027824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.unit = MPI3_VERSION_UNIT;
3028824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.major = MPI3_VERSION_MAJOR;
3029824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.minor = MPI3_VERSION_MINOR;
3030824a1566SKashyap Desai 	iocinit_req.who_init = MPI3_WHOINIT_HOST_DRIVER;
3031824a1566SKashyap Desai 	iocinit_req.reply_free_queue_depth = cpu_to_le16(mrioc->reply_free_qsz);
3032824a1566SKashyap Desai 	iocinit_req.reply_free_queue_address =
3033824a1566SKashyap Desai 	    cpu_to_le64(mrioc->reply_free_q_dma);
3034ec5ebd2cSSreekanth Reddy 	iocinit_req.sense_buffer_length = cpu_to_le16(MPI3MR_SENSE_BUF_SZ);
3035824a1566SKashyap Desai 	iocinit_req.sense_buffer_free_queue_depth =
3036824a1566SKashyap Desai 	    cpu_to_le16(mrioc->sense_buf_q_sz);
3037824a1566SKashyap Desai 	iocinit_req.sense_buffer_free_queue_address =
3038824a1566SKashyap Desai 	    cpu_to_le64(mrioc->sense_buf_q_dma);
3039824a1566SKashyap Desai 	iocinit_req.driver_information_address = cpu_to_le64(data_dma);
3040824a1566SKashyap Desai 
3041824a1566SKashyap Desai 	current_time = ktime_get_real();
3042824a1566SKashyap Desai 	iocinit_req.time_stamp = cpu_to_le64(ktime_to_ms(current_time));
3043824a1566SKashyap Desai 
3044824a1566SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
3045824a1566SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &iocinit_req,
3046824a1566SKashyap Desai 	    sizeof(iocinit_req), 1);
3047824a1566SKashyap Desai 	if (retval) {
3048824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCInit: Admin Post failed\n");
3049824a1566SKashyap Desai 		goto out_unlock;
3050824a1566SKashyap Desai 	}
3051824a1566SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
3052824a1566SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
3053824a1566SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
3054a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
3055824a1566SKashyap Desai 		    MPI3MR_RESET_FROM_IOCINIT_TIMEOUT);
3056a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "ioc_init timed out\n");
3057824a1566SKashyap Desai 		retval = -1;
3058824a1566SKashyap Desai 		goto out_unlock;
3059824a1566SKashyap Desai 	}
3060824a1566SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
3061824a1566SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
3062824a1566SKashyap Desai 		ioc_err(mrioc,
3063824a1566SKashyap Desai 		    "Issue IOCInit: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
3064824a1566SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
3065824a1566SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
3066824a1566SKashyap Desai 		retval = -1;
3067824a1566SKashyap Desai 		goto out_unlock;
3068824a1566SKashyap Desai 	}
3069824a1566SKashyap Desai 
3070e3605f65SSreekanth Reddy 	mrioc->reply_free_queue_host_index = mrioc->num_reply_bufs;
3071e3605f65SSreekanth Reddy 	writel(mrioc->reply_free_queue_host_index,
3072e3605f65SSreekanth Reddy 	    &mrioc->sysif_regs->reply_free_host_index);
3073e3605f65SSreekanth Reddy 
3074e3605f65SSreekanth Reddy 	mrioc->sbq_host_index = mrioc->num_sense_bufs;
3075e3605f65SSreekanth Reddy 	writel(mrioc->sbq_host_index,
3076e3605f65SSreekanth Reddy 	    &mrioc->sysif_regs->sense_buffer_free_host_index);
3077824a1566SKashyap Desai out_unlock:
3078824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
3079824a1566SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
3080824a1566SKashyap Desai 
3081824a1566SKashyap Desai out:
3082824a1566SKashyap Desai 	if (drv_info)
3083824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, data_len, drv_info,
3084824a1566SKashyap Desai 		    data_dma);
3085824a1566SKashyap Desai 
3086824a1566SKashyap Desai 	return retval;
3087824a1566SKashyap Desai }
3088824a1566SKashyap Desai 
3089824a1566SKashyap Desai /**
309013ef29eaSKashyap Desai  * mpi3mr_unmask_events - Unmask events in event mask bitmap
309113ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
309213ef29eaSKashyap Desai  * @event: MPI event ID
309313ef29eaSKashyap Desai  *
309413ef29eaSKashyap Desai  * Un mask the specific event by resetting the event_mask
309513ef29eaSKashyap Desai  * bitmap.
309613ef29eaSKashyap Desai  *
309713ef29eaSKashyap Desai  * Return: 0 on success, non-zero on failures.
309813ef29eaSKashyap Desai  */
309913ef29eaSKashyap Desai static void mpi3mr_unmask_events(struct mpi3mr_ioc *mrioc, u16 event)
310013ef29eaSKashyap Desai {
310113ef29eaSKashyap Desai 	u32 desired_event;
310213ef29eaSKashyap Desai 	u8 word;
310313ef29eaSKashyap Desai 
310413ef29eaSKashyap Desai 	if (event >= 128)
310513ef29eaSKashyap Desai 		return;
310613ef29eaSKashyap Desai 
310713ef29eaSKashyap Desai 	desired_event = (1 << (event % 32));
310813ef29eaSKashyap Desai 	word = event / 32;
310913ef29eaSKashyap Desai 
311013ef29eaSKashyap Desai 	mrioc->event_masks[word] &= ~desired_event;
311113ef29eaSKashyap Desai }
311213ef29eaSKashyap Desai 
311313ef29eaSKashyap Desai /**
311413ef29eaSKashyap Desai  * mpi3mr_issue_event_notification - Send event notification
311513ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
311613ef29eaSKashyap Desai  *
311713ef29eaSKashyap Desai  * Issue event notification MPI request through admin queue and
311813ef29eaSKashyap Desai  * wait for the completion of it or time out.
311913ef29eaSKashyap Desai  *
312013ef29eaSKashyap Desai  * Return: 0 on success, non-zero on failures.
312113ef29eaSKashyap Desai  */
312213ef29eaSKashyap Desai static int mpi3mr_issue_event_notification(struct mpi3mr_ioc *mrioc)
312313ef29eaSKashyap Desai {
312413ef29eaSKashyap Desai 	struct mpi3_event_notification_request evtnotify_req;
312513ef29eaSKashyap Desai 	int retval = 0;
312613ef29eaSKashyap Desai 	u8 i;
312713ef29eaSKashyap Desai 
312813ef29eaSKashyap Desai 	memset(&evtnotify_req, 0, sizeof(evtnotify_req));
312913ef29eaSKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
313013ef29eaSKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
313113ef29eaSKashyap Desai 		retval = -1;
313213ef29eaSKashyap Desai 		ioc_err(mrioc, "Issue EvtNotify: Init command is in use\n");
313313ef29eaSKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
313413ef29eaSKashyap Desai 		goto out;
313513ef29eaSKashyap Desai 	}
313613ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
313713ef29eaSKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
313813ef29eaSKashyap Desai 	mrioc->init_cmds.callback = NULL;
313913ef29eaSKashyap Desai 	evtnotify_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
314013ef29eaSKashyap Desai 	evtnotify_req.function = MPI3_FUNCTION_EVENT_NOTIFICATION;
314113ef29eaSKashyap Desai 	for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
314213ef29eaSKashyap Desai 		evtnotify_req.event_masks[i] =
314313ef29eaSKashyap Desai 		    cpu_to_le32(mrioc->event_masks[i]);
314413ef29eaSKashyap Desai 	init_completion(&mrioc->init_cmds.done);
314513ef29eaSKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &evtnotify_req,
314613ef29eaSKashyap Desai 	    sizeof(evtnotify_req), 1);
314713ef29eaSKashyap Desai 	if (retval) {
314813ef29eaSKashyap Desai 		ioc_err(mrioc, "Issue EvtNotify: Admin Post failed\n");
314913ef29eaSKashyap Desai 		goto out_unlock;
315013ef29eaSKashyap Desai 	}
315113ef29eaSKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
315213ef29eaSKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
315313ef29eaSKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
3154a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "event notification timed out\n");
3155a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
315613ef29eaSKashyap Desai 		    MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT);
315713ef29eaSKashyap Desai 		retval = -1;
315813ef29eaSKashyap Desai 		goto out_unlock;
315913ef29eaSKashyap Desai 	}
316013ef29eaSKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
316113ef29eaSKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
316213ef29eaSKashyap Desai 		ioc_err(mrioc,
316313ef29eaSKashyap Desai 		    "Issue EvtNotify: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
316413ef29eaSKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
316513ef29eaSKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
316613ef29eaSKashyap Desai 		retval = -1;
316713ef29eaSKashyap Desai 		goto out_unlock;
316813ef29eaSKashyap Desai 	}
316913ef29eaSKashyap Desai 
317013ef29eaSKashyap Desai out_unlock:
317113ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
317213ef29eaSKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
317313ef29eaSKashyap Desai out:
317413ef29eaSKashyap Desai 	return retval;
317513ef29eaSKashyap Desai }
317613ef29eaSKashyap Desai 
317713ef29eaSKashyap Desai /**
3178c1af985dSSreekanth Reddy  * mpi3mr_process_event_ack - Process event acknowledgment
317913ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
318013ef29eaSKashyap Desai  * @event: MPI3 event ID
3181c1af985dSSreekanth Reddy  * @event_ctx: event context
318213ef29eaSKashyap Desai  *
318313ef29eaSKashyap Desai  * Send event acknowledgment through admin queue and wait for
318413ef29eaSKashyap Desai  * it to complete.
318513ef29eaSKashyap Desai  *
318613ef29eaSKashyap Desai  * Return: 0 on success, non-zero on failures.
318713ef29eaSKashyap Desai  */
3188c1af985dSSreekanth Reddy int mpi3mr_process_event_ack(struct mpi3mr_ioc *mrioc, u8 event,
318913ef29eaSKashyap Desai 	u32 event_ctx)
319013ef29eaSKashyap Desai {
319113ef29eaSKashyap Desai 	struct mpi3_event_ack_request evtack_req;
319213ef29eaSKashyap Desai 	int retval = 0;
319313ef29eaSKashyap Desai 
319413ef29eaSKashyap Desai 	memset(&evtack_req, 0, sizeof(evtack_req));
319513ef29eaSKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
319613ef29eaSKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
319713ef29eaSKashyap Desai 		retval = -1;
319813ef29eaSKashyap Desai 		ioc_err(mrioc, "Send EvtAck: Init command is in use\n");
319913ef29eaSKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
320013ef29eaSKashyap Desai 		goto out;
320113ef29eaSKashyap Desai 	}
320213ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
320313ef29eaSKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
320413ef29eaSKashyap Desai 	mrioc->init_cmds.callback = NULL;
320513ef29eaSKashyap Desai 	evtack_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
320613ef29eaSKashyap Desai 	evtack_req.function = MPI3_FUNCTION_EVENT_ACK;
320713ef29eaSKashyap Desai 	evtack_req.event = event;
320813ef29eaSKashyap Desai 	evtack_req.event_context = cpu_to_le32(event_ctx);
320913ef29eaSKashyap Desai 
321013ef29eaSKashyap Desai 	init_completion(&mrioc->init_cmds.done);
321113ef29eaSKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &evtack_req,
321213ef29eaSKashyap Desai 	    sizeof(evtack_req), 1);
321313ef29eaSKashyap Desai 	if (retval) {
321413ef29eaSKashyap Desai 		ioc_err(mrioc, "Send EvtAck: Admin Post failed\n");
321513ef29eaSKashyap Desai 		goto out_unlock;
321613ef29eaSKashyap Desai 	}
321713ef29eaSKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
321813ef29eaSKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
321913ef29eaSKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
322013ef29eaSKashyap Desai 		ioc_err(mrioc, "Issue EvtNotify: command timed out\n");
3221fbaa9aa4SSreekanth Reddy 		if (!(mrioc->init_cmds.state & MPI3MR_CMD_RESET))
322213ef29eaSKashyap Desai 			mpi3mr_soft_reset_handler(mrioc,
322313ef29eaSKashyap Desai 			    MPI3MR_RESET_FROM_EVTACK_TIMEOUT, 1);
322413ef29eaSKashyap Desai 		retval = -1;
322513ef29eaSKashyap Desai 		goto out_unlock;
322613ef29eaSKashyap Desai 	}
322713ef29eaSKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
322813ef29eaSKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
322913ef29eaSKashyap Desai 		ioc_err(mrioc,
323013ef29eaSKashyap Desai 		    "Send EvtAck: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
323113ef29eaSKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
323213ef29eaSKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
323313ef29eaSKashyap Desai 		retval = -1;
323413ef29eaSKashyap Desai 		goto out_unlock;
323513ef29eaSKashyap Desai 	}
323613ef29eaSKashyap Desai 
323713ef29eaSKashyap Desai out_unlock:
323813ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
323913ef29eaSKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
324013ef29eaSKashyap Desai out:
324113ef29eaSKashyap Desai 	return retval;
324213ef29eaSKashyap Desai }
324313ef29eaSKashyap Desai 
324413ef29eaSKashyap Desai /**
3245824a1566SKashyap Desai  * mpi3mr_alloc_chain_bufs - Allocate chain buffers
3246824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3247824a1566SKashyap Desai  *
3248824a1566SKashyap Desai  * Allocate chain buffers and set a bitmap to indicate free
3249824a1566SKashyap Desai  * chain buffers. Chain buffers are used to pass the SGE
3250824a1566SKashyap Desai  * information along with MPI3 SCSI IO requests for host I/O.
3251824a1566SKashyap Desai  *
3252824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure
3253824a1566SKashyap Desai  */
3254824a1566SKashyap Desai static int mpi3mr_alloc_chain_bufs(struct mpi3mr_ioc *mrioc)
3255824a1566SKashyap Desai {
3256824a1566SKashyap Desai 	int retval = 0;
3257824a1566SKashyap Desai 	u32 sz, i;
3258824a1566SKashyap Desai 	u16 num_chains;
3259824a1566SKashyap Desai 
3260fe6db615SSreekanth Reddy 	if (mrioc->chain_sgl_list)
3261fe6db615SSreekanth Reddy 		return retval;
3262fe6db615SSreekanth Reddy 
3263824a1566SKashyap Desai 	num_chains = mrioc->max_host_ios / MPI3MR_CHAINBUF_FACTOR;
3264824a1566SKashyap Desai 
326574e1f30aSKashyap Desai 	if (prot_mask & (SHOST_DIX_TYPE0_PROTECTION
326674e1f30aSKashyap Desai 	    | SHOST_DIX_TYPE1_PROTECTION
326774e1f30aSKashyap Desai 	    | SHOST_DIX_TYPE2_PROTECTION
326874e1f30aSKashyap Desai 	    | SHOST_DIX_TYPE3_PROTECTION))
326974e1f30aSKashyap Desai 		num_chains += (num_chains / MPI3MR_CHAINBUFDIX_FACTOR);
327074e1f30aSKashyap Desai 
3271824a1566SKashyap Desai 	mrioc->chain_buf_count = num_chains;
3272824a1566SKashyap Desai 	sz = sizeof(struct chain_element) * num_chains;
3273824a1566SKashyap Desai 	mrioc->chain_sgl_list = kzalloc(sz, GFP_KERNEL);
3274824a1566SKashyap Desai 	if (!mrioc->chain_sgl_list)
3275824a1566SKashyap Desai 		goto out_failed;
3276824a1566SKashyap Desai 
3277824a1566SKashyap Desai 	sz = MPI3MR_PAGE_SIZE_4K;
3278824a1566SKashyap Desai 	mrioc->chain_buf_pool = dma_pool_create("chain_buf pool",
3279824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 16, 0);
3280824a1566SKashyap Desai 	if (!mrioc->chain_buf_pool) {
3281824a1566SKashyap Desai 		ioc_err(mrioc, "chain buf pool: dma_pool_create failed\n");
3282824a1566SKashyap Desai 		goto out_failed;
3283824a1566SKashyap Desai 	}
3284824a1566SKashyap Desai 
3285824a1566SKashyap Desai 	for (i = 0; i < num_chains; i++) {
3286824a1566SKashyap Desai 		mrioc->chain_sgl_list[i].addr =
3287824a1566SKashyap Desai 		    dma_pool_zalloc(mrioc->chain_buf_pool, GFP_KERNEL,
3288824a1566SKashyap Desai 		    &mrioc->chain_sgl_list[i].dma_addr);
3289824a1566SKashyap Desai 
3290824a1566SKashyap Desai 		if (!mrioc->chain_sgl_list[i].addr)
3291824a1566SKashyap Desai 			goto out_failed;
3292824a1566SKashyap Desai 	}
3293824a1566SKashyap Desai 	mrioc->chain_bitmap_sz = num_chains / 8;
3294824a1566SKashyap Desai 	if (num_chains % 8)
3295824a1566SKashyap Desai 		mrioc->chain_bitmap_sz++;
3296824a1566SKashyap Desai 	mrioc->chain_bitmap = kzalloc(mrioc->chain_bitmap_sz, GFP_KERNEL);
3297824a1566SKashyap Desai 	if (!mrioc->chain_bitmap)
3298824a1566SKashyap Desai 		goto out_failed;
3299824a1566SKashyap Desai 	return retval;
3300824a1566SKashyap Desai out_failed:
3301824a1566SKashyap Desai 	retval = -1;
3302824a1566SKashyap Desai 	return retval;
3303824a1566SKashyap Desai }
3304824a1566SKashyap Desai 
3305824a1566SKashyap Desai /**
3306023ab2a9SKashyap Desai  * mpi3mr_port_enable_complete - Mark port enable complete
3307023ab2a9SKashyap Desai  * @mrioc: Adapter instance reference
3308023ab2a9SKashyap Desai  * @drv_cmd: Internal command tracker
3309023ab2a9SKashyap Desai  *
3310023ab2a9SKashyap Desai  * Call back for asynchronous port enable request sets the
3311023ab2a9SKashyap Desai  * driver command to indicate port enable request is complete.
3312023ab2a9SKashyap Desai  *
3313023ab2a9SKashyap Desai  * Return: Nothing
3314023ab2a9SKashyap Desai  */
3315023ab2a9SKashyap Desai static void mpi3mr_port_enable_complete(struct mpi3mr_ioc *mrioc,
3316023ab2a9SKashyap Desai 	struct mpi3mr_drv_cmd *drv_cmd)
3317023ab2a9SKashyap Desai {
3318023ab2a9SKashyap Desai 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
3319023ab2a9SKashyap Desai 	drv_cmd->callback = NULL;
3320023ab2a9SKashyap Desai 	mrioc->scan_failed = drv_cmd->ioc_status;
3321023ab2a9SKashyap Desai 	mrioc->scan_started = 0;
3322023ab2a9SKashyap Desai }
3323023ab2a9SKashyap Desai 
3324023ab2a9SKashyap Desai /**
3325023ab2a9SKashyap Desai  * mpi3mr_issue_port_enable - Issue Port Enable
3326023ab2a9SKashyap Desai  * @mrioc: Adapter instance reference
3327023ab2a9SKashyap Desai  * @async: Flag to wait for completion or not
3328023ab2a9SKashyap Desai  *
3329023ab2a9SKashyap Desai  * Issue Port Enable MPI request through admin queue and if the
3330023ab2a9SKashyap Desai  * async flag is not set wait for the completion of the port
3331023ab2a9SKashyap Desai  * enable or time out.
3332023ab2a9SKashyap Desai  *
3333023ab2a9SKashyap Desai  * Return: 0 on success, non-zero on failures.
3334023ab2a9SKashyap Desai  */
3335023ab2a9SKashyap Desai int mpi3mr_issue_port_enable(struct mpi3mr_ioc *mrioc, u8 async)
3336023ab2a9SKashyap Desai {
3337023ab2a9SKashyap Desai 	struct mpi3_port_enable_request pe_req;
3338023ab2a9SKashyap Desai 	int retval = 0;
3339023ab2a9SKashyap Desai 	u32 pe_timeout = MPI3MR_PORTENABLE_TIMEOUT;
3340023ab2a9SKashyap Desai 
3341023ab2a9SKashyap Desai 	memset(&pe_req, 0, sizeof(pe_req));
3342023ab2a9SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
3343023ab2a9SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
3344023ab2a9SKashyap Desai 		retval = -1;
3345023ab2a9SKashyap Desai 		ioc_err(mrioc, "Issue PortEnable: Init command is in use\n");
3346023ab2a9SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
3347023ab2a9SKashyap Desai 		goto out;
3348023ab2a9SKashyap Desai 	}
3349023ab2a9SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
3350023ab2a9SKashyap Desai 	if (async) {
3351023ab2a9SKashyap Desai 		mrioc->init_cmds.is_waiting = 0;
3352023ab2a9SKashyap Desai 		mrioc->init_cmds.callback = mpi3mr_port_enable_complete;
3353023ab2a9SKashyap Desai 	} else {
3354023ab2a9SKashyap Desai 		mrioc->init_cmds.is_waiting = 1;
3355023ab2a9SKashyap Desai 		mrioc->init_cmds.callback = NULL;
3356023ab2a9SKashyap Desai 		init_completion(&mrioc->init_cmds.done);
3357023ab2a9SKashyap Desai 	}
3358023ab2a9SKashyap Desai 	pe_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
3359023ab2a9SKashyap Desai 	pe_req.function = MPI3_FUNCTION_PORT_ENABLE;
3360023ab2a9SKashyap Desai 
3361023ab2a9SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &pe_req, sizeof(pe_req), 1);
3362023ab2a9SKashyap Desai 	if (retval) {
3363023ab2a9SKashyap Desai 		ioc_err(mrioc, "Issue PortEnable: Admin Post failed\n");
3364023ab2a9SKashyap Desai 		goto out_unlock;
3365023ab2a9SKashyap Desai 	}
3366a6856cc4SSreekanth Reddy 	if (async) {
3367a6856cc4SSreekanth Reddy 		mutex_unlock(&mrioc->init_cmds.mutex);
3368a6856cc4SSreekanth Reddy 		goto out;
3369a6856cc4SSreekanth Reddy 	}
3370a6856cc4SSreekanth Reddy 
3371a6856cc4SSreekanth Reddy 	wait_for_completion_timeout(&mrioc->init_cmds.done, (pe_timeout * HZ));
3372023ab2a9SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
3373a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "port enable timed out\n");
3374023ab2a9SKashyap Desai 		retval = -1;
3375a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc, MPI3MR_RESET_FROM_PE_TIMEOUT);
3376023ab2a9SKashyap Desai 		goto out_unlock;
3377023ab2a9SKashyap Desai 	}
3378023ab2a9SKashyap Desai 	mpi3mr_port_enable_complete(mrioc, &mrioc->init_cmds);
3379a6856cc4SSreekanth Reddy 
3380023ab2a9SKashyap Desai out_unlock:
3381a6856cc4SSreekanth Reddy 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
3382023ab2a9SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
3383023ab2a9SKashyap Desai out:
3384023ab2a9SKashyap Desai 	return retval;
3385023ab2a9SKashyap Desai }
3386023ab2a9SKashyap Desai 
3387ff9561e9SKashyap Desai /* Protocol type to name mapper structure */
3388ff9561e9SKashyap Desai static const struct {
3389ff9561e9SKashyap Desai 	u8 protocol;
3390ff9561e9SKashyap Desai 	char *name;
3391ff9561e9SKashyap Desai } mpi3mr_protocols[] = {
3392ff9561e9SKashyap Desai 	{ MPI3_IOCFACTS_PROTOCOL_SCSI_INITIATOR, "Initiator" },
3393ff9561e9SKashyap Desai 	{ MPI3_IOCFACTS_PROTOCOL_SCSI_TARGET, "Target" },
3394ff9561e9SKashyap Desai 	{ MPI3_IOCFACTS_PROTOCOL_NVME, "NVMe attachment" },
3395ff9561e9SKashyap Desai };
3396ff9561e9SKashyap Desai 
3397ff9561e9SKashyap Desai /* Capability to name mapper structure*/
3398ff9561e9SKashyap Desai static const struct {
3399ff9561e9SKashyap Desai 	u32 capability;
3400ff9561e9SKashyap Desai 	char *name;
3401ff9561e9SKashyap Desai } mpi3mr_capabilities[] = {
3402ff9561e9SKashyap Desai 	{ MPI3_IOCFACTS_CAPABILITY_RAID_CAPABLE, "RAID" },
3403ff9561e9SKashyap Desai };
3404ff9561e9SKashyap Desai 
3405ff9561e9SKashyap Desai /**
3406ff9561e9SKashyap Desai  * mpi3mr_print_ioc_info - Display controller information
3407ff9561e9SKashyap Desai  * @mrioc: Adapter instance reference
3408ff9561e9SKashyap Desai  *
3409ff9561e9SKashyap Desai  * Display controller personalit, capability, supported
3410ff9561e9SKashyap Desai  * protocols etc.
3411ff9561e9SKashyap Desai  *
3412ff9561e9SKashyap Desai  * Return: Nothing
3413ff9561e9SKashyap Desai  */
3414ff9561e9SKashyap Desai static void
3415ff9561e9SKashyap Desai mpi3mr_print_ioc_info(struct mpi3mr_ioc *mrioc)
3416ff9561e9SKashyap Desai {
341776a4f7ccSDan Carpenter 	int i = 0, bytes_written = 0;
3418ff9561e9SKashyap Desai 	char personality[16];
3419ff9561e9SKashyap Desai 	char protocol[50] = {0};
3420ff9561e9SKashyap Desai 	char capabilities[100] = {0};
3421ff9561e9SKashyap Desai 	struct mpi3mr_compimg_ver *fwver = &mrioc->facts.fw_ver;
3422ff9561e9SKashyap Desai 
3423ff9561e9SKashyap Desai 	switch (mrioc->facts.personality) {
3424ff9561e9SKashyap Desai 	case MPI3_IOCFACTS_FLAGS_PERSONALITY_EHBA:
3425ff9561e9SKashyap Desai 		strncpy(personality, "Enhanced HBA", sizeof(personality));
3426ff9561e9SKashyap Desai 		break;
3427ff9561e9SKashyap Desai 	case MPI3_IOCFACTS_FLAGS_PERSONALITY_RAID_DDR:
3428ff9561e9SKashyap Desai 		strncpy(personality, "RAID", sizeof(personality));
3429ff9561e9SKashyap Desai 		break;
3430ff9561e9SKashyap Desai 	default:
3431ff9561e9SKashyap Desai 		strncpy(personality, "Unknown", sizeof(personality));
3432ff9561e9SKashyap Desai 		break;
3433ff9561e9SKashyap Desai 	}
3434ff9561e9SKashyap Desai 
3435ff9561e9SKashyap Desai 	ioc_info(mrioc, "Running in %s Personality", personality);
3436ff9561e9SKashyap Desai 
3437ff9561e9SKashyap Desai 	ioc_info(mrioc, "FW version(%d.%d.%d.%d.%d.%d)\n",
3438ff9561e9SKashyap Desai 	    fwver->gen_major, fwver->gen_minor, fwver->ph_major,
3439ff9561e9SKashyap Desai 	    fwver->ph_minor, fwver->cust_id, fwver->build_num);
3440ff9561e9SKashyap Desai 
3441ff9561e9SKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mpi3mr_protocols); i++) {
3442ff9561e9SKashyap Desai 		if (mrioc->facts.protocol_flags &
3443ff9561e9SKashyap Desai 		    mpi3mr_protocols[i].protocol) {
344430e99f05SDan Carpenter 			bytes_written += scnprintf(protocol + bytes_written,
344576a4f7ccSDan Carpenter 				    sizeof(protocol) - bytes_written, "%s%s",
344676a4f7ccSDan Carpenter 				    bytes_written ? "," : "",
3447ff9561e9SKashyap Desai 				    mpi3mr_protocols[i].name);
3448ff9561e9SKashyap Desai 		}
3449ff9561e9SKashyap Desai 	}
3450ff9561e9SKashyap Desai 
345176a4f7ccSDan Carpenter 	bytes_written = 0;
3452ff9561e9SKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mpi3mr_capabilities); i++) {
3453ff9561e9SKashyap Desai 		if (mrioc->facts.protocol_flags &
3454ff9561e9SKashyap Desai 		    mpi3mr_capabilities[i].capability) {
345530e99f05SDan Carpenter 			bytes_written += scnprintf(capabilities + bytes_written,
345676a4f7ccSDan Carpenter 				    sizeof(capabilities) - bytes_written, "%s%s",
345776a4f7ccSDan Carpenter 				    bytes_written ? "," : "",
3458ff9561e9SKashyap Desai 				    mpi3mr_capabilities[i].name);
3459ff9561e9SKashyap Desai 		}
3460ff9561e9SKashyap Desai 	}
3461ff9561e9SKashyap Desai 
3462ff9561e9SKashyap Desai 	ioc_info(mrioc, "Protocol=(%s), Capabilities=(%s)\n",
3463ff9561e9SKashyap Desai 		 protocol, capabilities);
3464ff9561e9SKashyap Desai }
3465ff9561e9SKashyap Desai 
3466023ab2a9SKashyap Desai /**
3467824a1566SKashyap Desai  * mpi3mr_cleanup_resources - Free PCI resources
3468824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3469824a1566SKashyap Desai  *
3470824a1566SKashyap Desai  * Unmap PCI device memory and disable PCI device.
3471824a1566SKashyap Desai  *
3472824a1566SKashyap Desai  * Return: 0 on success and non-zero on failure.
3473824a1566SKashyap Desai  */
3474824a1566SKashyap Desai void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc)
3475824a1566SKashyap Desai {
3476824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
3477824a1566SKashyap Desai 
3478824a1566SKashyap Desai 	mpi3mr_cleanup_isr(mrioc);
3479824a1566SKashyap Desai 
3480824a1566SKashyap Desai 	if (mrioc->sysif_regs) {
3481824a1566SKashyap Desai 		iounmap((void __iomem *)mrioc->sysif_regs);
3482824a1566SKashyap Desai 		mrioc->sysif_regs = NULL;
3483824a1566SKashyap Desai 	}
3484824a1566SKashyap Desai 
3485824a1566SKashyap Desai 	if (pci_is_enabled(pdev)) {
3486824a1566SKashyap Desai 		if (mrioc->bars)
3487824a1566SKashyap Desai 			pci_release_selected_regions(pdev, mrioc->bars);
3488824a1566SKashyap Desai 		pci_disable_device(pdev);
3489824a1566SKashyap Desai 	}
3490824a1566SKashyap Desai }
3491824a1566SKashyap Desai 
3492824a1566SKashyap Desai /**
3493824a1566SKashyap Desai  * mpi3mr_setup_resources - Enable PCI resources
3494824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3495824a1566SKashyap Desai  *
3496824a1566SKashyap Desai  * Enable PCI device memory, MSI-x registers and set DMA mask.
3497824a1566SKashyap Desai  *
3498824a1566SKashyap Desai  * Return: 0 on success and non-zero on failure.
3499824a1566SKashyap Desai  */
3500824a1566SKashyap Desai int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc)
3501824a1566SKashyap Desai {
3502824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
3503824a1566SKashyap Desai 	u32 memap_sz = 0;
3504824a1566SKashyap Desai 	int i, retval = 0, capb = 0;
3505824a1566SKashyap Desai 	u16 message_control;
3506824a1566SKashyap Desai 	u64 dma_mask = mrioc->dma_mask ? mrioc->dma_mask :
3507824a1566SKashyap Desai 	    (((dma_get_required_mask(&pdev->dev) > DMA_BIT_MASK(32)) &&
3508824a1566SKashyap Desai 	    (sizeof(dma_addr_t) > 4)) ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32));
3509824a1566SKashyap Desai 
3510824a1566SKashyap Desai 	if (pci_enable_device_mem(pdev)) {
3511824a1566SKashyap Desai 		ioc_err(mrioc, "pci_enable_device_mem: failed\n");
3512824a1566SKashyap Desai 		retval = -ENODEV;
3513824a1566SKashyap Desai 		goto out_failed;
3514824a1566SKashyap Desai 	}
3515824a1566SKashyap Desai 
3516824a1566SKashyap Desai 	capb = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
3517824a1566SKashyap Desai 	if (!capb) {
3518824a1566SKashyap Desai 		ioc_err(mrioc, "Unable to find MSI-X Capabilities\n");
3519824a1566SKashyap Desai 		retval = -ENODEV;
3520824a1566SKashyap Desai 		goto out_failed;
3521824a1566SKashyap Desai 	}
3522824a1566SKashyap Desai 	mrioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
3523824a1566SKashyap Desai 
3524824a1566SKashyap Desai 	if (pci_request_selected_regions(pdev, mrioc->bars,
3525824a1566SKashyap Desai 	    mrioc->driver_name)) {
3526824a1566SKashyap Desai 		ioc_err(mrioc, "pci_request_selected_regions: failed\n");
3527824a1566SKashyap Desai 		retval = -ENODEV;
3528824a1566SKashyap Desai 		goto out_failed;
3529824a1566SKashyap Desai 	}
3530824a1566SKashyap Desai 
3531824a1566SKashyap Desai 	for (i = 0; (i < DEVICE_COUNT_RESOURCE); i++) {
3532824a1566SKashyap Desai 		if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
3533824a1566SKashyap Desai 			mrioc->sysif_regs_phys = pci_resource_start(pdev, i);
3534824a1566SKashyap Desai 			memap_sz = pci_resource_len(pdev, i);
3535824a1566SKashyap Desai 			mrioc->sysif_regs =
3536824a1566SKashyap Desai 			    ioremap(mrioc->sysif_regs_phys, memap_sz);
3537824a1566SKashyap Desai 			break;
3538824a1566SKashyap Desai 		}
3539824a1566SKashyap Desai 	}
3540824a1566SKashyap Desai 
3541824a1566SKashyap Desai 	pci_set_master(pdev);
3542824a1566SKashyap Desai 
3543824a1566SKashyap Desai 	retval = dma_set_mask_and_coherent(&pdev->dev, dma_mask);
3544824a1566SKashyap Desai 	if (retval) {
3545824a1566SKashyap Desai 		if (dma_mask != DMA_BIT_MASK(32)) {
3546824a1566SKashyap Desai 			ioc_warn(mrioc, "Setting 64 bit DMA mask failed\n");
3547824a1566SKashyap Desai 			dma_mask = DMA_BIT_MASK(32);
3548824a1566SKashyap Desai 			retval = dma_set_mask_and_coherent(&pdev->dev,
3549824a1566SKashyap Desai 			    dma_mask);
3550824a1566SKashyap Desai 		}
3551824a1566SKashyap Desai 		if (retval) {
3552824a1566SKashyap Desai 			mrioc->dma_mask = 0;
3553824a1566SKashyap Desai 			ioc_err(mrioc, "Setting 32 bit DMA mask also failed\n");
3554824a1566SKashyap Desai 			goto out_failed;
3555824a1566SKashyap Desai 		}
3556824a1566SKashyap Desai 	}
3557824a1566SKashyap Desai 	mrioc->dma_mask = dma_mask;
3558824a1566SKashyap Desai 
3559824a1566SKashyap Desai 	if (!mrioc->sysif_regs) {
3560824a1566SKashyap Desai 		ioc_err(mrioc,
3561824a1566SKashyap Desai 		    "Unable to map adapter memory or resource not found\n");
3562824a1566SKashyap Desai 		retval = -EINVAL;
3563824a1566SKashyap Desai 		goto out_failed;
3564824a1566SKashyap Desai 	}
3565824a1566SKashyap Desai 
3566824a1566SKashyap Desai 	pci_read_config_word(pdev, capb + 2, &message_control);
3567824a1566SKashyap Desai 	mrioc->msix_count = (message_control & 0x3FF) + 1;
3568824a1566SKashyap Desai 
3569824a1566SKashyap Desai 	pci_save_state(pdev);
3570824a1566SKashyap Desai 
3571824a1566SKashyap Desai 	pci_set_drvdata(pdev, mrioc->shost);
3572824a1566SKashyap Desai 
3573824a1566SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
3574824a1566SKashyap Desai 
3575824a1566SKashyap Desai 	ioc_info(mrioc, "iomem(0x%016llx), mapped(0x%p), size(%d)\n",
3576824a1566SKashyap Desai 	    (unsigned long long)mrioc->sysif_regs_phys,
3577824a1566SKashyap Desai 	    mrioc->sysif_regs, memap_sz);
3578824a1566SKashyap Desai 	ioc_info(mrioc, "Number of MSI-X vectors found in capabilities: (%d)\n",
3579824a1566SKashyap Desai 	    mrioc->msix_count);
3580*afd3a579SSreekanth Reddy 
3581*afd3a579SSreekanth Reddy 	if (!reset_devices && poll_queues > 0)
3582*afd3a579SSreekanth Reddy 		mrioc->requested_poll_qcount = min_t(int, poll_queues,
3583*afd3a579SSreekanth Reddy 				mrioc->msix_count - 2);
3584824a1566SKashyap Desai 	return retval;
3585824a1566SKashyap Desai 
3586824a1566SKashyap Desai out_failed:
3587824a1566SKashyap Desai 	mpi3mr_cleanup_resources(mrioc);
3588824a1566SKashyap Desai 	return retval;
3589824a1566SKashyap Desai }
3590824a1566SKashyap Desai 
3591824a1566SKashyap Desai /**
3592e3605f65SSreekanth Reddy  * mpi3mr_enable_events - Enable required events
3593e3605f65SSreekanth Reddy  * @mrioc: Adapter instance reference
3594e3605f65SSreekanth Reddy  *
3595e3605f65SSreekanth Reddy  * This routine unmasks the events required by the driver by
3596e3605f65SSreekanth Reddy  * sennding appropriate event mask bitmapt through an event
3597e3605f65SSreekanth Reddy  * notification request.
3598e3605f65SSreekanth Reddy  *
3599e3605f65SSreekanth Reddy  * Return: 0 on success and non-zero on failure.
3600e3605f65SSreekanth Reddy  */
3601e3605f65SSreekanth Reddy static int mpi3mr_enable_events(struct mpi3mr_ioc *mrioc)
3602e3605f65SSreekanth Reddy {
3603e3605f65SSreekanth Reddy 	int retval = 0;
3604e3605f65SSreekanth Reddy 	u32  i;
3605e3605f65SSreekanth Reddy 
3606e3605f65SSreekanth Reddy 	for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
3607e3605f65SSreekanth Reddy 		mrioc->event_masks[i] = -1;
3608e3605f65SSreekanth Reddy 
3609e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_ADDED);
3610e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_INFO_CHANGED);
3611e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_STATUS_CHANGE);
3612e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE);
3613e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
3614e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DISCOVERY);
3615e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR);
3616e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_BROADCAST_PRIMITIVE);
3617e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST);
3618e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_ENUMERATION);
361978b76a07SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_PREPARE_FOR_RESET);
3620e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_CABLE_MGMT);
3621e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENERGY_PACK_CHANGE);
362295cca8d5SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_TEMP_THRESHOLD);
3623e3605f65SSreekanth Reddy 
3624e3605f65SSreekanth Reddy 	retval = mpi3mr_issue_event_notification(mrioc);
3625e3605f65SSreekanth Reddy 	if (retval)
3626e3605f65SSreekanth Reddy 		ioc_err(mrioc, "failed to issue event notification %d\n",
3627e3605f65SSreekanth Reddy 		    retval);
3628e3605f65SSreekanth Reddy 	return retval;
3629e3605f65SSreekanth Reddy }
3630e3605f65SSreekanth Reddy 
3631e3605f65SSreekanth Reddy /**
3632824a1566SKashyap Desai  * mpi3mr_init_ioc - Initialize the controller
3633824a1566SKashyap Desai  * @mrioc: Adapter instance reference
36340da66348SKashyap Desai  * @init_type: Flag to indicate is the init_type
3635824a1566SKashyap Desai  *
3636824a1566SKashyap Desai  * This the controller initialization routine, executed either
3637824a1566SKashyap Desai  * after soft reset or from pci probe callback.
3638824a1566SKashyap Desai  * Setup the required resources, memory map the controller
3639824a1566SKashyap Desai  * registers, create admin and operational reply queue pairs,
3640824a1566SKashyap Desai  * allocate required memory for reply pool, sense buffer pool,
3641824a1566SKashyap Desai  * issue IOC init request to the firmware, unmask the events and
3642824a1566SKashyap Desai  * issue port enable to discover SAS/SATA/NVMe devies and RAID
3643824a1566SKashyap Desai  * volumes.
3644824a1566SKashyap Desai  *
3645824a1566SKashyap Desai  * Return: 0 on success and non-zero on failure.
3646824a1566SKashyap Desai  */
3647fe6db615SSreekanth Reddy int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc)
3648824a1566SKashyap Desai {
3649824a1566SKashyap Desai 	int retval = 0;
3650fe6db615SSreekanth Reddy 	u8 retry = 0;
3651824a1566SKashyap Desai 	struct mpi3_ioc_facts_data facts_data;
3652824a1566SKashyap Desai 
3653fe6db615SSreekanth Reddy retry_init:
3654824a1566SKashyap Desai 	retval = mpi3mr_bring_ioc_ready(mrioc);
3655824a1566SKashyap Desai 	if (retval) {
3656824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to bring ioc ready: error %d\n",
3657824a1566SKashyap Desai 		    retval);
3658fe6db615SSreekanth Reddy 		goto out_failed_noretry;
3659824a1566SKashyap Desai 	}
3660824a1566SKashyap Desai 
3661824a1566SKashyap Desai 	retval = mpi3mr_setup_isr(mrioc, 1);
3662824a1566SKashyap Desai 	if (retval) {
3663824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to setup ISR error %d\n",
3664824a1566SKashyap Desai 		    retval);
3665fe6db615SSreekanth Reddy 		goto out_failed_noretry;
3666824a1566SKashyap Desai 	}
3667824a1566SKashyap Desai 
3668824a1566SKashyap Desai 	retval = mpi3mr_issue_iocfacts(mrioc, &facts_data);
3669824a1566SKashyap Desai 	if (retval) {
3670824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to Issue IOC Facts %d\n",
3671824a1566SKashyap Desai 		    retval);
3672824a1566SKashyap Desai 		goto out_failed;
3673824a1566SKashyap Desai 	}
3674824a1566SKashyap Desai 
3675c5758fc7SSreekanth Reddy 	mrioc->max_host_ios = mrioc->facts.max_reqs - MPI3MR_INTERNAL_CMDS_RESVD;
3676c5758fc7SSreekanth Reddy 
3677c5758fc7SSreekanth Reddy 	if (reset_devices)
3678c5758fc7SSreekanth Reddy 		mrioc->max_host_ios = min_t(int, mrioc->max_host_ios,
3679c5758fc7SSreekanth Reddy 		    MPI3MR_HOST_IOS_KDUMP);
3680c5758fc7SSreekanth Reddy 
3681c5758fc7SSreekanth Reddy 	mrioc->reply_sz = mrioc->facts.reply_sz;
3682fe6db615SSreekanth Reddy 
3683824a1566SKashyap Desai 	retval = mpi3mr_check_reset_dma_mask(mrioc);
3684824a1566SKashyap Desai 	if (retval) {
3685824a1566SKashyap Desai 		ioc_err(mrioc, "Resetting dma mask failed %d\n",
3686824a1566SKashyap Desai 		    retval);
3687fe6db615SSreekanth Reddy 		goto out_failed_noretry;
3688fb9b0457SKashyap Desai 	}
3689824a1566SKashyap Desai 
3690ff9561e9SKashyap Desai 	mpi3mr_print_ioc_info(mrioc);
3691ff9561e9SKashyap Desai 
3692824a1566SKashyap Desai 	retval = mpi3mr_alloc_reply_sense_bufs(mrioc);
3693824a1566SKashyap Desai 	if (retval) {
3694824a1566SKashyap Desai 		ioc_err(mrioc,
3695824a1566SKashyap Desai 		    "%s :Failed to allocated reply sense buffers %d\n",
3696824a1566SKashyap Desai 		    __func__, retval);
3697fe6db615SSreekanth Reddy 		goto out_failed_noretry;
3698824a1566SKashyap Desai 	}
3699824a1566SKashyap Desai 
3700824a1566SKashyap Desai 	retval = mpi3mr_alloc_chain_bufs(mrioc);
3701824a1566SKashyap Desai 	if (retval) {
3702824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to allocated chain buffers %d\n",
3703824a1566SKashyap Desai 		    retval);
3704fe6db615SSreekanth Reddy 		goto out_failed_noretry;
3705fb9b0457SKashyap Desai 	}
3706824a1566SKashyap Desai 
3707824a1566SKashyap Desai 	retval = mpi3mr_issue_iocinit(mrioc);
3708824a1566SKashyap Desai 	if (retval) {
3709824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to Issue IOC Init %d\n",
3710824a1566SKashyap Desai 		    retval);
3711824a1566SKashyap Desai 		goto out_failed;
3712824a1566SKashyap Desai 	}
3713824a1566SKashyap Desai 
37142ac794baSSreekanth Reddy 	retval = mpi3mr_print_pkg_ver(mrioc);
37152ac794baSSreekanth Reddy 	if (retval) {
37162ac794baSSreekanth Reddy 		ioc_err(mrioc, "failed to get package version\n");
37172ac794baSSreekanth Reddy 		goto out_failed;
37182ac794baSSreekanth Reddy 	}
37192ac794baSSreekanth Reddy 
3720824a1566SKashyap Desai 	retval = mpi3mr_setup_isr(mrioc, 0);
3721824a1566SKashyap Desai 	if (retval) {
3722824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to re-setup ISR, error %d\n",
3723824a1566SKashyap Desai 		    retval);
3724fe6db615SSreekanth Reddy 		goto out_failed_noretry;
3725fb9b0457SKashyap Desai 	}
3726824a1566SKashyap Desai 
3727c9566231SKashyap Desai 	retval = mpi3mr_create_op_queues(mrioc);
3728c9566231SKashyap Desai 	if (retval) {
3729c9566231SKashyap Desai 		ioc_err(mrioc, "Failed to create OpQueues error %d\n",
3730c9566231SKashyap Desai 		    retval);
3731c9566231SKashyap Desai 		goto out_failed;
3732c9566231SKashyap Desai 	}
3733c9566231SKashyap Desai 
3734e3605f65SSreekanth Reddy 	retval = mpi3mr_enable_events(mrioc);
373513ef29eaSKashyap Desai 	if (retval) {
3736e3605f65SSreekanth Reddy 		ioc_err(mrioc, "failed to enable events %d\n",
373713ef29eaSKashyap Desai 		    retval);
373813ef29eaSKashyap Desai 		goto out_failed;
373913ef29eaSKashyap Desai 	}
374013ef29eaSKashyap Desai 
3741fe6db615SSreekanth Reddy 	ioc_info(mrioc, "controller initialization completed successfully\n");
3742824a1566SKashyap Desai 	return retval;
3743824a1566SKashyap Desai out_failed:
3744fe6db615SSreekanth Reddy 	if (retry < 2) {
3745fe6db615SSreekanth Reddy 		retry++;
3746fe6db615SSreekanth Reddy 		ioc_warn(mrioc, "retrying controller initialization, retry_count:%d\n",
3747fe6db615SSreekanth Reddy 		    retry);
3748fe6db615SSreekanth Reddy 		mpi3mr_memset_buffers(mrioc);
3749fe6db615SSreekanth Reddy 		goto retry_init;
3750fe6db615SSreekanth Reddy 	}
3751fe6db615SSreekanth Reddy out_failed_noretry:
3752fe6db615SSreekanth Reddy 	ioc_err(mrioc, "controller initialization failed\n");
3753fe6db615SSreekanth Reddy 	mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
3754fe6db615SSreekanth Reddy 	    MPI3MR_RESET_FROM_CTLR_CLEANUP);
3755fe6db615SSreekanth Reddy 	mrioc->unrecoverable = 1;
3756824a1566SKashyap Desai 	return retval;
3757824a1566SKashyap Desai }
3758824a1566SKashyap Desai 
3759c0b00a93SSreekanth Reddy /**
3760c0b00a93SSreekanth Reddy  * mpi3mr_reinit_ioc - Re-Initialize the controller
3761c0b00a93SSreekanth Reddy  * @mrioc: Adapter instance reference
3762c0b00a93SSreekanth Reddy  * @is_resume: Called from resume or reset path
3763c0b00a93SSreekanth Reddy  *
3764c0b00a93SSreekanth Reddy  * This the controller re-initialization routine, executed from
3765c0b00a93SSreekanth Reddy  * the soft reset handler or resume callback. Creates
3766c0b00a93SSreekanth Reddy  * operational reply queue pairs, allocate required memory for
3767c0b00a93SSreekanth Reddy  * reply pool, sense buffer pool, issue IOC init request to the
3768c0b00a93SSreekanth Reddy  * firmware, unmask the events and issue port enable to discover
3769c0b00a93SSreekanth Reddy  * SAS/SATA/NVMe devices and RAID volumes.
3770c0b00a93SSreekanth Reddy  *
3771c0b00a93SSreekanth Reddy  * Return: 0 on success and non-zero on failure.
3772c0b00a93SSreekanth Reddy  */
3773fe6db615SSreekanth Reddy int mpi3mr_reinit_ioc(struct mpi3mr_ioc *mrioc, u8 is_resume)
3774fe6db615SSreekanth Reddy {
3775c0b00a93SSreekanth Reddy 	int retval = 0;
3776c0b00a93SSreekanth Reddy 	u8 retry = 0;
3777c0b00a93SSreekanth Reddy 	struct mpi3_ioc_facts_data facts_data;
3778fe6db615SSreekanth Reddy 
3779c0b00a93SSreekanth Reddy retry_init:
3780c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "bringing up the controller to ready state\n");
3781c0b00a93SSreekanth Reddy 	retval = mpi3mr_bring_ioc_ready(mrioc);
3782c0b00a93SSreekanth Reddy 	if (retval) {
3783c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to bring to ready state\n");
3784c0b00a93SSreekanth Reddy 		goto out_failed_noretry;
3785c0b00a93SSreekanth Reddy 	}
3786c0b00a93SSreekanth Reddy 
3787c0b00a93SSreekanth Reddy 	if (is_resume) {
3788c0b00a93SSreekanth Reddy 		dprint_reset(mrioc, "setting up single ISR\n");
3789c0b00a93SSreekanth Reddy 		retval = mpi3mr_setup_isr(mrioc, 1);
3790c0b00a93SSreekanth Reddy 		if (retval) {
3791c0b00a93SSreekanth Reddy 			ioc_err(mrioc, "failed to setup ISR\n");
3792c0b00a93SSreekanth Reddy 			goto out_failed_noretry;
3793c0b00a93SSreekanth Reddy 		}
3794c0b00a93SSreekanth Reddy 	} else
3795c0b00a93SSreekanth Reddy 		mpi3mr_ioc_enable_intr(mrioc);
3796c0b00a93SSreekanth Reddy 
3797c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "getting ioc_facts\n");
3798c0b00a93SSreekanth Reddy 	retval = mpi3mr_issue_iocfacts(mrioc, &facts_data);
3799c0b00a93SSreekanth Reddy 	if (retval) {
3800c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to get ioc_facts\n");
3801c0b00a93SSreekanth Reddy 		goto out_failed;
3802c0b00a93SSreekanth Reddy 	}
3803c0b00a93SSreekanth Reddy 
3804c5758fc7SSreekanth Reddy 	dprint_reset(mrioc, "validating ioc_facts\n");
3805c5758fc7SSreekanth Reddy 	retval = mpi3mr_revalidate_factsdata(mrioc);
3806c5758fc7SSreekanth Reddy 	if (retval) {
3807c5758fc7SSreekanth Reddy 		ioc_err(mrioc, "failed to revalidate ioc_facts data\n");
3808c5758fc7SSreekanth Reddy 		goto out_failed_noretry;
3809c5758fc7SSreekanth Reddy 	}
3810c0b00a93SSreekanth Reddy 
3811c0b00a93SSreekanth Reddy 	mpi3mr_print_ioc_info(mrioc);
3812c0b00a93SSreekanth Reddy 
3813c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "sending ioc_init\n");
3814c0b00a93SSreekanth Reddy 	retval = mpi3mr_issue_iocinit(mrioc);
3815c0b00a93SSreekanth Reddy 	if (retval) {
3816c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to send ioc_init\n");
3817c0b00a93SSreekanth Reddy 		goto out_failed;
3818c0b00a93SSreekanth Reddy 	}
3819c0b00a93SSreekanth Reddy 
3820c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "getting package version\n");
3821c0b00a93SSreekanth Reddy 	retval = mpi3mr_print_pkg_ver(mrioc);
3822c0b00a93SSreekanth Reddy 	if (retval) {
3823c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to get package version\n");
3824c0b00a93SSreekanth Reddy 		goto out_failed;
3825c0b00a93SSreekanth Reddy 	}
3826c0b00a93SSreekanth Reddy 
3827c0b00a93SSreekanth Reddy 	if (is_resume) {
3828c0b00a93SSreekanth Reddy 		dprint_reset(mrioc, "setting up multiple ISR\n");
3829c0b00a93SSreekanth Reddy 		retval = mpi3mr_setup_isr(mrioc, 0);
3830c0b00a93SSreekanth Reddy 		if (retval) {
3831c0b00a93SSreekanth Reddy 			ioc_err(mrioc, "failed to re-setup ISR\n");
3832c0b00a93SSreekanth Reddy 			goto out_failed_noretry;
3833c0b00a93SSreekanth Reddy 		}
3834c0b00a93SSreekanth Reddy 	}
3835c0b00a93SSreekanth Reddy 
3836c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "creating operational queue pairs\n");
3837c0b00a93SSreekanth Reddy 	retval = mpi3mr_create_op_queues(mrioc);
3838c0b00a93SSreekanth Reddy 	if (retval) {
3839c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to create operational queue pairs\n");
3840c0b00a93SSreekanth Reddy 		goto out_failed;
3841c0b00a93SSreekanth Reddy 	}
3842c0b00a93SSreekanth Reddy 
3843c0b00a93SSreekanth Reddy 	if (mrioc->shost->nr_hw_queues > mrioc->num_op_reply_q) {
3844c0b00a93SSreekanth Reddy 		ioc_err(mrioc,
3845c0b00a93SSreekanth Reddy 		    "cannot create minimum number of operatioanl queues expected:%d created:%d\n",
3846c0b00a93SSreekanth Reddy 		    mrioc->shost->nr_hw_queues, mrioc->num_op_reply_q);
3847c0b00a93SSreekanth Reddy 		goto out_failed_noretry;
3848c0b00a93SSreekanth Reddy 	}
3849c0b00a93SSreekanth Reddy 
3850c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "enabling events\n");
3851c0b00a93SSreekanth Reddy 	retval = mpi3mr_enable_events(mrioc);
3852c0b00a93SSreekanth Reddy 	if (retval) {
3853c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to enable events\n");
3854c0b00a93SSreekanth Reddy 		goto out_failed;
3855c0b00a93SSreekanth Reddy 	}
3856c0b00a93SSreekanth Reddy 
3857c0b00a93SSreekanth Reddy 	ioc_info(mrioc, "sending port enable\n");
3858c0b00a93SSreekanth Reddy 	retval = mpi3mr_issue_port_enable(mrioc, 0);
3859c0b00a93SSreekanth Reddy 	if (retval) {
3860c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to issue port enable\n");
3861c0b00a93SSreekanth Reddy 		goto out_failed;
3862c0b00a93SSreekanth Reddy 	}
3863c0b00a93SSreekanth Reddy 
3864c0b00a93SSreekanth Reddy 	ioc_info(mrioc, "controller %s completed successfully\n",
3865c0b00a93SSreekanth Reddy 	    (is_resume)?"resume":"re-initialization");
3866c0b00a93SSreekanth Reddy 	return retval;
3867c0b00a93SSreekanth Reddy out_failed:
3868c0b00a93SSreekanth Reddy 	if (retry < 2) {
3869c0b00a93SSreekanth Reddy 		retry++;
3870c0b00a93SSreekanth Reddy 		ioc_warn(mrioc, "retrying controller %s, retry_count:%d\n",
3871c0b00a93SSreekanth Reddy 		    (is_resume)?"resume":"re-initialization", retry);
3872c0b00a93SSreekanth Reddy 		mpi3mr_memset_buffers(mrioc);
3873c0b00a93SSreekanth Reddy 		goto retry_init;
3874c0b00a93SSreekanth Reddy 	}
3875c0b00a93SSreekanth Reddy out_failed_noretry:
3876c0b00a93SSreekanth Reddy 	ioc_err(mrioc, "controller %s is failed\n",
3877c0b00a93SSreekanth Reddy 	    (is_resume)?"resume":"re-initialization");
3878c0b00a93SSreekanth Reddy 	mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
3879c0b00a93SSreekanth Reddy 	    MPI3MR_RESET_FROM_CTLR_CLEANUP);
3880c0b00a93SSreekanth Reddy 	mrioc->unrecoverable = 1;
3881c0b00a93SSreekanth Reddy 	return retval;
3882fe6db615SSreekanth Reddy }
3883fe6db615SSreekanth Reddy 
3884824a1566SKashyap Desai /**
3885fb9b0457SKashyap Desai  * mpi3mr_memset_op_reply_q_buffers - memset the operational reply queue's
3886fb9b0457SKashyap Desai  *					segments
3887fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
3888fb9b0457SKashyap Desai  * @qidx: Operational reply queue index
3889fb9b0457SKashyap Desai  *
3890fb9b0457SKashyap Desai  * Return: Nothing.
3891fb9b0457SKashyap Desai  */
3892fb9b0457SKashyap Desai static void mpi3mr_memset_op_reply_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx)
3893fb9b0457SKashyap Desai {
3894fb9b0457SKashyap Desai 	struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
3895fb9b0457SKashyap Desai 	struct segments *segments;
3896fb9b0457SKashyap Desai 	int i, size;
3897fb9b0457SKashyap Desai 
3898fb9b0457SKashyap Desai 	if (!op_reply_q->q_segments)
3899fb9b0457SKashyap Desai 		return;
3900fb9b0457SKashyap Desai 
3901fb9b0457SKashyap Desai 	size = op_reply_q->segment_qd * mrioc->op_reply_desc_sz;
3902fb9b0457SKashyap Desai 	segments = op_reply_q->q_segments;
3903fb9b0457SKashyap Desai 	for (i = 0; i < op_reply_q->num_segments; i++)
3904fb9b0457SKashyap Desai 		memset(segments[i].segment, 0, size);
3905fb9b0457SKashyap Desai }
3906fb9b0457SKashyap Desai 
3907fb9b0457SKashyap Desai /**
3908fb9b0457SKashyap Desai  * mpi3mr_memset_op_req_q_buffers - memset the operational request queue's
3909fb9b0457SKashyap Desai  *					segments
3910fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
3911fb9b0457SKashyap Desai  * @qidx: Operational request queue index
3912fb9b0457SKashyap Desai  *
3913fb9b0457SKashyap Desai  * Return: Nothing.
3914fb9b0457SKashyap Desai  */
3915fb9b0457SKashyap Desai static void mpi3mr_memset_op_req_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx)
3916fb9b0457SKashyap Desai {
3917fb9b0457SKashyap Desai 	struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx;
3918fb9b0457SKashyap Desai 	struct segments *segments;
3919fb9b0457SKashyap Desai 	int i, size;
3920fb9b0457SKashyap Desai 
3921fb9b0457SKashyap Desai 	if (!op_req_q->q_segments)
3922fb9b0457SKashyap Desai 		return;
3923fb9b0457SKashyap Desai 
3924fb9b0457SKashyap Desai 	size = op_req_q->segment_qd * mrioc->facts.op_req_sz;
3925fb9b0457SKashyap Desai 	segments = op_req_q->q_segments;
3926fb9b0457SKashyap Desai 	for (i = 0; i < op_req_q->num_segments; i++)
3927fb9b0457SKashyap Desai 		memset(segments[i].segment, 0, size);
3928fb9b0457SKashyap Desai }
3929fb9b0457SKashyap Desai 
3930fb9b0457SKashyap Desai /**
3931fb9b0457SKashyap Desai  * mpi3mr_memset_buffers - memset memory for a controller
3932fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
3933fb9b0457SKashyap Desai  *
3934fb9b0457SKashyap Desai  * clear all the memory allocated for a controller, typically
3935fb9b0457SKashyap Desai  * called post reset to reuse the memory allocated during the
3936fb9b0457SKashyap Desai  * controller init.
3937fb9b0457SKashyap Desai  *
3938fb9b0457SKashyap Desai  * Return: Nothing.
3939fb9b0457SKashyap Desai  */
39400da66348SKashyap Desai void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc)
3941fb9b0457SKashyap Desai {
3942fb9b0457SKashyap Desai 	u16 i;
3943fb9b0457SKashyap Desai 
3944fe6db615SSreekanth Reddy 	mrioc->change_count = 0;
3945*afd3a579SSreekanth Reddy 	mrioc->active_poll_qcount = 0;
3946*afd3a579SSreekanth Reddy 	mrioc->default_qcount = 0;
3947fe6db615SSreekanth Reddy 	if (mrioc->admin_req_base)
3948fb9b0457SKashyap Desai 		memset(mrioc->admin_req_base, 0, mrioc->admin_req_q_sz);
3949fe6db615SSreekanth Reddy 	if (mrioc->admin_reply_base)
3950fb9b0457SKashyap Desai 		memset(mrioc->admin_reply_base, 0, mrioc->admin_reply_q_sz);
3951fb9b0457SKashyap Desai 
3952fe6db615SSreekanth Reddy 	if (mrioc->init_cmds.reply) {
3953fb9b0457SKashyap Desai 		memset(mrioc->init_cmds.reply, 0, sizeof(*mrioc->init_cmds.reply));
3954e844adb1SKashyap Desai 		memset(mrioc->host_tm_cmds.reply, 0,
3955e844adb1SKashyap Desai 		    sizeof(*mrioc->host_tm_cmds.reply));
3956fb9b0457SKashyap Desai 		for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++)
3957fb9b0457SKashyap Desai 			memset(mrioc->dev_rmhs_cmds[i].reply, 0,
3958fb9b0457SKashyap Desai 			    sizeof(*mrioc->dev_rmhs_cmds[i].reply));
3959c1af985dSSreekanth Reddy 		for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++)
3960c1af985dSSreekanth Reddy 			memset(mrioc->evtack_cmds[i].reply, 0,
3961c1af985dSSreekanth Reddy 			    sizeof(*mrioc->evtack_cmds[i].reply));
3962fb9b0457SKashyap Desai 		memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz);
3963fb9b0457SKashyap Desai 		memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz);
3964c1af985dSSreekanth Reddy 		memset(mrioc->evtack_cmds_bitmap, 0,
3965c1af985dSSreekanth Reddy 		    mrioc->evtack_cmds_bitmap_sz);
3966fe6db615SSreekanth Reddy 	}
3967fb9b0457SKashyap Desai 
3968fb9b0457SKashyap Desai 	for (i = 0; i < mrioc->num_queues; i++) {
3969fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].qid = 0;
3970fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].ci = 0;
3971fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].num_replies = 0;
3972fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].ephase = 0;
3973463429f8SKashyap Desai 		atomic_set(&mrioc->op_reply_qinfo[i].pend_ios, 0);
3974463429f8SKashyap Desai 		atomic_set(&mrioc->op_reply_qinfo[i].in_use, 0);
3975fb9b0457SKashyap Desai 		mpi3mr_memset_op_reply_q_buffers(mrioc, i);
3976fb9b0457SKashyap Desai 
3977fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].ci = 0;
3978fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].pi = 0;
3979fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].num_requests = 0;
3980fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].qid = 0;
3981fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].reply_qid = 0;
3982fb9b0457SKashyap Desai 		spin_lock_init(&mrioc->req_qinfo[i].q_lock);
3983fb9b0457SKashyap Desai 		mpi3mr_memset_op_req_q_buffers(mrioc, i);
3984fb9b0457SKashyap Desai 	}
3985fb9b0457SKashyap Desai }
3986fb9b0457SKashyap Desai 
3987fb9b0457SKashyap Desai /**
3988824a1566SKashyap Desai  * mpi3mr_free_mem - Free memory allocated for a controller
3989824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3990824a1566SKashyap Desai  *
3991824a1566SKashyap Desai  * Free all the memory allocated for a controller.
3992824a1566SKashyap Desai  *
3993824a1566SKashyap Desai  * Return: Nothing.
3994824a1566SKashyap Desai  */
3995fe6db615SSreekanth Reddy void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc)
3996824a1566SKashyap Desai {
3997824a1566SKashyap Desai 	u16 i;
3998824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info;
3999824a1566SKashyap Desai 
4000824a1566SKashyap Desai 	if (mrioc->sense_buf_pool) {
4001824a1566SKashyap Desai 		if (mrioc->sense_buf)
4002824a1566SKashyap Desai 			dma_pool_free(mrioc->sense_buf_pool, mrioc->sense_buf,
4003824a1566SKashyap Desai 			    mrioc->sense_buf_dma);
4004824a1566SKashyap Desai 		dma_pool_destroy(mrioc->sense_buf_pool);
4005824a1566SKashyap Desai 		mrioc->sense_buf = NULL;
4006824a1566SKashyap Desai 		mrioc->sense_buf_pool = NULL;
4007824a1566SKashyap Desai 	}
4008824a1566SKashyap Desai 	if (mrioc->sense_buf_q_pool) {
4009824a1566SKashyap Desai 		if (mrioc->sense_buf_q)
4010824a1566SKashyap Desai 			dma_pool_free(mrioc->sense_buf_q_pool,
4011824a1566SKashyap Desai 			    mrioc->sense_buf_q, mrioc->sense_buf_q_dma);
4012824a1566SKashyap Desai 		dma_pool_destroy(mrioc->sense_buf_q_pool);
4013824a1566SKashyap Desai 		mrioc->sense_buf_q = NULL;
4014824a1566SKashyap Desai 		mrioc->sense_buf_q_pool = NULL;
4015824a1566SKashyap Desai 	}
4016824a1566SKashyap Desai 
4017824a1566SKashyap Desai 	if (mrioc->reply_buf_pool) {
4018824a1566SKashyap Desai 		if (mrioc->reply_buf)
4019824a1566SKashyap Desai 			dma_pool_free(mrioc->reply_buf_pool, mrioc->reply_buf,
4020824a1566SKashyap Desai 			    mrioc->reply_buf_dma);
4021824a1566SKashyap Desai 		dma_pool_destroy(mrioc->reply_buf_pool);
4022824a1566SKashyap Desai 		mrioc->reply_buf = NULL;
4023824a1566SKashyap Desai 		mrioc->reply_buf_pool = NULL;
4024824a1566SKashyap Desai 	}
4025824a1566SKashyap Desai 	if (mrioc->reply_free_q_pool) {
4026824a1566SKashyap Desai 		if (mrioc->reply_free_q)
4027824a1566SKashyap Desai 			dma_pool_free(mrioc->reply_free_q_pool,
4028824a1566SKashyap Desai 			    mrioc->reply_free_q, mrioc->reply_free_q_dma);
4029824a1566SKashyap Desai 		dma_pool_destroy(mrioc->reply_free_q_pool);
4030824a1566SKashyap Desai 		mrioc->reply_free_q = NULL;
4031824a1566SKashyap Desai 		mrioc->reply_free_q_pool = NULL;
4032824a1566SKashyap Desai 	}
4033824a1566SKashyap Desai 
4034c9566231SKashyap Desai 	for (i = 0; i < mrioc->num_op_req_q; i++)
4035c9566231SKashyap Desai 		mpi3mr_free_op_req_q_segments(mrioc, i);
4036c9566231SKashyap Desai 
4037c9566231SKashyap Desai 	for (i = 0; i < mrioc->num_op_reply_q; i++)
4038c9566231SKashyap Desai 		mpi3mr_free_op_reply_q_segments(mrioc, i);
4039c9566231SKashyap Desai 
4040824a1566SKashyap Desai 	for (i = 0; i < mrioc->intr_info_count; i++) {
4041824a1566SKashyap Desai 		intr_info = mrioc->intr_info + i;
4042824a1566SKashyap Desai 		intr_info->op_reply_q = NULL;
4043824a1566SKashyap Desai 	}
4044824a1566SKashyap Desai 
4045824a1566SKashyap Desai 	kfree(mrioc->req_qinfo);
4046824a1566SKashyap Desai 	mrioc->req_qinfo = NULL;
4047824a1566SKashyap Desai 	mrioc->num_op_req_q = 0;
4048824a1566SKashyap Desai 
4049824a1566SKashyap Desai 	kfree(mrioc->op_reply_qinfo);
4050824a1566SKashyap Desai 	mrioc->op_reply_qinfo = NULL;
4051824a1566SKashyap Desai 	mrioc->num_op_reply_q = 0;
4052824a1566SKashyap Desai 
4053824a1566SKashyap Desai 	kfree(mrioc->init_cmds.reply);
4054824a1566SKashyap Desai 	mrioc->init_cmds.reply = NULL;
4055824a1566SKashyap Desai 
4056e844adb1SKashyap Desai 	kfree(mrioc->host_tm_cmds.reply);
4057e844adb1SKashyap Desai 	mrioc->host_tm_cmds.reply = NULL;
4058e844adb1SKashyap Desai 
4059c1af985dSSreekanth Reddy 	for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) {
4060c1af985dSSreekanth Reddy 		kfree(mrioc->evtack_cmds[i].reply);
4061c1af985dSSreekanth Reddy 		mrioc->evtack_cmds[i].reply = NULL;
4062c1af985dSSreekanth Reddy 	}
4063c1af985dSSreekanth Reddy 
4064e844adb1SKashyap Desai 	kfree(mrioc->removepend_bitmap);
4065e844adb1SKashyap Desai 	mrioc->removepend_bitmap = NULL;
4066e844adb1SKashyap Desai 
4067e844adb1SKashyap Desai 	kfree(mrioc->devrem_bitmap);
4068e844adb1SKashyap Desai 	mrioc->devrem_bitmap = NULL;
4069e844adb1SKashyap Desai 
4070c1af985dSSreekanth Reddy 	kfree(mrioc->evtack_cmds_bitmap);
4071c1af985dSSreekanth Reddy 	mrioc->evtack_cmds_bitmap = NULL;
4072c1af985dSSreekanth Reddy 
4073824a1566SKashyap Desai 	kfree(mrioc->chain_bitmap);
4074824a1566SKashyap Desai 	mrioc->chain_bitmap = NULL;
4075824a1566SKashyap Desai 
407613ef29eaSKashyap Desai 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
407713ef29eaSKashyap Desai 		kfree(mrioc->dev_rmhs_cmds[i].reply);
407813ef29eaSKashyap Desai 		mrioc->dev_rmhs_cmds[i].reply = NULL;
407913ef29eaSKashyap Desai 	}
408013ef29eaSKashyap Desai 
4081824a1566SKashyap Desai 	if (mrioc->chain_buf_pool) {
4082824a1566SKashyap Desai 		for (i = 0; i < mrioc->chain_buf_count; i++) {
4083824a1566SKashyap Desai 			if (mrioc->chain_sgl_list[i].addr) {
4084824a1566SKashyap Desai 				dma_pool_free(mrioc->chain_buf_pool,
4085824a1566SKashyap Desai 				    mrioc->chain_sgl_list[i].addr,
4086824a1566SKashyap Desai 				    mrioc->chain_sgl_list[i].dma_addr);
4087824a1566SKashyap Desai 				mrioc->chain_sgl_list[i].addr = NULL;
4088824a1566SKashyap Desai 			}
4089824a1566SKashyap Desai 		}
4090824a1566SKashyap Desai 		dma_pool_destroy(mrioc->chain_buf_pool);
4091824a1566SKashyap Desai 		mrioc->chain_buf_pool = NULL;
4092824a1566SKashyap Desai 	}
4093824a1566SKashyap Desai 
4094824a1566SKashyap Desai 	kfree(mrioc->chain_sgl_list);
4095824a1566SKashyap Desai 	mrioc->chain_sgl_list = NULL;
4096824a1566SKashyap Desai 
4097824a1566SKashyap Desai 	if (mrioc->admin_reply_base) {
4098824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz,
4099824a1566SKashyap Desai 		    mrioc->admin_reply_base, mrioc->admin_reply_dma);
4100824a1566SKashyap Desai 		mrioc->admin_reply_base = NULL;
4101824a1566SKashyap Desai 	}
4102824a1566SKashyap Desai 	if (mrioc->admin_req_base) {
4103824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz,
4104824a1566SKashyap Desai 		    mrioc->admin_req_base, mrioc->admin_req_dma);
4105824a1566SKashyap Desai 		mrioc->admin_req_base = NULL;
4106824a1566SKashyap Desai 	}
4107824a1566SKashyap Desai }
4108824a1566SKashyap Desai 
4109824a1566SKashyap Desai /**
4110824a1566SKashyap Desai  * mpi3mr_issue_ioc_shutdown - shutdown controller
4111824a1566SKashyap Desai  * @mrioc: Adapter instance reference
4112824a1566SKashyap Desai  *
4113824a1566SKashyap Desai  * Send shutodwn notification to the controller and wait for the
4114824a1566SKashyap Desai  * shutdown_timeout for it to be completed.
4115824a1566SKashyap Desai  *
4116824a1566SKashyap Desai  * Return: Nothing.
4117824a1566SKashyap Desai  */
4118824a1566SKashyap Desai static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc)
4119824a1566SKashyap Desai {
4120824a1566SKashyap Desai 	u32 ioc_config, ioc_status;
4121824a1566SKashyap Desai 	u8 retval = 1;
4122824a1566SKashyap Desai 	u32 timeout = MPI3MR_DEFAULT_SHUTDOWN_TIME * 10;
4123824a1566SKashyap Desai 
4124824a1566SKashyap Desai 	ioc_info(mrioc, "Issuing shutdown Notification\n");
4125824a1566SKashyap Desai 	if (mrioc->unrecoverable) {
4126824a1566SKashyap Desai 		ioc_warn(mrioc,
4127824a1566SKashyap Desai 		    "IOC is unrecoverable shutdown is not issued\n");
4128824a1566SKashyap Desai 		return;
4129824a1566SKashyap Desai 	}
4130824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
4131824a1566SKashyap Desai 	if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
4132824a1566SKashyap Desai 	    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS) {
4133824a1566SKashyap Desai 		ioc_info(mrioc, "shutdown already in progress\n");
4134824a1566SKashyap Desai 		return;
4135824a1566SKashyap Desai 	}
4136824a1566SKashyap Desai 
4137824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
4138824a1566SKashyap Desai 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL;
4139ec5ebd2cSSreekanth Reddy 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN_SEND_REQ;
4140824a1566SKashyap Desai 
4141824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
4142824a1566SKashyap Desai 
4143824a1566SKashyap Desai 	if (mrioc->facts.shutdown_timeout)
4144824a1566SKashyap Desai 		timeout = mrioc->facts.shutdown_timeout * 10;
4145824a1566SKashyap Desai 
4146824a1566SKashyap Desai 	do {
4147824a1566SKashyap Desai 		ioc_status = readl(&mrioc->sysif_regs->ioc_status);
4148824a1566SKashyap Desai 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
4149824a1566SKashyap Desai 		    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_COMPLETE) {
4150824a1566SKashyap Desai 			retval = 0;
4151824a1566SKashyap Desai 			break;
4152824a1566SKashyap Desai 		}
4153824a1566SKashyap Desai 		msleep(100);
4154824a1566SKashyap Desai 	} while (--timeout);
4155824a1566SKashyap Desai 
4156824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
4157824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
4158824a1566SKashyap Desai 
4159824a1566SKashyap Desai 	if (retval) {
4160824a1566SKashyap Desai 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
4161824a1566SKashyap Desai 		    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS)
4162824a1566SKashyap Desai 			ioc_warn(mrioc,
4163824a1566SKashyap Desai 			    "shutdown still in progress after timeout\n");
4164824a1566SKashyap Desai 	}
4165824a1566SKashyap Desai 
4166824a1566SKashyap Desai 	ioc_info(mrioc,
4167824a1566SKashyap Desai 	    "Base IOC Sts/Config after %s shutdown is (0x%x)/(0x%x)\n",
4168824a1566SKashyap Desai 	    (!retval) ? "successful" : "failed", ioc_status,
4169824a1566SKashyap Desai 	    ioc_config);
4170824a1566SKashyap Desai }
4171824a1566SKashyap Desai 
4172824a1566SKashyap Desai /**
4173824a1566SKashyap Desai  * mpi3mr_cleanup_ioc - Cleanup controller
4174824a1566SKashyap Desai  * @mrioc: Adapter instance reference
4175fe6db615SSreekanth Reddy 
4176824a1566SKashyap Desai  * controller cleanup handler, Message unit reset or soft reset
4177fe6db615SSreekanth Reddy  * and shutdown notification is issued to the controller.
4178824a1566SKashyap Desai  *
4179824a1566SKashyap Desai  * Return: Nothing.
4180824a1566SKashyap Desai  */
4181fe6db615SSreekanth Reddy void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc)
4182824a1566SKashyap Desai {
4183824a1566SKashyap Desai 	enum mpi3mr_iocstate ioc_state;
4184824a1566SKashyap Desai 
4185fe6db615SSreekanth Reddy 	dprint_exit(mrioc, "cleaning up the controller\n");
4186824a1566SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
4187824a1566SKashyap Desai 
4188824a1566SKashyap Desai 	ioc_state = mpi3mr_get_iocstate(mrioc);
4189824a1566SKashyap Desai 
4190824a1566SKashyap Desai 	if ((!mrioc->unrecoverable) && (!mrioc->reset_in_progress) &&
4191824a1566SKashyap Desai 	    (ioc_state == MRIOC_STATE_READY)) {
4192824a1566SKashyap Desai 		if (mpi3mr_issue_and_process_mur(mrioc,
4193824a1566SKashyap Desai 		    MPI3MR_RESET_FROM_CTLR_CLEANUP))
4194824a1566SKashyap Desai 			mpi3mr_issue_reset(mrioc,
4195824a1566SKashyap Desai 			    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
4196824a1566SKashyap Desai 			    MPI3MR_RESET_FROM_MUR_FAILURE);
4197824a1566SKashyap Desai 		mpi3mr_issue_ioc_shutdown(mrioc);
4198824a1566SKashyap Desai 	}
4199fe6db615SSreekanth Reddy 	dprint_exit(mrioc, "controller cleanup completed\n");
4200fb9b0457SKashyap Desai }
4201fb9b0457SKashyap Desai 
4202fb9b0457SKashyap Desai /**
4203fb9b0457SKashyap Desai  * mpi3mr_drv_cmd_comp_reset - Flush a internal driver command
4204fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
4205fb9b0457SKashyap Desai  * @cmdptr: Internal command tracker
4206fb9b0457SKashyap Desai  *
4207fb9b0457SKashyap Desai  * Complete an internal driver commands with state indicating it
4208fb9b0457SKashyap Desai  * is completed due to reset.
4209fb9b0457SKashyap Desai  *
4210fb9b0457SKashyap Desai  * Return: Nothing.
4211fb9b0457SKashyap Desai  */
4212fb9b0457SKashyap Desai static inline void mpi3mr_drv_cmd_comp_reset(struct mpi3mr_ioc *mrioc,
4213fb9b0457SKashyap Desai 	struct mpi3mr_drv_cmd *cmdptr)
4214fb9b0457SKashyap Desai {
4215fb9b0457SKashyap Desai 	if (cmdptr->state & MPI3MR_CMD_PENDING) {
4216fb9b0457SKashyap Desai 		cmdptr->state |= MPI3MR_CMD_RESET;
4217fb9b0457SKashyap Desai 		cmdptr->state &= ~MPI3MR_CMD_PENDING;
4218fb9b0457SKashyap Desai 		if (cmdptr->is_waiting) {
4219fb9b0457SKashyap Desai 			complete(&cmdptr->done);
4220fb9b0457SKashyap Desai 			cmdptr->is_waiting = 0;
4221fb9b0457SKashyap Desai 		} else if (cmdptr->callback)
4222fb9b0457SKashyap Desai 			cmdptr->callback(mrioc, cmdptr);
4223fb9b0457SKashyap Desai 	}
4224fb9b0457SKashyap Desai }
4225fb9b0457SKashyap Desai 
4226fb9b0457SKashyap Desai /**
4227fb9b0457SKashyap Desai  * mpi3mr_flush_drv_cmds - Flush internaldriver commands
4228fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
4229fb9b0457SKashyap Desai  *
4230fb9b0457SKashyap Desai  * Flush all internal driver commands post reset
4231fb9b0457SKashyap Desai  *
4232fb9b0457SKashyap Desai  * Return: Nothing.
4233fb9b0457SKashyap Desai  */
4234fb9b0457SKashyap Desai static void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc)
4235fb9b0457SKashyap Desai {
4236fb9b0457SKashyap Desai 	struct mpi3mr_drv_cmd *cmdptr;
4237fb9b0457SKashyap Desai 	u8 i;
4238fb9b0457SKashyap Desai 
4239fb9b0457SKashyap Desai 	cmdptr = &mrioc->init_cmds;
4240fb9b0457SKashyap Desai 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
4241e844adb1SKashyap Desai 	cmdptr = &mrioc->host_tm_cmds;
4242e844adb1SKashyap Desai 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
4243fb9b0457SKashyap Desai 
4244fb9b0457SKashyap Desai 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
4245fb9b0457SKashyap Desai 		cmdptr = &mrioc->dev_rmhs_cmds[i];
4246fb9b0457SKashyap Desai 		mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
4247fb9b0457SKashyap Desai 	}
4248c1af985dSSreekanth Reddy 
4249c1af985dSSreekanth Reddy 	for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) {
4250c1af985dSSreekanth Reddy 		cmdptr = &mrioc->evtack_cmds[i];
4251c1af985dSSreekanth Reddy 		mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
4252c1af985dSSreekanth Reddy 	}
4253fb9b0457SKashyap Desai }
4254fb9b0457SKashyap Desai 
4255fb9b0457SKashyap Desai /**
4256824a1566SKashyap Desai  * mpi3mr_soft_reset_handler - Reset the controller
4257824a1566SKashyap Desai  * @mrioc: Adapter instance reference
4258824a1566SKashyap Desai  * @reset_reason: Reset reason code
4259824a1566SKashyap Desai  * @snapdump: Flag to generate snapdump in firmware or not
4260824a1566SKashyap Desai  *
4261fb9b0457SKashyap Desai  * This is an handler for recovering controller by issuing soft
4262fb9b0457SKashyap Desai  * reset are diag fault reset.  This is a blocking function and
4263fb9b0457SKashyap Desai  * when one reset is executed if any other resets they will be
4264fb9b0457SKashyap Desai  * blocked. All IOCTLs/IO will be blocked during the reset. If
4265fb9b0457SKashyap Desai  * controller reset is successful then the controller will be
4266fb9b0457SKashyap Desai  * reinitalized, otherwise the controller will be marked as not
4267fb9b0457SKashyap Desai  * recoverable
4268fb9b0457SKashyap Desai  *
4269fb9b0457SKashyap Desai  * In snapdump bit is set, the controller is issued with diag
4270fb9b0457SKashyap Desai  * fault reset so that the firmware can create a snap dump and
4271fb9b0457SKashyap Desai  * post that the firmware will result in F000 fault and the
4272fb9b0457SKashyap Desai  * driver will issue soft reset to recover from that.
4273824a1566SKashyap Desai  *
4274824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
4275824a1566SKashyap Desai  */
4276824a1566SKashyap Desai int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
4277824a1566SKashyap Desai 	u32 reset_reason, u8 snapdump)
4278824a1566SKashyap Desai {
4279fb9b0457SKashyap Desai 	int retval = 0, i;
4280fb9b0457SKashyap Desai 	unsigned long flags;
4281fb9b0457SKashyap Desai 	u32 host_diagnostic, timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10;
4282fb9b0457SKashyap Desai 
4283b64845a7SSreekanth Reddy 	/* Block the reset handler until diag save in progress*/
4284b64845a7SSreekanth Reddy 	dprint_reset(mrioc,
4285b64845a7SSreekanth Reddy 	    "soft_reset_handler: check and block on diagsave_timeout(%d)\n",
4286b64845a7SSreekanth Reddy 	    mrioc->diagsave_timeout);
4287b64845a7SSreekanth Reddy 	while (mrioc->diagsave_timeout)
4288b64845a7SSreekanth Reddy 		ssleep(1);
4289fb9b0457SKashyap Desai 	/*
4290fb9b0457SKashyap Desai 	 * Block new resets until the currently executing one is finished and
4291fb9b0457SKashyap Desai 	 * return the status of the existing reset for all blocked resets
4292fb9b0457SKashyap Desai 	 */
4293b64845a7SSreekanth Reddy 	dprint_reset(mrioc, "soft_reset_handler: acquiring reset_mutex\n");
4294fb9b0457SKashyap Desai 	if (!mutex_trylock(&mrioc->reset_mutex)) {
4295b64845a7SSreekanth Reddy 		ioc_info(mrioc,
4296b64845a7SSreekanth Reddy 		    "controller reset triggered by %s is blocked due to another reset in progress\n",
4297b64845a7SSreekanth Reddy 		    mpi3mr_reset_rc_name(reset_reason));
4298b64845a7SSreekanth Reddy 		do {
4299b64845a7SSreekanth Reddy 			ssleep(1);
4300b64845a7SSreekanth Reddy 		} while (mrioc->reset_in_progress == 1);
4301b64845a7SSreekanth Reddy 		ioc_info(mrioc,
4302b64845a7SSreekanth Reddy 		    "returning previous reset result(%d) for the reset triggered by %s\n",
4303b64845a7SSreekanth Reddy 		    mrioc->prev_reset_result,
4304b64845a7SSreekanth Reddy 		    mpi3mr_reset_rc_name(reset_reason));
4305b64845a7SSreekanth Reddy 		return mrioc->prev_reset_result;
4306fb9b0457SKashyap Desai 	}
4307b64845a7SSreekanth Reddy 	ioc_info(mrioc, "controller reset is triggered by %s\n",
4308b64845a7SSreekanth Reddy 	    mpi3mr_reset_rc_name(reset_reason));
4309b64845a7SSreekanth Reddy 
4310fb9b0457SKashyap Desai 	mrioc->reset_in_progress = 1;
4311b64845a7SSreekanth Reddy 	mrioc->prev_reset_result = -1;
4312fb9b0457SKashyap Desai 
4313fb9b0457SKashyap Desai 	if ((!snapdump) && (reset_reason != MPI3MR_RESET_FROM_FAULT_WATCH) &&
4314b64845a7SSreekanth Reddy 	    (reset_reason != MPI3MR_RESET_FROM_FIRMWARE) &&
4315fb9b0457SKashyap Desai 	    (reset_reason != MPI3MR_RESET_FROM_CIACTIV_FAULT)) {
4316fb9b0457SKashyap Desai 		for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
4317fb9b0457SKashyap Desai 			mrioc->event_masks[i] = -1;
4318fb9b0457SKashyap Desai 
4319b64845a7SSreekanth Reddy 		dprint_reset(mrioc, "soft_reset_handler: masking events\n");
4320b64845a7SSreekanth Reddy 		mpi3mr_issue_event_notification(mrioc);
4321fb9b0457SKashyap Desai 	}
4322fb9b0457SKashyap Desai 
432344dc724fSKashyap Desai 	mpi3mr_wait_for_host_io(mrioc, MPI3MR_RESET_HOST_IOWAIT_TIMEOUT);
432444dc724fSKashyap Desai 
4325fb9b0457SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
4326fb9b0457SKashyap Desai 
4327fb9b0457SKashyap Desai 	if (snapdump) {
4328fb9b0457SKashyap Desai 		mpi3mr_set_diagsave(mrioc);
4329fb9b0457SKashyap Desai 		retval = mpi3mr_issue_reset(mrioc,
4330fb9b0457SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
4331fb9b0457SKashyap Desai 		if (!retval) {
4332fb9b0457SKashyap Desai 			do {
4333fb9b0457SKashyap Desai 				host_diagnostic =
4334fb9b0457SKashyap Desai 				    readl(&mrioc->sysif_regs->host_diagnostic);
4335fb9b0457SKashyap Desai 				if (!(host_diagnostic &
4336fb9b0457SKashyap Desai 				    MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS))
4337fb9b0457SKashyap Desai 					break;
4338fb9b0457SKashyap Desai 				msleep(100);
4339fb9b0457SKashyap Desai 			} while (--timeout);
4340fb9b0457SKashyap Desai 		}
4341fb9b0457SKashyap Desai 	}
4342fb9b0457SKashyap Desai 
4343fb9b0457SKashyap Desai 	retval = mpi3mr_issue_reset(mrioc,
4344fb9b0457SKashyap Desai 	    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, reset_reason);
4345fb9b0457SKashyap Desai 	if (retval) {
4346fb9b0457SKashyap Desai 		ioc_err(mrioc, "Failed to issue soft reset to the ioc\n");
4347fb9b0457SKashyap Desai 		goto out;
4348fb9b0457SKashyap Desai 	}
4349fb9b0457SKashyap Desai 
4350c1af985dSSreekanth Reddy 	mpi3mr_flush_delayed_cmd_lists(mrioc);
4351fb9b0457SKashyap Desai 	mpi3mr_flush_drv_cmds(mrioc);
4352fb9b0457SKashyap Desai 	memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz);
4353fb9b0457SKashyap Desai 	memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz);
4354c1af985dSSreekanth Reddy 	memset(mrioc->evtack_cmds_bitmap, 0, mrioc->evtack_cmds_bitmap_sz);
4355fb9b0457SKashyap Desai 	mpi3mr_cleanup_fwevt_list(mrioc);
4356fb9b0457SKashyap Desai 	mpi3mr_flush_host_io(mrioc);
4357fb9b0457SKashyap Desai 	mpi3mr_invalidate_devhandles(mrioc);
435878b76a07SSreekanth Reddy 	if (mrioc->prepare_for_reset) {
435978b76a07SSreekanth Reddy 		mrioc->prepare_for_reset = 0;
436078b76a07SSreekanth Reddy 		mrioc->prepare_for_reset_timeout_counter = 0;
436178b76a07SSreekanth Reddy 	}
4362fb9b0457SKashyap Desai 	mpi3mr_memset_buffers(mrioc);
4363fe6db615SSreekanth Reddy 	retval = mpi3mr_reinit_ioc(mrioc, 0);
4364fb9b0457SKashyap Desai 	if (retval) {
4365fb9b0457SKashyap Desai 		pr_err(IOCNAME "reinit after soft reset failed: reason %d\n",
4366fb9b0457SKashyap Desai 		    mrioc->name, reset_reason);
4367fb9b0457SKashyap Desai 		goto out;
4368fb9b0457SKashyap Desai 	}
4369fb9b0457SKashyap Desai 	ssleep(10);
4370fb9b0457SKashyap Desai 
4371fb9b0457SKashyap Desai out:
4372fb9b0457SKashyap Desai 	if (!retval) {
4373b64845a7SSreekanth Reddy 		mrioc->diagsave_timeout = 0;
4374fb9b0457SKashyap Desai 		mrioc->reset_in_progress = 0;
4375fb9b0457SKashyap Desai 		mpi3mr_rfresh_tgtdevs(mrioc);
437654dfcffbSKashyap Desai 		mrioc->ts_update_counter = 0;
4377fb9b0457SKashyap Desai 		spin_lock_irqsave(&mrioc->watchdog_lock, flags);
4378fb9b0457SKashyap Desai 		if (mrioc->watchdog_work_q)
4379fb9b0457SKashyap Desai 			queue_delayed_work(mrioc->watchdog_work_q,
4380fb9b0457SKashyap Desai 			    &mrioc->watchdog_work,
4381fb9b0457SKashyap Desai 			    msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL));
4382fb9b0457SKashyap Desai 		spin_unlock_irqrestore(&mrioc->watchdog_lock, flags);
4383fb9b0457SKashyap Desai 	} else {
4384fb9b0457SKashyap Desai 		mpi3mr_issue_reset(mrioc,
4385fb9b0457SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
4386fb9b0457SKashyap Desai 		mrioc->unrecoverable = 1;
4387fb9b0457SKashyap Desai 		mrioc->reset_in_progress = 0;
4388fb9b0457SKashyap Desai 		retval = -1;
4389fb9b0457SKashyap Desai 	}
4390b64845a7SSreekanth Reddy 	mrioc->prev_reset_result = retval;
4391fb9b0457SKashyap Desai 	mutex_unlock(&mrioc->reset_mutex);
4392b64845a7SSreekanth Reddy 	ioc_info(mrioc, "controller reset is %s\n",
4393b64845a7SSreekanth Reddy 	    ((retval == 0) ? "successful" : "failed"));
4394fb9b0457SKashyap Desai 	return retval;
4395824a1566SKashyap Desai }
4396