xref: /linux/drivers/scsi/mpi3mr/mpi3mr_fw.c (revision fb9b04574f147831d96b6aead161c8ca26670c97)
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;
175824a1566SKashyap Desai 	case MPI3MR_HOSTTAG_INVALID:
176824a1566SKashyap Desai 		if (def_reply && def_reply->function ==
177824a1566SKashyap Desai 		    MPI3_FUNCTION_EVENT_NOTIFICATION)
178824a1566SKashyap Desai 			mpi3mr_handle_events(mrioc, def_reply);
179824a1566SKashyap Desai 		return NULL;
180824a1566SKashyap Desai 	default:
181824a1566SKashyap Desai 		break;
182824a1566SKashyap Desai 	}
18313ef29eaSKashyap Desai 	if (host_tag >= MPI3MR_HOSTTAG_DEVRMCMD_MIN &&
18413ef29eaSKashyap Desai 	    host_tag <= MPI3MR_HOSTTAG_DEVRMCMD_MAX) {
18513ef29eaSKashyap Desai 		idx = host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
18613ef29eaSKashyap Desai 		return &mrioc->dev_rmhs_cmds[idx];
18713ef29eaSKashyap Desai 	}
188824a1566SKashyap Desai 
189824a1566SKashyap Desai 	return NULL;
190824a1566SKashyap Desai }
191824a1566SKashyap Desai 
192824a1566SKashyap Desai static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc,
193824a1566SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc, u64 *reply_dma)
194824a1566SKashyap Desai {
195824a1566SKashyap Desai 	u16 reply_desc_type, host_tag = 0;
196824a1566SKashyap Desai 	u16 ioc_status = MPI3_IOCSTATUS_SUCCESS;
197824a1566SKashyap Desai 	u32 ioc_loginfo = 0;
198824a1566SKashyap Desai 	struct mpi3_status_reply_descriptor *status_desc;
199824a1566SKashyap Desai 	struct mpi3_address_reply_descriptor *addr_desc;
200824a1566SKashyap Desai 	struct mpi3_success_reply_descriptor *success_desc;
201824a1566SKashyap Desai 	struct mpi3_default_reply *def_reply = NULL;
202824a1566SKashyap Desai 	struct mpi3mr_drv_cmd *cmdptr = NULL;
203824a1566SKashyap Desai 	struct mpi3_scsi_io_reply *scsi_reply;
204824a1566SKashyap Desai 	u8 *sense_buf = NULL;
205824a1566SKashyap Desai 
206824a1566SKashyap Desai 	*reply_dma = 0;
207824a1566SKashyap Desai 	reply_desc_type = le16_to_cpu(reply_desc->reply_flags) &
208824a1566SKashyap Desai 	    MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK;
209824a1566SKashyap Desai 	switch (reply_desc_type) {
210824a1566SKashyap Desai 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS:
211824a1566SKashyap Desai 		status_desc = (struct mpi3_status_reply_descriptor *)reply_desc;
212824a1566SKashyap Desai 		host_tag = le16_to_cpu(status_desc->host_tag);
213824a1566SKashyap Desai 		ioc_status = le16_to_cpu(status_desc->ioc_status);
214824a1566SKashyap Desai 		if (ioc_status &
215824a1566SKashyap Desai 		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
216824a1566SKashyap Desai 			ioc_loginfo = le32_to_cpu(status_desc->ioc_log_info);
217824a1566SKashyap Desai 		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
218824a1566SKashyap Desai 		break;
219824a1566SKashyap Desai 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY:
220824a1566SKashyap Desai 		addr_desc = (struct mpi3_address_reply_descriptor *)reply_desc;
221824a1566SKashyap Desai 		*reply_dma = le64_to_cpu(addr_desc->reply_frame_address);
222824a1566SKashyap Desai 		def_reply = mpi3mr_get_reply_virt_addr(mrioc, *reply_dma);
223824a1566SKashyap Desai 		if (!def_reply)
224824a1566SKashyap Desai 			goto out;
225824a1566SKashyap Desai 		host_tag = le16_to_cpu(def_reply->host_tag);
226824a1566SKashyap Desai 		ioc_status = le16_to_cpu(def_reply->ioc_status);
227824a1566SKashyap Desai 		if (ioc_status &
228824a1566SKashyap Desai 		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
229824a1566SKashyap Desai 			ioc_loginfo = le32_to_cpu(def_reply->ioc_log_info);
230824a1566SKashyap Desai 		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
231824a1566SKashyap Desai 		if (def_reply->function == MPI3_FUNCTION_SCSI_IO) {
232824a1566SKashyap Desai 			scsi_reply = (struct mpi3_scsi_io_reply *)def_reply;
233824a1566SKashyap Desai 			sense_buf = mpi3mr_get_sensebuf_virt_addr(mrioc,
234824a1566SKashyap Desai 			    le64_to_cpu(scsi_reply->sense_data_buffer_address));
235824a1566SKashyap Desai 		}
236824a1566SKashyap Desai 		break;
237824a1566SKashyap Desai 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS:
238824a1566SKashyap Desai 		success_desc = (struct mpi3_success_reply_descriptor *)reply_desc;
239824a1566SKashyap Desai 		host_tag = le16_to_cpu(success_desc->host_tag);
240824a1566SKashyap Desai 		break;
241824a1566SKashyap Desai 	default:
242824a1566SKashyap Desai 		break;
243824a1566SKashyap Desai 	}
244824a1566SKashyap Desai 
245824a1566SKashyap Desai 	cmdptr = mpi3mr_get_drv_cmd(mrioc, host_tag, def_reply);
246824a1566SKashyap Desai 	if (cmdptr) {
247824a1566SKashyap Desai 		if (cmdptr->state & MPI3MR_CMD_PENDING) {
248824a1566SKashyap Desai 			cmdptr->state |= MPI3MR_CMD_COMPLETE;
249824a1566SKashyap Desai 			cmdptr->ioc_loginfo = ioc_loginfo;
250824a1566SKashyap Desai 			cmdptr->ioc_status = ioc_status;
251824a1566SKashyap Desai 			cmdptr->state &= ~MPI3MR_CMD_PENDING;
252824a1566SKashyap Desai 			if (def_reply) {
253824a1566SKashyap Desai 				cmdptr->state |= MPI3MR_CMD_REPLY_VALID;
254824a1566SKashyap Desai 				memcpy((u8 *)cmdptr->reply, (u8 *)def_reply,
255824a1566SKashyap Desai 				    mrioc->facts.reply_sz);
256824a1566SKashyap Desai 			}
257824a1566SKashyap Desai 			if (cmdptr->is_waiting) {
258824a1566SKashyap Desai 				complete(&cmdptr->done);
259824a1566SKashyap Desai 				cmdptr->is_waiting = 0;
260824a1566SKashyap Desai 			} else if (cmdptr->callback)
261824a1566SKashyap Desai 				cmdptr->callback(mrioc, cmdptr);
262824a1566SKashyap Desai 		}
263824a1566SKashyap Desai 	}
264824a1566SKashyap Desai out:
265824a1566SKashyap Desai 	if (sense_buf)
266824a1566SKashyap Desai 		mpi3mr_repost_sense_buf(mrioc,
267824a1566SKashyap Desai 		    le64_to_cpu(scsi_reply->sense_data_buffer_address));
268824a1566SKashyap Desai }
269824a1566SKashyap Desai 
270824a1566SKashyap Desai static int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc)
271824a1566SKashyap Desai {
272824a1566SKashyap Desai 	u32 exp_phase = mrioc->admin_reply_ephase;
273824a1566SKashyap Desai 	u32 admin_reply_ci = mrioc->admin_reply_ci;
274824a1566SKashyap Desai 	u32 num_admin_replies = 0;
275824a1566SKashyap Desai 	u64 reply_dma = 0;
276824a1566SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc;
277824a1566SKashyap Desai 
278824a1566SKashyap Desai 	reply_desc = (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base +
279824a1566SKashyap Desai 	    admin_reply_ci;
280824a1566SKashyap Desai 
281824a1566SKashyap Desai 	if ((le16_to_cpu(reply_desc->reply_flags) &
282824a1566SKashyap Desai 	    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
283824a1566SKashyap Desai 		return 0;
284824a1566SKashyap Desai 
285824a1566SKashyap Desai 	do {
286824a1566SKashyap Desai 		mrioc->admin_req_ci = le16_to_cpu(reply_desc->request_queue_ci);
287824a1566SKashyap Desai 		mpi3mr_process_admin_reply_desc(mrioc, reply_desc, &reply_dma);
288824a1566SKashyap Desai 		if (reply_dma)
289824a1566SKashyap Desai 			mpi3mr_repost_reply_buf(mrioc, reply_dma);
290824a1566SKashyap Desai 		num_admin_replies++;
291824a1566SKashyap Desai 		if (++admin_reply_ci == mrioc->num_admin_replies) {
292824a1566SKashyap Desai 			admin_reply_ci = 0;
293824a1566SKashyap Desai 			exp_phase ^= 1;
294824a1566SKashyap Desai 		}
295824a1566SKashyap Desai 		reply_desc =
296824a1566SKashyap Desai 		    (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base +
297824a1566SKashyap Desai 		    admin_reply_ci;
298824a1566SKashyap Desai 		if ((le16_to_cpu(reply_desc->reply_flags) &
299824a1566SKashyap Desai 		    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
300824a1566SKashyap Desai 			break;
301824a1566SKashyap Desai 	} while (1);
302824a1566SKashyap Desai 
303824a1566SKashyap Desai 	writel(admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci);
304824a1566SKashyap Desai 	mrioc->admin_reply_ci = admin_reply_ci;
305824a1566SKashyap Desai 	mrioc->admin_reply_ephase = exp_phase;
306824a1566SKashyap Desai 
307824a1566SKashyap Desai 	return num_admin_replies;
308824a1566SKashyap Desai }
309824a1566SKashyap Desai 
310023ab2a9SKashyap Desai /**
311023ab2a9SKashyap Desai  * mpi3mr_get_reply_desc - get reply descriptor frame corresponding to
312023ab2a9SKashyap Desai  *	queue's consumer index from operational reply descriptor queue.
313023ab2a9SKashyap Desai  * @op_reply_q: op_reply_qinfo object
314023ab2a9SKashyap Desai  * @reply_ci: operational reply descriptor's queue consumer index
315023ab2a9SKashyap Desai  *
316023ab2a9SKashyap Desai  * Returns reply descriptor frame address
317023ab2a9SKashyap Desai  */
318023ab2a9SKashyap Desai static inline struct mpi3_default_reply_descriptor *
319023ab2a9SKashyap Desai mpi3mr_get_reply_desc(struct op_reply_qinfo *op_reply_q, u32 reply_ci)
320023ab2a9SKashyap Desai {
321023ab2a9SKashyap Desai 	void *segment_base_addr;
322023ab2a9SKashyap Desai 	struct segments *segments = op_reply_q->q_segments;
323023ab2a9SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc = NULL;
324023ab2a9SKashyap Desai 
325023ab2a9SKashyap Desai 	segment_base_addr =
326023ab2a9SKashyap Desai 	    segments[reply_ci / op_reply_q->segment_qd].segment;
327023ab2a9SKashyap Desai 	reply_desc = (struct mpi3_default_reply_descriptor *)segment_base_addr +
328023ab2a9SKashyap Desai 	    (reply_ci % op_reply_q->segment_qd);
329023ab2a9SKashyap Desai 	return reply_desc;
330023ab2a9SKashyap Desai }
331023ab2a9SKashyap Desai 
332023ab2a9SKashyap Desai static int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc,
333023ab2a9SKashyap Desai 	struct mpi3mr_intr_info *intr_info)
334023ab2a9SKashyap Desai {
335023ab2a9SKashyap Desai 	struct op_reply_qinfo *op_reply_q = intr_info->op_reply_q;
336023ab2a9SKashyap Desai 	struct op_req_qinfo *op_req_q;
337023ab2a9SKashyap Desai 	u32 exp_phase;
338023ab2a9SKashyap Desai 	u32 reply_ci;
339023ab2a9SKashyap Desai 	u32 num_op_reply = 0;
340023ab2a9SKashyap Desai 	u64 reply_dma = 0;
341023ab2a9SKashyap Desai 	struct mpi3_default_reply_descriptor *reply_desc;
342023ab2a9SKashyap Desai 	u16 req_q_idx = 0, reply_qidx;
343023ab2a9SKashyap Desai 
344023ab2a9SKashyap Desai 	reply_qidx = op_reply_q->qid - 1;
345023ab2a9SKashyap Desai 
346023ab2a9SKashyap Desai 	exp_phase = op_reply_q->ephase;
347023ab2a9SKashyap Desai 	reply_ci = op_reply_q->ci;
348023ab2a9SKashyap Desai 
349023ab2a9SKashyap Desai 	reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci);
350023ab2a9SKashyap Desai 	if ((le16_to_cpu(reply_desc->reply_flags) &
351023ab2a9SKashyap Desai 	    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) {
352023ab2a9SKashyap Desai 		return 0;
353023ab2a9SKashyap Desai 	}
354023ab2a9SKashyap Desai 
355023ab2a9SKashyap Desai 	do {
356023ab2a9SKashyap Desai 		req_q_idx = le16_to_cpu(reply_desc->request_queue_id) - 1;
357023ab2a9SKashyap Desai 		op_req_q = &mrioc->req_qinfo[req_q_idx];
358023ab2a9SKashyap Desai 
359023ab2a9SKashyap Desai 		WRITE_ONCE(op_req_q->ci, le16_to_cpu(reply_desc->request_queue_ci));
360023ab2a9SKashyap Desai 		mpi3mr_process_op_reply_desc(mrioc, reply_desc, &reply_dma,
361023ab2a9SKashyap Desai 		    reply_qidx);
362023ab2a9SKashyap Desai 		if (reply_dma)
363023ab2a9SKashyap Desai 			mpi3mr_repost_reply_buf(mrioc, reply_dma);
364023ab2a9SKashyap Desai 		num_op_reply++;
365023ab2a9SKashyap Desai 
366023ab2a9SKashyap Desai 		if (++reply_ci == op_reply_q->num_replies) {
367023ab2a9SKashyap Desai 			reply_ci = 0;
368023ab2a9SKashyap Desai 			exp_phase ^= 1;
369023ab2a9SKashyap Desai 		}
370023ab2a9SKashyap Desai 
371023ab2a9SKashyap Desai 		reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci);
372023ab2a9SKashyap Desai 
373023ab2a9SKashyap Desai 		if ((le16_to_cpu(reply_desc->reply_flags) &
374023ab2a9SKashyap Desai 		    MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
375023ab2a9SKashyap Desai 			break;
376023ab2a9SKashyap Desai 
377023ab2a9SKashyap Desai 	} while (1);
378023ab2a9SKashyap Desai 
379023ab2a9SKashyap Desai 	writel(reply_ci,
380023ab2a9SKashyap Desai 	    &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].consumer_index);
381023ab2a9SKashyap Desai 	op_reply_q->ci = reply_ci;
382023ab2a9SKashyap Desai 	op_reply_q->ephase = exp_phase;
383023ab2a9SKashyap Desai 
384023ab2a9SKashyap Desai 	return num_op_reply;
385023ab2a9SKashyap Desai }
386023ab2a9SKashyap Desai 
387824a1566SKashyap Desai static irqreturn_t mpi3mr_isr_primary(int irq, void *privdata)
388824a1566SKashyap Desai {
389824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info = privdata;
390824a1566SKashyap Desai 	struct mpi3mr_ioc *mrioc;
391824a1566SKashyap Desai 	u16 midx;
392824a1566SKashyap Desai 	u32 num_admin_replies = 0;
393824a1566SKashyap Desai 
394824a1566SKashyap Desai 	if (!intr_info)
395824a1566SKashyap Desai 		return IRQ_NONE;
396824a1566SKashyap Desai 
397824a1566SKashyap Desai 	mrioc = intr_info->mrioc;
398824a1566SKashyap Desai 
399824a1566SKashyap Desai 	if (!mrioc->intr_enabled)
400824a1566SKashyap Desai 		return IRQ_NONE;
401824a1566SKashyap Desai 
402824a1566SKashyap Desai 	midx = intr_info->msix_index;
403824a1566SKashyap Desai 
404824a1566SKashyap Desai 	if (!midx)
405824a1566SKashyap Desai 		num_admin_replies = mpi3mr_process_admin_reply_q(mrioc);
406824a1566SKashyap Desai 
407824a1566SKashyap Desai 	if (num_admin_replies)
408824a1566SKashyap Desai 		return IRQ_HANDLED;
409824a1566SKashyap Desai 	else
410824a1566SKashyap Desai 		return IRQ_NONE;
411824a1566SKashyap Desai }
412824a1566SKashyap Desai 
413824a1566SKashyap Desai static irqreturn_t mpi3mr_isr(int irq, void *privdata)
414824a1566SKashyap Desai {
415824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info = privdata;
416824a1566SKashyap Desai 	int ret;
417824a1566SKashyap Desai 
418824a1566SKashyap Desai 	if (!intr_info)
419824a1566SKashyap Desai 		return IRQ_NONE;
420824a1566SKashyap Desai 
421824a1566SKashyap Desai 	/* Call primary ISR routine */
422824a1566SKashyap Desai 	ret = mpi3mr_isr_primary(irq, privdata);
423824a1566SKashyap Desai 
424824a1566SKashyap Desai 	return ret;
425824a1566SKashyap Desai }
426824a1566SKashyap Desai 
427824a1566SKashyap Desai /**
428824a1566SKashyap Desai  * mpi3mr_isr_poll - Reply queue polling routine
429824a1566SKashyap Desai  * @irq: IRQ
430824a1566SKashyap Desai  * @privdata: Interrupt info
431824a1566SKashyap Desai  *
432824a1566SKashyap Desai  * poll for pending I/O completions in a loop until pending I/Os
433824a1566SKashyap Desai  * present or controller queue depth I/Os are processed.
434824a1566SKashyap Desai  *
435824a1566SKashyap Desai  * Return: IRQ_NONE or IRQ_HANDLED
436824a1566SKashyap Desai  */
437824a1566SKashyap Desai static irqreturn_t mpi3mr_isr_poll(int irq, void *privdata)
438824a1566SKashyap Desai {
439824a1566SKashyap Desai 	return IRQ_HANDLED;
440824a1566SKashyap Desai }
441824a1566SKashyap Desai 
442824a1566SKashyap Desai /**
443824a1566SKashyap Desai  * mpi3mr_request_irq - Request IRQ and register ISR
444824a1566SKashyap Desai  * @mrioc: Adapter instance reference
445824a1566SKashyap Desai  * @index: IRQ vector index
446824a1566SKashyap Desai  *
447824a1566SKashyap Desai  * Request threaded ISR with primary ISR and secondary
448824a1566SKashyap Desai  *
449824a1566SKashyap Desai  * Return: 0 on success and non zero on failures.
450824a1566SKashyap Desai  */
451824a1566SKashyap Desai static inline int mpi3mr_request_irq(struct mpi3mr_ioc *mrioc, u16 index)
452824a1566SKashyap Desai {
453824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
454824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info = mrioc->intr_info + index;
455824a1566SKashyap Desai 	int retval = 0;
456824a1566SKashyap Desai 
457824a1566SKashyap Desai 	intr_info->mrioc = mrioc;
458824a1566SKashyap Desai 	intr_info->msix_index = index;
459824a1566SKashyap Desai 	intr_info->op_reply_q = NULL;
460824a1566SKashyap Desai 
461824a1566SKashyap Desai 	snprintf(intr_info->name, MPI3MR_NAME_LENGTH, "%s%d-msix%d",
462824a1566SKashyap Desai 	    mrioc->driver_name, mrioc->id, index);
463824a1566SKashyap Desai 
464824a1566SKashyap Desai 	retval = request_threaded_irq(pci_irq_vector(pdev, index), mpi3mr_isr,
465824a1566SKashyap Desai 	    mpi3mr_isr_poll, IRQF_SHARED, intr_info->name, intr_info);
466824a1566SKashyap Desai 	if (retval) {
467824a1566SKashyap Desai 		ioc_err(mrioc, "%s: Unable to allocate interrupt %d!\n",
468824a1566SKashyap Desai 		    intr_info->name, pci_irq_vector(pdev, index));
469824a1566SKashyap Desai 		return retval;
470824a1566SKashyap Desai 	}
471824a1566SKashyap Desai 
472824a1566SKashyap Desai 	return retval;
473824a1566SKashyap Desai }
474824a1566SKashyap Desai 
475824a1566SKashyap Desai /**
476824a1566SKashyap Desai  * mpi3mr_setup_isr - Setup ISR for the controller
477824a1566SKashyap Desai  * @mrioc: Adapter instance reference
478824a1566SKashyap Desai  * @setup_one: Request one IRQ or more
479824a1566SKashyap Desai  *
480824a1566SKashyap Desai  * Allocate IRQ vectors and call mpi3mr_request_irq to setup ISR
481824a1566SKashyap Desai  *
482824a1566SKashyap Desai  * Return: 0 on success and non zero on failures.
483824a1566SKashyap Desai  */
484824a1566SKashyap Desai static int mpi3mr_setup_isr(struct mpi3mr_ioc *mrioc, u8 setup_one)
485824a1566SKashyap Desai {
486824a1566SKashyap Desai 	unsigned int irq_flags = PCI_IRQ_MSIX;
487824a1566SKashyap Desai 	u16 max_vectors = 0, i;
488824a1566SKashyap Desai 	int retval = 0;
489824a1566SKashyap Desai 	struct irq_affinity desc = { .pre_vectors =  1};
490824a1566SKashyap Desai 
491824a1566SKashyap Desai 	mpi3mr_cleanup_isr(mrioc);
492824a1566SKashyap Desai 
493824a1566SKashyap Desai 	if (setup_one || reset_devices)
494824a1566SKashyap Desai 		max_vectors = 1;
495824a1566SKashyap Desai 	else {
496824a1566SKashyap Desai 		max_vectors =
497824a1566SKashyap Desai 		    min_t(int, mrioc->cpu_count + 1, mrioc->msix_count);
498824a1566SKashyap Desai 
499824a1566SKashyap Desai 		ioc_info(mrioc,
500824a1566SKashyap Desai 		    "MSI-X vectors supported: %d, no of cores: %d,",
501824a1566SKashyap Desai 		    mrioc->msix_count, mrioc->cpu_count);
502824a1566SKashyap Desai 		ioc_info(mrioc,
503824a1566SKashyap Desai 		    "MSI-x vectors requested: %d\n", max_vectors);
504824a1566SKashyap Desai 	}
505824a1566SKashyap Desai 
506824a1566SKashyap Desai 	irq_flags |= PCI_IRQ_AFFINITY | PCI_IRQ_ALL_TYPES;
507824a1566SKashyap Desai 
508c9566231SKashyap Desai 	mrioc->op_reply_q_offset = (max_vectors > 1) ? 1 : 0;
509824a1566SKashyap Desai 	i = pci_alloc_irq_vectors_affinity(mrioc->pdev,
510824a1566SKashyap Desai 	    1, max_vectors, irq_flags, &desc);
511824a1566SKashyap Desai 	if (i <= 0) {
512824a1566SKashyap Desai 		ioc_err(mrioc, "Cannot alloc irq vectors\n");
513824a1566SKashyap Desai 		goto out_failed;
514824a1566SKashyap Desai 	}
515824a1566SKashyap Desai 	if (i != max_vectors) {
516824a1566SKashyap Desai 		ioc_info(mrioc,
517824a1566SKashyap Desai 		    "allocated vectors (%d) are less than configured (%d)\n",
518824a1566SKashyap Desai 		    i, max_vectors);
519c9566231SKashyap Desai 		/*
520c9566231SKashyap Desai 		 * If only one MSI-x is allocated, then MSI-x 0 will be shared
521c9566231SKashyap Desai 		 * between Admin queue and operational queue
522c9566231SKashyap Desai 		 */
523c9566231SKashyap Desai 		if (i == 1)
524c9566231SKashyap Desai 			mrioc->op_reply_q_offset = 0;
525824a1566SKashyap Desai 
526824a1566SKashyap Desai 		max_vectors = i;
527824a1566SKashyap Desai 	}
528824a1566SKashyap Desai 	mrioc->intr_info = kzalloc(sizeof(struct mpi3mr_intr_info) * max_vectors,
529824a1566SKashyap Desai 	    GFP_KERNEL);
530824a1566SKashyap Desai 	if (!mrioc->intr_info) {
531824a1566SKashyap Desai 		retval = -1;
532824a1566SKashyap Desai 		pci_free_irq_vectors(mrioc->pdev);
533824a1566SKashyap Desai 		goto out_failed;
534824a1566SKashyap Desai 	}
535824a1566SKashyap Desai 	for (i = 0; i < max_vectors; i++) {
536824a1566SKashyap Desai 		retval = mpi3mr_request_irq(mrioc, i);
537824a1566SKashyap Desai 		if (retval) {
538824a1566SKashyap Desai 			mrioc->intr_info_count = i;
539824a1566SKashyap Desai 			goto out_failed;
540824a1566SKashyap Desai 		}
541824a1566SKashyap Desai 	}
542824a1566SKashyap Desai 	mrioc->intr_info_count = max_vectors;
543824a1566SKashyap Desai 	mpi3mr_ioc_enable_intr(mrioc);
544824a1566SKashyap Desai 	return retval;
545824a1566SKashyap Desai out_failed:
546824a1566SKashyap Desai 	mpi3mr_cleanup_isr(mrioc);
547824a1566SKashyap Desai 
548824a1566SKashyap Desai 	return retval;
549824a1566SKashyap Desai }
550824a1566SKashyap Desai 
551824a1566SKashyap Desai static const struct {
552824a1566SKashyap Desai 	enum mpi3mr_iocstate value;
553824a1566SKashyap Desai 	char *name;
554824a1566SKashyap Desai } mrioc_states[] = {
555824a1566SKashyap Desai 	{ MRIOC_STATE_READY, "ready" },
556824a1566SKashyap Desai 	{ MRIOC_STATE_FAULT, "fault" },
557824a1566SKashyap Desai 	{ MRIOC_STATE_RESET, "reset" },
558824a1566SKashyap Desai 	{ MRIOC_STATE_BECOMING_READY, "becoming ready" },
559824a1566SKashyap Desai 	{ MRIOC_STATE_RESET_REQUESTED, "reset requested" },
560824a1566SKashyap Desai 	{ MRIOC_STATE_UNRECOVERABLE, "unrecoverable error" },
561824a1566SKashyap Desai };
562824a1566SKashyap Desai 
563824a1566SKashyap Desai static const char *mpi3mr_iocstate_name(enum mpi3mr_iocstate mrioc_state)
564824a1566SKashyap Desai {
565824a1566SKashyap Desai 	int i;
566824a1566SKashyap Desai 	char *name = NULL;
567824a1566SKashyap Desai 
568824a1566SKashyap Desai 	for (i = 0; i < ARRAY_SIZE(mrioc_states); i++) {
569824a1566SKashyap Desai 		if (mrioc_states[i].value == mrioc_state) {
570824a1566SKashyap Desai 			name = mrioc_states[i].name;
571824a1566SKashyap Desai 			break;
572824a1566SKashyap Desai 		}
573824a1566SKashyap Desai 	}
574824a1566SKashyap Desai 	return name;
575824a1566SKashyap Desai }
576824a1566SKashyap Desai 
577824a1566SKashyap Desai /**
578824a1566SKashyap Desai  * mpi3mr_print_fault_info - Display fault information
579824a1566SKashyap Desai  * @mrioc: Adapter instance reference
580824a1566SKashyap Desai  *
581824a1566SKashyap Desai  * Display the controller fault information if there is a
582824a1566SKashyap Desai  * controller fault.
583824a1566SKashyap Desai  *
584824a1566SKashyap Desai  * Return: Nothing.
585824a1566SKashyap Desai  */
586824a1566SKashyap Desai static void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc)
587824a1566SKashyap Desai {
588824a1566SKashyap Desai 	u32 ioc_status, code, code1, code2, code3;
589824a1566SKashyap Desai 
590824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
591824a1566SKashyap Desai 
592824a1566SKashyap Desai 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) {
593824a1566SKashyap Desai 		code = readl(&mrioc->sysif_regs->fault);
594824a1566SKashyap Desai 		code1 = readl(&mrioc->sysif_regs->fault_info[0]);
595824a1566SKashyap Desai 		code2 = readl(&mrioc->sysif_regs->fault_info[1]);
596824a1566SKashyap Desai 		code3 = readl(&mrioc->sysif_regs->fault_info[2]);
597824a1566SKashyap Desai 
598824a1566SKashyap Desai 		ioc_info(mrioc,
599824a1566SKashyap Desai 		    "fault code(0x%08X): Additional code: (0x%08X:0x%08X:0x%08X)\n",
600824a1566SKashyap Desai 		    code, code1, code2, code3);
601824a1566SKashyap Desai 	}
602824a1566SKashyap Desai }
603824a1566SKashyap Desai 
604824a1566SKashyap Desai /**
605824a1566SKashyap Desai  * mpi3mr_get_iocstate - Get IOC State
606824a1566SKashyap Desai  * @mrioc: Adapter instance reference
607824a1566SKashyap Desai  *
608824a1566SKashyap Desai  * Return a proper IOC state enum based on the IOC status and
609824a1566SKashyap Desai  * IOC configuration and unrcoverable state of the controller.
610824a1566SKashyap Desai  *
611824a1566SKashyap Desai  * Return: Current IOC state.
612824a1566SKashyap Desai  */
613824a1566SKashyap Desai enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc)
614824a1566SKashyap Desai {
615824a1566SKashyap Desai 	u32 ioc_status, ioc_config;
616824a1566SKashyap Desai 	u8 ready, enabled;
617824a1566SKashyap Desai 
618824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
619824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
620824a1566SKashyap Desai 
621824a1566SKashyap Desai 	if (mrioc->unrecoverable)
622824a1566SKashyap Desai 		return MRIOC_STATE_UNRECOVERABLE;
623824a1566SKashyap Desai 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)
624824a1566SKashyap Desai 		return MRIOC_STATE_FAULT;
625824a1566SKashyap Desai 
626824a1566SKashyap Desai 	ready = (ioc_status & MPI3_SYSIF_IOC_STATUS_READY);
627824a1566SKashyap Desai 	enabled = (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC);
628824a1566SKashyap Desai 
629824a1566SKashyap Desai 	if (ready && enabled)
630824a1566SKashyap Desai 		return MRIOC_STATE_READY;
631824a1566SKashyap Desai 	if ((!ready) && (!enabled))
632824a1566SKashyap Desai 		return MRIOC_STATE_RESET;
633824a1566SKashyap Desai 	if ((!ready) && (enabled))
634824a1566SKashyap Desai 		return MRIOC_STATE_BECOMING_READY;
635824a1566SKashyap Desai 
636824a1566SKashyap Desai 	return MRIOC_STATE_RESET_REQUESTED;
637824a1566SKashyap Desai }
638824a1566SKashyap Desai 
639824a1566SKashyap Desai /**
640824a1566SKashyap Desai  * mpi3mr_clear_reset_history - clear reset history
641824a1566SKashyap Desai  * @mrioc: Adapter instance reference
642824a1566SKashyap Desai  *
643824a1566SKashyap Desai  * Write the reset history bit in IOC status to clear the bit,
644824a1566SKashyap Desai  * if it is already set.
645824a1566SKashyap Desai  *
646824a1566SKashyap Desai  * Return: Nothing.
647824a1566SKashyap Desai  */
648824a1566SKashyap Desai static inline void mpi3mr_clear_reset_history(struct mpi3mr_ioc *mrioc)
649824a1566SKashyap Desai {
650824a1566SKashyap Desai 	u32 ioc_status;
651824a1566SKashyap Desai 
652824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
653824a1566SKashyap Desai 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)
654824a1566SKashyap Desai 		writel(ioc_status, &mrioc->sysif_regs->ioc_status);
655824a1566SKashyap Desai }
656824a1566SKashyap Desai 
657824a1566SKashyap Desai /**
658824a1566SKashyap Desai  * mpi3mr_issue_and_process_mur - Message unit Reset handler
659824a1566SKashyap Desai  * @mrioc: Adapter instance reference
660824a1566SKashyap Desai  * @reset_reason: Reset reason code
661824a1566SKashyap Desai  *
662824a1566SKashyap Desai  * Issue Message unit Reset to the controller and wait for it to
663824a1566SKashyap Desai  * be complete.
664824a1566SKashyap Desai  *
665824a1566SKashyap Desai  * Return: 0 on success, -1 on failure.
666824a1566SKashyap Desai  */
667824a1566SKashyap Desai static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc,
668824a1566SKashyap Desai 	u32 reset_reason)
669824a1566SKashyap Desai {
670824a1566SKashyap Desai 	u32 ioc_config, timeout, ioc_status;
671824a1566SKashyap Desai 	int retval = -1;
672824a1566SKashyap Desai 
673824a1566SKashyap Desai 	ioc_info(mrioc, "Issuing Message unit Reset(MUR)\n");
674824a1566SKashyap Desai 	if (mrioc->unrecoverable) {
675824a1566SKashyap Desai 		ioc_info(mrioc, "IOC is unrecoverable MUR not issued\n");
676824a1566SKashyap Desai 		return retval;
677824a1566SKashyap Desai 	}
678824a1566SKashyap Desai 	mpi3mr_clear_reset_history(mrioc);
679824a1566SKashyap Desai 	writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]);
680824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
681824a1566SKashyap Desai 	ioc_config &= ~MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
682824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
683824a1566SKashyap Desai 
684824a1566SKashyap Desai 	timeout = mrioc->ready_timeout * 10;
685824a1566SKashyap Desai 	do {
686824a1566SKashyap Desai 		ioc_status = readl(&mrioc->sysif_regs->ioc_status);
687824a1566SKashyap Desai 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)) {
688824a1566SKashyap Desai 			mpi3mr_clear_reset_history(mrioc);
689824a1566SKashyap Desai 			ioc_config =
690824a1566SKashyap Desai 			    readl(&mrioc->sysif_regs->ioc_configuration);
691824a1566SKashyap Desai 			if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) ||
692824a1566SKashyap Desai 			      (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) ||
693824a1566SKashyap Desai 			    (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) {
694824a1566SKashyap Desai 				retval = 0;
695824a1566SKashyap Desai 				break;
696824a1566SKashyap Desai 			}
697824a1566SKashyap Desai 		}
698824a1566SKashyap Desai 		msleep(100);
699824a1566SKashyap Desai 	} while (--timeout);
700824a1566SKashyap Desai 
701824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
702824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
703824a1566SKashyap Desai 
704824a1566SKashyap Desai 	ioc_info(mrioc, "Base IOC Sts/Config after %s MUR is (0x%x)/(0x%x)\n",
705824a1566SKashyap Desai 	    (!retval) ? "successful" : "failed", ioc_status, ioc_config);
706824a1566SKashyap Desai 	return retval;
707824a1566SKashyap Desai }
708824a1566SKashyap Desai 
709824a1566SKashyap Desai /**
710824a1566SKashyap Desai  * mpi3mr_bring_ioc_ready - Bring controller to ready state
711824a1566SKashyap Desai  * @mrioc: Adapter instance reference
712824a1566SKashyap Desai  *
713824a1566SKashyap Desai  * Set Enable IOC bit in IOC configuration register and wait for
714824a1566SKashyap Desai  * the controller to become ready.
715824a1566SKashyap Desai  *
716824a1566SKashyap Desai  * Return: 0 on success, -1 on failure.
717824a1566SKashyap Desai  */
718824a1566SKashyap Desai static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc)
719824a1566SKashyap Desai {
720824a1566SKashyap Desai 	u32 ioc_config, timeout;
721824a1566SKashyap Desai 	enum mpi3mr_iocstate current_state;
722824a1566SKashyap Desai 
723824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
724824a1566SKashyap Desai 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
725824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
726824a1566SKashyap Desai 
727824a1566SKashyap Desai 	timeout = mrioc->ready_timeout * 10;
728824a1566SKashyap Desai 	do {
729824a1566SKashyap Desai 		current_state = mpi3mr_get_iocstate(mrioc);
730824a1566SKashyap Desai 		if (current_state == MRIOC_STATE_READY)
731824a1566SKashyap Desai 			return 0;
732824a1566SKashyap Desai 		msleep(100);
733824a1566SKashyap Desai 	} while (--timeout);
734824a1566SKashyap Desai 
735824a1566SKashyap Desai 	return -1;
736824a1566SKashyap Desai }
737824a1566SKashyap Desai 
738824a1566SKashyap Desai /**
739824a1566SKashyap Desai  * mpi3mr_set_diagsave - Set diag save bit for snapdump
740824a1566SKashyap Desai  * @mrioc: Adapter reference
741824a1566SKashyap Desai  *
742824a1566SKashyap Desai  * Set diag save bit in IOC configuration register to enable
743824a1566SKashyap Desai  * snapdump.
744824a1566SKashyap Desai  *
745824a1566SKashyap Desai  * Return: Nothing.
746824a1566SKashyap Desai  */
747824a1566SKashyap Desai static inline void mpi3mr_set_diagsave(struct mpi3mr_ioc *mrioc)
748824a1566SKashyap Desai {
749824a1566SKashyap Desai 	u32 ioc_config;
750824a1566SKashyap Desai 
751824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
752824a1566SKashyap Desai 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_DIAG_SAVE;
753824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
754824a1566SKashyap Desai }
755824a1566SKashyap Desai 
756824a1566SKashyap Desai /**
757824a1566SKashyap Desai  * mpi3mr_issue_reset - Issue reset to the controller
758824a1566SKashyap Desai  * @mrioc: Adapter reference
759824a1566SKashyap Desai  * @reset_type: Reset type
760824a1566SKashyap Desai  * @reset_reason: Reset reason code
761824a1566SKashyap Desai  *
762824a1566SKashyap Desai  * TBD
763824a1566SKashyap Desai  *
764824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
765824a1566SKashyap Desai  */
766824a1566SKashyap Desai static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type,
767824a1566SKashyap Desai 	u32 reset_reason)
768824a1566SKashyap Desai {
769824a1566SKashyap Desai 	return 0;
770824a1566SKashyap Desai }
771824a1566SKashyap Desai 
772824a1566SKashyap Desai /**
773824a1566SKashyap Desai  * mpi3mr_admin_request_post - Post request to admin queue
774824a1566SKashyap Desai  * @mrioc: Adapter reference
775824a1566SKashyap Desai  * @admin_req: MPI3 request
776824a1566SKashyap Desai  * @admin_req_sz: Request size
777824a1566SKashyap Desai  * @ignore_reset: Ignore reset in process
778824a1566SKashyap Desai  *
779824a1566SKashyap Desai  * Post the MPI3 request into admin request queue and
780824a1566SKashyap Desai  * inform the controller, if the queue is full return
781824a1566SKashyap Desai  * appropriate error.
782824a1566SKashyap Desai  *
783824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
784824a1566SKashyap Desai  */
785824a1566SKashyap Desai int mpi3mr_admin_request_post(struct mpi3mr_ioc *mrioc, void *admin_req,
786824a1566SKashyap Desai 	u16 admin_req_sz, u8 ignore_reset)
787824a1566SKashyap Desai {
788824a1566SKashyap Desai 	u16 areq_pi = 0, areq_ci = 0, max_entries = 0;
789824a1566SKashyap Desai 	int retval = 0;
790824a1566SKashyap Desai 	unsigned long flags;
791824a1566SKashyap Desai 	u8 *areq_entry;
792824a1566SKashyap Desai 
793824a1566SKashyap Desai 	if (mrioc->unrecoverable) {
794824a1566SKashyap Desai 		ioc_err(mrioc, "%s : Unrecoverable controller\n", __func__);
795824a1566SKashyap Desai 		return -EFAULT;
796824a1566SKashyap Desai 	}
797824a1566SKashyap Desai 
798824a1566SKashyap Desai 	spin_lock_irqsave(&mrioc->admin_req_lock, flags);
799824a1566SKashyap Desai 	areq_pi = mrioc->admin_req_pi;
800824a1566SKashyap Desai 	areq_ci = mrioc->admin_req_ci;
801824a1566SKashyap Desai 	max_entries = mrioc->num_admin_req;
802824a1566SKashyap Desai 	if ((areq_ci == (areq_pi + 1)) || ((!areq_ci) &&
803824a1566SKashyap Desai 	    (areq_pi == (max_entries - 1)))) {
804824a1566SKashyap Desai 		ioc_err(mrioc, "AdminReqQ full condition detected\n");
805824a1566SKashyap Desai 		retval = -EAGAIN;
806824a1566SKashyap Desai 		goto out;
807824a1566SKashyap Desai 	}
808824a1566SKashyap Desai 	if (!ignore_reset && mrioc->reset_in_progress) {
809824a1566SKashyap Desai 		ioc_err(mrioc, "AdminReqQ submit reset in progress\n");
810824a1566SKashyap Desai 		retval = -EAGAIN;
811824a1566SKashyap Desai 		goto out;
812824a1566SKashyap Desai 	}
813824a1566SKashyap Desai 	areq_entry = (u8 *)mrioc->admin_req_base +
814824a1566SKashyap Desai 	    (areq_pi * MPI3MR_ADMIN_REQ_FRAME_SZ);
815824a1566SKashyap Desai 	memset(areq_entry, 0, MPI3MR_ADMIN_REQ_FRAME_SZ);
816824a1566SKashyap Desai 	memcpy(areq_entry, (u8 *)admin_req, admin_req_sz);
817824a1566SKashyap Desai 
818824a1566SKashyap Desai 	if (++areq_pi == max_entries)
819824a1566SKashyap Desai 		areq_pi = 0;
820824a1566SKashyap Desai 	mrioc->admin_req_pi = areq_pi;
821824a1566SKashyap Desai 
822824a1566SKashyap Desai 	writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi);
823824a1566SKashyap Desai 
824824a1566SKashyap Desai out:
825824a1566SKashyap Desai 	spin_unlock_irqrestore(&mrioc->admin_req_lock, flags);
826824a1566SKashyap Desai 
827824a1566SKashyap Desai 	return retval;
828824a1566SKashyap Desai }
829824a1566SKashyap Desai 
830824a1566SKashyap Desai /**
831c9566231SKashyap Desai  * mpi3mr_free_op_req_q_segments - free request memory segments
832c9566231SKashyap Desai  * @mrioc: Adapter instance reference
833c9566231SKashyap Desai  * @q_idx: operational request queue index
834c9566231SKashyap Desai  *
835c9566231SKashyap Desai  * Free memory segments allocated for operational request queue
836c9566231SKashyap Desai  *
837c9566231SKashyap Desai  * Return: Nothing.
838c9566231SKashyap Desai  */
839c9566231SKashyap Desai static void mpi3mr_free_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx)
840c9566231SKashyap Desai {
841c9566231SKashyap Desai 	u16 j;
842c9566231SKashyap Desai 	int size;
843c9566231SKashyap Desai 	struct segments *segments;
844c9566231SKashyap Desai 
845c9566231SKashyap Desai 	segments = mrioc->req_qinfo[q_idx].q_segments;
846c9566231SKashyap Desai 	if (!segments)
847c9566231SKashyap Desai 		return;
848c9566231SKashyap Desai 
849c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
850c9566231SKashyap Desai 		size = MPI3MR_OP_REQ_Q_SEG_SIZE;
851c9566231SKashyap Desai 		if (mrioc->req_qinfo[q_idx].q_segment_list) {
852c9566231SKashyap Desai 			dma_free_coherent(&mrioc->pdev->dev,
853c9566231SKashyap Desai 			    MPI3MR_MAX_SEG_LIST_SIZE,
854c9566231SKashyap Desai 			    mrioc->req_qinfo[q_idx].q_segment_list,
855c9566231SKashyap Desai 			    mrioc->req_qinfo[q_idx].q_segment_list_dma);
856c9566231SKashyap Desai 			mrioc->op_reply_qinfo[q_idx].q_segment_list = NULL;
857c9566231SKashyap Desai 		}
858c9566231SKashyap Desai 	} else
859c9566231SKashyap Desai 		size = mrioc->req_qinfo[q_idx].num_requests *
860c9566231SKashyap Desai 		    mrioc->facts.op_req_sz;
861c9566231SKashyap Desai 
862c9566231SKashyap Desai 	for (j = 0; j < mrioc->req_qinfo[q_idx].num_segments; j++) {
863c9566231SKashyap Desai 		if (!segments[j].segment)
864c9566231SKashyap Desai 			continue;
865c9566231SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev,
866c9566231SKashyap Desai 		    size, segments[j].segment, segments[j].segment_dma);
867c9566231SKashyap Desai 		segments[j].segment = NULL;
868c9566231SKashyap Desai 	}
869c9566231SKashyap Desai 	kfree(mrioc->req_qinfo[q_idx].q_segments);
870c9566231SKashyap Desai 	mrioc->req_qinfo[q_idx].q_segments = NULL;
871c9566231SKashyap Desai 	mrioc->req_qinfo[q_idx].qid = 0;
872c9566231SKashyap Desai }
873c9566231SKashyap Desai 
874c9566231SKashyap Desai /**
875c9566231SKashyap Desai  * mpi3mr_free_op_reply_q_segments - free reply memory segments
876c9566231SKashyap Desai  * @mrioc: Adapter instance reference
877c9566231SKashyap Desai  * @q_idx: operational reply queue index
878c9566231SKashyap Desai  *
879c9566231SKashyap Desai  * Free memory segments allocated for operational reply queue
880c9566231SKashyap Desai  *
881c9566231SKashyap Desai  * Return: Nothing.
882c9566231SKashyap Desai  */
883c9566231SKashyap Desai static void mpi3mr_free_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx)
884c9566231SKashyap Desai {
885c9566231SKashyap Desai 	u16 j;
886c9566231SKashyap Desai 	int size;
887c9566231SKashyap Desai 	struct segments *segments;
888c9566231SKashyap Desai 
889c9566231SKashyap Desai 	segments = mrioc->op_reply_qinfo[q_idx].q_segments;
890c9566231SKashyap Desai 	if (!segments)
891c9566231SKashyap Desai 		return;
892c9566231SKashyap Desai 
893c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
894c9566231SKashyap Desai 		size = MPI3MR_OP_REP_Q_SEG_SIZE;
895c9566231SKashyap Desai 		if (mrioc->op_reply_qinfo[q_idx].q_segment_list) {
896c9566231SKashyap Desai 			dma_free_coherent(&mrioc->pdev->dev,
897c9566231SKashyap Desai 			    MPI3MR_MAX_SEG_LIST_SIZE,
898c9566231SKashyap Desai 			    mrioc->op_reply_qinfo[q_idx].q_segment_list,
899c9566231SKashyap Desai 			    mrioc->op_reply_qinfo[q_idx].q_segment_list_dma);
900c9566231SKashyap Desai 			mrioc->op_reply_qinfo[q_idx].q_segment_list = NULL;
901c9566231SKashyap Desai 		}
902c9566231SKashyap Desai 	} else
903c9566231SKashyap Desai 		size = mrioc->op_reply_qinfo[q_idx].segment_qd *
904c9566231SKashyap Desai 		    mrioc->op_reply_desc_sz;
905c9566231SKashyap Desai 
906c9566231SKashyap Desai 	for (j = 0; j < mrioc->op_reply_qinfo[q_idx].num_segments; j++) {
907c9566231SKashyap Desai 		if (!segments[j].segment)
908c9566231SKashyap Desai 			continue;
909c9566231SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev,
910c9566231SKashyap Desai 		    size, segments[j].segment, segments[j].segment_dma);
911c9566231SKashyap Desai 		segments[j].segment = NULL;
912c9566231SKashyap Desai 	}
913c9566231SKashyap Desai 
914c9566231SKashyap Desai 	kfree(mrioc->op_reply_qinfo[q_idx].q_segments);
915c9566231SKashyap Desai 	mrioc->op_reply_qinfo[q_idx].q_segments = NULL;
916c9566231SKashyap Desai 	mrioc->op_reply_qinfo[q_idx].qid = 0;
917c9566231SKashyap Desai }
918c9566231SKashyap Desai 
919c9566231SKashyap Desai /**
920c9566231SKashyap Desai  * mpi3mr_delete_op_reply_q - delete operational reply queue
921c9566231SKashyap Desai  * @mrioc: Adapter instance reference
922c9566231SKashyap Desai  * @qidx: operational reply queue index
923c9566231SKashyap Desai  *
924c9566231SKashyap Desai  * Delete operatinal reply queue by issuing MPI request
925c9566231SKashyap Desai  * through admin queue.
926c9566231SKashyap Desai  *
927c9566231SKashyap Desai  * Return:  0 on success, non-zero on failure.
928c9566231SKashyap Desai  */
929c9566231SKashyap Desai static int mpi3mr_delete_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx)
930c9566231SKashyap Desai {
931c9566231SKashyap Desai 	struct mpi3_delete_reply_queue_request delq_req;
932c9566231SKashyap Desai 	int retval = 0;
933c9566231SKashyap Desai 	u16 reply_qid = 0, midx;
934c9566231SKashyap Desai 
935c9566231SKashyap Desai 	reply_qid = mrioc->op_reply_qinfo[qidx].qid;
936c9566231SKashyap Desai 
937c9566231SKashyap Desai 	midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset);
938c9566231SKashyap Desai 
939c9566231SKashyap Desai 	if (!reply_qid)	{
940c9566231SKashyap Desai 		retval = -1;
941c9566231SKashyap Desai 		ioc_err(mrioc, "Issue DelRepQ: called with invalid ReqQID\n");
942c9566231SKashyap Desai 		goto out;
943c9566231SKashyap Desai 	}
944c9566231SKashyap Desai 
945c9566231SKashyap Desai 	memset(&delq_req, 0, sizeof(delq_req));
946c9566231SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
947c9566231SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
948c9566231SKashyap Desai 		retval = -1;
949c9566231SKashyap Desai 		ioc_err(mrioc, "Issue DelRepQ: Init command is in use\n");
950c9566231SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
951c9566231SKashyap Desai 		goto out;
952c9566231SKashyap Desai 	}
953c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
954c9566231SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
955c9566231SKashyap Desai 	mrioc->init_cmds.callback = NULL;
956c9566231SKashyap Desai 	delq_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
957c9566231SKashyap Desai 	delq_req.function = MPI3_FUNCTION_DELETE_REPLY_QUEUE;
958c9566231SKashyap Desai 	delq_req.queue_id = cpu_to_le16(reply_qid);
959c9566231SKashyap Desai 
960c9566231SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
961c9566231SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &delq_req, sizeof(delq_req),
962c9566231SKashyap Desai 	    1);
963c9566231SKashyap Desai 	if (retval) {
964c9566231SKashyap Desai 		ioc_err(mrioc, "Issue DelRepQ: Admin Post failed\n");
965c9566231SKashyap Desai 		goto out_unlock;
966c9566231SKashyap Desai 	}
967c9566231SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
968c9566231SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
969c9566231SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
970c9566231SKashyap Desai 		ioc_err(mrioc, "Issue DelRepQ: command timed out\n");
971c9566231SKashyap Desai 		mpi3mr_set_diagsave(mrioc);
972c9566231SKashyap Desai 		mpi3mr_issue_reset(mrioc,
973c9566231SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
974c9566231SKashyap Desai 		    MPI3MR_RESET_FROM_DELREPQ_TIMEOUT);
975c9566231SKashyap Desai 		mrioc->unrecoverable = 1;
976c9566231SKashyap Desai 
977c9566231SKashyap Desai 		retval = -1;
978c9566231SKashyap Desai 		goto out_unlock;
979c9566231SKashyap Desai 	}
980c9566231SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
981c9566231SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
982c9566231SKashyap Desai 		ioc_err(mrioc,
983c9566231SKashyap Desai 		    "Issue DelRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
984c9566231SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
985c9566231SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
986c9566231SKashyap Desai 		retval = -1;
987c9566231SKashyap Desai 		goto out_unlock;
988c9566231SKashyap Desai 	}
989c9566231SKashyap Desai 	mrioc->intr_info[midx].op_reply_q = NULL;
990c9566231SKashyap Desai 
991c9566231SKashyap Desai 	mpi3mr_free_op_reply_q_segments(mrioc, qidx);
992c9566231SKashyap Desai out_unlock:
993c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
994c9566231SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
995c9566231SKashyap Desai out:
996c9566231SKashyap Desai 
997c9566231SKashyap Desai 	return retval;
998c9566231SKashyap Desai }
999c9566231SKashyap Desai 
1000c9566231SKashyap Desai /**
1001c9566231SKashyap Desai  * mpi3mr_alloc_op_reply_q_segments -Alloc segmented reply pool
1002c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1003c9566231SKashyap Desai  * @qidx: request queue index
1004c9566231SKashyap Desai  *
1005c9566231SKashyap Desai  * Allocate segmented memory pools for operational reply
1006c9566231SKashyap Desai  * queue.
1007c9566231SKashyap Desai  *
1008c9566231SKashyap Desai  * Return: 0 on success, non-zero on failure.
1009c9566231SKashyap Desai  */
1010c9566231SKashyap Desai static int mpi3mr_alloc_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx)
1011c9566231SKashyap Desai {
1012c9566231SKashyap Desai 	struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
1013c9566231SKashyap Desai 	int i, size;
1014c9566231SKashyap Desai 	u64 *q_segment_list_entry = NULL;
1015c9566231SKashyap Desai 	struct segments *segments;
1016c9566231SKashyap Desai 
1017c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1018c9566231SKashyap Desai 		op_reply_q->segment_qd =
1019c9566231SKashyap Desai 		    MPI3MR_OP_REP_Q_SEG_SIZE / mrioc->op_reply_desc_sz;
1020c9566231SKashyap Desai 
1021c9566231SKashyap Desai 		size = MPI3MR_OP_REP_Q_SEG_SIZE;
1022c9566231SKashyap Desai 
1023c9566231SKashyap Desai 		op_reply_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev,
1024c9566231SKashyap Desai 		    MPI3MR_MAX_SEG_LIST_SIZE, &op_reply_q->q_segment_list_dma,
1025c9566231SKashyap Desai 		    GFP_KERNEL);
1026c9566231SKashyap Desai 		if (!op_reply_q->q_segment_list)
1027c9566231SKashyap Desai 			return -ENOMEM;
1028c9566231SKashyap Desai 		q_segment_list_entry = (u64 *)op_reply_q->q_segment_list;
1029c9566231SKashyap Desai 	} else {
1030c9566231SKashyap Desai 		op_reply_q->segment_qd = op_reply_q->num_replies;
1031c9566231SKashyap Desai 		size = op_reply_q->num_replies * mrioc->op_reply_desc_sz;
1032c9566231SKashyap Desai 	}
1033c9566231SKashyap Desai 
1034c9566231SKashyap Desai 	op_reply_q->num_segments = DIV_ROUND_UP(op_reply_q->num_replies,
1035c9566231SKashyap Desai 	    op_reply_q->segment_qd);
1036c9566231SKashyap Desai 
1037c9566231SKashyap Desai 	op_reply_q->q_segments = kcalloc(op_reply_q->num_segments,
1038c9566231SKashyap Desai 	    sizeof(struct segments), GFP_KERNEL);
1039c9566231SKashyap Desai 	if (!op_reply_q->q_segments)
1040c9566231SKashyap Desai 		return -ENOMEM;
1041c9566231SKashyap Desai 
1042c9566231SKashyap Desai 	segments = op_reply_q->q_segments;
1043c9566231SKashyap Desai 	for (i = 0; i < op_reply_q->num_segments; i++) {
1044c9566231SKashyap Desai 		segments[i].segment =
1045c9566231SKashyap Desai 		    dma_alloc_coherent(&mrioc->pdev->dev,
1046c9566231SKashyap Desai 		    size, &segments[i].segment_dma, GFP_KERNEL);
1047c9566231SKashyap Desai 		if (!segments[i].segment)
1048c9566231SKashyap Desai 			return -ENOMEM;
1049c9566231SKashyap Desai 		if (mrioc->enable_segqueue)
1050c9566231SKashyap Desai 			q_segment_list_entry[i] =
1051c9566231SKashyap Desai 			    (unsigned long)segments[i].segment_dma;
1052c9566231SKashyap Desai 	}
1053c9566231SKashyap Desai 
1054c9566231SKashyap Desai 	return 0;
1055c9566231SKashyap Desai }
1056c9566231SKashyap Desai 
1057c9566231SKashyap Desai /**
1058c9566231SKashyap Desai  * mpi3mr_alloc_op_req_q_segments - Alloc segmented req pool.
1059c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1060c9566231SKashyap Desai  * @qidx: request queue index
1061c9566231SKashyap Desai  *
1062c9566231SKashyap Desai  * Allocate segmented memory pools for operational request
1063c9566231SKashyap Desai  * queue.
1064c9566231SKashyap Desai  *
1065c9566231SKashyap Desai  * Return: 0 on success, non-zero on failure.
1066c9566231SKashyap Desai  */
1067c9566231SKashyap Desai static int mpi3mr_alloc_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx)
1068c9566231SKashyap Desai {
1069c9566231SKashyap Desai 	struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx;
1070c9566231SKashyap Desai 	int i, size;
1071c9566231SKashyap Desai 	u64 *q_segment_list_entry = NULL;
1072c9566231SKashyap Desai 	struct segments *segments;
1073c9566231SKashyap Desai 
1074c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1075c9566231SKashyap Desai 		op_req_q->segment_qd =
1076c9566231SKashyap Desai 		    MPI3MR_OP_REQ_Q_SEG_SIZE / mrioc->facts.op_req_sz;
1077c9566231SKashyap Desai 
1078c9566231SKashyap Desai 		size = MPI3MR_OP_REQ_Q_SEG_SIZE;
1079c9566231SKashyap Desai 
1080c9566231SKashyap Desai 		op_req_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev,
1081c9566231SKashyap Desai 		    MPI3MR_MAX_SEG_LIST_SIZE, &op_req_q->q_segment_list_dma,
1082c9566231SKashyap Desai 		    GFP_KERNEL);
1083c9566231SKashyap Desai 		if (!op_req_q->q_segment_list)
1084c9566231SKashyap Desai 			return -ENOMEM;
1085c9566231SKashyap Desai 		q_segment_list_entry = (u64 *)op_req_q->q_segment_list;
1086c9566231SKashyap Desai 
1087c9566231SKashyap Desai 	} else {
1088c9566231SKashyap Desai 		op_req_q->segment_qd = op_req_q->num_requests;
1089c9566231SKashyap Desai 		size = op_req_q->num_requests * mrioc->facts.op_req_sz;
1090c9566231SKashyap Desai 	}
1091c9566231SKashyap Desai 
1092c9566231SKashyap Desai 	op_req_q->num_segments = DIV_ROUND_UP(op_req_q->num_requests,
1093c9566231SKashyap Desai 	    op_req_q->segment_qd);
1094c9566231SKashyap Desai 
1095c9566231SKashyap Desai 	op_req_q->q_segments = kcalloc(op_req_q->num_segments,
1096c9566231SKashyap Desai 	    sizeof(struct segments), GFP_KERNEL);
1097c9566231SKashyap Desai 	if (!op_req_q->q_segments)
1098c9566231SKashyap Desai 		return -ENOMEM;
1099c9566231SKashyap Desai 
1100c9566231SKashyap Desai 	segments = op_req_q->q_segments;
1101c9566231SKashyap Desai 	for (i = 0; i < op_req_q->num_segments; i++) {
1102c9566231SKashyap Desai 		segments[i].segment =
1103c9566231SKashyap Desai 		    dma_alloc_coherent(&mrioc->pdev->dev,
1104c9566231SKashyap Desai 		    size, &segments[i].segment_dma, GFP_KERNEL);
1105c9566231SKashyap Desai 		if (!segments[i].segment)
1106c9566231SKashyap Desai 			return -ENOMEM;
1107c9566231SKashyap Desai 		if (mrioc->enable_segqueue)
1108c9566231SKashyap Desai 			q_segment_list_entry[i] =
1109c9566231SKashyap Desai 			    (unsigned long)segments[i].segment_dma;
1110c9566231SKashyap Desai 	}
1111c9566231SKashyap Desai 
1112c9566231SKashyap Desai 	return 0;
1113c9566231SKashyap Desai }
1114c9566231SKashyap Desai 
1115c9566231SKashyap Desai /**
1116c9566231SKashyap Desai  * mpi3mr_create_op_reply_q - create operational reply queue
1117c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1118c9566231SKashyap Desai  * @qidx: operational reply queue index
1119c9566231SKashyap Desai  *
1120c9566231SKashyap Desai  * Create operatinal reply queue by issuing MPI request
1121c9566231SKashyap Desai  * through admin queue.
1122c9566231SKashyap Desai  *
1123c9566231SKashyap Desai  * Return:  0 on success, non-zero on failure.
1124c9566231SKashyap Desai  */
1125c9566231SKashyap Desai static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx)
1126c9566231SKashyap Desai {
1127c9566231SKashyap Desai 	struct mpi3_create_reply_queue_request create_req;
1128c9566231SKashyap Desai 	struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
1129c9566231SKashyap Desai 	int retval = 0;
1130c9566231SKashyap Desai 	u16 reply_qid = 0, midx;
1131c9566231SKashyap Desai 
1132c9566231SKashyap Desai 	reply_qid = op_reply_q->qid;
1133c9566231SKashyap Desai 
1134c9566231SKashyap Desai 	midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset);
1135c9566231SKashyap Desai 
1136c9566231SKashyap Desai 	if (reply_qid) {
1137c9566231SKashyap Desai 		retval = -1;
1138c9566231SKashyap Desai 		ioc_err(mrioc, "CreateRepQ: called for duplicate qid %d\n",
1139c9566231SKashyap Desai 		    reply_qid);
1140c9566231SKashyap Desai 
1141c9566231SKashyap Desai 		return retval;
1142c9566231SKashyap Desai 	}
1143c9566231SKashyap Desai 
1144c9566231SKashyap Desai 	reply_qid = qidx + 1;
1145c9566231SKashyap Desai 	op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD;
1146c9566231SKashyap Desai 	op_reply_q->ci = 0;
1147c9566231SKashyap Desai 	op_reply_q->ephase = 1;
1148c9566231SKashyap Desai 
1149c9566231SKashyap Desai 	if (!op_reply_q->q_segments) {
1150c9566231SKashyap Desai 		retval = mpi3mr_alloc_op_reply_q_segments(mrioc, qidx);
1151c9566231SKashyap Desai 		if (retval) {
1152c9566231SKashyap Desai 			mpi3mr_free_op_reply_q_segments(mrioc, qidx);
1153c9566231SKashyap Desai 			goto out;
1154c9566231SKashyap Desai 		}
1155c9566231SKashyap Desai 	}
1156c9566231SKashyap Desai 
1157c9566231SKashyap Desai 	memset(&create_req, 0, sizeof(create_req));
1158c9566231SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
1159c9566231SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
1160c9566231SKashyap Desai 		retval = -1;
1161c9566231SKashyap Desai 		ioc_err(mrioc, "CreateRepQ: Init command is in use\n");
1162c9566231SKashyap Desai 		goto out;
1163c9566231SKashyap Desai 	}
1164c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
1165c9566231SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
1166c9566231SKashyap Desai 	mrioc->init_cmds.callback = NULL;
1167c9566231SKashyap Desai 	create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
1168c9566231SKashyap Desai 	create_req.function = MPI3_FUNCTION_CREATE_REPLY_QUEUE;
1169c9566231SKashyap Desai 	create_req.queue_id = cpu_to_le16(reply_qid);
1170c9566231SKashyap Desai 	create_req.flags = MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_ENABLE;
1171c9566231SKashyap Desai 	create_req.msix_index = cpu_to_le16(mrioc->intr_info[midx].msix_index);
1172c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1173c9566231SKashyap Desai 		create_req.flags |=
1174c9566231SKashyap Desai 		    MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED;
1175c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
1176c9566231SKashyap Desai 		    op_reply_q->q_segment_list_dma);
1177c9566231SKashyap Desai 	} else
1178c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
1179c9566231SKashyap Desai 		    op_reply_q->q_segments[0].segment_dma);
1180c9566231SKashyap Desai 
1181c9566231SKashyap Desai 	create_req.size = cpu_to_le16(op_reply_q->num_replies);
1182c9566231SKashyap Desai 
1183c9566231SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
1184c9566231SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &create_req,
1185c9566231SKashyap Desai 	    sizeof(create_req), 1);
1186c9566231SKashyap Desai 	if (retval) {
1187c9566231SKashyap Desai 		ioc_err(mrioc, "CreateRepQ: Admin Post failed\n");
1188c9566231SKashyap Desai 		goto out_unlock;
1189c9566231SKashyap Desai 	}
1190c9566231SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
1191c9566231SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
1192c9566231SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
1193c9566231SKashyap Desai 		ioc_err(mrioc, "CreateRepQ: command timed out\n");
1194c9566231SKashyap Desai 		mpi3mr_set_diagsave(mrioc);
1195c9566231SKashyap Desai 		mpi3mr_issue_reset(mrioc,
1196c9566231SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
1197c9566231SKashyap Desai 		    MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT);
1198c9566231SKashyap Desai 		mrioc->unrecoverable = 1;
1199c9566231SKashyap Desai 		retval = -1;
1200c9566231SKashyap Desai 		goto out_unlock;
1201c9566231SKashyap Desai 	}
1202c9566231SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
1203c9566231SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
1204c9566231SKashyap Desai 		ioc_err(mrioc,
1205c9566231SKashyap Desai 		    "CreateRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
1206c9566231SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
1207c9566231SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
1208c9566231SKashyap Desai 		retval = -1;
1209c9566231SKashyap Desai 		goto out_unlock;
1210c9566231SKashyap Desai 	}
1211c9566231SKashyap Desai 	op_reply_q->qid = reply_qid;
1212c9566231SKashyap Desai 	mrioc->intr_info[midx].op_reply_q = op_reply_q;
1213c9566231SKashyap Desai 
1214c9566231SKashyap Desai out_unlock:
1215c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
1216c9566231SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
1217c9566231SKashyap Desai out:
1218c9566231SKashyap Desai 
1219c9566231SKashyap Desai 	return retval;
1220c9566231SKashyap Desai }
1221c9566231SKashyap Desai 
1222c9566231SKashyap Desai /**
1223c9566231SKashyap Desai  * mpi3mr_create_op_req_q - create operational request queue
1224c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1225c9566231SKashyap Desai  * @idx: operational request queue index
1226c9566231SKashyap Desai  * @reply_qid: Reply queue ID
1227c9566231SKashyap Desai  *
1228c9566231SKashyap Desai  * Create operatinal request queue by issuing MPI request
1229c9566231SKashyap Desai  * through admin queue.
1230c9566231SKashyap Desai  *
1231c9566231SKashyap Desai  * Return:  0 on success, non-zero on failure.
1232c9566231SKashyap Desai  */
1233c9566231SKashyap Desai static int mpi3mr_create_op_req_q(struct mpi3mr_ioc *mrioc, u16 idx,
1234c9566231SKashyap Desai 	u16 reply_qid)
1235c9566231SKashyap Desai {
1236c9566231SKashyap Desai 	struct mpi3_create_request_queue_request create_req;
1237c9566231SKashyap Desai 	struct op_req_qinfo *op_req_q = mrioc->req_qinfo + idx;
1238c9566231SKashyap Desai 	int retval = 0;
1239c9566231SKashyap Desai 	u16 req_qid = 0;
1240c9566231SKashyap Desai 
1241c9566231SKashyap Desai 	req_qid = op_req_q->qid;
1242c9566231SKashyap Desai 
1243c9566231SKashyap Desai 	if (req_qid) {
1244c9566231SKashyap Desai 		retval = -1;
1245c9566231SKashyap Desai 		ioc_err(mrioc, "CreateReqQ: called for duplicate qid %d\n",
1246c9566231SKashyap Desai 		    req_qid);
1247c9566231SKashyap Desai 
1248c9566231SKashyap Desai 		return retval;
1249c9566231SKashyap Desai 	}
1250c9566231SKashyap Desai 	req_qid = idx + 1;
1251c9566231SKashyap Desai 
1252c9566231SKashyap Desai 	op_req_q->num_requests = MPI3MR_OP_REQ_Q_QD;
1253c9566231SKashyap Desai 	op_req_q->ci = 0;
1254c9566231SKashyap Desai 	op_req_q->pi = 0;
1255c9566231SKashyap Desai 	op_req_q->reply_qid = reply_qid;
1256c9566231SKashyap Desai 	spin_lock_init(&op_req_q->q_lock);
1257c9566231SKashyap Desai 
1258c9566231SKashyap Desai 	if (!op_req_q->q_segments) {
1259c9566231SKashyap Desai 		retval = mpi3mr_alloc_op_req_q_segments(mrioc, idx);
1260c9566231SKashyap Desai 		if (retval) {
1261c9566231SKashyap Desai 			mpi3mr_free_op_req_q_segments(mrioc, idx);
1262c9566231SKashyap Desai 			goto out;
1263c9566231SKashyap Desai 		}
1264c9566231SKashyap Desai 	}
1265c9566231SKashyap Desai 
1266c9566231SKashyap Desai 	memset(&create_req, 0, sizeof(create_req));
1267c9566231SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
1268c9566231SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
1269c9566231SKashyap Desai 		retval = -1;
1270c9566231SKashyap Desai 		ioc_err(mrioc, "CreateReqQ: Init command is in use\n");
1271c9566231SKashyap Desai 		goto out;
1272c9566231SKashyap Desai 	}
1273c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
1274c9566231SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
1275c9566231SKashyap Desai 	mrioc->init_cmds.callback = NULL;
1276c9566231SKashyap Desai 	create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
1277c9566231SKashyap Desai 	create_req.function = MPI3_FUNCTION_CREATE_REQUEST_QUEUE;
1278c9566231SKashyap Desai 	create_req.queue_id = cpu_to_le16(req_qid);
1279c9566231SKashyap Desai 	if (mrioc->enable_segqueue) {
1280c9566231SKashyap Desai 		create_req.flags =
1281c9566231SKashyap Desai 		    MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED;
1282c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
1283c9566231SKashyap Desai 		    op_req_q->q_segment_list_dma);
1284c9566231SKashyap Desai 	} else
1285c9566231SKashyap Desai 		create_req.base_address = cpu_to_le64(
1286c9566231SKashyap Desai 		    op_req_q->q_segments[0].segment_dma);
1287c9566231SKashyap Desai 	create_req.reply_queue_id = cpu_to_le16(reply_qid);
1288c9566231SKashyap Desai 	create_req.size = cpu_to_le16(op_req_q->num_requests);
1289c9566231SKashyap Desai 
1290c9566231SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
1291c9566231SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &create_req,
1292c9566231SKashyap Desai 	    sizeof(create_req), 1);
1293c9566231SKashyap Desai 	if (retval) {
1294c9566231SKashyap Desai 		ioc_err(mrioc, "CreateReqQ: Admin Post failed\n");
1295c9566231SKashyap Desai 		goto out_unlock;
1296c9566231SKashyap Desai 	}
1297c9566231SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
1298c9566231SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
1299c9566231SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
1300c9566231SKashyap Desai 		ioc_err(mrioc, "CreateReqQ: command timed out\n");
1301c9566231SKashyap Desai 		mpi3mr_set_diagsave(mrioc);
1302c9566231SKashyap Desai 		if (mpi3mr_issue_reset(mrioc,
1303c9566231SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
1304c9566231SKashyap Desai 		    MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT))
1305c9566231SKashyap Desai 			mrioc->unrecoverable = 1;
1306c9566231SKashyap Desai 		retval = -1;
1307c9566231SKashyap Desai 		goto out_unlock;
1308c9566231SKashyap Desai 	}
1309c9566231SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
1310c9566231SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
1311c9566231SKashyap Desai 		ioc_err(mrioc,
1312c9566231SKashyap Desai 		    "CreateReqQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
1313c9566231SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
1314c9566231SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
1315c9566231SKashyap Desai 		retval = -1;
1316c9566231SKashyap Desai 		goto out_unlock;
1317c9566231SKashyap Desai 	}
1318c9566231SKashyap Desai 	op_req_q->qid = req_qid;
1319c9566231SKashyap Desai 
1320c9566231SKashyap Desai out_unlock:
1321c9566231SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
1322c9566231SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
1323c9566231SKashyap Desai out:
1324c9566231SKashyap Desai 
1325c9566231SKashyap Desai 	return retval;
1326c9566231SKashyap Desai }
1327c9566231SKashyap Desai 
1328c9566231SKashyap Desai /**
1329c9566231SKashyap Desai  * mpi3mr_create_op_queues - create operational queue pairs
1330c9566231SKashyap Desai  * @mrioc: Adapter instance reference
1331c9566231SKashyap Desai  *
1332c9566231SKashyap Desai  * Allocate memory for operational queue meta data and call
1333c9566231SKashyap Desai  * create request and reply queue functions.
1334c9566231SKashyap Desai  *
1335c9566231SKashyap Desai  * Return: 0 on success, non-zero on failures.
1336c9566231SKashyap Desai  */
1337c9566231SKashyap Desai static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc)
1338c9566231SKashyap Desai {
1339c9566231SKashyap Desai 	int retval = 0;
1340c9566231SKashyap Desai 	u16 num_queues = 0, i = 0, msix_count_op_q = 1;
1341c9566231SKashyap Desai 
1342c9566231SKashyap Desai 	num_queues = min_t(int, mrioc->facts.max_op_reply_q,
1343c9566231SKashyap Desai 	    mrioc->facts.max_op_req_q);
1344c9566231SKashyap Desai 
1345c9566231SKashyap Desai 	msix_count_op_q =
1346c9566231SKashyap Desai 	    mrioc->intr_info_count - mrioc->op_reply_q_offset;
1347c9566231SKashyap Desai 	if (!mrioc->num_queues)
1348c9566231SKashyap Desai 		mrioc->num_queues = min_t(int, num_queues, msix_count_op_q);
1349c9566231SKashyap Desai 	num_queues = mrioc->num_queues;
1350c9566231SKashyap Desai 	ioc_info(mrioc, "Trying to create %d Operational Q pairs\n",
1351c9566231SKashyap Desai 	    num_queues);
1352c9566231SKashyap Desai 
1353c9566231SKashyap Desai 	if (!mrioc->req_qinfo) {
1354c9566231SKashyap Desai 		mrioc->req_qinfo = kcalloc(num_queues,
1355c9566231SKashyap Desai 		    sizeof(struct op_req_qinfo), GFP_KERNEL);
1356c9566231SKashyap Desai 		if (!mrioc->req_qinfo) {
1357c9566231SKashyap Desai 			retval = -1;
1358c9566231SKashyap Desai 			goto out_failed;
1359c9566231SKashyap Desai 		}
1360c9566231SKashyap Desai 
1361c9566231SKashyap Desai 		mrioc->op_reply_qinfo = kzalloc(sizeof(struct op_reply_qinfo) *
1362c9566231SKashyap Desai 		    num_queues, GFP_KERNEL);
1363c9566231SKashyap Desai 		if (!mrioc->op_reply_qinfo) {
1364c9566231SKashyap Desai 			retval = -1;
1365c9566231SKashyap Desai 			goto out_failed;
1366c9566231SKashyap Desai 		}
1367c9566231SKashyap Desai 	}
1368c9566231SKashyap Desai 
1369c9566231SKashyap Desai 	if (mrioc->enable_segqueue)
1370c9566231SKashyap Desai 		ioc_info(mrioc,
1371c9566231SKashyap Desai 		    "allocating operational queues through segmented queues\n");
1372c9566231SKashyap Desai 
1373c9566231SKashyap Desai 	for (i = 0; i < num_queues; i++) {
1374c9566231SKashyap Desai 		if (mpi3mr_create_op_reply_q(mrioc, i)) {
1375c9566231SKashyap Desai 			ioc_err(mrioc, "Cannot create OP RepQ %d\n", i);
1376c9566231SKashyap Desai 			break;
1377c9566231SKashyap Desai 		}
1378c9566231SKashyap Desai 		if (mpi3mr_create_op_req_q(mrioc, i,
1379c9566231SKashyap Desai 		    mrioc->op_reply_qinfo[i].qid)) {
1380c9566231SKashyap Desai 			ioc_err(mrioc, "Cannot create OP ReqQ %d\n", i);
1381c9566231SKashyap Desai 			mpi3mr_delete_op_reply_q(mrioc, i);
1382c9566231SKashyap Desai 			break;
1383c9566231SKashyap Desai 		}
1384c9566231SKashyap Desai 	}
1385c9566231SKashyap Desai 
1386c9566231SKashyap Desai 	if (i == 0) {
1387c9566231SKashyap Desai 		/* Not even one queue is created successfully*/
1388c9566231SKashyap Desai 		retval = -1;
1389c9566231SKashyap Desai 		goto out_failed;
1390c9566231SKashyap Desai 	}
1391c9566231SKashyap Desai 	mrioc->num_op_reply_q = mrioc->num_op_req_q = i;
1392c9566231SKashyap Desai 	ioc_info(mrioc, "Successfully created %d Operational Q pairs\n",
1393c9566231SKashyap Desai 	    mrioc->num_op_reply_q);
1394c9566231SKashyap Desai 
1395c9566231SKashyap Desai 	return retval;
1396c9566231SKashyap Desai out_failed:
1397c9566231SKashyap Desai 	kfree(mrioc->req_qinfo);
1398c9566231SKashyap Desai 	mrioc->req_qinfo = NULL;
1399c9566231SKashyap Desai 
1400c9566231SKashyap Desai 	kfree(mrioc->op_reply_qinfo);
1401c9566231SKashyap Desai 	mrioc->op_reply_qinfo = NULL;
1402c9566231SKashyap Desai 
1403c9566231SKashyap Desai 	return retval;
1404c9566231SKashyap Desai }
1405c9566231SKashyap Desai 
1406c9566231SKashyap Desai /**
1407023ab2a9SKashyap Desai  * mpi3mr_op_request_post - Post request to operational queue
1408023ab2a9SKashyap Desai  * @mrioc: Adapter reference
1409023ab2a9SKashyap Desai  * @op_req_q: Operational request queue info
1410023ab2a9SKashyap Desai  * @req: MPI3 request
1411023ab2a9SKashyap Desai  *
1412023ab2a9SKashyap Desai  * Post the MPI3 request into operational request queue and
1413023ab2a9SKashyap Desai  * inform the controller, if the queue is full return
1414023ab2a9SKashyap Desai  * appropriate error.
1415023ab2a9SKashyap Desai  *
1416023ab2a9SKashyap Desai  * Return: 0 on success, non-zero on failure.
1417023ab2a9SKashyap Desai  */
1418023ab2a9SKashyap Desai int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc,
1419023ab2a9SKashyap Desai 	struct op_req_qinfo *op_req_q, u8 *req)
1420023ab2a9SKashyap Desai {
1421023ab2a9SKashyap Desai 	u16 pi = 0, max_entries, reply_qidx = 0, midx;
1422023ab2a9SKashyap Desai 	int retval = 0;
1423023ab2a9SKashyap Desai 	unsigned long flags;
1424023ab2a9SKashyap Desai 	u8 *req_entry;
1425023ab2a9SKashyap Desai 	void *segment_base_addr;
1426023ab2a9SKashyap Desai 	u16 req_sz = mrioc->facts.op_req_sz;
1427023ab2a9SKashyap Desai 	struct segments *segments = op_req_q->q_segments;
1428023ab2a9SKashyap Desai 
1429023ab2a9SKashyap Desai 	reply_qidx = op_req_q->reply_qid - 1;
1430023ab2a9SKashyap Desai 
1431023ab2a9SKashyap Desai 	if (mrioc->unrecoverable)
1432023ab2a9SKashyap Desai 		return -EFAULT;
1433023ab2a9SKashyap Desai 
1434023ab2a9SKashyap Desai 	spin_lock_irqsave(&op_req_q->q_lock, flags);
1435023ab2a9SKashyap Desai 	pi = op_req_q->pi;
1436023ab2a9SKashyap Desai 	max_entries = op_req_q->num_requests;
1437023ab2a9SKashyap Desai 
1438023ab2a9SKashyap Desai 	if (mpi3mr_check_req_qfull(op_req_q)) {
1439023ab2a9SKashyap Desai 		midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(
1440023ab2a9SKashyap Desai 		    reply_qidx, mrioc->op_reply_q_offset);
1441023ab2a9SKashyap Desai 		mpi3mr_process_op_reply_q(mrioc, &mrioc->intr_info[midx]);
1442023ab2a9SKashyap Desai 
1443023ab2a9SKashyap Desai 		if (mpi3mr_check_req_qfull(op_req_q)) {
1444023ab2a9SKashyap Desai 			retval = -EAGAIN;
1445023ab2a9SKashyap Desai 			goto out;
1446023ab2a9SKashyap Desai 		}
1447023ab2a9SKashyap Desai 	}
1448023ab2a9SKashyap Desai 
1449023ab2a9SKashyap Desai 	if (mrioc->reset_in_progress) {
1450023ab2a9SKashyap Desai 		ioc_err(mrioc, "OpReqQ submit reset in progress\n");
1451023ab2a9SKashyap Desai 		retval = -EAGAIN;
1452023ab2a9SKashyap Desai 		goto out;
1453023ab2a9SKashyap Desai 	}
1454023ab2a9SKashyap Desai 
1455023ab2a9SKashyap Desai 	segment_base_addr = segments[pi / op_req_q->segment_qd].segment;
1456023ab2a9SKashyap Desai 	req_entry = (u8 *)segment_base_addr +
1457023ab2a9SKashyap Desai 	    ((pi % op_req_q->segment_qd) * req_sz);
1458023ab2a9SKashyap Desai 
1459023ab2a9SKashyap Desai 	memset(req_entry, 0, req_sz);
1460023ab2a9SKashyap Desai 	memcpy(req_entry, req, MPI3MR_ADMIN_REQ_FRAME_SZ);
1461023ab2a9SKashyap Desai 
1462023ab2a9SKashyap Desai 	if (++pi == max_entries)
1463023ab2a9SKashyap Desai 		pi = 0;
1464023ab2a9SKashyap Desai 	op_req_q->pi = pi;
1465023ab2a9SKashyap Desai 
1466023ab2a9SKashyap Desai 	writel(op_req_q->pi,
1467023ab2a9SKashyap Desai 	    &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].producer_index);
1468023ab2a9SKashyap Desai 
1469023ab2a9SKashyap Desai out:
1470023ab2a9SKashyap Desai 	spin_unlock_irqrestore(&op_req_q->q_lock, flags);
1471023ab2a9SKashyap Desai 	return retval;
1472023ab2a9SKashyap Desai }
1473023ab2a9SKashyap Desai 
1474023ab2a9SKashyap Desai /**
1475672ae26cSKashyap Desai  * mpi3mr_watchdog_work - watchdog thread to monitor faults
1476672ae26cSKashyap Desai  * @work: work struct
1477672ae26cSKashyap Desai  *
1478672ae26cSKashyap Desai  * Watch dog work periodically executed (1 second interval) to
1479672ae26cSKashyap Desai  * monitor firmware fault and to issue periodic timer sync to
1480672ae26cSKashyap Desai  * the firmware.
1481672ae26cSKashyap Desai  *
1482672ae26cSKashyap Desai  * Return: Nothing.
1483672ae26cSKashyap Desai  */
1484672ae26cSKashyap Desai static void mpi3mr_watchdog_work(struct work_struct *work)
1485672ae26cSKashyap Desai {
1486672ae26cSKashyap Desai 	struct mpi3mr_ioc *mrioc =
1487672ae26cSKashyap Desai 	    container_of(work, struct mpi3mr_ioc, watchdog_work.work);
1488672ae26cSKashyap Desai 	unsigned long flags;
1489672ae26cSKashyap Desai 	enum mpi3mr_iocstate ioc_state;
1490672ae26cSKashyap Desai 	u32 fault, host_diagnostic;
1491672ae26cSKashyap Desai 
1492672ae26cSKashyap Desai 	/*Check for fault state every one second and issue Soft reset*/
1493672ae26cSKashyap Desai 	ioc_state = mpi3mr_get_iocstate(mrioc);
1494672ae26cSKashyap Desai 	if (ioc_state == MRIOC_STATE_FAULT) {
1495672ae26cSKashyap Desai 		fault = readl(&mrioc->sysif_regs->fault) &
1496672ae26cSKashyap Desai 		    MPI3_SYSIF_FAULT_CODE_MASK;
1497672ae26cSKashyap Desai 		host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic);
1498672ae26cSKashyap Desai 		if (host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS) {
1499672ae26cSKashyap Desai 			if (!mrioc->diagsave_timeout) {
1500672ae26cSKashyap Desai 				mpi3mr_print_fault_info(mrioc);
1501672ae26cSKashyap Desai 				ioc_warn(mrioc, "Diag save in progress\n");
1502672ae26cSKashyap Desai 			}
1503672ae26cSKashyap Desai 			if ((mrioc->diagsave_timeout++) <=
1504672ae26cSKashyap Desai 			    MPI3_SYSIF_DIAG_SAVE_TIMEOUT)
1505672ae26cSKashyap Desai 				goto schedule_work;
1506672ae26cSKashyap Desai 		} else
1507672ae26cSKashyap Desai 			mpi3mr_print_fault_info(mrioc);
1508672ae26cSKashyap Desai 		mrioc->diagsave_timeout = 0;
1509672ae26cSKashyap Desai 
1510672ae26cSKashyap Desai 		if (fault == MPI3_SYSIF_FAULT_CODE_FACTORY_RESET) {
1511672ae26cSKashyap Desai 			ioc_info(mrioc,
1512672ae26cSKashyap Desai 			    "Factory Reset fault occurred marking controller as unrecoverable"
1513672ae26cSKashyap Desai 			    );
1514672ae26cSKashyap Desai 			mrioc->unrecoverable = 1;
1515672ae26cSKashyap Desai 			goto out;
1516672ae26cSKashyap Desai 		}
1517672ae26cSKashyap Desai 
1518672ae26cSKashyap Desai 		if ((fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET) ||
1519672ae26cSKashyap Desai 		    (fault == MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS) ||
1520672ae26cSKashyap Desai 		    (mrioc->reset_in_progress))
1521672ae26cSKashyap Desai 			goto out;
1522672ae26cSKashyap Desai 		if (fault == MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET)
1523672ae26cSKashyap Desai 			mpi3mr_soft_reset_handler(mrioc,
1524672ae26cSKashyap Desai 			    MPI3MR_RESET_FROM_CIACTIV_FAULT, 0);
1525672ae26cSKashyap Desai 		else
1526672ae26cSKashyap Desai 			mpi3mr_soft_reset_handler(mrioc,
1527672ae26cSKashyap Desai 			    MPI3MR_RESET_FROM_FAULT_WATCH, 0);
1528672ae26cSKashyap Desai 	}
1529672ae26cSKashyap Desai 
1530672ae26cSKashyap Desai schedule_work:
1531672ae26cSKashyap Desai 	spin_lock_irqsave(&mrioc->watchdog_lock, flags);
1532672ae26cSKashyap Desai 	if (mrioc->watchdog_work_q)
1533672ae26cSKashyap Desai 		queue_delayed_work(mrioc->watchdog_work_q,
1534672ae26cSKashyap Desai 		    &mrioc->watchdog_work,
1535672ae26cSKashyap Desai 		    msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL));
1536672ae26cSKashyap Desai 	spin_unlock_irqrestore(&mrioc->watchdog_lock, flags);
1537672ae26cSKashyap Desai out:
1538672ae26cSKashyap Desai 	return;
1539672ae26cSKashyap Desai }
1540672ae26cSKashyap Desai 
1541672ae26cSKashyap Desai /**
1542672ae26cSKashyap Desai  * mpi3mr_start_watchdog - Start watchdog
1543672ae26cSKashyap Desai  * @mrioc: Adapter instance reference
1544672ae26cSKashyap Desai  *
1545672ae26cSKashyap Desai  * Create and start the watchdog thread to monitor controller
1546672ae26cSKashyap Desai  * faults.
1547672ae26cSKashyap Desai  *
1548672ae26cSKashyap Desai  * Return: Nothing.
1549672ae26cSKashyap Desai  */
1550672ae26cSKashyap Desai void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc)
1551672ae26cSKashyap Desai {
1552672ae26cSKashyap Desai 	if (mrioc->watchdog_work_q)
1553672ae26cSKashyap Desai 		return;
1554672ae26cSKashyap Desai 
1555672ae26cSKashyap Desai 	INIT_DELAYED_WORK(&mrioc->watchdog_work, mpi3mr_watchdog_work);
1556672ae26cSKashyap Desai 	snprintf(mrioc->watchdog_work_q_name,
1557672ae26cSKashyap Desai 	    sizeof(mrioc->watchdog_work_q_name), "watchdog_%s%d", mrioc->name,
1558672ae26cSKashyap Desai 	    mrioc->id);
1559672ae26cSKashyap Desai 	mrioc->watchdog_work_q =
1560672ae26cSKashyap Desai 	    create_singlethread_workqueue(mrioc->watchdog_work_q_name);
1561672ae26cSKashyap Desai 	if (!mrioc->watchdog_work_q) {
1562672ae26cSKashyap Desai 		ioc_err(mrioc, "%s: failed (line=%d)\n", __func__, __LINE__);
1563672ae26cSKashyap Desai 		return;
1564672ae26cSKashyap Desai 	}
1565672ae26cSKashyap Desai 
1566672ae26cSKashyap Desai 	if (mrioc->watchdog_work_q)
1567672ae26cSKashyap Desai 		queue_delayed_work(mrioc->watchdog_work_q,
1568672ae26cSKashyap Desai 		    &mrioc->watchdog_work,
1569672ae26cSKashyap Desai 		    msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL));
1570672ae26cSKashyap Desai }
1571672ae26cSKashyap Desai 
1572672ae26cSKashyap Desai /**
1573672ae26cSKashyap Desai  * mpi3mr_stop_watchdog - Stop watchdog
1574672ae26cSKashyap Desai  * @mrioc: Adapter instance reference
1575672ae26cSKashyap Desai  *
1576672ae26cSKashyap Desai  * Stop the watchdog thread created to monitor controller
1577672ae26cSKashyap Desai  * faults.
1578672ae26cSKashyap Desai  *
1579672ae26cSKashyap Desai  * Return: Nothing.
1580672ae26cSKashyap Desai  */
1581672ae26cSKashyap Desai void mpi3mr_stop_watchdog(struct mpi3mr_ioc *mrioc)
1582672ae26cSKashyap Desai {
1583672ae26cSKashyap Desai 	unsigned long flags;
1584672ae26cSKashyap Desai 	struct workqueue_struct *wq;
1585672ae26cSKashyap Desai 
1586672ae26cSKashyap Desai 	spin_lock_irqsave(&mrioc->watchdog_lock, flags);
1587672ae26cSKashyap Desai 	wq = mrioc->watchdog_work_q;
1588672ae26cSKashyap Desai 	mrioc->watchdog_work_q = NULL;
1589672ae26cSKashyap Desai 	spin_unlock_irqrestore(&mrioc->watchdog_lock, flags);
1590672ae26cSKashyap Desai 	if (wq) {
1591672ae26cSKashyap Desai 		if (!cancel_delayed_work_sync(&mrioc->watchdog_work))
1592672ae26cSKashyap Desai 			flush_workqueue(wq);
1593672ae26cSKashyap Desai 		destroy_workqueue(wq);
1594672ae26cSKashyap Desai 	}
1595672ae26cSKashyap Desai }
1596672ae26cSKashyap Desai 
1597672ae26cSKashyap Desai /**
1598*fb9b0457SKashyap Desai  * mpi3mr_kill_ioc - Kill the controller
1599*fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
1600*fb9b0457SKashyap Desai  * @reason: reason for the failure.
1601*fb9b0457SKashyap Desai  *
1602*fb9b0457SKashyap Desai  * If fault debug is enabled, display the fault info else issue
1603*fb9b0457SKashyap Desai  * diag fault and freeze the system for controller debug
1604*fb9b0457SKashyap Desai  * purpose.
1605*fb9b0457SKashyap Desai  *
1606*fb9b0457SKashyap Desai  * Return: Nothing.
1607*fb9b0457SKashyap Desai  */
1608*fb9b0457SKashyap Desai static void mpi3mr_kill_ioc(struct mpi3mr_ioc *mrioc, u32 reason)
1609*fb9b0457SKashyap Desai {
1610*fb9b0457SKashyap Desai 	enum mpi3mr_iocstate ioc_state;
1611*fb9b0457SKashyap Desai 
1612*fb9b0457SKashyap Desai 	if (!mrioc->fault_dbg)
1613*fb9b0457SKashyap Desai 		return;
1614*fb9b0457SKashyap Desai 
1615*fb9b0457SKashyap Desai 	dump_stack();
1616*fb9b0457SKashyap Desai 
1617*fb9b0457SKashyap Desai 	ioc_state = mpi3mr_get_iocstate(mrioc);
1618*fb9b0457SKashyap Desai 	if (ioc_state == MRIOC_STATE_FAULT)
1619*fb9b0457SKashyap Desai 		mpi3mr_print_fault_info(mrioc);
1620*fb9b0457SKashyap Desai 	else {
1621*fb9b0457SKashyap Desai 		ioc_err(mrioc, "Firmware is halted due to the reason %d\n",
1622*fb9b0457SKashyap Desai 		    reason);
1623*fb9b0457SKashyap Desai 		mpi3mr_diagfault_reset_handler(mrioc, reason);
1624*fb9b0457SKashyap Desai 	}
1625*fb9b0457SKashyap Desai 	if (mrioc->fault_dbg == 2)
1626*fb9b0457SKashyap Desai 		for (;;)
1627*fb9b0457SKashyap Desai 			;
1628*fb9b0457SKashyap Desai 	else
1629*fb9b0457SKashyap Desai 		panic("panic in %s\n", __func__);
1630*fb9b0457SKashyap Desai }
1631*fb9b0457SKashyap Desai 
1632*fb9b0457SKashyap Desai /**
1633824a1566SKashyap Desai  * mpi3mr_setup_admin_qpair - Setup admin queue pair
1634824a1566SKashyap Desai  * @mrioc: Adapter instance reference
1635824a1566SKashyap Desai  *
1636824a1566SKashyap Desai  * Allocate memory for admin queue pair if required and register
1637824a1566SKashyap Desai  * the admin queue with the controller.
1638824a1566SKashyap Desai  *
1639824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
1640824a1566SKashyap Desai  */
1641824a1566SKashyap Desai static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc)
1642824a1566SKashyap Desai {
1643824a1566SKashyap Desai 	int retval = 0;
1644824a1566SKashyap Desai 	u32 num_admin_entries = 0;
1645824a1566SKashyap Desai 
1646824a1566SKashyap Desai 	mrioc->admin_req_q_sz = MPI3MR_ADMIN_REQ_Q_SIZE;
1647824a1566SKashyap Desai 	mrioc->num_admin_req = mrioc->admin_req_q_sz /
1648824a1566SKashyap Desai 	    MPI3MR_ADMIN_REQ_FRAME_SZ;
1649824a1566SKashyap Desai 	mrioc->admin_req_ci = mrioc->admin_req_pi = 0;
1650824a1566SKashyap Desai 	mrioc->admin_req_base = NULL;
1651824a1566SKashyap Desai 
1652824a1566SKashyap Desai 	mrioc->admin_reply_q_sz = MPI3MR_ADMIN_REPLY_Q_SIZE;
1653824a1566SKashyap Desai 	mrioc->num_admin_replies = mrioc->admin_reply_q_sz /
1654824a1566SKashyap Desai 	    MPI3MR_ADMIN_REPLY_FRAME_SZ;
1655824a1566SKashyap Desai 	mrioc->admin_reply_ci = 0;
1656824a1566SKashyap Desai 	mrioc->admin_reply_ephase = 1;
1657824a1566SKashyap Desai 	mrioc->admin_reply_base = NULL;
1658824a1566SKashyap Desai 
1659824a1566SKashyap Desai 	if (!mrioc->admin_req_base) {
1660824a1566SKashyap Desai 		mrioc->admin_req_base = dma_alloc_coherent(&mrioc->pdev->dev,
1661824a1566SKashyap Desai 		    mrioc->admin_req_q_sz, &mrioc->admin_req_dma, GFP_KERNEL);
1662824a1566SKashyap Desai 
1663824a1566SKashyap Desai 		if (!mrioc->admin_req_base) {
1664824a1566SKashyap Desai 			retval = -1;
1665824a1566SKashyap Desai 			goto out_failed;
1666824a1566SKashyap Desai 		}
1667824a1566SKashyap Desai 
1668824a1566SKashyap Desai 		mrioc->admin_reply_base = dma_alloc_coherent(&mrioc->pdev->dev,
1669824a1566SKashyap Desai 		    mrioc->admin_reply_q_sz, &mrioc->admin_reply_dma,
1670824a1566SKashyap Desai 		    GFP_KERNEL);
1671824a1566SKashyap Desai 
1672824a1566SKashyap Desai 		if (!mrioc->admin_reply_base) {
1673824a1566SKashyap Desai 			retval = -1;
1674824a1566SKashyap Desai 			goto out_failed;
1675824a1566SKashyap Desai 		}
1676824a1566SKashyap Desai 	}
1677824a1566SKashyap Desai 
1678824a1566SKashyap Desai 	num_admin_entries = (mrioc->num_admin_replies << 16) |
1679824a1566SKashyap Desai 	    (mrioc->num_admin_req);
1680824a1566SKashyap Desai 	writel(num_admin_entries, &mrioc->sysif_regs->admin_queue_num_entries);
1681824a1566SKashyap Desai 	mpi3mr_writeq(mrioc->admin_req_dma,
1682824a1566SKashyap Desai 	    &mrioc->sysif_regs->admin_request_queue_address);
1683824a1566SKashyap Desai 	mpi3mr_writeq(mrioc->admin_reply_dma,
1684824a1566SKashyap Desai 	    &mrioc->sysif_regs->admin_reply_queue_address);
1685824a1566SKashyap Desai 	writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi);
1686824a1566SKashyap Desai 	writel(mrioc->admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci);
1687824a1566SKashyap Desai 	return retval;
1688824a1566SKashyap Desai 
1689824a1566SKashyap Desai out_failed:
1690824a1566SKashyap Desai 
1691824a1566SKashyap Desai 	if (mrioc->admin_reply_base) {
1692824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz,
1693824a1566SKashyap Desai 		    mrioc->admin_reply_base, mrioc->admin_reply_dma);
1694824a1566SKashyap Desai 		mrioc->admin_reply_base = NULL;
1695824a1566SKashyap Desai 	}
1696824a1566SKashyap Desai 	if (mrioc->admin_req_base) {
1697824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz,
1698824a1566SKashyap Desai 		    mrioc->admin_req_base, mrioc->admin_req_dma);
1699824a1566SKashyap Desai 		mrioc->admin_req_base = NULL;
1700824a1566SKashyap Desai 	}
1701824a1566SKashyap Desai 	return retval;
1702824a1566SKashyap Desai }
1703824a1566SKashyap Desai 
1704824a1566SKashyap Desai /**
1705824a1566SKashyap Desai  * mpi3mr_issue_iocfacts - Send IOC Facts
1706824a1566SKashyap Desai  * @mrioc: Adapter instance reference
1707824a1566SKashyap Desai  * @facts_data: Cached IOC facts data
1708824a1566SKashyap Desai  *
1709824a1566SKashyap Desai  * Issue IOC Facts MPI request through admin queue and wait for
1710824a1566SKashyap Desai  * the completion of it or time out.
1711824a1566SKashyap Desai  *
1712824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
1713824a1566SKashyap Desai  */
1714824a1566SKashyap Desai static int mpi3mr_issue_iocfacts(struct mpi3mr_ioc *mrioc,
1715824a1566SKashyap Desai 	struct mpi3_ioc_facts_data *facts_data)
1716824a1566SKashyap Desai {
1717824a1566SKashyap Desai 	struct mpi3_ioc_facts_request iocfacts_req;
1718824a1566SKashyap Desai 	void *data = NULL;
1719824a1566SKashyap Desai 	dma_addr_t data_dma;
1720824a1566SKashyap Desai 	u32 data_len = sizeof(*facts_data);
1721824a1566SKashyap Desai 	int retval = 0;
1722824a1566SKashyap Desai 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
1723824a1566SKashyap Desai 
1724824a1566SKashyap Desai 	data = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma,
1725824a1566SKashyap Desai 	    GFP_KERNEL);
1726824a1566SKashyap Desai 
1727824a1566SKashyap Desai 	if (!data) {
1728824a1566SKashyap Desai 		retval = -1;
1729824a1566SKashyap Desai 		goto out;
1730824a1566SKashyap Desai 	}
1731824a1566SKashyap Desai 
1732824a1566SKashyap Desai 	memset(&iocfacts_req, 0, sizeof(iocfacts_req));
1733824a1566SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
1734824a1566SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
1735824a1566SKashyap Desai 		retval = -1;
1736824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCFacts: Init command is in use\n");
1737824a1566SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
1738824a1566SKashyap Desai 		goto out;
1739824a1566SKashyap Desai 	}
1740824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
1741824a1566SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
1742824a1566SKashyap Desai 	mrioc->init_cmds.callback = NULL;
1743824a1566SKashyap Desai 	iocfacts_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
1744824a1566SKashyap Desai 	iocfacts_req.function = MPI3_FUNCTION_IOC_FACTS;
1745824a1566SKashyap Desai 
1746824a1566SKashyap Desai 	mpi3mr_add_sg_single(&iocfacts_req.sgl, sgl_flags, data_len,
1747824a1566SKashyap Desai 	    data_dma);
1748824a1566SKashyap Desai 
1749824a1566SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
1750824a1566SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &iocfacts_req,
1751824a1566SKashyap Desai 	    sizeof(iocfacts_req), 1);
1752824a1566SKashyap Desai 	if (retval) {
1753824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCFacts: Admin Post failed\n");
1754824a1566SKashyap Desai 		goto out_unlock;
1755824a1566SKashyap Desai 	}
1756824a1566SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
1757824a1566SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
1758824a1566SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
1759824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCFacts: command timed out\n");
1760824a1566SKashyap Desai 		mpi3mr_set_diagsave(mrioc);
1761824a1566SKashyap Desai 		mpi3mr_issue_reset(mrioc,
1762824a1566SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
1763824a1566SKashyap Desai 		    MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT);
1764824a1566SKashyap Desai 		mrioc->unrecoverable = 1;
1765824a1566SKashyap Desai 		retval = -1;
1766824a1566SKashyap Desai 		goto out_unlock;
1767824a1566SKashyap Desai 	}
1768824a1566SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
1769824a1566SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
1770824a1566SKashyap Desai 		ioc_err(mrioc,
1771824a1566SKashyap Desai 		    "Issue IOCFacts: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
1772824a1566SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
1773824a1566SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
1774824a1566SKashyap Desai 		retval = -1;
1775824a1566SKashyap Desai 		goto out_unlock;
1776824a1566SKashyap Desai 	}
1777824a1566SKashyap Desai 	memcpy(facts_data, (u8 *)data, data_len);
1778824a1566SKashyap Desai out_unlock:
1779824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
1780824a1566SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
1781824a1566SKashyap Desai 
1782824a1566SKashyap Desai out:
1783824a1566SKashyap Desai 	if (data)
1784824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, data_len, data, data_dma);
1785824a1566SKashyap Desai 
1786824a1566SKashyap Desai 	return retval;
1787824a1566SKashyap Desai }
1788824a1566SKashyap Desai 
1789824a1566SKashyap Desai /**
1790824a1566SKashyap Desai  * mpi3mr_check_reset_dma_mask - Process IOC facts data
1791824a1566SKashyap Desai  * @mrioc: Adapter instance reference
1792824a1566SKashyap Desai  *
1793824a1566SKashyap Desai  * Check whether the new DMA mask requested through IOCFacts by
1794824a1566SKashyap Desai  * firmware needs to be set, if so set it .
1795824a1566SKashyap Desai  *
1796824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
1797824a1566SKashyap Desai  */
1798824a1566SKashyap Desai static inline int mpi3mr_check_reset_dma_mask(struct mpi3mr_ioc *mrioc)
1799824a1566SKashyap Desai {
1800824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
1801824a1566SKashyap Desai 	int r;
1802824a1566SKashyap Desai 	u64 facts_dma_mask = DMA_BIT_MASK(mrioc->facts.dma_mask);
1803824a1566SKashyap Desai 
1804824a1566SKashyap Desai 	if (!mrioc->facts.dma_mask || (mrioc->dma_mask <= facts_dma_mask))
1805824a1566SKashyap Desai 		return 0;
1806824a1566SKashyap Desai 
1807824a1566SKashyap Desai 	ioc_info(mrioc, "Changing DMA mask from 0x%016llx to 0x%016llx\n",
1808824a1566SKashyap Desai 	    mrioc->dma_mask, facts_dma_mask);
1809824a1566SKashyap Desai 
1810824a1566SKashyap Desai 	r = dma_set_mask_and_coherent(&pdev->dev, facts_dma_mask);
1811824a1566SKashyap Desai 	if (r) {
1812824a1566SKashyap Desai 		ioc_err(mrioc, "Setting DMA mask to 0x%016llx failed: %d\n",
1813824a1566SKashyap Desai 		    facts_dma_mask, r);
1814824a1566SKashyap Desai 		return r;
1815824a1566SKashyap Desai 	}
1816824a1566SKashyap Desai 	mrioc->dma_mask = facts_dma_mask;
1817824a1566SKashyap Desai 	return r;
1818824a1566SKashyap Desai }
1819824a1566SKashyap Desai 
1820824a1566SKashyap Desai /**
1821824a1566SKashyap Desai  * mpi3mr_process_factsdata - Process IOC facts data
1822824a1566SKashyap Desai  * @mrioc: Adapter instance reference
1823824a1566SKashyap Desai  * @facts_data: Cached IOC facts data
1824824a1566SKashyap Desai  *
1825824a1566SKashyap Desai  * Convert IOC facts data into cpu endianness and cache it in
1826824a1566SKashyap Desai  * the driver .
1827824a1566SKashyap Desai  *
1828824a1566SKashyap Desai  * Return: Nothing.
1829824a1566SKashyap Desai  */
1830824a1566SKashyap Desai static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc,
1831824a1566SKashyap Desai 	struct mpi3_ioc_facts_data *facts_data)
1832824a1566SKashyap Desai {
1833824a1566SKashyap Desai 	u32 ioc_config, req_sz, facts_flags;
1834824a1566SKashyap Desai 
1835824a1566SKashyap Desai 	if ((le16_to_cpu(facts_data->ioc_facts_data_length)) !=
1836824a1566SKashyap Desai 	    (sizeof(*facts_data) / 4)) {
1837824a1566SKashyap Desai 		ioc_warn(mrioc,
1838824a1566SKashyap Desai 		    "IOCFactsdata length mismatch driver_sz(%zu) firmware_sz(%d)\n",
1839824a1566SKashyap Desai 		    sizeof(*facts_data),
1840824a1566SKashyap Desai 		    le16_to_cpu(facts_data->ioc_facts_data_length) * 4);
1841824a1566SKashyap Desai 	}
1842824a1566SKashyap Desai 
1843824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
1844824a1566SKashyap Desai 	req_sz = 1 << ((ioc_config & MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ) >>
1845824a1566SKashyap Desai 	    MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ_SHIFT);
1846824a1566SKashyap Desai 	if (le16_to_cpu(facts_data->ioc_request_frame_size) != (req_sz / 4)) {
1847824a1566SKashyap Desai 		ioc_err(mrioc,
1848824a1566SKashyap Desai 		    "IOCFacts data reqFrameSize mismatch hw_size(%d) firmware_sz(%d)\n",
1849824a1566SKashyap Desai 		    req_sz / 4, le16_to_cpu(facts_data->ioc_request_frame_size));
1850824a1566SKashyap Desai 	}
1851824a1566SKashyap Desai 
1852824a1566SKashyap Desai 	memset(&mrioc->facts, 0, sizeof(mrioc->facts));
1853824a1566SKashyap Desai 
1854824a1566SKashyap Desai 	facts_flags = le32_to_cpu(facts_data->flags);
1855824a1566SKashyap Desai 	mrioc->facts.op_req_sz = req_sz;
1856824a1566SKashyap Desai 	mrioc->op_reply_desc_sz = 1 << ((ioc_config &
1857824a1566SKashyap Desai 	    MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ) >>
1858824a1566SKashyap Desai 	    MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ_SHIFT);
1859824a1566SKashyap Desai 
1860824a1566SKashyap Desai 	mrioc->facts.ioc_num = facts_data->ioc_number;
1861824a1566SKashyap Desai 	mrioc->facts.who_init = facts_data->who_init;
1862824a1566SKashyap Desai 	mrioc->facts.max_msix_vectors = le16_to_cpu(facts_data->max_msix_vectors);
1863824a1566SKashyap Desai 	mrioc->facts.personality = (facts_flags &
1864824a1566SKashyap Desai 	    MPI3_IOCFACTS_FLAGS_PERSONALITY_MASK);
1865824a1566SKashyap Desai 	mrioc->facts.dma_mask = (facts_flags &
1866824a1566SKashyap Desai 	    MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >>
1867824a1566SKashyap Desai 	    MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT;
1868824a1566SKashyap Desai 	mrioc->facts.protocol_flags = facts_data->protocol_flags;
1869824a1566SKashyap Desai 	mrioc->facts.mpi_version = le32_to_cpu(facts_data->mpi_version.word);
1870824a1566SKashyap Desai 	mrioc->facts.max_reqs = le16_to_cpu(facts_data->max_outstanding_request);
1871824a1566SKashyap Desai 	mrioc->facts.product_id = le16_to_cpu(facts_data->product_id);
1872824a1566SKashyap Desai 	mrioc->facts.reply_sz = le16_to_cpu(facts_data->reply_frame_size) * 4;
1873824a1566SKashyap Desai 	mrioc->facts.exceptions = le16_to_cpu(facts_data->ioc_exceptions);
1874824a1566SKashyap Desai 	mrioc->facts.max_perids = le16_to_cpu(facts_data->max_persistent_id);
1875824a1566SKashyap Desai 	mrioc->facts.max_pds = le16_to_cpu(facts_data->max_pds);
1876824a1566SKashyap Desai 	mrioc->facts.max_vds = le16_to_cpu(facts_data->max_vds);
1877824a1566SKashyap Desai 	mrioc->facts.max_hpds = le16_to_cpu(facts_data->max_host_pds);
1878824a1566SKashyap Desai 	mrioc->facts.max_advhpds = le16_to_cpu(facts_data->max_advanced_host_pds);
1879824a1566SKashyap Desai 	mrioc->facts.max_raidpds = le16_to_cpu(facts_data->max_raid_pds);
1880824a1566SKashyap Desai 	mrioc->facts.max_nvme = le16_to_cpu(facts_data->max_nvme);
1881824a1566SKashyap Desai 	mrioc->facts.max_pcie_switches =
1882824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_pc_ie_switches);
1883824a1566SKashyap Desai 	mrioc->facts.max_sasexpanders =
1884824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_sas_expanders);
1885824a1566SKashyap Desai 	mrioc->facts.max_sasinitiators =
1886824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_sas_initiators);
1887824a1566SKashyap Desai 	mrioc->facts.max_enclosures = le16_to_cpu(facts_data->max_enclosures);
1888824a1566SKashyap Desai 	mrioc->facts.min_devhandle = le16_to_cpu(facts_data->min_dev_handle);
1889824a1566SKashyap Desai 	mrioc->facts.max_devhandle = le16_to_cpu(facts_data->max_dev_handle);
1890824a1566SKashyap Desai 	mrioc->facts.max_op_req_q =
1891824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_operational_request_queues);
1892824a1566SKashyap Desai 	mrioc->facts.max_op_reply_q =
1893824a1566SKashyap Desai 	    le16_to_cpu(facts_data->max_operational_reply_queues);
1894824a1566SKashyap Desai 	mrioc->facts.ioc_capabilities =
1895824a1566SKashyap Desai 	    le32_to_cpu(facts_data->ioc_capabilities);
1896824a1566SKashyap Desai 	mrioc->facts.fw_ver.build_num =
1897824a1566SKashyap Desai 	    le16_to_cpu(facts_data->fw_version.build_num);
1898824a1566SKashyap Desai 	mrioc->facts.fw_ver.cust_id =
1899824a1566SKashyap Desai 	    le16_to_cpu(facts_data->fw_version.customer_id);
1900824a1566SKashyap Desai 	mrioc->facts.fw_ver.ph_minor = facts_data->fw_version.phase_minor;
1901824a1566SKashyap Desai 	mrioc->facts.fw_ver.ph_major = facts_data->fw_version.phase_major;
1902824a1566SKashyap Desai 	mrioc->facts.fw_ver.gen_minor = facts_data->fw_version.gen_minor;
1903824a1566SKashyap Desai 	mrioc->facts.fw_ver.gen_major = facts_data->fw_version.gen_major;
1904824a1566SKashyap Desai 	mrioc->msix_count = min_t(int, mrioc->msix_count,
1905824a1566SKashyap Desai 	    mrioc->facts.max_msix_vectors);
1906824a1566SKashyap Desai 	mrioc->facts.sge_mod_mask = facts_data->sge_modifier_mask;
1907824a1566SKashyap Desai 	mrioc->facts.sge_mod_value = facts_data->sge_modifier_value;
1908824a1566SKashyap Desai 	mrioc->facts.sge_mod_shift = facts_data->sge_modifier_shift;
1909824a1566SKashyap Desai 	mrioc->facts.shutdown_timeout =
1910824a1566SKashyap Desai 	    le16_to_cpu(facts_data->shutdown_timeout);
1911824a1566SKashyap Desai 
1912824a1566SKashyap Desai 	ioc_info(mrioc, "ioc_num(%d), maxopQ(%d), maxopRepQ(%d), maxdh(%d),",
1913824a1566SKashyap Desai 	    mrioc->facts.ioc_num, mrioc->facts.max_op_req_q,
1914824a1566SKashyap Desai 	    mrioc->facts.max_op_reply_q, mrioc->facts.max_devhandle);
1915824a1566SKashyap Desai 	ioc_info(mrioc,
1916824a1566SKashyap Desai 	    "maxreqs(%d), mindh(%d) maxPDs(%d) maxvectors(%d) maxperids(%d)\n",
1917824a1566SKashyap Desai 	    mrioc->facts.max_reqs, mrioc->facts.min_devhandle,
1918824a1566SKashyap Desai 	    mrioc->facts.max_pds, mrioc->facts.max_msix_vectors,
1919824a1566SKashyap Desai 	    mrioc->facts.max_perids);
1920824a1566SKashyap Desai 	ioc_info(mrioc, "SGEModMask 0x%x SGEModVal 0x%x SGEModShift 0x%x ",
1921824a1566SKashyap Desai 	    mrioc->facts.sge_mod_mask, mrioc->facts.sge_mod_value,
1922824a1566SKashyap Desai 	    mrioc->facts.sge_mod_shift);
1923824a1566SKashyap Desai 	ioc_info(mrioc, "DMA mask %d InitialPE status 0x%x\n",
1924824a1566SKashyap Desai 	    mrioc->facts.dma_mask, (facts_flags &
1925824a1566SKashyap Desai 	    MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK));
1926824a1566SKashyap Desai 
1927824a1566SKashyap Desai 	mrioc->max_host_ios = mrioc->facts.max_reqs - MPI3MR_INTERNAL_CMDS_RESVD;
1928824a1566SKashyap Desai 
1929824a1566SKashyap Desai 	if (reset_devices)
1930824a1566SKashyap Desai 		mrioc->max_host_ios = min_t(int, mrioc->max_host_ios,
1931824a1566SKashyap Desai 		    MPI3MR_HOST_IOS_KDUMP);
1932824a1566SKashyap Desai }
1933824a1566SKashyap Desai 
1934824a1566SKashyap Desai /**
1935824a1566SKashyap Desai  * mpi3mr_alloc_reply_sense_bufs - Send IOC Init
1936824a1566SKashyap Desai  * @mrioc: Adapter instance reference
1937824a1566SKashyap Desai  *
1938824a1566SKashyap Desai  * Allocate and initialize the reply free buffers, sense
1939824a1566SKashyap Desai  * buffers, reply free queue and sense buffer queue.
1940824a1566SKashyap Desai  *
1941824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
1942824a1566SKashyap Desai  */
1943824a1566SKashyap Desai static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc)
1944824a1566SKashyap Desai {
1945824a1566SKashyap Desai 	int retval = 0;
1946824a1566SKashyap Desai 	u32 sz, i;
1947824a1566SKashyap Desai 	dma_addr_t phy_addr;
1948824a1566SKashyap Desai 
1949824a1566SKashyap Desai 	if (mrioc->init_cmds.reply)
1950824a1566SKashyap Desai 		goto post_reply_sbuf;
1951824a1566SKashyap Desai 
1952824a1566SKashyap Desai 	mrioc->init_cmds.reply = kzalloc(mrioc->facts.reply_sz, GFP_KERNEL);
1953824a1566SKashyap Desai 	if (!mrioc->init_cmds.reply)
1954824a1566SKashyap Desai 		goto out_failed;
1955824a1566SKashyap Desai 
195613ef29eaSKashyap Desai 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
195713ef29eaSKashyap Desai 		mrioc->dev_rmhs_cmds[i].reply = kzalloc(mrioc->facts.reply_sz,
195813ef29eaSKashyap Desai 		    GFP_KERNEL);
195913ef29eaSKashyap Desai 		if (!mrioc->dev_rmhs_cmds[i].reply)
196013ef29eaSKashyap Desai 			goto out_failed;
196113ef29eaSKashyap Desai 	}
196213ef29eaSKashyap Desai 
1963824a1566SKashyap Desai 	mrioc->num_reply_bufs = mrioc->facts.max_reqs + MPI3MR_NUM_EVT_REPLIES;
1964824a1566SKashyap Desai 	mrioc->reply_free_qsz = mrioc->num_reply_bufs + 1;
1965824a1566SKashyap Desai 	mrioc->num_sense_bufs = mrioc->facts.max_reqs / MPI3MR_SENSEBUF_FACTOR;
1966824a1566SKashyap Desai 	mrioc->sense_buf_q_sz = mrioc->num_sense_bufs + 1;
1967824a1566SKashyap Desai 
1968824a1566SKashyap Desai 	/* reply buffer pool, 16 byte align */
1969824a1566SKashyap Desai 	sz = mrioc->num_reply_bufs * mrioc->facts.reply_sz;
1970824a1566SKashyap Desai 	mrioc->reply_buf_pool = dma_pool_create("reply_buf pool",
1971824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 16, 0);
1972824a1566SKashyap Desai 	if (!mrioc->reply_buf_pool) {
1973824a1566SKashyap Desai 		ioc_err(mrioc, "reply buf pool: dma_pool_create failed\n");
1974824a1566SKashyap Desai 		goto out_failed;
1975824a1566SKashyap Desai 	}
1976824a1566SKashyap Desai 
1977824a1566SKashyap Desai 	mrioc->reply_buf = dma_pool_zalloc(mrioc->reply_buf_pool, GFP_KERNEL,
1978824a1566SKashyap Desai 	    &mrioc->reply_buf_dma);
1979824a1566SKashyap Desai 	if (!mrioc->reply_buf)
1980824a1566SKashyap Desai 		goto out_failed;
1981824a1566SKashyap Desai 
1982824a1566SKashyap Desai 	mrioc->reply_buf_dma_max_address = mrioc->reply_buf_dma + sz;
1983824a1566SKashyap Desai 
1984824a1566SKashyap Desai 	/* reply free queue, 8 byte align */
1985824a1566SKashyap Desai 	sz = mrioc->reply_free_qsz * 8;
1986824a1566SKashyap Desai 	mrioc->reply_free_q_pool = dma_pool_create("reply_free_q pool",
1987824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 8, 0);
1988824a1566SKashyap Desai 	if (!mrioc->reply_free_q_pool) {
1989824a1566SKashyap Desai 		ioc_err(mrioc, "reply_free_q pool: dma_pool_create failed\n");
1990824a1566SKashyap Desai 		goto out_failed;
1991824a1566SKashyap Desai 	}
1992824a1566SKashyap Desai 	mrioc->reply_free_q = dma_pool_zalloc(mrioc->reply_free_q_pool,
1993824a1566SKashyap Desai 	    GFP_KERNEL, &mrioc->reply_free_q_dma);
1994824a1566SKashyap Desai 	if (!mrioc->reply_free_q)
1995824a1566SKashyap Desai 		goto out_failed;
1996824a1566SKashyap Desai 
1997824a1566SKashyap Desai 	/* sense buffer pool,  4 byte align */
1998824a1566SKashyap Desai 	sz = mrioc->num_sense_bufs * MPI3MR_SENSEBUF_SZ;
1999824a1566SKashyap Desai 	mrioc->sense_buf_pool = dma_pool_create("sense_buf pool",
2000824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 4, 0);
2001824a1566SKashyap Desai 	if (!mrioc->sense_buf_pool) {
2002824a1566SKashyap Desai 		ioc_err(mrioc, "sense_buf pool: dma_pool_create failed\n");
2003824a1566SKashyap Desai 		goto out_failed;
2004824a1566SKashyap Desai 	}
2005824a1566SKashyap Desai 	mrioc->sense_buf = dma_pool_zalloc(mrioc->sense_buf_pool, GFP_KERNEL,
2006824a1566SKashyap Desai 	    &mrioc->sense_buf_dma);
2007824a1566SKashyap Desai 	if (!mrioc->sense_buf)
2008824a1566SKashyap Desai 		goto out_failed;
2009824a1566SKashyap Desai 
2010824a1566SKashyap Desai 	/* sense buffer queue, 8 byte align */
2011824a1566SKashyap Desai 	sz = mrioc->sense_buf_q_sz * 8;
2012824a1566SKashyap Desai 	mrioc->sense_buf_q_pool = dma_pool_create("sense_buf_q pool",
2013824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 8, 0);
2014824a1566SKashyap Desai 	if (!mrioc->sense_buf_q_pool) {
2015824a1566SKashyap Desai 		ioc_err(mrioc, "sense_buf_q pool: dma_pool_create failed\n");
2016824a1566SKashyap Desai 		goto out_failed;
2017824a1566SKashyap Desai 	}
2018824a1566SKashyap Desai 	mrioc->sense_buf_q = dma_pool_zalloc(mrioc->sense_buf_q_pool,
2019824a1566SKashyap Desai 	    GFP_KERNEL, &mrioc->sense_buf_q_dma);
2020824a1566SKashyap Desai 	if (!mrioc->sense_buf_q)
2021824a1566SKashyap Desai 		goto out_failed;
2022824a1566SKashyap Desai 
2023824a1566SKashyap Desai post_reply_sbuf:
2024824a1566SKashyap Desai 	sz = mrioc->num_reply_bufs * mrioc->facts.reply_sz;
2025824a1566SKashyap Desai 	ioc_info(mrioc,
2026824a1566SKashyap Desai 	    "reply buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n",
2027824a1566SKashyap Desai 	    mrioc->reply_buf, mrioc->num_reply_bufs, mrioc->facts.reply_sz,
2028824a1566SKashyap Desai 	    (sz / 1024), (unsigned long long)mrioc->reply_buf_dma);
2029824a1566SKashyap Desai 	sz = mrioc->reply_free_qsz * 8;
2030824a1566SKashyap Desai 	ioc_info(mrioc,
2031824a1566SKashyap Desai 	    "reply_free_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n",
2032824a1566SKashyap Desai 	    mrioc->reply_free_q, mrioc->reply_free_qsz, 8, (sz / 1024),
2033824a1566SKashyap Desai 	    (unsigned long long)mrioc->reply_free_q_dma);
2034824a1566SKashyap Desai 	sz = mrioc->num_sense_bufs * MPI3MR_SENSEBUF_SZ;
2035824a1566SKashyap Desai 	ioc_info(mrioc,
2036824a1566SKashyap Desai 	    "sense_buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n",
2037824a1566SKashyap Desai 	    mrioc->sense_buf, mrioc->num_sense_bufs, MPI3MR_SENSEBUF_SZ,
2038824a1566SKashyap Desai 	    (sz / 1024), (unsigned long long)mrioc->sense_buf_dma);
2039824a1566SKashyap Desai 	sz = mrioc->sense_buf_q_sz * 8;
2040824a1566SKashyap Desai 	ioc_info(mrioc,
2041824a1566SKashyap Desai 	    "sense_buf_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n",
2042824a1566SKashyap Desai 	    mrioc->sense_buf_q, mrioc->sense_buf_q_sz, 8, (sz / 1024),
2043824a1566SKashyap Desai 	    (unsigned long long)mrioc->sense_buf_q_dma);
2044824a1566SKashyap Desai 
2045824a1566SKashyap Desai 	/* initialize Reply buffer Queue */
2046824a1566SKashyap Desai 	for (i = 0, phy_addr = mrioc->reply_buf_dma;
2047824a1566SKashyap Desai 	    i < mrioc->num_reply_bufs; i++, phy_addr += mrioc->facts.reply_sz)
2048824a1566SKashyap Desai 		mrioc->reply_free_q[i] = cpu_to_le64(phy_addr);
2049824a1566SKashyap Desai 	mrioc->reply_free_q[i] = cpu_to_le64(0);
2050824a1566SKashyap Desai 
2051824a1566SKashyap Desai 	/* initialize Sense Buffer Queue */
2052824a1566SKashyap Desai 	for (i = 0, phy_addr = mrioc->sense_buf_dma;
2053824a1566SKashyap Desai 	    i < mrioc->num_sense_bufs; i++, phy_addr += MPI3MR_SENSEBUF_SZ)
2054824a1566SKashyap Desai 		mrioc->sense_buf_q[i] = cpu_to_le64(phy_addr);
2055824a1566SKashyap Desai 	mrioc->sense_buf_q[i] = cpu_to_le64(0);
2056824a1566SKashyap Desai 	return retval;
2057824a1566SKashyap Desai 
2058824a1566SKashyap Desai out_failed:
2059824a1566SKashyap Desai 	retval = -1;
2060824a1566SKashyap Desai 	return retval;
2061824a1566SKashyap Desai }
2062824a1566SKashyap Desai 
2063824a1566SKashyap Desai /**
2064824a1566SKashyap Desai  * mpi3mr_issue_iocinit - Send IOC Init
2065824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2066824a1566SKashyap Desai  *
2067824a1566SKashyap Desai  * Issue IOC Init MPI request through admin queue and wait for
2068824a1566SKashyap Desai  * the completion of it or time out.
2069824a1566SKashyap Desai  *
2070824a1566SKashyap Desai  * Return: 0 on success, non-zero on failures.
2071824a1566SKashyap Desai  */
2072824a1566SKashyap Desai static int mpi3mr_issue_iocinit(struct mpi3mr_ioc *mrioc)
2073824a1566SKashyap Desai {
2074824a1566SKashyap Desai 	struct mpi3_ioc_init_request iocinit_req;
2075824a1566SKashyap Desai 	struct mpi3_driver_info_layout *drv_info;
2076824a1566SKashyap Desai 	dma_addr_t data_dma;
2077824a1566SKashyap Desai 	u32 data_len = sizeof(*drv_info);
2078824a1566SKashyap Desai 	int retval = 0;
2079824a1566SKashyap Desai 	ktime_t current_time;
2080824a1566SKashyap Desai 
2081824a1566SKashyap Desai 	drv_info = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma,
2082824a1566SKashyap Desai 	    GFP_KERNEL);
2083824a1566SKashyap Desai 	if (!drv_info) {
2084824a1566SKashyap Desai 		retval = -1;
2085824a1566SKashyap Desai 		goto out;
2086824a1566SKashyap Desai 	}
2087824a1566SKashyap Desai 	drv_info->information_length = cpu_to_le32(data_len);
2088824a1566SKashyap Desai 	strncpy(drv_info->driver_signature, "Broadcom", sizeof(drv_info->driver_signature));
2089824a1566SKashyap Desai 	strncpy(drv_info->os_name, utsname()->sysname, sizeof(drv_info->os_name));
2090824a1566SKashyap Desai 	drv_info->os_name[sizeof(drv_info->os_name) - 1] = 0;
2091824a1566SKashyap Desai 	strncpy(drv_info->os_version, utsname()->release, sizeof(drv_info->os_version));
2092824a1566SKashyap Desai 	drv_info->os_version[sizeof(drv_info->os_version) - 1] = 0;
2093824a1566SKashyap Desai 	strncpy(drv_info->driver_name, MPI3MR_DRIVER_NAME, sizeof(drv_info->driver_name));
2094824a1566SKashyap Desai 	strncpy(drv_info->driver_version, MPI3MR_DRIVER_VERSION, sizeof(drv_info->driver_version));
2095824a1566SKashyap Desai 	strncpy(drv_info->driver_release_date, MPI3MR_DRIVER_RELDATE, sizeof(drv_info->driver_release_date));
2096824a1566SKashyap Desai 	drv_info->driver_capabilities = 0;
2097824a1566SKashyap Desai 	memcpy((u8 *)&mrioc->driver_info, (u8 *)drv_info,
2098824a1566SKashyap Desai 	    sizeof(mrioc->driver_info));
2099824a1566SKashyap Desai 
2100824a1566SKashyap Desai 	memset(&iocinit_req, 0, sizeof(iocinit_req));
2101824a1566SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
2102824a1566SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
2103824a1566SKashyap Desai 		retval = -1;
2104824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCInit: Init command is in use\n");
2105824a1566SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
2106824a1566SKashyap Desai 		goto out;
2107824a1566SKashyap Desai 	}
2108824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
2109824a1566SKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
2110824a1566SKashyap Desai 	mrioc->init_cmds.callback = NULL;
2111824a1566SKashyap Desai 	iocinit_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
2112824a1566SKashyap Desai 	iocinit_req.function = MPI3_FUNCTION_IOC_INIT;
2113824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.dev = MPI3_VERSION_DEV;
2114824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.unit = MPI3_VERSION_UNIT;
2115824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.major = MPI3_VERSION_MAJOR;
2116824a1566SKashyap Desai 	iocinit_req.mpi_version.mpi3_version.minor = MPI3_VERSION_MINOR;
2117824a1566SKashyap Desai 	iocinit_req.who_init = MPI3_WHOINIT_HOST_DRIVER;
2118824a1566SKashyap Desai 	iocinit_req.reply_free_queue_depth = cpu_to_le16(mrioc->reply_free_qsz);
2119824a1566SKashyap Desai 	iocinit_req.reply_free_queue_address =
2120824a1566SKashyap Desai 	    cpu_to_le64(mrioc->reply_free_q_dma);
2121824a1566SKashyap Desai 	iocinit_req.sense_buffer_length = cpu_to_le16(MPI3MR_SENSEBUF_SZ);
2122824a1566SKashyap Desai 	iocinit_req.sense_buffer_free_queue_depth =
2123824a1566SKashyap Desai 	    cpu_to_le16(mrioc->sense_buf_q_sz);
2124824a1566SKashyap Desai 	iocinit_req.sense_buffer_free_queue_address =
2125824a1566SKashyap Desai 	    cpu_to_le64(mrioc->sense_buf_q_dma);
2126824a1566SKashyap Desai 	iocinit_req.driver_information_address = cpu_to_le64(data_dma);
2127824a1566SKashyap Desai 
2128824a1566SKashyap Desai 	current_time = ktime_get_real();
2129824a1566SKashyap Desai 	iocinit_req.time_stamp = cpu_to_le64(ktime_to_ms(current_time));
2130824a1566SKashyap Desai 
2131824a1566SKashyap Desai 	init_completion(&mrioc->init_cmds.done);
2132824a1566SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &iocinit_req,
2133824a1566SKashyap Desai 	    sizeof(iocinit_req), 1);
2134824a1566SKashyap Desai 	if (retval) {
2135824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCInit: Admin Post failed\n");
2136824a1566SKashyap Desai 		goto out_unlock;
2137824a1566SKashyap Desai 	}
2138824a1566SKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
2139824a1566SKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
2140824a1566SKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
2141824a1566SKashyap Desai 		mpi3mr_set_diagsave(mrioc);
2142824a1566SKashyap Desai 		mpi3mr_issue_reset(mrioc,
2143824a1566SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
2144824a1566SKashyap Desai 		    MPI3MR_RESET_FROM_IOCINIT_TIMEOUT);
2145824a1566SKashyap Desai 		mrioc->unrecoverable = 1;
2146824a1566SKashyap Desai 		ioc_err(mrioc, "Issue IOCInit: command timed out\n");
2147824a1566SKashyap Desai 		retval = -1;
2148824a1566SKashyap Desai 		goto out_unlock;
2149824a1566SKashyap Desai 	}
2150824a1566SKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
2151824a1566SKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
2152824a1566SKashyap Desai 		ioc_err(mrioc,
2153824a1566SKashyap Desai 		    "Issue IOCInit: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
2154824a1566SKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
2155824a1566SKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
2156824a1566SKashyap Desai 		retval = -1;
2157824a1566SKashyap Desai 		goto out_unlock;
2158824a1566SKashyap Desai 	}
2159824a1566SKashyap Desai 
2160824a1566SKashyap Desai out_unlock:
2161824a1566SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
2162824a1566SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
2163824a1566SKashyap Desai 
2164824a1566SKashyap Desai out:
2165824a1566SKashyap Desai 	if (drv_info)
2166824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, data_len, drv_info,
2167824a1566SKashyap Desai 		    data_dma);
2168824a1566SKashyap Desai 
2169824a1566SKashyap Desai 	return retval;
2170824a1566SKashyap Desai }
2171824a1566SKashyap Desai 
2172824a1566SKashyap Desai /**
217313ef29eaSKashyap Desai  * mpi3mr_unmask_events - Unmask events in event mask bitmap
217413ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
217513ef29eaSKashyap Desai  * @event: MPI event ID
217613ef29eaSKashyap Desai  *
217713ef29eaSKashyap Desai  * Un mask the specific event by resetting the event_mask
217813ef29eaSKashyap Desai  * bitmap.
217913ef29eaSKashyap Desai  *
218013ef29eaSKashyap Desai  * Return: 0 on success, non-zero on failures.
218113ef29eaSKashyap Desai  */
218213ef29eaSKashyap Desai static void mpi3mr_unmask_events(struct mpi3mr_ioc *mrioc, u16 event)
218313ef29eaSKashyap Desai {
218413ef29eaSKashyap Desai 	u32 desired_event;
218513ef29eaSKashyap Desai 	u8 word;
218613ef29eaSKashyap Desai 
218713ef29eaSKashyap Desai 	if (event >= 128)
218813ef29eaSKashyap Desai 		return;
218913ef29eaSKashyap Desai 
219013ef29eaSKashyap Desai 	desired_event = (1 << (event % 32));
219113ef29eaSKashyap Desai 	word = event / 32;
219213ef29eaSKashyap Desai 
219313ef29eaSKashyap Desai 	mrioc->event_masks[word] &= ~desired_event;
219413ef29eaSKashyap Desai }
219513ef29eaSKashyap Desai 
219613ef29eaSKashyap Desai /**
219713ef29eaSKashyap Desai  * mpi3mr_issue_event_notification - Send event notification
219813ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
219913ef29eaSKashyap Desai  *
220013ef29eaSKashyap Desai  * Issue event notification MPI request through admin queue and
220113ef29eaSKashyap Desai  * wait for the completion of it or time out.
220213ef29eaSKashyap Desai  *
220313ef29eaSKashyap Desai  * Return: 0 on success, non-zero on failures.
220413ef29eaSKashyap Desai  */
220513ef29eaSKashyap Desai static int mpi3mr_issue_event_notification(struct mpi3mr_ioc *mrioc)
220613ef29eaSKashyap Desai {
220713ef29eaSKashyap Desai 	struct mpi3_event_notification_request evtnotify_req;
220813ef29eaSKashyap Desai 	int retval = 0;
220913ef29eaSKashyap Desai 	u8 i;
221013ef29eaSKashyap Desai 
221113ef29eaSKashyap Desai 	memset(&evtnotify_req, 0, sizeof(evtnotify_req));
221213ef29eaSKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
221313ef29eaSKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
221413ef29eaSKashyap Desai 		retval = -1;
221513ef29eaSKashyap Desai 		ioc_err(mrioc, "Issue EvtNotify: Init command is in use\n");
221613ef29eaSKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
221713ef29eaSKashyap Desai 		goto out;
221813ef29eaSKashyap Desai 	}
221913ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
222013ef29eaSKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
222113ef29eaSKashyap Desai 	mrioc->init_cmds.callback = NULL;
222213ef29eaSKashyap Desai 	evtnotify_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
222313ef29eaSKashyap Desai 	evtnotify_req.function = MPI3_FUNCTION_EVENT_NOTIFICATION;
222413ef29eaSKashyap Desai 	for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
222513ef29eaSKashyap Desai 		evtnotify_req.event_masks[i] =
222613ef29eaSKashyap Desai 		    cpu_to_le32(mrioc->event_masks[i]);
222713ef29eaSKashyap Desai 	init_completion(&mrioc->init_cmds.done);
222813ef29eaSKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &evtnotify_req,
222913ef29eaSKashyap Desai 	    sizeof(evtnotify_req), 1);
223013ef29eaSKashyap Desai 	if (retval) {
223113ef29eaSKashyap Desai 		ioc_err(mrioc, "Issue EvtNotify: Admin Post failed\n");
223213ef29eaSKashyap Desai 		goto out_unlock;
223313ef29eaSKashyap Desai 	}
223413ef29eaSKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
223513ef29eaSKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
223613ef29eaSKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
223713ef29eaSKashyap Desai 		ioc_err(mrioc, "Issue EvtNotify: command timed out\n");
223813ef29eaSKashyap Desai 		mpi3mr_set_diagsave(mrioc);
223913ef29eaSKashyap Desai 		mpi3mr_issue_reset(mrioc,
224013ef29eaSKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
224113ef29eaSKashyap Desai 		    MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT);
224213ef29eaSKashyap Desai 		mrioc->unrecoverable = 1;
224313ef29eaSKashyap Desai 		retval = -1;
224413ef29eaSKashyap Desai 		goto out_unlock;
224513ef29eaSKashyap Desai 	}
224613ef29eaSKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
224713ef29eaSKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
224813ef29eaSKashyap Desai 		ioc_err(mrioc,
224913ef29eaSKashyap Desai 		    "Issue EvtNotify: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
225013ef29eaSKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
225113ef29eaSKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
225213ef29eaSKashyap Desai 		retval = -1;
225313ef29eaSKashyap Desai 		goto out_unlock;
225413ef29eaSKashyap Desai 	}
225513ef29eaSKashyap Desai 
225613ef29eaSKashyap Desai out_unlock:
225713ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
225813ef29eaSKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
225913ef29eaSKashyap Desai out:
226013ef29eaSKashyap Desai 	return retval;
226113ef29eaSKashyap Desai }
226213ef29eaSKashyap Desai 
226313ef29eaSKashyap Desai /**
226413ef29eaSKashyap Desai  * mpi3mr_send_event_ack - Send event acknowledgment
226513ef29eaSKashyap Desai  * @mrioc: Adapter instance reference
226613ef29eaSKashyap Desai  * @event: MPI3 event ID
226713ef29eaSKashyap Desai  * @event_ctx: Event context
226813ef29eaSKashyap Desai  *
226913ef29eaSKashyap Desai  * Send event acknowledgment through admin queue and wait for
227013ef29eaSKashyap Desai  * it to complete.
227113ef29eaSKashyap Desai  *
227213ef29eaSKashyap Desai  * Return: 0 on success, non-zero on failures.
227313ef29eaSKashyap Desai  */
227413ef29eaSKashyap Desai int mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event,
227513ef29eaSKashyap Desai 	u32 event_ctx)
227613ef29eaSKashyap Desai {
227713ef29eaSKashyap Desai 	struct mpi3_event_ack_request evtack_req;
227813ef29eaSKashyap Desai 	int retval = 0;
227913ef29eaSKashyap Desai 
228013ef29eaSKashyap Desai 	memset(&evtack_req, 0, sizeof(evtack_req));
228113ef29eaSKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
228213ef29eaSKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
228313ef29eaSKashyap Desai 		retval = -1;
228413ef29eaSKashyap Desai 		ioc_err(mrioc, "Send EvtAck: Init command is in use\n");
228513ef29eaSKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
228613ef29eaSKashyap Desai 		goto out;
228713ef29eaSKashyap Desai 	}
228813ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
228913ef29eaSKashyap Desai 	mrioc->init_cmds.is_waiting = 1;
229013ef29eaSKashyap Desai 	mrioc->init_cmds.callback = NULL;
229113ef29eaSKashyap Desai 	evtack_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
229213ef29eaSKashyap Desai 	evtack_req.function = MPI3_FUNCTION_EVENT_ACK;
229313ef29eaSKashyap Desai 	evtack_req.event = event;
229413ef29eaSKashyap Desai 	evtack_req.event_context = cpu_to_le32(event_ctx);
229513ef29eaSKashyap Desai 
229613ef29eaSKashyap Desai 	init_completion(&mrioc->init_cmds.done);
229713ef29eaSKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &evtack_req,
229813ef29eaSKashyap Desai 	    sizeof(evtack_req), 1);
229913ef29eaSKashyap Desai 	if (retval) {
230013ef29eaSKashyap Desai 		ioc_err(mrioc, "Send EvtAck: Admin Post failed\n");
230113ef29eaSKashyap Desai 		goto out_unlock;
230213ef29eaSKashyap Desai 	}
230313ef29eaSKashyap Desai 	wait_for_completion_timeout(&mrioc->init_cmds.done,
230413ef29eaSKashyap Desai 	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
230513ef29eaSKashyap Desai 	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
230613ef29eaSKashyap Desai 		ioc_err(mrioc, "Issue EvtNotify: command timed out\n");
230713ef29eaSKashyap Desai 		mpi3mr_soft_reset_handler(mrioc,
230813ef29eaSKashyap Desai 		    MPI3MR_RESET_FROM_EVTACK_TIMEOUT, 1);
230913ef29eaSKashyap Desai 		retval = -1;
231013ef29eaSKashyap Desai 		goto out_unlock;
231113ef29eaSKashyap Desai 	}
231213ef29eaSKashyap Desai 	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
231313ef29eaSKashyap Desai 	    != MPI3_IOCSTATUS_SUCCESS) {
231413ef29eaSKashyap Desai 		ioc_err(mrioc,
231513ef29eaSKashyap Desai 		    "Send EvtAck: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
231613ef29eaSKashyap Desai 		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
231713ef29eaSKashyap Desai 		    mrioc->init_cmds.ioc_loginfo);
231813ef29eaSKashyap Desai 		retval = -1;
231913ef29eaSKashyap Desai 		goto out_unlock;
232013ef29eaSKashyap Desai 	}
232113ef29eaSKashyap Desai 
232213ef29eaSKashyap Desai out_unlock:
232313ef29eaSKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
232413ef29eaSKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
232513ef29eaSKashyap Desai out:
232613ef29eaSKashyap Desai 	return retval;
232713ef29eaSKashyap Desai }
232813ef29eaSKashyap Desai 
232913ef29eaSKashyap Desai /**
2330824a1566SKashyap Desai  * mpi3mr_alloc_chain_bufs - Allocate chain buffers
2331824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2332824a1566SKashyap Desai  *
2333824a1566SKashyap Desai  * Allocate chain buffers and set a bitmap to indicate free
2334824a1566SKashyap Desai  * chain buffers. Chain buffers are used to pass the SGE
2335824a1566SKashyap Desai  * information along with MPI3 SCSI IO requests for host I/O.
2336824a1566SKashyap Desai  *
2337824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure
2338824a1566SKashyap Desai  */
2339824a1566SKashyap Desai static int mpi3mr_alloc_chain_bufs(struct mpi3mr_ioc *mrioc)
2340824a1566SKashyap Desai {
2341824a1566SKashyap Desai 	int retval = 0;
2342824a1566SKashyap Desai 	u32 sz, i;
2343824a1566SKashyap Desai 	u16 num_chains;
2344824a1566SKashyap Desai 
2345824a1566SKashyap Desai 	num_chains = mrioc->max_host_ios / MPI3MR_CHAINBUF_FACTOR;
2346824a1566SKashyap Desai 
2347824a1566SKashyap Desai 	mrioc->chain_buf_count = num_chains;
2348824a1566SKashyap Desai 	sz = sizeof(struct chain_element) * num_chains;
2349824a1566SKashyap Desai 	mrioc->chain_sgl_list = kzalloc(sz, GFP_KERNEL);
2350824a1566SKashyap Desai 	if (!mrioc->chain_sgl_list)
2351824a1566SKashyap Desai 		goto out_failed;
2352824a1566SKashyap Desai 
2353824a1566SKashyap Desai 	sz = MPI3MR_PAGE_SIZE_4K;
2354824a1566SKashyap Desai 	mrioc->chain_buf_pool = dma_pool_create("chain_buf pool",
2355824a1566SKashyap Desai 	    &mrioc->pdev->dev, sz, 16, 0);
2356824a1566SKashyap Desai 	if (!mrioc->chain_buf_pool) {
2357824a1566SKashyap Desai 		ioc_err(mrioc, "chain buf pool: dma_pool_create failed\n");
2358824a1566SKashyap Desai 		goto out_failed;
2359824a1566SKashyap Desai 	}
2360824a1566SKashyap Desai 
2361824a1566SKashyap Desai 	for (i = 0; i < num_chains; i++) {
2362824a1566SKashyap Desai 		mrioc->chain_sgl_list[i].addr =
2363824a1566SKashyap Desai 		    dma_pool_zalloc(mrioc->chain_buf_pool, GFP_KERNEL,
2364824a1566SKashyap Desai 		    &mrioc->chain_sgl_list[i].dma_addr);
2365824a1566SKashyap Desai 
2366824a1566SKashyap Desai 		if (!mrioc->chain_sgl_list[i].addr)
2367824a1566SKashyap Desai 			goto out_failed;
2368824a1566SKashyap Desai 	}
2369824a1566SKashyap Desai 	mrioc->chain_bitmap_sz = num_chains / 8;
2370824a1566SKashyap Desai 	if (num_chains % 8)
2371824a1566SKashyap Desai 		mrioc->chain_bitmap_sz++;
2372824a1566SKashyap Desai 	mrioc->chain_bitmap = kzalloc(mrioc->chain_bitmap_sz, GFP_KERNEL);
2373824a1566SKashyap Desai 	if (!mrioc->chain_bitmap)
2374824a1566SKashyap Desai 		goto out_failed;
2375824a1566SKashyap Desai 	return retval;
2376824a1566SKashyap Desai out_failed:
2377824a1566SKashyap Desai 	retval = -1;
2378824a1566SKashyap Desai 	return retval;
2379824a1566SKashyap Desai }
2380824a1566SKashyap Desai 
2381824a1566SKashyap Desai /**
2382023ab2a9SKashyap Desai  * mpi3mr_port_enable_complete - Mark port enable complete
2383023ab2a9SKashyap Desai  * @mrioc: Adapter instance reference
2384023ab2a9SKashyap Desai  * @drv_cmd: Internal command tracker
2385023ab2a9SKashyap Desai  *
2386023ab2a9SKashyap Desai  * Call back for asynchronous port enable request sets the
2387023ab2a9SKashyap Desai  * driver command to indicate port enable request is complete.
2388023ab2a9SKashyap Desai  *
2389023ab2a9SKashyap Desai  * Return: Nothing
2390023ab2a9SKashyap Desai  */
2391023ab2a9SKashyap Desai static void mpi3mr_port_enable_complete(struct mpi3mr_ioc *mrioc,
2392023ab2a9SKashyap Desai 	struct mpi3mr_drv_cmd *drv_cmd)
2393023ab2a9SKashyap Desai {
2394023ab2a9SKashyap Desai 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
2395023ab2a9SKashyap Desai 	drv_cmd->callback = NULL;
2396023ab2a9SKashyap Desai 	mrioc->scan_failed = drv_cmd->ioc_status;
2397023ab2a9SKashyap Desai 	mrioc->scan_started = 0;
2398023ab2a9SKashyap Desai }
2399023ab2a9SKashyap Desai 
2400023ab2a9SKashyap Desai /**
2401023ab2a9SKashyap Desai  * mpi3mr_issue_port_enable - Issue Port Enable
2402023ab2a9SKashyap Desai  * @mrioc: Adapter instance reference
2403023ab2a9SKashyap Desai  * @async: Flag to wait for completion or not
2404023ab2a9SKashyap Desai  *
2405023ab2a9SKashyap Desai  * Issue Port Enable MPI request through admin queue and if the
2406023ab2a9SKashyap Desai  * async flag is not set wait for the completion of the port
2407023ab2a9SKashyap Desai  * enable or time out.
2408023ab2a9SKashyap Desai  *
2409023ab2a9SKashyap Desai  * Return: 0 on success, non-zero on failures.
2410023ab2a9SKashyap Desai  */
2411023ab2a9SKashyap Desai int mpi3mr_issue_port_enable(struct mpi3mr_ioc *mrioc, u8 async)
2412023ab2a9SKashyap Desai {
2413023ab2a9SKashyap Desai 	struct mpi3_port_enable_request pe_req;
2414023ab2a9SKashyap Desai 	int retval = 0;
2415023ab2a9SKashyap Desai 	u32 pe_timeout = MPI3MR_PORTENABLE_TIMEOUT;
2416023ab2a9SKashyap Desai 
2417023ab2a9SKashyap Desai 	memset(&pe_req, 0, sizeof(pe_req));
2418023ab2a9SKashyap Desai 	mutex_lock(&mrioc->init_cmds.mutex);
2419023ab2a9SKashyap Desai 	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
2420023ab2a9SKashyap Desai 		retval = -1;
2421023ab2a9SKashyap Desai 		ioc_err(mrioc, "Issue PortEnable: Init command is in use\n");
2422023ab2a9SKashyap Desai 		mutex_unlock(&mrioc->init_cmds.mutex);
2423023ab2a9SKashyap Desai 		goto out;
2424023ab2a9SKashyap Desai 	}
2425023ab2a9SKashyap Desai 	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
2426023ab2a9SKashyap Desai 	if (async) {
2427023ab2a9SKashyap Desai 		mrioc->init_cmds.is_waiting = 0;
2428023ab2a9SKashyap Desai 		mrioc->init_cmds.callback = mpi3mr_port_enable_complete;
2429023ab2a9SKashyap Desai 	} else {
2430023ab2a9SKashyap Desai 		mrioc->init_cmds.is_waiting = 1;
2431023ab2a9SKashyap Desai 		mrioc->init_cmds.callback = NULL;
2432023ab2a9SKashyap Desai 		init_completion(&mrioc->init_cmds.done);
2433023ab2a9SKashyap Desai 	}
2434023ab2a9SKashyap Desai 	pe_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
2435023ab2a9SKashyap Desai 	pe_req.function = MPI3_FUNCTION_PORT_ENABLE;
2436023ab2a9SKashyap Desai 
2437023ab2a9SKashyap Desai 	retval = mpi3mr_admin_request_post(mrioc, &pe_req, sizeof(pe_req), 1);
2438023ab2a9SKashyap Desai 	if (retval) {
2439023ab2a9SKashyap Desai 		ioc_err(mrioc, "Issue PortEnable: Admin Post failed\n");
2440023ab2a9SKashyap Desai 		goto out_unlock;
2441023ab2a9SKashyap Desai 	}
2442023ab2a9SKashyap Desai 	if (!async) {
2443023ab2a9SKashyap Desai 		wait_for_completion_timeout(&mrioc->init_cmds.done,
2444023ab2a9SKashyap Desai 		    (pe_timeout * HZ));
2445023ab2a9SKashyap Desai 		if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
2446023ab2a9SKashyap Desai 			ioc_err(mrioc, "Issue PortEnable: command timed out\n");
2447023ab2a9SKashyap Desai 			retval = -1;
2448023ab2a9SKashyap Desai 			mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR;
2449023ab2a9SKashyap Desai 			mpi3mr_set_diagsave(mrioc);
2450023ab2a9SKashyap Desai 			mpi3mr_issue_reset(mrioc,
2451023ab2a9SKashyap Desai 			    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
2452023ab2a9SKashyap Desai 			    MPI3MR_RESET_FROM_PE_TIMEOUT);
2453023ab2a9SKashyap Desai 			mrioc->unrecoverable = 1;
2454023ab2a9SKashyap Desai 			goto out_unlock;
2455023ab2a9SKashyap Desai 		}
2456023ab2a9SKashyap Desai 		mpi3mr_port_enable_complete(mrioc, &mrioc->init_cmds);
2457023ab2a9SKashyap Desai 	}
2458023ab2a9SKashyap Desai out_unlock:
2459023ab2a9SKashyap Desai 	mutex_unlock(&mrioc->init_cmds.mutex);
2460023ab2a9SKashyap Desai out:
2461023ab2a9SKashyap Desai 	return retval;
2462023ab2a9SKashyap Desai }
2463023ab2a9SKashyap Desai 
2464023ab2a9SKashyap Desai /**
2465824a1566SKashyap Desai  * mpi3mr_cleanup_resources - Free PCI resources
2466824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2467824a1566SKashyap Desai  *
2468824a1566SKashyap Desai  * Unmap PCI device memory and disable PCI device.
2469824a1566SKashyap Desai  *
2470824a1566SKashyap Desai  * Return: 0 on success and non-zero on failure.
2471824a1566SKashyap Desai  */
2472824a1566SKashyap Desai void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc)
2473824a1566SKashyap Desai {
2474824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
2475824a1566SKashyap Desai 
2476824a1566SKashyap Desai 	mpi3mr_cleanup_isr(mrioc);
2477824a1566SKashyap Desai 
2478824a1566SKashyap Desai 	if (mrioc->sysif_regs) {
2479824a1566SKashyap Desai 		iounmap((void __iomem *)mrioc->sysif_regs);
2480824a1566SKashyap Desai 		mrioc->sysif_regs = NULL;
2481824a1566SKashyap Desai 	}
2482824a1566SKashyap Desai 
2483824a1566SKashyap Desai 	if (pci_is_enabled(pdev)) {
2484824a1566SKashyap Desai 		if (mrioc->bars)
2485824a1566SKashyap Desai 			pci_release_selected_regions(pdev, mrioc->bars);
2486824a1566SKashyap Desai 		pci_disable_device(pdev);
2487824a1566SKashyap Desai 	}
2488824a1566SKashyap Desai }
2489824a1566SKashyap Desai 
2490824a1566SKashyap Desai /**
2491824a1566SKashyap Desai  * mpi3mr_setup_resources - Enable PCI resources
2492824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2493824a1566SKashyap Desai  *
2494824a1566SKashyap Desai  * Enable PCI device memory, MSI-x registers and set DMA mask.
2495824a1566SKashyap Desai  *
2496824a1566SKashyap Desai  * Return: 0 on success and non-zero on failure.
2497824a1566SKashyap Desai  */
2498824a1566SKashyap Desai int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc)
2499824a1566SKashyap Desai {
2500824a1566SKashyap Desai 	struct pci_dev *pdev = mrioc->pdev;
2501824a1566SKashyap Desai 	u32 memap_sz = 0;
2502824a1566SKashyap Desai 	int i, retval = 0, capb = 0;
2503824a1566SKashyap Desai 	u16 message_control;
2504824a1566SKashyap Desai 	u64 dma_mask = mrioc->dma_mask ? mrioc->dma_mask :
2505824a1566SKashyap Desai 	    (((dma_get_required_mask(&pdev->dev) > DMA_BIT_MASK(32)) &&
2506824a1566SKashyap Desai 	    (sizeof(dma_addr_t) > 4)) ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32));
2507824a1566SKashyap Desai 
2508824a1566SKashyap Desai 	if (pci_enable_device_mem(pdev)) {
2509824a1566SKashyap Desai 		ioc_err(mrioc, "pci_enable_device_mem: failed\n");
2510824a1566SKashyap Desai 		retval = -ENODEV;
2511824a1566SKashyap Desai 		goto out_failed;
2512824a1566SKashyap Desai 	}
2513824a1566SKashyap Desai 
2514824a1566SKashyap Desai 	capb = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
2515824a1566SKashyap Desai 	if (!capb) {
2516824a1566SKashyap Desai 		ioc_err(mrioc, "Unable to find MSI-X Capabilities\n");
2517824a1566SKashyap Desai 		retval = -ENODEV;
2518824a1566SKashyap Desai 		goto out_failed;
2519824a1566SKashyap Desai 	}
2520824a1566SKashyap Desai 	mrioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
2521824a1566SKashyap Desai 
2522824a1566SKashyap Desai 	if (pci_request_selected_regions(pdev, mrioc->bars,
2523824a1566SKashyap Desai 	    mrioc->driver_name)) {
2524824a1566SKashyap Desai 		ioc_err(mrioc, "pci_request_selected_regions: failed\n");
2525824a1566SKashyap Desai 		retval = -ENODEV;
2526824a1566SKashyap Desai 		goto out_failed;
2527824a1566SKashyap Desai 	}
2528824a1566SKashyap Desai 
2529824a1566SKashyap Desai 	for (i = 0; (i < DEVICE_COUNT_RESOURCE); i++) {
2530824a1566SKashyap Desai 		if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
2531824a1566SKashyap Desai 			mrioc->sysif_regs_phys = pci_resource_start(pdev, i);
2532824a1566SKashyap Desai 			memap_sz = pci_resource_len(pdev, i);
2533824a1566SKashyap Desai 			mrioc->sysif_regs =
2534824a1566SKashyap Desai 			    ioremap(mrioc->sysif_regs_phys, memap_sz);
2535824a1566SKashyap Desai 			break;
2536824a1566SKashyap Desai 		}
2537824a1566SKashyap Desai 	}
2538824a1566SKashyap Desai 
2539824a1566SKashyap Desai 	pci_set_master(pdev);
2540824a1566SKashyap Desai 
2541824a1566SKashyap Desai 	retval = dma_set_mask_and_coherent(&pdev->dev, dma_mask);
2542824a1566SKashyap Desai 	if (retval) {
2543824a1566SKashyap Desai 		if (dma_mask != DMA_BIT_MASK(32)) {
2544824a1566SKashyap Desai 			ioc_warn(mrioc, "Setting 64 bit DMA mask failed\n");
2545824a1566SKashyap Desai 			dma_mask = DMA_BIT_MASK(32);
2546824a1566SKashyap Desai 			retval = dma_set_mask_and_coherent(&pdev->dev,
2547824a1566SKashyap Desai 			    dma_mask);
2548824a1566SKashyap Desai 		}
2549824a1566SKashyap Desai 		if (retval) {
2550824a1566SKashyap Desai 			mrioc->dma_mask = 0;
2551824a1566SKashyap Desai 			ioc_err(mrioc, "Setting 32 bit DMA mask also failed\n");
2552824a1566SKashyap Desai 			goto out_failed;
2553824a1566SKashyap Desai 		}
2554824a1566SKashyap Desai 	}
2555824a1566SKashyap Desai 	mrioc->dma_mask = dma_mask;
2556824a1566SKashyap Desai 
2557824a1566SKashyap Desai 	if (!mrioc->sysif_regs) {
2558824a1566SKashyap Desai 		ioc_err(mrioc,
2559824a1566SKashyap Desai 		    "Unable to map adapter memory or resource not found\n");
2560824a1566SKashyap Desai 		retval = -EINVAL;
2561824a1566SKashyap Desai 		goto out_failed;
2562824a1566SKashyap Desai 	}
2563824a1566SKashyap Desai 
2564824a1566SKashyap Desai 	pci_read_config_word(pdev, capb + 2, &message_control);
2565824a1566SKashyap Desai 	mrioc->msix_count = (message_control & 0x3FF) + 1;
2566824a1566SKashyap Desai 
2567824a1566SKashyap Desai 	pci_save_state(pdev);
2568824a1566SKashyap Desai 
2569824a1566SKashyap Desai 	pci_set_drvdata(pdev, mrioc->shost);
2570824a1566SKashyap Desai 
2571824a1566SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
2572824a1566SKashyap Desai 
2573824a1566SKashyap Desai 	ioc_info(mrioc, "iomem(0x%016llx), mapped(0x%p), size(%d)\n",
2574824a1566SKashyap Desai 	    (unsigned long long)mrioc->sysif_regs_phys,
2575824a1566SKashyap Desai 	    mrioc->sysif_regs, memap_sz);
2576824a1566SKashyap Desai 	ioc_info(mrioc, "Number of MSI-X vectors found in capabilities: (%d)\n",
2577824a1566SKashyap Desai 	    mrioc->msix_count);
2578824a1566SKashyap Desai 	return retval;
2579824a1566SKashyap Desai 
2580824a1566SKashyap Desai out_failed:
2581824a1566SKashyap Desai 	mpi3mr_cleanup_resources(mrioc);
2582824a1566SKashyap Desai 	return retval;
2583824a1566SKashyap Desai }
2584824a1566SKashyap Desai 
2585824a1566SKashyap Desai /**
2586824a1566SKashyap Desai  * mpi3mr_init_ioc - Initialize the controller
2587824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2588*fb9b0457SKashyap Desai  * @re_init: Flag to indicate is this fresh init or re-init
2589824a1566SKashyap Desai  *
2590824a1566SKashyap Desai  * This the controller initialization routine, executed either
2591824a1566SKashyap Desai  * after soft reset or from pci probe callback.
2592824a1566SKashyap Desai  * Setup the required resources, memory map the controller
2593824a1566SKashyap Desai  * registers, create admin and operational reply queue pairs,
2594824a1566SKashyap Desai  * allocate required memory for reply pool, sense buffer pool,
2595824a1566SKashyap Desai  * issue IOC init request to the firmware, unmask the events and
2596824a1566SKashyap Desai  * issue port enable to discover SAS/SATA/NVMe devies and RAID
2597824a1566SKashyap Desai  * volumes.
2598824a1566SKashyap Desai  *
2599824a1566SKashyap Desai  * Return: 0 on success and non-zero on failure.
2600824a1566SKashyap Desai  */
2601*fb9b0457SKashyap Desai int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc, u8 re_init)
2602824a1566SKashyap Desai {
2603824a1566SKashyap Desai 	int retval = 0;
2604824a1566SKashyap Desai 	enum mpi3mr_iocstate ioc_state;
2605824a1566SKashyap Desai 	u64 base_info;
2606824a1566SKashyap Desai 	u32 timeout;
260713ef29eaSKashyap Desai 	u32 ioc_status, ioc_config, i;
2608824a1566SKashyap Desai 	struct mpi3_ioc_facts_data facts_data;
2609824a1566SKashyap Desai 
2610824a1566SKashyap Desai 	mrioc->change_count = 0;
2611*fb9b0457SKashyap Desai 	if (!re_init) {
2612824a1566SKashyap Desai 		mrioc->cpu_count = num_online_cpus();
2613824a1566SKashyap Desai 		retval = mpi3mr_setup_resources(mrioc);
2614824a1566SKashyap Desai 		if (retval) {
2615824a1566SKashyap Desai 			ioc_err(mrioc, "Failed to setup resources:error %d\n",
2616824a1566SKashyap Desai 			    retval);
2617824a1566SKashyap Desai 			goto out_nocleanup;
2618824a1566SKashyap Desai 		}
2619*fb9b0457SKashyap Desai 	}
2620*fb9b0457SKashyap Desai 
2621824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
2622824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
2623824a1566SKashyap Desai 
2624824a1566SKashyap Desai 	ioc_info(mrioc, "SOD status %x configuration %x\n",
2625824a1566SKashyap Desai 	    ioc_status, ioc_config);
2626824a1566SKashyap Desai 
2627824a1566SKashyap Desai 	base_info = lo_hi_readq(&mrioc->sysif_regs->ioc_information);
2628824a1566SKashyap Desai 	ioc_info(mrioc, "SOD base_info %llx\n",	base_info);
2629824a1566SKashyap Desai 
2630824a1566SKashyap Desai 	/*The timeout value is in 2sec unit, changing it to seconds*/
2631824a1566SKashyap Desai 	mrioc->ready_timeout =
2632824a1566SKashyap Desai 	    ((base_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >>
2633824a1566SKashyap Desai 	    MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT) * 2;
2634824a1566SKashyap Desai 
2635824a1566SKashyap Desai 	ioc_info(mrioc, "IOC ready timeout %d\n", mrioc->ready_timeout);
2636824a1566SKashyap Desai 
2637824a1566SKashyap Desai 	ioc_state = mpi3mr_get_iocstate(mrioc);
2638824a1566SKashyap Desai 	ioc_info(mrioc, "IOC in %s state during detection\n",
2639824a1566SKashyap Desai 	    mpi3mr_iocstate_name(ioc_state));
2640824a1566SKashyap Desai 
2641824a1566SKashyap Desai 	if (ioc_state == MRIOC_STATE_BECOMING_READY ||
2642824a1566SKashyap Desai 	    ioc_state == MRIOC_STATE_RESET_REQUESTED) {
2643824a1566SKashyap Desai 		timeout = mrioc->ready_timeout * 10;
2644824a1566SKashyap Desai 		do {
2645824a1566SKashyap Desai 			msleep(100);
2646824a1566SKashyap Desai 		} while (--timeout);
2647824a1566SKashyap Desai 
2648824a1566SKashyap Desai 		ioc_state = mpi3mr_get_iocstate(mrioc);
2649824a1566SKashyap Desai 		ioc_info(mrioc,
2650824a1566SKashyap Desai 		    "IOC in %s state after waiting for reset time\n",
2651824a1566SKashyap Desai 		    mpi3mr_iocstate_name(ioc_state));
2652824a1566SKashyap Desai 	}
2653824a1566SKashyap Desai 
2654824a1566SKashyap Desai 	if (ioc_state == MRIOC_STATE_READY) {
2655824a1566SKashyap Desai 		retval = mpi3mr_issue_and_process_mur(mrioc,
2656824a1566SKashyap Desai 		    MPI3MR_RESET_FROM_BRINGUP);
2657824a1566SKashyap Desai 		if (retval) {
2658824a1566SKashyap Desai 			ioc_err(mrioc, "Failed to MU reset IOC error %d\n",
2659824a1566SKashyap Desai 			    retval);
2660824a1566SKashyap Desai 		}
2661824a1566SKashyap Desai 		ioc_state = mpi3mr_get_iocstate(mrioc);
2662824a1566SKashyap Desai 	}
2663824a1566SKashyap Desai 	if (ioc_state != MRIOC_STATE_RESET) {
2664824a1566SKashyap Desai 		mpi3mr_print_fault_info(mrioc);
2665824a1566SKashyap Desai 		retval = mpi3mr_issue_reset(mrioc,
2666824a1566SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
2667824a1566SKashyap Desai 		    MPI3MR_RESET_FROM_BRINGUP);
2668824a1566SKashyap Desai 		if (retval) {
2669824a1566SKashyap Desai 			ioc_err(mrioc,
2670824a1566SKashyap Desai 			    "%s :Failed to soft reset IOC error %d\n",
2671824a1566SKashyap Desai 			    __func__, retval);
2672824a1566SKashyap Desai 			goto out_failed;
2673824a1566SKashyap Desai 		}
2674824a1566SKashyap Desai 	}
2675824a1566SKashyap Desai 	ioc_state = mpi3mr_get_iocstate(mrioc);
2676824a1566SKashyap Desai 	if (ioc_state != MRIOC_STATE_RESET) {
2677824a1566SKashyap Desai 		ioc_err(mrioc, "Cannot bring IOC to reset state\n");
2678824a1566SKashyap Desai 		goto out_failed;
2679824a1566SKashyap Desai 	}
2680824a1566SKashyap Desai 
2681824a1566SKashyap Desai 	retval = mpi3mr_setup_admin_qpair(mrioc);
2682824a1566SKashyap Desai 	if (retval) {
2683824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to setup admin Qs: error %d\n",
2684824a1566SKashyap Desai 		    retval);
2685824a1566SKashyap Desai 		goto out_failed;
2686824a1566SKashyap Desai 	}
2687824a1566SKashyap Desai 
2688824a1566SKashyap Desai 	retval = mpi3mr_bring_ioc_ready(mrioc);
2689824a1566SKashyap Desai 	if (retval) {
2690824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to bring ioc ready: error %d\n",
2691824a1566SKashyap Desai 		    retval);
2692824a1566SKashyap Desai 		goto out_failed;
2693824a1566SKashyap Desai 	}
2694824a1566SKashyap Desai 
2695*fb9b0457SKashyap Desai 	if (!re_init) {
2696824a1566SKashyap Desai 		retval = mpi3mr_setup_isr(mrioc, 1);
2697824a1566SKashyap Desai 		if (retval) {
2698824a1566SKashyap Desai 			ioc_err(mrioc, "Failed to setup ISR error %d\n",
2699824a1566SKashyap Desai 			    retval);
2700824a1566SKashyap Desai 			goto out_failed;
2701824a1566SKashyap Desai 		}
2702*fb9b0457SKashyap Desai 	} else
2703*fb9b0457SKashyap Desai 		mpi3mr_ioc_enable_intr(mrioc);
2704824a1566SKashyap Desai 
2705824a1566SKashyap Desai 	retval = mpi3mr_issue_iocfacts(mrioc, &facts_data);
2706824a1566SKashyap Desai 	if (retval) {
2707824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to Issue IOC Facts %d\n",
2708824a1566SKashyap Desai 		    retval);
2709824a1566SKashyap Desai 		goto out_failed;
2710824a1566SKashyap Desai 	}
2711824a1566SKashyap Desai 
2712824a1566SKashyap Desai 	mpi3mr_process_factsdata(mrioc, &facts_data);
2713*fb9b0457SKashyap Desai 	if (!re_init) {
2714824a1566SKashyap Desai 		retval = mpi3mr_check_reset_dma_mask(mrioc);
2715824a1566SKashyap Desai 		if (retval) {
2716824a1566SKashyap Desai 			ioc_err(mrioc, "Resetting dma mask failed %d\n",
2717824a1566SKashyap Desai 			    retval);
2718824a1566SKashyap Desai 			goto out_failed;
2719824a1566SKashyap Desai 		}
2720*fb9b0457SKashyap Desai 	}
2721824a1566SKashyap Desai 
2722824a1566SKashyap Desai 	retval = mpi3mr_alloc_reply_sense_bufs(mrioc);
2723824a1566SKashyap Desai 	if (retval) {
2724824a1566SKashyap Desai 		ioc_err(mrioc,
2725824a1566SKashyap Desai 		    "%s :Failed to allocated reply sense buffers %d\n",
2726824a1566SKashyap Desai 		    __func__, retval);
2727824a1566SKashyap Desai 		goto out_failed;
2728824a1566SKashyap Desai 	}
2729824a1566SKashyap Desai 
2730*fb9b0457SKashyap Desai 	if (!re_init) {
2731824a1566SKashyap Desai 		retval = mpi3mr_alloc_chain_bufs(mrioc);
2732824a1566SKashyap Desai 		if (retval) {
2733824a1566SKashyap Desai 			ioc_err(mrioc, "Failed to allocated chain buffers %d\n",
2734824a1566SKashyap Desai 			    retval);
2735824a1566SKashyap Desai 			goto out_failed;
2736824a1566SKashyap Desai 		}
2737*fb9b0457SKashyap Desai 	}
2738824a1566SKashyap Desai 
2739824a1566SKashyap Desai 	retval = mpi3mr_issue_iocinit(mrioc);
2740824a1566SKashyap Desai 	if (retval) {
2741824a1566SKashyap Desai 		ioc_err(mrioc, "Failed to Issue IOC Init %d\n",
2742824a1566SKashyap Desai 		    retval);
2743824a1566SKashyap Desai 		goto out_failed;
2744824a1566SKashyap Desai 	}
2745824a1566SKashyap Desai 	mrioc->reply_free_queue_host_index = mrioc->num_reply_bufs;
2746824a1566SKashyap Desai 	writel(mrioc->reply_free_queue_host_index,
2747824a1566SKashyap Desai 	    &mrioc->sysif_regs->reply_free_host_index);
2748824a1566SKashyap Desai 
2749824a1566SKashyap Desai 	mrioc->sbq_host_index = mrioc->num_sense_bufs;
2750824a1566SKashyap Desai 	writel(mrioc->sbq_host_index,
2751824a1566SKashyap Desai 	    &mrioc->sysif_regs->sense_buffer_free_host_index);
2752824a1566SKashyap Desai 
2753*fb9b0457SKashyap Desai 	if (!re_init)  {
2754824a1566SKashyap Desai 		retval = mpi3mr_setup_isr(mrioc, 0);
2755824a1566SKashyap Desai 		if (retval) {
2756824a1566SKashyap Desai 			ioc_err(mrioc, "Failed to re-setup ISR, error %d\n",
2757824a1566SKashyap Desai 			    retval);
2758824a1566SKashyap Desai 			goto out_failed;
2759824a1566SKashyap Desai 		}
2760*fb9b0457SKashyap Desai 	}
2761824a1566SKashyap Desai 
2762c9566231SKashyap Desai 	retval = mpi3mr_create_op_queues(mrioc);
2763c9566231SKashyap Desai 	if (retval) {
2764c9566231SKashyap Desai 		ioc_err(mrioc, "Failed to create OpQueues error %d\n",
2765c9566231SKashyap Desai 		    retval);
2766c9566231SKashyap Desai 		goto out_failed;
2767c9566231SKashyap Desai 	}
2768c9566231SKashyap Desai 
2769*fb9b0457SKashyap Desai 	if (re_init &&
2770*fb9b0457SKashyap Desai 	    (mrioc->shost->nr_hw_queues > mrioc->num_op_reply_q)) {
2771*fb9b0457SKashyap Desai 		ioc_err(mrioc,
2772*fb9b0457SKashyap Desai 		    "Cannot create minimum number of OpQueues expected:%d created:%d\n",
2773*fb9b0457SKashyap Desai 		    mrioc->shost->nr_hw_queues, mrioc->num_op_reply_q);
2774*fb9b0457SKashyap Desai 		goto out_failed;
2775*fb9b0457SKashyap Desai 	}
2776*fb9b0457SKashyap Desai 
277713ef29eaSKashyap Desai 	for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
277813ef29eaSKashyap Desai 		mrioc->event_masks[i] = -1;
277913ef29eaSKashyap Desai 
278013ef29eaSKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_ADDED);
278113ef29eaSKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_INFO_CHANGED);
278213ef29eaSKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_STATUS_CHANGE);
278313ef29eaSKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE);
278413ef29eaSKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
278513ef29eaSKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DISCOVERY);
278613ef29eaSKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR);
2787e36710dcSKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_BROADCAST_PRIMITIVE);
27888e653455SKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST);
27898e653455SKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_ENUMERATION);
2790e36710dcSKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_CABLE_MGMT);
2791e36710dcSKashyap Desai 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENERGY_PACK_CHANGE);
279213ef29eaSKashyap Desai 
279313ef29eaSKashyap Desai 	retval = mpi3mr_issue_event_notification(mrioc);
279413ef29eaSKashyap Desai 	if (retval) {
279513ef29eaSKashyap Desai 		ioc_err(mrioc, "Failed to issue event notification %d\n",
279613ef29eaSKashyap Desai 		    retval);
279713ef29eaSKashyap Desai 		goto out_failed;
279813ef29eaSKashyap Desai 	}
279913ef29eaSKashyap Desai 
2800*fb9b0457SKashyap Desai 	if (re_init) {
2801*fb9b0457SKashyap Desai 		ioc_info(mrioc, "Issuing Port Enable\n");
2802*fb9b0457SKashyap Desai 		retval = mpi3mr_issue_port_enable(mrioc, 0);
2803*fb9b0457SKashyap Desai 		if (retval) {
2804*fb9b0457SKashyap Desai 			ioc_err(mrioc, "Failed to issue port enable %d\n",
2805*fb9b0457SKashyap Desai 			    retval);
2806*fb9b0457SKashyap Desai 			goto out_failed;
2807*fb9b0457SKashyap Desai 		}
2808*fb9b0457SKashyap Desai 	}
2809824a1566SKashyap Desai 	return retval;
2810824a1566SKashyap Desai 
2811824a1566SKashyap Desai out_failed:
2812*fb9b0457SKashyap Desai 	mpi3mr_cleanup_ioc(mrioc, re_init);
2813824a1566SKashyap Desai out_nocleanup:
2814824a1566SKashyap Desai 	return retval;
2815824a1566SKashyap Desai }
2816824a1566SKashyap Desai 
2817824a1566SKashyap Desai /**
2818*fb9b0457SKashyap Desai  * mpi3mr_memset_op_reply_q_buffers - memset the operational reply queue's
2819*fb9b0457SKashyap Desai  *					segments
2820*fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
2821*fb9b0457SKashyap Desai  * @qidx: Operational reply queue index
2822*fb9b0457SKashyap Desai  *
2823*fb9b0457SKashyap Desai  * Return: Nothing.
2824*fb9b0457SKashyap Desai  */
2825*fb9b0457SKashyap Desai static void mpi3mr_memset_op_reply_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx)
2826*fb9b0457SKashyap Desai {
2827*fb9b0457SKashyap Desai 	struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
2828*fb9b0457SKashyap Desai 	struct segments *segments;
2829*fb9b0457SKashyap Desai 	int i, size;
2830*fb9b0457SKashyap Desai 
2831*fb9b0457SKashyap Desai 	if (!op_reply_q->q_segments)
2832*fb9b0457SKashyap Desai 		return;
2833*fb9b0457SKashyap Desai 
2834*fb9b0457SKashyap Desai 	size = op_reply_q->segment_qd * mrioc->op_reply_desc_sz;
2835*fb9b0457SKashyap Desai 	segments = op_reply_q->q_segments;
2836*fb9b0457SKashyap Desai 	for (i = 0; i < op_reply_q->num_segments; i++)
2837*fb9b0457SKashyap Desai 		memset(segments[i].segment, 0, size);
2838*fb9b0457SKashyap Desai }
2839*fb9b0457SKashyap Desai 
2840*fb9b0457SKashyap Desai /**
2841*fb9b0457SKashyap Desai  * mpi3mr_memset_op_req_q_buffers - memset the operational request queue's
2842*fb9b0457SKashyap Desai  *					segments
2843*fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
2844*fb9b0457SKashyap Desai  * @qidx: Operational request queue index
2845*fb9b0457SKashyap Desai  *
2846*fb9b0457SKashyap Desai  * Return: Nothing.
2847*fb9b0457SKashyap Desai  */
2848*fb9b0457SKashyap Desai static void mpi3mr_memset_op_req_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx)
2849*fb9b0457SKashyap Desai {
2850*fb9b0457SKashyap Desai 	struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx;
2851*fb9b0457SKashyap Desai 	struct segments *segments;
2852*fb9b0457SKashyap Desai 	int i, size;
2853*fb9b0457SKashyap Desai 
2854*fb9b0457SKashyap Desai 	if (!op_req_q->q_segments)
2855*fb9b0457SKashyap Desai 		return;
2856*fb9b0457SKashyap Desai 
2857*fb9b0457SKashyap Desai 	size = op_req_q->segment_qd * mrioc->facts.op_req_sz;
2858*fb9b0457SKashyap Desai 	segments = op_req_q->q_segments;
2859*fb9b0457SKashyap Desai 	for (i = 0; i < op_req_q->num_segments; i++)
2860*fb9b0457SKashyap Desai 		memset(segments[i].segment, 0, size);
2861*fb9b0457SKashyap Desai }
2862*fb9b0457SKashyap Desai 
2863*fb9b0457SKashyap Desai /**
2864*fb9b0457SKashyap Desai  * mpi3mr_memset_buffers - memset memory for a controller
2865*fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
2866*fb9b0457SKashyap Desai  *
2867*fb9b0457SKashyap Desai  * clear all the memory allocated for a controller, typically
2868*fb9b0457SKashyap Desai  * called post reset to reuse the memory allocated during the
2869*fb9b0457SKashyap Desai  * controller init.
2870*fb9b0457SKashyap Desai  *
2871*fb9b0457SKashyap Desai  * Return: Nothing.
2872*fb9b0457SKashyap Desai  */
2873*fb9b0457SKashyap Desai static void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc)
2874*fb9b0457SKashyap Desai {
2875*fb9b0457SKashyap Desai 	u16 i;
2876*fb9b0457SKashyap Desai 
2877*fb9b0457SKashyap Desai 	memset(mrioc->admin_req_base, 0, mrioc->admin_req_q_sz);
2878*fb9b0457SKashyap Desai 	memset(mrioc->admin_reply_base, 0, mrioc->admin_reply_q_sz);
2879*fb9b0457SKashyap Desai 
2880*fb9b0457SKashyap Desai 	memset(mrioc->init_cmds.reply, 0, sizeof(*mrioc->init_cmds.reply));
2881*fb9b0457SKashyap Desai 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++)
2882*fb9b0457SKashyap Desai 		memset(mrioc->dev_rmhs_cmds[i].reply, 0,
2883*fb9b0457SKashyap Desai 		    sizeof(*mrioc->dev_rmhs_cmds[i].reply));
2884*fb9b0457SKashyap Desai 	memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz);
2885*fb9b0457SKashyap Desai 	memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz);
2886*fb9b0457SKashyap Desai 
2887*fb9b0457SKashyap Desai 	for (i = 0; i < mrioc->num_queues; i++) {
2888*fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].qid = 0;
2889*fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].ci = 0;
2890*fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].num_replies = 0;
2891*fb9b0457SKashyap Desai 		mrioc->op_reply_qinfo[i].ephase = 0;
2892*fb9b0457SKashyap Desai 		mpi3mr_memset_op_reply_q_buffers(mrioc, i);
2893*fb9b0457SKashyap Desai 
2894*fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].ci = 0;
2895*fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].pi = 0;
2896*fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].num_requests = 0;
2897*fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].qid = 0;
2898*fb9b0457SKashyap Desai 		mrioc->req_qinfo[i].reply_qid = 0;
2899*fb9b0457SKashyap Desai 		spin_lock_init(&mrioc->req_qinfo[i].q_lock);
2900*fb9b0457SKashyap Desai 		mpi3mr_memset_op_req_q_buffers(mrioc, i);
2901*fb9b0457SKashyap Desai 	}
2902*fb9b0457SKashyap Desai }
2903*fb9b0457SKashyap Desai 
2904*fb9b0457SKashyap Desai /**
2905824a1566SKashyap Desai  * mpi3mr_free_mem - Free memory allocated for a controller
2906824a1566SKashyap Desai  * @mrioc: Adapter instance reference
2907824a1566SKashyap Desai  *
2908824a1566SKashyap Desai  * Free all the memory allocated for a controller.
2909824a1566SKashyap Desai  *
2910824a1566SKashyap Desai  * Return: Nothing.
2911824a1566SKashyap Desai  */
2912824a1566SKashyap Desai static void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc)
2913824a1566SKashyap Desai {
2914824a1566SKashyap Desai 	u16 i;
2915824a1566SKashyap Desai 	struct mpi3mr_intr_info *intr_info;
2916824a1566SKashyap Desai 
2917824a1566SKashyap Desai 	if (mrioc->sense_buf_pool) {
2918824a1566SKashyap Desai 		if (mrioc->sense_buf)
2919824a1566SKashyap Desai 			dma_pool_free(mrioc->sense_buf_pool, mrioc->sense_buf,
2920824a1566SKashyap Desai 			    mrioc->sense_buf_dma);
2921824a1566SKashyap Desai 		dma_pool_destroy(mrioc->sense_buf_pool);
2922824a1566SKashyap Desai 		mrioc->sense_buf = NULL;
2923824a1566SKashyap Desai 		mrioc->sense_buf_pool = NULL;
2924824a1566SKashyap Desai 	}
2925824a1566SKashyap Desai 	if (mrioc->sense_buf_q_pool) {
2926824a1566SKashyap Desai 		if (mrioc->sense_buf_q)
2927824a1566SKashyap Desai 			dma_pool_free(mrioc->sense_buf_q_pool,
2928824a1566SKashyap Desai 			    mrioc->sense_buf_q, mrioc->sense_buf_q_dma);
2929824a1566SKashyap Desai 		dma_pool_destroy(mrioc->sense_buf_q_pool);
2930824a1566SKashyap Desai 		mrioc->sense_buf_q = NULL;
2931824a1566SKashyap Desai 		mrioc->sense_buf_q_pool = NULL;
2932824a1566SKashyap Desai 	}
2933824a1566SKashyap Desai 
2934824a1566SKashyap Desai 	if (mrioc->reply_buf_pool) {
2935824a1566SKashyap Desai 		if (mrioc->reply_buf)
2936824a1566SKashyap Desai 			dma_pool_free(mrioc->reply_buf_pool, mrioc->reply_buf,
2937824a1566SKashyap Desai 			    mrioc->reply_buf_dma);
2938824a1566SKashyap Desai 		dma_pool_destroy(mrioc->reply_buf_pool);
2939824a1566SKashyap Desai 		mrioc->reply_buf = NULL;
2940824a1566SKashyap Desai 		mrioc->reply_buf_pool = NULL;
2941824a1566SKashyap Desai 	}
2942824a1566SKashyap Desai 	if (mrioc->reply_free_q_pool) {
2943824a1566SKashyap Desai 		if (mrioc->reply_free_q)
2944824a1566SKashyap Desai 			dma_pool_free(mrioc->reply_free_q_pool,
2945824a1566SKashyap Desai 			    mrioc->reply_free_q, mrioc->reply_free_q_dma);
2946824a1566SKashyap Desai 		dma_pool_destroy(mrioc->reply_free_q_pool);
2947824a1566SKashyap Desai 		mrioc->reply_free_q = NULL;
2948824a1566SKashyap Desai 		mrioc->reply_free_q_pool = NULL;
2949824a1566SKashyap Desai 	}
2950824a1566SKashyap Desai 
2951c9566231SKashyap Desai 	for (i = 0; i < mrioc->num_op_req_q; i++)
2952c9566231SKashyap Desai 		mpi3mr_free_op_req_q_segments(mrioc, i);
2953c9566231SKashyap Desai 
2954c9566231SKashyap Desai 	for (i = 0; i < mrioc->num_op_reply_q; i++)
2955c9566231SKashyap Desai 		mpi3mr_free_op_reply_q_segments(mrioc, i);
2956c9566231SKashyap Desai 
2957824a1566SKashyap Desai 	for (i = 0; i < mrioc->intr_info_count; i++) {
2958824a1566SKashyap Desai 		intr_info = mrioc->intr_info + i;
2959824a1566SKashyap Desai 		if (intr_info)
2960824a1566SKashyap Desai 			intr_info->op_reply_q = NULL;
2961824a1566SKashyap Desai 	}
2962824a1566SKashyap Desai 
2963824a1566SKashyap Desai 	kfree(mrioc->req_qinfo);
2964824a1566SKashyap Desai 	mrioc->req_qinfo = NULL;
2965824a1566SKashyap Desai 	mrioc->num_op_req_q = 0;
2966824a1566SKashyap Desai 
2967824a1566SKashyap Desai 	kfree(mrioc->op_reply_qinfo);
2968824a1566SKashyap Desai 	mrioc->op_reply_qinfo = NULL;
2969824a1566SKashyap Desai 	mrioc->num_op_reply_q = 0;
2970824a1566SKashyap Desai 
2971824a1566SKashyap Desai 	kfree(mrioc->init_cmds.reply);
2972824a1566SKashyap Desai 	mrioc->init_cmds.reply = NULL;
2973824a1566SKashyap Desai 
2974824a1566SKashyap Desai 	kfree(mrioc->chain_bitmap);
2975824a1566SKashyap Desai 	mrioc->chain_bitmap = NULL;
2976824a1566SKashyap Desai 
297713ef29eaSKashyap Desai 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
297813ef29eaSKashyap Desai 		kfree(mrioc->dev_rmhs_cmds[i].reply);
297913ef29eaSKashyap Desai 		mrioc->dev_rmhs_cmds[i].reply = NULL;
298013ef29eaSKashyap Desai 	}
298113ef29eaSKashyap Desai 
2982824a1566SKashyap Desai 	if (mrioc->chain_buf_pool) {
2983824a1566SKashyap Desai 		for (i = 0; i < mrioc->chain_buf_count; i++) {
2984824a1566SKashyap Desai 			if (mrioc->chain_sgl_list[i].addr) {
2985824a1566SKashyap Desai 				dma_pool_free(mrioc->chain_buf_pool,
2986824a1566SKashyap Desai 				    mrioc->chain_sgl_list[i].addr,
2987824a1566SKashyap Desai 				    mrioc->chain_sgl_list[i].dma_addr);
2988824a1566SKashyap Desai 				mrioc->chain_sgl_list[i].addr = NULL;
2989824a1566SKashyap Desai 			}
2990824a1566SKashyap Desai 		}
2991824a1566SKashyap Desai 		dma_pool_destroy(mrioc->chain_buf_pool);
2992824a1566SKashyap Desai 		mrioc->chain_buf_pool = NULL;
2993824a1566SKashyap Desai 	}
2994824a1566SKashyap Desai 
2995824a1566SKashyap Desai 	kfree(mrioc->chain_sgl_list);
2996824a1566SKashyap Desai 	mrioc->chain_sgl_list = NULL;
2997824a1566SKashyap Desai 
2998824a1566SKashyap Desai 	if (mrioc->admin_reply_base) {
2999824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz,
3000824a1566SKashyap Desai 		    mrioc->admin_reply_base, mrioc->admin_reply_dma);
3001824a1566SKashyap Desai 		mrioc->admin_reply_base = NULL;
3002824a1566SKashyap Desai 	}
3003824a1566SKashyap Desai 	if (mrioc->admin_req_base) {
3004824a1566SKashyap Desai 		dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz,
3005824a1566SKashyap Desai 		    mrioc->admin_req_base, mrioc->admin_req_dma);
3006824a1566SKashyap Desai 		mrioc->admin_req_base = NULL;
3007824a1566SKashyap Desai 	}
3008824a1566SKashyap Desai }
3009824a1566SKashyap Desai 
3010824a1566SKashyap Desai /**
3011824a1566SKashyap Desai  * mpi3mr_issue_ioc_shutdown - shutdown controller
3012824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3013824a1566SKashyap Desai  *
3014824a1566SKashyap Desai  * Send shutodwn notification to the controller and wait for the
3015824a1566SKashyap Desai  * shutdown_timeout for it to be completed.
3016824a1566SKashyap Desai  *
3017824a1566SKashyap Desai  * Return: Nothing.
3018824a1566SKashyap Desai  */
3019824a1566SKashyap Desai static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc)
3020824a1566SKashyap Desai {
3021824a1566SKashyap Desai 	u32 ioc_config, ioc_status;
3022824a1566SKashyap Desai 	u8 retval = 1;
3023824a1566SKashyap Desai 	u32 timeout = MPI3MR_DEFAULT_SHUTDOWN_TIME * 10;
3024824a1566SKashyap Desai 
3025824a1566SKashyap Desai 	ioc_info(mrioc, "Issuing shutdown Notification\n");
3026824a1566SKashyap Desai 	if (mrioc->unrecoverable) {
3027824a1566SKashyap Desai 		ioc_warn(mrioc,
3028824a1566SKashyap Desai 		    "IOC is unrecoverable shutdown is not issued\n");
3029824a1566SKashyap Desai 		return;
3030824a1566SKashyap Desai 	}
3031824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
3032824a1566SKashyap Desai 	if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
3033824a1566SKashyap Desai 	    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS) {
3034824a1566SKashyap Desai 		ioc_info(mrioc, "shutdown already in progress\n");
3035824a1566SKashyap Desai 		return;
3036824a1566SKashyap Desai 	}
3037824a1566SKashyap Desai 
3038824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
3039824a1566SKashyap Desai 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL;
3040824a1566SKashyap Desai 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN;
3041824a1566SKashyap Desai 
3042824a1566SKashyap Desai 	writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
3043824a1566SKashyap Desai 
3044824a1566SKashyap Desai 	if (mrioc->facts.shutdown_timeout)
3045824a1566SKashyap Desai 		timeout = mrioc->facts.shutdown_timeout * 10;
3046824a1566SKashyap Desai 
3047824a1566SKashyap Desai 	do {
3048824a1566SKashyap Desai 		ioc_status = readl(&mrioc->sysif_regs->ioc_status);
3049824a1566SKashyap Desai 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
3050824a1566SKashyap Desai 		    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_COMPLETE) {
3051824a1566SKashyap Desai 			retval = 0;
3052824a1566SKashyap Desai 			break;
3053824a1566SKashyap Desai 		}
3054824a1566SKashyap Desai 		msleep(100);
3055824a1566SKashyap Desai 	} while (--timeout);
3056824a1566SKashyap Desai 
3057824a1566SKashyap Desai 	ioc_status = readl(&mrioc->sysif_regs->ioc_status);
3058824a1566SKashyap Desai 	ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
3059824a1566SKashyap Desai 
3060824a1566SKashyap Desai 	if (retval) {
3061824a1566SKashyap Desai 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
3062824a1566SKashyap Desai 		    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS)
3063824a1566SKashyap Desai 			ioc_warn(mrioc,
3064824a1566SKashyap Desai 			    "shutdown still in progress after timeout\n");
3065824a1566SKashyap Desai 	}
3066824a1566SKashyap Desai 
3067824a1566SKashyap Desai 	ioc_info(mrioc,
3068824a1566SKashyap Desai 	    "Base IOC Sts/Config after %s shutdown is (0x%x)/(0x%x)\n",
3069824a1566SKashyap Desai 	    (!retval) ? "successful" : "failed", ioc_status,
3070824a1566SKashyap Desai 	    ioc_config);
3071824a1566SKashyap Desai }
3072824a1566SKashyap Desai 
3073824a1566SKashyap Desai /**
3074824a1566SKashyap Desai  * mpi3mr_cleanup_ioc - Cleanup controller
3075824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3076*fb9b0457SKashyap Desai  * @re_init: Cleanup due to a reinit or not
3077824a1566SKashyap Desai  *
3078824a1566SKashyap Desai  * controller cleanup handler, Message unit reset or soft reset
3079824a1566SKashyap Desai  * and shutdown notification is issued to the controller and the
3080824a1566SKashyap Desai  * associated memory resources are freed.
3081824a1566SKashyap Desai  *
3082824a1566SKashyap Desai  * Return: Nothing.
3083824a1566SKashyap Desai  */
3084*fb9b0457SKashyap Desai void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc, u8 re_init)
3085824a1566SKashyap Desai {
3086824a1566SKashyap Desai 	enum mpi3mr_iocstate ioc_state;
3087824a1566SKashyap Desai 
3088*fb9b0457SKashyap Desai 	if (!re_init)
3089672ae26cSKashyap Desai 		mpi3mr_stop_watchdog(mrioc);
3090672ae26cSKashyap Desai 
3091824a1566SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
3092824a1566SKashyap Desai 
3093824a1566SKashyap Desai 	ioc_state = mpi3mr_get_iocstate(mrioc);
3094824a1566SKashyap Desai 
3095824a1566SKashyap Desai 	if ((!mrioc->unrecoverable) && (!mrioc->reset_in_progress) &&
3096824a1566SKashyap Desai 	    (ioc_state == MRIOC_STATE_READY)) {
3097824a1566SKashyap Desai 		if (mpi3mr_issue_and_process_mur(mrioc,
3098824a1566SKashyap Desai 		    MPI3MR_RESET_FROM_CTLR_CLEANUP))
3099824a1566SKashyap Desai 			mpi3mr_issue_reset(mrioc,
3100824a1566SKashyap Desai 			    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
3101824a1566SKashyap Desai 			    MPI3MR_RESET_FROM_MUR_FAILURE);
3102824a1566SKashyap Desai 
3103*fb9b0457SKashyap Desai 		if (!re_init)
3104824a1566SKashyap Desai 			mpi3mr_issue_ioc_shutdown(mrioc);
3105824a1566SKashyap Desai 	}
3106824a1566SKashyap Desai 
3107*fb9b0457SKashyap Desai 	if (!re_init) {
3108824a1566SKashyap Desai 		mpi3mr_free_mem(mrioc);
3109824a1566SKashyap Desai 		mpi3mr_cleanup_resources(mrioc);
3110824a1566SKashyap Desai 	}
3111*fb9b0457SKashyap Desai }
3112*fb9b0457SKashyap Desai 
3113*fb9b0457SKashyap Desai /**
3114*fb9b0457SKashyap Desai  * mpi3mr_drv_cmd_comp_reset - Flush a internal driver command
3115*fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
3116*fb9b0457SKashyap Desai  * @cmdptr: Internal command tracker
3117*fb9b0457SKashyap Desai  *
3118*fb9b0457SKashyap Desai  * Complete an internal driver commands with state indicating it
3119*fb9b0457SKashyap Desai  * is completed due to reset.
3120*fb9b0457SKashyap Desai  *
3121*fb9b0457SKashyap Desai  * Return: Nothing.
3122*fb9b0457SKashyap Desai  */
3123*fb9b0457SKashyap Desai static inline void mpi3mr_drv_cmd_comp_reset(struct mpi3mr_ioc *mrioc,
3124*fb9b0457SKashyap Desai 	struct mpi3mr_drv_cmd *cmdptr)
3125*fb9b0457SKashyap Desai {
3126*fb9b0457SKashyap Desai 	if (cmdptr->state & MPI3MR_CMD_PENDING) {
3127*fb9b0457SKashyap Desai 		cmdptr->state |= MPI3MR_CMD_RESET;
3128*fb9b0457SKashyap Desai 		cmdptr->state &= ~MPI3MR_CMD_PENDING;
3129*fb9b0457SKashyap Desai 		if (cmdptr->is_waiting) {
3130*fb9b0457SKashyap Desai 			complete(&cmdptr->done);
3131*fb9b0457SKashyap Desai 			cmdptr->is_waiting = 0;
3132*fb9b0457SKashyap Desai 		} else if (cmdptr->callback)
3133*fb9b0457SKashyap Desai 			cmdptr->callback(mrioc, cmdptr);
3134*fb9b0457SKashyap Desai 	}
3135*fb9b0457SKashyap Desai }
3136*fb9b0457SKashyap Desai 
3137*fb9b0457SKashyap Desai /**
3138*fb9b0457SKashyap Desai  * mpi3mr_flush_drv_cmds - Flush internaldriver commands
3139*fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
3140*fb9b0457SKashyap Desai  *
3141*fb9b0457SKashyap Desai  * Flush all internal driver commands post reset
3142*fb9b0457SKashyap Desai  *
3143*fb9b0457SKashyap Desai  * Return: Nothing.
3144*fb9b0457SKashyap Desai  */
3145*fb9b0457SKashyap Desai static void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc)
3146*fb9b0457SKashyap Desai {
3147*fb9b0457SKashyap Desai 	struct mpi3mr_drv_cmd *cmdptr;
3148*fb9b0457SKashyap Desai 	u8 i;
3149*fb9b0457SKashyap Desai 
3150*fb9b0457SKashyap Desai 	cmdptr = &mrioc->init_cmds;
3151*fb9b0457SKashyap Desai 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
3152*fb9b0457SKashyap Desai 
3153*fb9b0457SKashyap Desai 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
3154*fb9b0457SKashyap Desai 		cmdptr = &mrioc->dev_rmhs_cmds[i];
3155*fb9b0457SKashyap Desai 		mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
3156*fb9b0457SKashyap Desai 	}
3157*fb9b0457SKashyap Desai }
3158*fb9b0457SKashyap Desai 
3159*fb9b0457SKashyap Desai /**
3160*fb9b0457SKashyap Desai  * mpi3mr_diagfault_reset_handler - Diag fault reset handler
3161*fb9b0457SKashyap Desai  * @mrioc: Adapter instance reference
3162*fb9b0457SKashyap Desai  * @reset_reason: Reset reason code
3163*fb9b0457SKashyap Desai  *
3164*fb9b0457SKashyap Desai  * This is an handler for issuing diag fault reset from the
3165*fb9b0457SKashyap Desai  * applications through IOCTL path to stop the execution of the
3166*fb9b0457SKashyap Desai  * controller
3167*fb9b0457SKashyap Desai  *
3168*fb9b0457SKashyap Desai  * Return: 0 on success, non-zero on failure.
3169*fb9b0457SKashyap Desai  */
3170*fb9b0457SKashyap Desai int mpi3mr_diagfault_reset_handler(struct mpi3mr_ioc *mrioc,
3171*fb9b0457SKashyap Desai 	u32 reset_reason)
3172*fb9b0457SKashyap Desai {
3173*fb9b0457SKashyap Desai 	int retval = 0;
3174*fb9b0457SKashyap Desai 
3175*fb9b0457SKashyap Desai 	mrioc->reset_in_progress = 1;
3176*fb9b0457SKashyap Desai 
3177*fb9b0457SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
3178*fb9b0457SKashyap Desai 
3179*fb9b0457SKashyap Desai 	retval = mpi3mr_issue_reset(mrioc,
3180*fb9b0457SKashyap Desai 	    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
3181*fb9b0457SKashyap Desai 
3182*fb9b0457SKashyap Desai 	if (retval) {
3183*fb9b0457SKashyap Desai 		ioc_err(mrioc, "The diag fault reset failed: reason %d\n",
3184*fb9b0457SKashyap Desai 		    reset_reason);
3185*fb9b0457SKashyap Desai 		mpi3mr_ioc_enable_intr(mrioc);
3186*fb9b0457SKashyap Desai 	}
3187*fb9b0457SKashyap Desai 	ioc_info(mrioc, "%s\n", ((retval == 0) ? "SUCCESS" : "FAILED"));
3188*fb9b0457SKashyap Desai 	mrioc->reset_in_progress = 0;
3189*fb9b0457SKashyap Desai 	return retval;
3190*fb9b0457SKashyap Desai }
3191824a1566SKashyap Desai 
3192824a1566SKashyap Desai /**
3193824a1566SKashyap Desai  * mpi3mr_soft_reset_handler - Reset the controller
3194824a1566SKashyap Desai  * @mrioc: Adapter instance reference
3195824a1566SKashyap Desai  * @reset_reason: Reset reason code
3196824a1566SKashyap Desai  * @snapdump: Flag to generate snapdump in firmware or not
3197824a1566SKashyap Desai  *
3198*fb9b0457SKashyap Desai  * This is an handler for recovering controller by issuing soft
3199*fb9b0457SKashyap Desai  * reset are diag fault reset.  This is a blocking function and
3200*fb9b0457SKashyap Desai  * when one reset is executed if any other resets they will be
3201*fb9b0457SKashyap Desai  * blocked. All IOCTLs/IO will be blocked during the reset. If
3202*fb9b0457SKashyap Desai  * controller reset is successful then the controller will be
3203*fb9b0457SKashyap Desai  * reinitalized, otherwise the controller will be marked as not
3204*fb9b0457SKashyap Desai  * recoverable
3205*fb9b0457SKashyap Desai  *
3206*fb9b0457SKashyap Desai  * In snapdump bit is set, the controller is issued with diag
3207*fb9b0457SKashyap Desai  * fault reset so that the firmware can create a snap dump and
3208*fb9b0457SKashyap Desai  * post that the firmware will result in F000 fault and the
3209*fb9b0457SKashyap Desai  * driver will issue soft reset to recover from that.
3210824a1566SKashyap Desai  *
3211824a1566SKashyap Desai  * Return: 0 on success, non-zero on failure.
3212824a1566SKashyap Desai  */
3213824a1566SKashyap Desai int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
3214824a1566SKashyap Desai 	u32 reset_reason, u8 snapdump)
3215824a1566SKashyap Desai {
3216*fb9b0457SKashyap Desai 	int retval = 0, i;
3217*fb9b0457SKashyap Desai 	unsigned long flags;
3218*fb9b0457SKashyap Desai 	u32 host_diagnostic, timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10;
3219*fb9b0457SKashyap Desai 
3220*fb9b0457SKashyap Desai 	if (mrioc->fault_dbg) {
3221*fb9b0457SKashyap Desai 		if (snapdump)
3222*fb9b0457SKashyap Desai 			mpi3mr_set_diagsave(mrioc);
3223*fb9b0457SKashyap Desai 		mpi3mr_kill_ioc(mrioc, reset_reason);
3224*fb9b0457SKashyap Desai 	}
3225*fb9b0457SKashyap Desai 
3226*fb9b0457SKashyap Desai 	/*
3227*fb9b0457SKashyap Desai 	 * Block new resets until the currently executing one is finished and
3228*fb9b0457SKashyap Desai 	 * return the status of the existing reset for all blocked resets
3229*fb9b0457SKashyap Desai 	 */
3230*fb9b0457SKashyap Desai 	if (!mutex_trylock(&mrioc->reset_mutex)) {
3231*fb9b0457SKashyap Desai 		ioc_info(mrioc, "Another reset in progress\n");
3232*fb9b0457SKashyap Desai 		return -1;
3233*fb9b0457SKashyap Desai 	}
3234*fb9b0457SKashyap Desai 	mrioc->reset_in_progress = 1;
3235*fb9b0457SKashyap Desai 
3236*fb9b0457SKashyap Desai 	if ((!snapdump) && (reset_reason != MPI3MR_RESET_FROM_FAULT_WATCH) &&
3237*fb9b0457SKashyap Desai 	    (reset_reason != MPI3MR_RESET_FROM_CIACTIV_FAULT)) {
3238*fb9b0457SKashyap Desai 		for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
3239*fb9b0457SKashyap Desai 			mrioc->event_masks[i] = -1;
3240*fb9b0457SKashyap Desai 
3241*fb9b0457SKashyap Desai 		retval = mpi3mr_issue_event_notification(mrioc);
3242*fb9b0457SKashyap Desai 
3243*fb9b0457SKashyap Desai 		if (retval) {
3244*fb9b0457SKashyap Desai 			ioc_err(mrioc,
3245*fb9b0457SKashyap Desai 			    "Failed to turn off events prior to reset %d\n",
3246*fb9b0457SKashyap Desai 			    retval);
3247*fb9b0457SKashyap Desai 		}
3248*fb9b0457SKashyap Desai 	}
3249*fb9b0457SKashyap Desai 
3250*fb9b0457SKashyap Desai 	mpi3mr_ioc_disable_intr(mrioc);
3251*fb9b0457SKashyap Desai 
3252*fb9b0457SKashyap Desai 	if (snapdump) {
3253*fb9b0457SKashyap Desai 		mpi3mr_set_diagsave(mrioc);
3254*fb9b0457SKashyap Desai 		retval = mpi3mr_issue_reset(mrioc,
3255*fb9b0457SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
3256*fb9b0457SKashyap Desai 		if (!retval) {
3257*fb9b0457SKashyap Desai 			do {
3258*fb9b0457SKashyap Desai 				host_diagnostic =
3259*fb9b0457SKashyap Desai 				    readl(&mrioc->sysif_regs->host_diagnostic);
3260*fb9b0457SKashyap Desai 				if (!(host_diagnostic &
3261*fb9b0457SKashyap Desai 				    MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS))
3262*fb9b0457SKashyap Desai 					break;
3263*fb9b0457SKashyap Desai 				msleep(100);
3264*fb9b0457SKashyap Desai 			} while (--timeout);
3265*fb9b0457SKashyap Desai 		}
3266*fb9b0457SKashyap Desai 	}
3267*fb9b0457SKashyap Desai 
3268*fb9b0457SKashyap Desai 	retval = mpi3mr_issue_reset(mrioc,
3269*fb9b0457SKashyap Desai 	    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, reset_reason);
3270*fb9b0457SKashyap Desai 	if (retval) {
3271*fb9b0457SKashyap Desai 		ioc_err(mrioc, "Failed to issue soft reset to the ioc\n");
3272*fb9b0457SKashyap Desai 		goto out;
3273*fb9b0457SKashyap Desai 	}
3274*fb9b0457SKashyap Desai 
3275*fb9b0457SKashyap Desai 	mpi3mr_flush_delayed_rmhs_list(mrioc);
3276*fb9b0457SKashyap Desai 	mpi3mr_flush_drv_cmds(mrioc);
3277*fb9b0457SKashyap Desai 	memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz);
3278*fb9b0457SKashyap Desai 	memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz);
3279*fb9b0457SKashyap Desai 	mpi3mr_cleanup_fwevt_list(mrioc);
3280*fb9b0457SKashyap Desai 	mpi3mr_flush_host_io(mrioc);
3281*fb9b0457SKashyap Desai 	mpi3mr_invalidate_devhandles(mrioc);
3282*fb9b0457SKashyap Desai 	mpi3mr_memset_buffers(mrioc);
3283*fb9b0457SKashyap Desai 	retval = mpi3mr_init_ioc(mrioc, 1);
3284*fb9b0457SKashyap Desai 	if (retval) {
3285*fb9b0457SKashyap Desai 		pr_err(IOCNAME "reinit after soft reset failed: reason %d\n",
3286*fb9b0457SKashyap Desai 		    mrioc->name, reset_reason);
3287*fb9b0457SKashyap Desai 		goto out;
3288*fb9b0457SKashyap Desai 	}
3289*fb9b0457SKashyap Desai 	ssleep(10);
3290*fb9b0457SKashyap Desai 
3291*fb9b0457SKashyap Desai out:
3292*fb9b0457SKashyap Desai 	if (!retval) {
3293*fb9b0457SKashyap Desai 		mrioc->reset_in_progress = 0;
3294*fb9b0457SKashyap Desai 		scsi_unblock_requests(mrioc->shost);
3295*fb9b0457SKashyap Desai 		mpi3mr_rfresh_tgtdevs(mrioc);
3296*fb9b0457SKashyap Desai 		spin_lock_irqsave(&mrioc->watchdog_lock, flags);
3297*fb9b0457SKashyap Desai 		if (mrioc->watchdog_work_q)
3298*fb9b0457SKashyap Desai 			queue_delayed_work(mrioc->watchdog_work_q,
3299*fb9b0457SKashyap Desai 			    &mrioc->watchdog_work,
3300*fb9b0457SKashyap Desai 			    msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL));
3301*fb9b0457SKashyap Desai 		spin_unlock_irqrestore(&mrioc->watchdog_lock, flags);
3302*fb9b0457SKashyap Desai 	} else {
3303*fb9b0457SKashyap Desai 		mpi3mr_issue_reset(mrioc,
3304*fb9b0457SKashyap Desai 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
3305*fb9b0457SKashyap Desai 		mrioc->unrecoverable = 1;
3306*fb9b0457SKashyap Desai 		mrioc->reset_in_progress = 0;
3307*fb9b0457SKashyap Desai 		retval = -1;
3308*fb9b0457SKashyap Desai 	}
3309*fb9b0457SKashyap Desai 
3310*fb9b0457SKashyap Desai 	mutex_unlock(&mrioc->reset_mutex);
3311*fb9b0457SKashyap Desai 	ioc_info(mrioc, "%s\n", ((retval == 0) ? "SUCCESS" : "FAILED"));
3312*fb9b0457SKashyap Desai 	return retval;
3313824a1566SKashyap Desai }
3314