xref: /linux/drivers/scsi/mpi3mr/mpi3mr_fw.c (revision 78b76a0768ef8a25ab92a28da4ac9a74db762c47)
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 
19824a1566SKashyap Desai #if defined(writeq) && defined(CONFIG_64BIT)
20824a1566SKashyap Desai static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr)
21824a1566SKashyap Desai {
22824a1566SKashyap Desai 	writeq(b, addr);
23824a1566SKashyap Desai }
24824a1566SKashyap Desai #else
25824a1566SKashyap Desai static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr)
26824a1566SKashyap Desai {
27824a1566SKashyap Desai 	__u64 data_out = b;
28824a1566SKashyap Desai 
29824a1566SKashyap Desai 	writel((u32)(data_out), addr);
30824a1566SKashyap Desai 	writel((u32)(data_out >> 32), (addr + 4));
31824a1566SKashyap Desai }
32824a1566SKashyap Desai #endif
33824a1566SKashyap Desai 
34023ab2a9SKashyap Desai static inline bool
35023ab2a9SKashyap Desai mpi3mr_check_req_qfull(struct op_req_qinfo *op_req_q)
36023ab2a9SKashyap Desai {
37023ab2a9SKashyap Desai 	u16 pi, ci, max_entries;
38023ab2a9SKashyap Desai 	bool is_qfull = false;
39023ab2a9SKashyap Desai 
40023ab2a9SKashyap Desai 	pi = op_req_q->pi;
41023ab2a9SKashyap Desai 	ci = READ_ONCE(op_req_q->ci);
42023ab2a9SKashyap Desai 	max_entries = op_req_q->num_requests;
43023ab2a9SKashyap Desai 
44023ab2a9SKashyap Desai 	if ((ci == (pi + 1)) || ((!ci) && (pi == (max_entries - 1))))
45023ab2a9SKashyap Desai 		is_qfull = true;
46023ab2a9SKashyap Desai 
47023ab2a9SKashyap Desai 	return is_qfull;
48023ab2a9SKashyap Desai }
49023ab2a9SKashyap Desai 
50824a1566SKashyap Desai static void mpi3mr_sync_irqs(struct mpi3mr_ioc *mrioc)
51824a1566SKashyap Desai {
52824a1566SKashyap Desai 	u16 i, max_vectors;
53824a1566SKashyap Desai 
54824a1566SKashyap Desai 	max_vectors = mrioc->intr_info_count;
55824a1566SKashyap Desai 
56824a1566SKashyap Desai 	for (i = 0; i < max_vectors; i++)
57824a1566SKashyap Desai 		synchronize_irq(pci_irq_vector(mrioc->pdev, i));
58824a1566SKashyap Desai }
59824a1566SKashyap Desai 
60824a1566SKashyap Desai void mpi3mr_ioc_disable_intr(struct mpi3mr_ioc *mrioc)
61824a1566SKashyap Desai {
62824a1566SKashyap Desai 	mrioc->intr_enabled = 0;
63824a1566SKashyap Desai 	mpi3mr_sync_irqs(mrioc);
64824a1566SKashyap Desai }
65824a1566SKashyap Desai 
66824a1566SKashyap Desai void mpi3mr_ioc_enable_intr(struct mpi3mr_ioc *mrioc)
67824a1566SKashyap Desai {
68824a1566SKashyap Desai 	mrioc->intr_enabled = 1;
69824a1566SKashyap Desai }
70824a1566SKashyap Desai 
71824a1566SKashyap Desai static void mpi3mr_cleanup_isr(struct mpi3mr_ioc *mrioc)
72824a1566SKashyap Desai {
73824a1566SKashyap Desai 	u16 i;
74824a1566SKashyap Desai 
75824a1566SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
76824a1566SKashyap Desai 
77824a1566SKashyap Desai 	if (!mrioc->intr_info)
78824a1566SKashyap Desai 		return;
79824a1566SKashyap Desai 
80824a1566SKashyap Desai 	for (i = 0; i < mrioc->intr_info_count; i++)
81824a1566SKashyap Desai 		free_irq(pci_irq_vector(mrioc->pdev, i),
82824a1566SKashyap Desai 		    (mrioc->intr_info + i));
83824a1566SKashyap Desai 
84824a1566SKashyap Desai 	kfree(mrioc->intr_info);
85824a1566SKashyap Desai 	mrioc->intr_info = NULL;
86824a1566SKashyap Desai 	mrioc->intr_info_count = 0;
87fe6db615SSreekanth Reddy 	mrioc->is_intr_info_set = false;
88824a1566SKashyap Desai 	pci_free_irq_vectors(mrioc->pdev);
89824a1566SKashyap Desai }
90824a1566SKashyap Desai 
91824a1566SKashyap Desai void mpi3mr_add_sg_single(void *paddr, u8 flags, u32 length,
92824a1566SKashyap Desai 	dma_addr_t dma_addr)
93824a1566SKashyap Desai {
94824a1566SKashyap Desai 	struct mpi3_sge_common *sgel = paddr;
95824a1566SKashyap Desai 
96824a1566SKashyap Desai 	sgel->flags = flags;
97824a1566SKashyap Desai 	sgel->length = cpu_to_le32(length);
98824a1566SKashyap Desai 	sgel->address = cpu_to_le64(dma_addr);
99824a1566SKashyap Desai }
100824a1566SKashyap Desai 
101824a1566SKashyap Desai void mpi3mr_build_zero_len_sge(void *paddr)
102824a1566SKashyap Desai {
103824a1566SKashyap Desai 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
104824a1566SKashyap Desai 
105824a1566SKashyap Desai 	mpi3mr_add_sg_single(paddr, sgl_flags, 0, -1);
106824a1566SKashyap Desai }
107824a1566SKashyap Desai 
108824a1566SKashyap Desai void *mpi3mr_get_reply_virt_addr(struct mpi3mr_ioc *mrioc,
109824a1566SKashyap Desai 	dma_addr_t phys_addr)
110824a1566SKashyap Desai {
111824a1566SKashyap Desai 	if (!phys_addr)
112824a1566SKashyap Desai 		return NULL;
113824a1566SKashyap Desai 
114824a1566SKashyap Desai 	if ((phys_addr < mrioc->reply_buf_dma) ||
115824a1566SKashyap Desai 	    (phys_addr > mrioc->reply_buf_dma_max_address))
116824a1566SKashyap Desai 		return NULL;
117824a1566SKashyap Desai 
118824a1566SKashyap Desai 	return mrioc->reply_buf + (phys_addr - mrioc->reply_buf_dma);
119824a1566SKashyap Desai }
120824a1566SKashyap Desai 
121824a1566SKashyap Desai void *mpi3mr_get_sensebuf_virt_addr(struct mpi3mr_ioc *mrioc,
122824a1566SKashyap Desai 	dma_addr_t phys_addr)
123824a1566SKashyap Desai {
124824a1566SKashyap Desai 	if (!phys_addr)
125824a1566SKashyap Desai 		return NULL;
126824a1566SKashyap Desai 
127824a1566SKashyap Desai 	return mrioc->sense_buf + (phys_addr - mrioc->sense_buf_dma);
128824a1566SKashyap Desai }
129824a1566SKashyap Desai 
130824a1566SKashyap Desai static void mpi3mr_repost_reply_buf(struct mpi3mr_ioc *mrioc,
131824a1566SKashyap Desai 	u64 reply_dma)
132824a1566SKashyap Desai {
133824a1566SKashyap Desai 	u32 old_idx = 0;
134a83ec831SSreekanth Reddy 	unsigned long flags;
135824a1566SKashyap Desai 
136a83ec831SSreekanth Reddy 	spin_lock_irqsave(&mrioc->reply_free_queue_lock, flags);
137824a1566SKashyap Desai 	old_idx  =  mrioc->reply_free_queue_host_index;
138824a1566SKashyap Desai 	mrioc->reply_free_queue_host_index = (
139824a1566SKashyap Desai 	    (mrioc->reply_free_queue_host_index ==
140824a1566SKashyap Desai 	    (mrioc->reply_free_qsz - 1)) ? 0 :
141824a1566SKashyap Desai 	    (mrioc->reply_free_queue_host_index + 1));
142824a1566SKashyap Desai 	mrioc->reply_free_q[old_idx] = cpu_to_le64(reply_dma);
143824a1566SKashyap Desai 	writel(mrioc->reply_free_queue_host_index,
144824a1566SKashyap Desai 	    &mrioc->sysif_regs->reply_free_host_index);
145a83ec831SSreekanth Reddy 	spin_unlock_irqrestore(&mrioc->reply_free_queue_lock, flags);
146824a1566SKashyap Desai }
147824a1566SKashyap Desai 
148824a1566SKashyap Desai void mpi3mr_repost_sense_buf(struct mpi3mr_ioc *mrioc,
149824a1566SKashyap Desai 	u64 sense_buf_dma)
150824a1566SKashyap Desai {
151824a1566SKashyap Desai 	u32 old_idx = 0;
152a83ec831SSreekanth Reddy 	unsigned long flags;
153824a1566SKashyap Desai 
154a83ec831SSreekanth Reddy 	spin_lock_irqsave(&mrioc->sbq_lock, flags);
155824a1566SKashyap Desai 	old_idx  =  mrioc->sbq_host_index;
156824a1566SKashyap Desai 	mrioc->sbq_host_index = ((mrioc->sbq_host_index ==
157824a1566SKashyap Desai 	    (mrioc->sense_buf_q_sz - 1)) ? 0 :
158824a1566SKashyap Desai 	    (mrioc->sbq_host_index + 1));
159824a1566SKashyap Desai 	mrioc->sense_buf_q[old_idx] = cpu_to_le64(sense_buf_dma);
160824a1566SKashyap Desai 	writel(mrioc->sbq_host_index,
161824a1566SKashyap Desai 	    &mrioc->sysif_regs->sense_buffer_free_host_index);
162a83ec831SSreekanth Reddy 	spin_unlock_irqrestore(&mrioc->sbq_lock, flags);
163824a1566SKashyap Desai }
164824a1566SKashyap Desai 
1659fc4abfeSKashyap Desai static void mpi3mr_print_event_data(struct mpi3mr_ioc *mrioc,
1669fc4abfeSKashyap Desai 	struct mpi3_event_notification_reply *event_reply)
1679fc4abfeSKashyap Desai {
1689fc4abfeSKashyap Desai 	char *desc = NULL;
1699fc4abfeSKashyap Desai 	u16 event;
1709fc4abfeSKashyap Desai 
1719fc4abfeSKashyap Desai 	event = event_reply->event;
1729fc4abfeSKashyap Desai 
1739fc4abfeSKashyap Desai 	switch (event) {
1749fc4abfeSKashyap Desai 	case MPI3_EVENT_LOG_DATA:
1759fc4abfeSKashyap Desai 		desc = "Log Data";
1769fc4abfeSKashyap Desai 		break;
1779fc4abfeSKashyap Desai 	case MPI3_EVENT_CHANGE:
1789fc4abfeSKashyap Desai 		desc = "Event Change";
1799fc4abfeSKashyap Desai 		break;
1809fc4abfeSKashyap Desai 	case MPI3_EVENT_GPIO_INTERRUPT:
1819fc4abfeSKashyap Desai 		desc = "GPIO Interrupt";
1829fc4abfeSKashyap Desai 		break;
1839fc4abfeSKashyap Desai 	case MPI3_EVENT_TEMP_THRESHOLD:
1849fc4abfeSKashyap Desai 		desc = "Temperature Threshold";
1859fc4abfeSKashyap Desai 		break;
1869fc4abfeSKashyap Desai 	case MPI3_EVENT_CABLE_MGMT:
1879fc4abfeSKashyap Desai 		desc = "Cable Management";
1889fc4abfeSKashyap Desai 		break;
1899fc4abfeSKashyap Desai 	case MPI3_EVENT_ENERGY_PACK_CHANGE:
1909fc4abfeSKashyap Desai 		desc = "Energy Pack Change";
1919fc4abfeSKashyap Desai 		break;
1929fc4abfeSKashyap Desai 	case MPI3_EVENT_DEVICE_ADDED:
1939fc4abfeSKashyap Desai 	{
1949fc4abfeSKashyap Desai 		struct mpi3_device_page0 *event_data =
1959fc4abfeSKashyap Desai 		    (struct mpi3_device_page0 *)event_reply->event_data;
1969fc4abfeSKashyap Desai 		ioc_info(mrioc, "Device Added: dev=0x%04x Form=0x%x\n",
1979fc4abfeSKashyap Desai 		    event_data->dev_handle, event_data->device_form);
1989fc4abfeSKashyap Desai 		return;
1999fc4abfeSKashyap Desai 	}
2009fc4abfeSKashyap Desai 	case MPI3_EVENT_DEVICE_INFO_CHANGED:
2019fc4abfeSKashyap Desai 	{
2029fc4abfeSKashyap Desai 		struct mpi3_device_page0 *event_data =
2039fc4abfeSKashyap Desai 		    (struct mpi3_device_page0 *)event_reply->event_data;
2049fc4abfeSKashyap Desai 		ioc_info(mrioc, "Device Info Changed: dev=0x%04x Form=0x%x\n",
2059fc4abfeSKashyap Desai 		    event_data->dev_handle, event_data->device_form);
2069fc4abfeSKashyap Desai 		return;
2079fc4abfeSKashyap Desai 	}
2089fc4abfeSKashyap Desai 	case MPI3_EVENT_DEVICE_STATUS_CHANGE:
2099fc4abfeSKashyap Desai 	{
2109fc4abfeSKashyap Desai 		struct mpi3_event_data_device_status_change *event_data =
2119fc4abfeSKashyap Desai 		    (struct mpi3_event_data_device_status_change *)event_reply->event_data;
2129fc4abfeSKashyap Desai 		ioc_info(mrioc, "Device status Change: dev=0x%04x RC=0x%x\n",
2139fc4abfeSKashyap Desai 		    event_data->dev_handle, event_data->reason_code);
2149fc4abfeSKashyap Desai 		return;
2159fc4abfeSKashyap Desai 	}
2169fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_DISCOVERY:
2179fc4abfeSKashyap Desai 	{
2189fc4abfeSKashyap Desai 		struct mpi3_event_data_sas_discovery *event_data =
2199fc4abfeSKashyap Desai 		    (struct mpi3_event_data_sas_discovery *)event_reply->event_data;
2209fc4abfeSKashyap Desai 		ioc_info(mrioc, "SAS Discovery: (%s) status (0x%08x)\n",
2219fc4abfeSKashyap Desai 		    (event_data->reason_code == MPI3_EVENT_SAS_DISC_RC_STARTED) ?
2229fc4abfeSKashyap Desai 		    "start" : "stop",
2239fc4abfeSKashyap Desai 		    le32_to_cpu(event_data->discovery_status));
2249fc4abfeSKashyap Desai 		return;
2259fc4abfeSKashyap Desai 	}
2269fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE:
2279fc4abfeSKashyap Desai 		desc = "SAS Broadcast Primitive";
2289fc4abfeSKashyap Desai 		break;
2299fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_NOTIFY_PRIMITIVE:
2309fc4abfeSKashyap Desai 		desc = "SAS Notify Primitive";
2319fc4abfeSKashyap Desai 		break;
2329fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
2339fc4abfeSKashyap Desai 		desc = "SAS Init Device Status Change";
2349fc4abfeSKashyap Desai 		break;
2359fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_INIT_TABLE_OVERFLOW:
2369fc4abfeSKashyap Desai 		desc = "SAS Init Table Overflow";
2379fc4abfeSKashyap Desai 		break;
2389fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
2399fc4abfeSKashyap Desai 		desc = "SAS Topology Change List";
2409fc4abfeSKashyap Desai 		break;
2419fc4abfeSKashyap Desai 	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
2429fc4abfeSKashyap Desai 		desc = "Enclosure Device Status Change";
2439fc4abfeSKashyap Desai 		break;
2449fc4abfeSKashyap Desai 	case MPI3_EVENT_HARD_RESET_RECEIVED:
2459fc4abfeSKashyap Desai 		desc = "Hard Reset Received";
2469fc4abfeSKashyap Desai 		break;
2479fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_PHY_COUNTER:
2489fc4abfeSKashyap Desai 		desc = "SAS PHY Counter";
2499fc4abfeSKashyap Desai 		break;
2509fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR:
2519fc4abfeSKashyap Desai 		desc = "SAS Device Discovery Error";
2529fc4abfeSKashyap Desai 		break;
2539fc4abfeSKashyap Desai 	case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
2549fc4abfeSKashyap Desai 		desc = "PCIE Topology Change List";
2559fc4abfeSKashyap Desai 		break;
2569fc4abfeSKashyap Desai 	case MPI3_EVENT_PCIE_ENUMERATION:
2579fc4abfeSKashyap Desai 	{
2589fc4abfeSKashyap Desai 		struct mpi3_event_data_pcie_enumeration *event_data =
2599fc4abfeSKashyap Desai 		    (struct mpi3_event_data_pcie_enumeration *)event_reply->event_data;
2609fc4abfeSKashyap Desai 		ioc_info(mrioc, "PCIE Enumeration: (%s)",
2619fc4abfeSKashyap Desai 		    (event_data->reason_code ==
2629fc4abfeSKashyap Desai 		    MPI3_EVENT_PCIE_ENUM_RC_STARTED) ? "start" : "stop");
2639fc4abfeSKashyap Desai 		if (event_data->enumeration_status)
2649fc4abfeSKashyap Desai 			ioc_info(mrioc, "enumeration_status(0x%08x)\n",
2659fc4abfeSKashyap Desai 			    le32_to_cpu(event_data->enumeration_status));
2669fc4abfeSKashyap Desai 		return;
2679fc4abfeSKashyap Desai 	}
2689fc4abfeSKashyap Desai 	case MPI3_EVENT_PREPARE_FOR_RESET:
2699fc4abfeSKashyap Desai 		desc = "Prepare For Reset";
2709fc4abfeSKashyap Desai 		break;
2719fc4abfeSKashyap Desai 	}
2729fc4abfeSKashyap Desai 
2739fc4abfeSKashyap Desai 	if (!desc)
2749fc4abfeSKashyap Desai 		return;
2759fc4abfeSKashyap Desai 
2769fc4abfeSKashyap Desai 	ioc_info(mrioc, "%s\n", desc);
2779fc4abfeSKashyap Desai }
2789fc4abfeSKashyap Desai 
279824a1566SKashyap Desai static void mpi3mr_handle_events(struct mpi3mr_ioc *mrioc,
280824a1566SKashyap Desai 	struct mpi3_default_reply *def_reply)
281824a1566SKashyap Desai {
282824a1566SKashyap Desai 	struct mpi3_event_notification_reply *event_reply =
283824a1566SKashyap Desai 	    (struct mpi3_event_notification_reply *)def_reply;
284824a1566SKashyap Desai 
285824a1566SKashyap Desai 	mrioc->change_count = le16_to_cpu(event_reply->ioc_change_count);
2869fc4abfeSKashyap Desai 	mpi3mr_print_event_data(mrioc, event_reply);
28713ef29eaSKashyap Desai 	mpi3mr_os_handle_events(mrioc, event_reply);
288824a1566SKashyap Desai }
289824a1566SKashyap Desai 
290824a1566SKashyap Desai static struct mpi3mr_drv_cmd *
291824a1566SKashyap Desai mpi3mr_get_drv_cmd(struct mpi3mr_ioc *mrioc, u16 host_tag,
292824a1566SKashyap Desai 	struct mpi3_default_reply *def_reply)
293824a1566SKashyap Desai {
29413ef29eaSKashyap Desai 	u16 idx;
29513ef29eaSKashyap Desai 
296824a1566SKashyap Desai 	switch (host_tag) {
297824a1566SKashyap Desai 	case MPI3MR_HOSTTAG_INITCMDS:
298824a1566SKashyap Desai 		return &mrioc->init_cmds;
299e844adb1SKashyap Desai 	case MPI3MR_HOSTTAG_BLK_TMS:
300e844adb1SKashyap Desai 		return &mrioc->host_tm_cmds;
301824a1566SKashyap Desai 	case MPI3MR_HOSTTAG_INVALID:
302824a1566SKashyap Desai 		if (def_reply && def_reply->function ==
303824a1566SKashyap Desai 		    MPI3_FUNCTION_EVENT_NOTIFICATION)
304824a1566SKashyap Desai 			mpi3mr_handle_events(mrioc, def_reply);
305824a1566SKashyap Desai 		return NULL;
306824a1566SKashyap Desai 	default:
307824a1566SKashyap Desai 		break;
308824a1566SKashyap Desai 	}
30913ef29eaSKashyap Desai 	if (host_tag >= MPI3MR_HOSTTAG_DEVRMCMD_MIN &&
31013ef29eaSKashyap Desai 	    host_tag <= MPI3MR_HOSTTAG_DEVRMCMD_MAX) {
31113ef29eaSKashyap Desai 		idx = host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
31213ef29eaSKashyap Desai 		return &mrioc->dev_rmhs_cmds[idx];
31313ef29eaSKashyap Desai 	}
314824a1566SKashyap Desai 
315c1af985dSSreekanth Reddy 	if (host_tag >= MPI3MR_HOSTTAG_EVTACKCMD_MIN &&
316c1af985dSSreekanth Reddy 	    host_tag <= MPI3MR_HOSTTAG_EVTACKCMD_MAX) {
317c1af985dSSreekanth Reddy 		idx = host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN;
318c1af985dSSreekanth Reddy 		return &mrioc->evtack_cmds[idx];
319c1af985dSSreekanth Reddy 	}
320c1af985dSSreekanth Reddy 
321824a1566SKashyap Desai 	return NULL;
322824a1566SKashyap Desai }
323824a1566SKashyap Desai 
324824a1566SKashyap Desai static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc,
325824a1566SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc, u64 *reply_dma)
326824a1566SKashyap Desai {
327824a1566SKashyap Desai 	u16 reply_desc_type, host_tag = 0;
328824a1566SKashyap Desai 	u16 ioc_status = MPI3_IOCSTATUS_SUCCESS;
329824a1566SKashyap Desai 	u32 ioc_loginfo = 0;
330824a1566SKashyap Desai 	struct mpi3_status_reply_descriptor *status_desc;
331824a1566SKashyap Desai 	struct mpi3_address_reply_descriptor *addr_desc;
332824a1566SKashyap Desai 	struct mpi3_success_reply_descriptor *success_desc;
333824a1566SKashyap Desai 	struct mpi3_default_reply *def_reply = NULL;
334824a1566SKashyap Desai 	struct mpi3mr_drv_cmd *cmdptr = NULL;
335824a1566SKashyap Desai 	struct mpi3_scsi_io_reply *scsi_reply;
336824a1566SKashyap Desai 	u8 *sense_buf = NULL;
337824a1566SKashyap Desai 
338824a1566SKashyap Desai 	*reply_dma = 0;
339824a1566SKashyap Desai 	reply_desc_type = le16_to_cpu(reply_desc->reply_flags) &
340824a1566SKashyap Desai 	    MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK;
341824a1566SKashyap Desai 	switch (reply_desc_type) {
342824a1566SKashyap Desai 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS:
343824a1566SKashyap Desai 		status_desc = (struct mpi3_status_reply_descriptor *)reply_desc;
344824a1566SKashyap Desai 		host_tag = le16_to_cpu(status_desc->host_tag);
345824a1566SKashyap Desai 		ioc_status = le16_to_cpu(status_desc->ioc_status);
346824a1566SKashyap Desai 		if (ioc_status &
347824a1566SKashyap Desai 		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
348824a1566SKashyap Desai 			ioc_loginfo = le32_to_cpu(status_desc->ioc_log_info);
349824a1566SKashyap Desai 		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
350824a1566SKashyap Desai 		break;
351824a1566SKashyap Desai 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY:
352824a1566SKashyap Desai 		addr_desc = (struct mpi3_address_reply_descriptor *)reply_desc;
353824a1566SKashyap Desai 		*reply_dma = le64_to_cpu(addr_desc->reply_frame_address);
354824a1566SKashyap Desai 		def_reply = mpi3mr_get_reply_virt_addr(mrioc, *reply_dma);
355824a1566SKashyap Desai 		if (!def_reply)
356824a1566SKashyap Desai 			goto out;
357824a1566SKashyap Desai 		host_tag = le16_to_cpu(def_reply->host_tag);
358824a1566SKashyap Desai 		ioc_status = le16_to_cpu(def_reply->ioc_status);
359824a1566SKashyap Desai 		if (ioc_status &
360824a1566SKashyap Desai 		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
361824a1566SKashyap Desai 			ioc_loginfo = le32_to_cpu(def_reply->ioc_log_info);
362824a1566SKashyap Desai 		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
363824a1566SKashyap Desai 		if (def_reply->function == MPI3_FUNCTION_SCSI_IO) {
364824a1566SKashyap Desai 			scsi_reply = (struct mpi3_scsi_io_reply *)def_reply;
365824a1566SKashyap Desai 			sense_buf = mpi3mr_get_sensebuf_virt_addr(mrioc,
366824a1566SKashyap Desai 			    le64_to_cpu(scsi_reply->sense_data_buffer_address));
367824a1566SKashyap Desai 		}
368824a1566SKashyap Desai 		break;
369824a1566SKashyap Desai 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS:
370824a1566SKashyap Desai 		success_desc = (struct mpi3_success_reply_descriptor *)reply_desc;
371824a1566SKashyap Desai 		host_tag = le16_to_cpu(success_desc->host_tag);
372824a1566SKashyap Desai 		break;
373824a1566SKashyap Desai 	default:
374824a1566SKashyap Desai 		break;
375824a1566SKashyap Desai 	}
376824a1566SKashyap Desai 
377824a1566SKashyap Desai 	cmdptr = mpi3mr_get_drv_cmd(mrioc, host_tag, def_reply);
378824a1566SKashyap Desai 	if (cmdptr) {
379824a1566SKashyap Desai 		if (cmdptr->state & MPI3MR_CMD_PENDING) {
380824a1566SKashyap Desai 			cmdptr->state |= MPI3MR_CMD_COMPLETE;
381824a1566SKashyap Desai 			cmdptr->ioc_loginfo = ioc_loginfo;
382824a1566SKashyap Desai 			cmdptr->ioc_status = ioc_status;
383824a1566SKashyap Desai 			cmdptr->state &= ~MPI3MR_CMD_PENDING;
384824a1566SKashyap Desai 			if (def_reply) {
385824a1566SKashyap Desai 				cmdptr->state |= MPI3MR_CMD_REPLY_VALID;
386824a1566SKashyap Desai 				memcpy((u8 *)cmdptr->reply, (u8 *)def_reply,
387c5758fc7SSreekanth Reddy 				    mrioc->reply_sz);
388824a1566SKashyap Desai 			}
389824a1566SKashyap Desai 			if (cmdptr->is_waiting) {
390824a1566SKashyap Desai 				complete(&cmdptr->done);
391824a1566SKashyap Desai 				cmdptr->is_waiting = 0;
392824a1566SKashyap Desai 			} else if (cmdptr->callback)
393824a1566SKashyap Desai 				cmdptr->callback(mrioc, cmdptr);
394824a1566SKashyap Desai 		}
395824a1566SKashyap Desai 	}
396824a1566SKashyap Desai out:
397824a1566SKashyap Desai 	if (sense_buf)
398824a1566SKashyap Desai 		mpi3mr_repost_sense_buf(mrioc,
399824a1566SKashyap Desai 		    le64_to_cpu(scsi_reply->sense_data_buffer_address));
400824a1566SKashyap Desai }
401824a1566SKashyap Desai 
402824a1566SKashyap Desai static int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc)
403824a1566SKashyap Desai {
404824a1566SKashyap Desai 	u32 exp_phase = mrioc->admin_reply_ephase;
405824a1566SKashyap Desai 	u32 admin_reply_ci = mrioc->admin_reply_ci;
406824a1566SKashyap Desai 	u32 num_admin_replies = 0;
407824a1566SKashyap Desai 	u64 reply_dma = 0;
408824a1566SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc;
409824a1566SKashyap Desai 
410824a1566SKashyap Desai 	reply_desc = (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base +
411824a1566SKashyap Desai 	    admin_reply_ci;
412824a1566SKashyap Desai 
413824a1566SKashyap Desai 	if ((le16_to_cpu(reply_desc->reply_flags) &
414824a1566SKashyap Desai 	    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
415824a1566SKashyap Desai 		return 0;
416824a1566SKashyap Desai 
417824a1566SKashyap Desai 	do {
418824a1566SKashyap Desai 		mrioc->admin_req_ci = le16_to_cpu(reply_desc->request_queue_ci);
419824a1566SKashyap Desai 		mpi3mr_process_admin_reply_desc(mrioc, reply_desc, &reply_dma);
420824a1566SKashyap Desai 		if (reply_dma)
421824a1566SKashyap Desai 			mpi3mr_repost_reply_buf(mrioc, reply_dma);
422824a1566SKashyap Desai 		num_admin_replies++;
423824a1566SKashyap Desai 		if (++admin_reply_ci == mrioc->num_admin_replies) {
424824a1566SKashyap Desai 			admin_reply_ci = 0;
425824a1566SKashyap Desai 			exp_phase ^= 1;
426824a1566SKashyap Desai 		}
427824a1566SKashyap Desai 		reply_desc =
428824a1566SKashyap Desai 		    (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base +
429824a1566SKashyap Desai 		    admin_reply_ci;
430824a1566SKashyap Desai 		if ((le16_to_cpu(reply_desc->reply_flags) &
431824a1566SKashyap Desai 		    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
432824a1566SKashyap Desai 			break;
433824a1566SKashyap Desai 	} while (1);
434824a1566SKashyap Desai 
435824a1566SKashyap Desai 	writel(admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci);
436824a1566SKashyap Desai 	mrioc->admin_reply_ci = admin_reply_ci;
437824a1566SKashyap Desai 	mrioc->admin_reply_ephase = exp_phase;
438824a1566SKashyap Desai 
439824a1566SKashyap Desai 	return num_admin_replies;
440824a1566SKashyap Desai }
441824a1566SKashyap Desai 
442023ab2a9SKashyap Desai /**
443023ab2a9SKashyap Desai  * mpi3mr_get_reply_desc - get reply descriptor frame corresponding to
444023ab2a9SKashyap Desai  *	queue's consumer index from operational reply descriptor queue.
445023ab2a9SKashyap Desai  * @op_reply_q: op_reply_qinfo object
446023ab2a9SKashyap Desai  * @reply_ci: operational reply descriptor's queue consumer index
447023ab2a9SKashyap Desai  *
448023ab2a9SKashyap Desai  * Returns reply descriptor frame address
449023ab2a9SKashyap Desai  */
450023ab2a9SKashyap Desai static inline struct mpi3_default_reply_descriptor *
451023ab2a9SKashyap Desai mpi3mr_get_reply_desc(struct op_reply_qinfo *op_reply_q, u32 reply_ci)
452023ab2a9SKashyap Desai {
453023ab2a9SKashyap Desai 	void *segment_base_addr;
454023ab2a9SKashyap Desai 	struct segments *segments = op_reply_q->q_segments;
455023ab2a9SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc = NULL;
456023ab2a9SKashyap Desai 
457023ab2a9SKashyap Desai 	segment_base_addr =
458023ab2a9SKashyap Desai 	    segments[reply_ci / op_reply_q->segment_qd].segment;
459023ab2a9SKashyap Desai 	reply_desc = (struct mpi3_default_reply_descriptor *)segment_base_addr +
460023ab2a9SKashyap Desai 	    (reply_ci % op_reply_q->segment_qd);
461023ab2a9SKashyap Desai 	return reply_desc;
462023ab2a9SKashyap Desai }
463023ab2a9SKashyap Desai 
464023ab2a9SKashyap Desai static int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc,
465023ab2a9SKashyap Desai 	struct mpi3mr_intr_info *intr_info)
466023ab2a9SKashyap Desai {
467023ab2a9SKashyap Desai 	struct op_reply_qinfo *op_reply_q = intr_info->op_reply_q;
468023ab2a9SKashyap Desai 	struct op_req_qinfo *op_req_q;
469023ab2a9SKashyap Desai 	u32 exp_phase;
470023ab2a9SKashyap Desai 	u32 reply_ci;
471023ab2a9SKashyap Desai 	u32 num_op_reply = 0;
472023ab2a9SKashyap Desai 	u64 reply_dma = 0;
473023ab2a9SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc;
474023ab2a9SKashyap Desai 	u16 req_q_idx = 0, reply_qidx;
475023ab2a9SKashyap Desai 
476023ab2a9SKashyap Desai 	reply_qidx = op_reply_q->qid - 1;
477023ab2a9SKashyap Desai 
478463429f8SKashyap Desai 	if (!atomic_add_unless(&op_reply_q->in_use, 1, 1))
479463429f8SKashyap Desai 		return 0;
480463429f8SKashyap Desai 
481023ab2a9SKashyap Desai 	exp_phase = op_reply_q->ephase;
482023ab2a9SKashyap Desai 	reply_ci = op_reply_q->ci;
483023ab2a9SKashyap Desai 
484023ab2a9SKashyap Desai 	reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci);
485023ab2a9SKashyap Desai 	if ((le16_to_cpu(reply_desc->reply_flags) &
486023ab2a9SKashyap Desai 	    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) {
487463429f8SKashyap Desai 		atomic_dec(&op_reply_q->in_use);
488023ab2a9SKashyap Desai 		return 0;
489023ab2a9SKashyap Desai 	}
490023ab2a9SKashyap Desai 
491023ab2a9SKashyap Desai 	do {
492023ab2a9SKashyap Desai 		req_q_idx = le16_to_cpu(reply_desc->request_queue_id) - 1;
493023ab2a9SKashyap Desai 		op_req_q = &mrioc->req_qinfo[req_q_idx];
494023ab2a9SKashyap Desai 
495023ab2a9SKashyap Desai 		WRITE_ONCE(op_req_q->ci, le16_to_cpu(reply_desc->request_queue_ci));
496023ab2a9SKashyap Desai 		mpi3mr_process_op_reply_desc(mrioc, reply_desc, &reply_dma,
497023ab2a9SKashyap Desai 		    reply_qidx);
498463429f8SKashyap Desai 		atomic_dec(&op_reply_q->pend_ios);
499023ab2a9SKashyap Desai 		if (reply_dma)
500023ab2a9SKashyap Desai 			mpi3mr_repost_reply_buf(mrioc, reply_dma);
501023ab2a9SKashyap Desai 		num_op_reply++;
502023ab2a9SKashyap Desai 
503023ab2a9SKashyap Desai 		if (++reply_ci == op_reply_q->num_replies) {
504023ab2a9SKashyap Desai 			reply_ci = 0;
505023ab2a9SKashyap Desai 			exp_phase ^= 1;
506023ab2a9SKashyap Desai 		}
507023ab2a9SKashyap Desai 
508023ab2a9SKashyap Desai 		reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci);
509023ab2a9SKashyap Desai 
510023ab2a9SKashyap Desai 		if ((le16_to_cpu(reply_desc->reply_flags) &
511023ab2a9SKashyap Desai 		    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
512023ab2a9SKashyap Desai 			break;
513463429f8SKashyap Desai 		/*
514463429f8SKashyap Desai 		 * Exit completion loop to avoid CPU lockup
515463429f8SKashyap Desai 		 * Ensure remaining completion happens from threaded ISR.
516463429f8SKashyap Desai 		 */
517463429f8SKashyap Desai 		if (num_op_reply > mrioc->max_host_ios) {
518463429f8SKashyap Desai 			intr_info->op_reply_q->enable_irq_poll = true;
519463429f8SKashyap Desai 			break;
520463429f8SKashyap Desai 		}
521023ab2a9SKashyap Desai 
522023ab2a9SKashyap Desai 	} while (1);
523023ab2a9SKashyap Desai 
524023ab2a9SKashyap Desai 	writel(reply_ci,
525023ab2a9SKashyap Desai 	    &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].consumer_index);
526023ab2a9SKashyap Desai 	op_reply_q->ci = reply_ci;
527023ab2a9SKashyap Desai 	op_reply_q->ephase = exp_phase;
528023ab2a9SKashyap Desai 
529463429f8SKashyap Desai 	atomic_dec(&op_reply_q->in_use);
530023ab2a9SKashyap Desai 	return num_op_reply;
531023ab2a9SKashyap Desai }
532023ab2a9SKashyap Desai 
533824a1566SKashyap Desai static irqreturn_t mpi3mr_isr_primary(int irq, void *privdata)
534824a1566SKashyap Desai {
535824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info = privdata;
536824a1566SKashyap Desai 	struct mpi3mr_ioc *mrioc;
537824a1566SKashyap Desai 	u16 midx;
538463429f8SKashyap Desai 	u32 num_admin_replies = 0, num_op_reply = 0;
539824a1566SKashyap Desai 
540824a1566SKashyap Desai 	if (!intr_info)
541824a1566SKashyap Desai 		return IRQ_NONE;
542824a1566SKashyap Desai 
543824a1566SKashyap Desai 	mrioc = intr_info->mrioc;
544824a1566SKashyap Desai 
545824a1566SKashyap Desai 	if (!mrioc->intr_enabled)
546824a1566SKashyap Desai 		return IRQ_NONE;
547824a1566SKashyap Desai 
548824a1566SKashyap Desai 	midx = intr_info->msix_index;
549824a1566SKashyap Desai 
550824a1566SKashyap Desai 	if (!midx)
551824a1566SKashyap Desai 		num_admin_replies = mpi3mr_process_admin_reply_q(mrioc);
552463429f8SKashyap Desai 	if (intr_info->op_reply_q)
553463429f8SKashyap Desai 		num_op_reply = mpi3mr_process_op_reply_q(mrioc, intr_info);
554824a1566SKashyap Desai 
555463429f8SKashyap Desai 	if (num_admin_replies || num_op_reply)
556824a1566SKashyap Desai 		return IRQ_HANDLED;
557824a1566SKashyap Desai 	else
558824a1566SKashyap Desai 		return IRQ_NONE;
559824a1566SKashyap Desai }
560824a1566SKashyap Desai 
561824a1566SKashyap Desai static irqreturn_t mpi3mr_isr(int irq, void *privdata)
562824a1566SKashyap Desai {
563824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info = privdata;
564463429f8SKashyap Desai 	struct mpi3mr_ioc *mrioc;
565463429f8SKashyap Desai 	u16 midx;
566824a1566SKashyap Desai 	int ret;
567824a1566SKashyap Desai 
568824a1566SKashyap Desai 	if (!intr_info)
569824a1566SKashyap Desai 		return IRQ_NONE;
570824a1566SKashyap Desai 
571463429f8SKashyap Desai 	mrioc = intr_info->mrioc;
572463429f8SKashyap Desai 	midx = intr_info->msix_index;
573824a1566SKashyap Desai 	/* Call primary ISR routine */
574824a1566SKashyap Desai 	ret = mpi3mr_isr_primary(irq, privdata);
575824a1566SKashyap Desai 
576463429f8SKashyap Desai 	/*
577463429f8SKashyap Desai 	 * If more IOs are expected, schedule IRQ polling thread.
578463429f8SKashyap Desai 	 * Otherwise exit from ISR.
579463429f8SKashyap Desai 	 */
580463429f8SKashyap Desai 	if (!intr_info->op_reply_q)
581824a1566SKashyap Desai 		return ret;
582463429f8SKashyap Desai 
583463429f8SKashyap Desai 	if (!intr_info->op_reply_q->enable_irq_poll ||
584463429f8SKashyap Desai 	    !atomic_read(&intr_info->op_reply_q->pend_ios))
585463429f8SKashyap Desai 		return ret;
586463429f8SKashyap Desai 
587463429f8SKashyap Desai 	disable_irq_nosync(pci_irq_vector(mrioc->pdev, midx));
588463429f8SKashyap Desai 
589463429f8SKashyap Desai 	return IRQ_WAKE_THREAD;
590824a1566SKashyap Desai }
591824a1566SKashyap Desai 
592824a1566SKashyap Desai /**
593824a1566SKashyap Desai  * mpi3mr_isr_poll - Reply queue polling routine
594824a1566SKashyap Desai  * @irq: IRQ
595824a1566SKashyap Desai  * @privdata: Interrupt info
596824a1566SKashyap Desai  *
597824a1566SKashyap Desai  * poll for pending I/O completions in a loop until pending I/Os
598824a1566SKashyap Desai  * present or controller queue depth I/Os are processed.
599824a1566SKashyap Desai  *
600824a1566SKashyap Desai  * Return: IRQ_NONE or IRQ_HANDLED
601824a1566SKashyap Desai  */
602824a1566SKashyap Desai static irqreturn_t mpi3mr_isr_poll(int irq, void *privdata)
603824a1566SKashyap Desai {
604463429f8SKashyap Desai 	struct mpi3mr_intr_info *intr_info = privdata;
605463429f8SKashyap Desai 	struct mpi3mr_ioc *mrioc;
606463429f8SKashyap Desai 	u16 midx;
607463429f8SKashyap Desai 	u32 num_op_reply = 0;
608463429f8SKashyap Desai 
609463429f8SKashyap Desai 	if (!intr_info || !intr_info->op_reply_q)
610463429f8SKashyap Desai 		return IRQ_NONE;
611463429f8SKashyap Desai 
612463429f8SKashyap Desai 	mrioc = intr_info->mrioc;
613463429f8SKashyap Desai 	midx = intr_info->msix_index;
614463429f8SKashyap Desai 
615463429f8SKashyap Desai 	/* Poll for pending IOs completions */
616463429f8SKashyap Desai 	do {
617463429f8SKashyap Desai 		if (!mrioc->intr_enabled)
618463429f8SKashyap Desai 			break;
619463429f8SKashyap Desai 
620463429f8SKashyap Desai 		if (!midx)
621463429f8SKashyap Desai 			mpi3mr_process_admin_reply_q(mrioc);
622463429f8SKashyap Desai 		if (intr_info->op_reply_q)
623463429f8SKashyap Desai 			num_op_reply +=
624463429f8SKashyap Desai 			    mpi3mr_process_op_reply_q(mrioc, intr_info);
625463429f8SKashyap Desai 
626463429f8SKashyap Desai 		usleep_range(mrioc->irqpoll_sleep, 10 * mrioc->irqpoll_sleep);
627463429f8SKashyap Desai 
628463429f8SKashyap Desai 	} while (atomic_read(&intr_info->op_reply_q->pend_ios) &&
629463429f8SKashyap Desai 	    (num_op_reply < mrioc->max_host_ios));
630463429f8SKashyap Desai 
631463429f8SKashyap Desai 	intr_info->op_reply_q->enable_irq_poll = false;
632463429f8SKashyap Desai 	enable_irq(pci_irq_vector(mrioc->pdev, midx));
633463429f8SKashyap Desai 
634824a1566SKashyap Desai 	return IRQ_HANDLED;
635824a1566SKashyap Desai }
636824a1566SKashyap Desai 
637824a1566SKashyap Desai /**
638824a1566SKashyap Desai  * mpi3mr_request_irq - Request IRQ and register ISR
639824a1566SKashyap Desai  * @mrioc: Adapter instance reference
640824a1566SKashyap Desai  * @index: IRQ vector index
641824a1566SKashyap Desai  *
642824a1566SKashyap Desai  * Request threaded ISR with primary ISR and secondary
643824a1566SKashyap Desai  *
644824a1566SKashyap Desai  * Return: 0 on success and non zero on failures.
645824a1566SKashyap Desai  */
646824a1566SKashyap Desai static inline int mpi3mr_request_irq(struct mpi3mr_ioc *mrioc, u16 index)
647824a1566SKashyap Desai {
648824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
649824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info = mrioc->intr_info + index;
650824a1566SKashyap Desai 	int retval = 0;
651824a1566SKashyap Desai 
652824a1566SKashyap Desai 	intr_info->mrioc = mrioc;
653824a1566SKashyap Desai 	intr_info->msix_index = index;
654824a1566SKashyap Desai 	intr_info->op_reply_q = NULL;
655824a1566SKashyap Desai 
656824a1566SKashyap Desai 	snprintf(intr_info->name, MPI3MR_NAME_LENGTH, "%s%d-msix%d",
657824a1566SKashyap Desai 	    mrioc->driver_name, mrioc->id, index);
658824a1566SKashyap Desai 
659824a1566SKashyap Desai 	retval = request_threaded_irq(pci_irq_vector(pdev, index), mpi3mr_isr,
660824a1566SKashyap Desai 	    mpi3mr_isr_poll, IRQF_SHARED, intr_info->name, intr_info);
661824a1566SKashyap Desai 	if (retval) {
662824a1566SKashyap Desai 		ioc_err(mrioc, "%s: Unable to allocate interrupt %d!\n",
663824a1566SKashyap Desai 		    intr_info->name, pci_irq_vector(pdev, index));
664824a1566SKashyap Desai 		return retval;
665824a1566SKashyap Desai 	}
666824a1566SKashyap Desai 
667824a1566SKashyap Desai 	return retval;
668824a1566SKashyap Desai }
669824a1566SKashyap Desai 
670824a1566SKashyap Desai /**
671824a1566SKashyap Desai  * mpi3mr_setup_isr - Setup ISR for the controller
672824a1566SKashyap Desai  * @mrioc: Adapter instance reference
673824a1566SKashyap Desai  * @setup_one: Request one IRQ or more
674824a1566SKashyap Desai  *
675824a1566SKashyap Desai  * Allocate IRQ vectors and call mpi3mr_request_irq to setup ISR
676824a1566SKashyap Desai  *
677824a1566SKashyap Desai  * Return: 0 on success and non zero on failures.
678824a1566SKashyap Desai  */
679824a1566SKashyap Desai static int mpi3mr_setup_isr(struct mpi3mr_ioc *mrioc, u8 setup_one)
680824a1566SKashyap Desai {
681824a1566SKashyap Desai 	unsigned int irq_flags = PCI_IRQ_MSIX;
6822938beddSDan Carpenter 	int max_vectors;
6832938beddSDan Carpenter 	int retval;
6842938beddSDan Carpenter 	int i;
685824a1566SKashyap Desai 	struct irq_affinity desc = { .pre_vectors =  1};
686824a1566SKashyap Desai 
687fe6db615SSreekanth Reddy 	if (mrioc->is_intr_info_set)
688fe6db615SSreekanth Reddy 		return 0;
689fe6db615SSreekanth Reddy 
690824a1566SKashyap Desai 	mpi3mr_cleanup_isr(mrioc);
691824a1566SKashyap Desai 
692824a1566SKashyap Desai 	if (setup_one || reset_devices)
693824a1566SKashyap Desai 		max_vectors = 1;
694824a1566SKashyap Desai 	else {
695824a1566SKashyap Desai 		max_vectors =
696824a1566SKashyap Desai 		    min_t(int, mrioc->cpu_count + 1, mrioc->msix_count);
697824a1566SKashyap Desai 
698824a1566SKashyap Desai 		ioc_info(mrioc,
699824a1566SKashyap Desai 		    "MSI-X vectors supported: %d, no of cores: %d,",
700824a1566SKashyap Desai 		    mrioc->msix_count, mrioc->cpu_count);
701824a1566SKashyap Desai 		ioc_info(mrioc,
702824a1566SKashyap Desai 		    "MSI-x vectors requested: %d\n", max_vectors);
703824a1566SKashyap Desai 	}
704824a1566SKashyap Desai 
705824a1566SKashyap Desai 	irq_flags |= PCI_IRQ_AFFINITY | PCI_IRQ_ALL_TYPES;
706824a1566SKashyap Desai 
707c9566231SKashyap Desai 	mrioc->op_reply_q_offset = (max_vectors > 1) ? 1 : 0;
7082938beddSDan Carpenter 	retval = pci_alloc_irq_vectors_affinity(mrioc->pdev,
709824a1566SKashyap Desai 				1, max_vectors, irq_flags, &desc);
7102938beddSDan Carpenter 	if (retval < 0) {
711824a1566SKashyap Desai 		ioc_err(mrioc, "Cannot alloc irq vectors\n");
712824a1566SKashyap Desai 		goto out_failed;
713824a1566SKashyap Desai 	}
7142938beddSDan Carpenter 	if (retval != max_vectors) {
715824a1566SKashyap Desai 		ioc_info(mrioc,
716824a1566SKashyap Desai 		    "allocated vectors (%d) are less than configured (%d)\n",
7172938beddSDan Carpenter 		    retval, max_vectors);
718c9566231SKashyap Desai 		/*
719c9566231SKashyap Desai 		 * If only one MSI-x is allocated, then MSI-x 0 will be shared
720c9566231SKashyap Desai 		 * between Admin queue and operational queue
721c9566231SKashyap Desai 		 */
7222938beddSDan Carpenter 		if (retval == 1)
723c9566231SKashyap Desai 			mrioc->op_reply_q_offset = 0;
724824a1566SKashyap Desai 
7252938beddSDan Carpenter 		max_vectors = retval;
726824a1566SKashyap Desai 	}
727824a1566SKashyap Desai 	mrioc->intr_info = kzalloc(sizeof(struct mpi3mr_intr_info) * max_vectors,
728824a1566SKashyap Desai 	    GFP_KERNEL);
729824a1566SKashyap Desai 	if (!mrioc->intr_info) {
7302938beddSDan Carpenter 		retval = -ENOMEM;
731824a1566SKashyap Desai 		pci_free_irq_vectors(mrioc->pdev);
732824a1566SKashyap Desai 		goto out_failed;
733824a1566SKashyap Desai 	}
734824a1566SKashyap Desai 	for (i = 0; i < max_vectors; i++) {
735824a1566SKashyap Desai 		retval = mpi3mr_request_irq(mrioc, i);
736824a1566SKashyap Desai 		if (retval) {
737824a1566SKashyap Desai 			mrioc->intr_info_count = i;
738824a1566SKashyap Desai 			goto out_failed;
739824a1566SKashyap Desai 		}
740824a1566SKashyap Desai 	}
741fe6db615SSreekanth Reddy 	if (reset_devices || !setup_one)
742fe6db615SSreekanth Reddy 		mrioc->is_intr_info_set = true;
743824a1566SKashyap Desai 	mrioc->intr_info_count = max_vectors;
744824a1566SKashyap Desai 	mpi3mr_ioc_enable_intr(mrioc);
7452938beddSDan Carpenter 	return 0;
7462938beddSDan Carpenter 
747824a1566SKashyap Desai out_failed:
748824a1566SKashyap Desai 	mpi3mr_cleanup_isr(mrioc);
749824a1566SKashyap Desai 
750824a1566SKashyap Desai 	return retval;
751824a1566SKashyap Desai }
752824a1566SKashyap Desai 
753824a1566SKashyap Desai static const struct {
754824a1566SKashyap Desai 	enum mpi3mr_iocstate value;
755824a1566SKashyap Desai 	char *name;
756824a1566SKashyap Desai } mrioc_states[] = {
757824a1566SKashyap Desai 	{ MRIOC_STATE_READY, "ready" },
758824a1566SKashyap Desai 	{ MRIOC_STATE_FAULT, "fault" },
759824a1566SKashyap Desai 	{ MRIOC_STATE_RESET, "reset" },
760824a1566SKashyap Desai 	{ MRIOC_STATE_BECOMING_READY, "becoming ready" },
761824a1566SKashyap Desai 	{ MRIOC_STATE_RESET_REQUESTED, "reset requested" },
762824a1566SKashyap Desai 	{ MRIOC_STATE_UNRECOVERABLE, "unrecoverable error" },
763824a1566SKashyap Desai };
764824a1566SKashyap Desai 
765824a1566SKashyap Desai static const char *mpi3mr_iocstate_name(enum mpi3mr_iocstate mrioc_state)
766824a1566SKashyap Desai {
767824a1566SKashyap Desai 	int i;
768824a1566SKashyap Desai 	char *name = NULL;
769824a1566SKashyap Desai 
770824a1566SKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mrioc_states); i++) {
771824a1566SKashyap Desai 		if (mrioc_states[i].value == mrioc_state) {
772824a1566SKashyap Desai 			name = mrioc_states[i].name;
773824a1566SKashyap Desai 			break;
774824a1566SKashyap Desai 		}
775824a1566SKashyap Desai 	}
776824a1566SKashyap Desai 	return name;
777824a1566SKashyap Desai }
778824a1566SKashyap Desai 
779f061178eSKashyap Desai /* Reset reason to name mapper structure*/
780f061178eSKashyap Desai static const struct {
781f061178eSKashyap Desai 	enum mpi3mr_reset_reason value;
782f061178eSKashyap Desai 	char *name;
783f061178eSKashyap Desai } mpi3mr_reset_reason_codes[] = {
784f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_BRINGUP, "timeout in bringup" },
785f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_FAULT_WATCH, "fault" },
786f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_IOCTL, "application invocation" },
787f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_EH_HOS, "error handling" },
788f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_TM_TIMEOUT, "TM timeout" },
789f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_IOCTL_TIMEOUT, "IOCTL timeout" },
790f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_MUR_FAILURE, "MUR failure" },
791f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_CTLR_CLEANUP, "timeout in controller cleanup" },
792f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_CIACTIV_FAULT, "component image activation fault" },
793f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_PE_TIMEOUT, "port enable timeout" },
794f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_TSU_TIMEOUT, "time stamp update timeout" },
795f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_DELREQQ_TIMEOUT, "delete request queue timeout" },
796f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_DELREPQ_TIMEOUT, "delete reply queue timeout" },
797f061178eSKashyap Desai 	{
798f061178eSKashyap Desai 		MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT,
799f061178eSKashyap Desai 		"create request queue timeout"
800f061178eSKashyap Desai 	},
801f061178eSKashyap Desai 	{
802f061178eSKashyap Desai 		MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT,
803f061178eSKashyap Desai 		"create reply queue timeout"
804f061178eSKashyap Desai 	},
805f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT, "IOC facts timeout" },
806f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_IOCINIT_TIMEOUT, "IOC init timeout" },
807f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT, "event notify timeout" },
808f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_EVTACK_TIMEOUT, "event acknowledgment timeout" },
809f061178eSKashyap Desai 	{
810f061178eSKashyap Desai 		MPI3MR_RESET_FROM_CIACTVRST_TIMER,
811f061178eSKashyap Desai 		"component image activation timeout"
812f061178eSKashyap Desai 	},
813f061178eSKashyap Desai 	{
814f061178eSKashyap Desai 		MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT,
815f061178eSKashyap Desai 		"get package version timeout"
816f061178eSKashyap Desai 	},
817f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_SYSFS, "sysfs invocation" },
818f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_SYSFS_TIMEOUT, "sysfs TM timeout" },
819b64845a7SSreekanth Reddy 	{ MPI3MR_RESET_FROM_FIRMWARE, "firmware asynchronus reset" },
820f061178eSKashyap Desai };
821f061178eSKashyap Desai 
822f061178eSKashyap Desai /**
823f061178eSKashyap Desai  * mpi3mr_reset_rc_name - get reset reason code name
824f061178eSKashyap Desai  * @reason_code: reset reason code value
825f061178eSKashyap Desai  *
826f061178eSKashyap Desai  * Map reset reason to an NULL terminated ASCII string
827f061178eSKashyap Desai  *
828f061178eSKashyap Desai  * Return: name corresponding to reset reason value or NULL.
829f061178eSKashyap Desai  */
830f061178eSKashyap Desai static const char *mpi3mr_reset_rc_name(enum mpi3mr_reset_reason reason_code)
831f061178eSKashyap Desai {
832f061178eSKashyap Desai 	int i;
833f061178eSKashyap Desai 	char *name = NULL;
834f061178eSKashyap Desai 
835f061178eSKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mpi3mr_reset_reason_codes); i++) {
836f061178eSKashyap Desai 		if (mpi3mr_reset_reason_codes[i].value == reason_code) {
837f061178eSKashyap Desai 			name = mpi3mr_reset_reason_codes[i].name;
838f061178eSKashyap Desai 			break;
839f061178eSKashyap Desai 		}
840f061178eSKashyap Desai 	}
841f061178eSKashyap Desai 	return name;
842f061178eSKashyap Desai }
843f061178eSKashyap Desai 
844f061178eSKashyap Desai /* Reset type to name mapper structure*/
845f061178eSKashyap Desai static const struct {
846f061178eSKashyap Desai 	u16 reset_type;
847f061178eSKashyap Desai 	char *name;
848f061178eSKashyap Desai } mpi3mr_reset_types[] = {
849f061178eSKashyap Desai 	{ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, "soft" },
850f061178eSKashyap Desai 	{ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, "diag fault" },
851f061178eSKashyap Desai };
852f061178eSKashyap Desai 
853f061178eSKashyap Desai /**
854f061178eSKashyap Desai  * mpi3mr_reset_type_name - get reset type name
855f061178eSKashyap Desai  * @reset_type: reset type value
856f061178eSKashyap Desai  *
857f061178eSKashyap Desai  * Map reset type to an NULL terminated ASCII string
858f061178eSKashyap Desai  *
859f061178eSKashyap Desai  * Return: name corresponding to reset type value or NULL.
860f061178eSKashyap Desai  */
861f061178eSKashyap Desai static const char *mpi3mr_reset_type_name(u16 reset_type)
862f061178eSKashyap Desai {
863f061178eSKashyap Desai 	int i;
864f061178eSKashyap Desai 	char *name = NULL;
865f061178eSKashyap Desai 
866f061178eSKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mpi3mr_reset_types); i++) {
867f061178eSKashyap Desai 		if (mpi3mr_reset_types[i].reset_type == reset_type) {
868f061178eSKashyap Desai 			name = mpi3mr_reset_types[i].name;
869f061178eSKashyap Desai 			break;
870f061178eSKashyap Desai 		}
871f061178eSKashyap Desai 	}
872f061178eSKashyap Desai 	return name;
873f061178eSKashyap Desai }
874f061178eSKashyap Desai 
875824a1566SKashyap Desai /**
876824a1566SKashyap Desai  * mpi3mr_print_fault_info - Display fault information
877824a1566SKashyap Desai  * @mrioc: Adapter instance reference
878824a1566SKashyap Desai  *
879824a1566SKashyap Desai  * Display the controller fault information if there is a
880824a1566SKashyap Desai  * controller fault.
881824a1566SKashyap Desai  *
882824a1566SKashyap Desai  * Return: Nothing.
883824a1566SKashyap Desai  */
884b64845a7SSreekanth Reddy void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc)
885824a1566SKashyap Desai {
886824a1566SKashyap Desai 	u32 ioc_status, code, code1, code2, code3;
887824a1566SKashyap Desai 
888824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
889824a1566SKashyap Desai 
890824a1566SKashyap Desai 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) {
891824a1566SKashyap Desai 		code = readl(&mrioc->sysif_regs->fault);
892824a1566SKashyap Desai 		code1 = readl(&mrioc->sysif_regs->fault_info[0]);
893824a1566SKashyap Desai 		code2 = readl(&mrioc->sysif_regs->fault_info[1]);
894824a1566SKashyap Desai 		code3 = readl(&mrioc->sysif_regs->fault_info[2]);
895824a1566SKashyap Desai 
896824a1566SKashyap Desai 		ioc_info(mrioc,
897824a1566SKashyap Desai 		    "fault code(0x%08X): Additional code: (0x%08X:0x%08X:0x%08X)\n",
898824a1566SKashyap Desai 		    code, code1, code2, code3);
899824a1566SKashyap Desai 	}
900824a1566SKashyap Desai }
901824a1566SKashyap Desai 
902824a1566SKashyap Desai /**
903824a1566SKashyap Desai  * mpi3mr_get_iocstate - Get IOC State
904824a1566SKashyap Desai  * @mrioc: Adapter instance reference
905824a1566SKashyap Desai  *
906824a1566SKashyap Desai  * Return a proper IOC state enum based on the IOC status and
907824a1566SKashyap Desai  * IOC configuration and unrcoverable state of the controller.
908824a1566SKashyap Desai  *
909824a1566SKashyap Desai  * Return: Current IOC state.
910824a1566SKashyap Desai  */
911824a1566SKashyap Desai enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc)
912824a1566SKashyap Desai {
913824a1566SKashyap Desai 	u32 ioc_status, ioc_config;
914824a1566SKashyap Desai 	u8 ready, enabled;
915824a1566SKashyap Desai 
916824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
917824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
918824a1566SKashyap Desai 
919824a1566SKashyap Desai 	if (mrioc->unrecoverable)
920824a1566SKashyap Desai 		return MRIOC_STATE_UNRECOVERABLE;
921824a1566SKashyap Desai 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)
922824a1566SKashyap Desai 		return MRIOC_STATE_FAULT;
923824a1566SKashyap Desai 
924824a1566SKashyap Desai 	ready = (ioc_status & MPI3_SYSIF_IOC_STATUS_READY);
925824a1566SKashyap Desai 	enabled = (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC);
926824a1566SKashyap Desai 
927824a1566SKashyap Desai 	if (ready && enabled)
928824a1566SKashyap Desai 		return MRIOC_STATE_READY;
929824a1566SKashyap Desai 	if ((!ready) && (!enabled))
930824a1566SKashyap Desai 		return MRIOC_STATE_RESET;
931824a1566SKashyap Desai 	if ((!ready) && (enabled))
932824a1566SKashyap Desai 		return MRIOC_STATE_BECOMING_READY;
933824a1566SKashyap Desai 
934824a1566SKashyap Desai 	return MRIOC_STATE_RESET_REQUESTED;
935824a1566SKashyap Desai }
936824a1566SKashyap Desai 
937824a1566SKashyap Desai /**
938824a1566SKashyap Desai  * mpi3mr_clear_reset_history - clear reset history
939824a1566SKashyap Desai  * @mrioc: Adapter instance reference
940824a1566SKashyap Desai  *
941824a1566SKashyap Desai  * Write the reset history bit in IOC status to clear the bit,
942824a1566SKashyap Desai  * if it is already set.
943824a1566SKashyap Desai  *
944824a1566SKashyap Desai  * Return: Nothing.
945824a1566SKashyap Desai  */
946824a1566SKashyap Desai static inline void mpi3mr_clear_reset_history(struct mpi3mr_ioc *mrioc)
947824a1566SKashyap Desai {
948824a1566SKashyap Desai 	u32 ioc_status;
949824a1566SKashyap Desai 
950824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
951824a1566SKashyap Desai 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)
952824a1566SKashyap Desai 		writel(ioc_status, &mrioc->sysif_regs->ioc_status);
953824a1566SKashyap Desai }
954824a1566SKashyap Desai 
955824a1566SKashyap Desai /**
956824a1566SKashyap Desai  * mpi3mr_issue_and_process_mur - Message unit Reset handler
957824a1566SKashyap Desai  * @mrioc: Adapter instance reference
958824a1566SKashyap Desai  * @reset_reason: Reset reason code
959824a1566SKashyap Desai  *
960824a1566SKashyap Desai  * Issue Message unit Reset to the controller and wait for it to
961824a1566SKashyap Desai  * be complete.
962824a1566SKashyap Desai  *
963824a1566SKashyap Desai  * Return: 0 on success, -1 on failure.
964824a1566SKashyap Desai  */
965824a1566SKashyap Desai static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc,
966824a1566SKashyap Desai 	u32 reset_reason)
967824a1566SKashyap Desai {
968824a1566SKashyap Desai 	u32 ioc_config, timeout, ioc_status;
969824a1566SKashyap Desai 	int retval = -1;
970824a1566SKashyap Desai 
971824a1566SKashyap Desai 	ioc_info(mrioc, "Issuing Message unit Reset(MUR)\n");
972824a1566SKashyap Desai 	if (mrioc->unrecoverable) {
973824a1566SKashyap Desai 		ioc_info(mrioc, "IOC is unrecoverable MUR not issued\n");
974824a1566SKashyap Desai 		return retval;
975824a1566SKashyap Desai 	}
976824a1566SKashyap Desai 	mpi3mr_clear_reset_history(mrioc);
977824a1566SKashyap Desai 	writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]);
978824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
979824a1566SKashyap Desai 	ioc_config &= ~MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
980824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
981824a1566SKashyap Desai 
982b64845a7SSreekanth Reddy 	timeout = MPI3MR_RESET_ACK_TIMEOUT * 10;
983824a1566SKashyap Desai 	do {
984824a1566SKashyap Desai 		ioc_status = readl(&mrioc->sysif_regs->ioc_status);
985824a1566SKashyap Desai 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)) {
986824a1566SKashyap Desai 			mpi3mr_clear_reset_history(mrioc);
987824a1566SKashyap Desai 			break;
988824a1566SKashyap Desai 		}
989b64845a7SSreekanth Reddy 		if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) {
990b64845a7SSreekanth Reddy 			mpi3mr_print_fault_info(mrioc);
991b64845a7SSreekanth Reddy 			break;
992824a1566SKashyap Desai 		}
993824a1566SKashyap Desai 		msleep(100);
994824a1566SKashyap Desai 	} while (--timeout);
995824a1566SKashyap Desai 
996824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
997b64845a7SSreekanth Reddy 	if (timeout && !((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) ||
998b64845a7SSreekanth Reddy 	      (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) ||
999b64845a7SSreekanth Reddy 	      (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC)))
1000b64845a7SSreekanth Reddy 		retval = 0;
1001824a1566SKashyap Desai 
1002824a1566SKashyap Desai 	ioc_info(mrioc, "Base IOC Sts/Config after %s MUR is (0x%x)/(0x%x)\n",
1003824a1566SKashyap Desai 	    (!retval) ? "successful" : "failed", ioc_status, ioc_config);
1004824a1566SKashyap Desai 	return retval;
1005824a1566SKashyap Desai }
1006824a1566SKashyap Desai 
1007824a1566SKashyap Desai /**
1008c5758fc7SSreekanth Reddy  * mpi3mr_revalidate_factsdata - validate IOCFacts parameters
1009c5758fc7SSreekanth Reddy  * during reset/resume
1010c5758fc7SSreekanth Reddy  * @mrioc: Adapter instance reference
1011c5758fc7SSreekanth Reddy  *
1012c5758fc7SSreekanth Reddy  * Return zero if the new IOCFacts parameters value is compatible with
1013c5758fc7SSreekanth Reddy  * older values else return -EPERM
1014c5758fc7SSreekanth Reddy  */
1015c5758fc7SSreekanth Reddy static int
1016c5758fc7SSreekanth Reddy mpi3mr_revalidate_factsdata(struct mpi3mr_ioc *mrioc)
1017c5758fc7SSreekanth Reddy {
1018c5758fc7SSreekanth Reddy 	u16 dev_handle_bitmap_sz;
1019c5758fc7SSreekanth Reddy 	void *removepend_bitmap;
1020c5758fc7SSreekanth Reddy 
1021c5758fc7SSreekanth Reddy 	if (mrioc->facts.reply_sz > mrioc->reply_sz) {
1022c5758fc7SSreekanth Reddy 		ioc_err(mrioc,
1023c5758fc7SSreekanth Reddy 		    "cannot increase reply size from %d to %d\n",
1024c5758fc7SSreekanth Reddy 		    mrioc->reply_sz, mrioc->facts.reply_sz);
1025c5758fc7SSreekanth Reddy 		return -EPERM;
1026c5758fc7SSreekanth Reddy 	}
1027c5758fc7SSreekanth Reddy 
1028c5758fc7SSreekanth Reddy 	if (mrioc->facts.max_op_reply_q < mrioc->num_op_reply_q) {
1029c5758fc7SSreekanth Reddy 		ioc_err(mrioc,
1030c5758fc7SSreekanth Reddy 		    "cannot reduce number of operational reply queues from %d to %d\n",
1031c5758fc7SSreekanth Reddy 		    mrioc->num_op_reply_q,
1032c5758fc7SSreekanth Reddy 		    mrioc->facts.max_op_reply_q);
1033c5758fc7SSreekanth Reddy 		return -EPERM;
1034c5758fc7SSreekanth Reddy 	}
1035c5758fc7SSreekanth Reddy 
1036c5758fc7SSreekanth Reddy 	if (mrioc->facts.max_op_req_q < mrioc->num_op_req_q) {
1037c5758fc7SSreekanth Reddy 		ioc_err(mrioc,
1038c5758fc7SSreekanth Reddy 		    "cannot reduce number of operational request queues from %d to %d\n",
1039c5758fc7SSreekanth Reddy 		    mrioc->num_op_req_q, mrioc->facts.max_op_req_q);
1040c5758fc7SSreekanth Reddy 		return -EPERM;
1041c5758fc7SSreekanth Reddy 	}
1042c5758fc7SSreekanth Reddy 
1043c5758fc7SSreekanth Reddy 	dev_handle_bitmap_sz = mrioc->facts.max_devhandle / 8;
1044c5758fc7SSreekanth Reddy 	if (mrioc->facts.max_devhandle % 8)
1045c5758fc7SSreekanth Reddy 		dev_handle_bitmap_sz++;
1046c5758fc7SSreekanth Reddy 	if (dev_handle_bitmap_sz > mrioc->dev_handle_bitmap_sz) {
1047c5758fc7SSreekanth Reddy 		removepend_bitmap = krealloc(mrioc->removepend_bitmap,
1048c5758fc7SSreekanth Reddy 		    dev_handle_bitmap_sz, GFP_KERNEL);
1049c5758fc7SSreekanth Reddy 		if (!removepend_bitmap) {
1050c5758fc7SSreekanth Reddy 			ioc_err(mrioc,
1051c5758fc7SSreekanth Reddy 			    "failed to increase removepend_bitmap sz from: %d to %d\n",
1052c5758fc7SSreekanth Reddy 			    mrioc->dev_handle_bitmap_sz, dev_handle_bitmap_sz);
1053c5758fc7SSreekanth Reddy 			return -EPERM;
1054c5758fc7SSreekanth Reddy 		}
1055c5758fc7SSreekanth Reddy 		memset(removepend_bitmap + mrioc->dev_handle_bitmap_sz, 0,
1056c5758fc7SSreekanth Reddy 		    dev_handle_bitmap_sz - mrioc->dev_handle_bitmap_sz);
1057c5758fc7SSreekanth Reddy 		mrioc->removepend_bitmap = removepend_bitmap;
1058c5758fc7SSreekanth Reddy 		ioc_info(mrioc,
1059c5758fc7SSreekanth Reddy 		    "increased dev_handle_bitmap_sz from %d to %d\n",
1060c5758fc7SSreekanth Reddy 		    mrioc->dev_handle_bitmap_sz, dev_handle_bitmap_sz);
1061c5758fc7SSreekanth Reddy 		mrioc->dev_handle_bitmap_sz = dev_handle_bitmap_sz;
1062c5758fc7SSreekanth Reddy 	}
1063c5758fc7SSreekanth Reddy 
1064c5758fc7SSreekanth Reddy 	return 0;
1065c5758fc7SSreekanth Reddy }
1066c5758fc7SSreekanth Reddy 
1067c5758fc7SSreekanth Reddy /**
1068824a1566SKashyap Desai  * mpi3mr_bring_ioc_ready - Bring controller to ready state
1069824a1566SKashyap Desai  * @mrioc: Adapter instance reference
1070824a1566SKashyap Desai  *
1071824a1566SKashyap Desai  * Set Enable IOC bit in IOC configuration register and wait for
1072824a1566SKashyap Desai  * the controller to become ready.
1073824a1566SKashyap Desai  *
107459bd9cfeSSreekanth Reddy  * Return: 0 on success, appropriate error on failure.
1075824a1566SKashyap Desai  */
1076824a1566SKashyap Desai static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc)
1077824a1566SKashyap Desai {
107859bd9cfeSSreekanth Reddy 	u32 ioc_config, ioc_status, timeout;
107959bd9cfeSSreekanth Reddy 	int retval = 0;
108059bd9cfeSSreekanth Reddy 	enum mpi3mr_iocstate ioc_state;
108159bd9cfeSSreekanth Reddy 	u64 base_info;
1082824a1566SKashyap Desai 
108359bd9cfeSSreekanth Reddy 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
108459bd9cfeSSreekanth Reddy 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
108559bd9cfeSSreekanth Reddy 	base_info = lo_hi_readq(&mrioc->sysif_regs->ioc_information);
108659bd9cfeSSreekanth Reddy 	ioc_info(mrioc, "ioc_status(0x%08x), ioc_config(0x%08x), ioc_info(0x%016llx) at the bringup\n",
108759bd9cfeSSreekanth Reddy 	    ioc_status, ioc_config, base_info);
108859bd9cfeSSreekanth Reddy 
108959bd9cfeSSreekanth Reddy 	/*The timeout value is in 2sec unit, changing it to seconds*/
109059bd9cfeSSreekanth Reddy 	mrioc->ready_timeout =
109159bd9cfeSSreekanth Reddy 	    ((base_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >>
109259bd9cfeSSreekanth Reddy 	    MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT) * 2;
109359bd9cfeSSreekanth Reddy 
109459bd9cfeSSreekanth Reddy 	ioc_info(mrioc, "ready timeout: %d seconds\n", mrioc->ready_timeout);
109559bd9cfeSSreekanth Reddy 
109659bd9cfeSSreekanth Reddy 	ioc_state = mpi3mr_get_iocstate(mrioc);
109759bd9cfeSSreekanth Reddy 	ioc_info(mrioc, "controller is in %s state during detection\n",
109859bd9cfeSSreekanth Reddy 	    mpi3mr_iocstate_name(ioc_state));
109959bd9cfeSSreekanth Reddy 
110059bd9cfeSSreekanth Reddy 	if (ioc_state == MRIOC_STATE_BECOMING_READY ||
110159bd9cfeSSreekanth Reddy 	    ioc_state == MRIOC_STATE_RESET_REQUESTED) {
110259bd9cfeSSreekanth Reddy 		timeout = mrioc->ready_timeout * 10;
110359bd9cfeSSreekanth Reddy 		do {
110459bd9cfeSSreekanth Reddy 			msleep(100);
110559bd9cfeSSreekanth Reddy 		} while (--timeout);
110659bd9cfeSSreekanth Reddy 
110759bd9cfeSSreekanth Reddy 		ioc_state = mpi3mr_get_iocstate(mrioc);
110859bd9cfeSSreekanth Reddy 		ioc_info(mrioc,
110959bd9cfeSSreekanth Reddy 		    "controller is in %s state after waiting to reset\n",
111059bd9cfeSSreekanth Reddy 		    mpi3mr_iocstate_name(ioc_state));
111159bd9cfeSSreekanth Reddy 	}
111259bd9cfeSSreekanth Reddy 
111359bd9cfeSSreekanth Reddy 	if (ioc_state == MRIOC_STATE_READY) {
111459bd9cfeSSreekanth Reddy 		ioc_info(mrioc, "issuing message unit reset (MUR) to bring to reset state\n");
111559bd9cfeSSreekanth Reddy 		retval = mpi3mr_issue_and_process_mur(mrioc,
111659bd9cfeSSreekanth Reddy 		    MPI3MR_RESET_FROM_BRINGUP);
111759bd9cfeSSreekanth Reddy 		ioc_state = mpi3mr_get_iocstate(mrioc);
111859bd9cfeSSreekanth Reddy 		if (retval)
111959bd9cfeSSreekanth Reddy 			ioc_err(mrioc,
112059bd9cfeSSreekanth Reddy 			    "message unit reset failed with error %d current state %s\n",
112159bd9cfeSSreekanth Reddy 			    retval, mpi3mr_iocstate_name(ioc_state));
112259bd9cfeSSreekanth Reddy 	}
112359bd9cfeSSreekanth Reddy 	if (ioc_state != MRIOC_STATE_RESET) {
112459bd9cfeSSreekanth Reddy 		mpi3mr_print_fault_info(mrioc);
112559bd9cfeSSreekanth Reddy 		ioc_info(mrioc, "issuing soft reset to bring to reset state\n");
112659bd9cfeSSreekanth Reddy 		retval = mpi3mr_issue_reset(mrioc,
112759bd9cfeSSreekanth Reddy 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
112859bd9cfeSSreekanth Reddy 		    MPI3MR_RESET_FROM_BRINGUP);
112959bd9cfeSSreekanth Reddy 		if (retval) {
113059bd9cfeSSreekanth Reddy 			ioc_err(mrioc,
113159bd9cfeSSreekanth Reddy 			    "soft reset failed with error %d\n", retval);
113259bd9cfeSSreekanth Reddy 			goto out_failed;
113359bd9cfeSSreekanth Reddy 		}
113459bd9cfeSSreekanth Reddy 	}
113559bd9cfeSSreekanth Reddy 	ioc_state = mpi3mr_get_iocstate(mrioc);
113659bd9cfeSSreekanth Reddy 	if (ioc_state != MRIOC_STATE_RESET) {
113759bd9cfeSSreekanth Reddy 		ioc_err(mrioc,
113859bd9cfeSSreekanth Reddy 		    "cannot bring controller to reset state, current state: %s\n",
113959bd9cfeSSreekanth Reddy 		    mpi3mr_iocstate_name(ioc_state));
114059bd9cfeSSreekanth Reddy 		goto out_failed;
114159bd9cfeSSreekanth Reddy 	}
114259bd9cfeSSreekanth Reddy 	mpi3mr_clear_reset_history(mrioc);
114359bd9cfeSSreekanth Reddy 	retval = mpi3mr_setup_admin_qpair(mrioc);
114459bd9cfeSSreekanth Reddy 	if (retval) {
114559bd9cfeSSreekanth Reddy 		ioc_err(mrioc, "failed to setup admin queues: error %d\n",
114659bd9cfeSSreekanth Reddy 		    retval);
114759bd9cfeSSreekanth Reddy 		goto out_failed;
114859bd9cfeSSreekanth Reddy 	}
114959bd9cfeSSreekanth Reddy 
115059bd9cfeSSreekanth Reddy 	ioc_info(mrioc, "bringing controller to ready state\n");
1151824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
1152824a1566SKashyap Desai 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
1153824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
1154824a1566SKashyap Desai 
1155824a1566SKashyap Desai 	timeout = mrioc->ready_timeout * 10;
1156824a1566SKashyap Desai 	do {
115759bd9cfeSSreekanth Reddy 		ioc_state = mpi3mr_get_iocstate(mrioc);
115859bd9cfeSSreekanth Reddy 		if (ioc_state == MRIOC_STATE_READY) {
115959bd9cfeSSreekanth Reddy 			ioc_info(mrioc,
116059bd9cfeSSreekanth Reddy 			    "successfully transistioned to %s state\n",
116159bd9cfeSSreekanth Reddy 			    mpi3mr_iocstate_name(ioc_state));
1162824a1566SKashyap Desai 			return 0;
116359bd9cfeSSreekanth Reddy 		}
1164824a1566SKashyap Desai 		msleep(100);
1165824a1566SKashyap Desai 	} while (--timeout);
1166824a1566SKashyap Desai 
116759bd9cfeSSreekanth Reddy out_failed:
116859bd9cfeSSreekanth Reddy 	ioc_state = mpi3mr_get_iocstate(mrioc);
116959bd9cfeSSreekanth Reddy 	ioc_err(mrioc,
117059bd9cfeSSreekanth Reddy 	    "failed to bring to ready state,  current state: %s\n",
117159bd9cfeSSreekanth Reddy 	    mpi3mr_iocstate_name(ioc_state));
117259bd9cfeSSreekanth Reddy 	return retval;
1173824a1566SKashyap Desai }
1174824a1566SKashyap Desai 
1175824a1566SKashyap Desai /**
1176f061178eSKashyap Desai  * mpi3mr_soft_reset_success - Check softreset is success or not
1177f061178eSKashyap Desai  * @ioc_status: IOC status register value
1178f061178eSKashyap Desai  * @ioc_config: IOC config register value
1179f061178eSKashyap Desai  *
1180f061178eSKashyap Desai  * Check whether the soft reset is successful or not based on
1181f061178eSKashyap Desai  * IOC status and IOC config register values.
1182f061178eSKashyap Desai  *
1183f061178eSKashyap Desai  * Return: True when the soft reset is success, false otherwise.
1184f061178eSKashyap Desai  */
1185f061178eSKashyap Desai static inline bool
1186f061178eSKashyap Desai mpi3mr_soft_reset_success(u32 ioc_status, u32 ioc_config)
1187f061178eSKashyap Desai {
1188f061178eSKashyap Desai 	if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) ||
1189f061178eSKashyap Desai 	    (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC)))
1190f061178eSKashyap Desai 		return true;
1191f061178eSKashyap Desai 	return false;
1192f061178eSKashyap Desai }
1193f061178eSKashyap Desai 
1194f061178eSKashyap Desai /**
1195f061178eSKashyap Desai  * mpi3mr_diagfault_success - Check diag fault is success or not
1196f061178eSKashyap Desai  * @mrioc: Adapter reference
1197f061178eSKashyap Desai  * @ioc_status: IOC status register value
1198f061178eSKashyap Desai  *
1199f061178eSKashyap Desai  * Check whether the controller hit diag reset fault code.
1200f061178eSKashyap Desai  *
1201f061178eSKashyap Desai  * Return: True when there is diag fault, false otherwise.
1202f061178eSKashyap Desai  */
1203f061178eSKashyap Desai static inline bool mpi3mr_diagfault_success(struct mpi3mr_ioc *mrioc,
1204f061178eSKashyap Desai 	u32 ioc_status)
1205f061178eSKashyap Desai {
1206f061178eSKashyap Desai 	u32 fault;
1207f061178eSKashyap Desai 
1208f061178eSKashyap Desai 	if (!(ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT))
1209f061178eSKashyap Desai 		return false;
1210f061178eSKashyap Desai 	fault = readl(&mrioc->sysif_regs->fault) & MPI3_SYSIF_FAULT_CODE_MASK;
1211b64845a7SSreekanth Reddy 	if (fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET) {
1212b64845a7SSreekanth Reddy 		mpi3mr_print_fault_info(mrioc);
1213f061178eSKashyap Desai 		return true;
1214b64845a7SSreekanth Reddy 	}
1215f061178eSKashyap Desai 	return false;
1216f061178eSKashyap Desai }
1217f061178eSKashyap Desai 
1218f061178eSKashyap Desai /**
1219824a1566SKashyap Desai  * mpi3mr_set_diagsave - Set diag save bit for snapdump
1220824a1566SKashyap Desai  * @mrioc: Adapter reference
1221824a1566SKashyap Desai  *
1222824a1566SKashyap Desai  * Set diag save bit in IOC configuration register to enable
1223824a1566SKashyap Desai  * snapdump.
1224824a1566SKashyap Desai  *
1225824a1566SKashyap Desai  * Return: Nothing.
1226824a1566SKashyap Desai  */
1227824a1566SKashyap Desai static inline void mpi3mr_set_diagsave(struct mpi3mr_ioc *mrioc)
1228824a1566SKashyap Desai {
1229824a1566SKashyap Desai 	u32 ioc_config;
1230824a1566SKashyap Desai 
1231824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
1232824a1566SKashyap Desai 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_DIAG_SAVE;
1233824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
1234824a1566SKashyap Desai }
1235824a1566SKashyap Desai 
1236824a1566SKashyap Desai /**
1237824a1566SKashyap Desai  * mpi3mr_issue_reset - Issue reset to the controller
1238824a1566SKashyap Desai  * @mrioc: Adapter reference
1239824a1566SKashyap Desai  * @reset_type: Reset type
1240824a1566SKashyap Desai  * @reset_reason: Reset reason code
1241824a1566SKashyap Desai  *
1242f061178eSKashyap Desai  * Unlock the host diagnostic registers and write the specific
1243f061178eSKashyap Desai  * reset type to that, wait for reset acknowledgment from the
1244f061178eSKashyap Desai  * controller, if the reset is not successful retry for the
1245f061178eSKashyap Desai  * predefined number of times.
1246824a1566SKashyap Desai  *
1247824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
1248824a1566SKashyap Desai  */
1249824a1566SKashyap Desai static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type,
1250824a1566SKashyap Desai 	u32 reset_reason)
1251824a1566SKashyap Desai {
1252f061178eSKashyap Desai 	int retval = -1;
1253b64845a7SSreekanth Reddy 	u8 unlock_retry_count = 0;
1254b64845a7SSreekanth Reddy 	u32 host_diagnostic, ioc_status, ioc_config;
1255b64845a7SSreekanth Reddy 	u32 timeout = MPI3MR_RESET_ACK_TIMEOUT * 10;
1256f061178eSKashyap Desai 
1257f061178eSKashyap Desai 	if ((reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET) &&
1258f061178eSKashyap Desai 	    (reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT))
1259b64845a7SSreekanth Reddy 		return retval;
1260f061178eSKashyap Desai 	if (mrioc->unrecoverable)
1261b64845a7SSreekanth Reddy 		return retval;
1262b64845a7SSreekanth Reddy 	if (reset_reason == MPI3MR_RESET_FROM_FIRMWARE) {
1263b64845a7SSreekanth Reddy 		retval = 0;
1264b64845a7SSreekanth Reddy 		return retval;
1265b64845a7SSreekanth Reddy 	}
1266b64845a7SSreekanth Reddy 
1267b64845a7SSreekanth Reddy 	ioc_info(mrioc, "%s reset due to %s(0x%x)\n",
1268b64845a7SSreekanth Reddy 	    mpi3mr_reset_type_name(reset_type),
1269b64845a7SSreekanth Reddy 	    mpi3mr_reset_rc_name(reset_reason), reset_reason);
1270b64845a7SSreekanth Reddy 
1271f061178eSKashyap Desai 	mpi3mr_clear_reset_history(mrioc);
1272f061178eSKashyap Desai 	do {
1273f061178eSKashyap Desai 		ioc_info(mrioc,
1274f061178eSKashyap Desai 		    "Write magic sequence to unlock host diag register (retry=%d)\n",
1275f061178eSKashyap Desai 		    ++unlock_retry_count);
1276f061178eSKashyap Desai 		if (unlock_retry_count >= MPI3MR_HOSTDIAG_UNLOCK_RETRY_COUNT) {
1277b64845a7SSreekanth Reddy 			ioc_err(mrioc,
1278b64845a7SSreekanth Reddy 			    "%s reset failed due to unlock failure, host_diagnostic(0x%08x)\n",
1279b64845a7SSreekanth Reddy 			    mpi3mr_reset_type_name(reset_type),
1280b64845a7SSreekanth Reddy 			    host_diagnostic);
1281f061178eSKashyap Desai 			mrioc->unrecoverable = 1;
1282b64845a7SSreekanth Reddy 			return retval;
1283f061178eSKashyap Desai 		}
1284f061178eSKashyap Desai 
1285f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_FLUSH,
1286f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1287f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_1ST,
1288f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1289f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND,
1290f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1291f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_3RD,
1292f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1293f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_4TH,
1294f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1295f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_5TH,
1296f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1297f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_6TH,
1298f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1299f061178eSKashyap Desai 		usleep_range(1000, 1100);
1300f061178eSKashyap Desai 		host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic);
1301f061178eSKashyap Desai 		ioc_info(mrioc,
1302f061178eSKashyap Desai 		    "wrote magic sequence: retry_count(%d), host_diagnostic(0x%08x)\n",
1303f061178eSKashyap Desai 		    unlock_retry_count, host_diagnostic);
1304f061178eSKashyap Desai 	} while (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_DIAG_WRITE_ENABLE));
1305f061178eSKashyap Desai 
1306f061178eSKashyap Desai 	writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]);
1307f061178eSKashyap Desai 	writel(host_diagnostic | reset_type,
1308f061178eSKashyap Desai 	    &mrioc->sysif_regs->host_diagnostic);
1309b64845a7SSreekanth Reddy 	switch (reset_type) {
1310b64845a7SSreekanth Reddy 	case MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET:
1311f061178eSKashyap Desai 		do {
1312f061178eSKashyap Desai 			ioc_status = readl(&mrioc->sysif_regs->ioc_status);
1313f061178eSKashyap Desai 			ioc_config =
1314f061178eSKashyap Desai 			    readl(&mrioc->sysif_regs->ioc_configuration);
1315b64845a7SSreekanth Reddy 			if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)
1316b64845a7SSreekanth Reddy 			    && mpi3mr_soft_reset_success(ioc_status, ioc_config)
1317b64845a7SSreekanth Reddy 			    ) {
1318b64845a7SSreekanth Reddy 				mpi3mr_clear_reset_history(mrioc);
1319f061178eSKashyap Desai 				retval = 0;
1320f061178eSKashyap Desai 				break;
1321f061178eSKashyap Desai 			}
1322f061178eSKashyap Desai 			msleep(100);
1323f061178eSKashyap Desai 		} while (--timeout);
1324b64845a7SSreekanth Reddy 		mpi3mr_print_fault_info(mrioc);
1325b64845a7SSreekanth Reddy 		break;
1326b64845a7SSreekanth Reddy 	case MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT:
1327f061178eSKashyap Desai 		do {
1328f061178eSKashyap Desai 			ioc_status = readl(&mrioc->sysif_regs->ioc_status);
1329f061178eSKashyap Desai 			if (mpi3mr_diagfault_success(mrioc, ioc_status)) {
1330f061178eSKashyap Desai 				retval = 0;
1331f061178eSKashyap Desai 				break;
1332f061178eSKashyap Desai 			}
1333f061178eSKashyap Desai 			msleep(100);
1334f061178eSKashyap Desai 		} while (--timeout);
1335b64845a7SSreekanth Reddy 		break;
1336b64845a7SSreekanth Reddy 	default:
1337b64845a7SSreekanth Reddy 		break;
1338b64845a7SSreekanth Reddy 	}
1339b64845a7SSreekanth Reddy 
1340f061178eSKashyap Desai 	writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND,
1341f061178eSKashyap Desai 	    &mrioc->sysif_regs->write_sequence);
1342f061178eSKashyap Desai 
1343f061178eSKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
1344b64845a7SSreekanth Reddy 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
1345f061178eSKashyap Desai 	ioc_info(mrioc,
1346b64845a7SSreekanth Reddy 	    "ioc_status/ioc_onfig after %s reset is (0x%x)/(0x%x)\n",
1347f061178eSKashyap Desai 	    (!retval)?"successful":"failed", ioc_status,
1348f061178eSKashyap Desai 	    ioc_config);
1349b64845a7SSreekanth Reddy 	if (retval)
1350b64845a7SSreekanth Reddy 		mrioc->unrecoverable = 1;
1351f061178eSKashyap Desai 	return retval;
1352824a1566SKashyap Desai }
1353824a1566SKashyap Desai 
1354824a1566SKashyap Desai /**
1355824a1566SKashyap Desai  * mpi3mr_admin_request_post - Post request to admin queue
1356824a1566SKashyap Desai  * @mrioc: Adapter reference
1357824a1566SKashyap Desai  * @admin_req: MPI3 request
1358824a1566SKashyap Desai  * @admin_req_sz: Request size
1359824a1566SKashyap Desai  * @ignore_reset: Ignore reset in process
1360824a1566SKashyap Desai  *
1361824a1566SKashyap Desai  * Post the MPI3 request into admin request queue and
1362824a1566SKashyap Desai  * inform the controller, if the queue is full return
1363824a1566SKashyap Desai  * appropriate error.
1364824a1566SKashyap Desai  *
1365824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
1366824a1566SKashyap Desai  */
1367824a1566SKashyap Desai int mpi3mr_admin_request_post(struct mpi3mr_ioc *mrioc, void *admin_req,
1368824a1566SKashyap Desai 	u16 admin_req_sz, u8 ignore_reset)
1369824a1566SKashyap Desai {
1370824a1566SKashyap Desai 	u16 areq_pi = 0, areq_ci = 0, max_entries = 0;
1371824a1566SKashyap Desai 	int retval = 0;
1372824a1566SKashyap Desai 	unsigned long flags;
1373824a1566SKashyap Desai 	u8 *areq_entry;
1374824a1566SKashyap Desai 
1375824a1566SKashyap Desai 	if (mrioc->unrecoverable) {
1376824a1566SKashyap Desai 		ioc_err(mrioc, "%s : Unrecoverable controller\n", __func__);
1377824a1566SKashyap Desai 		return -EFAULT;
1378824a1566SKashyap Desai 	}
1379824a1566SKashyap Desai 
1380824a1566SKashyap Desai 	spin_lock_irqsave(&mrioc->admin_req_lock, flags);
1381824a1566SKashyap Desai 	areq_pi = mrioc->admin_req_pi;
1382824a1566SKashyap Desai 	areq_ci = mrioc->admin_req_ci;
1383824a1566SKashyap Desai 	max_entries = mrioc->num_admin_req;
1384824a1566SKashyap Desai 	if ((areq_ci == (areq_pi + 1)) || ((!areq_ci) &&
1385824a1566SKashyap Desai 	    (areq_pi == (max_entries - 1)))) {
1386824a1566SKashyap Desai 		ioc_err(mrioc, "AdminReqQ full condition detected\n");
1387824a1566SKashyap Desai 		retval = -EAGAIN;
1388824a1566SKashyap Desai 		goto out;
1389824a1566SKashyap Desai 	}
1390824a1566SKashyap Desai 	if (!ignore_reset && mrioc->reset_in_progress) {
1391824a1566SKashyap Desai 		ioc_err(mrioc, "AdminReqQ submit reset in progress\n");
1392824a1566SKashyap Desai 		retval = -EAGAIN;
1393824a1566SKashyap Desai 		goto out;
1394824a1566SKashyap Desai 	}
1395824a1566SKashyap Desai 	areq_entry = (u8 *)mrioc->admin_req_base +
1396824a1566SKashyap Desai 	    (areq_pi * MPI3MR_ADMIN_REQ_FRAME_SZ);
1397824a1566SKashyap Desai 	memset(areq_entry, 0, MPI3MR_ADMIN_REQ_FRAME_SZ);
1398824a1566SKashyap Desai 	memcpy(areq_entry, (u8 *)admin_req, admin_req_sz);
1399824a1566SKashyap Desai 
1400824a1566SKashyap Desai 	if (++areq_pi == max_entries)
1401824a1566SKashyap Desai 		areq_pi = 0;
1402824a1566SKashyap Desai 	mrioc->admin_req_pi = areq_pi;
1403824a1566SKashyap Desai 
1404824a1566SKashyap Desai 	writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi);
1405824a1566SKashyap Desai 
1406824a1566SKashyap Desai out:
1407824a1566SKashyap Desai 	spin_unlock_irqrestore(&mrioc->admin_req_lock, flags);
1408824a1566SKashyap Desai 
1409824a1566SKashyap Desai 	return retval;
1410824a1566SKashyap Desai }
1411824a1566SKashyap Desai 
1412824a1566SKashyap Desai /**
1413c9566231SKashyap Desai  * mpi3mr_free_op_req_q_segments - free request memory segments
1414c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1415c9566231SKashyap Desai  * @q_idx: operational request queue index
1416c9566231SKashyap Desai  *
1417c9566231SKashyap Desai  * Free memory segments allocated for operational request queue
1418c9566231SKashyap Desai  *
1419c9566231SKashyap Desai  * Return: Nothing.
1420c9566231SKashyap Desai  */
1421c9566231SKashyap Desai static void mpi3mr_free_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx)
1422c9566231SKashyap Desai {
1423c9566231SKashyap Desai 	u16 j;
1424c9566231SKashyap Desai 	int size;
1425c9566231SKashyap Desai 	struct segments *segments;
1426c9566231SKashyap Desai 
1427c9566231SKashyap Desai 	segments = mrioc->req_qinfo[q_idx].q_segments;
1428c9566231SKashyap Desai 	if (!segments)
1429c9566231SKashyap Desai 		return;
1430c9566231SKashyap Desai 
1431c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1432c9566231SKashyap Desai 		size = MPI3MR_OP_REQ_Q_SEG_SIZE;
1433c9566231SKashyap Desai 		if (mrioc->req_qinfo[q_idx].q_segment_list) {
1434c9566231SKashyap Desai 			dma_free_coherent(&mrioc->pdev->dev,
1435c9566231SKashyap Desai 			    MPI3MR_MAX_SEG_LIST_SIZE,
1436c9566231SKashyap Desai 			    mrioc->req_qinfo[q_idx].q_segment_list,
1437c9566231SKashyap Desai 			    mrioc->req_qinfo[q_idx].q_segment_list_dma);
1438c9566231SKashyap Desai 			mrioc->op_reply_qinfo[q_idx].q_segment_list = NULL;
1439c9566231SKashyap Desai 		}
1440c9566231SKashyap Desai 	} else
1441c9566231SKashyap Desai 		size = mrioc->req_qinfo[q_idx].num_requests *
1442c9566231SKashyap Desai 		    mrioc->facts.op_req_sz;
1443c9566231SKashyap Desai 
1444c9566231SKashyap Desai 	for (j = 0; j < mrioc->req_qinfo[q_idx].num_segments; j++) {
1445c9566231SKashyap Desai 		if (!segments[j].segment)
1446c9566231SKashyap Desai 			continue;
1447c9566231SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev,
1448c9566231SKashyap Desai 		    size, segments[j].segment, segments[j].segment_dma);
1449c9566231SKashyap Desai 		segments[j].segment = NULL;
1450c9566231SKashyap Desai 	}
1451c9566231SKashyap Desai 	kfree(mrioc->req_qinfo[q_idx].q_segments);
1452c9566231SKashyap Desai 	mrioc->req_qinfo[q_idx].q_segments = NULL;
1453c9566231SKashyap Desai 	mrioc->req_qinfo[q_idx].qid = 0;
1454c9566231SKashyap Desai }
1455c9566231SKashyap Desai 
1456c9566231SKashyap Desai /**
1457c9566231SKashyap Desai  * mpi3mr_free_op_reply_q_segments - free reply memory segments
1458c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1459c9566231SKashyap Desai  * @q_idx: operational reply queue index
1460c9566231SKashyap Desai  *
1461c9566231SKashyap Desai  * Free memory segments allocated for operational reply queue
1462c9566231SKashyap Desai  *
1463c9566231SKashyap Desai  * Return: Nothing.
1464c9566231SKashyap Desai  */
1465c9566231SKashyap Desai static void mpi3mr_free_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx)
1466c9566231SKashyap Desai {
1467c9566231SKashyap Desai 	u16 j;
1468c9566231SKashyap Desai 	int size;
1469c9566231SKashyap Desai 	struct segments *segments;
1470c9566231SKashyap Desai 
1471c9566231SKashyap Desai 	segments = mrioc->op_reply_qinfo[q_idx].q_segments;
1472c9566231SKashyap Desai 	if (!segments)
1473c9566231SKashyap Desai 		return;
1474c9566231SKashyap Desai 
1475c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1476c9566231SKashyap Desai 		size = MPI3MR_OP_REP_Q_SEG_SIZE;
1477c9566231SKashyap Desai 		if (mrioc->op_reply_qinfo[q_idx].q_segment_list) {
1478c9566231SKashyap Desai 			dma_free_coherent(&mrioc->pdev->dev,
1479c9566231SKashyap Desai 			    MPI3MR_MAX_SEG_LIST_SIZE,
1480c9566231SKashyap Desai 			    mrioc->op_reply_qinfo[q_idx].q_segment_list,
1481c9566231SKashyap Desai 			    mrioc->op_reply_qinfo[q_idx].q_segment_list_dma);
1482c9566231SKashyap Desai 			mrioc->op_reply_qinfo[q_idx].q_segment_list = NULL;
1483c9566231SKashyap Desai 		}
1484c9566231SKashyap Desai 	} else
1485c9566231SKashyap Desai 		size = mrioc->op_reply_qinfo[q_idx].segment_qd *
1486c9566231SKashyap Desai 		    mrioc->op_reply_desc_sz;
1487c9566231SKashyap Desai 
1488c9566231SKashyap Desai 	for (j = 0; j < mrioc->op_reply_qinfo[q_idx].num_segments; j++) {
1489c9566231SKashyap Desai 		if (!segments[j].segment)
1490c9566231SKashyap Desai 			continue;
1491c9566231SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev,
1492c9566231SKashyap Desai 		    size, segments[j].segment, segments[j].segment_dma);
1493c9566231SKashyap Desai 		segments[j].segment = NULL;
1494c9566231SKashyap Desai 	}
1495c9566231SKashyap Desai 
1496c9566231SKashyap Desai 	kfree(mrioc->op_reply_qinfo[q_idx].q_segments);
1497c9566231SKashyap Desai 	mrioc->op_reply_qinfo[q_idx].q_segments = NULL;
1498c9566231SKashyap Desai 	mrioc->op_reply_qinfo[q_idx].qid = 0;
1499c9566231SKashyap Desai }
1500c9566231SKashyap Desai 
1501c9566231SKashyap Desai /**
1502c9566231SKashyap Desai  * mpi3mr_delete_op_reply_q - delete operational reply queue
1503c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1504c9566231SKashyap Desai  * @qidx: operational reply queue index
1505c9566231SKashyap Desai  *
1506c9566231SKashyap Desai  * Delete operatinal reply queue by issuing MPI request
1507c9566231SKashyap Desai  * through admin queue.
1508c9566231SKashyap Desai  *
1509c9566231SKashyap Desai  * Return:  0 on success, non-zero on failure.
1510c9566231SKashyap Desai  */
1511c9566231SKashyap Desai static int mpi3mr_delete_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx)
1512c9566231SKashyap Desai {
1513c9566231SKashyap Desai 	struct mpi3_delete_reply_queue_request delq_req;
1514c9566231SKashyap Desai 	int retval = 0;
1515c9566231SKashyap Desai 	u16 reply_qid = 0, midx;
1516c9566231SKashyap Desai 
1517c9566231SKashyap Desai 	reply_qid = mrioc->op_reply_qinfo[qidx].qid;
1518c9566231SKashyap Desai 
1519c9566231SKashyap Desai 	midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset);
1520c9566231SKashyap Desai 
1521c9566231SKashyap Desai 	if (!reply_qid)	{
1522c9566231SKashyap Desai 		retval = -1;
1523c9566231SKashyap Desai 		ioc_err(mrioc, "Issue DelRepQ: called with invalid ReqQID\n");
1524c9566231SKashyap Desai 		goto out;
1525c9566231SKashyap Desai 	}
1526c9566231SKashyap Desai 
1527c9566231SKashyap Desai 	memset(&delq_req, 0, sizeof(delq_req));
1528c9566231SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
1529c9566231SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
1530c9566231SKashyap Desai 		retval = -1;
1531c9566231SKashyap Desai 		ioc_err(mrioc, "Issue DelRepQ: Init command is in use\n");
1532c9566231SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
1533c9566231SKashyap Desai 		goto out;
1534c9566231SKashyap Desai 	}
1535c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
1536c9566231SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
1537c9566231SKashyap Desai 	mrioc->init_cmds.callback = NULL;
1538c9566231SKashyap Desai 	delq_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
1539c9566231SKashyap Desai 	delq_req.function = MPI3_FUNCTION_DELETE_REPLY_QUEUE;
1540c9566231SKashyap Desai 	delq_req.queue_id = cpu_to_le16(reply_qid);
1541c9566231SKashyap Desai 
1542c9566231SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
1543c9566231SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &delq_req, sizeof(delq_req),
1544c9566231SKashyap Desai 	    1);
1545c9566231SKashyap Desai 	if (retval) {
1546c9566231SKashyap Desai 		ioc_err(mrioc, "Issue DelRepQ: Admin Post failed\n");
1547c9566231SKashyap Desai 		goto out_unlock;
1548c9566231SKashyap Desai 	}
1549c9566231SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
1550c9566231SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
1551c9566231SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
1552a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "delete reply queue timed out\n");
1553a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
1554c9566231SKashyap Desai 		    MPI3MR_RESET_FROM_DELREPQ_TIMEOUT);
1555c9566231SKashyap Desai 		retval = -1;
1556c9566231SKashyap Desai 		goto out_unlock;
1557c9566231SKashyap Desai 	}
1558c9566231SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
1559c9566231SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
1560c9566231SKashyap Desai 		ioc_err(mrioc,
1561c9566231SKashyap Desai 		    "Issue DelRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
1562c9566231SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
1563c9566231SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
1564c9566231SKashyap Desai 		retval = -1;
1565c9566231SKashyap Desai 		goto out_unlock;
1566c9566231SKashyap Desai 	}
1567c9566231SKashyap Desai 	mrioc->intr_info[midx].op_reply_q = NULL;
1568c9566231SKashyap Desai 
1569c9566231SKashyap Desai 	mpi3mr_free_op_reply_q_segments(mrioc, qidx);
1570c9566231SKashyap Desai out_unlock:
1571c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
1572c9566231SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
1573c9566231SKashyap Desai out:
1574c9566231SKashyap Desai 
1575c9566231SKashyap Desai 	return retval;
1576c9566231SKashyap Desai }
1577c9566231SKashyap Desai 
1578c9566231SKashyap Desai /**
1579c9566231SKashyap Desai  * mpi3mr_alloc_op_reply_q_segments -Alloc segmented reply pool
1580c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1581c9566231SKashyap Desai  * @qidx: request queue index
1582c9566231SKashyap Desai  *
1583c9566231SKashyap Desai  * Allocate segmented memory pools for operational reply
1584c9566231SKashyap Desai  * queue.
1585c9566231SKashyap Desai  *
1586c9566231SKashyap Desai  * Return: 0 on success, non-zero on failure.
1587c9566231SKashyap Desai  */
1588c9566231SKashyap Desai static int mpi3mr_alloc_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx)
1589c9566231SKashyap Desai {
1590c9566231SKashyap Desai 	struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
1591c9566231SKashyap Desai 	int i, size;
1592c9566231SKashyap Desai 	u64 *q_segment_list_entry = NULL;
1593c9566231SKashyap Desai 	struct segments *segments;
1594c9566231SKashyap Desai 
1595c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1596c9566231SKashyap Desai 		op_reply_q->segment_qd =
1597c9566231SKashyap Desai 		    MPI3MR_OP_REP_Q_SEG_SIZE / mrioc->op_reply_desc_sz;
1598c9566231SKashyap Desai 
1599c9566231SKashyap Desai 		size = MPI3MR_OP_REP_Q_SEG_SIZE;
1600c9566231SKashyap Desai 
1601c9566231SKashyap Desai 		op_reply_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev,
1602c9566231SKashyap Desai 		    MPI3MR_MAX_SEG_LIST_SIZE, &op_reply_q->q_segment_list_dma,
1603c9566231SKashyap Desai 		    GFP_KERNEL);
1604c9566231SKashyap Desai 		if (!op_reply_q->q_segment_list)
1605c9566231SKashyap Desai 			return -ENOMEM;
1606c9566231SKashyap Desai 		q_segment_list_entry = (u64 *)op_reply_q->q_segment_list;
1607c9566231SKashyap Desai 	} else {
1608c9566231SKashyap Desai 		op_reply_q->segment_qd = op_reply_q->num_replies;
1609c9566231SKashyap Desai 		size = op_reply_q->num_replies * mrioc->op_reply_desc_sz;
1610c9566231SKashyap Desai 	}
1611c9566231SKashyap Desai 
1612c9566231SKashyap Desai 	op_reply_q->num_segments = DIV_ROUND_UP(op_reply_q->num_replies,
1613c9566231SKashyap Desai 	    op_reply_q->segment_qd);
1614c9566231SKashyap Desai 
1615c9566231SKashyap Desai 	op_reply_q->q_segments = kcalloc(op_reply_q->num_segments,
1616c9566231SKashyap Desai 	    sizeof(struct segments), GFP_KERNEL);
1617c9566231SKashyap Desai 	if (!op_reply_q->q_segments)
1618c9566231SKashyap Desai 		return -ENOMEM;
1619c9566231SKashyap Desai 
1620c9566231SKashyap Desai 	segments = op_reply_q->q_segments;
1621c9566231SKashyap Desai 	for (i = 0; i < op_reply_q->num_segments; i++) {
1622c9566231SKashyap Desai 		segments[i].segment =
1623c9566231SKashyap Desai 		    dma_alloc_coherent(&mrioc->pdev->dev,
1624c9566231SKashyap Desai 		    size, &segments[i].segment_dma, GFP_KERNEL);
1625c9566231SKashyap Desai 		if (!segments[i].segment)
1626c9566231SKashyap Desai 			return -ENOMEM;
1627c9566231SKashyap Desai 		if (mrioc->enable_segqueue)
1628c9566231SKashyap Desai 			q_segment_list_entry[i] =
1629c9566231SKashyap Desai 			    (unsigned long)segments[i].segment_dma;
1630c9566231SKashyap Desai 	}
1631c9566231SKashyap Desai 
1632c9566231SKashyap Desai 	return 0;
1633c9566231SKashyap Desai }
1634c9566231SKashyap Desai 
1635c9566231SKashyap Desai /**
1636c9566231SKashyap Desai  * mpi3mr_alloc_op_req_q_segments - Alloc segmented req pool.
1637c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1638c9566231SKashyap Desai  * @qidx: request queue index
1639c9566231SKashyap Desai  *
1640c9566231SKashyap Desai  * Allocate segmented memory pools for operational request
1641c9566231SKashyap Desai  * queue.
1642c9566231SKashyap Desai  *
1643c9566231SKashyap Desai  * Return: 0 on success, non-zero on failure.
1644c9566231SKashyap Desai  */
1645c9566231SKashyap Desai static int mpi3mr_alloc_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx)
1646c9566231SKashyap Desai {
1647c9566231SKashyap Desai 	struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx;
1648c9566231SKashyap Desai 	int i, size;
1649c9566231SKashyap Desai 	u64 *q_segment_list_entry = NULL;
1650c9566231SKashyap Desai 	struct segments *segments;
1651c9566231SKashyap Desai 
1652c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1653c9566231SKashyap Desai 		op_req_q->segment_qd =
1654c9566231SKashyap Desai 		    MPI3MR_OP_REQ_Q_SEG_SIZE / mrioc->facts.op_req_sz;
1655c9566231SKashyap Desai 
1656c9566231SKashyap Desai 		size = MPI3MR_OP_REQ_Q_SEG_SIZE;
1657c9566231SKashyap Desai 
1658c9566231SKashyap Desai 		op_req_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev,
1659c9566231SKashyap Desai 		    MPI3MR_MAX_SEG_LIST_SIZE, &op_req_q->q_segment_list_dma,
1660c9566231SKashyap Desai 		    GFP_KERNEL);
1661c9566231SKashyap Desai 		if (!op_req_q->q_segment_list)
1662c9566231SKashyap Desai 			return -ENOMEM;
1663c9566231SKashyap Desai 		q_segment_list_entry = (u64 *)op_req_q->q_segment_list;
1664c9566231SKashyap Desai 
1665c9566231SKashyap Desai 	} else {
1666c9566231SKashyap Desai 		op_req_q->segment_qd = op_req_q->num_requests;
1667c9566231SKashyap Desai 		size = op_req_q->num_requests * mrioc->facts.op_req_sz;
1668c9566231SKashyap Desai 	}
1669c9566231SKashyap Desai 
1670c9566231SKashyap Desai 	op_req_q->num_segments = DIV_ROUND_UP(op_req_q->num_requests,
1671c9566231SKashyap Desai 	    op_req_q->segment_qd);
1672c9566231SKashyap Desai 
1673c9566231SKashyap Desai 	op_req_q->q_segments = kcalloc(op_req_q->num_segments,
1674c9566231SKashyap Desai 	    sizeof(struct segments), GFP_KERNEL);
1675c9566231SKashyap Desai 	if (!op_req_q->q_segments)
1676c9566231SKashyap Desai 		return -ENOMEM;
1677c9566231SKashyap Desai 
1678c9566231SKashyap Desai 	segments = op_req_q->q_segments;
1679c9566231SKashyap Desai 	for (i = 0; i < op_req_q->num_segments; i++) {
1680c9566231SKashyap Desai 		segments[i].segment =
1681c9566231SKashyap Desai 		    dma_alloc_coherent(&mrioc->pdev->dev,
1682c9566231SKashyap Desai 		    size, &segments[i].segment_dma, GFP_KERNEL);
1683c9566231SKashyap Desai 		if (!segments[i].segment)
1684c9566231SKashyap Desai 			return -ENOMEM;
1685c9566231SKashyap Desai 		if (mrioc->enable_segqueue)
1686c9566231SKashyap Desai 			q_segment_list_entry[i] =
1687c9566231SKashyap Desai 			    (unsigned long)segments[i].segment_dma;
1688c9566231SKashyap Desai 	}
1689c9566231SKashyap Desai 
1690c9566231SKashyap Desai 	return 0;
1691c9566231SKashyap Desai }
1692c9566231SKashyap Desai 
1693c9566231SKashyap Desai /**
1694c9566231SKashyap Desai  * mpi3mr_create_op_reply_q - create operational reply queue
1695c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1696c9566231SKashyap Desai  * @qidx: operational reply queue index
1697c9566231SKashyap Desai  *
1698c9566231SKashyap Desai  * Create operatinal reply queue by issuing MPI request
1699c9566231SKashyap Desai  * through admin queue.
1700c9566231SKashyap Desai  *
1701c9566231SKashyap Desai  * Return:  0 on success, non-zero on failure.
1702c9566231SKashyap Desai  */
1703c9566231SKashyap Desai static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx)
1704c9566231SKashyap Desai {
1705c9566231SKashyap Desai 	struct mpi3_create_reply_queue_request create_req;
1706c9566231SKashyap Desai 	struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
1707c9566231SKashyap Desai 	int retval = 0;
1708c9566231SKashyap Desai 	u16 reply_qid = 0, midx;
1709c9566231SKashyap Desai 
1710c9566231SKashyap Desai 	reply_qid = op_reply_q->qid;
1711c9566231SKashyap Desai 
1712c9566231SKashyap Desai 	midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset);
1713c9566231SKashyap Desai 
1714c9566231SKashyap Desai 	if (reply_qid) {
1715c9566231SKashyap Desai 		retval = -1;
1716c9566231SKashyap Desai 		ioc_err(mrioc, "CreateRepQ: called for duplicate qid %d\n",
1717c9566231SKashyap Desai 		    reply_qid);
1718c9566231SKashyap Desai 
1719c9566231SKashyap Desai 		return retval;
1720c9566231SKashyap Desai 	}
1721c9566231SKashyap Desai 
1722c9566231SKashyap Desai 	reply_qid = qidx + 1;
1723c9566231SKashyap Desai 	op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD;
1724c9566231SKashyap Desai 	op_reply_q->ci = 0;
1725c9566231SKashyap Desai 	op_reply_q->ephase = 1;
1726463429f8SKashyap Desai 	atomic_set(&op_reply_q->pend_ios, 0);
1727463429f8SKashyap Desai 	atomic_set(&op_reply_q->in_use, 0);
1728463429f8SKashyap Desai 	op_reply_q->enable_irq_poll = false;
1729c9566231SKashyap Desai 
1730c9566231SKashyap Desai 	if (!op_reply_q->q_segments) {
1731c9566231SKashyap Desai 		retval = mpi3mr_alloc_op_reply_q_segments(mrioc, qidx);
1732c9566231SKashyap Desai 		if (retval) {
1733c9566231SKashyap Desai 			mpi3mr_free_op_reply_q_segments(mrioc, qidx);
1734c9566231SKashyap Desai 			goto out;
1735c9566231SKashyap Desai 		}
1736c9566231SKashyap Desai 	}
1737c9566231SKashyap Desai 
1738c9566231SKashyap Desai 	memset(&create_req, 0, sizeof(create_req));
1739c9566231SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
1740c9566231SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
1741c9566231SKashyap Desai 		retval = -1;
1742c9566231SKashyap Desai 		ioc_err(mrioc, "CreateRepQ: Init command is in use\n");
1743f9dc034dSYang Yingliang 		goto out_unlock;
1744c9566231SKashyap Desai 	}
1745c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
1746c9566231SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
1747c9566231SKashyap Desai 	mrioc->init_cmds.callback = NULL;
1748c9566231SKashyap Desai 	create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
1749c9566231SKashyap Desai 	create_req.function = MPI3_FUNCTION_CREATE_REPLY_QUEUE;
1750c9566231SKashyap Desai 	create_req.queue_id = cpu_to_le16(reply_qid);
1751c9566231SKashyap Desai 	create_req.flags = MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_ENABLE;
1752c9566231SKashyap Desai 	create_req.msix_index = cpu_to_le16(mrioc->intr_info[midx].msix_index);
1753c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1754c9566231SKashyap Desai 		create_req.flags |=
1755c9566231SKashyap Desai 		    MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED;
1756c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
1757c9566231SKashyap Desai 		    op_reply_q->q_segment_list_dma);
1758c9566231SKashyap Desai 	} else
1759c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
1760c9566231SKashyap Desai 		    op_reply_q->q_segments[0].segment_dma);
1761c9566231SKashyap Desai 
1762c9566231SKashyap Desai 	create_req.size = cpu_to_le16(op_reply_q->num_replies);
1763c9566231SKashyap Desai 
1764c9566231SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
1765c9566231SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &create_req,
1766c9566231SKashyap Desai 	    sizeof(create_req), 1);
1767c9566231SKashyap Desai 	if (retval) {
1768c9566231SKashyap Desai 		ioc_err(mrioc, "CreateRepQ: Admin Post failed\n");
1769c9566231SKashyap Desai 		goto out_unlock;
1770c9566231SKashyap Desai 	}
1771c9566231SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
1772c9566231SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
1773c9566231SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
1774a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "create reply queue timed out\n");
1775a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
1776c9566231SKashyap Desai 		    MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT);
1777c9566231SKashyap Desai 		retval = -1;
1778c9566231SKashyap Desai 		goto out_unlock;
1779c9566231SKashyap Desai 	}
1780c9566231SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
1781c9566231SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
1782c9566231SKashyap Desai 		ioc_err(mrioc,
1783c9566231SKashyap Desai 		    "CreateRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
1784c9566231SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
1785c9566231SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
1786c9566231SKashyap Desai 		retval = -1;
1787c9566231SKashyap Desai 		goto out_unlock;
1788c9566231SKashyap Desai 	}
1789c9566231SKashyap Desai 	op_reply_q->qid = reply_qid;
1790fe6db615SSreekanth Reddy 	if (midx < mrioc->intr_info_count)
1791c9566231SKashyap Desai 		mrioc->intr_info[midx].op_reply_q = op_reply_q;
1792c9566231SKashyap Desai 
1793c9566231SKashyap Desai out_unlock:
1794c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
1795c9566231SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
1796c9566231SKashyap Desai out:
1797c9566231SKashyap Desai 
1798c9566231SKashyap Desai 	return retval;
1799c9566231SKashyap Desai }
1800c9566231SKashyap Desai 
1801c9566231SKashyap Desai /**
1802c9566231SKashyap Desai  * mpi3mr_create_op_req_q - create operational request queue
1803c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1804c9566231SKashyap Desai  * @idx: operational request queue index
1805c9566231SKashyap Desai  * @reply_qid: Reply queue ID
1806c9566231SKashyap Desai  *
1807c9566231SKashyap Desai  * Create operatinal request queue by issuing MPI request
1808c9566231SKashyap Desai  * through admin queue.
1809c9566231SKashyap Desai  *
1810c9566231SKashyap Desai  * Return:  0 on success, non-zero on failure.
1811c9566231SKashyap Desai  */
1812c9566231SKashyap Desai static int mpi3mr_create_op_req_q(struct mpi3mr_ioc *mrioc, u16 idx,
1813c9566231SKashyap Desai 	u16 reply_qid)
1814c9566231SKashyap Desai {
1815c9566231SKashyap Desai 	struct mpi3_create_request_queue_request create_req;
1816c9566231SKashyap Desai 	struct op_req_qinfo *op_req_q = mrioc->req_qinfo + idx;
1817c9566231SKashyap Desai 	int retval = 0;
1818c9566231SKashyap Desai 	u16 req_qid = 0;
1819c9566231SKashyap Desai 
1820c9566231SKashyap Desai 	req_qid = op_req_q->qid;
1821c9566231SKashyap Desai 
1822c9566231SKashyap Desai 	if (req_qid) {
1823c9566231SKashyap Desai 		retval = -1;
1824c9566231SKashyap Desai 		ioc_err(mrioc, "CreateReqQ: called for duplicate qid %d\n",
1825c9566231SKashyap Desai 		    req_qid);
1826c9566231SKashyap Desai 
1827c9566231SKashyap Desai 		return retval;
1828c9566231SKashyap Desai 	}
1829c9566231SKashyap Desai 	req_qid = idx + 1;
1830c9566231SKashyap Desai 
1831c9566231SKashyap Desai 	op_req_q->num_requests = MPI3MR_OP_REQ_Q_QD;
1832c9566231SKashyap Desai 	op_req_q->ci = 0;
1833c9566231SKashyap Desai 	op_req_q->pi = 0;
1834c9566231SKashyap Desai 	op_req_q->reply_qid = reply_qid;
1835c9566231SKashyap Desai 	spin_lock_init(&op_req_q->q_lock);
1836c9566231SKashyap Desai 
1837c9566231SKashyap Desai 	if (!op_req_q->q_segments) {
1838c9566231SKashyap Desai 		retval = mpi3mr_alloc_op_req_q_segments(mrioc, idx);
1839c9566231SKashyap Desai 		if (retval) {
1840c9566231SKashyap Desai 			mpi3mr_free_op_req_q_segments(mrioc, idx);
1841c9566231SKashyap Desai 			goto out;
1842c9566231SKashyap Desai 		}
1843c9566231SKashyap Desai 	}
1844c9566231SKashyap Desai 
1845c9566231SKashyap Desai 	memset(&create_req, 0, sizeof(create_req));
1846c9566231SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
1847c9566231SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
1848c9566231SKashyap Desai 		retval = -1;
1849c9566231SKashyap Desai 		ioc_err(mrioc, "CreateReqQ: Init command is in use\n");
1850f9dc034dSYang Yingliang 		goto out_unlock;
1851c9566231SKashyap Desai 	}
1852c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
1853c9566231SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
1854c9566231SKashyap Desai 	mrioc->init_cmds.callback = NULL;
1855c9566231SKashyap Desai 	create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
1856c9566231SKashyap Desai 	create_req.function = MPI3_FUNCTION_CREATE_REQUEST_QUEUE;
1857c9566231SKashyap Desai 	create_req.queue_id = cpu_to_le16(req_qid);
1858c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1859c9566231SKashyap Desai 		create_req.flags =
1860c9566231SKashyap Desai 		    MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED;
1861c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
1862c9566231SKashyap Desai 		    op_req_q->q_segment_list_dma);
1863c9566231SKashyap Desai 	} else
1864c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
1865c9566231SKashyap Desai 		    op_req_q->q_segments[0].segment_dma);
1866c9566231SKashyap Desai 	create_req.reply_queue_id = cpu_to_le16(reply_qid);
1867c9566231SKashyap Desai 	create_req.size = cpu_to_le16(op_req_q->num_requests);
1868c9566231SKashyap Desai 
1869c9566231SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
1870c9566231SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &create_req,
1871c9566231SKashyap Desai 	    sizeof(create_req), 1);
1872c9566231SKashyap Desai 	if (retval) {
1873c9566231SKashyap Desai 		ioc_err(mrioc, "CreateReqQ: Admin Post failed\n");
1874c9566231SKashyap Desai 		goto out_unlock;
1875c9566231SKashyap Desai 	}
1876c9566231SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
1877c9566231SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
1878c9566231SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
1879a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "create request queue timed out\n");
1880a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
1881a6856cc4SSreekanth Reddy 		    MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT);
1882c9566231SKashyap Desai 		retval = -1;
1883c9566231SKashyap Desai 		goto out_unlock;
1884c9566231SKashyap Desai 	}
1885c9566231SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
1886c9566231SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
1887c9566231SKashyap Desai 		ioc_err(mrioc,
1888c9566231SKashyap Desai 		    "CreateReqQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
1889c9566231SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
1890c9566231SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
1891c9566231SKashyap Desai 		retval = -1;
1892c9566231SKashyap Desai 		goto out_unlock;
1893c9566231SKashyap Desai 	}
1894c9566231SKashyap Desai 	op_req_q->qid = req_qid;
1895c9566231SKashyap Desai 
1896c9566231SKashyap Desai out_unlock:
1897c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
1898c9566231SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
1899c9566231SKashyap Desai out:
1900c9566231SKashyap Desai 
1901c9566231SKashyap Desai 	return retval;
1902c9566231SKashyap Desai }
1903c9566231SKashyap Desai 
1904c9566231SKashyap Desai /**
1905c9566231SKashyap Desai  * mpi3mr_create_op_queues - create operational queue pairs
1906c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1907c9566231SKashyap Desai  *
1908c9566231SKashyap Desai  * Allocate memory for operational queue meta data and call
1909c9566231SKashyap Desai  * create request and reply queue functions.
1910c9566231SKashyap Desai  *
1911c9566231SKashyap Desai  * Return: 0 on success, non-zero on failures.
1912c9566231SKashyap Desai  */
1913c9566231SKashyap Desai static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc)
1914c9566231SKashyap Desai {
1915c9566231SKashyap Desai 	int retval = 0;
1916c9566231SKashyap Desai 	u16 num_queues = 0, i = 0, msix_count_op_q = 1;
1917c9566231SKashyap Desai 
1918c9566231SKashyap Desai 	num_queues = min_t(int, mrioc->facts.max_op_reply_q,
1919c9566231SKashyap Desai 	    mrioc->facts.max_op_req_q);
1920c9566231SKashyap Desai 
1921c9566231SKashyap Desai 	msix_count_op_q =
1922c9566231SKashyap Desai 	    mrioc->intr_info_count - mrioc->op_reply_q_offset;
1923c9566231SKashyap Desai 	if (!mrioc->num_queues)
1924c9566231SKashyap Desai 		mrioc->num_queues = min_t(int, num_queues, msix_count_op_q);
1925c5758fc7SSreekanth Reddy 	/*
1926c5758fc7SSreekanth Reddy 	 * During reset set the num_queues to the number of queues
1927c5758fc7SSreekanth Reddy 	 * that was set before the reset.
1928c5758fc7SSreekanth Reddy 	 */
1929c5758fc7SSreekanth Reddy 	num_queues = mrioc->num_op_reply_q ?
1930c5758fc7SSreekanth Reddy 	    mrioc->num_op_reply_q : mrioc->num_queues;
1931c5758fc7SSreekanth Reddy 	ioc_info(mrioc, "trying to create %d operational queue pairs\n",
1932c9566231SKashyap Desai 	    num_queues);
1933c9566231SKashyap Desai 
1934c9566231SKashyap Desai 	if (!mrioc->req_qinfo) {
1935c9566231SKashyap Desai 		mrioc->req_qinfo = kcalloc(num_queues,
1936c9566231SKashyap Desai 		    sizeof(struct op_req_qinfo), GFP_KERNEL);
1937c9566231SKashyap Desai 		if (!mrioc->req_qinfo) {
1938c9566231SKashyap Desai 			retval = -1;
1939c9566231SKashyap Desai 			goto out_failed;
1940c9566231SKashyap Desai 		}
1941c9566231SKashyap Desai 
1942c9566231SKashyap Desai 		mrioc->op_reply_qinfo = kzalloc(sizeof(struct op_reply_qinfo) *
1943c9566231SKashyap Desai 		    num_queues, GFP_KERNEL);
1944c9566231SKashyap Desai 		if (!mrioc->op_reply_qinfo) {
1945c9566231SKashyap Desai 			retval = -1;
1946c9566231SKashyap Desai 			goto out_failed;
1947c9566231SKashyap Desai 		}
1948c9566231SKashyap Desai 	}
1949c9566231SKashyap Desai 
1950c9566231SKashyap Desai 	if (mrioc->enable_segqueue)
1951c9566231SKashyap Desai 		ioc_info(mrioc,
1952c9566231SKashyap Desai 		    "allocating operational queues through segmented queues\n");
1953c9566231SKashyap Desai 
1954c9566231SKashyap Desai 	for (i = 0; i < num_queues; i++) {
1955c9566231SKashyap Desai 		if (mpi3mr_create_op_reply_q(mrioc, i)) {
1956c9566231SKashyap Desai 			ioc_err(mrioc, "Cannot create OP RepQ %d\n", i);
1957c9566231SKashyap Desai 			break;
1958c9566231SKashyap Desai 		}
1959c9566231SKashyap Desai 		if (mpi3mr_create_op_req_q(mrioc, i,
1960c9566231SKashyap Desai 		    mrioc->op_reply_qinfo[i].qid)) {
1961c9566231SKashyap Desai 			ioc_err(mrioc, "Cannot create OP ReqQ %d\n", i);
1962c9566231SKashyap Desai 			mpi3mr_delete_op_reply_q(mrioc, i);
1963c9566231SKashyap Desai 			break;
1964c9566231SKashyap Desai 		}
1965c9566231SKashyap Desai 	}
1966c9566231SKashyap Desai 
1967c9566231SKashyap Desai 	if (i == 0) {
1968c9566231SKashyap Desai 		/* Not even one queue is created successfully*/
1969c9566231SKashyap Desai 		retval = -1;
1970c9566231SKashyap Desai 		goto out_failed;
1971c9566231SKashyap Desai 	}
1972c9566231SKashyap Desai 	mrioc->num_op_reply_q = mrioc->num_op_req_q = i;
1973c9566231SKashyap Desai 	ioc_info(mrioc, "Successfully created %d Operational Q pairs\n",
1974c9566231SKashyap Desai 	    mrioc->num_op_reply_q);
1975c9566231SKashyap Desai 
1976c9566231SKashyap Desai 	return retval;
1977c9566231SKashyap Desai out_failed:
1978c9566231SKashyap Desai 	kfree(mrioc->req_qinfo);
1979c9566231SKashyap Desai 	mrioc->req_qinfo = NULL;
1980c9566231SKashyap Desai 
1981c9566231SKashyap Desai 	kfree(mrioc->op_reply_qinfo);
1982c9566231SKashyap Desai 	mrioc->op_reply_qinfo = NULL;
1983c9566231SKashyap Desai 
1984c9566231SKashyap Desai 	return retval;
1985c9566231SKashyap Desai }
1986c9566231SKashyap Desai 
1987c9566231SKashyap Desai /**
1988023ab2a9SKashyap Desai  * mpi3mr_op_request_post - Post request to operational queue
1989023ab2a9SKashyap Desai  * @mrioc: Adapter reference
1990023ab2a9SKashyap Desai  * @op_req_q: Operational request queue info
1991023ab2a9SKashyap Desai  * @req: MPI3 request
1992023ab2a9SKashyap Desai  *
1993023ab2a9SKashyap Desai  * Post the MPI3 request into operational request queue and
1994023ab2a9SKashyap Desai  * inform the controller, if the queue is full return
1995023ab2a9SKashyap Desai  * appropriate error.
1996023ab2a9SKashyap Desai  *
1997023ab2a9SKashyap Desai  * Return: 0 on success, non-zero on failure.
1998023ab2a9SKashyap Desai  */
1999023ab2a9SKashyap Desai int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc,
2000023ab2a9SKashyap Desai 	struct op_req_qinfo *op_req_q, u8 *req)
2001023ab2a9SKashyap Desai {
2002023ab2a9SKashyap Desai 	u16 pi = 0, max_entries, reply_qidx = 0, midx;
2003023ab2a9SKashyap Desai 	int retval = 0;
2004023ab2a9SKashyap Desai 	unsigned long flags;
2005023ab2a9SKashyap Desai 	u8 *req_entry;
2006023ab2a9SKashyap Desai 	void *segment_base_addr;
2007023ab2a9SKashyap Desai 	u16 req_sz = mrioc->facts.op_req_sz;
2008023ab2a9SKashyap Desai 	struct segments *segments = op_req_q->q_segments;
2009023ab2a9SKashyap Desai 
2010023ab2a9SKashyap Desai 	reply_qidx = op_req_q->reply_qid - 1;
2011023ab2a9SKashyap Desai 
2012023ab2a9SKashyap Desai 	if (mrioc->unrecoverable)
2013023ab2a9SKashyap Desai 		return -EFAULT;
2014023ab2a9SKashyap Desai 
2015023ab2a9SKashyap Desai 	spin_lock_irqsave(&op_req_q->q_lock, flags);
2016023ab2a9SKashyap Desai 	pi = op_req_q->pi;
2017023ab2a9SKashyap Desai 	max_entries = op_req_q->num_requests;
2018023ab2a9SKashyap Desai 
2019023ab2a9SKashyap Desai 	if (mpi3mr_check_req_qfull(op_req_q)) {
2020023ab2a9SKashyap Desai 		midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(
2021023ab2a9SKashyap Desai 		    reply_qidx, mrioc->op_reply_q_offset);
2022023ab2a9SKashyap Desai 		mpi3mr_process_op_reply_q(mrioc, &mrioc->intr_info[midx]);
2023023ab2a9SKashyap Desai 
2024023ab2a9SKashyap Desai 		if (mpi3mr_check_req_qfull(op_req_q)) {
2025023ab2a9SKashyap Desai 			retval = -EAGAIN;
2026023ab2a9SKashyap Desai 			goto out;
2027023ab2a9SKashyap Desai 		}
2028023ab2a9SKashyap Desai 	}
2029023ab2a9SKashyap Desai 
2030023ab2a9SKashyap Desai 	if (mrioc->reset_in_progress) {
2031023ab2a9SKashyap Desai 		ioc_err(mrioc, "OpReqQ submit reset in progress\n");
2032023ab2a9SKashyap Desai 		retval = -EAGAIN;
2033023ab2a9SKashyap Desai 		goto out;
2034023ab2a9SKashyap Desai 	}
2035023ab2a9SKashyap Desai 
2036023ab2a9SKashyap Desai 	segment_base_addr = segments[pi / op_req_q->segment_qd].segment;
2037023ab2a9SKashyap Desai 	req_entry = (u8 *)segment_base_addr +
2038023ab2a9SKashyap Desai 	    ((pi % op_req_q->segment_qd) * req_sz);
2039023ab2a9SKashyap Desai 
2040023ab2a9SKashyap Desai 	memset(req_entry, 0, req_sz);
2041023ab2a9SKashyap Desai 	memcpy(req_entry, req, MPI3MR_ADMIN_REQ_FRAME_SZ);
2042023ab2a9SKashyap Desai 
2043023ab2a9SKashyap Desai 	if (++pi == max_entries)
2044023ab2a9SKashyap Desai 		pi = 0;
2045023ab2a9SKashyap Desai 	op_req_q->pi = pi;
2046023ab2a9SKashyap Desai 
2047463429f8SKashyap Desai 	if (atomic_inc_return(&mrioc->op_reply_qinfo[reply_qidx].pend_ios)
2048463429f8SKashyap Desai 	    > MPI3MR_IRQ_POLL_TRIGGER_IOCOUNT)
2049463429f8SKashyap Desai 		mrioc->op_reply_qinfo[reply_qidx].enable_irq_poll = true;
2050463429f8SKashyap Desai 
2051023ab2a9SKashyap Desai 	writel(op_req_q->pi,
2052023ab2a9SKashyap Desai 	    &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].producer_index);
2053023ab2a9SKashyap Desai 
2054023ab2a9SKashyap Desai out:
2055023ab2a9SKashyap Desai 	spin_unlock_irqrestore(&op_req_q->q_lock, flags);
2056023ab2a9SKashyap Desai 	return retval;
2057023ab2a9SKashyap Desai }
2058023ab2a9SKashyap Desai 
2059023ab2a9SKashyap Desai /**
2060a6856cc4SSreekanth Reddy  * mpi3mr_check_rh_fault_ioc - check reset history and fault
2061a6856cc4SSreekanth Reddy  * controller
2062a6856cc4SSreekanth Reddy  * @mrioc: Adapter instance reference
2063a6856cc4SSreekanth Reddy  * @reason_code, reason code for the fault.
2064a6856cc4SSreekanth Reddy  *
2065a6856cc4SSreekanth Reddy  * This routine will save snapdump and fault the controller with
2066a6856cc4SSreekanth Reddy  * the given reason code if it is not already in the fault or
2067a6856cc4SSreekanth Reddy  * not asynchronosuly reset. This will be used to handle
2068a6856cc4SSreekanth Reddy  * initilaization time faults/resets/timeout as in those cases
2069a6856cc4SSreekanth Reddy  * immediate soft reset invocation is not required.
2070a6856cc4SSreekanth Reddy  *
2071a6856cc4SSreekanth Reddy  * Return:  None.
2072a6856cc4SSreekanth Reddy  */
2073a6856cc4SSreekanth Reddy void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code)
2074a6856cc4SSreekanth Reddy {
2075a6856cc4SSreekanth Reddy 	u32 ioc_status, host_diagnostic, timeout;
2076a6856cc4SSreekanth Reddy 
2077a6856cc4SSreekanth Reddy 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
2078a6856cc4SSreekanth Reddy 	if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) ||
2079a6856cc4SSreekanth Reddy 	    (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) {
2080a6856cc4SSreekanth Reddy 		mpi3mr_print_fault_info(mrioc);
2081a6856cc4SSreekanth Reddy 		return;
2082a6856cc4SSreekanth Reddy 	}
2083a6856cc4SSreekanth Reddy 	mpi3mr_set_diagsave(mrioc);
2084a6856cc4SSreekanth Reddy 	mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
2085a6856cc4SSreekanth Reddy 	    reason_code);
2086a6856cc4SSreekanth Reddy 	timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10;
2087a6856cc4SSreekanth Reddy 	do {
2088a6856cc4SSreekanth Reddy 		host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic);
2089a6856cc4SSreekanth Reddy 		if (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS))
2090a6856cc4SSreekanth Reddy 			break;
2091a6856cc4SSreekanth Reddy 		msleep(100);
2092a6856cc4SSreekanth Reddy 	} while (--timeout);
2093a6856cc4SSreekanth Reddy }
2094a6856cc4SSreekanth Reddy 
2095a6856cc4SSreekanth Reddy /**
209654dfcffbSKashyap Desai  * mpi3mr_sync_timestamp - Issue time stamp sync request
209754dfcffbSKashyap Desai  * @mrioc: Adapter reference
209854dfcffbSKashyap Desai  *
209954dfcffbSKashyap Desai  * Issue IO unit control MPI request to synchornize firmware
210054dfcffbSKashyap Desai  * timestamp with host time.
210154dfcffbSKashyap Desai  *
210254dfcffbSKashyap Desai  * Return: 0 on success, non-zero on failure.
210354dfcffbSKashyap Desai  */
210454dfcffbSKashyap Desai static int mpi3mr_sync_timestamp(struct mpi3mr_ioc *mrioc)
210554dfcffbSKashyap Desai {
210654dfcffbSKashyap Desai 	ktime_t current_time;
210754dfcffbSKashyap Desai 	struct mpi3_iounit_control_request iou_ctrl;
210854dfcffbSKashyap Desai 	int retval = 0;
210954dfcffbSKashyap Desai 
211054dfcffbSKashyap Desai 	memset(&iou_ctrl, 0, sizeof(iou_ctrl));
211154dfcffbSKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
211254dfcffbSKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
211354dfcffbSKashyap Desai 		retval = -1;
211454dfcffbSKashyap Desai 		ioc_err(mrioc, "Issue IOUCTL time_stamp: command is in use\n");
211554dfcffbSKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
211654dfcffbSKashyap Desai 		goto out;
211754dfcffbSKashyap Desai 	}
211854dfcffbSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
211954dfcffbSKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
212054dfcffbSKashyap Desai 	mrioc->init_cmds.callback = NULL;
212154dfcffbSKashyap Desai 	iou_ctrl.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
212254dfcffbSKashyap Desai 	iou_ctrl.function = MPI3_FUNCTION_IO_UNIT_CONTROL;
212354dfcffbSKashyap Desai 	iou_ctrl.operation = MPI3_CTRL_OP_UPDATE_TIMESTAMP;
212454dfcffbSKashyap Desai 	current_time = ktime_get_real();
212554dfcffbSKashyap Desai 	iou_ctrl.param64[0] = cpu_to_le64(ktime_to_ms(current_time));
212654dfcffbSKashyap Desai 
212754dfcffbSKashyap Desai 	init_completion(&mrioc->init_cmds.done);
212854dfcffbSKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &iou_ctrl,
212954dfcffbSKashyap Desai 	    sizeof(iou_ctrl), 0);
213054dfcffbSKashyap Desai 	if (retval) {
213154dfcffbSKashyap Desai 		ioc_err(mrioc, "Issue IOUCTL time_stamp: Admin Post failed\n");
213254dfcffbSKashyap Desai 		goto out_unlock;
213354dfcffbSKashyap Desai 	}
213454dfcffbSKashyap Desai 
213554dfcffbSKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
213654dfcffbSKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
213754dfcffbSKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
213854dfcffbSKashyap Desai 		ioc_err(mrioc, "Issue IOUCTL time_stamp: command timed out\n");
213954dfcffbSKashyap Desai 		mrioc->init_cmds.is_waiting = 0;
2140fbaa9aa4SSreekanth Reddy 		if (!(mrioc->init_cmds.state & MPI3MR_CMD_RESET))
214154dfcffbSKashyap Desai 			mpi3mr_soft_reset_handler(mrioc,
214254dfcffbSKashyap Desai 			    MPI3MR_RESET_FROM_TSU_TIMEOUT, 1);
214354dfcffbSKashyap Desai 		retval = -1;
214454dfcffbSKashyap Desai 		goto out_unlock;
214554dfcffbSKashyap Desai 	}
214654dfcffbSKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
214754dfcffbSKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
214854dfcffbSKashyap Desai 		ioc_err(mrioc,
214954dfcffbSKashyap Desai 		    "Issue IOUCTL time_stamp: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
215054dfcffbSKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
215154dfcffbSKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
215254dfcffbSKashyap Desai 		retval = -1;
215354dfcffbSKashyap Desai 		goto out_unlock;
215454dfcffbSKashyap Desai 	}
215554dfcffbSKashyap Desai 
215654dfcffbSKashyap Desai out_unlock:
215754dfcffbSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
215854dfcffbSKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
215954dfcffbSKashyap Desai 
216054dfcffbSKashyap Desai out:
216154dfcffbSKashyap Desai 	return retval;
216254dfcffbSKashyap Desai }
216354dfcffbSKashyap Desai 
216454dfcffbSKashyap Desai /**
21652ac794baSSreekanth Reddy  * mpi3mr_print_pkg_ver - display controller fw package version
21662ac794baSSreekanth Reddy  * @mrioc: Adapter reference
21672ac794baSSreekanth Reddy  *
21682ac794baSSreekanth Reddy  * Retrieve firmware package version from the component image
21692ac794baSSreekanth Reddy  * header of the controller flash and display it.
21702ac794baSSreekanth Reddy  *
21712ac794baSSreekanth Reddy  * Return: 0 on success and non-zero on failure.
21722ac794baSSreekanth Reddy  */
21732ac794baSSreekanth Reddy static int mpi3mr_print_pkg_ver(struct mpi3mr_ioc *mrioc)
21742ac794baSSreekanth Reddy {
21752ac794baSSreekanth Reddy 	struct mpi3_ci_upload_request ci_upload;
21762ac794baSSreekanth Reddy 	int retval = -1;
21772ac794baSSreekanth Reddy 	void *data = NULL;
21782ac794baSSreekanth Reddy 	dma_addr_t data_dma;
21792ac794baSSreekanth Reddy 	struct mpi3_ci_manifest_mpi *manifest;
21802ac794baSSreekanth Reddy 	u32 data_len = sizeof(struct mpi3_ci_manifest_mpi);
21812ac794baSSreekanth Reddy 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
21822ac794baSSreekanth Reddy 
21832ac794baSSreekanth Reddy 	data = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma,
21842ac794baSSreekanth Reddy 	    GFP_KERNEL);
21852ac794baSSreekanth Reddy 	if (!data)
21862ac794baSSreekanth Reddy 		return -ENOMEM;
21872ac794baSSreekanth Reddy 
21882ac794baSSreekanth Reddy 	memset(&ci_upload, 0, sizeof(ci_upload));
21892ac794baSSreekanth Reddy 	mutex_lock(&mrioc->init_cmds.mutex);
21902ac794baSSreekanth Reddy 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
21912ac794baSSreekanth Reddy 		ioc_err(mrioc, "sending get package version failed due to command in use\n");
21922ac794baSSreekanth Reddy 		mutex_unlock(&mrioc->init_cmds.mutex);
21932ac794baSSreekanth Reddy 		goto out;
21942ac794baSSreekanth Reddy 	}
21952ac794baSSreekanth Reddy 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
21962ac794baSSreekanth Reddy 	mrioc->init_cmds.is_waiting = 1;
21972ac794baSSreekanth Reddy 	mrioc->init_cmds.callback = NULL;
21982ac794baSSreekanth Reddy 	ci_upload.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
21992ac794baSSreekanth Reddy 	ci_upload.function = MPI3_FUNCTION_CI_UPLOAD;
22002ac794baSSreekanth Reddy 	ci_upload.msg_flags = MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_PRIMARY;
22012ac794baSSreekanth Reddy 	ci_upload.signature1 = cpu_to_le32(MPI3_IMAGE_HEADER_SIGNATURE1_MANIFEST);
22022ac794baSSreekanth Reddy 	ci_upload.image_offset = cpu_to_le32(MPI3_IMAGE_HEADER_SIZE);
22032ac794baSSreekanth Reddy 	ci_upload.segment_size = cpu_to_le32(data_len);
22042ac794baSSreekanth Reddy 
22052ac794baSSreekanth Reddy 	mpi3mr_add_sg_single(&ci_upload.sgl, sgl_flags, data_len,
22062ac794baSSreekanth Reddy 	    data_dma);
22072ac794baSSreekanth Reddy 	init_completion(&mrioc->init_cmds.done);
22082ac794baSSreekanth Reddy 	retval = mpi3mr_admin_request_post(mrioc, &ci_upload,
22092ac794baSSreekanth Reddy 	    sizeof(ci_upload), 1);
22102ac794baSSreekanth Reddy 	if (retval) {
22112ac794baSSreekanth Reddy 		ioc_err(mrioc, "posting get package version failed\n");
22122ac794baSSreekanth Reddy 		goto out_unlock;
22132ac794baSSreekanth Reddy 	}
22142ac794baSSreekanth Reddy 	wait_for_completion_timeout(&mrioc->init_cmds.done,
22152ac794baSSreekanth Reddy 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
22162ac794baSSreekanth Reddy 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
22172ac794baSSreekanth Reddy 		ioc_err(mrioc, "get package version timed out\n");
2218a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
2219a6856cc4SSreekanth Reddy 		    MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT);
22202ac794baSSreekanth Reddy 		retval = -1;
22212ac794baSSreekanth Reddy 		goto out_unlock;
22222ac794baSSreekanth Reddy 	}
22232ac794baSSreekanth Reddy 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
22242ac794baSSreekanth Reddy 	    == MPI3_IOCSTATUS_SUCCESS) {
22252ac794baSSreekanth Reddy 		manifest = (struct mpi3_ci_manifest_mpi *) data;
22262ac794baSSreekanth Reddy 		if (manifest->manifest_type == MPI3_CI_MANIFEST_TYPE_MPI) {
22272ac794baSSreekanth Reddy 			ioc_info(mrioc,
22282ac794baSSreekanth Reddy 			    "firmware package version(%d.%d.%d.%d.%05d-%05d)\n",
22292ac794baSSreekanth Reddy 			    manifest->package_version.gen_major,
22302ac794baSSreekanth Reddy 			    manifest->package_version.gen_minor,
22312ac794baSSreekanth Reddy 			    manifest->package_version.phase_major,
22322ac794baSSreekanth Reddy 			    manifest->package_version.phase_minor,
22332ac794baSSreekanth Reddy 			    manifest->package_version.customer_id,
22342ac794baSSreekanth Reddy 			    manifest->package_version.build_num);
22352ac794baSSreekanth Reddy 		}
22362ac794baSSreekanth Reddy 	}
22372ac794baSSreekanth Reddy 	retval = 0;
22382ac794baSSreekanth Reddy out_unlock:
22392ac794baSSreekanth Reddy 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
22402ac794baSSreekanth Reddy 	mutex_unlock(&mrioc->init_cmds.mutex);
22412ac794baSSreekanth Reddy 
22422ac794baSSreekanth Reddy out:
22432ac794baSSreekanth Reddy 	if (data)
22442ac794baSSreekanth Reddy 		dma_free_coherent(&mrioc->pdev->dev, data_len, data,
22452ac794baSSreekanth Reddy 		    data_dma);
22462ac794baSSreekanth Reddy 	return retval;
22472ac794baSSreekanth Reddy }
22482ac794baSSreekanth Reddy 
22492ac794baSSreekanth Reddy /**
2250672ae26cSKashyap Desai  * mpi3mr_watchdog_work - watchdog thread to monitor faults
2251672ae26cSKashyap Desai  * @work: work struct
2252672ae26cSKashyap Desai  *
2253672ae26cSKashyap Desai  * Watch dog work periodically executed (1 second interval) to
2254672ae26cSKashyap Desai  * monitor firmware fault and to issue periodic timer sync to
2255672ae26cSKashyap Desai  * the firmware.
2256672ae26cSKashyap Desai  *
2257672ae26cSKashyap Desai  * Return: Nothing.
2258672ae26cSKashyap Desai  */
2259672ae26cSKashyap Desai static void mpi3mr_watchdog_work(struct work_struct *work)
2260672ae26cSKashyap Desai {
2261672ae26cSKashyap Desai 	struct mpi3mr_ioc *mrioc =
2262672ae26cSKashyap Desai 	    container_of(work, struct mpi3mr_ioc, watchdog_work.work);
2263672ae26cSKashyap Desai 	unsigned long flags;
2264672ae26cSKashyap Desai 	enum mpi3mr_iocstate ioc_state;
2265*78b76a07SSreekanth Reddy 	u32 fault, host_diagnostic, ioc_status;
2266*78b76a07SSreekanth Reddy 	u32 reset_reason = MPI3MR_RESET_FROM_FAULT_WATCH;
2267672ae26cSKashyap Desai 
2268b64845a7SSreekanth Reddy 	if (mrioc->reset_in_progress || mrioc->unrecoverable)
2269b64845a7SSreekanth Reddy 		return;
2270b64845a7SSreekanth Reddy 
227154dfcffbSKashyap Desai 	if (mrioc->ts_update_counter++ >= MPI3MR_TSUPDATE_INTERVAL) {
227254dfcffbSKashyap Desai 		mrioc->ts_update_counter = 0;
227354dfcffbSKashyap Desai 		mpi3mr_sync_timestamp(mrioc);
227454dfcffbSKashyap Desai 	}
227554dfcffbSKashyap Desai 
2276*78b76a07SSreekanth Reddy 	if ((mrioc->prepare_for_reset) &&
2277*78b76a07SSreekanth Reddy 	    ((mrioc->prepare_for_reset_timeout_counter++) >=
2278*78b76a07SSreekanth Reddy 	     MPI3MR_PREPARE_FOR_RESET_TIMEOUT)) {
2279*78b76a07SSreekanth Reddy 		mpi3mr_soft_reset_handler(mrioc,
2280*78b76a07SSreekanth Reddy 		    MPI3MR_RESET_FROM_CIACTVRST_TIMER, 1);
2281*78b76a07SSreekanth Reddy 		return;
2282*78b76a07SSreekanth Reddy 	}
2283*78b76a07SSreekanth Reddy 
2284*78b76a07SSreekanth Reddy 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
2285*78b76a07SSreekanth Reddy 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) {
2286*78b76a07SSreekanth Reddy 		mpi3mr_soft_reset_handler(mrioc, MPI3MR_RESET_FROM_FIRMWARE, 0);
2287*78b76a07SSreekanth Reddy 		return;
2288*78b76a07SSreekanth Reddy 	}
2289*78b76a07SSreekanth Reddy 
2290672ae26cSKashyap Desai 	/*Check for fault state every one second and issue Soft reset*/
2291672ae26cSKashyap Desai 	ioc_state = mpi3mr_get_iocstate(mrioc);
2292*78b76a07SSreekanth Reddy 	if (ioc_state != MRIOC_STATE_FAULT)
2293*78b76a07SSreekanth Reddy 		goto schedule_work;
2294*78b76a07SSreekanth Reddy 
2295*78b76a07SSreekanth Reddy 	fault = readl(&mrioc->sysif_regs->fault) & MPI3_SYSIF_FAULT_CODE_MASK;
2296672ae26cSKashyap Desai 	host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic);
2297672ae26cSKashyap Desai 	if (host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS) {
2298672ae26cSKashyap Desai 		if (!mrioc->diagsave_timeout) {
2299672ae26cSKashyap Desai 			mpi3mr_print_fault_info(mrioc);
2300*78b76a07SSreekanth Reddy 			ioc_warn(mrioc, "diag save in progress\n");
2301672ae26cSKashyap Desai 		}
2302*78b76a07SSreekanth Reddy 		if ((mrioc->diagsave_timeout++) <= MPI3_SYSIF_DIAG_SAVE_TIMEOUT)
2303672ae26cSKashyap Desai 			goto schedule_work;
2304*78b76a07SSreekanth Reddy 	}
2305*78b76a07SSreekanth Reddy 
2306672ae26cSKashyap Desai 	mpi3mr_print_fault_info(mrioc);
2307672ae26cSKashyap Desai 	mrioc->diagsave_timeout = 0;
2308672ae26cSKashyap Desai 
2309*78b76a07SSreekanth Reddy 	switch (fault) {
2310*78b76a07SSreekanth Reddy 	case MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED:
2311672ae26cSKashyap Desai 		ioc_info(mrioc,
2312*78b76a07SSreekanth Reddy 		    "controller requires system power cycle, marking controller as unrecoverable\n");
2313672ae26cSKashyap Desai 		mrioc->unrecoverable = 1;
2314*78b76a07SSreekanth Reddy 		return;
2315*78b76a07SSreekanth Reddy 	case MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS:
2316*78b76a07SSreekanth Reddy 		return;
2317*78b76a07SSreekanth Reddy 	case MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET:
2318*78b76a07SSreekanth Reddy 		reset_reason = MPI3MR_RESET_FROM_CIACTIV_FAULT;
2319*78b76a07SSreekanth Reddy 		break;
2320*78b76a07SSreekanth Reddy 	default:
2321*78b76a07SSreekanth Reddy 		break;
2322672ae26cSKashyap Desai 	}
2323*78b76a07SSreekanth Reddy 	mpi3mr_soft_reset_handler(mrioc, reset_reason, 0);
2324*78b76a07SSreekanth Reddy 	return;
2325672ae26cSKashyap Desai 
2326672ae26cSKashyap Desai schedule_work:
2327672ae26cSKashyap Desai 	spin_lock_irqsave(&mrioc->watchdog_lock, flags);
2328672ae26cSKashyap Desai 	if (mrioc->watchdog_work_q)
2329672ae26cSKashyap Desai 		queue_delayed_work(mrioc->watchdog_work_q,
2330672ae26cSKashyap Desai 		    &mrioc->watchdog_work,
2331672ae26cSKashyap Desai 		    msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL));
2332672ae26cSKashyap Desai 	spin_unlock_irqrestore(&mrioc->watchdog_lock, flags);
2333672ae26cSKashyap Desai 	return;
2334672ae26cSKashyap Desai }
2335672ae26cSKashyap Desai 
2336672ae26cSKashyap Desai /**
2337672ae26cSKashyap Desai  * mpi3mr_start_watchdog - Start watchdog
2338672ae26cSKashyap Desai  * @mrioc: Adapter instance reference
2339672ae26cSKashyap Desai  *
2340672ae26cSKashyap Desai  * Create and start the watchdog thread to monitor controller
2341672ae26cSKashyap Desai  * faults.
2342672ae26cSKashyap Desai  *
2343672ae26cSKashyap Desai  * Return: Nothing.
2344672ae26cSKashyap Desai  */
2345672ae26cSKashyap Desai void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc)
2346672ae26cSKashyap Desai {
2347672ae26cSKashyap Desai 	if (mrioc->watchdog_work_q)
2348672ae26cSKashyap Desai 		return;
2349672ae26cSKashyap Desai 
2350672ae26cSKashyap Desai 	INIT_DELAYED_WORK(&mrioc->watchdog_work, mpi3mr_watchdog_work);
2351672ae26cSKashyap Desai 	snprintf(mrioc->watchdog_work_q_name,
2352672ae26cSKashyap Desai 	    sizeof(mrioc->watchdog_work_q_name), "watchdog_%s%d", mrioc->name,
2353672ae26cSKashyap Desai 	    mrioc->id);
2354672ae26cSKashyap Desai 	mrioc->watchdog_work_q =
2355672ae26cSKashyap Desai 	    create_singlethread_workqueue(mrioc->watchdog_work_q_name);
2356672ae26cSKashyap Desai 	if (!mrioc->watchdog_work_q) {
2357672ae26cSKashyap Desai 		ioc_err(mrioc, "%s: failed (line=%d)\n", __func__, __LINE__);
2358672ae26cSKashyap Desai 		return;
2359672ae26cSKashyap Desai 	}
2360672ae26cSKashyap Desai 
2361672ae26cSKashyap Desai 	if (mrioc->watchdog_work_q)
2362672ae26cSKashyap Desai 		queue_delayed_work(mrioc->watchdog_work_q,
2363672ae26cSKashyap Desai 		    &mrioc->watchdog_work,
2364672ae26cSKashyap Desai 		    msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL));
2365672ae26cSKashyap Desai }
2366672ae26cSKashyap Desai 
2367672ae26cSKashyap Desai /**
2368672ae26cSKashyap Desai  * mpi3mr_stop_watchdog - Stop watchdog
2369672ae26cSKashyap Desai  * @mrioc: Adapter instance reference
2370672ae26cSKashyap Desai  *
2371672ae26cSKashyap Desai  * Stop the watchdog thread created to monitor controller
2372672ae26cSKashyap Desai  * faults.
2373672ae26cSKashyap Desai  *
2374672ae26cSKashyap Desai  * Return: Nothing.
2375672ae26cSKashyap Desai  */
2376672ae26cSKashyap Desai void mpi3mr_stop_watchdog(struct mpi3mr_ioc *mrioc)
2377672ae26cSKashyap Desai {
2378672ae26cSKashyap Desai 	unsigned long flags;
2379672ae26cSKashyap Desai 	struct workqueue_struct *wq;
2380672ae26cSKashyap Desai 
2381672ae26cSKashyap Desai 	spin_lock_irqsave(&mrioc->watchdog_lock, flags);
2382672ae26cSKashyap Desai 	wq = mrioc->watchdog_work_q;
2383672ae26cSKashyap Desai 	mrioc->watchdog_work_q = NULL;
2384672ae26cSKashyap Desai 	spin_unlock_irqrestore(&mrioc->watchdog_lock, flags);
2385672ae26cSKashyap Desai 	if (wq) {
2386672ae26cSKashyap Desai 		if (!cancel_delayed_work_sync(&mrioc->watchdog_work))
2387672ae26cSKashyap Desai 			flush_workqueue(wq);
2388672ae26cSKashyap Desai 		destroy_workqueue(wq);
2389672ae26cSKashyap Desai 	}
2390672ae26cSKashyap Desai }
2391672ae26cSKashyap Desai 
2392672ae26cSKashyap Desai /**
2393824a1566SKashyap Desai  * mpi3mr_setup_admin_qpair - Setup admin queue pair
2394824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2395824a1566SKashyap Desai  *
2396824a1566SKashyap Desai  * Allocate memory for admin queue pair if required and register
2397824a1566SKashyap Desai  * the admin queue with the controller.
2398824a1566SKashyap Desai  *
2399824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
2400824a1566SKashyap Desai  */
2401824a1566SKashyap Desai static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc)
2402824a1566SKashyap Desai {
2403824a1566SKashyap Desai 	int retval = 0;
2404824a1566SKashyap Desai 	u32 num_admin_entries = 0;
2405824a1566SKashyap Desai 
2406824a1566SKashyap Desai 	mrioc->admin_req_q_sz = MPI3MR_ADMIN_REQ_Q_SIZE;
2407824a1566SKashyap Desai 	mrioc->num_admin_req = mrioc->admin_req_q_sz /
2408824a1566SKashyap Desai 	    MPI3MR_ADMIN_REQ_FRAME_SZ;
2409824a1566SKashyap Desai 	mrioc->admin_req_ci = mrioc->admin_req_pi = 0;
2410824a1566SKashyap Desai 	mrioc->admin_req_base = NULL;
2411824a1566SKashyap Desai 
2412824a1566SKashyap Desai 	mrioc->admin_reply_q_sz = MPI3MR_ADMIN_REPLY_Q_SIZE;
2413824a1566SKashyap Desai 	mrioc->num_admin_replies = mrioc->admin_reply_q_sz /
2414824a1566SKashyap Desai 	    MPI3MR_ADMIN_REPLY_FRAME_SZ;
2415824a1566SKashyap Desai 	mrioc->admin_reply_ci = 0;
2416824a1566SKashyap Desai 	mrioc->admin_reply_ephase = 1;
2417824a1566SKashyap Desai 	mrioc->admin_reply_base = NULL;
2418824a1566SKashyap Desai 
2419824a1566SKashyap Desai 	if (!mrioc->admin_req_base) {
2420824a1566SKashyap Desai 		mrioc->admin_req_base = dma_alloc_coherent(&mrioc->pdev->dev,
2421824a1566SKashyap Desai 		    mrioc->admin_req_q_sz, &mrioc->admin_req_dma, GFP_KERNEL);
2422824a1566SKashyap Desai 
2423824a1566SKashyap Desai 		if (!mrioc->admin_req_base) {
2424824a1566SKashyap Desai 			retval = -1;
2425824a1566SKashyap Desai 			goto out_failed;
2426824a1566SKashyap Desai 		}
2427824a1566SKashyap Desai 
2428824a1566SKashyap Desai 		mrioc->admin_reply_base = dma_alloc_coherent(&mrioc->pdev->dev,
2429824a1566SKashyap Desai 		    mrioc->admin_reply_q_sz, &mrioc->admin_reply_dma,
2430824a1566SKashyap Desai 		    GFP_KERNEL);
2431824a1566SKashyap Desai 
2432824a1566SKashyap Desai 		if (!mrioc->admin_reply_base) {
2433824a1566SKashyap Desai 			retval = -1;
2434824a1566SKashyap Desai 			goto out_failed;
2435824a1566SKashyap Desai 		}
2436824a1566SKashyap Desai 	}
2437824a1566SKashyap Desai 
2438824a1566SKashyap Desai 	num_admin_entries = (mrioc->num_admin_replies << 16) |
2439824a1566SKashyap Desai 	    (mrioc->num_admin_req);
2440824a1566SKashyap Desai 	writel(num_admin_entries, &mrioc->sysif_regs->admin_queue_num_entries);
2441824a1566SKashyap Desai 	mpi3mr_writeq(mrioc->admin_req_dma,
2442824a1566SKashyap Desai 	    &mrioc->sysif_regs->admin_request_queue_address);
2443824a1566SKashyap Desai 	mpi3mr_writeq(mrioc->admin_reply_dma,
2444824a1566SKashyap Desai 	    &mrioc->sysif_regs->admin_reply_queue_address);
2445824a1566SKashyap Desai 	writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi);
2446824a1566SKashyap Desai 	writel(mrioc->admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci);
2447824a1566SKashyap Desai 	return retval;
2448824a1566SKashyap Desai 
2449824a1566SKashyap Desai out_failed:
2450824a1566SKashyap Desai 
2451824a1566SKashyap Desai 	if (mrioc->admin_reply_base) {
2452824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz,
2453824a1566SKashyap Desai 		    mrioc->admin_reply_base, mrioc->admin_reply_dma);
2454824a1566SKashyap Desai 		mrioc->admin_reply_base = NULL;
2455824a1566SKashyap Desai 	}
2456824a1566SKashyap Desai 	if (mrioc->admin_req_base) {
2457824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz,
2458824a1566SKashyap Desai 		    mrioc->admin_req_base, mrioc->admin_req_dma);
2459824a1566SKashyap Desai 		mrioc->admin_req_base = NULL;
2460824a1566SKashyap Desai 	}
2461824a1566SKashyap Desai 	return retval;
2462824a1566SKashyap Desai }
2463824a1566SKashyap Desai 
2464824a1566SKashyap Desai /**
2465824a1566SKashyap Desai  * mpi3mr_issue_iocfacts - Send IOC Facts
2466824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2467824a1566SKashyap Desai  * @facts_data: Cached IOC facts data
2468824a1566SKashyap Desai  *
2469824a1566SKashyap Desai  * Issue IOC Facts MPI request through admin queue and wait for
2470824a1566SKashyap Desai  * the completion of it or time out.
2471824a1566SKashyap Desai  *
2472824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
2473824a1566SKashyap Desai  */
2474824a1566SKashyap Desai static int mpi3mr_issue_iocfacts(struct mpi3mr_ioc *mrioc,
2475824a1566SKashyap Desai 	struct mpi3_ioc_facts_data *facts_data)
2476824a1566SKashyap Desai {
2477824a1566SKashyap Desai 	struct mpi3_ioc_facts_request iocfacts_req;
2478824a1566SKashyap Desai 	void *data = NULL;
2479824a1566SKashyap Desai 	dma_addr_t data_dma;
2480824a1566SKashyap Desai 	u32 data_len = sizeof(*facts_data);
2481824a1566SKashyap Desai 	int retval = 0;
2482824a1566SKashyap Desai 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
2483824a1566SKashyap Desai 
2484824a1566SKashyap Desai 	data = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma,
2485824a1566SKashyap Desai 	    GFP_KERNEL);
2486824a1566SKashyap Desai 
2487824a1566SKashyap Desai 	if (!data) {
2488824a1566SKashyap Desai 		retval = -1;
2489824a1566SKashyap Desai 		goto out;
2490824a1566SKashyap Desai 	}
2491824a1566SKashyap Desai 
2492824a1566SKashyap Desai 	memset(&iocfacts_req, 0, sizeof(iocfacts_req));
2493824a1566SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
2494824a1566SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
2495824a1566SKashyap Desai 		retval = -1;
2496824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCFacts: Init command is in use\n");
2497824a1566SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
2498824a1566SKashyap Desai 		goto out;
2499824a1566SKashyap Desai 	}
2500824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
2501824a1566SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
2502824a1566SKashyap Desai 	mrioc->init_cmds.callback = NULL;
2503824a1566SKashyap Desai 	iocfacts_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
2504824a1566SKashyap Desai 	iocfacts_req.function = MPI3_FUNCTION_IOC_FACTS;
2505824a1566SKashyap Desai 
2506824a1566SKashyap Desai 	mpi3mr_add_sg_single(&iocfacts_req.sgl, sgl_flags, data_len,
2507824a1566SKashyap Desai 	    data_dma);
2508824a1566SKashyap Desai 
2509824a1566SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
2510824a1566SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &iocfacts_req,
2511824a1566SKashyap Desai 	    sizeof(iocfacts_req), 1);
2512824a1566SKashyap Desai 	if (retval) {
2513824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCFacts: Admin Post failed\n");
2514824a1566SKashyap Desai 		goto out_unlock;
2515824a1566SKashyap Desai 	}
2516824a1566SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
2517824a1566SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
2518824a1566SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
2519a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "ioc_facts timed out\n");
2520a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
2521824a1566SKashyap Desai 		    MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT);
2522824a1566SKashyap Desai 		retval = -1;
2523824a1566SKashyap Desai 		goto out_unlock;
2524824a1566SKashyap Desai 	}
2525824a1566SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
2526824a1566SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
2527824a1566SKashyap Desai 		ioc_err(mrioc,
2528824a1566SKashyap Desai 		    "Issue IOCFacts: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
2529824a1566SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
2530824a1566SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
2531824a1566SKashyap Desai 		retval = -1;
2532824a1566SKashyap Desai 		goto out_unlock;
2533824a1566SKashyap Desai 	}
2534824a1566SKashyap Desai 	memcpy(facts_data, (u8 *)data, data_len);
2535c5758fc7SSreekanth Reddy 	mpi3mr_process_factsdata(mrioc, facts_data);
2536824a1566SKashyap Desai out_unlock:
2537824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
2538824a1566SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
2539824a1566SKashyap Desai 
2540824a1566SKashyap Desai out:
2541824a1566SKashyap Desai 	if (data)
2542824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, data_len, data, data_dma);
2543824a1566SKashyap Desai 
2544824a1566SKashyap Desai 	return retval;
2545824a1566SKashyap Desai }
2546824a1566SKashyap Desai 
2547824a1566SKashyap Desai /**
2548824a1566SKashyap Desai  * mpi3mr_check_reset_dma_mask - Process IOC facts data
2549824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2550824a1566SKashyap Desai  *
2551824a1566SKashyap Desai  * Check whether the new DMA mask requested through IOCFacts by
2552824a1566SKashyap Desai  * firmware needs to be set, if so set it .
2553824a1566SKashyap Desai  *
2554824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
2555824a1566SKashyap Desai  */
2556824a1566SKashyap Desai static inline int mpi3mr_check_reset_dma_mask(struct mpi3mr_ioc *mrioc)
2557824a1566SKashyap Desai {
2558824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
2559824a1566SKashyap Desai 	int r;
2560824a1566SKashyap Desai 	u64 facts_dma_mask = DMA_BIT_MASK(mrioc->facts.dma_mask);
2561824a1566SKashyap Desai 
2562824a1566SKashyap Desai 	if (!mrioc->facts.dma_mask || (mrioc->dma_mask <= facts_dma_mask))
2563824a1566SKashyap Desai 		return 0;
2564824a1566SKashyap Desai 
2565824a1566SKashyap Desai 	ioc_info(mrioc, "Changing DMA mask from 0x%016llx to 0x%016llx\n",
2566824a1566SKashyap Desai 	    mrioc->dma_mask, facts_dma_mask);
2567824a1566SKashyap Desai 
2568824a1566SKashyap Desai 	r = dma_set_mask_and_coherent(&pdev->dev, facts_dma_mask);
2569824a1566SKashyap Desai 	if (r) {
2570824a1566SKashyap Desai 		ioc_err(mrioc, "Setting DMA mask to 0x%016llx failed: %d\n",
2571824a1566SKashyap Desai 		    facts_dma_mask, r);
2572824a1566SKashyap Desai 		return r;
2573824a1566SKashyap Desai 	}
2574824a1566SKashyap Desai 	mrioc->dma_mask = facts_dma_mask;
2575824a1566SKashyap Desai 	return r;
2576824a1566SKashyap Desai }
2577824a1566SKashyap Desai 
2578824a1566SKashyap Desai /**
2579824a1566SKashyap Desai  * mpi3mr_process_factsdata - Process IOC facts data
2580824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2581824a1566SKashyap Desai  * @facts_data: Cached IOC facts data
2582824a1566SKashyap Desai  *
2583824a1566SKashyap Desai  * Convert IOC facts data into cpu endianness and cache it in
2584824a1566SKashyap Desai  * the driver .
2585824a1566SKashyap Desai  *
2586824a1566SKashyap Desai  * Return: Nothing.
2587824a1566SKashyap Desai  */
2588824a1566SKashyap Desai static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc,
2589824a1566SKashyap Desai 	struct mpi3_ioc_facts_data *facts_data)
2590824a1566SKashyap Desai {
2591824a1566SKashyap Desai 	u32 ioc_config, req_sz, facts_flags;
2592824a1566SKashyap Desai 
2593824a1566SKashyap Desai 	if ((le16_to_cpu(facts_data->ioc_facts_data_length)) !=
2594824a1566SKashyap Desai 	    (sizeof(*facts_data) / 4)) {
2595824a1566SKashyap Desai 		ioc_warn(mrioc,
2596824a1566SKashyap Desai 		    "IOCFactsdata length mismatch driver_sz(%zu) firmware_sz(%d)\n",
2597824a1566SKashyap Desai 		    sizeof(*facts_data),
2598824a1566SKashyap Desai 		    le16_to_cpu(facts_data->ioc_facts_data_length) * 4);
2599824a1566SKashyap Desai 	}
2600824a1566SKashyap Desai 
2601824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
2602824a1566SKashyap Desai 	req_sz = 1 << ((ioc_config & MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ) >>
2603824a1566SKashyap Desai 	    MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ_SHIFT);
2604824a1566SKashyap Desai 	if (le16_to_cpu(facts_data->ioc_request_frame_size) != (req_sz / 4)) {
2605824a1566SKashyap Desai 		ioc_err(mrioc,
2606824a1566SKashyap Desai 		    "IOCFacts data reqFrameSize mismatch hw_size(%d) firmware_sz(%d)\n",
2607824a1566SKashyap Desai 		    req_sz / 4, le16_to_cpu(facts_data->ioc_request_frame_size));
2608824a1566SKashyap Desai 	}
2609824a1566SKashyap Desai 
2610824a1566SKashyap Desai 	memset(&mrioc->facts, 0, sizeof(mrioc->facts));
2611824a1566SKashyap Desai 
2612824a1566SKashyap Desai 	facts_flags = le32_to_cpu(facts_data->flags);
2613824a1566SKashyap Desai 	mrioc->facts.op_req_sz = req_sz;
2614824a1566SKashyap Desai 	mrioc->op_reply_desc_sz = 1 << ((ioc_config &
2615824a1566SKashyap Desai 	    MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ) >>
2616824a1566SKashyap Desai 	    MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ_SHIFT);
2617824a1566SKashyap Desai 
2618824a1566SKashyap Desai 	mrioc->facts.ioc_num = facts_data->ioc_number;
2619824a1566SKashyap Desai 	mrioc->facts.who_init = facts_data->who_init;
2620824a1566SKashyap Desai 	mrioc->facts.max_msix_vectors = le16_to_cpu(facts_data->max_msix_vectors);
2621824a1566SKashyap Desai 	mrioc->facts.personality = (facts_flags &
2622824a1566SKashyap Desai 	    MPI3_IOCFACTS_FLAGS_PERSONALITY_MASK);
2623824a1566SKashyap Desai 	mrioc->facts.dma_mask = (facts_flags &
2624824a1566SKashyap Desai 	    MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >>
2625824a1566SKashyap Desai 	    MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT;
2626824a1566SKashyap Desai 	mrioc->facts.protocol_flags = facts_data->protocol_flags;
2627824a1566SKashyap Desai 	mrioc->facts.mpi_version = le32_to_cpu(facts_data->mpi_version.word);
2628824a1566SKashyap Desai 	mrioc->facts.max_reqs = le16_to_cpu(facts_data->max_outstanding_request);
2629824a1566SKashyap Desai 	mrioc->facts.product_id = le16_to_cpu(facts_data->product_id);
2630824a1566SKashyap Desai 	mrioc->facts.reply_sz = le16_to_cpu(facts_data->reply_frame_size) * 4;
2631824a1566SKashyap Desai 	mrioc->facts.exceptions = le16_to_cpu(facts_data->ioc_exceptions);
2632824a1566SKashyap Desai 	mrioc->facts.max_perids = le16_to_cpu(facts_data->max_persistent_id);
2633824a1566SKashyap Desai 	mrioc->facts.max_vds = le16_to_cpu(facts_data->max_vds);
2634824a1566SKashyap Desai 	mrioc->facts.max_hpds = le16_to_cpu(facts_data->max_host_pds);
2635ec5ebd2cSSreekanth Reddy 	mrioc->facts.max_advhpds = le16_to_cpu(facts_data->max_adv_host_pds);
2636ec5ebd2cSSreekanth Reddy 	mrioc->facts.max_raid_pds = le16_to_cpu(facts_data->max_raid_pds);
2637824a1566SKashyap Desai 	mrioc->facts.max_nvme = le16_to_cpu(facts_data->max_nvme);
2638824a1566SKashyap Desai 	mrioc->facts.max_pcie_switches =
2639ec5ebd2cSSreekanth Reddy 	    le16_to_cpu(facts_data->max_pcie_switches);
2640824a1566SKashyap Desai 	mrioc->facts.max_sasexpanders =
2641824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_sas_expanders);
2642824a1566SKashyap Desai 	mrioc->facts.max_sasinitiators =
2643824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_sas_initiators);
2644824a1566SKashyap Desai 	mrioc->facts.max_enclosures = le16_to_cpu(facts_data->max_enclosures);
2645824a1566SKashyap Desai 	mrioc->facts.min_devhandle = le16_to_cpu(facts_data->min_dev_handle);
2646824a1566SKashyap Desai 	mrioc->facts.max_devhandle = le16_to_cpu(facts_data->max_dev_handle);
2647824a1566SKashyap Desai 	mrioc->facts.max_op_req_q =
2648824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_operational_request_queues);
2649824a1566SKashyap Desai 	mrioc->facts.max_op_reply_q =
2650824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_operational_reply_queues);
2651824a1566SKashyap Desai 	mrioc->facts.ioc_capabilities =
2652824a1566SKashyap Desai 	    le32_to_cpu(facts_data->ioc_capabilities);
2653824a1566SKashyap Desai 	mrioc->facts.fw_ver.build_num =
2654824a1566SKashyap Desai 	    le16_to_cpu(facts_data->fw_version.build_num);
2655824a1566SKashyap Desai 	mrioc->facts.fw_ver.cust_id =
2656824a1566SKashyap Desai 	    le16_to_cpu(facts_data->fw_version.customer_id);
2657824a1566SKashyap Desai 	mrioc->facts.fw_ver.ph_minor = facts_data->fw_version.phase_minor;
2658824a1566SKashyap Desai 	mrioc->facts.fw_ver.ph_major = facts_data->fw_version.phase_major;
2659824a1566SKashyap Desai 	mrioc->facts.fw_ver.gen_minor = facts_data->fw_version.gen_minor;
2660824a1566SKashyap Desai 	mrioc->facts.fw_ver.gen_major = facts_data->fw_version.gen_major;
2661824a1566SKashyap Desai 	mrioc->msix_count = min_t(int, mrioc->msix_count,
2662824a1566SKashyap Desai 	    mrioc->facts.max_msix_vectors);
2663824a1566SKashyap Desai 	mrioc->facts.sge_mod_mask = facts_data->sge_modifier_mask;
2664824a1566SKashyap Desai 	mrioc->facts.sge_mod_value = facts_data->sge_modifier_value;
2665824a1566SKashyap Desai 	mrioc->facts.sge_mod_shift = facts_data->sge_modifier_shift;
2666824a1566SKashyap Desai 	mrioc->facts.shutdown_timeout =
2667824a1566SKashyap Desai 	    le16_to_cpu(facts_data->shutdown_timeout);
2668824a1566SKashyap Desai 
2669824a1566SKashyap Desai 	ioc_info(mrioc, "ioc_num(%d), maxopQ(%d), maxopRepQ(%d), maxdh(%d),",
2670824a1566SKashyap Desai 	    mrioc->facts.ioc_num, mrioc->facts.max_op_req_q,
2671824a1566SKashyap Desai 	    mrioc->facts.max_op_reply_q, mrioc->facts.max_devhandle);
2672824a1566SKashyap Desai 	ioc_info(mrioc,
2673ec5ebd2cSSreekanth Reddy 	    "maxreqs(%d), mindh(%d) maxvectors(%d) maxperids(%d)\n",
2674824a1566SKashyap Desai 	    mrioc->facts.max_reqs, mrioc->facts.min_devhandle,
2675ec5ebd2cSSreekanth Reddy 	    mrioc->facts.max_msix_vectors, mrioc->facts.max_perids);
2676824a1566SKashyap Desai 	ioc_info(mrioc, "SGEModMask 0x%x SGEModVal 0x%x SGEModShift 0x%x ",
2677824a1566SKashyap Desai 	    mrioc->facts.sge_mod_mask, mrioc->facts.sge_mod_value,
2678824a1566SKashyap Desai 	    mrioc->facts.sge_mod_shift);
2679824a1566SKashyap Desai 	ioc_info(mrioc, "DMA mask %d InitialPE status 0x%x\n",
2680824a1566SKashyap Desai 	    mrioc->facts.dma_mask, (facts_flags &
2681824a1566SKashyap Desai 	    MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK));
2682824a1566SKashyap Desai }
2683824a1566SKashyap Desai 
2684824a1566SKashyap Desai /**
2685824a1566SKashyap Desai  * mpi3mr_alloc_reply_sense_bufs - Send IOC Init
2686824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2687824a1566SKashyap Desai  *
2688824a1566SKashyap Desai  * Allocate and initialize the reply free buffers, sense
2689824a1566SKashyap Desai  * buffers, reply free queue and sense buffer queue.
2690824a1566SKashyap Desai  *
2691824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
2692824a1566SKashyap Desai  */
2693824a1566SKashyap Desai static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc)
2694824a1566SKashyap Desai {
2695824a1566SKashyap Desai 	int retval = 0;
2696824a1566SKashyap Desai 	u32 sz, i;
2697824a1566SKashyap Desai 
2698824a1566SKashyap Desai 	if (mrioc->init_cmds.reply)
2699e3605f65SSreekanth Reddy 		return retval;
2700824a1566SKashyap Desai 
2701c5758fc7SSreekanth Reddy 	mrioc->init_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL);
2702824a1566SKashyap Desai 	if (!mrioc->init_cmds.reply)
2703824a1566SKashyap Desai 		goto out_failed;
2704824a1566SKashyap Desai 
270513ef29eaSKashyap Desai 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
2706c5758fc7SSreekanth Reddy 		mrioc->dev_rmhs_cmds[i].reply = kzalloc(mrioc->reply_sz,
270713ef29eaSKashyap Desai 		    GFP_KERNEL);
270813ef29eaSKashyap Desai 		if (!mrioc->dev_rmhs_cmds[i].reply)
270913ef29eaSKashyap Desai 			goto out_failed;
271013ef29eaSKashyap Desai 	}
271113ef29eaSKashyap Desai 
2712c1af985dSSreekanth Reddy 	for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) {
2713c1af985dSSreekanth Reddy 		mrioc->evtack_cmds[i].reply = kzalloc(mrioc->reply_sz,
2714c1af985dSSreekanth Reddy 		    GFP_KERNEL);
2715c1af985dSSreekanth Reddy 		if (!mrioc->evtack_cmds[i].reply)
2716c1af985dSSreekanth Reddy 			goto out_failed;
2717c1af985dSSreekanth Reddy 	}
2718c1af985dSSreekanth Reddy 
2719c5758fc7SSreekanth Reddy 	mrioc->host_tm_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL);
2720e844adb1SKashyap Desai 	if (!mrioc->host_tm_cmds.reply)
2721e844adb1SKashyap Desai 		goto out_failed;
2722e844adb1SKashyap Desai 
2723e844adb1SKashyap Desai 	mrioc->dev_handle_bitmap_sz = mrioc->facts.max_devhandle / 8;
2724e844adb1SKashyap Desai 	if (mrioc->facts.max_devhandle % 8)
2725e844adb1SKashyap Desai 		mrioc->dev_handle_bitmap_sz++;
2726e844adb1SKashyap Desai 	mrioc->removepend_bitmap = kzalloc(mrioc->dev_handle_bitmap_sz,
2727e844adb1SKashyap Desai 	    GFP_KERNEL);
2728e844adb1SKashyap Desai 	if (!mrioc->removepend_bitmap)
2729e844adb1SKashyap Desai 		goto out_failed;
2730e844adb1SKashyap Desai 
2731e844adb1SKashyap Desai 	mrioc->devrem_bitmap_sz = MPI3MR_NUM_DEVRMCMD / 8;
2732e844adb1SKashyap Desai 	if (MPI3MR_NUM_DEVRMCMD % 8)
2733e844adb1SKashyap Desai 		mrioc->devrem_bitmap_sz++;
2734e844adb1SKashyap Desai 	mrioc->devrem_bitmap = kzalloc(mrioc->devrem_bitmap_sz,
2735e844adb1SKashyap Desai 	    GFP_KERNEL);
2736e844adb1SKashyap Desai 	if (!mrioc->devrem_bitmap)
2737e844adb1SKashyap Desai 		goto out_failed;
2738e844adb1SKashyap Desai 
2739c1af985dSSreekanth Reddy 	mrioc->evtack_cmds_bitmap_sz = MPI3MR_NUM_EVTACKCMD / 8;
2740c1af985dSSreekanth Reddy 	if (MPI3MR_NUM_EVTACKCMD % 8)
2741c1af985dSSreekanth Reddy 		mrioc->evtack_cmds_bitmap_sz++;
2742c1af985dSSreekanth Reddy 	mrioc->evtack_cmds_bitmap = kzalloc(mrioc->evtack_cmds_bitmap_sz,
2743c1af985dSSreekanth Reddy 	    GFP_KERNEL);
2744c1af985dSSreekanth Reddy 	if (!mrioc->evtack_cmds_bitmap)
2745c1af985dSSreekanth Reddy 		goto out_failed;
2746c1af985dSSreekanth Reddy 
2747824a1566SKashyap Desai 	mrioc->num_reply_bufs = mrioc->facts.max_reqs + MPI3MR_NUM_EVT_REPLIES;
2748824a1566SKashyap Desai 	mrioc->reply_free_qsz = mrioc->num_reply_bufs + 1;
2749824a1566SKashyap Desai 	mrioc->num_sense_bufs = mrioc->facts.max_reqs / MPI3MR_SENSEBUF_FACTOR;
2750824a1566SKashyap Desai 	mrioc->sense_buf_q_sz = mrioc->num_sense_bufs + 1;
2751824a1566SKashyap Desai 
2752824a1566SKashyap Desai 	/* reply buffer pool, 16 byte align */
2753c5758fc7SSreekanth Reddy 	sz = mrioc->num_reply_bufs * mrioc->reply_sz;
2754824a1566SKashyap Desai 	mrioc->reply_buf_pool = dma_pool_create("reply_buf pool",
2755824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 16, 0);
2756824a1566SKashyap Desai 	if (!mrioc->reply_buf_pool) {
2757824a1566SKashyap Desai 		ioc_err(mrioc, "reply buf pool: dma_pool_create failed\n");
2758824a1566SKashyap Desai 		goto out_failed;
2759824a1566SKashyap Desai 	}
2760824a1566SKashyap Desai 
2761824a1566SKashyap Desai 	mrioc->reply_buf = dma_pool_zalloc(mrioc->reply_buf_pool, GFP_KERNEL,
2762824a1566SKashyap Desai 	    &mrioc->reply_buf_dma);
2763824a1566SKashyap Desai 	if (!mrioc->reply_buf)
2764824a1566SKashyap Desai 		goto out_failed;
2765824a1566SKashyap Desai 
2766824a1566SKashyap Desai 	mrioc->reply_buf_dma_max_address = mrioc->reply_buf_dma + sz;
2767824a1566SKashyap Desai 
2768824a1566SKashyap Desai 	/* reply free queue, 8 byte align */
2769824a1566SKashyap Desai 	sz = mrioc->reply_free_qsz * 8;
2770824a1566SKashyap Desai 	mrioc->reply_free_q_pool = dma_pool_create("reply_free_q pool",
2771824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 8, 0);
2772824a1566SKashyap Desai 	if (!mrioc->reply_free_q_pool) {
2773824a1566SKashyap Desai 		ioc_err(mrioc, "reply_free_q pool: dma_pool_create failed\n");
2774824a1566SKashyap Desai 		goto out_failed;
2775824a1566SKashyap Desai 	}
2776824a1566SKashyap Desai 	mrioc->reply_free_q = dma_pool_zalloc(mrioc->reply_free_q_pool,
2777824a1566SKashyap Desai 	    GFP_KERNEL, &mrioc->reply_free_q_dma);
2778824a1566SKashyap Desai 	if (!mrioc->reply_free_q)
2779824a1566SKashyap Desai 		goto out_failed;
2780824a1566SKashyap Desai 
2781824a1566SKashyap Desai 	/* sense buffer pool,  4 byte align */
2782ec5ebd2cSSreekanth Reddy 	sz = mrioc->num_sense_bufs * MPI3MR_SENSE_BUF_SZ;
2783824a1566SKashyap Desai 	mrioc->sense_buf_pool = dma_pool_create("sense_buf pool",
2784824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 4, 0);
2785824a1566SKashyap Desai 	if (!mrioc->sense_buf_pool) {
2786824a1566SKashyap Desai 		ioc_err(mrioc, "sense_buf pool: dma_pool_create failed\n");
2787824a1566SKashyap Desai 		goto out_failed;
2788824a1566SKashyap Desai 	}
2789824a1566SKashyap Desai 	mrioc->sense_buf = dma_pool_zalloc(mrioc->sense_buf_pool, GFP_KERNEL,
2790824a1566SKashyap Desai 	    &mrioc->sense_buf_dma);
2791824a1566SKashyap Desai 	if (!mrioc->sense_buf)
2792824a1566SKashyap Desai 		goto out_failed;
2793824a1566SKashyap Desai 
2794824a1566SKashyap Desai 	/* sense buffer queue, 8 byte align */
2795824a1566SKashyap Desai 	sz = mrioc->sense_buf_q_sz * 8;
2796824a1566SKashyap Desai 	mrioc->sense_buf_q_pool = dma_pool_create("sense_buf_q pool",
2797824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 8, 0);
2798824a1566SKashyap Desai 	if (!mrioc->sense_buf_q_pool) {
2799824a1566SKashyap Desai 		ioc_err(mrioc, "sense_buf_q pool: dma_pool_create failed\n");
2800824a1566SKashyap Desai 		goto out_failed;
2801824a1566SKashyap Desai 	}
2802824a1566SKashyap Desai 	mrioc->sense_buf_q = dma_pool_zalloc(mrioc->sense_buf_q_pool,
2803824a1566SKashyap Desai 	    GFP_KERNEL, &mrioc->sense_buf_q_dma);
2804824a1566SKashyap Desai 	if (!mrioc->sense_buf_q)
2805824a1566SKashyap Desai 		goto out_failed;
2806824a1566SKashyap Desai 
2807e3605f65SSreekanth Reddy 	return retval;
2808e3605f65SSreekanth Reddy 
2809e3605f65SSreekanth Reddy out_failed:
2810e3605f65SSreekanth Reddy 	retval = -1;
2811e3605f65SSreekanth Reddy 	return retval;
2812e3605f65SSreekanth Reddy }
2813e3605f65SSreekanth Reddy 
2814e3605f65SSreekanth Reddy /**
2815e3605f65SSreekanth Reddy  * mpimr_initialize_reply_sbuf_queues - initialize reply sense
2816e3605f65SSreekanth Reddy  * buffers
2817e3605f65SSreekanth Reddy  * @mrioc: Adapter instance reference
2818e3605f65SSreekanth Reddy  *
2819e3605f65SSreekanth Reddy  * Helper function to initialize reply and sense buffers along
2820e3605f65SSreekanth Reddy  * with some debug prints.
2821e3605f65SSreekanth Reddy  *
2822e3605f65SSreekanth Reddy  * Return:  None.
2823e3605f65SSreekanth Reddy  */
2824e3605f65SSreekanth Reddy static void mpimr_initialize_reply_sbuf_queues(struct mpi3mr_ioc *mrioc)
2825e3605f65SSreekanth Reddy {
2826e3605f65SSreekanth Reddy 	u32 sz, i;
2827e3605f65SSreekanth Reddy 	dma_addr_t phy_addr;
2828e3605f65SSreekanth Reddy 
2829c5758fc7SSreekanth Reddy 	sz = mrioc->num_reply_bufs * mrioc->reply_sz;
2830824a1566SKashyap Desai 	ioc_info(mrioc,
2831824a1566SKashyap Desai 	    "reply buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n",
2832c5758fc7SSreekanth Reddy 	    mrioc->reply_buf, mrioc->num_reply_bufs, mrioc->reply_sz,
2833824a1566SKashyap Desai 	    (sz / 1024), (unsigned long long)mrioc->reply_buf_dma);
2834824a1566SKashyap Desai 	sz = mrioc->reply_free_qsz * 8;
2835824a1566SKashyap Desai 	ioc_info(mrioc,
2836824a1566SKashyap Desai 	    "reply_free_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n",
2837824a1566SKashyap Desai 	    mrioc->reply_free_q, mrioc->reply_free_qsz, 8, (sz / 1024),
2838824a1566SKashyap Desai 	    (unsigned long long)mrioc->reply_free_q_dma);
2839ec5ebd2cSSreekanth Reddy 	sz = mrioc->num_sense_bufs * MPI3MR_SENSE_BUF_SZ;
2840824a1566SKashyap Desai 	ioc_info(mrioc,
2841824a1566SKashyap Desai 	    "sense_buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n",
2842ec5ebd2cSSreekanth Reddy 	    mrioc->sense_buf, mrioc->num_sense_bufs, MPI3MR_SENSE_BUF_SZ,
2843824a1566SKashyap Desai 	    (sz / 1024), (unsigned long long)mrioc->sense_buf_dma);
2844824a1566SKashyap Desai 	sz = mrioc->sense_buf_q_sz * 8;
2845824a1566SKashyap Desai 	ioc_info(mrioc,
2846824a1566SKashyap Desai 	    "sense_buf_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n",
2847824a1566SKashyap Desai 	    mrioc->sense_buf_q, mrioc->sense_buf_q_sz, 8, (sz / 1024),
2848824a1566SKashyap Desai 	    (unsigned long long)mrioc->sense_buf_q_dma);
2849824a1566SKashyap Desai 
2850824a1566SKashyap Desai 	/* initialize Reply buffer Queue */
2851824a1566SKashyap Desai 	for (i = 0, phy_addr = mrioc->reply_buf_dma;
2852c5758fc7SSreekanth Reddy 	    i < mrioc->num_reply_bufs; i++, phy_addr += mrioc->reply_sz)
2853824a1566SKashyap Desai 		mrioc->reply_free_q[i] = cpu_to_le64(phy_addr);
2854824a1566SKashyap Desai 	mrioc->reply_free_q[i] = cpu_to_le64(0);
2855824a1566SKashyap Desai 
2856824a1566SKashyap Desai 	/* initialize Sense Buffer Queue */
2857824a1566SKashyap Desai 	for (i = 0, phy_addr = mrioc->sense_buf_dma;
2858ec5ebd2cSSreekanth Reddy 	    i < mrioc->num_sense_bufs; i++, phy_addr += MPI3MR_SENSE_BUF_SZ)
2859824a1566SKashyap Desai 		mrioc->sense_buf_q[i] = cpu_to_le64(phy_addr);
2860824a1566SKashyap Desai 	mrioc->sense_buf_q[i] = cpu_to_le64(0);
2861824a1566SKashyap Desai }
2862824a1566SKashyap Desai 
2863824a1566SKashyap Desai /**
2864824a1566SKashyap Desai  * mpi3mr_issue_iocinit - Send IOC Init
2865824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2866824a1566SKashyap Desai  *
2867824a1566SKashyap Desai  * Issue IOC Init MPI request through admin queue and wait for
2868824a1566SKashyap Desai  * the completion of it or time out.
2869824a1566SKashyap Desai  *
2870824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
2871824a1566SKashyap Desai  */
2872824a1566SKashyap Desai static int mpi3mr_issue_iocinit(struct mpi3mr_ioc *mrioc)
2873824a1566SKashyap Desai {
2874824a1566SKashyap Desai 	struct mpi3_ioc_init_request iocinit_req;
2875824a1566SKashyap Desai 	struct mpi3_driver_info_layout *drv_info;
2876824a1566SKashyap Desai 	dma_addr_t data_dma;
2877824a1566SKashyap Desai 	u32 data_len = sizeof(*drv_info);
2878824a1566SKashyap Desai 	int retval = 0;
2879824a1566SKashyap Desai 	ktime_t current_time;
2880824a1566SKashyap Desai 
2881824a1566SKashyap Desai 	drv_info = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma,
2882824a1566SKashyap Desai 	    GFP_KERNEL);
2883824a1566SKashyap Desai 	if (!drv_info) {
2884824a1566SKashyap Desai 		retval = -1;
2885824a1566SKashyap Desai 		goto out;
2886824a1566SKashyap Desai 	}
2887e3605f65SSreekanth Reddy 	mpimr_initialize_reply_sbuf_queues(mrioc);
2888e3605f65SSreekanth Reddy 
2889824a1566SKashyap Desai 	drv_info->information_length = cpu_to_le32(data_len);
2890aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->driver_signature, "Broadcom", sizeof(drv_info->driver_signature));
2891aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->os_name, utsname()->sysname, sizeof(drv_info->os_name));
2892aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->os_version, utsname()->release, sizeof(drv_info->os_version));
2893aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->driver_name, MPI3MR_DRIVER_NAME, sizeof(drv_info->driver_name));
2894aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->driver_version, MPI3MR_DRIVER_VERSION, sizeof(drv_info->driver_version));
2895aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->driver_release_date, MPI3MR_DRIVER_RELDATE,
2896aa0dc6a7SSreekanth Reddy 	    sizeof(drv_info->driver_release_date));
2897824a1566SKashyap Desai 	drv_info->driver_capabilities = 0;
2898824a1566SKashyap Desai 	memcpy((u8 *)&mrioc->driver_info, (u8 *)drv_info,
2899824a1566SKashyap Desai 	    sizeof(mrioc->driver_info));
2900824a1566SKashyap Desai 
2901824a1566SKashyap Desai 	memset(&iocinit_req, 0, sizeof(iocinit_req));
2902824a1566SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
2903824a1566SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
2904824a1566SKashyap Desai 		retval = -1;
2905824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCInit: Init command is in use\n");
2906824a1566SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
2907824a1566SKashyap Desai 		goto out;
2908824a1566SKashyap Desai 	}
2909824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
2910824a1566SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
2911824a1566SKashyap Desai 	mrioc->init_cmds.callback = NULL;
2912824a1566SKashyap Desai 	iocinit_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
2913824a1566SKashyap Desai 	iocinit_req.function = MPI3_FUNCTION_IOC_INIT;
2914824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.dev = MPI3_VERSION_DEV;
2915824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.unit = MPI3_VERSION_UNIT;
2916824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.major = MPI3_VERSION_MAJOR;
2917824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.minor = MPI3_VERSION_MINOR;
2918824a1566SKashyap Desai 	iocinit_req.who_init = MPI3_WHOINIT_HOST_DRIVER;
2919824a1566SKashyap Desai 	iocinit_req.reply_free_queue_depth = cpu_to_le16(mrioc->reply_free_qsz);
2920824a1566SKashyap Desai 	iocinit_req.reply_free_queue_address =
2921824a1566SKashyap Desai 	    cpu_to_le64(mrioc->reply_free_q_dma);
2922ec5ebd2cSSreekanth Reddy 	iocinit_req.sense_buffer_length = cpu_to_le16(MPI3MR_SENSE_BUF_SZ);
2923824a1566SKashyap Desai 	iocinit_req.sense_buffer_free_queue_depth =
2924824a1566SKashyap Desai 	    cpu_to_le16(mrioc->sense_buf_q_sz);
2925824a1566SKashyap Desai 	iocinit_req.sense_buffer_free_queue_address =
2926824a1566SKashyap Desai 	    cpu_to_le64(mrioc->sense_buf_q_dma);
2927824a1566SKashyap Desai 	iocinit_req.driver_information_address = cpu_to_le64(data_dma);
2928824a1566SKashyap Desai 
2929824a1566SKashyap Desai 	current_time = ktime_get_real();
2930824a1566SKashyap Desai 	iocinit_req.time_stamp = cpu_to_le64(ktime_to_ms(current_time));
2931824a1566SKashyap Desai 
2932824a1566SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
2933824a1566SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &iocinit_req,
2934824a1566SKashyap Desai 	    sizeof(iocinit_req), 1);
2935824a1566SKashyap Desai 	if (retval) {
2936824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCInit: Admin Post failed\n");
2937824a1566SKashyap Desai 		goto out_unlock;
2938824a1566SKashyap Desai 	}
2939824a1566SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
2940824a1566SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
2941824a1566SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
2942a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
2943824a1566SKashyap Desai 		    MPI3MR_RESET_FROM_IOCINIT_TIMEOUT);
2944a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "ioc_init timed out\n");
2945824a1566SKashyap Desai 		retval = -1;
2946824a1566SKashyap Desai 		goto out_unlock;
2947824a1566SKashyap Desai 	}
2948824a1566SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
2949824a1566SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
2950824a1566SKashyap Desai 		ioc_err(mrioc,
2951824a1566SKashyap Desai 		    "Issue IOCInit: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
2952824a1566SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
2953824a1566SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
2954824a1566SKashyap Desai 		retval = -1;
2955824a1566SKashyap Desai 		goto out_unlock;
2956824a1566SKashyap Desai 	}
2957824a1566SKashyap Desai 
2958e3605f65SSreekanth Reddy 	mrioc->reply_free_queue_host_index = mrioc->num_reply_bufs;
2959e3605f65SSreekanth Reddy 	writel(mrioc->reply_free_queue_host_index,
2960e3605f65SSreekanth Reddy 	    &mrioc->sysif_regs->reply_free_host_index);
2961e3605f65SSreekanth Reddy 
2962e3605f65SSreekanth Reddy 	mrioc->sbq_host_index = mrioc->num_sense_bufs;
2963e3605f65SSreekanth Reddy 	writel(mrioc->sbq_host_index,
2964e3605f65SSreekanth Reddy 	    &mrioc->sysif_regs->sense_buffer_free_host_index);
2965824a1566SKashyap Desai out_unlock:
2966824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
2967824a1566SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
2968824a1566SKashyap Desai 
2969824a1566SKashyap Desai out:
2970824a1566SKashyap Desai 	if (drv_info)
2971824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, data_len, drv_info,
2972824a1566SKashyap Desai 		    data_dma);
2973824a1566SKashyap Desai 
2974824a1566SKashyap Desai 	return retval;
2975824a1566SKashyap Desai }
2976824a1566SKashyap Desai 
2977824a1566SKashyap Desai /**
297813ef29eaSKashyap Desai  * mpi3mr_unmask_events - Unmask events in event mask bitmap
297913ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
298013ef29eaSKashyap Desai  * @event: MPI event ID
298113ef29eaSKashyap Desai  *
298213ef29eaSKashyap Desai  * Un mask the specific event by resetting the event_mask
298313ef29eaSKashyap Desai  * bitmap.
298413ef29eaSKashyap Desai  *
298513ef29eaSKashyap Desai  * Return: 0 on success, non-zero on failures.
298613ef29eaSKashyap Desai  */
298713ef29eaSKashyap Desai static void mpi3mr_unmask_events(struct mpi3mr_ioc *mrioc, u16 event)
298813ef29eaSKashyap Desai {
298913ef29eaSKashyap Desai 	u32 desired_event;
299013ef29eaSKashyap Desai 	u8 word;
299113ef29eaSKashyap Desai 
299213ef29eaSKashyap Desai 	if (event >= 128)
299313ef29eaSKashyap Desai 		return;
299413ef29eaSKashyap Desai 
299513ef29eaSKashyap Desai 	desired_event = (1 << (event % 32));
299613ef29eaSKashyap Desai 	word = event / 32;
299713ef29eaSKashyap Desai 
299813ef29eaSKashyap Desai 	mrioc->event_masks[word] &= ~desired_event;
299913ef29eaSKashyap Desai }
300013ef29eaSKashyap Desai 
300113ef29eaSKashyap Desai /**
300213ef29eaSKashyap Desai  * mpi3mr_issue_event_notification - Send event notification
300313ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
300413ef29eaSKashyap Desai  *
300513ef29eaSKashyap Desai  * Issue event notification MPI request through admin queue and
300613ef29eaSKashyap Desai  * wait for the completion of it or time out.
300713ef29eaSKashyap Desai  *
300813ef29eaSKashyap Desai  * Return: 0 on success, non-zero on failures.
300913ef29eaSKashyap Desai  */
301013ef29eaSKashyap Desai static int mpi3mr_issue_event_notification(struct mpi3mr_ioc *mrioc)
301113ef29eaSKashyap Desai {
301213ef29eaSKashyap Desai 	struct mpi3_event_notification_request evtnotify_req;
301313ef29eaSKashyap Desai 	int retval = 0;
301413ef29eaSKashyap Desai 	u8 i;
301513ef29eaSKashyap Desai 
301613ef29eaSKashyap Desai 	memset(&evtnotify_req, 0, sizeof(evtnotify_req));
301713ef29eaSKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
301813ef29eaSKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
301913ef29eaSKashyap Desai 		retval = -1;
302013ef29eaSKashyap Desai 		ioc_err(mrioc, "Issue EvtNotify: Init command is in use\n");
302113ef29eaSKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
302213ef29eaSKashyap Desai 		goto out;
302313ef29eaSKashyap Desai 	}
302413ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
302513ef29eaSKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
302613ef29eaSKashyap Desai 	mrioc->init_cmds.callback = NULL;
302713ef29eaSKashyap Desai 	evtnotify_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
302813ef29eaSKashyap Desai 	evtnotify_req.function = MPI3_FUNCTION_EVENT_NOTIFICATION;
302913ef29eaSKashyap Desai 	for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
303013ef29eaSKashyap Desai 		evtnotify_req.event_masks[i] =
303113ef29eaSKashyap Desai 		    cpu_to_le32(mrioc->event_masks[i]);
303213ef29eaSKashyap Desai 	init_completion(&mrioc->init_cmds.done);
303313ef29eaSKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &evtnotify_req,
303413ef29eaSKashyap Desai 	    sizeof(evtnotify_req), 1);
303513ef29eaSKashyap Desai 	if (retval) {
303613ef29eaSKashyap Desai 		ioc_err(mrioc, "Issue EvtNotify: Admin Post failed\n");
303713ef29eaSKashyap Desai 		goto out_unlock;
303813ef29eaSKashyap Desai 	}
303913ef29eaSKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
304013ef29eaSKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
304113ef29eaSKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
3042a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "event notification timed out\n");
3043a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
304413ef29eaSKashyap Desai 		    MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT);
304513ef29eaSKashyap Desai 		retval = -1;
304613ef29eaSKashyap Desai 		goto out_unlock;
304713ef29eaSKashyap Desai 	}
304813ef29eaSKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
304913ef29eaSKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
305013ef29eaSKashyap Desai 		ioc_err(mrioc,
305113ef29eaSKashyap Desai 		    "Issue EvtNotify: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
305213ef29eaSKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
305313ef29eaSKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
305413ef29eaSKashyap Desai 		retval = -1;
305513ef29eaSKashyap Desai 		goto out_unlock;
305613ef29eaSKashyap Desai 	}
305713ef29eaSKashyap Desai 
305813ef29eaSKashyap Desai out_unlock:
305913ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
306013ef29eaSKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
306113ef29eaSKashyap Desai out:
306213ef29eaSKashyap Desai 	return retval;
306313ef29eaSKashyap Desai }
306413ef29eaSKashyap Desai 
306513ef29eaSKashyap Desai /**
3066c1af985dSSreekanth Reddy  * mpi3mr_process_event_ack - Process event acknowledgment
306713ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
306813ef29eaSKashyap Desai  * @event: MPI3 event ID
3069c1af985dSSreekanth Reddy  * @event_ctx: event context
307013ef29eaSKashyap Desai  *
307113ef29eaSKashyap Desai  * Send event acknowledgment through admin queue and wait for
307213ef29eaSKashyap Desai  * it to complete.
307313ef29eaSKashyap Desai  *
307413ef29eaSKashyap Desai  * Return: 0 on success, non-zero on failures.
307513ef29eaSKashyap Desai  */
3076c1af985dSSreekanth Reddy int mpi3mr_process_event_ack(struct mpi3mr_ioc *mrioc, u8 event,
307713ef29eaSKashyap Desai 	u32 event_ctx)
307813ef29eaSKashyap Desai {
307913ef29eaSKashyap Desai 	struct mpi3_event_ack_request evtack_req;
308013ef29eaSKashyap Desai 	int retval = 0;
308113ef29eaSKashyap Desai 
308213ef29eaSKashyap Desai 	memset(&evtack_req, 0, sizeof(evtack_req));
308313ef29eaSKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
308413ef29eaSKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
308513ef29eaSKashyap Desai 		retval = -1;
308613ef29eaSKashyap Desai 		ioc_err(mrioc, "Send EvtAck: Init command is in use\n");
308713ef29eaSKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
308813ef29eaSKashyap Desai 		goto out;
308913ef29eaSKashyap Desai 	}
309013ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
309113ef29eaSKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
309213ef29eaSKashyap Desai 	mrioc->init_cmds.callback = NULL;
309313ef29eaSKashyap Desai 	evtack_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
309413ef29eaSKashyap Desai 	evtack_req.function = MPI3_FUNCTION_EVENT_ACK;
309513ef29eaSKashyap Desai 	evtack_req.event = event;
309613ef29eaSKashyap Desai 	evtack_req.event_context = cpu_to_le32(event_ctx);
309713ef29eaSKashyap Desai 
309813ef29eaSKashyap Desai 	init_completion(&mrioc->init_cmds.done);
309913ef29eaSKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &evtack_req,
310013ef29eaSKashyap Desai 	    sizeof(evtack_req), 1);
310113ef29eaSKashyap Desai 	if (retval) {
310213ef29eaSKashyap Desai 		ioc_err(mrioc, "Send EvtAck: Admin Post failed\n");
310313ef29eaSKashyap Desai 		goto out_unlock;
310413ef29eaSKashyap Desai 	}
310513ef29eaSKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
310613ef29eaSKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
310713ef29eaSKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
310813ef29eaSKashyap Desai 		ioc_err(mrioc, "Issue EvtNotify: command timed out\n");
3109fbaa9aa4SSreekanth Reddy 		if (!(mrioc->init_cmds.state & MPI3MR_CMD_RESET))
311013ef29eaSKashyap Desai 			mpi3mr_soft_reset_handler(mrioc,
311113ef29eaSKashyap Desai 			    MPI3MR_RESET_FROM_EVTACK_TIMEOUT, 1);
311213ef29eaSKashyap Desai 		retval = -1;
311313ef29eaSKashyap Desai 		goto out_unlock;
311413ef29eaSKashyap Desai 	}
311513ef29eaSKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
311613ef29eaSKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
311713ef29eaSKashyap Desai 		ioc_err(mrioc,
311813ef29eaSKashyap Desai 		    "Send EvtAck: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
311913ef29eaSKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
312013ef29eaSKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
312113ef29eaSKashyap Desai 		retval = -1;
312213ef29eaSKashyap Desai 		goto out_unlock;
312313ef29eaSKashyap Desai 	}
312413ef29eaSKashyap Desai 
312513ef29eaSKashyap Desai out_unlock:
312613ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
312713ef29eaSKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
312813ef29eaSKashyap Desai out:
312913ef29eaSKashyap Desai 	return retval;
313013ef29eaSKashyap Desai }
313113ef29eaSKashyap Desai 
313213ef29eaSKashyap Desai /**
3133824a1566SKashyap Desai  * mpi3mr_alloc_chain_bufs - Allocate chain buffers
3134824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3135824a1566SKashyap Desai  *
3136824a1566SKashyap Desai  * Allocate chain buffers and set a bitmap to indicate free
3137824a1566SKashyap Desai  * chain buffers. Chain buffers are used to pass the SGE
3138824a1566SKashyap Desai  * information along with MPI3 SCSI IO requests for host I/O.
3139824a1566SKashyap Desai  *
3140824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure
3141824a1566SKashyap Desai  */
3142824a1566SKashyap Desai static int mpi3mr_alloc_chain_bufs(struct mpi3mr_ioc *mrioc)
3143824a1566SKashyap Desai {
3144824a1566SKashyap Desai 	int retval = 0;
3145824a1566SKashyap Desai 	u32 sz, i;
3146824a1566SKashyap Desai 	u16 num_chains;
3147824a1566SKashyap Desai 
3148fe6db615SSreekanth Reddy 	if (mrioc->chain_sgl_list)
3149fe6db615SSreekanth Reddy 		return retval;
3150fe6db615SSreekanth Reddy 
3151824a1566SKashyap Desai 	num_chains = mrioc->max_host_ios / MPI3MR_CHAINBUF_FACTOR;
3152824a1566SKashyap Desai 
315374e1f30aSKashyap Desai 	if (prot_mask & (SHOST_DIX_TYPE0_PROTECTION
315474e1f30aSKashyap Desai 	    | SHOST_DIX_TYPE1_PROTECTION
315574e1f30aSKashyap Desai 	    | SHOST_DIX_TYPE2_PROTECTION
315674e1f30aSKashyap Desai 	    | SHOST_DIX_TYPE3_PROTECTION))
315774e1f30aSKashyap Desai 		num_chains += (num_chains / MPI3MR_CHAINBUFDIX_FACTOR);
315874e1f30aSKashyap Desai 
3159824a1566SKashyap Desai 	mrioc->chain_buf_count = num_chains;
3160824a1566SKashyap Desai 	sz = sizeof(struct chain_element) * num_chains;
3161824a1566SKashyap Desai 	mrioc->chain_sgl_list = kzalloc(sz, GFP_KERNEL);
3162824a1566SKashyap Desai 	if (!mrioc->chain_sgl_list)
3163824a1566SKashyap Desai 		goto out_failed;
3164824a1566SKashyap Desai 
3165824a1566SKashyap Desai 	sz = MPI3MR_PAGE_SIZE_4K;
3166824a1566SKashyap Desai 	mrioc->chain_buf_pool = dma_pool_create("chain_buf pool",
3167824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 16, 0);
3168824a1566SKashyap Desai 	if (!mrioc->chain_buf_pool) {
3169824a1566SKashyap Desai 		ioc_err(mrioc, "chain buf pool: dma_pool_create failed\n");
3170824a1566SKashyap Desai 		goto out_failed;
3171824a1566SKashyap Desai 	}
3172824a1566SKashyap Desai 
3173824a1566SKashyap Desai 	for (i = 0; i < num_chains; i++) {
3174824a1566SKashyap Desai 		mrioc->chain_sgl_list[i].addr =
3175824a1566SKashyap Desai 		    dma_pool_zalloc(mrioc->chain_buf_pool, GFP_KERNEL,
3176824a1566SKashyap Desai 		    &mrioc->chain_sgl_list[i].dma_addr);
3177824a1566SKashyap Desai 
3178824a1566SKashyap Desai 		if (!mrioc->chain_sgl_list[i].addr)
3179824a1566SKashyap Desai 			goto out_failed;
3180824a1566SKashyap Desai 	}
3181824a1566SKashyap Desai 	mrioc->chain_bitmap_sz = num_chains / 8;
3182824a1566SKashyap Desai 	if (num_chains % 8)
3183824a1566SKashyap Desai 		mrioc->chain_bitmap_sz++;
3184824a1566SKashyap Desai 	mrioc->chain_bitmap = kzalloc(mrioc->chain_bitmap_sz, GFP_KERNEL);
3185824a1566SKashyap Desai 	if (!mrioc->chain_bitmap)
3186824a1566SKashyap Desai 		goto out_failed;
3187824a1566SKashyap Desai 	return retval;
3188824a1566SKashyap Desai out_failed:
3189824a1566SKashyap Desai 	retval = -1;
3190824a1566SKashyap Desai 	return retval;
3191824a1566SKashyap Desai }
3192824a1566SKashyap Desai 
3193824a1566SKashyap Desai /**
3194023ab2a9SKashyap Desai  * mpi3mr_port_enable_complete - Mark port enable complete
3195023ab2a9SKashyap Desai  * @mrioc: Adapter instance reference
3196023ab2a9SKashyap Desai  * @drv_cmd: Internal command tracker
3197023ab2a9SKashyap Desai  *
3198023ab2a9SKashyap Desai  * Call back for asynchronous port enable request sets the
3199023ab2a9SKashyap Desai  * driver command to indicate port enable request is complete.
3200023ab2a9SKashyap Desai  *
3201023ab2a9SKashyap Desai  * Return: Nothing
3202023ab2a9SKashyap Desai  */
3203023ab2a9SKashyap Desai static void mpi3mr_port_enable_complete(struct mpi3mr_ioc *mrioc,
3204023ab2a9SKashyap Desai 	struct mpi3mr_drv_cmd *drv_cmd)
3205023ab2a9SKashyap Desai {
3206023ab2a9SKashyap Desai 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
3207023ab2a9SKashyap Desai 	drv_cmd->callback = NULL;
3208023ab2a9SKashyap Desai 	mrioc->scan_failed = drv_cmd->ioc_status;
3209023ab2a9SKashyap Desai 	mrioc->scan_started = 0;
3210023ab2a9SKashyap Desai }
3211023ab2a9SKashyap Desai 
3212023ab2a9SKashyap Desai /**
3213023ab2a9SKashyap Desai  * mpi3mr_issue_port_enable - Issue Port Enable
3214023ab2a9SKashyap Desai  * @mrioc: Adapter instance reference
3215023ab2a9SKashyap Desai  * @async: Flag to wait for completion or not
3216023ab2a9SKashyap Desai  *
3217023ab2a9SKashyap Desai  * Issue Port Enable MPI request through admin queue and if the
3218023ab2a9SKashyap Desai  * async flag is not set wait for the completion of the port
3219023ab2a9SKashyap Desai  * enable or time out.
3220023ab2a9SKashyap Desai  *
3221023ab2a9SKashyap Desai  * Return: 0 on success, non-zero on failures.
3222023ab2a9SKashyap Desai  */
3223023ab2a9SKashyap Desai int mpi3mr_issue_port_enable(struct mpi3mr_ioc *mrioc, u8 async)
3224023ab2a9SKashyap Desai {
3225023ab2a9SKashyap Desai 	struct mpi3_port_enable_request pe_req;
3226023ab2a9SKashyap Desai 	int retval = 0;
3227023ab2a9SKashyap Desai 	u32 pe_timeout = MPI3MR_PORTENABLE_TIMEOUT;
3228023ab2a9SKashyap Desai 
3229023ab2a9SKashyap Desai 	memset(&pe_req, 0, sizeof(pe_req));
3230023ab2a9SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
3231023ab2a9SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
3232023ab2a9SKashyap Desai 		retval = -1;
3233023ab2a9SKashyap Desai 		ioc_err(mrioc, "Issue PortEnable: Init command is in use\n");
3234023ab2a9SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
3235023ab2a9SKashyap Desai 		goto out;
3236023ab2a9SKashyap Desai 	}
3237023ab2a9SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
3238023ab2a9SKashyap Desai 	if (async) {
3239023ab2a9SKashyap Desai 		mrioc->init_cmds.is_waiting = 0;
3240023ab2a9SKashyap Desai 		mrioc->init_cmds.callback = mpi3mr_port_enable_complete;
3241023ab2a9SKashyap Desai 	} else {
3242023ab2a9SKashyap Desai 		mrioc->init_cmds.is_waiting = 1;
3243023ab2a9SKashyap Desai 		mrioc->init_cmds.callback = NULL;
3244023ab2a9SKashyap Desai 		init_completion(&mrioc->init_cmds.done);
3245023ab2a9SKashyap Desai 	}
3246023ab2a9SKashyap Desai 	pe_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
3247023ab2a9SKashyap Desai 	pe_req.function = MPI3_FUNCTION_PORT_ENABLE;
3248023ab2a9SKashyap Desai 
3249023ab2a9SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &pe_req, sizeof(pe_req), 1);
3250023ab2a9SKashyap Desai 	if (retval) {
3251023ab2a9SKashyap Desai 		ioc_err(mrioc, "Issue PortEnable: Admin Post failed\n");
3252023ab2a9SKashyap Desai 		goto out_unlock;
3253023ab2a9SKashyap Desai 	}
3254a6856cc4SSreekanth Reddy 	if (async) {
3255a6856cc4SSreekanth Reddy 		mutex_unlock(&mrioc->init_cmds.mutex);
3256a6856cc4SSreekanth Reddy 		goto out;
3257a6856cc4SSreekanth Reddy 	}
3258a6856cc4SSreekanth Reddy 
3259a6856cc4SSreekanth Reddy 	wait_for_completion_timeout(&mrioc->init_cmds.done, (pe_timeout * HZ));
3260023ab2a9SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
3261a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "port enable timed out\n");
3262023ab2a9SKashyap Desai 		retval = -1;
3263a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc, MPI3MR_RESET_FROM_PE_TIMEOUT);
3264023ab2a9SKashyap Desai 		goto out_unlock;
3265023ab2a9SKashyap Desai 	}
3266023ab2a9SKashyap Desai 	mpi3mr_port_enable_complete(mrioc, &mrioc->init_cmds);
3267a6856cc4SSreekanth Reddy 
3268023ab2a9SKashyap Desai out_unlock:
3269a6856cc4SSreekanth Reddy 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
3270023ab2a9SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
3271023ab2a9SKashyap Desai out:
3272023ab2a9SKashyap Desai 	return retval;
3273023ab2a9SKashyap Desai }
3274023ab2a9SKashyap Desai 
3275ff9561e9SKashyap Desai /* Protocol type to name mapper structure */
3276ff9561e9SKashyap Desai static const struct {
3277ff9561e9SKashyap Desai 	u8 protocol;
3278ff9561e9SKashyap Desai 	char *name;
3279ff9561e9SKashyap Desai } mpi3mr_protocols[] = {
3280ff9561e9SKashyap Desai 	{ MPI3_IOCFACTS_PROTOCOL_SCSI_INITIATOR, "Initiator" },
3281ff9561e9SKashyap Desai 	{ MPI3_IOCFACTS_PROTOCOL_SCSI_TARGET, "Target" },
3282ff9561e9SKashyap Desai 	{ MPI3_IOCFACTS_PROTOCOL_NVME, "NVMe attachment" },
3283ff9561e9SKashyap Desai };
3284ff9561e9SKashyap Desai 
3285ff9561e9SKashyap Desai /* Capability to name mapper structure*/
3286ff9561e9SKashyap Desai static const struct {
3287ff9561e9SKashyap Desai 	u32 capability;
3288ff9561e9SKashyap Desai 	char *name;
3289ff9561e9SKashyap Desai } mpi3mr_capabilities[] = {
3290ff9561e9SKashyap Desai 	{ MPI3_IOCFACTS_CAPABILITY_RAID_CAPABLE, "RAID" },
3291ff9561e9SKashyap Desai };
3292ff9561e9SKashyap Desai 
3293ff9561e9SKashyap Desai /**
3294ff9561e9SKashyap Desai  * mpi3mr_print_ioc_info - Display controller information
3295ff9561e9SKashyap Desai  * @mrioc: Adapter instance reference
3296ff9561e9SKashyap Desai  *
3297ff9561e9SKashyap Desai  * Display controller personalit, capability, supported
3298ff9561e9SKashyap Desai  * protocols etc.
3299ff9561e9SKashyap Desai  *
3300ff9561e9SKashyap Desai  * Return: Nothing
3301ff9561e9SKashyap Desai  */
3302ff9561e9SKashyap Desai static void
3303ff9561e9SKashyap Desai mpi3mr_print_ioc_info(struct mpi3mr_ioc *mrioc)
3304ff9561e9SKashyap Desai {
330576a4f7ccSDan Carpenter 	int i = 0, bytes_written = 0;
3306ff9561e9SKashyap Desai 	char personality[16];
3307ff9561e9SKashyap Desai 	char protocol[50] = {0};
3308ff9561e9SKashyap Desai 	char capabilities[100] = {0};
3309ff9561e9SKashyap Desai 	struct mpi3mr_compimg_ver *fwver = &mrioc->facts.fw_ver;
3310ff9561e9SKashyap Desai 
3311ff9561e9SKashyap Desai 	switch (mrioc->facts.personality) {
3312ff9561e9SKashyap Desai 	case MPI3_IOCFACTS_FLAGS_PERSONALITY_EHBA:
3313ff9561e9SKashyap Desai 		strncpy(personality, "Enhanced HBA", sizeof(personality));
3314ff9561e9SKashyap Desai 		break;
3315ff9561e9SKashyap Desai 	case MPI3_IOCFACTS_FLAGS_PERSONALITY_RAID_DDR:
3316ff9561e9SKashyap Desai 		strncpy(personality, "RAID", sizeof(personality));
3317ff9561e9SKashyap Desai 		break;
3318ff9561e9SKashyap Desai 	default:
3319ff9561e9SKashyap Desai 		strncpy(personality, "Unknown", sizeof(personality));
3320ff9561e9SKashyap Desai 		break;
3321ff9561e9SKashyap Desai 	}
3322ff9561e9SKashyap Desai 
3323ff9561e9SKashyap Desai 	ioc_info(mrioc, "Running in %s Personality", personality);
3324ff9561e9SKashyap Desai 
3325ff9561e9SKashyap Desai 	ioc_info(mrioc, "FW version(%d.%d.%d.%d.%d.%d)\n",
3326ff9561e9SKashyap Desai 	    fwver->gen_major, fwver->gen_minor, fwver->ph_major,
3327ff9561e9SKashyap Desai 	    fwver->ph_minor, fwver->cust_id, fwver->build_num);
3328ff9561e9SKashyap Desai 
3329ff9561e9SKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mpi3mr_protocols); i++) {
3330ff9561e9SKashyap Desai 		if (mrioc->facts.protocol_flags &
3331ff9561e9SKashyap Desai 		    mpi3mr_protocols[i].protocol) {
333230e99f05SDan Carpenter 			bytes_written += scnprintf(protocol + bytes_written,
333376a4f7ccSDan Carpenter 				    sizeof(protocol) - bytes_written, "%s%s",
333476a4f7ccSDan Carpenter 				    bytes_written ? "," : "",
3335ff9561e9SKashyap Desai 				    mpi3mr_protocols[i].name);
3336ff9561e9SKashyap Desai 		}
3337ff9561e9SKashyap Desai 	}
3338ff9561e9SKashyap Desai 
333976a4f7ccSDan Carpenter 	bytes_written = 0;
3340ff9561e9SKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mpi3mr_capabilities); i++) {
3341ff9561e9SKashyap Desai 		if (mrioc->facts.protocol_flags &
3342ff9561e9SKashyap Desai 		    mpi3mr_capabilities[i].capability) {
334330e99f05SDan Carpenter 			bytes_written += scnprintf(capabilities + bytes_written,
334476a4f7ccSDan Carpenter 				    sizeof(capabilities) - bytes_written, "%s%s",
334576a4f7ccSDan Carpenter 				    bytes_written ? "," : "",
3346ff9561e9SKashyap Desai 				    mpi3mr_capabilities[i].name);
3347ff9561e9SKashyap Desai 		}
3348ff9561e9SKashyap Desai 	}
3349ff9561e9SKashyap Desai 
3350ff9561e9SKashyap Desai 	ioc_info(mrioc, "Protocol=(%s), Capabilities=(%s)\n",
3351ff9561e9SKashyap Desai 		 protocol, capabilities);
3352ff9561e9SKashyap Desai }
3353ff9561e9SKashyap Desai 
3354023ab2a9SKashyap Desai /**
3355824a1566SKashyap Desai  * mpi3mr_cleanup_resources - Free PCI resources
3356824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3357824a1566SKashyap Desai  *
3358824a1566SKashyap Desai  * Unmap PCI device memory and disable PCI device.
3359824a1566SKashyap Desai  *
3360824a1566SKashyap Desai  * Return: 0 on success and non-zero on failure.
3361824a1566SKashyap Desai  */
3362824a1566SKashyap Desai void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc)
3363824a1566SKashyap Desai {
3364824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
3365824a1566SKashyap Desai 
3366824a1566SKashyap Desai 	mpi3mr_cleanup_isr(mrioc);
3367824a1566SKashyap Desai 
3368824a1566SKashyap Desai 	if (mrioc->sysif_regs) {
3369824a1566SKashyap Desai 		iounmap((void __iomem *)mrioc->sysif_regs);
3370824a1566SKashyap Desai 		mrioc->sysif_regs = NULL;
3371824a1566SKashyap Desai 	}
3372824a1566SKashyap Desai 
3373824a1566SKashyap Desai 	if (pci_is_enabled(pdev)) {
3374824a1566SKashyap Desai 		if (mrioc->bars)
3375824a1566SKashyap Desai 			pci_release_selected_regions(pdev, mrioc->bars);
3376824a1566SKashyap Desai 		pci_disable_device(pdev);
3377824a1566SKashyap Desai 	}
3378824a1566SKashyap Desai }
3379824a1566SKashyap Desai 
3380824a1566SKashyap Desai /**
3381824a1566SKashyap Desai  * mpi3mr_setup_resources - Enable PCI resources
3382824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3383824a1566SKashyap Desai  *
3384824a1566SKashyap Desai  * Enable PCI device memory, MSI-x registers and set DMA mask.
3385824a1566SKashyap Desai  *
3386824a1566SKashyap Desai  * Return: 0 on success and non-zero on failure.
3387824a1566SKashyap Desai  */
3388824a1566SKashyap Desai int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc)
3389824a1566SKashyap Desai {
3390824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
3391824a1566SKashyap Desai 	u32 memap_sz = 0;
3392824a1566SKashyap Desai 	int i, retval = 0, capb = 0;
3393824a1566SKashyap Desai 	u16 message_control;
3394824a1566SKashyap Desai 	u64 dma_mask = mrioc->dma_mask ? mrioc->dma_mask :
3395824a1566SKashyap Desai 	    (((dma_get_required_mask(&pdev->dev) > DMA_BIT_MASK(32)) &&
3396824a1566SKashyap Desai 	    (sizeof(dma_addr_t) > 4)) ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32));
3397824a1566SKashyap Desai 
3398824a1566SKashyap Desai 	if (pci_enable_device_mem(pdev)) {
3399824a1566SKashyap Desai 		ioc_err(mrioc, "pci_enable_device_mem: failed\n");
3400824a1566SKashyap Desai 		retval = -ENODEV;
3401824a1566SKashyap Desai 		goto out_failed;
3402824a1566SKashyap Desai 	}
3403824a1566SKashyap Desai 
3404824a1566SKashyap Desai 	capb = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
3405824a1566SKashyap Desai 	if (!capb) {
3406824a1566SKashyap Desai 		ioc_err(mrioc, "Unable to find MSI-X Capabilities\n");
3407824a1566SKashyap Desai 		retval = -ENODEV;
3408824a1566SKashyap Desai 		goto out_failed;
3409824a1566SKashyap Desai 	}
3410824a1566SKashyap Desai 	mrioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
3411824a1566SKashyap Desai 
3412824a1566SKashyap Desai 	if (pci_request_selected_regions(pdev, mrioc->bars,
3413824a1566SKashyap Desai 	    mrioc->driver_name)) {
3414824a1566SKashyap Desai 		ioc_err(mrioc, "pci_request_selected_regions: failed\n");
3415824a1566SKashyap Desai 		retval = -ENODEV;
3416824a1566SKashyap Desai 		goto out_failed;
3417824a1566SKashyap Desai 	}
3418824a1566SKashyap Desai 
3419824a1566SKashyap Desai 	for (i = 0; (i < DEVICE_COUNT_RESOURCE); i++) {
3420824a1566SKashyap Desai 		if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
3421824a1566SKashyap Desai 			mrioc->sysif_regs_phys = pci_resource_start(pdev, i);
3422824a1566SKashyap Desai 			memap_sz = pci_resource_len(pdev, i);
3423824a1566SKashyap Desai 			mrioc->sysif_regs =
3424824a1566SKashyap Desai 			    ioremap(mrioc->sysif_regs_phys, memap_sz);
3425824a1566SKashyap Desai 			break;
3426824a1566SKashyap Desai 		}
3427824a1566SKashyap Desai 	}
3428824a1566SKashyap Desai 
3429824a1566SKashyap Desai 	pci_set_master(pdev);
3430824a1566SKashyap Desai 
3431824a1566SKashyap Desai 	retval = dma_set_mask_and_coherent(&pdev->dev, dma_mask);
3432824a1566SKashyap Desai 	if (retval) {
3433824a1566SKashyap Desai 		if (dma_mask != DMA_BIT_MASK(32)) {
3434824a1566SKashyap Desai 			ioc_warn(mrioc, "Setting 64 bit DMA mask failed\n");
3435824a1566SKashyap Desai 			dma_mask = DMA_BIT_MASK(32);
3436824a1566SKashyap Desai 			retval = dma_set_mask_and_coherent(&pdev->dev,
3437824a1566SKashyap Desai 			    dma_mask);
3438824a1566SKashyap Desai 		}
3439824a1566SKashyap Desai 		if (retval) {
3440824a1566SKashyap Desai 			mrioc->dma_mask = 0;
3441824a1566SKashyap Desai 			ioc_err(mrioc, "Setting 32 bit DMA mask also failed\n");
3442824a1566SKashyap Desai 			goto out_failed;
3443824a1566SKashyap Desai 		}
3444824a1566SKashyap Desai 	}
3445824a1566SKashyap Desai 	mrioc->dma_mask = dma_mask;
3446824a1566SKashyap Desai 
3447824a1566SKashyap Desai 	if (!mrioc->sysif_regs) {
3448824a1566SKashyap Desai 		ioc_err(mrioc,
3449824a1566SKashyap Desai 		    "Unable to map adapter memory or resource not found\n");
3450824a1566SKashyap Desai 		retval = -EINVAL;
3451824a1566SKashyap Desai 		goto out_failed;
3452824a1566SKashyap Desai 	}
3453824a1566SKashyap Desai 
3454824a1566SKashyap Desai 	pci_read_config_word(pdev, capb + 2, &message_control);
3455824a1566SKashyap Desai 	mrioc->msix_count = (message_control & 0x3FF) + 1;
3456824a1566SKashyap Desai 
3457824a1566SKashyap Desai 	pci_save_state(pdev);
3458824a1566SKashyap Desai 
3459824a1566SKashyap Desai 	pci_set_drvdata(pdev, mrioc->shost);
3460824a1566SKashyap Desai 
3461824a1566SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
3462824a1566SKashyap Desai 
3463824a1566SKashyap Desai 	ioc_info(mrioc, "iomem(0x%016llx), mapped(0x%p), size(%d)\n",
3464824a1566SKashyap Desai 	    (unsigned long long)mrioc->sysif_regs_phys,
3465824a1566SKashyap Desai 	    mrioc->sysif_regs, memap_sz);
3466824a1566SKashyap Desai 	ioc_info(mrioc, "Number of MSI-X vectors found in capabilities: (%d)\n",
3467824a1566SKashyap Desai 	    mrioc->msix_count);
3468824a1566SKashyap Desai 	return retval;
3469824a1566SKashyap Desai 
3470824a1566SKashyap Desai out_failed:
3471824a1566SKashyap Desai 	mpi3mr_cleanup_resources(mrioc);
3472824a1566SKashyap Desai 	return retval;
3473824a1566SKashyap Desai }
3474824a1566SKashyap Desai 
3475824a1566SKashyap Desai /**
3476e3605f65SSreekanth Reddy  * mpi3mr_enable_events - Enable required events
3477e3605f65SSreekanth Reddy  * @mrioc: Adapter instance reference
3478e3605f65SSreekanth Reddy  *
3479e3605f65SSreekanth Reddy  * This routine unmasks the events required by the driver by
3480e3605f65SSreekanth Reddy  * sennding appropriate event mask bitmapt through an event
3481e3605f65SSreekanth Reddy  * notification request.
3482e3605f65SSreekanth Reddy  *
3483e3605f65SSreekanth Reddy  * Return: 0 on success and non-zero on failure.
3484e3605f65SSreekanth Reddy  */
3485e3605f65SSreekanth Reddy static int mpi3mr_enable_events(struct mpi3mr_ioc *mrioc)
3486e3605f65SSreekanth Reddy {
3487e3605f65SSreekanth Reddy 	int retval = 0;
3488e3605f65SSreekanth Reddy 	u32  i;
3489e3605f65SSreekanth Reddy 
3490e3605f65SSreekanth Reddy 	for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
3491e3605f65SSreekanth Reddy 		mrioc->event_masks[i] = -1;
3492e3605f65SSreekanth Reddy 
3493e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_ADDED);
3494e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_INFO_CHANGED);
3495e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_STATUS_CHANGE);
3496e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE);
3497e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
3498e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DISCOVERY);
3499e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR);
3500e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_BROADCAST_PRIMITIVE);
3501e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST);
3502e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_ENUMERATION);
3503*78b76a07SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_PREPARE_FOR_RESET);
3504e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_CABLE_MGMT);
3505e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENERGY_PACK_CHANGE);
3506e3605f65SSreekanth Reddy 
3507e3605f65SSreekanth Reddy 	retval = mpi3mr_issue_event_notification(mrioc);
3508e3605f65SSreekanth Reddy 	if (retval)
3509e3605f65SSreekanth Reddy 		ioc_err(mrioc, "failed to issue event notification %d\n",
3510e3605f65SSreekanth Reddy 		    retval);
3511e3605f65SSreekanth Reddy 	return retval;
3512e3605f65SSreekanth Reddy }
3513e3605f65SSreekanth Reddy 
3514e3605f65SSreekanth Reddy /**
3515824a1566SKashyap Desai  * mpi3mr_init_ioc - Initialize the controller
3516824a1566SKashyap Desai  * @mrioc: Adapter instance reference
35170da66348SKashyap Desai  * @init_type: Flag to indicate is the init_type
3518824a1566SKashyap Desai  *
3519824a1566SKashyap Desai  * This the controller initialization routine, executed either
3520824a1566SKashyap Desai  * after soft reset or from pci probe callback.
3521824a1566SKashyap Desai  * Setup the required resources, memory map the controller
3522824a1566SKashyap Desai  * registers, create admin and operational reply queue pairs,
3523824a1566SKashyap Desai  * allocate required memory for reply pool, sense buffer pool,
3524824a1566SKashyap Desai  * issue IOC init request to the firmware, unmask the events and
3525824a1566SKashyap Desai  * issue port enable to discover SAS/SATA/NVMe devies and RAID
3526824a1566SKashyap Desai  * volumes.
3527824a1566SKashyap Desai  *
3528824a1566SKashyap Desai  * Return: 0 on success and non-zero on failure.
3529824a1566SKashyap Desai  */
3530fe6db615SSreekanth Reddy int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc)
3531824a1566SKashyap Desai {
3532824a1566SKashyap Desai 	int retval = 0;
3533fe6db615SSreekanth Reddy 	u8 retry = 0;
3534824a1566SKashyap Desai 	struct mpi3_ioc_facts_data facts_data;
3535824a1566SKashyap Desai 
3536fe6db615SSreekanth Reddy retry_init:
3537824a1566SKashyap Desai 	retval = mpi3mr_bring_ioc_ready(mrioc);
3538824a1566SKashyap Desai 	if (retval) {
3539824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to bring ioc ready: error %d\n",
3540824a1566SKashyap Desai 		    retval);
3541fe6db615SSreekanth Reddy 		goto out_failed_noretry;
3542824a1566SKashyap Desai 	}
3543824a1566SKashyap Desai 
3544824a1566SKashyap Desai 	retval = mpi3mr_setup_isr(mrioc, 1);
3545824a1566SKashyap Desai 	if (retval) {
3546824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to setup ISR error %d\n",
3547824a1566SKashyap Desai 		    retval);
3548fe6db615SSreekanth Reddy 		goto out_failed_noretry;
3549824a1566SKashyap Desai 	}
3550824a1566SKashyap Desai 
3551824a1566SKashyap Desai 	retval = mpi3mr_issue_iocfacts(mrioc, &facts_data);
3552824a1566SKashyap Desai 	if (retval) {
3553824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to Issue IOC Facts %d\n",
3554824a1566SKashyap Desai 		    retval);
3555824a1566SKashyap Desai 		goto out_failed;
3556824a1566SKashyap Desai 	}
3557824a1566SKashyap Desai 
3558c5758fc7SSreekanth Reddy 	mrioc->max_host_ios = mrioc->facts.max_reqs - MPI3MR_INTERNAL_CMDS_RESVD;
3559c5758fc7SSreekanth Reddy 
3560c5758fc7SSreekanth Reddy 	if (reset_devices)
3561c5758fc7SSreekanth Reddy 		mrioc->max_host_ios = min_t(int, mrioc->max_host_ios,
3562c5758fc7SSreekanth Reddy 		    MPI3MR_HOST_IOS_KDUMP);
3563c5758fc7SSreekanth Reddy 
3564c5758fc7SSreekanth Reddy 	mrioc->reply_sz = mrioc->facts.reply_sz;
3565fe6db615SSreekanth Reddy 
3566824a1566SKashyap Desai 	retval = mpi3mr_check_reset_dma_mask(mrioc);
3567824a1566SKashyap Desai 	if (retval) {
3568824a1566SKashyap Desai 		ioc_err(mrioc, "Resetting dma mask failed %d\n",
3569824a1566SKashyap Desai 		    retval);
3570fe6db615SSreekanth Reddy 		goto out_failed_noretry;
3571fb9b0457SKashyap Desai 	}
3572824a1566SKashyap Desai 
3573ff9561e9SKashyap Desai 	mpi3mr_print_ioc_info(mrioc);
3574ff9561e9SKashyap Desai 
3575824a1566SKashyap Desai 	retval = mpi3mr_alloc_reply_sense_bufs(mrioc);
3576824a1566SKashyap Desai 	if (retval) {
3577824a1566SKashyap Desai 		ioc_err(mrioc,
3578824a1566SKashyap Desai 		    "%s :Failed to allocated reply sense buffers %d\n",
3579824a1566SKashyap Desai 		    __func__, retval);
3580fe6db615SSreekanth Reddy 		goto out_failed_noretry;
3581824a1566SKashyap Desai 	}
3582824a1566SKashyap Desai 
3583824a1566SKashyap Desai 	retval = mpi3mr_alloc_chain_bufs(mrioc);
3584824a1566SKashyap Desai 	if (retval) {
3585824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to allocated chain buffers %d\n",
3586824a1566SKashyap Desai 		    retval);
3587fe6db615SSreekanth Reddy 		goto out_failed_noretry;
3588fb9b0457SKashyap Desai 	}
3589824a1566SKashyap Desai 
3590824a1566SKashyap Desai 	retval = mpi3mr_issue_iocinit(mrioc);
3591824a1566SKashyap Desai 	if (retval) {
3592824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to Issue IOC Init %d\n",
3593824a1566SKashyap Desai 		    retval);
3594824a1566SKashyap Desai 		goto out_failed;
3595824a1566SKashyap Desai 	}
3596824a1566SKashyap Desai 
35972ac794baSSreekanth Reddy 	retval = mpi3mr_print_pkg_ver(mrioc);
35982ac794baSSreekanth Reddy 	if (retval) {
35992ac794baSSreekanth Reddy 		ioc_err(mrioc, "failed to get package version\n");
36002ac794baSSreekanth Reddy 		goto out_failed;
36012ac794baSSreekanth Reddy 	}
36022ac794baSSreekanth Reddy 
3603824a1566SKashyap Desai 	retval = mpi3mr_setup_isr(mrioc, 0);
3604824a1566SKashyap Desai 	if (retval) {
3605824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to re-setup ISR, error %d\n",
3606824a1566SKashyap Desai 		    retval);
3607fe6db615SSreekanth Reddy 		goto out_failed_noretry;
3608fb9b0457SKashyap Desai 	}
3609824a1566SKashyap Desai 
3610c9566231SKashyap Desai 	retval = mpi3mr_create_op_queues(mrioc);
3611c9566231SKashyap Desai 	if (retval) {
3612c9566231SKashyap Desai 		ioc_err(mrioc, "Failed to create OpQueues error %d\n",
3613c9566231SKashyap Desai 		    retval);
3614c9566231SKashyap Desai 		goto out_failed;
3615c9566231SKashyap Desai 	}
3616c9566231SKashyap Desai 
3617e3605f65SSreekanth Reddy 	retval = mpi3mr_enable_events(mrioc);
361813ef29eaSKashyap Desai 	if (retval) {
3619e3605f65SSreekanth Reddy 		ioc_err(mrioc, "failed to enable events %d\n",
362013ef29eaSKashyap Desai 		    retval);
362113ef29eaSKashyap Desai 		goto out_failed;
362213ef29eaSKashyap Desai 	}
362313ef29eaSKashyap Desai 
3624fe6db615SSreekanth Reddy 	ioc_info(mrioc, "controller initialization completed successfully\n");
3625824a1566SKashyap Desai 	return retval;
3626824a1566SKashyap Desai out_failed:
3627fe6db615SSreekanth Reddy 	if (retry < 2) {
3628fe6db615SSreekanth Reddy 		retry++;
3629fe6db615SSreekanth Reddy 		ioc_warn(mrioc, "retrying controller initialization, retry_count:%d\n",
3630fe6db615SSreekanth Reddy 		    retry);
3631fe6db615SSreekanth Reddy 		mpi3mr_memset_buffers(mrioc);
3632fe6db615SSreekanth Reddy 		goto retry_init;
3633fe6db615SSreekanth Reddy 	}
3634fe6db615SSreekanth Reddy out_failed_noretry:
3635fe6db615SSreekanth Reddy 	ioc_err(mrioc, "controller initialization failed\n");
3636fe6db615SSreekanth Reddy 	mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
3637fe6db615SSreekanth Reddy 	    MPI3MR_RESET_FROM_CTLR_CLEANUP);
3638fe6db615SSreekanth Reddy 	mrioc->unrecoverable = 1;
3639824a1566SKashyap Desai 	return retval;
3640824a1566SKashyap Desai }
3641824a1566SKashyap Desai 
3642c0b00a93SSreekanth Reddy /**
3643c0b00a93SSreekanth Reddy  * mpi3mr_reinit_ioc - Re-Initialize the controller
3644c0b00a93SSreekanth Reddy  * @mrioc: Adapter instance reference
3645c0b00a93SSreekanth Reddy  * @is_resume: Called from resume or reset path
3646c0b00a93SSreekanth Reddy  *
3647c0b00a93SSreekanth Reddy  * This the controller re-initialization routine, executed from
3648c0b00a93SSreekanth Reddy  * the soft reset handler or resume callback. Creates
3649c0b00a93SSreekanth Reddy  * operational reply queue pairs, allocate required memory for
3650c0b00a93SSreekanth Reddy  * reply pool, sense buffer pool, issue IOC init request to the
3651c0b00a93SSreekanth Reddy  * firmware, unmask the events and issue port enable to discover
3652c0b00a93SSreekanth Reddy  * SAS/SATA/NVMe devices and RAID volumes.
3653c0b00a93SSreekanth Reddy  *
3654c0b00a93SSreekanth Reddy  * Return: 0 on success and non-zero on failure.
3655c0b00a93SSreekanth Reddy  */
3656fe6db615SSreekanth Reddy int mpi3mr_reinit_ioc(struct mpi3mr_ioc *mrioc, u8 is_resume)
3657fe6db615SSreekanth Reddy {
3658c0b00a93SSreekanth Reddy 	int retval = 0;
3659c0b00a93SSreekanth Reddy 	u8 retry = 0;
3660c0b00a93SSreekanth Reddy 	struct mpi3_ioc_facts_data facts_data;
3661fe6db615SSreekanth Reddy 
3662c0b00a93SSreekanth Reddy retry_init:
3663c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "bringing up the controller to ready state\n");
3664c0b00a93SSreekanth Reddy 	retval = mpi3mr_bring_ioc_ready(mrioc);
3665c0b00a93SSreekanth Reddy 	if (retval) {
3666c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to bring to ready state\n");
3667c0b00a93SSreekanth Reddy 		goto out_failed_noretry;
3668c0b00a93SSreekanth Reddy 	}
3669c0b00a93SSreekanth Reddy 
3670c0b00a93SSreekanth Reddy 	if (is_resume) {
3671c0b00a93SSreekanth Reddy 		dprint_reset(mrioc, "setting up single ISR\n");
3672c0b00a93SSreekanth Reddy 		retval = mpi3mr_setup_isr(mrioc, 1);
3673c0b00a93SSreekanth Reddy 		if (retval) {
3674c0b00a93SSreekanth Reddy 			ioc_err(mrioc, "failed to setup ISR\n");
3675c0b00a93SSreekanth Reddy 			goto out_failed_noretry;
3676c0b00a93SSreekanth Reddy 		}
3677c0b00a93SSreekanth Reddy 	} else
3678c0b00a93SSreekanth Reddy 		mpi3mr_ioc_enable_intr(mrioc);
3679c0b00a93SSreekanth Reddy 
3680c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "getting ioc_facts\n");
3681c0b00a93SSreekanth Reddy 	retval = mpi3mr_issue_iocfacts(mrioc, &facts_data);
3682c0b00a93SSreekanth Reddy 	if (retval) {
3683c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to get ioc_facts\n");
3684c0b00a93SSreekanth Reddy 		goto out_failed;
3685c0b00a93SSreekanth Reddy 	}
3686c0b00a93SSreekanth Reddy 
3687c5758fc7SSreekanth Reddy 	dprint_reset(mrioc, "validating ioc_facts\n");
3688c5758fc7SSreekanth Reddy 	retval = mpi3mr_revalidate_factsdata(mrioc);
3689c5758fc7SSreekanth Reddy 	if (retval) {
3690c5758fc7SSreekanth Reddy 		ioc_err(mrioc, "failed to revalidate ioc_facts data\n");
3691c5758fc7SSreekanth Reddy 		goto out_failed_noretry;
3692c5758fc7SSreekanth Reddy 	}
3693c0b00a93SSreekanth Reddy 
3694c0b00a93SSreekanth Reddy 	mpi3mr_print_ioc_info(mrioc);
3695c0b00a93SSreekanth Reddy 
3696c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "sending ioc_init\n");
3697c0b00a93SSreekanth Reddy 	retval = mpi3mr_issue_iocinit(mrioc);
3698c0b00a93SSreekanth Reddy 	if (retval) {
3699c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to send ioc_init\n");
3700c0b00a93SSreekanth Reddy 		goto out_failed;
3701c0b00a93SSreekanth Reddy 	}
3702c0b00a93SSreekanth Reddy 
3703c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "getting package version\n");
3704c0b00a93SSreekanth Reddy 	retval = mpi3mr_print_pkg_ver(mrioc);
3705c0b00a93SSreekanth Reddy 	if (retval) {
3706c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to get package version\n");
3707c0b00a93SSreekanth Reddy 		goto out_failed;
3708c0b00a93SSreekanth Reddy 	}
3709c0b00a93SSreekanth Reddy 
3710c0b00a93SSreekanth Reddy 	if (is_resume) {
3711c0b00a93SSreekanth Reddy 		dprint_reset(mrioc, "setting up multiple ISR\n");
3712c0b00a93SSreekanth Reddy 		retval = mpi3mr_setup_isr(mrioc, 0);
3713c0b00a93SSreekanth Reddy 		if (retval) {
3714c0b00a93SSreekanth Reddy 			ioc_err(mrioc, "failed to re-setup ISR\n");
3715c0b00a93SSreekanth Reddy 			goto out_failed_noretry;
3716c0b00a93SSreekanth Reddy 		}
3717c0b00a93SSreekanth Reddy 	}
3718c0b00a93SSreekanth Reddy 
3719c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "creating operational queue pairs\n");
3720c0b00a93SSreekanth Reddy 	retval = mpi3mr_create_op_queues(mrioc);
3721c0b00a93SSreekanth Reddy 	if (retval) {
3722c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to create operational queue pairs\n");
3723c0b00a93SSreekanth Reddy 		goto out_failed;
3724c0b00a93SSreekanth Reddy 	}
3725c0b00a93SSreekanth Reddy 
3726c0b00a93SSreekanth Reddy 	if (mrioc->shost->nr_hw_queues > mrioc->num_op_reply_q) {
3727c0b00a93SSreekanth Reddy 		ioc_err(mrioc,
3728c0b00a93SSreekanth Reddy 		    "cannot create minimum number of operatioanl queues expected:%d created:%d\n",
3729c0b00a93SSreekanth Reddy 		    mrioc->shost->nr_hw_queues, mrioc->num_op_reply_q);
3730c0b00a93SSreekanth Reddy 		goto out_failed_noretry;
3731c0b00a93SSreekanth Reddy 	}
3732c0b00a93SSreekanth Reddy 
3733c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "enabling events\n");
3734c0b00a93SSreekanth Reddy 	retval = mpi3mr_enable_events(mrioc);
3735c0b00a93SSreekanth Reddy 	if (retval) {
3736c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to enable events\n");
3737c0b00a93SSreekanth Reddy 		goto out_failed;
3738c0b00a93SSreekanth Reddy 	}
3739c0b00a93SSreekanth Reddy 
3740c0b00a93SSreekanth Reddy 	ioc_info(mrioc, "sending port enable\n");
3741c0b00a93SSreekanth Reddy 	retval = mpi3mr_issue_port_enable(mrioc, 0);
3742c0b00a93SSreekanth Reddy 	if (retval) {
3743c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to issue port enable\n");
3744c0b00a93SSreekanth Reddy 		goto out_failed;
3745c0b00a93SSreekanth Reddy 	}
3746c0b00a93SSreekanth Reddy 
3747c0b00a93SSreekanth Reddy 	ioc_info(mrioc, "controller %s completed successfully\n",
3748c0b00a93SSreekanth Reddy 	    (is_resume)?"resume":"re-initialization");
3749c0b00a93SSreekanth Reddy 	return retval;
3750c0b00a93SSreekanth Reddy out_failed:
3751c0b00a93SSreekanth Reddy 	if (retry < 2) {
3752c0b00a93SSreekanth Reddy 		retry++;
3753c0b00a93SSreekanth Reddy 		ioc_warn(mrioc, "retrying controller %s, retry_count:%d\n",
3754c0b00a93SSreekanth Reddy 		    (is_resume)?"resume":"re-initialization", retry);
3755c0b00a93SSreekanth Reddy 		mpi3mr_memset_buffers(mrioc);
3756c0b00a93SSreekanth Reddy 		goto retry_init;
3757c0b00a93SSreekanth Reddy 	}
3758c0b00a93SSreekanth Reddy out_failed_noretry:
3759c0b00a93SSreekanth Reddy 	ioc_err(mrioc, "controller %s is failed\n",
3760c0b00a93SSreekanth Reddy 	    (is_resume)?"resume":"re-initialization");
3761c0b00a93SSreekanth Reddy 	mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
3762c0b00a93SSreekanth Reddy 	    MPI3MR_RESET_FROM_CTLR_CLEANUP);
3763c0b00a93SSreekanth Reddy 	mrioc->unrecoverable = 1;
3764c0b00a93SSreekanth Reddy 	return retval;
3765fe6db615SSreekanth Reddy }
3766fe6db615SSreekanth Reddy 
3767824a1566SKashyap Desai /**
3768fb9b0457SKashyap Desai  * mpi3mr_memset_op_reply_q_buffers - memset the operational reply queue's
3769fb9b0457SKashyap Desai  *					segments
3770fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
3771fb9b0457SKashyap Desai  * @qidx: Operational reply queue index
3772fb9b0457SKashyap Desai  *
3773fb9b0457SKashyap Desai  * Return: Nothing.
3774fb9b0457SKashyap Desai  */
3775fb9b0457SKashyap Desai static void mpi3mr_memset_op_reply_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx)
3776fb9b0457SKashyap Desai {
3777fb9b0457SKashyap Desai 	struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
3778fb9b0457SKashyap Desai 	struct segments *segments;
3779fb9b0457SKashyap Desai 	int i, size;
3780fb9b0457SKashyap Desai 
3781fb9b0457SKashyap Desai 	if (!op_reply_q->q_segments)
3782fb9b0457SKashyap Desai 		return;
3783fb9b0457SKashyap Desai 
3784fb9b0457SKashyap Desai 	size = op_reply_q->segment_qd * mrioc->op_reply_desc_sz;
3785fb9b0457SKashyap Desai 	segments = op_reply_q->q_segments;
3786fb9b0457SKashyap Desai 	for (i = 0; i < op_reply_q->num_segments; i++)
3787fb9b0457SKashyap Desai 		memset(segments[i].segment, 0, size);
3788fb9b0457SKashyap Desai }
3789fb9b0457SKashyap Desai 
3790fb9b0457SKashyap Desai /**
3791fb9b0457SKashyap Desai  * mpi3mr_memset_op_req_q_buffers - memset the operational request queue's
3792fb9b0457SKashyap Desai  *					segments
3793fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
3794fb9b0457SKashyap Desai  * @qidx: Operational request queue index
3795fb9b0457SKashyap Desai  *
3796fb9b0457SKashyap Desai  * Return: Nothing.
3797fb9b0457SKashyap Desai  */
3798fb9b0457SKashyap Desai static void mpi3mr_memset_op_req_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx)
3799fb9b0457SKashyap Desai {
3800fb9b0457SKashyap Desai 	struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx;
3801fb9b0457SKashyap Desai 	struct segments *segments;
3802fb9b0457SKashyap Desai 	int i, size;
3803fb9b0457SKashyap Desai 
3804fb9b0457SKashyap Desai 	if (!op_req_q->q_segments)
3805fb9b0457SKashyap Desai 		return;
3806fb9b0457SKashyap Desai 
3807fb9b0457SKashyap Desai 	size = op_req_q->segment_qd * mrioc->facts.op_req_sz;
3808fb9b0457SKashyap Desai 	segments = op_req_q->q_segments;
3809fb9b0457SKashyap Desai 	for (i = 0; i < op_req_q->num_segments; i++)
3810fb9b0457SKashyap Desai 		memset(segments[i].segment, 0, size);
3811fb9b0457SKashyap Desai }
3812fb9b0457SKashyap Desai 
3813fb9b0457SKashyap Desai /**
3814fb9b0457SKashyap Desai  * mpi3mr_memset_buffers - memset memory for a controller
3815fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
3816fb9b0457SKashyap Desai  *
3817fb9b0457SKashyap Desai  * clear all the memory allocated for a controller, typically
3818fb9b0457SKashyap Desai  * called post reset to reuse the memory allocated during the
3819fb9b0457SKashyap Desai  * controller init.
3820fb9b0457SKashyap Desai  *
3821fb9b0457SKashyap Desai  * Return: Nothing.
3822fb9b0457SKashyap Desai  */
38230da66348SKashyap Desai void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc)
3824fb9b0457SKashyap Desai {
3825fb9b0457SKashyap Desai 	u16 i;
3826fb9b0457SKashyap Desai 
3827fe6db615SSreekanth Reddy 	mrioc->change_count = 0;
3828fe6db615SSreekanth Reddy 	if (mrioc->admin_req_base)
3829fb9b0457SKashyap Desai 		memset(mrioc->admin_req_base, 0, mrioc->admin_req_q_sz);
3830fe6db615SSreekanth Reddy 	if (mrioc->admin_reply_base)
3831fb9b0457SKashyap Desai 		memset(mrioc->admin_reply_base, 0, mrioc->admin_reply_q_sz);
3832fb9b0457SKashyap Desai 
3833fe6db615SSreekanth Reddy 	if (mrioc->init_cmds.reply) {
3834fb9b0457SKashyap Desai 		memset(mrioc->init_cmds.reply, 0, sizeof(*mrioc->init_cmds.reply));
3835e844adb1SKashyap Desai 		memset(mrioc->host_tm_cmds.reply, 0,
3836e844adb1SKashyap Desai 		    sizeof(*mrioc->host_tm_cmds.reply));
3837fb9b0457SKashyap Desai 		for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++)
3838fb9b0457SKashyap Desai 			memset(mrioc->dev_rmhs_cmds[i].reply, 0,
3839fb9b0457SKashyap Desai 			    sizeof(*mrioc->dev_rmhs_cmds[i].reply));
3840c1af985dSSreekanth Reddy 		for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++)
3841c1af985dSSreekanth Reddy 			memset(mrioc->evtack_cmds[i].reply, 0,
3842c1af985dSSreekanth Reddy 			    sizeof(*mrioc->evtack_cmds[i].reply));
3843fb9b0457SKashyap Desai 		memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz);
3844fb9b0457SKashyap Desai 		memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz);
3845c1af985dSSreekanth Reddy 		memset(mrioc->evtack_cmds_bitmap, 0,
3846c1af985dSSreekanth Reddy 		    mrioc->evtack_cmds_bitmap_sz);
3847fe6db615SSreekanth Reddy 	}
3848fb9b0457SKashyap Desai 
3849fb9b0457SKashyap Desai 	for (i = 0; i < mrioc->num_queues; i++) {
3850fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].qid = 0;
3851fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].ci = 0;
3852fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].num_replies = 0;
3853fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].ephase = 0;
3854463429f8SKashyap Desai 		atomic_set(&mrioc->op_reply_qinfo[i].pend_ios, 0);
3855463429f8SKashyap Desai 		atomic_set(&mrioc->op_reply_qinfo[i].in_use, 0);
3856fb9b0457SKashyap Desai 		mpi3mr_memset_op_reply_q_buffers(mrioc, i);
3857fb9b0457SKashyap Desai 
3858fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].ci = 0;
3859fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].pi = 0;
3860fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].num_requests = 0;
3861fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].qid = 0;
3862fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].reply_qid = 0;
3863fb9b0457SKashyap Desai 		spin_lock_init(&mrioc->req_qinfo[i].q_lock);
3864fb9b0457SKashyap Desai 		mpi3mr_memset_op_req_q_buffers(mrioc, i);
3865fb9b0457SKashyap Desai 	}
3866fb9b0457SKashyap Desai }
3867fb9b0457SKashyap Desai 
3868fb9b0457SKashyap Desai /**
3869824a1566SKashyap Desai  * mpi3mr_free_mem - Free memory allocated for a controller
3870824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3871824a1566SKashyap Desai  *
3872824a1566SKashyap Desai  * Free all the memory allocated for a controller.
3873824a1566SKashyap Desai  *
3874824a1566SKashyap Desai  * Return: Nothing.
3875824a1566SKashyap Desai  */
3876fe6db615SSreekanth Reddy void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc)
3877824a1566SKashyap Desai {
3878824a1566SKashyap Desai 	u16 i;
3879824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info;
3880824a1566SKashyap Desai 
3881824a1566SKashyap Desai 	if (mrioc->sense_buf_pool) {
3882824a1566SKashyap Desai 		if (mrioc->sense_buf)
3883824a1566SKashyap Desai 			dma_pool_free(mrioc->sense_buf_pool, mrioc->sense_buf,
3884824a1566SKashyap Desai 			    mrioc->sense_buf_dma);
3885824a1566SKashyap Desai 		dma_pool_destroy(mrioc->sense_buf_pool);
3886824a1566SKashyap Desai 		mrioc->sense_buf = NULL;
3887824a1566SKashyap Desai 		mrioc->sense_buf_pool = NULL;
3888824a1566SKashyap Desai 	}
3889824a1566SKashyap Desai 	if (mrioc->sense_buf_q_pool) {
3890824a1566SKashyap Desai 		if (mrioc->sense_buf_q)
3891824a1566SKashyap Desai 			dma_pool_free(mrioc->sense_buf_q_pool,
3892824a1566SKashyap Desai 			    mrioc->sense_buf_q, mrioc->sense_buf_q_dma);
3893824a1566SKashyap Desai 		dma_pool_destroy(mrioc->sense_buf_q_pool);
3894824a1566SKashyap Desai 		mrioc->sense_buf_q = NULL;
3895824a1566SKashyap Desai 		mrioc->sense_buf_q_pool = NULL;
3896824a1566SKashyap Desai 	}
3897824a1566SKashyap Desai 
3898824a1566SKashyap Desai 	if (mrioc->reply_buf_pool) {
3899824a1566SKashyap Desai 		if (mrioc->reply_buf)
3900824a1566SKashyap Desai 			dma_pool_free(mrioc->reply_buf_pool, mrioc->reply_buf,
3901824a1566SKashyap Desai 			    mrioc->reply_buf_dma);
3902824a1566SKashyap Desai 		dma_pool_destroy(mrioc->reply_buf_pool);
3903824a1566SKashyap Desai 		mrioc->reply_buf = NULL;
3904824a1566SKashyap Desai 		mrioc->reply_buf_pool = NULL;
3905824a1566SKashyap Desai 	}
3906824a1566SKashyap Desai 	if (mrioc->reply_free_q_pool) {
3907824a1566SKashyap Desai 		if (mrioc->reply_free_q)
3908824a1566SKashyap Desai 			dma_pool_free(mrioc->reply_free_q_pool,
3909824a1566SKashyap Desai 			    mrioc->reply_free_q, mrioc->reply_free_q_dma);
3910824a1566SKashyap Desai 		dma_pool_destroy(mrioc->reply_free_q_pool);
3911824a1566SKashyap Desai 		mrioc->reply_free_q = NULL;
3912824a1566SKashyap Desai 		mrioc->reply_free_q_pool = NULL;
3913824a1566SKashyap Desai 	}
3914824a1566SKashyap Desai 
3915c9566231SKashyap Desai 	for (i = 0; i < mrioc->num_op_req_q; i++)
3916c9566231SKashyap Desai 		mpi3mr_free_op_req_q_segments(mrioc, i);
3917c9566231SKashyap Desai 
3918c9566231SKashyap Desai 	for (i = 0; i < mrioc->num_op_reply_q; i++)
3919c9566231SKashyap Desai 		mpi3mr_free_op_reply_q_segments(mrioc, i);
3920c9566231SKashyap Desai 
3921824a1566SKashyap Desai 	for (i = 0; i < mrioc->intr_info_count; i++) {
3922824a1566SKashyap Desai 		intr_info = mrioc->intr_info + i;
3923824a1566SKashyap Desai 		intr_info->op_reply_q = NULL;
3924824a1566SKashyap Desai 	}
3925824a1566SKashyap Desai 
3926824a1566SKashyap Desai 	kfree(mrioc->req_qinfo);
3927824a1566SKashyap Desai 	mrioc->req_qinfo = NULL;
3928824a1566SKashyap Desai 	mrioc->num_op_req_q = 0;
3929824a1566SKashyap Desai 
3930824a1566SKashyap Desai 	kfree(mrioc->op_reply_qinfo);
3931824a1566SKashyap Desai 	mrioc->op_reply_qinfo = NULL;
3932824a1566SKashyap Desai 	mrioc->num_op_reply_q = 0;
3933824a1566SKashyap Desai 
3934824a1566SKashyap Desai 	kfree(mrioc->init_cmds.reply);
3935824a1566SKashyap Desai 	mrioc->init_cmds.reply = NULL;
3936824a1566SKashyap Desai 
3937e844adb1SKashyap Desai 	kfree(mrioc->host_tm_cmds.reply);
3938e844adb1SKashyap Desai 	mrioc->host_tm_cmds.reply = NULL;
3939e844adb1SKashyap Desai 
3940c1af985dSSreekanth Reddy 	for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) {
3941c1af985dSSreekanth Reddy 		kfree(mrioc->evtack_cmds[i].reply);
3942c1af985dSSreekanth Reddy 		mrioc->evtack_cmds[i].reply = NULL;
3943c1af985dSSreekanth Reddy 	}
3944c1af985dSSreekanth Reddy 
3945e844adb1SKashyap Desai 	kfree(mrioc->removepend_bitmap);
3946e844adb1SKashyap Desai 	mrioc->removepend_bitmap = NULL;
3947e844adb1SKashyap Desai 
3948e844adb1SKashyap Desai 	kfree(mrioc->devrem_bitmap);
3949e844adb1SKashyap Desai 	mrioc->devrem_bitmap = NULL;
3950e844adb1SKashyap Desai 
3951c1af985dSSreekanth Reddy 	kfree(mrioc->evtack_cmds_bitmap);
3952c1af985dSSreekanth Reddy 	mrioc->evtack_cmds_bitmap = NULL;
3953c1af985dSSreekanth Reddy 
3954824a1566SKashyap Desai 	kfree(mrioc->chain_bitmap);
3955824a1566SKashyap Desai 	mrioc->chain_bitmap = NULL;
3956824a1566SKashyap Desai 
395713ef29eaSKashyap Desai 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
395813ef29eaSKashyap Desai 		kfree(mrioc->dev_rmhs_cmds[i].reply);
395913ef29eaSKashyap Desai 		mrioc->dev_rmhs_cmds[i].reply = NULL;
396013ef29eaSKashyap Desai 	}
396113ef29eaSKashyap Desai 
3962824a1566SKashyap Desai 	if (mrioc->chain_buf_pool) {
3963824a1566SKashyap Desai 		for (i = 0; i < mrioc->chain_buf_count; i++) {
3964824a1566SKashyap Desai 			if (mrioc->chain_sgl_list[i].addr) {
3965824a1566SKashyap Desai 				dma_pool_free(mrioc->chain_buf_pool,
3966824a1566SKashyap Desai 				    mrioc->chain_sgl_list[i].addr,
3967824a1566SKashyap Desai 				    mrioc->chain_sgl_list[i].dma_addr);
3968824a1566SKashyap Desai 				mrioc->chain_sgl_list[i].addr = NULL;
3969824a1566SKashyap Desai 			}
3970824a1566SKashyap Desai 		}
3971824a1566SKashyap Desai 		dma_pool_destroy(mrioc->chain_buf_pool);
3972824a1566SKashyap Desai 		mrioc->chain_buf_pool = NULL;
3973824a1566SKashyap Desai 	}
3974824a1566SKashyap Desai 
3975824a1566SKashyap Desai 	kfree(mrioc->chain_sgl_list);
3976824a1566SKashyap Desai 	mrioc->chain_sgl_list = NULL;
3977824a1566SKashyap Desai 
3978824a1566SKashyap Desai 	if (mrioc->admin_reply_base) {
3979824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz,
3980824a1566SKashyap Desai 		    mrioc->admin_reply_base, mrioc->admin_reply_dma);
3981824a1566SKashyap Desai 		mrioc->admin_reply_base = NULL;
3982824a1566SKashyap Desai 	}
3983824a1566SKashyap Desai 	if (mrioc->admin_req_base) {
3984824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz,
3985824a1566SKashyap Desai 		    mrioc->admin_req_base, mrioc->admin_req_dma);
3986824a1566SKashyap Desai 		mrioc->admin_req_base = NULL;
3987824a1566SKashyap Desai 	}
3988824a1566SKashyap Desai }
3989824a1566SKashyap Desai 
3990824a1566SKashyap Desai /**
3991824a1566SKashyap Desai  * mpi3mr_issue_ioc_shutdown - shutdown controller
3992824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3993824a1566SKashyap Desai  *
3994824a1566SKashyap Desai  * Send shutodwn notification to the controller and wait for the
3995824a1566SKashyap Desai  * shutdown_timeout for it to be completed.
3996824a1566SKashyap Desai  *
3997824a1566SKashyap Desai  * Return: Nothing.
3998824a1566SKashyap Desai  */
3999824a1566SKashyap Desai static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc)
4000824a1566SKashyap Desai {
4001824a1566SKashyap Desai 	u32 ioc_config, ioc_status;
4002824a1566SKashyap Desai 	u8 retval = 1;
4003824a1566SKashyap Desai 	u32 timeout = MPI3MR_DEFAULT_SHUTDOWN_TIME * 10;
4004824a1566SKashyap Desai 
4005824a1566SKashyap Desai 	ioc_info(mrioc, "Issuing shutdown Notification\n");
4006824a1566SKashyap Desai 	if (mrioc->unrecoverable) {
4007824a1566SKashyap Desai 		ioc_warn(mrioc,
4008824a1566SKashyap Desai 		    "IOC is unrecoverable shutdown is not issued\n");
4009824a1566SKashyap Desai 		return;
4010824a1566SKashyap Desai 	}
4011824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
4012824a1566SKashyap Desai 	if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
4013824a1566SKashyap Desai 	    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS) {
4014824a1566SKashyap Desai 		ioc_info(mrioc, "shutdown already in progress\n");
4015824a1566SKashyap Desai 		return;
4016824a1566SKashyap Desai 	}
4017824a1566SKashyap Desai 
4018824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
4019824a1566SKashyap Desai 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL;
4020ec5ebd2cSSreekanth Reddy 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN_SEND_REQ;
4021824a1566SKashyap Desai 
4022824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
4023824a1566SKashyap Desai 
4024824a1566SKashyap Desai 	if (mrioc->facts.shutdown_timeout)
4025824a1566SKashyap Desai 		timeout = mrioc->facts.shutdown_timeout * 10;
4026824a1566SKashyap Desai 
4027824a1566SKashyap Desai 	do {
4028824a1566SKashyap Desai 		ioc_status = readl(&mrioc->sysif_regs->ioc_status);
4029824a1566SKashyap Desai 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
4030824a1566SKashyap Desai 		    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_COMPLETE) {
4031824a1566SKashyap Desai 			retval = 0;
4032824a1566SKashyap Desai 			break;
4033824a1566SKashyap Desai 		}
4034824a1566SKashyap Desai 		msleep(100);
4035824a1566SKashyap Desai 	} while (--timeout);
4036824a1566SKashyap Desai 
4037824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
4038824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
4039824a1566SKashyap Desai 
4040824a1566SKashyap Desai 	if (retval) {
4041824a1566SKashyap Desai 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
4042824a1566SKashyap Desai 		    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS)
4043824a1566SKashyap Desai 			ioc_warn(mrioc,
4044824a1566SKashyap Desai 			    "shutdown still in progress after timeout\n");
4045824a1566SKashyap Desai 	}
4046824a1566SKashyap Desai 
4047824a1566SKashyap Desai 	ioc_info(mrioc,
4048824a1566SKashyap Desai 	    "Base IOC Sts/Config after %s shutdown is (0x%x)/(0x%x)\n",
4049824a1566SKashyap Desai 	    (!retval) ? "successful" : "failed", ioc_status,
4050824a1566SKashyap Desai 	    ioc_config);
4051824a1566SKashyap Desai }
4052824a1566SKashyap Desai 
4053824a1566SKashyap Desai /**
4054824a1566SKashyap Desai  * mpi3mr_cleanup_ioc - Cleanup controller
4055824a1566SKashyap Desai  * @mrioc: Adapter instance reference
4056fe6db615SSreekanth Reddy 
4057824a1566SKashyap Desai  * controller cleanup handler, Message unit reset or soft reset
4058fe6db615SSreekanth Reddy  * and shutdown notification is issued to the controller.
4059824a1566SKashyap Desai  *
4060824a1566SKashyap Desai  * Return: Nothing.
4061824a1566SKashyap Desai  */
4062fe6db615SSreekanth Reddy void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc)
4063824a1566SKashyap Desai {
4064824a1566SKashyap Desai 	enum mpi3mr_iocstate ioc_state;
4065824a1566SKashyap Desai 
4066fe6db615SSreekanth Reddy 	dprint_exit(mrioc, "cleaning up the controller\n");
4067824a1566SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
4068824a1566SKashyap Desai 
4069824a1566SKashyap Desai 	ioc_state = mpi3mr_get_iocstate(mrioc);
4070824a1566SKashyap Desai 
4071824a1566SKashyap Desai 	if ((!mrioc->unrecoverable) && (!mrioc->reset_in_progress) &&
4072824a1566SKashyap Desai 	    (ioc_state == MRIOC_STATE_READY)) {
4073824a1566SKashyap Desai 		if (mpi3mr_issue_and_process_mur(mrioc,
4074824a1566SKashyap Desai 		    MPI3MR_RESET_FROM_CTLR_CLEANUP))
4075824a1566SKashyap Desai 			mpi3mr_issue_reset(mrioc,
4076824a1566SKashyap Desai 			    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
4077824a1566SKashyap Desai 			    MPI3MR_RESET_FROM_MUR_FAILURE);
4078824a1566SKashyap Desai 		mpi3mr_issue_ioc_shutdown(mrioc);
4079824a1566SKashyap Desai 	}
4080fe6db615SSreekanth Reddy 	dprint_exit(mrioc, "controller cleanup completed\n");
4081fb9b0457SKashyap Desai }
4082fb9b0457SKashyap Desai 
4083fb9b0457SKashyap Desai /**
4084fb9b0457SKashyap Desai  * mpi3mr_drv_cmd_comp_reset - Flush a internal driver command
4085fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
4086fb9b0457SKashyap Desai  * @cmdptr: Internal command tracker
4087fb9b0457SKashyap Desai  *
4088fb9b0457SKashyap Desai  * Complete an internal driver commands with state indicating it
4089fb9b0457SKashyap Desai  * is completed due to reset.
4090fb9b0457SKashyap Desai  *
4091fb9b0457SKashyap Desai  * Return: Nothing.
4092fb9b0457SKashyap Desai  */
4093fb9b0457SKashyap Desai static inline void mpi3mr_drv_cmd_comp_reset(struct mpi3mr_ioc *mrioc,
4094fb9b0457SKashyap Desai 	struct mpi3mr_drv_cmd *cmdptr)
4095fb9b0457SKashyap Desai {
4096fb9b0457SKashyap Desai 	if (cmdptr->state & MPI3MR_CMD_PENDING) {
4097fb9b0457SKashyap Desai 		cmdptr->state |= MPI3MR_CMD_RESET;
4098fb9b0457SKashyap Desai 		cmdptr->state &= ~MPI3MR_CMD_PENDING;
4099fb9b0457SKashyap Desai 		if (cmdptr->is_waiting) {
4100fb9b0457SKashyap Desai 			complete(&cmdptr->done);
4101fb9b0457SKashyap Desai 			cmdptr->is_waiting = 0;
4102fb9b0457SKashyap Desai 		} else if (cmdptr->callback)
4103fb9b0457SKashyap Desai 			cmdptr->callback(mrioc, cmdptr);
4104fb9b0457SKashyap Desai 	}
4105fb9b0457SKashyap Desai }
4106fb9b0457SKashyap Desai 
4107fb9b0457SKashyap Desai /**
4108fb9b0457SKashyap Desai  * mpi3mr_flush_drv_cmds - Flush internaldriver commands
4109fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
4110fb9b0457SKashyap Desai  *
4111fb9b0457SKashyap Desai  * Flush all internal driver commands post reset
4112fb9b0457SKashyap Desai  *
4113fb9b0457SKashyap Desai  * Return: Nothing.
4114fb9b0457SKashyap Desai  */
4115fb9b0457SKashyap Desai static void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc)
4116fb9b0457SKashyap Desai {
4117fb9b0457SKashyap Desai 	struct mpi3mr_drv_cmd *cmdptr;
4118fb9b0457SKashyap Desai 	u8 i;
4119fb9b0457SKashyap Desai 
4120fb9b0457SKashyap Desai 	cmdptr = &mrioc->init_cmds;
4121fb9b0457SKashyap Desai 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
4122e844adb1SKashyap Desai 	cmdptr = &mrioc->host_tm_cmds;
4123e844adb1SKashyap Desai 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
4124fb9b0457SKashyap Desai 
4125fb9b0457SKashyap Desai 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
4126fb9b0457SKashyap Desai 		cmdptr = &mrioc->dev_rmhs_cmds[i];
4127fb9b0457SKashyap Desai 		mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
4128fb9b0457SKashyap Desai 	}
4129c1af985dSSreekanth Reddy 
4130c1af985dSSreekanth Reddy 	for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) {
4131c1af985dSSreekanth Reddy 		cmdptr = &mrioc->evtack_cmds[i];
4132c1af985dSSreekanth Reddy 		mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
4133c1af985dSSreekanth Reddy 	}
4134fb9b0457SKashyap Desai }
4135fb9b0457SKashyap Desai 
4136fb9b0457SKashyap Desai /**
4137824a1566SKashyap Desai  * mpi3mr_soft_reset_handler - Reset the controller
4138824a1566SKashyap Desai  * @mrioc: Adapter instance reference
4139824a1566SKashyap Desai  * @reset_reason: Reset reason code
4140824a1566SKashyap Desai  * @snapdump: Flag to generate snapdump in firmware or not
4141824a1566SKashyap Desai  *
4142fb9b0457SKashyap Desai  * This is an handler for recovering controller by issuing soft
4143fb9b0457SKashyap Desai  * reset are diag fault reset.  This is a blocking function and
4144fb9b0457SKashyap Desai  * when one reset is executed if any other resets they will be
4145fb9b0457SKashyap Desai  * blocked. All IOCTLs/IO will be blocked during the reset. If
4146fb9b0457SKashyap Desai  * controller reset is successful then the controller will be
4147fb9b0457SKashyap Desai  * reinitalized, otherwise the controller will be marked as not
4148fb9b0457SKashyap Desai  * recoverable
4149fb9b0457SKashyap Desai  *
4150fb9b0457SKashyap Desai  * In snapdump bit is set, the controller is issued with diag
4151fb9b0457SKashyap Desai  * fault reset so that the firmware can create a snap dump and
4152fb9b0457SKashyap Desai  * post that the firmware will result in F000 fault and the
4153fb9b0457SKashyap Desai  * driver will issue soft reset to recover from that.
4154824a1566SKashyap Desai  *
4155824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
4156824a1566SKashyap Desai  */
4157824a1566SKashyap Desai int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
4158824a1566SKashyap Desai 	u32 reset_reason, u8 snapdump)
4159824a1566SKashyap Desai {
4160fb9b0457SKashyap Desai 	int retval = 0, i;
4161fb9b0457SKashyap Desai 	unsigned long flags;
4162fb9b0457SKashyap Desai 	u32 host_diagnostic, timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10;
4163fb9b0457SKashyap Desai 
4164b64845a7SSreekanth Reddy 	/* Block the reset handler until diag save in progress*/
4165b64845a7SSreekanth Reddy 	dprint_reset(mrioc,
4166b64845a7SSreekanth Reddy 	    "soft_reset_handler: check and block on diagsave_timeout(%d)\n",
4167b64845a7SSreekanth Reddy 	    mrioc->diagsave_timeout);
4168b64845a7SSreekanth Reddy 	while (mrioc->diagsave_timeout)
4169b64845a7SSreekanth Reddy 		ssleep(1);
4170fb9b0457SKashyap Desai 	/*
4171fb9b0457SKashyap Desai 	 * Block new resets until the currently executing one is finished and
4172fb9b0457SKashyap Desai 	 * return the status of the existing reset for all blocked resets
4173fb9b0457SKashyap Desai 	 */
4174b64845a7SSreekanth Reddy 	dprint_reset(mrioc, "soft_reset_handler: acquiring reset_mutex\n");
4175fb9b0457SKashyap Desai 	if (!mutex_trylock(&mrioc->reset_mutex)) {
4176b64845a7SSreekanth Reddy 		ioc_info(mrioc,
4177b64845a7SSreekanth Reddy 		    "controller reset triggered by %s is blocked due to another reset in progress\n",
4178b64845a7SSreekanth Reddy 		    mpi3mr_reset_rc_name(reset_reason));
4179b64845a7SSreekanth Reddy 		do {
4180b64845a7SSreekanth Reddy 			ssleep(1);
4181b64845a7SSreekanth Reddy 		} while (mrioc->reset_in_progress == 1);
4182b64845a7SSreekanth Reddy 		ioc_info(mrioc,
4183b64845a7SSreekanth Reddy 		    "returning previous reset result(%d) for the reset triggered by %s\n",
4184b64845a7SSreekanth Reddy 		    mrioc->prev_reset_result,
4185b64845a7SSreekanth Reddy 		    mpi3mr_reset_rc_name(reset_reason));
4186b64845a7SSreekanth Reddy 		return mrioc->prev_reset_result;
4187fb9b0457SKashyap Desai 	}
4188b64845a7SSreekanth Reddy 	ioc_info(mrioc, "controller reset is triggered by %s\n",
4189b64845a7SSreekanth Reddy 	    mpi3mr_reset_rc_name(reset_reason));
4190b64845a7SSreekanth Reddy 
4191fb9b0457SKashyap Desai 	mrioc->reset_in_progress = 1;
4192b64845a7SSreekanth Reddy 	mrioc->prev_reset_result = -1;
4193fb9b0457SKashyap Desai 
4194fb9b0457SKashyap Desai 	if ((!snapdump) && (reset_reason != MPI3MR_RESET_FROM_FAULT_WATCH) &&
4195b64845a7SSreekanth Reddy 	    (reset_reason != MPI3MR_RESET_FROM_FIRMWARE) &&
4196fb9b0457SKashyap Desai 	    (reset_reason != MPI3MR_RESET_FROM_CIACTIV_FAULT)) {
4197fb9b0457SKashyap Desai 		for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
4198fb9b0457SKashyap Desai 			mrioc->event_masks[i] = -1;
4199fb9b0457SKashyap Desai 
4200b64845a7SSreekanth Reddy 		dprint_reset(mrioc, "soft_reset_handler: masking events\n");
4201b64845a7SSreekanth Reddy 		mpi3mr_issue_event_notification(mrioc);
4202fb9b0457SKashyap Desai 	}
4203fb9b0457SKashyap Desai 
420444dc724fSKashyap Desai 	mpi3mr_wait_for_host_io(mrioc, MPI3MR_RESET_HOST_IOWAIT_TIMEOUT);
420544dc724fSKashyap Desai 
4206fb9b0457SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
4207fb9b0457SKashyap Desai 
4208fb9b0457SKashyap Desai 	if (snapdump) {
4209fb9b0457SKashyap Desai 		mpi3mr_set_diagsave(mrioc);
4210fb9b0457SKashyap Desai 		retval = mpi3mr_issue_reset(mrioc,
4211fb9b0457SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
4212fb9b0457SKashyap Desai 		if (!retval) {
4213fb9b0457SKashyap Desai 			do {
4214fb9b0457SKashyap Desai 				host_diagnostic =
4215fb9b0457SKashyap Desai 				    readl(&mrioc->sysif_regs->host_diagnostic);
4216fb9b0457SKashyap Desai 				if (!(host_diagnostic &
4217fb9b0457SKashyap Desai 				    MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS))
4218fb9b0457SKashyap Desai 					break;
4219fb9b0457SKashyap Desai 				msleep(100);
4220fb9b0457SKashyap Desai 			} while (--timeout);
4221fb9b0457SKashyap Desai 		}
4222fb9b0457SKashyap Desai 	}
4223fb9b0457SKashyap Desai 
4224fb9b0457SKashyap Desai 	retval = mpi3mr_issue_reset(mrioc,
4225fb9b0457SKashyap Desai 	    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, reset_reason);
4226fb9b0457SKashyap Desai 	if (retval) {
4227fb9b0457SKashyap Desai 		ioc_err(mrioc, "Failed to issue soft reset to the ioc\n");
4228fb9b0457SKashyap Desai 		goto out;
4229fb9b0457SKashyap Desai 	}
4230fb9b0457SKashyap Desai 
4231c1af985dSSreekanth Reddy 	mpi3mr_flush_delayed_cmd_lists(mrioc);
4232fb9b0457SKashyap Desai 	mpi3mr_flush_drv_cmds(mrioc);
4233fb9b0457SKashyap Desai 	memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz);
4234fb9b0457SKashyap Desai 	memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz);
4235c1af985dSSreekanth Reddy 	memset(mrioc->evtack_cmds_bitmap, 0, mrioc->evtack_cmds_bitmap_sz);
4236fb9b0457SKashyap Desai 	mpi3mr_cleanup_fwevt_list(mrioc);
4237fb9b0457SKashyap Desai 	mpi3mr_flush_host_io(mrioc);
4238fb9b0457SKashyap Desai 	mpi3mr_invalidate_devhandles(mrioc);
4239*78b76a07SSreekanth Reddy 	if (mrioc->prepare_for_reset) {
4240*78b76a07SSreekanth Reddy 		mrioc->prepare_for_reset = 0;
4241*78b76a07SSreekanth Reddy 		mrioc->prepare_for_reset_timeout_counter = 0;
4242*78b76a07SSreekanth Reddy 	}
4243fb9b0457SKashyap Desai 	mpi3mr_memset_buffers(mrioc);
4244fe6db615SSreekanth Reddy 	retval = mpi3mr_reinit_ioc(mrioc, 0);
4245fb9b0457SKashyap Desai 	if (retval) {
4246fb9b0457SKashyap Desai 		pr_err(IOCNAME "reinit after soft reset failed: reason %d\n",
4247fb9b0457SKashyap Desai 		    mrioc->name, reset_reason);
4248fb9b0457SKashyap Desai 		goto out;
4249fb9b0457SKashyap Desai 	}
4250fb9b0457SKashyap Desai 	ssleep(10);
4251fb9b0457SKashyap Desai 
4252fb9b0457SKashyap Desai out:
4253fb9b0457SKashyap Desai 	if (!retval) {
4254b64845a7SSreekanth Reddy 		mrioc->diagsave_timeout = 0;
4255fb9b0457SKashyap Desai 		mrioc->reset_in_progress = 0;
4256fb9b0457SKashyap Desai 		mpi3mr_rfresh_tgtdevs(mrioc);
425754dfcffbSKashyap Desai 		mrioc->ts_update_counter = 0;
4258fb9b0457SKashyap Desai 		spin_lock_irqsave(&mrioc->watchdog_lock, flags);
4259fb9b0457SKashyap Desai 		if (mrioc->watchdog_work_q)
4260fb9b0457SKashyap Desai 			queue_delayed_work(mrioc->watchdog_work_q,
4261fb9b0457SKashyap Desai 			    &mrioc->watchdog_work,
4262fb9b0457SKashyap Desai 			    msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL));
4263fb9b0457SKashyap Desai 		spin_unlock_irqrestore(&mrioc->watchdog_lock, flags);
4264fb9b0457SKashyap Desai 	} else {
4265fb9b0457SKashyap Desai 		mpi3mr_issue_reset(mrioc,
4266fb9b0457SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
4267fb9b0457SKashyap Desai 		mrioc->unrecoverable = 1;
4268fb9b0457SKashyap Desai 		mrioc->reset_in_progress = 0;
4269fb9b0457SKashyap Desai 		retval = -1;
4270fb9b0457SKashyap Desai 	}
4271b64845a7SSreekanth Reddy 	mrioc->prev_reset_result = retval;
4272fb9b0457SKashyap Desai 	mutex_unlock(&mrioc->reset_mutex);
4273b64845a7SSreekanth Reddy 	ioc_info(mrioc, "controller reset is %s\n",
4274b64845a7SSreekanth Reddy 	    ((retval == 0) ? "successful" : "failed"));
4275fb9b0457SKashyap Desai 	return retval;
4276824a1566SKashyap Desai }
4277