xref: /linux/drivers/scsi/mpi3mr/mpi3mr_fw.c (revision e844adb1fbdc41c3e1531a5bdf30f376563945f1)
1824a1566SKashyap Desai // SPDX-License-Identifier: GPL-2.0-or-later
2824a1566SKashyap Desai /*
3824a1566SKashyap Desai  * Driver for Broadcom MPI3 Storage Controllers
4824a1566SKashyap Desai  *
5824a1566SKashyap Desai  * Copyright (C) 2017-2021 Broadcom Inc.
6824a1566SKashyap Desai  *  (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
7824a1566SKashyap Desai  *
8824a1566SKashyap Desai  */
9824a1566SKashyap Desai 
10824a1566SKashyap Desai #include "mpi3mr.h"
11824a1566SKashyap Desai #include <linux/io-64-nonatomic-lo-hi.h>
12824a1566SKashyap Desai 
13824a1566SKashyap Desai #if defined(writeq) && defined(CONFIG_64BIT)
14824a1566SKashyap Desai static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr)
15824a1566SKashyap Desai {
16824a1566SKashyap Desai 	writeq(b, addr);
17824a1566SKashyap Desai }
18824a1566SKashyap Desai #else
19824a1566SKashyap Desai static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr)
20824a1566SKashyap Desai {
21824a1566SKashyap Desai 	__u64 data_out = b;
22824a1566SKashyap Desai 
23824a1566SKashyap Desai 	writel((u32)(data_out), addr);
24824a1566SKashyap Desai 	writel((u32)(data_out >> 32), (addr + 4));
25824a1566SKashyap Desai }
26824a1566SKashyap Desai #endif
27824a1566SKashyap Desai 
28023ab2a9SKashyap Desai static inline bool
29023ab2a9SKashyap Desai mpi3mr_check_req_qfull(struct op_req_qinfo *op_req_q)
30023ab2a9SKashyap Desai {
31023ab2a9SKashyap Desai 	u16 pi, ci, max_entries;
32023ab2a9SKashyap Desai 	bool is_qfull = false;
33023ab2a9SKashyap Desai 
34023ab2a9SKashyap Desai 	pi = op_req_q->pi;
35023ab2a9SKashyap Desai 	ci = READ_ONCE(op_req_q->ci);
36023ab2a9SKashyap Desai 	max_entries = op_req_q->num_requests;
37023ab2a9SKashyap Desai 
38023ab2a9SKashyap Desai 	if ((ci == (pi + 1)) || ((!ci) && (pi == (max_entries - 1))))
39023ab2a9SKashyap Desai 		is_qfull = true;
40023ab2a9SKashyap Desai 
41023ab2a9SKashyap Desai 	return is_qfull;
42023ab2a9SKashyap Desai }
43023ab2a9SKashyap Desai 
44824a1566SKashyap Desai static void mpi3mr_sync_irqs(struct mpi3mr_ioc *mrioc)
45824a1566SKashyap Desai {
46824a1566SKashyap Desai 	u16 i, max_vectors;
47824a1566SKashyap Desai 
48824a1566SKashyap Desai 	max_vectors = mrioc->intr_info_count;
49824a1566SKashyap Desai 
50824a1566SKashyap Desai 	for (i = 0; i < max_vectors; i++)
51824a1566SKashyap Desai 		synchronize_irq(pci_irq_vector(mrioc->pdev, i));
52824a1566SKashyap Desai }
53824a1566SKashyap Desai 
54824a1566SKashyap Desai void mpi3mr_ioc_disable_intr(struct mpi3mr_ioc *mrioc)
55824a1566SKashyap Desai {
56824a1566SKashyap Desai 	mrioc->intr_enabled = 0;
57824a1566SKashyap Desai 	mpi3mr_sync_irqs(mrioc);
58824a1566SKashyap Desai }
59824a1566SKashyap Desai 
60824a1566SKashyap Desai void mpi3mr_ioc_enable_intr(struct mpi3mr_ioc *mrioc)
61824a1566SKashyap Desai {
62824a1566SKashyap Desai 	mrioc->intr_enabled = 1;
63824a1566SKashyap Desai }
64824a1566SKashyap Desai 
65824a1566SKashyap Desai static void mpi3mr_cleanup_isr(struct mpi3mr_ioc *mrioc)
66824a1566SKashyap Desai {
67824a1566SKashyap Desai 	u16 i;
68824a1566SKashyap Desai 
69824a1566SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
70824a1566SKashyap Desai 
71824a1566SKashyap Desai 	if (!mrioc->intr_info)
72824a1566SKashyap Desai 		return;
73824a1566SKashyap Desai 
74824a1566SKashyap Desai 	for (i = 0; i < mrioc->intr_info_count; i++)
75824a1566SKashyap Desai 		free_irq(pci_irq_vector(mrioc->pdev, i),
76824a1566SKashyap Desai 		    (mrioc->intr_info + i));
77824a1566SKashyap Desai 
78824a1566SKashyap Desai 	kfree(mrioc->intr_info);
79824a1566SKashyap Desai 	mrioc->intr_info = NULL;
80824a1566SKashyap Desai 	mrioc->intr_info_count = 0;
81824a1566SKashyap Desai 	pci_free_irq_vectors(mrioc->pdev);
82824a1566SKashyap Desai }
83824a1566SKashyap Desai 
84824a1566SKashyap Desai void mpi3mr_add_sg_single(void *paddr, u8 flags, u32 length,
85824a1566SKashyap Desai 	dma_addr_t dma_addr)
86824a1566SKashyap Desai {
87824a1566SKashyap Desai 	struct mpi3_sge_common *sgel = paddr;
88824a1566SKashyap Desai 
89824a1566SKashyap Desai 	sgel->flags = flags;
90824a1566SKashyap Desai 	sgel->length = cpu_to_le32(length);
91824a1566SKashyap Desai 	sgel->address = cpu_to_le64(dma_addr);
92824a1566SKashyap Desai }
93824a1566SKashyap Desai 
94824a1566SKashyap Desai void mpi3mr_build_zero_len_sge(void *paddr)
95824a1566SKashyap Desai {
96824a1566SKashyap Desai 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
97824a1566SKashyap Desai 
98824a1566SKashyap Desai 	mpi3mr_add_sg_single(paddr, sgl_flags, 0, -1);
99824a1566SKashyap Desai }
100824a1566SKashyap Desai 
101824a1566SKashyap Desai void *mpi3mr_get_reply_virt_addr(struct mpi3mr_ioc *mrioc,
102824a1566SKashyap Desai 	dma_addr_t phys_addr)
103824a1566SKashyap Desai {
104824a1566SKashyap Desai 	if (!phys_addr)
105824a1566SKashyap Desai 		return NULL;
106824a1566SKashyap Desai 
107824a1566SKashyap Desai 	if ((phys_addr < mrioc->reply_buf_dma) ||
108824a1566SKashyap Desai 	    (phys_addr > mrioc->reply_buf_dma_max_address))
109824a1566SKashyap Desai 		return NULL;
110824a1566SKashyap Desai 
111824a1566SKashyap Desai 	return mrioc->reply_buf + (phys_addr - mrioc->reply_buf_dma);
112824a1566SKashyap Desai }
113824a1566SKashyap Desai 
114824a1566SKashyap Desai void *mpi3mr_get_sensebuf_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 	return mrioc->sense_buf + (phys_addr - mrioc->sense_buf_dma);
121824a1566SKashyap Desai }
122824a1566SKashyap Desai 
123824a1566SKashyap Desai static void mpi3mr_repost_reply_buf(struct mpi3mr_ioc *mrioc,
124824a1566SKashyap Desai 	u64 reply_dma)
125824a1566SKashyap Desai {
126824a1566SKashyap Desai 	u32 old_idx = 0;
127824a1566SKashyap Desai 
128824a1566SKashyap Desai 	spin_lock(&mrioc->reply_free_queue_lock);
129824a1566SKashyap Desai 	old_idx  =  mrioc->reply_free_queue_host_index;
130824a1566SKashyap Desai 	mrioc->reply_free_queue_host_index = (
131824a1566SKashyap Desai 	    (mrioc->reply_free_queue_host_index ==
132824a1566SKashyap Desai 	    (mrioc->reply_free_qsz - 1)) ? 0 :
133824a1566SKashyap Desai 	    (mrioc->reply_free_queue_host_index + 1));
134824a1566SKashyap Desai 	mrioc->reply_free_q[old_idx] = cpu_to_le64(reply_dma);
135824a1566SKashyap Desai 	writel(mrioc->reply_free_queue_host_index,
136824a1566SKashyap Desai 	    &mrioc->sysif_regs->reply_free_host_index);
137824a1566SKashyap Desai 	spin_unlock(&mrioc->reply_free_queue_lock);
138824a1566SKashyap Desai }
139824a1566SKashyap Desai 
140824a1566SKashyap Desai void mpi3mr_repost_sense_buf(struct mpi3mr_ioc *mrioc,
141824a1566SKashyap Desai 	u64 sense_buf_dma)
142824a1566SKashyap Desai {
143824a1566SKashyap Desai 	u32 old_idx = 0;
144824a1566SKashyap Desai 
145824a1566SKashyap Desai 	spin_lock(&mrioc->sbq_lock);
146824a1566SKashyap Desai 	old_idx  =  mrioc->sbq_host_index;
147824a1566SKashyap Desai 	mrioc->sbq_host_index = ((mrioc->sbq_host_index ==
148824a1566SKashyap Desai 	    (mrioc->sense_buf_q_sz - 1)) ? 0 :
149824a1566SKashyap Desai 	    (mrioc->sbq_host_index + 1));
150824a1566SKashyap Desai 	mrioc->sense_buf_q[old_idx] = cpu_to_le64(sense_buf_dma);
151824a1566SKashyap Desai 	writel(mrioc->sbq_host_index,
152824a1566SKashyap Desai 	    &mrioc->sysif_regs->sense_buffer_free_host_index);
153824a1566SKashyap Desai 	spin_unlock(&mrioc->sbq_lock);
154824a1566SKashyap Desai }
155824a1566SKashyap Desai 
156824a1566SKashyap Desai static void mpi3mr_handle_events(struct mpi3mr_ioc *mrioc,
157824a1566SKashyap Desai 	struct mpi3_default_reply *def_reply)
158824a1566SKashyap Desai {
159824a1566SKashyap Desai 	struct mpi3_event_notification_reply *event_reply =
160824a1566SKashyap Desai 	    (struct mpi3_event_notification_reply *)def_reply;
161824a1566SKashyap Desai 
162824a1566SKashyap Desai 	mrioc->change_count = le16_to_cpu(event_reply->ioc_change_count);
16313ef29eaSKashyap Desai 	mpi3mr_os_handle_events(mrioc, event_reply);
164824a1566SKashyap Desai }
165824a1566SKashyap Desai 
166824a1566SKashyap Desai static struct mpi3mr_drv_cmd *
167824a1566SKashyap Desai mpi3mr_get_drv_cmd(struct mpi3mr_ioc *mrioc, u16 host_tag,
168824a1566SKashyap Desai 	struct mpi3_default_reply *def_reply)
169824a1566SKashyap Desai {
17013ef29eaSKashyap Desai 	u16 idx;
17113ef29eaSKashyap Desai 
172824a1566SKashyap Desai 	switch (host_tag) {
173824a1566SKashyap Desai 	case MPI3MR_HOSTTAG_INITCMDS:
174824a1566SKashyap Desai 		return &mrioc->init_cmds;
175*e844adb1SKashyap Desai 	case MPI3MR_HOSTTAG_BLK_TMS:
176*e844adb1SKashyap Desai 		return &mrioc->host_tm_cmds;
177824a1566SKashyap Desai 	case MPI3MR_HOSTTAG_INVALID:
178824a1566SKashyap Desai 		if (def_reply && def_reply->function ==
179824a1566SKashyap Desai 		    MPI3_FUNCTION_EVENT_NOTIFICATION)
180824a1566SKashyap Desai 			mpi3mr_handle_events(mrioc, def_reply);
181824a1566SKashyap Desai 		return NULL;
182824a1566SKashyap Desai 	default:
183824a1566SKashyap Desai 		break;
184824a1566SKashyap Desai 	}
18513ef29eaSKashyap Desai 	if (host_tag >= MPI3MR_HOSTTAG_DEVRMCMD_MIN &&
18613ef29eaSKashyap Desai 	    host_tag <= MPI3MR_HOSTTAG_DEVRMCMD_MAX) {
18713ef29eaSKashyap Desai 		idx = host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
18813ef29eaSKashyap Desai 		return &mrioc->dev_rmhs_cmds[idx];
18913ef29eaSKashyap Desai 	}
190824a1566SKashyap Desai 
191824a1566SKashyap Desai 	return NULL;
192824a1566SKashyap Desai }
193824a1566SKashyap Desai 
194824a1566SKashyap Desai static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc,
195824a1566SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc, u64 *reply_dma)
196824a1566SKashyap Desai {
197824a1566SKashyap Desai 	u16 reply_desc_type, host_tag = 0;
198824a1566SKashyap Desai 	u16 ioc_status = MPI3_IOCSTATUS_SUCCESS;
199824a1566SKashyap Desai 	u32 ioc_loginfo = 0;
200824a1566SKashyap Desai 	struct mpi3_status_reply_descriptor *status_desc;
201824a1566SKashyap Desai 	struct mpi3_address_reply_descriptor *addr_desc;
202824a1566SKashyap Desai 	struct mpi3_success_reply_descriptor *success_desc;
203824a1566SKashyap Desai 	struct mpi3_default_reply *def_reply = NULL;
204824a1566SKashyap Desai 	struct mpi3mr_drv_cmd *cmdptr = NULL;
205824a1566SKashyap Desai 	struct mpi3_scsi_io_reply *scsi_reply;
206824a1566SKashyap Desai 	u8 *sense_buf = NULL;
207824a1566SKashyap Desai 
208824a1566SKashyap Desai 	*reply_dma = 0;
209824a1566SKashyap Desai 	reply_desc_type = le16_to_cpu(reply_desc->reply_flags) &
210824a1566SKashyap Desai 	    MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK;
211824a1566SKashyap Desai 	switch (reply_desc_type) {
212824a1566SKashyap Desai 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS:
213824a1566SKashyap Desai 		status_desc = (struct mpi3_status_reply_descriptor *)reply_desc;
214824a1566SKashyap Desai 		host_tag = le16_to_cpu(status_desc->host_tag);
215824a1566SKashyap Desai 		ioc_status = le16_to_cpu(status_desc->ioc_status);
216824a1566SKashyap Desai 		if (ioc_status &
217824a1566SKashyap Desai 		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
218824a1566SKashyap Desai 			ioc_loginfo = le32_to_cpu(status_desc->ioc_log_info);
219824a1566SKashyap Desai 		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
220824a1566SKashyap Desai 		break;
221824a1566SKashyap Desai 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY:
222824a1566SKashyap Desai 		addr_desc = (struct mpi3_address_reply_descriptor *)reply_desc;
223824a1566SKashyap Desai 		*reply_dma = le64_to_cpu(addr_desc->reply_frame_address);
224824a1566SKashyap Desai 		def_reply = mpi3mr_get_reply_virt_addr(mrioc, *reply_dma);
225824a1566SKashyap Desai 		if (!def_reply)
226824a1566SKashyap Desai 			goto out;
227824a1566SKashyap Desai 		host_tag = le16_to_cpu(def_reply->host_tag);
228824a1566SKashyap Desai 		ioc_status = le16_to_cpu(def_reply->ioc_status);
229824a1566SKashyap Desai 		if (ioc_status &
230824a1566SKashyap Desai 		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
231824a1566SKashyap Desai 			ioc_loginfo = le32_to_cpu(def_reply->ioc_log_info);
232824a1566SKashyap Desai 		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
233824a1566SKashyap Desai 		if (def_reply->function == MPI3_FUNCTION_SCSI_IO) {
234824a1566SKashyap Desai 			scsi_reply = (struct mpi3_scsi_io_reply *)def_reply;
235824a1566SKashyap Desai 			sense_buf = mpi3mr_get_sensebuf_virt_addr(mrioc,
236824a1566SKashyap Desai 			    le64_to_cpu(scsi_reply->sense_data_buffer_address));
237824a1566SKashyap Desai 		}
238824a1566SKashyap Desai 		break;
239824a1566SKashyap Desai 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS:
240824a1566SKashyap Desai 		success_desc = (struct mpi3_success_reply_descriptor *)reply_desc;
241824a1566SKashyap Desai 		host_tag = le16_to_cpu(success_desc->host_tag);
242824a1566SKashyap Desai 		break;
243824a1566SKashyap Desai 	default:
244824a1566SKashyap Desai 		break;
245824a1566SKashyap Desai 	}
246824a1566SKashyap Desai 
247824a1566SKashyap Desai 	cmdptr = mpi3mr_get_drv_cmd(mrioc, host_tag, def_reply);
248824a1566SKashyap Desai 	if (cmdptr) {
249824a1566SKashyap Desai 		if (cmdptr->state & MPI3MR_CMD_PENDING) {
250824a1566SKashyap Desai 			cmdptr->state |= MPI3MR_CMD_COMPLETE;
251824a1566SKashyap Desai 			cmdptr->ioc_loginfo = ioc_loginfo;
252824a1566SKashyap Desai 			cmdptr->ioc_status = ioc_status;
253824a1566SKashyap Desai 			cmdptr->state &= ~MPI3MR_CMD_PENDING;
254824a1566SKashyap Desai 			if (def_reply) {
255824a1566SKashyap Desai 				cmdptr->state |= MPI3MR_CMD_REPLY_VALID;
256824a1566SKashyap Desai 				memcpy((u8 *)cmdptr->reply, (u8 *)def_reply,
257824a1566SKashyap Desai 				    mrioc->facts.reply_sz);
258824a1566SKashyap Desai 			}
259824a1566SKashyap Desai 			if (cmdptr->is_waiting) {
260824a1566SKashyap Desai 				complete(&cmdptr->done);
261824a1566SKashyap Desai 				cmdptr->is_waiting = 0;
262824a1566SKashyap Desai 			} else if (cmdptr->callback)
263824a1566SKashyap Desai 				cmdptr->callback(mrioc, cmdptr);
264824a1566SKashyap Desai 		}
265824a1566SKashyap Desai 	}
266824a1566SKashyap Desai out:
267824a1566SKashyap Desai 	if (sense_buf)
268824a1566SKashyap Desai 		mpi3mr_repost_sense_buf(mrioc,
269824a1566SKashyap Desai 		    le64_to_cpu(scsi_reply->sense_data_buffer_address));
270824a1566SKashyap Desai }
271824a1566SKashyap Desai 
272824a1566SKashyap Desai static int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc)
273824a1566SKashyap Desai {
274824a1566SKashyap Desai 	u32 exp_phase = mrioc->admin_reply_ephase;
275824a1566SKashyap Desai 	u32 admin_reply_ci = mrioc->admin_reply_ci;
276824a1566SKashyap Desai 	u32 num_admin_replies = 0;
277824a1566SKashyap Desai 	u64 reply_dma = 0;
278824a1566SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc;
279824a1566SKashyap Desai 
280824a1566SKashyap Desai 	reply_desc = (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base +
281824a1566SKashyap Desai 	    admin_reply_ci;
282824a1566SKashyap Desai 
283824a1566SKashyap Desai 	if ((le16_to_cpu(reply_desc->reply_flags) &
284824a1566SKashyap Desai 	    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
285824a1566SKashyap Desai 		return 0;
286824a1566SKashyap Desai 
287824a1566SKashyap Desai 	do {
288824a1566SKashyap Desai 		mrioc->admin_req_ci = le16_to_cpu(reply_desc->request_queue_ci);
289824a1566SKashyap Desai 		mpi3mr_process_admin_reply_desc(mrioc, reply_desc, &reply_dma);
290824a1566SKashyap Desai 		if (reply_dma)
291824a1566SKashyap Desai 			mpi3mr_repost_reply_buf(mrioc, reply_dma);
292824a1566SKashyap Desai 		num_admin_replies++;
293824a1566SKashyap Desai 		if (++admin_reply_ci == mrioc->num_admin_replies) {
294824a1566SKashyap Desai 			admin_reply_ci = 0;
295824a1566SKashyap Desai 			exp_phase ^= 1;
296824a1566SKashyap Desai 		}
297824a1566SKashyap Desai 		reply_desc =
298824a1566SKashyap Desai 		    (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base +
299824a1566SKashyap Desai 		    admin_reply_ci;
300824a1566SKashyap Desai 		if ((le16_to_cpu(reply_desc->reply_flags) &
301824a1566SKashyap Desai 		    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
302824a1566SKashyap Desai 			break;
303824a1566SKashyap Desai 	} while (1);
304824a1566SKashyap Desai 
305824a1566SKashyap Desai 	writel(admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci);
306824a1566SKashyap Desai 	mrioc->admin_reply_ci = admin_reply_ci;
307824a1566SKashyap Desai 	mrioc->admin_reply_ephase = exp_phase;
308824a1566SKashyap Desai 
309824a1566SKashyap Desai 	return num_admin_replies;
310824a1566SKashyap Desai }
311824a1566SKashyap Desai 
312023ab2a9SKashyap Desai /**
313023ab2a9SKashyap Desai  * mpi3mr_get_reply_desc - get reply descriptor frame corresponding to
314023ab2a9SKashyap Desai  *	queue's consumer index from operational reply descriptor queue.
315023ab2a9SKashyap Desai  * @op_reply_q: op_reply_qinfo object
316023ab2a9SKashyap Desai  * @reply_ci: operational reply descriptor's queue consumer index
317023ab2a9SKashyap Desai  *
318023ab2a9SKashyap Desai  * Returns reply descriptor frame address
319023ab2a9SKashyap Desai  */
320023ab2a9SKashyap Desai static inline struct mpi3_default_reply_descriptor *
321023ab2a9SKashyap Desai mpi3mr_get_reply_desc(struct op_reply_qinfo *op_reply_q, u32 reply_ci)
322023ab2a9SKashyap Desai {
323023ab2a9SKashyap Desai 	void *segment_base_addr;
324023ab2a9SKashyap Desai 	struct segments *segments = op_reply_q->q_segments;
325023ab2a9SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc = NULL;
326023ab2a9SKashyap Desai 
327023ab2a9SKashyap Desai 	segment_base_addr =
328023ab2a9SKashyap Desai 	    segments[reply_ci / op_reply_q->segment_qd].segment;
329023ab2a9SKashyap Desai 	reply_desc = (struct mpi3_default_reply_descriptor *)segment_base_addr +
330023ab2a9SKashyap Desai 	    (reply_ci % op_reply_q->segment_qd);
331023ab2a9SKashyap Desai 	return reply_desc;
332023ab2a9SKashyap Desai }
333023ab2a9SKashyap Desai 
334023ab2a9SKashyap Desai static int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc,
335023ab2a9SKashyap Desai 	struct mpi3mr_intr_info *intr_info)
336023ab2a9SKashyap Desai {
337023ab2a9SKashyap Desai 	struct op_reply_qinfo *op_reply_q = intr_info->op_reply_q;
338023ab2a9SKashyap Desai 	struct op_req_qinfo *op_req_q;
339023ab2a9SKashyap Desai 	u32 exp_phase;
340023ab2a9SKashyap Desai 	u32 reply_ci;
341023ab2a9SKashyap Desai 	u32 num_op_reply = 0;
342023ab2a9SKashyap Desai 	u64 reply_dma = 0;
343023ab2a9SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc;
344023ab2a9SKashyap Desai 	u16 req_q_idx = 0, reply_qidx;
345023ab2a9SKashyap Desai 
346023ab2a9SKashyap Desai 	reply_qidx = op_reply_q->qid - 1;
347023ab2a9SKashyap Desai 
348023ab2a9SKashyap Desai 	exp_phase = op_reply_q->ephase;
349023ab2a9SKashyap Desai 	reply_ci = op_reply_q->ci;
350023ab2a9SKashyap Desai 
351023ab2a9SKashyap Desai 	reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci);
352023ab2a9SKashyap Desai 	if ((le16_to_cpu(reply_desc->reply_flags) &
353023ab2a9SKashyap Desai 	    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) {
354023ab2a9SKashyap Desai 		return 0;
355023ab2a9SKashyap Desai 	}
356023ab2a9SKashyap Desai 
357023ab2a9SKashyap Desai 	do {
358023ab2a9SKashyap Desai 		req_q_idx = le16_to_cpu(reply_desc->request_queue_id) - 1;
359023ab2a9SKashyap Desai 		op_req_q = &mrioc->req_qinfo[req_q_idx];
360023ab2a9SKashyap Desai 
361023ab2a9SKashyap Desai 		WRITE_ONCE(op_req_q->ci, le16_to_cpu(reply_desc->request_queue_ci));
362023ab2a9SKashyap Desai 		mpi3mr_process_op_reply_desc(mrioc, reply_desc, &reply_dma,
363023ab2a9SKashyap Desai 		    reply_qidx);
364023ab2a9SKashyap Desai 		if (reply_dma)
365023ab2a9SKashyap Desai 			mpi3mr_repost_reply_buf(mrioc, reply_dma);
366023ab2a9SKashyap Desai 		num_op_reply++;
367023ab2a9SKashyap Desai 
368023ab2a9SKashyap Desai 		if (++reply_ci == op_reply_q->num_replies) {
369023ab2a9SKashyap Desai 			reply_ci = 0;
370023ab2a9SKashyap Desai 			exp_phase ^= 1;
371023ab2a9SKashyap Desai 		}
372023ab2a9SKashyap Desai 
373023ab2a9SKashyap Desai 		reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci);
374023ab2a9SKashyap Desai 
375023ab2a9SKashyap Desai 		if ((le16_to_cpu(reply_desc->reply_flags) &
376023ab2a9SKashyap Desai 		    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
377023ab2a9SKashyap Desai 			break;
378023ab2a9SKashyap Desai 
379023ab2a9SKashyap Desai 	} while (1);
380023ab2a9SKashyap Desai 
381023ab2a9SKashyap Desai 	writel(reply_ci,
382023ab2a9SKashyap Desai 	    &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].consumer_index);
383023ab2a9SKashyap Desai 	op_reply_q->ci = reply_ci;
384023ab2a9SKashyap Desai 	op_reply_q->ephase = exp_phase;
385023ab2a9SKashyap Desai 
386023ab2a9SKashyap Desai 	return num_op_reply;
387023ab2a9SKashyap Desai }
388023ab2a9SKashyap Desai 
389824a1566SKashyap Desai static irqreturn_t mpi3mr_isr_primary(int irq, void *privdata)
390824a1566SKashyap Desai {
391824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info = privdata;
392824a1566SKashyap Desai 	struct mpi3mr_ioc *mrioc;
393824a1566SKashyap Desai 	u16 midx;
394824a1566SKashyap Desai 	u32 num_admin_replies = 0;
395824a1566SKashyap Desai 
396824a1566SKashyap Desai 	if (!intr_info)
397824a1566SKashyap Desai 		return IRQ_NONE;
398824a1566SKashyap Desai 
399824a1566SKashyap Desai 	mrioc = intr_info->mrioc;
400824a1566SKashyap Desai 
401824a1566SKashyap Desai 	if (!mrioc->intr_enabled)
402824a1566SKashyap Desai 		return IRQ_NONE;
403824a1566SKashyap Desai 
404824a1566SKashyap Desai 	midx = intr_info->msix_index;
405824a1566SKashyap Desai 
406824a1566SKashyap Desai 	if (!midx)
407824a1566SKashyap Desai 		num_admin_replies = mpi3mr_process_admin_reply_q(mrioc);
408824a1566SKashyap Desai 
409824a1566SKashyap Desai 	if (num_admin_replies)
410824a1566SKashyap Desai 		return IRQ_HANDLED;
411824a1566SKashyap Desai 	else
412824a1566SKashyap Desai 		return IRQ_NONE;
413824a1566SKashyap Desai }
414824a1566SKashyap Desai 
415824a1566SKashyap Desai static irqreturn_t mpi3mr_isr(int irq, void *privdata)
416824a1566SKashyap Desai {
417824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info = privdata;
418824a1566SKashyap Desai 	int ret;
419824a1566SKashyap Desai 
420824a1566SKashyap Desai 	if (!intr_info)
421824a1566SKashyap Desai 		return IRQ_NONE;
422824a1566SKashyap Desai 
423824a1566SKashyap Desai 	/* Call primary ISR routine */
424824a1566SKashyap Desai 	ret = mpi3mr_isr_primary(irq, privdata);
425824a1566SKashyap Desai 
426824a1566SKashyap Desai 	return ret;
427824a1566SKashyap Desai }
428824a1566SKashyap Desai 
429824a1566SKashyap Desai /**
430824a1566SKashyap Desai  * mpi3mr_isr_poll - Reply queue polling routine
431824a1566SKashyap Desai  * @irq: IRQ
432824a1566SKashyap Desai  * @privdata: Interrupt info
433824a1566SKashyap Desai  *
434824a1566SKashyap Desai  * poll for pending I/O completions in a loop until pending I/Os
435824a1566SKashyap Desai  * present or controller queue depth I/Os are processed.
436824a1566SKashyap Desai  *
437824a1566SKashyap Desai  * Return: IRQ_NONE or IRQ_HANDLED
438824a1566SKashyap Desai  */
439824a1566SKashyap Desai static irqreturn_t mpi3mr_isr_poll(int irq, void *privdata)
440824a1566SKashyap Desai {
441824a1566SKashyap Desai 	return IRQ_HANDLED;
442824a1566SKashyap Desai }
443824a1566SKashyap Desai 
444824a1566SKashyap Desai /**
445824a1566SKashyap Desai  * mpi3mr_request_irq - Request IRQ and register ISR
446824a1566SKashyap Desai  * @mrioc: Adapter instance reference
447824a1566SKashyap Desai  * @index: IRQ vector index
448824a1566SKashyap Desai  *
449824a1566SKashyap Desai  * Request threaded ISR with primary ISR and secondary
450824a1566SKashyap Desai  *
451824a1566SKashyap Desai  * Return: 0 on success and non zero on failures.
452824a1566SKashyap Desai  */
453824a1566SKashyap Desai static inline int mpi3mr_request_irq(struct mpi3mr_ioc *mrioc, u16 index)
454824a1566SKashyap Desai {
455824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
456824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info = mrioc->intr_info + index;
457824a1566SKashyap Desai 	int retval = 0;
458824a1566SKashyap Desai 
459824a1566SKashyap Desai 	intr_info->mrioc = mrioc;
460824a1566SKashyap Desai 	intr_info->msix_index = index;
461824a1566SKashyap Desai 	intr_info->op_reply_q = NULL;
462824a1566SKashyap Desai 
463824a1566SKashyap Desai 	snprintf(intr_info->name, MPI3MR_NAME_LENGTH, "%s%d-msix%d",
464824a1566SKashyap Desai 	    mrioc->driver_name, mrioc->id, index);
465824a1566SKashyap Desai 
466824a1566SKashyap Desai 	retval = request_threaded_irq(pci_irq_vector(pdev, index), mpi3mr_isr,
467824a1566SKashyap Desai 	    mpi3mr_isr_poll, IRQF_SHARED, intr_info->name, intr_info);
468824a1566SKashyap Desai 	if (retval) {
469824a1566SKashyap Desai 		ioc_err(mrioc, "%s: Unable to allocate interrupt %d!\n",
470824a1566SKashyap Desai 		    intr_info->name, pci_irq_vector(pdev, index));
471824a1566SKashyap Desai 		return retval;
472824a1566SKashyap Desai 	}
473824a1566SKashyap Desai 
474824a1566SKashyap Desai 	return retval;
475824a1566SKashyap Desai }
476824a1566SKashyap Desai 
477824a1566SKashyap Desai /**
478824a1566SKashyap Desai  * mpi3mr_setup_isr - Setup ISR for the controller
479824a1566SKashyap Desai  * @mrioc: Adapter instance reference
480824a1566SKashyap Desai  * @setup_one: Request one IRQ or more
481824a1566SKashyap Desai  *
482824a1566SKashyap Desai  * Allocate IRQ vectors and call mpi3mr_request_irq to setup ISR
483824a1566SKashyap Desai  *
484824a1566SKashyap Desai  * Return: 0 on success and non zero on failures.
485824a1566SKashyap Desai  */
486824a1566SKashyap Desai static int mpi3mr_setup_isr(struct mpi3mr_ioc *mrioc, u8 setup_one)
487824a1566SKashyap Desai {
488824a1566SKashyap Desai 	unsigned int irq_flags = PCI_IRQ_MSIX;
489824a1566SKashyap Desai 	u16 max_vectors = 0, i;
490824a1566SKashyap Desai 	int retval = 0;
491824a1566SKashyap Desai 	struct irq_affinity desc = { .pre_vectors =  1};
492824a1566SKashyap Desai 
493824a1566SKashyap Desai 	mpi3mr_cleanup_isr(mrioc);
494824a1566SKashyap Desai 
495824a1566SKashyap Desai 	if (setup_one || reset_devices)
496824a1566SKashyap Desai 		max_vectors = 1;
497824a1566SKashyap Desai 	else {
498824a1566SKashyap Desai 		max_vectors =
499824a1566SKashyap Desai 		    min_t(int, mrioc->cpu_count + 1, mrioc->msix_count);
500824a1566SKashyap Desai 
501824a1566SKashyap Desai 		ioc_info(mrioc,
502824a1566SKashyap Desai 		    "MSI-X vectors supported: %d, no of cores: %d,",
503824a1566SKashyap Desai 		    mrioc->msix_count, mrioc->cpu_count);
504824a1566SKashyap Desai 		ioc_info(mrioc,
505824a1566SKashyap Desai 		    "MSI-x vectors requested: %d\n", max_vectors);
506824a1566SKashyap Desai 	}
507824a1566SKashyap Desai 
508824a1566SKashyap Desai 	irq_flags |= PCI_IRQ_AFFINITY | PCI_IRQ_ALL_TYPES;
509824a1566SKashyap Desai 
510c9566231SKashyap Desai 	mrioc->op_reply_q_offset = (max_vectors > 1) ? 1 : 0;
511824a1566SKashyap Desai 	i = pci_alloc_irq_vectors_affinity(mrioc->pdev,
512824a1566SKashyap Desai 	    1, max_vectors, irq_flags, &desc);
513824a1566SKashyap Desai 	if (i <= 0) {
514824a1566SKashyap Desai 		ioc_err(mrioc, "Cannot alloc irq vectors\n");
515824a1566SKashyap Desai 		goto out_failed;
516824a1566SKashyap Desai 	}
517824a1566SKashyap Desai 	if (i != max_vectors) {
518824a1566SKashyap Desai 		ioc_info(mrioc,
519824a1566SKashyap Desai 		    "allocated vectors (%d) are less than configured (%d)\n",
520824a1566SKashyap Desai 		    i, max_vectors);
521c9566231SKashyap Desai 		/*
522c9566231SKashyap Desai 		 * If only one MSI-x is allocated, then MSI-x 0 will be shared
523c9566231SKashyap Desai 		 * between Admin queue and operational queue
524c9566231SKashyap Desai 		 */
525c9566231SKashyap Desai 		if (i == 1)
526c9566231SKashyap Desai 			mrioc->op_reply_q_offset = 0;
527824a1566SKashyap Desai 
528824a1566SKashyap Desai 		max_vectors = i;
529824a1566SKashyap Desai 	}
530824a1566SKashyap Desai 	mrioc->intr_info = kzalloc(sizeof(struct mpi3mr_intr_info) * max_vectors,
531824a1566SKashyap Desai 	    GFP_KERNEL);
532824a1566SKashyap Desai 	if (!mrioc->intr_info) {
533824a1566SKashyap Desai 		retval = -1;
534824a1566SKashyap Desai 		pci_free_irq_vectors(mrioc->pdev);
535824a1566SKashyap Desai 		goto out_failed;
536824a1566SKashyap Desai 	}
537824a1566SKashyap Desai 	for (i = 0; i < max_vectors; i++) {
538824a1566SKashyap Desai 		retval = mpi3mr_request_irq(mrioc, i);
539824a1566SKashyap Desai 		if (retval) {
540824a1566SKashyap Desai 			mrioc->intr_info_count = i;
541824a1566SKashyap Desai 			goto out_failed;
542824a1566SKashyap Desai 		}
543824a1566SKashyap Desai 	}
544824a1566SKashyap Desai 	mrioc->intr_info_count = max_vectors;
545824a1566SKashyap Desai 	mpi3mr_ioc_enable_intr(mrioc);
546824a1566SKashyap Desai 	return retval;
547824a1566SKashyap Desai out_failed:
548824a1566SKashyap Desai 	mpi3mr_cleanup_isr(mrioc);
549824a1566SKashyap Desai 
550824a1566SKashyap Desai 	return retval;
551824a1566SKashyap Desai }
552824a1566SKashyap Desai 
553824a1566SKashyap Desai static const struct {
554824a1566SKashyap Desai 	enum mpi3mr_iocstate value;
555824a1566SKashyap Desai 	char *name;
556824a1566SKashyap Desai } mrioc_states[] = {
557824a1566SKashyap Desai 	{ MRIOC_STATE_READY, "ready" },
558824a1566SKashyap Desai 	{ MRIOC_STATE_FAULT, "fault" },
559824a1566SKashyap Desai 	{ MRIOC_STATE_RESET, "reset" },
560824a1566SKashyap Desai 	{ MRIOC_STATE_BECOMING_READY, "becoming ready" },
561824a1566SKashyap Desai 	{ MRIOC_STATE_RESET_REQUESTED, "reset requested" },
562824a1566SKashyap Desai 	{ MRIOC_STATE_UNRECOVERABLE, "unrecoverable error" },
563824a1566SKashyap Desai };
564824a1566SKashyap Desai 
565824a1566SKashyap Desai static const char *mpi3mr_iocstate_name(enum mpi3mr_iocstate mrioc_state)
566824a1566SKashyap Desai {
567824a1566SKashyap Desai 	int i;
568824a1566SKashyap Desai 	char *name = NULL;
569824a1566SKashyap Desai 
570824a1566SKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mrioc_states); i++) {
571824a1566SKashyap Desai 		if (mrioc_states[i].value == mrioc_state) {
572824a1566SKashyap Desai 			name = mrioc_states[i].name;
573824a1566SKashyap Desai 			break;
574824a1566SKashyap Desai 		}
575824a1566SKashyap Desai 	}
576824a1566SKashyap Desai 	return name;
577824a1566SKashyap Desai }
578824a1566SKashyap Desai 
579824a1566SKashyap Desai /**
580824a1566SKashyap Desai  * mpi3mr_print_fault_info - Display fault information
581824a1566SKashyap Desai  * @mrioc: Adapter instance reference
582824a1566SKashyap Desai  *
583824a1566SKashyap Desai  * Display the controller fault information if there is a
584824a1566SKashyap Desai  * controller fault.
585824a1566SKashyap Desai  *
586824a1566SKashyap Desai  * Return: Nothing.
587824a1566SKashyap Desai  */
588824a1566SKashyap Desai static void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc)
589824a1566SKashyap Desai {
590824a1566SKashyap Desai 	u32 ioc_status, code, code1, code2, code3;
591824a1566SKashyap Desai 
592824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
593824a1566SKashyap Desai 
594824a1566SKashyap Desai 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) {
595824a1566SKashyap Desai 		code = readl(&mrioc->sysif_regs->fault);
596824a1566SKashyap Desai 		code1 = readl(&mrioc->sysif_regs->fault_info[0]);
597824a1566SKashyap Desai 		code2 = readl(&mrioc->sysif_regs->fault_info[1]);
598824a1566SKashyap Desai 		code3 = readl(&mrioc->sysif_regs->fault_info[2]);
599824a1566SKashyap Desai 
600824a1566SKashyap Desai 		ioc_info(mrioc,
601824a1566SKashyap Desai 		    "fault code(0x%08X): Additional code: (0x%08X:0x%08X:0x%08X)\n",
602824a1566SKashyap Desai 		    code, code1, code2, code3);
603824a1566SKashyap Desai 	}
604824a1566SKashyap Desai }
605824a1566SKashyap Desai 
606824a1566SKashyap Desai /**
607824a1566SKashyap Desai  * mpi3mr_get_iocstate - Get IOC State
608824a1566SKashyap Desai  * @mrioc: Adapter instance reference
609824a1566SKashyap Desai  *
610824a1566SKashyap Desai  * Return a proper IOC state enum based on the IOC status and
611824a1566SKashyap Desai  * IOC configuration and unrcoverable state of the controller.
612824a1566SKashyap Desai  *
613824a1566SKashyap Desai  * Return: Current IOC state.
614824a1566SKashyap Desai  */
615824a1566SKashyap Desai enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc)
616824a1566SKashyap Desai {
617824a1566SKashyap Desai 	u32 ioc_status, ioc_config;
618824a1566SKashyap Desai 	u8 ready, enabled;
619824a1566SKashyap Desai 
620824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
621824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
622824a1566SKashyap Desai 
623824a1566SKashyap Desai 	if (mrioc->unrecoverable)
624824a1566SKashyap Desai 		return MRIOC_STATE_UNRECOVERABLE;
625824a1566SKashyap Desai 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)
626824a1566SKashyap Desai 		return MRIOC_STATE_FAULT;
627824a1566SKashyap Desai 
628824a1566SKashyap Desai 	ready = (ioc_status & MPI3_SYSIF_IOC_STATUS_READY);
629824a1566SKashyap Desai 	enabled = (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC);
630824a1566SKashyap Desai 
631824a1566SKashyap Desai 	if (ready && enabled)
632824a1566SKashyap Desai 		return MRIOC_STATE_READY;
633824a1566SKashyap Desai 	if ((!ready) && (!enabled))
634824a1566SKashyap Desai 		return MRIOC_STATE_RESET;
635824a1566SKashyap Desai 	if ((!ready) && (enabled))
636824a1566SKashyap Desai 		return MRIOC_STATE_BECOMING_READY;
637824a1566SKashyap Desai 
638824a1566SKashyap Desai 	return MRIOC_STATE_RESET_REQUESTED;
639824a1566SKashyap Desai }
640824a1566SKashyap Desai 
641824a1566SKashyap Desai /**
642824a1566SKashyap Desai  * mpi3mr_clear_reset_history - clear reset history
643824a1566SKashyap Desai  * @mrioc: Adapter instance reference
644824a1566SKashyap Desai  *
645824a1566SKashyap Desai  * Write the reset history bit in IOC status to clear the bit,
646824a1566SKashyap Desai  * if it is already set.
647824a1566SKashyap Desai  *
648824a1566SKashyap Desai  * Return: Nothing.
649824a1566SKashyap Desai  */
650824a1566SKashyap Desai static inline void mpi3mr_clear_reset_history(struct mpi3mr_ioc *mrioc)
651824a1566SKashyap Desai {
652824a1566SKashyap Desai 	u32 ioc_status;
653824a1566SKashyap Desai 
654824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
655824a1566SKashyap Desai 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)
656824a1566SKashyap Desai 		writel(ioc_status, &mrioc->sysif_regs->ioc_status);
657824a1566SKashyap Desai }
658824a1566SKashyap Desai 
659824a1566SKashyap Desai /**
660824a1566SKashyap Desai  * mpi3mr_issue_and_process_mur - Message unit Reset handler
661824a1566SKashyap Desai  * @mrioc: Adapter instance reference
662824a1566SKashyap Desai  * @reset_reason: Reset reason code
663824a1566SKashyap Desai  *
664824a1566SKashyap Desai  * Issue Message unit Reset to the controller and wait for it to
665824a1566SKashyap Desai  * be complete.
666824a1566SKashyap Desai  *
667824a1566SKashyap Desai  * Return: 0 on success, -1 on failure.
668824a1566SKashyap Desai  */
669824a1566SKashyap Desai static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc,
670824a1566SKashyap Desai 	u32 reset_reason)
671824a1566SKashyap Desai {
672824a1566SKashyap Desai 	u32 ioc_config, timeout, ioc_status;
673824a1566SKashyap Desai 	int retval = -1;
674824a1566SKashyap Desai 
675824a1566SKashyap Desai 	ioc_info(mrioc, "Issuing Message unit Reset(MUR)\n");
676824a1566SKashyap Desai 	if (mrioc->unrecoverable) {
677824a1566SKashyap Desai 		ioc_info(mrioc, "IOC is unrecoverable MUR not issued\n");
678824a1566SKashyap Desai 		return retval;
679824a1566SKashyap Desai 	}
680824a1566SKashyap Desai 	mpi3mr_clear_reset_history(mrioc);
681824a1566SKashyap Desai 	writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]);
682824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
683824a1566SKashyap Desai 	ioc_config &= ~MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
684824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
685824a1566SKashyap Desai 
686824a1566SKashyap Desai 	timeout = mrioc->ready_timeout * 10;
687824a1566SKashyap Desai 	do {
688824a1566SKashyap Desai 		ioc_status = readl(&mrioc->sysif_regs->ioc_status);
689824a1566SKashyap Desai 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)) {
690824a1566SKashyap Desai 			mpi3mr_clear_reset_history(mrioc);
691824a1566SKashyap Desai 			ioc_config =
692824a1566SKashyap Desai 			    readl(&mrioc->sysif_regs->ioc_configuration);
693824a1566SKashyap Desai 			if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) ||
694824a1566SKashyap Desai 			      (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) ||
695824a1566SKashyap Desai 			    (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) {
696824a1566SKashyap Desai 				retval = 0;
697824a1566SKashyap Desai 				break;
698824a1566SKashyap Desai 			}
699824a1566SKashyap Desai 		}
700824a1566SKashyap Desai 		msleep(100);
701824a1566SKashyap Desai 	} while (--timeout);
702824a1566SKashyap Desai 
703824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
704824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
705824a1566SKashyap Desai 
706824a1566SKashyap Desai 	ioc_info(mrioc, "Base IOC Sts/Config after %s MUR is (0x%x)/(0x%x)\n",
707824a1566SKashyap Desai 	    (!retval) ? "successful" : "failed", ioc_status, ioc_config);
708824a1566SKashyap Desai 	return retval;
709824a1566SKashyap Desai }
710824a1566SKashyap Desai 
711824a1566SKashyap Desai /**
712824a1566SKashyap Desai  * mpi3mr_bring_ioc_ready - Bring controller to ready state
713824a1566SKashyap Desai  * @mrioc: Adapter instance reference
714824a1566SKashyap Desai  *
715824a1566SKashyap Desai  * Set Enable IOC bit in IOC configuration register and wait for
716824a1566SKashyap Desai  * the controller to become ready.
717824a1566SKashyap Desai  *
718824a1566SKashyap Desai  * Return: 0 on success, -1 on failure.
719824a1566SKashyap Desai  */
720824a1566SKashyap Desai static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc)
721824a1566SKashyap Desai {
722824a1566SKashyap Desai 	u32 ioc_config, timeout;
723824a1566SKashyap Desai 	enum mpi3mr_iocstate current_state;
724824a1566SKashyap Desai 
725824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
726824a1566SKashyap Desai 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
727824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
728824a1566SKashyap Desai 
729824a1566SKashyap Desai 	timeout = mrioc->ready_timeout * 10;
730824a1566SKashyap Desai 	do {
731824a1566SKashyap Desai 		current_state = mpi3mr_get_iocstate(mrioc);
732824a1566SKashyap Desai 		if (current_state == MRIOC_STATE_READY)
733824a1566SKashyap Desai 			return 0;
734824a1566SKashyap Desai 		msleep(100);
735824a1566SKashyap Desai 	} while (--timeout);
736824a1566SKashyap Desai 
737824a1566SKashyap Desai 	return -1;
738824a1566SKashyap Desai }
739824a1566SKashyap Desai 
740824a1566SKashyap Desai /**
741824a1566SKashyap Desai  * mpi3mr_set_diagsave - Set diag save bit for snapdump
742824a1566SKashyap Desai  * @mrioc: Adapter reference
743824a1566SKashyap Desai  *
744824a1566SKashyap Desai  * Set diag save bit in IOC configuration register to enable
745824a1566SKashyap Desai  * snapdump.
746824a1566SKashyap Desai  *
747824a1566SKashyap Desai  * Return: Nothing.
748824a1566SKashyap Desai  */
749824a1566SKashyap Desai static inline void mpi3mr_set_diagsave(struct mpi3mr_ioc *mrioc)
750824a1566SKashyap Desai {
751824a1566SKashyap Desai 	u32 ioc_config;
752824a1566SKashyap Desai 
753824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
754824a1566SKashyap Desai 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_DIAG_SAVE;
755824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
756824a1566SKashyap Desai }
757824a1566SKashyap Desai 
758824a1566SKashyap Desai /**
759824a1566SKashyap Desai  * mpi3mr_issue_reset - Issue reset to the controller
760824a1566SKashyap Desai  * @mrioc: Adapter reference
761824a1566SKashyap Desai  * @reset_type: Reset type
762824a1566SKashyap Desai  * @reset_reason: Reset reason code
763824a1566SKashyap Desai  *
764824a1566SKashyap Desai  * TBD
765824a1566SKashyap Desai  *
766824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
767824a1566SKashyap Desai  */
768824a1566SKashyap Desai static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type,
769824a1566SKashyap Desai 	u32 reset_reason)
770824a1566SKashyap Desai {
771824a1566SKashyap Desai 	return 0;
772824a1566SKashyap Desai }
773824a1566SKashyap Desai 
774824a1566SKashyap Desai /**
775824a1566SKashyap Desai  * mpi3mr_admin_request_post - Post request to admin queue
776824a1566SKashyap Desai  * @mrioc: Adapter reference
777824a1566SKashyap Desai  * @admin_req: MPI3 request
778824a1566SKashyap Desai  * @admin_req_sz: Request size
779824a1566SKashyap Desai  * @ignore_reset: Ignore reset in process
780824a1566SKashyap Desai  *
781824a1566SKashyap Desai  * Post the MPI3 request into admin request queue and
782824a1566SKashyap Desai  * inform the controller, if the queue is full return
783824a1566SKashyap Desai  * appropriate error.
784824a1566SKashyap Desai  *
785824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
786824a1566SKashyap Desai  */
787824a1566SKashyap Desai int mpi3mr_admin_request_post(struct mpi3mr_ioc *mrioc, void *admin_req,
788824a1566SKashyap Desai 	u16 admin_req_sz, u8 ignore_reset)
789824a1566SKashyap Desai {
790824a1566SKashyap Desai 	u16 areq_pi = 0, areq_ci = 0, max_entries = 0;
791824a1566SKashyap Desai 	int retval = 0;
792824a1566SKashyap Desai 	unsigned long flags;
793824a1566SKashyap Desai 	u8 *areq_entry;
794824a1566SKashyap Desai 
795824a1566SKashyap Desai 	if (mrioc->unrecoverable) {
796824a1566SKashyap Desai 		ioc_err(mrioc, "%s : Unrecoverable controller\n", __func__);
797824a1566SKashyap Desai 		return -EFAULT;
798824a1566SKashyap Desai 	}
799824a1566SKashyap Desai 
800824a1566SKashyap Desai 	spin_lock_irqsave(&mrioc->admin_req_lock, flags);
801824a1566SKashyap Desai 	areq_pi = mrioc->admin_req_pi;
802824a1566SKashyap Desai 	areq_ci = mrioc->admin_req_ci;
803824a1566SKashyap Desai 	max_entries = mrioc->num_admin_req;
804824a1566SKashyap Desai 	if ((areq_ci == (areq_pi + 1)) || ((!areq_ci) &&
805824a1566SKashyap Desai 	    (areq_pi == (max_entries - 1)))) {
806824a1566SKashyap Desai 		ioc_err(mrioc, "AdminReqQ full condition detected\n");
807824a1566SKashyap Desai 		retval = -EAGAIN;
808824a1566SKashyap Desai 		goto out;
809824a1566SKashyap Desai 	}
810824a1566SKashyap Desai 	if (!ignore_reset && mrioc->reset_in_progress) {
811824a1566SKashyap Desai 		ioc_err(mrioc, "AdminReqQ submit reset in progress\n");
812824a1566SKashyap Desai 		retval = -EAGAIN;
813824a1566SKashyap Desai 		goto out;
814824a1566SKashyap Desai 	}
815824a1566SKashyap Desai 	areq_entry = (u8 *)mrioc->admin_req_base +
816824a1566SKashyap Desai 	    (areq_pi * MPI3MR_ADMIN_REQ_FRAME_SZ);
817824a1566SKashyap Desai 	memset(areq_entry, 0, MPI3MR_ADMIN_REQ_FRAME_SZ);
818824a1566SKashyap Desai 	memcpy(areq_entry, (u8 *)admin_req, admin_req_sz);
819824a1566SKashyap Desai 
820824a1566SKashyap Desai 	if (++areq_pi == max_entries)
821824a1566SKashyap Desai 		areq_pi = 0;
822824a1566SKashyap Desai 	mrioc->admin_req_pi = areq_pi;
823824a1566SKashyap Desai 
824824a1566SKashyap Desai 	writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi);
825824a1566SKashyap Desai 
826824a1566SKashyap Desai out:
827824a1566SKashyap Desai 	spin_unlock_irqrestore(&mrioc->admin_req_lock, flags);
828824a1566SKashyap Desai 
829824a1566SKashyap Desai 	return retval;
830824a1566SKashyap Desai }
831824a1566SKashyap Desai 
832824a1566SKashyap Desai /**
833c9566231SKashyap Desai  * mpi3mr_free_op_req_q_segments - free request memory segments
834c9566231SKashyap Desai  * @mrioc: Adapter instance reference
835c9566231SKashyap Desai  * @q_idx: operational request queue index
836c9566231SKashyap Desai  *
837c9566231SKashyap Desai  * Free memory segments allocated for operational request queue
838c9566231SKashyap Desai  *
839c9566231SKashyap Desai  * Return: Nothing.
840c9566231SKashyap Desai  */
841c9566231SKashyap Desai static void mpi3mr_free_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx)
842c9566231SKashyap Desai {
843c9566231SKashyap Desai 	u16 j;
844c9566231SKashyap Desai 	int size;
845c9566231SKashyap Desai 	struct segments *segments;
846c9566231SKashyap Desai 
847c9566231SKashyap Desai 	segments = mrioc->req_qinfo[q_idx].q_segments;
848c9566231SKashyap Desai 	if (!segments)
849c9566231SKashyap Desai 		return;
850c9566231SKashyap Desai 
851c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
852c9566231SKashyap Desai 		size = MPI3MR_OP_REQ_Q_SEG_SIZE;
853c9566231SKashyap Desai 		if (mrioc->req_qinfo[q_idx].q_segment_list) {
854c9566231SKashyap Desai 			dma_free_coherent(&mrioc->pdev->dev,
855c9566231SKashyap Desai 			    MPI3MR_MAX_SEG_LIST_SIZE,
856c9566231SKashyap Desai 			    mrioc->req_qinfo[q_idx].q_segment_list,
857c9566231SKashyap Desai 			    mrioc->req_qinfo[q_idx].q_segment_list_dma);
858c9566231SKashyap Desai 			mrioc->op_reply_qinfo[q_idx].q_segment_list = NULL;
859c9566231SKashyap Desai 		}
860c9566231SKashyap Desai 	} else
861c9566231SKashyap Desai 		size = mrioc->req_qinfo[q_idx].num_requests *
862c9566231SKashyap Desai 		    mrioc->facts.op_req_sz;
863c9566231SKashyap Desai 
864c9566231SKashyap Desai 	for (j = 0; j < mrioc->req_qinfo[q_idx].num_segments; j++) {
865c9566231SKashyap Desai 		if (!segments[j].segment)
866c9566231SKashyap Desai 			continue;
867c9566231SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev,
868c9566231SKashyap Desai 		    size, segments[j].segment, segments[j].segment_dma);
869c9566231SKashyap Desai 		segments[j].segment = NULL;
870c9566231SKashyap Desai 	}
871c9566231SKashyap Desai 	kfree(mrioc->req_qinfo[q_idx].q_segments);
872c9566231SKashyap Desai 	mrioc->req_qinfo[q_idx].q_segments = NULL;
873c9566231SKashyap Desai 	mrioc->req_qinfo[q_idx].qid = 0;
874c9566231SKashyap Desai }
875c9566231SKashyap Desai 
876c9566231SKashyap Desai /**
877c9566231SKashyap Desai  * mpi3mr_free_op_reply_q_segments - free reply memory segments
878c9566231SKashyap Desai  * @mrioc: Adapter instance reference
879c9566231SKashyap Desai  * @q_idx: operational reply queue index
880c9566231SKashyap Desai  *
881c9566231SKashyap Desai  * Free memory segments allocated for operational reply queue
882c9566231SKashyap Desai  *
883c9566231SKashyap Desai  * Return: Nothing.
884c9566231SKashyap Desai  */
885c9566231SKashyap Desai static void mpi3mr_free_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx)
886c9566231SKashyap Desai {
887c9566231SKashyap Desai 	u16 j;
888c9566231SKashyap Desai 	int size;
889c9566231SKashyap Desai 	struct segments *segments;
890c9566231SKashyap Desai 
891c9566231SKashyap Desai 	segments = mrioc->op_reply_qinfo[q_idx].q_segments;
892c9566231SKashyap Desai 	if (!segments)
893c9566231SKashyap Desai 		return;
894c9566231SKashyap Desai 
895c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
896c9566231SKashyap Desai 		size = MPI3MR_OP_REP_Q_SEG_SIZE;
897c9566231SKashyap Desai 		if (mrioc->op_reply_qinfo[q_idx].q_segment_list) {
898c9566231SKashyap Desai 			dma_free_coherent(&mrioc->pdev->dev,
899c9566231SKashyap Desai 			    MPI3MR_MAX_SEG_LIST_SIZE,
900c9566231SKashyap Desai 			    mrioc->op_reply_qinfo[q_idx].q_segment_list,
901c9566231SKashyap Desai 			    mrioc->op_reply_qinfo[q_idx].q_segment_list_dma);
902c9566231SKashyap Desai 			mrioc->op_reply_qinfo[q_idx].q_segment_list = NULL;
903c9566231SKashyap Desai 		}
904c9566231SKashyap Desai 	} else
905c9566231SKashyap Desai 		size = mrioc->op_reply_qinfo[q_idx].segment_qd *
906c9566231SKashyap Desai 		    mrioc->op_reply_desc_sz;
907c9566231SKashyap Desai 
908c9566231SKashyap Desai 	for (j = 0; j < mrioc->op_reply_qinfo[q_idx].num_segments; j++) {
909c9566231SKashyap Desai 		if (!segments[j].segment)
910c9566231SKashyap Desai 			continue;
911c9566231SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev,
912c9566231SKashyap Desai 		    size, segments[j].segment, segments[j].segment_dma);
913c9566231SKashyap Desai 		segments[j].segment = NULL;
914c9566231SKashyap Desai 	}
915c9566231SKashyap Desai 
916c9566231SKashyap Desai 	kfree(mrioc->op_reply_qinfo[q_idx].q_segments);
917c9566231SKashyap Desai 	mrioc->op_reply_qinfo[q_idx].q_segments = NULL;
918c9566231SKashyap Desai 	mrioc->op_reply_qinfo[q_idx].qid = 0;
919c9566231SKashyap Desai }
920c9566231SKashyap Desai 
921c9566231SKashyap Desai /**
922c9566231SKashyap Desai  * mpi3mr_delete_op_reply_q - delete operational reply queue
923c9566231SKashyap Desai  * @mrioc: Adapter instance reference
924c9566231SKashyap Desai  * @qidx: operational reply queue index
925c9566231SKashyap Desai  *
926c9566231SKashyap Desai  * Delete operatinal reply queue by issuing MPI request
927c9566231SKashyap Desai  * through admin queue.
928c9566231SKashyap Desai  *
929c9566231SKashyap Desai  * Return:  0 on success, non-zero on failure.
930c9566231SKashyap Desai  */
931c9566231SKashyap Desai static int mpi3mr_delete_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx)
932c9566231SKashyap Desai {
933c9566231SKashyap Desai 	struct mpi3_delete_reply_queue_request delq_req;
934c9566231SKashyap Desai 	int retval = 0;
935c9566231SKashyap Desai 	u16 reply_qid = 0, midx;
936c9566231SKashyap Desai 
937c9566231SKashyap Desai 	reply_qid = mrioc->op_reply_qinfo[qidx].qid;
938c9566231SKashyap Desai 
939c9566231SKashyap Desai 	midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset);
940c9566231SKashyap Desai 
941c9566231SKashyap Desai 	if (!reply_qid)	{
942c9566231SKashyap Desai 		retval = -1;
943c9566231SKashyap Desai 		ioc_err(mrioc, "Issue DelRepQ: called with invalid ReqQID\n");
944c9566231SKashyap Desai 		goto out;
945c9566231SKashyap Desai 	}
946c9566231SKashyap Desai 
947c9566231SKashyap Desai 	memset(&delq_req, 0, sizeof(delq_req));
948c9566231SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
949c9566231SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
950c9566231SKashyap Desai 		retval = -1;
951c9566231SKashyap Desai 		ioc_err(mrioc, "Issue DelRepQ: Init command is in use\n");
952c9566231SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
953c9566231SKashyap Desai 		goto out;
954c9566231SKashyap Desai 	}
955c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
956c9566231SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
957c9566231SKashyap Desai 	mrioc->init_cmds.callback = NULL;
958c9566231SKashyap Desai 	delq_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
959c9566231SKashyap Desai 	delq_req.function = MPI3_FUNCTION_DELETE_REPLY_QUEUE;
960c9566231SKashyap Desai 	delq_req.queue_id = cpu_to_le16(reply_qid);
961c9566231SKashyap Desai 
962c9566231SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
963c9566231SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &delq_req, sizeof(delq_req),
964c9566231SKashyap Desai 	    1);
965c9566231SKashyap Desai 	if (retval) {
966c9566231SKashyap Desai 		ioc_err(mrioc, "Issue DelRepQ: Admin Post failed\n");
967c9566231SKashyap Desai 		goto out_unlock;
968c9566231SKashyap Desai 	}
969c9566231SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
970c9566231SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
971c9566231SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
972c9566231SKashyap Desai 		ioc_err(mrioc, "Issue DelRepQ: command timed out\n");
973c9566231SKashyap Desai 		mpi3mr_set_diagsave(mrioc);
974c9566231SKashyap Desai 		mpi3mr_issue_reset(mrioc,
975c9566231SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
976c9566231SKashyap Desai 		    MPI3MR_RESET_FROM_DELREPQ_TIMEOUT);
977c9566231SKashyap Desai 		mrioc->unrecoverable = 1;
978c9566231SKashyap Desai 
979c9566231SKashyap Desai 		retval = -1;
980c9566231SKashyap Desai 		goto out_unlock;
981c9566231SKashyap Desai 	}
982c9566231SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
983c9566231SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
984c9566231SKashyap Desai 		ioc_err(mrioc,
985c9566231SKashyap Desai 		    "Issue DelRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
986c9566231SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
987c9566231SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
988c9566231SKashyap Desai 		retval = -1;
989c9566231SKashyap Desai 		goto out_unlock;
990c9566231SKashyap Desai 	}
991c9566231SKashyap Desai 	mrioc->intr_info[midx].op_reply_q = NULL;
992c9566231SKashyap Desai 
993c9566231SKashyap Desai 	mpi3mr_free_op_reply_q_segments(mrioc, qidx);
994c9566231SKashyap Desai out_unlock:
995c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
996c9566231SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
997c9566231SKashyap Desai out:
998c9566231SKashyap Desai 
999c9566231SKashyap Desai 	return retval;
1000c9566231SKashyap Desai }
1001c9566231SKashyap Desai 
1002c9566231SKashyap Desai /**
1003c9566231SKashyap Desai  * mpi3mr_alloc_op_reply_q_segments -Alloc segmented reply pool
1004c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1005c9566231SKashyap Desai  * @qidx: request queue index
1006c9566231SKashyap Desai  *
1007c9566231SKashyap Desai  * Allocate segmented memory pools for operational reply
1008c9566231SKashyap Desai  * queue.
1009c9566231SKashyap Desai  *
1010c9566231SKashyap Desai  * Return: 0 on success, non-zero on failure.
1011c9566231SKashyap Desai  */
1012c9566231SKashyap Desai static int mpi3mr_alloc_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx)
1013c9566231SKashyap Desai {
1014c9566231SKashyap Desai 	struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
1015c9566231SKashyap Desai 	int i, size;
1016c9566231SKashyap Desai 	u64 *q_segment_list_entry = NULL;
1017c9566231SKashyap Desai 	struct segments *segments;
1018c9566231SKashyap Desai 
1019c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1020c9566231SKashyap Desai 		op_reply_q->segment_qd =
1021c9566231SKashyap Desai 		    MPI3MR_OP_REP_Q_SEG_SIZE / mrioc->op_reply_desc_sz;
1022c9566231SKashyap Desai 
1023c9566231SKashyap Desai 		size = MPI3MR_OP_REP_Q_SEG_SIZE;
1024c9566231SKashyap Desai 
1025c9566231SKashyap Desai 		op_reply_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev,
1026c9566231SKashyap Desai 		    MPI3MR_MAX_SEG_LIST_SIZE, &op_reply_q->q_segment_list_dma,
1027c9566231SKashyap Desai 		    GFP_KERNEL);
1028c9566231SKashyap Desai 		if (!op_reply_q->q_segment_list)
1029c9566231SKashyap Desai 			return -ENOMEM;
1030c9566231SKashyap Desai 		q_segment_list_entry = (u64 *)op_reply_q->q_segment_list;
1031c9566231SKashyap Desai 	} else {
1032c9566231SKashyap Desai 		op_reply_q->segment_qd = op_reply_q->num_replies;
1033c9566231SKashyap Desai 		size = op_reply_q->num_replies * mrioc->op_reply_desc_sz;
1034c9566231SKashyap Desai 	}
1035c9566231SKashyap Desai 
1036c9566231SKashyap Desai 	op_reply_q->num_segments = DIV_ROUND_UP(op_reply_q->num_replies,
1037c9566231SKashyap Desai 	    op_reply_q->segment_qd);
1038c9566231SKashyap Desai 
1039c9566231SKashyap Desai 	op_reply_q->q_segments = kcalloc(op_reply_q->num_segments,
1040c9566231SKashyap Desai 	    sizeof(struct segments), GFP_KERNEL);
1041c9566231SKashyap Desai 	if (!op_reply_q->q_segments)
1042c9566231SKashyap Desai 		return -ENOMEM;
1043c9566231SKashyap Desai 
1044c9566231SKashyap Desai 	segments = op_reply_q->q_segments;
1045c9566231SKashyap Desai 	for (i = 0; i < op_reply_q->num_segments; i++) {
1046c9566231SKashyap Desai 		segments[i].segment =
1047c9566231SKashyap Desai 		    dma_alloc_coherent(&mrioc->pdev->dev,
1048c9566231SKashyap Desai 		    size, &segments[i].segment_dma, GFP_KERNEL);
1049c9566231SKashyap Desai 		if (!segments[i].segment)
1050c9566231SKashyap Desai 			return -ENOMEM;
1051c9566231SKashyap Desai 		if (mrioc->enable_segqueue)
1052c9566231SKashyap Desai 			q_segment_list_entry[i] =
1053c9566231SKashyap Desai 			    (unsigned long)segments[i].segment_dma;
1054c9566231SKashyap Desai 	}
1055c9566231SKashyap Desai 
1056c9566231SKashyap Desai 	return 0;
1057c9566231SKashyap Desai }
1058c9566231SKashyap Desai 
1059c9566231SKashyap Desai /**
1060c9566231SKashyap Desai  * mpi3mr_alloc_op_req_q_segments - Alloc segmented req pool.
1061c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1062c9566231SKashyap Desai  * @qidx: request queue index
1063c9566231SKashyap Desai  *
1064c9566231SKashyap Desai  * Allocate segmented memory pools for operational request
1065c9566231SKashyap Desai  * queue.
1066c9566231SKashyap Desai  *
1067c9566231SKashyap Desai  * Return: 0 on success, non-zero on failure.
1068c9566231SKashyap Desai  */
1069c9566231SKashyap Desai static int mpi3mr_alloc_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx)
1070c9566231SKashyap Desai {
1071c9566231SKashyap Desai 	struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx;
1072c9566231SKashyap Desai 	int i, size;
1073c9566231SKashyap Desai 	u64 *q_segment_list_entry = NULL;
1074c9566231SKashyap Desai 	struct segments *segments;
1075c9566231SKashyap Desai 
1076c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1077c9566231SKashyap Desai 		op_req_q->segment_qd =
1078c9566231SKashyap Desai 		    MPI3MR_OP_REQ_Q_SEG_SIZE / mrioc->facts.op_req_sz;
1079c9566231SKashyap Desai 
1080c9566231SKashyap Desai 		size = MPI3MR_OP_REQ_Q_SEG_SIZE;
1081c9566231SKashyap Desai 
1082c9566231SKashyap Desai 		op_req_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev,
1083c9566231SKashyap Desai 		    MPI3MR_MAX_SEG_LIST_SIZE, &op_req_q->q_segment_list_dma,
1084c9566231SKashyap Desai 		    GFP_KERNEL);
1085c9566231SKashyap Desai 		if (!op_req_q->q_segment_list)
1086c9566231SKashyap Desai 			return -ENOMEM;
1087c9566231SKashyap Desai 		q_segment_list_entry = (u64 *)op_req_q->q_segment_list;
1088c9566231SKashyap Desai 
1089c9566231SKashyap Desai 	} else {
1090c9566231SKashyap Desai 		op_req_q->segment_qd = op_req_q->num_requests;
1091c9566231SKashyap Desai 		size = op_req_q->num_requests * mrioc->facts.op_req_sz;
1092c9566231SKashyap Desai 	}
1093c9566231SKashyap Desai 
1094c9566231SKashyap Desai 	op_req_q->num_segments = DIV_ROUND_UP(op_req_q->num_requests,
1095c9566231SKashyap Desai 	    op_req_q->segment_qd);
1096c9566231SKashyap Desai 
1097c9566231SKashyap Desai 	op_req_q->q_segments = kcalloc(op_req_q->num_segments,
1098c9566231SKashyap Desai 	    sizeof(struct segments), GFP_KERNEL);
1099c9566231SKashyap Desai 	if (!op_req_q->q_segments)
1100c9566231SKashyap Desai 		return -ENOMEM;
1101c9566231SKashyap Desai 
1102c9566231SKashyap Desai 	segments = op_req_q->q_segments;
1103c9566231SKashyap Desai 	for (i = 0; i < op_req_q->num_segments; i++) {
1104c9566231SKashyap Desai 		segments[i].segment =
1105c9566231SKashyap Desai 		    dma_alloc_coherent(&mrioc->pdev->dev,
1106c9566231SKashyap Desai 		    size, &segments[i].segment_dma, GFP_KERNEL);
1107c9566231SKashyap Desai 		if (!segments[i].segment)
1108c9566231SKashyap Desai 			return -ENOMEM;
1109c9566231SKashyap Desai 		if (mrioc->enable_segqueue)
1110c9566231SKashyap Desai 			q_segment_list_entry[i] =
1111c9566231SKashyap Desai 			    (unsigned long)segments[i].segment_dma;
1112c9566231SKashyap Desai 	}
1113c9566231SKashyap Desai 
1114c9566231SKashyap Desai 	return 0;
1115c9566231SKashyap Desai }
1116c9566231SKashyap Desai 
1117c9566231SKashyap Desai /**
1118c9566231SKashyap Desai  * mpi3mr_create_op_reply_q - create operational reply queue
1119c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1120c9566231SKashyap Desai  * @qidx: operational reply queue index
1121c9566231SKashyap Desai  *
1122c9566231SKashyap Desai  * Create operatinal reply queue by issuing MPI request
1123c9566231SKashyap Desai  * through admin queue.
1124c9566231SKashyap Desai  *
1125c9566231SKashyap Desai  * Return:  0 on success, non-zero on failure.
1126c9566231SKashyap Desai  */
1127c9566231SKashyap Desai static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx)
1128c9566231SKashyap Desai {
1129c9566231SKashyap Desai 	struct mpi3_create_reply_queue_request create_req;
1130c9566231SKashyap Desai 	struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
1131c9566231SKashyap Desai 	int retval = 0;
1132c9566231SKashyap Desai 	u16 reply_qid = 0, midx;
1133c9566231SKashyap Desai 
1134c9566231SKashyap Desai 	reply_qid = op_reply_q->qid;
1135c9566231SKashyap Desai 
1136c9566231SKashyap Desai 	midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset);
1137c9566231SKashyap Desai 
1138c9566231SKashyap Desai 	if (reply_qid) {
1139c9566231SKashyap Desai 		retval = -1;
1140c9566231SKashyap Desai 		ioc_err(mrioc, "CreateRepQ: called for duplicate qid %d\n",
1141c9566231SKashyap Desai 		    reply_qid);
1142c9566231SKashyap Desai 
1143c9566231SKashyap Desai 		return retval;
1144c9566231SKashyap Desai 	}
1145c9566231SKashyap Desai 
1146c9566231SKashyap Desai 	reply_qid = qidx + 1;
1147c9566231SKashyap Desai 	op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD;
1148c9566231SKashyap Desai 	op_reply_q->ci = 0;
1149c9566231SKashyap Desai 	op_reply_q->ephase = 1;
1150c9566231SKashyap Desai 
1151c9566231SKashyap Desai 	if (!op_reply_q->q_segments) {
1152c9566231SKashyap Desai 		retval = mpi3mr_alloc_op_reply_q_segments(mrioc, qidx);
1153c9566231SKashyap Desai 		if (retval) {
1154c9566231SKashyap Desai 			mpi3mr_free_op_reply_q_segments(mrioc, qidx);
1155c9566231SKashyap Desai 			goto out;
1156c9566231SKashyap Desai 		}
1157c9566231SKashyap Desai 	}
1158c9566231SKashyap Desai 
1159c9566231SKashyap Desai 	memset(&create_req, 0, sizeof(create_req));
1160c9566231SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
1161c9566231SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
1162c9566231SKashyap Desai 		retval = -1;
1163c9566231SKashyap Desai 		ioc_err(mrioc, "CreateRepQ: Init command is in use\n");
1164c9566231SKashyap Desai 		goto out;
1165c9566231SKashyap Desai 	}
1166c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
1167c9566231SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
1168c9566231SKashyap Desai 	mrioc->init_cmds.callback = NULL;
1169c9566231SKashyap Desai 	create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
1170c9566231SKashyap Desai 	create_req.function = MPI3_FUNCTION_CREATE_REPLY_QUEUE;
1171c9566231SKashyap Desai 	create_req.queue_id = cpu_to_le16(reply_qid);
1172c9566231SKashyap Desai 	create_req.flags = MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_ENABLE;
1173c9566231SKashyap Desai 	create_req.msix_index = cpu_to_le16(mrioc->intr_info[midx].msix_index);
1174c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1175c9566231SKashyap Desai 		create_req.flags |=
1176c9566231SKashyap Desai 		    MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED;
1177c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
1178c9566231SKashyap Desai 		    op_reply_q->q_segment_list_dma);
1179c9566231SKashyap Desai 	} else
1180c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
1181c9566231SKashyap Desai 		    op_reply_q->q_segments[0].segment_dma);
1182c9566231SKashyap Desai 
1183c9566231SKashyap Desai 	create_req.size = cpu_to_le16(op_reply_q->num_replies);
1184c9566231SKashyap Desai 
1185c9566231SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
1186c9566231SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &create_req,
1187c9566231SKashyap Desai 	    sizeof(create_req), 1);
1188c9566231SKashyap Desai 	if (retval) {
1189c9566231SKashyap Desai 		ioc_err(mrioc, "CreateRepQ: Admin Post failed\n");
1190c9566231SKashyap Desai 		goto out_unlock;
1191c9566231SKashyap Desai 	}
1192c9566231SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
1193c9566231SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
1194c9566231SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
1195c9566231SKashyap Desai 		ioc_err(mrioc, "CreateRepQ: command timed out\n");
1196c9566231SKashyap Desai 		mpi3mr_set_diagsave(mrioc);
1197c9566231SKashyap Desai 		mpi3mr_issue_reset(mrioc,
1198c9566231SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
1199c9566231SKashyap Desai 		    MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT);
1200c9566231SKashyap Desai 		mrioc->unrecoverable = 1;
1201c9566231SKashyap Desai 		retval = -1;
1202c9566231SKashyap Desai 		goto out_unlock;
1203c9566231SKashyap Desai 	}
1204c9566231SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
1205c9566231SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
1206c9566231SKashyap Desai 		ioc_err(mrioc,
1207c9566231SKashyap Desai 		    "CreateRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
1208c9566231SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
1209c9566231SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
1210c9566231SKashyap Desai 		retval = -1;
1211c9566231SKashyap Desai 		goto out_unlock;
1212c9566231SKashyap Desai 	}
1213c9566231SKashyap Desai 	op_reply_q->qid = reply_qid;
1214c9566231SKashyap Desai 	mrioc->intr_info[midx].op_reply_q = op_reply_q;
1215c9566231SKashyap Desai 
1216c9566231SKashyap Desai out_unlock:
1217c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
1218c9566231SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
1219c9566231SKashyap Desai out:
1220c9566231SKashyap Desai 
1221c9566231SKashyap Desai 	return retval;
1222c9566231SKashyap Desai }
1223c9566231SKashyap Desai 
1224c9566231SKashyap Desai /**
1225c9566231SKashyap Desai  * mpi3mr_create_op_req_q - create operational request queue
1226c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1227c9566231SKashyap Desai  * @idx: operational request queue index
1228c9566231SKashyap Desai  * @reply_qid: Reply queue ID
1229c9566231SKashyap Desai  *
1230c9566231SKashyap Desai  * Create operatinal request queue by issuing MPI request
1231c9566231SKashyap Desai  * through admin queue.
1232c9566231SKashyap Desai  *
1233c9566231SKashyap Desai  * Return:  0 on success, non-zero on failure.
1234c9566231SKashyap Desai  */
1235c9566231SKashyap Desai static int mpi3mr_create_op_req_q(struct mpi3mr_ioc *mrioc, u16 idx,
1236c9566231SKashyap Desai 	u16 reply_qid)
1237c9566231SKashyap Desai {
1238c9566231SKashyap Desai 	struct mpi3_create_request_queue_request create_req;
1239c9566231SKashyap Desai 	struct op_req_qinfo *op_req_q = mrioc->req_qinfo + idx;
1240c9566231SKashyap Desai 	int retval = 0;
1241c9566231SKashyap Desai 	u16 req_qid = 0;
1242c9566231SKashyap Desai 
1243c9566231SKashyap Desai 	req_qid = op_req_q->qid;
1244c9566231SKashyap Desai 
1245c9566231SKashyap Desai 	if (req_qid) {
1246c9566231SKashyap Desai 		retval = -1;
1247c9566231SKashyap Desai 		ioc_err(mrioc, "CreateReqQ: called for duplicate qid %d\n",
1248c9566231SKashyap Desai 		    req_qid);
1249c9566231SKashyap Desai 
1250c9566231SKashyap Desai 		return retval;
1251c9566231SKashyap Desai 	}
1252c9566231SKashyap Desai 	req_qid = idx + 1;
1253c9566231SKashyap Desai 
1254c9566231SKashyap Desai 	op_req_q->num_requests = MPI3MR_OP_REQ_Q_QD;
1255c9566231SKashyap Desai 	op_req_q->ci = 0;
1256c9566231SKashyap Desai 	op_req_q->pi = 0;
1257c9566231SKashyap Desai 	op_req_q->reply_qid = reply_qid;
1258c9566231SKashyap Desai 	spin_lock_init(&op_req_q->q_lock);
1259c9566231SKashyap Desai 
1260c9566231SKashyap Desai 	if (!op_req_q->q_segments) {
1261c9566231SKashyap Desai 		retval = mpi3mr_alloc_op_req_q_segments(mrioc, idx);
1262c9566231SKashyap Desai 		if (retval) {
1263c9566231SKashyap Desai 			mpi3mr_free_op_req_q_segments(mrioc, idx);
1264c9566231SKashyap Desai 			goto out;
1265c9566231SKashyap Desai 		}
1266c9566231SKashyap Desai 	}
1267c9566231SKashyap Desai 
1268c9566231SKashyap Desai 	memset(&create_req, 0, sizeof(create_req));
1269c9566231SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
1270c9566231SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
1271c9566231SKashyap Desai 		retval = -1;
1272c9566231SKashyap Desai 		ioc_err(mrioc, "CreateReqQ: Init command is in use\n");
1273c9566231SKashyap Desai 		goto out;
1274c9566231SKashyap Desai 	}
1275c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
1276c9566231SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
1277c9566231SKashyap Desai 	mrioc->init_cmds.callback = NULL;
1278c9566231SKashyap Desai 	create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
1279c9566231SKashyap Desai 	create_req.function = MPI3_FUNCTION_CREATE_REQUEST_QUEUE;
1280c9566231SKashyap Desai 	create_req.queue_id = cpu_to_le16(req_qid);
1281c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1282c9566231SKashyap Desai 		create_req.flags =
1283c9566231SKashyap Desai 		    MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED;
1284c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
1285c9566231SKashyap Desai 		    op_req_q->q_segment_list_dma);
1286c9566231SKashyap Desai 	} else
1287c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
1288c9566231SKashyap Desai 		    op_req_q->q_segments[0].segment_dma);
1289c9566231SKashyap Desai 	create_req.reply_queue_id = cpu_to_le16(reply_qid);
1290c9566231SKashyap Desai 	create_req.size = cpu_to_le16(op_req_q->num_requests);
1291c9566231SKashyap Desai 
1292c9566231SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
1293c9566231SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &create_req,
1294c9566231SKashyap Desai 	    sizeof(create_req), 1);
1295c9566231SKashyap Desai 	if (retval) {
1296c9566231SKashyap Desai 		ioc_err(mrioc, "CreateReqQ: Admin Post failed\n");
1297c9566231SKashyap Desai 		goto out_unlock;
1298c9566231SKashyap Desai 	}
1299c9566231SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
1300c9566231SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
1301c9566231SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
1302c9566231SKashyap Desai 		ioc_err(mrioc, "CreateReqQ: command timed out\n");
1303c9566231SKashyap Desai 		mpi3mr_set_diagsave(mrioc);
1304c9566231SKashyap Desai 		if (mpi3mr_issue_reset(mrioc,
1305c9566231SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
1306c9566231SKashyap Desai 		    MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT))
1307c9566231SKashyap Desai 			mrioc->unrecoverable = 1;
1308c9566231SKashyap Desai 		retval = -1;
1309c9566231SKashyap Desai 		goto out_unlock;
1310c9566231SKashyap Desai 	}
1311c9566231SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
1312c9566231SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
1313c9566231SKashyap Desai 		ioc_err(mrioc,
1314c9566231SKashyap Desai 		    "CreateReqQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
1315c9566231SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
1316c9566231SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
1317c9566231SKashyap Desai 		retval = -1;
1318c9566231SKashyap Desai 		goto out_unlock;
1319c9566231SKashyap Desai 	}
1320c9566231SKashyap Desai 	op_req_q->qid = req_qid;
1321c9566231SKashyap Desai 
1322c9566231SKashyap Desai out_unlock:
1323c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
1324c9566231SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
1325c9566231SKashyap Desai out:
1326c9566231SKashyap Desai 
1327c9566231SKashyap Desai 	return retval;
1328c9566231SKashyap Desai }
1329c9566231SKashyap Desai 
1330c9566231SKashyap Desai /**
1331c9566231SKashyap Desai  * mpi3mr_create_op_queues - create operational queue pairs
1332c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1333c9566231SKashyap Desai  *
1334c9566231SKashyap Desai  * Allocate memory for operational queue meta data and call
1335c9566231SKashyap Desai  * create request and reply queue functions.
1336c9566231SKashyap Desai  *
1337c9566231SKashyap Desai  * Return: 0 on success, non-zero on failures.
1338c9566231SKashyap Desai  */
1339c9566231SKashyap Desai static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc)
1340c9566231SKashyap Desai {
1341c9566231SKashyap Desai 	int retval = 0;
1342c9566231SKashyap Desai 	u16 num_queues = 0, i = 0, msix_count_op_q = 1;
1343c9566231SKashyap Desai 
1344c9566231SKashyap Desai 	num_queues = min_t(int, mrioc->facts.max_op_reply_q,
1345c9566231SKashyap Desai 	    mrioc->facts.max_op_req_q);
1346c9566231SKashyap Desai 
1347c9566231SKashyap Desai 	msix_count_op_q =
1348c9566231SKashyap Desai 	    mrioc->intr_info_count - mrioc->op_reply_q_offset;
1349c9566231SKashyap Desai 	if (!mrioc->num_queues)
1350c9566231SKashyap Desai 		mrioc->num_queues = min_t(int, num_queues, msix_count_op_q);
1351c9566231SKashyap Desai 	num_queues = mrioc->num_queues;
1352c9566231SKashyap Desai 	ioc_info(mrioc, "Trying to create %d Operational Q pairs\n",
1353c9566231SKashyap Desai 	    num_queues);
1354c9566231SKashyap Desai 
1355c9566231SKashyap Desai 	if (!mrioc->req_qinfo) {
1356c9566231SKashyap Desai 		mrioc->req_qinfo = kcalloc(num_queues,
1357c9566231SKashyap Desai 		    sizeof(struct op_req_qinfo), GFP_KERNEL);
1358c9566231SKashyap Desai 		if (!mrioc->req_qinfo) {
1359c9566231SKashyap Desai 			retval = -1;
1360c9566231SKashyap Desai 			goto out_failed;
1361c9566231SKashyap Desai 		}
1362c9566231SKashyap Desai 
1363c9566231SKashyap Desai 		mrioc->op_reply_qinfo = kzalloc(sizeof(struct op_reply_qinfo) *
1364c9566231SKashyap Desai 		    num_queues, GFP_KERNEL);
1365c9566231SKashyap Desai 		if (!mrioc->op_reply_qinfo) {
1366c9566231SKashyap Desai 			retval = -1;
1367c9566231SKashyap Desai 			goto out_failed;
1368c9566231SKashyap Desai 		}
1369c9566231SKashyap Desai 	}
1370c9566231SKashyap Desai 
1371c9566231SKashyap Desai 	if (mrioc->enable_segqueue)
1372c9566231SKashyap Desai 		ioc_info(mrioc,
1373c9566231SKashyap Desai 		    "allocating operational queues through segmented queues\n");
1374c9566231SKashyap Desai 
1375c9566231SKashyap Desai 	for (i = 0; i < num_queues; i++) {
1376c9566231SKashyap Desai 		if (mpi3mr_create_op_reply_q(mrioc, i)) {
1377c9566231SKashyap Desai 			ioc_err(mrioc, "Cannot create OP RepQ %d\n", i);
1378c9566231SKashyap Desai 			break;
1379c9566231SKashyap Desai 		}
1380c9566231SKashyap Desai 		if (mpi3mr_create_op_req_q(mrioc, i,
1381c9566231SKashyap Desai 		    mrioc->op_reply_qinfo[i].qid)) {
1382c9566231SKashyap Desai 			ioc_err(mrioc, "Cannot create OP ReqQ %d\n", i);
1383c9566231SKashyap Desai 			mpi3mr_delete_op_reply_q(mrioc, i);
1384c9566231SKashyap Desai 			break;
1385c9566231SKashyap Desai 		}
1386c9566231SKashyap Desai 	}
1387c9566231SKashyap Desai 
1388c9566231SKashyap Desai 	if (i == 0) {
1389c9566231SKashyap Desai 		/* Not even one queue is created successfully*/
1390c9566231SKashyap Desai 		retval = -1;
1391c9566231SKashyap Desai 		goto out_failed;
1392c9566231SKashyap Desai 	}
1393c9566231SKashyap Desai 	mrioc->num_op_reply_q = mrioc->num_op_req_q = i;
1394c9566231SKashyap Desai 	ioc_info(mrioc, "Successfully created %d Operational Q pairs\n",
1395c9566231SKashyap Desai 	    mrioc->num_op_reply_q);
1396c9566231SKashyap Desai 
1397c9566231SKashyap Desai 	return retval;
1398c9566231SKashyap Desai out_failed:
1399c9566231SKashyap Desai 	kfree(mrioc->req_qinfo);
1400c9566231SKashyap Desai 	mrioc->req_qinfo = NULL;
1401c9566231SKashyap Desai 
1402c9566231SKashyap Desai 	kfree(mrioc->op_reply_qinfo);
1403c9566231SKashyap Desai 	mrioc->op_reply_qinfo = NULL;
1404c9566231SKashyap Desai 
1405c9566231SKashyap Desai 	return retval;
1406c9566231SKashyap Desai }
1407c9566231SKashyap Desai 
1408c9566231SKashyap Desai /**
1409023ab2a9SKashyap Desai  * mpi3mr_op_request_post - Post request to operational queue
1410023ab2a9SKashyap Desai  * @mrioc: Adapter reference
1411023ab2a9SKashyap Desai  * @op_req_q: Operational request queue info
1412023ab2a9SKashyap Desai  * @req: MPI3 request
1413023ab2a9SKashyap Desai  *
1414023ab2a9SKashyap Desai  * Post the MPI3 request into operational request queue and
1415023ab2a9SKashyap Desai  * inform the controller, if the queue is full return
1416023ab2a9SKashyap Desai  * appropriate error.
1417023ab2a9SKashyap Desai  *
1418023ab2a9SKashyap Desai  * Return: 0 on success, non-zero on failure.
1419023ab2a9SKashyap Desai  */
1420023ab2a9SKashyap Desai int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc,
1421023ab2a9SKashyap Desai 	struct op_req_qinfo *op_req_q, u8 *req)
1422023ab2a9SKashyap Desai {
1423023ab2a9SKashyap Desai 	u16 pi = 0, max_entries, reply_qidx = 0, midx;
1424023ab2a9SKashyap Desai 	int retval = 0;
1425023ab2a9SKashyap Desai 	unsigned long flags;
1426023ab2a9SKashyap Desai 	u8 *req_entry;
1427023ab2a9SKashyap Desai 	void *segment_base_addr;
1428023ab2a9SKashyap Desai 	u16 req_sz = mrioc->facts.op_req_sz;
1429023ab2a9SKashyap Desai 	struct segments *segments = op_req_q->q_segments;
1430023ab2a9SKashyap Desai 
1431023ab2a9SKashyap Desai 	reply_qidx = op_req_q->reply_qid - 1;
1432023ab2a9SKashyap Desai 
1433023ab2a9SKashyap Desai 	if (mrioc->unrecoverable)
1434023ab2a9SKashyap Desai 		return -EFAULT;
1435023ab2a9SKashyap Desai 
1436023ab2a9SKashyap Desai 	spin_lock_irqsave(&op_req_q->q_lock, flags);
1437023ab2a9SKashyap Desai 	pi = op_req_q->pi;
1438023ab2a9SKashyap Desai 	max_entries = op_req_q->num_requests;
1439023ab2a9SKashyap Desai 
1440023ab2a9SKashyap Desai 	if (mpi3mr_check_req_qfull(op_req_q)) {
1441023ab2a9SKashyap Desai 		midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(
1442023ab2a9SKashyap Desai 		    reply_qidx, mrioc->op_reply_q_offset);
1443023ab2a9SKashyap Desai 		mpi3mr_process_op_reply_q(mrioc, &mrioc->intr_info[midx]);
1444023ab2a9SKashyap Desai 
1445023ab2a9SKashyap Desai 		if (mpi3mr_check_req_qfull(op_req_q)) {
1446023ab2a9SKashyap Desai 			retval = -EAGAIN;
1447023ab2a9SKashyap Desai 			goto out;
1448023ab2a9SKashyap Desai 		}
1449023ab2a9SKashyap Desai 	}
1450023ab2a9SKashyap Desai 
1451023ab2a9SKashyap Desai 	if (mrioc->reset_in_progress) {
1452023ab2a9SKashyap Desai 		ioc_err(mrioc, "OpReqQ submit reset in progress\n");
1453023ab2a9SKashyap Desai 		retval = -EAGAIN;
1454023ab2a9SKashyap Desai 		goto out;
1455023ab2a9SKashyap Desai 	}
1456023ab2a9SKashyap Desai 
1457023ab2a9SKashyap Desai 	segment_base_addr = segments[pi / op_req_q->segment_qd].segment;
1458023ab2a9SKashyap Desai 	req_entry = (u8 *)segment_base_addr +
1459023ab2a9SKashyap Desai 	    ((pi % op_req_q->segment_qd) * req_sz);
1460023ab2a9SKashyap Desai 
1461023ab2a9SKashyap Desai 	memset(req_entry, 0, req_sz);
1462023ab2a9SKashyap Desai 	memcpy(req_entry, req, MPI3MR_ADMIN_REQ_FRAME_SZ);
1463023ab2a9SKashyap Desai 
1464023ab2a9SKashyap Desai 	if (++pi == max_entries)
1465023ab2a9SKashyap Desai 		pi = 0;
1466023ab2a9SKashyap Desai 	op_req_q->pi = pi;
1467023ab2a9SKashyap Desai 
1468023ab2a9SKashyap Desai 	writel(op_req_q->pi,
1469023ab2a9SKashyap Desai 	    &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].producer_index);
1470023ab2a9SKashyap Desai 
1471023ab2a9SKashyap Desai out:
1472023ab2a9SKashyap Desai 	spin_unlock_irqrestore(&op_req_q->q_lock, flags);
1473023ab2a9SKashyap Desai 	return retval;
1474023ab2a9SKashyap Desai }
1475023ab2a9SKashyap Desai 
1476023ab2a9SKashyap Desai /**
147754dfcffbSKashyap Desai  * mpi3mr_sync_timestamp - Issue time stamp sync request
147854dfcffbSKashyap Desai  * @mrioc: Adapter reference
147954dfcffbSKashyap Desai  *
148054dfcffbSKashyap Desai  * Issue IO unit control MPI request to synchornize firmware
148154dfcffbSKashyap Desai  * timestamp with host time.
148254dfcffbSKashyap Desai  *
148354dfcffbSKashyap Desai  * Return: 0 on success, non-zero on failure.
148454dfcffbSKashyap Desai  */
148554dfcffbSKashyap Desai static int mpi3mr_sync_timestamp(struct mpi3mr_ioc *mrioc)
148654dfcffbSKashyap Desai {
148754dfcffbSKashyap Desai 	ktime_t current_time;
148854dfcffbSKashyap Desai 	struct mpi3_iounit_control_request iou_ctrl;
148954dfcffbSKashyap Desai 	int retval = 0;
149054dfcffbSKashyap Desai 
149154dfcffbSKashyap Desai 	memset(&iou_ctrl, 0, sizeof(iou_ctrl));
149254dfcffbSKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
149354dfcffbSKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
149454dfcffbSKashyap Desai 		retval = -1;
149554dfcffbSKashyap Desai 		ioc_err(mrioc, "Issue IOUCTL time_stamp: command is in use\n");
149654dfcffbSKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
149754dfcffbSKashyap Desai 		goto out;
149854dfcffbSKashyap Desai 	}
149954dfcffbSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
150054dfcffbSKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
150154dfcffbSKashyap Desai 	mrioc->init_cmds.callback = NULL;
150254dfcffbSKashyap Desai 	iou_ctrl.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
150354dfcffbSKashyap Desai 	iou_ctrl.function = MPI3_FUNCTION_IO_UNIT_CONTROL;
150454dfcffbSKashyap Desai 	iou_ctrl.operation = MPI3_CTRL_OP_UPDATE_TIMESTAMP;
150554dfcffbSKashyap Desai 	current_time = ktime_get_real();
150654dfcffbSKashyap Desai 	iou_ctrl.param64[0] = cpu_to_le64(ktime_to_ms(current_time));
150754dfcffbSKashyap Desai 
150854dfcffbSKashyap Desai 	init_completion(&mrioc->init_cmds.done);
150954dfcffbSKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &iou_ctrl,
151054dfcffbSKashyap Desai 	    sizeof(iou_ctrl), 0);
151154dfcffbSKashyap Desai 	if (retval) {
151254dfcffbSKashyap Desai 		ioc_err(mrioc, "Issue IOUCTL time_stamp: Admin Post failed\n");
151354dfcffbSKashyap Desai 		goto out_unlock;
151454dfcffbSKashyap Desai 	}
151554dfcffbSKashyap Desai 
151654dfcffbSKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
151754dfcffbSKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
151854dfcffbSKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
151954dfcffbSKashyap Desai 		ioc_err(mrioc, "Issue IOUCTL time_stamp: command timed out\n");
152054dfcffbSKashyap Desai 		mrioc->init_cmds.is_waiting = 0;
152154dfcffbSKashyap Desai 		mpi3mr_soft_reset_handler(mrioc,
152254dfcffbSKashyap Desai 		    MPI3MR_RESET_FROM_TSU_TIMEOUT, 1);
152354dfcffbSKashyap Desai 		retval = -1;
152454dfcffbSKashyap Desai 		goto out_unlock;
152554dfcffbSKashyap Desai 	}
152654dfcffbSKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
152754dfcffbSKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
152854dfcffbSKashyap Desai 		ioc_err(mrioc,
152954dfcffbSKashyap Desai 		    "Issue IOUCTL time_stamp: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
153054dfcffbSKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
153154dfcffbSKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
153254dfcffbSKashyap Desai 		retval = -1;
153354dfcffbSKashyap Desai 		goto out_unlock;
153454dfcffbSKashyap Desai 	}
153554dfcffbSKashyap Desai 
153654dfcffbSKashyap Desai out_unlock:
153754dfcffbSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
153854dfcffbSKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
153954dfcffbSKashyap Desai 
154054dfcffbSKashyap Desai out:
154154dfcffbSKashyap Desai 	return retval;
154254dfcffbSKashyap Desai }
154354dfcffbSKashyap Desai 
154454dfcffbSKashyap Desai /**
1545672ae26cSKashyap Desai  * mpi3mr_watchdog_work - watchdog thread to monitor faults
1546672ae26cSKashyap Desai  * @work: work struct
1547672ae26cSKashyap Desai  *
1548672ae26cSKashyap Desai  * Watch dog work periodically executed (1 second interval) to
1549672ae26cSKashyap Desai  * monitor firmware fault and to issue periodic timer sync to
1550672ae26cSKashyap Desai  * the firmware.
1551672ae26cSKashyap Desai  *
1552672ae26cSKashyap Desai  * Return: Nothing.
1553672ae26cSKashyap Desai  */
1554672ae26cSKashyap Desai static void mpi3mr_watchdog_work(struct work_struct *work)
1555672ae26cSKashyap Desai {
1556672ae26cSKashyap Desai 	struct mpi3mr_ioc *mrioc =
1557672ae26cSKashyap Desai 	    container_of(work, struct mpi3mr_ioc, watchdog_work.work);
1558672ae26cSKashyap Desai 	unsigned long flags;
1559672ae26cSKashyap Desai 	enum mpi3mr_iocstate ioc_state;
1560672ae26cSKashyap Desai 	u32 fault, host_diagnostic;
1561672ae26cSKashyap Desai 
156254dfcffbSKashyap Desai 	if (mrioc->ts_update_counter++ >= MPI3MR_TSUPDATE_INTERVAL) {
156354dfcffbSKashyap Desai 		mrioc->ts_update_counter = 0;
156454dfcffbSKashyap Desai 		mpi3mr_sync_timestamp(mrioc);
156554dfcffbSKashyap Desai 	}
156654dfcffbSKashyap Desai 
1567672ae26cSKashyap Desai 	/*Check for fault state every one second and issue Soft reset*/
1568672ae26cSKashyap Desai 	ioc_state = mpi3mr_get_iocstate(mrioc);
1569672ae26cSKashyap Desai 	if (ioc_state == MRIOC_STATE_FAULT) {
1570672ae26cSKashyap Desai 		fault = readl(&mrioc->sysif_regs->fault) &
1571672ae26cSKashyap Desai 		    MPI3_SYSIF_FAULT_CODE_MASK;
1572672ae26cSKashyap Desai 		host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic);
1573672ae26cSKashyap Desai 		if (host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS) {
1574672ae26cSKashyap Desai 			if (!mrioc->diagsave_timeout) {
1575672ae26cSKashyap Desai 				mpi3mr_print_fault_info(mrioc);
1576672ae26cSKashyap Desai 				ioc_warn(mrioc, "Diag save in progress\n");
1577672ae26cSKashyap Desai 			}
1578672ae26cSKashyap Desai 			if ((mrioc->diagsave_timeout++) <=
1579672ae26cSKashyap Desai 			    MPI3_SYSIF_DIAG_SAVE_TIMEOUT)
1580672ae26cSKashyap Desai 				goto schedule_work;
1581672ae26cSKashyap Desai 		} else
1582672ae26cSKashyap Desai 			mpi3mr_print_fault_info(mrioc);
1583672ae26cSKashyap Desai 		mrioc->diagsave_timeout = 0;
1584672ae26cSKashyap Desai 
1585672ae26cSKashyap Desai 		if (fault == MPI3_SYSIF_FAULT_CODE_FACTORY_RESET) {
1586672ae26cSKashyap Desai 			ioc_info(mrioc,
1587672ae26cSKashyap Desai 			    "Factory Reset fault occurred marking controller as unrecoverable"
1588672ae26cSKashyap Desai 			    );
1589672ae26cSKashyap Desai 			mrioc->unrecoverable = 1;
1590672ae26cSKashyap Desai 			goto out;
1591672ae26cSKashyap Desai 		}
1592672ae26cSKashyap Desai 
1593672ae26cSKashyap Desai 		if ((fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET) ||
1594672ae26cSKashyap Desai 		    (fault == MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS) ||
1595672ae26cSKashyap Desai 		    (mrioc->reset_in_progress))
1596672ae26cSKashyap Desai 			goto out;
1597672ae26cSKashyap Desai 		if (fault == MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET)
1598672ae26cSKashyap Desai 			mpi3mr_soft_reset_handler(mrioc,
1599672ae26cSKashyap Desai 			    MPI3MR_RESET_FROM_CIACTIV_FAULT, 0);
1600672ae26cSKashyap Desai 		else
1601672ae26cSKashyap Desai 			mpi3mr_soft_reset_handler(mrioc,
1602672ae26cSKashyap Desai 			    MPI3MR_RESET_FROM_FAULT_WATCH, 0);
1603672ae26cSKashyap Desai 	}
1604672ae26cSKashyap Desai 
1605672ae26cSKashyap Desai schedule_work:
1606672ae26cSKashyap Desai 	spin_lock_irqsave(&mrioc->watchdog_lock, flags);
1607672ae26cSKashyap Desai 	if (mrioc->watchdog_work_q)
1608672ae26cSKashyap Desai 		queue_delayed_work(mrioc->watchdog_work_q,
1609672ae26cSKashyap Desai 		    &mrioc->watchdog_work,
1610672ae26cSKashyap Desai 		    msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL));
1611672ae26cSKashyap Desai 	spin_unlock_irqrestore(&mrioc->watchdog_lock, flags);
1612672ae26cSKashyap Desai out:
1613672ae26cSKashyap Desai 	return;
1614672ae26cSKashyap Desai }
1615672ae26cSKashyap Desai 
1616672ae26cSKashyap Desai /**
1617672ae26cSKashyap Desai  * mpi3mr_start_watchdog - Start watchdog
1618672ae26cSKashyap Desai  * @mrioc: Adapter instance reference
1619672ae26cSKashyap Desai  *
1620672ae26cSKashyap Desai  * Create and start the watchdog thread to monitor controller
1621672ae26cSKashyap Desai  * faults.
1622672ae26cSKashyap Desai  *
1623672ae26cSKashyap Desai  * Return: Nothing.
1624672ae26cSKashyap Desai  */
1625672ae26cSKashyap Desai void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc)
1626672ae26cSKashyap Desai {
1627672ae26cSKashyap Desai 	if (mrioc->watchdog_work_q)
1628672ae26cSKashyap Desai 		return;
1629672ae26cSKashyap Desai 
1630672ae26cSKashyap Desai 	INIT_DELAYED_WORK(&mrioc->watchdog_work, mpi3mr_watchdog_work);
1631672ae26cSKashyap Desai 	snprintf(mrioc->watchdog_work_q_name,
1632672ae26cSKashyap Desai 	    sizeof(mrioc->watchdog_work_q_name), "watchdog_%s%d", mrioc->name,
1633672ae26cSKashyap Desai 	    mrioc->id);
1634672ae26cSKashyap Desai 	mrioc->watchdog_work_q =
1635672ae26cSKashyap Desai 	    create_singlethread_workqueue(mrioc->watchdog_work_q_name);
1636672ae26cSKashyap Desai 	if (!mrioc->watchdog_work_q) {
1637672ae26cSKashyap Desai 		ioc_err(mrioc, "%s: failed (line=%d)\n", __func__, __LINE__);
1638672ae26cSKashyap Desai 		return;
1639672ae26cSKashyap Desai 	}
1640672ae26cSKashyap Desai 
1641672ae26cSKashyap Desai 	if (mrioc->watchdog_work_q)
1642672ae26cSKashyap Desai 		queue_delayed_work(mrioc->watchdog_work_q,
1643672ae26cSKashyap Desai 		    &mrioc->watchdog_work,
1644672ae26cSKashyap Desai 		    msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL));
1645672ae26cSKashyap Desai }
1646672ae26cSKashyap Desai 
1647672ae26cSKashyap Desai /**
1648672ae26cSKashyap Desai  * mpi3mr_stop_watchdog - Stop watchdog
1649672ae26cSKashyap Desai  * @mrioc: Adapter instance reference
1650672ae26cSKashyap Desai  *
1651672ae26cSKashyap Desai  * Stop the watchdog thread created to monitor controller
1652672ae26cSKashyap Desai  * faults.
1653672ae26cSKashyap Desai  *
1654672ae26cSKashyap Desai  * Return: Nothing.
1655672ae26cSKashyap Desai  */
1656672ae26cSKashyap Desai void mpi3mr_stop_watchdog(struct mpi3mr_ioc *mrioc)
1657672ae26cSKashyap Desai {
1658672ae26cSKashyap Desai 	unsigned long flags;
1659672ae26cSKashyap Desai 	struct workqueue_struct *wq;
1660672ae26cSKashyap Desai 
1661672ae26cSKashyap Desai 	spin_lock_irqsave(&mrioc->watchdog_lock, flags);
1662672ae26cSKashyap Desai 	wq = mrioc->watchdog_work_q;
1663672ae26cSKashyap Desai 	mrioc->watchdog_work_q = NULL;
1664672ae26cSKashyap Desai 	spin_unlock_irqrestore(&mrioc->watchdog_lock, flags);
1665672ae26cSKashyap Desai 	if (wq) {
1666672ae26cSKashyap Desai 		if (!cancel_delayed_work_sync(&mrioc->watchdog_work))
1667672ae26cSKashyap Desai 			flush_workqueue(wq);
1668672ae26cSKashyap Desai 		destroy_workqueue(wq);
1669672ae26cSKashyap Desai 	}
1670672ae26cSKashyap Desai }
1671672ae26cSKashyap Desai 
1672672ae26cSKashyap Desai /**
1673fb9b0457SKashyap Desai  * mpi3mr_kill_ioc - Kill the controller
1674fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
1675fb9b0457SKashyap Desai  * @reason: reason for the failure.
1676fb9b0457SKashyap Desai  *
1677fb9b0457SKashyap Desai  * If fault debug is enabled, display the fault info else issue
1678fb9b0457SKashyap Desai  * diag fault and freeze the system for controller debug
1679fb9b0457SKashyap Desai  * purpose.
1680fb9b0457SKashyap Desai  *
1681fb9b0457SKashyap Desai  * Return: Nothing.
1682fb9b0457SKashyap Desai  */
1683fb9b0457SKashyap Desai static void mpi3mr_kill_ioc(struct mpi3mr_ioc *mrioc, u32 reason)
1684fb9b0457SKashyap Desai {
1685fb9b0457SKashyap Desai 	enum mpi3mr_iocstate ioc_state;
1686fb9b0457SKashyap Desai 
1687fb9b0457SKashyap Desai 	if (!mrioc->fault_dbg)
1688fb9b0457SKashyap Desai 		return;
1689fb9b0457SKashyap Desai 
1690fb9b0457SKashyap Desai 	dump_stack();
1691fb9b0457SKashyap Desai 
1692fb9b0457SKashyap Desai 	ioc_state = mpi3mr_get_iocstate(mrioc);
1693fb9b0457SKashyap Desai 	if (ioc_state == MRIOC_STATE_FAULT)
1694fb9b0457SKashyap Desai 		mpi3mr_print_fault_info(mrioc);
1695fb9b0457SKashyap Desai 	else {
1696fb9b0457SKashyap Desai 		ioc_err(mrioc, "Firmware is halted due to the reason %d\n",
1697fb9b0457SKashyap Desai 		    reason);
1698fb9b0457SKashyap Desai 		mpi3mr_diagfault_reset_handler(mrioc, reason);
1699fb9b0457SKashyap Desai 	}
1700fb9b0457SKashyap Desai 	if (mrioc->fault_dbg == 2)
1701fb9b0457SKashyap Desai 		for (;;)
1702fb9b0457SKashyap Desai 			;
1703fb9b0457SKashyap Desai 	else
1704fb9b0457SKashyap Desai 		panic("panic in %s\n", __func__);
1705fb9b0457SKashyap Desai }
1706fb9b0457SKashyap Desai 
1707fb9b0457SKashyap Desai /**
1708824a1566SKashyap Desai  * mpi3mr_setup_admin_qpair - Setup admin queue pair
1709824a1566SKashyap Desai  * @mrioc: Adapter instance reference
1710824a1566SKashyap Desai  *
1711824a1566SKashyap Desai  * Allocate memory for admin queue pair if required and register
1712824a1566SKashyap Desai  * the admin queue with the controller.
1713824a1566SKashyap Desai  *
1714824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
1715824a1566SKashyap Desai  */
1716824a1566SKashyap Desai static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc)
1717824a1566SKashyap Desai {
1718824a1566SKashyap Desai 	int retval = 0;
1719824a1566SKashyap Desai 	u32 num_admin_entries = 0;
1720824a1566SKashyap Desai 
1721824a1566SKashyap Desai 	mrioc->admin_req_q_sz = MPI3MR_ADMIN_REQ_Q_SIZE;
1722824a1566SKashyap Desai 	mrioc->num_admin_req = mrioc->admin_req_q_sz /
1723824a1566SKashyap Desai 	    MPI3MR_ADMIN_REQ_FRAME_SZ;
1724824a1566SKashyap Desai 	mrioc->admin_req_ci = mrioc->admin_req_pi = 0;
1725824a1566SKashyap Desai 	mrioc->admin_req_base = NULL;
1726824a1566SKashyap Desai 
1727824a1566SKashyap Desai 	mrioc->admin_reply_q_sz = MPI3MR_ADMIN_REPLY_Q_SIZE;
1728824a1566SKashyap Desai 	mrioc->num_admin_replies = mrioc->admin_reply_q_sz /
1729824a1566SKashyap Desai 	    MPI3MR_ADMIN_REPLY_FRAME_SZ;
1730824a1566SKashyap Desai 	mrioc->admin_reply_ci = 0;
1731824a1566SKashyap Desai 	mrioc->admin_reply_ephase = 1;
1732824a1566SKashyap Desai 	mrioc->admin_reply_base = NULL;
1733824a1566SKashyap Desai 
1734824a1566SKashyap Desai 	if (!mrioc->admin_req_base) {
1735824a1566SKashyap Desai 		mrioc->admin_req_base = dma_alloc_coherent(&mrioc->pdev->dev,
1736824a1566SKashyap Desai 		    mrioc->admin_req_q_sz, &mrioc->admin_req_dma, GFP_KERNEL);
1737824a1566SKashyap Desai 
1738824a1566SKashyap Desai 		if (!mrioc->admin_req_base) {
1739824a1566SKashyap Desai 			retval = -1;
1740824a1566SKashyap Desai 			goto out_failed;
1741824a1566SKashyap Desai 		}
1742824a1566SKashyap Desai 
1743824a1566SKashyap Desai 		mrioc->admin_reply_base = dma_alloc_coherent(&mrioc->pdev->dev,
1744824a1566SKashyap Desai 		    mrioc->admin_reply_q_sz, &mrioc->admin_reply_dma,
1745824a1566SKashyap Desai 		    GFP_KERNEL);
1746824a1566SKashyap Desai 
1747824a1566SKashyap Desai 		if (!mrioc->admin_reply_base) {
1748824a1566SKashyap Desai 			retval = -1;
1749824a1566SKashyap Desai 			goto out_failed;
1750824a1566SKashyap Desai 		}
1751824a1566SKashyap Desai 	}
1752824a1566SKashyap Desai 
1753824a1566SKashyap Desai 	num_admin_entries = (mrioc->num_admin_replies << 16) |
1754824a1566SKashyap Desai 	    (mrioc->num_admin_req);
1755824a1566SKashyap Desai 	writel(num_admin_entries, &mrioc->sysif_regs->admin_queue_num_entries);
1756824a1566SKashyap Desai 	mpi3mr_writeq(mrioc->admin_req_dma,
1757824a1566SKashyap Desai 	    &mrioc->sysif_regs->admin_request_queue_address);
1758824a1566SKashyap Desai 	mpi3mr_writeq(mrioc->admin_reply_dma,
1759824a1566SKashyap Desai 	    &mrioc->sysif_regs->admin_reply_queue_address);
1760824a1566SKashyap Desai 	writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi);
1761824a1566SKashyap Desai 	writel(mrioc->admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci);
1762824a1566SKashyap Desai 	return retval;
1763824a1566SKashyap Desai 
1764824a1566SKashyap Desai out_failed:
1765824a1566SKashyap Desai 
1766824a1566SKashyap Desai 	if (mrioc->admin_reply_base) {
1767824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz,
1768824a1566SKashyap Desai 		    mrioc->admin_reply_base, mrioc->admin_reply_dma);
1769824a1566SKashyap Desai 		mrioc->admin_reply_base = NULL;
1770824a1566SKashyap Desai 	}
1771824a1566SKashyap Desai 	if (mrioc->admin_req_base) {
1772824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz,
1773824a1566SKashyap Desai 		    mrioc->admin_req_base, mrioc->admin_req_dma);
1774824a1566SKashyap Desai 		mrioc->admin_req_base = NULL;
1775824a1566SKashyap Desai 	}
1776824a1566SKashyap Desai 	return retval;
1777824a1566SKashyap Desai }
1778824a1566SKashyap Desai 
1779824a1566SKashyap Desai /**
1780824a1566SKashyap Desai  * mpi3mr_issue_iocfacts - Send IOC Facts
1781824a1566SKashyap Desai  * @mrioc: Adapter instance reference
1782824a1566SKashyap Desai  * @facts_data: Cached IOC facts data
1783824a1566SKashyap Desai  *
1784824a1566SKashyap Desai  * Issue IOC Facts MPI request through admin queue and wait for
1785824a1566SKashyap Desai  * the completion of it or time out.
1786824a1566SKashyap Desai  *
1787824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
1788824a1566SKashyap Desai  */
1789824a1566SKashyap Desai static int mpi3mr_issue_iocfacts(struct mpi3mr_ioc *mrioc,
1790824a1566SKashyap Desai 	struct mpi3_ioc_facts_data *facts_data)
1791824a1566SKashyap Desai {
1792824a1566SKashyap Desai 	struct mpi3_ioc_facts_request iocfacts_req;
1793824a1566SKashyap Desai 	void *data = NULL;
1794824a1566SKashyap Desai 	dma_addr_t data_dma;
1795824a1566SKashyap Desai 	u32 data_len = sizeof(*facts_data);
1796824a1566SKashyap Desai 	int retval = 0;
1797824a1566SKashyap Desai 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
1798824a1566SKashyap Desai 
1799824a1566SKashyap Desai 	data = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma,
1800824a1566SKashyap Desai 	    GFP_KERNEL);
1801824a1566SKashyap Desai 
1802824a1566SKashyap Desai 	if (!data) {
1803824a1566SKashyap Desai 		retval = -1;
1804824a1566SKashyap Desai 		goto out;
1805824a1566SKashyap Desai 	}
1806824a1566SKashyap Desai 
1807824a1566SKashyap Desai 	memset(&iocfacts_req, 0, sizeof(iocfacts_req));
1808824a1566SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
1809824a1566SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
1810824a1566SKashyap Desai 		retval = -1;
1811824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCFacts: Init command is in use\n");
1812824a1566SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
1813824a1566SKashyap Desai 		goto out;
1814824a1566SKashyap Desai 	}
1815824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
1816824a1566SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
1817824a1566SKashyap Desai 	mrioc->init_cmds.callback = NULL;
1818824a1566SKashyap Desai 	iocfacts_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
1819824a1566SKashyap Desai 	iocfacts_req.function = MPI3_FUNCTION_IOC_FACTS;
1820824a1566SKashyap Desai 
1821824a1566SKashyap Desai 	mpi3mr_add_sg_single(&iocfacts_req.sgl, sgl_flags, data_len,
1822824a1566SKashyap Desai 	    data_dma);
1823824a1566SKashyap Desai 
1824824a1566SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
1825824a1566SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &iocfacts_req,
1826824a1566SKashyap Desai 	    sizeof(iocfacts_req), 1);
1827824a1566SKashyap Desai 	if (retval) {
1828824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCFacts: Admin Post failed\n");
1829824a1566SKashyap Desai 		goto out_unlock;
1830824a1566SKashyap Desai 	}
1831824a1566SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
1832824a1566SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
1833824a1566SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
1834824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCFacts: command timed out\n");
1835824a1566SKashyap Desai 		mpi3mr_set_diagsave(mrioc);
1836824a1566SKashyap Desai 		mpi3mr_issue_reset(mrioc,
1837824a1566SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
1838824a1566SKashyap Desai 		    MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT);
1839824a1566SKashyap Desai 		mrioc->unrecoverable = 1;
1840824a1566SKashyap Desai 		retval = -1;
1841824a1566SKashyap Desai 		goto out_unlock;
1842824a1566SKashyap Desai 	}
1843824a1566SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
1844824a1566SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
1845824a1566SKashyap Desai 		ioc_err(mrioc,
1846824a1566SKashyap Desai 		    "Issue IOCFacts: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
1847824a1566SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
1848824a1566SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
1849824a1566SKashyap Desai 		retval = -1;
1850824a1566SKashyap Desai 		goto out_unlock;
1851824a1566SKashyap Desai 	}
1852824a1566SKashyap Desai 	memcpy(facts_data, (u8 *)data, data_len);
1853824a1566SKashyap Desai out_unlock:
1854824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
1855824a1566SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
1856824a1566SKashyap Desai 
1857824a1566SKashyap Desai out:
1858824a1566SKashyap Desai 	if (data)
1859824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, data_len, data, data_dma);
1860824a1566SKashyap Desai 
1861824a1566SKashyap Desai 	return retval;
1862824a1566SKashyap Desai }
1863824a1566SKashyap Desai 
1864824a1566SKashyap Desai /**
1865824a1566SKashyap Desai  * mpi3mr_check_reset_dma_mask - Process IOC facts data
1866824a1566SKashyap Desai  * @mrioc: Adapter instance reference
1867824a1566SKashyap Desai  *
1868824a1566SKashyap Desai  * Check whether the new DMA mask requested through IOCFacts by
1869824a1566SKashyap Desai  * firmware needs to be set, if so set it .
1870824a1566SKashyap Desai  *
1871824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
1872824a1566SKashyap Desai  */
1873824a1566SKashyap Desai static inline int mpi3mr_check_reset_dma_mask(struct mpi3mr_ioc *mrioc)
1874824a1566SKashyap Desai {
1875824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
1876824a1566SKashyap Desai 	int r;
1877824a1566SKashyap Desai 	u64 facts_dma_mask = DMA_BIT_MASK(mrioc->facts.dma_mask);
1878824a1566SKashyap Desai 
1879824a1566SKashyap Desai 	if (!mrioc->facts.dma_mask || (mrioc->dma_mask <= facts_dma_mask))
1880824a1566SKashyap Desai 		return 0;
1881824a1566SKashyap Desai 
1882824a1566SKashyap Desai 	ioc_info(mrioc, "Changing DMA mask from 0x%016llx to 0x%016llx\n",
1883824a1566SKashyap Desai 	    mrioc->dma_mask, facts_dma_mask);
1884824a1566SKashyap Desai 
1885824a1566SKashyap Desai 	r = dma_set_mask_and_coherent(&pdev->dev, facts_dma_mask);
1886824a1566SKashyap Desai 	if (r) {
1887824a1566SKashyap Desai 		ioc_err(mrioc, "Setting DMA mask to 0x%016llx failed: %d\n",
1888824a1566SKashyap Desai 		    facts_dma_mask, r);
1889824a1566SKashyap Desai 		return r;
1890824a1566SKashyap Desai 	}
1891824a1566SKashyap Desai 	mrioc->dma_mask = facts_dma_mask;
1892824a1566SKashyap Desai 	return r;
1893824a1566SKashyap Desai }
1894824a1566SKashyap Desai 
1895824a1566SKashyap Desai /**
1896824a1566SKashyap Desai  * mpi3mr_process_factsdata - Process IOC facts data
1897824a1566SKashyap Desai  * @mrioc: Adapter instance reference
1898824a1566SKashyap Desai  * @facts_data: Cached IOC facts data
1899824a1566SKashyap Desai  *
1900824a1566SKashyap Desai  * Convert IOC facts data into cpu endianness and cache it in
1901824a1566SKashyap Desai  * the driver .
1902824a1566SKashyap Desai  *
1903824a1566SKashyap Desai  * Return: Nothing.
1904824a1566SKashyap Desai  */
1905824a1566SKashyap Desai static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc,
1906824a1566SKashyap Desai 	struct mpi3_ioc_facts_data *facts_data)
1907824a1566SKashyap Desai {
1908824a1566SKashyap Desai 	u32 ioc_config, req_sz, facts_flags;
1909824a1566SKashyap Desai 
1910824a1566SKashyap Desai 	if ((le16_to_cpu(facts_data->ioc_facts_data_length)) !=
1911824a1566SKashyap Desai 	    (sizeof(*facts_data) / 4)) {
1912824a1566SKashyap Desai 		ioc_warn(mrioc,
1913824a1566SKashyap Desai 		    "IOCFactsdata length mismatch driver_sz(%zu) firmware_sz(%d)\n",
1914824a1566SKashyap Desai 		    sizeof(*facts_data),
1915824a1566SKashyap Desai 		    le16_to_cpu(facts_data->ioc_facts_data_length) * 4);
1916824a1566SKashyap Desai 	}
1917824a1566SKashyap Desai 
1918824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
1919824a1566SKashyap Desai 	req_sz = 1 << ((ioc_config & MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ) >>
1920824a1566SKashyap Desai 	    MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ_SHIFT);
1921824a1566SKashyap Desai 	if (le16_to_cpu(facts_data->ioc_request_frame_size) != (req_sz / 4)) {
1922824a1566SKashyap Desai 		ioc_err(mrioc,
1923824a1566SKashyap Desai 		    "IOCFacts data reqFrameSize mismatch hw_size(%d) firmware_sz(%d)\n",
1924824a1566SKashyap Desai 		    req_sz / 4, le16_to_cpu(facts_data->ioc_request_frame_size));
1925824a1566SKashyap Desai 	}
1926824a1566SKashyap Desai 
1927824a1566SKashyap Desai 	memset(&mrioc->facts, 0, sizeof(mrioc->facts));
1928824a1566SKashyap Desai 
1929824a1566SKashyap Desai 	facts_flags = le32_to_cpu(facts_data->flags);
1930824a1566SKashyap Desai 	mrioc->facts.op_req_sz = req_sz;
1931824a1566SKashyap Desai 	mrioc->op_reply_desc_sz = 1 << ((ioc_config &
1932824a1566SKashyap Desai 	    MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ) >>
1933824a1566SKashyap Desai 	    MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ_SHIFT);
1934824a1566SKashyap Desai 
1935824a1566SKashyap Desai 	mrioc->facts.ioc_num = facts_data->ioc_number;
1936824a1566SKashyap Desai 	mrioc->facts.who_init = facts_data->who_init;
1937824a1566SKashyap Desai 	mrioc->facts.max_msix_vectors = le16_to_cpu(facts_data->max_msix_vectors);
1938824a1566SKashyap Desai 	mrioc->facts.personality = (facts_flags &
1939824a1566SKashyap Desai 	    MPI3_IOCFACTS_FLAGS_PERSONALITY_MASK);
1940824a1566SKashyap Desai 	mrioc->facts.dma_mask = (facts_flags &
1941824a1566SKashyap Desai 	    MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >>
1942824a1566SKashyap Desai 	    MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT;
1943824a1566SKashyap Desai 	mrioc->facts.protocol_flags = facts_data->protocol_flags;
1944824a1566SKashyap Desai 	mrioc->facts.mpi_version = le32_to_cpu(facts_data->mpi_version.word);
1945824a1566SKashyap Desai 	mrioc->facts.max_reqs = le16_to_cpu(facts_data->max_outstanding_request);
1946824a1566SKashyap Desai 	mrioc->facts.product_id = le16_to_cpu(facts_data->product_id);
1947824a1566SKashyap Desai 	mrioc->facts.reply_sz = le16_to_cpu(facts_data->reply_frame_size) * 4;
1948824a1566SKashyap Desai 	mrioc->facts.exceptions = le16_to_cpu(facts_data->ioc_exceptions);
1949824a1566SKashyap Desai 	mrioc->facts.max_perids = le16_to_cpu(facts_data->max_persistent_id);
1950824a1566SKashyap Desai 	mrioc->facts.max_pds = le16_to_cpu(facts_data->max_pds);
1951824a1566SKashyap Desai 	mrioc->facts.max_vds = le16_to_cpu(facts_data->max_vds);
1952824a1566SKashyap Desai 	mrioc->facts.max_hpds = le16_to_cpu(facts_data->max_host_pds);
1953824a1566SKashyap Desai 	mrioc->facts.max_advhpds = le16_to_cpu(facts_data->max_advanced_host_pds);
1954824a1566SKashyap Desai 	mrioc->facts.max_raidpds = le16_to_cpu(facts_data->max_raid_pds);
1955824a1566SKashyap Desai 	mrioc->facts.max_nvme = le16_to_cpu(facts_data->max_nvme);
1956824a1566SKashyap Desai 	mrioc->facts.max_pcie_switches =
1957824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_pc_ie_switches);
1958824a1566SKashyap Desai 	mrioc->facts.max_sasexpanders =
1959824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_sas_expanders);
1960824a1566SKashyap Desai 	mrioc->facts.max_sasinitiators =
1961824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_sas_initiators);
1962824a1566SKashyap Desai 	mrioc->facts.max_enclosures = le16_to_cpu(facts_data->max_enclosures);
1963824a1566SKashyap Desai 	mrioc->facts.min_devhandle = le16_to_cpu(facts_data->min_dev_handle);
1964824a1566SKashyap Desai 	mrioc->facts.max_devhandle = le16_to_cpu(facts_data->max_dev_handle);
1965824a1566SKashyap Desai 	mrioc->facts.max_op_req_q =
1966824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_operational_request_queues);
1967824a1566SKashyap Desai 	mrioc->facts.max_op_reply_q =
1968824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_operational_reply_queues);
1969824a1566SKashyap Desai 	mrioc->facts.ioc_capabilities =
1970824a1566SKashyap Desai 	    le32_to_cpu(facts_data->ioc_capabilities);
1971824a1566SKashyap Desai 	mrioc->facts.fw_ver.build_num =
1972824a1566SKashyap Desai 	    le16_to_cpu(facts_data->fw_version.build_num);
1973824a1566SKashyap Desai 	mrioc->facts.fw_ver.cust_id =
1974824a1566SKashyap Desai 	    le16_to_cpu(facts_data->fw_version.customer_id);
1975824a1566SKashyap Desai 	mrioc->facts.fw_ver.ph_minor = facts_data->fw_version.phase_minor;
1976824a1566SKashyap Desai 	mrioc->facts.fw_ver.ph_major = facts_data->fw_version.phase_major;
1977824a1566SKashyap Desai 	mrioc->facts.fw_ver.gen_minor = facts_data->fw_version.gen_minor;
1978824a1566SKashyap Desai 	mrioc->facts.fw_ver.gen_major = facts_data->fw_version.gen_major;
1979824a1566SKashyap Desai 	mrioc->msix_count = min_t(int, mrioc->msix_count,
1980824a1566SKashyap Desai 	    mrioc->facts.max_msix_vectors);
1981824a1566SKashyap Desai 	mrioc->facts.sge_mod_mask = facts_data->sge_modifier_mask;
1982824a1566SKashyap Desai 	mrioc->facts.sge_mod_value = facts_data->sge_modifier_value;
1983824a1566SKashyap Desai 	mrioc->facts.sge_mod_shift = facts_data->sge_modifier_shift;
1984824a1566SKashyap Desai 	mrioc->facts.shutdown_timeout =
1985824a1566SKashyap Desai 	    le16_to_cpu(facts_data->shutdown_timeout);
1986824a1566SKashyap Desai 
1987824a1566SKashyap Desai 	ioc_info(mrioc, "ioc_num(%d), maxopQ(%d), maxopRepQ(%d), maxdh(%d),",
1988824a1566SKashyap Desai 	    mrioc->facts.ioc_num, mrioc->facts.max_op_req_q,
1989824a1566SKashyap Desai 	    mrioc->facts.max_op_reply_q, mrioc->facts.max_devhandle);
1990824a1566SKashyap Desai 	ioc_info(mrioc,
1991824a1566SKashyap Desai 	    "maxreqs(%d), mindh(%d) maxPDs(%d) maxvectors(%d) maxperids(%d)\n",
1992824a1566SKashyap Desai 	    mrioc->facts.max_reqs, mrioc->facts.min_devhandle,
1993824a1566SKashyap Desai 	    mrioc->facts.max_pds, mrioc->facts.max_msix_vectors,
1994824a1566SKashyap Desai 	    mrioc->facts.max_perids);
1995824a1566SKashyap Desai 	ioc_info(mrioc, "SGEModMask 0x%x SGEModVal 0x%x SGEModShift 0x%x ",
1996824a1566SKashyap Desai 	    mrioc->facts.sge_mod_mask, mrioc->facts.sge_mod_value,
1997824a1566SKashyap Desai 	    mrioc->facts.sge_mod_shift);
1998824a1566SKashyap Desai 	ioc_info(mrioc, "DMA mask %d InitialPE status 0x%x\n",
1999824a1566SKashyap Desai 	    mrioc->facts.dma_mask, (facts_flags &
2000824a1566SKashyap Desai 	    MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK));
2001824a1566SKashyap Desai 
2002824a1566SKashyap Desai 	mrioc->max_host_ios = mrioc->facts.max_reqs - MPI3MR_INTERNAL_CMDS_RESVD;
2003824a1566SKashyap Desai 
2004824a1566SKashyap Desai 	if (reset_devices)
2005824a1566SKashyap Desai 		mrioc->max_host_ios = min_t(int, mrioc->max_host_ios,
2006824a1566SKashyap Desai 		    MPI3MR_HOST_IOS_KDUMP);
2007824a1566SKashyap Desai }
2008824a1566SKashyap Desai 
2009824a1566SKashyap Desai /**
2010824a1566SKashyap Desai  * mpi3mr_alloc_reply_sense_bufs - Send IOC Init
2011824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2012824a1566SKashyap Desai  *
2013824a1566SKashyap Desai  * Allocate and initialize the reply free buffers, sense
2014824a1566SKashyap Desai  * buffers, reply free queue and sense buffer queue.
2015824a1566SKashyap Desai  *
2016824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
2017824a1566SKashyap Desai  */
2018824a1566SKashyap Desai static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc)
2019824a1566SKashyap Desai {
2020824a1566SKashyap Desai 	int retval = 0;
2021824a1566SKashyap Desai 	u32 sz, i;
2022824a1566SKashyap Desai 	dma_addr_t phy_addr;
2023824a1566SKashyap Desai 
2024824a1566SKashyap Desai 	if (mrioc->init_cmds.reply)
2025824a1566SKashyap Desai 		goto post_reply_sbuf;
2026824a1566SKashyap Desai 
2027824a1566SKashyap Desai 	mrioc->init_cmds.reply = kzalloc(mrioc->facts.reply_sz, GFP_KERNEL);
2028824a1566SKashyap Desai 	if (!mrioc->init_cmds.reply)
2029824a1566SKashyap Desai 		goto out_failed;
2030824a1566SKashyap Desai 
203113ef29eaSKashyap Desai 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
203213ef29eaSKashyap Desai 		mrioc->dev_rmhs_cmds[i].reply = kzalloc(mrioc->facts.reply_sz,
203313ef29eaSKashyap Desai 		    GFP_KERNEL);
203413ef29eaSKashyap Desai 		if (!mrioc->dev_rmhs_cmds[i].reply)
203513ef29eaSKashyap Desai 			goto out_failed;
203613ef29eaSKashyap Desai 	}
203713ef29eaSKashyap Desai 
2038*e844adb1SKashyap Desai 	mrioc->host_tm_cmds.reply = kzalloc(mrioc->facts.reply_sz, GFP_KERNEL);
2039*e844adb1SKashyap Desai 	if (!mrioc->host_tm_cmds.reply)
2040*e844adb1SKashyap Desai 		goto out_failed;
2041*e844adb1SKashyap Desai 
2042*e844adb1SKashyap Desai 	mrioc->dev_handle_bitmap_sz = mrioc->facts.max_devhandle / 8;
2043*e844adb1SKashyap Desai 	if (mrioc->facts.max_devhandle % 8)
2044*e844adb1SKashyap Desai 		mrioc->dev_handle_bitmap_sz++;
2045*e844adb1SKashyap Desai 	mrioc->removepend_bitmap = kzalloc(mrioc->dev_handle_bitmap_sz,
2046*e844adb1SKashyap Desai 	    GFP_KERNEL);
2047*e844adb1SKashyap Desai 	if (!mrioc->removepend_bitmap)
2048*e844adb1SKashyap Desai 		goto out_failed;
2049*e844adb1SKashyap Desai 
2050*e844adb1SKashyap Desai 	mrioc->devrem_bitmap_sz = MPI3MR_NUM_DEVRMCMD / 8;
2051*e844adb1SKashyap Desai 	if (MPI3MR_NUM_DEVRMCMD % 8)
2052*e844adb1SKashyap Desai 		mrioc->devrem_bitmap_sz++;
2053*e844adb1SKashyap Desai 	mrioc->devrem_bitmap = kzalloc(mrioc->devrem_bitmap_sz,
2054*e844adb1SKashyap Desai 	    GFP_KERNEL);
2055*e844adb1SKashyap Desai 	if (!mrioc->devrem_bitmap)
2056*e844adb1SKashyap Desai 		goto out_failed;
2057*e844adb1SKashyap Desai 
2058824a1566SKashyap Desai 	mrioc->num_reply_bufs = mrioc->facts.max_reqs + MPI3MR_NUM_EVT_REPLIES;
2059824a1566SKashyap Desai 	mrioc->reply_free_qsz = mrioc->num_reply_bufs + 1;
2060824a1566SKashyap Desai 	mrioc->num_sense_bufs = mrioc->facts.max_reqs / MPI3MR_SENSEBUF_FACTOR;
2061824a1566SKashyap Desai 	mrioc->sense_buf_q_sz = mrioc->num_sense_bufs + 1;
2062824a1566SKashyap Desai 
2063824a1566SKashyap Desai 	/* reply buffer pool, 16 byte align */
2064824a1566SKashyap Desai 	sz = mrioc->num_reply_bufs * mrioc->facts.reply_sz;
2065824a1566SKashyap Desai 	mrioc->reply_buf_pool = dma_pool_create("reply_buf pool",
2066824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 16, 0);
2067824a1566SKashyap Desai 	if (!mrioc->reply_buf_pool) {
2068824a1566SKashyap Desai 		ioc_err(mrioc, "reply buf pool: dma_pool_create failed\n");
2069824a1566SKashyap Desai 		goto out_failed;
2070824a1566SKashyap Desai 	}
2071824a1566SKashyap Desai 
2072824a1566SKashyap Desai 	mrioc->reply_buf = dma_pool_zalloc(mrioc->reply_buf_pool, GFP_KERNEL,
2073824a1566SKashyap Desai 	    &mrioc->reply_buf_dma);
2074824a1566SKashyap Desai 	if (!mrioc->reply_buf)
2075824a1566SKashyap Desai 		goto out_failed;
2076824a1566SKashyap Desai 
2077824a1566SKashyap Desai 	mrioc->reply_buf_dma_max_address = mrioc->reply_buf_dma + sz;
2078824a1566SKashyap Desai 
2079824a1566SKashyap Desai 	/* reply free queue, 8 byte align */
2080824a1566SKashyap Desai 	sz = mrioc->reply_free_qsz * 8;
2081824a1566SKashyap Desai 	mrioc->reply_free_q_pool = dma_pool_create("reply_free_q pool",
2082824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 8, 0);
2083824a1566SKashyap Desai 	if (!mrioc->reply_free_q_pool) {
2084824a1566SKashyap Desai 		ioc_err(mrioc, "reply_free_q pool: dma_pool_create failed\n");
2085824a1566SKashyap Desai 		goto out_failed;
2086824a1566SKashyap Desai 	}
2087824a1566SKashyap Desai 	mrioc->reply_free_q = dma_pool_zalloc(mrioc->reply_free_q_pool,
2088824a1566SKashyap Desai 	    GFP_KERNEL, &mrioc->reply_free_q_dma);
2089824a1566SKashyap Desai 	if (!mrioc->reply_free_q)
2090824a1566SKashyap Desai 		goto out_failed;
2091824a1566SKashyap Desai 
2092824a1566SKashyap Desai 	/* sense buffer pool,  4 byte align */
2093824a1566SKashyap Desai 	sz = mrioc->num_sense_bufs * MPI3MR_SENSEBUF_SZ;
2094824a1566SKashyap Desai 	mrioc->sense_buf_pool = dma_pool_create("sense_buf pool",
2095824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 4, 0);
2096824a1566SKashyap Desai 	if (!mrioc->sense_buf_pool) {
2097824a1566SKashyap Desai 		ioc_err(mrioc, "sense_buf pool: dma_pool_create failed\n");
2098824a1566SKashyap Desai 		goto out_failed;
2099824a1566SKashyap Desai 	}
2100824a1566SKashyap Desai 	mrioc->sense_buf = dma_pool_zalloc(mrioc->sense_buf_pool, GFP_KERNEL,
2101824a1566SKashyap Desai 	    &mrioc->sense_buf_dma);
2102824a1566SKashyap Desai 	if (!mrioc->sense_buf)
2103824a1566SKashyap Desai 		goto out_failed;
2104824a1566SKashyap Desai 
2105824a1566SKashyap Desai 	/* sense buffer queue, 8 byte align */
2106824a1566SKashyap Desai 	sz = mrioc->sense_buf_q_sz * 8;
2107824a1566SKashyap Desai 	mrioc->sense_buf_q_pool = dma_pool_create("sense_buf_q pool",
2108824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 8, 0);
2109824a1566SKashyap Desai 	if (!mrioc->sense_buf_q_pool) {
2110824a1566SKashyap Desai 		ioc_err(mrioc, "sense_buf_q pool: dma_pool_create failed\n");
2111824a1566SKashyap Desai 		goto out_failed;
2112824a1566SKashyap Desai 	}
2113824a1566SKashyap Desai 	mrioc->sense_buf_q = dma_pool_zalloc(mrioc->sense_buf_q_pool,
2114824a1566SKashyap Desai 	    GFP_KERNEL, &mrioc->sense_buf_q_dma);
2115824a1566SKashyap Desai 	if (!mrioc->sense_buf_q)
2116824a1566SKashyap Desai 		goto out_failed;
2117824a1566SKashyap Desai 
2118824a1566SKashyap Desai post_reply_sbuf:
2119824a1566SKashyap Desai 	sz = mrioc->num_reply_bufs * mrioc->facts.reply_sz;
2120824a1566SKashyap Desai 	ioc_info(mrioc,
2121824a1566SKashyap Desai 	    "reply buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n",
2122824a1566SKashyap Desai 	    mrioc->reply_buf, mrioc->num_reply_bufs, mrioc->facts.reply_sz,
2123824a1566SKashyap Desai 	    (sz / 1024), (unsigned long long)mrioc->reply_buf_dma);
2124824a1566SKashyap Desai 	sz = mrioc->reply_free_qsz * 8;
2125824a1566SKashyap Desai 	ioc_info(mrioc,
2126824a1566SKashyap Desai 	    "reply_free_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n",
2127824a1566SKashyap Desai 	    mrioc->reply_free_q, mrioc->reply_free_qsz, 8, (sz / 1024),
2128824a1566SKashyap Desai 	    (unsigned long long)mrioc->reply_free_q_dma);
2129824a1566SKashyap Desai 	sz = mrioc->num_sense_bufs * MPI3MR_SENSEBUF_SZ;
2130824a1566SKashyap Desai 	ioc_info(mrioc,
2131824a1566SKashyap Desai 	    "sense_buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n",
2132824a1566SKashyap Desai 	    mrioc->sense_buf, mrioc->num_sense_bufs, MPI3MR_SENSEBUF_SZ,
2133824a1566SKashyap Desai 	    (sz / 1024), (unsigned long long)mrioc->sense_buf_dma);
2134824a1566SKashyap Desai 	sz = mrioc->sense_buf_q_sz * 8;
2135824a1566SKashyap Desai 	ioc_info(mrioc,
2136824a1566SKashyap Desai 	    "sense_buf_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n",
2137824a1566SKashyap Desai 	    mrioc->sense_buf_q, mrioc->sense_buf_q_sz, 8, (sz / 1024),
2138824a1566SKashyap Desai 	    (unsigned long long)mrioc->sense_buf_q_dma);
2139824a1566SKashyap Desai 
2140824a1566SKashyap Desai 	/* initialize Reply buffer Queue */
2141824a1566SKashyap Desai 	for (i = 0, phy_addr = mrioc->reply_buf_dma;
2142824a1566SKashyap Desai 	    i < mrioc->num_reply_bufs; i++, phy_addr += mrioc->facts.reply_sz)
2143824a1566SKashyap Desai 		mrioc->reply_free_q[i] = cpu_to_le64(phy_addr);
2144824a1566SKashyap Desai 	mrioc->reply_free_q[i] = cpu_to_le64(0);
2145824a1566SKashyap Desai 
2146824a1566SKashyap Desai 	/* initialize Sense Buffer Queue */
2147824a1566SKashyap Desai 	for (i = 0, phy_addr = mrioc->sense_buf_dma;
2148824a1566SKashyap Desai 	    i < mrioc->num_sense_bufs; i++, phy_addr += MPI3MR_SENSEBUF_SZ)
2149824a1566SKashyap Desai 		mrioc->sense_buf_q[i] = cpu_to_le64(phy_addr);
2150824a1566SKashyap Desai 	mrioc->sense_buf_q[i] = cpu_to_le64(0);
2151824a1566SKashyap Desai 	return retval;
2152824a1566SKashyap Desai 
2153824a1566SKashyap Desai out_failed:
2154824a1566SKashyap Desai 	retval = -1;
2155824a1566SKashyap Desai 	return retval;
2156824a1566SKashyap Desai }
2157824a1566SKashyap Desai 
2158824a1566SKashyap Desai /**
2159824a1566SKashyap Desai  * mpi3mr_issue_iocinit - Send IOC Init
2160824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2161824a1566SKashyap Desai  *
2162824a1566SKashyap Desai  * Issue IOC Init MPI request through admin queue and wait for
2163824a1566SKashyap Desai  * the completion of it or time out.
2164824a1566SKashyap Desai  *
2165824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
2166824a1566SKashyap Desai  */
2167824a1566SKashyap Desai static int mpi3mr_issue_iocinit(struct mpi3mr_ioc *mrioc)
2168824a1566SKashyap Desai {
2169824a1566SKashyap Desai 	struct mpi3_ioc_init_request iocinit_req;
2170824a1566SKashyap Desai 	struct mpi3_driver_info_layout *drv_info;
2171824a1566SKashyap Desai 	dma_addr_t data_dma;
2172824a1566SKashyap Desai 	u32 data_len = sizeof(*drv_info);
2173824a1566SKashyap Desai 	int retval = 0;
2174824a1566SKashyap Desai 	ktime_t current_time;
2175824a1566SKashyap Desai 
2176824a1566SKashyap Desai 	drv_info = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma,
2177824a1566SKashyap Desai 	    GFP_KERNEL);
2178824a1566SKashyap Desai 	if (!drv_info) {
2179824a1566SKashyap Desai 		retval = -1;
2180824a1566SKashyap Desai 		goto out;
2181824a1566SKashyap Desai 	}
2182824a1566SKashyap Desai 	drv_info->information_length = cpu_to_le32(data_len);
2183824a1566SKashyap Desai 	strncpy(drv_info->driver_signature, "Broadcom", sizeof(drv_info->driver_signature));
2184824a1566SKashyap Desai 	strncpy(drv_info->os_name, utsname()->sysname, sizeof(drv_info->os_name));
2185824a1566SKashyap Desai 	drv_info->os_name[sizeof(drv_info->os_name) - 1] = 0;
2186824a1566SKashyap Desai 	strncpy(drv_info->os_version, utsname()->release, sizeof(drv_info->os_version));
2187824a1566SKashyap Desai 	drv_info->os_version[sizeof(drv_info->os_version) - 1] = 0;
2188824a1566SKashyap Desai 	strncpy(drv_info->driver_name, MPI3MR_DRIVER_NAME, sizeof(drv_info->driver_name));
2189824a1566SKashyap Desai 	strncpy(drv_info->driver_version, MPI3MR_DRIVER_VERSION, sizeof(drv_info->driver_version));
2190824a1566SKashyap Desai 	strncpy(drv_info->driver_release_date, MPI3MR_DRIVER_RELDATE, sizeof(drv_info->driver_release_date));
2191824a1566SKashyap Desai 	drv_info->driver_capabilities = 0;
2192824a1566SKashyap Desai 	memcpy((u8 *)&mrioc->driver_info, (u8 *)drv_info,
2193824a1566SKashyap Desai 	    sizeof(mrioc->driver_info));
2194824a1566SKashyap Desai 
2195824a1566SKashyap Desai 	memset(&iocinit_req, 0, sizeof(iocinit_req));
2196824a1566SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
2197824a1566SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
2198824a1566SKashyap Desai 		retval = -1;
2199824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCInit: Init command is in use\n");
2200824a1566SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
2201824a1566SKashyap Desai 		goto out;
2202824a1566SKashyap Desai 	}
2203824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
2204824a1566SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
2205824a1566SKashyap Desai 	mrioc->init_cmds.callback = NULL;
2206824a1566SKashyap Desai 	iocinit_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
2207824a1566SKashyap Desai 	iocinit_req.function = MPI3_FUNCTION_IOC_INIT;
2208824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.dev = MPI3_VERSION_DEV;
2209824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.unit = MPI3_VERSION_UNIT;
2210824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.major = MPI3_VERSION_MAJOR;
2211824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.minor = MPI3_VERSION_MINOR;
2212824a1566SKashyap Desai 	iocinit_req.who_init = MPI3_WHOINIT_HOST_DRIVER;
2213824a1566SKashyap Desai 	iocinit_req.reply_free_queue_depth = cpu_to_le16(mrioc->reply_free_qsz);
2214824a1566SKashyap Desai 	iocinit_req.reply_free_queue_address =
2215824a1566SKashyap Desai 	    cpu_to_le64(mrioc->reply_free_q_dma);
2216824a1566SKashyap Desai 	iocinit_req.sense_buffer_length = cpu_to_le16(MPI3MR_SENSEBUF_SZ);
2217824a1566SKashyap Desai 	iocinit_req.sense_buffer_free_queue_depth =
2218824a1566SKashyap Desai 	    cpu_to_le16(mrioc->sense_buf_q_sz);
2219824a1566SKashyap Desai 	iocinit_req.sense_buffer_free_queue_address =
2220824a1566SKashyap Desai 	    cpu_to_le64(mrioc->sense_buf_q_dma);
2221824a1566SKashyap Desai 	iocinit_req.driver_information_address = cpu_to_le64(data_dma);
2222824a1566SKashyap Desai 
2223824a1566SKashyap Desai 	current_time = ktime_get_real();
2224824a1566SKashyap Desai 	iocinit_req.time_stamp = cpu_to_le64(ktime_to_ms(current_time));
2225824a1566SKashyap Desai 
2226824a1566SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
2227824a1566SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &iocinit_req,
2228824a1566SKashyap Desai 	    sizeof(iocinit_req), 1);
2229824a1566SKashyap Desai 	if (retval) {
2230824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCInit: Admin Post failed\n");
2231824a1566SKashyap Desai 		goto out_unlock;
2232824a1566SKashyap Desai 	}
2233824a1566SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
2234824a1566SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
2235824a1566SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
2236824a1566SKashyap Desai 		mpi3mr_set_diagsave(mrioc);
2237824a1566SKashyap Desai 		mpi3mr_issue_reset(mrioc,
2238824a1566SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
2239824a1566SKashyap Desai 		    MPI3MR_RESET_FROM_IOCINIT_TIMEOUT);
2240824a1566SKashyap Desai 		mrioc->unrecoverable = 1;
2241824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCInit: command timed out\n");
2242824a1566SKashyap Desai 		retval = -1;
2243824a1566SKashyap Desai 		goto out_unlock;
2244824a1566SKashyap Desai 	}
2245824a1566SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
2246824a1566SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
2247824a1566SKashyap Desai 		ioc_err(mrioc,
2248824a1566SKashyap Desai 		    "Issue IOCInit: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
2249824a1566SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
2250824a1566SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
2251824a1566SKashyap Desai 		retval = -1;
2252824a1566SKashyap Desai 		goto out_unlock;
2253824a1566SKashyap Desai 	}
2254824a1566SKashyap Desai 
2255824a1566SKashyap Desai out_unlock:
2256824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
2257824a1566SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
2258824a1566SKashyap Desai 
2259824a1566SKashyap Desai out:
2260824a1566SKashyap Desai 	if (drv_info)
2261824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, data_len, drv_info,
2262824a1566SKashyap Desai 		    data_dma);
2263824a1566SKashyap Desai 
2264824a1566SKashyap Desai 	return retval;
2265824a1566SKashyap Desai }
2266824a1566SKashyap Desai 
2267824a1566SKashyap Desai /**
226813ef29eaSKashyap Desai  * mpi3mr_unmask_events - Unmask events in event mask bitmap
226913ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
227013ef29eaSKashyap Desai  * @event: MPI event ID
227113ef29eaSKashyap Desai  *
227213ef29eaSKashyap Desai  * Un mask the specific event by resetting the event_mask
227313ef29eaSKashyap Desai  * bitmap.
227413ef29eaSKashyap Desai  *
227513ef29eaSKashyap Desai  * Return: 0 on success, non-zero on failures.
227613ef29eaSKashyap Desai  */
227713ef29eaSKashyap Desai static void mpi3mr_unmask_events(struct mpi3mr_ioc *mrioc, u16 event)
227813ef29eaSKashyap Desai {
227913ef29eaSKashyap Desai 	u32 desired_event;
228013ef29eaSKashyap Desai 	u8 word;
228113ef29eaSKashyap Desai 
228213ef29eaSKashyap Desai 	if (event >= 128)
228313ef29eaSKashyap Desai 		return;
228413ef29eaSKashyap Desai 
228513ef29eaSKashyap Desai 	desired_event = (1 << (event % 32));
228613ef29eaSKashyap Desai 	word = event / 32;
228713ef29eaSKashyap Desai 
228813ef29eaSKashyap Desai 	mrioc->event_masks[word] &= ~desired_event;
228913ef29eaSKashyap Desai }
229013ef29eaSKashyap Desai 
229113ef29eaSKashyap Desai /**
229213ef29eaSKashyap Desai  * mpi3mr_issue_event_notification - Send event notification
229313ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
229413ef29eaSKashyap Desai  *
229513ef29eaSKashyap Desai  * Issue event notification MPI request through admin queue and
229613ef29eaSKashyap Desai  * wait for the completion of it or time out.
229713ef29eaSKashyap Desai  *
229813ef29eaSKashyap Desai  * Return: 0 on success, non-zero on failures.
229913ef29eaSKashyap Desai  */
230013ef29eaSKashyap Desai static int mpi3mr_issue_event_notification(struct mpi3mr_ioc *mrioc)
230113ef29eaSKashyap Desai {
230213ef29eaSKashyap Desai 	struct mpi3_event_notification_request evtnotify_req;
230313ef29eaSKashyap Desai 	int retval = 0;
230413ef29eaSKashyap Desai 	u8 i;
230513ef29eaSKashyap Desai 
230613ef29eaSKashyap Desai 	memset(&evtnotify_req, 0, sizeof(evtnotify_req));
230713ef29eaSKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
230813ef29eaSKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
230913ef29eaSKashyap Desai 		retval = -1;
231013ef29eaSKashyap Desai 		ioc_err(mrioc, "Issue EvtNotify: Init command is in use\n");
231113ef29eaSKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
231213ef29eaSKashyap Desai 		goto out;
231313ef29eaSKashyap Desai 	}
231413ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
231513ef29eaSKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
231613ef29eaSKashyap Desai 	mrioc->init_cmds.callback = NULL;
231713ef29eaSKashyap Desai 	evtnotify_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
231813ef29eaSKashyap Desai 	evtnotify_req.function = MPI3_FUNCTION_EVENT_NOTIFICATION;
231913ef29eaSKashyap Desai 	for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
232013ef29eaSKashyap Desai 		evtnotify_req.event_masks[i] =
232113ef29eaSKashyap Desai 		    cpu_to_le32(mrioc->event_masks[i]);
232213ef29eaSKashyap Desai 	init_completion(&mrioc->init_cmds.done);
232313ef29eaSKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &evtnotify_req,
232413ef29eaSKashyap Desai 	    sizeof(evtnotify_req), 1);
232513ef29eaSKashyap Desai 	if (retval) {
232613ef29eaSKashyap Desai 		ioc_err(mrioc, "Issue EvtNotify: Admin Post failed\n");
232713ef29eaSKashyap Desai 		goto out_unlock;
232813ef29eaSKashyap Desai 	}
232913ef29eaSKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
233013ef29eaSKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
233113ef29eaSKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
233213ef29eaSKashyap Desai 		ioc_err(mrioc, "Issue EvtNotify: command timed out\n");
233313ef29eaSKashyap Desai 		mpi3mr_set_diagsave(mrioc);
233413ef29eaSKashyap Desai 		mpi3mr_issue_reset(mrioc,
233513ef29eaSKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
233613ef29eaSKashyap Desai 		    MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT);
233713ef29eaSKashyap Desai 		mrioc->unrecoverable = 1;
233813ef29eaSKashyap Desai 		retval = -1;
233913ef29eaSKashyap Desai 		goto out_unlock;
234013ef29eaSKashyap Desai 	}
234113ef29eaSKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
234213ef29eaSKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
234313ef29eaSKashyap Desai 		ioc_err(mrioc,
234413ef29eaSKashyap Desai 		    "Issue EvtNotify: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
234513ef29eaSKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
234613ef29eaSKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
234713ef29eaSKashyap Desai 		retval = -1;
234813ef29eaSKashyap Desai 		goto out_unlock;
234913ef29eaSKashyap Desai 	}
235013ef29eaSKashyap Desai 
235113ef29eaSKashyap Desai out_unlock:
235213ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
235313ef29eaSKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
235413ef29eaSKashyap Desai out:
235513ef29eaSKashyap Desai 	return retval;
235613ef29eaSKashyap Desai }
235713ef29eaSKashyap Desai 
235813ef29eaSKashyap Desai /**
235913ef29eaSKashyap Desai  * mpi3mr_send_event_ack - Send event acknowledgment
236013ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
236113ef29eaSKashyap Desai  * @event: MPI3 event ID
236213ef29eaSKashyap Desai  * @event_ctx: Event context
236313ef29eaSKashyap Desai  *
236413ef29eaSKashyap Desai  * Send event acknowledgment through admin queue and wait for
236513ef29eaSKashyap Desai  * it to complete.
236613ef29eaSKashyap Desai  *
236713ef29eaSKashyap Desai  * Return: 0 on success, non-zero on failures.
236813ef29eaSKashyap Desai  */
236913ef29eaSKashyap Desai int mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event,
237013ef29eaSKashyap Desai 	u32 event_ctx)
237113ef29eaSKashyap Desai {
237213ef29eaSKashyap Desai 	struct mpi3_event_ack_request evtack_req;
237313ef29eaSKashyap Desai 	int retval = 0;
237413ef29eaSKashyap Desai 
237513ef29eaSKashyap Desai 	memset(&evtack_req, 0, sizeof(evtack_req));
237613ef29eaSKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
237713ef29eaSKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
237813ef29eaSKashyap Desai 		retval = -1;
237913ef29eaSKashyap Desai 		ioc_err(mrioc, "Send EvtAck: Init command is in use\n");
238013ef29eaSKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
238113ef29eaSKashyap Desai 		goto out;
238213ef29eaSKashyap Desai 	}
238313ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
238413ef29eaSKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
238513ef29eaSKashyap Desai 	mrioc->init_cmds.callback = NULL;
238613ef29eaSKashyap Desai 	evtack_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
238713ef29eaSKashyap Desai 	evtack_req.function = MPI3_FUNCTION_EVENT_ACK;
238813ef29eaSKashyap Desai 	evtack_req.event = event;
238913ef29eaSKashyap Desai 	evtack_req.event_context = cpu_to_le32(event_ctx);
239013ef29eaSKashyap Desai 
239113ef29eaSKashyap Desai 	init_completion(&mrioc->init_cmds.done);
239213ef29eaSKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &evtack_req,
239313ef29eaSKashyap Desai 	    sizeof(evtack_req), 1);
239413ef29eaSKashyap Desai 	if (retval) {
239513ef29eaSKashyap Desai 		ioc_err(mrioc, "Send EvtAck: Admin Post failed\n");
239613ef29eaSKashyap Desai 		goto out_unlock;
239713ef29eaSKashyap Desai 	}
239813ef29eaSKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
239913ef29eaSKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
240013ef29eaSKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
240113ef29eaSKashyap Desai 		ioc_err(mrioc, "Issue EvtNotify: command timed out\n");
240213ef29eaSKashyap Desai 		mpi3mr_soft_reset_handler(mrioc,
240313ef29eaSKashyap Desai 		    MPI3MR_RESET_FROM_EVTACK_TIMEOUT, 1);
240413ef29eaSKashyap Desai 		retval = -1;
240513ef29eaSKashyap Desai 		goto out_unlock;
240613ef29eaSKashyap Desai 	}
240713ef29eaSKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
240813ef29eaSKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
240913ef29eaSKashyap Desai 		ioc_err(mrioc,
241013ef29eaSKashyap Desai 		    "Send EvtAck: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
241113ef29eaSKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
241213ef29eaSKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
241313ef29eaSKashyap Desai 		retval = -1;
241413ef29eaSKashyap Desai 		goto out_unlock;
241513ef29eaSKashyap Desai 	}
241613ef29eaSKashyap Desai 
241713ef29eaSKashyap Desai out_unlock:
241813ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
241913ef29eaSKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
242013ef29eaSKashyap Desai out:
242113ef29eaSKashyap Desai 	return retval;
242213ef29eaSKashyap Desai }
242313ef29eaSKashyap Desai 
242413ef29eaSKashyap Desai /**
2425824a1566SKashyap Desai  * mpi3mr_alloc_chain_bufs - Allocate chain buffers
2426824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2427824a1566SKashyap Desai  *
2428824a1566SKashyap Desai  * Allocate chain buffers and set a bitmap to indicate free
2429824a1566SKashyap Desai  * chain buffers. Chain buffers are used to pass the SGE
2430824a1566SKashyap Desai  * information along with MPI3 SCSI IO requests for host I/O.
2431824a1566SKashyap Desai  *
2432824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure
2433824a1566SKashyap Desai  */
2434824a1566SKashyap Desai static int mpi3mr_alloc_chain_bufs(struct mpi3mr_ioc *mrioc)
2435824a1566SKashyap Desai {
2436824a1566SKashyap Desai 	int retval = 0;
2437824a1566SKashyap Desai 	u32 sz, i;
2438824a1566SKashyap Desai 	u16 num_chains;
2439824a1566SKashyap Desai 
2440824a1566SKashyap Desai 	num_chains = mrioc->max_host_ios / MPI3MR_CHAINBUF_FACTOR;
2441824a1566SKashyap Desai 
2442824a1566SKashyap Desai 	mrioc->chain_buf_count = num_chains;
2443824a1566SKashyap Desai 	sz = sizeof(struct chain_element) * num_chains;
2444824a1566SKashyap Desai 	mrioc->chain_sgl_list = kzalloc(sz, GFP_KERNEL);
2445824a1566SKashyap Desai 	if (!mrioc->chain_sgl_list)
2446824a1566SKashyap Desai 		goto out_failed;
2447824a1566SKashyap Desai 
2448824a1566SKashyap Desai 	sz = MPI3MR_PAGE_SIZE_4K;
2449824a1566SKashyap Desai 	mrioc->chain_buf_pool = dma_pool_create("chain_buf pool",
2450824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 16, 0);
2451824a1566SKashyap Desai 	if (!mrioc->chain_buf_pool) {
2452824a1566SKashyap Desai 		ioc_err(mrioc, "chain buf pool: dma_pool_create failed\n");
2453824a1566SKashyap Desai 		goto out_failed;
2454824a1566SKashyap Desai 	}
2455824a1566SKashyap Desai 
2456824a1566SKashyap Desai 	for (i = 0; i < num_chains; i++) {
2457824a1566SKashyap Desai 		mrioc->chain_sgl_list[i].addr =
2458824a1566SKashyap Desai 		    dma_pool_zalloc(mrioc->chain_buf_pool, GFP_KERNEL,
2459824a1566SKashyap Desai 		    &mrioc->chain_sgl_list[i].dma_addr);
2460824a1566SKashyap Desai 
2461824a1566SKashyap Desai 		if (!mrioc->chain_sgl_list[i].addr)
2462824a1566SKashyap Desai 			goto out_failed;
2463824a1566SKashyap Desai 	}
2464824a1566SKashyap Desai 	mrioc->chain_bitmap_sz = num_chains / 8;
2465824a1566SKashyap Desai 	if (num_chains % 8)
2466824a1566SKashyap Desai 		mrioc->chain_bitmap_sz++;
2467824a1566SKashyap Desai 	mrioc->chain_bitmap = kzalloc(mrioc->chain_bitmap_sz, GFP_KERNEL);
2468824a1566SKashyap Desai 	if (!mrioc->chain_bitmap)
2469824a1566SKashyap Desai 		goto out_failed;
2470824a1566SKashyap Desai 	return retval;
2471824a1566SKashyap Desai out_failed:
2472824a1566SKashyap Desai 	retval = -1;
2473824a1566SKashyap Desai 	return retval;
2474824a1566SKashyap Desai }
2475824a1566SKashyap Desai 
2476824a1566SKashyap Desai /**
2477023ab2a9SKashyap Desai  * mpi3mr_port_enable_complete - Mark port enable complete
2478023ab2a9SKashyap Desai  * @mrioc: Adapter instance reference
2479023ab2a9SKashyap Desai  * @drv_cmd: Internal command tracker
2480023ab2a9SKashyap Desai  *
2481023ab2a9SKashyap Desai  * Call back for asynchronous port enable request sets the
2482023ab2a9SKashyap Desai  * driver command to indicate port enable request is complete.
2483023ab2a9SKashyap Desai  *
2484023ab2a9SKashyap Desai  * Return: Nothing
2485023ab2a9SKashyap Desai  */
2486023ab2a9SKashyap Desai static void mpi3mr_port_enable_complete(struct mpi3mr_ioc *mrioc,
2487023ab2a9SKashyap Desai 	struct mpi3mr_drv_cmd *drv_cmd)
2488023ab2a9SKashyap Desai {
2489023ab2a9SKashyap Desai 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
2490023ab2a9SKashyap Desai 	drv_cmd->callback = NULL;
2491023ab2a9SKashyap Desai 	mrioc->scan_failed = drv_cmd->ioc_status;
2492023ab2a9SKashyap Desai 	mrioc->scan_started = 0;
2493023ab2a9SKashyap Desai }
2494023ab2a9SKashyap Desai 
2495023ab2a9SKashyap Desai /**
2496023ab2a9SKashyap Desai  * mpi3mr_issue_port_enable - Issue Port Enable
2497023ab2a9SKashyap Desai  * @mrioc: Adapter instance reference
2498023ab2a9SKashyap Desai  * @async: Flag to wait for completion or not
2499023ab2a9SKashyap Desai  *
2500023ab2a9SKashyap Desai  * Issue Port Enable MPI request through admin queue and if the
2501023ab2a9SKashyap Desai  * async flag is not set wait for the completion of the port
2502023ab2a9SKashyap Desai  * enable or time out.
2503023ab2a9SKashyap Desai  *
2504023ab2a9SKashyap Desai  * Return: 0 on success, non-zero on failures.
2505023ab2a9SKashyap Desai  */
2506023ab2a9SKashyap Desai int mpi3mr_issue_port_enable(struct mpi3mr_ioc *mrioc, u8 async)
2507023ab2a9SKashyap Desai {
2508023ab2a9SKashyap Desai 	struct mpi3_port_enable_request pe_req;
2509023ab2a9SKashyap Desai 	int retval = 0;
2510023ab2a9SKashyap Desai 	u32 pe_timeout = MPI3MR_PORTENABLE_TIMEOUT;
2511023ab2a9SKashyap Desai 
2512023ab2a9SKashyap Desai 	memset(&pe_req, 0, sizeof(pe_req));
2513023ab2a9SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
2514023ab2a9SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
2515023ab2a9SKashyap Desai 		retval = -1;
2516023ab2a9SKashyap Desai 		ioc_err(mrioc, "Issue PortEnable: Init command is in use\n");
2517023ab2a9SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
2518023ab2a9SKashyap Desai 		goto out;
2519023ab2a9SKashyap Desai 	}
2520023ab2a9SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
2521023ab2a9SKashyap Desai 	if (async) {
2522023ab2a9SKashyap Desai 		mrioc->init_cmds.is_waiting = 0;
2523023ab2a9SKashyap Desai 		mrioc->init_cmds.callback = mpi3mr_port_enable_complete;
2524023ab2a9SKashyap Desai 	} else {
2525023ab2a9SKashyap Desai 		mrioc->init_cmds.is_waiting = 1;
2526023ab2a9SKashyap Desai 		mrioc->init_cmds.callback = NULL;
2527023ab2a9SKashyap Desai 		init_completion(&mrioc->init_cmds.done);
2528023ab2a9SKashyap Desai 	}
2529023ab2a9SKashyap Desai 	pe_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
2530023ab2a9SKashyap Desai 	pe_req.function = MPI3_FUNCTION_PORT_ENABLE;
2531023ab2a9SKashyap Desai 
2532023ab2a9SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &pe_req, sizeof(pe_req), 1);
2533023ab2a9SKashyap Desai 	if (retval) {
2534023ab2a9SKashyap Desai 		ioc_err(mrioc, "Issue PortEnable: Admin Post failed\n");
2535023ab2a9SKashyap Desai 		goto out_unlock;
2536023ab2a9SKashyap Desai 	}
2537023ab2a9SKashyap Desai 	if (!async) {
2538023ab2a9SKashyap Desai 		wait_for_completion_timeout(&mrioc->init_cmds.done,
2539023ab2a9SKashyap Desai 		    (pe_timeout * HZ));
2540023ab2a9SKashyap Desai 		if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
2541023ab2a9SKashyap Desai 			ioc_err(mrioc, "Issue PortEnable: command timed out\n");
2542023ab2a9SKashyap Desai 			retval = -1;
2543023ab2a9SKashyap Desai 			mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR;
2544023ab2a9SKashyap Desai 			mpi3mr_set_diagsave(mrioc);
2545023ab2a9SKashyap Desai 			mpi3mr_issue_reset(mrioc,
2546023ab2a9SKashyap Desai 			    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
2547023ab2a9SKashyap Desai 			    MPI3MR_RESET_FROM_PE_TIMEOUT);
2548023ab2a9SKashyap Desai 			mrioc->unrecoverable = 1;
2549023ab2a9SKashyap Desai 			goto out_unlock;
2550023ab2a9SKashyap Desai 		}
2551023ab2a9SKashyap Desai 		mpi3mr_port_enable_complete(mrioc, &mrioc->init_cmds);
2552023ab2a9SKashyap Desai 	}
2553023ab2a9SKashyap Desai out_unlock:
2554023ab2a9SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
2555023ab2a9SKashyap Desai out:
2556023ab2a9SKashyap Desai 	return retval;
2557023ab2a9SKashyap Desai }
2558023ab2a9SKashyap Desai 
2559ff9561e9SKashyap Desai /* Protocol type to name mapper structure*/
2560ff9561e9SKashyap Desai static const struct {
2561ff9561e9SKashyap Desai 	u8 protocol;
2562ff9561e9SKashyap Desai 	char *name;
2563ff9561e9SKashyap Desai } mpi3mr_protocols[] = {
2564ff9561e9SKashyap Desai 	{ MPI3_IOCFACTS_PROTOCOL_SCSI_INITIATOR, "Initiator" },
2565ff9561e9SKashyap Desai 	{ MPI3_IOCFACTS_PROTOCOL_SCSI_TARGET, "Target" },
2566ff9561e9SKashyap Desai 	{ MPI3_IOCFACTS_PROTOCOL_NVME, "NVMe attachment" },
2567ff9561e9SKashyap Desai };
2568ff9561e9SKashyap Desai 
2569ff9561e9SKashyap Desai /* Capability to name mapper structure*/
2570ff9561e9SKashyap Desai static const struct {
2571ff9561e9SKashyap Desai 	u32 capability;
2572ff9561e9SKashyap Desai 	char *name;
2573ff9561e9SKashyap Desai } mpi3mr_capabilities[] = {
2574ff9561e9SKashyap Desai 	{ MPI3_IOCFACTS_CAPABILITY_RAID_CAPABLE, "RAID" },
2575ff9561e9SKashyap Desai };
2576ff9561e9SKashyap Desai 
2577ff9561e9SKashyap Desai /**
2578ff9561e9SKashyap Desai  * mpi3mr_print_ioc_info - Display controller information
2579ff9561e9SKashyap Desai  * @mrioc: Adapter instance reference
2580ff9561e9SKashyap Desai  *
2581ff9561e9SKashyap Desai  * Display controller personalit, capability, supported
2582ff9561e9SKashyap Desai  * protocols etc.
2583ff9561e9SKashyap Desai  *
2584ff9561e9SKashyap Desai  * Return: Nothing
2585ff9561e9SKashyap Desai  */
2586ff9561e9SKashyap Desai static void
2587ff9561e9SKashyap Desai mpi3mr_print_ioc_info(struct mpi3mr_ioc *mrioc)
2588ff9561e9SKashyap Desai {
2589ff9561e9SKashyap Desai 	int i = 0, bytes_wrote = 0;
2590ff9561e9SKashyap Desai 	char personality[16];
2591ff9561e9SKashyap Desai 	char protocol[50] = {0};
2592ff9561e9SKashyap Desai 	char capabilities[100] = {0};
2593ff9561e9SKashyap Desai 	bool is_string_nonempty = false;
2594ff9561e9SKashyap Desai 	struct mpi3mr_compimg_ver *fwver = &mrioc->facts.fw_ver;
2595ff9561e9SKashyap Desai 
2596ff9561e9SKashyap Desai 	switch (mrioc->facts.personality) {
2597ff9561e9SKashyap Desai 	case MPI3_IOCFACTS_FLAGS_PERSONALITY_EHBA:
2598ff9561e9SKashyap Desai 		strncpy(personality, "Enhanced HBA", sizeof(personality));
2599ff9561e9SKashyap Desai 		break;
2600ff9561e9SKashyap Desai 	case MPI3_IOCFACTS_FLAGS_PERSONALITY_RAID_DDR:
2601ff9561e9SKashyap Desai 		strncpy(personality, "RAID", sizeof(personality));
2602ff9561e9SKashyap Desai 		break;
2603ff9561e9SKashyap Desai 	default:
2604ff9561e9SKashyap Desai 		strncpy(personality, "Unknown", sizeof(personality));
2605ff9561e9SKashyap Desai 		break;
2606ff9561e9SKashyap Desai 	}
2607ff9561e9SKashyap Desai 
2608ff9561e9SKashyap Desai 	ioc_info(mrioc, "Running in %s Personality", personality);
2609ff9561e9SKashyap Desai 
2610ff9561e9SKashyap Desai 	ioc_info(mrioc, "FW version(%d.%d.%d.%d.%d.%d)\n",
2611ff9561e9SKashyap Desai 	    fwver->gen_major, fwver->gen_minor, fwver->ph_major,
2612ff9561e9SKashyap Desai 	    fwver->ph_minor, fwver->cust_id, fwver->build_num);
2613ff9561e9SKashyap Desai 
2614ff9561e9SKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mpi3mr_protocols); i++) {
2615ff9561e9SKashyap Desai 		if (mrioc->facts.protocol_flags &
2616ff9561e9SKashyap Desai 		    mpi3mr_protocols[i].protocol) {
2617ff9561e9SKashyap Desai 			if (is_string_nonempty &&
2618ff9561e9SKashyap Desai 			    (bytes_wrote < sizeof(protocol)))
2619ff9561e9SKashyap Desai 				bytes_wrote += snprintf(protocol + bytes_wrote,
2620ff9561e9SKashyap Desai 				    (sizeof(protocol) - bytes_wrote), ",");
2621ff9561e9SKashyap Desai 
2622ff9561e9SKashyap Desai 			if (bytes_wrote < sizeof(protocol))
2623ff9561e9SKashyap Desai 				bytes_wrote += snprintf(protocol + bytes_wrote,
2624ff9561e9SKashyap Desai 				    (sizeof(protocol) - bytes_wrote), "%s",
2625ff9561e9SKashyap Desai 				    mpi3mr_protocols[i].name);
2626ff9561e9SKashyap Desai 			is_string_nonempty = true;
2627ff9561e9SKashyap Desai 		}
2628ff9561e9SKashyap Desai 	}
2629ff9561e9SKashyap Desai 
2630ff9561e9SKashyap Desai 	bytes_wrote = 0;
2631ff9561e9SKashyap Desai 	is_string_nonempty = false;
2632ff9561e9SKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mpi3mr_capabilities); i++) {
2633ff9561e9SKashyap Desai 		if (mrioc->facts.protocol_flags &
2634ff9561e9SKashyap Desai 		    mpi3mr_capabilities[i].capability) {
2635ff9561e9SKashyap Desai 			if (is_string_nonempty &&
2636ff9561e9SKashyap Desai 			    (bytes_wrote < sizeof(capabilities)))
2637ff9561e9SKashyap Desai 				bytes_wrote += snprintf(capabilities + bytes_wrote,
2638ff9561e9SKashyap Desai 				    (sizeof(capabilities) - bytes_wrote), ",");
2639ff9561e9SKashyap Desai 
2640ff9561e9SKashyap Desai 			if (bytes_wrote < sizeof(capabilities))
2641ff9561e9SKashyap Desai 				bytes_wrote += snprintf(capabilities + bytes_wrote,
2642ff9561e9SKashyap Desai 				    (sizeof(capabilities) - bytes_wrote), "%s",
2643ff9561e9SKashyap Desai 				    mpi3mr_capabilities[i].name);
2644ff9561e9SKashyap Desai 			is_string_nonempty = true;
2645ff9561e9SKashyap Desai 		}
2646ff9561e9SKashyap Desai 	}
2647ff9561e9SKashyap Desai 
2648ff9561e9SKashyap Desai 	ioc_info(mrioc, "Protocol=(%s), Capabilities=(%s)\n",
2649ff9561e9SKashyap Desai 	    protocol, capabilities);
2650ff9561e9SKashyap Desai }
2651ff9561e9SKashyap Desai 
2652023ab2a9SKashyap Desai /**
2653824a1566SKashyap Desai  * mpi3mr_cleanup_resources - Free PCI resources
2654824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2655824a1566SKashyap Desai  *
2656824a1566SKashyap Desai  * Unmap PCI device memory and disable PCI device.
2657824a1566SKashyap Desai  *
2658824a1566SKashyap Desai  * Return: 0 on success and non-zero on failure.
2659824a1566SKashyap Desai  */
2660824a1566SKashyap Desai void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc)
2661824a1566SKashyap Desai {
2662824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
2663824a1566SKashyap Desai 
2664824a1566SKashyap Desai 	mpi3mr_cleanup_isr(mrioc);
2665824a1566SKashyap Desai 
2666824a1566SKashyap Desai 	if (mrioc->sysif_regs) {
2667824a1566SKashyap Desai 		iounmap((void __iomem *)mrioc->sysif_regs);
2668824a1566SKashyap Desai 		mrioc->sysif_regs = NULL;
2669824a1566SKashyap Desai 	}
2670824a1566SKashyap Desai 
2671824a1566SKashyap Desai 	if (pci_is_enabled(pdev)) {
2672824a1566SKashyap Desai 		if (mrioc->bars)
2673824a1566SKashyap Desai 			pci_release_selected_regions(pdev, mrioc->bars);
2674824a1566SKashyap Desai 		pci_disable_device(pdev);
2675824a1566SKashyap Desai 	}
2676824a1566SKashyap Desai }
2677824a1566SKashyap Desai 
2678824a1566SKashyap Desai /**
2679824a1566SKashyap Desai  * mpi3mr_setup_resources - Enable PCI resources
2680824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2681824a1566SKashyap Desai  *
2682824a1566SKashyap Desai  * Enable PCI device memory, MSI-x registers and set DMA mask.
2683824a1566SKashyap Desai  *
2684824a1566SKashyap Desai  * Return: 0 on success and non-zero on failure.
2685824a1566SKashyap Desai  */
2686824a1566SKashyap Desai int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc)
2687824a1566SKashyap Desai {
2688824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
2689824a1566SKashyap Desai 	u32 memap_sz = 0;
2690824a1566SKashyap Desai 	int i, retval = 0, capb = 0;
2691824a1566SKashyap Desai 	u16 message_control;
2692824a1566SKashyap Desai 	u64 dma_mask = mrioc->dma_mask ? mrioc->dma_mask :
2693824a1566SKashyap Desai 	    (((dma_get_required_mask(&pdev->dev) > DMA_BIT_MASK(32)) &&
2694824a1566SKashyap Desai 	    (sizeof(dma_addr_t) > 4)) ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32));
2695824a1566SKashyap Desai 
2696824a1566SKashyap Desai 	if (pci_enable_device_mem(pdev)) {
2697824a1566SKashyap Desai 		ioc_err(mrioc, "pci_enable_device_mem: failed\n");
2698824a1566SKashyap Desai 		retval = -ENODEV;
2699824a1566SKashyap Desai 		goto out_failed;
2700824a1566SKashyap Desai 	}
2701824a1566SKashyap Desai 
2702824a1566SKashyap Desai 	capb = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
2703824a1566SKashyap Desai 	if (!capb) {
2704824a1566SKashyap Desai 		ioc_err(mrioc, "Unable to find MSI-X Capabilities\n");
2705824a1566SKashyap Desai 		retval = -ENODEV;
2706824a1566SKashyap Desai 		goto out_failed;
2707824a1566SKashyap Desai 	}
2708824a1566SKashyap Desai 	mrioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
2709824a1566SKashyap Desai 
2710824a1566SKashyap Desai 	if (pci_request_selected_regions(pdev, mrioc->bars,
2711824a1566SKashyap Desai 	    mrioc->driver_name)) {
2712824a1566SKashyap Desai 		ioc_err(mrioc, "pci_request_selected_regions: failed\n");
2713824a1566SKashyap Desai 		retval = -ENODEV;
2714824a1566SKashyap Desai 		goto out_failed;
2715824a1566SKashyap Desai 	}
2716824a1566SKashyap Desai 
2717824a1566SKashyap Desai 	for (i = 0; (i < DEVICE_COUNT_RESOURCE); i++) {
2718824a1566SKashyap Desai 		if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
2719824a1566SKashyap Desai 			mrioc->sysif_regs_phys = pci_resource_start(pdev, i);
2720824a1566SKashyap Desai 			memap_sz = pci_resource_len(pdev, i);
2721824a1566SKashyap Desai 			mrioc->sysif_regs =
2722824a1566SKashyap Desai 			    ioremap(mrioc->sysif_regs_phys, memap_sz);
2723824a1566SKashyap Desai 			break;
2724824a1566SKashyap Desai 		}
2725824a1566SKashyap Desai 	}
2726824a1566SKashyap Desai 
2727824a1566SKashyap Desai 	pci_set_master(pdev);
2728824a1566SKashyap Desai 
2729824a1566SKashyap Desai 	retval = dma_set_mask_and_coherent(&pdev->dev, dma_mask);
2730824a1566SKashyap Desai 	if (retval) {
2731824a1566SKashyap Desai 		if (dma_mask != DMA_BIT_MASK(32)) {
2732824a1566SKashyap Desai 			ioc_warn(mrioc, "Setting 64 bit DMA mask failed\n");
2733824a1566SKashyap Desai 			dma_mask = DMA_BIT_MASK(32);
2734824a1566SKashyap Desai 			retval = dma_set_mask_and_coherent(&pdev->dev,
2735824a1566SKashyap Desai 			    dma_mask);
2736824a1566SKashyap Desai 		}
2737824a1566SKashyap Desai 		if (retval) {
2738824a1566SKashyap Desai 			mrioc->dma_mask = 0;
2739824a1566SKashyap Desai 			ioc_err(mrioc, "Setting 32 bit DMA mask also failed\n");
2740824a1566SKashyap Desai 			goto out_failed;
2741824a1566SKashyap Desai 		}
2742824a1566SKashyap Desai 	}
2743824a1566SKashyap Desai 	mrioc->dma_mask = dma_mask;
2744824a1566SKashyap Desai 
2745824a1566SKashyap Desai 	if (!mrioc->sysif_regs) {
2746824a1566SKashyap Desai 		ioc_err(mrioc,
2747824a1566SKashyap Desai 		    "Unable to map adapter memory or resource not found\n");
2748824a1566SKashyap Desai 		retval = -EINVAL;
2749824a1566SKashyap Desai 		goto out_failed;
2750824a1566SKashyap Desai 	}
2751824a1566SKashyap Desai 
2752824a1566SKashyap Desai 	pci_read_config_word(pdev, capb + 2, &message_control);
2753824a1566SKashyap Desai 	mrioc->msix_count = (message_control & 0x3FF) + 1;
2754824a1566SKashyap Desai 
2755824a1566SKashyap Desai 	pci_save_state(pdev);
2756824a1566SKashyap Desai 
2757824a1566SKashyap Desai 	pci_set_drvdata(pdev, mrioc->shost);
2758824a1566SKashyap Desai 
2759824a1566SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
2760824a1566SKashyap Desai 
2761824a1566SKashyap Desai 	ioc_info(mrioc, "iomem(0x%016llx), mapped(0x%p), size(%d)\n",
2762824a1566SKashyap Desai 	    (unsigned long long)mrioc->sysif_regs_phys,
2763824a1566SKashyap Desai 	    mrioc->sysif_regs, memap_sz);
2764824a1566SKashyap Desai 	ioc_info(mrioc, "Number of MSI-X vectors found in capabilities: (%d)\n",
2765824a1566SKashyap Desai 	    mrioc->msix_count);
2766824a1566SKashyap Desai 	return retval;
2767824a1566SKashyap Desai 
2768824a1566SKashyap Desai out_failed:
2769824a1566SKashyap Desai 	mpi3mr_cleanup_resources(mrioc);
2770824a1566SKashyap Desai 	return retval;
2771824a1566SKashyap Desai }
2772824a1566SKashyap Desai 
2773824a1566SKashyap Desai /**
2774824a1566SKashyap Desai  * mpi3mr_init_ioc - Initialize the controller
2775824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2776fb9b0457SKashyap Desai  * @re_init: Flag to indicate is this fresh init or re-init
2777824a1566SKashyap Desai  *
2778824a1566SKashyap Desai  * This the controller initialization routine, executed either
2779824a1566SKashyap Desai  * after soft reset or from pci probe callback.
2780824a1566SKashyap Desai  * Setup the required resources, memory map the controller
2781824a1566SKashyap Desai  * registers, create admin and operational reply queue pairs,
2782824a1566SKashyap Desai  * allocate required memory for reply pool, sense buffer pool,
2783824a1566SKashyap Desai  * issue IOC init request to the firmware, unmask the events and
2784824a1566SKashyap Desai  * issue port enable to discover SAS/SATA/NVMe devies and RAID
2785824a1566SKashyap Desai  * volumes.
2786824a1566SKashyap Desai  *
2787824a1566SKashyap Desai  * Return: 0 on success and non-zero on failure.
2788824a1566SKashyap Desai  */
2789fb9b0457SKashyap Desai int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc, u8 re_init)
2790824a1566SKashyap Desai {
2791824a1566SKashyap Desai 	int retval = 0;
2792824a1566SKashyap Desai 	enum mpi3mr_iocstate ioc_state;
2793824a1566SKashyap Desai 	u64 base_info;
2794824a1566SKashyap Desai 	u32 timeout;
279513ef29eaSKashyap Desai 	u32 ioc_status, ioc_config, i;
2796824a1566SKashyap Desai 	struct mpi3_ioc_facts_data facts_data;
2797824a1566SKashyap Desai 
2798824a1566SKashyap Desai 	mrioc->change_count = 0;
2799fb9b0457SKashyap Desai 	if (!re_init) {
2800824a1566SKashyap Desai 		mrioc->cpu_count = num_online_cpus();
2801824a1566SKashyap Desai 		retval = mpi3mr_setup_resources(mrioc);
2802824a1566SKashyap Desai 		if (retval) {
2803824a1566SKashyap Desai 			ioc_err(mrioc, "Failed to setup resources:error %d\n",
2804824a1566SKashyap Desai 			    retval);
2805824a1566SKashyap Desai 			goto out_nocleanup;
2806824a1566SKashyap Desai 		}
2807fb9b0457SKashyap Desai 	}
2808fb9b0457SKashyap Desai 
2809824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
2810824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
2811824a1566SKashyap Desai 
2812824a1566SKashyap Desai 	ioc_info(mrioc, "SOD status %x configuration %x\n",
2813824a1566SKashyap Desai 	    ioc_status, ioc_config);
2814824a1566SKashyap Desai 
2815824a1566SKashyap Desai 	base_info = lo_hi_readq(&mrioc->sysif_regs->ioc_information);
2816824a1566SKashyap Desai 	ioc_info(mrioc, "SOD base_info %llx\n",	base_info);
2817824a1566SKashyap Desai 
2818824a1566SKashyap Desai 	/*The timeout value is in 2sec unit, changing it to seconds*/
2819824a1566SKashyap Desai 	mrioc->ready_timeout =
2820824a1566SKashyap Desai 	    ((base_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >>
2821824a1566SKashyap Desai 	    MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT) * 2;
2822824a1566SKashyap Desai 
2823824a1566SKashyap Desai 	ioc_info(mrioc, "IOC ready timeout %d\n", mrioc->ready_timeout);
2824824a1566SKashyap Desai 
2825824a1566SKashyap Desai 	ioc_state = mpi3mr_get_iocstate(mrioc);
2826824a1566SKashyap Desai 	ioc_info(mrioc, "IOC in %s state during detection\n",
2827824a1566SKashyap Desai 	    mpi3mr_iocstate_name(ioc_state));
2828824a1566SKashyap Desai 
2829824a1566SKashyap Desai 	if (ioc_state == MRIOC_STATE_BECOMING_READY ||
2830824a1566SKashyap Desai 	    ioc_state == MRIOC_STATE_RESET_REQUESTED) {
2831824a1566SKashyap Desai 		timeout = mrioc->ready_timeout * 10;
2832824a1566SKashyap Desai 		do {
2833824a1566SKashyap Desai 			msleep(100);
2834824a1566SKashyap Desai 		} while (--timeout);
2835824a1566SKashyap Desai 
2836824a1566SKashyap Desai 		ioc_state = mpi3mr_get_iocstate(mrioc);
2837824a1566SKashyap Desai 		ioc_info(mrioc,
2838824a1566SKashyap Desai 		    "IOC in %s state after waiting for reset time\n",
2839824a1566SKashyap Desai 		    mpi3mr_iocstate_name(ioc_state));
2840824a1566SKashyap Desai 	}
2841824a1566SKashyap Desai 
2842824a1566SKashyap Desai 	if (ioc_state == MRIOC_STATE_READY) {
2843824a1566SKashyap Desai 		retval = mpi3mr_issue_and_process_mur(mrioc,
2844824a1566SKashyap Desai 		    MPI3MR_RESET_FROM_BRINGUP);
2845824a1566SKashyap Desai 		if (retval) {
2846824a1566SKashyap Desai 			ioc_err(mrioc, "Failed to MU reset IOC error %d\n",
2847824a1566SKashyap Desai 			    retval);
2848824a1566SKashyap Desai 		}
2849824a1566SKashyap Desai 		ioc_state = mpi3mr_get_iocstate(mrioc);
2850824a1566SKashyap Desai 	}
2851824a1566SKashyap Desai 	if (ioc_state != MRIOC_STATE_RESET) {
2852824a1566SKashyap Desai 		mpi3mr_print_fault_info(mrioc);
2853824a1566SKashyap Desai 		retval = mpi3mr_issue_reset(mrioc,
2854824a1566SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
2855824a1566SKashyap Desai 		    MPI3MR_RESET_FROM_BRINGUP);
2856824a1566SKashyap Desai 		if (retval) {
2857824a1566SKashyap Desai 			ioc_err(mrioc,
2858824a1566SKashyap Desai 			    "%s :Failed to soft reset IOC error %d\n",
2859824a1566SKashyap Desai 			    __func__, retval);
2860824a1566SKashyap Desai 			goto out_failed;
2861824a1566SKashyap Desai 		}
2862824a1566SKashyap Desai 	}
2863824a1566SKashyap Desai 	ioc_state = mpi3mr_get_iocstate(mrioc);
2864824a1566SKashyap Desai 	if (ioc_state != MRIOC_STATE_RESET) {
2865824a1566SKashyap Desai 		ioc_err(mrioc, "Cannot bring IOC to reset state\n");
2866824a1566SKashyap Desai 		goto out_failed;
2867824a1566SKashyap Desai 	}
2868824a1566SKashyap Desai 
2869824a1566SKashyap Desai 	retval = mpi3mr_setup_admin_qpair(mrioc);
2870824a1566SKashyap Desai 	if (retval) {
2871824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to setup admin Qs: error %d\n",
2872824a1566SKashyap Desai 		    retval);
2873824a1566SKashyap Desai 		goto out_failed;
2874824a1566SKashyap Desai 	}
2875824a1566SKashyap Desai 
2876824a1566SKashyap Desai 	retval = mpi3mr_bring_ioc_ready(mrioc);
2877824a1566SKashyap Desai 	if (retval) {
2878824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to bring ioc ready: error %d\n",
2879824a1566SKashyap Desai 		    retval);
2880824a1566SKashyap Desai 		goto out_failed;
2881824a1566SKashyap Desai 	}
2882824a1566SKashyap Desai 
2883fb9b0457SKashyap Desai 	if (!re_init) {
2884824a1566SKashyap Desai 		retval = mpi3mr_setup_isr(mrioc, 1);
2885824a1566SKashyap Desai 		if (retval) {
2886824a1566SKashyap Desai 			ioc_err(mrioc, "Failed to setup ISR error %d\n",
2887824a1566SKashyap Desai 			    retval);
2888824a1566SKashyap Desai 			goto out_failed;
2889824a1566SKashyap Desai 		}
2890fb9b0457SKashyap Desai 	} else
2891fb9b0457SKashyap Desai 		mpi3mr_ioc_enable_intr(mrioc);
2892824a1566SKashyap Desai 
2893824a1566SKashyap Desai 	retval = mpi3mr_issue_iocfacts(mrioc, &facts_data);
2894824a1566SKashyap Desai 	if (retval) {
2895824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to Issue IOC Facts %d\n",
2896824a1566SKashyap Desai 		    retval);
2897824a1566SKashyap Desai 		goto out_failed;
2898824a1566SKashyap Desai 	}
2899824a1566SKashyap Desai 
2900824a1566SKashyap Desai 	mpi3mr_process_factsdata(mrioc, &facts_data);
2901fb9b0457SKashyap Desai 	if (!re_init) {
2902824a1566SKashyap Desai 		retval = mpi3mr_check_reset_dma_mask(mrioc);
2903824a1566SKashyap Desai 		if (retval) {
2904824a1566SKashyap Desai 			ioc_err(mrioc, "Resetting dma mask failed %d\n",
2905824a1566SKashyap Desai 			    retval);
2906824a1566SKashyap Desai 			goto out_failed;
2907824a1566SKashyap Desai 		}
2908fb9b0457SKashyap Desai 	}
2909824a1566SKashyap Desai 
2910ff9561e9SKashyap Desai 	mpi3mr_print_ioc_info(mrioc);
2911ff9561e9SKashyap Desai 
2912824a1566SKashyap Desai 	retval = mpi3mr_alloc_reply_sense_bufs(mrioc);
2913824a1566SKashyap Desai 	if (retval) {
2914824a1566SKashyap Desai 		ioc_err(mrioc,
2915824a1566SKashyap Desai 		    "%s :Failed to allocated reply sense buffers %d\n",
2916824a1566SKashyap Desai 		    __func__, retval);
2917824a1566SKashyap Desai 		goto out_failed;
2918824a1566SKashyap Desai 	}
2919824a1566SKashyap Desai 
2920fb9b0457SKashyap Desai 	if (!re_init) {
2921824a1566SKashyap Desai 		retval = mpi3mr_alloc_chain_bufs(mrioc);
2922824a1566SKashyap Desai 		if (retval) {
2923824a1566SKashyap Desai 			ioc_err(mrioc, "Failed to allocated chain buffers %d\n",
2924824a1566SKashyap Desai 			    retval);
2925824a1566SKashyap Desai 			goto out_failed;
2926824a1566SKashyap Desai 		}
2927fb9b0457SKashyap Desai 	}
2928824a1566SKashyap Desai 
2929824a1566SKashyap Desai 	retval = mpi3mr_issue_iocinit(mrioc);
2930824a1566SKashyap Desai 	if (retval) {
2931824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to Issue IOC Init %d\n",
2932824a1566SKashyap Desai 		    retval);
2933824a1566SKashyap Desai 		goto out_failed;
2934824a1566SKashyap Desai 	}
2935824a1566SKashyap Desai 	mrioc->reply_free_queue_host_index = mrioc->num_reply_bufs;
2936824a1566SKashyap Desai 	writel(mrioc->reply_free_queue_host_index,
2937824a1566SKashyap Desai 	    &mrioc->sysif_regs->reply_free_host_index);
2938824a1566SKashyap Desai 
2939824a1566SKashyap Desai 	mrioc->sbq_host_index = mrioc->num_sense_bufs;
2940824a1566SKashyap Desai 	writel(mrioc->sbq_host_index,
2941824a1566SKashyap Desai 	    &mrioc->sysif_regs->sense_buffer_free_host_index);
2942824a1566SKashyap Desai 
2943fb9b0457SKashyap Desai 	if (!re_init)  {
2944824a1566SKashyap Desai 		retval = mpi3mr_setup_isr(mrioc, 0);
2945824a1566SKashyap Desai 		if (retval) {
2946824a1566SKashyap Desai 			ioc_err(mrioc, "Failed to re-setup ISR, error %d\n",
2947824a1566SKashyap Desai 			    retval);
2948824a1566SKashyap Desai 			goto out_failed;
2949824a1566SKashyap Desai 		}
2950fb9b0457SKashyap Desai 	}
2951824a1566SKashyap Desai 
2952c9566231SKashyap Desai 	retval = mpi3mr_create_op_queues(mrioc);
2953c9566231SKashyap Desai 	if (retval) {
2954c9566231SKashyap Desai 		ioc_err(mrioc, "Failed to create OpQueues error %d\n",
2955c9566231SKashyap Desai 		    retval);
2956c9566231SKashyap Desai 		goto out_failed;
2957c9566231SKashyap Desai 	}
2958c9566231SKashyap Desai 
2959fb9b0457SKashyap Desai 	if (re_init &&
2960fb9b0457SKashyap Desai 	    (mrioc->shost->nr_hw_queues > mrioc->num_op_reply_q)) {
2961fb9b0457SKashyap Desai 		ioc_err(mrioc,
2962fb9b0457SKashyap Desai 		    "Cannot create minimum number of OpQueues expected:%d created:%d\n",
2963fb9b0457SKashyap Desai 		    mrioc->shost->nr_hw_queues, mrioc->num_op_reply_q);
2964fb9b0457SKashyap Desai 		goto out_failed;
2965fb9b0457SKashyap Desai 	}
2966fb9b0457SKashyap Desai 
296713ef29eaSKashyap Desai 	for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
296813ef29eaSKashyap Desai 		mrioc->event_masks[i] = -1;
296913ef29eaSKashyap Desai 
297013ef29eaSKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_ADDED);
297113ef29eaSKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_INFO_CHANGED);
297213ef29eaSKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_STATUS_CHANGE);
297313ef29eaSKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE);
297413ef29eaSKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
297513ef29eaSKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DISCOVERY);
297613ef29eaSKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR);
2977e36710dcSKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_BROADCAST_PRIMITIVE);
29788e653455SKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST);
29798e653455SKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_ENUMERATION);
2980e36710dcSKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_CABLE_MGMT);
2981e36710dcSKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENERGY_PACK_CHANGE);
298213ef29eaSKashyap Desai 
298313ef29eaSKashyap Desai 	retval = mpi3mr_issue_event_notification(mrioc);
298413ef29eaSKashyap Desai 	if (retval) {
298513ef29eaSKashyap Desai 		ioc_err(mrioc, "Failed to issue event notification %d\n",
298613ef29eaSKashyap Desai 		    retval);
298713ef29eaSKashyap Desai 		goto out_failed;
298813ef29eaSKashyap Desai 	}
298913ef29eaSKashyap Desai 
2990fb9b0457SKashyap Desai 	if (re_init) {
2991fb9b0457SKashyap Desai 		ioc_info(mrioc, "Issuing Port Enable\n");
2992fb9b0457SKashyap Desai 		retval = mpi3mr_issue_port_enable(mrioc, 0);
2993fb9b0457SKashyap Desai 		if (retval) {
2994fb9b0457SKashyap Desai 			ioc_err(mrioc, "Failed to issue port enable %d\n",
2995fb9b0457SKashyap Desai 			    retval);
2996fb9b0457SKashyap Desai 			goto out_failed;
2997fb9b0457SKashyap Desai 		}
2998fb9b0457SKashyap Desai 	}
2999824a1566SKashyap Desai 	return retval;
3000824a1566SKashyap Desai 
3001824a1566SKashyap Desai out_failed:
3002fb9b0457SKashyap Desai 	mpi3mr_cleanup_ioc(mrioc, re_init);
3003824a1566SKashyap Desai out_nocleanup:
3004824a1566SKashyap Desai 	return retval;
3005824a1566SKashyap Desai }
3006824a1566SKashyap Desai 
3007824a1566SKashyap Desai /**
3008fb9b0457SKashyap Desai  * mpi3mr_memset_op_reply_q_buffers - memset the operational reply queue's
3009fb9b0457SKashyap Desai  *					segments
3010fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
3011fb9b0457SKashyap Desai  * @qidx: Operational reply queue index
3012fb9b0457SKashyap Desai  *
3013fb9b0457SKashyap Desai  * Return: Nothing.
3014fb9b0457SKashyap Desai  */
3015fb9b0457SKashyap Desai static void mpi3mr_memset_op_reply_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx)
3016fb9b0457SKashyap Desai {
3017fb9b0457SKashyap Desai 	struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
3018fb9b0457SKashyap Desai 	struct segments *segments;
3019fb9b0457SKashyap Desai 	int i, size;
3020fb9b0457SKashyap Desai 
3021fb9b0457SKashyap Desai 	if (!op_reply_q->q_segments)
3022fb9b0457SKashyap Desai 		return;
3023fb9b0457SKashyap Desai 
3024fb9b0457SKashyap Desai 	size = op_reply_q->segment_qd * mrioc->op_reply_desc_sz;
3025fb9b0457SKashyap Desai 	segments = op_reply_q->q_segments;
3026fb9b0457SKashyap Desai 	for (i = 0; i < op_reply_q->num_segments; i++)
3027fb9b0457SKashyap Desai 		memset(segments[i].segment, 0, size);
3028fb9b0457SKashyap Desai }
3029fb9b0457SKashyap Desai 
3030fb9b0457SKashyap Desai /**
3031fb9b0457SKashyap Desai  * mpi3mr_memset_op_req_q_buffers - memset the operational request queue's
3032fb9b0457SKashyap Desai  *					segments
3033fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
3034fb9b0457SKashyap Desai  * @qidx: Operational request queue index
3035fb9b0457SKashyap Desai  *
3036fb9b0457SKashyap Desai  * Return: Nothing.
3037fb9b0457SKashyap Desai  */
3038fb9b0457SKashyap Desai static void mpi3mr_memset_op_req_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx)
3039fb9b0457SKashyap Desai {
3040fb9b0457SKashyap Desai 	struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx;
3041fb9b0457SKashyap Desai 	struct segments *segments;
3042fb9b0457SKashyap Desai 	int i, size;
3043fb9b0457SKashyap Desai 
3044fb9b0457SKashyap Desai 	if (!op_req_q->q_segments)
3045fb9b0457SKashyap Desai 		return;
3046fb9b0457SKashyap Desai 
3047fb9b0457SKashyap Desai 	size = op_req_q->segment_qd * mrioc->facts.op_req_sz;
3048fb9b0457SKashyap Desai 	segments = op_req_q->q_segments;
3049fb9b0457SKashyap Desai 	for (i = 0; i < op_req_q->num_segments; i++)
3050fb9b0457SKashyap Desai 		memset(segments[i].segment, 0, size);
3051fb9b0457SKashyap Desai }
3052fb9b0457SKashyap Desai 
3053fb9b0457SKashyap Desai /**
3054fb9b0457SKashyap Desai  * mpi3mr_memset_buffers - memset memory for a controller
3055fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
3056fb9b0457SKashyap Desai  *
3057fb9b0457SKashyap Desai  * clear all the memory allocated for a controller, typically
3058fb9b0457SKashyap Desai  * called post reset to reuse the memory allocated during the
3059fb9b0457SKashyap Desai  * controller init.
3060fb9b0457SKashyap Desai  *
3061fb9b0457SKashyap Desai  * Return: Nothing.
3062fb9b0457SKashyap Desai  */
3063fb9b0457SKashyap Desai static void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc)
3064fb9b0457SKashyap Desai {
3065fb9b0457SKashyap Desai 	u16 i;
3066fb9b0457SKashyap Desai 
3067fb9b0457SKashyap Desai 	memset(mrioc->admin_req_base, 0, mrioc->admin_req_q_sz);
3068fb9b0457SKashyap Desai 	memset(mrioc->admin_reply_base, 0, mrioc->admin_reply_q_sz);
3069fb9b0457SKashyap Desai 
3070fb9b0457SKashyap Desai 	memset(mrioc->init_cmds.reply, 0, sizeof(*mrioc->init_cmds.reply));
3071*e844adb1SKashyap Desai 	memset(mrioc->host_tm_cmds.reply, 0,
3072*e844adb1SKashyap Desai 	    sizeof(*mrioc->host_tm_cmds.reply));
3073fb9b0457SKashyap Desai 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++)
3074fb9b0457SKashyap Desai 		memset(mrioc->dev_rmhs_cmds[i].reply, 0,
3075fb9b0457SKashyap Desai 		    sizeof(*mrioc->dev_rmhs_cmds[i].reply));
3076fb9b0457SKashyap Desai 	memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz);
3077fb9b0457SKashyap Desai 	memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz);
3078fb9b0457SKashyap Desai 
3079fb9b0457SKashyap Desai 	for (i = 0; i < mrioc->num_queues; i++) {
3080fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].qid = 0;
3081fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].ci = 0;
3082fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].num_replies = 0;
3083fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].ephase = 0;
3084fb9b0457SKashyap Desai 		mpi3mr_memset_op_reply_q_buffers(mrioc, i);
3085fb9b0457SKashyap Desai 
3086fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].ci = 0;
3087fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].pi = 0;
3088fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].num_requests = 0;
3089fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].qid = 0;
3090fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].reply_qid = 0;
3091fb9b0457SKashyap Desai 		spin_lock_init(&mrioc->req_qinfo[i].q_lock);
3092fb9b0457SKashyap Desai 		mpi3mr_memset_op_req_q_buffers(mrioc, i);
3093fb9b0457SKashyap Desai 	}
3094fb9b0457SKashyap Desai }
3095fb9b0457SKashyap Desai 
3096fb9b0457SKashyap Desai /**
3097824a1566SKashyap Desai  * mpi3mr_free_mem - Free memory allocated for a controller
3098824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3099824a1566SKashyap Desai  *
3100824a1566SKashyap Desai  * Free all the memory allocated for a controller.
3101824a1566SKashyap Desai  *
3102824a1566SKashyap Desai  * Return: Nothing.
3103824a1566SKashyap Desai  */
3104824a1566SKashyap Desai static void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc)
3105824a1566SKashyap Desai {
3106824a1566SKashyap Desai 	u16 i;
3107824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info;
3108824a1566SKashyap Desai 
3109824a1566SKashyap Desai 	if (mrioc->sense_buf_pool) {
3110824a1566SKashyap Desai 		if (mrioc->sense_buf)
3111824a1566SKashyap Desai 			dma_pool_free(mrioc->sense_buf_pool, mrioc->sense_buf,
3112824a1566SKashyap Desai 			    mrioc->sense_buf_dma);
3113824a1566SKashyap Desai 		dma_pool_destroy(mrioc->sense_buf_pool);
3114824a1566SKashyap Desai 		mrioc->sense_buf = NULL;
3115824a1566SKashyap Desai 		mrioc->sense_buf_pool = NULL;
3116824a1566SKashyap Desai 	}
3117824a1566SKashyap Desai 	if (mrioc->sense_buf_q_pool) {
3118824a1566SKashyap Desai 		if (mrioc->sense_buf_q)
3119824a1566SKashyap Desai 			dma_pool_free(mrioc->sense_buf_q_pool,
3120824a1566SKashyap Desai 			    mrioc->sense_buf_q, mrioc->sense_buf_q_dma);
3121824a1566SKashyap Desai 		dma_pool_destroy(mrioc->sense_buf_q_pool);
3122824a1566SKashyap Desai 		mrioc->sense_buf_q = NULL;
3123824a1566SKashyap Desai 		mrioc->sense_buf_q_pool = NULL;
3124824a1566SKashyap Desai 	}
3125824a1566SKashyap Desai 
3126824a1566SKashyap Desai 	if (mrioc->reply_buf_pool) {
3127824a1566SKashyap Desai 		if (mrioc->reply_buf)
3128824a1566SKashyap Desai 			dma_pool_free(mrioc->reply_buf_pool, mrioc->reply_buf,
3129824a1566SKashyap Desai 			    mrioc->reply_buf_dma);
3130824a1566SKashyap Desai 		dma_pool_destroy(mrioc->reply_buf_pool);
3131824a1566SKashyap Desai 		mrioc->reply_buf = NULL;
3132824a1566SKashyap Desai 		mrioc->reply_buf_pool = NULL;
3133824a1566SKashyap Desai 	}
3134824a1566SKashyap Desai 	if (mrioc->reply_free_q_pool) {
3135824a1566SKashyap Desai 		if (mrioc->reply_free_q)
3136824a1566SKashyap Desai 			dma_pool_free(mrioc->reply_free_q_pool,
3137824a1566SKashyap Desai 			    mrioc->reply_free_q, mrioc->reply_free_q_dma);
3138824a1566SKashyap Desai 		dma_pool_destroy(mrioc->reply_free_q_pool);
3139824a1566SKashyap Desai 		mrioc->reply_free_q = NULL;
3140824a1566SKashyap Desai 		mrioc->reply_free_q_pool = NULL;
3141824a1566SKashyap Desai 	}
3142824a1566SKashyap Desai 
3143c9566231SKashyap Desai 	for (i = 0; i < mrioc->num_op_req_q; i++)
3144c9566231SKashyap Desai 		mpi3mr_free_op_req_q_segments(mrioc, i);
3145c9566231SKashyap Desai 
3146c9566231SKashyap Desai 	for (i = 0; i < mrioc->num_op_reply_q; i++)
3147c9566231SKashyap Desai 		mpi3mr_free_op_reply_q_segments(mrioc, i);
3148c9566231SKashyap Desai 
3149824a1566SKashyap Desai 	for (i = 0; i < mrioc->intr_info_count; i++) {
3150824a1566SKashyap Desai 		intr_info = mrioc->intr_info + i;
3151824a1566SKashyap Desai 		if (intr_info)
3152824a1566SKashyap Desai 			intr_info->op_reply_q = NULL;
3153824a1566SKashyap Desai 	}
3154824a1566SKashyap Desai 
3155824a1566SKashyap Desai 	kfree(mrioc->req_qinfo);
3156824a1566SKashyap Desai 	mrioc->req_qinfo = NULL;
3157824a1566SKashyap Desai 	mrioc->num_op_req_q = 0;
3158824a1566SKashyap Desai 
3159824a1566SKashyap Desai 	kfree(mrioc->op_reply_qinfo);
3160824a1566SKashyap Desai 	mrioc->op_reply_qinfo = NULL;
3161824a1566SKashyap Desai 	mrioc->num_op_reply_q = 0;
3162824a1566SKashyap Desai 
3163824a1566SKashyap Desai 	kfree(mrioc->init_cmds.reply);
3164824a1566SKashyap Desai 	mrioc->init_cmds.reply = NULL;
3165824a1566SKashyap Desai 
3166*e844adb1SKashyap Desai 	kfree(mrioc->host_tm_cmds.reply);
3167*e844adb1SKashyap Desai 	mrioc->host_tm_cmds.reply = NULL;
3168*e844adb1SKashyap Desai 
3169*e844adb1SKashyap Desai 	kfree(mrioc->removepend_bitmap);
3170*e844adb1SKashyap Desai 	mrioc->removepend_bitmap = NULL;
3171*e844adb1SKashyap Desai 
3172*e844adb1SKashyap Desai 	kfree(mrioc->devrem_bitmap);
3173*e844adb1SKashyap Desai 	mrioc->devrem_bitmap = NULL;
3174*e844adb1SKashyap Desai 
3175824a1566SKashyap Desai 	kfree(mrioc->chain_bitmap);
3176824a1566SKashyap Desai 	mrioc->chain_bitmap = NULL;
3177824a1566SKashyap Desai 
317813ef29eaSKashyap Desai 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
317913ef29eaSKashyap Desai 		kfree(mrioc->dev_rmhs_cmds[i].reply);
318013ef29eaSKashyap Desai 		mrioc->dev_rmhs_cmds[i].reply = NULL;
318113ef29eaSKashyap Desai 	}
318213ef29eaSKashyap Desai 
3183824a1566SKashyap Desai 	if (mrioc->chain_buf_pool) {
3184824a1566SKashyap Desai 		for (i = 0; i < mrioc->chain_buf_count; i++) {
3185824a1566SKashyap Desai 			if (mrioc->chain_sgl_list[i].addr) {
3186824a1566SKashyap Desai 				dma_pool_free(mrioc->chain_buf_pool,
3187824a1566SKashyap Desai 				    mrioc->chain_sgl_list[i].addr,
3188824a1566SKashyap Desai 				    mrioc->chain_sgl_list[i].dma_addr);
3189824a1566SKashyap Desai 				mrioc->chain_sgl_list[i].addr = NULL;
3190824a1566SKashyap Desai 			}
3191824a1566SKashyap Desai 		}
3192824a1566SKashyap Desai 		dma_pool_destroy(mrioc->chain_buf_pool);
3193824a1566SKashyap Desai 		mrioc->chain_buf_pool = NULL;
3194824a1566SKashyap Desai 	}
3195824a1566SKashyap Desai 
3196824a1566SKashyap Desai 	kfree(mrioc->chain_sgl_list);
3197824a1566SKashyap Desai 	mrioc->chain_sgl_list = NULL;
3198824a1566SKashyap Desai 
3199824a1566SKashyap Desai 	if (mrioc->admin_reply_base) {
3200824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz,
3201824a1566SKashyap Desai 		    mrioc->admin_reply_base, mrioc->admin_reply_dma);
3202824a1566SKashyap Desai 		mrioc->admin_reply_base = NULL;
3203824a1566SKashyap Desai 	}
3204824a1566SKashyap Desai 	if (mrioc->admin_req_base) {
3205824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz,
3206824a1566SKashyap Desai 		    mrioc->admin_req_base, mrioc->admin_req_dma);
3207824a1566SKashyap Desai 		mrioc->admin_req_base = NULL;
3208824a1566SKashyap Desai 	}
3209824a1566SKashyap Desai }
3210824a1566SKashyap Desai 
3211824a1566SKashyap Desai /**
3212824a1566SKashyap Desai  * mpi3mr_issue_ioc_shutdown - shutdown controller
3213824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3214824a1566SKashyap Desai  *
3215824a1566SKashyap Desai  * Send shutodwn notification to the controller and wait for the
3216824a1566SKashyap Desai  * shutdown_timeout for it to be completed.
3217824a1566SKashyap Desai  *
3218824a1566SKashyap Desai  * Return: Nothing.
3219824a1566SKashyap Desai  */
3220824a1566SKashyap Desai static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc)
3221824a1566SKashyap Desai {
3222824a1566SKashyap Desai 	u32 ioc_config, ioc_status;
3223824a1566SKashyap Desai 	u8 retval = 1;
3224824a1566SKashyap Desai 	u32 timeout = MPI3MR_DEFAULT_SHUTDOWN_TIME * 10;
3225824a1566SKashyap Desai 
3226824a1566SKashyap Desai 	ioc_info(mrioc, "Issuing shutdown Notification\n");
3227824a1566SKashyap Desai 	if (mrioc->unrecoverable) {
3228824a1566SKashyap Desai 		ioc_warn(mrioc,
3229824a1566SKashyap Desai 		    "IOC is unrecoverable shutdown is not issued\n");
3230824a1566SKashyap Desai 		return;
3231824a1566SKashyap Desai 	}
3232824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
3233824a1566SKashyap Desai 	if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
3234824a1566SKashyap Desai 	    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS) {
3235824a1566SKashyap Desai 		ioc_info(mrioc, "shutdown already in progress\n");
3236824a1566SKashyap Desai 		return;
3237824a1566SKashyap Desai 	}
3238824a1566SKashyap Desai 
3239824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
3240824a1566SKashyap Desai 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL;
3241824a1566SKashyap Desai 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN;
3242824a1566SKashyap Desai 
3243824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
3244824a1566SKashyap Desai 
3245824a1566SKashyap Desai 	if (mrioc->facts.shutdown_timeout)
3246824a1566SKashyap Desai 		timeout = mrioc->facts.shutdown_timeout * 10;
3247824a1566SKashyap Desai 
3248824a1566SKashyap Desai 	do {
3249824a1566SKashyap Desai 		ioc_status = readl(&mrioc->sysif_regs->ioc_status);
3250824a1566SKashyap Desai 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
3251824a1566SKashyap Desai 		    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_COMPLETE) {
3252824a1566SKashyap Desai 			retval = 0;
3253824a1566SKashyap Desai 			break;
3254824a1566SKashyap Desai 		}
3255824a1566SKashyap Desai 		msleep(100);
3256824a1566SKashyap Desai 	} while (--timeout);
3257824a1566SKashyap Desai 
3258824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
3259824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
3260824a1566SKashyap Desai 
3261824a1566SKashyap Desai 	if (retval) {
3262824a1566SKashyap Desai 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
3263824a1566SKashyap Desai 		    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS)
3264824a1566SKashyap Desai 			ioc_warn(mrioc,
3265824a1566SKashyap Desai 			    "shutdown still in progress after timeout\n");
3266824a1566SKashyap Desai 	}
3267824a1566SKashyap Desai 
3268824a1566SKashyap Desai 	ioc_info(mrioc,
3269824a1566SKashyap Desai 	    "Base IOC Sts/Config after %s shutdown is (0x%x)/(0x%x)\n",
3270824a1566SKashyap Desai 	    (!retval) ? "successful" : "failed", ioc_status,
3271824a1566SKashyap Desai 	    ioc_config);
3272824a1566SKashyap Desai }
3273824a1566SKashyap Desai 
3274824a1566SKashyap Desai /**
3275824a1566SKashyap Desai  * mpi3mr_cleanup_ioc - Cleanup controller
3276824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3277fb9b0457SKashyap Desai  * @re_init: Cleanup due to a reinit or not
3278824a1566SKashyap Desai  *
3279824a1566SKashyap Desai  * controller cleanup handler, Message unit reset or soft reset
3280824a1566SKashyap Desai  * and shutdown notification is issued to the controller and the
3281824a1566SKashyap Desai  * associated memory resources are freed.
3282824a1566SKashyap Desai  *
3283824a1566SKashyap Desai  * Return: Nothing.
3284824a1566SKashyap Desai  */
3285fb9b0457SKashyap Desai void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc, u8 re_init)
3286824a1566SKashyap Desai {
3287824a1566SKashyap Desai 	enum mpi3mr_iocstate ioc_state;
3288824a1566SKashyap Desai 
3289fb9b0457SKashyap Desai 	if (!re_init)
3290672ae26cSKashyap Desai 		mpi3mr_stop_watchdog(mrioc);
3291672ae26cSKashyap Desai 
3292824a1566SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
3293824a1566SKashyap Desai 
3294824a1566SKashyap Desai 	ioc_state = mpi3mr_get_iocstate(mrioc);
3295824a1566SKashyap Desai 
3296824a1566SKashyap Desai 	if ((!mrioc->unrecoverable) && (!mrioc->reset_in_progress) &&
3297824a1566SKashyap Desai 	    (ioc_state == MRIOC_STATE_READY)) {
3298824a1566SKashyap Desai 		if (mpi3mr_issue_and_process_mur(mrioc,
3299824a1566SKashyap Desai 		    MPI3MR_RESET_FROM_CTLR_CLEANUP))
3300824a1566SKashyap Desai 			mpi3mr_issue_reset(mrioc,
3301824a1566SKashyap Desai 			    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
3302824a1566SKashyap Desai 			    MPI3MR_RESET_FROM_MUR_FAILURE);
3303824a1566SKashyap Desai 
3304fb9b0457SKashyap Desai 		if (!re_init)
3305824a1566SKashyap Desai 			mpi3mr_issue_ioc_shutdown(mrioc);
3306824a1566SKashyap Desai 	}
3307824a1566SKashyap Desai 
3308fb9b0457SKashyap Desai 	if (!re_init) {
3309824a1566SKashyap Desai 		mpi3mr_free_mem(mrioc);
3310824a1566SKashyap Desai 		mpi3mr_cleanup_resources(mrioc);
3311824a1566SKashyap Desai 	}
3312fb9b0457SKashyap Desai }
3313fb9b0457SKashyap Desai 
3314fb9b0457SKashyap Desai /**
3315fb9b0457SKashyap Desai  * mpi3mr_drv_cmd_comp_reset - Flush a internal driver command
3316fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
3317fb9b0457SKashyap Desai  * @cmdptr: Internal command tracker
3318fb9b0457SKashyap Desai  *
3319fb9b0457SKashyap Desai  * Complete an internal driver commands with state indicating it
3320fb9b0457SKashyap Desai  * is completed due to reset.
3321fb9b0457SKashyap Desai  *
3322fb9b0457SKashyap Desai  * Return: Nothing.
3323fb9b0457SKashyap Desai  */
3324fb9b0457SKashyap Desai static inline void mpi3mr_drv_cmd_comp_reset(struct mpi3mr_ioc *mrioc,
3325fb9b0457SKashyap Desai 	struct mpi3mr_drv_cmd *cmdptr)
3326fb9b0457SKashyap Desai {
3327fb9b0457SKashyap Desai 	if (cmdptr->state & MPI3MR_CMD_PENDING) {
3328fb9b0457SKashyap Desai 		cmdptr->state |= MPI3MR_CMD_RESET;
3329fb9b0457SKashyap Desai 		cmdptr->state &= ~MPI3MR_CMD_PENDING;
3330fb9b0457SKashyap Desai 		if (cmdptr->is_waiting) {
3331fb9b0457SKashyap Desai 			complete(&cmdptr->done);
3332fb9b0457SKashyap Desai 			cmdptr->is_waiting = 0;
3333fb9b0457SKashyap Desai 		} else if (cmdptr->callback)
3334fb9b0457SKashyap Desai 			cmdptr->callback(mrioc, cmdptr);
3335fb9b0457SKashyap Desai 	}
3336fb9b0457SKashyap Desai }
3337fb9b0457SKashyap Desai 
3338fb9b0457SKashyap Desai /**
3339fb9b0457SKashyap Desai  * mpi3mr_flush_drv_cmds - Flush internaldriver commands
3340fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
3341fb9b0457SKashyap Desai  *
3342fb9b0457SKashyap Desai  * Flush all internal driver commands post reset
3343fb9b0457SKashyap Desai  *
3344fb9b0457SKashyap Desai  * Return: Nothing.
3345fb9b0457SKashyap Desai  */
3346fb9b0457SKashyap Desai static void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc)
3347fb9b0457SKashyap Desai {
3348fb9b0457SKashyap Desai 	struct mpi3mr_drv_cmd *cmdptr;
3349fb9b0457SKashyap Desai 	u8 i;
3350fb9b0457SKashyap Desai 
3351fb9b0457SKashyap Desai 	cmdptr = &mrioc->init_cmds;
3352fb9b0457SKashyap Desai 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
3353*e844adb1SKashyap Desai 	cmdptr = &mrioc->host_tm_cmds;
3354*e844adb1SKashyap Desai 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
3355fb9b0457SKashyap Desai 
3356fb9b0457SKashyap Desai 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
3357fb9b0457SKashyap Desai 		cmdptr = &mrioc->dev_rmhs_cmds[i];
3358fb9b0457SKashyap Desai 		mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
3359fb9b0457SKashyap Desai 	}
3360fb9b0457SKashyap Desai }
3361fb9b0457SKashyap Desai 
3362fb9b0457SKashyap Desai /**
3363fb9b0457SKashyap Desai  * mpi3mr_diagfault_reset_handler - Diag fault reset handler
3364fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
3365fb9b0457SKashyap Desai  * @reset_reason: Reset reason code
3366fb9b0457SKashyap Desai  *
3367fb9b0457SKashyap Desai  * This is an handler for issuing diag fault reset from the
3368fb9b0457SKashyap Desai  * applications through IOCTL path to stop the execution of the
3369fb9b0457SKashyap Desai  * controller
3370fb9b0457SKashyap Desai  *
3371fb9b0457SKashyap Desai  * Return: 0 on success, non-zero on failure.
3372fb9b0457SKashyap Desai  */
3373fb9b0457SKashyap Desai int mpi3mr_diagfault_reset_handler(struct mpi3mr_ioc *mrioc,
3374fb9b0457SKashyap Desai 	u32 reset_reason)
3375fb9b0457SKashyap Desai {
3376fb9b0457SKashyap Desai 	int retval = 0;
3377fb9b0457SKashyap Desai 
3378fb9b0457SKashyap Desai 	mrioc->reset_in_progress = 1;
3379fb9b0457SKashyap Desai 
3380fb9b0457SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
3381fb9b0457SKashyap Desai 
3382fb9b0457SKashyap Desai 	retval = mpi3mr_issue_reset(mrioc,
3383fb9b0457SKashyap Desai 	    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
3384fb9b0457SKashyap Desai 
3385fb9b0457SKashyap Desai 	if (retval) {
3386fb9b0457SKashyap Desai 		ioc_err(mrioc, "The diag fault reset failed: reason %d\n",
3387fb9b0457SKashyap Desai 		    reset_reason);
3388fb9b0457SKashyap Desai 		mpi3mr_ioc_enable_intr(mrioc);
3389fb9b0457SKashyap Desai 	}
3390fb9b0457SKashyap Desai 	ioc_info(mrioc, "%s\n", ((retval == 0) ? "SUCCESS" : "FAILED"));
3391fb9b0457SKashyap Desai 	mrioc->reset_in_progress = 0;
3392fb9b0457SKashyap Desai 	return retval;
3393fb9b0457SKashyap Desai }
3394824a1566SKashyap Desai 
3395824a1566SKashyap Desai /**
3396824a1566SKashyap Desai  * mpi3mr_soft_reset_handler - Reset the controller
3397824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3398824a1566SKashyap Desai  * @reset_reason: Reset reason code
3399824a1566SKashyap Desai  * @snapdump: Flag to generate snapdump in firmware or not
3400824a1566SKashyap Desai  *
3401fb9b0457SKashyap Desai  * This is an handler for recovering controller by issuing soft
3402fb9b0457SKashyap Desai  * reset are diag fault reset.  This is a blocking function and
3403fb9b0457SKashyap Desai  * when one reset is executed if any other resets they will be
3404fb9b0457SKashyap Desai  * blocked. All IOCTLs/IO will be blocked during the reset. If
3405fb9b0457SKashyap Desai  * controller reset is successful then the controller will be
3406fb9b0457SKashyap Desai  * reinitalized, otherwise the controller will be marked as not
3407fb9b0457SKashyap Desai  * recoverable
3408fb9b0457SKashyap Desai  *
3409fb9b0457SKashyap Desai  * In snapdump bit is set, the controller is issued with diag
3410fb9b0457SKashyap Desai  * fault reset so that the firmware can create a snap dump and
3411fb9b0457SKashyap Desai  * post that the firmware will result in F000 fault and the
3412fb9b0457SKashyap Desai  * driver will issue soft reset to recover from that.
3413824a1566SKashyap Desai  *
3414824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
3415824a1566SKashyap Desai  */
3416824a1566SKashyap Desai int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
3417824a1566SKashyap Desai 	u32 reset_reason, u8 snapdump)
3418824a1566SKashyap Desai {
3419fb9b0457SKashyap Desai 	int retval = 0, i;
3420fb9b0457SKashyap Desai 	unsigned long flags;
3421fb9b0457SKashyap Desai 	u32 host_diagnostic, timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10;
3422fb9b0457SKashyap Desai 
3423fb9b0457SKashyap Desai 	if (mrioc->fault_dbg) {
3424fb9b0457SKashyap Desai 		if (snapdump)
3425fb9b0457SKashyap Desai 			mpi3mr_set_diagsave(mrioc);
3426fb9b0457SKashyap Desai 		mpi3mr_kill_ioc(mrioc, reset_reason);
3427fb9b0457SKashyap Desai 	}
3428fb9b0457SKashyap Desai 
3429fb9b0457SKashyap Desai 	/*
3430fb9b0457SKashyap Desai 	 * Block new resets until the currently executing one is finished and
3431fb9b0457SKashyap Desai 	 * return the status of the existing reset for all blocked resets
3432fb9b0457SKashyap Desai 	 */
3433fb9b0457SKashyap Desai 	if (!mutex_trylock(&mrioc->reset_mutex)) {
3434fb9b0457SKashyap Desai 		ioc_info(mrioc, "Another reset in progress\n");
3435fb9b0457SKashyap Desai 		return -1;
3436fb9b0457SKashyap Desai 	}
3437fb9b0457SKashyap Desai 	mrioc->reset_in_progress = 1;
3438fb9b0457SKashyap Desai 
3439fb9b0457SKashyap Desai 	if ((!snapdump) && (reset_reason != MPI3MR_RESET_FROM_FAULT_WATCH) &&
3440fb9b0457SKashyap Desai 	    (reset_reason != MPI3MR_RESET_FROM_CIACTIV_FAULT)) {
3441fb9b0457SKashyap Desai 		for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
3442fb9b0457SKashyap Desai 			mrioc->event_masks[i] = -1;
3443fb9b0457SKashyap Desai 
3444fb9b0457SKashyap Desai 		retval = mpi3mr_issue_event_notification(mrioc);
3445fb9b0457SKashyap Desai 
3446fb9b0457SKashyap Desai 		if (retval) {
3447fb9b0457SKashyap Desai 			ioc_err(mrioc,
3448fb9b0457SKashyap Desai 			    "Failed to turn off events prior to reset %d\n",
3449fb9b0457SKashyap Desai 			    retval);
3450fb9b0457SKashyap Desai 		}
3451fb9b0457SKashyap Desai 	}
3452fb9b0457SKashyap Desai 
3453fb9b0457SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
3454fb9b0457SKashyap Desai 
3455fb9b0457SKashyap Desai 	if (snapdump) {
3456fb9b0457SKashyap Desai 		mpi3mr_set_diagsave(mrioc);
3457fb9b0457SKashyap Desai 		retval = mpi3mr_issue_reset(mrioc,
3458fb9b0457SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
3459fb9b0457SKashyap Desai 		if (!retval) {
3460fb9b0457SKashyap Desai 			do {
3461fb9b0457SKashyap Desai 				host_diagnostic =
3462fb9b0457SKashyap Desai 				    readl(&mrioc->sysif_regs->host_diagnostic);
3463fb9b0457SKashyap Desai 				if (!(host_diagnostic &
3464fb9b0457SKashyap Desai 				    MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS))
3465fb9b0457SKashyap Desai 					break;
3466fb9b0457SKashyap Desai 				msleep(100);
3467fb9b0457SKashyap Desai 			} while (--timeout);
3468fb9b0457SKashyap Desai 		}
3469fb9b0457SKashyap Desai 	}
3470fb9b0457SKashyap Desai 
3471fb9b0457SKashyap Desai 	retval = mpi3mr_issue_reset(mrioc,
3472fb9b0457SKashyap Desai 	    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, reset_reason);
3473fb9b0457SKashyap Desai 	if (retval) {
3474fb9b0457SKashyap Desai 		ioc_err(mrioc, "Failed to issue soft reset to the ioc\n");
3475fb9b0457SKashyap Desai 		goto out;
3476fb9b0457SKashyap Desai 	}
3477fb9b0457SKashyap Desai 
3478fb9b0457SKashyap Desai 	mpi3mr_flush_delayed_rmhs_list(mrioc);
3479fb9b0457SKashyap Desai 	mpi3mr_flush_drv_cmds(mrioc);
3480fb9b0457SKashyap Desai 	memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz);
3481fb9b0457SKashyap Desai 	memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz);
3482fb9b0457SKashyap Desai 	mpi3mr_cleanup_fwevt_list(mrioc);
3483fb9b0457SKashyap Desai 	mpi3mr_flush_host_io(mrioc);
3484fb9b0457SKashyap Desai 	mpi3mr_invalidate_devhandles(mrioc);
3485fb9b0457SKashyap Desai 	mpi3mr_memset_buffers(mrioc);
3486fb9b0457SKashyap Desai 	retval = mpi3mr_init_ioc(mrioc, 1);
3487fb9b0457SKashyap Desai 	if (retval) {
3488fb9b0457SKashyap Desai 		pr_err(IOCNAME "reinit after soft reset failed: reason %d\n",
3489fb9b0457SKashyap Desai 		    mrioc->name, reset_reason);
3490fb9b0457SKashyap Desai 		goto out;
3491fb9b0457SKashyap Desai 	}
3492fb9b0457SKashyap Desai 	ssleep(10);
3493fb9b0457SKashyap Desai 
3494fb9b0457SKashyap Desai out:
3495fb9b0457SKashyap Desai 	if (!retval) {
3496fb9b0457SKashyap Desai 		mrioc->reset_in_progress = 0;
3497fb9b0457SKashyap Desai 		scsi_unblock_requests(mrioc->shost);
3498fb9b0457SKashyap Desai 		mpi3mr_rfresh_tgtdevs(mrioc);
349954dfcffbSKashyap Desai 		mrioc->ts_update_counter = 0;
3500fb9b0457SKashyap Desai 		spin_lock_irqsave(&mrioc->watchdog_lock, flags);
3501fb9b0457SKashyap Desai 		if (mrioc->watchdog_work_q)
3502fb9b0457SKashyap Desai 			queue_delayed_work(mrioc->watchdog_work_q,
3503fb9b0457SKashyap Desai 			    &mrioc->watchdog_work,
3504fb9b0457SKashyap Desai 			    msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL));
3505fb9b0457SKashyap Desai 		spin_unlock_irqrestore(&mrioc->watchdog_lock, flags);
3506fb9b0457SKashyap Desai 	} else {
3507fb9b0457SKashyap Desai 		mpi3mr_issue_reset(mrioc,
3508fb9b0457SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
3509fb9b0457SKashyap Desai 		mrioc->unrecoverable = 1;
3510fb9b0457SKashyap Desai 		mrioc->reset_in_progress = 0;
3511fb9b0457SKashyap Desai 		retval = -1;
3512fb9b0457SKashyap Desai 	}
3513fb9b0457SKashyap Desai 
3514fb9b0457SKashyap Desai 	mutex_unlock(&mrioc->reset_mutex);
3515fb9b0457SKashyap Desai 	ioc_info(mrioc, "%s\n", ((retval == 0) ? "SUCCESS" : "FAILED"));
3516fb9b0457SKashyap Desai 	return retval;
3517824a1566SKashyap Desai }
3518