xref: /linux/drivers/scsi/mpi3mr/mpi3mr_fw.c (revision 3ed7df085225ea8736b80d1e1a247a40d91281c8)
1824a1566SKashyap Desai // SPDX-License-Identifier: GPL-2.0-or-later
2824a1566SKashyap Desai /*
3824a1566SKashyap Desai  * Driver for Broadcom MPI3 Storage Controllers
4824a1566SKashyap Desai  *
5e74f2fbdSRanjan Kumar  * Copyright (C) 2017-2023 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
140a2714b7SRanjan Kumar mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, u16 reset_reason);
1559bd9cfeSSreekanth Reddy static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc);
16c5758fc7SSreekanth Reddy static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc,
17c5758fc7SSreekanth Reddy 	struct mpi3_ioc_facts_data *facts_data);
1843ca1100SSumit Saxena static void mpi3mr_pel_wait_complete(struct mpi3mr_ioc *mrioc,
1943ca1100SSumit Saxena 	struct mpi3mr_drv_cmd *drv_cmd);
2059bd9cfeSSreekanth Reddy 
21afd3a579SSreekanth Reddy static int poll_queues;
22afd3a579SSreekanth Reddy module_param(poll_queues, int, 0444);
23afd3a579SSreekanth Reddy MODULE_PARM_DESC(poll_queues, "Number of queues for io_uring poll mode. (Range 1 - 126)");
24afd3a579SSreekanth Reddy 
25824a1566SKashyap Desai #if defined(writeq) && defined(CONFIG_64BIT)
mpi3mr_writeq(__u64 b,volatile void __iomem * addr)26824a1566SKashyap Desai static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr)
27824a1566SKashyap Desai {
28824a1566SKashyap Desai 	writeq(b, addr);
29824a1566SKashyap Desai }
30824a1566SKashyap Desai #else
mpi3mr_writeq(__u64 b,volatile void __iomem * addr)31824a1566SKashyap Desai static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr)
32824a1566SKashyap Desai {
33824a1566SKashyap Desai 	__u64 data_out = b;
34824a1566SKashyap Desai 
35824a1566SKashyap Desai 	writel((u32)(data_out), addr);
36824a1566SKashyap Desai 	writel((u32)(data_out >> 32), (addr + 4));
37824a1566SKashyap Desai }
38824a1566SKashyap Desai #endif
39824a1566SKashyap Desai 
40023ab2a9SKashyap Desai static inline bool
mpi3mr_check_req_qfull(struct op_req_qinfo * op_req_q)41023ab2a9SKashyap Desai mpi3mr_check_req_qfull(struct op_req_qinfo *op_req_q)
42023ab2a9SKashyap Desai {
43023ab2a9SKashyap Desai 	u16 pi, ci, max_entries;
44023ab2a9SKashyap Desai 	bool is_qfull = false;
45023ab2a9SKashyap Desai 
46023ab2a9SKashyap Desai 	pi = op_req_q->pi;
47023ab2a9SKashyap Desai 	ci = READ_ONCE(op_req_q->ci);
48023ab2a9SKashyap Desai 	max_entries = op_req_q->num_requests;
49023ab2a9SKashyap Desai 
50023ab2a9SKashyap Desai 	if ((ci == (pi + 1)) || ((!ci) && (pi == (max_entries - 1))))
51023ab2a9SKashyap Desai 		is_qfull = true;
52023ab2a9SKashyap Desai 
53023ab2a9SKashyap Desai 	return is_qfull;
54023ab2a9SKashyap Desai }
55023ab2a9SKashyap Desai 
mpi3mr_sync_irqs(struct mpi3mr_ioc * mrioc)56824a1566SKashyap Desai static void mpi3mr_sync_irqs(struct mpi3mr_ioc *mrioc)
57824a1566SKashyap Desai {
58824a1566SKashyap Desai 	u16 i, max_vectors;
59824a1566SKashyap Desai 
60824a1566SKashyap Desai 	max_vectors = mrioc->intr_info_count;
61824a1566SKashyap Desai 
62824a1566SKashyap Desai 	for (i = 0; i < max_vectors; i++)
63824a1566SKashyap Desai 		synchronize_irq(pci_irq_vector(mrioc->pdev, i));
64824a1566SKashyap Desai }
65824a1566SKashyap Desai 
mpi3mr_ioc_disable_intr(struct mpi3mr_ioc * mrioc)66824a1566SKashyap Desai void mpi3mr_ioc_disable_intr(struct mpi3mr_ioc *mrioc)
67824a1566SKashyap Desai {
68824a1566SKashyap Desai 	mrioc->intr_enabled = 0;
69824a1566SKashyap Desai 	mpi3mr_sync_irqs(mrioc);
70824a1566SKashyap Desai }
71824a1566SKashyap Desai 
mpi3mr_ioc_enable_intr(struct mpi3mr_ioc * mrioc)72824a1566SKashyap Desai void mpi3mr_ioc_enable_intr(struct mpi3mr_ioc *mrioc)
73824a1566SKashyap Desai {
74824a1566SKashyap Desai 	mrioc->intr_enabled = 1;
75824a1566SKashyap Desai }
76824a1566SKashyap Desai 
mpi3mr_cleanup_isr(struct mpi3mr_ioc * mrioc)77824a1566SKashyap Desai static void mpi3mr_cleanup_isr(struct mpi3mr_ioc *mrioc)
78824a1566SKashyap Desai {
79824a1566SKashyap Desai 	u16 i;
80824a1566SKashyap Desai 
81824a1566SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
82824a1566SKashyap Desai 
83824a1566SKashyap Desai 	if (!mrioc->intr_info)
84824a1566SKashyap Desai 		return;
85824a1566SKashyap Desai 
86824a1566SKashyap Desai 	for (i = 0; i < mrioc->intr_info_count; i++)
87824a1566SKashyap Desai 		free_irq(pci_irq_vector(mrioc->pdev, i),
88824a1566SKashyap Desai 		    (mrioc->intr_info + i));
89824a1566SKashyap Desai 
90824a1566SKashyap Desai 	kfree(mrioc->intr_info);
91824a1566SKashyap Desai 	mrioc->intr_info = NULL;
92824a1566SKashyap Desai 	mrioc->intr_info_count = 0;
93fe6db615SSreekanth Reddy 	mrioc->is_intr_info_set = false;
94824a1566SKashyap Desai 	pci_free_irq_vectors(mrioc->pdev);
95824a1566SKashyap Desai }
96824a1566SKashyap Desai 
mpi3mr_add_sg_single(void * paddr,u8 flags,u32 length,dma_addr_t dma_addr)97824a1566SKashyap Desai void mpi3mr_add_sg_single(void *paddr, u8 flags, u32 length,
98824a1566SKashyap Desai 	dma_addr_t dma_addr)
99824a1566SKashyap Desai {
100824a1566SKashyap Desai 	struct mpi3_sge_common *sgel = paddr;
101824a1566SKashyap Desai 
102824a1566SKashyap Desai 	sgel->flags = flags;
103824a1566SKashyap Desai 	sgel->length = cpu_to_le32(length);
104824a1566SKashyap Desai 	sgel->address = cpu_to_le64(dma_addr);
105824a1566SKashyap Desai }
106824a1566SKashyap Desai 
mpi3mr_build_zero_len_sge(void * paddr)107824a1566SKashyap Desai void mpi3mr_build_zero_len_sge(void *paddr)
108824a1566SKashyap Desai {
109824a1566SKashyap Desai 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
110824a1566SKashyap Desai 
111824a1566SKashyap Desai 	mpi3mr_add_sg_single(paddr, sgl_flags, 0, -1);
112824a1566SKashyap Desai }
113824a1566SKashyap Desai 
mpi3mr_get_reply_virt_addr(struct mpi3mr_ioc * mrioc,dma_addr_t phys_addr)114824a1566SKashyap Desai void *mpi3mr_get_reply_virt_addr(struct mpi3mr_ioc *mrioc,
115824a1566SKashyap Desai 	dma_addr_t phys_addr)
116824a1566SKashyap Desai {
117824a1566SKashyap Desai 	if (!phys_addr)
118824a1566SKashyap Desai 		return NULL;
119824a1566SKashyap Desai 
120824a1566SKashyap Desai 	if ((phys_addr < mrioc->reply_buf_dma) ||
121824a1566SKashyap Desai 	    (phys_addr > mrioc->reply_buf_dma_max_address))
122824a1566SKashyap Desai 		return NULL;
123824a1566SKashyap Desai 
124824a1566SKashyap Desai 	return mrioc->reply_buf + (phys_addr - mrioc->reply_buf_dma);
125824a1566SKashyap Desai }
126824a1566SKashyap Desai 
mpi3mr_get_sensebuf_virt_addr(struct mpi3mr_ioc * mrioc,dma_addr_t phys_addr)127824a1566SKashyap Desai void *mpi3mr_get_sensebuf_virt_addr(struct mpi3mr_ioc *mrioc,
128824a1566SKashyap Desai 	dma_addr_t phys_addr)
129824a1566SKashyap Desai {
130824a1566SKashyap Desai 	if (!phys_addr)
131824a1566SKashyap Desai 		return NULL;
132824a1566SKashyap Desai 
133824a1566SKashyap Desai 	return mrioc->sense_buf + (phys_addr - mrioc->sense_buf_dma);
134824a1566SKashyap Desai }
135824a1566SKashyap Desai 
mpi3mr_repost_reply_buf(struct mpi3mr_ioc * mrioc,u64 reply_dma)136824a1566SKashyap Desai static void mpi3mr_repost_reply_buf(struct mpi3mr_ioc *mrioc,
137824a1566SKashyap Desai 	u64 reply_dma)
138824a1566SKashyap Desai {
139824a1566SKashyap Desai 	u32 old_idx = 0;
140a83ec831SSreekanth Reddy 	unsigned long flags;
141824a1566SKashyap Desai 
142a83ec831SSreekanth Reddy 	spin_lock_irqsave(&mrioc->reply_free_queue_lock, flags);
143824a1566SKashyap Desai 	old_idx  =  mrioc->reply_free_queue_host_index;
144824a1566SKashyap Desai 	mrioc->reply_free_queue_host_index = (
145824a1566SKashyap Desai 	    (mrioc->reply_free_queue_host_index ==
146824a1566SKashyap Desai 	    (mrioc->reply_free_qsz - 1)) ? 0 :
147824a1566SKashyap Desai 	    (mrioc->reply_free_queue_host_index + 1));
148824a1566SKashyap Desai 	mrioc->reply_free_q[old_idx] = cpu_to_le64(reply_dma);
149824a1566SKashyap Desai 	writel(mrioc->reply_free_queue_host_index,
150824a1566SKashyap Desai 	    &mrioc->sysif_regs->reply_free_host_index);
151a83ec831SSreekanth Reddy 	spin_unlock_irqrestore(&mrioc->reply_free_queue_lock, flags);
152824a1566SKashyap Desai }
153824a1566SKashyap Desai 
mpi3mr_repost_sense_buf(struct mpi3mr_ioc * mrioc,u64 sense_buf_dma)154824a1566SKashyap Desai void mpi3mr_repost_sense_buf(struct mpi3mr_ioc *mrioc,
155824a1566SKashyap Desai 	u64 sense_buf_dma)
156824a1566SKashyap Desai {
157824a1566SKashyap Desai 	u32 old_idx = 0;
158a83ec831SSreekanth Reddy 	unsigned long flags;
159824a1566SKashyap Desai 
160a83ec831SSreekanth Reddy 	spin_lock_irqsave(&mrioc->sbq_lock, flags);
161824a1566SKashyap Desai 	old_idx  =  mrioc->sbq_host_index;
162824a1566SKashyap Desai 	mrioc->sbq_host_index = ((mrioc->sbq_host_index ==
163824a1566SKashyap Desai 	    (mrioc->sense_buf_q_sz - 1)) ? 0 :
164824a1566SKashyap Desai 	    (mrioc->sbq_host_index + 1));
165824a1566SKashyap Desai 	mrioc->sense_buf_q[old_idx] = cpu_to_le64(sense_buf_dma);
166824a1566SKashyap Desai 	writel(mrioc->sbq_host_index,
167824a1566SKashyap Desai 	    &mrioc->sysif_regs->sense_buffer_free_host_index);
168a83ec831SSreekanth Reddy 	spin_unlock_irqrestore(&mrioc->sbq_lock, flags);
169824a1566SKashyap Desai }
170824a1566SKashyap Desai 
mpi3mr_print_event_data(struct mpi3mr_ioc * mrioc,struct mpi3_event_notification_reply * event_reply)1719fc4abfeSKashyap Desai static void mpi3mr_print_event_data(struct mpi3mr_ioc *mrioc,
1729fc4abfeSKashyap Desai 	struct mpi3_event_notification_reply *event_reply)
1739fc4abfeSKashyap Desai {
1749fc4abfeSKashyap Desai 	char *desc = NULL;
1759fc4abfeSKashyap Desai 	u16 event;
1769fc4abfeSKashyap Desai 
1779fc4abfeSKashyap Desai 	event = event_reply->event;
1789fc4abfeSKashyap Desai 
1799fc4abfeSKashyap Desai 	switch (event) {
1809fc4abfeSKashyap Desai 	case MPI3_EVENT_LOG_DATA:
1819fc4abfeSKashyap Desai 		desc = "Log Data";
1829fc4abfeSKashyap Desai 		break;
1839fc4abfeSKashyap Desai 	case MPI3_EVENT_CHANGE:
1849fc4abfeSKashyap Desai 		desc = "Event Change";
1859fc4abfeSKashyap Desai 		break;
1869fc4abfeSKashyap Desai 	case MPI3_EVENT_GPIO_INTERRUPT:
1879fc4abfeSKashyap Desai 		desc = "GPIO Interrupt";
1889fc4abfeSKashyap Desai 		break;
1899fc4abfeSKashyap Desai 	case MPI3_EVENT_CABLE_MGMT:
1909fc4abfeSKashyap Desai 		desc = "Cable Management";
1919fc4abfeSKashyap Desai 		break;
1929fc4abfeSKashyap Desai 	case MPI3_EVENT_ENERGY_PACK_CHANGE:
1939fc4abfeSKashyap Desai 		desc = "Energy Pack Change";
1949fc4abfeSKashyap Desai 		break;
1959fc4abfeSKashyap Desai 	case MPI3_EVENT_DEVICE_ADDED:
1969fc4abfeSKashyap Desai 	{
1979fc4abfeSKashyap Desai 		struct mpi3_device_page0 *event_data =
1989fc4abfeSKashyap Desai 		    (struct mpi3_device_page0 *)event_reply->event_data;
1999fc4abfeSKashyap Desai 		ioc_info(mrioc, "Device Added: dev=0x%04x Form=0x%x\n",
2009fc4abfeSKashyap Desai 		    event_data->dev_handle, event_data->device_form);
2019fc4abfeSKashyap Desai 		return;
2029fc4abfeSKashyap Desai 	}
2039fc4abfeSKashyap Desai 	case MPI3_EVENT_DEVICE_INFO_CHANGED:
2049fc4abfeSKashyap Desai 	{
2059fc4abfeSKashyap Desai 		struct mpi3_device_page0 *event_data =
2069fc4abfeSKashyap Desai 		    (struct mpi3_device_page0 *)event_reply->event_data;
2079fc4abfeSKashyap Desai 		ioc_info(mrioc, "Device Info Changed: dev=0x%04x Form=0x%x\n",
2089fc4abfeSKashyap Desai 		    event_data->dev_handle, event_data->device_form);
2099fc4abfeSKashyap Desai 		return;
2109fc4abfeSKashyap Desai 	}
2119fc4abfeSKashyap Desai 	case MPI3_EVENT_DEVICE_STATUS_CHANGE:
2129fc4abfeSKashyap Desai 	{
2139fc4abfeSKashyap Desai 		struct mpi3_event_data_device_status_change *event_data =
2149fc4abfeSKashyap Desai 		    (struct mpi3_event_data_device_status_change *)event_reply->event_data;
2159fc4abfeSKashyap Desai 		ioc_info(mrioc, "Device status Change: dev=0x%04x RC=0x%x\n",
2169fc4abfeSKashyap Desai 		    event_data->dev_handle, event_data->reason_code);
2179fc4abfeSKashyap Desai 		return;
2189fc4abfeSKashyap Desai 	}
2199fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_DISCOVERY:
2209fc4abfeSKashyap Desai 	{
2219fc4abfeSKashyap Desai 		struct mpi3_event_data_sas_discovery *event_data =
2229fc4abfeSKashyap Desai 		    (struct mpi3_event_data_sas_discovery *)event_reply->event_data;
2239fc4abfeSKashyap Desai 		ioc_info(mrioc, "SAS Discovery: (%s) status (0x%08x)\n",
2249fc4abfeSKashyap Desai 		    (event_data->reason_code == MPI3_EVENT_SAS_DISC_RC_STARTED) ?
2259fc4abfeSKashyap Desai 		    "start" : "stop",
2269fc4abfeSKashyap Desai 		    le32_to_cpu(event_data->discovery_status));
2279fc4abfeSKashyap Desai 		return;
2289fc4abfeSKashyap Desai 	}
2299fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE:
2309fc4abfeSKashyap Desai 		desc = "SAS Broadcast Primitive";
2319fc4abfeSKashyap Desai 		break;
2329fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_NOTIFY_PRIMITIVE:
2339fc4abfeSKashyap Desai 		desc = "SAS Notify Primitive";
2349fc4abfeSKashyap Desai 		break;
2359fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
2369fc4abfeSKashyap Desai 		desc = "SAS Init Device Status Change";
2379fc4abfeSKashyap Desai 		break;
2389fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_INIT_TABLE_OVERFLOW:
2399fc4abfeSKashyap Desai 		desc = "SAS Init Table Overflow";
2409fc4abfeSKashyap Desai 		break;
2419fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
2429fc4abfeSKashyap Desai 		desc = "SAS Topology Change List";
2439fc4abfeSKashyap Desai 		break;
2449fc4abfeSKashyap Desai 	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
2459fc4abfeSKashyap Desai 		desc = "Enclosure Device Status Change";
2469fc4abfeSKashyap Desai 		break;
2477188c03fSSreekanth Reddy 	case MPI3_EVENT_ENCL_DEVICE_ADDED:
2487188c03fSSreekanth Reddy 		desc = "Enclosure Added";
2497188c03fSSreekanth Reddy 		break;
2509fc4abfeSKashyap Desai 	case MPI3_EVENT_HARD_RESET_RECEIVED:
2519fc4abfeSKashyap Desai 		desc = "Hard Reset Received";
2529fc4abfeSKashyap Desai 		break;
2539fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_PHY_COUNTER:
2549fc4abfeSKashyap Desai 		desc = "SAS PHY Counter";
2559fc4abfeSKashyap Desai 		break;
2569fc4abfeSKashyap Desai 	case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR:
2579fc4abfeSKashyap Desai 		desc = "SAS Device Discovery Error";
2589fc4abfeSKashyap Desai 		break;
2599fc4abfeSKashyap Desai 	case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
2609fc4abfeSKashyap Desai 		desc = "PCIE Topology Change List";
2619fc4abfeSKashyap Desai 		break;
2629fc4abfeSKashyap Desai 	case MPI3_EVENT_PCIE_ENUMERATION:
2639fc4abfeSKashyap Desai 	{
2649fc4abfeSKashyap Desai 		struct mpi3_event_data_pcie_enumeration *event_data =
2659fc4abfeSKashyap Desai 		    (struct mpi3_event_data_pcie_enumeration *)event_reply->event_data;
2669fc4abfeSKashyap Desai 		ioc_info(mrioc, "PCIE Enumeration: (%s)",
2679fc4abfeSKashyap Desai 		    (event_data->reason_code ==
2689fc4abfeSKashyap Desai 		    MPI3_EVENT_PCIE_ENUM_RC_STARTED) ? "start" : "stop");
2699fc4abfeSKashyap Desai 		if (event_data->enumeration_status)
2709fc4abfeSKashyap Desai 			ioc_info(mrioc, "enumeration_status(0x%08x)\n",
2719fc4abfeSKashyap Desai 			    le32_to_cpu(event_data->enumeration_status));
2729fc4abfeSKashyap Desai 		return;
2739fc4abfeSKashyap Desai 	}
2749fc4abfeSKashyap Desai 	case MPI3_EVENT_PREPARE_FOR_RESET:
2759fc4abfeSKashyap Desai 		desc = "Prepare For Reset";
2769fc4abfeSKashyap Desai 		break;
277d8d08d16SRanjan Kumar 	case MPI3_EVENT_DIAGNOSTIC_BUFFER_STATUS_CHANGE:
278d8d08d16SRanjan Kumar 		desc = "Diagnostic Buffer Status Change";
279d8d08d16SRanjan Kumar 		break;
2809fc4abfeSKashyap Desai 	}
2819fc4abfeSKashyap Desai 
2829fc4abfeSKashyap Desai 	if (!desc)
2839fc4abfeSKashyap Desai 		return;
2849fc4abfeSKashyap Desai 
2859fc4abfeSKashyap Desai 	ioc_info(mrioc, "%s\n", desc);
2869fc4abfeSKashyap Desai }
2879fc4abfeSKashyap Desai 
mpi3mr_handle_events(struct mpi3mr_ioc * mrioc,struct mpi3_default_reply * def_reply)288824a1566SKashyap Desai static void mpi3mr_handle_events(struct mpi3mr_ioc *mrioc,
289824a1566SKashyap Desai 	struct mpi3_default_reply *def_reply)
290824a1566SKashyap Desai {
291824a1566SKashyap Desai 	struct mpi3_event_notification_reply *event_reply =
292824a1566SKashyap Desai 	    (struct mpi3_event_notification_reply *)def_reply;
293824a1566SKashyap Desai 
294824a1566SKashyap Desai 	mrioc->change_count = le16_to_cpu(event_reply->ioc_change_count);
2959fc4abfeSKashyap Desai 	mpi3mr_print_event_data(mrioc, event_reply);
29613ef29eaSKashyap Desai 	mpi3mr_os_handle_events(mrioc, event_reply);
297824a1566SKashyap Desai }
298824a1566SKashyap Desai 
299824a1566SKashyap Desai static struct mpi3mr_drv_cmd *
mpi3mr_get_drv_cmd(struct mpi3mr_ioc * mrioc,u16 host_tag,struct mpi3_default_reply * def_reply)300824a1566SKashyap Desai mpi3mr_get_drv_cmd(struct mpi3mr_ioc *mrioc, u16 host_tag,
301824a1566SKashyap Desai 	struct mpi3_default_reply *def_reply)
302824a1566SKashyap Desai {
30313ef29eaSKashyap Desai 	u16 idx;
30413ef29eaSKashyap Desai 
305824a1566SKashyap Desai 	switch (host_tag) {
306824a1566SKashyap Desai 	case MPI3MR_HOSTTAG_INITCMDS:
307824a1566SKashyap Desai 		return &mrioc->init_cmds;
30832d457d5SSreekanth Reddy 	case MPI3MR_HOSTTAG_CFG_CMDS:
30932d457d5SSreekanth Reddy 		return &mrioc->cfg_cmds;
310f5e6d5a3SSumit Saxena 	case MPI3MR_HOSTTAG_BSG_CMDS:
311f5e6d5a3SSumit Saxena 		return &mrioc->bsg_cmds;
312e844adb1SKashyap Desai 	case MPI3MR_HOSTTAG_BLK_TMS:
313e844adb1SKashyap Desai 		return &mrioc->host_tm_cmds;
31443ca1100SSumit Saxena 	case MPI3MR_HOSTTAG_PEL_ABORT:
31543ca1100SSumit Saxena 		return &mrioc->pel_abort_cmd;
31643ca1100SSumit Saxena 	case MPI3MR_HOSTTAG_PEL_WAIT:
31743ca1100SSumit Saxena 		return &mrioc->pel_cmds;
3182bd37e28SSreekanth Reddy 	case MPI3MR_HOSTTAG_TRANSPORT_CMDS:
3192bd37e28SSreekanth Reddy 		return &mrioc->transport_cmds;
320824a1566SKashyap Desai 	case MPI3MR_HOSTTAG_INVALID:
321824a1566SKashyap Desai 		if (def_reply && def_reply->function ==
322824a1566SKashyap Desai 		    MPI3_FUNCTION_EVENT_NOTIFICATION)
323824a1566SKashyap Desai 			mpi3mr_handle_events(mrioc, def_reply);
324824a1566SKashyap Desai 		return NULL;
325824a1566SKashyap Desai 	default:
326824a1566SKashyap Desai 		break;
327824a1566SKashyap Desai 	}
32813ef29eaSKashyap Desai 	if (host_tag >= MPI3MR_HOSTTAG_DEVRMCMD_MIN &&
32913ef29eaSKashyap Desai 	    host_tag <= MPI3MR_HOSTTAG_DEVRMCMD_MAX) {
33013ef29eaSKashyap Desai 		idx = host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
33113ef29eaSKashyap Desai 		return &mrioc->dev_rmhs_cmds[idx];
33213ef29eaSKashyap Desai 	}
333824a1566SKashyap Desai 
334c1af985dSSreekanth Reddy 	if (host_tag >= MPI3MR_HOSTTAG_EVTACKCMD_MIN &&
335c1af985dSSreekanth Reddy 	    host_tag <= MPI3MR_HOSTTAG_EVTACKCMD_MAX) {
336c1af985dSSreekanth Reddy 		idx = host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN;
337c1af985dSSreekanth Reddy 		return &mrioc->evtack_cmds[idx];
338c1af985dSSreekanth Reddy 	}
339c1af985dSSreekanth Reddy 
340824a1566SKashyap Desai 	return NULL;
341824a1566SKashyap Desai }
342824a1566SKashyap Desai 
mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc * mrioc,struct mpi3_default_reply_descriptor * reply_desc,u64 * reply_dma)343824a1566SKashyap Desai static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc,
344824a1566SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc, u64 *reply_dma)
345824a1566SKashyap Desai {
346824a1566SKashyap Desai 	u16 reply_desc_type, host_tag = 0;
347824a1566SKashyap Desai 	u16 ioc_status = MPI3_IOCSTATUS_SUCCESS;
3486dc7050dSRanjan Kumar 	u16 masked_ioc_status = MPI3_IOCSTATUS_SUCCESS;
349d8d08d16SRanjan Kumar 	u32 ioc_loginfo = 0, sense_count = 0;
350824a1566SKashyap Desai 	struct mpi3_status_reply_descriptor *status_desc;
351824a1566SKashyap Desai 	struct mpi3_address_reply_descriptor *addr_desc;
352824a1566SKashyap Desai 	struct mpi3_success_reply_descriptor *success_desc;
353824a1566SKashyap Desai 	struct mpi3_default_reply *def_reply = NULL;
354824a1566SKashyap Desai 	struct mpi3mr_drv_cmd *cmdptr = NULL;
355824a1566SKashyap Desai 	struct mpi3_scsi_io_reply *scsi_reply;
356d8d08d16SRanjan Kumar 	struct scsi_sense_hdr sshdr;
357824a1566SKashyap Desai 	u8 *sense_buf = NULL;
358824a1566SKashyap Desai 
359824a1566SKashyap Desai 	*reply_dma = 0;
360824a1566SKashyap Desai 	reply_desc_type = le16_to_cpu(reply_desc->reply_flags) &
361824a1566SKashyap Desai 	    MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK;
362824a1566SKashyap Desai 	switch (reply_desc_type) {
363824a1566SKashyap Desai 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS:
364824a1566SKashyap Desai 		status_desc = (struct mpi3_status_reply_descriptor *)reply_desc;
365824a1566SKashyap Desai 		host_tag = le16_to_cpu(status_desc->host_tag);
366824a1566SKashyap Desai 		ioc_status = le16_to_cpu(status_desc->ioc_status);
367824a1566SKashyap Desai 		if (ioc_status &
368824a1566SKashyap Desai 		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
369824a1566SKashyap Desai 			ioc_loginfo = le32_to_cpu(status_desc->ioc_log_info);
3706dc7050dSRanjan Kumar 		masked_ioc_status = ioc_status & MPI3_IOCSTATUS_STATUS_MASK;
3716dc7050dSRanjan Kumar 		mpi3mr_reply_trigger(mrioc, masked_ioc_status, ioc_loginfo);
372824a1566SKashyap Desai 		break;
373824a1566SKashyap Desai 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY:
374824a1566SKashyap Desai 		addr_desc = (struct mpi3_address_reply_descriptor *)reply_desc;
375824a1566SKashyap Desai 		*reply_dma = le64_to_cpu(addr_desc->reply_frame_address);
376824a1566SKashyap Desai 		def_reply = mpi3mr_get_reply_virt_addr(mrioc, *reply_dma);
377824a1566SKashyap Desai 		if (!def_reply)
378824a1566SKashyap Desai 			goto out;
379824a1566SKashyap Desai 		host_tag = le16_to_cpu(def_reply->host_tag);
380824a1566SKashyap Desai 		ioc_status = le16_to_cpu(def_reply->ioc_status);
381824a1566SKashyap Desai 		if (ioc_status &
382824a1566SKashyap Desai 		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
383824a1566SKashyap Desai 			ioc_loginfo = le32_to_cpu(def_reply->ioc_log_info);
3846dc7050dSRanjan Kumar 		masked_ioc_status = ioc_status & MPI3_IOCSTATUS_STATUS_MASK;
385824a1566SKashyap Desai 		if (def_reply->function == MPI3_FUNCTION_SCSI_IO) {
386824a1566SKashyap Desai 			scsi_reply = (struct mpi3_scsi_io_reply *)def_reply;
387824a1566SKashyap Desai 			sense_buf = mpi3mr_get_sensebuf_virt_addr(mrioc,
388824a1566SKashyap Desai 			    le64_to_cpu(scsi_reply->sense_data_buffer_address));
389d8d08d16SRanjan Kumar 			sense_count = le32_to_cpu(scsi_reply->sense_count);
390d8d08d16SRanjan Kumar 			if (sense_buf) {
391d8d08d16SRanjan Kumar 				scsi_normalize_sense(sense_buf, sense_count,
392d8d08d16SRanjan Kumar 				    &sshdr);
393d8d08d16SRanjan Kumar 				mpi3mr_scsisense_trigger(mrioc, sshdr.sense_key,
394d8d08d16SRanjan Kumar 				    sshdr.asc, sshdr.ascq);
395824a1566SKashyap Desai 			}
396d8d08d16SRanjan Kumar 		}
3976dc7050dSRanjan Kumar 		mpi3mr_reply_trigger(mrioc, masked_ioc_status, ioc_loginfo);
398824a1566SKashyap Desai 		break;
399824a1566SKashyap Desai 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS:
400824a1566SKashyap Desai 		success_desc = (struct mpi3_success_reply_descriptor *)reply_desc;
401824a1566SKashyap Desai 		host_tag = le16_to_cpu(success_desc->host_tag);
402824a1566SKashyap Desai 		break;
403824a1566SKashyap Desai 	default:
404824a1566SKashyap Desai 		break;
405824a1566SKashyap Desai 	}
406824a1566SKashyap Desai 
407824a1566SKashyap Desai 	cmdptr = mpi3mr_get_drv_cmd(mrioc, host_tag, def_reply);
408824a1566SKashyap Desai 	if (cmdptr) {
409824a1566SKashyap Desai 		if (cmdptr->state & MPI3MR_CMD_PENDING) {
410824a1566SKashyap Desai 			cmdptr->state |= MPI3MR_CMD_COMPLETE;
411824a1566SKashyap Desai 			cmdptr->ioc_loginfo = ioc_loginfo;
4126dc7050dSRanjan Kumar 			if (host_tag == MPI3MR_HOSTTAG_BSG_CMDS)
413824a1566SKashyap Desai 				cmdptr->ioc_status = ioc_status;
4146dc7050dSRanjan Kumar 			else
4156dc7050dSRanjan Kumar 				cmdptr->ioc_status = masked_ioc_status;
416824a1566SKashyap Desai 			cmdptr->state &= ~MPI3MR_CMD_PENDING;
417824a1566SKashyap Desai 			if (def_reply) {
418824a1566SKashyap Desai 				cmdptr->state |= MPI3MR_CMD_REPLY_VALID;
419824a1566SKashyap Desai 				memcpy((u8 *)cmdptr->reply, (u8 *)def_reply,
420c5758fc7SSreekanth Reddy 				    mrioc->reply_sz);
421824a1566SKashyap Desai 			}
422f762326bSSathya Prakash 			if (sense_buf && cmdptr->sensebuf) {
423f762326bSSathya Prakash 				cmdptr->is_sense = 1;
424f762326bSSathya Prakash 				memcpy(cmdptr->sensebuf, sense_buf,
425f762326bSSathya Prakash 				       MPI3MR_SENSE_BUF_SZ);
426f762326bSSathya Prakash 			}
427824a1566SKashyap Desai 			if (cmdptr->is_waiting) {
428824a1566SKashyap Desai 				complete(&cmdptr->done);
429824a1566SKashyap Desai 				cmdptr->is_waiting = 0;
430824a1566SKashyap Desai 			} else if (cmdptr->callback)
431824a1566SKashyap Desai 				cmdptr->callback(mrioc, cmdptr);
432824a1566SKashyap Desai 		}
433824a1566SKashyap Desai 	}
434824a1566SKashyap Desai out:
435824a1566SKashyap Desai 	if (sense_buf)
436824a1566SKashyap Desai 		mpi3mr_repost_sense_buf(mrioc,
437824a1566SKashyap Desai 		    le64_to_cpu(scsi_reply->sense_data_buffer_address));
438824a1566SKashyap Desai }
439824a1566SKashyap Desai 
mpi3mr_process_admin_reply_q(struct mpi3mr_ioc * mrioc)44002ca7da2SRanjan Kumar int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc)
441824a1566SKashyap Desai {
442824a1566SKashyap Desai 	u32 exp_phase = mrioc->admin_reply_ephase;
443824a1566SKashyap Desai 	u32 admin_reply_ci = mrioc->admin_reply_ci;
444824a1566SKashyap Desai 	u32 num_admin_replies = 0;
445824a1566SKashyap Desai 	u64 reply_dma = 0;
446199510e3SRanjan Kumar 	u16 threshold_comps = 0;
447824a1566SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc;
448824a1566SKashyap Desai 
44902ca7da2SRanjan Kumar 	if (!atomic_add_unless(&mrioc->admin_reply_q_in_use, 1, 1))
45002ca7da2SRanjan Kumar 		return 0;
45102ca7da2SRanjan Kumar 
452824a1566SKashyap Desai 	reply_desc = (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base +
453824a1566SKashyap Desai 	    admin_reply_ci;
454824a1566SKashyap Desai 
455824a1566SKashyap Desai 	if ((le16_to_cpu(reply_desc->reply_flags) &
45602ca7da2SRanjan Kumar 	    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) {
45702ca7da2SRanjan Kumar 		atomic_dec(&mrioc->admin_reply_q_in_use);
458824a1566SKashyap Desai 		return 0;
45902ca7da2SRanjan Kumar 	}
460824a1566SKashyap Desai 
461824a1566SKashyap Desai 	do {
462f2a79d20SSreekanth Reddy 		if (mrioc->unrecoverable)
463f2a79d20SSreekanth Reddy 			break;
464f2a79d20SSreekanth Reddy 
465824a1566SKashyap Desai 		mrioc->admin_req_ci = le16_to_cpu(reply_desc->request_queue_ci);
466824a1566SKashyap Desai 		mpi3mr_process_admin_reply_desc(mrioc, reply_desc, &reply_dma);
467824a1566SKashyap Desai 		if (reply_dma)
468824a1566SKashyap Desai 			mpi3mr_repost_reply_buf(mrioc, reply_dma);
469824a1566SKashyap Desai 		num_admin_replies++;
470199510e3SRanjan Kumar 		threshold_comps++;
471824a1566SKashyap Desai 		if (++admin_reply_ci == mrioc->num_admin_replies) {
472824a1566SKashyap Desai 			admin_reply_ci = 0;
473824a1566SKashyap Desai 			exp_phase ^= 1;
474824a1566SKashyap Desai 		}
475824a1566SKashyap Desai 		reply_desc =
476824a1566SKashyap Desai 		    (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base +
477824a1566SKashyap Desai 		    admin_reply_ci;
478824a1566SKashyap Desai 		if ((le16_to_cpu(reply_desc->reply_flags) &
479824a1566SKashyap Desai 		    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
480824a1566SKashyap Desai 			break;
481199510e3SRanjan Kumar 		if (threshold_comps == MPI3MR_THRESHOLD_REPLY_COUNT) {
482199510e3SRanjan Kumar 			writel(admin_reply_ci,
483199510e3SRanjan Kumar 			    &mrioc->sysif_regs->admin_reply_queue_ci);
484199510e3SRanjan Kumar 			threshold_comps = 0;
485199510e3SRanjan Kumar 		}
486824a1566SKashyap Desai 	} while (1);
487824a1566SKashyap Desai 
488824a1566SKashyap Desai 	writel(admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci);
489824a1566SKashyap Desai 	mrioc->admin_reply_ci = admin_reply_ci;
490824a1566SKashyap Desai 	mrioc->admin_reply_ephase = exp_phase;
49102ca7da2SRanjan Kumar 	atomic_dec(&mrioc->admin_reply_q_in_use);
492824a1566SKashyap Desai 
493824a1566SKashyap Desai 	return num_admin_replies;
494824a1566SKashyap Desai }
495824a1566SKashyap Desai 
496023ab2a9SKashyap Desai /**
497023ab2a9SKashyap Desai  * mpi3mr_get_reply_desc - get reply descriptor frame corresponding to
498023ab2a9SKashyap Desai  *	queue's consumer index from operational reply descriptor queue.
499023ab2a9SKashyap Desai  * @op_reply_q: op_reply_qinfo object
500023ab2a9SKashyap Desai  * @reply_ci: operational reply descriptor's queue consumer index
501023ab2a9SKashyap Desai  *
502904fdd20SRandy Dunlap  * Returns: reply descriptor frame address
503023ab2a9SKashyap Desai  */
504023ab2a9SKashyap Desai static inline struct mpi3_default_reply_descriptor *
mpi3mr_get_reply_desc(struct op_reply_qinfo * op_reply_q,u32 reply_ci)505023ab2a9SKashyap Desai mpi3mr_get_reply_desc(struct op_reply_qinfo *op_reply_q, u32 reply_ci)
506023ab2a9SKashyap Desai {
507023ab2a9SKashyap Desai 	void *segment_base_addr;
508023ab2a9SKashyap Desai 	struct segments *segments = op_reply_q->q_segments;
509023ab2a9SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc = NULL;
510023ab2a9SKashyap Desai 
511023ab2a9SKashyap Desai 	segment_base_addr =
512023ab2a9SKashyap Desai 	    segments[reply_ci / op_reply_q->segment_qd].segment;
513023ab2a9SKashyap Desai 	reply_desc = (struct mpi3_default_reply_descriptor *)segment_base_addr +
514023ab2a9SKashyap Desai 	    (reply_ci % op_reply_q->segment_qd);
515023ab2a9SKashyap Desai 	return reply_desc;
516023ab2a9SKashyap Desai }
517023ab2a9SKashyap Desai 
518afd3a579SSreekanth Reddy /**
519afd3a579SSreekanth Reddy  * mpi3mr_process_op_reply_q - Operational reply queue handler
520afd3a579SSreekanth Reddy  * @mrioc: Adapter instance reference
521afd3a579SSreekanth Reddy  * @op_reply_q: Operational reply queue info
522afd3a579SSreekanth Reddy  *
523afd3a579SSreekanth Reddy  * Checks the specific operational reply queue and drains the
524afd3a579SSreekanth Reddy  * reply queue entries until the queue is empty and process the
525afd3a579SSreekanth Reddy  * individual reply descriptors.
526afd3a579SSreekanth Reddy  *
527afd3a579SSreekanth Reddy  * Return: 0 if queue is already processed,or number of reply
528afd3a579SSreekanth Reddy  *	    descriptors processed.
529afd3a579SSreekanth Reddy  */
mpi3mr_process_op_reply_q(struct mpi3mr_ioc * mrioc,struct op_reply_qinfo * op_reply_q)530afd3a579SSreekanth Reddy int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc,
531afd3a579SSreekanth Reddy 	struct op_reply_qinfo *op_reply_q)
532023ab2a9SKashyap Desai {
533023ab2a9SKashyap Desai 	struct op_req_qinfo *op_req_q;
534023ab2a9SKashyap Desai 	u32 exp_phase;
535023ab2a9SKashyap Desai 	u32 reply_ci;
536023ab2a9SKashyap Desai 	u32 num_op_reply = 0;
537023ab2a9SKashyap Desai 	u64 reply_dma = 0;
538023ab2a9SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc;
539199510e3SRanjan Kumar 	u16 req_q_idx = 0, reply_qidx, threshold_comps = 0;
540023ab2a9SKashyap Desai 
541023ab2a9SKashyap Desai 	reply_qidx = op_reply_q->qid - 1;
542023ab2a9SKashyap Desai 
543463429f8SKashyap Desai 	if (!atomic_add_unless(&op_reply_q->in_use, 1, 1))
544463429f8SKashyap Desai 		return 0;
545463429f8SKashyap Desai 
546023ab2a9SKashyap Desai 	exp_phase = op_reply_q->ephase;
547023ab2a9SKashyap Desai 	reply_ci = op_reply_q->ci;
548023ab2a9SKashyap Desai 
549023ab2a9SKashyap Desai 	reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci);
550023ab2a9SKashyap Desai 	if ((le16_to_cpu(reply_desc->reply_flags) &
551023ab2a9SKashyap Desai 	    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) {
552463429f8SKashyap Desai 		atomic_dec(&op_reply_q->in_use);
553023ab2a9SKashyap Desai 		return 0;
554023ab2a9SKashyap Desai 	}
555023ab2a9SKashyap Desai 
556023ab2a9SKashyap Desai 	do {
557f2a79d20SSreekanth Reddy 		if (mrioc->unrecoverable)
558f2a79d20SSreekanth Reddy 			break;
559f2a79d20SSreekanth Reddy 
560023ab2a9SKashyap Desai 		req_q_idx = le16_to_cpu(reply_desc->request_queue_id) - 1;
561023ab2a9SKashyap Desai 		op_req_q = &mrioc->req_qinfo[req_q_idx];
562023ab2a9SKashyap Desai 
563023ab2a9SKashyap Desai 		WRITE_ONCE(op_req_q->ci, le16_to_cpu(reply_desc->request_queue_ci));
564023ab2a9SKashyap Desai 		mpi3mr_process_op_reply_desc(mrioc, reply_desc, &reply_dma,
565023ab2a9SKashyap Desai 		    reply_qidx);
566463429f8SKashyap Desai 		atomic_dec(&op_reply_q->pend_ios);
567023ab2a9SKashyap Desai 		if (reply_dma)
568023ab2a9SKashyap Desai 			mpi3mr_repost_reply_buf(mrioc, reply_dma);
569023ab2a9SKashyap Desai 		num_op_reply++;
570199510e3SRanjan Kumar 		threshold_comps++;
571023ab2a9SKashyap Desai 
572023ab2a9SKashyap Desai 		if (++reply_ci == op_reply_q->num_replies) {
573023ab2a9SKashyap Desai 			reply_ci = 0;
574023ab2a9SKashyap Desai 			exp_phase ^= 1;
575023ab2a9SKashyap Desai 		}
576023ab2a9SKashyap Desai 
577023ab2a9SKashyap Desai 		reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci);
578023ab2a9SKashyap Desai 
579023ab2a9SKashyap Desai 		if ((le16_to_cpu(reply_desc->reply_flags) &
580023ab2a9SKashyap Desai 		    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
581023ab2a9SKashyap Desai 			break;
5827f9f953dSSreekanth Reddy #ifndef CONFIG_PREEMPT_RT
583463429f8SKashyap Desai 		/*
584463429f8SKashyap Desai 		 * Exit completion loop to avoid CPU lockup
585463429f8SKashyap Desai 		 * Ensure remaining completion happens from threaded ISR.
586463429f8SKashyap Desai 		 */
587463429f8SKashyap Desai 		if (num_op_reply > mrioc->max_host_ios) {
588afd3a579SSreekanth Reddy 			op_reply_q->enable_irq_poll = true;
589463429f8SKashyap Desai 			break;
590463429f8SKashyap Desai 		}
5917f9f953dSSreekanth Reddy #endif
592199510e3SRanjan Kumar 		if (threshold_comps == MPI3MR_THRESHOLD_REPLY_COUNT) {
593199510e3SRanjan Kumar 			writel(reply_ci,
594199510e3SRanjan Kumar 			    &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].consumer_index);
595199510e3SRanjan Kumar 			atomic_sub(threshold_comps, &op_reply_q->pend_ios);
596199510e3SRanjan Kumar 			threshold_comps = 0;
597199510e3SRanjan Kumar 		}
598023ab2a9SKashyap Desai 	} while (1);
599023ab2a9SKashyap Desai 
600023ab2a9SKashyap Desai 	writel(reply_ci,
601023ab2a9SKashyap Desai 	    &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].consumer_index);
602023ab2a9SKashyap Desai 	op_reply_q->ci = reply_ci;
603023ab2a9SKashyap Desai 	op_reply_q->ephase = exp_phase;
604199510e3SRanjan Kumar 	atomic_sub(threshold_comps, &op_reply_q->pend_ios);
605463429f8SKashyap Desai 	atomic_dec(&op_reply_q->in_use);
606023ab2a9SKashyap Desai 	return num_op_reply;
607023ab2a9SKashyap Desai }
608023ab2a9SKashyap Desai 
609afd3a579SSreekanth Reddy /**
610afd3a579SSreekanth Reddy  * mpi3mr_blk_mq_poll - Operational reply queue handler
611afd3a579SSreekanth Reddy  * @shost: SCSI Host reference
612afd3a579SSreekanth Reddy  * @queue_num: Request queue number (w.r.t OS it is hardware context number)
613afd3a579SSreekanth Reddy  *
614afd3a579SSreekanth Reddy  * Checks the specific operational reply queue and drains the
615afd3a579SSreekanth Reddy  * reply queue entries until the queue is empty and process the
616afd3a579SSreekanth Reddy  * individual reply descriptors.
617afd3a579SSreekanth Reddy  *
618afd3a579SSreekanth Reddy  * Return: 0 if queue is already processed,or number of reply
619afd3a579SSreekanth Reddy  *	    descriptors processed.
620afd3a579SSreekanth Reddy  */
mpi3mr_blk_mq_poll(struct Scsi_Host * shost,unsigned int queue_num)621afd3a579SSreekanth Reddy int mpi3mr_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
622afd3a579SSreekanth Reddy {
623afd3a579SSreekanth Reddy 	int num_entries = 0;
624afd3a579SSreekanth Reddy 	struct mpi3mr_ioc *mrioc;
625afd3a579SSreekanth Reddy 
626afd3a579SSreekanth Reddy 	mrioc = (struct mpi3mr_ioc *)shost->hostdata;
627afd3a579SSreekanth Reddy 
628f2a79d20SSreekanth Reddy 	if ((mrioc->reset_in_progress || mrioc->prepare_for_reset ||
6291c342b05SSumit Saxena 	    mrioc->unrecoverable || mrioc->pci_err_recovery))
630afd3a579SSreekanth Reddy 		return 0;
631afd3a579SSreekanth Reddy 
632afd3a579SSreekanth Reddy 	num_entries = mpi3mr_process_op_reply_q(mrioc,
633afd3a579SSreekanth Reddy 			&mrioc->op_reply_qinfo[queue_num]);
634afd3a579SSreekanth Reddy 
635afd3a579SSreekanth Reddy 	return num_entries;
636afd3a579SSreekanth Reddy }
637afd3a579SSreekanth Reddy 
mpi3mr_isr_primary(int irq,void * privdata)638824a1566SKashyap Desai static irqreturn_t mpi3mr_isr_primary(int irq, void *privdata)
639824a1566SKashyap Desai {
640824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info = privdata;
641824a1566SKashyap Desai 	struct mpi3mr_ioc *mrioc;
642824a1566SKashyap Desai 	u16 midx;
643463429f8SKashyap Desai 	u32 num_admin_replies = 0, num_op_reply = 0;
644824a1566SKashyap Desai 
645824a1566SKashyap Desai 	if (!intr_info)
646824a1566SKashyap Desai 		return IRQ_NONE;
647824a1566SKashyap Desai 
648824a1566SKashyap Desai 	mrioc = intr_info->mrioc;
649824a1566SKashyap Desai 
650824a1566SKashyap Desai 	if (!mrioc->intr_enabled)
651824a1566SKashyap Desai 		return IRQ_NONE;
652824a1566SKashyap Desai 
653824a1566SKashyap Desai 	midx = intr_info->msix_index;
654824a1566SKashyap Desai 
655824a1566SKashyap Desai 	if (!midx)
656824a1566SKashyap Desai 		num_admin_replies = mpi3mr_process_admin_reply_q(mrioc);
657463429f8SKashyap Desai 	if (intr_info->op_reply_q)
658afd3a579SSreekanth Reddy 		num_op_reply = mpi3mr_process_op_reply_q(mrioc,
659afd3a579SSreekanth Reddy 		    intr_info->op_reply_q);
660824a1566SKashyap Desai 
661463429f8SKashyap Desai 	if (num_admin_replies || num_op_reply)
662824a1566SKashyap Desai 		return IRQ_HANDLED;
663824a1566SKashyap Desai 	else
664824a1566SKashyap Desai 		return IRQ_NONE;
665824a1566SKashyap Desai }
666824a1566SKashyap Desai 
6677f9f953dSSreekanth Reddy #ifndef CONFIG_PREEMPT_RT
6687f9f953dSSreekanth Reddy 
mpi3mr_isr(int irq,void * privdata)669824a1566SKashyap Desai static irqreturn_t mpi3mr_isr(int irq, void *privdata)
670824a1566SKashyap Desai {
671824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info = privdata;
672824a1566SKashyap Desai 	int ret;
673824a1566SKashyap Desai 
674824a1566SKashyap Desai 	if (!intr_info)
675824a1566SKashyap Desai 		return IRQ_NONE;
676824a1566SKashyap Desai 
677824a1566SKashyap Desai 	/* Call primary ISR routine */
678824a1566SKashyap Desai 	ret = mpi3mr_isr_primary(irq, privdata);
679824a1566SKashyap Desai 
680463429f8SKashyap Desai 	/*
681463429f8SKashyap Desai 	 * If more IOs are expected, schedule IRQ polling thread.
682463429f8SKashyap Desai 	 * Otherwise exit from ISR.
683463429f8SKashyap Desai 	 */
684463429f8SKashyap Desai 	if (!intr_info->op_reply_q)
685824a1566SKashyap Desai 		return ret;
686463429f8SKashyap Desai 
687463429f8SKashyap Desai 	if (!intr_info->op_reply_q->enable_irq_poll ||
688463429f8SKashyap Desai 	    !atomic_read(&intr_info->op_reply_q->pend_ios))
689463429f8SKashyap Desai 		return ret;
690463429f8SKashyap Desai 
6912e31be86SSreekanth Reddy 	disable_irq_nosync(intr_info->os_irq);
692463429f8SKashyap Desai 
693463429f8SKashyap Desai 	return IRQ_WAKE_THREAD;
694824a1566SKashyap Desai }
695824a1566SKashyap Desai 
696824a1566SKashyap Desai /**
697824a1566SKashyap Desai  * mpi3mr_isr_poll - Reply queue polling routine
698824a1566SKashyap Desai  * @irq: IRQ
699824a1566SKashyap Desai  * @privdata: Interrupt info
700824a1566SKashyap Desai  *
701824a1566SKashyap Desai  * poll for pending I/O completions in a loop until pending I/Os
702824a1566SKashyap Desai  * present or controller queue depth I/Os are processed.
703824a1566SKashyap Desai  *
704824a1566SKashyap Desai  * Return: IRQ_NONE or IRQ_HANDLED
705824a1566SKashyap Desai  */
mpi3mr_isr_poll(int irq,void * privdata)706824a1566SKashyap Desai static irqreturn_t mpi3mr_isr_poll(int irq, void *privdata)
707824a1566SKashyap Desai {
708463429f8SKashyap Desai 	struct mpi3mr_intr_info *intr_info = privdata;
709463429f8SKashyap Desai 	struct mpi3mr_ioc *mrioc;
710463429f8SKashyap Desai 	u16 midx;
711463429f8SKashyap Desai 	u32 num_op_reply = 0;
712463429f8SKashyap Desai 
713463429f8SKashyap Desai 	if (!intr_info || !intr_info->op_reply_q)
714463429f8SKashyap Desai 		return IRQ_NONE;
715463429f8SKashyap Desai 
716463429f8SKashyap Desai 	mrioc = intr_info->mrioc;
717463429f8SKashyap Desai 	midx = intr_info->msix_index;
718463429f8SKashyap Desai 
719463429f8SKashyap Desai 	/* Poll for pending IOs completions */
720463429f8SKashyap Desai 	do {
721f2a79d20SSreekanth Reddy 		if (!mrioc->intr_enabled || mrioc->unrecoverable)
722463429f8SKashyap Desai 			break;
723463429f8SKashyap Desai 
724463429f8SKashyap Desai 		if (!midx)
725463429f8SKashyap Desai 			mpi3mr_process_admin_reply_q(mrioc);
726463429f8SKashyap Desai 		if (intr_info->op_reply_q)
727463429f8SKashyap Desai 			num_op_reply +=
728afd3a579SSreekanth Reddy 			    mpi3mr_process_op_reply_q(mrioc,
729afd3a579SSreekanth Reddy 				intr_info->op_reply_q);
730463429f8SKashyap Desai 
73124d7071dSTomas Henzl 		usleep_range(MPI3MR_IRQ_POLL_SLEEP, MPI3MR_IRQ_POLL_SLEEP + 1);
732463429f8SKashyap Desai 
733463429f8SKashyap Desai 	} while (atomic_read(&intr_info->op_reply_q->pend_ios) &&
734463429f8SKashyap Desai 	    (num_op_reply < mrioc->max_host_ios));
735463429f8SKashyap Desai 
736463429f8SKashyap Desai 	intr_info->op_reply_q->enable_irq_poll = false;
7372e31be86SSreekanth Reddy 	enable_irq(intr_info->os_irq);
738463429f8SKashyap Desai 
739824a1566SKashyap Desai 	return IRQ_HANDLED;
740824a1566SKashyap Desai }
741824a1566SKashyap Desai 
7427f9f953dSSreekanth Reddy #endif
7437f9f953dSSreekanth Reddy 
744824a1566SKashyap Desai /**
745824a1566SKashyap Desai  * mpi3mr_request_irq - Request IRQ and register ISR
746824a1566SKashyap Desai  * @mrioc: Adapter instance reference
747824a1566SKashyap Desai  * @index: IRQ vector index
748824a1566SKashyap Desai  *
749824a1566SKashyap Desai  * Request threaded ISR with primary ISR and secondary
750824a1566SKashyap Desai  *
751824a1566SKashyap Desai  * Return: 0 on success and non zero on failures.
752824a1566SKashyap Desai  */
mpi3mr_request_irq(struct mpi3mr_ioc * mrioc,u16 index)753824a1566SKashyap Desai static inline int mpi3mr_request_irq(struct mpi3mr_ioc *mrioc, u16 index)
754824a1566SKashyap Desai {
755824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
756824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info = mrioc->intr_info + index;
757824a1566SKashyap Desai 	int retval = 0;
758824a1566SKashyap Desai 
759824a1566SKashyap Desai 	intr_info->mrioc = mrioc;
760824a1566SKashyap Desai 	intr_info->msix_index = index;
761824a1566SKashyap Desai 	intr_info->op_reply_q = NULL;
762824a1566SKashyap Desai 
763824a1566SKashyap Desai 	snprintf(intr_info->name, MPI3MR_NAME_LENGTH, "%s%d-msix%d",
764824a1566SKashyap Desai 	    mrioc->driver_name, mrioc->id, index);
765824a1566SKashyap Desai 
7667f9f953dSSreekanth Reddy #ifndef CONFIG_PREEMPT_RT
767824a1566SKashyap Desai 	retval = request_threaded_irq(pci_irq_vector(pdev, index), mpi3mr_isr,
768824a1566SKashyap Desai 	    mpi3mr_isr_poll, IRQF_SHARED, intr_info->name, intr_info);
7697f9f953dSSreekanth Reddy #else
7707f9f953dSSreekanth Reddy 	retval = request_threaded_irq(pci_irq_vector(pdev, index), mpi3mr_isr_primary,
7717f9f953dSSreekanth Reddy 	    NULL, IRQF_SHARED, intr_info->name, intr_info);
7727f9f953dSSreekanth Reddy #endif
773824a1566SKashyap Desai 	if (retval) {
774824a1566SKashyap Desai 		ioc_err(mrioc, "%s: Unable to allocate interrupt %d!\n",
775824a1566SKashyap Desai 		    intr_info->name, pci_irq_vector(pdev, index));
776824a1566SKashyap Desai 		return retval;
777824a1566SKashyap Desai 	}
778824a1566SKashyap Desai 
7792e31be86SSreekanth Reddy 	intr_info->os_irq = pci_irq_vector(pdev, index);
780824a1566SKashyap Desai 	return retval;
781824a1566SKashyap Desai }
782824a1566SKashyap Desai 
mpi3mr_calc_poll_queues(struct mpi3mr_ioc * mrioc,u16 max_vectors)783afd3a579SSreekanth Reddy static void mpi3mr_calc_poll_queues(struct mpi3mr_ioc *mrioc, u16 max_vectors)
784afd3a579SSreekanth Reddy {
785afd3a579SSreekanth Reddy 	if (!mrioc->requested_poll_qcount)
786afd3a579SSreekanth Reddy 		return;
787afd3a579SSreekanth Reddy 
788afd3a579SSreekanth Reddy 	/* Reserved for Admin and Default Queue */
789afd3a579SSreekanth Reddy 	if (max_vectors > 2 &&
790afd3a579SSreekanth Reddy 		(mrioc->requested_poll_qcount < max_vectors - 2)) {
791afd3a579SSreekanth Reddy 		ioc_info(mrioc,
792afd3a579SSreekanth Reddy 		    "enabled polled queues (%d) msix (%d)\n",
793afd3a579SSreekanth Reddy 		    mrioc->requested_poll_qcount, max_vectors);
794afd3a579SSreekanth Reddy 	} else {
795afd3a579SSreekanth Reddy 		ioc_info(mrioc,
796afd3a579SSreekanth Reddy 		    "disabled polled queues (%d) msix (%d) because of no resources for default queue\n",
797afd3a579SSreekanth Reddy 		    mrioc->requested_poll_qcount, max_vectors);
798afd3a579SSreekanth Reddy 		mrioc->requested_poll_qcount = 0;
799afd3a579SSreekanth Reddy 	}
800afd3a579SSreekanth Reddy }
801afd3a579SSreekanth Reddy 
802824a1566SKashyap Desai /**
803824a1566SKashyap Desai  * mpi3mr_setup_isr - Setup ISR for the controller
804824a1566SKashyap Desai  * @mrioc: Adapter instance reference
805824a1566SKashyap Desai  * @setup_one: Request one IRQ or more
806824a1566SKashyap Desai  *
807824a1566SKashyap Desai  * Allocate IRQ vectors and call mpi3mr_request_irq to setup ISR
808824a1566SKashyap Desai  *
809824a1566SKashyap Desai  * Return: 0 on success and non zero on failures.
810824a1566SKashyap Desai  */
mpi3mr_setup_isr(struct mpi3mr_ioc * mrioc,u8 setup_one)811824a1566SKashyap Desai static int mpi3mr_setup_isr(struct mpi3mr_ioc *mrioc, u8 setup_one)
812824a1566SKashyap Desai {
813824a1566SKashyap Desai 	unsigned int irq_flags = PCI_IRQ_MSIX;
814afd3a579SSreekanth Reddy 	int max_vectors, min_vec;
8152938beddSDan Carpenter 	int retval;
8162938beddSDan Carpenter 	int i;
817afd3a579SSreekanth Reddy 	struct irq_affinity desc = { .pre_vectors =  1, .post_vectors = 1 };
818824a1566SKashyap Desai 
819fe6db615SSreekanth Reddy 	if (mrioc->is_intr_info_set)
820fe6db615SSreekanth Reddy 		return 0;
821fe6db615SSreekanth Reddy 
822824a1566SKashyap Desai 	mpi3mr_cleanup_isr(mrioc);
823824a1566SKashyap Desai 
824afd3a579SSreekanth Reddy 	if (setup_one || reset_devices) {
825824a1566SKashyap Desai 		max_vectors = 1;
826afd3a579SSreekanth Reddy 		retval = pci_alloc_irq_vectors(mrioc->pdev,
827afd3a579SSreekanth Reddy 		    1, max_vectors, irq_flags);
828afd3a579SSreekanth Reddy 		if (retval < 0) {
829afd3a579SSreekanth Reddy 			ioc_err(mrioc, "cannot allocate irq vectors, ret %d\n",
830afd3a579SSreekanth Reddy 			    retval);
831afd3a579SSreekanth Reddy 			goto out_failed;
832afd3a579SSreekanth Reddy 		}
833afd3a579SSreekanth Reddy 	} else {
834824a1566SKashyap Desai 		max_vectors =
835afd3a579SSreekanth Reddy 		    min_t(int, mrioc->cpu_count + 1 +
836afd3a579SSreekanth Reddy 			mrioc->requested_poll_qcount, mrioc->msix_count);
837afd3a579SSreekanth Reddy 
838afd3a579SSreekanth Reddy 		mpi3mr_calc_poll_queues(mrioc, max_vectors);
839824a1566SKashyap Desai 
840824a1566SKashyap Desai 		ioc_info(mrioc,
841824a1566SKashyap Desai 		    "MSI-X vectors supported: %d, no of cores: %d,",
842824a1566SKashyap Desai 		    mrioc->msix_count, mrioc->cpu_count);
843824a1566SKashyap Desai 		ioc_info(mrioc,
844afd3a579SSreekanth Reddy 		    "MSI-x vectors requested: %d poll_queues %d\n",
845afd3a579SSreekanth Reddy 		    max_vectors, mrioc->requested_poll_qcount);
846824a1566SKashyap Desai 
847afd3a579SSreekanth Reddy 		desc.post_vectors = mrioc->requested_poll_qcount;
848afd3a579SSreekanth Reddy 		min_vec = desc.pre_vectors + desc.post_vectors;
849824a1566SKashyap Desai 		irq_flags |= PCI_IRQ_AFFINITY | PCI_IRQ_ALL_TYPES;
850824a1566SKashyap Desai 
8512938beddSDan Carpenter 		retval = pci_alloc_irq_vectors_affinity(mrioc->pdev,
852afd3a579SSreekanth Reddy 			min_vec, max_vectors, irq_flags, &desc);
853afd3a579SSreekanth Reddy 
8542938beddSDan Carpenter 		if (retval < 0) {
855afd3a579SSreekanth Reddy 			ioc_err(mrioc, "cannot allocate irq vectors, ret %d\n",
856afd3a579SSreekanth Reddy 			    retval);
857824a1566SKashyap Desai 			goto out_failed;
858824a1566SKashyap Desai 		}
859afd3a579SSreekanth Reddy 
860afd3a579SSreekanth Reddy 
861c9566231SKashyap Desai 		/*
862c9566231SKashyap Desai 		 * If only one MSI-x is allocated, then MSI-x 0 will be shared
863c9566231SKashyap Desai 		 * between Admin queue and operational queue
864c9566231SKashyap Desai 		 */
865afd3a579SSreekanth Reddy 		if (retval == min_vec)
866c9566231SKashyap Desai 			mrioc->op_reply_q_offset = 0;
867afd3a579SSreekanth Reddy 		else if (retval != (max_vectors)) {
868afd3a579SSreekanth Reddy 			ioc_info(mrioc,
869afd3a579SSreekanth Reddy 			    "allocated vectors (%d) are less than configured (%d)\n",
870afd3a579SSreekanth Reddy 			    retval, max_vectors);
871afd3a579SSreekanth Reddy 		}
872824a1566SKashyap Desai 
8732938beddSDan Carpenter 		max_vectors = retval;
874afd3a579SSreekanth Reddy 		mrioc->op_reply_q_offset = (max_vectors > 1) ? 1 : 0;
875afd3a579SSreekanth Reddy 
876afd3a579SSreekanth Reddy 		mpi3mr_calc_poll_queues(mrioc, max_vectors);
877afd3a579SSreekanth Reddy 
878824a1566SKashyap Desai 	}
879afd3a579SSreekanth Reddy 
880824a1566SKashyap Desai 	mrioc->intr_info = kzalloc(sizeof(struct mpi3mr_intr_info) * max_vectors,
881824a1566SKashyap Desai 	    GFP_KERNEL);
882824a1566SKashyap Desai 	if (!mrioc->intr_info) {
8832938beddSDan Carpenter 		retval = -ENOMEM;
884824a1566SKashyap Desai 		pci_free_irq_vectors(mrioc->pdev);
885824a1566SKashyap Desai 		goto out_failed;
886824a1566SKashyap Desai 	}
887824a1566SKashyap Desai 	for (i = 0; i < max_vectors; i++) {
888824a1566SKashyap Desai 		retval = mpi3mr_request_irq(mrioc, i);
889824a1566SKashyap Desai 		if (retval) {
890824a1566SKashyap Desai 			mrioc->intr_info_count = i;
891824a1566SKashyap Desai 			goto out_failed;
892824a1566SKashyap Desai 		}
893824a1566SKashyap Desai 	}
894fe6db615SSreekanth Reddy 	if (reset_devices || !setup_one)
895fe6db615SSreekanth Reddy 		mrioc->is_intr_info_set = true;
896824a1566SKashyap Desai 	mrioc->intr_info_count = max_vectors;
897824a1566SKashyap Desai 	mpi3mr_ioc_enable_intr(mrioc);
8982938beddSDan Carpenter 	return 0;
8992938beddSDan Carpenter 
900824a1566SKashyap Desai out_failed:
901824a1566SKashyap Desai 	mpi3mr_cleanup_isr(mrioc);
902824a1566SKashyap Desai 
903824a1566SKashyap Desai 	return retval;
904824a1566SKashyap Desai }
905824a1566SKashyap Desai 
906824a1566SKashyap Desai static const struct {
907824a1566SKashyap Desai 	enum mpi3mr_iocstate value;
908824a1566SKashyap Desai 	char *name;
909824a1566SKashyap Desai } mrioc_states[] = {
910824a1566SKashyap Desai 	{ MRIOC_STATE_READY, "ready" },
911824a1566SKashyap Desai 	{ MRIOC_STATE_FAULT, "fault" },
912824a1566SKashyap Desai 	{ MRIOC_STATE_RESET, "reset" },
913824a1566SKashyap Desai 	{ MRIOC_STATE_BECOMING_READY, "becoming ready" },
914824a1566SKashyap Desai 	{ MRIOC_STATE_RESET_REQUESTED, "reset requested" },
915824a1566SKashyap Desai 	{ MRIOC_STATE_UNRECOVERABLE, "unrecoverable error" },
916824a1566SKashyap Desai };
917824a1566SKashyap Desai 
mpi3mr_iocstate_name(enum mpi3mr_iocstate mrioc_state)918824a1566SKashyap Desai static const char *mpi3mr_iocstate_name(enum mpi3mr_iocstate mrioc_state)
919824a1566SKashyap Desai {
920824a1566SKashyap Desai 	int i;
921824a1566SKashyap Desai 	char *name = NULL;
922824a1566SKashyap Desai 
923824a1566SKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mrioc_states); i++) {
924824a1566SKashyap Desai 		if (mrioc_states[i].value == mrioc_state) {
925824a1566SKashyap Desai 			name = mrioc_states[i].name;
926824a1566SKashyap Desai 			break;
927824a1566SKashyap Desai 		}
928824a1566SKashyap Desai 	}
929824a1566SKashyap Desai 	return name;
930824a1566SKashyap Desai }
931824a1566SKashyap Desai 
932f061178eSKashyap Desai /* Reset reason to name mapper structure*/
933f061178eSKashyap Desai static const struct {
934f061178eSKashyap Desai 	enum mpi3mr_reset_reason value;
935f061178eSKashyap Desai 	char *name;
936f061178eSKashyap Desai } mpi3mr_reset_reason_codes[] = {
937f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_BRINGUP, "timeout in bringup" },
938f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_FAULT_WATCH, "fault" },
939f5e6d5a3SSumit Saxena 	{ MPI3MR_RESET_FROM_APP, "application invocation" },
940f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_EH_HOS, "error handling" },
941f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_TM_TIMEOUT, "TM timeout" },
942f5e6d5a3SSumit Saxena 	{ MPI3MR_RESET_FROM_APP_TIMEOUT, "application command timeout" },
943f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_MUR_FAILURE, "MUR failure" },
944f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_CTLR_CLEANUP, "timeout in controller cleanup" },
945f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_CIACTIV_FAULT, "component image activation fault" },
946f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_PE_TIMEOUT, "port enable timeout" },
947f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_TSU_TIMEOUT, "time stamp update timeout" },
948f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_DELREQQ_TIMEOUT, "delete request queue timeout" },
949f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_DELREPQ_TIMEOUT, "delete reply queue timeout" },
950f061178eSKashyap Desai 	{
951f061178eSKashyap Desai 		MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT,
952f061178eSKashyap Desai 		"create request queue timeout"
953f061178eSKashyap Desai 	},
954f061178eSKashyap Desai 	{
955f061178eSKashyap Desai 		MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT,
956f061178eSKashyap Desai 		"create reply queue timeout"
957f061178eSKashyap Desai 	},
958f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT, "IOC facts timeout" },
959f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_IOCINIT_TIMEOUT, "IOC init timeout" },
960f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT, "event notify timeout" },
961f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_EVTACK_TIMEOUT, "event acknowledgment timeout" },
962f061178eSKashyap Desai 	{
963f061178eSKashyap Desai 		MPI3MR_RESET_FROM_CIACTVRST_TIMER,
964f061178eSKashyap Desai 		"component image activation timeout"
965f061178eSKashyap Desai 	},
966f061178eSKashyap Desai 	{
967f061178eSKashyap Desai 		MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT,
968f061178eSKashyap Desai 		"get package version timeout"
969f061178eSKashyap Desai 	},
970f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_SYSFS, "sysfs invocation" },
971f061178eSKashyap Desai 	{ MPI3MR_RESET_FROM_SYSFS_TIMEOUT, "sysfs TM timeout" },
972d8d08d16SRanjan Kumar 	{
973d8d08d16SRanjan Kumar 		MPI3MR_RESET_FROM_DIAG_BUFFER_POST_TIMEOUT,
974d8d08d16SRanjan Kumar 		"diagnostic buffer post timeout"
975d8d08d16SRanjan Kumar 	},
976d8d08d16SRanjan Kumar 	{
977d8d08d16SRanjan Kumar 		MPI3MR_RESET_FROM_DIAG_BUFFER_RELEASE_TIMEOUT,
978d8d08d16SRanjan Kumar 		"diagnostic buffer release timeout"
979d8d08d16SRanjan Kumar 	},
9805867b856SColin Ian King 	{ MPI3MR_RESET_FROM_FIRMWARE, "firmware asynchronous reset" },
98132d457d5SSreekanth Reddy 	{ MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT, "configuration request timeout"},
9822bd37e28SSreekanth Reddy 	{ MPI3MR_RESET_FROM_SAS_TRANSPORT_TIMEOUT, "timeout of a SAS transport layer request" },
983f061178eSKashyap Desai };
984f061178eSKashyap Desai 
985f061178eSKashyap Desai /**
986f061178eSKashyap Desai  * mpi3mr_reset_rc_name - get reset reason code name
987f061178eSKashyap Desai  * @reason_code: reset reason code value
988f061178eSKashyap Desai  *
989f061178eSKashyap Desai  * Map reset reason to an NULL terminated ASCII string
990f061178eSKashyap Desai  *
991f061178eSKashyap Desai  * Return: name corresponding to reset reason value or NULL.
992f061178eSKashyap Desai  */
mpi3mr_reset_rc_name(enum mpi3mr_reset_reason reason_code)993f061178eSKashyap Desai static const char *mpi3mr_reset_rc_name(enum mpi3mr_reset_reason reason_code)
994f061178eSKashyap Desai {
995f061178eSKashyap Desai 	int i;
996f061178eSKashyap Desai 	char *name = NULL;
997f061178eSKashyap Desai 
998f061178eSKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mpi3mr_reset_reason_codes); i++) {
999f061178eSKashyap Desai 		if (mpi3mr_reset_reason_codes[i].value == reason_code) {
1000f061178eSKashyap Desai 			name = mpi3mr_reset_reason_codes[i].name;
1001f061178eSKashyap Desai 			break;
1002f061178eSKashyap Desai 		}
1003f061178eSKashyap Desai 	}
1004f061178eSKashyap Desai 	return name;
1005f061178eSKashyap Desai }
1006f061178eSKashyap Desai 
1007f061178eSKashyap Desai /* Reset type to name mapper structure*/
1008f061178eSKashyap Desai static const struct {
1009f061178eSKashyap Desai 	u16 reset_type;
1010f061178eSKashyap Desai 	char *name;
1011f061178eSKashyap Desai } mpi3mr_reset_types[] = {
1012f061178eSKashyap Desai 	{ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, "soft" },
1013f061178eSKashyap Desai 	{ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, "diag fault" },
1014f061178eSKashyap Desai };
1015f061178eSKashyap Desai 
1016f061178eSKashyap Desai /**
1017f061178eSKashyap Desai  * mpi3mr_reset_type_name - get reset type name
1018f061178eSKashyap Desai  * @reset_type: reset type value
1019f061178eSKashyap Desai  *
1020f061178eSKashyap Desai  * Map reset type to an NULL terminated ASCII string
1021f061178eSKashyap Desai  *
1022f061178eSKashyap Desai  * Return: name corresponding to reset type value or NULL.
1023f061178eSKashyap Desai  */
mpi3mr_reset_type_name(u16 reset_type)1024f061178eSKashyap Desai static const char *mpi3mr_reset_type_name(u16 reset_type)
1025f061178eSKashyap Desai {
1026f061178eSKashyap Desai 	int i;
1027f061178eSKashyap Desai 	char *name = NULL;
1028f061178eSKashyap Desai 
1029f061178eSKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mpi3mr_reset_types); i++) {
1030f061178eSKashyap Desai 		if (mpi3mr_reset_types[i].reset_type == reset_type) {
1031f061178eSKashyap Desai 			name = mpi3mr_reset_types[i].name;
1032f061178eSKashyap Desai 			break;
1033f061178eSKashyap Desai 		}
1034f061178eSKashyap Desai 	}
1035f061178eSKashyap Desai 	return name;
1036f061178eSKashyap Desai }
1037f061178eSKashyap Desai 
1038824a1566SKashyap Desai /**
1039824a1566SKashyap Desai  * mpi3mr_print_fault_info - Display fault information
1040824a1566SKashyap Desai  * @mrioc: Adapter instance reference
1041824a1566SKashyap Desai  *
1042824a1566SKashyap Desai  * Display the controller fault information if there is a
1043824a1566SKashyap Desai  * controller fault.
1044824a1566SKashyap Desai  *
1045824a1566SKashyap Desai  * Return: Nothing.
1046824a1566SKashyap Desai  */
mpi3mr_print_fault_info(struct mpi3mr_ioc * mrioc)1047b64845a7SSreekanth Reddy void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc)
1048824a1566SKashyap Desai {
1049824a1566SKashyap Desai 	u32 ioc_status, code, code1, code2, code3;
1050824a1566SKashyap Desai 
1051824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
1052824a1566SKashyap Desai 
1053824a1566SKashyap Desai 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) {
1054824a1566SKashyap Desai 		code = readl(&mrioc->sysif_regs->fault);
1055824a1566SKashyap Desai 		code1 = readl(&mrioc->sysif_regs->fault_info[0]);
1056824a1566SKashyap Desai 		code2 = readl(&mrioc->sysif_regs->fault_info[1]);
1057824a1566SKashyap Desai 		code3 = readl(&mrioc->sysif_regs->fault_info[2]);
1058824a1566SKashyap Desai 
1059824a1566SKashyap Desai 		ioc_info(mrioc,
1060824a1566SKashyap Desai 		    "fault code(0x%08X): Additional code: (0x%08X:0x%08X:0x%08X)\n",
1061824a1566SKashyap Desai 		    code, code1, code2, code3);
1062824a1566SKashyap Desai 	}
1063824a1566SKashyap Desai }
1064824a1566SKashyap Desai 
1065824a1566SKashyap Desai /**
1066824a1566SKashyap Desai  * mpi3mr_get_iocstate - Get IOC State
1067824a1566SKashyap Desai  * @mrioc: Adapter instance reference
1068824a1566SKashyap Desai  *
1069824a1566SKashyap Desai  * Return a proper IOC state enum based on the IOC status and
1070824a1566SKashyap Desai  * IOC configuration and unrcoverable state of the controller.
1071824a1566SKashyap Desai  *
1072824a1566SKashyap Desai  * Return: Current IOC state.
1073824a1566SKashyap Desai  */
mpi3mr_get_iocstate(struct mpi3mr_ioc * mrioc)1074824a1566SKashyap Desai enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc)
1075824a1566SKashyap Desai {
1076824a1566SKashyap Desai 	u32 ioc_status, ioc_config;
1077824a1566SKashyap Desai 	u8 ready, enabled;
1078824a1566SKashyap Desai 
1079824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
1080824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
1081824a1566SKashyap Desai 
1082824a1566SKashyap Desai 	if (mrioc->unrecoverable)
1083824a1566SKashyap Desai 		return MRIOC_STATE_UNRECOVERABLE;
1084824a1566SKashyap Desai 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)
1085824a1566SKashyap Desai 		return MRIOC_STATE_FAULT;
1086824a1566SKashyap Desai 
1087824a1566SKashyap Desai 	ready = (ioc_status & MPI3_SYSIF_IOC_STATUS_READY);
1088824a1566SKashyap Desai 	enabled = (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC);
1089824a1566SKashyap Desai 
1090824a1566SKashyap Desai 	if (ready && enabled)
1091824a1566SKashyap Desai 		return MRIOC_STATE_READY;
1092824a1566SKashyap Desai 	if ((!ready) && (!enabled))
1093824a1566SKashyap Desai 		return MRIOC_STATE_RESET;
1094824a1566SKashyap Desai 	if ((!ready) && (enabled))
1095824a1566SKashyap Desai 		return MRIOC_STATE_BECOMING_READY;
1096824a1566SKashyap Desai 
1097824a1566SKashyap Desai 	return MRIOC_STATE_RESET_REQUESTED;
1098824a1566SKashyap Desai }
1099824a1566SKashyap Desai 
1100824a1566SKashyap Desai /**
1101c432e167SChandrakanth patil  * mpi3mr_free_ioctl_dma_memory - free memory for ioctl dma
1102c432e167SChandrakanth patil  * @mrioc: Adapter instance reference
1103c432e167SChandrakanth patil  *
1104c432e167SChandrakanth patil  * Free the DMA memory allocated for IOCTL handling purpose.
1105c432e167SChandrakanth patil  *
1106c432e167SChandrakanth patil  * Return: None
1107c432e167SChandrakanth patil  */
mpi3mr_free_ioctl_dma_memory(struct mpi3mr_ioc * mrioc)1108c432e167SChandrakanth patil static void mpi3mr_free_ioctl_dma_memory(struct mpi3mr_ioc *mrioc)
1109c432e167SChandrakanth patil {
1110c432e167SChandrakanth patil 	struct dma_memory_desc *mem_desc;
1111c432e167SChandrakanth patil 	u16 i;
1112c432e167SChandrakanth patil 
1113c432e167SChandrakanth patil 	if (!mrioc->ioctl_dma_pool)
1114c432e167SChandrakanth patil 		return;
1115c432e167SChandrakanth patil 
1116c432e167SChandrakanth patil 	for (i = 0; i < MPI3MR_NUM_IOCTL_SGE; i++) {
1117c432e167SChandrakanth patil 		mem_desc = &mrioc->ioctl_sge[i];
1118c432e167SChandrakanth patil 		if (mem_desc->addr) {
1119c432e167SChandrakanth patil 			dma_pool_free(mrioc->ioctl_dma_pool,
1120c432e167SChandrakanth patil 				      mem_desc->addr,
1121c432e167SChandrakanth patil 				      mem_desc->dma_addr);
1122c432e167SChandrakanth patil 			mem_desc->addr = NULL;
1123c432e167SChandrakanth patil 		}
1124c432e167SChandrakanth patil 	}
1125c432e167SChandrakanth patil 	dma_pool_destroy(mrioc->ioctl_dma_pool);
1126c432e167SChandrakanth patil 	mrioc->ioctl_dma_pool = NULL;
1127c432e167SChandrakanth patil 	mem_desc = &mrioc->ioctl_chain_sge;
1128c432e167SChandrakanth patil 
1129c432e167SChandrakanth patil 	if (mem_desc->addr) {
1130c432e167SChandrakanth patil 		dma_free_coherent(&mrioc->pdev->dev, mem_desc->size,
1131c432e167SChandrakanth patil 				  mem_desc->addr, mem_desc->dma_addr);
1132c432e167SChandrakanth patil 		mem_desc->addr = NULL;
1133c432e167SChandrakanth patil 	}
1134c432e167SChandrakanth patil 	mem_desc = &mrioc->ioctl_resp_sge;
1135c432e167SChandrakanth patil 	if (mem_desc->addr) {
1136c432e167SChandrakanth patil 		dma_free_coherent(&mrioc->pdev->dev, mem_desc->size,
1137c432e167SChandrakanth patil 				  mem_desc->addr, mem_desc->dma_addr);
1138c432e167SChandrakanth patil 		mem_desc->addr = NULL;
1139c432e167SChandrakanth patil 	}
1140c432e167SChandrakanth patil 
1141c432e167SChandrakanth patil 	mrioc->ioctl_sges_allocated = false;
1142c432e167SChandrakanth patil }
1143c432e167SChandrakanth patil 
1144c432e167SChandrakanth patil /**
1145c432e167SChandrakanth patil  * mpi3mr_alloc_ioctl_dma_memory - Alloc memory for ioctl dma
1146c432e167SChandrakanth patil  * @mrioc: Adapter instance reference
1147c432e167SChandrakanth patil  *
1148c432e167SChandrakanth patil  * This function allocates dmaable memory required to handle the
1149c432e167SChandrakanth patil  * application issued MPI3 IOCTL requests.
1150c432e167SChandrakanth patil  *
1151c432e167SChandrakanth patil  * Return: None
1152c432e167SChandrakanth patil  */
mpi3mr_alloc_ioctl_dma_memory(struct mpi3mr_ioc * mrioc)1153c432e167SChandrakanth patil static void mpi3mr_alloc_ioctl_dma_memory(struct mpi3mr_ioc *mrioc)
1154c432e167SChandrakanth patil 
1155c432e167SChandrakanth patil {
1156c432e167SChandrakanth patil 	struct dma_memory_desc *mem_desc;
1157c432e167SChandrakanth patil 	u16 i;
1158c432e167SChandrakanth patil 
1159c432e167SChandrakanth patil 	mrioc->ioctl_dma_pool = dma_pool_create("ioctl dma pool",
1160c432e167SChandrakanth patil 						&mrioc->pdev->dev,
1161c432e167SChandrakanth patil 						MPI3MR_IOCTL_SGE_SIZE,
1162c432e167SChandrakanth patil 						MPI3MR_PAGE_SIZE_4K, 0);
1163c432e167SChandrakanth patil 
1164c432e167SChandrakanth patil 	if (!mrioc->ioctl_dma_pool) {
1165c432e167SChandrakanth patil 		ioc_err(mrioc, "ioctl_dma_pool: dma_pool_create failed\n");
1166c432e167SChandrakanth patil 		goto out_failed;
1167c432e167SChandrakanth patil 	}
1168c432e167SChandrakanth patil 
1169c432e167SChandrakanth patil 	for (i = 0; i < MPI3MR_NUM_IOCTL_SGE; i++) {
1170c432e167SChandrakanth patil 		mem_desc = &mrioc->ioctl_sge[i];
1171c432e167SChandrakanth patil 		mem_desc->size = MPI3MR_IOCTL_SGE_SIZE;
1172c432e167SChandrakanth patil 		mem_desc->addr = dma_pool_zalloc(mrioc->ioctl_dma_pool,
1173c432e167SChandrakanth patil 						 GFP_KERNEL,
1174c432e167SChandrakanth patil 						 &mem_desc->dma_addr);
1175c432e167SChandrakanth patil 		if (!mem_desc->addr)
1176c432e167SChandrakanth patil 			goto out_failed;
1177c432e167SChandrakanth patil 	}
1178c432e167SChandrakanth patil 
1179c432e167SChandrakanth patil 	mem_desc = &mrioc->ioctl_chain_sge;
1180c432e167SChandrakanth patil 	mem_desc->size = MPI3MR_PAGE_SIZE_4K;
1181c432e167SChandrakanth patil 	mem_desc->addr = dma_alloc_coherent(&mrioc->pdev->dev,
1182c432e167SChandrakanth patil 					    mem_desc->size,
1183c432e167SChandrakanth patil 					    &mem_desc->dma_addr,
1184c432e167SChandrakanth patil 					    GFP_KERNEL);
1185c432e167SChandrakanth patil 	if (!mem_desc->addr)
1186c432e167SChandrakanth patil 		goto out_failed;
1187c432e167SChandrakanth patil 
1188c432e167SChandrakanth patil 	mem_desc = &mrioc->ioctl_resp_sge;
1189c432e167SChandrakanth patil 	mem_desc->size = MPI3MR_PAGE_SIZE_4K;
1190c432e167SChandrakanth patil 	mem_desc->addr = dma_alloc_coherent(&mrioc->pdev->dev,
1191c432e167SChandrakanth patil 					    mem_desc->size,
1192c432e167SChandrakanth patil 					    &mem_desc->dma_addr,
1193c432e167SChandrakanth patil 					    GFP_KERNEL);
1194c432e167SChandrakanth patil 	if (!mem_desc->addr)
1195c432e167SChandrakanth patil 		goto out_failed;
1196c432e167SChandrakanth patil 
1197c432e167SChandrakanth patil 	mrioc->ioctl_sges_allocated = true;
1198c432e167SChandrakanth patil 
1199c432e167SChandrakanth patil 	return;
1200c432e167SChandrakanth patil out_failed:
1201c432e167SChandrakanth patil 	ioc_warn(mrioc, "cannot allocate DMA memory for the mpt commands\n"
1202c432e167SChandrakanth patil 		 "from the applications, application interface for MPT command is disabled\n");
1203c432e167SChandrakanth patil 	mpi3mr_free_ioctl_dma_memory(mrioc);
1204c432e167SChandrakanth patil }
1205c432e167SChandrakanth patil 
1206c432e167SChandrakanth patil /**
1207824a1566SKashyap Desai  * mpi3mr_clear_reset_history - clear reset history
1208824a1566SKashyap Desai  * @mrioc: Adapter instance reference
1209824a1566SKashyap Desai  *
1210824a1566SKashyap Desai  * Write the reset history bit in IOC status to clear the bit,
1211824a1566SKashyap Desai  * if it is already set.
1212824a1566SKashyap Desai  *
1213824a1566SKashyap Desai  * Return: Nothing.
1214824a1566SKashyap Desai  */
mpi3mr_clear_reset_history(struct mpi3mr_ioc * mrioc)1215824a1566SKashyap Desai static inline void mpi3mr_clear_reset_history(struct mpi3mr_ioc *mrioc)
1216824a1566SKashyap Desai {
1217824a1566SKashyap Desai 	u32 ioc_status;
1218824a1566SKashyap Desai 
1219824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
1220824a1566SKashyap Desai 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)
1221824a1566SKashyap Desai 		writel(ioc_status, &mrioc->sysif_regs->ioc_status);
1222824a1566SKashyap Desai }
1223824a1566SKashyap Desai 
1224824a1566SKashyap Desai /**
1225824a1566SKashyap Desai  * mpi3mr_issue_and_process_mur - Message unit Reset handler
1226824a1566SKashyap Desai  * @mrioc: Adapter instance reference
1227824a1566SKashyap Desai  * @reset_reason: Reset reason code
1228824a1566SKashyap Desai  *
1229824a1566SKashyap Desai  * Issue Message unit Reset to the controller and wait for it to
1230824a1566SKashyap Desai  * be complete.
1231824a1566SKashyap Desai  *
1232824a1566SKashyap Desai  * Return: 0 on success, -1 on failure.
1233824a1566SKashyap Desai  */
mpi3mr_issue_and_process_mur(struct mpi3mr_ioc * mrioc,u32 reset_reason)1234824a1566SKashyap Desai static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc,
1235824a1566SKashyap Desai 	u32 reset_reason)
1236824a1566SKashyap Desai {
12370a2714b7SRanjan Kumar 	u32 ioc_config, timeout, ioc_status, scratch_pad0;
1238824a1566SKashyap Desai 	int retval = -1;
1239824a1566SKashyap Desai 
1240824a1566SKashyap Desai 	ioc_info(mrioc, "Issuing Message unit Reset(MUR)\n");
1241824a1566SKashyap Desai 	if (mrioc->unrecoverable) {
1242824a1566SKashyap Desai 		ioc_info(mrioc, "IOC is unrecoverable MUR not issued\n");
1243824a1566SKashyap Desai 		return retval;
1244824a1566SKashyap Desai 	}
1245824a1566SKashyap Desai 	mpi3mr_clear_reset_history(mrioc);
12460a2714b7SRanjan Kumar 	scratch_pad0 = ((MPI3MR_RESET_REASON_OSTYPE_LINUX <<
12470a2714b7SRanjan Kumar 			 MPI3MR_RESET_REASON_OSTYPE_SHIFT) |
12480a2714b7SRanjan Kumar 			(mrioc->facts.ioc_num <<
12490a2714b7SRanjan Kumar 			 MPI3MR_RESET_REASON_IOCNUM_SHIFT) | reset_reason);
12500a2714b7SRanjan Kumar 	writel(scratch_pad0, &mrioc->sysif_regs->scratchpad[0]);
1251824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
1252824a1566SKashyap Desai 	ioc_config &= ~MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
1253824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
1254824a1566SKashyap Desai 
125522beef38SRanjan Kumar 	timeout = MPI3MR_MUR_TIMEOUT * 10;
1256824a1566SKashyap Desai 	do {
1257824a1566SKashyap Desai 		ioc_status = readl(&mrioc->sysif_regs->ioc_status);
1258824a1566SKashyap Desai 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)) {
1259824a1566SKashyap Desai 			mpi3mr_clear_reset_history(mrioc);
1260824a1566SKashyap Desai 			break;
1261824a1566SKashyap Desai 		}
1262b64845a7SSreekanth Reddy 		if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) {
1263b64845a7SSreekanth Reddy 			mpi3mr_print_fault_info(mrioc);
1264b64845a7SSreekanth Reddy 			break;
1265824a1566SKashyap Desai 		}
1266824a1566SKashyap Desai 		msleep(100);
1267824a1566SKashyap Desai 	} while (--timeout);
1268824a1566SKashyap Desai 
1269824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
1270b64845a7SSreekanth Reddy 	if (timeout && !((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) ||
1271b64845a7SSreekanth Reddy 	      (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) ||
1272b64845a7SSreekanth Reddy 	      (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC)))
1273b64845a7SSreekanth Reddy 		retval = 0;
1274824a1566SKashyap Desai 
1275824a1566SKashyap Desai 	ioc_info(mrioc, "Base IOC Sts/Config after %s MUR is (0x%x)/(0x%x)\n",
1276824a1566SKashyap Desai 	    (!retval) ? "successful" : "failed", ioc_status, ioc_config);
1277824a1566SKashyap Desai 	return retval;
1278824a1566SKashyap Desai }
1279824a1566SKashyap Desai 
1280824a1566SKashyap Desai /**
1281c5758fc7SSreekanth Reddy  * mpi3mr_revalidate_factsdata - validate IOCFacts parameters
1282c5758fc7SSreekanth Reddy  * during reset/resume
1283c5758fc7SSreekanth Reddy  * @mrioc: Adapter instance reference
1284c5758fc7SSreekanth Reddy  *
1285904fdd20SRandy Dunlap  * Return: zero if the new IOCFacts parameters value is compatible with
1286c5758fc7SSreekanth Reddy  * older values else return -EPERM
1287c5758fc7SSreekanth Reddy  */
1288c5758fc7SSreekanth Reddy static int
mpi3mr_revalidate_factsdata(struct mpi3mr_ioc * mrioc)1289c5758fc7SSreekanth Reddy mpi3mr_revalidate_factsdata(struct mpi3mr_ioc *mrioc)
1290c5758fc7SSreekanth Reddy {
1291144679dfSChristophe JAILLET 	unsigned long *removepend_bitmap;
1292c5758fc7SSreekanth Reddy 
1293c5758fc7SSreekanth Reddy 	if (mrioc->facts.reply_sz > mrioc->reply_sz) {
1294c5758fc7SSreekanth Reddy 		ioc_err(mrioc,
1295c5758fc7SSreekanth Reddy 		    "cannot increase reply size from %d to %d\n",
1296c5758fc7SSreekanth Reddy 		    mrioc->reply_sz, mrioc->facts.reply_sz);
1297c5758fc7SSreekanth Reddy 		return -EPERM;
1298c5758fc7SSreekanth Reddy 	}
1299c5758fc7SSreekanth Reddy 
1300c5758fc7SSreekanth Reddy 	if (mrioc->facts.max_op_reply_q < mrioc->num_op_reply_q) {
1301c5758fc7SSreekanth Reddy 		ioc_err(mrioc,
1302c5758fc7SSreekanth Reddy 		    "cannot reduce number of operational reply queues from %d to %d\n",
1303c5758fc7SSreekanth Reddy 		    mrioc->num_op_reply_q,
1304c5758fc7SSreekanth Reddy 		    mrioc->facts.max_op_reply_q);
1305c5758fc7SSreekanth Reddy 		return -EPERM;
1306c5758fc7SSreekanth Reddy 	}
1307c5758fc7SSreekanth Reddy 
1308c5758fc7SSreekanth Reddy 	if (mrioc->facts.max_op_req_q < mrioc->num_op_req_q) {
1309c5758fc7SSreekanth Reddy 		ioc_err(mrioc,
1310c5758fc7SSreekanth Reddy 		    "cannot reduce number of operational request queues from %d to %d\n",
1311c5758fc7SSreekanth Reddy 		    mrioc->num_op_req_q, mrioc->facts.max_op_req_q);
1312c5758fc7SSreekanth Reddy 		return -EPERM;
1313c5758fc7SSreekanth Reddy 	}
1314c5758fc7SSreekanth Reddy 
1315d9adb81eSRanjan Kumar 	if (mrioc->shost->max_sectors != (mrioc->facts.max_data_length / 512))
1316d9adb81eSRanjan Kumar 		ioc_err(mrioc, "Warning: The maximum data transfer length\n"
1317d9adb81eSRanjan Kumar 			    "\tchanged after reset: previous(%d), new(%d),\n"
1318d9adb81eSRanjan Kumar 			    "the driver cannot change this at run time\n",
1319d9adb81eSRanjan Kumar 			    mrioc->shost->max_sectors * 512, mrioc->facts.max_data_length);
1320d9adb81eSRanjan Kumar 
1321c4723e68SSreekanth Reddy 	if ((mrioc->sas_transport_enabled) && (mrioc->facts.ioc_capabilities &
132257a80be5SRanjan Kumar 	    MPI3_IOCFACTS_CAPABILITY_MULTIPATH_SUPPORTED))
1323c4723e68SSreekanth Reddy 		ioc_err(mrioc,
1324c4723e68SSreekanth Reddy 		    "critical error: multipath capability is enabled at the\n"
1325c4723e68SSreekanth Reddy 		    "\tcontroller while sas transport support is enabled at the\n"
1326c4723e68SSreekanth Reddy 		    "\tdriver, please reboot the system or reload the driver\n");
1327c4723e68SSreekanth Reddy 
1328339e6156SShin'ichiro Kawasaki 	if (mrioc->facts.max_devhandle > mrioc->dev_handle_bitmap_bits) {
1329339e6156SShin'ichiro Kawasaki 		removepend_bitmap = bitmap_zalloc(mrioc->facts.max_devhandle,
1330339e6156SShin'ichiro Kawasaki 						  GFP_KERNEL);
1331c5758fc7SSreekanth Reddy 		if (!removepend_bitmap) {
1332c5758fc7SSreekanth Reddy 			ioc_err(mrioc,
1333339e6156SShin'ichiro Kawasaki 				"failed to increase removepend_bitmap bits from %d to %d\n",
1334339e6156SShin'ichiro Kawasaki 				mrioc->dev_handle_bitmap_bits,
1335339e6156SShin'ichiro Kawasaki 				mrioc->facts.max_devhandle);
1336c5758fc7SSreekanth Reddy 			return -EPERM;
1337c5758fc7SSreekanth Reddy 		}
1338339e6156SShin'ichiro Kawasaki 		bitmap_free(mrioc->removepend_bitmap);
1339c5758fc7SSreekanth Reddy 		mrioc->removepend_bitmap = removepend_bitmap;
1340c5758fc7SSreekanth Reddy 		ioc_info(mrioc,
1341339e6156SShin'ichiro Kawasaki 			 "increased bits of dev_handle_bitmap from %d to %d\n",
1342339e6156SShin'ichiro Kawasaki 			 mrioc->dev_handle_bitmap_bits,
1343339e6156SShin'ichiro Kawasaki 			 mrioc->facts.max_devhandle);
1344339e6156SShin'ichiro Kawasaki 		mrioc->dev_handle_bitmap_bits = mrioc->facts.max_devhandle;
1345c5758fc7SSreekanth Reddy 	}
1346c5758fc7SSreekanth Reddy 
1347c5758fc7SSreekanth Reddy 	return 0;
1348c5758fc7SSreekanth Reddy }
1349c5758fc7SSreekanth Reddy 
1350c5758fc7SSreekanth Reddy /**
1351824a1566SKashyap Desai  * mpi3mr_bring_ioc_ready - Bring controller to ready state
1352824a1566SKashyap Desai  * @mrioc: Adapter instance reference
1353824a1566SKashyap Desai  *
1354824a1566SKashyap Desai  * Set Enable IOC bit in IOC configuration register and wait for
1355824a1566SKashyap Desai  * the controller to become ready.
1356824a1566SKashyap Desai  *
135759bd9cfeSSreekanth Reddy  * Return: 0 on success, appropriate error on failure.
1358824a1566SKashyap Desai  */
mpi3mr_bring_ioc_ready(struct mpi3mr_ioc * mrioc)1359824a1566SKashyap Desai static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc)
1360824a1566SKashyap Desai {
13610a319f16SRanjan Kumar 	u32 ioc_config, ioc_status, timeout, host_diagnostic;
136259bd9cfeSSreekanth Reddy 	int retval = 0;
136359bd9cfeSSreekanth Reddy 	enum mpi3mr_iocstate ioc_state;
136459bd9cfeSSreekanth Reddy 	u64 base_info;
13659634bb07SRanjan Kumar 	u8 retry = 0;
13669634bb07SRanjan Kumar 	u64 start_time, elapsed_time_sec;
13679634bb07SRanjan Kumar 
13689634bb07SRanjan Kumar retry_bring_ioc_ready:
1369824a1566SKashyap Desai 
137059bd9cfeSSreekanth Reddy 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
137159bd9cfeSSreekanth Reddy 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
137259bd9cfeSSreekanth Reddy 	base_info = lo_hi_readq(&mrioc->sysif_regs->ioc_information);
137359bd9cfeSSreekanth Reddy 	ioc_info(mrioc, "ioc_status(0x%08x), ioc_config(0x%08x), ioc_info(0x%016llx) at the bringup\n",
137459bd9cfeSSreekanth Reddy 	    ioc_status, ioc_config, base_info);
137559bd9cfeSSreekanth Reddy 
137659bd9cfeSSreekanth Reddy 	/*The timeout value is in 2sec unit, changing it to seconds*/
137759bd9cfeSSreekanth Reddy 	mrioc->ready_timeout =
137859bd9cfeSSreekanth Reddy 	    ((base_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >>
137959bd9cfeSSreekanth Reddy 	    MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT) * 2;
138059bd9cfeSSreekanth Reddy 
138159bd9cfeSSreekanth Reddy 	ioc_info(mrioc, "ready timeout: %d seconds\n", mrioc->ready_timeout);
138259bd9cfeSSreekanth Reddy 
138359bd9cfeSSreekanth Reddy 	ioc_state = mpi3mr_get_iocstate(mrioc);
138459bd9cfeSSreekanth Reddy 	ioc_info(mrioc, "controller is in %s state during detection\n",
138559bd9cfeSSreekanth Reddy 	    mpi3mr_iocstate_name(ioc_state));
138659bd9cfeSSreekanth Reddy 
138759bd9cfeSSreekanth Reddy 	timeout = mrioc->ready_timeout * 10;
1388*4616a4b3SRanjan Kumar 
138959bd9cfeSSreekanth Reddy 	do {
1390*4616a4b3SRanjan Kumar 		ioc_state = mpi3mr_get_iocstate(mrioc);
1391*4616a4b3SRanjan Kumar 
1392*4616a4b3SRanjan Kumar 		if (ioc_state != MRIOC_STATE_BECOMING_READY &&
1393*4616a4b3SRanjan Kumar 		    ioc_state != MRIOC_STATE_RESET_REQUESTED)
1394*4616a4b3SRanjan Kumar 			break;
139559bd9cfeSSreekanth Reddy 
1396f2a79d20SSreekanth Reddy 		if (!pci_device_is_present(mrioc->pdev)) {
1397f2a79d20SSreekanth Reddy 			mrioc->unrecoverable = 1;
1398*4616a4b3SRanjan Kumar 			ioc_err(mrioc, "controller is not present while waiting to reset\n");
1399f2a79d20SSreekanth Reddy 			goto out_device_not_present;
1400f2a79d20SSreekanth Reddy 		}
1401f2a79d20SSreekanth Reddy 
1402*4616a4b3SRanjan Kumar 		msleep(100);
1403*4616a4b3SRanjan Kumar 	} while (--timeout);
140459bd9cfeSSreekanth Reddy 
140559bd9cfeSSreekanth Reddy 	if (ioc_state == MRIOC_STATE_READY) {
140659bd9cfeSSreekanth Reddy 		ioc_info(mrioc, "issuing message unit reset (MUR) to bring to reset state\n");
140759bd9cfeSSreekanth Reddy 		retval = mpi3mr_issue_and_process_mur(mrioc,
140859bd9cfeSSreekanth Reddy 		    MPI3MR_RESET_FROM_BRINGUP);
140959bd9cfeSSreekanth Reddy 		ioc_state = mpi3mr_get_iocstate(mrioc);
141059bd9cfeSSreekanth Reddy 		if (retval)
141159bd9cfeSSreekanth Reddy 			ioc_err(mrioc,
141259bd9cfeSSreekanth Reddy 			    "message unit reset failed with error %d current state %s\n",
141359bd9cfeSSreekanth Reddy 			    retval, mpi3mr_iocstate_name(ioc_state));
141459bd9cfeSSreekanth Reddy 	}
141559bd9cfeSSreekanth Reddy 	if (ioc_state != MRIOC_STATE_RESET) {
14160a319f16SRanjan Kumar 		if (ioc_state == MRIOC_STATE_FAULT) {
14170a319f16SRanjan Kumar 			timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10;
14180a319f16SRanjan Kumar 			mpi3mr_print_fault_info(mrioc);
14190a319f16SRanjan Kumar 			do {
14200a319f16SRanjan Kumar 				host_diagnostic =
14210a319f16SRanjan Kumar 					readl(&mrioc->sysif_regs->host_diagnostic);
14220a319f16SRanjan Kumar 				if (!(host_diagnostic &
14230a319f16SRanjan Kumar 				      MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS))
14240a319f16SRanjan Kumar 					break;
14250a319f16SRanjan Kumar 				if (!pci_device_is_present(mrioc->pdev)) {
14260a319f16SRanjan Kumar 					mrioc->unrecoverable = 1;
14270a319f16SRanjan Kumar 					ioc_err(mrioc, "controller is not present at the bringup\n");
14280a319f16SRanjan Kumar 					goto out_device_not_present;
14290a319f16SRanjan Kumar 				}
14300a319f16SRanjan Kumar 				msleep(100);
14310a319f16SRanjan Kumar 			} while (--timeout);
14320a319f16SRanjan Kumar 		}
143359bd9cfeSSreekanth Reddy 		mpi3mr_print_fault_info(mrioc);
143459bd9cfeSSreekanth Reddy 		ioc_info(mrioc, "issuing soft reset to bring to reset state\n");
143559bd9cfeSSreekanth Reddy 		retval = mpi3mr_issue_reset(mrioc,
143659bd9cfeSSreekanth Reddy 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
143759bd9cfeSSreekanth Reddy 		    MPI3MR_RESET_FROM_BRINGUP);
143859bd9cfeSSreekanth Reddy 		if (retval) {
143959bd9cfeSSreekanth Reddy 			ioc_err(mrioc,
144059bd9cfeSSreekanth Reddy 			    "soft reset failed with error %d\n", retval);
144159bd9cfeSSreekanth Reddy 			goto out_failed;
144259bd9cfeSSreekanth Reddy 		}
144359bd9cfeSSreekanth Reddy 	}
144459bd9cfeSSreekanth Reddy 	ioc_state = mpi3mr_get_iocstate(mrioc);
144559bd9cfeSSreekanth Reddy 	if (ioc_state != MRIOC_STATE_RESET) {
144659bd9cfeSSreekanth Reddy 		ioc_err(mrioc,
144759bd9cfeSSreekanth Reddy 		    "cannot bring controller to reset state, current state: %s\n",
144859bd9cfeSSreekanth Reddy 		    mpi3mr_iocstate_name(ioc_state));
144959bd9cfeSSreekanth Reddy 		goto out_failed;
145059bd9cfeSSreekanth Reddy 	}
145159bd9cfeSSreekanth Reddy 	mpi3mr_clear_reset_history(mrioc);
145259bd9cfeSSreekanth Reddy 	retval = mpi3mr_setup_admin_qpair(mrioc);
145359bd9cfeSSreekanth Reddy 	if (retval) {
145459bd9cfeSSreekanth Reddy 		ioc_err(mrioc, "failed to setup admin queues: error %d\n",
145559bd9cfeSSreekanth Reddy 		    retval);
145659bd9cfeSSreekanth Reddy 		goto out_failed;
145759bd9cfeSSreekanth Reddy 	}
145859bd9cfeSSreekanth Reddy 
145959bd9cfeSSreekanth Reddy 	ioc_info(mrioc, "bringing controller to ready state\n");
1460824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
1461824a1566SKashyap Desai 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
1462824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
1463824a1566SKashyap Desai 
14649634bb07SRanjan Kumar 	if (retry == 0)
14659634bb07SRanjan Kumar 		start_time = jiffies;
14669634bb07SRanjan Kumar 
1467824a1566SKashyap Desai 	timeout = mrioc->ready_timeout * 10;
1468824a1566SKashyap Desai 	do {
146959bd9cfeSSreekanth Reddy 		ioc_state = mpi3mr_get_iocstate(mrioc);
147059bd9cfeSSreekanth Reddy 		if (ioc_state == MRIOC_STATE_READY) {
147159bd9cfeSSreekanth Reddy 			ioc_info(mrioc,
14725867b856SColin Ian King 			    "successfully transitioned to %s state\n",
147359bd9cfeSSreekanth Reddy 			    mpi3mr_iocstate_name(ioc_state));
1474824a1566SKashyap Desai 			return 0;
147559bd9cfeSSreekanth Reddy 		}
14769634bb07SRanjan Kumar 		ioc_status = readl(&mrioc->sysif_regs->ioc_status);
14779634bb07SRanjan Kumar 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) ||
14789634bb07SRanjan Kumar 		    (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) {
14799634bb07SRanjan Kumar 			mpi3mr_print_fault_info(mrioc);
14809634bb07SRanjan Kumar 			goto out_failed;
14819634bb07SRanjan Kumar 		}
1482f2a79d20SSreekanth Reddy 		if (!pci_device_is_present(mrioc->pdev)) {
1483f2a79d20SSreekanth Reddy 			mrioc->unrecoverable = 1;
1484f2a79d20SSreekanth Reddy 			ioc_err(mrioc,
1485f2a79d20SSreekanth Reddy 			    "controller is not present at the bringup\n");
1486f2a79d20SSreekanth Reddy 			retval = -1;
1487f2a79d20SSreekanth Reddy 			goto out_device_not_present;
1488f2a79d20SSreekanth Reddy 		}
1489824a1566SKashyap Desai 		msleep(100);
14909634bb07SRanjan Kumar 		elapsed_time_sec = jiffies_to_msecs(jiffies - start_time)/1000;
14919634bb07SRanjan Kumar 	} while (elapsed_time_sec < mrioc->ready_timeout);
1492824a1566SKashyap Desai 
149359bd9cfeSSreekanth Reddy out_failed:
14949634bb07SRanjan Kumar 	elapsed_time_sec = jiffies_to_msecs(jiffies - start_time)/1000;
14959634bb07SRanjan Kumar 	if ((retry < 2) && (elapsed_time_sec < (mrioc->ready_timeout - 60))) {
14969634bb07SRanjan Kumar 		retry++;
14979634bb07SRanjan Kumar 
14989634bb07SRanjan Kumar 		ioc_warn(mrioc, "retrying to bring IOC ready, retry_count:%d\n"
14999634bb07SRanjan Kumar 				" elapsed time =%llu\n", retry, elapsed_time_sec);
15009634bb07SRanjan Kumar 
15019634bb07SRanjan Kumar 		goto retry_bring_ioc_ready;
15029634bb07SRanjan Kumar 	}
150359bd9cfeSSreekanth Reddy 	ioc_state = mpi3mr_get_iocstate(mrioc);
150459bd9cfeSSreekanth Reddy 	ioc_err(mrioc,
150559bd9cfeSSreekanth Reddy 	    "failed to bring to ready state,  current state: %s\n",
150659bd9cfeSSreekanth Reddy 	    mpi3mr_iocstate_name(ioc_state));
1507f2a79d20SSreekanth Reddy out_device_not_present:
150859bd9cfeSSreekanth Reddy 	return retval;
1509824a1566SKashyap Desai }
1510824a1566SKashyap Desai 
1511824a1566SKashyap Desai /**
1512f061178eSKashyap Desai  * mpi3mr_soft_reset_success - Check softreset is success or not
1513f061178eSKashyap Desai  * @ioc_status: IOC status register value
1514f061178eSKashyap Desai  * @ioc_config: IOC config register value
1515f061178eSKashyap Desai  *
1516f061178eSKashyap Desai  * Check whether the soft reset is successful or not based on
1517f061178eSKashyap Desai  * IOC status and IOC config register values.
1518f061178eSKashyap Desai  *
1519f061178eSKashyap Desai  * Return: True when the soft reset is success, false otherwise.
1520f061178eSKashyap Desai  */
1521f061178eSKashyap Desai static inline bool
mpi3mr_soft_reset_success(u32 ioc_status,u32 ioc_config)1522f061178eSKashyap Desai mpi3mr_soft_reset_success(u32 ioc_status, u32 ioc_config)
1523f061178eSKashyap Desai {
1524f061178eSKashyap Desai 	if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) ||
1525f061178eSKashyap Desai 	    (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC)))
1526f061178eSKashyap Desai 		return true;
1527f061178eSKashyap Desai 	return false;
1528f061178eSKashyap Desai }
1529f061178eSKashyap Desai 
1530f061178eSKashyap Desai /**
1531f061178eSKashyap Desai  * mpi3mr_diagfault_success - Check diag fault is success or not
1532f061178eSKashyap Desai  * @mrioc: Adapter reference
1533f061178eSKashyap Desai  * @ioc_status: IOC status register value
1534f061178eSKashyap Desai  *
1535f061178eSKashyap Desai  * Check whether the controller hit diag reset fault code.
1536f061178eSKashyap Desai  *
1537f061178eSKashyap Desai  * Return: True when there is diag fault, false otherwise.
1538f061178eSKashyap Desai  */
mpi3mr_diagfault_success(struct mpi3mr_ioc * mrioc,u32 ioc_status)1539f061178eSKashyap Desai static inline bool mpi3mr_diagfault_success(struct mpi3mr_ioc *mrioc,
1540f061178eSKashyap Desai 	u32 ioc_status)
1541f061178eSKashyap Desai {
1542f061178eSKashyap Desai 	u32 fault;
1543f061178eSKashyap Desai 
1544f061178eSKashyap Desai 	if (!(ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT))
1545f061178eSKashyap Desai 		return false;
1546f061178eSKashyap Desai 	fault = readl(&mrioc->sysif_regs->fault) & MPI3_SYSIF_FAULT_CODE_MASK;
1547b64845a7SSreekanth Reddy 	if (fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET) {
1548b64845a7SSreekanth Reddy 		mpi3mr_print_fault_info(mrioc);
1549f061178eSKashyap Desai 		return true;
1550b64845a7SSreekanth Reddy 	}
1551f061178eSKashyap Desai 	return false;
1552f061178eSKashyap Desai }
1553f061178eSKashyap Desai 
1554f061178eSKashyap Desai /**
1555824a1566SKashyap Desai  * mpi3mr_set_diagsave - Set diag save bit for snapdump
1556824a1566SKashyap Desai  * @mrioc: Adapter reference
1557824a1566SKashyap Desai  *
1558824a1566SKashyap Desai  * Set diag save bit in IOC configuration register to enable
1559824a1566SKashyap Desai  * snapdump.
1560824a1566SKashyap Desai  *
1561824a1566SKashyap Desai  * Return: Nothing.
1562824a1566SKashyap Desai  */
mpi3mr_set_diagsave(struct mpi3mr_ioc * mrioc)1563824a1566SKashyap Desai static inline void mpi3mr_set_diagsave(struct mpi3mr_ioc *mrioc)
1564824a1566SKashyap Desai {
1565824a1566SKashyap Desai 	u32 ioc_config;
1566824a1566SKashyap Desai 
1567824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
1568824a1566SKashyap Desai 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_DIAG_SAVE;
1569824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
1570824a1566SKashyap Desai }
1571824a1566SKashyap Desai 
1572824a1566SKashyap Desai /**
1573824a1566SKashyap Desai  * mpi3mr_issue_reset - Issue reset to the controller
1574824a1566SKashyap Desai  * @mrioc: Adapter reference
1575824a1566SKashyap Desai  * @reset_type: Reset type
1576824a1566SKashyap Desai  * @reset_reason: Reset reason code
1577824a1566SKashyap Desai  *
1578f061178eSKashyap Desai  * Unlock the host diagnostic registers and write the specific
1579f061178eSKashyap Desai  * reset type to that, wait for reset acknowledgment from the
1580f061178eSKashyap Desai  * controller, if the reset is not successful retry for the
1581f061178eSKashyap Desai  * predefined number of times.
1582824a1566SKashyap Desai  *
1583824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
1584824a1566SKashyap Desai  */
mpi3mr_issue_reset(struct mpi3mr_ioc * mrioc,u16 reset_type,u16 reset_reason)1585824a1566SKashyap Desai static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type,
15860a2714b7SRanjan Kumar 	u16 reset_reason)
1587824a1566SKashyap Desai {
1588f061178eSKashyap Desai 	int retval = -1;
1589b64845a7SSreekanth Reddy 	u8 unlock_retry_count = 0;
15900a2714b7SRanjan Kumar 	u32 host_diagnostic, ioc_status, ioc_config, scratch_pad0;
1591b64845a7SSreekanth Reddy 	u32 timeout = MPI3MR_RESET_ACK_TIMEOUT * 10;
1592f061178eSKashyap Desai 
1593f061178eSKashyap Desai 	if ((reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET) &&
1594f061178eSKashyap Desai 	    (reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT))
1595b64845a7SSreekanth Reddy 		return retval;
1596f061178eSKashyap Desai 	if (mrioc->unrecoverable)
1597b64845a7SSreekanth Reddy 		return retval;
1598b64845a7SSreekanth Reddy 	if (reset_reason == MPI3MR_RESET_FROM_FIRMWARE) {
1599b64845a7SSreekanth Reddy 		retval = 0;
1600b64845a7SSreekanth Reddy 		return retval;
1601b64845a7SSreekanth Reddy 	}
1602b64845a7SSreekanth Reddy 
1603b64845a7SSreekanth Reddy 	ioc_info(mrioc, "%s reset due to %s(0x%x)\n",
1604b64845a7SSreekanth Reddy 	    mpi3mr_reset_type_name(reset_type),
1605b64845a7SSreekanth Reddy 	    mpi3mr_reset_rc_name(reset_reason), reset_reason);
1606b64845a7SSreekanth Reddy 
1607f061178eSKashyap Desai 	mpi3mr_clear_reset_history(mrioc);
1608f061178eSKashyap Desai 	do {
1609f061178eSKashyap Desai 		ioc_info(mrioc,
1610f061178eSKashyap Desai 		    "Write magic sequence to unlock host diag register (retry=%d)\n",
1611f061178eSKashyap Desai 		    ++unlock_retry_count);
1612f061178eSKashyap Desai 		if (unlock_retry_count >= MPI3MR_HOSTDIAG_UNLOCK_RETRY_COUNT) {
1613b64845a7SSreekanth Reddy 			ioc_err(mrioc,
1614b64845a7SSreekanth Reddy 			    "%s reset failed due to unlock failure, host_diagnostic(0x%08x)\n",
1615b64845a7SSreekanth Reddy 			    mpi3mr_reset_type_name(reset_type),
1616b64845a7SSreekanth Reddy 			    host_diagnostic);
1617f061178eSKashyap Desai 			mrioc->unrecoverable = 1;
1618b64845a7SSreekanth Reddy 			return retval;
1619f061178eSKashyap Desai 		}
1620f061178eSKashyap Desai 
1621f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_FLUSH,
1622f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1623f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_1ST,
1624f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1625f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND,
1626f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1627f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_3RD,
1628f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1629f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_4TH,
1630f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1631f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_5TH,
1632f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1633f061178eSKashyap Desai 		writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_6TH,
1634f061178eSKashyap Desai 		    &mrioc->sysif_regs->write_sequence);
1635f061178eSKashyap Desai 		usleep_range(1000, 1100);
1636f061178eSKashyap Desai 		host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic);
1637f061178eSKashyap Desai 		ioc_info(mrioc,
1638f061178eSKashyap Desai 		    "wrote magic sequence: retry_count(%d), host_diagnostic(0x%08x)\n",
1639f061178eSKashyap Desai 		    unlock_retry_count, host_diagnostic);
1640f061178eSKashyap Desai 	} while (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_DIAG_WRITE_ENABLE));
1641f061178eSKashyap Desai 
16420a2714b7SRanjan Kumar 	scratch_pad0 = ((MPI3MR_RESET_REASON_OSTYPE_LINUX <<
16430a2714b7SRanjan Kumar 	    MPI3MR_RESET_REASON_OSTYPE_SHIFT) | (mrioc->facts.ioc_num <<
16440a2714b7SRanjan Kumar 	    MPI3MR_RESET_REASON_IOCNUM_SHIFT) | reset_reason);
1645f061178eSKashyap Desai 	writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]);
1646f061178eSKashyap Desai 	writel(host_diagnostic | reset_type,
1647f061178eSKashyap Desai 	    &mrioc->sysif_regs->host_diagnostic);
1648b64845a7SSreekanth Reddy 	switch (reset_type) {
1649b64845a7SSreekanth Reddy 	case MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET:
1650f061178eSKashyap Desai 		do {
1651f061178eSKashyap Desai 			ioc_status = readl(&mrioc->sysif_regs->ioc_status);
1652f061178eSKashyap Desai 			ioc_config =
1653f061178eSKashyap Desai 			    readl(&mrioc->sysif_regs->ioc_configuration);
1654b64845a7SSreekanth Reddy 			if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)
1655b64845a7SSreekanth Reddy 			    && mpi3mr_soft_reset_success(ioc_status, ioc_config)
1656b64845a7SSreekanth Reddy 			    ) {
1657b64845a7SSreekanth Reddy 				mpi3mr_clear_reset_history(mrioc);
1658f061178eSKashyap Desai 				retval = 0;
1659f061178eSKashyap Desai 				break;
1660f061178eSKashyap Desai 			}
1661f061178eSKashyap Desai 			msleep(100);
1662f061178eSKashyap Desai 		} while (--timeout);
1663b64845a7SSreekanth Reddy 		mpi3mr_print_fault_info(mrioc);
1664b64845a7SSreekanth Reddy 		break;
1665b64845a7SSreekanth Reddy 	case MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT:
1666f061178eSKashyap Desai 		do {
1667f061178eSKashyap Desai 			ioc_status = readl(&mrioc->sysif_regs->ioc_status);
1668f061178eSKashyap Desai 			if (mpi3mr_diagfault_success(mrioc, ioc_status)) {
1669f061178eSKashyap Desai 				retval = 0;
1670f061178eSKashyap Desai 				break;
1671f061178eSKashyap Desai 			}
1672f061178eSKashyap Desai 			msleep(100);
1673f061178eSKashyap Desai 		} while (--timeout);
1674b64845a7SSreekanth Reddy 		break;
1675b64845a7SSreekanth Reddy 	default:
1676b64845a7SSreekanth Reddy 		break;
1677b64845a7SSreekanth Reddy 	}
1678b64845a7SSreekanth Reddy 
1679f061178eSKashyap Desai 	writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND,
1680f061178eSKashyap Desai 	    &mrioc->sysif_regs->write_sequence);
1681f061178eSKashyap Desai 
1682f061178eSKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
1683b64845a7SSreekanth Reddy 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
1684f061178eSKashyap Desai 	ioc_info(mrioc,
1685b64845a7SSreekanth Reddy 	    "ioc_status/ioc_onfig after %s reset is (0x%x)/(0x%x)\n",
1686f061178eSKashyap Desai 	    (!retval)?"successful":"failed", ioc_status,
1687f061178eSKashyap Desai 	    ioc_config);
1688b64845a7SSreekanth Reddy 	if (retval)
1689b64845a7SSreekanth Reddy 		mrioc->unrecoverable = 1;
1690f061178eSKashyap Desai 	return retval;
1691824a1566SKashyap Desai }
1692824a1566SKashyap Desai 
1693824a1566SKashyap Desai /**
1694824a1566SKashyap Desai  * mpi3mr_admin_request_post - Post request to admin queue
1695824a1566SKashyap Desai  * @mrioc: Adapter reference
1696824a1566SKashyap Desai  * @admin_req: MPI3 request
1697824a1566SKashyap Desai  * @admin_req_sz: Request size
1698824a1566SKashyap Desai  * @ignore_reset: Ignore reset in process
1699824a1566SKashyap Desai  *
1700824a1566SKashyap Desai  * Post the MPI3 request into admin request queue and
1701824a1566SKashyap Desai  * inform the controller, if the queue is full return
1702824a1566SKashyap Desai  * appropriate error.
1703824a1566SKashyap Desai  *
1704824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
1705824a1566SKashyap Desai  */
mpi3mr_admin_request_post(struct mpi3mr_ioc * mrioc,void * admin_req,u16 admin_req_sz,u8 ignore_reset)1706824a1566SKashyap Desai int mpi3mr_admin_request_post(struct mpi3mr_ioc *mrioc, void *admin_req,
1707824a1566SKashyap Desai 	u16 admin_req_sz, u8 ignore_reset)
1708824a1566SKashyap Desai {
1709824a1566SKashyap Desai 	u16 areq_pi = 0, areq_ci = 0, max_entries = 0;
1710824a1566SKashyap Desai 	int retval = 0;
1711824a1566SKashyap Desai 	unsigned long flags;
1712824a1566SKashyap Desai 	u8 *areq_entry;
1713824a1566SKashyap Desai 
1714824a1566SKashyap Desai 	if (mrioc->unrecoverable) {
1715824a1566SKashyap Desai 		ioc_err(mrioc, "%s : Unrecoverable controller\n", __func__);
1716824a1566SKashyap Desai 		return -EFAULT;
1717824a1566SKashyap Desai 	}
1718824a1566SKashyap Desai 
1719824a1566SKashyap Desai 	spin_lock_irqsave(&mrioc->admin_req_lock, flags);
1720824a1566SKashyap Desai 	areq_pi = mrioc->admin_req_pi;
1721824a1566SKashyap Desai 	areq_ci = mrioc->admin_req_ci;
1722824a1566SKashyap Desai 	max_entries = mrioc->num_admin_req;
1723824a1566SKashyap Desai 	if ((areq_ci == (areq_pi + 1)) || ((!areq_ci) &&
1724824a1566SKashyap Desai 	    (areq_pi == (max_entries - 1)))) {
1725824a1566SKashyap Desai 		ioc_err(mrioc, "AdminReqQ full condition detected\n");
1726824a1566SKashyap Desai 		retval = -EAGAIN;
1727824a1566SKashyap Desai 		goto out;
1728824a1566SKashyap Desai 	}
1729824a1566SKashyap Desai 	if (!ignore_reset && mrioc->reset_in_progress) {
1730824a1566SKashyap Desai 		ioc_err(mrioc, "AdminReqQ submit reset in progress\n");
1731824a1566SKashyap Desai 		retval = -EAGAIN;
1732824a1566SKashyap Desai 		goto out;
1733824a1566SKashyap Desai 	}
17341c342b05SSumit Saxena 	if (mrioc->pci_err_recovery) {
17351c342b05SSumit Saxena 		ioc_err(mrioc, "admin request queue submission failed due to pci error recovery in progress\n");
17361c342b05SSumit Saxena 		retval = -EAGAIN;
17371c342b05SSumit Saxena 		goto out;
17381c342b05SSumit Saxena 	}
17391c342b05SSumit Saxena 
1740824a1566SKashyap Desai 	areq_entry = (u8 *)mrioc->admin_req_base +
1741824a1566SKashyap Desai 	    (areq_pi * MPI3MR_ADMIN_REQ_FRAME_SZ);
1742824a1566SKashyap Desai 	memset(areq_entry, 0, MPI3MR_ADMIN_REQ_FRAME_SZ);
1743824a1566SKashyap Desai 	memcpy(areq_entry, (u8 *)admin_req, admin_req_sz);
1744824a1566SKashyap Desai 
1745824a1566SKashyap Desai 	if (++areq_pi == max_entries)
1746824a1566SKashyap Desai 		areq_pi = 0;
1747824a1566SKashyap Desai 	mrioc->admin_req_pi = areq_pi;
1748824a1566SKashyap Desai 
1749824a1566SKashyap Desai 	writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi);
1750824a1566SKashyap Desai 
1751824a1566SKashyap Desai out:
1752824a1566SKashyap Desai 	spin_unlock_irqrestore(&mrioc->admin_req_lock, flags);
1753824a1566SKashyap Desai 
1754824a1566SKashyap Desai 	return retval;
1755824a1566SKashyap Desai }
1756824a1566SKashyap Desai 
1757824a1566SKashyap Desai /**
1758c9566231SKashyap Desai  * mpi3mr_free_op_req_q_segments - free request memory segments
1759c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1760c9566231SKashyap Desai  * @q_idx: operational request queue index
1761c9566231SKashyap Desai  *
1762c9566231SKashyap Desai  * Free memory segments allocated for operational request queue
1763c9566231SKashyap Desai  *
1764c9566231SKashyap Desai  * Return: Nothing.
1765c9566231SKashyap Desai  */
mpi3mr_free_op_req_q_segments(struct mpi3mr_ioc * mrioc,u16 q_idx)1766c9566231SKashyap Desai static void mpi3mr_free_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx)
1767c9566231SKashyap Desai {
1768c9566231SKashyap Desai 	u16 j;
1769c9566231SKashyap Desai 	int size;
1770c9566231SKashyap Desai 	struct segments *segments;
1771c9566231SKashyap Desai 
1772c9566231SKashyap Desai 	segments = mrioc->req_qinfo[q_idx].q_segments;
1773c9566231SKashyap Desai 	if (!segments)
1774c9566231SKashyap Desai 		return;
1775c9566231SKashyap Desai 
1776c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1777c9566231SKashyap Desai 		size = MPI3MR_OP_REQ_Q_SEG_SIZE;
1778c9566231SKashyap Desai 		if (mrioc->req_qinfo[q_idx].q_segment_list) {
1779c9566231SKashyap Desai 			dma_free_coherent(&mrioc->pdev->dev,
1780c9566231SKashyap Desai 			    MPI3MR_MAX_SEG_LIST_SIZE,
1781c9566231SKashyap Desai 			    mrioc->req_qinfo[q_idx].q_segment_list,
1782c9566231SKashyap Desai 			    mrioc->req_qinfo[q_idx].q_segment_list_dma);
1783d44b5fefSSreekanth Reddy 			mrioc->req_qinfo[q_idx].q_segment_list = NULL;
1784c9566231SKashyap Desai 		}
1785c9566231SKashyap Desai 	} else
1786243bcc8eSSreekanth Reddy 		size = mrioc->req_qinfo[q_idx].segment_qd *
1787c9566231SKashyap Desai 		    mrioc->facts.op_req_sz;
1788c9566231SKashyap Desai 
1789c9566231SKashyap Desai 	for (j = 0; j < mrioc->req_qinfo[q_idx].num_segments; j++) {
1790c9566231SKashyap Desai 		if (!segments[j].segment)
1791c9566231SKashyap Desai 			continue;
1792c9566231SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev,
1793c9566231SKashyap Desai 		    size, segments[j].segment, segments[j].segment_dma);
1794c9566231SKashyap Desai 		segments[j].segment = NULL;
1795c9566231SKashyap Desai 	}
1796c9566231SKashyap Desai 	kfree(mrioc->req_qinfo[q_idx].q_segments);
1797c9566231SKashyap Desai 	mrioc->req_qinfo[q_idx].q_segments = NULL;
1798c9566231SKashyap Desai 	mrioc->req_qinfo[q_idx].qid = 0;
1799c9566231SKashyap Desai }
1800c9566231SKashyap Desai 
1801c9566231SKashyap Desai /**
1802c9566231SKashyap Desai  * mpi3mr_free_op_reply_q_segments - free reply memory segments
1803c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1804c9566231SKashyap Desai  * @q_idx: operational reply queue index
1805c9566231SKashyap Desai  *
1806c9566231SKashyap Desai  * Free memory segments allocated for operational reply queue
1807c9566231SKashyap Desai  *
1808c9566231SKashyap Desai  * Return: Nothing.
1809c9566231SKashyap Desai  */
mpi3mr_free_op_reply_q_segments(struct mpi3mr_ioc * mrioc,u16 q_idx)1810c9566231SKashyap Desai static void mpi3mr_free_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx)
1811c9566231SKashyap Desai {
1812c9566231SKashyap Desai 	u16 j;
1813c9566231SKashyap Desai 	int size;
1814c9566231SKashyap Desai 	struct segments *segments;
1815c9566231SKashyap Desai 
1816c9566231SKashyap Desai 	segments = mrioc->op_reply_qinfo[q_idx].q_segments;
1817c9566231SKashyap Desai 	if (!segments)
1818c9566231SKashyap Desai 		return;
1819c9566231SKashyap Desai 
1820c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1821c9566231SKashyap Desai 		size = MPI3MR_OP_REP_Q_SEG_SIZE;
1822c9566231SKashyap Desai 		if (mrioc->op_reply_qinfo[q_idx].q_segment_list) {
1823c9566231SKashyap Desai 			dma_free_coherent(&mrioc->pdev->dev,
1824c9566231SKashyap Desai 			    MPI3MR_MAX_SEG_LIST_SIZE,
1825c9566231SKashyap Desai 			    mrioc->op_reply_qinfo[q_idx].q_segment_list,
1826c9566231SKashyap Desai 			    mrioc->op_reply_qinfo[q_idx].q_segment_list_dma);
1827c9566231SKashyap Desai 			mrioc->op_reply_qinfo[q_idx].q_segment_list = NULL;
1828c9566231SKashyap Desai 		}
1829c9566231SKashyap Desai 	} else
1830c9566231SKashyap Desai 		size = mrioc->op_reply_qinfo[q_idx].segment_qd *
1831c9566231SKashyap Desai 		    mrioc->op_reply_desc_sz;
1832c9566231SKashyap Desai 
1833c9566231SKashyap Desai 	for (j = 0; j < mrioc->op_reply_qinfo[q_idx].num_segments; j++) {
1834c9566231SKashyap Desai 		if (!segments[j].segment)
1835c9566231SKashyap Desai 			continue;
1836c9566231SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev,
1837c9566231SKashyap Desai 		    size, segments[j].segment, segments[j].segment_dma);
1838c9566231SKashyap Desai 		segments[j].segment = NULL;
1839c9566231SKashyap Desai 	}
1840c9566231SKashyap Desai 
1841c9566231SKashyap Desai 	kfree(mrioc->op_reply_qinfo[q_idx].q_segments);
1842c9566231SKashyap Desai 	mrioc->op_reply_qinfo[q_idx].q_segments = NULL;
1843c9566231SKashyap Desai 	mrioc->op_reply_qinfo[q_idx].qid = 0;
1844c9566231SKashyap Desai }
1845c9566231SKashyap Desai 
1846c9566231SKashyap Desai /**
1847c9566231SKashyap Desai  * mpi3mr_delete_op_reply_q - delete operational reply queue
1848c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1849c9566231SKashyap Desai  * @qidx: operational reply queue index
1850c9566231SKashyap Desai  *
1851c9566231SKashyap Desai  * Delete operatinal reply queue by issuing MPI request
1852c9566231SKashyap Desai  * through admin queue.
1853c9566231SKashyap Desai  *
1854c9566231SKashyap Desai  * Return:  0 on success, non-zero on failure.
1855c9566231SKashyap Desai  */
mpi3mr_delete_op_reply_q(struct mpi3mr_ioc * mrioc,u16 qidx)1856c9566231SKashyap Desai static int mpi3mr_delete_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx)
1857c9566231SKashyap Desai {
1858c9566231SKashyap Desai 	struct mpi3_delete_reply_queue_request delq_req;
1859afd3a579SSreekanth Reddy 	struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
1860c9566231SKashyap Desai 	int retval = 0;
1861c9566231SKashyap Desai 	u16 reply_qid = 0, midx;
1862c9566231SKashyap Desai 
1863afd3a579SSreekanth Reddy 	reply_qid = op_reply_q->qid;
1864c9566231SKashyap Desai 
1865c9566231SKashyap Desai 	midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset);
1866c9566231SKashyap Desai 
1867c9566231SKashyap Desai 	if (!reply_qid)	{
1868c9566231SKashyap Desai 		retval = -1;
1869c9566231SKashyap Desai 		ioc_err(mrioc, "Issue DelRepQ: called with invalid ReqQID\n");
1870c9566231SKashyap Desai 		goto out;
1871c9566231SKashyap Desai 	}
1872c9566231SKashyap Desai 
1873afd3a579SSreekanth Reddy 	(op_reply_q->qtype == MPI3MR_DEFAULT_QUEUE) ? mrioc->default_qcount-- :
1874afd3a579SSreekanth Reddy 	    mrioc->active_poll_qcount--;
1875afd3a579SSreekanth Reddy 
1876c9566231SKashyap Desai 	memset(&delq_req, 0, sizeof(delq_req));
1877c9566231SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
1878c9566231SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
1879c9566231SKashyap Desai 		retval = -1;
1880c9566231SKashyap Desai 		ioc_err(mrioc, "Issue DelRepQ: Init command is in use\n");
1881c9566231SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
1882c9566231SKashyap Desai 		goto out;
1883c9566231SKashyap Desai 	}
1884c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
1885c9566231SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
1886c9566231SKashyap Desai 	mrioc->init_cmds.callback = NULL;
1887c9566231SKashyap Desai 	delq_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
1888c9566231SKashyap Desai 	delq_req.function = MPI3_FUNCTION_DELETE_REPLY_QUEUE;
1889c9566231SKashyap Desai 	delq_req.queue_id = cpu_to_le16(reply_qid);
1890c9566231SKashyap Desai 
1891c9566231SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
1892c9566231SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &delq_req, sizeof(delq_req),
1893c9566231SKashyap Desai 	    1);
1894c9566231SKashyap Desai 	if (retval) {
1895c9566231SKashyap Desai 		ioc_err(mrioc, "Issue DelRepQ: Admin Post failed\n");
1896c9566231SKashyap Desai 		goto out_unlock;
1897c9566231SKashyap Desai 	}
1898c9566231SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
1899c9566231SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
1900c9566231SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
1901a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "delete reply queue timed out\n");
1902a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
1903c9566231SKashyap Desai 		    MPI3MR_RESET_FROM_DELREPQ_TIMEOUT);
1904c9566231SKashyap Desai 		retval = -1;
1905c9566231SKashyap Desai 		goto out_unlock;
1906c9566231SKashyap Desai 	}
1907c9566231SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
1908c9566231SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
1909c9566231SKashyap Desai 		ioc_err(mrioc,
1910c9566231SKashyap Desai 		    "Issue DelRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
1911c9566231SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
1912c9566231SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
1913c9566231SKashyap Desai 		retval = -1;
1914c9566231SKashyap Desai 		goto out_unlock;
1915c9566231SKashyap Desai 	}
1916c9566231SKashyap Desai 	mrioc->intr_info[midx].op_reply_q = NULL;
1917c9566231SKashyap Desai 
1918c9566231SKashyap Desai 	mpi3mr_free_op_reply_q_segments(mrioc, qidx);
1919c9566231SKashyap Desai out_unlock:
1920c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
1921c9566231SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
1922c9566231SKashyap Desai out:
1923c9566231SKashyap Desai 
1924c9566231SKashyap Desai 	return retval;
1925c9566231SKashyap Desai }
1926c9566231SKashyap Desai 
1927c9566231SKashyap Desai /**
1928c9566231SKashyap Desai  * mpi3mr_alloc_op_reply_q_segments -Alloc segmented reply pool
1929c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1930c9566231SKashyap Desai  * @qidx: request queue index
1931c9566231SKashyap Desai  *
1932c9566231SKashyap Desai  * Allocate segmented memory pools for operational reply
1933c9566231SKashyap Desai  * queue.
1934c9566231SKashyap Desai  *
1935c9566231SKashyap Desai  * Return: 0 on success, non-zero on failure.
1936c9566231SKashyap Desai  */
mpi3mr_alloc_op_reply_q_segments(struct mpi3mr_ioc * mrioc,u16 qidx)1937c9566231SKashyap Desai static int mpi3mr_alloc_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx)
1938c9566231SKashyap Desai {
1939c9566231SKashyap Desai 	struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
1940c9566231SKashyap Desai 	int i, size;
1941c9566231SKashyap Desai 	u64 *q_segment_list_entry = NULL;
1942c9566231SKashyap Desai 	struct segments *segments;
1943c9566231SKashyap Desai 
1944c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1945c9566231SKashyap Desai 		op_reply_q->segment_qd =
1946c9566231SKashyap Desai 		    MPI3MR_OP_REP_Q_SEG_SIZE / mrioc->op_reply_desc_sz;
1947c9566231SKashyap Desai 
1948c9566231SKashyap Desai 		size = MPI3MR_OP_REP_Q_SEG_SIZE;
1949c9566231SKashyap Desai 
1950c9566231SKashyap Desai 		op_reply_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev,
1951c9566231SKashyap Desai 		    MPI3MR_MAX_SEG_LIST_SIZE, &op_reply_q->q_segment_list_dma,
1952c9566231SKashyap Desai 		    GFP_KERNEL);
1953c9566231SKashyap Desai 		if (!op_reply_q->q_segment_list)
1954c9566231SKashyap Desai 			return -ENOMEM;
1955c9566231SKashyap Desai 		q_segment_list_entry = (u64 *)op_reply_q->q_segment_list;
1956c9566231SKashyap Desai 	} else {
1957c9566231SKashyap Desai 		op_reply_q->segment_qd = op_reply_q->num_replies;
1958c9566231SKashyap Desai 		size = op_reply_q->num_replies * mrioc->op_reply_desc_sz;
1959c9566231SKashyap Desai 	}
1960c9566231SKashyap Desai 
1961c9566231SKashyap Desai 	op_reply_q->num_segments = DIV_ROUND_UP(op_reply_q->num_replies,
1962c9566231SKashyap Desai 	    op_reply_q->segment_qd);
1963c9566231SKashyap Desai 
1964c9566231SKashyap Desai 	op_reply_q->q_segments = kcalloc(op_reply_q->num_segments,
1965c9566231SKashyap Desai 	    sizeof(struct segments), GFP_KERNEL);
1966c9566231SKashyap Desai 	if (!op_reply_q->q_segments)
1967c9566231SKashyap Desai 		return -ENOMEM;
1968c9566231SKashyap Desai 
1969c9566231SKashyap Desai 	segments = op_reply_q->q_segments;
1970c9566231SKashyap Desai 	for (i = 0; i < op_reply_q->num_segments; i++) {
1971c9566231SKashyap Desai 		segments[i].segment =
1972c9566231SKashyap Desai 		    dma_alloc_coherent(&mrioc->pdev->dev,
1973c9566231SKashyap Desai 		    size, &segments[i].segment_dma, GFP_KERNEL);
1974c9566231SKashyap Desai 		if (!segments[i].segment)
1975c9566231SKashyap Desai 			return -ENOMEM;
1976c9566231SKashyap Desai 		if (mrioc->enable_segqueue)
1977c9566231SKashyap Desai 			q_segment_list_entry[i] =
1978c9566231SKashyap Desai 			    (unsigned long)segments[i].segment_dma;
1979c9566231SKashyap Desai 	}
1980c9566231SKashyap Desai 
1981c9566231SKashyap Desai 	return 0;
1982c9566231SKashyap Desai }
1983c9566231SKashyap Desai 
1984c9566231SKashyap Desai /**
1985c9566231SKashyap Desai  * mpi3mr_alloc_op_req_q_segments - Alloc segmented req pool.
1986c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1987c9566231SKashyap Desai  * @qidx: request queue index
1988c9566231SKashyap Desai  *
1989c9566231SKashyap Desai  * Allocate segmented memory pools for operational request
1990c9566231SKashyap Desai  * queue.
1991c9566231SKashyap Desai  *
1992c9566231SKashyap Desai  * Return: 0 on success, non-zero on failure.
1993c9566231SKashyap Desai  */
mpi3mr_alloc_op_req_q_segments(struct mpi3mr_ioc * mrioc,u16 qidx)1994c9566231SKashyap Desai static int mpi3mr_alloc_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx)
1995c9566231SKashyap Desai {
1996c9566231SKashyap Desai 	struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx;
1997c9566231SKashyap Desai 	int i, size;
1998c9566231SKashyap Desai 	u64 *q_segment_list_entry = NULL;
1999c9566231SKashyap Desai 	struct segments *segments;
2000c9566231SKashyap Desai 
2001c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
2002c9566231SKashyap Desai 		op_req_q->segment_qd =
2003c9566231SKashyap Desai 		    MPI3MR_OP_REQ_Q_SEG_SIZE / mrioc->facts.op_req_sz;
2004c9566231SKashyap Desai 
2005c9566231SKashyap Desai 		size = MPI3MR_OP_REQ_Q_SEG_SIZE;
2006c9566231SKashyap Desai 
2007c9566231SKashyap Desai 		op_req_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev,
2008c9566231SKashyap Desai 		    MPI3MR_MAX_SEG_LIST_SIZE, &op_req_q->q_segment_list_dma,
2009c9566231SKashyap Desai 		    GFP_KERNEL);
2010c9566231SKashyap Desai 		if (!op_req_q->q_segment_list)
2011c9566231SKashyap Desai 			return -ENOMEM;
2012c9566231SKashyap Desai 		q_segment_list_entry = (u64 *)op_req_q->q_segment_list;
2013c9566231SKashyap Desai 
2014c9566231SKashyap Desai 	} else {
2015c9566231SKashyap Desai 		op_req_q->segment_qd = op_req_q->num_requests;
2016c9566231SKashyap Desai 		size = op_req_q->num_requests * mrioc->facts.op_req_sz;
2017c9566231SKashyap Desai 	}
2018c9566231SKashyap Desai 
2019c9566231SKashyap Desai 	op_req_q->num_segments = DIV_ROUND_UP(op_req_q->num_requests,
2020c9566231SKashyap Desai 	    op_req_q->segment_qd);
2021c9566231SKashyap Desai 
2022c9566231SKashyap Desai 	op_req_q->q_segments = kcalloc(op_req_q->num_segments,
2023c9566231SKashyap Desai 	    sizeof(struct segments), GFP_KERNEL);
2024c9566231SKashyap Desai 	if (!op_req_q->q_segments)
2025c9566231SKashyap Desai 		return -ENOMEM;
2026c9566231SKashyap Desai 
2027c9566231SKashyap Desai 	segments = op_req_q->q_segments;
2028c9566231SKashyap Desai 	for (i = 0; i < op_req_q->num_segments; i++) {
2029c9566231SKashyap Desai 		segments[i].segment =
2030c9566231SKashyap Desai 		    dma_alloc_coherent(&mrioc->pdev->dev,
2031c9566231SKashyap Desai 		    size, &segments[i].segment_dma, GFP_KERNEL);
2032c9566231SKashyap Desai 		if (!segments[i].segment)
2033c9566231SKashyap Desai 			return -ENOMEM;
2034c9566231SKashyap Desai 		if (mrioc->enable_segqueue)
2035c9566231SKashyap Desai 			q_segment_list_entry[i] =
2036c9566231SKashyap Desai 			    (unsigned long)segments[i].segment_dma;
2037c9566231SKashyap Desai 	}
2038c9566231SKashyap Desai 
2039c9566231SKashyap Desai 	return 0;
2040c9566231SKashyap Desai }
2041c9566231SKashyap Desai 
2042c9566231SKashyap Desai /**
2043c9566231SKashyap Desai  * mpi3mr_create_op_reply_q - create operational reply queue
2044c9566231SKashyap Desai  * @mrioc: Adapter instance reference
2045c9566231SKashyap Desai  * @qidx: operational reply queue index
2046c9566231SKashyap Desai  *
2047c9566231SKashyap Desai  * Create operatinal reply queue by issuing MPI request
2048c9566231SKashyap Desai  * through admin queue.
2049c9566231SKashyap Desai  *
2050c9566231SKashyap Desai  * Return:  0 on success, non-zero on failure.
2051c9566231SKashyap Desai  */
mpi3mr_create_op_reply_q(struct mpi3mr_ioc * mrioc,u16 qidx)2052c9566231SKashyap Desai static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx)
2053c9566231SKashyap Desai {
2054c9566231SKashyap Desai 	struct mpi3_create_reply_queue_request create_req;
2055c9566231SKashyap Desai 	struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
2056c9566231SKashyap Desai 	int retval = 0;
2057c9566231SKashyap Desai 	u16 reply_qid = 0, midx;
2058c9566231SKashyap Desai 
2059c9566231SKashyap Desai 	reply_qid = op_reply_q->qid;
2060c9566231SKashyap Desai 
2061c9566231SKashyap Desai 	midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset);
2062c9566231SKashyap Desai 
2063c9566231SKashyap Desai 	if (reply_qid) {
2064c9566231SKashyap Desai 		retval = -1;
2065c9566231SKashyap Desai 		ioc_err(mrioc, "CreateRepQ: called for duplicate qid %d\n",
2066c9566231SKashyap Desai 		    reply_qid);
2067c9566231SKashyap Desai 
2068c9566231SKashyap Desai 		return retval;
2069c9566231SKashyap Desai 	}
2070c9566231SKashyap Desai 
2071c9566231SKashyap Desai 	reply_qid = qidx + 1;
2072c9566231SKashyap Desai 	op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD;
2073c9260ff2SSumit Saxena 	if ((mrioc->pdev->device == MPI3_MFGPAGE_DEVID_SAS4116) &&
2074c9260ff2SSumit Saxena 		!mrioc->pdev->revision)
2075243bcc8eSSreekanth Reddy 		op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD4K;
2076c9566231SKashyap Desai 	op_reply_q->ci = 0;
2077c9566231SKashyap Desai 	op_reply_q->ephase = 1;
2078463429f8SKashyap Desai 	atomic_set(&op_reply_q->pend_ios, 0);
2079463429f8SKashyap Desai 	atomic_set(&op_reply_q->in_use, 0);
2080463429f8SKashyap Desai 	op_reply_q->enable_irq_poll = false;
2081c9566231SKashyap Desai 
2082c9566231SKashyap Desai 	if (!op_reply_q->q_segments) {
2083c9566231SKashyap Desai 		retval = mpi3mr_alloc_op_reply_q_segments(mrioc, qidx);
2084c9566231SKashyap Desai 		if (retval) {
2085c9566231SKashyap Desai 			mpi3mr_free_op_reply_q_segments(mrioc, qidx);
2086c9566231SKashyap Desai 			goto out;
2087c9566231SKashyap Desai 		}
2088c9566231SKashyap Desai 	}
2089c9566231SKashyap Desai 
2090c9566231SKashyap Desai 	memset(&create_req, 0, sizeof(create_req));
2091c9566231SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
2092c9566231SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
2093c9566231SKashyap Desai 		retval = -1;
2094c9566231SKashyap Desai 		ioc_err(mrioc, "CreateRepQ: Init command is in use\n");
2095f9dc034dSYang Yingliang 		goto out_unlock;
2096c9566231SKashyap Desai 	}
2097c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
2098c9566231SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
2099c9566231SKashyap Desai 	mrioc->init_cmds.callback = NULL;
2100c9566231SKashyap Desai 	create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
2101c9566231SKashyap Desai 	create_req.function = MPI3_FUNCTION_CREATE_REPLY_QUEUE;
2102c9566231SKashyap Desai 	create_req.queue_id = cpu_to_le16(reply_qid);
2103afd3a579SSreekanth Reddy 
2104afd3a579SSreekanth Reddy 	if (midx < (mrioc->intr_info_count - mrioc->requested_poll_qcount))
2105afd3a579SSreekanth Reddy 		op_reply_q->qtype = MPI3MR_DEFAULT_QUEUE;
2106afd3a579SSreekanth Reddy 	else
2107afd3a579SSreekanth Reddy 		op_reply_q->qtype = MPI3MR_POLL_QUEUE;
2108afd3a579SSreekanth Reddy 
2109afd3a579SSreekanth Reddy 	if (op_reply_q->qtype == MPI3MR_DEFAULT_QUEUE) {
2110afd3a579SSreekanth Reddy 		create_req.flags =
2111afd3a579SSreekanth Reddy 			MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_ENABLE;
2112afd3a579SSreekanth Reddy 		create_req.msix_index =
2113afd3a579SSreekanth Reddy 			cpu_to_le16(mrioc->intr_info[midx].msix_index);
2114afd3a579SSreekanth Reddy 	} else {
2115afd3a579SSreekanth Reddy 		create_req.msix_index = cpu_to_le16(mrioc->intr_info_count - 1);
2116afd3a579SSreekanth Reddy 		ioc_info(mrioc, "create reply queue(polled): for qid(%d), midx(%d)\n",
2117afd3a579SSreekanth Reddy 			reply_qid, midx);
2118afd3a579SSreekanth Reddy 		if (!mrioc->active_poll_qcount)
2119afd3a579SSreekanth Reddy 			disable_irq_nosync(pci_irq_vector(mrioc->pdev,
2120afd3a579SSreekanth Reddy 			    mrioc->intr_info_count - 1));
2121afd3a579SSreekanth Reddy 	}
2122afd3a579SSreekanth Reddy 
2123c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
2124c9566231SKashyap Desai 		create_req.flags |=
2125c9566231SKashyap Desai 		    MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED;
2126c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
2127c9566231SKashyap Desai 		    op_reply_q->q_segment_list_dma);
2128c9566231SKashyap Desai 	} else
2129c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
2130c9566231SKashyap Desai 		    op_reply_q->q_segments[0].segment_dma);
2131c9566231SKashyap Desai 
2132c9566231SKashyap Desai 	create_req.size = cpu_to_le16(op_reply_q->num_replies);
2133c9566231SKashyap Desai 
2134c9566231SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
2135c9566231SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &create_req,
2136c9566231SKashyap Desai 	    sizeof(create_req), 1);
2137c9566231SKashyap Desai 	if (retval) {
2138c9566231SKashyap Desai 		ioc_err(mrioc, "CreateRepQ: Admin Post failed\n");
2139c9566231SKashyap Desai 		goto out_unlock;
2140c9566231SKashyap Desai 	}
2141c9566231SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
2142c9566231SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
2143c9566231SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
2144a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "create reply queue timed out\n");
2145a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
2146c9566231SKashyap Desai 		    MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT);
2147c9566231SKashyap Desai 		retval = -1;
2148c9566231SKashyap Desai 		goto out_unlock;
2149c9566231SKashyap Desai 	}
2150c9566231SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
2151c9566231SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
2152c9566231SKashyap Desai 		ioc_err(mrioc,
2153c9566231SKashyap Desai 		    "CreateRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
2154c9566231SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
2155c9566231SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
2156c9566231SKashyap Desai 		retval = -1;
2157c9566231SKashyap Desai 		goto out_unlock;
2158c9566231SKashyap Desai 	}
2159c9566231SKashyap Desai 	op_reply_q->qid = reply_qid;
2160fe6db615SSreekanth Reddy 	if (midx < mrioc->intr_info_count)
2161c9566231SKashyap Desai 		mrioc->intr_info[midx].op_reply_q = op_reply_q;
2162c9566231SKashyap Desai 
2163afd3a579SSreekanth Reddy 	(op_reply_q->qtype == MPI3MR_DEFAULT_QUEUE) ? mrioc->default_qcount++ :
2164afd3a579SSreekanth Reddy 	    mrioc->active_poll_qcount++;
2165afd3a579SSreekanth Reddy 
2166c9566231SKashyap Desai out_unlock:
2167c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
2168c9566231SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
2169c9566231SKashyap Desai out:
2170c9566231SKashyap Desai 
2171c9566231SKashyap Desai 	return retval;
2172c9566231SKashyap Desai }
2173c9566231SKashyap Desai 
2174c9566231SKashyap Desai /**
2175c9566231SKashyap Desai  * mpi3mr_create_op_req_q - create operational request queue
2176c9566231SKashyap Desai  * @mrioc: Adapter instance reference
2177c9566231SKashyap Desai  * @idx: operational request queue index
2178c9566231SKashyap Desai  * @reply_qid: Reply queue ID
2179c9566231SKashyap Desai  *
2180c9566231SKashyap Desai  * Create operatinal request queue by issuing MPI request
2181c9566231SKashyap Desai  * through admin queue.
2182c9566231SKashyap Desai  *
2183c9566231SKashyap Desai  * Return:  0 on success, non-zero on failure.
2184c9566231SKashyap Desai  */
mpi3mr_create_op_req_q(struct mpi3mr_ioc * mrioc,u16 idx,u16 reply_qid)2185c9566231SKashyap Desai static int mpi3mr_create_op_req_q(struct mpi3mr_ioc *mrioc, u16 idx,
2186c9566231SKashyap Desai 	u16 reply_qid)
2187c9566231SKashyap Desai {
2188c9566231SKashyap Desai 	struct mpi3_create_request_queue_request create_req;
2189c9566231SKashyap Desai 	struct op_req_qinfo *op_req_q = mrioc->req_qinfo + idx;
2190c9566231SKashyap Desai 	int retval = 0;
2191c9566231SKashyap Desai 	u16 req_qid = 0;
2192c9566231SKashyap Desai 
2193c9566231SKashyap Desai 	req_qid = op_req_q->qid;
2194c9566231SKashyap Desai 
2195c9566231SKashyap Desai 	if (req_qid) {
2196c9566231SKashyap Desai 		retval = -1;
2197c9566231SKashyap Desai 		ioc_err(mrioc, "CreateReqQ: called for duplicate qid %d\n",
2198c9566231SKashyap Desai 		    req_qid);
2199c9566231SKashyap Desai 
2200c9566231SKashyap Desai 		return retval;
2201c9566231SKashyap Desai 	}
2202c9566231SKashyap Desai 	req_qid = idx + 1;
2203c9566231SKashyap Desai 
2204c9566231SKashyap Desai 	op_req_q->num_requests = MPI3MR_OP_REQ_Q_QD;
2205c9566231SKashyap Desai 	op_req_q->ci = 0;
2206c9566231SKashyap Desai 	op_req_q->pi = 0;
2207c9566231SKashyap Desai 	op_req_q->reply_qid = reply_qid;
2208c9566231SKashyap Desai 	spin_lock_init(&op_req_q->q_lock);
2209c9566231SKashyap Desai 
2210c9566231SKashyap Desai 	if (!op_req_q->q_segments) {
2211c9566231SKashyap Desai 		retval = mpi3mr_alloc_op_req_q_segments(mrioc, idx);
2212c9566231SKashyap Desai 		if (retval) {
2213c9566231SKashyap Desai 			mpi3mr_free_op_req_q_segments(mrioc, idx);
2214c9566231SKashyap Desai 			goto out;
2215c9566231SKashyap Desai 		}
2216c9566231SKashyap Desai 	}
2217c9566231SKashyap Desai 
2218c9566231SKashyap Desai 	memset(&create_req, 0, sizeof(create_req));
2219c9566231SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
2220c9566231SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
2221c9566231SKashyap Desai 		retval = -1;
2222c9566231SKashyap Desai 		ioc_err(mrioc, "CreateReqQ: Init command is in use\n");
2223f9dc034dSYang Yingliang 		goto out_unlock;
2224c9566231SKashyap Desai 	}
2225c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
2226c9566231SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
2227c9566231SKashyap Desai 	mrioc->init_cmds.callback = NULL;
2228c9566231SKashyap Desai 	create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
2229c9566231SKashyap Desai 	create_req.function = MPI3_FUNCTION_CREATE_REQUEST_QUEUE;
2230c9566231SKashyap Desai 	create_req.queue_id = cpu_to_le16(req_qid);
2231c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
2232c9566231SKashyap Desai 		create_req.flags =
2233c9566231SKashyap Desai 		    MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED;
2234c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
2235c9566231SKashyap Desai 		    op_req_q->q_segment_list_dma);
2236c9566231SKashyap Desai 	} else
2237c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
2238c9566231SKashyap Desai 		    op_req_q->q_segments[0].segment_dma);
2239c9566231SKashyap Desai 	create_req.reply_queue_id = cpu_to_le16(reply_qid);
2240c9566231SKashyap Desai 	create_req.size = cpu_to_le16(op_req_q->num_requests);
2241c9566231SKashyap Desai 
2242c9566231SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
2243c9566231SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &create_req,
2244c9566231SKashyap Desai 	    sizeof(create_req), 1);
2245c9566231SKashyap Desai 	if (retval) {
2246c9566231SKashyap Desai 		ioc_err(mrioc, "CreateReqQ: Admin Post failed\n");
2247c9566231SKashyap Desai 		goto out_unlock;
2248c9566231SKashyap Desai 	}
2249c9566231SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
2250c9566231SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
2251c9566231SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
2252a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "create request queue timed out\n");
2253a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
2254a6856cc4SSreekanth Reddy 		    MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT);
2255c9566231SKashyap Desai 		retval = -1;
2256c9566231SKashyap Desai 		goto out_unlock;
2257c9566231SKashyap Desai 	}
2258c9566231SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
2259c9566231SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
2260c9566231SKashyap Desai 		ioc_err(mrioc,
2261c9566231SKashyap Desai 		    "CreateReqQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
2262c9566231SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
2263c9566231SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
2264c9566231SKashyap Desai 		retval = -1;
2265c9566231SKashyap Desai 		goto out_unlock;
2266c9566231SKashyap Desai 	}
2267c9566231SKashyap Desai 	op_req_q->qid = req_qid;
2268c9566231SKashyap Desai 
2269c9566231SKashyap Desai out_unlock:
2270c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
2271c9566231SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
2272c9566231SKashyap Desai out:
2273c9566231SKashyap Desai 
2274c9566231SKashyap Desai 	return retval;
2275c9566231SKashyap Desai }
2276c9566231SKashyap Desai 
2277c9566231SKashyap Desai /**
2278c9566231SKashyap Desai  * mpi3mr_create_op_queues - create operational queue pairs
2279c9566231SKashyap Desai  * @mrioc: Adapter instance reference
2280c9566231SKashyap Desai  *
2281c9566231SKashyap Desai  * Allocate memory for operational queue meta data and call
2282c9566231SKashyap Desai  * create request and reply queue functions.
2283c9566231SKashyap Desai  *
2284c9566231SKashyap Desai  * Return: 0 on success, non-zero on failures.
2285c9566231SKashyap Desai  */
mpi3mr_create_op_queues(struct mpi3mr_ioc * mrioc)2286c9566231SKashyap Desai static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc)
2287c9566231SKashyap Desai {
2288c9566231SKashyap Desai 	int retval = 0;
2289c9566231SKashyap Desai 	u16 num_queues = 0, i = 0, msix_count_op_q = 1;
2290c9566231SKashyap Desai 
2291c9566231SKashyap Desai 	num_queues = min_t(int, mrioc->facts.max_op_reply_q,
2292c9566231SKashyap Desai 	    mrioc->facts.max_op_req_q);
2293c9566231SKashyap Desai 
2294c9566231SKashyap Desai 	msix_count_op_q =
2295c9566231SKashyap Desai 	    mrioc->intr_info_count - mrioc->op_reply_q_offset;
2296c9566231SKashyap Desai 	if (!mrioc->num_queues)
2297c9566231SKashyap Desai 		mrioc->num_queues = min_t(int, num_queues, msix_count_op_q);
2298c5758fc7SSreekanth Reddy 	/*
2299c5758fc7SSreekanth Reddy 	 * During reset set the num_queues to the number of queues
2300c5758fc7SSreekanth Reddy 	 * that was set before the reset.
2301c5758fc7SSreekanth Reddy 	 */
2302c5758fc7SSreekanth Reddy 	num_queues = mrioc->num_op_reply_q ?
2303c5758fc7SSreekanth Reddy 	    mrioc->num_op_reply_q : mrioc->num_queues;
2304c5758fc7SSreekanth Reddy 	ioc_info(mrioc, "trying to create %d operational queue pairs\n",
2305c9566231SKashyap Desai 	    num_queues);
2306c9566231SKashyap Desai 
2307c9566231SKashyap Desai 	if (!mrioc->req_qinfo) {
2308c9566231SKashyap Desai 		mrioc->req_qinfo = kcalloc(num_queues,
2309c9566231SKashyap Desai 		    sizeof(struct op_req_qinfo), GFP_KERNEL);
2310c9566231SKashyap Desai 		if (!mrioc->req_qinfo) {
2311c9566231SKashyap Desai 			retval = -1;
2312c9566231SKashyap Desai 			goto out_failed;
2313c9566231SKashyap Desai 		}
2314c9566231SKashyap Desai 
2315c9566231SKashyap Desai 		mrioc->op_reply_qinfo = kzalloc(sizeof(struct op_reply_qinfo) *
2316c9566231SKashyap Desai 		    num_queues, GFP_KERNEL);
2317c9566231SKashyap Desai 		if (!mrioc->op_reply_qinfo) {
2318c9566231SKashyap Desai 			retval = -1;
2319c9566231SKashyap Desai 			goto out_failed;
2320c9566231SKashyap Desai 		}
2321c9566231SKashyap Desai 	}
2322c9566231SKashyap Desai 
2323c9566231SKashyap Desai 	if (mrioc->enable_segqueue)
2324c9566231SKashyap Desai 		ioc_info(mrioc,
2325c9566231SKashyap Desai 		    "allocating operational queues through segmented queues\n");
2326c9566231SKashyap Desai 
2327c9566231SKashyap Desai 	for (i = 0; i < num_queues; i++) {
2328c9566231SKashyap Desai 		if (mpi3mr_create_op_reply_q(mrioc, i)) {
2329c9566231SKashyap Desai 			ioc_err(mrioc, "Cannot create OP RepQ %d\n", i);
2330c9566231SKashyap Desai 			break;
2331c9566231SKashyap Desai 		}
2332c9566231SKashyap Desai 		if (mpi3mr_create_op_req_q(mrioc, i,
2333c9566231SKashyap Desai 		    mrioc->op_reply_qinfo[i].qid)) {
2334c9566231SKashyap Desai 			ioc_err(mrioc, "Cannot create OP ReqQ %d\n", i);
2335c9566231SKashyap Desai 			mpi3mr_delete_op_reply_q(mrioc, i);
2336c9566231SKashyap Desai 			break;
2337c9566231SKashyap Desai 		}
2338c9566231SKashyap Desai 	}
2339c9566231SKashyap Desai 
2340c9566231SKashyap Desai 	if (i == 0) {
2341c9566231SKashyap Desai 		/* Not even one queue is created successfully*/
2342c9566231SKashyap Desai 		retval = -1;
2343c9566231SKashyap Desai 		goto out_failed;
2344c9566231SKashyap Desai 	}
2345c9566231SKashyap Desai 	mrioc->num_op_reply_q = mrioc->num_op_req_q = i;
2346afd3a579SSreekanth Reddy 	ioc_info(mrioc,
2347afd3a579SSreekanth Reddy 	    "successfully created %d operational queue pairs(default/polled) queue = (%d/%d)\n",
2348afd3a579SSreekanth Reddy 	    mrioc->num_op_reply_q, mrioc->default_qcount,
2349afd3a579SSreekanth Reddy 	    mrioc->active_poll_qcount);
2350c9566231SKashyap Desai 
2351c9566231SKashyap Desai 	return retval;
2352c9566231SKashyap Desai out_failed:
2353c9566231SKashyap Desai 	kfree(mrioc->req_qinfo);
2354c9566231SKashyap Desai 	mrioc->req_qinfo = NULL;
2355c9566231SKashyap Desai 
2356c9566231SKashyap Desai 	kfree(mrioc->op_reply_qinfo);
2357c9566231SKashyap Desai 	mrioc->op_reply_qinfo = NULL;
2358c9566231SKashyap Desai 
2359c9566231SKashyap Desai 	return retval;
2360c9566231SKashyap Desai }
2361c9566231SKashyap Desai 
2362c9566231SKashyap Desai /**
2363023ab2a9SKashyap Desai  * mpi3mr_op_request_post - Post request to operational queue
2364023ab2a9SKashyap Desai  * @mrioc: Adapter reference
2365023ab2a9SKashyap Desai  * @op_req_q: Operational request queue info
2366023ab2a9SKashyap Desai  * @req: MPI3 request
2367023ab2a9SKashyap Desai  *
2368023ab2a9SKashyap Desai  * Post the MPI3 request into operational request queue and
2369023ab2a9SKashyap Desai  * inform the controller, if the queue is full return
2370023ab2a9SKashyap Desai  * appropriate error.
2371023ab2a9SKashyap Desai  *
2372023ab2a9SKashyap Desai  * Return: 0 on success, non-zero on failure.
2373023ab2a9SKashyap Desai  */
mpi3mr_op_request_post(struct mpi3mr_ioc * mrioc,struct op_req_qinfo * op_req_q,u8 * req)2374023ab2a9SKashyap Desai int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc,
2375023ab2a9SKashyap Desai 	struct op_req_qinfo *op_req_q, u8 *req)
2376023ab2a9SKashyap Desai {
2377023ab2a9SKashyap Desai 	u16 pi = 0, max_entries, reply_qidx = 0, midx;
2378023ab2a9SKashyap Desai 	int retval = 0;
2379023ab2a9SKashyap Desai 	unsigned long flags;
2380023ab2a9SKashyap Desai 	u8 *req_entry;
2381023ab2a9SKashyap Desai 	void *segment_base_addr;
2382023ab2a9SKashyap Desai 	u16 req_sz = mrioc->facts.op_req_sz;
2383023ab2a9SKashyap Desai 	struct segments *segments = op_req_q->q_segments;
2384023ab2a9SKashyap Desai 
2385023ab2a9SKashyap Desai 	reply_qidx = op_req_q->reply_qid - 1;
2386023ab2a9SKashyap Desai 
2387023ab2a9SKashyap Desai 	if (mrioc->unrecoverable)
2388023ab2a9SKashyap Desai 		return -EFAULT;
2389023ab2a9SKashyap Desai 
2390023ab2a9SKashyap Desai 	spin_lock_irqsave(&op_req_q->q_lock, flags);
2391023ab2a9SKashyap Desai 	pi = op_req_q->pi;
2392023ab2a9SKashyap Desai 	max_entries = op_req_q->num_requests;
2393023ab2a9SKashyap Desai 
2394023ab2a9SKashyap Desai 	if (mpi3mr_check_req_qfull(op_req_q)) {
2395023ab2a9SKashyap Desai 		midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(
2396023ab2a9SKashyap Desai 		    reply_qidx, mrioc->op_reply_q_offset);
2397afd3a579SSreekanth Reddy 		mpi3mr_process_op_reply_q(mrioc, mrioc->intr_info[midx].op_reply_q);
2398023ab2a9SKashyap Desai 
2399023ab2a9SKashyap Desai 		if (mpi3mr_check_req_qfull(op_req_q)) {
2400023ab2a9SKashyap Desai 			retval = -EAGAIN;
2401023ab2a9SKashyap Desai 			goto out;
2402023ab2a9SKashyap Desai 		}
2403023ab2a9SKashyap Desai 	}
2404023ab2a9SKashyap Desai 
2405023ab2a9SKashyap Desai 	if (mrioc->reset_in_progress) {
2406023ab2a9SKashyap Desai 		ioc_err(mrioc, "OpReqQ submit reset in progress\n");
2407023ab2a9SKashyap Desai 		retval = -EAGAIN;
2408023ab2a9SKashyap Desai 		goto out;
2409023ab2a9SKashyap Desai 	}
24101c342b05SSumit Saxena 	if (mrioc->pci_err_recovery) {
24111c342b05SSumit Saxena 		ioc_err(mrioc, "operational request queue submission failed due to pci error recovery in progress\n");
24121c342b05SSumit Saxena 		retval = -EAGAIN;
24131c342b05SSumit Saxena 		goto out;
24141c342b05SSumit Saxena 	}
2415023ab2a9SKashyap Desai 
2416023ab2a9SKashyap Desai 	segment_base_addr = segments[pi / op_req_q->segment_qd].segment;
2417023ab2a9SKashyap Desai 	req_entry = (u8 *)segment_base_addr +
2418023ab2a9SKashyap Desai 	    ((pi % op_req_q->segment_qd) * req_sz);
2419023ab2a9SKashyap Desai 
2420023ab2a9SKashyap Desai 	memset(req_entry, 0, req_sz);
2421023ab2a9SKashyap Desai 	memcpy(req_entry, req, MPI3MR_ADMIN_REQ_FRAME_SZ);
2422023ab2a9SKashyap Desai 
2423023ab2a9SKashyap Desai 	if (++pi == max_entries)
2424023ab2a9SKashyap Desai 		pi = 0;
2425023ab2a9SKashyap Desai 	op_req_q->pi = pi;
2426023ab2a9SKashyap Desai 
24277f9f953dSSreekanth Reddy #ifndef CONFIG_PREEMPT_RT
2428463429f8SKashyap Desai 	if (atomic_inc_return(&mrioc->op_reply_qinfo[reply_qidx].pend_ios)
2429463429f8SKashyap Desai 	    > MPI3MR_IRQ_POLL_TRIGGER_IOCOUNT)
2430463429f8SKashyap Desai 		mrioc->op_reply_qinfo[reply_qidx].enable_irq_poll = true;
24317f9f953dSSreekanth Reddy #else
24327f9f953dSSreekanth Reddy 	atomic_inc_return(&mrioc->op_reply_qinfo[reply_qidx].pend_ios);
24337f9f953dSSreekanth Reddy #endif
2434463429f8SKashyap Desai 
2435023ab2a9SKashyap Desai 	writel(op_req_q->pi,
2436023ab2a9SKashyap Desai 	    &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].producer_index);
2437023ab2a9SKashyap Desai 
2438023ab2a9SKashyap Desai out:
2439023ab2a9SKashyap Desai 	spin_unlock_irqrestore(&op_req_q->q_lock, flags);
2440023ab2a9SKashyap Desai 	return retval;
2441023ab2a9SKashyap Desai }
2442023ab2a9SKashyap Desai 
2443023ab2a9SKashyap Desai /**
2444a6856cc4SSreekanth Reddy  * mpi3mr_check_rh_fault_ioc - check reset history and fault
2445a6856cc4SSreekanth Reddy  * controller
2446a6856cc4SSreekanth Reddy  * @mrioc: Adapter instance reference
24473bb3c24eSYang Li  * @reason_code: reason code for the fault.
2448a6856cc4SSreekanth Reddy  *
2449a6856cc4SSreekanth Reddy  * This routine will save snapdump and fault the controller with
2450a6856cc4SSreekanth Reddy  * the given reason code if it is not already in the fault or
2451a6856cc4SSreekanth Reddy  * not asynchronosuly reset. This will be used to handle
2452a6856cc4SSreekanth Reddy  * initilaization time faults/resets/timeout as in those cases
2453a6856cc4SSreekanth Reddy  * immediate soft reset invocation is not required.
2454a6856cc4SSreekanth Reddy  *
2455a6856cc4SSreekanth Reddy  * Return:  None.
2456a6856cc4SSreekanth Reddy  */
mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc * mrioc,u32 reason_code)2457a6856cc4SSreekanth Reddy void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code)
2458a6856cc4SSreekanth Reddy {
2459a6856cc4SSreekanth Reddy 	u32 ioc_status, host_diagnostic, timeout;
2460d8d08d16SRanjan Kumar 	union mpi3mr_trigger_data trigger_data;
2461a6856cc4SSreekanth Reddy 
2462f2a79d20SSreekanth Reddy 	if (mrioc->unrecoverable) {
2463f2a79d20SSreekanth Reddy 		ioc_err(mrioc, "controller is unrecoverable\n");
2464f2a79d20SSreekanth Reddy 		return;
2465f2a79d20SSreekanth Reddy 	}
2466f2a79d20SSreekanth Reddy 
2467f2a79d20SSreekanth Reddy 	if (!pci_device_is_present(mrioc->pdev)) {
2468f2a79d20SSreekanth Reddy 		mrioc->unrecoverable = 1;
2469f2a79d20SSreekanth Reddy 		ioc_err(mrioc, "controller is not present\n");
2470f2a79d20SSreekanth Reddy 		return;
2471f2a79d20SSreekanth Reddy 	}
2472d8d08d16SRanjan Kumar 	memset(&trigger_data, 0, sizeof(trigger_data));
2473a6856cc4SSreekanth Reddy 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
2474d8d08d16SRanjan Kumar 
2475d8d08d16SRanjan Kumar 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) {
2476d8d08d16SRanjan Kumar 		mpi3mr_set_trigger_data_in_all_hdb(mrioc,
2477d8d08d16SRanjan Kumar 		    MPI3MR_HDB_TRIGGER_TYPE_FW_RELEASED, NULL, 0);
2478d8d08d16SRanjan Kumar 		return;
2479d8d08d16SRanjan Kumar 	} else if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) {
2480d8d08d16SRanjan Kumar 		trigger_data.fault = (readl(&mrioc->sysif_regs->fault) &
2481d8d08d16SRanjan Kumar 		      MPI3_SYSIF_FAULT_CODE_MASK);
2482d8d08d16SRanjan Kumar 
2483d8d08d16SRanjan Kumar 		mpi3mr_set_trigger_data_in_all_hdb(mrioc,
2484d8d08d16SRanjan Kumar 		    MPI3MR_HDB_TRIGGER_TYPE_FAULT, &trigger_data, 0);
2485a6856cc4SSreekanth Reddy 		mpi3mr_print_fault_info(mrioc);
2486a6856cc4SSreekanth Reddy 		return;
2487a6856cc4SSreekanth Reddy 	}
2488d8d08d16SRanjan Kumar 
2489a6856cc4SSreekanth Reddy 	mpi3mr_set_diagsave(mrioc);
2490a6856cc4SSreekanth Reddy 	mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
2491a6856cc4SSreekanth Reddy 	    reason_code);
2492d8d08d16SRanjan Kumar 	trigger_data.fault = (readl(&mrioc->sysif_regs->fault) &
2493d8d08d16SRanjan Kumar 		      MPI3_SYSIF_FAULT_CODE_MASK);
2494d8d08d16SRanjan Kumar 	mpi3mr_set_trigger_data_in_all_hdb(mrioc, MPI3MR_HDB_TRIGGER_TYPE_FAULT,
2495d8d08d16SRanjan Kumar 	    &trigger_data, 0);
2496a6856cc4SSreekanth Reddy 	timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10;
2497a6856cc4SSreekanth Reddy 	do {
2498a6856cc4SSreekanth Reddy 		host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic);
2499a6856cc4SSreekanth Reddy 		if (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS))
2500a6856cc4SSreekanth Reddy 			break;
2501a6856cc4SSreekanth Reddy 		msleep(100);
2502a6856cc4SSreekanth Reddy 	} while (--timeout);
2503a6856cc4SSreekanth Reddy }
2504a6856cc4SSreekanth Reddy 
2505a6856cc4SSreekanth Reddy /**
250654dfcffbSKashyap Desai  * mpi3mr_sync_timestamp - Issue time stamp sync request
250754dfcffbSKashyap Desai  * @mrioc: Adapter reference
250854dfcffbSKashyap Desai  *
250954dfcffbSKashyap Desai  * Issue IO unit control MPI request to synchornize firmware
251054dfcffbSKashyap Desai  * timestamp with host time.
251154dfcffbSKashyap Desai  *
251254dfcffbSKashyap Desai  * Return: 0 on success, non-zero on failure.
251354dfcffbSKashyap Desai  */
mpi3mr_sync_timestamp(struct mpi3mr_ioc * mrioc)251454dfcffbSKashyap Desai static int mpi3mr_sync_timestamp(struct mpi3mr_ioc *mrioc)
251554dfcffbSKashyap Desai {
251654dfcffbSKashyap Desai 	ktime_t current_time;
251754dfcffbSKashyap Desai 	struct mpi3_iounit_control_request iou_ctrl;
251854dfcffbSKashyap Desai 	int retval = 0;
251954dfcffbSKashyap Desai 
252054dfcffbSKashyap Desai 	memset(&iou_ctrl, 0, sizeof(iou_ctrl));
252154dfcffbSKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
252254dfcffbSKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
252354dfcffbSKashyap Desai 		retval = -1;
252454dfcffbSKashyap Desai 		ioc_err(mrioc, "Issue IOUCTL time_stamp: command is in use\n");
252554dfcffbSKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
252654dfcffbSKashyap Desai 		goto out;
252754dfcffbSKashyap Desai 	}
252854dfcffbSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
252954dfcffbSKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
253054dfcffbSKashyap Desai 	mrioc->init_cmds.callback = NULL;
253154dfcffbSKashyap Desai 	iou_ctrl.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
253254dfcffbSKashyap Desai 	iou_ctrl.function = MPI3_FUNCTION_IO_UNIT_CONTROL;
253354dfcffbSKashyap Desai 	iou_ctrl.operation = MPI3_CTRL_OP_UPDATE_TIMESTAMP;
253454dfcffbSKashyap Desai 	current_time = ktime_get_real();
253554dfcffbSKashyap Desai 	iou_ctrl.param64[0] = cpu_to_le64(ktime_to_ms(current_time));
253654dfcffbSKashyap Desai 
253754dfcffbSKashyap Desai 	init_completion(&mrioc->init_cmds.done);
253854dfcffbSKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &iou_ctrl,
253954dfcffbSKashyap Desai 	    sizeof(iou_ctrl), 0);
254054dfcffbSKashyap Desai 	if (retval) {
254154dfcffbSKashyap Desai 		ioc_err(mrioc, "Issue IOUCTL time_stamp: Admin Post failed\n");
254254dfcffbSKashyap Desai 		goto out_unlock;
254354dfcffbSKashyap Desai 	}
254454dfcffbSKashyap Desai 
254554dfcffbSKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
254654dfcffbSKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
254754dfcffbSKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
254854dfcffbSKashyap Desai 		ioc_err(mrioc, "Issue IOUCTL time_stamp: command timed out\n");
254954dfcffbSKashyap Desai 		mrioc->init_cmds.is_waiting = 0;
2550fbaa9aa4SSreekanth Reddy 		if (!(mrioc->init_cmds.state & MPI3MR_CMD_RESET))
25519134211fSRanjan Kumar 			mpi3mr_check_rh_fault_ioc(mrioc,
25529134211fSRanjan Kumar 			    MPI3MR_RESET_FROM_TSU_TIMEOUT);
255354dfcffbSKashyap Desai 		retval = -1;
255454dfcffbSKashyap Desai 		goto out_unlock;
255554dfcffbSKashyap Desai 	}
255654dfcffbSKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
255754dfcffbSKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
255854dfcffbSKashyap Desai 		ioc_err(mrioc,
255954dfcffbSKashyap Desai 		    "Issue IOUCTL time_stamp: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
256054dfcffbSKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
256154dfcffbSKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
256254dfcffbSKashyap Desai 		retval = -1;
256354dfcffbSKashyap Desai 		goto out_unlock;
256454dfcffbSKashyap Desai 	}
256554dfcffbSKashyap Desai 
256654dfcffbSKashyap Desai out_unlock:
256754dfcffbSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
256854dfcffbSKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
256954dfcffbSKashyap Desai 
257054dfcffbSKashyap Desai out:
257154dfcffbSKashyap Desai 	return retval;
257254dfcffbSKashyap Desai }
257354dfcffbSKashyap Desai 
257454dfcffbSKashyap Desai /**
25752ac794baSSreekanth Reddy  * mpi3mr_print_pkg_ver - display controller fw package version
25762ac794baSSreekanth Reddy  * @mrioc: Adapter reference
25772ac794baSSreekanth Reddy  *
25782ac794baSSreekanth Reddy  * Retrieve firmware package version from the component image
25792ac794baSSreekanth Reddy  * header of the controller flash and display it.
25802ac794baSSreekanth Reddy  *
25812ac794baSSreekanth Reddy  * Return: 0 on success and non-zero on failure.
25822ac794baSSreekanth Reddy  */
mpi3mr_print_pkg_ver(struct mpi3mr_ioc * mrioc)25832ac794baSSreekanth Reddy static int mpi3mr_print_pkg_ver(struct mpi3mr_ioc *mrioc)
25842ac794baSSreekanth Reddy {
25852ac794baSSreekanth Reddy 	struct mpi3_ci_upload_request ci_upload;
25862ac794baSSreekanth Reddy 	int retval = -1;
25872ac794baSSreekanth Reddy 	void *data = NULL;
25882ac794baSSreekanth Reddy 	dma_addr_t data_dma;
25892ac794baSSreekanth Reddy 	struct mpi3_ci_manifest_mpi *manifest;
25902ac794baSSreekanth Reddy 	u32 data_len = sizeof(struct mpi3_ci_manifest_mpi);
25912ac794baSSreekanth Reddy 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
25922ac794baSSreekanth Reddy 
25932ac794baSSreekanth Reddy 	data = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma,
25942ac794baSSreekanth Reddy 	    GFP_KERNEL);
25952ac794baSSreekanth Reddy 	if (!data)
25962ac794baSSreekanth Reddy 		return -ENOMEM;
25972ac794baSSreekanth Reddy 
25982ac794baSSreekanth Reddy 	memset(&ci_upload, 0, sizeof(ci_upload));
25992ac794baSSreekanth Reddy 	mutex_lock(&mrioc->init_cmds.mutex);
26002ac794baSSreekanth Reddy 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
26012ac794baSSreekanth Reddy 		ioc_err(mrioc, "sending get package version failed due to command in use\n");
26022ac794baSSreekanth Reddy 		mutex_unlock(&mrioc->init_cmds.mutex);
26032ac794baSSreekanth Reddy 		goto out;
26042ac794baSSreekanth Reddy 	}
26052ac794baSSreekanth Reddy 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
26062ac794baSSreekanth Reddy 	mrioc->init_cmds.is_waiting = 1;
26072ac794baSSreekanth Reddy 	mrioc->init_cmds.callback = NULL;
26082ac794baSSreekanth Reddy 	ci_upload.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
26092ac794baSSreekanth Reddy 	ci_upload.function = MPI3_FUNCTION_CI_UPLOAD;
26102ac794baSSreekanth Reddy 	ci_upload.msg_flags = MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_PRIMARY;
26112ac794baSSreekanth Reddy 	ci_upload.signature1 = cpu_to_le32(MPI3_IMAGE_HEADER_SIGNATURE1_MANIFEST);
26122ac794baSSreekanth Reddy 	ci_upload.image_offset = cpu_to_le32(MPI3_IMAGE_HEADER_SIZE);
26132ac794baSSreekanth Reddy 	ci_upload.segment_size = cpu_to_le32(data_len);
26142ac794baSSreekanth Reddy 
26152ac794baSSreekanth Reddy 	mpi3mr_add_sg_single(&ci_upload.sgl, sgl_flags, data_len,
26162ac794baSSreekanth Reddy 	    data_dma);
26172ac794baSSreekanth Reddy 	init_completion(&mrioc->init_cmds.done);
26182ac794baSSreekanth Reddy 	retval = mpi3mr_admin_request_post(mrioc, &ci_upload,
26192ac794baSSreekanth Reddy 	    sizeof(ci_upload), 1);
26202ac794baSSreekanth Reddy 	if (retval) {
26212ac794baSSreekanth Reddy 		ioc_err(mrioc, "posting get package version failed\n");
26222ac794baSSreekanth Reddy 		goto out_unlock;
26232ac794baSSreekanth Reddy 	}
26242ac794baSSreekanth Reddy 	wait_for_completion_timeout(&mrioc->init_cmds.done,
26252ac794baSSreekanth Reddy 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
26262ac794baSSreekanth Reddy 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
26272ac794baSSreekanth Reddy 		ioc_err(mrioc, "get package version timed out\n");
2628a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
2629a6856cc4SSreekanth Reddy 		    MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT);
26302ac794baSSreekanth Reddy 		retval = -1;
26312ac794baSSreekanth Reddy 		goto out_unlock;
26322ac794baSSreekanth Reddy 	}
26332ac794baSSreekanth Reddy 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
26342ac794baSSreekanth Reddy 	    == MPI3_IOCSTATUS_SUCCESS) {
26352ac794baSSreekanth Reddy 		manifest = (struct mpi3_ci_manifest_mpi *) data;
26362ac794baSSreekanth Reddy 		if (manifest->manifest_type == MPI3_CI_MANIFEST_TYPE_MPI) {
26372ac794baSSreekanth Reddy 			ioc_info(mrioc,
26382ac794baSSreekanth Reddy 			    "firmware package version(%d.%d.%d.%d.%05d-%05d)\n",
26392ac794baSSreekanth Reddy 			    manifest->package_version.gen_major,
26402ac794baSSreekanth Reddy 			    manifest->package_version.gen_minor,
26412ac794baSSreekanth Reddy 			    manifest->package_version.phase_major,
26422ac794baSSreekanth Reddy 			    manifest->package_version.phase_minor,
26432ac794baSSreekanth Reddy 			    manifest->package_version.customer_id,
26442ac794baSSreekanth Reddy 			    manifest->package_version.build_num);
26452ac794baSSreekanth Reddy 		}
26462ac794baSSreekanth Reddy 	}
26472ac794baSSreekanth Reddy 	retval = 0;
26482ac794baSSreekanth Reddy out_unlock:
26492ac794baSSreekanth Reddy 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
26502ac794baSSreekanth Reddy 	mutex_unlock(&mrioc->init_cmds.mutex);
26512ac794baSSreekanth Reddy 
26522ac794baSSreekanth Reddy out:
26532ac794baSSreekanth Reddy 	if (data)
26542ac794baSSreekanth Reddy 		dma_free_coherent(&mrioc->pdev->dev, data_len, data,
26552ac794baSSreekanth Reddy 		    data_dma);
26562ac794baSSreekanth Reddy 	return retval;
26572ac794baSSreekanth Reddy }
26582ac794baSSreekanth Reddy 
26592ac794baSSreekanth Reddy /**
2660672ae26cSKashyap Desai  * mpi3mr_watchdog_work - watchdog thread to monitor faults
2661672ae26cSKashyap Desai  * @work: work struct
2662672ae26cSKashyap Desai  *
2663672ae26cSKashyap Desai  * Watch dog work periodically executed (1 second interval) to
2664672ae26cSKashyap Desai  * monitor firmware fault and to issue periodic timer sync to
2665672ae26cSKashyap Desai  * the firmware.
2666672ae26cSKashyap Desai  *
2667672ae26cSKashyap Desai  * Return: Nothing.
2668672ae26cSKashyap Desai  */
mpi3mr_watchdog_work(struct work_struct * work)2669672ae26cSKashyap Desai static void mpi3mr_watchdog_work(struct work_struct *work)
2670672ae26cSKashyap Desai {
2671672ae26cSKashyap Desai 	struct mpi3mr_ioc *mrioc =
2672672ae26cSKashyap Desai 	    container_of(work, struct mpi3mr_ioc, watchdog_work.work);
2673672ae26cSKashyap Desai 	unsigned long flags;
2674672ae26cSKashyap Desai 	enum mpi3mr_iocstate ioc_state;
2675d8d08d16SRanjan Kumar 	u32 host_diagnostic, ioc_status;
2676d8d08d16SRanjan Kumar 	union mpi3mr_trigger_data trigger_data;
26770a2714b7SRanjan Kumar 	u16 reset_reason = MPI3MR_RESET_FROM_FAULT_WATCH;
2678672ae26cSKashyap Desai 
26791c342b05SSumit Saxena 	if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
2680b64845a7SSreekanth Reddy 		return;
2681b64845a7SSreekanth Reddy 
2682f2a79d20SSreekanth Reddy 	if (!mrioc->unrecoverable && !pci_device_is_present(mrioc->pdev)) {
2683f2a79d20SSreekanth Reddy 		ioc_err(mrioc, "watchdog could not detect the controller\n");
2684f2a79d20SSreekanth Reddy 		mrioc->unrecoverable = 1;
2685f2a79d20SSreekanth Reddy 	}
2686f2a79d20SSreekanth Reddy 
2687f2a79d20SSreekanth Reddy 	if (mrioc->unrecoverable) {
2688f2a79d20SSreekanth Reddy 		ioc_err(mrioc,
2689f2a79d20SSreekanth Reddy 		    "flush pending commands for unrecoverable controller\n");
2690f2a79d20SSreekanth Reddy 		mpi3mr_flush_cmds_for_unrecovered_controller(mrioc);
2691f2a79d20SSreekanth Reddy 		return;
2692f2a79d20SSreekanth Reddy 	}
2693f2a79d20SSreekanth Reddy 
2694fc1ddda3SRanjan Kumar 	if (mrioc->ts_update_counter++ >= mrioc->ts_update_interval) {
269554dfcffbSKashyap Desai 		mrioc->ts_update_counter = 0;
269654dfcffbSKashyap Desai 		mpi3mr_sync_timestamp(mrioc);
269754dfcffbSKashyap Desai 	}
269854dfcffbSKashyap Desai 
269978b76a07SSreekanth Reddy 	if ((mrioc->prepare_for_reset) &&
270078b76a07SSreekanth Reddy 	    ((mrioc->prepare_for_reset_timeout_counter++) >=
270178b76a07SSreekanth Reddy 	     MPI3MR_PREPARE_FOR_RESET_TIMEOUT)) {
270278b76a07SSreekanth Reddy 		mpi3mr_soft_reset_handler(mrioc,
270378b76a07SSreekanth Reddy 		    MPI3MR_RESET_FROM_CIACTVRST_TIMER, 1);
270478b76a07SSreekanth Reddy 		return;
270578b76a07SSreekanth Reddy 	}
270678b76a07SSreekanth Reddy 
2707d8d08d16SRanjan Kumar 	memset(&trigger_data, 0, sizeof(trigger_data));
270878b76a07SSreekanth Reddy 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
270978b76a07SSreekanth Reddy 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) {
2710d8d08d16SRanjan Kumar 		mpi3mr_set_trigger_data_in_all_hdb(mrioc,
2711d8d08d16SRanjan Kumar 		    MPI3MR_HDB_TRIGGER_TYPE_FW_RELEASED, NULL, 0);
271278b76a07SSreekanth Reddy 		mpi3mr_soft_reset_handler(mrioc, MPI3MR_RESET_FROM_FIRMWARE, 0);
271378b76a07SSreekanth Reddy 		return;
271478b76a07SSreekanth Reddy 	}
271578b76a07SSreekanth Reddy 
2716672ae26cSKashyap Desai 	/*Check for fault state every one second and issue Soft reset*/
2717672ae26cSKashyap Desai 	ioc_state = mpi3mr_get_iocstate(mrioc);
271878b76a07SSreekanth Reddy 	if (ioc_state != MRIOC_STATE_FAULT)
271978b76a07SSreekanth Reddy 		goto schedule_work;
272078b76a07SSreekanth Reddy 
2721d8d08d16SRanjan Kumar 	trigger_data.fault = readl(&mrioc->sysif_regs->fault) & MPI3_SYSIF_FAULT_CODE_MASK;
2722d8d08d16SRanjan Kumar 	mpi3mr_set_trigger_data_in_all_hdb(mrioc,
2723d8d08d16SRanjan Kumar 	    MPI3MR_HDB_TRIGGER_TYPE_FAULT, &trigger_data, 0);
2724672ae26cSKashyap Desai 	host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic);
2725672ae26cSKashyap Desai 	if (host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS) {
2726672ae26cSKashyap Desai 		if (!mrioc->diagsave_timeout) {
2727672ae26cSKashyap Desai 			mpi3mr_print_fault_info(mrioc);
272878b76a07SSreekanth Reddy 			ioc_warn(mrioc, "diag save in progress\n");
2729672ae26cSKashyap Desai 		}
273078b76a07SSreekanth Reddy 		if ((mrioc->diagsave_timeout++) <= MPI3_SYSIF_DIAG_SAVE_TIMEOUT)
2731672ae26cSKashyap Desai 			goto schedule_work;
273278b76a07SSreekanth Reddy 	}
273378b76a07SSreekanth Reddy 
2734672ae26cSKashyap Desai 	mpi3mr_print_fault_info(mrioc);
2735672ae26cSKashyap Desai 	mrioc->diagsave_timeout = 0;
2736672ae26cSKashyap Desai 
2737d8d08d16SRanjan Kumar 	switch (trigger_data.fault) {
2738bad2f28dSSreekanth Reddy 	case MPI3_SYSIF_FAULT_CODE_COMPLETE_RESET_NEEDED:
273978b76a07SSreekanth Reddy 	case MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED:
2740bad2f28dSSreekanth Reddy 		ioc_warn(mrioc,
274178b76a07SSreekanth Reddy 		    "controller requires system power cycle, marking controller as unrecoverable\n");
2742672ae26cSKashyap Desai 		mrioc->unrecoverable = 1;
2743f2a79d20SSreekanth Reddy 		goto schedule_work;
274478b76a07SSreekanth Reddy 	case MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS:
2745a3d27dfdSRanjan Kumar 		goto schedule_work;
274678b76a07SSreekanth Reddy 	case MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET:
274778b76a07SSreekanth Reddy 		reset_reason = MPI3MR_RESET_FROM_CIACTIV_FAULT;
274878b76a07SSreekanth Reddy 		break;
274978b76a07SSreekanth Reddy 	default:
275078b76a07SSreekanth Reddy 		break;
2751672ae26cSKashyap Desai 	}
275278b76a07SSreekanth Reddy 	mpi3mr_soft_reset_handler(mrioc, reset_reason, 0);
275378b76a07SSreekanth Reddy 	return;
2754672ae26cSKashyap Desai 
2755672ae26cSKashyap Desai schedule_work:
2756672ae26cSKashyap Desai 	spin_lock_irqsave(&mrioc->watchdog_lock, flags);
2757672ae26cSKashyap Desai 	if (mrioc->watchdog_work_q)
2758672ae26cSKashyap Desai 		queue_delayed_work(mrioc->watchdog_work_q,
2759672ae26cSKashyap Desai 		    &mrioc->watchdog_work,
2760672ae26cSKashyap Desai 		    msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL));
2761672ae26cSKashyap Desai 	spin_unlock_irqrestore(&mrioc->watchdog_lock, flags);
2762672ae26cSKashyap Desai 	return;
2763672ae26cSKashyap Desai }
2764672ae26cSKashyap Desai 
2765672ae26cSKashyap Desai /**
2766672ae26cSKashyap Desai  * mpi3mr_start_watchdog - Start watchdog
2767672ae26cSKashyap Desai  * @mrioc: Adapter instance reference
2768672ae26cSKashyap Desai  *
2769672ae26cSKashyap Desai  * Create and start the watchdog thread to monitor controller
2770672ae26cSKashyap Desai  * faults.
2771672ae26cSKashyap Desai  *
2772672ae26cSKashyap Desai  * Return: Nothing.
2773672ae26cSKashyap Desai  */
mpi3mr_start_watchdog(struct mpi3mr_ioc * mrioc)2774672ae26cSKashyap Desai void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc)
2775672ae26cSKashyap Desai {
2776672ae26cSKashyap Desai 	if (mrioc->watchdog_work_q)
2777672ae26cSKashyap Desai 		return;
2778672ae26cSKashyap Desai 
2779672ae26cSKashyap Desai 	INIT_DELAYED_WORK(&mrioc->watchdog_work, mpi3mr_watchdog_work);
2780672ae26cSKashyap Desai 	snprintf(mrioc->watchdog_work_q_name,
2781672ae26cSKashyap Desai 	    sizeof(mrioc->watchdog_work_q_name), "watchdog_%s%d", mrioc->name,
2782672ae26cSKashyap Desai 	    mrioc->id);
2783b97c0741SBart Van Assche 	mrioc->watchdog_work_q = alloc_ordered_workqueue(
2784b97c0741SBart Van Assche 		"%s", WQ_MEM_RECLAIM, mrioc->watchdog_work_q_name);
2785672ae26cSKashyap Desai 	if (!mrioc->watchdog_work_q) {
2786672ae26cSKashyap Desai 		ioc_err(mrioc, "%s: failed (line=%d)\n", __func__, __LINE__);
2787672ae26cSKashyap Desai 		return;
2788672ae26cSKashyap Desai 	}
2789672ae26cSKashyap Desai 
2790672ae26cSKashyap Desai 	if (mrioc->watchdog_work_q)
2791672ae26cSKashyap Desai 		queue_delayed_work(mrioc->watchdog_work_q,
2792672ae26cSKashyap Desai 		    &mrioc->watchdog_work,
2793672ae26cSKashyap Desai 		    msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL));
2794672ae26cSKashyap Desai }
2795672ae26cSKashyap Desai 
2796672ae26cSKashyap Desai /**
2797672ae26cSKashyap Desai  * mpi3mr_stop_watchdog - Stop watchdog
2798672ae26cSKashyap Desai  * @mrioc: Adapter instance reference
2799672ae26cSKashyap Desai  *
2800672ae26cSKashyap Desai  * Stop the watchdog thread created to monitor controller
2801672ae26cSKashyap Desai  * faults.
2802672ae26cSKashyap Desai  *
2803672ae26cSKashyap Desai  * Return: Nothing.
2804672ae26cSKashyap Desai  */
mpi3mr_stop_watchdog(struct mpi3mr_ioc * mrioc)2805672ae26cSKashyap Desai void mpi3mr_stop_watchdog(struct mpi3mr_ioc *mrioc)
2806672ae26cSKashyap Desai {
2807672ae26cSKashyap Desai 	unsigned long flags;
2808672ae26cSKashyap Desai 	struct workqueue_struct *wq;
2809672ae26cSKashyap Desai 
2810672ae26cSKashyap Desai 	spin_lock_irqsave(&mrioc->watchdog_lock, flags);
2811672ae26cSKashyap Desai 	wq = mrioc->watchdog_work_q;
2812672ae26cSKashyap Desai 	mrioc->watchdog_work_q = NULL;
2813672ae26cSKashyap Desai 	spin_unlock_irqrestore(&mrioc->watchdog_lock, flags);
2814672ae26cSKashyap Desai 	if (wq) {
2815672ae26cSKashyap Desai 		if (!cancel_delayed_work_sync(&mrioc->watchdog_work))
2816672ae26cSKashyap Desai 			flush_workqueue(wq);
2817672ae26cSKashyap Desai 		destroy_workqueue(wq);
2818672ae26cSKashyap Desai 	}
2819672ae26cSKashyap Desai }
2820672ae26cSKashyap Desai 
2821672ae26cSKashyap Desai /**
2822824a1566SKashyap Desai  * mpi3mr_setup_admin_qpair - Setup admin queue pair
2823824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2824824a1566SKashyap Desai  *
2825824a1566SKashyap Desai  * Allocate memory for admin queue pair if required and register
2826824a1566SKashyap Desai  * the admin queue with the controller.
2827824a1566SKashyap Desai  *
2828824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
2829824a1566SKashyap Desai  */
mpi3mr_setup_admin_qpair(struct mpi3mr_ioc * mrioc)2830824a1566SKashyap Desai static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc)
2831824a1566SKashyap Desai {
2832824a1566SKashyap Desai 	int retval = 0;
2833824a1566SKashyap Desai 	u32 num_admin_entries = 0;
2834824a1566SKashyap Desai 
2835824a1566SKashyap Desai 	mrioc->admin_req_q_sz = MPI3MR_ADMIN_REQ_Q_SIZE;
2836824a1566SKashyap Desai 	mrioc->num_admin_req = mrioc->admin_req_q_sz /
2837824a1566SKashyap Desai 	    MPI3MR_ADMIN_REQ_FRAME_SZ;
2838824a1566SKashyap Desai 	mrioc->admin_req_ci = mrioc->admin_req_pi = 0;
2839824a1566SKashyap Desai 
2840824a1566SKashyap Desai 	mrioc->admin_reply_q_sz = MPI3MR_ADMIN_REPLY_Q_SIZE;
2841824a1566SKashyap Desai 	mrioc->num_admin_replies = mrioc->admin_reply_q_sz /
2842824a1566SKashyap Desai 	    MPI3MR_ADMIN_REPLY_FRAME_SZ;
2843824a1566SKashyap Desai 	mrioc->admin_reply_ci = 0;
2844824a1566SKashyap Desai 	mrioc->admin_reply_ephase = 1;
284502ca7da2SRanjan Kumar 	atomic_set(&mrioc->admin_reply_q_in_use, 0);
2846824a1566SKashyap Desai 
2847824a1566SKashyap Desai 	if (!mrioc->admin_req_base) {
2848824a1566SKashyap Desai 		mrioc->admin_req_base = dma_alloc_coherent(&mrioc->pdev->dev,
2849824a1566SKashyap Desai 		    mrioc->admin_req_q_sz, &mrioc->admin_req_dma, GFP_KERNEL);
2850824a1566SKashyap Desai 
2851824a1566SKashyap Desai 		if (!mrioc->admin_req_base) {
2852824a1566SKashyap Desai 			retval = -1;
2853824a1566SKashyap Desai 			goto out_failed;
2854824a1566SKashyap Desai 		}
2855824a1566SKashyap Desai 
2856824a1566SKashyap Desai 		mrioc->admin_reply_base = dma_alloc_coherent(&mrioc->pdev->dev,
2857824a1566SKashyap Desai 		    mrioc->admin_reply_q_sz, &mrioc->admin_reply_dma,
2858824a1566SKashyap Desai 		    GFP_KERNEL);
2859824a1566SKashyap Desai 
2860824a1566SKashyap Desai 		if (!mrioc->admin_reply_base) {
2861824a1566SKashyap Desai 			retval = -1;
2862824a1566SKashyap Desai 			goto out_failed;
2863824a1566SKashyap Desai 		}
2864824a1566SKashyap Desai 	}
2865824a1566SKashyap Desai 
2866824a1566SKashyap Desai 	num_admin_entries = (mrioc->num_admin_replies << 16) |
2867824a1566SKashyap Desai 	    (mrioc->num_admin_req);
2868824a1566SKashyap Desai 	writel(num_admin_entries, &mrioc->sysif_regs->admin_queue_num_entries);
2869824a1566SKashyap Desai 	mpi3mr_writeq(mrioc->admin_req_dma,
2870824a1566SKashyap Desai 	    &mrioc->sysif_regs->admin_request_queue_address);
2871824a1566SKashyap Desai 	mpi3mr_writeq(mrioc->admin_reply_dma,
2872824a1566SKashyap Desai 	    &mrioc->sysif_regs->admin_reply_queue_address);
2873824a1566SKashyap Desai 	writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi);
2874824a1566SKashyap Desai 	writel(mrioc->admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci);
2875824a1566SKashyap Desai 	return retval;
2876824a1566SKashyap Desai 
2877824a1566SKashyap Desai out_failed:
2878824a1566SKashyap Desai 
2879824a1566SKashyap Desai 	if (mrioc->admin_reply_base) {
2880824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz,
2881824a1566SKashyap Desai 		    mrioc->admin_reply_base, mrioc->admin_reply_dma);
2882824a1566SKashyap Desai 		mrioc->admin_reply_base = NULL;
2883824a1566SKashyap Desai 	}
2884824a1566SKashyap Desai 	if (mrioc->admin_req_base) {
2885824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz,
2886824a1566SKashyap Desai 		    mrioc->admin_req_base, mrioc->admin_req_dma);
2887824a1566SKashyap Desai 		mrioc->admin_req_base = NULL;
2888824a1566SKashyap Desai 	}
2889824a1566SKashyap Desai 	return retval;
2890824a1566SKashyap Desai }
2891824a1566SKashyap Desai 
2892824a1566SKashyap Desai /**
2893824a1566SKashyap Desai  * mpi3mr_issue_iocfacts - Send IOC Facts
2894824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2895824a1566SKashyap Desai  * @facts_data: Cached IOC facts data
2896824a1566SKashyap Desai  *
2897824a1566SKashyap Desai  * Issue IOC Facts MPI request through admin queue and wait for
2898824a1566SKashyap Desai  * the completion of it or time out.
2899824a1566SKashyap Desai  *
2900824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
2901824a1566SKashyap Desai  */
mpi3mr_issue_iocfacts(struct mpi3mr_ioc * mrioc,struct mpi3_ioc_facts_data * facts_data)2902824a1566SKashyap Desai static int mpi3mr_issue_iocfacts(struct mpi3mr_ioc *mrioc,
2903824a1566SKashyap Desai 	struct mpi3_ioc_facts_data *facts_data)
2904824a1566SKashyap Desai {
2905824a1566SKashyap Desai 	struct mpi3_ioc_facts_request iocfacts_req;
2906824a1566SKashyap Desai 	void *data = NULL;
2907824a1566SKashyap Desai 	dma_addr_t data_dma;
2908824a1566SKashyap Desai 	u32 data_len = sizeof(*facts_data);
2909824a1566SKashyap Desai 	int retval = 0;
2910824a1566SKashyap Desai 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
2911824a1566SKashyap Desai 
2912824a1566SKashyap Desai 	data = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma,
2913824a1566SKashyap Desai 	    GFP_KERNEL);
2914824a1566SKashyap Desai 
2915824a1566SKashyap Desai 	if (!data) {
2916824a1566SKashyap Desai 		retval = -1;
2917824a1566SKashyap Desai 		goto out;
2918824a1566SKashyap Desai 	}
2919824a1566SKashyap Desai 
2920824a1566SKashyap Desai 	memset(&iocfacts_req, 0, sizeof(iocfacts_req));
2921824a1566SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
2922824a1566SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
2923824a1566SKashyap Desai 		retval = -1;
2924824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCFacts: Init command is in use\n");
2925824a1566SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
2926824a1566SKashyap Desai 		goto out;
2927824a1566SKashyap Desai 	}
2928824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
2929824a1566SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
2930824a1566SKashyap Desai 	mrioc->init_cmds.callback = NULL;
2931824a1566SKashyap Desai 	iocfacts_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
2932824a1566SKashyap Desai 	iocfacts_req.function = MPI3_FUNCTION_IOC_FACTS;
2933824a1566SKashyap Desai 
2934824a1566SKashyap Desai 	mpi3mr_add_sg_single(&iocfacts_req.sgl, sgl_flags, data_len,
2935824a1566SKashyap Desai 	    data_dma);
2936824a1566SKashyap Desai 
2937824a1566SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
2938824a1566SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &iocfacts_req,
2939824a1566SKashyap Desai 	    sizeof(iocfacts_req), 1);
2940824a1566SKashyap Desai 	if (retval) {
2941824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCFacts: Admin Post failed\n");
2942824a1566SKashyap Desai 		goto out_unlock;
2943824a1566SKashyap Desai 	}
2944824a1566SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
2945824a1566SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
2946824a1566SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
2947a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "ioc_facts timed out\n");
2948a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
2949824a1566SKashyap Desai 		    MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT);
2950824a1566SKashyap Desai 		retval = -1;
2951824a1566SKashyap Desai 		goto out_unlock;
2952824a1566SKashyap Desai 	}
2953824a1566SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
2954824a1566SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
2955824a1566SKashyap Desai 		ioc_err(mrioc,
2956824a1566SKashyap Desai 		    "Issue IOCFacts: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
2957824a1566SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
2958824a1566SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
2959824a1566SKashyap Desai 		retval = -1;
2960824a1566SKashyap Desai 		goto out_unlock;
2961824a1566SKashyap Desai 	}
2962824a1566SKashyap Desai 	memcpy(facts_data, (u8 *)data, data_len);
2963c5758fc7SSreekanth Reddy 	mpi3mr_process_factsdata(mrioc, facts_data);
2964824a1566SKashyap Desai out_unlock:
2965824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
2966824a1566SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
2967824a1566SKashyap Desai 
2968824a1566SKashyap Desai out:
2969824a1566SKashyap Desai 	if (data)
2970824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, data_len, data, data_dma);
2971824a1566SKashyap Desai 
2972824a1566SKashyap Desai 	return retval;
2973824a1566SKashyap Desai }
2974824a1566SKashyap Desai 
2975824a1566SKashyap Desai /**
2976824a1566SKashyap Desai  * mpi3mr_check_reset_dma_mask - Process IOC facts data
2977824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2978824a1566SKashyap Desai  *
2979824a1566SKashyap Desai  * Check whether the new DMA mask requested through IOCFacts by
2980824a1566SKashyap Desai  * firmware needs to be set, if so set it .
2981824a1566SKashyap Desai  *
2982824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
2983824a1566SKashyap Desai  */
mpi3mr_check_reset_dma_mask(struct mpi3mr_ioc * mrioc)2984824a1566SKashyap Desai static inline int mpi3mr_check_reset_dma_mask(struct mpi3mr_ioc *mrioc)
2985824a1566SKashyap Desai {
2986824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
2987824a1566SKashyap Desai 	int r;
2988824a1566SKashyap Desai 	u64 facts_dma_mask = DMA_BIT_MASK(mrioc->facts.dma_mask);
2989824a1566SKashyap Desai 
2990824a1566SKashyap Desai 	if (!mrioc->facts.dma_mask || (mrioc->dma_mask <= facts_dma_mask))
2991824a1566SKashyap Desai 		return 0;
2992824a1566SKashyap Desai 
2993824a1566SKashyap Desai 	ioc_info(mrioc, "Changing DMA mask from 0x%016llx to 0x%016llx\n",
2994824a1566SKashyap Desai 	    mrioc->dma_mask, facts_dma_mask);
2995824a1566SKashyap Desai 
2996824a1566SKashyap Desai 	r = dma_set_mask_and_coherent(&pdev->dev, facts_dma_mask);
2997824a1566SKashyap Desai 	if (r) {
2998824a1566SKashyap Desai 		ioc_err(mrioc, "Setting DMA mask to 0x%016llx failed: %d\n",
2999824a1566SKashyap Desai 		    facts_dma_mask, r);
3000824a1566SKashyap Desai 		return r;
3001824a1566SKashyap Desai 	}
3002824a1566SKashyap Desai 	mrioc->dma_mask = facts_dma_mask;
3003824a1566SKashyap Desai 	return r;
3004824a1566SKashyap Desai }
3005824a1566SKashyap Desai 
3006824a1566SKashyap Desai /**
3007824a1566SKashyap Desai  * mpi3mr_process_factsdata - Process IOC facts data
3008824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3009824a1566SKashyap Desai  * @facts_data: Cached IOC facts data
3010824a1566SKashyap Desai  *
3011824a1566SKashyap Desai  * Convert IOC facts data into cpu endianness and cache it in
3012824a1566SKashyap Desai  * the driver .
3013824a1566SKashyap Desai  *
3014824a1566SKashyap Desai  * Return: Nothing.
3015824a1566SKashyap Desai  */
mpi3mr_process_factsdata(struct mpi3mr_ioc * mrioc,struct mpi3_ioc_facts_data * facts_data)3016824a1566SKashyap Desai static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc,
3017824a1566SKashyap Desai 	struct mpi3_ioc_facts_data *facts_data)
3018824a1566SKashyap Desai {
3019824a1566SKashyap Desai 	u32 ioc_config, req_sz, facts_flags;
3020824a1566SKashyap Desai 
3021824a1566SKashyap Desai 	if ((le16_to_cpu(facts_data->ioc_facts_data_length)) !=
3022824a1566SKashyap Desai 	    (sizeof(*facts_data) / 4)) {
3023824a1566SKashyap Desai 		ioc_warn(mrioc,
3024824a1566SKashyap Desai 		    "IOCFactsdata length mismatch driver_sz(%zu) firmware_sz(%d)\n",
3025824a1566SKashyap Desai 		    sizeof(*facts_data),
3026824a1566SKashyap Desai 		    le16_to_cpu(facts_data->ioc_facts_data_length) * 4);
3027824a1566SKashyap Desai 	}
3028824a1566SKashyap Desai 
3029824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
3030824a1566SKashyap Desai 	req_sz = 1 << ((ioc_config & MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ) >>
3031824a1566SKashyap Desai 	    MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ_SHIFT);
3032824a1566SKashyap Desai 	if (le16_to_cpu(facts_data->ioc_request_frame_size) != (req_sz / 4)) {
3033824a1566SKashyap Desai 		ioc_err(mrioc,
3034824a1566SKashyap Desai 		    "IOCFacts data reqFrameSize mismatch hw_size(%d) firmware_sz(%d)\n",
3035824a1566SKashyap Desai 		    req_sz / 4, le16_to_cpu(facts_data->ioc_request_frame_size));
3036824a1566SKashyap Desai 	}
3037824a1566SKashyap Desai 
3038824a1566SKashyap Desai 	memset(&mrioc->facts, 0, sizeof(mrioc->facts));
3039824a1566SKashyap Desai 
3040824a1566SKashyap Desai 	facts_flags = le32_to_cpu(facts_data->flags);
3041824a1566SKashyap Desai 	mrioc->facts.op_req_sz = req_sz;
3042824a1566SKashyap Desai 	mrioc->op_reply_desc_sz = 1 << ((ioc_config &
3043824a1566SKashyap Desai 	    MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ) >>
3044824a1566SKashyap Desai 	    MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ_SHIFT);
3045824a1566SKashyap Desai 
3046824a1566SKashyap Desai 	mrioc->facts.ioc_num = facts_data->ioc_number;
3047824a1566SKashyap Desai 	mrioc->facts.who_init = facts_data->who_init;
3048824a1566SKashyap Desai 	mrioc->facts.max_msix_vectors = le16_to_cpu(facts_data->max_msix_vectors);
3049824a1566SKashyap Desai 	mrioc->facts.personality = (facts_flags &
3050824a1566SKashyap Desai 	    MPI3_IOCFACTS_FLAGS_PERSONALITY_MASK);
3051824a1566SKashyap Desai 	mrioc->facts.dma_mask = (facts_flags &
3052824a1566SKashyap Desai 	    MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >>
3053824a1566SKashyap Desai 	    MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT;
3054824a1566SKashyap Desai 	mrioc->facts.protocol_flags = facts_data->protocol_flags;
3055824a1566SKashyap Desai 	mrioc->facts.mpi_version = le32_to_cpu(facts_data->mpi_version.word);
305604b27e53SSreekanth Reddy 	mrioc->facts.max_reqs = le16_to_cpu(facts_data->max_outstanding_requests);
3057824a1566SKashyap Desai 	mrioc->facts.product_id = le16_to_cpu(facts_data->product_id);
3058824a1566SKashyap Desai 	mrioc->facts.reply_sz = le16_to_cpu(facts_data->reply_frame_size) * 4;
3059824a1566SKashyap Desai 	mrioc->facts.exceptions = le16_to_cpu(facts_data->ioc_exceptions);
3060824a1566SKashyap Desai 	mrioc->facts.max_perids = le16_to_cpu(facts_data->max_persistent_id);
3061824a1566SKashyap Desai 	mrioc->facts.max_vds = le16_to_cpu(facts_data->max_vds);
3062824a1566SKashyap Desai 	mrioc->facts.max_hpds = le16_to_cpu(facts_data->max_host_pds);
3063ec5ebd2cSSreekanth Reddy 	mrioc->facts.max_advhpds = le16_to_cpu(facts_data->max_adv_host_pds);
3064ec5ebd2cSSreekanth Reddy 	mrioc->facts.max_raid_pds = le16_to_cpu(facts_data->max_raid_pds);
3065824a1566SKashyap Desai 	mrioc->facts.max_nvme = le16_to_cpu(facts_data->max_nvme);
3066824a1566SKashyap Desai 	mrioc->facts.max_pcie_switches =
3067ec5ebd2cSSreekanth Reddy 	    le16_to_cpu(facts_data->max_pcie_switches);
3068824a1566SKashyap Desai 	mrioc->facts.max_sasexpanders =
3069824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_sas_expanders);
3070d9adb81eSRanjan Kumar 	mrioc->facts.max_data_length = le16_to_cpu(facts_data->max_data_length);
3071824a1566SKashyap Desai 	mrioc->facts.max_sasinitiators =
3072824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_sas_initiators);
3073824a1566SKashyap Desai 	mrioc->facts.max_enclosures = le16_to_cpu(facts_data->max_enclosures);
3074824a1566SKashyap Desai 	mrioc->facts.min_devhandle = le16_to_cpu(facts_data->min_dev_handle);
3075824a1566SKashyap Desai 	mrioc->facts.max_devhandle = le16_to_cpu(facts_data->max_dev_handle);
3076824a1566SKashyap Desai 	mrioc->facts.max_op_req_q =
3077824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_operational_request_queues);
3078824a1566SKashyap Desai 	mrioc->facts.max_op_reply_q =
3079824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_operational_reply_queues);
3080824a1566SKashyap Desai 	mrioc->facts.ioc_capabilities =
3081824a1566SKashyap Desai 	    le32_to_cpu(facts_data->ioc_capabilities);
3082824a1566SKashyap Desai 	mrioc->facts.fw_ver.build_num =
3083824a1566SKashyap Desai 	    le16_to_cpu(facts_data->fw_version.build_num);
3084824a1566SKashyap Desai 	mrioc->facts.fw_ver.cust_id =
3085824a1566SKashyap Desai 	    le16_to_cpu(facts_data->fw_version.customer_id);
3086824a1566SKashyap Desai 	mrioc->facts.fw_ver.ph_minor = facts_data->fw_version.phase_minor;
3087824a1566SKashyap Desai 	mrioc->facts.fw_ver.ph_major = facts_data->fw_version.phase_major;
3088824a1566SKashyap Desai 	mrioc->facts.fw_ver.gen_minor = facts_data->fw_version.gen_minor;
3089824a1566SKashyap Desai 	mrioc->facts.fw_ver.gen_major = facts_data->fw_version.gen_major;
3090824a1566SKashyap Desai 	mrioc->msix_count = min_t(int, mrioc->msix_count,
3091824a1566SKashyap Desai 	    mrioc->facts.max_msix_vectors);
3092824a1566SKashyap Desai 	mrioc->facts.sge_mod_mask = facts_data->sge_modifier_mask;
3093824a1566SKashyap Desai 	mrioc->facts.sge_mod_value = facts_data->sge_modifier_value;
3094824a1566SKashyap Desai 	mrioc->facts.sge_mod_shift = facts_data->sge_modifier_shift;
3095824a1566SKashyap Desai 	mrioc->facts.shutdown_timeout =
3096824a1566SKashyap Desai 	    le16_to_cpu(facts_data->shutdown_timeout);
3097fc444494SRanjan Kumar 	mrioc->facts.diag_trace_sz =
3098fc444494SRanjan Kumar 	    le32_to_cpu(facts_data->diag_trace_size);
3099fc444494SRanjan Kumar 	mrioc->facts.diag_fw_sz =
3100fc444494SRanjan Kumar 	    le32_to_cpu(facts_data->diag_fw_size);
3101fc444494SRanjan Kumar 	mrioc->facts.diag_drvr_sz = le32_to_cpu(facts_data->diag_driver_size);
3102f10af057SSreekanth Reddy 	mrioc->facts.max_dev_per_tg =
3103f10af057SSreekanth Reddy 	    facts_data->max_devices_per_throttle_group;
3104f10af057SSreekanth Reddy 	mrioc->facts.io_throttle_data_length =
3105f10af057SSreekanth Reddy 	    le16_to_cpu(facts_data->io_throttle_data_length);
3106f10af057SSreekanth Reddy 	mrioc->facts.max_io_throttle_group =
3107f10af057SSreekanth Reddy 	    le16_to_cpu(facts_data->max_io_throttle_group);
3108f10af057SSreekanth Reddy 	mrioc->facts.io_throttle_low = le16_to_cpu(facts_data->io_throttle_low);
3109f10af057SSreekanth Reddy 	mrioc->facts.io_throttle_high =
3110f10af057SSreekanth Reddy 	    le16_to_cpu(facts_data->io_throttle_high);
3111f10af057SSreekanth Reddy 
3112d9adb81eSRanjan Kumar 	if (mrioc->facts.max_data_length ==
3113d9adb81eSRanjan Kumar 	    MPI3_IOCFACTS_MAX_DATA_LENGTH_NOT_REPORTED)
3114d9adb81eSRanjan Kumar 		mrioc->facts.max_data_length = MPI3MR_DEFAULT_MAX_IO_SIZE;
3115d9adb81eSRanjan Kumar 	else
3116d9adb81eSRanjan Kumar 		mrioc->facts.max_data_length *= MPI3MR_PAGE_SIZE_4K;
3117f10af057SSreekanth Reddy 	/* Store in 512b block count */
3118f10af057SSreekanth Reddy 	if (mrioc->facts.io_throttle_data_length)
3119f10af057SSreekanth Reddy 		mrioc->io_throttle_data_length =
3120f10af057SSreekanth Reddy 		    (mrioc->facts.io_throttle_data_length * 2 * 4);
3121f10af057SSreekanth Reddy 	else
3122f10af057SSreekanth Reddy 		/* set the length to 1MB + 1K to disable throttle */
3123d9adb81eSRanjan Kumar 		mrioc->io_throttle_data_length = (mrioc->facts.max_data_length / 512) + 2;
3124f10af057SSreekanth Reddy 
3125f10af057SSreekanth Reddy 	mrioc->io_throttle_high = (mrioc->facts.io_throttle_high * 2 * 1024);
3126f10af057SSreekanth Reddy 	mrioc->io_throttle_low = (mrioc->facts.io_throttle_low * 2 * 1024);
3127f10af057SSreekanth Reddy 
3128824a1566SKashyap Desai 	ioc_info(mrioc, "ioc_num(%d), maxopQ(%d), maxopRepQ(%d), maxdh(%d),",
3129824a1566SKashyap Desai 	    mrioc->facts.ioc_num, mrioc->facts.max_op_req_q,
3130824a1566SKashyap Desai 	    mrioc->facts.max_op_reply_q, mrioc->facts.max_devhandle);
3131824a1566SKashyap Desai 	ioc_info(mrioc,
3132ec5ebd2cSSreekanth Reddy 	    "maxreqs(%d), mindh(%d) maxvectors(%d) maxperids(%d)\n",
3133824a1566SKashyap Desai 	    mrioc->facts.max_reqs, mrioc->facts.min_devhandle,
3134ec5ebd2cSSreekanth Reddy 	    mrioc->facts.max_msix_vectors, mrioc->facts.max_perids);
3135824a1566SKashyap Desai 	ioc_info(mrioc, "SGEModMask 0x%x SGEModVal 0x%x SGEModShift 0x%x ",
3136824a1566SKashyap Desai 	    mrioc->facts.sge_mod_mask, mrioc->facts.sge_mod_value,
3137824a1566SKashyap Desai 	    mrioc->facts.sge_mod_shift);
3138d9adb81eSRanjan Kumar 	ioc_info(mrioc, "DMA mask %d InitialPE status 0x%x max_data_len (%d)\n",
3139824a1566SKashyap Desai 	    mrioc->facts.dma_mask, (facts_flags &
3140d9adb81eSRanjan Kumar 	    MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK), mrioc->facts.max_data_length);
3141f10af057SSreekanth Reddy 	ioc_info(mrioc,
3142f10af057SSreekanth Reddy 	    "max_dev_per_throttle_group(%d), max_throttle_groups(%d)\n",
3143f10af057SSreekanth Reddy 	    mrioc->facts.max_dev_per_tg, mrioc->facts.max_io_throttle_group);
3144f10af057SSreekanth Reddy 	ioc_info(mrioc,
3145f10af057SSreekanth Reddy 	   "io_throttle_data_len(%dKiB), io_throttle_high(%dMiB), io_throttle_low(%dMiB)\n",
3146f10af057SSreekanth Reddy 	   mrioc->facts.io_throttle_data_length * 4,
3147f10af057SSreekanth Reddy 	   mrioc->facts.io_throttle_high, mrioc->facts.io_throttle_low);
3148824a1566SKashyap Desai }
3149824a1566SKashyap Desai 
3150824a1566SKashyap Desai /**
3151824a1566SKashyap Desai  * mpi3mr_alloc_reply_sense_bufs - Send IOC Init
3152824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3153824a1566SKashyap Desai  *
3154824a1566SKashyap Desai  * Allocate and initialize the reply free buffers, sense
3155824a1566SKashyap Desai  * buffers, reply free queue and sense buffer queue.
3156824a1566SKashyap Desai  *
3157824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
3158824a1566SKashyap Desai  */
mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc * mrioc)3159824a1566SKashyap Desai static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc)
3160824a1566SKashyap Desai {
3161824a1566SKashyap Desai 	int retval = 0;
3162824a1566SKashyap Desai 	u32 sz, i;
3163824a1566SKashyap Desai 
3164824a1566SKashyap Desai 	if (mrioc->init_cmds.reply)
3165e3605f65SSreekanth Reddy 		return retval;
3166824a1566SKashyap Desai 
3167c5758fc7SSreekanth Reddy 	mrioc->init_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL);
3168824a1566SKashyap Desai 	if (!mrioc->init_cmds.reply)
3169824a1566SKashyap Desai 		goto out_failed;
3170824a1566SKashyap Desai 
3171f5e6d5a3SSumit Saxena 	mrioc->bsg_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL);
3172f5e6d5a3SSumit Saxena 	if (!mrioc->bsg_cmds.reply)
3173f5e6d5a3SSumit Saxena 		goto out_failed;
3174f5e6d5a3SSumit Saxena 
31752bd37e28SSreekanth Reddy 	mrioc->transport_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL);
31762bd37e28SSreekanth Reddy 	if (!mrioc->transport_cmds.reply)
31772bd37e28SSreekanth Reddy 		goto out_failed;
31782bd37e28SSreekanth Reddy 
317913ef29eaSKashyap Desai 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
3180c5758fc7SSreekanth Reddy 		mrioc->dev_rmhs_cmds[i].reply = kzalloc(mrioc->reply_sz,
318113ef29eaSKashyap Desai 		    GFP_KERNEL);
318213ef29eaSKashyap Desai 		if (!mrioc->dev_rmhs_cmds[i].reply)
318313ef29eaSKashyap Desai 			goto out_failed;
318413ef29eaSKashyap Desai 	}
318513ef29eaSKashyap Desai 
3186c1af985dSSreekanth Reddy 	for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) {
3187c1af985dSSreekanth Reddy 		mrioc->evtack_cmds[i].reply = kzalloc(mrioc->reply_sz,
3188c1af985dSSreekanth Reddy 		    GFP_KERNEL);
3189c1af985dSSreekanth Reddy 		if (!mrioc->evtack_cmds[i].reply)
3190c1af985dSSreekanth Reddy 			goto out_failed;
3191c1af985dSSreekanth Reddy 	}
3192c1af985dSSreekanth Reddy 
3193c5758fc7SSreekanth Reddy 	mrioc->host_tm_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL);
3194e844adb1SKashyap Desai 	if (!mrioc->host_tm_cmds.reply)
3195e844adb1SKashyap Desai 		goto out_failed;
3196e844adb1SKashyap Desai 
319743ca1100SSumit Saxena 	mrioc->pel_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL);
319843ca1100SSumit Saxena 	if (!mrioc->pel_cmds.reply)
319943ca1100SSumit Saxena 		goto out_failed;
320043ca1100SSumit Saxena 
320143ca1100SSumit Saxena 	mrioc->pel_abort_cmd.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL);
320243ca1100SSumit Saxena 	if (!mrioc->pel_abort_cmd.reply)
320343ca1100SSumit Saxena 		goto out_failed;
320443ca1100SSumit Saxena 
3205339e6156SShin'ichiro Kawasaki 	mrioc->dev_handle_bitmap_bits = mrioc->facts.max_devhandle;
3206339e6156SShin'ichiro Kawasaki 	mrioc->removepend_bitmap = bitmap_zalloc(mrioc->dev_handle_bitmap_bits,
3207e844adb1SKashyap Desai 						 GFP_KERNEL);
3208e844adb1SKashyap Desai 	if (!mrioc->removepend_bitmap)
3209e844adb1SKashyap Desai 		goto out_failed;
3210e844adb1SKashyap Desai 
3211339e6156SShin'ichiro Kawasaki 	mrioc->devrem_bitmap = bitmap_zalloc(MPI3MR_NUM_DEVRMCMD, GFP_KERNEL);
3212e844adb1SKashyap Desai 	if (!mrioc->devrem_bitmap)
3213e844adb1SKashyap Desai 		goto out_failed;
3214e844adb1SKashyap Desai 
3215339e6156SShin'ichiro Kawasaki 	mrioc->evtack_cmds_bitmap = bitmap_zalloc(MPI3MR_NUM_EVTACKCMD,
3216c1af985dSSreekanth Reddy 						  GFP_KERNEL);
3217c1af985dSSreekanth Reddy 	if (!mrioc->evtack_cmds_bitmap)
3218c1af985dSSreekanth Reddy 		goto out_failed;
3219c1af985dSSreekanth Reddy 
3220824a1566SKashyap Desai 	mrioc->num_reply_bufs = mrioc->facts.max_reqs + MPI3MR_NUM_EVT_REPLIES;
3221824a1566SKashyap Desai 	mrioc->reply_free_qsz = mrioc->num_reply_bufs + 1;
3222824a1566SKashyap Desai 	mrioc->num_sense_bufs = mrioc->facts.max_reqs / MPI3MR_SENSEBUF_FACTOR;
3223824a1566SKashyap Desai 	mrioc->sense_buf_q_sz = mrioc->num_sense_bufs + 1;
3224824a1566SKashyap Desai 
3225824a1566SKashyap Desai 	/* reply buffer pool, 16 byte align */
3226c5758fc7SSreekanth Reddy 	sz = mrioc->num_reply_bufs * mrioc->reply_sz;
3227824a1566SKashyap Desai 	mrioc->reply_buf_pool = dma_pool_create("reply_buf pool",
3228824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 16, 0);
3229824a1566SKashyap Desai 	if (!mrioc->reply_buf_pool) {
3230824a1566SKashyap Desai 		ioc_err(mrioc, "reply buf pool: dma_pool_create failed\n");
3231824a1566SKashyap Desai 		goto out_failed;
3232824a1566SKashyap Desai 	}
3233824a1566SKashyap Desai 
3234824a1566SKashyap Desai 	mrioc->reply_buf = dma_pool_zalloc(mrioc->reply_buf_pool, GFP_KERNEL,
3235824a1566SKashyap Desai 	    &mrioc->reply_buf_dma);
3236824a1566SKashyap Desai 	if (!mrioc->reply_buf)
3237824a1566SKashyap Desai 		goto out_failed;
3238824a1566SKashyap Desai 
3239824a1566SKashyap Desai 	mrioc->reply_buf_dma_max_address = mrioc->reply_buf_dma + sz;
3240824a1566SKashyap Desai 
3241824a1566SKashyap Desai 	/* reply free queue, 8 byte align */
3242824a1566SKashyap Desai 	sz = mrioc->reply_free_qsz * 8;
3243824a1566SKashyap Desai 	mrioc->reply_free_q_pool = dma_pool_create("reply_free_q pool",
3244824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 8, 0);
3245824a1566SKashyap Desai 	if (!mrioc->reply_free_q_pool) {
3246824a1566SKashyap Desai 		ioc_err(mrioc, "reply_free_q pool: dma_pool_create failed\n");
3247824a1566SKashyap Desai 		goto out_failed;
3248824a1566SKashyap Desai 	}
3249824a1566SKashyap Desai 	mrioc->reply_free_q = dma_pool_zalloc(mrioc->reply_free_q_pool,
3250824a1566SKashyap Desai 	    GFP_KERNEL, &mrioc->reply_free_q_dma);
3251824a1566SKashyap Desai 	if (!mrioc->reply_free_q)
3252824a1566SKashyap Desai 		goto out_failed;
3253824a1566SKashyap Desai 
3254824a1566SKashyap Desai 	/* sense buffer pool,  4 byte align */
3255ec5ebd2cSSreekanth Reddy 	sz = mrioc->num_sense_bufs * MPI3MR_SENSE_BUF_SZ;
3256824a1566SKashyap Desai 	mrioc->sense_buf_pool = dma_pool_create("sense_buf pool",
3257824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 4, 0);
3258824a1566SKashyap Desai 	if (!mrioc->sense_buf_pool) {
3259824a1566SKashyap Desai 		ioc_err(mrioc, "sense_buf pool: dma_pool_create failed\n");
3260824a1566SKashyap Desai 		goto out_failed;
3261824a1566SKashyap Desai 	}
3262824a1566SKashyap Desai 	mrioc->sense_buf = dma_pool_zalloc(mrioc->sense_buf_pool, GFP_KERNEL,
3263824a1566SKashyap Desai 	    &mrioc->sense_buf_dma);
3264824a1566SKashyap Desai 	if (!mrioc->sense_buf)
3265824a1566SKashyap Desai 		goto out_failed;
3266824a1566SKashyap Desai 
3267824a1566SKashyap Desai 	/* sense buffer queue, 8 byte align */
3268824a1566SKashyap Desai 	sz = mrioc->sense_buf_q_sz * 8;
3269824a1566SKashyap Desai 	mrioc->sense_buf_q_pool = dma_pool_create("sense_buf_q pool",
3270824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 8, 0);
3271824a1566SKashyap Desai 	if (!mrioc->sense_buf_q_pool) {
3272824a1566SKashyap Desai 		ioc_err(mrioc, "sense_buf_q pool: dma_pool_create failed\n");
3273824a1566SKashyap Desai 		goto out_failed;
3274824a1566SKashyap Desai 	}
3275824a1566SKashyap Desai 	mrioc->sense_buf_q = dma_pool_zalloc(mrioc->sense_buf_q_pool,
3276824a1566SKashyap Desai 	    GFP_KERNEL, &mrioc->sense_buf_q_dma);
3277824a1566SKashyap Desai 	if (!mrioc->sense_buf_q)
3278824a1566SKashyap Desai 		goto out_failed;
3279824a1566SKashyap Desai 
3280e3605f65SSreekanth Reddy 	return retval;
3281e3605f65SSreekanth Reddy 
3282e3605f65SSreekanth Reddy out_failed:
3283e3605f65SSreekanth Reddy 	retval = -1;
3284e3605f65SSreekanth Reddy 	return retval;
3285e3605f65SSreekanth Reddy }
3286e3605f65SSreekanth Reddy 
3287e3605f65SSreekanth Reddy /**
3288e3605f65SSreekanth Reddy  * mpimr_initialize_reply_sbuf_queues - initialize reply sense
3289e3605f65SSreekanth Reddy  * buffers
3290e3605f65SSreekanth Reddy  * @mrioc: Adapter instance reference
3291e3605f65SSreekanth Reddy  *
3292e3605f65SSreekanth Reddy  * Helper function to initialize reply and sense buffers along
3293e3605f65SSreekanth Reddy  * with some debug prints.
3294e3605f65SSreekanth Reddy  *
3295e3605f65SSreekanth Reddy  * Return:  None.
3296e3605f65SSreekanth Reddy  */
mpimr_initialize_reply_sbuf_queues(struct mpi3mr_ioc * mrioc)3297e3605f65SSreekanth Reddy static void mpimr_initialize_reply_sbuf_queues(struct mpi3mr_ioc *mrioc)
3298e3605f65SSreekanth Reddy {
3299e3605f65SSreekanth Reddy 	u32 sz, i;
3300e3605f65SSreekanth Reddy 	dma_addr_t phy_addr;
3301e3605f65SSreekanth Reddy 
3302c5758fc7SSreekanth Reddy 	sz = mrioc->num_reply_bufs * mrioc->reply_sz;
3303824a1566SKashyap Desai 	ioc_info(mrioc,
3304824a1566SKashyap Desai 	    "reply buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n",
3305c5758fc7SSreekanth Reddy 	    mrioc->reply_buf, mrioc->num_reply_bufs, mrioc->reply_sz,
3306824a1566SKashyap Desai 	    (sz / 1024), (unsigned long long)mrioc->reply_buf_dma);
3307824a1566SKashyap Desai 	sz = mrioc->reply_free_qsz * 8;
3308824a1566SKashyap Desai 	ioc_info(mrioc,
3309824a1566SKashyap Desai 	    "reply_free_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n",
3310824a1566SKashyap Desai 	    mrioc->reply_free_q, mrioc->reply_free_qsz, 8, (sz / 1024),
3311824a1566SKashyap Desai 	    (unsigned long long)mrioc->reply_free_q_dma);
3312ec5ebd2cSSreekanth Reddy 	sz = mrioc->num_sense_bufs * MPI3MR_SENSE_BUF_SZ;
3313824a1566SKashyap Desai 	ioc_info(mrioc,
3314824a1566SKashyap Desai 	    "sense_buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n",
3315ec5ebd2cSSreekanth Reddy 	    mrioc->sense_buf, mrioc->num_sense_bufs, MPI3MR_SENSE_BUF_SZ,
3316824a1566SKashyap Desai 	    (sz / 1024), (unsigned long long)mrioc->sense_buf_dma);
3317824a1566SKashyap Desai 	sz = mrioc->sense_buf_q_sz * 8;
3318824a1566SKashyap Desai 	ioc_info(mrioc,
3319824a1566SKashyap Desai 	    "sense_buf_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n",
3320824a1566SKashyap Desai 	    mrioc->sense_buf_q, mrioc->sense_buf_q_sz, 8, (sz / 1024),
3321824a1566SKashyap Desai 	    (unsigned long long)mrioc->sense_buf_q_dma);
3322824a1566SKashyap Desai 
3323824a1566SKashyap Desai 	/* initialize Reply buffer Queue */
3324824a1566SKashyap Desai 	for (i = 0, phy_addr = mrioc->reply_buf_dma;
3325c5758fc7SSreekanth Reddy 	    i < mrioc->num_reply_bufs; i++, phy_addr += mrioc->reply_sz)
3326824a1566SKashyap Desai 		mrioc->reply_free_q[i] = cpu_to_le64(phy_addr);
3327824a1566SKashyap Desai 	mrioc->reply_free_q[i] = cpu_to_le64(0);
3328824a1566SKashyap Desai 
3329824a1566SKashyap Desai 	/* initialize Sense Buffer Queue */
3330824a1566SKashyap Desai 	for (i = 0, phy_addr = mrioc->sense_buf_dma;
3331ec5ebd2cSSreekanth Reddy 	    i < mrioc->num_sense_bufs; i++, phy_addr += MPI3MR_SENSE_BUF_SZ)
3332824a1566SKashyap Desai 		mrioc->sense_buf_q[i] = cpu_to_le64(phy_addr);
3333824a1566SKashyap Desai 	mrioc->sense_buf_q[i] = cpu_to_le64(0);
3334824a1566SKashyap Desai }
3335824a1566SKashyap Desai 
3336824a1566SKashyap Desai /**
3337824a1566SKashyap Desai  * mpi3mr_issue_iocinit - Send IOC Init
3338824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3339824a1566SKashyap Desai  *
3340824a1566SKashyap Desai  * Issue IOC Init MPI request through admin queue and wait for
3341824a1566SKashyap Desai  * the completion of it or time out.
3342824a1566SKashyap Desai  *
3343824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
3344824a1566SKashyap Desai  */
mpi3mr_issue_iocinit(struct mpi3mr_ioc * mrioc)3345824a1566SKashyap Desai static int mpi3mr_issue_iocinit(struct mpi3mr_ioc *mrioc)
3346824a1566SKashyap Desai {
3347824a1566SKashyap Desai 	struct mpi3_ioc_init_request iocinit_req;
3348824a1566SKashyap Desai 	struct mpi3_driver_info_layout *drv_info;
3349824a1566SKashyap Desai 	dma_addr_t data_dma;
3350824a1566SKashyap Desai 	u32 data_len = sizeof(*drv_info);
3351824a1566SKashyap Desai 	int retval = 0;
3352824a1566SKashyap Desai 	ktime_t current_time;
3353824a1566SKashyap Desai 
3354824a1566SKashyap Desai 	drv_info = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma,
3355824a1566SKashyap Desai 	    GFP_KERNEL);
3356824a1566SKashyap Desai 	if (!drv_info) {
3357824a1566SKashyap Desai 		retval = -1;
3358824a1566SKashyap Desai 		goto out;
3359824a1566SKashyap Desai 	}
3360e3605f65SSreekanth Reddy 	mpimr_initialize_reply_sbuf_queues(mrioc);
3361e3605f65SSreekanth Reddy 
3362824a1566SKashyap Desai 	drv_info->information_length = cpu_to_le32(data_len);
3363aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->driver_signature, "Broadcom", sizeof(drv_info->driver_signature));
3364aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->os_name, utsname()->sysname, sizeof(drv_info->os_name));
3365aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->os_version, utsname()->release, sizeof(drv_info->os_version));
3366aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->driver_name, MPI3MR_DRIVER_NAME, sizeof(drv_info->driver_name));
3367aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->driver_version, MPI3MR_DRIVER_VERSION, sizeof(drv_info->driver_version));
3368aa0dc6a7SSreekanth Reddy 	strscpy(drv_info->driver_release_date, MPI3MR_DRIVER_RELDATE,
3369aa0dc6a7SSreekanth Reddy 	    sizeof(drv_info->driver_release_date));
3370824a1566SKashyap Desai 	drv_info->driver_capabilities = 0;
3371824a1566SKashyap Desai 	memcpy((u8 *)&mrioc->driver_info, (u8 *)drv_info,
3372824a1566SKashyap Desai 	    sizeof(mrioc->driver_info));
3373824a1566SKashyap Desai 
3374824a1566SKashyap Desai 	memset(&iocinit_req, 0, sizeof(iocinit_req));
3375824a1566SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
3376824a1566SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
3377824a1566SKashyap Desai 		retval = -1;
3378824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCInit: Init command is in use\n");
3379824a1566SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
3380824a1566SKashyap Desai 		goto out;
3381824a1566SKashyap Desai 	}
3382824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
3383824a1566SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
3384824a1566SKashyap Desai 	mrioc->init_cmds.callback = NULL;
3385824a1566SKashyap Desai 	iocinit_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
3386824a1566SKashyap Desai 	iocinit_req.function = MPI3_FUNCTION_IOC_INIT;
3387824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.dev = MPI3_VERSION_DEV;
3388824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.unit = MPI3_VERSION_UNIT;
3389824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.major = MPI3_VERSION_MAJOR;
3390824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.minor = MPI3_VERSION_MINOR;
3391824a1566SKashyap Desai 	iocinit_req.who_init = MPI3_WHOINIT_HOST_DRIVER;
3392824a1566SKashyap Desai 	iocinit_req.reply_free_queue_depth = cpu_to_le16(mrioc->reply_free_qsz);
3393824a1566SKashyap Desai 	iocinit_req.reply_free_queue_address =
3394824a1566SKashyap Desai 	    cpu_to_le64(mrioc->reply_free_q_dma);
3395ec5ebd2cSSreekanth Reddy 	iocinit_req.sense_buffer_length = cpu_to_le16(MPI3MR_SENSE_BUF_SZ);
3396824a1566SKashyap Desai 	iocinit_req.sense_buffer_free_queue_depth =
3397824a1566SKashyap Desai 	    cpu_to_le16(mrioc->sense_buf_q_sz);
3398824a1566SKashyap Desai 	iocinit_req.sense_buffer_free_queue_address =
3399824a1566SKashyap Desai 	    cpu_to_le64(mrioc->sense_buf_q_dma);
3400824a1566SKashyap Desai 	iocinit_req.driver_information_address = cpu_to_le64(data_dma);
3401824a1566SKashyap Desai 
3402824a1566SKashyap Desai 	current_time = ktime_get_real();
3403824a1566SKashyap Desai 	iocinit_req.time_stamp = cpu_to_le64(ktime_to_ms(current_time));
3404824a1566SKashyap Desai 
34051193a89dSSumit Saxena 	iocinit_req.msg_flags |=
34061193a89dSSumit Saxena 	    MPI3_IOCINIT_MSGFLAGS_SCSIIOSTATUSREPLY_SUPPORTED;
3407e8a5a3c3SRanjan Kumar 	iocinit_req.msg_flags |=
3408e8a5a3c3SRanjan Kumar 		MPI3_IOCINIT_MSGFLAGS_WRITESAMEDIVERT_SUPPORTED;
34091193a89dSSumit Saxena 
3410824a1566SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
3411824a1566SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &iocinit_req,
3412824a1566SKashyap Desai 	    sizeof(iocinit_req), 1);
3413824a1566SKashyap Desai 	if (retval) {
3414824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCInit: Admin Post failed\n");
3415824a1566SKashyap Desai 		goto out_unlock;
3416824a1566SKashyap Desai 	}
3417824a1566SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
3418824a1566SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
3419824a1566SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
3420a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
3421824a1566SKashyap Desai 		    MPI3MR_RESET_FROM_IOCINIT_TIMEOUT);
3422a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "ioc_init timed out\n");
3423824a1566SKashyap Desai 		retval = -1;
3424824a1566SKashyap Desai 		goto out_unlock;
3425824a1566SKashyap Desai 	}
3426824a1566SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
3427824a1566SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
3428824a1566SKashyap Desai 		ioc_err(mrioc,
3429824a1566SKashyap Desai 		    "Issue IOCInit: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
3430824a1566SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
3431824a1566SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
3432824a1566SKashyap Desai 		retval = -1;
3433824a1566SKashyap Desai 		goto out_unlock;
3434824a1566SKashyap Desai 	}
3435824a1566SKashyap Desai 
3436e3605f65SSreekanth Reddy 	mrioc->reply_free_queue_host_index = mrioc->num_reply_bufs;
3437e3605f65SSreekanth Reddy 	writel(mrioc->reply_free_queue_host_index,
3438e3605f65SSreekanth Reddy 	    &mrioc->sysif_regs->reply_free_host_index);
3439e3605f65SSreekanth Reddy 
3440e3605f65SSreekanth Reddy 	mrioc->sbq_host_index = mrioc->num_sense_bufs;
3441e3605f65SSreekanth Reddy 	writel(mrioc->sbq_host_index,
3442e3605f65SSreekanth Reddy 	    &mrioc->sysif_regs->sense_buffer_free_host_index);
3443824a1566SKashyap Desai out_unlock:
3444824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
3445824a1566SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
3446824a1566SKashyap Desai 
3447824a1566SKashyap Desai out:
3448824a1566SKashyap Desai 	if (drv_info)
3449824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, data_len, drv_info,
3450824a1566SKashyap Desai 		    data_dma);
3451824a1566SKashyap Desai 
3452824a1566SKashyap Desai 	return retval;
3453824a1566SKashyap Desai }
3454824a1566SKashyap Desai 
3455824a1566SKashyap Desai /**
345613ef29eaSKashyap Desai  * mpi3mr_unmask_events - Unmask events in event mask bitmap
345713ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
345813ef29eaSKashyap Desai  * @event: MPI event ID
345913ef29eaSKashyap Desai  *
346013ef29eaSKashyap Desai  * Un mask the specific event by resetting the event_mask
346113ef29eaSKashyap Desai  * bitmap.
346213ef29eaSKashyap Desai  *
346313ef29eaSKashyap Desai  * Return: 0 on success, non-zero on failures.
346413ef29eaSKashyap Desai  */
mpi3mr_unmask_events(struct mpi3mr_ioc * mrioc,u16 event)346513ef29eaSKashyap Desai static void mpi3mr_unmask_events(struct mpi3mr_ioc *mrioc, u16 event)
346613ef29eaSKashyap Desai {
346713ef29eaSKashyap Desai 	u32 desired_event;
346813ef29eaSKashyap Desai 	u8 word;
346913ef29eaSKashyap Desai 
347013ef29eaSKashyap Desai 	if (event >= 128)
347113ef29eaSKashyap Desai 		return;
347213ef29eaSKashyap Desai 
347313ef29eaSKashyap Desai 	desired_event = (1 << (event % 32));
347413ef29eaSKashyap Desai 	word = event / 32;
347513ef29eaSKashyap Desai 
347613ef29eaSKashyap Desai 	mrioc->event_masks[word] &= ~desired_event;
347713ef29eaSKashyap Desai }
347813ef29eaSKashyap Desai 
347913ef29eaSKashyap Desai /**
348013ef29eaSKashyap Desai  * mpi3mr_issue_event_notification - Send event notification
348113ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
348213ef29eaSKashyap Desai  *
348313ef29eaSKashyap Desai  * Issue event notification MPI request through admin queue and
348413ef29eaSKashyap Desai  * wait for the completion of it or time out.
348513ef29eaSKashyap Desai  *
348613ef29eaSKashyap Desai  * Return: 0 on success, non-zero on failures.
348713ef29eaSKashyap Desai  */
mpi3mr_issue_event_notification(struct mpi3mr_ioc * mrioc)348813ef29eaSKashyap Desai static int mpi3mr_issue_event_notification(struct mpi3mr_ioc *mrioc)
348913ef29eaSKashyap Desai {
349013ef29eaSKashyap Desai 	struct mpi3_event_notification_request evtnotify_req;
349113ef29eaSKashyap Desai 	int retval = 0;
349213ef29eaSKashyap Desai 	u8 i;
349313ef29eaSKashyap Desai 
349413ef29eaSKashyap Desai 	memset(&evtnotify_req, 0, sizeof(evtnotify_req));
349513ef29eaSKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
349613ef29eaSKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
349713ef29eaSKashyap Desai 		retval = -1;
349813ef29eaSKashyap Desai 		ioc_err(mrioc, "Issue EvtNotify: Init command is in use\n");
349913ef29eaSKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
350013ef29eaSKashyap Desai 		goto out;
350113ef29eaSKashyap Desai 	}
350213ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
350313ef29eaSKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
350413ef29eaSKashyap Desai 	mrioc->init_cmds.callback = NULL;
350513ef29eaSKashyap Desai 	evtnotify_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
350613ef29eaSKashyap Desai 	evtnotify_req.function = MPI3_FUNCTION_EVENT_NOTIFICATION;
350713ef29eaSKashyap Desai 	for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
350813ef29eaSKashyap Desai 		evtnotify_req.event_masks[i] =
350913ef29eaSKashyap Desai 		    cpu_to_le32(mrioc->event_masks[i]);
351013ef29eaSKashyap Desai 	init_completion(&mrioc->init_cmds.done);
351113ef29eaSKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &evtnotify_req,
351213ef29eaSKashyap Desai 	    sizeof(evtnotify_req), 1);
351313ef29eaSKashyap Desai 	if (retval) {
351413ef29eaSKashyap Desai 		ioc_err(mrioc, "Issue EvtNotify: Admin Post failed\n");
351513ef29eaSKashyap Desai 		goto out_unlock;
351613ef29eaSKashyap Desai 	}
351713ef29eaSKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
351813ef29eaSKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
351913ef29eaSKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
3520a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "event notification timed out\n");
3521a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
352213ef29eaSKashyap Desai 		    MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT);
352313ef29eaSKashyap Desai 		retval = -1;
352413ef29eaSKashyap Desai 		goto out_unlock;
352513ef29eaSKashyap Desai 	}
352613ef29eaSKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
352713ef29eaSKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
352813ef29eaSKashyap Desai 		ioc_err(mrioc,
352913ef29eaSKashyap Desai 		    "Issue EvtNotify: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
353013ef29eaSKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
353113ef29eaSKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
353213ef29eaSKashyap Desai 		retval = -1;
353313ef29eaSKashyap Desai 		goto out_unlock;
353413ef29eaSKashyap Desai 	}
353513ef29eaSKashyap Desai 
353613ef29eaSKashyap Desai out_unlock:
353713ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
353813ef29eaSKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
353913ef29eaSKashyap Desai out:
354013ef29eaSKashyap Desai 	return retval;
354113ef29eaSKashyap Desai }
354213ef29eaSKashyap Desai 
354313ef29eaSKashyap Desai /**
3544c1af985dSSreekanth Reddy  * mpi3mr_process_event_ack - Process event acknowledgment
354513ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
354613ef29eaSKashyap Desai  * @event: MPI3 event ID
3547c1af985dSSreekanth Reddy  * @event_ctx: event context
354813ef29eaSKashyap Desai  *
354913ef29eaSKashyap Desai  * Send event acknowledgment through admin queue and wait for
355013ef29eaSKashyap Desai  * it to complete.
355113ef29eaSKashyap Desai  *
355213ef29eaSKashyap Desai  * Return: 0 on success, non-zero on failures.
355313ef29eaSKashyap Desai  */
mpi3mr_process_event_ack(struct mpi3mr_ioc * mrioc,u8 event,u32 event_ctx)3554c1af985dSSreekanth Reddy int mpi3mr_process_event_ack(struct mpi3mr_ioc *mrioc, u8 event,
355513ef29eaSKashyap Desai 	u32 event_ctx)
355613ef29eaSKashyap Desai {
355713ef29eaSKashyap Desai 	struct mpi3_event_ack_request evtack_req;
355813ef29eaSKashyap Desai 	int retval = 0;
355913ef29eaSKashyap Desai 
356013ef29eaSKashyap Desai 	memset(&evtack_req, 0, sizeof(evtack_req));
356113ef29eaSKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
356213ef29eaSKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
356313ef29eaSKashyap Desai 		retval = -1;
356413ef29eaSKashyap Desai 		ioc_err(mrioc, "Send EvtAck: Init command is in use\n");
356513ef29eaSKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
356613ef29eaSKashyap Desai 		goto out;
356713ef29eaSKashyap Desai 	}
356813ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
356913ef29eaSKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
357013ef29eaSKashyap Desai 	mrioc->init_cmds.callback = NULL;
357113ef29eaSKashyap Desai 	evtack_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
357213ef29eaSKashyap Desai 	evtack_req.function = MPI3_FUNCTION_EVENT_ACK;
357313ef29eaSKashyap Desai 	evtack_req.event = event;
357413ef29eaSKashyap Desai 	evtack_req.event_context = cpu_to_le32(event_ctx);
357513ef29eaSKashyap Desai 
357613ef29eaSKashyap Desai 	init_completion(&mrioc->init_cmds.done);
357713ef29eaSKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &evtack_req,
357813ef29eaSKashyap Desai 	    sizeof(evtack_req), 1);
357913ef29eaSKashyap Desai 	if (retval) {
358013ef29eaSKashyap Desai 		ioc_err(mrioc, "Send EvtAck: Admin Post failed\n");
358113ef29eaSKashyap Desai 		goto out_unlock;
358213ef29eaSKashyap Desai 	}
358313ef29eaSKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
358413ef29eaSKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
358513ef29eaSKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
358613ef29eaSKashyap Desai 		ioc_err(mrioc, "Issue EvtNotify: command timed out\n");
3587fbaa9aa4SSreekanth Reddy 		if (!(mrioc->init_cmds.state & MPI3MR_CMD_RESET))
35889134211fSRanjan Kumar 			mpi3mr_check_rh_fault_ioc(mrioc,
35899134211fSRanjan Kumar 			    MPI3MR_RESET_FROM_EVTACK_TIMEOUT);
359013ef29eaSKashyap Desai 		retval = -1;
359113ef29eaSKashyap Desai 		goto out_unlock;
359213ef29eaSKashyap Desai 	}
359313ef29eaSKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
359413ef29eaSKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
359513ef29eaSKashyap Desai 		ioc_err(mrioc,
359613ef29eaSKashyap Desai 		    "Send EvtAck: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
359713ef29eaSKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
359813ef29eaSKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
359913ef29eaSKashyap Desai 		retval = -1;
360013ef29eaSKashyap Desai 		goto out_unlock;
360113ef29eaSKashyap Desai 	}
360213ef29eaSKashyap Desai 
360313ef29eaSKashyap Desai out_unlock:
360413ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
360513ef29eaSKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
360613ef29eaSKashyap Desai out:
360713ef29eaSKashyap Desai 	return retval;
360813ef29eaSKashyap Desai }
360913ef29eaSKashyap Desai 
361013ef29eaSKashyap Desai /**
3611824a1566SKashyap Desai  * mpi3mr_alloc_chain_bufs - Allocate chain buffers
3612824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3613824a1566SKashyap Desai  *
3614824a1566SKashyap Desai  * Allocate chain buffers and set a bitmap to indicate free
3615824a1566SKashyap Desai  * chain buffers. Chain buffers are used to pass the SGE
3616824a1566SKashyap Desai  * information along with MPI3 SCSI IO requests for host I/O.
3617824a1566SKashyap Desai  *
3618824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure
3619824a1566SKashyap Desai  */
mpi3mr_alloc_chain_bufs(struct mpi3mr_ioc * mrioc)3620824a1566SKashyap Desai static int mpi3mr_alloc_chain_bufs(struct mpi3mr_ioc *mrioc)
3621824a1566SKashyap Desai {
3622824a1566SKashyap Desai 	int retval = 0;
3623824a1566SKashyap Desai 	u32 sz, i;
3624824a1566SKashyap Desai 	u16 num_chains;
3625824a1566SKashyap Desai 
3626fe6db615SSreekanth Reddy 	if (mrioc->chain_sgl_list)
3627fe6db615SSreekanth Reddy 		return retval;
3628fe6db615SSreekanth Reddy 
3629824a1566SKashyap Desai 	num_chains = mrioc->max_host_ios / MPI3MR_CHAINBUF_FACTOR;
3630824a1566SKashyap Desai 
363174e1f30aSKashyap Desai 	if (prot_mask & (SHOST_DIX_TYPE0_PROTECTION
363274e1f30aSKashyap Desai 	    | SHOST_DIX_TYPE1_PROTECTION
363374e1f30aSKashyap Desai 	    | SHOST_DIX_TYPE2_PROTECTION
363474e1f30aSKashyap Desai 	    | SHOST_DIX_TYPE3_PROTECTION))
363574e1f30aSKashyap Desai 		num_chains += (num_chains / MPI3MR_CHAINBUFDIX_FACTOR);
363674e1f30aSKashyap Desai 
3637824a1566SKashyap Desai 	mrioc->chain_buf_count = num_chains;
3638824a1566SKashyap Desai 	sz = sizeof(struct chain_element) * num_chains;
3639824a1566SKashyap Desai 	mrioc->chain_sgl_list = kzalloc(sz, GFP_KERNEL);
3640824a1566SKashyap Desai 	if (!mrioc->chain_sgl_list)
3641824a1566SKashyap Desai 		goto out_failed;
3642824a1566SKashyap Desai 
3643d9adb81eSRanjan Kumar 	if (mrioc->max_sgl_entries > (mrioc->facts.max_data_length /
3644d9adb81eSRanjan Kumar 		MPI3MR_PAGE_SIZE_4K))
3645d9adb81eSRanjan Kumar 		mrioc->max_sgl_entries = mrioc->facts.max_data_length /
3646d9adb81eSRanjan Kumar 			MPI3MR_PAGE_SIZE_4K;
3647d9adb81eSRanjan Kumar 	sz = mrioc->max_sgl_entries * sizeof(struct mpi3_sge_common);
3648d9adb81eSRanjan Kumar 	ioc_info(mrioc, "number of sgl entries=%d chain buffer size=%dKB\n",
3649d9adb81eSRanjan Kumar 			mrioc->max_sgl_entries, sz/1024);
3650d9adb81eSRanjan Kumar 
3651824a1566SKashyap Desai 	mrioc->chain_buf_pool = dma_pool_create("chain_buf pool",
3652824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 16, 0);
3653824a1566SKashyap Desai 	if (!mrioc->chain_buf_pool) {
3654824a1566SKashyap Desai 		ioc_err(mrioc, "chain buf pool: dma_pool_create failed\n");
3655824a1566SKashyap Desai 		goto out_failed;
3656824a1566SKashyap Desai 	}
3657824a1566SKashyap Desai 
3658824a1566SKashyap Desai 	for (i = 0; i < num_chains; i++) {
3659824a1566SKashyap Desai 		mrioc->chain_sgl_list[i].addr =
3660824a1566SKashyap Desai 		    dma_pool_zalloc(mrioc->chain_buf_pool, GFP_KERNEL,
3661824a1566SKashyap Desai 		    &mrioc->chain_sgl_list[i].dma_addr);
3662824a1566SKashyap Desai 
3663824a1566SKashyap Desai 		if (!mrioc->chain_sgl_list[i].addr)
3664824a1566SKashyap Desai 			goto out_failed;
3665824a1566SKashyap Desai 	}
3666339e6156SShin'ichiro Kawasaki 	mrioc->chain_bitmap = bitmap_zalloc(num_chains, GFP_KERNEL);
3667824a1566SKashyap Desai 	if (!mrioc->chain_bitmap)
3668824a1566SKashyap Desai 		goto out_failed;
3669824a1566SKashyap Desai 	return retval;
3670824a1566SKashyap Desai out_failed:
3671824a1566SKashyap Desai 	retval = -1;
3672824a1566SKashyap Desai 	return retval;
3673824a1566SKashyap Desai }
3674824a1566SKashyap Desai 
3675824a1566SKashyap Desai /**
3676023ab2a9SKashyap Desai  * mpi3mr_port_enable_complete - Mark port enable complete
3677023ab2a9SKashyap Desai  * @mrioc: Adapter instance reference
3678023ab2a9SKashyap Desai  * @drv_cmd: Internal command tracker
3679023ab2a9SKashyap Desai  *
3680023ab2a9SKashyap Desai  * Call back for asynchronous port enable request sets the
3681023ab2a9SKashyap Desai  * driver command to indicate port enable request is complete.
3682023ab2a9SKashyap Desai  *
3683023ab2a9SKashyap Desai  * Return: Nothing
3684023ab2a9SKashyap Desai  */
mpi3mr_port_enable_complete(struct mpi3mr_ioc * mrioc,struct mpi3mr_drv_cmd * drv_cmd)3685023ab2a9SKashyap Desai static void mpi3mr_port_enable_complete(struct mpi3mr_ioc *mrioc,
3686023ab2a9SKashyap Desai 	struct mpi3mr_drv_cmd *drv_cmd)
3687023ab2a9SKashyap Desai {
3688023ab2a9SKashyap Desai 	drv_cmd->callback = NULL;
3689023ab2a9SKashyap Desai 	mrioc->scan_started = 0;
3690f2a79d20SSreekanth Reddy 	if (drv_cmd->state & MPI3MR_CMD_RESET)
3691f2a79d20SSreekanth Reddy 		mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR;
3692f2a79d20SSreekanth Reddy 	else
3693f2a79d20SSreekanth Reddy 		mrioc->scan_failed = drv_cmd->ioc_status;
3694f2a79d20SSreekanth Reddy 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
3695023ab2a9SKashyap Desai }
3696023ab2a9SKashyap Desai 
3697023ab2a9SKashyap Desai /**
3698023ab2a9SKashyap Desai  * mpi3mr_issue_port_enable - Issue Port Enable
3699023ab2a9SKashyap Desai  * @mrioc: Adapter instance reference
3700023ab2a9SKashyap Desai  * @async: Flag to wait for completion or not
3701023ab2a9SKashyap Desai  *
3702023ab2a9SKashyap Desai  * Issue Port Enable MPI request through admin queue and if the
3703023ab2a9SKashyap Desai  * async flag is not set wait for the completion of the port
3704023ab2a9SKashyap Desai  * enable or time out.
3705023ab2a9SKashyap Desai  *
3706023ab2a9SKashyap Desai  * Return: 0 on success, non-zero on failures.
3707023ab2a9SKashyap Desai  */
mpi3mr_issue_port_enable(struct mpi3mr_ioc * mrioc,u8 async)3708023ab2a9SKashyap Desai int mpi3mr_issue_port_enable(struct mpi3mr_ioc *mrioc, u8 async)
3709023ab2a9SKashyap Desai {
3710023ab2a9SKashyap Desai 	struct mpi3_port_enable_request pe_req;
3711023ab2a9SKashyap Desai 	int retval = 0;
3712023ab2a9SKashyap Desai 	u32 pe_timeout = MPI3MR_PORTENABLE_TIMEOUT;
3713023ab2a9SKashyap Desai 
3714023ab2a9SKashyap Desai 	memset(&pe_req, 0, sizeof(pe_req));
3715023ab2a9SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
3716023ab2a9SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
3717023ab2a9SKashyap Desai 		retval = -1;
3718023ab2a9SKashyap Desai 		ioc_err(mrioc, "Issue PortEnable: Init command is in use\n");
3719023ab2a9SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
3720023ab2a9SKashyap Desai 		goto out;
3721023ab2a9SKashyap Desai 	}
3722023ab2a9SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
3723023ab2a9SKashyap Desai 	if (async) {
3724023ab2a9SKashyap Desai 		mrioc->init_cmds.is_waiting = 0;
3725023ab2a9SKashyap Desai 		mrioc->init_cmds.callback = mpi3mr_port_enable_complete;
3726023ab2a9SKashyap Desai 	} else {
3727023ab2a9SKashyap Desai 		mrioc->init_cmds.is_waiting = 1;
3728023ab2a9SKashyap Desai 		mrioc->init_cmds.callback = NULL;
3729023ab2a9SKashyap Desai 		init_completion(&mrioc->init_cmds.done);
3730023ab2a9SKashyap Desai 	}
3731023ab2a9SKashyap Desai 	pe_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
3732023ab2a9SKashyap Desai 	pe_req.function = MPI3_FUNCTION_PORT_ENABLE;
3733023ab2a9SKashyap Desai 
3734023ab2a9SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &pe_req, sizeof(pe_req), 1);
3735023ab2a9SKashyap Desai 	if (retval) {
3736023ab2a9SKashyap Desai 		ioc_err(mrioc, "Issue PortEnable: Admin Post failed\n");
3737023ab2a9SKashyap Desai 		goto out_unlock;
3738023ab2a9SKashyap Desai 	}
3739a6856cc4SSreekanth Reddy 	if (async) {
3740a6856cc4SSreekanth Reddy 		mutex_unlock(&mrioc->init_cmds.mutex);
3741a6856cc4SSreekanth Reddy 		goto out;
3742a6856cc4SSreekanth Reddy 	}
3743a6856cc4SSreekanth Reddy 
3744a6856cc4SSreekanth Reddy 	wait_for_completion_timeout(&mrioc->init_cmds.done, (pe_timeout * HZ));
3745023ab2a9SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
3746a6856cc4SSreekanth Reddy 		ioc_err(mrioc, "port enable timed out\n");
3747023ab2a9SKashyap Desai 		retval = -1;
3748a6856cc4SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc, MPI3MR_RESET_FROM_PE_TIMEOUT);
3749023ab2a9SKashyap Desai 		goto out_unlock;
3750023ab2a9SKashyap Desai 	}
3751023ab2a9SKashyap Desai 	mpi3mr_port_enable_complete(mrioc, &mrioc->init_cmds);
3752a6856cc4SSreekanth Reddy 
3753023ab2a9SKashyap Desai out_unlock:
3754a6856cc4SSreekanth Reddy 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
3755023ab2a9SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
3756023ab2a9SKashyap Desai out:
3757023ab2a9SKashyap Desai 	return retval;
3758023ab2a9SKashyap Desai }
3759023ab2a9SKashyap Desai 
3760ff9561e9SKashyap Desai /* Protocol type to name mapper structure */
3761ff9561e9SKashyap Desai static const struct {
3762ff9561e9SKashyap Desai 	u8 protocol;
3763ff9561e9SKashyap Desai 	char *name;
3764ff9561e9SKashyap Desai } mpi3mr_protocols[] = {
3765ff9561e9SKashyap Desai 	{ MPI3_IOCFACTS_PROTOCOL_SCSI_INITIATOR, "Initiator" },
3766ff9561e9SKashyap Desai 	{ MPI3_IOCFACTS_PROTOCOL_SCSI_TARGET, "Target" },
3767ff9561e9SKashyap Desai 	{ MPI3_IOCFACTS_PROTOCOL_NVME, "NVMe attachment" },
3768ff9561e9SKashyap Desai };
3769ff9561e9SKashyap Desai 
3770ff9561e9SKashyap Desai /* Capability to name mapper structure*/
3771ff9561e9SKashyap Desai static const struct {
3772ff9561e9SKashyap Desai 	u32 capability;
3773ff9561e9SKashyap Desai 	char *name;
3774ff9561e9SKashyap Desai } mpi3mr_capabilities[] = {
377557a80be5SRanjan Kumar 	{ MPI3_IOCFACTS_CAPABILITY_RAID_SUPPORTED, "RAID" },
377657a80be5SRanjan Kumar 	{ MPI3_IOCFACTS_CAPABILITY_MULTIPATH_SUPPORTED, "MultiPath" },
3777ff9561e9SKashyap Desai };
3778ff9561e9SKashyap Desai 
3779ff9561e9SKashyap Desai /**
3780fc444494SRanjan Kumar  * mpi3mr_repost_diag_bufs - repost host diag buffers
3781fc444494SRanjan Kumar  * @mrioc: Adapter instance reference
3782fc444494SRanjan Kumar  *
3783fc444494SRanjan Kumar  * repost firmware and trace diag buffers based on global
3784fc444494SRanjan Kumar  * trigger flag from driver page 2
3785fc444494SRanjan Kumar  *
3786fc444494SRanjan Kumar  * Return: 0 on success, non-zero on failures.
3787fc444494SRanjan Kumar  */
mpi3mr_repost_diag_bufs(struct mpi3mr_ioc * mrioc)3788fc444494SRanjan Kumar static int mpi3mr_repost_diag_bufs(struct mpi3mr_ioc *mrioc)
3789fc444494SRanjan Kumar {
3790fc444494SRanjan Kumar 	u64 global_trigger;
3791fc444494SRanjan Kumar 	union mpi3mr_trigger_data prev_trigger_data;
3792fc444494SRanjan Kumar 	struct diag_buffer_desc *trace_hdb = NULL;
3793fc444494SRanjan Kumar 	struct diag_buffer_desc *fw_hdb = NULL;
3794fc444494SRanjan Kumar 	int retval = 0;
3795fc444494SRanjan Kumar 	bool trace_repost_needed = false;
3796fc444494SRanjan Kumar 	bool fw_repost_needed = false;
3797fc444494SRanjan Kumar 	u8 prev_trigger_type;
3798fc444494SRanjan Kumar 
3799fc444494SRanjan Kumar 	retval = mpi3mr_refresh_trigger(mrioc, MPI3_CONFIG_ACTION_READ_CURRENT);
3800fc444494SRanjan Kumar 	if (retval)
3801fc444494SRanjan Kumar 		return -1;
3802fc444494SRanjan Kumar 
3803fc444494SRanjan Kumar 	trace_hdb = mpi3mr_diag_buffer_for_type(mrioc,
3804fc444494SRanjan Kumar 	    MPI3_DIAG_BUFFER_TYPE_TRACE);
3805fc444494SRanjan Kumar 
3806fc444494SRanjan Kumar 	if (trace_hdb &&
3807fc444494SRanjan Kumar 	    trace_hdb->status != MPI3MR_HDB_BUFSTATUS_NOT_ALLOCATED &&
3808fc444494SRanjan Kumar 	    trace_hdb->trigger_type != MPI3MR_HDB_TRIGGER_TYPE_GLOBAL &&
3809fc444494SRanjan Kumar 	    trace_hdb->trigger_type != MPI3MR_HDB_TRIGGER_TYPE_ELEMENT)
3810fc444494SRanjan Kumar 		trace_repost_needed = true;
3811fc444494SRanjan Kumar 
3812fc444494SRanjan Kumar 	fw_hdb = mpi3mr_diag_buffer_for_type(mrioc, MPI3_DIAG_BUFFER_TYPE_FW);
3813fc444494SRanjan Kumar 
3814fc444494SRanjan Kumar 	if (fw_hdb && fw_hdb->status != MPI3MR_HDB_BUFSTATUS_NOT_ALLOCATED &&
3815fc444494SRanjan Kumar 	    fw_hdb->trigger_type != MPI3MR_HDB_TRIGGER_TYPE_GLOBAL &&
3816fc444494SRanjan Kumar 	    fw_hdb->trigger_type != MPI3MR_HDB_TRIGGER_TYPE_ELEMENT)
3817fc444494SRanjan Kumar 		fw_repost_needed = true;
3818fc444494SRanjan Kumar 
3819fc444494SRanjan Kumar 	if (trace_repost_needed || fw_repost_needed) {
3820fc444494SRanjan Kumar 		global_trigger = le64_to_cpu(mrioc->driver_pg2->global_trigger);
3821fc444494SRanjan Kumar 		if (global_trigger &
3822fc444494SRanjan Kumar 		      MPI3_DRIVER2_GLOBALTRIGGER_POST_DIAG_TRACE_DISABLED)
3823fc444494SRanjan Kumar 			trace_repost_needed = false;
3824fc444494SRanjan Kumar 		if (global_trigger &
3825fc444494SRanjan Kumar 		     MPI3_DRIVER2_GLOBALTRIGGER_POST_DIAG_FW_DISABLED)
3826fc444494SRanjan Kumar 			fw_repost_needed = false;
3827fc444494SRanjan Kumar 	}
3828fc444494SRanjan Kumar 
3829fc444494SRanjan Kumar 	if (trace_repost_needed) {
3830fc444494SRanjan Kumar 		prev_trigger_type = trace_hdb->trigger_type;
3831fc444494SRanjan Kumar 		memcpy(&prev_trigger_data, &trace_hdb->trigger_data,
3832fc444494SRanjan Kumar 		    sizeof(trace_hdb->trigger_data));
3833fc444494SRanjan Kumar 		retval = mpi3mr_issue_diag_buf_post(mrioc, trace_hdb);
3834fc444494SRanjan Kumar 		if (!retval) {
3835fc444494SRanjan Kumar 			dprint_init(mrioc, "trace diag buffer reposted");
3836fc444494SRanjan Kumar 			mpi3mr_set_trigger_data_in_hdb(trace_hdb,
3837fc444494SRanjan Kumar 				    MPI3MR_HDB_TRIGGER_TYPE_UNKNOWN, NULL, 1);
3838fc444494SRanjan Kumar 		} else {
3839fc444494SRanjan Kumar 			trace_hdb->trigger_type = prev_trigger_type;
3840fc444494SRanjan Kumar 			memcpy(&trace_hdb->trigger_data, &prev_trigger_data,
3841fc444494SRanjan Kumar 			    sizeof(prev_trigger_data));
3842fc444494SRanjan Kumar 			ioc_err(mrioc, "trace diag buffer repost failed");
3843fc444494SRanjan Kumar 			return -1;
3844fc444494SRanjan Kumar 		}
3845fc444494SRanjan Kumar 	}
3846fc444494SRanjan Kumar 
3847fc444494SRanjan Kumar 	if (fw_repost_needed) {
3848fc444494SRanjan Kumar 		prev_trigger_type = fw_hdb->trigger_type;
3849fc444494SRanjan Kumar 		memcpy(&prev_trigger_data, &fw_hdb->trigger_data,
3850fc444494SRanjan Kumar 		    sizeof(fw_hdb->trigger_data));
3851fc444494SRanjan Kumar 		retval = mpi3mr_issue_diag_buf_post(mrioc, fw_hdb);
3852fc444494SRanjan Kumar 		if (!retval) {
3853fc444494SRanjan Kumar 			dprint_init(mrioc, "firmware diag buffer reposted");
3854fc444494SRanjan Kumar 			mpi3mr_set_trigger_data_in_hdb(fw_hdb,
3855fc444494SRanjan Kumar 				    MPI3MR_HDB_TRIGGER_TYPE_UNKNOWN, NULL, 1);
3856fc444494SRanjan Kumar 		} else {
3857fc444494SRanjan Kumar 			fw_hdb->trigger_type = prev_trigger_type;
3858fc444494SRanjan Kumar 			memcpy(&fw_hdb->trigger_data, &prev_trigger_data,
3859fc444494SRanjan Kumar 			    sizeof(prev_trigger_data));
3860fc444494SRanjan Kumar 			ioc_err(mrioc, "firmware diag buffer repost failed");
3861fc444494SRanjan Kumar 			return -1;
3862fc444494SRanjan Kumar 		}
3863fc444494SRanjan Kumar 	}
3864fc444494SRanjan Kumar 	return retval;
3865fc444494SRanjan Kumar }
3866fc444494SRanjan Kumar 
3867fc444494SRanjan Kumar /**
3868fc1ddda3SRanjan Kumar  * mpi3mr_read_tsu_interval - Update time stamp interval
3869fc1ddda3SRanjan Kumar  * @mrioc: Adapter instance reference
3870fc1ddda3SRanjan Kumar  *
3871fc1ddda3SRanjan Kumar  * Update time stamp interval if its defined in driver page 1,
3872fc1ddda3SRanjan Kumar  * otherwise use default value.
3873fc1ddda3SRanjan Kumar  *
3874fc1ddda3SRanjan Kumar  * Return: Nothing
3875fc1ddda3SRanjan Kumar  */
3876fc1ddda3SRanjan Kumar static void
mpi3mr_read_tsu_interval(struct mpi3mr_ioc * mrioc)3877fc1ddda3SRanjan Kumar mpi3mr_read_tsu_interval(struct mpi3mr_ioc *mrioc)
3878fc1ddda3SRanjan Kumar {
3879fc1ddda3SRanjan Kumar 	struct mpi3_driver_page1 driver_pg1;
3880fc1ddda3SRanjan Kumar 	u16 pg_sz = sizeof(driver_pg1);
3881fc1ddda3SRanjan Kumar 	int retval = 0;
3882fc1ddda3SRanjan Kumar 
3883fc1ddda3SRanjan Kumar 	mrioc->ts_update_interval = MPI3MR_TSUPDATE_INTERVAL;
3884fc1ddda3SRanjan Kumar 
3885fc1ddda3SRanjan Kumar 	retval = mpi3mr_cfg_get_driver_pg1(mrioc, &driver_pg1, pg_sz);
3886fc1ddda3SRanjan Kumar 	if (!retval && driver_pg1.time_stamp_update)
3887fc1ddda3SRanjan Kumar 		mrioc->ts_update_interval = (driver_pg1.time_stamp_update * 60);
3888fc1ddda3SRanjan Kumar }
3889fc1ddda3SRanjan Kumar 
3890fc1ddda3SRanjan Kumar /**
3891ff9561e9SKashyap Desai  * mpi3mr_print_ioc_info - Display controller information
3892ff9561e9SKashyap Desai  * @mrioc: Adapter instance reference
3893ff9561e9SKashyap Desai  *
38948c8e2422SJustin Stitt  * Display controller personality, capability, supported
3895ff9561e9SKashyap Desai  * protocols etc.
3896ff9561e9SKashyap Desai  *
3897ff9561e9SKashyap Desai  * Return: Nothing
3898ff9561e9SKashyap Desai  */
3899ff9561e9SKashyap Desai static void
mpi3mr_print_ioc_info(struct mpi3mr_ioc * mrioc)3900ff9561e9SKashyap Desai mpi3mr_print_ioc_info(struct mpi3mr_ioc *mrioc)
3901ff9561e9SKashyap Desai {
390276a4f7ccSDan Carpenter 	int i = 0, bytes_written = 0;
39038c8e2422SJustin Stitt 	const char *personality;
3904ff9561e9SKashyap Desai 	char protocol[50] = {0};
3905ff9561e9SKashyap Desai 	char capabilities[100] = {0};
3906ff9561e9SKashyap Desai 	struct mpi3mr_compimg_ver *fwver = &mrioc->facts.fw_ver;
3907ff9561e9SKashyap Desai 
3908ff9561e9SKashyap Desai 	switch (mrioc->facts.personality) {
3909ff9561e9SKashyap Desai 	case MPI3_IOCFACTS_FLAGS_PERSONALITY_EHBA:
39108c8e2422SJustin Stitt 		personality = "Enhanced HBA";
3911ff9561e9SKashyap Desai 		break;
3912ff9561e9SKashyap Desai 	case MPI3_IOCFACTS_FLAGS_PERSONALITY_RAID_DDR:
39138c8e2422SJustin Stitt 		personality = "RAID";
3914ff9561e9SKashyap Desai 		break;
3915ff9561e9SKashyap Desai 	default:
39168c8e2422SJustin Stitt 		personality = "Unknown";
3917ff9561e9SKashyap Desai 		break;
3918ff9561e9SKashyap Desai 	}
3919ff9561e9SKashyap Desai 
3920ff9561e9SKashyap Desai 	ioc_info(mrioc, "Running in %s Personality", personality);
3921ff9561e9SKashyap Desai 
3922ff9561e9SKashyap Desai 	ioc_info(mrioc, "FW version(%d.%d.%d.%d.%d.%d)\n",
3923ff9561e9SKashyap Desai 	    fwver->gen_major, fwver->gen_minor, fwver->ph_major,
3924ff9561e9SKashyap Desai 	    fwver->ph_minor, fwver->cust_id, fwver->build_num);
3925ff9561e9SKashyap Desai 
3926ff9561e9SKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mpi3mr_protocols); i++) {
3927ff9561e9SKashyap Desai 		if (mrioc->facts.protocol_flags &
3928ff9561e9SKashyap Desai 		    mpi3mr_protocols[i].protocol) {
392930e99f05SDan Carpenter 			bytes_written += scnprintf(protocol + bytes_written,
393076a4f7ccSDan Carpenter 				    sizeof(protocol) - bytes_written, "%s%s",
393176a4f7ccSDan Carpenter 				    bytes_written ? "," : "",
3932ff9561e9SKashyap Desai 				    mpi3mr_protocols[i].name);
3933ff9561e9SKashyap Desai 		}
3934ff9561e9SKashyap Desai 	}
3935ff9561e9SKashyap Desai 
393676a4f7ccSDan Carpenter 	bytes_written = 0;
3937ff9561e9SKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mpi3mr_capabilities); i++) {
3938ff9561e9SKashyap Desai 		if (mrioc->facts.protocol_flags &
3939ff9561e9SKashyap Desai 		    mpi3mr_capabilities[i].capability) {
394030e99f05SDan Carpenter 			bytes_written += scnprintf(capabilities + bytes_written,
394176a4f7ccSDan Carpenter 				    sizeof(capabilities) - bytes_written, "%s%s",
394276a4f7ccSDan Carpenter 				    bytes_written ? "," : "",
3943ff9561e9SKashyap Desai 				    mpi3mr_capabilities[i].name);
3944ff9561e9SKashyap Desai 		}
3945ff9561e9SKashyap Desai 	}
3946ff9561e9SKashyap Desai 
3947ff9561e9SKashyap Desai 	ioc_info(mrioc, "Protocol=(%s), Capabilities=(%s)\n",
3948ff9561e9SKashyap Desai 		 protocol, capabilities);
3949ff9561e9SKashyap Desai }
3950ff9561e9SKashyap Desai 
3951023ab2a9SKashyap Desai /**
3952824a1566SKashyap Desai  * mpi3mr_cleanup_resources - Free PCI resources
3953824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3954824a1566SKashyap Desai  *
3955824a1566SKashyap Desai  * Unmap PCI device memory and disable PCI device.
3956824a1566SKashyap Desai  *
3957824a1566SKashyap Desai  * Return: 0 on success and non-zero on failure.
3958824a1566SKashyap Desai  */
mpi3mr_cleanup_resources(struct mpi3mr_ioc * mrioc)3959824a1566SKashyap Desai void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc)
3960824a1566SKashyap Desai {
3961824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
3962824a1566SKashyap Desai 
3963824a1566SKashyap Desai 	mpi3mr_cleanup_isr(mrioc);
3964824a1566SKashyap Desai 
3965824a1566SKashyap Desai 	if (mrioc->sysif_regs) {
3966824a1566SKashyap Desai 		iounmap((void __iomem *)mrioc->sysif_regs);
3967824a1566SKashyap Desai 		mrioc->sysif_regs = NULL;
3968824a1566SKashyap Desai 	}
3969824a1566SKashyap Desai 
3970824a1566SKashyap Desai 	if (pci_is_enabled(pdev)) {
3971824a1566SKashyap Desai 		if (mrioc->bars)
3972824a1566SKashyap Desai 			pci_release_selected_regions(pdev, mrioc->bars);
3973824a1566SKashyap Desai 		pci_disable_device(pdev);
3974824a1566SKashyap Desai 	}
3975824a1566SKashyap Desai }
3976824a1566SKashyap Desai 
3977824a1566SKashyap Desai /**
3978824a1566SKashyap Desai  * mpi3mr_setup_resources - Enable PCI resources
3979824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3980824a1566SKashyap Desai  *
3981824a1566SKashyap Desai  * Enable PCI device memory, MSI-x registers and set DMA mask.
3982824a1566SKashyap Desai  *
3983824a1566SKashyap Desai  * Return: 0 on success and non-zero on failure.
3984824a1566SKashyap Desai  */
mpi3mr_setup_resources(struct mpi3mr_ioc * mrioc)3985824a1566SKashyap Desai int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc)
3986824a1566SKashyap Desai {
3987824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
3988824a1566SKashyap Desai 	u32 memap_sz = 0;
3989824a1566SKashyap Desai 	int i, retval = 0, capb = 0;
3990824a1566SKashyap Desai 	u16 message_control;
3991824a1566SKashyap Desai 	u64 dma_mask = mrioc->dma_mask ? mrioc->dma_mask :
3992d347a951SSreekanth Reddy 	    ((sizeof(dma_addr_t) > 4) ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32));
3993824a1566SKashyap Desai 
3994824a1566SKashyap Desai 	if (pci_enable_device_mem(pdev)) {
3995824a1566SKashyap Desai 		ioc_err(mrioc, "pci_enable_device_mem: failed\n");
3996824a1566SKashyap Desai 		retval = -ENODEV;
3997824a1566SKashyap Desai 		goto out_failed;
3998824a1566SKashyap Desai 	}
3999824a1566SKashyap Desai 
4000824a1566SKashyap Desai 	capb = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
4001824a1566SKashyap Desai 	if (!capb) {
4002824a1566SKashyap Desai 		ioc_err(mrioc, "Unable to find MSI-X Capabilities\n");
4003824a1566SKashyap Desai 		retval = -ENODEV;
4004824a1566SKashyap Desai 		goto out_failed;
4005824a1566SKashyap Desai 	}
4006824a1566SKashyap Desai 	mrioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
4007824a1566SKashyap Desai 
4008824a1566SKashyap Desai 	if (pci_request_selected_regions(pdev, mrioc->bars,
4009824a1566SKashyap Desai 	    mrioc->driver_name)) {
4010824a1566SKashyap Desai 		ioc_err(mrioc, "pci_request_selected_regions: failed\n");
4011824a1566SKashyap Desai 		retval = -ENODEV;
4012824a1566SKashyap Desai 		goto out_failed;
4013824a1566SKashyap Desai 	}
4014824a1566SKashyap Desai 
4015824a1566SKashyap Desai 	for (i = 0; (i < DEVICE_COUNT_RESOURCE); i++) {
4016824a1566SKashyap Desai 		if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
4017824a1566SKashyap Desai 			mrioc->sysif_regs_phys = pci_resource_start(pdev, i);
4018824a1566SKashyap Desai 			memap_sz = pci_resource_len(pdev, i);
4019824a1566SKashyap Desai 			mrioc->sysif_regs =
4020824a1566SKashyap Desai 			    ioremap(mrioc->sysif_regs_phys, memap_sz);
4021824a1566SKashyap Desai 			break;
4022824a1566SKashyap Desai 		}
4023824a1566SKashyap Desai 	}
4024824a1566SKashyap Desai 
4025824a1566SKashyap Desai 	pci_set_master(pdev);
4026824a1566SKashyap Desai 
4027824a1566SKashyap Desai 	retval = dma_set_mask_and_coherent(&pdev->dev, dma_mask);
4028824a1566SKashyap Desai 	if (retval) {
4029824a1566SKashyap Desai 		if (dma_mask != DMA_BIT_MASK(32)) {
4030824a1566SKashyap Desai 			ioc_warn(mrioc, "Setting 64 bit DMA mask failed\n");
4031824a1566SKashyap Desai 			dma_mask = DMA_BIT_MASK(32);
4032824a1566SKashyap Desai 			retval = dma_set_mask_and_coherent(&pdev->dev,
4033824a1566SKashyap Desai 			    dma_mask);
4034824a1566SKashyap Desai 		}
4035824a1566SKashyap Desai 		if (retval) {
4036824a1566SKashyap Desai 			mrioc->dma_mask = 0;
4037824a1566SKashyap Desai 			ioc_err(mrioc, "Setting 32 bit DMA mask also failed\n");
4038824a1566SKashyap Desai 			goto out_failed;
4039824a1566SKashyap Desai 		}
4040824a1566SKashyap Desai 	}
4041824a1566SKashyap Desai 	mrioc->dma_mask = dma_mask;
4042824a1566SKashyap Desai 
4043824a1566SKashyap Desai 	if (!mrioc->sysif_regs) {
4044824a1566SKashyap Desai 		ioc_err(mrioc,
4045824a1566SKashyap Desai 		    "Unable to map adapter memory or resource not found\n");
4046824a1566SKashyap Desai 		retval = -EINVAL;
4047824a1566SKashyap Desai 		goto out_failed;
4048824a1566SKashyap Desai 	}
4049824a1566SKashyap Desai 
4050824a1566SKashyap Desai 	pci_read_config_word(pdev, capb + 2, &message_control);
4051824a1566SKashyap Desai 	mrioc->msix_count = (message_control & 0x3FF) + 1;
4052824a1566SKashyap Desai 
4053824a1566SKashyap Desai 	pci_save_state(pdev);
4054824a1566SKashyap Desai 
4055824a1566SKashyap Desai 	pci_set_drvdata(pdev, mrioc->shost);
4056824a1566SKashyap Desai 
4057824a1566SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
4058824a1566SKashyap Desai 
4059824a1566SKashyap Desai 	ioc_info(mrioc, "iomem(0x%016llx), mapped(0x%p), size(%d)\n",
4060824a1566SKashyap Desai 	    (unsigned long long)mrioc->sysif_regs_phys,
4061824a1566SKashyap Desai 	    mrioc->sysif_regs, memap_sz);
4062824a1566SKashyap Desai 	ioc_info(mrioc, "Number of MSI-X vectors found in capabilities: (%d)\n",
4063824a1566SKashyap Desai 	    mrioc->msix_count);
4064afd3a579SSreekanth Reddy 
4065afd3a579SSreekanth Reddy 	if (!reset_devices && poll_queues > 0)
4066afd3a579SSreekanth Reddy 		mrioc->requested_poll_qcount = min_t(int, poll_queues,
4067afd3a579SSreekanth Reddy 				mrioc->msix_count - 2);
4068824a1566SKashyap Desai 	return retval;
4069824a1566SKashyap Desai 
4070824a1566SKashyap Desai out_failed:
4071824a1566SKashyap Desai 	mpi3mr_cleanup_resources(mrioc);
4072824a1566SKashyap Desai 	return retval;
4073824a1566SKashyap Desai }
4074824a1566SKashyap Desai 
4075824a1566SKashyap Desai /**
4076e3605f65SSreekanth Reddy  * mpi3mr_enable_events - Enable required events
4077e3605f65SSreekanth Reddy  * @mrioc: Adapter instance reference
4078e3605f65SSreekanth Reddy  *
4079e3605f65SSreekanth Reddy  * This routine unmasks the events required by the driver by
4080e3605f65SSreekanth Reddy  * sennding appropriate event mask bitmapt through an event
4081e3605f65SSreekanth Reddy  * notification request.
4082e3605f65SSreekanth Reddy  *
4083e3605f65SSreekanth Reddy  * Return: 0 on success and non-zero on failure.
4084e3605f65SSreekanth Reddy  */
mpi3mr_enable_events(struct mpi3mr_ioc * mrioc)4085e3605f65SSreekanth Reddy static int mpi3mr_enable_events(struct mpi3mr_ioc *mrioc)
4086e3605f65SSreekanth Reddy {
4087e3605f65SSreekanth Reddy 	int retval = 0;
4088e3605f65SSreekanth Reddy 	u32  i;
4089e3605f65SSreekanth Reddy 
4090e3605f65SSreekanth Reddy 	for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
4091e3605f65SSreekanth Reddy 		mrioc->event_masks[i] = -1;
4092e3605f65SSreekanth Reddy 
4093e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_ADDED);
4094e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_INFO_CHANGED);
4095e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_STATUS_CHANGE);
4096e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE);
40977188c03fSSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_ADDED);
4098e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
4099e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DISCOVERY);
4100e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR);
4101e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_BROADCAST_PRIMITIVE);
4102e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST);
4103e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_ENUMERATION);
410478b76a07SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_PREPARE_FOR_RESET);
4105e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_CABLE_MGMT);
4106e3605f65SSreekanth Reddy 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENERGY_PACK_CHANGE);
4107d8d08d16SRanjan Kumar 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DIAGNOSTIC_BUFFER_STATUS_CHANGE);
4108e3605f65SSreekanth Reddy 
4109e3605f65SSreekanth Reddy 	retval = mpi3mr_issue_event_notification(mrioc);
4110e3605f65SSreekanth Reddy 	if (retval)
4111e3605f65SSreekanth Reddy 		ioc_err(mrioc, "failed to issue event notification %d\n",
4112e3605f65SSreekanth Reddy 		    retval);
4113e3605f65SSreekanth Reddy 	return retval;
4114e3605f65SSreekanth Reddy }
4115e3605f65SSreekanth Reddy 
4116e3605f65SSreekanth Reddy /**
4117824a1566SKashyap Desai  * mpi3mr_init_ioc - Initialize the controller
4118824a1566SKashyap Desai  * @mrioc: Adapter instance reference
4119824a1566SKashyap Desai  *
4120824a1566SKashyap Desai  * This the controller initialization routine, executed either
4121824a1566SKashyap Desai  * after soft reset or from pci probe callback.
4122824a1566SKashyap Desai  * Setup the required resources, memory map the controller
4123824a1566SKashyap Desai  * registers, create admin and operational reply queue pairs,
4124824a1566SKashyap Desai  * allocate required memory for reply pool, sense buffer pool,
4125824a1566SKashyap Desai  * issue IOC init request to the firmware, unmask the events and
4126824a1566SKashyap Desai  * issue port enable to discover SAS/SATA/NVMe devies and RAID
4127824a1566SKashyap Desai  * volumes.
4128824a1566SKashyap Desai  *
4129824a1566SKashyap Desai  * Return: 0 on success and non-zero on failure.
4130824a1566SKashyap Desai  */
mpi3mr_init_ioc(struct mpi3mr_ioc * mrioc)4131fe6db615SSreekanth Reddy int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc)
4132824a1566SKashyap Desai {
4133824a1566SKashyap Desai 	int retval = 0;
4134fe6db615SSreekanth Reddy 	u8 retry = 0;
4135824a1566SKashyap Desai 	struct mpi3_ioc_facts_data facts_data;
4136f10af057SSreekanth Reddy 	u32 sz;
4137824a1566SKashyap Desai 
4138fe6db615SSreekanth Reddy retry_init:
4139824a1566SKashyap Desai 	retval = mpi3mr_bring_ioc_ready(mrioc);
4140824a1566SKashyap Desai 	if (retval) {
4141824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to bring ioc ready: error %d\n",
4142824a1566SKashyap Desai 		    retval);
4143fe6db615SSreekanth Reddy 		goto out_failed_noretry;
4144824a1566SKashyap Desai 	}
4145824a1566SKashyap Desai 
4146824a1566SKashyap Desai 	retval = mpi3mr_setup_isr(mrioc, 1);
4147824a1566SKashyap Desai 	if (retval) {
4148824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to setup ISR error %d\n",
4149824a1566SKashyap Desai 		    retval);
4150fe6db615SSreekanth Reddy 		goto out_failed_noretry;
4151824a1566SKashyap Desai 	}
4152824a1566SKashyap Desai 
4153824a1566SKashyap Desai 	retval = mpi3mr_issue_iocfacts(mrioc, &facts_data);
4154824a1566SKashyap Desai 	if (retval) {
4155824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to Issue IOC Facts %d\n",
4156824a1566SKashyap Desai 		    retval);
4157824a1566SKashyap Desai 		goto out_failed;
4158824a1566SKashyap Desai 	}
4159824a1566SKashyap Desai 
4160c5758fc7SSreekanth Reddy 	mrioc->max_host_ios = mrioc->facts.max_reqs - MPI3MR_INTERNAL_CMDS_RESVD;
4161d9adb81eSRanjan Kumar 	mrioc->shost->max_sectors = mrioc->facts.max_data_length / 512;
4162f10af057SSreekanth Reddy 	mrioc->num_io_throttle_group = mrioc->facts.max_io_throttle_group;
4163f10af057SSreekanth Reddy 	atomic_set(&mrioc->pend_large_data_sz, 0);
4164f10af057SSreekanth Reddy 
4165c5758fc7SSreekanth Reddy 	if (reset_devices)
4166c5758fc7SSreekanth Reddy 		mrioc->max_host_ios = min_t(int, mrioc->max_host_ios,
4167c5758fc7SSreekanth Reddy 		    MPI3MR_HOST_IOS_KDUMP);
4168c5758fc7SSreekanth Reddy 
4169c4723e68SSreekanth Reddy 	if (!(mrioc->facts.ioc_capabilities &
417057a80be5SRanjan Kumar 	    MPI3_IOCFACTS_CAPABILITY_MULTIPATH_SUPPORTED)) {
4171c4723e68SSreekanth Reddy 		mrioc->sas_transport_enabled = 1;
4172626665e9SSreekanth Reddy 		mrioc->scsi_device_channel = 1;
4173626665e9SSreekanth Reddy 		mrioc->shost->max_channel = 1;
4174176d4aa6SSreekanth Reddy 		mrioc->shost->transportt = mpi3mr_transport_template;
4175c4723e68SSreekanth Reddy 	}
4176c4723e68SSreekanth Reddy 
4177c5758fc7SSreekanth Reddy 	mrioc->reply_sz = mrioc->facts.reply_sz;
4178fe6db615SSreekanth Reddy 
4179824a1566SKashyap Desai 	retval = mpi3mr_check_reset_dma_mask(mrioc);
4180824a1566SKashyap Desai 	if (retval) {
4181824a1566SKashyap Desai 		ioc_err(mrioc, "Resetting dma mask failed %d\n",
4182824a1566SKashyap Desai 		    retval);
4183fe6db615SSreekanth Reddy 		goto out_failed_noretry;
4184fb9b0457SKashyap Desai 	}
4185824a1566SKashyap Desai 
4186fc1ddda3SRanjan Kumar 	mpi3mr_read_tsu_interval(mrioc);
4187ff9561e9SKashyap Desai 	mpi3mr_print_ioc_info(mrioc);
4188ff9561e9SKashyap Desai 
4189c7983044STomas Henzl 	if (!mrioc->cfg_page) {
419032d457d5SSreekanth Reddy 		dprint_init(mrioc, "allocating config page buffers\n");
4191c7983044STomas Henzl 		mrioc->cfg_page_sz = MPI3MR_DEFAULT_CFG_PAGE_SZ;
419232d457d5SSreekanth Reddy 		mrioc->cfg_page = dma_alloc_coherent(&mrioc->pdev->dev,
4193c7983044STomas Henzl 		    mrioc->cfg_page_sz, &mrioc->cfg_page_dma, GFP_KERNEL);
4194ba8a9ba4SRanjan Kumar 		if (!mrioc->cfg_page) {
4195ba8a9ba4SRanjan Kumar 			retval = -1;
419632d457d5SSreekanth Reddy 			goto out_failed_noretry;
4197ba8a9ba4SRanjan Kumar 		}
4198c7983044STomas Henzl 	}
419932d457d5SSreekanth Reddy 
4200fc444494SRanjan Kumar 	dprint_init(mrioc, "allocating host diag buffers\n");
4201fc444494SRanjan Kumar 	mpi3mr_alloc_diag_bufs(mrioc);
4202fc444494SRanjan Kumar 
4203c432e167SChandrakanth patil 	dprint_init(mrioc, "allocating ioctl dma buffers\n");
4204c432e167SChandrakanth patil 	mpi3mr_alloc_ioctl_dma_memory(mrioc);
4205c432e167SChandrakanth patil 
4206fc444494SRanjan Kumar 	dprint_init(mrioc, "posting host diag buffers\n");
4207fc444494SRanjan Kumar 	retval = mpi3mr_post_diag_bufs(mrioc);
4208fc444494SRanjan Kumar 
4209fc444494SRanjan Kumar 	if (retval)
4210fc444494SRanjan Kumar 		ioc_warn(mrioc, "failed to post host diag buffers\n");
4211fc444494SRanjan Kumar 
4212c7983044STomas Henzl 	if (!mrioc->init_cmds.reply) {
4213824a1566SKashyap Desai 		retval = mpi3mr_alloc_reply_sense_bufs(mrioc);
4214824a1566SKashyap Desai 		if (retval) {
4215824a1566SKashyap Desai 			ioc_err(mrioc,
4216824a1566SKashyap Desai 			    "%s :Failed to allocated reply sense buffers %d\n",
4217824a1566SKashyap Desai 			    __func__, retval);
4218fe6db615SSreekanth Reddy 			goto out_failed_noretry;
4219824a1566SKashyap Desai 		}
4220c7983044STomas Henzl 	}
4221824a1566SKashyap Desai 
4222c7983044STomas Henzl 	if (!mrioc->chain_sgl_list) {
4223824a1566SKashyap Desai 		retval = mpi3mr_alloc_chain_bufs(mrioc);
4224824a1566SKashyap Desai 		if (retval) {
4225824a1566SKashyap Desai 			ioc_err(mrioc, "Failed to allocated chain buffers %d\n",
4226824a1566SKashyap Desai 			    retval);
4227fe6db615SSreekanth Reddy 			goto out_failed_noretry;
4228fb9b0457SKashyap Desai 		}
4229c7983044STomas Henzl 	}
4230824a1566SKashyap Desai 
4231824a1566SKashyap Desai 	retval = mpi3mr_issue_iocinit(mrioc);
4232824a1566SKashyap Desai 	if (retval) {
4233824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to Issue IOC Init %d\n",
4234824a1566SKashyap Desai 		    retval);
4235824a1566SKashyap Desai 		goto out_failed;
4236824a1566SKashyap Desai 	}
4237824a1566SKashyap Desai 
42382ac794baSSreekanth Reddy 	retval = mpi3mr_print_pkg_ver(mrioc);
42392ac794baSSreekanth Reddy 	if (retval) {
42402ac794baSSreekanth Reddy 		ioc_err(mrioc, "failed to get package version\n");
42412ac794baSSreekanth Reddy 		goto out_failed;
42422ac794baSSreekanth Reddy 	}
42432ac794baSSreekanth Reddy 
4244824a1566SKashyap Desai 	retval = mpi3mr_setup_isr(mrioc, 0);
4245824a1566SKashyap Desai 	if (retval) {
4246824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to re-setup ISR, error %d\n",
4247824a1566SKashyap Desai 		    retval);
4248fe6db615SSreekanth Reddy 		goto out_failed_noretry;
4249fb9b0457SKashyap Desai 	}
4250824a1566SKashyap Desai 
4251c9566231SKashyap Desai 	retval = mpi3mr_create_op_queues(mrioc);
4252c9566231SKashyap Desai 	if (retval) {
4253c9566231SKashyap Desai 		ioc_err(mrioc, "Failed to create OpQueues error %d\n",
4254c9566231SKashyap Desai 		    retval);
4255c9566231SKashyap Desai 		goto out_failed;
4256c9566231SKashyap Desai 	}
4257c9566231SKashyap Desai 
425843ca1100SSumit Saxena 	if (!mrioc->pel_seqnum_virt) {
425943ca1100SSumit Saxena 		dprint_init(mrioc, "allocating memory for pel_seqnum_virt\n");
426043ca1100SSumit Saxena 		mrioc->pel_seqnum_sz = sizeof(struct mpi3_pel_seq);
426143ca1100SSumit Saxena 		mrioc->pel_seqnum_virt = dma_alloc_coherent(&mrioc->pdev->dev,
426243ca1100SSumit Saxena 		    mrioc->pel_seqnum_sz, &mrioc->pel_seqnum_dma,
426343ca1100SSumit Saxena 		    GFP_KERNEL);
4264bc7896d3SDan Carpenter 		if (!mrioc->pel_seqnum_virt) {
4265bc7896d3SDan Carpenter 			retval = -ENOMEM;
426643ca1100SSumit Saxena 			goto out_failed_noretry;
426743ca1100SSumit Saxena 		}
4268bc7896d3SDan Carpenter 	}
426943ca1100SSumit Saxena 
4270f10af057SSreekanth Reddy 	if (!mrioc->throttle_groups && mrioc->num_io_throttle_group) {
4271f10af057SSreekanth Reddy 		dprint_init(mrioc, "allocating memory for throttle groups\n");
4272f10af057SSreekanth Reddy 		sz = sizeof(struct mpi3mr_throttle_group_info);
4273c863a2dcSJules Irenge 		mrioc->throttle_groups = kcalloc(mrioc->num_io_throttle_group, sz, GFP_KERNEL);
4274ba8a9ba4SRanjan Kumar 		if (!mrioc->throttle_groups) {
4275ba8a9ba4SRanjan Kumar 			retval = -1;
4276f10af057SSreekanth Reddy 			goto out_failed_noretry;
4277f10af057SSreekanth Reddy 		}
4278ba8a9ba4SRanjan Kumar 	}
4279f10af057SSreekanth Reddy 
4280e3605f65SSreekanth Reddy 	retval = mpi3mr_enable_events(mrioc);
428113ef29eaSKashyap Desai 	if (retval) {
4282e3605f65SSreekanth Reddy 		ioc_err(mrioc, "failed to enable events %d\n",
428313ef29eaSKashyap Desai 		    retval);
428413ef29eaSKashyap Desai 		goto out_failed;
428513ef29eaSKashyap Desai 	}
428613ef29eaSKashyap Desai 
4287d8d08d16SRanjan Kumar 	retval = mpi3mr_refresh_trigger(mrioc, MPI3_CONFIG_ACTION_READ_CURRENT);
4288d8d08d16SRanjan Kumar 	if (retval) {
4289d8d08d16SRanjan Kumar 		ioc_err(mrioc, "failed to refresh triggers\n");
4290d8d08d16SRanjan Kumar 		goto out_failed;
4291d8d08d16SRanjan Kumar 	}
4292d8d08d16SRanjan Kumar 
4293fe6db615SSreekanth Reddy 	ioc_info(mrioc, "controller initialization completed successfully\n");
4294824a1566SKashyap Desai 	return retval;
4295824a1566SKashyap Desai out_failed:
4296fe6db615SSreekanth Reddy 	if (retry < 2) {
4297fe6db615SSreekanth Reddy 		retry++;
4298fe6db615SSreekanth Reddy 		ioc_warn(mrioc, "retrying controller initialization, retry_count:%d\n",
4299fe6db615SSreekanth Reddy 		    retry);
4300fe6db615SSreekanth Reddy 		mpi3mr_memset_buffers(mrioc);
4301fe6db615SSreekanth Reddy 		goto retry_init;
4302fe6db615SSreekanth Reddy 	}
4303ba8a9ba4SRanjan Kumar 	retval = -1;
4304fe6db615SSreekanth Reddy out_failed_noretry:
4305fe6db615SSreekanth Reddy 	ioc_err(mrioc, "controller initialization failed\n");
4306fe6db615SSreekanth Reddy 	mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
4307fe6db615SSreekanth Reddy 	    MPI3MR_RESET_FROM_CTLR_CLEANUP);
4308fe6db615SSreekanth Reddy 	mrioc->unrecoverable = 1;
4309824a1566SKashyap Desai 	return retval;
4310824a1566SKashyap Desai }
4311824a1566SKashyap Desai 
4312c0b00a93SSreekanth Reddy /**
4313c0b00a93SSreekanth Reddy  * mpi3mr_reinit_ioc - Re-Initialize the controller
4314c0b00a93SSreekanth Reddy  * @mrioc: Adapter instance reference
4315c0b00a93SSreekanth Reddy  * @is_resume: Called from resume or reset path
4316c0b00a93SSreekanth Reddy  *
4317c0b00a93SSreekanth Reddy  * This the controller re-initialization routine, executed from
4318c0b00a93SSreekanth Reddy  * the soft reset handler or resume callback. Creates
4319c0b00a93SSreekanth Reddy  * operational reply queue pairs, allocate required memory for
4320c0b00a93SSreekanth Reddy  * reply pool, sense buffer pool, issue IOC init request to the
4321c0b00a93SSreekanth Reddy  * firmware, unmask the events and issue port enable to discover
4322c0b00a93SSreekanth Reddy  * SAS/SATA/NVMe devices and RAID volumes.
4323c0b00a93SSreekanth Reddy  *
4324c0b00a93SSreekanth Reddy  * Return: 0 on success and non-zero on failure.
4325c0b00a93SSreekanth Reddy  */
mpi3mr_reinit_ioc(struct mpi3mr_ioc * mrioc,u8 is_resume)4326fe6db615SSreekanth Reddy int mpi3mr_reinit_ioc(struct mpi3mr_ioc *mrioc, u8 is_resume)
4327fe6db615SSreekanth Reddy {
4328c0b00a93SSreekanth Reddy 	int retval = 0;
4329c0b00a93SSreekanth Reddy 	u8 retry = 0;
4330c0b00a93SSreekanth Reddy 	struct mpi3_ioc_facts_data facts_data;
4331f2a79d20SSreekanth Reddy 	u32 pe_timeout, ioc_status;
4332fe6db615SSreekanth Reddy 
4333c0b00a93SSreekanth Reddy retry_init:
4334f2a79d20SSreekanth Reddy 	pe_timeout =
4335f2a79d20SSreekanth Reddy 	    (MPI3MR_PORTENABLE_TIMEOUT / MPI3MR_PORTENABLE_POLL_INTERVAL);
4336f2a79d20SSreekanth Reddy 
4337c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "bringing up the controller to ready state\n");
4338c0b00a93SSreekanth Reddy 	retval = mpi3mr_bring_ioc_ready(mrioc);
4339c0b00a93SSreekanth Reddy 	if (retval) {
4340c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to bring to ready state\n");
4341c0b00a93SSreekanth Reddy 		goto out_failed_noretry;
4342c0b00a93SSreekanth Reddy 	}
4343c0b00a93SSreekanth Reddy 
43441c342b05SSumit Saxena 	if (is_resume || mrioc->block_on_pci_err) {
4345c0b00a93SSreekanth Reddy 		dprint_reset(mrioc, "setting up single ISR\n");
4346c0b00a93SSreekanth Reddy 		retval = mpi3mr_setup_isr(mrioc, 1);
4347c0b00a93SSreekanth Reddy 		if (retval) {
4348c0b00a93SSreekanth Reddy 			ioc_err(mrioc, "failed to setup ISR\n");
4349c0b00a93SSreekanth Reddy 			goto out_failed_noretry;
4350c0b00a93SSreekanth Reddy 		}
4351c0b00a93SSreekanth Reddy 	} else
4352c0b00a93SSreekanth Reddy 		mpi3mr_ioc_enable_intr(mrioc);
4353c0b00a93SSreekanth Reddy 
4354c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "getting ioc_facts\n");
4355c0b00a93SSreekanth Reddy 	retval = mpi3mr_issue_iocfacts(mrioc, &facts_data);
4356c0b00a93SSreekanth Reddy 	if (retval) {
4357c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to get ioc_facts\n");
4358c0b00a93SSreekanth Reddy 		goto out_failed;
4359c0b00a93SSreekanth Reddy 	}
4360c0b00a93SSreekanth Reddy 
4361c5758fc7SSreekanth Reddy 	dprint_reset(mrioc, "validating ioc_facts\n");
4362c5758fc7SSreekanth Reddy 	retval = mpi3mr_revalidate_factsdata(mrioc);
4363c5758fc7SSreekanth Reddy 	if (retval) {
4364c5758fc7SSreekanth Reddy 		ioc_err(mrioc, "failed to revalidate ioc_facts data\n");
4365c5758fc7SSreekanth Reddy 		goto out_failed_noretry;
4366c5758fc7SSreekanth Reddy 	}
4367c0b00a93SSreekanth Reddy 
4368fc1ddda3SRanjan Kumar 	mpi3mr_read_tsu_interval(mrioc);
4369c0b00a93SSreekanth Reddy 	mpi3mr_print_ioc_info(mrioc);
4370c0b00a93SSreekanth Reddy 
4371fc444494SRanjan Kumar 	if (is_resume) {
4372fc444494SRanjan Kumar 		dprint_reset(mrioc, "posting host diag buffers\n");
4373fc444494SRanjan Kumar 		retval = mpi3mr_post_diag_bufs(mrioc);
4374fc444494SRanjan Kumar 		if (retval)
4375fc444494SRanjan Kumar 			ioc_warn(mrioc, "failed to post host diag buffers\n");
4376fc444494SRanjan Kumar 	} else {
4377fc444494SRanjan Kumar 		retval = mpi3mr_repost_diag_bufs(mrioc);
4378fc444494SRanjan Kumar 		if (retval)
4379fc444494SRanjan Kumar 			ioc_warn(mrioc, "failed to re post host diag buffers\n");
4380fc444494SRanjan Kumar 	}
4381fc444494SRanjan Kumar 
4382c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "sending ioc_init\n");
4383c0b00a93SSreekanth Reddy 	retval = mpi3mr_issue_iocinit(mrioc);
4384c0b00a93SSreekanth Reddy 	if (retval) {
4385c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to send ioc_init\n");
4386c0b00a93SSreekanth Reddy 		goto out_failed;
4387c0b00a93SSreekanth Reddy 	}
4388c0b00a93SSreekanth Reddy 
4389c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "getting package version\n");
4390c0b00a93SSreekanth Reddy 	retval = mpi3mr_print_pkg_ver(mrioc);
4391c0b00a93SSreekanth Reddy 	if (retval) {
4392c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to get package version\n");
4393c0b00a93SSreekanth Reddy 		goto out_failed;
4394c0b00a93SSreekanth Reddy 	}
4395c0b00a93SSreekanth Reddy 
43961c342b05SSumit Saxena 	if (is_resume || mrioc->block_on_pci_err) {
4397c0b00a93SSreekanth Reddy 		dprint_reset(mrioc, "setting up multiple ISR\n");
4398c0b00a93SSreekanth Reddy 		retval = mpi3mr_setup_isr(mrioc, 0);
4399c0b00a93SSreekanth Reddy 		if (retval) {
4400c0b00a93SSreekanth Reddy 			ioc_err(mrioc, "failed to re-setup ISR\n");
4401c0b00a93SSreekanth Reddy 			goto out_failed_noretry;
4402c0b00a93SSreekanth Reddy 		}
4403c0b00a93SSreekanth Reddy 	}
4404c0b00a93SSreekanth Reddy 
4405c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "creating operational queue pairs\n");
4406c0b00a93SSreekanth Reddy 	retval = mpi3mr_create_op_queues(mrioc);
4407c0b00a93SSreekanth Reddy 	if (retval) {
4408c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to create operational queue pairs\n");
4409c0b00a93SSreekanth Reddy 		goto out_failed;
4410c0b00a93SSreekanth Reddy 	}
4411c0b00a93SSreekanth Reddy 
441243ca1100SSumit Saxena 	if (!mrioc->pel_seqnum_virt) {
441343ca1100SSumit Saxena 		dprint_reset(mrioc, "allocating memory for pel_seqnum_virt\n");
441443ca1100SSumit Saxena 		mrioc->pel_seqnum_sz = sizeof(struct mpi3_pel_seq);
441543ca1100SSumit Saxena 		mrioc->pel_seqnum_virt = dma_alloc_coherent(&mrioc->pdev->dev,
441643ca1100SSumit Saxena 		    mrioc->pel_seqnum_sz, &mrioc->pel_seqnum_dma,
441743ca1100SSumit Saxena 		    GFP_KERNEL);
4418bc7896d3SDan Carpenter 		if (!mrioc->pel_seqnum_virt) {
4419bc7896d3SDan Carpenter 			retval = -ENOMEM;
442043ca1100SSumit Saxena 			goto out_failed_noretry;
442143ca1100SSumit Saxena 		}
4422bc7896d3SDan Carpenter 	}
442343ca1100SSumit Saxena 
4424c0b00a93SSreekanth Reddy 	if (mrioc->shost->nr_hw_queues > mrioc->num_op_reply_q) {
4425c0b00a93SSreekanth Reddy 		ioc_err(mrioc,
44265867b856SColin Ian King 		    "cannot create minimum number of operational queues expected:%d created:%d\n",
4427c0b00a93SSreekanth Reddy 		    mrioc->shost->nr_hw_queues, mrioc->num_op_reply_q);
4428ba8a9ba4SRanjan Kumar 		retval = -1;
4429c0b00a93SSreekanth Reddy 		goto out_failed_noretry;
4430c0b00a93SSreekanth Reddy 	}
4431c0b00a93SSreekanth Reddy 
4432c0b00a93SSreekanth Reddy 	dprint_reset(mrioc, "enabling events\n");
4433c0b00a93SSreekanth Reddy 	retval = mpi3mr_enable_events(mrioc);
4434c0b00a93SSreekanth Reddy 	if (retval) {
4435c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to enable events\n");
4436c0b00a93SSreekanth Reddy 		goto out_failed;
4437c0b00a93SSreekanth Reddy 	}
4438c0b00a93SSreekanth Reddy 
44392745ce0eSSreekanth Reddy 	mrioc->device_refresh_on = 1;
44402745ce0eSSreekanth Reddy 	mpi3mr_add_event_wait_for_device_refresh(mrioc);
44412745ce0eSSreekanth Reddy 
4442c0b00a93SSreekanth Reddy 	ioc_info(mrioc, "sending port enable\n");
4443f2a79d20SSreekanth Reddy 	retval = mpi3mr_issue_port_enable(mrioc, 1);
4444c0b00a93SSreekanth Reddy 	if (retval) {
4445c0b00a93SSreekanth Reddy 		ioc_err(mrioc, "failed to issue port enable\n");
4446c0b00a93SSreekanth Reddy 		goto out_failed;
4447c0b00a93SSreekanth Reddy 	}
4448f2a79d20SSreekanth Reddy 	do {
4449f2a79d20SSreekanth Reddy 		ssleep(MPI3MR_PORTENABLE_POLL_INTERVAL);
4450f2a79d20SSreekanth Reddy 		if (mrioc->init_cmds.state == MPI3MR_CMD_NOTUSED)
4451f2a79d20SSreekanth Reddy 			break;
4452f2a79d20SSreekanth Reddy 		if (!pci_device_is_present(mrioc->pdev))
4453f2a79d20SSreekanth Reddy 			mrioc->unrecoverable = 1;
4454f2a79d20SSreekanth Reddy 		if (mrioc->unrecoverable) {
4455f2a79d20SSreekanth Reddy 			retval = -1;
4456f2a79d20SSreekanth Reddy 			goto out_failed_noretry;
4457f2a79d20SSreekanth Reddy 		}
4458f2a79d20SSreekanth Reddy 		ioc_status = readl(&mrioc->sysif_regs->ioc_status);
4459f2a79d20SSreekanth Reddy 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) ||
4460f2a79d20SSreekanth Reddy 		    (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) {
4461f2a79d20SSreekanth Reddy 			mpi3mr_print_fault_info(mrioc);
4462f2a79d20SSreekanth Reddy 			mrioc->init_cmds.is_waiting = 0;
4463f2a79d20SSreekanth Reddy 			mrioc->init_cmds.callback = NULL;
4464f2a79d20SSreekanth Reddy 			mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
4465f2a79d20SSreekanth Reddy 			goto out_failed;
4466f2a79d20SSreekanth Reddy 		}
4467f2a79d20SSreekanth Reddy 	} while (--pe_timeout);
4468f2a79d20SSreekanth Reddy 
4469f2a79d20SSreekanth Reddy 	if (!pe_timeout) {
4470f2a79d20SSreekanth Reddy 		ioc_err(mrioc, "port enable timed out\n");
4471f2a79d20SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
4472f2a79d20SSreekanth Reddy 		    MPI3MR_RESET_FROM_PE_TIMEOUT);
4473f2a79d20SSreekanth Reddy 		mrioc->init_cmds.is_waiting = 0;
4474f2a79d20SSreekanth Reddy 		mrioc->init_cmds.callback = NULL;
4475f2a79d20SSreekanth Reddy 		mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
4476f2a79d20SSreekanth Reddy 		goto out_failed;
4477f2a79d20SSreekanth Reddy 	} else if (mrioc->scan_failed) {
4478f2a79d20SSreekanth Reddy 		ioc_err(mrioc,
4479f2a79d20SSreekanth Reddy 		    "port enable failed with status=0x%04x\n",
4480f2a79d20SSreekanth Reddy 		    mrioc->scan_failed);
4481f2a79d20SSreekanth Reddy 	} else
4482f2a79d20SSreekanth Reddy 		ioc_info(mrioc, "port enable completed successfully\n");
4483c0b00a93SSreekanth Reddy 
4484c0b00a93SSreekanth Reddy 	ioc_info(mrioc, "controller %s completed successfully\n",
4485c0b00a93SSreekanth Reddy 	    (is_resume)?"resume":"re-initialization");
4486c0b00a93SSreekanth Reddy 	return retval;
4487c0b00a93SSreekanth Reddy out_failed:
4488c0b00a93SSreekanth Reddy 	if (retry < 2) {
4489c0b00a93SSreekanth Reddy 		retry++;
4490c0b00a93SSreekanth Reddy 		ioc_warn(mrioc, "retrying controller %s, retry_count:%d\n",
4491c0b00a93SSreekanth Reddy 		    (is_resume)?"resume":"re-initialization", retry);
4492c0b00a93SSreekanth Reddy 		mpi3mr_memset_buffers(mrioc);
4493c0b00a93SSreekanth Reddy 		goto retry_init;
4494c0b00a93SSreekanth Reddy 	}
4495ba8a9ba4SRanjan Kumar 	retval = -1;
4496c0b00a93SSreekanth Reddy out_failed_noretry:
4497c0b00a93SSreekanth Reddy 	ioc_err(mrioc, "controller %s is failed\n",
4498c0b00a93SSreekanth Reddy 	    (is_resume)?"resume":"re-initialization");
4499c0b00a93SSreekanth Reddy 	mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
4500c0b00a93SSreekanth Reddy 	    MPI3MR_RESET_FROM_CTLR_CLEANUP);
4501c0b00a93SSreekanth Reddy 	mrioc->unrecoverable = 1;
4502c0b00a93SSreekanth Reddy 	return retval;
4503fe6db615SSreekanth Reddy }
4504fe6db615SSreekanth Reddy 
4505824a1566SKashyap Desai /**
4506fb9b0457SKashyap Desai  * mpi3mr_memset_op_reply_q_buffers - memset the operational reply queue's
4507fb9b0457SKashyap Desai  *					segments
4508fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
4509fb9b0457SKashyap Desai  * @qidx: Operational reply queue index
4510fb9b0457SKashyap Desai  *
4511fb9b0457SKashyap Desai  * Return: Nothing.
4512fb9b0457SKashyap Desai  */
mpi3mr_memset_op_reply_q_buffers(struct mpi3mr_ioc * mrioc,u16 qidx)4513fb9b0457SKashyap Desai static void mpi3mr_memset_op_reply_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx)
4514fb9b0457SKashyap Desai {
4515fb9b0457SKashyap Desai 	struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
4516fb9b0457SKashyap Desai 	struct segments *segments;
4517fb9b0457SKashyap Desai 	int i, size;
4518fb9b0457SKashyap Desai 
4519fb9b0457SKashyap Desai 	if (!op_reply_q->q_segments)
4520fb9b0457SKashyap Desai 		return;
4521fb9b0457SKashyap Desai 
4522fb9b0457SKashyap Desai 	size = op_reply_q->segment_qd * mrioc->op_reply_desc_sz;
4523fb9b0457SKashyap Desai 	segments = op_reply_q->q_segments;
4524fb9b0457SKashyap Desai 	for (i = 0; i < op_reply_q->num_segments; i++)
4525fb9b0457SKashyap Desai 		memset(segments[i].segment, 0, size);
4526fb9b0457SKashyap Desai }
4527fb9b0457SKashyap Desai 
4528fb9b0457SKashyap Desai /**
4529fb9b0457SKashyap Desai  * mpi3mr_memset_op_req_q_buffers - memset the operational request queue's
4530fb9b0457SKashyap Desai  *					segments
4531fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
4532fb9b0457SKashyap Desai  * @qidx: Operational request queue index
4533fb9b0457SKashyap Desai  *
4534fb9b0457SKashyap Desai  * Return: Nothing.
4535fb9b0457SKashyap Desai  */
mpi3mr_memset_op_req_q_buffers(struct mpi3mr_ioc * mrioc,u16 qidx)4536fb9b0457SKashyap Desai static void mpi3mr_memset_op_req_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx)
4537fb9b0457SKashyap Desai {
4538fb9b0457SKashyap Desai 	struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx;
4539fb9b0457SKashyap Desai 	struct segments *segments;
4540fb9b0457SKashyap Desai 	int i, size;
4541fb9b0457SKashyap Desai 
4542fb9b0457SKashyap Desai 	if (!op_req_q->q_segments)
4543fb9b0457SKashyap Desai 		return;
4544fb9b0457SKashyap Desai 
4545fb9b0457SKashyap Desai 	size = op_req_q->segment_qd * mrioc->facts.op_req_sz;
4546fb9b0457SKashyap Desai 	segments = op_req_q->q_segments;
4547fb9b0457SKashyap Desai 	for (i = 0; i < op_req_q->num_segments; i++)
4548fb9b0457SKashyap Desai 		memset(segments[i].segment, 0, size);
4549fb9b0457SKashyap Desai }
4550fb9b0457SKashyap Desai 
4551fb9b0457SKashyap Desai /**
4552fb9b0457SKashyap Desai  * mpi3mr_memset_buffers - memset memory for a controller
4553fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
4554fb9b0457SKashyap Desai  *
4555fb9b0457SKashyap Desai  * clear all the memory allocated for a controller, typically
4556fb9b0457SKashyap Desai  * called post reset to reuse the memory allocated during the
4557fb9b0457SKashyap Desai  * controller init.
4558fb9b0457SKashyap Desai  *
4559fb9b0457SKashyap Desai  * Return: Nothing.
4560fb9b0457SKashyap Desai  */
mpi3mr_memset_buffers(struct mpi3mr_ioc * mrioc)45610da66348SKashyap Desai void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc)
4562fb9b0457SKashyap Desai {
4563fb9b0457SKashyap Desai 	u16 i;
4564f10af057SSreekanth Reddy 	struct mpi3mr_throttle_group_info *tg;
4565fb9b0457SKashyap Desai 
4566fe6db615SSreekanth Reddy 	mrioc->change_count = 0;
4567afd3a579SSreekanth Reddy 	mrioc->active_poll_qcount = 0;
4568afd3a579SSreekanth Reddy 	mrioc->default_qcount = 0;
4569fe6db615SSreekanth Reddy 	if (mrioc->admin_req_base)
4570fb9b0457SKashyap Desai 		memset(mrioc->admin_req_base, 0, mrioc->admin_req_q_sz);
4571fe6db615SSreekanth Reddy 	if (mrioc->admin_reply_base)
4572fb9b0457SKashyap Desai 		memset(mrioc->admin_reply_base, 0, mrioc->admin_reply_q_sz);
457302ca7da2SRanjan Kumar 	atomic_set(&mrioc->admin_reply_q_in_use, 0);
4574fb9b0457SKashyap Desai 
4575fe6db615SSreekanth Reddy 	if (mrioc->init_cmds.reply) {
4576fb9b0457SKashyap Desai 		memset(mrioc->init_cmds.reply, 0, sizeof(*mrioc->init_cmds.reply));
4577f5e6d5a3SSumit Saxena 		memset(mrioc->bsg_cmds.reply, 0,
4578f5e6d5a3SSumit Saxena 		    sizeof(*mrioc->bsg_cmds.reply));
4579e844adb1SKashyap Desai 		memset(mrioc->host_tm_cmds.reply, 0,
4580e844adb1SKashyap Desai 		    sizeof(*mrioc->host_tm_cmds.reply));
458143ca1100SSumit Saxena 		memset(mrioc->pel_cmds.reply, 0,
458243ca1100SSumit Saxena 		    sizeof(*mrioc->pel_cmds.reply));
458343ca1100SSumit Saxena 		memset(mrioc->pel_abort_cmd.reply, 0,
458443ca1100SSumit Saxena 		    sizeof(*mrioc->pel_abort_cmd.reply));
45852bd37e28SSreekanth Reddy 		memset(mrioc->transport_cmds.reply, 0,
45862bd37e28SSreekanth Reddy 		    sizeof(*mrioc->transport_cmds.reply));
4587fb9b0457SKashyap Desai 		for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++)
4588fb9b0457SKashyap Desai 			memset(mrioc->dev_rmhs_cmds[i].reply, 0,
4589fb9b0457SKashyap Desai 			    sizeof(*mrioc->dev_rmhs_cmds[i].reply));
4590c1af985dSSreekanth Reddy 		for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++)
4591c1af985dSSreekanth Reddy 			memset(mrioc->evtack_cmds[i].reply, 0,
4592c1af985dSSreekanth Reddy 			    sizeof(*mrioc->evtack_cmds[i].reply));
4593339e6156SShin'ichiro Kawasaki 		bitmap_clear(mrioc->removepend_bitmap, 0,
4594339e6156SShin'ichiro Kawasaki 			     mrioc->dev_handle_bitmap_bits);
4595339e6156SShin'ichiro Kawasaki 		bitmap_clear(mrioc->devrem_bitmap, 0, MPI3MR_NUM_DEVRMCMD);
4596339e6156SShin'ichiro Kawasaki 		bitmap_clear(mrioc->evtack_cmds_bitmap, 0,
4597339e6156SShin'ichiro Kawasaki 			     MPI3MR_NUM_EVTACKCMD);
4598fe6db615SSreekanth Reddy 	}
4599fb9b0457SKashyap Desai 
4600fb9b0457SKashyap Desai 	for (i = 0; i < mrioc->num_queues; i++) {
4601fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].qid = 0;
4602fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].ci = 0;
4603fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].num_replies = 0;
4604fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].ephase = 0;
4605463429f8SKashyap Desai 		atomic_set(&mrioc->op_reply_qinfo[i].pend_ios, 0);
4606463429f8SKashyap Desai 		atomic_set(&mrioc->op_reply_qinfo[i].in_use, 0);
4607fb9b0457SKashyap Desai 		mpi3mr_memset_op_reply_q_buffers(mrioc, i);
4608fb9b0457SKashyap Desai 
4609fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].ci = 0;
4610fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].pi = 0;
4611fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].num_requests = 0;
4612fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].qid = 0;
4613fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].reply_qid = 0;
4614fb9b0457SKashyap Desai 		spin_lock_init(&mrioc->req_qinfo[i].q_lock);
4615fb9b0457SKashyap Desai 		mpi3mr_memset_op_req_q_buffers(mrioc, i);
4616fb9b0457SKashyap Desai 	}
4617f10af057SSreekanth Reddy 
4618f10af057SSreekanth Reddy 	atomic_set(&mrioc->pend_large_data_sz, 0);
4619f10af057SSreekanth Reddy 	if (mrioc->throttle_groups) {
4620f10af057SSreekanth Reddy 		tg = mrioc->throttle_groups;
4621f10af057SSreekanth Reddy 		for (i = 0; i < mrioc->num_io_throttle_group; i++, tg++) {
4622f10af057SSreekanth Reddy 			tg->id = 0;
4623cf1ce8b7SSreekanth Reddy 			tg->fw_qd = 0;
4624cf1ce8b7SSreekanth Reddy 			tg->modified_qd = 0;
4625f10af057SSreekanth Reddy 			tg->io_divert = 0;
4626cf1ce8b7SSreekanth Reddy 			tg->need_qd_reduction = 0;
4627f10af057SSreekanth Reddy 			tg->high = 0;
4628f10af057SSreekanth Reddy 			tg->low = 0;
4629cf1ce8b7SSreekanth Reddy 			tg->qd_reduction = 0;
4630f10af057SSreekanth Reddy 			atomic_set(&tg->pend_large_data_sz, 0);
4631f10af057SSreekanth Reddy 		}
4632f10af057SSreekanth Reddy 	}
4633fb9b0457SKashyap Desai }
4634fb9b0457SKashyap Desai 
4635fb9b0457SKashyap Desai /**
4636824a1566SKashyap Desai  * mpi3mr_free_mem - Free memory allocated for a controller
4637824a1566SKashyap Desai  * @mrioc: Adapter instance reference
4638824a1566SKashyap Desai  *
4639824a1566SKashyap Desai  * Free all the memory allocated for a controller.
4640824a1566SKashyap Desai  *
4641824a1566SKashyap Desai  * Return: Nothing.
4642824a1566SKashyap Desai  */
mpi3mr_free_mem(struct mpi3mr_ioc * mrioc)4643fe6db615SSreekanth Reddy void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc)
4644824a1566SKashyap Desai {
4645824a1566SKashyap Desai 	u16 i;
4646824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info;
4647fc444494SRanjan Kumar 	struct diag_buffer_desc *diag_buffer;
4648824a1566SKashyap Desai 
4649130fc180SSreekanth Reddy 	mpi3mr_free_enclosure_list(mrioc);
4650c432e167SChandrakanth patil 	mpi3mr_free_ioctl_dma_memory(mrioc);
4651130fc180SSreekanth Reddy 
4652824a1566SKashyap Desai 	if (mrioc->sense_buf_pool) {
4653824a1566SKashyap Desai 		if (mrioc->sense_buf)
4654824a1566SKashyap Desai 			dma_pool_free(mrioc->sense_buf_pool, mrioc->sense_buf,
4655824a1566SKashyap Desai 			    mrioc->sense_buf_dma);
4656824a1566SKashyap Desai 		dma_pool_destroy(mrioc->sense_buf_pool);
4657824a1566SKashyap Desai 		mrioc->sense_buf = NULL;
4658824a1566SKashyap Desai 		mrioc->sense_buf_pool = NULL;
4659824a1566SKashyap Desai 	}
4660824a1566SKashyap Desai 	if (mrioc->sense_buf_q_pool) {
4661824a1566SKashyap Desai 		if (mrioc->sense_buf_q)
4662824a1566SKashyap Desai 			dma_pool_free(mrioc->sense_buf_q_pool,
4663824a1566SKashyap Desai 			    mrioc->sense_buf_q, mrioc->sense_buf_q_dma);
4664824a1566SKashyap Desai 		dma_pool_destroy(mrioc->sense_buf_q_pool);
4665824a1566SKashyap Desai 		mrioc->sense_buf_q = NULL;
4666824a1566SKashyap Desai 		mrioc->sense_buf_q_pool = NULL;
4667824a1566SKashyap Desai 	}
4668824a1566SKashyap Desai 
4669824a1566SKashyap Desai 	if (mrioc->reply_buf_pool) {
4670824a1566SKashyap Desai 		if (mrioc->reply_buf)
4671824a1566SKashyap Desai 			dma_pool_free(mrioc->reply_buf_pool, mrioc->reply_buf,
4672824a1566SKashyap Desai 			    mrioc->reply_buf_dma);
4673824a1566SKashyap Desai 		dma_pool_destroy(mrioc->reply_buf_pool);
4674824a1566SKashyap Desai 		mrioc->reply_buf = NULL;
4675824a1566SKashyap Desai 		mrioc->reply_buf_pool = NULL;
4676824a1566SKashyap Desai 	}
4677824a1566SKashyap Desai 	if (mrioc->reply_free_q_pool) {
4678824a1566SKashyap Desai 		if (mrioc->reply_free_q)
4679824a1566SKashyap Desai 			dma_pool_free(mrioc->reply_free_q_pool,
4680824a1566SKashyap Desai 			    mrioc->reply_free_q, mrioc->reply_free_q_dma);
4681824a1566SKashyap Desai 		dma_pool_destroy(mrioc->reply_free_q_pool);
4682824a1566SKashyap Desai 		mrioc->reply_free_q = NULL;
4683824a1566SKashyap Desai 		mrioc->reply_free_q_pool = NULL;
4684824a1566SKashyap Desai 	}
4685824a1566SKashyap Desai 
4686c9566231SKashyap Desai 	for (i = 0; i < mrioc->num_op_req_q; i++)
4687c9566231SKashyap Desai 		mpi3mr_free_op_req_q_segments(mrioc, i);
4688c9566231SKashyap Desai 
4689c9566231SKashyap Desai 	for (i = 0; i < mrioc->num_op_reply_q; i++)
4690c9566231SKashyap Desai 		mpi3mr_free_op_reply_q_segments(mrioc, i);
4691c9566231SKashyap Desai 
4692824a1566SKashyap Desai 	for (i = 0; i < mrioc->intr_info_count; i++) {
4693824a1566SKashyap Desai 		intr_info = mrioc->intr_info + i;
4694824a1566SKashyap Desai 		intr_info->op_reply_q = NULL;
4695824a1566SKashyap Desai 	}
4696824a1566SKashyap Desai 
4697824a1566SKashyap Desai 	kfree(mrioc->req_qinfo);
4698824a1566SKashyap Desai 	mrioc->req_qinfo = NULL;
4699824a1566SKashyap Desai 	mrioc->num_op_req_q = 0;
4700824a1566SKashyap Desai 
4701824a1566SKashyap Desai 	kfree(mrioc->op_reply_qinfo);
4702824a1566SKashyap Desai 	mrioc->op_reply_qinfo = NULL;
4703824a1566SKashyap Desai 	mrioc->num_op_reply_q = 0;
4704824a1566SKashyap Desai 
4705824a1566SKashyap Desai 	kfree(mrioc->init_cmds.reply);
4706824a1566SKashyap Desai 	mrioc->init_cmds.reply = NULL;
4707824a1566SKashyap Desai 
4708f5e6d5a3SSumit Saxena 	kfree(mrioc->bsg_cmds.reply);
4709f5e6d5a3SSumit Saxena 	mrioc->bsg_cmds.reply = NULL;
4710f5e6d5a3SSumit Saxena 
4711e844adb1SKashyap Desai 	kfree(mrioc->host_tm_cmds.reply);
4712e844adb1SKashyap Desai 	mrioc->host_tm_cmds.reply = NULL;
4713e844adb1SKashyap Desai 
471443ca1100SSumit Saxena 	kfree(mrioc->pel_cmds.reply);
471543ca1100SSumit Saxena 	mrioc->pel_cmds.reply = NULL;
471643ca1100SSumit Saxena 
471743ca1100SSumit Saxena 	kfree(mrioc->pel_abort_cmd.reply);
471843ca1100SSumit Saxena 	mrioc->pel_abort_cmd.reply = NULL;
471943ca1100SSumit Saxena 
4720c1af985dSSreekanth Reddy 	for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) {
4721c1af985dSSreekanth Reddy 		kfree(mrioc->evtack_cmds[i].reply);
4722c1af985dSSreekanth Reddy 		mrioc->evtack_cmds[i].reply = NULL;
4723c1af985dSSreekanth Reddy 	}
4724c1af985dSSreekanth Reddy 
4725339e6156SShin'ichiro Kawasaki 	bitmap_free(mrioc->removepend_bitmap);
4726e844adb1SKashyap Desai 	mrioc->removepend_bitmap = NULL;
4727e844adb1SKashyap Desai 
4728339e6156SShin'ichiro Kawasaki 	bitmap_free(mrioc->devrem_bitmap);
4729e844adb1SKashyap Desai 	mrioc->devrem_bitmap = NULL;
4730e844adb1SKashyap Desai 
4731339e6156SShin'ichiro Kawasaki 	bitmap_free(mrioc->evtack_cmds_bitmap);
4732c1af985dSSreekanth Reddy 	mrioc->evtack_cmds_bitmap = NULL;
4733c1af985dSSreekanth Reddy 
4734339e6156SShin'ichiro Kawasaki 	bitmap_free(mrioc->chain_bitmap);
4735824a1566SKashyap Desai 	mrioc->chain_bitmap = NULL;
4736824a1566SKashyap Desai 
47372bd37e28SSreekanth Reddy 	kfree(mrioc->transport_cmds.reply);
47382bd37e28SSreekanth Reddy 	mrioc->transport_cmds.reply = NULL;
47392bd37e28SSreekanth Reddy 
474013ef29eaSKashyap Desai 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
474113ef29eaSKashyap Desai 		kfree(mrioc->dev_rmhs_cmds[i].reply);
474213ef29eaSKashyap Desai 		mrioc->dev_rmhs_cmds[i].reply = NULL;
474313ef29eaSKashyap Desai 	}
474413ef29eaSKashyap Desai 
4745824a1566SKashyap Desai 	if (mrioc->chain_buf_pool) {
4746824a1566SKashyap Desai 		for (i = 0; i < mrioc->chain_buf_count; i++) {
4747824a1566SKashyap Desai 			if (mrioc->chain_sgl_list[i].addr) {
4748824a1566SKashyap Desai 				dma_pool_free(mrioc->chain_buf_pool,
4749824a1566SKashyap Desai 				    mrioc->chain_sgl_list[i].addr,
4750824a1566SKashyap Desai 				    mrioc->chain_sgl_list[i].dma_addr);
4751824a1566SKashyap Desai 				mrioc->chain_sgl_list[i].addr = NULL;
4752824a1566SKashyap Desai 			}
4753824a1566SKashyap Desai 		}
4754824a1566SKashyap Desai 		dma_pool_destroy(mrioc->chain_buf_pool);
4755824a1566SKashyap Desai 		mrioc->chain_buf_pool = NULL;
4756824a1566SKashyap Desai 	}
4757824a1566SKashyap Desai 
4758824a1566SKashyap Desai 	kfree(mrioc->chain_sgl_list);
4759824a1566SKashyap Desai 	mrioc->chain_sgl_list = NULL;
4760824a1566SKashyap Desai 
4761824a1566SKashyap Desai 	if (mrioc->admin_reply_base) {
4762824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz,
4763824a1566SKashyap Desai 		    mrioc->admin_reply_base, mrioc->admin_reply_dma);
4764824a1566SKashyap Desai 		mrioc->admin_reply_base = NULL;
4765824a1566SKashyap Desai 	}
4766824a1566SKashyap Desai 	if (mrioc->admin_req_base) {
4767824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz,
4768824a1566SKashyap Desai 		    mrioc->admin_req_base, mrioc->admin_req_dma);
4769824a1566SKashyap Desai 		mrioc->admin_req_base = NULL;
4770824a1566SKashyap Desai 	}
47717d2b0217STomas Henzl 	if (mrioc->cfg_page) {
47727d2b0217STomas Henzl 		dma_free_coherent(&mrioc->pdev->dev, mrioc->cfg_page_sz,
47737d2b0217STomas Henzl 		    mrioc->cfg_page, mrioc->cfg_page_dma);
47747d2b0217STomas Henzl 		mrioc->cfg_page = NULL;
47757d2b0217STomas Henzl 	}
477643ca1100SSumit Saxena 	if (mrioc->pel_seqnum_virt) {
477743ca1100SSumit Saxena 		dma_free_coherent(&mrioc->pdev->dev, mrioc->pel_seqnum_sz,
477843ca1100SSumit Saxena 		    mrioc->pel_seqnum_virt, mrioc->pel_seqnum_dma);
477943ca1100SSumit Saxena 		mrioc->pel_seqnum_virt = NULL;
478043ca1100SSumit Saxena 	}
478143ca1100SSumit Saxena 
4782fc444494SRanjan Kumar 	for (i = 0; i < MPI3MR_MAX_NUM_HDB; i++) {
4783fc444494SRanjan Kumar 		diag_buffer = &mrioc->diag_buffers[i];
4784fc444494SRanjan Kumar 		if (diag_buffer->addr) {
4785fc444494SRanjan Kumar 			dma_free_coherent(&mrioc->pdev->dev,
4786fc444494SRanjan Kumar 			    diag_buffer->size, diag_buffer->addr,
4787fc444494SRanjan Kumar 			    diag_buffer->dma_addr);
4788fc444494SRanjan Kumar 			diag_buffer->addr = NULL;
4789fc444494SRanjan Kumar 			diag_buffer->size = 0;
4790fc444494SRanjan Kumar 			diag_buffer->type = 0;
4791fc444494SRanjan Kumar 			diag_buffer->status = 0;
4792fc444494SRanjan Kumar 		}
4793fc444494SRanjan Kumar 	}
4794fc444494SRanjan Kumar 
4795f305a7b6STomas Henzl 	kfree(mrioc->throttle_groups);
4796f305a7b6STomas Henzl 	mrioc->throttle_groups = NULL;
4797f305a7b6STomas Henzl 
479843ca1100SSumit Saxena 	kfree(mrioc->logdata_buf);
479943ca1100SSumit Saxena 	mrioc->logdata_buf = NULL;
480043ca1100SSumit Saxena 
4801824a1566SKashyap Desai }
4802824a1566SKashyap Desai 
4803824a1566SKashyap Desai /**
4804824a1566SKashyap Desai  * mpi3mr_issue_ioc_shutdown - shutdown controller
4805824a1566SKashyap Desai  * @mrioc: Adapter instance reference
4806824a1566SKashyap Desai  *
4807824a1566SKashyap Desai  * Send shutodwn notification to the controller and wait for the
4808824a1566SKashyap Desai  * shutdown_timeout for it to be completed.
4809824a1566SKashyap Desai  *
4810824a1566SKashyap Desai  * Return: Nothing.
4811824a1566SKashyap Desai  */
mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc * mrioc)4812824a1566SKashyap Desai static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc)
4813824a1566SKashyap Desai {
4814824a1566SKashyap Desai 	u32 ioc_config, ioc_status;
4815824a1566SKashyap Desai 	u8 retval = 1;
4816824a1566SKashyap Desai 	u32 timeout = MPI3MR_DEFAULT_SHUTDOWN_TIME * 10;
4817824a1566SKashyap Desai 
4818824a1566SKashyap Desai 	ioc_info(mrioc, "Issuing shutdown Notification\n");
4819824a1566SKashyap Desai 	if (mrioc->unrecoverable) {
4820824a1566SKashyap Desai 		ioc_warn(mrioc,
4821824a1566SKashyap Desai 		    "IOC is unrecoverable shutdown is not issued\n");
4822824a1566SKashyap Desai 		return;
4823824a1566SKashyap Desai 	}
4824824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
4825824a1566SKashyap Desai 	if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
4826824a1566SKashyap Desai 	    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS) {
4827824a1566SKashyap Desai 		ioc_info(mrioc, "shutdown already in progress\n");
4828824a1566SKashyap Desai 		return;
4829824a1566SKashyap Desai 	}
4830824a1566SKashyap Desai 
4831824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
4832824a1566SKashyap Desai 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL;
4833ec5ebd2cSSreekanth Reddy 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN_SEND_REQ;
4834824a1566SKashyap Desai 
4835824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
4836824a1566SKashyap Desai 
4837824a1566SKashyap Desai 	if (mrioc->facts.shutdown_timeout)
4838824a1566SKashyap Desai 		timeout = mrioc->facts.shutdown_timeout * 10;
4839824a1566SKashyap Desai 
4840824a1566SKashyap Desai 	do {
4841824a1566SKashyap Desai 		ioc_status = readl(&mrioc->sysif_regs->ioc_status);
4842824a1566SKashyap Desai 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
4843824a1566SKashyap Desai 		    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_COMPLETE) {
4844824a1566SKashyap Desai 			retval = 0;
4845824a1566SKashyap Desai 			break;
4846824a1566SKashyap Desai 		}
4847824a1566SKashyap Desai 		msleep(100);
4848824a1566SKashyap Desai 	} while (--timeout);
4849824a1566SKashyap Desai 
4850824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
4851824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
4852824a1566SKashyap Desai 
4853824a1566SKashyap Desai 	if (retval) {
4854824a1566SKashyap Desai 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
4855824a1566SKashyap Desai 		    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS)
4856824a1566SKashyap Desai 			ioc_warn(mrioc,
4857824a1566SKashyap Desai 			    "shutdown still in progress after timeout\n");
4858824a1566SKashyap Desai 	}
4859824a1566SKashyap Desai 
4860824a1566SKashyap Desai 	ioc_info(mrioc,
4861824a1566SKashyap Desai 	    "Base IOC Sts/Config after %s shutdown is (0x%x)/(0x%x)\n",
4862824a1566SKashyap Desai 	    (!retval) ? "successful" : "failed", ioc_status,
4863824a1566SKashyap Desai 	    ioc_config);
4864824a1566SKashyap Desai }
4865824a1566SKashyap Desai 
4866824a1566SKashyap Desai /**
4867824a1566SKashyap Desai  * mpi3mr_cleanup_ioc - Cleanup controller
4868824a1566SKashyap Desai  * @mrioc: Adapter instance reference
48693bb3c24eSYang Li  *
4870824a1566SKashyap Desai  * controller cleanup handler, Message unit reset or soft reset
4871fe6db615SSreekanth Reddy  * and shutdown notification is issued to the controller.
4872824a1566SKashyap Desai  *
4873824a1566SKashyap Desai  * Return: Nothing.
4874824a1566SKashyap Desai  */
mpi3mr_cleanup_ioc(struct mpi3mr_ioc * mrioc)4875fe6db615SSreekanth Reddy void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc)
4876824a1566SKashyap Desai {
4877824a1566SKashyap Desai 	enum mpi3mr_iocstate ioc_state;
4878824a1566SKashyap Desai 
4879fe6db615SSreekanth Reddy 	dprint_exit(mrioc, "cleaning up the controller\n");
4880824a1566SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
4881824a1566SKashyap Desai 
4882824a1566SKashyap Desai 	ioc_state = mpi3mr_get_iocstate(mrioc);
4883824a1566SKashyap Desai 
48841c342b05SSumit Saxena 	if (!mrioc->unrecoverable && !mrioc->reset_in_progress &&
48851c342b05SSumit Saxena 	    !mrioc->pci_err_recovery &&
4886824a1566SKashyap Desai 	    (ioc_state == MRIOC_STATE_READY)) {
4887824a1566SKashyap Desai 		if (mpi3mr_issue_and_process_mur(mrioc,
4888824a1566SKashyap Desai 		    MPI3MR_RESET_FROM_CTLR_CLEANUP))
4889824a1566SKashyap Desai 			mpi3mr_issue_reset(mrioc,
4890824a1566SKashyap Desai 			    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
4891824a1566SKashyap Desai 			    MPI3MR_RESET_FROM_MUR_FAILURE);
4892824a1566SKashyap Desai 		mpi3mr_issue_ioc_shutdown(mrioc);
4893824a1566SKashyap Desai 	}
4894fe6db615SSreekanth Reddy 	dprint_exit(mrioc, "controller cleanup completed\n");
4895fb9b0457SKashyap Desai }
4896fb9b0457SKashyap Desai 
4897fb9b0457SKashyap Desai /**
4898fb9b0457SKashyap Desai  * mpi3mr_drv_cmd_comp_reset - Flush a internal driver command
4899fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
4900fb9b0457SKashyap Desai  * @cmdptr: Internal command tracker
4901fb9b0457SKashyap Desai  *
4902fb9b0457SKashyap Desai  * Complete an internal driver commands with state indicating it
4903fb9b0457SKashyap Desai  * is completed due to reset.
4904fb9b0457SKashyap Desai  *
4905fb9b0457SKashyap Desai  * Return: Nothing.
4906fb9b0457SKashyap Desai  */
mpi3mr_drv_cmd_comp_reset(struct mpi3mr_ioc * mrioc,struct mpi3mr_drv_cmd * cmdptr)4907fb9b0457SKashyap Desai static inline void mpi3mr_drv_cmd_comp_reset(struct mpi3mr_ioc *mrioc,
4908fb9b0457SKashyap Desai 	struct mpi3mr_drv_cmd *cmdptr)
4909fb9b0457SKashyap Desai {
4910fb9b0457SKashyap Desai 	if (cmdptr->state & MPI3MR_CMD_PENDING) {
4911fb9b0457SKashyap Desai 		cmdptr->state |= MPI3MR_CMD_RESET;
4912fb9b0457SKashyap Desai 		cmdptr->state &= ~MPI3MR_CMD_PENDING;
4913fb9b0457SKashyap Desai 		if (cmdptr->is_waiting) {
4914fb9b0457SKashyap Desai 			complete(&cmdptr->done);
4915fb9b0457SKashyap Desai 			cmdptr->is_waiting = 0;
4916fb9b0457SKashyap Desai 		} else if (cmdptr->callback)
4917fb9b0457SKashyap Desai 			cmdptr->callback(mrioc, cmdptr);
4918fb9b0457SKashyap Desai 	}
4919fb9b0457SKashyap Desai }
4920fb9b0457SKashyap Desai 
4921fb9b0457SKashyap Desai /**
4922fb9b0457SKashyap Desai  * mpi3mr_flush_drv_cmds - Flush internaldriver commands
4923fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
4924fb9b0457SKashyap Desai  *
4925fb9b0457SKashyap Desai  * Flush all internal driver commands post reset
4926fb9b0457SKashyap Desai  *
4927fb9b0457SKashyap Desai  * Return: Nothing.
4928fb9b0457SKashyap Desai  */
mpi3mr_flush_drv_cmds(struct mpi3mr_ioc * mrioc)4929f2a79d20SSreekanth Reddy void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc)
4930fb9b0457SKashyap Desai {
4931fb9b0457SKashyap Desai 	struct mpi3mr_drv_cmd *cmdptr;
4932fb9b0457SKashyap Desai 	u8 i;
4933fb9b0457SKashyap Desai 
4934fb9b0457SKashyap Desai 	cmdptr = &mrioc->init_cmds;
4935fb9b0457SKashyap Desai 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
493632d457d5SSreekanth Reddy 
493732d457d5SSreekanth Reddy 	cmdptr = &mrioc->cfg_cmds;
493832d457d5SSreekanth Reddy 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
493932d457d5SSreekanth Reddy 
4940f5e6d5a3SSumit Saxena 	cmdptr = &mrioc->bsg_cmds;
4941f5e6d5a3SSumit Saxena 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
4942e844adb1SKashyap Desai 	cmdptr = &mrioc->host_tm_cmds;
4943e844adb1SKashyap Desai 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
4944fb9b0457SKashyap Desai 
4945fb9b0457SKashyap Desai 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
4946fb9b0457SKashyap Desai 		cmdptr = &mrioc->dev_rmhs_cmds[i];
4947fb9b0457SKashyap Desai 		mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
4948fb9b0457SKashyap Desai 	}
4949c1af985dSSreekanth Reddy 
4950c1af985dSSreekanth Reddy 	for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) {
4951c1af985dSSreekanth Reddy 		cmdptr = &mrioc->evtack_cmds[i];
4952c1af985dSSreekanth Reddy 		mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
4953c1af985dSSreekanth Reddy 	}
495443ca1100SSumit Saxena 
495543ca1100SSumit Saxena 	cmdptr = &mrioc->pel_cmds;
495643ca1100SSumit Saxena 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
495743ca1100SSumit Saxena 
495843ca1100SSumit Saxena 	cmdptr = &mrioc->pel_abort_cmd;
495943ca1100SSumit Saxena 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
496043ca1100SSumit Saxena 
49612bd37e28SSreekanth Reddy 	cmdptr = &mrioc->transport_cmds;
49622bd37e28SSreekanth Reddy 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
496343ca1100SSumit Saxena }
496443ca1100SSumit Saxena 
496543ca1100SSumit Saxena /**
496643ca1100SSumit Saxena  * mpi3mr_pel_wait_post - Issue PEL Wait
496743ca1100SSumit Saxena  * @mrioc: Adapter instance reference
496843ca1100SSumit Saxena  * @drv_cmd: Internal command tracker
496943ca1100SSumit Saxena  *
497043ca1100SSumit Saxena  * Issue PEL Wait MPI request through admin queue and return.
497143ca1100SSumit Saxena  *
497243ca1100SSumit Saxena  * Return: Nothing.
497343ca1100SSumit Saxena  */
mpi3mr_pel_wait_post(struct mpi3mr_ioc * mrioc,struct mpi3mr_drv_cmd * drv_cmd)497443ca1100SSumit Saxena static void mpi3mr_pel_wait_post(struct mpi3mr_ioc *mrioc,
497543ca1100SSumit Saxena 	struct mpi3mr_drv_cmd *drv_cmd)
497643ca1100SSumit Saxena {
497743ca1100SSumit Saxena 	struct mpi3_pel_req_action_wait pel_wait;
497843ca1100SSumit Saxena 
497943ca1100SSumit Saxena 	mrioc->pel_abort_requested = false;
498043ca1100SSumit Saxena 
498143ca1100SSumit Saxena 	memset(&pel_wait, 0, sizeof(pel_wait));
498243ca1100SSumit Saxena 	drv_cmd->state = MPI3MR_CMD_PENDING;
498343ca1100SSumit Saxena 	drv_cmd->is_waiting = 0;
498443ca1100SSumit Saxena 	drv_cmd->callback = mpi3mr_pel_wait_complete;
498543ca1100SSumit Saxena 	drv_cmd->ioc_status = 0;
498643ca1100SSumit Saxena 	drv_cmd->ioc_loginfo = 0;
498743ca1100SSumit Saxena 	pel_wait.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_PEL_WAIT);
498843ca1100SSumit Saxena 	pel_wait.function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG;
498943ca1100SSumit Saxena 	pel_wait.action = MPI3_PEL_ACTION_WAIT;
499043ca1100SSumit Saxena 	pel_wait.starting_sequence_number = cpu_to_le32(mrioc->pel_newest_seqnum);
499143ca1100SSumit Saxena 	pel_wait.locale = cpu_to_le16(mrioc->pel_locale);
499243ca1100SSumit Saxena 	pel_wait.class = cpu_to_le16(mrioc->pel_class);
499343ca1100SSumit Saxena 	pel_wait.wait_time = MPI3_PEL_WAITTIME_INFINITE_WAIT;
499443ca1100SSumit Saxena 	dprint_bsg_info(mrioc, "sending pel_wait seqnum(%d), class(%d), locale(0x%08x)\n",
499543ca1100SSumit Saxena 	    mrioc->pel_newest_seqnum, mrioc->pel_class, mrioc->pel_locale);
499643ca1100SSumit Saxena 
499743ca1100SSumit Saxena 	if (mpi3mr_admin_request_post(mrioc, &pel_wait, sizeof(pel_wait), 0)) {
499843ca1100SSumit Saxena 		dprint_bsg_err(mrioc,
499943ca1100SSumit Saxena 			    "Issuing PELWait: Admin post failed\n");
500043ca1100SSumit Saxena 		drv_cmd->state = MPI3MR_CMD_NOTUSED;
500143ca1100SSumit Saxena 		drv_cmd->callback = NULL;
500243ca1100SSumit Saxena 		drv_cmd->retry_count = 0;
500343ca1100SSumit Saxena 		mrioc->pel_enabled = false;
500443ca1100SSumit Saxena 	}
500543ca1100SSumit Saxena }
500643ca1100SSumit Saxena 
500743ca1100SSumit Saxena /**
500843ca1100SSumit Saxena  * mpi3mr_pel_get_seqnum_post - Issue PEL Get Sequence number
500943ca1100SSumit Saxena  * @mrioc: Adapter instance reference
501043ca1100SSumit Saxena  * @drv_cmd: Internal command tracker
501143ca1100SSumit Saxena  *
501243ca1100SSumit Saxena  * Issue PEL get sequence number MPI request through admin queue
501343ca1100SSumit Saxena  * and return.
501443ca1100SSumit Saxena  *
501543ca1100SSumit Saxena  * Return: 0 on success, non-zero on failure.
501643ca1100SSumit Saxena  */
mpi3mr_pel_get_seqnum_post(struct mpi3mr_ioc * mrioc,struct mpi3mr_drv_cmd * drv_cmd)501743ca1100SSumit Saxena int mpi3mr_pel_get_seqnum_post(struct mpi3mr_ioc *mrioc,
501843ca1100SSumit Saxena 	struct mpi3mr_drv_cmd *drv_cmd)
501943ca1100SSumit Saxena {
502043ca1100SSumit Saxena 	struct mpi3_pel_req_action_get_sequence_numbers pel_getseq_req;
502143ca1100SSumit Saxena 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
502243ca1100SSumit Saxena 	int retval = 0;
502343ca1100SSumit Saxena 
502443ca1100SSumit Saxena 	memset(&pel_getseq_req, 0, sizeof(pel_getseq_req));
502543ca1100SSumit Saxena 	mrioc->pel_cmds.state = MPI3MR_CMD_PENDING;
502643ca1100SSumit Saxena 	mrioc->pel_cmds.is_waiting = 0;
502743ca1100SSumit Saxena 	mrioc->pel_cmds.ioc_status = 0;
502843ca1100SSumit Saxena 	mrioc->pel_cmds.ioc_loginfo = 0;
502943ca1100SSumit Saxena 	mrioc->pel_cmds.callback = mpi3mr_pel_get_seqnum_complete;
503043ca1100SSumit Saxena 	pel_getseq_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_PEL_WAIT);
503143ca1100SSumit Saxena 	pel_getseq_req.function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG;
503243ca1100SSumit Saxena 	pel_getseq_req.action = MPI3_PEL_ACTION_GET_SEQNUM;
503343ca1100SSumit Saxena 	mpi3mr_add_sg_single(&pel_getseq_req.sgl, sgl_flags,
503443ca1100SSumit Saxena 	    mrioc->pel_seqnum_sz, mrioc->pel_seqnum_dma);
503543ca1100SSumit Saxena 
503643ca1100SSumit Saxena 	retval = mpi3mr_admin_request_post(mrioc, &pel_getseq_req,
503743ca1100SSumit Saxena 			sizeof(pel_getseq_req), 0);
503843ca1100SSumit Saxena 	if (retval) {
503943ca1100SSumit Saxena 		if (drv_cmd) {
504043ca1100SSumit Saxena 			drv_cmd->state = MPI3MR_CMD_NOTUSED;
504143ca1100SSumit Saxena 			drv_cmd->callback = NULL;
504243ca1100SSumit Saxena 			drv_cmd->retry_count = 0;
504343ca1100SSumit Saxena 		}
504443ca1100SSumit Saxena 		mrioc->pel_enabled = false;
504543ca1100SSumit Saxena 	}
504643ca1100SSumit Saxena 
504743ca1100SSumit Saxena 	return retval;
504843ca1100SSumit Saxena }
504943ca1100SSumit Saxena 
505043ca1100SSumit Saxena /**
505143ca1100SSumit Saxena  * mpi3mr_pel_wait_complete - PELWait Completion callback
505243ca1100SSumit Saxena  * @mrioc: Adapter instance reference
505343ca1100SSumit Saxena  * @drv_cmd: Internal command tracker
505443ca1100SSumit Saxena  *
505543ca1100SSumit Saxena  * This is a callback handler for the PELWait request and
505643ca1100SSumit Saxena  * firmware completes a PELWait request when it is aborted or a
505743ca1100SSumit Saxena  * new PEL entry is available. This sends AEN to the application
505843ca1100SSumit Saxena  * and if the PELwait completion is not due to PELAbort then
505943ca1100SSumit Saxena  * this will send a request for new PEL Sequence number
506043ca1100SSumit Saxena  *
506143ca1100SSumit Saxena  * Return: Nothing.
506243ca1100SSumit Saxena  */
mpi3mr_pel_wait_complete(struct mpi3mr_ioc * mrioc,struct mpi3mr_drv_cmd * drv_cmd)506343ca1100SSumit Saxena static void mpi3mr_pel_wait_complete(struct mpi3mr_ioc *mrioc,
506443ca1100SSumit Saxena 	struct mpi3mr_drv_cmd *drv_cmd)
506543ca1100SSumit Saxena {
506643ca1100SSumit Saxena 	struct mpi3_pel_reply *pel_reply = NULL;
506743ca1100SSumit Saxena 	u16 ioc_status, pe_log_status;
506843ca1100SSumit Saxena 	bool do_retry = false;
506943ca1100SSumit Saxena 
507043ca1100SSumit Saxena 	if (drv_cmd->state & MPI3MR_CMD_RESET)
507143ca1100SSumit Saxena 		goto cleanup_drv_cmd;
507243ca1100SSumit Saxena 
507343ca1100SSumit Saxena 	ioc_status = drv_cmd->ioc_status & MPI3_IOCSTATUS_STATUS_MASK;
507443ca1100SSumit Saxena 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
507543ca1100SSumit Saxena 		ioc_err(mrioc, "%s: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
507643ca1100SSumit Saxena 			__func__, ioc_status, drv_cmd->ioc_loginfo);
507743ca1100SSumit Saxena 		dprint_bsg_err(mrioc,
507843ca1100SSumit Saxena 		    "pel_wait: failed with ioc_status(0x%04x), log_info(0x%08x)\n",
507943ca1100SSumit Saxena 		    ioc_status, drv_cmd->ioc_loginfo);
508043ca1100SSumit Saxena 		do_retry = true;
508143ca1100SSumit Saxena 	}
508243ca1100SSumit Saxena 
508343ca1100SSumit Saxena 	if (drv_cmd->state & MPI3MR_CMD_REPLY_VALID)
508443ca1100SSumit Saxena 		pel_reply = (struct mpi3_pel_reply *)drv_cmd->reply;
508543ca1100SSumit Saxena 
508643ca1100SSumit Saxena 	if (!pel_reply) {
508743ca1100SSumit Saxena 		dprint_bsg_err(mrioc,
508843ca1100SSumit Saxena 		    "pel_wait: failed due to no reply\n");
508943ca1100SSumit Saxena 		goto out_failed;
509043ca1100SSumit Saxena 	}
509143ca1100SSumit Saxena 
509243ca1100SSumit Saxena 	pe_log_status = le16_to_cpu(pel_reply->pe_log_status);
509343ca1100SSumit Saxena 	if ((pe_log_status != MPI3_PEL_STATUS_SUCCESS) &&
509443ca1100SSumit Saxena 	    (pe_log_status != MPI3_PEL_STATUS_ABORTED)) {
509543ca1100SSumit Saxena 		ioc_err(mrioc, "%s: Failed pe_log_status(0x%04x)\n",
509643ca1100SSumit Saxena 			__func__, pe_log_status);
509743ca1100SSumit Saxena 		dprint_bsg_err(mrioc,
509843ca1100SSumit Saxena 		    "pel_wait: failed due to pel_log_status(0x%04x)\n",
509943ca1100SSumit Saxena 		    pe_log_status);
510043ca1100SSumit Saxena 		do_retry = true;
510143ca1100SSumit Saxena 	}
510243ca1100SSumit Saxena 
510343ca1100SSumit Saxena 	if (do_retry) {
510443ca1100SSumit Saxena 		if (drv_cmd->retry_count < MPI3MR_PEL_RETRY_COUNT) {
510543ca1100SSumit Saxena 			drv_cmd->retry_count++;
510643ca1100SSumit Saxena 			dprint_bsg_err(mrioc, "pel_wait: retrying(%d)\n",
510743ca1100SSumit Saxena 			    drv_cmd->retry_count);
510843ca1100SSumit Saxena 			mpi3mr_pel_wait_post(mrioc, drv_cmd);
510943ca1100SSumit Saxena 			return;
511043ca1100SSumit Saxena 		}
511143ca1100SSumit Saxena 		dprint_bsg_err(mrioc,
511243ca1100SSumit Saxena 		    "pel_wait: failed after all retries(%d)\n",
511343ca1100SSumit Saxena 		    drv_cmd->retry_count);
511443ca1100SSumit Saxena 		goto out_failed;
511543ca1100SSumit Saxena 	}
511643ca1100SSumit Saxena 	atomic64_inc(&event_counter);
511743ca1100SSumit Saxena 	if (!mrioc->pel_abort_requested) {
511843ca1100SSumit Saxena 		mrioc->pel_cmds.retry_count = 0;
511943ca1100SSumit Saxena 		mpi3mr_pel_get_seqnum_post(mrioc, &mrioc->pel_cmds);
512043ca1100SSumit Saxena 	}
512143ca1100SSumit Saxena 
512243ca1100SSumit Saxena 	return;
512343ca1100SSumit Saxena out_failed:
512443ca1100SSumit Saxena 	mrioc->pel_enabled = false;
512543ca1100SSumit Saxena cleanup_drv_cmd:
512643ca1100SSumit Saxena 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
512743ca1100SSumit Saxena 	drv_cmd->callback = NULL;
512843ca1100SSumit Saxena 	drv_cmd->retry_count = 0;
512943ca1100SSumit Saxena }
513043ca1100SSumit Saxena 
513143ca1100SSumit Saxena /**
513243ca1100SSumit Saxena  * mpi3mr_pel_get_seqnum_complete - PELGetSeqNum Completion callback
513343ca1100SSumit Saxena  * @mrioc: Adapter instance reference
513443ca1100SSumit Saxena  * @drv_cmd: Internal command tracker
513543ca1100SSumit Saxena  *
513643ca1100SSumit Saxena  * This is a callback handler for the PEL get sequence number
513743ca1100SSumit Saxena  * request and a new PEL wait request will be issued to the
513843ca1100SSumit Saxena  * firmware from this
513943ca1100SSumit Saxena  *
514043ca1100SSumit Saxena  * Return: Nothing.
514143ca1100SSumit Saxena  */
mpi3mr_pel_get_seqnum_complete(struct mpi3mr_ioc * mrioc,struct mpi3mr_drv_cmd * drv_cmd)514243ca1100SSumit Saxena void mpi3mr_pel_get_seqnum_complete(struct mpi3mr_ioc *mrioc,
514343ca1100SSumit Saxena 	struct mpi3mr_drv_cmd *drv_cmd)
514443ca1100SSumit Saxena {
514543ca1100SSumit Saxena 	struct mpi3_pel_reply *pel_reply = NULL;
514643ca1100SSumit Saxena 	struct mpi3_pel_seq *pel_seqnum_virt;
514743ca1100SSumit Saxena 	u16 ioc_status;
514843ca1100SSumit Saxena 	bool do_retry = false;
514943ca1100SSumit Saxena 
515043ca1100SSumit Saxena 	pel_seqnum_virt = (struct mpi3_pel_seq *)mrioc->pel_seqnum_virt;
515143ca1100SSumit Saxena 
515243ca1100SSumit Saxena 	if (drv_cmd->state & MPI3MR_CMD_RESET)
515343ca1100SSumit Saxena 		goto cleanup_drv_cmd;
515443ca1100SSumit Saxena 
515543ca1100SSumit Saxena 	ioc_status = drv_cmd->ioc_status & MPI3_IOCSTATUS_STATUS_MASK;
515643ca1100SSumit Saxena 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
515743ca1100SSumit Saxena 		dprint_bsg_err(mrioc,
515843ca1100SSumit Saxena 		    "pel_get_seqnum: failed with ioc_status(0x%04x), log_info(0x%08x)\n",
515943ca1100SSumit Saxena 		    ioc_status, drv_cmd->ioc_loginfo);
516043ca1100SSumit Saxena 		do_retry = true;
516143ca1100SSumit Saxena 	}
516243ca1100SSumit Saxena 
516343ca1100SSumit Saxena 	if (drv_cmd->state & MPI3MR_CMD_REPLY_VALID)
516443ca1100SSumit Saxena 		pel_reply = (struct mpi3_pel_reply *)drv_cmd->reply;
516543ca1100SSumit Saxena 	if (!pel_reply) {
516643ca1100SSumit Saxena 		dprint_bsg_err(mrioc,
516743ca1100SSumit Saxena 		    "pel_get_seqnum: failed due to no reply\n");
516843ca1100SSumit Saxena 		goto out_failed;
516943ca1100SSumit Saxena 	}
517043ca1100SSumit Saxena 
517143ca1100SSumit Saxena 	if (le16_to_cpu(pel_reply->pe_log_status) != MPI3_PEL_STATUS_SUCCESS) {
517243ca1100SSumit Saxena 		dprint_bsg_err(mrioc,
517343ca1100SSumit Saxena 		    "pel_get_seqnum: failed due to pel_log_status(0x%04x)\n",
517443ca1100SSumit Saxena 		    le16_to_cpu(pel_reply->pe_log_status));
517543ca1100SSumit Saxena 		do_retry = true;
517643ca1100SSumit Saxena 	}
517743ca1100SSumit Saxena 
517843ca1100SSumit Saxena 	if (do_retry) {
517943ca1100SSumit Saxena 		if (drv_cmd->retry_count < MPI3MR_PEL_RETRY_COUNT) {
518043ca1100SSumit Saxena 			drv_cmd->retry_count++;
518143ca1100SSumit Saxena 			dprint_bsg_err(mrioc,
518243ca1100SSumit Saxena 			    "pel_get_seqnum: retrying(%d)\n",
518343ca1100SSumit Saxena 			    drv_cmd->retry_count);
518443ca1100SSumit Saxena 			mpi3mr_pel_get_seqnum_post(mrioc, drv_cmd);
518543ca1100SSumit Saxena 			return;
518643ca1100SSumit Saxena 		}
518743ca1100SSumit Saxena 
518843ca1100SSumit Saxena 		dprint_bsg_err(mrioc,
518943ca1100SSumit Saxena 		    "pel_get_seqnum: failed after all retries(%d)\n",
519043ca1100SSumit Saxena 		    drv_cmd->retry_count);
519143ca1100SSumit Saxena 		goto out_failed;
519243ca1100SSumit Saxena 	}
519343ca1100SSumit Saxena 	mrioc->pel_newest_seqnum = le32_to_cpu(pel_seqnum_virt->newest) + 1;
519443ca1100SSumit Saxena 	drv_cmd->retry_count = 0;
519543ca1100SSumit Saxena 	mpi3mr_pel_wait_post(mrioc, drv_cmd);
519643ca1100SSumit Saxena 
519743ca1100SSumit Saxena 	return;
519843ca1100SSumit Saxena out_failed:
519943ca1100SSumit Saxena 	mrioc->pel_enabled = false;
520043ca1100SSumit Saxena cleanup_drv_cmd:
520143ca1100SSumit Saxena 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
520243ca1100SSumit Saxena 	drv_cmd->callback = NULL;
520343ca1100SSumit Saxena 	drv_cmd->retry_count = 0;
5204fb9b0457SKashyap Desai }
5205fb9b0457SKashyap Desai 
5206fb9b0457SKashyap Desai /**
5207824a1566SKashyap Desai  * mpi3mr_soft_reset_handler - Reset the controller
5208824a1566SKashyap Desai  * @mrioc: Adapter instance reference
5209824a1566SKashyap Desai  * @reset_reason: Reset reason code
5210824a1566SKashyap Desai  * @snapdump: Flag to generate snapdump in firmware or not
5211824a1566SKashyap Desai  *
5212fb9b0457SKashyap Desai  * This is an handler for recovering controller by issuing soft
5213fb9b0457SKashyap Desai  * reset are diag fault reset.  This is a blocking function and
5214fb9b0457SKashyap Desai  * when one reset is executed if any other resets they will be
5215f5e6d5a3SSumit Saxena  * blocked. All BSG requests will be blocked during the reset. If
5216fb9b0457SKashyap Desai  * controller reset is successful then the controller will be
5217fb9b0457SKashyap Desai  * reinitalized, otherwise the controller will be marked as not
5218fb9b0457SKashyap Desai  * recoverable
5219fb9b0457SKashyap Desai  *
5220fb9b0457SKashyap Desai  * In snapdump bit is set, the controller is issued with diag
5221fb9b0457SKashyap Desai  * fault reset so that the firmware can create a snap dump and
5222fb9b0457SKashyap Desai  * post that the firmware will result in F000 fault and the
5223fb9b0457SKashyap Desai  * driver will issue soft reset to recover from that.
5224824a1566SKashyap Desai  *
5225824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
5226824a1566SKashyap Desai  */
mpi3mr_soft_reset_handler(struct mpi3mr_ioc * mrioc,u16 reset_reason,u8 snapdump)5227824a1566SKashyap Desai int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
52280a2714b7SRanjan Kumar 	u16 reset_reason, u8 snapdump)
5229824a1566SKashyap Desai {
5230fb9b0457SKashyap Desai 	int retval = 0, i;
5231fb9b0457SKashyap Desai 	unsigned long flags;
5232fb9b0457SKashyap Desai 	u32 host_diagnostic, timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10;
5233d8d08d16SRanjan Kumar 	union mpi3mr_trigger_data trigger_data;
5234fb9b0457SKashyap Desai 
5235b64845a7SSreekanth Reddy 	/* Block the reset handler until diag save in progress*/
5236b64845a7SSreekanth Reddy 	dprint_reset(mrioc,
5237b64845a7SSreekanth Reddy 	    "soft_reset_handler: check and block on diagsave_timeout(%d)\n",
5238b64845a7SSreekanth Reddy 	    mrioc->diagsave_timeout);
5239b64845a7SSreekanth Reddy 	while (mrioc->diagsave_timeout)
5240b64845a7SSreekanth Reddy 		ssleep(1);
5241fb9b0457SKashyap Desai 	/*
5242fb9b0457SKashyap Desai 	 * Block new resets until the currently executing one is finished and
5243fb9b0457SKashyap Desai 	 * return the status of the existing reset for all blocked resets
5244fb9b0457SKashyap Desai 	 */
5245b64845a7SSreekanth Reddy 	dprint_reset(mrioc, "soft_reset_handler: acquiring reset_mutex\n");
5246fb9b0457SKashyap Desai 	if (!mutex_trylock(&mrioc->reset_mutex)) {
5247b64845a7SSreekanth Reddy 		ioc_info(mrioc,
5248b64845a7SSreekanth Reddy 		    "controller reset triggered by %s is blocked due to another reset in progress\n",
5249b64845a7SSreekanth Reddy 		    mpi3mr_reset_rc_name(reset_reason));
5250b64845a7SSreekanth Reddy 		do {
5251b64845a7SSreekanth Reddy 			ssleep(1);
5252b64845a7SSreekanth Reddy 		} while (mrioc->reset_in_progress == 1);
5253b64845a7SSreekanth Reddy 		ioc_info(mrioc,
5254b64845a7SSreekanth Reddy 		    "returning previous reset result(%d) for the reset triggered by %s\n",
5255b64845a7SSreekanth Reddy 		    mrioc->prev_reset_result,
5256b64845a7SSreekanth Reddy 		    mpi3mr_reset_rc_name(reset_reason));
5257b64845a7SSreekanth Reddy 		return mrioc->prev_reset_result;
5258fb9b0457SKashyap Desai 	}
5259b64845a7SSreekanth Reddy 	ioc_info(mrioc, "controller reset is triggered by %s\n",
5260b64845a7SSreekanth Reddy 	    mpi3mr_reset_rc_name(reset_reason));
5261b64845a7SSreekanth Reddy 
52622745ce0eSSreekanth Reddy 	mrioc->device_refresh_on = 0;
5263fb9b0457SKashyap Desai 	mrioc->reset_in_progress = 1;
5264f5e6d5a3SSumit Saxena 	mrioc->stop_bsgs = 1;
5265b64845a7SSreekanth Reddy 	mrioc->prev_reset_result = -1;
5266d8d08d16SRanjan Kumar 	memset(&trigger_data, 0, sizeof(trigger_data));
5267fb9b0457SKashyap Desai 
5268fb9b0457SKashyap Desai 	if ((!snapdump) && (reset_reason != MPI3MR_RESET_FROM_FAULT_WATCH) &&
5269b64845a7SSreekanth Reddy 	    (reset_reason != MPI3MR_RESET_FROM_FIRMWARE) &&
5270fb9b0457SKashyap Desai 	    (reset_reason != MPI3MR_RESET_FROM_CIACTIV_FAULT)) {
5271d8d08d16SRanjan Kumar 		mpi3mr_set_trigger_data_in_all_hdb(mrioc,
5272d8d08d16SRanjan Kumar 		    MPI3MR_HDB_TRIGGER_TYPE_SOFT_RESET, NULL, 0);
5273fc444494SRanjan Kumar 		dprint_reset(mrioc,
5274fc444494SRanjan Kumar 		    "soft_reset_handler: releasing host diagnostic buffers\n");
5275fc444494SRanjan Kumar 		mpi3mr_release_diag_bufs(mrioc, 0);
5276fb9b0457SKashyap Desai 		for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
5277fb9b0457SKashyap Desai 			mrioc->event_masks[i] = -1;
5278fb9b0457SKashyap Desai 
5279b64845a7SSreekanth Reddy 		dprint_reset(mrioc, "soft_reset_handler: masking events\n");
5280b64845a7SSreekanth Reddy 		mpi3mr_issue_event_notification(mrioc);
5281fb9b0457SKashyap Desai 	}
5282fb9b0457SKashyap Desai 
528344dc724fSKashyap Desai 	mpi3mr_wait_for_host_io(mrioc, MPI3MR_RESET_HOST_IOWAIT_TIMEOUT);
528444dc724fSKashyap Desai 
5285fb9b0457SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
5286fb9b0457SKashyap Desai 
5287fb9b0457SKashyap Desai 	if (snapdump) {
5288fb9b0457SKashyap Desai 		mpi3mr_set_diagsave(mrioc);
5289fb9b0457SKashyap Desai 		retval = mpi3mr_issue_reset(mrioc,
5290fb9b0457SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
5291fb9b0457SKashyap Desai 		if (!retval) {
5292d8d08d16SRanjan Kumar 			trigger_data.fault = (readl(&mrioc->sysif_regs->fault) &
5293d8d08d16SRanjan Kumar 				      MPI3_SYSIF_FAULT_CODE_MASK);
5294fb9b0457SKashyap Desai 			do {
5295fb9b0457SKashyap Desai 				host_diagnostic =
5296fb9b0457SKashyap Desai 				    readl(&mrioc->sysif_regs->host_diagnostic);
5297fb9b0457SKashyap Desai 				if (!(host_diagnostic &
5298fb9b0457SKashyap Desai 				    MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS))
5299fb9b0457SKashyap Desai 					break;
5300fb9b0457SKashyap Desai 				msleep(100);
5301fb9b0457SKashyap Desai 			} while (--timeout);
5302d8d08d16SRanjan Kumar 			mpi3mr_set_trigger_data_in_all_hdb(mrioc,
5303d8d08d16SRanjan Kumar 			    MPI3MR_HDB_TRIGGER_TYPE_FAULT, &trigger_data, 0);
5304fb9b0457SKashyap Desai 		}
5305fb9b0457SKashyap Desai 	}
5306fb9b0457SKashyap Desai 
5307fb9b0457SKashyap Desai 	retval = mpi3mr_issue_reset(mrioc,
5308fb9b0457SKashyap Desai 	    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, reset_reason);
5309fb9b0457SKashyap Desai 	if (retval) {
5310fb9b0457SKashyap Desai 		ioc_err(mrioc, "Failed to issue soft reset to the ioc\n");
5311fb9b0457SKashyap Desai 		goto out;
5312fb9b0457SKashyap Desai 	}
5313f10af057SSreekanth Reddy 	if (mrioc->num_io_throttle_group !=
5314f10af057SSreekanth Reddy 	    mrioc->facts.max_io_throttle_group) {
5315f10af057SSreekanth Reddy 		ioc_err(mrioc,
5316f10af057SSreekanth Reddy 		    "max io throttle group doesn't match old(%d), new(%d)\n",
5317f10af057SSreekanth Reddy 		    mrioc->num_io_throttle_group,
5318f10af057SSreekanth Reddy 		    mrioc->facts.max_io_throttle_group);
53192a8a0147SDan Carpenter 		retval = -EPERM;
53202a8a0147SDan Carpenter 		goto out;
5321f10af057SSreekanth Reddy 	}
5322fb9b0457SKashyap Desai 
5323c1af985dSSreekanth Reddy 	mpi3mr_flush_delayed_cmd_lists(mrioc);
5324fb9b0457SKashyap Desai 	mpi3mr_flush_drv_cmds(mrioc);
5325339e6156SShin'ichiro Kawasaki 	bitmap_clear(mrioc->devrem_bitmap, 0, MPI3MR_NUM_DEVRMCMD);
5326339e6156SShin'ichiro Kawasaki 	bitmap_clear(mrioc->removepend_bitmap, 0,
5327339e6156SShin'ichiro Kawasaki 		     mrioc->dev_handle_bitmap_bits);
5328339e6156SShin'ichiro Kawasaki 	bitmap_clear(mrioc->evtack_cmds_bitmap, 0, MPI3MR_NUM_EVTACKCMD);
5329fb9b0457SKashyap Desai 	mpi3mr_flush_host_io(mrioc);
5330580e6742SSreekanth Reddy 	mpi3mr_cleanup_fwevt_list(mrioc);
5331fb9b0457SKashyap Desai 	mpi3mr_invalidate_devhandles(mrioc);
5332130fc180SSreekanth Reddy 	mpi3mr_free_enclosure_list(mrioc);
5333130fc180SSreekanth Reddy 
533478b76a07SSreekanth Reddy 	if (mrioc->prepare_for_reset) {
533578b76a07SSreekanth Reddy 		mrioc->prepare_for_reset = 0;
533678b76a07SSreekanth Reddy 		mrioc->prepare_for_reset_timeout_counter = 0;
533778b76a07SSreekanth Reddy 	}
5338fb9b0457SKashyap Desai 	mpi3mr_memset_buffers(mrioc);
5339fc444494SRanjan Kumar 	mpi3mr_release_diag_bufs(mrioc, 1);
5340d8d08d16SRanjan Kumar 	mrioc->fw_release_trigger_active = false;
5341d8d08d16SRanjan Kumar 	mrioc->trace_release_trigger_active = false;
5342d8d08d16SRanjan Kumar 	mrioc->snapdump_trigger_active = false;
5343d8d08d16SRanjan Kumar 	mpi3mr_set_trigger_data_in_all_hdb(mrioc,
5344d8d08d16SRanjan Kumar 	    MPI3MR_HDB_TRIGGER_TYPE_SOFT_RESET, NULL, 0);
5345d8d08d16SRanjan Kumar 
5346d8d08d16SRanjan Kumar 	dprint_reset(mrioc,
5347d8d08d16SRanjan Kumar 	    "soft_reset_handler: reinitializing the controller\n");
5348fe6db615SSreekanth Reddy 	retval = mpi3mr_reinit_ioc(mrioc, 0);
5349fb9b0457SKashyap Desai 	if (retval) {
5350fb9b0457SKashyap Desai 		pr_err(IOCNAME "reinit after soft reset failed: reason %d\n",
5351fb9b0457SKashyap Desai 		    mrioc->name, reset_reason);
5352fb9b0457SKashyap Desai 		goto out;
5353fb9b0457SKashyap Desai 	}
5354f84e8b5bSSreekanth Reddy 	ssleep(MPI3MR_RESET_TOPOLOGY_SETTLE_TIME);
5355fb9b0457SKashyap Desai 
5356fb9b0457SKashyap Desai out:
5357fb9b0457SKashyap Desai 	if (!retval) {
5358b64845a7SSreekanth Reddy 		mrioc->diagsave_timeout = 0;
5359fb9b0457SKashyap Desai 		mrioc->reset_in_progress = 0;
536043ca1100SSumit Saxena 		mrioc->pel_abort_requested = 0;
536143ca1100SSumit Saxena 		if (mrioc->pel_enabled) {
536243ca1100SSumit Saxena 			mrioc->pel_cmds.retry_count = 0;
536343ca1100SSumit Saxena 			mpi3mr_pel_wait_post(mrioc, &mrioc->pel_cmds);
536443ca1100SSumit Saxena 		}
536543ca1100SSumit Saxena 
53662745ce0eSSreekanth Reddy 		mrioc->device_refresh_on = 0;
53672745ce0eSSreekanth Reddy 
536854dfcffbSKashyap Desai 		mrioc->ts_update_counter = 0;
5369fb9b0457SKashyap Desai 		spin_lock_irqsave(&mrioc->watchdog_lock, flags);
5370fb9b0457SKashyap Desai 		if (mrioc->watchdog_work_q)
5371fb9b0457SKashyap Desai 			queue_delayed_work(mrioc->watchdog_work_q,
5372fb9b0457SKashyap Desai 			    &mrioc->watchdog_work,
5373fb9b0457SKashyap Desai 			    msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL));
5374fb9b0457SKashyap Desai 		spin_unlock_irqrestore(&mrioc->watchdog_lock, flags);
5375f5e6d5a3SSumit Saxena 		mrioc->stop_bsgs = 0;
537643ca1100SSumit Saxena 		if (mrioc->pel_enabled)
537743ca1100SSumit Saxena 			atomic64_inc(&event_counter);
5378fb9b0457SKashyap Desai 	} else {
5379fb9b0457SKashyap Desai 		mpi3mr_issue_reset(mrioc,
5380fb9b0457SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
53812745ce0eSSreekanth Reddy 		mrioc->device_refresh_on = 0;
5382fb9b0457SKashyap Desai 		mrioc->unrecoverable = 1;
5383fb9b0457SKashyap Desai 		mrioc->reset_in_progress = 0;
538431ec576eSRanjan Kumar 		mrioc->stop_bsgs = 0;
5385fb9b0457SKashyap Desai 		retval = -1;
5386f2a79d20SSreekanth Reddy 		mpi3mr_flush_cmds_for_unrecovered_controller(mrioc);
5387fb9b0457SKashyap Desai 	}
5388b64845a7SSreekanth Reddy 	mrioc->prev_reset_result = retval;
5389fb9b0457SKashyap Desai 	mutex_unlock(&mrioc->reset_mutex);
5390b64845a7SSreekanth Reddy 	ioc_info(mrioc, "controller reset is %s\n",
5391b64845a7SSreekanth Reddy 	    ((retval == 0) ? "successful" : "failed"));
5392fb9b0457SKashyap Desai 	return retval;
5393824a1566SKashyap Desai }
539432d457d5SSreekanth Reddy 
539532d457d5SSreekanth Reddy 
539632d457d5SSreekanth Reddy /**
539732d457d5SSreekanth Reddy  * mpi3mr_free_config_dma_memory - free memory for config page
539832d457d5SSreekanth Reddy  * @mrioc: Adapter instance reference
539932d457d5SSreekanth Reddy  * @mem_desc: memory descriptor structure
540032d457d5SSreekanth Reddy  *
540132d457d5SSreekanth Reddy  * Check whether the size of the buffer specified by the memory
540232d457d5SSreekanth Reddy  * descriptor is greater than the default page size if so then
540332d457d5SSreekanth Reddy  * free the memory pointed by the descriptor.
540432d457d5SSreekanth Reddy  *
540532d457d5SSreekanth Reddy  * Return: Nothing.
540632d457d5SSreekanth Reddy  */
mpi3mr_free_config_dma_memory(struct mpi3mr_ioc * mrioc,struct dma_memory_desc * mem_desc)540732d457d5SSreekanth Reddy static void mpi3mr_free_config_dma_memory(struct mpi3mr_ioc *mrioc,
540832d457d5SSreekanth Reddy 	struct dma_memory_desc *mem_desc)
540932d457d5SSreekanth Reddy {
541032d457d5SSreekanth Reddy 	if ((mem_desc->size > mrioc->cfg_page_sz) && mem_desc->addr) {
541132d457d5SSreekanth Reddy 		dma_free_coherent(&mrioc->pdev->dev, mem_desc->size,
541232d457d5SSreekanth Reddy 		    mem_desc->addr, mem_desc->dma_addr);
541332d457d5SSreekanth Reddy 		mem_desc->addr = NULL;
541432d457d5SSreekanth Reddy 	}
541532d457d5SSreekanth Reddy }
541632d457d5SSreekanth Reddy 
541732d457d5SSreekanth Reddy /**
541832d457d5SSreekanth Reddy  * mpi3mr_alloc_config_dma_memory - Alloc memory for config page
541932d457d5SSreekanth Reddy  * @mrioc: Adapter instance reference
542032d457d5SSreekanth Reddy  * @mem_desc: Memory descriptor to hold dma memory info
542132d457d5SSreekanth Reddy  *
542232d457d5SSreekanth Reddy  * This function allocates new dmaable memory or provides the
542332d457d5SSreekanth Reddy  * default config page dmaable memory based on the memory size
542432d457d5SSreekanth Reddy  * described by the descriptor.
542532d457d5SSreekanth Reddy  *
542632d457d5SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
542732d457d5SSreekanth Reddy  */
mpi3mr_alloc_config_dma_memory(struct mpi3mr_ioc * mrioc,struct dma_memory_desc * mem_desc)542832d457d5SSreekanth Reddy static int mpi3mr_alloc_config_dma_memory(struct mpi3mr_ioc *mrioc,
542932d457d5SSreekanth Reddy 	struct dma_memory_desc *mem_desc)
543032d457d5SSreekanth Reddy {
543132d457d5SSreekanth Reddy 	if (mem_desc->size > mrioc->cfg_page_sz) {
543232d457d5SSreekanth Reddy 		mem_desc->addr = dma_alloc_coherent(&mrioc->pdev->dev,
543332d457d5SSreekanth Reddy 		    mem_desc->size, &mem_desc->dma_addr, GFP_KERNEL);
543432d457d5SSreekanth Reddy 		if (!mem_desc->addr)
543532d457d5SSreekanth Reddy 			return -ENOMEM;
543632d457d5SSreekanth Reddy 	} else {
543732d457d5SSreekanth Reddy 		mem_desc->addr = mrioc->cfg_page;
543832d457d5SSreekanth Reddy 		mem_desc->dma_addr = mrioc->cfg_page_dma;
543932d457d5SSreekanth Reddy 		memset(mem_desc->addr, 0, mrioc->cfg_page_sz);
544032d457d5SSreekanth Reddy 	}
544132d457d5SSreekanth Reddy 	return 0;
544232d457d5SSreekanth Reddy }
544332d457d5SSreekanth Reddy 
544432d457d5SSreekanth Reddy /**
544532d457d5SSreekanth Reddy  * mpi3mr_post_cfg_req - Issue config requests and wait
544632d457d5SSreekanth Reddy  * @mrioc: Adapter instance reference
544732d457d5SSreekanth Reddy  * @cfg_req: Configuration request
544832d457d5SSreekanth Reddy  * @timeout: Timeout in seconds
544932d457d5SSreekanth Reddy  * @ioc_status: Pointer to return ioc status
545032d457d5SSreekanth Reddy  *
545132d457d5SSreekanth Reddy  * A generic function for posting MPI3 configuration request to
545232d457d5SSreekanth Reddy  * the firmware. This blocks for the completion of request for
545332d457d5SSreekanth Reddy  * timeout seconds and if the request times out this function
545432d457d5SSreekanth Reddy  * faults the controller with proper reason code.
545532d457d5SSreekanth Reddy  *
545632d457d5SSreekanth Reddy  * On successful completion of the request this function returns
545732d457d5SSreekanth Reddy  * appropriate ioc status from the firmware back to the caller.
545832d457d5SSreekanth Reddy  *
545932d457d5SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
546032d457d5SSreekanth Reddy  */
mpi3mr_post_cfg_req(struct mpi3mr_ioc * mrioc,struct mpi3_config_request * cfg_req,int timeout,u16 * ioc_status)546132d457d5SSreekanth Reddy static int mpi3mr_post_cfg_req(struct mpi3mr_ioc *mrioc,
546232d457d5SSreekanth Reddy 	struct mpi3_config_request *cfg_req, int timeout, u16 *ioc_status)
546332d457d5SSreekanth Reddy {
546432d457d5SSreekanth Reddy 	int retval = 0;
546532d457d5SSreekanth Reddy 
546632d457d5SSreekanth Reddy 	mutex_lock(&mrioc->cfg_cmds.mutex);
546732d457d5SSreekanth Reddy 	if (mrioc->cfg_cmds.state & MPI3MR_CMD_PENDING) {
546832d457d5SSreekanth Reddy 		retval = -1;
546932d457d5SSreekanth Reddy 		ioc_err(mrioc, "sending config request failed due to command in use\n");
547032d457d5SSreekanth Reddy 		mutex_unlock(&mrioc->cfg_cmds.mutex);
547132d457d5SSreekanth Reddy 		goto out;
547232d457d5SSreekanth Reddy 	}
547332d457d5SSreekanth Reddy 	mrioc->cfg_cmds.state = MPI3MR_CMD_PENDING;
547432d457d5SSreekanth Reddy 	mrioc->cfg_cmds.is_waiting = 1;
547532d457d5SSreekanth Reddy 	mrioc->cfg_cmds.callback = NULL;
547632d457d5SSreekanth Reddy 	mrioc->cfg_cmds.ioc_status = 0;
547732d457d5SSreekanth Reddy 	mrioc->cfg_cmds.ioc_loginfo = 0;
547832d457d5SSreekanth Reddy 
547932d457d5SSreekanth Reddy 	cfg_req->host_tag = cpu_to_le16(MPI3MR_HOSTTAG_CFG_CMDS);
548032d457d5SSreekanth Reddy 	cfg_req->function = MPI3_FUNCTION_CONFIG;
548132d457d5SSreekanth Reddy 
548232d457d5SSreekanth Reddy 	init_completion(&mrioc->cfg_cmds.done);
548332d457d5SSreekanth Reddy 	dprint_cfg_info(mrioc, "posting config request\n");
548432d457d5SSreekanth Reddy 	if (mrioc->logging_level & MPI3_DEBUG_CFG_INFO)
548532d457d5SSreekanth Reddy 		dprint_dump(cfg_req, sizeof(struct mpi3_config_request),
548632d457d5SSreekanth Reddy 		    "mpi3_cfg_req");
548732d457d5SSreekanth Reddy 	retval = mpi3mr_admin_request_post(mrioc, cfg_req, sizeof(*cfg_req), 1);
548832d457d5SSreekanth Reddy 	if (retval) {
548932d457d5SSreekanth Reddy 		ioc_err(mrioc, "posting config request failed\n");
549032d457d5SSreekanth Reddy 		goto out_unlock;
549132d457d5SSreekanth Reddy 	}
549232d457d5SSreekanth Reddy 	wait_for_completion_timeout(&mrioc->cfg_cmds.done, (timeout * HZ));
549332d457d5SSreekanth Reddy 	if (!(mrioc->cfg_cmds.state & MPI3MR_CMD_COMPLETE)) {
549432d457d5SSreekanth Reddy 		mpi3mr_check_rh_fault_ioc(mrioc,
549532d457d5SSreekanth Reddy 		    MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT);
549632d457d5SSreekanth Reddy 		ioc_err(mrioc, "config request timed out\n");
549732d457d5SSreekanth Reddy 		retval = -1;
549832d457d5SSreekanth Reddy 		goto out_unlock;
549932d457d5SSreekanth Reddy 	}
550032d457d5SSreekanth Reddy 	*ioc_status = mrioc->cfg_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK;
550132d457d5SSreekanth Reddy 	if ((*ioc_status) != MPI3_IOCSTATUS_SUCCESS)
550232d457d5SSreekanth Reddy 		dprint_cfg_err(mrioc,
550332d457d5SSreekanth Reddy 		    "cfg_page request returned with ioc_status(0x%04x), log_info(0x%08x)\n",
550432d457d5SSreekanth Reddy 		    *ioc_status, mrioc->cfg_cmds.ioc_loginfo);
550532d457d5SSreekanth Reddy 
550632d457d5SSreekanth Reddy out_unlock:
550732d457d5SSreekanth Reddy 	mrioc->cfg_cmds.state = MPI3MR_CMD_NOTUSED;
550832d457d5SSreekanth Reddy 	mutex_unlock(&mrioc->cfg_cmds.mutex);
550932d457d5SSreekanth Reddy 
551032d457d5SSreekanth Reddy out:
551132d457d5SSreekanth Reddy 	return retval;
551232d457d5SSreekanth Reddy }
551332d457d5SSreekanth Reddy 
551432d457d5SSreekanth Reddy /**
551532d457d5SSreekanth Reddy  * mpi3mr_process_cfg_req - config page request processor
551632d457d5SSreekanth Reddy  * @mrioc: Adapter instance reference
551732d457d5SSreekanth Reddy  * @cfg_req: Configuration request
551832d457d5SSreekanth Reddy  * @cfg_hdr: Configuration page header
551932d457d5SSreekanth Reddy  * @timeout: Timeout in seconds
552032d457d5SSreekanth Reddy  * @ioc_status: Pointer to return ioc status
552132d457d5SSreekanth Reddy  * @cfg_buf: Memory pointer to copy config page or header
552232d457d5SSreekanth Reddy  * @cfg_buf_sz: Size of the memory to get config page or header
552332d457d5SSreekanth Reddy  *
552432d457d5SSreekanth Reddy  * This is handler for config page read, write and config page
552532d457d5SSreekanth Reddy  * header read operations.
552632d457d5SSreekanth Reddy  *
552732d457d5SSreekanth Reddy  * This function expects the cfg_req to be populated with page
552832d457d5SSreekanth Reddy  * type, page number, action for the header read and with page
552932d457d5SSreekanth Reddy  * address for all other operations.
553032d457d5SSreekanth Reddy  *
553132d457d5SSreekanth Reddy  * The cfg_hdr can be passed as null for reading required header
553232d457d5SSreekanth Reddy  * details for read/write pages the cfg_hdr should point valid
553332d457d5SSreekanth Reddy  * configuration page header.
553432d457d5SSreekanth Reddy  *
553532d457d5SSreekanth Reddy  * This allocates dmaable memory based on the size of the config
553632d457d5SSreekanth Reddy  * buffer and set the SGE of the cfg_req.
553732d457d5SSreekanth Reddy  *
553832d457d5SSreekanth Reddy  * For write actions, the config page data has to be passed in
553932d457d5SSreekanth Reddy  * the cfg_buf and size of the data has to be mentioned in the
554032d457d5SSreekanth Reddy  * cfg_buf_sz.
554132d457d5SSreekanth Reddy  *
554232d457d5SSreekanth Reddy  * For read/header actions, on successful completion of the
554332d457d5SSreekanth Reddy  * request with successful ioc_status the data will be copied
554432d457d5SSreekanth Reddy  * into the cfg_buf limited to a minimum of actual page size and
554532d457d5SSreekanth Reddy  * cfg_buf_sz
554632d457d5SSreekanth Reddy  *
554732d457d5SSreekanth Reddy  *
554832d457d5SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
554932d457d5SSreekanth Reddy  */
mpi3mr_process_cfg_req(struct mpi3mr_ioc * mrioc,struct mpi3_config_request * cfg_req,struct mpi3_config_page_header * cfg_hdr,int timeout,u16 * ioc_status,void * cfg_buf,u32 cfg_buf_sz)555032d457d5SSreekanth Reddy static int mpi3mr_process_cfg_req(struct mpi3mr_ioc *mrioc,
555132d457d5SSreekanth Reddy 	struct mpi3_config_request *cfg_req,
555232d457d5SSreekanth Reddy 	struct mpi3_config_page_header *cfg_hdr, int timeout, u16 *ioc_status,
555332d457d5SSreekanth Reddy 	void *cfg_buf, u32 cfg_buf_sz)
555432d457d5SSreekanth Reddy {
555532d457d5SSreekanth Reddy 	struct dma_memory_desc mem_desc;
555632d457d5SSreekanth Reddy 	int retval = -1;
555732d457d5SSreekanth Reddy 	u8 invalid_action = 0;
555832d457d5SSreekanth Reddy 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
555932d457d5SSreekanth Reddy 
556032d457d5SSreekanth Reddy 	memset(&mem_desc, 0, sizeof(struct dma_memory_desc));
556132d457d5SSreekanth Reddy 
556232d457d5SSreekanth Reddy 	if (cfg_req->action == MPI3_CONFIG_ACTION_PAGE_HEADER)
556332d457d5SSreekanth Reddy 		mem_desc.size = sizeof(struct mpi3_config_page_header);
556432d457d5SSreekanth Reddy 	else {
556532d457d5SSreekanth Reddy 		if (!cfg_hdr) {
556632d457d5SSreekanth Reddy 			ioc_err(mrioc, "null config header passed for config action(%d), page_type(0x%02x), page_num(%d)\n",
556732d457d5SSreekanth Reddy 			    cfg_req->action, cfg_req->page_type,
556832d457d5SSreekanth Reddy 			    cfg_req->page_number);
556932d457d5SSreekanth Reddy 			goto out;
557032d457d5SSreekanth Reddy 		}
557132d457d5SSreekanth Reddy 		switch (cfg_hdr->page_attribute & MPI3_CONFIG_PAGEATTR_MASK) {
557232d457d5SSreekanth Reddy 		case MPI3_CONFIG_PAGEATTR_READ_ONLY:
557332d457d5SSreekanth Reddy 			if (cfg_req->action
557432d457d5SSreekanth Reddy 			    != MPI3_CONFIG_ACTION_READ_CURRENT)
557532d457d5SSreekanth Reddy 				invalid_action = 1;
557632d457d5SSreekanth Reddy 			break;
557732d457d5SSreekanth Reddy 		case MPI3_CONFIG_PAGEATTR_CHANGEABLE:
557832d457d5SSreekanth Reddy 			if ((cfg_req->action ==
557932d457d5SSreekanth Reddy 			     MPI3_CONFIG_ACTION_READ_PERSISTENT) ||
558032d457d5SSreekanth Reddy 			    (cfg_req->action ==
558132d457d5SSreekanth Reddy 			     MPI3_CONFIG_ACTION_WRITE_PERSISTENT))
558232d457d5SSreekanth Reddy 				invalid_action = 1;
558332d457d5SSreekanth Reddy 			break;
558432d457d5SSreekanth Reddy 		case MPI3_CONFIG_PAGEATTR_PERSISTENT:
558532d457d5SSreekanth Reddy 		default:
558632d457d5SSreekanth Reddy 			break;
558732d457d5SSreekanth Reddy 		}
558832d457d5SSreekanth Reddy 		if (invalid_action) {
558932d457d5SSreekanth Reddy 			ioc_err(mrioc,
559032d457d5SSreekanth Reddy 			    "config action(%d) is not allowed for page_type(0x%02x), page_num(%d) with page_attribute(0x%02x)\n",
559132d457d5SSreekanth Reddy 			    cfg_req->action, cfg_req->page_type,
559232d457d5SSreekanth Reddy 			    cfg_req->page_number, cfg_hdr->page_attribute);
559332d457d5SSreekanth Reddy 			goto out;
559432d457d5SSreekanth Reddy 		}
559532d457d5SSreekanth Reddy 		mem_desc.size = le16_to_cpu(cfg_hdr->page_length) * 4;
559632d457d5SSreekanth Reddy 		cfg_req->page_length = cfg_hdr->page_length;
559732d457d5SSreekanth Reddy 		cfg_req->page_version = cfg_hdr->page_version;
559832d457d5SSreekanth Reddy 	}
559932d457d5SSreekanth Reddy 	if (mpi3mr_alloc_config_dma_memory(mrioc, &mem_desc))
560032d457d5SSreekanth Reddy 		goto out;
560132d457d5SSreekanth Reddy 
560232d457d5SSreekanth Reddy 	mpi3mr_add_sg_single(&cfg_req->sgl, sgl_flags, mem_desc.size,
560332d457d5SSreekanth Reddy 	    mem_desc.dma_addr);
560432d457d5SSreekanth Reddy 
560532d457d5SSreekanth Reddy 	if ((cfg_req->action == MPI3_CONFIG_ACTION_WRITE_PERSISTENT) ||
560632d457d5SSreekanth Reddy 	    (cfg_req->action == MPI3_CONFIG_ACTION_WRITE_CURRENT)) {
560732d457d5SSreekanth Reddy 		memcpy(mem_desc.addr, cfg_buf, min_t(u16, mem_desc.size,
560832d457d5SSreekanth Reddy 		    cfg_buf_sz));
560932d457d5SSreekanth Reddy 		dprint_cfg_info(mrioc, "config buffer to be written\n");
561032d457d5SSreekanth Reddy 		if (mrioc->logging_level & MPI3_DEBUG_CFG_INFO)
561132d457d5SSreekanth Reddy 			dprint_dump(mem_desc.addr, mem_desc.size, "cfg_buf");
561232d457d5SSreekanth Reddy 	}
561332d457d5SSreekanth Reddy 
561432d457d5SSreekanth Reddy 	if (mpi3mr_post_cfg_req(mrioc, cfg_req, timeout, ioc_status))
561532d457d5SSreekanth Reddy 		goto out;
561632d457d5SSreekanth Reddy 
561732d457d5SSreekanth Reddy 	retval = 0;
561832d457d5SSreekanth Reddy 	if ((*ioc_status == MPI3_IOCSTATUS_SUCCESS) &&
561932d457d5SSreekanth Reddy 	    (cfg_req->action != MPI3_CONFIG_ACTION_WRITE_PERSISTENT) &&
562032d457d5SSreekanth Reddy 	    (cfg_req->action != MPI3_CONFIG_ACTION_WRITE_CURRENT)) {
562132d457d5SSreekanth Reddy 		memcpy(cfg_buf, mem_desc.addr, min_t(u16, mem_desc.size,
562232d457d5SSreekanth Reddy 		    cfg_buf_sz));
562332d457d5SSreekanth Reddy 		dprint_cfg_info(mrioc, "config buffer read\n");
562432d457d5SSreekanth Reddy 		if (mrioc->logging_level & MPI3_DEBUG_CFG_INFO)
562532d457d5SSreekanth Reddy 			dprint_dump(mem_desc.addr, mem_desc.size, "cfg_buf");
562632d457d5SSreekanth Reddy 	}
562732d457d5SSreekanth Reddy 
562832d457d5SSreekanth Reddy out:
562932d457d5SSreekanth Reddy 	mpi3mr_free_config_dma_memory(mrioc, &mem_desc);
563032d457d5SSreekanth Reddy 	return retval;
563132d457d5SSreekanth Reddy }
563264a8d931SSreekanth Reddy 
563364a8d931SSreekanth Reddy /**
563464a8d931SSreekanth Reddy  * mpi3mr_cfg_get_dev_pg0 - Read current device page0
563564a8d931SSreekanth Reddy  * @mrioc: Adapter instance reference
563664a8d931SSreekanth Reddy  * @ioc_status: Pointer to return ioc status
563764a8d931SSreekanth Reddy  * @dev_pg0: Pointer to return device page 0
563864a8d931SSreekanth Reddy  * @pg_sz: Size of the memory allocated to the page pointer
563964a8d931SSreekanth Reddy  * @form: The form to be used for addressing the page
564064a8d931SSreekanth Reddy  * @form_spec: Form specific information like device handle
564164a8d931SSreekanth Reddy  *
564264a8d931SSreekanth Reddy  * This is handler for config page read for a specific device
564364a8d931SSreekanth Reddy  * page0. The ioc_status has the controller returned ioc_status.
564464a8d931SSreekanth Reddy  * This routine doesn't check ioc_status to decide whether the
564564a8d931SSreekanth Reddy  * page read is success or not and it is the callers
564664a8d931SSreekanth Reddy  * responsibility.
564764a8d931SSreekanth Reddy  *
564864a8d931SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
564964a8d931SSreekanth Reddy  */
mpi3mr_cfg_get_dev_pg0(struct mpi3mr_ioc * mrioc,u16 * ioc_status,struct mpi3_device_page0 * dev_pg0,u16 pg_sz,u32 form,u32 form_spec)565064a8d931SSreekanth Reddy int mpi3mr_cfg_get_dev_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
565164a8d931SSreekanth Reddy 	struct mpi3_device_page0 *dev_pg0, u16 pg_sz, u32 form, u32 form_spec)
565264a8d931SSreekanth Reddy {
565364a8d931SSreekanth Reddy 	struct mpi3_config_page_header cfg_hdr;
565464a8d931SSreekanth Reddy 	struct mpi3_config_request cfg_req;
565564a8d931SSreekanth Reddy 	u32 page_address;
565664a8d931SSreekanth Reddy 
565764a8d931SSreekanth Reddy 	memset(dev_pg0, 0, pg_sz);
565864a8d931SSreekanth Reddy 	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
565964a8d931SSreekanth Reddy 	memset(&cfg_req, 0, sizeof(cfg_req));
566064a8d931SSreekanth Reddy 
566164a8d931SSreekanth Reddy 	cfg_req.function = MPI3_FUNCTION_CONFIG;
566264a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
566364a8d931SSreekanth Reddy 	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_DEVICE;
566464a8d931SSreekanth Reddy 	cfg_req.page_number = 0;
566564a8d931SSreekanth Reddy 	cfg_req.page_address = 0;
566664a8d931SSreekanth Reddy 
566764a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
566864a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
566964a8d931SSreekanth Reddy 		ioc_err(mrioc, "device page0 header read failed\n");
567064a8d931SSreekanth Reddy 		goto out_failed;
567164a8d931SSreekanth Reddy 	}
567264a8d931SSreekanth Reddy 	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
567364a8d931SSreekanth Reddy 		ioc_err(mrioc, "device page0 header read failed with ioc_status(0x%04x)\n",
567464a8d931SSreekanth Reddy 		    *ioc_status);
567564a8d931SSreekanth Reddy 		goto out_failed;
567664a8d931SSreekanth Reddy 	}
567764a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
567864a8d931SSreekanth Reddy 	page_address = ((form & MPI3_DEVICE_PGAD_FORM_MASK) |
567964a8d931SSreekanth Reddy 	    (form_spec & MPI3_DEVICE_PGAD_HANDLE_MASK));
568064a8d931SSreekanth Reddy 	cfg_req.page_address = cpu_to_le32(page_address);
568164a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
568264a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, dev_pg0, pg_sz)) {
568364a8d931SSreekanth Reddy 		ioc_err(mrioc, "device page0 read failed\n");
568464a8d931SSreekanth Reddy 		goto out_failed;
568564a8d931SSreekanth Reddy 	}
568664a8d931SSreekanth Reddy 	return 0;
568764a8d931SSreekanth Reddy out_failed:
568864a8d931SSreekanth Reddy 	return -1;
568964a8d931SSreekanth Reddy }
569064a8d931SSreekanth Reddy 
569164a8d931SSreekanth Reddy 
569264a8d931SSreekanth Reddy /**
569364a8d931SSreekanth Reddy  * mpi3mr_cfg_get_sas_phy_pg0 - Read current SAS Phy page0
569464a8d931SSreekanth Reddy  * @mrioc: Adapter instance reference
569564a8d931SSreekanth Reddy  * @ioc_status: Pointer to return ioc status
569664a8d931SSreekanth Reddy  * @phy_pg0: Pointer to return SAS Phy page 0
569764a8d931SSreekanth Reddy  * @pg_sz: Size of the memory allocated to the page pointer
569864a8d931SSreekanth Reddy  * @form: The form to be used for addressing the page
569964a8d931SSreekanth Reddy  * @form_spec: Form specific information like phy number
570064a8d931SSreekanth Reddy  *
570164a8d931SSreekanth Reddy  * This is handler for config page read for a specific SAS Phy
570264a8d931SSreekanth Reddy  * page0. The ioc_status has the controller returned ioc_status.
570364a8d931SSreekanth Reddy  * This routine doesn't check ioc_status to decide whether the
570464a8d931SSreekanth Reddy  * page read is success or not and it is the callers
570564a8d931SSreekanth Reddy  * responsibility.
570664a8d931SSreekanth Reddy  *
570764a8d931SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
570864a8d931SSreekanth Reddy  */
mpi3mr_cfg_get_sas_phy_pg0(struct mpi3mr_ioc * mrioc,u16 * ioc_status,struct mpi3_sas_phy_page0 * phy_pg0,u16 pg_sz,u32 form,u32 form_spec)570964a8d931SSreekanth Reddy int mpi3mr_cfg_get_sas_phy_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
571064a8d931SSreekanth Reddy 	struct mpi3_sas_phy_page0 *phy_pg0, u16 pg_sz, u32 form,
571164a8d931SSreekanth Reddy 	u32 form_spec)
571264a8d931SSreekanth Reddy {
571364a8d931SSreekanth Reddy 	struct mpi3_config_page_header cfg_hdr;
571464a8d931SSreekanth Reddy 	struct mpi3_config_request cfg_req;
571564a8d931SSreekanth Reddy 	u32 page_address;
571664a8d931SSreekanth Reddy 
571764a8d931SSreekanth Reddy 	memset(phy_pg0, 0, pg_sz);
571864a8d931SSreekanth Reddy 	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
571964a8d931SSreekanth Reddy 	memset(&cfg_req, 0, sizeof(cfg_req));
572064a8d931SSreekanth Reddy 
572164a8d931SSreekanth Reddy 	cfg_req.function = MPI3_FUNCTION_CONFIG;
572264a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
572364a8d931SSreekanth Reddy 	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_PHY;
572464a8d931SSreekanth Reddy 	cfg_req.page_number = 0;
572564a8d931SSreekanth Reddy 	cfg_req.page_address = 0;
572664a8d931SSreekanth Reddy 
572764a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
572864a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
572964a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas phy page0 header read failed\n");
573064a8d931SSreekanth Reddy 		goto out_failed;
573164a8d931SSreekanth Reddy 	}
573264a8d931SSreekanth Reddy 	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
573364a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas phy page0 header read failed with ioc_status(0x%04x)\n",
573464a8d931SSreekanth Reddy 		    *ioc_status);
573564a8d931SSreekanth Reddy 		goto out_failed;
573664a8d931SSreekanth Reddy 	}
573764a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
573864a8d931SSreekanth Reddy 	page_address = ((form & MPI3_SAS_PHY_PGAD_FORM_MASK) |
573964a8d931SSreekanth Reddy 	    (form_spec & MPI3_SAS_PHY_PGAD_PHY_NUMBER_MASK));
574064a8d931SSreekanth Reddy 	cfg_req.page_address = cpu_to_le32(page_address);
574164a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
574264a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, phy_pg0, pg_sz)) {
574364a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas phy page0 read failed\n");
574464a8d931SSreekanth Reddy 		goto out_failed;
574564a8d931SSreekanth Reddy 	}
574664a8d931SSreekanth Reddy 	return 0;
574764a8d931SSreekanth Reddy out_failed:
574864a8d931SSreekanth Reddy 	return -1;
574964a8d931SSreekanth Reddy }
575064a8d931SSreekanth Reddy 
575164a8d931SSreekanth Reddy /**
575264a8d931SSreekanth Reddy  * mpi3mr_cfg_get_sas_phy_pg1 - Read current SAS Phy page1
575364a8d931SSreekanth Reddy  * @mrioc: Adapter instance reference
575464a8d931SSreekanth Reddy  * @ioc_status: Pointer to return ioc status
575564a8d931SSreekanth Reddy  * @phy_pg1: Pointer to return SAS Phy page 1
575664a8d931SSreekanth Reddy  * @pg_sz: Size of the memory allocated to the page pointer
575764a8d931SSreekanth Reddy  * @form: The form to be used for addressing the page
575864a8d931SSreekanth Reddy  * @form_spec: Form specific information like phy number
575964a8d931SSreekanth Reddy  *
576064a8d931SSreekanth Reddy  * This is handler for config page read for a specific SAS Phy
576164a8d931SSreekanth Reddy  * page1. The ioc_status has the controller returned ioc_status.
576264a8d931SSreekanth Reddy  * This routine doesn't check ioc_status to decide whether the
576364a8d931SSreekanth Reddy  * page read is success or not and it is the callers
576464a8d931SSreekanth Reddy  * responsibility.
576564a8d931SSreekanth Reddy  *
576664a8d931SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
576764a8d931SSreekanth Reddy  */
mpi3mr_cfg_get_sas_phy_pg1(struct mpi3mr_ioc * mrioc,u16 * ioc_status,struct mpi3_sas_phy_page1 * phy_pg1,u16 pg_sz,u32 form,u32 form_spec)576864a8d931SSreekanth Reddy int mpi3mr_cfg_get_sas_phy_pg1(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
576964a8d931SSreekanth Reddy 	struct mpi3_sas_phy_page1 *phy_pg1, u16 pg_sz, u32 form,
577064a8d931SSreekanth Reddy 	u32 form_spec)
577164a8d931SSreekanth Reddy {
577264a8d931SSreekanth Reddy 	struct mpi3_config_page_header cfg_hdr;
577364a8d931SSreekanth Reddy 	struct mpi3_config_request cfg_req;
577464a8d931SSreekanth Reddy 	u32 page_address;
577564a8d931SSreekanth Reddy 
577664a8d931SSreekanth Reddy 	memset(phy_pg1, 0, pg_sz);
577764a8d931SSreekanth Reddy 	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
577864a8d931SSreekanth Reddy 	memset(&cfg_req, 0, sizeof(cfg_req));
577964a8d931SSreekanth Reddy 
578064a8d931SSreekanth Reddy 	cfg_req.function = MPI3_FUNCTION_CONFIG;
578164a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
578264a8d931SSreekanth Reddy 	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_PHY;
578364a8d931SSreekanth Reddy 	cfg_req.page_number = 1;
578464a8d931SSreekanth Reddy 	cfg_req.page_address = 0;
578564a8d931SSreekanth Reddy 
578664a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
578764a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
578864a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas phy page1 header read failed\n");
578964a8d931SSreekanth Reddy 		goto out_failed;
579064a8d931SSreekanth Reddy 	}
579164a8d931SSreekanth Reddy 	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
579264a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas phy page1 header read failed with ioc_status(0x%04x)\n",
579364a8d931SSreekanth Reddy 		    *ioc_status);
579464a8d931SSreekanth Reddy 		goto out_failed;
579564a8d931SSreekanth Reddy 	}
579664a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
579764a8d931SSreekanth Reddy 	page_address = ((form & MPI3_SAS_PHY_PGAD_FORM_MASK) |
579864a8d931SSreekanth Reddy 	    (form_spec & MPI3_SAS_PHY_PGAD_PHY_NUMBER_MASK));
579964a8d931SSreekanth Reddy 	cfg_req.page_address = cpu_to_le32(page_address);
580064a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
580164a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, phy_pg1, pg_sz)) {
580264a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas phy page1 read failed\n");
580364a8d931SSreekanth Reddy 		goto out_failed;
580464a8d931SSreekanth Reddy 	}
580564a8d931SSreekanth Reddy 	return 0;
580664a8d931SSreekanth Reddy out_failed:
580764a8d931SSreekanth Reddy 	return -1;
580864a8d931SSreekanth Reddy }
580964a8d931SSreekanth Reddy 
581064a8d931SSreekanth Reddy 
581164a8d931SSreekanth Reddy /**
581264a8d931SSreekanth Reddy  * mpi3mr_cfg_get_sas_exp_pg0 - Read current SAS Expander page0
581364a8d931SSreekanth Reddy  * @mrioc: Adapter instance reference
581464a8d931SSreekanth Reddy  * @ioc_status: Pointer to return ioc status
581564a8d931SSreekanth Reddy  * @exp_pg0: Pointer to return SAS Expander page 0
581664a8d931SSreekanth Reddy  * @pg_sz: Size of the memory allocated to the page pointer
581764a8d931SSreekanth Reddy  * @form: The form to be used for addressing the page
581864a8d931SSreekanth Reddy  * @form_spec: Form specific information like device handle
581964a8d931SSreekanth Reddy  *
582064a8d931SSreekanth Reddy  * This is handler for config page read for a specific SAS
582164a8d931SSreekanth Reddy  * Expander page0. The ioc_status has the controller returned
582264a8d931SSreekanth Reddy  * ioc_status. This routine doesn't check ioc_status to decide
582364a8d931SSreekanth Reddy  * whether the page read is success or not and it is the callers
582464a8d931SSreekanth Reddy  * responsibility.
582564a8d931SSreekanth Reddy  *
582664a8d931SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
582764a8d931SSreekanth Reddy  */
mpi3mr_cfg_get_sas_exp_pg0(struct mpi3mr_ioc * mrioc,u16 * ioc_status,struct mpi3_sas_expander_page0 * exp_pg0,u16 pg_sz,u32 form,u32 form_spec)582864a8d931SSreekanth Reddy int mpi3mr_cfg_get_sas_exp_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
582964a8d931SSreekanth Reddy 	struct mpi3_sas_expander_page0 *exp_pg0, u16 pg_sz, u32 form,
583064a8d931SSreekanth Reddy 	u32 form_spec)
583164a8d931SSreekanth Reddy {
583264a8d931SSreekanth Reddy 	struct mpi3_config_page_header cfg_hdr;
583364a8d931SSreekanth Reddy 	struct mpi3_config_request cfg_req;
583464a8d931SSreekanth Reddy 	u32 page_address;
583564a8d931SSreekanth Reddy 
583664a8d931SSreekanth Reddy 	memset(exp_pg0, 0, pg_sz);
583764a8d931SSreekanth Reddy 	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
583864a8d931SSreekanth Reddy 	memset(&cfg_req, 0, sizeof(cfg_req));
583964a8d931SSreekanth Reddy 
584064a8d931SSreekanth Reddy 	cfg_req.function = MPI3_FUNCTION_CONFIG;
584164a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
584264a8d931SSreekanth Reddy 	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_EXPANDER;
584364a8d931SSreekanth Reddy 	cfg_req.page_number = 0;
584464a8d931SSreekanth Reddy 	cfg_req.page_address = 0;
584564a8d931SSreekanth Reddy 
584664a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
584764a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
584864a8d931SSreekanth Reddy 		ioc_err(mrioc, "expander page0 header read failed\n");
584964a8d931SSreekanth Reddy 		goto out_failed;
585064a8d931SSreekanth Reddy 	}
585164a8d931SSreekanth Reddy 	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
585264a8d931SSreekanth Reddy 		ioc_err(mrioc, "expander page0 header read failed with ioc_status(0x%04x)\n",
585364a8d931SSreekanth Reddy 		    *ioc_status);
585464a8d931SSreekanth Reddy 		goto out_failed;
585564a8d931SSreekanth Reddy 	}
585664a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
585764a8d931SSreekanth Reddy 	page_address = ((form & MPI3_SAS_EXPAND_PGAD_FORM_MASK) |
585864a8d931SSreekanth Reddy 	    (form_spec & (MPI3_SAS_EXPAND_PGAD_PHYNUM_MASK |
585964a8d931SSreekanth Reddy 	    MPI3_SAS_EXPAND_PGAD_HANDLE_MASK)));
586064a8d931SSreekanth Reddy 	cfg_req.page_address = cpu_to_le32(page_address);
586164a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
586264a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, exp_pg0, pg_sz)) {
586364a8d931SSreekanth Reddy 		ioc_err(mrioc, "expander page0 read failed\n");
586464a8d931SSreekanth Reddy 		goto out_failed;
586564a8d931SSreekanth Reddy 	}
586664a8d931SSreekanth Reddy 	return 0;
586764a8d931SSreekanth Reddy out_failed:
586864a8d931SSreekanth Reddy 	return -1;
586964a8d931SSreekanth Reddy }
587064a8d931SSreekanth Reddy 
587164a8d931SSreekanth Reddy /**
587264a8d931SSreekanth Reddy  * mpi3mr_cfg_get_sas_exp_pg1 - Read current SAS Expander page1
587364a8d931SSreekanth Reddy  * @mrioc: Adapter instance reference
587464a8d931SSreekanth Reddy  * @ioc_status: Pointer to return ioc status
587564a8d931SSreekanth Reddy  * @exp_pg1: Pointer to return SAS Expander page 1
587664a8d931SSreekanth Reddy  * @pg_sz: Size of the memory allocated to the page pointer
587764a8d931SSreekanth Reddy  * @form: The form to be used for addressing the page
587864a8d931SSreekanth Reddy  * @form_spec: Form specific information like phy number
587964a8d931SSreekanth Reddy  *
588064a8d931SSreekanth Reddy  * This is handler for config page read for a specific SAS
588164a8d931SSreekanth Reddy  * Expander page1. The ioc_status has the controller returned
588264a8d931SSreekanth Reddy  * ioc_status. This routine doesn't check ioc_status to decide
588364a8d931SSreekanth Reddy  * whether the page read is success or not and it is the callers
588464a8d931SSreekanth Reddy  * responsibility.
588564a8d931SSreekanth Reddy  *
588664a8d931SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
588764a8d931SSreekanth Reddy  */
mpi3mr_cfg_get_sas_exp_pg1(struct mpi3mr_ioc * mrioc,u16 * ioc_status,struct mpi3_sas_expander_page1 * exp_pg1,u16 pg_sz,u32 form,u32 form_spec)588864a8d931SSreekanth Reddy int mpi3mr_cfg_get_sas_exp_pg1(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
588964a8d931SSreekanth Reddy 	struct mpi3_sas_expander_page1 *exp_pg1, u16 pg_sz, u32 form,
589064a8d931SSreekanth Reddy 	u32 form_spec)
589164a8d931SSreekanth Reddy {
589264a8d931SSreekanth Reddy 	struct mpi3_config_page_header cfg_hdr;
589364a8d931SSreekanth Reddy 	struct mpi3_config_request cfg_req;
589464a8d931SSreekanth Reddy 	u32 page_address;
589564a8d931SSreekanth Reddy 
589664a8d931SSreekanth Reddy 	memset(exp_pg1, 0, pg_sz);
589764a8d931SSreekanth Reddy 	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
589864a8d931SSreekanth Reddy 	memset(&cfg_req, 0, sizeof(cfg_req));
589964a8d931SSreekanth Reddy 
590064a8d931SSreekanth Reddy 	cfg_req.function = MPI3_FUNCTION_CONFIG;
590164a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
590264a8d931SSreekanth Reddy 	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_EXPANDER;
590364a8d931SSreekanth Reddy 	cfg_req.page_number = 1;
590464a8d931SSreekanth Reddy 	cfg_req.page_address = 0;
590564a8d931SSreekanth Reddy 
590664a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
590764a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
590864a8d931SSreekanth Reddy 		ioc_err(mrioc, "expander page1 header read failed\n");
590964a8d931SSreekanth Reddy 		goto out_failed;
591064a8d931SSreekanth Reddy 	}
591164a8d931SSreekanth Reddy 	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
591264a8d931SSreekanth Reddy 		ioc_err(mrioc, "expander page1 header read failed with ioc_status(0x%04x)\n",
591364a8d931SSreekanth Reddy 		    *ioc_status);
591464a8d931SSreekanth Reddy 		goto out_failed;
591564a8d931SSreekanth Reddy 	}
591664a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
591764a8d931SSreekanth Reddy 	page_address = ((form & MPI3_SAS_EXPAND_PGAD_FORM_MASK) |
591864a8d931SSreekanth Reddy 	    (form_spec & (MPI3_SAS_EXPAND_PGAD_PHYNUM_MASK |
591964a8d931SSreekanth Reddy 	    MPI3_SAS_EXPAND_PGAD_HANDLE_MASK)));
592064a8d931SSreekanth Reddy 	cfg_req.page_address = cpu_to_le32(page_address);
592164a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
592264a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, exp_pg1, pg_sz)) {
592364a8d931SSreekanth Reddy 		ioc_err(mrioc, "expander page1 read failed\n");
592464a8d931SSreekanth Reddy 		goto out_failed;
592564a8d931SSreekanth Reddy 	}
592664a8d931SSreekanth Reddy 	return 0;
592764a8d931SSreekanth Reddy out_failed:
592864a8d931SSreekanth Reddy 	return -1;
592964a8d931SSreekanth Reddy }
593064a8d931SSreekanth Reddy 
593164a8d931SSreekanth Reddy /**
593264a8d931SSreekanth Reddy  * mpi3mr_cfg_get_enclosure_pg0 - Read current Enclosure page0
593364a8d931SSreekanth Reddy  * @mrioc: Adapter instance reference
593464a8d931SSreekanth Reddy  * @ioc_status: Pointer to return ioc status
593564a8d931SSreekanth Reddy  * @encl_pg0: Pointer to return Enclosure page 0
593664a8d931SSreekanth Reddy  * @pg_sz: Size of the memory allocated to the page pointer
593764a8d931SSreekanth Reddy  * @form: The form to be used for addressing the page
593864a8d931SSreekanth Reddy  * @form_spec: Form specific information like device handle
593964a8d931SSreekanth Reddy  *
594064a8d931SSreekanth Reddy  * This is handler for config page read for a specific Enclosure
594164a8d931SSreekanth Reddy  * page0. The ioc_status has the controller returned ioc_status.
594264a8d931SSreekanth Reddy  * This routine doesn't check ioc_status to decide whether the
594364a8d931SSreekanth Reddy  * page read is success or not and it is the callers
594464a8d931SSreekanth Reddy  * responsibility.
594564a8d931SSreekanth Reddy  *
594664a8d931SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
594764a8d931SSreekanth Reddy  */
mpi3mr_cfg_get_enclosure_pg0(struct mpi3mr_ioc * mrioc,u16 * ioc_status,struct mpi3_enclosure_page0 * encl_pg0,u16 pg_sz,u32 form,u32 form_spec)594864a8d931SSreekanth Reddy int mpi3mr_cfg_get_enclosure_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
594964a8d931SSreekanth Reddy 	struct mpi3_enclosure_page0 *encl_pg0, u16 pg_sz, u32 form,
595064a8d931SSreekanth Reddy 	u32 form_spec)
595164a8d931SSreekanth Reddy {
595264a8d931SSreekanth Reddy 	struct mpi3_config_page_header cfg_hdr;
595364a8d931SSreekanth Reddy 	struct mpi3_config_request cfg_req;
595464a8d931SSreekanth Reddy 	u32 page_address;
595564a8d931SSreekanth Reddy 
595664a8d931SSreekanth Reddy 	memset(encl_pg0, 0, pg_sz);
595764a8d931SSreekanth Reddy 	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
595864a8d931SSreekanth Reddy 	memset(&cfg_req, 0, sizeof(cfg_req));
595964a8d931SSreekanth Reddy 
596064a8d931SSreekanth Reddy 	cfg_req.function = MPI3_FUNCTION_CONFIG;
596164a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
596264a8d931SSreekanth Reddy 	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_ENCLOSURE;
596364a8d931SSreekanth Reddy 	cfg_req.page_number = 0;
596464a8d931SSreekanth Reddy 	cfg_req.page_address = 0;
596564a8d931SSreekanth Reddy 
596664a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
596764a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
596864a8d931SSreekanth Reddy 		ioc_err(mrioc, "enclosure page0 header read failed\n");
596964a8d931SSreekanth Reddy 		goto out_failed;
597064a8d931SSreekanth Reddy 	}
597164a8d931SSreekanth Reddy 	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
597264a8d931SSreekanth Reddy 		ioc_err(mrioc, "enclosure page0 header read failed with ioc_status(0x%04x)\n",
597364a8d931SSreekanth Reddy 		    *ioc_status);
597464a8d931SSreekanth Reddy 		goto out_failed;
597564a8d931SSreekanth Reddy 	}
597664a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
597764a8d931SSreekanth Reddy 	page_address = ((form & MPI3_ENCLOS_PGAD_FORM_MASK) |
597864a8d931SSreekanth Reddy 	    (form_spec & MPI3_ENCLOS_PGAD_HANDLE_MASK));
597964a8d931SSreekanth Reddy 	cfg_req.page_address = cpu_to_le32(page_address);
598064a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
598164a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, encl_pg0, pg_sz)) {
598264a8d931SSreekanth Reddy 		ioc_err(mrioc, "enclosure page0 read failed\n");
598364a8d931SSreekanth Reddy 		goto out_failed;
598464a8d931SSreekanth Reddy 	}
598564a8d931SSreekanth Reddy 	return 0;
598664a8d931SSreekanth Reddy out_failed:
598764a8d931SSreekanth Reddy 	return -1;
598864a8d931SSreekanth Reddy }
598964a8d931SSreekanth Reddy 
599064a8d931SSreekanth Reddy 
599164a8d931SSreekanth Reddy /**
599264a8d931SSreekanth Reddy  * mpi3mr_cfg_get_sas_io_unit_pg0 - Read current SASIOUnit page0
599364a8d931SSreekanth Reddy  * @mrioc: Adapter instance reference
599464a8d931SSreekanth Reddy  * @sas_io_unit_pg0: Pointer to return SAS IO Unit page 0
599564a8d931SSreekanth Reddy  * @pg_sz: Size of the memory allocated to the page pointer
599664a8d931SSreekanth Reddy  *
599764a8d931SSreekanth Reddy  * This is handler for config page read for the SAS IO Unit
599864a8d931SSreekanth Reddy  * page0. This routine checks ioc_status to decide whether the
599964a8d931SSreekanth Reddy  * page read is success or not.
600064a8d931SSreekanth Reddy  *
600164a8d931SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
600264a8d931SSreekanth Reddy  */
mpi3mr_cfg_get_sas_io_unit_pg0(struct mpi3mr_ioc * mrioc,struct mpi3_sas_io_unit_page0 * sas_io_unit_pg0,u16 pg_sz)600364a8d931SSreekanth Reddy int mpi3mr_cfg_get_sas_io_unit_pg0(struct mpi3mr_ioc *mrioc,
600464a8d931SSreekanth Reddy 	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0, u16 pg_sz)
600564a8d931SSreekanth Reddy {
600664a8d931SSreekanth Reddy 	struct mpi3_config_page_header cfg_hdr;
600764a8d931SSreekanth Reddy 	struct mpi3_config_request cfg_req;
600864a8d931SSreekanth Reddy 	u16 ioc_status = 0;
600964a8d931SSreekanth Reddy 
601064a8d931SSreekanth Reddy 	memset(sas_io_unit_pg0, 0, pg_sz);
601164a8d931SSreekanth Reddy 	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
601264a8d931SSreekanth Reddy 	memset(&cfg_req, 0, sizeof(cfg_req));
601364a8d931SSreekanth Reddy 
601464a8d931SSreekanth Reddy 	cfg_req.function = MPI3_FUNCTION_CONFIG;
601564a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
601664a8d931SSreekanth Reddy 	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_IO_UNIT;
601764a8d931SSreekanth Reddy 	cfg_req.page_number = 0;
601864a8d931SSreekanth Reddy 	cfg_req.page_address = 0;
601964a8d931SSreekanth Reddy 
602064a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
602164a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
602264a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page0 header read failed\n");
602364a8d931SSreekanth Reddy 		goto out_failed;
602464a8d931SSreekanth Reddy 	}
602564a8d931SSreekanth Reddy 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
602664a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page0 header read failed with ioc_status(0x%04x)\n",
602764a8d931SSreekanth Reddy 		    ioc_status);
602864a8d931SSreekanth Reddy 		goto out_failed;
602964a8d931SSreekanth Reddy 	}
603064a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
603164a8d931SSreekanth Reddy 
603264a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
603364a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, sas_io_unit_pg0, pg_sz)) {
603464a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page0 read failed\n");
603564a8d931SSreekanth Reddy 		goto out_failed;
603664a8d931SSreekanth Reddy 	}
603764a8d931SSreekanth Reddy 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
603864a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page0 read failed with ioc_status(0x%04x)\n",
603964a8d931SSreekanth Reddy 		    ioc_status);
604064a8d931SSreekanth Reddy 		goto out_failed;
604164a8d931SSreekanth Reddy 	}
604264a8d931SSreekanth Reddy 	return 0;
604364a8d931SSreekanth Reddy out_failed:
604464a8d931SSreekanth Reddy 	return -1;
604564a8d931SSreekanth Reddy }
604664a8d931SSreekanth Reddy 
604764a8d931SSreekanth Reddy /**
604864a8d931SSreekanth Reddy  * mpi3mr_cfg_get_sas_io_unit_pg1 - Read current SASIOUnit page1
604964a8d931SSreekanth Reddy  * @mrioc: Adapter instance reference
605064a8d931SSreekanth Reddy  * @sas_io_unit_pg1: Pointer to return SAS IO Unit page 1
605164a8d931SSreekanth Reddy  * @pg_sz: Size of the memory allocated to the page pointer
605264a8d931SSreekanth Reddy  *
605364a8d931SSreekanth Reddy  * This is handler for config page read for the SAS IO Unit
605464a8d931SSreekanth Reddy  * page1. This routine checks ioc_status to decide whether the
605564a8d931SSreekanth Reddy  * page read is success or not.
605664a8d931SSreekanth Reddy  *
605764a8d931SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
605864a8d931SSreekanth Reddy  */
mpi3mr_cfg_get_sas_io_unit_pg1(struct mpi3mr_ioc * mrioc,struct mpi3_sas_io_unit_page1 * sas_io_unit_pg1,u16 pg_sz)605964a8d931SSreekanth Reddy int mpi3mr_cfg_get_sas_io_unit_pg1(struct mpi3mr_ioc *mrioc,
606064a8d931SSreekanth Reddy 	struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1, u16 pg_sz)
606164a8d931SSreekanth Reddy {
606264a8d931SSreekanth Reddy 	struct mpi3_config_page_header cfg_hdr;
606364a8d931SSreekanth Reddy 	struct mpi3_config_request cfg_req;
606464a8d931SSreekanth Reddy 	u16 ioc_status = 0;
606564a8d931SSreekanth Reddy 
606664a8d931SSreekanth Reddy 	memset(sas_io_unit_pg1, 0, pg_sz);
606764a8d931SSreekanth Reddy 	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
606864a8d931SSreekanth Reddy 	memset(&cfg_req, 0, sizeof(cfg_req));
606964a8d931SSreekanth Reddy 
607064a8d931SSreekanth Reddy 	cfg_req.function = MPI3_FUNCTION_CONFIG;
607164a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
607264a8d931SSreekanth Reddy 	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_IO_UNIT;
607364a8d931SSreekanth Reddy 	cfg_req.page_number = 1;
607464a8d931SSreekanth Reddy 	cfg_req.page_address = 0;
607564a8d931SSreekanth Reddy 
607664a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
607764a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
607864a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page1 header read failed\n");
607964a8d931SSreekanth Reddy 		goto out_failed;
608064a8d931SSreekanth Reddy 	}
608164a8d931SSreekanth Reddy 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
608264a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page1 header read failed with ioc_status(0x%04x)\n",
608364a8d931SSreekanth Reddy 		    ioc_status);
608464a8d931SSreekanth Reddy 		goto out_failed;
608564a8d931SSreekanth Reddy 	}
608664a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
608764a8d931SSreekanth Reddy 
608864a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
608964a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, sas_io_unit_pg1, pg_sz)) {
609064a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page1 read failed\n");
609164a8d931SSreekanth Reddy 		goto out_failed;
609264a8d931SSreekanth Reddy 	}
609364a8d931SSreekanth Reddy 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
609464a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page1 read failed with ioc_status(0x%04x)\n",
609564a8d931SSreekanth Reddy 		    ioc_status);
609664a8d931SSreekanth Reddy 		goto out_failed;
609764a8d931SSreekanth Reddy 	}
609864a8d931SSreekanth Reddy 	return 0;
609964a8d931SSreekanth Reddy out_failed:
610064a8d931SSreekanth Reddy 	return -1;
610164a8d931SSreekanth Reddy }
610264a8d931SSreekanth Reddy 
610364a8d931SSreekanth Reddy /**
610464a8d931SSreekanth Reddy  * mpi3mr_cfg_set_sas_io_unit_pg1 - Write SASIOUnit page1
610564a8d931SSreekanth Reddy  * @mrioc: Adapter instance reference
610664a8d931SSreekanth Reddy  * @sas_io_unit_pg1: Pointer to the SAS IO Unit page 1 to write
610764a8d931SSreekanth Reddy  * @pg_sz: Size of the memory allocated to the page pointer
610864a8d931SSreekanth Reddy  *
610964a8d931SSreekanth Reddy  * This is handler for config page write for the SAS IO Unit
611064a8d931SSreekanth Reddy  * page1. This routine checks ioc_status to decide whether the
611164a8d931SSreekanth Reddy  * page read is success or not. This will modify both current
611264a8d931SSreekanth Reddy  * and persistent page.
611364a8d931SSreekanth Reddy  *
611464a8d931SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
611564a8d931SSreekanth Reddy  */
mpi3mr_cfg_set_sas_io_unit_pg1(struct mpi3mr_ioc * mrioc,struct mpi3_sas_io_unit_page1 * sas_io_unit_pg1,u16 pg_sz)611664a8d931SSreekanth Reddy int mpi3mr_cfg_set_sas_io_unit_pg1(struct mpi3mr_ioc *mrioc,
611764a8d931SSreekanth Reddy 	struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1, u16 pg_sz)
611864a8d931SSreekanth Reddy {
611964a8d931SSreekanth Reddy 	struct mpi3_config_page_header cfg_hdr;
612064a8d931SSreekanth Reddy 	struct mpi3_config_request cfg_req;
612164a8d931SSreekanth Reddy 	u16 ioc_status = 0;
612264a8d931SSreekanth Reddy 
612364a8d931SSreekanth Reddy 	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
612464a8d931SSreekanth Reddy 	memset(&cfg_req, 0, sizeof(cfg_req));
612564a8d931SSreekanth Reddy 
612664a8d931SSreekanth Reddy 	cfg_req.function = MPI3_FUNCTION_CONFIG;
612764a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
612864a8d931SSreekanth Reddy 	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_IO_UNIT;
612964a8d931SSreekanth Reddy 	cfg_req.page_number = 1;
613064a8d931SSreekanth Reddy 	cfg_req.page_address = 0;
613164a8d931SSreekanth Reddy 
613264a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
613364a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
613464a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page1 header read failed\n");
613564a8d931SSreekanth Reddy 		goto out_failed;
613664a8d931SSreekanth Reddy 	}
613764a8d931SSreekanth Reddy 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
613864a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page1 header read failed with ioc_status(0x%04x)\n",
613964a8d931SSreekanth Reddy 		    ioc_status);
614064a8d931SSreekanth Reddy 		goto out_failed;
614164a8d931SSreekanth Reddy 	}
614264a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_WRITE_CURRENT;
614364a8d931SSreekanth Reddy 
614464a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
614564a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, sas_io_unit_pg1, pg_sz)) {
614664a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page1 write current failed\n");
614764a8d931SSreekanth Reddy 		goto out_failed;
614864a8d931SSreekanth Reddy 	}
614964a8d931SSreekanth Reddy 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
615064a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page1 write current failed with ioc_status(0x%04x)\n",
615164a8d931SSreekanth Reddy 		    ioc_status);
615264a8d931SSreekanth Reddy 		goto out_failed;
615364a8d931SSreekanth Reddy 	}
615464a8d931SSreekanth Reddy 
615564a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_WRITE_PERSISTENT;
615664a8d931SSreekanth Reddy 
615764a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
615864a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, sas_io_unit_pg1, pg_sz)) {
615964a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page1 write persistent failed\n");
616064a8d931SSreekanth Reddy 		goto out_failed;
616164a8d931SSreekanth Reddy 	}
616264a8d931SSreekanth Reddy 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
616364a8d931SSreekanth Reddy 		ioc_err(mrioc, "sas io unit page1 write persistent failed with ioc_status(0x%04x)\n",
616464a8d931SSreekanth Reddy 		    ioc_status);
616564a8d931SSreekanth Reddy 		goto out_failed;
616664a8d931SSreekanth Reddy 	}
616764a8d931SSreekanth Reddy 	return 0;
616864a8d931SSreekanth Reddy out_failed:
616964a8d931SSreekanth Reddy 	return -1;
617064a8d931SSreekanth Reddy }
617164a8d931SSreekanth Reddy 
617264a8d931SSreekanth Reddy /**
617364a8d931SSreekanth Reddy  * mpi3mr_cfg_get_driver_pg1 - Read current Driver page1
617464a8d931SSreekanth Reddy  * @mrioc: Adapter instance reference
617564a8d931SSreekanth Reddy  * @driver_pg1: Pointer to return Driver page 1
617664a8d931SSreekanth Reddy  * @pg_sz: Size of the memory allocated to the page pointer
617764a8d931SSreekanth Reddy  *
617864a8d931SSreekanth Reddy  * This is handler for config page read for the Driver page1.
617964a8d931SSreekanth Reddy  * This routine checks ioc_status to decide whether the page
618064a8d931SSreekanth Reddy  * read is success or not.
618164a8d931SSreekanth Reddy  *
618264a8d931SSreekanth Reddy  * Return: 0 on success, non-zero on failure.
618364a8d931SSreekanth Reddy  */
mpi3mr_cfg_get_driver_pg1(struct mpi3mr_ioc * mrioc,struct mpi3_driver_page1 * driver_pg1,u16 pg_sz)618464a8d931SSreekanth Reddy int mpi3mr_cfg_get_driver_pg1(struct mpi3mr_ioc *mrioc,
618564a8d931SSreekanth Reddy 	struct mpi3_driver_page1 *driver_pg1, u16 pg_sz)
618664a8d931SSreekanth Reddy {
618764a8d931SSreekanth Reddy 	struct mpi3_config_page_header cfg_hdr;
618864a8d931SSreekanth Reddy 	struct mpi3_config_request cfg_req;
618964a8d931SSreekanth Reddy 	u16 ioc_status = 0;
619064a8d931SSreekanth Reddy 
619164a8d931SSreekanth Reddy 	memset(driver_pg1, 0, pg_sz);
619264a8d931SSreekanth Reddy 	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
619364a8d931SSreekanth Reddy 	memset(&cfg_req, 0, sizeof(cfg_req));
619464a8d931SSreekanth Reddy 
619564a8d931SSreekanth Reddy 	cfg_req.function = MPI3_FUNCTION_CONFIG;
619664a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
619764a8d931SSreekanth Reddy 	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_DRIVER;
619864a8d931SSreekanth Reddy 	cfg_req.page_number = 1;
619964a8d931SSreekanth Reddy 	cfg_req.page_address = 0;
620064a8d931SSreekanth Reddy 
620164a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
620264a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
620364a8d931SSreekanth Reddy 		ioc_err(mrioc, "driver page1 header read failed\n");
620464a8d931SSreekanth Reddy 		goto out_failed;
620564a8d931SSreekanth Reddy 	}
620664a8d931SSreekanth Reddy 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
620764a8d931SSreekanth Reddy 		ioc_err(mrioc, "driver page1 header read failed with ioc_status(0x%04x)\n",
620864a8d931SSreekanth Reddy 		    ioc_status);
620964a8d931SSreekanth Reddy 		goto out_failed;
621064a8d931SSreekanth Reddy 	}
621164a8d931SSreekanth Reddy 	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
621264a8d931SSreekanth Reddy 
621364a8d931SSreekanth Reddy 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
621464a8d931SSreekanth Reddy 	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, driver_pg1, pg_sz)) {
621564a8d931SSreekanth Reddy 		ioc_err(mrioc, "driver page1 read failed\n");
621664a8d931SSreekanth Reddy 		goto out_failed;
621764a8d931SSreekanth Reddy 	}
621864a8d931SSreekanth Reddy 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
621964a8d931SSreekanth Reddy 		ioc_err(mrioc, "driver page1 read failed with ioc_status(0x%04x)\n",
622064a8d931SSreekanth Reddy 		    ioc_status);
622164a8d931SSreekanth Reddy 		goto out_failed;
622264a8d931SSreekanth Reddy 	}
622364a8d931SSreekanth Reddy 	return 0;
622464a8d931SSreekanth Reddy out_failed:
622564a8d931SSreekanth Reddy 	return -1;
622664a8d931SSreekanth Reddy }
6227fc444494SRanjan Kumar 
6228fc444494SRanjan Kumar /**
6229fc444494SRanjan Kumar  * mpi3mr_cfg_get_driver_pg2 - Read current driver page2
6230fc444494SRanjan Kumar  * @mrioc: Adapter instance reference
6231fc444494SRanjan Kumar  * @driver_pg2: Pointer to return driver page 2
6232fc444494SRanjan Kumar  * @pg_sz: Size of the memory allocated to the page pointer
6233fc444494SRanjan Kumar  * @page_action: Page action
6234fc444494SRanjan Kumar  *
6235fc444494SRanjan Kumar  * This is handler for config page read for the driver page2.
6236fc444494SRanjan Kumar  * This routine checks ioc_status to decide whether the page
6237fc444494SRanjan Kumar  * read is success or not.
6238fc444494SRanjan Kumar  *
6239fc444494SRanjan Kumar  * Return: 0 on success, non-zero on failure.
6240fc444494SRanjan Kumar  */
mpi3mr_cfg_get_driver_pg2(struct mpi3mr_ioc * mrioc,struct mpi3_driver_page2 * driver_pg2,u16 pg_sz,u8 page_action)6241fc444494SRanjan Kumar int mpi3mr_cfg_get_driver_pg2(struct mpi3mr_ioc *mrioc,
6242fc444494SRanjan Kumar 	struct mpi3_driver_page2 *driver_pg2, u16 pg_sz, u8 page_action)
6243fc444494SRanjan Kumar {
6244fc444494SRanjan Kumar 	struct mpi3_config_page_header cfg_hdr;
6245fc444494SRanjan Kumar 	struct mpi3_config_request cfg_req;
6246fc444494SRanjan Kumar 	u16 ioc_status = 0;
6247fc444494SRanjan Kumar 
6248fc444494SRanjan Kumar 	memset(driver_pg2, 0, pg_sz);
6249fc444494SRanjan Kumar 	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
6250fc444494SRanjan Kumar 	memset(&cfg_req, 0, sizeof(cfg_req));
6251fc444494SRanjan Kumar 
6252fc444494SRanjan Kumar 	cfg_req.function = MPI3_FUNCTION_CONFIG;
6253fc444494SRanjan Kumar 	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
6254fc444494SRanjan Kumar 	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_DRIVER;
6255fc444494SRanjan Kumar 	cfg_req.page_number = 2;
6256fc444494SRanjan Kumar 	cfg_req.page_address = 0;
6257fc444494SRanjan Kumar 	cfg_req.page_version = MPI3_DRIVER2_PAGEVERSION;
6258fc444494SRanjan Kumar 
6259fc444494SRanjan Kumar 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
6260fc444494SRanjan Kumar 	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
6261fc444494SRanjan Kumar 		ioc_err(mrioc, "driver page2 header read failed\n");
6262fc444494SRanjan Kumar 		goto out_failed;
6263fc444494SRanjan Kumar 	}
6264fc444494SRanjan Kumar 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
6265fc444494SRanjan Kumar 		ioc_err(mrioc, "driver page2 header read failed with\n"
6266fc444494SRanjan Kumar 			       "ioc_status(0x%04x)\n",
6267fc444494SRanjan Kumar 		    ioc_status);
6268fc444494SRanjan Kumar 		goto out_failed;
6269fc444494SRanjan Kumar 	}
6270fc444494SRanjan Kumar 	cfg_req.action = page_action;
6271fc444494SRanjan Kumar 
6272fc444494SRanjan Kumar 	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
6273fc444494SRanjan Kumar 	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, driver_pg2, pg_sz)) {
6274fc444494SRanjan Kumar 		ioc_err(mrioc, "driver page2 read failed\n");
6275fc444494SRanjan Kumar 		goto out_failed;
6276fc444494SRanjan Kumar 	}
6277fc444494SRanjan Kumar 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
6278fc444494SRanjan Kumar 		ioc_err(mrioc, "driver page2 read failed with\n"
6279fc444494SRanjan Kumar 			       "ioc_status(0x%04x)\n",
6280fc444494SRanjan Kumar 		    ioc_status);
6281fc444494SRanjan Kumar 		goto out_failed;
6282fc444494SRanjan Kumar 	}
6283fc444494SRanjan Kumar 	return 0;
6284fc444494SRanjan Kumar out_failed:
6285fc444494SRanjan Kumar 	return -1;
6286fc444494SRanjan Kumar }
6287fc444494SRanjan Kumar 
6288